diff options
Diffstat (limited to 'include')
563 files changed, 304582 insertions, 0 deletions
diff --git a/include/.scm-settings b/include/.scm-settings new file mode 100644 index 00000000..48ca6339 --- /dev/null +++ b/include/.scm-settings @@ -0,0 +1,112 @@ +# $Id: .scm-settings $ +## @file +# Source code massager settings for the includes. +# + +# +# Copyright (C) 2010-2022 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + + +# Default license for headers is dual GPL and CDDL. +--license-ose-dual + +# Only the headers should be dual. +/Makefile.kmk: --license-ose-gpl +/.scm-settings: --license-ose-gpl + +# /iprt/nocrt/* C++ style header files +/iprt/nocrt/algorithm: --treat-as h +/iprt/nocrt/cassert: --treat-as h +/iprt/nocrt/cstddef: --treat-as h +/iprt/nocrt/cstdlib: --treat-as h +/iprt/nocrt/exception: --treat-as h +/iprt/nocrt/fstream: --treat-as h +/iprt/nocrt/iomanip: --treat-as h +/iprt/nocrt/ios: --treat-as h +/iprt/nocrt/iosfwd: --treat-as h +/iprt/nocrt/iostream: --treat-as h +/iprt/nocrt/limits: --treat-as h +/iprt/nocrt/memory: --treat-as h +/iprt/nocrt/new: --treat-as h +/iprt/nocrt/ostream: --treat-as h +/iprt/nocrt/string: --treat-as h +/iprt/nocrt/type_traits: --treat-as h +/iprt/nocrt/vector: --treat-as h + +# These three have no Oracle license or copyright stuff for some reason. +/iprt/formats/elf-amd64.h: --no-update-license --no-update-copyright-year +/iprt/formats/elf-common.h: --no-update-license --no-update-copyright-year +/iprt/formats/elf-i386.h: --no-update-license --no-update-copyright-year +/iprt/formats/elf-i386.h: --no-update-license --no-update-copyright-year + +# external copyright +/iprt/formats/lx.h: --external-copyright + +# This is using LGPL (from WINE) with Oracle disclaimer. +/VBox/VBoxKeyboard.h: --external-copyright --lgpl-disclaimer + +# Some of the graphics stuff is using MIT. +/VBox/Graphics/HGSMI.h: --license-mit +/VBox/Graphics/HGSMIBase.h: --license-mit +/VBox/Graphics/HGSMIChannels.h: --license-mit +/VBox/Graphics/HGSMIChSetup.h: --license-mit +/VBox/Graphics/HGSMIContext.h: --license-mit +/VBox/Graphics/HGSMIDefs.h: --license-mit +/VBox/Graphics/VBoxVideo.h: --license-mit +/VBox/Graphics/VBoxVideoErr.h: --license-mit +/VBox/Graphics/VBoxVideoGuest.h: --license-mit +/VBox/Graphics/VBoxVideoVBE.h: --license-mit +/VBox/Graphics/VBoxVideoVBEPrivate.h: --license-mit + +# And so are some files used by the shared folder guest code. +/VBox/shflsvc.h: --license-mit +/VBox/VBoxGuest.h: --license-mit +/VBox/VBoxGuestCoreTypes.h: --license-mit +/VBox/VBoxGuestLib.h: --license-mit +/VBox/VBoxGuestLibSharedFolders.h: --license-mit +/VBox/VBoxGuestLibSharedFoldersInline.h: --license-mit +/VBox/VMMDev.h: --license-mit +/VBox/VMMDevCoreTypes.h: --license-mit + +/VBox/HostServices/glext.h: --external-copyright --no-convert-tabs --no-strip-trailing-blanks +/VBox/HostServices/glxext.h: --external-copyright --no-convert-tabs --no-strip-trailing-blanks +/VBox/HostServices/wglext.h: --external-copyright --no-convert-tabs --no-strip-trailing-blanks + +# Some headers actually shouldn't have include guards: +/VBox/dbus-calls.h: --no-fix-header-guards +/VBox/xrandr-calls.h: --no-fix-header-guards +/VBox/VDEPlugSymDefs.h: --no-fix-header-guards +/VBox/vmm/vmmr3vtable-def.h: --no-fix-header-guards +/iprt/asn1-generator-core.h: --no-fix-header-guards +/iprt/asn1-generator-pass.h: --no-fix-header-guards +/iprt/asn1-generator-sanity.h: --no-fix-header-guards +/iprt/asn1-generator-internal-header.h: --no-fix-header-guards +/iprt/asn1-generator-asn1-decoder.h: --no-fix-header-guards +/iprt/asn1-generator-init.h: --no-fix-header-guards +/iprt/runtime-loader.h: --no-fix-header-guards +/iprt/bldprog-strtab-template.cpp.h: --no-fix-header-guards +/iprt/asm*watcom*.h: --no-pragma-once + +/iprt/*.h: --guard-relative-to-dir iprt --guard-prefix IPRT_INCLUDED_ +/VBox/*.h: --guard-relative-to-dir VBox --guard-prefix VBOX_INCLUDED_ +/iprt/sanitized/*: --guard-relative-to-dir iprt --guard-prefix IPRT_INCLUDED_ --treat-as h + diff --git a/include/Makefile.kmk b/include/Makefile.kmk new file mode 100644 index 00000000..4a9e615c --- /dev/null +++ b/include/Makefile.kmk @@ -0,0 +1,286 @@ +# $Id: Makefile.kmk $ +## @file +# Some hacks to allow syntax and prerequisite include checking of headers. +# This makefile doesn't and shouldn't build successfully. +# + +# +# Copyright (C) 2006-2022 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +SUB_DEPTH = .. +include $(KBUILD_PATH)/subheader.kmk + +LIBRARIES += SyntaxVBoxIncludeR3 SyntaxVBoxIncludeR0 + +# Omit headers that are using C++ features and upsets gcc. +VBOX_HDRS_CPP_FEATURES := \ + VBox/vmm/hm.h \ + VBox/vmm/hm_vmx.h \ + VBox/vmm/pdmaudioinline.h \ + VBox/vmm/pdmaudiohostenuminline.h \ + VBox/HostServices/GuestControlSvc.h \ + VBox/HostServices/DragAndDropSvc.h \ + VBox/HostServices/Service.h \ + VBox/GuestHost/GuestControl.h \ + VBox/GuestHost/DragAndDrop.h \ + VBox/GuestHost/SharedClipboard-transfers.h \ + VBox/dbus.h \ + VBox/xrandr.h \ + VBox/VBoxCrHgsmi.h \ + VBox/VBoxGuestLibSharedFoldersInline.h \ + VBox/VBoxPktDmp.h \ + VBox/VBoxUhgsmi.h \ + iprt/cpp/% + +# Omit headers that are C++ and ring-3. +VBOX_HDRS_R3_CPP := \ + VBox/dbggui.h \ + VBox/settings.h \ + VBox/com/Guid.h \ + VBox/vmm/vmmr3vtable.h \ + iprt/cpp/% \ + VBox/com/% \ + $(subst $(PATH_SUB_CURRENT)/,,$(wildcard $(PATH_SUB_CURRENT)/iprt/*_cpp.h)) + +# Ring-3 only headers. +VBOX_HDRS_R3_ONLY := \ + VBox/vrdpapi.h \ + VBox/vrdpusb.h \ + VBox/VBoxHDD.h \ + VBox/VBoxHDD-Plugin.h \ + VBox/VBoxCrHgsmi.h \ + VBox/VBoxUhgsmi.h \ + VBox/VBoxNetCfg-win.h \ + VBox/VBoxDrvCfg-win.h \ + VBox/dbus.h \ + VBox/xrandr.h \ + $(if-expr "$(KBUILD_TARGET)" == "win",VBox/usblib.h,) \ + VBox/usblib-win.h \ + VBox/vd.h \ + VBox/vd-cache-backend.h \ + VBox/vd-ifs.h \ + VBox/vd-ifs-internal.h \ + VBox/vd-image-backend.h \ + VBox/vd-plugin.h \ + VBox/vd-filter-backend.h \ + VBox/vddbg.h \ + VBox/vmm/uvm.h \ + VBox/vmm/dbgfflowtrace.h \ + VBox/vscsi.h \ + VBox/ExtPack/% \ + VBox/GuestHost/SharedClipboard-transfers.h \ + VBox/GuestHost/SharedClipboard-win.h \ + VBox/GuestHost/SharedClipboard-x11.h \ + VBox/GuestHost/DragAndDrop.h \ + VBox/HostServices/Service.h \ + iprt/win/% \ + iprt/alloca.h \ + iprt/tcp.h \ + iprt/localipc.h \ + iprt/linux/sysfs.h \ + iprt/socket.h \ + iprt/udp.h \ + iprt/fuzz.h \ + iprt/linux/symvers.h + +# Ring-0 driver only headers. +VBOX_HDRS_R0DRV_ONLY := \ + VBox/VBoxGuestLibSharedFolders.h \ + VBox/VBoxGuestLibSharedFoldersInline.h \ + iprt/linux/version.h + +# GCC only headers. +VBOX_HDRS_GCC_ONLY := \ + iprt/nocrt/fenv.h \ + iprt/nocrt/math.h + +# Headers to omit all together. +VBOX_HDRS_OMIT := \ + VBox/HostServices/glext.h \ + VBox/HostServices/glxext.h \ + VBox/HostServices/wglext.h \ + VBox/VBoxGL2D.h \ + $(if-expr "$(KBUILD_TARGET)" != "linux", \ + VBox/GuestHost/SharedClipboard-x11.h \ + ,)\ + $(if-expr "$(KBUILD_TARGET)" != "solaris", \ + VBox/usblib-solaris.h \ + ,)\ + VBox/VDEPlug.h \ + VBox/VDEPlugSymDefs.h \ + VBox/VBoxNetCmn-win.h \ + $(if-expr "$(KBUILD_TARGET)" != "win", \ + VBox/com/microatl.h \ + VBox/GuestHost/SharedClipboard-win.h \ + VBox/usblib-win.h \ + VBox/VBoxDrvCfg-win.h \ + VBox/VBoxNetCfg-win.h \ + iprt/sanitized/intrin.h \ + ,$(VBOX_HDRS_GCC_ONLY)) \ + \ + VBox/dbus-calls.h \ + VBox/xrandr-calls.h \ + VBox/VBoxKeyboard.h \ + VBox/vmm/pdmpcidevint.h \ + VBox/vmm/vmmr3vtable-def.h \ + iprt/runtime-loader.h \ + iprt/mangling.h \ + $(subst $(PATH_SUB_CURRENT)/,,$(wildcard $(PATH_SUB_CURRENT)/iprt/asm*watcom*.h)) \ + iprt/asn1-generator% \ + iprt/win/% \ + iprt/nt/% \ + \ + $(foreach os,$(filter-out $(KBUILD_TARGET),$(KBUILD_OSES)),iprt/$(os)/% VBox/$(os)/%) \ + $(foreach arch,$(KBUILD_ARCHES),iprt/nocrt/$(arch)/%) + +# AMD64 only headers. +ifneq ($(KBUILD_TARGET_ARCH),amd64) +VBOX_HDRS_OMIT += \ + VBox/vmm/cpumctx.h \ + VBox/vmm/cpumctx-v1_6.h \ + VBox/vmm/dbgfcorefmt.h +endif +# ARM only headers. +ifn1of ($(KBUILD_TARGET_ARCH), arm32 arm64) +VBOX_HDRS_OMIT += \ + iprt/asm-arm.h +endif + + +# We omit a few headers which have platform specific issues or are templates. +VBOX_HDRS_ALL := $(filter-out $(VBOX_HDRS_OMIT), \ + $(subst $(PATH_SUB_CURRENT)/,,$(wildcard \ + $(PATH_SUB_CURRENT)/VBox/*.h \ + $(PATH_SUB_CURRENT)/VBox/*/*.h \ + $(PATH_SUB_CURRENT)/iprt/*.h \ + $(PATH_SUB_CURRENT)/iprt/*/*.h \ +))) + +# ring-3, ring-0 and raw-mode context specific exclusions. +VBOX_HDRS_ALL_R3 := $(filter-out $(VBOX_HDRS_R0DRV_ONLY), $(VBOX_HDRS_ALL)) +if "$(intersects $(KBUILD_TARGET_ARCH),$(VBOX_SUPPORTED_HOST_ARCHS))" == "" + ifeq ($(KBUILD_TARGET),win) +VBOX_HDRS_ALL_R3 := $(filter-out VBox/com/VirtualBox.h VBox/com/listeners.h VBox/settings.h,$(VBOX_HDRS_ALL_R3)) + else +VBOX_HDRS_ALL_R3 := $(filter-out VBox/com/% VBox/settings.h,$(VBOX_HDRS_ALL_R3)) + endif +endif +VBOX_HDRS_ALL_R3_C := $(filter-out $(VBOX_HDRS_CPP_FEATURES) $(VBOX_HDRS_R3_CPP), $(VBOX_HDRS_ALL_R3)) +VBOX_HDRS_ALL_R0 := $(filter-out $(VBOX_HDRS_R3_CPP) $(VBOX_HDRS_R3_ONLY) $(VBOX_HDRS_R0DRV_ONLY), $(VBOX_HDRS_ALL)) +VBOX_HDRS_ALL_R0_C := $(filter-out $(VBOX_HDRS_CPP_FEATURES), $(VBOX_HDRS_ALL_R0)) +VBOX_HDRS_ALL_R0DRV := $(filter-out $(VBOX_HDRS_R3_CPP) $(VBOX_HDRS_R3_ONLY), $(VBOX_HDRS_ALL)) +VBOX_HDRS_ALL_R0DRV_C := $(filter-out $(VBOX_HDRS_CPP_FEATURES), $(VBOX_HDRS_ALL_R0DRV)) +VBOX_HDRS_ALL_RC := $(filter-out \ + VBox/VBoxGuestLib.h \ + VBox/vmm/gvm.h \ + iprt/thread.h \ + iprt/mem.h \ + iprt/memsafer.h \ + iprt/alloc.h \ + iprt/vector.h \ + $(VBOX_HDRS_R3_CPP) \ + $(VBOX_HDRS_R3_ONLY) \ + $(VBOX_HDRS_R0DRV_ONLY) \ + , $(VBOX_HDRS_ALL)) +VBOX_HDRS_ALL_RC_C := $(filter-out $(VBOX_HDRS_CPP_FEATURES), $(VBOX_HDRS_ALL_RC)) +#$(error $(subst $(SP),$(NLTAB),$(strip $(sort $(VBOX_HDRS_ALL_RC_C))))) + +if1of ($(KBUILD_TARGET_ARCH), $(VBOX_SUPPORTED_HOST_ARCHS)) +SyntaxVBoxIncludeR3_TEMPLATE = VBOXMAINEXE +SyntaxVBoxIncludeR3_DEFS = VBOX_WITH_HGCM +else +SyntaxVBoxIncludeR3_TEMPLATE = VBOXR3EXE +SyntaxVBoxIncludeR3_SDKS.win = ReorderCompilerIncs $(VBOX_WINPSDK) $(VBOX_WINDDK) +endif +SyntaxVBoxIncludeR3_DEFS += USING_VMM_COMMON_DEFS +SyntaxVBoxIncludeR3_CDEFS = IPRT_WITHOUT_NAMED_UNIONS_AND_STRUCTS +SyntaxVBoxIncludeR3_SOURCES := \ + $(addprefix $(PATH_OBJ)/include/c/, $(addsuffix .c, $(basename $(VBOX_HDRS_ALL_R3_C)))) \ + $(addprefix $(PATH_OBJ)/include/cpp/,$(addsuffix .cpp,$(basename $(VBOX_HDRS_ALL_R3)))) +SyntaxVBoxIncludeR3_CLEAN = $(SyntaxVBoxIncludeR3_SOURCES) +#$(error $(subst $(SP),$(NLTAB),$(strip $(sort $(SyntaxVBoxIncludeR3_SOURCES))))) + +SyntaxVBoxIncludeR0_TEMPLATE = VBoxR0 +SyntaxVBoxIncludeR0_DEFS = VBOX_WITH_HGCM USING_VMM_COMMON_DEFS +SyntaxVBoxIncludeR0_CDEFS = IPRT_WITHOUT_NAMED_UNIONS_AND_STRUCTS +SyntaxVBoxIncludeR0_SOURCES := \ + $(addprefix $(PATH_OBJ)/include/c/, $(addsuffix .c, $(basename $(VBOX_HDRS_ALL_R0_C)))) \ + $(addprefix $(PATH_OBJ)/include/cpp/,$(addsuffix .cpp,$(basename $(VBOX_HDRS_ALL_R0)))) +SyntaxVBoxIncludeR0_CLEAN = $(SyntaxVBoxIncludeR0_SOURCES) + +if1of ($(KBUILD_TARGET), darwin os2 solaris win) +LIBRARIES += SyntaxVBoxIncludeR0Drv +SyntaxVBoxIncludeR0Drv_TEMPLATE = VBoxR0DrvLib +SyntaxVBoxIncludeR0Drv_SDKS.win = ReorderCompilerIncs $(VBOX_WINDDK) $(VBOX_WINPSDK_INCS) +SyntaxVBoxIncludeR0Drv_DEFS = VBOX_WITH_HGCM USING_VMM_COMMON_DEFS +SyntaxVBoxIncludeR0Drv_CDEFS = IPRT_WITHOUT_NAMED_UNIONS_AND_STRUCTS +SyntaxVBoxIncludeR0Drv_SOURCES := \ + $(addprefix $(PATH_OBJ)/include/c/, $(addsuffix .c, $(basename $(VBOX_HDRS_ALL_R0DRV_C)))) \ + $(addprefix $(PATH_OBJ)/include/cpp/,$(addsuffix .cpp,$(basename $(VBOX_HDRS_ALL_R0DRV)))) +SyntaxVBoxIncludeR0Drv_CLEAN = $(SyntaxVBoxIncludeR0Drv_SOURCES) +endif + +ifdef VBOX_WITH_RAW_MODE +LIBRARIES += SyntaxVBoxIncludeRC +SyntaxVBoxIncludeRC_TEMPLATE = VBoxRc +SyntaxVBoxIncludeRC_DEFS = VBOX_WITH_HGCM USING_VMM_COMMON_DEFS +SyntaxVBoxIncludeRC_CDEFS = IPRT_WITHOUT_NAMED_UNIONS_AND_STRUCTS +SyntaxVBoxIncludeRC_SOURCES := \ + $(addprefix $(PATH_OBJ)/include/c/, $(addsuffix .c, $(basename $(VBOX_HDRS_ALL_RC_C)))) \ + $(addprefix $(PATH_OBJ)/include/cpp/,$(addsuffix .cpp,$(basename $(VBOX_HDRS_ALL_RC)))) +SyntaxVBoxIncludeRC_CLEAN = $(SyntaxVBoxIncludeRC_SOURCES) +endif + + +# Headers that must only be included once. +VBOX_HDRS_ONLY_ONCE := \ + iprt/bldprog-strtab-template.cpp.h + + +# Generate the files we compile. +define def_hdr + $(eval functioname := $(translate $(basename $(hdr)),-./,___)) + + $$(PATH_OBJ)/include/c/$(basename $(hdr)).c: | $$$$(dir $$$$@) + $(QUIET)$$(APPEND) -t -n $$@ \ + '#include <$(hdr)>' \ + $(if-expr $(intersects $(hdr),$(VBOX_HDRS_ONLY_ONCE)),, '#include <$(hdr)>') \ + 'extern int $(functioname)_c(void);' \ + 'int $(functioname)_c(void) { return 0;}' + + $$(PATH_OBJ)/include/cpp/$(basename $(hdr)).cpp: | $$$$(dir $$$$@) + $(QUIET)$$(APPEND) -t -n $$@ \ + '#include <$(hdr)>' \ + $(if-expr $(intersects $(hdr),$(VBOX_HDRS_ONLY_ONCE)),, '#include <$(hdr)>') \ + 'extern int $(functioname)_cpp(void);' \ + 'int $(functioname)_cpp(void) { return 0;}' + +endef + +$(foreach hdr,$(VBOX_HDRS_ALL), $(eval $(def_hdr))) + +# Tell kBuild to generate rules for making the directories for the generated files. +VBOX_HDR_DIRS := $(sort $(dir $(VBOX_HDRS_ALL))) +BLDDIRS += $(addprefix $(PATH_OBJ)/include/c/,$(VBOX_HDR_DIRS)) $(addprefix $(PATH_OBJ)/include/cpp/,$(VBOX_HDR_DIRS)) + + +include $(FILE_KBUILD_SUB_FOOTER) diff --git a/include/VBox/AssertGuest.h b/include/VBox/AssertGuest.h new file mode 100644 index 00000000..c4946ff0 --- /dev/null +++ b/include/VBox/AssertGuest.h @@ -0,0 +1,1781 @@ +/** @file + * VirtualBox - Guest input assertions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_AssertGuest_h +#define VBOX_INCLUDED_AssertGuest_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <iprt/assert.h> + + +/** @defgroup grp_vbox_assert_guest VBox Guest Input Assertion Macros + * @{ + */ + + +/** @name Guest input assertions + * + * These assertions will only trigger when VBOX_STRICT_GUEST is defined. When + * it is undefined they will all be no-ops and generate no code, unless they + * have other side effected (i.e. the _RETURN, _STMT, _BREAK variations). + * + * The assertions build on top of the functions in iprt/assert.h. + * + * @{ + */ + + +/** @def ASSERT_GUEST_PANIC() + * If VBOX_STRICT_GUEST is defined this macro will invoke RTAssertDoPanic if + * RTAssertShouldPanic returns true. If VBOX_STRICT_GUEST isn't defined it won't + * do any thing. + */ +#if defined(VBOX_STRICT_GUEST) && !defined(VBOX_STRICT_GUEST_DONT_PANIC) +# define ASSERT_GUEST_PANIC() do { if (RTAssertShouldPanic()) RTAssertDoPanic(); } while (0) +#else +# define ASSERT_GUEST_PANIC() do { } while (0) +#endif + +/** Wrapper around RTAssertMsg1Weak that prefixes the expression. */ +#define ASSERT_GUEST_MSG1(szExpr, iLine, pszFile, pszFunction) \ + RTAssertMsg1Weak("guest-input: " szExpr, iLine, pszFile, pszFunction) + + +/** @def ASSERT_GUEST + * Assert that an expression is true. If false, hit breakpoint. + * @param a_Expr Expression which should be true. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST(a_Expr) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + } \ + } while (0) +#else +# define ASSERT_GUEST(a_Expr) do { } while (0) +#endif + + +/** @def ASSERT_GUEST_STMT + * Assert that an expression is true. If false, hit breakpoint and execute the + * statement. + * @param a_Expr Expression which should be true. + * @param a_Stmt Statement to execute on failure. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_STMT(a_Expr, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + } \ + } while (0) +#else +# define ASSERT_GUEST_STMT(a_Expr, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + a_Stmt; \ + } \ + } while (0) +#endif + + +/** @def ASSERT_GUEST_RETURN + * Assert that an expression is true and returns if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before returning. + * + * @param a_Expr Expression which should be true. + * @param a_rc What is to be presented to return. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_RETURN(a_Expr, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + return (a_rc); \ + } \ + } while (0) +#else +# define ASSERT_GUEST_RETURN(a_Expr, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + return (a_rc); \ + } while (0) +#endif + +/** @def ASSERT_GUEST_STMT_RETURN + * Assert that an expression is true, if it isn't execute the given statement + * and return rc. + * + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before executing the statement and + * returning. + * + * @param a_Expr Expression which should be true. + * @param a_Stmt Statement to execute before returning on failure. + * @param a_rc What is to be presented to return. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_STMT_RETURN(a_Expr, a_Stmt, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return (a_rc); \ + } \ + } while (0) +#else +# define ASSERT_GUEST_STMT_RETURN(a_Expr, a_Stmt, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + a_Stmt; \ + return (a_rc); \ + } \ + } while (0) +#endif + +/** @def ASSERT_GUEST_RETURN_VOID + * Assert that an expression is true and returns if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before returning. + * + * @param a_Expr Expression which should be true. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_RETURN_VOID(a_Expr) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + return; \ + } \ + } while (0) +#else +# define ASSERT_GUEST_RETURN_VOID(a_Expr) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + return; \ + } while (0) +#endif + +/** @def ASSERT_GUEST_STMT_RETURN_VOID + * Assert that an expression is true, if it isn't execute the given statement + * and return. + * + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before returning. + * + * @param a_Expr Expression which should be true. + * @param a_Stmt Statement to execute before returning on failure. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_STMT_RETURN_VOID(a_Expr, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return; \ + } \ + } while (0) +#else +# define ASSERT_GUEST_STMT_RETURN_VOID(a_Expr, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + a_Stmt; \ + return; \ + } \ + } while (0) +#endif + + +/** @def ASSERT_GUEST_BREAK + * Assert that an expression is true and breaks if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before breaking. + * + * @param a_Expr Expression which should be true. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_BREAK(a_Expr) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + break; \ + } else \ + break +#else +# define ASSERT_GUEST_BREAK(a_Expr) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + break +#endif + +/** @def ASSERT_GUEST_CONTINUE + * Assert that an expression is true and continue if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before continuing. + * + * @param a_Expr Expression which should be true. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_CONTINUE(a_Expr) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + continue; \ + } else do {} while (0) +#else +# define ASSERT_GUEST_CONTINUE(a_Expr) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + continue +#endif + +/** @def ASSERT_GUEST_STMT_BREAK + * Assert that an expression is true and breaks if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before doing break. + * + * @param a_Expr Expression which should be true. + * @param a_Stmt Statement to execute before break in case of a failed assertion. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_STMT_BREAK(a_Expr, a_Stmt) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + break; \ + } else do {} while (0) +#else +# define ASSERT_GUEST_STMT_BREAK(a_Expr, a_Stmt) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + a_Stmt; \ + break; \ + } else do {} while (0) +#endif + + +/** @def ASSERT_GUEST_MSG + * Assert that an expression is true. If it's not print message and hit breakpoint. + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG(a_Expr, a) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + } \ + } while (0) +#else +# define ASSERT_GUEST_MSG(a_Expr, a) do { } while (0) +#endif + +/** @def ASSERT_GUEST_MSG_STMT + * Assert that an expression is true. If it's not print message and hit + * breakpoint and execute the statement. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute in case of a failed assertion. + * + * @remarks The expression and statement will be evaluated in all build types. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_STMT(a_Expr, a, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + } \ + } while (0) +#else +# define ASSERT_GUEST_MSG_STMT(a_Expr, a, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + a_Stmt; \ + } \ + } while (0) +#endif + +/** @def ASSERT_GUEST_MSG_RETURN + * Assert that an expression is true and returns if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before returning. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_rc What is to be presented to return. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_RETURN(a_Expr, a, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + return (a_rc); \ + } \ + } while (0) +#else +# define ASSERT_GUEST_MSG_RETURN(a_Expr, a, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + return (a_rc); \ + } while (0) +#endif + +/** @def ASSERT_GUEST_MSG_STMT_RETURN + * Assert that an expression is true, if it isn't execute the statement and + * return. + * + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before returning. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before returning in case of a failed + * assertion. + * @param a_rc What is to be presented to return. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_STMT_RETURN(a_Expr, a, a_Stmt, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return (a_rc); \ + } \ + } while (0) +#else +# define ASSERT_GUEST_MSG_STMT_RETURN(a_Expr, a, a_Stmt, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + a_Stmt; \ + return (a_rc); \ + } \ + } while (0) +#endif + +/** @def ASSERT_GUEST_MSG_RETURN_VOID + * Assert that an expression is true and returns if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before returning. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_RETURN_VOID(a_Expr, a) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + return; \ + } \ + } while (0) +#else +# define ASSERT_GUEST_MSG_RETURN_VOID(a_Expr, a) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + return; \ + } while (0) +#endif + +/** @def ASSERT_GUEST_MSG_STMT_RETURN_VOID + * Assert that an expression is true, if it isn't execute the statement and + * return. + * + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before returning. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before return in case of a failed assertion. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_STMT_RETURN_VOID(a_Expr, a, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return; \ + } \ + } while (0) +#else +# define ASSERT_GUEST_MSG_STMT_RETURN_VOID(a_Expr, a, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + a_Stmt; \ + return; \ + } \ + } while (0) +#endif + + +/** @def ASSERT_GUEST_MSG_BREAK + * Assert that an expression is true and breaks if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before returning. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_BREAK(a_Expr, a) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + break; \ + } else \ + break +#else +# define ASSERT_GUEST_MSG_BREAK(a_Expr, a) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + break +#endif + +/** @def ASSERT_GUEST_MSG_STMT_BREAK + * Assert that an expression is true and breaks if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before doing break. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before break in case of a failed assertion. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_STMT_BREAK(a_Expr, a, a_Stmt) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + break; \ + } else \ + break +#else +# define ASSERT_GUEST_MSG_STMT_BREAK(a_Expr, a, a_Stmt) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + a_Stmt; \ + break; \ + } else \ + break +#endif + +/** @def ASSERT_GUEST_FAILED + * An assertion failed, hit breakpoint. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_FAILED() \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + } while (0) +#else +# define ASSERT_GUEST_FAILED() do { } while (0) +#endif + +/** @def ASSERT_GUEST_FAILED_STMT + * An assertion failed, hit breakpoint and execute statement. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_FAILED_STMT(a_Stmt) \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + } while (0) +#else +# define ASSERT_GUEST_FAILED_STMT(a_Stmt) do { a_Stmt; } while (0) +#endif + +/** @def ASSERT_GUEST_FAILED_RETURN + * An assertion failed, hit breakpoint (VBOX_STRICT_GUEST mode only) and return. + * + * @param a_rc The a_rc to return. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_FAILED_RETURN(a_rc) \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + return (a_rc); \ + } while (0) +#else +# define ASSERT_GUEST_FAILED_RETURN(a_rc) \ + do { \ + return (a_rc); \ + } while (0) +#endif + +/** @def ASSERT_GUEST_FAILED_STMT_RETURN + * An assertion failed, hit breakpoint (VBOX_STRICT_GUEST mode only), execute a + * statement and return a value. + * + * @param a_Stmt The statement to execute before returning. + * @param a_rc The value to return. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_FAILED_STMT_RETURN(a_Stmt, a_rc) \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return (a_rc); \ + } while (0) +#else +# define ASSERT_GUEST_FAILED_STMT_RETURN(a_Stmt, a_rc) \ + do { \ + a_Stmt; \ + return (a_rc); \ + } while (0) +#endif + +/** @def ASSERT_GUEST_FAILED_RETURN_VOID + * An assertion failed, hit breakpoint (VBOX_STRICT_GUEST mode only) and return. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_FAILED_RETURN_VOID() \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + return; \ + } while (0) +#else +# define ASSERT_GUEST_FAILED_RETURN_VOID() \ + do { \ + return; \ + } while (0) +#endif + +/** @def ASSERT_GUEST_FAILED_STMT_RETURN_VOID + * An assertion failed, hit breakpoint (VBOX_STRICT_GUEST mode only), execute a + * statement and return. + * + * @param a_Stmt The statement to execute before returning. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_FAILED_STMT_RETURN_VOID(a_Stmt) \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return; \ + } while (0) +#else +# define ASSERT_GUEST_FAILED_STMT_RETURN_VOID(a_Stmt) \ + do { \ + a_Stmt; \ + return; \ + } while (0) +#endif + + +/** @def ASSERT_GUEST_FAILED_BREAK + * An assertion failed, hit breakpoint (VBOX_STRICT_GUEST mode only) and break. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_FAILED_BREAK() \ + if (1) { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + break; \ + } else \ + break +#else +# define ASSERT_GUEST_FAILED_BREAK() \ + if (1) \ + break; \ + else \ + break +#endif + +/** @def ASSERT_GUEST_FAILED_STMT_BREAK + * An assertion failed, hit breakpoint (VBOX_STRICT_GUEST mode only), execute + * the given statement and break. + * + * @param a_Stmt Statement to execute before break. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_FAILED_STMT_BREAK(a_Stmt) \ + if (1) { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + break; \ + } else \ + break +#else +# define ASSERT_GUEST_FAILED_STMT_BREAK(a_Stmt) \ + if (1) { \ + a_Stmt; \ + break; \ + } else \ + break +#endif + + +/** @def ASSERT_GUEST_MSG_FAILED + * An assertion failed print a message and a hit breakpoint. + * + * @param a printf argument list (in parenthesis). + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_FAILED(a) \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + } while (0) +#else +# define ASSERT_GUEST_MSG_FAILED(a) do { } while (0) +#endif + +/** @def ASSERT_GUEST_MSG_FAILED_RETURN + * An assertion failed, hit breakpoint with message (VBOX_STRICT_GUEST mode only) and return. + * + * @param a printf argument list (in parenthesis). + * @param a_rc What is to be presented to return. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_FAILED_RETURN(a, a_rc) \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + return (a_rc); \ + } while (0) +#else +# define ASSERT_GUEST_MSG_FAILED_RETURN(a, a_rc) \ + do { \ + return (a_rc); \ + } while (0) +#endif + +/** @def ASSERT_GUEST_MSG_FAILED_RETURN_VOID + * An assertion failed, hit breakpoint with message (VBOX_STRICT_GUEST mode only) and return. + * + * @param a printf argument list (in parenthesis). + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_FAILED_RETURN_VOID(a) \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + return; \ + } while (0) +#else +# define ASSERT_GUEST_MSG_FAILED_RETURN_VOID(a) \ + do { \ + return; \ + } while (0) +#endif + + +/** @def ASSERT_GUEST_MSG_FAILED_BREAK + * An assertion failed, hit breakpoint with message (VBOX_STRICT_GUEST mode only) and break. + * + * @param a printf argument list (in parenthesis). + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_FAILED_BREAK(a) \ + if (1) { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + break; \ + } else \ + break +#else +# define ASSERT_GUEST_MSG_FAILED_BREAK(a) \ + if (1) \ + break; \ + else \ + break +#endif + +/** @def ASSERT_GUEST_MSG_FAILED_STMT_BREAK + * An assertion failed, hit breakpoint (VBOX_STRICT_GUEST mode only), execute + * the given statement and break. + * + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before break. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_FAILED_STMT_BREAK(a, a_Stmt) \ + if (1) { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + break; \ + } else \ + break +#else +# define ASSERT_GUEST_MSG_FAILED_STMT_BREAK(a, a_Stmt) \ + if (1) { \ + a_Stmt; \ + break; \ + } else \ + break +#endif + +/** @} */ + + + +/** @name Guest input release log assertions + * + * These assertions will work like normal strict assertion when VBOX_STRICT_GUEST is + * defined and LogRel statements when VBOX_STRICT_GUEST is undefined. Typically + * used for important guest input that it would be helpful to find in VBox.log + * if the guest doesn't get it right. + * + * @{ + */ + + +/** @def ASSERT_GUEST_LOGREL_MSG1 + * RTAssertMsg1Weak (strict builds) / LogRel wrapper (non-strict). + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_LOGREL_MSG1(szExpr, iLine, pszFile, pszFunction) \ + RTAssertMsg1Weak("guest-input: " szExpr, iLine, pszFile, pszFunction) +#else +# define ASSERT_GUEST_LOGREL_MSG1(szExpr, iLine, pszFile, pszFunction) \ + LogRel(("ASSERT_GUEST_LOGREL %s(%d) %s: %s\n", (pszFile), (iLine), (pszFunction), (szExpr) )) +#endif + +/** @def ASSERT_GUEST_LOGREL_MSG2 + * RTAssertMsg2Weak (strict builds) / LogRel wrapper (non-strict). + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_LOGREL_MSG2(a) RTAssertMsg2Weak a +#else +# define ASSERT_GUEST_LOGREL_MSG2(a) LogRel(a) +#endif + +/** @def ASSERT_GUEST_LOGREL + * Assert that an expression is true. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + */ +#define ASSERT_GUEST_LOGREL(a_Expr) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + } \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_RETURN + * Assert that an expression is true, return \a a_rc if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a_rc What is to be presented to return. + */ +#define ASSERT_GUEST_LOGREL_RETURN(a_Expr, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + return (a_rc); \ + } \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_RETURN_VOID + * Assert that an expression is true, return void if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + */ +#define ASSERT_GUEST_LOGREL_RETURN_VOID(a_Expr) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + return; \ + } \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_BREAK + * Assert that an expression is true, break if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + */ +#define ASSERT_GUEST_LOGREL_BREAK(a_Expr) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + break; \ + } \ + else \ + break + +/** @def ASSERT_GUEST_LOGREL_STMT_BREAK + * Assert that an expression is true, execute \a a_Stmt and break if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a_Stmt Statement to execute before break in case of a failed assertion. + */ +#define ASSERT_GUEST_LOGREL_STMT_BREAK(a_Expr, a_Stmt) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + break; \ + } else \ + break + +/** @def ASSERT_GUEST_LOGREL_MSG + * Assert that an expression is true. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#define ASSERT_GUEST_LOGREL_MSG(a_Expr, a) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else\ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + } \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_STMT + * Assert that an expression is true, execute \a a_Stmt and break if it isn't + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute in case of a failed assertion. + */ +#define ASSERT_GUEST_LOGREL_MSG_STMT(a_Expr, a, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else\ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + } \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RETURN + * Assert that an expression is true, return \a a_rc if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_rc What is to be presented to return. + */ +#define ASSERT_GUEST_LOGREL_MSG_RETURN(a_Expr, a, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else\ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + return (a_rc); \ + } \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_STMT_RETURN + * Assert that an expression is true, execute @a a_Stmt and return @a rcRet if it + * isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + */ +#define ASSERT_GUEST_LOGREL_MSG_STMT_RETURN(a_Expr, a, a_Stmt, rcRet) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else\ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return (rcRet); \ + } \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RETURN_VOID + * Assert that an expression is true, return (void) if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#define ASSERT_GUEST_LOGREL_MSG_RETURN_VOID(a_Expr, a) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else\ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + return; \ + } \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_BREAK + * Assert that an expression is true, break if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#define ASSERT_GUEST_LOGREL_MSG_BREAK(a_Expr, a) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + break; \ + } \ + else \ + break + +/** @def ASSERT_GUEST_LOGREL_MSG_STMT_BREAK + * Assert that an expression is true, execute \a a_Stmt and break if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before break in case of a failed assertion. + */ +#define ASSERT_GUEST_LOGREL_MSG_STMT_BREAK(a_Expr, a, a_Stmt) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + break; \ + } else \ + break + +/** @def ASSERT_GUEST_LOGREL_FAILED + * An assertion failed. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + */ +#define ASSERT_GUEST_LOGREL_FAILED() \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_FAILED_RETURN + * An assertion failed. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_rc What is to be presented to return. + */ +#define ASSERT_GUEST_LOGREL_FAILED_RETURN(a_rc) \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + return (a_rc); \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_FAILED_RETURN_VOID + * An assertion failed, hit a breakpoint and return. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + */ +#define ASSERT_GUEST_LOGREL_FAILED_RETURN_VOID() \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + return; \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_FAILED_BREAK + * An assertion failed, break. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + */ +#define ASSERT_GUEST_LOGREL_FAILED_BREAK() \ + if (1) \ + { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + break; \ + } else \ + break + +/** @def ASSERT_GUEST_LOGREL_FAILED_STMT_BREAK + * An assertion failed, execute \a a_Stmt and break. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Stmt Statement to execute before break. + */ +#define ASSERT_GUEST_LOGREL_FAILED_STMT_BREAK(a_Stmt) \ + if (1) \ + { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + break; \ + } else \ + break + +/** @def ASSERT_GUEST_LOGREL_MSG_FAILED + * An assertion failed. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + */ +#define ASSERT_GUEST_LOGREL_MSG_FAILED(a) \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_FAILED_STMT + * An assertion failed, execute @a a_Stmt. + * + * Strict builds will hit a breakpoint, non-strict will only do LogRel. The + * statement will be executed in regardless of build type. + * + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute after raising/logging the assertion. + */ +#define ASSERT_GUEST_LOGREL_MSG_FAILED_STMT(a, a_Stmt) \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_FAILED_RETURN + * An assertion failed, return \a a_rc. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + * @param a_rc What is to be presented to return. + */ +#define ASSERT_GUEST_LOGREL_MSG_FAILED_RETURN(a, a_rc) \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + return (a_rc); \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_FAILED_STMT_RETURN + * An assertion failed, execute @a a_Stmt and return @a a_rc. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before returning in case of a failed + * assertion. + * @param a_rc What is to be presented to return. + */ +#define ASSERT_GUEST_LOGREL_MSG_FAILED_STMT_RETURN(a, a_Stmt, a_rc) \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return (a_rc); \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_FAILED_RETURN_VOID + * An assertion failed, return void. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + */ +#define ASSERT_GUEST_LOGREL_MSG_FAILED_RETURN_VOID(a) \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + return; \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_FAILED_STMT_RETURN_VOID + * An assertion failed, execute @a a_Stmt and return void. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before returning in case of a failed + * assertion. + */ +#define ASSERT_GUEST_LOGREL_MSG_FAILED_STMT_RETURN_VOID(a, a_Stmt) \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return; \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_FAILED_BREAK + * An assertion failed, break. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + */ +#define ASSERT_GUEST_LOGREL_MSG_FAILED_BREAK(a) \ + if (1)\ + { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + break; \ + } else \ + break + +/** @def ASSERT_GUEST_LOGREL_MSG_FAILED_STMT_BREAK + * An assertion failed, execute \a a_Stmt and break. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before break. + */ +#define ASSERT_GUEST_LOGREL_MSG_FAILED_STMT_BREAK(a, a_Stmt) \ + if (1) \ + { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + break; \ + } else \ + break + +/** @} */ + + +/** @name Convenience Assertions Macros + * @{ + */ + +/** @def ASSERT_GUEST_RC + * Asserts a iprt status code successful. + * + * On failure it will print info about the rc and hit a breakpoint. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC(rc) ASSERT_GUEST_MSG_RC(rc, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_RC_STMT + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and execute + * @a stmt if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_STMT(rc, stmt) ASSERT_GUEST_MSG_RC_STMT(rc, ("%Rra\n", (rc)), stmt) + +/** @def ASSERT_GUEST_RC_RETURN + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_RETURN(rc, rcRet) ASSERT_GUEST_MSG_RC_RETURN(rc, ("%Rra\n", (rc)), rcRet) + +/** @def ASSERT_GUEST_RC_STMT_RETURN + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and returns @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_STMT_RETURN(rc, stmt, rcRet) ASSERT_GUEST_MSG_RC_STMT_RETURN(rc, ("%Rra\n", (rc)), stmt, rcRet) + +/** @def ASSERT_GUEST_RC_RETURN_VOID + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_RETURN_VOID(rc) ASSERT_GUEST_MSG_RC_RETURN_VOID(rc, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_RC_STMT_RETURN_VOID + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), and + * execute the given statement/return if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning on failure. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_STMT_RETURN_VOID(rc, stmt) ASSERT_GUEST_MSG_RC_STMT_RETURN_VOID(rc, ("%Rra\n", (rc)), stmt) + +/** @def ASSERT_GUEST_RC_BREAK + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_BREAK(rc) ASSERT_GUEST_MSG_RC_BREAK(rc, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_RC_STMT_BREAK + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_STMT_BREAK(rc, stmt) ASSERT_GUEST_MSG_RC_STMT_BREAK(rc, ("%Rra\n", (rc)), stmt) + +/** @def ASSERT_GUEST_MSG_RC + * Asserts a iprt status code successful. + * + * It prints a custom message and hits a breakpoint on FAILURE. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_MSG_RC(rc, msg) \ + do { ASSERT_GUEST_MSG(RT_SUCCESS_NP(rc), msg); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_MSG_RC_STMT + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and + * execute @a stmt if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_MSG_RC_STMT(rc, msg, stmt) \ + do { ASSERT_GUEST_MSG_STMT(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_MSG_RC_RETURN + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return + * @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_MSG_RC_RETURN(rc, msg, rcRet) \ + do { ASSERT_GUEST_MSG_RETURN(RT_SUCCESS_NP(rc), msg, rcRet); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_MSG_RC_STMT_RETURN + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and return @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_MSG_RC_STMT_RETURN(rc, msg, stmt, rcRet) \ + do { ASSERT_GUEST_MSG_STMT_RETURN(RT_SUCCESS_NP(rc), msg, stmt, rcRet); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_MSG_RC_RETURN_VOID + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return + * void if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_MSG_RC_RETURN_VOID(rc, msg) \ + do { ASSERT_GUEST_MSG_RETURN_VOID(RT_SUCCESS_NP(rc), msg); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_MSG_RC_STMT_RETURN_VOID + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and return void if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_MSG_RC_STMT_RETURN_VOID(rc, msg, stmt) \ + do { ASSERT_GUEST_MSG_STMT_RETURN_VOID(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_MSG_RC_BREAK + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break + * if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_MSG_RC_BREAK(rc, msg) \ + if (1) { ASSERT_GUEST_MSG_BREAK(RT_SUCCESS(rc), msg); NOREF(rc); } else do {} while (0) + +/** @def ASSERT_GUEST_MSG_RC_STMT_BREAK + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and break if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_MSG_RC_STMT_BREAK(rc, msg, stmt) \ + if (1) { ASSERT_GUEST_MSG_STMT_BREAK(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } else do {} while (0) + +/** @def ASSERT_GUEST_RC_SUCCESS + * Asserts an iprt status code equals VINF_SUCCESS. + * + * On failure it will print info about the rc and hit a breakpoint. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_SUCCESS(rc) do { ASSERT_GUEST_MSG((rc) == VINF_SUCCESS, ("%Rra\n", (rc))); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_RC_SUCCESS_RETURN + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_SUCCESS_RETURN(rc, rcRet) ASSERT_GUEST_MSG_RETURN((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), rcRet) + +/** @def ASSERT_GUEST_RC_SUCCESS_RETURN_VOID + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_SUCCESS_RETURN_VOID(rc) ASSERT_GUEST_MSG_RETURN_VOID((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_RC_SUCCESS_BREAK + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_SUCCESS_BREAK(rc) ASSERT_GUEST_MSG_BREAK((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_RC_SUCCESS_STMT_BREAK + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_SUCCESS_STMT_BREAK(rc, stmt) ASSERT_GUEST_MSG_STMT_BREAK((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), stmt) + +/** @def ASSERT_GUEST_GCPHYS32 + * Asserts that the high dword of a physical address is zero + * + * @param GCPhys The address (RTGCPHYS). + */ +#define ASSERT_GUEST_GCPHYS32(GCPhys) ASSERT_GUEST_MSG(VALID_PHYS32(GCPhys), ("%RGp\n", (RTGCPHYS)(GCPhys))) + + +/** @def ASSERT_GUEST_RC + * Asserts a iprt status code successful. + * + * On failure it will print info about the rc and hit a breakpoint. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC(rc) ASSERT_GUEST_LOGREL_MSG_RC(rc, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_LOGREL_RC_STMT + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and execute + * @a stmt if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_STMT(rc, stmt) ASSERT_GUEST_LOGREL_MSG_RC_STMT(rc, ("%Rra\n", (rc)), stmt) + +/** @def ASSERT_GUEST_LOGREL_RC_RETURN + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_RETURN(rc, rcRet) ASSERT_GUEST_LOGREL_MSG_RC_RETURN(rc, ("%Rra\n", (rc)), rcRet) + +/** @def ASSERT_GUEST_LOGREL_RC_STMT_RETURN + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and returns @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_STMT_RETURN(rc, stmt, rcRet) ASSERT_GUEST_LOGREL_MSG_RC_STMT_RETURN(rc, ("%Rra\n", (rc)), stmt, rcRet) + +/** @def ASSERT_GUEST_LOGREL_RC_RETURN_VOID + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_RETURN_VOID(rc) ASSERT_GUEST_LOGREL_MSG_RC_RETURN_VOID(rc, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_LOGREL_RC_STMT_RETURN_VOID + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), and + * execute the given statement/return if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning on failure. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_STMT_RETURN_VOID(rc, stmt) ASSERT_GUEST_LOGREL_MSG_RC_STMT_RETURN_VOID(rc, ("%Rra\n", (rc)), stmt) + +/** @def ASSERT_GUEST_LOGREL_RC_BREAK + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_BREAK(rc) ASSERT_GUEST_LOGREL_MSG_RC_BREAK(rc, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_LOGREL_RC_STMT_BREAK + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_STMT_BREAK(rc, stmt) ASSERT_GUEST_LOGREL_MSG_RC_STMT_BREAK(rc, ("%Rra\n", (rc)), stmt) + +/** @def ASSERT_GUEST_LOGREL_MSG_RC + * Asserts a iprt status code successful. + * + * It prints a custom message and hits a breakpoint on FAILURE. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_MSG_RC(rc, msg) \ + do { ASSERT_GUEST_LOGREL_MSG(RT_SUCCESS_NP(rc), msg); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RC_STMT + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and + * execute @a stmt if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_MSG_RC_STMT(rc, msg, stmt) \ + do { ASSERT_GUEST_LOGREL_MSG_STMT(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RC_RETURN + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return + * @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_MSG_RC_RETURN(rc, msg, rcRet) \ + do { ASSERT_GUEST_LOGREL_MSG_RETURN(RT_SUCCESS_NP(rc), msg, rcRet); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RC_STMT_RETURN + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and return @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_MSG_RC_STMT_RETURN(rc, msg, stmt, rcRet) \ + do { ASSERT_GUEST_LOGREL_MSG_STMT_RETURN(RT_SUCCESS_NP(rc), msg, stmt, rcRet); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RC_RETURN_VOID + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return + * void if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_MSG_RC_RETURN_VOID(rc, msg) \ + do { ASSERT_GUEST_LOGREL_MSG_RETURN_VOID(RT_SUCCESS_NP(rc), msg); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RC_STMT_RETURN_VOID + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and return void if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_MSG_RC_STMT_RETURN_VOID(rc, msg, stmt) \ + do { ASSERT_GUEST_LOGREL_MSG_STMT_RETURN_VOID(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RC_BREAK + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break + * if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_MSG_RC_BREAK(rc, msg) \ + if (1) { ASSERT_GUEST_LOGREL_MSG_BREAK(RT_SUCCESS(rc), msg); NOREF(rc); } else do {} while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RC_STMT_BREAK + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and break if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_MSG_RC_STMT_BREAK(rc, msg, stmt) \ + if (1) { ASSERT_GUEST_LOGREL_MSG_STMT_BREAK(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } else do {} while (0) + +/** @def ASSERT_GUEST_LOGREL_RC_SUCCESS + * Asserts an iprt status code equals VINF_SUCCESS. + * + * On failure it will print info about the rc and hit a breakpoint. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_SUCCESS(rc) do { ASSERT_GUEST_LOGREL_MSG((rc) == VINF_SUCCESS, ("%Rra\n", (rc))); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_LOGREL_RC_SUCCESS_RETURN + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_SUCCESS_RETURN(rc, rcRet) ASSERT_GUEST_LOGREL_MSG_RETURN((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), rcRet) + +/** @def ASSERT_GUEST_LOGREL_RC_SUCCESS_RETURN_VOID + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_SUCCESS_RETURN_VOID(rc) ASSERT_GUEST_LOGREL_MSG_RETURN_VOID((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_LOGREL_RC_SUCCESS_BREAK + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_SUCCESS_BREAK(rc) ASSERT_GUEST_LOGREL_MSG_BREAK((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_LOGREL_RC_SUCCESS_STMT_BREAK + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_SUCCESS_STMT_BREAK(rc, stmt) ASSERT_GUEST_LOGREL_MSG_STMT_BREAK((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), stmt) + +/** @def ASSERT_GUEST_LOGREL_GCPHYS32 + * Asserts that the high dword of a physical address is zero + * + * @param GCPhys The address (RTGCPHYS). + */ +#define ASSERT_GUEST_LOGREL_GCPHYS32(GCPhys) ASSERT_GUEST_LOGREL_MSG(VALID_PHYS32(GCPhys), ("%RGp\n", (RTGCPHYS)(GCPhys))) + + +/** @} */ + + +/** @} */ + +#endif /* !VBOX_INCLUDED_AssertGuest_h */ + diff --git a/include/VBox/ExtPack/ExtPack.h b/include/VBox/ExtPack/ExtPack.h new file mode 100644 index 00000000..61f415c3 --- /dev/null +++ b/include/VBox/ExtPack/ExtPack.h @@ -0,0 +1,647 @@ +/** @file + * VirtualBox - Extension Pack Interface. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_ExtPack_ExtPack_h +#define VBOX_INCLUDED_ExtPack_ExtPack_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + +/** @def VBOXEXTPACK_IF_CS + * Selects 'class' on 'struct' for interface references. + * @param I The interface name + */ +#if defined(__cplusplus) && !defined(RT_OS_WINDOWS) +# define VBOXEXTPACK_IF_CS(I) class I +#else +# define VBOXEXTPACK_IF_CS(I) struct I +#endif + +VBOXEXTPACK_IF_CS(IUnknown); +VBOXEXTPACK_IF_CS(IConsole); +VBOXEXTPACK_IF_CS(IMachine); +VBOXEXTPACK_IF_CS(IVirtualBox); +VBOXEXTPACK_IF_CS(IProgress); +VBOXEXTPACK_IF_CS(IEvent); +VBOXEXTPACK_IF_CS(IVetoEvent); +VBOXEXTPACK_IF_CS(IEventSource); + +/** + * Module kind for use with VBOXEXTPACKHLP::pfnFindModule. + */ +typedef enum VBOXEXTPACKMODKIND +{ + /** Zero is invalid as always. */ + VBOXEXTPACKMODKIND_INVALID = 0, + /** Raw-mode context module. */ + VBOXEXTPACKMODKIND_RC, + /** Ring-0 context module. */ + VBOXEXTPACKMODKIND_R0, + /** Ring-3 context module. */ + VBOXEXTPACKMODKIND_R3, + /** End of the valid values (exclusive). */ + VBOXEXTPACKMODKIND_END, + /** The usual 32-bit type hack. */ + VBOXEXTPACKMODKIND_32BIT_HACK = 0x7fffffff +} VBOXEXTPACKMODKIND; + +/** + * Contexts returned by VBOXEXTPACKHLP::pfnGetContext. + */ +typedef enum VBOXEXTPACKCTX +{ + /** Zero is invalid as always. */ + VBOXEXTPACKCTX_INVALID = 0, + /** The per-user daemon process (VBoxSVC). */ + VBOXEXTPACKCTX_PER_USER_DAEMON, + /** A VM process. */ + VBOXEXTPACKCTX_VM_PROCESS, + /** An API client process. + * @remarks This will not be returned by VirtualBox yet. */ + VBOXEXTPACKCTX_CLIENT_PROCESS, + /** End of the valid values (exclusive). */ + VBOXEXTPACKCTX_END, + /** The usual 32-bit type hack. */ + VBOXEXTPACKCTX_32BIT_HACK = 0x7fffffff +} VBOXEXTPACKCTX; + + +/** Pointer to const helpers passed to the VBoxExtPackRegister() call. */ +typedef const struct VBOXEXTPACKHLP *PCVBOXEXTPACKHLP; +/** + * Extension pack helpers passed to VBoxExtPackRegister(). + * + * This will be valid until the module is unloaded. + */ +typedef struct VBOXEXTPACKHLP +{ + /** Interface version. + * This is set to VBOXEXTPACKHLP_VERSION. */ + uint32_t u32Version; + + /** The VirtualBox full version (see VBOX_FULL_VERSION). */ + uint32_t uVBoxFullVersion; + /** The VirtualBox subversion tree revision. */ + uint32_t uVBoxInternalRevision; + /** Explicit alignment padding, must be zero. */ + uint32_t u32Padding; + /** Pointer to the version string (read-only). */ + const char *pszVBoxVersion; + + /** + * Finds a module belonging to this extension pack. + * + * @returns VBox status code. + * @param pHlp Pointer to this helper structure. + * @param pszName The module base name. + * @param pszExt The extension. If NULL the default ring-3 + * library extension will be used. + * @param enmKind The kind of module to locate. + * @param pszFound Where to return the path to the module on + * success. + * @param cbFound The size of the buffer @a pszFound points to. + * @param pfNative Where to return the native/agnostic indicator. + */ + DECLR3CALLBACKMEMBER(int, pfnFindModule,(PCVBOXEXTPACKHLP pHlp, const char *pszName, const char *pszExt, + VBOXEXTPACKMODKIND enmKind, + char *pszFound, size_t cbFound, bool *pfNative)); + + /** + * Gets the path to a file belonging to this extension pack. + * + * @returns VBox status code. + * @retval VERR_INVALID_POINTER if any of the pointers are invalid. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. The buffer + * will contain nothing. + * + * @param pHlp Pointer to this helper structure. + * @param pszFilename The filename. + * @param pszPath Where to return the path to the file on + * success. + * @param cbPath The size of the buffer @a pszPath. + */ + DECLR3CALLBACKMEMBER(int, pfnGetFilePath,(PCVBOXEXTPACKHLP pHlp, const char *pszFilename, char *pszPath, size_t cbPath)); + + /** + * Gets the context the extension pack is operating in. + * + * @returns The context. + * @retval VBOXEXTPACKCTX_INVALID if @a pHlp is invalid. + * + * @param pHlp Pointer to this helper structure. + */ + DECLR3CALLBACKMEMBER(VBOXEXTPACKCTX, pfnGetContext,(PCVBOXEXTPACKHLP pHlp)); + + /** + * Loads a HGCM service provided by an extension pack. + * + * @returns VBox status code. + * @param pHlp Pointer to this helper structure. + * @param pConsole Pointer to the VM's console object. + * @param pszServiceLibrary Name of the library file containing the + * service implementation, without extension. + * @param pszServiceName Name of HGCM service. + */ + DECLR3CALLBACKMEMBER(int, pfnLoadHGCMService,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IConsole) *pConsole, + const char *pszServiceLibrary, const char *pszServiceName)); + + /** + * Loads a VD plugin provided by an extension pack. + * + * This makes sense only in the context of the per-user service (VBoxSVC). + * + * @returns VBox status code. + * @param pHlp Pointer to this helper structure. + * @param pVirtualBox Pointer to the VirtualBox object. + * @param pszPluginLibrary Name of the library file containing the plugin + * implementation, without extension. + */ + DECLR3CALLBACKMEMBER(int, pfnLoadVDPlugin,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IVirtualBox) *pVirtualBox, + const char *pszPluginLibrary)); + + /** + * Unloads a VD plugin provided by an extension pack. + * + * This makes sense only in the context of the per-user service (VBoxSVC). + * + * @returns VBox status code. + * @param pHlp Pointer to this helper structure. + * @param pVirtualBox Pointer to the VirtualBox object. + * @param pszPluginLibrary Name of the library file containing the plugin + * implementation, without extension. + */ + DECLR3CALLBACKMEMBER(int, pfnUnloadVDPlugin,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IVirtualBox) *pVirtualBox, + const char *pszPluginLibrary)); + + /** + * Creates an IProgress object instance for a long running extension + * pack provided API operation which is executed asynchronously. + * + * This implicitly creates a cancellable progress object, since anything + * else is user unfriendly. You need to design your code to handle + * cancellation with reasonable response time. + * + * @returns COM status code. + * @param pHlp Pointer to this helper structure. + * @param pInitiator Pointer to the initiating object. + * @param pcszDescription Description of the overall task. + * @param cOperations Number of operations for this task. + * @param uTotalOperationsWeight Overall weight for the entire task. + * @param pcszFirstOperationDescription Description of the first operation. + * @param uFirstOperationWeight Weight for the first operation. + * @param ppProgressOut Output parameter for the IProgress object reference. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnCreateProgress,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IUnknown) *pInitiator, + const char *pcszDescription, uint32_t cOperations, + uint32_t uTotalOperationsWeight, const char *pcszFirstOperationDescription, + uint32_t uFirstOperationWeight, VBOXEXTPACK_IF_CS(IProgress) **ppProgressOut)); + + /** + * Checks if the Progress object is marked as canceled. + * + * @returns COM status code. + * @param pHlp Pointer to this helper structure. + * @param pProgress Pointer to the IProgress object reference returned + * by pfnCreateProgress. + * @param pfCanceled @c true if canceled, @c false otherwise. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetCanceledProgress,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress, + bool *pfCanceled)); + + /** + * Updates the percentage value of the current operation of the + * Progress object. + * + * @returns COM status code. + * @param pHlp Pointer to this helper structure. + * @param pProgress Pointer to the IProgress object reference returned + * by pfnCreateProgress. + * @param uPercent Result of the overall task. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnUpdateProgress,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress, + uint32_t uPercent)); + + /** + * Signals that the current operation is successfully completed and + * advances to the next operation. The operation percentage is reset + * to 0. + * + * If the operation count is exceeded this returns an error. + * + * @returns COM status code. + * @param pHlp Pointer to this helper structure. + * @param pProgress Pointer to the IProgress object reference returned + * by pfnCreateProgress. + * @param pcszNextOperationDescription Description of the next operation. + * @param uNextOperationWeight Weight for the next operation. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnNextOperationProgress,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress, + const char *pcszNextOperationDescription, + uint32_t uNextOperationWeight)); + + /** + * Waits until the other task is completed (including all sub-operations) + * and forward all changes from the other progress to this progress. This + * means sub-operation number, description, percent and so on. + * + * The caller is responsible for having at least the same count of + * sub-operations in this progress object as there are in the other + * progress object. + * + * If the other progress object supports cancel and this object gets any + * cancel request (when here enabled as well), it will be forwarded to + * the other progress object. + * + * Error information is automatically preserved (by transferring it to + * the current thread's error information). If the caller wants to set it + * as the completion state of this progress it needs to be done separately. + * + * @returns COM status code. + * @param pHlp Pointer to this helper structure. + * @param pProgress Pointer to the IProgress object reference returned + * by pfnCreateProgress. + * @param pProgressOther Pointer to an IProgress object reference, the one + * to be waited for. + * @param cTimeoutMS Timeout in milliseconds, 0 for indefinite wait. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnWaitOtherProgress,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress, + VBOXEXTPACK_IF_CS(IProgress) *pProgressOther, + uint32_t cTimeoutMS)); + + /** + * Marks the whole task as complete and sets the result code. + * + * If the result code indicates a failure then this method will store + * the currently set COM error info from the current thread in the + * the errorInfo attribute of this Progress object instance. If there + * is no error information available then an error is returned. + * + * If the result code indicates success then the task is terminated, + * without paying attention to the current operation being the last. + * + * Note that this must be called only once for the given Progress + * object. Subsequent calls will return errors. + * + * @returns COM status code. + * @param pHlp Pointer to this helper structure. + * @param pProgress Pointer to the IProgress object reference returned + * by pfnCreateProgress. + * @param uResultCode Result of the overall task. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnCompleteProgress,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress, + uint32_t uResultCode)); + + + DECLR3CALLBACKMEMBER(uint32_t, pfnCreateEvent,(PCVBOXEXTPACKHLP pHlp, + VBOXEXTPACK_IF_CS(IEventSource) *aSource, + /* VBoxEventType_T */ uint32_t aType, bool aWaitable, + VBOXEXTPACK_IF_CS(IEvent) **ppEventOut)); + + DECLR3CALLBACKMEMBER(uint32_t, pfnCreateVetoEvent,(PCVBOXEXTPACKHLP pHlp, + VBOXEXTPACK_IF_CS(IEventSource) *aSource, + /* VBoxEventType_T */ uint32_t aType, + VBOXEXTPACK_IF_CS(IVetoEvent) **ppEventOut)); + + /** + * Translate the string using registered translation files. + * + * Translation files are excluded from translation engine. Although + * the already loaded translation remains in the translation cache the new + * translation will not be loaded after returning from the function if the + * user changes the language. + * + * @returns Translated string on success the pszSourceText otherwise. + * @param pHlp Pointer to this helper structure. + * @param aComponent Translation context e.g. class name + * @param pszSourceText String to translate + * @param pszComment Comment to the string to resolve possible ambiguities + * (NULL means no comment). + * @param aNum Number used to define plural form of the translation + */ + DECLR3CALLBACKMEMBER(const char *, pfnTranslate,(PCVBOXEXTPACKHLP pHlp, + const char *pszComponent, + const char *pszSourceText, + const char *pszComment, + const size_t aNum)); + + DECLR3CALLBACKMEMBER(int, pfnReserved1,(PCVBOXEXTPACKHLP pHlp)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved2,(PCVBOXEXTPACKHLP pHlp)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved3,(PCVBOXEXTPACKHLP pHlp)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved4,(PCVBOXEXTPACKHLP pHlp)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved5,(PCVBOXEXTPACKHLP pHlp)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved6,(PCVBOXEXTPACKHLP pHlp)); /**< Reserved for minor structure revisions. */ + + /** Reserved for minor structure revisions. */ + uint32_t uReserved7; + + /** End of structure marker (VBOXEXTPACKHLP_VERSION). */ + uint32_t u32EndMarker; +} VBOXEXTPACKHLP; +/** Current version of the VBOXEXTPACKHLP structure. */ +#define VBOXEXTPACKHLP_VERSION RT_MAKE_U32(0, 5) + + +/** Pointer to the extension pack callback table. */ +typedef struct VBOXEXTPACKREG const *PCVBOXEXTPACKREG; +/** + * Callback table returned by VBoxExtPackRegister. + * + * All the callbacks are called the context of the per-user service (VBoxSVC). + * + * This must be valid until the extension pack main module is unloaded. + */ +typedef struct VBOXEXTPACKREG +{ + /** Interface version. + * This is set to VBOXEXTPACKREG_VERSION. */ + uint32_t u32Version; + /** The VirtualBox version this extension pack was built against. */ + uint32_t uVBoxVersion; + /** Translation files base name. Set to NULL if no translation files. */ + const char *pszNlsBaseName; + + /** + * Hook for doing setups after the extension pack was installed. + * + * @returns VBox status code. + * @retval VERR_EXTPACK_UNSUPPORTED_HOST_UNINSTALL if the extension pack + * requires some different host version or a prerequisite is + * missing from the host. Automatic uninstall will be attempted. + * Must set error info. + * + * @param pThis Pointer to this structure. + * @param pVirtualBox The VirtualBox interface. + * @param pErrInfo Where to return extended error information. + */ + DECLCALLBACKMEMBER(int, pfnInstalled,(PCVBOXEXTPACKREG pThis, VBOXEXTPACK_IF_CS(IVirtualBox) *pVirtualBox, + PRTERRINFO pErrInfo)); + + /** + * Hook for cleaning up before the extension pack is uninstalled. + * + * @returns VBox status code. + * @param pThis Pointer to this structure. + * @param pVirtualBox The VirtualBox interface. + * + * @todo This is currently called holding locks making pVirtualBox + * relatively unusable. + */ + DECLCALLBACKMEMBER(int, pfnUninstall,(PCVBOXEXTPACKREG pThis, VBOXEXTPACK_IF_CS(IVirtualBox) *pVirtualBox)); + + /** + * Hook for doing work after the VirtualBox object is ready. + * + * @param pThis Pointer to this structure. + * @param pVirtualBox The VirtualBox interface. + */ + DECLCALLBACKMEMBER(void, pfnVirtualBoxReady,(PCVBOXEXTPACKREG pThis, VBOXEXTPACK_IF_CS(IVirtualBox) *pVirtualBox)); + + /** + * Hook for doing work before unloading. + * + * @param pThis Pointer to this structure. + * + * @remarks The helpers are not available at this point in time. + * @remarks This is not called on uninstall, then pfnUninstall will be the + * last callback. + */ + DECLCALLBACKMEMBER(void, pfnUnload,(PCVBOXEXTPACKREG pThis)); + + /** + * Hook for changing the default VM configuration upon creation. + * + * @returns VBox status code. + * @param pThis Pointer to this structure. + * @param pVirtualBox The VirtualBox interface. + * @param pMachine The machine interface. + */ + DECLCALLBACKMEMBER(int, pfnVMCreated,(PCVBOXEXTPACKREG pThis, VBOXEXTPACK_IF_CS(IVirtualBox) *pVirtualBox, + VBOXEXTPACK_IF_CS(IMachine) *pMachine)); + + /** + * Query the IUnknown interface to an object in the main module. + * + * @returns IUnknown pointer (referenced) on success, NULL on failure. + * @param pThis Pointer to this structure. + * @param pObjectId Pointer to the object ID (UUID). + */ + DECLCALLBACKMEMBER(void *, pfnQueryObject,(PCVBOXEXTPACKREG pThis, PCRTUUID pObjectId)); + + DECLR3CALLBACKMEMBER(int, pfnReserved1,(PCVBOXEXTPACKREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved2,(PCVBOXEXTPACKREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved3,(PCVBOXEXTPACKREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved4,(PCVBOXEXTPACKREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved5,(PCVBOXEXTPACKREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved6,(PCVBOXEXTPACKREG pThis)); /**< Reserved for minor structure revisions. */ + + /** Reserved for minor structure revisions. */ + uint32_t uReserved7; + + /** End of structure marker (VBOXEXTPACKREG_VERSION). */ + uint32_t u32EndMarker; +} VBOXEXTPACKREG; +/** Current version of the VBOXEXTPACKREG structure. */ +#define VBOXEXTPACKREG_VERSION RT_MAKE_U32(0, 3) + + +/** + * The VBoxExtPackRegister callback function. + * + * The Main API (as in VBoxSVC) will invoke this function after loading an + * extension pack Main module. Its job is to do version compatibility checking + * and returning the extension pack registration structure. + * + * @returns VBox status code. + * @param pHlp Pointer to the extension pack helper function + * table. This is valid until the module is unloaded. + * @param ppReg Where to return the pointer to the registration + * structure containing all the hooks. This structure + * be valid and unchanged until the module is unloaded + * (i.e. use some static const data for it). + * @param pErrInfo Where to return extended error information. + */ +typedef DECLCALLBACKTYPE(int, FNVBOXEXTPACKREGISTER,(PCVBOXEXTPACKHLP pHlp, PCVBOXEXTPACKREG *ppReg, PRTERRINFO pErrInfo)); +/** Pointer to a FNVBOXEXTPACKREGISTER. */ +typedef FNVBOXEXTPACKREGISTER *PFNVBOXEXTPACKREGISTER; + +/** The name of the main module entry point. */ +#define VBOX_EXTPACK_MAIN_MOD_ENTRY_POINT "VBoxExtPackRegister" + + +/** Pointer to the extension pack VM callback table. */ +typedef struct VBOXEXTPACKVMREG const *PCVBOXEXTPACKVMREG; +/** + * Callback table returned by VBoxExtPackVMRegister. + * + * All the callbacks are called the context of a VM process. + * + * This must be valid until the extension pack main VM module is unloaded. + */ +typedef struct VBOXEXTPACKVMREG +{ + /** Interface version. + * This is set to VBOXEXTPACKVMREG_VERSION. */ + uint32_t u32Version; + /** The VirtualBox version this extension pack was built against. */ + uint32_t uVBoxVersion; + /** Translation files base name. Set to NULL if no translation files. */ + const char *pszNlsBaseName; + + /** + * Hook for doing work after the Console object is ready. + * + * @param pThis Pointer to this structure. + * @param pConsole The Console interface. + */ + DECLCALLBACKMEMBER(void, pfnConsoleReady,(PCVBOXEXTPACKVMREG pThis, VBOXEXTPACK_IF_CS(IConsole) *pConsole)); + + /** + * Hook for doing work before unloading. + * + * @param pThis Pointer to this structure. + * + * @remarks The helpers are not available at this point in time. + */ + DECLCALLBACKMEMBER(void, pfnUnload,(PCVBOXEXTPACKVMREG pThis)); + + /** + * Hook for configuring the VMM for a VM. + * + * @returns VBox status code. + * @param pThis Pointer to this structure. + * @param pConsole The console interface. + * @param pVM The cross context VM structure. + * @param pVMM The VMM function table. + */ + DECLCALLBACKMEMBER(int, pfnVMConfigureVMM,(PCVBOXEXTPACKVMREG pThis, VBOXEXTPACK_IF_CS(IConsole) *pConsole, + PVM pVM, PCVMMR3VTABLE pVMM)); + + /** + * Hook for doing work right before powering on the VM. + * + * @returns VBox status code. + * @param pThis Pointer to this structure. + * @param pConsole The console interface. + * @param pVM The cross context VM structure. + * @param pVMM The VMM function table. + */ + DECLCALLBACKMEMBER(int, pfnVMPowerOn,(PCVBOXEXTPACKVMREG pThis, VBOXEXTPACK_IF_CS(IConsole) *pConsole, + PVM pVM, PCVMMR3VTABLE pVMM)); + + /** + * Hook for doing work after powering off the VM. + * + * @param pThis Pointer to this structure. + * @param pConsole The console interface. + * @param pVM The cross context VM structure. Can be NULL. + * @param pVMM The VMM function table. + */ + DECLCALLBACKMEMBER(void, pfnVMPowerOff,(PCVBOXEXTPACKVMREG pThis, VBOXEXTPACK_IF_CS(IConsole) *pConsole, + PVM pVM, PCVMMR3VTABLE pVMM)); + + /** + * Query the IUnknown interface to an object in the main VM module. + * + * @returns IUnknown pointer (referenced) on success, NULL on failure. + * @param pThis Pointer to this structure. + * @param pObjectId Pointer to the object ID (UUID). + */ + DECLCALLBACKMEMBER(void *, pfnQueryObject,(PCVBOXEXTPACKVMREG pThis, PCRTUUID pObjectId)); + + DECLR3CALLBACKMEMBER(int, pfnReserved1,(PCVBOXEXTPACKVMREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved2,(PCVBOXEXTPACKVMREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved3,(PCVBOXEXTPACKVMREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved4,(PCVBOXEXTPACKVMREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved5,(PCVBOXEXTPACKVMREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved6,(PCVBOXEXTPACKVMREG pThis)); /**< Reserved for minor structure revisions. */ + + /** Reserved for minor structure revisions. */ + uint32_t uReserved7; + + /** End of structure marker (VBOXEXTPACKVMREG_VERSION). */ + uint32_t u32EndMarker; +} VBOXEXTPACKVMREG; +/** Current version of the VBOXEXTPACKVMREG structure. */ +#define VBOXEXTPACKVMREG_VERSION RT_MAKE_U32(1, 0) + + +/** + * The VBoxExtPackVMRegister callback function. + * + * The Main API (in a VM process) will invoke this function after loading an + * extension pack VM module. Its job is to do version compatibility checking + * and returning the extension pack registration structure for a VM. + * + * @returns VBox status code. + * @param pHlp Pointer to the extension pack helper function + * table. This is valid until the module is unloaded. + * @param ppReg Where to return the pointer to the registration + * structure containing all the hooks. This structure + * be valid and unchanged until the module is unloaded + * (i.e. use some static const data for it). + * @param pErrInfo Where to return extended error information. + */ +typedef DECLCALLBACKTYPE(int, FNVBOXEXTPACKVMREGISTER,(PCVBOXEXTPACKHLP pHlp, PCVBOXEXTPACKVMREG *ppReg, PRTERRINFO pErrInfo)); +/** Pointer to a FNVBOXEXTPACKVMREGISTER. */ +typedef FNVBOXEXTPACKVMREGISTER *PFNVBOXEXTPACKVMREGISTER; + +/** The name of the main VM module entry point. */ +#define VBOX_EXTPACK_MAIN_VM_MOD_ENTRY_POINT "VBoxExtPackVMRegister" + + +/** + * Checks if extension pack interface version is compatible. + * + * @returns true if the do, false if they don't. + * @param u32Provider The provider version. + * @param u32User The user version. + */ +#define VBOXEXTPACK_IS_VER_COMPAT(u32Provider, u32User) \ + ( VBOXEXTPACK_IS_MAJOR_VER_EQUAL(u32Provider, u32User) \ + && (int32_t)RT_LOWORD(u32Provider) >= (int32_t)RT_LOWORD(u32User) ) /* stupid casts to shut up gcc */ + +/** + * Check if two extension pack interface versions has the same major version. + * + * @returns true if the do, false if they don't. + * @param u32Ver1 The first version number. + * @param u32Ver2 The second version number. + */ +#define VBOXEXTPACK_IS_MAJOR_VER_EQUAL(u32Ver1, u32Ver2) (RT_HIWORD(u32Ver1) == RT_HIWORD(u32Ver2)) + +#endif /* !VBOX_INCLUDED_ExtPack_ExtPack_h */ + diff --git a/include/VBox/Graphics/HGSMI.h b/include/VBox/Graphics/HGSMI.h new file mode 100644 index 00000000..da485add --- /dev/null +++ b/include/VBox/Graphics/HGSMI.h @@ -0,0 +1,251 @@ +/* $Id: HGSMI.h $ */ +/** @file + * VBox Host Guest Shared Memory Interface (HGSMI) - Host/Guest shared part. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_HGSMI_h +#define VBOX_INCLUDED_Graphics_HGSMI_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBoxVideoIPRT.h" + +#include "HGSMIDefs.h" +#include "HGSMIChannels.h" +#include "HGSMIMemAlloc.h" + +/** + * Basic mechanism for the HGSMI is to prepare and pass data buffer to the host and the guest. + * Data inside these buffers are opaque for the HGSMI and are interpreted by higher levels. + * + * Every shared memory buffer passed between the guest/host has the following structure: + * + * HGSMIBUFFERHEADER header; + * uint8_t data[header.u32BufferSize]; + * HGSMIBUFFERTAIL tail; + * + * Note: Offset of the 'header' in the memory is used for virtual hardware IO. + * + * Buffers are verifyed using the offset and the content of the header and the tail, + * which are constant during a call. + * + * Invalid buffers are ignored. + * + * Actual 'data' is not verifyed, as it is expected that the data can be changed by the + * called function. + * + * Since only the offset of the buffer is passed in a IO operation, the header and tail + * must contain: + * * size of data in this buffer; + * * checksum for buffer verification. + * + * For segmented transfers: + * * the sequence identifier; + * * offset of the current segment in the sequence; + * * total bytes in the transfer. + * + * Additionally contains: + * * the channel ID; + * * the channel information. + */ + +typedef struct HGSMIHEAP +{ + HGSMIAREA area; /**< Description. */ + HGSMIMADATA ma; /**< Memory allocator */ +} HGSMIHEAP; + +/* The size of the array of channels. Array indexes are uint8_t. Note: the value must not be changed. */ +#define HGSMI_NUMBER_OF_CHANNELS 0x100 + +/** + * Channel handler called when the guest submits a buffer. + * + * @returns stuff + * @param pvHandler Value specified when registring. + * @param u16ChannelInfo Command code. + * @param pvBuffer HGSMI buffer with command data. This is shared with + * the guest. Consider untrusted and volatile! + * @param cbBuffer Size of command data. + * @thread EMT on the host side. + */ +typedef DECLCALLBACKTYPE(int, FNHGSMICHANNELHANDLER,(void *pvHandler, uint16_t u16ChannelInfo, + RT_UNTRUSTED_VOLATILE_HSTGST void *pvBuffer, HGSMISIZE cbBuffer)); +/** Pointer to a channel handler callback. */ +typedef FNHGSMICHANNELHANDLER *PFNHGSMICHANNELHANDLER; + +/** Information about a handler: pfn + context. */ +typedef struct _HGSMICHANNELHANDLER +{ + PFNHGSMICHANNELHANDLER pfnHandler; + void *pvHandler; +} HGSMICHANNELHANDLER; + +/** Channel description. */ +typedef struct _HGSMICHANNEL +{ + HGSMICHANNELHANDLER handler; /**< The channel handler. */ + const char *pszName; /**< NULL for hardcoded channels or RTStrDup'ed name. */ + uint8_t u8Channel; /**< The channel id, equal to the channel index in the array. */ + uint8_t u8Flags; /**< HGSMI_CH_F_* */ +} HGSMICHANNEL; + +typedef struct _HGSMICHANNELINFO +{ + /** Channel handlers indexed by the channel id. + * The array is accessed under the instance lock. */ + HGSMICHANNEL Channels[HGSMI_NUMBER_OF_CHANNELS]; +} HGSMICHANNELINFO; + + +RT_C_DECLS_BEGIN + +DECLINLINE(HGSMIBUFFERHEADER *) HGSMIBufferHeaderFromPtr(void RT_UNTRUSTED_VOLATILE_HSTGST *pvBuffer) +{ + return (HGSMIBUFFERHEADER *)pvBuffer; +} + +DECLINLINE(uint8_t RT_UNTRUSTED_VOLATILE_HSTGST *) HGSMIBufferDataFromPtr(void RT_UNTRUSTED_VOLATILE_HSTGST *pvBuffer) +{ + return (uint8_t RT_UNTRUSTED_VOLATILE_HSTGST *)pvBuffer + sizeof(HGSMIBUFFERHEADER); +} + +DECLINLINE(HGSMIBUFFERTAIL RT_UNTRUSTED_VOLATILE_HSTGST *) +HGSMIBufferTailFromPtr(void RT_UNTRUSTED_VOLATILE_HSTGST *pvBuffer, uint32_t u32DataSize) +{ + return (HGSMIBUFFERTAIL RT_UNTRUSTED_VOLATILE_HSTGST *)(HGSMIBufferDataFromPtr(pvBuffer) + u32DataSize); +} + +DECLINLINE(HGSMISIZE) HGSMIBufferMinimumSize(void) +{ + return sizeof(HGSMIBUFFERHEADER) + sizeof(HGSMIBUFFERTAIL); +} + +DECLINLINE(HGSMIBUFFERHEADER RT_UNTRUSTED_VOLATILE_HSTGST *) HGSMIBufferHeaderFromData(const void RT_UNTRUSTED_VOLATILE_HSTGST *pvData) +{ + return (HGSMIBUFFERHEADER RT_UNTRUSTED_VOLATILE_HSTGST *)((uint8_t *)pvData - sizeof(HGSMIBUFFERHEADER)); +} + +DECLINLINE(HGSMISIZE) HGSMIBufferRequiredSize(uint32_t u32DataSize) +{ + return HGSMIBufferMinimumSize() + u32DataSize; +} + +DECLINLINE(HGSMIOFFSET) HGSMIPointerToOffset(const HGSMIAREA *pArea, const void RT_UNTRUSTED_VOLATILE_HSTGST *pv) +{ + return pArea->offBase + (HGSMIOFFSET)((uint8_t *)pv - pArea->pu8Base); +} + +DECLINLINE(void RT_UNTRUSTED_VOLATILE_HSTGST *) HGSMIOffsetToPointer(const HGSMIAREA *pArea, HGSMIOFFSET offBuffer) +{ + return pArea->pu8Base + (offBuffer - pArea->offBase); +} + +DECLINLINE(uint8_t RT_UNTRUSTED_VOLATILE_HSTGST*) HGSMIBufferDataFromOffset(const HGSMIAREA *pArea, HGSMIOFFSET offBuffer) +{ + void RT_UNTRUSTED_VOLATILE_HSTGST *pvBuffer = HGSMIOffsetToPointer(pArea, offBuffer); + return HGSMIBufferDataFromPtr(pvBuffer); +} + +DECLINLINE(HGSMIOFFSET) HGSMIBufferOffsetFromData(const HGSMIAREA *pArea, void RT_UNTRUSTED_VOLATILE_HSTGST *pvData) +{ + HGSMIBUFFERHEADER RT_UNTRUSTED_VOLATILE_HSTGST *pHeader = HGSMIBufferHeaderFromData(pvData); + return HGSMIPointerToOffset(pArea, pHeader); +} + +DECLINLINE(uint8_t RT_UNTRUSTED_VOLATILE_HSTGST *) HGSMIBufferDataAndChInfoFromOffset(const HGSMIAREA *pArea, + HGSMIOFFSET offBuffer, + uint16_t *pu16ChannelInfo) +{ + HGSMIBUFFERHEADER RT_UNTRUSTED_VOLATILE_HSTGST *pHeader = + (HGSMIBUFFERHEADER RT_UNTRUSTED_VOLATILE_HSTGST *)HGSMIOffsetToPointer(pArea, offBuffer); + *pu16ChannelInfo = pHeader->u16ChannelInfo; + return HGSMIBufferDataFromPtr(pHeader); +} + +uint32_t HGSMIChecksum(HGSMIOFFSET offBuffer, const HGSMIBUFFERHEADER RT_UNTRUSTED_VOLATILE_HSTGST *pHeader, + const HGSMIBUFFERTAIL RT_UNTRUSTED_VOLATILE_HSTGST *pTail); + +int HGSMIAreaInitialize(HGSMIAREA *pArea, void *pvBase, HGSMISIZE cbArea, HGSMIOFFSET offBase); +void HGSMIAreaClear(HGSMIAREA *pArea); + +DECLINLINE(bool) HGSMIAreaContainsOffset(const HGSMIAREA *pArea, HGSMIOFFSET off) +{ + return off >= pArea->offBase && off - pArea->offBase < pArea->cbArea; +} + +DECLINLINE(bool) HGSMIAreaContainsPointer(const HGSMIAREA *pArea, const void RT_UNTRUSTED_VOLATILE_HSTGST *pv) +{ + return (uintptr_t)pv - (uintptr_t)pArea->pu8Base < pArea->cbArea; +} + +HGSMIOFFSET HGSMIBufferInitializeSingle(const HGSMIAREA *pArea, HGSMIBUFFERHEADER *pHeader, HGSMISIZE cbBuffer, + uint8_t u8Channel, uint16_t u16ChannelInfo); + +int HGSMIHeapSetup(HGSMIHEAP *pHeap, void *pvBase, HGSMISIZE cbArea, HGSMIOFFSET offBase, const HGSMIENV *pEnv); +void HGSMIHeapDestroy(HGSMIHEAP *pHeap); +void RT_UNTRUSTED_VOLATILE_HSTGST *HGSMIHeapBufferAlloc(HGSMIHEAP *pHeap, HGSMISIZE cbBuffer); +void HGSMIHeapBufferFree(HGSMIHEAP *pHeap, void RT_UNTRUSTED_VOLATILE_HSTGST *pvBuf); + +void RT_UNTRUSTED_VOLATILE_HOST *HGSMIHeapAlloc(HGSMIHEAP *pHeap, + HGSMISIZE cbData, + uint8_t u8Channel, + uint16_t u16ChannelInfo); + +void HGSMIHeapFree(HGSMIHEAP *pHeap, void RT_UNTRUSTED_VOLATILE_HSTGST *pvData); + +DECLINLINE(const HGSMIAREA *) HGSMIHeapArea(HGSMIHEAP *pHeap) +{ + return &pHeap->area; +} + +DECLINLINE(HGSMIOFFSET) HGSMIHeapOffset(HGSMIHEAP *pHeap) +{ + return HGSMIHeapArea(pHeap)->offBase; +} + +DECLINLINE(HGSMISIZE) HGSMIHeapSize(HGSMIHEAP *pHeap) +{ + return HGSMIHeapArea(pHeap)->cbArea; +} + +DECLINLINE(HGSMIOFFSET) HGSMIHeapBufferOffset(HGSMIHEAP *pHeap, void RT_UNTRUSTED_VOLATILE_HOST *pvData) +{ + return HGSMIBufferOffsetFromData(HGSMIHeapArea(pHeap), pvData); +} + +HGSMICHANNEL *HGSMIChannelFindById(HGSMICHANNELINFO *pChannelInfo, uint8_t u8Channel); + +int HGSMIChannelRegister(HGSMICHANNELINFO *pChannelInfo, uint8_t u8Channel, const char *pszName, + PFNHGSMICHANNELHANDLER pfnChannelHandler, void *pvChannelHandler); +int HGSMIBufferProcess(const HGSMIAREA *pArea, HGSMICHANNELINFO *pChannelInfo, HGSMIOFFSET offBuffer); +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_Graphics_HGSMI_h */ + diff --git a/include/VBox/Graphics/HGSMIBase.h b/include/VBox/Graphics/HGSMIBase.h new file mode 100644 index 00000000..aad0bfbe --- /dev/null +++ b/include/VBox/Graphics/HGSMIBase.h @@ -0,0 +1,60 @@ +/* $Id: HGSMIBase.h $ */ +/** @file + * VBox Host Guest Shared Memory Interface (HGSMI) - buffer management. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_HGSMIBase_h +#define VBOX_INCLUDED_Graphics_HGSMIBase_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "HGSMI.h" +#include "HGSMIContext.h" +#include "VBoxVideoIPRT.h" + +RT_C_DECLS_BEGIN + +/** @name Base HGSMI Buffer APIs + * @{ */ + +/** Acknowlege an IRQ. */ +DECLINLINE(void) VBoxHGSMIClearIrq(PHGSMIHOSTCOMMANDCONTEXT pCtx) +{ + VBVO_PORT_WRITE_U32(pCtx->port, HGSMIOFFSET_VOID); +} + +DECLHIDDEN(void RT_UNTRUSTED_VOLATILE_HOST *) VBoxHGSMIBufferAlloc(PHGSMIGUESTCOMMANDCONTEXT pCtx, HGSMISIZE cbData, + uint8_t u8Ch, uint16_t u16Op); +DECLHIDDEN(void) VBoxHGSMIBufferFree(PHGSMIGUESTCOMMANDCONTEXT pCtx, void RT_UNTRUSTED_VOLATILE_HOST *pvBuffer); +DECLHIDDEN(int) VBoxHGSMIBufferSubmit(PHGSMIGUESTCOMMANDCONTEXT pCtx, void RT_UNTRUSTED_VOLATILE_HOST *pvBuffer); +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_Graphics_HGSMIBase_h */ diff --git a/include/VBox/Graphics/HGSMIChSetup.h b/include/VBox/Graphics/HGSMIChSetup.h new file mode 100644 index 00000000..0e11b580 --- /dev/null +++ b/include/VBox/Graphics/HGSMIChSetup.h @@ -0,0 +1,88 @@ +/* $Id: HGSMIChSetup.h $ */ +/** @file + * VBox Host Guest Shared Memory Interface (HGSMI), Host/Guest shared part. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_HGSMIChSetup_h +#define VBOX_INCLUDED_Graphics_HGSMIChSetup_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "HGSMIDefs.h" + +/* HGSMI setup and configuration channel commands and data structures. */ +/* + * Tell the host the location of hgsmi_host_flags structure, where the host + * can write information about pending buffers, etc, and which can be quickly + * polled by the guest without a need to port IO. + */ +#define HGSMI_CC_HOST_FLAGS_LOCATION 0 + +typedef struct HGSMIBUFFERLOCATION +{ + HGSMIOFFSET offLocation; + HGSMISIZE cbLocation; +} HGSMIBUFFERLOCATION; +AssertCompileSize(HGSMIBUFFERLOCATION, 8); + +/* HGSMI setup and configuration data structures. */ +/* host->guest commands pending, should be accessed under FIFO lock only */ +#define HGSMIHOSTFLAGS_COMMANDS_PENDING UINT32_C(0x01) +/* IRQ is fired, should be accessed under VGAState::lock only */ +#define HGSMIHOSTFLAGS_IRQ UINT32_C(0x02) +#ifdef VBOX_WITH_WDDM +/* one or more guest commands is completed, should be accessed under FIFO lock only */ +# define HGSMIHOSTFLAGS_GCOMMAND_COMPLETED UINT32_C(0x04) +#endif +/* vsync interrupt flag, should be accessed under VGAState::lock only */ +#define HGSMIHOSTFLAGS_VSYNC UINT32_C(0x10) +/** monitor hotplug flag, should be accessed under VGAState::lock only */ +#define HGSMIHOSTFLAGS_HOTPLUG UINT32_C(0x20) +/** + * Cursor capability state change flag, should be accessed under + * VGAState::lock only. @see VBVACONF32. + */ +#define HGSMIHOSTFLAGS_CURSOR_CAPABILITIES UINT32_C(0x40) + +typedef struct HGSMIHOSTFLAGS +{ + /* + * Host flags can be accessed and modified in multiple threads + * concurrently, e.g. CrOpenGL HGCM and GUI threads when completing + * HGSMI 3D and Video Accel respectively, EMT thread when dealing with + * HGSMI command processing, etc. + * Besides settings/cleaning flags atomically, some flags have their + * own special sync restrictions, see comments for flags above. + */ + volatile uint32_t u32HostFlags; + uint32_t au32Reserved[3]; +} HGSMIHOSTFLAGS; +AssertCompileSize(HGSMIHOSTFLAGS, 16); + +#endif /* !VBOX_INCLUDED_Graphics_HGSMIChSetup_h */ diff --git a/include/VBox/Graphics/HGSMIChannels.h b/include/VBox/Graphics/HGSMIChannels.h new file mode 100644 index 00000000..c957040b --- /dev/null +++ b/include/VBox/Graphics/HGSMIChannels.h @@ -0,0 +1,77 @@ +/* $Id: HGSMIChannels.h $ */ +/** @file + * + * VBox Host Guest Shared Memory Interface (HGSMI). + * Host/Guest shared part. + * Channel identifiers. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_HGSMIChannels_h +#define VBOX_INCLUDED_Graphics_HGSMIChannels_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/* + * Each channel has an 8 bit identifier. There are a number of predefined + * (hardcoded) channels. + * + * HGSMI_CH_HGSMI channel can be used to map a string channel identifier + * to a free 16 bit numerical value. values are allocated in range + * [HGSMI_CH_STRING_FIRST;HGSMI_CH_STRING_LAST]. + */ + + +/* Predefined channel identifiers. Used internally by VBOX to simplify the channel setup. */ +/* A reserved channel value */ +#define HGSMI_CH_RESERVED 0x00 +/* HGCMI: setup and configuration */ +#define HGSMI_CH_HGSMI 0x01 +/* Graphics: VBVA */ +#define HGSMI_CH_VBVA 0x02 +/* Graphics: Seamless with a single guest region */ +#define HGSMI_CH_SEAMLESS 0x03 +/* Graphics: Seamless with separate host windows */ +#define HGSMI_CH_SEAMLESS2 0x04 +/* Graphics: OpenGL HW acceleration */ +#define HGSMI_CH_OPENGL 0x05 + + +/* Dynamically allocated channel identifiers. */ +/* The first channel index to be used for string mappings (inclusive) */ +#define HGSMI_CH_STRING_FIRST 0x20 +/* The last channel index for string mappings (inclusive) */ +#define HGSMI_CH_STRING_LAST 0xff + + +/* Check whether the channel identifier is allocated for a dynamic channel */ +#define HGSMI_IS_DYNAMIC_CHANNEL(_channel) (((uint8_t)(_channel) & 0xE0) != 0) + + +#endif /* !VBOX_INCLUDED_Graphics_HGSMIChannels_h */ diff --git a/include/VBox/Graphics/HGSMIContext.h b/include/VBox/Graphics/HGSMIContext.h new file mode 100644 index 00000000..23e810c0 --- /dev/null +++ b/include/VBox/Graphics/HGSMIContext.h @@ -0,0 +1,114 @@ +/* $Id: HGSMIContext.h $ */ +/** @file + * VBox Host Guest Shared Memory Interface (HGSMI) - command contexts. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_HGSMIContext_h +#define VBOX_INCLUDED_Graphics_HGSMIContext_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "HGSMI.h" +#include "HGSMIChSetup.h" +#include "VBoxVideoIPRT.h" + +#ifdef VBOX_WDDM_MINIPORT +# include "wddm/VBoxMPShgsmi.h" + typedef VBOXSHGSMI HGSMIGUESTCMDHEAP; +# define HGSMIGUESTCMDHEAP_GET(_p) (&(_p)->Heap) +#else + typedef HGSMIHEAP HGSMIGUESTCMDHEAP; +# define HGSMIGUESTCMDHEAP_GET(_p) (_p) +#endif + +RT_C_DECLS_BEGIN + +/** + * Structure grouping the context needed for submitting commands to the host + * via HGSMI + */ +typedef struct HGSMIGUESTCOMMANDCONTEXT +{ + /** Information about the memory heap located in VRAM from which data + * structures to be sent to the host are allocated. */ + HGSMIGUESTCMDHEAP heapCtx; + /** The I/O port used for submitting commands to the host by writing their + * offsets into the heap. */ + RTIOPORT port; +} HGSMIGUESTCOMMANDCONTEXT, *PHGSMIGUESTCOMMANDCONTEXT; + + +/** + * Structure grouping the context needed for receiving commands from the host + * via HGSMI + */ +typedef struct HGSMIHOSTCOMMANDCONTEXT +{ + /** Information about the memory area located in VRAM in which the host + * places data structures to be read by the guest. */ + HGSMIAREA areaCtx; + /** Convenience structure used for matching host commands to handlers. */ + /** @todo handlers are registered individually in code rather than just + * passing a static structure in order to gain extra flexibility. There is + * currently no expected usage case for this though. Is the additional + * complexity really justified? */ + HGSMICHANNELINFO channels; + /** Flag to indicate that one thread is currently processing the command + * queue. */ + volatile bool fHostCmdProcessing; + /* Pointer to the VRAM location where the HGSMI host flags are kept. */ + volatile HGSMIHOSTFLAGS *pfHostFlags; + /** The I/O port used for receiving commands from the host as offsets into + * the memory area and sending back confirmations (command completion, + * IRQ acknowlegement). */ + RTIOPORT port; +} HGSMIHOSTCOMMANDCONTEXT, *PHGSMIHOSTCOMMANDCONTEXT; + +/** @name HGSMI context initialisation APIs. + * @{ */ + +/** @todo we should provide a cleanup function too as part of the API */ +DECLHIDDEN(int) VBoxHGSMISetupGuestContext(PHGSMIGUESTCOMMANDCONTEXT pCtx, + void *pvGuestHeapMemory, + uint32_t cbGuestHeapMemory, + uint32_t offVRAMGuestHeapMemory, + const HGSMIENV *pEnv); +DECLHIDDEN(void) VBoxHGSMISetupHostContext(PHGSMIHOSTCOMMANDCONTEXT pCtx, + void *pvBaseMapping, + uint32_t offHostFlags, + void *pvHostAreaMapping, + uint32_t offVRAMHostArea, + uint32_t cbHostArea); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_Graphics_HGSMIContext_h */ + diff --git a/include/VBox/Graphics/HGSMIDefs.h b/include/VBox/Graphics/HGSMIDefs.h new file mode 100644 index 00000000..adbceafe --- /dev/null +++ b/include/VBox/Graphics/HGSMIDefs.h @@ -0,0 +1,128 @@ +/* $Id: HGSMIDefs.h $ */ +/** @file + * VBox Host Guest Shared Memory Interface (HGSMI) - shared part - types and defines. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_HGSMIDefs_h +#define VBOX_INCLUDED_Graphics_HGSMIDefs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBoxVideoIPRT.h" + +/* HGSMI uses 32 bit offsets and sizes. */ +typedef uint32_t HGSMISIZE; +typedef uint32_t HGSMIOFFSET; + +#define HGSMIOFFSET_VOID ((HGSMIOFFSET)~0) + +/** + * Describes a shared memory area buffer. + * + * Used for calculations with offsets and for buffers verification. + */ +typedef struct HGSMIAREA +{ + uint8_t *pu8Base; /**< The starting address of the area. Corresponds to offset 'offBase'. */ + HGSMIOFFSET offBase; /**< The starting offset of the area. */ + HGSMIOFFSET offLast; /**< The last valid offset: offBase + cbArea - 1 - (sizeof(header) + sizeof(tail)). */ + HGSMISIZE cbArea; /**< Size of the area. */ +} HGSMIAREA; + + +/* The buffer description flags. */ +#define HGSMI_BUFFER_HEADER_F_SEQ_MASK 0x03 /* Buffer sequence type mask. */ +#define HGSMI_BUFFER_HEADER_F_SEQ_SINGLE 0x00 /* Single buffer, not a part of a sequence. */ +#define HGSMI_BUFFER_HEADER_F_SEQ_START 0x01 /* The first buffer in a sequence. */ +#define HGSMI_BUFFER_HEADER_F_SEQ_CONTINUE 0x02 /* A middle buffer in a sequence. */ +#define HGSMI_BUFFER_HEADER_F_SEQ_END 0x03 /* The last buffer in a sequence. */ + + +#pragma pack(1) /** @todo not necessary. use AssertCompileSize instead. */ +/* 16 bytes buffer header. */ +typedef struct HGSMIBUFFERHEADER +{ + uint32_t u32DataSize; /* Size of data that follows the header. */ + + uint8_t u8Flags; /* The buffer description: HGSMI_BUFFER_HEADER_F_* */ + + uint8_t u8Channel; /* The channel the data must be routed to. */ + uint16_t u16ChannelInfo; /* Opaque to the HGSMI, used by the channel. */ + + union { + uint8_t au8Union[8]; /* Opaque placeholder to make the union 8 bytes. */ + + struct + { /* HGSMI_BUFFER_HEADER_F_SEQ_SINGLE */ + uint32_t u32Reserved1; /* A reserved field, initialize to 0. */ + uint32_t u32Reserved2; /* A reserved field, initialize to 0. */ + } Buffer; + + struct + { /* HGSMI_BUFFER_HEADER_F_SEQ_START */ + uint32_t u32SequenceNumber; /* The sequence number, the same for all buffers in the sequence. */ + uint32_t u32SequenceSize; /* The total size of the sequence. */ + } SequenceStart; + + struct + { /* HGSMI_BUFFER_HEADER_F_SEQ_CONTINUE and HGSMI_BUFFER_HEADER_F_SEQ_END */ + uint32_t u32SequenceNumber; /* The sequence number, the same for all buffers in the sequence. */ + uint32_t u32SequenceOffset; /* Data offset in the entire sequence. */ + } SequenceContinue; + } u; +} HGSMIBUFFERHEADER; + +/* 8 bytes buffer tail. */ +typedef struct HGSMIBUFFERTAIL +{ + uint32_t u32Reserved; /* Reserved, must be initialized to 0. */ + uint32_t u32Checksum; /* Verifyer for the buffer header and offset and for first 4 bytes of the tail. */ +} HGSMIBUFFERTAIL; +#pragma pack() + +AssertCompileSize(HGSMIBUFFERHEADER, 16); +AssertCompileSize(HGSMIBUFFERTAIL, 8); + +/* The size of the array of channels. Array indexes are uint8_t. Note: the value must not be changed. */ +#define HGSMI_NUMBER_OF_CHANNELS 0x100 + +typedef struct HGSMIENV +{ + /* Environment context pointer. */ + void *pvEnv; + + /* Allocate system memory. */ + DECLCALLBACKMEMBER(void *, pfnAlloc,(void *pvEnv, HGSMISIZE cb)); + + /* Free system memory. */ + DECLCALLBACKMEMBER(void, pfnFree,(void *pvEnv, void *pv)); +} HGSMIENV; + +#endif /* !VBOX_INCLUDED_Graphics_HGSMIDefs_h */ + diff --git a/include/VBox/Graphics/HGSMIHostCmd.h b/include/VBox/Graphics/HGSMIHostCmd.h new file mode 100644 index 00000000..9c8b0b9e --- /dev/null +++ b/include/VBox/Graphics/HGSMIHostCmd.h @@ -0,0 +1,59 @@ +/* $Id: HGSMIHostCmd.h $ */ +/** @file + * VBox Host Guest Shared Memory Interface (HGSMI) - buffer management. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_Graphics_HGSMIHostCmd_h +#define VBOX_INCLUDED_Graphics_HGSMIHostCmd_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "HGSMI.h" +#include "HGSMIContext.h" +#include "VBoxVideoIPRT.h" + +RT_C_DECLS_BEGIN + +/** @name Base HGSMI host command APIs. + * @{ */ + +DECLHIDDEN(void) VBoxHGSMIHostCmdComplete(PHGSMIHOSTCOMMANDCONTEXT pCtx, void RT_UNTRUSTED_VOLATILE_HOST *pvMem); +DECLHIDDEN(void) VBoxHGSMIProcessHostQueue(PHGSMIHOSTCOMMANDCONTEXT pCtx); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_Graphics_HGSMIHostCmd_h */ diff --git a/include/VBox/Graphics/HGSMIMemAlloc.h b/include/VBox/Graphics/HGSMIMemAlloc.h new file mode 100644 index 00000000..a837dc34 --- /dev/null +++ b/include/VBox/Graphics/HGSMIMemAlloc.h @@ -0,0 +1,113 @@ +/* $Id: HGSMIMemAlloc.h $ */ +/** @file + * VBox Host Guest Shared Memory Interface (HGSMI) - Memory allocator. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_Graphics_HGSMIMemAlloc_h +#define VBOX_INCLUDED_Graphics_HGSMIMemAlloc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "HGSMIDefs.h" +#include "VBoxVideoIPRT.h" + + +/* Descriptor. */ +#define HGSMI_MA_DESC_OFFSET_MASK UINT32_C(0xFFFFFFE0) +#define HGSMI_MA_DESC_FREE_MASK UINT32_C(0x00000010) +#define HGSMI_MA_DESC_ORDER_MASK UINT32_C(0x0000000F) + +#define HGSMI_MA_DESC_OFFSET(d) ((d) & HGSMI_MA_DESC_OFFSET_MASK) +#define HGSMI_MA_DESC_IS_FREE(d) (((d) & HGSMI_MA_DESC_FREE_MASK) != 0) +#define HGSMI_MA_DESC_ORDER(d) ((d) & HGSMI_MA_DESC_ORDER_MASK) + +#define HGSMI_MA_DESC_ORDER_BASE UINT32_C(5) + +#define HGSMI_MA_BLOCK_SIZE_MIN (UINT32_C(1) << (HGSMI_MA_DESC_ORDER_BASE + 0)) +#define HGSMI_MA_BLOCK_SIZE_MAX (UINT32_C(1) << (HGSMI_MA_DESC_ORDER_BASE + HGSMI_MA_DESC_ORDER_MASK)) + +/* HGSMI_MA_DESC_ORDER_BASE must correspond to HGSMI_MA_DESC_OFFSET_MASK. */ +AssertCompile((~HGSMI_MA_DESC_OFFSET_MASK + 1) == HGSMI_MA_BLOCK_SIZE_MIN); + + +typedef struct HGSMIMABLOCK +{ + RTLISTNODE nodeBlock; + RTLISTNODE nodeFree; + HGSMIOFFSET descriptor; +} HGSMIMABLOCK; + +typedef struct HGSMIMADATA +{ + HGSMIAREA area; + HGSMIENV env; + HGSMISIZE cbMaxBlock; + + uint32_t cBlocks; /* How many blocks in the listBlocks. */ + RTLISTANCHOR listBlocks; /* All memory blocks, sorted. */ + RTLISTANCHOR aListFreeBlocks[HGSMI_MA_DESC_ORDER_MASK + 1]; /* For free blocks of each order. */ +} HGSMIMADATA; + +RT_C_DECLS_BEGIN + +int HGSMIMAInit(HGSMIMADATA *pMA, const HGSMIAREA *pArea, + HGSMIOFFSET *paDescriptors, uint32_t cDescriptors, HGSMISIZE cbMaxBlock, + const HGSMIENV *pEnv); +void HGSMIMAUninit(HGSMIMADATA *pMA); + +void RT_UNTRUSTED_VOLATILE_HSTGST *HGSMIMAAlloc(HGSMIMADATA *pMA, HGSMISIZE cb); +void HGSMIMAFree(HGSMIMADATA *pMA, void RT_UNTRUSTED_VOLATILE_GUEST *pv); + +HGSMIMABLOCK *HGSMIMASearchOffset(HGSMIMADATA *pMA, HGSMIOFFSET off); + +uint32_t HGSMIPopCnt32(uint32_t u32); + +DECLINLINE(HGSMISIZE) HGSMIMAOrder2Size(HGSMIOFFSET order) +{ + return (UINT32_C(1) << (HGSMI_MA_DESC_ORDER_BASE + order)); +} + +DECLINLINE(HGSMIOFFSET) HGSMIMASize2Order(HGSMISIZE cb) +{ + HGSMIOFFSET order = HGSMIPopCnt32(cb - 1) - HGSMI_MA_DESC_ORDER_BASE; +#ifdef HGSMI_STRICT + Assert(HGSMIMAOrder2Size(order) == cb); +#endif + return order; +} + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_Graphics_HGSMIMemAlloc_h */ diff --git a/include/VBox/Graphics/Makefile.kup b/include/VBox/Graphics/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/VBox/Graphics/Makefile.kup diff --git a/include/VBox/Graphics/VBoxUhgsmi.h b/include/VBox/Graphics/VBoxUhgsmi.h new file mode 100644 index 00000000..8f1328e2 --- /dev/null +++ b/include/VBox/Graphics/VBoxUhgsmi.h @@ -0,0 +1,145 @@ +/* $Id: VBoxUhgsmi.h $ */ +/** @file + * Document me, pretty please. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_Graphics_VBoxUhgsmi_h +#define VBOX_INCLUDED_Graphics_VBoxUhgsmi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +typedef struct VBOXUHGSMI *PVBOXUHGSMI; + +typedef struct VBOXUHGSMI_BUFFER *PVBOXUHGSMI_BUFFER; + +typedef union VBOXUHGSMI_BUFFER_TYPE_FLAGS +{ + uint32_t Value; + struct + { + uint32_t fCommand : 1; + uint32_t Reserved : 31; + } s; +} VBOXUHGSMI_BUFFER_TYPE_FLAGS; + +typedef union VBOXUHGSMI_BUFFER_LOCK_FLAGS +{ + uint32_t Value; + struct + { + uint32_t fReadOnly : 1; + uint32_t fWriteOnly : 1; + uint32_t fDonotWait : 1; + uint32_t fDiscard : 1; + uint32_t fLockEntire : 1; + uint32_t Reserved : 27; + } s; +} VBOXUHGSMI_BUFFER_LOCK_FLAGS; + +typedef union VBOXUHGSMI_BUFFER_SUBMIT_FLAGS +{ + uint32_t Value; + struct + { + uint32_t fHostReadOnly : 1; + uint32_t fHostWriteOnly : 1; + uint32_t fDoNotRetire : 1; /**< the buffer will be used in a subsequent command */ + uint32_t fEntireBuffer : 1; + uint32_t Reserved : 28; + } s; +} VBOXUHGSMI_BUFFER_SUBMIT_FLAGS, *PVBOXUHGSMI_BUFFER_SUBMIT_FLAGS; + +/* the caller can specify NULL as a hSynch and specify a valid enmSynchType to make UHGSMI create a proper object itself, + * */ +typedef DECLCALLBACKTYPE(int, FNVBOXUHGSMI_BUFFER_CREATE,(PVBOXUHGSMI pHgsmi, uint32_t cbBuf, VBOXUHGSMI_BUFFER_TYPE_FLAGS fType, + PVBOXUHGSMI_BUFFER* ppBuf)); +typedef FNVBOXUHGSMI_BUFFER_CREATE *PFNVBOXUHGSMI_BUFFER_CREATE; + +typedef struct VBOXUHGSMI_BUFFER_SUBMIT +{ + PVBOXUHGSMI_BUFFER pBuf; + uint32_t offData; + uint32_t cbData; + VBOXUHGSMI_BUFFER_SUBMIT_FLAGS fFlags; +} VBOXUHGSMI_BUFFER_SUBMIT, *PVBOXUHGSMI_BUFFER_SUBMIT; + +typedef DECLCALLBACKTYPE(int, FNVBOXUHGSMI_BUFFER_SUBMIT,(PVBOXUHGSMI pHgsmi, PVBOXUHGSMI_BUFFER_SUBMIT aBuffers, + uint32_t cBuffers)); +typedef FNVBOXUHGSMI_BUFFER_SUBMIT *PFNVBOXUHGSMI_BUFFER_SUBMIT; + +typedef DECLCALLBACKTYPE(int, FNVBOXUHGSMI_BUFFER_DESTROY,(PVBOXUHGSMI_BUFFER pBuf)); +typedef FNVBOXUHGSMI_BUFFER_DESTROY *PFNVBOXUHGSMI_BUFFER_DESTROY; + +typedef DECLCALLBACKTYPE(int, FNVBOXUHGSMI_BUFFER_LOCK,(PVBOXUHGSMI_BUFFER pBuf, uint32_t offLock, uint32_t cbLock, + VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags, void**pvLock)); +typedef FNVBOXUHGSMI_BUFFER_LOCK *PFNVBOXUHGSMI_BUFFER_LOCK; + +typedef DECLCALLBACKTYPE(int, FNVBOXUHGSMI_BUFFER_UNLOCK,(PVBOXUHGSMI_BUFFER pBuf)); +typedef FNVBOXUHGSMI_BUFFER_UNLOCK *PFNVBOXUHGSMI_BUFFER_UNLOCK; + +typedef struct VBOXUHGSMI +{ + PFNVBOXUHGSMI_BUFFER_CREATE pfnBufferCreate; + PFNVBOXUHGSMI_BUFFER_SUBMIT pfnBufferSubmit; + /** User custom data. */ + void *pvUserData; +} VBOXUHGSMI; + +typedef struct VBOXUHGSMI_BUFFER +{ + PFNVBOXUHGSMI_BUFFER_LOCK pfnLock; + PFNVBOXUHGSMI_BUFFER_UNLOCK pfnUnlock; + PFNVBOXUHGSMI_BUFFER_DESTROY pfnDestroy; + + /* r/o data added for ease of access and simplicity + * modifying it leads to unpredictable behavior */ + VBOXUHGSMI_BUFFER_TYPE_FLAGS fType; + uint32_t cbBuffer; + /** User custom data. */ + void *pvUserData; +} VBOXUHGSMI_BUFFER; + +#define VBoxUhgsmiBufferCreate(_pUhgsmi, _cbBuf, _fType, _ppBuf) ((_pUhgsmi)->pfnBufferCreate(_pUhgsmi, _cbBuf, _fType, _ppBuf)) +#define VBoxUhgsmiBufferSubmit(_pUhgsmi, _aBuffers, _cBuffers) ((_pUhgsmi)->pfnBufferSubmit(_pUhgsmi, _aBuffers, _cBuffers)) + +#define VBoxUhgsmiBufferLock(_pBuf, _offLock, _cbLock, _fFlags, _pvLock) ((_pBuf)->pfnLock(_pBuf, _offLock, _cbLock, _fFlags, _pvLock)) +#define VBoxUhgsmiBufferUnlock(_pBuf) ((_pBuf)->pfnUnlock(_pBuf)) +#define VBoxUhgsmiBufferDestroy(_pBuf) ((_pBuf)->pfnDestroy(_pBuf)) + +#endif /* !VBOX_INCLUDED_Graphics_VBoxUhgsmi_h */ + diff --git a/include/VBox/Graphics/VBoxVideo.h b/include/VBox/Graphics/VBoxVideo.h new file mode 100644 index 00000000..ca779315 --- /dev/null +++ b/include/VBox/Graphics/VBoxVideo.h @@ -0,0 +1,1490 @@ +/* $Id: VBoxVideo.h $ */ +/** @file + * VirtualBox Video interface. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_VBoxVideo_h +#define VBOX_INCLUDED_Graphics_VBoxVideo_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBoxVideoIPRT.h" + +/* this should be in sync with monitorCount <xsd:maxInclusive value="64"/> in src/VBox/Main/xml/VirtualBox-settings-common.xsd */ +#define VBOX_VIDEO_MAX_SCREENS 64 + +/* + * The last 4096 bytes of the guest VRAM contains the generic info for all + * DualView chunks: sizes and offsets of chunks. This is filled by miniport. + * + * Last 4096 bytes of each chunk contain chunk specific data: framebuffer info, + * etc. This is used exclusively by the corresponding instance of a display driver. + * + * The VRAM layout: + * Last 4096 bytes - Adapter information area. + * 4096 bytes aligned miniport heap (value specified in the config rouded up). + * Slack - what left after dividing the VRAM. + * 4096 bytes aligned framebuffers: + * last 4096 bytes of each framebuffer is the display information area. + * + * The Virtual Graphics Adapter information in the guest VRAM is stored by the + * guest video driver using structures prepended by VBOXVIDEOINFOHDR. + * + * When the guest driver writes dword 0 to the VBE_DISPI_INDEX_VBOX_VIDEO + * the host starts to process the info. The first element at the start of + * the 4096 bytes region should be normally be a LINK that points to + * actual information chain. That way the guest driver can have some + * fixed layout of the information memory block and just rewrite + * the link to point to relevant memory chain. + * + * The processing stops at the END element. + * + * The host can access the memory only when the port IO is processed. + * All data that will be needed later must be copied from these 4096 bytes. + * But other VRAM can be used by host until the mode is disabled. + * + * The guest driver writes dword 0xffffffff to the VBE_DISPI_INDEX_VBOX_VIDEO + * to disable the mode. + * + * VBE_DISPI_INDEX_VBOX_VIDEO is used to read the configuration information + * from the host and issue commands to the host. + * + * The guest writes the VBE_DISPI_INDEX_VBOX_VIDEO index register, the the + * following operations with the VBE data register can be performed: + * + * Operation Result + * write 16 bit value NOP + * read 16 bit value count of monitors + * write 32 bit value sets the vbox command value and the command processed by the host + * read 32 bit value result of the last vbox command is returned + */ + +#define VBOX_VIDEO_PRIMARY_SCREEN 0 +#define VBOX_VIDEO_NO_SCREEN ~0 + +/** + * VBVA command header. + * + * @todo Where does this fit in? + */ +typedef struct VBVACMDHDR +{ + /** Coordinates of affected rectangle. */ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; +} VBVACMDHDR; +AssertCompileSize(VBVACMDHDR, 8); + +/** @name VBVA ring defines. + * + * The VBVA ring buffer is suitable for transferring large (< 2GB) amount of + * data. For example big bitmaps which do not fit to the buffer. + * + * Guest starts writing to the buffer by initializing a record entry in the + * aRecords queue. VBVA_F_RECORD_PARTIAL indicates that the record is being + * written. As data is written to the ring buffer, the guest increases off32End + * for the record. + * + * The host reads the aRecords on flushes and processes all completed records. + * When host encounters situation when only a partial record presents and + * cbRecord & ~VBVA_F_RECORD_PARTIAL >= VBVA_RING_BUFFER_SIZE - + * VBVA_RING_BUFFER_THRESHOLD, the host fetched all record data and updates + * off32Head. After that on each flush the host continues fetching the data + * until the record is completed. + * + */ +#define VBVA_RING_BUFFER_SIZE (_4M - _1K) +#define VBVA_RING_BUFFER_THRESHOLD (4 * _1K) + +#define VBVA_MAX_RECORDS (64) + +#define VBVA_F_MODE_ENABLED UINT32_C(0x00000001) +#define VBVA_F_MODE_VRDP UINT32_C(0x00000002) +#define VBVA_F_MODE_VRDP_RESET UINT32_C(0x00000004) +#define VBVA_F_MODE_VRDP_ORDER_MASK UINT32_C(0x00000008) + +#define VBVA_F_STATE_PROCESSING UINT32_C(0x00010000) + +#define VBVA_F_RECORD_PARTIAL UINT32_C(0x80000000) + +/** + * VBVA record. + */ +typedef struct VBVARECORD +{ + /** The length of the record. Changed by guest. */ + uint32_t cbRecord; +} VBVARECORD; +AssertCompileSize(VBVARECORD, 4); + +/* The size of the information. */ +/* + * The minimum HGSMI heap size is PAGE_SIZE (4096 bytes) and is a restriction of the + * runtime heapsimple API. Use minimum 2 pages here, because the info area also may + * contain other data (for example HGSMIHOSTFLAGS structure). + */ +#ifndef VBOX_XPDM_MINIPORT +# define VBVA_ADAPTER_INFORMATION_SIZE (64*_1K) +#else +#define VBVA_ADAPTER_INFORMATION_SIZE (16*_1K) +#define VBVA_DISPLAY_INFORMATION_SIZE (64*_1K) +#endif +#define VBVA_MIN_BUFFER_SIZE (64*_1K) + + +/* The value for port IO to let the adapter to interpret the adapter memory. */ +#define VBOX_VIDEO_DISABLE_ADAPTER_MEMORY 0xFFFFFFFF + +/* The value for port IO to let the adapter to interpret the adapter memory. */ +#define VBOX_VIDEO_INTERPRET_ADAPTER_MEMORY 0x00000000 + +/* The value for port IO to let the adapter to interpret the display memory. + * The display number is encoded in low 16 bits. + */ +#define VBOX_VIDEO_INTERPRET_DISPLAY_MEMORY_BASE 0x00010000 + + +/* The end of the information. */ +#define VBOX_VIDEO_INFO_TYPE_END 0 +/* Instructs the host to fetch the next VBOXVIDEOINFOHDR at the given offset of VRAM. */ +#define VBOX_VIDEO_INFO_TYPE_LINK 1 +/* Information about a display memory position. */ +#define VBOX_VIDEO_INFO_TYPE_DISPLAY 2 +/* Information about a screen. */ +#define VBOX_VIDEO_INFO_TYPE_SCREEN 3 +/* Information about host notifications for the driver. */ +#define VBOX_VIDEO_INFO_TYPE_HOST_EVENTS 4 +/* Information about non-volatile guest VRAM heap. */ +#define VBOX_VIDEO_INFO_TYPE_NV_HEAP 5 +/* VBVA enable/disable. */ +#define VBOX_VIDEO_INFO_TYPE_VBVA_STATUS 6 +/* VBVA flush. */ +#define VBOX_VIDEO_INFO_TYPE_VBVA_FLUSH 7 +/* Query configuration value. */ +#define VBOX_VIDEO_INFO_TYPE_QUERY_CONF32 8 + + +#pragma pack(1) +typedef struct VBOXVIDEOINFOHDR +{ + uint8_t u8Type; + uint8_t u8Reserved; + uint16_t u16Length; +} VBOXVIDEOINFOHDR; + + +typedef struct VBOXVIDEOINFOLINK +{ + /* Relative offset in VRAM */ + int32_t i32Offset; +} VBOXVIDEOINFOLINK; + + +/* Resides in adapter info memory. Describes a display VRAM chunk. */ +typedef struct VBOXVIDEOINFODISPLAY +{ + /* Index of the framebuffer assigned by guest. */ + uint32_t u32Index; + + /* Absolute offset in VRAM of the framebuffer to be displayed on the monitor. */ + uint32_t u32Offset; + + /* The size of the memory that can be used for the screen. */ + uint32_t u32FramebufferSize; + + /* The size of the memory that is used for the Display information. + * The information is at u32Offset + u32FramebufferSize + */ + uint32_t u32InformationSize; + +} VBOXVIDEOINFODISPLAY; + + +/* Resides in display info area, describes the current video mode. */ +#define VBOX_VIDEO_INFO_SCREEN_F_NONE 0x00 +#define VBOX_VIDEO_INFO_SCREEN_F_ACTIVE 0x01 + +typedef struct VBOXVIDEOINFOSCREEN +{ + /* Physical X origin relative to the primary screen. */ + int32_t xOrigin; + + /* Physical Y origin relative to the primary screen. */ + int32_t yOrigin; + + /* The scan line size in bytes. */ + uint32_t u32LineSize; + + /* Width of the screen. */ + uint16_t u16Width; + + /* Height of the screen. */ + uint16_t u16Height; + + /* Color depth. */ + uint8_t bitsPerPixel; + + /* VBOX_VIDEO_INFO_SCREEN_F_* */ + uint8_t u8Flags; +} VBOXVIDEOINFOSCREEN; + +/* The guest initializes the structure to 0. The positions of the structure in the + * display info area must not be changed, host will update the structure. Guest checks + * the events and modifies the structure as a response to host. + */ +#define VBOX_VIDEO_INFO_HOST_EVENTS_F_NONE 0x00000000 +#define VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET 0x00000080 + +typedef struct VBOXVIDEOINFOHOSTEVENTS +{ + /* Host events. */ + uint32_t fu32Events; +} VBOXVIDEOINFOHOSTEVENTS; + +/* Resides in adapter info memory. Describes the non-volatile VRAM heap. */ +typedef struct VBOXVIDEOINFONVHEAP +{ + /* Absolute offset in VRAM of the start of the heap. */ + uint32_t u32HeapOffset; + + /* The size of the heap. */ + uint32_t u32HeapSize; + +} VBOXVIDEOINFONVHEAP; + +/* Display information area. */ +typedef struct VBOXVIDEOINFOVBVASTATUS +{ + /* Absolute offset in VRAM of the start of the VBVA QUEUE. 0 to disable VBVA. */ + uint32_t u32QueueOffset; + + /* The size of the VBVA QUEUE. 0 to disable VBVA. */ + uint32_t u32QueueSize; + +} VBOXVIDEOINFOVBVASTATUS; + +typedef struct VBOXVIDEOINFOVBVAFLUSH +{ + uint32_t u32DataStart; + + uint32_t u32DataEnd; + +} VBOXVIDEOINFOVBVAFLUSH; + +#define VBOX_VIDEO_QCI32_MONITOR_COUNT 0 +#define VBOX_VIDEO_QCI32_OFFSCREEN_HEAP_SIZE 1 + +typedef struct VBOXVIDEOINFOQUERYCONF32 +{ + uint32_t u32Index; + + uint32_t u32Value; + +} VBOXVIDEOINFOQUERYCONF32; +#pragma pack() + +#ifdef VBOX_WITH_VIDEOHWACCEL +#pragma pack(1) + +#define VBOXVHWA_VERSION_MAJ 0 +#define VBOXVHWA_VERSION_MIN 0 +#define VBOXVHWA_VERSION_BLD 6 +#define VBOXVHWA_VERSION_RSV 0 + +typedef enum +{ + VBOXVHWACMD_TYPE_SURF_CANCREATE = 1, + VBOXVHWACMD_TYPE_SURF_CREATE, + VBOXVHWACMD_TYPE_SURF_DESTROY, + VBOXVHWACMD_TYPE_SURF_LOCK, + VBOXVHWACMD_TYPE_SURF_UNLOCK, + VBOXVHWACMD_TYPE_SURF_BLT, + VBOXVHWACMD_TYPE_SURF_FLIP, + VBOXVHWACMD_TYPE_SURF_OVERLAY_UPDATE, + VBOXVHWACMD_TYPE_SURF_OVERLAY_SETPOSITION, + VBOXVHWACMD_TYPE_SURF_COLORKEY_SET, + VBOXVHWACMD_TYPE_QUERY_INFO1, + VBOXVHWACMD_TYPE_QUERY_INFO2, + VBOXVHWACMD_TYPE_ENABLE, + VBOXVHWACMD_TYPE_DISABLE, + VBOXVHWACMD_TYPE_HH_CONSTRUCT, + VBOXVHWACMD_TYPE_HH_RESET +#ifdef VBOX_WITH_WDDM + , VBOXVHWACMD_TYPE_SURF_GETINFO + , VBOXVHWACMD_TYPE_SURF_COLORFILL +#endif + , VBOXVHWACMD_TYPE_HH_DISABLE + , VBOXVHWACMD_TYPE_HH_ENABLE + , VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN + , VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND + , VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM + , VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM +} VBOXVHWACMD_TYPE; + +/** The command processing was asynch, set by the host to indicate asynch + * command completion. Must not be cleared once set, the command completion is + * performed by issuing a host->guest completion command while keeping this + * flag unchanged */ +#define VBOXVHWACMD_FLAG_HG_ASYNCH UINT32_C(0x00010000) +/** asynch completion is performed by issuing the event */ +#define VBOXVHWACMD_FLAG_GH_ASYNCH_EVENT UINT32_C(0x00000001) +/** issue interrupt on asynch completion */ +#define VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ UINT32_C(0x00000002) +/** Guest does not do any op on completion of this command, the host may copy + * the command and indicate that it does not need the command anymore + * by setting the VBOXVHWACMD_FLAG_HG_ASYNCH_RETURNED flag */ +#define VBOXVHWACMD_FLAG_GH_ASYNCH_NOCOMPLETION UINT32_C(0x00000004) +/** the host has copied the VBOXVHWACMD_FLAG_GH_ASYNCH_NOCOMPLETION command and returned it to the guest */ +#define VBOXVHWACMD_FLAG_HG_ASYNCH_RETURNED UINT32_C(0x00020000) +/** this is the host->host cmd, i.e. a configuration command posted by the host to the framebuffer */ +#define VBOXVHWACMD_FLAG_HH_CMD UINT32_C(0x10000000) + +typedef struct VBOXVHWACMD +{ + VBOXVHWACMD_TYPE enmCmd; /**< command type */ + volatile int32_t rc; /**< command result */ + int32_t iDisplay; /**< display index */ + volatile int32_t Flags; /**< ORed VBOXVHWACMD_FLAG_xxx values */ + uint64_t GuestVBVAReserved1; /**< field internally used by the guest VBVA cmd handling, must NOT be modified by clients */ + uint64_t GuestVBVAReserved2; /**< field internally used by the guest VBVA cmd handling, must NOT be modified by clients */ + volatile uint32_t cRefs; + int32_t Reserved; + union + { + struct VBOXVHWACMD *pNext; + uint32_t offNext; + uint64_t Data; /**< the body is 64-bit aligned */ + } u; + char body[1]; +} VBOXVHWACMD; + +#define VBOXVHWACMD_HEADSIZE() (RT_OFFSETOF(VBOXVHWACMD, body)) +#define VBOXVHWACMD_SIZE_FROMBODYSIZE(a_cbBody) (VBOXVHWACMD_HEADSIZE() + (a_cbBody)) +#define VBOXVHWACMD_SIZE(a_tTypeCmd) (VBOXVHWACMD_SIZE_FROMBODYSIZE(sizeof(a_tTypeCmd))) +typedef unsigned int VBOXVHWACMD_LENGTH; +typedef uint64_t VBOXVHWA_SURFHANDLE; +#define VBOXVHWA_SURFHANDLE_INVALID UINT64_C(0) +#define VBOXVHWACMD_BODY(a_pHdr, a_TypeBody) ( (a_TypeBody RT_UNTRUSTED_VOLATILE_HSTGST *)&(a_pHdr)->body[0] ) +#if !defined(IN_GUEST) && defined(IN_RING3) +# define VBOXVHWACMD_BODY_HOST_HEAP(a_pHdr, a_TypeBody) ( (a_TypeBody *)&(a_pHdr)->body[0] ) +#endif +#define VBOXVHWACMD_HEAD(a_pBody)\ + ( (VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HSTGST *)((uint8_t *)(a_pBody) - RT_OFFSETOF(VBOXVHWACMD, body))) + +typedef struct VBOXVHWA_RECTL +{ + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +} VBOXVHWA_RECTL; + +typedef struct VBOXVHWA_COLORKEY +{ + uint32_t low; + uint32_t high; +} VBOXVHWA_COLORKEY; + +typedef struct VBOXVHWA_PIXELFORMAT +{ + uint32_t flags; + uint32_t fourCC; + union + { + uint32_t rgbBitCount; + uint32_t yuvBitCount; + } c; + + union + { + uint32_t rgbRBitMask; + uint32_t yuvYBitMask; + } m1; + + union + { + uint32_t rgbGBitMask; + uint32_t yuvUBitMask; + } m2; + + union + { + uint32_t rgbBBitMask; + uint32_t yuvVBitMask; + } m3; + + union + { + uint32_t rgbABitMask; + } m4; + + uint32_t Reserved; +} VBOXVHWA_PIXELFORMAT; + +typedef struct VBOXVHWA_SURFACEDESC +{ + uint32_t flags; + uint32_t height; + uint32_t width; + uint32_t pitch; + uint32_t sizeX; + uint32_t sizeY; + uint32_t cBackBuffers; + uint32_t Reserved; + VBOXVHWA_COLORKEY DstOverlayCK; + VBOXVHWA_COLORKEY DstBltCK; + VBOXVHWA_COLORKEY SrcOverlayCK; + VBOXVHWA_COLORKEY SrcBltCK; + VBOXVHWA_PIXELFORMAT PixelFormat; + uint32_t surfCaps; + uint32_t Reserved2; + VBOXVHWA_SURFHANDLE hSurf; + uint64_t offSurface; +} VBOXVHWA_SURFACEDESC; + +typedef struct VBOXVHWA_BLTFX +{ + uint32_t flags; + uint32_t rop; + uint32_t rotationOp; + uint32_t rotation; + uint32_t fillColor; + uint32_t Reserved; + VBOXVHWA_COLORKEY DstCK; + VBOXVHWA_COLORKEY SrcCK; +} VBOXVHWA_BLTFX; + +typedef struct VBOXVHWA_OVERLAYFX +{ + uint32_t flags; + uint32_t Reserved1; + uint32_t fxFlags; + uint32_t Reserved2; + VBOXVHWA_COLORKEY DstCK; + VBOXVHWA_COLORKEY SrcCK; +} VBOXVHWA_OVERLAYFX; + +#define VBOXVHWA_CAPS_BLT 0x00000040 +#define VBOXVHWA_CAPS_BLTCOLORFILL 0x04000000 +#define VBOXVHWA_CAPS_BLTFOURCC 0x00000100 +#define VBOXVHWA_CAPS_BLTSTRETCH 0x00000200 +#define VBOXVHWA_CAPS_BLTQUEUE 0x00000080 + +#define VBOXVHWA_CAPS_OVERLAY 0x00000800 +#define VBOXVHWA_CAPS_OVERLAYFOURCC 0x00002000 +#define VBOXVHWA_CAPS_OVERLAYSTRETCH 0x00004000 +#define VBOXVHWA_CAPS_OVERLAYCANTCLIP 0x00001000 + +#define VBOXVHWA_CAPS_COLORKEY 0x00400000 +#define VBOXVHWA_CAPS_COLORKEYHWASSIST 0x01000000 + +#define VBOXVHWA_SCAPS_BACKBUFFER 0x00000004 +#define VBOXVHWA_SCAPS_COMPLEX 0x00000008 +#define VBOXVHWA_SCAPS_FLIP 0x00000010 +#define VBOXVHWA_SCAPS_FRONTBUFFER 0x00000020 +#define VBOXVHWA_SCAPS_OFFSCREENPLAIN 0x00000040 +#define VBOXVHWA_SCAPS_OVERLAY 0x00000080 +#define VBOXVHWA_SCAPS_PRIMARYSURFACE 0x00000200 +#define VBOXVHWA_SCAPS_SYSTEMMEMORY 0x00000800 +#define VBOXVHWA_SCAPS_VIDEOMEMORY 0x00004000 +#define VBOXVHWA_SCAPS_VISIBLE 0x00008000 +#define VBOXVHWA_SCAPS_LOCALVIDMEM 0x10000000 + +#define VBOXVHWA_PF_PALETTEINDEXED8 0x00000020 +#define VBOXVHWA_PF_RGB 0x00000040 +#define VBOXVHWA_PF_RGBTOYUV 0x00000100 +#define VBOXVHWA_PF_YUV 0x00000200 +#define VBOXVHWA_PF_FOURCC 0x00000004 + +#define VBOXVHWA_LOCK_DISCARDCONTENTS 0x00002000 + +#define VBOXVHWA_CFG_ENABLED 0x00000001 + +#define VBOXVHWA_SD_BACKBUFFERCOUNT 0x00000020 +#define VBOXVHWA_SD_CAPS 0x00000001 +#define VBOXVHWA_SD_CKDESTBLT 0x00004000 +#define VBOXVHWA_SD_CKDESTOVERLAY 0x00002000 +#define VBOXVHWA_SD_CKSRCBLT 0x00010000 +#define VBOXVHWA_SD_CKSRCOVERLAY 0x00008000 +#define VBOXVHWA_SD_HEIGHT 0x00000002 +#define VBOXVHWA_SD_PITCH 0x00000008 +#define VBOXVHWA_SD_PIXELFORMAT 0x00001000 +/*#define VBOXVHWA_SD_REFRESHRATE 0x00040000*/ +#define VBOXVHWA_SD_WIDTH 0x00000004 + +#define VBOXVHWA_CKEYCAPS_DESTBLT 0x00000001 +#define VBOXVHWA_CKEYCAPS_DESTBLTCLRSPACE 0x00000002 +#define VBOXVHWA_CKEYCAPS_DESTBLTCLRSPACEYUV 0x00000004 +#define VBOXVHWA_CKEYCAPS_DESTBLTYUV 0x00000008 +#define VBOXVHWA_CKEYCAPS_DESTOVERLAY 0x00000010 +#define VBOXVHWA_CKEYCAPS_DESTOVERLAYCLRSPACE 0x00000020 +#define VBOXVHWA_CKEYCAPS_DESTOVERLAYCLRSPACEYUV 0x00000040 +#define VBOXVHWA_CKEYCAPS_DESTOVERLAYONEACTIVE 0x00000080 +#define VBOXVHWA_CKEYCAPS_DESTOVERLAYYUV 0x00000100 +#define VBOXVHWA_CKEYCAPS_SRCBLT 0x00000200 +#define VBOXVHWA_CKEYCAPS_SRCBLTCLRSPACE 0x00000400 +#define VBOXVHWA_CKEYCAPS_SRCBLTCLRSPACEYUV 0x00000800 +#define VBOXVHWA_CKEYCAPS_SRCBLTYUV 0x00001000 +#define VBOXVHWA_CKEYCAPS_SRCOVERLAY 0x00002000 +#define VBOXVHWA_CKEYCAPS_SRCOVERLAYCLRSPACE 0x00004000 +#define VBOXVHWA_CKEYCAPS_SRCOVERLAYCLRSPACEYUV 0x00008000 +#define VBOXVHWA_CKEYCAPS_SRCOVERLAYONEACTIVE 0x00010000 +#define VBOXVHWA_CKEYCAPS_SRCOVERLAYYUV 0x00020000 +#define VBOXVHWA_CKEYCAPS_NOCOSTOVERLAY 0x00040000 + +#define VBOXVHWA_BLT_COLORFILL 0x00000400 +#define VBOXVHWA_BLT_DDFX 0x00000800 +#define VBOXVHWA_BLT_EXTENDED_FLAGS 0x40000000 +#define VBOXVHWA_BLT_EXTENDED_LINEAR_CONTENT 0x00000004 +#define VBOXVHWA_BLT_EXTENDED_PRESENTATION_STRETCHFACTOR 0x00000010 +#define VBOXVHWA_BLT_KEYDESTOVERRIDE 0x00004000 +#define VBOXVHWA_BLT_KEYSRCOVERRIDE 0x00010000 +#define VBOXVHWA_BLT_LAST_PRESENTATION 0x20000000 +#define VBOXVHWA_BLT_PRESENTATION 0x10000000 +#define VBOXVHWA_BLT_ROP 0x00020000 + + +#define VBOXVHWA_OVER_DDFX 0x00080000 +#define VBOXVHWA_OVER_HIDE 0x00000200 +#define VBOXVHWA_OVER_KEYDEST 0x00000400 +#define VBOXVHWA_OVER_KEYDESTOVERRIDE 0x00000800 +#define VBOXVHWA_OVER_KEYSRC 0x00001000 +#define VBOXVHWA_OVER_KEYSRCOVERRIDE 0x00002000 +#define VBOXVHWA_OVER_SHOW 0x00004000 + +#define VBOXVHWA_CKEY_COLORSPACE 0x00000001 +#define VBOXVHWA_CKEY_DESTBLT 0x00000002 +#define VBOXVHWA_CKEY_DESTOVERLAY 0x00000004 +#define VBOXVHWA_CKEY_SRCBLT 0x00000008 +#define VBOXVHWA_CKEY_SRCOVERLAY 0x00000010 + +#define VBOXVHWA_BLT_ARITHSTRETCHY 0x00000001 +#define VBOXVHWA_BLT_MIRRORLEFTRIGHT 0x00000002 +#define VBOXVHWA_BLT_MIRRORUPDOWN 0x00000004 + +#define VBOXVHWA_OVERFX_ARITHSTRETCHY 0x00000001 +#define VBOXVHWA_OVERFX_MIRRORLEFTRIGHT 0x00000002 +#define VBOXVHWA_OVERFX_MIRRORUPDOWN 0x00000004 + +#define VBOXVHWA_CAPS2_CANRENDERWINDOWED 0x00080000 +#define VBOXVHWA_CAPS2_WIDESURFACES 0x00001000 +#define VBOXVHWA_CAPS2_COPYFOURCC 0x00008000 +/*#define VBOXVHWA_CAPS2_FLIPINTERVAL 0x00200000*/ +/*#define VBOXVHWA_CAPS2_FLIPNOVSYNC 0x00400000*/ + + +#define VBOXVHWA_OFFSET64_VOID (UINT64_MAX) + +typedef struct VBOXVHWA_VERSION +{ + uint32_t maj; + uint32_t min; + uint32_t bld; + uint32_t reserved; +} VBOXVHWA_VERSION; + +#define VBOXVHWA_VERSION_INIT(_pv) do { \ + (_pv)->maj = VBOXVHWA_VERSION_MAJ; \ + (_pv)->min = VBOXVHWA_VERSION_MIN; \ + (_pv)->bld = VBOXVHWA_VERSION_BLD; \ + (_pv)->reserved = VBOXVHWA_VERSION_RSV; \ + } while(0) + +typedef struct VBOXVHWACMD_QUERYINFO1 +{ + union + { + struct + { + VBOXVHWA_VERSION guestVersion; + } in; + + struct + { + uint32_t cfgFlags; + uint32_t caps; + + uint32_t caps2; + uint32_t colorKeyCaps; + + uint32_t stretchCaps; + uint32_t surfaceCaps; + + uint32_t numOverlays; + uint32_t curOverlays; + + uint32_t numFourCC; + uint32_t reserved; + } out; + } u; +} VBOXVHWACMD_QUERYINFO1; + +typedef struct VBOXVHWACMD_QUERYINFO2 +{ + uint32_t numFourCC; + uint32_t FourCC[1]; +} VBOXVHWACMD_QUERYINFO2; + +#define VBOXVHWAINFO2_SIZE(_cFourCC) RT_UOFFSETOF_DYN(VBOXVHWACMD_QUERYINFO2, FourCC[_cFourCC]) + +typedef struct VBOXVHWACMD_SURF_CANCREATE +{ + VBOXVHWA_SURFACEDESC SurfInfo; + union + { + struct + { + uint32_t bIsDifferentPixelFormat; + uint32_t Reserved; + } in; + + struct + { + int32_t ErrInfo; + } out; + } u; +} VBOXVHWACMD_SURF_CANCREATE; + +typedef struct VBOXVHWACMD_SURF_CREATE +{ + VBOXVHWA_SURFACEDESC SurfInfo; +} VBOXVHWACMD_SURF_CREATE; + +#ifdef VBOX_WITH_WDDM +typedef struct VBOXVHWACMD_SURF_GETINFO +{ + VBOXVHWA_SURFACEDESC SurfInfo; +} VBOXVHWACMD_SURF_GETINFO; +#endif + +typedef struct VBOXVHWACMD_SURF_DESTROY +{ + union + { + struct + { + VBOXVHWA_SURFHANDLE hSurf; + } in; + } u; +} VBOXVHWACMD_SURF_DESTROY; + +typedef struct VBOXVHWACMD_SURF_LOCK +{ + union + { + struct + { + VBOXVHWA_SURFHANDLE hSurf; + uint64_t offSurface; + uint32_t flags; + uint32_t rectValid; + VBOXVHWA_RECTL rect; + } in; + } u; +} VBOXVHWACMD_SURF_LOCK; + +typedef struct VBOXVHWACMD_SURF_UNLOCK +{ + union + { + struct + { + VBOXVHWA_SURFHANDLE hSurf; + uint32_t xUpdatedMemValid; + uint32_t reserved; + VBOXVHWA_RECTL xUpdatedMemRect; + } in; + } u; +} VBOXVHWACMD_SURF_UNLOCK; + +typedef struct VBOXVHWACMD_SURF_BLT +{ + uint64_t DstGuestSurfInfo; + uint64_t SrcGuestSurfInfo; + union + { + struct + { + VBOXVHWA_SURFHANDLE hDstSurf; + uint64_t offDstSurface; + VBOXVHWA_RECTL dstRect; + VBOXVHWA_SURFHANDLE hSrcSurf; + uint64_t offSrcSurface; + VBOXVHWA_RECTL srcRect; + uint32_t flags; + uint32_t xUpdatedSrcMemValid; + VBOXVHWA_BLTFX desc; + VBOXVHWA_RECTL xUpdatedSrcMemRect; + } in; + } u; +} VBOXVHWACMD_SURF_BLT; + +#ifdef VBOX_WITH_WDDM +typedef struct VBOXVHWACMD_SURF_COLORFILL +{ + union + { + struct + { + VBOXVHWA_SURFHANDLE hSurf; + uint64_t offSurface; + uint32_t u32Reserved; + uint32_t cRects; + VBOXVHWA_RECTL aRects[1]; + } in; + } u; +} VBOXVHWACMD_SURF_COLORFILL; +#endif + +typedef struct VBOXVHWACMD_SURF_FLIP +{ + uint64_t TargGuestSurfInfo; + uint64_t CurrGuestSurfInfo; + union + { + struct + { + VBOXVHWA_SURFHANDLE hTargSurf; + uint64_t offTargSurface; + VBOXVHWA_SURFHANDLE hCurrSurf; + uint64_t offCurrSurface; + uint32_t flags; + uint32_t xUpdatedTargMemValid; + VBOXVHWA_RECTL xUpdatedTargMemRect; + } in; + } u; +} VBOXVHWACMD_SURF_FLIP; + +typedef struct VBOXVHWACMD_SURF_COLORKEY_SET +{ + union + { + struct + { + VBOXVHWA_SURFHANDLE hSurf; + uint64_t offSurface; + VBOXVHWA_COLORKEY CKey; + uint32_t flags; + uint32_t reserved; + } in; + } u; +} VBOXVHWACMD_SURF_COLORKEY_SET; + +#define VBOXVHWACMD_SURF_OVERLAY_UPDATE_F_SRCMEMRECT 0x00000001 +#define VBOXVHWACMD_SURF_OVERLAY_UPDATE_F_DSTMEMRECT 0x00000002 + +typedef struct VBOXVHWACMD_SURF_OVERLAY_UPDATE +{ + union + { + struct + { + VBOXVHWA_SURFHANDLE hDstSurf; + uint64_t offDstSurface; + VBOXVHWA_RECTL dstRect; + VBOXVHWA_SURFHANDLE hSrcSurf; + uint64_t offSrcSurface; + VBOXVHWA_RECTL srcRect; + uint32_t flags; + uint32_t xFlags; + VBOXVHWA_OVERLAYFX desc; + VBOXVHWA_RECTL xUpdatedSrcMemRect; + VBOXVHWA_RECTL xUpdatedDstMemRect; + } in; + } u; +}VBOXVHWACMD_SURF_OVERLAY_UPDATE; + +typedef struct VBOXVHWACMD_SURF_OVERLAY_SETPOSITION +{ + union + { + struct + { + VBOXVHWA_SURFHANDLE hDstSurf; + uint64_t offDstSurface; + VBOXVHWA_SURFHANDLE hSrcSurf; + uint64_t offSrcSurface; + uint32_t xPos; + uint32_t yPos; + uint32_t flags; + uint32_t reserved; + } in; + } u; +} VBOXVHWACMD_SURF_OVERLAY_SETPOSITION; + +typedef struct VBOXVHWACMD_HH_CONSTRUCT +{ + void *pVM; + /* VRAM info for the backend to be able to properly translate VRAM offsets */ + void *pvVRAM; + uint32_t cbVRAM; +} VBOXVHWACMD_HH_CONSTRUCT; + +typedef struct VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM +{ + struct SSMHANDLE * pSSM; +} VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM; + +typedef struct VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM +{ + struct SSMHANDLE * pSSM; +} VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM; + +typedef DECLCALLBACKTYPE(void, FNVBOXVHWA_HH_CALLBACK,(void *)); +typedef FNVBOXVHWA_HH_CALLBACK *PFNVBOXVHWA_HH_CALLBACK; + +#define VBOXVHWA_HH_CALLBACK_SET(_pCmd, _pfn, _parg) \ + do { \ + (_pCmd)->GuestVBVAReserved1 = (uint64_t)(uintptr_t)(_pfn); \ + (_pCmd)->GuestVBVAReserved2 = (uint64_t)(uintptr_t)(_parg); \ + }while(0) + +#define VBOXVHWA_HH_CALLBACK_GET(_pCmd) ((PFNVBOXVHWA_HH_CALLBACK)(_pCmd)->GuestVBVAReserved1) +#define VBOXVHWA_HH_CALLBACK_GET_ARG(_pCmd) ((void*)(_pCmd)->GuestVBVAReserved2) + +#pragma pack() +#endif /* #ifdef VBOX_WITH_VIDEOHWACCEL */ + +/* All structures are without alignment. */ +#pragma pack(1) + +typedef struct VBVAHOSTFLAGS +{ + uint32_t u32HostEvents; + uint32_t u32SupportedOrders; +} VBVAHOSTFLAGS; + +typedef struct VBVABUFFER +{ + VBVAHOSTFLAGS hostFlags; + + /* The offset where the data start in the buffer. */ + uint32_t off32Data; + /* The offset where next data must be placed in the buffer. */ + uint32_t off32Free; + + /* The queue of record descriptions. */ + VBVARECORD aRecords[VBVA_MAX_RECORDS]; + uint32_t indexRecordFirst; + uint32_t indexRecordFree; + + /* Space to leave free in the buffer when large partial records are transferred. */ + uint32_t cbPartialWriteThreshold; + + uint32_t cbData; + uint8_t au8Data[1]; /* variable size for the rest of the VBVABUFFER area in VRAM. */ +} VBVABUFFER; + +#define VBVA_MAX_RECORD_SIZE (128*_1M) + +/* guest->host commands */ +#define VBVA_QUERY_CONF32 1 +#define VBVA_SET_CONF32 2 +#define VBVA_INFO_VIEW 3 +#define VBVA_INFO_HEAP 4 +#define VBVA_FLUSH 5 +#define VBVA_INFO_SCREEN 6 +/** Enables or disables VBVA. Enabling VBVA without disabling it before + * causes a complete screen update. */ +#define VBVA_ENABLE 7 +#define VBVA_MOUSE_POINTER_SHAPE 8 +#ifdef VBOX_WITH_VIDEOHWACCEL +# define VBVA_VHWA_CMD 9 +#endif /* # ifdef VBOX_WITH_VIDEOHWACCEL */ +#ifdef VBOX_WITH_VDMA +# define VBVA_VDMA_CTL 10 /* setup G<->H DMA channel info */ +# define VBVA_VDMA_CMD 11 /* G->H DMA command */ +#endif +#define VBVA_INFO_CAPS 12 /* informs host about HGSMI caps. see VBVACAPS below */ +#define VBVA_SCANLINE_CFG 13 /* configures scanline, see VBVASCANLINECFG below */ +#define VBVA_SCANLINE_INFO 14 /* requests scanline info, see VBVASCANLINEINFO below */ +#define VBVA_CMDVBVA_SUBMIT 16 /* inform host about VBVA Command submission */ +#define VBVA_CMDVBVA_FLUSH 17 /* inform host about VBVA Command submission */ +#define VBVA_CMDVBVA_CTL 18 /* G->H DMA command */ +#define VBVA_QUERY_MODE_HINTS 19 /* Query most recent mode hints sent. */ +/** Report the guest virtual desktop position and size for mapping host and + * guest pointer positions. */ +#define VBVA_REPORT_INPUT_MAPPING 20 +/** Report the guest cursor position and query the host position. */ +#define VBVA_CURSOR_POSITION 21 + +/* host->guest commands */ +#define VBVAHG_EVENT 1 +#define VBVAHG_DISPLAY_CUSTOM 2 +#ifdef VBOX_WITH_VDMA +#define VBVAHG_SHGSMI_COMPLETION 3 +#endif + +#ifdef VBOX_WITH_VIDEOHWACCEL +#define VBVAHG_DCUSTOM_VHWA_CMDCOMPLETE 1 +#pragma pack(1) +typedef struct VBVAHOSTCMDVHWACMDCOMPLETE +{ + uint32_t offCmd; +}VBVAHOSTCMDVHWACMDCOMPLETE; +#pragma pack() +#endif /* # ifdef VBOX_WITH_VIDEOHWACCEL */ + +#pragma pack(1) +typedef enum +{ + VBVAHOSTCMD_OP_EVENT = 1, + VBVAHOSTCMD_OP_CUSTOM +}VBVAHOSTCMD_OP_TYPE; + +typedef struct VBVAHOSTCMDEVENT +{ + uint64_t pEvent; +}VBVAHOSTCMDEVENT; + + +typedef struct VBVAHOSTCMD +{ + /* destination ID if >=0 specifies display index, otherwize the command is directed to the miniport */ + int32_t iDstID; + int32_t customOpCode; + union + { + struct VBVAHOSTCMD *pNext; + uint32_t offNext; + uint64_t Data; /* the body is 64-bit aligned */ + } u; + char body[1]; +} VBVAHOSTCMD; + +#define VBVAHOSTCMD_SIZE(a_cb) (sizeof(VBVAHOSTCMD) + (a_cb)) +#define VBVAHOSTCMD_BODY(a_pCmd, a_TypeBody) ((a_TypeBody RT_UNTRUSTED_VOLATILE_HSTGST *)&(a_pCmd)->body[0]) +#define VBVAHOSTCMD_HDR(a_pBody) \ + ( (VBVAHOSTCMD RT_UNTRUSTED_VOLATILE_HSTGST *)( (uint8_t *)(a_pBody) - RT_OFFSETOF(VBVAHOSTCMD, body)) ) +#define VBVAHOSTCMD_HDRSIZE (RT_OFFSETOF(VBVAHOSTCMD, body)) + +#pragma pack() + +/* VBVACONF32::u32Index */ +#define VBOX_VBVA_CONF32_MONITOR_COUNT 0 +#define VBOX_VBVA_CONF32_HOST_HEAP_SIZE 1 +/** Returns VINF_SUCCESS if the host can report mode hints via VBVA. + * Set value to VERR_NOT_SUPPORTED before calling. */ +#define VBOX_VBVA_CONF32_MODE_HINT_REPORTING 2 +/** Returns VINF_SUCCESS if the host can report guest cursor enabled status via + * VBVA. Set value to VERR_NOT_SUPPORTED before calling. */ +#define VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING 3 +/** Returns the currently available host cursor capabilities. Available if + * VBVACONF32::VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING returns success. + * @see VMMDevReqMouseStatus::mouseFeatures. */ +#define VBOX_VBVA_CONF32_CURSOR_CAPABILITIES 4 +/** Returns the supported flags in VBVAINFOSCREEN::u8Flags. */ +#define VBOX_VBVA_CONF32_SCREEN_FLAGS 5 +/** Returns the max size of VBVA record. */ +#define VBOX_VBVA_CONF32_MAX_RECORD_SIZE 6 + +typedef struct VBVACONF32 +{ + uint32_t u32Index; + uint32_t u32Value; +} VBVACONF32; + +/** Reserved for historical reasons. */ +#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED0 RT_BIT(0) +/** Guest cursor capability: can the host show a hardware cursor at the host + * pointer location? */ +#define VBOX_VBVA_CURSOR_CAPABILITY_HARDWARE RT_BIT(1) +/** Reserved for historical reasons. */ +#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED2 RT_BIT(2) +/** Reserved for historical reasons. Must always be unset. */ +#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED3 RT_BIT(3) +/** Reserved for historical reasons. */ +#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED4 RT_BIT(4) +/** Reserved for historical reasons. */ +#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED5 RT_BIT(5) + +typedef struct VBVAINFOVIEW +{ + /* Index of the screen, assigned by the guest. */ + uint32_t u32ViewIndex; + + /* The screen offset in VRAM, the framebuffer starts here. */ + uint32_t u32ViewOffset; + + /* The size of the VRAM memory that can be used for the view. */ + uint32_t u32ViewSize; + + /* The recommended maximum size of the VRAM memory for the screen. */ + uint32_t u32MaxScreenSize; +} VBVAINFOVIEW; + +typedef struct VBVAINFOHEAP +{ + /* Absolute offset in VRAM of the start of the heap. */ + uint32_t u32HeapOffset; + + /* The size of the heap. */ + uint32_t u32HeapSize; + +} VBVAINFOHEAP; + +typedef struct VBVAFLUSH +{ + uint32_t u32Reserved; + +} VBVAFLUSH; + +typedef struct VBVACMDVBVASUBMIT +{ + uint32_t u32Reserved; +} VBVACMDVBVASUBMIT; + +/* flush is requested because due to guest command buffer overflow */ +#define VBVACMDVBVAFLUSH_F_GUEST_BUFFER_OVERFLOW 1 + +typedef struct VBVACMDVBVAFLUSH +{ + uint32_t u32Flags; +} VBVACMDVBVAFLUSH; + + +/* VBVAINFOSCREEN::u8Flags */ +#define VBVA_SCREEN_F_NONE 0x0000 +#define VBVA_SCREEN_F_ACTIVE 0x0001 +/** The virtual monitor has been disabled by the guest and should be removed + * by the host and ignored for purposes of pointer position calculation. */ +#define VBVA_SCREEN_F_DISABLED 0x0002 +/** The virtual monitor has been blanked by the guest and should be blacked + * out by the host using width, height, etc values from the VBVAINFOSCREEN request. */ +#define VBVA_SCREEN_F_BLANK 0x0004 +/** The virtual monitor has been blanked by the guest and should be blacked + * out by the host using the previous mode values for width. height, etc. */ +#define VBVA_SCREEN_F_BLANK2 0x0008 + +typedef struct VBVAINFOSCREEN +{ + /* Which view contains the screen. */ + uint32_t u32ViewIndex; + + /* Physical X origin relative to the primary screen. */ + int32_t i32OriginX; + + /* Physical Y origin relative to the primary screen. */ + int32_t i32OriginY; + + /* Offset of visible framebuffer relative to the framebuffer start. */ + uint32_t u32StartOffset; + + /* The scan line size in bytes. */ + uint32_t u32LineSize; + + /* Width of the screen. */ + uint32_t u32Width; + + /* Height of the screen. */ + uint32_t u32Height; + + /* Color depth. */ + uint16_t u16BitsPerPixel; + + /* VBVA_SCREEN_F_* */ + uint16_t u16Flags; +} VBVAINFOSCREEN; + + +/* VBVAENABLE::u32Flags */ +#define VBVA_F_NONE 0x00000000 +#define VBVA_F_ENABLE 0x00000001 +#define VBVA_F_DISABLE 0x00000002 +/* extended VBVA to be used with WDDM */ +#define VBVA_F_EXTENDED 0x00000004 +/* vbva offset is absolute VRAM offset */ +#define VBVA_F_ABSOFFSET 0x00000008 + +typedef struct VBVAENABLE +{ + uint32_t u32Flags; + uint32_t u32Offset; + int32_t i32Result; +} VBVAENABLE; + +typedef struct VBVAENABLE_EX +{ + VBVAENABLE Base; + uint32_t u32ScreenId; +} VBVAENABLE_EX; + + +typedef struct VBVAMOUSEPOINTERSHAPE +{ + /* The host result. */ + int32_t i32Result; + + /* VBOX_MOUSE_POINTER_* bit flags. */ + uint32_t fu32Flags; + + /* X coordinate of the hot spot. */ + uint32_t u32HotX; + + /* Y coordinate of the hot spot. */ + uint32_t u32HotY; + + /* Width of the pointer in pixels. */ + uint32_t u32Width; + + /* Height of the pointer in scanlines. */ + uint32_t u32Height; + + /* Pointer data. + * + **** + * The data consists of 1 bpp AND mask followed by 32 bpp XOR (color) mask. + * + * For pointers without alpha channel the XOR mask pixels are 32 bit values: (lsb)BGR0(msb). + * For pointers with alpha channel the XOR mask consists of (lsb)BGRA(msb) 32 bit values. + * + * Guest driver must create the AND mask for pointers with alpha channel, so if host does not + * support alpha, the pointer could be displayed as a normal color pointer. The AND mask can + * be constructed from alpha values. For example alpha value >= 0xf0 means bit 0 in the AND mask. + * + * The AND mask is 1 bpp bitmap with byte aligned scanlines. Size of AND mask, + * therefore, is cbAnd = (width + 7) / 8 * height. The padding bits at the + * end of any scanline are undefined. + * + * The XOR mask follows the AND mask on the next 4 bytes aligned offset: + * uint8_t *pXor = pAnd + (cbAnd + 3) & ~3 + * Bytes in the gap between the AND and the XOR mask are undefined. + * XOR mask scanlines have no gap between them and size of XOR mask is: + * cXor = width * 4 * height. + **** + * + * Preallocate 4 bytes for accessing actual data as p->au8Data. + */ + uint8_t au8Data[4]; + +} VBVAMOUSEPOINTERSHAPE; + +/** @name VBVAMOUSEPOINTERSHAPE::fu32Flags + * @note The VBOX_MOUSE_POINTER_* flags are used in the guest video driver, + * values must be <= 0x8000 and must not be changed. (try make more sense + * of this, please). + * @{ + */ +/** pointer is visible */ +#define VBOX_MOUSE_POINTER_VISIBLE (0x0001) +/** pointer has alpha channel */ +#define VBOX_MOUSE_POINTER_ALPHA (0x0002) +/** pointerData contains new pointer shape */ +#define VBOX_MOUSE_POINTER_SHAPE (0x0004) +/** @} */ + +/* the guest driver can handle asynch guest cmd completion by reading the command offset from io port */ +#define VBVACAPS_COMPLETEGCMD_BY_IOREAD 0x00000001 +/* the guest driver can handle video adapter IRQs */ +#define VBVACAPS_IRQ 0x00000002 +/** The guest can read video mode hints sent via VBVA. */ +#define VBVACAPS_VIDEO_MODE_HINTS 0x00000004 +/** The guest can switch to a software cursor on demand. */ +#define VBVACAPS_DISABLE_CURSOR_INTEGRATION 0x00000008 +/** The guest does not depend on host handling the VBE registers. */ +#define VBVACAPS_USE_VBVA_ONLY 0x00000010 +typedef struct VBVACAPS +{ + int32_t rc; + uint32_t fCaps; +} VBVACAPS; + +/* makes graphics device generate IRQ on VSYNC */ +#define VBVASCANLINECFG_ENABLE_VSYNC_IRQ 0x00000001 +/* guest driver may request the current scanline */ +#define VBVASCANLINECFG_ENABLE_SCANLINE_INFO 0x00000002 +/* request the current refresh period, returned in u32RefreshPeriodMs */ +#define VBVASCANLINECFG_QUERY_REFRESH_PERIOD 0x00000004 +/* set new refresh period specified in u32RefreshPeriodMs. + * if used with VBVASCANLINECFG_QUERY_REFRESH_PERIOD, + * u32RefreshPeriodMs is set to the previous refresh period on return */ +#define VBVASCANLINECFG_SET_REFRESH_PERIOD 0x00000008 + +typedef struct VBVASCANLINECFG +{ + int32_t rc; + uint32_t fFlags; + uint32_t u32RefreshPeriodMs; + uint32_t u32Reserved; +} VBVASCANLINECFG; + +typedef struct VBVASCANLINEINFO +{ + int32_t rc; + uint32_t u32ScreenId; + uint32_t u32InVBlank; + uint32_t u32ScanLine; +} VBVASCANLINEINFO; + +/** Query the most recent mode hints received from the host. */ +typedef struct VBVAQUERYMODEHINTS +{ + /** The maximum number of screens to return hints for. */ + uint16_t cHintsQueried; + /** The size of the mode hint structures directly following this one. */ + uint16_t cbHintStructureGuest; + /** The return code for the operation. Initialise to VERR_NOT_SUPPORTED. */ + int32_t rc; +} VBVAQUERYMODEHINTS; + +/** Structure in which a mode hint is returned. The guest allocates an array + * of these immediately after the VBVAQUERYMODEHINTS structure. To accomodate + * future extensions, the VBVAQUERYMODEHINTS structure specifies the size of + * the VBVAMODEHINT structures allocated by the guest, and the host only fills + * out structure elements which fit into that size. The host should fill any + * unused members (e.g. dx, dy) or structure space on the end with ~0. The + * whole structure can legally be set to ~0 to skip a screen. */ +typedef struct VBVAMODEHINT +{ + uint32_t magic; + uint32_t cx; + uint32_t cy; + uint32_t cBPP; /* Which has never been used... */ + uint32_t cDisplay; + uint32_t dx; /**< X offset into the virtual frame-buffer. */ + uint32_t dy; /**< Y offset into the virtual frame-buffer. */ + uint32_t fEnabled; /* Not fFlags. Add new members for new flags. */ +} VBVAMODEHINT; + +#define VBVAMODEHINT_MAGIC UINT32_C(0x0801add9) + +/** Report the rectangle relative to which absolute pointer events should be + * expressed. This information remains valid until the next VBVA resize event + * for any screen, at which time it is reset to the bounding rectangle of all + * virtual screens and must be re-set. + * @see VBVA_REPORT_INPUT_MAPPING. */ +typedef struct VBVAREPORTINPUTMAPPING +{ + int32_t x; /**< Upper left X co-ordinate relative to the first screen. */ + int32_t y; /**< Upper left Y co-ordinate relative to the first screen. */ + uint32_t cx; /**< Rectangle width. */ + uint32_t cy; /**< Rectangle height. */ +} VBVAREPORTINPUTMAPPING; + +/** Report the guest cursor position and query the host one. The host may wish + * to use the guest information to re-position its own cursor, particularly + * when the cursor is captured and the guest does not support switching to a + * software cursor. After every mode switch the guest must signal that it + * supports sending position information by sending an event with + * @a fReportPosition set to false. + * @see VBVA_CURSOR_POSITION */ +typedef struct VBVACURSORPOSITION +{ + uint32_t fReportPosition; /**< Are we reporting a position? */ + uint32_t x; /**< Guest cursor X position */ + uint32_t y; /**< Guest cursor Y position */ +} VBVACURSORPOSITION; + +#pragma pack() + +typedef uint64_t VBOXVIDEOOFFSET; + +#define VBOXVIDEOOFFSET_VOID ((VBOXVIDEOOFFSET)~0) + +#pragma pack(1) + +/* + * VBOXSHGSMI made on top HGSMI and allows receiving notifications + * about G->H command completion + */ +/* SHGSMI command header */ +typedef struct VBOXSHGSMIHEADER +{ + uint64_t pvNext; /*<- completion processing queue */ + uint32_t fFlags; /*<- see VBOXSHGSMI_FLAG_XXX Flags */ + uint32_t cRefs; /*<- command referece count */ + uint64_t u64Info1; /*<- contents depends on the fFlags value */ + uint64_t u64Info2; /*<- contents depends on the fFlags value */ +} VBOXSHGSMIHEADER, *PVBOXSHGSMIHEADER; + +typedef enum +{ + VBOXVDMACMD_TYPE_UNDEFINED = 0, + VBOXVDMACMD_TYPE_DMA_PRESENT_BLT = 1, + VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER, + VBOXVDMACMD_TYPE_DMA_BPB_FILL, + VBOXVDMACMD_TYPE_DMA_PRESENT_SHADOW2PRIMARY, + VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL, + VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP, + VBOXVDMACMD_TYPE_DMA_NOP, + VBOXVDMACMD_TYPE_CHROMIUM_CMD, /* chromium cmd */ + VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER_VRAMSYS, + VBOXVDMACMD_TYPE_CHILD_STATUS_IRQ /* make the device notify child (monitor) state change IRQ */ +} VBOXVDMACMD_TYPE; + +#pragma pack() + +/* the command processing was asynch, set by the host to indicate asynch command completion + * must not be cleared once set, the command completion is performed by issuing a host->guest completion command + * while keeping this flag unchanged */ +#define VBOXSHGSMI_FLAG_HG_ASYNCH 0x00010000 +#if 0 +/* if set - asynch completion is performed by issuing the event, + * if cleared - asynch completion is performed by calling a callback */ +#define VBOXSHGSMI_FLAG_GH_ASYNCH_EVENT 0x00000001 +#endif +/* issue interrupt on asynch completion, used for critical G->H commands, + * i.e. for completion of which guest is waiting. */ +#define VBOXSHGSMI_FLAG_GH_ASYNCH_IRQ 0x00000002 +/* guest does not do any op on completion of this command, + * the host may copy the command and indicate that it does not need the command anymore + * by not setting VBOXSHGSMI_FLAG_HG_ASYNCH */ +#define VBOXSHGSMI_FLAG_GH_ASYNCH_NOCOMPLETION 0x00000004 +/* guest requires the command to be processed asynchronously, + * not setting VBOXSHGSMI_FLAG_HG_ASYNCH by the host in this case is treated as command failure */ +#define VBOXSHGSMI_FLAG_GH_ASYNCH_FORCE 0x00000008 +/* force IRQ on cmd completion */ +#define VBOXSHGSMI_FLAG_GH_ASYNCH_IRQ_FORCE 0x00000010 +/* an IRQ-level callback is associated with the command */ +#define VBOXSHGSMI_FLAG_GH_ASYNCH_CALLBACK_IRQ 0x00000020 +/* guest expects this command to be completed synchronously */ +#define VBOXSHGSMI_FLAG_GH_SYNCH 0x00000040 + + +DECLINLINE(uint8_t RT_UNTRUSTED_VOLATILE_GUEST *) +VBoxSHGSMIBufferData(const VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_GUEST *pHeader) +{ + return (uint8_t RT_UNTRUSTED_VOLATILE_GUEST *)pHeader + sizeof(VBOXSHGSMIHEADER); +} + +#define VBoxSHGSMIBufferHeaderSize() (sizeof(VBOXSHGSMIHEADER)) + +DECLINLINE(VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_GUEST *) VBoxSHGSMIBufferHeader(const void RT_UNTRUSTED_VOLATILE_GUEST *pvData) +{ + return (VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_GUEST *)((uintptr_t)pvData - sizeof(VBOXSHGSMIHEADER)); +} + +#ifdef VBOX_WITH_VDMA +# pragma pack(1) + +/* VDMA - Video DMA */ + +/* VDMA Control API */ +/* VBOXVDMA_CTL::u32Flags */ +typedef enum +{ + VBOXVDMA_CTL_TYPE_NONE = 0, + VBOXVDMA_CTL_TYPE_ENABLE, + VBOXVDMA_CTL_TYPE_DISABLE, + VBOXVDMA_CTL_TYPE_FLUSH, + VBOXVDMA_CTL_TYPE_WATCHDOG, + VBOXVDMA_CTL_TYPE_END +} VBOXVDMA_CTL_TYPE; + +typedef struct VBOXVDMA_CTL +{ + VBOXVDMA_CTL_TYPE enmCtl; + uint32_t u32Offset; + int32_t i32Result; +} VBOXVDMA_CTL; + +/* VBOXVDMACBUF_DR::phBuf specifies offset in VRAM */ +#define VBOXVDMACBUF_FLAG_BUF_VRAM_OFFSET 0x00000001 +/* command buffer follows the VBOXVDMACBUF_DR in VRAM, VBOXVDMACBUF_DR::phBuf is ignored */ +#define VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR 0x00000002 + +/** + * We can not submit the DMA command via VRAM since we do not have control over + * DMA command buffer [de]allocation, i.e. we only control the buffer contents. + * In other words the system may call one of our callbacks to fill a command buffer + * with the necessary commands and then discard the buffer w/o any notification. + * + * We have only DMA command buffer physical address at submission time. + * + * so the only way is to */ +typedef struct VBOXVDMACBUF_DR +{ + uint16_t fFlags; + uint16_t cbBuf; + /* RT_SUCCESS() - on success + * VERR_INTERRUPTED - on preemption + * VERR_xxx - on error */ + int32_t rc; + union + { + uint64_t phBuf; + VBOXVIDEOOFFSET offVramBuf; + } Location; + uint64_t aGuestData[7]; +} VBOXVDMACBUF_DR, *PVBOXVDMACBUF_DR; + +#define VBOXVDMACBUF_DR_TAIL(a_pCmd, a_TailType) \ + ( (a_TailType RT_UNTRUSTED_VOLATILE_HSTGST *)( ((uint8_t*)(a_pCmd)) + sizeof(VBOXVDMACBUF_DR)) ) +#define VBOXVDMACBUF_DR_FROM_TAIL(a_pCmd) \ + ( (VBOXVDMACBUF_DR RT_UNTRUSTED_VOLATILE_HSTGST *)( ((uint8_t*)(a_pCmd)) - sizeof(VBOXVDMACBUF_DR)) ) + +typedef struct VBOXVDMACMD +{ + VBOXVDMACMD_TYPE enmType; + uint32_t u32CmdSpecific; +} VBOXVDMACMD; + +#define VBOXVDMACMD_HEADER_SIZE() sizeof(VBOXVDMACMD) +#define VBOXVDMACMD_SIZE_FROMBODYSIZE(_s) ((uint32_t)(VBOXVDMACMD_HEADER_SIZE() + (_s))) +#define VBOXVDMACMD_SIZE(_t) (VBOXVDMACMD_SIZE_FROMBODYSIZE(sizeof(_t))) +#define VBOXVDMACMD_BODY(a_pCmd, a_TypeBody) \ + ( (a_TypeBody RT_UNTRUSTED_VOLATILE_HSTGST *)( ((uint8_t *)(a_pCmd)) + VBOXVDMACMD_HEADER_SIZE()) ) +#define VBOXVDMACMD_BODY_SIZE(_s) ( (_s) - VBOXVDMACMD_HEADER_SIZE() ) +#define VBOXVDMACMD_FROM_BODY(a_pBody) \ + ( (VBOXVDMACMD RT_UNTRUSTED_VOLATILE_HSTGST *)( ((uint8_t *)(a_pBody)) - VBOXVDMACMD_HEADER_SIZE()) ) +#define VBOXVDMACMD_BODY_FIELD_OFFSET(_ot, _t, _f) ( (_ot)(uintptr_t)( VBOXVDMACMD_BODY(0, uint8_t) + RT_UOFFSETOF_DYN(_t, _f) ) ) + +# pragma pack() +#endif /* #ifdef VBOX_WITH_VDMA */ + + +#define VBOXVDMA_CHILD_STATUS_F_CONNECTED 0x01 +#define VBOXVDMA_CHILD_STATUS_F_DISCONNECTED 0x02 +#define VBOXVDMA_CHILD_STATUS_F_ROTATED 0x04 + +typedef struct VBOXVDMA_CHILD_STATUS +{ + uint32_t iChild; + uint8_t fFlags; + uint8_t u8RotationAngle; + uint16_t u16Reserved; +} VBOXVDMA_CHILD_STATUS, *PVBOXVDMA_CHILD_STATUS; + +/* apply the aInfos are applied to all targets, the iTarget is ignored */ +#define VBOXVDMACMD_CHILD_STATUS_IRQ_F_APPLY_TO_ALL 0x00000001 + +typedef struct VBOXVDMACMD_CHILD_STATUS_IRQ +{ + uint32_t cInfos; + uint32_t fFlags; + VBOXVDMA_CHILD_STATUS aInfos[1]; +} VBOXVDMACMD_CHILD_STATUS_IRQ, *PVBOXVDMACMD_CHILD_STATUS_IRQ; + +#define VBOXCMDVBVA_SCREENMAP_SIZE(_elType) ((VBOX_VIDEO_MAX_SCREENS + sizeof (_elType) - 1) / sizeof (_elType)) +#define VBOXCMDVBVA_SCREENMAP_DECL(_elType, _name) _elType _name[VBOXCMDVBVA_SCREENMAP_SIZE(_elType)] + +#endif /* !VBOX_INCLUDED_Graphics_VBoxVideo_h */ + diff --git a/include/VBox/Graphics/VBoxVideo3D.h b/include/VBox/Graphics/VBoxVideo3D.h new file mode 100644 index 00000000..b1545d6f --- /dev/null +++ b/include/VBox/Graphics/VBoxVideo3D.h @@ -0,0 +1,186 @@ +/* $Id: VBoxVideo3D.h $ */ +/** @file + * VirtualBox 3D common tooling + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_Graphics_VBoxVideo3D_h +#define VBOX_INCLUDED_Graphics_VBoxVideo3D_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/asm.h> +#ifndef VBoxTlsRefGetImpl +# ifdef VBoxTlsRefSetImpl +# error "VBoxTlsRefSetImpl is defined, unexpected!" +# endif +# include <iprt/thread.h> +# define VBoxTlsRefGetImpl(_tls) (RTTlsGet((RTTLS)(_tls))) +# define VBoxTlsRefSetImpl(_tls, _val) (RTTlsSet((RTTLS)(_tls), (_val))) +#else +# ifndef VBoxTlsRefSetImpl +# error "VBoxTlsRefSetImpl is NOT defined, unexpected!" +# endif +#endif + +#ifndef VBoxTlsRefAssertImpl +# define VBoxTlsRefAssertImpl(_a) do {} while (0) +#endif + +typedef DECLCALLBACKTYPE(void, FNVBOXTLSREFDTOR,(void *)); +typedef FNVBOXTLSREFDTOR *PFNVBOXTLSREFDTOR; + +typedef enum { + VBOXTLSREFDATA_STATE_UNDEFINED = 0, + VBOXTLSREFDATA_STATE_INITIALIZED, + VBOXTLSREFDATA_STATE_TOBE_DESTROYED, + VBOXTLSREFDATA_STATE_DESTROYING, + VBOXTLSREFDATA_STATE_32BIT_HACK = 0x7fffffff +} VBOXTLSREFDATA_STATE; + +#define VBOXTLSREFDATA \ + volatile int32_t cTlsRefs; \ + VBOXTLSREFDATA_STATE enmTlsRefState; \ + PFNVBOXTLSREFDTOR pfnTlsRefDtor; \ + +struct VBOXTLSREFDATA_DUMMY +{ + VBOXTLSREFDATA +}; + +#define VBOXTLSREFDATA_OFFSET(_t) RT_OFFSETOF(_t, cTlsRefs) +#define VBOXTLSREFDATA_ASSERT_OFFSET(_t) RTASSERT_OFFSET_OF(_t, cTlsRefs) +#define VBOXTLSREFDATA_SIZE() (sizeof (struct VBOXTLSREFDATA_DUMMY)) +#define VBOXTLSREFDATA_COPY(_pDst, _pSrc) do { \ + (_pDst)->cTlsRefs = (_pSrc)->cTlsRefs; \ + (_pDst)->enmTlsRefState = (_pSrc)->enmTlsRefState; \ + (_pDst)->pfnTlsRefDtor = (_pSrc)->pfnTlsRefDtor; \ + } while (0) + +#define VBOXTLSREFDATA_EQUAL(_pDst, _pSrc) ( \ + (_pDst)->cTlsRefs == (_pSrc)->cTlsRefs \ + && (_pDst)->enmTlsRefState == (_pSrc)->enmTlsRefState \ + && (_pDst)->pfnTlsRefDtor == (_pSrc)->pfnTlsRefDtor \ + ) + + +#define VBoxTlsRefInit(_p, _pfnDtor) do { \ + (_p)->cTlsRefs = 1; \ + (_p)->enmTlsRefState = VBOXTLSREFDATA_STATE_INITIALIZED; \ + (_p)->pfnTlsRefDtor = (_pfnDtor); \ + } while (0) + +#define VBoxTlsRefIsFunctional(_p) (!!((_p)->enmTlsRefState == VBOXTLSREFDATA_STATE_INITIALIZED)) + +#define VBoxTlsRefAddRef(_p) do { \ + int cRefs = ASMAtomicIncS32(&(_p)->cTlsRefs); \ + VBoxTlsRefAssertImpl(cRefs > 1 || (_p)->enmTlsRefState == VBOXTLSREFDATA_STATE_DESTROYING); \ + RT_NOREF(cRefs); \ + } while (0) + +#define VBoxTlsRefCountGet(_p) (ASMAtomicReadS32(&(_p)->cTlsRefs)) + +#define VBoxTlsRefRelease(_p) do { \ + int cRefs = ASMAtomicDecS32(&(_p)->cTlsRefs); \ + VBoxTlsRefAssertImpl(cRefs >= 0); \ + if (!cRefs && (_p)->enmTlsRefState != VBOXTLSREFDATA_STATE_DESTROYING /* <- avoid recursion if VBoxTlsRefAddRef/Release is called from dtor */) { \ + (_p)->enmTlsRefState = VBOXTLSREFDATA_STATE_DESTROYING; \ + (_p)->pfnTlsRefDtor((_p)); \ + } \ + } while (0) + +#define VBoxTlsRefMarkDestroy(_p) do { \ + (_p)->enmTlsRefState = VBOXTLSREFDATA_STATE_TOBE_DESTROYED; \ + } while (0) + +#define VBoxTlsRefGetCurrent(_t, _Tsd) ((_t*) VBoxTlsRefGetImpl((_Tsd))) + +#define VBoxTlsRefGetCurrentFunctional(_val, _t, _Tsd) do { \ + _t * cur = VBoxTlsRefGetCurrent(_t, _Tsd); \ + if (!cur || VBoxTlsRefIsFunctional(cur)) { \ + (_val) = cur; \ + } else { \ + VBoxTlsRefSetCurrent(_t, _Tsd, NULL); \ + (_val) = NULL; \ + } \ + } while (0) + +#define VBoxTlsRefSetCurrent(_t, _Tsd, _p) do { \ + _t * oldCur = VBoxTlsRefGetCurrent(_t, _Tsd); \ + if (oldCur != (_p)) { \ + VBoxTlsRefSetImpl((_Tsd), (_p)); \ + if (oldCur) { \ + VBoxTlsRefRelease(oldCur); \ + } \ + if ((_p)) { \ + VBoxTlsRefAddRef((_t*)(_p)); \ + } \ + } \ + } while (0) + + +/* host 3D->Fe[/Qt] notification mechanism defines */ +typedef enum +{ + VBOX3D_NOTIFY_TYPE_TEST_FUNCTIONAL = 3, + VBOX3D_NOTIFY_TYPE_3DDATA_VISIBLE = 4, + VBOX3D_NOTIFY_TYPE_3DDATA_HIDDEN = 5, + + VBOX3D_NOTIFY_TYPE_HW_SCREEN_FIRST = 100, + VBOX3D_NOTIFY_TYPE_HW_SCREEN_IS_SUPPORTED = 100, + VBOX3D_NOTIFY_TYPE_HW_SCREEN_CREATED = 101, + VBOX3D_NOTIFY_TYPE_HW_SCREEN_DESTROYED = 102, + VBOX3D_NOTIFY_TYPE_HW_SCREEN_UPDATE_BEGIN = 103, + VBOX3D_NOTIFY_TYPE_HW_SCREEN_UPDATE_END = 104, + VBOX3D_NOTIFY_TYPE_HW_SCREEN_BIND_SURFACE = 105, + VBOX3D_NOTIFY_TYPE_HW_SCREEN_LAST = 105, + + VBOX3D_NOTIFY_TYPE_HW_OVERLAY_CREATED = 200, + VBOX3D_NOTIFY_TYPE_HW_OVERLAY_DESTROYED = 201, + VBOX3D_NOTIFY_TYPE_HW_OVERLAY_GET_ID = 202, + + VBOX3D_NOTIFY_TYPE_32BIT_HACK = 0x7fffffff +} VBOX3D_NOTIFY_TYPE; + +typedef struct VBOX3DNOTIFY +{ + VBOX3D_NOTIFY_TYPE enmNotification; + int32_t iDisplay; + uint32_t u32Reserved; + uint32_t cbData; + uint8_t au8Data[sizeof(uint64_t)]; +} VBOX3DNOTIFY; + +#endif /* !VBOX_INCLUDED_Graphics_VBoxVideo3D_h */ diff --git a/include/VBox/Graphics/VBoxVideoErr.h b/include/VBox/Graphics/VBoxVideoErr.h new file mode 100644 index 00000000..a934d16a --- /dev/null +++ b/include/VBox/Graphics/VBoxVideoErr.h @@ -0,0 +1,76 @@ +/* $Id: VBoxVideoErr.h $ */ +/** @file + * VirtualBox Video driver, common code - iprt and VirtualBox macros and + * definitions. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_VBoxVideoErr_h +#define VBOX_INCLUDED_Graphics_VBoxVideoErr_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/** @name VirtualBox error macros + * @{ */ + +#define VINF_SUCCESS 0 +#define VERR_INVALID_PARAMETER (-2) +#define VERR_INVALID_POINTER (-6) +#define VERR_NO_MEMORY (-8) +#define VERR_NOT_IMPLEMENTED (-12) +#define VERR_INVALID_FUNCTION (-36) +#define VERR_NOT_SUPPORTED (-37) +#define VERR_TOO_MUCH_DATA (-42) +#define VERR_NOT_FOUND (-78) +#define VERR_INVALID_STATE (-79) +#define VERR_OUT_OF_RESOURCES (-80) +#define VERR_ALREADY_EXISTS (-105) +#define VERR_INTERNAL_ERROR (-225) + +#define RT_SUCCESS_NP(rc) ( (int)(rc) >= VINF_SUCCESS ) +#define RT_SUCCESS(rc) ( likely(RT_SUCCESS_NP(rc)) ) +#define RT_FAILURE(rc) ( unlikely(!RT_SUCCESS_NP(rc)) ) + +/** @} */ + +/** @name VirtualBox assertions + * @{ */ + +/* Unlike BUILD_BUG_ON(), these can be used outside of functions. */ +extern int vbox_assert_var[1]; +#define assert_compile(expr) \ + extern int vbox_assert_var[1] __attribute__((__unused__)), \ + vbox_assert_var[(expr) ? 1 : 0] __attribute__((__unused__)) +#define assert_compile_size(type, size) \ + assert_compile(sizeof(type) == (size)) +#define assert_ptr_return(ptr,ret) \ + do { if (unlikely(!(ptr))) { WARN_ON_ONCE(!(ptr)); return ret; } } while (0) + +/** @} */ + +#endif /* !VBOX_INCLUDED_Graphics_VBoxVideoErr_h */ diff --git a/include/VBox/Graphics/VBoxVideoGuest.h b/include/VBox/Graphics/VBoxVideoGuest.h new file mode 100644 index 00000000..82018737 --- /dev/null +++ b/include/VBox/Graphics/VBoxVideoGuest.h @@ -0,0 +1,185 @@ +/* $Id: VBoxVideoGuest.h $ */ +/** @file + * VBox Host Guest Shared Memory Interface (HGSMI) - OS-independent guest structures. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_VBoxVideoGuest_h +#define VBOX_INCLUDED_Graphics_VBoxVideoGuest_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBoxVideoIPRT.h" +#include "HGSMIBase.h" +#include "VBoxVideo.h" + +RT_C_DECLS_BEGIN + +/** + * Structure grouping the context needed for sending graphics acceleration + * information to the host via VBVA. Each screen has its own VBVA buffer. + */ +typedef struct VBVABUFFERCONTEXT +{ + /** Offset of the buffer in the VRAM section for the screen */ + uint32_t offVRAMBuffer; + /** Length of the buffer in bytes */ + uint32_t cbBuffer; + /** This flag is set if we wrote to the buffer faster than the host could + * read it. */ + bool fHwBufferOverflow; + /** The VBVA record that we are currently preparing for the host, NULL if + * none. */ + struct VBVARECORD *pRecord; + /** Pointer to the VBVA buffer mapped into the current address space. Will + * be NULL if VBVA is not enabled. */ + struct VBVABUFFER *pVBVA; +} VBVABUFFERCONTEXT, *PVBVABUFFERCONTEXT; + +/** @name Base HGSMI APIs + * @{ */ + +DECLHIDDEN(bool) VBoxHGSMIIsSupported(void); +DECLHIDDEN(void) VBoxHGSMIGetBaseMappingInfo(uint32_t cbVRAM, + uint32_t *poffVRAMBaseMapping, + uint32_t *pcbMapping, + uint32_t *poffGuestHeapMemory, + uint32_t *pcbGuestHeapMemory, + uint32_t *poffHostFlags); +DECLHIDDEN(int) VBoxHGSMIReportFlagsLocation(PHGSMIGUESTCOMMANDCONTEXT pCtx, + HGSMIOFFSET offLocation); +DECLHIDDEN(int) VBoxHGSMISendCapsInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx, + uint32_t fCaps); +DECLHIDDEN(void) VBoxHGSMIGetHostAreaMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx, + uint32_t cbVRAM, + uint32_t offVRAMBaseMapping, + uint32_t *poffVRAMHostArea, + uint32_t *pcbHostArea); +DECLHIDDEN(int) VBoxHGSMISendHostCtxInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx, + HGSMIOFFSET offVRAMFlagsLocation, + uint32_t fCaps, + uint32_t offVRAMHostArea, + uint32_t cbHostArea); +DECLHIDDEN(int) VBoxQueryConfHGSMI(PHGSMIGUESTCOMMANDCONTEXT pCtx, + uint32_t u32Index, uint32_t *pulValue); +DECLHIDDEN(int) VBoxQueryConfHGSMIDef(PHGSMIGUESTCOMMANDCONTEXT pCtx, + uint32_t u32Index, uint32_t u32DefValue, uint32_t *pulValue); +DECLHIDDEN(int) VBoxHGSMIUpdatePointerShape(PHGSMIGUESTCOMMANDCONTEXT pCtx, + uint32_t fFlags, + uint32_t cHotX, + uint32_t cHotY, + uint32_t cWidth, + uint32_t cHeight, + uint8_t *pPixels, + uint32_t cbLength); +DECLHIDDEN(int) VBoxHGSMICursorPosition(PHGSMIGUESTCOMMANDCONTEXT pCtx, bool fReportPosition, uint32_t x, uint32_t y, + uint32_t *pxHost, uint32_t *pyHost); + +/** @} */ + +/** @name VBVA APIs + * @{ */ +DECLHIDDEN(bool) VBoxVBVAEnable(PVBVABUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, + struct VBVABUFFER *pVBVA, int32_t cScreen); +DECLHIDDEN(void) VBoxVBVADisable(PVBVABUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, + int32_t cScreen); +DECLHIDDEN(bool) VBoxVBVABufferBeginUpdate(PVBVABUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx); +DECLHIDDEN(void) VBoxVBVABufferEndUpdate(PVBVABUFFERCONTEXT pCtx); +DECLHIDDEN(bool) VBoxVBVAWrite(PVBVABUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, + const void *pv, uint32_t cb); +DECLHIDDEN(bool) VBoxVBVAOrderSupported(PVBVABUFFERCONTEXT pCtx, unsigned code); +DECLHIDDEN(void) VBoxVBVASetupBufferContext(PVBVABUFFERCONTEXT pCtx, + uint32_t offVRAMBuffer, + uint32_t cbBuffer); + +/** @} */ + +/** @name Modesetting APIs + * @{ */ + +DECLHIDDEN(uint32_t) VBoxHGSMIGetMonitorCount(PHGSMIGUESTCOMMANDCONTEXT pCtx); +DECLHIDDEN(bool) VBoxVGACfgAvailable(void); +DECLHIDDEN(bool) VBoxVGACfgQuery(uint16_t u16Id, uint32_t *pu32Value, uint32_t u32DefValue); +DECLHIDDEN(uint32_t) VBoxVideoGetVRAMSize(void); +DECLHIDDEN(bool) VBoxVideoAnyWidthAllowed(void); +DECLHIDDEN(uint16_t) VBoxHGSMIGetScreenFlags(PHGSMIGUESTCOMMANDCONTEXT pCtx); + +struct VBVAINFOVIEW; +/** + * Callback funtion called from @a VBoxHGSMISendViewInfo to initialise + * the @a VBVAINFOVIEW structure for each screen. + * + * @returns iprt status code + * @param pvData context data for the callback, passed to @a + * VBoxHGSMISendViewInfo along with the callback + * @param pInfo array of @a VBVAINFOVIEW structures to be filled in + * @todo explicitly pass the array size + */ +typedef DECLCALLBACKTYPE(int, FNHGSMIFILLVIEWINFO,(void *pvData, struct VBVAINFOVIEW *pInfo, uint32_t cViews)); +/** Pointer to a FNHGSMIFILLVIEWINFO callback */ +typedef FNHGSMIFILLVIEWINFO *PFNHGSMIFILLVIEWINFO; + +DECLHIDDEN(int) VBoxHGSMISendViewInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx, + uint32_t u32Count, + PFNHGSMIFILLVIEWINFO pfnFill, + void *pvData); +DECLHIDDEN(void) VBoxVideoSetModeRegisters(uint16_t cWidth, uint16_t cHeight, + uint16_t cVirtWidth, uint16_t cBPP, + uint16_t fFlags, + uint16_t cx, uint16_t cy); +DECLHIDDEN(bool) VBoxVideoGetModeRegisters(uint16_t *pcWidth, + uint16_t *pcHeight, + uint16_t *pcVirtWidth, + uint16_t *pcBPP, + uint16_t *pfFlags); +DECLHIDDEN(void) VBoxVideoDisableVBE(void); +DECLHIDDEN(void) VBoxHGSMIProcessDisplayInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx, + uint32_t cDisplay, + int32_t cOriginX, + int32_t cOriginY, + uint32_t offStart, + uint32_t cbPitch, + uint32_t cWidth, + uint32_t cHeight, + uint16_t cBPP, + uint16_t fFlags); +DECLHIDDEN(int) VBoxHGSMIUpdateInputMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx, int32_t cOriginX, int32_t cOriginY, + uint32_t cWidth, uint32_t cHeight); +DECLHIDDEN(int) VBoxHGSMIGetModeHints(PHGSMIGUESTCOMMANDCONTEXT pCtx, + unsigned cScreens, VBVAMODEHINT *paHints); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_Graphics_VBoxVideoGuest_h */ + diff --git a/include/VBox/Graphics/VBoxVideoIPRT.h b/include/VBox/Graphics/VBoxVideoIPRT.h new file mode 100644 index 00000000..b1533e72 --- /dev/null +++ b/include/VBox/Graphics/VBoxVideoIPRT.h @@ -0,0 +1,114 @@ +/* $Id: VBoxVideoIPRT.h $ */ +/** @file + * VirtualBox Video driver, common code - iprt and VirtualBox macros and definitions. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_Graphics_VBoxVideoIPRT_h +#define VBOX_INCLUDED_Graphics_VBoxVideoIPRT_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#if !defined(RT_OS_OS2) || !defined(__IBMC__) /* IBM VACpp 3.08 doesn't properly eliminate unused inline functions */ +# include <iprt/asm.h> +# include <iprt/string.h> +#endif +#include <iprt/assert.h> +#include <iprt/cdefs.h> +#include <iprt/err.h> +#include <iprt/list.h> +#include <iprt/stdarg.h> +#include <iprt/stdint.h> +#include <iprt/types.h> + +#if !defined(VBOX_XPDM_MINIPORT) && !defined(RT_OS_OS2) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) +# include <iprt/asm-amd64-x86.h> +#endif + +#ifdef VBOX_XPDM_MINIPORT +# include <iprt/nt/miniport.h> +# include <ntddvdeo.h> /* sdk, clean */ +# include <iprt/nt/Video.h> +#endif + +/** @name Port I/O helpers + * @{ */ + +#ifdef VBOX_XPDM_MINIPORT + +/** Write an 8-bit value to an I/O port. */ +# define VBVO_PORT_WRITE_U8(Port, Value) \ + VideoPortWritePortUchar((PUCHAR)Port, Value) +/** Write a 16-bit value to an I/O port. */ +# define VBVO_PORT_WRITE_U16(Port, Value) \ + VideoPortWritePortUshort((PUSHORT)Port, Value) +/** Write a 32-bit value to an I/O port. */ +# define VBVO_PORT_WRITE_U32(Port, Value) \ + VideoPortWritePortUlong((PULONG)Port, Value) +/** Read an 8-bit value from an I/O port. */ +# define VBVO_PORT_READ_U8(Port) \ + VideoPortReadPortUchar((PUCHAR)Port) +/** Read a 16-bit value from an I/O port. */ +# define VBVO_PORT_READ_U16(Port) \ + VideoPortReadPortUshort((PUSHORT)Port) +/** Read a 32-bit value from an I/O port. */ +# define VBVO_PORT_READ_U32(Port) \ + VideoPortReadPortUlong((PULONG)Port) + +#else /** @todo make these explicit */ + +/** Write an 8-bit value to an I/O port. */ +# define VBVO_PORT_WRITE_U8(Port, Value) \ + ASMOutU8(Port, Value) +/** Write a 16-bit value to an I/O port. */ +# define VBVO_PORT_WRITE_U16(Port, Value) \ + ASMOutU16(Port, Value) +/** Write a 32-bit value to an I/O port. */ +# define VBVO_PORT_WRITE_U32(Port, Value) \ + ASMOutU32(Port, Value) +/** Read an 8-bit value from an I/O port. */ +# define VBVO_PORT_READ_U8(Port) \ + ASMInU8(Port) +/** Read a 16-bit value from an I/O port. */ +# define VBVO_PORT_READ_U16(Port) \ + ASMInU16(Port) +/** Read a 32-bit value from an I/O port. */ +# define VBVO_PORT_READ_U32(Port) \ + ASMInU32(Port) +#endif + +/** @} */ + +#endif /* !VBOX_INCLUDED_Graphics_VBoxVideoIPRT_h */ + diff --git a/include/VBox/Graphics/VBoxVideoVBE.h b/include/VBox/Graphics/VBoxVideoVBE.h new file mode 100644 index 00000000..fb1c6808 --- /dev/null +++ b/include/VBox/Graphics/VBoxVideoVBE.h @@ -0,0 +1,107 @@ +/* $Id: VBoxVideoVBE.h $ */ +/** @file + * VirtualBox graphics card port I/O definitions + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_VBoxVideoVBE_h +#define VBOX_INCLUDED_Graphics_VBoxVideoVBE_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* GUEST <-> HOST Communication API */ + +/** @todo FIXME: Either dynamicly ask host for this or put somewhere high in + * physical memory like 0xE0000000. */ + +#define VBE_DISPI_BANK_ADDRESS 0xA0000 +#define VBE_DISPI_BANK_SIZE_KB 64 + +#define VBE_DISPI_MAX_XRES 16384 +#define VBE_DISPI_MAX_YRES 16384 +#define VBE_DISPI_MAX_BPP 32 + +#define VBE_DISPI_IOPORT_INDEX 0x01CE +#define VBE_DISPI_IOPORT_DATA 0x01CF + +#define VBE_DISPI_IOPORT_DAC_WRITE_INDEX 0x03C8 +#define VBE_DISPI_IOPORT_DAC_DATA 0x03C9 + +/* Cross reference with src/VBox/Devices/Graphics/DevVGA.h */ +#define VBE_DISPI_INDEX_ID 0x0 +#define VBE_DISPI_INDEX_XRES 0x1 +#define VBE_DISPI_INDEX_YRES 0x2 +#define VBE_DISPI_INDEX_BPP 0x3 +#define VBE_DISPI_INDEX_ENABLE 0x4 +#define VBE_DISPI_INDEX_BANK 0x5 +#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 +#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 +#define VBE_DISPI_INDEX_X_OFFSET 0x8 +#define VBE_DISPI_INDEX_Y_OFFSET 0x9 +#define VBE_DISPI_INDEX_VBOX_VIDEO 0xa +#define VBE_DISPI_INDEX_FB_BASE_HI 0xb +#define VBE_DISPI_INDEX_CFG 0xc + +#define VBE_DISPI_ID0 0xB0C0 +#define VBE_DISPI_ID1 0xB0C1 +#define VBE_DISPI_ID2 0xB0C2 +#define VBE_DISPI_ID3 0xB0C3 +#define VBE_DISPI_ID4 0xB0C4 + +#define VBE_DISPI_ID_VBOX_VIDEO 0xBE00 +/* The VBOX interface id. Indicates support for VBVA shared memory interface. */ +#define VBE_DISPI_ID_HGSMI 0xBE01 +#define VBE_DISPI_ID_ANYX 0xBE02 +#define VBE_DISPI_ID_CFG 0xBE03 /* VBE_DISPI_INDEX_CFG is available. */ + +#define VBE_DISPI_DISABLED 0x00 +#define VBE_DISPI_ENABLED 0x01 +#define VBE_DISPI_GETCAPS 0x02 +#define VBE_DISPI_8BIT_DAC 0x20 +/** @note this definition is a BOCHS legacy, used only in the video BIOS + * code and ignored by the emulated hardware. */ +#define VBE_DISPI_LFB_ENABLED 0x40 +#define VBE_DISPI_NOCLEARMEM 0x80 + +/* VBE_DISPI_INDEX_CFG content. */ +#define VBE_DISPI_CFG_MASK_ID 0x0FFF /* Identifier of a configuration value. */ +#define VBE_DISPI_CFG_MASK_SUPPORT 0x1000 /* Query whether the identifier is supported. */ +#define VBE_DISPI_CFG_MASK_RESERVED 0xE000 /* For future extensions. Must be 0. */ + +/* VBE_DISPI_INDEX_CFG values. */ +#define VBE_DISPI_CFG_ID_VERSION 0x0000 /* Version of the configuration interface. */ +#define VBE_DISPI_CFG_ID_VRAM_SIZE 0x0001 /* VRAM size. */ +#define VBE_DISPI_CFG_ID_3D 0x0002 /* 3D support. */ +#define VBE_DISPI_CFG_ID_VMSVGA 0x0003 /* VMSVGA FIFO and ports are available. */ +#define VBE_DISPI_CFG_ID_VMSVGA_DX 0x0004 /* VGPU10 is enabled. */ + +#define VGA_PORT_HGSMI_HOST 0x3b0 +#define VGA_PORT_HGSMI_GUEST 0x3d0 + +#endif /* !VBOX_INCLUDED_Graphics_VBoxVideoVBE_h */ + diff --git a/include/VBox/Graphics/VBoxVideoVBEPrivate.h b/include/VBox/Graphics/VBoxVideoVBEPrivate.h new file mode 100644 index 00000000..40f8bfa4 --- /dev/null +++ b/include/VBox/Graphics/VBoxVideoVBEPrivate.h @@ -0,0 +1,245 @@ +/** @file + * VirtualBox graphics card definitions, private interface for firmware + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_VBoxVideoVBEPrivate_h +#define VBOX_INCLUDED_Graphics_VBoxVideoVBEPrivate_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef VBE +# include <stdint.h> +#else +# include <iprt/types.h> +#endif + +/* VBE Mode Numbers */ +#define VBE_MODE_VESA_DEFINED 0x0100 +#define VBE_MODE_REFRESH_RATE_USE_CRTC 0x0800 +#define VBE_MODE_LINEAR_FRAME_BUFFER 0x4000 +#define VBE_MODE_PRESERVE_DISPLAY_MEMORY 0x8000 + +/* VBE GFX Mode Number */ +#define VBE_VESA_MODE_640X400X8 0x100 +#define VBE_VESA_MODE_640X480X8 0x101 +#define VBE_VESA_MODE_800X600X4 0x102 +#define VBE_VESA_MODE_800X600X8 0x103 +#define VBE_VESA_MODE_1024X768X4 0x104 +#define VBE_VESA_MODE_1024X768X8 0x105 +#define VBE_VESA_MODE_1280X1024X4 0x106 +#define VBE_VESA_MODE_1280X1024X8 0x107 +#define VBE_VESA_MODE_320X200X1555 0x10D +#define VBE_VESA_MODE_320X200X565 0x10E +#define VBE_VESA_MODE_320X200X888 0x10F +#define VBE_VESA_MODE_640X480X1555 0x110 +#define VBE_VESA_MODE_640X480X565 0x111 +#define VBE_VESA_MODE_640X480X888 0x112 +#define VBE_VESA_MODE_800X600X1555 0x113 +#define VBE_VESA_MODE_800X600X565 0x114 +#define VBE_VESA_MODE_800X600X888 0x115 +#define VBE_VESA_MODE_1024X768X1555 0x116 +#define VBE_VESA_MODE_1024X768X565 0x117 +#define VBE_VESA_MODE_1024X768X888 0x118 +#define VBE_VESA_MODE_1280X1024X1555 0x119 +#define VBE_VESA_MODE_1280X1024X565 0x11A +#define VBE_VESA_MODE_1280X1024X888 0x11B +#define VBE_VESA_MODE_1600X1200X8 0x11C +#define VBE_VESA_MODE_1600X1200X1555 0x11D +#define VBE_VESA_MODE_1600X1200X565 0x11E +#define VBE_VESA_MODE_1600X1200X888 0x11F + +/* BOCHS/PLEX86 'own' mode numbers */ +#define VBE_OWN_MODE_320X200X8888 0x140 +#define VBE_OWN_MODE_640X400X8888 0x141 +#define VBE_OWN_MODE_640X480X8888 0x142 +#define VBE_OWN_MODE_800X600X8888 0x143 +#define VBE_OWN_MODE_1024X768X8888 0x144 +#define VBE_OWN_MODE_1280X1024X8888 0x145 +#define VBE_OWN_MODE_320X200X8 0x146 +#define VBE_OWN_MODE_1600X1200X8888 0x147 +#define VBE_OWN_MODE_1152X864X8 0x148 +#define VBE_OWN_MODE_1152X864X1555 0x149 +#define VBE_OWN_MODE_1152X864X565 0x14a +#define VBE_OWN_MODE_1152X864X888 0x14b +#define VBE_OWN_MODE_1152X864X8888 0x14c + +/* VirtualBox 'own' mode numbers */ +#define VBE_VBOX_MODE_CUSTOM1 0x160 +#define VBE_VBOX_MODE_CUSTOM2 0x161 +#define VBE_VBOX_MODE_CUSTOM3 0x162 +#define VBE_VBOX_MODE_CUSTOM4 0x163 +#define VBE_VBOX_MODE_CUSTOM5 0x164 +#define VBE_VBOX_MODE_CUSTOM6 0x165 +#define VBE_VBOX_MODE_CUSTOM7 0x166 +#define VBE_VBOX_MODE_CUSTOM8 0x167 +#define VBE_VBOX_MODE_CUSTOM9 0x168 +#define VBE_VBOX_MODE_CUSTOM10 0x169 +#define VBE_VBOX_MODE_CUSTOM11 0x16a +#define VBE_VBOX_MODE_CUSTOM12 0x16b +#define VBE_VBOX_MODE_CUSTOM13 0x16c +#define VBE_VBOX_MODE_CUSTOM14 0x16d +#define VBE_VBOX_MODE_CUSTOM15 0x16e +#define VBE_VBOX_MODE_CUSTOM16 0x16f + +#define VBE_VESA_MODE_END_OF_LIST 0xFFFF + +/* Capabilities */ +#define VBE_CAPABILITY_8BIT_DAC 0x0001 +#define VBE_CAPABILITY_NOT_VGA_COMPATIBLE 0x0002 +#define VBE_CAPABILITY_RAMDAC_USE_BLANK_BIT 0x0004 +#define VBE_CAPABILITY_STEREOSCOPIC_SUPPORT 0x0008 +#define VBE_CAPABILITY_STEREO_VIA_VESA_EVC 0x0010 + +/* Mode Attributes */ +#define VBE_MODE_ATTRIBUTE_SUPPORTED 0x0001 +#define VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE 0x0002 +#define VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT 0x0004 +#define VBE_MODE_ATTRIBUTE_COLOR_MODE 0x0008 +#define VBE_MODE_ATTRIBUTE_GRAPHICS_MODE 0x0010 +#define VBE_MODE_ATTRIBUTE_NOT_VGA_COMPATIBLE 0x0020 +#define VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW 0x0040 +#define VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE 0x0080 +#define VBE_MODE_ATTRIBUTE_DOUBLE_SCAN_MODE 0x0100 +#define VBE_MODE_ATTRIBUTE_INTERLACE_MODE 0x0200 +#define VBE_MODE_ATTRIBUTE_HARDWARE_TRIPLE_BUFFER 0x0400 +#define VBE_MODE_ATTRIBUTE_HARDWARE_STEREOSCOPIC_DISPLAY 0x0800 +#define VBE_MODE_ATTRIBUTE_DUAL_DISPLAY_START_ADDRESS 0x1000 + +#define VBE_MODE_ATTTRIBUTE_LFB_ONLY ( VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE ) + +/* Window attributes */ +#define VBE_WINDOW_ATTRIBUTE_RELOCATABLE 0x01 +#define VBE_WINDOW_ATTRIBUTE_READABLE 0x02 +#define VBE_WINDOW_ATTRIBUTE_WRITEABLE 0x04 + +/* Memory model */ +#define VBE_MEMORYMODEL_TEXT_MODE 0x00 +#define VBE_MEMORYMODEL_CGA_GRAPHICS 0x01 +#define VBE_MEMORYMODEL_HERCULES_GRAPHICS 0x02 +#define VBE_MEMORYMODEL_PLANAR 0x03 +#define VBE_MEMORYMODEL_PACKED_PIXEL 0x04 +#define VBE_MEMORYMODEL_NON_CHAIN_4_256 0x05 +#define VBE_MEMORYMODEL_DIRECT_COLOR 0x06 +#define VBE_MEMORYMODEL_YUV 0x07 + +/* DirectColorModeInfo */ +#define VBE_DIRECTCOLOR_COLOR_RAMP_PROGRAMMABLE 0x01 +#define VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE 0x02 + +/* Video memory */ +#define VGAMEM_GRAPH 0xA000 + +/** + * VBE Bios Extra Data structure. + */ +typedef struct VBEHeader +{ + /** Signature (VBEHEADER_MAGIC). */ + uint16_t u16Signature; + /** Data size. */ + uint16_t cbData; +} VBEHeader; + +/** The value of the VBEHeader::u16Signature field. */ +#define VBEHEADER_MAGIC 0x77CC + +/** The extra port which is used to read the mode list. */ +#define VBE_EXTRA_PORT 0x3b6 + +/** The extra port which is used for debug printf. */ +#define VBE_PRINTF_PORT 0x3b7 + +/** + * This one is for compactly storing a list of mode info blocks + */ +#pragma pack(1) /* pack(1) is important! (you'll get a byte extra for each of the u8 fields elsewise...) + * bird: Load of non-sense. You'll get two extra bytes before MaxPixelClock if you don't pack it. */ +typedef struct ModeInfoBlockCompact +{ + /* Mandatory information for all VBE revisions */ + uint16_t ModeAttributes; + uint8_t WinAAttributes; + uint8_t WinBAttributes; + uint16_t WinGranularity; + uint16_t WinSize; + uint16_t WinASegment; + uint16_t WinBSegment; + uint32_t WinFuncPtr; + uint16_t BytesPerScanLine; + /* Mandatory information for VBE 1.2 and above */ + uint16_t XResolution; + uint16_t YResolution; + uint8_t XCharSize; + uint8_t YCharSize; + uint8_t NumberOfPlanes; + uint8_t BitsPerPixel; + uint8_t NumberOfBanks; + uint8_t MemoryModel; + uint8_t BankSize; + uint8_t NumberOfImagePages; + uint8_t Reserved_page; + /* Direct Color fields (required for direct/6 and YUV/7 memory models) */ + uint8_t RedMaskSize; + uint8_t RedFieldPosition; + uint8_t GreenMaskSize; + uint8_t GreenFieldPosition; + uint8_t BlueMaskSize; + uint8_t BlueFieldPosition; + uint8_t RsvdMaskSize; + uint8_t RsvdFieldPosition; + uint8_t DirectColorModeInfo; + /* Mandatory information for VBE 2.0 and above */ + uint32_t PhysBasePtr; + uint32_t OffScreenMemOffset; + uint16_t OffScreenMemSize; + /* Mandatory information for VBE 3.0 and above */ + uint16_t LinBytesPerScanLine; + uint8_t BnkNumberOfPages; + uint8_t LinNumberOfPages; + uint8_t LinRedMaskSize; + uint8_t LinRedFieldPosition; + uint8_t LinGreenMaskSize; + uint8_t LinGreenFieldPosition; + uint8_t LinBlueMaskSize; + uint8_t LinBlueFieldPosition; + uint8_t LinRsvdMaskSize; + uint8_t LinRsvdFieldPosition; + uint32_t MaxPixelClock; +} ModeInfoBlockCompact; +#pragma pack() + +typedef struct ModeInfoListItem +{ + uint16_t mode; + ModeInfoBlockCompact info; +} ModeInfoListItem; + + +#endif /* !VBOX_INCLUDED_Graphics_VBoxVideoVBEPrivate_h */ + diff --git a/include/VBox/GuestHost/DragAndDrop.h b/include/VBox/GuestHost/DragAndDrop.h new file mode 100644 index 00000000..a9722c59 --- /dev/null +++ b/include/VBox/GuestHost/DragAndDrop.h @@ -0,0 +1,350 @@ +/* $Id: DragAndDrop.h $ */ +/** @file + * DnD - Shared functions between host and guest. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_DragAndDrop_h +#define VBOX_INCLUDED_GuestHost_DragAndDrop_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assert.h> +#include <iprt/fs.h> +#include <iprt/list.h> + +#include <VBox/GuestHost/DragAndDropDefs.h> + +/** DnDURIDroppedFiles flags. */ +typedef uint32_t DNDURIDROPPEDFILEFLAGS; + +/** No flags specified. */ +#define DNDURIDROPPEDFILE_FLAGS_NONE 0 + +/** + * Structure for keeping a DnD dropped files entry. + */ +typedef struct DNDDROPPEDFILESENTRY +{ + RTLISTNODE Node; + char *pszPath; +} DNDDROPPEDFILESENTRY; +/** Pointer to a DnD dropped files entry. */ +typedef DNDDROPPEDFILESENTRY *PDNDDROPPEDFILESENTRY; + +/** + * Structure for maintaining a "dropped files" directory + * on the host or guest. This will contain all received files & directories + * for a single drag and drop operation. + * + * In case of a failed drag and drop operation this can also + * perform a gentle rollback if required. + */ +typedef struct DNDDROPPEDFILES +{ + /** Open flags. */ + uint32_t m_fOpen; + /** Directory handle for drop directory. */ + RTDIR m_hDir; + /** Absolute path to drop directory. */ + char *pszPathAbs; + /** List for holding created directories in the case of a rollback. */ + RTLISTANCHOR m_lstDirs; + /** List for holding created files in the case of a rollback. */ + RTLISTANCHOR m_lstFiles; +} DNDDROPPEDFILES; +/** Pointer to a DnD dropped files directory. */ +typedef DNDDROPPEDFILES *PDNDDROPPEDFILES; + +int DnDDroppedFilesInit(PDNDDROPPEDFILES pDF); +int DnDDroppedFilesInitEx(PDNDDROPPEDFILES pDF, const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags); +void DnDDroppedFilesDestroy(PDNDDROPPEDFILES pDF); +int DnDDroppedFilesAddFile(PDNDDROPPEDFILES pDF, const char *pszFile); +int DnDDroppedFilesAddDir(PDNDDROPPEDFILES pDF, const char *pszDir); +int DnDDroppedFilesClose(PDNDDROPPEDFILES pDF); +bool DnDDroppedFilesIsOpen(PDNDDROPPEDFILES pDF); +int DnDDroppedFilesOpenEx(PDNDDROPPEDFILES pDF, const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags); +int DnDDroppedFilesOpenTemp(PDNDDROPPEDFILES pDF, DNDURIDROPPEDFILEFLAGS fFlags); +const char *DnDDroppedFilesGetDirAbs(PDNDDROPPEDFILES pDF); +int DnDDroppedFilesReopen(PDNDDROPPEDFILES pDF); +int DnDDroppedFilesReset(PDNDDROPPEDFILES pDF, bool fDelete); +int DnDDroppedFilesRollback(PDNDDROPPEDFILES pDF); + +const char *DnDHostMsgToStr(uint32_t uMsg); +const char *DnDGuestMsgToStr(uint32_t uMsg); +const char *DnDActionToStr(VBOXDNDACTION uAction); + char *DnDActionListToStrA(VBOXDNDACTIONLIST fActionList); +const char *DnDStateToStr(VBOXDNDSTATE enmState); + +bool DnDMIMEHasFileURLs(const char *pcszFormat, size_t cchFormatMax); +bool DnDMIMENeedsDropDir(const char *pcszFormat, size_t cchFormatMax); + +int DnDPathValidate(const char *pcszPath, bool fMustExist); + +/** DnD path conversion flags. */ +typedef uint32_t DNDPATHCONVERTFLAGS; + +/** No flags specified. + * This will convert the path to the universal tansport style. */ +#define DNDPATHCONVERT_FLAGS_TRANSPORT 0 +/** Converts the path to a OS-dependent path. */ +#define DNDPATHCONVERT_FLAGS_TO_DOS RT_BIT(0) + +/** Mask of all valid DnD path conversion flags. */ +#define DNDPATHCONVERT_FLAGS_VALID_MASK UINT32_C(0x1) + +int DnDPathConvert(char *pszPath, size_t cbPath, DNDPATHCONVERTFLAGS fFlags); +int DnDPathSanitizeFileName(char *pszPath, size_t cbPath); +int DnDPathRebase(const char *pcszPathAbs, const char *pcszBaseOld, const char *pcszBaseNew, char **ppszPath); + +/** DnDTransferObject flags. */ +typedef uint32_t DNDTRANSFEROBJECTFLAGS; + +/** No flags specified. */ +#define DNDTRANSFEROBJECT_FLAGS_NONE 0 + +/** Mask of all valid DnD transfer object flags. */ +#define DNDTRANSFEROBJECT_FLAGS_VALID_MASK UINT32_C(0x0) + +/** + * Enumeration for specifying a transfer object type. + */ +typedef enum DNDTRANSFEROBJTYPE +{ + /** Unknown type, do not use. */ + DNDTRANSFEROBJTYPE_UNKNOWN = 0, + /** Object is a file. */ + DNDTRANSFEROBJTYPE_FILE, + /** Object is a directory. */ + DNDTRANSFEROBJTYPE_DIRECTORY, + /** The usual 32-bit hack. */ + DNDTRANSFEROBJTYPE_32BIT_HACK = 0x7fffffff +} DNDTRANSFEROBJTYPE; + +/** + * Enumeration for specifying a path style. + */ +typedef enum DNDTRANSFEROBJPATHSTYLE +{ + /** Transport style (UNIX-y), the default. */ + DNDTRANSFEROBJPATHSTYLE_TRANSPORT = 0, + /** DOS style, containing back slashes. */ + DNDTRANSFEROBJPATHSTYLE_DOS, + /** The usual 32-bit hack. */ + DNDTRANSFEROBJPATHSTYLE_32BIT_HACK = 0x7fffffff +} DNDTRANSFEROBJPATHSTYLE; + +/** + * Structure for keeping a DnD transfer object. + */ +typedef struct DNDTRANSFEROBJECT +{ + RTLISTNODE Node; + /** The object's type. */ + DNDTRANSFEROBJTYPE enmType; + /** Index (in characters, UTF-8) at which the first destination segment starts. */ + uint16_t idxDst; + /** Allocated path. Includdes the absolute source path (if any) + destination segments. + * Transport (IPRT) style. */ + char *pszPath; + + /** Union containing data depending on the object's type. */ + union + { + /** Structure containing members for objects that + * are files. */ + struct + { + /** File handle. */ + RTFILE hFile; + /** File system object information of this file. */ + RTFSOBJINFO objInfo; + /** Bytes to proces for reading/writing. */ + uint64_t cbToProcess; + /** Bytes processed reading/writing. */ + uint64_t cbProcessed; + } File; + struct + { + /** Directory handle. */ + RTDIR hDir; + /** File system object information of this directory. */ + RTFSOBJINFO objInfo; + } Dir; + } u; +} DNDTRANSFEROBJECT; +/** Pointer to a DnD transfer object. */ +typedef DNDTRANSFEROBJECT *PDNDTRANSFEROBJECT; + +int DnDTransferObjectInit(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectInitEx(PDNDTRANSFEROBJECT pObj, DNDTRANSFEROBJTYPE enmType, const char *pcszPathSrcAbs, const char *pcszPathDst); +void DnDTransferObjectDestroy(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectClose(PDNDTRANSFEROBJECT pObj); +void DnDTransferObjectReset(PDNDTRANSFEROBJECT pObj); +const char *DnDTransferObjectGetSourcePath(PDNDTRANSFEROBJECT pObj); +const char *DnDTransferObjectGetDestPath(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectGetDestPathEx(PDNDTRANSFEROBJECT pObj, DNDTRANSFEROBJPATHSTYLE enmStyle, char *pszBuf, size_t cbBuf); +RTFMODE DnDTransferObjectGetMode(PDNDTRANSFEROBJECT pObj); +uint64_t DnDTransferObjectGetProcessed(PDNDTRANSFEROBJECT pObj); +uint64_t DnDTransferObjectGetSize(PDNDTRANSFEROBJECT pObj); +DNDTRANSFEROBJTYPE DnDTransferObjectGetType(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectSetSize(PDNDTRANSFEROBJECT pObj, uint64_t cbSize); +bool DnDTransferObjectIsComplete(PDNDTRANSFEROBJECT pObj); +bool DnDTransferObjectIsOpen(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectOpen(PDNDTRANSFEROBJECT pObj, uint64_t fOpen, RTFMODE fMode, DNDTRANSFEROBJECTFLAGS fFlags); +int DnDTransferObjectQueryInfo(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectRead(PDNDTRANSFEROBJECT pObj, void *pvBuf, size_t cbBuf, uint32_t *pcbRead); +int DnDTransferObjectWrite(PDNDTRANSFEROBJECT pObj, const void *pvBuf, size_t cbBuf, uint32_t *pcbWritten); + +/** Defines the default chunk size of DnD data transfers. + * Supported on all (older) Guest Additions which also support DnD. */ +#define DND_DEFAULT_CHUNK_SIZE _64K + +/** Separator for a formats list. */ +#define DND_FORMATS_SEPARATOR_STR "\r\n" + +/** Default URI list path separator, if not specified otherwise. + * + * This is there for hysterical raisins, to not break older Guest Additions. + ** @todo Get rid of this. */ +#define DND_PATH_SEPARATOR_STR "\r\n" + +/** DnDTransferList flags. */ +typedef uint32_t DNDTRANSFERLISTFLAGS; + +/** No flags specified. */ +#define DNDTRANSFERLIST_FLAGS_NONE 0 +/** Enables recurisve directory handling. */ +#define DNDTRANSFERLIST_FLAGS_RECURSIVE RT_BIT(0) +/** Resolve all symlinks. Currently not supported and will be ignored. */ +#define DNDTRANSFERLIST_FLAGS_RESOLVE_SYMLINKS RT_BIT(1) +/** Keep the files + directory entries open while + * being in this list. */ +#define DNDTRANSFERLIST_FLAGS_KEEP_OPEN RT_BIT(2) +/** Lazy loading: Only enumerate sub directories when needed. Not implemented yet. + ** @todo Implement lazy loading. */ +#define DNDTRANSFERLIST_FLAGS_LAZY RT_BIT(3) + +/** Mask of all valid DnD transfer list flags. */ +#define DNDTRANSFERLIST_FLAGS_VALID_MASK UINT32_C(0xF) + +/** + * Enumeration for specifying a transfer list format. + */ +typedef enum DNDTRANSFERLISTFMT +{ + /** Unknown format, do not use. */ + DNDTRANSFERLISTFMT_UNKNOWN = 0, + /** Native format. */ + DNDTRANSFERLISTFMT_NATIVE, + /** URI format. */ + DNDTRANSFERLISTFMT_URI, + /** The usual 32-bit hack. */ + DNDTRANSFERLISTFMT_32BIT_HACK = 0x7fffffff +} DNDTRANSFERLISTFMT; + +/** + * Structure for keeping a DnD transfer list root entry. + * + * A root entry always is relative to the parent list maintaining it. + */ +typedef struct DNDTRANSFERLISTROOT +{ + /** List node. */ + RTLISTNODE Node; + /** Pointer to the allocated root path. + * - Relative to the list's root path + * - Always ends with a trailing slash + * - Always stored in transport style (UNIX-y). */ + char *pszPathRoot; +} DNDTRANSFERLISTROOT; +/** Pointer to a DnD list root entry. */ +typedef DNDTRANSFERLISTROOT *PDNDTRANSFERLISTROOT; + +/** + * Struct for keeping a DnD transfer list. + * + * All entries must share a common (absolute) root path. For different root paths another transfer list is needed. + */ +typedef struct DNDTRANSFERLIST +{ + /** Absolute root path of this transfer list, in native path style. + * Always ends with a separator. */ + char *pszPathRootAbs; + /** List of all relative (to \a pszPathRootAbs) top-level file/directory entries, of type DNDTRANSFERLISTROOT. + * Note: All paths are stored internally in transport style (UNIX paths) for + * easier conversion/handling! */ + RTLISTANCHOR lstRoot; + /** Total number of all transfer root entries. */ + uint64_t cRoots; + /** List of all transfer objects added, of type DNDTRANSFEROBJECT. + * + * The order of objects being added is crucial for traversing the tree. + * In other words, sub directories must come first before its contents. */ + RTLISTANCHOR lstObj; + /** Total number of all transfer objects. */ + uint64_t cObj; + /** Total size of all transfer objects, that is, the file + * size of all objects (in bytes). + * Note: Do *not* size_t here, as we also want to support large files + * on 32-bit guests. */ + uint64_t cbObjTotal; +} DNDTRANSFERLIST; +/** Pointer to a DNDTRANSFERLIST struct. */ +typedef DNDTRANSFERLIST *PDNDTRANSFERLIST; + +int DnDTransferListInit(PDNDTRANSFERLIST pList); +int DnDTransferListInitEx(PDNDTRANSFERLIST pList, const char *pcszRootPathAbs, DNDTRANSFERLISTFMT enmFmt); +void DnDTransferListDestroy(PDNDTRANSFERLIST pList); +void DnDTransferListReset(PDNDTRANSFERLIST pList); + +int DnDTransferListAppendPath(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char *pszPath, DNDTRANSFERLISTFLAGS fFlags); +int DnDTransferListAppendPathsFromBuffer(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char *pszPaths, size_t cbPaths, const char *pcszSeparator, DNDTRANSFERLISTFLAGS fFlags); +int DnDTransferListAppendPathsFromArray(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char * const *papcszPaths, size_t cPaths, DNDTRANSFERLISTFLAGS fFlags); +int DnDTransferListAppendRootsFromBuffer(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char *pszPaths, size_t cbPaths, const char *pcszSeparator, DNDTRANSFERLISTFLAGS fFlags); +int DnDTransferListAppendRootsFromArray(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char * const *papcszPaths, size_t cPaths, DNDTRANSFERLISTFLAGS fFlags); + +int DnDTransferListGetRootsEx(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char *pcszPathBase, const char *pcszSeparator, char **ppszBuffer, size_t *pcbBuffer); +int DnDTransferListGetRoots(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, char **ppszBuffer, size_t *pcbBuffer); +uint64_t DnDTransferListGetRootCount(PDNDTRANSFERLIST pList); +const char *DnDTransferListGetRootPathAbs(PDNDTRANSFERLIST pList); + +PDNDTRANSFEROBJECT DnDTransferListObjGetFirst(PDNDTRANSFERLIST pList); +void DnDTransferListObjRemove(PDNDTRANSFERLIST pList, PDNDTRANSFEROBJECT pObj); +void DnDTransferListObjRemoveFirst(PDNDTRANSFERLIST pList); +uint64_t DnDTransferListObjCount(PDNDTRANSFERLIST pList); +uint64_t DnDTransferListObjTotalBytes(PDNDTRANSFERLIST pList); + +#endif /* !VBOX_INCLUDED_GuestHost_DragAndDrop_h */ + diff --git a/include/VBox/GuestHost/DragAndDropDefs.h b/include/VBox/GuestHost/DragAndDropDefs.h new file mode 100644 index 00000000..0968fa8a --- /dev/null +++ b/include/VBox/GuestHost/DragAndDropDefs.h @@ -0,0 +1,112 @@ +/** @file + * Drag and Drop definitions - Common header for host service and guest clients. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_DragAndDropDefs_h +#define VBOX_INCLUDED_GuestHost_DragAndDropDefs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/* + * The mode of operations. + */ +#define VBOX_DRAG_AND_DROP_MODE_OFF 0 +#define VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST 1 +#define VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST 2 +#define VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL 3 + +#define VBOX_DND_ACTION_IGNORE UINT32_C(0) +#define VBOX_DND_ACTION_COPY RT_BIT_32(0) +#define VBOX_DND_ACTION_MOVE RT_BIT_32(1) +#define VBOX_DND_ACTION_LINK RT_BIT_32(2) + +/** A single DnD action. */ +typedef uint32_t VBOXDNDACTION; +/** A list of (OR'ed) DnD actions. */ +typedef uint32_t VBOXDNDACTIONLIST; + +#define hasDnDCopyAction(a) ((a) & VBOX_DND_ACTION_COPY) +#define hasDnDMoveAction(a) ((a) & VBOX_DND_ACTION_MOVE) +#define hasDnDLinkAction(a) ((a) & VBOX_DND_ACTION_LINK) + +#define isDnDIgnoreAction(a) ((a) == VBOX_DND_ACTION_IGNORE) +#define isDnDCopyAction(a) ((a) == VBOX_DND_ACTION_COPY) +#define isDnDMoveAction(a) ((a) == VBOX_DND_ACTION_MOVE) +#define isDnDLinkAction(a) ((a) == VBOX_DND_ACTION_LINK) + +/** @def VBOX_DND_FORMATS_DEFAULT + * Default drag'n drop formats. + * Note: If you add new entries here, make sure you test those + * with all supported guest OSes! + */ +#define VBOX_DND_FORMATS_DEFAULT \ + "text/uri-list", \ + /* Text. */ \ + "text/html", \ + "text/plain;charset=utf-8", \ + "text/plain;charset=utf-16", \ + "text/plain", \ + "text/richtext", \ + "UTF8_STRING", \ + "TEXT", \ + "STRING", \ + /* OpenOffice formats. */ \ + /* See: https://wiki.openoffice.org/wiki/Documentation/DevGuide/OfficeDev/Common_Application_Features#OpenOffice.org_Clipboard_Data_Formats */ \ + "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"", \ + "application/x-openoffice;windows_formatname=\"Bitmap\"" + +/** + * Enumeration for keeping a DnD state. + */ +typedef enum +{ + VBOXDNDSTATE_UNKNOWN = 0, + VBOXDNDSTATE_ENTERED, + VBOXDNDSTATE_LEFT, + VBOXDNDSTATE_QUERY_FORMATS, + VBOXDNDSTATE_QUERY_STATUS, + VBOXDNDSTATE_DRAGGING, + VBOXDNDSTATE_DROP_STARTED, + VBOXDNDSTATE_DROP_ENDED, + VBOXDNDSTATE_CANCELLED, + VBOXDNDSTATE_ERROR +} VBOXDNDSTATE; +/** Pointer to a DnD state. */ +typedef VBOXDNDSTATE *PVBOXDNDSTATE; + +#endif /* !VBOX_INCLUDED_GuestHost_DragAndDropDefs_h */ + diff --git a/include/VBox/GuestHost/GuestControl.h b/include/VBox/GuestHost/GuestControl.h new file mode 100644 index 00000000..3ecbc0a3 --- /dev/null +++ b/include/VBox/GuestHost/GuestControl.h @@ -0,0 +1,236 @@ +/* $Id: GuestControl.h $ */ +/** @file + * Guest Control - Common Guest and Host Code. + * + * @todo r=bird: Just merge this with GuestControlSvc.h! + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_GuestControl_h +#define VBOX_INCLUDED_GuestHost_GuestControl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/* Everything defined in this file lives in this namespace. */ +namespace guestControl { + +/** + * Process status when executed in the guest. + */ +enum eProcessStatus +{ + /** Process is in an undefined state. */ + PROC_STS_UNDEFINED = 0, + /** Process has been started. */ + PROC_STS_STARTED = 1, + /** Process terminated normally. */ + PROC_STS_TEN = 2, + /** Process terminated via signal. */ + PROC_STS_TES = 3, + /** Process terminated abnormally. */ + PROC_STS_TEA = 4, + /** Process timed out and was killed. */ + PROC_STS_TOK = 5, + /** Process timed out and was not killed successfully. */ + PROC_STS_TOA = 6, + /** Service/OS is stopping, process was killed. */ + PROC_STS_DWN = 7, + /** Something went wrong (error code in flags). */ + PROC_STS_ERROR = 8 +}; + +/** + * Input flags, set by the host. This is needed for + * handling flags on the guest side. + * Note: Has to match Main's ProcessInputFlag_* flags! + */ +#define GUEST_PROC_IN_FLAG_NONE 0x0 +#define GUEST_PROC_IN_FLAG_EOF RT_BIT(0) + +/** + * Guest session creation flags. + * Only handled internally at the moment. + */ +#define SESSIONCREATIONFLAG_NONE 0x0 + +/** @name DIRREMOVEREC_FLAG_XXX - Guest directory removement flags. + * Essentially using what IPRT's RTDIRRMREC_F_ + * defines have to offer. + * @{ + */ +/** No remove flags specified. */ +#define DIRREMOVEREC_FLAG_NONE UINT32_C(0x0) +/** Recursively deletes the directory contents. */ +#define DIRREMOVEREC_FLAG_RECURSIVE RT_BIT(0) +/** Delete the content of the directory and the directory itself. */ +#define DIRREMOVEREC_FLAG_CONTENT_AND_DIR RT_BIT(1) +/** Only delete the content of the directory, omit the directory it self. */ +#define DIRREMOVEREC_FLAG_CONTENT_ONLY RT_BIT(2) +/** Mask of valid flags. */ +#define DIRREMOVEREC_FLAG_VALID_MASK UINT32_C(0x00000007) +/** @} */ + +/** @name GUEST_PROC_CREATE_FLAG_XXX - Guest process creation flags. + * @note Has to match Main's ProcessCreateFlag_* flags! + * @{ + */ +#define GUEST_PROC_CREATE_FLAG_NONE UINT32_C(0x0) +#define GUEST_PROC_CREATE_FLAG_WAIT_START RT_BIT(0) +#define GUEST_PROC_CREATE_FLAG_IGNORE_ORPHANED RT_BIT(1) +#define GUEST_PROC_CREATE_FLAG_HIDDEN RT_BIT(2) +#define GUEST_PROC_CREATE_FLAG_PROFILE RT_BIT(3) +#define GUEST_PROC_CREATE_FLAG_WAIT_STDOUT RT_BIT(4) +#define GUEST_PROC_CREATE_FLAG_WAIT_STDERR RT_BIT(5) +#define GUEST_PROC_CREATE_FLAG_EXPAND_ARGUMENTS RT_BIT(6) +#define GUEST_PROC_CREATE_FLAG_UNQUOTED_ARGS RT_BIT(7) +/** @} */ + +/** @name GUEST_PROC_OUT_H_XXX - Pipe handle IDs used internally for referencing + * to a certain pipe buffer. + * @{ + */ +#define GUEST_PROC_OUT_H_STDOUT_DEPRECATED 0 /**< Needed for VBox hosts < 4.1.0. */ +#define GUEST_PROC_OUT_H_STDOUT 1 +#define GUEST_PROC_OUT_H_STDERR 2 +/** @} */ + +/** @name PATHRENAME_FLAG_XXX - Guest path rename flags. + * Essentially using what IPRT's RTPATHRENAME_FLAGS_XXX have to offer. + * @{ + */ +/** Do not replace anything. */ +#define PATHRENAME_FLAG_NO_REPLACE UINT32_C(0) +/** This will replace attempt any target which isn't a directory. */ +#define PATHRENAME_FLAG_REPLACE RT_BIT(0) +/** Don't allow symbolic links as part of the path. */ +#define PATHRENAME_FLAG_NO_SYMLINKS RT_BIT(1) +/** Mask of valid flags. */ +#define PATHRENAME_FLAG_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** @name GUEST_SHUTDOWN_FLAG_XXX - Guest shutdown flags. + * Must match Main's GuestShutdownFlag_ definitions. + * @{ + */ +#define GUEST_SHUTDOWN_FLAG_NONE UINT32_C(0) +#define GUEST_SHUTDOWN_FLAG_POWER_OFF RT_BIT(0) +#define GUEST_SHUTDOWN_FLAG_REBOOT RT_BIT(1) +#define GUEST_SHUTDOWN_FLAG_FORCE RT_BIT(2) +/** @} */ + +/** @name Defines for default (initial) guest process buffer lengths. + * Note: These defaults were the maximum values before; so be careful when raising those in order to + * not break running with older Guest Additions. + * @{ + */ +#define GUEST_PROC_DEF_CMD_LEN _1K +#define GUEST_PROC_DEF_ARGS_LEN _1K +#define GUEST_PROC_DEF_ENV_LEN _1K +#define GUEST_PROC_DEF_USER_LEN 128 +#define GUEST_PROC_DEF_PASSWORD_LEN 128 +#define GUEST_PROC_DEF_DOMAIN_LEN 256 +/** @} */ + +/** @name Defines for maximum guest process buffer lengths. + * @{ + */ +#define GUEST_PROC_MAX_CMD_LEN _1M +#define GUEST_PROC_MAX_ARGS_LEN _2M +#define GUEST_PROC_MAX_ENV_LEN _4M +#define GUEST_PROC_MAX_USER_LEN _64K +#define GUEST_PROC_MAX_PASSWORD_LEN _64K +#define GUEST_PROC_MAX_DOMAIN_LEN _64K +/** @} */ + +/** @name Internal tools built into VBoxService which are used in order + * to accomplish tasks host<->guest. + * @{ + */ +#define VBOXSERVICE_TOOL_CAT "vbox_cat" +#define VBOXSERVICE_TOOL_LS "vbox_ls" +#define VBOXSERVICE_TOOL_RM "vbox_rm" +#define VBOXSERVICE_TOOL_MKDIR "vbox_mkdir" +#define VBOXSERVICE_TOOL_MKTEMP "vbox_mktemp" +#define VBOXSERVICE_TOOL_STAT "vbox_stat" +/** @} */ + +/** Special process exit codes for "vbox_cat". */ +typedef enum VBOXSERVICETOOLBOX_CAT_EXITCODE +{ + VBOXSERVICETOOLBOX_CAT_EXITCODE_ACCESS_DENIED = RTEXITCODE_END, + VBOXSERVICETOOLBOX_CAT_EXITCODE_FILE_NOT_FOUND, + VBOXSERVICETOOLBOX_CAT_EXITCODE_PATH_NOT_FOUND, + VBOXSERVICETOOLBOX_CAT_EXITCODE_SHARING_VIOLATION, + VBOXSERVICETOOLBOX_CAT_EXITCODE_IS_A_DIRECTORY, + /** The usual 32-bit type hack. */ + VBOXSERVICETOOLBOX_CAT_32BIT_HACK = 0x7fffffff +} VBOXSERVICETOOLBOX_CAT_EXITCODE; + +/** Special process exit codes for "vbox_stat". */ +typedef enum VBOXSERVICETOOLBOX_STAT_EXITCODE +{ + VBOXSERVICETOOLBOX_STAT_EXITCODE_ACCESS_DENIED = RTEXITCODE_END, + VBOXSERVICETOOLBOX_STAT_EXITCODE_FILE_NOT_FOUND, + VBOXSERVICETOOLBOX_STAT_EXITCODE_PATH_NOT_FOUND, + VBOXSERVICETOOLBOX_STAT_EXITCODE_NET_PATH_NOT_FOUND, + VBOXSERVICETOOLBOX_STAT_EXITCODE_INVALID_NAME, + /** The usual 32-bit type hack. */ + VBOXSERVICETOOLBOX_STAT_32BIT_HACK = 0x7fffffff +} VBOXSERVICETOOLBOX_STAT_EXITCODE; + +/** + * Input status, reported by the client. + */ +enum eInputStatus +{ + /** Input is in an undefined state. */ + INPUT_STS_UNDEFINED = 0, + /** Input was written (partially, see cbProcessed). */ + INPUT_STS_WRITTEN = 1, + /** Input failed with an error (see flags for rc). */ + INPUT_STS_ERROR = 20, + /** Process has abandoned / terminated input handling. */ + INPUT_STS_TERMINATED = 21, + /** Too much input data. */ + INPUT_STS_OVERFLOW = 30 +}; + + + +} /* namespace guestControl */ + +#endif /* !VBOX_INCLUDED_GuestHost_GuestControl_h */ + diff --git a/include/VBox/GuestHost/HGCMMock.h b/include/VBox/GuestHost/HGCMMock.h new file mode 100644 index 00000000..3aabed57 --- /dev/null +++ b/include/VBox/GuestHost/HGCMMock.h @@ -0,0 +1,804 @@ +/* $Id: HGCMMock.h $ */ +/** @file + * HGCMMock.h: Mocking framework for testing HGCM-based host services + + * Vbgl code on the host side. + * + * Goal is to run host service + Vbgl code as unmodified as + * possible as part of testcases to gain test coverage which + * otherwise wouldn't possible for heavily user-centric features + * like Shared Clipboard or drag'n drop (DnD). + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_HGCMMock_h +#define VBOX_INCLUDED_GuestHost_HGCMMock_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +#include <iprt/asm.h> +#include <iprt/assert.h> +#include <iprt/list.h> +#include <iprt/mem.h> +#include <iprt/rand.h> +#include <iprt/semaphore.h> +#include <iprt/test.h> +#include <iprt/time.h> +#include <iprt/thread.h> +#include <iprt/utf16.h> + +#include <VBox/err.h> +#include <VBox/VBoxGuestLib.h> +#include <VBox/hgcmsvc.h> + + +/********************************************************************************************************************************* +* Definitions. * +*********************************************************************************************************************************/ + +#if defined(IN_RING3) /* Only R3 parts implemented so far. */ + +RT_C_DECLS_BEGIN + +DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *ptable); + +RT_C_DECLS_END + +# define VBGLR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL + +/** Simple call handle structure for the guest call completion callback. */ +typedef struct VBOXHGCMCALLHANDLE_TYPEDEF +{ + /** Where to store the result code on call completion. */ + int32_t rc; +} VBOXHGCMCALLHANDLE_TYPEDEF; + +/** + * Enumeration for a HGCM mock function type. + */ +typedef enum TSTHGCMMOCKFNTYPE +{ + TSTHGCMMOCKFNTYPE_NONE = 0, + TSTHGCMMOCKFNTYPE_CONNECT, + TSTHGCMMOCKFNTYPE_DISCONNECT, + TSTHGCMMOCKFNTYPE_CALL, + TSTHGCMMOCKFNTYPE_HOST_CALL +} TSTHGCMMOCKFNTYPE; + +/** Pointer to a mock HGCM service. */ +typedef struct TSTHGCMMOCKSVC *PTSTHGCMMOCKSVC; + +/** + * Structure for mocking a server-side HGCM client. + */ +typedef struct TSTHGCMMOCKCLIENT +{ + /** Pointer to to mock service instance this client belongs to. */ + PTSTHGCMMOCKSVC pSvc; + /** Assigned HGCM client ID. */ + uint32_t idClient; + /** Opaque pointer to service-specific client data. + * Can be NULL if not being used. */ + void *pvClient; + /** Size (in bytes) of \a pvClient. */ + size_t cbClient; + /** The client's current HGCM call handle. */ + VBOXHGCMCALLHANDLE_TYPEDEF hCall; + /** Whether the current client call has an asynchronous + * call pending or not. */ + bool fAsyncExec; + /** Event semaphore to signal call completion. */ + RTSEMEVENT hEvent; +} TSTHGCMMOCKCLIENT; +/** Pointer to a mock HGCM client. */ +typedef TSTHGCMMOCKCLIENT *PTSTHGCMMOCKCLIENT; + +/** + * Structure for keeping HGCM mock function parameters. + */ +typedef struct TSTHGCMMOCKFN +{ + /** List node for storing this struct into a queue. */ + RTLISTNODE Node; + /** Function type. */ + TSTHGCMMOCKFNTYPE enmType; + /** Pointer to associated client. */ + PTSTHGCMMOCKCLIENT pClient; + /** Union keeping function-specific parameters, + * depending on \a enmType. */ + union + { + struct + { + int32_t iFunc; + uint32_t cParms; + PVBOXHGCMSVCPARM pParms; + VBOXHGCMCALLHANDLE hCall; + } Call; + struct + { + int32_t iFunc; + uint32_t cParms; + PVBOXHGCMSVCPARM pParms; + } HostCall; + } u; +} TSTHGCMMOCKFN; +/** Pointer to a HGCM mock function parameters structure. */ +typedef TSTHGCMMOCKFN *PTSTHGCMMOCKFN; + +/** + * Structure for keeping a HGCM mock service instance. + */ +typedef struct TSTHGCMMOCKSVC +{ + /** HGCM helper table to use. */ + VBOXHGCMSVCHELPERS fnHelpers; + /** HGCM service function table to use. */ + VBOXHGCMSVCFNTABLE fnTable; + /** Next HGCM client ID to assign. + * 0 is considered as being invalid. */ + HGCMCLIENTID uNextClientId; + /** Size (in bytes) of opaque pvClient area to reserve + * for a connected client. */ + size_t cbClient; + /** Array of connected HGCM mock clients. + * Currently limited to 4 clients maximum. */ + TSTHGCMMOCKCLIENT aHgcmClient[4]; + /** Thread handle for the service's main loop. */ + RTTHREAD hThread; + /** Event semaphore for signalling a message + * queue change. */ + RTSEMEVENT hEventQueue; + /** Event semaphore for clients connecting to the server. */ + RTSEMEVENT hEventConnect; + /** Number of current host calls being served. + * Currently limited to one call at a time. */ + uint8_t cHostCallers; + /** Result code of last returned host call. */ + int rcHostCall; + /** Event semaphore for host calls. */ + RTSEMEVENT hEventHostCall; + /** List (queue) of function calls to process. */ + RTLISTANCHOR lstCall; + /** Shutdown indicator flag. */ + volatile bool fShutdown; +} TSTHGCMMOCKSVC; + +/** Static HGCM service to mock. */ +static TSTHGCMMOCKSVC s_tstHgcmSvc; + +/********************************************************************************************************************************* +* Prototypes. * +*********************************************************************************************************************************/ +PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void); +PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout); +PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc); +int TstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc, size_t cbClient); +int TstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc); +int TstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc); +int TstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc); + +int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); + +VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient); +VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient); +VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo); + + + +/********************************************************************************************************************************* +* Internal functions * +*********************************************************************************************************************************/ + +/** + * Initializes a HGCM mock client. + * + * @return VBox status code. + * @param pClient Client instance to initialize. + * @param idClient HGCM client ID to assign. + * @param cbClient Size (in bytes) of service-specific (opaque) client data to allocate. + */ +static int tstHgcmMockClientInit(PTSTHGCMMOCKCLIENT pClient, uint32_t idClient, size_t cbClient) +{ + RT_BZERO(pClient, sizeof(TSTHGCMMOCKCLIENT)); + + pClient->idClient = idClient; + if (cbClient) + { + pClient->pvClient = RTMemAllocZ(cbClient); + AssertPtrReturn(pClient->pvClient, VERR_NO_MEMORY); + pClient->cbClient = cbClient; + } + + return RTSemEventCreate(&pClient->hEvent); +} + +/** + * Destroys a HGCM mock client. + * + * @return VBox status code. + * @param pClient Client instance to destroy. + */ +static int tstHgcmMockClientDestroy(PTSTHGCMMOCKCLIENT pClient) +{ + int rc = RTSemEventDestroy(pClient->hEvent); + if (RT_SUCCESS(rc)) + { + if (pClient->pvClient) + { + Assert(pClient->cbClient); + RTMemFree(pClient->pvClient); + pClient->pvClient = NULL; + pClient->cbClient = 0; + } + + pClient->hEvent = NIL_RTSEMEVENT; + } + + return rc; +} + +/* @copydoc VBOXHGCMSVCFNTABLE::pfnConnect */ +static DECLCALLBACK(int) tstHgcmMockSvcConnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t *pidClient) +{ + RT_NOREF(pvService); + + PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN)); + AssertPtrReturn(pFn, VERR_NO_MEMORY); + + PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[pSvc->uNextClientId]; + + int rc = tstHgcmMockClientInit(pClient, pSvc->uNextClientId, pSvc->cbClient); + if (RT_FAILURE(rc)) + return rc; + + pFn->enmType = TSTHGCMMOCKFNTYPE_CONNECT; + pFn->pClient = pClient; + + RTListAppend(&pSvc->lstCall, &pFn->Node); + pFn = NULL; /* Thread takes ownership now. */ + + int rc2 = RTSemEventSignal(pSvc->hEventQueue); + AssertRCReturn(rc2, rc2); + rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC); + AssertRCReturn(rc2, rc2); + + ASMAtomicIncU32(&pSvc->uNextClientId); + + rc2 = RTSemEventSignal(pSvc->hEventConnect); + AssertRCReturn(rc2, rc2); + + *pidClient = pClient->idClient; + + return VINF_SUCCESS; +} + +/* @copydoc VBOXHGCMSVCFNTABLE::pfnDisconnect */ +static DECLCALLBACK(int) tstHgcmMockSvcDisconnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t idClient) +{ + RT_NOREF(pvService); + + PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient]; + + PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN)); + AssertPtrReturn(pFn, VERR_NO_MEMORY); + + pFn->enmType = TSTHGCMMOCKFNTYPE_DISCONNECT; + pFn->pClient = pClient; + + RTListAppend(&pSvc->lstCall, &pFn->Node); + pFn = NULL; /* Thread takes ownership now. */ + + int rc2 = RTSemEventSignal(pSvc->hEventQueue); + AssertRCReturn(rc2, rc2); + + rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC); + AssertRCReturn(rc2, rc2); + + return tstHgcmMockClientDestroy(pClient); +} + +/* @copydoc VBOXHGCMSVCFNTABLE::pfnCall */ +static DECLCALLBACK(int) tstHgcmMockSvcCall(PTSTHGCMMOCKSVC pSvc, void *pvService, VBOXHGCMCALLHANDLE callHandle, uint32_t idClient, void *pvClient, + int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) +{ + RT_NOREF(pvService, pvClient); + + PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient]; + + PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN)); + AssertPtrReturn(pFn, VERR_NO_MEMORY); + + const size_t cbParms = cParms * sizeof(VBOXHGCMSVCPARM); + + pFn->enmType = TSTHGCMMOCKFNTYPE_CALL; + pFn->pClient = pClient; + + pFn->u.Call.hCall = callHandle; + pFn->u.Call.iFunc = function; + pFn->u.Call.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cbParms); + AssertPtrReturn(pFn->u.Call.pParms, VERR_NO_MEMORY); + pFn->u.Call.cParms = cParms; + + RTListAppend(&pSvc->lstCall, &pFn->Node); + + int rc2 = RTSemEventSignal(pSvc->hEventQueue); + AssertRCReturn(rc2, rc2); + + rc2 = RTSemEventWait(pClient->hEvent, RT_INDEFINITE_WAIT); + AssertRCReturn(rc2, rc2); + + memcpy(paParms, pFn->u.Call.pParms, cbParms); + + return VINF_SUCCESS; /** @todo Return host call rc */ +} + +/* @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall */ +/** Note: Public for also being able to test host calls via testcases. */ +int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) +{ + RT_NOREF(pvService); + AssertReturn(pSvc->cHostCallers == 0, VERR_WRONG_ORDER); /* Only one host call at a time. */ + + pSvc->cHostCallers++; + + PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN)); + AssertPtrReturn(pFn, VERR_INVALID_POINTER); + + pFn->enmType = TSTHGCMMOCKFNTYPE_HOST_CALL; + pFn->u.HostCall.iFunc = function; + if (cParms) + { + pFn->u.HostCall.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cParms * sizeof(VBOXHGCMSVCPARM)); + AssertPtrReturn(pFn->u.HostCall.pParms, VERR_NO_MEMORY); + pFn->u.HostCall.cParms = cParms; + } + + RTListAppend(&pSvc->lstCall, &pFn->Node); + pFn = NULL; /* Thread takes ownership now. */ + + int rc2 = RTSemEventSignal(pSvc->hEventQueue); + AssertRC(rc2); + + rc2 = RTSemEventWait(pSvc->hEventHostCall, RT_INDEFINITE_WAIT); + AssertRCReturn(rc2, rc2); + + Assert(pSvc->cHostCallers); + pSvc->cHostCallers--; + + return pSvc->rcHostCall; +} + +/** + * Call completion callback for guest calls. + * + * @return VBox status code. + * @param callHandle Call handle to complete. + * @param rc Return code to return to the caller. + */ +static DECLCALLBACK(int) tstHgcmMockSvcCallComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc) +{ + PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst(); + + size_t i = 0; + for (; RT_ELEMENTS(pSvc->aHgcmClient); i++) + { + PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[i]; + if (&pClient->hCall == callHandle) /* Slow, but works for now. */ + { + if (rc == VINF_HGCM_ASYNC_EXECUTE) + { + Assert(pClient->fAsyncExec == false); + } + else /* Complete call + notify client. */ + { + callHandle->rc = rc; + + int rc2 = RTSemEventSignal(pClient->hEvent); + AssertRCReturn(rc2, rc2); + } + + return VINF_SUCCESS; + } + } + + return VERR_NOT_FOUND; +} + +/** + * Main thread of HGCM mock service. + * + * @return VBox status code. + * @param hThread Thread handle. + * @param pvUser User-supplied data of type PTSTHGCMMOCKSVC. + */ +static DECLCALLBACK(int) tstHgcmMockSvcThread(RTTHREAD hThread, void *pvUser) +{ + RT_NOREF(hThread); + PTSTHGCMMOCKSVC pSvc = (PTSTHGCMMOCKSVC)pvUser; + + pSvc->uNextClientId = 0; + + pSvc->fnTable.cbSize = sizeof(pSvc->fnTable); + pSvc->fnTable.u32Version = VBOX_HGCM_SVC_VERSION; + + RT_ZERO(pSvc->fnHelpers); + pSvc->fnHelpers.pfnCallComplete = tstHgcmMockSvcCallComplete; + pSvc->fnTable.pHelpers = &pSvc->fnHelpers; + + int rc = VBoxHGCMSvcLoad(&pSvc->fnTable); + if (RT_SUCCESS(rc)) + { + RTThreadUserSignal(hThread); + + for (;;) + { + rc = RTSemEventWait(pSvc->hEventQueue, 10 /* ms */); + if (ASMAtomicReadBool(&pSvc->fShutdown)) + { + rc = VINF_SUCCESS; + break; + } + if (rc == VERR_TIMEOUT) + continue; + + PTSTHGCMMOCKFN pFn = RTListGetFirst(&pSvc->lstCall, TSTHGCMMOCKFN, Node); + if (pFn) + { + switch (pFn->enmType) + { + case TSTHGCMMOCKFNTYPE_CONNECT: + { + rc = pSvc->fnTable.pfnConnect(pSvc->fnTable.pvService, + pFn->pClient->idClient, pFn->pClient->pvClient, + VMMDEV_REQUESTOR_USR_NOT_GIVEN /* fRequestor */, false /* fRestoring */); + + int rc2 = RTSemEventSignal(pFn->pClient->hEvent); + AssertRC(rc2); + break; + } + + case TSTHGCMMOCKFNTYPE_DISCONNECT: + { + rc = pSvc->fnTable.pfnDisconnect(pSvc->fnTable.pvService, + pFn->pClient->idClient, pFn->pClient->pvClient); + + int rc2 = RTSemEventSignal(pFn->pClient->hEvent); + AssertRC(rc2); + break; + } + + case TSTHGCMMOCKFNTYPE_CALL: + { + pSvc->fnTable.pfnCall(NULL, pFn->u.Call.hCall, pFn->pClient->idClient, pFn->pClient->pvClient, + pFn->u.Call.iFunc, pFn->u.Call.cParms, pFn->u.Call.pParms, RTTimeMilliTS()); + + /* Note: Call will be completed in the call completion callback. */ + break; + } + + case TSTHGCMMOCKFNTYPE_HOST_CALL: + { + pSvc->rcHostCall = pSvc->fnTable.pfnHostCall(NULL, pFn->u.HostCall.iFunc, pFn->u.HostCall.cParms, pFn->u.HostCall.pParms); + + int rc2 = RTSemEventSignal(pSvc->hEventHostCall); + AssertRC(rc2); + break; + } + + default: + AssertFailed(); + break; + } + RTListNodeRemove(&pFn->Node); + RTMemFree(pFn); + } + } + } + + return rc; +} + + +/********************************************************************************************************************************* +* Public functions * +*********************************************************************************************************************************/ + +/** + * Returns the pointer to the HGCM mock service instance. + * + * @return Pointer to HGCM mock service instance. + */ +PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void) +{ + return &s_tstHgcmSvc; +} + +/** + * Waits for a HGCM mock client to connect, extended version. + * + * @return Pointer to connected client, or NULL if ran into timeout. + * @param pSvc HGCM mock service instance. + * @param msTimeout Timeout (in ms) to wait for connection. + */ +PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout) +{ + int rc = RTSemEventWait(pSvc->hEventConnect, msTimeout); + if (RT_SUCCESS(rc)) + { + Assert(pSvc->uNextClientId); + return &pSvc->aHgcmClient[pSvc->uNextClientId - 1]; + } + return NULL; +} + +/** + * Waits for a HGCM mock client to connect. + * + * @return Pointer to connected client, or NULL if waiting for connection was aborted. + * @param pSvc HGCM mock service instance. + */ +PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc) +{ + return TstHgcmMockSvcWaitForConnectEx(pSvc, RT_MS_30SEC); +} + +/** + * Creates a HGCM mock service instance. + * + * @return VBox status code. + * @param pSvc HGCM mock service instance to create. + * @param cbClient Size (in bytes) of service-specific client data to + * allocate for a HGCM mock client. + */ +int TstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc, size_t cbClient) +{ + AssertReturn(cbClient, VERR_INVALID_PARAMETER); + + RT_ZERO(pSvc->aHgcmClient); + pSvc->fShutdown = false; + int rc = RTSemEventCreate(&pSvc->hEventQueue); + if (RT_SUCCESS(rc)) + { + rc = RTSemEventCreate(&pSvc->hEventHostCall); + if (RT_SUCCESS(rc)) + { + rc = RTSemEventCreate(&pSvc->hEventConnect); + if (RT_SUCCESS(rc)) + { + RTListInit(&pSvc->lstCall); + + pSvc->cbClient = cbClient; + } + } + } + + return rc; +} + +/** + * Destroys a HGCM mock service instance. + * + * @return VBox status code. + * @param pSvc HGCM mock service instance to destroy. + */ +int TstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc) +{ + int rc = RTSemEventDestroy(pSvc->hEventQueue); + if (RT_SUCCESS(rc)) + { + rc = RTSemEventDestroy(pSvc->hEventHostCall); + if (RT_SUCCESS(rc)) + RTSemEventDestroy(pSvc->hEventConnect); + } + return rc; +} + +/** + * Starts a HGCM mock service instance. + * + * @return VBox status code. + * @param pSvc HGCM mock service instance to start. + */ +int TstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc) +{ + int rc = RTThreadCreate(&pSvc->hThread, tstHgcmMockSvcThread, pSvc, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, + "MockSvc"); + if (RT_SUCCESS(rc)) + rc = RTThreadUserWait(pSvc->hThread, RT_MS_30SEC); + + return rc; +} + +/** + * Stops a HGCM mock service instance. + * + * @return VBox status code. + * @param pSvc HGCM mock service instance to stop. + */ +int TstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc) +{ + ASMAtomicWriteBool(&pSvc->fShutdown, true); + + int rcThread; + int rc = RTThreadWait(pSvc->hThread, RT_MS_30SEC, &rcThread); + if (RT_SUCCESS(rc)) + rc = rcThread; + if (RT_SUCCESS(rc)) + { + pSvc->hThread = NIL_RTTHREAD; + } + + return rc; +} + + +/********************************************************************************************************************************* +* VbglR3 stubs * +*********************************************************************************************************************************/ + +/** + * Connects to an HGCM mock service. + * + * @returns VBox status code + * @param pszServiceName Name of the host service. + * @param pidClient Where to put the client ID on success. The client ID + * must be passed to all the other calls to the service. + */ +VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient) +{ + RT_NOREF(pszServiceName); + + PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst(); + + return tstHgcmMockSvcConnect(pSvc, pSvc->fnTable.pvService, pidClient); +} + +/** + * Disconnect from an HGCM mock service. + * + * @returns VBox status code. + * @param idClient The client id returned by VbglR3HGCMConnect(). + */ +VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient) +{ + PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst(); + + return tstHgcmMockSvcDisconnect(pSvc, pSvc->fnTable.pvService, idClient); +} + +/** + * Makes a fully prepared HGCM call to an HGCM mock service. + * + * @returns VBox status code. + * @param pInfo Fully prepared HGCM call info. + * @param cbInfo Size of the info. This may sometimes be larger than + * what the parameter count indicates because of + * parameter changes between versions and such. + */ +VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo) +{ + RT_NOREF(cbInfo); + + AssertMsg(pInfo->Hdr.cbIn == cbInfo, ("cbIn=%#x cbInfo=%#zx\n", pInfo->Hdr.cbIn, cbInfo)); + AssertMsg(pInfo->Hdr.cbOut == cbInfo, ("cbOut=%#x cbInfo=%#zx\n", pInfo->Hdr.cbOut, cbInfo)); + Assert(sizeof(*pInfo) + pInfo->cParms * sizeof(HGCMFunctionParameter) <= cbInfo); + + HGCMFunctionParameter *offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo); + PVBOXHGCMSVCPARM paDstParms = (PVBOXHGCMSVCPARM)RTMemAlloc(pInfo->cParms * sizeof(VBOXHGCMSVCPARM)); + + uint16_t i = 0; + for (; i < pInfo->cParms; i++) + { + switch (offSrcParms->type) + { + case VMMDevHGCMParmType_32bit: + { + paDstParms[i].type = VBOX_HGCM_SVC_PARM_32BIT; + paDstParms[i].u.uint32 = offSrcParms->u.value32; + break; + } + + case VMMDevHGCMParmType_64bit: + { + paDstParms[i].type = VBOX_HGCM_SVC_PARM_64BIT; + paDstParms[i].u.uint64 = offSrcParms->u.value64; + break; + } + + case VMMDevHGCMParmType_LinAddr: + { + paDstParms[i].type = VBOX_HGCM_SVC_PARM_PTR; + paDstParms[i].u.pointer.addr = (void *)offSrcParms->u.LinAddr.uAddr; + paDstParms[i].u.pointer.size = offSrcParms->u.LinAddr.cb; + break; + } + + default: + AssertFailed(); + break; + } + + offSrcParms++; + } + + PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst(); + + int rc2 = tstHgcmMockSvcCall(pSvc, pSvc->fnTable.pvService, &pSvc->aHgcmClient[pInfo->u32ClientID].hCall, + pInfo->u32ClientID, pSvc->aHgcmClient[pInfo->u32ClientID].pvClient, + pInfo->u32Function, pInfo->cParms, paDstParms); + if (RT_SUCCESS(rc2)) + { + offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo); + + for (i = 0; i < pInfo->cParms; i++) + { + paDstParms[i].type = offSrcParms->type; + switch (paDstParms[i].type) + { + case VMMDevHGCMParmType_32bit: + offSrcParms->u.value32 = paDstParms[i].u.uint32; + break; + + case VMMDevHGCMParmType_64bit: + offSrcParms->u.value64 = paDstParms[i].u.uint64; + break; + + case VMMDevHGCMParmType_LinAddr: + { + offSrcParms->u.LinAddr.cb = paDstParms[i].u.pointer.size; + break; + } + + default: + AssertFailed(); + break; + } + + offSrcParms++; + } + } + + RTMemFree(paDstParms); + + if (RT_SUCCESS(rc2)) + rc2 = pSvc->aHgcmClient[pInfo->u32ClientID].hCall.rc; + + return rc2; +} + +#endif /* IN_RING3 */ + +#endif /* !VBOX_INCLUDED_GuestHost_HGCMMock_h */ diff --git a/include/VBox/GuestHost/HGCMMockUtils.h b/include/VBox/GuestHost/HGCMMockUtils.h new file mode 100644 index 00000000..8eb9f943 --- /dev/null +++ b/include/VBox/GuestHost/HGCMMockUtils.h @@ -0,0 +1,428 @@ +/* $Id */ +/** @file + * HGCMMockUtils.h: Utility functions for the HGCM Mocking framework. + * + * The utility functions are optional to the actual HGCM Mocking framework and + * can support testcases which require a more advanced setup. + * + * With this one can setup host and guest side threads, which in turn can simulate + * specific host (i.e. HGCM service) + guest (i.e. like in the Guest Addditions + * via VbglR3) scenarios. + * + * Glossary: + * + * Host thread: + * - The host thread is used as part of the actual HGCM service being tested and + * provides callbacks (@see TSTHGCMUTILSHOSTCALLBACKS) for the unit test. + * Guest thread: + * - The guest thread is used as part of the guest side and mimics + * VBoxClient / VBoxTray / VBoxService parts. (i.e. for VbglR3 calls). + * Task: + * - A task is the simplest unit of test execution and used between the guest + * and host mocking threads. + * + ** @todo Add TstHGCMSimpleHost / TstHGCMSimpleGuest wrappers along those lines: + * Callback.pfnOnClientConnected = tstOnHostClientConnected() + * TstHGCMSimpleHostInitAndStart(&Callback) + * Callback.pfnOnConnected = tstOnGuestConnected() + * TstHGCMSimpleClientInitAndStart(&Callback) + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_HGCMMockUtils_h +#define VBOX_INCLUDED_GuestHost_HGCMMockUtils_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/err.h> +#include <iprt/semaphore.h> +#include <iprt/thread.h> +#include <iprt/types.h> + + +#include <VBox/GuestHost/HGCMMock.h> +#include <VBox/VBoxGuestLib.h> + + +#if defined(IN_RING3) /* Only R3 parts implemented so far. */ + +/** Pointer to a HGCM Mock utils context. */ +typedef struct TSTHGCMUTILSCTX *PTSTHGCMUTILSCTX; + +/** + * Structure for keeping a HGCM Mock utils host service callback table. + */ +typedef struct TSTHGCMUTILSHOSTCALLBACKS +{ + DECLCALLBACKMEMBER(int, pfnOnClientConnected,(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKCLIENT pClient, void *pvUser)); +} TSTHGCMUTILSHOSTCALLBACKS; +/** Pointer to a HGCM Mock utils host callbacks table. */ +typedef TSTHGCMUTILSHOSTCALLBACKS *PTSTHGCMUTILSHOSTCALLBACKS; + +/** + * Structure for keeping a generic HGCM Mock utils task. + * + * A task is a single test unit / entity. + */ +typedef struct TSTHGCMUTILSTASK +{ + /** Completion event. */ + RTSEMEVENT hEvent; + /** Completion rc. + * Set to VERR_IPE_UNINITIALIZED_STATUS if not completed yet. */ + int rcCompleted; + /** Expected completion rc. */ + int rcExpected; + /** Pointer to opaque (testcase-specific) task parameters. + * Might be NULL if not needed / used. */ + void *pvUser; +} TSTHGCMUTILSTASK; +/** Pointer to a HGCM Mock utils task. */ +typedef TSTHGCMUTILSTASK *PTSTHGCMUTILSTASK; + +/** Callback function for HGCM Mock utils threads. */ +typedef DECLCALLBACKTYPE(int, FNTSTHGCMUTILSTHREAD,(PTSTHGCMUTILSCTX pCtx, void *pvUser)); +/** Pointer to a HGCM Mock utils guest thread callback. */ +typedef FNTSTHGCMUTILSTHREAD *PFNTSTHGCMUTILSTHREAD; + +/** + * Structure for keeping a HGCM Mock utils context. + */ +typedef struct TSTHGCMUTILSCTX +{ + /** Pointer to the HGCM Mock service instance to use. */ + PTSTHGCMMOCKSVC pSvc; + /** Currently we only support one task at a time. */ + TSTHGCMUTILSTASK Task; + struct + { + RTTHREAD hThread; + volatile bool fShutdown; + PFNTSTHGCMUTILSTHREAD pfnThread; + void *pvUser; + } Guest; + struct + { + RTTHREAD hThread; + volatile bool fShutdown; + TSTHGCMUTILSHOSTCALLBACKS Callbacks; + void *pvUser; + } Host; +} TSTHGCMUTILSCTX; + + +/********************************************************************************************************************************* +* Prototypes. * +*********************************************************************************************************************************/ +/** @name Context handling. + * @{ */ +void TstHGCMUtilsCtxInit(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKSVC pSvc); +/** @} */ + +/** @name Task handling. + * @{ */ +PTSTHGCMUTILSTASK TstHGCMUtilsTaskGetCurrent(PTSTHGCMUTILSCTX pCtx); +int TstHGCMUtilsTaskInit(PTSTHGCMUTILSTASK pTask); +void TstHGCMUtilsTaskDestroy(PTSTHGCMUTILSTASK pTask); +int TstHGCMUtilsTaskWait(PTSTHGCMUTILSTASK pTask, RTMSINTERVAL msTimeout); +bool TstHGCMUtilsTaskOk(PTSTHGCMUTILSTASK pTask); +bool TstHGCMUtilsTaskCompleted(PTSTHGCMUTILSTASK pTask); +void TstHGCMUtilsTaskSignal(PTSTHGCMUTILSTASK pTask, int rc); +/** @} */ + +/** @name Threading. + * @{ */ +int TstHGCMUtilsGuestThreadStart(PTSTHGCMUTILSCTX pCtx, PFNTSTHGCMUTILSTHREAD pFnThread, void *pvUser); +int TstHGCMUtilsGuestThreadStop(PTSTHGCMUTILSCTX pCtx); +int TstHGCMUtilsHostThreadStart(PTSTHGCMUTILSCTX pCtx, PTSTHGCMUTILSHOSTCALLBACKS pCallbacks, void *pvUser); +int TstHGCMUtilsHostThreadStop(PTSTHGCMUTILSCTX pCtx); +/** @} */ + + +/********************************************************************************************************************************* + * Context * + ********************************************************************************************************************************/ +/** + * Initializes a HGCM Mock utils context. + * + * @param pCtx Context to intiialize. + * @param pSvc HGCM Mock service instance to use. + */ +void TstHGCMUtilsCtxInit(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKSVC pSvc) +{ + RT_BZERO(pCtx, sizeof(TSTHGCMUTILSCTX)); + + pCtx->pSvc = pSvc; +} + + +/********************************************************************************************************************************* + * Tasks * + ********************************************************************************************************************************/ +/** + * Returns the current task of a HGCM Mock utils context. + * + * @returns Current task of a HGCM Mock utils context. NULL if no current task found. + * @param pCtx HGCM Mock utils context. + */ +PTSTHGCMUTILSTASK TstHGCMUtilsTaskGetCurrent(PTSTHGCMUTILSCTX pCtx) +{ + /* Currently we only support one task at a time. */ + return &pCtx->Task; +} + +/** + * Initializes a HGCM Mock utils task. + * + * @returns VBox status code. + * @param pTask Task to initialize. + */ +int TstHGCMUtilsTaskInit(PTSTHGCMUTILSTASK pTask) +{ + pTask->pvUser = NULL; + pTask->rcCompleted = pTask->rcExpected = VERR_IPE_UNINITIALIZED_STATUS; + return RTSemEventCreate(&pTask->hEvent); +} + +/** + * Destroys a HGCM Mock utils task. + * + * @returns VBox status code. + * @param pTask Task to destroy. + */ +void TstHGCMUtilsTaskDestroy(PTSTHGCMUTILSTASK pTask) +{ + RTSemEventDestroy(pTask->hEvent); +} + +/** + * Waits for a HGCM Mock utils task to complete. + * + * @returns VBox status code. + * @param pTask Task to wait for. + * @param msTimeout Timeout (in ms) to wait. + */ +int TstHGCMUtilsTaskWait(PTSTHGCMUTILSTASK pTask, RTMSINTERVAL msTimeout) +{ + return RTSemEventWait(pTask->hEvent, msTimeout); +} + +/** + * Returns if the HGCM Mock utils task has been completed successfully. + * + * @returns \c true if successful, \c false if not. + * @param pTask Task to check. + */ +bool TstHGCMUtilsTaskOk(PTSTHGCMUTILSTASK pTask) +{ + return pTask->rcCompleted == pTask->rcExpected; +} + +/** + * Returns if the HGCM Mock utils task has been completed (failed or succeeded). + * + * @returns \c true if completed, \c false if (still) running. + * @param pTask Task to check. + */ +bool TstHGCMUtilsTaskCompleted(PTSTHGCMUTILSTASK pTask) +{ + return pTask->rcCompleted != VERR_IPE_UNINITIALIZED_STATUS; +} + +/** + * Signals a HGCM Mock utils task to complete its operation. + * + * @param pTask Task to complete. + * @param rc Task result to set for completion. + */ +void TstHGCMUtilsTaskSignal(PTSTHGCMUTILSTASK pTask, int rc) +{ + AssertMsg(pTask->rcCompleted == VERR_IPE_UNINITIALIZED_STATUS, ("Task already completed\n")); + pTask->rcCompleted = rc; + int rc2 = RTSemEventSignal(pTask->hEvent); + AssertRC(rc2); +} + + +/********************************************************************************************************************************* + * Threading * + ********************************************************************************************************************************/ + +/** + * Thread worker for the guest side thread. + * + * @returns VBox status code. + * @param hThread Thread handle. + * @param pvUser Pointer of type PTSTHGCMUTILSCTX. + * + * @note Runs in the guest thread. + */ +static DECLCALLBACK(int) tstHGCMUtilsGuestThread(RTTHREAD hThread, void *pvUser) +{ + RT_NOREF(hThread); + PTSTHGCMUTILSCTX pCtx = (PTSTHGCMUTILSCTX)pvUser; + AssertPtr(pCtx); + + RTThreadUserSignal(hThread); + + if (pCtx->Guest.pfnThread) + return pCtx->Guest.pfnThread(pCtx, pCtx->Guest.pvUser); + + return VINF_SUCCESS; +} + +/** + * Starts the guest side thread. + * + * @returns VBox status code. + * @param pCtx HGCM Mock utils context to start guest thread for. + * @param pFnThread Pointer to custom thread worker function to call within the guest side thread. + * @param pvUser User-supplied pointer to guest thread context data. Optional and can be NULL. + */ +int TstHGCMUtilsGuestThreadStart(PTSTHGCMUTILSCTX pCtx, PFNTSTHGCMUTILSTHREAD pFnThread, void *pvUser) +{ + pCtx->Guest.pfnThread = pFnThread; + pCtx->Guest.pvUser = pvUser; + + int rc = RTThreadCreate(&pCtx->Guest.hThread, tstHGCMUtilsGuestThread, pCtx, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, + "tstShClGst"); + if (RT_SUCCESS(rc)) + rc = RTThreadUserWait(pCtx->Guest.hThread, RT_MS_30SEC); + + return rc; +} + +/** + * Stops the guest side thread. + * + * @returns VBox status code. + * @param pCtx HGCM Mock utils context to stop guest thread for. + */ +int TstHGCMUtilsGuestThreadStop(PTSTHGCMUTILSCTX pCtx) +{ + ASMAtomicWriteBool(&pCtx->Guest.fShutdown, true); + + int rcThread; + int rc = RTThreadWait(pCtx->Guest.hThread, RT_MS_30SEC, &rcThread); + if (RT_SUCCESS(rc)) + rc = rcThread; + if (RT_SUCCESS(rc)) + pCtx->Guest.hThread = NIL_RTTHREAD; + + return rc; +} + +/** + * Thread worker function for the host side HGCM service. + * + * @returns VBox status code. + * @param hThread Thread handle. + * @param pvUser Pointer of type PTSTHGCMUTILSCTX. + * + * @note Runs in the host service thread. + */ +static DECLCALLBACK(int) tstHGCMUtilsHostThreadWorker(RTTHREAD hThread, void *pvUser) +{ + RT_NOREF(hThread); + PTSTHGCMUTILSCTX pCtx = (PTSTHGCMUTILSCTX)pvUser; + AssertPtr(pCtx); + + int rc = VINF_SUCCESS; + + RTThreadUserSignal(hThread); + + PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst(); + + for (;;) + { + if (ASMAtomicReadBool(&pCtx->Host.fShutdown)) + break; + + /* Wait for a new (mock) HGCM client to connect. */ + PTSTHGCMMOCKCLIENT pMockClient = TstHgcmMockSvcWaitForConnectEx(pSvc, 100 /* ms */); + if (pMockClient) /* Might be NULL when timed out. */ + { + if (pCtx->Host.Callbacks.pfnOnClientConnected) + /* ignore rc */ pCtx->Host.Callbacks.pfnOnClientConnected(pCtx, pMockClient, pCtx->Host.pvUser); + } + } + + return rc; +} + +/** + * Starts the host side thread. + * + * @returns VBox status code. + * @param pCtx HGCM Mock utils context to start host thread for. + * @param pCallbacks Pointer to host callback table to use. + * @param pvUser User-supplied pointer to reach into the host thread callbacks. + */ +int TstHGCMUtilsHostThreadStart(PTSTHGCMUTILSCTX pCtx, PTSTHGCMUTILSHOSTCALLBACKS pCallbacks, void *pvUser) +{ + memcpy(&pCtx->Host.Callbacks, pCallbacks, sizeof(TSTHGCMUTILSHOSTCALLBACKS)); + pCtx->Host.pvUser = pvUser; + + int rc = RTThreadCreate(&pCtx->Host.hThread, tstHGCMUtilsHostThreadWorker, pCtx, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, + "tstShClHst"); + if (RT_SUCCESS(rc)) + rc = RTThreadUserWait(pCtx->Host.hThread, RT_MS_30SEC); + + return rc; +} + +/** + * Stops the host side thread. + * + * @returns VBox status code. + * @param pCtx HGCM Mock utils context to stop host thread for. + */ +int TstHGCMUtilsHostThreadStop(PTSTHGCMUTILSCTX pCtx) +{ + ASMAtomicWriteBool(&pCtx->Host.fShutdown, true); + + int rcThread; + int rc = RTThreadWait(pCtx->Host.hThread, RT_MS_30SEC, &rcThread); + if (RT_SUCCESS(rc)) + rc = rcThread; + if (RT_SUCCESS(rc)) + pCtx->Host.hThread = NIL_RTTHREAD; + + return rc; +} + +#endif /* IN_RING3 */ + +#endif /* !VBOX_INCLUDED_GuestHost_HGCMMockUtils_h */ + diff --git a/include/VBox/GuestHost/Makefile.kup b/include/VBox/GuestHost/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/VBox/GuestHost/Makefile.kup diff --git a/include/VBox/GuestHost/SharedClipboard-transfers.h b/include/VBox/GuestHost/SharedClipboard-transfers.h new file mode 100644 index 00000000..32e5b814 --- /dev/null +++ b/include/VBox/GuestHost/SharedClipboard-transfers.h @@ -0,0 +1,993 @@ +/* $Id: SharedClipboard-transfers.h $ */ +/** @file + * Shared Clipboard - Shared transfer functions between host and guest. + */ + +/* + * Copyright (C) 2019-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_transfers_h +#define VBOX_INCLUDED_GuestHost_SharedClipboard_transfers_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <map> + +#include <iprt/assert.h> +#include <iprt/critsect.h> +#include <iprt/fs.h> +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP +# include <iprt/http-server.h> +#endif +#include <iprt/list.h> + +#include <iprt/cpp/list.h> +#include <iprt/cpp/ministring.h> + +#include <VBox/GuestHost/SharedClipboard.h> +#include <VBox/HostServices/VBoxClipboardSvc.h> + + +struct SHCLTRANSFER; +/** Pointer to a single shared clipboard transfer */ +typedef struct SHCLTRANSFER *PSHCLTRANSFER; + + +/** @name Shared Clipboard transfer definitions. + * @{ + */ + +/** Defines the maximum length (in chars) a Shared Clipboard transfer path can have. */ +#define SHCL_TRANSFER_PATH_MAX RTPATH_MAX + +/** + * Defines the transfer status codes. + */ +typedef enum +{ + /** No status set. */ + SHCLTRANSFERSTATUS_NONE = 0, + /** The transfer has been initialized but is not running yet. */ + SHCLTRANSFERSTATUS_INITIALIZED, + /** The transfer is active and running. */ + SHCLTRANSFERSTATUS_STARTED, + /** The transfer has been stopped. */ + SHCLTRANSFERSTATUS_STOPPED, + /** The transfer has been canceled. */ + SHCLTRANSFERSTATUS_CANCELED, + /** The transfer has been killed. */ + SHCLTRANSFERSTATUS_KILLED, + /** The transfer ran into an unrecoverable error. */ + SHCLTRANSFERSTATUS_ERROR, + /** The usual 32-bit hack. */ + SHCLTRANSFERSTATUS_32BIT_SIZE_HACK = 0x7fffffff +} SHCLTRANSFERSTATUSENUM; + +/** Defines a transfer status. */ +typedef uint32_t SHCLTRANSFERSTATUS; + +/** @} */ + +/** @name Shared Clipboard handles. + * @{ + */ + +/** A Shared Clipboard list handle. */ +typedef uint64_t SHCLLISTHANDLE; +/** Pointer to a Shared Clipboard list handle. */ +typedef SHCLLISTHANDLE *PSHCLLISTHANDLE; +/** Specifies an invalid Shared Clipboard list handle. + * @todo r=bird: The convention is NIL_SHCLLISTHANDLE. */ +#define SHCLLISTHANDLE_INVALID ((SHCLLISTHANDLE)UINT64_MAX) + +/** A Shared Clipboard object handle. */ +typedef uint64_t SHCLOBJHANDLE; +/** Pointer to a Shared Clipboard object handle. */ +typedef SHCLOBJHANDLE *PSHCLOBJHANDLE; +/** Specifies an invalid Shared Clipboard object handle. + * @todo r=bird: The convention is NIL_SHCLOBJHANDLE. */ +#define SHCLOBJHANDLE_INVALID ((SHCLOBJHANDLE)UINT64_MAX) + +/** @} */ + +/** @name Shared Clipboard open/create flags. + * @{ + */ +/** No flags. Initialization value. */ +#define SHCL_OBJ_CF_NONE UINT32_C(0x00000000) + +#if 0 /* These probably won't be needed either */ +/** Lookup only the object, do not return a handle. All other flags are ignored. */ +#define SHCL_OBJ_CF_LOOKUP UINT32_C(0x00000001) +/** Create/open a directory. */ +#define SHCL_OBJ_CF_DIRECTORY UINT32_C(0x00000004) +#endif + +/** Read/write requested access for the object. */ +#define SHCL_OBJ_CF_ACCESS_MASK_RW UINT32_C(0x00001000) +/** No access requested. */ +#define SHCL_OBJ_CF_ACCESS_NONE UINT32_C(0x00000000) +/** Read access requested. */ +#define SHCL_OBJ_CF_ACCESS_READ UINT32_C(0x00001000) + +/** Requested share access for the object. */ +#define SHCL_OBJ_CF_ACCESS_MASK_DENY UINT32_C(0x00008000) +/** Allow any access. */ +#define SHCL_OBJ_CF_ACCESS_DENYNONE UINT32_C(0x00000000) +/** Do not allow write. */ +#define SHCL_OBJ_CF_ACCESS_DENYWRITE UINT32_C(0x00008000) + +/** Requested access to attributes of the object. */ +#define SHCL_OBJ_CF_ACCESS_MASK_ATTR UINT32_C(0x00010000) +/** No access requested. */ +#define SHCL_OBJ_CF_ACCESS_ATTR_NONE UINT32_C(0x00000000) +/** Read access requested. */ +#define SHCL_OBJ_CF_ACCESS_ATTR_READ UINT32_C(0x00010000) + +/** Valid bits. */ +#define SHCL_OBJ_CF_VALID_MASK UINT32_C(0x00019000) +/** @} */ + +/** + * The available additional information in a SHCLFSOBJATTR object. + * @sa RTFSOBJATTRADD + */ +typedef enum _SHCLFSOBJATTRADD +{ + /** No additional information is available / requested. */ + SHCLFSOBJATTRADD_NOTHING = 1, + /** The additional unix attributes (SHCLFSOBJATTR::u::Unix) are + * available / requested. */ + SHCLFSOBJATTRADD_UNIX, + /** The additional extended attribute size (SHCLFSOBJATTR::u::EASize) is + * available / requested. */ + SHCLFSOBJATTRADD_EASIZE, + /** The last valid item (inclusive). + * The valid range is SHCLFSOBJATTRADD_NOTHING thru + * SHCLFSOBJATTRADD_LAST. */ + SHCLFSOBJATTRADD_LAST = SHCLFSOBJATTRADD_EASIZE, + /** The usual 32-bit hack. */ + SHCLFSOBJATTRADD_32BIT_SIZE_HACK = 0x7fffffff +} SHCLFSOBJATTRADD; + + +/* Assert sizes of the IRPT types we're using below. */ +AssertCompileSize(RTFMODE, 4); +AssertCompileSize(RTFOFF, 8); +AssertCompileSize(RTINODE, 8); +AssertCompileSize(RTTIMESPEC, 8); +AssertCompileSize(RTDEV, 4); +AssertCompileSize(RTUID, 4); + +/** + * Shared Clipboard filesystem object attributes. + * + * @sa RTFSOBJATTR + */ +typedef struct _SHCLFSOBJATTR +{ + /** Mode flags (st_mode). RTFS_UNIX_*, RTFS_TYPE_*, and RTFS_DOS_*. + * @remarks We depend on a number of RTFS_ defines to remain unchanged. + * Fortuntately, these are depending on windows, dos and unix + * standard values, so this shouldn't be much of a pain. */ + RTFMODE fMode; + + /** The additional attributes available. */ + SHCLFSOBJATTRADD enmAdditional; + + /** + * Additional attributes. + * + * Unless explicitly specified to an API, the API can provide additional + * data as it is provided by the underlying OS. + */ + union SHCLFSOBJATTRUNION + { + /** Additional Unix Attributes + * These are available when SHCLFSOBJATTRADD is set in fUnix. + */ + struct SHCLFSOBJATTRUNIX + { + /** The user owning the filesystem object (st_uid). + * This field is ~0U if not supported. */ + RTUID uid; + + /** The group the filesystem object is assigned (st_gid). + * This field is ~0U if not supported. */ + RTGID gid; + + /** Number of hard links to this filesystem object (st_nlink). + * This field is 1 if the filesystem doesn't support hardlinking or + * the information isn't available. + */ + uint32_t cHardlinks; + + /** The device number of the device which this filesystem object resides on (st_dev). + * This field is 0 if this information is not available. */ + RTDEV INodeIdDevice; + + /** The unique identifier (within the filesystem) of this filesystem object (st_ino). + * Together with INodeIdDevice, this field can be used as a OS wide unique id + * when both their values are not 0. + * This field is 0 if the information is not available. */ + RTINODE INodeId; + + /** User flags (st_flags). + * This field is 0 if this information is not available. */ + uint32_t fFlags; + + /** The current generation number (st_gen). + * This field is 0 if this information is not available. */ + uint32_t GenerationId; + + /** The device number of a character or block device type object (st_rdev). + * This field is 0 if the file isn't of a character or block device type and + * when the OS doesn't subscribe to the major+minor device idenfication scheme. */ + RTDEV Device; + } Unix; + + /** + * Extended attribute size. + */ + struct SHCLFSOBJATTREASIZE + { + /** Size of EAs. */ + RTFOFF cb; + } EASize; + + /** Padding the structure to a multiple of 8 bytes. */ + uint64_t au64Padding[5]; + } u; +} SHCLFSOBJATTR; +AssertCompileSize(SHCLFSOBJATTR, 48); +/** Pointer to a Shared Clipboard filesystem object attributes structure. */ +typedef SHCLFSOBJATTR *PSHCLFSOBJATTR; +/** Pointer to a const Shared Clipboard filesystem object attributes structure. */ +typedef const SHCLFSOBJATTR *PCSHCLFSOBJATTR; + +/** + * Shared Clipboard file system object information structure. + * + * @sa RTFSOBJINFO + */ +typedef struct _SHCLFSOBJINFO +{ + /** Logical size (st_size). + * For normal files this is the size of the file. + * For symbolic links, this is the length of the path name contained + * in the symbolic link. + * For other objects this fields needs to be specified. + */ + RTFOFF cbObject; + + /** Disk allocation size (st_blocks * DEV_BSIZE). */ + RTFOFF cbAllocated; + + /** Time of last access (st_atime). + * @remarks Here (and other places) we depend on the IPRT timespec to + * remain unchanged. */ + RTTIMESPEC AccessTime; + + /** Time of last data modification (st_mtime). */ + RTTIMESPEC ModificationTime; + + /** Time of last status change (st_ctime). + * If not available this is set to ModificationTime. + */ + RTTIMESPEC ChangeTime; + + /** Time of file birth (st_birthtime). + * If not available this is set to ChangeTime. + */ + RTTIMESPEC BirthTime; + + /** Attributes. */ + SHCLFSOBJATTR Attr; + +} SHCLFSOBJINFO; +AssertCompileSize(SHCLFSOBJINFO, 96); +/** Pointer to a Shared Clipboard filesystem object information structure. */ +typedef SHCLFSOBJINFO *PSHCLFSOBJINFO; +/** Pointer to a const Shared Clipboard filesystem object information + * structure. */ +typedef const SHCLFSOBJINFO *PCSHCLFSOBJINFO; + +/** + * Structure for keeping object open/create parameters. + */ +typedef struct _SHCLOBJOPENCREATEPARMS +{ + /** Path to object to open / create. */ + char *pszPath; + /** Size (in bytes) of path to to object. */ + uint32_t cbPath; + /** SHCL_OBJ_CF_* */ + uint32_t fCreate; + /** + * Attributes of object to open/create and + * returned actual attributes of opened/created object. + */ + SHCLFSOBJINFO ObjInfo; +} SHCLOBJOPENCREATEPARMS, *PSHCLOBJOPENCREATEPARMS; + +/** + * Structure for keeping a reply message. + */ +typedef struct _SHCLREPLY +{ + /** Message type of type VBOX_SHCL_REPLYMSGTYPE_XXX. */ + uint32_t uType; + /** IPRT result of overall operation. Note: int vs. uint32! */ + uint32_t rc; + union + { + struct + { + SHCLTRANSFERSTATUS uStatus; + } TransferStatus; + struct + { + SHCLLISTHANDLE uHandle; + } ListOpen; + struct + { + SHCLLISTHANDLE uHandle; + } ListClose; + struct + { + SHCLOBJHANDLE uHandle; + } ObjOpen; + struct + { + SHCLOBJHANDLE uHandle; + } ObjClose; + } u; + /** Pointer to optional payload. */ + void *pvPayload; + /** Payload size (in bytes). */ + uint32_t cbPayload; +} SHCLREPLY, *PSHCLREPLY; + +struct _SHCLLISTENTRY; +typedef _SHCLLISTENTRY SHCLLISTENTRY; + +/** Defines a single root list entry. Currently the same as a regular list entry. */ +typedef SHCLLISTENTRY SHCLROOTLISTENTRY; +/** Defines a pointer to a single root list entry. Currently the same as a regular list entry pointer. */ +typedef SHCLROOTLISTENTRY *PSHCLROOTLISTENTRY; + +/** + * Structure for keeping Shared Clipboard root list headers. + */ +typedef struct _SHCLROOTLISTHDR +{ + /** Roots listing flags; unused at the moment. */ + uint32_t fRoots; + /** Number of root list entries. */ + uint32_t cRoots; +} SHCLROOTLISTHDR, *PSHCLROOTLISTHDR; + +/** + * Structure for maintaining a Shared Clipboard root list. + */ +typedef struct _SHCLROOTLIST +{ + /** Root list header. */ + SHCLROOTLISTHDR Hdr; + /** Root list entries. */ + SHCLROOTLISTENTRY *paEntries; +} SHCLROOTLIST, *PSHCLROOTLIST; + +/** + * Structure for maintaining Shared Clipboard list open paramters. + */ +typedef struct _SHCLLISTOPENPARMS +{ + /** Listing flags (see VBOX_SHCL_LIST_FLAG_XXX). */ + uint32_t fList; + /** Size (in bytes) of the filter string. */ + uint32_t cbFilter; + /** Filter string. DOS wilcard-style. */ + char *pszFilter; + /** Size (in bytes) of the listing path. */ + uint32_t cbPath; + /** Listing path (absolute). If empty or NULL the listing's root path will be opened. */ + char *pszPath; +} SHCLLISTOPENPARMS, *PSHCLLISTOPENPARMS; + +/** + * Structure for keeping a Shared Clipboard list header. + */ +typedef struct _SHCLLISTHDR +{ + /** Feature flag(s). Not being used atm. */ + uint32_t fFeatures; + /** Total objects returned. */ + uint64_t cTotalObjects; + /** Total size (in bytes) returned. */ + uint64_t cbTotalSize; +} SHCLLISTHDR, *PSHCLLISTHDR; + +/** + * Structure for a Shared Clipboard list entry. + */ +typedef struct _SHCLLISTENTRY +{ + /** Entry name. */ + char *pszName; + /** Size (in bytes) of entry name. */ + uint32_t cbName; + /** Information flag(s). */ + uint32_t fInfo; + /** Size (in bytes) of the actual list entry. */ + uint32_t cbInfo; + /** Data of the actual list entry. */ + void *pvInfo; +} SHCLLISTENTRY, *PSHCLLISTENTRY; + +/** Maximum length (in UTF-8 characters) of a list entry name. */ +#define SHCLLISTENTRY_MAX_NAME RTPATH_MAX /** @todo Improve this to be more dynamic. */ + +/** + * Structure for maintaining a Shared Clipboard list. + */ +typedef struct _SHCLLIST +{ + /** List header. */ + SHCLLISTHDR Hdr; + /** List entries. */ + SHCLROOTLISTENTRY *paEntries; +} SHCLLIST, *PSHCLLIST; + +/** + * Structure for keeping a Shared Clipboard object data chunk. + */ +typedef struct _SHCLOBJDATACHUNK +{ + /** Handle of object this data chunk is related to. */ + uint64_t uHandle; + /** Pointer to actual data chunk. */ + void *pvData; + /** Size (in bytes) of data chunk. */ + uint32_t cbData; +} SHCLOBJDATACHUNK, *PSHCLOBJDATACHUNK; + +/** + * Structure for handling a single transfer object context. + */ +typedef struct _SHCLCLIENTTRANSFEROBJCTX +{ + SHCLTRANSFER *pTransfer; + SHCLOBJHANDLE uHandle; +} SHCLCLIENTTRANSFEROBJCTX, *PSHCLCLIENTTRANSFEROBJCTX; + +typedef struct _SHCLTRANSFEROBJSTATE +{ + /** How many bytes were processed (read / write) so far. */ + uint64_t cbProcessed; +} SHCLTRANSFEROBJSTATE, *PSHCLTRANSFEROBJSTATE; + +typedef struct _SHCLTRANSFEROBJ +{ + SHCLOBJHANDLE uHandle; + char *pszPathAbs; + SHCLFSOBJINFO objInfo; + SHCLSOURCE enmSource; + SHCLTRANSFEROBJSTATE State; +} SHCLTRANSFEROBJ, *PSHCLTRANSFEROBJ; + +/** + * Enumeration for specifying a Shared Clipboard object type. + */ +typedef enum _SHCLOBJTYPE +{ + /** Invalid object type. */ + SHCLOBJTYPE_INVALID = 0, + /** Object is a directory. */ + SHCLOBJTYPE_DIRECTORY, + /** Object is a file. */ + SHCLOBJTYPE_FILE, + /** Object is a symbolic link. */ + SHCLOBJTYPE_SYMLINK, + /** The usual 32-bit hack. */ + SHCLOBJTYPE_32BIT_SIZE_HACK = 0x7fffffff +} SHCLOBJTYPE; + +/** + * Structure for keeping transfer list handle information. + * This is using to map own (local) handles to the underlying file system. + */ +typedef struct _SHCLLISTHANDLEINFO +{ + /** The list node. */ + RTLISTNODE Node; + /** The list's handle. */ + SHCLLISTHANDLE hList; + /** Type of list handle. */ + SHCLOBJTYPE enmType; + /** Absolute local path of the list object. */ + char *pszPathLocalAbs; + union + { + /** Local data, based on enmType. */ + struct + { + union + { + RTDIR hDir; + RTFILE hFile; + }; + } Local; + } u; +} SHCLLISTHANDLEINFO, *PSHCLLISTHANDLEINFO; + +/** + * Structure for keeping transfer object handle information. + * This is using to map own (local) handles to the underlying file system. + */ +typedef struct _SHCLOBJHANDLEINFO +{ + /** The list node. */ + RTLISTNODE Node; + /** The object's handle. */ + SHCLOBJHANDLE hObj; + /** Type of object handle. */ + SHCLOBJTYPE enmType; + /** Absolute local path of the object. */ + char *pszPathLocalAbs; + union + { + /** Local data, based on enmType. */ + struct + { + union + { + RTDIR hDir; + RTFILE hFile; + }; + } Local; + } u; +} SHCLOBJHANDLEINFO, *PSHCLOBJHANDLEINFO; + +/** + * Structure for keeping a single root list entry. + */ +typedef struct _SHCLLISTROOT +{ + /** The list node. */ + RTLISTNODE Node; + /** Absolute path of entry. */ + char *pszPathAbs; +} SHCLLISTROOT, *PSHCLLISTROOT; + +/** + * Structure for maintaining an Shared Clipboard transfer state. + * Everything in here will be part of a saved state (later). + */ +typedef struct _SHCLTRANSFERSTATE +{ + /** The transfer's (local) ID. */ + SHCLTRANSFERID uID; + /** The transfer's current status. */ + SHCLTRANSFERSTATUS enmStatus; + /** The transfer's direction, seen from the perspective who created the transfer. */ + SHCLTRANSFERDIR enmDir; + /** The transfer's source, seen from the perspective who created the transfer. */ + SHCLSOURCE enmSource; +} SHCLTRANSFERSTATE, *PSHCLTRANSFERSTATE; + +/** + * Structure maintaining clipboard transfer provider context data. + * This is handed in to the provider interface implementations. + */ +typedef struct _SHCLTXPROVIDERCTX +{ + /** Pointer to the related Shared Clipboard transfer. */ + PSHCLTRANSFER pTransfer; + /** User-defined data pointer. Can be NULL if not needed. */ + void *pvUser; + /** Size (in bytes) of data at user pointer. */ + size_t cbUser; +} SHCLTXPROVIDERCTX, *PSHCLTXPROVIDERCTX; + +struct SHCLTRANSFERCTX; +typedef struct SHCLTRANSFERCTX *PSHCLTRANSFERCTX; + +/** + * Shared Clipboard transfer provider interface table. + * + * A transfer provider inteface implementation realizes all low level functions + * needed for making a Shared Clipboard transfer happen. + */ +typedef struct _SHCLTXPROVIDERIFACE +{ + DECLCALLBACKMEMBER(int, pfnRootsGet,(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList)); + DECLCALLBACKMEMBER(int, pfnListOpen,(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList)); + DECLCALLBACKMEMBER(int, pfnListClose,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)); + DECLCALLBACKMEMBER(int, pfnListHdrRead,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)); + DECLCALLBACKMEMBER(int, pfnListHdrWrite,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)); + DECLCALLBACKMEMBER(int, pfnListEntryRead,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry)); + DECLCALLBACKMEMBER(int, pfnListEntryWrite,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry)); + DECLCALLBACKMEMBER(int, pfnObjOpen,(PSHCLTXPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)); + DECLCALLBACKMEMBER(int, pfnObjClose,(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)); + DECLCALLBACKMEMBER(int, pfnObjRead,(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData, + uint32_t fFlags, uint32_t *pcbRead)); + DECLCALLBACKMEMBER(int, pfnObjWrite,(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData, + uint32_t fFlags, uint32_t *pcbWritten)); +} SHCLTXPROVIDERIFACE, *PSHCLTXPROVIDERIFACE; + +/** + * Structure for the Shared Clipboard transfer provider creation context. + */ +typedef struct _SHCLTXPROVIDERCREATIONCTX +{ + /** Specifies what the source of the provider is. */ + SHCLSOURCE enmSource; + /** The provider interface table. */ + SHCLTXPROVIDERIFACE Interface; + /** User-provided callback data. */ + void *pvUser; + /** Size (in bytes) of data at user pointer. */ + size_t cbUser; +} SHCLTXPROVIDERCREATIONCTX, *PSHCLTXPROVIDERCREATIONCTX; + +/** + * Structure maintaining clipboard transfer callback context data. + */ +typedef struct _SHCLTRANSFERCALLBACKCTX +{ + /** Pointer to the related Shared Clipboard transfer. */ + PSHCLTRANSFER pTransfer; + /** User-defined data pointer. Can be NULL if not needed. */ + void *pvUser; + /** Size (in bytes) of data at user pointer. */ + size_t cbUser; +} SHCLTRANSFERCALLBACKCTX, *PSHCLTRANSFERCALLBACKCTX; + +/** + * Shared Clipboard transfer callback table. + * + * All callbacks are optional and can provide additional information / feedback to a frontend. + */ +typedef struct _SHCLTRANSFERCALLBACKTABLE +{ + /** + * Called when the transfer gets initialized. + * + * @param pCbCtx Pointer to callback context to use. + */ + DECLCALLBACKMEMBER(int, pfnOnInitialize,(PSHCLTRANSFERCALLBACKCTX pCbCtx)); + /** + * Called before the transfer will be started. + * + * @param pCbCtx Pointer to callback context to use. + */ + DECLCALLBACKMEMBER(int, pfnOnStart,(PSHCLTRANSFERCALLBACKCTX pCbCtx)); + /** + * Called when the transfer has been complete. + * + * @param pCbCtx Pointer to callback context to use. + * @param rcCompletion Completion result. + * VERR_CANCELED if transfer has been canceled. + */ + DECLCALLBACKMEMBER(void, pfnOnCompleted,(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcCompletion)); + /** + * Called when transfer resulted in an unrecoverable error. + * + * @param pCbCtx Pointer to callback context to use. + * @param rcError Error reason, IPRT-style. + */ + DECLCALLBACKMEMBER(void, pfnOnError,(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcError)); + /** + * Called when transfer got registered to a transfer context. + * + * @param pCbCtx Pointer to callback context to use. + * @param pTransferCtx Transfer context transfer was registered to. + */ + DECLCALLBACKMEMBER(void, pfnOnRegistered,(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)); + /** + * Called when transfer got unregistered from a transfer context. + * + * @param pCbCtx Pointer to callback context to use. + * @param pTransferCtx Transfer context transfer was unregistered from. + */ + DECLCALLBACKMEMBER(void, pfnOnUnregistered,(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)); + + /** User-provided callback data. Can be NULL if not used. */ + void *pvUser; + /** Size (in bytes) of data pointer at \a pvUser. */ + size_t cbUser; +} SHCLTRANSFERCALLBACKTABLE, *PSHCLTRANSFERCALLBACKTABLE; + +/** + * Structure for thread-related members for a single Shared Clipboard transfer. + */ +typedef struct _SHCLTRANSFERTHREAD +{ + /** Thread handle for the reading / writing thread. + * Can be NIL_RTTHREAD if not being used. */ + RTTHREAD hThread; + /** Thread started indicator. */ + volatile bool fStarted; + /** Thread stop flag. */ + volatile bool fStop; + /** Thread cancelled flag / indicator. */ + volatile bool fCancelled; +} SHCLTRANSFERTHREAD, *PSHCLTRANSFERTHREAD; + +/** + * A single Shared Clipboard transfer. + * + ** @todo Not yet thread safe. + */ +typedef struct SHCLTRANSFER +{ + /** The node member for using this struct in a RTList. */ + RTLISTNODE Node; + /** The transfer's state (for SSM, later). */ + SHCLTRANSFERSTATE State; + /** Absolute path to root entries. */ + char *pszPathRootAbs; + /** Timeout (in ms) for waiting of events. Default is 30s. */ + RTMSINTERVAL uTimeoutMs; + /** Maximum data chunk size (in bytes) to transfer. Default is 64K. */ + uint32_t cbMaxChunkSize; + /** The transfer's own event source. */ + SHCLEVENTSOURCE Events; + /** Current number of concurrent list handles. */ + uint32_t cListHandles; + /** Maximum number of concurrent list handles. */ + uint32_t cMaxListHandles; + /** Next upcoming list handle. */ + SHCLLISTHANDLE uListHandleNext; + /** List of all list handles elated to this transfer. */ + RTLISTANCHOR lstList; + /** Number of root entries in list. */ + uint64_t cRoots; + /** List of root entries of this transfer. */ + RTLISTANCHOR lstRoots; + /** Current number of concurrent object handles. */ + uint32_t cObjHandles; + /** Maximum number of concurrent object handles. */ + uint32_t cMaxObjHandles; + /** Next upcoming object handle. */ + SHCLOBJHANDLE uObjHandleNext; + /** Map of all objects handles related to this transfer. */ + RTLISTANCHOR lstObj; + /** The transfer's own provider context. */ + SHCLTXPROVIDERCTX ProviderCtx; + /** The transfer's provider interface. */ + SHCLTXPROVIDERIFACE ProviderIface; + /** The transfer's callback context. */ + SHCLTRANSFERCALLBACKCTX CallbackCtx; + /** The transfer's callback table. */ + SHCLTRANSFERCALLBACKTABLE Callbacks; + /** Opaque pointer to implementation-specific parameters. */ + void *pvUser; + /** Size (in bytes) of implementation-specific parameters. */ + size_t cbUser; + /** Contains thread-related attributes. */ + SHCLTRANSFERTHREAD Thread; + /** Critical section for serializing access. */ + RTCRITSECT CritSect; +} SHCLTRANSFER, *PSHCLTRANSFER; + +/** + * Structure for keeping an Shared Clipboard transfer status report. + */ +typedef struct _SHCLTRANSFERREPORT +{ + /** Actual status to report. */ + SHCLTRANSFERSTATUS uStatus; + /** Result code (rc) to report; might be unused / invalid, based on enmStatus. */ + int rc; + /** Reporting flags. Currently unused and must be 0. */ + uint32_t fFlags; +} SHCLTRANSFERREPORT, *PSHCLTRANSFERREPORT; + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP +typedef struct _SHCLHTTPSERVER +{ + /** Critical section for serializing access. */ + RTCRITSECT CritSect; + /** Handle of the HTTP server instance. */ + RTHTTPSERVER hHTTPServer; + /** Port number the HTTP server is running on. 0 if not running. */ + uint16_t uPort; + /** List of registered HTTP transfers. */ + RTLISTANCHOR lstTransfers; + /** Number of registered HTTP transfers. */ + uint32_t cTransfers; + /** Cached response data. */ + RTHTTPSERVERRESP Resp; +} SHCLHTTPSERVER; +typedef SHCLHTTPSERVER *PSHCLHTTPSERVER; + +typedef struct _SHCLHTTPCONTEXT +{ + /** HTTP server instance data. */ + SHCLHTTPSERVER HttpServer; +} SHCLHTTPCONTEXT; +typedef SHCLHTTPCONTEXT *PSHCLHTTPCONTEXT; + +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */ + +/** + * Structure for keeping Shared Clipboard transfer context around. + */ +struct SHCLTRANSFERCTX +{ + /** Critical section for serializing access. */ + RTCRITSECT CritSect; + /** List of transfers. */ + RTLISTANCHOR List; + /** Transfer ID allocation bitmap; clear bits are free, set bits are busy. */ + uint64_t bmTransferIds[VBOX_SHCL_MAX_TRANSFERS / sizeof(uint64_t) / 8]; + /** Number of running (concurrent) transfers. */ + uint16_t cRunning; + /** Maximum Number of running (concurrent) transfers. */ + uint16_t cMaxRunning; + /** Number of total transfers (in list). */ + uint16_t cTransfers; +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP + /** HTTP server instance for this transfer context. */ + SHCLHTTPSERVER HttpServer; +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */ +}; + +int ShClTransferObjCtxInit(PSHCLCLIENTTRANSFEROBJCTX pObjCtx); +void ShClTransferObjCtxDestroy(PSHCLCLIENTTRANSFEROBJCTX pObjCtx); +bool ShClTransferObjCtxIsValid(PSHCLCLIENTTRANSFEROBJCTX pObjCtx); + +int ShClTransferObjHandleInfoInit(PSHCLOBJHANDLEINFO pInfo); +void ShClTransferObjHandleInfoDestroy(PSHCLOBJHANDLEINFO pInfo); + +int ShClTransferObjOpenParmsInit(PSHCLOBJOPENCREATEPARMS pParms); +int ShClTransferObjOpenParmsCopy(PSHCLOBJOPENCREATEPARMS pParmsDst, PSHCLOBJOPENCREATEPARMS pParmsSrc); +void ShClTransferObjOpenParmsDestroy(PSHCLOBJOPENCREATEPARMS pParms); + +int ShClTransferObjOpen(PSHCLTRANSFER pTransfer, PSHCLOBJOPENCREATEPARMS pOpenCreateParms, PSHCLOBJHANDLE phObj); +int ShClTransferObjClose(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj); +int ShClTransferObjRead(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, uint32_t fFlags, uint32_t *pcbRead); +int ShClTransferObjWrite(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, uint32_t fFlags, uint32_t *pcbWritten); + +PSHCLOBJDATACHUNK ShClTransferObjDataChunkDup(PSHCLOBJDATACHUNK pDataChunk); +void ShClTransferObjDataChunkDestroy(PSHCLOBJDATACHUNK pDataChunk); +void ShClTransferObjDataChunkFree(PSHCLOBJDATACHUNK pDataChunk); + +int ShClTransferCreate(PSHCLTRANSFER *ppTransfer); +int ShClTransferInit(PSHCLTRANSFER pTransfer, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource); +int ShClTransferDestroy(PSHCLTRANSFER pTransfer); + +int ShClTransferListOpen(PSHCLTRANSFER pTransfer, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList); +int ShClTransferListClose(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList); +int ShClTransferListGetHeader(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, PSHCLLISTHDR pHdr); +PSHCLTRANSFEROBJ ShClTransferListGetObj(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, uint64_t uIdx); +int ShClTransferListRead(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry); +int ShClTransferListWrite(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry); +bool ShClTransferListHandleIsValid(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList); + +int ShClPathSanitizeFilename(char *pszPath, size_t cbPath); +int ShClPathSanitize(char *pszPath, size_t cbPath); + +PSHCLROOTLIST ShClTransferRootListAlloc(void); +void ShClTransferRootListFree(PSHCLROOTLIST pRootList); + +PSHCLROOTLISTHDR ShClTransferRootListHdrDup(PSHCLROOTLISTHDR pRoots); +int ShClTransferRootListHdrInit(PSHCLROOTLISTHDR pRoots); +void ShClTransferRootListHdrDestroy(PSHCLROOTLISTHDR pRoots); + +int ShClTransferRootListEntryCopy(PSHCLROOTLISTENTRY pDst, PSHCLROOTLISTENTRY pSrc); +int ShClTransferRootListEntryInit(PSHCLROOTLISTENTRY pRootListEntry); +void ShClTransferRootListEntryDestroy(PSHCLROOTLISTENTRY pRootListEntry); +PSHCLROOTLISTENTRY ShClTransferRootListEntryDup(PSHCLROOTLISTENTRY pRootListEntry); + +int ShClTransferListHandleInfoInit(PSHCLLISTHANDLEINFO pInfo); +void ShClTransferListHandleInfoDestroy(PSHCLLISTHANDLEINFO pInfo); + +int ShClTransferListHdrAlloc(PSHCLLISTHDR *ppListHdr); +void ShClTransferListHdrFree(PSHCLLISTHDR pListHdr); +PSHCLLISTHDR ShClTransferListHdrDup(PSHCLLISTHDR pListHdr); +int ShClTransferListHdrInit(PSHCLLISTHDR pListHdr); +void ShClTransferListHdrDestroy(PSHCLLISTHDR pListHdr); +void ShClTransferListHdrReset(PSHCLLISTHDR pListHdr); +bool ShClTransferListHdrIsValid(PSHCLLISTHDR pListHdr); + +int ShClTransferListOpenParmsCopy(PSHCLLISTOPENPARMS pDst, PSHCLLISTOPENPARMS pSrc); +PSHCLLISTOPENPARMS ShClTransferListOpenParmsDup(PSHCLLISTOPENPARMS pParms); +int ShClTransferListOpenParmsInit(PSHCLLISTOPENPARMS pParms); +void ShClTransferListOpenParmsDestroy(PSHCLLISTOPENPARMS pParms); + +int ShClTransferListEntryAlloc(PSHCLLISTENTRY *ppListEntry); +void ShClTransferListEntryFree(PSHCLLISTENTRY pListEntry); +int ShClTransferListEntryCopy(PSHCLLISTENTRY pDst, PSHCLLISTENTRY pSrc); +PSHCLLISTENTRY ShClTransferListEntryDup(PSHCLLISTENTRY pListEntry); +int ShClTransferListEntryInit(PSHCLLISTENTRY pListEntry); +void ShClTransferListEntryDestroy(PSHCLLISTENTRY pListEntry); +bool ShClTransferListEntryIsValid(PSHCLLISTENTRY pListEntry); + +void ShClTransferCopyCallbacks(PSHCLTRANSFERCALLBACKTABLE pCallbacksDst, PSHCLTRANSFERCALLBACKTABLE pCallbacksSrc); +void ShClTransferSetCallbacks(PSHCLTRANSFER pTransfer, PSHCLTRANSFERCALLBACKTABLE pCallbacks); +int ShClTransferSetProviderIface(PSHCLTRANSFER pTransfer, PSHCLTXPROVIDERCREATIONCTX pCreationCtx); +int ShClTransferRootsSet(PSHCLTRANSFER pTransfer, const char *pszRoots, size_t cbRoots); +void ShClTransferReset(PSHCLTRANSFER pTransfer); + +uint32_t ShClTransferRootsCount(PSHCLTRANSFER pTransfer); +int ShClTransferRootsEntry(PSHCLTRANSFER pTransfer, uint64_t uIndex, PSHCLROOTLISTENTRY pEntry); +int ShClTransferRootsGet(PSHCLTRANSFER pTransfer, PSHCLROOTLIST *ppRootList); + +SHCLTRANSFERID ShClTransferGetID(PSHCLTRANSFER pTransfer); +SHCLTRANSFERDIR ShClTransferGetDir(PSHCLTRANSFER pTransfer); +SHCLSOURCE ShClTransferGetSource(PSHCLTRANSFER pTransfer); +SHCLTRANSFERSTATUS ShClTransferGetStatus(PSHCLTRANSFER pTransfer); +int ShClTransferRun(PSHCLTRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser); +int ShClTransferStart(PSHCLTRANSFER pTransfer); + +int ShClTransferCtxInit(PSHCLTRANSFERCTX pTransferCtx); +void ShClTransferCtxDestroy(PSHCLTRANSFERCTX pTransferCtx); +void ShClTransferCtxReset(PSHCLTRANSFERCTX pTransferCtx); +PSHCLTRANSFER ShClTransferCtxGetTransferById(PSHCLTRANSFERCTX pTransferCtx, uint32_t uID); +PSHCLTRANSFER ShClTransferCtxGetTransferByIndex(PSHCLTRANSFERCTX pTransferCtx, uint32_t uIdx); +uint32_t ShClTransferCtxGetRunningTransfers(PSHCLTRANSFERCTX pTransferCtx); +uint32_t ShClTransferCtxGetTotalTransfers(PSHCLTRANSFERCTX pTransferCtx); +void ShClTransferCtxCleanup(PSHCLTRANSFERCTX pTransferCtx); +bool ShClTransferCtxTransfersMaximumReached(PSHCLTRANSFERCTX pTransferCtx); +int ShClTransferCtxTransferRegister(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERID *pidTransfer); +int ShClTransferCtxTransferRegisterById(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERID idTransfer); +int ShClTransferCtxTransferUnregister(PSHCLTRANSFERCTX pTransferCtx, SHCLTRANSFERID idTransfer); + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP +int ShClHttpTransferRegister(PSHCLHTTPCONTEXT pCtx, PSHCLTRANSFER pTransfer); +int ShClHttpTransferUnregister(PSHCLHTTPCONTEXT pCtx, PSHCLTRANSFER pTransfer); + +int ShClTransferHttpServerCreate(PSHCLHTTPSERVER pSrv, uint16_t *puPort); +int ShClTransferHttpServerCreateEx(PSHCLHTTPSERVER pSrv, uint16_t uPort); +int ShClTransferHttpServerDestroy(PSHCLHTTPSERVER pSrv); +void ShClTransferHttpServerInit(PSHCLHTTPSERVER pSrv); +int ShClTransferHttpServerRegisterTransfer(PSHCLHTTPSERVER pSrv, PSHCLTRANSFER pTransfer); +int ShClTransferHttpServerUnregisterTransfer(PSHCLHTTPSERVER pSrv, PSHCLTRANSFER pTransfer); +bool ShClTransferHttpServerHasTransfer(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer); +uint16_t ShClTransferHttpServerGetPort(PSHCLHTTPSERVER pSrv); +uint32_t ShClTransferHttpServerGetTransferCount(PSHCLHTTPSERVER pSrv); +char *ShClTransferHttpServerGetAddressA(PSHCLHTTPSERVER pSrv); +char *ShClTransferHttpServerGetUrlA(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer); +bool ShClTransferHttpServerIsRunning(PSHCLHTTPSERVER pSrv); +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */ + +void ShClFsObjFromIPRT(PSHCLFSOBJINFO pDst, PCRTFSOBJINFO pSrc); + +bool ShClMIMEHasFileURLs(const char *pcszFormat, size_t cchFormatMax); +bool ShClMIMENeedsCache(const char *pcszFormat, size_t cchFormatMax); + +const char *ShClTransferStatusToStr(SHCLTRANSFERSTATUS enmStatus); + +#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_transfers_h */ diff --git a/include/VBox/GuestHost/SharedClipboard-win.h b/include/VBox/GuestHost/SharedClipboard-win.h new file mode 100644 index 00000000..0e35b409 --- /dev/null +++ b/include/VBox/GuestHost/SharedClipboard-win.h @@ -0,0 +1,419 @@ +/** @file + * Shared Clipboard - Common Guest and Host Code, for Windows OSes. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_win_h +#define VBOX_INCLUDED_GuestHost_SharedClipboard_win_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/critsect.h> +#include <iprt/types.h> +#include <iprt/win/windows.h> + +#include <VBox/GuestHost/SharedClipboard.h> + +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +# include <vector> + +# include <iprt/cpp/ministring.h> /* For RTCString. */ +# include <iprt/win/shlobj.h> /* For DROPFILES and friends. */ +# include <VBox/com/string.h> /* For Utf8Str. */ +# include <oleidl.h> + +# include <VBox/GuestHost/SharedClipboard-transfers.h> + +using namespace com; +# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ + +#ifndef WM_CLIPBOARDUPDATE +# define WM_CLIPBOARDUPDATE 0x031D +#endif + +#define SHCL_WIN_WNDCLASS_NAME "VBoxSharedClipboardClass" + +/** See: https://docs.microsoft.com/en-us/windows/desktop/dataxchg/html-clipboard-format + * Do *not* change the name, as this will break compatbility with other (legacy) applications! */ +#define SHCL_WIN_REGFMT_HTML "HTML Format" + +/** Default timeout (in ms) for passing down messages down the clipboard chain. */ +#define SHCL_WIN_CBCHAIN_TIMEOUT_MS 5000 + +/** Reports clipboard formats. */ +#define SHCL_WIN_WM_REPORT_FORMATS WM_USER +/** Reads data from the clipboard and sends it to the destination. */ +#define SHCL_WIN_WM_READ_DATA WM_USER + 1 +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +/** Starts a transfer on the guest. + * This creates the necessary IDataObject in the matching window thread. */ +# define SHCL_WIN_WM_TRANSFER_START WM_USER + 2 +#endif + +/* Dynamically load clipboard functions from User32.dll. */ +typedef BOOL WINAPI FNADDCLIPBOARDFORMATLISTENER(HWND); +typedef FNADDCLIPBOARDFORMATLISTENER *PFNADDCLIPBOARDFORMATLISTENER; + +typedef BOOL WINAPI FNREMOVECLIPBOARDFORMATLISTENER(HWND); +typedef FNREMOVECLIPBOARDFORMATLISTENER *PFNREMOVECLIPBOARDFORMATLISTENER; + +/** + * Structure for keeping function pointers for the new clipboard API. + * If the new API is not available, those function pointer are NULL. + */ +typedef struct _SHCLWINAPINEW +{ + PFNADDCLIPBOARDFORMATLISTENER pfnAddClipboardFormatListener; + PFNREMOVECLIPBOARDFORMATLISTENER pfnRemoveClipboardFormatListener; +} SHCLWINAPINEW, *PSHCLWINAPINEW; + +/** + * Structure for keeping variables which are needed to drive the old clipboard API. + */ +typedef struct _SHCLWINAPIOLD +{ + /** Timer ID for the refresh timer. */ + UINT timerRefresh; + /** Whether "pinging" the clipboard chain currently is in progress or not. */ + bool fCBChainPingInProcess; +} SHCLWINAPIOLD, *PSHCLWINAPIOLD; + +/** + * Structure for maintaining a Shared Clipboard context on Windows platforms. + */ +typedef struct _SHCLWINCTX +{ + /** Critical section to serialize access. */ + RTCRITSECT CritSect; + /** Window handle of our (invisible) clipbaord window. */ + HWND hWnd; + /** Window handle which is next to us in the clipboard chain. */ + HWND hWndNextInChain; + /** Window handle of the clipboard owner *if* we are the owner. + * @todo r=bird: Ignore the misleading statement above. This is only set to + * NULL by the initialization code and then it's set to the clipboard owner + * after we announce data to the clipboard. So, essentially this will be our + * windows handle or NULL. End of story. */ + HWND hWndClipboardOwnerUs; + /** Structure for maintaining the new clipboard API. */ + SHCLWINAPINEW newAPI; + /** Structure for maintaining the old clipboard API. */ + SHCLWINAPIOLD oldAPI; +} SHCLWINCTX, *PSHCLWINCTX; + +int SharedClipboardWinOpen(HWND hWnd); +int SharedClipboardWinClose(void); +int SharedClipboardWinClear(void); + +int SharedClipboardWinCtxInit(PSHCLWINCTX pWinCtx); +void SharedClipboardWinCtxDestroy(PSHCLWINCTX pWinCtx); + +int SharedClipboardWinCheckAndInitNewAPI(PSHCLWINAPINEW pAPI); +bool SharedClipboardWinIsNewAPI(PSHCLWINAPINEW pAPI); + +int SharedClipboardWinDataWrite(UINT cfFormat, void *pvData, uint32_t cbData); + +int SharedClipboardWinChainAdd(PSHCLWINCTX pCtx); +int SharedClipboardWinChainRemove(PSHCLWINCTX pCtx); +VOID CALLBACK SharedClipboardWinChainPingProc(HWND hWnd, UINT uMsg, ULONG_PTR dwData, LRESULT lResult) RT_NOTHROW_DEF; +LRESULT SharedClipboardWinChainPassToNext(PSHCLWINCTX pWinCtx, UINT msg, WPARAM wParam, LPARAM lParam); + +SHCLFORMAT SharedClipboardWinClipboardFormatToVBox(UINT uFormat); +int SharedClipboardWinGetFormats(PSHCLWINCTX pCtx, PSHCLFORMATS pfFormats); + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +int SharedClipboardWinGetRoots(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer); +int SharedClipboardWinDropFilesToStringList(DROPFILES *pDropFiles, char **papszList, uint32_t *pcbList); +#endif + +int SharedClipboardWinGetCFHTMLHeaderValue(const char *pszSrc, const char *pszOption, uint32_t *puValue); +bool SharedClipboardWinIsCFHTML(const char *pszSource); +int SharedClipboardWinConvertCFHTMLToMIME(const char *pszSource, const uint32_t cch, char **ppszOutput, uint32_t *pcbOutput); +int SharedClipboardWinConvertMIMEToCFHTML(const char *pszSource, size_t cb, char **ppszOutput, uint32_t *pcbOutput); + +LRESULT SharedClipboardWinHandleWMChangeCBChain(PSHCLWINCTX pWinCtx, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +int SharedClipboardWinHandleWMDestroy(PSHCLWINCTX pWinCtx); +int SharedClipboardWinHandleWMRenderAllFormats(PSHCLWINCTX pWinCtx, HWND hWnd); +int SharedClipboardWinHandleWMTimer(PSHCLWINCTX pWinCtx); + +int SharedClipboardWinClearAndAnnounceFormats(PSHCLWINCTX pWinCtx, SHCLFORMATS fFormats, HWND hWnd); +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +int SharedClipboardWinTransferCreate(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer); +void SharedClipboardWinTransferDestroy(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer); +#endif + +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +class SharedClipboardTransferList; +# ifndef FILEGROUPDESCRIPTOR +class FILEGROUPDESCRIPTOR; +# endif + +class SharedClipboardWinDataObject : public IDataObject //, public IDataObjectAsyncCapability +{ +public: + + enum Status + { + /** The object is uninitialized (not ready). */ + Uninitialized = 0, + /** The object is initialized and ready to use. */ + Initialized, + /** The operation has been successfully completed. */ + Completed, + /** The operation has been canceled. */ + Canceled, + /** An (unrecoverable) error occurred. */ + Error + }; + +public: + + SharedClipboardWinDataObject(PSHCLTRANSFER pTransfer, + LPFORMATETC pFormatEtc = NULL, LPSTGMEDIUM pStgMed = NULL, ULONG cFormats = 0); + virtual ~SharedClipboardWinDataObject(void); + +public: /* IUnknown methods. */ + + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + +public: /* IDataObject methods. */ + + STDMETHOD(GetData)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium); + STDMETHOD(GetDataHere)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium); + STDMETHOD(QueryGetData)(LPFORMATETC pFormatEtc); + STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC pFormatEct, LPFORMATETC pFormatEtcOut); + STDMETHOD(SetData)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium, BOOL fRelease); + STDMETHOD(EnumFormatEtc)(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc); + STDMETHOD(DAdvise)(LPFORMATETC pFormatEtc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection); + STDMETHOD(DUnadvise)(DWORD dwConnection); + STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppEnumAdvise); + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC +public: /* IDataObjectAsyncCapability methods. */ + + STDMETHOD(EndOperation)(HRESULT hResult, IBindCtx* pbcReserved, DWORD dwEffects); + STDMETHOD(GetAsyncMode)(BOOL* pfIsOpAsync); + STDMETHOD(InOperation)(BOOL* pfInAsyncOp); + STDMETHOD(SetAsyncMode)(BOOL fDoOpAsync); + STDMETHOD(StartOperation)(IBindCtx* pbcReserved); +#endif /* VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC */ + +public: + + int Init(void); + void OnTransferComplete(int rc = VINF_SUCCESS); + void OnTransferCanceled(); + +public: + + static DECLCALLBACK(int) readThread(RTTHREAD ThreadSelf, void *pvUser); + + static void logFormat(CLIPFORMAT fmt); + +protected: + + static int Thread(RTTHREAD hThread, void *pvUser); + + int readDir(PSHCLTRANSFER pTransfer, const Utf8Str &strPath); + + int copyToHGlobal(const void *pvData, size_t cbData, UINT fFlags, HGLOBAL *phGlobal); + int createFileGroupDescriptorFromTransfer(PSHCLTRANSFER pTransfer, + bool fUnicode, HGLOBAL *phGlobal); + + bool lookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex); + void registerFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat, TYMED tyMed = TYMED_HGLOBAL, + LONG lindex = -1, DWORD dwAspect = DVASPECT_CONTENT, DVTARGETDEVICE *pTargetDevice = NULL); +protected: + + /** + * Structure for keeping a single file system object entry. + */ + struct FSOBJENTRY + { + /** Relative path of the object. */ + Utf8Str strPath; + /** Related (cached) object information. */ + SHCLFSOBJINFO objInfo; + }; + + /** Vector containing file system objects with its (cached) objection information. */ + typedef std::vector<FSOBJENTRY> FsObjEntryList; + + /** The object's current status. */ + Status m_enmStatus; + /** The object's current reference count. */ + LONG m_lRefCount; + /** How many formats have been registered. */ + ULONG m_cFormats; + LPFORMATETC m_pFormatEtc; + LPSTGMEDIUM m_pStgMedium; + /** Pointer to the associated transfer object being handled. */ + PSHCLTRANSFER m_pTransfer; + /** Current stream object being used. */ + IStream *m_pStream; + /** Current object index being handled by the data object. + * This is needed to create the next IStream object for e.g. the next upcoming file/dir/++ in the transfer. */ + ULONG m_uObjIdx; + /** List of (cached) file system objects. */ + FsObjEntryList m_lstEntries; + /** Whether the transfer thread is running. */ + bool m_fRunning; + /** Event being triggered when reading the transfer list been completed. */ + RTSEMEVENT m_EventListComplete; + /** Event being triggered when the transfer has been completed. */ + RTSEMEVENT m_EventTransferComplete; + /** Registered format for CFSTR_FILEDESCRIPTORA. */ + UINT m_cfFileDescriptorA; + /** Registered format for CFSTR_FILEDESCRIPTORW. */ + UINT m_cfFileDescriptorW; + /** Registered format for CFSTR_FILECONTENTS. */ + UINT m_cfFileContents; + /** Registered format for CFSTR_PERFORMEDDROPEFFECT. */ + UINT m_cfPerformedDropEffect; +}; + +class SharedClipboardWinEnumFormatEtc : public IEnumFORMATETC +{ +public: + + SharedClipboardWinEnumFormatEtc(LPFORMATETC pFormatEtc, ULONG cFormats); + virtual ~SharedClipboardWinEnumFormatEtc(void); + +public: /* IUnknown methods. */ + + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + +public: /* IEnumFORMATETC methods. */ + + STDMETHOD(Next)(ULONG cFormats, LPFORMATETC pFormatEtc, ULONG *pcFetched); + STDMETHOD(Skip)(ULONG cFormats); + STDMETHOD(Reset)(void); + STDMETHOD(Clone)(IEnumFORMATETC **ppEnumFormatEtc); + +public: + + static void CopyFormat(LPFORMATETC pFormatDest, LPFORMATETC pFormatSource); + static HRESULT CreateEnumFormatEtc(UINT cFormats, LPFORMATETC pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc); + +private: + + LONG m_lRefCount; + ULONG m_nIndex; + ULONG m_nNumFormats; + LPFORMATETC m_pFormatEtc; +}; + +/** + * Own IStream implementation to implement file-based clipboard operations + * through HGCM. Needed on Windows hosts and guests. + */ +class SharedClipboardWinStreamImpl : public IStream +{ +public: + + SharedClipboardWinStreamImpl(SharedClipboardWinDataObject *pParent, PSHCLTRANSFER pTransfer, + const Utf8Str &strPath, PSHCLFSOBJINFO pObjInfo); + virtual ~SharedClipboardWinStreamImpl(void); + +public: /* IUnknown methods. */ + + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + +public: /* IStream methods. */ + + STDMETHOD(Clone)(IStream** ppStream); + STDMETHOD(Commit)(DWORD dwFrags); + STDMETHOD(CopyTo)(IStream* pDestStream, ULARGE_INTEGER nBytesToCopy, ULARGE_INTEGER* nBytesRead, ULARGE_INTEGER* nBytesWritten); + STDMETHOD(LockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes,DWORD dwFlags); + STDMETHOD(Read)(void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead); + STDMETHOD(Revert)(void); + STDMETHOD(Seek)(LARGE_INTEGER nMove, DWORD dwOrigin, ULARGE_INTEGER* nNewPos); + STDMETHOD(SetSize)(ULARGE_INTEGER nNewSize); + STDMETHOD(Stat)(STATSTG* statstg, DWORD dwFlags); + STDMETHOD(UnlockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes, DWORD dwFlags); + STDMETHOD(Write)(const void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead); + +public: /* Own methods. */ + + static HRESULT Create(SharedClipboardWinDataObject *pParent, PSHCLTRANSFER pTransfer, const Utf8Str &strPath, + PSHCLFSOBJINFO pObjInfo, IStream **ppStream); +private: + + /** Pointer to the parent data object. */ + SharedClipboardWinDataObject *m_pParent; + /** The stream object's current reference count. */ + LONG m_lRefCount; + /** Pointer to the associated Shared Clipboard transfer. */ + PSHCLTRANSFER m_pTransfer; + /** The object handle to use. */ + SHCLOBJHANDLE m_hObj; + /** Object path. */ + Utf8Str m_strPath; + /** (Cached) object information. */ + SHCLFSOBJINFO m_objInfo; + /** Number of bytes already processed. */ + uint64_t m_cbProcessed; + /** Whether this object already is in completed state or not. */ + bool m_fIsComplete; +}; + +/** + * Class for Windows-specifics for maintaining a single Shared Clipboard transfer. + * Set as pvUser / cbUser in SHCLTRANSFERCTX. + */ +class SharedClipboardWinTransferCtx +{ +public: + SharedClipboardWinTransferCtx() + : pDataObj(NULL) { } + + virtual ~SharedClipboardWinTransferCtx() + { + if (pDataObj) + delete pDataObj; + } + + /** Pointer to data object to use for this transfer. + * Can be NULL if not being used. */ + SharedClipboardWinDataObject *pDataObj; +}; +# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ +#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_win_h */ + diff --git a/include/VBox/GuestHost/SharedClipboard-x11.h b/include/VBox/GuestHost/SharedClipboard-x11.h new file mode 100644 index 00000000..c06f2dd2 --- /dev/null +++ b/include/VBox/GuestHost/SharedClipboard-x11.h @@ -0,0 +1,187 @@ +/** @file + * Shared Clipboard - Common X11 code. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_x11_h +#define VBOX_INCLUDED_GuestHost_SharedClipboard_x11_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <X11/Intrinsic.h> + +#include <iprt/thread.h> + +#include <VBox/GuestHost/SharedClipboard.h> +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +# include <VBox/GuestHost/SharedClipboard-transfers.h> +#endif + +/** + * The maximum number of simultaneous connections to shared clipboard service. + * This constant limits amount of GUEST -> HOST connections to shared clipboard host service + * for X11 host only. Once amount of connections reaches this number, all the + * further attempts to CONNECT will be dropped on an early stage. Possibility to connect + * is available again after one of existing connections is closed by DISCONNECT call. + */ +#define VBOX_SHARED_CLIPBOARD_X11_CONNECTIONS_MAX (20) + +/** Enables the Xt busy / update handling. */ +#define VBOX_WITH_SHARED_CLIPBOARD_XT_BUSY 1 + +/** + * Enumeration for all clipboard formats which we support on X11. + */ +typedef enum _SHCLX11FMT +{ + SHCLX11FMT_INVALID = 0, + SHCLX11FMT_TARGETS, + SHCLX11FMT_TEXT, /* Treat this as UTF-8, but it may really be ascii */ + SHCLX11FMT_UTF8, + SHCLX11FMT_BMP, + SHCLX11FMT_HTML +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + , SHCLX11FMT_URI_LIST +#endif +} SHCLX11FMT; + +/** + * The table maps X11 names to data formats + * and to the corresponding VBox clipboard formats. + */ +typedef struct SHCLX11FMTTABLE +{ + /** The X11 atom name of the format (several names can match one format). */ + const char *pcszAtom; + /** The format corresponding to the name. */ + SHCLX11FMT enmFmtX11; + /** The corresponding VBox clipboard format. */ + SHCLFORMAT uFmtVBox; +} SHCLX11FMTTABLE; + +#define NIL_CLIPX11FORMAT 0 + +/** Defines an index of the X11 clipboad format table. */ +typedef unsigned SHCLX11FMTIDX; + +/** + * Structure for maintaining a Shared Clipboard context on X11 platforms. + */ +typedef struct _SHCLX11CTX +{ + /** Opaque data structure describing the front-end. */ + PSHCLCONTEXT pFrontend; + /** Our callback table to use. */ + SHCLCALLBACKS Callbacks; + /** Is an X server actually available? */ + bool fHaveX11; + /** The X Toolkit application context structure. */ + XtAppContext pAppContext; + /** We have a separate thread to wait for window and clipboard events. */ + RTTHREAD Thread; + /** Flag indicating that the thread is in a started state. */ + bool fThreadStarted; + /** The X Toolkit widget which we use as our clipboard client. It is never made visible. */ + Widget pWidget; + /** Should we try to grab the clipboard on startup? */ + bool fGrabClipboardOnStart; + /** The best text format X11 has to offer, as an index into the formats table. */ + SHCLX11FMTIDX idxFmtText; + /** The best bitmap format X11 has to offer, as an index into the formats table. */ + SHCLX11FMTIDX idxFmtBmp; + /** The best HTML format X11 has to offer, as an index into the formats table. */ + SHCLX11FMTIDX idxFmtHTML; +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + /** The best HTML format X11 has to offer, as an index into the formats table. */ + SHCLX11FMTIDX idxFmtURI; +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP + /** HTTP transfer context data. */ + SHCLHTTPCONTEXT HttpCtx; +# endif +#endif + /** What kind of formats does VBox have to offer? */ + SHCLFORMATS vboxFormats; + /** Cache of the last unicode data that we received. */ + void *pvUnicodeCache; + /** Size of the unicode data in the cache. */ + uint32_t cbUnicodeCache; + /** When we wish the clipboard to exit, we have to wake up the event + * loop. We do this by writing into a pipe. This end of the pipe is + * the end that another thread can write to. */ + int wakeupPipeWrite; + /** The reader end of the pipe. */ + int wakeupPipeRead; + /** A pointer to the XFixesSelectSelectionInput function. */ + void (*fixesSelectInput)(Display *, Window, Atom, unsigned long); + /** The first XFixes event number. */ + int fixesEventBase; +#ifdef VBOX_WITH_SHARED_CLIPBOARD_XT_BUSY + /** XtGetSelectionValue on some versions of libXt isn't re-entrant + * so block overlapping requests on this flag. */ + bool fXtBusy; + /** If a request is blocked on the previous flag, set this flag to request + * an update later - the first callback should check and clear this flag + * before processing the callback event. */ + bool fXtNeedsUpdate; +#endif +} SHCLX11CTX, *PSHCLX11CTX; + +/** + * Structure for keeping a X11 read data request. + */ +typedef struct _SHCLX11READDATAREQ +{ + /** Actual read request to handle. */ + CLIPREADCBREQ *pReq; + /** Result code of the operation on completion. */ + int rcCompletion; +} SHCLX11READDATAREQ; +/** Pointer to a send data request. */ +typedef SHCLX11READDATAREQ *PSHCLX11READDATAREQ; + +/** @name Shared Clipboard APIs for X11. + * @{ + */ +int ShClX11Init(PSHCLX11CTX pCtx, PSHCLCALLBACKS pCallbacks, PSHCLCONTEXT pParent, bool fHeadless); +void ShClX11Destroy(PSHCLX11CTX pCtx); +int ShClX11ThreadStart(PSHCLX11CTX pCtx, bool grab); +int ShClX11ThreadStartEx(PSHCLX11CTX pCtx, const char *pszName, bool fGrab); +int ShClX11ThreadStop(PSHCLX11CTX pCtx); +int ShClX11ReportFormatsToX11(PSHCLX11CTX pCtx, SHCLFORMATS vboxFormats); +int ShClX11ReadDataFromX11(PSHCLX11CTX pCtx, SHCLFORMATS vboxFormat, CLIPREADCBREQ *pReq); +void ShClX11SetCallbacks(PSHCLX11CTX pCtx, PSHCLCALLBACKS pCallbacks); +/** @} */ + +#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_x11_h */ + diff --git a/include/VBox/GuestHost/SharedClipboard.h b/include/VBox/GuestHost/SharedClipboard.h new file mode 100644 index 00000000..ef61bc6c --- /dev/null +++ b/include/VBox/GuestHost/SharedClipboard.h @@ -0,0 +1,354 @@ +/** @file + * Shared Clipboard - Common guest and host Code. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_h +#define VBOX_INCLUDED_GuestHost_SharedClipboard_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/critsect.h> +#include <iprt/types.h> +#include <iprt/list.h> + +/** @name VBOX_SHCL_FMT_XXX - Data formats (flags) for Shared Clipboard. + * @{ + */ +/** No format set. */ +#define VBOX_SHCL_FMT_NONE 0 +/** Shared Clipboard format is an Unicode text. */ +#define VBOX_SHCL_FMT_UNICODETEXT RT_BIT(0) +/** Shared Clipboard format is bitmap (BMP / DIB). */ +#define VBOX_SHCL_FMT_BITMAP RT_BIT(1) +/** Shared Clipboard format is HTML. */ +#define VBOX_SHCL_FMT_HTML RT_BIT(2) +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +/** Shared Clipboard format is a transfer list. */ +# define VBOX_SHCL_FMT_URI_LIST RT_BIT(3) +#endif +/** @} */ + + +/** A single Shared Clipboard format (VBOX_SHCL_FMT_XXX). */ +typedef uint32_t SHCLFORMAT; +/** Pointer to a single Shared Clipboard format (VBOX_SHCL_FMT_XXX). */ +typedef SHCLFORMAT *PSHCLFORMAT; + +/** Bit map (flags) of Shared Clipboard formats (VBOX_SHCL_FMT_XXX). */ +typedef uint32_t SHCLFORMATS; +/** Pointer to a bit map of Shared Clipboard formats (VBOX_SHCL_FMT_XXX). */ +typedef SHCLFORMATS *PSHCLFORMATS; + + +/** + * Shared Clipboard transfer direction. + */ +typedef enum SHCLTRANSFERDIR +{ + /** Unknown transfer directory. */ + SHCLTRANSFERDIR_UNKNOWN = 0, + /** Read transfer (from source). */ + SHCLTRANSFERDIR_FROM_REMOTE, + /** Write transfer (to target). */ + SHCLTRANSFERDIR_TO_REMOTE, + /** The usual 32-bit hack. */ + SHCLTRANSFERDIR_32BIT_HACK = 0x7fffffff +} SHCLTRANSFERDIR; +/** Pointer to a shared clipboard transfer direction. */ +typedef SHCLTRANSFERDIR *PSHCLTRANSFERDIR; + + +/** + * Shared Clipboard data read request. + */ +typedef struct SHCLDATAREQ +{ + /** In which format the data needs to be sent. */ + SHCLFORMAT uFmt; + /** Read flags; currently unused. */ + uint32_t fFlags; + /** Maximum data (in byte) can be sent. */ + uint32_t cbSize; +} SHCLDATAREQ; +/** Pointer to a shared clipboard data request. */ +typedef SHCLDATAREQ *PSHCLDATAREQ; + +/** + * Shared Clipboard event payload (optional). + */ +typedef struct SHCLEVENTPAYLOAD +{ + /** Payload ID; currently unused. */ + uint32_t uID; + /** Size (in bytes) of actual payload data. */ + uint32_t cbData; + /** Pointer to actual payload data. */ + void *pvData; +} SHCLEVENTPAYLOAD; +/** Pointer to a shared clipboard event payload. */ +typedef SHCLEVENTPAYLOAD *PSHCLEVENTPAYLOAD; + +/** A shared clipboard event source ID. */ +typedef uint16_t SHCLEVENTSOURCEID; +/** Pointer to a shared clipboard event source ID. */ +typedef SHCLEVENTSOURCEID *PSHCLEVENTSOURCEID; + +/** A shared clipboard session ID. */ +typedef uint16_t SHCLSESSIONID; +/** Pointer to a shared clipboard session ID. */ +typedef SHCLSESSIONID *PSHCLSESSIONID; +/** NIL shared clipboard session ID. */ +#define NIL_SHCLSESSIONID UINT16_MAX + +/** A shared clipboard transfer ID. */ +typedef uint16_t SHCLTRANSFERID; +/** Pointer to a shared clipboard transfer ID. */ +typedef SHCLTRANSFERID *PSHCLTRANSFERID; +/** NIL shared clipboardtransfer ID. */ +#define NIL_SHCLTRANSFERID UINT16_MAX + +/** A shared clipboard event ID. */ +typedef uint32_t SHCLEVENTID; +/** Pointer to a shared clipboard event source ID. */ +typedef SHCLEVENTID *PSHCLEVENTID; +/** NIL shared clipboard event ID. */ +#define NIL_SHCLEVENTID UINT32_MAX + +/** Pointer to a shared clipboard event source. + * Forward declaration, needed for SHCLEVENT. */ +typedef struct SHCLEVENTSOURCE *PSHCLEVENTSOURCE; + +/** + * Shared Clipboard event. + */ +typedef struct SHCLEVENT +{ + /** List node. */ + RTLISTNODE Node; + /** Parent (source) this event belongs to. */ + PSHCLEVENTSOURCE pParent; + /** The event's ID, for self-reference. */ + SHCLEVENTID idEvent; + /** Reference count to this event. */ + uint32_t cRefs; + /** Event semaphore for signalling the event. */ + RTSEMEVENTMULTI hEvtMulSem; + /** Payload to this event, optional (NULL). */ + PSHCLEVENTPAYLOAD pPayload; +} SHCLEVENT; +/** Pointer to a shared clipboard event. */ +typedef SHCLEVENT *PSHCLEVENT; + +/** + * Shared Clipboard event source. + * + * Each event source maintains an own counter for events, so that it can be used + * in different contexts. + */ +typedef struct SHCLEVENTSOURCE +{ + /** The event source ID. */ + SHCLEVENTSOURCEID uID; + /** Critical section for serializing access. */ + RTCRITSECT CritSect; + /** Next upcoming event ID. */ + SHCLEVENTID idNextEvent; + /** List of events (PSHCLEVENT). */ + RTLISTANCHOR lstEvents; +} SHCLEVENTSOURCE; + +/** @name Shared Clipboard data payload functions. + * @{ + */ +int ShClPayloadAlloc(uint32_t uID, const void *pvData, uint32_t cbData, PSHCLEVENTPAYLOAD *ppPayload); +void ShClPayloadFree(PSHCLEVENTPAYLOAD pPayload); +/** @} */ + +/** @name Shared Clipboard event source functions. + * @{ + */ +int ShClEventSourceCreate(PSHCLEVENTSOURCE pSource, SHCLEVENTSOURCEID idEvtSrc); +int ShClEventSourceDestroy(PSHCLEVENTSOURCE pSource); +void ShClEventSourceReset(PSHCLEVENTSOURCE pSource); +int ShClEventSourceGenerateAndRegisterEvent(PSHCLEVENTSOURCE pSource, PSHCLEVENT *ppEvent); +PSHCLEVENT ShClEventSourceGetFromId(PSHCLEVENTSOURCE pSource, SHCLEVENTID idEvent); +PSHCLEVENT ShClEventSourceGetLast(PSHCLEVENTSOURCE pSource); +/** @} */ + +/** @name Shared Clipboard event functions. + * @{ + */ +uint32_t ShClEventGetRefs(PSHCLEVENT pEvent); +uint32_t ShClEventRetain(PSHCLEVENT pEvent); +uint32_t ShClEventRelease(PSHCLEVENT pEvent); +int ShClEventSignal(PSHCLEVENT pEvent, PSHCLEVENTPAYLOAD pPayload); +int ShClEventWait(PSHCLEVENT pEvent, RTMSINTERVAL uTimeoutMs, PSHCLEVENTPAYLOAD *ppPayload); +/** @} */ + +/** + * Shared Clipboard transfer source type. + * @note Part of saved state! + */ +typedef enum SHCLSOURCE +{ + /** Invalid source type. */ + SHCLSOURCE_INVALID = 0, + /** Source is local. */ + SHCLSOURCE_LOCAL, + /** Source is remote. */ + SHCLSOURCE_REMOTE, + /** The usual 32-bit hack. */ + SHCLSOURCE_32BIT_HACK = 0x7fffffff +} SHCLSOURCE; + +/** Opaque data structure for the X11/VBox frontend/glue code. + * @{ */ +struct SHCLCONTEXT; +typedef struct SHCLCONTEXT SHCLCONTEXT; +/** @} */ +/** Pointer to opaque data structure the X11/VBox frontend/glue code. */ +typedef SHCLCONTEXT *PSHCLCONTEXT; + +/** + * @name Shared Clipboard callback table. + * + * This table gets used by + * - the backends on the host (where required) + * - guest side implementations (e.g. VBoxClient) + * - by the underlying core code (e.g. X11 backend -> X11 common code -> callback) + * + * Some clipboard mechanisms (e.g. X11) require asynchronous and/or event-driven handling + * of clipboard data, making it hard to control our program flow when testing stuff. + * + * So overriding required callbacks on runtime for testing purposes makes this approach much + * more flexible without implementing separate code paths for production code and test units. + * + * @{ + */ +typedef struct _SHCLCALLBACKS +{ + /** + * Callback for reporting supported clipoard formats of current clipboard data. + * + * @note On X11: + * Runs in Xt event thread for the X11 code. + * + * @returns VBox status code. + * @param pCtx Opaque context pointer for the glue code. + * @param fFormats The formats available. + * @param pvUser Implementation-dependent pointer to data for fullfilling the request. + * Optional and can be NULL. + */ + DECLCALLBACKMEMBER(int, pfnReportFormats, (PSHCLCONTEXT pCtx, SHCLFORMATS fFormats, void *pvUser)); + + /** + * Callback for reading data from the clipboard. + * Optional and can be NULL. + * + * @note Used for testing X11 clipboard code. + * + * @returns VBox status code. + * @param pCtx Opaque context pointer for the glue code. + * @param uFmt The format in which the data should be read + * (VBOX_SHCL_FMT_XXX). + * @param ppv Returns an allocated buffer with data from on success. + * Needs to be free'd with RTMemFree() by the caller. + * @param pcb Returns the amount of data read (in bytes) on success. + * @param pvUser Implementation-dependent pointer to data for fullfilling the request. + * Optional and can be NULL. + */ + DECLCALLBACKMEMBER(int, pfnOnClipboardRead, (PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, size_t *pcb, void *pvUser)); + + /** + * Callback for writing data to the clipboard. + * Optional and can be NULL. + * + * @note Used for testing X11 clipboard code. + * + * @returns VBox status code. + * @param pCtx Opaque context pointer for the glue code. + * @param uFmt The format in which the data should be written as + * (VBOX_SHCL_FMT_XXX). + * @param pv The clipboard data to write. + * @param cb The size of the data in @a pv. + * @param pvUser Implementation-dependent pointer to data for fullfilling the request. + * Optional and can be NULL. + */ + DECLCALLBACKMEMBER(int, pfnOnClipboardWrite, (PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void *pv, size_t cb, void *pvUser)); + + /** + * Callback for requesting clipboard data from the source. + * + * @note On X11: + * The function will be invoked for every single target the clipboard requests. + * Runs in Xt event thread for the X11 code. + * + * @returns VBox status code. VERR_NO_DATA if no data available. + * @param pCtx Opaque context pointer for the glue code. + * @param uFmt The format in which the data should be transferred + * (VBOX_SHCL_FMT_XXX). + * @param ppv Returns an allocated buffer with data read from the guest on success. + * Needs to be free'd with RTMemFree() by the caller. + * @param pcb Returns the amount of data read (in bytes) on success. + * @param pvUser Implementation-dependent pointer to data for fullfilling the request. + * Optional and can be NULL. + * On X11: Of type PSHCLX11READDATAREQ; We RTMemFree() this in this function. + */ + DECLCALLBACKMEMBER(int, pfnOnRequestDataFromSource, (PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser)); + + /** + * Callback for sending clipboard data to the destination. + * + * @returns VBox status code. + * @param pCtx Opaque context pointer for the glue code. + * @param pv The clipboard data returned if the request succeeded. + * @param cb The size of the data in @a pv. + * @param pvUser Implementation-dependent pointer to data for fullfilling the request. + * Optional and can be NUL + * On X11: Of type PSHCLX11READDATAREQ. + */ + DECLCALLBACKMEMBER(int, pfnOnSendDataToDest, (PSHCLCONTEXT pCtx, void *pv, uint32_t cb, void *pvUser)); +} SHCLCALLBACKS; +typedef SHCLCALLBACKS *PSHCLCALLBACKS; +/** @} */ + +/** Opaque request structure for X11 clipboard data. + * @{ */ +struct CLIPREADCBREQ; +typedef struct CLIPREADCBREQ CLIPREADCBREQ; +/** @} */ + +#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_h */ + diff --git a/include/VBox/GuestHost/clipboard-helper.h b/include/VBox/GuestHost/clipboard-helper.h new file mode 100644 index 00000000..e1c4ad9d --- /dev/null +++ b/include/VBox/GuestHost/clipboard-helper.h @@ -0,0 +1,250 @@ +/* $Id: clipboard-helper.h $ */ +/** @file + * Shared Clipboard - Some helper function for converting between the various EOLs. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_clipboard_helper_h +#define VBOX_INCLUDED_GuestHost_clipboard_helper_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/string.h> + +#include <VBox/GuestHost/SharedClipboard.h> + +/** Constants needed for string conversions done by the Linux/Mac clipboard code. */ +enum +{ + /** In Linux, lines end with a linefeed character. */ + VBOX_SHCL_LINEFEED = 0xa, + /** In Windows, lines end with a carriage return and a linefeed character. */ + VBOX_SHCL_CARRIAGERETURN = 0xd, + /** Little endian "real" UTF-16 strings start with this marker. */ + VBOX_SHCL_UTF16LEMARKER = 0xfeff, + /** Big endian "real" UTF-16 strings start with this marker. */ + VBOX_SHCL_UTF16BEMARKER = 0xfffe +}; + +/** + * Returns the length (in UTF-8 characters) of an UTF-16 string with LF EOL. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to return size for. + * @param cwcSrc Length of the string in RTUTF16 units. + * @param pchLen Where to return the length (in UTF-8 characters). + * Does not include terminator. + */ +int ShClUtf16LFLenUtf8(PCRTUTF16 pcwszSrc, size_t cwcSrc, size_t *pchLen); + +/** + * Returns the length (in UTF-8 characters) of an UTF-16 string with CRLF EOL. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to return size for. + * @param cwcSrc Length of the source string in RTUTF16 units. + * @param pchLen Where to return the length (in UTF-8 characters). + * Does not include terminator. + */ +int ShClUtf16CRLFLenUtf8(PCRTUTF16 pcwszSrc, size_t cwcSrc, size_t *pchLen); + +/** + * Returns the length (in characters) of an UTF-16 string, including terminator. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to return size for. + * @param cwcSrc Length of the source string in RTUTF16 units. + * @param pchLen Where to return the length (in UTF-8 characters). + * Does not include terminator. + */ +int ShClUtf16LenUtf8(PCRTUTF16 pcwszSrc, size_t cwcSrc, size_t *pchLen); + +/** + * Converts an UTF-16 string with LF EOL to an UTF-16 string with CRLF EOL. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to convert. + * @param cwcSrc Size of the string int RTUTF16 units. + * @param pwszDst Buffer to store the converted string to. + * @param cwcDst The size of \a pwszDst in RTUTF16 units. + */ +int ShClConvUtf16LFToCRLF(PCRTUTF16 pcwszSrc, size_t cwcSrc, PRTUTF16 pwszDst, size_t cwcDst); + +/** + * Converts an UTF-16 string with LF EOL to an UTF-16 string with CRLF EOL. + * + * Convenience function which returns the allocated + converted string on success. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to convert. + * @param cwcSrc Size of the string int RTUTF16 units. + * @param ppwszDst Where to return the allocated converted string. Must be free'd by the caller. + * @param pcwDst Where to return the size of the converted string in RTUTF16 units. + * Does not include the terminator. + */ +int ShClConvUtf16LFToCRLFA(PCRTUTF16 pcwszSrc, size_t cwcSrc, PRTUTF16 *ppwszDst, size_t *pcwDst); + +/** + * Converts an UTF-16 string with CRLF EOL to an UTF-16 string with LF EOL. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to convert. + * @param cwcSrc Size of the string in RTUTF16 units. + * @param pwszDst Where to store the converted string to. + * @param cwcDst The size of \a pwszDst in RTUTF16 units. + */ +int ShClConvUtf16CRLFToLF(PCRTUTF16 pcwszSrc, size_t cwcSrc, PRTUTF16 pwszDst, size_t cwcDst); + +/** + * Converts an UTF-16 string with CRLF EOL to UTF-8 LF. + * + * @returns VBox status code. Will return VERR_NO_DATA if no data was converted. + * @param pcwszSrc UTF-16 string to convert. + * @param cbSrc Length of @a pwszSrc (in bytes). + * @param pszBuf Where to write the converted string. + * @param cbBuf The size of the buffer pointed to by @a pszBuf. + * @param pcbLen Where to store the size (in bytes) of the converted string. + * Does not include terminator. + */ +int ShClConvUtf16CRLFToUtf8LF(PCRTUTF16 pcwszSrc, size_t cbSrc, char *pszBuf, size_t cbBuf, size_t *pcbLen); + +/** +* Converts an HTML string from UTF-16 into UTF-8. +* +* @returns VBox status code. +* @param pcwszSrc UTF-16 string to convert. +* @param cwcSrc Length (in RTUTF16 units) of the source text. +* @param ppszDst Where to store the converted result on success. +* @param pcbDst Where to store the number of bytes written. +*/ +int ShClConvUtf16ToUtf8HTML(PCRTUTF16 pcwszSrc, size_t cwcSrc, char **ppszDst, size_t *pcbDst); + +/** + * Converts an UTF-8 string with LF EOL into UTF-16 CRLF. + * + * @returns VBox status code. + * @param pcszSrc UTF-8 string to convert. + * @param cbSrc Size of UTF-8 string to convert (in bytes), not counting the terminating zero. + * @param ppwszDst Where to return the allocated buffer on success. + * @param pcwDst Where to return the size (in RTUTF16 units) of the allocated buffer on success. + * Does not include terminator. + */ +int ShClConvUtf8LFToUtf16CRLF(const char *pcszSrc, size_t cbSrc, PRTUTF16 *ppwszDst, size_t *pcwDst); + +/** + * Converts a Latin-1 string with LF EOL into UTF-16 CRLF. + * + * @returns VBox status code. + * @param pcszSrc UTF-8 string to convert. + * @param cbSrc Size of string (in bytes), not counting the terminating zero. + * @param ppwszDst Where to return the allocated buffer on success. + * @param pcwDst Where to return the size (in RTUTF16 units) of the allocated buffer on success. + * Does not include terminator. + */ +int ShClConvLatin1LFToUtf16CRLF(const char *pcszSrc, size_t cbSrc, PRTUTF16 *ppwszDst, size_t *pcwDst); + +/** + * Convert CF_DIB data to full BMP data by prepending the BM header. + * Allocates with RTMemAlloc. + * + * @returns VBox status code. + * @param pvSrc DIB data to convert + * @param cbSrc Size of the DIB data to convert in bytes + * @param ppvDst Where to store the pointer to the buffer for the + * destination data + * @param pcbDst Pointer to the size of the buffer for the destination + * data in bytes. + */ +int ShClDibToBmp(const void *pvSrc, size_t cbSrc, void **ppvDst, size_t *pcbDst); + +/** + * Get the address and size of CF_DIB data in a full BMP data in the input buffer. + * Does not do any allocation. + * + * @returns VBox status code. + * @param pvSrc BMP data to convert + * @param cbSrc Size of the BMP data to convert in bytes + * @param ppvDst Where to store the pointer to the destination data + * @param pcbDst Pointer to the size of the destination data in bytes + */ +int ShClBmpGetDib(const void *pvSrc, size_t cbSrc, const void **ppvDst, size_t *pcbDst); + +#ifdef LOG_ENABLED +/** + * Dumps HTML data to the debug log. + * + * @returns VBox status code. + * @param pszSrc HTML data to dump. + * @param cbSrc Size (in bytes) of HTML data to dump. + */ +int ShClDbgDumpHtml(const char *pszSrc, size_t cbSrc); + +/** + * Dumps data using a specified clipboard format. + * + * @param pv Pointer to data to dump. + * @param cb Size (in bytes) of data to dump. + * @param u32Format Clipboard format to use for dumping. + */ +void ShClDbgDumpData(const void *pv, size_t cb, SHCLFORMAT u32Format); +#endif /* LOG_ENABLED */ + +/** + * Translates a Shared Clipboard host function number to a string. + * + * @returns Function ID string name. + * @param uFn The function to translate. + */ +const char *ShClHostFunctionToStr(uint32_t uFn); + +/** + * Translates a Shared Clipboard host message enum to a string. + * + * @returns Message ID string name. + * @param uMsg The message to translate. + */ +const char *ShClHostMsgToStr(uint32_t uMsg); + +/** + * Translates a Shared Clipboard guest message enum to a string. + * + * @returns Message ID string name. + * @param uMsg The message to translate. + */ +const char *ShClGuestMsgToStr(uint32_t uMsg); + +char *ShClFormatsToStrA(SHCLFORMATS fFormats); + +#endif /* !VBOX_INCLUDED_GuestHost_clipboard_helper_h */ + diff --git a/include/VBox/HostServices/DragAndDropSvc.h b/include/VBox/HostServices/DragAndDropSvc.h new file mode 100644 index 00000000..ba42cdef --- /dev/null +++ b/include/VBox/HostServices/DragAndDropSvc.h @@ -0,0 +1,1198 @@ +/* $Id: DragAndDropSvc.h $ */ +/** @file + * Drag and Drop service - Common header for host service and guest clients. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +/** + * Protocol handling and notes: + * All client/server components should be backwards compatible. + * + ****************************************************************************** + * + * Protocol changelog: + * + * Protocol v1 (VBox < 5.0, deprecated): + * | Initial implementation which only implemented host to guest transfers. + * | For file transfers all file information such as the file name and file size were + * transferred with every file data chunk being sent. + * + * Protocol v2 (VBox 5.0 - VBox 5.0.8, deprecated): + * + Added support for guest to host transfers. + * + Added protocol version support through VBOXDNDCONNECTMSG. The host takes the installed + * Guest Additions version as indicator which protocol to use for communicating with the guest. + * The guest itself uses VBOXDNDCONNECTMSG to report its supported protocol version to the DnD service. + * + * Protocol v3 (VBox 5.0.10 and up, deprecated): + * + Added VBOXDNDDISCONNECTMSG for being able to track client disconnects on host side (Main). + * + Added context IDs for every HGCM message. Not used yet and must be 0. + * + Added VBOXDNDSNDDATAHDR and VBOXDNDCBSNDDATAHDRDATA to support (simple) accounting of objects + * being transferred, along with supplying separate meta data size (which is part of the total size being sent). + * + Added new HOST_DND_FN_HG_SND_DATA_HDR + GUEST_DND_FN_GH_SND_DATA_HDR commands which now allow specifying an optional + * compression type and defining a checksum for the overall data transfer. + * + Enhannced VBOXDNDGHSENDDATAMSG to support (rolling) checksums for the supplied data block. + * + VBOXDNDHGSENDDATAMSG and VBOXDNDGHSENDDATAMSG can now contain an optional checksum for the current data block. + * | VBOXDNDHGSENDFILEDATAMSG and VBOXDNDGHSENDFILEDATAMSG are now sharing the same HGCM mesasge. + * - Removed unused HOST_DND_FN_GH_RECV_DIR, HOST_DND_FN_GH_RECV_FILE_DATA and HOST_DND_FN_GH_RECV_FILE_HDR commands. + * + * VBox 6.1.x and up, current: + * + Added GUEST_DND_FN_QUERY_FEATURES + GUEST_DND_FN_REPORT_FEATURES. + * - Protocol versioning support in VBOXDNDCONNECTMSG is now marked as being deprecated. + * + ** @todo: + * - Split up messages which use VBOXDNDHGACTIONMSG into own functions and remove parameters which + * are not actually needed / used by a function. Why does HOST_DND_FN_HG_EVT_MOVE need all the format stuff, for example? + */ + +#ifndef VBOX_INCLUDED_HostServices_DragAndDropSvc_h +#define VBOX_INCLUDED_HostServices_DragAndDropSvc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/hgcmsvc.h> +#include <VBox/VMMDevCoreTypes.h> +#include <VBox/VBoxGuestCoreTypes.h> + +#include <VBox/GuestHost/DragAndDropDefs.h> + +namespace DragAndDropSvc { + +/****************************************************************************** +* Typedefs, constants and inlines * +******************************************************************************/ + +/** + * The service functions which are callable by host. + * Note: When adding new functions to this table, make sure that the actual ID + * does *not* overlap with the eGuestFn enumeration below! + */ +enum eHostFn +{ + /** The host sets a new DnD mode. */ + HOST_DND_FN_SET_MODE = 100, + /** The host requests to cancel the current DnD operation on + * the guest side. This can happen on user request on the host's + * UI side or due to some host error which has happened. + * + * Note: This is a fire-and-forget message, as the host should + * not rely on an answer from the guest side in order to + * properly cancel the operation. */ + HOST_DND_FN_CANCEL = 204, + + /* + * Host -> Guest messages + */ + + /** The host enters the VM window for starting an actual + * DnD operation. */ + HOST_DND_FN_HG_EVT_ENTER = 200, + /** The host's DnD cursor moves within the VM window. */ + HOST_DND_FN_HG_EVT_MOVE = 201, + /** The host leaves the guest VM window. */ + HOST_DND_FN_HG_EVT_LEAVE = 202, + /** The host issues a "drop" event, meaning that the host is + * ready to transfer data over to the guest. */ + HOST_DND_FN_HG_EVT_DROPPED = 203, + /** The host sends the data header at the beginning of a (new) + * data transfer. */ + HOST_DND_FN_HG_SND_DATA_HDR = 210, + /** + * The host sends the actual meta data, based on + * the format(s) specified by HOST_DND_FN_HG_EVT_ENTER. + * + * Protocol v1/v2: If the guest supplied buffer too small to send + * the actual data, the host will send a HOST_DND_FN_HG_SND_MORE_DATA + * message as follow-up. + * Protocol v3+: The incoming meta data size is specified upfront in the + * HOST_DND_FN_HG_SND_DATA_HDR message and must be handled accordingly. + */ + HOST_DND_FN_HG_SND_DATA = 205, + /** The host sends more data in case the data did not entirely fit in + * the HOST_DND_FN_HG_SND_DATA message. */ + /** @todo Deprecated function; do not use anymore. */ + HOST_DND_FN_HG_SND_MORE_DATA = 206, + /** The host sends a directory entry to the guest. */ + HOST_DND_FN_HG_SND_DIR = 207, + /** The host sends a file data chunk to the guest. */ + HOST_DND_FN_HG_SND_FILE_DATA = 208, + /** The host sends a file header to the guest. + * Note: Only for protocol version 2 and up (>= VBox 5.0). */ + HOST_DND_FN_HG_SND_FILE_HDR = 209, + + /* + * Guest -> Host messages + */ + + /** The host asks the guest whether a DnD operation + * is in progress when the mouse leaves the guest window. */ + HOST_DND_FN_GH_REQ_PENDING = 600, + /** The host informs the guest that a DnD drop operation + * has been started and that the host wants the data in + * a specific MIME type. */ + HOST_DND_FN_GH_EVT_DROPPED = 601, + /** Blow the type up to 32-bit. */ + HOST_DND_FN_32BIT_HACK = 0x7fffffff +}; + +/** + * The service functions which are called by guest. + * Note: When adding new functions to this table, make sure that the actual ID + * does *not* overlap with the eHostFn enumeration above! + */ +enum eGuestFn +{ + /** + * The guest sends a connection request to the HGCM service, + * along with some additional information like supported + * protocol version and flags. + * Note: New since protocol version 2. */ + GUEST_DND_FN_CONNECT = 10, + + /** The guest client disconnects from the HGCM service. */ + GUEST_DND_FN_DISCONNECT = 11, + + /** Report guest side feature flags and retrieve the host ones. + * + * Two 64-bit parameters are passed in from the guest with the guest features + * (VBOX_DND_GF_XXX), the host replies by replacing the parameter values with + * the host ones (VBOX_DND_HF_XXX). + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ + GUEST_DND_FN_REPORT_FEATURES = 12, + + /** Query the host ones feature masks. + * + * That way the guest (client) can get hold of the features from the host. + * Again, it is prudent to set the 127 bit and observe it being cleared on + * success, as older hosts might return success without doing anything. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ + GUEST_DND_FN_QUERY_FEATURES = 13, + + /** + * The guest waits for a new message the host wants to process + * on the guest side. This can be a blocking call. + */ + GUEST_DND_FN_GET_NEXT_HOST_MSG = 300, + + /** Reports back an error to the host. + * + * Note: Don't change the ID to also support older hosts + * (was GUEST_DND_FN_GH_EVT_ERROR before < 7.0, only for G->H transfers). + * + * This was changed to GUEST_DND_FN_EVT_ERROR to be a generic event + * that also can be used for H->G transfers. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 7.0.x + */ + GUEST_DND_FN_EVT_ERROR = 502, + + /* + * Host -> Guest operation messages. + */ + + /** The guest acknowledges that a pending DnD operation from the host + * can be dropped on the currently selected area on the guest. */ + GUEST_DND_FN_HG_ACK_OP = 400, + /** The guest requests the actual DnD data to be sent from the host. */ + GUEST_DND_FN_HG_REQ_DATA = 401, + /** The guest reports back its progress back to the host. */ + GUEST_DND_FN_HG_EVT_PROGRESS = 402, + + /* + * Guest -> Host operation messages. + */ + + /** + * The guests acknowledges that it currently has a drag'n drop + * operation in progress on the guest, which eventually could be + * dragged over to the host. + */ + GUEST_DND_FN_GH_ACK_PENDING = 500, + /** The guest sends the data header at the beginning of a (new) + * data transfer. */ + GUEST_DND_FN_GH_SND_DATA_HDR = 503, + /** + * The guest sends data of the requested format to the host. There can + * be more than one message if the actual data does not fit + * into one. + */ + GUEST_DND_FN_GH_SND_DATA = 501, + /** The guest sends a directory entry to the host. */ + GUEST_DND_FN_GH_SND_DIR = 700, + /** The guest sends file data to the host. + * Note: On protocol version 1 this also contains the file name + * and other attributes. */ + GUEST_DND_FN_GH_SND_FILE_DATA = 701, + /** The guest sends a file header to the host, marking the + * beginning of a (new) file transfer. + * Note: Available since protocol version 2 (VBox 5.0). */ + GUEST_DND_FN_GH_SND_FILE_HDR = 702, + /** Blow the type up to 32-bit. */ + GUEST_DND_FN_32BIT_HACK = 0x7fffffff +}; + +/** @name VBOX_DND_GF_XXX - Guest features. + * @sa GUEST_DND_FN_REPORT_FEATURES + * @{ */ +/** No flags set. */ +#define VBOX_DND_GF_NONE 0 +/** Bit that must be set in the 2nd parameter, will be cleared if the host reponds + * correctly (old hosts might not). */ +#define VBOX_DND_GF_1_MUST_BE_ONE RT_BIT_64(63) +/** @} */ + +/** @name VBOX_DND_HF_XXX - Host features. + * @sa DND_GUEST_REPORT_FEATURES + * @{ */ +/** No flags set. */ +#define VBOX_DND_HF_NONE 0 +/** @} */ + +/** + * DnD operation progress states. + */ +typedef enum DNDPROGRESS +{ + DND_PROGRESS_UNKNOWN = 0, + DND_PROGRESS_RUNNING = 1, + DND_PROGRESS_COMPLETE, + DND_PROGRESS_CANCELLED, + DND_PROGRESS_ERROR, + /** Blow the type up to 32-bit. */ + DND_PROGRESS_32BIT_HACK = 0x7fffffff +} DNDPROGRESS, *PDNDPROGRESS; + +#pragma pack (1) + +/* + * Host events + */ + +/** + * Action message for telling the guest about the currently ongoing + * drag and drop action when entering the guest's area, moving around in it + * and dropping content into it from the host. + * + * Used by: + * HOST_DND_FN_HG_EVT_ENTER + * HOST_DND_FN_HG_EVT_MOVE + * HOST_DND_FN_HG_EVT_DROPPED + */ +typedef struct HGCMMsgHGAction +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + HGCMFunctionParameter uScreenId; /* OUT uint32_t */ + HGCMFunctionParameter uX; /* OUT uint32_t */ + HGCMFunctionParameter uY; /* OUT uint32_t */ + HGCMFunctionParameter uDefAction; /* OUT uint32_t */ + HGCMFunctionParameter uAllActions; /* OUT uint32_t */ + HGCMFunctionParameter pvFormats; /* OUT ptr */ + HGCMFunctionParameter cbFormats; /* OUT uint32_t */ + } v1; + struct + { + /** Context ID. */ + HGCMFunctionParameter uContext; + HGCMFunctionParameter uScreenId; /* OUT uint32_t */ + HGCMFunctionParameter uX; /* OUT uint32_t */ + HGCMFunctionParameter uY; /* OUT uint32_t */ + HGCMFunctionParameter uDefAction; /* OUT uint32_t */ + HGCMFunctionParameter uAllActions; /* OUT uint32_t */ + HGCMFunctionParameter pvFormats; /* OUT ptr */ + HGCMFunctionParameter cbFormats; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgHGAction; + +/** + * Tells the guest that the host has left its drag and drop area on the guest. + * + * Used by: + * HOST_DND_FN_HG_EVT_LEAVE + */ +typedef struct HGCMMsgHGLeave +{ + VBGLIOCHGCMCALL hdr; + union + { + struct + { + /** Context ID. */ + HGCMFunctionParameter uContext; + } v3; + } u; +} HGCMMsgHGLeave; + +/** + * Tells the guest that the host wants to cancel the current drag and drop operation. + * + * Used by: + * HOST_DND_FN_HG_EVT_CANCEL + */ +typedef struct HGCMMsgHGCancel +{ + VBGLIOCHGCMCALL hdr; + union + { + struct + { + /** Context ID. */ + HGCMFunctionParameter uContext; + } v3; + } u; +} HGCMMsgHGCancel; + +/** + * Sends the header of an incoming (meta) data block. + * + * Used by: + * HOST_DND_FN_HG_SND_DATA_HDR + * GUEST_DND_FN_GH_SND_DATA_HDR + * + * New since protocol v3. + */ +typedef struct HGCMMsgHGSendDataHdr +{ + VBGLIOCHGCMCALL hdr; + + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Data transfer flags. Not yet used and must be 0. */ + HGCMFunctionParameter uFlags; /* OUT uint32_t */ + /** Screen ID where the data originates from. */ + HGCMFunctionParameter uScreenId; /* OUT uint32_t */ + /** Total size (in bytes) to transfer. */ + HGCMFunctionParameter cbTotal; /* OUT uint64_t */ + /** + * Total meta data size (in bytes) to transfer. + * This size also is part of cbTotal already, so: + * + * cbTotal = cbMeta + additional size for files etc. + */ + HGCMFunctionParameter cbMeta; /* OUT uint64_t */ + /** Meta data format. */ + HGCMFunctionParameter pvMetaFmt; /* OUT ptr */ + /** Size (in bytes) of meta data format. */ + HGCMFunctionParameter cbMetaFmt; /* OUT uint32_t */ + /* Number of objects (files/directories) to transfer. */ + HGCMFunctionParameter cObjects; /* OUT uint64_t */ + /** Compression type. */ + HGCMFunctionParameter enmCompression; /* OUT uint32_t */ + /** Checksum type. */ + HGCMFunctionParameter enmChecksumType; /* OUT uint32_t */ + /** Checksum buffer for the entire data to be transferred. */ + HGCMFunctionParameter pvChecksum; /* OUT ptr */ + /** Size (in bytes) of checksum. */ + HGCMFunctionParameter cbChecksum; /* OUT uint32_t */ +} HGCMMsgHGSendDataHdr; + +/** + * Sends a (meta) data block to the guest. + * + * Used by: + * HOST_DND_FN_HG_SND_DATA + */ +typedef struct HGCMMsgHGSendData +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + HGCMFunctionParameter uScreenId; /* OUT uint32_t */ + HGCMFunctionParameter pvFormat; /* OUT ptr */ + HGCMFunctionParameter cbFormat; /* OUT uint32_t */ + HGCMFunctionParameter pvData; /* OUT ptr */ + HGCMFunctionParameter cbData; /* OUT uint32_t */ + } v1; + /* No changes in v2. */ + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Data block to send. */ + HGCMFunctionParameter pvData; /* OUT ptr */ + /** Size (in bytes) of data block to send. */ + HGCMFunctionParameter cbData; /* OUT uint32_t */ + /** Checksum of data block, based on the checksum + * type in the data header. Optional. */ + HGCMFunctionParameter pvChecksum; /* OUT ptr */ + /** Size (in bytes) of checksum to send. */ + HGCMFunctionParameter cbChecksum; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgHGSendData; + +/** + * Sends more (meta) data in case the data didn't fit + * into the current XXX_DND_HG_SND_DATA message. + * + ** @todo Deprecated since protocol v3. Don't use! Will be removed. + * + * Used by: + * HOST_DND_FN_HG_SND_MORE_DATA + */ +typedef struct HGCMMsgHGSendMoreData +{ + VBGLIOCHGCMCALL hdr; + + HGCMFunctionParameter pvData; /* OUT ptr */ + HGCMFunctionParameter cbData; /* OUT uint32_t */ +} HGCMMsgHGSendMoreData; + +/** + * Directory entry event. + * + * Used by: + * HOST_DND_FN_HG_SND_DIR + * GUEST_DND_FN_GH_SND_DIR + */ +typedef struct HGCMMsgHGSendDir +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + /** Directory name. */ + HGCMFunctionParameter pvName; /* OUT ptr */ + /** Size (in bytes) of directory name. */ + HGCMFunctionParameter cbName; /* OUT uint32_t */ + /** Directory mode. */ + HGCMFunctionParameter fMode; /* OUT uint32_t */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Directory name. */ + HGCMFunctionParameter pvName; /* OUT ptr */ + /** Size (in bytes) of directory name. */ + HGCMFunctionParameter cbName; /* OUT uint32_t */ + /** Directory mode. */ + HGCMFunctionParameter fMode; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgHGSendDir; + +/** + * File header message, marking the start of transferring a new file. + * Note: Only for protocol version 2 and up. + * + * Used by: + * HOST_DND_FN_HG_SND_FILE_HDR + * GUEST_DND_FN_GH_SND_FILE_HDR + */ +typedef struct HGCMMsgHGSendFileHdr +{ + VBGLIOCHGCMCALL hdr; + + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** File path. */ + HGCMFunctionParameter pvName; /* OUT ptr */ + /** Size (in bytes) of file path. */ + HGCMFunctionParameter cbName; /* OUT uint32_t */ + /** Optional flags; unused at the moment. */ + HGCMFunctionParameter uFlags; /* OUT uint32_t */ + /** File creation mode. */ + HGCMFunctionParameter fMode; /* OUT uint32_t */ + /** Total size (in bytes). */ + HGCMFunctionParameter cbTotal; /* OUT uint64_t */ +} HGCMMsgHGSendFileHdr; + +/** + * HG: File data (chunk) event. + * + * Used by: + * HOST_DND_FN_HG_SND_FILE + */ +typedef struct HGCMMsgHGSendFileData +{ + VBGLIOCHGCMCALL hdr; + + union + { + /* Note: Protocol v1 sends the file name + file mode + * every time a file data chunk is being sent. */ + struct + { + /** File name. */ + HGCMFunctionParameter pvName; /* OUT ptr */ + /** Size (in bytes) of file name. */ + HGCMFunctionParameter cbName; /* OUT uint32_t */ + /** Current data chunk. */ + HGCMFunctionParameter pvData; /* OUT ptr */ + /** Size (in bytes) of current data chunk. */ + HGCMFunctionParameter cbData; /* OUT uint32_t */ + /** File mode. */ + HGCMFunctionParameter fMode; /* OUT uint32_t */ + } v1; + struct + { + /** Note: pvName is now part of the VBOXDNDHGSENDFILEHDRMSG message. */ + /** Note: cbName is now part of the VBOXDNDHGSENDFILEHDRMSG message. */ + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Current data chunk. */ + HGCMFunctionParameter pvData; /* OUT ptr */ + /** Size (in bytes) of current data chunk. */ + HGCMFunctionParameter cbData; /* OUT uint32_t */ + /** Note: fMode is now part of the VBOXDNDHGSENDFILEHDRMSG message. */ + } v2; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Current data chunk. */ + HGCMFunctionParameter pvData; /* OUT ptr */ + /** Size (in bytes) of current data chunk. */ + HGCMFunctionParameter cbData; /* OUT uint32_t */ + /** Checksum of data block, based on the checksum + * type in the data header. Optional. */ + HGCMFunctionParameter pvChecksum; /* OUT ptr */ + /** Size (in bytes) of curren data chunk checksum. */ + HGCMFunctionParameter cbChecksum; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgHGSendFileData; + +/** + * Asks the guest if a guest->host DnD operation is in progress. + * + * Used by: + * HOST_DND_FN_GH_REQ_PENDING + */ +typedef struct HGCMMsgGHReqPending +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + /** Screen ID. */ + HGCMFunctionParameter uScreenId; /* OUT uint32_t */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Screen ID. */ + HGCMFunctionParameter uScreenId; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgGHReqPending; + +/** + * Tells the guest that the host has dropped the ongoing guest->host + * DnD operation on a valid target on the host. + * + * Used by: + * HOST_DND_FN_GH_EVT_DROPPED + */ +typedef struct HGCMMsgGHDropped +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + /** Requested format for sending the data. */ + HGCMFunctionParameter pvFormat; /* OUT ptr */ + /** Size (in bytes) of requested format. */ + HGCMFunctionParameter cbFormat; /* OUT uint32_t */ + /** Drop action peformed on the host. */ + HGCMFunctionParameter uAction; /* OUT uint32_t */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Requested format for sending the data. */ + HGCMFunctionParameter pvFormat; /* OUT ptr */ + /** Size (in bytes) of requested format. */ + HGCMFunctionParameter cbFormat; /* OUT uint32_t */ + /** Drop action peformed on the host. */ + HGCMFunctionParameter uAction; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgGHDropped; + +/* + * Guest events + */ + +/** + * Asks the host for the next command to process, along + * with the needed amount of parameters and an optional blocking + * flag. + * + * Used by: + * GUEST_DND_FN_GET_NEXT_HOST_MSG + */ +typedef struct HGCMMsgGetNext +{ + VBGLIOCHGCMCALL hdr; + + /** Message ID. */ + HGCMFunctionParameter uMsg; /* OUT uint32_t */ + /** Number of parameters the message needs. */ + HGCMFunctionParameter cParms; /* OUT uint32_t */ + /** Whether or not to block (wait) for a + * new message to arrive. */ + HGCMFunctionParameter fBlock; /* OUT uint32_t */ +} HGCMMsgGetNext; + +/** + * Guest connection request. Used to tell the DnD protocol + * version to the (host) service. + * + * Used by: + * GUEST_DND_FN_CONNECT + */ +typedef struct HGCMMsgConnect +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + /** Protocol version to use. + * Deprecated since VBox 6.1.x. Do not use / rely on it anymore. */ + HGCMFunctionParameter uProtocol; /* OUT uint32_t */ + /** Connection flags. Optional. */ + HGCMFunctionParameter uFlags; /* OUT uint32_t */ + } v2; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Protocol version to use. + * Deprecated since VBox 6.1.x. Do not use / rely on it anymore. */ + HGCMFunctionParameter uProtocol; /* OUT uint32_t */ + /** Connection flags. Optional. */ + HGCMFunctionParameter uFlags; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgConnect; + +/** + * Acknowledges a host operation along with the allowed + * action(s) on the guest. + * + * Used by: + * GUEST_DND_FN_HG_ACK_OP + */ +typedef struct HGCMMsgHGAck +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + HGCMFunctionParameter uAction; /* OUT uint32_t */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + HGCMFunctionParameter uAction; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgHGAck; + +/** + * Requests data to be sent to the guest. + * + * Used by: + * GUEST_DND_FN_HG_REQ_DATA + */ +typedef struct HGCMMsgHGReqData +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + HGCMFunctionParameter pvFormat; /* OUT ptr */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + HGCMFunctionParameter pvFormat; /* OUT ptr */ + HGCMFunctionParameter cbFormat; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgHGReqData; + +typedef struct HGCMMsgHGProgress +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + HGCMFunctionParameter uStatus; /* OUT uint32_t */ + HGCMFunctionParameter uPercent; /* OUT uint32_t */ + HGCMFunctionParameter rc; /* OUT uint32_t */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + HGCMFunctionParameter uStatus; /* OUT uint32_t */ + HGCMFunctionParameter uPercent; /* OUT uint32_t */ + HGCMFunctionParameter rc; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgHGProgress; + +/** + * Acknowledges a pending guest drag and drop event to the host. + * + * Used by: + * GUEST_DND_FN_GH_ACK_PENDING + */ +typedef struct HGCMMsgGHAckPending +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + HGCMFunctionParameter uDefAction; /* OUT uint32_t */ + HGCMFunctionParameter uAllActions; /* OUT uint32_t */ + HGCMFunctionParameter pvFormats; /* OUT ptr */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + HGCMFunctionParameter uDefAction; /* OUT uint32_t */ + HGCMFunctionParameter uAllActions; /* OUT uint32_t */ + HGCMFunctionParameter pvFormats; /* OUT ptr */ + HGCMFunctionParameter cbFormats; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgGHAckPending; + +/** + * Sends the header of an incoming data block + * to the host. + * + * Used by: + * GUEST_DND_FN_GH_SND_DATA_HDR + * + * New since protocol v3. + */ +typedef struct HGCMMsgHGSendDataHdr HGCMMsgGHSendDataHdr; + +/** + * Sends a (meta) data block to the host. + * + * Used by: + * GUEST_DND_FN_GH_SND_DATA + */ +typedef struct HGCMMsgGHSendData +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + HGCMFunctionParameter pvData; /* OUT ptr */ + /** Total bytes to send. This can be more than + * the data block specified in pvData above, e.g. + * when sending over file objects afterwards. */ + HGCMFunctionParameter cbTotalBytes; /* OUT uint32_t */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Data block to send. */ + HGCMFunctionParameter pvData; /* OUT ptr */ + /** Size (in bytes) of data block to send. */ + HGCMFunctionParameter cbData; /* OUT uint32_t */ + /** (Rolling) Checksum, based on checksum type in data header. */ + HGCMFunctionParameter pvChecksum; /* OUT ptr */ + /** Size (in bytes) of checksum. */ + HGCMFunctionParameter cbChecksum; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgGHSendData; + +/** + * Sends a directory entry to the host. + * + * Used by: + * GUEST_DND_FN_GH_SND_DIR + */ +typedef struct HGCMMsgHGSendDir HGCMMsgGHSendDir; + +/** + * Sends a file header to the host. + * + * Used by: + * GUEST_DND_FN_GH_SND_FILE_HDR + * + * New since protocol v2. + */ +typedef struct HGCMMsgHGSendFileHdr HGCMMsgGHSendFileHdr; + +/** + * Sends file data to the host. + * + * Used by: + * GUEST_DND_FN_GH_SND_FILE_DATA + */ +typedef struct HGCMMsgHGSendFileData HGCMMsgGHSendFileData; + +/** + * Sends a guest error event to the host. + * + * Used by: + * GUEST_DND_FN_GH_EVT_ERROR + */ +typedef struct HGCMMsgGHError +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + HGCMFunctionParameter rc; /* OUT uint32_t */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + HGCMFunctionParameter rc; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgGHError; + +#pragma pack() + +/** Builds a callback magic out of the function ID and the version + * of the callback data. */ +#define VBOX_DND_CB_MAGIC_MAKE(uFn, uVer) \ + RT_MAKE_U32(uVer, uFn) + +/* + * Callback magics. + */ +enum eDnDCallbackMagics +{ + CB_MAGIC_DND_CONNECT = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_CONNECT, 0), + CB_MAGIC_DND_REPORT_FEATURES = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_REPORT_FEATURES, 0), + CB_MAGIC_DND_EVT_ERROR = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_EVT_ERROR, 0), + CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_GET_NEXT_HOST_MSG, 0), + CB_MAGIC_DND_HG_ACK_OP = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_HG_ACK_OP, 0), + CB_MAGIC_DND_HG_REQ_DATA = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_HG_REQ_DATA, 0), + CB_MAGIC_DND_HG_EVT_PROGRESS = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_HG_EVT_PROGRESS, 0), + CB_MAGIC_DND_GH_ACK_PENDING = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_GH_ACK_PENDING, 0), + CB_MAGIC_DND_GH_SND_DATA = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_GH_SND_DATA, 0), + CB_MAGIC_DND_GH_SND_DATA_HDR = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_GH_SND_DATA_HDR, 0), + CB_MAGIC_DND_GH_SND_DIR = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_GH_SND_DIR, 0), + CB_MAGIC_DND_GH_SND_FILE_HDR = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_GH_SND_FILE_HDR, 0), + CB_MAGIC_DND_GH_SND_FILE_DATA = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_GH_SND_FILE_DATA, 0) +}; + +typedef struct VBOXDNDCBHEADERDATA +{ + /** Magic number to identify the structure. */ + uint32_t uMagic; + /** Context ID to identify callback data. */ + uint32_t uContextID; +} VBOXDNDCBHEADERDATA, *PVBOXDNDCBHEADERDATA; + +typedef struct VBOXDNDCBCONNECTDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + /** Protocol version to use. + * Deprecated since VBox 6.1.x. Do not use / rely on it anymore. */ + uint32_t uProtocolVersion; + /** Connection flags; currently unused. */ + uint32_t fFlags; +} VBOXDNDCBCONNECTDATA, *PVBOXDNDCBCONNECTDATA; + +typedef struct VBOXDNDCBREPORTFEATURESDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + uint32_t fGuestFeatures0; +} VBOXDNDCBREPORTFEATURESDATA, *PVBOXDNDCBREPORTFEATURESDATA; + +typedef struct VBOXDNDCBDISCONNECTMSGDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; +} VBOXDNDCBDISCONNECTMSGDATA, *PVBOXDNDCBDISCONNECTMSGDATA; + +typedef struct VBOXDNDCBHGGETNEXTHOSTMSG +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + uint32_t uMsg; + uint32_t cParms; +} VBOXDNDCBHGGETNEXTHOSTMSG, *PVBOXDNDCBHGGETNEXTHOSTMSG; + +typedef struct VBOXDNDCBHGGETNEXTHOSTMSGDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + uint32_t uMsg; + uint32_t cParms; + PVBOXHGCMSVCPARM paParms; +} VBOXDNDCBHGGETNEXTHOSTMSGDATA, *PVBOXDNDCBHGGETNEXTHOSTMSGDATA; + +typedef struct VBOXDNDCBHGACKOPDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + uint32_t uAction; +} VBOXDNDCBHGACKOPDATA, *PVBOXDNDCBHGACKOPDATA; + +typedef struct VBOXDNDCBHGREQDATADATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + char *pszFormat; + uint32_t cbFormat; +} VBOXDNDCBHGREQDATADATA, *PVBOXDNDCBHGREQDATADATA; + +typedef struct VBOXDNDCBHGEVTPROGRESSDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + uint32_t uPercentage; + uint32_t uStatus; + uint32_t rc; +} VBOXDNDCBHGEVTPROGRESSDATA, *PVBOXDNDCBHGEVTPROGRESSDATA; + +typedef struct VBOXDNDCBGHACKPENDINGDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + uint32_t uDefAction; + uint32_t uAllActions; + char *pszFormat; + uint32_t cbFormat; +} VBOXDNDCBGHACKPENDINGDATA, *PVBOXDNDCBGHACKPENDINGDATA; + +/** + * Data header. + * New since protocol v3. + */ +typedef struct VBOXDNDDATAHDR +{ + /** Data transfer flags. Not yet used and must be 0. */ + uint32_t uFlags; + /** Screen ID where the data originates from. */ + uint32_t uScreenId; + /** Total size (in bytes) to transfer. */ + uint64_t cbTotal; + /** Meta data size (in bytes) to transfer. + * This size also is part of cbTotal already. */ + uint32_t cbMeta; + /** Meta format buffer. */ + void *pvMetaFmt; + /** Size (in bytes) of meta format buffer. */ + uint32_t cbMetaFmt; + /** Number of objects (files/directories) to transfer. */ + uint64_t cObjects; + /** Compression type. Currently unused, so specify 0. + **@todo Add IPRT compression type enumeration as soon as it's available. */ + uint32_t enmCompression; + /** Checksum type. Currently unused, so specify RTDIGESTTYPE_INVALID. */ + RTDIGESTTYPE enmChecksumType; + /** The actual checksum buffer for the entire data to be transferred, + * based on enmChksumType. If RTDIGESTTYPE_INVALID is specified, + * no checksum is being used and pvChecksum will be NULL. */ + void *pvChecksum; + /** Size (in bytes) of checksum. */ + uint32_t cbChecksum; +} VBOXDNDDATAHDR, *PVBOXDNDSNDDATAHDR; + +/* New since protocol v3. */ +typedef struct VBOXDNDCBSNDDATAHDRDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + /** Actual header data. */ + VBOXDNDDATAHDR data; +} VBOXDNDCBSNDDATAHDRDATA, *PVBOXDNDCBSNDDATAHDRDATA; + +typedef struct VBOXDNDSNDDATA +{ + union + { + struct + { + /** Data block buffer. */ + void *pvData; + /** Size (in bytes) of data block. */ + uint32_t cbData; + /** Total metadata size (in bytes). This is transmitted + * with every message because the size can change. */ + uint32_t cbTotalSize; + } v1; + /* Protocol v2: No changes. */ + struct + { + /** Data block buffer. */ + void *pvData; + /** Size (in bytes) of data block. */ + uint32_t cbData; + /** (Rolling) Checksum. Not yet implemented. */ + void *pvChecksum; + /** Size (in bytes) of checksum. Not yet implemented. */ + uint32_t cbChecksum; + } v3; + } u; +} VBOXDNDSNDDATA, *PVBOXDNDSNDDATA; + +typedef struct VBOXDNDCBSNDDATADATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + /** Actual data. */ + VBOXDNDSNDDATA data; +} VBOXDNDCBSNDDATADATA, *PVBOXDNDCBSNDDATADATA; + +typedef struct VBOXDNDCBSNDDIRDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + /** Directory path. */ + char *pszPath; + /** Size (in bytes) of path. */ + uint32_t cbPath; + /** Directory creation mode. */ + uint32_t fMode; +} VBOXDNDCBSNDDIRDATA, *PVBOXDNDCBSNDDIRDATA; + +/* Note: Only for protocol version 2 and up (>= VBox 5.0). */ +typedef struct VBOXDNDCBSNDFILEHDRDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + /** File path (name). */ + char *pszFilePath; + /** Size (in bytes) of file path. */ + uint32_t cbFilePath; + /** Total size (in bytes) of this file. */ + uint64_t cbSize; + /** File (creation) mode. */ + uint32_t fMode; + /** Additional flags. Not used at the moment. */ + uint32_t fFlags; +} VBOXDNDCBSNDFILEHDRDATA, *PVBOXDNDCBSNDFILEHDRDATA; + +typedef struct VBOXDNDCBSNDFILEDATADATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + /** Current file data chunk. */ + void *pvData; + /** Size (in bytes) of current data chunk. */ + uint32_t cbData; + union + { + struct + { + /** File path (name). */ + char *pszFilePath; + /** Size (in bytes) of file path. */ + uint32_t cbFilePath; + /** File (creation) mode. */ + uint32_t fMode; + } v1; + /* Protocol v2 + v3: Have the file attributes (name, size, mode, ...) + in the VBOXDNDCBSNDFILEHDRDATA structure. */ + struct + { + /** Checksum for current file data chunk. */ + void *pvChecksum; + /** Size (in bytes) of current data chunk. */ + uint32_t cbChecksum; + } v3; + } u; +} VBOXDNDCBSNDFILEDATADATA, *PVBOXDNDCBSNDFILEDATADATA; + +typedef struct VBOXDNDCBEVTERRORDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + int32_t rc; +} VBOXDNDCBEVTERRORDATA, *PVBOXDNDCBEVTERRORDATA; + +} /* namespace DragAndDropSvc */ + +#endif /* !VBOX_INCLUDED_HostServices_DragAndDropSvc_h */ + diff --git a/include/VBox/HostServices/GuestControlSvc.h b/include/VBox/HostServices/GuestControlSvc.h new file mode 100644 index 00000000..8ed0b2ba --- /dev/null +++ b/include/VBox/HostServices/GuestControlSvc.h @@ -0,0 +1,1500 @@ +/* $Id: GuestControlSvc.h $ */ +/** @file + * Guest control service - Common header for host service and guest clients. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_HostServices_GuestControlSvc_h +#define VBOX_INCLUDED_HostServices_GuestControlSvc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/VMMDevCoreTypes.h> +#include <VBox/VBoxGuestCoreTypes.h> +#include <VBox/hgcmsvc.h> +#include <iprt/assert.h> + +/* Everything defined in this file lives in this namespace. */ +namespace guestControl { + +/****************************************************************************** +* Typedefs, constants and inlines * +******************************************************************************/ + +#define HGCMSERVICE_NAME "VBoxGuestControlSvc" + +/** Maximum number of concurrent guest sessions a VM can have. */ +#define VBOX_GUESTCTRL_MAX_SESSIONS 32 +/** Maximum number of concurrent guest objects (processes, files, ...) + * a guest session can have. */ +#define VBOX_GUESTCTRL_MAX_OBJECTS _2K +/** Maximum of callback contexts a guest process can have. */ +#define VBOX_GUESTCTRL_MAX_CONTEXTS _64K + +/** Base (start) of guest control session IDs. Session + * ID 0 is reserved for the root process which + * hosts all other guest session processes. */ +#define VBOX_GUESTCTRL_SESSION_ID_BASE 1 + +/** Builds a context ID out of the session ID, object ID and an + * increasing count. */ +#define VBOX_GUESTCTRL_CONTEXTID_MAKE(uSession, uObject, uCount) \ + ( (uint32_t)((uSession) & 0x1f) << 27 \ + | (uint32_t)((uObject) & 0x7ff) << 16 \ + | (uint32_t)((uCount) & 0xffff) \ + ) +/** Creates a context ID out of a session ID. */ +#define VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(uSession) \ + ((uint32_t)((uSession) & 0x1f) << 27) +/** Gets the session ID out of a context ID. */ +#define VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID) \ + (((uContextID) >> 27) & 0x1f) +/** Gets the process ID out of a context ID. */ +#define VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID) \ + (((uContextID) >> 16) & 0x7ff) +/** Gets the context count of a process out of a context ID. */ +#define VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID) \ + ((uContextID) & 0xffff) +/** Filter context IDs by session. Can be used in conjunction + * with VbglR3GuestCtrlMsgFilterSet(). */ +#define VBOX_GUESTCTRL_FILTER_BY_SESSION(uSession) \ + (VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(uSession) | 0xF8000000) + +/** + * Structure keeping the context of a host callback. + */ +typedef struct VBOXGUESTCTRLHOSTCBCTX +{ + /** HGCM message number. */ + uint32_t uMessage; + /** The context ID. */ + uint32_t uContextID; + /** Protocol version of this guest session. Might + * be 0 if not supported. */ + uint32_t uProtocol; +} VBOXGUESTCTRLHOSTCBCTX, *PVBOXGUESTCTRLHOSTCBCTX; + +/** + * Structure for low level HGCM host callback from + * the guest. No deep copy. */ +typedef struct VBOXGUESTCTRLHOSTCALLBACK +{ + /** Number of HGCM parameters. */ + uint32_t mParms; + /** Actual HGCM parameters. */ + PVBOXHGCMSVCPARM mpaParms; +} VBOXGUESTCTRLHOSTCALLBACK, *PVBOXGUESTCTRLHOSTCALLBACK; + +/** @name Host message destination flags. + * + * This is ORed into the context ID parameter Main after extending it to 64-bit. + * + * @internal Host internal. + * @{ */ +#define VBOX_GUESTCTRL_DST_ROOT_SVC RT_BIT_64(63) +#define VBOX_GUESTCTRL_DST_SESSION RT_BIT_64(62) +#define VBOX_GUESTCTRL_DST_BOTH ( VBOX_GUESTCTRL_DST_ROOT_SVC | VBOX_GUESTCTRL_DST_SESSION ) +/** @} */ + + +/** + * The service messages which are callable by host. + */ +enum eHostMsg +{ + /** + * The host asks the client to cancel all pending waits and exit. + */ + HOST_MSG_CANCEL_PENDING_WAITS = 0, + /** + * The host wants to create a guest session. + */ + HOST_MSG_SESSION_CREATE = 20, + /** + * The host wants to close a guest session. + */ + HOST_MSG_SESSION_CLOSE = 21, + /** + * The host wants to execute something in the guest. This can be a command + * line or starting a program. + */ + HOST_MSG_EXEC_CMD = 100, + /** + * Sends input data for stdin to a running process executed by HOST_EXEC_CMD. + */ + HOST_MSG_EXEC_SET_INPUT = 101, + /** + * Gets the current status of a running process, e.g. + * new data on stdout/stderr, process terminated etc. + */ + HOST_MSG_EXEC_GET_OUTPUT = 102, + /** + * Terminates a running guest process. + */ + HOST_MSG_EXEC_TERMINATE = 110, + /** + * Waits for a certain event to happen. This can be an input, output + * or status event. + */ + HOST_MSG_EXEC_WAIT_FOR = 120, + /** + * Opens a guest file. + */ + HOST_MSG_FILE_OPEN = 240, + /** + * Closes a guest file. + */ + HOST_MSG_FILE_CLOSE, + /** + * Reads from an opened guest file. + */ + HOST_MSG_FILE_READ = 250, + /** + * Reads from an opened guest file at a specified offset. + */ + HOST_MSG_FILE_READ_AT, + /** + * Write to an opened guest file. + */ + HOST_MSG_FILE_WRITE = 260, + /** + * Write to an opened guest file at a specified offset. + */ + HOST_MSG_FILE_WRITE_AT, + /** + * Changes the read & write position of an opened guest file. + */ + HOST_MSG_FILE_SEEK = 270, + /** + * Gets the current file position of an opened guest file. + */ + HOST_MSG_FILE_TELL, + /** + * Changes the file size. + */ + HOST_MSG_FILE_SET_SIZE, + /** + * Removes a directory on the guest. + */ + HOST_MSG_DIR_REMOVE = 320, + /** + * Renames a path on the guest. + */ + HOST_MSG_PATH_RENAME = 330, + /** + * Retrieves the user's documents directory. + */ + HOST_MSG_PATH_USER_DOCUMENTS, + /** + * Retrieves the user's home directory. + */ + HOST_MSG_PATH_USER_HOME, + /** + * Issues a shutdown / reboot of the guest OS. + */ + HOST_MSG_SHUTDOWN, + + /** Blow the type up to 32-bits. */ + HOST_MSG_32BIT_HACK = 0x7fffffff +}; + + +/** + * Translates a guest control host message enum to a string. + * + * @returns Enum string name. + * @param enmMsg The message to translate. + */ +DECLINLINE(const char *) GstCtrlHostMsgtoStr(enum eHostMsg enmMsg) +{ + switch (enmMsg) + { + RT_CASE_RET_STR(HOST_MSG_CANCEL_PENDING_WAITS); + RT_CASE_RET_STR(HOST_MSG_SESSION_CREATE); + RT_CASE_RET_STR(HOST_MSG_SESSION_CLOSE); + RT_CASE_RET_STR(HOST_MSG_EXEC_CMD); + RT_CASE_RET_STR(HOST_MSG_EXEC_SET_INPUT); + RT_CASE_RET_STR(HOST_MSG_EXEC_GET_OUTPUT); + RT_CASE_RET_STR(HOST_MSG_EXEC_TERMINATE); + RT_CASE_RET_STR(HOST_MSG_EXEC_WAIT_FOR); + RT_CASE_RET_STR(HOST_MSG_FILE_OPEN); + RT_CASE_RET_STR(HOST_MSG_FILE_CLOSE); + RT_CASE_RET_STR(HOST_MSG_FILE_READ); + RT_CASE_RET_STR(HOST_MSG_FILE_READ_AT); + RT_CASE_RET_STR(HOST_MSG_FILE_WRITE); + RT_CASE_RET_STR(HOST_MSG_FILE_WRITE_AT); + RT_CASE_RET_STR(HOST_MSG_FILE_SEEK); + RT_CASE_RET_STR(HOST_MSG_FILE_TELL); + RT_CASE_RET_STR(HOST_MSG_FILE_SET_SIZE); + RT_CASE_RET_STR(HOST_MSG_DIR_REMOVE); + RT_CASE_RET_STR(HOST_MSG_PATH_RENAME); + RT_CASE_RET_STR(HOST_MSG_PATH_USER_DOCUMENTS); + RT_CASE_RET_STR(HOST_MSG_PATH_USER_HOME); + RT_CASE_RET_STR(HOST_MSG_SHUTDOWN); + RT_CASE_RET_STR(HOST_MSG_32BIT_HACK); + } + return "Unknown"; +} + + +/** + * The service messages which are callable by the guest. + * + * @note The message numbers cannot be changed. Please use the first non-zero + * number that's not in use when adding new messages. + * + * @note Remember to update service.cpp when adding new messages for Main, + * as it validates all incoming messages before passing them on. + */ +enum eGuestMsg +{ + /** Guest waits for a new message the host wants to process on the guest side. + * This is a blocking call and can be deferred. + * + * @note This message is rather odd. The above description isn't really + * correct. Yes, it (1) waits for a new message and will return the + * mesage number and parameter count when one is available. However, it + * is also (2) used to retrieve the message parameters. For some weird + * reasons it was decided that it should always return VERR_TOO_MUCH_DATA + * when used in the first capacity. + * + * @note Has a problem if the guest kernel module cancels the HGCM call, as the + * guest cannot resume waiting till the host issues a message for it and + * the cancelled call returns. The new message may potentially end up in + * /dev/null depending and hang the message conversation between the guest + * and the host (SIGCHLD). + * + * @deprecated Replaced by GUEST_MSG_PEEK_WAIT, GUEST_MSG_GET and + * GUEST_MSG_CANCEL. + */ + GUEST_MSG_WAIT = 1, + /** Cancels pending calls for this client session. + * + * This should be used if a GUEST_MSG_PEEK_WAIT or GUEST_MSG_WAIT call gets + * interrupted on the client end, so as to prevent being rebuffed with + * VERR_RESOURCE_BUSY when restarting the call. + * + * @retval VINF_SUCCESS if cancelled any calls. + * @retval VWRN_NOT_FOUND if no callers. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @since 6.0 + */ + GUEST_MSG_CANCEL = 2, + /** Guest disconnected (terminated normally or due to a crash HGCM + * detected when calling service::clientDisconnect(). + * + * @note This is a host side notification message that has no business in this + * enum. The guest cannot use this message number, host will reject it. + */ + GUEST_MSG_DISCONNECTED = 3, + /** Sets a message filter to only get messages which have a certain + * context ID scheme (that is, a specific session, object etc). + * Since VBox 4.3+. + * @deprecated Replaced by GUEST_SESSION_ACCEPT. + */ + GUEST_MSG_FILTER_SET = 4, + /** Unsets (and resets) a previously set message filter. + * @retval VERR_NOT_IMPLEMENTED since 6.0. + * @deprecated Never needed or used, + */ + GUEST_MSG_FILTER_UNSET = 5, + /** Peeks at the next message, returning immediately. + * + * Returns two 32-bit parameters, first is the message ID and the second the + * parameter count. May optionally return additional 32-bit parameters with the + * sizes of respective message parameters. To distinguish buffer sizes from + * integer parameters, the latter gets their sizes inverted (uint32_t is ~4U, + * uint64_t is ~8U). + * + * Does also support the VM restore checking as in GUEST_MSG_PEEK_WAIT (64-bit + * param \# 0), see documentation there. + * + * @retval VINF_SUCCESS if a message was pending and is being returned. + * @retval VERR_TRY_AGAIN if no message pending. + * @retval VERR_VM_RESTORED if first parameter is a non-zero 64-bit value that + * does not match VbglR3GetSessionId() any more. The new value is + * returned. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.0 + */ + GUEST_MSG_PEEK_NOWAIT = 6, + /** Peeks at the next message, waiting for one to arrive. + * + * Returns two 32-bit parameters, first is the message ID and the second the + * parameter count. May optionally return additional 32-bit parameters with the + * sizes of respective message parameters. To distinguish buffer sizes from + * integer parameters, the latter gets their sizes inverted (uint32_t is ~4U, + * uint64_t is ~8U). + * + * To facilitate VM restore checking, the first parameter can be a 64-bit + * integer holding the VbglR3GetSessionId() value the guest knowns. The + * function will then check this before going to sleep and return + * VERR_VM_RESTORED if it doesn't match, same thing happens when the VM is + * restored. + * + * @retval VINF_SUCCESS if info about an pending message is being returned. + * @retval VINF_TRY_AGAIN and message set to HOST_CANCEL_PENDING_WAITS if + * cancelled by GUEST_MSG_CANCEL. + * @retval VERR_RESOURCE_BUSY if another thread already made a waiting call. + * @retval VERR_VM_RESTORED if first parameter is a non-zero 64-bit value that + * does not match VbglR3GetSessionId() any more. The new value is + * returned. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @note This replaces GUEST_MSG_WAIT. + * @since 6.0 + */ + GUEST_MSG_PEEK_WAIT = 7, + /** Gets the next message, returning immediately. + * + * All parameters are specific to the message being retrieved, however if the + * first one is an integer value it shall be an input parameter holding the + * ID of the message being retrieved. While it would be nice to add a separate + * parameter for this purpose, this is difficult without breaking GUEST_MSG_WAIT + * compatibility. + * + * @retval VINF_SUCCESS if message retrieved and removed from the pending queue. + * @retval VERR_TRY_AGAIN if no message pending. + * @retval VERR_MISMATCH if the incoming message ID does not match the pending. + * @retval VERR_BUFFER_OVERFLOW if a parmeter buffer is too small. The buffer + * size was updated to reflect the required size. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @note This replaces GUEST_MSG_WAIT. + * @since 6.0 + */ + GUEST_MSG_GET = 8, + /** Skip message. + * + * This skips the current message, replying to the main backend as best it can. + * Takes between zero and two parameters. The first parameter is the 32-bit + * VBox status code to pass onto Main when skipping the message, defaults to + * VERR_NOT_SUPPORTED. The second parameter is the 32-bit message ID of the + * message to skip, by default whatever is first in the queue is removed. This + * is also the case if UINT32_MAX is specified. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_FOUND if no message pending. + * @retval VERR_MISMATCH if the specified message ID didn't match. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @since 6.0 + */ + GUEST_MSG_SKIP = 9, + /** + * Skips the current assigned message returned by GUEST_MSG_WAIT. + * Needed for telling the host service to not keep stale + * host messages in the queue. + * @deprecated Replaced by GUEST_MSG_SKIP. + */ + GUEST_MSG_SKIP_OLD = 10, + /** General reply to a host message. + * Only contains basic data along with a simple payload. + * @todo proper docs. + */ + GUEST_MSG_REPLY = 11, + /** General message for updating a pending progress for a long task. + * @todo proper docs. + */ + GUEST_MSG_PROGRESS_UPDATE = 12, + /** Sets the caller as the master. + * + * Called by the root VBoxService to explicitly tell the host that's the master + * service. Required to use main VBoxGuest device node. No parameters. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_ACCESS_DENIED if not using main VBoxGuest device not + * @retval VERR_RESOURCE_BUSY if there is already a master. + * @retval VERR_VERSION_MISMATCH if VBoxGuest didn't supply requestor info. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @since 6.0 + */ + GUEST_MSG_MAKE_ME_MASTER = 13, + /** Prepares the starting of a session. + * + * VBoxService makes this call before spawning a session process (must be + * master). The first parameter is the session ID and the second is a one time + * key for identifying the right session process. First parameter is a 32-bit + * session ID with a value between 1 and 0xfff0. The second parameter is a byte + * buffer containing a key that GUEST_SESSION_ACCEPT checks against, minimum + * length is 64 bytes, maximum 16384 bytes. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_OUT_OF_RESOURCES if too many pending sessions hanging around. + * @retval VERR_OUT_OF_RANGE if the session ID outside the allowed range. + * @retval VERR_BUFFER_OVERFLOW if key too large. + * @retval VERR_BUFFER_UNDERFLOW if key too small. + * @retval VERR_ACCESS_DENIED if not master or in legacy mode. + * @retval VERR_DUPLICATE if the session ID has been prepared already. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.0 + */ + GUEST_MSG_SESSION_PREPARE = 14, + /** Cancels a prepared session. + * + * VBoxService makes this call to clean up after spawning a session process + * failed. One parameter, 32-bit session ID. If UINT32_MAX is passed, all + * prepared sessions are cancelled. + * + * @retval VINF_SUCCESS on success. + * @retval VWRN_NOT_FOUND if no session with the specified ID. + * @retval VERR_ACCESS_DENIED if not master or in legacy mode. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.0 + */ + GUEST_MSG_SESSION_CANCEL_PREPARED = 15, + /** Accepts a prepared session. + * + * The session processes makes this call to accept a prepared session. The + * session ID is then uniquely associated with the HGCM client ID of the caller. + * The parameters must be identical to the matching GUEST_SESSION_PREPARE call. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_FOUND if the specified session ID wasn't found. + * @retval VERR_OUT_OF_RANGE if the session ID outside the allowed range. + * @retval VERR_BUFFER_OVERFLOW if key too large. + * @retval VERR_BUFFER_UNDERFLOW if key too small. + * @retval VERR_ACCESS_DENIED if we're in legacy mode or is master. + * @retval VERR_RESOURCE_BUSY if the client is already associated with a session. + * @retval VERR_MISMATCH if the key didn't match. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.0 + */ + GUEST_MSG_SESSION_ACCEPT = 16, + /** + * Guest reports back a guest session status. + * @todo proper docs. + */ + GUEST_MSG_SESSION_NOTIFY = 20, + /** + * Guest wants to close a specific guest session. + * @todo proper docs. + */ + GUEST_MSG_SESSION_CLOSE = 21, + + /** Report guest side feature flags and retrieve the host ones. + * + * VBoxService makes this call right after becoming master to indicate to the + * host what features it support in addition. In return the host will return + * features the host supports. Two 64-bit parameters are passed in from the + * guest with the guest features (VBOX_GUESTCTRL_GF_XXX), the host replies by + * replacing the parameter values with the host ones (VBOX_GUESTCTRL_HF_XXX). + * + * @retval VINF_SUCCESS on success. + * @retval VERR_ACCESS_DENIED it not master. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.0.10, 5.2.32 + */ + GUEST_MSG_REPORT_FEATURES, + /** Query the host ones feature masks. + * + * This is for the session sub-process so that it can get hold of the features + * from the host. Again, it is prudent to set the 127 bit and observe it being + * cleared on success, as older hosts might return success without doing + * anything. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.0.10, 5.2.32 + */ + GUEST_MSG_QUERY_FEATURES, + + /** + * Guests sends output from an executed process. + * @todo proper docs. + */ + GUEST_MSG_EXEC_OUTPUT = 100, + /** + * Guest sends a status update of an executed process to the host. + * @todo proper docs. + */ + GUEST_MSG_EXEC_STATUS = 101, + /** + * Guests sends an input status notification to the host. + * @todo proper docs. + */ + GUEST_MSG_EXEC_INPUT_STATUS = 102, + /** + * Guest notifies the host about some I/O event. This can be + * a stdout, stderr or a stdin event. The actual event only tells + * how many data is available / can be sent without actually + * transmitting the data. + * @todo proper docs. + */ + GUEST_MSG_EXEC_IO_NOTIFY = 210, + /** + * Guest notifies the host about some directory event. + * @todo proper docs. + */ + GUEST_MSG_DIR_NOTIFY = 230, + /** + * Guest notifies the host about some file event. + * @todo proper docs. + */ + GUEST_MSG_FILE_NOTIFY = 240 +}; + +/** + * Translates a guest control guest message enum to a string. + * + * @returns Enum string name. + * @param enmMsg The message to translate. + */ +DECLINLINE(const char *) GstCtrlGuestMsgToStr(enum eGuestMsg enmMsg) +{ + switch (enmMsg) + { + RT_CASE_RET_STR(GUEST_MSG_WAIT); + RT_CASE_RET_STR(GUEST_MSG_CANCEL); + RT_CASE_RET_STR(GUEST_MSG_DISCONNECTED); + RT_CASE_RET_STR(GUEST_MSG_FILTER_SET); + RT_CASE_RET_STR(GUEST_MSG_FILTER_UNSET); + RT_CASE_RET_STR(GUEST_MSG_PEEK_NOWAIT); + RT_CASE_RET_STR(GUEST_MSG_PEEK_WAIT); + RT_CASE_RET_STR(GUEST_MSG_GET); + RT_CASE_RET_STR(GUEST_MSG_SKIP_OLD); + RT_CASE_RET_STR(GUEST_MSG_REPLY); + RT_CASE_RET_STR(GUEST_MSG_PROGRESS_UPDATE); + RT_CASE_RET_STR(GUEST_MSG_SKIP); + RT_CASE_RET_STR(GUEST_MSG_MAKE_ME_MASTER); + RT_CASE_RET_STR(GUEST_MSG_SESSION_PREPARE); + RT_CASE_RET_STR(GUEST_MSG_SESSION_CANCEL_PREPARED); + RT_CASE_RET_STR(GUEST_MSG_SESSION_ACCEPT); + RT_CASE_RET_STR(GUEST_MSG_SESSION_NOTIFY); + RT_CASE_RET_STR(GUEST_MSG_SESSION_CLOSE); + RT_CASE_RET_STR(GUEST_MSG_REPORT_FEATURES); + RT_CASE_RET_STR(GUEST_MSG_QUERY_FEATURES); + RT_CASE_RET_STR(GUEST_MSG_EXEC_OUTPUT); + RT_CASE_RET_STR(GUEST_MSG_EXEC_STATUS); + RT_CASE_RET_STR(GUEST_MSG_EXEC_INPUT_STATUS); + RT_CASE_RET_STR(GUEST_MSG_EXEC_IO_NOTIFY); + RT_CASE_RET_STR(GUEST_MSG_DIR_NOTIFY); + RT_CASE_RET_STR(GUEST_MSG_FILE_NOTIFY); + } + return "Unknown"; +} + + +/** + * Guest session notification types. + * @sa HGCMMsgSessionNotify. + */ +enum GUEST_SESSION_NOTIFYTYPE +{ + GUEST_SESSION_NOTIFYTYPE_UNDEFINED = 0, + /** Something went wrong (see rc). */ + GUEST_SESSION_NOTIFYTYPE_ERROR = 1, + /** Guest session has been started. */ + GUEST_SESSION_NOTIFYTYPE_STARTED = 11, + /** Guest session terminated normally. */ + GUEST_SESSION_NOTIFYTYPE_TEN = 20, + /** Guest session terminated via signal. */ + GUEST_SESSION_NOTIFYTYPE_TES = 30, + /** Guest session terminated abnormally. */ + GUEST_SESSION_NOTIFYTYPE_TEA = 40, + /** Guest session timed out and was killed. */ + GUEST_SESSION_NOTIFYTYPE_TOK = 50, + /** Guest session timed out and was not killed successfully. */ + GUEST_SESSION_NOTIFYTYPE_TOA = 60, + /** Service/OS is stopping, process was killed. */ + GUEST_SESSION_NOTIFYTYPE_DWN = 150 +}; + +/** + * Guest directory notification types. + * @sa HGCMMsgDirNotify. + */ +enum GUEST_DIR_NOTIFYTYPE +{ + GUEST_DIR_NOTIFYTYPE_UNKNOWN = 0, + /** Something went wrong (see rc). */ + GUEST_DIR_NOTIFYTYPE_ERROR = 1, + /** Guest directory opened. */ + GUEST_DIR_NOTIFYTYPE_OPEN = 10, + /** Guest directory closed. */ + GUEST_DIR_NOTIFYTYPE_CLOSE = 20, + /** Information about an open guest directory. */ + GUEST_DIR_NOTIFYTYPE_INFO = 40, + /** Guest directory created. */ + GUEST_DIR_NOTIFYTYPE_CREATE = 70, + /** Guest directory deleted. */ + GUEST_DIR_NOTIFYTYPE_REMOVE = 80 +}; + +/** + * Guest file notification types. + * @sa HGCMMsgFileNotify. + */ +enum GUEST_FILE_NOTIFYTYPE +{ + GUEST_FILE_NOTIFYTYPE_UNKNOWN = 0, + GUEST_FILE_NOTIFYTYPE_ERROR = 1, + GUEST_FILE_NOTIFYTYPE_OPEN = 10, + GUEST_FILE_NOTIFYTYPE_CLOSE = 20, + GUEST_FILE_NOTIFYTYPE_READ = 30, + GUEST_FILE_NOTIFYTYPE_READ_OFFSET, /**< @since 6.0.10, 5.2.32 - VBOX_GUESTCTRL_HF_0_NOTIFY_RDWR_OFFSET */ + GUEST_FILE_NOTIFYTYPE_WRITE = 40, + GUEST_FILE_NOTIFYTYPE_WRITE_OFFSET, /**< @since 6.0.10, 5.2.32 - VBOX_GUESTCTRL_HF_0_NOTIFY_RDWR_OFFSET */ + GUEST_FILE_NOTIFYTYPE_SEEK = 50, + GUEST_FILE_NOTIFYTYPE_TELL = 60, + GUEST_FILE_NOTIFYTYPE_SET_SIZE +}; + +/** + * Guest file seeking types. Has to match FileSeekType in Main. + * + * @note This is not compatible with RTFileSeek, which is an unncessary pain. + */ +enum GUEST_FILE_SEEKTYPE +{ + GUEST_FILE_SEEKTYPE_BEGIN = 1, + GUEST_FILE_SEEKTYPE_CURRENT = 4, + GUEST_FILE_SEEKTYPE_END = 8 +}; + +/** @name VBOX_GUESTCTRL_GF_XXX - Guest features. + * @sa GUEST_MSG_REPORT_FEATURES + * @{ */ +/** Supports HOST_MSG_FILE_SET_SIZE. */ +#define VBOX_GUESTCTRL_GF_0_SET_SIZE RT_BIT_64(0) +/** Supports passing process arguments starting at argv[0] rather than argv[1]. + * Guest additions which doesn't support this feature will instead use the + * executable image path as argv[0]. + * @sa VBOX_GUESTCTRL_HF_0_PROCESS_ARGV0 + * @since 6.1.6 */ +#define VBOX_GUESTCTRL_GF_0_PROCESS_ARGV0 RT_BIT_64(1) +/** Supports passing cmd / arguments / environment blocks bigger than + * GUESTPROCESS_DEFAULT_CMD_LEN / GUESTPROCESS_DEFAULT_ARGS_LEN / GUESTPROCESS_DEFAULT_ENV_LEN (bytes, in total). */ +#define VBOX_GUESTCTRL_GF_0_PROCESS_DYNAMIC_SIZES RT_BIT_64(2) +/** Supports shutting down / rebooting the guest. */ +#define VBOX_GUESTCTRL_GF_0_SHUTDOWN RT_BIT_64(3) +/** Bit that must be set in the 2nd parameter, will be cleared if the host reponds + * correctly (old hosts might not). */ +#define VBOX_GUESTCTRL_GF_1_MUST_BE_ONE RT_BIT_64(63) +/** @} */ + +/** @name VBOX_GUESTCTRL_HF_XXX - Host features. + * @sa GUEST_MSG_REPORT_FEATURES + * @{ */ +/** Host supports the GUEST_FILE_NOTIFYTYPE_READ_OFFSET and + * GUEST_FILE_NOTIFYTYPE_WRITE_OFFSET notification types. */ +#define VBOX_GUESTCTRL_HF_0_NOTIFY_RDWR_OFFSET RT_BIT_64(0) +/** Host supports process passing arguments starting at argv[0] rather than + * argv[1], when the guest additions reports VBOX_GUESTCTRL_GF_0_PROCESS_ARGV0. + * @since 6.1.6 */ +#define VBOX_GUESTCTRL_HF_0_PROCESS_ARGV0 RT_BIT_64(1) +/** @} */ + + +/* + * HGCM parameter structures. + */ +#pragma pack (1) + +/** + * Waits for a host message to arrive. The structure then contains the + * actual message type + required number of parameters needed to successfully + * retrieve that host message (in a next round). + */ +typedef struct HGCMMsgWaitFor +{ + VBGLIOCHGCMCALL hdr; + /** The returned message the host wants to run on the guest. */ + HGCMFunctionParameter msg; /* OUT uint32_t */ + /** Number of parameters the message needs. */ + HGCMFunctionParameter num_parms; /* OUT uint32_t */ +} HGCMMsgWaitFor; + +/** + * Asks the guest control host service to set a message + * filter for this client. This filter will then only + * deliver messages to the client which match the + * wanted context ID (ranges). + */ +typedef struct HGCMMsgFilterSet +{ + VBGLIOCHGCMCALL hdr; + /** Value to filter for after filter mask was applied. */ + HGCMFunctionParameter value; /* IN uint32_t */ + /** Mask to add to the current set filter. */ + HGCMFunctionParameter mask_add; /* IN uint32_t */ + /** Mask to remove from the current set filter. */ + HGCMFunctionParameter mask_remove; /* IN uint32_t */ + /** Filter flags; currently unused. */ + HGCMFunctionParameter flags; /* IN uint32_t */ +} HGCMMsgFilterSet; + +/** + * Asks the guest control host service to disable + * a previously set message filter again. + */ +typedef struct HGCMMsgFilterUnset +{ + VBGLIOCHGCMCALL hdr; + /** Unset flags; currently unused. */ + HGCMFunctionParameter flags; /* IN uint32_t */ +} HGCMMsgFilterUnset; + +/** + * Asks the guest control host service to skip the + * currently assigned host message returned by + * VbglR3GuestCtrlMsgWaitFor(). + */ +typedef struct HGCMMsgSkip +{ + VBGLIOCHGCMCALL hdr; + /** Skip flags; currently unused. */ + HGCMFunctionParameter flags; /* IN uint32_t */ +} HGCMMsgSkip; + +/** + * Asks the guest control host service to cancel all pending (outstanding) + * waits which were not processed yet. This is handy for a graceful shutdown. + */ +typedef struct HGCMMsgCancelPendingWaits +{ + VBGLIOCHGCMCALL hdr; +} HGCMMsgCancelPendingWaits; + +typedef struct HGCMMsgReply +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** Message type. */ + HGCMFunctionParameter type; + /** IPRT result of overall operation. */ + HGCMFunctionParameter rc; + /** Optional payload to this reply. */ + HGCMFunctionParameter payload; +} HGCMMsgReply; + +/** + * Creates a guest session. + */ +typedef struct HGCMMsgSessionOpen +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** The guest control protocol version this + * session is about to use. */ + HGCMFunctionParameter protocol; + /** The user name to run the guest session under. */ + HGCMFunctionParameter username; + /** The user's password. */ + HGCMFunctionParameter password; + /** The domain to run the guest session under. */ + HGCMFunctionParameter domain; + /** Session creation flags. */ + HGCMFunctionParameter flags; +} HGCMMsgSessionOpen; + +/** + * Terminates (closes) a guest session. + */ +typedef struct HGCMMsgSessionClose +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** Session termination flags. */ + HGCMFunctionParameter flags; +} HGCMMsgSessionClose; + +/** + * Reports back a guest session's status. + */ +typedef struct HGCMMsgSessionNotify +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** Notification type. */ + HGCMFunctionParameter type; + /** Notification result. */ + HGCMFunctionParameter result; +} HGCMMsgSessionNotify; + +typedef struct HGCMMsgPathRename +{ + VBGLIOCHGCMCALL hdr; + /** UInt32: Context ID. */ + HGCMFunctionParameter context; + /** Source to rename. */ + HGCMFunctionParameter source; + /** Destination to rename source to. */ + HGCMFunctionParameter dest; + /** UInt32: Rename flags. */ + HGCMFunctionParameter flags; +} HGCMMsgPathRename; + +typedef struct HGCMMsgPathUserDocuments +{ + VBGLIOCHGCMCALL hdr; + /** UInt32: Context ID. */ + HGCMFunctionParameter context; +} HGCMMsgPathUserDocuments; + +typedef struct HGCMMsgPathUserHome +{ + VBGLIOCHGCMCALL hdr; + /** UInt32: Context ID. */ + HGCMFunctionParameter context; +} HGCMMsgPathUserHome; + +/** + * Shuts down / reboots the guest. + */ +typedef struct HGCMMsgShutdown +{ + VBGLIOCHGCMCALL hdr; + /** UInt32: Context ID. */ + HGCMFunctionParameter context; + /** UInt32: Action flags. */ + HGCMFunctionParameter action; +} HGCMMsgShutdown; + +/** + * Executes a command inside the guest. + */ +typedef struct HGCMMsgProcExec +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** The command to execute on the guest. */ + HGCMFunctionParameter cmd; + /** Execution flags (see IGuest::ProcessCreateFlag_*). */ + HGCMFunctionParameter flags; + /** Number of arguments. */ + HGCMFunctionParameter num_args; + /** The actual arguments. */ + HGCMFunctionParameter args; + /** Number of environment value pairs. */ + HGCMFunctionParameter num_env; + /** Size (in bytes) of environment block, including terminating zeros. */ + HGCMFunctionParameter cb_env; + /** The actual environment block. */ + HGCMFunctionParameter env; + union + { + struct + { + /** The user name to run the executed command under. + * Only for VBox < 4.3 hosts. */ + HGCMFunctionParameter username; + /** The user's password. + * Only for VBox < 4.3 hosts. */ + HGCMFunctionParameter password; + /** Timeout (in msec) which either specifies the + * overall lifetime of the process or how long it + * can take to bring the process up and running - + * (depends on the IGuest::ProcessCreateFlag_*). */ + HGCMFunctionParameter timeout; + } v1; + struct + { + /** Timeout (in ms) which either specifies the + * overall lifetime of the process or how long it + * can take to bring the process up and running - + * (depends on the IGuest::ProcessCreateFlag_*). */ + HGCMFunctionParameter timeout; + /** Process priority. */ + HGCMFunctionParameter priority; + /** Number of process affinity blocks. */ + HGCMFunctionParameter num_affinity; + /** Pointer to process affinity blocks (uint64_t). */ + HGCMFunctionParameter affinity; + } v2; + } u; +} HGCMMsgProcExec; + +/** + * Sends input to a guest process via stdin. + */ +typedef struct HGCMMsgProcInput +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** The process ID (PID) to send the input to. */ + HGCMFunctionParameter pid; + /** Input flags (see IGuest::ProcessInputFlag_*). */ + HGCMFunctionParameter flags; + /** Data buffer. */ + HGCMFunctionParameter data; + /** Actual size of data (in bytes). */ + HGCMFunctionParameter size; +} HGCMMsgProcInput; + +/** + * Retrieves ouptut from a previously executed process + * from stdout/stderr. + */ +typedef struct HGCMMsgProcOutput +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** The process ID (PID). */ + HGCMFunctionParameter pid; + /** The pipe handle ID (stdout/stderr). */ + HGCMFunctionParameter handle; + /** Optional flags. */ + HGCMFunctionParameter flags; + /** Data buffer. */ + HGCMFunctionParameter data; +} HGCMMsgProcOutput; + +/** + * Reports the current status of a guest process. + */ +typedef struct HGCMMsgProcStatus +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** The process ID (PID). */ + HGCMFunctionParameter pid; + /** The process status. */ + HGCMFunctionParameter status; + /** Optional flags (based on status). */ + HGCMFunctionParameter flags; + /** Optional data buffer (not used atm). */ + HGCMFunctionParameter data; +} HGCMMsgProcStatus; + +/** + * Reports back the status of data written to a process. + */ +typedef struct HGCMMsgProcStatusInput +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** The process ID (PID). */ + HGCMFunctionParameter pid; + /** Status of the operation. */ + HGCMFunctionParameter status; + /** Optional flags. */ + HGCMFunctionParameter flags; + /** Data written. */ + HGCMFunctionParameter written; +} HGCMMsgProcStatusInput; + +/* + * Guest control 2.0 messages. + */ + +/** + * Terminates a guest process. + */ +typedef struct HGCMMsgProcTerminate +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** The process ID (PID). */ + HGCMFunctionParameter pid; +} HGCMMsgProcTerminate; + +/** + * Waits for certain events to happen. + */ +typedef struct HGCMMsgProcWaitFor +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** The process ID (PID). */ + HGCMFunctionParameter pid; + /** Wait (event) flags. */ + HGCMFunctionParameter flags; + /** Timeout (in ms). */ + HGCMFunctionParameter timeout; +} HGCMMsgProcWaitFor; + +typedef struct HGCMMsgDirRemove +{ + VBGLIOCHGCMCALL hdr; + /** UInt32: Context ID. */ + HGCMFunctionParameter context; + /** Directory to remove. */ + HGCMFunctionParameter path; + /** UInt32: Removement flags. */ + HGCMFunctionParameter flags; +} HGCMMsgDirRemove; + +/** + * Opens a guest file. + */ +typedef struct HGCMMsgFileOpen +{ + VBGLIOCHGCMCALL hdr; + /** UInt32: Context ID. */ + HGCMFunctionParameter context; + /** File to open. */ + HGCMFunctionParameter filename; + /** Open mode. */ + HGCMFunctionParameter openmode; + /** Disposition mode. */ + HGCMFunctionParameter disposition; + /** Sharing mode. */ + HGCMFunctionParameter sharing; + /** UInt32: Creation mode. */ + HGCMFunctionParameter creationmode; + /** UInt64: Initial offset. */ + HGCMFunctionParameter offset; +} HGCMMsgFileOpen; + +/** + * Closes a guest file. + */ +typedef struct HGCMMsgFileClose +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** File handle to close. */ + HGCMFunctionParameter handle; +} HGCMMsgFileClose; + +/** + * Reads from a guest file. + */ +typedef struct HGCMMsgFileRead +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** File handle to read from. */ + HGCMFunctionParameter handle; + /** Size (in bytes) to read. */ + HGCMFunctionParameter size; +} HGCMMsgFileRead; + +/** + * Reads at a specified offset from a guest file. + */ +typedef struct HGCMMsgFileReadAt +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** File handle to read from. */ + HGCMFunctionParameter handle; + /** Offset where to start reading from. */ + HGCMFunctionParameter offset; + /** Actual size of data (in bytes). */ + HGCMFunctionParameter size; +} HGCMMsgFileReadAt; + +/** + * Writes to a guest file. + */ +typedef struct HGCMMsgFileWrite +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** File handle to write to. */ + HGCMFunctionParameter handle; + /** Actual size of data (in bytes). */ + HGCMFunctionParameter size; + /** Data buffer to write to the file. */ + HGCMFunctionParameter data; +} HGCMMsgFileWrite; + +/** + * Writes at a specified offset to a guest file. + */ +typedef struct HGCMMsgFileWriteAt +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** File handle to write to. */ + HGCMFunctionParameter handle; + /** Offset where to start reading from. */ + HGCMFunctionParameter offset; + /** Actual size of data (in bytes). */ + HGCMFunctionParameter size; + /** Data buffer to write to the file. */ + HGCMFunctionParameter data; +} HGCMMsgFileWriteAt; + +/** + * Seeks the read/write position of a guest file. + */ +typedef struct HGCMMsgFileSeek +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** File handle to seek. */ + HGCMFunctionParameter handle; + /** The seeking method. */ + HGCMFunctionParameter method; + /** The seeking offset. */ + HGCMFunctionParameter offset; +} HGCMMsgFileSeek; + +/** + * Tells the current read/write position of a guest file. + */ +typedef struct HGCMMsgFileTell +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** File handle to get the current position for. */ + HGCMFunctionParameter handle; +} HGCMMsgFileTell; + +/** + * Changes the file size. + */ +typedef struct HGCMMsgFileSetSize +{ + VBGLIOCHGCMCALL Hdr; + /** Context ID. */ + HGCMFunctionParameter id32Context; + /** File handle to seek. */ + HGCMFunctionParameter id32Handle; + /** The new file size. */ + HGCMFunctionParameter cb64NewSize; +} HGCMMsgFileSetSize; + + +/****************************************************************************** +* HGCM replies from the guest. These are handled in Main's low-level HGCM * +* callbacks and dispatched to the appropriate guest object. * +******************************************************************************/ + +typedef struct HGCMReplyFileNotify +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** Notification type. */ + HGCMFunctionParameter type; + /** IPRT result of overall operation. */ + HGCMFunctionParameter rc; + union + { + struct + { + /** Guest file handle. */ + HGCMFunctionParameter handle; + } open; + /** Note: Close does not have any additional data (yet). */ + struct + { + /** Actual data read (if any). */ + HGCMFunctionParameter data; + } read; + struct + { + /** Actual data read (if any). */ + HGCMFunctionParameter pvData; + /** The new file offset (signed). Negative value if non-seekable files. */ + HGCMFunctionParameter off64New; + } ReadOffset; + struct + { + /** How much data (in bytes) have been successfully written. */ + HGCMFunctionParameter written; + } write; + struct + { + /** Number of bytes that was successfully written. */ + HGCMFunctionParameter cb32Written; + /** The new file offset (signed). Negative value if non-seekable files. */ + HGCMFunctionParameter off64New; + } WriteOffset; + struct + { + HGCMFunctionParameter offset; + } seek; + struct + { + HGCMFunctionParameter offset; + } tell; + struct + { + HGCMFunctionParameter cb64Size; + } SetSize; + } u; +} HGCMReplyFileNotify; + +typedef struct HGCMReplyDirNotify +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** Notification type. */ + HGCMFunctionParameter type; + /** IPRT result of overall operation. */ + HGCMFunctionParameter rc; + union + { + struct + { + /** Directory information. */ + HGCMFunctionParameter objInfo; + } info; + struct + { + /** Guest directory handle. */ + HGCMFunctionParameter handle; + } open; + struct + { + /** Current read directory entry. */ + HGCMFunctionParameter entry; + /** Extended entry object information. Optional. */ + HGCMFunctionParameter objInfo; + } read; + } u; +} HGCMReplyDirNotify; + +#pragma pack () + +/****************************************************************************** +* Callback data structures. * +******************************************************************************/ + +/** + * The guest control callback data header. Must come first + * on each callback structure defined below this struct. + */ +typedef struct CALLBACKDATA_HEADER +{ + /** Context ID to identify callback data. This is + * and *must* be the very first parameter in this + * structure to still be backwards compatible. */ + uint32_t uContextID; +} CALLBACKDATA_HEADER, *PCALLBACKDATA_HEADER; + +/* + * These structures make up the actual low level HGCM callback data sent from + * the guest back to the host. + */ + +typedef struct CALLBACKDATA_CLIENT_DISCONNECTED +{ + /** Callback data header. */ + CALLBACKDATA_HEADER hdr; +} CALLBACKDATA_CLIENT_DISCONNECTED, *PCALLBACKDATA_CLIENT_DISCONNECTED; + +typedef struct CALLBACKDATA_MSG_REPLY +{ + /** Callback data header. */ + CALLBACKDATA_HEADER hdr; + /** Notification type. */ + uint32_t uType; + /** Notification result. Note: int vs. uint32! */ + uint32_t rc; + /** Pointer to optional payload. */ + void *pvPayload; + /** Payload size (in bytes). */ + uint32_t cbPayload; +} CALLBACKDATA_MSG_REPLY, *PCALLBACKDATA_MSG_REPLY; + +typedef struct CALLBACKDATA_SESSION_NOTIFY +{ + /** Callback data header. */ + CALLBACKDATA_HEADER hdr; + /** Notification type. */ + uint32_t uType; + /** Notification result. Note: int vs. uint32! */ + uint32_t uResult; +} CALLBACKDATA_SESSION_NOTIFY, *PCALLBACKDATA_SESSION_NOTIFY; + +typedef struct CALLBACKDATA_PROC_STATUS +{ + /** Callback data header. */ + CALLBACKDATA_HEADER hdr; + /** The process ID (PID). */ + uint32_t uPID; + /** The process status. */ + uint32_t uStatus; + /** Optional flags, varies, based on u32Status. */ + uint32_t uFlags; + /** Optional data buffer (not used atm). */ + void *pvData; + /** Size of optional data buffer (not used atm). */ + uint32_t cbData; +} CALLBACKDATA_PROC_STATUS, *PCALLBACKDATA_PROC_STATUS; + +typedef struct CALLBACKDATA_PROC_OUTPUT +{ + /** Callback data header. */ + CALLBACKDATA_HEADER hdr; + /** The process ID (PID). */ + uint32_t uPID; + /** The handle ID (stdout/stderr). */ + uint32_t uHandle; + /** Optional flags (not used atm). */ + uint32_t uFlags; + /** Optional data buffer. */ + void *pvData; + /** Size (in bytes) of optional data buffer. */ + uint32_t cbData; +} CALLBACKDATA_PROC_OUTPUT, *PCALLBACKDATA_PROC_OUTPUT; + +typedef struct CALLBACKDATA_PROC_INPUT +{ + /** Callback data header. */ + CALLBACKDATA_HEADER hdr; + /** The process ID (PID). */ + uint32_t uPID; + /** Current input status. */ + uint32_t uStatus; + /** Optional flags. */ + uint32_t uFlags; + /** Size (in bytes) of processed input data. */ + uint32_t uProcessed; +} CALLBACKDATA_PROC_INPUT, *PCALLBACKDATA_PROC_INPUT; + +/** + * General guest directory notification callback. + */ +typedef struct CALLBACKDATA_DIR_NOTIFY +{ + /** Callback data header. */ + CALLBACKDATA_HEADER hdr; + /** Notification type. */ + uint32_t uType; + /** IPRT result of overall operation. */ + uint32_t rc; + union + { + struct + { + /** Size (in bytes) of directory information. */ + uint32_t cbObjInfo; + /** Pointer to directory information. */ + void *pvObjInfo; + } info; + struct + { + /** Guest directory handle. */ + uint32_t uHandle; + } open; + /** Note: Close does not have any additional data (yet). */ + struct + { + /** Size (in bytes) of directory entry information. */ + uint32_t cbEntry; + /** Pointer to directory entry information. */ + void *pvEntry; + /** Size (in bytes) of directory entry object information. */ + uint32_t cbObjInfo; + /** Pointer to directory entry object information. */ + void *pvObjInfo; + } read; + } u; +} CALLBACKDATA_DIR_NOTIFY, *PCALLBACKDATA_DIR_NOTIFY; + +/** + * General guest file notification callback. + */ +typedef struct CALLBACKDATA_FILE_NOTIFY +{ + /** Callback data header. */ + CALLBACKDATA_HEADER hdr; + /** Notification type. */ + uint32_t uType; + /** IPRT result of overall operation. */ + uint32_t rc; + union + { + struct + { + /** Guest file handle. */ + uint32_t uHandle; + } open; + /** Note: Close does not have any additional data (yet). */ + struct + { + /** How much data (in bytes) have been read. */ + uint32_t cbData; + /** Actual data read (if any). */ + void *pvData; + } read; + struct + { + /** How much data (in bytes) have been successfully written. */ + uint32_t cbWritten; + } write; + struct + { + /** New file offset after successful seek. */ + uint64_t uOffActual; + } seek; + struct + { + /** New file offset after successful tell. */ + uint64_t uOffActual; + } tell; + struct + { + /** The new file siz.e */ + uint64_t cbSize; + } SetSize; + } u; +} CALLBACKDATA_FILE_NOTIFY, *PCALLBACKDATA_FILE_NOTIFY; + +} /* namespace guestControl */ + +#endif /* !VBOX_INCLUDED_HostServices_GuestControlSvc_h */ + diff --git a/include/VBox/HostServices/GuestPropertySvc.h b/include/VBox/HostServices/GuestPropertySvc.h new file mode 100644 index 00000000..806ba306 --- /dev/null +++ b/include/VBox/HostServices/GuestPropertySvc.h @@ -0,0 +1,553 @@ +/** @file + * Guest property service - Common header for host service and guest clients. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_HostServices_GuestPropertySvc_h +#define VBOX_INCLUDED_HostServices_GuestPropertySvc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/VMMDevCoreTypes.h> +#include <VBox/VBoxGuestCoreTypes.h> +#include <VBox/log.h> +#include <iprt/err.h> +#include <iprt/assertcompile.h> +#include <iprt/string.h> + + +/** Maximum size for property names (including the terminator). */ +#define GUEST_PROP_MAX_NAME_LEN 64 +/** Maximum size for property values (including the terminator). */ +#define GUEST_PROP_MAX_VALUE_LEN 1024 +/** Maximum number of properties per guest. */ +#define GUEST_PROP_MAX_PROPS 256 +/** Maximum size for enumeration patterns (including the terminators). */ +#define GUEST_PROP_MAX_PATTERN_LEN 1024 +/** Maximum number of changes we remember for guest notifications. */ +#define GUEST_PROP_MAX_GUEST_NOTIFICATIONS 256 +/** Maximum number of current pending waits per client. */ +#define GUEST_PROP_MAX_GUEST_CONCURRENT_WAITS 16 + + +/** @name GUEST_PROP_F_XXX - The guest property flag values which are currently accepted. + * @{ + */ +#define GUEST_PROP_F_NILFLAG UINT32_C(0) +/** Transient until VM gets shut down. */ +#define GUEST_PROP_F_TRANSIENT RT_BIT_32(1) +#define GUEST_PROP_F_RDONLYGUEST RT_BIT_32(2) +#define GUEST_PROP_F_RDONLYHOST RT_BIT_32(3) +/** Transient until VM gets a reset / restarts. + * Implies TRANSIENT. */ +#define GUEST_PROP_F_TRANSRESET RT_BIT_32(4) +#define GUEST_PROP_F_READONLY (GUEST_PROP_F_RDONLYGUEST | GUEST_PROP_F_RDONLYHOST) +#define GUEST_PROP_F_ALLFLAGS (GUEST_PROP_F_TRANSIENT | GUEST_PROP_F_READONLY | GUEST_PROP_F_TRANSRESET) +/** @} */ + +/** + * Check that a string fits our criteria for a property name. + * + * @returns IPRT status code + * @param pszName The string to check, must be valid Utf8 + * @param cbName The number of bytes @a pszName points to, including the + * terminating character. + */ +DECLINLINE(int) GuestPropValidateName(const char *pszName, size_t cbName) +{ + /* Property name is expected to be at least 1 charecter long plus terminating character. */ + AssertReturn(cbName >= 2, VERR_INVALID_PARAMETER); + AssertReturn(cbName <= GUEST_PROP_MAX_NAME_LEN, VERR_INVALID_PARAMETER); + + AssertPtrReturn(pszName, VERR_INVALID_POINTER); + + AssertReturn(memchr(pszName, '*', cbName) == NULL, VERR_INVALID_PARAMETER); + AssertReturn(memchr(pszName, '?', cbName) == NULL, VERR_INVALID_PARAMETER); + AssertReturn(memchr(pszName, '|', cbName) == NULL, VERR_INVALID_PARAMETER); + + return VINF_SUCCESS; +} + +/** + * Check a string fits our criteria for the value of a guest property. + * + * @returns IPRT status code + * @retval VINF_SUCCESS if guest property value corresponds to all criteria. + * @retval VERR_TOO_MUCH_DATA if guest property value size exceeds limits. + * @retval VERR_INVALID_PARAMETER if guest property does not correspond to all other criteria. + * @param pszValue The string to check, must be valid utf-8. + * @param cbValue The size of of @a pszValue in bytes, including the + * terminator. + * @thread HGCM + */ +DECLINLINE(int) GuestPropValidateValue(const char *pszValue, size_t cbValue) +{ + AssertPtrReturn(pszValue, VERR_INVALID_POINTER); + + /* Zero-length values are possible, however buffer should contain terminating character at least. */ + AssertReturn(cbValue > 0, VERR_INVALID_PARAMETER); + AssertReturn(cbValue <= GUEST_PROP_MAX_VALUE_LEN, VERR_TOO_MUCH_DATA); + + return VINF_SUCCESS; +} + +/** + * Get the name of a flag as a string. + * @returns the name, or NULL if fFlag is invalid. + * @param fFlag The flag, GUEST_PROP_F_XXX. + * @param pcchName Where to return the name length. + */ +DECLINLINE(const char *) GuestPropFlagNameAndLen(uint32_t fFlag, size_t *pcchName) +{ + switch (fFlag) + { + case GUEST_PROP_F_TRANSIENT: + *pcchName = sizeof("TRANSIENT") - 1; + return "TRANSIENT"; + case GUEST_PROP_F_RDONLYGUEST: + *pcchName = sizeof("RDONLYGUEST") - 1; + return "RDONLYGUEST"; + case GUEST_PROP_F_RDONLYHOST: + *pcchName = sizeof("RDONLYHOST") - 1; + return "RDONLYHOST"; + case GUEST_PROP_F_READONLY: + *pcchName = sizeof("READONLY") - 1; + return "READONLY"; + case GUEST_PROP_F_TRANSRESET: + *pcchName = sizeof("TRANSRESET") - 1; + return "TRANSRESET"; + default: + *pcchName = 0; + return NULL; + } +} + +/** + * Maximum length for the property flags field. We only ever return one of + * RDONLYGUEST, RDONLYHOST and RDONLY + */ +#define GUEST_PROP_MAX_FLAGS_LEN sizeof("TRANSIENT, RDONLYGUEST, TRANSRESET") + +/** + * Parse a guest properties flags string for flag names and make sure that + * there is no junk text in the string. + * + * @returns IPRT status code + * @retval VERR_INVALID_PARAMETER if the flag string is not valid + * @param pcszFlags the flag string to parse + * @param pfFlags where to store the parse result. May not be NULL. + * @note This function is also inline because it must be accessible from + * several modules and it does not seem reasonable to put it into + * its own library. + */ +DECLINLINE(int) GuestPropValidateFlags(const char *pcszFlags, uint32_t *pfFlags) +{ + static const uint32_t s_aFlagList[] = + { + GUEST_PROP_F_TRANSIENT, GUEST_PROP_F_READONLY, GUEST_PROP_F_RDONLYGUEST, GUEST_PROP_F_RDONLYHOST, GUEST_PROP_F_TRANSRESET + }; + const char *pcszNext = pcszFlags; + int rc = VINF_SUCCESS; + uint32_t fFlags = 0; + AssertLogRelReturn(RT_VALID_PTR(pfFlags), VERR_INVALID_POINTER); + + if (pcszFlags) + { + while (*pcszNext == ' ') + ++pcszNext; + while ((*pcszNext != '\0') && RT_SUCCESS(rc)) + { + unsigned i; + rc = VERR_PARSE_ERROR; + for (i = 0; i < RT_ELEMENTS(s_aFlagList); ++i) + { + size_t cchFlagName; + const char *pszFlagName = GuestPropFlagNameAndLen(s_aFlagList[i], &cchFlagName); + if (RTStrNICmpAscii(pcszNext, pszFlagName, cchFlagName) == 0) + { + char ch; + fFlags |= s_aFlagList[i]; + pcszNext += cchFlagName; + while ((ch = *pcszNext) == ' ') + ++pcszNext; + rc = VINF_SUCCESS; + if (ch == ',') + { + ++pcszNext; + while (*pcszNext == ' ') + ++pcszNext; + } + else if (ch != '\0') + rc = VERR_PARSE_ERROR; + break; + } + } + } + } + if (RT_SUCCESS(rc)) + *pfFlags = fFlags; + return rc; +} + + +/** + * Write out flags to a string. + * @returns IPRT status code + * @param fFlags the flags to write out + * @param pszFlags where to write the flags string. This must point to + * a buffer of size (at least) GUEST_PROP_MAX_FLAGS_LEN. + */ +DECLINLINE(int) GuestPropWriteFlags(uint32_t fFlags, char *pszFlags) +{ + /* Putting READONLY before the other RDONLY flags keeps the result short. */ + static const uint32_t s_aFlagList[] = + { + GUEST_PROP_F_TRANSIENT, GUEST_PROP_F_READONLY, GUEST_PROP_F_RDONLYGUEST, GUEST_PROP_F_RDONLYHOST, GUEST_PROP_F_TRANSRESET + }; + int rc = VINF_SUCCESS; + + AssertLogRelReturn(RT_VALID_PTR(pszFlags), VERR_INVALID_POINTER); + if ((fFlags & ~GUEST_PROP_F_ALLFLAGS) == GUEST_PROP_F_NILFLAG) + { + char *pszNext; + unsigned i; + + /* TRANSRESET implies TRANSIENT. For compatability with old clients we + always set TRANSIENT when TRANSRESET appears. */ + if (fFlags & GUEST_PROP_F_TRANSRESET) + fFlags |= GUEST_PROP_F_TRANSIENT; + + pszNext = pszFlags; + for (i = 0; i < RT_ELEMENTS(s_aFlagList); ++i) + { + if (s_aFlagList[i] == (fFlags & s_aFlagList[i])) + { + size_t cchFlagName; + const char *pszFlagName = GuestPropFlagNameAndLen(s_aFlagList[i], &cchFlagName); + memcpy(pszNext, pszFlagName, cchFlagName); + pszNext += cchFlagName; + fFlags &= ~s_aFlagList[i]; + if (fFlags != GUEST_PROP_F_NILFLAG) + { + *pszNext++ = ','; + *pszNext++ = ' '; + } + } + } + *pszNext = '\0'; + + Assert((uintptr_t)(pszNext - pszFlags) < GUEST_PROP_MAX_FLAGS_LEN); + Assert(fFlags == GUEST_PROP_F_NILFLAG); /* bad s_aFlagList */ + } + else + rc = VERR_INVALID_PARAMETER; + return rc; +} + + +/** @name The service functions which are callable by host. + * @{ + */ +/** Set properties in a block. + * The parameters are pointers to NULL-terminated arrays containing the + * parameters. These are, in order, name, value, timestamp, flags. Strings are + * stored as pointers to mutable utf8 data. All parameters must be supplied. */ +#define GUEST_PROP_FN_HOST_SET_PROPS 1 +/** Get the value attached to a guest property. + * The parameter format matches that of GET_PROP. */ +#define GUEST_PROP_FN_HOST_GET_PROP 2 +/** Set the value attached to a guest property. + * The parameter format matches that of SET_PROP. */ +#define GUEST_PROP_FN_HOST_SET_PROP 3 +/** Set the value attached to a guest property. + * The parameter format matches that of SET_PROP_VALUE. */ +#define GUEST_PROP_FN_HOST_SET_PROP_VALUE 4 +/** Remove a guest property. + * The parameter format matches that of DEL_PROP. */ +#define GUEST_PROP_FN_HOST_DEL_PROP 5 +/** Enumerate guest properties. + * The parameter format matches that of ENUM_PROPS. */ +#define GUEST_PROP_FN_HOST_ENUM_PROPS 6 +/** Set global flags for the service. + * Currently RDONLYGUEST is supported. Takes one 32-bit unsigned integer + * parameter for the flags. */ +#define GUEST_PROP_FN_HOST_SET_GLOBAL_FLAGS 7 +/** @} */ + + +/** @name The service functions which are called by guest. + * + * @note The numbers may not change! + * @{ + */ +/** Get a guest property */ +#define GUEST_PROP_FN_GET_PROP 1 +/** Set a guest property */ +#define GUEST_PROP_FN_SET_PROP 2 +/** Set just the value of a guest property */ +#define GUEST_PROP_FN_SET_PROP_VALUE 3 +/** Delete a guest property */ +#define GUEST_PROP_FN_DEL_PROP 4 +/** Enumerate guest properties */ +#define GUEST_PROP_FN_ENUM_PROPS 5 +/** Poll for guest notifications */ +#define GUEST_PROP_FN_GET_NOTIFICATION 6 +/** @} */ + + +/** + * Data structure to pass to the service extension callback. + * We use this to notify the host of changes to properties. + */ +typedef struct GUESTPROPHOSTCALLBACKDATA +{ + /** Magic number to identify the structure (GUESTPROPHOSTCALLBACKDATA_MAGIC). */ + uint32_t u32Magic; + /** The name of the property that was changed */ + const char *pcszName; + /** The new property value, or NULL if the property was deleted */ + const char *pcszValue; + /** The timestamp of the modification */ + uint64_t u64Timestamp; + /** The flags field of the modified property */ + const char *pcszFlags; +} GUESTPROPHOSTCALLBACKDATA; +/** Poitner to a data structure to pass to the service extension callback. */ +typedef GUESTPROPHOSTCALLBACKDATA *PGUESTPROPHOSTCALLBACKDATA; + +/** Magic number for sanity checking the HOSTCALLBACKDATA structure */ +#define GUESTPROPHOSTCALLBACKDATA_MAGIC UINT32_C(0x69c87a78) + +/** + * HGCM parameter structures. Packing is explicitly defined as this is a wire format. + */ +/** The guest is requesting the value of a property */ +typedef struct GuestPropMsgGetProperty +{ + VBGLIOCHGCMCALL hdr; + + /** + * The property name (IN pointer) + * This must fit to a number of criteria, namely + * - Only Utf8 strings are allowed + * - Less than or equal to MAX_NAME_LEN bytes in length + * - Zero terminated + */ + HGCMFunctionParameter name; + + /** + * The returned string data will be placed here. (OUT pointer) + * This call returns two null-terminated strings which will be placed one + * after another: value and flags. + */ + HGCMFunctionParameter buffer; + + /** + * The property timestamp. (OUT uint64_t) + */ + HGCMFunctionParameter timestamp; + + /** + * If the buffer provided was large enough this will contain the size of + * the returned data. Otherwise it will contain the size of the buffer + * needed to hold the data and VERR_BUFFER_OVERFLOW will be returned. + * (OUT uint32_t) + */ + HGCMFunctionParameter size; +} GuestPropMsgGetProperty; +AssertCompileSize(GuestPropMsgGetProperty, 40 + 4 * (ARCH_BITS == 64 ? 16 : 12)); + +/** The guest is requesting to change a property */ +typedef struct GuestPropMsgSetProperty +{ + VBGLIOCHGCMCALL hdr; + + /** + * The property name. (IN pointer) + * This must fit to a number of criteria, namely + * - Only Utf8 strings are allowed + * - Less than or equal to MAX_NAME_LEN bytes in length + * - Zero terminated + */ + HGCMFunctionParameter name; + + /** + * The value of the property (IN pointer) + * Criteria as for the name parameter, but with length less than or equal to + * MAX_VALUE_LEN. + */ + HGCMFunctionParameter value; + + /** + * The property flags (IN pointer) + * This is a comma-separated list of the format flag=value + * The length must be less than or equal to GUEST_PROP_MAX_FLAGS_LEN and only + * known flag names and values will be accepted. + */ + HGCMFunctionParameter flags; +} GuestPropMsgSetProperty; +AssertCompileSize(GuestPropMsgSetProperty, 40 + 3 * (ARCH_BITS == 64 ? 16 : 12)); + +/** The guest is requesting to change the value of a property */ +typedef struct GuestPropMsgSetPropertyValue +{ + VBGLIOCHGCMCALL hdr; + + /** + * The property name. (IN pointer) + * This must fit to a number of criteria, namely + * - Only Utf8 strings are allowed + * - Less than or equal to MAX_NAME_LEN bytes in length + * - Zero terminated + */ + HGCMFunctionParameter name; + + /** + * The value of the property (IN pointer) + * Criteria as for the name parameter, but with length less than or equal to + * MAX_VALUE_LEN. + */ + HGCMFunctionParameter value; +} GuestPropMsgSetPropertyValue; +AssertCompileSize(GuestPropMsgSetPropertyValue, 40 + 2 * (ARCH_BITS == 64 ? 16 : 12)); + +/** The guest is requesting to remove a property */ +typedef struct GuestPropMsgDelProperty +{ + VBGLIOCHGCMCALL hdr; + + /** + * The property name. This must fit to a number of criteria, namely + * - Only Utf8 strings are allowed + * - Less than or equal to MAX_NAME_LEN bytes in length + * - Zero terminated + */ + HGCMFunctionParameter name; +} GuestPropMsgDelProperty; +AssertCompileSize(GuestPropMsgDelProperty, 40 + 1 * (ARCH_BITS == 64 ? 16 : 12)); + +/** The guest is requesting to enumerate properties */ +typedef struct GuestPropMsgEnumProperties +{ + VBGLIOCHGCMCALL hdr; + + /** + * Array of patterns to match the properties against, separated by '|' + * characters. For backwards compatibility, '\\0' is also accepted + * as a separater. + * (IN pointer) + * If only a single, empty pattern is given then match all. + */ + HGCMFunctionParameter patterns; + /** + * On success, null-separated array of strings in which the properties are + * returned. (OUT pointer) + * The number of strings in the array is always a multiple of four, + * and in sequences of name, value, timestamp (hexadecimal string) and the + * flags as a comma-separated list in the format "name=value". The list + * is terminated by an empty string after a "flags" entry (or at the + * start). + */ + HGCMFunctionParameter strings; + /** + * On success, the size of the returned data. If the buffer provided is + * too small, the size of buffer needed. (OUT uint32_t) + */ + HGCMFunctionParameter size; +} GuestPropMsgEnumProperties; +AssertCompileSize(GuestPropMsgEnumProperties, 40 + 3 * (ARCH_BITS == 64 ? 16 : 12)); + +/** + * The guest is polling for notifications on changes to properties, specifying + * a set of patterns to match the names of changed properties against and + * optionally the timestamp of the last notification seen. + * On success, VINF_SUCCESS will be returned and the buffer will contain + * details of a property notification. If no new notification is available + * which matches one of the specified patterns, the call will block until one + * is. + * If the last notification could not be found by timestamp, VWRN_NOT_FOUND + * will be returned and the oldest available notification will be returned. + * If a zero timestamp is specified, the call will always wait for a new + * notification to arrive. + * If the buffer supplied was not large enough to hold the notification, + * VERR_BUFFER_OVERFLOW will be returned and the size parameter will contain + * the size of the buffer needed. + * + * The protocol for a guest to obtain notifications is to call + * GET_NOTIFICATION in a loop. On the first call, the ingoing timestamp + * parameter should be set to zero. On subsequent calls, it should be set to + * the outgoing timestamp from the previous call. + */ +typedef struct GuestPropMsgGetNotification +{ + VBGLIOCHGCMCALL hdr; + + /** + * A list of patterns to match the guest event name against, separated by + * vertical bars (|) (IN pointer) + * An empty string means match all. + */ + HGCMFunctionParameter patterns; + /** + * The timestamp of the last change seen (IN uint64_t) + * This may be zero, in which case the oldest available change will be + * sent. If the service does not remember an event matching the + * timestamp, then VWRN_NOT_FOUND will be returned, and the guest should + * assume that it has missed a certain number of notifications. + * + * The timestamp of the change being notified of (OUT uint64_t) + * Undefined on failure. + */ + HGCMFunctionParameter timestamp; + + /** + * The returned data, if any, will be placed here. (OUT pointer) + * This call returns three null-terminated strings which will be placed + * one after another: name, value and flags. For a delete notification, + * value and flags will be empty strings. Undefined on failure. + */ + HGCMFunctionParameter buffer; + + /** + * On success, the size of the returned data. (OUT uint32_t) + * On buffer overflow, the size of the buffer needed to hold the data. + * Undefined on failure. + */ + HGCMFunctionParameter size; +} GuestPropMsgGetNotification; +AssertCompileSize(GuestPropMsgGetNotification, 40 + 4 * (ARCH_BITS == 64 ? 16 : 12)); + + +#endif /* !VBOX_INCLUDED_HostServices_GuestPropertySvc_h */ + diff --git a/include/VBox/HostServices/Makefile.kup b/include/VBox/HostServices/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/VBox/HostServices/Makefile.kup diff --git a/include/VBox/HostServices/Service.h b/include/VBox/HostServices/Service.h new file mode 100644 index 00000000..d45512cb --- /dev/null +++ b/include/VBox/HostServices/Service.h @@ -0,0 +1,358 @@ +/** @file + * Base class for an host-guest service. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_HostServices_Service_h +#define VBOX_INCLUDED_HostServices_Service_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/log.h> +#include <VBox/hgcmsvc.h> + +#include <iprt/assert.h> +#include <iprt/alloc.h> +#include <iprt/cpp/utils.h> + +#include <new> + + +namespace HGCM +{ + +/** + * Structure for keeping a HGCM service context. + */ +typedef struct VBOXHGCMSVCTX +{ + /** HGCM helper functions. */ + PVBOXHGCMSVCHELPERS pHelpers; + /** + * Callback function supplied by the host for notification of updates + * to properties. + */ + PFNHGCMSVCEXT pfnHostCallback; + /** User data pointer to be supplied to the host callback function. */ + void *pvHostData; +} VBOXHGCMSVCTX, *PVBOXHGCMSVCTX; + +/** + * Base class encapsulating and working with a HGCM message. + */ +class Message +{ +public: + Message(void); + Message(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]); + virtual ~Message(void); + + uint32_t GetParamCount(void) const RT_NOEXCEPT; + int GetData(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]) const RT_NOEXCEPT; + int GetParmU32(uint32_t uParm, uint32_t *pu32Info) const RT_NOEXCEPT; + int GetParmU64(uint32_t uParm, uint64_t *pu64Info) const RT_NOEXCEPT; + int GetParmPtr(uint32_t uParm, void **ppvAddr, uint32_t *pcbSize) const RT_NOEXCEPT; + uint32_t GetType(void) const RT_NOEXCEPT; + +public: + static int CopyParms(PVBOXHGCMSVCPARM paParmsDst, uint32_t cParmsDst, + PVBOXHGCMSVCPARM paParmsSrc, uint32_t cParmsSrc, + bool fDeepCopy) RT_NOEXCEPT; + +protected: + int initData(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]) RT_NOEXCEPT; + void reset() RT_NOEXCEPT; + +protected: + + /** Stored message type. */ + uint32_t m_uMsg; + /** Number of stored HGCM parameters. */ + uint32_t m_cParms; + /** Stored HGCM parameters. */ + PVBOXHGCMSVCPARM m_paParms; +}; + +/** + * Class for keeping and tracking a HGCM client. + */ +class Client +{ +public: + Client(uint32_t idClient); + virtual ~Client(void); + +public: + int Complete(VBOXHGCMCALLHANDLE hHandle, int rcOp = VINF_SUCCESS) RT_NOEXCEPT; + int CompleteDeferred(int rcOp = VINF_SUCCESS) RT_NOEXCEPT; + uint32_t GetClientID(void) const RT_NOEXCEPT; + VBOXHGCMCALLHANDLE GetHandle(void) const RT_NOEXCEPT; + uint32_t GetMsgType(void) const RT_NOEXCEPT; + uint32_t GetMsgParamCount(void) const RT_NOEXCEPT; + bool IsDeferred(void) const RT_NOEXCEPT; + void SetDeferred(VBOXHGCMCALLHANDLE hHandle, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT; + void SetSvcContext(const VBOXHGCMSVCTX &SvcCtx) RT_NOEXCEPT; + +public: + int SetDeferredMsgInfo(uint32_t uMsg, uint32_t cParms) RT_NOEXCEPT; + int SetDeferredMsgInfo(const Message *pMessage) RT_NOEXCEPT; + +protected: + int completeInternal(VBOXHGCMCALLHANDLE hHandle, int rcOp) RT_NOEXCEPT; + void reset(void) RT_NOEXCEPT; + +protected: + /** The client's HGCM client ID. */ + uint32_t m_idClient; + /** The HGCM service context this client is bound to. */ + VBOXHGCMSVCTX m_SvcCtx; + /** Flag indicating whether this client currently is deferred mode, + * meaning that it did not return to the caller yet. */ + bool m_fDeferred; + /** Structure for keeping the client's deferred state. + * A client is in a deferred state when it asks for the next HGCM message, + * but the service can't provide it yet. That way a client will block (on the guest side, does not return) + * until the service can complete the call. */ + struct + { + /** The client's HGCM call handle. Needed for completing a deferred call. */ + VBOXHGCMCALLHANDLE hHandle; + /** Message type (function number) to use when completing the deferred call. + * @todo r=bird: uType or uMsg? Make up your mind (Message::m_uMsg). */ + uint32_t uType; + /** Parameter count to use when completing the deferred call. */ + uint32_t cParms; + /** Parameters to use when completing the deferred call. */ + PVBOXHGCMSVCPARM paParms; + } m_Deferred; +}; + +template <class T> +class AbstractService : public RTCNonCopyable +{ +public: + /** + * @copydoc FNVBOXHGCMSVCLOAD + */ + static DECLCALLBACK(int) svcLoad(VBOXHGCMSVCFNTABLE *pTable) + { + LogFlowFunc(("ptable = %p\n", pTable)); + int rc = VINF_SUCCESS; + + if (!RT_VALID_PTR(pTable)) + rc = VERR_INVALID_PARAMETER; + else + { + LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", pTable->cbSize, pTable->u32Version)); + + if ( pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE) + || pTable->u32Version != VBOX_HGCM_SVC_VERSION) + rc = VERR_VERSION_MISMATCH; + else + { + AbstractService *pService = NULL; + /* No exceptions may propagate outside (callbacks like this one are nothrow/noexcept). */ + try { pService = new T(pTable->pHelpers); } + catch (std::bad_alloc &) { rc = VERR_NO_MEMORY; } + catch (...) { rc = VERR_UNEXPECTED_EXCEPTION; } + if (RT_SUCCESS(rc)) + { + /* We don't need an additional client data area on the host, + because we're a class which can have members for that :-). */ + /** @todo r=bird: What the comment above says is that we can duplicate the + * work of associating data with a client ID already done by the HGCM and create + * additional bugs because we think that's cool. It's not. Utterly + * appalling as well as inefficient. Just a structure with a pointer to a + * client base class would go a long way here. */ + pTable->cbClient = 0; + + /* These functions are mandatory */ + pTable->pfnUnload = svcUnload; + pTable->pfnConnect = svcConnect; + pTable->pfnDisconnect = svcDisconnect; + pTable->pfnCall = svcCall; + /* Clear obligatory functions. */ + pTable->pfnHostCall = NULL; + pTable->pfnSaveState = NULL; + pTable->pfnLoadState = NULL; + pTable->pfnRegisterExtension = NULL; + + /* Let the service itself initialize. */ + rc = pService->init(pTable); + if (RT_SUCCESS(rc)) + pTable->pvService = pService; + else + delete pService; + } + } + } + + LogFlowFunc(("returning %Rrc\n", rc)); + return rc; + } + virtual ~AbstractService() {}; + +protected: + explicit AbstractService(PVBOXHGCMSVCHELPERS pHelpers) + { + RT_ZERO(m_SvcCtx); + m_SvcCtx.pHelpers = pHelpers; + } + virtual int init(VBOXHGCMSVCFNTABLE *ptable) RT_NOEXCEPT + { RT_NOREF1(ptable); return VINF_SUCCESS; } + virtual int uninit() RT_NOEXCEPT + { return VINF_SUCCESS; } + virtual int clientConnect(uint32_t idClient, void *pvClient) RT_NOEXCEPT = 0; + virtual int clientDisconnect(uint32_t idClient, void *pvClient) RT_NOEXCEPT = 0; + virtual void guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t idClient, void *pvClient, uint32_t eFunction, + uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT = 0; + virtual int hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT + { RT_NOREF3(eFunction, cParms, paParms); return VINF_SUCCESS; } + + /** Type definition for use in callback functions. */ + typedef AbstractService SELF; + /** The HGCM service context this service is bound to. */ + VBOXHGCMSVCTX m_SvcCtx; + + /** + * @copydoc VBOXHGCMSVCFNTABLE::pfnUnload + * Simply deletes the service object + */ + static DECLCALLBACK(int) svcUnload(void *pvService) + { + AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER); + SELF *pSelf = reinterpret_cast<SELF *>(pvService); + int rc = pSelf->uninit(); + AssertRC(rc); + if (RT_SUCCESS(rc)) + delete pSelf; + return rc; + } + + /** + * @copydoc VBOXHGCMSVCFNTABLE::pfnConnect + * Stub implementation of pfnConnect and pfnDisconnect. + */ + static DECLCALLBACK(int) svcConnect(void *pvService, + uint32_t idClient, + void *pvClient, + uint32_t fRequestor, + bool fRestoring) + { + RT_NOREF(fRequestor, fRestoring); + AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER); + LogFlowFunc(("pvService=%p, idClient=%u, pvClient=%p\n", pvService, idClient, pvClient)); + SELF *pSelf = reinterpret_cast<SELF *>(pvService); + int rc = pSelf->clientConnect(idClient, pvClient); + LogFlowFunc(("rc=%Rrc\n", rc)); + return rc; + } + + /** + * @copydoc VBOXHGCMSVCFNTABLE::pfnConnect + * Stub implementation of pfnConnect and pfnDisconnect. + */ + static DECLCALLBACK(int) svcDisconnect(void *pvService, + uint32_t idClient, + void *pvClient) + { + AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER); + LogFlowFunc(("pvService=%p, idClient=%u, pvClient=%p\n", pvService, idClient, pvClient)); + SELF *pSelf = reinterpret_cast<SELF *>(pvService); + int rc = pSelf->clientDisconnect(idClient, pvClient); + LogFlowFunc(("rc=%Rrc\n", rc)); + return rc; + } + + /** + * @copydoc VBOXHGCMSVCFNTABLE::pfnCall + * Wraps to the call member function + */ + static DECLCALLBACK(void) svcCall(void *pvService, + VBOXHGCMCALLHANDLE callHandle, + uint32_t idClient, + void *pvClient, + uint32_t u32Function, + uint32_t cParms, + VBOXHGCMSVCPARM paParms[], + uint64_t tsArrival) + { + AssertLogRelReturnVoid(RT_VALID_PTR(pvService)); + LogFlowFunc(("pvService=%p, callHandle=%p, idClient=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n", + pvService, callHandle, idClient, pvClient, u32Function, cParms, paParms)); + SELF *pSelf = reinterpret_cast<SELF *>(pvService); + pSelf->guestCall(callHandle, idClient, pvClient, u32Function, cParms, paParms); + LogFlowFunc(("returning\n")); + RT_NOREF_PV(tsArrival); + } + + /** + * @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall + * Wraps to the hostCall member function + */ + static DECLCALLBACK(int) svcHostCall(void *pvService, + uint32_t u32Function, + uint32_t cParms, + VBOXHGCMSVCPARM paParms[]) + { + AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER); + LogFlowFunc(("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms)); + SELF *pSelf = reinterpret_cast<SELF *>(pvService); + int rc = pSelf->hostCall(u32Function, cParms, paParms); + LogFlowFunc(("rc=%Rrc\n", rc)); + return rc; + } + + /** + * @copydoc VBOXHGCMSVCFNTABLE::pfnRegisterExtension + * Installs a host callback for notifications of property changes. + */ + static DECLCALLBACK(int) svcRegisterExtension(void *pvService, + PFNHGCMSVCEXT pfnExtension, + void *pvExtension) + { + AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER); + LogFlowFunc(("pvService=%p, pfnExtension=%p, pvExtention=%p\n", pvService, pfnExtension, pvExtension)); + SELF *pSelf = reinterpret_cast<SELF *>(pvService); + pSelf->m_SvcCtx.pfnHostCallback = pfnExtension; + pSelf->m_SvcCtx.pvHostData = pvExtension; + return VINF_SUCCESS; + } + + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AbstractService); +}; + +} +#endif /* !VBOX_INCLUDED_HostServices_Service_h */ + diff --git a/include/VBox/HostServices/VBoxClipboardExt.h b/include/VBox/HostServices/VBoxClipboardExt.h new file mode 100644 index 00000000..d93acf23 --- /dev/null +++ b/include/VBox/HostServices/VBoxClipboardExt.h @@ -0,0 +1,66 @@ +/** @file + * Shared Clipboard - Common header for the service extension. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_HostServices_VBoxClipboardExt_h +#define VBOX_INCLUDED_HostServices_VBoxClipboardExt_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +# include <VBox/GuestHost/SharedClipboard-transfers.h> +#endif + +#define VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK (0) +#define VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE (1) +#define VBOX_CLIPBOARD_EXT_FN_DATA_READ (2) +#define VBOX_CLIPBOARD_EXT_FN_DATA_WRITE (3) + +typedef DECLCALLBACKTYPE(int, FNVRDPCLIPBOARDEXTCALLBACK,(uint32_t u32Function, uint32_t u32Format, void *pvData, uint32_t cbData)); +typedef FNVRDPCLIPBOARDEXTCALLBACK *PFNVRDPCLIPBOARDEXTCALLBACK; + +typedef struct _SHCLEXTPARMS +{ + uint32_t uFormat; + union + { + void *pvData; + PFNVRDPCLIPBOARDEXTCALLBACK pfnCallback; + } u; + uint32_t cbData; +} SHCLEXTPARMS; + +#endif /* !VBOX_INCLUDED_HostServices_VBoxClipboardExt_h */ diff --git a/include/VBox/HostServices/VBoxClipboardSvc.h b/include/VBox/HostServices/VBoxClipboardSvc.h new file mode 100644 index 00000000..45bb954a --- /dev/null +++ b/include/VBox/HostServices/VBoxClipboardSvc.h @@ -0,0 +1,1220 @@ +/** @file + * Shared Clipboard - Common header for host service and guest clients. + * + * Protocol history notes (incomplete): + * + * - VirtualBox 6.1.0 betas: Started work on adding support for copying & + * pasting files and directories, refactoring the protocol in the process. + * - Adds guest/host feature flags. + * - Adds context IDs (via guest feature flags). + * - Borrowed the message handling from guest controls. + * - Adds a multitude of functions and messages for dealing with file & dir + * copying, most inte + * + * - VirtualBox x.x.x: Missing a lot of gradual improvements here. + * + * - VirtualBox 1.3.2 (r17182): Initial implementation, supporting text. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_HostServices_VBoxClipboardSvc_h +#define VBOX_INCLUDED_HostServices_VBoxClipboardSvc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/VMMDevCoreTypes.h> +#include <VBox/VBoxGuestCoreTypes.h> +#include <VBox/hgcmsvc.h> + + +/** @name VBOX_SHCL_MODE_XXX - The Shared Clipboard modes of operation. + * @{ + */ +/** Shared Clipboard is disabled completely. */ +#define VBOX_SHCL_MODE_OFF 0 +/** Only transfers from host to the guest are possible. */ +#define VBOX_SHCL_MODE_HOST_TO_GUEST 1 +/** Only transfers from guest to the host are possible. */ +#define VBOX_SHCL_MODE_GUEST_TO_HOST 2 +/** Bidirectional transfers between guest and host are possible. */ +#define VBOX_SHCL_MODE_BIDIRECTIONAL 3 +/** @} */ + +/** @name VBOX_SHCL_TRANSFER_MODE_XXX - The Shared Clipboard file transfer mode (bit field). + * @{ + */ +/** Shared Clipboard file transfers are disabled. */ +#define VBOX_SHCL_TRANSFER_MODE_DISABLED UINT32_C(0) +/** Shared Clipboard file transfers are enabled. */ +#define VBOX_SHCL_TRANSFER_MODE_ENABLED RT_BIT(0) +/** Shared Clipboard file transfer mode valid mask. */ +#define VBOX_SHCL_TRANSFER_MODE_VALID_MASK UINT32_C(0x1) +/** @} */ + + +/** @name VBOX_SHCL_HOST_FN_XXX - The service functions which are callable by host. + * @note These are not sacred and can be modified at will as long as all host + * clients are updated accordingly (probably just Main). + * @{ + */ +/** Sets the current Shared Clipboard operation mode. */ +#define VBOX_SHCL_HOST_FN_SET_MODE 1 +/** Sets the current Shared Clipboard (file) transfers mode. + * Operates on the VBOX_SHCL_TRANSFERS_XXX defines. + * @since 6.1 */ +#define VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE 2 +/** Run headless on the host, i.e. do not touch the host clipboard. */ +#define VBOX_SHCL_HOST_FN_SET_HEADLESS 3 + +/** Reports cancellation of the current operation to the guest. + * @since 6.1 - still a todo */ +#define VBOX_SHCL_HOST_FN_CANCEL 4 +/** Reports an error to the guest. + * @since 6.1 - still a todo */ +#define VBOX_SHCL_HOST_FN_ERROR 5 +/** @} */ + + +/** @name VBOX_SHCL_HOST_MSG_XXX - The host messages for the guest. + * @{ + */ +/** Returned only when the HGCM client session is closed (by different thread). + * + * This can require no futher host interaction since the session has been + * closed. + * + * @since 1.3.2 + */ +#define VBOX_SHCL_HOST_MSG_QUIT 1 +/** Request data for a specific format from the guest. + * + * Two parameters, first the 32-bit message ID followed by a 32-bit format bit + * (VBOX_SHCL_FMT_XXX). The guest will respond by issuing a + * VBOX_SHCL_GUEST_FN_DATA_WRITE. + * + * @note The host may sometimes incorrectly set more than one format bit, in + * which case it's up to the guest to pick which to write back. + * @since 1.3.2 + */ +#define VBOX_SHCL_HOST_MSG_READ_DATA 2 +/** Reports available clipboard format on the host to the guest. + * + * Two parameters, first the 32-bit message ID followed by a 32-bit format mask + * containing zero or more VBOX_SHCL_FMT_XXX flags. The guest is not require to + * respond to the host when receiving this message. + * + * @since 1.3.2 + */ +#define VBOX_SHCL_HOST_MSG_FORMATS_REPORT 3 +/** Message PEEK or GET operation was canceled, try again. + * + * This is returned by VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT and + * VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT in response to the guest calling + * VBOX_SHCL_GUEST_FN_MSG_CANCEL. The 2nd parameter is set to zero (be it + * thought of as a parameter count or a format mask). + * + * @since 6.1.0 + */ +#define VBOX_SHCL_HOST_MSG_CANCELED 4 + +/** Request data for a specific format from the guest with context ID. + * + * This is send instead of the VBOX_SHCL_HOST_MSG_READ_DATA message to guest + * that advertises VBOX_SHCL_GF_0_CONTEXT_ID. The first parameter is a 64-bit + * context ID which is to be used when issuing VBOX_SHCL_GUEST_F_DATA_WRITE, and + * the second parameter is a 32-bit format bit (VBOX_SHCL_FMT_XXX). The guest + * will respond by issuing a VBOX_SHCL_GUEST_F_DATA_WRITE. + * + * @note The host may sometimes incorrectly set more than one format bit, in + * which case it's up to the guest to pick which to write back. + * @since 6.1.2 + */ +#define VBOX_SHCL_HOST_MSG_READ_DATA_CID 5 + +/** Sends a transfer status to the guest side. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_STATUS 50 +/** Reads the root list header from the guest. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ 51 +/** Writes the root list header to the guest. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_WRITE 52 +/** Reads a root list entry from the guest. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ 53 +/** Writes a root list entry to the guest. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_WRITE 54 +/** Open a transfer list on the guest side. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN 55 +/** Closes a formerly opened transfer list on the guest side. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE 56 +/** Reads a list header from the guest. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ 57 +/** Writes a list header to the guest. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_WRITE 58 +/** Reads a list entry from the guest. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ 59 +/** Writes a list entry to the guest. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_WRITE 60 +/** Open a transfer object on the guest side. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN 61 +/** Closes a formerly opened transfer object on the guest side. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE 62 +/** Reads from an object on the guest side. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ 63 +/** Writes to an object on the guest side. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_WRITE 64 +/** Indicates that the host has canceled a transfer. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_CANCEL 65 +/** Indicates that the an unrecoverable error on the host occurred. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_ERROR 66 +/** @} */ + + +/** @name VBOX_SHCL_GUEST_FN_XXX - The service functions which are called by guest. + * @{ + */ +/** Calls the host and waits (blocking) for an host event VBOX_SHCL_HOST_MSG_XXX. + * + * @deprecated Replaced by VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT, + * VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_GUEST_FN_MSG_CANCEL. + * @since 1.3.2 + */ +#define VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT 1 +/** Sends a list of available formats to the host. + * + * This function takes a single parameter, a 32-bit set of formats + * (VBOX_SHCL_FMT_XXX), this can be zero if the clipboard is empty or previously + * reported formats are no longer avaible (logout, shutdown, whatever). + * + * There was a period during 6.1 development where it would take three + * parameters, a 64-bit context ID preceeded the formats and a 32-bit MBZ flags + * parameter was appended. This is still accepted, though deprecated. + * + * @returns May return informational statuses indicating partial success, just + * ignore it. + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @retval VERR_NOT_SUPPORTED if all the formats are unsupported, host + * clipboard will be empty. + * @since 1.3.2 + */ +#define VBOX_SHCL_GUEST_FN_REPORT_FORMATS 2 +/** Reads data in specified format from the host. + * + * This function takes three parameters, a 32-bit format bit + * (VBOX_SHCL_FMT_XXX), a buffer and 32-bit number of bytes read (output). + * + * There was a period during 6.1 development where it would take five parameters + * when VBOX_SHCL_GF_0_CONTEXT_ID was reported by the guest. A 64-bit context + * ID (ignored as purpose undefined), a 32-bit unused flag (MBZ), then the + * 32-bit format bits, number of bytes read (output), and the buffer. This + * format is still accepted. + * + * @retval VINF_SUCCESS on success. + * @retval VINF_BUFFER_OVERLFLOW (VBox >= 6.1 only) if not enough buffer space + * has been given to retrieve the actual data, no data actually copied. + * The call then must be repeated with a buffer size returned from the + * host in cbData. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 1.3.2 + */ +#define VBOX_SHCL_GUEST_FN_DATA_READ 3 +/** Writes requested data to the host. + * + * This function takes either 2 or 3 parameters. The last two parameters are a + * 32-bit format bit (VBOX_SHCL_FMT_XXX) and a data buffer holding the related + * data. The three parameter variant have a context ID first, which shall be a + * copy of the ID in the data request message. + * + * There was a period during 6.1 development where there would be a 5 parameter + * version of this, inserting an unused flags parameter between the context ID + * and the format bit, as well as a 32-bit data buffer size repate between the + * format bit and the data buffer. This format is still accepted, though + * deprecated. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @retval VERR_INVALID_CONTEXT if the context ID didn't match up. + * @since 1.3.2 + */ +#define VBOX_SHCL_GUEST_FN_DATA_WRITE 4 + +/** This is a left-over from the 6.1 dev cycle and will always fail. + * + * It used to take three 32-bit parameters, only one of which was actually used. + * + * It was replaced by VBOX_SHCL_GUEST_FN_REPORT_FEATURES and + * VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE. + * + * @retval VERR_NOT_IMPLEMENTED + * @since 6.1 + */ +#define VBOX_SHCL_GUEST_FN_CONNECT 5 +/** Report guest side feature flags and retrieve the host ones. + * + * Two 64-bit parameters are passed in from the guest with the guest features + * (VBOX_SHCL_GF_XXX), the host replies by replacing the parameter values with + * the host ones (VBOX_SHCL_HF_XXX). + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.0 + */ +#define VBOX_SHCL_GUEST_FN_REPORT_FEATURES 6 +/** Query the host ones feature masks. + * + * That way the guest (client) can get hold of the features from the host. + * Again, it is prudent to set the 127 bit and observe it being cleared on + * success, as older hosts might return success without doing anything. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.0 + */ +#define VBOX_SHCL_GUEST_FN_QUERY_FEATURES 7 +/** Peeks at the next message, returning immediately. + * + * Returns two 32-bit parameters, first is the message ID and the second the + * parameter count. May optionally return additional 32-bit parameters with the + * sizes of respective message parameters. To distinguish buffer sizes from + * integer parameters, the latter gets their sizes inverted (uint32_t is ~4U, + * uint64_t is ~8U). + * + * Does also support the VM restore checking as in VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT + * (64-bit param \# 0), see documentation there. + * + * @retval VINF_SUCCESS if a message was pending and is being returned. + * @retval VERR_TRY_AGAIN if no message pending. + * @retval VERR_VM_RESTORED if first parameter is a non-zero 64-bit value that + * does not match VbglR3GetSessionId() any more. The new value is + * returned. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.0 + */ +#define VBOX_SHCL_GUEST_FN_MSG_PEEK_NOWAIT 8 +/** Peeks at the next message, waiting for one to arrive. + * + * Returns two 32-bit parameters, first is the message ID and the second the + * parameter count. May optionally return additional 32-bit parameters with the + * sizes of respective message parameters. To distinguish buffer sizes from + * integer parameters, the latter gets their sizes inverted (uint32_t is ~4U, + * uint64_t is ~8U). + * + * To facilitate VM restore checking, the first parameter can be a 64-bit + * integer holding the VbglR3GetSessionId() value the guest knowns. The + * function will then check this before going to sleep and return + * VERR_VM_RESTORED if it doesn't match, same thing happens when the VM is + * restored. + * + * @retval VINF_SUCCESS if info about an pending message is being returned. + * @retval VINF_TRY_AGAIN and message set to VBOX_SHCL_HOST_MSG_CANCELED if + * cancelled by VBOX_SHCL_GUEST_FN_MSG_CANCEL. + * @retval VERR_RESOURCE_BUSY if another thread already made a waiting call. + * @retval VERR_VM_RESTORED if first parameter is a non-zero 64-bit value that + * does not match VbglR3GetSessionId() any more. The new value is + * returned. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @note This replaces VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT. + * @since 6.1.0 + */ +#define VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT 9 +/** Gets the next message, returning immediately. + * + * All parameters are specific to the message being retrieved, however if the + * first one is an integer value it shall be an input parameter holding the + * ID of the message being retrieved. While it would be nice to add a separate + * parameter for this purpose, this is done so because the code was liften from + * Guest Controls which had backwards compatibilities to consider and we just + * kept it like that. + * + * @retval VINF_SUCCESS if message retrieved and removed from the pending queue. + * @retval VERR_TRY_AGAIN if no message pending. + * @retval VERR_MISMATCH if the incoming message ID does not match the pending. + * @retval VERR_BUFFER_OVERFLOW if a parmeter buffer is too small. The buffer + * size was updated to reflect the required size. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @note This replaces VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT. + * @since 6.1.0 + */ +#define VBOX_SHCL_GUEST_FN_MSG_GET 10 +/** Cancels pending calls for this client session. + * + * This should be used if a VBOX_SHCL_GUEST_FN__MSG_PEEK_WAIT or + * VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT call gets interrupted on the client end, + * so as to prevent being rebuffed with VERR_RESOURCE_BUSY when restarting the + * call. + * + * @retval VINF_SUCCESS if cancelled any calls. + * @retval VWRN_NOT_FOUND if no callers. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @since 6.1.0 + */ +#define VBOX_SHCL_GUEST_FN_MSG_CANCEL 26 + +/** Replies to a function from the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_REPLY 11 +/** Gets the root list header from the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ 12 +/** Sends the root list header to the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE 13 +/** Gets a root list root entry from the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ 14 +/** Sends a root list root entry to the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE 15 +/** Opens / gets a list handle from the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_LIST_OPEN 16 +/** Closes a list handle from the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_LIST_CLOSE 17 +/** Reads a list header from the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_LIST_HDR_READ 18 +/** Writes a list header to the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE 19 +/** Reads a list entry from the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ 20 +/** Sends a list entry to the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE 21 +/** Opens an object on the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_OBJ_OPEN 22 +/** Closes an object on the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_OBJ_CLOSE 23 +/** Reads from an object on the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_OBJ_READ 24 +/** Writes to an object on the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_OBJ_WRITE 25 +/** Reports an error to the host. + * + * @todo r=bird: Smells like GUEST_MSG_SKIP + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1 + */ +#define VBOX_SHCL_GUEST_FN_ERROR 27 + +/** For negotiating a chunk size between the guest and host. + * + * Takes two 32-bit parameters both being byte counts, the first one gives the + * maximum chunk size the guest can handle and the second the preferred choice + * of the guest. Upon return, the host will have updated both of them to + * reflect the maximum and default chunk sizes this client connect. The guest + * may set the 2nd value to zero and let the host choose. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @retval VERR_INVALID_PARAMETER if the 2nd parameter is larger than the + * first one + * @since 6.1 + */ +#define VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE 28 + +/** The last function number (used for validation/sanity). */ +#define VBOX_SHCL_GUEST_FN_LAST VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE +/** @} */ + + +/** Maximum chunk size for a single data transfer. */ +#define VBOX_SHCL_MAX_CHUNK_SIZE VMMDEV_MAX_HGCM_DATA_SIZE - _4K +/** Default chunk size for a single data transfer. */ +#define VBOX_SHCL_DEFAULT_CHUNK_SIZE RT_MIN(_64K, VBOX_SHCL_MAX_CHUNK_SIZE); + + +/** @name VBOX_SHCL_GF_XXX - Guest features. + * @sa VBOX_SHCL_GUEST_FN_REPORT_FEATURES + * @{ */ +/** No flags set. */ +#define VBOX_SHCL_GF_NONE 0 +/** The guest can handle context IDs where applicable. */ +#define VBOX_SHCL_GF_0_CONTEXT_ID RT_BIT_64(0) +/** The guest can copy & paste files and directories. + * @since 6.x */ +#define VBOX_SHCL_GF_0_TRANSFERS RT_BIT_64(1) +/** The guest supports a (guest OS-)native frontend for showing and handling file transfers. + * If not set, the host will show a modal progress dialog instead and transferring file to + * a guest-specific temporary location first. + * Currently only supported for Windows guests (integrated into Windows Explorer via IDataObject). */ +#define VBOX_SHCL_GF_0_TRANSFERS_FRONTEND RT_BIT_64(2) +/** Bit that must be set in the 2nd parameter, will be cleared if the host reponds + * correctly (old hosts might not). */ +#define VBOX_SHCL_GF_1_MUST_BE_ONE RT_BIT_64(63) +/** @} */ + +/** @name VBOX_GUESTCTRL_HF_XXX - Host features. + * @sa VBOX_SHCL_GUEST_FN_REPORT_FEATURES + * @{ */ +/** No flags set. */ +#define VBOX_SHCL_HF_NONE 0 +/** The host can handle context IDs where applicable as well as the new + * message handling functions. */ +#define VBOX_SHCL_HF_0_CONTEXT_ID RT_BIT_64(0) +/** The host can copy & paste files and directories. + * This includes messages like + * @since 6.1.? */ +#define VBOX_SHCL_HF_0_TRANSFERS RT_BIT_64(1) +/** @} */ + +/** @name Context ID related macros and limits + * @{ */ +/** + * Creates a context ID out of a client ID, a transfer ID and an event ID (count). + */ +#define VBOX_SHCL_CONTEXTID_MAKE(a_idSession, a_idTransfer, a_idEvent) \ + ( ((uint64_t)((a_idSession) & 0xffff) << 48) \ + | ((uint64_t)((a_idTransfer) & 0xffff) << 32) \ + | ((uint32_t) (a_idEvent)) \ + ) +/** Creates a context ID out of a session ID. */ +#define VBOX_SHCL_CONTEXTID_MAKE_SESSION(a_idSession) VBOX_SHCL_CONTEXTID_MAKE(a_idSession, 0, 0) +/** Gets the session ID out of a context ID. */ +#define VBOX_SHCL_CONTEXTID_GET_SESSION(a_idContext) ( (uint16_t)(((a_idContext) >> 48) & UINT16_MAX) ) +/** Gets the transfer ID out of a context ID. */ +#define VBOX_SHCL_CONTEXTID_GET_TRANSFER(a_idContext) ( (uint16_t)(((a_idContext) >> 32) & UINT16_MAX) ) +/** Gets the transfer event out of a context ID. */ +#define VBOX_SHCL_CONTEXTID_GET_EVENT(a_idContext) ( (uint32_t)( (a_idContext) & UINT32_MAX) ) + +/** Maximum number of concurrent Shared Clipboard client sessions a VM can have. */ +#define VBOX_SHCL_MAX_SESSIONS (UINT16_MAX - 1) +/** Maximum number of concurrent Shared Clipboard transfers a single client can have. */ +#define VBOX_SHCL_MAX_TRANSFERS (UINT16_MAX - 1) +/** Maximum number of events a single Shared Clipboard transfer can have. */ +#define VBOX_SHCL_MAX_EVENTS (UINT32_MAX - 1) +/** @} */ + + +/* + * HGCM parameter structures. + */ +/** @todo r=bird: These structures are mostly pointless, as they're only + * ever used by the VbglR3 part. The host service does not use these + * structures for decoding guest requests, instead it's all hardcoded. */ +#pragma pack(1) +/** + * Waits (blocking) for a new host message to arrive. + * Deprecated; do not use anymore. + * Kept for maintaining compatibility with older Guest Additions. + */ +typedef struct _VBoxShClGetHostMsgOld +{ + VBGLIOCHGCMCALL hdr; + + /** uint32_t, out: Host message type. */ + HGCMFunctionParameter msg; + /** uint32_t, out: VBOX_SHCL_FMT_*, depends on the 'msg'. + * r=andy This actual can have *different* meanings, depending on the host message type. */ + HGCMFunctionParameter formats; /* OUT uint32_t */ +} VBoxShClGetHostMsgOld; + +#define VBOX_SHCL_CPARMS_GET_HOST_MSG_OLD 2 + +/** @name VBOX_SHCL_GUEST_FN_REPORT_FORMATS + * @{ */ +/** VBOX_SHCL_GUEST_FN_REPORT_FORMATS parameters. */ +typedef struct VBoxShClParmReportFormats +{ + /** uint32_t, int: Zero or more VBOX_SHCL_FMT_XXX bits. */ + HGCMFunctionParameter f32Formats; +} VBoxShClParmReportFormats; + +#define VBOX_SHCL_CPARMS_REPORT_FORMATS 1 /**< The parameter count for VBOX_SHCL_GUEST_FN_REPORT_FORMATS. */ +#define VBOX_SHCL_CPARMS_REPORT_FORMATS_61B 3 /**< The 6.1 dev cycle variant, see VBOX_SHCL_GUEST_FN_REPORT_FORMATS. */ +/** @} */ + +/** @name VBOX_SHCL_GUEST_FN_DATA_READ + * @{ */ +/** VBOX_SHCL_GUEST_FN_DATA_READ parameters. */ +typedef struct VBoxShClParmDataRead +{ + /** uint32_t, in: Requested format (VBOX_SHCL_FMT_XXX). */ + HGCMFunctionParameter f32Format; + /** ptr, out: The data buffer to put the data in on success. */ + HGCMFunctionParameter pData; + /** uint32_t, out: Size of returned data, if larger than the buffer, then no + * data was actually transferred and the guest must repeat the call. */ + HGCMFunctionParameter cb32Needed; +} VBoxShClParmDataRead; + +#define VBOX_SHCL_CPARMS_DATA_READ 3 /**< The parameter count for VBOX_SHCL_GUEST_FN_DATA_READ. */ +#define VBOX_SHCL_CPARMS_DATA_READ_61B 5 /**< The 6.1 dev cycle variant, see VBOX_SHCL_GUEST_FN_DATA_READ. */ +/** @} */ + +/** @name + * @{ */ + +/** VBOX_SHCL_GUEST_FN_DATA_WRITE parameters. */ +typedef struct VBoxShClParmDataWrite +{ + /** uint64_t, in: Context ID from VBOX_SHCL_HOST_MSG_READ_DATA. */ + HGCMFunctionParameter id64Context; + /** uint32_t, in: The data format (VBOX_SHCL_FMT_XXX). */ + HGCMFunctionParameter f32Format; + /** ptr, in: The data. */ + HGCMFunctionParameter pData; +} VBoxShClParmDataWrite; + +/** Old VBOX_SHCL_GUEST_FN_DATA_WRITE parameters. */ +typedef struct VBoxShClParmDataWriteOld +{ + /** uint32_t, in: The data format (VBOX_SHCL_FMT_XXX). */ + HGCMFunctionParameter f32Format; + /** ptr, in: The data. */ + HGCMFunctionParameter pData; +} VBoxShClParmDataWriteOld; + +#define VBOX_SHCL_CPARMS_DATA_WRITE 3 /**< The variant used when VBOX_SHCL_GF_0_CONTEXT_ID is reported. */ +#define VBOX_SHCL_CPARMS_DATA_WRITE_OLD 2 /**< The variant used when VBOX_SHCL_GF_0_CONTEXT_ID isn't reported. */ +#define VBOX_SHCL_CPARMS_DATA_WRITE_61B 5 /**< The 6.1 dev cycle variant, see VBOX_SHCL_GUEST_FN_DATA_WRITE. */ +/** @} */ + +/** + * Reports a transfer status. + */ +typedef struct _VBoxShClTransferStatusMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, out: Context ID. */ + HGCMFunctionParameter uContext; + /** uint32_t, out: Direction of transfer; of type SHCLTRANSFERDIR_. */ + HGCMFunctionParameter enmDir; + /** uint32_t, out: Status to report; of type SHCLTRANSFERSTATUS_. */ + HGCMFunctionParameter enmStatus; + /** uint32_t, out: Result code to report. Optional. */ + HGCMFunctionParameter rc; + /** uint32_t, out: Reporting flags. Currently unused and must be 0. */ + HGCMFunctionParameter fFlags; +} VBoxShClTransferStatusMsg; + +#define VBOX_SHCL_CPARMS_TRANSFER_STATUS 5 + +/** + * Asks the host for the next command to process, along + * with the needed amount of parameters and an optional blocking + * flag. + * + * Used by: VBOX_SHCL_GUEST_FN_GET_HOST_MSG + * + */ +typedef struct _VBoxShClGetHostMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint32_t, out: Message ID. */ + HGCMFunctionParameter uMsg; + /** uint32_t, out: Number of parameters the message needs. */ + HGCMFunctionParameter cParms; + /** uint32_t, in: Whether or not to block (wait) for a new message to arrive. */ + HGCMFunctionParameter fBlock; +} VBoxShClPeekMsg; + +#define VBOX_SHCL_CPARMS_GET_HOST_MSG 3 + +/** No listing flags specified. */ +#define VBOX_SHCL_LIST_FLAG_NONE 0 +/** Only returns one entry per read. */ +#define VBOX_SHCL_LIST_FLAG_RETURN_ONE RT_BIT(0) +/** Restarts reading a list from the beginning. */ +#define VBOX_SHCL_LIST_FLAG_RESTART RT_BIT(1) + +#define VBOX_SHCL_LISTHDR_FLAG_NONE 0 + +/** No additional information provided. */ +#define VBOX_SHCL_INFO_FLAG_NONE 0 +/** Get object information of type SHCLFSOBJINFO. */ +#define VBOX_SHCL_INFO_FLAG_FSOBJINFO RT_BIT(0) + +/** + * Status message for lists and objects. + */ +typedef struct _VBoxShClStatusMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, in: Context ID. */ + HGCMFunctionParameter uContext; + /** uint32_t, in: Transfer status of type SHCLTRANSFERSTATUS. */ + HGCMFunctionParameter uStatus; + /** pointer, in: Optional payload of this status, based on the status type. */ + HGCMFunctionParameter pvPayload; +} VBoxShClStatusMsg; + +#define VBOX_SHCL_CPARMS_STATUS 3 + +/** Invalid message type, do not use. */ +#define VBOX_SHCL_REPLYMSGTYPE_INVALID 0 +/** Replies a transfer status. */ +#define VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS 1 +/** Replies a list open status. */ +#define VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN 2 +/** Replies a list close status. */ +#define VBOX_SHCL_REPLYMSGTYPE_LIST_CLOSE 3 +/** Replies an object open status. */ +#define VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN 4 +/** Replies an object close status. */ +#define VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE 5 + +/** + * Generic reply message. + */ +typedef struct _VBoxShClReplyMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, out: Context ID. */ + HGCMFunctionParameter uContext; + /** uint32_t, out: Message type of type VBOX_SHCL_REPLYMSGTYPE_XXX. */ + HGCMFunctionParameter enmType; + /** uint32_t, out: IPRT result of overall operation. */ + HGCMFunctionParameter rc; + /** pointer, out: Optional payload of this reply, based on the message type. */ + HGCMFunctionParameter pvPayload; + union + { + struct + { + HGCMFunctionParameter enmStatus; + } TransferStatus; + struct + { + HGCMFunctionParameter uHandle; + } ListOpen; + struct + { + HGCMFunctionParameter uHandle; + } ObjOpen; + struct + { + HGCMFunctionParameter uHandle; + } ObjClose; + } u; +} VBoxShClReplyMsg; + +/** Minimum parameters (HGCM function parameters minus the union) a reply message must have. */ +#define VBOX_SHCL_CPARMS_REPLY_MIN 4 + +/** + * Structure for keeping root list message parameters. + */ +typedef struct _VBoxShClRootListParms +{ + /** uint64_t, in: Context ID. */ + HGCMFunctionParameter uContext; + /** uint32_t, in: Roots listing flags; unused at the moment. */ + HGCMFunctionParameter fRoots; +} VBoxShClRootListParms; + +#define VBOX_SHCL_CPARMS_ROOT_LIST 2 + +/** + * Requests to read the root list header. + */ +typedef struct _VBoxShClRootListReadReqMsg +{ + VBGLIOCHGCMCALL hdr; + + VBoxShClRootListParms ReqParms; +} VBoxShClRootListReadReqMsg; + +#define VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ_REQ VBOX_SHCL_CPARMS_ROOT_LIST + +/** + * Reads / Writes a root list header. + */ +typedef struct _VBoxShClRootListHdrMsg +{ + VBGLIOCHGCMCALL hdr; + + VBoxShClRootListParms ReqParms; + /** uint64_t, in/out: Number of total root list entries. */ + HGCMFunctionParameter cRoots; +} VBoxShClRootListHdrMsg; + +#define VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ VBOX_SHCL_CPARMS_ROOT_LIST + 1 +#define VBOX_SHCL_CPARMS_ROOT_LIST_HDR_WRITE VBOX_SHCL_CPARMS_ROOT_LIST + 1 + +/** + * Structure for keeping list entry message parameters. + */ +typedef struct _VBoxShClRootListEntryParms +{ + /** uint64_t, in: Context ID. */ + HGCMFunctionParameter uContext; + /** uint32_t, in: VBOX_SHCL_INFO_FLAG_XXX. */ + HGCMFunctionParameter fInfo; + /** uint32_t, in: Index of root list entry to get (zero-based). */ + HGCMFunctionParameter uIndex; +} VBoxShClRootListEntryParms; + +#define VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY 3 + +/** + * Request to read a list root entry. + */ +typedef struct _VBoxShClRootListEntryReadReqMsg +{ + VBGLIOCHGCMCALL hdr; + + /** in: Request parameters. */ + VBoxShClRootListEntryParms Parms; +} VBoxShClRootListEntryReadReqMsg; + +#define VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY + +/** + * Reads / Writes a root list entry. + */ +typedef struct _VBoxShClRootListEntryMsg +{ + VBGLIOCHGCMCALL hdr; + + /** in/out: Request parameters. */ + VBoxShClRootListEntryParms Parms; + /** pointer, in/out: Entry name. */ + HGCMFunctionParameter szName; + /** uint32_t, out: Bytes to be used for information/How many bytes were used. */ + HGCMFunctionParameter cbInfo; + /** pointer, in/out: Information to be set/get (SHCLFSOBJINFO only currently). + * Do not forget to set the SHCLFSOBJINFO::Attr::enmAdditional for Get operation as well. */ + HGCMFunctionParameter pvInfo; +} VBoxShClRootListEntryMsg; + +#define VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY + 3 +#define VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_WRITE VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY + 3 + +/** + * Opens a list. + */ +typedef struct _VBoxShClListOpenMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, in: Context ID. */ + HGCMFunctionParameter uContext; + /** uint32_t, in: Listing flags (see VBOX_SHCL_LIST_FLAG_XXX). */ + HGCMFunctionParameter fList; + /** pointer, in: Filter string. */ + HGCMFunctionParameter pvFilter; + /** pointer, in: Listing poth. If empty or NULL the listing's root path will be opened. */ + HGCMFunctionParameter pvPath; + /** uint64_t, out: List handle. */ + HGCMFunctionParameter uHandle; +} VBoxShClListOpenMsg; + +#define VBOX_SHCL_CPARMS_LIST_OPEN 5 + +/** + * Closes a list. + */ +typedef struct _VBoxShClListCloseMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, in/out: Context ID. */ + HGCMFunctionParameter uContext; + /** uint64_t, in: List handle. */ + HGCMFunctionParameter uHandle; +} VBoxShClListCloseMsg; + +#define VBOX_SHCL_CPARMS_LIST_CLOSE 2 + +typedef struct _VBoxShClListHdrReqParms +{ + /** uint64_t, in: Context ID. */ + HGCMFunctionParameter uContext; + /** uint64_t, in: List handle. */ + HGCMFunctionParameter uHandle; + /** uint32_t, in: Flags of type VBOX_SHCL_LISTHDR_FLAG_XXX. */ + HGCMFunctionParameter fFlags; +} VBoxShClListHdrReqParms; + +#define VBOX_SHCL_CPARMS_LIST_HDR_REQ 3 + +/** + * Request to read a list header. + */ +typedef struct _VBoxShClListHdrReadReqMsg +{ + VBGLIOCHGCMCALL hdr; + + VBoxShClListHdrReqParms ReqParms; +} VBoxShClListHdrReadReqMsg; + +#define VBOX_SHCL_CPARMS_LIST_HDR_READ_REQ VBOX_SHCL_CPARMS_LIST_HDR_REQ + +/** + * Reads / Writes a list header. + */ +typedef struct _VBoxShClListHdrMsg +{ + VBGLIOCHGCMCALL hdr; + + VBoxShClListHdrReqParms ReqParms; + /** uint32_t, in/out: Feature flags (see VBOX_SHCL_FEATURE_FLAG_XXX). */ + HGCMFunctionParameter fFeatures; + /** uint64_t, in/out: Number of total objects to transfer. */ + HGCMFunctionParameter cTotalObjects; + /** uint64_t, in/out: Number of total bytes to transfer. */ + HGCMFunctionParameter cbTotalSize; +} VBoxShClListHdrMsg; + +#define VBOX_SHCL_CPARMS_LIST_HDR VBOX_SHCL_CPARMS_LIST_HDR_REQ + 3 + +typedef struct _VBoxShClListEntryReqParms +{ + /** uint64_t, in: Context ID. */ + HGCMFunctionParameter uContext; + /** uint64_t, in: List handle. */ + HGCMFunctionParameter uHandle; + /** uint32_t, in: VBOX_SHCL_INFO_FLAG_XXX. */ + HGCMFunctionParameter fInfo; +} VBoxShClListEntryReqParms; + +#define VBOX_SHCL_CPARMS_LIST_ENTRY_REQ 3 + +/** + * Request to read a list entry. + */ +typedef struct _VBoxShClListEntryReadReqMsg +{ + VBGLIOCHGCMCALL hdr; + + VBoxShClListEntryReqParms ReqParms; +} VBoxShClListEntryReadReqMsg; + +#define VBOX_SHCL_CPARMS_LIST_ENTRY_READ VBOX_SHCL_CPARMS_LIST_ENTRY_REQ + +/** + * Reads / Writes a list entry. + */ +typedef struct _VBoxShClListEntryMsg +{ + VBGLIOCHGCMCALL hdr; + + /** in/out: Request parameters. */ + VBoxShClListEntryReqParms ReqParms; + /** pointer, in/out: Entry name. */ + HGCMFunctionParameter szName; + /** uint32_t, out: Bytes to be used for information/How many bytes were used. */ + HGCMFunctionParameter cbInfo; + /** pointer, in/out: Information to be set/get (SHCLFSOBJINFO only currently). + * Do not forget to set the SHCLFSOBJINFO::Attr::enmAdditional for Get operation as well. */ + HGCMFunctionParameter pvInfo; +} VBoxShClListEntryMsg; + +#define VBOX_SHCL_CPARMS_LIST_ENTRY VBOX_SHCL_CPARMS_LIST_ENTRY_REQ + 3 + +/** + * Opens a Shared Clipboard object. + */ +typedef struct _VBoxShClObjOpenMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, in/out: Context ID. */ + HGCMFunctionParameter uContext; + /** uint64_t, out: Object handle. */ + HGCMFunctionParameter uHandle; + /** pointer, in: Absoulte path of object to open/create. */ + HGCMFunctionParameter szPath; + /** uint32_t in: Open / Create flags of type SHCL_OBJ_CF_. */ + HGCMFunctionParameter fCreate; +} VBoxShClObjOpenMsg; + +#define VBOX_SHCL_CPARMS_OBJ_OPEN 4 + +/** + * Closes a Shared Clipboard object. + */ +typedef struct _VBoxShClObjCloseMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, in/out: Context ID. */ + HGCMFunctionParameter uContext; + /** uint64_t, in: SHCLOBJHANDLE of object to close. */ + HGCMFunctionParameter uHandle; +} VBoxShClObjCloseMsg; + +#define VBOX_SHCL_CPARMS_OBJ_CLOSE 2 + +/** + * Structure for keeping read parameters of a Shared Clipboard object. + */ +typedef struct _VBoxShClObjReadReqParms +{ + /** uint64_t, in: Context ID. */ + HGCMFunctionParameter uContext; + /** uint64_t, in: SHCLOBJHANDLE of object to write to. */ + HGCMFunctionParameter uHandle; + /** uint32_t, in: How many bytes to read. */ + HGCMFunctionParameter cbToRead; + /** uint32_t, in: Read flags. Currently unused and must be 0. */ + HGCMFunctionParameter fRead; +} VBoxShClObjReadReqParms; + +/** + * Reads from a Shared Clipboard object. + */ +typedef struct _VBoxShClObjReadReqMsg +{ + VBGLIOCHGCMCALL hdr; + + VBoxShClObjReadReqParms ReqParms; +} VBoxShClObjReadReqMsg; + +#define VBOX_SHCL_CPARMS_OBJ_READ_REQ 4 + +/** + * Reads / writes data of / to an object. + * + * Used by: + * VBOX_SHCL_FN_OBJ_READ + * VBOX_SHCL_FN_OBJ_WRITE + */ +typedef struct _VBoxShClObjReadWriteMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, in/out: Context ID. */ + HGCMFunctionParameter uContext; + /** uint64_t, in/out: SHCLOBJHANDLE of object to write to. */ + HGCMFunctionParameter uHandle; + /** uint32_t, out: Size (in bytes) read/written. */ + HGCMFunctionParameter cbData; + /** pointer, in/out: Current data chunk. */ + HGCMFunctionParameter pvData; + /** uint32_t, in/out: Size (in bytes) of current data chunk checksum. */ + HGCMFunctionParameter cbChecksum; + /** pointer, in/out: Checksum of data block, based on the checksum + * type in the data header. Optional. */ + HGCMFunctionParameter pvChecksum; +} VBoxShClObjReadWriteMsg; + +#define VBOX_SHCL_CPARMS_OBJ_READ 6 +#define VBOX_SHCL_CPARMS_OBJ_WRITE 6 + +/** + * Sends an error event. + * + * Used by: + * VBOX_SHCL_FN_WRITE_ERROR + */ +typedef struct _VBoxShClErrorMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, in: Context ID. */ + HGCMFunctionParameter uContext; + /** uint32_t, in: The error code (IPRT-style). */ + HGCMFunctionParameter rc; +} VBoxShClWriteErrorMsg; + +#define VBOX_SHCL_CPARMS_ERROR 2 + +/** @name VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE + * @{ */ +/** VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE parameters. */ +typedef struct _VBoxShClParmNegotiateChunkSize +{ + VBGLIOCHGCMCALL hdr; + + /** uint32_t, in: Maximum chunk size. */ + HGCMFunctionParameter cb32MaxChunkSize; + /** uint32_t, in: Default chunk size. */ + HGCMFunctionParameter cb32ChunkSize; +} VBoxShClParmNegotiateChunkSize; + +#define VBOX_SHCL_CPARMS_NEGOTIATE_CHUNK_SIZE 2 +/** @} */ + +#pragma pack() + +#endif /* !VBOX_INCLUDED_HostServices_VBoxClipboardSvc_h */ + diff --git a/include/VBox/HostServices/VBoxHostChannel.h b/include/VBox/HostServices/VBoxHostChannel.h new file mode 100644 index 00000000..7ac452de --- /dev/null +++ b/include/VBox/HostServices/VBoxHostChannel.h @@ -0,0 +1,229 @@ +/** @file + * + * Host Channel: the service definition. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_HostServices_VBoxHostChannel_h +#define VBOX_INCLUDED_HostServices_VBoxHostChannel_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/VMMDevCoreTypes.h> +#include <VBox/VBoxGuestCoreTypes.h> +#include <VBox/hgcmsvc.h> + +/* + * Host calls. + */ +#define VBOX_HOST_CHANNEL_HOST_FN_REGISTER 1 +#define VBOX_HOST_CHANNEL_HOST_FN_UNREGISTER 2 + +/* + * Guest calls. + */ +#define VBOX_HOST_CHANNEL_FN_ATTACH 1 /* Attach to a channel. */ +#define VBOX_HOST_CHANNEL_FN_DETACH 2 /* Detach from the channel. */ +#define VBOX_HOST_CHANNEL_FN_SEND 3 /* Send data to the host. */ +#define VBOX_HOST_CHANNEL_FN_RECV 4 /* Receive data from the host. */ +#define VBOX_HOST_CHANNEL_FN_CONTROL 5 /* Generic data exchange using a channel instance. */ +#define VBOX_HOST_CHANNEL_FN_EVENT_WAIT 6 /* Blocking wait for a host event. */ +#define VBOX_HOST_CHANNEL_FN_EVENT_CANCEL 7 /* Cancel the blocking wait. */ +#define VBOX_HOST_CHANNEL_FN_QUERY 8 /* Generic data exchange using a channel name. */ + +/* + * The host event ids for the guest. + */ +#define VBOX_HOST_CHANNEL_EVENT_CANCELLED 0 /* Event was cancelled by FN_EVENT_CANCEL. */ +#define VBOX_HOST_CHANNEL_EVENT_UNREGISTERED 1 /* Channel was unregistered on host. */ +#define VBOX_HOST_CHANNEL_EVENT_RECV 2 /* Data is available for receiving. */ +#define VBOX_HOST_CHANNEL_EVENT_USER 1000 /* Base of channel specific events. */ + +/* + * The common control code ids for the VBOX_HOST_CHANNEL_FN_[CONTROL|QUERY] + */ +#define VBOX_HOST_CHANNEL_CTRL_EXISTS 0 /* Whether the channel instance or provider exists. */ +#define VBOX_HOST_CHANNEL_CTRL_USER 1000 /* Base of channel specific events. */ + +#pragma pack(1) + +/* Parameter of VBOX_HOST_CHANNEL_EVENT_RECV */ +typedef struct VBOXHOSTCHANNELEVENTRECV +{ + uint32_t u32SizeAvailable; /* How many bytes can be read from the channel. */ +} VBOXHOSTCHANNELEVENTRECV; + +/* + * Guest calls. + */ + +typedef struct VBoxHostChannelAttach +{ + VBGLIOCHGCMCALL hdr; + HGCMFunctionParameter name; /* IN linear ptr: Channel name utf8 nul terminated. */ + HGCMFunctionParameter flags; /* IN uint32_t: Channel specific flags. */ + HGCMFunctionParameter handle; /* OUT uint32_t: The channel handle. */ +} VBoxHostChannelAttach; + +typedef struct VBoxHostChannelDetach +{ + VBGLIOCHGCMCALL hdr; + HGCMFunctionParameter handle; /* IN uint32_t: The channel handle. */ +} VBoxHostChannelDetach; + +typedef struct VBoxHostChannelSend +{ + VBGLIOCHGCMCALL hdr; + HGCMFunctionParameter handle; /* IN uint32_t: The channel handle. */ + HGCMFunctionParameter data; /* IN linear pointer: Data to be sent. */ +} VBoxHostChannelSend; + +typedef struct VBoxHostChannelRecv +{ + VBGLIOCHGCMCALL hdr; + HGCMFunctionParameter handle; /* IN uint32_t: The channel handle. */ + HGCMFunctionParameter data; /* OUT linear pointer: Buffer for data to be received. */ + HGCMFunctionParameter sizeReceived; /* OUT uint32_t: Bytes received. */ + HGCMFunctionParameter sizeRemaining; /* OUT uint32_t: Bytes remaining in the channel. */ +} VBoxHostChannelRecv; + +typedef struct VBoxHostChannelControl +{ + VBGLIOCHGCMCALL hdr; + HGCMFunctionParameter handle; /* IN uint32_t: The channel handle. */ + HGCMFunctionParameter code; /* IN uint32_t: The channel specific control code. */ + HGCMFunctionParameter parm; /* IN linear pointer: Parameters of the function. */ + HGCMFunctionParameter data; /* OUT linear pointer: Buffer for results. */ + HGCMFunctionParameter sizeDataReturned; /* OUT uint32_t: Bytes returned in the 'data' buffer. */ +} VBoxHostChannelControl; + +typedef struct VBoxHostChannelEventWait +{ + VBGLIOCHGCMCALL hdr; + HGCMFunctionParameter handle; /* OUT uint32_t: The channel which generated the event. */ + HGCMFunctionParameter id; /* OUT uint32_t: The event VBOX_HOST_CHANNEL_EVENT_*. */ + HGCMFunctionParameter parm; /* OUT linear pointer: Parameters of the event. */ + HGCMFunctionParameter sizeReturned; /* OUT uint32_t: Size of the parameters. */ +} VBoxHostChannelEventWait; + +typedef struct VBoxHostChannelEventCancel +{ + VBGLIOCHGCMCALL hdr; +} VBoxHostChannelEventCancel; + +typedef struct VBoxHostChannelQuery +{ + VBGLIOCHGCMCALL hdr; + HGCMFunctionParameter name; /* IN linear ptr: Channel name utf8 nul terminated. */ + HGCMFunctionParameter code; /* IN uint32_t: The control code. */ + HGCMFunctionParameter parm; /* IN linear pointer: Parameters of the function. */ + HGCMFunctionParameter data; /* OUT linear pointer: Buffer for results. */ + HGCMFunctionParameter sizeDataReturned; /* OUT uint32_t: Bytes returned in the 'data' buffer. */ +} VBoxHostChannelQuery; + + +/* + * Host calls + */ + +typedef struct VBoxHostChannelHostRegister +{ + VBOXHGCMSVCPARM name; /* IN ptr: Channel name utf8 nul terminated. */ + VBOXHGCMSVCPARM iface; /* IN ptr: VBOXHOSTCHANNELINTERFACE. */ +} VBoxHostChannelHostRegister; + +typedef struct VBoxHostChannelHostUnregister +{ + VBOXHGCMSVCPARM name; /* IN ptr: Channel name utf8 nul terminated */ +} VBoxHostChannelHostUnregister; + +/* The channel provider will invoke this callback to report channel events. */ +typedef struct VBOXHOSTCHANNELCALLBACKS +{ + /* A channel event occured. + * + * @param pvCallbacks The callback context specified in HostChannelAttach. + * @param pvChannel The channel instance returned by HostChannelAttach. + * @param u32Id The event id. + * @param pvEvent The event parameters. + * @param cbEvent The size of event parameters. + */ + DECLR3CALLBACKMEMBER(void, HostChannelCallbackEvent, (void *pvCallbacks, void *pvChannel, + uint32_t u32Id, const void *pvEvent, uint32_t cbEvent)); + + /* The channel has been deleted by the provider. pvCallback will not be used anymore. + * + * @param pvCallbacks The callback context specified in HostChannelAttach. + * @param pvChannel The channel instance returned by HostChannelAttach. + */ + DECLR3CALLBACKMEMBER(void, HostChannelCallbackDeleted, (void *pvCallbacks, void *pvChannel)); +} VBOXHOSTCHANNELCALLBACKS; + +typedef struct VBOXHOSTCHANNELINTERFACE +{ + /* The channel provider context. */ + void *pvProvider; + + /* A new channel is requested. + * + * @param pvProvider The provider context VBOXHOSTCHANNELINTERFACE::pvProvider. + * @param ppvChannel Where to store pointer to the channel instance created by the provider. + * @param u32Flags Channel specific flags. + * @param pCallbacks Callbacks to be invoked by the channel provider. + * @param pvCallbacks The context of callbacks. + */ + DECLR3CALLBACKMEMBER(int, HostChannelAttach, (void *pvProvider, void **ppvChannel, uint32_t u32Flags, + VBOXHOSTCHANNELCALLBACKS *pCallbacks, void *pvCallbacks)); + + /* The channel is closed. */ + DECLR3CALLBACKMEMBER(void, HostChannelDetach, (void *pvChannel)); + + /* The guest sends data to the channel. */ + DECLR3CALLBACKMEMBER(int, HostChannelSend, (void *pvChannel, const void *pvData, uint32_t cbData)); + + /* The guest reads data from the channel. */ + DECLR3CALLBACKMEMBER(int, HostChannelRecv, (void *pvChannel, void *pvData, uint32_t cbData, + uint32_t *pcbReceived, uint32_t *pcbRemaining)); + + /* The guest talks to the provider of the channel. + * @param pvChannel The channel instance. NULL if the target is the provider, rather than a channel. + */ + DECLR3CALLBACKMEMBER(int, HostChannelControl, (void *pvChannel, uint32_t u32Code, + const void *pvParm, uint32_t cbParm, + const void *pvData, uint32_t cbData, uint32_t *pcbDataReturned)); +} VBOXHOSTCHANNELINTERFACE; + +#pragma pack() + +#endif /* !VBOX_INCLUDED_HostServices_VBoxHostChannel_h */ diff --git a/include/VBox/Makefile.kup b/include/VBox/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/VBox/Makefile.kup diff --git a/include/VBox/RemoteDesktop/Makefile.kup b/include/VBox/RemoteDesktop/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/VBox/RemoteDesktop/Makefile.kup diff --git a/include/VBox/RemoteDesktop/VRDE.h b/include/VBox/RemoteDesktop/VRDE.h new file mode 100644 index 00000000..56c03226 --- /dev/null +++ b/include/VBox/RemoteDesktop/VRDE.h @@ -0,0 +1,1615 @@ +/** @file + * VBox Remote Desktop Extension (VRDE) - Public APIs. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_RemoteDesktop_VRDE_h +#define VBOX_INCLUDED_RemoteDesktop_VRDE_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +/** @defgroup grp_vrdp VRDE + * VirtualBox Remote Desktop Extension (VRDE) interface that lets to use + * a Remote Desktop server like RDP. + * @{ + */ + +RT_C_DECLS_BEGIN + +/* Forward declaration of the VRDE server instance handle. + * This is an opaque pointer for VirtualBox. + * The VRDE library uses it as a pointer to some internal data. + */ +#ifdef __cplusplus +class VRDEServer; +typedef class VRDEServerType *HVRDESERVER; +#else +struct VRDEServer; +typedef struct VRDEServerType *HVRDESERVER; +#endif /* !__cplusplus */ + +/* Callback based VRDE server interface declarations. */ + +/** The color mouse pointer information. */ +typedef struct _VRDECOLORPOINTER +{ + uint16_t u16HotX; + uint16_t u16HotY; + uint16_t u16Width; + uint16_t u16Height; + uint16_t u16MaskLen; + uint16_t u16DataLen; + /* The 1BPP mask and the 24BPP bitmap follow. */ +} VRDECOLORPOINTER; + +/** Audio format information packed in a 32 bit value. */ +typedef uint32_t VRDEAUDIOFORMAT; + +/** Constructs 32 bit value for given frequency, number of channel and bits per sample. */ +#define VRDE_AUDIO_FMT_MAKE(freq, c, bps, s) ((((s) & 0x1) << 28) + (((bps) & 0xFF) << 20) + (((c) & 0xF) << 16) + ((freq) & 0xFFFF)) + +/** Decode frequency. */ +#define VRDE_AUDIO_FMT_SAMPLE_FREQ(a) ((a) & 0xFFFF) +/** Decode number of channels. */ +#define VRDE_AUDIO_FMT_CHANNELS(a) (((a) >> 16) & 0xF) +/** Decode number signess. */ +#define VRDE_AUDIO_FMT_SIGNED(a) (((a) >> 28) & 0x1) +/** Decode number of bits per sample. */ +#define VRDE_AUDIO_FMT_BITS_PER_SAMPLE(a) (((a) >> 20) & 0xFF) +/** Decode number of bytes per sample. */ +#define VRDE_AUDIO_FMT_BYTES_PER_SAMPLE(a) ((VRDE_AUDIO_FMT_BITS_PER_SAMPLE(a) + 7) / 8) + + +/* + * Audio input. + */ + +/* Audio input notifications. */ +#define VRDE_AUDIOIN_BEGIN 1 +#define VRDE_AUDIOIN_DATA 2 +#define VRDE_AUDIOIN_END 3 + +typedef struct VRDEAUDIOINBEGIN +{ + VRDEAUDIOFORMAT fmt; /* Actual format of data, which will be sent in VRDE_AUDIOIN_DATA events. */ +} VRDEAUDIOINBEGIN, *PVRDEAUDIOINBEGIN; + + +/* + * Remote USB protocol. + */ + +/* The initial version 1. */ +#define VRDE_USB_VERSION_1 (1) +/* Version 2: look for VRDE_USB_VERSION_2 comments in the code. */ +#define VRDE_USB_VERSION_2 (2) +/* Version 3: look for VRDE_USB_VERSION_3 comments in the code. */ +#define VRDE_USB_VERSION_3 (3) + +/* The default VRDE server version of Remote USB Protocol. */ +#define VRDE_USB_VERSION VRDE_USB_VERSION_3 + + +/** USB backend operations. */ +#define VRDE_USB_REQ_OPEN (0) +#define VRDE_USB_REQ_CLOSE (1) +#define VRDE_USB_REQ_RESET (2) +#define VRDE_USB_REQ_SET_CONFIG (3) +#define VRDE_USB_REQ_CLAIM_INTERFACE (4) +#define VRDE_USB_REQ_RELEASE_INTERFACE (5) +#define VRDE_USB_REQ_INTERFACE_SETTING (6) +#define VRDE_USB_REQ_QUEUE_URB (7) +#define VRDE_USB_REQ_REAP_URB (8) +#define VRDE_USB_REQ_CLEAR_HALTED_EP (9) +#define VRDE_USB_REQ_CANCEL_URB (10) + +/** USB service operations. */ +#define VRDE_USB_REQ_DEVICE_LIST (11) +#define VRDE_USB_REQ_NEGOTIATE (12) + +/** An operation completion status is a byte. */ +typedef uint8_t VRDEUSBSTATUS; + +/** USB device identifier is an 32 bit value. */ +typedef uint32_t VRDEUSBDEVID; + +/** Status codes. */ +#define VRDE_USB_STATUS_SUCCESS ((VRDEUSBSTATUS)0) +#define VRDE_USB_STATUS_ACCESS_DENIED ((VRDEUSBSTATUS)1) +#define VRDE_USB_STATUS_DEVICE_REMOVED ((VRDEUSBSTATUS)2) + +/* + * Data structures to use with VRDEUSBRequest. + * The *RET* structures always represent the layout of VRDE data. + * The *PARM* structures normally the same as VRDE layout. + * However the VRDE_USB_REQ_QUEUE_URB_PARM has a pointer to + * URB data in place where actual data will be in VRDE layout. + * + * Since replies (*RET*) are asynchronous, the 'success' + * replies are not required for operations which return + * only the status code (VRDEUSBREQRETHDR only): + * VRDE_USB_REQ_OPEN + * VRDE_USB_REQ_RESET + * VRDE_USB_REQ_SET_CONFIG + * VRDE_USB_REQ_CLAIM_INTERFACE + * VRDE_USB_REQ_RELEASE_INTERFACE + * VRDE_USB_REQ_INTERFACE_SETTING + * VRDE_USB_REQ_CLEAR_HALTED_EP + * + */ + +/* VRDE layout has no alignments. */ +#pragma pack(1) +/* Common header for all VRDE USB packets. After the reply hdr follows *PARM* or *RET* data. */ +typedef struct _VRDEUSBPKTHDR +{ + /* Total length of the reply NOT including the 'length' field. */ + uint32_t length; + /* The operation code for which the reply was sent by the client. */ + uint8_t code; +} VRDEUSBPKTHDR; + +/* Common header for all return structures. */ +typedef struct _VRDEUSBREQRETHDR +{ + /* Device status. */ + VRDEUSBSTATUS status; + /* Device id. */ + VRDEUSBDEVID id; +} VRDEUSBREQRETHDR; + + +/* VRDE_USB_REQ_OPEN + */ +typedef struct _VRDE_USB_REQ_OPEN_PARM +{ + uint8_t code; + VRDEUSBDEVID id; +} VRDE_USB_REQ_OPEN_PARM; + +typedef struct _VRDE_USB_REQ_OPEN_RET +{ + VRDEUSBREQRETHDR hdr; +} VRDE_USB_REQ_OPEN_RET; + + +/* VRDE_USB_REQ_CLOSE + */ +typedef struct _VRDE_USB_REQ_CLOSE_PARM +{ + uint8_t code; + VRDEUSBDEVID id; +} VRDE_USB_REQ_CLOSE_PARM; + +/* The close request has no returned data. */ + + +/* VRDE_USB_REQ_RESET + */ +typedef struct _VRDE_USB_REQ_RESET_PARM +{ + uint8_t code; + VRDEUSBDEVID id; +} VRDE_USB_REQ_RESET_PARM; + +typedef struct _VRDE_USB_REQ_RESET_RET +{ + VRDEUSBREQRETHDR hdr; +} VRDE_USB_REQ_RESET_RET; + + +/* VRDE_USB_REQ_SET_CONFIG + */ +typedef struct _VRDE_USB_REQ_SET_CONFIG_PARM +{ + uint8_t code; + VRDEUSBDEVID id; + uint8_t configuration; +} VRDE_USB_REQ_SET_CONFIG_PARM; + +typedef struct _VRDE_USB_REQ_SET_CONFIG_RET +{ + VRDEUSBREQRETHDR hdr; +} VRDE_USB_REQ_SET_CONFIG_RET; + + +/* VRDE_USB_REQ_CLAIM_INTERFACE + */ +typedef struct _VRDE_USB_REQ_CLAIM_INTERFACE_PARM +{ + uint8_t code; + VRDEUSBDEVID id; + uint8_t iface; +} VRDE_USB_REQ_CLAIM_INTERFACE_PARM; + +typedef struct _VRDE_USB_REQ_CLAIM_INTERFACE_RET +{ + VRDEUSBREQRETHDR hdr; +} VRDE_USB_REQ_CLAIM_INTERFACE_RET; + + +/* VRDE_USB_REQ_RELEASE_INTERFACE + */ +typedef struct _VRDE_USB_REQ_RELEASE_INTERFACE_PARM +{ + uint8_t code; + VRDEUSBDEVID id; + uint8_t iface; +} VRDE_USB_REQ_RELEASE_INTERFACE_PARM; + +typedef struct _VRDE_USB_REQ_RELEASE_INTERFACE_RET +{ + VRDEUSBREQRETHDR hdr; +} VRDE_USB_REQ_RELEASE_INTERFACE_RET; + + +/* VRDE_USB_REQ_INTERFACE_SETTING + */ +typedef struct _VRDE_USB_REQ_INTERFACE_SETTING_PARM +{ + uint8_t code; + VRDEUSBDEVID id; + uint8_t iface; + uint8_t setting; +} VRDE_USB_REQ_INTERFACE_SETTING_PARM; + +typedef struct _VRDE_USB_REQ_INTERFACE_SETTING_RET +{ + VRDEUSBREQRETHDR hdr; +} VRDE_USB_REQ_INTERFACE_SETTING_RET; + + +/* VRDE_USB_REQ_QUEUE_URB + */ + +#define VRDE_USB_TRANSFER_TYPE_CTRL (0) +#define VRDE_USB_TRANSFER_TYPE_ISOC (1) +#define VRDE_USB_TRANSFER_TYPE_BULK (2) +#define VRDE_USB_TRANSFER_TYPE_INTR (3) +#define VRDE_USB_TRANSFER_TYPE_MSG (4) + +#define VRDE_USB_DIRECTION_SETUP (0) +#define VRDE_USB_DIRECTION_IN (1) +#define VRDE_USB_DIRECTION_OUT (2) + +typedef struct _VRDE_USB_REQ_QUEUE_URB_PARM +{ + uint8_t code; + VRDEUSBDEVID id; + uint32_t handle; /* Distinguishes that particular URB. Later used in CancelURB and returned by ReapURB */ + uint8_t type; + uint8_t ep; + uint8_t direction; + uint32_t urblen; /* Length of the URB. */ + uint32_t datalen; /* Length of the data. */ + void *data; /* In RDP layout the data follow. */ +} VRDE_USB_REQ_QUEUE_URB_PARM; + +/* The queue URB has no explicit return. The reap URB reply will be + * eventually the indirect result. + */ + + +/* VRDE_USB_REQ_REAP_URB + * Notificationg from server to client that server expects an URB + * from any device. + * Only sent if negotiated URB return method is polling. + * Normally, the client will send URBs back as soon as they are ready. + */ +typedef struct _VRDE_USB_REQ_REAP_URB_PARM +{ + uint8_t code; +} VRDE_USB_REQ_REAP_URB_PARM; + + +#define VRDE_USB_XFER_OK (0) +#define VRDE_USB_XFER_STALL (1) +#define VRDE_USB_XFER_DNR (2) +#define VRDE_USB_XFER_CRC (3) +/* VRDE_USB_VERSION_2: New error codes. OHCI Completion Codes. */ +#define VRDE_USB_XFER_BS (4) /* BitStuffing */ +#define VRDE_USB_XFER_DTM (5) /* DataToggleMismatch */ +#define VRDE_USB_XFER_PCF (6) /* PIDCheckFailure */ +#define VRDE_USB_XFER_UPID (7) /* UnexpectedPID */ +#define VRDE_USB_XFER_DO (8) /* DataOverrun */ +#define VRDE_USB_XFER_DU (9) /* DataUnderrun */ +#define VRDE_USB_XFER_BO (10) /* BufferOverrun */ +#define VRDE_USB_XFER_BU (11) /* BufferUnderrun */ +#define VRDE_USB_XFER_ERR (12) /* VBox protocol error. */ + +#define VRDE_USB_REAP_FLAG_CONTINUED (0x0) +#define VRDE_USB_REAP_FLAG_LAST (0x1) +/* VRDE_USB_VERSION_3: Fragmented URBs. */ +#define VRDE_USB_REAP_FLAG_FRAGMENT (0x2) + +#define VRDE_USB_REAP_VALID_FLAGS (VRDE_USB_REAP_FLAG_LAST) +/* VRDE_USB_VERSION_3: Fragmented URBs. */ +#define VRDE_USB_REAP_VALID_FLAGS_3 (VRDE_USB_REAP_FLAG_LAST | VRDE_USB_REAP_FLAG_FRAGMENT) + +typedef struct _VRDEUSBREQREAPURBBODY +{ + VRDEUSBDEVID id; /* From which device the URB arrives. */ + uint8_t flags; /* VRDE_USB_REAP_FLAG_* */ + uint8_t error; /* VRDE_USB_XFER_* */ + uint32_t handle; /* Handle of returned URB. Not 0. */ + uint32_t len; /* Length of data actually transferred. */ + /* 'len' bytes of data follow if direction of this URB was VRDE_USB_DIRECTION_IN. */ +} VRDEUSBREQREAPURBBODY; + +typedef struct _VRDE_USB_REQ_REAP_URB_RET +{ + /* The REAP URB has no header, only completed URBs are returned. */ + VRDEUSBREQREAPURBBODY body; + /* Another body may follow, depending on flags. */ +} VRDE_USB_REQ_REAP_URB_RET; + + +/* VRDE_USB_REQ_CLEAR_HALTED_EP + */ +typedef struct _VRDE_USB_REQ_CLEAR_HALTED_EP_PARM +{ + uint8_t code; + VRDEUSBDEVID id; + uint8_t ep; +} VRDE_USB_REQ_CLEAR_HALTED_EP_PARM; + +typedef struct _VRDE_USB_REQ_CLEAR_HALTED_EP_RET +{ + VRDEUSBREQRETHDR hdr; +} VRDE_USB_REQ_CLEAR_HALTED_EP_RET; + + +/* VRDE_USB_REQ_CANCEL_URB + */ +typedef struct _VRDE_USB_REQ_CANCEL_URB_PARM +{ + uint8_t code; + VRDEUSBDEVID id; + uint32_t handle; +} VRDE_USB_REQ_CANCEL_URB_PARM; + +/* The cancel URB request has no return. */ + + +/* VRDE_USB_REQ_DEVICE_LIST + * + * Server polls USB devices on client by sending this request + * periodically. Client sends back a list of all devices + * connected to it. Each device is assigned with an identifier, + * that is used to distinguish the particular device. + */ +typedef struct _VRDE_USB_REQ_DEVICE_LIST_PARM +{ + uint8_t code; +} VRDE_USB_REQ_DEVICE_LIST_PARM; + +/* Data is a list of the following variable length structures. */ +typedef struct _VRDEUSBDEVICEDESC +{ + /* Offset of the next structure. 0 if last. */ + uint16_t oNext; + + /* Identifier of the device assigned by client. */ + VRDEUSBDEVID id; + + /** USB version number. */ + uint16_t bcdUSB; + /** Device class. */ + uint8_t bDeviceClass; + /** Device subclass. */ + uint8_t bDeviceSubClass; + /** Device protocol */ + uint8_t bDeviceProtocol; + /** Vendor ID. */ + uint16_t idVendor; + /** Product ID. */ + uint16_t idProduct; + /** Revision, integer part. */ + uint16_t bcdRev; + /** Offset of the UTF8 manufacturer string relative to the structure start. */ + uint16_t oManufacturer; + /** Offset of the UTF8 product string relative to the structure start. */ + uint16_t oProduct; + /** Offset of the UTF8 serial number string relative to the structure start. */ + uint16_t oSerialNumber; + /** Physical USB port the device is connected to. */ + uint16_t idPort; + +} VRDEUSBDEVICEDESC; + +#define VRDE_USBDEVICESPEED_UNKNOWN 0 /* Unknown. */ +#define VRDE_USBDEVICESPEED_LOW 1 /* Low speed (1.5 Mbit/s). */ +#define VRDE_USBDEVICESPEED_FULL 2 /* Full speed (12 Mbit/s). */ +#define VRDE_USBDEVICESPEED_HIGH 3 /* High speed (480 Mbit/s). */ +#define VRDE_USBDEVICESPEED_VARIABLE 4 /* Variable speed - USB 2.5 / wireless. */ +#define VRDE_USBDEVICESPEED_SUPERSPEED 5 /* Super Speed - USB 3.0 */ + +typedef struct _VRDEUSBDEVICEDESCEXT +{ + VRDEUSBDEVICEDESC desc; + + /* Extended info. + */ + + /** The USB device speed: VRDE_USBDEVICESPEED_*. */ + uint16_t u16DeviceSpeed; +} VRDEUSBDEVICEDESCEXT; + +typedef struct _VRDE_USB_REQ_DEVICE_LIST_RET +{ + VRDEUSBDEVICEDESC body; + /* Other devices may follow. + * The list ends with (uint16_t)0, + * which means that an empty list consists of 2 zero bytes. + */ +} VRDE_USB_REQ_DEVICE_LIST_RET; + +typedef struct _VRDE_USB_REQ_DEVICE_LIST_EXT_RET +{ + VRDEUSBDEVICEDESCEXT body; + /* Other devices may follow. + * The list ends with (uint16_t)0, + * which means that an empty list consists of 2 zero bytes. + */ +} VRDE_USB_REQ_DEVICE_LIST_EXT_RET; + +/* The server requests the version of the port the device is attached to. + * The client must use VRDEUSBDEVICEDESCEXT structure. + */ +#define VRDE_USB_SERVER_CAPS_PORT_VERSION 0x0001 + +typedef struct _VRDEUSBREQNEGOTIATEPARM +{ + uint8_t code; + + /* Remote USB Protocol version. */ + /* VRDE_USB_VERSION_3: the 32 bit field is splitted to 16 bit version and 16 bit flags. + * Version 1 and 2 servers therefore have 'flags' == 0. + * Version 3+ servers can send some capabilities in this field, this way it is possible to add + * a new capability without increasing the protocol version. + */ + uint16_t version; + uint16_t flags; /* See VRDE_USB_SERVER_CAPS_* */ + +} VRDEUSBREQNEGOTIATEPARM; + +/* VRDEUSBREQNEGOTIATERET flags. */ +#define VRDE_USB_CAPS_FLAG_ASYNC (0x0) +#define VRDE_USB_CAPS_FLAG_POLL (0x1) +/* VRDE_USB_VERSION_2: New flag. */ +#define VRDE_USB_CAPS2_FLAG_VERSION (0x2) /* The client is negotiating the protocol version. */ +/* VRDE_USB_VERSION_3: New flag. */ +#define VRDE_USB_CAPS3_FLAG_EXT (0x4) /* The client is negotiating the extended flags. + * If this flag is set, then the VRDE_USB_CAPS2_FLAG_VERSION + * must also be set. + */ + + +#define VRDE_USB_CAPS_VALID_FLAGS (VRDE_USB_CAPS_FLAG_POLL) +/* VRDE_USB_VERSION_2: A set of valid flags. */ +#define VRDE_USB_CAPS2_VALID_FLAGS (VRDE_USB_CAPS_FLAG_POLL | VRDE_USB_CAPS2_FLAG_VERSION) +/* VRDE_USB_VERSION_3: A set of valid flags. */ +#define VRDE_USB_CAPS3_VALID_FLAGS (VRDE_USB_CAPS_FLAG_POLL | VRDE_USB_CAPS2_FLAG_VERSION | VRDE_USB_CAPS3_FLAG_EXT) + +typedef struct _VRDEUSBREQNEGOTIATERET +{ + uint8_t flags; +} VRDEUSBREQNEGOTIATERET; + +typedef struct _VRDEUSBREQNEGOTIATERET_2 +{ + uint8_t flags; + uint32_t u32Version; /* This field presents only if the VRDE_USB_CAPS2_FLAG_VERSION flag is set. */ +} VRDEUSBREQNEGOTIATERET_2; + +/* The server requests the version of the port the device is attached to. + * The client must use VRDEUSBDEVICEDESCEXT structure. + */ +#define VRDE_USB_CLIENT_CAPS_PORT_VERSION 0x00000001 + +typedef struct _VRDEUSBREQNEGOTIATERET_3 +{ + uint8_t flags; + uint32_t u32Version; /* This field presents only if the VRDE_USB_CAPS2_FLAG_VERSION flag is set. */ + uint32_t u32Flags; /* This field presents only if both VRDE_USB_CAPS2_FLAG_VERSION and + * VRDE_USB_CAPS2_FLAG_EXT flag are set. + * See VRDE_USB_CLIENT_CAPS_* + */ +} VRDEUSBREQNEGOTIATERET_3; +#pragma pack() + +#define VRDE_CLIPBOARD_FORMAT_NULL (0x0) +#define VRDE_CLIPBOARD_FORMAT_UNICODE_TEXT (0x1) +#define VRDE_CLIPBOARD_FORMAT_BITMAP (0x2) +#define VRDE_CLIPBOARD_FORMAT_HTML (0x4) + +#define VRDE_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE (0) +#define VRDE_CLIPBOARD_FUNCTION_DATA_READ (1) +#define VRDE_CLIPBOARD_FUNCTION_DATA_WRITE (2) + + +/** Indexes of information values. */ + +/** Whether a client is connected at the moment. + * uint32_t + */ +#define VRDE_QI_ACTIVE (0) + +/** How many times a client connected up to current moment. + * uint32_t + */ +#define VRDE_QI_NUMBER_OF_CLIENTS (1) + +/** When last connection was established. + * int64_t time in milliseconds since 1970-01-01 00:00:00 UTC + */ +#define VRDE_QI_BEGIN_TIME (2) + +/** When last connection was terminated or current time if connection still active. + * int64_t time in milliseconds since 1970-01-01 00:00:00 UTC + */ +#define VRDE_QI_END_TIME (3) + +/** How many bytes were sent in last (current) connection. + * uint64_t + */ +#define VRDE_QI_BYTES_SENT (4) + +/** How many bytes were sent in all connections. + * uint64_t + */ +#define VRDE_QI_BYTES_SENT_TOTAL (5) + +/** How many bytes were received in last (current) connection. + * uint64_t + */ +#define VRDE_QI_BYTES_RECEIVED (6) + +/** How many bytes were received in all connections. + * uint64_t + */ +#define VRDE_QI_BYTES_RECEIVED_TOTAL (7) + +/** Login user name supplied by the client. + * UTF8 nul terminated string. + */ +#define VRDE_QI_USER (8) + +/** Login domain supplied by the client. + * UTF8 nul terminated string. + */ +#define VRDE_QI_DOMAIN (9) + +/** The client name supplied by the client. + * UTF8 nul terminated string. + */ +#define VRDE_QI_CLIENT_NAME (10) + +/** IP address of the client. + * UTF8 nul terminated string. + */ +#define VRDE_QI_CLIENT_IP (11) + +/** The client software version number. + * uint32_t. + */ +#define VRDE_QI_CLIENT_VERSION (12) + +/** Public key exchange method used when connection was established. + * Values: 0 - RDP4 public key exchange scheme. + * 1 - X509 sertificates were sent to client. + * uint32_t. + */ +#define VRDE_QI_ENCRYPTION_STYLE (13) + +/** TCP port where the server listens. + * Values: 0 - VRDE server failed to start. + * -1 - . + * int32_t. + */ +#define VRDE_QI_PORT (14) + + +/** Hints what has been intercepted by the application. */ +#define VRDE_CLIENT_INTERCEPT_AUDIO RT_BIT(0) +#define VRDE_CLIENT_INTERCEPT_USB RT_BIT(1) +#define VRDE_CLIENT_INTERCEPT_CLIPBOARD RT_BIT(2) +#define VRDE_CLIENT_INTERCEPT_AUDIO_INPUT RT_BIT(3) + + +/** The version of the VRDE server interface. */ +#define VRDE_INTERFACE_VERSION_1 (1) +#define VRDE_INTERFACE_VERSION_2 (2) +#define VRDE_INTERFACE_VERSION_3 (3) +#define VRDE_INTERFACE_VERSION_4 (4) + +/** The header that does not change when the interface changes. */ +typedef struct _VRDEINTERFACEHDR +{ + /** The version of the interface. */ + uint64_t u64Version; + + /** The size of the structure. */ + uint64_t u64Size; + +} VRDEINTERFACEHDR; + +/** The VRDE server entry points. Interface version 1. */ +typedef struct _VRDEENTRYPOINTS_1 +{ + /** The header. */ + VRDEINTERFACEHDR header; + + /** Destroy the server instance. + * + * @param hServer The server instance handle. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(void, VRDEDestroy,(HVRDESERVER hServer)); + + /** The server should start to accept clients connections. + * + * @param hServer The server instance handle. + * @param fEnable Whether to enable or disable client connections. + * When is false, all existing clients are disconnected. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEEnableConnections,(HVRDESERVER hServer, + bool fEnable)); + + /** The server should disconnect the client. + * + * @param hServer The server instance handle. + * @param u32ClientId The client identifier. + * @param fReconnect Whether to send a "REDIRECT to the same server" packet to the + * client before disconnecting. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(void, VRDEDisconnect,(HVRDESERVER hServer, + uint32_t u32ClientId, + bool fReconnect)); + + /** + * Inform the server that the display was resized. + * The server will query information about display + * from the application via callbacks. + * + * @param hServer Handle of VRDE server instance. + */ + DECLR3CALLBACKMEMBER(void, VRDEResize,(HVRDESERVER hServer)); + + /** + * Send a update. + * + * Note: the server must access the framebuffer bitmap only when VRDEUpdate is called. + * If the have to access the bitmap later or from another thread, then + * it must used an intermediate buffer and copy the framebuffer data to the + * intermediate buffer in VRDEUpdate. + * + * @param hServer Handle of VRDE server instance. + * @param uScreenId The screen index. + * @param pvUpdate Pointer to VRDEOrders.h::VRDEORDERHDR structure with extra data. + * @param cbUpdate Size of the update data. + */ + DECLR3CALLBACKMEMBER(void, VRDEUpdate,(HVRDESERVER hServer, + unsigned uScreenId, + void *pvUpdate, + uint32_t cbUpdate)); + + /** + * Set the mouse pointer shape. + * + * @param hServer Handle of VRDE server instance. + * @param pPointer The pointer shape information. + */ + DECLR3CALLBACKMEMBER(void, VRDEColorPointer,(HVRDESERVER hServer, + const VRDECOLORPOINTER *pPointer)); + + /** + * Hide the mouse pointer. + * + * @param hServer Handle of VRDE server instance. + */ + DECLR3CALLBACKMEMBER(void, VRDEHidePointer,(HVRDESERVER hServer)); + + /** + * Queues the samples to be sent to clients. + * + * @param hServer Handle of VRDE server instance. + * @param pvSamples Address of samples to be sent. + * @param cSamples Number of samples. + * @param format Encoded audio format for these samples. + * + * @note Initialized to NULL when the application audio callbacks are NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEAudioSamples,(HVRDESERVER hServer, + const void *pvSamples, + uint32_t cSamples, + VRDEAUDIOFORMAT format)); + + /** + * Sets the sound volume on clients. + * + * @param hServer Handle of VRDE server instance. + * @param left 0..0xFFFF volume level for left channel. + * @param right 0..0xFFFF volume level for right channel. + * + * @note Initialized to NULL when the application audio callbacks are NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEAudioVolume,(HVRDESERVER hServer, + uint16_t u16Left, + uint16_t u16Right)); + + /** + * Sends a USB request. + * + * @param hServer Handle of VRDE server instance. + * @param u32ClientId An identifier that allows the server to find the corresponding client. + * The identifier is always passed by the server as a parameter + * of the FNVRDEUSBCALLBACK. Note that the value is the same as + * in the VRDESERVERCALLBACK functions. + * @param pvParm Function specific parameters buffer. + * @param cbParm Size of the buffer. + * + * @note Initialized to NULL when the application USB callbacks are NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEUSBRequest,(HVRDESERVER hServer, + uint32_t u32ClientId, + void *pvParm, + uint32_t cbParm)); + + /** + * Called by the application when (VRDE_CLIPBOARD_FUNCTION_*): + * - (0) guest announces available clipboard formats; + * - (1) guest requests clipboard data; + * - (2) guest responds to the client's request for clipboard data. + * + * @param hServer The VRDE server handle. + * @param u32Function The cause of the call. + * @param u32Format Bitmask of announced formats or the format of data. + * @param pvData Points to: (1) buffer to be filled with clients data; + * (2) data from the host. + * @param cbData Size of 'pvData' buffer in bytes. + * @param pcbActualRead Size of the copied data in bytes. + * + * @note Initialized to NULL when the application clipboard callbacks are NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEClipboard,(HVRDESERVER hServer, + uint32_t u32Function, + uint32_t u32Format, + void *pvData, + uint32_t cbData, + uint32_t *pcbActualRead)); + + /** + * Query various information from the VRDE server. + * + * @param hServer The VRDE server handle. + * @param index VRDE_QI_* identifier of information to be returned. + * @param pvBuffer Address of memory buffer to which the information must be written. + * @param cbBuffer Size of the memory buffer in bytes. + * @param pcbOut Size in bytes of returned information value. + * + * @remark The caller must check the *pcbOut. 0 there means no information was returned. + * A value greater than cbBuffer means that information is too big to fit in the + * buffer, in that case no information was placed to the buffer. + */ + DECLR3CALLBACKMEMBER(void, VRDEQueryInfo,(HVRDESERVER hServer, + uint32_t index, + void *pvBuffer, + uint32_t cbBuffer, + uint32_t *pcbOut)); +} VRDEENTRYPOINTS_1; + +/** The VRDE server entry points. Interface version 2. + * A new entry point VRDERedirect has been added relative to version 1. + */ +typedef struct _VRDEENTRYPOINTS_2 +{ + /** The header. */ + VRDEINTERFACEHDR header; + + /** Destroy the server instance. + * + * @param hServer The server instance handle. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(void, VRDEDestroy,(HVRDESERVER hServer)); + + /** The server should start to accept clients connections. + * + * @param hServer The server instance handle. + * @param fEnable Whether to enable or disable client connections. + * When is false, all existing clients are disconnected. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEEnableConnections,(HVRDESERVER hServer, + bool fEnable)); + + /** The server should disconnect the client. + * + * @param hServer The server instance handle. + * @param u32ClientId The client identifier. + * @param fReconnect Whether to send a "REDIRECT to the same server" packet to the + * client before disconnecting. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(void, VRDEDisconnect,(HVRDESERVER hServer, + uint32_t u32ClientId, + bool fReconnect)); + + /** + * Inform the server that the display was resized. + * The server will query information about display + * from the application via callbacks. + * + * @param hServer Handle of VRDE server instance. + */ + DECLR3CALLBACKMEMBER(void, VRDEResize,(HVRDESERVER hServer)); + + /** + * Send a update. + * + * Note: the server must access the framebuffer bitmap only when VRDEUpdate is called. + * If the have to access the bitmap later or from another thread, then + * it must used an intermediate buffer and copy the framebuffer data to the + * intermediate buffer in VRDEUpdate. + * + * @param hServer Handle of VRDE server instance. + * @param uScreenId The screen index. + * @param pvUpdate Pointer to VRDEOrders.h::VRDEORDERHDR structure with extra data. + * @param cbUpdate Size of the update data. + */ + DECLR3CALLBACKMEMBER(void, VRDEUpdate,(HVRDESERVER hServer, + unsigned uScreenId, + void *pvUpdate, + uint32_t cbUpdate)); + + /** + * Set the mouse pointer shape. + * + * @param hServer Handle of VRDE server instance. + * @param pPointer The pointer shape information. + */ + DECLR3CALLBACKMEMBER(void, VRDEColorPointer,(HVRDESERVER hServer, + const VRDECOLORPOINTER *pPointer)); + + /** + * Hide the mouse pointer. + * + * @param hServer Handle of VRDE server instance. + */ + DECLR3CALLBACKMEMBER(void, VRDEHidePointer,(HVRDESERVER hServer)); + + /** + * Queues the samples to be sent to clients. + * + * @param hServer Handle of VRDE server instance. + * @param pvSamples Address of samples to be sent. + * @param cSamples Number of samples. + * @param format Encoded audio format for these samples. + * + * @note Initialized to NULL when the application audio callbacks are NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEAudioSamples,(HVRDESERVER hServer, + const void *pvSamples, + uint32_t cSamples, + VRDEAUDIOFORMAT format)); + + /** + * Sets the sound volume on clients. + * + * @param hServer Handle of VRDE server instance. + * @param left 0..0xFFFF volume level for left channel. + * @param right 0..0xFFFF volume level for right channel. + * + * @note Initialized to NULL when the application audio callbacks are NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEAudioVolume,(HVRDESERVER hServer, + uint16_t u16Left, + uint16_t u16Right)); + + /** + * Sends a USB request. + * + * @param hServer Handle of VRDE server instance. + * @param u32ClientId An identifier that allows the server to find the corresponding client. + * The identifier is always passed by the server as a parameter + * of the FNVRDEUSBCALLBACK. Note that the value is the same as + * in the VRDESERVERCALLBACK functions. + * @param pvParm Function specific parameters buffer. + * @param cbParm Size of the buffer. + * + * @note Initialized to NULL when the application USB callbacks are NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEUSBRequest,(HVRDESERVER hServer, + uint32_t u32ClientId, + void *pvParm, + uint32_t cbParm)); + + /** + * Called by the application when (VRDE_CLIPBOARD_FUNCTION_*): + * - (0) guest announces available clipboard formats; + * - (1) guest requests clipboard data; + * - (2) guest responds to the client's request for clipboard data. + * + * @param hServer The VRDE server handle. + * @param u32Function The cause of the call. + * @param u32Format Bitmask of announced formats or the format of data. + * @param pvData Points to: (1) buffer to be filled with clients data; + * (2) data from the host. + * @param cbData Size of 'pvData' buffer in bytes. + * @param pcbActualRead Size of the copied data in bytes. + * + * @note Initialized to NULL when the application clipboard callbacks are NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEClipboard,(HVRDESERVER hServer, + uint32_t u32Function, + uint32_t u32Format, + void *pvData, + uint32_t cbData, + uint32_t *pcbActualRead)); + + /** + * Query various information from the VRDE server. + * + * @param hServer The VRDE server handle. + * @param index VRDE_QI_* identifier of information to be returned. + * @param pvBuffer Address of memory buffer to which the information must be written. + * @param cbBuffer Size of the memory buffer in bytes. + * @param pcbOut Size in bytes of returned information value. + * + * @remark The caller must check the *pcbOut. 0 there means no information was returned. + * A value greater than cbBuffer means that information is too big to fit in the + * buffer, in that case no information was placed to the buffer. + */ + DECLR3CALLBACKMEMBER(void, VRDEQueryInfo,(HVRDESERVER hServer, + uint32_t index, + void *pvBuffer, + uint32_t cbBuffer, + uint32_t *pcbOut)); + + /** + * The server should redirect the client to the specified server. + * + * @param hServer The server instance handle. + * @param u32ClientId The client identifier. + * @param pszServer The server to redirect the client to. + * @param pszUser The username to use for the redirection. + * Can be NULL. + * @param pszDomain The domain. Can be NULL. + * @param pszPassword The password. Can be NULL. + * @param u32SessionId The ID of the session to redirect to. + * @param pszCookie The routing token used by a load balancer to + * route the redirection. Can be NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDERedirect,(HVRDESERVER hServer, + uint32_t u32ClientId, + const char *pszServer, + const char *pszUser, + const char *pszDomain, + const char *pszPassword, + uint32_t u32SessionId, + const char *pszCookie)); +} VRDEENTRYPOINTS_2; + +/** The VRDE server entry points. Interface version 3. + * New entry points VRDEAudioInOpen and VRDEAudioInClose has been added relative to version 2. + */ +typedef struct _VRDEENTRYPOINTS_3 +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* + * Same as version 2. See comment in VRDEENTRYPOINTS_2. + */ + + DECLR3CALLBACKMEMBER(void, VRDEDestroy,(HVRDESERVER hServer)); + + DECLR3CALLBACKMEMBER(int, VRDEEnableConnections,(HVRDESERVER hServer, + bool fEnable)); + + DECLR3CALLBACKMEMBER(void, VRDEDisconnect,(HVRDESERVER hServer, + uint32_t u32ClientId, + bool fReconnect)); + + DECLR3CALLBACKMEMBER(void, VRDEResize,(HVRDESERVER hServer)); + + DECLR3CALLBACKMEMBER(void, VRDEUpdate,(HVRDESERVER hServer, + unsigned uScreenId, + void *pvUpdate, + uint32_t cbUpdate)); + + DECLR3CALLBACKMEMBER(void, VRDEColorPointer,(HVRDESERVER hServer, + const VRDECOLORPOINTER *pPointer)); + + DECLR3CALLBACKMEMBER(void, VRDEHidePointer,(HVRDESERVER hServer)); + + DECLR3CALLBACKMEMBER(void, VRDEAudioSamples,(HVRDESERVER hServer, + const void *pvSamples, + uint32_t cSamples, + VRDEAUDIOFORMAT format)); + + DECLR3CALLBACKMEMBER(void, VRDEAudioVolume,(HVRDESERVER hServer, + uint16_t u16Left, + uint16_t u16Right)); + + DECLR3CALLBACKMEMBER(void, VRDEUSBRequest,(HVRDESERVER hServer, + uint32_t u32ClientId, + void *pvParm, + uint32_t cbParm)); + + DECLR3CALLBACKMEMBER(void, VRDEClipboard,(HVRDESERVER hServer, + uint32_t u32Function, + uint32_t u32Format, + void *pvData, + uint32_t cbData, + uint32_t *pcbActualRead)); + + DECLR3CALLBACKMEMBER(void, VRDEQueryInfo,(HVRDESERVER hServer, + uint32_t index, + void *pvBuffer, + uint32_t cbBuffer, + uint32_t *pcbOut)); + + DECLR3CALLBACKMEMBER(void, VRDERedirect,(HVRDESERVER hServer, + uint32_t u32ClientId, + const char *pszServer, + const char *pszUser, + const char *pszDomain, + const char *pszPassword, + uint32_t u32SessionId, + const char *pszCookie)); + + /* + * New for version 3. + */ + + /** + * Audio input open request. + * + * @param hServer Handle of VRDE server instance. + * @param pvCtx To be used in VRDECallbackAudioIn. + * @param u32ClientId An identifier that allows the server to find the corresponding client. + * @param audioFormat Preferred format of audio data. + * @param u32SamplesPerBlock Preferred number of samples in one block of audio input data. + * + * @note Initialized to NULL when the VRDECallbackAudioIn callback is NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEAudioInOpen,(HVRDESERVER hServer, + void *pvCtx, + uint32_t u32ClientId, + VRDEAUDIOFORMAT audioFormat, + uint32_t u32SamplesPerBlock)); + + /** + * Audio input close request. + * + * @param hServer Handle of VRDE server instance. + * @param u32ClientId An identifier that allows the server to find the corresponding client. + * + * @note Initialized to NULL when the VRDECallbackAudioIn callback is NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEAudioInClose,(HVRDESERVER hServer, + uint32_t u32ClientId)); +} VRDEENTRYPOINTS_3; + + +/* Indexes for VRDECallbackProperty. + * *_QP_* queries a property. + * *_SP_* sets a property. + */ +#define VRDE_QP_NETWORK_PORT (1) /* Obsolete. Use VRDE_QP_NETWORK_PORT_RANGE instead. */ +#define VRDE_QP_NETWORK_ADDRESS (2) /* UTF8 string. Host network interface IP address to bind to. */ +#define VRDE_QP_NUMBER_MONITORS (3) /* 32 bit. Number of monitors in the VM. */ +#define VRDE_QP_NETWORK_PORT_RANGE (4) /* UTF8 string. List of ports. The server must bind to one of + * free ports from the list. Example: "3000,3010-3012,4000", + * which tells the server to bind to either of ports: + * 3000, 3010, 3011, 3012, 4000. + */ +#define VRDE_QP_VIDEO_CHANNEL (5) +#define VRDE_QP_VIDEO_CHANNEL_QUALITY (6) +#define VRDE_QP_VIDEO_CHANNEL_SUNFLSH (7) +#define VRDE_QP_FEATURE (8) /* VRDEFEATURE structure. Generic interface to query named VRDE properties. */ +#define VRDE_QP_UNIX_SOCKET_PATH (9) /* Path to a UNIX Socket for incoming connections */ + +#define VRDE_SP_BASE 0x1000 +#define VRDE_SP_NETWORK_BIND_PORT (VRDE_SP_BASE + 1) /* 32 bit. The port number actually used by the server. + * If VRDECreateServer fails, it should set the port to 0. + * If VRDECreateServer succeeds, then the port must be set + * in VRDEEnableConnections to the actually used value. + * VRDEDestroy must set the port to 0xFFFFFFFF. + */ +#define VRDE_SP_CLIENT_STATUS (VRDE_SP_BASE + 2) /* UTF8 string. The change of the generic client status: + * "ATTACH" - the client is attached; + * "DETACH" - the client is detached; + * "NAME=..." - the client name changes. + * Can be used for other notifications. + */ + +#pragma pack(1) +/* VRDE_QP_FEATURE data. */ +typedef struct _VRDEFEATURE +{ + uint32_t u32ClientId; + char achInfo[1]; /* UTF8 property input name and output value. */ +} VRDEFEATURE; + +/* VRDE_SP_CLIENT_STATUS data. */ +typedef struct VRDECLIENTSTATUS +{ + uint32_t u32ClientId; + uint32_t cbStatus; + char achStatus[1]; /* UTF8 status string. */ +} VRDECLIENTSTATUS; + +/* A framebuffer description. */ +typedef struct _VRDEFRAMEBUFFERINFO +{ + const uint8_t *pu8Bits; + int xOrigin; + int yOrigin; + unsigned cWidth; + unsigned cHeight; + unsigned cBitsPerPixel; + unsigned cbLine; +} VRDEFRAMEBUFFERINFO; + +#define VRDE_INPUT_SCANCODE 0 +#define VRDE_INPUT_POINT 1 +#define VRDE_INPUT_CAD 2 +#define VRDE_INPUT_RESET 3 +#define VRDE_INPUT_SYNCH 4 + +typedef struct _VRDEINPUTSCANCODE +{ + unsigned uScancode; +} VRDEINPUTSCANCODE; + +#define VRDE_INPUT_POINT_BUTTON1 0x01 +#define VRDE_INPUT_POINT_BUTTON2 0x02 +#define VRDE_INPUT_POINT_BUTTON3 0x04 +#define VRDE_INPUT_POINT_WHEEL_UP 0x08 +#define VRDE_INPUT_POINT_WHEEL_DOWN 0x10 + +typedef struct _VRDEINPUTPOINT +{ + int x; + int y; + unsigned uButtons; +} VRDEINPUTPOINT; + +#define VRDE_INPUT_SYNCH_SCROLL 0x01 +#define VRDE_INPUT_SYNCH_NUMLOCK 0x02 +#define VRDE_INPUT_SYNCH_CAPITAL 0x04 + +typedef struct _VRDEINPUTSYNCH +{ + unsigned uLockStatus; +} VRDEINPUTSYNCH; +#pragma pack() + +/** The VRDE server callbacks. Interface version 1. */ +typedef struct _VRDECALLBACKS_1 +{ + /** The header. */ + VRDEINTERFACEHDR header; + + /** + * Query or set various information, on how the VRDE server operates, from or to the application. + * Queries for properties will always return success, and if the key is not known or has no + * value associated with it an empty string is returned. + * + * + * @param pvCallback The callback specific pointer. + * @param index VRDE_[Q|S]P_* identifier of information to be returned or set. + * @param pvBuffer Address of memory buffer to which the information must be written or read. + * @param cbBuffer Size of the memory buffer in bytes. + * @param pcbOut Size in bytes of returned information value. + * + * @return IPRT status code. VINF_BUFFER_OVERFLOW if the buffer is too small for the value. + */ + DECLR3CALLBACKMEMBER(int, VRDECallbackProperty,(void *pvCallback, + uint32_t index, + void *pvBuffer, + uint32_t cbBuffer, + uint32_t *pcbOut)); + + /* A client is logging in, the application must decide whether + * to let to connect the client. The server will drop the connection, + * when an error code is returned by the callback. + * + * @param pvCallback The callback specific pointer. + * @param u32ClientId An unique client identifier generated by the server. + * @param pszUser The username. + * @param pszPassword The password. + * @param pszDomain The domain. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDECallbackClientLogon,(void *pvCallback, + uint32_t u32ClientId, + const char *pszUser, + const char *pszPassword, + const char *pszDomain)); + + /* The client has been successfully connected. That is logon was successful and the + * remote desktop protocol connection completely established. + * + * @param pvCallback The callback specific pointer. + * @param u32ClientId An unique client identifier generated by the server. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackClientConnect,(void *pvCallback, + uint32_t u32ClientId)); + + /* The client has been disconnected. + * + * @param pvCallback The callback specific pointer. + * @param u32ClientId An unique client identifier generated by the server. + * @param fu32Intercepted What was intercepted by the client (VRDE_CLIENT_INTERCEPT_*). + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackClientDisconnect,(void *pvCallback, + uint32_t u32ClientId, + uint32_t fu32Intercepted)); + /* The client supports one of RDP channels. + * + * @param pvCallback The callback specific pointer. + * @param u32ClientId An unique client identifier generated by the server. + * @param fu32Intercept What the client wants to intercept. One of VRDE_CLIENT_INTERCEPT_* flags. + * @param ppvIntercept The value to be passed to the channel specific callback. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDECallbackIntercept,(void *pvCallback, + uint32_t u32ClientId, + uint32_t fu32Intercept, + void **ppvIntercept)); + + /** + * Called by the server when a reply is received from a client. + * + * @param pvCallback The callback specific pointer. + * @param ppvIntercept The value returned by VRDECallbackIntercept for the VRDE_CLIENT_INTERCEPT_USB. + * @param u32ClientId Identifies the client that sent the reply. + * @param u8Code The operation code VRDE_USB_REQ_*. + * @param pvRet Points to data received from the client. + * @param cbRet Size of the data in bytes. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDECallbackUSB,(void *pvCallback, + void *pvIntercept, + uint32_t u32ClientId, + uint8_t u8Code, + const void *pvRet, + uint32_t cbRet)); + + /** + * Called by the server when (VRDE_CLIPBOARD_FUNCTION_*): + * - (0) client announces available clipboard formats; + * - (1) client requests clipboard data. + * + * @param pvCallback The callback specific pointer. + * @param ppvIntercept The value returned by VRDECallbackIntercept for the VRDE_CLIENT_INTERCEPT_CLIPBOARD. + * @param u32ClientId Identifies the RDP client that sent the reply. + * @param u32Function The cause of the callback. + * @param u32Format Bitmask of reported formats or the format of received data. + * @param pvData Reserved. + * @param cbData Reserved. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDECallbackClipboard,(void *pvCallback, + void *pvIntercept, + uint32_t u32ClientId, + uint32_t u32Function, + uint32_t u32Format, + const void *pvData, + uint32_t cbData)); + + /* The framebuffer information is queried. + * + * @param pvCallback The callback specific pointer. + * @param uScreenId The framebuffer index. + * @param pInfo The information structure to ber filled. + * + * @return Whether the framebuffer is available. + */ + DECLR3CALLBACKMEMBER(bool, VRDECallbackFramebufferQuery,(void *pvCallback, + unsigned uScreenId, + VRDEFRAMEBUFFERINFO *pInfo)); + + /* Request the exclusive access to the framebuffer bitmap. + * Currently not used because VirtualBox makes sure that the framebuffer is available + * when VRDEUpdate is called. + * + * @param pvCallback The callback specific pointer. + * @param uScreenId The framebuffer index. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackFramebufferLock,(void *pvCallback, + unsigned uScreenId)); + + /* Release the exclusive access to the framebuffer bitmap. + * Currently not used because VirtualBox makes sure that the framebuffer is available + * when VRDEUpdate is called. + * + * @param pvCallback The callback specific pointer. + * @param uScreenId The framebuffer index. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackFramebufferUnlock,(void *pvCallback, + unsigned uScreenId)); + + /* Input from the client. + * + * @param pvCallback The callback specific pointer. + * @param pvInput The input information. + * @param cbInput The size of the input information. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackInput,(void *pvCallback, + int type, + const void *pvInput, + unsigned cbInput)); + + /* Video mode hint from the client. + * + * @param pvCallback The callback specific pointer. + * @param cWidth Requested width. + * @param cHeight Requested height. + * @param cBitsPerPixel Requested color depth. + * @param uScreenId The framebuffer index. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackVideoModeHint,(void *pvCallback, + unsigned cWidth, + unsigned cHeight, + unsigned cBitsPerPixel, + unsigned uScreenId)); + +} VRDECALLBACKS_1; + +/* Callbacks are the same for the version 1 and version 2 interfaces. */ +typedef VRDECALLBACKS_1 VRDECALLBACKS_2; + +/** The VRDE server callbacks. Interface version 3. */ +typedef struct _VRDECALLBACKS_3 +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* + * Same as in version 1 and 2. See comment in VRDECALLBACKS_1. + */ + DECLR3CALLBACKMEMBER(int, VRDECallbackProperty,(void *pvCallback, + uint32_t index, + void *pvBuffer, + uint32_t cbBuffer, + uint32_t *pcbOut)); + + DECLR3CALLBACKMEMBER(int, VRDECallbackClientLogon,(void *pvCallback, + uint32_t u32ClientId, + const char *pszUser, + const char *pszPassword, + const char *pszDomain)); + + DECLR3CALLBACKMEMBER(void, VRDECallbackClientConnect,(void *pvCallback, + uint32_t u32ClientId)); + + DECLR3CALLBACKMEMBER(void, VRDECallbackClientDisconnect,(void *pvCallback, + uint32_t u32ClientId, + uint32_t fu32Intercepted)); + DECLR3CALLBACKMEMBER(int, VRDECallbackIntercept,(void *pvCallback, + uint32_t u32ClientId, + uint32_t fu32Intercept, + void **ppvIntercept)); + + DECLR3CALLBACKMEMBER(int, VRDECallbackUSB,(void *pvCallback, + void *pvIntercept, + uint32_t u32ClientId, + uint8_t u8Code, + const void *pvRet, + uint32_t cbRet)); + + DECLR3CALLBACKMEMBER(int, VRDECallbackClipboard,(void *pvCallback, + void *pvIntercept, + uint32_t u32ClientId, + uint32_t u32Function, + uint32_t u32Format, + const void *pvData, + uint32_t cbData)); + + DECLR3CALLBACKMEMBER(bool, VRDECallbackFramebufferQuery,(void *pvCallback, + unsigned uScreenId, + VRDEFRAMEBUFFERINFO *pInfo)); + + DECLR3CALLBACKMEMBER(void, VRDECallbackFramebufferLock,(void *pvCallback, + unsigned uScreenId)); + + DECLR3CALLBACKMEMBER(void, VRDECallbackFramebufferUnlock,(void *pvCallback, + unsigned uScreenId)); + + DECLR3CALLBACKMEMBER(void, VRDECallbackInput,(void *pvCallback, + int type, + const void *pvInput, + unsigned cbInput)); + + DECLR3CALLBACKMEMBER(void, VRDECallbackVideoModeHint,(void *pvCallback, + unsigned cWidth, + unsigned cHeight, + unsigned cBitsPerPixel, + unsigned uScreenId)); + + /* + * New for version 3. + */ + + /** + * Called by the server when something happens with audio input. + * + * @param pvCallback The callback specific pointer. + * @param pvCtx The value passed in VRDEAudioInOpen. + * @param u32ClientId Identifies the client that sent the reply. + * @param u32Event The event code VRDE_AUDIOIN_*. + * @param pvData Points to data received from the client. + * @param cbData Size of the data in bytes. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackAudioIn,(void *pvCallback, + void *pvCtx, + uint32_t u32ClientId, + uint32_t u32Event, + const void *pvData, + uint32_t cbData)); +} VRDECALLBACKS_3; + +/** The VRDE server entry points. Interface version 4. + * New entry point VRDEGetInterface has been added relative to version 3. + */ +typedef struct _VRDEENTRYPOINTS_4 +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* + * Same as version 3. See comment in VRDEENTRYPOINTS_3. + */ + + DECLR3CALLBACKMEMBER(void, VRDEDestroy,(HVRDESERVER hServer)); + DECLR3CALLBACKMEMBER(int, VRDEEnableConnections,(HVRDESERVER hServer, bool fEnable)); + DECLR3CALLBACKMEMBER(void, VRDEDisconnect,(HVRDESERVER hServer, uint32_t u32ClientId, bool fReconnect)); + DECLR3CALLBACKMEMBER(void, VRDEResize,(HVRDESERVER hServer)); + DECLR3CALLBACKMEMBER(void, VRDEUpdate,(HVRDESERVER hServer, unsigned uScreenId, void *pvUpdate, + uint32_t cbUpdate)); + DECLR3CALLBACKMEMBER(void, VRDEColorPointer,(HVRDESERVER hServer, const VRDECOLORPOINTER *pPointer)); + DECLR3CALLBACKMEMBER(void, VRDEHidePointer,(HVRDESERVER hServer)); + DECLR3CALLBACKMEMBER(void, VRDEAudioSamples,(HVRDESERVER hServer, const void *pvSamples, uint32_t cSamples, + VRDEAUDIOFORMAT format)); + DECLR3CALLBACKMEMBER(void, VRDEAudioVolume,(HVRDESERVER hServer, uint16_t u16Left, uint16_t u16Right)); + DECLR3CALLBACKMEMBER(void, VRDEUSBRequest,(HVRDESERVER hServer, uint32_t u32ClientId, void *pvParm, + uint32_t cbParm)); + DECLR3CALLBACKMEMBER(void, VRDEClipboard,(HVRDESERVER hServer, uint32_t u32Function, uint32_t u32Format, + void *pvData, uint32_t cbData, uint32_t *pcbActualRead)); + DECLR3CALLBACKMEMBER(void, VRDEQueryInfo,(HVRDESERVER hServer, uint32_t index, void *pvBuffer, uint32_t cbBuffer, + uint32_t *pcbOut)); + DECLR3CALLBACKMEMBER(void, VRDERedirect,(HVRDESERVER hServer, uint32_t u32ClientId, const char *pszServer, + const char *pszUser, const char *pszDomain, const char *pszPassword, + uint32_t u32SessionId, const char *pszCookie)); + DECLR3CALLBACKMEMBER(void, VRDEAudioInOpen,(HVRDESERVER hServer, void *pvCtx, uint32_t u32ClientId, + VRDEAUDIOFORMAT audioFormat, uint32_t u32SamplesPerBlock)); + DECLR3CALLBACKMEMBER(void, VRDEAudioInClose,(HVRDESERVER hServer, uint32_t u32ClientId)); + + /** + * Generic interface query. An interface is a set of entry points and callbacks. + * It is not a reference counted interface. + * + * @param hServer Handle of VRDE server instance. + * @param pszId String identifier of the interface, like uuid. + * @param pInterface The interface structure to be initialized by the VRDE server. + * Only VRDEINTERFACEHDR is initialized by the caller. + * @param pCallbacks Callbacks required by the interface. The server makes a local copy. + * VRDEINTERFACEHDR version must correspond to the requested interface version. + * @param pvContext The context to be used in callbacks. + */ + + DECLR3CALLBACKMEMBER(int, VRDEGetInterface, (HVRDESERVER hServer, + const char *pszId, + VRDEINTERFACEHDR *pInterface, + const VRDEINTERFACEHDR *pCallbacks, + void *pvContext)); +} VRDEENTRYPOINTS_4; + +/* Callbacks are the same for the version 3 and version 4 interfaces. */ +typedef VRDECALLBACKS_3 VRDECALLBACKS_4; + +/** + * Create a new VRDE server instance. The instance is fully functional but refuses + * client connections until the entry point VRDEEnableConnections is called by the application. + * + * The caller prepares the VRDECALLBACKS_* structure. The header.u64Version field of the + * structure must be initialized with the version of the interface to use. + * The server will return pointer to VRDEENTRYPOINTS_* table in *ppEntryPoints + * to match the requested interface. + * That is if pCallbacks->header.u64Version == VRDE_INTERFACE_VERSION_1, then the server + * expects pCallbacks to point to VRDECALLBACKS_1 and will return a pointer to VRDEENTRYPOINTS_1. + * + * @param pCallback Pointer to the application callbacks which let the server to fetch + * the configuration data and to access the desktop. + * @param pvCallback The callback specific pointer to be passed back to the application. + * @param ppEntryPoints Where to store the pointer to the VRDE entry points structure. + * @param phServer Pointer to the created server instance handle. + * + * @return IPRT status code. + */ +DECLEXPORT(int) VRDECreateServer (const VRDEINTERFACEHDR *pCallbacks, + void *pvCallback, + VRDEINTERFACEHDR **ppEntryPoints, + HVRDESERVER *phServer); + +typedef DECLCALLBACKTYPE(int, FNVRDECREATESERVER,(const VRDEINTERFACEHDR *pCallbacks, + void *pvCallback, + VRDEINTERFACEHDR **ppEntryPoints, + HVRDESERVER *phServer)); +typedef FNVRDECREATESERVER *PFNVRDECREATESERVER; + +/** + * List of names of the VRDE properties, which are recognized by the VRDE. + * + * For example VRDESupportedProperties should return gapszProperties declared as: + * + * static const char * const gapszProperties[] = + * { + * "TCP/Ports", + * "TCP/Address", + * NULL + * }; + * + * @returns pointer to array of pointers to name strings (UTF8). + */ +DECLEXPORT(const char * const *) VRDESupportedProperties (void); + +typedef DECLCALLBACKTYPE(const char * const *, FNVRDESUPPORTEDPROPERTIES,(void)); +typedef FNVRDESUPPORTEDPROPERTIES *PFNVRDESUPPORTEDPROPERTIES; + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_RemoteDesktop_VRDE_h */ diff --git a/include/VBox/RemoteDesktop/VRDEImage.h b/include/VBox/RemoteDesktop/VRDEImage.h new file mode 100644 index 00000000..54cd674e --- /dev/null +++ b/include/VBox/RemoteDesktop/VRDEImage.h @@ -0,0 +1,256 @@ +/** @file + * VBox Remote Desktop Extension (VRDE) - Image updates interface. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_RemoteDesktop_VRDEImage_h +#define VBOX_INCLUDED_RemoteDesktop_VRDEImage_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/RemoteDesktop/VRDE.h> + +/* + * Generic interface for external image updates with a clipping region to be sent + * to the client. + * + * Async callbacks are used for reporting errors, providing feedback, etc. + */ + +#define VRDE_IMAGE_INTERFACE_NAME "IMAGE" + +#ifdef __cplusplus +class VRDEImage; +typedef class VRDEImage *HVRDEIMAGE; +#else +struct VRDEImage; +typedef struct VRDEImage *HVRDEIMAGE; +#endif /* __cplusplus */ + +/* + * Format description structures for VRDEImageHandleCreate. + */ +typedef struct VRDEIMAGEFORMATBITMAP +{ + uint32_t u32BytesPerPixel; /** @todo impl */ +} VRDEIMAGEFORMATBITMAP; + +typedef struct VRDEIMAGEBITMAP +{ + uint32_t cWidth; /* The width of the bitmap in pixels. */ + uint32_t cHeight; /* The height of the bitmap in pixels. */ + const void *pvData; /* Address of pixel buffer. */ + uint32_t cbData; /* Size of pixel buffer. */ + const void *pvScanLine0; /* Address of first scanline. */ + int32_t iScanDelta; /* Difference between two scanlines. */ +} VRDEIMAGEBITMAP; + +/* + * Image update handle creation flags. + */ +#define VRDE_IMAGE_F_CREATE_DEFAULT 0x00000000 +#define VRDE_IMAGE_F_CREATE_CONTENT_3D 0x00000001 /* Input image data is a rendered 3d scene. */ +#define VRDE_IMAGE_F_CREATE_CONTENT_VIDEO 0x00000002 /* Input image data is a sequence of video frames. */ +#define VRDE_IMAGE_F_CREATE_WINDOW 0x00000004 /* pRect parameter is the image update area. */ + +/* + * Completion flags for image update handle creation. + */ +#define VRDE_IMAGE_F_COMPLETE_DEFAULT 0x00000000 /* The handle has been created. */ +#define VRDE_IMAGE_F_COMPLETE_ASYNC 0x00000001 /* The server will call VRDEImageCbNotify when the handle is ready. */ + +/* + * Supported input image formats. + * + * The identifiers are arbitrary and new formats can be introduced later. + * + */ +#define VRDE_IMAGE_FMT_ID_BITMAP_BGRA8 "BITMAP_BGRA8.07e46a64-e93e-41d4-a845-204094f5ccf1" + +/** The VRDE server external image updates interface entry points. Interface version 1. */ +typedef struct VRDEIMAGEINTERFACE +{ + /** The header. */ + VRDEINTERFACEHDR header; + + /** Create image updates handle. + * + * The server can setup a context which will speed up further updates. + * + * A failure is returned if the server either does not support requested updates + * or it failed to create a handle. + * + * A success means that the server was able to create an internal context for + * the updates. + * + * @param hServer The server instance handle. + * @param phImage The returned image updates handle. + * @param pvUser The caller context of the call. + * @param u32ScreenId Updates are for this screen in a multimonitor config. + * @param fu32Flags VRDE_IMAGE_F_CREATE_* flags, which describe input data. + * @param pRect If VRDE_IMAGE_F_CREATE_WINDOW is set, this is the area of expected updates. + * Otherwise the entire screen will be used for updates. + * @param pvFormat Format specific data. + * @param cbFormat Size of format specific data. + * @param *pfu32CompletionFlags VRDE_IMAGE_F_COMPLETE_* flags. Async handle creation, etc. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEImageHandleCreate, (HVRDESERVER hServer, + HVRDEIMAGE *phImage, + void *pvUser, + uint32_t u32ScreenId, + uint32_t fu32Flags, + const RTRECT *pRect, + const char *pszFormatId, + const void *pvFormat, + uint32_t cbFormat, + uint32_t *pfu32CompletionFlags)); + + /** Create image updates handle. + * + * @param hImage The image updates handle, which the caller will not use anymore. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(void, VRDEImageHandleClose, (HVRDEIMAGE hImage)); + + /** Set a clipping region for a particular screen. + * + * @param hImage The image updates handle. + * @param cRects How many rectangles. 0 clears region for this screen. + * @param paRects Rectangles in the screen coordinates. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEImageRegionSet, (HVRDEIMAGE hImage, + uint32_t cRects, + const RTRECT *paRects)); + + /** Set the new position of the update area. Only works if the image handle + * has been created with VRDE_IMAGE_F_CREATE_WINDOW. + * + * @param hImage The image updates handle. + * @param pRect New area rectangle in the screen coordinates. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEImageGeometrySet, (HVRDEIMAGE hImage, + const RTRECT *pRect)); + + /** Set a configuration parameter. + * + * @param hImage The image updates handle. + * @param pszName The parameter name. + * @param pszValue The parameter value. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEImagePropertySet, (HVRDEIMAGE hImage, + const char *pszName, + const char *pszValue)); + + /** Query a configuration parameter. + * + * @param hImage The image updates handle. + * @param pszName The parameter name. + * @param pszValue The parameter value. + * @param cbValueIn The size of pszValue buffer. + * @param pcbValueOut The length of data returned in pszValue buffer. + * + * Properties names: + * "ID" - an unique string for this hImage. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEImagePropertyQuery, (HVRDEIMAGE hImage, + const char *pszName, + char *pszValue, + uint32_t cbValueIn, + uint32_t *pcbValueOut)); + + /** Data for an image update. + * + * @param hImage The image updates handle. + * @param i32TargetX Target x. + * @param i32TargetY Target y. + * @param i32TargetW Target width. + * @param i32TargetH Target height. + * @param pvImageData Format specific image data (for example VRDEIMAGEBITMAP). + * @param cbImageData Size of format specific image data. + */ + DECLR3CALLBACKMEMBER(void, VRDEImageUpdate, (HVRDEIMAGE hImage, + int32_t i32TargetX, + int32_t i32TargetY, + uint32_t u32TargetW, + uint32_t u32TargetH, + const void *pvImageData, + uint32_t cbImageData)); +} VRDEIMAGEINTERFACE; + +/* + * Notifications. + * u32Id parameter of VRDEIMAGECALLBACKS::VRDEImageCbNotify. + */ +#define VRDE_IMAGE_NOTIFY_HANDLE_CREATE 1 /* Async result of VRDEImageHandleCreate. + * pvData: uint32_t = 0 if stream was not created, + * a non zero value otherwise. + */ + +typedef struct VRDEIMAGECALLBACKS +{ + /** The header. */ + VRDEINTERFACEHDR header; + + /** Generic notification callback. + * + * @param hServer The server instance handle. + * @param pvContext The callbacks context specified in VRDEGetInterface. + * @param pvUser The pvUser parameter of VRDEImageHandleCreate. + * @param hImage The handle, same as returned by VRDEImageHandleCreate. + * @param u32Id The notification identifier: VRDE_IMAGE_NOTIFY_*. + * @param pvData The callback specific data. + * @param cbData The size of buffer pointed by pvData. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEImageCbNotify,(void *pvContext, + void *pvUser, + HVRDEIMAGE hVideo, + uint32_t u32Id, + void *pvData, + uint32_t cbData)); +} VRDEIMAGECALLBACKS; + +#endif /* !VBOX_INCLUDED_RemoteDesktop_VRDEImage_h */ diff --git a/include/VBox/RemoteDesktop/VRDEInput.h b/include/VBox/RemoteDesktop/VRDEInput.h new file mode 100644 index 00000000..378520ec --- /dev/null +++ b/include/VBox/RemoteDesktop/VRDEInput.h @@ -0,0 +1,234 @@ +/** @file + * VBox Remote Desktop Extension (VRDE) - Input interface. + */ + +/* + * Copyright (C) 2013-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_RemoteDesktop_VRDEInput_h +#define VBOX_INCLUDED_RemoteDesktop_VRDEInput_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/RemoteDesktop/VRDE.h> + +/* + * Interface for receiving input events from the client. + */ + +/* All structures in this file are packed. + * Everything is little-endian. + */ +#pragma pack(1) + +/* + * The application interface between VirtualBox and the VRDE server. + */ + +#define VRDE_INPUT_INTERFACE_NAME "VRDE::INPUT" + +/* + * Supported input methods. + */ +#define VRDE_INPUT_METHOD_TOUCH 1 + +/* + * fu32Flags for VRDEInputSetup + */ +#define VRDE_INPUT_F_ENABLE 1 + +/* The interface entry points. Interface version 1. */ +typedef struct VRDEINPUTINTERFACE +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* Tell the server that an input method will be used or disabled, etc. + * VRDECallbackInputSetup will be called with a result. + * + * @param hServer The VRDE server instance. + * @param u32Method The method VRDE_INPUT_METHOD_*. + * @param fu32Flags What to do with the method VRDE_INPUT_F_*. + * @param pvSetup Method specific parameters (optional). + * @param cbSetup Size of method specific parameters (optional). + */ + DECLR3CALLBACKMEMBER(void, VRDEInputSetup, (HVRDESERVER hServer, + uint32_t u32Method, + uint32_t fu32Flags, + const void *pvSetup, + uint32_t cbSetup)); +} VRDEINPUTINTERFACE; + + +/* Interface callbacks. */ +typedef struct VRDEINPUTCALLBACKS +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* VRDPInputSetup async result. + * + * @param pvCallback The callbacks context specified in VRDEGetInterface. + * @param rcSetup The result code of the request. + * @param u32Method The method VRDE_INPUT_METHOD_*. + * @param pvResult The result information. + * @param cbResult The size of buffer pointed by pvResult. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackInputSetup,(void *pvCallback, + int rcRequest, + uint32_t u32Method, + const void *pvResult, + uint32_t cbResult)); + + /* Input event. + * + * @param pvCallback The callbacks context specified in VRDEGetInterface. + * @param u32Method The method VRDE_INPUT_METHOD_*. + * @param pvEvent The event data. + * @param cbEvent The size of buffer pointed by pvEvent. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackInputEvent,(void *pvCallback, + uint32_t u32Method, + const void *pvEvent, + uint32_t cbEvent)); +} VRDEINPUTCALLBACKS; + + +/* + * Touch input definitions VRDE_INPUT_METHOD_TOUCH. + */ + +/* pvResult is not used */ + +/* RDPINPUT_HEADER */ +typedef struct VRDEINPUTHEADER +{ + uint16_t u16EventId; + uint32_t u32PDULength; +} VRDEINPUTHEADER; + +/* VRDEINPUTHEADER::u16EventId */ +#define VRDEINPUT_EVENTID_SC_READY 0x0001 +#define VRDEINPUT_EVENTID_CS_READY 0x0002 +#define VRDEINPUT_EVENTID_TOUCH 0x0003 +#define VRDEINPUT_EVENTID_SUSPEND_TOUCH 0x0004 +#define VRDEINPUT_EVENTID_RESUME_TOUCH 0x0005 +#define VRDEINPUT_EVENTID_DISMISS_HOVERING_CONTACT 0x0006 + +/* RDPINPUT_SC_READY_PDU */ +typedef struct VRDEINPUT_SC_READY_PDU +{ + VRDEINPUTHEADER header; + uint32_t u32ProtocolVersion; +} VRDEINPUT_SC_READY_PDU; + +#define VRDEINPUT_PROTOCOL_V1 0x00010000 +#define VRDEINPUT_PROTOCOL_V101 0x00010001 + +/* RDPINPUT_CS_READY_PDU */ +typedef struct VRDEINPUT_CS_READY_PDU +{ + VRDEINPUTHEADER header; + uint32_t u32Flags; + uint32_t u32ProtocolVersion; + uint16_t u16MaxTouchContacts; +} VRDEINPUT_CS_READY_PDU; + +#define VRDEINPUT_READY_FLAGS_SHOW_TOUCH_VISUALS 0x00000001 +#define VRDEINPUT_READY_FLAGS_DISABLE_TIMESTAMP_INJECTION 0x00000002 + +/* RDPINPUT_CONTACT_DATA */ +typedef struct VRDEINPUT_CONTACT_DATA +{ + uint8_t u8ContactId; + uint16_t u16FieldsPresent; + int32_t i32X; + int32_t i32Y; + uint32_t u32ContactFlags; + int16_t i16ContactRectLeft; + int16_t i16ContactRectTop; + int16_t i16ContactRectRight; + int16_t i16ContactRectBottom; + uint32_t u32Orientation; + uint32_t u32Pressure; +} VRDEINPUT_CONTACT_DATA; + +#define VRDEINPUT_CONTACT_DATA_CONTACTRECT_PRESENT 0x0001 +#define VRDEINPUT_CONTACT_DATA_ORIENTATION_PRESENT 0x0002 +#define VRDEINPUT_CONTACT_DATA_PRESSURE_PRESENT 0x0004 + +#define VRDEINPUT_CONTACT_FLAG_DOWN 0x0001 +#define VRDEINPUT_CONTACT_FLAG_UPDATE 0x0002 +#define VRDEINPUT_CONTACT_FLAG_UP 0x0004 +#define VRDEINPUT_CONTACT_FLAG_INRANGE 0x0008 +#define VRDEINPUT_CONTACT_FLAG_INCONTACT 0x0010 +#define VRDEINPUT_CONTACT_FLAG_CANCELED 0x0020 + +/* RDPINPUT_TOUCH_FRAME */ +typedef struct VRDEINPUT_TOUCH_FRAME +{ + uint16_t u16ContactCount; + uint64_t u64FrameOffset; + VRDEINPUT_CONTACT_DATA aContacts[1]; +} VRDEINPUT_TOUCH_FRAME; + +/* RDPINPUT_TOUCH_EVENT_PDU */ +typedef struct VRDEINPUT_TOUCH_EVENT_PDU +{ + VRDEINPUTHEADER header; + uint32_t u32EncodeTime; + uint16_t u16FrameCount; + VRDEINPUT_TOUCH_FRAME aFrames[1]; +} VRDEINPUT_TOUCH_EVENT_PDU; + +/* RDPINPUT_SUSPEND_TOUCH_PDU */ +typedef struct VRDEINPUT_SUSPEND_TOUCH_PDU +{ + VRDEINPUTHEADER header; +} VRDEINPUT_SUSPEND_TOUCH_PDU; + +/* RDPINPUT_RESUME_TOUCH_PDU */ +typedef struct VRDEINPUT_RESUME_TOUCH_PDU +{ + VRDEINPUTHEADER header; +} VRDEINPUT_RESUME_TOUCH_PDU; + +/* RDPINPUT_DISMISS_HOVERING_CONTACT_PDU */ +typedef struct VRDEINPUT_DISMISS_HOVERING_CONTACT_PDU +{ + VRDEINPUTHEADER header; + uint8_t u8ContactId; +} VRDEINPUT_DISMISS_HOVERING_CONTACT_PDU; + +#pragma pack() + +#endif /* !VBOX_INCLUDED_RemoteDesktop_VRDEInput_h */ diff --git a/include/VBox/RemoteDesktop/VRDEMousePtr.h b/include/VBox/RemoteDesktop/VRDEMousePtr.h new file mode 100644 index 00000000..e62bc708 --- /dev/null +++ b/include/VBox/RemoteDesktop/VRDEMousePtr.h @@ -0,0 +1,82 @@ +/** @file + * VBox Remote Desktop Extension (VRDE) - Mouse pointer updates interface. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_RemoteDesktop_VRDEMousePtr_h +#define VBOX_INCLUDED_RemoteDesktop_VRDEMousePtr_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/RemoteDesktop/VRDE.h> + +/* + * Interface for mouse pointer updates. + */ + +#define VRDE_MOUSEPTR_INTERFACE_NAME "MOUSEPTR" + +#pragma pack(1) +/* The color mouse pointer information: maximum allowed pointer size is 256x256. */ +typedef struct VRDEMOUSEPTRDATA +{ + uint16_t u16HotX; + uint16_t u16HotY; + uint16_t u16Width; + uint16_t u16Height; + uint16_t u16MaskLen; /* 0 for 32BPP pointers with alpha channel. */ + uint32_t u32DataLen; + /* uint8_t au8Mask[u16MaskLen]; The 1BPP mask. Optional: does not exist if u16MaskLen == 0. */ + /* uint8_t au8Data[u16DataLen]; The color bitmap, 32 bits color depth. */ +} VRDEMOUSEPTRDATA; +#pragma pack() + +/** The VRDE server external mouse pointer updates interface entry points. Interface version 1. */ +typedef struct VRDEMOUSEPTRINTERFACE +{ + /** The header. */ + VRDEINTERFACEHDR header; + + /** Set the mouse pointer. + * + * @param hServer The server instance handle. + * @param pPointer The mouse pointer description. + * + */ + DECLR3CALLBACKMEMBER(void, VRDEMousePtr, (HVRDESERVER hServer, + const VRDEMOUSEPTRDATA *pPointer)); + +} VRDEMOUSEPTRINTERFACE; + +#endif /* !VBOX_INCLUDED_RemoteDesktop_VRDEMousePtr_h */ diff --git a/include/VBox/RemoteDesktop/VRDEOrders.h b/include/VBox/RemoteDesktop/VRDEOrders.h new file mode 100644 index 00000000..06428fe0 --- /dev/null +++ b/include/VBox/RemoteDesktop/VRDEOrders.h @@ -0,0 +1,310 @@ +/** @file + * VBox Remote Desktop Extension (VRDE) - Graphics Orders Structures. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_RemoteDesktop_VRDEOrders_h +#define VBOX_INCLUDED_RemoteDesktop_VRDEOrders_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/* + * VRDE gets an information about a graphical update as a pointer + * to a memory block and the size of the memory block. + * The memory block layout is: + * VRDEORDERHDR - Describes the affected rectangle. + * Then VRDE orders follow: + * VRDEORDERCODE; + * a VRDEORDER* structure. + * + * If size of the memory block is equal to the VRDEORDERHDR, then a bitmap + * update is assumed. + */ + +/* VRDE order codes. Must be >= 0, because the VRDE internally + * uses negative values to mark some operations. + */ +#define VRDE_ORDER_DIRTY_RECT (0) +#define VRDE_ORDER_SOLIDRECT (1) +#define VRDE_ORDER_SOLIDBLT (2) +#define VRDE_ORDER_DSTBLT (3) +#define VRDE_ORDER_SCREENBLT (4) +#define VRDE_ORDER_PATBLTBRUSH (5) +#define VRDE_ORDER_MEMBLT (6) +#define VRDE_ORDER_CACHED_BITMAP (7) +#define VRDE_ORDER_DELETED_BITMAP (8) +#define VRDE_ORDER_LINE (9) +#define VRDE_ORDER_BOUNDS (10) +#define VRDE_ORDER_REPEAT (11) +#define VRDE_ORDER_POLYLINE (12) +#define VRDE_ORDER_ELLIPSE (13) +#define VRDE_ORDER_SAVESCREEN (14) +#define VRDE_ORDER_TEXT (15) + +/* 128 bit bitmap hash. */ +typedef uint8_t VRDEBITMAPHASH[16]; + +#pragma pack(1) +typedef struct _VRDEORDERHDR +{ + /** Coordinates of the affected rectangle. */ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; +} VRDEORDERHDR; + +typedef struct _VRDEORDERCODE +{ + uint32_t u32Code; +} VRDEORDERCODE; + +typedef struct _VRDEORDERPOINT +{ + int16_t x; + int16_t y; +} VRDEORDERPOINT; + +typedef struct _VRDEORDERPOLYPOINTS +{ + uint8_t c; + VRDEORDERPOINT a[16]; +} VRDEORDERPOLYPOINTS; + +typedef struct _VRDEORDERAREA +{ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; +} VRDEORDERAREA; + +typedef struct _VRDEORDERRECT +{ + int16_t left; + int16_t top; + int16_t right; + int16_t bottom; +} VRDEORDERRECT; + + +typedef struct _VRDEORDERBOUNDS +{ + VRDEORDERPOINT pt1; + VRDEORDERPOINT pt2; +} VRDEORDERBOUNDS; + +typedef struct _VRDEORDERREPEAT +{ + VRDEORDERBOUNDS bounds; +} VRDEORDERREPEAT; + + +/* Header for bitmap bits. */ +typedef struct _VRDEDATABITS +{ + uint32_t cb; /* Size of bitmap data without the header. */ + int16_t x; + int16_t y; + uint16_t cWidth; + uint16_t cHeight; + uint8_t cbPixel; + /* Bitmap data follow. */ +} VRDEDATABITS; + +typedef struct _VRDEORDERSOLIDRECT +{ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; + uint32_t rgb; +} VRDEORDERSOLIDRECT; + +typedef struct _VRDEORDERSOLIDBLT +{ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; + uint32_t rgb; + uint8_t rop; +} VRDEORDERSOLIDBLT; + +typedef struct _VRDEORDERDSTBLT +{ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; + uint8_t rop; +} VRDEORDERDSTBLT; + +typedef struct _VRDEORDERSCREENBLT +{ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; + int16_t xSrc; + int16_t ySrc; + uint8_t rop; +} VRDEORDERSCREENBLT; + +typedef struct _VRDEORDERPATBLTBRUSH +{ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; + int8_t xSrc; + int8_t ySrc; + uint32_t rgbFG; + uint32_t rgbBG; + uint8_t rop; + uint8_t pattern[8]; +} VRDEORDERPATBLTBRUSH; + +typedef struct _VRDEORDERMEMBLT +{ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; + int16_t xSrc; + int16_t ySrc; + uint8_t rop; + VRDEBITMAPHASH hash; +} VRDEORDERMEMBLT; + +typedef struct _VRDEORDERCACHEDBITMAP +{ + VRDEBITMAPHASH hash; + /* VRDEDATABITS and the bitmap data follow. */ +} VRDEORDERCACHEDBITMAP; + +typedef struct _VRDEORDERDELETEDBITMAP +{ + VRDEBITMAPHASH hash; +} VRDEORDERDELETEDBITMAP; + +typedef struct _VRDEORDERLINE +{ + int16_t x1; + int16_t y1; + int16_t x2; + int16_t y2; + int16_t xBounds1; + int16_t yBounds1; + int16_t xBounds2; + int16_t yBounds2; + uint8_t mix; + uint32_t rgb; +} VRDEORDERLINE; + +typedef struct _VRDEORDERPOLYLINE +{ + VRDEORDERPOINT ptStart; + uint8_t mix; + uint32_t rgb; + VRDEORDERPOLYPOINTS points; +} VRDEORDERPOLYLINE; + +typedef struct _VRDEORDERELLIPSE +{ + VRDEORDERPOINT pt1; + VRDEORDERPOINT pt2; + uint8_t mix; + uint8_t fillMode; + uint32_t rgb; +} VRDEORDERELLIPSE; + +typedef struct _VRDEORDERSAVESCREEN +{ + VRDEORDERPOINT pt1; + VRDEORDERPOINT pt2; + uint8_t ident; + uint8_t restore; +} VRDEORDERSAVESCREEN; + +typedef struct _VRDEORDERGLYPH +{ + uint32_t o32NextGlyph; + uint64_t u64Handle; + + /* The glyph origin position on the screen. */ + int16_t x; + int16_t y; + + /* The glyph bitmap dimensions. Note w == h == 0 for the space character. */ + uint16_t w; + uint16_t h; + + /* The character origin in the bitmap. */ + int16_t xOrigin; + int16_t yOrigin; + + /* 1BPP bitmap. Rows are byte aligned. Size is (((w + 7)/8) * h + 3) & ~3. */ + uint8_t au8Bitmap[1]; +} VRDEORDERGLYPH; + +typedef struct _VRDEORDERTEXT +{ + uint32_t cbOrder; + + int16_t xBkGround; + int16_t yBkGround; + uint16_t wBkGround; + uint16_t hBkGround; + + int16_t xOpaque; + int16_t yOpaque; + uint16_t wOpaque; + uint16_t hOpaque; + + uint16_t u16MaxGlyph; + + uint8_t u8Glyphs; + uint8_t u8Flags; + uint16_t u8CharInc; + uint32_t u32FgRGB; + uint32_t u32BgRGB; + + /* u8Glyphs glyphs follow. Size of each glyph structure may vary. */ +} VRDEORDERTEXT; +#pragma pack() + +#endif /* !VBOX_INCLUDED_RemoteDesktop_VRDEOrders_h */ diff --git a/include/VBox/RemoteDesktop/VRDESCard.h b/include/VBox/RemoteDesktop/VRDESCard.h new file mode 100644 index 00000000..9281ebed --- /dev/null +++ b/include/VBox/RemoteDesktop/VRDESCard.h @@ -0,0 +1,528 @@ +/** @file + * VBox Remote Desktop Extension (VRDE) - SmartCard interface. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_RemoteDesktop_VRDESCard_h +#define VBOX_INCLUDED_RemoteDesktop_VRDESCard_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/RemoteDesktop/VRDE.h> + +/* + * Interface for accessing the smart card reader devices on the client. + * + * Async callbacks are used for providing feedback, reporting errors, etc. + * + * The caller prepares a VRDESCARD*REQ structure and submits it. + */ + +#define VRDE_SCARD_INTERFACE_NAME "SCARD" + +/** The VRDE server smart card access interface entry points. Interface version 1. */ +typedef struct VRDESCARDINTERFACE +{ + /** The header. */ + VRDEINTERFACEHDR header; + + /** Submit an async IO request to the client. + * + * @param hServer The VRDE server instance. + * @param pvUser The callers context of this request. + * @param u32Function The function: VRDE_SCARD_FN_*. + * @param pvData Function specific data: VRDESCARD*REQ. + * @param cbData Size of data. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDESCardRequest, (HVRDESERVER hServer, + void *pvUser, + uint32_t u32Function, + const void *pvData, + uint32_t cbData)); + +} VRDESCARDINTERFACE; + +/* Smartcard interface callbacks. */ +typedef struct VRDESCARDCALLBACKS +{ + /** The header. */ + VRDEINTERFACEHDR header; + + /** Notifications. + * + * @param pvContext The callbacks context specified in VRDEGetInterface. + * @param u32Id The notification identifier: VRDE_SCARD_NOTIFY_*. + * @param pvData The notification specific data. + * @param cbData The size of buffer pointed by pvData. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDESCardCbNotify, (void *pvContext, + uint32_t u32Id, + void *pvData, + uint32_t cbData)); + + /** IO response. + * + * @param pvContext The callbacks context specified in VRDEGetInterface. + * @param rcRequest The IPRT status code for the request. + * @param pvUser The pvUser parameter of VRDESCardRequest. + * @param u32Function The completed function: VRDE_SCARD_FN_*. + * @param pvData Function specific response data: VRDESCARD*RSP. + * @param cbData The size of the buffer pointed by pvData. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDESCardCbResponse, (void *pvContext, + int rcRequest, + void *pvUser, + uint32_t u32Function, + void *pvData, + uint32_t cbData)); +} VRDESCARDCALLBACKS; + + +/* + * Notifications. + * u32Id parameter of VRDESCARDCALLBACKS::VRDESCardCbNotify. + */ + +#define VRDE_SCARD_NOTIFY_ATTACH 1 /* A SCARD RDPDR device has been attached. */ +#define VRDE_SCARD_NOTIFY_DETACH 2 /* A SCARD RDPDR device has been detached. */ + +/* + * Notifications. + * Data structures: pvData of VRDESCARDCALLBACKS::VRDESCardCbNotify. + */ +typedef struct VRDESCARDNOTIFYATTACH +{ + uint32_t u32ClientId; + uint32_t u32DeviceId; +} VRDESCARDNOTIFYATTACH; + +typedef struct VRDESCARDNOTIFYDETACH +{ + uint32_t u32ClientId; + uint32_t u32DeviceId; +} VRDESCARDNOTIFYDETACH; + + +/* + * IO request codes. + * Must be not 0, which is used internally. + */ + +#define VRDE_SCARD_FN_ESTABLISHCONTEXT 1 +#define VRDE_SCARD_FN_LISTREADERS 2 +#define VRDE_SCARD_FN_RELEASECONTEXT 3 +#define VRDE_SCARD_FN_GETSTATUSCHANGE 4 +#define VRDE_SCARD_FN_CANCEL 5 +#define VRDE_SCARD_FN_CONNECT 6 +#define VRDE_SCARD_FN_RECONNECT 7 +#define VRDE_SCARD_FN_DISCONNECT 8 +#define VRDE_SCARD_FN_BEGINTRANSACTION 9 +#define VRDE_SCARD_FN_ENDTRANSACTION 10 +#define VRDE_SCARD_FN_STATE 11 +#define VRDE_SCARD_FN_STATUS 12 +#define VRDE_SCARD_FN_TRANSMIT 13 +#define VRDE_SCARD_FN_CONTROL 14 +#define VRDE_SCARD_FN_GETATTRIB 15 +#define VRDE_SCARD_FN_SETATTRIB 16 + +#define VRDE_SCARD_MAX_READERS 10 +#define VRDE_SCARD_MAX_ATR_LENGTH 36 +#define VRDE_SCARD_MAX_PCI_DATA 1024 + +#define VRDE_SCARD_S_SUCCESS 0x00000000 +#define VRDE_SCARD_F_INTERNAL_ERROR 0x80100001 +#define VRDE_SCARD_E_CANCELLED 0x80100002 +#define VRDE_SCARD_E_INVALID_HANDLE 0x80100003 +#define VRDE_SCARD_E_INVALID_PARAMETER 0x80100004 +#define VRDE_SCARD_E_INVALID_TARGET 0x80100005 +#define VRDE_SCARD_E_NO_MEMORY 0x80100006 +#define VRDE_SCARD_F_WAITED_TOO_LONG 0x80100007 +#define VRDE_SCARD_E_INSUFFICIENT_BUFFER 0x80100008 +#define VRDE_SCARD_E_UNKNOWN_READER 0x80100009 +#define VRDE_SCARD_E_TIMEOUT 0x8010000A +#define VRDE_SCARD_E_SHARING_VIOLATION 0x8010000B +#define VRDE_SCARD_E_NO_SMARTCARD 0x8010000C +#define VRDE_SCARD_E_UNKNOWN_CARD 0x8010000D +#define VRDE_SCARD_E_CANT_DISPOSE 0x8010000E +#define VRDE_SCARD_E_PROTO_MISMATCH 0x8010000F +#define VRDE_SCARD_E_NOT_READY 0x80100010 +#define VRDE_SCARD_E_INVALID_VALUE 0x80100011 +#define VRDE_SCARD_E_SYSTEM_CANCELLED 0x80100012 +#define VRDE_SCARD_F_COMM_ERROR 0x80100013 +#define VRDE_SCARD_F_UNKNOWN_ERROR 0x80100014 +#define VRDE_SCARD_E_INVALID_ATR 0x80100015 +#define VRDE_SCARD_E_NOT_TRANSACTED 0x80100016 +#define VRDE_SCARD_E_READER_UNAVAILABLE 0x80100017 +#define VRDE_SCARD_P_SHUTDOWN 0x80100018 +#define VRDE_SCARD_E_PCI_TOO_SMALL 0x80100019 +#define VRDE_SCARD_E_ICC_INSTALLATION 0x80100020 +#define VRDE_SCARD_E_ICC_CREATEORDER 0x80100021 +#define VRDE_SCARD_E_UNSUPPORTED_FEATURE 0x80100022 +#define VRDE_SCARD_E_DIR_NOT_FOUND 0x80100023 +#define VRDE_SCARD_E_FILE_NOT_FOUND 0x80100024 +#define VRDE_SCARD_E_NO_DIR 0x80100025 +#define VRDE_SCARD_E_READER_UNSUPPORTED 0x8010001A +#define VRDE_SCARD_E_DUPLICATE_READER 0x8010001B +#define VRDE_SCARD_E_CARD_UNSUPPORTED 0x8010001C +#define VRDE_SCARD_E_NO_SERVICE 0x8010001D +#define VRDE_SCARD_E_SERVICE_STOPPED 0x8010001E +#define VRDE_SCARD_E_UNEXPECTED 0x8010001F +#define VRDE_SCARD_E_NO_FILE 0x80100026 +#define VRDE_SCARD_E_NO_ACCESS 0x80100027 +#define VRDE_SCARD_E_WRITE_TOO_MANY 0x80100028 +#define VRDE_SCARD_E_BAD_SEEK 0x80100029 +#define VRDE_SCARD_E_INVALID_CHV 0x8010002A +#define VRDE_SCARD_E_UNKNOWN_RES_MSG 0x8010002B +#define VRDE_SCARD_E_NO_SUCH_CERTIFICATE 0x8010002C +#define VRDE_SCARD_E_CERTIFICATE_UNAVAILABLE 0x8010002D +#define VRDE_SCARD_E_NO_READERS_AVAILABLE 0x8010002E +#define VRDE_SCARD_E_COMM_DATA_LOST 0x8010002F +#define VRDE_SCARD_E_NO_KEY_CONTAINER 0x80100030 +#define VRDE_SCARD_E_SERVER_TOO_BUSY 0x80100031 +#define VRDE_SCARD_E_PIN_CACHE_EXPIRED 0x80100032 +#define VRDE_SCARD_E_NO_PIN_CACHE 0x80100033 +#define VRDE_SCARD_E_READ_ONLY_CARD 0x80100034 +#define VRDE_SCARD_W_UNSUPPORTED_CARD 0x80100065 +#define VRDE_SCARD_W_UNRESPONSIVE_CARD 0x80100066 +#define VRDE_SCARD_W_UNPOWERED_CARD 0x80100067 +#define VRDE_SCARD_W_RESET_CARD 0x80100068 +#define VRDE_SCARD_W_REMOVED_CARD 0x80100069 +#define VRDE_SCARD_W_SECURITY_VIOLATION 0x8010006A +#define VRDE_SCARD_W_WRONG_CHV 0x8010006B +#define VRDE_SCARD_W_CHV_BLOCKED 0x8010006C +#define VRDE_SCARD_W_EOF 0x8010006D +#define VRDE_SCARD_W_CANCELLED_BY_USER 0x8010006E +#define VRDE_SCARD_W_CARD_NOT_AUTHENTICATED 0x8010006F +#define VRDE_SCARD_W_CACHE_ITEM_NOT_FOUND 0x80100070 +#define VRDE_SCARD_W_CACHE_ITEM_STALE 0x80100071 +#define VRDE_SCARD_W_CACHE_ITEM_TOO_BIG 0x80100072 + +#define VRDE_SCARD_STATE_UNAWARE 0x0000 +#define VRDE_SCARD_STATE_IGNORE 0x0001 +#define VRDE_SCARD_STATE_CHANGED 0x0002 +#define VRDE_SCARD_STATE_UNKNOWN 0x0004 +#define VRDE_SCARD_STATE_UNAVAILABLE 0x0008 +#define VRDE_SCARD_STATE_EMPTY 0x0010 +#define VRDE_SCARD_STATE_PRESENT 0x0020 +#define VRDE_SCARD_STATE_ATRMATCH 0x0040 +#define VRDE_SCARD_STATE_EXCLUSIVE 0x0080 +#define VRDE_SCARD_STATE_INUSE 0x0100 +#define VRDE_SCARD_STATE_MUTE 0x0200 +#define VRDE_SCARD_STATE_UNPOWERED 0x0400 +#define VRDE_SCARD_STATE_MASK UINT32_C(0x0000FFFF) +#define VRDE_SCARD_STATE_COUNT_MASK UINT32_C(0xFFFF0000) + +#define VRDE_SCARD_PROTOCOL_UNDEFINED 0x00000000 +#define VRDE_SCARD_PROTOCOL_T0 0x00000001 +#define VRDE_SCARD_PROTOCOL_T1 0x00000002 +#define VRDE_SCARD_PROTOCOL_Tx 0x00000003 +#define VRDE_SCARD_PROTOCOL_RAW 0x00010000 + +#define VRDE_SCARD_PROTOCOL_DEFAULT 0x80000000 +#define VRDE_SCARD_PROTOCOL_OPTIMAL 0x00000000 + +#define VRDE_SCARD_SHARE_EXCLUSIVE 0x00000001 +#define VRDE_SCARD_SHARE_SHARED 0x00000002 +#define VRDE_SCARD_SHARE_DIRECT 0x00000003 + +/* u32Initialization, u32Disposition */ +#define VRDE_SCARD_LEAVE_CARD 0x00000000 +#define VRDE_SCARD_RESET_CARD 0x00000001 +#define VRDE_SCARD_UNPOWER_CARD 0x00000002 +#define VRDE_SCARD_EJECT_CARD 0x00000003 + +/* VRDESCARDSTATUSRSP::u32State */ +#define VRDE_SCARD_UNKNOWN 0x00000000 +#define VRDE_SCARD_ABSENT 0x00000001 +#define VRDE_SCARD_PRESENT 0x00000002 +#define VRDE_SCARD_SWALLOWED 0x00000003 +#define VRDE_SCARD_POWERED 0x00000004 +#define VRDE_SCARD_NEGOTIABLE 0x00000005 +#define VRDE_SCARD_SPECIFICMODE 0x00000006 + + +/* + * IO request data structures. + */ +typedef struct VRDESCARDCONTEXT +{ + uint32_t u32ContextSize; + uint8_t au8Context[16]; +} VRDESCARDCONTEXT; + +typedef struct VRDESCARDHANDLE +{ + VRDESCARDCONTEXT Context; + uint32_t u32HandleSize; + uint8_t au8Handle[16]; +} VRDESCARDHANDLE; + +typedef struct VRDESCARDREADERSTATECALL +{ + char *pszReader; /* UTF8 */ + uint32_t u32CurrentState; /* VRDE_SCARD_STATE_* */ +} VRDESCARDREADERSTATECALL; + +typedef struct VRDESCARDREADERSTATERETURN +{ + uint32_t u32CurrentState; /* VRDE_SCARD_STATE_* */ + uint32_t u32EventState; /* VRDE_SCARD_STATE_* */ + uint32_t u32AtrLength; + uint8_t au8Atr[VRDE_SCARD_MAX_ATR_LENGTH]; +} VRDESCARDREADERSTATERETURN; + +typedef struct VRDESCARDPCI +{ + uint32_t u32Protocol; /* VRDE_SCARD_PROTOCOL_* */ + uint32_t u32PciLength; /* Includes u32Protocol and u32PciLength fields. 8 if no data in au8PciData. */ + uint8_t au8PciData[VRDE_SCARD_MAX_PCI_DATA]; +} VRDESCARDPCI; + +typedef struct VRDESCARDESTABLISHCONTEXTREQ +{ + uint32_t u32ClientId; + uint32_t u32DeviceId; +} VRDESCARDESTABLISHCONTEXTREQ; + +typedef struct VRDESCARDESTABLISHCONTEXTRSP +{ + uint32_t u32ReturnCode; + VRDESCARDCONTEXT Context; +} VRDESCARDESTABLISHCONTEXTRSP; + +typedef struct VRDESCARDLISTREADERSREQ +{ + VRDESCARDCONTEXT Context; +} VRDESCARDLISTREADERSREQ; + +typedef struct VRDESCARDLISTREADERSRSP +{ + uint32_t u32ReturnCode; + uint32_t cReaders; + char *apszNames[VRDE_SCARD_MAX_READERS]; /* UTF8 */ +} VRDESCARDLISTREADERSRSP; + +typedef struct VRDESCARDRELEASECONTEXTREQ +{ + VRDESCARDCONTEXT Context; +} VRDESCARDRELEASECONTEXTREQ; + +typedef struct VRDESCARDRELEASECONTEXTRSP +{ + uint32_t u32ReturnCode; +} VRDESCARDRELEASECONTEXTRSP; + +typedef struct VRDESCARDGETSTATUSCHANGEREQ +{ + VRDESCARDCONTEXT Context; + uint32_t u32Timeout; /* Milliseconds. 0xFFFFFFFF = INFINITE */ + uint32_t cReaders; + VRDESCARDREADERSTATECALL aReaderStates[VRDE_SCARD_MAX_READERS]; +} VRDESCARDGETSTATUSCHANGEREQ; + +typedef struct VRDESCARDGETSTATUSCHANGERSP +{ + uint32_t u32ReturnCode; + uint32_t cReaders; + VRDESCARDREADERSTATERETURN aReaderStates[VRDE_SCARD_MAX_READERS]; +} VRDESCARDGETSTATUSCHANGERSP; + +typedef struct VRDESCARDCANCELREQ +{ + VRDESCARDCONTEXT Context; +} VRDESCARDCANCELREQ; + +typedef struct VRDESCARDCANCELRSP +{ + uint32_t u32ReturnCode; +} VRDESCARDCANCELRSP; + +typedef struct VRDESCARDCONNECTREQ +{ + VRDESCARDCONTEXT Context; + char *pszReader; /* UTF8 */ + uint32_t u32ShareMode; /* VRDE_SCARD_SHARE_* */ + uint32_t u32PreferredProtocols; +} VRDESCARDCONNECTREQ; + +typedef struct VRDESCARDCONNECTRSP +{ + uint32_t u32ReturnCode; + VRDESCARDHANDLE hCard; + uint32_t u32ActiveProtocol; +} VRDESCARDCONNECTRSP; + +typedef struct VRDESCARDRECONNECTREQ +{ + VRDESCARDHANDLE hCard; + uint32_t u32ShareMode; + uint32_t u32PreferredProtocols; + uint32_t u32Initialization; +} VRDESCARDRECONNECTREQ; + +typedef struct VRDESCARDRECONNECTRSP +{ + uint32_t u32ReturnCode; + uint32_t u32ActiveProtocol; +} VRDESCARDRECONNECTRSP; + +typedef struct VRDESCARDDISCONNECTREQ +{ + VRDESCARDHANDLE hCard; + uint32_t u32Disposition; +} VRDESCARDDISCONNECTREQ; + +typedef struct VRDESCARDDISCONNECTRSP +{ + uint32_t u32ReturnCode; +} VRDESCARDDISCONNECTRSP; + +typedef struct VRDESCARDBEGINTRANSACTIONREQ +{ + VRDESCARDHANDLE hCard; + uint32_t u32Disposition; +} VRDESCARDBEGINTRANSACTIONREQ; + +typedef struct VRDESCARDBEGINTRANSACTIONRSP +{ + uint32_t u32ReturnCode; +} VRDESCARDBEGINTRANSACTIONRSP; + +typedef struct VRDESCARDENDTRANSACTIONREQ +{ + VRDESCARDHANDLE hCard; + uint32_t u32Disposition; +} VRDESCARDENDTRANSACTIONREQ; + +typedef struct VRDESCARDENDTRANSACTIONRSP +{ + uint32_t u32ReturnCode; +} VRDESCARDENDTRANSACTIONRSP; + +typedef struct VRDESCARDSTATEREQ +{ + VRDESCARDHANDLE hCard; +} VRDESCARDSTATEREQ; + +typedef struct VRDESCARDSTATERSP +{ + uint32_t u32ReturnCode; + uint32_t u32State; + uint32_t u32Protocol; + uint32_t u32AtrLength; + uint8_t au8Atr[VRDE_SCARD_MAX_ATR_LENGTH]; +} VRDESCARDSTATERSP; + +typedef struct VRDESCARDSTATUSREQ +{ + VRDESCARDHANDLE hCard; +} VRDESCARDSTATUSREQ; + +typedef struct VRDESCARDSTATUSRSP +{ + uint32_t u32ReturnCode; + char *szReader; + uint32_t u32State; + uint32_t u32Protocol; + uint32_t u32AtrLength; + uint8_t au8Atr[VRDE_SCARD_MAX_ATR_LENGTH]; +} VRDESCARDSTATUSRSP; + +typedef struct VRDESCARDTRANSMITREQ +{ + VRDESCARDHANDLE hCard; + VRDESCARDPCI ioSendPci; + uint32_t u32SendLength; + uint8_t *pu8SendBuffer; + uint32_t u32RecvLength; +} VRDESCARDTRANSMITREQ; + +typedef struct VRDESCARDTRANSMITRSP +{ + uint32_t u32ReturnCode; + VRDESCARDPCI ioRecvPci; + uint32_t u32RecvLength; + uint8_t *pu8RecvBuffer; +} VRDESCARDTRANSMITRSP; + +typedef struct VRDESCARDCONTROLREQ +{ + VRDESCARDHANDLE hCard; + uint32_t u32ControlCode; + uint32_t u32InBufferSize; + uint8_t *pu8InBuffer; + uint32_t u32OutBufferSize; +} VRDESCARDCONTROLREQ; + +typedef struct VRDESCARDCONTROLRSP +{ + uint32_t u32ReturnCode; + uint32_t u32OutBufferSize; + uint8_t *pu8OutBuffer; +} VRDESCARDCONTROLRSP; + +typedef struct VRDESCARDGETATTRIBREQ +{ + VRDESCARDHANDLE hCard; + uint32_t u32AttrId; + uint32_t u32AttrLen; +} VRDESCARDGETATTRIBREQ; + +typedef struct VRDESCARDGETATTRIBRSP +{ + uint32_t u32ReturnCode; + uint32_t u32AttrLength; + uint8_t *pu8Attr; +} VRDESCARDGETATTRIBRSP; + +typedef struct VRDESCARDSETATTRIBREQ +{ + VRDESCARDHANDLE hCard; + uint32_t u32AttrId; + uint32_t u32AttrLen; + uint8_t *pu8Attr; +} VRDESCARDSETATTRIBREQ; + +typedef struct VRDESCARDSETATTRIBRSP +{ + uint32_t u32ReturnCode; +} VRDESCARDSETATTRIBRSP; + +#endif /* !VBOX_INCLUDED_RemoteDesktop_VRDESCard_h */ diff --git a/include/VBox/RemoteDesktop/VRDETSMF.h b/include/VBox/RemoteDesktop/VRDETSMF.h new file mode 100644 index 00000000..40fb9d5b --- /dev/null +++ b/include/VBox/RemoteDesktop/VRDETSMF.h @@ -0,0 +1,154 @@ +/* @file + * VBox Remote Desktop Extension (VRDE) - raw TSMF dynamic channel interface. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_RemoteDesktop_VRDETSMF_h +#define VBOX_INCLUDED_RemoteDesktop_VRDETSMF_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/RemoteDesktop/VRDE.h> + +/* + * Interface creating a TSMF dynamic channel instances and sending/receving data. + * + * Async callbacks are used for providing feedback, reporting errors, etc. + */ + +#define VRDE_TSMF_INTERFACE_NAME "TSMFRAW" + +/* The VRDE server TSMF interface entry points. Interface version 1. */ +typedef struct VRDETSMFINTERFACE +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* Create a new TSMF channel instance. + * The channel is created only for one client, which is connected to the server. + * The client is the first which supports dynamic RDP channels. + * + * If this method return success then the server will use the VRDE_TSMF_N_CREATE_* + * notification to report the channel handle. + * + * @param hServer The VRDE server instance. + * @param pvChannel A context to be associated with the channel. + * @param u32Flags VRDE_TSMF_F_* + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDETSMFChannelCreate, (HVRDESERVER hServer, + void *pvChannel, + uint32_t u32Flags)); + + /* Close a TSMF channel instance. + * + * @param hServer The VRDE server instance. + * @param u32ChannelHandle Which channel to close. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDETSMFChannelClose, (HVRDESERVER hServer, + uint32_t u32ChannelHandle)); + + /* Send data to the TSMF channel instance. + * + * @param hServer The VRDE server instance. + * @param u32ChannelHandle Channel to send data. + * @param pvData Raw data to be sent, the format depends on which + * u32Flags were specified in Create: TSMF message, + * or channel header + TSMF message. + * @param cbData Size of data. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDETSMFChannelSend, (HVRDESERVER hServer, + uint32_t u32ChannelHandle, + const void *pvData, + uint32_t cbData)); +} VRDETSMFINTERFACE; + +/* TSMF interface callbacks. */ +typedef struct VRDETSMFCALLBACKS +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* Channel event notification. + * + * @param pvContext The callbacks context specified in VRDEGetInterface. + * @param u32Notification The kind of the notification: VRDE_TSMF_N_*. + * @param pvChannel A context which was used in VRDETSMFChannelCreate. + * @param pvParm The notification specific data. + * @param cbParm The size of buffer pointed by pvParm. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(void, VRDETSMFCbNotify, (void *pvContext, + uint32_t u32Notification, + void *pvChannel, + const void *pvParm, + uint32_t cbParm)); +} VRDETSMFCALLBACKS; + + +/* VRDETSMFChannelCreate::u32Flags */ +#define VRDE_TSMF_F_CHANNEL_HEADER 0x00000001 + + +/* VRDETSMFCbNotify::u32Notification */ +#define VRDE_TSMF_N_CREATE_ACCEPTED 1 +#define VRDE_TSMF_N_CREATE_DECLINED 2 +#define VRDE_TSMF_N_DATA 3 /* Data received. */ +#define VRDE_TSMF_N_DISCONNECTED 4 /* The channel is not connected anymore. */ + + +/* + * Notification parameters. + */ + +/* VRDE_TSMF_N_CREATE_ACCEPTED */ +typedef struct VRDETSMFNOTIFYCREATEACCEPTED +{ + uint32_t u32ChannelHandle; +} VRDETSMFNOTIFYCREATEACCEPTED; + +/* VRDE_TSMF_N_EVENT_DATA */ +typedef struct VRDETSMFNOTIFYDATA +{ + const void *pvData; + uint32_t cbData; /* How many bytes available. */ +} VRDETSMFNOTIFYDATA; + +#endif /* !VBOX_INCLUDED_RemoteDesktop_VRDETSMF_h */ diff --git a/include/VBox/RemoteDesktop/VRDEVideoIn.h b/include/VBox/RemoteDesktop/VRDEVideoIn.h new file mode 100644 index 00000000..07c45579 --- /dev/null +++ b/include/VBox/RemoteDesktop/VRDEVideoIn.h @@ -0,0 +1,1093 @@ +/** @file + * VBox Remote Desktop Extension (VRDE) - Video Input interface. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_RemoteDesktop_VRDEVideoIn_h +#define VBOX_INCLUDED_RemoteDesktop_VRDEVideoIn_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/* Define VRDE_VIDEOIN_WITH_VRDEINTERFACE to include the server VRDE interface parts. */ + +#ifdef VRDE_VIDEOIN_WITH_VRDEINTERFACE +# include <VBox/RemoteDesktop/VRDE.h> +#endif /* VRDE_VIDEOIN_WITH_VRDEINTERFACE */ + +#ifdef AssertCompileSize +# define ASSERTSIZE(type, size) AssertCompileSize(type, size); +#else +# define ASSERTSIZE(type, size) +#endif /* AssertCompileSize */ + +#include <iprt/types.h> + + +/* + * Interface for accessing a video camera device on the client. + * + * Async callbacks are used for providing feedback, reporting errors, etc. + * + * Initial version supports: Camera + Processing Unit + Streaming Control. + * + * There are 2 modes: + * 1) The virtual WebCam is already attached to the guest. + * 2) The virtual WebCam will be attached when the client has it. + * + * Initially the mode 1 is supported. + * + * Mode 1 details: + * The WebCam has some fixed functionality, according to the descriptors, + * which has been already read by the guest. So some of functions will + * not work if the client does not support them. + * + * Mode 2 details: + * Virtual WebCam descriptors are built from the client capabilities. + * + * Similarly to the smartcard, the server will inform the ConsoleVRDE that there is a WebCam. + * ConsoleVRDE creates a VRDEVIDEOIN handle and forwards virtual WebCam requests to it. + * + * Interface with VBox. + * + * Virtual WebCam ConsoleVRDE VRDE + * + * Negotiate <-> + * <- VideoInDeviceNotify(Attached, DeviceId) + * -> GetDeviceDesc + * <- DeviceDesc + * 2 <- CreateCamera + * 2 CameraCreated -> + * + * CameraRequest -> Request -> + * Response <- <- Response <- Response + * Frame <- <- Frame <- Frame + * <- VideoInDeviceNotify(Detached, DeviceId) + * + * Unsupported requests fail. + * The Device Description received from the client may be used to validate WebCam requests + * in the ConsoleVRDE code, for example filter out unsupported requests. + * + */ + +/* All structures in this file are packed. + * Everything is little-endian. + */ +#pragma pack(1) + +/* + * The interface supports generic video input descriptors, capabilities and controls: + * * Descriptors + * + Interface + * - Input, Camera Terminal + * - Processing Unit + * + Video Streaming + * - Input Header + * - Payload Format + * - Video Frame + * - Still Image Frame + * * Video Control requests + * + Interface + * - Power Mode + * + Unit and Terminal + * camera + * - Scanning Mode (interlaced, progressive) + * - Auto-Exposure Mode + * - Auto-Exposure Priority + * - Exposure Time Absolute, Relative + * - Focus Absolute, Relative, Auto + * - Iris Absolute, Relative + * - Zoom Absolute, Relative + * - PanTilt Absolute, Relative + * - Roll Absolute, Relative + * - Privacy + * processing + * - Backlight Compensation + * - Brightness + * - Contrast + * - Gain + * - Power Line Frequency + * - Hue Manual, Auto + * - Saturation + * - Sharpness + * - Gamma + * - White Balance Temperature Manual, Auto + * - White Balance Component Manual, Auto + * - Digital Multiplier + * - Digital Multiplier Limit + * * Video Streaming requests + * + Interface + * - Synch Delay + * - Still Image Trigger + * - Generate Key Frame + * - Update Frame Segment + * - Stream Error Code + * + * + * Notes: + * * still capture uses a method similar to method 2, because the still frame will + * be send instead of video over the channel. + * Also the method 2 can be in principle emulated by both 1 and 3 on the client. + * However the client can initiate a still frame transfer, similar to hardware button trigger. + * * all control changes are async. + * * probe/commit are not used. The server can select a supported format/frame from the list. + * * no color matching. sRGB is the default. + * * most of constants are the same as in USB Video Class spec, but they are not the same and + * should be always converted. + */ + +/* + * The DEVICEDEC describes the device and provides a list of supported formats: + * VRDEVIDEOINDEVICEDESC + * VRDEVIDEOINFORMATDESC[0]; + * VRDEVIDEOINFRAMEDESC[0..N-1] + * VRDEVIDEOINFORMATDESC[1]; + * VRDEVIDEOINFRAMEDESC[0..M-1] + * ... + */ + +typedef struct VRDEVIDEOINDEVICEDESC +{ + uint16_t u16ObjectiveFocalLengthMin; + uint16_t u16ObjectiveFocalLengthMax; + uint16_t u16OcularFocalLength; + uint16_t u16MaxMultiplier; + uint32_t fu32CameraControls; /* VRDE_VIDEOIN_F_CT_CTRL_* */ + uint32_t fu32ProcessingControls; /* VRDE_VIDEOIN_F_PU_CTRL_* */ + uint8_t fu8DeviceCaps; /* VRDE_VIDEOIN_F_DEV_CAP_* */ + uint8_t u8NumFormats; /* Number of following VRDEVIDEOINFORMATDESC structures. */ + uint16_t cbExt; /* Size of the optional extended description. */ + /* An extended description may follow. */ + /* An array of VRDEVIDEOINFORMATDESC follows. */ +} VRDEVIDEOINDEVICEDESC; + +/* VRDEVIDEOINDEVICEDESC::fu32CameraControls */ +#define VRDE_VIDEOIN_F_CT_CTRL_SCANNING_MODE 0x00000001 /* D0: Scanning Mode */ +#define VRDE_VIDEOIN_F_CT_CTRL_AE_MODE 0x00000002 /* D1: Auto-Exposure Mode */ +#define VRDE_VIDEOIN_F_CT_CTRL_AE_PRIORITY 0x00000004 /* D2: Auto-Exposure Priority */ +#define VRDE_VIDEOIN_F_CT_CTRL_EXPOSURE_TIME_ABSOLUTE 0x00000008 /* D3: Exposure Time (Absolute) */ +#define VRDE_VIDEOIN_F_CT_CTRL_EXPOSURE_TIME_RELATIVE 0x00000010 /* D4: Exposure Time (Relative) */ +#define VRDE_VIDEOIN_F_CT_CTRL_FOCUS_ABSOLUTE 0x00000020 /* D5: Focus (Absolute) */ +#define VRDE_VIDEOIN_F_CT_CTRL_FOCUS_RELATIVE 0x00000040 /* D6: Focus (Relative) */ +#define VRDE_VIDEOIN_F_CT_CTRL_IRIS_ABSOLUTE 0x00000080 /* D7: Iris (Absolute) */ +#define VRDE_VIDEOIN_F_CT_CTRL_IRIS_RELATIVE 0x00000100 /* D8: Iris (Relative) */ +#define VRDE_VIDEOIN_F_CT_CTRL_ZOOM_ABSOLUTE 0x00000200 /* D9: Zoom (Absolute) */ +#define VRDE_VIDEOIN_F_CT_CTRL_ZOOM_RELATIVE 0x00000400 /* D10: Zoom (Relative) */ +#define VRDE_VIDEOIN_F_CT_CTRL_PANTILT_ABSOLUTE 0x00000800 /* D11: PanTilt (Absolute) */ +#define VRDE_VIDEOIN_F_CT_CTRL_PANTILT_RELATIVE 0x00001000 /* D12: PanTilt (Relative) */ +#define VRDE_VIDEOIN_F_CT_CTRL_ROLL_ABSOLUTE 0x00002000 /* D13: Roll (Absolute) */ +#define VRDE_VIDEOIN_F_CT_CTRL_ROLL_RELATIVE 0x00004000 /* D14: Roll (Relative) */ +#define VRDE_VIDEOIN_F_CT_CTRL_RESERVED1 0x00008000 /* D15: Reserved */ +#define VRDE_VIDEOIN_F_CT_CTRL_RESERVED2 0x00010000 /* D16: Reserved */ +#define VRDE_VIDEOIN_F_CT_CTRL_FOCUS_AUTO 0x00020000 /* D17: Focus, Auto */ +#define VRDE_VIDEOIN_F_CT_CTRL_PRIVACY 0x00040000 /* D18: Privacy */ + +/* VRDEVIDEOINDEVICEDESC::fu32ProcessingControls */ +#define VRDE_VIDEOIN_F_PU_CTRL_BRIGHTNESS 0x00000001 /* D0: Brightness */ +#define VRDE_VIDEOIN_F_PU_CTRL_CONTRAST 0x00000002 /* D1: Contrast */ +#define VRDE_VIDEOIN_F_PU_CTRL_HUE 0x00000004 /* D2: Hue */ +#define VRDE_VIDEOIN_F_PU_CTRL_SATURATION 0x00000008 /* D3: Saturation */ +#define VRDE_VIDEOIN_F_PU_CTRL_SHARPNESS 0x00000010 /* D4: Sharpness */ +#define VRDE_VIDEOIN_F_PU_CTRL_GAMMA 0x00000020 /* D5: Gamma */ +#define VRDE_VIDEOIN_F_PU_CTRL_WHITE_BALANCE_TEMPERATURE 0x00000040 /* D6: White Balance Temperature */ +#define VRDE_VIDEOIN_F_PU_CTRL_WHITE_BALANCE_COMPONENT 0x00000080 /* D7: White Balance Component */ +#define VRDE_VIDEOIN_F_PU_CTRL_BACKLIGHT_COMPENSATION 0x00000100 /* D8: Backlight Compensation */ +#define VRDE_VIDEOIN_F_PU_CTRL_GAIN 0x00000200 /* D9: Gain */ +#define VRDE_VIDEOIN_F_PU_CTRL_POWER_LINE_FREQUENCY 0x00000400 /* D10: Power Line Frequency */ +#define VRDE_VIDEOIN_F_PU_CTRL_HUE_AUTO 0x00000800 /* D11: Hue, Auto */ +#define VRDE_VIDEOIN_F_PU_CTRL_WHITE_BALANCE_TEMPERATURE_AUTO 0x00001000 /* D12: White Balance Temperature, Auto */ +#define VRDE_VIDEOIN_F_PU_CTRL_WHITE_BALANCE_COMPONENT_AUTO 0x00002000 /* D13: White Balance Component, Auto */ +#define VRDE_VIDEOIN_F_PU_CTRL_DIGITAL_MULTIPLIER 0x00004000 /* D14: Digital Multiplier */ +#define VRDE_VIDEOIN_F_PU_CTRL_DIGITAL_MULTIPLIER_LIMIT 0x00008000 /* D15: Digital Multiplier Limit */ + +/* VRDEVIDEOINDEVICEDESC::fu8DeviceCaps */ +#define VRDE_VIDEOIN_F_DEV_CAP_DYNAMICCHANGE 0x01 /* Whether dynamic format change is supported. */ +#define VRDE_VIDEOIN_F_DEV_CAP_TRIGGER 0x02 /* Whether hardware triggering is supported. */ +#define VRDE_VIDEOIN_F_DEV_CAP_TRIGGER_USAGE 0x04 /* 0 - still image, 1 - generic button event.*/ + +/* VRDEVIDEOINDEVICEDESC extended description. */ +typedef struct VRDEVIDEOINDEVICEEXT +{ + uint32_t fu32Fields; + /* One or more VRDEVIDEOINDEVICEFIELD follow. */ +} VRDEVIDEOINDEVICEEXT; + +typedef struct VRDEVIDEOINDEVICEFIELDHDR +{ + uint16_t cbField; /* Number of bytes reserved for this field. */ +} VRDEVIDEOINDEVICEFIELDHDR; + +/* VRDEVIDEOINDEVICEDESC::fu32Fields */ +#define VRDE_VIDEOIN_F_DEV_EXT_NAME 0x00000001 /* Utf8 device name. */ +#define VRDE_VIDEOIN_F_DEV_EXT_SERIAL 0x00000002 /* Utf8 device serial number. */ + +/* The video format descriptor. */ +typedef struct VRDEVIDEOINFORMATDESC +{ + uint16_t cbFormat; /* Size of the structure including cbFormat and format specific data. */ + uint8_t u8FormatId; /* The unique identifier of the format on the client. */ + uint8_t u8FormatType; /* MJPEG etc. VRDE_VIDEOIN_FORMAT_* */ + uint8_t u8FormatFlags; /* VRDE_VIDEOIN_F_FMT_* */ + uint8_t u8NumFrames; /* Number of following VRDEVIDEOINFRAMEDESC structures. */ + uint16_t u16Reserved; /* Must be set to 0. */ + /* Other format specific data may follow. */ + /* An array of VRDEVIDEOINFRAMEDESC follows. */ +} VRDEVIDEOINFORMATDESC; + +/* VRDEVIDEOINFORMATDESC::u8FormatType */ +#define VRDE_VIDEOIN_FORMAT_UNCOMPRESSED 0x04 +#define VRDE_VIDEOIN_FORMAT_MJPEG 0x06 +#define VRDE_VIDEOIN_FORMAT_MPEG2TS 0x0A +#define VRDE_VIDEOIN_FORMAT_DV 0x0C +#define VRDE_VIDEOIN_FORMAT_FRAME_BASED 0x10 +#define VRDE_VIDEOIN_FORMAT_STREAM_BASED 0x12 + +/* VRDEVIDEOINFORMATDESC::u8FormatFlags. */ +#define VRDE_VIDEOIN_F_FMT_GENERATEKEYFRAME 0x01 /* Supports Generate Key Frame */ +#define VRDE_VIDEOIN_F_FMT_UPDATEFRAMESEGMENT 0x02 /* Supports Update Frame Segment */ +#define VRDE_VIDEOIN_F_FMT_COPYPROTECT 0x04 /* If duplication should be restricted. */ +#define VRDE_VIDEOIN_F_FMT_COMPQUALITY 0x08 /* If the format supports an adjustable compression quality. */ + +typedef struct VRDEVIDEOINFRAMEDESC +{ + uint16_t cbFrame; /* Size of the structure including cbFrame and frame specific data. */ + uint8_t u8FrameId; /* The unique identifier of the frame for the corresponding format on the client. */ + uint8_t u8FrameFlags; + uint16_t u16Width; + uint16_t u16Height; + uint32_t u32NumFrameIntervals; /* The number of supported frame intervals. */ + uint32_t u32MinFrameInterval; /* Shortest frame interval supported (at highest frame rate), in 100ns units. */ + uint32_t u32MaxFrameInterval; /* Longest frame interval supported (at lowest frame rate), in 100ns units. */ + /* Supported frame intervals (in 100ns units) follow if VRDE_VIDEOIN_F_FRM_DISCRETE_INTERVALS is set. + * uint32_t au32FrameIntervals[u32NumFrameIntervals]; + */ + /* Supported min and max bitrate in bits per second follow if VRDE_VIDEOIN_F_FRM_BITRATE is set. + * uint32_t u32MinBitRate; + * uint32_t u32MaxBitRate; + */ + /* Other frame specific data may follow. */ +} VRDEVIDEOINFRAMEDESC; + +/* VRDEVIDEOINFRAMEDESC::u8FrameFlags. */ +#define VRDE_VIDEOIN_F_FRM_STILL 0x01 /* If still images are supported for this frame. */ +#define VRDE_VIDEOIN_F_FRM_DISCRETE_INTERVALS 0x02 /* If the discrete intervals list is included. */ +#define VRDE_VIDEOIN_F_FRM_BITRATE 0x04 /* If the bitrate fields are included. */ +#define VRDE_VIDEOIN_F_FRM_SIZE_OF_FIELDS 0x08 /* If the all optional fields start with 16 bit field size. */ + +/* + * Controls. + * + * The same structures are used for both SET and GET requests. + * Requests are async. A callback is invoked, when the client returns a reply. + * A control change notification also uses these structures. + * + * If a control request can not be fulfilled, then VRDE_VIDEOIN_CTRLHDR_F_FAIL + * will be set and u8Status contains the error code. This replaces the VC_REQUEST_ERROR_CODE_CONTROL. + * + * If the client receives an unsupported control, then the client must ignore it. + * That is the control request must not affect the client in any way. + * The client may send a VRDEVIDEOINCTRLHDR response for the unsupported control with: + * u16ControlSelector = the received value; + * u16RequestType = the received value; + * u16ParmSize = 0; + * u8Flags = VRDE_VIDEOIN_CTRLHDR_F_FAIL; + * u8Status = VRDE_VIDEOIN_CTRLHDR_STATUS_INVALIDCONTROL; + */ + +typedef struct VRDEVIDEOINCTRLHDR +{ + uint16_t u16ControlSelector; /* VRDE_VIDEOIN_CTRLSEL_* */ + uint16_t u16RequestType; /* VRDE_VIDEOIN_CTRLREQ_* */ + uint16_t u16ParmSize; /* The size of the control specific parameters. */ + uint8_t u8Flags; /* VRDE_VIDEOIN_CTRLHDR_F_* */ + uint8_t u8Status; /* VRDE_VIDEOIN_CTRLHDR_STATUS_* */ + /* Control specific data follows. */ +} VRDEVIDEOINCTRLHDR; + +/* Control request types: VRDEVIDEOINCTRLHDR::u16RequestType. */ +#define VRDE_VIDEOIN_CTRLREQ_UNDEFINED 0x00 +#define VRDE_VIDEOIN_CTRLREQ_SET_CUR 0x01 +#define VRDE_VIDEOIN_CTRLREQ_GET_CUR 0x81 +#define VRDE_VIDEOIN_CTRLREQ_GET_MIN 0x82 +#define VRDE_VIDEOIN_CTRLREQ_GET_MAX 0x83 +#define VRDE_VIDEOIN_CTRLREQ_GET_RES 0x84 +#define VRDE_VIDEOIN_CTRLREQ_GET_LEN 0x85 +#define VRDE_VIDEOIN_CTRLREQ_GET_INFO 0x86 +#define VRDE_VIDEOIN_CTRLREQ_GET_DEF 0x87 + +/* VRDEVIDEOINCTRLHDR::u8Flags */ +#define VRDE_VIDEOIN_CTRLHDR_F_NOTIFY 0x01 /* Control change notification, the attribute is derived from u16RequestType and F_FAIL. */ +#define VRDE_VIDEOIN_CTRLHDR_F_FAIL 0x02 /* The operation failed. Error code is in u8Status. */ + +/* VRDEVIDEOINCTRLHDR::u8Status if the VRDE_VIDEOIN_CTRLHDR_F_FAIL is set. */ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_SUCCESS 0x00 /**/ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_NOTREADY 0x01 /* Not ready */ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_WRONGSTATE 0x02 /* Wrong state */ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_POWER 0x03 /* Power */ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_OUTOFRANGE 0x04 /* Out of range */ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_INVALIDUNIT 0x05 /* Invalid unit */ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_INVALIDCONTROL 0x06 /* Invalid control */ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_INVALIDREQUEST 0x07 /* Invalid request */ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_UNKNOWN 0xFF /* Unknown */ + +/* Control selectors. 16 bit. High byte is the category. Low byte is the identifier.*/ +#ifdef RT_MAKE_U16 +#define VRDE_VIDEOIN_CTRLSEL_MAKE(Lo, Hi) RT_MAKE_U16(Lo, Hi) +#else +#define VRDE_VIDEOIN_CTRLSEL_MAKE(Lo, Hi) ((uint16_t)( (uint16_t)((uint8_t)(Hi)) << 8 | (uint8_t)(Lo) )) +#endif + +#define VRDE_VIDEOIN_CTRLSEL_VC(a) VRDE_VIDEOIN_CTRLSEL_MAKE(a, 0x01) +#define VRDE_VIDEOIN_CTRLSEL_CT(a) VRDE_VIDEOIN_CTRLSEL_MAKE(a, 0x02) +#define VRDE_VIDEOIN_CTRLSEL_PU(a) VRDE_VIDEOIN_CTRLSEL_MAKE(a, 0x03) +#define VRDE_VIDEOIN_CTRLSEL_VS(a) VRDE_VIDEOIN_CTRLSEL_MAKE(a, 0x04) +#define VRDE_VIDEOIN_CTRLSEL_HW(a) VRDE_VIDEOIN_CTRLSEL_MAKE(a, 0x05) +#define VRDE_VIDEOIN_CTRLSEL_PROT(a) VRDE_VIDEOIN_CTRLSEL_MAKE(a, 0x06) + +#define VRDE_VIDEOIN_CTRLSEL_VC_VIDEO_POWER_MODE_CONTROL VRDE_VIDEOIN_CTRLSEL_VC(0x01) + +#define VRDE_VIDEOIN_CTRLSEL_CT_UNDEFINED VRDE_VIDEOIN_CTRLSEL_CT(0x00) +#define VRDE_VIDEOIN_CTRLSEL_CT_SCANNING_MODE VRDE_VIDEOIN_CTRLSEL_CT(0x01) +#define VRDE_VIDEOIN_CTRLSEL_CT_AE_MODE VRDE_VIDEOIN_CTRLSEL_CT(0x02) +#define VRDE_VIDEOIN_CTRLSEL_CT_AE_PRIORITY VRDE_VIDEOIN_CTRLSEL_CT(0x03) +#define VRDE_VIDEOIN_CTRLSEL_CT_EXPOSURE_TIME_ABSOLUTE VRDE_VIDEOIN_CTRLSEL_CT(0x04) +#define VRDE_VIDEOIN_CTRLSEL_CT_EXPOSURE_TIME_RELATIVE VRDE_VIDEOIN_CTRLSEL_CT(0x05) +#define VRDE_VIDEOIN_CTRLSEL_CT_FOCUS_ABSOLUTE VRDE_VIDEOIN_CTRLSEL_CT(0x06) +#define VRDE_VIDEOIN_CTRLSEL_CT_FOCUS_RELATIVE VRDE_VIDEOIN_CTRLSEL_CT(0x07) +#define VRDE_VIDEOIN_CTRLSEL_CT_FOCUS_AUTO VRDE_VIDEOIN_CTRLSEL_CT(0x08) +#define VRDE_VIDEOIN_CTRLSEL_CT_IRIS_ABSOLUTE VRDE_VIDEOIN_CTRLSEL_CT(0x09) +#define VRDE_VIDEOIN_CTRLSEL_CT_IRIS_RELATIVE VRDE_VIDEOIN_CTRLSEL_CT(0x0A) +#define VRDE_VIDEOIN_CTRLSEL_CT_ZOOM_ABSOLUTE VRDE_VIDEOIN_CTRLSEL_CT(0x0B) +#define VRDE_VIDEOIN_CTRLSEL_CT_ZOOM_RELATIVE VRDE_VIDEOIN_CTRLSEL_CT(0x0C) +#define VRDE_VIDEOIN_CTRLSEL_CT_PANTILT_ABSOLUTE VRDE_VIDEOIN_CTRLSEL_CT(0x0D) +#define VRDE_VIDEOIN_CTRLSEL_CT_PANTILT_RELATIVE VRDE_VIDEOIN_CTRLSEL_CT(0x0E) +#define VRDE_VIDEOIN_CTRLSEL_CT_ROLL_ABSOLUTE VRDE_VIDEOIN_CTRLSEL_CT(0x0F) +#define VRDE_VIDEOIN_CTRLSEL_CT_ROLL_RELATIVE VRDE_VIDEOIN_CTRLSEL_CT(0x10) +#define VRDE_VIDEOIN_CTRLSEL_CT_PRIVACY VRDE_VIDEOIN_CTRLSEL_CT(0x11) + +#define VRDE_VIDEOIN_CTRLSEL_PU_UNDEFINED VRDE_VIDEOIN_CTRLSEL_PU(0x00) +#define VRDE_VIDEOIN_CTRLSEL_PU_BACKLIGHT_COMPENSATION VRDE_VIDEOIN_CTRLSEL_PU(0x01) +#define VRDE_VIDEOIN_CTRLSEL_PU_BRIGHTNESS VRDE_VIDEOIN_CTRLSEL_PU(0x02) +#define VRDE_VIDEOIN_CTRLSEL_PU_CONTRAST VRDE_VIDEOIN_CTRLSEL_PU(0x03) +#define VRDE_VIDEOIN_CTRLSEL_PU_GAIN VRDE_VIDEOIN_CTRLSEL_PU(0x04) +#define VRDE_VIDEOIN_CTRLSEL_PU_POWER_LINE_FREQUENCY VRDE_VIDEOIN_CTRLSEL_PU(0x05) +#define VRDE_VIDEOIN_CTRLSEL_PU_HUE VRDE_VIDEOIN_CTRLSEL_PU(0x06) +#define VRDE_VIDEOIN_CTRLSEL_PU_SATURATION VRDE_VIDEOIN_CTRLSEL_PU(0x07) +#define VRDE_VIDEOIN_CTRLSEL_PU_SHARPNESS VRDE_VIDEOIN_CTRLSEL_PU(0x08) +#define VRDE_VIDEOIN_CTRLSEL_PU_GAMMA VRDE_VIDEOIN_CTRLSEL_PU(0x09) +#define VRDE_VIDEOIN_CTRLSEL_PU_WHITE_BALANCE_TEMPERATURE VRDE_VIDEOIN_CTRLSEL_PU(0x0A) +#define VRDE_VIDEOIN_CTRLSEL_PU_WHITE_BALANCE_TEMPERATURE_AUTO VRDE_VIDEOIN_CTRLSEL_PU(0x0B) +#define VRDE_VIDEOIN_CTRLSEL_PU_WHITE_BALANCE_COMPONENT VRDE_VIDEOIN_CTRLSEL_PU(0x0C) +#define VRDE_VIDEOIN_CTRLSEL_PU_WHITE_BALANCE_COMPONENT_AUTO VRDE_VIDEOIN_CTRLSEL_PU(0x0D) +#define VRDE_VIDEOIN_CTRLSEL_PU_DIGITAL_MULTIPLIER VRDE_VIDEOIN_CTRLSEL_PU(0x0E) +#define VRDE_VIDEOIN_CTRLSEL_PU_DIGITAL_MULTIPLIER_LIMIT VRDE_VIDEOIN_CTRLSEL_PU(0x0F) +#define VRDE_VIDEOIN_CTRLSEL_PU_HUE_AUTO VRDE_VIDEOIN_CTRLSEL_PU(0x10) +#define VRDE_VIDEOIN_CTRLSEL_PU_ANALOG_VIDEO_STANDARD VRDE_VIDEOIN_CTRLSEL_PU(0x11) +#define VRDE_VIDEOIN_CTRLSEL_PU_ANALOG_LOCK_STATUS VRDE_VIDEOIN_CTRLSEL_PU(0x12) + +#define VRDE_VIDEOIN_CTRLSEL_VS_UNDEFINED VRDE_VIDEOIN_CTRLSEL_VS(0x00) +#define VRDE_VIDEOIN_CTRLSEL_VS_SETUP VRDE_VIDEOIN_CTRLSEL_VS(0x01) +#define VRDE_VIDEOIN_CTRLSEL_VS_OFF VRDE_VIDEOIN_CTRLSEL_VS(0x02) +#define VRDE_VIDEOIN_CTRLSEL_VS_ON VRDE_VIDEOIN_CTRLSEL_VS(0x03) +#define VRDE_VIDEOIN_CTRLSEL_VS_STILL_IMAGE_TRIGGER VRDE_VIDEOIN_CTRLSEL_VS(0x05) +#define VRDE_VIDEOIN_CTRLSEL_VS_STREAM_ERROR_CODE VRDE_VIDEOIN_CTRLSEL_VS(0x06) +#define VRDE_VIDEOIN_CTRLSEL_VS_GENERATE_KEY_FRAME VRDE_VIDEOIN_CTRLSEL_VS(0x07) +#define VRDE_VIDEOIN_CTRLSEL_VS_UPDATE_FRAME_SEGMENT VRDE_VIDEOIN_CTRLSEL_VS(0x08) +#define VRDE_VIDEOIN_CTRLSEL_VS_SYNCH_DELAY VRDE_VIDEOIN_CTRLSEL_VS(0x09) + +#define VRDE_VIDEOIN_CTRLSEL_HW_BUTTON VRDE_VIDEOIN_CTRLSEL_HW(0x01) + +#define VRDE_VIDEOIN_CTRLSEL_PROT_PING VRDE_VIDEOIN_CTRLSEL_PROT(0x01) +#define VRDE_VIDEOIN_CTRLSEL_PROT_SAMPLING VRDE_VIDEOIN_CTRLSEL_PROT(0x02) +#define VRDE_VIDEOIN_CTRLSEL_PROT_FRAMES VRDE_VIDEOIN_CTRLSEL_PROT(0x03) + +typedef struct VRDEVIDEOINCTRL_VIDEO_POWER_MODE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8DevicePowerMode; +} VRDEVIDEOINCTRL_VIDEO_POWER_MODE; + +typedef struct VRDEVIDEOINCTRL_CT_SCANNING_MODE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8ScanningMode; +} VRDEVIDEOINCTRL_CT_SCANNING_MODE; + +typedef struct VRDEVIDEOINCTRL_CT_AE_MODE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8AutoExposureMode; +} VRDEVIDEOINCTRL_CT_AE_MODE; + +typedef struct VRDEVIDEOINCTRL_CT_AE_PRIORITY +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8AutoExposurePriority; +} VRDEVIDEOINCTRL_CT_AE_PRIORITY; + +typedef struct VRDEVIDEOINCTRL_CT_EXPOSURE_TIME_ABSOLUTE +{ + VRDEVIDEOINCTRLHDR hdr; + uint32_t u32ExposureTimeAbsolute; +} VRDEVIDEOINCTRL_CT_EXPOSURE_TIME_ABSOLUTE; + +typedef struct VRDEVIDEOINCTRL_CT_EXPOSURE_TIME_RELATIVE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8ExposureTimeRelative; +} VRDEVIDEOINCTRL_CT_EXPOSURE_TIME_RELATIVE; + +typedef struct VRDEVIDEOINCTRL_CT_FOCUS_ABSOLUTE +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16FocusAbsolute; +} VRDEVIDEOINCTRL_CT_FOCUS_ABSOLUTE; + +typedef struct VRDEVIDEOINCTRL_CT_FOCUS_RELATIVE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8FocusRelative; + uint8_t u8Speed; +} VRDEVIDEOINCTRL_CT_FOCUS_RELATIVE; + +typedef struct VRDEVIDEOINCTRL_CT_FOCUS_AUTO +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8FocusAuto; +} VRDEVIDEOINCTRL_CT_FOCUS_AUTO; + +typedef struct VRDEVIDEOINCTRL_CT_IRIS_ABSOLUTE +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16IrisAbsolute; +} VRDEVIDEOINCTRL_CT_IRIS_ABSOLUTE; + +typedef struct VRDEVIDEOINCTRL_CT_IRIS_RELATIVE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8IrisRelative; +} VRDEVIDEOINCTRL_CT_IRIS_RELATIVE; + +typedef struct VRDEVIDEOINCTRL_CT_ZOOM_ABSOLUTE +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16ZoomAbsolute; +} VRDEVIDEOINCTRL_CT_ZOOM_ABSOLUTE; + +typedef struct VRDEVIDEOINCTRL_CT_ZOOM_RELATIVE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8Zoom; + uint8_t u8DigitalZoom; + uint8_t u8Speed; +} VRDEVIDEOINCTRL_CT_ZOOM_RELATIVE; + +typedef struct VRDEVIDEOINCTRL_CT_PANTILT_ABSOLUTE +{ + VRDEVIDEOINCTRLHDR hdr; + uint32_t u32PanAbsolute; + uint32_t u32TiltAbsolute; +} VRDEVIDEOINCTRL_CT_PANTILT_ABSOLUTE; + +typedef struct VRDEVIDEOINCTRL_CT_PANTILT_RELATIVE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8PanRelative; + uint8_t u8PanSpeed; + uint8_t u8TiltRelative; + uint8_t u8TiltSpeed; +} VRDEVIDEOINCTRL_CT_PANTILT_RELATIVE; + +typedef struct VRDEVIDEOINCTRL_CT_ROLL_ABSOLUTE +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16RollAbsolute; +} VRDEVIDEOINCTRL_CT_ROLL_ABSOLUTE; + +typedef struct VRDEVIDEOINCTRL_CT_ROLL_RELATIVE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8RollRelative; + uint8_t u8Speed; +} VRDEVIDEOINCTRL_CT_ROLL_RELATIVE; + +typedef struct VRDEVIDEOINCTRL_CT_PRIVACY_MODE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8Privacy; +} VRDEVIDEOINCTRL_CT_PRIVACY_MODE; + +typedef struct VRDEVIDEOINCTRL_PU_BACKLIGHT_COMPENSATION +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16BacklightCompensation; +} VRDEVIDEOINCTRL_PU_BACKLIGHT_COMPENSATION; + +typedef struct VRDEVIDEOINCTRL_PU_BRIGHTNESS +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16Brightness; +} VRDEVIDEOINCTRL_PU_BRIGHTNESS; + +typedef struct VRDEVIDEOINCTRL_PU_CONTRAST +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16Contrast; +} VRDEVIDEOINCTRL_PU_CONTRAST; + +typedef struct VRDEVIDEOINCTRL_PU_GAIN +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16Gain; +} VRDEVIDEOINCTRL_PU_GAIN; + +typedef struct VRDEVIDEOINCTRL_PU_POWER_LINE_FREQUENCY +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16PowerLineFrequency; +} VRDEVIDEOINCTRL_PU_POWER_LINE_FREQUENCY; + +typedef struct VRDEVIDEOINCTRL_PU_HUE +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16Hue; +} VRDEVIDEOINCTRL_PU_HUE; + +typedef struct VRDEVIDEOINCTRL_PU_HUE_AUTO +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8HueAuto; +} VRDEVIDEOINCTRL_PU_HUE_AUTO; + +typedef struct VRDEVIDEOINCTRL_PU_SATURATION +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16Saturation; +} VRDEVIDEOINCTRL_PU_SATURATION; + +typedef struct VRDEVIDEOINCTRL_PU_SHARPNESS +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16Sharpness; +} VRDEVIDEOINCTRL_PU_SHARPNESS; + +typedef struct VRDEVIDEOINCTRL_PU_GAMMA +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16Gamma; +} VRDEVIDEOINCTRL_PU_GAMMA; + +typedef struct VRDEVIDEOINCTRL_PU_WHITE_BALANCE_TEMPERATURE +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16WhiteBalanceTemperature; +} VRDEVIDEOINCTRL_PU_WHITE_BALANCE_TEMPERATURE; + +typedef struct VRDEVIDEOINCTRL_PU_WHITE_BALANCE_TEMPERATURE_AUTO +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8WhiteBalanceTemperatureAuto; +} VRDEVIDEOINCTRL_PU_WHITE_BALANCE_TEMPERATURE_AUTO; + +typedef struct VRDEVIDEOINCTRL_PU_WHITE_BALANCE_COMPONENT +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16WhiteBalanceBlue; + uint16_t u16WhiteBalanceRed; +} VRDEVIDEOINCTRL_PU_WHITE_BALANCE_COMPONENT; + +typedef struct VRDEVIDEOINCTRL_PU_WHITE_BALANCE_COMPONENT_AUTO +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8WhiteBalanceComponentAuto; +} VRDEVIDEOINCTRL_PU_WHITE_BALANCE_COMPONENT_AUTO; + +typedef struct VRDEVIDEOINCTRL_PU_DIGITAL_MULTIPLIER +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16MultiplierStep; +} VRDEVIDEOINCTRL_PU_DIGITAL_MULTIPLIER; + +typedef struct VRDEVIDEOINCTRL_PU_DIGITAL_MULTIPLIER_LIMIT +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16MultiplierLimit; +} VRDEVIDEOINCTRL_PU_DIGITAL_MULTIPLIER_LIMIT; + +typedef struct VRDEVIDEOINCTRL_PU_ANALOG_VIDEO_STANDARD +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8VideoStandard; +} VRDEVIDEOINCTRL_PU_ANALOG_VIDEO_STANDARD; + +typedef struct VRDEVIDEOINCTRL_PU_ANALOG_LOCK_STATUS +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8Status; +} VRDEVIDEOINCTRL_PU_ANALOG_LOCK_STATUS; + +/* Set streaming parameters. The actual streaming will be enabled by VS_ON. */ +#define VRDEVIDEOINCTRL_F_VS_SETUP_FID 0x01 +#define VRDEVIDEOINCTRL_F_VS_SETUP_EOF 0x02 + +typedef struct VRDEVIDEOINCTRL_VS_SETUP +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8FormatId; /* The format id on the client: VRDEVIDEOINFORMATDESC::u8FormatId. */ + uint8_t u8FramingInfo; /* VRDEVIDEOINCTRL_F_VS_SETUP_*. Set by the client. */ + uint16_t u16Width; + uint16_t u16Height; + uint32_t u32FrameInterval; /* Frame interval in 100 ns units, 0 means a still image capture. + * The client may choose a different interval if this value is + * not supported. + */ + uint16_t u16CompQuality; /* 0 .. 10000 = 0 .. 100%. + * Applicable if the format has VRDE_VIDEOIN_F_FMT_COMPQUALITY, + * otherwise this field is ignored. + */ + uint16_t u16Delay; /* Latency in ms from video data capture to presentation on the channel. + * Set by the client, read by the server. + */ + uint32_t u32ClockFrequency; /* @todo just all clocks in 100ns units? */ +} VRDEVIDEOINCTRL_VS_SETUP; + +/* Stop sending video frames. */ +typedef struct VRDEVIDEOINCTRL_VS_OFF +{ + VRDEVIDEOINCTRLHDR hdr; +} VRDEVIDEOINCTRL_VS_OFF; + +/* Start sending video frames with parameters set by VS_SETUP. */ +typedef struct VRDEVIDEOINCTRL_VS_ON +{ + VRDEVIDEOINCTRLHDR hdr; +} VRDEVIDEOINCTRL_VS_ON; + +typedef struct VRDEVIDEOINCTRL_VS_STILL_IMAGE_TRIGGER +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8Trigger; +} VRDEVIDEOINCTRL_VS_STILL_IMAGE_TRIGGER; + +typedef struct VRDEVIDEOINCTRL_VS_STREAM_ERROR_CODE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8StreamErrorCode; +} VRDEVIDEOINCTRL_VS_STREAM_ERROR_CODE; + +typedef struct VRDEVIDEOINCTRL_VS_GENERATE_KEY_FRAME +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8GenerateKeyFrame; +} VRDEVIDEOINCTRL_VS_GENERATE_KEY_FRAME; + +typedef struct VRDEVIDEOINCTRL_VS_UPDATE_FRAME_SEGMENT +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8StartFrameSegment; + uint8_t u8EndFrameSegment; +} VRDEVIDEOINCTRL_VS_UPDATE_FRAME_SEGMENT; + +typedef struct VRDEVIDEOINCTRL_VS_SYNCH_DELAY +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16Delay; +} VRDEVIDEOINCTRL_VS_SYNCH_DELAY; + +/* A hardware button was pressed/released on the device. */ +typedef struct VRDEVIDEOINCTRL_HW_BUTTON +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8Pressed; +} VRDEVIDEOINCTRL_HW_BUTTON; + +typedef struct VRDEVIDEOINCTRL_PROT_PING +{ + VRDEVIDEOINCTRLHDR hdr; + uint32_t u32Timestamp; /* Set in the request and the same value must be send back in the response. */ +} VRDEVIDEOINCTRL_PROT_PING; + +typedef struct VRDEVIDEOINCTRL_PROT_SAMPLING +{ + VRDEVIDEOINCTRLHDR hdr; + uint32_t fu32SampleStart; /* Which parameters must be sampled VRDEVIDEOINCTRL_F_PROT_SAMPLING_*. */ + uint32_t fu32SampleStop; /* Which parameters to disable VRDEVIDEOINCTRL_F_PROT_SAMPLING_*. + * If both Start and Stop is set, then restart the sampling. + */ + uint32_t u32PeriodMS; /* Sampling period in milliseconds. Applies to all samples in fu32SampleStart. + * Not mandatory, the actual sampling period may be different. + */ +} VRDEVIDEOINCTRL_PROT_SAMPLING; + +#define VRDEVIDEOINCTRL_F_PROT_SAMPLING_FRAMES_SOURCE 0x00000001 /* Periodic VRDEVIDEOINCTRL_PROT_FRAMES samples */ +#define VRDEVIDEOINCTRL_F_PROT_SAMPLING_FRAMES_CLIENT_OUT 0x00000002 /* Periodic VRDEVIDEOINCTRL_PROT_FRAMES samples */ + +typedef struct VRDEVIDEOINCTRL_PROT_FRAMES +{ + VRDEVIDEOINCTRLHDR hdr; /* Note: the message should be sent as VRDE_VIDEOIN_FN_CONTROL_NOTIFY. */ + uint32_t u32Sample; /* Which sample is this, one of VRDEVIDEOINCTRL_F_PROT_SAMPLING_*. */ + uint32_t u32TimestampMS; /* When the period started, milliseconds since the start of sampling. */ + uint32_t u32PeriodMS; /* Actual period during which the frames were counted in milliseconds. + * This may be different from VRDEVIDEOINCTRL_PROT_SAMPLING::u32PeriodMS. + */ + uint32_t u32FramesCount; /* How many frames per u32PeriodMS milliseconds. */ +} VRDEVIDEOINCTRL_PROT_FRAMES; + + +/* + * Payload transfers. How frames are sent to the server: + * the client send a PAYLOAD packet, which has the already set format. + * The server enables the transfers by sending VRDEVIDEOINCTRL_VS_ON. + */ + +/* Payload header */ +typedef struct VRDEVIDEOINPAYLOADHDR +{ + uint8_t u8HeaderLength; /* Entire header. */ + uint8_t u8HeaderInfo; /* VRDE_VIDEOIN_PAYLOAD_F_* */ + uint32_t u32PresentationTime; /* @todo define this */ + uint32_t u32SourceTimeClock; /* @todo At the moment when the frame was sent to the channel. + * Allows the server to measure clock drift. + */ + uint16_t u16Reserved; /* @todo */ +} VRDEVIDEOINPAYLOADHDR; + +/* VRDEVIDEOINPAYLOADHDR::u8HeaderInfo */ +#define VRDE_VIDEOIN_PAYLOAD_F_FID 0x01 /* Frame ID */ +#define VRDE_VIDEOIN_PAYLOAD_F_EOF 0x02 /* End of Frame */ +#define VRDE_VIDEOIN_PAYLOAD_F_PTS 0x04 /* Presentation Time */ +#define VRDE_VIDEOIN_PAYLOAD_F_SCR 0x08 /* Source Clock Reference */ +#define VRDE_VIDEOIN_PAYLOAD_F_RES 0x10 /* Reserved */ +#define VRDE_VIDEOIN_PAYLOAD_F_STI 0x20 /* Still Image */ +#define VRDE_VIDEOIN_PAYLOAD_F_ERR 0x40 /* Error */ +#define VRDE_VIDEOIN_PAYLOAD_F_EOH 0x80 /* End of header */ + + +/* + * The network channel specification. + */ + +/* + * The protocol uses a dynamic RDP channel. + * Everything is little-endian. + */ + +/* The dynamic RDP channel name. */ +#define VRDE_VIDEOIN_CHANNEL "RVIDEOIN" + +/* Major functions. */ +#define VRDE_VIDEOIN_FN_NEGOTIATE 0x0000 /* Version and capabilities check. */ +#define VRDE_VIDEOIN_FN_NOTIFY 0x0001 /* Device attach/detach from the client. */ +#define VRDE_VIDEOIN_FN_DEVICEDESC 0x0002 /* Query device description. */ +#define VRDE_VIDEOIN_FN_CONTROL 0x0003 /* Control the device and start/stop video input. + * This function is used for sending a request and + * the corresponding response. + */ +#define VRDE_VIDEOIN_FN_CONTROL_NOTIFY 0x0004 /* The client reports a control change, etc. + * This function indicated that the message is + * not a response to a CONTROL request. + */ +#define VRDE_VIDEOIN_FN_FRAME 0x0005 /* Frame from the client. */ + +/* Status codes. */ +#define VRDE_VIDEOIN_STATUS_SUCCESS 0 /* Function completed successfully. */ +#define VRDE_VIDEOIN_STATUS_FAILED 1 /* Failed for some reason. */ + +typedef struct VRDEVIDEOINMSGHDR +{ + uint32_t u32Length; /* The length of the message in bytes, including the header. */ + uint32_t u32DeviceId; /* The client's device id. */ + uint32_t u32MessageId; /* Unique id assigned by the server. The client must send a reply with the same id. + * If the client initiates a request, then this must be set to 0, because there is + * currently no client requests, which would require a response from the server. + */ + uint16_t u16FunctionId; /* VRDE_VIDEOIN_FN_* */ + uint16_t u16Status; /* The result of a request. VRDE_VIDEOIN_STATUS_*. */ +} VRDEVIDEOINMSGHDR; +ASSERTSIZE(VRDEVIDEOINMSGHDR, 16) + +/* + * VRDE_VIDEOIN_FN_NEGOTIATE + * + * Sent by the server when the channel is established and the client replies with its capabilities. + */ +#define VRDE_VIDEOIN_NEGOTIATE_VERSION 1 + +/* VRDEVIDEOINMSG_NEGOTIATE::fu32Capabilities */ +#define VRDE_VIDEOIN_NEGOTIATE_CAP_VOID 0x00000000 +#define VRDE_VIDEOIN_NEGOTIATE_CAP_PROT 0x00000001 /* Supports VRDE_VIDEOIN_CTRLSEL_PROT_* controls. */ + +typedef struct VRDEVIDEOINMSG_NEGOTIATE +{ + VRDEVIDEOINMSGHDR hdr; + uint32_t u32Version; /* VRDE_VIDEOIN_NEGOTIATE_VERSION */ + uint32_t fu32Capabilities; /* VRDE_VIDEOIN_NEGOTIATE_CAP_* */ +} VRDEVIDEOINMSG_NEGOTIATE; + +/* + * VRDE_VIDEOIN_FN_NOTIFY + * + * Sent by the client when a webcam is attached or detached. + * The client must send the ATTACH notification for each webcam, which is + * already connected to the client when the VIDEOIN channel is established. + */ +#define VRDE_VIDEOIN_NOTIFY_EVENT_ATTACH 0 +#define VRDE_VIDEOIN_NOTIFY_EVENT_DETACH 1 +#define VRDE_VIDEOIN_NOTIFY_EVENT_NEGOTIATE 2 /* Negotiate again with the client. */ + +typedef struct VRDEVIDEOINMSG_NOTIFY +{ + VRDEVIDEOINMSGHDR hdr; + uint32_t u32NotifyEvent; /* VRDE_VIDEOIN_NOTIFY_EVENT_* */ + /* Event specific data may follow. The underlying protocol provides the length of the message. */ +} VRDEVIDEOINMSG_NOTIFY; + +/* + * VRDE_VIDEOIN_FN_DEVICEDESC + * + * The server queries the description of a device. + */ +typedef struct VRDEVIDEOINMSG_DEVICEDESC_REQ +{ + VRDEVIDEOINMSGHDR hdr; +} VRDEVIDEOINMSG_DEVICEDESC_REQ; + +typedef struct VRDEVIDEOINMSG_DEVICEDESC_RSP +{ + VRDEVIDEOINMSGHDR hdr; + VRDEVIDEOINDEVICEDESC Device; + /* + * VRDEVIDEOINFORMATDESC[0] + * VRDEVIDEOINFRAMEDESC[0] + * ... + * VRDEVIDEOINFRAMEDESC[n] + * VRDEVIDEOINFORMATDESC[1] + * VRDEVIDEOINFRAMEDESC[0] + * ... + * VRDEVIDEOINFRAMEDESC[m] + * ... + */ +} VRDEVIDEOINMSG_DEVICEDESC_RSP; + +/* + * VRDE_VIDEOIN_FN_CONTROL + * VRDE_VIDEOIN_FN_CONTROL_NOTIFY + * + * Either sent by the server or by the client as a notification/response. + * If sent by the client as a notification, then hdr.u32MessageId must be 0. + */ +typedef struct VRDEVIDEOINMSG_CONTROL +{ + VRDEVIDEOINMSGHDR hdr; + VRDEVIDEOINCTRLHDR Control; + /* Control specific data may follow. */ +} VRDEVIDEOINMSG_CONTROL; + +/* + * VRDE_VIDEOIN_FN_FRAME + * + * The client sends a video/still frame in the already specified format. + * hdr.u32MessageId must be 0. + */ +typedef struct VRDEVIDEOINMSG_FRAME +{ + VRDEVIDEOINMSGHDR hdr; + VRDEVIDEOINPAYLOADHDR Payload; + /* The frame data follow. */ +} VRDEVIDEOINMSG_FRAME; + + +#ifdef VRDE_VIDEOIN_WITH_VRDEINTERFACE +/* + * The application interface between VirtualBox and the VRDE server. + */ + +#define VRDE_VIDEOIN_INTERFACE_NAME "VIDEOIN" + +typedef struct VRDEVIDEOINDEVICEHANDLE +{ + uint32_t u32ClientId; + uint32_t u32DeviceId; +} VRDEVIDEOINDEVICEHANDLE; + +/* The VRDE server video input interface entry points. Interface version 1. */ +typedef struct VRDEVIDEOININTERFACE +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* Tell the server that this device will be used and associate a context with the device. + * + * @param hServer The VRDE server instance. + * @param pDeviceHandle The device reported by ATTACH notification. + * @param pvDeviceCtx The caller context associated with the pDeviceHandle. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEVideoInDeviceAttach, (HVRDESERVER hServer, + const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle, + void *pvDeviceCtx)); + + /* This device will be not be used anymore. The device context must not be used by the server too. + * + * @param hServer The VRDE server instance. + * @param pDeviceHandle The device reported by ATTACH notification. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEVideoInDeviceDetach, (HVRDESERVER hServer, + const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle)); + + /* Get a device description. + * + * @param hServer The VRDE server instance. + * @param pvUser The callers context of this request. + * @param pDeviceHandle The device reported by ATTACH notification. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEVideoInGetDeviceDesc, (HVRDESERVER hServer, + void *pvUser, + const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle)); + + /* Submit a set/get control request. + * + * @param hServer The VRDE server instance. + * @param pvUser The callers context of this request. + * @param pDeviceHandle The device reported by ATTACH notification. + * @param pReq The request. + * @param cbReq Size of the request. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEVideoInControl, (HVRDESERVER hServer, + void *pvUser, + const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle, + const VRDEVIDEOINCTRLHDR *pReq, + uint32_t cbReq)); + +} VRDEVIDEOININTERFACE; + + +/* + * Notifications. + * Data structures: pvData of VRDEVIDEOINCALLBACKS::VRDECallbackVideoInNotify. + */ +typedef struct VRDEVIDEOINNOTIFYATTACH +{ + VRDEVIDEOINDEVICEHANDLE deviceHandle; + uint32_t u32Version; /* VRDE_VIDEOIN_NEGOTIATE_VERSION */ + uint32_t fu32Capabilities; /* VRDE_VIDEOIN_NEGOTIATE_CAP_* */ +} VRDEVIDEOINNOTIFYATTACH; + +typedef struct VRDEVIDEOINNOTIFYDETACH +{ + VRDEVIDEOINDEVICEHANDLE deviceHandle; +} VRDEVIDEOINNOTIFYDETACH; + +/* Notification codes, */ +#define VRDE_VIDEOIN_NOTIFY_ID_ATTACH 0 +#define VRDE_VIDEOIN_NOTIFY_ID_DETACH 1 + + +/* Video input interface callbacks. */ +typedef struct VRDEVIDEOINCALLBACKS +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* Notifications. + * + * @param pvCallback The callbacks context specified in VRDEGetInterface. + * @param u32EventId The notification identifier: VRDE_VIDEOIN_NOTIFY_*. + * @param pvData The notification specific data. + * @param cbData The size of buffer pointed by pvData. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackVideoInNotify,(void *pvCallback, + uint32_t u32Id, + const void *pvData, + uint32_t cbData)); + + /* Device description received from the client. + * + * @param pvCallback The callbacks context specified in VRDEGetInterface. + * @param rcRequest The result code of the request. + * @param pDeviceCtx The device context associated with the device in VRDEVideoInGetDeviceDesc. + * @param pvUser The pvUser parameter of VRDEVideoInGetDeviceDesc. + * @param pDeviceDesc The device description. + * @param cbDeviceDesc The size of buffer pointed by pDevice. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackVideoInDeviceDesc,(void *pvCallback, + int rcRequest, + void *pDeviceCtx, + void *pvUser, + const VRDEVIDEOINDEVICEDESC *pDeviceDesc, + uint32_t cbDeviceDesc)); + + /* Control response or notification. + * + * @param pvCallback The callbacks context specified in VRDEGetInterface. + * @param rcRequest The result code of the request. + * @param pDeviceCtx The device context associated with the device in VRDEVideoInGetDeviceDesc. + * @param pvUser The pvUser parameter of VRDEVideoInControl. NULL if this is a notification. + * @param pControl The control information. + * @param cbControl The size of buffer pointed by pControl. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackVideoInControl,(void *pvCallback, + int rcRequest, + void *pDeviceCtx, + void *pvUser, + const VRDEVIDEOINCTRLHDR *pControl, + uint32_t cbControl)); + + /* Frame which was received from the client. + * + * @param pvCallback The callbacks context specified in VRDEGetInterface. + * @param rcRequest The result code of the request. + * @param pDeviceCtx The device context associated with the device in VRDEVideoInGetDeviceDesc. + * @param pFrame The frame data. + * @param cbFrame The size of buffer pointed by pFrame. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackVideoInFrame,(void *pvCallback, + int rcRequest, + void *pDeviceCtx, + const VRDEVIDEOINPAYLOADHDR *pFrame, + uint32_t cbFrame)); + +} VRDEVIDEOINCALLBACKS; +#endif /* VRDE_VIDEOIN_WITH_VRDEINTERFACE */ + +#pragma pack() + +#endif /* !VBOX_INCLUDED_RemoteDesktop_VRDEVideoIn_h */ diff --git a/include/VBox/SUPDrvMangling.h b/include/VBox/SUPDrvMangling.h new file mode 100644 index 00000000..40934528 --- /dev/null +++ b/include/VBox/SUPDrvMangling.h @@ -0,0 +1,48 @@ +/** @file + * SUPDrv - Mangling of IPRT symbols for host drivers. + * + * This is included via a compiler directive on platforms with a global kernel + * symbol name space (i.e. not Windows, OS/2 and Mac OS X (?)). + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SUPDrvMangling_h +#define VBOX_INCLUDED_SUPDrvMangling_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#define RT_MANGLER(symbol) VBoxHost_##symbol +#include <iprt/mangling.h> + +#endif /* !VBOX_INCLUDED_SUPDrvMangling_h */ diff --git a/include/VBox/SUPR0StackWrapper.mac b/include/VBox/SUPR0StackWrapper.mac new file mode 100644 index 00000000..152da635 --- /dev/null +++ b/include/VBox/SUPR0StackWrapper.mac @@ -0,0 +1,180 @@ +; $Id: SUPR0StackWrapper.mac $ +;; @file +; SUP - Support Library, ring-0 stack switching wrappers. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_SUPR0StackWrapper_mac +%define ___VBox_SUPR0StackWrapper_mac + +%include "VBox/asmdefs.mac" + +;; VBox's own Stack +%define SUPR0STACKINFO_MAGIC0 0786f4256h ; VBox +%define SUPR0STACKINFO_MAGIC1 06f207327h ; 's o +%define SUPR0STACKINFO_MAGIC2 053206e77h ; wn S +%define SUPR0STACKINFO_MAGIC3 06b636174h ; tack + +;; +; Stack info located before the start of the stack, at the top of the page. +; +struc SUPR0STACKINFO + .magic0 resd 1 + .magic1 resd 1 + .magic2 resd 1 + .magic3 resd 1 + .pResumeKernelStack resq 1 + .pSelf resq 1 +endstruc + +;; +; Number of parameters in GPRs and the spill area size. +%ifdef RT_ARCH_AMD64 + %ifdef ASM_CALL64_MSC + %define SUPR0_GRP_PARAMS 4 + %define SUPR0_SPILL_AREA 4 + %else + %define SUPR0_GRP_PARAMS 6 + %define SUPR0_SPILL_AREA 0 + %endif +%else + %define SUPR0_GRP_PARAMS 0 + %define SUPR0_SPILL_AREA 0 +%endif + +;; +; Generic stack switching wrapper. +; +; @param %1 The name +; @param %2 Number of arguments. +; +%macro SUPR0StackWrapperGeneric 2 +BEGINCODE +extern NAME(StkBack_ %+ %1) + +BEGINPROC %1 +%ifdef RT_ARCH_AMD64 ; Only for amd64 for now. + ; + ; Check for the stack info. + ; + mov rax, rsp + or rax, 0fffh + sub rax, SUPR0STACKINFO_size - 1 + + ; Check for the magic. + cmp dword [rax + SUPR0STACKINFO.magic0], SUPR0STACKINFO_MAGIC0 + jne .regular + cmp dword [rax + SUPR0STACKINFO.magic1], SUPR0STACKINFO_MAGIC1 + jne .regular + cmp dword [rax + SUPR0STACKINFO.magic2], SUPR0STACKINFO_MAGIC2 + jne .regular + cmp dword [rax + SUPR0STACKINFO.magic3], SUPR0STACKINFO_MAGIC3 + jne .regular + + ; Verify the self pointer. + cmp [rax + SUPR0STACKINFO.pSelf], rax + jne .regular + + ; + ; Perform a stack switch. We set up a RBP frame on the old stack so we + ; can use leave to restore the incoming stack upon return. + ; + push rbp + mov rbp, rsp + + ; The actual switch. + mov r10, 0ffffffffffffffe0h ; shuts up warning on 'and rsp, 0ffffffffffffffe0h' + and r10, [rax + SUPR0STACKINFO.pResumeKernelStack] + mov rsp, r10 + + ; + ; Copy over stack arguments. + ; + ; Note! We always copy 2-3 extra arguments (%2 + 2) just in case someone got + ; the argument count wrong. + ; +%if (%2 + 2) > SUPR0_GRP_PARAMS + 18 + %error too many parameters + %fatal too many parameters +%endif +%if (%2 + 2) > SUPR0_GRP_PARAMS + 16 + push qword [rbp + 98h] + push qword [rbp + 90h] +%endif +%if (%2 + 2) > SUPR0_GRP_PARAMS + 14 + push qword [rbp + 88h] + push qword [rbp + 80h] +%endif +%if (%2 + 2) > SUPR0_GRP_PARAMS + 12 + push qword [rbp + 78h] + push qword [rbp + 70h] +%endif +%if (%2 + 2) > SUPR0_GRP_PARAMS + 10 + push qword [rbp + 68h] + push qword [rbp + 60h] +%endif +%if (%2 + 2) > SUPR0_GRP_PARAMS + 8 + push qword [rbp + 58h] + push qword [rbp + 50h] +%endif +%if (%2 + 2) > SUPR0_GRP_PARAMS + 6 + push qword [rbp + 48h] + push qword [rbp + 40h] +%endif +%if (%2 + 2) > SUPR0_GRP_PARAMS + 4 + push qword [rbp + 38h] + push qword [rbp + 30h] +%endif +%if ((%2 + 2) > SUPR0_GRP_PARAMS + 2) || (SUPR0_SPILL_AREA > 2) + push qword [rbp + 28h] + push qword [rbp + 20h] +%endif +%if ((%2 + 2) > SUPR0_GRP_PARAMS) || (SUPR0_SPILL_AREA > 0) + push qword [rbp + 18h] + push qword [rbp + 10h] +%endif + + call NAME(StkBack_ %+ %1) + + leave + ret + +.regular: +%endif ; RT_ARCH_AMD64 + jmp NAME(StkBack_ %+ %1) +ENDPROC %1 +%endmacro + + +%endif + diff --git a/include/VBox/VBoxAuth.h b/include/VBox/VBoxAuth.h new file mode 100644 index 00000000..c10b1e8e --- /dev/null +++ b/include/VBox/VBoxAuth.h @@ -0,0 +1,209 @@ +/** @file + * VirtualBox External Authentication Library Interface. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxAuth_h +#define VBOX_INCLUDED_VBoxAuth_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/** @defgroup grp_vboxauth VirtualBox External Authentication Library Interface + * @{ + */ + +/* The following 2 enums are 32 bits values.*/ +typedef enum AuthResult +{ + AuthResultAccessDenied = 0, + AuthResultAccessGranted = 1, + AuthResultDelegateToGuest = 2, + AuthResultSizeHack = 0x7fffffff +} AuthResult; + +typedef enum AuthGuestJudgement +{ + AuthGuestNotAsked = 0, + AuthGuestAccessDenied = 1, + AuthGuestNoJudgement = 2, + AuthGuestAccessGranted = 3, + AuthGuestNotReacted = 4, + AuthGuestSizeHack = 0x7fffffff +} AuthGuestJudgement; + +/** UUID memory representation. Array of 16 bytes. + * + * @note VirtualBox uses a consistent binary representation of UUIDs on all platforms. For this reason + * the integer fields comprising the UUID are stored as little endian values. If you want to pass such + * UUIDs to code which assumes that the integer fields are big endian (often also called network byte + * order), you need to adjust the contents of the UUID to e.g. achieve the same string representation. + * + * The required changes are: + * - reverse the order of byte 0, 1, 2 and 3 + * - reverse the order of byte 4 and 5 + * - reverse the order of byte 6 and 7. + * + * Using this conversion you will get identical results when converting the binary UUID to the string + * representation. + */ +typedef unsigned char AUTHUUID[16]; +typedef AUTHUUID *PAUTHUUID; + +/** The library entry point calling convention. */ +#ifdef _MSC_VER +# define AUTHCALL __cdecl +#elif defined(__GNUC__) +# define AUTHCALL +#else +# error "Unsupported compiler" +#endif + + +/** + * Authentication library entry point. + * + * @param pUuid Pointer to the UUID of the accessed virtual machine. Can be NULL. + * @param guestJudgement Result of the guest authentication. + * @param pszUser User name passed in by the client (UTF8). + * @param pszPassword Password passed in by the client (UTF8). + * @param pszDomain Domain passed in by the client (UTF8). + * + * Return code: + * + * @retval AuthAccessDenied Client access has been denied. + * @retval AuthAccessGranted Client has the right to use the virtual machine. + * @retval AuthDelegateToGuest Guest operating system must + * authenticate the client and the + * library must be called again with + * the result of the guest + * authentication. + */ +typedef AuthResult AUTHCALL FNAUTHENTRY(PAUTHUUID pUuid, + AuthGuestJudgement guestJudgement, + const char *pszUser, + const char *pszPassword, + const char *pszDomain); +/** Pointer to a FNAUTHENTRY function. */ +typedef FNAUTHENTRY *PFNAUTHENTRY; +/** @deprecated */ +typedef FNAUTHENTRY AUTHENTRY; +/** @deprecated */ +typedef PFNAUTHENTRY PAUTHENTRY; +/** Name of the FNAUTHENTRY entry point. */ +#define AUTHENTRY_NAME "VRDPAuth" + +/** + * Authentication library entry point version 2. + * + * @param pUuid Pointer to the UUID of the accessed virtual machine. Can be NULL. + * @param guestJudgement Result of the guest authentication. + * @param pszUser User name passed in by the client (UTF8). + * @param pszPassword Password passed in by the client (UTF8). + * @param pszDomain Domain passed in by the client (UTF8). + * @param fLogon Boolean flag. Indicates whether the entry point is + * called for a client logon or the client disconnect. + * @param clientId Server side unique identifier of the client. + * + * @retval AuthAccessDenied Client access has been denied. + * @retval AuthAccessGranted Client has the right to use the virtual machine. + * @retval AuthDelegateToGuest Guest operating system must + * authenticate the client and the + * library must be called again with + * the result of the guest authentication. + * + * @note When @a fLogon is 0, only @a pUuid and @a clientId are valid and the + * return code is ignored. + */ +typedef AuthResult AUTHCALL FNAUTHENTRY2(PAUTHUUID pUuid, + AuthGuestJudgement guestJudgement, + const char *pszUser, + const char *pszPassword, + const char *pszDomain, + int fLogon, + unsigned clientId); +/** Pointer to a FNAUTHENTRY2 function. */ +typedef FNAUTHENTRY2 *PFNAUTHENTRY2; +/** @deprecated */ +typedef FNAUTHENTRY2 AUTHENTRY2; +/** @deprecated */ +typedef PFNAUTHENTRY2 PAUTHENTRY2; +/** Name of the FNAUTHENTRY2 entry point. */ +#define AUTHENTRY2_NAME "VRDPAuth2" + +/** + * Authentication library entry point version 3. + * + * @param pszCaller The name of the component which calls the library (UTF8). + * @param pUuid Pointer to the UUID of the accessed virtual machine. Can be NULL. + * @param guestJudgement Result of the guest authentication. + * @param pszUser User name passed in by the client (UTF8). + * @param pszPassword Password passed in by the client (UTF8). + * @param pszDomain Domain passed in by the client (UTF8). + * @param fLogon Boolean flag. Indicates whether the entry point is + * called for a client logon or the client disconnect. + * @param clientId Server side unique identifier of the client. + * + * @retval AuthResultAccessDenied Client access has been denied. + * @retval AuthResultAccessGranted Client has the right to use the + * virtual machine. + * @retval AuthResultDelegateToGuest Guest operating system must + * authenticate the client and the + * library must be called again with + * the result of the guest + * authentication. + * + * @note When @a fLogon is 0, only @a pszCaller, @a pUuid and @a clientId are + * valid and the return code is ignored. + */ +typedef AuthResult AUTHCALL FNAUTHENTRY3(const char *pszCaller, + PAUTHUUID pUuid, + AuthGuestJudgement guestJudgement, + const char *pszUser, + const char *pszPassword, + const char *pszDomain, + int fLogon, + unsigned clientId); +/** Pointer to a FNAUTHENTRY3 function. */ +typedef FNAUTHENTRY3 *PFNAUTHENTRY3; +/** @deprecated */ +typedef FNAUTHENTRY3 AUTHENTRY3; +/** @deprecated */ +typedef PFNAUTHENTRY3 PAUTHENTRY3; + +/** Name of the FNAUTHENTRY3 entry point. */ +#define AUTHENTRY3_NAME "AuthEntry" + +/** @} */ + +#endif /* !VBOX_INCLUDED_VBoxAuth_h */ diff --git a/include/VBox/VBoxCocoa.h b/include/VBox/VBoxCocoa.h new file mode 100644 index 00000000..6409555e --- /dev/null +++ b/include/VBox/VBoxCocoa.h @@ -0,0 +1,89 @@ +/** @file + * VBoxCocoa Helper + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxCocoa_h +#define VBOX_INCLUDED_VBoxCocoa_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/** Macro which add a typedef of the given Cocoa class in an appropriate form + * for the current context. This means void* in the C/CPP context and + * NSWhatever* in the ObjC/ObjCPP context. Use + * NativeNSWhateverRef/ConstNativeNSWhateverRef when you reference the Cocoa + * type somewhere. The use of this prevents extensive casting of void* to the + * right type in the Cocoa context. */ +#ifdef __OBJC__ +# define ADD_COCOA_NATIVE_REF(CocoaClass) \ + @class CocoaClass; \ + typedef CocoaClass *Native##CocoaClass##Ref; \ + typedef const CocoaClass *ConstNative##CocoaClass##Ref +#else /* !__OBJC__ */ +# define ADD_COCOA_NATIVE_REF(CocoaClass) \ + typedef void *Native##CocoaClass##Ref; \ + typedef const void *ConstNative##CocoaClass##Ref +#endif /* !__OBJC__ */ + + +/* + * Objective-C++ Helpers. + */ +#if defined(__OBJC__) && defined (__cplusplus) + +/* Global includes */ +# import <Foundation/NSAutoreleasePool.h> + +/** Helper class for automatic creation & destroying of a cocoa auto release + * pool. */ +class CocoaAutoreleasePool +{ +public: + inline CocoaAutoreleasePool() + { + mPool = [[NSAutoreleasePool alloc] init]; + } + inline ~CocoaAutoreleasePool() + { + [mPool release]; + } + +private: + NSAutoreleasePool *mPool; +}; + +#endif /* __OBJC__ && __cplusplus */ + +#endif /* !VBOX_INCLUDED_VBoxCocoa_h */ + diff --git a/include/VBox/VBoxCryptoIf.h b/include/VBox/VBoxCryptoIf.h new file mode 100644 index 00000000..8e687d38 --- /dev/null +++ b/include/VBox/VBoxCryptoIf.h @@ -0,0 +1,320 @@ +/** @file + * VirtualBox - Cryptographic support functions Interface. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxCryptoIf_h +#define VBOX_INCLUDED_VBoxCryptoIf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/vfs.h> +#include <VBox/types.h> + +/** An opaque VBox cryptographic context handle. */ +typedef struct VBOXCRYPTOCTXINT *VBOXCRYPTOCTX; +/**Pointer to an opaque VBox cryptographic context handle. */ +typedef VBOXCRYPTOCTX *PVBOXCRYPTOCTX; + +/** Magic identifying the cryptographic interface (Charles Babbage). */ +#define VBOXCRYPTOIF_MAGIC UINT32_C(0x17911226) + +/** Pointer to const cryptographic interface. */ +typedef const struct VBOXCRYPTOIF *PCVBOXCRYPTOIF; +/** + * The main cryptographic callbacks interface table. + */ +typedef struct VBOXCRYPTOIF +{ + /** Interface magic, set to VBOXCRYPTOIF_MAGIC. */ + uint32_t u32Magic; + /** Interface version. + * This is set to VBOXCRYPTOIF_VERSION. */ + uint32_t u32Version; + /** Description string. */ + const char *pszDesc; + + /** @name Generic crytographic context operations. + * @{ */ + + /** + * Creates a new cryptographic context for encryption. + * + * @returns VBox status code. + * @param pszCipher The identifier of the cipher to use. + * @param pszPassword Password for encrypting the context. + * @param phCryptoCtx Where to store the handle to the crypto context on success. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxCreate, (const char *pszCipher, const char *pszPassword, + PVBOXCRYPTOCTX phCryptoCtx)); + + /** + * Creates a new cryptographic context for decryption from the given base-64 encoded context. + * + * @returns VBox status code. + * @param pszStoredCtx The base-64 encoded context to decrypt with the given password. + * @param pszPassword Password for encrypting the context. + * @param phCryptoCtx Where to store the handle to the crypto context on success. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxLoad, (const char *pszStoredCtx, const char *pszPassword, + PVBOXCRYPTOCTX phCryptoCtx)); + + /** + * Destroys a previously created cryptographic context. + * + * @returns VBox status code. + * @param hCryptoCtx Handle of crpytographic context to destroy. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxDestroy, (VBOXCRYPTOCTX hCryptoCtx)); + + /** + * Returns the given cryptographic context as a base-64 encoded string. + * + * @returns VBox status code. + * @param hCryptoCtx Handle of crpytographic context. + * @param ppszStoredCtx Where to store the base-64 encoded cryptographic context on success. + * Must be freed with RTMemFree() when not required anymore. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxSave, (VBOXCRYPTOCTX hCryptoCtx, char **ppszStoredCtx)); + + /** + * Changes the encryption password for the given context. + * + * @returns VBox status code. + * @param hCryptoCtx Handle of crpytographic context. + * @param pszPassword New password used for encrypting the DEK. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxPasswordChange, (VBOXCRYPTOCTX hCryptoCtx, const char *pszPassword)); + + /** + * Queries the required size of the output buffer for encrypted data. Depends on the cipher. + * + * @returns VBox status code. + * @param hCryptoCtx Handle of crpytographic context. + * @param cbPlainText The size of the data to be encrypted. + * @param pcbEncrypted Where to store the size in bytes of the encrypted data on success. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxQueryEncryptedSize, (VBOXCRYPTOCTX hCryptoCtx, size_t cbPlaintext, + size_t *pcbEncrypted)); + + /** + * Queries the required size of the output buffer for decrypted data. Depends on the cipher. + * + * @returns VBox status code. + * @param hCryptoCtx Handle of crpytographic context. + * @param cbEncrypted The size of the encrypted chunk before decryption. + * @param pcbPlaintext Where to store the size in bytes of the decrypted data on success. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxQueryDecryptedSize, (VBOXCRYPTOCTX hCryptoCtx, size_t cbEncrypted, + size_t *pcbPlaintext)); + + /** + * Encrypts data. + * + * @returns VBox status code. + * @param hCryptoCtx Handle of crpytographic context. + * @param fPartial Only part of data to be encrypted is specified. The encryption + * cipher context will not be closed. Set to false for last piece + * of data, or if data is specified completely. + * Only CTR mode supports partial encryption. + * @param pvIV Pointer to IV. If null it will be generated. + * @param cbIV Size of the IV. + * @param pvPlainText Data to encrypt. + * @param cbPlainText Size of the data in the pvPlainText. + * @param pvAuthData Data used for authenticate the pvPlainText + * @param cbAuthData Size of the pvAuthData + * @param pvEncrypted Buffer to store encrypted data + * @param cbEncrypted Size of the buffer in pvEncrypted + * @param pcbEncrypted Placeholder where the size of the encrypted data returned. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxEncrypt, (VBOXCRYPTOCTX hCryptoCtx, bool fPartial, void const *pvIV, size_t cbIV, + void const *pvPlainText, size_t cbPlainText, + void const *pvAuthData, size_t cbAuthData, + void *pvEncrypted, size_t cbEncrypted, + size_t *pcbEncrypted)); + + /** + * Decrypts data. + * + * @returns VBox status code. + * @param hCryptoCtx Handle of crpytographic context. + * @param fPartial Only part of data to be encrypted is specified. The encryption + * cipher context will not be closed. Set to false for last piece + * of data, or if data is specified completely. + * Only CTR mode supports partial encryption. + * @param pvEncrypted Data to decrypt. + * @param cbEncrypted Size of the data in the pvEncrypted. + * @param pvAuthData Data used for authenticate the pvEncrypted + * @param cbAuthData Size of the pvAuthData + * @param pvPlainText Buffer to store decrypted data + * @param cbPlainText Size of the buffer in pvPlainText + * @param pcbPlainText Placeholder where the size of the decrypted data returned. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxDecrypt, (VBOXCRYPTOCTX hCryptoCtx, bool fPartial, + void const *pvEncrypted, size_t cbEncrypted, + void const *pvAuthData, size_t cbAuthData, + void *pvPlainText, size_t cbPlainText, size_t *pcbPlainText)); + /** @} */ + + /** @name File based cryptographic operations. + * @{ */ + /** + * Creates a new VFS file handle for an encrypted or to be encrypted file handle. + * + * @returns VBox status code. + * @param hVfsFile The input file handle, a new reference is retained upon success. + * @param pszKeyStore The key store containing the DEK used for encryption. + * @param pszPassword Password encrypting the DEK. + * @param phVfsFile Where to store the handle to the VFS file on success. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoFileFromVfsFile, (RTVFSFILE hVfsFile, const char *pszKeyStore, const char *pszPassword, + PRTVFSFILE phVfsFile)); + + /** + * Opens a new encryption I/O stream. + * + * @returns VBox status code. + * @param hVfsIosDst The encrypted output stream (must be writeable). + * The reference is not consumed, instead another + * one is retained. + * @param pszKeyStore The key store containing the DEK used for encryption. + * @param pszPassword Password encrypting the DEK. + * @param phVfsIosCrypt Where to return the crypting input I/O stream handle + * (you write to this). + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoIoStrmFromVfsIoStrmEncrypt, (RTVFSIOSTREAM hVfsIosDst, const char *pszKeyStore, + const char *pszPassword, PRTVFSIOSTREAM phVfsIosCrypt)); + + /** + * Opens a new decryption I/O stream. + * + * @returns VBox status code. + * @param hVfsIosIn The encrypted input stream (must be readable). + * The reference is not consumed, instead another + * one is retained. + * @param pszKeyStore The key store containing the DEK used for encryption. + * @param pszPassword Password encrypting the DEK. + * @param phVfsIosOut Where to return the handle to the decrypted I/O stream (read). + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoIoStrmFromVfsIoStrmDecrypt, (RTVFSIOSTREAM hVfsIosIn, const char *pszKeyStore, + const char *pszPassword, PRTVFSIOSTREAM phVfsIosOut)); + /** @} */ + + /** @name Keystore related functions. + * @{ */ + /** + * Return the encryption parameters and DEK from the base64 encoded key store data. + * + * @returns VBox status code. + * @param pszEnc The base64 encoded key store data. + * @param pszPassword The password to use for key decryption. + * If the password is NULL only the cipher is returned. + * @param ppbKey Where to store the DEK on success. + * Must be freed with RTMemSaferFree(). + * @param pcbKey Where to store the DEK size in bytes on success. + * @param ppszCipher Where to store the used cipher for the decrypted DEK. + * Must be freed with RTStrFree(). + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoKeyStoreGetDekFromEncoded, (const char *pszEnc, const char *pszPassword, + uint8_t **ppbKey, size_t *pcbKey, char **ppszCipher)); + + /** + * Stores the given DEK in a key store protected by the given password. + * + * @returns VBox status code. + * @param pszPassword The password to protect the DEK. + * @param pbKey The DEK to protect. + * @param cbKey Size of the DEK to protect. + * @param pszCipher The cipher string associated with the DEK. + * @param ppszEnc Where to store the base64 encoded key store data on success. + * Must be freed with RTMemFree(). + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoKeyStoreCreate, (const char *pszPassword, const uint8_t *pbKey, size_t cbKey, + const char *pszCipher, char **ppszEnc)); + /** @} */ + + DECLR3CALLBACKMEMBER(int, pfnReserved1,(void)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved2,(void)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved3,(void)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved4,(void)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved5,(void)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved6,(void)); /**< Reserved for minor structure revisions. */ + + /** Reserved for minor structure revisions. */ + uint32_t uReserved7; + + /** End of structure marker (VBOXCRYPTOIF_VERSION). */ + uint32_t u32EndMarker; +} VBOXCRYPTOIF; +/** Current version of the VBOXCRYPTOIF structure. */ +#define VBOXCRYPTOIF_VERSION RT_MAKE_U32(0, 1) + + +/** + * The VBoxCrypto entry callback function. + * + * @returns VBox status code. + * @param ppCryptoIf Where to store the pointer to the crypto module interface callback table + * on success. + */ +typedef DECLCALLBACKTYPE(int, FNVBOXCRYPTOENTRY,(PCVBOXCRYPTOIF *ppCryptoIf)); +/** Pointer to a FNVBOXCRYPTOENTRY. */ +typedef FNVBOXCRYPTOENTRY *PFNVBOXCRYPTOENTRY; + +/** The name of the crypto module entry point. */ +#define VBOX_CRYPTO_MOD_ENTRY_POINT "VBoxCryptoEntry" + + +/** + * Checks if cryptographic interface version is compatible. + * + * @returns true if the do, false if they don't. + * @param u32Provider The provider version. + * @param u32User The user version. + */ +#define VBOXCRYPTO_IS_VER_COMPAT(u32Provider, u32User) \ + ( VBOXCRYPTO_IS_MAJOR_VER_EQUAL(u32Provider, u32User) \ + && (int32_t)RT_LOWORD(u32Provider) >= (int32_t)RT_LOWORD(u32User) ) /* stupid casts to shut up gcc */ + +/** + * Check if two cryptographic interface versions have the same major version. + * + * @returns true if the do, false if they don't. + * @param u32Ver1 The first version number. + * @param u32Ver2 The second version number. + */ +#define VBOXCRYPTO_IS_MAJOR_VER_EQUAL(u32Ver1, u32Ver2) (RT_HIWORD(u32Ver1) == RT_HIWORD(u32Ver2)) + +#endif /* !VBOX_INCLUDED_VBoxCryptoIf_h */ + diff --git a/include/VBox/VBoxDrvCfg-win.h b/include/VBox/VBoxDrvCfg-win.h new file mode 100644 index 00000000..5ac12ae1 --- /dev/null +++ b/include/VBox/VBoxDrvCfg-win.h @@ -0,0 +1,91 @@ +/* $Id: VBoxDrvCfg-win.h $ */ +/** @file + * Windows Driver Manipulation API. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxDrvCfg_win_h +#define VBOX_INCLUDED_VBoxDrvCfg_win_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/win/windows.h> +#include <VBox/cdefs.h> + +RT_C_DECLS_BEGIN + +#if 0 +/* enable this in case we include this in a dll*/ +# ifdef IN_VBOXDRVCFG +# define VBOXDRVCFG_DECL(a_Type) DECLEXPORT(a_Type) +# else +# define VBOXDRVCFG_DECL(a_Type) DECLIMPORT(a_Type) +# endif +#else +/*enable this in case we include this in a static lib*/ +# define VBOXDRVCFG_DECL(a_Type) a_Type VBOXCALL +#endif + +typedef enum +{ + VBOXDRVCFG_LOG_SEVERITY_FLOW = 1, + VBOXDRVCFG_LOG_SEVERITY_REGULAR, + VBOXDRVCFG_LOG_SEVERITY_REL +} VBOXDRVCFG_LOG_SEVERITY_T; + +typedef DECLCALLBACKTYPE(void, FNVBOXDRVCFGLOG,(VBOXDRVCFG_LOG_SEVERITY_T enmSeverity, char *pszMsg, void *pvContext)); +typedef FNVBOXDRVCFGLOG *PFNVBOXDRVCFGLOG; + +VBOXDRVCFG_DECL(void) VBoxDrvCfgLoggerSet(PFNVBOXDRVCFGLOG pfnLog, void *pvLog); + +typedef DECLCALLBACKTYPE(void, FNVBOXDRVCFGPANIC,(void *pvPanic)); +typedef FNVBOXDRVCFGPANIC *PFNVBOXDRVCFGPANIC; +VBOXDRVCFG_DECL(void) VBoxDrvCfgPanicSet(PFNVBOXDRVCFGPANIC pfnPanic, void *pvPanic); + +/* Driver package API*/ +VBOXDRVCFG_DECL(HRESULT) VBoxDrvCfgInfInstall(IN LPCWSTR pwszInfPath); +VBOXDRVCFG_DECL(HRESULT) VBoxDrvCfgInfUninstall(IN LPCWSTR pwszInfPath, IN DWORD fFlags); +VBOXDRVCFG_DECL(HRESULT) VBoxDrvCfgInfUninstallAllSetupDi(IN const GUID * pGuidClass, IN LPCWSTR pwszClassName, + IN LPCWSTR pwszPnPId, IN DWORD fFlags); +VBOXDRVCFG_DECL(HRESULT) VBoxDrvCfgInfUninstallAllF(IN LPCWSTR pwszClassName, IN LPCWSTR pwszPnPId, IN DWORD fFlags); + +/* Service API */ +VBOXDRVCFG_DECL(HRESULT) VBoxDrvCfgSvcStart(LPCWSTR pwszSvcName); + +HRESULT VBoxDrvCfgDrvUpdate(LPCWSTR pszwHwId, LPCWSTR psxwInf, BOOL *pfRebootRequired); + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_VBoxDrvCfg_win_h */ + diff --git a/include/VBox/VBoxGL2D.h b/include/VBox/VBoxGL2D.h new file mode 100644 index 00000000..c0a9a4aa --- /dev/null +++ b/include/VBox/VBoxGL2D.h @@ -0,0 +1,390 @@ +/** @file + * + * VBox frontends: Qt GUI ("VirtualBox"): + * OpenGL support info used for 2D support detection + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxGL2D_h +#define VBOX_INCLUDED_VBoxGL2D_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +typedef char GLchar; + +#ifndef GL_COMPILE_STATUS +# define GL_COMPILE_STATUS 0x8b81 +#endif +#ifndef GL_LINK_STATUS +# define GL_LINK_STATUS 0x8b82 +#endif +#ifndef GL_FRAGMENT_SHADER +# define GL_FRAGMENT_SHADER 0x8b30 +#endif +#ifndef GL_VERTEX_SHADER +# define GL_VERTEX_SHADER 0x8b31 +#endif + +/* GL_ARB_multitexture */ +#ifndef GL_TEXTURE0 +# define GL_TEXTURE0 0x84c0 +#endif +#ifndef GL_TEXTURE1 +# define GL_TEXTURE1 0x84c1 +#endif +#ifndef GL_MAX_TEXTURE_COORDS +# define GL_MAX_TEXTURE_COORDS 0x8871 +#endif +#ifndef GL_MAX_TEXTURE_IMAGE_UNITS +# define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#endif + +#ifndef APIENTRY +# define APIENTRY +#endif + +typedef GLvoid (APIENTRY *PFNVBOXVHWA_ACTIVE_TEXTURE) (GLenum texture); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_MULTI_TEX_COORD2I) (GLenum texture, GLint v0, GLint v1); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_MULTI_TEX_COORD2F) (GLenum texture, GLfloat v0, GLfloat v1); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_MULTI_TEX_COORD2D) (GLenum texture, GLdouble v0, GLdouble v1); + +/* GL_ARB_texture_rectangle */ +#ifndef GL_TEXTURE_RECTANGLE +# define GL_TEXTURE_RECTANGLE 0x84F5 +#endif + +/* GL_ARB_shader_objects */ +/* GL_ARB_fragment_shader */ + +typedef GLuint (APIENTRY *PFNVBOXVHWA_CREATE_SHADER) (GLenum type); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_SHADER_SOURCE) (GLuint shader, GLsizei count, const GLchar **string, const GLint *length); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_COMPILE_SHADER) (GLuint shader); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_DELETE_SHADER) (GLuint shader); + +typedef GLuint (APIENTRY *PFNVBOXVHWA_CREATE_PROGRAM) (); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_ATTACH_SHADER) (GLuint program, GLuint shader); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_DETACH_SHADER) (GLuint program, GLuint shader); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_LINK_PROGRAM) (GLuint program); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_USE_PROGRAM) (GLuint program); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_DELETE_PROGRAM) (GLuint program); + +typedef GLboolean (APIENTRY *PFNVBOXVHWA_IS_SHADER) (GLuint shader); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_GET_SHADERIV) (GLuint shader, GLenum pname, GLint *params); +typedef GLboolean (APIENTRY *PFNVBOXVHWA_IS_PROGRAM) (GLuint program); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_GET_PROGRAMIV) (GLuint program, GLenum pname, GLint *params); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_GET_ATTACHED_SHADERS) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_GET_SHADER_INFO_LOG) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_GET_PROGRAM_INFO_LOG) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef GLint (APIENTRY *PFNVBOXVHWA_GET_UNIFORM_LOCATION) (GLint programObj, const GLchar *name); + +typedef GLvoid (APIENTRY *PFNVBOXVHWA_UNIFORM1F)(GLint location, GLfloat v0); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_UNIFORM2F)(GLint location, GLfloat v0, GLfloat v1); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_UNIFORM3F)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_UNIFORM4F)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); + +typedef GLvoid (APIENTRY *PFNVBOXVHWA_UNIFORM1I)(GLint location, GLint v0); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_UNIFORM2I)(GLint location, GLint v0, GLint v1); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_UNIFORM3I)(GLint location, GLint v0, GLint v1, GLint v2); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_UNIFORM4I)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); + +/* GL_ARB_pixel_buffer_object*/ +#ifndef Q_WS_MAC +/* apears to be defined on mac */ +typedef ptrdiff_t GLsizeiptr; +#endif + +#ifndef GL_READ_ONLY +# define GL_READ_ONLY 0x88B8 +#endif +#ifndef GL_WRITE_ONLY +# define GL_WRITE_ONLY 0x88B9 +#endif +#ifndef GL_READ_WRITE +# define GL_READ_WRITE 0x88BA +#endif +#ifndef GL_STREAM_DRAW +# define GL_STREAM_DRAW 0x88E0 +#endif +#ifndef GL_STREAM_READ +# define GL_STREAM_READ 0x88E1 +#endif +#ifndef GL_STREAM_COPY +# define GL_STREAM_COPY 0x88E2 +#endif +#ifndef GL_DYNAMIC_DRAW +# define GL_DYNAMIC_DRAW 0x88E8 +#endif + +#ifndef GL_PIXEL_PACK_BUFFER +# define GL_PIXEL_PACK_BUFFER 0x88EB +#endif +#ifndef GL_PIXEL_UNPACK_BUFFER +# define GL_PIXEL_UNPACK_BUFFER 0x88EC +#endif +#ifndef GL_PIXEL_PACK_BUFFER_BINDING +# define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#endif +#ifndef GL_PIXEL_UNPACK_BUFFER_BINDING +# define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#endif + +typedef GLvoid (APIENTRY *PFNVBOXVHWA_GEN_BUFFERS)(GLsizei n, GLuint *buffers); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_DELETE_BUFFERS)(GLsizei n, const GLuint *buffers); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_BIND_BUFFER)(GLenum target, GLuint buffer); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_BUFFER_DATA)(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); +typedef GLvoid* (APIENTRY *PFNVBOXVHWA_MAP_BUFFER)(GLenum target, GLenum access); +typedef GLboolean (APIENTRY *PFNVBOXVHWA_UNMAP_BUFFER)(GLenum target); + +/* GL_EXT_framebuffer_object */ +#ifndef GL_FRAMEBUFFER +# define GL_FRAMEBUFFER 0x8D40 +#endif +#ifndef GL_COLOR_ATTACHMENT0 +# define GL_COLOR_ATTACHMENT0 0x8CE0 +#endif + +typedef GLboolean (APIENTRY *PFNVBOXVHWA_IS_FRAMEBUFFER)(GLuint framebuffer); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_BIND_FRAMEBUFFER)(GLenum target, GLuint framebuffer); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_DELETE_FRAMEBUFFERS)(GLsizei n, const GLuint *framebuffers); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_GEN_FRAMEBUFFERS)(GLsizei n, GLuint *framebuffers); +typedef GLenum (APIENTRY *PFNVBOXVHWA_CHECK_FRAMEBUFFER_STATUS)(GLenum target); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_FRAMEBUFFER_TEXTURE1D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_FRAMEBUFFER_TEXTURE2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_FRAMEBUFFER_TEXTURE3D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_GET_FRAMEBUFFER_ATTACHMENT_PARAMETRIV)(GLenum target, GLenum attachment, GLenum pname, GLint *params); + + +/*****************/ + +/* functions */ + +/* @todo: move those to VBoxGLInfo class instance members ??? */ +extern PFNVBOXVHWA_ACTIVE_TEXTURE vboxglActiveTexture; +extern PFNVBOXVHWA_MULTI_TEX_COORD2I vboxglMultiTexCoord2i; +extern PFNVBOXVHWA_MULTI_TEX_COORD2D vboxglMultiTexCoord2d; +extern PFNVBOXVHWA_MULTI_TEX_COORD2F vboxglMultiTexCoord2f; + + +extern PFNVBOXVHWA_CREATE_SHADER vboxglCreateShader; +extern PFNVBOXVHWA_SHADER_SOURCE vboxglShaderSource; +extern PFNVBOXVHWA_COMPILE_SHADER vboxglCompileShader; +extern PFNVBOXVHWA_DELETE_SHADER vboxglDeleteShader; + +extern PFNVBOXVHWA_CREATE_PROGRAM vboxglCreateProgram; +extern PFNVBOXVHWA_ATTACH_SHADER vboxglAttachShader; +extern PFNVBOXVHWA_DETACH_SHADER vboxglDetachShader; +extern PFNVBOXVHWA_LINK_PROGRAM vboxglLinkProgram; +extern PFNVBOXVHWA_USE_PROGRAM vboxglUseProgram; +extern PFNVBOXVHWA_DELETE_PROGRAM vboxglDeleteProgram; + +extern PFNVBOXVHWA_IS_SHADER vboxglIsShader; +extern PFNVBOXVHWA_GET_SHADERIV vboxglGetShaderiv; +extern PFNVBOXVHWA_IS_PROGRAM vboxglIsProgram; +extern PFNVBOXVHWA_GET_PROGRAMIV vboxglGetProgramiv; +extern PFNVBOXVHWA_GET_ATTACHED_SHADERS vboxglGetAttachedShaders; +extern PFNVBOXVHWA_GET_SHADER_INFO_LOG vboxglGetShaderInfoLog; +extern PFNVBOXVHWA_GET_PROGRAM_INFO_LOG vboxglGetProgramInfoLog; + +extern PFNVBOXVHWA_GET_UNIFORM_LOCATION vboxglGetUniformLocation; + +extern PFNVBOXVHWA_UNIFORM1F vboxglUniform1f; +extern PFNVBOXVHWA_UNIFORM2F vboxglUniform2f; +extern PFNVBOXVHWA_UNIFORM3F vboxglUniform3f; +extern PFNVBOXVHWA_UNIFORM4F vboxglUniform4f; + +extern PFNVBOXVHWA_UNIFORM1I vboxglUniform1i; +extern PFNVBOXVHWA_UNIFORM2I vboxglUniform2i; +extern PFNVBOXVHWA_UNIFORM3I vboxglUniform3i; +extern PFNVBOXVHWA_UNIFORM4I vboxglUniform4i; + +extern PFNVBOXVHWA_GEN_BUFFERS vboxglGenBuffers; +extern PFNVBOXVHWA_DELETE_BUFFERS vboxglDeleteBuffers; +extern PFNVBOXVHWA_BIND_BUFFER vboxglBindBuffer; +extern PFNVBOXVHWA_BUFFER_DATA vboxglBufferData; +extern PFNVBOXVHWA_MAP_BUFFER vboxglMapBuffer; +extern PFNVBOXVHWA_UNMAP_BUFFER vboxglUnmapBuffer; + +extern PFNVBOXVHWA_IS_FRAMEBUFFER vboxglIsFramebuffer; +extern PFNVBOXVHWA_BIND_FRAMEBUFFER vboxglBindFramebuffer; +extern PFNVBOXVHWA_DELETE_FRAMEBUFFERS vboxglDeleteFramebuffers; +extern PFNVBOXVHWA_GEN_FRAMEBUFFERS vboxglGenFramebuffers; +extern PFNVBOXVHWA_CHECK_FRAMEBUFFER_STATUS vboxglCheckFramebufferStatus; +extern PFNVBOXVHWA_FRAMEBUFFER_TEXTURE1D vboxglFramebufferTexture1D; +extern PFNVBOXVHWA_FRAMEBUFFER_TEXTURE2D vboxglFramebufferTexture2D; +extern PFNVBOXVHWA_FRAMEBUFFER_TEXTURE3D vboxglFramebufferTexture3D; +extern PFNVBOXVHWA_GET_FRAMEBUFFER_ATTACHMENT_PARAMETRIV vboxglGetFramebufferAttachmentParameteriv; + + +/* + * Glossing over qt 5 vs 6 differences. + * + * Note! We could use the qt6 classes in 5, but we probably don't have the + * necessary modules in our current qt builds. + */ +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +class QOpenGLWidget; +class QOpenGLContext; +# define MY_QOpenGLWidget QOpenGLWidget +# define MY_QOpenGLContext QOpenGLContext +#else +class QGLWidget; +class QGLContext; +# define MY_QOpenGLWidget QGLWidget +# define MY_QOpenGLContext QGLContext +#endif + + +class VBoxGLInfo +{ +public: + VBoxGLInfo() : + mGLVersion(0), + mFragmentShaderSupported(false), + mTextureRectangleSupported(false), + mTextureNP2Supported(false), + mPBOSupported(false), + mFBOSupported(false), + mMultiTexNumSupported(1), /* 1 would mean it is not supported */ + m_GL_ARB_multitexture(false), + m_GL_ARB_shader_objects(false), + m_GL_ARB_fragment_shader(false), + m_GL_ARB_pixel_buffer_object(false), + m_GL_ARB_texture_rectangle(false), + m_GL_EXT_texture_rectangle(false), + m_GL_NV_texture_rectangle(false), + m_GL_ARB_texture_non_power_of_two(false), + m_GL_EXT_framebuffer_object(false), + mInitialized(false) + {} + + void init(const MY_QOpenGLContext *pContext); + + bool isInitialized() const { return mInitialized; } + + int getGLVersion() const { return mGLVersion; } + bool isFragmentShaderSupported() const { return mFragmentShaderSupported; } + bool isTextureRectangleSupported() const { return mTextureRectangleSupported; } + bool isTextureNP2Supported() const { return mTextureNP2Supported; } + bool isPBOSupported() const { return mPBOSupported; } + /* some ATI drivers do not seem to support non-zero offsets when dealing with PBOs + * @todo: add a check for that, always unsupported currently */ + bool isPBOOffsetSupported() const { return false; } + bool isFBOSupported() const { return mFBOSupported; } + /* 1 would mean it is not supported */ + int getMultiTexNumSupported() const { return mMultiTexNumSupported; } + + static int parseVersion(const GLubyte * ver); +private: + void initExtSupport(const MY_QOpenGLContext &context); + + int mGLVersion; + bool mFragmentShaderSupported; + bool mTextureRectangleSupported; + bool mTextureNP2Supported; + bool mPBOSupported; + bool mFBOSupported; + int mMultiTexNumSupported; /* 1 would mean it is not supported */ + + bool m_GL_ARB_multitexture; + bool m_GL_ARB_shader_objects; + bool m_GL_ARB_fragment_shader; + bool m_GL_ARB_pixel_buffer_object; + bool m_GL_ARB_texture_rectangle; + bool m_GL_EXT_texture_rectangle; + bool m_GL_NV_texture_rectangle; + bool m_GL_ARB_texture_non_power_of_two; + bool m_GL_EXT_framebuffer_object; + + bool mInitialized; +}; + +class VBoxGLTmpContext +{ +public: + VBoxGLTmpContext(); + ~VBoxGLTmpContext(); + + const MY_QOpenGLContext *makeCurrent(); +private: + MY_QOpenGLWidget *mWidget; +}; + + +#define VBOXQGL_MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((uint32_t)(uint8_t)(ch0) | ((uint32_t)(uint8_t)(ch1) << 8) | \ + ((uint32_t)(uint8_t)(ch2) << 16) | ((uint32_t)(uint8_t)(ch3) << 24 )) + +#define FOURCC_AYUV VBOXQGL_MAKEFOURCC('A', 'Y', 'U', 'V') +#define FOURCC_UYVY VBOXQGL_MAKEFOURCC('U', 'Y', 'V', 'Y') +#define FOURCC_YUY2 VBOXQGL_MAKEFOURCC('Y', 'U', 'Y', '2') +#define FOURCC_YV12 VBOXQGL_MAKEFOURCC('Y', 'V', '1', '2') +#define VBOXVHWA_NUMFOURCC 4 + +class VBoxVHWAInfo +{ +public: + VBoxVHWAInfo() : + mFourccSupportedCount(0), + mInitialized(false) + {} + + VBoxVHWAInfo(const VBoxGLInfo & glInfo) : + mglInfo(glInfo), + mFourccSupportedCount(0), + mInitialized(false) + {} + + void init(const MY_QOpenGLContext *pContext); + + bool isInitialized() const { return mInitialized; } + + const VBoxGLInfo & getGlInfo() const { return mglInfo; } + + bool isVHWASupported() const; + + int getFourccSupportedCount() const { return mFourccSupportedCount; } + const uint32_t * getFourccSupportedList() const { return mFourccSupportedList; } + + static bool checkVHWASupport(); +private: + VBoxGLInfo mglInfo; + uint32_t mFourccSupportedList[VBOXVHWA_NUMFOURCC]; + int mFourccSupportedCount; + + bool mInitialized; +}; + +#endif /* !VBOX_INCLUDED_VBoxGL2D_h */ diff --git a/include/VBox/VBoxGuest.h b/include/VBox/VBoxGuest.h new file mode 100644 index 00000000..ddd78327 --- /dev/null +++ b/include/VBox/VBoxGuest.h @@ -0,0 +1,1012 @@ +/** @file + * VBoxGuest - VirtualBox Guest Additions Driver Interface. (ADD,DEV) + * + * @note This file is used by 16-bit compilers too (OpenWatcom). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_VBoxGuest_h +#define VBOX_INCLUDED_VBoxGuest_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/assertcompile.h> +#include <VBox/VMMDevCoreTypes.h> +#include <VBox/VBoxGuestCoreTypes.h> + + + +/** @defgroup grp_vboxguest VirtualBox Guest Additions Device Driver + * + * Also know as VBoxGuest. + * + * @{ + */ + +/** @defgroup grp_vboxguest_ioc VirtualBox Guest Additions Driver Interface + * + * @note This is considered internal in ring-3, please use the VbglR3 functions. + * + * - I/O controls for user and/or kernel mode starts at 0. + * - IDC specific requests descends from 63. + * - Bits 7 and 6 are currently reserved for future hacks. + * + * @remarks When creating new IOCtl interfaces keep in mind that not all OSes supports + * reporting back the output size. (This got messed up a little bit in VBoxDrv.) + * + * The request size is also a little bit tricky as it's passed as part of the + * request code on unix. The size field is 14 bits on Linux, 12 bits on *BSD, + * 13 bits Darwin, and 8-bits on Solaris. All the BSDs and Darwin kernels + * will make use of the size field, while Linux and Solaris will not. We're of + * course using the size to validate and/or map/lock the request, so it has + * to be valid. + * + * For Solaris we will have to do something special though, 255 isn't + * sufficient for all we need. A 4KB restriction (BSD) is probably not + * too problematic (yet) as a general one. + * + * More info can be found in SUPDRVIOC.h and related sources. + * + * @remarks If adding interfaces that only has input or only has output, some new macros + * needs to be created so the most efficient IOCtl data buffering method can be + * used. + * + * @{ + */ +#if !defined(IN_RC) && !defined(IN_RING0_AGNOSTIC) + +/** Fictive start address of the hypervisor physical memory for MmMapIoSpace. */ +#define VBOXGUEST_HYPERVISOR_PHYSICAL_START UINT32_C(0xf8000000) + +#ifdef RT_OS_DARWIN +/** Cookie used to fend off some unwanted clients to the IOService. */ +# define VBOXGUEST_DARWIN_IOSERVICE_COOKIE UINT32_C(0x56426f78) /* 'VBox' */ +#endif + + +#if defined(RT_OS_WINDOWS) +# ifndef CTL_CODE +# include <iprt/win/windows.h> +# endif + /* Automatic buffering, size not encoded. */ +# define VBGL_IOCTL_CODE_SIZE(Function, Size) CTL_CODE(FILE_DEVICE_UNKNOWN, 2048 + (Function), METHOD_BUFFERED, FILE_WRITE_ACCESS) +# define VBGL_IOCTL_CODE_BIG(Function) CTL_CODE(FILE_DEVICE_UNKNOWN, 2048 + (Function), METHOD_BUFFERED, FILE_WRITE_ACCESS) +# define VBGL_IOCTL_CODE_FAST(Function) CTL_CODE(FILE_DEVICE_UNKNOWN, 2048 + (Function), METHOD_NEITHER, FILE_WRITE_ACCESS) +# define VBGL_IOCTL_CODE_STRIPPED(a_uIOCtl) (a_uIOCtl) +# define VBOXGUEST_DEVICE_NAME "\\\\.\\VBoxGuest" +/** The support service name. */ +# define VBOXGUEST_SERVICE_NAME "VBoxGuest" +/** Global name for Win2k+ */ +# define VBOXGUEST_DEVICE_NAME_GLOBAL "\\\\.\\Global\\VBoxGuest" +/** Win32 driver name */ +# define VBOXGUEST_DEVICE_NAME_NT L"\\Device\\VBoxGuest" +/** Device name. */ +# define VBOXGUEST_DEVICE_NAME_DOS L"\\DosDevices\\VBoxGuest" + +#elif defined(RT_OS_OS2) + /* No automatic buffering, size not encoded. */ +# define VBGL_IOCTL_CATEGORY 0xc2 +# define VBGL_IOCTL_CODE_SIZE(Function, Size) ((unsigned char)(Function)) +# define VBGL_IOCTL_CODE_BIG(Function) ((unsigned char)(Function)) +# define VBGL_IOCTL_CATEGORY_FAST 0xc3 /**< Also defined in VBoxGuestA-os2.asm. */ +# define VBGL_IOCTL_CODE_FAST(Function) ((unsigned char)(Function)) +# define VBGL_IOCTL_CODE_STRIPPED(a_uIOCtl) (a_uIOCtl) +# define VBOXGUEST_DEVICE_NAME "\\Dev\\VBoxGst$" +/** Short device name for AttachDD. + * @note Case sensitive. Must match what VBoxGuestA-os2.asm says! */ +# define VBOXGUEST_DEVICE_NAME_SHORT "vboxgst$" + +#elif defined(RT_OS_SOLARIS) + /* No automatic buffering, size limited to 255 bytes => use VBGLBIGREQ for everything. */ +# include <sys/ioccom.h> +# define VBGL_IOCTL_CODE_SIZE(Function, Size) ((uintptr_t)(_IOWRN('V', (Function), sizeof(VBGLREQHDR)))) +# define VBGL_IOCTL_CODE_BIG(Function) _IOWRN('V', (Function), sizeof(VBGLREQHDR)) +# define VBGL_IOCTL_CODE_FAST(Function) _IO( 'F', (Function)) +# define VBGL_IOCTL_CODE_STRIPPED(a_uIOCtl) (a_uIOCtl) +# define VBGL_IOCTL_IS_FAST(a_uIOCtl) ( ((a_uIOCtl) & 0x0000ff00) == ('F' << 8) ) + +#elif defined(RT_OS_LINUX) + /* No automatic buffering, size limited to 16KB. */ +# include <linux/ioctl.h> +# define VBGL_IOCTL_CODE_SIZE(Function, Size) _IOC(_IOC_READ | _IOC_WRITE, 'V', (Function), (Size)) +# define VBGL_IOCTL_CODE_BIG(Function) _IO('V', (Function)) +# define VBGL_IOCTL_CODE_FAST(Function) _IO('F', (Function)) +# define VBGL_IOCTL_CODE_STRIPPED(a_uIOCtl) _IOC_NR((a_uIOCtl)) +# define VBOXGUEST_USER_DEVICE_NAME "/dev/vboxuser" + +#elif defined(RT_OS_HAIKU) + /* No automatic buffering, size not encoded. */ + /** @todo do something better */ +# define VBGL_IOCTL_CODE_SIZE(Function, Size) (0x56420000 | (Function)) +# define VBGL_IOCTL_CODE_BIG(Function) (0x56420000 | (Function)) +# define VBGL_IOCTL_CODE_FAST(Function) (0x56420000 | (Function)) +# define VBGL_IOCTL_CODE_STRIPPED(a_uIOCtl) (a_uIOCtl) +# define VBOXGUEST_DEVICE_NAME "/dev/misc/vboxguest" + +#else /* BSD Like */ + /* Automatic buffering, size limited to 4KB on *BSD and 8KB on Darwin - commands the limit, 4KB. */ +# include <sys/ioccom.h> +# define VBGL_IOCTL_CODE_SIZE(Function, Size) _IOC(IOC_INOUT, 'V', (Function), (Size)) +# define VBGL_IOCTL_CODE_BIG(Function) _IO('V', (Function)) +# define VBGL_IOCTL_CODE_FAST(Function) _IO('F', (Function)) +# define VBGL_IOCTL_CODE_STRIPPED(a_uIOCtl) ((a_uIOCtl) & ~(_IOC(0,0,0,IOCPARM_MASK))) +# define VBGL_IOCTL_IS_FAST(a_uIOCtl) ( IOCGROUP(a_uIOCtl) == 'F' ) +# if defined(RT_OS_DARWIN) +# define VBOXGUEST_DEVICE_NAME "/dev/vboxguest" +# define VBOXGUEST_USER_DEVICE_NAME "/dev/vboxguestu" +# endif + +#endif + +/** @todo It would be nice if we could have two defines without paths. */ + +/** @def VBOXGUEST_DEVICE_NAME + * The support device name. */ +#ifndef VBOXGUEST_DEVICE_NAME /* PORTME */ +# define VBOXGUEST_DEVICE_NAME "/dev/vboxguest" +#endif + +/** @def VBOXGUEST_USER_DEVICE_NAME + * The support device name of the user accessible device node. */ +#ifndef VBOXGUEST_USER_DEVICE_NAME +# define VBOXGUEST_USER_DEVICE_NAME VBOXGUEST_DEVICE_NAME +#endif + + +/** + * The VBoxGuest I/O control version. + * + * As usual, the high word contains the major version and changes to it + * signifies incompatible changes. + * + * The lower word is the minor version number, it is increased when new + * functions are added or existing changed in a backwards compatible manner. + */ +#define VBGL_IOC_VERSION UINT32_C(0x00010000) + + + +/** @name VBGL_IOCTL_DRIVER_INFO + * Adjust and get driver information. + * + * @note May switch the session to a backwards compatible interface version if + * uClientVersion indicates older client code. + * + * @{ + */ +#define VBGL_IOCTL_DRIVER_VERSION_INFO VBGL_IOCTL_CODE_SIZE(0, VBGL_IOCTL_DRIVER_VERSION_INFO_SIZE) +#define VBGL_IOCTL_DRIVER_VERSION_INFO_SIZE sizeof(VBGLIOCDRIVERVERSIONINFO) +#define VBGL_IOCTL_DRIVER_VERSION_INFO_SIZE_IN RT_UOFFSET_AFTER(VBGLIOCDRIVERVERSIONINFO, u.In) +#define VBGL_IOCTL_DRIVER_VERSION_INFO_SIZE_OUT sizeof(VBGLIOCDRIVERVERSIONINFO) +typedef struct VBGLIOCDRIVERVERSIONINFO +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** The requested interface version number (VBGL_IOC_VERSION). */ + uint32_t uReqVersion; + /** The minimum interface version number + * (typically the major version part of VBGL_IOC_VERSION). */ + uint32_t uMinVersion; + /** Reserved, MBZ. */ + uint32_t uReserved1; + /** Reserved, MBZ. */ + uint32_t uReserved2; + } In; + struct + { + /** Interface version for this session (typically VBGL_IOC_VERSION). */ + uint32_t uSessionVersion; + /** The version of the IDC interface (VBGL_IOC_VERSION). */ + uint32_t uDriverVersion; + /** The SVN revision of the driver. + * This will be set to 0 if not compiled into the driver. */ + uint32_t uDriverRevision; + /** Reserved \#1 (will be returned as zero until defined). */ + uint32_t uReserved1; + /** Reserved \#2 (will be returned as zero until defined). */ + uint32_t uReserved2; + } Out; + } u; +} VBGLIOCDRIVERVERSIONINFO, RT_FAR *PVBGLIOCDRIVERVERSIONINFO; +AssertCompileSize(VBGLIOCDRIVERVERSIONINFO, 24 + 20); +#if !defined(__GNUC__) /* Some GCC versions can't handle the complicated RT_UOFFSET_AFTER macro, it seems. */ \ + && (!defined(RT_OS_OS2) || (!defined(__IBMC__) && !defined(__IBMCPP__) && (!defined(__WATCOMC__) || !defined(__cplusplus)))) +AssertCompile(VBGL_IOCTL_DRIVER_VERSION_INFO_SIZE_IN == 24 + 16); +#endif +/** @} */ + + +/** @name VBGL_IOCTL_GET_PORT_INFO + * Query VMMDev I/O port region and MMIO mapping address. + * @remarks Ring-0 only. + * @{ + */ +#define VBGL_IOCTL_GET_VMMDEV_IO_INFO VBGL_IOCTL_CODE_SIZE(1, VBGL_IOCTL_GET_VMMDEV_IO_INFO_SIZE) +#define VBGL_IOCTL_GET_VMMDEV_IO_INFO_SIZE sizeof(VBGLIOCGETVMMDEVIOINFO) +#define VBGL_IOCTL_GET_VMMDEV_IO_INFO_SIZE_IN sizeof(VBGLREQHDR) +#define VBGL_IOCTL_GET_VMMDEV_IO_INFO_SIZE_OUT sizeof(VBGLIOCGETVMMDEVIOINFO) +typedef struct VBGLIOCGETVMMDEVIOINFO +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** The MMIO mapping. NULL if no MMIO region. */ + struct VMMDevMemory volatile RT_FAR *pvVmmDevMapping; + /** The I/O port address. */ + RTIOPORT IoPort; + /** Padding, ignore. */ + RTIOPORT auPadding[HC_ARCH_BITS == 64 ? 3 : 1]; + } Out; + } u; +} VBGLIOCGETVMMDEVIOINFO, RT_FAR *PVBGLIOCGETVMMDEVIOINFO; +AssertCompileSize(VBGLIOCGETVMMDEVIOINFO, 24 + (HC_ARCH_BITS == 64 ? 16 : 8)); +/** @} */ + + +/** @name VBGL_IOCTL_VMMDEV_REQUEST + * IOCTL to VBoxGuest to perform a VMM Device request less than 1KB in size. + * @{ + */ +#define VBGL_IOCTL_VMMDEV_REQUEST(a_cb) VBGL_IOCTL_CODE_SIZE(2, (a_cb)) +/** @} */ + + +/** @name VBGL_IOCTL_VMMDEV_REQUEST_BIG + * IOCTL to VBoxGuest to perform a VMM Device request that can 1KB or larger. + * @{ + */ +#define VBGL_IOCTL_VMMDEV_REQUEST_BIG VBGL_IOCTL_CODE_BIG(3) +/** @} */ + +#ifdef VBOX_WITH_HGCM + +/** @name VBGL_IOCTL_HGCM_CONNECT + * Connect to a HGCM service. + * @{ */ +# define VBGL_IOCTL_HGCM_CONNECT VBGL_IOCTL_CODE_SIZE(4, VBGL_IOCTL_HGCM_CONNECT_SIZE) +# define VBGL_IOCTL_HGCM_CONNECT_SIZE sizeof(VBGLIOCHGCMCONNECT) +# define VBGL_IOCTL_HGCM_CONNECT_SIZE_IN sizeof(VBGLIOCHGCMCONNECT) +# define VBGL_IOCTL_HGCM_CONNECT_SIZE_OUT RT_UOFFSET_AFTER(VBGLIOCHGCMCONNECT, u.Out) +typedef struct VBGLIOCHGCMCONNECT +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + HGCMServiceLocation Loc; + } In; + struct + { + uint32_t idClient; + } Out; + } u; +} VBGLIOCHGCMCONNECT, RT_FAR *PVBGLIOCHGCMCONNECT; +AssertCompileSize(VBGLIOCHGCMCONNECT, 24 + 132); +#if !defined(__GNUC__) /* Some GCC versions can't handle the complicated RT_UOFFSET_AFTER macro, it seems. */ \ + && (!defined(RT_OS_OS2) || (!defined(__IBMC__) && !defined(__IBMCPP__) && (!defined(__WATCOMC__) || !defined(__cplusplus)))) +AssertCompile(VBGL_IOCTL_HGCM_CONNECT_SIZE_OUT == 24 + 4); +#endif +/** @} */ + + +/** @name VBGL_IOCTL_HGCM_DISCONNECT + * Disconnect from a HGCM service. + * @{ */ +# define VBGL_IOCTL_HGCM_DISCONNECT VBGL_IOCTL_CODE_SIZE(5, VBGL_IOCTL_HGCM_DISCONNECT_SIZE) +# define VBGL_IOCTL_HGCM_DISCONNECT_SIZE sizeof(VBGLIOCHGCMDISCONNECT) +# define VBGL_IOCTL_HGCM_DISCONNECT_SIZE_IN sizeof(VBGLIOCHGCMDISCONNECT) +# define VBGL_IOCTL_HGCM_DISCONNECT_SIZE_OUT sizeof(VBGLREQHDR) +/** @note This is also used by a VbglR0 API. */ +typedef struct VBGLIOCHGCMDISCONNECT +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + uint32_t idClient; + } In; + } u; +} VBGLIOCHGCMDISCONNECT, RT_FAR *PVBGLIOCHGCMDISCONNECT; +AssertCompileSize(VBGLIOCHGCMDISCONNECT, 24 + 4); +/** @} */ + + +/** @name VBGL_IOCTL_HGCM_CALL, VBGL_IOCTL_HGCM_CALL_WITH_USER_DATA + * + * Make a call to a HGCM service. There are several variations here. + * + * The VBGL_IOCTL_HGCM_CALL_WITH_USER_DATA variation is for other drivers (like + * the graphics ones) passing on requests from user land that contains user + * data. These calls are always interruptible. + * + * @{ */ +# define VBGL_IOCTL_HGCM_CALL_32(a_cb) VBGL_IOCTL_CODE_SIZE(6, (a_cb)) +# define VBGL_IOCTL_HGCM_CALL_64(a_cb) VBGL_IOCTL_CODE_SIZE(7, (a_cb)) +# if ARCH_BITS == 64 +# define VBGL_IOCTL_HGCM_CALL(a_cb) VBGL_IOCTL_HGCM_CALL_64(a_cb) +# else +# define VBGL_IOCTL_HGCM_CALL(a_cb) VBGL_IOCTL_HGCM_CALL_32(a_cb) +# endif +# define VBGL_IOCTL_HGCM_CALL_WITH_USER_DATA(a_cb) VBGL_IOCTL_CODE_SIZE(8, (a_cb)) +/** @} */ + + +/** @name VBGL_IOCTL_IDC_HGCM_FAST_CALL + * + * Variant of VBGL_IOCTL_HGCM_CALL for drivers that submits the request as-is to + * the host and handles the waiting, the caller does all the rest. + * + * @note ring-0 only. + * @note Size is not encoded in the I/O control code. + * @{ + */ +#define VBGL_IOCTL_IDC_HGCM_FAST_CALL VBGL_IOCTL_CODE_SIZE(61, sizeof(VBGLIOCIDCHGCMFASTCALL)) +#define VBGL_IOCTL_IDC_HGCM_FAST_CALL_SIZE(a_cb) (a_cb) +#define VBGL_IOCTL_IDC_HGCM_FAST_CALL_SIZE_IN(a_cb) (a_cb) +#define VBGL_IOCTL_IDC_HGCM_FAST_CALL_SIZE_OUT(a_cb) (a_cb) +#pragma pack(4) /* Want it to fit nicely with the 44 byte VMMDevHGCMCall and optimally align 64-bit parameters structures. */ +typedef struct VBGLIOCIDCHGCMFASTCALL +{ + /** The header. */ + VBGLREQHDR Hdr; + /** The physical address of the following VMMDevHGCMCall structure. */ + RTGCPHYS32 GCPhysReq; + /** Set if interruptible. */ + bool fInterruptible; + /** Reserved. */ + uint8_t abReserved0[3]; + uint64_t uTimestamp[2]; + uint8_t abReserved1[4]; + /* After this structure follows a VMMDevHGCMCall strcuture (44 bytes), then + zero or more HGCMFunctionParameter structures (12 or 16 bytes), and finally + page lists and embedded buffers. */ +} VBGLIOCIDCHGCMFASTCALL, RT_FAR *PVBGLIOCIDCHGCMFASTCALL; +#pragma pack() +AssertCompileSize(VBGLIOCIDCHGCMFASTCALL, /* 24 + 4 + 1 + 3 + 2*8 + 4 = 0x34 (52) = */ 0x34); + +/** + * Macro for initializing VBGLIOCIDCHGCMFASTCALL and the following + * VMMDevHGCMCall structures. + * + * @param a_pHdr The request header to initialize. + * @param a_HdrPhys The 32-bit physical address corresponding to @a a_pHdr. + * @param a_pCall Pointer to the VMMDevHGCMCall structure. + * @param a_idClient The HGCM client ID. + * @param a_uFunction The HGCM function number. + * @param a_cParms The number of parameters following @a a_pCall. + * @param a_cbReq The size of the whole request. + */ +#define VBGLIOCIDCHGCMFASTCALL_INIT(a_pHdr, a_HdrPhys, a_pCall, a_idClient, a_uFunction, a_cParms, a_cbReq) \ + do { \ + Assert((uintptr_t)(a_pHdr) + sizeof(VBGLIOCIDCHGCMFASTCALL) == (uintptr_t)(a_pCall)); \ + VBGLREQHDR_INIT_EX(&(a_pHdr)->Hdr, a_cbReq, a_cbReq); \ + pReq->Hdr.GCPhysReq = (a_HdrPhys) + sizeof(VBGLIOCIDCHGCMFASTCALL); \ + pReq->Hdr.fInterruptible = false; \ + \ + (a_pCall)->header.header.size = (a_cbReq) - sizeof(VBGLIOCIDCHGCMFASTCALL); \ + (a_pCall)->header.header.version = VBGLREQHDR_VERSION; \ + (a_pCall)->header.header.requestType= (ARCH_BITS == 64 ? VMMDevReq_HGCMCall64 : VMMDevReq_HGCMCall32); \ + (a_pCall)->header.header.rc = VERR_INTERNAL_ERROR; \ + (a_pCall)->header.header.reserved1 = 0; \ + (a_pCall)->header.header.fRequestor = VMMDEV_REQUESTOR_KERNEL | VMMDEV_REQUESTOR_USR_DRV_OTHER \ + | VMMDEV_REQUESTOR_CON_DONT_KNOW | VMMDEV_REQUESTOR_TRUST_NOT_GIVEN; \ + (a_pCall)->header.fu32Flags = 0; \ + (a_pCall)->header.result = VERR_INTERNAL_ERROR; \ + (a_pCall)->u32ClientID = (a_idClient); \ + (a_pCall)->u32Function = (a_uFunction); \ + (a_pCall)->cParms = (a_cParms); \ + } while (0) + + +/** @} */ + +#endif /* VBOX_WITH_HGCM */ + + +/** @name VBGL_IOCTL_LOG + * IOCTL to VBoxGuest to perform backdoor logging. + * @{ */ +#define VBOXGUEST_IOCTL_LOG(Size) +#define VBGL_IOCTL_LOG(a_cchMsg) VBGL_IOCTL_CODE_BIG(9) +#define VBGL_IOCTL_LOG_SIZE(a_cchMsg) (sizeof(VBGLREQHDR) + (a_cchMsg) + 1) +#define VBGL_IOCTL_LOG_SIZE_IN(a_cchMsg) (sizeof(VBGLREQHDR) + (a_cchMsg) + 1) +#define VBGL_IOCTL_LOG_SIZE_OUT sizeof(VBGLREQHDR) +typedef struct VBGLIOCLOG +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** The log message. + * The length is determined from the input size and zero termination. */ + char szMsg[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + } In; + } u; +} VBGLIOCLOG, RT_FAR *PVBGLIOCLOG; +/** @} */ + + +/** @name VBGL_IOCTL_WAIT_FOR_EVENTS + * Wait for a VMMDev host event notification. + * @{ + */ +#define VBGL_IOCTL_WAIT_FOR_EVENTS VBGL_IOCTL_CODE_SIZE(10, VBGL_IOCTL_WAIT_FOR_EVENTS_SIZE) +#define VBGL_IOCTL_WAIT_FOR_EVENTS_SIZE sizeof(VBGLIOCWAITFOREVENTS) +#define VBGL_IOCTL_WAIT_FOR_EVENTS_SIZE_IN sizeof(VBGLIOCWAITFOREVENTS) +#define VBGL_IOCTL_WAIT_FOR_EVENTS_SIZE_OUT RT_UOFFSET_AFTER(VBGLIOCWAITFOREVENTS, u.Out) +typedef struct VBGLIOCWAITFOREVENTS +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** Timeout in milliseconds. */ + uint32_t cMsTimeOut; + /** Events to wait for. */ + uint32_t fEvents; + } In; + struct + { + /** Events that occurred. */ + uint32_t fEvents; + } Out; + } u; +} VBGLIOCWAITFOREVENTS, RT_FAR *PVBGLIOCWAITFOREVENTS; +AssertCompileSize(VBGLIOCWAITFOREVENTS, 24 + 8); +/** @} */ + + +/** @name VBGL_IOCTL_INTERRUPT_ALL_WAIT_FOR_EVENTS + * IOCTL to VBoxGuest to interrupt (cancel) any pending + * VBGL_IOCTL_WAIT_FOR_EVENTS and return. + * + * Handled inside the guest additions and not seen by the host at all. + * After calling this, VBGL_IOCTL_WAIT_FOR_EVENTS should no longer be called in + * the same session. At the time of writing this is not enforced; at the time + * of reading it may be. + * @see VBGL_IOCTL_WAIT_FOR_EVENTS + * + * @{ + */ +#define VBGL_IOCTL_INTERRUPT_ALL_WAIT_FOR_EVENTS VBGL_IOCTL_CODE_SIZE(11, VBGL_IOCTL_INTERRUPT_ALL_WAIT_FOR_EVENTS_SIZE) +#define VBGL_IOCTL_INTERRUPT_ALL_WAIT_FOR_EVENTS_SIZE sizeof(VBGLREQHDR) +#define VBGL_IOCTL_INTERRUPT_ALL_WAIT_FOR_EVENTS_SIZE_IN sizeof(VBGLREQHDR) +#define VBGL_IOCTL_INTERRUPT_ALL_WAIT_FOR_EVENTS_SIZE_OUT sizeof(VBGLREQHDR) +/** @} */ + + +/** @name VBGL_IOCTL_CHANGE_FILTER_MASK + * IOCTL to VBoxGuest to control the event filter mask. + * @{ */ +#define VBGL_IOCTL_CHANGE_FILTER_MASK VBGL_IOCTL_CODE_SIZE(12, VBGL_IOCTL_CHANGE_FILTER_MASK_SIZE) +#define VBGL_IOCTL_CHANGE_FILTER_MASK_SIZE sizeof(VBGLIOCCHANGEFILTERMASK) +#define VBGL_IOCTL_CHANGE_FILTER_MASK_SIZE_IN sizeof(VBGLIOCCHANGEFILTERMASK) +#define VBGL_IOCTL_CHANGE_FILTER_MASK_SIZE_OUT sizeof(VBGLREQHDR) +typedef struct VBGLIOCCHANGEFILTERMASK +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** Flags to set. */ + uint32_t fOrMask; + /** Flags to remove. */ + uint32_t fNotMask; + } In; + } u; +} VBGLIOCCHANGEFILTERMASK, RT_FAR *PVBGLIOCCHANGEFILTERMASK; +AssertCompileSize(VBGLIOCCHANGEFILTERMASK, 24 + 8); +/** @} */ + + +/** @name VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES + * IOCTL to for acquiring and releasing guest capabilities. + * + * This is used for multiple purposes: + * 1. By doing @a acquire r3 client application (e.g. VBoxTray) claims it will + * use the given session for performing operations like @a seamless or + * @a auto-resize, thus, if the application terminates, the driver will + * automatically cleanup the caps reported to host, so that host knows guest + * does not support them anymore + * 2. In a multy-user environment this will not allow r3 applications (like + * VBoxTray) running in different user sessions simultaneously to interfere + * with each other. An r3 client application (like VBoxTray) is responsible + * for Acquiring/Releasing caps properly as needed. + * + * + * VERR_RESOURCE_BUSY is returned if any capabilities in the fOrMask are + * currently acquired by some other VBoxGuest session. + * + * @todo Rename to VBGL_IOCTL_ACQUIRE_GUEST_CAPS + * @{ + */ +#define VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES VBGL_IOCTL_CODE_SIZE(13, VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES_SIZE) +#define VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES_SIZE sizeof(VBGLIOCACQUIREGUESTCAPS) +#define VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES_SIZE_IN sizeof(VBGLIOCACQUIREGUESTCAPS) +#define VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES_SIZE_OUT sizeof(VBGLREQHDR) + +/** Default operation (full acquire/release). */ +#define VBGL_IOC_AGC_FLAGS_DEFAULT UINT32_C(0x00000000) +/** Configures VBoxGuest to use the specified caps in Acquire mode, w/o making + * any caps acquisition/release. This is only possible to set acquire mode for + * caps, but not clear it, so fNotMask is ignored when this flag is set. */ +#define VBGL_IOC_AGC_FLAGS_CONFIG_ACQUIRE_MODE UINT32_C(0x00000001) +/** Valid flag mask. */ +#define VBGL_IOC_AGC_FLAGS_VALID_MASK UINT32_C(0x00000001) + +typedef struct VBGLIOCACQUIREGUESTCAPS +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** Acquire flags (VBGL_IOC_AGC_FLAGS_XXX). */ + uint32_t fFlags; + /** Guest capabilities to acquire (VMMDEV_GUEST_SUPPORTS_XXX). */ + uint32_t fOrMask; + /** Guest capabilities to release (VMMDEV_GUEST_SUPPORTS_XXX). */ + uint32_t fNotMask; + } In; + } u; +} VBGLIOCACQUIREGUESTCAPS, RT_FAR *PVBGLIOCACQUIREGUESTCAPS; +AssertCompileSize(VBGLIOCACQUIREGUESTCAPS, 24 + 12); +/** @} */ + + +/** @name VBGL_IOCTL_CHANGE_GUEST_CAPABILITIES + * IOCTL to VBoxGuest to set guest capabilities. + * @{ */ +#define VBGL_IOCTL_CHANGE_GUEST_CAPABILITIES VBGL_IOCTL_CODE_SIZE(14, VBGL_IOCTL_CHANGE_GUEST_CAPABILITIES_SIZE) +#define VBGL_IOCTL_CHANGE_GUEST_CAPABILITIES_SIZE sizeof(VBGLIOCSETGUESTCAPS) +#define VBGL_IOCTL_CHANGE_GUEST_CAPABILITIES_SIZE_IN sizeof(VBGLIOCSETGUESTCAPS) +#define VBGL_IOCTL_CHANGE_GUEST_CAPABILITIES_SIZE_OUT sizeof(VBGLIOCSETGUESTCAPS) +typedef struct VBGLIOCSETGUESTCAPS +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** The capabilities to set (VMMDEV_GUEST_SUPPORTS_XXX). */ + uint32_t fOrMask; + /** The capabilities to drop (VMMDEV_GUEST_SUPPORTS_XXX). */ + uint32_t fNotMask; + } In; + struct + { + /** The capabilities held by the session after the call (VMMDEV_GUEST_SUPPORTS_XXX). */ + uint32_t fSessionCaps; + /** The capabilities for all the sessions after the call (VMMDEV_GUEST_SUPPORTS_XXX). */ + uint32_t fGlobalCaps; + } Out; + } u; +} VBGLIOCSETGUESTCAPS, RT_FAR *PVBGLIOCSETGUESTCAPS; +AssertCompileSize(VBGLIOCSETGUESTCAPS, 24 + 8); +typedef VBGLIOCSETGUESTCAPS VBoxGuestSetCapabilitiesInfo; +/** @} */ + + +/** @name VBGL_IOCTL_SET_MOUSE_STATUS + * IOCTL to VBoxGuest to update the mouse status features. + * @{ */ +#define VBGL_IOCTL_SET_MOUSE_STATUS VBGL_IOCTL_CODE_SIZE(15, VBGL_IOCTL_SET_MOUSE_STATUS_SIZE) +#define VBGL_IOCTL_SET_MOUSE_STATUS_SIZE sizeof(VBGLIOCSETMOUSESTATUS) +#define VBGL_IOCTL_SET_MOUSE_STATUS_SIZE_IN sizeof(VBGLIOCSETMOUSESTATUS) +#define VBGL_IOCTL_SET_MOUSE_STATUS_SIZE_OUT sizeof(VBGLREQHDR) +typedef struct VBGLIOCSETMOUSESTATUS +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** Mouse status flags (VMMDEV_MOUSE_XXX). */ + uint32_t fStatus; + } In; + } u; +} VBGLIOCSETMOUSESTATUS, RT_FAR *PVBGLIOCSETMOUSESTATUS; +/** @} */ + + +/** @name VBGL_IOCTL_SET_MOUSE_NOTIFY_CALLBACK + * + * IOCTL to for setting the mouse driver callback. + * @note The callback will be called in interrupt context with the VBoxGuest + * device event spinlock held. + * @note ring-0 only. + * + * @{ */ +#define VBGL_IOCTL_SET_MOUSE_NOTIFY_CALLBACK VBGL_IOCTL_CODE_SIZE(16, VBGL_IOCTL_SET_MOUSE_NOTIFY_CALLBACK_SIZE) +#define VBGL_IOCTL_SET_MOUSE_NOTIFY_CALLBACK_SIZE sizeof(VBGLIOCSETMOUSENOTIFYCALLBACK) +#define VBGL_IOCTL_SET_MOUSE_NOTIFY_CALLBACK_SIZE_IN sizeof(VBGLIOCSETMOUSENOTIFYCALLBACK) +#define VBGL_IOCTL_SET_MOUSE_NOTIFY_CALLBACK_SIZE_OUT sizeof(VBGLREQHDR) +typedef struct VBGLIOCSETMOUSENOTIFYCALLBACK +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** Mouse notification callback function. */ + PFNVBOXGUESTMOUSENOTIFY pfnNotify; + /** The callback argument. */ + void RT_FAR *pvUser; + } In; + } u; +} VBGLIOCSETMOUSENOTIFYCALLBACK, RT_FAR *PVBGLIOCSETMOUSENOTIFYCALLBACK; +/** @} */ + + +/** @name VBGL_IOCTL_CHECK_BALLOON + * IOCTL to VBoxGuest to check memory ballooning. + * + * The guest kernel module / device driver will ask the host for the current size of + * the balloon and adjust the size. Or it will set fHandledInR0 = false and R3 is + * responsible for allocating memory and calling R0 (VBGL_IOCTL_CHANGE_BALLOON). + * @{ */ +#define VBGL_IOCTL_CHECK_BALLOON VBGL_IOCTL_CODE_SIZE(17, VBGL_IOCTL_CHECK_BALLOON_SIZE) +#define VBGL_IOCTL_CHECK_BALLOON_SIZE sizeof(VBGLIOCCHECKBALLOON) +#define VBGL_IOCTL_CHECK_BALLOON_SIZE_IN sizeof(VBGLREQHDR) +#define VBGL_IOCTL_CHECK_BALLOON_SIZE_OUT sizeof(VBGLIOCCHECKBALLOON) +typedef struct VBGLIOCCHECKBALLOON +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** The size of the balloon in chunks of 1MB. */ + uint32_t cBalloonChunks; + /** false = handled in R0, no further action required. + * true = allocate balloon memory in R3. */ + bool fHandleInR3; + /** Explicit padding, please ignore. */ + bool afPadding[3]; + } Out; + } u; +} VBGLIOCCHECKBALLOON, RT_FAR *PVBGLIOCCHECKBALLOON; +AssertCompileSize(VBGLIOCCHECKBALLOON, 24 + 8); +typedef VBGLIOCCHECKBALLOON VBoxGuestCheckBalloonInfo; +/** @} */ + + +/** @name VBGL_IOCTL_CHANGE_BALLOON + * IOCTL to VBoxGuest to supply or revoke one chunk for ballooning. + * + * The guest kernel module / device driver will lock down supplied memory or + * unlock reclaimed memory and then forward the physical addresses of the + * changed balloon chunk to the host. + * + * @{ */ +#define VBGL_IOCTL_CHANGE_BALLOON VBGL_IOCTL_CODE_SIZE(18, VBGL_IOCTL_CHANGE_BALLOON_SIZE) +#define VBGL_IOCTL_CHANGE_BALLOON_SIZE sizeof(VBGLIOCCHANGEBALLOON) +#define VBGL_IOCTL_CHANGE_BALLOON_SIZE_IN sizeof(VBGLIOCCHANGEBALLOON) +#define VBGL_IOCTL_CHANGE_BALLOON_SIZE_OUT sizeof(VBGLREQHDR) +typedef struct VBGLIOCCHANGEBALLOON +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** Address of the chunk (user space address). */ + RTR3PTR pvChunk; + /** Explicit alignment padding, MBZ. */ + uint8_t abPadding[ARCH_BITS == 64 ? 0 + 7 : 4 + 7]; + /** true = inflate, false = deflate. */ + bool fInflate; + } In; + } u; +} VBGLIOCCHANGEBALLOON, RT_FAR *PVBGLIOCCHANGEBALLOON; +AssertCompileSize(VBGLIOCCHANGEBALLOON, 24+16); +/** @} */ + + +/** @name VBGL_IOCTL_WRITE_CORE_DUMP + * IOCTL to VBoxGuest to write guest core. + * @{ */ +#define VBGL_IOCTL_WRITE_CORE_DUMP VBGL_IOCTL_CODE_SIZE(19, VBGL_IOCTL_WRITE_CORE_DUMP_SIZE) +#define VBGL_IOCTL_WRITE_CORE_DUMP_SIZE sizeof(VBGLIOCWRITECOREDUMP) +#define VBGL_IOCTL_WRITE_CORE_DUMP_SIZE_IN sizeof(VBGLIOCWRITECOREDUMP) +#define VBGL_IOCTL_WRITE_CORE_DUMP_SIZE_OUT sizeof(VBGLREQHDR) +typedef struct VBGLIOCWRITECOREDUMP +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** Flags (reserved, MBZ). */ + uint32_t fFlags; + } In; + } u; +} VBGLIOCWRITECOREDUMP, RT_FAR *PVBGLIOCWRITECOREDUMP; +AssertCompileSize(VBGLIOCWRITECOREDUMP, 24 + 4); +typedef VBGLIOCWRITECOREDUMP VBoxGuestWriteCoreDump; +/** @} */ + + +#ifdef VBOX_WITH_DPC_LATENCY_CHECKER +/** @name VBGL_IOCTL_DPC_LATENCY_CHECKER + * IOCTL to VBoxGuest to perform DPC latency tests, printing the result in + * the release log on the host. Takes no data, returns no data. + * @{ */ +# define VBGL_IOCTL_DPC_LATENCY_CHECKER VBGL_IOCTL_CODE_SIZE(20, VBGL_IOCTL_DPC_LATENCY_CHECKER_SIZE) +# define VBGL_IOCTL_DPC_LATENCY_CHECKER_SIZE sizeof(VBGLREQHDR) +# define VBGL_IOCTL_DPC_LATENCY_CHECKER_SIZE_IN sizeof(VBGLREQHDR) +# define VBGL_IOCTL_DPC_LATENCY_CHECKER_SIZE_OUT sizeof(VBGLREQHDR) +/** @} */ +#endif + + +#ifdef RT_OS_OS2 +/** + * The data buffer layout for the IDC entry point (AttachDD). + * + * @remark This is defined in multiple 16-bit headers / sources. + * Some places it's called VBGOS2IDC to short things a bit. + */ +typedef struct VBGLOS2ATTACHDD +{ + /** VBGL_IOC_VERSION. */ + uint32_t u32Version; + /** Opaque session handle. */ + uint32_t u32Session; + + /** + * The 32-bit service entry point. + * + * @returns VBox status code. + * @param u32Session The session handle (PVBOXGUESTSESSION). + * @param iFunction The requested function. + * @param pReqHdr The input/output data buffer. The caller + * ensures that this cannot be swapped out, or that + * it's acceptable to take a page in fault in the + * current context. If the request doesn't take + * input or produces output, apssing NULL is okay. + * @param cbReq The size of the data buffer. + */ +# if ARCH_BITS == 32 || defined(DOXYGEN_RUNNING) + DECLCALLBACKMEMBER(int, pfnServiceEP,(uint32_t u32Session, unsigned iFunction, PVBGLREQHDR pReqHdr, size_t cbReq)); +# else + uint32_t pfnServiceEP; +#endif + + /** The 16-bit service entry point for C code (cdecl). + * + * It's the same as the 32-bit entry point, but the types has + * changed to 16-bit equivalents. + * + * @code + * int far cdecl + * VBoxGuestOs2IDCService16(uint32_t u32Session, uint16_t iFunction, + * PVBGLREQHDR fpvData, uint16_t cbData); + * @endcode + */ +# if ARCH_BITS == 16 || defined(DOXYGEN_RUNNING) + DECLCALLBACKMEMBER(int, fpfnServiceEP,(uint32_t u32Session, uint16_t iFunction, PVBGLREQHDR fpvData, uint16_t cbData)); +# else + RTFAR16 fpfnServiceEP; +# endif + + /** The 16-bit service entry point for Assembly code (register). + * + * This is just a wrapper around fpfnServiceEP to simplify calls + * from 16-bit assembly code. + * + * @returns (e)ax: VBox status code; cx: The amount of data returned. + * + * @param u32Session eax - The above session handle. + * @param iFunction dl - The requested function. + * @param pvData es:bx - The input/output data buffer. + * @param cbData cx - The size of the data buffer. + */ + RTFAR16 fpfnServiceAsmEP; +} VBGLOS2ATTACHDD; +/** Pointer to VBOXGUESTOS2IDCCONNECT buffer. */ +typedef VBGLOS2ATTACHDD RT_FAR *PVBGLOS2ATTACHDD; + +/** + * Prototype for the 16-bit callback returned by AttachDD on OS/2. + * @param pAttachInfo Pointer to structure to fill in. + */ +# if defined(__IBMC__) || defined(__IBMCPP__) +typedef void (* __cdecl RT_FAR_CODE PFNVBGLOS2ATTACHDD)(PVBGLOS2ATTACHDD pAttachInfo); +# else +typedef void (__cdecl RT_FAR_CODE *PFNVBGLOS2ATTACHDD)(PVBGLOS2ATTACHDD pAttachInfo); +# endif +#endif /* RT_OS_OS2 */ + + +/** @name VBGL_IOCL_IDC_CONNECT + * IDC client connect request. + * + * On platforms other than Windows and OS/2, this will also create a kernel + * session for the caller. + * + * @note ring-0 only. + * @{ + */ +#define VBGL_IOCTL_IDC_CONNECT VBGL_IOCTL_CODE_SIZE(63, VBGL_IOCTL_IDC_CONNECT_SIZE) +#define VBGL_IOCTL_IDC_CONNECT_SIZE sizeof(VBGLIOCIDCCONNECT) +#define VBGL_IOCTL_IDC_CONNECT_SIZE_IN RT_UOFFSET_AFTER(VBGLIOCIDCCONNECT, u.In) +#define VBGL_IOCTL_IDC_CONNECT_SIZE_OUT sizeof(VBGLIOCIDCCONNECT) +typedef struct VBGLIOCIDCCONNECT +{ + /** The header. */ + VBGLREQHDR Hdr; + /** The payload union. */ + union + { + struct + { + /** VBGL_IOCTL_IDC_CONNECT_MAGIC_COOKIE. */ + uint32_t u32MagicCookie; + /** The desired version of the I/O control interface (VBGL_IOC_VERSION). */ + uint32_t uReqVersion; + /** The minimum version of the I/O control interface (VBGL_IOC_VERSION). */ + uint32_t uMinVersion; + /** Reserved, MBZ. */ + uint32_t uReserved; + } In; + struct + { + /** The session handle (opaque). */ +#if ARCH_BITS >= 32 + void RT_FAR *pvSession; +#else + uint32_t pvSession; +#endif + /** The version of the I/O control interface for this session + * (typically VBGL_IOC_VERSION). */ + uint32_t uSessionVersion; + /** The I/O control interface version for of the driver (VBGL_IOC_VERSION). */ + uint32_t uDriverVersion; + /** The SVN revision of the driver. + * This will be set to 0 if not compiled into the driver. */ + uint32_t uDriverRevision; + /** Reserved \#1 (will be returned as zero until defined). */ + uint32_t uReserved1; + /** Reserved \#2 (will be returned as NULL until defined). */ + void RT_FAR *pvReserved2; + } Out; + } u; +} VBGLIOCIDCCONNECT, RT_FAR *PVBGLIOCIDCCONNECT; +AssertCompileSize(VBGLIOCIDCCONNECT, 24 + 16 + (ARCH_BITS == 64 ? 8 : 4) * 2); +#if !defined(__GNUC__) /* Some GCC versions can't handle the complicated RT_UOFFSET_AFTER macro, it seems. */ \ + && (!defined(RT_OS_OS2) || (!defined(__IBMC__) && !defined(__IBMCPP__) && (!defined(__WATCOMC__) || !defined(__cplusplus)))) +AssertCompile(VBGL_IOCTL_IDC_CONNECT_SIZE_IN == 24 + 16); +#endif +#define VBGL_IOCTL_IDC_CONNECT_MAGIC_COOKIE UINT32_C(0x55aa4d5a) /**< Magic value for doing an IDC connect. */ +/** @} */ + + +/** @name VBGL_IOCL_IDC_DISCONNECT + * IDC client disconnect request. + * + * This will destroy the kernel session associated with the IDC connection. + * + * @note ring-0 only. + * @{ + */ +#define VBGL_IOCTL_IDC_DISCONNECT VBGL_IOCTL_CODE_SIZE(62, VBGL_IOCTL_IDC_DISCONNECT_SIZE) +#define VBGL_IOCTL_IDC_DISCONNECT_SIZE sizeof(VBGLIOCIDCDISCONNECT) +#define VBGL_IOCTL_IDC_DISCONNECT_SIZE_IN sizeof(VBGLIOCIDCDISCONNECT) +#define VBGL_IOCTL_IDC_DISCONNECT_SIZE_OUT sizeof(VBGLREQHDR) +typedef struct VBGLIOCIDCDISCONNECT +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** The session handle for platforms where this is needed. */ +#if ARCH_BITS >= 32 + void RT_FAR *pvSession; +#else + uint32_t pvSession; +#endif + } In; + } u; +} VBGLIOCIDCDISCONNECT, RT_FAR *PVBGLIOCIDCDISCONNECT; +AssertCompileSize(VBGLIOCIDCDISCONNECT, 24 + (ARCH_BITS == 64 ? 8 : 4)); +/** @} */ + + +#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2) +RT_C_DECLS_BEGIN +/** + * The VBoxGuest IDC entry point. + * + * @returns VBox status code. + * @param pvSession The session. + * @param uReq The request code. + * @param pReqHdr The request. + * @param cbReq The request size. + */ +int VBOXCALL VBoxGuestIDC(void RT_FAR *pvSession, uintptr_t uReq, PVBGLREQHDR pReqHdr, size_t cbReq); +RT_C_DECLS_END +#endif + + +#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) + +/* Private IOCtls between user space and the kernel video driver. DRM private + * IOCtls always have the type 'd' and a number between 0x40 and 0x99 (0x9F?) */ + +# define VBOX_DRM_IOCTL(a) (0x40 + DRM_VBOX_ ## a) + +/** Stop using HGSMI in the kernel driver until it is re-enabled, so that a + * user-space driver can use it. It must be re-enabled before the kernel + * driver can be used again in a sensible way. */ +/** @note These IOCtls was removed from the code, but are left here as + * templates as we may need similar ones in future. */ +# define DRM_VBOX_DISABLE_HGSMI 0 +# define DRM_IOCTL_VBOX_DISABLE_HGSMI VBOX_DRM_IOCTL(DISABLE_HGSMI) +# define VBOXVIDEO_IOCTL_DISABLE_HGSMI _IO('d', DRM_IOCTL_VBOX_DISABLE_HGSMI) +/** Enable HGSMI in the kernel driver after it was previously disabled. */ +# define DRM_VBOX_ENABLE_HGSMI 1 +# define DRM_IOCTL_VBOX_ENABLE_HGSMI VBOX_DRM_IOCTL(ENABLE_HGSMI) +# define VBOXVIDEO_IOCTL_ENABLE_HGSMI _IO('d', DRM_IOCTL_VBOX_ENABLE_HGSMI) + +#endif /* RT_OS_LINUX || RT_OS_SOLARIS || RT_OS_FREEBSD */ + +#endif /* !defined(IN_RC) && !defined(IN_RING0_AGNOSTIC) && !defined(IPRT_NO_CRT) */ + +/** @} */ + +/** @} */ +#endif /* !VBOX_INCLUDED_VBoxGuest_h */ + diff --git a/include/VBox/VBoxGuestCoreTypes.h b/include/VBox/VBoxGuestCoreTypes.h new file mode 100644 index 00000000..0d820aab --- /dev/null +++ b/include/VBox/VBoxGuestCoreTypes.h @@ -0,0 +1,238 @@ +/** @file + * VBoxGuest - VirtualBox Guest Additions, Core Types. + * + * This contains types that are used both in the VBoxGuest I/O control interface + * and the VBoxGuestLib. The goal is to avoid having to include VBoxGuest.h + * everwhere VBoxGuestLib.h is used. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_VBoxGuestCoreTypes_h +#define VBOX_INCLUDED_VBoxGuestCoreTypes_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + +/** @addtogroup grp_vboxguest + * @{ */ + +/** + * Common in/out header. + * + * This is a copy/mirror of VMMDevRequestHeader to prevent duplicating data and + * needing to verify things multiple times. For that reason this differs a bit + * from SUPREQHDR. + * + * @sa VMMDevRequestHeader + */ +typedef struct VBGLREQHDR +{ + /** IN: The request input size, and output size if cbOut is zero. + * @sa VMMDevRequestHeader::size */ + uint32_t cbIn; + /** IN: Structure version (VBGLREQHDR_VERSION) + * @sa VMMDevRequestHeader::version */ + uint32_t uVersion; + /** IN: The VMMDev request type, set to VBGLREQHDR_TYPE_DEFAULT unless this is a + * kind of VMMDev request. + * @sa VMMDevRequestType, VMMDevRequestHeader::requestType */ + uint32_t uType; + /** OUT: The VBox status code of the operation, out direction only. */ + int32_t rc; + /** IN: The output size. This is optional - set to zero to use cbIn as the + * output size. */ + uint32_t cbOut; + /** Reserved / filled in by kernel, MBZ. + * @sa VMMDevRequestHeader::fRequestor */ + uint32_t uReserved; +} VBGLREQHDR; +AssertCompileSize(VBGLREQHDR, 24); +/** Pointer to a IOC header. */ +typedef VBGLREQHDR RT_FAR *PVBGLREQHDR; + +/** Version of VMMDevRequestHeader structure. */ +#define VBGLREQHDR_VERSION UINT32_C(0x10001) +/** Default request type. Use this for non-VMMDev requests. */ +#define VBGLREQHDR_TYPE_DEFAULT UINT32_C(0) + +/** Initialize a VBGLREQHDR structure for a fixed size I/O control call. + * @param a_pHdr Pointer to the header to initialize. + * @param a_IOCtl The base I/O control name, no VBGL_IOCTL_ prefix. We + * have to skip the prefix to avoid it getting expanded + * before we append _SIZE_IN and _SIZE_OUT to it. + */ +#define VBGLREQHDR_INIT(a_pHdr, a_IOCtl) \ + VBGLREQHDR_INIT_EX(a_pHdr, RT_CONCAT3(VBGL_IOCTL_,a_IOCtl,_SIZE_IN), RT_CONCAT3(VBGL_IOCTL_,a_IOCtl,_SIZE_OUT)) +/** Initialize a VBGLREQHDR structure, extended version. */ +#define VBGLREQHDR_INIT_EX(a_pHdr, a_cbIn, a_cbOut) \ + do { \ + (a_pHdr)->cbIn = (uint32_t)(a_cbIn); \ + (a_pHdr)->uVersion = VBGLREQHDR_VERSION; \ + (a_pHdr)->uType = VBGLREQHDR_TYPE_DEFAULT; \ + (a_pHdr)->rc = VERR_INTERNAL_ERROR; \ + (a_pHdr)->cbOut = (uint32_t)(a_cbOut); \ + (a_pHdr)->uReserved = 0; \ + } while (0) +/** Initialize a VBGLREQHDR structure for a VMMDev request. + * Same as VMMDEV_REQ_HDR_INIT(). */ +#define VBGLREQHDR_INIT_VMMDEV(a_pHdr, a_cb, a_enmType) \ + do { \ + (a_pHdr)->cbIn = (a_cb); \ + (a_pHdr)->uVersion = VBGLREQHDR_VERSION; \ + (a_pHdr)->uType = (a_enmType); \ + (a_pHdr)->rc = VERR_INTERNAL_ERROR; \ + (a_pHdr)->cbOut = 0; \ + (a_pHdr)->uReserved = 0; \ + } while (0) + + +/** + * For VBGL_IOCTL_HGCM_CALL and VBGL_IOCTL_HGCM_CALL_WITH_USER_DATA. + * + * @note This is used by alot of HGCM call structures. + */ +typedef struct VBGLIOCHGCMCALL +{ + /** Common header. */ + VBGLREQHDR Hdr; + /** Input: The id of the caller. */ + uint32_t u32ClientID; + /** Input: Function number. */ + uint32_t u32Function; + /** Input: How long to wait (milliseconds) for completion before cancelling the + * call. This is ignored if not a VBGL_IOCTL_HGCM_CALL_TIMED or + * VBGL_IOCTL_HGCM_CALL_TIMED_32 request. */ + uint32_t cMsTimeout; + /** Input: Whether a timed call is interruptible (ring-0 only). This is ignored + * if not a VBGL_IOCTL_HGCM_CALL_TIMED or VBGL_IOCTL_HGCM_CALL_TIMED_32 + * request, or if made from user land. */ + bool fInterruptible; + /** Explicit padding, MBZ. */ + uint8_t bReserved; + /** Input: How many parameters following this structure. + * + * The parameters are either HGCMFunctionParameter64 or HGCMFunctionParameter32, + * depending on whether we're receiving a 64-bit or 32-bit request. + * + * The current maximum is 61 parameters (given a 1KB max request size, + * and a 64-bit parameter size of 16 bytes). + * + * @note This information is duplicated by Hdr.cbIn, but it's currently too much + * work to eliminate this. */ + uint16_t cParms; + /* Parameters follow in form HGCMFunctionParameter aParms[cParms] */ +} VBGLIOCHGCMCALL, RT_FAR *PVBGLIOCHGCMCALL; +AssertCompileSize(VBGLIOCHGCMCALL, 24 + 16); +typedef VBGLIOCHGCMCALL const RT_FAR *PCVBGLIOCHGCMCALL; + +/** + * Initialize a HGCM header (VBGLIOCHGCMCALL) for a non-timed call. + * + * @param a_pHdr The header to initalize. + * @param a_idClient The client connection ID to call thru. + * @param a_idFunction The function we're calling + * @param a_cParameters Number of parameters. + */ +# define VBGL_HGCM_HDR_INIT(a_pHdr, a_idClient, a_idFunction, a_cParameters) \ + do { \ + VBGLREQHDR_INIT_EX(&(a_pHdr)->Hdr, \ + sizeof(VBGLIOCHGCMCALL) + (a_cParameters) * sizeof(HGCMFunctionParameter), \ + sizeof(VBGLIOCHGCMCALL) + (a_cParameters) * sizeof(HGCMFunctionParameter)); \ + (a_pHdr)->u32ClientID = (a_idClient); \ + (a_pHdr)->u32Function = (a_idFunction); \ + (a_pHdr)->cMsTimeout = RT_INDEFINITE_WAIT; \ + (a_pHdr)->fInterruptible = true; \ + (a_pHdr)->bReserved = 0; \ + (a_pHdr)->cParms = (a_cParameters); \ + } while (0) + +/** + * Initialize a HGCM header (VBGLIOCHGCMCALL) for a non-timed call, custom size. + * + * This is usually only needed when appending page lists to the call. + * + * @param a_pHdr The header to initalize. + * @param a_idClient The client connection ID to call thru. + * @param a_idFunction The function we're calling + * @param a_cParameters Number of parameters. + * @param a_cbReq The request size. + */ +# define VBGL_HGCM_HDR_INIT_EX(a_pHdr, a_idClient, a_idFunction, a_cParameters, a_cbReq) \ + do { \ + Assert((a_cbReq) >= sizeof(VBGLIOCHGCMCALL) + (a_cParameters) * sizeof(HGCMFunctionParameter)); \ + VBGLREQHDR_INIT_EX(&(a_pHdr)->Hdr, (a_cbReq), (a_cbReq)); \ + (a_pHdr)->u32ClientID = (a_idClient); \ + (a_pHdr)->u32Function = (a_idFunction); \ + (a_pHdr)->cMsTimeout = RT_INDEFINITE_WAIT; \ + (a_pHdr)->fInterruptible = true; \ + (a_pHdr)->bReserved = 0; \ + (a_pHdr)->cParms = (a_cParameters); \ + } while (0) + +/** + * Initialize a HGCM header (VBGLIOCHGCMCALL), with timeout (interruptible). + * + * @param a_pHdr The header to initalize. + * @param a_idClient The client connection ID to call thru. + * @param a_idFunction The function we're calling + * @param a_cParameters Number of parameters. + * @param a_cMsTimeout The timeout in milliseconds. + */ +# define VBGL_HGCM_HDR_INIT_TIMED(a_pHdr, a_idClient, a_idFunction, a_cParameters, a_cMsTimeout) \ + do { \ + VBGLREQHDR_INIT_EX(&(a_pHdr)->Hdr, \ + sizeof(VBGLIOCHGCMCALL) + (a_cParameters) * sizeof(HGCMFunctionParameter), \ + sizeof(VBGLIOCHGCMCALL) + (a_cParameters) * sizeof(HGCMFunctionParameter)); \ + (a_pHdr)->u32ClientID = (a_idClient); \ + (a_pHdr)->u32Function = (a_idFunction); \ + (a_pHdr)->cMsTimeout = (a_cMsTimeout); \ + (a_pHdr)->fInterruptible = true; \ + (a_pHdr)->bReserved = 0; \ + (a_pHdr)->cParms = (a_cParameters); \ + } while (0) + +/** Get the pointer to the first HGCM parameter. */ +# define VBGL_HGCM_GET_CALL_PARMS(a_pInfo) ( (HGCMFunctionParameter *)((uint8_t *)(a_pInfo) + sizeof(VBGLIOCHGCMCALL)) ) +/** Get the pointer to the first HGCM parameter in a 32-bit request. */ +# define VBGL_HGCM_GET_CALL_PARMS32(a_pInfo) ( (HGCMFunctionParameter32 *)((uint8_t *)(a_pInfo) + sizeof(VBGLIOCHGCMCALL)) ) + + +/** + * Mouse event noticification callback function. + * @param pvUser Argument given when setting the callback. + */ +typedef DECLCALLBACKTYPE(void, FNVBOXGUESTMOUSENOTIFY,(void *pvUser)); +/** Pointer to a mouse event notification callback function. */ +typedef FNVBOXGUESTMOUSENOTIFY *PFNVBOXGUESTMOUSENOTIFY; /**< @todo fix type prefix */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_VBoxGuestCoreTypes_h */ + diff --git a/include/VBox/VBoxGuestLib.h b/include/VBox/VBoxGuestLib.h new file mode 100644 index 00000000..10a92428 --- /dev/null +++ b/include/VBox/VBoxGuestLib.h @@ -0,0 +1,1405 @@ +/** @file + * VBoxGuestLib - VirtualBox Guest Additions Library. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_VBoxGuestLib_h +#define VBOX_INCLUDED_VBoxGuestLib_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/VMMDev.h> +#include <VBox/VBoxGuestCoreTypes.h> +# ifdef VBOX_WITH_DRAG_AND_DROP +# include <VBox/GuestHost/DragAndDrop.h> +# include <VBox/GuestHost/DragAndDropDefs.h> +# endif +# ifdef VBOX_WITH_SHARED_CLIPBOARD +# include <VBox/GuestHost/SharedClipboard.h> +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +# include <VBox/GuestHost/SharedClipboard-transfers.h> +# endif +# endif /* VBOX_WITH_SHARED_CLIPBOARD */ + +/** @defgroup grp_vboxguest_lib VirtualBox Guest Additions Library + * @ingroup grp_vboxguest + * @{ + */ + +/** @page pg_guest_lib VirtualBox Guest Library + * + * This is a library for abstracting the additions driver interface. There are + * multiple versions of the library depending on the context. The main + * distinction is between kernel and user mode where the interfaces are very + * different. + * + * + * @section sec_guest_lib_ring0 Ring-0 + * + * In ring-0 there are two version: + * - VBOX_LIB_VBGL_R0_BASE / VBoxGuestR0LibBase for the VBoxGuest main driver, + * who is responsible for managing the VMMDev virtual hardware. + * - VBOX_LIB_VBGL_R0 / VBoxGuestR0Lib for other (client) guest drivers. + * + * + * The library source code and the header have a define VBGL_VBOXGUEST, which is + * defined for VBoxGuest and undefined for other drivers. Drivers must choose + * right library in their makefiles and set VBGL_VBOXGUEST accordingly. + * + * The libraries consists of: + * - common code to be used by both VBoxGuest and other drivers; + * - VBoxGuest specific code; + * - code for other drivers which communicate with VBoxGuest via an IOCTL. + * + * + * @section sec_guest_lib_ring3 Ring-3 + * + * There are more variants of the library here: + * - VBOX_LIB_VBGL_R3 / VBoxGuestR3Lib for programs. + * - VBOX_LIB_VBGL_R3_XFREE86 / VBoxGuestR3LibXFree86 for old style XFree + * drivers which uses special loader and or symbol resolving strategy. + * - VBOX_LIB_VBGL_R3_SHARED / VBoxGuestR3LibShared for shared objects / DLLs / + * Dylibs. + * + */ + +RT_C_DECLS_BEGIN + +/** HGCM client ID. + * @todo Promote to VBox/types.h */ +typedef uint32_t HGCMCLIENTID; + + +/** @defgroup grp_vboxguest_lib_r0 Ring-0 interface. + * @{ + */ +#ifdef IN_RING0 +/** @def DECLR0VBGL + * Declare a VBGL ring-0 API with the right calling convention and visibilitiy. + * @param type Return type. */ +# ifdef RT_OS_DARWIN /** @todo probably apply to all, but don't want a forest fire on our hands right now. */ +# define DECLR0VBGL(type) DECLHIDDEN(DECL_NOTHROW(type)) VBOXCALL +# else +# define DECLR0VBGL(type) DECL_NOTHROW(type) VBOXCALL +# endif +# define DECLVBGL(type) DECLR0VBGL(type) + + +/** + * The library initialization function to be used by the main VBoxGuest driver. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0InitPrimary(RTIOPORT portVMMDev, VMMDevMemory *pVMMDevMemory, uint32_t *pfFeatures); + +/** + * The library termination function to be used by the main VBoxGuest driver. + * + * @author bird (2017-08-23) + */ +DECLR0VBGL(void) VbglR0TerminatePrimary(void); + +/** + * The library initialization function to be used by all drivers + * other than the main VBoxGuest system driver. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0InitClient(void); + +/** + * The library termination function. + */ +DECLR0VBGL(void) VbglR0TerminateClient(void); + +/** + * Query the host feature mask. + * + * @returns VBox status code. + * @param pfHostFeatures Where to return the host feature mask, + * VMMDEV_HVF_XXX. + * @note Client only. May fail we're unable to connect VBoxGuest. + */ +DECLR0VBGL(int) VbglR0QueryHostFeatures(uint32_t *pfHostFeatures); + + +/** @name The IDC Client Interface + * @{ + */ + +/** + * Inter-Driver Communication Handle. + */ +typedef union VBGLIDCHANDLE +{ + /** Padding for opaque usage. + * Must be greater or equal in size than the private struct. */ + void *apvPadding[4]; +#ifdef VBGLIDCHANDLEPRIVATE_DECLARED + /** The private view. */ + struct VBGLIDCHANDLEPRIVATE s; +#endif +} VBGLIDCHANDLE; +/** Pointer to a handle. */ +typedef VBGLIDCHANDLE *PVBGLIDCHANDLE; + +DECLR0VBGL(int) VbglR0IdcOpen(PVBGLIDCHANDLE pHandle, uint32_t uReqVersion, uint32_t uMinVersion, + uint32_t *puSessionVersion, uint32_t *puDriverVersion, uint32_t *puDriverRevision); +struct VBGLREQHDR; +DECLR0VBGL(int) VbglR0IdcCallRaw(PVBGLIDCHANDLE pHandle, uintptr_t uReq, struct VBGLREQHDR *pReqHdr, uint32_t cbReq); +DECLR0VBGL(int) VbglR0IdcCall(PVBGLIDCHANDLE pHandle, uintptr_t uReq, struct VBGLREQHDR *pReqHdr, uint32_t cbReq); +DECLR0VBGL(int) VbglR0IdcClose(PVBGLIDCHANDLE pHandle); + +/** @} */ + + +/** @name Generic request functions. + * @{ + */ + +/** + * Allocate memory for generic request and initialize the request header. + * + * @returns VBox status code. + * @param ppReq Where to return the pointer to the allocated memory. + * @param cbReq Size of memory block required for the request. + * @param enmReqType the generic request type. + */ +# if defined(VBOX_INCLUDED_VMMDev_h) || defined(DOXYGEN_RUNNING) +DECLR0VBGL(int) VbglR0GRAlloc(struct VMMDevRequestHeader **ppReq, size_t cbReq, VMMDevRequestType enmReqType); +# else +DECLR0VBGL(int) VbglR0GRAlloc(struct VMMDevRequestHeader **ppReq, size_t cbReq, int32_t enmReqType); +# endif + +/** + * Perform the generic request. + * + * @param pReq pointer the request structure. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0GRPerform(struct VMMDevRequestHeader *pReq); + +/** + * Free the generic request memory. + * + * @param pReq pointer the request structure. + * + * @return VBox status code. + */ +DECLR0VBGL(void) VbglR0GRFree(struct VMMDevRequestHeader *pReq); + +/** + * Verify the generic request header. + * + * @param pReq pointer the request header structure. + * @param cbReq size of the request memory block. It should be equal to the request size + * for fixed size requests. It can be greater than the request size for + * variable size requests. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglGR0Verify(const struct VMMDevRequestHeader *pReq, size_t cbReq); + +/** @} */ + +# ifdef VBOX_WITH_HGCM +struct VBGLIOCHGCMCALL; +struct VBGLIOCIDCHGCMFASTCALL; + +# ifdef VBGL_VBOXGUEST + +/** + * Callback function called from HGCM helpers when a wait for request + * completion IRQ is required. + * + * @returns VINF_SUCCESS, VERR_INTERRUPT or VERR_TIMEOUT. + * @param pvData VBoxGuest pointer to be passed to callback. + * @param u32Data VBoxGuest 32 bit value to be passed to callback. + */ +typedef DECLCALLBACKTYPE(int, FNVBGLHGCMCALLBACK,(VMMDevHGCMRequestHeader *pHeader, void *pvData, uint32_t u32Data)); +/** Pointer to a FNVBGLHGCMCALLBACK. */ +typedef FNVBGLHGCMCALLBACK *PFNVBGLHGCMCALLBACK; + +/** + * Perform a connect request. + * + * That is locate required service and obtain a client identifier for future + * access. + * + * @note This function can NOT handle cancelled requests! + * + * @param pLoc The service to connect to. + * @param fRequestor VMMDEV_REQUESTOR_XXX. + * @param pidClient Where to return the client ID on success. + * @param pfnAsyncCallback Required pointer to function that is calledwhen + * host returns VINF_HGCM_ASYNC_EXECUTE. VBoxGuest + * implements waiting for an IRQ in this function. + * @param pvAsyncData An arbitrary VBoxGuest pointer to be passed to callback. + * @param u32AsyncData An arbitrary VBoxGuest 32 bit value to be passed to callback. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0HGCMInternalConnect(HGCMServiceLocation const *pLoc, uint32_t fRequestor, HGCMCLIENTID *pidClient, + PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData); + + +/** + * Perform a disconnect request. + * + * That is tell the host that the client will not call the service anymore. + * + * @note This function can NOT handle cancelled requests! + * + * @param idClient The client ID to disconnect. + * @param fRequestor VMMDEV_REQUESTOR_XXX. + * @param pfnAsyncCallback Required pointer to function that is called when + * host returns VINF_HGCM_ASYNC_EXECUTE. VBoxGuest + * implements waiting for an IRQ in this function. + * @param pvAsyncData An arbitrary VBoxGuest pointer to be passed to callback. + * @param u32AsyncData An arbitrary VBoxGuest 32 bit value to be passed to + * callback. + * + * @return VBox status code. + */ + +DECLR0VBGL(int) VbglR0HGCMInternalDisconnect(HGCMCLIENTID idClient, uint32_t fRequestor, + PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData); + +/** Call a HGCM service. + * + * @note This function can deal with cancelled requests. + * + * @param pCallInfo The request data. + * @param fFlags Flags, see VBGLR0_HGCMCALL_F_XXX. + * @param fRequestor VMMDEV_REQUESTOR_XXX. + * @param pfnAsyncCallback Required pointer to function that is called when + * host returns VINF_HGCM_ASYNC_EXECUTE. VBoxGuest + * implements waiting for an IRQ in this function. + * @param pvAsyncData An arbitrary VBoxGuest pointer to be passed to callback. + * @param u32AsyncData An arbitrary VBoxGuest 32 bit value to be passed to callback. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0HGCMInternalCall(struct VBGLIOCHGCMCALL *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags, uint32_t fRequestor, + PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData); + +/** Call a HGCM service. (32 bits packet structure in a 64 bits guest) + * + * @note This function can deal with cancelled requests. + * + * @param pCallInfo The request data. + * @param fFlags Flags, see VBGLR0_HGCMCALL_F_XXX. + * @param fRequestor VMMDEV_REQUESTOR_XXX. + * @param pfnAsyncCallback Required pointer to function that is called when + * host returns VINF_HGCM_ASYNC_EXECUTE. VBoxGuest + * implements waiting for an IRQ in this function. + * @param pvAsyncData An arbitrary VBoxGuest pointer to be passed to callback. + * @param u32AsyncData An arbitrary VBoxGuest 32 bit value to be passed to callback. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0HGCMInternalCall32(struct VBGLIOCHGCMCALL *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags, uint32_t fRequestor, + PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData); + +/** @name VbglR0HGCMInternalCall flags + * @{ */ +/** User mode request. + * Indicates that only user mode addresses are permitted as parameters. */ +#define VBGLR0_HGCMCALL_F_USER UINT32_C(0) +/** Kernel mode request. + * Indicates that kernel mode addresses are permitted as parameters. Whether or + * not user mode addresses are permitted is, unfortunately, OS specific. The + * following OSes allows user mode addresses: Windows, TODO. + */ +#define VBGLR0_HGCMCALL_F_KERNEL UINT32_C(1) +/** Mode mask. */ +#define VBGLR0_HGCMCALL_F_MODE_MASK UINT32_C(1) +/** @} */ + +# else /* !VBGL_VBOXGUEST */ + +#ifndef VBGL_VBOXGUEST +/** @internal */ +typedef struct VBGLHGCMHANDLEDATA +{ + uint32_t fAllocated; + VBGLIDCHANDLE IdcHandle; +} VBGLHGCMHANDLEDATA; +#else +struct VBGLHGCMHANDLEDATA; +#endif + +typedef struct VBGLHGCMHANDLEDATA *VBGLHGCMHANDLE; + +/** @name HGCM functions + * @{ + */ + +/** + * Initializes HGCM in the R0 guest library. Must be called before any HGCM + * connections are made. Is called by VbglInitClient(). + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0HGCMInit(void); + +/** + * Terminates HGCM in the R0 guest library. Is called by VbglTerminate(). + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0HGCMTerminate(void); + +/** + * Connect to a service. + * + * @param pHandle Pointer to variable that will hold a handle to be used + * further in VbglHGCMCall and VbglHGCMClose. + * @param pszServiceName The service to connect to. + * @param pidClient Where to return the client ID for the connection. + * + * @return VBox status code. + * + * @todo consider baking the client Id into the handle. + */ +DECLR0VBGL(int) VbglR0HGCMConnect(VBGLHGCMHANDLE *pHandle, const char *pszServiceName, HGCMCLIENTID *pidClient); + +/** + * Connect to a service. + * + * @param handle Handle of the connection. + * @param idClient The ID of the client connection. + * + * @return VBox status code. + * + * @todo consider baking the client Id into the handle. + */ +DECLR0VBGL(int) VbglR0HGCMDisconnect(VBGLHGCMHANDLE handle, HGCMCLIENTID idClient); + +/** + * Call to a service, returning only the I/O control status code. + * + * @param handle Handle of the connection. + * @param pData Call request information structure, including function parameters. + * @param cbData Length in bytes of data. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0HGCMCallRaw(VBGLHGCMHANDLE handle, struct VBGLIOCHGCMCALL *pData, uint32_t cbData); + +/** + * Call to a service, returning the HGCM status code. + * + * @param handle Handle of the connection. + * @param pData Call request information structure, including function parameters. + * @param cbData Length in bytes of data. + * + * @return VBox status code. Either the I/O control status code if that failed, + * or the HGCM status code (pData->Hdr.rc). + */ +DECLR0VBGL(int) VbglR0HGCMCall(VBGLHGCMHANDLE handle, struct VBGLIOCHGCMCALL *pData, uint32_t cbData); + +/** + * Call to a service with user-mode data received by the calling driver from the User-Mode process. + * The call must be done in the context of a calling process. + * + * @param handle Handle of the connection. + * @param pData Call request information structure, including function parameters. + * @param cbData Length in bytes of data. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0HGCMCallUserDataRaw(VBGLHGCMHANDLE handle, struct VBGLIOCHGCMCALL *pData, uint32_t cbData); + +/** + * Call to a service, w/o any repacking and buffer locking in VBoxGuest, + * returning the only request related status code (not HGCM). + * + * The driver only submits the request and waits for completion, nothing else. + * + * @param hHandle The connection handle. + * @param pCallReq The call request. Will be passed directly to the host. + * @param cbCallReq The size of the whole call request. + * + * @return VBox status code. + * + * @remarks The result of the HGCM call is found in + * @a pCallReq->HgcmCallReq.header.result on a successful return. The + * @a pCallReq->Hdr.rc and @a pCallReq->HgcmCallReq.header.header.rc + * fields are the same as the return value and can safely be ignored. + */ +DECLR0VBGL(int) VbglR0HGCMFastCall(VBGLHGCMHANDLE hHandle, struct VBGLIOCIDCHGCMFASTCALL *pCallReq, uint32_t cbCallReq); + +/** @} */ + +/** @name Undocumented helpers for talking to the Chromium OpenGL Host Service + * @{ */ +typedef VBGLHGCMHANDLE VBGLCRCTLHANDLE; +DECLR0VBGL(int) VbglR0CrCtlCreate(VBGLCRCTLHANDLE *phCtl); +DECLR0VBGL(int) VbglR0CrCtlDestroy(VBGLCRCTLHANDLE hCtl); +DECLR0VBGL(int) VbglR0CrCtlConConnect(VBGLCRCTLHANDLE hCtl, HGCMCLIENTID *pidClient); +DECLR0VBGL(int) VbglR0CrCtlConDisconnect(VBGLCRCTLHANDLE hCtl, HGCMCLIENTID idClient); +struct VBGLIOCHGCMCALL; +DECLR0VBGL(int) VbglR0CrCtlConCallRaw(VBGLCRCTLHANDLE hCtl, struct VBGLIOCHGCMCALL *pCallInfo, int cbCallInfo); +DECLR0VBGL(int) VbglR0CrCtlConCall(VBGLCRCTLHANDLE hCtl, struct VBGLIOCHGCMCALL *pCallInfo, int cbCallInfo); +DECLR0VBGL(int) VbglR0CrCtlConCallUserDataRaw(VBGLCRCTLHANDLE hCtl, struct VBGLIOCHGCMCALL *pCallInfo, int cbCallInfo); +/** @} */ + +# endif /* !VBGL_VBOXGUEST */ + +# endif /* VBOX_WITH_HGCM */ + + +/** + * Initialize the heap. + * + * @returns VBox status code. + */ +DECLR0VBGL(int) VbglR0PhysHeapInit(void); + +/** + * Shutdown the heap. + */ +DECLR0VBGL(void) VbglR0PhysHeapTerminate(void); + +/** + * Allocate a memory block. + * + * @returns Virtual address of the allocated memory block. + * @param cb Number of bytes to allocate. + */ +DECLR0VBGL(void *) VbglR0PhysHeapAlloc(uint32_t cb); + +/** + * Get physical address of memory block pointed by the virtual address. + * + * @note WARNING! + * The function does not acquire the Heap mutex! + * When calling the function make sure that the pointer is a valid one and + * is not being deallocated. This function can NOT be used for verifying + * if the given pointer is a valid one allocated from the heap. + * + * @param pv Virtual address of memory block. + * @returns Physical address of the memory block. Zero is returned if @a pv + * isn't valid. + */ +DECLR0VBGL(uint32_t) VbglR0PhysHeapGetPhysAddr(void *pv); + +# ifdef IN_TESTCASE +DECLVBGL(size_t) VbglR0PhysHeapGetFreeSize(void); +# endif + +/** + * Free a memory block. + * + * @param pv Virtual address of memory block. + */ +DECLR0VBGL(void) VbglR0PhysHeapFree(void *pv); + +DECLR0VBGL(int) VbglR0QueryVMMDevMemory(struct VMMDevMemory **ppVMMDevMemory); +DECLR0VBGL(bool) VbglR0CanUsePhysPageList(void); + +# ifndef VBOX_GUEST +/** @name Mouse + * @{ */ +DECLR0VBGL(int) VbglR0SetMouseNotifyCallback(PFNVBOXGUESTMOUSENOTIFY pfnNotify, void *pvUser); +DECLR0VBGL(int) VbglR0GetMouseStatus(uint32_t *pfFeatures, uint32_t *px, uint32_t *py); +DECLR0VBGL(int) VbglR0SetMouseStatus(uint32_t fFeatures); +/** @} */ +# endif /* VBOX_GUEST */ + +#endif /* IN_RING0 */ + +/** @} */ + + +/** @defgroup grp_vboxguest_lib_r3 Ring-3 interface. + * @{ + */ +#ifdef IN_RING3 + +/** @def VBGLR3DECL + * Ring 3 VBGL declaration. + * @param type The return type of the function declaration. + */ +# define VBGLR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL + +/** @name General-purpose functions + * @{ */ +VBGLR3DECL(int) VbglR3Init(void); +VBGLR3DECL(int) VbglR3InitUser(void); +VBGLR3DECL(void) VbglR3Term(void); +# ifdef IPRT_INCLUDED_time_h +VBGLR3DECL(int) VbglR3GetHostTime(PRTTIMESPEC pTime); +# endif +VBGLR3DECL(int) VbglR3InterruptEventWaits(void); +VBGLR3DECL(int) VbglR3WriteLog(const char *pch, size_t cch); +VBGLR3DECL(int) VbglR3CtlFilterMask(uint32_t fOr, uint32_t fNot); +VBGLR3DECL(int) VbglR3Daemonize(bool fNoChDir, bool fNoClose, bool fRespawn, unsigned *pcRespawn); +VBGLR3DECL(int) VbglR3PidFile(const char *pszPath, PRTFILE phFile); +VBGLR3DECL(void) VbglR3ClosePidFile(const char *pszPath, RTFILE hFile); +VBGLR3DECL(int) VbglR3SetGuestCaps(uint32_t fOr, uint32_t fNot); +VBGLR3DECL(int) VbglR3AcquireGuestCaps(uint32_t fOr, uint32_t fNot, bool fConfig); +VBGLR3DECL(int) VbglR3WaitEvent(uint32_t fMask, uint32_t cMillies, uint32_t *pfEvents); + +VBGLR3DECL(int) VbglR3ReportAdditionsStatus(VBoxGuestFacilityType Facility, VBoxGuestFacilityStatus StatusCurrent, + uint32_t fFlags); +VBGLR3DECL(int) VbglR3GetAdditionsVersion(char **ppszVer, char **ppszVerEx, char **ppszRev); +VBGLR3DECL(int) VbglR3GetAdditionsInstallationPath(char **ppszPath); +VBGLR3DECL(int) VbglR3GetSessionId(uint64_t *pu64IdSession); + +/** @} */ + +# ifdef VBOX_WITH_SHARED_CLIPBOARD +/** @name Shared Clipboard + * @{ */ + +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +/** + * Structure for maintaining a VbglR3 Shared Clipboard transfer context. + */ +typedef struct VBGLR3SHCLTRANSFERCMDCTX +{ + /** Default chunk size (in bytes). + * This is set by VbglR3ClipboardConnectEx(). */ + uint32_t cbChunkSize; + /** Max chunk size (in bytes). + * This is set by VbglR3ClipboardConnectEx(). */ + uint32_t cbMaxChunkSize; + /** Optional callbacks to invoke. */ + SHCLTRANSFERCALLBACKTABLE Callbacks; +} VBGLR3SHCLTRANSFERCTX; +/** Pointer to a Shared Clipboard transfer context. */ +typedef VBGLR3SHCLTRANSFERCMDCTX *PVBGLR3SHCLTRANSFERCMDCTX; +# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ + +/** + * The context required for either retrieving or sending a HGCM shared clipboard + * commands from or to the host. + * + * @todo This struct could be handy if we want to implement a second + * communication channel, e.g. via TCP/IP. Use a union for the HGCM stuff then. + */ +typedef struct VBGLR3SHCLCMDCTX +{ + /** HGCM client ID to use for communication. + * This is set by VbglR3ClipboardConnectEx(). */ + uint32_t idClient; + /** This is @c false if both VBOX_SHCL_HF_0_CONTEXT_ID and + * VBOX_SHCL_GF_0_CONTEXT_ID are set, otherwise @c true and only the old + * protocol (< 6.1) should be used. + * This is set by VbglR3ClipboardConnectEx(). */ + bool fUseLegacyProtocol; + /** Host feature flags (VBOX_SHCL_HF_XXX). + * This is set by VbglR3ClipboardConnectEx(). */ + uint64_t fHostFeatures; + /** The guest feature flags reported to the host (VBOX_SHCL_GF_XXX). + * This is set by VbglR3ClipboardConnectEx(). */ + uint64_t fGuestFeatures; + /** The context ID - input or/and output depending on the operation. */ + uint64_t idContext; + /** OUT: Number of parameters retrieved. + * This is set by ??. */ + uint32_t cParmsRecived; +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + /** Data related to Shared Clipboard file transfers. */ + VBGLR3SHCLTRANSFERCMDCTX Transfers; +# endif +} VBGLR3SHCLCMDCTX; +/** Pointer to a shared clipboard context for Vbgl. */ +typedef VBGLR3SHCLCMDCTX *PVBGLR3SHCLCMDCTX; + +/** + * Enumeration specifying a Shared Clipboard event type. + * @todo r=bird: Surely, this isn't necessary?! + */ +typedef enum _VBGLR3CLIPBOARDEVENTTYPE +{ + /** No event needed / defined. */ + VBGLR3CLIPBOARDEVENTTYPE_NONE = 0, + /** Host reports available clipboard formats to the guest. */ + VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS, + /** Host wants to read Shared Clipboard data from the guest. */ + VBGLR3CLIPBOARDEVENTTYPE_READ_DATA, + /** Terminates the Shared Clipboard service. */ + VBGLR3CLIPBOARDEVENTTYPE_QUIT, +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + /** Reports a transfer status to the guest. */ + VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS, +# endif + /** Blow the type up to 32-bit. */ + VBGLR3CLIPBOARDEVENTTYPE_32BIT_HACK = 0x7fffffff +} VBGLR3CLIPBOARDEVENTTYPE; + +/** + * Structure for keeping a Shared Clipboard VbglR3 event. + */ +typedef struct _VBGLR3CLIPBOARDEVENT +{ + /** The event type the union contains. */ + VBGLR3CLIPBOARDEVENTTYPE enmType; + /** Command context bound to this event. */ + VBGLR3SHCLCMDCTX cmdCtx; + union + { + /** Reports available formats from the host. */ + SHCLFORMATS fReportedFormats; + /** Reports that data needs to be read from the guest. */ + SHCLFORMAT fReadData; +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + /** Reports a transfer status to the guest. */ + struct + { + /** ID of the trnasfer. */ + SHCLTRANSFERID uID; + /** Transfer direction. */ + SHCLTRANSFERDIR enmDir; + /** Additional reproting information. */ + SHCLTRANSFERREPORT Report; + } TransferStatus; +# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ + } u; +} VBGLR3CLIPBOARDEVENT, *PVBGLR3CLIPBOARDEVENT; +typedef const PVBGLR3CLIPBOARDEVENT CPVBGLR3CLIPBOARDEVENT; + +/** @todo r=bird: I'm not sure it is appropriate for the VbglR3 to use types + * from VBox/GuestHost/SharedClipboard*.h, doesn't seem clean to me. */ + +VBGLR3DECL(int) VbglR3ClipboardConnect(HGCMCLIENTID *pidClient); +VBGLR3DECL(int) VbglR3ClipboardDisconnect(HGCMCLIENTID idClient); +VBGLR3DECL(int) VbglR3ClipboardGetHostMsgOld(HGCMCLIENTID idClient, uint32_t *pMsg, uint32_t *pfFormats); +VBGLR3DECL(int) VbglR3ClipboardReadData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb, uint32_t *pcb); +VBGLR3DECL(int) VbglR3ClipboardReadDataEx(PVBGLR3SHCLCMDCTX pCtx, SHCLFORMAT uFormat, void *pvData, uint32_t cbData, uint32_t *pcbRead); +VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb); +VBGLR3DECL(int) VbglR3ClipboardWriteDataEx(PVBGLR3SHCLCMDCTX pCtx, SHCLFORMAT fFormat, void *pvData, uint32_t cbData); +VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats); + +VBGLR3DECL(int) VbglR3ClipboardConnectEx(PVBGLR3SHCLCMDCTX pCtx, uint64_t fGuestFeatures); +VBGLR3DECL(int) VbglR3ClipboardDisconnectEx(PVBGLR3SHCLCMDCTX pCtx); + +VBGLR3DECL(int) VbglR3ClipboardReportFeatures(uint32_t idClient, uint64_t fGuestFeatures, uint64_t *pfHostFeatures); +VBGLR3DECL(int) VbglR3ClipboardQueryFeatures(uint32_t idClient, uint64_t *pfHostFeatures); +VBGLR3DECL(int) VbglR3ClipboardMsgPeekWait(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg, uint32_t *pcParameters, uint64_t *pidRestoreCheck); +VBGLR3DECL(int) VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent); +VBGLR3DECL(void) VbglR3ClipboardEventFree(PVBGLR3CLIPBOARDEVENT pEvent); + +VBGLR3DECL(int) VbglR3ClipboardWriteError(HGCMCLIENTID idClient, int rcErr); + +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +VBGLR3DECL(void) VbglR3ClipboardTransferSetCallbacks(PSHCLTRANSFERCALLBACKTABLE pCallbacks); +VBGLR3DECL(int) VbglR3ClipboardEventGetNextEx(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFERCTX pTransferCtx, PVBGLR3CLIPBOARDEVENT pEvent); + +VBGLR3DECL(int) VbglR3ClipboardTransferStatusReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus); + +VBGLR3DECL(int) VbglR3ClipboardRootListRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLIST *ppRootList); + +VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReq(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pfRoots); +VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLIST pRootList); +VBGLR3DECL(int) VbglR3ClipboardRootsWrite(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLISTHDR pRoots); + +VBGLR3DECL(int) VbglR3ClipboardListOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList); +VBGLR3DECL(int) VbglR3ClipboardListOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms); +VBGLR3DECL(int) VbglR3ClipboardListOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList); + +VBGLR3DECL(int) VbglR3ClipboardListCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList); +VBGLR3DECL(int) VbglR3ClipboardListCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList); + +VBGLR3DECL(int) VbglR3ClipboardListHdrWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr); +VBGLR3DECL(int) VbglR3ClipboardListEntryWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry); + +VBGLR3DECL(int) VbglR3ClipboardObjOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms); +VBGLR3DECL(int) VbglR3ClipboardObjOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj); +VBGLR3DECL(int) VbglR3ClipboardObjOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms, + PSHCLOBJHANDLE phObj); + +VBGLR3DECL(int) VbglR3ClipboardObjCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj); +VBGLR3DECL(int) VbglR3ClipboardObjCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj); +VBGLR3DECL(int) VbglR3ClipboardObjCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj); + +VBGLR3DECL(int) VbglR3ClipboardObjReadRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj, uint32_t pcbToRead, + uint32_t *pfFlags); +VBGLR3DECL(int) VbglR3ClipboardObjReadSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, + uint32_t *pcbRead); +VBGLR3DECL(int) VbglR3ClipboardObjWriteSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, + uint32_t *pcbWritten); +# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ +/** @} */ +# endif /* VBOX_WITH_SHARED_CLIPBOARD */ + +/** @name Seamless mode + * @{ */ +VBGLR3DECL(int) VbglR3SeamlessSetCap(bool fState); +VBGLR3DECL(int) VbglR3SeamlessWaitEvent(VMMDevSeamlessMode *pMode); +VBGLR3DECL(int) VbglR3SeamlessSendRects(uint32_t cRects, PRTRECT pRects); +VBGLR3DECL(int) VbglR3SeamlessSendMonitorPositions(uint32_t cPositions, PRTPOINT pPositions); +VBGLR3DECL(int) VbglR3SeamlessGetLastEvent(VMMDevSeamlessMode *pMode); + +/** @} */ + +/** @name Mouse + * @{ */ +VBGLR3DECL(int) VbglR3GetMouseStatus(uint32_t *pfFeatures, uint32_t *px, uint32_t *py); +VBGLR3DECL(int) VbglR3SetMouseStatus(uint32_t fFeatures); +/** @} */ + +/** @name Video + * @{ */ +VBGLR3DECL(int) VbglR3VideoAccelEnable(bool fEnable); +VBGLR3DECL(int) VbglR3VideoAccelFlush(void); +VBGLR3DECL(int) VbglR3SetPointerShape(uint32_t fFlags, uint32_t xHot, uint32_t yHot, uint32_t cx, uint32_t cy, + const void *pvImg, size_t cbImg); +VBGLR3DECL(int) VbglR3SetPointerShapeReq(struct VMMDevReqMousePointer *pReq); +/** @} */ + +/** @name Display + * @{ */ +/** The folder for the video mode hint unix domain socket on Unix-like guests. + * @note This can be safely changed as all users are rebuilt in lock-step. */ +#define VBGLR3HOSTDISPSOCKETPATH "/tmp/.VBoxService" +/** The path to the video mode hint unix domain socket on Unix-like guests. */ +#define VBGLR3HOSTDISPSOCKET VBGLR3VIDEOMODEHINTSOCKETPATH "/VideoModeHint" + +/** The folder for saving video mode hints to between sessions. */ +#define VBGLR3HOSTDISPSAVEDMODEPATH "/var/lib/VBoxGuestAdditions" +/** The path to the file for saving video mode hints to between sessions. */ +#define VBGLR3HOSTDISPSAVEDMODE VBGLR3HOSTDISPSAVEDMODEPATH "/SavedVideoModes" + +VBGLR3DECL(int) VbglR3GetDisplayChangeRequest(uint32_t *pcx, uint32_t *pcy, uint32_t *pcBits, uint32_t *piDisplay, + uint32_t *pdx, uint32_t *pdy, bool *pfEnabled, bool *pfChangeOrigin, bool fAck); +VBGLR3DECL(int) VbglR3GetDisplayChangeRequestMulti(uint32_t cDisplaysIn, uint32_t *pcDisplaysOut, + VMMDevDisplayDef *paDisplays, bool fAck); +VBGLR3DECL(bool) VbglR3HostLikesVideoMode(uint32_t cx, uint32_t cy, uint32_t cBits); +VBGLR3DECL(int) VbglR3VideoModeGetHighestSavedScreen(unsigned *pcScreen); +VBGLR3DECL(int) VbglR3SaveVideoMode(unsigned cScreen, unsigned cx, unsigned cy, unsigned cBits, + unsigned x, unsigned y, bool fEnabled); +VBGLR3DECL(int) VbglR3RetrieveVideoMode(unsigned cScreen, unsigned *pcx, unsigned *pcy, unsigned *pcBits, + unsigned *px, unsigned *py, bool *pfEnabled); +/** @} */ + +/** @name VRDP + * @{ */ +VBGLR3DECL(int) VbglR3VrdpGetChangeRequest(bool *pfActive, uint32_t *puExperienceLevel); +/** @} */ + +/** @name VM Statistics + * @{ */ +VBGLR3DECL(int) VbglR3StatQueryInterval(uint32_t *pu32Interval); +# if defined(VBOX_INCLUDED_VMMDev_h) || defined(DOXYGEN_RUNNING) +VBGLR3DECL(int) VbglR3StatReport(VMMDevReportGuestStats *pReq); +# endif +/** @} */ + +/** @name Memory ballooning + * @{ */ +VBGLR3DECL(int) VbglR3MemBalloonRefresh(uint32_t *pcChunks, bool *pfHandleInR3); +VBGLR3DECL(int) VbglR3MemBalloonChange(void *pv, bool fInflate); +/** @} */ + +/** @name Core Dump + * @{ */ +VBGLR3DECL(int) VbglR3WriteCoreDump(void); + +/** @} */ + +/** @name DRM client handling + * @{ */ +/** Guest property names pattern which is used by Guest Additions DRM services. */ +# define VBGLR3DRMPROPPTR "/VirtualBox/GuestAdd/DRM*" +/** Guest property that defines if the DRM IPC server access should be restricted to a specific user group. */ +# define VBGLR3DRMIPCPROPRESTRICT "/VirtualBox/GuestAdd/DRMIpcRestricted" + +VBGLR3DECL(bool) VbglR3DrmClientIsNeeded(void); +VBGLR3DECL(bool) VbglR3DrmRestrictedIpcAccessIsNeeded(void); +VBGLR3DECL(bool) VbglR3DrmClientIsRunning(void); +VBGLR3DECL(int) VbglR3DrmClientStart(void); +VBGLR3DECL(int) VbglR3DrmLegacyClientStart(void); +VBGLR3DECL(int) VbglR3DrmLegacyX11AgentStart(void); +/** @} */ + +# ifdef VBOX_WITH_GUEST_PROPS +/** @name Guest properties + * @{ */ +/** @todo Docs. */ +typedef struct VBGLR3GUESTPROPENUM VBGLR3GUESTPROPENUM; +/** @todo Docs. */ +typedef VBGLR3GUESTPROPENUM *PVBGLR3GUESTPROPENUM; +VBGLR3DECL(int) VbglR3GuestPropConnect(uint32_t *pidClient); +VBGLR3DECL(int) VbglR3GuestPropDisconnect(HGCMCLIENTID idClient); +VBGLR3DECL(bool) VbglR3GuestPropExist(uint32_t idClient, const char *pszPropName); +VBGLR3DECL(int) VbglR3GuestPropWrite(HGCMCLIENTID idClient, const char *pszName, const char *pszValue, const char *pszFlags); +VBGLR3DECL(int) VbglR3GuestPropWriteValue(HGCMCLIENTID idClient, const char *pszName, const char *pszValue); +VBGLR3DECL(int) VbglR3GuestPropWriteValueV(HGCMCLIENTID idClient, const char *pszName, + const char *pszValueFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); +VBGLR3DECL(int) VbglR3GuestPropWriteValueF(HGCMCLIENTID idClient, const char *pszName, + const char *pszValueFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); +VBGLR3DECL(int) VbglR3GuestPropRead(HGCMCLIENTID idClient, const char *pszName, void *pvBuf, uint32_t cbBuf, char **ppszValue, + uint64_t *pu64Timestamp, char **ppszFlags, uint32_t *pcbBufActual); +VBGLR3DECL(int) VbglR3GuestPropReadEx(uint32_t u32ClientId, + const char *pszPropName, char **ppszValue, char **ppszFlags, uint64_t *puTimestamp); +VBGLR3DECL(int) VbglR3GuestPropReadValue(uint32_t ClientId, const char *pszName, char *pszValue, uint32_t cchValue, + uint32_t *pcchValueActual); +VBGLR3DECL(int) VbglR3GuestPropReadValueAlloc(HGCMCLIENTID idClient, const char *pszName, char **ppszValue); +VBGLR3DECL(void) VbglR3GuestPropReadValueFree(char *pszValue); +VBGLR3DECL(int) VbglR3GuestPropEnumRaw(HGCMCLIENTID idClient, const char *paszPatterns, char *pcBuf, uint32_t cbBuf, + uint32_t *pcbBufActual); +VBGLR3DECL(int) VbglR3GuestPropEnum(HGCMCLIENTID idClient, char const * const *ppaszPatterns, uint32_t cPatterns, + PVBGLR3GUESTPROPENUM *ppHandle, char const **ppszName, char const **ppszValue, + uint64_t *pu64Timestamp, char const **ppszFlags); +VBGLR3DECL(int) VbglR3GuestPropEnumNext(PVBGLR3GUESTPROPENUM pHandle, char const **ppszName, char const **ppszValue, + uint64_t *pu64Timestamp, char const **ppszFlags); +VBGLR3DECL(void) VbglR3GuestPropEnumFree(PVBGLR3GUESTPROPENUM pHandle); +VBGLR3DECL(int) VbglR3GuestPropDelete(HGCMCLIENTID idClient, const char *pszName); +VBGLR3DECL(int) VbglR3GuestPropDelSet(HGCMCLIENTID idClient, char const * const *papszPatterns, uint32_t cPatterns); +VBGLR3DECL(int) VbglR3GuestPropWait(HGCMCLIENTID idClient, const char *pszPatterns, void *pvBuf, uint32_t cbBuf, + uint64_t u64Timestamp, uint32_t cMillies, char ** ppszName, char **ppszValue, + uint64_t *pu64Timestamp, char **ppszFlags, uint32_t *pcbBufActual, bool *pfWasDeleted); +/** @} */ + +/** @name Guest user handling / reporting. + * @{ */ +VBGLR3DECL(int) VbglR3GuestUserReportState(const char *pszUser, const char *pszDomain, VBoxGuestUserState enmState, + uint8_t *pbDetails, uint32_t cbDetails); +/** @} */ + +/** @name Host version handling + * @{ */ +VBGLR3DECL(int) VbglR3HostVersionCheckForUpdate(HGCMCLIENTID idClient, bool *pfUpdate, char **ppszHostVersion, + char **ppszGuestVersion); +VBGLR3DECL(int) VbglR3HostVersionLastCheckedLoad(HGCMCLIENTID idClient, char **ppszVer); +VBGLR3DECL(int) VbglR3HostVersionLastCheckedStore(HGCMCLIENTID idClient, const char *pszVer); +/** @} */ +# endif /* VBOX_WITH_GUEST_PROPS defined */ + +# ifdef VBOX_WITH_SHARED_FOLDERS +/** @name Shared folders + * @{ */ +/** + * Structure containing mapping information for a shared folder. + */ +typedef struct VBGLR3SHAREDFOLDERMAPPING +{ + /** Mapping status. */ + uint32_t u32Status; + /** Root handle. */ + uint32_t u32Root; +} VBGLR3SHAREDFOLDERMAPPING; +/** Pointer to a shared folder mapping information structure. */ +typedef VBGLR3SHAREDFOLDERMAPPING *PVBGLR3SHAREDFOLDERMAPPING; +/** Pointer to a const shared folder mapping information structure. */ +typedef VBGLR3SHAREDFOLDERMAPPING const *PCVBGLR3SHAREDFOLDERMAPPING; + +VBGLR3DECL(int) VbglR3SharedFolderConnect(uint32_t *pidClient); +VBGLR3DECL(int) VbglR3SharedFolderDisconnect(HGCMCLIENTID idClient); +VBGLR3DECL(bool) VbglR3SharedFolderExists(HGCMCLIENTID idClient, const char *pszShareName); +VBGLR3DECL(int) VbglR3SharedFolderGetMappings(HGCMCLIENTID idClient, bool fAutoMountOnly, + PVBGLR3SHAREDFOLDERMAPPING *ppaMappings, uint32_t *pcMappings); +VBGLR3DECL(void) VbglR3SharedFolderFreeMappings(PVBGLR3SHAREDFOLDERMAPPING paMappings); +VBGLR3DECL(int) VbglR3SharedFolderGetName(HGCMCLIENTID idClient,uint32_t u32Root, char **ppszName); /**< @todo r=bird: GET functions return the value, not a status code!*/ +VBGLR3DECL(int) VbglR3SharedFolderQueryFolderInfo(HGCMCLIENTID idClient, uint32_t idRoot, uint64_t fQueryFlags, + char **ppszName, char **ppszMountPoint, + uint64_t *pfFlags, uint32_t *puRootIdVersion); +VBGLR3DECL(int) VbglR3SharedFolderWaitForMappingsChanges(HGCMCLIENTID idClient, uint32_t uPrevVersion, uint32_t *puCurVersion); +VBGLR3DECL(int) VbglR3SharedFolderCancelMappingsChangesWaits(HGCMCLIENTID idClient); + +VBGLR3DECL(int) VbglR3SharedFolderGetMountPrefix(char **ppszPrefix); /**< @todo r=bird: GET functions return the value, not a status code! */ +VBGLR3DECL(int) VbglR3SharedFolderGetMountDir(char **ppszDir); /**< @todo r=bird: GET functions return the value, not a status code! */ +/** @} */ +# endif /* VBOX_WITH_SHARED_FOLDERS defined */ + +# ifdef VBOX_WITH_GUEST_CONTROL +/** @name Guest control + * @{ */ + +/** + * Structure containing the context required for + * either retrieving or sending a HGCM guest control + * commands from or to the host. + * + * @note Do not change parameter order without also adapting all structure + * initializers. + */ +typedef struct VBGLR3GUESTCTRLCMDCTX +{ + /** @todo This struct could be handy if we want to implement + * a second communication channel, e.g. via TCP/IP. + * Use a union for the HGCM stuff then. */ + + /** IN: HGCM client ID to use for communication. */ + uint32_t uClientID; + /** IN/OUT: Context ID to retrieve or to use. */ + uint32_t uContextID; + /** IN: Protocol version to use. */ + uint32_t uProtocol; + /** OUT: Number of parameters retrieved. */ + uint32_t uNumParms; +} VBGLR3GUESTCTRLCMDCTX, *PVBGLR3GUESTCTRLCMDCTX; + +/** + * Structure holding information for starting a guest + * session. + */ +typedef struct VBGLR3GUESTCTRLSESSIONSTARTUPINFO +{ + /** The session's protocol version to use. */ + uint32_t uProtocol; + /** The session's ID. */ + uint32_t uSessionID; + /** User name (account) to start the guest session under. */ + char *pszUser; + /** Size (in bytes) of allocated pszUser. */ + uint32_t cbUser; + /** Password of specified user name (account). */ + char *pszPassword; + /** Size (in bytes) of allocated pszPassword. */ + uint32_t cbPassword; + /** Domain of the user account. */ + char *pszDomain; + /** Size (in bytes) of allocated pszDomain. */ + uint32_t cbDomain; + /** Session creation flags. + * @sa VBOXSERVICECTRLSESSIONSTARTUPFLAG_* flags. */ + uint32_t fFlags; +} VBGLR3GUESTCTRLSESSIONSTARTUPINFO; +/** Pointer to a guest session startup info. */ +typedef VBGLR3GUESTCTRLSESSIONSTARTUPINFO *PVBGLR3GUESTCTRLSESSIONSTARTUPINFO; + +/** + * Structure holding information for starting a guest + * process. + */ +typedef struct VBGLR3GUESTCTRLPROCSTARTUPINFO +{ + /** Full qualified path of process to start (without arguments). + * Note: This is *not* argv[0]! */ + char *pszCmd; + /** Size (in bytes) of allocated pszCmd. */ + uint32_t cbCmd; + /** Process execution flags. @sa */ + uint32_t fFlags; + /** Command line arguments. */ + char *pszArgs; + /** Size (in bytes) of allocated pszArgs. */ + uint32_t cbArgs; + /** Number of arguments specified in pszArgs. */ + uint32_t cArgs; + /** String of environment variables ("FOO=BAR") to pass to the process + * to start. */ + char *pszEnv; + /** Size (in bytes) of environment variables block. */ + uint32_t cbEnv; + /** Number of environment variables specified in pszEnv. */ + uint32_t cEnvVars; + /** User name (account) to start the process under. */ + char *pszUser; + /** Size (in bytes) of allocated pszUser. */ + uint32_t cbUser; + /** Password of specified user name (account). */ + char *pszPassword; + /** Size (in bytes) of allocated pszPassword. */ + uint32_t cbPassword; + /** Domain to be used for authenticating the specified user name (account). */ + char *pszDomain; + /** Size (in bytes) of allocated pszDomain. */ + uint32_t cbDomain; + /** Time limit (in ms) of the process' life time. */ + uint32_t uTimeLimitMS; + /** Process priority. */ + uint32_t uPriority; + /** Process affinity block. At the moment we support + * up to 4 blocks, that is, 4 * 64 = 256 CPUs total. */ + uint64_t uAffinity[4]; + /** Number of used process affinity blocks. */ + uint32_t cAffinity; +} VBGLR3GUESTCTRLPROCSTARTUPINFO; +/** Pointer to a guest process startup info. */ +typedef VBGLR3GUESTCTRLPROCSTARTUPINFO *PVBGLR3GUESTCTRLPROCSTARTUPINFO; + +/* General message handling on the guest. */ +VBGLR3DECL(int) VbglR3GuestCtrlConnect(uint32_t *pidClient); +VBGLR3DECL(int) VbglR3GuestCtrlDisconnect(uint32_t idClient); +VBGLR3DECL(bool) VbglR3GuestCtrlSupportsOptimizations(uint32_t idClient); +VBGLR3DECL(int) VbglR3GuestCtrlMakeMeMaster(uint32_t idClient); +VBGLR3DECL(int) VbglR3GuestCtrlReportFeatures(uint32_t idClient, uint64_t fGuestFeatures, uint64_t *pfHostFeatures); +VBGLR3DECL(int) VbglR3GuestCtrlQueryFeatures(uint32_t idClient, uint64_t *pfHostFeatures); +VBGLR3DECL(int) VbglR3GuestCtrlMsgFilterSet(uint32_t uClientId, uint32_t uValue, uint32_t uMaskAdd, uint32_t uMaskRemove); +VBGLR3DECL(int) VbglR3GuestCtrlMsgReply(PVBGLR3GUESTCTRLCMDCTX pCtx, int rc); +VBGLR3DECL(int) VbglR3GuestCtrlMsgReplyEx(PVBGLR3GUESTCTRLCMDCTX pCtx, int rc, uint32_t uType, + void *pvPayload, uint32_t cbPayload); +VBGLR3DECL(int) VbglR3GuestCtrlMsgSkip(uint32_t idClient, int rcSkip, uint32_t idMsg); +VBGLR3DECL(int) VbglR3GuestCtrlMsgSkipOld(uint32_t uClientId); +VBGLR3DECL(int) VbglR3GuestCtrlMsgPeekWait(uint32_t idClient, uint32_t *pidMsg, uint32_t *pcParameters, uint64_t *pidRestoreCheck); +VBGLR3DECL(int) VbglR3GuestCtrlCancelPendingWaits(HGCMCLIENTID idClient); +/* Guest session handling. */ +VBGLR3DECL(int) VbglR3GuestCtrlSessionStartupInfoInit(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfo); +VBGLR3DECL(int) VbglR3GuestCtrlSessionStartupInfoInitEx(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfo, size_t cbUser, size_t cbPassword, size_t cbDomain); +VBGLR3DECL(void) VbglR3GuestCtrlSessionStartupInfoDestroy(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfo); +VBGLR3DECL(void) VbglR3GuestCtrlSessionStartupInfoFree(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfo); +VBGLR3DECL(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO) VbglR3GuestCtrlSessionStartupInfoDup(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfo); +VBGLR3DECL(int) VbglR3GuestCtrlSessionPrepare(uint32_t idClient, uint32_t idSession, void const *pvKey, uint32_t cbKey); +VBGLR3DECL(int) VbglR3GuestCtrlSessionAccept(uint32_t idClient, uint32_t idSession, void const *pvKey, uint32_t cbKey); +VBGLR3DECL(int) VbglR3GuestCtrlSessionCancelPrepared(uint32_t idClient, uint32_t idSession); +VBGLR3DECL(int) VbglR3GuestCtrlSessionHasChanged(uint32_t idClient, uint64_t idNewControlSession); +VBGLR3DECL(int) VbglR3GuestCtrlSessionClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t fFlags); +VBGLR3DECL(int) VbglR3GuestCtrlSessionNotify(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uType, int32_t iResult); +VBGLR3DECL(int) VbglR3GuestCtrlSessionGetOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, PVBGLR3GUESTCTRLSESSIONSTARTUPINFO *ppStartupInfo); +VBGLR3DECL(int) VbglR3GuestCtrlSessionGetClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *pfFlags, uint32_t *pidSession); +/* Guest path handling. */ +VBGLR3DECL(int) VbglR3GuestCtrlPathGetRename(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszSource, uint32_t cbSource, char *pszDest, + uint32_t cbDest, uint32_t *pfFlags); +VBGLR3DECL(int) VbglR3GuestCtrlPathGetUserDocuments(PVBGLR3GUESTCTRLCMDCTX pCtx); +VBGLR3DECL(int) VbglR3GuestCtrlPathGetUserHome(PVBGLR3GUESTCTRLCMDCTX pCtx); +VBGLR3DECL(int) VbglR3GuestCtrlGetShutdown(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *pfAction); +/* Guest process execution. */ +VBGLR3DECL(int) VbglR3GuestCtrlProcStartupInfoInit(PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo); +VBGLR3DECL(int) VbglR3GuestCtrlProcStartupInfoInitEx(PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo, size_t cbCmd, size_t cbUser, size_t cbPassword, size_t cbDomain, size_t cbArgs, size_t cbEnv); +VBGLR3DECL(void) VbglR3GuestCtrlProcStartupInfoDestroy(PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo); +VBGLR3DECL(void) VbglR3GuestCtrlProcStartupInfoFree(PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo); +VBGLR3DECL(PVBGLR3GUESTCTRLPROCSTARTUPINFO) VbglR3GuestCtrlProcStartupInfoDup(PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo); +VBGLR3DECL(int) VbglR3GuestCtrlProcGetStart(PVBGLR3GUESTCTRLCMDCTX pCtx, PVBGLR3GUESTCTRLPROCSTARTUPINFO *ppStartupInfo); +VBGLR3DECL(int) VbglR3GuestCtrlProcGetTerminate(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puPID); +VBGLR3DECL(int) VbglR3GuestCtrlProcGetInput(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puPID, uint32_t *pfFlags, void *pvData, + uint32_t cbData, uint32_t *pcbSize); +VBGLR3DECL(int) VbglR3GuestCtrlProcGetOutput(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puPID, uint32_t *puHandle, uint32_t *pfFlags); +VBGLR3DECL(int) VbglR3GuestCtrlProcGetWaitFor(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puPID, uint32_t *puWaitFlags, + uint32_t *puTimeoutMS); +/* Guest native directory handling. */ +VBGLR3DECL(int) VbglR3GuestCtrlDirGetRemove(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszPath, uint32_t cbPath, uint32_t *pfFlags); +/* Guest native file handling. */ +VBGLR3DECL(int) VbglR3GuestCtrlFileGetOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszFileName, uint32_t cbFileName, char *pszOpenMode, + uint32_t cbOpenMode, char *pszDisposition, uint32_t cbDisposition, char *pszSharing, + uint32_t cbSharing, uint32_t *puCreationMode, uint64_t *puOffset); +VBGLR3DECL(int) VbglR3GuestCtrlFileGetClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle); +VBGLR3DECL(int) VbglR3GuestCtrlFileGetRead(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, uint32_t *puToRead); +VBGLR3DECL(int) VbglR3GuestCtrlFileGetReadAt(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, + uint32_t *puToRead, uint64_t *poffRead); +VBGLR3DECL(int) VbglR3GuestCtrlFileGetWrite(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, + void *pvData, uint32_t cbData, uint32_t *pcbActual); +VBGLR3DECL(int) VbglR3GuestCtrlFileGetWriteAt(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, void *pvData, uint32_t cbData, + uint32_t *pcbActual, uint64_t *poffWrite); +VBGLR3DECL(int) VbglR3GuestCtrlFileGetSeek(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, + uint32_t *puSeekMethod, uint64_t *poffSeek); +VBGLR3DECL(int) VbglR3GuestCtrlFileGetTell(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle); +VBGLR3DECL(int) VbglR3GuestCtrlFileGetSetSize(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, uint64_t *pcbNew); + +/* Guest -> Host. */ +VBGLR3DECL(int) VbglR3GuestCtrlFileCbOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint32_t uFileHandle); +VBGLR3DECL(int) VbglR3GuestCtrlFileCbClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc); +VBGLR3DECL(int) VbglR3GuestCtrlFileCbError(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc); +VBGLR3DECL(int) VbglR3GuestCtrlFileCbRead(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, void *pvData, uint32_t cbData); +VBGLR3DECL(int) VbglR3GuestCtrlFileCbReadOffset(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, + void *pvData, uint32_t cbData, int64_t offNew); +VBGLR3DECL(int) VbglR3GuestCtrlFileCbWrite(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint32_t cbWritten); +VBGLR3DECL(int) VbglR3GuestCtrlFileCbWriteOffset(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint32_t cbWritten, int64_t offNew); + +VBGLR3DECL(int) VbglR3GuestCtrlFileCbSeek(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint64_t offCurrent); +VBGLR3DECL(int) VbglR3GuestCtrlFileCbTell(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint64_t offCurrent); +VBGLR3DECL(int) VbglR3GuestCtrlFileCbSetSize(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint64_t cbNew); +VBGLR3DECL(int) VbglR3GuestCtrlProcCbStatus(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uPID, uint32_t uStatus, uint32_t fFlags, + void *pvData, uint32_t cbData); +VBGLR3DECL(int) VbglR3GuestCtrlProcCbOutput(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uPID, uint32_t uHandle, uint32_t fFlags, + void *pvData, uint32_t cbData); +VBGLR3DECL(int) VbglR3GuestCtrlProcCbStatusInput(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t u32PID, uint32_t uStatus, + uint32_t fFlags, uint32_t cbWritten); + +/** @} */ +# endif /* VBOX_WITH_GUEST_CONTROL defined */ + +/** @name Auto-logon handling + * @{ */ +VBGLR3DECL(int) VbglR3AutoLogonReportStatus(VBoxGuestFacilityStatus enmStatus); +VBGLR3DECL(bool) VbglR3AutoLogonIsRemoteSession(void); +/** @} */ + +/** @name User credentials handling + * @{ */ +VBGLR3DECL(int) VbglR3CredentialsQueryAvailability(void); +VBGLR3DECL(int) VbglR3CredentialsRetrieve(char **ppszUser, char **ppszPassword, char **ppszDomain); +VBGLR3DECL(int) VbglR3CredentialsRetrieveUtf16(PRTUTF16 *ppwszUser, PRTUTF16 *ppwszPassword, PRTUTF16 *ppwszDomain); +VBGLR3DECL(void) VbglR3CredentialsDestroy(char *pszUser, char *pszPassword, char *pszDomain, uint32_t cPasses); +VBGLR3DECL(void) VbglR3CredentialsDestroyUtf16(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszDomain, + uint32_t cPasses); +/** @} */ + +/** @name CPU hotplug monitor + * @{ */ +VBGLR3DECL(int) VbglR3CpuHotPlugInit(void); +VBGLR3DECL(int) VbglR3CpuHotPlugTerm(void); +VBGLR3DECL(int) VbglR3CpuHotPlugWaitForEvent(VMMDevCpuEventType *penmEventType, uint32_t *pidCpuCore, uint32_t *pidCpuPackage); +/** @} */ + +/** @name Page sharing + * @{ */ +struct VMMDEVSHAREDREGIONDESC; +VBGLR3DECL(int) VbglR3RegisterSharedModule(char *pszModuleName, char *pszVersion, RTGCPTR64 GCBaseAddr, uint32_t cbModule, + unsigned cRegions, struct VMMDEVSHAREDREGIONDESC *pRegions); +VBGLR3DECL(int) VbglR3UnregisterSharedModule(char *pszModuleName, char *pszVersion, RTGCPTR64 GCBaseAddr, uint32_t cbModule); +VBGLR3DECL(int) VbglR3CheckSharedModules(void); +VBGLR3DECL(bool) VbglR3PageSharingIsEnabled(void); +VBGLR3DECL(int) VbglR3PageIsShared(RTGCPTR pPage, bool *pfShared, uint64_t *puPageFlags); +/** @} */ + +# ifdef VBOX_WITH_DRAG_AND_DROP +/** @name Drag and Drop + * @{ */ +/** + * Structure containing the context required for + * either retrieving or sending a HGCM guest drag'n drop + * commands from or to the host. + * + * Note: Do not change parameter order without also + * adapting all structure initializers. + */ +typedef struct VBGLR3GUESTDNDCMDCTX +{ + /** @todo This struct could be handy if we want to implement + * a second communication channel, e.g. via TCP/IP. + * Use a union for the HGCM stuff then. */ + + /** HGCM client ID to use for communication. */ + uint32_t uClientID; + /** The VM's current session ID. */ + uint64_t uSessionID; + /** Protocol version to use. + * Deprecated; do not used / rely on it anymore. */ + uint32_t uProtocolDeprecated; + /** Host feature flags (VBOX_DND_HF_XXX). + * This is set by VbglR3DnDConnect(). */ + uint64_t fHostFeatures; + /** The guest feature flags reported to the host (VBOX_DND_GF_XXX). + * This is set by VbglR3DnDConnect(). */ + uint64_t fGuestFeatures; + /** Number of parameters retrieved for the current command. */ + uint32_t uNumParms; + /** Max chunk size (in bytes) for data transfers. */ + uint32_t cbMaxChunkSize; +} VBGLR3GUESTDNDCMDCTX, *PVBGLR3GUESTDNDCMDCTX; + +/** + * Enumeration for specifying the DnD meta data type. + */ +typedef enum VBGLR3GUESTDNDMETADATATYPE +{ + /** Unknown meta data type; don't use. */ + VBGLR3GUESTDNDMETADATATYPE_UNKNOWN = 0, + /** Raw meta data; can be everything. */ + VBGLR3GUESTDNDMETADATATYPE_RAW, + /** Meta data is a transfer list, specifying objects. */ + VBGLR3GUESTDNDMETADATATYPE_URI_LIST, + /** Blow the type up to 32-bit. */ + VBGLR3GUESTDNDMETADATATYPE_32BIT_HACK = 0x7fffffff +} VBGLR3GUESTDNDMETADATATYPE; + +/** + * Structure for keeping + handling DnD meta data. + */ +typedef struct VBGLR3GUESTDNDMETADATA +{ + /** The meta data type the union contains. */ + VBGLR3GUESTDNDMETADATATYPE enmType; + /** Union based on \a enmType. */ + union + { + struct + { + /** Pointer to actual meta data. */ + void *pvMeta; + /** Size (in bytes) of meta data. */ + uint32_t cbMeta; + } Raw; + struct + { + DNDTRANSFERLIST Transfer; + } URI; + } u; +} VBGLR3GUESTDNDMETADATA; + +/** Pointer to VBGLR3GUESTDNDMETADATA. */ +typedef VBGLR3GUESTDNDMETADATA *PVBGLR3GUESTDNDMETADATA; + +/** Const pointer to VBGLR3GUESTDNDMETADATA. */ +typedef const PVBGLR3GUESTDNDMETADATA CPVBGLR3GUESTDNDMETADATA; + +/** + * Enumeration specifying a DnD event type. + */ +typedef enum VBGLR3DNDEVENTTYPE +{ + VBGLR3DNDEVENTTYPE_INVALID = 0, + VBGLR3DNDEVENTTYPE_CANCEL, + VBGLR3DNDEVENTTYPE_HG_ERROR, + VBGLR3DNDEVENTTYPE_HG_ENTER, + VBGLR3DNDEVENTTYPE_HG_MOVE, + VBGLR3DNDEVENTTYPE_HG_LEAVE, + VBGLR3DNDEVENTTYPE_HG_DROP, + VBGLR3DNDEVENTTYPE_HG_RECEIVE, +# ifdef VBOX_WITH_DRAG_AND_DROP_GH + VBGLR3DNDEVENTTYPE_GH_ERROR, + VBGLR3DNDEVENTTYPE_GH_REQ_PENDING, + VBGLR3DNDEVENTTYPE_GH_DROP, +# endif + /** Tells the caller that it has to quit operation. */ + VBGLR3DNDEVENTTYPE_QUIT, + /** Blow the type up to 32-bit. */ + VBGLR3DNDEVENTTYPE_32BIT_HACK = 0x7fffffff +} VBGLR3DNDEVENTTYPE; + +typedef struct VBGLR3DNDEVENT +{ + /** The event type the union contains. */ + VBGLR3DNDEVENTTYPE enmType; + union + { + struct + { + /** Screen ID this request belongs to. */ + uint32_t uScreenID; + /** Format list (UTF-8, \r\n separated). */ + char *pszFormats; + /** Size (in bytes) of pszFormats (\0 included). */ + uint32_t cbFormats; + /** List of allowed DnD actions. */ + VBOXDNDACTIONLIST dndLstActionsAllowed; + } HG_Enter; + struct + { + /** Absolute X position of guest screen. */ + uint32_t uXpos; + /** Absolute Y position of guest screen. */ + uint32_t uYpos; + /** Default DnD action. */ + VBOXDNDACTION dndActionDefault; + } HG_Move; + struct + { + /** Absolute X position of guest screen. */ + uint32_t uXpos; + /** Absolute Y position of guest screen. */ + uint32_t uYpos; + /** Default DnD action. */ + VBOXDNDACTION dndActionDefault; + } HG_Drop; + struct + { + /** Meta data for the operation. */ + VBGLR3GUESTDNDMETADATA Meta; + } HG_Received; + struct + { + /** IPRT-style error code. */ + int rc; + } HG_Error; +# ifdef VBOX_WITH_DRAG_AND_DROP_GH + struct + { + /** Screen ID this request belongs to. */ + uint32_t uScreenID; + } GH_IsPending; + struct + { + /** Requested format by the host. */ + char *pszFormat; + /** Size (in bytes) of pszFormat (\0 included). */ + uint32_t cbFormat; + /** Requested DnD action. */ + VBOXDNDACTION dndActionRequested; + } GH_Drop; +# endif + } u; +} VBGLR3DNDEVENT; +typedef VBGLR3DNDEVENT *PVBGLR3DNDEVENT; +typedef const PVBGLR3DNDEVENT CPVBGLR3DNDEVENT; + +VBGLR3DECL(int) VbglR3DnDConnect(PVBGLR3GUESTDNDCMDCTX pCtx); +VBGLR3DECL(int) VbglR3DnDDisconnect(PVBGLR3GUESTDNDCMDCTX pCtx); + +VBGLR3DECL(int) VbglR3DnDReportFeatures(uint32_t idClient, uint64_t fGuestFeatures, uint64_t *pfHostFeatures); +VBGLR3DECL(int) VbglR3DnDSendError(PVBGLR3GUESTDNDCMDCTX pCtx, int rcOp); + +VBGLR3DECL(int) VbglR3DnDEventGetNext(PVBGLR3GUESTDNDCMDCTX pCtx, PVBGLR3DNDEVENT *ppEvent); +VBGLR3DECL(void) VbglR3DnDEventFree(PVBGLR3DNDEVENT pEvent); + +VBGLR3DECL(int) VbglR3DnDHGSendAckOp(PVBGLR3GUESTDNDCMDCTX pCtx, VBOXDNDACTION dndAction); +VBGLR3DECL(int) VbglR3DnDHGSendReqData(PVBGLR3GUESTDNDCMDCTX pCtx, const char *pcszFormat); +VBGLR3DECL(int) VbglR3DnDHGSendProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr); +# ifdef VBOX_WITH_DRAG_AND_DROP_GH +VBGLR3DECL(int) VbglR3DnDGHSendAckPending(PVBGLR3GUESTDNDCMDCTX pCtx, VBOXDNDACTION dndActionDefault, VBOXDNDACTIONLIST dndLstActionsAllowed, const char* pcszFormats, uint32_t cbFormats); +VBGLR3DECL(int) VbglR3DnDGHSendData(PVBGLR3GUESTDNDCMDCTX pCtx, const char *pszFormat, void *pvData, uint32_t cbData); +# endif /* VBOX_WITH_DRAG_AND_DROP_GH */ +/** @} */ +# endif /* VBOX_WITH_DRAG_AND_DROP */ + +/* Generic Host Channel Service. */ +VBGLR3DECL(int) VbglR3HostChannelInit(uint32_t *pidClient); +VBGLR3DECL(void) VbglR3HostChannelTerm(uint32_t idClient); +VBGLR3DECL(int) VbglR3HostChannelAttach(uint32_t *pu32ChannelHandle, uint32_t u32HGCMClientId, + const char *pszName, uint32_t u32Flags); +VBGLR3DECL(void) VbglR3HostChannelDetach(uint32_t u32ChannelHandle, uint32_t u32HGCMClientId); +VBGLR3DECL(int) VbglR3HostChannelSend(uint32_t u32ChannelHandle, uint32_t u32HGCMClientId, + void *pvData, uint32_t cbData); +VBGLR3DECL(int) VbglR3HostChannelRecv(uint32_t u32ChannelHandle, uint32_t u32HGCMClientId, + void *pvData, uint32_t cbData, + uint32_t *pu32SizeReceived, uint32_t *pu32SizeRemaining); +VBGLR3DECL(int) VbglR3HostChannelControl(uint32_t u32ChannelHandle, uint32_t u32HGCMClientId, + uint32_t u32Code, void *pvParm, uint32_t cbParm, + void *pvData, uint32_t cbData, uint32_t *pu32SizeDataReturned); +VBGLR3DECL(int) VbglR3HostChannelEventWait(uint32_t *pu32ChannelHandle, uint32_t u32HGCMClientId, + uint32_t *pu32EventId, void *pvParm, uint32_t cbParm, + uint32_t *pu32SizeReturned); +VBGLR3DECL(int) VbglR3HostChannelEventCancel(uint32_t u32ChannelHandle, uint32_t u32HGCMClientId); +VBGLR3DECL(int) VbglR3HostChannelQuery(const char *pszName, uint32_t u32HGCMClientId, uint32_t u32Code, + void *pvParm, uint32_t cbParm, void *pvData, uint32_t cbData, + uint32_t *pu32SizeDataReturned); + +/** @name Mode hint storage + * @{ */ +VBGLR3DECL(int) VbglR3ReadVideoMode(unsigned cDisplay, unsigned *cx, + unsigned *cy, unsigned *cBPP, unsigned *x, + unsigned *y, unsigned *fEnabled); +VBGLR3DECL(int) VbglR3WriteVideoMode(unsigned cDisplay, unsigned cx, + unsigned cy, unsigned cBPP, unsigned x, + unsigned y, unsigned fEnabled); +/** @} */ + +/** @name Generic HGCM + * @{ */ +VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient); +VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient); +struct VBGLIOCHGCMCALL; +VBGLR3DECL(int) VbglR3HGCMCall(struct VBGLIOCHGCMCALL *pInfo, size_t cbInfo); +/** @} */ + +#endif /* IN_RING3 */ +/** @} */ + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_VBoxGuestLib_h */ diff --git a/include/VBox/VBoxGuestLibSharedFolders.h b/include/VBox/VBoxGuestLibSharedFolders.h new file mode 100644 index 00000000..c227cc39 --- /dev/null +++ b/include/VBox/VBoxGuestLibSharedFolders.h @@ -0,0 +1,131 @@ +/* $Id: VBoxGuestLibSharedFolders.h $ */ +/** @file + * VBoxGuestLib - Central calls header. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_VBoxGuestLibSharedFolders_h +#define VBOX_INCLUDED_VBoxGuestLibSharedFolders_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/VBoxGuestLib.h> +#include <VBox/shflsvc.h> + +#ifndef IN_RING0 +# error "ring-0 only" +#endif + +RT_C_DECLS_BEGIN + + +/** @addtogroup grp_vboxguest_lib_r0 + * @{ + */ + +typedef struct VBGLSFCLIENT +{ + HGCMCLIENTID idClient; + VBGLHGCMHANDLE handle; +} VBGLSFCLIENT; +typedef VBGLSFCLIENT *PVBGLSFCLIENT; + +typedef struct VBGLSFMAP +{ + SHFLROOT root; +} VBGLSFMAP, *PVBGLSFMAP; + +DECLVBGL(int) VbglR0SfInit(void); +DECLVBGL(void) VbglR0SfTerm(void); +DECLVBGL(int) VbglR0SfConnect(PVBGLSFCLIENT pClient); +DECLVBGL(void) VbglR0SfDisconnect(PVBGLSFCLIENT pClient); + +DECLVBGL(int) VbglR0SfQueryMappings(PVBGLSFCLIENT pClient, SHFLMAPPING paMappings[], uint32_t *pcMappings); + +DECLVBGL(int) VbglR0SfQueryMapName(PVBGLSFCLIENT pClient, SHFLROOT root, SHFLSTRING *pString, uint32_t size); + +/** + * Create a new file or folder or open an existing one in a shared folder. Proxies + * to vbsfCreate in the host shared folder service. + * + * @returns IPRT status code, but see note below + * @param pClient Host-guest communication connection + * @param pMap The mapping for the shared folder in which the file + * or folder is to be created + * @param pParsedPath The path of the file or folder relative to the shared + * folder + * @param pCreateParms Parameters for file/folder creation. See the + * structure description in shflsvc.h + * @retval pCreateParms See the structure description in shflsvc.h + * + * @note This function reports errors as follows. The return value is always + * VINF_SUCCESS unless an exceptional condition occurs - out of + * memory, invalid arguments, etc. If the file or folder could not be + * opened or created, pCreateParms->Handle will be set to + * SHFL_HANDLE_NIL on return. In this case the value in + * pCreateParms->Result provides information as to why (e.g. + * SHFL_FILE_EXISTS). pCreateParms->Result is also set on success + * as additional information. + */ +DECLVBGL(int) VbglR0SfCreate(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, PSHFLSTRING pParsedPath, PSHFLCREATEPARMS pCreateParms); + +DECLVBGL(int) VbglR0SfClose(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE Handle); +DECLVBGL(int) VbglR0SfRemove(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, PSHFLSTRING pParsedPath, uint32_t flags); +DECLVBGL(int) VbglR0SfRename(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, PSHFLSTRING pSrcPath, PSHFLSTRING pDestPath, uint32_t flags); +DECLVBGL(int) VbglR0SfFlush(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile); + +DECLVBGL(int) VbglR0SfRead(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer, bool fLocked); +DECLVBGL(int) VbglR0SfReadPageList(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint32_t *pcbBuffer, + uint16_t offFirstPage, uint16_t cPages, RTGCPHYS64 *paPages); +DECLVBGL(int) VbglR0SfWrite(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, + uint32_t *pcbBuffer, uint8_t *pBuffer, bool fLocked); +DECLVBGL(int) VbglR0SfWritePhysCont(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, + uint32_t *pcbBuffer, RTCCPHYS PhysBuffer); +DECLVBGL(int) VbglR0SfWritePageList(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint32_t *pcbBuffer, + uint16_t offFirstPage, uint16_t cPages, RTGCPHYS64 *paPages); + +DECLVBGL(int) VbglR0SfLock(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint64_t cbSize, uint32_t fLock); + +DECLVBGL(int) VbglR0SfDirInfo(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile,PSHFLSTRING ParsedPath, uint32_t flags, + uint32_t index, uint32_t *pcbBuffer, PSHFLDIRINFO pBuffer, uint32_t *pcFiles); +DECLVBGL(int) VbglR0SfFsInfo(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint32_t flags, uint32_t *pcbBuffer, PSHFLDIRINFO pBuffer); + +DECLVBGL(int) VbglR0SfMapFolder(PVBGLSFCLIENT pClient, PSHFLSTRING szFolderName, PVBGLSFMAP pMap); +DECLVBGL(int) VbglR0SfUnmapFolder(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap); +DECLVBGL(int) VbglR0SfSetUtf8(PVBGLSFCLIENT pClient); + +DECLVBGL(int) VbglR0SfReadLink(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, PSHFLSTRING ParsedPath, uint32_t pcbBuffer, uint8_t *pBuffer); +DECLVBGL(int) VbglR0SfSymlink(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, PSHFLSTRING pNewPath, PSHFLSTRING pOldPath, PSHFLFSOBJINFO pBuffer); +DECLVBGL(int) VbglR0SfSetSymlinks(PVBGLSFCLIENT pClient); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_VBoxGuestLibSharedFolders_h */ + diff --git a/include/VBox/VBoxGuestLibSharedFoldersInline.h b/include/VBox/VBoxGuestLibSharedFoldersInline.h new file mode 100644 index 00000000..7d67ffea --- /dev/null +++ b/include/VBox/VBoxGuestLibSharedFoldersInline.h @@ -0,0 +1,1612 @@ +/* $Id: VBoxGuestLibSharedFoldersInline.h $ */ +/** @file + * VBoxGuestLib - Shared Folders Host Request Helpers (ring-0). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_VBoxGuestLibSharedFoldersInline_h +#define VBOX_INCLUDED_VBoxGuestLibSharedFoldersInline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assert.h> +#include <VBox/VBoxGuest.h> +#include <VBox/VBoxGuestLib.h> +#include <VBox/VBoxGuestLibSharedFolders.h> +#include <VBox/VMMDev.h> +#include <VBox/shflsvc.h> +#include <iprt/err.h> + + +/** @defgroup grp_vboxguest_lib_r0_sf_inline Shared Folders Host Request Helpers + * @ingroup grp_vboxguest_lib_r0 + * + * @note Using inline functions to avoid wasting precious ring-0 stack space on + * passing parameters that ends up in the structure @a pReq points to. It + * is also safe to assume that it's faster too. It's worth a few bytes + * larger code section in the resulting shared folders driver. + * + * @note This currently requires a C++ compiler or a C compiler capable of + * mixing code and variables (i.e. C99). + * + * @{ + */ + +/** VMMDEV_HVF_XXX (set during init). */ +extern uint32_t g_fHostFeatures; +extern VBGLSFCLIENT g_SfClient; /**< Move this into the parameters? */ + +/** Request structure for VbglR0SfHostReqQueryFeatures. */ +typedef struct VBOXSFQUERYFEATURES +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmQueryFeatures Parms; +} VBOXSFQUERYFEATURES; + +/** + * SHFL_FN_QUERY_FEATURES request. + */ +DECLINLINE(int) VbglR0SfHostReqQueryFeatures(VBOXSFQUERYFEATURES *pReq) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_QUERY_FEATURES, SHFL_CPARMS_QUERY_FEATURES, sizeof(*pReq)); + + pReq->Parms.f64Features.type = VMMDevHGCMParmType_64bit; + pReq->Parms.f64Features.u.value64 = 0; + + pReq->Parms.u32LastFunction.type = VMMDevHGCMParmType_32bit; + pReq->Parms.u32LastFunction.u.value32 = 0; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + + /* + * Provide fallback values based on g_fHostFeatures to simplify + * compatibility with older hosts and avoid duplicating this logic. + */ + if (RT_FAILURE(vrc)) + { + pReq->Parms.f64Features.u.value64 = 0; + pReq->Parms.u32LastFunction.u.value32 = g_fHostFeatures & VMMDEV_HVF_HGCM_NO_BOUNCE_PAGE_LIST + ? SHFL_FN_SET_FILE_SIZE : SHFL_FN_SET_SYMLINKS; + if (vrc == VERR_NOT_SUPPORTED) + vrc = VINF_NOT_SUPPORTED; + } + return vrc; +} + +/** + * SHFL_FN_QUERY_FEATURES request, simplified version. + */ +DECLINLINE(int) VbglR0SfHostReqQueryFeaturesSimple(uint64_t *pfFeatures, uint32_t *puLastFunction) +{ + VBOXSFQUERYFEATURES *pReq = (VBOXSFQUERYFEATURES *)VbglR0PhysHeapAlloc(sizeof(*pReq)); + if (pReq) + { + int rc = VbglR0SfHostReqQueryFeatures(pReq); + if (pfFeatures) + *pfFeatures = pReq->Parms.f64Features.u.value64; + if (puLastFunction) + *puLastFunction = pReq->Parms.u32LastFunction.u.value32; + + VbglR0PhysHeapFree(pReq); + return rc; + } + return VERR_NO_MEMORY; +} + + +/** Request structure for VbglR0SfHostReqSetUtf8 and VbglR0SfHostReqSetSymlink. */ +typedef struct VBOXSFNOPARMS +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + /* no parameters */ +} VBOXSFNOPARMS; + +/** + * Worker for request without any parameters. + */ +DECLINLINE(int) VbglR0SfHostReqNoParms(VBOXSFNOPARMS *pReq, uint32_t uFunction, uint32_t cParms) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + uFunction, cParms, sizeof(*pReq)); + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** + * Worker for request without any parameters, simplified. + */ +DECLINLINE(int) VbglR0SfHostReqNoParmsSimple(uint32_t uFunction, uint32_t cParms) +{ + VBOXSFNOPARMS *pReq = (VBOXSFNOPARMS *)VbglR0PhysHeapAlloc(sizeof(*pReq)); + if (pReq) + { + int vrc = VbglR0SfHostReqNoParms(pReq, uFunction, cParms); + VbglR0PhysHeapFree(pReq); + return vrc; + } + return VERR_NO_MEMORY; +} + + +/** + * SHFL_F_SET_UTF8 request. + */ +DECLINLINE(int) VbglR0SfHostReqSetUtf8(VBOXSFNOPARMS *pReq) +{ + return VbglR0SfHostReqNoParms(pReq, SHFL_FN_SET_UTF8, SHFL_CPARMS_SET_UTF8); +} + +/** + * SHFL_F_SET_UTF8 request, simplified version. + */ +DECLINLINE(int) VbglR0SfHostReqSetUtf8Simple(void) +{ + return VbglR0SfHostReqNoParmsSimple(SHFL_FN_SET_UTF8, SHFL_CPARMS_SET_UTF8); +} + + +/** + * SHFL_F_SET_SYMLINKS request. + */ +DECLINLINE(int) VbglR0SfHostReqSetSymlinks(VBOXSFNOPARMS *pReq) +{ + return VbglR0SfHostReqNoParms(pReq, SHFL_FN_SET_SYMLINKS, SHFL_CPARMS_SET_SYMLINKS); +} + +/** + * SHFL_F_SET_SYMLINKS request, simplified version. + */ +DECLINLINE(int) VbglR0SfHostReqSetSymlinksSimple(void) +{ + return VbglR0SfHostReqNoParmsSimple(SHFL_FN_SET_SYMLINKS, SHFL_CPARMS_SET_SYMLINKS); +} + + +/** Request structure for VbglR0SfHostReqSetErrorStyle. */ +typedef struct VBOXSFSETERRORSTYLE +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmSetErrorStyle Parms; +} VBOXSFSETERRORSTYLE; + +/** + * SHFL_FN_QUERY_FEATURES request. + */ +DECLINLINE(int) VbglR0SfHostReqSetErrorStyle(VBOXSFSETERRORSTYLE *pReq, SHFLERRORSTYLE enmStyle) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_SET_ERROR_STYLE, SHFL_CPARMS_SET_ERROR_STYLE, sizeof(*pReq)); + + pReq->Parms.u32Style.type = VMMDevHGCMParmType_32bit; + pReq->Parms.u32Style.u.value32 = (uint32_t)enmStyle; + + pReq->Parms.u32Reserved.type = VMMDevHGCMParmType_32bit; + pReq->Parms.u32Reserved.u.value32 = 0; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** + * SHFL_FN_QUERY_FEATURES request, simplified version. + */ +DECLINLINE(int) VbglR0SfHostReqSetErrorStyleSimple(SHFLERRORSTYLE enmStyle) +{ + VBOXSFSETERRORSTYLE *pReq = (VBOXSFSETERRORSTYLE *)VbglR0PhysHeapAlloc(sizeof(*pReq)); + if (pReq) + { + int rc = VbglR0SfHostReqSetErrorStyle(pReq, enmStyle); + VbglR0PhysHeapFree(pReq); + return rc; + } + return VERR_NO_MEMORY; +} + + +/** Request structure for VbglR0SfHostReqMapFolderWithBuf. */ +typedef struct VBOXSFMAPFOLDERWITHBUFREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmMapFolder Parms; + HGCMPageListInfo PgLst; +} VBOXSFMAPFOLDERWITHBUFREQ; + + +/** + * SHFL_FN_MAP_FOLDER request. + */ +DECLINLINE(int) VbglR0SfHostReqMapFolderWithContig(VBOXSFMAPFOLDERWITHBUFREQ *pReq, PSHFLSTRING pStrName, RTGCPHYS64 PhysStrName, + RTUTF16 wcDelimiter, bool fCaseSensitive) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_MAP_FOLDER, SHFL_CPARMS_MAP_FOLDER, sizeof(*pReq)); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = SHFL_ROOT_NIL; + + pReq->Parms.uc32Delimiter.type = VMMDevHGCMParmType_32bit; + pReq->Parms.uc32Delimiter.u.value32 = wcDelimiter; + + pReq->Parms.fCaseSensitive.type = VMMDevHGCMParmType_32bit; + pReq->Parms.fCaseSensitive.u.value32 = fCaseSensitive; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST) + { + pReq->Parms.pStrName.type = VMMDevHGCMParmType_PageList; + pReq->Parms.pStrName.u.PageList.size = SHFLSTRING_HEADER_SIZE + pStrName->u16Size; + pReq->Parms.pStrName.u.PageList.offset = RT_UOFFSETOF(VBOXSFMAPFOLDERWITHBUFREQ, PgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_BOTH; + pReq->PgLst.offFirstPage = (uint16_t)PhysStrName & (uint16_t)(PAGE_OFFSET_MASK); + pReq->PgLst.aPages[0] = PhysStrName & ~(RTGCPHYS64)PAGE_OFFSET_MASK; + pReq->PgLst.cPages = 1; + } + else + { + pReq->Parms.pStrName.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrName.u.LinAddr.cb = SHFLSTRING_HEADER_SIZE + pStrName->u16Size; + pReq->Parms.pStrName.u.LinAddr.uAddr = (uintptr_t)pStrName; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** + * SHFL_FN_MAP_FOLDER request. + */ +DECLINLINE(int) VbglR0SfHostReqMapFolderWithContigSimple(PSHFLSTRING pStrName, RTGCPHYS64 PhysStrName, + RTUTF16 wcDelimiter, bool fCaseSensitive, SHFLROOT *pidRoot) +{ + VBOXSFMAPFOLDERWITHBUFREQ *pReq = (VBOXSFMAPFOLDERWITHBUFREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq)); + if (pReq) + { + int rc = VbglR0SfHostReqMapFolderWithContig(pReq, pStrName, PhysStrName, wcDelimiter, fCaseSensitive); + *pidRoot = RT_SUCCESS(rc) ? pReq->Parms.id32Root.u.value32 : SHFL_ROOT_NIL; + VbglR0PhysHeapFree(pReq); + return rc; + } + *pidRoot = SHFL_ROOT_NIL; + return VERR_NO_MEMORY; +} + + +/** + * SHFL_FN_MAP_FOLDER request. + */ +DECLINLINE(int) VbglR0SfHostReqMapFolderWithBuf(VBOXSFMAPFOLDERWITHBUFREQ *pReq, PSHFLSTRING pStrName, + RTUTF16 wcDelimiter, bool fCaseSensitive) +{ + return VbglR0SfHostReqMapFolderWithContig(pReq, pStrName, VbglR0PhysHeapGetPhysAddr(pStrName), wcDelimiter, fCaseSensitive); +} + + + +/** Request structure used by vboxSfOs2HostReqUnmapFolder. */ +typedef struct VBOXSFUNMAPFOLDERREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmUnmapFolder Parms; +} VBOXSFUNMAPFOLDERREQ; + + +/** + * SHFL_FN_UNMAP_FOLDER request. + */ +DECLINLINE(int) VbglR0SfHostReqUnmapFolderSimple(uint32_t idRoot) +{ + VBOXSFUNMAPFOLDERREQ *pReq = (VBOXSFUNMAPFOLDERREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq)); + if (pReq) + { + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_UNMAP_FOLDER, SHFL_CPARMS_UNMAP_FOLDER, sizeof(*pReq)); + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + + VbglR0PhysHeapFree(pReq); + return vrc; + } + return VERR_NO_MEMORY; +} + + +/** Request structure for VbglR0SfHostReqCreate. */ +typedef struct VBOXSFCREATEREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmCreate Parms; + SHFLCREATEPARMS CreateParms; + SHFLSTRING StrPath; +} VBOXSFCREATEREQ; + +/** + * SHFL_FN_CREATE request. + */ +DECLINLINE(int) VbglR0SfHostReqCreate(SHFLROOT idRoot, VBOXSFCREATEREQ *pReq) +{ + uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS + ? RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String) + pReq->StrPath.u16Size + : RT_UOFFSETOF(VBOXSFCREATEREQ, CreateParms); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_CREATE, SHFL_CPARMS_CREATE, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pStrPath.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pStrPath.u.Embedded.cbData = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size; + pReq->Parms.pStrPath.u.Embedded.offData = RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pStrPath.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + + pReq->Parms.pCreateParms.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pCreateParms.u.Embedded.cbData = sizeof(pReq->CreateParms); + pReq->Parms.pCreateParms.u.Embedded.offData = RT_UOFFSETOF(VBOXSFCREATEREQ, CreateParms) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pCreateParms.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_BOTH; + } + else + { + pReq->Parms.pStrPath.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrPath.u.LinAddr.cb = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size; + pReq->Parms.pStrPath.u.LinAddr.uAddr = (uintptr_t)&pReq->StrPath; + + pReq->Parms.pCreateParms.type = VMMDevHGCMParmType_LinAddr; + pReq->Parms.pCreateParms.u.LinAddr.cb = sizeof(pReq->CreateParms); + pReq->Parms.pCreateParms.u.LinAddr.uAddr = (uintptr_t)&pReq->CreateParms; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for VbglR0SfHostReqClose. */ +typedef struct VBOXSFCLOSEREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmClose Parms; +} VBOXSFCLOSEREQ; + +/** + * SHFL_FN_CLOSE request. + */ +DECLINLINE(int) VbglR0SfHostReqClose(SHFLROOT idRoot, VBOXSFCLOSEREQ *pReq, uint64_t hHostFile) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_CLOSE, SHFL_CPARMS_CLOSE, sizeof(*pReq)); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** + * SHFL_FN_CLOSE request, allocate request buffer. + */ +DECLINLINE(int) VbglR0SfHostReqCloseSimple(SHFLROOT idRoot, uint64_t hHostFile) +{ + VBOXSFCLOSEREQ *pReq = (VBOXSFCLOSEREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq)); + if (pReq) + { + int vrc = VbglR0SfHostReqClose(idRoot, pReq, hHostFile); + VbglR0PhysHeapFree(pReq); + return vrc; + } + return VERR_NO_MEMORY; +} + + +/** Request structure for VbglR0SfHostReqQueryVolInfo. */ +typedef struct VBOXSFVOLINFOREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmInformation Parms; + SHFLVOLINFO VolInfo; +} VBOXSFVOLINFOREQ; + +/** + * SHFL_FN_INFORMATION[SHFL_INFO_VOLUME | SHFL_INFO_GET] request. + */ +DECLINLINE(int) VbglR0SfHostReqQueryVolInfo(SHFLROOT idRoot, VBOXSFVOLINFOREQ *pReq, uint64_t hHostFile) +{ + uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS + ? sizeof(*pReq) : RT_UOFFSETOF(VBOXSFVOLINFOREQ, VolInfo); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = SHFL_INFO_VOLUME | SHFL_INFO_GET; + + pReq->Parms.cb32.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32.u.value32 = sizeof(pReq->VolInfo); + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pInfo.u.Embedded.cbData = sizeof(pReq->VolInfo); + pReq->Parms.pInfo.u.Embedded.offData = RT_UOFFSETOF(VBOXSFVOLINFOREQ, VolInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pInfo.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; + } + else + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_LinAddr_Out; + pReq->Parms.pInfo.u.LinAddr.cb = sizeof(pReq->VolInfo); + pReq->Parms.pInfo.u.LinAddr.uAddr = (uintptr_t)&pReq->VolInfo; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for VbglR0SfHostReqSetObjInfo & VbglR0SfHostReqQueryObjInfo. */ +typedef struct VBOXSFOBJINFOREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmInformation Parms; + SHFLFSOBJINFO ObjInfo; +} VBOXSFOBJINFOREQ; + +/** + * SHFL_FN_INFORMATION[SHFL_INFO_GET | SHFL_INFO_FILE] request. + */ +DECLINLINE(int) VbglR0SfHostReqQueryObjInfo(SHFLROOT idRoot, VBOXSFOBJINFOREQ *pReq, uint64_t hHostFile) +{ + uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS + ? sizeof(*pReq) : RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = SHFL_INFO_GET | SHFL_INFO_FILE; + + pReq->Parms.cb32.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32.u.value32 = sizeof(pReq->ObjInfo); + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pInfo.u.Embedded.cbData = sizeof(pReq->ObjInfo); + pReq->Parms.pInfo.u.Embedded.offData = RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pInfo.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; + } + else + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_LinAddr_Out; + pReq->Parms.pInfo.u.LinAddr.cb = sizeof(pReq->ObjInfo); + pReq->Parms.pInfo.u.LinAddr.uAddr = (uintptr_t)&pReq->ObjInfo; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** + * SHFL_FN_INFORMATION[SHFL_INFO_SET | SHFL_INFO_FILE] request. + */ +DECLINLINE(int) VbglR0SfHostReqSetObjInfo(SHFLROOT idRoot, VBOXSFOBJINFOREQ *pReq, uint64_t hHostFile) +{ + uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS + ? sizeof(*pReq) : RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = SHFL_INFO_SET | SHFL_INFO_FILE; + + pReq->Parms.cb32.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32.u.value32 = sizeof(pReq->ObjInfo); + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pInfo.u.Embedded.cbData = sizeof(pReq->ObjInfo); + pReq->Parms.pInfo.u.Embedded.offData = RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pInfo.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_BOTH; + } + else + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_LinAddr; + pReq->Parms.pInfo.u.LinAddr.cb = sizeof(pReq->ObjInfo); + pReq->Parms.pInfo.u.LinAddr.uAddr = (uintptr_t)&pReq->ObjInfo; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** + * SHFL_FN_INFORMATION[SHFL_INFO_SET | SHFL_INFO_SIZE] request. + */ +DECLINLINE(int) VbglR0SfHostReqSetFileSizeOld(SHFLROOT idRoot, VBOXSFOBJINFOREQ *pReq, uint64_t hHostFile) +{ + uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS + ? sizeof(*pReq) : RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = SHFL_INFO_SET | SHFL_INFO_SIZE; + + pReq->Parms.cb32.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32.u.value32 = sizeof(pReq->ObjInfo); + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pInfo.u.Embedded.cbData = sizeof(pReq->ObjInfo); + pReq->Parms.pInfo.u.Embedded.offData = RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pInfo.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_BOTH; + } + else + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_LinAddr; + pReq->Parms.pInfo.u.LinAddr.cb = sizeof(pReq->ObjInfo); + pReq->Parms.pInfo.u.LinAddr.uAddr = (uintptr_t)&pReq->ObjInfo; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for VbglR0SfHostReqSetObjInfo. */ +typedef struct VBOXSFOBJINFOWITHBUFREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmInformation Parms; + HGCMPageListInfo PgLst; +} VBOXSFOBJINFOWITHBUFREQ; + +/** + * SHFL_FN_INFORMATION[SHFL_INFO_SET | SHFL_INFO_FILE] request, with separate + * buffer (on the physical heap). + */ +DECLINLINE(int) VbglR0SfHostReqSetObjInfoWithBuf(SHFLROOT idRoot, VBOXSFOBJINFOWITHBUFREQ *pReq, uint64_t hHostFile, + PSHFLFSOBJINFO pObjInfo, uint32_t offObjInfoInAlloc) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, sizeof(*pReq)); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = SHFL_INFO_SET | SHFL_INFO_FILE; + + pReq->Parms.cb32.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32.u.value32 = sizeof(*pObjInfo); + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST) + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_ContiguousPageList; + pReq->Parms.pInfo.u.PageList.size = sizeof(*pObjInfo); + pReq->Parms.pInfo.u.PageList.offset = RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_BOTH; + pReq->PgLst.aPages[0] = VbglR0PhysHeapGetPhysAddr((uint8_t *)pObjInfo - offObjInfoInAlloc) + offObjInfoInAlloc; + pReq->PgLst.offFirstPage = (uint16_t)(pReq->PgLst.aPages[0] & PAGE_OFFSET_MASK); + pReq->PgLst.aPages[0] &= ~(RTGCPHYS)PAGE_OFFSET_MASK; + pReq->PgLst.cPages = 1; + } + else + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_LinAddr; + pReq->Parms.pInfo.u.LinAddr.cb = sizeof(*pObjInfo); + pReq->Parms.pInfo.u.LinAddr.uAddr = (uintptr_t)pObjInfo; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for VbglR0SfHostReqRemove. */ +typedef struct VBOXSFREMOVEREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmRemove Parms; + SHFLSTRING StrPath; +} VBOXSFREMOVEREQ; + +/** + * SHFL_FN_REMOVE request. + */ +DECLINLINE(int) VbglR0SfHostReqRemove(SHFLROOT idRoot, VBOXSFREMOVEREQ *pReq, uint32_t fFlags) +{ + uint32_t const cbReq = RT_UOFFSETOF(VBOXSFREMOVEREQ, StrPath.String) + + (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS ? pReq->StrPath.u16Size : 0); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_REMOVE, SHFL_CPARMS_REMOVE, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pStrPath.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pStrPath.u.Embedded.cbData = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size; + pReq->Parms.pStrPath.u.Embedded.offData = RT_UOFFSETOF(VBOXSFREMOVEREQ, StrPath) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pStrPath.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + } + else + { + pReq->Parms.pStrPath.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrPath.u.LinAddr.cb = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size; + pReq->Parms.pStrPath.u.LinAddr.uAddr = (uintptr_t)&pReq->StrPath; + } + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = fFlags; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for VbglR0SfHostReqCloseAndRemove. */ +typedef struct VBOXSFCLOSEANDREMOVEREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmCloseAndRemove Parms; + SHFLSTRING StrPath; +} VBOXSFCLOSEANDREMOVEREQ; + +/** + * SHFL_FN_CLOSE_AND_REMOVE request. + */ +DECLINLINE(int) VbglR0SfHostReqCloseAndRemove(SHFLROOT idRoot, VBOXSFCLOSEANDREMOVEREQ *pReq, uint32_t fFlags, SHFLHANDLE hToClose) +{ + uint32_t const cbReq = RT_UOFFSETOF(VBOXSFCLOSEANDREMOVEREQ, StrPath.String) + + (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS ? pReq->StrPath.u16Size : 0); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_CLOSE_AND_REMOVE, SHFL_CPARMS_CLOSE_AND_REMOVE, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pStrPath.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pStrPath.u.Embedded.cbData = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size; + pReq->Parms.pStrPath.u.Embedded.offData = RT_UOFFSETOF(VBOXSFCLOSEANDREMOVEREQ, StrPath) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pStrPath.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + } + else + { + pReq->Parms.pStrPath.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrPath.u.LinAddr.cb = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size; + pReq->Parms.pStrPath.u.LinAddr.uAddr = (uintptr_t)&pReq->StrPath; + } + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = fFlags; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hToClose; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for VbglR0SfHostReqRenameWithSrcContig and + * VbglR0SfHostReqRenameWithSrcBuf. */ +typedef struct VBOXSFRENAMEWITHSRCBUFREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmRename Parms; + HGCMPageListInfo PgLst; + SHFLSTRING StrDstPath; +} VBOXSFRENAMEWITHSRCBUFREQ; + + +/** + * SHFL_FN_REMOVE request. + */ +DECLINLINE(int) VbglR0SfHostReqRenameWithSrcContig(SHFLROOT idRoot, VBOXSFRENAMEWITHSRCBUFREQ *pReq, + PSHFLSTRING pSrcStr, RTGCPHYS64 PhysSrcStr, uint32_t fFlags) +{ + uint32_t const cbReq = RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ, StrDstPath.String) + + (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS ? pReq->StrDstPath.u16Size : 0); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_RENAME, SHFL_CPARMS_RENAME, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST) + { + pReq->Parms.pStrSrcPath.type = VMMDevHGCMParmType_ContiguousPageList; + pReq->Parms.pStrSrcPath.u.PageList.size = SHFLSTRING_HEADER_SIZE + pSrcStr->u16Size; + pReq->Parms.pStrSrcPath.u.PageList.offset = RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ, PgLst) + - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + pReq->PgLst.offFirstPage = (uint16_t)PhysSrcStr & (uint16_t)(PAGE_OFFSET_MASK); + pReq->PgLst.aPages[0] = PhysSrcStr & ~(RTGCPHYS64)PAGE_OFFSET_MASK; + pReq->PgLst.cPages = 1; + } + else + { + pReq->Parms.pStrSrcPath.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrSrcPath.u.LinAddr.cb = SHFLSTRING_HEADER_SIZE + pSrcStr->u16Size; + pReq->Parms.pStrSrcPath.u.LinAddr.uAddr = (uintptr_t)pSrcStr; + } + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pStrDstPath.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pStrDstPath.u.Embedded.cbData = SHFLSTRING_HEADER_SIZE + pReq->StrDstPath.u16Size; + pReq->Parms.pStrDstPath.u.Embedded.offData = RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ, StrDstPath) + - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pStrDstPath.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + } + else + { + pReq->Parms.pStrDstPath.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrDstPath.u.LinAddr.cb = SHFLSTRING_HEADER_SIZE + pReq->StrDstPath.u16Size; + pReq->Parms.pStrDstPath.u.LinAddr.uAddr = (uintptr_t)&pReq->StrDstPath; + } + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = fFlags; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** + * SHFL_FN_REMOVE request. + */ +DECLINLINE(int) VbglR0SfHostReqRenameWithSrcBuf(SHFLROOT idRoot, VBOXSFRENAMEWITHSRCBUFREQ *pReq, + PSHFLSTRING pSrcStr, uint32_t fFlags) +{ + return VbglR0SfHostReqRenameWithSrcContig(idRoot, pReq, pSrcStr, VbglR0PhysHeapGetPhysAddr(pSrcStr), fFlags); +} + + +/** Request structure for VbglR0SfHostReqFlush. */ +typedef struct VBOXSFFLUSHREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmFlush Parms; +} VBOXSFFLUSHREQ; + +/** + * SHFL_FN_FLUSH request. + */ +DECLINLINE(int) VbglR0SfHostReqFlush(SHFLROOT idRoot, VBOXSFFLUSHREQ *pReq, uint64_t hHostFile) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_FLUSH, SHFL_CPARMS_FLUSH, sizeof(*pReq)); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** + * SHFL_FN_FLUSH request, allocate request buffer. + */ +DECLINLINE(int) VbglR0SfHostReqFlushSimple(SHFLROOT idRoot, uint64_t hHostFile) +{ + VBOXSFFLUSHREQ *pReq = (VBOXSFFLUSHREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq)); + if (pReq) + { + int vrc = VbglR0SfHostReqFlush(idRoot, pReq, hHostFile); + VbglR0PhysHeapFree(pReq); + return vrc; + } + return VERR_NO_MEMORY; +} + + +/** Request structure for VbglR0SfHostReqSetFileSize. */ +typedef struct VBOXSFSETFILESIZEREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmSetFileSize Parms; +} VBOXSFSETFILESIZEREQ; + +/** + * SHFL_FN_SET_FILE_SIZE request. + */ +DECLINLINE(int) VbglR0SfHostReqSetFileSize(SHFLROOT idRoot, VBOXSFSETFILESIZEREQ *pReq, uint64_t hHostFile, uint64_t cbNewSize) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_SET_FILE_SIZE, SHFL_CPARMS_SET_FILE_SIZE, sizeof(*pReq)); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.cb64NewSize.type = VMMDevHGCMParmType_64bit; + pReq->Parms.cb64NewSize.u.value64 = cbNewSize; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** + * SHFL_FN_SET_FILE_SIZE request, allocate request buffer. + */ +DECLINLINE(int) VbglR0SfHostReqSetFileSizeSimple(SHFLROOT idRoot, uint64_t hHostFile, uint64_t cbNewSize) +{ + VBOXSFSETFILESIZEREQ *pReq = (VBOXSFSETFILESIZEREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq)); + if (pReq) + { + int vrc = VbglR0SfHostReqSetFileSize(idRoot, pReq, hHostFile, cbNewSize); + VbglR0PhysHeapFree(pReq); + return vrc; + } + return VERR_NO_MEMORY; +} + + +/** Request structure for VbglR0SfHostReqReadEmbedded. */ +typedef struct VBOXSFREADEMBEDDEDREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmRead Parms; + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abData[RT_FLEXIBLE_ARRAY]; +} VBOXSFREADEMBEDDEDREQ; + +/** + * SHFL_FN_READ request using embedded data buffer. + */ +DECLINLINE(int) VbglR0SfHostReqReadEmbedded(SHFLROOT idRoot, VBOXSFREADEMBEDDEDREQ *pReq, uint64_t hHostFile, + uint64_t offRead, uint32_t cbToRead) +{ + uint32_t const cbReq = RT_UOFFSETOF(VBOXSFREADEMBEDDEDREQ, abData[0]) + + (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS ? cbToRead : 0); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_READ, SHFL_CPARMS_READ, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.off64Read.type = VMMDevHGCMParmType_64bit; + pReq->Parms.off64Read.u.value64 = offRead; + + pReq->Parms.cb32Read.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32Read.u.value32 = cbToRead; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pBuf.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pBuf.u.Embedded.cbData = cbToRead; + pReq->Parms.pBuf.u.Embedded.offData = RT_UOFFSETOF(VBOXSFREADEMBEDDEDREQ, abData[0]) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pBuf.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; + } + else + { + pReq->Parms.pBuf.type = VMMDevHGCMParmType_LinAddr_Out; + pReq->Parms.pBuf.u.LinAddr.cb = cbToRead; + pReq->Parms.pBuf.u.LinAddr.uAddr = (uintptr_t)&pReq->abData[0]; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for vboxSfOs2HostReqRead & VbglR0SfHostReqReadContig. */ +typedef struct VBOXSFREADPGLSTREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmRead Parms; + HGCMPageListInfo PgLst; +} VBOXSFREADPGLSTREQ; + +/** + * SHFL_FN_READ request using page list for data buffer (caller populated). + */ +DECLINLINE(int) VbglR0SfHostReqReadPgLst(SHFLROOT idRoot, VBOXSFREADPGLSTREQ *pReq, uint64_t hHostFile, + uint64_t offRead, uint32_t cbToRead, uint32_t cPages) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_READ, SHFL_CPARMS_READ, + RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[cPages])); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.off64Read.type = VMMDevHGCMParmType_64bit; + pReq->Parms.off64Read.u.value64 = offRead; + + pReq->Parms.cb32Read.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32Read.u.value32 = cbToRead; + + pReq->Parms.pBuf.type = g_fHostFeatures & VMMDEV_HVF_HGCM_NO_BOUNCE_PAGE_LIST + ? VMMDevHGCMParmType_NoBouncePageList : VMMDevHGCMParmType_PageList; + pReq->Parms.pBuf.u.PageList.size = cbToRead; + pReq->Parms.pBuf.u.PageList.offset = RT_UOFFSETOF(VBOXSFREADPGLSTREQ, PgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; + pReq->PgLst.cPages = (uint16_t)cPages; + AssertReturn(cPages <= UINT16_MAX, VERR_OUT_OF_RANGE); + /* caller sets offset */ + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, + RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[cPages])); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** + * SHFL_FN_READ request using a physically contiguous buffer. + */ +DECLINLINE(int) VbglR0SfHostReqReadContig(SHFLROOT idRoot, VBOXSFREADPGLSTREQ *pReq, uint64_t hHostFile, + uint64_t offRead, uint32_t cbToRead, void *pvBuffer, RTGCPHYS64 PhysBuffer) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_READ, SHFL_CPARMS_READ, RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[1])); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.off64Read.type = VMMDevHGCMParmType_64bit; + pReq->Parms.off64Read.u.value64 = offRead; + + pReq->Parms.cb32Read.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32Read.u.value32 = cbToRead; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST) + { + pReq->Parms.pBuf.type = VMMDevHGCMParmType_ContiguousPageList; + pReq->Parms.pBuf.u.PageList.size = cbToRead; + pReq->Parms.pBuf.u.PageList.offset = RT_UOFFSETOF(VBOXSFREADPGLSTREQ, PgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; + pReq->PgLst.offFirstPage = (uint16_t)(PhysBuffer & PAGE_OFFSET_MASK); + pReq->PgLst.cPages = 1; + pReq->PgLst.aPages[0] = PhysBuffer & ~(RTGCPHYS64)PAGE_OFFSET_MASK; + } + else + { + pReq->Parms.pBuf.type = VMMDevHGCMParmType_LinAddr_Out; + pReq->Parms.pBuf.u.LinAddr.cb = cbToRead; + pReq->Parms.pBuf.u.LinAddr.uAddr = (uintptr_t)pvBuffer; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[1])); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + + +/** Request structure for VbglR0SfHostReqWriteEmbedded. */ +typedef struct VBOXSFWRITEEMBEDDEDREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmWrite Parms; + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abData[RT_FLEXIBLE_ARRAY]; +} VBOXSFWRITEEMBEDDEDREQ; + +/** + * SHFL_FN_WRITE request using embedded data buffer. + */ +DECLINLINE(int) VbglR0SfHostReqWriteEmbedded(SHFLROOT idRoot, VBOXSFWRITEEMBEDDEDREQ *pReq, uint64_t hHostFile, + uint64_t offWrite, uint32_t cbToWrite) +{ + uint32_t const cbReq = RT_UOFFSETOF(VBOXSFWRITEEMBEDDEDREQ, abData[0]) + + (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS ? cbToWrite : 0); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_WRITE, SHFL_CPARMS_WRITE, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.off64Write.type = VMMDevHGCMParmType_64bit; + pReq->Parms.off64Write.u.value64 = offWrite; + + pReq->Parms.cb32Write.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32Write.u.value32 = cbToWrite; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pBuf.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pBuf.u.Embedded.cbData = cbToWrite; + pReq->Parms.pBuf.u.Embedded.offData = RT_UOFFSETOF(VBOXSFWRITEEMBEDDEDREQ, abData[0]) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pBuf.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + } + else + { + pReq->Parms.pBuf.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pBuf.u.LinAddr.cb = cbToWrite; + pReq->Parms.pBuf.u.LinAddr.uAddr = (uintptr_t)&pReq->abData[0]; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for vboxSfOs2HostReqWrite and VbglR0SfHostReqWriteContig. */ +typedef struct VBOXSFWRITEPGLSTREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmWrite Parms; + HGCMPageListInfo PgLst; +} VBOXSFWRITEPGLSTREQ; + +/** + * SHFL_FN_WRITE request using page list for data buffer (caller populated). + */ +DECLINLINE(int) VbglR0SfHostReqWritePgLst(SHFLROOT idRoot, VBOXSFWRITEPGLSTREQ *pReq, uint64_t hHostFile, + uint64_t offWrite, uint32_t cbToWrite, uint32_t cPages) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_WRITE, SHFL_CPARMS_WRITE, + RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[cPages])); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.off64Write.type = VMMDevHGCMParmType_64bit; + pReq->Parms.off64Write.u.value64 = offWrite; + + pReq->Parms.cb32Write.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32Write.u.value32 = cbToWrite; + + pReq->Parms.pBuf.type = g_fHostFeatures & VMMDEV_HVF_HGCM_NO_BOUNCE_PAGE_LIST + ? VMMDevHGCMParmType_NoBouncePageList : VMMDevHGCMParmType_PageList;; + pReq->Parms.pBuf.u.PageList.size = cbToWrite; + pReq->Parms.pBuf.u.PageList.offset = RT_UOFFSETOF(VBOXSFWRITEPGLSTREQ, PgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + pReq->PgLst.cPages = (uint16_t)cPages; + AssertReturn(cPages <= UINT16_MAX, VERR_OUT_OF_RANGE); + /* caller sets offset */ + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, + RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[cPages])); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** + * SHFL_FN_WRITE request using a physically contiguous buffer. + */ +DECLINLINE(int) VbglR0SfHostReqWriteContig(SHFLROOT idRoot, VBOXSFWRITEPGLSTREQ *pReq, uint64_t hHostFile, + uint64_t offWrite, uint32_t cbToWrite, void const *pvBuffer, RTGCPHYS64 PhysBuffer) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_WRITE, SHFL_CPARMS_WRITE, RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[1])); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.off64Write.type = VMMDevHGCMParmType_64bit; + pReq->Parms.off64Write.u.value64 = offWrite; + + pReq->Parms.cb32Write.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32Write.u.value32 = cbToWrite; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST) + { + pReq->Parms.pBuf.type = VMMDevHGCMParmType_ContiguousPageList; + pReq->Parms.pBuf.u.PageList.size = cbToWrite; + pReq->Parms.pBuf.u.PageList.offset = RT_UOFFSETOF(VBOXSFWRITEPGLSTREQ, PgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + pReq->PgLst.offFirstPage = (uint16_t)(PhysBuffer & PAGE_OFFSET_MASK); + pReq->PgLst.cPages = 1; + pReq->PgLst.aPages[0] = PhysBuffer & ~(RTGCPHYS64)PAGE_OFFSET_MASK; + } + else + { + pReq->Parms.pBuf.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pBuf.u.LinAddr.cb = cbToWrite; + pReq->Parms.pBuf.u.LinAddr.uAddr = (uintptr_t)pvBuffer; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[1])); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for VbglR0SfHostReqCopyFilePart. */ +typedef struct VBOXSFCOPYFILEPARTREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmCopyFilePart Parms; +} VBOXSFCOPYFILEPARTREQ; + +/** + * SHFL_FN_CREATE request. + */ +DECLINLINE(int) VbglR0SfHostReqCopyFilePart(SHFLROOT idRootSrc, SHFLHANDLE hHostFileSrc, uint64_t offSrc, + SHFLROOT idRootDst, SHFLHANDLE hHostFileDst, uint64_t offDst, + uint64_t cbToCopy, uint32_t fFlags, VBOXSFCOPYFILEPARTREQ *pReq) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_COPY_FILE_PART, SHFL_CPARMS_COPY_FILE_PART, sizeof(*pReq)); + + pReq->Parms.id32RootSrc.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32RootSrc.u.value32 = idRootSrc; + + pReq->Parms.u64HandleSrc.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64HandleSrc.u.value64 = hHostFileSrc; + + pReq->Parms.off64Src.type = VMMDevHGCMParmType_64bit; + pReq->Parms.off64Src.u.value64 = offSrc; + + pReq->Parms.id32RootDst.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32RootDst.u.value32 = idRootDst; + + pReq->Parms.u64HandleDst.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64HandleDst.u.value64 = hHostFileDst; + + pReq->Parms.off64Dst.type = VMMDevHGCMParmType_64bit; + pReq->Parms.off64Dst.u.value64 = offDst; + + pReq->Parms.cb64ToCopy.type = VMMDevHGCMParmType_64bit; + pReq->Parms.cb64ToCopy.u.value64 = cbToCopy; + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = fFlags; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + + +/** Request structure for VbglR0SfHostReqListDirContig2x() and + * VbglR0SfHostReqListDir(). */ +typedef struct VBOXSFLISTDIRREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmList Parms; + HGCMPageListInfo StrPgLst; + HGCMPageListInfo BufPgLst; +} VBOXSFLISTDIRREQ; + +/** + * SHFL_FN_LIST request with separate string buffer and buffers for entries, + * both physically contiguous allocations. + */ +DECLINLINE(int) VbglR0SfHostReqListDirContig2x(SHFLROOT idRoot, VBOXSFLISTDIRREQ *pReq, uint64_t hHostDir, + PSHFLSTRING pFilter, RTGCPHYS64 PhysFilter, uint32_t fFlags, + PSHFLDIRINFO pBuffer, RTGCPHYS64 PhysBuffer, uint32_t cbBuffer) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_LIST, SHFL_CPARMS_LIST, sizeof(*pReq)); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostDir; + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = fFlags; + + pReq->Parms.cb32Buffer.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32Buffer.u.value32 = cbBuffer; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST) + { + pReq->Parms.pStrFilter.type = VMMDevHGCMParmType_ContiguousPageList; + pReq->Parms.pStrFilter.u.PageList.offset = RT_UOFFSETOF(VBOXSFLISTDIRREQ, StrPgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->StrPgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + pReq->StrPgLst.cPages = 1; + if (pFilter) + { + pReq->Parms.pStrFilter.u.PageList.size = SHFLSTRING_HEADER_SIZE + pFilter->u16Size; + uint32_t const offFirstPage = (uint32_t)PhysFilter & PAGE_OFFSET_MASK; + pReq->StrPgLst.offFirstPage = (uint16_t)offFirstPage; + pReq->StrPgLst.aPages[0] = PhysFilter - offFirstPage; + } + else + { + pReq->Parms.pStrFilter.u.PageList.size = 0; + pReq->StrPgLst.offFirstPage = 0; + pReq->StrPgLst.aPages[0] = NIL_RTGCPHYS64; + } + + pReq->Parms.pBuffer.type = VMMDevHGCMParmType_ContiguousPageList; + pReq->Parms.pBuffer.u.PageList.offset = RT_UOFFSETOF(VBOXSFLISTDIRREQ, BufPgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pBuffer.u.PageList.size = cbBuffer; + pReq->BufPgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; + pReq->BufPgLst.cPages = 1; + uint32_t const offFirstPage = (uint32_t)PhysBuffer & PAGE_OFFSET_MASK; + pReq->BufPgLst.offFirstPage = (uint16_t)offFirstPage; + pReq->BufPgLst.aPages[0] = PhysBuffer - offFirstPage; + } + else + { + pReq->Parms.pStrFilter.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrFilter.u.LinAddr.cb = pFilter ? SHFLSTRING_HEADER_SIZE + pFilter->u16Size : 0; + pReq->Parms.pStrFilter.u.LinAddr.uAddr = (uintptr_t)pFilter; + + pReq->Parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_Out; + pReq->Parms.pBuffer.u.LinAddr.cb = cbBuffer; + pReq->Parms.pBuffer.u.LinAddr.uAddr = (uintptr_t)pBuffer; + } + + pReq->Parms.f32More.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32More.u.value32 = 0; + + pReq->Parms.c32Entries.type = VMMDevHGCMParmType_32bit; + pReq->Parms.c32Entries.u.value32 = 0; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** + * SHFL_FN_LIST request with separate string buffer and buffers for entries, + * both allocated on the physical heap. + */ +DECLINLINE(int) VbglR0SfHostReqListDir(SHFLROOT idRoot, VBOXSFLISTDIRREQ *pReq, uint64_t hHostDir, + PSHFLSTRING pFilter, uint32_t fFlags, PSHFLDIRINFO pBuffer, uint32_t cbBuffer) +{ + return VbglR0SfHostReqListDirContig2x(idRoot, + pReq, + hHostDir, + pFilter, + pFilter ? VbglR0PhysHeapGetPhysAddr(pFilter) : NIL_RTGCPHYS64, + fFlags, + pBuffer, + VbglR0PhysHeapGetPhysAddr(pBuffer), + cbBuffer); +} + + +/** Request structure for VbglR0SfHostReqReadLink. */ +typedef struct VBOXSFREADLINKREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmReadLink Parms; + HGCMPageListInfo PgLst; + SHFLSTRING StrPath; +} VBOXSFREADLINKREQ; + +/** + * SHFL_FN_READLINK request. + * + * @note Buffer contains UTF-8 characters on success, regardless of the + * UTF-8/UTF-16 setting of the connection. + */ +DECLINLINE(int) VbglR0SfHostReqReadLinkContig(SHFLROOT idRoot, void *pvBuffer, RTGCPHYS64 PhysBuffer, uint32_t cbBuffer, + VBOXSFREADLINKREQ *pReq) +{ + uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS + ? RT_UOFFSETOF(VBOXSFREADLINKREQ, StrPath.String) + pReq->StrPath.u16Size + : cbBuffer <= PAGE_SIZE - (PhysBuffer & PAGE_OFFSET_MASK) + || (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST) + ? RT_UOFFSETOF(VBOXSFREADLINKREQ, StrPath.String) + : RT_UOFFSETOF(VBOXSFREADLINKREQ, PgLst); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_READLINK, SHFL_CPARMS_READLINK, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pStrPath.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pStrPath.u.Embedded.cbData = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size; + pReq->Parms.pStrPath.u.Embedded.offData = RT_UOFFSETOF(VBOXSFREADLINKREQ, StrPath) + - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pStrPath.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + } + else + { + pReq->Parms.pStrPath.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrPath.u.LinAddr.cb = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size; + pReq->Parms.pStrPath.u.LinAddr.uAddr = (uintptr_t)&pReq->StrPath; + } + + if ( cbBuffer <= PAGE_SIZE - (PhysBuffer & PAGE_OFFSET_MASK) + || (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST)) + { + pReq->Parms.pBuffer.type = cbBuffer <= PAGE_SIZE - (PhysBuffer & PAGE_OFFSET_MASK) + ? VMMDevHGCMParmType_PageList + : VMMDevHGCMParmType_ContiguousPageList; + pReq->Parms.pBuffer.u.PageList.size = cbBuffer; + pReq->Parms.pBuffer.u.PageList.offset = RT_UOFFSETOF(VBOXSFREADLINKREQ, PgLst) + - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; + pReq->PgLst.offFirstPage = (uint16_t)PhysBuffer & (uint16_t)(PAGE_OFFSET_MASK); + pReq->PgLst.aPages[0] = PhysBuffer & ~(RTGCPHYS64)PAGE_OFFSET_MASK; + pReq->PgLst.cPages = 1; + } + else + { + pReq->Parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_Out; + pReq->Parms.pBuffer.u.LinAddr.cb = cbBuffer; + pReq->Parms.pBuffer.u.LinAddr.uAddr = (uintptr_t)pvBuffer; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** + * SHFL_FN_READLINK request, simplified version. + * + * + * @note Buffer contains UTF-8 characters on success, regardless of the + * UTF-8/UTF-16 setting of the connection. + */ +DECLINLINE(int) VbglR0SfHostReqReadLinkContigSimple(SHFLROOT idRoot, const char *pszPath, size_t cchPath, void *pvBuf, + RTGCPHYS64 PhysBuffer, uint32_t cbBuffer) +{ + if (cchPath < _64K - 1) + { + VBOXSFREADLINKREQ *pReq = (VBOXSFREADLINKREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFREADLINKREQ, StrPath.String) + + SHFLSTRING_HEADER_SIZE + (uint32_t)cchPath); + if (pReq) + { + pReq->StrPath.u16Length = (uint16_t)cchPath; + pReq->StrPath.u16Size = (uint16_t)cchPath + 1; + memcpy(pReq->StrPath.String.ach, pszPath, cchPath); + pReq->StrPath.String.ach[cchPath] = '\0'; + + { + int vrc = VbglR0SfHostReqReadLinkContig(idRoot, pvBuf, PhysBuffer, cbBuffer, pReq); + VbglR0PhysHeapFree(pReq); + return vrc; + } + } + return VERR_NO_MEMORY; + } + return VERR_FILENAME_TOO_LONG; +} + + +/** Request structure for VbglR0SfHostReqCreateSymlink. */ +typedef struct VBOXSFCREATESYMLINKREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmCreateSymlink Parms; + HGCMPageListInfo PgLstTarget; + SHFLFSOBJINFO ObjInfo; + SHFLSTRING StrSymlinkPath; +} VBOXSFCREATESYMLINKREQ; + +/** + * SHFL_FN_SYMLINK request. + * + * Caller fills in the symlink string and supplies a physical contiguous + * target string + */ +DECLINLINE(int) VbglR0SfHostReqCreateSymlinkContig(SHFLROOT idRoot, PCSHFLSTRING pStrTarget, RTGCPHYS64 PhysTarget, + VBOXSFCREATESYMLINKREQ *pReq) +{ + uint32_t const cbTarget = SHFLSTRING_HEADER_SIZE + pStrTarget->u16Size; + uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS + ? RT_UOFFSETOF(VBOXSFCREATESYMLINKREQ, StrSymlinkPath.String) + pReq->StrSymlinkPath.u16Size + : RT_UOFFSETOF(VBOXSFCREATESYMLINKREQ, ObjInfo) /*simplified*/; + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_SYMLINK, SHFL_CPARMS_SYMLINK, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pStrSymlink.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pStrSymlink.u.Embedded.cbData = SHFLSTRING_HEADER_SIZE + pReq->StrSymlinkPath.u16Size; + pReq->Parms.pStrSymlink.u.Embedded.offData = RT_UOFFSETOF(VBOXSFCREATESYMLINKREQ, StrSymlinkPath) + - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pStrSymlink.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + } + else + { + pReq->Parms.pStrSymlink.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrSymlink.u.LinAddr.cb = SHFLSTRING_HEADER_SIZE + pReq->StrSymlinkPath.u16Size; + pReq->Parms.pStrSymlink.u.LinAddr.uAddr = (uintptr_t)&pReq->StrSymlinkPath; + } + + if ( cbTarget <= PAGE_SIZE - (PhysTarget & PAGE_OFFSET_MASK) + || (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST)) + { + pReq->Parms.pStrTarget.type = cbTarget <= PAGE_SIZE - (PhysTarget & PAGE_OFFSET_MASK) + ? VMMDevHGCMParmType_PageList + : VMMDevHGCMParmType_ContiguousPageList; + pReq->Parms.pStrTarget.u.PageList.size = cbTarget; + pReq->Parms.pStrTarget.u.PageList.offset = RT_UOFFSETOF(VBOXSFCREATESYMLINKREQ, PgLstTarget) + - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLstTarget.flags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + pReq->PgLstTarget.offFirstPage = (uint16_t)PhysTarget & (uint16_t)(PAGE_OFFSET_MASK); + pReq->PgLstTarget.aPages[0] = PhysTarget & ~(RTGCPHYS64)PAGE_OFFSET_MASK; + pReq->PgLstTarget.cPages = 1; + } + else + { + pReq->Parms.pStrTarget.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrTarget.u.LinAddr.cb = cbTarget; + pReq->Parms.pStrTarget.u.LinAddr.uAddr = (uintptr_t)pStrTarget; + } + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pInfo.u.Embedded.cbData = sizeof(pReq->ObjInfo); + pReq->Parms.pInfo.u.Embedded.offData = RT_UOFFSETOF(VBOXSFCREATESYMLINKREQ, ObjInfo) + - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pInfo.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; + } + else + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_LinAddr_Out; + pReq->Parms.pInfo.u.LinAddr.cb = sizeof(pReq->ObjInfo); + pReq->Parms.pInfo.u.LinAddr.uAddr = (uintptr_t)&pReq->ObjInfo; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** @} */ + +#endif /* !VBOX_INCLUDED_VBoxGuestLibSharedFoldersInline_h */ + diff --git a/include/VBox/VBoxGuestMangling.h b/include/VBox/VBoxGuestMangling.h new file mode 100644 index 00000000..2049051d --- /dev/null +++ b/include/VBox/VBoxGuestMangling.h @@ -0,0 +1,49 @@ +/** @file + * VBoxGuest - Mangling of IPRT symbols for guest drivers. + * + * This is included via a compiler directive on platforms with a global kernel + * symbol name space (i.e. not Windows, OS/2 and Mac OS X (?)). + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxGuestMangling_h +#define VBOX_INCLUDED_VBoxGuestMangling_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#define RT_MANGLER(symbol) VBoxGuest_##symbol +#include <iprt/mangling.h> + +#endif /* !VBOX_INCLUDED_VBoxGuestMangling_h */ + diff --git a/include/VBox/VBoxKeyboard.h b/include/VBox/VBoxKeyboard.h new file mode 100644 index 00000000..c39bf522 --- /dev/null +++ b/include/VBox/VBoxKeyboard.h @@ -0,0 +1,56 @@ +/** @file + * Frontends/Common - X11 keyboard driver interface. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* + * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice + * other than GPL or LGPL is available it will apply instead, Oracle elects to use only + * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where + * a choice of LGPL license versions is made available with the language indicating + * that LGPLv2 or any later version may be used, or where a choice of which version + * of the LGPL is applied is otherwise unspecified. + */ + +#ifndef VBOX_INCLUDED_VBoxKeyboard_h +#define VBOX_INCLUDED_VBoxKeyboard_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <X11/Xlib.h> + +/* Exported definitions */ +#undef CCALL +#ifdef __cplusplus +# define CCALL "C" +#else +# define CCALL +#endif +#ifdef VBOX_HAVE_VISIBILITY_HIDDEN +extern CCALL __attribute__((visibility("default"))) unsigned *X11DRV_getKeyc2scan(void); +extern CCALL __attribute__((visibility("default"))) unsigned X11DRV_InitKeyboard(Display *dpy, unsigned *byLayoutOK, unsigned *byTypeOK, unsigned *byXkbOK, int (*remapScancodes)[2]); +extern CCALL __attribute__((visibility("default"))) unsigned X11DRV_KeyEvent(Display *dpy, KeyCode code); +#else +extern CCALL unsigned *X11DRV_getKeyc2scan(void); +extern CCALL unsigned X11DRV_InitKeyboard(Display *dpy, unsigned *byLayoutOK, unsigned *byTypeOK, unsigned *byXkbOK, int (*remapScancodes)[2]); +extern CCALL unsigned X11DRV_KeyEvent(Display *dpy, KeyCode code); +#endif + +#endif /* !VBOX_INCLUDED_VBoxKeyboard_h */ + diff --git a/include/VBox/VBoxNetCfg-win.h b/include/VBox/VBoxNetCfg-win.h new file mode 100644 index 00000000..8a1dc671 --- /dev/null +++ b/include/VBox/VBoxNetCfg-win.h @@ -0,0 +1,147 @@ +/* $Id: VBoxNetCfg-win.h $ */ +/** @file + * Network Configuration API for Windows platforms. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxNetCfg_win_h +#define VBOX_INCLUDED_VBoxNetCfg_win_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* + * Defining VBOXNETCFG_DELAYEDRENAME postpones renaming of host-only adapter + * connection during adapter creation after it has been assigned with an + * IP address. This hopefully prevents collisions that may happen when we + * attempt to rename a connection too early, while its configuration is + * still being 'committed' by the network setup engine. + */ +#define VBOXNETCFG_DELAYEDRENAME + +#include <iprt/win/winsock2.h> +#include <iprt/win/windows.h> +#include <Netcfgn.h> +#include <iprt/win/Setupapi.h> +#include <VBox/cdefs.h> +#include <iprt/types.h> + +/** @defgroup grp_vboxnetcfgwin The Windows Network Configration Library + * @{ */ + +/** @def VBOXNETCFGWIN_DECL + * The usual declaration wrapper. + */ +#if 0 +/* enable this in case we include this in a dll*/ +# ifdef IN_VBOXDDU +# define VBOXNETCFGWIN_DECL(a_Type) DECLEXPORT(a_Type) +# else +# define VBOXNETCFGWIN_DECL(a_Type) DECLIMPORT(a_Type) +# endif +#else +/*enable this in case we include this in a static lib*/ +# define VBOXNETCFGWIN_DECL(a_Type) a_Type VBOXCALL +#endif + +RT_C_DECLS_BEGIN + +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinQueryINetCfg(OUT INetCfg **ppNetCfg, + IN BOOL fGetWriteLock, + IN LPCWSTR pszwClientDescription, + IN DWORD cmsTimeout, + OUT LPWSTR *ppszwClientDescription); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinReleaseINetCfg(IN INetCfg *pNetCfg, IN BOOL fHasWriteLock); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetComponentByGuid(IN INetCfg *pNc, IN const GUID *pguidClass, + IN const GUID * pComponentGuid, OUT INetCfgComponent **ppncc); + +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetFltInstall(IN INetCfg *pNc, IN LPCWSTR const *pwszInfFullPaths, IN UINT cInfFullPaths); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetFltUninstall(IN INetCfg *pNc); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetLwfInstall(IN INetCfg *pNc, IN LPCWSTR const pwszInfFullPath); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetLwfUninstall(IN INetCfg *pNc); + +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetAdpUninstall(IN INetCfg *pNc, IN LPCWSTR pwszId); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetAdpInstall(IN INetCfg *pNc,IN LPCWSTR const pwszInfFullPath); + +#ifndef VBOXNETCFG_DELAYEDRENAME +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pwszInfPath, IN bool fIsInfPathFile, + IN BSTR pBstrDesiredName, + OUT GUID *pGuid, OUT BSTR *pBstrName, OUT BSTR *pErrMsg); +#else /* VBOXNETCFG_DELAYEDRENAME */ +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pwszInfPath, IN bool fIsInfPathFile, + IN BSTR pBstrDesiredName, + OUT GUID *pGuid, OUT BSTR *pBstrId, OUT BSTR *pErrMsg); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameHostOnlyConnection(IN const GUID *pGuid, IN LPCWSTR pszId, OUT BSTR *pDevName); +#endif /* VBOXNETCFG_DELAYEDRENAME */ +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinUpdateHostOnlyNetworkInterface(LPCWSTR pcsxwInf, BOOL *pfRebootRequired, LPCWSTR pcsxwId); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveHostOnlyNetworkInterface(IN const GUID *pGUID, OUT BSTR *pErrMsg); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveAllNetDevicesOfId(IN LPCWSTR lpszPnPId); + +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostonlyConnectionName(IN PCWSTR pwszDevName, OUT WCHAR *pwszBuf, + IN ULONG cwcBuf, OUT PULONG pcwcNeeded); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameConnection(IN LPWSTR pwszGuid, IN PCWSTR pwszNewName); + +typedef enum VBOXNECTFGWINPROPCHANGE_TYPE_T +{ + VBOXNECTFGWINPROPCHANGE_TYPE_UNDEFINED = 0, + VBOXNECTFGWINPROPCHANGE_TYPE_DISABLE, + VBOXNECTFGWINPROPCHANGE_TYPE_ENABLE +} VBOXNECTFGWINPROPCHANGE_TYPE_T; + +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinPropChangeAllNetDevicesOfId(IN LPCWSTR lpszPnPId, VBOXNECTFGWINPROPCHANGE_TYPE_T enmPcType); + +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostOnlyNetworkNetworkIp(OUT PULONG pNetIp, OUT PULONG pNetMask); + +typedef struct ADAPTER_SETTINGS +{ + ULONG ip; + ULONG mask; + BOOL bDhcp; +} ADAPTER_SETTINGS, *PADAPTER_SETTINGS; /**< I'm not prefixed */ + +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnableStaticIpConfig(IN const GUID *pGuid, IN ULONG ip, IN ULONG mask); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetAdapterSettings(IN const GUID * pGuid, OUT PADAPTER_SETTINGS pSettings); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnableDynamicIpConfig(IN const GUID *pGuid); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinDhcpRediscover(IN const GUID *pGuid); + + +typedef DECLCALLBACKTYPE(void, FNVBOXNETCFGLOGGER,(const char *pszString)); +typedef FNVBOXNETCFGLOGGER *PFNVBOXNETCFGLOGGER; +VBOXNETCFGWIN_DECL(void) VBoxNetCfgWinSetLogging(IN PFNVBOXNETCFGLOGGER pfnLogger); + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_VBoxNetCfg_win_h */ + diff --git a/include/VBox/VBoxNetCmn-win.h b/include/VBox/VBoxNetCmn-win.h new file mode 100644 index 00000000..e1e0e643 --- /dev/null +++ b/include/VBox/VBoxNetCmn-win.h @@ -0,0 +1,163 @@ +/* $Id: VBoxNetCmn-win.h $ */ +/** @file + * VBoxNetCmn-win.h - NDIS6 Networking Driver Common Definitions, Windows-specific code. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxNetCmn_win_h +#define VBOX_INCLUDED_VBoxNetCmn_win_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/log.h> /* for LOG_ENABLED */ + + +DECLHIDDEN(void) vboxNetCmnWinDumpOidRequest(const char *pcszFunction, PNDIS_OID_REQUEST pRequest) +{ +# ifdef LOG_ENABLED + const char *pszType; + const char *pszOid = "unknown"; + + switch (pRequest->RequestType) + { + case NdisRequestSetInformation: pszType = "set"; break; + case NdisRequestMethod: pszType = "method"; break; + case NdisRequestQueryInformation: pszType = "query info"; break; + case NdisRequestQueryStatistics: pszType = "query stats"; break; + default: pszType = "unknown"; + } + switch (pRequest->DATA.SET_INFORMATION.Oid) + { + case OID_GEN_MAX_LINK_SPEED: pszOid = "OID_GEN_MAX_LINK_SPEED"; break; + case OID_GEN_LINK_STATE: pszOid = "OID_GEN_LINK_STATE"; break; + case OID_GEN_LINK_PARAMETERS: pszOid = "OID_GEN_LINK_PARAMETERS"; break; + case OID_GEN_MINIPORT_RESTART_ATTRIBUTES: pszOid = "OID_GEN_MINIPORT_RESTART_ATTRIBUTES"; break; + case OID_GEN_ENUMERATE_PORTS: pszOid = "OID_GEN_ENUMERATE_PORTS"; break; + case OID_GEN_PORT_STATE: pszOid = "OID_GEN_PORT_STATE"; break; + case OID_GEN_PORT_AUTHENTICATION_PARAMETERS: pszOid = "OID_GEN_PORT_AUTHENTICATION_PARAMETERS"; break; + case OID_GEN_INTERRUPT_MODERATION: pszOid = "OID_GEN_INTERRUPT_MODERATION"; break; + case OID_GEN_PHYSICAL_MEDIUM_EX: pszOid = "OID_GEN_PHYSICAL_MEDIUM_EX"; break; + case OID_GEN_SUPPORTED_LIST: pszOid = "OID_GEN_SUPPORTED_LIST"; break; + case OID_GEN_HARDWARE_STATUS: pszOid = "OID_GEN_HARDWARE_STATUS"; break; + case OID_GEN_MEDIA_SUPPORTED: pszOid = "OID_GEN_MEDIA_SUPPORTED"; break; + case OID_GEN_MEDIA_IN_USE: pszOid = "OID_GEN_MEDIA_IN_USE"; break; + case OID_GEN_MAXIMUM_LOOKAHEAD: pszOid = "OID_GEN_MAXIMUM_LOOKAHEAD"; break; + case OID_GEN_MAXIMUM_FRAME_SIZE: pszOid = "OID_GEN_MAXIMUM_FRAME_SIZE"; break; + case OID_GEN_LINK_SPEED: pszOid = "OID_GEN_LINK_SPEED"; break; + case OID_GEN_TRANSMIT_BUFFER_SPACE: pszOid = "OID_GEN_TRANSMIT_BUFFER_SPACE"; break; + case OID_GEN_RECEIVE_BUFFER_SPACE: pszOid = "OID_GEN_RECEIVE_BUFFER_SPACE"; break; + case OID_GEN_TRANSMIT_BLOCK_SIZE: pszOid = "OID_GEN_TRANSMIT_BLOCK_SIZE"; break; + case OID_GEN_RECEIVE_BLOCK_SIZE: pszOid = "OID_GEN_RECEIVE_BLOCK_SIZE"; break; + case OID_GEN_VENDOR_ID: pszOid = "OID_GEN_VENDOR_ID"; break; + case OID_GEN_VENDOR_DESCRIPTION: pszOid = "OID_GEN_VENDOR_DESCRIPTION"; break; + case OID_GEN_VENDOR_DRIVER_VERSION: pszOid = "OID_GEN_VENDOR_DRIVER_VERSION"; break; + case OID_GEN_CURRENT_PACKET_FILTER: pszOid = "OID_GEN_CURRENT_PACKET_FILTER"; break; + case OID_GEN_CURRENT_LOOKAHEAD: pszOid = "OID_GEN_CURRENT_LOOKAHEAD"; break; + case OID_GEN_DRIVER_VERSION: pszOid = "OID_GEN_DRIVER_VERSION"; break; + case OID_GEN_MAXIMUM_TOTAL_SIZE: pszOid = "OID_GEN_MAXIMUM_TOTAL_SIZE"; break; + case OID_GEN_PROTOCOL_OPTIONS: pszOid = "OID_GEN_PROTOCOL_OPTIONS"; break; + case OID_GEN_MAC_OPTIONS: pszOid = "OID_GEN_MAC_OPTIONS"; break; + case OID_GEN_MEDIA_CONNECT_STATUS: pszOid = "OID_GEN_MEDIA_CONNECT_STATUS"; break; + case OID_GEN_MAXIMUM_SEND_PACKETS: pszOid = "OID_GEN_MAXIMUM_SEND_PACKETS"; break; + case OID_GEN_SUPPORTED_GUIDS: pszOid = "OID_GEN_SUPPORTED_GUIDS"; break; + case OID_GEN_NETWORK_LAYER_ADDRESSES: pszOid = "OID_GEN_NETWORK_LAYER_ADDRESSES"; break; + case OID_GEN_TRANSPORT_HEADER_OFFSET: pszOid = "OID_GEN_TRANSPORT_HEADER_OFFSET"; break; + case OID_GEN_PHYSICAL_MEDIUM: pszOid = "OID_GEN_PHYSICAL_MEDIUM"; break; + case OID_GEN_MACHINE_NAME: pszOid = "OID_GEN_MACHINE_NAME"; break; + case OID_GEN_VLAN_ID: pszOid = "OID_GEN_VLAN_ID"; break; + case OID_GEN_RNDIS_CONFIG_PARAMETER: pszOid = "OID_GEN_RNDIS_CONFIG_PARAMETER"; break; + case OID_GEN_NDIS_RESERVED_1: pszOid = "OID_GEN_NDIS_RESERVED_1"; break; + case OID_GEN_NDIS_RESERVED_2: pszOid = "OID_GEN_NDIS_RESERVED_2"; break; + case OID_GEN_NDIS_RESERVED_5: pszOid = "OID_GEN_NDIS_RESERVED_5"; break; + case OID_GEN_MEDIA_CAPABILITIES: pszOid = "OID_GEN_MEDIA_CAPABILITIES"; break; + case OID_GEN_DEVICE_PROFILE: pszOid = "OID_GEN_DEVICE_PROFILE"; break; + case OID_GEN_FRIENDLY_NAME: pszOid = "OID_GEN_FRIENDLY_NAME"; break; + case OID_802_3_ADD_MULTICAST_ADDRESS: pszOid = "OID_802_3_ADD_MULTICAST_ADDRESS"; break; + case OID_802_3_DELETE_MULTICAST_ADDRESS: pszOid = "OID_802_3_DELETE_MULTICAST_ADDRESS"; break; + case OID_802_3_PERMANENT_ADDRESS: pszOid = "OID_802_3_PERMANENT_ADDRESS"; break; + case OID_802_3_CURRENT_ADDRESS: pszOid = "OID_802_3_CURRENT_ADDRESS"; break; + case OID_802_3_MULTICAST_LIST: pszOid = "OID_802_3_MULTICAST_LIST"; break; + case OID_802_3_MAXIMUM_LIST_SIZE: pszOid = "OID_802_3_MAXIMUM_LIST_SIZE"; break; + case OID_802_3_MAC_OPTIONS: pszOid = "OID_802_3_MAC_OPTIONS"; break; + case OID_TCP_TASK_OFFLOAD: pszOid = "OID_TCP_TASK_OFFLOAD"; break; + case OID_TCP_TASK_IPSEC_ADD_SA: pszOid = "OID_TCP_TASK_IPSEC_ADD_SA"; break; + case OID_TCP_TASK_IPSEC_ADD_UDPESP_SA: pszOid = "OID_TCP_TASK_IPSEC_ADD_UDPESP_SA"; break; + case OID_TCP_TASK_IPSEC_DELETE_SA: pszOid = "OID_TCP_TASK_IPSEC_DELETE_SA"; break; + case OID_TCP_TASK_IPSEC_DELETE_UDPESP_SA: pszOid = "OID_TCP_TASK_IPSEC_DELETE_UDPESP_SA"; break; + + case OID_GEN_STATISTICS: pszOid = "OID_GEN_STATISTICS"; break; + case OID_GEN_BYTES_RCV: pszOid = "OID_GEN_BYTES_RCV"; break; + case OID_GEN_BYTES_XMIT: pszOid = "OID_GEN_BYTES_XMIT"; break; + case OID_GEN_RCV_DISCARDS: pszOid = "OID_GEN_RCV_DISCARDS"; break; + case OID_GEN_XMIT_DISCARDS: pszOid = "OID_GEN_XMIT_DISCARDS"; break; + case OID_GEN_XMIT_OK: pszOid = "OID_GEN_XMIT_OK"; break; + case OID_GEN_RCV_OK: pszOid = "OID_GEN_RCV_OK"; break; + case OID_GEN_XMIT_ERROR: pszOid = "OID_GEN_XMIT_ERROR"; break; + case OID_GEN_RCV_ERROR: pszOid = "OID_GEN_RCV_ERROR"; break; + case OID_GEN_RCV_NO_BUFFER: pszOid = "OID_GEN_RCV_NO_BUFFER"; break; + case OID_GEN_DIRECTED_BYTES_XMIT: pszOid = "OID_GEN_DIRECTED_BYTES_XMIT"; break; + case OID_GEN_DIRECTED_FRAMES_XMIT: pszOid = "OID_GEN_DIRECTED_FRAMES_XMIT"; break; + case OID_GEN_MULTICAST_BYTES_XMIT: pszOid = "OID_GEN_MULTICAST_BYTES_XMIT"; break; + case OID_GEN_MULTICAST_FRAMES_XMIT: pszOid = "OID_GEN_MULTICAST_FRAMES_XMIT"; break; + case OID_GEN_BROADCAST_BYTES_XMIT: pszOid = "OID_GEN_BROADCAST_BYTES_XMIT"; break; + case OID_GEN_BROADCAST_FRAMES_XMIT: pszOid = "OID_GEN_BROADCAST_FRAMES_XMIT"; break; + case OID_GEN_DIRECTED_BYTES_RCV: pszOid = "OID_GEN_DIRECTED_BYTES_RCV"; break; + case OID_GEN_DIRECTED_FRAMES_RCV: pszOid = "OID_GEN_DIRECTED_FRAMES_RCV"; break; + case OID_GEN_MULTICAST_BYTES_RCV: pszOid = "OID_GEN_MULTICAST_BYTES_RCV"; break; + case OID_GEN_MULTICAST_FRAMES_RCV: pszOid = "OID_GEN_MULTICAST_FRAMES_RCV"; break; + case OID_GEN_BROADCAST_BYTES_RCV: pszOid = "OID_GEN_BROADCAST_BYTES_RCV"; break; + case OID_GEN_BROADCAST_FRAMES_RCV: pszOid = "OID_GEN_BROADCAST_FRAMES_RCV"; break; + case OID_GEN_RCV_CRC_ERROR: pszOid = "OID_GEN_RCV_CRC_ERROR"; break; + case OID_GEN_TRANSMIT_QUEUE_LENGTH: pszOid = "OID_GEN_TRANSMIT_QUEUE_LENGTH"; break; + case OID_GEN_INIT_TIME_MS: pszOid = "OID_GEN_INIT_TIME_MS"; break; + case OID_GEN_RESET_COUNTS: pszOid = "OID_GEN_RESET_COUNTS"; break; + case OID_GEN_MEDIA_SENSE_COUNTS: pszOid = "OID_GEN_MEDIA_SENSE_COUNTS"; break; + + case OID_PNP_CAPABILITIES: pszOid = "OID_PNP_CAPABILITIES"; break; + case OID_PNP_SET_POWER: pszOid = "OID_PNP_SET_POWER"; break; + case OID_PNP_QUERY_POWER: pszOid = "OID_PNP_QUERY_POWER"; break; + case OID_PNP_ADD_WAKE_UP_PATTERN: pszOid = "OID_PNP_ADD_WAKE_UP_PATTERN"; break; + case OID_PNP_REMOVE_WAKE_UP_PATTERN: pszOid = "OID_PNP_REMOVE_WAKE_UP_PATTERN"; break; + case OID_PNP_WAKE_UP_PATTERN_LIST: pszOid = "OID_PNP_WAKE_UP_PATTERN_LIST"; break; + case OID_PNP_ENABLE_WAKE_UP: pszOid = "OID_PNP_ENABLE_WAKE_UP"; break; + case OID_PNP_WAKE_UP_OK: pszOid = "OID_PNP_WAKE_UP_OK"; break; + case OID_PNP_WAKE_UP_ERROR: pszOid = "OID_PNP_WAKE_UP_ERROR"; break; + } + Log(("%s: %s(0x%x) %s(0x%x)\n", pcszFunction, pszType, pRequest->RequestType, pszOid, pRequest->DATA.SET_INFORMATION.Oid)); +# else + RT_NOREF2(pcszFunction, pRequest); +# endif +} + +#endif /* !VBOX_INCLUDED_VBoxNetCmn_win_h */ diff --git a/include/VBox/VBoxOGL.h b/include/VBox/VBoxOGL.h new file mode 100644 index 00000000..df7e27dd --- /dev/null +++ b/include/VBox/VBoxOGL.h @@ -0,0 +1,70 @@ +/* $Id: VBoxOGL.h $ */ +/** @file + * VBox 3D Support API + */ +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxOGL_h +#define VBOX_INCLUDED_VBoxOGL_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/* GUI and VBox OpenGL code require scaling factor value to be stored in container + * of type of 'double'. Communication between them is done via Main. In the same time, + * currently, Main does not like type of 'double' to be used for an interface method parameter. + * An integer type should be used instead. This value is used in order to specify scaling factor in type + * of 'integer' units. It is assumed that GUI feeds Main with its internal scaling factor value + * (which is originally of type of 'double') multiplied by this constant and converted resulting + * value to type of 'uint32_t'. Then Main provides this data to OpenGL HGCM thread. Finally, VBox OpenGL + * code divides received scalar by this constant and converts result to type of 'double'. + * This constant can be increased (multiplied by 10^n) in order to get better precision + * for scaling factor manipulations. */ +#define VBOX_OGL_SCALE_FACTOR_MULTIPLIER 10000.0 + +/* 3D content scale factor range bounds. */ +#define VBOX_OGL_SCALE_FACTOR_MIN 0.01 +#define VBOX_OGL_SCALE_FACTOR_MAX 10.0 + +bool RTCALL VBoxOglIsOfflineRenderingAppropriate(void); +bool RTCALL VBoxOglIs3DAccelerationSupported(void); + +DECLEXPORT(int) VBoxOglSetScaleFactor(uint32_t idScreen, double dScaleFactorW, double dScaleFactorH); + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_VBoxOGL_h */ diff --git a/include/VBox/VBoxPktDmp.h b/include/VBox/VBoxPktDmp.h new file mode 100644 index 00000000..ea6e3303 --- /dev/null +++ b/include/VBox/VBoxPktDmp.h @@ -0,0 +1,186 @@ +/* $Id: VBoxPktDmp.h $ */ +/** @file + * VBoxPktDmp.h - Dump Ethernet frame into debug log. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxPktDmp_h +#define VBOX_INCLUDED_VBoxPktDmp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/net.h> +#include <iprt/log.h> +#if defined(LOG_ENABLED) && !defined(VBOX_DEVICE_STRUCT_TESTCASE) +# include <iprt/asm.h> +#endif + + +DECLINLINE(const char *) vboxEthTypeStr(uint16_t uType) +{ + switch (uType) + { + case RTNET_ETHERTYPE_IPV4: return "IP"; + case RTNET_ETHERTYPE_IPV6: return "IPv6"; + case RTNET_ETHERTYPE_ARP: return "ARP"; + } + return "unknown"; +} + + +DECLINLINE(void) vboxEthPacketDump(const char *pcszInstance, const char *pcszText, const uint8_t *pcPacket, uint32_t cb) +{ +#if defined(LOG_ENABLED) && !defined(VBOX_DEVICE_STRUCT_TESTCASE) + AssertReturnVoid(cb >= 14); + + const uint8_t *pHdr = pcPacket; + const uint8_t *pEnd = pcPacket + cb; + AssertReturnVoid(pEnd - pHdr >= 14); + uint16_t uEthType = RT_N2H_U16(*(uint16_t*)(pHdr+12)); + Log2(("%s: %s (%d bytes), %RTmac => %RTmac, EthType=%s(0x%x)\n", pcszInstance, + pcszText, cb, pHdr+6, pHdr, vboxEthTypeStr(uEthType), uEthType)); + pHdr += sizeof(RTNETETHERHDR); + if (uEthType == RTNET_ETHERTYPE_VLAN) + { + AssertReturnVoid(pEnd - pHdr >= 4); + uEthType = RT_N2H_U16(*(uint16_t*)(pHdr+2)); + Log2((" + VLAN: id=%d EthType=%s(0x%x)\n", RT_N2H_U16(*(uint16_t*)(pHdr)) & 0xFFF, + vboxEthTypeStr(uEthType), uEthType)); + pHdr += 2 * sizeof(uint16_t); + } + uint8_t uProto = 0xFF; + switch (uEthType) + { + case RTNET_ETHERTYPE_IPV6: + AssertReturnVoid(pEnd - pHdr >= 40); + uProto = pHdr[6]; + Log2((" + IPv6: %RTnaipv6 => %RTnaipv6\n", pHdr+8, pHdr+24)); + pHdr += 40; + break; + case RTNET_ETHERTYPE_IPV4: + AssertReturnVoid(pEnd - pHdr >= 20); + uProto = pHdr[9]; + Log2((" + IP: %RTnaipv4 => %RTnaipv4\n", *(uint32_t*)(pHdr+12), *(uint32_t*)(pHdr+16))); + pHdr += (pHdr[0] & 0xF) * 4; + break; + case RTNET_ETHERTYPE_ARP: + AssertReturnVoid(pEnd - pHdr >= 28); + AssertReturnVoid(RT_N2H_U16(*(uint16_t*)(pHdr+2)) == RTNET_ETHERTYPE_IPV4); + switch (RT_N2H_U16(*(uint16_t*)(pHdr+6))) + { + case 1: /* ARP request */ + Log2((" + ARP-REQ: who-has %RTnaipv4 tell %RTnaipv4\n", + *(uint32_t*)(pHdr+24), *(uint32_t*)(pHdr+14))); + break; + case 2: /* ARP reply */ + Log2((" + ARP-RPL: %RTnaipv4 is-at %RTmac\n", + *(uint32_t*)(pHdr+14), pHdr+8)); + break; + default: + Log2((" + ARP: unknown op %d\n", RT_N2H_U16(*(uint16_t*)(pHdr+6)))); + break; + } + break; + /* There is no default case as uProto is initialized with 0xFF */ + } + while (uProto != 0xFF) + { + switch (uProto) + { + case 0: /* IPv6 Hop-by-Hop option*/ + case 60: /* IPv6 Destination option*/ + case 43: /* IPv6 Routing option */ + case 44: /* IPv6 Fragment option */ + Log2((" + IPv6 option (%d): <not implemented>\n", uProto)); + uProto = pHdr[0]; + pHdr += pHdr[1] * 8 + 8; /* Skip to the next extension/protocol */ + break; + case 51: /* IPv6 IPsec AH */ + Log2((" + IPv6 IPsec AH: <not implemented>\n")); + uProto = pHdr[0]; + pHdr += (pHdr[1] + 2) * 4; /* Skip to the next extension/protocol */ + break; + case 50: /* IPv6 IPsec ESP */ + /* Cannot decode IPsec, fall through */ + Log2((" + IPv6 IPsec ESP: <not implemented>\n")); + uProto = 0xFF; + break; + case 59: /* No Next Header */ + Log2((" + IPv6 No Next Header\n")); + uProto = 0xFF; + break; + case 58: /* IPv6-ICMP */ + switch (pHdr[0]) + { + case 1: Log2((" + IPv6-ICMP: destination unreachable, code %d\n", pHdr[1])); break; + case 128: Log2((" + IPv6-ICMP: echo request\n")); break; + case 129: Log2((" + IPv6-ICMP: echo reply\n")); break; + default: Log2((" + IPv6-ICMP: unknown type %d, code %d\n", pHdr[0], pHdr[1])); break; + } + uProto = 0xFF; + break; + case 1: /* ICMP */ + switch (pHdr[0]) + { + case 0: Log2((" + ICMP: echo reply\n")); break; + case 8: Log2((" + ICMP: echo request\n")); break; + case 3: Log2((" + ICMP: destination unreachable, code %d\n", pHdr[1])); break; + default: Log2((" + ICMP: unknown type %d, code %d\n", pHdr[0], pHdr[1])); break; + } + uProto = 0xFF; + break; + case 6: /* TCP */ + Log2((" + TCP: src=%d dst=%d seq=%x ack=%x\n", + RT_N2H_U16(*(uint16_t*)(pHdr)), RT_N2H_U16(*(uint16_t*)(pHdr+2)), + RT_N2H_U32(*(uint32_t*)(pHdr+4)), RT_N2H_U32(*(uint32_t*)(pHdr+8)))); + uProto = 0xFF; + break; + case 17: /* UDP */ + Log2((" + UDP: src=%d dst=%d\n", + RT_N2H_U16(*(uint16_t*)(pHdr)), RT_N2H_U16(*(uint16_t*)(pHdr+2)))); + uProto = 0xFF; + break; + default: + Log2((" + Unknown: proto=0x%x\n", uProto)); + uProto = 0xFF; + break; + } + } + Log3(("%.*Rhxd\n", cb, pcPacket)); +#else + RT_NOREF4(pcszInstance, pcszText, pcPacket, cb); +#endif +} + +#endif /* !VBOX_INCLUDED_VBoxPktDmp_h */ diff --git a/include/VBox/VBoxTpG.h b/include/VBox/VBoxTpG.h new file mode 100644 index 00000000..0105ee52 --- /dev/null +++ b/include/VBox/VBoxTpG.h @@ -0,0 +1,455 @@ +/* $Id: VBoxTpG.h $ */ +/** @file + * VBox Tracepoint Generator Structures. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxTpG_h +#define VBOX_INCLUDED_VBoxTpG_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assert.h> + +RT_C_DECLS_BEGIN + +/** + * 32-bit probe location. + */ +typedef struct VTGPROBELOC32 +{ + uint32_t uLine : 31; + uint32_t fEnabled : 1; + uint32_t idProbe; + uint32_t pszFunction; + uint32_t pProbe; +} VTGPROBELOC32; +AssertCompileSize(VTGPROBELOC32, 16); +/** Pointer to a 32-bit probe location. */ +typedef VTGPROBELOC32 *PVTGPROBELOC32; +/** Pointer to a const 32-bit probe location. */ +typedef VTGPROBELOC32 const *PCVTGPROBELOC32; + +/** + * 64-bit probe location. + */ +typedef struct VTGPROBELOC64 +{ + uint32_t uLine : 31; + uint32_t fEnabled : 1; + uint32_t idProbe; + uint64_t pszFunction; + uint64_t pProbe; + uint64_t uAlignment; +} VTGPROBELOC64; +AssertCompileSize(VTGPROBELOC64, 32); +/** Pointer to a 64-bit probe location. */ +typedef VTGPROBELOC64 *PVTGPROBELOC64; +/** Pointer to a const 64-bit probe location. */ +typedef VTGPROBELOC64 const *PCVTGPROBELOC64; + + +/** + * Probe location. + */ +typedef struct VTGPROBELOC +{ + uint32_t uLine : 31; + uint32_t fEnabled : 1; + uint32_t idProbe; + const char *pszFunction; + struct VTGDESCPROBE *pProbe; +#if ARCH_BITS == 64 + uintptr_t uAlignment; +#endif +} VTGPROBELOC; +AssertCompileSizeAlignment(VTGPROBELOC, 16); +/** Pointer to a probe location. */ +typedef VTGPROBELOC *PVTGPROBELOC; +/** Pointer to a const probe location. */ +typedef VTGPROBELOC const *PCVTGPROBELOC; + +/** @def VTG_OBJ_SECT + * The name of the section containing the other probe data provided by the + * assembly / object generated by VBoxTpG. */ +/** @def VTG_LOC_SECT + * The name of the section containing the VTGPROBELOC structures. This is + * filled by the probe macros, @see VTG_DECL_VTGPROBELOC. */ +/** @def VTG_DECL_VTGPROBELOC + * Declares a static variable, @a a_VarName, of type VTGPROBELOC in the section + * indicated by VTG_LOC_SECT. */ +#if defined(RT_OS_WINDOWS) +# define VTG_OBJ_SECT "VTGObj" +# define VTG_LOC_SECT "VTGPrLc.Data" +# ifdef _MSC_VER +# define VTG_DECL_VTGPROBELOC(a_VarName) \ + __declspec(allocate(VTG_LOC_SECT)) static VTGPROBELOC a_VarName +# elif defined(__GNUC__) || defined(DOXYGEN_RUNNING) +# define VTG_DECL_VTGPROBELOC(a_VarName) \ + static VTGPROBELOC __attribute__((section(VTG_LOC_SECT))) a_VarName +# else +# error "Unsupported Windows compiler!" +# endif + +#elif defined(RT_OS_DARWIN) +# define VTG_OBJ_SECT "__VTGObj" +# define VTG_LOC_SECT "__VTGPrLc" +# define VTG_LOC_SEG "__VTG" +# if defined(__GNUC__) || defined(DOXYGEN_RUNNING) +# define VTG_DECL_VTGPROBELOC(a_VarName) \ + static VTGPROBELOC __attribute__((section(VTG_LOC_SEG "," VTG_LOC_SECT ",regular")/*, aligned(16)*/)) a_VarName +# else +# error "Unsupported Darwin compiler!" +# endif + +#elif defined(RT_OS_OS2) /** @todo This doesn't actually work, but it makes the code compile. */ +# define VTG_OBJ_SECT "__DATA" +# define VTG_LOC_SECT "__VTGPrLc" +# define VTG_LOC_SET "__VTGPrLcSet" +# if defined(__GNUC__) || defined(DOXYGEN_RUNNING) +# define VTG_DECL_VTGPROBELOC(a_VarName) \ + static VTGPROBELOC a_VarName; \ + __asm__ (".stabs \"__VTGPrLcSet\", 23, 0, 0, _" #a_VarName ); + +# else +# error "Unsupported Darwin compiler!" +# endif + +#else /* Assume the rest uses ELF. */ +# define VTG_OBJ_SECT ".VTGObj" +# define VTG_LOC_SECT ".VTGPrLc" +# if defined(__GNUC__) || defined(DOXYGEN_RUNNING) +# define VTG_DECL_VTGPROBELOC(a_VarName) \ + static VTGPROBELOC __attribute__((section(VTG_LOC_SECT))) a_VarName +# else +# error "Unsupported compiler!" +# endif +#endif + +/** VTG string table offset. */ +typedef uint32_t VTGSTROFF; + + +/** @name VTG type flags + * @{ */ +/** Masking out the fixed size if given. */ +#define VTG_TYPE_SIZE_MASK UINT32_C(0x000000ff) +/** Indicates that VTG_TYPE_SIZE_MASK can be applied, UNSIGNED or SIGNED is + * usually set as well, so may PHYS. */ +#define VTG_TYPE_FIXED_SIZED RT_BIT_32(8) +/** It's a pointer type, the size is given by the context the probe fired in. */ +#define VTG_TYPE_POINTER RT_BIT_32(9) +/** A context specfic pointer or address, consult VTG_TYPE_CTX_XXX. */ +#define VTG_TYPE_CTX_POINTER RT_BIT_32(10) +/** The type has the same size as the host architecture. */ +#define VTG_TYPE_HC_ARCH_SIZED RT_BIT_32(11) +/** Const char pointer, requires casting in wrapper headers. */ +#define VTG_TYPE_CONST_CHAR_PTR RT_BIT_32(12) +/** The type applies to ring-3 context. */ +#define VTG_TYPE_CTX_R3 RT_BIT_32(24) +/** The type applies to ring-0 context. */ +#define VTG_TYPE_CTX_R0 RT_BIT_32(25) +/** The type applies to raw-mode context. */ +#define VTG_TYPE_CTX_RC RT_BIT_32(26) +/** The type applies to guest context. */ +#define VTG_TYPE_CTX_GST RT_BIT_32(27) +/** The type context mask. */ +#define VTG_TYPE_CTX_MASK UINT32_C(0x0f000000) +/** The type is automatically converted to a ring-0 pointer. */ +#define VTG_TYPE_AUTO_CONV_PTR RT_BIT_32(28) +/** The type is a physical address. */ +#define VTG_TYPE_PHYS RT_BIT_32(29) +/** The type is unsigned. */ +#define VTG_TYPE_UNSIGNED RT_BIT_32(30) +/** The type is signed. */ +#define VTG_TYPE_SIGNED RT_BIT_32(31) +/** Mask of valid bits (for simple validation). */ +#define VTG_TYPE_VALID_MASK UINT32_C(0xff001fff) +/** @} */ + +/** + * Checks if the VTG type flags indicates a large fixed size argument. + */ +#define VTG_TYPE_IS_LARGE(a_fType) \ + ( ((a_fType) & VTG_TYPE_SIZE_MASK) > 4 && ((a_fType) & VTG_TYPE_FIXED_SIZED) ) + + +/** + * VTG argument descriptor. + */ +typedef struct VTGDESCARG +{ + VTGSTROFF offType; + uint32_t fType; +} VTGDESCARG; +/** Pointer to an argument descriptor. */ +typedef VTGDESCARG *PVTGDESCARG; +/** Pointer to a const argument descriptor. */ +typedef VTGDESCARG const *PCVTGDESCARG; + + +/** + * VTG argument list descriptor. + */ +typedef struct VTGDESCARGLIST +{ + uint8_t cArgs; + uint8_t fHaveLargeArgs; + uint8_t abReserved[2]; + VTGDESCARG aArgs[1]; +} VTGDESCARGLIST; +/** Pointer to a VTG argument list descriptor. */ +typedef VTGDESCARGLIST *PVTGDESCARGLIST; +/** Pointer to a const VTG argument list descriptor. */ +typedef VTGDESCARGLIST const *PCVTGDESCARGLIST; + + +/** + * VTG probe descriptor. + */ +typedef struct VTGDESCPROBE +{ + VTGSTROFF offName; + uint32_t offArgList; + uint16_t idxEnabled; + uint16_t idxProvider; + /** The distance from this structure to the VTG object header. */ + int32_t offObjHdr; +} VTGDESCPROBE; +AssertCompileSize(VTGDESCPROBE, 16); +/** Pointer to a VTG probe descriptor. */ +typedef VTGDESCPROBE *PVTGDESCPROBE; +/** Pointer to a const VTG probe descriptor. */ +typedef VTGDESCPROBE const *PCVTGDESCPROBE; + + +/** + * Code/data stability. + */ +typedef enum kVTGStability +{ + kVTGStability_Invalid = 0, + kVTGStability_Internal, + kVTGStability_Private, + kVTGStability_Obsolete, + kVTGStability_External, + kVTGStability_Unstable, + kVTGStability_Evolving, + kVTGStability_Stable, + kVTGStability_Standard, + kVTGStability_End +} kVTGStability; + +/** + * Data dependency. + */ +typedef enum kVTGClass +{ + kVTGClass_Invalid = 0, + kVTGClass_Unknown, + kVTGClass_Cpu, + kVTGClass_Platform, + kVTGClass_Group, + kVTGClass_Isa, + kVTGClass_Common, + kVTGClass_End +} kVTGClass; + + +/** + * VTG attributes. + */ +typedef struct VTGDESCATTR +{ + uint8_t u8Code; + uint8_t u8Data; + uint8_t u8DataDep; +} VTGDESCATTR; +AssertCompileSize(VTGDESCATTR, 3); +/** Pointer to a const VTG attribute. */ +typedef VTGDESCATTR const *PCVTGDESCATTR; + + +/** + * VTG provider descriptor. + */ +typedef struct VTGDESCPROVIDER +{ + VTGSTROFF offName; + uint16_t iFirstProbe; + uint16_t cProbes; + VTGDESCATTR AttrSelf; + VTGDESCATTR AttrModules; + VTGDESCATTR AttrFunctions; + VTGDESCATTR AttrNames; + VTGDESCATTR AttrArguments; + uint8_t bReserved; + uint32_t volatile cProbesEnabled; + /** This increases every time a probe is enabled or disabled. + * Can be used in non-ring-3 context via PROVIDER_GET_SETTINGS_SEQ_NO() in + * order to only configure probes related stuff when actually required. */ + uint32_t volatile uSettingsSerialNo; +} VTGDESCPROVIDER; +AssertCompileSize(VTGDESCPROVIDER, 32); +/** Pointer to a VTG provider descriptor. */ +typedef VTGDESCPROVIDER *PVTGDESCPROVIDER; +/** Pointer to a const VTG provider descriptor. */ +typedef VTGDESCPROVIDER const *PCVTGDESCPROVIDER; + + +/** + * VTG data object header. + */ +typedef struct VTGOBJHDR +{ + /** Magic value (VTGOBJHDR_MAGIC). */ + char szMagic[24]; + /** The bitness of the structures. + * This only affects the probe location pointers and structures. */ + uint32_t cBits; + /** The size of the VTG object. This excludes the probe locations. */ + uint32_t cbObj; + + /** @name Area Descriptors + * @remarks The offsets are relative to the header. The members are + * ordered by ascending offset (maybe with the exception of the + * probe locations). No overlaps, though there might be zero + * filled gaps between them due to alignment. + * @{ */ + /* 32: */ + /** Offset of the string table (char) relative to this header. */ + uint32_t offStrTab; + /** The size of the string table, in bytes. */ + uint32_t cbStrTab; + /** Offset of the argument lists (VTGDESCARGLIST - variable size) relative + * to this header. */ + uint32_t offArgLists; + /** The size of the argument lists, in bytes. */ + uint32_t cbArgLists; + /* 48: */ + /** Offset of the probe array (VTGDESCPROBE) relative to this header. */ + uint32_t offProbes; + /** The size of the probe array, in bytes. */ + uint32_t cbProbes; + /** Offset of the provider array (VTGDESCPROVIDER) relative to this + * header. */ + uint32_t offProviders; + /** The size of the provider array, in bytes. */ + uint32_t cbProviders; + /* 64: */ + /** Offset of the probe-enabled array (uint32_t) relative to this + * header. */ + uint32_t offProbeEnabled; + /** The size of the probe-enabled array, in bytes. */ + uint32_t cbProbeEnabled; + /** Offset of the probe location array (VTGPROBELOC) relative to this + * header. + * @remarks This is filled in by the first VTG user using uProbeLocs. */ + int32_t offProbeLocs; + /** The size of the probe location array, in bytes. + * @remarks This is filled in by the first VTG user using uProbeLocs. */ + uint32_t cbProbeLocs; + /** @} */ + /* 80: */ + /** + * The probe location array is generated by C code and lives in a + * different section/subsection/segment than the rest of the data. + * + * The assembler cannot generate offsets across sections for most (if not + * all) object formats, so we have to store pointers here. The first user + * of the data will convert these two members into offset and size and fill + * in the offProbeLocs and cbProbeLocs members above. + * + * @remarks Converting these members to offset+size and reusing the members + * to store the converted values isn't possible because of + * raw-mode context modules having relocations associated with the + * fields. + */ + union + { + PVTGPROBELOC p; + uintptr_t uPtr; + uint32_t u32; + uint64_t u64; + } + /** Pointer to the probe location array. */ + uProbeLocs, + /** Pointer to the end of the probe location array. */ + uProbeLocsEnd; + /** UUID for making sharing ring-0 structures for the same ring-3 + * modules easier. */ + RTUUID Uuid; + /** Mac 10.6.x load workaround. + * The linker or/and load messes up the uProbeLocs and uProbeLocsEnd fields + * so that they will be link addresses instead of load addresses. To be + * able to work around it we store the start address of the __VTGObj section + * here and uses it to validate the probe location addresses. */ + uint64_t u64VtgObjSectionStart; + /** Reserved / alignment. */ + uint32_t au32Reserved1[2]; +} VTGOBJHDR; +AssertCompileSize(VTGOBJHDR, 128); +AssertCompileMemberAlignment(VTGOBJHDR, uProbeLocs, 8); +AssertCompileMemberAlignment(VTGOBJHDR, uProbeLocsEnd, 8); +/** Pointer to a VTG data object header. */ +typedef VTGOBJHDR *PVTGOBJHDR; +/** Pointer to a const VTG data object header. */ +typedef VTGOBJHDR const *PCVTGOBJHDR; + +/** The current VTGOBJHDR::szMagic value. */ +#define VTGOBJHDR_MAGIC "VTG Object Header v1.7\0" + +/** The name of the VTG data object header symbol in the object file. */ +extern VTGOBJHDR g_VTGObjHeader; + + +/** @name Macros for converting typical pointer arguments to ring-0 pointers. + * @{ */ +#ifdef IN_RING0 +# define VTG_VM_TO_R0(a_pVM) (a_pVM) +# define VTG_VMCPU_TO_R0(a_pVCpu) (a_pVCpu) +# define VTG_CPUMCTX_TO_R0(a_pVCpu, a_pCtx) (a_pCtx) +#else +# define VTG_VM_TO_R0(a_pVM) ((a_pVM) ? (a_pVM)->pVMR0ForCall : NIL_RTR0PTR) +# define VTG_VMCPU_TO_R0(a_pVCpu) ((a_pVCpu) ? (a_pVCpu)->pVCpuR0ForVtg : NIL_RTR0PTR) +# define VTG_CPUMCTX_TO_R0(a_pVCpu, a_pCtx) ((a_pVCpu) ? (a_pVCpu)->pVCpuR0ForVtg + ((uintptr_t)(a_pCtx) - (uintptr_t)(a_pVCpu)) : NIL_RTR0PTR) +#endif +/** @} */ + + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_VBoxTpG_h */ + diff --git a/include/VBox/VDEPlug.h b/include/VBox/VDEPlug.h new file mode 100644 index 00000000..4463d4fe --- /dev/null +++ b/include/VBox/VDEPlug.h @@ -0,0 +1,74 @@ +/** @file + * libvdeplug header and dynamic symbol loader. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VDEPlug_h +#define VBOX_INCLUDED_VDEPlug_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <stddef.h> +#include <sys/types.h> + +#define LIBVDEPLUG_INTERFACE_VERSION 1 + +#define vde_open(vde_switch, descr, open_args) \ + vde_open_real((vde_switch), (descr), LIBVDEPLUG_INTERFACE_VERSION, (open_args)) + +/** Opaque connection type */ +struct vdeconn; +typedef struct vdeconn VDECONN; + +/** Structure to be passed to the open function describing the connection. + * All members can be left zero to use the default values. */ +struct vde_open_args +{ + /** The port of the switch to connect to. */ + int port; + /** The group to set ownership of the port socket to. */ + char *group; + /** The file mode to set the port socket to. */ + mode_t mode; +}; + +/* Declarations of the functions that we need from the library */ +#define VDEPLUG_GENERATE_HEADER + +#include <VBox/VDEPlugSymDefs.h> + +#undef VDEPLUG_GENERATE_HEADER + +#endif /* !VBOX_INCLUDED_VDEPlug_h */ +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/include/VBox/VDEPlugSymDefs.h b/include/VBox/VDEPlugSymDefs.h new file mode 100644 index 00000000..beaa73cc --- /dev/null +++ b/include/VBox/VDEPlugSymDefs.h @@ -0,0 +1,73 @@ +/** @file + * Symbols from libvdeplug.so to be loaded at runtime for DrvVDE.cpp + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +/** The file name of the DBus library */ +#define VBOX_LIB_VDE_PLUG_NAME "libvdeplug.so" +#define RT_RUNTIME_LOADER_LIB_NAME VBOX_LIB_VDE_PLUG_NAME + +/** The name of the loader function */ +#define RT_RUNTIME_LOADER_FUNCTION DrvVDELoadVDEPlug + +/** The following are the symbols which we need from the library. */ +#define RT_RUNTIME_LOADER_INSERT_SYMBOLS \ + RT_PROXY_STUB(vde_open_real, VDECONN *, \ + (const char *vde_switch, const char *descr, int interface_version, struct vde_open_args *open_args), \ + (vde_switch, descr, interface_version, open_args)) \ + RT_PROXY_STUB(vde_recv, size_t, \ + (VDECONN *conn, void *buf,size_t len, int flags), \ + (conn, buf, len, flags)) \ + RT_PROXY_STUB(vde_send, size_t, \ + (VDECONN *conn, const void *buf, size_t len, int flags), \ + (conn, buf, len, flags)) \ + RT_PROXY_STUB(vde_datafd, int, (VDECONN *conn), (conn)) \ + RT_PROXY_STUB(vde_close, void, (VDECONN *conn), (conn)) + +#ifdef VDEPLUG_GENERATE_HEADER +# define RT_RUNTIME_LOADER_GENERATE_HEADER +# define RT_RUNTIME_LOADER_GENERATE_DECLS +# include <iprt/runtime-loader.h> +# undef RT_RUNTIME_LOADER_GENERATE_HEADER +# undef RT_RUNTIME_LOADER_GENERATE_DECLS +#elif defined (VDEPLUG_GENERATE_BODY) +# define RT_RUNTIME_LOADER_GENERATE_BODY_STUBS +# include <iprt/runtime-loader.h> +# undef RT_RUNTIME_LOADER_GENERATE_BODY_STUBS +#else +# error This file should only be included to generate stubs for loading the libvdeplug library at runtime +#endif + +#undef RT_RUNTIME_LOADER_LIB_NAME +#undef RT_RUNTIME_LOADER_INSERT_SYMBOLS + diff --git a/include/VBox/VMMDev.h b/include/VBox/VMMDev.h new file mode 100644 index 00000000..69618cce --- /dev/null +++ b/include/VBox/VMMDev.h @@ -0,0 +1,2034 @@ +/** @file + * Virtual Device for Guest <-> VMM/Host communication (ADD,DEV). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_VMMDev_h +#define VBOX_INCLUDED_VMMDev_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/param.h> /* for the PCI IDs. */ +#include <VBox/types.h> +#include <VBox/ostypes.h> +#include <VBox/VMMDevCoreTypes.h> +#include <iprt/assertcompile.h> +#include <iprt/errcore.h> + + +#pragma pack(4) /* force structure dword packing here. */ +RT_C_DECLS_BEGIN + + +/** @defgroup grp_vmmdev VMM Device + * + * @note This interface cannot be changed, it can only be extended! + * + * @{ + */ + + +/** Size of VMMDev RAM region accessible by guest. + * Must be big enough to contain VMMDevMemory structure (see further down). + * For now: 4 megabyte. + */ +#define VMMDEV_RAM_SIZE (4 * 256 * PAGE_SIZE) + +/** Size of VMMDev heap region accessible by guest. + * (Must be a power of two (pci range).) + */ +#define VMMDEV_HEAP_SIZE (4 * PAGE_SIZE) + +/** Port for generic request interface (relative offset). */ +#define VMMDEV_PORT_OFF_REQUEST 0 +/** Port for requests that can be handled w/o going to ring-3 (relative offset). + * This works like VMMDevReq_AcknowledgeEvents when read. */ +#define VMMDEV_PORT_OFF_REQUEST_FAST 8 + + +/** @defgroup grp_vmmdev_req VMMDev Generic Request Interface + * @{ + */ + +/** @name Current version of the VMMDev interface. + * + * Additions are allowed to work only if + * additions_major == vmmdev_current && additions_minor <= vmmdev_current. + * Additions version is reported to host (VMMDev) by VMMDevReq_ReportGuestInfo. + * + * @remarks These defines also live in the 16-bit and assembly versions of this + * header. + * @{ + */ +#define VMMDEV_VERSION 0x00010004 +#define VMMDEV_VERSION_MAJOR (VMMDEV_VERSION >> 16) +#define VMMDEV_VERSION_MINOR (VMMDEV_VERSION & 0xffff) +/** @} */ + +/** Maximum request packet size. */ +#define VMMDEV_MAX_VMMDEVREQ_SIZE _1M +/** Maximum number of HGCM parameters. + * @note This used to be 1024, which is kind of insane. Was changed to 32, + * given that (guest) user land can only pass 61 anyway. + * See comments on VBGLIOCHGCMCALL::cParms. */ +#define VMMDEV_MAX_HGCM_PARMS 32 +/** Maximum total size of hgcm buffers in one call. + * @note Used to be 2G, since reduced to 128MB. */ +#define VMMDEV_MAX_HGCM_DATA_SIZE _128M + +/** + * VMMDev request types. + * @note when updating this, adjust vmmdevGetRequestSize() as well + */ +typedef enum VMMDevRequestType +{ + VMMDevReq_InvalidRequest = 0, + VMMDevReq_GetMouseStatus = 1, + VMMDevReq_SetMouseStatus = 2, + VMMDevReq_SetPointerShape = 3, + VMMDevReq_GetHostVersion = 4, + VMMDevReq_Idle = 5, + VMMDevReq_GetHostTime = 10, + VMMDevReq_GetHypervisorInfo = 20, + VMMDevReq_SetHypervisorInfo = 21, + VMMDevReq_RegisterPatchMemory = 22, /**< @since version 3.0.6 */ + VMMDevReq_DeregisterPatchMemory = 23, /**< @since version 3.0.6 */ + VMMDevReq_SetPowerStatus = 30, + VMMDevReq_AcknowledgeEvents = 41, + VMMDevReq_CtlGuestFilterMask = 42, + VMMDevReq_ReportGuestInfo = 50, + VMMDevReq_ReportGuestInfo2 = 58, /**< @since version 3.2.0 */ + VMMDevReq_ReportGuestStatus = 59, /**< @since version 3.2.8 */ + VMMDevReq_ReportGuestUserState = 74, /**< @since version 4.3 */ + /** + * Retrieve a display resize request sent by the host using + * @a IDisplay:setVideoModeHint. Deprecated. + * + * Similar to @a VMMDevReq_GetDisplayChangeRequest2, except that it only + * considers host requests sent for the first virtual display. This guest + * request should not be used in new guest code, and the results are + * undefined if a guest mixes calls to this and + * @a VMMDevReq_GetDisplayChangeRequest2. + */ + VMMDevReq_GetDisplayChangeRequest = 51, + VMMDevReq_VideoModeSupported = 52, + VMMDevReq_GetHeightReduction = 53, + /** + * Retrieve a display resize request sent by the host using + * @a IDisplay:setVideoModeHint. + * + * Queries a display resize request sent from the host. If the + * @a eventAck member is sent to true and there is an unqueried + * request available for one of the virtual display then that request will + * be returned. If several displays have unqueried requests the lowest + * numbered display will be chosen first. Only the most recent unseen + * request for each display is remembered. + * If @a eventAck is set to false, the last host request queried with + * @a eventAck set is resent, or failing that the most recent received from + * the host. If no host request was ever received then all zeros are + * returned. + */ + VMMDevReq_GetDisplayChangeRequest2 = 54, + VMMDevReq_ReportGuestCapabilities = 55, + VMMDevReq_SetGuestCapabilities = 56, + VMMDevReq_VideoModeSupported2 = 57, /**< @since version 3.2.0 */ + VMMDevReq_GetDisplayChangeRequestEx = 80, /**< @since version 4.2.4 */ + VMMDevReq_GetDisplayChangeRequestMulti = 81, +#ifdef VBOX_WITH_HGCM + VMMDevReq_HGCMConnect = 60, + VMMDevReq_HGCMDisconnect = 61, + VMMDevReq_HGCMCall32 = 62, + VMMDevReq_HGCMCall64 = 63, +# ifdef IN_GUEST +# if ARCH_BITS == 64 + VMMDevReq_HGCMCall = VMMDevReq_HGCMCall64, +# elif ARCH_BITS == 32 || ARCH_BITS == 16 + VMMDevReq_HGCMCall = VMMDevReq_HGCMCall32, +# else +# error "Unsupported ARCH_BITS" +# endif +# endif + VMMDevReq_HGCMCancel = 64, + VMMDevReq_HGCMCancel2 = 65, +#endif + VMMDevReq_VideoAccelEnable = 70, + VMMDevReq_VideoAccelFlush = 71, + VMMDevReq_VideoSetVisibleRegion = 72, + VMMDevReq_GetSeamlessChangeRequest = 73, + VMMDevReq_QueryCredentials = 100, + VMMDevReq_ReportCredentialsJudgement = 101, + VMMDevReq_ReportGuestStats = 110, + VMMDevReq_GetMemBalloonChangeRequest = 111, + VMMDevReq_GetStatisticsChangeRequest = 112, + VMMDevReq_ChangeMemBalloon = 113, + VMMDevReq_GetVRDPChangeRequest = 150, + VMMDevReq_LogString = 200, + VMMDevReq_GetCpuHotPlugRequest = 210, + VMMDevReq_SetCpuHotPlugStatus = 211, + VMMDevReq_RegisterSharedModule = 212, + VMMDevReq_UnregisterSharedModule = 213, + VMMDevReq_CheckSharedModules = 214, + VMMDevReq_GetPageSharingStatus = 215, + VMMDevReq_DebugIsPageShared = 216, + VMMDevReq_GetSessionId = 217, /**< @since version 3.2.8 */ + VMMDevReq_WriteCoreDump = 218, + VMMDevReq_GuestHeartbeat = 219, + VMMDevReq_HeartbeatConfigure = 220, + VMMDevReq_NtBugCheck = 221, + VMMDevReq_VideoUpdateMonitorPositions= 222, + VMMDevReq_GetMouseStatusEx = 223, + VMMDevReq_SizeHack = 0x7fffffff +} VMMDevRequestType; + +/** Version of VMMDevRequestHeader structure. */ +#define VMMDEV_REQUEST_HEADER_VERSION (0x10001) + + +/** + * Generic VMMDev request header. + * + * This structure is copied/mirrored by VBGLREQHDR in the VBoxGuest I/O control + * interface. Changes there needs to be mirrored in it. + * + * @sa VBGLREQHDR + */ +typedef struct VMMDevRequestHeader +{ + /** IN: Size of the structure in bytes (including body). + * (VBGLREQHDR uses this for input size and output if reserved1 is zero). */ + uint32_t size; + /** IN: Version of the structure. */ + uint32_t version; + /** IN: Type of the request. + * @note VBGLREQHDR uses this for optional output size. */ + VMMDevRequestType requestType; + /** OUT: VBox status code. */ + int32_t rc; + /** Reserved field no.1. MBZ. + * @note VBGLREQHDR uses this for optional output size, however never for a + * real VMMDev request, only in the I/O control interface. */ + uint32_t reserved1; + /** IN: Requestor information (VMMDEV_REQUESTOR_XXX) when + * VBOXGSTINFO2_F_REQUESTOR_INFO is set, otherwise ignored by the host. */ + uint32_t fRequestor; +} VMMDevRequestHeader; +AssertCompileSize(VMMDevRequestHeader, 24); + +/** @name VMMDEV_REQUESTOR_XXX - Requestor information. + * + * This is information provided to the host by the VBoxGuest device driver, so + * the host can implemented fine grained access to functionality if it likes. + * @bugref{9105} + * + * @{ */ +/** Requestor user not given. */ +#define VMMDEV_REQUESTOR_USR_NOT_GIVEN UINT32_C(0x00000000) +/** The kernel driver (VBoxGuest) is the requestor. */ +#define VMMDEV_REQUESTOR_USR_DRV UINT32_C(0x00000001) +/** Some other kernel driver is the requestor. */ +#define VMMDEV_REQUESTOR_USR_DRV_OTHER UINT32_C(0x00000002) +/** The root or a admin user is the requestor. */ +#define VMMDEV_REQUESTOR_USR_ROOT UINT32_C(0x00000003) +/** Requestor is the windows system user (SID S-1-5-18). */ +#define VMMDEV_REQUESTOR_USR_SYSTEM UINT32_C(0x00000004) +/** Reserved requestor user \#1, treat like VMMDEV_REQUESTOR_USR_USER. */ +#define VMMDEV_REQUESTOR_USR_RESERVED1 UINT32_C(0x00000005) +/** Regular joe user is making the request. */ +#define VMMDEV_REQUESTOR_USR_USER UINT32_C(0x00000006) +/** Requestor is a guest user (or in a guest user group). */ +#define VMMDEV_REQUESTOR_USR_GUEST UINT32_C(0x00000007) +/** User classification mask. */ +#define VMMDEV_REQUESTOR_USR_MASK UINT32_C(0x00000007) + +/** Kernel mode request. + * @note This is zero, so test for VMMDEV_REQUESTOR_USERMODE instead. */ +#define VMMDEV_REQUESTOR_KERNEL UINT32_C(0x00000000) +/** User mode request. */ +#define VMMDEV_REQUESTOR_USERMODE UINT32_C(0x00000008) + +/** Don't know the physical console association of the requestor. */ +#define VMMDEV_REQUESTOR_CON_DONT_KNOW UINT32_C(0x00000000) +/** The request originates with a process that is NOT associated with the + * physical console. */ +#define VMMDEV_REQUESTOR_CON_NO UINT32_C(0x00000010) +/** Requestor process DOES is associated with the physical console. */ +#define VMMDEV_REQUESTOR_CON_YES UINT32_C(0x00000020) +/** Requestor process belongs to user on the physical console, but cannot + * ascertain that it is associated with that login. */ +#define VMMDEV_REQUESTOR_CON_USER UINT32_C(0x00000030) +/** Mask the physical console state of the request. */ +#define VMMDEV_REQUESTOR_CON_MASK UINT32_C(0x00000030) + +/** Requestor is member of special VirtualBox user group (not on windows). */ +#define VMMDEV_REQUESTOR_GRP_VBOX UINT32_C(0x00000080) +/** Requestor is member of wheel / administrators group (SID S-1-5-32-544). */ +#define VMMDEV_REQUESTOR_GRP_WHEEL UINT32_C(0x00000100) + +/** Requestor trust level: Unspecified */ +#define VMMDEV_REQUESTOR_TRUST_NOT_GIVEN UINT32_C(0x00000000) +/** Requestor trust level: Untrusted (SID S-1-16-0) */ +#define VMMDEV_REQUESTOR_TRUST_UNTRUSTED UINT32_C(0x00001000) +/** Requestor trust level: Untrusted (SID S-1-16-4096) */ +#define VMMDEV_REQUESTOR_TRUST_LOW UINT32_C(0x00002000) +/** Requestor trust level: Medium (SID S-1-16-8192) */ +#define VMMDEV_REQUESTOR_TRUST_MEDIUM UINT32_C(0x00003000) +/** Requestor trust level: Medium plus (SID S-1-16-8448) */ +#define VMMDEV_REQUESTOR_TRUST_MEDIUM_PLUS UINT32_C(0x00004000) +/** Requestor trust level: High (SID S-1-16-12288) */ +#define VMMDEV_REQUESTOR_TRUST_HIGH UINT32_C(0x00005000) +/** Requestor trust level: System (SID S-1-16-16384) */ +#define VMMDEV_REQUESTOR_TRUST_SYSTEM UINT32_C(0x00006000) +/** Requestor trust level: Protected or higher (SID S-1-16-20480, S-1-16-28672) + * @note To avoid wasting an unnecessary bit, we combine the two top most + * mandatory security labels on Windows (protected and secure). */ +#define VMMDEV_REQUESTOR_TRUST_PROTECTED UINT32_C(0x00007000) +/** Requestor trust level mask. + * The higher the value, the more the guest trusts the process. */ +#define VMMDEV_REQUESTOR_TRUST_MASK UINT32_C(0x00007000) + +/** Requestor is using the less trusted user device node (/dev/vboxuser). */ +#define VMMDEV_REQUESTOR_USER_DEVICE UINT32_C(0x00008000) +/** There is no user device node (/dev/vboxuser). */ +#define VMMDEV_REQUESTOR_NO_USER_DEVICE UINT32_C(0x00010000) + +/** Legacy value for when VBOXGSTINFO2_F_REQUESTOR_INFO is clear. + * @internal Host only. */ +#define VMMDEV_REQUESTOR_LEGACY UINT32_MAX +/** Lowest conceivable trust level, for error situations of getters. + * @internal Host only. */ +#define VMMDEV_REQUESTOR_LOWEST ( VMMDEV_REQUESTOR_TRUST_UNTRUSTED | VMMDEV_REQUESTOR_USER_DEVICE \ + | VMMDEV_REQUESTOR_CON_NO | VMMDEV_REQUESTOR_USERMODE \ + | VMMDEV_REQUESTOR_USR_GUEST) +/** Used on the host to check whether a requestor value is present or not. */ +#define VMMDEV_REQUESTOR_IS_PRESENT(a_fRequestor) ((a_fRequestor) != VMMDEV_REQUESTOR_LEGACY) +/** @} */ + +/** Initialize a VMMDevRequestHeader structure. + * Same as VBGLREQHDR_INIT_VMMDEV(). */ +#define VMMDEV_REQ_HDR_INIT(a_pHdr, a_cb, a_enmType) \ + do { \ + (a_pHdr)->size = (a_cb); \ + (a_pHdr)->version = VMMDEV_REQUEST_HEADER_VERSION; \ + (a_pHdr)->requestType = (a_enmType); \ + (a_pHdr)->rc = VERR_INTERNAL_ERROR; \ + (a_pHdr)->reserved1 = 0; \ + (a_pHdr)->fRequestor = 0; \ + } while (0) + + +/** + * Mouse status request structure. + * + * Used by VMMDevReq_GetMouseStatus and VMMDevReq_SetMouseStatus. + */ +typedef struct +{ + /** header */ + VMMDevRequestHeader header; + /** Mouse feature mask. See VMMDEV_MOUSE_*. */ + uint32_t mouseFeatures; + /** Mouse x position. */ + int32_t pointerXPos; + /** Mouse y position. */ + int32_t pointerYPos; +} VMMDevReqMouseStatus; +AssertCompileSize(VMMDevReqMouseStatus, 24+12); + + +/** @name Mouse buttons state bits for VMMDevReqMouseStatusEx::fButtons (identical to PDMIMOUSEPORT_BUTTON_XXX). + * @{ */ +/** Left mouse button pressed. */ +#define VMMDEV_MOUSE_BUTTON_LEFT RT_BIT(0) +/** Right mouse button pressed. */ +#define VMMDEV_MOUSE_BUTTON_RIGHT RT_BIT(1) +/** Middle mouse button pressed. */ +#define VMMDEV_MOUSE_BUTTON_MIDDLE RT_BIT(2) +/** X1 mouse button pressed. */ +#define VMMDEV_MOUSE_BUTTON_X1 RT_BIT(3) +/** X2 mouse button pressed. */ +#define VMMDEV_MOUSE_BUTTON_X2 RT_BIT(4) +/** @} */ + + +/** + * Extended mouse status request structure. + * + * Used by VMMDevReq_GetMouseStatusEx. + */ +typedef struct +{ + /** Legacy mouse status request structure. */ + VMMDevReqMouseStatus Core; + /** Mouse wheel vertical mvement. */ + int32_t dz; + /** Mouse wheel horizontal movement. */ + int32_t dw; + /** Mouse buttons state. */ + uint32_t fButtons; +} VMMDevReqMouseStatusEx; +AssertCompileSize(VMMDevReqMouseStatusEx, 24+24); + + +/** @name Mouse capability bits (VMMDevReqMouseStatus::mouseFeatures). + * @{ */ +/** The guest can (== wants to) handle absolute coordinates. */ +#define VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE RT_BIT(0) +/** The host can (== wants to) send absolute coordinates. + * (Input not captured.) */ +#define VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE RT_BIT(1) +/** The guest can *NOT* switch to software cursor and therefore depends on the + * host cursor. + * + * When guest additions are installed and the host has promised to display the + * cursor itself, the guest installs a hardware mouse driver. Don't ask the + * guest to switch to a software cursor then. */ +#define VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR RT_BIT(2) +/** The host does NOT provide support for drawing the cursor itself. */ +#define VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER RT_BIT(3) +/** The guest can read VMMDev events to find out about pointer movement */ +#define VMMDEV_MOUSE_NEW_PROTOCOL RT_BIT(4) +/** If the guest changes the status of the + * VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR bit, the host will honour this */ +#define VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR RT_BIT(5) +/** The host supplies an absolute pointing device. The Guest Additions may + * wish to use this to decide whether to install their own driver */ +#define VMMDEV_MOUSE_HOST_HAS_ABS_DEV RT_BIT(6) +/** The guest can read VMMDev events to find out about full mouse state */ +#define VMMDEV_MOUSE_GUEST_USES_FULL_STATE_PROTOCOL RT_BIT(7) +/** The host can provide full mouse state over VMMDev events */ +#define VMMDEV_MOUSE_HOST_USES_FULL_STATE_PROTOCOL RT_BIT(8) +/** The mask of all VMMDEV_MOUSE_* flags */ +#define VMMDEV_MOUSE_MASK UINT32_C(0x000001ff) +/** The mask of guest capability changes for which notification events should + * be sent */ +#define VMMDEV_MOUSE_NOTIFY_HOST_MASK \ + (VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE | VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR) +/** The mask of all capabilities which the guest can legitimately change */ +#define VMMDEV_MOUSE_GUEST_MASK \ + (VMMDEV_MOUSE_NOTIFY_HOST_MASK | VMMDEV_MOUSE_NEW_PROTOCOL | VMMDEV_MOUSE_GUEST_USES_FULL_STATE_PROTOCOL) +/** The mask of host capability changes for which notification events should + * be sent */ +#define VMMDEV_MOUSE_NOTIFY_GUEST_MASK \ + VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE +/** The mask of all capabilities which the host can legitimately change */ +#define VMMDEV_MOUSE_HOST_MASK \ + ( VMMDEV_MOUSE_NOTIFY_GUEST_MASK \ + | VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER \ + | VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR \ + | VMMDEV_MOUSE_HOST_HAS_ABS_DEV \ + | VMMDEV_MOUSE_HOST_USES_FULL_STATE_PROTOCOL) +/** @} */ + +/** @name Absolute mouse reporting range + * @{ */ +/** @todo Should these be here? They are needed by both host and guest. */ +/** The minumum value our pointing device can return. */ +#define VMMDEV_MOUSE_RANGE_MIN 0 +/** The maximum value our pointing device can return. */ +#define VMMDEV_MOUSE_RANGE_MAX 0xFFFF +/** The full range our pointing device can return. */ +#define VMMDEV_MOUSE_RANGE (VMMDEV_MOUSE_RANGE_MAX - VMMDEV_MOUSE_RANGE_MIN) +/** @} */ + + +/** + * Mouse pointer shape/visibility change request. + * + * Used by VMMDevReq_SetPointerShape. The size is variable. + */ +typedef struct VMMDevReqMousePointer +{ + /** Header. */ + VMMDevRequestHeader header; + /** VBOX_MOUSE_POINTER_* bit flags from VBox/Graphics/VBoxVideo.h. */ + uint32_t fFlags; + /** x coordinate of hot spot. */ + uint32_t xHot; + /** y coordinate of hot spot. */ + uint32_t yHot; + /** Width of the pointer in pixels. */ + uint32_t width; + /** Height of the pointer in scanlines. */ + uint32_t height; + /** Pointer data. + * + **** + * The data consists of 1 bpp AND mask followed by 32 bpp XOR (color) mask. + * + * For pointers without alpha channel the XOR mask pixels are 32 bit values: (lsb)BGR0(msb). + * For pointers with alpha channel the XOR mask consists of (lsb)BGRA(msb) 32 bit values. + * + * Guest driver must create the AND mask for pointers with alpha channel, so if host does not + * support alpha, the pointer could be displayed as a normal color pointer. The AND mask can + * be constructed from alpha values. For example alpha value >= 0xf0 means bit 0 in the AND mask. + * + * The AND mask is 1 bpp bitmap with byte aligned scanlines. Size of AND mask, + * therefore, is cbAnd = (width + 7) / 8 * height. The padding bits at the + * end of any scanline are undefined. + * + * The XOR mask follows the AND mask on the next 4 bytes aligned offset: + * uint8_t *pXor = pAnd + (cbAnd + 3) & ~3 + * Bytes in the gap between the AND and the XOR mask are undefined. + * XOR mask scanlines have no gap between them and size of XOR mask is: + * cXor = width * 4 * height. + **** + * + * Preallocate 4 bytes for accessing actual data as p->pointerData. + */ + char pointerData[4]; +} VMMDevReqMousePointer; +AssertCompileSize(VMMDevReqMousePointer, 24+24); + +/** + * Get the size that a VMMDevReqMousePointer request should have for a given + * size of cursor, including the trailing cursor image and mask data. + * @note an "empty" request still has the four preallocated bytes of data + * + * @returns the size + * @param width the cursor width + * @param height the cursor height + */ +DECLINLINE(size_t) vmmdevGetMousePointerReqSize(uint32_t width, uint32_t height) +{ + size_t cbBase = RT_UOFFSETOF(VMMDevReqMousePointer, pointerData[0]); + size_t cbMask = (width + 7) / 8 * height; + size_t cbArgb = width * height * 4; + return RT_MAX(cbBase + ((cbMask + 3) & ~(size_t)3) + cbArgb, + sizeof(VMMDevReqMousePointer)); +} + + +/** + * String log request structure. + * + * Used by VMMDevReq_LogString. + * @deprecated Use the IPRT logger or VbglR3WriteLog instead. + */ +typedef struct +{ + /** header */ + VMMDevRequestHeader header; + /** variable length string data */ + char szString[1]; +} VMMDevReqLogString; +AssertCompileSize(VMMDevReqLogString, 24+4); + + +/** + * VirtualBox host version request structure. + * + * Used by VMMDevReq_GetHostVersion. + * + * @remarks VBGL uses this to detect the precense of new features in the + * interface. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Major version. */ + uint16_t major; + /** Minor version. */ + uint16_t minor; + /** Build number. */ + uint32_t build; + /** SVN revision. */ + uint32_t revision; + /** Feature mask. */ + uint32_t features; +} VMMDevReqHostVersion; +AssertCompileSize(VMMDevReqHostVersion, 24+16); + +/** @name VMMDEV_HVF_XXX - VMMDevReqHostVersion::features + * @{ */ +/** Physical page lists are supported by HGCM. */ +#define VMMDEV_HVF_HGCM_PHYS_PAGE_LIST RT_BIT_32(0) +/** HGCM supports the embedded buffer parameter type. */ +#define VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS RT_BIT_32(1) +/** HGCM supports the contiguous page list parameter type. */ +#define VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST RT_BIT_32(2) +/** HGCM supports the no-bounce page list parameter type. */ +#define VMMDEV_HVF_HGCM_NO_BOUNCE_PAGE_LIST RT_BIT_32(3) +/** VMMDev supports fast IRQ acknowledgements. */ +#define VMMDEV_HVF_FAST_IRQ_ACK RT_BIT_32(31) +/** @} */ + + +/** + * Guest capabilities structure. + * + * Used by VMMDevReq_ReportGuestCapabilities. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Capabilities (VMMDEV_GUEST_*). */ + uint32_t caps; +} VMMDevReqGuestCapabilities; +AssertCompileSize(VMMDevReqGuestCapabilities, 24+4); + + +/** + * Guest capabilities structure, version 2. + * + * Used by VMMDevReq_SetGuestCapabilities. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Mask of capabilities to be added. */ + uint32_t u32OrMask; + /** Mask of capabilities to be removed. */ + uint32_t u32NotMask; +} VMMDevReqGuestCapabilities2; +AssertCompileSize(VMMDevReqGuestCapabilities2, 24+8); + + +/** + * Idle request structure. + * + * Used by VMMDevReq_Idle. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; +} VMMDevReqIdle; +AssertCompileSize(VMMDevReqIdle, 24); + + +/** + * Host time request structure. + * + * Used by VMMDevReq_GetHostTime. + */ +typedef struct +{ + /** Header */ + VMMDevRequestHeader header; + /** OUT: Time in milliseconds since unix epoch. */ + uint64_t time; +} VMMDevReqHostTime; +AssertCompileSize(VMMDevReqHostTime, 24+8); + + +/** + * Hypervisor info structure. + * + * Used by VMMDevReq_GetHypervisorInfo and VMMDevReq_SetHypervisorInfo. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Guest virtual address of proposed hypervisor start. + * Not used by VMMDevReq_GetHypervisorInfo. + * @todo Make this 64-bit compatible? */ + RTGCPTR32 hypervisorStart; + /** Hypervisor size in bytes. */ + uint32_t hypervisorSize; +} VMMDevReqHypervisorInfo; +AssertCompileSize(VMMDevReqHypervisorInfo, 24+8); + +/** @name Default patch memory size . + * Used by VMMDevReq_RegisterPatchMemory and VMMDevReq_DeregisterPatchMemory. + * @{ */ +#define VMMDEV_GUEST_DEFAULT_PATCHMEM_SIZE 8192 +/** @} */ + +/** + * Patching memory structure. (locked executable & read-only page from the guest's perspective) + * + * Used by VMMDevReq_RegisterPatchMemory and VMMDevReq_DeregisterPatchMemory + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Guest virtual address of the patching page(s). */ + RTGCPTR64 pPatchMem; + /** Patch page size in bytes. */ + uint32_t cbPatchMem; +} VMMDevReqPatchMemory; +AssertCompileSize(VMMDevReqPatchMemory, 24+12); + + +/** + * Guest power requests. + * + * See VMMDevReq_SetPowerStatus and VMMDevPowerStateRequest. + */ +typedef enum +{ + VMMDevPowerState_Invalid = 0, + VMMDevPowerState_Pause = 1, + VMMDevPowerState_PowerOff = 2, + VMMDevPowerState_SaveState = 3, + VMMDevPowerState_SizeHack = 0x7fffffff +} VMMDevPowerState; +AssertCompileSize(VMMDevPowerState, 4); + +/** + * VM power status structure. + * + * Used by VMMDevReq_SetPowerStatus. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Power state request. */ + VMMDevPowerState powerState; +} VMMDevPowerStateRequest; +AssertCompileSize(VMMDevPowerStateRequest, 24+4); + + +/** + * Pending events structure. + * + * Used by VMMDevReq_AcknowledgeEvents. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** OUT: Pending event mask. */ + uint32_t events; +} VMMDevEvents; +AssertCompileSize(VMMDevEvents, 24+4); + + +/** + * Guest event filter mask control. + * + * Used by VMMDevReq_CtlGuestFilterMask. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Mask of events to be added to the filter. */ + uint32_t u32OrMask; + /** Mask of events to be removed from the filter. */ + uint32_t u32NotMask; +} VMMDevCtlGuestFilterMask; +AssertCompileSize(VMMDevCtlGuestFilterMask, 24+8); + + +/** + * Guest information structure. + * + * Used by VMMDevReportGuestInfo and PDMIVMMDEVCONNECTOR::pfnUpdateGuestVersion. + */ +typedef struct VBoxGuestInfo +{ + /** The VMMDev interface version expected by additions. + * *Deprecated*, do not use anymore! Will be removed. */ + uint32_t interfaceVersion; + /** Guest OS type. */ + VBOXOSTYPE osType; +} VBoxGuestInfo; +AssertCompileSize(VBoxGuestInfo, 8); + +/** + * Guest information report. + * + * Used by VMMDevReq_ReportGuestInfo. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Guest information. */ + VBoxGuestInfo guestInfo; +} VMMDevReportGuestInfo; +AssertCompileSize(VMMDevReportGuestInfo, 24+8); + + +/** + * Guest information structure, version 2. + * + * Used by VMMDevReportGuestInfo2 and PDMIVMMDEVCONNECTOR::pfnUpdateGuestVersion2. + */ +typedef struct VBoxGuestInfo2 +{ + /** Major version. */ + uint16_t additionsMajor; + /** Minor version. */ + uint16_t additionsMinor; + /** Build number. */ + uint32_t additionsBuild; + /** SVN revision. */ + uint32_t additionsRevision; + /** Feature mask, VBOXGSTINFO2_F_XXX. */ + uint32_t additionsFeatures; + /** The intentional meaning of this field was: + * Some additional information, for example 'Beta 1' or something like that. + * + * The way it was implemented was implemented: VBOX_VERSION_STRING. + * + * This means the first three members are duplicated in this field (if the guest + * build config is sane). So, the user must check this and chop it off before + * usage. There is, because of the Main code's blind trust in the field's + * content, no way back. */ + char szName[128]; +} VBoxGuestInfo2; +AssertCompileSize(VBoxGuestInfo2, 144); + +/** @name VBOXGSTINFO2_F_XXX - Features + * @{ */ +/** Request header carries requestor information. */ +#define VBOXGSTINFO2_F_REQUESTOR_INFO RT_BIT_32(0) +/** @} */ + + +/** + * Guest information report, version 2. + * + * Used by VMMDevReq_ReportGuestInfo2. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Guest information. */ + VBoxGuestInfo2 guestInfo; +} VMMDevReportGuestInfo2; +AssertCompileSize(VMMDevReportGuestInfo2, 24+144); + + +/** + * The facility class. + * + * This needs to be kept in sync with AdditionsFacilityClass of the Main API! + */ +typedef enum +{ + VBoxGuestFacilityClass_None = 0, + VBoxGuestFacilityClass_Driver = 10, + VBoxGuestFacilityClass_Service = 30, + VBoxGuestFacilityClass_Program = 50, + VBoxGuestFacilityClass_Feature = 100, + VBoxGuestFacilityClass_ThirdParty = 999, + VBoxGuestFacilityClass_All = 0x7ffffffe, + VBoxGuestFacilityClass_SizeHack = 0x7fffffff +} VBoxGuestFacilityClass; +AssertCompileSize(VBoxGuestFacilityClass, 4); + +/** + * Guest status structure. + * + * Used by VMMDevReqGuestStatus. + */ +typedef struct VBoxGuestStatus +{ + /** Facility the status is indicated for. */ + VBoxGuestFacilityType facility; + /** Current guest status. */ + VBoxGuestFacilityStatus status; + /** Flags, not used at the moment. */ + uint32_t flags; +} VBoxGuestStatus; +AssertCompileSize(VBoxGuestStatus, 12); + +/** + * Guest Additions status structure. + * + * Used by VMMDevReq_ReportGuestStatus. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Guest information. */ + VBoxGuestStatus guestStatus; +} VMMDevReportGuestStatus; +AssertCompileSize(VMMDevReportGuestStatus, 24+12); + + +/** + * Guest user status updates. + */ +typedef struct VBoxGuestUserStatus +{ + /** The guest user state to send. */ + VBoxGuestUserState state; + /** Size (in bytes) of szUser. */ + uint32_t cbUser; + /** Size (in bytes) of szDomain. */ + uint32_t cbDomain; + /** Size (in bytes) of aDetails. */ + uint32_t cbDetails; + /** Note: Here begins the dynamically + * allocated region. */ + /** Guest user to report state for. */ + char szUser[1]; + /** Domain the guest user is bound to. */ + char szDomain[1]; + /** Optional details of the state. */ + uint8_t aDetails[1]; +} VBoxGuestUserStatus; +AssertCompileSize(VBoxGuestUserStatus, 20); + + +/** + * Guest user status structure. + * + * Used by VMMDevReq_ReportGuestUserStatus. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Guest user status. */ + VBoxGuestUserStatus status; +} VMMDevReportGuestUserState; +AssertCompileSize(VMMDevReportGuestUserState, 24+20); + + +/** + * Guest statistics structure. + * + * Used by VMMDevReportGuestStats and PDMIVMMDEVCONNECTOR::pfnReportStatistics. + */ +typedef struct VBoxGuestStatistics +{ + /** Virtual CPU ID. */ + uint32_t u32CpuId; + /** Reported statistics. */ + uint32_t u32StatCaps; + /** Idle CPU load (0-100) for last interval. */ + uint32_t u32CpuLoad_Idle; + /** Kernel CPU load (0-100) for last interval. */ + uint32_t u32CpuLoad_Kernel; + /** User CPU load (0-100) for last interval. */ + uint32_t u32CpuLoad_User; + /** Nr of threads. */ + uint32_t u32Threads; + /** Nr of processes. */ + uint32_t u32Processes; + /** Nr of handles. */ + uint32_t u32Handles; + /** Memory load (0-100). */ + uint32_t u32MemoryLoad; + /** Page size of guest system. */ + uint32_t u32PageSize; + /** Total physical memory (in 4KB pages). */ + uint32_t u32PhysMemTotal; + /** Available physical memory (in 4KB pages). */ + uint32_t u32PhysMemAvail; + /** Ballooned physical memory (in 4KB pages). */ + uint32_t u32PhysMemBalloon; + /** Total number of committed memory (which is not necessarily in-use) (in 4KB pages). */ + uint32_t u32MemCommitTotal; + /** Total amount of memory used by the kernel (in 4KB pages). */ + uint32_t u32MemKernelTotal; + /** Total amount of paged memory used by the kernel (in 4KB pages). */ + uint32_t u32MemKernelPaged; + /** Total amount of nonpaged memory used by the kernel (in 4KB pages). */ + uint32_t u32MemKernelNonPaged; + /** Total amount of memory used for the system cache (in 4KB pages). */ + uint32_t u32MemSystemCache; + /** Pagefile size (in 4KB pages). */ + uint32_t u32PageFileSize; +} VBoxGuestStatistics; +AssertCompileSize(VBoxGuestStatistics, 19*4); + +/** @name Guest statistics values (VBoxGuestStatistics::u32StatCaps). + * @{ */ +#define VBOX_GUEST_STAT_CPU_LOAD_IDLE RT_BIT(0) +#define VBOX_GUEST_STAT_CPU_LOAD_KERNEL RT_BIT(1) +#define VBOX_GUEST_STAT_CPU_LOAD_USER RT_BIT(2) +#define VBOX_GUEST_STAT_THREADS RT_BIT(3) +#define VBOX_GUEST_STAT_PROCESSES RT_BIT(4) +#define VBOX_GUEST_STAT_HANDLES RT_BIT(5) +#define VBOX_GUEST_STAT_MEMORY_LOAD RT_BIT(6) +#define VBOX_GUEST_STAT_PHYS_MEM_TOTAL RT_BIT(7) +#define VBOX_GUEST_STAT_PHYS_MEM_AVAIL RT_BIT(8) +#define VBOX_GUEST_STAT_PHYS_MEM_BALLOON RT_BIT(9) +#define VBOX_GUEST_STAT_MEM_COMMIT_TOTAL RT_BIT(10) +#define VBOX_GUEST_STAT_MEM_KERNEL_TOTAL RT_BIT(11) +#define VBOX_GUEST_STAT_MEM_KERNEL_PAGED RT_BIT(12) +#define VBOX_GUEST_STAT_MEM_KERNEL_NONPAGED RT_BIT(13) +#define VBOX_GUEST_STAT_MEM_SYSTEM_CACHE RT_BIT(14) +#define VBOX_GUEST_STAT_PAGE_FILE_SIZE RT_BIT(15) +/** @} */ + +/** + * Guest statistics command structure. + * + * Used by VMMDevReq_ReportGuestStats. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Guest information. */ + VBoxGuestStatistics guestStats; +} VMMDevReportGuestStats; +AssertCompileSize(VMMDevReportGuestStats, 24+19*4); + + +/** Memory balloon change request structure. */ +#define VMMDEV_MAX_MEMORY_BALLOON(PhysMemTotal) ( (9 * (PhysMemTotal)) / 10 ) + +/** + * Poll for ballooning change request. + * + * Used by VMMDevReq_GetMemBalloonChangeRequest. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Balloon size in megabytes. */ + uint32_t cBalloonChunks; + /** Guest ram size in megabytes. */ + uint32_t cPhysMemChunks; + /** Setting this to VMMDEV_EVENT_BALLOON_CHANGE_REQUEST indicates that the + * request is a response to that event. + * (Don't confuse this with VMMDevReq_AcknowledgeEvents.) */ + uint32_t eventAck; +} VMMDevGetMemBalloonChangeRequest; +AssertCompileSize(VMMDevGetMemBalloonChangeRequest, 24+12); + + +/** + * Change the size of the balloon. + * + * Used by VMMDevReq_ChangeMemBalloon. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** The number of pages in the array. */ + uint32_t cPages; + /** true = inflate, false = deflate. */ + uint32_t fInflate; + /** Physical address (RTGCPHYS) of each page, variable size. */ + RTGCPHYS aPhysPage[1]; +} VMMDevChangeMemBalloon; +AssertCompileSize(VMMDevChangeMemBalloon, 24+16); + + +/** + * Guest statistics interval change request structure. + * + * Used by VMMDevReq_GetStatisticsChangeRequest. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** The interval in seconds. */ + uint32_t u32StatInterval; + /** Setting this to VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST indicates + * that the request is a response to that event. + * (Don't confuse this with VMMDevReq_AcknowledgeEvents.) */ + uint32_t eventAck; +} VMMDevGetStatisticsChangeRequest; +AssertCompileSize(VMMDevGetStatisticsChangeRequest, 24+8); + + +/** The size of a string field in the credentials request (including '\\0'). + * @see VMMDevCredentials */ +#define VMMDEV_CREDENTIALS_SZ_SIZE 128 + +/** + * Credentials request structure. + * + * Used by VMMDevReq_QueryCredentials. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** IN/OUT: Request flags. */ + uint32_t u32Flags; + /** OUT: User name (UTF-8). */ + char szUserName[VMMDEV_CREDENTIALS_SZ_SIZE]; + /** OUT: Password (UTF-8). */ + char szPassword[VMMDEV_CREDENTIALS_SZ_SIZE]; + /** OUT: Domain name (UTF-8). */ + char szDomain[VMMDEV_CREDENTIALS_SZ_SIZE]; +} VMMDevCredentials; +AssertCompileSize(VMMDevCredentials, 24+4+3*128); + +/** @name Credentials request flag (VMMDevCredentials::u32Flags) + * @{ */ +/** query from host whether credentials are present */ +#define VMMDEV_CREDENTIALS_QUERYPRESENCE RT_BIT(1) +/** read credentials from host (can be combined with clear) */ +#define VMMDEV_CREDENTIALS_READ RT_BIT(2) +/** clear credentials on host (can be combined with read) */ +#define VMMDEV_CREDENTIALS_CLEAR RT_BIT(3) +/** read credentials for judgement in the guest */ +#define VMMDEV_CREDENTIALS_READJUDGE RT_BIT(8) +/** clear credentials for judegement on the host */ +#define VMMDEV_CREDENTIALS_CLEARJUDGE RT_BIT(9) +/** report credentials acceptance by guest */ +#define VMMDEV_CREDENTIALS_JUDGE_OK RT_BIT(10) +/** report credentials denial by guest */ +#define VMMDEV_CREDENTIALS_JUDGE_DENY RT_BIT(11) +/** report that no judgement could be made by guest */ +#define VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT RT_BIT(12) + +/** flag telling the guest that credentials are present */ +#define VMMDEV_CREDENTIALS_PRESENT RT_BIT(16) +/** flag telling guest that local logons should be prohibited */ +#define VMMDEV_CREDENTIALS_NOLOCALLOGON RT_BIT(17) +/** @} */ + + +/** + * Seamless mode change request structure. + * + * Used by VMMDevReq_GetSeamlessChangeRequest. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + + /** New seamless mode. */ + VMMDevSeamlessMode mode; + /** Setting this to VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST indicates + * that the request is a response to that event. + * (Don't confuse this with VMMDevReq_AcknowledgeEvents.) */ + uint32_t eventAck; +} VMMDevSeamlessChangeRequest; +AssertCompileSize(VMMDevSeamlessChangeRequest, 24+8); +AssertCompileMemberOffset(VMMDevSeamlessChangeRequest, eventAck, 24+4); + + +/** + * Display change request structure. + * + * Used by VMMDevReq_GetDisplayChangeRequest. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Horizontal pixel resolution (0 = do not change). */ + uint32_t xres; + /** Vertical pixel resolution (0 = do not change). */ + uint32_t yres; + /** Bits per pixel (0 = do not change). */ + uint32_t bpp; + /** Setting this to VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST indicates + * that the request is a response to that event. + * (Don't confuse this with VMMDevReq_AcknowledgeEvents.) */ + uint32_t eventAck; +} VMMDevDisplayChangeRequest; +AssertCompileSize(VMMDevDisplayChangeRequest, 24+16); + + +/** + * Display change request structure, version 2. + * + * Used by VMMDevReq_GetDisplayChangeRequest2. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Horizontal pixel resolution (0 = do not change). */ + uint32_t xres; + /** Vertical pixel resolution (0 = do not change). */ + uint32_t yres; + /** Bits per pixel (0 = do not change). */ + uint32_t bpp; + /** Setting this to VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST indicates + * that the request is a response to that event. + * (Don't confuse this with VMMDevReq_AcknowledgeEvents.) */ + uint32_t eventAck; + /** 0 for primary display, 1 for the first secondary, etc. */ + uint32_t display; +} VMMDevDisplayChangeRequest2; +AssertCompileSize(VMMDevDisplayChangeRequest2, 24+20); + + +/** + * Display change request structure, version Extended. + * + * Used by VMMDevReq_GetDisplayChangeRequestEx. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Horizontal pixel resolution (0 = do not change). */ + uint32_t xres; + /** Vertical pixel resolution (0 = do not change). */ + uint32_t yres; + /** Bits per pixel (0 = do not change). */ + uint32_t bpp; + /** Setting this to VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST indicates + * that the request is a response to that event. + * (Don't confuse this with VMMDevReq_AcknowledgeEvents.) */ + uint32_t eventAck; + /** 0 for primary display, 1 for the first secondary, etc. */ + uint32_t display; + /** New OriginX of secondary virtual screen */ + uint32_t cxOrigin; + /** New OriginY of secondary virtual screen */ + uint32_t cyOrigin; + /** Change in origin of the secondary virtaul scree is + * required */ + bool fChangeOrigin; + /** secondary virtual screen enabled or disabled */ + bool fEnabled; +} VMMDevDisplayChangeRequestEx; +AssertCompileSize(VMMDevDisplayChangeRequestEx, 24+32); + + +/** Flags for VMMDevDisplayDef::fDisplayFlags */ +#define VMMDEV_DISPLAY_PRIMARY UINT32_C(0x00000001) /**< Primary display. */ +#define VMMDEV_DISPLAY_DISABLED UINT32_C(0x00000002) /**< Display is disabled. */ +#define VMMDEV_DISPLAY_ORIGIN UINT32_C(0x00000004) /**< Change position of the diplay. */ +#define VMMDEV_DISPLAY_CX UINT32_C(0x00000008) /**< Change the horizontal resolution of the display. */ +#define VMMDEV_DISPLAY_CY UINT32_C(0x00000010) /**< Change the vertical resolution of the display. */ +#define VMMDEV_DISPLAY_BPP UINT32_C(0x00000020) /**< Change the color depth of the display. */ + +/** Definition of one monitor. Used by VMMDevReq_GetDisplayChangeRequestMulti. */ +typedef struct VMMDevDisplayDef +{ + uint32_t fDisplayFlags; /**< VMMDEV_DISPLAY_* flags. */ + uint32_t idDisplay; /**< The display number. */ + int32_t xOrigin; /**< New OriginX of the guest screen. */ + int32_t yOrigin; /**< New OriginY of the guest screen. */ + uint32_t cx; /**< Horizontal pixel resolution. */ + uint32_t cy; /**< Vertical pixel resolution. */ + uint32_t cBitsPerPixel; /**< Bits per pixel. */ +} VMMDevDisplayDef; +AssertCompileSize(VMMDevDisplayDef, 28); + +/** Multimonitor display change request structure. Used by VMMDevReq_GetDisplayChangeRequestMulti. */ +typedef struct VMMDevDisplayChangeRequestMulti +{ + VMMDevRequestHeader header; /**< Header. */ + uint32_t eventAck; /**< Setting this to VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST indicates + * that the request is a response to that event. + * (Don't confuse this with VMMDevReq_AcknowledgeEvents.) */ + uint32_t cDisplays; /**< Number of monitors. In: how many the guest expects. + * Out: how many the host provided. */ + VMMDevDisplayDef aDisplays[1]; /**< Layout of monitors. */ +} VMMDevDisplayChangeRequestMulti; +AssertCompileSize(VMMDevDisplayChangeRequestMulti, 24+8+28); + + +/** + * Video mode supported request structure. + * + * Used by VMMDevReq_VideoModeSupported. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** IN: Horizontal pixel resolution. */ + uint32_t width; + /** IN: Vertical pixel resolution. */ + uint32_t height; + /** IN: Bits per pixel. */ + uint32_t bpp; + /** OUT: Support indicator. */ + bool fSupported; +} VMMDevVideoModeSupportedRequest; +AssertCompileSize(VMMDevVideoModeSupportedRequest, 24+16); + +/** + * Video mode supported request structure for a specific display. + * + * Used by VMMDevReq_VideoModeSupported2. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** IN: The guest display number. */ + uint32_t display; + /** IN: Horizontal pixel resolution. */ + uint32_t width; + /** IN: Vertical pixel resolution. */ + uint32_t height; + /** IN: Bits per pixel. */ + uint32_t bpp; + /** OUT: Support indicator. */ + bool fSupported; +} VMMDevVideoModeSupportedRequest2; +AssertCompileSize(VMMDevVideoModeSupportedRequest2, 24+20); + +/** + * Video modes height reduction request structure. + * + * Used by VMMDevReq_GetHeightReduction. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** OUT: Height reduction in pixels. */ + uint32_t heightReduction; +} VMMDevGetHeightReductionRequest; +AssertCompileSize(VMMDevGetHeightReductionRequest, 24+4); + + +/** + * VRDP change request structure. + * + * Used by VMMDevReq_GetVRDPChangeRequest. + */ +typedef struct +{ + /** Header */ + VMMDevRequestHeader header; + /** Whether VRDP is active or not. */ + uint8_t u8VRDPActive; + /** The configured experience level for active VRDP. */ + uint32_t u32VRDPExperienceLevel; +} VMMDevVRDPChangeRequest; +AssertCompileSize(VMMDevVRDPChangeRequest, 24+8); +AssertCompileMemberOffset(VMMDevVRDPChangeRequest, u8VRDPActive, 24); +AssertCompileMemberOffset(VMMDevVRDPChangeRequest, u32VRDPExperienceLevel, 24+4); + +/** @name VRDP Experience level (VMMDevVRDPChangeRequest::u32VRDPExperienceLevel) + * @{ */ +#define VRDP_EXPERIENCE_LEVEL_ZERO 0 /**< Theming disabled. */ +#define VRDP_EXPERIENCE_LEVEL_LOW 1 /**< Full window dragging and desktop wallpaper disabled. */ +#define VRDP_EXPERIENCE_LEVEL_MEDIUM 2 /**< Font smoothing, gradients. */ +#define VRDP_EXPERIENCE_LEVEL_HIGH 3 /**< Animation effects disabled. */ +#define VRDP_EXPERIENCE_LEVEL_FULL 4 /**< Everything enabled. */ +/** @} */ + + +/** + * VBVA enable request structure. + * + * Used by VMMDevReq_VideoAccelEnable. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** 0 - disable, !0 - enable. */ + uint32_t u32Enable; + /** The size of VBVAMEMORY::au8RingBuffer expected by driver. + * The host will refuse to enable VBVA if the size is not equal to + * VBVA_RING_BUFFER_SIZE. + */ + uint32_t cbRingBuffer; + /** Guest initializes the status to 0. Host sets appropriate VBVA_F_STATUS_ flags. */ + uint32_t fu32Status; +} VMMDevVideoAccelEnable; +AssertCompileSize(VMMDevVideoAccelEnable, 24+12); + +/** @name VMMDevVideoAccelEnable::fu32Status. + * @{ */ +#define VBVA_F_STATUS_ACCEPTED (0x01) +#define VBVA_F_STATUS_ENABLED (0x02) +/** @} */ + + +/** + * VBVA flush request structure. + * + * Used by VMMDevReq_VideoAccelFlush. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; +} VMMDevVideoAccelFlush; +AssertCompileSize(VMMDevVideoAccelFlush, 24); + + +/** + * VBVA set visible region request structure. + * + * Used by VMMDevReq_VideoSetVisibleRegion. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Number of rectangles */ + uint32_t cRect; + /** Rectangle array. + * @todo array is spelled aRects[1]. */ + RTRECT Rect; +} VMMDevVideoSetVisibleRegion; +AssertCompileSize(RTRECT, 16); +AssertCompileSize(VMMDevVideoSetVisibleRegion, 24+4+16); + +/** + * VBVA monitor positions update request structure. + * + * Used by VMMDevReq_VideoUpdateMonitorPositions. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Number of monitor positions (monitors) */ + uint32_t cPositions; + /** Positions array.*/ + RTPOINT aPositions[1]; +} VMMDevVideoUpdateMonitorPositions; +AssertCompileSize(RTPOINT, 8); +AssertCompileSize(VMMDevVideoUpdateMonitorPositions, 24+4+8); + +/** + * CPU event types. + */ +typedef enum +{ + VMMDevCpuStatusType_Invalid = 0, + VMMDevCpuStatusType_Disable = 1, + VMMDevCpuStatusType_Enable = 2, + VMMDevCpuStatusType_SizeHack = 0x7fffffff +} VMMDevCpuStatusType; + +/** + * CPU hotplug event status request. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Status type */ + VMMDevCpuStatusType enmStatusType; +} VMMDevCpuHotPlugStatusRequest; +AssertCompileSize(VMMDevCpuHotPlugStatusRequest, 24+4); + +/** + * Get the ID of the changed CPU and event type. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Event type */ + VMMDevCpuEventType enmEventType; + /** core id of the CPU changed */ + uint32_t idCpuCore; + /** package id of the CPU changed */ + uint32_t idCpuPackage; +} VMMDevGetCpuHotPlugRequest; +AssertCompileSize(VMMDevGetCpuHotPlugRequest, 24+4+4+4); + + +AssertCompileSize(VMMDEVSHAREDREGIONDESC, 16); /* structure was promoted to VBox/types.h. */ + +#define VMMDEVSHAREDREGIONDESC_MAX 32 + +/** + * Shared module registration + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Shared module size. */ + uint32_t cbModule; + /** Number of included region descriptors */ + uint32_t cRegions; + /** Base address of the shared module. */ + RTGCPTR64 GCBaseAddr; + /** Guest OS type. */ + VBOXOSFAMILY enmGuestOS; + /** Alignment. */ + uint32_t u32Align; + /** Module name */ + char szName[128]; + /** Module version */ + char szVersion[16]; + /** Shared region descriptor(s). */ + VMMDEVSHAREDREGIONDESC aRegions[1]; +} VMMDevSharedModuleRegistrationRequest; +AssertCompileSize(VMMDevSharedModuleRegistrationRequest, 24+4+4+8+4+4+128+16+16); + + +/** + * Shared module unregistration + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Shared module size. */ + uint32_t cbModule; + /** Align at 8 byte boundary. */ + uint32_t u32Alignment; + /** Base address of the shared module. */ + RTGCPTR64 GCBaseAddr; + /** Module name */ + char szName[128]; + /** Module version */ + char szVersion[16]; +} VMMDevSharedModuleUnregistrationRequest; +AssertCompileSize(VMMDevSharedModuleUnregistrationRequest, 24+4+4+8+128+16); + + +/** + * Shared module periodic check + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; +} VMMDevSharedModuleCheckRequest; +AssertCompileSize(VMMDevSharedModuleCheckRequest, 24); + +/** + * Paging sharing enabled query + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Enabled flag (out) */ + bool fEnabled; + /** Alignment */ + bool fAlignment[3]; +} VMMDevPageSharingStatusRequest; +AssertCompileSize(VMMDevPageSharingStatusRequest, 24+4); + + +/** + * Page sharing status query (debug build only) + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Page address. */ + RTGCPTR GCPtrPage; + /** Page flags. */ + uint64_t uPageFlags; + /** Shared flag (out) */ + bool fShared; + /** Alignment */ + bool fAlignment[3]; +} VMMDevPageIsSharedRequest; + +/** + * Session id request structure. + * + * Used by VMMDevReq_GetSessionId. + */ +typedef struct +{ + /** Header */ + VMMDevRequestHeader header; + /** OUT: unique session id; the id will be different after each start, reset or restore of the VM */ + uint64_t idSession; +} VMMDevReqSessionId; +AssertCompileSize(VMMDevReqSessionId, 24+8); + + +/** + * Write Core Dump request. + * + * Used by VMMDevReq_WriteCoreDump. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Flags (reserved, MBZ). */ + uint32_t fFlags; +} VMMDevReqWriteCoreDump; +AssertCompileSize(VMMDevReqWriteCoreDump, 24+4); + + +/** + * Heart beat check state structure. + * Used by VMMDevReq_HeartbeatConfigure. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** OUT: Guest heartbeat interval in nanosec. */ + uint64_t cNsInterval; + /** Heartbeat check flag. */ + bool fEnabled; +} VMMDevReqHeartbeat; +AssertCompileSize(VMMDevReqHeartbeat, 24+12); + + +/** + * NT bug check report. + * Used by VMMDevReq_NtBugCheck. + * @remarks Can be issued with just the header if no more data is available. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** The bug check number (P0). */ + uint64_t uBugCheck; + /** The four bug check parameters. */ + uint64_t auParameters[4]; +} VMMDevReqNtBugCheck; +AssertCompileSize(VMMDevReqNtBugCheck, 24+40); + + + +#ifdef VBOX_WITH_HGCM + +/** @name HGCM flags. + * @{ + */ +# define VBOX_HGCM_REQ_DONE RT_BIT_32(VBOX_HGCM_REQ_DONE_BIT) +# define VBOX_HGCM_REQ_DONE_BIT 0 +# define VBOX_HGCM_REQ_CANCELLED (0x2) +/** @} */ + +/** + * HGCM request header. + */ +typedef struct VMMDevHGCMRequestHeader +{ + /** Request header. */ + VMMDevRequestHeader header; + + /** HGCM flags. */ + uint32_t fu32Flags; + + /** Result code. */ + int32_t result; +} VMMDevHGCMRequestHeader; +AssertCompileSize(VMMDevHGCMRequestHeader, 24+8); + +/** + * HGCM connect request structure. + * + * Used by VMMDevReq_HGCMConnect. + */ +typedef struct +{ + /** HGCM request header. */ + VMMDevHGCMRequestHeader header; + + /** IN: Description of service to connect to. */ + HGCMServiceLocation loc; + + /** OUT: Client identifier assigned by local instance of HGCM. */ + uint32_t u32ClientID; +} VMMDevHGCMConnect; +AssertCompileSize(VMMDevHGCMConnect, 32+132+4); + + +/** + * HGCM disconnect request structure. + * + * Used by VMMDevReq_HGCMDisconnect. + */ +typedef struct +{ + /** HGCM request header. */ + VMMDevHGCMRequestHeader header; + + /** IN: Client identifier. */ + uint32_t u32ClientID; +} VMMDevHGCMDisconnect; +AssertCompileSize(VMMDevHGCMDisconnect, 32+4); + +/** + * HGCM call request structure. + * + * Used by VMMDevReq_HGCMCall32 and VMMDevReq_HGCMCall64. + */ +typedef struct +{ + /* request header */ + VMMDevHGCMRequestHeader header; + + /** IN: Client identifier. */ + uint32_t u32ClientID; + /** IN: Service function number. */ + uint32_t u32Function; + /** IN: Number of parameters. */ + uint32_t cParms; + /** Parameters follow in form: HGCMFunctionParameter aParms[X]; */ +} VMMDevHGCMCall; +AssertCompileSize(VMMDevHGCMCall, 32+12); + +/** @name Direction of data transfer (HGCMPageListInfo::flags). Bit flags. + * @{ */ +#define VBOX_HGCM_F_PARM_DIRECTION_NONE UINT32_C(0x00000000) +#define VBOX_HGCM_F_PARM_DIRECTION_TO_HOST UINT32_C(0x00000001) +#define VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST UINT32_C(0x00000002) +#define VBOX_HGCM_F_PARM_DIRECTION_BOTH UINT32_C(0x00000003) +#define VBOX_HGCM_F_PARM_DIRECTION_MASK UINT32_C(0x00000003) +/** Macro for validating that the specified flags are valid. */ +#define VBOX_HGCM_F_PARM_ARE_VALID(fFlags) \ + ( ((fFlags) & VBOX_HGCM_F_PARM_DIRECTION_MASK) \ + && !((fFlags) & ~VBOX_HGCM_F_PARM_DIRECTION_MASK) ) +/** @} */ + +/** + * VMMDevHGCMParmType_PageList points to this structure to actually describe the + * buffer. + */ +typedef struct +{ + uint32_t flags; /**< VBOX_HGCM_F_PARM_*. */ + uint16_t offFirstPage; /**< Offset in the first page where data begins. */ + uint16_t cPages; /**< Number of pages. */ + RTGCPHYS64 aPages[1]; /**< Page addresses. */ +} HGCMPageListInfo; +AssertCompileSize(HGCMPageListInfo, 4+2+2+8); + + +/** Get the pointer to the first parmater of a HGCM call request. */ +# define VMMDEV_HGCM_CALL_PARMS(a) ((HGCMFunctionParameter *)((uint8_t *)(a) + sizeof (VMMDevHGCMCall))) +/** Get the pointer to the first parmater of a 32-bit HGCM call request. */ +# define VMMDEV_HGCM_CALL_PARMS32(a) ((HGCMFunctionParameter32 *)((uint8_t *)(a) + sizeof (VMMDevHGCMCall))) + +# ifdef VBOX_WITH_64_BITS_GUESTS +/* Explicit defines for the host code. */ +# ifdef VBOX_HGCM_HOST_CODE +# define VMMDEV_HGCM_CALL_PARMS32(a) ((HGCMFunctionParameter32 *)((uint8_t *)(a) + sizeof (VMMDevHGCMCall))) +# define VMMDEV_HGCM_CALL_PARMS64(a) ((HGCMFunctionParameter64 *)((uint8_t *)(a) + sizeof (VMMDevHGCMCall))) +# endif /* VBOX_HGCM_HOST_CODE */ +# endif /* VBOX_WITH_64_BITS_GUESTS */ + +# define VBOX_HGCM_MAX_PARMS 32 + +/** + * HGCM cancel request structure. + * + * The Cancel request is issued using the same physical memory address as was + * used for the corresponding initial HGCMCall. + * + * Used by VMMDevReq_HGCMCancel. + */ +typedef struct +{ + /** Header. */ + VMMDevHGCMRequestHeader header; +} VMMDevHGCMCancel; +AssertCompileSize(VMMDevHGCMCancel, 32); + +/** + * HGCM cancel request structure, version 2. + * + * Used by VMMDevReq_HGCMCancel2. + * + * VINF_SUCCESS when cancelled. + * VERR_NOT_FOUND if the specified request cannot be found. + * VERR_INVALID_PARAMETER if the address is invalid valid. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** The physical address of the request to cancel. */ + RTGCPHYS32 physReqToCancel; +} VMMDevHGCMCancel2; +AssertCompileSize(VMMDevHGCMCancel2, 24+4); + +#endif /* VBOX_WITH_HGCM */ + + +/** + * Inline helper to determine the request size for the given operation. + * Returns 0 if the given operation is not handled and/or supported. + * + * @returns Size. + * @param requestType The VMMDev request type. + */ +DECLINLINE(size_t) vmmdevGetRequestSize(VMMDevRequestType requestType) +{ + switch (requestType) + { + case VMMDevReq_GetMouseStatus: + case VMMDevReq_SetMouseStatus: + return sizeof(VMMDevReqMouseStatus); + case VMMDevReq_GetMouseStatusEx: + return sizeof(VMMDevReqMouseStatusEx); + case VMMDevReq_SetPointerShape: + return sizeof(VMMDevReqMousePointer); + case VMMDevReq_GetHostVersion: + return sizeof(VMMDevReqHostVersion); + case VMMDevReq_Idle: + return sizeof(VMMDevReqIdle); + case VMMDevReq_GetHostTime: + return sizeof(VMMDevReqHostTime); + case VMMDevReq_GetHypervisorInfo: + case VMMDevReq_SetHypervisorInfo: + return sizeof(VMMDevReqHypervisorInfo); + case VMMDevReq_RegisterPatchMemory: + case VMMDevReq_DeregisterPatchMemory: + return sizeof(VMMDevReqPatchMemory); + case VMMDevReq_SetPowerStatus: + return sizeof(VMMDevPowerStateRequest); + case VMMDevReq_AcknowledgeEvents: + return sizeof(VMMDevEvents); + case VMMDevReq_ReportGuestInfo: + return sizeof(VMMDevReportGuestInfo); + case VMMDevReq_ReportGuestInfo2: + return sizeof(VMMDevReportGuestInfo2); + case VMMDevReq_ReportGuestStatus: + return sizeof(VMMDevReportGuestStatus); + case VMMDevReq_ReportGuestUserState: + return sizeof(VMMDevReportGuestUserState); + case VMMDevReq_GetDisplayChangeRequest: + return sizeof(VMMDevDisplayChangeRequest); + case VMMDevReq_GetDisplayChangeRequest2: + return sizeof(VMMDevDisplayChangeRequest2); + case VMMDevReq_GetDisplayChangeRequestEx: + return sizeof(VMMDevDisplayChangeRequestEx); + case VMMDevReq_GetDisplayChangeRequestMulti: + return RT_UOFFSETOF(VMMDevDisplayChangeRequestMulti, aDisplays[0]); + case VMMDevReq_VideoModeSupported: + return sizeof(VMMDevVideoModeSupportedRequest); + case VMMDevReq_GetHeightReduction: + return sizeof(VMMDevGetHeightReductionRequest); + case VMMDevReq_ReportGuestCapabilities: + return sizeof(VMMDevReqGuestCapabilities); + case VMMDevReq_SetGuestCapabilities: + return sizeof(VMMDevReqGuestCapabilities2); +#ifdef VBOX_WITH_HGCM + case VMMDevReq_HGCMConnect: + return sizeof(VMMDevHGCMConnect); + case VMMDevReq_HGCMDisconnect: + return sizeof(VMMDevHGCMDisconnect); + case VMMDevReq_HGCMCall32: + return sizeof(VMMDevHGCMCall); +# ifdef VBOX_WITH_64_BITS_GUESTS + case VMMDevReq_HGCMCall64: + return sizeof(VMMDevHGCMCall); +# endif + case VMMDevReq_HGCMCancel: + return sizeof(VMMDevHGCMCancel); +#endif /* VBOX_WITH_HGCM */ + case VMMDevReq_VideoAccelEnable: + return sizeof(VMMDevVideoAccelEnable); + case VMMDevReq_VideoAccelFlush: + return sizeof(VMMDevVideoAccelFlush); + case VMMDevReq_VideoSetVisibleRegion: + /* The original protocol didn't consider a guest with NO visible + * windows */ + return sizeof(VMMDevVideoSetVisibleRegion) - sizeof(RTRECT); + case VMMDevReq_GetSeamlessChangeRequest: + return sizeof(VMMDevSeamlessChangeRequest); + case VMMDevReq_QueryCredentials: + return sizeof(VMMDevCredentials); + case VMMDevReq_ReportGuestStats: + return sizeof(VMMDevReportGuestStats); + case VMMDevReq_GetMemBalloonChangeRequest: + return sizeof(VMMDevGetMemBalloonChangeRequest); + case VMMDevReq_GetStatisticsChangeRequest: + return sizeof(VMMDevGetStatisticsChangeRequest); + case VMMDevReq_ChangeMemBalloon: + return sizeof(VMMDevChangeMemBalloon); + case VMMDevReq_GetVRDPChangeRequest: + return sizeof(VMMDevVRDPChangeRequest); + case VMMDevReq_LogString: + return sizeof(VMMDevReqLogString); + case VMMDevReq_CtlGuestFilterMask: + return sizeof(VMMDevCtlGuestFilterMask); + case VMMDevReq_GetCpuHotPlugRequest: + return sizeof(VMMDevGetCpuHotPlugRequest); + case VMMDevReq_SetCpuHotPlugStatus: + return sizeof(VMMDevCpuHotPlugStatusRequest); + case VMMDevReq_RegisterSharedModule: + return sizeof(VMMDevSharedModuleRegistrationRequest); + case VMMDevReq_UnregisterSharedModule: + return sizeof(VMMDevSharedModuleUnregistrationRequest); + case VMMDevReq_CheckSharedModules: + return sizeof(VMMDevSharedModuleCheckRequest); + case VMMDevReq_GetPageSharingStatus: + return sizeof(VMMDevPageSharingStatusRequest); + case VMMDevReq_DebugIsPageShared: + return sizeof(VMMDevPageIsSharedRequest); + case VMMDevReq_GetSessionId: + return sizeof(VMMDevReqSessionId); + case VMMDevReq_HeartbeatConfigure: + return sizeof(VMMDevReqHeartbeat); + case VMMDevReq_GuestHeartbeat: + return sizeof(VMMDevRequestHeader); + case VMMDevReq_VideoUpdateMonitorPositions: + return sizeof(VMMDevVideoUpdateMonitorPositions); + default: + break; + } + + return 0; +} + + +/** + * Initializes a request structure. + * + * @returns VBox status code. + * @param req The request structure to initialize. + * @param type The request type. + */ +DECLINLINE(int) vmmdevInitRequest(VMMDevRequestHeader *req, VMMDevRequestType type) +{ + uint32_t requestSize; + if (!req) + return VERR_INVALID_PARAMETER; + requestSize = (uint32_t)vmmdevGetRequestSize(type); + if (!requestSize) + return VERR_INVALID_PARAMETER; + req->size = requestSize; + req->version = VMMDEV_REQUEST_HEADER_VERSION; + req->requestType = type; + req->rc = VERR_GENERAL_FAILURE; + req->reserved1 = 0; + req->fRequestor = 0; + return VINF_SUCCESS; +} + + +/** @name VBVA ring defines. + * + * The VBVA ring buffer is suitable for transferring large (< 2GB) amount of + * data. For example big bitmaps which do not fit to the buffer. + * + * Guest starts writing to the buffer by initializing a record entry in the + * aRecords queue. VBVA_F_RECORD_PARTIAL indicates that the record is being + * written. As data is written to the ring buffer, the guest increases off32End + * for the record. + * + * The host reads the aRecords on flushes and processes all completed records. + * When host encounters situation when only a partial record presents and + * cbRecord & ~VBVA_F_RECORD_PARTIAL >= VBVA_RING_BUFFER_SIZE - + * VBVA_RING_BUFFER_THRESHOLD, the host fetched all record data and updates + * off32Head. After that on each flush the host continues fetching the data + * until the record is completed. + * + * @{ */ +#define VMMDEV_VBVA_RING_BUFFER_SIZE (_4M - _1K) +#define VMMDEV_VBVA_RING_BUFFER_THRESHOLD (4 * _1K) + +#define VMMDEV_VBVA_MAX_RECORDS (64) +/** @} */ + +/** + * VBVA record. + */ +typedef struct VMMDEVVBVARECORD +{ + /** The length of the record. Changed by guest. */ + uint32_t cbRecord; +} VMMDEVVBVARECORD; +AssertCompileSize(VMMDEVVBVARECORD, 4); + +#if ARCH_BITS >= 32 + +/** + * VBVA memory layout. + * + * This is a subsection of the VMMDevMemory structure. + */ +typedef struct VBVAMEMORY +{ + /** VBVA_F_MODE_*. */ + uint32_t fu32ModeFlags; + + /** The offset where the data start in the buffer. */ + uint32_t off32Data; + /** The offset where next data must be placed in the buffer. */ + uint32_t off32Free; + + /** The ring buffer for data. */ + uint8_t au8RingBuffer[VMMDEV_VBVA_RING_BUFFER_SIZE]; + + /** The queue of record descriptions. */ + VMMDEVVBVARECORD aRecords[VMMDEV_VBVA_MAX_RECORDS]; + uint32_t indexRecordFirst; + uint32_t indexRecordFree; + + /** RDP orders supported by the client. The guest reports only them + * and falls back to DIRTY rects for not supported ones. + * + * (1 << VBVA_VRDP_*) + */ + uint32_t fu32SupportedOrders; + +} VBVAMEMORY; +AssertCompileSize(VBVAMEMORY, 12 + (_4M-_1K) + 4*64 + 12); + + +/** + * The layout of VMMDEV RAM region that contains information for guest. + */ +typedef struct VMMDevMemory +{ + /** The size of this structure. */ + uint32_t u32Size; + /** The structure version. (VMMDEV_MEMORY_VERSION) */ + uint32_t u32Version; + + union + { + struct + { + /** Flag telling that VMMDev set the IRQ and acknowlegment is required */ + bool fHaveEvents; + } V1_04; + + struct + { + /** Pending events flags, set by host. */ + uint32_t u32HostEvents; + /** Mask of events the guest wants to see, set by guest. */ + uint32_t u32GuestEventMask; + } V1_03; + } V; + + VBVAMEMORY vbvaMemory; + +} VMMDevMemory; +AssertCompileSize(VMMDevMemory, 8+8 + (12 + (_4M-_1K) + 4*64 + 12) ); +AssertCompileMemberOffset(VMMDevMemory, vbvaMemory, 16); + +/** Version of VMMDevMemory structure (VMMDevMemory::u32Version). */ +# define VMMDEV_MEMORY_VERSION (1) + +#endif /* ARCH_BITS >= 32 */ + +/** @} */ + +/** @} */ +RT_C_DECLS_END +#pragma pack() + +#endif /* !VBOX_INCLUDED_VMMDev_h */ diff --git a/include/VBox/VMMDevCoreTypes.h b/include/VBox/VMMDevCoreTypes.h new file mode 100644 index 00000000..e1d8aef3 --- /dev/null +++ b/include/VBox/VMMDevCoreTypes.h @@ -0,0 +1,556 @@ +/** @file + * Virtual Device for Guest <-> VMM/Host communication, Core Types. (ADD,DEV) + * + * These types are needed by several headers VBoxGuestLib.h and are kept + * separate to avoid having to include the whole VMMDev.h fun. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_VMMDevCoreTypes_h +#define VBOX_INCLUDED_VMMDevCoreTypes_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assertcompile.h> +#include <iprt/types.h> +#ifdef __cplusplus +# include <iprt/assert.h> +# include <iprt/errcore.h> +#endif + + +/** @addtogroup grp_vmmdev + * @{ + */ + +/* Helpful forward declarations: */ +struct VMMDevRequestHeader; +struct VMMDevReqMousePointer; +struct VMMDevMemory; + + +/** @name VMMDev events. + * + * Used mainly by VMMDevReq_AcknowledgeEvents/VMMDevEvents and version 1.3 of + * VMMDevMemory. + * + * @{ + */ +/** Host mouse capabilities has been changed. */ +#define VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED RT_BIT(0) +/** HGCM event. */ +#define VMMDEV_EVENT_HGCM RT_BIT(1) +/** A display change request has been issued. */ +#define VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST RT_BIT(2) +/** Credentials are available for judgement. */ +#define VMMDEV_EVENT_JUDGE_CREDENTIALS RT_BIT(3) +/** The guest has been restored. */ +#define VMMDEV_EVENT_RESTORED RT_BIT(4) +/** Seamless mode state changed. */ +#define VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST RT_BIT(5) +/** Memory balloon size changed. */ +#define VMMDEV_EVENT_BALLOON_CHANGE_REQUEST RT_BIT(6) +/** Statistics interval changed. */ +#define VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST RT_BIT(7) +/** VRDP status changed. */ +#define VMMDEV_EVENT_VRDP RT_BIT(8) +/** New mouse position data available. */ +#define VMMDEV_EVENT_MOUSE_POSITION_CHANGED RT_BIT(9) +/** CPU hotplug event occurred. */ +#define VMMDEV_EVENT_CPU_HOTPLUG RT_BIT(10) +/** The mask of valid events, for sanity checking. */ +#define VMMDEV_EVENT_VALID_EVENT_MASK UINT32_C(0x000007ff) +/** @} */ + + +/** @name The ballooning chunk size which VMMDev works at. + * @{ */ +#define VMMDEV_MEMORY_BALLOON_CHUNK_PAGES (_1M/4096) +#define VMMDEV_MEMORY_BALLOON_CHUNK_SIZE (VMMDEV_MEMORY_BALLOON_CHUNK_PAGES*4096) +/** @} */ + + +/** + * Seamless mode. + * + * Used by VbglR3SeamlessWaitEvent + * + * @ingroup grp_vmmdev_req + */ +typedef enum +{ + VMMDev_Seamless_Disabled = 0, /**< normal mode; entire guest desktop displayed. */ + VMMDev_Seamless_Visible_Region = 1, /**< visible region mode; only top-level guest windows displayed. */ + VMMDev_Seamless_Host_Window = 2, /**< windowed mode; each top-level guest window is represented in a host window. */ + VMMDev_Seamless_SizeHack = 0x7fffffff +} VMMDevSeamlessMode; +AssertCompileSize(VMMDevSeamlessMode, 4); + + +/** + * CPU event types. + * + * Used by VbglR3CpuHotplugWaitForEvent + * + * @ingroup grp_vmmdev_req + */ +typedef enum +{ + VMMDevCpuEventType_Invalid = 0, + VMMDevCpuEventType_None = 1, + VMMDevCpuEventType_Plug = 2, + VMMDevCpuEventType_Unplug = 3, + VMMDevCpuEventType_SizeHack = 0x7fffffff +} VMMDevCpuEventType; +AssertCompileSize(VMMDevCpuEventType, 4); + + +/** @name Guest capability bits. + * Used by VMMDevReq_ReportGuestCapabilities and VMMDevReq_SetGuestCapabilities. + * @{ */ +/** The guest supports seamless display rendering. */ +#define VMMDEV_GUEST_SUPPORTS_SEAMLESS RT_BIT_32(0) +/** The guest supports mapping guest to host windows. */ +#define VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING RT_BIT_32(1) +/** The guest graphical additions are active. + * Used for fast activation and deactivation of certain graphical operations + * (e.g. resizing & seamless). The legacy VMMDevReq_ReportGuestCapabilities + * request sets this automatically, but VMMDevReq_SetGuestCapabilities does + * not. */ +#define VMMDEV_GUEST_SUPPORTS_GRAPHICS RT_BIT_32(2) +/** The mask of valid events, for sanity checking. */ +#define VMMDEV_GUEST_CAPABILITIES_MASK UINT32_C(0x00000007) +/** @} */ + + +/** + * The guest facility. + * This needs to be kept in sync with AdditionsFacilityType of the Main API! + */ +typedef enum +{ + VBoxGuestFacilityType_Unknown = 0, + VBoxGuestFacilityType_VBoxGuestDriver = 20, + VBoxGuestFacilityType_AutoLogon = 90, /* VBoxGINA / VBoxCredProv / pam_vbox. */ + VBoxGuestFacilityType_VBoxService = 100, + VBoxGuestFacilityType_VBoxTrayClient = 101, /* VBoxTray (Windows), VBoxClient (Linux, Unix). */ + VBoxGuestFacilityType_Seamless = 1000, + VBoxGuestFacilityType_Graphics = 1100, + VBoxGuestFacilityType_MonitorAttach = 1101, + VBoxGuestFacilityType_All = 0x7ffffffe, + VBoxGuestFacilityType_SizeHack = 0x7fffffff +} VBoxGuestFacilityType; +AssertCompileSize(VBoxGuestFacilityType, 4); + + +/** + * The current guest status of a facility. + * This needs to be kept in sync with AdditionsFacilityStatus of the Main API! + * + * @remarks r=bird: Pretty please, for future types like this, simply do a + * linear allocation without any gaps. This stuff is impossible work + * efficiently with, let alone validate. Applies to the other facility + * enums too. + */ +typedef enum +{ + VBoxGuestFacilityStatus_Inactive = 0, + VBoxGuestFacilityStatus_Paused = 1, + VBoxGuestFacilityStatus_PreInit = 20, + VBoxGuestFacilityStatus_Init = 30, + VBoxGuestFacilityStatus_Active = 50, + VBoxGuestFacilityStatus_Terminating = 100, + VBoxGuestFacilityStatus_Terminated = 101, + VBoxGuestFacilityStatus_Failed = 800, + VBoxGuestFacilityStatus_Unknown = 999, + VBoxGuestFacilityStatus_SizeHack = 0x7fffffff +} VBoxGuestFacilityStatus; +AssertCompileSize(VBoxGuestFacilityStatus, 4); + + +/** + * The current status of specific guest user. + * This needs to be kept in sync with GuestUserState of the Main API! + */ +typedef enum VBoxGuestUserState +{ + VBoxGuestUserState_Unknown = 0, + VBoxGuestUserState_LoggedIn = 1, + VBoxGuestUserState_LoggedOut = 2, + VBoxGuestUserState_Locked = 3, + VBoxGuestUserState_Unlocked = 4, + VBoxGuestUserState_Disabled = 5, + VBoxGuestUserState_Idle = 6, + VBoxGuestUserState_InUse = 7, + VBoxGuestUserState_Created = 8, + VBoxGuestUserState_Deleted = 9, + VBoxGuestUserState_SessionChanged = 10, + VBoxGuestUserState_CredentialsChanged = 11, + VBoxGuestUserState_RoleChanged = 12, + VBoxGuestUserState_GroupAdded = 13, + VBoxGuestUserState_GroupRemoved = 14, + VBoxGuestUserState_Elevated = 15, + VBoxGuestUserState_SizeHack = 0x7fffffff +} VBoxGuestUserState; +AssertCompileSize(VBoxGuestUserState, 4); + + + +/** + * HGCM service location types. + * @ingroup grp_vmmdev_req + */ +typedef enum +{ + VMMDevHGCMLoc_Invalid = 0, + VMMDevHGCMLoc_LocalHost = 1, + VMMDevHGCMLoc_LocalHost_Existing = 2, + VMMDevHGCMLoc_SizeHack = 0x7fffffff +} HGCMServiceLocationType; +AssertCompileSize(HGCMServiceLocationType, 4); + +/** + * HGCM host service location. + * @ingroup grp_vmmdev_req + */ +typedef struct +{ + char achName[128]; /**< This is really szName. */ +} HGCMServiceLocationHost; +AssertCompileSize(HGCMServiceLocationHost, 128); + +/** + * HGCM service location. + * @ingroup grp_vmmdev_req + */ +typedef struct HGCMSERVICELOCATION +{ + /** Type of the location. */ + HGCMServiceLocationType type; + + union + { + HGCMServiceLocationHost host; + } u; +} HGCMServiceLocation; +AssertCompileSize(HGCMServiceLocation, 128+4); + + +/** + * HGCM parameter type. + */ +typedef enum +{ + VMMDevHGCMParmType_Invalid = 0, + VMMDevHGCMParmType_32bit = 1, + VMMDevHGCMParmType_64bit = 2, + VMMDevHGCMParmType_PhysAddr = 3, /**< @deprecated Doesn't work, use PageList. */ + VMMDevHGCMParmType_LinAddr = 4, /**< In and Out */ + VMMDevHGCMParmType_LinAddr_In = 5, /**< In (read; host<-guest) */ + VMMDevHGCMParmType_LinAddr_Out = 6, /**< Out (write; host->guest) */ + VMMDevHGCMParmType_LinAddr_Locked = 7, /**< Locked In and Out - for VBoxGuest, not host. */ + VMMDevHGCMParmType_LinAddr_Locked_In = 8, /**< Locked In (read; host<-guest) - for VBoxGuest, not host. */ + VMMDevHGCMParmType_LinAddr_Locked_Out = 9, /**< Locked Out (write; host->guest) - for VBoxGuest, not host. */ + VMMDevHGCMParmType_PageList = 10, /**< Physical addresses of locked pages for a buffer. */ + VMMDevHGCMParmType_Embedded = 11, /**< Small buffer embedded in request. */ + VMMDevHGCMParmType_ContiguousPageList = 12, /**< Like PageList but with physically contiguous memory, so only one page entry. */ + VMMDevHGCMParmType_NoBouncePageList = 13, /**< Like PageList but host function requires no bounce buffering. */ + VMMDevHGCMParmType_SizeHack = 0x7fffffff +} HGCMFunctionParameterType; +AssertCompileSize(HGCMFunctionParameterType, 4); + + +# ifdef VBOX_WITH_64_BITS_GUESTS +/** + * HGCM function parameter, 32-bit client. + */ +# pragma pack(4) /* We force structure dword packing here for hysterical raisins. Saves us 4 bytes, at the cost of + misaligning the value64 member of every other parameter structure. */ +typedef struct HGCMFunctionParameter32 +{ + HGCMFunctionParameterType type; + union + { + uint32_t value32; + uint64_t value64; + struct + { + uint32_t size; + + union + { + RTGCPHYS32 physAddr; + RTGCPTR32 linearAddr; + } u; + } Pointer; + struct + { + uint32_t cb; + RTGCPTR32 uAddr; + } LinAddr; /**< Shorter version of the above Pointer structure. */ + struct + { + uint32_t size; /**< Size of the buffer described by the page list. */ + uint32_t offset; /**< Relative to the request header of a HGCMPageListInfo structure, valid if size != 0. */ + } PageList; + struct + { + uint32_t fFlags : 8; /**< VBOX_HGCM_F_PARM_*. */ + uint32_t offData : 24; /**< Relative to the request header, valid if cb != 0. */ + uint32_t cbData; /**< The buffer size. */ + } Embedded; + } u; +# ifdef __cplusplus + void SetUInt32(uint32_t u32) + { + type = VMMDevHGCMParmType_32bit; + u.value64 = 0; /* init unused bits to 0 */ + u.value32 = u32; + } + + int GetUInt32(uint32_t RT_FAR *pu32) + { + if (type == VMMDevHGCMParmType_32bit) + { + *pu32 = u.value32; + return VINF_SUCCESS; + } + return VERR_INVALID_PARAMETER; + } + + void SetUInt64(uint64_t u64) + { + type = VMMDevHGCMParmType_64bit; + u.value64 = u64; + } + + int GetUInt64(uint64_t RT_FAR *pu64) + { + if (type == VMMDevHGCMParmType_64bit) + { + *pu64 = u.value64; + return VINF_SUCCESS; + } + return VERR_INVALID_PARAMETER; + } + + void SetPtr(void RT_FAR *pv, uint32_t cb) + { + type = VMMDevHGCMParmType_LinAddr; + u.Pointer.size = cb; + u.Pointer.u.linearAddr = (RTGCPTR32)(uintptr_t)pv; + } +# endif /* __cplusplus */ +} HGCMFunctionParameter32; +# pragma pack() +AssertCompileSize(HGCMFunctionParameter32, 4+8); + +/** + * HGCM function parameter, 64-bit client. + */ +# pragma pack(4)/* We force structure dword packing here for hysterical raisins. Saves us 4 bytes, + at the cost of misaligning the value64 members. */ +typedef struct HGCMFunctionParameter64 +{ + HGCMFunctionParameterType type; + union + { + uint32_t value32; + uint64_t value64; + struct + { + uint32_t size; + + union + { + RTGCPHYS64 physAddr; + RTGCPTR64 linearAddr; + } u; + } Pointer; + struct + { + uint32_t cb; + RTGCPTR64 uAddr; + } LinAddr; /**< Shorter version of the above Pointer structure. */ + struct + { + uint32_t size; /**< Size of the buffer described by the page list. */ + uint32_t offset; /**< Relative to the request header, valid if size != 0. */ + } PageList; + struct + { + uint32_t fFlags : 8; /**< VBOX_HGCM_F_PARM_*. */ + uint32_t offData : 24; /**< Relative to the request header, valid if cb != 0. */ + uint32_t cbData; /**< The buffer size. */ + } Embedded; + } u; +# ifdef __cplusplus + void SetUInt32(uint32_t u32) + { + type = VMMDevHGCMParmType_32bit; + u.value64 = 0; /* init unused bits to 0 */ + u.value32 = u32; + } + + int GetUInt32(uint32_t RT_FAR *pu32) + { + if (type == VMMDevHGCMParmType_32bit) + { + *pu32 = u.value32; + return VINF_SUCCESS; + } + return VERR_INVALID_PARAMETER; + } + + void SetUInt64(uint64_t u64) + { + type = VMMDevHGCMParmType_64bit; + u.value64 = u64; + } + + int GetUInt64(uint64_t RT_FAR *pu64) + { + if (type == VMMDevHGCMParmType_64bit) + { + *pu64 = u.value64; + return VINF_SUCCESS; + } + return VERR_INVALID_PARAMETER; + } + + void SetPtr(void RT_FAR *pv, uint32_t cb) + { + type = VMMDevHGCMParmType_LinAddr; + u.Pointer.size = cb; + u.Pointer.u.linearAddr = (uintptr_t)pv; + } +# endif /** __cplusplus */ +} HGCMFunctionParameter64; +# pragma pack() +AssertCompileSize(HGCMFunctionParameter64, 4+12); + +/* Redefine the structure type for the guest code. */ +# ifndef VBOX_HGCM_HOST_CODE +# if ARCH_BITS == 64 +# define HGCMFunctionParameter HGCMFunctionParameter64 +# elif ARCH_BITS == 32 || ARCH_BITS == 16 +# define HGCMFunctionParameter HGCMFunctionParameter32 +# else +# error "Unsupported sizeof (void *)" +# endif +# endif /* !VBOX_HGCM_HOST_CODE */ + +# else /* !VBOX_WITH_64_BITS_GUESTS */ + +/** + * HGCM function parameter, 32-bit client. + * + * @todo If this is the same as HGCMFunctionParameter32, why the duplication? + */ +# pragma pack(4) /* We force structure dword packing here for hysterical raisins. Saves us 4 bytes, at the cost of + misaligning the value64 member of every other parameter structure. */ +typedef struct +{ + HGCMFunctionParameterType type; + union + { + uint32_t value32; + uint64_t value64; + struct + { + uint32_t size; + + union + { + RTGCPHYS32 physAddr; + RTGCPTR32 linearAddr; + } u; + } Pointer; + struct + { + uint32_t cb; + RTGCPTR32 uAddr; + } LinAddr; /**< Shorter version of the above Pointer structure. */ + struct + { + uint32_t size; /**< Size of the buffer described by the page list. */ + uint32_t offset; /**< Relative to the request header, valid if size != 0. */ + } PageList; + struct + { + uint32_t fFlags : 8; /**< VBOX_HGCM_F_PARM_*. */ + uint32_t offData : 24; /**< Relative to the request header (must be a valid offset even if cbData is zero). */ + uint32_t cbData; /**< The buffer size. */ + } Embedded; + } u; +# ifdef __cplusplus + void SetUInt32(uint32_t u32) + { + type = VMMDevHGCMParmType_32bit; + u.value64 = 0; /* init unused bits to 0 */ + u.value32 = u32; + } + + int GetUInt32(uint32_t *pu32) + { + AssertMsgReturnStmt(type == VMMDevHGCMParmType_32bit, ("type=-%d\n", type), + *pu32 = UINT32_MAX /* shut up gcc */, VERR_WRONG_PARAMETER_TYPE) + *pu32 = u.value32; + return VINF_SUCCESS; + } + + void SetUInt64(uint64_t u64) + { + type = VMMDevHGCMParmType_64bit; + u.value64 = u64; + } + + int GetUInt64(uint64_t *pu64) + { + AssertMsgReturnStmt(type == VMMDevHGCMParmType_64bit, ("type=%d\n", type), + *pu64 = UINT32_MAX /* shut up gcc */, VERR_WRONG_PARAMETER_TYPE); + *pu64 = u.value64; + return VINF_SUCCESS; + } + + void SetPtr(void *pv, uint32_t cb) + { + type = VMMDevHGCMParmType_LinAddr; + u.Pointer.size = cb; + u.Pointer.u.linearAddr = (uintptr_t)pv; + } +# endif /* __cplusplus */ +} HGCMFunctionParameter; +# pragma pack() +AssertCompileSize(HGCMFunctionParameter, 4+8); +# endif /* !VBOX_WITH_64_BITS_GUESTS */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_VMMDevCoreTypes_h */ + diff --git a/include/VBox/VMMDevTesting.h b/include/VBox/VMMDevTesting.h new file mode 100644 index 00000000..d68d9c1b --- /dev/null +++ b/include/VBox/VMMDevTesting.h @@ -0,0 +1,272 @@ +/* $Id: VMMDevTesting.h $ */ +/** @file + * VMMDev - Testing Extensions. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VMMDevTesting_h +#define VBOX_INCLUDED_VMMDevTesting_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + + +/** @defgroup grp_vmmdev_testing VMM Device Testing + * @ingroup grp_vmmdev + * @{ + */ + +/** The base address of the MMIO range used for testing. + * @remarks This used to be at 0x101000 but moved to 0xdf000 so that it would + * work better with prototype NEM code. This also means enabling A20 + * is not a requirement. */ +#define VMMDEV_TESTING_MMIO_BASE UINT32_C(0x000df000) +/** The size of the MMIO range used for testing. */ +#define VMMDEV_TESTING_MMIO_SIZE UINT32_C(0x00001000) + +/** MMIO offset: The NOP register - 1248 RW. */ +#define VMMDEV_TESTING_MMIO_OFF_NOP (0x000) +/** MMIO offset: The go-to-ring-3-NOP register - 1248 RW. */ +#define VMMDEV_TESTING_MMIO_OFF_NOP_R3 (0x008) +/** MMIO offset: The readback registers - 64 bytes of read/write "memory". */ +#define VMMDEV_TESTING_MMIO_OFF_READBACK (0x040) +/** MMIO offset: Readback register view that always goes to ring-3. */ +#define VMMDEV_TESTING_MMIO_OFF_READBACK_R3 (0x080) +/** The size of the MMIO readback registers. */ +#define VMMDEV_TESTING_READBACK_SIZE (0x40) + +/** Default address of VMMDEV_TESTING_MMIO_OFF_NOP. */ +#define VMMDEV_TESTING_MMIO_NOP (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_NOP) +/** Default address of VMMDEV_TESTING_MMIO_OFF_NOP_R3. */ +#define VMMDEV_TESTING_MMIO_NOP_R3 (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_NOP_R3) +/** Default address of VMMDEV_TESTING_MMIO_OFF_READBACK. */ +#define VMMDEV_TESTING_MMIO_READBACK (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_READBACK) +/** Default address of VMMDEV_TESTING_MMIO_OFF_READBACK_R3. */ +#define VMMDEV_TESTING_MMIO_READBACK_R3 (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_READBACK_R3) + +/** The real mode selector to use. */ +#define VMMDEV_TESTING_MMIO_RM_SEL 0xdf00 +/** Calculate the real mode offset of a MMIO register. */ +#define VMMDEV_TESTING_MMIO_RM_OFF(val) ((val) - VMMDEV_TESTING_MMIO_BASE) +/** Calculate the real mode offset of a MMIO register offset. */ +#define VMMDEV_TESTING_MMIO_RM_OFF2(off) (off) + +/** The base port of the I/O range used for testing. */ +#define VMMDEV_TESTING_IOPORT_BASE 0x0510 +/** The number of I/O ports reserved for testing. */ +#define VMMDEV_TESTING_IOPORT_COUNT 0x0010 +/** The NOP I/O port - 1,2,4 RW. */ +#define VMMDEV_TESTING_IOPORT_NOP (VMMDEV_TESTING_IOPORT_BASE + 0) +/** The low nanosecond timestamp - 4 RO. */ +#define VMMDEV_TESTING_IOPORT_TS_LOW (VMMDEV_TESTING_IOPORT_BASE + 1) +/** The high nanosecond timestamp - 4 RO. Read this after the low one! */ +#define VMMDEV_TESTING_IOPORT_TS_HIGH (VMMDEV_TESTING_IOPORT_BASE + 2) +/** Command register usually used for preparing the data register - 4/2 WO. */ +#define VMMDEV_TESTING_IOPORT_CMD (VMMDEV_TESTING_IOPORT_BASE + 3) +/** Data register which use depends on the current command - 1s, 4 WO. */ +#define VMMDEV_TESTING_IOPORT_DATA (VMMDEV_TESTING_IOPORT_BASE + 4) +/** The go-to-ring-3-NOP I/O port - 1,2,4 RW. */ +#define VMMDEV_TESTING_IOPORT_NOP_R3 (VMMDEV_TESTING_IOPORT_BASE + 5) +/** Take the VMMDev lock in arrival context and return - 1,2,4 RW. + * Writing configures counter action by a thread taking the lock to trigger + * contention: + * - bits 15:0: Number of microseconds thread should hold lock. + * - bits 31:16: Number of microseconds thread should wait before locking + * again. */ +#define VMMDEV_TESTING_IOPORT_LOCKED_LO (VMMDEV_TESTING_IOPORT_BASE + 6) +/** Take the VMMDev lock in arrival context and return - 1,2,4 RW. + * Writing configures counter action by a thread taking the lock to trigger + * contention: + * - bits 19:0: Number of kilo (1024) ticks the EMT should hold lock. + * - bits 25:20: Reserved, must be zero. + * - bit 26: Thread takes lock in shared mode when set, exclusive when clear. + * - bit 27: EMT takes lock in shared mode when set, exclusive when clear. + * - bit 28: Use read/write critical section when set, device section if clear. + * - bit 29: EMT passes VINF_SUCCESS as rcBusy when set. + * - bit 30: Makes thread poke all EMTs before release lock. + * - bit 31: Enables the thread. */ +#define VMMDEV_TESTING_IOPORT_LOCKED_HI (VMMDEV_TESTING_IOPORT_BASE + 7) + +/** @name Commands. + * @{ */ +/** Initialize test, sending name (zero terminated string). (RTTestCreate) */ +#define VMMDEV_TESTING_CMD_INIT UINT32_C(0xcab1e000) +/** Test done, sending 32-bit total error count with it. (RTTestSummaryAndDestroy) */ +#define VMMDEV_TESTING_CMD_TERM UINT32_C(0xcab1e001) +/** Start a new sub-test, sending name (zero terminated string). (RTTestSub) */ +#define VMMDEV_TESTING_CMD_SUB_NEW UINT32_C(0xcab1e002) +/** Sub-test is done, sending 32-bit error count for it. (RTTestDone) */ +#define VMMDEV_TESTING_CMD_SUB_DONE UINT32_C(0xcab1e003) +/** Report a failure, sending reason (zero terminated string). (RTTestFailed) */ +#define VMMDEV_TESTING_CMD_FAILED UINT32_C(0xcab1e004) +/** Report a value, sending the 64-bit value (2x4), the 32-bit unit (4), and + * finally the name (zero terminated string). (RTTestValue) */ +#define VMMDEV_TESTING_CMD_VALUE UINT32_C(0xcab1e005) +/** Report a failure, sending reason (zero terminated string). (RTTestSkipped) */ +#define VMMDEV_TESTING_CMD_SKIPPED UINT32_C(0xcab1e006) +/** Report a value found in a VMM register, sending a string on the form + * "value-name:register-name". */ +#define VMMDEV_TESTING_CMD_VALUE_REG UINT32_C(0xcab1e007) +/** Print string, sending a string including newline. (RTTestPrintf) */ +#define VMMDEV_TESTING_CMD_PRINT UINT32_C(0xcab1e008) +/** Query a config value, sending a 16-bit word (VMMDEV_TESTING_CFG_XXX) to the + * DATA port and reading back the result. */ +#define VMMDEV_TESTING_CMD_QUERY_CFG UINT32_C(0xcab1e009) + +/** The magic part of the command. */ +#define VMMDEV_TESTING_CMD_MAGIC UINT32_C(0xcab1e000) +/** The magic part of the command. */ +#define VMMDEV_TESTING_CMD_MAGIC_MASK UINT32_C(0xffffff00) +/** The magic high word automatically supplied to 16-bit CMD writes. */ +#define VMMDEV_TESTING_CMD_MAGIC_HI_WORD UINT32_C(0xcab10000) +/** @} */ + +/** @name Value units + * @note Same as RTTESTUNIT, see rules here for adding new units. + * @{ */ +#define VMMDEV_TESTING_UNIT_PCT UINT8_C(0x01) /**< Percentage. */ +#define VMMDEV_TESTING_UNIT_BYTES UINT8_C(0x02) /**< Bytes. */ +#define VMMDEV_TESTING_UNIT_BYTES_PER_SEC UINT8_C(0x03) /**< Bytes per second. */ +#define VMMDEV_TESTING_UNIT_KILOBYTES UINT8_C(0x04) /**< Kilobytes. */ +#define VMMDEV_TESTING_UNIT_KILOBYTES_PER_SEC UINT8_C(0x05) /**< Kilobytes per second. */ +#define VMMDEV_TESTING_UNIT_MEGABYTES UINT8_C(0x06) /**< Megabytes. */ +#define VMMDEV_TESTING_UNIT_MEGABYTES_PER_SEC UINT8_C(0x07) /**< Megabytes per second. */ +#define VMMDEV_TESTING_UNIT_PACKETS UINT8_C(0x08) /**< Packets. */ +#define VMMDEV_TESTING_UNIT_PACKETS_PER_SEC UINT8_C(0x09) /**< Packets per second. */ +#define VMMDEV_TESTING_UNIT_FRAMES UINT8_C(0x0a) /**< Frames. */ +#define VMMDEV_TESTING_UNIT_FRAMES_PER_SEC UINT8_C(0x0b) /**< Frames per second. */ +#define VMMDEV_TESTING_UNIT_OCCURRENCES UINT8_C(0x0c) /**< Occurrences. */ +#define VMMDEV_TESTING_UNIT_OCCURRENCES_PER_SEC UINT8_C(0x0d) /**< Occurrences per second. */ +#define VMMDEV_TESTING_UNIT_CALLS UINT8_C(0x0e) /**< Calls. */ +#define VMMDEV_TESTING_UNIT_CALLS_PER_SEC UINT8_C(0x0f) /**< Calls per second. */ +#define VMMDEV_TESTING_UNIT_ROUND_TRIP UINT8_C(0x10) /**< Round trips. */ +#define VMMDEV_TESTING_UNIT_SECS UINT8_C(0x11) /**< Seconds. */ +#define VMMDEV_TESTING_UNIT_MS UINT8_C(0x12) /**< Milliseconds. */ +#define VMMDEV_TESTING_UNIT_NS UINT8_C(0x13) /**< Nanoseconds. */ +#define VMMDEV_TESTING_UNIT_NS_PER_CALL UINT8_C(0x14) /**< Nanoseconds per call. */ +#define VMMDEV_TESTING_UNIT_NS_PER_FRAME UINT8_C(0x15) /**< Nanoseconds per frame. */ +#define VMMDEV_TESTING_UNIT_NS_PER_OCCURRENCE UINT8_C(0x16) /**< Nanoseconds per occurrence. */ +#define VMMDEV_TESTING_UNIT_NS_PER_PACKET UINT8_C(0x17) /**< Nanoseconds per frame. */ +#define VMMDEV_TESTING_UNIT_NS_PER_ROUND_TRIP UINT8_C(0x18) /**< Nanoseconds per round trip. */ +#define VMMDEV_TESTING_UNIT_INSTRS UINT8_C(0x19) /**< Instructions. */ +#define VMMDEV_TESTING_UNIT_INSTRS_PER_SEC UINT8_C(0x1a) /**< Instructions per second. */ +#define VMMDEV_TESTING_UNIT_NONE UINT8_C(0x1b) /**< No unit. */ +#define VMMDEV_TESTING_UNIT_PP1K UINT8_C(0x1c) /**< Parts per thousand (10^-3). */ +#define VMMDEV_TESTING_UNIT_PP10K UINT8_C(0x1d) /**< Parts per ten thousand (10^-4). */ +#define VMMDEV_TESTING_UNIT_PPM UINT8_C(0x1e) /**< Parts per million (10^-6). */ +#define VMMDEV_TESTING_UNIT_PPB UINT8_C(0x1f) /**< Parts per billion (10^-9). */ +#define VMMDEV_TESTING_UNIT_TICKS UINT8_C(0x20) /**< CPU ticks. */ +#define VMMDEV_TESTING_UNIT_TICKS_PER_CALL UINT8_C(0x21) /**< CPU ticks per call. */ +#define VMMDEV_TESTING_UNIT_TICKS_PER_OCCURENCE UINT8_C(0x22) /**< CPU ticks per occurence. */ +#define VMMDEV_TESTING_UNIT_PAGES UINT8_C(0x23) /**< Page count. */ +#define VMMDEV_TESTING_UNIT_PAGES_PER_SEC UINT8_C(0x24) /**< Pages per second. */ +#define VMMDEV_TESTING_UNIT_TICKS_PER_PAGE UINT8_C(0x25) /**< CPU ticks per page. */ +#define VMMDEV_TESTING_UNIT_NS_PER_PAGE UINT8_C(0x26) /**< Nanoseconds per page. */ +#define VMMDEV_TESTING_UNIT_PS UINT8_C(0x27) /**< Picoseconds. */ +#define VMMDEV_TESTING_UNIT_PS_PER_CALL UINT8_C(0x28) /**< Picoseconds per call. */ +#define VMMDEV_TESTING_UNIT_PS_PER_FRAME UINT8_C(0x29) /**< Picoseconds per frame. */ +#define VMMDEV_TESTING_UNIT_PS_PER_OCCURRENCE UINT8_C(0x2a) /**< Picoseconds per occurrence. */ +#define VMMDEV_TESTING_UNIT_PS_PER_PACKET UINT8_C(0x2b) /**< Picoseconds per frame. */ +#define VMMDEV_TESTING_UNIT_PS_PER_ROUND_TRIP UINT8_C(0x2c) /**< Picoseconds per round trip. */ +#define VMMDEV_TESTING_UNIT_PS_PER_PAGE UINT8_C(0x2d) /**< Picoseconds per page. */ +/** @} */ + +/** What the NOP accesses returns. */ +#define VMMDEV_TESTING_NOP_RET UINT32_C(0x64726962) /* bird */ + +/** @name Low and High Locking Control Dwords + * @{ */ +/** Low Locking Control: Thread lock hold interval in microseconds. */ +#define VMMDEV_TESTING_LOCKED_LO_HOLD_MASK UINT32_C(0x0000ffff) +/** Low Locking Control: Thread wait time in microseconds between locking + * attempts. */ +#define VMMDEV_TESTING_LOCKED_LO_WAIT_MASK UINT32_C(0xffff0000) +/** Low Locking Control: Thread wait time shift count. */ +#define VMMDEV_TESTING_LOCKED_LO_WAIT_SHIFT 16 +/** High Locking Control: Kilo (1024) ticks the EMT should hold the lock. */ +#define VMMDEV_TESTING_LOCKED_HI_TICKS_MASK UINT32_C(0x000fffff) +/** High Locking Control: Must be zero. */ +#define VMMDEV_TESTING_LOCKED_HI_MBZ_MASK UINT32_C(0x03f00000) +/** High Locking Control: Thread takes lock in shared mode when set, exclusive + * when clear. */ +#define VMMDEV_TESTING_LOCKED_HI_THREAD_SHARED UINT32_C(0x04000000) +/** High Locking Control: EMT takes lock in shared mode when set, exclusive + * when clear. */ +#define VMMDEV_TESTING_LOCKED_HI_EMT_SHARED UINT32_C(0x08000000) +/** High Locking Control: Use read/write critical section instead of regular. */ +#define VMMDEV_TESTING_LOCKED_HI_TYPE_RW UINT32_C(0x10000000) +/** High Locking Control: EMT takes lock with rcBusy set to VINF_SUCCESS. */ +#define VMMDEV_TESTING_LOCKED_HI_BUSY_SUCCESS UINT32_C(0x20000000) +/** High Locking Control: Thread pokes EMTs before releasing lock. */ +#define VMMDEV_TESTING_LOCKED_HI_POKE UINT32_C(0x40000000) +/** High Locking Control: Thread enabled. */ +#define VMMDEV_TESTING_LOCKED_HI_ENABLED UINT32_C(0x80000000) +/** @} */ + +/** @name VMMDEV_TESTING_CFG_XXX - Configuration values that can be queried. + * @{ */ +/** Generic 32-bit value \#0 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD0 UINT16_C(0x0000) +/** Generic 32-bit value \#1 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD1 UINT16_C(0x0001) +/** Generic 32-bit value \#2 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD2 UINT16_C(0x0002) +/** Generic 32-bit value \#3 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD3 UINT16_C(0x0003) +/** Generic 32-bit value \#4 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD4 UINT16_C(0x0004) +/** Generic 32-bit value \#5 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD5 UINT16_C(0x0005) +/** Generic 32-bit value \#6 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD6 UINT16_C(0x0006) +/** Generic 32-bit value \#7 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD7 UINT16_C(0x0007) +/** Generic 32-bit value \#8 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD8 UINT16_C(0x0008) +/** Generic 32-bit value \#9 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD9 UINT16_C(0x0009) + +/** Boolean (8-bit): Running in NEM on Linux? */ +#define VMMDEV_TESTING_CFG_IS_NEM_LINUX UINT16_C(0x0100) +/** Boolean (8-bit): Running in NEM on Windows? */ +#define VMMDEV_TESTING_CFG_IS_NEM_WINDOWS UINT16_C(0x0101) +/** Boolean (8-bit): Running in NEM on Darwin? */ +#define VMMDEV_TESTING_CFG_IS_NEM_DARWIN UINT16_C(0x0102) +/** @} */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_VMMDevTesting_h */ + diff --git a/include/VBox/VMMDevTesting.mac b/include/VBox/VMMDevTesting.mac new file mode 100644 index 00000000..79434866 --- /dev/null +++ b/include/VBox/VMMDevTesting.mac @@ -0,0 +1,148 @@ +; $Id: VMMDevTesting.mac $ ;/ +;; @file +; VMMDev - Testing Extensions. +; Automatically generated by various.sed. DO NOT EDIT! + +; +; Copyright (C) 2010-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef VBOX_INCLUDED_VMMDevTesting_h +%define VBOX_INCLUDED_VMMDevTesting_h +%ifndef RT_WITHOUT_PRAGMA_ONCE +%endif +%define VMMDEV_TESTING_MMIO_BASE 0x000df000 +%define VMMDEV_TESTING_MMIO_SIZE 0x00001000 +%define VMMDEV_TESTING_MMIO_OFF_NOP (0x000) +%define VMMDEV_TESTING_MMIO_OFF_NOP_R3 (0x008) +%define VMMDEV_TESTING_MMIO_OFF_READBACK (0x040) +%define VMMDEV_TESTING_MMIO_OFF_READBACK_R3 (0x080) +%define VMMDEV_TESTING_READBACK_SIZE (0x40) +%define VMMDEV_TESTING_MMIO_NOP (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_NOP) +%define VMMDEV_TESTING_MMIO_NOP_R3 (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_NOP_R3) +%define VMMDEV_TESTING_MMIO_READBACK (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_READBACK) +%define VMMDEV_TESTING_MMIO_READBACK_R3 (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_READBACK_R3) +%define VMMDEV_TESTING_MMIO_RM_SEL 0xdf00 +%define VMMDEV_TESTING_MMIO_RM_OFF(val) ((val) - VMMDEV_TESTING_MMIO_BASE) +%define VMMDEV_TESTING_MMIO_RM_OFF2(off) (off) +%define VMMDEV_TESTING_IOPORT_BASE 0x0510 +%define VMMDEV_TESTING_IOPORT_COUNT 0x0010 +%define VMMDEV_TESTING_IOPORT_NOP (VMMDEV_TESTING_IOPORT_BASE + 0) +%define VMMDEV_TESTING_IOPORT_TS_LOW (VMMDEV_TESTING_IOPORT_BASE + 1) +%define VMMDEV_TESTING_IOPORT_TS_HIGH (VMMDEV_TESTING_IOPORT_BASE + 2) +%define VMMDEV_TESTING_IOPORT_CMD (VMMDEV_TESTING_IOPORT_BASE + 3) +%define VMMDEV_TESTING_IOPORT_DATA (VMMDEV_TESTING_IOPORT_BASE + 4) +%define VMMDEV_TESTING_IOPORT_NOP_R3 (VMMDEV_TESTING_IOPORT_BASE + 5) +%define VMMDEV_TESTING_IOPORT_LOCKED_LO (VMMDEV_TESTING_IOPORT_BASE + 6) +%define VMMDEV_TESTING_IOPORT_LOCKED_HI (VMMDEV_TESTING_IOPORT_BASE + 7) +%define VMMDEV_TESTING_CMD_INIT 0xcab1e000 +%define VMMDEV_TESTING_CMD_TERM 0xcab1e001 +%define VMMDEV_TESTING_CMD_SUB_NEW 0xcab1e002 +%define VMMDEV_TESTING_CMD_SUB_DONE 0xcab1e003 +%define VMMDEV_TESTING_CMD_FAILED 0xcab1e004 +%define VMMDEV_TESTING_CMD_VALUE 0xcab1e005 +%define VMMDEV_TESTING_CMD_SKIPPED 0xcab1e006 +%define VMMDEV_TESTING_CMD_VALUE_REG 0xcab1e007 +%define VMMDEV_TESTING_CMD_PRINT 0xcab1e008 +%define VMMDEV_TESTING_CMD_QUERY_CFG 0xcab1e009 +%define VMMDEV_TESTING_CMD_MAGIC 0xcab1e000 +%define VMMDEV_TESTING_CMD_MAGIC_MASK 0xffffff00 +%define VMMDEV_TESTING_CMD_MAGIC_HI_WORD 0xcab10000 +%define VMMDEV_TESTING_UNIT_PCT 0x01 +%define VMMDEV_TESTING_UNIT_BYTES 0x02 +%define VMMDEV_TESTING_UNIT_BYTES_PER_SEC 0x03 +%define VMMDEV_TESTING_UNIT_KILOBYTES 0x04 +%define VMMDEV_TESTING_UNIT_KILOBYTES_PER_SEC 0x05 +%define VMMDEV_TESTING_UNIT_MEGABYTES 0x06 +%define VMMDEV_TESTING_UNIT_MEGABYTES_PER_SEC 0x07 +%define VMMDEV_TESTING_UNIT_PACKETS 0x08 +%define VMMDEV_TESTING_UNIT_PACKETS_PER_SEC 0x09 +%define VMMDEV_TESTING_UNIT_FRAMES 0x0a +%define VMMDEV_TESTING_UNIT_FRAMES_PER_SEC 0x0b +%define VMMDEV_TESTING_UNIT_OCCURRENCES 0x0c +%define VMMDEV_TESTING_UNIT_OCCURRENCES_PER_SEC 0x0d +%define VMMDEV_TESTING_UNIT_CALLS 0x0e +%define VMMDEV_TESTING_UNIT_CALLS_PER_SEC 0x0f +%define VMMDEV_TESTING_UNIT_ROUND_TRIP 0x10 +%define VMMDEV_TESTING_UNIT_SECS 0x11 +%define VMMDEV_TESTING_UNIT_MS 0x12 +%define VMMDEV_TESTING_UNIT_NS 0x13 +%define VMMDEV_TESTING_UNIT_NS_PER_CALL 0x14 +%define VMMDEV_TESTING_UNIT_NS_PER_FRAME 0x15 +%define VMMDEV_TESTING_UNIT_NS_PER_OCCURRENCE 0x16 +%define VMMDEV_TESTING_UNIT_NS_PER_PACKET 0x17 +%define VMMDEV_TESTING_UNIT_NS_PER_ROUND_TRIP 0x18 +%define VMMDEV_TESTING_UNIT_INSTRS 0x19 +%define VMMDEV_TESTING_UNIT_INSTRS_PER_SEC 0x1a +%define VMMDEV_TESTING_UNIT_NONE 0x1b +%define VMMDEV_TESTING_UNIT_PP1K 0x1c +%define VMMDEV_TESTING_UNIT_PP10K 0x1d +%define VMMDEV_TESTING_UNIT_PPM 0x1e +%define VMMDEV_TESTING_UNIT_PPB 0x1f +%define VMMDEV_TESTING_UNIT_TICKS 0x20 +%define VMMDEV_TESTING_UNIT_TICKS_PER_CALL 0x21 +%define VMMDEV_TESTING_UNIT_TICKS_PER_OCCURENCE 0x22 +%define VMMDEV_TESTING_UNIT_PAGES 0x23 +%define VMMDEV_TESTING_UNIT_PAGES_PER_SEC 0x24 +%define VMMDEV_TESTING_UNIT_TICKS_PER_PAGE 0x25 +%define VMMDEV_TESTING_UNIT_NS_PER_PAGE 0x26 +%define VMMDEV_TESTING_UNIT_PS 0x27 +%define VMMDEV_TESTING_UNIT_PS_PER_CALL 0x28 +%define VMMDEV_TESTING_UNIT_PS_PER_FRAME 0x29 +%define VMMDEV_TESTING_UNIT_PS_PER_OCCURRENCE 0x2a +%define VMMDEV_TESTING_UNIT_PS_PER_PACKET 0x2b +%define VMMDEV_TESTING_UNIT_PS_PER_ROUND_TRIP 0x2c +%define VMMDEV_TESTING_UNIT_PS_PER_PAGE 0x2d +%define VMMDEV_TESTING_NOP_RET 0x64726962 +%define VMMDEV_TESTING_LOCKED_LO_HOLD_MASK 0x0000ffff +%define VMMDEV_TESTING_LOCKED_LO_WAIT_MASK 0xffff0000 +%define VMMDEV_TESTING_LOCKED_LO_WAIT_SHIFT 16 +%define VMMDEV_TESTING_LOCKED_HI_TICKS_MASK 0x000fffff +%define VMMDEV_TESTING_LOCKED_HI_MBZ_MASK 0x03f00000 +%define VMMDEV_TESTING_LOCKED_HI_THREAD_SHARED 0x04000000 +%define VMMDEV_TESTING_LOCKED_HI_EMT_SHARED 0x08000000 +%define VMMDEV_TESTING_LOCKED_HI_TYPE_RW 0x10000000 +%define VMMDEV_TESTING_LOCKED_HI_BUSY_SUCCESS 0x20000000 +%define VMMDEV_TESTING_LOCKED_HI_POKE 0x40000000 +%define VMMDEV_TESTING_LOCKED_HI_ENABLED 0x80000000 +%define VMMDEV_TESTING_CFG_DWORD0 0x0000 +%define VMMDEV_TESTING_CFG_DWORD1 0x0001 +%define VMMDEV_TESTING_CFG_DWORD2 0x0002 +%define VMMDEV_TESTING_CFG_DWORD3 0x0003 +%define VMMDEV_TESTING_CFG_DWORD4 0x0004 +%define VMMDEV_TESTING_CFG_DWORD5 0x0005 +%define VMMDEV_TESTING_CFG_DWORD6 0x0006 +%define VMMDEV_TESTING_CFG_DWORD7 0x0007 +%define VMMDEV_TESTING_CFG_DWORD8 0x0008 +%define VMMDEV_TESTING_CFG_DWORD9 0x0009 +%define VMMDEV_TESTING_CFG_IS_NEM_LINUX 0x0100 +%define VMMDEV_TESTING_CFG_IS_NEM_WINDOWS 0x0101 +%define VMMDEV_TESTING_CFG_IS_NEM_DARWIN 0x0102 +%endif diff --git a/include/VBox/apic.h b/include/VBox/apic.h new file mode 100644 index 00000000..e6f213f4 --- /dev/null +++ b/include/VBox/apic.h @@ -0,0 +1,493 @@ +/** @file + * X86 (and AMD64) Local APIC registers (VMM,++). + * + * apic.mac is generated from this file by running 'kmk incs' in the root. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_apic_h +#define VBOX_INCLUDED_apic_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/x86.h> + +/** @todo These are defines used by CPUM and perhaps some assembly code. Remove + * these and use the XAPIC counterpart defines below later. */ +#define APIC_REG_VERSION 0x0030 +#define APIC_REG_VERSION_GET_VER(u32) (u32 & 0xff) +#define APIC_REG_VERSION_GET_MAX_LVT(u32) ((u32 & 0xff0000) >> 16) + +/* Defines according to Figure 10-8 of the Intel Software Developers Manual Vol 3A */ +#define APIC_REG_LVT_LINT0 0x0350 +#define APIC_REG_LVT_LINT1 0x0360 +#define APIC_REG_LVT_ERR 0x0370 +#define APIC_REG_LVT_PC 0x0340 +#define APIC_REG_LVT_THMR 0x0330 +#define APIC_REG_LVT_CMCI 0x02F0 +#define APIC_REG_EILVT0 0x0500 +#define APIC_REG_EILVT1 0x0510 +#define APIC_REG_EILVT2 0x0520 +#define APIC_REG_EILVT3 0x0530 +#define APIC_REG_LVT_MODE_MASK (RT_BIT(8) | RT_BIT(9) | RT_BIT(10)) +#define APIC_REG_LVT_MODE_FIXED 0 +#define APIC_REG_LVT_MODE_NMI RT_BIT(10) +#define APIC_REG_LVT_MODE_EXTINT (RT_BIT(8) | RT_BIT(9) | RT_BIT(10)) +#define APIC_REG_LVT_PIN_POLARIY RT_BIT(13) +#define APIC_REG_LVT_REMOTE_IRR RT_BIT(14) +#define APIC_REG_LVT_LEVEL_TRIGGER RT_BIT(15) +#define APIC_REG_LVT_MASKED RT_BIT(16) + +/** The APIC hardware version number for Pentium 4. */ +#define XAPIC_HARDWARE_VERSION_P4 UINT8_C(0x14) +/** Maximum number of LVT entries for Pentium 4. */ +#define XAPIC_MAX_LVT_ENTRIES_P4 UINT8_C(6) +/** Size of the APIC ID bits for Pentium 4. */ +#define XAPIC_APIC_ID_BIT_COUNT_P4 UINT8_C(8) + +/** The APIC hardware version number for Pentium 6. */ +#define XAPIC_HARDWARE_VERSION_P6 UINT8_C(0x10) +/** Maximum number of LVT entries for Pentium 6. */ +#define XAPIC_MAX_LVT_ENTRIES_P6 UINT8_C(4) +/** Size of the APIC ID bits for Pentium 6. */ +#define XAPIC_APIC_ID_BIT_COUNT_P6 UINT8_C(4) + +/** Illegal APIC vector value start. */ +#define XAPIC_ILLEGAL_VECTOR_START UINT8_C(0) +/** Illegal APIC vector value end (inclusive). */ +#define XAPIC_ILLEGAL_VECTOR_END UINT8_C(15) +/** Reserved APIC vector value start. */ +#define XAPIC_RSVD_VECTOR_START UINT8_C(16) +/** Reserved APIC vector value end (inclusive). */ +#define XAPIC_RSVD_VECTOR_END UINT8_C(31) + +/** ESR - Send checksum error for Pentium 6. */ +# define XAPIC_ESR_SEND_CHKSUM_ERROR_P6 RT_BIT(0) +/** ESR - Send accept error for Pentium 6. */ +# define XAPIC_ESR_RECV_CHKSUM_ERROR_P6 RT_BIT(1) +/** ESR - Send accept error for Pentium 6. */ +# define XAPIC_ESR_SEND_ACCEPT_ERROR_P6 RT_BIT(2) +/** ESR - Receive accept error for Pentium 6. */ +# define XAPIC_ESR_RECV_ACCEPT_ERROR_P6 RT_BIT(3) + +/** ESR - Redirectable IPI. */ +#define XAPIC_ESR_REDIRECTABLE_IPI RT_BIT(4) +/** ESR - Send accept error. */ +#define XAPIC_ESR_SEND_ILLEGAL_VECTOR RT_BIT(5) +/** ESR - Send accept error. */ +#define XAPIC_ESR_RECV_ILLEGAL_VECTOR RT_BIT(6) +/** ESR - Send accept error. */ +#define XAPIC_ESR_ILLEGAL_REG_ADDRESS RT_BIT(7) +/** ESR - Valid write-only bits. */ +#define XAPIC_ESR_WO_VALID UINT32_C(0x0) + +/** TPR - Valid bits. */ +#define XAPIC_TPR_VALID UINT32_C(0xff) +/** TPR - Task-priority class. */ +#define XAPIC_TPR_TP UINT32_C(0xf0) +/** TPR - Task-priority subclass. */ +#define XAPIC_TPR_TP_SUBCLASS UINT32_C(0x0f) +/** TPR - Gets the task-priority class. */ +#define XAPIC_TPR_GET_TP(a_Tpr) ((a_Tpr) & XAPIC_TPR_TP) +/** TPR - Gets the task-priority subclass. */ +#define XAPIC_TPR_GET_TP_SUBCLASS(a_Tpr) ((a_Tpr) & XAPIC_TPR_TP_SUBCLASS) + +/** PPR - Valid bits. */ +#define XAPIC_PPR_VALID UINT32_C(0xff) +/** PPR - Processor-priority class. */ +#define XAPIC_PPR_PP UINT32_C(0xf0) +/** PPR - Processor-priority subclass. */ +#define XAPIC_PPR_PP_SUBCLASS UINT32_C(0x0f) +/** PPR - Get the processor-priority class. */ +#define XAPIC_PPR_GET_PP(a_Ppr) ((a_Ppr) & XAPIC_PPR_PP) +/** PPR - Get the processor-priority subclass. */ +#define XAPIC_PPR_GET_PP_SUBCLASS(a_Ppr) ((a_Ppr) & XAPIC_PPR_PP_SUBCLASS) + +/** Timer mode - One-shot. */ +#define XAPIC_TIMER_MODE_ONESHOT UINT32_C(0) +/** Timer mode - Periodic. */ +#define XAPIC_TIMER_MODE_PERIODIC UINT32_C(1) +/** Timer mode - TSC deadline. */ +#define XAPIC_TIMER_MODE_TSC_DEADLINE UINT32_C(2) + +/** LVT - The vector. */ +#define XAPIC_LVT_VECTOR UINT32_C(0xff) +/** LVT - Gets the vector from an LVT entry. */ +#define XAPIC_LVT_GET_VECTOR(a_Lvt) ((a_Lvt) & XAPIC_LVT_VECTOR) +/** LVT - The mask. */ +#define XAPIC_LVT_MASK RT_BIT(16) +/** LVT - Is the LVT masked? */ +#define XAPIC_LVT_IS_MASKED(a_Lvt) RT_BOOL((a_Lvt) & XAPIC_LVT_MASK) +/** LVT - Timer mode. */ +#define XAPIC_LVT_TIMER_MODE RT_BIT(17) +/** LVT - Timer TSC-deadline timer mode. */ +#define XAPIC_LVT_TIMER_TSCDEADLINE RT_BIT(18) +/** LVT - Gets the timer mode. */ +#define XAPIC_LVT_GET_TIMER_MODE(a_Lvt) (XAPICTIMERMODE)(((a_Lvt) >> 17) & UINT32_C(3)) +/** LVT - Delivery mode. */ +#define XAPIC_LVT_DELIVERY_MODE (RT_BIT(8) | RT_BIT(9) | RT_BIT(10)) +/** LVT - Gets the delivery mode. */ +#define XAPIC_LVT_GET_DELIVERY_MODE(a_Lvt) (XAPICDELIVERYMODE)(((a_Lvt) >> 8) & UINT32_C(7)) +/** LVT - Delivery status. */ +#define XAPIC_LVT_DELIVERY_STATUS RT_BIT(12) +/** LVT - Trigger mode. */ +#define XAPIC_LVT_TRIGGER_MODE RT_BIT(15) +/** LVT - Gets the trigger mode. */ +#define XAPIC_LVT_GET_TRIGGER_MODE(a_Lvt) (XAPICTRIGGERMODE)(((a_Lvt) >> 15) & UINT32_C(1)) +/** LVT - Remote IRR. */ +#define XAPIC_LVT_REMOTE_IRR RT_BIT(14) +/** LVT - Gets the Remote IRR. */ +#define XAPIC_LVT_GET_REMOTE_IRR(a_Lvt) (((a_Lvt) >> 14) & 1) +/** LVT - Interrupt Input Pin Polarity. */ +#define XAPIC_LVT_POLARITY RT_BIT(13) +/** LVT - Gets the Interrupt Input Pin Polarity. */ +#define XAPIC_LVT_GET_POLARITY(a_Lvt) (((a_Lvt) >> 13) & 1) +/** LVT - Valid bits common to all LVTs. */ +#define XAPIC_LVT_COMMON_VALID (XAPIC_LVT_VECTOR | XAPIC_LVT_DELIVERY_STATUS | XAPIC_LVT_MASK) +/** LVT CMCI - Valid bits. */ +#define XAPIC_LVT_CMCI_VALID (XAPIC_LVT_COMMON_VALID | XAPIC_LVT_DELIVERY_MODE) +/** LVT Timer - Valid bits. */ +#define XAPIC_LVT_TIMER_VALID (XAPIC_LVT_COMMON_VALID | XAPIC_LVT_TIMER_MODE | XAPIC_LVT_TIMER_TSCDEADLINE) +/** LVT Thermal - Valid bits. */ +#define XAPIC_LVT_THERMAL_VALID (XAPIC_LVT_COMMON_VALID | XAPIC_LVT_DELIVERY_MODE) +/** LVT Perf - Valid bits. */ +#define XAPIC_LVT_PERF_VALID (XAPIC_LVT_COMMON_VALID | XAPIC_LVT_DELIVERY_MODE) +/** LVT LINTx - Valid bits. */ +#define XAPIC_LVT_LINT_VALID ( XAPIC_LVT_COMMON_VALID | XAPIC_LVT_DELIVERY_MODE | XAPIC_LVT_DELIVERY_STATUS \ + | XAPIC_LVT_POLARITY | XAPIC_LVT_REMOTE_IRR | XAPIC_LVT_TRIGGER_MODE) +/** LVT Error - Valid bits. */ +#define XAPIC_LVT_ERROR_VALID (XAPIC_LVT_COMMON_VALID) + +/** SVR - The vector. */ +#define XAPIC_SVR_VECTOR UINT32_C(0xff) +/** SVR - APIC Software enable. */ +#define XAPIC_SVR_SOFTWARE_ENABLE RT_BIT(8) +/** SVR - Supress EOI broadcast. */ +#define XAPIC_SVR_SUPRESS_EOI_BROADCAST RT_BIT(12) +/** SVR - Valid bits for Pentium 4. */ +# define XAPIC_SVR_VALID_P4 (XAPIC_SVR_VECTOR | XAPIC_SVR_SOFTWARE_ENABLE) +/** @todo SVR - Valid bits for Pentium 6. */ + +/** DFR - Valid bits. */ +#define XAPIC_DFR_VALID UINT32_C(0xf0000000) +/** DFR - Reserved bits that must always remain set. */ +#define XAPIC_DFR_RSVD_MB1 UINT32_C(0x0fffffff) +/** DFR - The model. */ +#define XAPIC_DFR_MODEL UINT32_C(0xf) +/** DFR - Gets the destination model. */ +#define XAPIC_DFR_GET_MODEL(a_uReg) (((a_uReg) >> 28) & XAPIC_DFR_MODEL) + +/** LDR - Valid bits. */ +#define XAPIC_LDR_VALID UINT32_C(0xff000000) +/** LDR - Cluster ID mask (x2APIC). */ +#define X2APIC_LDR_CLUSTER_ID UINT32_C(0xffff0000) +/** LDR - Mask of the LDR cluster ID (x2APIC). */ +#define X2APIC_LDR_GET_CLUSTER_ID(a_uReg) ((a_uReg) & X2APIC_LDR_CLUSTER_ID) +/** LDR - Mask of the LDR logical ID (x2APIC). */ +#define X2APIC_LDR_LOGICAL_ID UINT32_C(0x0000ffff) + +/** LDR - Flat mode logical ID mask. */ +#define XAPIC_LDR_FLAT_LOGICAL_ID UINT32_C(0xff) +/** LDR - Clustered mode cluster ID mask. */ +#define XAPIC_LDR_CLUSTERED_CLUSTER_ID UINT32_C(0xf0) +/** LDR - Clustered mode logical ID mask. */ +#define XAPIC_LDR_CLUSTERED_LOGICAL_ID UINT32_C(0x0f) +/** LDR - Gets the clustered mode cluster ID. */ +#define XAPIC_LDR_CLUSTERED_GET_CLUSTER_ID(a_uReg) ((a_uReg) & XAPIC_LDR_CLUSTERED_CLUSTER_ID) + + +/** EOI - Valid write-only bits. */ +#define XAPIC_EOI_WO_VALID UINT32_C(0x0) +/** Timer ICR - Valid bits. */ +#define XAPIC_TIMER_ICR_VALID UINT32_C(0xffffffff) +/** Timer DCR - Valid bits. */ +#define XAPIC_TIMER_DCR_VALID (RT_BIT(0) | RT_BIT(1) | RT_BIT(3)) + +/** Self IPI - Valid bits. */ +#define XAPIC_SELF_IPI_VALID UINT32_C(0xff) +/** Self IPI - The vector. */ +#define XAPIC_SELF_IPI_VECTOR UINT32_C(0xff) +/** Self IPI - Gets the vector. */ +#define XAPIC_SELF_IPI_GET_VECTOR(a_uReg) ((a_uReg) & XAPIC_SELF_IPI_VECTOR) + +/** ICR Low - The Vector. */ +#define XAPIC_ICR_LO_VECTOR UINT32_C(0xff) +/** ICR Low - Gets the vector. */ +#define XAPIC_ICR_LO_GET_VECTOR(a_uIcr) ((a_uIcr) & XAPIC_ICR_LO_VECTOR) +/** ICR Low - The delivery mode. */ +#define XAPIC_ICR_LO_DELIVERY_MODE (RT_BIT(8) | RT_BIT(9) | RT_BIT(10)) +/** ICR Low - The destination mode. */ +#define XAPIC_ICR_LO_DEST_MODE RT_BIT(11) +/** ICR Low - The delivery status. */ +#define XAPIC_ICR_LO_DELIVERY_STATUS RT_BIT(12) +/** ICR Low - The level. */ +#define XAPIC_ICR_LO_LEVEL RT_BIT(14) +/** ICR Low - The trigger mode. */ +#define XAPIC_ICR_TRIGGER_MODE RT_BIT(15) +/** ICR Low - The destination shorthand. */ +#define XAPIC_ICR_LO_DEST_SHORTHAND (RT_BIT(18) | RT_BIT(19)) +/** ICR Low - Valid write bits. */ +#define XAPIC_ICR_LO_WR_VALID ( XAPIC_ICR_LO_VECTOR | XAPIC_ICR_LO_DELIVERY_MODE | XAPIC_ICR_LO_DEST_MODE \ + | XAPIC_ICR_LO_LEVEL | XAPIC_ICR_TRIGGER_MODE | XAPIC_ICR_LO_DEST_SHORTHAND) + +/** ICR High - The destination field. */ +#define XAPIC_ICR_HI_DEST UINT32_C(0xff000000) +/** ICR High - Get the destination field. */ +#define XAPIC_ICR_HI_GET_DEST(a_u32IcrHi) (((a_u32IcrHi) >> 24) & XAPIC_ICR_HI_DEST) +/** ICR High - Valid write bits in xAPIC mode. */ +#define XAPIC_ICR_HI_WR_VALID XAPIC_ICR_HI_DEST + +/** APIC ID broadcast mask - x2APIC mode. */ +#define X2APIC_ID_BROADCAST_MASK UINT32_C(0xffffffff) +/** APIC ID broadcast mask - xAPIC mode for Pentium 4. */ +# define XAPIC_ID_BROADCAST_MASK_P4 UINT32_C(0xff) +/** @todo Broadcast mask for Pentium 6. */ + +/** Get an xAPIC page offset for an x2APIC MSR value. */ +#define X2APIC_GET_XAPIC_OFF(a_uMsr) ((((a_uMsr) - MSR_IA32_X2APIC_START) << 4) & UINT32_C(0xff0)) +/** Get an x2APIC MSR for an xAPIC page offset. */ +#define XAPIC_GET_X2APIC_MSR(a_offReg) ((((a_offReg) & UINT32_C(0xff0)) >> 4) | MSR_IA32_X2APIC_START) + +/** @name xAPIC and x2APIC register offsets. + * See Intel spec. 10.4.1 "The Local APIC Block Diagram". + * @{ */ +/** Offset of APIC ID Register. */ +#define XAPIC_OFF_ID 0x020 +/** Offset of APIC Version Register. */ +#define XAPIC_OFF_VERSION 0x030 +/** Offset of Task Priority Register. */ +#define XAPIC_OFF_TPR 0x080 +/** Offset of Arbitrartion Priority register. */ +#define XAPIC_OFF_APR 0x090 +/** Offset of Processor Priority register. */ +#define XAPIC_OFF_PPR 0x0A0 +/** Offset of End Of Interrupt register. */ +#define XAPIC_OFF_EOI 0x0B0 +/** Offset of Remote Read Register. */ +#define XAPIC_OFF_RRD 0x0C0 +/** Offset of Logical Destination Register. */ +#define XAPIC_OFF_LDR 0x0D0 +/** Offset of Destination Format Register. */ +#define XAPIC_OFF_DFR 0x0E0 +/** Offset of Spurious Interrupt Vector Register. */ +#define XAPIC_OFF_SVR 0x0F0 +/** Offset of In-service Register (bits 31:0). */ +#define XAPIC_OFF_ISR0 0x100 +/** Offset of In-service Register (bits 63:32). */ +#define XAPIC_OFF_ISR1 0x110 +/** Offset of In-service Register (bits 95:64). */ +#define XAPIC_OFF_ISR2 0x120 +/** Offset of In-service Register (bits 127:96). */ +#define XAPIC_OFF_ISR3 0x130 +/** Offset of In-service Register (bits 159:128). */ +#define XAPIC_OFF_ISR4 0x140 +/** Offset of In-service Register (bits 191:160). */ +#define XAPIC_OFF_ISR5 0x150 +/** Offset of In-service Register (bits 223:192). */ +#define XAPIC_OFF_ISR6 0x160 +/** Offset of In-service Register (bits 255:224). */ +#define XAPIC_OFF_ISR7 0x170 +/** Offset of Trigger Mode Register (bits 31:0). */ +#define XAPIC_OFF_TMR0 0x180 +/** Offset of Trigger Mode Register (bits 63:32). */ +#define XAPIC_OFF_TMR1 0x190 +/** Offset of Trigger Mode Register (bits 95:64). */ +#define XAPIC_OFF_TMR2 0x1A0 +/** Offset of Trigger Mode Register (bits 127:96). */ +#define XAPIC_OFF_TMR3 0x1B0 +/** Offset of Trigger Mode Register (bits 159:128). */ +#define XAPIC_OFF_TMR4 0x1C0 +/** Offset of Trigger Mode Register (bits 191:160). */ +#define XAPIC_OFF_TMR5 0x1D0 +/** Offset of Trigger Mode Register (bits 223:192). */ +#define XAPIC_OFF_TMR6 0x1E0 +/** Offset of Trigger Mode Register (bits 255:224). */ +#define XAPIC_OFF_TMR7 0x1F0 +/** Offset of Interrupt Request Register (bits 31:0). */ +#define XAPIC_OFF_IRR0 0x200 +/** Offset of Interrupt Request Register (bits 63:32). */ +#define XAPIC_OFF_IRR1 0x210 +/** Offset of Interrupt Request Register (bits 95:64). */ +#define XAPIC_OFF_IRR2 0x220 +/** Offset of Interrupt Request Register (bits 127:96). */ +#define XAPIC_OFF_IRR3 0x230 +/** Offset of Interrupt Request Register (bits 159:128). */ +#define XAPIC_OFF_IRR4 0x240 +/** Offset of Interrupt Request Register (bits 191:160). */ +#define XAPIC_OFF_IRR5 0x250 +/** Offset of Interrupt Request Register (bits 223:192). */ +#define XAPIC_OFF_IRR6 0x260 +/** Offset of Interrupt Request Register (bits 255:224). */ +#define XAPIC_OFF_IRR7 0x270 +/** Offset of Error Status Register. */ +#define XAPIC_OFF_ESR 0x280 +/** Offset of LVT CMCI Register. */ +#define XAPIC_OFF_LVT_CMCI 0x2F0 +/** Offset of Interrupt Command Register - Lo. */ +#define XAPIC_OFF_ICR_LO 0x300 +/** Offset of Interrupt Command Register - Hi. */ +#define XAPIC_OFF_ICR_HI 0x310 +/** Offset of LVT Timer Register. */ +#define XAPIC_OFF_LVT_TIMER 0x320 +/** Offset of LVT Thermal Sensor Register. */ +#define XAPIC_OFF_LVT_THERMAL 0x330 +/** Offset of LVT Performance Counter Register. */ +#define XAPIC_OFF_LVT_PERF 0x340 +/** Offset of LVT LINT0 Register. */ +#define XAPIC_OFF_LVT_LINT0 0x350 +/** Offset of LVT LINT1 Register. */ +#define XAPIC_OFF_LVT_LINT1 0x360 +/** Offset of LVT Error Register . */ +#define XAPIC_OFF_LVT_ERROR 0x370 +/** Offset of Timer Initial Count Register. */ +#define XAPIC_OFF_TIMER_ICR 0x380 +/** Offset of Timer Current Count Register. */ +#define XAPIC_OFF_TIMER_CCR 0x390 +/** Offset of Timer Divide Configuration Register. */ +#define XAPIC_OFF_TIMER_DCR 0x3E0 +/** Offset of Self-IPI Register (x2APIC only). */ +#define X2APIC_OFF_SELF_IPI 0x3F0 + +/** Offset of LVT range start. */ +#define XAPIC_OFF_LVT_START XAPIC_OFF_LVT_TIMER +/** Offset of LVT range end (inclusive). */ +#define XAPIC_OFF_LVT_END XAPIC_OFF_LVT_ERROR +/** Offset of LVT extended range start. */ +#define XAPIC_OFF_LVT_EXT_START XAPIC_OFF_LVT_CMCI +/** Offset of LVT extended range end (inclusive). */ +#define XAPIC_OFF_LVT_EXT_END XAPIC_OFF_LVT_CMCI +/** Offset of the last register (incl. reserved) in the xAPIC/x2APIC range. */ +#define XAPIC_OFF_END 0x3F0 +/** @} */ + +/** @name xAPIC Destination Format Register bits. + * See Intel spec. 10.6.2.2 "Logical Destination Mode". + * @{ */ +typedef enum XAPICDESTFORMAT +{ + XAPICDESTFORMAT_FLAT = 0xf, + XAPICDESTFORMAT_CLUSTER = 0 +} XAPICDESTFORMAT; +/** @} */ + +/** @name xAPIC Timer Mode bits. + * See Intel spec. 10.5.1 "Local Vector Table". + * @{ */ +typedef enum XAPICTIMERMODE +{ + XAPICTIMERMODE_ONESHOT = XAPIC_TIMER_MODE_ONESHOT, + XAPICTIMERMODE_PERIODIC = XAPIC_TIMER_MODE_PERIODIC, + XAPICTIMERMODE_TSC_DEADLINE = XAPIC_TIMER_MODE_TSC_DEADLINE +} XAPICTIMERMODE; +/** @} */ + +/** @name xAPIC Interrupt Command Register bits. + * See Intel spec. 10.6.1 "Interrupt Command Register (ICR)". + * See Intel spec. 10.5.1 "Local Vector Table". + * @{ */ +/** + * xAPIC destination shorthand. + */ +typedef enum XAPICDESTSHORTHAND +{ + XAPICDESTSHORTHAND_NONE = 0, + XAPICDESTSHORTHAND_SELF, + XAPIDDESTSHORTHAND_ALL_INCL_SELF, + XAPICDESTSHORTHAND_ALL_EXCL_SELF +} XAPICDESTSHORTHAND; + +/** + * xAPIC INIT level de-assert delivery mode. + */ +typedef enum XAPICINITLEVEL +{ + XAPICINITLEVEL_DEASSERT = 0, + XAPICINITLEVEL_ASSERT +} XAPICLEVEL; + +/** + * xAPIC destination mode. + */ +typedef enum XAPICDESTMODE +{ + XAPICDESTMODE_PHYSICAL = 0, + XAPICDESTMODE_LOGICAL +} XAPICDESTMODE; + +/** + * xAPIC delivery mode type. + */ +typedef enum XAPICDELIVERYMODE +{ + XAPICDELIVERYMODE_FIXED = 0, + XAPICDELIVERYMODE_LOWEST_PRIO = 1, + XAPICDELIVERYMODE_SMI = 2, + XAPICDELIVERYMODE_NMI = 4, + XAPICDELIVERYMODE_INIT = 5, + XAPICDELIVERYMODE_STARTUP = 6, + XAPICDELIVERYMODE_EXTINT = 7 +} XAPICDELIVERYMODE; + +/** + * xAPIC trigger mode. + */ +typedef enum XAPICTRIGGERMODE +{ + XAPICTRIGGERMODE_EDGE = 0, + XAPICTRIGGERMODE_LEVEL +} XAPICTRIGGERMODE; +/** @} */ + + +DECLINLINE(uint32_t) ApicRegRead(void *pvBase, uint32_t offReg) +{ + return *(const volatile uint32_t *)((uintptr_t)pvBase + offReg); +} + + +#ifdef IPRT_INCLUDED_asm_amd64_x86_h +/** + * Reads an X2APIC register. + * + * @param offReg MMIO offset, APIC_REG_XXX. + */ +DECLINLINE(uint32_t) ApicX2RegRead32(uint32_t offReg) +{ + return ASMRdMsr((offReg >> 4) + MSR_IA32_X2APIC_START); +} +#endif + +#endif /* !VBOX_INCLUDED_apic_h */ + diff --git a/include/VBox/apic.mac b/include/VBox/apic.mac new file mode 100644 index 00000000..db4ba7d7 --- /dev/null +++ b/include/VBox/apic.mac @@ -0,0 +1,213 @@ +;; @file +; X86 (and AMD64) Local APIC registers (VMM,++). +; +; Automatically generated by various.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2010-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef VBOX_INCLUDED_apic_h +%define VBOX_INCLUDED_apic_h +%ifndef RT_WITHOUT_PRAGMA_ONCE +%endif +%define APIC_REG_VERSION 0x0030 +%define APIC_REG_VERSION_GET_VER(u32) (u32 & 0xff) +%define APIC_REG_VERSION_GET_MAX_LVT(u32) ((u32 & 0xff0000) >> 16) +%define APIC_REG_LVT_LINT0 0x0350 +%define APIC_REG_LVT_LINT1 0x0360 +%define APIC_REG_LVT_ERR 0x0370 +%define APIC_REG_LVT_PC 0x0340 +%define APIC_REG_LVT_THMR 0x0330 +%define APIC_REG_LVT_CMCI 0x02F0 +%define APIC_REG_EILVT0 0x0500 +%define APIC_REG_EILVT1 0x0510 +%define APIC_REG_EILVT2 0x0520 +%define APIC_REG_EILVT3 0x0530 +%define APIC_REG_LVT_MODE_MASK (RT_BIT(8) | RT_BIT(9) | RT_BIT(10)) +%define APIC_REG_LVT_MODE_FIXED 0 +%define APIC_REG_LVT_MODE_NMI RT_BIT(10) +%define APIC_REG_LVT_MODE_EXTINT (RT_BIT(8) | RT_BIT(9) | RT_BIT(10)) +%define APIC_REG_LVT_PIN_POLARIY RT_BIT(13) +%define APIC_REG_LVT_REMOTE_IRR RT_BIT(14) +%define APIC_REG_LVT_LEVEL_TRIGGER RT_BIT(15) +%define APIC_REG_LVT_MASKED RT_BIT(16) +%define XAPIC_HARDWARE_VERSION_P4 0x14 +%define XAPIC_MAX_LVT_ENTRIES_P4 6 +%define XAPIC_APIC_ID_BIT_COUNT_P4 8 +%define XAPIC_HARDWARE_VERSION_P6 0x10 +%define XAPIC_MAX_LVT_ENTRIES_P6 4 +%define XAPIC_APIC_ID_BIT_COUNT_P6 4 +%define XAPIC_ILLEGAL_VECTOR_START 0 +%define XAPIC_ILLEGAL_VECTOR_END 15 +%define XAPIC_RSVD_VECTOR_START 16 +%define XAPIC_RSVD_VECTOR_END 31 + %define XAPIC_ESR_SEND_CHKSUM_ERROR_P6 RT_BIT(0) + %define XAPIC_ESR_RECV_CHKSUM_ERROR_P6 RT_BIT(1) + %define XAPIC_ESR_SEND_ACCEPT_ERROR_P6 RT_BIT(2) + %define XAPIC_ESR_RECV_ACCEPT_ERROR_P6 RT_BIT(3) +%define XAPIC_ESR_REDIRECTABLE_IPI RT_BIT(4) +%define XAPIC_ESR_SEND_ILLEGAL_VECTOR RT_BIT(5) +%define XAPIC_ESR_RECV_ILLEGAL_VECTOR RT_BIT(6) +%define XAPIC_ESR_ILLEGAL_REG_ADDRESS RT_BIT(7) +%define XAPIC_ESR_WO_VALID 0x0 +%define XAPIC_TPR_VALID 0xff +%define XAPIC_TPR_TP 0xf0 +%define XAPIC_TPR_TP_SUBCLASS 0x0f +%define XAPIC_TPR_GET_TP(a_Tpr) ((a_Tpr) & XAPIC_TPR_TP) +%define XAPIC_TPR_GET_TP_SUBCLASS(a_Tpr) ((a_Tpr) & XAPIC_TPR_TP_SUBCLASS) +%define XAPIC_PPR_VALID 0xff +%define XAPIC_PPR_PP 0xf0 +%define XAPIC_PPR_PP_SUBCLASS 0x0f +%define XAPIC_PPR_GET_PP(a_Ppr) ((a_Ppr) & XAPIC_PPR_PP) +%define XAPIC_PPR_GET_PP_SUBCLASS(a_Ppr) ((a_Ppr) & XAPIC_PPR_PP_SUBCLASS) +%define XAPIC_TIMER_MODE_ONESHOT 0 +%define XAPIC_TIMER_MODE_PERIODIC 1 +%define XAPIC_TIMER_MODE_TSC_DEADLINE 2 +%define XAPIC_LVT_VECTOR 0xff +%define XAPIC_LVT_GET_VECTOR(a_Lvt) ((a_Lvt) & XAPIC_LVT_VECTOR) +%define XAPIC_LVT_MASK RT_BIT(16) +%define XAPIC_LVT_IS_MASKED(a_Lvt) RT_BOOL((a_Lvt) & XAPIC_LVT_MASK) +%define XAPIC_LVT_TIMER_MODE RT_BIT(17) +%define XAPIC_LVT_TIMER_TSCDEADLINE RT_BIT(18) +%define XAPIC_LVT_GET_TIMER_MODE(a_Lvt) (XAPICTIMERMODE)(((a_Lvt) >> 17) & 3) +%define XAPIC_LVT_DELIVERY_MODE (RT_BIT(8) | RT_BIT(9) | RT_BIT(10)) +%define XAPIC_LVT_GET_DELIVERY_MODE(a_Lvt) (XAPICDELIVERYMODE)(((a_Lvt) >> 8) & 7) +%define XAPIC_LVT_DELIVERY_STATUS RT_BIT(12) +%define XAPIC_LVT_TRIGGER_MODE RT_BIT(15) +%define XAPIC_LVT_GET_TRIGGER_MODE(a_Lvt) (XAPICTRIGGERMODE)(((a_Lvt) >> 15) & 1) +%define XAPIC_LVT_REMOTE_IRR RT_BIT(14) +%define XAPIC_LVT_GET_REMOTE_IRR(a_Lvt) (((a_Lvt) >> 14) & 1) +%define XAPIC_LVT_POLARITY RT_BIT(13) +%define XAPIC_LVT_GET_POLARITY(a_Lvt) (((a_Lvt) >> 13) & 1) +%define XAPIC_LVT_COMMON_VALID (XAPIC_LVT_VECTOR | XAPIC_LVT_DELIVERY_STATUS | XAPIC_LVT_MASK) +%define XAPIC_LVT_CMCI_VALID (XAPIC_LVT_COMMON_VALID | XAPIC_LVT_DELIVERY_MODE) +%define XAPIC_LVT_TIMER_VALID (XAPIC_LVT_COMMON_VALID | XAPIC_LVT_TIMER_MODE | XAPIC_LVT_TIMER_TSCDEADLINE) +%define XAPIC_LVT_THERMAL_VALID (XAPIC_LVT_COMMON_VALID | XAPIC_LVT_DELIVERY_MODE) +%define XAPIC_LVT_PERF_VALID (XAPIC_LVT_COMMON_VALID | XAPIC_LVT_DELIVERY_MODE) +%define XAPIC_LVT_LINT_VALID ( XAPIC_LVT_COMMON_VALID | XAPIC_LVT_DELIVERY_MODE | XAPIC_LVT_DELIVERY_STATUS \ + | XAPIC_LVT_POLARITY | XAPIC_LVT_REMOTE_IRR | XAPIC_LVT_TRIGGER_MODE) +%define XAPIC_LVT_ERROR_VALID (XAPIC_LVT_COMMON_VALID) +%define XAPIC_SVR_VECTOR 0xff +%define XAPIC_SVR_SOFTWARE_ENABLE RT_BIT(8) +%define XAPIC_SVR_SUPRESS_EOI_BROADCAST RT_BIT(12) + %define XAPIC_SVR_VALID_P4 (XAPIC_SVR_VECTOR | XAPIC_SVR_SOFTWARE_ENABLE) +%define XAPIC_DFR_VALID 0xf0000000 +%define XAPIC_DFR_RSVD_MB1 0x0fffffff +%define XAPIC_DFR_MODEL 0xf +%define XAPIC_DFR_GET_MODEL(a_uReg) (((a_uReg) >> 28) & XAPIC_DFR_MODEL) +%define XAPIC_LDR_VALID 0xff000000 +%define X2APIC_LDR_CLUSTER_ID 0xffff0000 +%define X2APIC_LDR_GET_CLUSTER_ID(a_uReg) ((a_uReg) & X2APIC_LDR_CLUSTER_ID) +%define X2APIC_LDR_LOGICAL_ID 0x0000ffff +%define XAPIC_LDR_FLAT_LOGICAL_ID 0xff +%define XAPIC_LDR_CLUSTERED_CLUSTER_ID 0xf0 +%define XAPIC_LDR_CLUSTERED_LOGICAL_ID 0x0f +%define XAPIC_LDR_CLUSTERED_GET_CLUSTER_ID(a_uReg) ((a_uReg) & XAPIC_LDR_CLUSTERED_CLUSTER_ID) +%define XAPIC_EOI_WO_VALID 0x0 +%define XAPIC_TIMER_ICR_VALID 0xffffffff +%define XAPIC_TIMER_DCR_VALID (RT_BIT(0) | RT_BIT(1) | RT_BIT(3)) +%define XAPIC_SELF_IPI_VALID 0xff +%define XAPIC_SELF_IPI_VECTOR 0xff +%define XAPIC_SELF_IPI_GET_VECTOR(a_uReg) ((a_uReg) & XAPIC_SELF_IPI_VECTOR) +%define XAPIC_ICR_LO_VECTOR 0xff +%define XAPIC_ICR_LO_GET_VECTOR(a_uIcr) ((a_uIcr) & XAPIC_ICR_LO_VECTOR) +%define XAPIC_ICR_LO_DELIVERY_MODE (RT_BIT(8) | RT_BIT(9) | RT_BIT(10)) +%define XAPIC_ICR_LO_DEST_MODE RT_BIT(11) +%define XAPIC_ICR_LO_DELIVERY_STATUS RT_BIT(12) +%define XAPIC_ICR_LO_LEVEL RT_BIT(14) +%define XAPIC_ICR_TRIGGER_MODE RT_BIT(15) +%define XAPIC_ICR_LO_DEST_SHORTHAND (RT_BIT(18) | RT_BIT(19)) +%define XAPIC_ICR_LO_WR_VALID ( XAPIC_ICR_LO_VECTOR | XAPIC_ICR_LO_DELIVERY_MODE | XAPIC_ICR_LO_DEST_MODE \ + | XAPIC_ICR_LO_LEVEL | XAPIC_ICR_TRIGGER_MODE | XAPIC_ICR_LO_DEST_SHORTHAND) +%define XAPIC_ICR_HI_DEST 0xff000000 +%define XAPIC_ICR_HI_GET_DEST(a_u32IcrHi) (((a_u32IcrHi) >> 24) & XAPIC_ICR_HI_DEST) +%define XAPIC_ICR_HI_WR_VALID XAPIC_ICR_HI_DEST +%define X2APIC_ID_BROADCAST_MASK 0xffffffff + %define XAPIC_ID_BROADCAST_MASK_P4 0xff +%define X2APIC_GET_XAPIC_OFF(a_uMsr) ((((a_uMsr) - MSR_IA32_X2APIC_START) << 4) & 0xff0) +%define XAPIC_GET_X2APIC_MSR(a_offReg) ((((a_offReg) & 0xff0) >> 4) | MSR_IA32_X2APIC_START) +%define XAPIC_OFF_ID 0x020 +%define XAPIC_OFF_VERSION 0x030 +%define XAPIC_OFF_TPR 0x080 +%define XAPIC_OFF_APR 0x090 +%define XAPIC_OFF_PPR 0x0A0 +%define XAPIC_OFF_EOI 0x0B0 +%define XAPIC_OFF_RRD 0x0C0 +%define XAPIC_OFF_LDR 0x0D0 +%define XAPIC_OFF_DFR 0x0E0 +%define XAPIC_OFF_SVR 0x0F0 +%define XAPIC_OFF_ISR0 0x100 +%define XAPIC_OFF_ISR1 0x110 +%define XAPIC_OFF_ISR2 0x120 +%define XAPIC_OFF_ISR3 0x130 +%define XAPIC_OFF_ISR4 0x140 +%define XAPIC_OFF_ISR5 0x150 +%define XAPIC_OFF_ISR6 0x160 +%define XAPIC_OFF_ISR7 0x170 +%define XAPIC_OFF_TMR0 0x180 +%define XAPIC_OFF_TMR1 0x190 +%define XAPIC_OFF_TMR2 0x1A0 +%define XAPIC_OFF_TMR3 0x1B0 +%define XAPIC_OFF_TMR4 0x1C0 +%define XAPIC_OFF_TMR5 0x1D0 +%define XAPIC_OFF_TMR6 0x1E0 +%define XAPIC_OFF_TMR7 0x1F0 +%define XAPIC_OFF_IRR0 0x200 +%define XAPIC_OFF_IRR1 0x210 +%define XAPIC_OFF_IRR2 0x220 +%define XAPIC_OFF_IRR3 0x230 +%define XAPIC_OFF_IRR4 0x240 +%define XAPIC_OFF_IRR5 0x250 +%define XAPIC_OFF_IRR6 0x260 +%define XAPIC_OFF_IRR7 0x270 +%define XAPIC_OFF_ESR 0x280 +%define XAPIC_OFF_LVT_CMCI 0x2F0 +%define XAPIC_OFF_ICR_LO 0x300 +%define XAPIC_OFF_ICR_HI 0x310 +%define XAPIC_OFF_LVT_TIMER 0x320 +%define XAPIC_OFF_LVT_THERMAL 0x330 +%define XAPIC_OFF_LVT_PERF 0x340 +%define XAPIC_OFF_LVT_LINT0 0x350 +%define XAPIC_OFF_LVT_LINT1 0x360 +%define XAPIC_OFF_LVT_ERROR 0x370 +%define XAPIC_OFF_TIMER_ICR 0x380 +%define XAPIC_OFF_TIMER_CCR 0x390 +%define XAPIC_OFF_TIMER_DCR 0x3E0 +%define X2APIC_OFF_SELF_IPI 0x3F0 +%define XAPIC_OFF_LVT_START XAPIC_OFF_LVT_TIMER +%define XAPIC_OFF_LVT_END XAPIC_OFF_LVT_ERROR +%define XAPIC_OFF_LVT_EXT_START XAPIC_OFF_LVT_CMCI +%define XAPIC_OFF_LVT_EXT_END XAPIC_OFF_LVT_CMCI +%define XAPIC_OFF_END 0x3F0 +%ifdef IPRT_INCLUDED_asm_amd64_x86_h +%endif +%endif diff --git a/include/VBox/asmdefs.mac b/include/VBox/asmdefs.mac new file mode 100644 index 00000000..0e167033 --- /dev/null +++ b/include/VBox/asmdefs.mac @@ -0,0 +1,785 @@ +;; @file +; VirtualBox YASM/NASM macros, structs, etc. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_asmdefs_mac +%define ___VBox_asmdefs_mac + +;; @def VBOX_WITH_STATISTICS +; When defined all statistics will be included in the build. +; This is enabled by default in all debug builds. +%ifndef VBOX_WITH_STATISTICS + %ifdef DEBUG + %define VBOX_WITH_STATISTICS + %endif +%endif + +%include "iprt/asmdefs.mac" + +;; @def VBOX_STRICT +; Enables strict checks in the VBox code. +; This is enabled by default in all debug builds and when RT_STRICT is enabled. +%ifndef VBOX_STRICT + %ifdef DEBUG + %define VBOX_STRICT + %endif + %ifdef RT_STRICT + %define VBOX_STRICT + %endif +%endif + + +%ifndef VBOX_UART_BASE + %ifndef IPRT_UART_BASE + %define VBOX_UART_BASE 3f8h ; COM1 (see src/VBox/Runtime/common/log/logcom.cpp) + %else + %define VBOX_UART_BASE IPRT_UART_BASE + %endif +%endif +%ifndef VBOX_UART_RATE + %define VBOX_UART_RATE 12 ; 9600 bps +%endif +%ifndef VBOX_UART_PARAMS + %define VBOX_UART_PARAMS 00000011b ; 8n1 +%endif + + +;; +; Initializes the com port to 9600 baud 8n1. +; al and dx are wasted. +; @todo comport init doesn't quite work - therefore we no longer use this! :-/ +; @todo test again, it might work now... +%macro COM_INIT 0 + push eax + push edx + + mov dx, VBOX_UART_BASE + 2 + mov al, 0 + out dx, al ; Disable the fifos (old software relies on it) + + mov dx, VBOX_UART_BASE + 3 + mov al, 80h + out dx, al ; make DL register accessible + + mov dx, VBOX_UART_BASE + mov ax, VBOX_UART_RATE + out dx, al ; write low bps rate divisor + + mov dx, VBOX_UART_BASE+1 + xchg al, ah + out dx, al ; write high bps rate divisor + + mov dx, VBOX_UART_BASE + 3 + mov al, VBOX_UART_PARAMS + out dx, al ; write parameters & lock divisor + + mov dx, VBOX_UART_BASE + 4 ; disconnect the UART from the int line + mov al, 0 + out dx, al + + mov dx, VBOX_UART_BASE + 1 ; disable UART ints + out dx, al + + mov dx, VBOX_UART_BASE + in al, dx ; clear receiver + mov dx, VBOX_UART_BASE + 5 + in al, dx ; clear line status + inc dx + in al, dx ; clear modem status + mov dx, VBOX_UART_BASE + 2 + in al, dx ; clear interrupts (IIR) + + pop edx + pop eax +%endmacro + + +;; +; writes string to comport +; trashes nothing (uses stack though) + +%macro COM32_S_PRINT 1+ + push esi + push ecx + push eax + mov ecx, edx + shl ecx, 16 + + call %%stringend +%%string: db %1 +%%stringend: + pop esi + mov cx, %%stringend - %%string +%%status: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status + + mov al, [esi] + mov dx, VBOX_UART_BASE + out dx, al + inc esi + dec cx + jnz short %%status + +%%status2: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status2 + + shr ecx, 16 + mov dx, cx + pop eax + pop ecx + pop esi +%endmacro + +%macro COM64_S_PRINT 1+ + push rsi + push rdx + push rcx + push rax + + jmp %%stringend +%%string: db %1 +%%stringend: + lea rsi, [%%string wrt rip] + mov cx, %%stringend - %%string +%%status: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status + + mov al, [rsi] + mov dx, VBOX_UART_BASE + out dx, al + inc rsi + dec cx + jnz short %%status + +%%status2: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status2 + + pop rax + pop rcx + pop rdx + pop rsi +%endmacro + +%macro COM_S_PRINT 1+ +%ifdef RT_ARCH_AMD64 + COM64_S_PRINT %1 +%else + COM32_S_PRINT %1 +%endif +%endmacro + + +;; Write char. +; trashes esi +%macro COM_CHAR 1 + mov esi, eax + shl esi, 16 + mov si, dx + +%%status: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status + + mov al, %1 + mov dx, VBOX_UART_BASE + out dx, al + +%%status2: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status2 + + mov dx, si + shr esi, 16 + mov ax, si +%endmacro + + +;; Write char. +; trashes nothing (uses stack though) + +%macro COM32_S_CHAR 1 + push eax + push edx + +%%status: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status + + mov al, %1 + mov dx, VBOX_UART_BASE + out dx, al + +%%status2: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status2 + + pop edx + pop eax +%endmacro + +%macro COM64_S_CHAR 1 + push rax + push rdx + +%%status: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status + + mov al, %1 + mov dx, VBOX_UART_BASE + out dx, al + +%%status2: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status2 + + pop rdx + pop rax +%endmacro + +%macro COM_S_CHAR 1 +%ifdef RT_ARCH_AMD64 + COM64_S_CHAR %1 +%else + COM32_S_CHAR %1 +%endif +%endmacro + + +;; Writes newline +; trashes esi +%macro COM_NEWLINE 0 + mov esi, eax + shl esi, 16 + mov si, dx + +%%status1: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status1 + + mov al, 13 + mov dx, VBOX_UART_BASE + out dx, al + +%%status2: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status2 + + mov al, 10 + mov dx, VBOX_UART_BASE + out dx, al + +%%status3: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status3 + + mov dx, si + shr esi, 16 + mov ax, si +%endmacro + + +;; Writes newline +; trashes nothing (uses stack though) + +%macro COM32_S_NEWLINE 0 + push edx + push eax + +%%status1: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status1 + + mov al, 13 + mov dx, VBOX_UART_BASE + out dx, al + +%%status2: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status2 + + mov al, 10 + mov dx, VBOX_UART_BASE + out dx, al + +%%status3: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status3 + + pop eax + pop edx +%endmacro + +%macro COM64_S_NEWLINE 0 + push rdx + push rax + +%%status1: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status1 + + mov al, 13 + mov dx, VBOX_UART_BASE + out dx, al + +%%status2: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status2 + + mov al, 10 + mov dx, VBOX_UART_BASE + out dx, al + +%%status3: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status3 + + pop rax + pop rdx +%endmacro + +%macro COM_S_NEWLINE 0 +%ifdef RT_ARCH_AMD64 + COM64_S_NEWLINE +%else + COM32_S_NEWLINE +%endif +%endmacro + + +;; Writes a dword from register to com port. +; trashes esi, edi +; edi cannot be used as input register +%macro COM_DWORD_REG 1 + mov edi, ebx ; save ebx + mov ebx, %1 ; get value we're supposed to print + mov esi, eax ; save ax + shl esi, 16 ; save dx + mov si, dx + + mov ah, 8 ; loop counter. +%%daloop: + rol ebx, 4 ; shift next digit to the front + +%%status0: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status0 + + mov al, bl ; get next char + and al, 0fh + cmp al, 10 + jae short %%hex ; yasm BUG! It sometimes generate a near jump here. YASMCHECK! + add al, '0' + jmp short %%print +%%hex: + add al, 'a' - 10 +%%print: + mov dx, VBOX_UART_BASE + out dx, al + + dec ah + jnz short %%daloop ; loop + + mov dx, si ; restore dx + shr esi, 16 + mov ax, si ; restore ax + mov ebx, edi ; restore ebx +%endmacro + + +;; Writes a dword from register to com port. +; trashes nothing (uses stack though) + +%macro COM32_S_DWORD_REG 1 + push edx + push eax + push ebx + + mov ebx, %1 ; get value we're supposed to print + + mov ah, 8 ; loop counter. +%%daloop: + rol ebx, 4 ; shift next digit to the front + +%%status0: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status0 + + mov al, bl ; get next char + and al, 0fh + cmp al, 10 + jae short %%hex ; yasm BUG! It sometimes generate a near jump here. YASMCHECK! + add al, '0' + jmp short %%print +%%hex: + add al, 'a' - 10 +%%print: + mov dx, VBOX_UART_BASE + out dx, al + + dec ah + jnz short %%daloop ; loop + + pop ebx + pop eax + pop edx +%endmacro + +%macro COM64_S_DWORD_REG 1 + push rdx + push rax + push rbx + + mov ebx, %1 ; get value we're supposed to print + + mov ah, 8 ; loop counter. +%%daloop: + rol ebx, 4 ; shift next digit to the front + +%%status0: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status0 + + mov al, bl ; get next char + and al, 0fh + cmp al, 10 + jae short %%hex ; yasm BUG! It sometimes generate a near jump here. YASMCHECK! + add al, '0' + jmp short %%print +%%hex: + add al, 'a' - 10 +%%print: + mov dx, VBOX_UART_BASE + out dx, al + + dec ah + jnz short %%daloop ; loop + + pop rbx + pop rax + pop rdx +%endmacro + +%macro COM_S_DWORD_REG 1 +%ifdef RT_ARCH_AMD64 + COM64_S_DWORD_REG %1 +%else + COM32_S_DWORD_REG %1 +%endif +%endmacro + + +;; Writes a qword from register to com port. +; trashes nothing (uses stack though) +%macro COM64_S_QWORD_REG 1 + push rdx + push rax + push rbx + + mov rbx, %1 ; get value we're supposed to print + + mov ah, 16 ; loop counter. +%%daloop: + rol rbx, 4 ; shift next digit to the front + +%%status0: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status0 + + mov al, bl ; get next char + and al, 0fh + cmp al, 10 + jae short %%hex ; yasm BUG! It sometimes generate a near jump here. YASMCHECK! + add al, '0' + jmp short %%print +%%hex: + add al, 'a' - 10 +%%print: + mov dx, VBOX_UART_BASE + out dx, al + + dec ah + jnz short %%daloop ; loop + + pop rbx + pop rax + pop rdx +%endmacro + + +;; Writes a byte from register to com port. +; trashes nothing (uses stack though) + +%macro COM32_S_BYTE_REG 1 + push edx + push eax + push ebx + + mov ebx, %1 ; get value we're supposed to print + + mov ah, 2 ; loop counter. + ror ebx, 8 ; shift next digit to the front +%%daloop: + rol ebx, 4 ; shift next digit to the front + +%%status0: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status0 + + mov al, bl ; get next char + and al, 0fh + cmp al, 10 + jae short %%hex ; yasm BUG! It sometimes generate a near jump here. YASMCHECK! + add al, '0' + jmp short %%print +%%hex: + add al, 'a' - 10 +%%print: + mov dx, VBOX_UART_BASE + out dx, al + + dec ah + jnz short %%daloop ; loop + + pop ebx + pop eax + pop edx +%endmacro + +%macro COM64_S_BYTE_REG 1 + push rdx + push rax + push rbx + + mov ebx, %1 ; get value we're supposed to print + + mov ah, 2 ; loop counter. + ror ebx, 8 ; shift next digit to the front +%%daloop: + rol ebx, 4 ; shift next digit to the front + +%%status0: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status0 + + mov al, bl ; get next char + and al, 0fh + cmp al, 10 + jae short %%hex ; yasm BUG! It sometimes generate a near jump here. YASMCHECK! + add al, '0' + jmp short %%print +%%hex: + add al, 'a' - 10 +%%print: + mov dx, VBOX_UART_BASE + out dx, al + + dec ah + jnz short %%daloop ; loop + + pop rbx + pop rax + pop rdx +%endmacro + +%macro COM_S_BYTE_REG 1 +%ifdef RT_ARCH_AMD64 + COM64_S_BYTE_REG %1 +%else + COM32_S_BYTE_REG %1 +%endif +%endmacro + + + +;; Writes a single hex digit from register to com port. +; trashes nothing (uses stack though) + +%macro COM32_S_DIGIT_REG 1 + push edx + push eax + push ebx + + mov ebx, %1 ; get value we're supposed to print +%%status0: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status0 + + mov al, bl ; get next char + and al, 0fh + cmp al, 10 + jae short %%hex ; yasm BUG! It sometimes generate a near jump here. YASMCHECK! + add al, '0' + jmp short %%print +%%hex: + add al, 'a' - 10 +%%print: + mov dx, VBOX_UART_BASE + out dx, al + + pop ebx + pop eax + pop edx +%endmacro + +%macro COM64_S_DIGIT_REG 1 + push rdx + push rax + push rbx + + mov ebx, %1 ; get value we're supposed to print +%%status0: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status0 + + mov al, bl ; get next char + and al, 0fh + cmp al, 10 + jae short %%hex ; yasm BUG! It sometimes generate a near jump here. YASMCHECK! + add al, '0' + jmp short %%print +%%hex: + add al, 'a' - 10 +%%print: + mov dx, VBOX_UART_BASE + out dx, al + + pop rbx + pop rax + pop rdx +%endmacro + +%macro COM_S_DIGIT_REG 1 +%ifdef RT_ARCH_AMD64 + COM64_S_DIGIT_REG %1 +%else + COM32_S_DIGIT_REG %1 +%endif +%endmacro + + +;; +; Loops for a while. +; ecx is trashed. +%macro LOOP_A_WHILE 0 + + xor ecx, ecx + dec ecx + shr ecx, 1 +%%looplabel: + nop + nop + nop + dec ecx + jnz short %%looplabel + +%endmacro + + +;; +; Loops for a short while. +; ecx is trashed. +%macro LOOP_SHORT_WHILE 0 + + xor ecx, ecx + dec ecx + shr ecx, 4 +%%looplabel: + nop + nop + dec ecx + jnz short %%looplabel + +%endmacro + +%endif + diff --git a/include/VBox/ata.h b/include/VBox/ata.h new file mode 100644 index 00000000..3a8be20f --- /dev/null +++ b/include/VBox/ata.h @@ -0,0 +1,222 @@ +/* $Id: ata.h $ */ +/** @file + * VBox storage devices: ATA/ATAPI declarations + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_ata_h +#define VBOX_INCLUDED_ata_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/* Bits of HD_STATUS */ +#define ATA_STAT_ERR 0x01 +#define ATA_STAT_INDEX 0x02 +#define ATA_STAT_ECC 0x04 /* Corrected error */ +#define ATA_STAT_DRQ 0x08 +#define ATA_STAT_SEEK 0x10 +#define ATA_STAT_SRV 0x10 +#define ATA_STAT_WRERR 0x20 +#define ATA_STAT_READY 0x40 +#define ATA_STAT_BUSY 0x80 + +/* Bits for HD_ERROR */ +#define MARK_ERR 0x01 /* Bad address mark */ +#define TRK0_ERR 0x02 /* couldn't find track 0 */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* media change request */ +#define ID_ERR 0x10 /* ID field not found */ +#define MC_ERR 0x20 /* media changed */ +#define ECC_ERR 0x40 /* Uncorrectable ECC error */ +#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */ +#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ + +/* Bits for uATARegDevCtl. */ +#define ATA_DEVCTL_DISABLE_IRQ 0x02 +#define ATA_DEVCTL_RESET 0x04 +#define ATA_DEVCTL_HOB 0x80 + + +/* ATA/ATAPI Commands (as of ATA/ATAPI-8 draft T13/1699D Revision 3a). + * Please keep this in sync with g_apszATACmdNames. */ +typedef enum ATACMD +{ + ATA_NOP = 0x00, + ATA_CFA_REQUEST_EXTENDED_ERROR_CODE = 0x03, + ATA_DATA_SET_MANAGEMENT = 0x06, + ATA_DEVICE_RESET = 0x08, + ATA_RECALIBRATE = 0x10, + ATA_READ_SECTORS = 0x20, + ATA_READ_SECTORS_WITHOUT_RETRIES = 0x21, + ATA_READ_LONG = 0x22, + ATA_READ_LONG_WITHOUT_RETRIES = 0x23, + ATA_READ_SECTORS_EXT = 0x24, + ATA_READ_DMA_EXT = 0x25, + ATA_READ_DMA_QUEUED_EXT = 0x26, + ATA_READ_NATIVE_MAX_ADDRESS_EXT = 0x27, + ATA_READ_MULTIPLE_EXT = 0x29, + ATA_READ_STREAM_DMA_EXT = 0x2a, + ATA_READ_STREAM_EXT = 0x2b, + ATA_READ_LOG_EXT = 0x2f, + ATA_WRITE_SECTORS = 0x30, + ATA_WRITE_SECTORS_WITHOUT_RETRIES = 0x31, + ATA_WRITE_LONG = 0x32, + ATA_WRITE_LONG_WITHOUT_RETRIES = 0x33, + ATA_WRITE_SECTORS_EXT = 0x34, + ATA_WRITE_DMA_EXT = 0x35, + ATA_WRITE_DMA_QUEUED_EXT = 0x36, + ATA_SET_MAX_ADDRESS_EXT = 0x37, + ATA_CFA_WRITE_SECTORS_WITHOUT_ERASE = 0x38, + ATA_WRITE_MULTIPLE_EXT = 0x39, + ATA_WRITE_STREAM_DMA_EXT = 0x3a, + ATA_WRITE_STREAM_EXT = 0x3b, + ATA_WRITE_VERIFY = 0x3c, + ATA_WRITE_DMA_FUA_EXT = 0x3d, + ATA_WRITE_DMA_QUEUED_FUA_EXT = 0x3e, + ATA_WRITE_LOG_EXT = 0x3f, + ATA_READ_VERIFY_SECTORS = 0x40, + ATA_READ_VERIFY_SECTORS_WITHOUT_RETRIES = 0x41, + ATA_READ_VERIFY_SECTORS_EXT = 0x42, + ATA_WRITE_UNCORRECTABLE_EXT = 0x45, + ATA_READ_LOG_DMA_EXT = 0x47, + ATA_FORMAT_TRACK = 0x50, + ATA_CONFIGURE_STREAM = 0x51, + ATA_WRITE_LOG_DMA_EXT = 0x57, + ATA_TRUSTED_RECEIVE = 0x5c, + ATA_TRUSTED_RECEIVE_DMA = 0x5d, + ATA_TRUSTED_SEND = 0x5e, + ATA_TRUSTED_SEND_DMA = 0x5f, + ATA_READ_FPDMA_QUEUED = 0x60, + ATA_WRITE_FPDMA_QUEUED = 0x61, + ATA_SEEK = 0x70, + ATA_CFA_TRANSLATE_SECTOR = 0x87, + ATA_EXECUTE_DEVICE_DIAGNOSTIC = 0x90, + ATA_INITIALIZE_DEVICE_PARAMETERS = 0x91, + ATA_DOWNLOAD_MICROCODE = 0x92, + ATA_STANDBY_IMMEDIATE__ALT = 0x94, + ATA_IDLE_IMMEDIATE__ALT = 0x95, + ATA_STANDBY__ALT = 0x96, + ATA_IDLE__ALT = 0x97, + ATA_CHECK_POWER_MODE__ALT = 0x98, + ATA_SLEEP__ALT = 0x99, + ATA_PACKET = 0xa0, + ATA_IDENTIFY_PACKET_DEVICE = 0xa1, + ATA_SERVICE = 0xa2, + ATA_SMART = 0xb0, + ATA_DEVICE_CONFIGURATION_OVERLAY = 0xb1, + ATA_NV_CACHE = 0xb6, + ATA_CFA_ERASE_SECTORS = 0xc0, + ATA_READ_MULTIPLE = 0xc4, + ATA_WRITE_MULTIPLE = 0xc5, + ATA_SET_MULTIPLE_MODE = 0xc6, + ATA_READ_DMA_QUEUED = 0xc7, + ATA_READ_DMA = 0xc8, + ATA_READ_DMA_WITHOUT_RETRIES = 0xc9, + ATA_WRITE_DMA = 0xca, + ATA_WRITE_DMA_WITHOUT_RETRIES = 0xcb, + ATA_WRITE_DMA_QUEUED = 0xcc, + ATA_CFA_WRITE_MULTIPLE_WITHOUT_ERASE = 0xcd, + ATA_WRITE_MULTIPLE_FUA_EXT = 0xce, + ATA_CHECK_MEDIA_CARD_TYPE = 0xd1, + ATA_GET_MEDIA_STATUS = 0xda, + ATA_ACKNOWLEDGE_MEDIA_CHANGE = 0xdb, + ATA_BOOT_POST_BOOT = 0xdc, + ATA_BOOT_PRE_BOOT = 0xdd, + ATA_MEDIA_LOCK = 0xde, + ATA_MEDIA_UNLOCK = 0xdf, + ATA_STANDBY_IMMEDIATE = 0xe0, + ATA_IDLE_IMMEDIATE = 0xe1, + ATA_STANDBY = 0xe2, + ATA_IDLE = 0xe3, + ATA_READ_BUFFER = 0xe4, + ATA_CHECK_POWER_MODE = 0xe5, + ATA_SLEEP = 0xe6, + ATA_FLUSH_CACHE = 0xe7, + ATA_WRITE_BUFFER = 0xe8, + ATA_WRITE_SAME = 0xe9, + ATA_FLUSH_CACHE_EXT = 0xea, + ATA_IDENTIFY_DEVICE = 0xec, + ATA_MEDIA_EJECT = 0xed, + ATA_IDENTIFY_DMA = 0xee, + ATA_SET_FEATURES = 0xef, + ATA_SECURITY_SET_PASSWORD = 0xf1, + ATA_SECURITY_UNLOCK = 0xf2, + ATA_SECURITY_ERASE_PREPARE = 0xf3, + ATA_SECURITY_ERASE_UNIT = 0xf4, + ATA_SECURITY_FREEZE_LOCK = 0xf5, + ATA_SECURITY_DISABLE_PASSWORD = 0xf6, + ATA_READ_NATIVE_MAX_ADDRESS = 0xf8, + ATA_SET_MAX = 0xf9 +} ATACMD; + + +#define ATA_MODE_MDMA 0x20 +#define ATA_MODE_UDMA 0x40 + + +#define ATA_TRANSFER_ID(thismode, maxspeed, currmode) \ + ( ((1 << (maxspeed + 1)) - 1) \ + | ((((thismode ^ currmode) & 0xf8) == 0) ? 1 << ((currmode & 0x07) + 8) : 0)) + +/** + * Length of the ATA VPD data (without termination) + */ +#define ATA_SERIAL_NUMBER_LENGTH 20 +#define ATA_FIRMWARE_REVISION_LENGTH 8 +#define ATA_MODEL_NUMBER_LENGTH 40 + +/** Mask to get the LBA value from a LBA range. */ +#define ATA_RANGE_LBA_MASK UINT64_C(0xffffffffffff) +/** Mas to get the length value from a LBA range. */ +#define ATA_RANGE_LENGTH_MASK UINT64_C(0xffff000000000000) +/** Returns the length of the range in sectors. */ +#define ATA_RANGE_LENGTH_GET(val) (((val) & ATA_RANGE_LENGTH_MASK) >> 48) + +/* ATAPI defines */ + +#define ATAPI_PACKET_SIZE 12 + + +#define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */ +#define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */ +#define ATAPI_INT_REASON_REL 0x04 +#define ATAPI_INT_REASON_TAG_MASK 0xf8 + +#if defined(LOG_ENABLED) && defined(IN_RING3) +const char * ATACmdText(uint8_t uCmd); +#endif + +#endif /* !VBOX_INCLUDED_ata_h */ + diff --git a/include/VBox/bios.h b/include/VBox/bios.h new file mode 100644 index 00000000..9b75ab3f --- /dev/null +++ b/include/VBox/bios.h @@ -0,0 +1,56 @@ +/** @file + * X86 (and AMD64) Local APIC registers (VMM,++). + * + * bios.mac is generated from this file by running 'kmk -f Maintenance.kmk incs'. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_bios_h +#define VBOX_INCLUDED_bios_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/** The BIOS shutdown port. + * You write "Shutdown" byte by byte to shutdown the VM. + * @sa VBOX_BIOS_OLD_SHUTDOWN_PORT */ +#define VBOX_BIOS_SHUTDOWN_PORT 0x040f + +/** The old shutdown port number. + * Older versions of VirtualBox uses this as does Bochs. + * @sa VBOX_BIOS_SHUTDOWN_PORT */ +#define VBOX_BIOS_OLD_SHUTDOWN_PORT 0x8900 + + +#endif /* !VBOX_INCLUDED_bios_h */ + diff --git a/include/VBox/bios.mac b/include/VBox/bios.mac new file mode 100644 index 00000000..a38627ad --- /dev/null +++ b/include/VBox/bios.mac @@ -0,0 +1,44 @@ +;; @file +; X86 (and AMD64) Local APIC registers (VMM,++). +; +; Automatically generated by various.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2017-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef VBOX_INCLUDED_bios_h +%define VBOX_INCLUDED_bios_h +%ifndef RT_WITHOUT_PRAGMA_ONCE +%endif +%define VBOX_BIOS_SHUTDOWN_PORT 0x040f +%define VBOX_BIOS_OLD_SHUTDOWN_PORT 0x8900 +%endif diff --git a/include/VBox/bioslogo.h b/include/VBox/bioslogo.h new file mode 100644 index 00000000..4738f1ef --- /dev/null +++ b/include/VBox/bioslogo.h @@ -0,0 +1,108 @@ +/* $Id: bioslogo.h $ */ +/** @file + * BiosLogo - The Private BIOS Logo Interface. (DEV) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_bioslogo_h +#define VBOX_INCLUDED_bioslogo_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef VBOX_PC_BIOS +# include <iprt/types.h> +# include <iprt/assert.h> +#endif + +/** @defgroup grp_bios_logo The Private BIOS Logo Interface. + * @ingroup grp_devdrv + * @internal + * + * @remark All this is currently duplicated in logo.c. + * + * @{ + */ + +/** The extra port which is used to show the BIOS logo. */ +#define LOGO_IO_PORT 0x3b8 + +/** The BIOS logo fade in/fade out steps. */ +#define LOGO_SHOW_STEPS 16 + +/** @name The BIOS logo commands. + * @{ + */ +#define LOGO_CMD_NOP 0 +#define LOGO_CMD_SET_OFFSET 0x100 +#define LOGO_CMD_SHOW_BMP 0x200 +/** @} */ + +/** + * PC Bios logo data structure. + */ +typedef struct LOGOHDR +{ + /** Signature (LOGO_HDR_MAGIC/0x66BB). */ + uint16_t u16Signature; + /** Logo time (msec). */ + uint16_t u16LogoMillies; + /** Fade in - boolean. */ + uint8_t fu8FadeIn; + /** Fade out - boolean. */ + uint8_t fu8FadeOut; + /** Show setup - boolean. */ + uint8_t fu8ShowBootMenu; + /** Reserved / padding. */ + uint8_t u8Reserved; + /** Logo file size. */ + uint32_t cbLogo; +} LOGOHDR; +#ifndef VBOX_PC_BIOS +AssertCompileSize(LOGOHDR, 12); +#endif +/** Pointer to a PC BIOS logo header. */ +typedef LOGOHDR *PLOGOHDR; +/** Pointer to a const PC BIOS logo header. */ +typedef LOGOHDR const *PCLOGOHDR; + +/** The value of the LOGOHDR::u16Signature field. */ +#define LOGO_HDR_MAGIC 0x66BB + +/** The value which will switch you the default logo. */ +#define LOGO_DEFAULT_LOGO 0xFFFF + +/** @} */ + +#endif /* !VBOX_INCLUDED_bioslogo_h */ + diff --git a/include/VBox/cdefs.h b/include/VBox/cdefs.h new file mode 100644 index 00000000..a77389d6 --- /dev/null +++ b/include/VBox/cdefs.h @@ -0,0 +1,493 @@ +/** @file + * VirtualBox - Common C and C++ definition. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_cdefs_h +#define VBOX_INCLUDED_cdefs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> + + +/** @defgroup grp_vbox_cdefs VBox Common Defintions and Macros + * @{ + */ + +/** @def VBOX_WITH_STATISTICS + * When defined all statistics will be included in the build. + * This is enabled by default in all debug builds. + */ +#ifndef VBOX_WITH_STATISTICS +# ifdef DEBUG +# define VBOX_WITH_STATISTICS +# endif +#endif + +/** @def VBOX_STRICT + * Alias for RT_STRICT. + */ +#ifdef RT_STRICT +# ifndef VBOX_STRICT +# define VBOX_STRICT +# endif +#endif + +/** @def VBOX_STRICT_GUEST + * Be strict on guest input. This can be overriden on the compiler command line + * or per source file by defining VBOX_NO_STRICT_GUEST. + * + * @sa VBox/assert.h and its ASSERT_GUEST_XXXX macros. + */ +#ifndef VBOX_STRICT_GUEST +# ifdef VBOX_STRICT +# define VBOX_STRICT_GUEST +# endif +#endif +/** @def VBOX_NO_STRICT_GUEST + * Define to override VBOX_STRICT_GUEST, disabling asserting on guest input. */ +#ifdef VBOX_NO_STRICT_GUEST +# undef VBOX_STRICT_GUEST +#endif + + +/* + * Shut up DOXYGEN warnings and guide it properly thru the code. + */ +#ifdef DOXYGEN_RUNNING +#define VBOX_WITH_STATISTICS +#define VBOX_STRICT +#define VBOX_STRICT_GUEST +#define VBOX_NO_STRICT_GUEST +#define IN_DBG +#define IN_DIS +#define IN_INTNET_R0 +#define IN_INTNET_R3 +#define IN_PCIRAW_R0 +#define IN_PCIRAW_R3 +#define IN_REM_R3 +#define IN_SUP_R0 +#define IN_SUP_R3 +#define IN_SUP_RC +#define IN_SUP_STATIC +#define IN_USBLIB +#define IN_VBOXDDU +#define IN_VMM_RC +#define IN_VMM_R0 +#define IN_VMM_R3 +#define IN_VMM_STATIC +#endif + + + + +/** @def VBOXCALL + * The standard calling convention for VBOX interfaces. + */ +#define VBOXCALL RTCALL + + + +/** @def IN_DIS + * Used to indicate whether we're inside the same link module as the + * disassembler. + */ +/** @def DISDECL(type) + * Disassembly export or import declaration. + * @param type The return type of the function declaration. + */ +#if defined(IN_DIS) +# ifdef IN_DIS_STATIC +# define DISDECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +# else +# define DISDECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +# endif +#else +# define DISDECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + + + +/** @def IN_DBG + * Used to indicate whether we're inside the same link module as the debugger + * console, gui, and related things (ring-3). + */ +/** @def DBGDECL(type) + * Debugger module export or import declaration. + * Functions declared using this exists only in R3 since the + * debugger modules is R3 only. + * @param type The return type of the function declaration. + */ +#if defined(IN_DBG_R3) || defined(IN_DBG) +# define DBGDECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define DBGDECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + + + +/** @def IN_INTNET_R3 + * Used to indicate whether we're inside the same link module as the Ring-3 + * Internal Networking Service. + */ +/** @def INTNETR3DECL(type) + * Internal Networking Service export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_INTNET_R3 +# define INTNETR3DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define INTNETR3DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + +/** @def IN_INTNET_R0 + * Used to indicate whether we're inside the same link module as the R0 + * Internal Network Service. + */ +/** @def INTNETR0DECL(type) + * Internal Networking Service export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_INTNET_R0 +# define INTNETR0DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define INTNETR0DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + + + +/** @def IN_PCIRAW_R3 + * Used to indicate whether we're inside the same link module as the Ring-3 + * PCI passthrough support. + */ +/** @def PCIRAWR3DECL(type) + * PCI passthrough export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_PCIRAW_R3 +# define PCIRAWR3DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define PCIRAWR3DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + +/** @def IN_PCIRAW_R0 + * Used to indicate whether we're inside the same link module as the R0 + * PCI passthrough support. + */ +/** @def PCIRAWR0DECL(type) + * PCI passthroug export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_PCIRAW_R0 +# define PCIRAWR0DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define PCIRAWR0DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + + + +/** @def IN_REM_R3 + * Used to indicate whether we're inside the same link module as + * the HC Ring-3 Recompiled Execution Manager. + */ +/** @def REMR3DECL(type) + * Recompiled Execution Manager HC Ring-3 export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_REM_R3 +# define REMR3DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define REMR3DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + + + +/** @def IN_SUP_R3 + * Used to indicate whether we're inside the same link module as the Ring-3 + * Support Library or not. + */ +/** @def SUPR3DECL(type) + * Support library export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_SUP_R3 +# ifdef IN_SUP_STATIC +# define SUPR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +# else +# define SUPR3DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +# endif +#else +# ifdef IN_SUP_STATIC +# define SUPR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +# else +# define SUPR3DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +# endif +#endif + +/** @def IN_SUP_R0 + * Used to indicate whether we're inside the same link module as the Ring-0 + * Support Library or not. + */ +/** @def IN_SUP_STATIC + * Used to indicate that the Support Library is built or used as a static + * library. + */ +/** @def SUPR0DECL(type) + * Support library export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_SUP_R0 +# ifdef IN_SUP_STATIC +# define SUPR0DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +# else +# define SUPR0DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +# endif +#else +# ifdef IN_SUP_STATIC +# define SUPR0DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +# else +# define SUPR0DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +# endif +#endif + +/** @def IN_SUP_RC + * Used to indicate whether we're inside the same link module as the RC Support + * Library or not. + */ +/** @def SUPRCDECL(type) + * Support library export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_SUP_RC +# define SUPRCDECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define SUPRCDECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + +/** @def IN_SUP_R0 + * Used to indicate whether we're inside the same link module as the Ring-0 + * Support Library or not. + */ +/** @def SUPR0DECL(type) + * Support library export or import declaration. + * @param type The return type of the function declaration. + */ +#if defined(IN_SUP_R0) || defined(IN_SUP_R3) || defined(IN_SUP_RC) +# define SUPDECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define SUPDECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + + + +/** @def IN_USBLIB + * Used to indicate whether we're inside the same link module as the USBLib. + */ +/** @def USBLIB_DECL + * USBLIB export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_RING0 +# define USBLIB_DECL(type) type VBOXCALL +#elif defined(IN_USBLIB) +# define USBLIB_DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define USBLIB_DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + + + +/** @def IN_VMM_STATIC + * Used to indicate that the virtual machine monitor is built or used as a + * static library. + */ +/** @def IN_VMM_R3 + * Used to indicate whether we're inside the same link module as the ring 3 part of the + * virtual machine monitor or not. + */ +/** @def VMMR3DECL + * Ring-3 VMM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_VMM_R3 +# ifdef IN_VMM_STATIC +# define VMMR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +# else +# define VMMR3DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +# endif +#elif defined(IN_RING3) +# ifdef IN_VMM_STATIC +# define VMMR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +# else +# define VMMR3DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +# endif +#else +# define VMMR3DECL(type) DECL_INVALID(type) +#endif + +/** @def IN_VMM_R0 + * Used to indicate whether we're inside the same link module as the ring-0 part + * of the virtual machine monitor or not. + */ +/** @def VMMR0DECL + * Ring-0 VMM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_VMM_R0 +# define VMMR0DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#elif defined(IN_RING0) +# define VMMR0DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#else +# define VMMR0DECL(type) DECL_INVALID(type) +#endif + +/** @def IN_VMM_RC + * Used to indicate whether we're inside the same link module as the raw-mode + * context part of the virtual machine monitor or not. + */ +/** @def VMMRCDECL + * Raw-mode context VMM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_VMM_RC +# define VMMRCDECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#elif defined(IN_RC) +# define VMMRCDECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#else +# define VMMRCDECL(type) DECL_INVALID(type) +#endif + +/** @def VMMRZDECL + * Ring-0 and Raw-mode context VMM export or import declaration. + * @param type The return type of the function declaration. + */ +#if defined(IN_VMM_R0) || defined(IN_VMM_RC) +# define VMMRZDECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#elif defined(IN_RING0) || defined(IN_RZ) +# define VMMRZDECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#else +# define VMMRZDECL(type) DECL_INVALID(type) +#endif + +/** @def VMMDECL + * VMM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_VMM_STATIC +# define VMMDECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +#elif defined(IN_VMM_R3) || defined(IN_VMM_R0) || defined(IN_VMM_RC) +# define VMMDECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define VMMDECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + +/** @def VMM_INT_DECL + * VMM internal function. + * @param type The return type of the function declaration. + */ +#if defined(IN_VMM_R3) || defined(IN_VMM_R0) || defined(IN_VMM_RC) +# define VMM_INT_DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +#else +# define VMM_INT_DECL(type) DECL_INVALID(type) +#endif + +/** @def VMMR3_INT_DECL + * VMM internal function, ring-3. + * @param type The return type of the function declaration. + */ +#ifdef IN_VMM_R3 +# define VMMR3_INT_DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +#else +# define VMMR3_INT_DECL(type) DECL_INVALID(type) +#endif + +/** @def VMMR0_INT_DECL + * VMM internal function, ring-0. + * @param type The return type of the function declaration. + */ +#ifdef IN_VMM_R0 +# define VMMR0_INT_DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +#else +# define VMMR0_INT_DECL(type) DECL_INVALID(type) +#endif + +/** @def VMMRC_INT_DECL + * VMM internal function, raw-mode context. + * @param type The return type of the function declaration. + */ +#ifdef IN_VMM_RC +# define VMMRC_INT_DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +#else +# define VMMRC_INT_DECL(type) DECL_INVALID(type) +#endif + +/** @def VMMRZ_INT_DECL + * VMM internal function, ring-0 + raw-mode context. + * @param type The return type of the function declaration. + */ +#if defined(IN_VMM_RC) || defined(IN_VMM_R0) +# define VMMRZ_INT_DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +#else +# define VMMRZ_INT_DECL(type) DECL_INVALID(type) +#endif + + + +/** @def IN_VBOXDDU + * Used to indicate whether we're inside the VBoxDDU shared object. + */ +/** @def VBOXDDU_DECL(type) + * VBoxDDU export or import (ring-3). + * @param type The return type of the function declaration. + */ +#ifdef IN_VBOXDDU +# ifdef IN_VBOXDDU_STATIC +# define VBOXDDU_DECL(type) type +# else +# define VBOXDDU_DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +# endif +#else +# define VBOXDDU_DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + +/** @} */ + + +/** @defgroup grp_devdrv Device Emulations and Drivers + * @{ */ +/** @} */ + +#endif /* !VBOX_INCLUDED_cdefs_h */ + diff --git a/include/VBox/com/AutoLock.h b/include/VBox/com/AutoLock.h new file mode 100644 index 00000000..344c4a29 --- /dev/null +++ b/include/VBox/com/AutoLock.h @@ -0,0 +1,704 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - Automatic locks, implementation. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_AutoLock_h +#define VBOX_INCLUDED_com_AutoLock_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + + +/** @defgroup grp_com_autolock Automatic Locks + * @ingroup grp_com + * @{ + */ + +// macros for automatic lock validation; these will amount to nothing +// unless lock validation is enabled for the runtime +#if defined(RT_LOCK_STRICT) +# define VBOX_WITH_MAIN_LOCK_VALIDATION +# define COMMA_LOCKVAL_SRC_POS , RT_SRC_POS +# define LOCKVAL_SRC_POS_DECL RT_SRC_POS_DECL +# define COMMA_LOCKVAL_SRC_POS_DECL , RT_SRC_POS_DECL +# define LOCKVAL_SRC_POS_ARGS RT_SRC_POS_ARGS +# define COMMA_LOCKVAL_SRC_POS_ARGS , RT_SRC_POS_ARGS +#else +# define COMMA_LOCKVAL_SRC_POS +# define LOCKVAL_SRC_POS_DECL +# define COMMA_LOCKVAL_SRC_POS_DECL +# define LOCKVAL_SRC_POS_ARGS +# define COMMA_LOCKVAL_SRC_POS_ARGS +#endif + +namespace util +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// Order classes for lock validation +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * IPRT now has a sophisticated system of run-time locking classes to validate + * locking order. Since the Main code is handled by simpler minds, we want + * compile-time constants for simplicity, and we'll look up the run-time classes + * in AutoLock.cpp transparently. These are passed to the constructors of the + * LockHandle classes. + */ +enum VBoxLockingClass +{ + LOCKCLASS_NONE = 0, + LOCKCLASS_WEBSERVICE = 1, // highest order: webservice locks + LOCKCLASS_VIRTUALBOXOBJECT = 2, // highest order within Main itself: VirtualBox object lock + LOCKCLASS_HOSTOBJECT = 3, // Host object lock + LOCKCLASS_LISTOFMACHINES = 4, // list of machines in VirtualBox object + LOCKCLASS_MACHINEOBJECT = 5, // Machine object lock + LOCKCLASS_SNAPSHOTOBJECT = 6, // snapshot object locks + // (the snapshots tree, including the child pointers in Snapshot, + // is protected by the normal Machine object lock) + LOCKCLASS_MEDIUMQUERY = 7, // lock used to protect Machine::queryInfo + LOCKCLASS_LISTOFMEDIA = 8, // list of media (hard disks, DVDs, floppies) in VirtualBox object + LOCKCLASS_LISTOFOTHEROBJECTS = 9, // any other list of objects + LOCKCLASS_OTHEROBJECT = 10, // any regular object member variable lock + LOCKCLASS_PROGRESSLIST = 11, // list of progress objects in VirtualBox; no other object lock + // may be held after this! + LOCKCLASS_OBJECTSTATE = 12, // object state lock (handled by AutoCaller classes) + LOCKCLASS_TRANSLATOR = 13 // translator internal lock +}; + +void InitAutoLockSystem(); + +/** + * Check whether the current thread holds any locks in the given class + * + * @return true if any such locks are held, false otherwise. If the lock + * validator is not compiled in, always returns false. + * @param lockClass Which lock class to check. + */ +bool AutoLockHoldsLocksInClass(VBoxLockingClass lockClass); + +//////////////////////////////////////////////////////////////////////////////// +// +// LockHandle and friends +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Abstract base class for semaphore handles (RWLockHandle and WriteLockHandle). + * Don't use this directly, but this implements lock validation for them. + */ +class LockHandle +{ +public: + LockHandle() + {} + + virtual ~LockHandle() + {} + + /** + * Returns @c true if the current thread holds a write lock on this + * read/write semaphore. Intended for debugging only. + */ + virtual bool isWriteLockOnCurrentThread() const = 0; + + /** + * Returns @c true if the current thread holds a read lock on this + * read/write semaphore. Intended for debugging only as it isn't always + * accurate given @a fWannaHear. + */ + virtual bool isReadLockedOnCurrentThread(bool fWannaHear = true) const = 0; + + /** + * Returns the current write lock level of this semaphore. The lock level + * determines the number of nested #lockWrite() calls on the given + * semaphore handle. + * + * Note that this call is valid only when the current thread owns a write + * lock on the given semaphore handle and will assert otherwise. + */ + virtual uint32_t writeLockLevel() const = 0; + + virtual void lockWrite(LOCKVAL_SRC_POS_DECL) = 0; + virtual void unlockWrite() = 0; + virtual void lockRead(LOCKVAL_SRC_POS_DECL) = 0; + virtual void unlockRead() = 0; + +#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION + virtual const char* describe() const = 0; +#endif + +private: + // prohibit copy + assignment + LockHandle(const LockHandle&); + LockHandle& operator=(const LockHandle&); +}; + +/** + * Full-featured read/write semaphore handle implementation. + * + * This is an auxiliary base class for classes that need full-featured + * read/write locking as described in the AutoWriteLock class documentation. + * Instances of classes inherited from this class can be passed as arguments to + * the AutoWriteLock and AutoReadLock constructors. + */ +class RWLockHandle : public LockHandle +{ +public: + RWLockHandle(VBoxLockingClass lockClass); + virtual ~RWLockHandle(); + + virtual bool isWriteLockOnCurrentThread() const; + virtual bool isReadLockedOnCurrentThread(bool fWannaHear = true) const; + + virtual void lockWrite(LOCKVAL_SRC_POS_DECL); + virtual void unlockWrite(); + virtual void lockRead(LOCKVAL_SRC_POS_DECL); + virtual void unlockRead(); + + virtual uint32_t writeLockLevel() const; + +#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION + virtual const char* describe() const; +#endif + +private: + struct Data; + Data *m; + + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(RWLockHandle); /* Shuts up MSC warning C4625. */ +}; + +/** + * Write-only semaphore handle implementation. + * + * This is an auxiliary base class for classes that need write-only (exclusive) + * locking and do not need read (shared) locking. This implementation uses a + * cheap and fast critical section for both lockWrite() and lockRead() methods + * which makes a lockRead() call fully equivalent to the lockWrite() call and + * therefore makes it pointless to use instahces of this class with + * AutoReadLock instances -- shared locking will not be possible anyway and + * any call to lock() will block if there are lock owners on other threads. + * + * Use with care only when absolutely sure that shared locks are not necessary. + */ +class WriteLockHandle : public LockHandle +{ +public: + WriteLockHandle(VBoxLockingClass lockClass); + virtual ~WriteLockHandle(); + virtual bool isWriteLockOnCurrentThread() const; + virtual bool isReadLockedOnCurrentThread(bool fWannaHear = true) const; + + virtual void lockWrite(LOCKVAL_SRC_POS_DECL); + virtual void unlockWrite(); + virtual void lockRead(LOCKVAL_SRC_POS_DECL); + virtual void unlockRead(); + virtual uint32_t writeLockLevel() const; + +#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION + virtual const char* describe() const; +#endif + +private: + struct Data; + Data *m; + + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(WriteLockHandle); /* Shuts up MSC warning C4625. */ +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// Lockable +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Lockable interface. + * + * This is an abstract base for classes that need read/write locking. Unlike + * RWLockHandle and other classes that makes the read/write semaphore a part of + * class data, this class allows subclasses to decide which semaphore handle to + * use. + */ +class Lockable +{ +public: + virtual ~Lockable() { } /* To make VC++ 2019 happy. */ + + /** + * Returns a pointer to a LockHandle used by AutoWriteLock/AutoReadLock + * for locking. Subclasses are allowed to return @c NULL -- in this case, + * the AutoWriteLock/AutoReadLock object constructed using an instance of + * such subclass will simply turn into no-op. + */ + virtual LockHandle *lockHandle() const = 0; + + /** + * Equivalent to <tt>#lockHandle()->isWriteLockOnCurrentThread()</tt>. + * Returns @c false if lockHandle() returns @c NULL. + */ + bool isWriteLockOnCurrentThread() + { + LockHandle *h = lockHandle(); + return h ? h->isWriteLockOnCurrentThread() : false; + } + + /** + * Equivalent to <tt>#lockHandle()->isReadLockedOnCurrentThread()</tt>. + * Returns @c false if lockHandle() returns @c NULL. + * @note Use with care, simple debug assertions and similar only. + */ + bool isReadLockedOnCurrentThread(bool fWannaHear = true) const + { + LockHandle *h = lockHandle(); + return h ? h->isReadLockedOnCurrentThread(fWannaHear) : false; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// AutoLockBase +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Abstract base class for all autolocks. + * + * This cannot be used directly. Use AutoReadLock or AutoWriteLock or AutoMultiWriteLock2/3 + * which directly and indirectly derive from this. + * + * In the implementation, the instance data contains a list of lock handles. + * The class provides some utility functions to help locking and unlocking + * them. + */ + +class AutoLockBase +{ +protected: + AutoLockBase(uint32_t cHandles + COMMA_LOCKVAL_SRC_POS_DECL); + AutoLockBase(uint32_t cHandles, + LockHandle *pHandle + COMMA_LOCKVAL_SRC_POS_DECL); + virtual ~AutoLockBase(); + + struct Data; + Data *m; + + virtual void callLockImpl(LockHandle &l) = 0; + virtual void callUnlockImpl(LockHandle &l) = 0; + + void callLockOnAllHandles(); + void callUnlockOnAllHandles(); + + void cleanup(); + +public: + void acquire(); + void release(); + +private: + // prohibit copy + assignment + AutoLockBase(const AutoLockBase&); + AutoLockBase& operator=(const AutoLockBase&); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// AutoReadLock +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Automatic read lock. Use this with a RWLockHandle to request a read/write + * semaphore in read mode. You can also use this with a WriteLockHandle but + * that makes little sense since they treat read mode like write mode. + * + * If constructed with a RWLockHandle or an instance of Lockable (which in + * practice means any VirtualBoxBase derivative), it autoamtically requests + * the lock in read mode and releases the read lock in the destructor. + */ +class AutoReadLock : public AutoLockBase +{ +public: + + /** + * Constructs a null instance that does not manage any read/write + * semaphore. + * + * Note that all method calls on a null instance are no-ops. This allows to + * have the code where lock protection can be selected (or omitted) at + * runtime. + */ + AutoReadLock(LOCKVAL_SRC_POS_DECL) + : AutoLockBase(1, + NULL + COMMA_LOCKVAL_SRC_POS_ARGS) + { } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a read lock. + */ + AutoReadLock(LockHandle *aHandle + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(1, + aHandle + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a read lock. + */ + AutoReadLock(LockHandle &aHandle + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(1, + &aHandle + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a read lock. + */ + AutoReadLock(const Lockable &aLockable + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(1, + aLockable.lockHandle() + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a read lock. + */ + AutoReadLock(const Lockable *aLockable + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(1, + aLockable ? aLockable->lockHandle() : NULL + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + virtual ~AutoReadLock(); + + virtual void callLockImpl(LockHandle &l); + virtual void callUnlockImpl(LockHandle &l); + +private: + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoReadLock); /* Shuts up MSC warning C4625. */ +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// AutoWriteLockBase +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Base class for all auto write locks. + * + * This cannot be used directly. Use AutoWriteLock or AutoMultiWriteLock2/3 + * which derive from this. + * + * It has some utility methods for subclasses. + */ +class AutoWriteLockBase : public AutoLockBase +{ +protected: + AutoWriteLockBase(uint32_t cHandles + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(cHandles + COMMA_LOCKVAL_SRC_POS_ARGS) + { } + + AutoWriteLockBase(uint32_t cHandles, + LockHandle *pHandle + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(cHandles, + pHandle + COMMA_LOCKVAL_SRC_POS_ARGS) + { } + + virtual ~AutoWriteLockBase() + { } + + virtual void callLockImpl(LockHandle &l); + virtual void callUnlockImpl(LockHandle &l); + +private: + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoWriteLockBase); /* Shuts up MSC warning C4625. */ +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// AutoWriteLock +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Automatic write lock. Use this with a RWLockHandle to request a read/write + * semaphore in write mode. There can only ever be one writer of a read/write + * semaphore: while the lock is held in write mode, no other writer or reader + * can request the semaphore and will block. + * + * If constructed with a RWLockHandle or an instance of Lockable (which in + * practice means any VirtualBoxBase derivative), it autoamtically requests + * the lock in write mode and releases the write lock in the destructor. + * + * When used with a WriteLockHandle, it requests the semaphore contained therein + * exclusively. + */ +class AutoWriteLock : public AutoWriteLockBase +{ +public: + + /** + * Constructs a null instance that does not manage any read/write + * semaphore. + * + * Note that all method calls on a null instance are no-ops. This allows to + * have the code where lock protection can be selected (or omitted) at + * runtime. + */ + AutoWriteLock(LOCKVAL_SRC_POS_DECL) + : AutoWriteLockBase(1, + NULL + COMMA_LOCKVAL_SRC_POS_ARGS) + { } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a write lock. + */ + AutoWriteLock(LockHandle *aHandle + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoWriteLockBase(1, + aHandle + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a write lock. + */ + AutoWriteLock(LockHandle &aHandle + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoWriteLockBase(1, + &aHandle + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a write lock. + */ + AutoWriteLock(const Lockable &aLockable + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoWriteLockBase(1, + aLockable.lockHandle() + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a write lock. + */ + AutoWriteLock(const Lockable *aLockable + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoWriteLockBase(1, + aLockable ? aLockable->lockHandle() : NULL + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a write lock. + */ + AutoWriteLock(uint32_t cHandles, + LockHandle** pHandles + COMMA_LOCKVAL_SRC_POS_DECL); + + /** + * Release all write locks acquired by this instance through the #acquire() + * call and destroys the instance. + * + * Note that if there there are nested #acquire() calls without the + * corresponding number of #release() calls when the destructor is called, it + * will assert. This is because having an unbalanced number of nested locks + * is a program logic error which must be fixed. + */ + virtual ~AutoWriteLock() + { + cleanup(); + } + + void attach(LockHandle *aHandle); + + /** @see attach (LockHandle *) */ + void attach(LockHandle &aHandle) + { + attach(&aHandle); + } + + /** @see attach (LockHandle *) */ + void attach(const Lockable &aLockable) + { + attach(aLockable.lockHandle()); + } + + /** @see attach (LockHandle *) */ + void attach(const Lockable *aLockable) + { + attach(aLockable ? aLockable->lockHandle() : NULL); + } + + bool isWriteLockOnCurrentThread() const; + uint32_t writeLockLevel() const; + + bool isReadLockedOnCurrentThread(bool fWannaHear = true) const; + +private: + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoWriteLock); /* Shuts up MSC warning C4625. */ +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// AutoMultiWriteLock* +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * A multi-write-lock containing two other write locks. + * + */ +class AutoMultiWriteLock2 : public AutoWriteLockBase +{ +public: + AutoMultiWriteLock2(Lockable *pl1, + Lockable *pl2 + COMMA_LOCKVAL_SRC_POS_DECL); + AutoMultiWriteLock2(LockHandle *pl1, + LockHandle *pl2 + COMMA_LOCKVAL_SRC_POS_DECL); + + virtual ~AutoMultiWriteLock2() + { + cleanup(); + } + +private: + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoMultiWriteLock2); /* Shuts up MSC warning C4625. */ +}; + +/** + * A multi-write-lock containing three other write locks. + * + */ +class AutoMultiWriteLock3 : public AutoWriteLockBase +{ +public: + AutoMultiWriteLock3(Lockable *pl1, + Lockable *pl2, + Lockable *pl3 + COMMA_LOCKVAL_SRC_POS_DECL); + AutoMultiWriteLock3(LockHandle *pl1, + LockHandle *pl2, + LockHandle *pl3 + COMMA_LOCKVAL_SRC_POS_DECL); + + virtual ~AutoMultiWriteLock3() + { + cleanup(); + } + +private: + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoMultiWriteLock3); /* Shuts up MSC warning C4625. */ +}; + +/** + * A multi-write-lock containing four other write locks. + * + */ +class AutoMultiWriteLock4 : public AutoWriteLockBase +{ +public: + AutoMultiWriteLock4(Lockable *pl1, + Lockable *pl2, + Lockable *pl3, + Lockable *pl4 + COMMA_LOCKVAL_SRC_POS_DECL); + AutoMultiWriteLock4(LockHandle *pl1, + LockHandle *pl2, + LockHandle *pl3, + LockHandle *pl4 + COMMA_LOCKVAL_SRC_POS_DECL); + + virtual ~AutoMultiWriteLock4() + { + cleanup(); + } + +private: + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoMultiWriteLock4); /* Shuts up MSC warning C4625. */ +}; + +} /* namespace util */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_AutoLock_h */ + +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/include/VBox/com/ErrorInfo.h b/include/VBox/com/ErrorInfo.h new file mode 100644 index 00000000..fd6e786c --- /dev/null +++ b/include/VBox/com/ErrorInfo.h @@ -0,0 +1,545 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - ErrorInfo class declaration. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_ErrorInfo_h +#define VBOX_INCLUDED_com_ErrorInfo_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBox/com/ptr.h" +#include "VBox/com/string.h" +#include "VBox/com/Guid.h" +#include "VBox/com/assert.h" + + +/** @defgroup grp_com_errinfo ErrorInfo Classes + * @ingroup grp_com + * @{ + */ + +COM_STRUCT_OR_CLASS(IProgress); +COM_STRUCT_OR_CLASS(IVirtualBoxErrorInfo); + +namespace com +{ + +/** + * General discussion: + * + * In COM all errors are stored on a per thread basis. In general this means + * only _one_ active error is possible per thread. A new error will overwrite + * the previous one. To prevent this use MultiResult or ErrorInfoKeeper (see + * below). The implementations in MSCOM/XPCOM differ slightly, but the details + * are handled by this glue code. + * + * We have different classes which are involved in the error management. I try + * to describe them separately to make clear what they are there for. + * + * ErrorInfo: + * + * This class is able to retrieve the per thread error and store it into its + * member variables. This class can also handle non-VirtualBox errors (like + * standard COM errors). + * + * ProgressErrorInfo: + * + * This is just a simple wrapper class to get the ErrorInfo stored within an + * IProgress object. That is the error which was stored when the progress + * object was in use and not an error produced by IProgress itself. + * + * IVirtualBoxErrorInfo: + * + * The VirtualBox interface class for accessing error information from Main + * clients. This class is also used for storing the error information in the + * thread context. + * + * ErrorInfoKeeper: + * + * A helper class which stores the current per thread info internally. After + * calling methods which may produce other errors it is possible to restore + * the previous error and therefore restore the situation before calling the + * other methods. + * + * MultiResult: + * + * Creating an instance of MultiResult turns error chain saving on. All errors + * which follow will be saved in a chain for later access. + * + * COMErrorInfo (Qt/Gui only): + * + * The Qt GUI does some additional work for saving errors. Because we create + * wrappers for _every_ COM call, it is possible to automatically save the + * error info after the execution. This allow some additional info like saving + * the callee. Please note that this error info is saved on the client side + * and therefore locally to the object instance. See COMBaseWithEI, + * COMErrorInfo and the generated COMWrappers.cpp in the GUI. + * + * Errors itself are set in VirtualBoxBase::setErrorInternal. First a + * IVirtualBoxErrorInfo object is created and the given error is saved within. + * If MultiResult is active the current per thread error is fetched and + * attached to the new created IVirtualBoxErrorInfo object. Next this object is + * set as the new per thread error. + * + * Some general hints: + * + * - Always use setError, especially when you are working in an asynchronous thread + * to indicate an error. Otherwise the error information itself will not make + * it into the client. + * + */ + +/** + * The ErrorInfo class provides a convenient way to retrieve error + * information set by the most recent interface method, that was invoked on + * the current thread and returned an unsuccessful result code. + * + * Once the instance of this class is created, the error information for + * the current thread is cleared. + * + * There is no sense to use instances of this class after the last + * invoked interface method returns a success. + * + * The class usage pattern is as follows: + * <code> + * IFoo *foo; + * ... + * HRESULT rc = foo->SomeMethod(); + * if (FAILED(rc)) { + * ErrorInfo info(foo); + * if (info.isFullAvailable()) { + * printf("error message = %ls\n", info.getText().raw()); + * } + * } + * </code> + * + * This class fetches error information using the IErrorInfo interface on + * Win32 (MS COM) or the nsIException interface on other platforms (XPCOM), + * or the extended IVirtualBoxErrorInfo interface when when it is available + * (i.e. a given IErrorInfo or nsIException instance implements it). + * Currently, IVirtualBoxErrorInfo is only available for VirtualBox components. + * + * ErrorInfo::isFullAvailable() and ErrorInfo::isBasicAvailable() determine + * what level of error information is available. If #isBasicAvailable() + * returns true, it means that only IErrorInfo or nsIException is available as + * the source of information (depending on the platform), but not + * IVirtualBoxErrorInfo. If #isFullAvailable() returns true, it means that all + * three interfaces are available. If both methods return false, no error info + * is available at all. + * + * Here is a table of correspondence between this class methods and + * and IErrorInfo/nsIException/IVirtualBoxErrorInfo attributes/methods: + * + * ErrorInfo IErrorInfo nsIException IVirtualBoxErrorInfo + * -------------------------------------------------------------------- + * getResultCode -- result resultCode + * getIID GetGUID -- interfaceID + * getComponent GetSource -- component + * getText GetDescription message text + * + * '--' means that this interface does not provide the corresponding portion + * of information, therefore it is useless to query it if only + * #isBasicAvailable() returns true. As it can be seen, the amount of + * information provided at the basic level, depends on the platform + * (MS COM or XPCOM). + */ +class ErrorInfo +{ +public: + + /** + * Constructs a new, "interfaceless" ErrorInfo instance that takes + * the error information possibly set on the current thread by an + * interface method of some COM component or by the COM subsystem. + * + * This constructor is useful, for example, after an unsuccessful attempt + * to instantiate (create) a component, so there is no any valid interface + * pointer available. + */ + explicit ErrorInfo() + : mIsBasicAvailable(false), + mIsFullAvailable(false), + mResultCode(S_OK), + mResultDetail(0), + m_pNext(NULL) + { + init(); + } + + ErrorInfo(IUnknown *pObj, const GUID &aIID) + : mIsBasicAvailable(false), + mIsFullAvailable(false), + mResultCode(S_OK), + mResultDetail(0), + m_pNext(NULL) + { + init(pObj, aIID); + } + + /** Specialization for the IVirtualBoxErrorInfo smart pointer */ + ErrorInfo(const ComPtr<IVirtualBoxErrorInfo> &aPtr) + : mIsBasicAvailable(false), mIsFullAvailable(false) + , mResultCode(S_OK), mResultDetail(0) + { init(aPtr); } + + /** + * Constructs a new ErrorInfo instance from the IVirtualBoxErrorInfo + * interface pointer. If this pointer is not NULL, both #isFullAvailable() + * and #isBasicAvailable() will return |true|. + * + * @param aInfo pointer to the IVirtualBoxErrorInfo interface that + * holds error info to be fetched by this instance + */ + ErrorInfo(IVirtualBoxErrorInfo *aInfo) + : mIsBasicAvailable(false), mIsFullAvailable(false) + , mResultCode(S_OK), mResultDetail(0) + { init(aInfo); } + + ErrorInfo(const ErrorInfo &x) + { + copyFrom(x); + } + + virtual ~ErrorInfo() + { + cleanup(); + } + + ErrorInfo& operator=(const ErrorInfo& x) + { + cleanup(); + copyFrom(x); + return *this; + } + + /** + * Returns whether basic error info is actually available for the current + * thread. If the instance was created from an interface pointer that + * supports basic error info and successfully provided it, or if it is an + * "interfaceless" instance and there is some error info for the current + * thread, the returned value will be true. + * + * See the class description for details about the basic error info level. + * + * The appropriate methods of this class provide meaningful info only when + * this method returns true (otherwise they simply return NULL-like values). + */ + bool isBasicAvailable() const + { + return mIsBasicAvailable; + } + + /** + * Returns whether full error info is actually available for the current + * thread. If the instance was created from an interface pointer that + * supports full error info and successfully provided it, or if it is an + * "interfaceless" instance and there is some error info for the current + * thread, the returned value will be true. + * + * See the class description for details about the full error info level. + * + * The appropriate methods of this class provide meaningful info only when + * this method returns true (otherwise they simply return NULL-like values). + */ + bool isFullAvailable() const + { + return mIsFullAvailable; + } + + /** + * Returns the COM result code of the failed operation. + */ + HRESULT getResultCode() const + { + return mResultCode; + } + + /** + * Returns the (optional) result detail code of the failed operation. + */ + LONG getResultDetail() const + { + return mResultDetail; + } + + /** + * Returns the IID of the interface that defined the error. + */ + const Guid& getInterfaceID() const + { + return mInterfaceID; + } + + /** + * Returns the name of the component that generated the error. + */ + const Bstr& getComponent() const + { + return mComponent; + } + + /** + * Returns the textual description of the error. + */ + const Bstr& getText() const + { + return mText; + } + + /** + * Returns the next error information object or @c NULL if there is none. + */ + const ErrorInfo* getNext() const + { + return m_pNext; + } + + /** + * Returns the name of the interface that defined the error + */ + const Bstr& getInterfaceName() const + { + return mInterfaceName; + } + + /** + * Returns the IID of the interface that returned the error. + * + * This method returns a non-null IID only if the instance was created + * using template \<class I\> ErrorInfo(I *i) or + * template \<class I\> ErrorInfo(const ComPtr<I> &i) constructor. + * + * @todo broken ErrorInfo documentation links, possibly misleading. + */ + const Guid& getCalleeIID() const + { + return mCalleeIID; + } + + /** + * Returns the name of the interface that returned the error + * + * This method returns a non-null name only if the instance was created + * using template \<class I\> ErrorInfo(I *i) or + * template \<class I\> ErrorInfo(const ComPtr<I> &i) constructor. + * + * @todo broken ErrorInfo documentation links, possibly misleading. + */ + const Bstr& getCalleeName() const + { + return mCalleeName; + } + + HRESULT getVirtualBoxErrorInfo(ComPtr<IVirtualBoxErrorInfo> &pVirtualBoxErrorInfo); + + /** + * Resets all collected error information. #isBasicAvailable() and + * #isFullAvailable will return @c true after this method is called. + */ + void setNull() + { + cleanup(); + } + +protected: + + ErrorInfo(bool /* aDummy */) + : mIsBasicAvailable(false), + mIsFullAvailable(false), + mResultCode(S_OK), + m_pNext(NULL) + { } + + void copyFrom(const ErrorInfo &x); + void cleanup(); + + void init(bool aKeepObj = false); + void init(IUnknown *aUnk, const GUID &aIID, bool aKeepObj = false); + void init(IVirtualBoxErrorInfo *aInfo); + + bool mIsBasicAvailable : 1; + bool mIsFullAvailable : 1; + + HRESULT mResultCode; + LONG mResultDetail; + Guid mInterfaceID; + Bstr mComponent; + Bstr mText; + + ErrorInfo *m_pNext; + + Bstr mInterfaceName; + Guid mCalleeIID; + Bstr mCalleeName; + + ComPtr<IUnknown> mErrorInfo; +}; + +/** + * A convenience subclass of ErrorInfo that, given an IProgress interface + * pointer, reads its errorInfo attribute and uses the returned + * IVirtualBoxErrorInfo instance to construct itself. + */ +class ProgressErrorInfo : public ErrorInfo +{ +public: + + /** + * Constructs a new instance by fetching error information from the + * IProgress interface pointer. If the progress object is not NULL, + * its completed attribute is true, resultCode represents a failure, + * and the errorInfo attribute returns a valid IVirtualBoxErrorInfo pointer, + * both #isFullAvailable() and #isBasicAvailable() will return true. + * + * @param progress the progress object representing a failed operation + */ + ProgressErrorInfo(IProgress *progress); +}; + +/** + * A convenience subclass of ErrorInfo that allows to preserve the current + * error info. Instances of this class fetch an error info object set on the + * current thread and keep a reference to it, which allows to restore it + * later using the #restore() method. This is useful to preserve error + * information returned by some method for the duration of making another COM + * call that may set its own error info and overwrite the existing + * one. Preserving and restoring error information makes sense when some + * method wants to return error information set by other call as its own + * error information while it still needs to make another call before return. + * + * Instead of calling #restore() explicitly you may let the object destructor + * do it for you, if you correctly limit the object's lifetime. + * + * The usage pattern is: + * <code> + * rc = foo->method(); + * if (FAILED(rc)) + * { + * ErrorInfoKeeper eik; + * ... + * // bar may return error info as well + * bar->method(); + * ... + * // no need to call #restore() explicitly here because the eik's + * // destructor will restore error info fetched after the failed + * // call to foo before returning to the caller + * return rc; + * } + * </code> + */ +class ErrorInfoKeeper : public ErrorInfo +{ +public: + + /** + * Constructs a new instance that will fetch the current error info if + * @a aIsNull is @c false (by default) or remain uninitialized (null) + * otherwise. + * + * @param aIsNull @c true to prevent fetching error info and leave + * the instance uninitialized. + */ + ErrorInfoKeeper(bool aIsNull = false) + : ErrorInfo(false), mForgot(aIsNull) + { + if (!aIsNull) + init(true /* aKeepObj */); + } + + /** + * Constructs a new instance from an ErrorInfo object, to inject a full + * error info created elsewhere. + * + * @param aInfo @c true to prevent fetching error info and leave + * the instance uninitialized. + */ + ErrorInfoKeeper(const ErrorInfo &aInfo) + : ErrorInfo(false), mForgot(false) + { + copyFrom(aInfo); + } + + /** + * Destroys this instance and automatically calls #restore() which will + * either restore error info fetched by the constructor or do nothing + * if #forget() was called before destruction. + */ + ~ErrorInfoKeeper() { if (!mForgot) restore(); } + + /** + * Tries to (re-)fetch error info set on the current thread. On success, + * the previous error information, if any, will be overwritten with the + * new error information. On failure, or if there is no error information + * available, this instance will be reset to null. + */ + void fetch() + { + setNull(); + mForgot = false; + init(true /* aKeepObj */); + } + + /** + * Restores error info fetched by the constructor and forgets it + * afterwards. Does nothing if the error info was forgotten by #forget(). + * + * @return COM result of the restore operation. + */ + HRESULT restore(); + + /** + * Forgets error info fetched by the constructor to prevent it from + * being restored by #restore() or by the destructor. + */ + void forget() { mForgot = true; } + + /** + * Forgets error info fetched by the constructor to prevent it from + * being restored by #restore() or by the destructor, and returns the + * stored error info object to the caller. + */ + ComPtr<IUnknown> takeError() { mForgot = true; return mErrorInfo; } + +private: + + bool mForgot : 1; +}; + +} /* namespace com */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_ErrorInfo_h */ + diff --git a/include/VBox/com/EventQueue.h b/include/VBox/com/EventQueue.h new file mode 100644 index 00000000..ef101377 --- /dev/null +++ b/include/VBox/com/EventQueue.h @@ -0,0 +1,151 @@ +/* $Id: EventQueue.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - Event queue class declaration. + */ + +/* + * Copyright (C) 2013-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_EventQueue_h +#define VBOX_INCLUDED_com_EventQueue_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <list> + +#include <iprt/asm.h> +#include <iprt/critsect.h> + +#include <VBox/com/defs.h> +#include <VBox/com/assert.h> + + +/** @defgroup grp_com_evtqueue Event Queue Classes + * @ingroup grp_com + * @{ + */ + +namespace com +{ + +class EventQueue; + +/** + * Base class for all events. Intended to be subclassed to introduce new + * events and handlers for them. + * + * Subclasses usually reimplement virtual #handler() (that does nothing by + * default) and add new data members describing the event. + */ +class Event +{ +public: + + Event(void) : + mRefCount(0) { } + virtual ~Event(void) { AssertMsg(!mRefCount, + ("Reference count of event=%p not 0 on destruction (is %RU32)\n", + this, mRefCount)); } +public: + + uint32_t AddRef(void) { return ASMAtomicIncU32(&mRefCount); } + void Release(void) + { + Assert(mRefCount); + uint32_t cRefs = ASMAtomicDecU32(&mRefCount); + if (!cRefs) + delete this; + } + +protected: + + /** + * Event handler. Called in the context of the event queue's thread. + * Always reimplemented by subclasses + * + * @return reserved, should be NULL. + */ + virtual void *handler(void) { return NULL; } + + friend class EventQueue; + +protected: + + /** The event's reference count. */ + uint32_t mRefCount; +}; + +typedef std::list< Event* > EventQueueList; +typedef std::list< Event* >::iterator EventQueueListIterator; +typedef std::list< Event* >::const_iterator EventQueueListIteratorConst; + +/** + * Simple event queue. + */ +class EventQueue +{ +public: + + EventQueue(void); + virtual ~EventQueue(void); + +public: + + BOOL postEvent(Event *event); + int processEventQueue(RTMSINTERVAL cMsTimeout); + int processPendingEvents(size_t cNumEvents); + int interruptEventQueueProcessing(); + +private: + + /** Critical section for serializing access to this + * event queue. */ + RTCRITSECT mCritSect; + /** Number of concurrent users. At the moment we + * only support one concurrent user at a time when + calling processEventQueue(). */ + uint32_t mUserCnt; + /** Event semaphore for getting notified on new + * events being handled. */ + RTSEMEVENT mSemEvent; + /** The actual event queue, implemented as a list. */ + EventQueueList mEvents; + /** Shutdown indicator. */ + bool mShutdown; +}; + +} /* namespace com */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_EventQueue_h */ + diff --git a/include/VBox/com/Guid.h b/include/VBox/com/Guid.h new file mode 100644 index 00000000..42663323 --- /dev/null +++ b/include/VBox/com/Guid.h @@ -0,0 +1,526 @@ +/* $Id: Guid.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - Guid class declaration. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_Guid_h +#define VBOX_INCLUDED_com_Guid_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Make sure all the stdint.h macros are included - must come first! */ +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#include "VBox/com/string.h" + +#include <iprt/uuid.h> + + +/** @defgroup grp_com_guid GUID Class + * @ingroup grp_com + * @{ + */ + +namespace com +{ + +typedef enum GuidState_t +{ + GUID_ZERO, + GUID_NORMAL, + GUID_INVALID +} GuidState_t; + +/** + * Helper class that represents the UUID type and hides platform-specific + * implementation details. + */ +class Guid +{ +public: + + Guid() + { + clear(); + } + + Guid(const Guid &that) + { + mUuid = that.mUuid; + mGuidState = that.mGuidState; + dbg_refresh(); + } + + Guid(const RTUUID &that) + { + mUuid = that; + updateState(); + dbg_refresh(); + } + + Guid(const GUID &that) + { + AssertCompileSize(GUID, sizeof(RTUUID)); + ::memcpy(&mUuid, &that, sizeof(GUID)); + updateState(); + dbg_refresh(); + } + + /** + * Construct a GUID from a string. + * + * @param that The UUID string. Can be with or without the curly + * brackets. Empty strings are translated to a zero + * GUID, and strings which are not confirming to + * valid GUID string representations are marked as + * invalid. + */ + Guid(const char *that) + { + initString(that); + } + + /** + * Construct a GUID from a BSTR. + * + * @param that The UUID BSTR. Can be with or without the curly + * brackets. Empty strings are translated to a zero + * GUID, and strings which are not confirming to + * valid GUID string representations are marked as + * invalid. + */ + Guid(CBSTR that) + { + initBSTR(that); + } + + /** + * Construct a GUID from a Utf8Str. + * + * @param that The UUID Utf8Str. Can be with or without the curly + * brackets. Empty strings are translated to a zero + * GUID, and strings which are not confirming to + * valid GUID string representations are marked as + */ + Guid(const Utf8Str &that) + { + initString(that.c_str()); + } + + /** + * Construct a GUID from a RTCString. + * + * @param that The UUID RTCString. Can be with or without the curly + * brackets. Empty strings are translated to a zero + * GUID, and strings which are not confirming to + * valid GUID string representations are marked as + */ + Guid(const RTCString &that) + { + initString(that.c_str()); + } + + /** + * Construct a GUID from a Bstr. + * + * @param that The UUID Bstr. Can be with or without the curly + * brackets. Empty strings are translated to a zero + * GUID, and strings which are not confirming to + * valid GUID string representations are marked as + */ + Guid(const Bstr &that) + { + initBSTR(that.raw()); + } + + Guid& operator=(const Guid &that) + { + mUuid = that.mUuid; + mGuidState = that.mGuidState; + dbg_refresh(); + return *this; + } + + Guid& operator=(const RTUUID &guid) + { + mUuid = guid; + updateState(); + dbg_refresh(); + return *this; + } + + Guid& operator=(const GUID &guid) + { + AssertCompileSize(GUID, sizeof(RTUUID)); + ::memcpy(&mUuid, &guid, sizeof(GUID)); + updateState(); + dbg_refresh(); + return *this; + } + + Guid& operator=(const char *str) + { + initString(str); + return *this; + } + + Guid& operator=(CBSTR str) + { + initBSTR(str); + return *this; + } + + Guid& operator=(const Utf8Str &str) + { + return operator=(str.c_str()); + } + + Guid& operator=(const RTCString &str) + { + return operator=(str.c_str()); + } + + Guid& operator=(const Bstr &str) + { + return operator=(str.raw()); + } + + void create() + { + ::RTUuidCreate(&mUuid); + mGuidState = GUID_NORMAL; + dbg_refresh(); + } + + void clear() + { + makeClear(); + dbg_refresh(); + } + + /** + * Convert the GUID to a string. + * + * @returns String object containing the formatted GUID. + * @throws std::bad_alloc + */ + Utf8Str toString() const + { + if (mGuidState == GUID_INVALID) + { + /* What to return in case of wrong Guid */ + return Utf8Str("00000000-0000-0000-0000-00000000000"); + } + + char buf[RTUUID_STR_LENGTH]; + ::memset(buf, '\0', sizeof(buf)); + ::RTUuidToStr(&mUuid, buf, sizeof(buf)); + + return Utf8Str(buf); + } + + /** + * Like toString, but encloses the returned string in curly brackets. + * + * @returns String object containing the formatted GUID in curly brackets. + * @throws std::bad_alloc + */ + Utf8Str toStringCurly() const + { + if (mGuidState == GUID_INVALID) + { + /* What to return in case of wrong Guid */ + return Utf8Str("{00000000-0000-0000-0000-00000000000}"); + } + + char buf[RTUUID_STR_LENGTH + 2]; + ::memset(buf, '\0', sizeof(buf)); + ::RTUuidToStr(&mUuid, buf + 1, sizeof(buf) - 2); + buf[0] = '{'; + buf[sizeof(buf) - 2] = '}'; + + return Utf8Str(buf); + } + + /** + * Convert the GUID to a string. + * + * @returns Bstr object containing the formatted GUID. + * @throws std::bad_alloc + */ + Bstr toUtf16() const + { + if (mGuidState == GUID_INVALID) + { + /* What to return in case of wrong Guid */ + return Bstr("00000000-0000-0000-0000-00000000000"); + } + + RTUTF16 buf[RTUUID_STR_LENGTH]; + ::memset(buf, '\0', sizeof(buf)); + ::RTUuidToUtf16(&mUuid, buf, RT_ELEMENTS(buf)); + + return Bstr(buf); + } + + /** + * Convert the GUID to a C string. + * + * @returns See RTUuidToStr. + * @param pszUuid The output buffer + * @param cbUuid The size of the output buffer. Should be at least + * RTUUID_STR_LENGTH in length. + */ + int toString(char *pszUuid, size_t cbUuid) const + { + return ::RTUuidToStr(mGuidState != GUID_INVALID ? &mUuid : &Empty.mUuid, pszUuid, cbUuid); + } + + bool isValid() const + { + return mGuidState != GUID_INVALID; + } + + bool isZero() const + { + return mGuidState == GUID_ZERO; + } + + bool operator==(const Guid &that) const { return ::RTUuidCompare(&mUuid, &that.mUuid) == 0; } + bool operator==(const RTUUID &guid) const { return ::RTUuidCompare(&mUuid, &guid) == 0; } + bool operator==(const GUID &guid) const { return ::RTUuidCompare(&mUuid, (PRTUUID)&guid) == 0; } + bool operator!=(const Guid &that) const { return !operator==(that); } + bool operator!=(const GUID &guid) const { return !operator==(guid); } + bool operator!=(const RTUUID &guid) const { return !operator==(guid); } + bool operator<(const Guid &that) const { return ::RTUuidCompare(&mUuid, &that.mUuid) < 0; } + bool operator<(const GUID &guid) const { return ::RTUuidCompare(&mUuid, (PRTUUID)&guid) < 0; } + bool operator<(const RTUUID &guid) const { return ::RTUuidCompare(&mUuid, &guid) < 0; } + + /** Compare with a UUID string representation. + * @note Not an operator as that could lead to confusion. */ + bool equalsString(const char *pszUuid2) const { return ::RTUuidCompareStr(&mUuid, pszUuid2) == 0; } + + /** + * To directly copy the contents to a GUID, or for passing it as an input + * parameter of type (const GUID *), the compiler converts. */ + const GUID &ref() const + { + return *(const GUID *)&mUuid; + } + + /** + * To pass instances to printf-like functions. + */ + PCRTUUID raw() const + { + return (PCRTUUID)&mUuid; + } + +#if !defined(VBOX_WITH_XPCOM) + + /** To assign instances to OUT_GUID parameters from within the interface + * method. */ + const Guid &cloneTo(GUID *pguid) const + { + if (pguid) + ::memcpy(pguid, &mUuid, sizeof(GUID)); + return *this; + } + + /** To pass instances as OUT_GUID parameters to interface methods. */ + GUID *asOutParam() + { + return (GUID *)&mUuid; + } + +#else + + /** To assign instances to OUT_GUID parameters from within the + * interface method */ + const Guid &cloneTo(nsID **ppGuid) const + { + if (ppGuid) + *ppGuid = (nsID *)nsMemory::Clone(&mUuid, sizeof(nsID)); + + return *this; + } + + /** + * Internal helper class for asOutParam(). + * + * This takes a GUID reference in the constructor and copies the mUuid from + * the method to that instance in its destructor. + */ + class GuidOutParam + { + GuidOutParam(Guid &guid) + : ptr(0), + outer(guid) + { + outer.clear(); + } + + nsID *ptr; + Guid &outer; + GuidOutParam(const GuidOutParam &that); // disabled + GuidOutParam &operator=(const GuidOutParam &that); // disabled + public: + operator nsID**() { return &ptr; } + ~GuidOutParam() + { + if (ptr && outer.isZero()) + { + outer = *ptr; + outer.dbg_refresh(); + nsMemory::Free(ptr); + } + } + friend class Guid; + }; + + /** to pass instances as OUT_GUID parameters to interface methods */ + GuidOutParam asOutParam() { return GuidOutParam(*this); } + +#endif + + /** + * Static immutable empty (zero) object. May be used for comparison purposes. + */ + static const Guid Empty; + +private: + void makeClear() + { + ::RTUuidClear(&mUuid); + mGuidState = GUID_ZERO; + } + + void makeInvalid() + { + ::RTUuidClear(&mUuid); + mGuidState = GUID_INVALID; + } + + void updateState() + { + if (::RTUuidIsNull(&mUuid)) + mGuidState = GUID_ZERO; + else + mGuidState = GUID_NORMAL; + } + + void initString(const char *that) + { + if (!that || !*that) + { + makeClear(); + } + else + { + int rc = ::RTUuidFromStr(&mUuid, that); + if (RT_SUCCESS(rc)) + updateState(); + else + makeInvalid(); + } + dbg_refresh(); + } + + void initBSTR(CBSTR that) + { + if (!that || !*that) + { + makeClear(); + } + else + { + int rc = ::RTUuidFromUtf16(&mUuid, that); + if (RT_SUCCESS(rc)) + updateState(); + else + makeInvalid(); + } + dbg_refresh(); + } + + /** + * Refresh the debug-only UUID string. + * + * In debug code, refresh the UUID string representatino for debugging; + * must be called every time the internal uuid changes; compiles to nothing + * in release code. + */ + inline void dbg_refresh() + { +#ifdef DEBUG + switch (mGuidState) + { + case GUID_ZERO: + case GUID_NORMAL: + ::RTUuidToStr(&mUuid, mszUuid, RTUUID_STR_LENGTH); + break; + default: + ::memset(mszUuid, '\0', sizeof(mszUuid)); + ::RTStrCopy(mszUuid, sizeof(mszUuid), "INVALID"); + break; + } + m_pcszUUID = mszUuid; +#endif + } + + /** The UUID. */ + RTUUID mUuid; + + GuidState_t mGuidState; + +#ifdef DEBUG + /** String representation of mUuid for printing in the debugger. */ + char mszUuid[RTUUID_STR_LENGTH]; + /** Another string variant for the debugger, points to szUUID. */ + const char *m_pcszUUID; +#endif +}; + +} /* namespace com */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_Guid_h */ + diff --git a/include/VBox/com/Makefile.kup b/include/VBox/com/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/VBox/com/Makefile.kup diff --git a/include/VBox/com/MultiResult.h b/include/VBox/com/MultiResult.h new file mode 100644 index 00000000..c64ad58c --- /dev/null +++ b/include/VBox/com/MultiResult.h @@ -0,0 +1,278 @@ +/* $Id: MultiResult.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - MultiResult class declarations. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_MultiResult_h +#define VBOX_INCLUDED_com_MultiResult_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBox/com/defs.h" +#include "VBox/com/string.h" + +#include <stdarg.h> + +/** @defgroup grp_com_mr MultiResult Classes + * @ingroup grp_com + * @{ + */ + +namespace com +{ + +/** + * "First worst" result type. + * + * Variables of this class are used instead of HRESULT variables when it is + * desirable to memorize the "first worst" result code instead of the last + * assigned one. In other words, an assignment operation to a variable of this + * class will succeed only if the result code to assign has worse severity. The + * following table demonstrate this (the first column lists the previous result + * code stored in the variable, the first row lists the new result code being + * assigned, 'A' means the assignment will take place, '> S_OK' means a warning + * result code): + * + * {{{ + * FAILED > S_OK S_OK + * FAILED - - - + * > S_OK A - - + * S_OK A A - + * + * }}} + * + * In practice, you will need to use a FWResult variable when you call some COM + * method B after another COM method A fails and want to return the result code + * of A even if B also fails, but want to return the failed result code of B if + * A issues a warning or succeeds. + */ +class FWResult +{ + +public: + + /** + * Constructs a new variable. Note that by default this constructor sets the + * result code to E_FAIL to make sure a failure is returned to the caller if + * the variable is never assigned another value (which is considered as the + * improper use of this class). + */ + FWResult (HRESULT aRC = E_FAIL) : mRC (aRC) {} + + FWResult &operator= (HRESULT aRC) + { + if ((FAILED (aRC) && !FAILED (mRC)) || + (mRC == S_OK && aRC != S_OK)) + mRC = aRC; + + return *this; + } + + operator HRESULT() const { return mRC; } + + HRESULT *operator&() { return &mRC; } + +private: + + HRESULT mRC; +}; + +/** + * The MultiResult class is a com::FWResult enhancement that also acts as a + * switch to turn on multi-error mode for VirtualBoxBase::setError() and + * VirtualBoxBase::setWarning() calls. + * + * When an instance of this class is created, multi-error mode is turned on + * for the current thread and the turn-on counter is increased by one. In + * multi-error mode, a call to setError() or setWarning() does not + * overwrite the current error or warning info object possibly set on the + * current thread by other method calls, but instead it stores this old + * object in the IVirtualBoxErrorInfo::next attribute of the new error + * object being set. + * + * This way, error/warning objects are stacked together and form a chain of + * errors where the most recent error is the first one retrieved by the + * calling party, the preceding error is what the + * IVirtualBoxErrorInfo::next attribute of the first error points to, and so + * on, up to the first error or warning occurred which is the last in the + * chain. See IVirtualBoxErrorInfo documentation for more info. + * + * When the instance of the MultiResult class goes out of scope and gets + * destroyed, it automatically decreases the turn-on counter by one. If + * the counter drops to zero, multi-error mode for the current thread is + * turned off and the thread switches back to single-error mode where every + * next error or warning object overwrites the previous one. + * + * Note that the caller of a COM method uses a non-S_OK result code to + * decide if the method has returned an error (negative codes) or a warning + * (positive non-zero codes) and will query extended error info only in + * these two cases. However, since multi-error mode implies that the method + * doesn't return control return to the caller immediately after the first + * error or warning but continues its execution, the functionality provided + * by the base com::FWResult class becomes very useful because it allows to + * preserve the error or the warning result code even if it is later assigned + * a S_OK value multiple times. See com::FWResult for details. + * + * Here is the typical usage pattern: + * @code + HRESULT Bar::method() + { + // assume multi-errors are turned off here... + + if (something) + { + // Turn on multi-error mode and make sure severity is preserved + MultiResult rc = foo->method1(); + + // return on fatal error, but continue on warning or on success + CheckComRCReturnRC (rc); + + rc = foo->method2(); + // no matter what result, stack it and continue + + // ... + + // return the last worst result code (it will be preserved even if + // foo->method2() returns S_OK. + return rc; + } + + // multi-errors are turned off here again... + + return S_OK; + } + * @endcode + * + * @note This class is intended to be instantiated on the stack, therefore + * You cannot create them using new(). Although it is possible to copy + * instances of MultiResult or return them by value, please never do + * that as it is breaks the class semantics (and will assert); + */ +class MultiResult : public FWResult +{ +public: + + /** + * @copydoc FWResult::FWResult() + */ + MultiResult (HRESULT aRC = E_FAIL) : FWResult (aRC) { incCounter(); } + + MultiResult (const MultiResult &aThat) : FWResult (aThat) + { + /* We need this copy constructor only for GCC that wants to have + * it in case of expressions like |MultiResult rc = E_FAIL;|. But + * we assert since the optimizer should actually avoid the + * temporary and call the other constructor directly instead. */ + AssertFailed(); + } + + ~MultiResult() { decCounter(); } + + MultiResult &operator= (HRESULT aRC) + { + FWResult::operator= (aRC); + return *this; + } + + MultiResult &operator= (const MultiResult & /* aThat */) + { + /* We need this copy constructor only for GCC that wants to have + * it in case of expressions like |MultiResult rc = E_FAIL;|. But + * we assert since the optimizer should actually avoid the + * temporary and call the other constructor directly instead. */ + AssertFailed(); + return *this; + } + + /** + * Returns true if multi-mode is enabled for the current thread (i.e. at + * least one MultiResult instance exists on the stack somewhere). + * @return + */ + static bool isMultiEnabled(); + +private: + + DECLARE_CLS_NEW_DELETE_NOOP(MultiResult); + + static void incCounter(); + static void decCounter(); + + static RTTLS sCounter; + + friend class MultiResultRef; +}; + +/** + * The MultiResultRef class is equivalent to MultiResult except that it takes + * a reference to the existing HRESULT variable instead of maintaining its own + * one. + */ +class MultiResultRef +{ +public: + + MultiResultRef (HRESULT &aRC) : mRC (aRC) { MultiResult::incCounter(); } + + ~MultiResultRef() { MultiResult::decCounter(); } + + MultiResultRef &operator= (HRESULT aRC) + { + /* Copied from FWResult */ + if ((FAILED (aRC) && !FAILED (mRC)) || + (mRC == S_OK && aRC != S_OK)) + mRC = aRC; + + return *this; + } + + operator HRESULT() const { return mRC; } + + HRESULT *operator&() { return &mRC; } + +private: + + DECLARE_CLS_NEW_DELETE_NOOP(MultiResultRef); + + HRESULT &mRC; +}; + + +} /* namespace com */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_MultiResult_h */ + diff --git a/include/VBox/com/NativeEventQueue.h b/include/VBox/com/NativeEventQueue.h new file mode 100644 index 00000000..240acfa3 --- /dev/null +++ b/include/VBox/com/NativeEventQueue.h @@ -0,0 +1,161 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - Event and EventQueue class declaration. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_NativeEventQueue_h +#define VBOX_INCLUDED_com_NativeEventQueue_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef VBOX_WITH_XPCOM +# include <iprt/win/windows.h> +#else +# include <nsEventQueueUtils.h> +#endif + +#include <VBox/com/defs.h> +#include <VBox/com/assert.h> + + +/** @defgroup grp_com_evt Event and EventQueue Classes + * @ingroup grp_com + * @{ + */ + +namespace com +{ + +class MainEventQueue; + +/** + * Base class for all events. Intended to be subclassed to introduce new + * events and handlers for them. + * + * Subclasses usually reimplement virtual #handler() (that does nothing by + * default) and add new data members describing the event. + */ +class NativeEvent +{ +public: + + NativeEvent() {} + virtual ~NativeEvent() {}; + +protected: + + /** + * Event handler. Called in the context of the event queue's thread. + * Always reimplemented by subclasses + * + * @return reserved, should be NULL. + */ + virtual void *handler() { return NULL; } + + friend class NativeEventQueue; +}; + +/** + * Simple event queue. + * + * When using XPCOM, this will map onto the default XPCOM queue for the thread. + * So, if a queue is created on the main thread, it automatically processes + * XPCOM/IPC events while waiting. + * + * When using Windows, Darwin and OS/2, this will map onto the native thread + * queue/runloop. So, windows messages and what not will be processed while + * waiting for events. + * + * @note It is intentional that there is no way to retrieve arbitrary + * events and controlling their processing. There is no use case which + * warrants introducing the complexity of platform independent events. + */ +class NativeEventQueue +{ +public: + + NativeEventQueue(); + virtual ~NativeEventQueue(); + + BOOL postEvent(NativeEvent *event); + int processEventQueue(RTMSINTERVAL cMsTimeout); + int interruptEventQueueProcessing(); + int getSelectFD(); + static int init(); + static int uninit(); + static NativeEventQueue *getMainEventQueue(); + +#ifdef VBOX_WITH_XPCOM + already_AddRefed<nsIEventQueue> getIEventQueue() + { + return mEventQ.get(); + } +#else + static int dispatchMessageOnWindows(MSG const *pMsg, int rc); +#endif + +private: + static NativeEventQueue *sMainQueue; + +#ifndef VBOX_WITH_XPCOM + + /** The thread which the queue belongs to. */ + DWORD mThreadId; + /** Duplicated thread handle for MsgWaitForMultipleObjects. */ + HANDLE mhThread; + +#else // VBOX_WITH_XPCOM + + /** Whether it was created (and thus needs destroying) or if a queue already + * associated with the thread was used. */ + bool mEQCreated; + + /** Whether event processing should be interrupted. */ + bool mInterrupted; + + nsCOMPtr <nsIEventQueue> mEventQ; + nsCOMPtr <nsIEventQueueService> mEventQService; + + static void *PR_CALLBACK plEventHandler(PLEvent *self); + static void PR_CALLBACK plEventDestructor(PLEvent *self); + +#endif // VBOX_WITH_XPCOM +}; + +} /* namespace com */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_NativeEventQueue_h */ + diff --git a/include/VBox/com/VirtualBox.h b/include/VBox/com/VirtualBox.h new file mode 100644 index 00000000..ffaede31 --- /dev/null +++ b/include/VBox/com/VirtualBox.h @@ -0,0 +1,71 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - VirtualBox COM Library definitions. + * + * @note This is the main header file that COM/XPCOM clients include; however, + * it is only a wrapper around another platform-dependent include file + * that contains the real COM/XPCOM interface declarations. That other + * include file is generated automatically at build time from + * /src/VBox/Main/idl/VirtualBox.xidl, which contains all the VirtualBox + * interfaces; the include file is called VirtualBox.h on Windows hosts + * and VirtualBox_XPCOM.h on Linux hosts. The build process places it in + * out/{platform}/bin/sdk/include, from where it gets + * included by the rest of the VirtualBox code. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_VirtualBox_h +#define VBOX_INCLUDED_com_VirtualBox_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* For XPCOM/C++ enum hack checks. */ +#include <iprt/assertcompile.h> + +/* Generated VirtualBox COM library definition file. */ +#if !defined(VBOXCOM_NOINCLUDE) +# if !defined(VBOX_WITH_XPCOM) +# include <iprt/win/windows.h> /* Included by VirtualBox.h via rpc.h, so include our wrapper with cleanups. */ +# include <VirtualBox.h> +# else +# define VBOX_WITH_XPCOM_CPP_ENUM_HACK +# include <VirtualBox_XPCOM.h> +# endif +#endif + +/* For convenience. */ +#include "VBox/com/defs.h" +#include "VBox/com/ptr.h" + +#endif /* !VBOX_INCLUDED_com_VirtualBox_h */ + diff --git a/include/VBox/com/array.h b/include/VBox/com/array.h new file mode 100644 index 00000000..33fc34e3 --- /dev/null +++ b/include/VBox/com/array.h @@ -0,0 +1,1833 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - Safe array helper class declaration. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_array_h +#define VBOX_INCLUDED_com_array_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/** @defgroup grp_com_arrays COM/XPCOM Arrays + * @ingroup grp_com + * @{ + * + * The COM/XPCOM array support layer provides a cross-platform way to pass + * arrays to and from COM interface methods and consists of the com::SafeArray + * template and a set of ComSafeArray* macros part of which is defined in + * VBox/com/defs.h. + * + * This layer works with interface attributes and method parameters that have + * the 'safearray="yes"' attribute in the XIDL definition: + * @code + + <interface name="ISomething" ...> + + <method name="testArrays"> + <param name="inArr" type="long" dir="in" safearray="yes"/> + <param name="outArr" type="long" dir="out" safearray="yes"/> + <param name="retArr" type="long" dir="return" safearray="yes"/> + </method> + + </interface> + + * @endcode + * + * Methods generated from this and similar definitions are implemented in + * component classes using the following declarations: + * @code + + STDMETHOD(TestArrays)(ComSafeArrayIn(LONG, aIn), + ComSafeArrayOut(LONG, aOut), + ComSafeArrayOut(LONG, aRet)); + + * @endcode + * + * And the following function bodies: + * @code + + STDMETHODIMP Component::TestArrays(ComSafeArrayIn(LONG, aIn), + ComSafeArrayOut(LONG, aOut), + ComSafeArrayOut(LONG, aRet)) + { + if (ComSafeArrayInIsNull(aIn)) + return E_INVALIDARG; + if (ComSafeArrayOutIsNull(aOut)) + return E_POINTER; + if (ComSafeArrayOutIsNull(aRet)) + return E_POINTER; + + // Use SafeArray to access the input array parameter + + com::SafeArray<LONG> in(ComSafeArrayInArg(aIn)); + + for (size_t i = 0; i < in.size(); ++ i) + LogFlow(("*** in[%u]=%d\n", i, in[i])); + + // Use SafeArray to create the return array (the same technique is used + // for output array parameters) + + SafeArray<LONG> ret(in.size() * 2); + for (size_t i = 0; i < in.size(); ++ i) + { + ret[i] = in[i]; + ret[i + in.size()] = in[i] * 10; + } + + ret.detachTo(ComSafeArrayOutArg(aRet)); + + return S_OK; + } + + * @endcode + * + * Such methods can be called from the client code using the following pattern: + * @code + + ComPtr<ISomething> component; + + // ... + + com::SafeArray<LONG> in(3); + in[0] = -1; + in[1] = -2; + in[2] = -3; + + com::SafeArray<LONG> out; + com::SafeArray<LONG> ret; + + HRESULT rc = component->TestArrays(ComSafeArrayAsInParam(in), + ComSafeArrayAsOutParam(out), + ComSafeArrayAsOutParam(ret)); + + if (SUCCEEDED(rc)) + for (size_t i = 0; i < ret.size(); ++ i) + printf("*** ret[%u]=%d\n", i, ret[i]); + + * @endcode + * + * For interoperability with standard C++ containers, there is a template + * constructor that takes such a container as argument and performs a deep copy + * of its contents. This can be used in method implementations like this: + * @code + + STDMETHODIMP Component::COMGETTER(Values)(ComSafeArrayOut(int, aValues)) + { + // ... assume there is a |std::list<int> mValues| data member + + com::SafeArray<int> values(mValues); + values.detachTo(ComSafeArrayOutArg(aValues)); + + return S_OK; + } + + * @endcode + * + * The current implementation of the SafeArray layer supports all types normally + * allowed in XIDL as array element types (including 'wstring' and 'uuid'). + * However, 'pointer-to-...' types (e.g. 'long *', 'wstring *') are not + * supported and therefore cannot be used as element types. + * + * Note that for GUID arrays you should use SafeGUIDArray and + * SafeConstGUIDArray, customized SafeArray<> specializations. + * + * Also note that in order to pass input BSTR array parameters declared + * using the ComSafeArrayIn(IN_BSTR, aParam) macro to the SafeArray<> + * constructor using the ComSafeArrayInArg() macro, you should use IN_BSTR + * as the SafeArray<> template argument, not just BSTR. + * + * Arrays of interface pointers are also supported but they require to use a + * special SafeArray implementation, com::SafeIfacePointer, which takes the + * interface class name as a template argument (e.g. + * com::SafeIfacePointer\<IUnknown\>). This implementation functions + * identically to com::SafeArray. + */ + +#ifdef VBOX_WITH_XPCOM +# include <nsMemory.h> +#endif + +#include "VBox/com/defs.h" + +#if RT_GNUC_PREREQ(4, 6) || (defined(_MSC_VER) && (_MSC_VER >= 1600)) +/** @def VBOX_WITH_TYPE_TRAITS + * Type traits are a C++ 11 feature, so not available everywhere (yet). + * Only GCC 4.6 or newer and MSVC++ 16.0 (Visual Studio 2010) or newer. + */ +# define VBOX_WITH_TYPE_TRAITS +#endif + +#ifdef VBOX_WITH_TYPE_TRAITS +# include <type_traits> +#endif + +#include "VBox/com/ptr.h" +#include "VBox/com/assert.h" +#include "iprt/cpp/list.h" + +/** @def ComSafeArrayAsInParam + * Wraps the given com::SafeArray instance to generate an expression that is + * suitable for passing it to functions that take input safearray parameters + * declared using the ComSafeArrayIn macro. + * + * @param aArray com::SafeArray instance to pass as an input parameter. + */ + +/** @def ComSafeArrayAsOutParam + * Wraps the given com::SafeArray instance to generate an expression that is + * suitable for passing it to functions that take output safearray parameters + * declared using the ComSafeArrayOut macro. + * + * @param aArray com::SafeArray instance to pass as an output parameter. + */ + +/** @def ComSafeArrayNullInParam + * Helper for passing a NULL array parameter to a COM / XPCOM method. + */ + +#ifdef VBOX_WITH_XPCOM + +# define ComSafeArrayAsInParam(aArray) \ + (PRUint32)(aArray).size(), (aArray).__asInParam_Arr((aArray).raw()) + +# define ComSafeArrayAsOutParam(aArray) \ + (aArray).__asOutParam_Size(), (aArray).__asOutParam_Arr() + +# define ComSafeArrayNullInParam() 0, NULL + +#else /* !VBOX_WITH_XPCOM */ + +# define ComSafeArrayAsInParam(aArray) (aArray).__asInParam() + +# define ComSafeArrayAsOutParam(aArray) (aArray).__asOutParam() + +# define ComSafeArrayNullInParam() (NULL) + +#endif /* !VBOX_WITH_XPCOM */ + +/** + * + */ +namespace com +{ + +/** Used for dummy element access in com::SafeArray, avoiding crashes. */ +extern const char Zeroes[16]; + + +#ifdef VBOX_WITH_XPCOM + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Provides various helpers for SafeArray. + * + * @param T Type of array elements. + */ +template<typename T> +struct SafeArrayTraits +{ +protected: + + /** Initializes memory for aElem. */ + static void Init(T &aElem) { aElem = (T)0; } + + /** Initializes memory occupied by aElem. */ + static void Uninit(T &aElem) { RT_NOREF(aElem); } + + /** Creates a deep copy of aFrom and stores it in aTo. */ + static void Copy(const T &aFrom, T &aTo) { aTo = aFrom; } + +public: + + /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard (that + * in particular forbid casts of 'char **' to 'const char **'). Then initial + * reason for this magic is that XPIDL declares input strings + * (char/PRUnichar pointers) as const but doesn't do so for pointers to + * arrays. */ + static T *__asInParam_Arr(T *aArr) { return aArr; } + static T *__asInParam_Arr(const T *aArr) { return const_cast<T *>(aArr); } +}; + +template<typename T> +struct SafeArrayTraits<T *> +{ + // Arbitrary pointers are not supported +}; + +template<> +struct SafeArrayTraits<PRUnichar *> +{ +protected: + + static void Init(PRUnichar * &aElem) { aElem = NULL; } + + static void Uninit(PRUnichar * &aElem) + { + if (aElem) + { + ::SysFreeString(aElem); + aElem = NULL; + } + } + + static void Copy(const PRUnichar * aFrom, PRUnichar * &aTo) + { + AssertCompile(sizeof(PRUnichar) == sizeof(OLECHAR)); + aTo = aFrom ? ::SysAllocString((const OLECHAR *)aFrom) : NULL; + } + +public: + + /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard */ + static const PRUnichar **__asInParam_Arr(PRUnichar **aArr) + { + return const_cast<const PRUnichar **>(aArr); + } + static const PRUnichar **__asInParam_Arr(const PRUnichar **aArr) { return aArr; } +}; + +template<> +struct SafeArrayTraits<const PRUnichar *> +{ +protected: + + static void Init(const PRUnichar * &aElem) { aElem = NULL; } + static void Uninit(const PRUnichar * &aElem) + { + if (aElem) + { + ::SysFreeString(const_cast<PRUnichar *>(aElem)); + aElem = NULL; + } + } + + static void Copy(const PRUnichar * aFrom, const PRUnichar * &aTo) + { + AssertCompile(sizeof(PRUnichar) == sizeof(OLECHAR)); + aTo = aFrom ? ::SysAllocString((const OLECHAR *)aFrom) : NULL; + } + +public: + + /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard */ + static const PRUnichar **__asInParam_Arr(const PRUnichar **aArr) { return aArr; } +}; + +template<> +struct SafeArrayTraits<nsID *> +{ +protected: + + static void Init(nsID * &aElem) { aElem = NULL; } + + static void Uninit(nsID * &aElem) + { + if (aElem) + { + ::nsMemory::Free(aElem); + aElem = NULL; + } + } + + static void Copy(const nsID * aFrom, nsID * &aTo) + { + if (aFrom) + { + aTo = (nsID *) ::nsMemory::Alloc(sizeof(nsID)); + if (aTo) + *aTo = *aFrom; + } + else + aTo = NULL; + } + + /* This specification is also reused for SafeConstGUIDArray, so provide a + * no-op Init() and Uninit() which are necessary for SafeArray<> but should + * be never called in context of SafeConstGUIDArray. */ + + static void Init(const nsID * &aElem) { NOREF(aElem); AssertFailed(); } + static void Uninit(const nsID * &aElem) { NOREF(aElem); AssertFailed(); } + +public: + + /** Magic to workaround strict rules of par. 4.4.4 of the C++ standard. */ + static const nsID **__asInParam_Arr(nsID **aArr) + { + return const_cast<const nsID **>(aArr); + } + static const nsID **__asInParam_Arr(const nsID **aArr) { return aArr; } +}; + +#else /* !VBOX_WITH_XPCOM */ + +//////////////////////////////////////////////////////////////////////////////// + +struct SafeArrayTraitsBase +{ +protected: + + static SAFEARRAY *CreateSafeArray(VARTYPE aVarType, SAFEARRAYBOUND *aBound) + { return SafeArrayCreate(aVarType, 1, aBound); } +}; + +/** + * Provides various helpers for SafeArray. + * + * @param T Type of array elements. + * + * Specializations of this template must provide the following methods: + * + // Returns the VARTYPE of COM SafeArray elements to be used for T + static VARTYPE VarType(); + + // Returns the number of VarType() elements necessary for aSize + // elements of T + static ULONG VarCount(size_t aSize); + + // Returns the number of elements of T that fit into the given number of + // VarType() elements (opposite to VarCount(size_t aSize)). + static size_t Size(ULONG aVarCount); + + // Creates a deep copy of aFrom and stores it in aTo + static void Copy(ULONG aFrom, ULONG &aTo); + */ +template<typename T> +struct SafeArrayTraits : public SafeArrayTraitsBase +{ +protected: + + // Arbitrary types are treated as passed by value and each value is + // represented by a number of VT_Ix type elements where VT_Ix has the + // biggest possible bitness necessary to represent T w/o a gap. COM enums + // fall into this category. + + static VARTYPE VarType() + { +#ifdef VBOX_WITH_TYPE_TRAITS + if ( std::is_integral<T>::value + && !std::is_signed<T>::value) + { + if (sizeof(T) % 8 == 0) return VT_UI8; + if (sizeof(T) % 4 == 0) return VT_UI4; + if (sizeof(T) % 2 == 0) return VT_UI2; + return VT_UI1; + } +#endif + if (sizeof(T) % 8 == 0) return VT_I8; + if (sizeof(T) % 4 == 0) return VT_I4; + if (sizeof(T) % 2 == 0) return VT_I2; + return VT_I1; + } + + /* + * Fallback method in case type traits (VBOX_WITH_TYPE_TRAITS) + * are not available. Always returns unsigned types. + */ + static VARTYPE VarTypeUnsigned() + { + if (sizeof(T) % 8 == 0) return VT_UI8; + if (sizeof(T) % 4 == 0) return VT_UI4; + if (sizeof(T) % 2 == 0) return VT_UI2; + return VT_UI1; + } + + static ULONG VarCount(size_t aSize) + { + if (sizeof(T) % 8 == 0) return (ULONG)((sizeof(T) / 8) * aSize); + if (sizeof(T) % 4 == 0) return (ULONG)((sizeof(T) / 4) * aSize); + if (sizeof(T) % 2 == 0) return (ULONG)((sizeof(T) / 2) * aSize); + return (ULONG)(sizeof(T) * aSize); + } + + static size_t Size(ULONG aVarCount) + { + if (sizeof(T) % 8 == 0) return (size_t)(aVarCount * 8) / sizeof(T); + if (sizeof(T) % 4 == 0) return (size_t)(aVarCount * 4) / sizeof(T); + if (sizeof(T) % 2 == 0) return (size_t)(aVarCount * 2) / sizeof(T); + return (size_t) aVarCount / sizeof(T); + } + + static void Copy(T aFrom, T &aTo) { aTo = aFrom; } +}; + +template<typename T> +struct SafeArrayTraits<T *> +{ + // Arbitrary pointer types are not supported +}; + +/* Although the generic SafeArrayTraits template would work for all integers, + * we specialize it for some of them in order to use the correct VT_ type */ + +template<> +struct SafeArrayTraits<LONG> : public SafeArrayTraitsBase +{ +protected: + + static VARTYPE VarType() { return VT_I4; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(LONG aFrom, LONG &aTo) { aTo = aFrom; } +}; + +template<> +struct SafeArrayTraits<ULONG> : public SafeArrayTraitsBase +{ +protected: + + static VARTYPE VarType() { return VT_UI4; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(ULONG aFrom, ULONG &aTo) { aTo = aFrom; } +}; + +template<> +struct SafeArrayTraits<LONG64> : public SafeArrayTraitsBase +{ +protected: + + static VARTYPE VarType() { return VT_I8; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(LONG64 aFrom, LONG64 &aTo) { aTo = aFrom; } +}; + +template<> +struct SafeArrayTraits<ULONG64> : public SafeArrayTraitsBase +{ +protected: + + static VARTYPE VarType() { return VT_UI8; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(ULONG64 aFrom, ULONG64 &aTo) { aTo = aFrom; } +}; + +template<> +struct SafeArrayTraits<BSTR> : public SafeArrayTraitsBase +{ +protected: + + static VARTYPE VarType() { return VT_BSTR; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(BSTR aFrom, BSTR &aTo) + { + aTo = aFrom ? ::SysAllocString((const OLECHAR *)aFrom) : NULL; + } +}; + +template<> +struct SafeArrayTraits<GUID> : public SafeArrayTraitsBase +{ +protected: + + /* Use the 64-bit unsigned integer type for GUID */ + static VARTYPE VarType() { return VT_UI8; } + + /* GUID is 128 bit, so we need two VT_UI8 */ + static ULONG VarCount(size_t aSize) + { + AssertCompileSize(GUID, 16); + return (ULONG)(aSize * 2); + } + + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount / 2; } + + static void Copy(GUID aFrom, GUID &aTo) { aTo = aFrom; } +}; + +/** + * Helper for SafeArray::__asOutParam() that automatically updates m.raw after a + * non-NULL m.arr assignment. + */ +class OutSafeArrayDipper +{ + OutSafeArrayDipper(SAFEARRAY **aArr, void **aRaw) + : arr(aArr), raw(aRaw) { Assert(*aArr == NULL && *aRaw == NULL); } + + SAFEARRAY **arr; + void **raw; + + template<class, class> friend class SafeArray; + +public: + + ~OutSafeArrayDipper() + { + if (*arr != NULL) + { + HRESULT rc = SafeArrayAccessData(*arr, raw); + AssertComRC(rc); + } + } + + operator SAFEARRAY **() { return arr; } +}; + +#endif /* !VBOX_WITH_XPCOM */ + +//////////////////////////////////////////////////////////////////////////////// + +/** + * The SafeArray class represents the safe array type used in COM to pass arrays + * to/from interface methods. + * + * This helper class hides all MSCOM/XPCOM specific implementation details and, + * together with ComSafeArrayIn, ComSafeArrayOut and ComSafeArrayRet macros, + * provides a platform-neutral way to handle safe arrays in the method + * implementation. + * + * When an instance of this class is destroyed, it automatically frees all + * resources occupied by individual elements of the array as well as by the + * array itself. However, when the value of an element is manually changed + * using #operator[] or by accessing array data through the #raw() pointer, it is + * the caller's responsibility to free resources occupied by the previous + * element's value. + * + * Also, objects of this class do not support copy and assignment operations and + * therefore cannot be returned from functions by value. In other words, this + * class is just a temporary storage for handling interface method calls and not + * intended to be used to store arrays as data members and such -- you should + * use normal list/vector classes for that. + * + * @note The current implementation supports only one-dimensional arrays. + * + * @note This class is not thread-safe. + */ +template<typename T, class Traits = SafeArrayTraits<T> > +class SafeArray : public Traits +{ +public: + + /** + * Creates a null array. + */ + SafeArray() { } + + /** + * Creates a new array of the given size. All elements of the newly created + * array initialized with null values. + * + * @param aSize Initial number of elements in the array. + * + * @note If this object remains null after construction it means that there + * was not enough memory for creating an array of the requested size. + * The constructor will also assert in this case. + */ + SafeArray(size_t aSize) { resize(aSize); } + + /** + * Weakly attaches this instance to the existing array passed in a method + * parameter declared using the ComSafeArrayIn macro. When using this call, + * always wrap the parameter name in the ComSafeArrayInArg macro call like + * this: + * <pre> + * SafeArray safeArray(ComSafeArrayInArg(aArg)); + * </pre> + * + * Note that this constructor doesn't take the ownership of the array. In + * particular, it means that operations that operate on the ownership (e.g. + * #detachTo()) are forbidden and will assert. + * + * @param aArg Input method parameter to attach to. + */ + SafeArray(ComSafeArrayIn(T, aArg)) + { + if (aArg) + { +#ifdef VBOX_WITH_XPCOM + + m.size = aArgSize; + m.arr = aArg; + m.isWeak = true; + +#else /* !VBOX_WITH_XPCOM */ + + SAFEARRAY *arg = aArg; + + AssertReturnVoid(arg->cDims == 1); + + VARTYPE vt; + HRESULT rc = SafeArrayGetVartype(arg, &vt); + AssertComRCReturnVoid(rc); +# ifndef VBOX_WITH_TYPE_TRAITS + AssertMsgReturnVoid( + vt == VarType() + || vt == VarTypeUnsigned(), + ("Expected vartype %d or %d, got %d.\n", + VarType(), VarTypeUnsigned(), vt)); +# else /* !VBOX_WITH_TYPE_TRAITS */ + AssertMsgReturnVoid( + vt == VarType(), + ("Expected vartype %d, got %d.\n", + VarType(), vt)); +# endif + rc = SafeArrayAccessData(arg, (void HUGEP **)&m.raw); + AssertComRCReturnVoid(rc); + + m.arr = arg; + m.isWeak = true; + +#endif /* !VBOX_WITH_XPCOM */ + } + } + + /** + * Creates a deep copy of the given standard C++ container that stores + * T objects. + * + * @param aCntr Container object to copy. + * + * @tparam C Standard C++ container template class (normally deduced from + * @c aCntr). + */ + template<template<typename, typename> class C, class A> + SafeArray(const C<T, A> & aCntr) + { + resize(aCntr.size()); + AssertReturnVoid(!isNull()); + + size_t i = 0; + for (typename C<T, A>::const_iterator it = aCntr.begin(); + it != aCntr.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + SafeArray::Copy(*it, m.arr[i]); +#else + Copy(*it, m.raw[i]); +#endif + } + + /** + * Creates a deep copy of the given standard C++ map that stores T objects + * as values. + * + * @param aMap Map object to copy. + * + * @tparam C Standard C++ map template class (normally deduced from + * @a aMap). + * @tparam L Standard C++ compare class (deduced from @a aMap). + * @tparam A Standard C++ allocator class (deduced from @a aMap). + * @tparam K Map key class (deduced from @a aMap). + */ + template<template<typename, typename, typename, typename> + class C, class L, class A, class K> + SafeArray(const C<K, T, L, A> & aMap) + { + typedef C<K, T, L, A> Map; + + resize(aMap.size()); + AssertReturnVoid(!isNull()); + + size_t i = 0; + for (typename Map::const_iterator it = aMap.begin(); + it != aMap.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + Copy(it->second, m.arr[i]); +#else + Copy(it->second, m.raw[i]); +#endif + } + + /** + * Destroys this instance after calling #setNull() to release allocated + * resources. See #setNull() for more details. + */ + virtual ~SafeArray() { setNull(); } + + /** + * Returns @c true if this instance represents a null array. + */ + bool isNull() const { return m.arr == NULL; } + + /** + * Returns @c true if this instance does not represents a null array. + */ + bool isNotNull() const { return m.arr != NULL; } + + /** + * Resets this instance to null and, if this instance is not a weak one, + * releases any resources occupied by the array data. + * + * @note This method destroys (cleans up) all elements of the array using + * the corresponding cleanup routine for the element type before the + * array itself is destroyed. + */ + virtual void setNull() { m.uninit(); } + + /** + * Returns @c true if this instance is weak. A weak instance doesn't own the + * array data and therefore operations manipulating the ownership (e.g. + * #detachTo()) are forbidden and will assert. + */ + bool isWeak() const { return m.isWeak; } + + /** Number of elements in the array. */ + size_t size() const + { +#ifdef VBOX_WITH_XPCOM + if (m.arr) + return m.size; + return 0; +#else + if (m.arr) + return Size(m.arr->rgsabound[0].cElements); + return 0; +#endif + } + + /** + * Appends a copy of the given element at the end of the array. + * + * The array size is increased by one by this method and the additional + * space is allocated as needed. + * + * This method is handy in cases where you want to assign a copy of the + * existing value to the array element, for example: + * <tt>Bstr string; array.push_back(string);</tt>. If you create a string + * just to put it in the array, you may find #appendedRaw() more useful. + * + * @param aElement Element to append. + * + * @return @c true on success and @c false if there is not enough + * memory for resizing. + */ + bool push_back(const T &aElement) + { + if (!ensureCapacity(size() + 1)) + return false; + +#ifdef VBOX_WITH_XPCOM + SafeArray::Copy(aElement, m.arr[m.size]); + ++ m.size; +#else + Copy(aElement, m.raw[size() - 1]); +#endif + return true; + } + + /** + * Appends an empty element at the end of the array and returns a raw + * pointer to it suitable for assigning a raw value (w/o constructing a + * copy). + * + * The array size is increased by one by this method and the additional + * space is allocated as needed. + * + * Note that in case of raw assignment, value ownership (for types with + * dynamically allocated data and for interface pointers) is transferred to + * the safe array object. + * + * This method is handy for operations like + * <tt>Bstr("foo").detachTo(array.appendedRaw());</tt>. Don't use it as + * an l-value (<tt>array.appendedRaw() = SysAllocString(L"tralala");</tt>) + * since this doesn't check for a NULL condition; use #resize() instead. If + * you need to assign a copy of the existing value instead of transferring + * the ownership, look at #push_back(). + * + * @return Raw pointer to the added element or NULL if no memory. + */ + T *appendedRaw() + { + if (!ensureCapacity(size() + 1)) + return NULL; + +#ifdef VBOX_WITH_XPCOM + SafeArray::Init(m.arr[m.size]); + ++ m.size; + return &m.arr[m.size - 1]; +#else + /* nothing to do here, SafeArrayCreate() has performed element + * initialization */ + return &m.raw[size() - 1]; +#endif + } + + /** + * Resizes the array preserving its contents when possible. If the new size + * is larger than the old size, new elements are initialized with null + * values. If the new size is less than the old size, the contents of the + * array beyond the new size is lost. + * + * @param aNewSize New number of elements in the array. + * @return @c true on success and @c false if there is not enough + * memory for resizing. + */ + bool resize(size_t aNewSize) + { + if (!ensureCapacity(aNewSize)) + return false; + +#ifdef VBOX_WITH_XPCOM + + if (m.size < aNewSize) + { + /* initialize the new elements */ + for (size_t i = m.size; i < aNewSize; ++ i) + SafeArray::Init(m.arr[i]); + } + + /** @todo Fix this! */ + m.size = (PRUint32)aNewSize; +#else + /* nothing to do here, SafeArrayCreate() has performed element + * initialization */ +#endif + return true; + } + + /** + * Reinitializes this instance by preallocating space for the given number + * of elements. The previous array contents is lost. + * + * @param aNewSize New number of elements in the array. + * @return @c true on success and @c false if there is not enough + * memory for resizing. + */ + bool reset(size_t aNewSize) + { + m.uninit(); + return resize(aNewSize); + } + + /** + * Returns a pointer to the raw array data. Use this raw pointer with care + * as no type or bound checking is done for you in this case. + * + * @note This method returns @c NULL when this instance is null. + * @see #operator[] + */ + T *raw() + { +#ifdef VBOX_WITH_XPCOM + return m.arr; +#else + return m.raw; +#endif + } + + /** + * Const version of #raw(). + */ + const T *raw() const + { +#ifdef VBOX_WITH_XPCOM + return m.arr; +#else + return m.raw; +#endif + } + + /** + * Array access operator that returns an array element by reference. A bit + * safer than #raw(): asserts and returns a reference to a static zero + * element (const, i.e. writes will fail) if this instance is null or + * if the index is out of bounds. + * + * @note For weak instances, this call will succeed but the behavior of + * changing the contents of an element of the weak array instance is + * undefined and may lead to a program crash on some platforms. + */ + T &operator[] (size_t aIdx) + { + /** @todo r=klaus should do this as a AssertCompile, but cannot find a way which works. */ + Assert(sizeof(T) <= sizeof(Zeroes)); + AssertReturn(m.arr != NULL, *(T *)&Zeroes[0]); + AssertReturn(aIdx < size(), *(T *)&Zeroes[0]); +#ifdef VBOX_WITH_XPCOM + return m.arr[aIdx]; +#else + AssertReturn(m.raw != NULL, *(T *)&Zeroes[0]); + return m.raw[aIdx]; +#endif + } + + /** + * Const version of #operator[] that returns an array element by value. + */ + const T operator[] (size_t aIdx) const + { + AssertReturn(m.arr != NULL, *(const T *)&Zeroes[0]); + AssertReturn(aIdx < size(), *(const T *)&Zeroes[0]); +#ifdef VBOX_WITH_XPCOM + return m.arr[aIdx]; +#else + AssertReturn(m.raw != NULL, *(const T *)&Zeroes[0]); + return m.raw[aIdx]; +#endif + } + + /** + * Creates a copy of this array and stores it in a method parameter declared + * using the ComSafeArrayOut macro. When using this call, always wrap the + * parameter name in the ComSafeArrayOutArg macro call like this: + * <pre> + * safeArray.cloneTo(ComSafeArrayOutArg(aArg)); + * </pre> + * + * @note It is assumed that the ownership of the returned copy is + * transferred to the caller of the method and he is responsible to free the + * array data when it is no longer needed. + * + * @param aArg Output method parameter to clone to. + */ + virtual const SafeArray &cloneTo(ComSafeArrayOut(T, aArg)) const + { + /// @todo Implement me! +#ifdef VBOX_WITH_XPCOM + NOREF(aArgSize); + NOREF(aArg); +#else + NOREF(aArg); +#endif + AssertFailedReturn(*this); + } + + HRESULT cloneTo(SafeArray<T>& aOther) const + { + aOther.reset(size()); + return aOther.initFrom(*this); + } + + + /** + * Transfers the ownership of this array's data to the specified location + * declared using the ComSafeArrayOut macro and makes this array a null + * array. When using this call, always wrap the parameter name in the + * ComSafeArrayOutArg macro call like this: + * <pre> + * safeArray.detachTo(ComSafeArrayOutArg(aArg)); + * </pre> + * + * Detaching the null array is also possible in which case the location will + * receive NULL. + * + * @note Since the ownership of the array data is transferred to the + * caller of the method, he is responsible to free the array data when it is + * no longer needed. + * + * @param aArg Location to detach to. + */ + virtual SafeArray &detachTo(ComSafeArrayOut(T, aArg)) + { + AssertReturn(!m.isWeak, *this); + +#ifdef VBOX_WITH_XPCOM + + AssertReturn(aArgSize != NULL, *this); + AssertReturn(aArg != NULL, *this); + + *aArgSize = m.size; + *aArg = m.arr; + + m.isWeak = false; + m.size = 0; + m.arr = NULL; + +#else /* !VBOX_WITH_XPCOM */ + + AssertReturn(aArg != NULL, *this); + *aArg = m.arr; + + if (m.raw) + { + HRESULT rc = SafeArrayUnaccessData(m.arr); + AssertComRCReturn(rc, *this); + m.raw = NULL; + } + + m.isWeak = false; + m.arr = NULL; + +#endif /* !VBOX_WITH_XPCOM */ + + return *this; + } + + /** + * Returns a copy of this SafeArray as RTCList<T>. + */ + RTCList<T> toList() + { + RTCList<T> list(size()); + for (size_t i = 0; i < size(); ++i) +#ifdef VBOX_WITH_XPCOM + list.append(m.arr[i]); +#else + list.append(m.raw[i]); +#endif + return list; + } + + inline HRESULT initFrom(const com::SafeArray<T> & aRef); + inline HRESULT initFrom(const T* aPtr, size_t aSize); + + // Public methods for internal purposes only. + +#ifdef VBOX_WITH_XPCOM + + /** Internal function. Never call it directly. */ + PRUint32 *__asOutParam_Size() { setNull(); return &m.size; } + + /** Internal function Never call it directly. */ + T **__asOutParam_Arr() { Assert(isNull()); return &m.arr; } + +#else /* !VBOX_WITH_XPCOM */ + + /** Internal function Never call it directly. */ + SAFEARRAY * __asInParam() { return m.arr; } + + /** Internal function Never call it directly. */ + OutSafeArrayDipper __asOutParam() + { setNull(); return OutSafeArrayDipper(&m.arr, (void **)&m.raw); } + +#endif /* !VBOX_WITH_XPCOM */ + + static const SafeArray Null; + +protected: + + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(SafeArray); + + /** + * Ensures that the array is big enough to contain aNewSize elements. + * + * If the new size is greater than the current capacity, a new array is + * allocated and elements from the old array are copied over. The size of + * the array doesn't change, only the capacity increases (which is always + * greater than the size). Note that the additionally allocated elements are + * left uninitialized by this method. + * + * If the new size is less than the current size, the existing array is + * truncated to the specified size and the elements outside the new array + * boundary are freed. + * + * If the new size is the same as the current size, nothing happens. + * + * @param aNewSize New size of the array. + * + * @return @c true on success and @c false if not enough memory. + */ + bool ensureCapacity(size_t aNewSize) + { + AssertReturn(!m.isWeak, false); + +#ifdef VBOX_WITH_XPCOM + + /* Note: we distinguish between a null array and an empty (zero + * elements) array. Therefore we never use zero in malloc (even if + * aNewSize is zero) to make sure we get a non-null pointer. */ + + if (m.size == aNewSize && m.arr != NULL) + return true; + + /* Allocate in 16-byte pieces. */ + size_t newCapacity = RT_MAX((aNewSize + 15) / 16 * 16, 16); + + if (m.capacity != newCapacity) + { + T *newArr = (T *)nsMemory::Alloc(RT_MAX(newCapacity, 1) * sizeof(T)); + AssertReturn(newArr != NULL, false); + + if (m.arr != NULL) + { + if (m.size > aNewSize) + { + /* Truncation takes place, uninit exceeding elements and + * shrink the size. */ + for (size_t i = aNewSize; i < m.size; ++ i) + SafeArray::Uninit(m.arr[i]); + + /** @todo Fix this! */ + m.size = (PRUint32)aNewSize; + } + + /* Copy the old contents. */ + memcpy(newArr, m.arr, m.size * sizeof(T)); + nsMemory::Free((void *)m.arr); + } + + m.arr = newArr; + } + else + { + if (m.size > aNewSize) + { + /* Truncation takes place, uninit exceeding elements and + * shrink the size. */ + for (size_t i = aNewSize; i < m.size; ++ i) + SafeArray::Uninit(m.arr[i]); + + /** @todo Fix this! */ + m.size = (PRUint32)aNewSize; + } + } + + /** @todo Fix this! */ + m.capacity = (PRUint32)newCapacity; + +#else + + SAFEARRAYBOUND bound = { VarCount(aNewSize), 0 }; + HRESULT rc; + + if (m.arr == NULL) + { + m.arr = CreateSafeArray(VarType(), &bound); + AssertReturn(m.arr != NULL, false); + } + else + { + SafeArrayUnaccessData(m.arr); + + rc = SafeArrayRedim(m.arr, &bound); + AssertComRCReturn(rc == S_OK, false); + } + + rc = SafeArrayAccessData(m.arr, (void HUGEP **)&m.raw); + AssertComRCReturn(rc, false); + +#endif + return true; + } + + struct Data + { + Data() + : isWeak(false) +#ifdef VBOX_WITH_XPCOM + , capacity(0), size(0), arr(NULL) +#else + , arr(NULL), raw(NULL) +#endif + {} + + ~Data() { uninit(); } + + void uninit() + { +#ifdef VBOX_WITH_XPCOM + + if (arr) + { + if (!isWeak) + { + for (size_t i = 0; i < size; ++ i) + SafeArray::Uninit(arr[i]); + + nsMemory::Free((void *)arr); + } + else + isWeak = false; + + arr = NULL; + } + + size = capacity = 0; + +#else /* !VBOX_WITH_XPCOM */ + + if (arr) + { + if (raw) + { + SafeArrayUnaccessData(arr); + raw = NULL; + } + + if (!isWeak) + { + HRESULT rc = SafeArrayDestroy(arr); + AssertComRCReturnVoid(rc); + } + else + isWeak = false; + + arr = NULL; + } + +#endif /* !VBOX_WITH_XPCOM */ + } + + bool isWeak : 1; + +#ifdef VBOX_WITH_XPCOM + PRUint32 capacity; + PRUint32 size; + T *arr; +#else + SAFEARRAY *arr; + T *raw; +#endif + }; + + Data m; +}; + +/* Few fast specializations for primitive array types */ +template<> +inline HRESULT com::SafeArray<BYTE>::initFrom(const com::SafeArray<BYTE> & aRef) +{ + size_t sSize = aRef.size(); + if (resize(sSize)) + { + ::memcpy(raw(), aRef.raw(), sSize); + return S_OK; + } + return E_OUTOFMEMORY; +} +template<> +inline HRESULT com::SafeArray<BYTE>::initFrom(const BYTE *aPtr, size_t aSize) +{ + if (resize(aSize)) + { + ::memcpy(raw(), aPtr, aSize); + return S_OK; + } + return E_OUTOFMEMORY; +} + + +template<> +inline HRESULT com::SafeArray<SHORT>::initFrom(const com::SafeArray<SHORT> & aRef) +{ + size_t sSize = aRef.size(); + if (resize(sSize)) + { + ::memcpy(raw(), aRef.raw(), sSize * sizeof(SHORT)); + return S_OK; + } + return E_OUTOFMEMORY; +} +template<> +inline HRESULT com::SafeArray<SHORT>::initFrom(const SHORT *aPtr, size_t aSize) +{ + if (resize(aSize)) + { + ::memcpy(raw(), aPtr, aSize * sizeof(SHORT)); + return S_OK; + } + return E_OUTOFMEMORY; +} + +template<> +inline HRESULT com::SafeArray<USHORT>::initFrom(const com::SafeArray<USHORT> & aRef) +{ + size_t sSize = aRef.size(); + if (resize(sSize)) + { + ::memcpy(raw(), aRef.raw(), sSize * sizeof(USHORT)); + return S_OK; + } + return E_OUTOFMEMORY; +} +template<> +inline HRESULT com::SafeArray<USHORT>::initFrom(const USHORT *aPtr, size_t aSize) +{ + if (resize(aSize)) + { + ::memcpy(raw(), aPtr, aSize * sizeof(USHORT)); + return S_OK; + } + return E_OUTOFMEMORY; +} + +template<> +inline HRESULT com::SafeArray<LONG>::initFrom(const com::SafeArray<LONG> & aRef) +{ + size_t sSize = aRef.size(); + if (resize(sSize)) + { + ::memcpy(raw(), aRef.raw(), sSize * sizeof(LONG)); + return S_OK; + } + return E_OUTOFMEMORY; +} +template<> +inline HRESULT com::SafeArray<LONG>::initFrom(const LONG *aPtr, size_t aSize) +{ + if (resize(aSize)) + { + ::memcpy(raw(), aPtr, aSize * sizeof(LONG)); + return S_OK; + } + return E_OUTOFMEMORY; +} + + +//////////////////////////////////////////////////////////////////////////////// + +#ifdef VBOX_WITH_XPCOM + +/** + * Version of com::SafeArray for arrays of GUID. + * + * In MS COM, GUID arrays store GUIDs by value and therefore input arrays are + * represented using |GUID *| and out arrays -- using |GUID **|. In XPCOM, + * GUID arrays store pointers to nsID so that input arrays are |const nsID **| + * and out arrays are |nsID ***|. Due to this difference, it is impossible to + * work with arrays of GUID on both platforms by simply using com::SafeArray + * <GUID>. This class is intended to provide some level of cross-platform + * behavior. + * + * The basic usage pattern is basically similar to com::SafeArray<> except that + * you use ComSafeGUIDArrayIn* and ComSafeGUIDArrayOut* macros instead of + * ComSafeArrayIn* and ComSafeArrayOut*. Another important nuance is that the + * raw() array type is different (nsID **, or GUID ** on XPCOM and GUID * on MS + * COM) so it is recommended to use operator[] instead which always returns a + * GUID by value. + * + * Note that due to const modifiers, you cannot use SafeGUIDArray for input GUID + * arrays. Please use SafeConstGUIDArray for this instead. + * + * Other than mentioned above, the functionality of this class is equivalent to + * com::SafeArray<>. See the description of that template and its methods for + * more information. + * + * Output GUID arrays are handled by a separate class, SafeGUIDArrayOut, since + * this class cannot handle them because of const modifiers. + */ +class SafeGUIDArray : public SafeArray<nsID *> +{ +public: + + typedef SafeArray<nsID *> Base; + + class nsIDRef + { + public: + + nsIDRef(nsID * &aVal) : mVal(aVal) { AssertCompile(sizeof(nsID) <= sizeof(Zeroes)); } + + operator const nsID &() const { return mVal ? *mVal : *(const nsID *)&Zeroes[0]; } + operator nsID() const { return mVal ? *mVal : *(nsID *)&Zeroes[0]; } + + const nsID *operator&() const { return mVal ? mVal : (const nsID *)&Zeroes[0]; } + + nsIDRef &operator= (const nsID &aThat) + { + if (mVal == NULL) + Copy(&aThat, mVal); + else + *mVal = aThat; + return *this; + } + + private: + + nsID * &mVal; + + friend class SafeGUIDArray; + }; + + /** See SafeArray<>::SafeArray(). */ + SafeGUIDArray() {} + + /** See SafeArray<>::SafeArray(size_t). */ + SafeGUIDArray(size_t aSize) : Base(aSize) {} + + /** + * Array access operator that returns an array element by reference. As a + * special case, the return value of this operator on XPCOM is an nsID (GUID) + * reference, instead of an nsID pointer (the actual SafeArray template + * argument), for compatibility with the MS COM version. + * + * The rest is equivalent to SafeArray<>::operator[]. + */ + nsIDRef operator[] (size_t aIdx) + { + Assert(m.arr != NULL); + Assert(aIdx < size()); + return nsIDRef(m.arr[aIdx]); + } + + /** + * Const version of #operator[] that returns an array element by value. + */ + const nsID &operator[] (size_t aIdx) const + { + Assert(m.arr != NULL); + Assert(aIdx < size()); + return m.arr[aIdx] ? *m.arr[aIdx] : *(const nsID *)&Zeroes[0]; + } +}; + +/** + * Version of com::SafeArray for const arrays of GUID. + * + * This class is used to work with input GUID array parameters in method + * implementations. See SafeGUIDArray for more details. + */ +class SafeConstGUIDArray : public SafeArray<const nsID *, + SafeArrayTraits<nsID *> > +{ +public: + + typedef SafeArray<const nsID *, SafeArrayTraits<nsID *> > Base; + + /** See SafeArray<>::SafeArray(). */ + SafeConstGUIDArray() { AssertCompile(sizeof(nsID) <= sizeof(Zeroes)); } + + /* See SafeArray<>::SafeArray(ComSafeArrayIn(T, aArg)). */ + SafeConstGUIDArray(ComSafeGUIDArrayIn(aArg)) + : Base(ComSafeGUIDArrayInArg(aArg)) {} + + /** + * Array access operator that returns an array element by reference. As a + * special case, the return value of this operator on XPCOM is nsID (GUID) + * instead of nsID *, for compatibility with the MS COM version. + * + * The rest is equivalent to SafeArray<>::operator[]. + */ + const nsID &operator[] (size_t aIdx) const + { + AssertReturn(m.arr != NULL, *(const nsID *)&Zeroes[0]); + AssertReturn(aIdx < size(), *(const nsID *)&Zeroes[0]); + return *m.arr[aIdx]; + } + +private: + + /* These are disabled because of const. */ + bool reset(size_t aNewSize) { NOREF(aNewSize); return false; } +}; + +#else /* !VBOX_WITH_XPCOM */ + +typedef SafeArray<GUID> SafeGUIDArray; +typedef SafeArray<const GUID, SafeArrayTraits<GUID> > SafeConstGUIDArray; + +#endif /* !VBOX_WITH_XPCOM */ + +//////////////////////////////////////////////////////////////////////////////// + +#ifdef VBOX_WITH_XPCOM + +template<class I> +struct SafeIfaceArrayTraits +{ +protected: + + static void Init(I * &aElem) { aElem = NULL; } + static void Uninit(I * &aElem) + { + if (aElem) + { + aElem->Release(); + aElem = NULL; + } + } + + static void Copy(I * aFrom, I * &aTo) + { + if (aFrom != NULL) + { + aTo = aFrom; + aTo->AddRef(); + } + else + aTo = NULL; + } + +public: + + /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard. */ + static I **__asInParam_Arr(I **aArr) { return aArr; } + static I **__asInParam_Arr(const I **aArr) { return const_cast<I **>(aArr); } +}; + +#else /* !VBOX_WITH_XPCOM */ + +template<class I> +struct SafeIfaceArrayTraits +{ +protected: + + static VARTYPE VarType() { return VT_DISPATCH; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(I * aFrom, I * &aTo) + { + if (aFrom != NULL) + { + aTo = aFrom; + aTo->AddRef(); + } + else + aTo = NULL; + } + + static SAFEARRAY *CreateSafeArray(VARTYPE aVarType, SAFEARRAYBOUND *aBound) + { + NOREF(aVarType); + return SafeArrayCreateEx(VT_DISPATCH, 1, aBound, (PVOID)&COM_IIDOF(I)); + } +}; + +#endif /* !VBOX_WITH_XPCOM */ + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Version of com::SafeArray for arrays of interface pointers. + * + * Except that it manages arrays of interface pointers, the usage of this class + * is identical to com::SafeArray. + * + * @param I Interface class (no asterisk). + */ +template<class I> +class SafeIfaceArray : public SafeArray<I *, SafeIfaceArrayTraits<I> > +{ +public: + + typedef SafeArray<I *, SafeIfaceArrayTraits<I> > Base; + + /** + * Creates a null array. + */ + SafeIfaceArray() {} + + /** + * Creates a new array of the given size. All elements of the newly created + * array initialized with null values. + * + * @param aSize Initial number of elements in the array. Must be greater + * than 0. + * + * @note If this object remains null after construction it means that there + * was not enough memory for creating an array of the requested size. + * The constructor will also assert in this case. + */ + SafeIfaceArray(size_t aSize) { Base::resize(aSize); } + + /** + * Weakly attaches this instance to the existing array passed in a method + * parameter declared using the ComSafeArrayIn macro. When using this call, + * always wrap the parameter name in the ComSafeArrayOutArg macro call like + * this: + * <pre> + * SafeArray safeArray(ComSafeArrayInArg(aArg)); + * </pre> + * + * Note that this constructor doesn't take the ownership of the array. In + * particular, this means that operations that operate on the ownership + * (e.g. #detachTo()) are forbidden and will assert. + * + * @param aArg Input method parameter to attach to. + */ + SafeIfaceArray(ComSafeArrayIn(I *, aArg)) + { + if (aArg) + { +#ifdef VBOX_WITH_XPCOM + + Base::m.size = aArgSize; + Base::m.arr = aArg; + Base::m.isWeak = true; + +#else /* !VBOX_WITH_XPCOM */ + + SAFEARRAY *arg = aArg; + + AssertReturnVoid(arg->cDims == 1); + + VARTYPE vt; + HRESULT rc = SafeArrayGetVartype(arg, &vt); + AssertComRCReturnVoid(rc); + AssertMsgReturnVoid(vt == VT_UNKNOWN || vt == VT_DISPATCH, + ("Expected vartype VT_UNKNOWN or VT_DISPATCH, got %d.\n", + vt)); + GUID guid; + rc = SafeArrayGetIID(arg, &guid); + AssertComRCReturnVoid(rc); + AssertMsgReturnVoid(InlineIsEqualGUID(COM_IIDOF(I), guid) || arg->rgsabound[0].cElements == 0 /* IDispatch if empty */, + ("Expected IID {%RTuuid}, got {%RTuuid}.\n", &COM_IIDOF(I), &guid)); + + rc = SafeArrayAccessData(arg, (void HUGEP **)&m.raw); + AssertComRCReturnVoid(rc); + + m.arr = arg; + m.isWeak = true; + +#endif /* !VBOX_WITH_XPCOM */ + } + } + + /** + * Creates a deep copy of the given standard C++ container that stores + * interface pointers as objects of the ComPtr\<I\> class. + * + * @param aCntr Container object to copy. + * + * @tparam C Standard C++ container template class (normally deduced from + * @c aCntr). + * @tparam A Standard C++ allocator class (deduced from @c aCntr). + * @tparam OI Argument to the ComPtr template (deduced from @c aCntr). + */ + template<template<typename, typename> class C, class A, class OI> + SafeIfaceArray(const C<ComPtr<OI>, A> & aCntr) + { + typedef C<ComPtr<OI>, A> List; + + Base::resize(aCntr.size()); + AssertReturnVoid(!Base::isNull()); + + size_t i = 0; + for (typename List::const_iterator it = aCntr.begin(); + it != aCntr.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + this->Copy(*it, Base::m.arr[i]); +#else + Copy(*it, Base::m.raw[i]); +#endif + } + + /** + * Creates a deep copy of the given standard C++ container that stores + * interface pointers as objects of the ComObjPtr\<I\> class. + * + * @param aCntr Container object to copy. + * + * @tparam C Standard C++ container template class (normally deduced from + * @c aCntr). + * @tparam A Standard C++ allocator class (deduced from @c aCntr). + * @tparam OI Argument to the ComObjPtr template (deduced from @c aCntr). + */ + template<template<typename, typename> class C, class A, class OI> + SafeIfaceArray(const C<ComObjPtr<OI>, A> & aCntr) + { + typedef C<ComObjPtr<OI>, A> List; + + Base::resize(aCntr.size()); + AssertReturnVoid(!Base::isNull()); + + size_t i = 0; + for (typename List::const_iterator it = aCntr.begin(); + it != aCntr.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + SafeIfaceArray::Copy(*it, Base::m.arr[i]); +#else + Copy(*it, Base::m.raw[i]); +#endif + } + + /** + * Creates a deep copy of the given standard C++ map whose values are + * interface pointers stored as objects of the ComPtr\<I\> class. + * + * @param aMap Map object to copy. + * + * @tparam C Standard C++ map template class (normally deduced from + * @c aCntr). + * @tparam L Standard C++ compare class (deduced from @c aCntr). + * @tparam A Standard C++ allocator class (deduced from @c aCntr). + * @tparam K Map key class (deduced from @c aCntr). + * @tparam OI Argument to the ComPtr template (deduced from @c aCntr). + */ + template<template<typename, typename, typename, typename> + class C, class L, class A, class K, class OI> + SafeIfaceArray(const C<K, ComPtr<OI>, L, A> & aMap) + { + typedef C<K, ComPtr<OI>, L, A> Map; + + Base::resize(aMap.size()); + AssertReturnVoid(!Base::isNull()); + + size_t i = 0; + for (typename Map::const_iterator it = aMap.begin(); + it != aMap.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + SafeIfaceArray::Copy(it->second, Base::m.arr[i]); +#else + Copy(it->second, Base::m.raw[i]); +#endif + } + + /** + * Creates a deep copy of the given standard C++ map whose values are + * interface pointers stored as objects of the ComObjPtr\<I\> class. + * + * @param aMap Map object to copy. + * + * @tparam C Standard C++ map template class (normally deduced from + * @c aCntr). + * @tparam L Standard C++ compare class (deduced from @c aCntr). + * @tparam A Standard C++ allocator class (deduced from @c aCntr). + * @tparam K Map key class (deduced from @c aCntr). + * @tparam OI Argument to the ComObjPtr template (deduced from @c aCntr). + */ + template<template<typename, typename, typename, typename> + class C, class L, class A, class K, class OI> + SafeIfaceArray(const C<K, ComObjPtr<OI>, L, A> & aMap) + { + typedef C<K, ComObjPtr<OI>, L, A> Map; + + Base::resize(aMap.size()); + AssertReturnVoid(!Base::isNull()); + + size_t i = 0; + for (typename Map::const_iterator it = aMap.begin(); + it != aMap.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + SafeIfaceArray::Copy(it->second, Base::m.arr[i]); +#else + Copy(it->second, Base::m.raw[i]); +#endif + } + + void setElement(size_t iIdx, I* obj) + { +#ifdef VBOX_WITH_XPCOM + SafeIfaceArray::Copy(obj, Base::m.arr[iIdx]); +#else + Copy(obj, Base::m.raw[iIdx]); +#endif + } +}; + +} /* namespace com */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_array_h */ + diff --git a/include/VBox/com/assert.h b/include/VBox/com/assert.h new file mode 100644 index 00000000..f70f474d --- /dev/null +++ b/include/VBox/com/assert.h @@ -0,0 +1,135 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - Assertion macros for COM/XPCOM. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_assert_h +#define VBOX_INCLUDED_com_assert_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assert.h> + +/** @defgroup grp_com_assert Assertion Macros for COM/XPCOM + * @ingroup grp_com + * @{ + */ + + +/** + * Asserts that the COM result code is succeeded in strict builds. + * In non-strict builds the result code will be NOREF'ed to kill compiler warnings. + * + * @param hrc The COM result code + */ +#define AssertComRC(hrc) \ + do { AssertMsg(SUCCEEDED(hrc), ("COM RC = %Rhrc (0x%08X)\n", hrc, hrc)); NOREF(hrc); } while (0) + +/** + * Same as AssertComRC, except the caller already knows we failed. + * + * @param hrc The COM result code + */ +#define AssertComRCFailed(hrc) \ + do { AssertMsgFailed(("COM RC = %Rhrc (0x%08X)\n", hrc, hrc)); NOREF(hrc); } while (0) + +/** + * A special version of AssertComRC that returns the given expression + * if the result code is failed. + * + * @param hrc The COM result code + * @param RetExpr The expression to return + */ +#define AssertComRCReturn(hrc, RetExpr) \ + AssertMsgReturn(SUCCEEDED(hrc), ("COM RC = %Rhrc (0x%08X)\n", hrc, hrc), RetExpr) + +/** + * A special version of AssertComRC that returns the given result code + * if it is failed. + * + * @param hrc The COM result code + */ +#define AssertComRCReturnRC(hrc) \ + AssertMsgReturn(SUCCEEDED(hrc), ("COM RC = %Rhrc (0x%08X)\n", hrc, hrc), hrc) + +/** + * A special version of AssertComRC that returns if the result code is failed. + * + * @param hrc The COM result code + */ +#define AssertComRCReturnVoid(hrc) \ + AssertMsgReturnVoid(SUCCEEDED(hrc), ("COM RC = %Rhrc (0x%08X)\n", hrc, hrc)) + +/** + * A special version of AssertComRC that evaluates the given expression and + * breaks if the result code is failed. + * + * @param hrc The COM result code + * @param PreBreakExpr The expression to evaluate on failure. + */ +#define AssertComRCBreak(hrc, PreBreakExpr) \ + if (!SUCCEEDED(hrc)) { AssertComRCFailed(hrc); PreBreakExpr; break; } else do {} while (0) + +/** + * A special version of AssertComRC that evaluates the given expression and + * throws it if the result code is failed. + * + * @param hrc The COM result code + * @param ThrowMeExpr The expression which result to be thrown on failure. + */ +#define AssertComRCThrow(hrc, ThrowMeExpr) \ + do { if (SUCCEEDED(hrc)) { /*likely*/} else { AssertComRCFailed(hrc); throw (ThrowMeExpr); } } while (0) + +/** + * A special version of AssertComRC that just breaks if the result code is + * failed. + * + * @param hrc The COM result code + */ +#define AssertComRCBreakRC(hrc) \ + if (!SUCCEEDED(hrc)) { AssertComRCFailed(hrc); break; } else do {} while (0) + +/** + * A special version of AssertComRC that just throws @a hrc if the result code + * is failed. + * + * @param hrc The COM result code + */ +#define AssertComRCThrowRC(hrc) \ + do { if (SUCCEEDED(hrc)) { /*likely*/ } else { AssertComRCFailed(hrc); throw hrc; } } while (0) + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_assert_h */ + diff --git a/include/VBox/com/com.h b/include/VBox/com/com.h new file mode 100644 index 00000000..946122b1 --- /dev/null +++ b/include/VBox/com/com.h @@ -0,0 +1,102 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - COM initialization / shutdown. + */ + +/* + * Copyright (C) 2005-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_com_h +#define VBOX_INCLUDED_com_com_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBox/com/defs.h" +#include "VBox/com/utils.h" + +/** @defgroup grp_com MS COM / XPCOM Abstraction Layer + * @{ + */ + +namespace com +{ + +/** @name VBOX_COM_INIT_F_XXX - flags for com::Initialize(). + * @{ */ +/** Windows: Caller is the GUI and needs a STA rather than MTA apartment. */ +#define VBOX_COM_INIT_F_GUI RT_BIT_32(0) +/** Windows: Auto registration updating, if privileged enough. */ +#define VBOX_COM_INIT_F_AUTO_REG_UPDATE RT_BIT_32(1) +/** Windows: Opt-out of COM patching (client code should do this). */ +#define VBOX_COM_INIT_F_NO_COM_PATCHING RT_BIT_32(2) +/** The default flags. */ +#define VBOX_COM_INIT_F_DEFAULT (VBOX_COM_INIT_F_AUTO_REG_UPDATE) +/** @} */ + +/** + * Initializes the COM runtime. + * + * Must be called on the main thread, before any COM activity in any thread, and by any thread + * willing to perform COM operations. + * + * @return COM result code + */ +HRESULT Initialize(uint32_t fInitFlags = VBOX_COM_INIT_F_DEFAULT); + +/** + * Shuts down the COM runtime. + * + * Must be called on the main thread before termination. + * No COM calls may be made in any thread after this method returns. + */ +HRESULT Shutdown(); + +/** + * Resolves a given interface ID to a string containing the interface name. + * + * If, for some reason, the given IID cannot be resolved to a name, a NULL + * string is returned. A non-NULL string returned by this function must be + * freed using SysFreeString(). + * + * @param aIID ID of the interface to get a name for + * @param aName Resolved interface name or @c NULL on error + */ +void GetInterfaceNameByIID(const GUID &aIID, BSTR *aName); + +#ifdef RT_OS_WINDOWS +void PatchComBugs(void); +#endif + +} /* namespace com */ + +/** @} */ +#endif /* !VBOX_INCLUDED_com_com_h */ + diff --git a/include/VBox/com/defs.h b/include/VBox/com/defs.h new file mode 100644 index 00000000..86b7b101 --- /dev/null +++ b/include/VBox/com/defs.h @@ -0,0 +1,606 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - Common Definitions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_defs_h +#define VBOX_INCLUDED_com_defs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Make sure all the stdint.h macros are included - must come first! */ +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#if defined (RT_OS_OS2) + +# if defined(RT_MAX) && RT_MAX != 22 +# undef RT_MAX +# define REDEFINE_RT_MAX +# endif +# undef RT_MAX + +/* Make sure OS/2 Toolkit headers are pulled in to have BOOL/ULONG/etc. typedefs + * already defined in order to be able to redefine them using #define. */ +# define INCL_BASE +# define INCL_PM +# include <os2.h> + +/* OS/2 Toolkit defines TRUE and FALSE */ +# undef FALSE +# undef TRUE + +/* */ +# undef RT_MAX +# ifdef REDEFINE_RT_MAX +# define RT_MAX(Value1, Value2) ( (Value1) >= (Value2) ? (Value1) : (Value2) ) +# endif + +#endif /* defined(RT_OS_OS2) */ + +/* Include iprt/types.h (which also includes iprt/types.h) now to make sure iprt + * gets to stdint.h first, otherwise a system/xpcom header might beat us and + * we'll be without the macros that are optional in C++. */ +#include <iprt/types.h> + + + +/** @defgroup grp_com_defs Common Definitions + * @ingroup grp_com + * @{ + */ + +#if !defined(VBOX_WITH_XPCOM) + +#ifdef RT_OS_WINDOWS + +// Windows COM +///////////////////////////////////////////////////////////////////////////// + +# include <iprt/win/objbase.h> +# ifndef VBOX_COM_NO_ATL + +/* Do not use actual ATL, just provide a superficial lookalike ourselves. */ +# include <VBox/com/microatl.h> +# endif /* VBOX_COM_NO_ATL */ + +# define NS_DECL_ISUPPORTS +# define NS_IMPL_ISUPPORTS1_CI(a, b) + +/* these are XPCOM only, one for every interface implemented */ +# define NS_DECL_ISUPPORTS + +/** Returns @c true if @a rc represents a warning result code */ +# define SUCCEEDED_WARNING(rc) (SUCCEEDED(rc) && (rc) != S_OK) + +/** Tests is a COM result code indicates that the process implementing the + * interface is dead. + * + * COM status codes: + * 0x800706ba - RPC_S_SERVER_UNAVAILABLE. Killed before call was made. + * 0x800706be - RPC_S_CALL_FAILED. Killed after call was made. + * 0x800706bf - RPC_S_CALL_FAILED_DNE. Not observed, but should be + * matter of timing. + * 0x80010108 - RPC_E_DISCONNECTED. Observed deregistering + * python event listener. + * 0x800706b5 - RPC_S_UNKNOWN_IF. Observed deregistering python + * event listener + */ +#define FAILED_DEAD_INTERFACE(rc) \ + ( (rc) == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) \ + || (rc) == HRESULT_FROM_WIN32(RPC_S_CALL_FAILED) \ + || (rc) == HRESULT_FROM_WIN32(RPC_S_CALL_FAILED_DNE) \ + || (rc) == RPC_E_DISCONNECTED \ + ) + +/** Immutable BSTR string */ +typedef const OLECHAR *CBSTR; + +/** Input BSTR argument of interface method declaration. */ +#define IN_BSTR BSTR + +/** Input GUID argument of interface method declaration. */ +#define IN_GUID GUID +/** Output GUID argument of interface method declaration. */ +#define OUT_GUID GUID * + +/** Makes the name of the getter interface function (n must be capitalized). */ +#define COMGETTER(n) get_##n +/** Makes the name of the setter interface function (n must be capitalized). */ +#define COMSETTER(n) put_##n + +/** + * Declares an input safearray parameter in the COM method implementation. Also + * used to declare the COM attribute setter parameter. Corresponds to either of + * the following XIDL definitions: + * <pre> + * <param name="arg" ... dir="in" safearray="yes"/> + * ... + * <attribute name="arg" ... safearray="yes"/> + * </pre> + * + * The method implementation should use the com::SafeArray helper class to work + * with parameters declared using this define. + * + * @param aType Array element type. + * @param aArg Parameter/attribute name. + */ +#define ComSafeArrayIn(aType, aArg) SAFEARRAY *aArg + +/** + * Expands to @c true if the given input safearray parameter is a "null pointer" + * which makes it impossible to use it for reading safearray data. + */ +#define ComSafeArrayInIsNull(aArg) ((aArg) == NULL) + +/** + * Wraps the given parameter name to generate an expression that is suitable for + * passing the parameter to functions that take input safearray parameters + * declared using the ComSafeArrayIn macro. + * + * @param aArg Parameter name to wrap. The given parameter must be declared + * within the calling function using the ComSafeArrayIn macro. + */ +#define ComSafeArrayInArg(aArg) aArg + +/** + * Declares an output safearray parameter in the COM method implementation. Also + * used to declare the COM attribute getter parameter. Corresponds to either of + * the following XIDL definitions: + * <pre> + * <param name="arg" ... dir="out" safearray="yes"/> + * <param name="arg" ... dir="return" safearray="yes"/> + * ... + * <attribute name="arg" ... safearray="yes"/> + * </pre> + * + * The method implementation should use the com::SafeArray helper class to work + * with parameters declared using this define. + * + * @param aType Array element type. + * @param aArg Parameter/attribute name. + */ +#define ComSafeArrayOut(aType, aArg) SAFEARRAY **aArg + +/** + * Expands to @c true if the given output safearray parameter is a "null + * pointer" which makes it impossible to use it for returning a safearray. + */ +#define ComSafeArrayOutIsNull(aArg) ((aArg) == NULL) + +/** + * Wraps the given parameter name to generate an expression that is suitable for + * passing the parameter to functions that take output safearray parameters + * declared using the ComSafeArrayOut marco. + * + * @param aArg Parameter name to wrap. The given parameter must be declared + * within the calling function using the ComSafeArrayOut macro. + */ +#define ComSafeArrayOutArg(aArg) aArg + +/** + * Version of ComSafeArrayIn for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayIn(aArg) SAFEARRAY *aArg + +/** + * Version of ComSafeArrayInIsNull for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayInIsNull(aArg) ComSafeArrayInIsNull(aArg) + +/** + * Version of ComSafeArrayInArg for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayInArg(aArg) ComSafeArrayInArg(aArg) + +/** + * Version of ComSafeArrayOut for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayOut(aArg) SAFEARRAY **aArg + +/** + * Version of ComSafeArrayOutIsNull for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayOutIsNull(aArg) ComSafeArrayOutIsNull(aArg) + +/** + * Version of ComSafeArrayOutArg for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayOutArg(aArg) ComSafeArrayOutArg(aArg) + +/** + * Gets size of safearray parameter. + * @param aArg Parameter name. + */ +#define ComSafeArraySize(aArg) ((aArg) == NULL ? 0 : (aArg)->rgsabound[0].cElements) + +/** + * Apply RT_NOREF_PV to a safearray parameter. + * @param aArg Parameter name. + */ +#define ComSafeArrayNoRef(aArg) RT_NOREF_PV(aArg) + +/** + * Returns the const reference to the IID (i.e., |const GUID &|) of the given + * interface. + * + * @param I interface class + */ +#define COM_IIDOF(I) __uuidof(I) + +/** + * For using interfaces before including the interface definitions. This will + * deal with XPCOM using 'class' and COM using 'struct' when defining + * interfaces. + * + * @param I interface name. + */ +#define COM_STRUCT_OR_CLASS(I) struct I + +#else /* defined(RT_OS_WINDOWS) */ + +#error "VBOX_WITH_XPCOM must be defined on a platform other than Windows!" + +#endif /* defined(RT_OS_WINDOWS) */ + +#else /* !defined(VBOX_WITH_XPCOM) */ + +// XPCOM +///////////////////////////////////////////////////////////////////////////// + +#if defined(RT_OS_DARWIN) || (defined(QT_VERSION) && (QT_VERSION >= 0x040000)) + /* CFBase.h defines these & + * qglobal.h from Qt4 defines these */ +# undef FALSE +# undef TRUE +#endif /* RT_OS_DARWIN || QT_VERSION */ + +#include <nsID.h> + +#define HRESULT nsresult +#define SUCCEEDED NS_SUCCEEDED +#define FAILED NS_FAILED + +#define SUCCEEDED_WARNING(rc) (NS_SUCCEEDED(rc) && (rc) != NS_OK) + +#define FAILED_DEAD_INTERFACE(rc) ( (rc) == NS_ERROR_ABORT \ + || (rc) == NS_ERROR_CALL_FAILED \ + ) + +#define IUnknown nsISupports + +#define BOOL PRBool +#define BYTE PRUint8 +#define SHORT PRInt16 +#define USHORT PRUint16 +#define LONG PRInt32 +#define ULONG PRUint32 +#define LONG64 PRInt64 +#define ULONG64 PRUint64 +/* XPCOM has only 64bit floats */ +#define FLOAT PRFloat64 +#define DOUBLE PRFloat64 + +#define FALSE PR_FALSE +#define TRUE PR_TRUE + +#define OLECHAR wchar_t + +/* note: typedef to semantically match BSTR on Win32 */ +typedef PRUnichar *BSTR; +typedef const PRUnichar *CBSTR; +typedef BSTR *LPBSTR; + +/** Input BSTR argument the interface method declaration. */ +#define IN_BSTR CBSTR + +/** + * Type to define a raw GUID variable (for members use the com::Guid class + * instead). + */ +#define GUID nsID +/** Input GUID argument the interface method declaration. */ +#define IN_GUID const nsID & +/** Output GUID argument the interface method declaration. */ +#define OUT_GUID nsID ** + +/** Makes the name of the getter interface function (n must be capitalized). */ +#define COMGETTER(n) Get##n +/** Makes the name of the setter interface function (n must be capitalized). */ +#define COMSETTER(n) Set##n + +/* safearray input parameter macros */ +#define ComSafeArrayIn(aType, aArg) PRUint32 aArg##Size, aType *aArg +#define ComSafeArrayInIsNull(aArg) ((aArg) == NULL) +#define ComSafeArrayInArg(aArg) aArg##Size, aArg + +/* safearray output parameter macros */ +#define ComSafeArrayOut(aType, aArg) PRUint32 *aArg##Size, aType **aArg +#define ComSafeArrayOutIsNull(aArg) ((aArg) == NULL) +#define ComSafeArrayOutArg(aArg) aArg##Size, aArg + +/* safearray input parameter macros for GUID */ +#define ComSafeGUIDArrayIn(aArg) PRUint32 aArg##Size, const nsID **aArg +#define ComSafeGUIDArrayInIsNull(aArg) ComSafeArrayInIsNull(aArg) +#define ComSafeGUIDArrayInArg(aArg) ComSafeArrayInArg(aArg) + +/* safearray output parameter macros for GUID */ +#define ComSafeGUIDArrayOut(aArg) PRUint32 *aArg##Size, nsID ***aArg +#define ComSafeGUIDArrayOutIsNull(aArg) ComSafeArrayOutIsNull(aArg) +#define ComSafeGUIDArrayOutArg(aArg) ComSafeArrayOutArg(aArg) + +/** safearray size */ +#define ComSafeArraySize(aArg) ((aArg) == NULL ? 0 : (aArg##Size)) + +/** NOREF a COM safe array argument. */ +#define ComSafeArrayNoRef(aArg) RT_NOREF2(aArg, aArg##Size) + +/* CLSID and IID for compatibility with Win32 */ +typedef nsCID CLSID; +typedef nsIID IID; + +/* OLE error codes */ +#define S_OK ((nsresult)NS_OK) +#define S_FALSE ((nsresult)1) +#define E_UNEXPECTED NS_ERROR_UNEXPECTED +#define E_NOTIMPL NS_ERROR_NOT_IMPLEMENTED +#define E_OUTOFMEMORY NS_ERROR_OUT_OF_MEMORY +#define E_INVALIDARG NS_ERROR_INVALID_ARG +#define E_NOINTERFACE NS_ERROR_NO_INTERFACE +#define E_POINTER NS_ERROR_NULL_POINTER +#define E_ABORT NS_ERROR_ABORT +#define E_FAIL NS_ERROR_FAILURE +/* Note: a better analog for E_ACCESSDENIED would probably be + * NS_ERROR_NOT_AVAILABLE, but we want binary compatibility for now. */ +#define E_ACCESSDENIED ((nsresult)0x80070005L) + +#define STDMETHOD(a) NS_IMETHOD a +#define STDMETHODIMP NS_IMETHODIMP +#define STDMETHOD_(ret, meth) NS_IMETHOD_(ret) meth + +#define COM_IIDOF(I) NS_GET_IID(I) + +#define COM_STRUCT_OR_CLASS(I) class I + +/* helper functions */ +extern "C" +{ +BSTR SysAllocString(const OLECHAR *sz); +BSTR SysAllocStringByteLen(char const *psz, unsigned int len); +BSTR SysAllocStringLen(const OLECHAR *pch, unsigned int cch); +void SysFreeString(BSTR bstr); +int SysReAllocString(BSTR *pbstr, const OLECHAR *psz); +int SysReAllocStringLen(BSTR *pbstr, const OLECHAR *psz, unsigned int cch); +unsigned int SysStringByteLen(BSTR bstr); +unsigned int SysStringLen(BSTR bstr); +} + +#ifndef VBOX_COM_NO_ATL + +namespace ATL +{ + +#define ATL_NO_VTABLE +#define DECLARE_CLASSFACTORY(a) +#define DECLARE_CLASSFACTORY_SINGLETON(a) +#define DECLARE_REGISTRY_RESOURCEID(a) +#define DECLARE_NOT_AGGREGATABLE(a) +#define DECLARE_PROTECT_FINAL_CONSTRUCT() +#define BEGIN_COM_MAP(a) +#define COM_INTERFACE_ENTRY(a) +#define COM_INTERFACE_ENTRY2(a,b) +#define END_COM_MAP() NS_DECL_ISUPPORTS +#define COM_INTERFACE_ENTRY_AGGREGATE(a,b) + +/* A few very simple ATL emulator classes to provide + * FinalConstruct()/FinalRelease() functionality with XPCOM. */ + +class CComMultiThreadModel +{ +}; + +template <class DummyThreadModel> class CComObjectRootEx +{ +public: + HRESULT FinalConstruct() + { + return S_OK; + } + void FinalRelease() + { + } +}; + +template <class Base> class CComObject : public Base +{ +public: + virtual ~CComObject() { this->FinalRelease(); } +}; + +} /* namespace ATL */ + + +/** + * 'Constructor' for the component class. + * This constructor, as opposed to NS_GENERIC_FACTORY_CONSTRUCTOR, + * assumes that the component class is derived from the CComObjectRootEx<> + * template, so it calls FinalConstruct() right after object creation + * and ensures that FinalRelease() will be called right before destruction. + * The result from FinalConstruct() is returned to the caller. + */ +#define NS_GENERIC_FACTORY_CONSTRUCTOR_WITH_RC(_InstanceClass) \ +static NS_IMETHODIMP \ +_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ + void **aResult) \ +{ \ + nsresult rv; \ + \ + *aResult = NULL; \ + if (NULL != aOuter) { \ + rv = NS_ERROR_NO_AGGREGATION; \ + return rv; \ + } \ + \ + ATL::CComObject<_InstanceClass> *inst = new ATL::CComObject<_InstanceClass>(); \ + if (NULL == inst) { \ + rv = NS_ERROR_OUT_OF_MEMORY; \ + return rv; \ + } \ + \ + NS_ADDREF(inst); /* protect FinalConstruct() */ \ + rv = inst->FinalConstruct(); \ + if (NS_SUCCEEDED(rv)) \ + rv = inst->QueryInterface(aIID, aResult); \ + NS_RELEASE(inst); \ + \ + return rv; \ +} + +/** + * 'Constructor' that uses an existing getter function that gets a singleton. + * The getter function must have the following prototype: + * nsresult _GetterProc(_InstanceClass **inst) + * This constructor, as opposed to NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR, + * lets the getter function return a result code that is passed back to the + * caller that tries to instantiate the object. + * NOTE: assumes that getter does an AddRef - so additional AddRef is not done. + */ +#define NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR_WITH_RC(_InstanceClass, _GetterProc) \ +static NS_IMETHODIMP \ +_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ + void **aResult) \ +{ \ + nsresult rv; \ + \ + _InstanceClass *inst = NULL; /* initialized to shut up gcc */ \ + \ + *aResult = NULL; \ + if (NULL != aOuter) { \ + rv = NS_ERROR_NO_AGGREGATION; \ + return rv; \ + } \ + \ + rv = _GetterProc(&inst); \ + if (NS_FAILED(rv)) \ + return rv; \ + \ + /* sanity check */ \ + if (NULL == inst) \ + return NS_ERROR_OUT_OF_MEMORY; \ + \ + /* NS_ADDREF(inst); */ \ + if (NS_SUCCEEDED(rv)) { \ + rv = inst->QueryInterface(aIID, aResult); \ + } \ + NS_RELEASE(inst); \ + \ + return rv; \ +} + +#endif /* !VBOX_COM_NO_ATL */ + +#endif /* !defined(VBOX_WITH_XPCOM) */ + +/** + * Declares a wchar_t string literal from the argument. + * Necessary to overcome MSC / GCC differences. + * @param s expression to stringify + */ +#if defined(_MSC_VER) +# define WSTR_LITERAL(s) L#s +#elif defined(__GNUC__) +# define WSTR_LITERAL(s) L""#s +#else +# error "Unsupported compiler!" +#endif + +namespace com +{ + +#ifndef VBOX_COM_NO_ATL + +// use this macro to implement scriptable interfaces +#ifdef RT_OS_WINDOWS +#define VBOX_SCRIPTABLE_IMPL(iface) \ + public ATL::IDispatchImpl<iface, &IID_##iface, &LIBID_VirtualBox, \ + kTypeLibraryMajorVersion, kTypeLibraryMinorVersion> + +#define VBOX_SCRIPTABLE_DISPATCH_IMPL(iface) \ + STDMETHOD(QueryInterface)(REFIID riid, void **ppObj) \ + { \ + if (riid == IID_##iface) \ + { \ + *ppObj = (iface *)this; \ + AddRef(); \ + return S_OK; \ + } \ + if (riid == IID_IUnknown) \ + { \ + *ppObj = (IUnknown *)this; \ + AddRef(); \ + return S_OK; \ + } \ + if (riid == IID_IDispatch) \ + { \ + *ppObj = (IDispatch *)this; \ + AddRef(); \ + return S_OK; \ + } \ + *ppObj = NULL; \ + return E_NOINTERFACE; \ + } +#else +#define VBOX_SCRIPTABLE_IMPL(iface) \ + public iface +#define VBOX_SCRIPTABLE_DISPATCH_IMPL(iface) +#endif + +#endif /* !VBOX_COM_NO_ATL */ + +} /* namespace com */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_defs_h */ + diff --git a/include/VBox/com/errorprint.h b/include/VBox/com/errorprint.h new file mode 100644 index 00000000..037b1ff4 --- /dev/null +++ b/include/VBox/com/errorprint.h @@ -0,0 +1,401 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - Error Reporting. + * + * Error printing macros using shared functions defined in shared glue code. + * Use these CHECK_* macros for efficient error checking around calling COM + * methods. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_errorprint_h +#define VBOX_INCLUDED_com_errorprint_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/com/ErrorInfo.h> + + +/** @defgroup grp_com_error_reporting Error Reporting + * @ingroup grp_com + * @{ + */ + +namespace com +{ + +// shared prototypes; these are defined in shared glue code and are +// compiled only once for all front-ends +void GluePrintErrorInfo(const com::ErrorInfo &info); +void GluePrintErrorContext(const char *pcszContext, const char *pcszSourceFile, uint32_t uLine, bool fWarning = false); +void GluePrintRCMessage(HRESULT rc); +void GlueHandleComError(ComPtr<IUnknown> iface, const char *pcszContext, HRESULT rc, const char *pcszSourceFile, uint32_t uLine); +void GlueHandleComErrorNoCtx(ComPtr<IUnknown> iface, HRESULT rc); +void GlueHandleComErrorProgress(ComPtr<IProgress> progress, const char *pcszContext, HRESULT rc, + const char *pcszSourceFile, uint32_t uLine); + +/** + * Extended macro that implements all the other CHECK_ERROR2XXX macros. + * + * Calls the method of the given interface and checks the return status code. + * If the status indicates failure, as much information as possible is reported + * about the error, including current source file and line. + * + * After reporting an error, the statement |stmtError| is executed. + * + * This macro family is intended for command line tools like VBoxManage, but + * could also be handy for debugging. + * + * @param type For defining @a hrc locally inside the the macro + * expansion, pass |HRESULT| otherwise |RT_NOTHING|. + * @param hrc Name of the HRESULT variable to assign the result of the + * method call to. + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @param stmtError Statement to be executed after reporting failures. This + * can be a |break| or |return| statement, if so desired. + * + * @remarks Unlike CHECK_ERROR, CHECK_ERROR_RET and family, this macro family + * does not presuppose a |rc| variable but instead either let the user + * specify the variable to use or employs a local variable |hrcCheck| + * within its own scope. + * + * @sa CHECK_ERROR2, CHECK_ERROR2I, CHECK_ERROR2_STMT, CHECK_ERROR2I_STMT, + * CHECK_ERROR2_BREAK, CHECK_ERROR2I_BREAK, CHECK_ERROR2_RET, + * CHECK_ERROR2I_RET + */ +#define CHECK_ERROR2_EX(type, hrc, iface, method, stmtError) \ + if (1) { \ + type hrc = iface->method; \ + if (SUCCEEDED(hrc) && !SUCCEEDED_WARNING(hrc)) \ + { /*likely*/ } \ + else \ + { \ + com::GlueHandleComError(iface, #method, (hrc), __FILE__, __LINE__); \ + if (!SUCCEEDED_WARNING(hrc)) \ + { \ + stmtError; \ + } \ + } \ + } else do { /* nothing */ } while (0) + + +/** + * Calls the given method of the given interface and then checks if the return + * value (COM result code) indicates a failure. If so, prints the failed + * function/line/file, the description of the result code and attempts to + * query the extended error information on the current thread (using + * com::ErrorInfo) if the interface reports that it supports error information. + * + * Used by command line tools or for debugging and assumes the |HRESULT rc| + * variable is accessible for assigning in the current scope. + * @sa CHECK_ERROR2, CHECK_ERROR2I + */ +#define CHECK_ERROR(iface, method) \ + do { \ + hrc = iface->method; \ + if (FAILED(hrc) || SUCCEEDED_WARNING(hrc)) \ + com::GlueHandleComError(iface, #method, hrc, __FILE__, __LINE__); \ + } while (0) +/** + * Simplified version of CHECK_ERROR2_EX, no error statement or type necessary. + * + * @param hrc Name of the HRESULT variable to assign the result of the + * method call to. + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @sa CHECK_ERROR2I, CHECK_ERROR2_EX + */ +#define CHECK_ERROR2(hrc, iface, method) CHECK_ERROR2_EX(RT_NOTHING, hrc, iface, method, (void)1) +/** + * Simplified version of CHECK_ERROR2_EX that uses an internal variable + * |hrcCheck| for holding the result and have no error statement. + * + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @sa CHECK_ERROR2, CHECK_ERROR2_EX + */ +#define CHECK_ERROR2I(iface, method) CHECK_ERROR2_EX(HRESULT, hrcCheck, iface, method, (void)1) + + +/** + * Same as CHECK_ERROR except that it also executes the statement |stmt| on + * failure. + * @sa CHECK_ERROR2_STMT, CHECK_ERROR2I_STMT + */ +#define CHECK_ERROR_STMT(iface, method, stmt) \ + do { \ + hrc = iface->method; \ + if (FAILED(hrc) || SUCCEEDED_WARNING(hrc)) \ + { \ + com::GlueHandleComError(iface, #method, hrc, __FILE__, __LINE__); \ + if (!SUCCEEDED_WARNING(hrc) \ + { \ + stmt; \ + } \ + } \ + } while (0) +/** + * Simplified version of CHECK_ERROR2_EX (no @a hrc type). + * + * @param hrc Name of the HRESULT variable to assign the result of the + * method call to. + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @param stmt Statement to be executed after reporting failures. + * @sa CHECK_ERROR2I_STMT, CHECK_ERROR2_EX + */ +#define CHECK_ERROR2_STMT(hrc, iface, method, stmt) CHECK_ERROR2_EX(RT_NOTHING, hrc, iface, method, stmt) +/** + * Simplified version of CHECK_ERROR2_EX that uses an internal variable + * |hrcCheck| for holding the result. + * + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @param stmt Statement to be executed after reporting failures. + * @sa CHECK_ERROR2_STMT, CHECK_ERROR2_EX + */ +#define CHECK_ERROR2I_STMT(iface, method, stmt) CHECK_ERROR2_EX(HRESULT, hrcCheck, iface, method, stmt) + + +/** + * Does the same as CHECK_ERROR(), but executes the |break| statement on + * failure. + * @sa CHECK_ERROR2_BREAK, CHECK_ERROR2I_BREAK + */ +#ifdef __GNUC__ +# define CHECK_ERROR_BREAK(iface, method) \ + __extension__ \ + ({ \ + hrc = iface->method; \ + if (FAILED(hrc) || SUCCEEDED_WARNING(hrc)) \ + { \ + com::GlueHandleComError(iface, #method, hrc, __FILE__, __LINE__); \ + if (!SUCCEEDED_WARNING(hrc)) \ + break; \ + } \ + }) +#else +# define CHECK_ERROR_BREAK(iface, method) \ + if (1) \ + { \ + hrc = iface->method; \ + if (FAILED(hrc)) \ + { \ + com::GlueHandleComError(iface, #method, hrc, __FILE__, __LINE__); \ + if (!SUCCEEDED_WARNING(hrc)) \ + break; \ + } \ + } \ + else do {} while (0) +#endif +/** + * Simplified version of CHECK_ERROR2_EX that executes the |break| statement + * after error reporting (no @a hrc type). + * + * @param hrc The result variable (type HRESULT). + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @sa CHECK_ERROR2I_BREAK, CHECK_ERROR2_EX + */ +#define CHECK_ERROR2_BREAK(hrc, iface, method) CHECK_ERROR2_EX(RT_NOTHING, hrc, iface, method, break) +/** + * Simplified version of CHECK_ERROR2_EX that executes the |break| statement + * after error reporting and that uses an internal variable |hrcCheck| for + * holding the result. + * + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @sa CHECK_ERROR2_BREAK, CHECK_ERROR2_EX + */ +#define CHECK_ERROR2I_BREAK(iface, method) CHECK_ERROR2_EX(HRESULT, hrcCheck, iface, method, break) +/** + * Simplified version of CHECK_ERROR2_EX that executes the |stmt;break| + * statements after error reporting and that uses an internal variable + * |hrcCheck| for holding the result. + * + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @param stmt Statement to be executed after reporting failures. + * @sa CHECK_ERROR2_BREAK, CHECK_ERROR2_EX + */ +#define CHECK_ERROR2I_BREAK_STMT(iface, method, stmt) CHECK_ERROR2_EX(HRESULT, hrcCheck, iface, method, stmt; break) + + +/** + * Does the same as CHECK_ERROR(), but executes the |return ret| statement on + * failure. + * @sa CHECK_ERROR2_RET, CHECK_ERROR2I_RET + */ +#define CHECK_ERROR_RET(iface, method, ret) \ + do { \ + hrc = iface->method; \ + if (FAILED(hrc) || SUCCEEDED_WARNING(hrc)) \ + { \ + com::GlueHandleComError(iface, #method, hrc, __FILE__, __LINE__); \ + if (!SUCCEEDED_WARNING(hrc)) \ + return (ret); \ + } \ + } while (0) +/** + * Simplified version of CHECK_ERROR2_EX that executes the |return (rcRet)| + * statement after error reporting. + * + * @param hrc The result variable (type HRESULT). + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @param rcRet What to return on failure. + */ +#define CHECK_ERROR2_RET(hrc, iface, method, rcRet) CHECK_ERROR2_EX(RT_NOTHING, hrc, iface, method, return (rcRet)) +/** + * Simplified version of CHECK_ERROR2_EX that executes the |return (rcRet)| + * statement after error reporting and that uses an internal variable |hrcCheck| + * for holding the result. + * + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @param rcRet What to return on failure. Use |hrcCheck| to return + * the status code of the method call. + */ +#define CHECK_ERROR2I_RET(iface, method, rcRet) CHECK_ERROR2_EX(HRESULT, hrcCheck, iface, method, return (rcRet)) + + +/** + * Check the progress object for an error and if there is one print out the + * extended error information. + * @remarks Requires HRESULT variable named @a rc. + */ +#define CHECK_PROGRESS_ERROR(progress, msg) \ + do { \ + LONG iRc; \ + hrc = progress->COMGETTER(ResultCode)(&iRc); \ + if (FAILED(hrc) || FAILED(iRc)) \ + { \ + if (SUCCEEDED(hrc)) hrc = iRc; else iRc = hrc; \ + RTMsgError msg; \ + com::GlueHandleComErrorProgress(progress, __PRETTY_FUNCTION__, iRc, __FILE__, __LINE__); \ + } \ + } while (0) + +/** + * Does the same as CHECK_PROGRESS_ERROR(), but executes the |break| statement + * on failure. + * @remarks Requires HRESULT variable named @a rc. + */ +#ifdef __GNUC__ +# define CHECK_PROGRESS_ERROR_BREAK(progress, msg) \ + __extension__ \ + ({ \ + LONG iRc; \ + hrc = progress->COMGETTER(ResultCode)(&iRc); \ + if (FAILED(hrc) || FAILED(iRc)) \ + { \ + if (SUCCEEDED(hrc)) hrc = iRc; else iRc = hrc; \ + RTMsgError msg; \ + com::GlueHandleComErrorProgress(progress, __PRETTY_FUNCTION__, iRc, __FILE__, __LINE__); \ + break; \ + } \ + }) +#else +# define CHECK_PROGRESS_ERROR_BREAK(progress, msg) \ + if (1) \ + { \ + LONG iRc; \ + hrc = progress->COMGETTER(ResultCode)(&iRc); \ + if (FAILED(hrc) || FAILED(iRc)) \ + { \ + if (SUCCEEDED(hrc)) hrc = iRc; else iRc = hrc; \ + RTMsgError msg; \ + com::GlueHandleComErrorProgress(progress, __PRETTY_FUNCTION__, iRc, __FILE__, __LINE__); \ + break; \ + } \ + } \ + else do {} while (0) +#endif + +/** + * Does the same as CHECK_PROGRESS_ERROR(), but executes the |return ret| + * statement on failure. + */ +#define CHECK_PROGRESS_ERROR_RET(progress, msg, ret) \ + do { \ + LONG iRc; \ + HRESULT hrcCheck = progress->COMGETTER(ResultCode)(&iRc); \ + if (SUCCEEDED(hrcCheck) && SUCCEEDED(iRc)) \ + { /* likely */ } \ + else \ + { \ + RTMsgError msg; \ + com::GlueHandleComErrorProgress(progress, __PRETTY_FUNCTION__, \ + SUCCEEDED(hrcCheck) ? iRc : hrcCheck, __FILE__, __LINE__); \ + return (ret); \ + } \ + } while (0) + +/** + * Asserts the given expression is true. When the expression is false, prints + * a line containing the failed function/line/file; otherwise does nothing. + */ +#define ASSERT(expr) \ + do { \ + if (!(expr)) \ + { \ + RTPrintf ("[!] ASSERTION FAILED at line %d: %s\n", __LINE__, #expr); \ + Log (("[!] ASSERTION FAILED at line %d: %s\n", __LINE__, #expr)); \ + } \ + } while (0) + + +/** + * Does the same as ASSERT(), but executes the |return ret| statement if the + * expression to assert is false; + * @remarks WARNING! @a expr is evalutated TWICE! + */ +#define ASSERT_RET(expr, ret) \ + do { ASSERT(expr); if (!(expr)) return (ret); } while (0) + +/** + * Does the same as ASSERT(), but executes the |break| statement if the + * expression to assert is false; + * @remarks WARNING! @a expr is evalutated TWICE! + */ +#define ASSERT_BREAK(expr, ret) \ + if (1) { ASSERT(expr); if (!(expr)) break; } else do {} while (0) + +} /* namespace com */ + + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_errorprint_h */ + diff --git a/include/VBox/com/list.h b/include/VBox/com/list.h new file mode 100644 index 00000000..e898e15b --- /dev/null +++ b/include/VBox/com/list.h @@ -0,0 +1,223 @@ +/* $Id: list.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - List classes declaration. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_list_h +#define VBOX_INCLUDED_com_list_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/com/ptr.h> +#include <VBox/com/string.h> +#include <VBox/com/array.h> +#include <iprt/cpp/list.h> + + +/** @defgroup grp_com_list List Classes + * @ingroup grp_com + * @{ + */ + +/** + * Specialized list class for using with com::ComPtr<C> + * + * @note This is necessary cause ComPtr<IFACE> has a size of 8. + */ +template <typename C> +class RTCList< ComPtr<C> >: public RTCListBase< ComPtr<C>, ComPtr<C>*, false> +{ + /* Traits */ + typedef ComPtr<C> T; + typedef T *ITYPE; + static const bool MT = false; + typedef RTCListBase<T, ITYPE, MT> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * Specialized list class for using with com::ComObjPtr<C> + * + * @note: This is necessary cause ComObjPtr<IFACE> has a size of 8. + */ +template <typename C> +class RTCList< ComObjPtr<C> >: public RTCListBase< ComObjPtr<C>, ComObjPtr<C>*, false> +{ + /* Traits */ + typedef ComObjPtr<C> T; + typedef T *ITYPE; + static const bool MT = false; + typedef RTCListBase<T, ITYPE, MT> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * Specialized list class for using with com::Utf8Str. + * + * The class offers methods for importing com::SafeArray's of com::Bstr's. + */ +template <> +class RTCList<com::Utf8Str>: public RTCListBase<com::Utf8Str, com::Utf8Str*, false> +{ + /* Traits */ + typedef com::Utf8Str T; + typedef T *ITYPE; + static const bool MT = false; + typedef RTCListBase<T, ITYPE, MT> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /** + * Creates a copy of another list. + * + * The other list will be fully copied and the capacity will be the same as + * the size of the other list. The com::Bstr's are silently converted to + * com::Utf8Str's. + * + * @param other The list to copy. + * @throws std::bad_alloc + */ + RTCList(ComSafeArrayIn(IN_BSTR, other)) + { + com::SafeArray<IN_BSTR> sfaOther(ComSafeArrayInArg(other)); + size_t const cElementsOther = sfaOther.size(); + resizeArray(cElementsOther); + m_cElements = cElementsOther; + for (size_t i = 0; i < cElementsOther; ++i) + RTCListHelper<T, ITYPE>::set(m_pArray, i, T(sfaOther[i])); + } + + /** + * Creates a copy of another list. + * + * The other list will be fully copied and the capacity will be the same as + * the size of the other list. The com::Bstr's are silently converted to + * com::Utf8Str's. + * + * @param other The list to copy. + * @throws std::bad_alloc + */ + RTCList(const com::SafeArray<IN_BSTR> &other) + : BASE(other.size()) + { + for (size_t i = 0; i < m_cElements; ++i) + RTCListHelper<T, ITYPE>::set(m_pArray, i, T(other[i])); + } + + /** + * Copy the items of the other list into this list. All previous items of + * this list are deleted. + * + * @param other The list to copy. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase<T, ITYPE, MT> &operator=(const com::SafeArray<IN_BSTR> &other) + { + m_guard.enterWrite(); + + /* Values cleanup */ + RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements); + + /* Copy */ + size_t cElementsOther = other.size(); + if (cElementsOther != m_cCapacity) + resizeArrayNoErase(cElementsOther); + m_cElements = cElementsOther; + for (size_t i = 0; i < cElementsOther; ++i) + RTCListHelper<T, ITYPE>::set(m_pArray, i, T(other[i])); + + m_guard.leaveWrite(); + return *this; + } + + /** + * Implicit conversion to a RTCString list. + * + * This allows the usage of the RTCString::join method with this list type. + * + * @return a converted const reference to this list. + */ + operator const RTCList<RTCString, RTCString*>&() + { + return *reinterpret_cast<RTCList<RTCString, RTCString*> *>(this); + } + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_list_h */ + diff --git a/include/VBox/com/listeners.h b/include/VBox/com/listeners.h new file mode 100644 index 00000000..06f35ebf --- /dev/null +++ b/include/VBox/com/listeners.h @@ -0,0 +1,194 @@ +/* $Id: listeners.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - Listener helpers. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_listeners_h +#define VBOX_INCLUDED_com_listeners_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/com/com.h> +#include <VBox/com/VirtualBox.h> + + +/** @defgroup grp_com_listeners Listener Helpers + * @ingroup grp_com + * @{ + */ + + +#ifdef VBOX_WITH_XPCOM +# define NS_IMPL_QUERY_HEAD_INLINE() \ +NS_IMETHODIMP QueryInterface(REFNSIID aIID, void **aInstancePtr) \ +{ \ + NS_ASSERTION(aInstancePtr, "QueryInterface requires a non-NULL destination!"); \ + nsISupports *foundInterface; + +# define NS_INTERFACE_MAP_BEGIN_INLINE() NS_IMPL_QUERY_HEAD_INLINE() + +# define NS_IMPL_QUERY_INTERFACE1_INLINE(a_i1) \ + NS_INTERFACE_MAP_BEGIN_INLINE() \ + NS_INTERFACE_MAP_ENTRY(a_i1) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, a_i1) \ + NS_INTERFACE_MAP_END +#endif + +template <class T, class TParam = void *> +class ListenerImpl : + public ATL::CComObjectRootEx<ATL::CComMultiThreadModel>, + VBOX_SCRIPTABLE_IMPL(IEventListener) +{ + T* mListener; + +#ifdef RT_OS_WINDOWS + /* FTM stuff */ + ComPtr<IUnknown> m_pUnkMarshaler; +#else + nsAutoRefCnt mRefCnt; + NS_DECL_OWNINGTHREAD +#endif + +public: + ListenerImpl() + { + } + + virtual ~ListenerImpl() + { + } + + HRESULT init(T* aListener, TParam param) + { + mListener = aListener; + return mListener->init(param); + } + + HRESULT init(T* aListener) + { + mListener = aListener; + return mListener->init(); + } + + void uninit() + { + if (mListener) + { + mListener->uninit(); + delete mListener; + mListener = 0; + } + } + + HRESULT FinalConstruct() + { +#ifdef RT_OS_WINDOWS + return CoCreateFreeThreadedMarshaler(this, &m_pUnkMarshaler.m_p); +#else + return S_OK; +#endif + } + + void FinalRelease() + { + uninit(); +#ifdef RT_OS_WINDOWS + m_pUnkMarshaler.setNull(); +#endif + } + + T* getWrapped() + { + return mListener; + } + + DECLARE_NOT_AGGREGATABLE(ListenerImpl) + + DECLARE_PROTECT_FINAL_CONSTRUCT() + +#ifdef RT_OS_WINDOWS + BEGIN_COM_MAP(ListenerImpl) + COM_INTERFACE_ENTRY(IEventListener) + COM_INTERFACE_ENTRY2(IDispatch, IEventListener) + COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pUnkMarshaler.m_p) + END_COM_MAP() +#else + NS_IMETHOD_(nsrefcnt) AddRef(void) + { + NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); + nsrefcnt count; + count = PR_AtomicIncrement((PRInt32*)&mRefCnt); + NS_LOG_ADDREF(this, count, "ListenerImpl", sizeof(*this)); + return count; + } + + NS_IMETHOD_(nsrefcnt) Release(void) + { + nsrefcnt count; + NS_PRECONDITION(0 != mRefCnt, "dup release"); + count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); + NS_LOG_RELEASE(this, count, "ListenerImpl"); + if (0 == count) { + mRefCnt = 1; /* stabilize */ + /* enable this to find non-threadsafe destructors: */ + /* NS_ASSERT_OWNINGTHREAD(_class); */ + NS_DELETEXPCOM(this); + return 0; + } + return count; + } + + NS_IMPL_QUERY_INTERFACE1_INLINE(IEventListener) +#endif + + + STDMETHOD(HandleEvent)(IEvent * aEvent) + { + VBoxEventType_T aType = VBoxEventType_Invalid; + HRESULT hrc = aEvent->COMGETTER(Type)(&aType); + AssertMsg(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc)); RT_NOREF(hrc); + return mListener->HandleEvent(aType, aEvent); + } +}; + +#ifdef VBOX_WITH_XPCOM +# define VBOX_LISTENER_DECLARE(klazz) NS_DECL_CLASSINFO(klazz) +#else +# define VBOX_LISTENER_DECLARE(klazz) +#endif + +/** @} */ +#endif /* !VBOX_INCLUDED_com_listeners_h */ + diff --git a/include/VBox/com/microatl.h b/include/VBox/com/microatl.h new file mode 100644 index 00000000..7066ed02 --- /dev/null +++ b/include/VBox/com/microatl.h @@ -0,0 +1,1408 @@ +/** @file + * ATL lookalike, just the tiny subset we actually need. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_microatl_h +#define VBOX_INCLUDED_com_microatl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> /* VBOX_STRICT */ +#include <iprt/assert.h> +#include <iprt/critsect.h> +#include <iprt/errcore.h> /* RT_FAILURE() */ + +#include <iprt/win/windows.h> + +#include <new> + + +namespace ATL +{ + +#define ATL_NO_VTABLE __declspec(novtable) + +class CAtlModule; +__declspec(selectany) CAtlModule *_pAtlModule = NULL; + +class CComModule; +__declspec(selectany) CComModule *_pModule = NULL; + +typedef HRESULT (WINAPI FNCREATEINSTANCE)(void *pv, REFIID riid, void **ppv); +typedef FNCREATEINSTANCE *PFNCREATEINSTANCE; +typedef HRESULT (WINAPI FNINTERFACEMAPHELPER)(void *pv, REFIID riid, void **ppv, DWORD_PTR dw); +typedef FNINTERFACEMAPHELPER *PFNINTERFACEMAPHELPER; +typedef void (__stdcall FNATLTERMFUNC)(void *pv); +typedef FNATLTERMFUNC *PFNATLTERMFUNC; + +struct _ATL_TERMFUNC_ELEM +{ + PFNATLTERMFUNC pfn; + void *pv; + _ATL_TERMFUNC_ELEM *pNext; +}; + +struct _ATL_INTMAP_ENTRY +{ + const IID *piid; // interface ID + DWORD_PTR dw; + PFNINTERFACEMAPHELPER pFunc; // NULL: end of array, 1: offset based map entry, other: function pointer +}; + +#define COM_SIMPLEMAPENTRY ((ATL::PFNINTERFACEMAPHELPER)1) + +#define DECLARE_CLASSFACTORY_EX(c) typedef ATL::CComCreator<ATL::CComObjectNoLock<c> > _ClassFactoryCreatorClass; +#define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(ATL::CComClassFactory) +#define DECLARE_CLASSFACTORY_SINGLETON(o) DECLARE_CLASSFACTORY_EX(ATL::CComClassFactorySingleton<o>) +#define DECLARE_AGGREGATABLE(c) \ +public: \ + typedef ATL::CComCreator2<ATL::CComCreator<ATL::CComObject<c> >, ATL::CComCreator<ATL::CComAggObject<c> > > _CreatorClass; +#define DECLARE_NOT_AGGREGATABLE(c) \ +public: \ + typedef ATL::CComCreator2<ATL::CComCreator<ATL::CComObject<c> >, ATL::CComFailCreator<CLASS_E_NOAGGREGATION> > _CreatorClass; + +#define DECLARE_PROTECT_FINAL_CONSTRUCT() \ + void InternalFinalConstructAddRef() \ + { \ + InternalAddRef(); \ + } \ + void InternalFinalConstructRelease() \ + { \ + InternalRelease(); \ + } + +#define BEGIN_COM_MAP(c) \ +public: \ + typedef c _ComClass; \ + HRESULT _InternalQueryInterface(REFIID iid, void **ppvObj) throw() \ + { \ + return InternalQueryInterface(this, _GetEntries(), iid, ppvObj); \ + } \ + const static ATL::_ATL_INTMAP_ENTRY *WINAPI _GetEntries() throw() \ + { \ + static const ATL::_ATL_INTMAP_ENTRY _aInterfaces[] = \ + { + +#define COM_INTERFACE_ENTRY(c) \ + { &__uuidof(c), (DWORD_PTR)(static_cast<c *>((_ComClass *)8))-8, COM_SIMPLEMAPENTRY }, + +#define COM_INTERFACE_ENTRY2(c, c2) \ + { &__uuidof(c), (DWORD_PTR)(static_cast<c *>(static_cast<c2 *>((_ComClass *)8)))-8, COM_SIMPLEMAPENTRY }, + +#define COM_INTERFACE_ENTRY_AGGREGATE(iid, pUnk) \ + { &iid, (DWORD_PTR)RT_UOFFSETOF(_ComClass, pUnk), _Delegate}, + +#define END_COM_MAP() \ + { NULL, 0, NULL} \ + }; \ + return _aInterfaces; \ + } \ + virtual ULONG STDMETHODCALLTYPE AddRef(void) throw() = 0; \ + virtual ULONG STDMETHODCALLTYPE Release(void) throw() = 0; \ + STDMETHOD(QueryInterface)(REFIID, void **) throw() = 0; + +struct _ATL_OBJMAP_ENTRY +{ + const CLSID *pclsid; + PFNCREATEINSTANCE pfnGetClassObject; + PFNCREATEINSTANCE pfnCreateInstance; + IUnknown *pCF; + DWORD dwRegister; +}; + +#define BEGIN_OBJECT_MAP(o) static ATL::_ATL_OBJMAP_ENTRY o[] = { +#define END_OBJECT_MAP() {NULL, NULL, NULL, NULL, 0}}; +#define OBJECT_ENTRY(clsid, c) {&clsid, c::_ClassFactoryCreatorClass::CreateInstance, c::_CreatorClass::CreateInstance, NULL, 0 }, + + +class CComCriticalSection +{ +public: + CComCriticalSection() throw() + { + memset(&m_CritSect, 0, sizeof(m_CritSect)); + } + ~CComCriticalSection() + { + } + HRESULT Lock() throw() + { + RTCritSectEnter(&m_CritSect); + return S_OK; + } + HRESULT Unlock() throw() + { + RTCritSectLeave(&m_CritSect); + return S_OK; + } + HRESULT Init() throw() + { + HRESULT hrc = S_OK; + if (RT_FAILURE(RTCritSectInit(&m_CritSect))) + hrc = E_FAIL; + return hrc; + } + + HRESULT Term() throw() + { + RTCritSectDelete(&m_CritSect); + return S_OK; + } + + RTCRITSECT m_CritSect; +}; + +template<class TLock> +class CComCritSectLockManual +{ +public: + CComCritSectLockManual(CComCriticalSection &cs) + : m_cs(cs) + , m_fLocked(false) + { + } + + ~CComCritSectLockManual() throw() + { + if (m_fLocked) + Unlock(); + } + + HRESULT Lock() + { + Assert(!m_fLocked); + HRESULT hrc = m_cs.Lock(); + if (FAILED(hrc)) + return hrc; + m_fLocked = true; + return S_OK; + } + + void Unlock() throw() + { + Assert(m_fLocked); + m_cs.Unlock(); + m_fLocked = false; + } + + +private: + TLock &m_cs; + bool m_fLocked; + + CComCritSectLockManual(const CComCritSectLockManual&) throw(); // Do not call. + CComCritSectLockManual &operator=(const CComCritSectLockManual &) throw(); // Do not call. +}; + + +#ifdef RT_EXCEPTIONS_ENABLED +/** This is called CComCritSecLock in real ATL... */ +template<class TLock> +class CComCritSectLock : public CComCritSectLockManual<TLock> +{ +public: + CComCritSectLock(CComCriticalSection &cs, bool fInitialLock = true) + : CComCritSectLockManual(cs) + { + if (fInitialLock) + { + HRESULT hrc = Lock(); + if (FAILED(hrc)) + throw hrc; + } + } + +private: + CComCritSectLock(const CComCritSectLock&) throw(); // Do not call. + CComCritSectLock &operator=(const CComCritSectLock &) throw(); // Do not call. +}; +#endif + +class CComFakeCriticalSection +{ +public: + HRESULT Lock() throw() + { + return S_OK; + } + HRESULT Unlock() throw() + { + return S_OK; + } + HRESULT Init() throw() + { + return S_OK; + } + HRESULT Term() throw() + { + return S_OK; + } +}; + +class CComAutoCriticalSection : public CComCriticalSection +{ +public: + CComAutoCriticalSection() + { + HRESULT hrc = CComCriticalSection::Init(); + if (FAILED(hrc)) + throw hrc; + } + ~CComAutoCriticalSection() throw() + { + CComCriticalSection::Term(); + } +private : + HRESULT Init() throw(); // Do not call. + HRESULT Term() throw(); // Do not call. +}; + +class CComAutoDeleteCriticalSection : public CComCriticalSection +{ +public: + CComAutoDeleteCriticalSection(): m_fInit(false) + { + } + + ~CComAutoDeleteCriticalSection() throw() + { + if (!m_fInit) + return; + m_fInit = false; + CComCriticalSection::Term(); + } + + HRESULT Init() throw() + { + Assert(!m_fInit); + HRESULT hrc = CComCriticalSection::Init(); + if (SUCCEEDED(hrc)) + m_fInit = true; + return hrc; + } + + HRESULT Lock() + { + Assert(m_fInit); + return CComCriticalSection::Lock(); + } + + HRESULT Unlock() + { + Assert(m_fInit); + return CComCriticalSection::Unlock(); + } + +private: + HRESULT Term() throw(); + bool m_fInit; +}; + + +class CComMultiThreadModelNoCS +{ +public: + static ULONG WINAPI Increment(LONG *pL) throw() + { + return InterlockedIncrement(pL); + } + static ULONG WINAPI Decrement(LONG *pL) throw() + { + return InterlockedDecrement(pL); + } + typedef CComFakeCriticalSection AutoCriticalSection; + typedef CComFakeCriticalSection AutoDeleteCriticalSection; + typedef CComMultiThreadModelNoCS ThreadModelNoCS; +}; + +class CComMultiThreadModel +{ +public: + static ULONG WINAPI Increment(LONG *pL) throw() + { + return InterlockedIncrement(pL); + } + static ULONG WINAPI Decrement(LONG *pL) throw() + { + return InterlockedDecrement(pL); + } + typedef CComAutoCriticalSection AutoCriticalSection; + typedef CComAutoDeleteCriticalSection AutoDeleteCriticalSection; + typedef CComMultiThreadModelNoCS ThreadModelNoCS; +}; + +class ATL_NO_VTABLE CAtlModule +{ +public: + static GUID m_LibID; + CComCriticalSection m_csStaticDataInitAndTypeInfo; + + CAtlModule() throw() + { + // One instance only per linking namespace! + AssertMsg(!_pAtlModule, ("CAtlModule: trying to create more than one instance per linking namespace\n")); + + fInit = false; + + m_cLock = 0; + m_pTermFuncs = NULL; + _pAtlModule = this; + + if (FAILED(m_csStaticDataInitAndTypeInfo.Init())) + { + AssertMsgFailed(("CAtlModule: failed to init critsect\n")); + return; + } + fInit = true; + } + + void Term() throw() + { + if (!fInit) + return; + + // Call all term functions. + if (m_pTermFuncs) + { + _ATL_TERMFUNC_ELEM *p = m_pTermFuncs; + _ATL_TERMFUNC_ELEM *pNext; + while (p) + { + p->pfn(p->pv); + pNext = p->pNext; + delete p; + p = pNext; + } + m_pTermFuncs = NULL; + } + m_csStaticDataInitAndTypeInfo.Term(); + fInit = false; + } + + virtual ~CAtlModule() throw() + { + Term(); + } + + virtual LONG Lock() throw() + { + return CComMultiThreadModel::Increment(&m_cLock); + } + + virtual LONG Unlock() throw() + { + return CComMultiThreadModel::Decrement(&m_cLock); + } + + virtual LONG GetLockCount() throw() + { + return m_cLock; + } + + HRESULT AddTermFunc(PFNATLTERMFUNC pfn, void *pv) + { + _ATL_TERMFUNC_ELEM *pNew = new(std::nothrow) _ATL_TERMFUNC_ELEM; + if (!pNew) + return E_OUTOFMEMORY; + pNew->pfn = pfn; + pNew->pv = pv; + CComCritSectLockManual<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo); + HRESULT hrc = lock.Lock(); + if (SUCCEEDED(hrc)) + { + pNew->pNext = m_pTermFuncs; + m_pTermFuncs = pNew; + } + else + { + delete pNew; + AssertMsgFailed(("CComModule::AddTermFunc: failed to lock critsect\n")); + } + return hrc; + } + +protected: + bool fInit; + LONG m_cLock; + _ATL_TERMFUNC_ELEM *m_pTermFuncs; +}; + +__declspec(selectany) GUID CAtlModule::m_LibID = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} }; + +struct _ATL_COM_MODULE +{ + HINSTANCE m_hInstTypeLib; + CComCriticalSection m_csObjMap; +}; + +#ifndef _delayimp_h +extern "C" IMAGE_DOS_HEADER __ImageBase; +#endif + +class CAtlComModule : public _ATL_COM_MODULE +{ +public: + static bool m_fInitFailed; + CAtlComModule() throw() + { + m_hInstTypeLib = reinterpret_cast<HINSTANCE>(&__ImageBase); + + if (FAILED(m_csObjMap.Init())) + { + AssertMsgFailed(("CAtlComModule: critsect init failed\n")); + m_fInitFailed = true; + return; + } + } + + ~CAtlComModule() + { + Term(); + } + + void Term() + { + m_csObjMap.Term(); + } +}; + +__declspec(selectany) bool CAtlComModule::m_fInitFailed = false; +__declspec(selectany) CAtlComModule _AtlComModule; + +template <class T> class ATL_NO_VTABLE CAtlModuleT : public CAtlModule +{ +public: + CAtlModuleT() throw() + { + T::InitLibId(); + } + + static void InitLibId() throw() + { + } +}; + +/** + * + * This class not _not_ be statically instantiated as a global variable! It may + * use VBoxRT before it's initialized otherwise, messing up logging and whatnot. + * + * When possible create the instance inside the TrustedMain() or main() as a + * stack variable. In DLLs use 'new' to instantiate it in the DllMain function. + */ +class CComModule : public CAtlModuleT<CComModule> +{ +public: + CComModule() + { + // One instance only per linking namespace! + AssertMsg(!_pModule, ("CComModule: trying to create more than one instance per linking namespace\n")); + _pModule = this; + m_pObjMap = NULL; + } + + ~CComModule() + { + } + + _ATL_OBJMAP_ENTRY *m_pObjMap; + HRESULT Init(_ATL_OBJMAP_ENTRY *p, HINSTANCE h, const GUID *pLibID = NULL) throw() + { + RT_NOREF1(h); + + if (pLibID) + m_LibID = *pLibID; + + // Go over the object map to do some sanity checking, making things + // crash early if something is seriously busted. + _ATL_OBJMAP_ENTRY *pEntry; + if (p != (_ATL_OBJMAP_ENTRY *)-1) + { + m_pObjMap = p; + if (m_pObjMap) + { + pEntry = m_pObjMap; + while (pEntry->pclsid) + pEntry++; + } + } + return S_OK; + } + + void Term() throw() + { + _ATL_OBJMAP_ENTRY *pEntry; + if (m_pObjMap) + { + pEntry = m_pObjMap; + while (pEntry->pclsid) + { + if (pEntry->pCF) + pEntry->pCF->Release(); + pEntry->pCF = NULL; + pEntry++; + } + } + + CAtlModuleT<CComModule>::Term(); + } + + HRESULT GetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) throw() + { + *ppv = NULL; + HRESULT hrc = S_OK; + + if (m_pObjMap) + { + const _ATL_OBJMAP_ENTRY *pEntry = m_pObjMap; + + while (pEntry->pclsid) + { + if (pEntry->pfnGetClassObject && rclsid == *pEntry->pclsid) + { + if (!pEntry->pCF) + { + CComCritSectLockManual<CComCriticalSection> lock(_AtlComModule.m_csObjMap); + hrc = lock.Lock(); + if (FAILED(hrc)) + { + AssertMsgFailed(("CComModule::GetClassObject: failed to lock critsect\n")); + break; + } + + if (!pEntry->pCF) + { + hrc = pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (void **)&pEntry->pCF); + } + } + + if (pEntry->pCF) + { + hrc = pEntry->pCF->QueryInterface(riid, ppv); + } + break; + } + pEntry++; + } + } + + return hrc; + } + + // For EXE only: register all class factories with COM. + HRESULT RegisterClassObjects(DWORD dwClsContext, DWORD dwFlags) throw() + { + HRESULT hrc = S_OK; + _ATL_OBJMAP_ENTRY *pEntry; + if (m_pObjMap) + { + pEntry = m_pObjMap; + while (pEntry->pclsid && SUCCEEDED(hrc)) + { + if (pEntry->pfnGetClassObject) + { + IUnknown *p; + hrc = pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (void **)&p); + if (SUCCEEDED(hrc)) + hrc = CoRegisterClassObject(*(pEntry->pclsid), p, dwClsContext, dwFlags, &pEntry->dwRegister); + if (p) + p->Release(); + } + pEntry++; + } + } + return hrc; + } + // For EXE only: revoke all class factories with COM. + HRESULT RevokeClassObjects() throw() + { + HRESULT hrc = S_OK; + _ATL_OBJMAP_ENTRY *pEntry; + if (m_pObjMap != NULL) + { + pEntry = m_pObjMap; + while (pEntry->pclsid && SUCCEEDED(hrc)) + { + if (pEntry->dwRegister) + hrc = CoRevokeClassObject(pEntry->dwRegister); + pEntry++; + } + } + return hrc; + } +}; + + +template <class T> class CComCreator +{ +public: + static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, void **ppv) + { + AssertReturn(ppv, E_POINTER); + *ppv = NULL; + HRESULT hrc = E_OUTOFMEMORY; + T *p = new(std::nothrow) T(pv); + if (p) + { + p->SetVoid(pv); + p->InternalFinalConstructAddRef(); + hrc = p->_AtlInitialConstruct(); + if (SUCCEEDED(hrc)) + hrc = p->FinalConstruct(); + p->InternalFinalConstructRelease(); + if (SUCCEEDED(hrc)) + hrc = p->QueryInterface(riid, ppv); + if (FAILED(hrc)) + delete p; + } + return hrc; + } +}; + +template <HRESULT hrc> class CComFailCreator +{ +public: + static HRESULT WINAPI CreateInstance(void *, REFIID, void **ppv) + { + AssertReturn(ppv, E_POINTER); + *ppv = NULL; + + return hrc; + } +}; + +template <class T1, class T2> class CComCreator2 +{ +public: + static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, void **ppv) + { + AssertReturn(ppv, E_POINTER); + + return !pv ? T1::CreateInstance(NULL, riid, ppv) : T2::CreateInstance(pv, riid, ppv); + } +}; + +template <class Base> class CComObjectCached : public Base +{ +public: + CComObjectCached(void * = NULL) + { + } + virtual ~CComObjectCached() + { + // Catch refcount screwups by setting refcount to -(LONG_MAX/2). + m_iRef = -(LONG_MAX/2); + FinalRelease(); + } + STDMETHOD_(ULONG, AddRef)() throw() + { + // If you get errors about undefined InternalAddRef then Base does not + // derive from CComObjectRootEx. + ULONG l = InternalAddRef(); + if (l == 2) + { + AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n")); + _pAtlModule->Lock(); + } + return l; + } + STDMETHOD_(ULONG, Release)() throw() + { + // If you get errors about undefined InternalRelease then Base does not + // derive from CComObjectRootEx. + ULONG l = InternalRelease(); + if (l == 0) + delete this; + else if (l == 1) + { + AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n")); + _pAtlModule->Unlock(); + } + return l; + } + STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw() + { + // If you get errors about undefined _InternalQueryInterface then + // double check BEGIN_COM_MAP in the class definition. + return _InternalQueryInterface(iid, ppvObj); + } + static HRESULT WINAPI CreateInstance(CComObjectCached<Base> **pp) throw() + { + AssertReturn(pp, E_POINTER); + *pp = NULL; + + HRESULT hrc = E_OUTOFMEMORY; + CComObjectCached<Base> *p = new(std::nothrow) CComObjectCached<Base>(); + if (p) + { + p->SetVoid(NULL); + p->InternalFinalConstructAddRef(); + hrc = p->_AtlInitialConstruct(); + if (SUCCEEDED(hrc)) + hrc = p->FinalConstruct(); + p->InternalFinalConstructRelease(); + if (FAILED(hrc)) + delete p; + else + *pp = p; + } + return hrc; + } +}; + +template <class Base> class CComObjectNoLock : public Base +{ +public: + CComObjectNoLock(void * = NULL) + { + } + virtual ~CComObjectNoLock() + { + // Catch refcount screwups by setting refcount to -(LONG_MAX/2). + m_iRef = -(LONG_MAX/2); + FinalRelease(); + } + STDMETHOD_(ULONG, AddRef)() throw() + { + // If you get errors about undefined InternalAddRef then Base does not + // derive from CComObjectRootEx. + return InternalAddRef(); + } + STDMETHOD_(ULONG, Release)() throw() + { + // If you get errors about undefined InternalRelease then Base does not + // derive from CComObjectRootEx. + ULONG l = InternalRelease(); + if (l == 0) + delete this; + return l; + } + STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw() + { + // If you get errors about undefined _InternalQueryInterface then + // double check BEGIN_COM_MAP in the class definition. + return _InternalQueryInterface(iid, ppvObj); + } +}; + +class CComTypeInfoHolder +{ + /** @todo implement type info caching, making stuff more efficient - would we benefit? */ +public: + const GUID *m_pGUID; + const GUID *m_pLibID; + WORD m_iMajor; + WORD m_iMinor; + ITypeInfo *m_pTInfo; + + HRESULT GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) + { + if (iTInfo != 0) + return DISP_E_BADINDEX; + return GetTI(lcid, ppTInfo); + } + HRESULT GetIDsOfNames(REFIID riid, LPOLESTR *pwszNames, UINT cNames, LCID lcid, DISPID *pDispID) + { + RT_NOREF1(riid); /* should be IID_NULL */ + HRESULT hrc = FetchTI(lcid); + if (m_pTInfo) + hrc = m_pTInfo->GetIDsOfNames(pwszNames, cNames, pDispID); + return hrc; + } + HRESULT Invoke(IDispatch *p, DISPID DispID, REFIID riid, LCID lcid, WORD iFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) + { + RT_NOREF1(riid); /* should be IID_NULL */ + HRESULT hrc = FetchTI(lcid); + if (m_pTInfo) + hrc = m_pTInfo->Invoke(p, DispID, iFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + return hrc; + } +private: + static void __stdcall Cleanup(void *pv) + { + AssertReturnVoid(pv); + CComTypeInfoHolder *p = (CComTypeInfoHolder *)pv; + if (p->m_pTInfo != NULL) + p->m_pTInfo->Release(); + p->m_pTInfo = NULL; + } + + HRESULT GetTI(LCID lcid) + { + AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n")); + Assert(m_pLibID && m_pGUID); + if (m_pTInfo) + return S_OK; + + CComCritSectLockManual<CComCriticalSection> lock(_pAtlModule->m_csStaticDataInitAndTypeInfo); + HRESULT hrc = lock.Lock(); + if (SUCCEEDED(hrc)) + { + ITypeLib *pTypeLib = NULL; + Assert(*m_pLibID != GUID_NULL); + hrc = LoadRegTypeLib(*m_pLibID, m_iMajor, m_iMinor, lcid, &pTypeLib); + if (SUCCEEDED(hrc)) + { + ITypeInfo *pTypeInfo; + hrc = pTypeLib->GetTypeInfoOfGuid(*m_pGUID, &pTypeInfo); + if (SUCCEEDED(hrc)) + { + ITypeInfo2 *pTypeInfo2; + if (SUCCEEDED(pTypeInfo->QueryInterface(__uuidof(ITypeInfo2), (void **)&pTypeInfo2))) + { + pTypeInfo->Release(); + pTypeInfo = pTypeInfo2; + } + m_pTInfo = pTypeInfo; + _pAtlModule->AddTermFunc(Cleanup, (void *)this); + } + pTypeLib->Release(); + } + } + return hrc; + } + HRESULT GetTI(LCID lcid, ITypeInfo **ppTInfo) + { + AssertReturn(ppTInfo, E_POINTER); + HRESULT hrc = S_OK; + if (!m_pTInfo) + hrc = GetTI(lcid); + if (m_pTInfo) + { + m_pTInfo->AddRef(); + hrc = S_OK; + } + *ppTInfo = m_pTInfo; + return hrc; + } + HRESULT FetchTI(LCID lcid) + { + if (!m_pTInfo) + return GetTI(lcid); + return S_OK; + } +}; + +template <class ThreadModel> class CComObjectRootEx +{ +public: + typedef ThreadModel _ThreadModel; + CComObjectRootEx() + { + m_iRef = 0L; + } + ~CComObjectRootEx() + { + } + ULONG InternalAddRef() + { + Assert(m_iRef != -1L); + return ThreadModel::Increment(&m_iRef); + } + ULONG InternalRelease() + { +#ifdef VBOX_STRICT + LONG c = ThreadModel::Decrement(&m_iRef); + AssertMsg(c >= -(LONG_MAX / 2), /* See ~CComObjectNoLock, ~CComObject & ~CComAggObject. */ + ("Release called on object which has been already destroyed!\n")); + return c; +#else + return ThreadModel::Decrement(&m_iRef); +#endif + } + ULONG OuterAddRef() + { + return m_pOuterUnknown->AddRef(); + } + ULONG OuterRelease() + { + return m_pOuterUnknown->Release(); + } + HRESULT OuterQueryInterface(REFIID iid, void **ppvObject) + { + return m_pOuterUnknown->QueryInterface(iid, ppvObject); + } + HRESULT _AtlInitialConstruct() + { + return m_CritSect.Init(); + } + void Lock() + { + m_CritSect.Lock(); + } + void Unlock() + { + m_CritSect.Unlock(); + } + void SetVoid(void *) + { + } + void InternalFinalConstructAddRef() + { + } + void InternalFinalConstructRelease() + { + Assert(m_iRef == 0); + } + HRESULT FinalConstruct() + { + return S_OK; + } + void FinalRelease() + { + } + static HRESULT WINAPI InternalQueryInterface(void *pThis, const _ATL_INTMAP_ENTRY *pEntries, REFIID iid, void **ppvObj) + { + AssertReturn(pThis, E_INVALIDARG); + AssertReturn(pEntries, E_INVALIDARG); + AssertReturn(ppvObj, E_POINTER); + *ppvObj = NULL; + if (iid == IID_IUnknown) + { + // For IUnknown use first interface, must be simple map entry. + Assert(pEntries->pFunc == COM_SIMPLEMAPENTRY); + IUnknown *pObj = (IUnknown *)((INT_PTR)pThis + pEntries->dw); + pObj->AddRef(); + *ppvObj = pObj; + return S_OK; + } + while (pEntries->pFunc) + { + if (iid == *pEntries->piid) + { + if (pEntries->pFunc == COM_SIMPLEMAPENTRY) + { + IUnknown *pObj = (IUnknown *)((INT_PTR)pThis + pEntries->dw); + pObj->AddRef(); + *ppvObj = pObj; + return S_OK; + } + else + return pEntries->pFunc(pThis, iid, ppvObj, pEntries->dw); + } + pEntries++; + } + return E_NOINTERFACE; + } + static HRESULT WINAPI _Delegate(void *pThis, REFIID iid, void **ppvObj, DWORD_PTR dw) + { + AssertPtrReturn(pThis, E_NOINTERFACE); + IUnknown *pObj = *(IUnknown **)((DWORD_PTR)pThis + dw); + // If this assertion fails then the object has a delegation with a NULL + // object pointer, which is highly unusual often means that the pointer + // was not set up correctly. Check the COM interface map of the class + // for bugs with initializing. + AssertPtrReturn(pObj, E_NOINTERFACE); + return pObj->QueryInterface(iid, ppvObj); + } + + union + { + LONG m_iRef; + IUnknown *m_pOuterUnknown; + }; +private: + typename ThreadModel::AutoDeleteCriticalSection m_CritSect; +}; + +template <class Base> class CComObject : public Base +{ +public: + CComObject(void * = NULL) throw() + { + AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n")); + _pAtlModule->Lock(); + } + virtual ~CComObject() throw() + { + AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n")); + // Catch refcount screwups by setting refcount to -(LONG_MAX/2). + m_iRef = -(LONG_MAX/2); + FinalRelease(); + _pAtlModule->Unlock(); + } + STDMETHOD_(ULONG, AddRef)() + { + // If you get errors about undefined InternalAddRef then Base does not + // derive from CComObjectRootEx. + return InternalAddRef(); + } + STDMETHOD_(ULONG, Release)() + { + // If you get errors about undefined InternalRelease then Base does not + // derive from CComObjectRootEx. + ULONG l = InternalRelease(); + if (l == 0) + delete this; + return l; + } + STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw() + { + // If you get errors about undefined _InternalQueryInterface then + // double check BEGIN_COM_MAP in the class definition. + return _InternalQueryInterface(iid, ppvObj); + } + + static HRESULT WINAPI CreateInstance(CComObject<Base> **pp) throw() + { + AssertReturn(pp, E_POINTER); + *pp = NULL; + + HRESULT hrc = E_OUTOFMEMORY; + CComObject<Base> *p = NULL; + try + { + p = new CComObject<Base>(); + } + catch (std::bad_alloc &) + { + p = NULL; + } + if (p) + { + p->InternalFinalConstructAddRef(); + try + { + hrc = p->_AtlInitialConstruct(); + if (SUCCEEDED(hrc)) + hrc = p->FinalConstruct(); + } + catch (std::bad_alloc &) + { + hrc = E_OUTOFMEMORY; + } + p->InternalFinalConstructRelease(); + if (FAILED(hrc)) + { + delete p; + p = NULL; + } + } + *pp = p; + return hrc; + } +}; + +template <class T, const IID *piid, const GUID *pLibID, WORD iMajor = 1, WORD iMinor = 0> class ATL_NO_VTABLE IDispatchImpl : public T +{ +public: + // IDispatch + STDMETHOD(GetTypeInfoCount)(UINT *pcTInfo) + { + if (!pcTInfo) + return E_POINTER; + *pcTInfo = 1; + return S_OK; + } + STDMETHOD(GetTypeInfo)(UINT cTInfo, LCID lcid, ITypeInfo **ppTInfo) + { + return tih.GetTypeInfo(cTInfo, lcid, ppTInfo); + } + STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR *pwszNames, UINT cNames, LCID lcid, DISPID *pDispID) + { + return tih.GetIDsOfNames(riid, pwszNames, cNames, lcid, pDispID); + } + STDMETHOD(Invoke)(DISPID DispID, REFIID riid, LCID lcid, WORD iFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) + { + return tih.Invoke((IDispatch *)this, DispID, riid, lcid, iFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + } +protected: + static CComTypeInfoHolder tih; + static HRESULT GetTI(LCID lcid, ITypeInfo **ppTInfo) + { + return tih.GetTI(lcid, ppTInfo); + } +}; + +template <class T, const IID *piid, const GUID *pLibID, WORD iMajor, WORD iMinor> CComTypeInfoHolder IDispatchImpl<T, piid, pLibID, iMajor, iMinor>::tih = { piid, pLibID, iMajor, iMinor, NULL }; + + +template <class Base> class CComContainedObject : public Base +{ +public: + CComContainedObject(void *pv) + { + m_pOuterUnknown = (IUnknown *)pv; + } + + STDMETHOD_(ULONG, AddRef)() throw() + { + return OuterAddRef(); + } + STDMETHOD_(ULONG, Release)() throw() + { + return OuterRelease(); + } + STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw() + { + return OuterQueryInterface(iid, ppvObj); + } +}; + +template <class Aggregated> class CComAggObject : + public IUnknown, + public CComObjectRootEx<typename Aggregated::_ThreadModel::ThreadModelNoCS> +{ +public: + CComAggObject(void *pv) : + m_Aggregated(pv) + { + AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n")); + _pAtlModule->Lock(); + } + virtual ~CComAggObject() + { + AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n")); + // Catch refcount screwups by setting refcount to -(LONG_MAX/2). + m_iRef = -(LONG_MAX/2); + FinalRelease(); + _pAtlModule->Unlock(); + } + HRESULT _AtlInitialConstruct() + { + HRESULT hrc = m_Aggregated._AtlInitialConstruct(); + if (SUCCEEDED(hrc)) + { + hrc = CComObjectRootEx<typename Aggregated::_ThreadModel::ThreadModelNoCS>::_AtlInitialConstruct(); + } + return hrc; + } + HRESULT FinalConstruct() + { + CComObjectRootEx<Aggregated::_ThreadModel::ThreadModelNoCS>::FinalConstruct(); + return m_Aggregated.FinalConstruct(); + } + void FinalRelease() + { + CComObjectRootEx<Aggregated::_ThreadModel::ThreadModelNoCS>::FinalRelease(); + m_Aggregated.FinalRelease(); + } + + STDMETHOD_(ULONG, AddRef)() + { + return InternalAddRef(); + } + STDMETHOD_(ULONG, Release)() + { + ULONG l = InternalRelease(); + if (l == 0) + delete this; + return l; + } + STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) + { + AssertReturn(ppvObj, E_POINTER); + *ppvObj = NULL; + + HRESULT hrc = S_OK; + if (iid == __uuidof(IUnknown)) + { + *ppvObj = (void *)(IUnknown *)this; + AddRef(); + } + else + hrc = m_Aggregated._InternalQueryInterface(iid, ppvObj); + return hrc; + } + static HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, CComAggObject<Aggregated> **pp) + { + AssertReturn(pp, E_POINTER); + *pp = NULL; + + HRESULT hrc = E_OUTOFMEMORY; + CComAggObject<Aggregated> *p = new(std::nothrow) CComAggObject<Aggregated>(pUnkOuter); + if (p) + { + p->SetVoid(NULL); + p->InternalFinalConstructAddRef(); + hrc = p->_AtlInitialConstruct(); + if (SUCCEEDED(hrc)) + hrc = p->FinalConstruct(); + p->InternalFinalConstructRelease(); + if (FAILED(hrc)) + delete p; + else + *pp = p; + } + return hrc; + } + + CComContainedObject<Aggregated> m_Aggregated; +}; + +class CComClassFactory: + public IClassFactory, + public CComObjectRootEx<CComMultiThreadModel> +{ +public: + BEGIN_COM_MAP(CComClassFactory) + COM_INTERFACE_ENTRY(IClassFactory) + END_COM_MAP() + + virtual ~CComClassFactory() + { + } + + // IClassFactory + STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj) + { + Assert(m_pfnCreateInstance); + HRESULT hrc = E_POINTER; + if (ppvObj) + { + *ppvObj = NULL; + if (pUnkOuter && riid != __uuidof(IUnknown)) + { + AssertMsgFailed(("CComClassFactory: cannot create an aggregated object other than IUnknown\n")); + hrc = CLASS_E_NOAGGREGATION; + } + else + hrc = m_pfnCreateInstance(pUnkOuter, riid, ppvObj); + } + return hrc; + } + + STDMETHOD(LockServer)(BOOL fLock) + { + AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n")); + if (fLock) + _pAtlModule->Lock(); + else + _pAtlModule->Unlock(); + return S_OK; + } + + // Set creator for use by the factory. + void SetVoid(void *pv) + { + m_pfnCreateInstance = (PFNCREATEINSTANCE)pv; + } + + PFNCREATEINSTANCE m_pfnCreateInstance; +}; + +template <class T> class CComClassFactorySingleton : public CComClassFactory +{ +public: + CComClassFactorySingleton() : + m_hrc(S_OK), + m_pObj(NULL) + { + } + virtual ~CComClassFactorySingleton() + { + if (m_pObj) + m_pObj->Release(); + } + // IClassFactory + STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **pvObj) + { + HRESULT hrc = E_POINTER; + if (ppvObj) + { + *ppvObj = NULL; + // Singleton factories do not support aggregation. + AssertReturn(!pUnkOuter, CLASS_E_NOAGGREGATION); + + // Test if singleton is already created. Do it outside the lock, + // relying on atomic checks. Remember the inherent race! + if (SUCCEEDED(m_hrc) && !m_pObj) + { + Lock(); + // Make sure that the module is in use, otherwise the + // module can terminate while we're creating a new + // instance, which leads to strange errors. + LockServer(true); + __try + { + // Repeat above test to avoid races when multiple threads + // want to create a singleton simultaneously. + if (SUCCEEDED(m_hrc) && !m_pObj) + { + CComObjectCached<T> *p; + m_hrc = CComObjectCached<T>::CreateInstance(&p); + if (SUCCEEDED(m_hrc)) + { + m_hrc = p->QueryInterface(IID_IUnknown, (void **)&m_pObj); + if (FAILED(m_hrc)) + { + delete p; + } + } + } + } + __finally + { + Unlock(); + LockServer(false); + } + } + if (SUCCEEDED(m_hrc)) + { + hrc = m_pObj->QueryInterface(riid, ppvObj); + } + else + { + hrc = m_hrc; + } + } + return hrc; + } + HRESULT m_hrc; + IUnknown *m_pObj; +}; + + +template <class T, const CLSID *pClsID = &CLSID_NULL> class CComCoClass +{ +public: + DECLARE_CLASSFACTORY() + DECLARE_AGGREGATABLE(T) + static const CLSID& WINAPI GetObjectCLSID() + { + return *pClsID; + } + template <class Q> + static HRESULT CreateInstance(Q **pp) + { + return T::_CreatorClass::CreateInstance(NULL, __uuidof(Q), (void **)pp); + } +}; + +} /* namespace ATL */ + +#endif /* !VBOX_INCLUDED_com_microatl_h */ + diff --git a/include/VBox/com/mtlist.h b/include/VBox/com/mtlist.h new file mode 100644 index 00000000..0ff79bb1 --- /dev/null +++ b/include/VBox/com/mtlist.h @@ -0,0 +1,220 @@ +/* $Id: mtlist.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - Thread-safe list classes declaration. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_mtlist_h +#define VBOX_INCLUDED_com_mtlist_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/com/ptr.h> +#include <VBox/com/string.h> +#include <VBox/com/array.h> +#include <iprt/cpp/mtlist.h> + + +/** @defgroup grp_com_mtlist Thread-safe List Classes + * @ingroup grp_com + * @{ + */ + +/** + * Specialized thread-safe list class for using with com::ComPtr<C> + * + * @note: This is necessary cause ComPtr<IFACE> has a size of 8. + */ +template <typename C> +class RTCMTList< ComPtr<C> >: public RTCListBase< ComPtr<C>, ComPtr<C>*, true> +{ + /* Traits */ + typedef ComPtr<C> T; + typedef T *ITYPE; + static const bool MT = true; + typedef RTCListBase<T, ITYPE, MT> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCMTList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * Specialized thread-safe list class for using with com::ComObjPtr<C> + * + * @note: This is necessary cause ComObjPtr<IFACE> has a size of 8. + */ +template <typename C> +class RTCMTList< ComObjPtr<C> >: public RTCListBase< ComObjPtr<C>, ComObjPtr<C>*, true> +{ + /* Traits */ + typedef ComObjPtr<C> T; + typedef T *ITYPE; + static const bool MT = true; + typedef RTCListBase<T, ITYPE, MT> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCMTList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * Specialized thread-safe list class for using with com::Utf8Str. + * + * The class offers methods for importing com::SafeArray's of com::Bstr's. + */ +template <> +class RTCMTList<com::Utf8Str>: public RTCListBase<com::Utf8Str, com::Utf8Str *, true> +{ + /* Traits */ + typedef com::Utf8Str T; + typedef T *ITYPE; + static const bool MT = true; + typedef RTCListBase<T, ITYPE, MT> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCMTList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /** + * Creates a copy of another list. + * + * The other list will be fully copied and the capacity will be the same as + * the size of the other list. The com::Bstr's are silently converted to + * com::Utf8Str's. + * + * @param other The list to copy. + * @throws std::bad_alloc + */ + RTCMTList(ComSafeArrayIn(IN_BSTR, other)) + { + com::SafeArray<IN_BSTR> sfaOther(ComSafeArrayInArg(other)); + size_t const cElementsOther = sfaOther.size(); + resizeArray(cElementsOther); + m_cElements = cElementsOther; + for (size_t i = 0; i < cElementsOther; ++i) + RTCListHelper<T, ITYPE>::set(m_pArray, i, T(sfaOther[i])); + } + + /** + * Creates a copy of another list. + * + * The other list will be fully copied and the capacity will be the same as + * the size of the other list. The com::Bstr's are silently converted to + * com::Utf8Str's. + * + * @param other The list to copy. + * @throws std::bad_alloc + */ + RTCMTList(const com::SafeArray<IN_BSTR> &other) + : BASE(other.size()) + { + for (size_t i = 0; i < m_cElements; ++i) + RTCListHelper<T, ITYPE>::set(m_pArray, i, T(other[i])); + } + + /** + * Copy the items of the other list into this list. All previous items of + * this list are deleted. + * + * @param other The list to copy. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase<T, ITYPE, MT> &operator=(const com::SafeArray<IN_BSTR> &other) + { + m_guard.enterWrite(); + /* Values cleanup */ + RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements); + /* Copy */ + if (other.size() != m_cCapacity) + resizeArrayNoErase(other.size()); + m_cElements = other.size(); + for (size_t i = 0; i < other.size(); ++i) + RTCListHelper<T, ITYPE>::set(m_pArray, i, T(other[i])); + m_guard.leaveWrite(); + + return *this; + } + + /** + * Implicit conversion to a RTCString list. + * + * This allows the usage of the RTCString::join method with this list type. + * + * @return a converted const reference to this list. + */ + operator const RTCMTList<RTCString, RTCString*>&() + { + return *reinterpret_cast<RTCMTList<RTCString, RTCString*> *>(this); + } + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_mtlist_h */ + diff --git a/include/VBox/com/ptr.h b/include/VBox/com/ptr.h new file mode 100644 index 00000000..613d2d08 --- /dev/null +++ b/include/VBox/com/ptr.h @@ -0,0 +1,569 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - Smart COM pointer classes declaration. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_ptr_h +#define VBOX_INCLUDED_com_ptr_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Make sure all the stdint.h macros are included - must come first! */ +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#ifdef VBOX_WITH_XPCOM +# include <nsISupportsUtils.h> +#endif /* VBOX_WITH_XPCOM */ + +#include <VBox/com/defs.h> +#include <new> /* For bad_alloc. */ + + +/** @defgroup grp_com_ptr Smart COM Pointer Classes + * @ingroup grp_com + * @{ + */ + +#ifdef VBOX_WITH_XPCOM + +namespace com +{ +// declare a couple of XPCOM helper methods (defined in glue/com.cpp) +// so we don't have to include a ton of XPCOM implementation headers here +HRESULT GlueCreateObjectOnServer(const CLSID &clsid, + const char *serverName, + const nsIID &id, + void **ppobj); +HRESULT GlueCreateInstance(const CLSID &clsid, + const nsIID &id, + void **ppobj); +} + +#endif // VBOX_WITH_XPCOM + +/** + * COM autopointer class which takes care of all required reference counting. + * + * This automatically calls the required basic COM methods on COM pointers + * given to it: + * + * -- AddRef() gets called automatically whenever a new COM pointer is assigned + * to the ComPtr instance (either in the copy constructor or by assignment); + * + * -- Release() gets called automatically by the destructor and when an existing + * object gets released in assignment; + * + * -- QueryInterface() gets called automatically when COM pointers get converted + * from one interface to another. + * + * Example usage: + * + * @code + * + * { + * ComPtr<IMachine> pMachine = findMachine("blah"); // calls AddRef() + * ComPtr<IUnknown> pUnknown = pMachine; // calls QueryInterface() + * } # ComPtr destructor of both instances calls Release() + * + * @endcode + */ +template <class T> +class ComPtr +{ +public: + + /** + * Default constructor, sets up a NULL pointer. + */ + ComPtr() + : m_p(NULL) + { } + + /** + * Destructor. Calls Release() on the contained COM object. + */ + ~ComPtr() + { + cleanup(); + } + + /** + * Copy constructor from another ComPtr of any interface. + * + * This calls QueryInterface(T) and can result in a NULL pointer if the input + * pointer p does not support the ComPtr interface T. + * + * Does not call AddRef explicitly because if QueryInterface succeeded, then + * the refcount will have been increased by one already. + */ + template <class T2> + ComPtr(const ComPtr<T2> &that) + { + m_p = NULL; + if (!that.isNull()) + that->QueryInterface(COM_IIDOF(T), (void **)&m_p); + } + + /** + * Specialization: copy constructor from another ComPtr<T>. Calls AddRef(). + */ + ComPtr(const ComPtr &that) + { + copyFrom(that.m_p); + } + + /** + * Copy constructor from another interface pointer of any interface. + * + * This calls QueryInterface(T) and can result in a NULL pointer if the input + * pointer p does not support the ComPtr interface T. + * + * Does not call AddRef explicitly because if QueryInterface succeeded, then + * the refcount will have been increased by one already. + */ + template <class T2> + ComPtr(T2 *p) + { + m_p = NULL; + if (p) + p->QueryInterface(COM_IIDOF(T), (void **)&m_p); + } + + /** + * Specialization: copy constructor from a plain T * pointer. Calls AddRef(). + */ + ComPtr(T *that_p) + { + copyFrom(that_p); + } + + /** + * Assignment from another ComPtr of any interface. + * + * This calls QueryInterface(T) and can result in a NULL pointer if the input + * pointer p does not support the ComPtr interface T. + * + * Does not call AddRef explicitly because if QueryInterface succeeded, then + * the refcount will have been increased by one already. + */ + template <class T2> + ComPtr& operator=(const ComPtr<T2> &that) + { + return operator=((T2 *)that); + } + + /** + * Specialization of the previous: assignment from another ComPtr<T>. + * Calls Release() on the previous member pointer, if any, and AddRef() on the new one. + */ + ComPtr& operator=(const ComPtr &that) + { + return operator=((T *)that); + } + + /** + * Assignment from another interface pointer of any interface. + * + * This calls QueryInterface(T) and can result in a NULL pointer if the input + * pointer p does not support the ComPtr interface T. + * + * Does not call AddRef explicitly because if QueryInterface succeeded, then + * the refcount will have been increased by one already. + */ + template <class T2> + ComPtr& operator=(T2 *p) + { + cleanup(); + if (p) + p->QueryInterface(COM_IIDOF(T), (void **)&m_p); + return *this; + } + + /** + * Specialization of the previous: assignment from a plain T * pointer. + * Calls Release() on the previous member pointer, if any, and AddRef() on the new one. + */ + ComPtr& operator=(T *p) + { + cleanup(); + copyFrom(p); + return *this; + } + + /** + * Resets the ComPtr to NULL. Works like a NULL assignment except it avoids the templates. + */ + void setNull() + { + cleanup(); + } + + /** + * Returns true if the pointer is NULL. + */ + bool isNull() const + { + return (m_p == NULL); + } + + /** + * Returns true if the pointer is not NULL. + */ + bool isNotNull() const + { + return (m_p != NULL); + } + + bool operator<(T *p) const + { + return m_p < p; + } + + /** + * Conversion operator, most often used to pass ComPtr instances as + * parameters to COM method calls. + */ + operator T *() const + { + return m_p; + } + + /** + * Dereferences the instance (redirects the -> operator to the managed + * pointer). + */ + T *operator->() const + { + return m_p; + } + + /** + * Special method which allows using a ComPtr as an output argument of a COM method. + * The ComPtr will then accept the method's interface pointer without calling AddRef() + * itself, since by COM convention this must has been done by the method which created + * the object that is being accepted. + * + * The ComPtr destructor will then still invoke Release() so that the returned object + * can get cleaned up properly. + */ + T **asOutParam() + { + cleanup(); + return &m_p; + } + + /** + * Converts the contained pointer to a different interface + * by calling QueryInterface() on it. + * @param pp + * @return + */ + template <class T2> + HRESULT queryInterfaceTo(T2 **pp) const + { + if (pp) + { + if (m_p) + return m_p->QueryInterface(COM_IIDOF(T2), (void **)pp); + *pp = NULL; + return S_OK; + } + return E_INVALIDARG; + } + + /** + * Equality test operator. By COM definition, two COM objects are considered + * equal if their IUnknown interface pointers are equal. + */ + template <class T2> + bool operator==(T2 *p) + { + IUnknown *p1 = NULL; + bool fNeedsRelease1 = false; + if (m_p) + fNeedsRelease1 = (SUCCEEDED(m_p->QueryInterface(COM_IIDOF(IUnknown), (void **)&p1))); + + IUnknown *p2 = NULL; + bool fNeedsRelease2 = false; + if (p) + fNeedsRelease2 = (SUCCEEDED(p->QueryInterface(COM_IIDOF(IUnknown), (void **)&p2))); + + bool f = p1 == p2; + if (fNeedsRelease1) + p1->Release(); + if (fNeedsRelease2) + p2->Release(); + return f; + } + + /** + * Creates an in-process object of the given class ID and starts to + * manage a reference to the created object in case of success. + */ + HRESULT createInprocObject(const CLSID &clsid) + { + HRESULT rc; + T *obj = NULL; +#ifndef VBOX_WITH_XPCOM + rc = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, COM_IIDOF(T), + (void **)&obj); +#else /* VBOX_WITH_XPCOM */ + using namespace com; + rc = GlueCreateInstance(clsid, NS_GET_IID(T), (void **)&obj); +#endif /* VBOX_WITH_XPCOM */ + *this = obj; + if (SUCCEEDED(rc)) + obj->Release(); + return rc; + } + + /** + * Creates a local (out-of-process) object of the given class ID and starts + * to manage a reference to the created object in case of success. + * + * Note: In XPCOM, the out-of-process functionality is currently emulated + * through in-process wrapper objects (that start a dedicated process and + * redirect all object requests to that process). For this reason, this + * method is fully equivalent to #createInprocObject() for now. + */ + HRESULT createLocalObject(const CLSID &clsid) + { +#ifndef VBOX_WITH_XPCOM + HRESULT rc; + T *obj = NULL; + rc = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, COM_IIDOF(T), + (void **)&obj); + *this = obj; + if (SUCCEEDED(rc)) + obj->Release(); + return rc; +#else /* VBOX_WITH_XPCOM */ + return createInprocObject(clsid); +#endif /* VBOX_WITH_XPCOM */ + } + +#ifdef VBOX_WITH_XPCOM + /** + * Creates an object of the given class ID on the specified server and + * starts to manage a reference to the created object in case of success. + * + * @param serverName Name of the server to create an object within. + */ + HRESULT createObjectOnServer(const CLSID &clsid, const char *serverName) + { + T *obj = NULL; + HRESULT rc = GlueCreateObjectOnServer(clsid, serverName, NS_GET_IID(T), (void **)&obj); + *this = obj; + if (SUCCEEDED(rc)) + obj->Release(); + return rc; + } +#endif + +protected: + void copyFrom(T *p) + { + m_p = p; + if (m_p) + m_p->AddRef(); + } + + void cleanup() + { + if (m_p) + { + m_p->Release(); + m_p = NULL; + } + } + +public: + // Do NOT access this member unless you really know what you're doing! + T *m_p; +}; + +/** + * ComObjPtr is a more specialized variant of ComPtr designed to be used for implementation + * objects. For example, use ComPtr<IMachine> for a client pointer that calls the interface + * but ComObjPtr<Machine> for a pointer to an implementation object. + * + * The methods behave the same except that ComObjPtr has the additional createObject() + * method which allows for instantiating a new implementation object. + * + * Note: To convert a ComObjPtr<InterfaceImpl> to a ComObj<IInterface> you have + * to query the interface. See the following example code for the IProgress + * interface: + * + * @code + * + * { + * ComObjPtr<Progress> pProgress; // create the server side object + * pProgress.createObject(); // ... + * pProgress->init(...); // ... + * ComPtr<IProgress> pProgress2; // create an interface pointer + * pProgress.queryInterfaceTo(pProgress2.asOutParam()); // transfer the interface + * } + * + * @endcode + */ +template <class T> +class ComObjPtr : public ComPtr<T> +{ +public: + + ComObjPtr() + : ComPtr<T>() + {} + + ComObjPtr(const ComObjPtr &that) + : ComPtr<T>(that) + {} + + ComObjPtr(T *that_p) + : ComPtr<T>(that_p) + {} + + ComObjPtr& operator=(const ComObjPtr &that) + { + ComPtr<T>::operator=(that); + return *this; + } + + ComObjPtr& operator=(T *that_p) + { + ComPtr<T>::operator=(that_p); + return *this; + } + + /** + * Creates a new server-side object of the given component class and + * immediately starts to manage a pointer to the created object (the + * previous pointer, if any, is of course released when appropriate). + * + * @note Win32: when VBOX_COM_OUTOFPROC_MODULE is defined, the created + * object doesn't increase the lock count of the server module, as it + * does otherwise. + * + * @note In order to make it easier to use, this method does _not_ throw + * bad_alloc, but instead returns E_OUTOFMEMORY. + */ + HRESULT createObject() + { + HRESULT hrc; +#ifndef VBOX_WITH_XPCOM +# ifdef VBOX_COM_OUTOFPROC_MODULE + ATL::CComObjectNoLock<T> *obj = NULL; + try + { + obj = new ATL::CComObjectNoLock<T>(); + } + catch (std::bad_alloc &) + { + obj = NULL; + } + if (obj) + { + obj->InternalFinalConstructAddRef(); + try + { + hrc = obj->FinalConstruct(); + } + catch (std::bad_alloc &) + { + hrc = E_OUTOFMEMORY; + } + obj->InternalFinalConstructRelease(); + if (FAILED(hrc)) + { + delete obj; + obj = NULL; + } + } + else + hrc = E_OUTOFMEMORY; +# else + ATL::CComObject<T> *obj = NULL; + hrc = ATL::CComObject<T>::CreateInstance(&obj); +# endif +#else /* VBOX_WITH_XPCOM */ + ATL::CComObject<T> *obj; +# ifndef RT_EXCEPTIONS_ENABLED + obj = new ATL::CComObject<T>(); +# else + try + { + obj = new ATL::CComObject<T>(); + } + catch (std::bad_alloc &) + { + obj = NULL; + } +# endif + if (obj) + { +# ifndef RT_EXCEPTIONS_ENABLED + hrc = obj->FinalConstruct(); +# else + try + { + hrc = obj->FinalConstruct(); + } + catch (std::bad_alloc &) + { + hrc = E_OUTOFMEMORY; + } +# endif + if (FAILED(hrc)) + { + delete obj; + obj = NULL; + } + } + else + hrc = E_OUTOFMEMORY; +#endif /* VBOX_WITH_XPCOM */ + *this = obj; + return hrc; + } +}; + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_ptr_h */ + diff --git a/include/VBox/com/string.h b/include/VBox/com/string.h new file mode 100644 index 00000000..62d5abc1 --- /dev/null +++ b/include/VBox/com/string.h @@ -0,0 +1,1494 @@ +/* $Id: string.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - Smart string classes declaration. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_string_h +#define VBOX_INCLUDED_com_string_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Make sure all the stdint.h macros are included - must come first! */ +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#if defined(VBOX_WITH_XPCOM) +# include <nsMemory.h> +#endif + +#include "VBox/com/defs.h" +#include "VBox/com/assert.h" + +#include <iprt/mem.h> +#include <iprt/utf16.h> +#include <iprt/cpp/ministring.h> + + +/** @defgroup grp_com_str Smart String Classes + * @ingroup grp_com + * @{ + */ + +namespace com +{ + +class Utf8Str; + +// global constant in glue/string.cpp that represents an empty BSTR +extern const BSTR g_bstrEmpty; + +/** + * String class used universally in Main for COM-style Utf-16 strings. + * + * Unfortunately COM on Windows uses UTF-16 everywhere, requiring conversions + * back and forth since most of VirtualBox and our libraries use UTF-8. + * + * To make things more obscure, on Windows, a COM-style BSTR is not just a + * pointer to a null-terminated wide character array, but the four bytes (32 + * bits) BEFORE the memory that the pointer points to are a length DWORD. One + * must therefore avoid pointer arithmetic and always use SysAllocString and + * the like to deal with BSTR pointers, which manage that DWORD correctly. + * + * For platforms other than Windows, we provide our own versions of the Sys* + * functions in Main/xpcom/helpers.cpp which do NOT use length prefixes though + * to be compatible with how XPCOM allocates string parameters to public + * functions. + * + * The Bstr class hides all this handling behind a std::string-like interface + * and also provides automatic conversions to RTCString and Utf8Str instances. + * + * The one advantage of using the SysString* routines is that this makes it + * possible to use it as a type of member variables of COM/XPCOM components and + * pass their values to callers through component methods' output parameters + * using the #cloneTo() operation. Also, the class can adopt (take ownership + * of) string buffers returned in output parameters of COM methods using the + * #asOutParam() operation and correctly free them afterwards. + * + * Starting with VirtualBox 3.2, like Utf8Str, Bstr no longer differentiates + * between NULL strings and empty strings. In other words, Bstr("") and + * Bstr(NULL) behave the same. In both cases, Bstr allocates no memory, + * reports a zero length and zero allocated bytes for both, and returns an + * empty C wide string from raw(). + * + * @note All Bstr methods ASSUMES valid UTF-16 or UTF-8 input strings. + * The VirtualBox policy in this regard is to validate strings coming + * from external sources before passing them to Bstr or Utf8Str. + */ +class Bstr +{ +public: + + Bstr() + : m_bstr(NULL) + { } + + Bstr(const Bstr &that) + { + copyFrom((const OLECHAR *)that.m_bstr); + } + + Bstr(CBSTR that) + { + copyFrom((const OLECHAR *)that); + } + +#if defined(VBOX_WITH_XPCOM) + Bstr(const wchar_t *that) + { + AssertCompile(sizeof(wchar_t) == sizeof(OLECHAR)); + copyFrom((const OLECHAR *)that); + } +#endif + + Bstr(const RTCString &that) + { + copyFrom(that.c_str()); + } + + Bstr(const char *that) + { + copyFrom(that); + } + + Bstr(const char *a_pThat, size_t a_cchMax) + { + copyFromN(a_pThat, a_cchMax); + } + + ~Bstr() + { + setNull(); + } + + Bstr &operator=(const Bstr &that) + { + cleanupAndCopyFrom((const OLECHAR *)that.m_bstr); + return *this; + } + + Bstr &operator=(CBSTR that) + { + cleanupAndCopyFrom((const OLECHAR *)that); + return *this; + } + +#if defined(VBOX_WITH_XPCOM) + Bstr &operator=(const wchar_t *that) + { + cleanupAndCopyFrom((const OLECHAR *)that); + return *this; + } +#endif + + Bstr &setNull() + { + cleanup(); + return *this; + } + + /** + * Extended assignment method that returns a COM status code instead of an + * exception on failure. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_rSrcStr The source string + */ + HRESULT assignEx(const Bstr &a_rSrcStr) RT_NOEXCEPT + { + return cleanupAndCopyFromEx((const OLECHAR *)a_rSrcStr.m_bstr); + } + + /** + * Extended assignment method that returns a COM status code instead of an + * exception on failure. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_pSrcStr The source string + */ + HRESULT assignEx(CBSTR a_pSrcStr) RT_NOEXCEPT + { + return cleanupAndCopyFromEx((const OLECHAR *)a_pSrcStr); + } + + /** + * Assign the value of a RTCString/Utf8Str string, no exceptions. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_rSrcStr The source string + */ + HRESULT assignEx(RTCString const &a_rSrcStr) RT_NOEXCEPT + { + return cleanupAndCopyFromNoThrow(a_rSrcStr.c_str(), a_rSrcStr.length()); + } + + /** + * Assign the value of a RTCString/Utf8Str substring, no exceptions. + * + * @returns S_OK, E_OUTOFMEMORY or E_INVALIDARG. + * @param a_rSrcStr The source string + * @param a_offSrc The character (byte) offset of the substring. + * @param a_cchSrc The number of characters (bytes) to copy from the source + * string. + */ + HRESULT assignEx(RTCString const &a_rSrcStr, size_t a_offSrc, size_t a_cchSrc) RT_NOEXCEPT + { + size_t const cchTmp = a_rSrcStr.length(); + if ( a_offSrc + a_cchSrc < cchTmp + && a_offSrc < cchTmp) + return cleanupAndCopyFromNoThrow(a_rSrcStr.c_str() + a_offSrc, a_cchSrc); + return E_INVALIDARG; + } + + /** + * Assign the value of a zero terminated UTF-8 string, no exceptions. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_pszSrcStr The source string. + */ + HRESULT assignEx(const char *a_pszSrcStr) RT_NOEXCEPT + { + return cleanupAndCopyFromNoThrow(a_pszSrcStr, RTSTR_MAX); + } + + /** + * Assign the value of a UTF-8 substring, no exceptions. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_pszSrcStr The source string. + * @param a_cchSrc The number of characters (bytes) to copy from the source + * string. + */ + HRESULT assignEx(const char *a_pszSrcStr, size_t a_cchSrc) RT_NOEXCEPT + { + return cleanupAndCopyFromNoThrow(a_pszSrcStr, a_cchSrc); + } + +#ifdef _MSC_VER +# if _MSC_VER >= 1400 + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +# endif +#else + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +#endif + + /** Case sensitivity selector. */ + enum CaseSensitivity + { + CaseSensitive, + CaseInsensitive + }; + + /** + * Compares the member string to str. + * @param str + * @param cs Whether comparison should be case-sensitive. + * @return + */ + int compare(CBSTR str, CaseSensitivity cs = CaseSensitive) const + { + if (cs == CaseSensitive) + return ::RTUtf16Cmp((PRTUTF16)m_bstr, (PRTUTF16)str); + return ::RTUtf16LocaleICmp((PRTUTF16)m_bstr, (PRTUTF16)str); + } + + int compare(BSTR str, CaseSensitivity cs = CaseSensitive) const + { + return compare((CBSTR)str, cs); + } + + int compare(const Bstr &that, CaseSensitivity cs = CaseSensitive) const + { + return compare(that.m_bstr, cs); + } + + bool operator==(const Bstr &that) const { return !compare(that.m_bstr); } + bool operator==(CBSTR that) const { return !compare(that); } + bool operator==(BSTR that) const { return !compare(that); } + bool operator!=(const Bstr &that) const { return !!compare(that.m_bstr); } + bool operator!=(CBSTR that) const { return !!compare(that); } + bool operator!=(BSTR that) const { return !!compare(that); } + bool operator<(const Bstr &that) const { return compare(that.m_bstr) < 0; } + bool operator<(CBSTR that) const { return compare(that) < 0; } + bool operator<(BSTR that) const { return compare(that) < 0; } + bool operator<=(const Bstr &that) const { return compare(that.m_bstr) <= 0; } + bool operator<=(CBSTR that) const { return compare(that) <= 0; } + bool operator<=(BSTR that) const { return compare(that) <= 0; } + bool operator>(const Bstr &that) const { return compare(that.m_bstr) > 0; } + bool operator>(CBSTR that) const { return compare(that) > 0; } + bool operator>(BSTR that) const { return compare(that) > 0; } + bool operator>=(const Bstr &that) const { return compare(that.m_bstr) >= 0; } + bool operator>=(CBSTR that) const { return compare(that) >= 0; } + bool operator>=(BSTR that) const { return compare(that) >= 0; } + + /** + * Compares this string to an UTF-8 C style string. + * + * @retval 0 if equal + * @retval -1 if this string is smaller than the UTF-8 one. + * @retval 1 if the UTF-8 string is smaller than this. + * + * @param a_pszRight The string to compare with. + * @param a_enmCase Whether comparison should be case-sensitive. + */ + int compareUtf8(const char *a_pszRight, CaseSensitivity a_enmCase = CaseSensitive) const; + + /** Java style compare method. + * @returns true if @a a_pszRight equals this string. + * @param a_pszRight The (UTF-8) string to compare with. */ + bool equals(const char *a_pszRight) const { return compareUtf8(a_pszRight, CaseSensitive) == 0; } + + /** Java style case-insensitive compare method. + * @returns true if @a a_pszRight equals this string. + * @param a_pszRight The (UTF-8) string to compare with. */ + bool equalsIgnoreCase(const char *a_pszRight) const { return compareUtf8(a_pszRight, CaseInsensitive) == 0; } + + /** Java style compare method. + * @returns true if @a a_rThat equals this string. + * @param a_rThat The other Bstr instance to compare with. */ + bool equals(const Bstr &a_rThat) const { return compare(a_rThat.m_bstr, CaseSensitive) == 0; } + /** Java style case-insensitive compare method. + * @returns true if @a a_rThat equals this string. + * @param a_rThat The other Bstr instance to compare with. */ + bool equalsIgnoreCase(const Bstr &a_rThat) const { return compare(a_rThat.m_bstr, CaseInsensitive) == 0; } + + /** Java style compare method. + * @returns true if @a a_pThat equals this string. + * @param a_pThat The native const BSTR to compare with. */ + bool equals(CBSTR a_pThat) const { return compare(a_pThat, CaseSensitive) == 0; } + /** Java style case-insensitive compare method. + * @returns true if @a a_pThat equals this string. + * @param a_pThat The native const BSTR to compare with. */ + bool equalsIgnoreCase(CBSTR a_pThat) const { return compare(a_pThat, CaseInsensitive) == 0; } + + /** Java style compare method. + * @returns true if @a a_pThat equals this string. + * @param a_pThat The native BSTR to compare with. */ + bool equals(BSTR a_pThat) const { return compare(a_pThat, CaseSensitive) == 0; } + /** Java style case-insensitive compare method. + * @returns true if @a a_pThat equals this string. + * @param a_pThat The native BSTR to compare with. */ + bool equalsIgnoreCase(BSTR a_pThat) const { return compare(a_pThat, CaseInsensitive) == 0; } + + /** + * Checks if the string starts with @a a_rStart. + */ + bool startsWith(Bstr const &a_rStart) const; + /** + * Checks if the string starts with @a a_rStart. + */ + bool startsWith(RTCString const &a_rStart) const; + /** + * Checks if the string starts with @a a_pszStart. + */ + bool startsWith(const char *a_pszStart) const; + + /** + * Returns true if the member string has no length. + * This is true for instances created from both NULL and "" input strings. + * + * @note Always use this method to check if an instance is empty. Do not + * use length() because that may need to run through the entire string + * (Bstr does not cache string lengths). + */ + bool isEmpty() const { return m_bstr == NULL || *m_bstr == 0; } + + /** + * Returns true if the member string has a length of one or more. + * + * @returns true if not empty, false if empty (NULL or ""). + */ + bool isNotEmpty() const { return m_bstr != NULL && *m_bstr != 0; } + + size_t length() const { return isEmpty() ? 0 : ::RTUtf16Len((PRTUTF16)m_bstr); } + + /** + * Assigns the output of the string format operation (RTStrPrintf). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + * + * @throws std::bad_alloc On allocation error. Object state is undefined. + * + * @returns Reference to the object. + */ + Bstr &printf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + + /** + * Assigns the output of the string format operation (RTStrPrintf). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + * + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT printfNoThrow(const char *pszFormat, ...) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 2); + + /** + * Assigns the output of the string format operation (RTStrPrintfV). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param va Argument vector containing the arguments + * specified by the format string. + * + * @throws std::bad_alloc On allocation error. Object state is undefined. + * + * @returns Reference to the object. + */ + Bstr &printfV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + + /** + * Assigns the output of the string format operation (RTStrPrintfV). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param va Argument vector containing the arguments + * specified by the format string. + * + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT printfVNoThrow(const char *pszFormat, va_list va) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 0); + + /** @name Append methods and operators + * @{ */ + + /** + * Appends the string @a that to @a rThat. + * + * @param rThat The string to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(const Bstr &rThat); + + /** + * Appends the string @a that to @a rThat. + * + * @param rThat The string to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(const Bstr &rThat) RT_NOEXCEPT; + + /** + * Appends the UTF-8 string @a that to @a rThat. + * + * @param rThat The string to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(const RTCString &rThat); + + /** + * Appends the UTF-8 string @a that to @a rThat. + * + * @param rThat The string to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(const RTCString &rThat) RT_NOEXCEPT; + + /** + * Appends the UTF-16 string @a pszSrc to @a this. + * + * @param pwszSrc The C-style UTF-16 string to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(CBSTR pwszSrc); + + /** + * Appends the UTF-16 string @a pszSrc to @a this. + * + * @param pwszSrc The C-style UTF-16 string to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(CBSTR pwszSrc) RT_NOEXCEPT; + + /** + * Appends the UTF-8 string @a pszSrc to @a this. + * + * @param pszSrc The C-style string to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(const char *pszSrc); + + /** + * Appends the UTF-8 string @a pszSrc to @a this. + * + * @param pszSrc The C-style string to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(const char *pszSrc) RT_NOEXCEPT; + + /** + * Appends the a substring from @a rThat to @a this. + * + * @param rThat The string to append a substring from. + * @param offStart The start of the substring to append (UTF-16 + * offset, not codepoint). + * @param cwcMax The maximum number of UTF-16 units to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(const Bstr &rThat, size_t offStart, size_t cwcMax = RTSTR_MAX); + + /** + * Appends the a substring from @a rThat to @a this. + * + * @param rThat The string to append a substring from. + * @param offStart The start of the substring to append (UTF-16 + * offset, not codepoint). + * @param cwcMax The maximum number of UTF-16 units to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(const Bstr &rThat, size_t offStart, size_t cwcMax = RTSTR_MAX) RT_NOEXCEPT; + + /** + * Appends the a substring from UTF-8 @a rThat to @a this. + * + * @param rThat The string to append a substring from. + * @param offStart The start of the substring to append (byte offset, + * not codepoint). + * @param cchMax The maximum number of bytes to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(const RTCString &rThat, size_t offStart, size_t cchMax = RTSTR_MAX); + + /** + * Appends the a substring from UTF-8 @a rThat to @a this. + * + * @param rThat The string to append a substring from. + * @param offStart The start of the substring to append (byte offset, + * not codepoint). + * @param cchMax The maximum number of bytes to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(const RTCString &rThat, size_t offStart, size_t cchMax = RTSTR_MAX) RT_NOEXCEPT; + + /** + * Appends the first @a cchMax chars from UTF-16 string @a pszThat to @a this. + * + * @param pwszThat The C-style UTF-16 string to append. + * @param cchMax The maximum number of bytes to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(CBSTR pwszThat, size_t cchMax); + + /** + * Appends the first @a cchMax chars from UTF-16 string @a pszThat to @a this. + * + * @param pwszThat The C-style UTF-16 string to append. + * @param cchMax The maximum number of bytes to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(CBSTR pwszThat, size_t cchMax) RT_NOEXCEPT; + + /** + * Appends the first @a cchMax chars from string @a pszThat to @a this. + * + * @param pszThat The C-style string to append. + * @param cchMax The maximum number of bytes to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(const char *pszThat, size_t cchMax); + + /** + * Appends the first @a cchMax chars from string @a pszThat to @a this. + * + * @param pszThat The C-style string to append. + * @param cchMax The maximum number of bytes to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(const char *pszThat, size_t cchMax) RT_NOEXCEPT; + + /** + * Appends the given character to @a this. + * + * @param ch The character to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(char ch); + + /** + * Appends the given character to @a this. + * + * @param ch The character to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(char ch) RT_NOEXCEPT; + + /** + * Appends the given unicode code point to @a this. + * + * @param uc The unicode code point to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &appendCodePoint(RTUNICP uc); + + /** + * Appends the given unicode code point to @a this. + * + * @param uc The unicode code point to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendCodePointNoThrow(RTUNICP uc) RT_NOEXCEPT; + + /** + * Appends the output of the string format operation (RTStrPrintf). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + * + * @throws std::bad_alloc On allocation error. Object state is undefined. + * + * @returns Reference to the object. + */ + Bstr &appendPrintf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + + /** + * Appends the output of the string format operation (RTStrPrintf). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + * + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendPrintfNoThrow(const char *pszFormat, ...) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 2); + + /** + * Appends the output of the string format operation (RTStrPrintfV). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param va Argument vector containing the arguments + * specified by the format string. + * + * @throws std::bad_alloc On allocation error. Object state is undefined. + * + * @returns Reference to the object. + */ + Bstr &appendPrintfV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + + /** + * Appends the output of the string format operation (RTStrPrintfV). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param va Argument vector containing the arguments + * specified by the format string. + * + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendPrintfVNoThrow(const char *pszFormat, va_list va) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 0); + + /** + * Shortcut to append(), Bstr variant. + * + * @param rThat The string to append. + * @returns Reference to the object. + */ + Bstr &operator+=(const Bstr &rThat) + { + return append(rThat); + } + + /** + * Shortcut to append(), RTCString variant. + * + * @param rThat The string to append. + * @returns Reference to the object. + */ + Bstr &operator+=(const RTCString &rThat) + { + return append(rThat); + } + + /** + * Shortcut to append(), CBSTR variant. + * + * @param pwszThat The C-style string to append. + * @returns Reference to the object. + */ + Bstr &operator+=(CBSTR pwszThat) + { + return append(pwszThat); + } + + /** + * Shortcut to append(), const char * variant. + * + * @param pszThat The C-style string to append. + * @returns Reference to the object. + */ + Bstr &operator+=(const char *pszThat) + { + return append(pszThat); + } + + /** + * Shortcut to append(), char variant. + * + * @param ch The character to append. + * + * @returns Reference to the object. + */ + Bstr &operator+=(char ch) + { + return append(ch); + } + + /** @} */ + + /** + * Erases a sequence from the string. + * + * @returns Reference to the object. + * @param offStart Where in @a this string to start erasing (UTF-16 + * units, not codepoints). + * @param cwcLength How much following @a offStart to erase (UTF-16 + * units, not codepoints). + */ + Bstr &erase(size_t offStart = 0, size_t cwcLength = RTSTR_MAX) RT_NOEXCEPT; + + + /** @name BASE64 related methods + * @{ */ + /** + * Encodes the given data as BASE64. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param pvData Pointer to the data to encode. + * @param cbData Number of bytes to encode. + * @param fLineBreaks Whether to add line breaks (true) or just encode it + * as a continuous string. + * @sa RTBase64EncodeUtf16 + */ + HRESULT base64Encode(const void *pvData, size_t cbData, bool fLineBreaks = false); + + /** + * Decodes the string as BASE64. + * + * @returns IPRT status code, see RTBase64DecodeUtf16Ex. + * @param pvData Where to return the decoded bytes. + * @param cbData Size of the @a pvData return buffer. + * @param pcbActual Where to return number of bytes actually decoded. + * This is optional and if not specified, the request + * will fail unless @a cbData matches the data size + * exactly. + * @param ppwszEnd Where to return pointer to the first non-base64 + * character following the encoded data. This is + * optional and if NULL, the request will fail if there + * are anything trailing the encoded bytes in the + * string. + * @sa base64DecodedSize, RTBase64DecodeUtf16 + */ + int base64Decode(void *pvData, size_t cbData, size_t *pcbActual = NULL, PRTUTF16 *ppwszEnd = NULL); + + /** + * Determins the size of the BASE64 encoded data in the string. + * + * @returns The length in bytes. -1 if the encoding is bad. + * + * @param ppwszEnd If not NULL, this will point to the first char + * following the Base64 encoded text block. If + * NULL the entire string is assumed to be Base64. + * @sa base64Decode, RTBase64DecodedUtf16Size + */ + ssize_t base64DecodedSize(PRTUTF16 *ppwszEnd = NULL); + /** @} */ + +#if defined(VBOX_WITH_XPCOM) + /** + * Returns a pointer to the raw member UTF-16 string. If the member string is empty, + * returns a pointer to a global variable containing an empty BSTR with a proper zero + * length prefix so that Windows is happy. + */ + CBSTR raw() const + { + if (m_bstr) + return m_bstr; + + return g_bstrEmpty; + } +#else + /** + * Windows-only hack, as the automatically generated headers use BSTR. + * So if we don't want to cast like crazy we have to be more loose than + * on XPCOM. + * + * Returns a pointer to the raw member UTF-16 string. If the member string is empty, + * returns a pointer to a global variable containing an empty BSTR with a proper zero + * length prefix so that Windows is happy. + */ + BSTR raw() const + { + if (m_bstr) + return m_bstr; + + return g_bstrEmpty; + } +#endif + + /** + * Returns a non-const raw pointer that allows modifying the string directly. + * + * @note As opposed to raw(), this DOES return NULL if the member string is + * empty because we cannot return a mutable pointer to the global variable + * with the empty string. + * + * @note If modifying the string size (only shrinking it is allows), #jolt() or + * #joltNoThrow() must be called! + * + * @note Do not modify memory beyond the #length() of the string! + * + * @sa joltNoThrow(), mutalbleRaw(), reserve(), reserveNoThrow() + */ + BSTR mutableRaw() { return m_bstr; } + + /** + * Correct the embedded length after using mutableRaw(). + * + * This is needed on COM (Windows) to update the embedded string length. It is + * a stub on hosts using XPCOM. + * + * @param cwcNew The new string length, if handy, otherwise a negative + * number. + * @sa joltNoThrow(), mutalbleRaw(), reserve(), reserveNoThrow() + */ +#ifndef VBOX_WITH_XPCOM + void jolt(ssize_t cwcNew = -1); +#else + void jolt(ssize_t cwcNew = -1) + { + Assert(cwcNew < 0 || (cwcNew == 0 && !m_bstr) || m_bstr[cwcNew] == '\0'); RT_NOREF(cwcNew); + } +#endif + + /** + * Correct the embedded length after using mutableRaw(). + * + * This is needed on COM (Windows) to update the embedded string length. It is + * a stub on hosts using XPCOM. + * + * @returns S_OK on success, E_OUTOFMEMORY if shrinking the string failed. + * @param cwcNew The new string length, if handy, otherwise a negative + * number. + * @sa jolt(), mutalbleRaw(), reserve(), reserveNoThrow() + */ +#ifndef VBOX_WITH_XPCOM + HRESULT joltNoThrow(ssize_t cwcNew = -1) RT_NOEXCEPT; +#else + HRESULT joltNoThrow(ssize_t cwcNew = -1) RT_NOEXCEPT + { + Assert(cwcNew < 0 || (cwcNew == 0 && !m_bstr) || m_bstr[cwcNew] == '\0'); RT_NOREF(cwcNew); + return S_OK; + } +#endif + + /** + * Make sure at that least @a cwc of buffer space is reserved. + * + * Requests that the contained memory buffer have at least cb bytes allocated. + * This may expand or shrink the string's storage, but will never truncate the + * contained string. In other words, cb will be ignored if it's smaller than + * length() + 1. + * + * @param cwcMin The new minimum string length that the can be stored. This + * does not include the terminator. + * @param fForce Force this size. + * + * @throws std::bad_alloc On allocation error. The object is left unchanged. + */ + void reserve(size_t cwcMin, bool fForce = false); + + /** + * A C like version of the #reserve() method, i.e. return code instead of throw. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param cwcMin The new minimum string length that the can be stored. This + * does not include the terminator. + * @param fForce Force this size. + */ + HRESULT reserveNoThrow(size_t cwcMin, bool fForce = false) RT_NOEXCEPT; + + /** + * Intended to assign copies of instances to |BSTR| out parameters from + * within the interface method. Transfers the ownership of the duplicated + * string to the caller. + * + * If the member string is empty, this allocates an empty BSTR in *pstr + * (i.e. makes it point to a new buffer with a null byte). + * + * @deprecated Use cloneToEx instead to avoid throwing exceptions. + */ + void cloneTo(BSTR *pstr) const + { + if (pstr) + { + *pstr = ::SysAllocString((const OLECHAR *)raw()); // raw() returns a pointer to "" if empty +#ifdef RT_EXCEPTIONS_ENABLED + if (!*pstr) + throw std::bad_alloc(); +#endif + } + } + + /** + * A version of cloneTo that does not throw any out of memory exceptions, but + * returns E_OUTOFMEMORY intead. + * @returns S_OK or E_OUTOFMEMORY. + */ + HRESULT cloneToEx(BSTR *pstr) const + { + if (!pstr) + return S_OK; + *pstr = ::SysAllocString((const OLECHAR *)raw()); // raw() returns a pointer to "" if empty + return pstr ? S_OK : E_OUTOFMEMORY; + } + + /** + * Intended to assign instances to |BSTR| out parameters from within the + * interface method. Transfers the ownership of the original string to the + * caller and resets the instance to null. + * + * As opposed to cloneTo(), this method doesn't create a copy of the + * string. + * + * If the member string is empty, this allocates an empty BSTR in *pstr + * (i.e. makes it point to a new buffer with a null byte). + * + * @param pbstrDst The BSTR variable to detach the string to. + * + * @throws std::bad_alloc if we failed to allocate a new empty string. + */ + void detachTo(BSTR *pbstrDst) + { + if (m_bstr) + { + *pbstrDst = m_bstr; + m_bstr = NULL; + } + else + { + // allocate null BSTR + *pbstrDst = ::SysAllocString((const OLECHAR *)g_bstrEmpty); +#ifdef RT_EXCEPTIONS_ENABLED + if (!*pbstrDst) + throw std::bad_alloc(); +#endif + } + } + + /** + * A version of detachTo that does not throw exceptions on out-of-memory + * conditions, but instead returns E_OUTOFMEMORY. + * + * @param pbstrDst The BSTR variable to detach the string to. + * @returns S_OK or E_OUTOFMEMORY. + */ + HRESULT detachToEx(BSTR *pbstrDst) + { + if (m_bstr) + { + *pbstrDst = m_bstr; + m_bstr = NULL; + } + else + { + // allocate null BSTR + *pbstrDst = ::SysAllocString((const OLECHAR *)g_bstrEmpty); + if (!*pbstrDst) + return E_OUTOFMEMORY; + } + return S_OK; + } + + /** + * Intended to pass instances as |BSTR| out parameters to methods. + * Takes the ownership of the returned data. + */ + BSTR *asOutParam() + { + cleanup(); + return &m_bstr; + } + + /** + * Static immutable empty-string object. May be used for comparison purposes. + */ + static const Bstr Empty; + +protected: + + void cleanup(); + + /** + * Protected internal helper to copy a string. This ignores the previous object + * state, so either call this from a constructor or call cleanup() first. + * + * This variant copies from a zero-terminated UTF-16 string (which need not + * be a BSTR, i.e. need not have a length prefix). + * + * If the source is empty, this sets the member string to NULL. + * + * @param a_bstrSrc The source string. The caller guarantees + * that this is valid UTF-16. + * + * @throws std::bad_alloc - the object is representing an empty string. + */ + void copyFrom(const OLECHAR *a_bstrSrc); + + /** cleanup() + copyFrom() - for assignment operators. */ + void cleanupAndCopyFrom(const OLECHAR *a_bstrSrc); + + /** + * Protected internal helper to copy a string, implying cleanup(). + * + * This variant copies from a zero-terminated UTF-16 string (which need not be a + * BSTR, i.e. need not have a length prefix). + * + * If the source is empty, this sets the member string to NULL. + * + * @param a_bstrSrc The source string. The caller guarantees + * that this is valid UTF-16. + * @returns S_OK or E_OUTOFMEMORY + */ + HRESULT cleanupAndCopyFromEx(const OLECHAR *a_bstrSrc) RT_NOEXCEPT; + + /** + * Protected internal helper to copy a string. This ignores the previous object + * state, so either call this from a constructor or call cleanup() first. + * + * This variant copies and converts from a zero-terminated UTF-8 string. + * + * If the source is empty, this sets the member string to NULL. + * + * @param a_pszSrc The source string. The caller guarantees + * that this is valid UTF-8. + * + * @throws std::bad_alloc - the object is representing an empty string. + */ + void copyFrom(const char *a_pszSrc) + { + copyFromN(a_pszSrc, RTSTR_MAX); + } + + /** + * Variant of copyFrom for sub-string constructors. + * + * @param a_pszSrc The source string. The caller guarantees + * that this is valid UTF-8. + * @param a_cchSrc The maximum number of chars (not codepoints) to + * copy. If you pass RTSTR_MAX it'll be exactly + * like copyFrom(). + * + * @throws std::bad_alloc - the object is representing an empty string. + */ + void copyFromN(const char *a_pszSrc, size_t a_cchSrc); + + /** cleanup() + non-throwing copyFromN(). */ + HRESULT cleanupAndCopyFromNoThrow(const char *a_pszSrc, size_t a_cchMax) RT_NOEXCEPT; + + Bstr &appendWorkerUtf16(PCRTUTF16 pwszSrc, size_t cwcSrc); + Bstr &appendWorkerUtf8(const char *pszSrc, size_t cchSrc); + HRESULT appendWorkerUtf16NoThrow(PCRTUTF16 pwszSrc, size_t cwcSrc) RT_NOEXCEPT; + HRESULT appendWorkerUtf8NoThrow(const char *pszSrc, size_t cchSrc) RT_NOEXCEPT; + + static DECLCALLBACK(size_t) printfOutputCallbackNoThrow(void *pvArg, const char *pachChars, size_t cbChars) RT_NOEXCEPT; + + BSTR m_bstr; + + friend class Utf8Str; /* to access our raw_copy() */ +}; + +/* symmetric compare operators */ +inline bool operator==(CBSTR l, const Bstr &r) { return r.operator==(l); } +inline bool operator!=(CBSTR l, const Bstr &r) { return r.operator!=(l); } +inline bool operator==(BSTR l, const Bstr &r) { return r.operator==(l); } +inline bool operator!=(BSTR l, const Bstr &r) { return r.operator!=(l); } + + + + +/** + * String class used universally in Main for UTF-8 strings. + * + * This is based on RTCString, to which some functionality has been + * moved. Here we keep things that are specific to Main, such as conversions + * with UTF-16 strings (Bstr). + * + * Like RTCString, Utf8Str does not differentiate between NULL strings + * and empty strings. In other words, Utf8Str("") and Utf8Str(NULL) behave the + * same. In both cases, RTCString allocates no memory, reports + * a zero length and zero allocated bytes for both, and returns an empty + * C string from c_str(). + * + * @note All Utf8Str methods ASSUMES valid UTF-8 or UTF-16 input strings. + * The VirtualBox policy in this regard is to validate strings coming + * from external sources before passing them to Utf8Str or Bstr. + */ +class Utf8Str : public RTCString +{ +public: + + Utf8Str() {} + + Utf8Str(const RTCString &that) + : RTCString(that) + {} + + Utf8Str(const char *that) + : RTCString(that) + {} + + Utf8Str(const Bstr &that) + { + copyFrom(that.raw()); + } + + Utf8Str(CBSTR that, size_t a_cwcSize = RTSTR_MAX) + { + copyFrom(that, a_cwcSize); + } + + Utf8Str(const char *a_pszSrc, size_t a_cchSrc) + : RTCString(a_pszSrc, a_cchSrc) + { + } + + /** + * Constructs a new string given the format string and the list of the + * arguments for the format string. + * + * @param a_pszFormat Pointer to the format string (UTF-8), + * @see pg_rt_str_format. + * @param a_va Argument vector containing the arguments + * specified by the format string. + * @sa RTCString::printfV + */ + Utf8Str(const char *a_pszFormat, va_list a_va) RT_IPRT_FORMAT_ATTR(1, 0) + : RTCString(a_pszFormat, a_va) + { + } + + Utf8Str& operator=(const RTCString &that) + { + RTCString::operator=(that); + return *this; + } + + Utf8Str& operator=(const char *that) + { + RTCString::operator=(that); + return *this; + } + + Utf8Str& operator=(const Bstr &that) + { + cleanup(); + copyFrom(that.raw()); + return *this; + } + + Utf8Str& operator=(CBSTR that) + { + cleanup(); + copyFrom(that); + return *this; + } + + /** + * Extended assignment method that returns a COM status code instead of an + * exception on failure. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_rSrcStr The source string + */ + HRESULT assignEx(Utf8Str const &a_rSrcStr) + { + return copyFromExNComRC(a_rSrcStr.m_psz, 0, a_rSrcStr.m_cch); + } + + /** + * Extended assignment method that returns a COM status code instead of an + * exception on failure. + * + * @returns S_OK, E_OUTOFMEMORY or E_INVALIDARG. + * @param a_rSrcStr The source string + * @param a_offSrc The character (byte) offset of the substring. + * @param a_cchSrc The number of characters (bytes) to copy from the source + * string. + */ + HRESULT assignEx(Utf8Str const &a_rSrcStr, size_t a_offSrc, size_t a_cchSrc) + { + if ( a_offSrc + a_cchSrc > a_rSrcStr.m_cch + || a_offSrc > a_rSrcStr.m_cch) + return E_INVALIDARG; + return copyFromExNComRC(a_rSrcStr.m_psz, a_offSrc, a_cchSrc); + } + + /** + * Extended assignment method that returns a COM status code instead of an + * exception on failure. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_pcszSrc The source string + */ + HRESULT assignEx(const char *a_pcszSrc) + { + return copyFromExNComRC(a_pcszSrc, 0, a_pcszSrc ? strlen(a_pcszSrc) : 0); + } + + /** + * Extended assignment method that returns a COM status code instead of an + * exception on failure. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_pcszSrc The source string + * @param a_cchSrc The number of characters (bytes) to copy from the source + * string. + */ + HRESULT assignEx(const char *a_pcszSrc, size_t a_cchSrc) + { + return copyFromExNComRC(a_pcszSrc, 0, a_cchSrc); + } + + RTMEMEF_NEW_AND_DELETE_OPERATORS(); + +#if defined(VBOX_WITH_XPCOM) + /** + * Intended to assign instances to |char *| out parameters from within the + * interface method. Transfers the ownership of the duplicated string to the + * caller. + * + * This allocates a single 0 byte in the target if the member string is empty. + * + * This uses XPCOM memory allocation and thus only works on XPCOM. MSCOM doesn't + * like char* strings anyway. + */ + void cloneTo(char **pstr) const; + + /** + * A version of cloneTo that does not throw allocation errors but returns + * E_OUTOFMEMORY instead. + * @returns S_OK or E_OUTOFMEMORY (COM status codes). + */ + HRESULT cloneToEx(char **pstr) const; +#endif + + /** + * Intended to assign instances to |BSTR| out parameters from within the + * interface method. Transfers the ownership of the duplicated string to the + * caller. + */ + void cloneTo(BSTR *pstr) const + { + if (pstr) + { + Bstr bstr(*this); + bstr.cloneTo(pstr); + } + } + + /** + * A version of cloneTo that does not throw allocation errors but returns + * E_OUTOFMEMORY instead. + * + * @param pbstr Where to store a clone of the string. + * @returns S_OK or E_OUTOFMEMORY (COM status codes). + */ + HRESULT cloneToEx(BSTR *pbstr) const RT_NOEXCEPT; + + /** + * Safe assignment from BSTR. + * + * @param pbstrSrc The source string. + * @returns S_OK or E_OUTOFMEMORY (COM status codes). + */ + HRESULT cloneEx(CBSTR pbstrSrc) + { + cleanup(); + return copyFromEx(pbstrSrc); + } + + /** + * Removes a trailing slash from the member string, if present. + * Calls RTPathStripTrailingSlash() without having to mess with mutableRaw(). + */ + Utf8Str& stripTrailingSlash(); + + /** + * Removes a trailing filename from the member string, if present. + * Calls RTPathStripFilename() without having to mess with mutableRaw(). + */ + Utf8Str& stripFilename(); + + /** + * Removes the path component from the member string, if present. + * Calls RTPathFilename() without having to mess with mutableRaw(). + */ + Utf8Str& stripPath(); + + /** + * Removes a trailing file name suffix from the member string, if present. + * Calls RTPathStripSuffix() without having to mess with mutableRaw(). + */ + Utf8Str& stripSuffix(); + + /** + * Parses key=value pairs. + * + * @returns offset of the @a a_rPairSeparator following the returned value. + * @retval npos is returned if there are no more key/value pairs. + * + * @param a_rKey Reference to variable that should receive + * the key substring. This is set to null if + * no key/value found. (It's also possible the + * key is an empty string, so be careful.) + * @param a_rValue Reference to variable that should receive + * the value substring. This is set to null if + * no key/value found. (It's also possible the + * value is an empty string, so be careful.) + * @param a_offStart The offset to start searching from. This is + * typically 0 for the first call, and the + * return value of the previous call for the + * subsequent ones. + * @param a_rPairSeparator The pair separator string. If this is an + * empty string, the whole string will be + * considered as a single key/value pair. + * @param a_rKeyValueSeparator The key/value separator string. + */ + size_t parseKeyValue(Utf8Str &a_rKey, Utf8Str &a_rValue, size_t a_offStart = 0, + const Utf8Str &a_rPairSeparator = ",", const Utf8Str &a_rKeyValueSeparator = "=") const; + + /** + * Static immutable empty-string object. May be used for comparison purposes. + */ + static const Utf8Str Empty; +protected: + + void copyFrom(CBSTR a_pbstr, size_t a_cwcMax = RTSTR_MAX); + HRESULT copyFromEx(CBSTR a_pbstr); + HRESULT copyFromExNComRC(const char *a_pcszSrc, size_t a_offSrc, size_t a_cchSrc); + + friend class Bstr; /* to access our raw_copy() */ +}; + +/** + * Class with RTCString::printf as constructor for your convenience. + * + * Constructing a Utf8Str string object from a format string and a variable + * number of arguments can easily be confused with the other Utf8Str + * constructures, thus this child class. + * + * The usage of this class is like the following: + * @code + Utf8StrFmt strName("program name = %s", argv[0]); + @endcode + * + * @note Do not use in assignments to Utf8Str variables. Instead use + * RTCString::printf directly on the variable! This avoid an extra + * temporary Utf8Str instance and assignment operation. + */ +class Utf8StrFmt : public Utf8Str +{ +public: + + /** + * Constructs a new string given the format string and the list of the + * arguments for the format string. + * + * @param a_pszFormat Pointer to the format string (UTF-8), + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + */ + explicit Utf8StrFmt(const char *a_pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2) + { + va_list va; + va_start(va, a_pszFormat); + printfV(a_pszFormat, va); + va_end(va); + } + + RTMEMEF_NEW_AND_DELETE_OPERATORS(); + +protected: + Utf8StrFmt() + { } + +private: +}; + +/** + * Class with Bstr::printf as constructor for your convenience. + */ +class BstrFmt : public Bstr +{ +public: + + /** + * Constructs a new string given the format string and the list of the + * arguments for the format string. + * + * @param a_pszFormat printf-like format string (in UTF-8 encoding), see + * iprt/string.h for details. + * @param ... List of the arguments for the format string. + */ + explicit BstrFmt(const char *a_pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2) + { + va_list va; + va_start(va, a_pszFormat); + printfV(a_pszFormat, va); + va_end(va); + } + + RTMEMEF_NEW_AND_DELETE_OPERATORS(); + +protected: + BstrFmt() + { } +}; + +/** + * Class with Bstr::printfV as constructor for your convenience. + */ +class BstrFmtVA : public Bstr +{ +public: + + /** + * Constructs a new string given the format string and the list of the + * arguments for the format string. + * + * @param a_pszFormat printf-like format string (in UTF-8 encoding), see + * iprt/string.h for details. + * @param a_va List of arguments for the format string + */ + BstrFmtVA(const char *a_pszFormat, va_list a_va) RT_IPRT_FORMAT_ATTR(1, 0) + { + printfV(a_pszFormat, a_va); + } + + RTMEMEF_NEW_AND_DELETE_OPERATORS(); + +protected: + BstrFmtVA() + { } +}; + +} /* namespace com */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_string_h */ + diff --git a/include/VBox/com/utils.h b/include/VBox/com/utils.h new file mode 100644 index 00000000..e47b4129 --- /dev/null +++ b/include/VBox/com/utils.h @@ -0,0 +1,132 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - COM initialization / shutdown. + */ + +/* + * Copyright (C) 2005-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_utils_h +#define VBOX_INCLUDED_com_utils_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "iprt/types.h" + +/** @addtogroup grp_com + * @{ + */ + +namespace com +{ + +/** + * Returns the VirtualBox user home directory. + * + * On failure, this function will return a path that caused a failure (or + * NULL if the failure is not path-related). + * + * On success, this function will try to create the returned directory if it + * doesn't exist yet. This may also fail with the corresponding status code. + * + * If @a aDirLen is smaller than RTPATH_MAX then there is a great chance that + * this method will return VERR_BUFFER_OVERFLOW. + * + * @param aDir Buffer to store the directory string in UTF-8 encoding. + * @param aDirLen Length of the supplied buffer including space for the + * terminating null character, in bytes. + * @param fCreateDir Flag whether to create the returned directory on success + * if it doesn't exist. + * @returns VBox status code. + */ +int GetVBoxUserHomeDirectory(char *aDir, size_t aDirLen, bool fCreateDir = true); + +/** + * Creates a release log file, used both in VBoxSVC and in API clients. + * + * @param pszEntity Human readable name of the program. + * @param pszLogFile Name of the release log file. + * @param fFlags Logger instance flags. + * @param pszGroupSettings Group logging settings. + * @param pszEnvVarBase Base environment variable name for the logger. + * @param fDestFlags Logger destination flags. + * @param cMaxEntriesPerGroup Limit for log entries per group. UINT32_MAX for no limit. + * @param cHistory Number of old log files to keep. + * @param uHistoryFileTime Maximum amount of time to put in a log file. + * @param uHistoryFileSize Maximum size of a log file before rotating. + * @param pErrInfo Where to return extended error information. + * Optional. + * + * @returns VBox status code. + */ +int VBoxLogRelCreate(const char *pszEntity, const char *pszLogFile, + uint32_t fFlags, const char *pszGroupSettings, + const char *pszEnvVarBase, uint32_t fDestFlags, + uint32_t cMaxEntriesPerGroup, uint32_t cHistory, + uint32_t uHistoryFileTime, uint64_t uHistoryFileSize, + PRTERRINFO pErrInfo); + +/** + * Creates a release log file, used both in VBoxSVC and in API clients. + * + * @param pszEntity Human readable name of the program. + * @param pszLogFile Name of the release log file. + * @param fFlags Logger instance flags. + * @param pszGroupSettings Group logging settings. + * @param pszEnvVarBase Base environment variable name for the logger. + * @param fDestFlags Logger destination flags. + * @param cMaxEntriesPerGroup Limit for log entries per group. UINT32_MAX for no limit. + * @param cHistory Number of old log files to keep. + * @param uHistoryFileTime Maximum amount of time to put in a log file. + * @param uHistoryFileSize Maximum size of a log file before rotating. + * @param pOutputIf The optional file output interface, can be NULL which will + * make use of the default one. + * @param pvOutputIfUser The opaque user data to pass to the callbacks in the output interface. + * @param pErrInfo Where to return extended error information. + * Optional. + * + * @returns VBox status code. + * + * @note Can't include log.h here because of precompiled header fun, hence pOutputIf is void *... + */ +int VBoxLogRelCreateEx(const char *pszEntity, const char *pszLogFile, + uint32_t fFlags, const char *pszGroupSettings, + const char *pszEnvVarBase, uint32_t fDestFlags, + uint32_t cMaxEntriesPerGroup, uint32_t cHistory, + uint32_t uHistoryFileTime, uint64_t uHistoryFileSize, + const void *pOutputIf, void *pvOutputIfUser, + PRTERRINFO pErrInfo); + +} /* namespace com */ + +/** @} */ +#endif /* !VBOX_INCLUDED_com_utils_h */ + diff --git a/include/VBox/dbg.h b/include/VBox/dbg.h new file mode 100644 index 00000000..901b72da --- /dev/null +++ b/include/VBox/dbg.h @@ -0,0 +1,1222 @@ +/** @file + * Debugger Interfaces. (VBoxDbg) + * + * This header covers all external interfaces of the Debugger module. + * However, it does not cover the DBGF interface since that part of the + * VMM. Use dbgf.h for that. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_dbg_h +#define VBOX_INCLUDED_dbg_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <VBox/vmm/dbgf.h> + +#include <iprt/stdarg.h> +#ifdef IN_RING3 +# include <iprt/errcore.h> +#endif + +RT_C_DECLS_BEGIN + + + +/** @defgroup grp_dbg The VirtualBox Debugger + * @{ + */ + +#ifdef IN_RING3 /* The debugger stuff is ring-3 only. */ + +/** @defgroup grp_dbgc The Debugger Console API + * @{ + */ + +/** @def VBOX_WITH_DEBUGGER + * The build is with debugger module. Test if this is defined before registering + * external debugger commands. This is normally defined in Config.kmk. + */ +#ifdef DOXYGEN_RUNNING +# define VBOX_WITH_DEBUGGER +#endif + + +/** + * DBGC variable category. + * + * Used to describe an argument to a command or function and a functions + * return value. + */ +typedef enum DBGCVARCAT +{ + /** Any type is fine. */ + DBGCVAR_CAT_ANY = 0, + /** Any kind of pointer or number. */ + DBGCVAR_CAT_POINTER_NUMBER, + /** Any kind of pointer or number, no range. */ + DBGCVAR_CAT_POINTER_NUMBER_NO_RANGE, + /** Any kind of pointer. */ + DBGCVAR_CAT_POINTER, + /** Any kind of pointer with no range option. */ + DBGCVAR_CAT_POINTER_NO_RANGE, + /** GC pointer. */ + DBGCVAR_CAT_GC_POINTER, + /** GC pointer with no range option. */ + DBGCVAR_CAT_GC_POINTER_NO_RANGE, + /** Numeric argument. */ + DBGCVAR_CAT_NUMBER, + /** Numeric argument with no range option. */ + DBGCVAR_CAT_NUMBER_NO_RANGE, + /** String. */ + DBGCVAR_CAT_STRING, + /** Symbol. */ + DBGCVAR_CAT_SYMBOL, + /** Option. */ + DBGCVAR_CAT_OPTION, + /** Option + string. */ + DBGCVAR_CAT_OPTION_STRING, + /** Option + number. */ + DBGCVAR_CAT_OPTION_NUMBER +} DBGCVARCAT; + + +/** + * DBGC variable type. + */ +typedef enum DBGCVARTYPE +{ + /** unknown... */ + DBGCVAR_TYPE_UNKNOWN = 0, + /** Flat GC pointer. */ + DBGCVAR_TYPE_GC_FLAT, + /** Segmented GC pointer. */ + DBGCVAR_TYPE_GC_FAR, + /** Physical GC pointer. */ + DBGCVAR_TYPE_GC_PHYS, + /** Flat HC pointer. */ + DBGCVAR_TYPE_HC_FLAT, + /** Physical HC pointer. */ + DBGCVAR_TYPE_HC_PHYS, + /** Number. */ + DBGCVAR_TYPE_NUMBER, + /** String. */ + DBGCVAR_TYPE_STRING, + /** Symbol. */ + DBGCVAR_TYPE_SYMBOL, + /** Special type used when querying symbols. */ + DBGCVAR_TYPE_ANY +} DBGCVARTYPE; + +/** @todo Rename to DBGCVAR_IS_xyz. */ + +/** Checks if the specified variable type is of a pointer persuasion. */ +#define DBGCVAR_ISPOINTER(enmType) ((enmType) >= DBGCVAR_TYPE_GC_FLAT && enmType <= DBGCVAR_TYPE_HC_PHYS) +/** Checks if the specified variable type is of a pointer persuasion. */ +#define DBGCVAR_IS_FAR_PTR(enmType) ((enmType) == DBGCVAR_TYPE_GC_FAR) +/** Checks if the specified variable type is of a pointer persuasion and of the guest context sort. */ +#define DBGCVAR_ISGCPOINTER(enmType) ((enmType) >= DBGCVAR_TYPE_GC_FLAT && (enmType) <= DBGCVAR_TYPE_GC_PHYS) +/** Checks if the specified variable type is of a pointer persuasion and of the host context sort. */ +#define DBGCVAR_ISHCPOINTER(enmType) ((enmType) >= DBGCVAR_TYPE_HC_FLAT && (enmType) <= DBGCVAR_TYPE_HC_PHYS) + + +/** + * DBGC variable range type. + */ +typedef enum DBGCVARRANGETYPE +{ + /** No range appliable or no range specified. */ + DBGCVAR_RANGE_NONE = 0, + /** Number of elements. */ + DBGCVAR_RANGE_ELEMENTS, + /** Number of bytes. */ + DBGCVAR_RANGE_BYTES +} DBGCVARRANGETYPE; + + +/** + * Variable descriptor. + */ +typedef struct DBGCVARDESC +{ + /** The minimal number of times this argument may occur. + * Use 0 here to inidicate that the argument is optional. */ + unsigned cTimesMin; + /** Maximum number of occurrences. + * Use ~0 here to indicate infinite. */ + unsigned cTimesMax; + /** Argument category. */ + DBGCVARCAT enmCategory; + /** Flags, DBGCVD_FLAGS_* */ + unsigned fFlags; + /** Argument name. */ + const char *pszName; + /** Argument name. */ + const char *pszDescription; +} DBGCVARDESC; +/** Pointer to an argument descriptor. */ +typedef DBGCVARDESC *PDBGCVARDESC; +/** Pointer to a const argument descriptor. */ +typedef const DBGCVARDESC *PCDBGCVARDESC; + +/** Variable descriptor flags. + * @{ */ +/** Indicates that the variable depends on the previous being present. */ +#define DBGCVD_FLAGS_DEP_PREV RT_BIT(1) +/** @} */ + + +/** + * DBGC variable. + */ +typedef struct DBGCVAR +{ + /** Pointer to the argument descriptor. */ + PCDBGCVARDESC pDesc; + /** Pointer to the next argument. */ + struct DBGCVAR *pNext; + + /** Argument type. */ + DBGCVARTYPE enmType; + /** Type specific. */ + union + { + /** Flat GC Address. (DBGCVAR_TYPE_GC_FLAT) */ + RTGCPTR GCFlat; + /** Far (16:32) GC Address. (DBGCVAR_TYPE_GC_FAR) */ + RTFAR32 GCFar; + /** Physical GC Address. (DBGCVAR_TYPE_GC_PHYS) */ + RTGCPHYS GCPhys; + /** Flat HC Address. (DBGCVAR_TYPE_HC_FLAT) */ + void *pvHCFlat; + /** Physical GC Address. (DBGCVAR_TYPE_HC_PHYS) */ + RTHCPHYS HCPhys; + /** String. (DBGCVAR_TYPE_STRING) + * The basic idea is the the this is a pointer to the expression we're + * parsing, so no messing with freeing. */ + const char *pszString; + /** Number. (DBGCVAR_TYPE_NUMBER) */ + uint64_t u64Number; + } u; + + /** Range type. */ + DBGCVARRANGETYPE enmRangeType; + /** Range. The use of the content depends on the enmRangeType. */ + uint64_t u64Range; +} DBGCVAR; +/** Pointer to a command argument. */ +typedef DBGCVAR *PDBGCVAR; +/** Pointer to a const command argument. */ +typedef const DBGCVAR *PCDBGCVAR; + + +/** + * Macro for initializing a DBGC variable with defaults. + * The result is an unknown variable type without any range. + */ +#define DBGCVAR_INIT(pVar) \ + do { \ + (pVar)->pDesc = NULL;\ + (pVar)->pNext = NULL; \ + (pVar)->enmType = DBGCVAR_TYPE_UNKNOWN; \ + (pVar)->u.u64Number = 0; \ + (pVar)->enmRangeType = DBGCVAR_RANGE_NONE; \ + (pVar)->u64Range = 0; \ + } while (0) + +/** + * Macro for initializing a DBGC variable with a HC physical address. + */ +#define DBGCVAR_INIT_HC_PHYS(pVar, Phys) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_HC_PHYS; \ + (pVar)->u.HCPhys = (Phys); \ + } while (0) + +/** + * Macro for initializing a DBGC variable with a HC flat address. + */ +#define DBGCVAR_INIT_HC_FLAT(pVar, Flat) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_HC_FLAT; \ + (pVar)->u.pvHCFlat = (Flat); \ + } while (0) + +/** + * Macro for initializing a DBGC variable with a GC physical address. + */ +#define DBGCVAR_INIT_GC_PHYS(pVar, Phys) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_GC_PHYS; \ + (pVar)->u.GCPhys = (Phys); \ + } while (0) + +/** + * Macro for initializing a DBGC variable with a GC flat address. + */ +#define DBGCVAR_INIT_GC_FLAT(pVar, Flat) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_GC_FLAT; \ + (pVar)->u.GCFlat = (Flat); \ + } while (0) + +/** + * Macro for initializing a DBGC variable with a GC flat address. + */ +#define DBGCVAR_INIT_GC_FLAT_BYTE_RANGE(pVar, Flat, cbRange) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_GC_FLAT; \ + (pVar)->u.GCFlat = (Flat); \ + DBGCVAR_SET_RANGE(pVar, DBGCVAR_RANGE_BYTES, cbRange); \ + } while (0) + +/** + * Macro for initializing a DBGC variable with a GC far address. + */ +#define DBGCVAR_INIT_GC_FAR(pVar, _sel, _off) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_GC_FAR; \ + (pVar)->u.GCFar.sel = (_sel); \ + (pVar)->u.GCFar.off = (_off); \ + } while (0) + +/** + * Macro for initializing a DBGC variable with a number. + */ +#define DBGCVAR_INIT_NUMBER(pVar, Value) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_NUMBER; \ + (pVar)->u.u64Number = (Value); \ + } while (0) + +/** + * Macro for initializing a DBGC variable with a string. + */ +#define DBGCVAR_INIT_STRING(pVar, a_pszString) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_STRING; \ + (pVar)->enmRangeType = DBGCVAR_RANGE_BYTES; \ + (pVar)->u.pszString = (a_pszString); \ + (pVar)->u64Range = strlen(a_pszString); \ + } while (0) + + +/** + * Macro for initializing a DBGC variable with a symbol. + */ +#define DBGCVAR_INIT_SYMBOL(pVar, a_pszSymbol) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_SYMBOL; \ + (pVar)->enmRangeType = DBGCVAR_RANGE_BYTES; \ + (pVar)->u.pszString = (a_pszSymbol); \ + (pVar)->u64Range = strlen(a_pszSymbol); \ + } while (0) + + +/** + * Macro for setting the range of a DBGC variable. + * @param pVar The variable. + * @param _enmRangeType The range type. + * @param Value The range length value. + */ +#define DBGCVAR_SET_RANGE(pVar, _enmRangeType, Value) \ + do { \ + (pVar)->enmRangeType = (_enmRangeType); \ + (pVar)->u64Range = (Value); \ + } while (0) + + +/** + * Macro for setting the range of a DBGC variable. + * @param a_pVar The variable. + * @param a_cbRange The range, in bytes. + */ +#define DBGCVAR_SET_BYTE_RANGE(a_pVar, a_cbRange) \ + DBGCVAR_SET_RANGE(a_pVar, DBGCVAR_RANGE_BYTES, a_cbRange) + + +/** + * Macro for resetting the range a DBGC variable. + * @param a_pVar The variable. + */ +#define DBGCVAR_ZAP_RANGE(a_pVar) \ + do { \ + (a_pVar)->enmRangeType = DBGCVAR_RANGE_NONE; \ + (a_pVar)->u64Range = 0; \ + } while (0) + + +/** + * Macro for assigning one DBGC variable to another. + * @param a_pResult The result (target) variable. + * @param a_pVar The source variable. + */ +#define DBGCVAR_ASSIGN(a_pResult, a_pVar) \ + do { \ + *(a_pResult) = *(a_pVar); \ + } while (0) + + +/** Pointer to a command descriptor. */ +typedef struct DBGCCMD *PDBGCCMD; +/** Pointer to a const command descriptor. */ +typedef const struct DBGCCMD *PCDBGCCMD; + +/** Pointer to a function descriptor. */ +typedef struct DBGCFUNC *PDBGCFUNC; +/** Pointer to a const function descriptor. */ +typedef const struct DBGCFUNC *PCDBGCFUNC; + +/** Pointer to helper functions for commands. */ +typedef struct DBGCCMDHLP *PDBGCCMDHLP; + + +/** + * Helper functions for commands. + */ +typedef struct DBGCCMDHLP +{ + /** Magic value (DBGCCMDHLP_MAGIC). */ + uint32_t u32Magic; + + /** + * Command helper for writing formatted text to the debug console. + * + * @returns VBox status. + * @param pCmdHlp Pointer to the command callback structure. + * @param pcbWritten Where to store the number of bytes written. + * This is optional. + * @param pszFormat The format string. This may use all IPRT extensions as + * well as the debugger ones. + * @param ... Arguments specified in the format string. + */ + DECLCALLBACKMEMBER(int, pfnPrintf,(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, + const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(3, 4); + + /** + * Command helper for writing formatted text to the debug console. + * + * @returns VBox status. + * @param pCmdHlp Pointer to the command callback structure. + * @param pcbWritten Where to store the number of bytes written. + * This is optional. + * @param pszFormat The format string. This may use all IPRT extensions as + * well as the debugger ones. + * @param args Arguments specified in the format string. + */ + DECLCALLBACKMEMBER(int, pfnPrintfV,(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, + const char *pszFormat, va_list args)) RT_IPRT_FORMAT_ATTR(3, 0); + + /** + * Command helper for formatting a string with debugger format specifiers. + * + * @returns The number of bytes written. + * @param pCmdHlp Pointer to the command callback structure. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pszFormat The format string. This may use all IPRT extensions as + * well as the debugger ones. + * @param ... Arguments specified in the format string. + */ + DECLCALLBACKMEMBER(size_t, pfnStrPrintf,(PDBGCCMDHLP pCmdHlp, char *pszBuf, size_t cbBuf, + const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(4, 5); + + /** + * Command helper for formatting a string with debugger format specifiers. + * + * @returns The number of bytes written. + * @param pCmdHlp Pointer to the command callback structure. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pszFormat The format string. This may use all IPRT extensions as + * well as the debugger ones. + * @param va Arguments specified in the format string. + */ + DECLCALLBACKMEMBER(size_t, pfnStrPrintfV,(PDBGCCMDHLP pCmdHlp, char *pszBuf, size_t cbBuf, + const char *pszFormat, va_list va)) RT_IPRT_FORMAT_ATTR(4, 0); + + /** + * Command helper for formatting and error message for a VBox status code. + * + * @returns VBox status code appropriate to return from a command. + * @param pCmdHlp Pointer to the command callback structure. + * @param rc The VBox status code. + * @param pszFormat Format string for additional messages. Can be NULL. + * @param ... Format arguments, optional. + */ + DECLCALLBACKMEMBER(int, pfnVBoxError,(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(3, 4); + + /** + * Command helper for formatting and error message for a VBox status code. + * + * @returns VBox status code appropriate to return from a command. + * @param pCmdHlp Pointer to the command callback structure. + * @param rc The VBox status code. + * @param pszFormat Format string for additional messages. Can be NULL. + * @param args Format arguments, optional. + */ + DECLCALLBACKMEMBER(int, pfnVBoxErrorV,(PDBGCCMDHLP pCmdHlp, int rc, + const char *pszFormat, va_list args)) RT_IPRT_FORMAT_ATTR(3, 0); + + /** + * Command helper for reading memory specified by a DBGC variable. + * + * @returns VBox status code appropriate to return from a command. + * @param pCmdHlp Pointer to the command callback structure. + * @param pvBuffer Where to store the read data. + * @param cbRead Number of bytes to read. + * @param pVarPointer DBGC variable specifying where to start reading. + * @param pcbRead Where to store the number of bytes actually read. + * This optional, but it's useful when read GC virtual memory where a + * page in the requested range might not be present. + * If not specified not-present failure or end of a HC physical page + * will cause failure. + */ + DECLCALLBACKMEMBER(int, pfnMemRead,(PDBGCCMDHLP pCmdHlp, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)); + + /** + * Command helper for writing memory specified by a DBGC variable. + * + * @returns VBox status code appropriate to return from a command. + * @param pCmdHlp Pointer to the command callback structure. + * @param pvBuffer What to write. + * @param cbWrite Number of bytes to write. + * @param pVarPointer DBGC variable specifying where to start reading. + * @param pcbWritten Where to store the number of bytes written. + * This is optional. If NULL be aware that some of the buffer + * might have been written to the specified address. + */ + DECLCALLBACKMEMBER(int, pfnMemWrite,(PDBGCCMDHLP pCmdHlp, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten)); + + /** + * Executes command an expression. + * (Hopefully the parser and functions are fully reentrant.) + * + * @returns VBox status code appropriate to return from a command. + * @param pCmdHlp Pointer to the command callback structure. + * @param pszExpr The expression. Format string with the format DBGC extensions. + * @param ... Format arguments. + */ + DECLCALLBACKMEMBER(int, pfnExec,(PDBGCCMDHLP pCmdHlp, const char *pszExpr, ...)) RT_IPRT_FORMAT_ATTR(2, 3); + + /** + * Evaluates an expression. + * (Hopefully the parser and functions are fully reentrant.) + * + * @returns VBox status code appropriate to return from a command. + * @param pCmdHlp Pointer to the command callback structure. + * @param pResult Where to store the result. + * @param pszExpr The expression. Format string with the format DBGC extensions. + * @param va Format arguments. + */ + DECLCALLBACKMEMBER(int, pfnEvalV,(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, + const char *pszExpr, va_list va)) RT_IPRT_FORMAT_ATTR(3, 0); + + /** + * Print an error and fail the current command. + * + * @returns VBox status code to pass upwards. + * + * @param pCmdHlp Pointer to the command callback structure. + * @param pCmd The failing command. + * @param pszFormat The error message format string. + * @param va Format arguments. + */ + DECLCALLBACKMEMBER(int, pfnFailV,(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, + const char *pszFormat, va_list va)) RT_IPRT_FORMAT_ATTR(3, 0); + + /** + * Print an error and fail the current command. + * + * @returns VBox status code to pass upwards. + * + * @param pCmdHlp Pointer to the command callback structure. + * @param pCmd The failing command. + * @param rc The status code indicating the failure. This will + * be appended to the message after a colon (': '). + * @param pszFormat The error message format string. + * @param va Format arguments. + * + * @see DBGCCmdHlpFailRc + */ + DECLCALLBACKMEMBER(int, pfnFailRcV,(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, int rc, + const char *pszFormat, va_list va)) RT_IPRT_FORMAT_ATTR(4, 0); + + /** + * Parser error. + * + * @returns VBox status code to pass upwards. + * + * @param pCmdHlp Pointer to the command callback structure. + * @param pCmd The failing command, can be NULL but shouldn't. + * @param iArg The offending argument, -1 when lazy. + * @param pszExpr The expression. + * @param iLine The line number. + */ + DECLCALLBACKMEMBER(int, pfnParserError,(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, int iArg, const char *pszExpr, unsigned iLine)); + + /** + * Converts a DBGC variable to a DBGF address structure. + * + * @returns VBox status code. + * @param pCmdHlp Pointer to the command callback structure. + * @param pVar The variable to convert. + * @param pAddress The target address. + */ + DECLCALLBACKMEMBER(int, pfnVarToDbgfAddr,(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)); + + /** + * Converts a DBGF address structure to a DBGC variable. + * + * @returns VBox status code. + * @param pCmdHlp Pointer to the command callback structure. + * @param pAddress The source address. + * @param pResult The result variable. + */ + DECLCALLBACKMEMBER(int, pfnVarFromDbgfAddr,(PDBGCCMDHLP pCmdHlp, PCDBGFADDRESS pAddress, PDBGCVAR pResult)); + + /** + * Converts a DBGC variable to a 64-bit number. + * + * @returns VBox status code. + * @param pCmdHlp Pointer to the command callback structure. + * @param pVar The variable to convert. + * @param pu64Number Where to store the number. + */ + DECLCALLBACKMEMBER(int, pfnVarToNumber,(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, uint64_t *pu64Number)); + + /** + * Converts a DBGC variable to a boolean. + * + * @returns VBox status code. + * @param pCmdHlp Pointer to the command callback structure. + * @param pVar The variable to convert. + * @param pf Where to store the boolean. + */ + DECLCALLBACKMEMBER(int, pfnVarToBool,(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf)); + + /** + * Get the range of a variable in bytes, resolving symbols if necessary. + * + * @returns VBox status code. + * @param pCmdHlp Pointer to the command callback structure. + * @param pVar The variable to convert. + * @param cbElement Conversion factor for element ranges. + * @param cbDefault The default range. + * @param pcbRange The length of the range. + */ + DECLCALLBACKMEMBER(int, pfnVarGetRange,(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, uint64_t cbElement, uint64_t cbDefault, + uint64_t *pcbRange)); + + /** + * Converts a variable to one with the specified type. + * + * This preserves the range. + * + * @returns VBox status code. + * @param pCmdHlp Pointer to the command callback structure. + * @param pVar The variable to convert. + * @param enmToType The target type. + * @param fConvSyms If @c true, then attempt to resolve symbols. + * @param pResult The output variable. Can be the same as @a pVar. + */ + DECLCALLBACKMEMBER(int, pfnVarConvert,(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, DBGCVARTYPE enmToType, bool fConvSyms, + PDBGCVAR pResult)); + + /** + * Gets a DBGF output helper that directs the output to the debugger + * console. + * + * @returns Pointer to the helper structure. + * @param pCmdHlp Pointer to the command callback structure. + */ + DECLCALLBACKMEMBER(PCDBGFINFOHLP, pfnGetDbgfOutputHlp,(PDBGCCMDHLP pCmdHlp)); + + /** + * Gets the ID currently selected CPU. + * + * @returns Current CPU ID. + * @param pCmdHlp Pointer to the command callback structure. + */ + DECLCALLBACKMEMBER(VMCPUID, pfnGetCurrentCpu,(PDBGCCMDHLP pCmdHlp)); + + /** + * Gets the mode the currently selected CPU is running in, in the current + * context. + * + * @returns Current CPU mode. + * @param pCmdHlp Pointer to the command callback structure. + */ + DECLCALLBACKMEMBER(CPUMMODE, pfnGetCpuMode,(PDBGCCMDHLP pCmdHlp)); + + /** + * Prints the register set of the given CPU. + * + * @returns VBox status code. + * @param pCmdHlp Pointer to the command callback structure. + * @param idCpu The CPU ID to print the register set of. + * @param f64BitMode True to dump 64-bit state, false to dump 32-bit state, + * -1 to use the current CPU mode. + * @param fTerse Flag to indicate whether to dump the complete register set. + */ + DECLCALLBACKMEMBER(int, pfnRegPrintf, (PDBGCCMDHLP pCmdHlp, VMCPUID idCpu, int f64BitMode, bool fTerse)); + + /** End marker (DBGCCMDHLP_MAGIC). */ + uint32_t u32EndMarker; +} DBGCCMDHLP; + +/** Magic value for DBGCCMDHLP::u32Magic. (Fyodor Mikhaylovich Dostoyevsky) */ +#define DBGCCMDHLP_MAGIC UINT32_C(18211111) + + +#if defined(IN_RING3) || defined(IN_SLICKEDIT) + +/** + * Command helper for writing formatted text to the debug console. + * + * @returns VBox status. + * @param pCmdHlp Pointer to the command callback structure. + * @param pszFormat The format string. This may use all IPRT extensions as + * well as the debugger ones. + * @param ... Arguments specified in the format string. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(2, 3) DBGCCmdHlpPrintf(PDBGCCMDHLP pCmdHlp, const char *pszFormat, ...) +{ + va_list va; + int rc; + + va_start(va, pszFormat); + rc = pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, va); + va_end(va); + + return rc; +} + +/** + * Command helper for writing formatted text to the debug console. + * + * @returns VBox status. + * @param pCmdHlp Pointer to the command callback structure. + * @param pcbWritten Where to store the amount of written characters on success. + * @param pszFormat The format string. This may use all IPRT extensions as + * well as the debugger ones. + * @param ... Arguments specified in the format string. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(3, 4) DBGCCmdHlpPrintfEx(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, + const char *pszFormat, ...) +{ + va_list va; + int rc; + + va_start(va, pszFormat); + rc = pCmdHlp->pfnPrintfV(pCmdHlp, pcbWritten, pszFormat, va); + va_end(va); + + return rc; +} + +/** + * Command helper for writing formatted text to the debug console. + * + * @returns Number of bytes written. + * @param pCmdHlp Pointer to the command callback structure. + * @param pszFormat The format string. This may use all IPRT extensions as + * well as the debugger ones. + * @param ... Arguments specified in the format string. + */ +DECLINLINE(size_t) RT_IPRT_FORMAT_ATTR(2, 3) DBGCCmdHlpPrintfLen(PDBGCCMDHLP pCmdHlp, const char *pszFormat, ...) +{ + va_list va; + int rc; + size_t cbWritten = 0; + + va_start(va, pszFormat); + rc = pCmdHlp->pfnPrintfV(pCmdHlp, &cbWritten, pszFormat, va); + va_end(va); + + return RT_SUCCESS(rc) ? cbWritten : 0; +} + +/** + * @copydoc DBGCCMDHLP::pfnStrPrintf + */ +DECLINLINE(size_t) RT_IPRT_FORMAT_ATTR(4, 5) DBGCCmdHlpStrPrintf(PDBGCCMDHLP pCmdHlp, char *pszBuf, size_t cbBuf, + const char *pszFormat, ...) +{ + va_list va; + size_t cch; + + va_start(va, pszFormat); + cch = pCmdHlp->pfnStrPrintfV(pCmdHlp, pszBuf, cbBuf, pszFormat, va); + va_end(va); + + return cch; +} + +/** + * @copydoc DBGCCMDHLP::pfnVBoxError + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(3, 4) DBGCCmdHlpVBoxError(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...) +{ + va_list va; + + va_start(va, pszFormat); + rc = pCmdHlp->pfnVBoxErrorV(pCmdHlp, rc, pszFormat, va); + va_end(va); + + return rc; +} + +/** + * @copydoc DBGCCMDHLP::pfnMemRead + */ +DECLINLINE(int) DBGCCmdHlpMemRead(PDBGCCMDHLP pCmdHlp, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead) +{ + return pCmdHlp->pfnMemRead(pCmdHlp, pvBuffer, cbRead, pVarPointer, pcbRead); +} + +/** + * Evaluates an expression. + * (Hopefully the parser and functions are fully reentrant.) + * + * @returns VBox status code appropriate to return from a command. + * @param pCmdHlp Pointer to the command callback structure. + * @param pResult Where to store the result. + * @param pszExpr The expression. Format string with the format DBGC extensions. + * @param ... Format arguments. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(3, 4) DBGCCmdHlpEval(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, ...) +{ + va_list va; + int rc; + + va_start(va, pszExpr); + rc = pCmdHlp->pfnEvalV(pCmdHlp, pResult, pszExpr, va); + va_end(va); + + return rc; +} + +/** + * Print an error and fail the current command. + * + * @returns VBox status code to pass upwards. + * + * @param pCmdHlp Pointer to the command callback structure. + * @param pCmd The failing command. + * @param pszFormat The error message format string. + * @param ... Format arguments. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(3, 4) DBGCCmdHlpFail(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, const char *pszFormat, ...) +{ + va_list va; + int rc; + + va_start(va, pszFormat); + rc = pCmdHlp->pfnFailV(pCmdHlp, pCmd, pszFormat, va); + va_end(va); + + return rc; +} + +/** + * Print an error and fail the current command. + * + * Usage example: + * @code + int rc = VMMR3Something(pVM); + if (RT_FAILURE(rc)) + return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "VMMR3Something"); + return VINF_SUCCESS; + * @endcode + * + * @returns VBox status code to pass upwards. + * + * @param pCmdHlp Pointer to the command callback structure. + * @param pCmd The failing command. + * @param rc The status code indicating the failure. + * @param pszFormat The error message format string. + * @param ... Format arguments. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(4, 5) DBGCCmdHlpFailRc(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, int rc, + const char *pszFormat, ...) +{ + va_list va; + + va_start(va, pszFormat); + rc = pCmdHlp->pfnFailRcV(pCmdHlp, pCmd, rc, pszFormat, va); + va_end(va); + + return rc; +} + +/** + * @copydoc DBGCCMDHLP::pfnParserError + */ +DECLINLINE(int) DBGCCmdHlpParserError(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, int iArg, const char *pszExpr, unsigned iLine) +{ + return pCmdHlp->pfnParserError(pCmdHlp, pCmd, iArg, pszExpr, iLine); +} + +/** Assert+return like macro for checking parser sanity. + * Returns with failure if the precodition is not met. */ +#define DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, iArg, expr) \ + do { \ + if (!(expr)) \ + return DBGCCmdHlpParserError(pCmdHlp, pCmd, iArg, #expr, __LINE__); \ + } while (0) + +/** Assert+return like macro that the VM handle is present. + * Returns with failure if the VM handle is NIL. */ +#define DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM) \ + do { \ + if (!(pUVM)) \ + return DBGCCmdHlpFail(pCmdHlp, pCmd, "No VM selected"); \ + } while (0) + +/** + * @copydoc DBGCCMDHLP::pfnVarToDbgfAddr + */ +DECLINLINE(int) DBGCCmdHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress) +{ + return pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, pVar, pAddress); +} + +/** + * @copydoc DBGCCMDHLP::pfnVarFromDbgfAddr + */ +DECLINLINE(int) DBGCCmdHlpVarFromDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGFADDRESS pAddress, PDBGCVAR pResult) +{ + return pCmdHlp->pfnVarFromDbgfAddr(pCmdHlp, pAddress, pResult); +} + +/** + * Converts an variable to a flat address. + * + * @returns VBox status code. + * @param pCmdHlp Pointer to the command callback structure. + * @param pVar The variable to convert. + * @param pFlatPtr Where to store the flat address. + */ +DECLINLINE(int) DBGCCmdHlpVarToFlatAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PRTGCPTR pFlatPtr) +{ + DBGFADDRESS Addr; + int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, pVar, &Addr); + if (RT_SUCCESS(rc)) + *pFlatPtr = Addr.FlatPtr; + return rc; +} + +/** + * @copydoc DBGCCMDHLP::pfnVarToNumber + */ +DECLINLINE(int) DBGCCmdHlpVarToNumber(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, uint64_t *pu64Number) +{ + return pCmdHlp->pfnVarToNumber(pCmdHlp, pVar, pu64Number); +} + +/** + * @copydoc DBGCCMDHLP::pfnVarToBool + */ +DECLINLINE(int) DBGCCmdHlpVarToBool(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf) +{ + return pCmdHlp->pfnVarToBool(pCmdHlp, pVar, pf); +} + +/** + * @copydoc DBGCCMDHLP::pfnVarGetRange + */ +DECLINLINE(int) DBGCCmdHlpVarGetRange(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, uint64_t cbElement, uint64_t cbDefault, uint64_t *pcbRange) +{ + return pCmdHlp->pfnVarGetRange(pCmdHlp, pVar, cbElement, cbDefault, pcbRange); +} + +/** + * @copydoc DBGCCMDHLP::pfnVarConvert + */ +DECLINLINE(int) DBGCCmdHlpConvert(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, DBGCVARTYPE enmToType, bool fConvSyms, PDBGCVAR pResult) +{ + return pCmdHlp->pfnVarConvert(pCmdHlp, pVar, enmToType, fConvSyms, pResult); +} + +/** + * @copydoc DBGCCMDHLP::pfnGetDbgfOutputHlp + */ +DECLINLINE(PCDBGFINFOHLP) DBGCCmdHlpGetDbgfOutputHlp(PDBGCCMDHLP pCmdHlp) +{ + return pCmdHlp->pfnGetDbgfOutputHlp(pCmdHlp); +} + +/** + * @copydoc DBGCCMDHLP::pfnGetCurrentCpu + */ +DECLINLINE(VMCPUID) DBGCCmdHlpGetCurrentCpu(PDBGCCMDHLP pCmdHlp) +{ + return pCmdHlp->pfnGetCurrentCpu(pCmdHlp); +} + +/** + * @copydoc DBGCCMDHLP::pfnGetCpuMode + */ +DECLINLINE(CPUMMODE) DBGCCmdHlpGetCpuMode(PDBGCCMDHLP pCmdHlp) +{ + return pCmdHlp->pfnGetCpuMode(pCmdHlp); +} + +/** + * @copydoc DBGCCMDHLP::pfnRegPrintf + */ +DECLINLINE(int) DBGCCmdHlpRegPrintf(PDBGCCMDHLP pCmdHlp, VMCPUID idCpu, int f64BitMode, bool fTerse) +{ + return pCmdHlp->pfnRegPrintf(pCmdHlp, idCpu, f64BitMode, fTerse); +} + +#endif /* IN_RING3 */ + + + +/** + * Command handler. + * + * The console will call the handler for a command once it's finished + * parsing the user input. The command handler function is responsible + * for executing the command itself. + * + * @returns VBox status. + * @param pCmd Pointer to the command descriptor (as registered). + * @param pCmdHlp Pointer to command helper functions. + * @param pUVM The user mode VM handle, can in theory be NULL. + * @param paArgs Pointer to (readonly) array of arguments. + * @param cArgs Number of arguments in the array. + */ +typedef DECLCALLBACKTYPE(int, FNDBGCCMD,(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)); +/** Pointer to a FNDBGCCMD() function. */ +typedef FNDBGCCMD *PFNDBGCCMD; + +/** + * DBGC command descriptor. + */ +typedef struct DBGCCMD +{ + /** Command string. */ + const char *pszCmd; + /** Minimum number of arguments. */ + unsigned cArgsMin; + /** Max number of arguments. */ + unsigned cArgsMax; + /** Argument descriptors (array). */ + PCDBGCVARDESC paArgDescs; + /** Number of argument descriptors. */ + unsigned cArgDescs; + /** flags. (reserved for now) */ + unsigned fFlags; + /** Handler function. */ + PFNDBGCCMD pfnHandler; + /** Command syntax. */ + const char *pszSyntax; + /** Command description. */ + const char *pszDescription; +} DBGCCMD; + +/** DBGCCMD Flags. + * @{ + */ +/** @} */ + + +/** + * Function handler. + * + * The console will call the handler for a command once it's finished + * parsing the user input. The command handler function is responsible + * for executing the command itself. + * + * @returns VBox status. + * @param pFunc Pointer to the function descriptor (as registered). + * @param pCmdHlp Pointer to command helper functions. + * @param pUVM The user mode VM handle, can in theory be NULL. + * @param paArgs Pointer to (readonly) array of arguments. + * @param cArgs Number of arguments in the array. + * @param pResult Where to return the result. + */ +typedef DECLCALLBACKTYPE(int, FNDBGCFUNC,(PCDBGCFUNC pFunc, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs, + PDBGCVAR pResult)); +/** Pointer to a FNDBGCFUNC() function. */ +typedef FNDBGCFUNC *PFNDBGCFUNC; + +/** + * DBGC function descriptor. + */ +typedef struct DBGCFUNC +{ + /** Command string. */ + const char *pszFuncNm; + /** Minimum number of arguments. */ + unsigned cArgsMin; + /** Max number of arguments. */ + unsigned cArgsMax; + /** Argument descriptors (array). */ + PCDBGCVARDESC paArgDescs; + /** Number of argument descriptors. */ + unsigned cArgDescs; + /** flags. (reserved for now) */ + unsigned fFlags; + /** Handler function. */ + PFNDBGCFUNC pfnHandler; + /** Function syntax. */ + const char *pszSyntax; + /** Function description. */ + const char *pszDescription; +} DBGCFUNC; + + +/** Pointer to a const I/O callback table. */ +typedef const struct DBGCIO *PCDBGCIO; + +/** + * I/O callback table. + */ +typedef struct DBGCIO +{ + /** + * Destroys the given I/O instance. + * + * @returns nothing. + * @param pIo Pointer to the I/O structure supplied by the I/O provider. + */ + DECLCALLBACKMEMBER(void, pfnDestroy, (PCDBGCIO pIo)); + + /** + * Wait for input available for reading. + * + * @returns Flag whether there is input ready upon return. + * @retval true if there is input ready. + * @retval false if there not input ready. + * @param pIo Pointer to the I/O structure supplied by + * the I/O provider. The backend can use this to find it's instance data. + * @param cMillies Number of milliseconds to wait on input data. + */ + DECLCALLBACKMEMBER(bool, pfnInput, (PCDBGCIO pIo, uint32_t cMillies)); + + /** + * Read input. + * + * @returns VBox status code. + * @param pIo Pointer to the I/O structure supplied by + * the I/O provider. The backend can use this to find it's instance data. + * @param pvBuf Where to put the bytes we read. + * @param cbBuf Maximum nymber of bytes to read. + * @param pcbRead Where to store the number of bytes actually read. + * If NULL the entire buffer must be filled for a + * successful return. + */ + DECLCALLBACKMEMBER(int, pfnRead, (PCDBGCIO pIo, void *pvBuf, size_t cbBuf, size_t *pcbRead)); + + /** + * Write (output). + * + * @returns VBox status code. + * @param pIo Pointer to the I/O structure supplied by + * the I/O provider. The backend can use this to find it's instance data. + * @param pvBuf What to write. + * @param cbBuf Number of bytes to write. + * @param pcbWritten Where to store the number of bytes actually written. + * If NULL the entire buffer must be successfully written. + */ + DECLCALLBACKMEMBER(int, pfnWrite, (PCDBGCIO pIo, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)); + + /** + * Marks the beginning of a new packet being sent - optional. + * + * @returns VBox status code. + * @param pIo Pointer to the I/O structure supplied by + * the I/O provider. The backend can use this to find it's instance data. + * @param cbPktHint Size of the packet in bytes, serves as a hint for the I/O provider to arrange buffers. + * Give 0 if size is unknown upfront. + */ + DECLCALLBACKMEMBER(int, pfnPktBegin, (PCDBGCIO pIo, size_t cbPktHint)); + + /** + * Marks the end of the packet - optional. + * + * @returns VBox status code. + * @param pIo Pointer to the I/O structure supplied by + * the I/O provider. The backend can use this to find it's instance data. + * + * @note Some I/O providers might decide to send data only when this is called not in the + * DBGCIO::pfnWrite callback. + */ + DECLCALLBACKMEMBER(int, pfnPktEnd, (PCDBGCIO pIo)); + + /** + * Ready / busy notification. + * + * @returns nothing. + * @param pIo Pointer to the I/O structure supplied by + * the I/O provider. The backend can use this to find it's instance data. + * @param fReady Whether it's ready (true) or busy (false). + */ + DECLCALLBACKMEMBER(void, pfnSetReady, (PCDBGCIO pIo, bool fReady)); + +} DBGCIO; +/** Pointer to an I/O callback table. */ +typedef DBGCIO *PDBGCIO; + + +DBGDECL(int) DBGCCreate(PUVM pUVM, PCDBGCIO pIo, unsigned fFlags); +DBGDECL(int) DBGCRegisterCommands(PCDBGCCMD paCommands, unsigned cCommands); +DBGDECL(int) DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands); + +DBGDECL(int) DBGCIoCreate(PUVM pUVM, void **ppvData); +DBGDECL(int) DBGCIoTerminate(PUVM pUVM, void *pvData); + +/** @} */ + +#endif /* IN_RING3 */ + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_dbg_h */ diff --git a/include/VBox/dbggui.h b/include/VBox/dbggui.h new file mode 100644 index 00000000..88c0b46d --- /dev/null +++ b/include/VBox/dbggui.h @@ -0,0 +1,191 @@ +/** @file + * DBGGUI - The VirtualBox Debugger GUI. (VBoxDbg) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_dbggui_h +#define VBOX_INCLUDED_dbggui_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_dbggui VirtualBox Debugger GUI + * @ingroup grp_dbg + * @{ + */ + +#ifdef RT_OS_WINDOWS +struct ISession; +#else +class ISession; +#endif + +/** Pointer to the debugger GUI instance structure. */ +typedef struct DBGGUI *PDBGGUI; + +/** Virtual method table for the debugger GUI. */ +typedef struct DBGGUIVT +{ + /** The version. (DBGGUIVT_VERSION) */ + uint32_t u32Version; + /** @copydoc DBGGuiDestroy */ + DECLCALLBACKMEMBER(int, pfnDestroy,(PDBGGUI pGui)); + /** @copydoc DBGGuiAdjustRelativePos */ + DECLCALLBACKMEMBER(void, pfnAdjustRelativePos,(PDBGGUI pGui, int x, int y, unsigned cx, unsigned cy)); + /** @copydoc DBGGuiShowStatistics */ + DECLCALLBACKMEMBER(int, pfnShowStatistics,(PDBGGUI pGui, const char *pszFilter, const char *pszExpand)); + /** @copydoc DBGGuiShowCommandLine */ + DECLCALLBACKMEMBER(int, pfnShowCommandLine,(PDBGGUI pGui)); + /** @copydoc DBGGuiSetParent */ + DECLCALLBACKMEMBER(void, pfnSetParent,(PDBGGUI pGui, void *pvParent)); + /** @copydoc DBGGuiSetMenu */ + DECLCALLBACKMEMBER(void, pfnSetMenu,(PDBGGUI pGui, void *pvMenu)); + /** The end version. (DBGGUIVT_VERSION) */ + uint32_t u32EndVersion; +} DBGGUIVT; +/** Pointer to the virtual method table for the debugger GUI. */ +typedef DBGGUIVT const *PCDBGGUIVT; +/** The u32Version value. + * The first byte is the minor version, the 2nd byte is major version number. + * The high 16-bit word is a magic. */ +#define DBGGUIVT_VERSION UINT32_C(0xbead0200) +/** Macro for determining whether two versions are compatible or not. + * @returns boolean result. + * @param uVer1 The first version number. + * @param uVer2 The second version number. + */ +#define DBGGUIVT_ARE_VERSIONS_COMPATIBLE(uVer1, uVer2) \ + ( ((uVer1) & UINT32_C(0xffffff00)) == ((uVer2) & UINT32_C(0xffffff00)) ) + + +/** + * Creates the debugger GUI. + * + * @returns VBox status code. + * @param pSession The VirtualBox session. + * @param ppGui Where to store the pointer to the debugger instance. + * @param ppGuiVT Where to store the virtual method table pointer. + * Optional. + */ +DBGDECL(int) DBGGuiCreate(ISession *pSession, PDBGGUI *ppGui, PCDBGGUIVT *ppGuiVT); +/** @copydoc DBGGuiCreate */ +typedef DECLCALLBACKTYPE(int, FNDBGGUICREATE,(ISession *pSession, PDBGGUI *ppGui, PCDBGGUIVT *ppGuiVT)); +/** Pointer to DBGGuiCreate. */ +typedef FNDBGGUICREATE *PFNDBGGUICREATE; + +/** + * Creates the debugger GUI given a VM handle. + * + * @returns VBox status code. + * @param pUVM The VM handle. + * @param pVMM The VMM function table. + * @param ppGui Where to store the pointer to the debugger instance. + * @param ppGuiVT Where to store the virtual method table pointer. + * Optional. + */ +DBGDECL(int) DBGGuiCreateForVM(PUVM pUVM, PCVMMR3VTABLE pVMM, PDBGGUI *ppGui, PCDBGGUIVT *ppGuiVT); +/** @copydoc DBGGuiCreateForVM */ +typedef DECLCALLBACKTYPE(int, FNDBGGUICREATEFORVM,(PUVM pUVM, PCVMMR3VTABLE pVMM, PDBGGUI *ppGui, PCDBGGUIVT *ppGuiVT)); +/** Pointer to DBGGuiCreateForVM. */ +typedef FNDBGGUICREATEFORVM *PFNDBGGUICREATEFORVM; + +/** + * Destroys the debugger GUI. + * + * @returns VBox status code. + * @param pGui The instance returned by DBGGuiCreate(). + */ +DBGDECL(int) DBGGuiDestroy(PDBGGUI pGui); + +/** + * Notifies the debugger GUI that the console window (or whatever) has changed + * size or position. + * + * @param pGui The instance returned by DBGGuiCreate(). + * @param x The x-coordinate of the window the debugger is relative to. + * @param y The y-coordinate of the window the debugger is relative to. + * @param cx The width of the window the debugger is relative to. + * @param cy The height of the window the debugger is relative to. + */ +DBGDECL(void) DBGGuiAdjustRelativePos(PDBGGUI pGui, int x, int y, unsigned cx, unsigned cy); + +/** + * Shows the default statistics window. + * + * @returns VBox status code. + * @param pGui The instance returned by DBGGuiCreate(). + * @param pszFilter Filter pattern. + * @param pszExpand Expand pattern. + */ +DBGDECL(int) DBGGuiShowStatistics(PDBGGUI pGui, const char *pszFilter, const char *pszExpand); + +/** + * Shows the default command line window. + * + * @returns VBox status code. + * @param pGui The instance returned by DBGGuiCreate(). + */ +DBGDECL(int) DBGGuiShowCommandLine(PDBGGUI pGui); + +/** + * Sets the parent windows. + * + * @param pGui The instance returned by DBGGuiCreate(). + * @param pvParent Pointer to a QWidget object. + * + * @remarks This will no affect any existing windows, so call it right after + * creating the thing. + */ +DBGDECL(void) DBGGuiSetParent(PDBGGUI pGui, void *pvParent); + +/** + * Sets the debug menu object. + * + * @param pGui The instance returned by DBGGuiCreate(). + * @param pvMenu Pointer to a QMenu object. + * + * @remarks Call right after creation or risk losing menu item. + */ +DBGDECL(void) DBGGuiSetMenu(PDBGGUI pGui, void *pvMenu); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_dbggui_h */ + diff --git a/include/VBox/dbus-calls.h b/include/VBox/dbus-calls.h new file mode 100644 index 00000000..4b9cfadb --- /dev/null +++ b/include/VBox/dbus-calls.h @@ -0,0 +1,180 @@ +/** @file + * Stubs for dynamically loading libdbus-1 and the symbols which are needed by + * VirtualBox. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +/** The file name of the DBus library */ +#define RT_RUNTIME_LOADER_LIB_NAME "libdbus-1.so.3" + +/** The name of the loader function */ +#define RT_RUNTIME_LOADER_FUNCTION RTDBusLoadLib + +/** The following are the symbols which we need from the DBus library. */ +#define RT_RUNTIME_LOADER_INSERT_SYMBOLS \ + RT_PROXY_STUB(dbus_error_init, void, (DBusError *error), \ + (error)) \ + RT_PROXY_STUB(dbus_error_is_set, dbus_bool_t, (const DBusError *error), \ + (error)) \ + RT_PROXY_STUB(dbus_bus_get, DBusConnection *, \ + (DBusBusType type, DBusError *error), (type, error)) \ + RT_PROXY_STUB(dbus_bus_get_private, DBusConnection *, \ + (DBusBusType type, DBusError *error), (type, error)) \ + RT_PROXY_STUB(dbus_error_free, void, (DBusError *error), \ + (error)) \ + RT_PROXY_STUB(dbus_free_string_array, void, (char **str_array), \ + (str_array)) \ + RT_PROXY_STUB(dbus_connection_ref, DBusConnection *, (DBusConnection *connection), \ + (connection)) \ + RT_PROXY_STUB(dbus_connection_unref, void, (DBusConnection *connection), \ + (connection)) \ + RT_PROXY_STUB(dbus_connection_close, void, (DBusConnection *connection), \ + (connection)) \ + RT_PROXY_STUB(dbus_connection_send, dbus_bool_t, \ + (DBusConnection *connection, DBusMessage *message, dbus_uint32_t *serial), \ + (connection, message, serial)) \ + RT_PROXY_STUB(dbus_connection_flush, void, (DBusConnection *connection), \ + (connection)) \ + RT_PROXY_STUB(dbus_connection_set_exit_on_disconnect, void, \ + (DBusConnection *connection, dbus_bool_t boolean), \ + (connection, boolean)) \ + RT_PROXY_STUB(dbus_bus_name_has_owner, dbus_bool_t, \ + (DBusConnection *connection, const char *string, DBusError *error), \ + (connection, string, error)) \ + RT_PROXY_STUB(dbus_bus_add_match, void, \ + (DBusConnection *connection, const char *string, \ + DBusError *error), \ + (connection, string, error)) \ + RT_PROXY_STUB(dbus_bus_remove_match, void, \ + (DBusConnection *connection, const char *string, \ + DBusError *error), \ + (connection, string, error)) \ + RT_PROXY_STUB(dbus_message_append_args_valist, dbus_bool_t, \ + (DBusMessage *message, int first_arg_type, va_list var_args), \ + (message, first_arg_type, var_args)) \ + RT_PROXY_STUB(dbus_message_get_args_valist, dbus_bool_t, \ + (DBusMessage *message, DBusError *error, int first_arg_type, va_list var_args), \ + (message, error, first_arg_type, var_args)) \ + RT_PROXY_STUB(dbus_message_get_type, int, \ + (DBusMessage *message), \ + (message)) \ + RT_PROXY_STUB(dbus_message_iter_open_container, dbus_bool_t, \ + (DBusMessageIter *iter, int type, const char *contained_signature, DBusMessageIter *sub), \ + (iter, type, contained_signature, sub)) \ + RT_PROXY_STUB(dbus_message_iter_close_container, dbus_bool_t, \ + (DBusMessageIter *iter, DBusMessageIter *sub), \ + (iter, sub)) \ + RT_PROXY_STUB(dbus_message_iter_append_fixed_array, dbus_bool_t, \ + (DBusMessageIter *iter, int element_type, const void *value, int n_elements), \ + (iter, element_type, value, n_elements)) \ + RT_PROXY_STUB(dbus_message_unref, void, (DBusMessage *message), \ + (message)) \ + RT_PROXY_STUB(dbus_message_new_method_call, DBusMessage*, \ + (const char *string1, const char *string2, const char *string3, \ + const char *string4), \ + (string1, string2, string3, string4)) \ + RT_PROXY_STUB(dbus_message_iter_init_append, void, \ + (DBusMessage *message, DBusMessageIter *iter), \ + (message, iter)) \ + RT_PROXY_STUB(dbus_message_iter_append_basic, dbus_bool_t, \ + (DBusMessageIter *iter, int val, const void *string), \ + (iter, val, string)) \ + RT_PROXY_STUB(dbus_connection_send_with_reply_and_block, DBusMessage *, \ + (DBusConnection *connection, DBusMessage *message, int val, \ + DBusError *error), \ + (connection, message, val, error)) \ + RT_PROXY_STUB(dbus_message_iter_init, dbus_bool_t, \ + (DBusMessage *message, DBusMessageIter *iter), \ + (message, iter)) \ + RT_PROXY_STUB(dbus_message_get_signature, char *, (DBusMessage *message), \ + (message)) \ + RT_PROXY_STUB(dbus_message_iter_get_signature, char *, (DBusMessageIter *iter), \ + (iter)) \ + RT_PROXY_STUB(dbus_message_iter_get_arg_type, int, (DBusMessageIter *iter), \ + (iter)) \ + RT_PROXY_STUB(dbus_message_iter_get_element_type, int, \ + (DBusMessageIter *iter), (iter)) \ + RT_PROXY_STUB(dbus_message_iter_recurse, void, \ + (DBusMessageIter *iter1, DBusMessageIter *iter2), \ + (iter1, iter2)) \ + RT_PROXY_STUB(dbus_message_iter_get_basic, void, \ + (DBusMessageIter *iter, void *pvoid), (iter, pvoid)) \ + RT_PROXY_STUB(dbus_message_iter_has_next, dbus_bool_t, \ + (DBusMessageIter *iter), (iter)) \ + RT_PROXY_STUB(dbus_message_iter_next, dbus_bool_t, (DBusMessageIter *iter), \ + (iter)) \ + RT_PROXY_STUB(dbus_message_iter_abandon_container_if_open, void, \ + (DBusMessageIter *iter, DBusMessageIter *sub), (iter, sub)) \ + RT_PROXY_STUB(dbus_connection_add_filter, dbus_bool_t, \ + (DBusConnection *connection, \ + DBusHandleMessageFunction function1, void *pvoid, \ + DBusFreeFunction function2), \ + (connection, function1, pvoid, function2)) \ + RT_PROXY_STUB(dbus_connection_remove_filter, void, \ + (DBusConnection *connection, \ + DBusHandleMessageFunction function, void *pvoid), \ + (connection, function, pvoid)) \ + RT_PROXY_STUB(dbus_connection_read_write, dbus_bool_t, \ + (DBusConnection *connection, int val), (connection, val)) \ + RT_PROXY_STUB(dbus_connection_read_write_dispatch, dbus_bool_t, \ + (DBusConnection *connection, int val), (connection, val)) \ + RT_PROXY_STUB(dbus_message_is_signal, dbus_bool_t, \ + (DBusMessage *message, const char *string1, \ + const char *string2), \ + (message, string1, string2)) \ + RT_PROXY_STUB(dbus_connection_pop_message, DBusMessage *, \ + (DBusConnection *connection), (connection)) \ + RT_PROXY_STUB(dbus_set_error_from_message, dbus_bool_t, \ + (DBusError *error, DBusMessage *message), (error, message)) \ + RT_PROXY_STUB(dbus_free, void, \ + (void *memory), (memory)) + +#ifdef VBOX_DBUS_GENERATE_HEADER +# define RT_RUNTIME_LOADER_GENERATE_HEADER +# define RT_RUNTIME_LOADER_GENERATE_DECLS +# include <iprt/runtime-loader.h> +# undef RT_RUNTIME_LOADER_GENERATE_HEADER +# undef RT_RUNTIME_LOADER_GENERATE_DECLS + +#elif defined(VBOX_DBUS_GENERATE_BODY) +# define RT_RUNTIME_LOADER_GENERATE_BODY_STUBS +# include <iprt/runtime-loader.h> +# undef RT_RUNTIME_LOADER_GENERATE_BODY_STUBS + +#else +# error This file should only be included to generate stubs for loading the DBus library at runtime +#endif + +#undef RT_RUNTIME_LOADER_LIB_NAME +#undef RT_RUNTIME_LOADER_INSERT_SYMBOLS + diff --git a/include/VBox/dbus.h b/include/VBox/dbus.h new file mode 100644 index 00000000..1b3993c1 --- /dev/null +++ b/include/VBox/dbus.h @@ -0,0 +1,139 @@ +/** @file + * Module to dynamically load libdbus and load all symbols which are needed by + * VirtualBox. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_dbus_h +#define VBOX_INCLUDED_dbus_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/stdarg.h> + +#ifndef __cplusplus +# error "This header requires C++ to avoid name clashes." +#endif + +/** Types and defines from the dbus header files which we need. These are + * taken more or less verbatim from the DBus public interface header files. */ +struct DBusError +{ + const char *name; + const char *message; + unsigned int dummy1 : 1; + unsigned int dummy2 : 1; + unsigned int dummy3 : 1; + unsigned int dummy4 : 1; + unsigned int dummy5 : 1; + void *padding1; +}; +typedef struct DBusError DBusError; + +struct DBusConnection; +typedef struct DBusConnection DBusConnection; + +typedef uint32_t dbus_bool_t; +typedef uint32_t dbus_uint32_t; +typedef enum { DBUS_BUS_SESSION, DBUS_BUS_SYSTEM, DBUS_BUS_STARTER } DBusBusType; + +struct DBusMessage; +typedef struct DBusMessage DBusMessage; + +struct DBusMessageIter +{ + void *dummy1; + void *dummy2; + dbus_uint32_t dummy3; + int dummy4; + int dummy5; + int dummy6; + int dummy7; + int dummy8; + int dummy9; + int dummy10; + int dummy11; + int pad1; + int pad2; + void *pad3; +}; +typedef struct DBusMessageIter DBusMessageIter; + +#define DBUS_ERROR_NO_MEMORY "org.freedesktop.DBus.Error.NoMemory" + +/* Message types. */ +#define DBUS_MESSAGE_TYPE_INVALID 0 +#define DBUS_MESSAGE_TYPE_METHOD_CALL 1 +#define DBUS_MESSAGE_TYPE_METHOD_RETURN 2 +#define DBUS_MESSAGE_TYPE_ERROR 3 +#define DBUS_MESSAGE_TYPE_SIGNAL 4 + +/* Primitive types. */ +#define DBUS_TYPE_INVALID ((int) '\0') +#define DBUS_TYPE_BOOLEAN ((int) 'b') +#define DBUS_TYPE_INT32 ((int) 'i') +#define DBUS_TYPE_UINT32 ((int) 'u') +#define DBUS_TYPE_DOUBLE ((int) 'd') +#define DBUS_TYPE_STRING ((int) 's') +#define DBUS_TYPE_STRING_AS_STRING "s" + +/* Compound types. */ +#define DBUS_TYPE_OBJECT_PATH ((int) 'o') +#define DBUS_TYPE_ARRAY ((int) 'a') +#define DBUS_TYPE_ARRAY_AS_STRING "a" +#define DBUS_TYPE_DICT_ENTRY ((int) 'e') +#define DBUS_TYPE_DICT_ENTRY_AS_STRING "e" +#define DBUS_TYPE_STRUCT ((int) 'r') + +typedef enum +{ + DBUS_HANDLER_RESULT_HANDLED, + DBUS_HANDLER_RESULT_NOT_YET_HANDLED, + DBUS_HANDLER_RESULT_NEED_MEMORY +} DBusHandlerResult; + +typedef DBusHandlerResult (* DBusHandleMessageFunction)(DBusConnection *, + DBusMessage *, void *); +typedef void (* DBusFreeFunction) (void *); + +/* Declarations of the functions that we need from libdbus-1 */ +#define VBOX_DBUS_GENERATE_HEADER + +#include <VBox/dbus-calls.h> + +#undef VBOX_DBUS_GENERATE_HEADER + +#endif /* !VBOX_INCLUDED_dbus_h */ + diff --git a/include/VBox/dis.h b/include/VBox/dis.h new file mode 100644 index 00000000..f20c895e --- /dev/null +++ b/include/VBox/dis.h @@ -0,0 +1,912 @@ +/** @file + * DIS - The VirtualBox Disassembler. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_dis_h +#define VBOX_INCLUDED_dis_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/disopcode.h> +#include <iprt/assert.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_dis VBox Disassembler + * @{ */ + +/** @name Prefix byte flags (DISSTATE::fPrefix). + * @{ + */ +#define DISPREFIX_NONE UINT8_C(0x00) +/** non-default address size. */ +#define DISPREFIX_ADDRSIZE UINT8_C(0x01) +/** non-default operand size. */ +#define DISPREFIX_OPSIZE UINT8_C(0x02) +/** lock prefix. */ +#define DISPREFIX_LOCK UINT8_C(0x04) +/** segment prefix. */ +#define DISPREFIX_SEG UINT8_C(0x08) +/** rep(e) prefix (not a prefix, but we'll treat is as one). */ +#define DISPREFIX_REP UINT8_C(0x10) +/** rep(e) prefix (not a prefix, but we'll treat is as one). */ +#define DISPREFIX_REPNE UINT8_C(0x20) +/** REX prefix (64 bits) */ +#define DISPREFIX_REX UINT8_C(0x40) +/** @} */ + +/** @name VEX.Lvvvv prefix destination register flag. + * @{ + */ +#define VEX_LEN256 UINT8_C(0x01) +#define VEXREG_IS256B(x) ((x) & VEX_LEN256) +/* Convert second byte of VEX prefix to internal format */ +#define VEX_2B2INT(x) ((((x) >> 2) & 0x1f)) +#define VEX_HAS_REX_R(x) (!((x) & 0x80)) + +#define DISPREFIX_VEX_FLAG_W UINT8_C(0x01) + /** @} */ + +/** @name 64 bits prefix byte flags (DISSTATE::fRexPrefix). + * Requires VBox/disopcode.h. + * @{ + */ +#define DISPREFIX_REX_OP_2_FLAGS(a) (a - OP_PARM_REX_START) +/*#define DISPREFIX_REX_FLAGS DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX) - 0, which is no flag */ +#define DISPREFIX_REX_FLAGS_B DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_B) +#define DISPREFIX_REX_FLAGS_X DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_X) +#define DISPREFIX_REX_FLAGS_XB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_XB) +#define DISPREFIX_REX_FLAGS_R DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_R) +#define DISPREFIX_REX_FLAGS_RB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_RB) +#define DISPREFIX_REX_FLAGS_RX DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_RX) +#define DISPREFIX_REX_FLAGS_RXB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_RXB) +#define DISPREFIX_REX_FLAGS_W DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_W) +#define DISPREFIX_REX_FLAGS_WB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WB) +#define DISPREFIX_REX_FLAGS_WX DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WX) +#define DISPREFIX_REX_FLAGS_WXB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WXB) +#define DISPREFIX_REX_FLAGS_WR DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WR) +#define DISPREFIX_REX_FLAGS_WRB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WRB) +#define DISPREFIX_REX_FLAGS_WRX DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WRX) +#define DISPREFIX_REX_FLAGS_WRXB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WRXB) +/** @} */ +AssertCompile(RT_IS_POWER_OF_TWO(DISPREFIX_REX_FLAGS_B)); +AssertCompile(RT_IS_POWER_OF_TWO(DISPREFIX_REX_FLAGS_X)); +AssertCompile(RT_IS_POWER_OF_TWO(DISPREFIX_REX_FLAGS_W)); +AssertCompile(RT_IS_POWER_OF_TWO(DISPREFIX_REX_FLAGS_R)); + +/** @name Operand type (DISOPCODE::fOpType). + * @{ + */ +#define DISOPTYPE_INVALID RT_BIT_32(0) +#define DISOPTYPE_HARMLESS RT_BIT_32(1) +#define DISOPTYPE_CONTROLFLOW RT_BIT_32(2) +#define DISOPTYPE_POTENTIALLY_DANGEROUS RT_BIT_32(3) +#define DISOPTYPE_DANGEROUS RT_BIT_32(4) +#define DISOPTYPE_PORTIO RT_BIT_32(5) +#define DISOPTYPE_PRIVILEGED RT_BIT_32(6) +#define DISOPTYPE_PRIVILEGED_NOTRAP RT_BIT_32(7) +#define DISOPTYPE_UNCOND_CONTROLFLOW RT_BIT_32(8) +#define DISOPTYPE_RELATIVE_CONTROLFLOW RT_BIT_32(9) +#define DISOPTYPE_COND_CONTROLFLOW RT_BIT_32(10) +#define DISOPTYPE_INTERRUPT RT_BIT_32(11) +#define DISOPTYPE_ILLEGAL RT_BIT_32(12) +#define DISOPTYPE_RRM_DANGEROUS RT_BIT_32(14) /**< Some additional dangerous ones when recompiling raw r0. */ +#define DISOPTYPE_RRM_DANGEROUS_16 RT_BIT_32(15) /**< Some additional dangerous ones when recompiling 16-bit raw r0. */ +#define DISOPTYPE_RRM_MASK (DISOPTYPE_RRM_DANGEROUS | DISOPTYPE_RRM_DANGEROUS_16) +#define DISOPTYPE_INHIBIT_IRQS RT_BIT_32(16) /**< Will or can inhibit irqs (sti, pop ss, mov ss) */ +#define DISOPTYPE_PORTIO_READ RT_BIT_32(17) +#define DISOPTYPE_PORTIO_WRITE RT_BIT_32(18) +#define DISOPTYPE_INVALID_64 RT_BIT_32(19) /**< Invalid in 64 bits mode */ +#define DISOPTYPE_ONLY_64 RT_BIT_32(20) /**< Only valid in 64 bits mode */ +#define DISOPTYPE_DEFAULT_64_OP_SIZE RT_BIT_32(21) /**< Default 64 bits operand size */ +#define DISOPTYPE_FORCED_64_OP_SIZE RT_BIT_32(22) /**< Forced 64 bits operand size; regardless of prefix bytes */ +#define DISOPTYPE_REXB_EXTENDS_OPREG RT_BIT_32(23) /**< REX.B extends the register field in the opcode byte */ +#define DISOPTYPE_MOD_FIXED_11 RT_BIT_32(24) /**< modrm.mod is always 11b */ +#define DISOPTYPE_FORCED_32_OP_SIZE_X86 RT_BIT_32(25) /**< Forced 32 bits operand size; regardless of prefix bytes (only in 16 & 32 bits mode!) */ +#define DISOPTYPE_AVX RT_BIT_32(28) /**< AVX,AVX2,++ instruction. Not implemented yet! */ +#define DISOPTYPE_SSE RT_BIT_32(29) /**< SSE,SSE2,SSE3,SSE4,++ instruction. Not implemented yet! */ +#define DISOPTYPE_MMX RT_BIT_32(30) /**< MMX,MMXExt,3DNow,++ instruction. Not implemented yet! */ +#define DISOPTYPE_FPU RT_BIT_32(31) /**< FPU instruction. Not implemented yet! */ +#define DISOPTYPE_ALL UINT32_C(0xffffffff) +/** @} */ + +/** @name Parameter usage flags. + * @{ + */ +#define DISUSE_BASE RT_BIT_64(0) +#define DISUSE_INDEX RT_BIT_64(1) +#define DISUSE_SCALE RT_BIT_64(2) +#define DISUSE_REG_GEN8 RT_BIT_64(3) +#define DISUSE_REG_GEN16 RT_BIT_64(4) +#define DISUSE_REG_GEN32 RT_BIT_64(5) +#define DISUSE_REG_GEN64 RT_BIT_64(6) +#define DISUSE_REG_FP RT_BIT_64(7) +#define DISUSE_REG_MMX RT_BIT_64(8) +#define DISUSE_REG_XMM RT_BIT_64(9) +#define DISUSE_REG_YMM RT_BIT_64(10) +#define DISUSE_REG_CR RT_BIT_64(11) +#define DISUSE_REG_DBG RT_BIT_64(12) +#define DISUSE_REG_SEG RT_BIT_64(13) +#define DISUSE_REG_TEST RT_BIT_64(14) +#define DISUSE_DISPLACEMENT8 RT_BIT_64(15) +#define DISUSE_DISPLACEMENT16 RT_BIT_64(16) +#define DISUSE_DISPLACEMENT32 RT_BIT_64(17) +#define DISUSE_DISPLACEMENT64 RT_BIT_64(18) +#define DISUSE_RIPDISPLACEMENT32 RT_BIT_64(19) +#define DISUSE_IMMEDIATE8 RT_BIT_64(20) +#define DISUSE_IMMEDIATE8_REL RT_BIT_64(21) +#define DISUSE_IMMEDIATE16 RT_BIT_64(22) +#define DISUSE_IMMEDIATE16_REL RT_BIT_64(23) +#define DISUSE_IMMEDIATE32 RT_BIT_64(24) +#define DISUSE_IMMEDIATE32_REL RT_BIT_64(25) +#define DISUSE_IMMEDIATE64 RT_BIT_64(26) +#define DISUSE_IMMEDIATE64_REL RT_BIT_64(27) +#define DISUSE_IMMEDIATE_ADDR_0_32 RT_BIT_64(28) +#define DISUSE_IMMEDIATE_ADDR_16_32 RT_BIT_64(29) +#define DISUSE_IMMEDIATE_ADDR_0_16 RT_BIT_64(30) +#define DISUSE_IMMEDIATE_ADDR_16_16 RT_BIT_64(31) +/** DS:ESI */ +#define DISUSE_POINTER_DS_BASED RT_BIT_64(32) +/** ES:EDI */ +#define DISUSE_POINTER_ES_BASED RT_BIT_64(33) +#define DISUSE_IMMEDIATE16_SX8 RT_BIT_64(34) +#define DISUSE_IMMEDIATE32_SX8 RT_BIT_64(35) +#define DISUSE_IMMEDIATE64_SX8 RT_BIT_64(36) + +/** Mask of immediate use flags. */ +#define DISUSE_IMMEDIATE ( DISUSE_IMMEDIATE8 \ + | DISUSE_IMMEDIATE16 \ + | DISUSE_IMMEDIATE32 \ + | DISUSE_IMMEDIATE64 \ + | DISUSE_IMMEDIATE8_REL \ + | DISUSE_IMMEDIATE16_REL \ + | DISUSE_IMMEDIATE32_REL \ + | DISUSE_IMMEDIATE64_REL \ + | DISUSE_IMMEDIATE_ADDR_0_32 \ + | DISUSE_IMMEDIATE_ADDR_16_32 \ + | DISUSE_IMMEDIATE_ADDR_0_16 \ + | DISUSE_IMMEDIATE_ADDR_16_16 \ + | DISUSE_IMMEDIATE16_SX8 \ + | DISUSE_IMMEDIATE32_SX8 \ + | DISUSE_IMMEDIATE64_SX8) +/** Check if the use flags indicates an effective address. */ +#define DISUSE_IS_EFFECTIVE_ADDR(a_fUseFlags) (!!( (a_fUseFlags) \ + & ( DISUSE_BASE \ + | DISUSE_INDEX \ + | DISUSE_DISPLACEMENT32 \ + | DISUSE_DISPLACEMENT64 \ + | DISUSE_DISPLACEMENT16 \ + | DISUSE_DISPLACEMENT8 \ + | DISUSE_RIPDISPLACEMENT32) )) +/** @} */ + +/** @name 64-bit general register indexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxGenReg and DISOPPARAM::Index.idxGenReg. + * @note Safe to assume same values as the 16-bit and 32-bit general registers. + * @{ + */ +#define DISGREG_RAX UINT8_C(0) +#define DISGREG_RCX UINT8_C(1) +#define DISGREG_RDX UINT8_C(2) +#define DISGREG_RBX UINT8_C(3) +#define DISGREG_RSP UINT8_C(4) +#define DISGREG_RBP UINT8_C(5) +#define DISGREG_RSI UINT8_C(6) +#define DISGREG_RDI UINT8_C(7) +#define DISGREG_R8 UINT8_C(8) +#define DISGREG_R9 UINT8_C(9) +#define DISGREG_R10 UINT8_C(10) +#define DISGREG_R11 UINT8_C(11) +#define DISGREG_R12 UINT8_C(12) +#define DISGREG_R13 UINT8_C(13) +#define DISGREG_R14 UINT8_C(14) +#define DISGREG_R15 UINT8_C(15) +/** @} */ + +/** @name 32-bit general register indexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxGenReg and DISOPPARAM::Index.idxGenReg. + * @note Safe to assume same values as the 16-bit and 64-bit general registers. + * @{ + */ +#define DISGREG_EAX UINT8_C(0) +#define DISGREG_ECX UINT8_C(1) +#define DISGREG_EDX UINT8_C(2) +#define DISGREG_EBX UINT8_C(3) +#define DISGREG_ESP UINT8_C(4) +#define DISGREG_EBP UINT8_C(5) +#define DISGREG_ESI UINT8_C(6) +#define DISGREG_EDI UINT8_C(7) +#define DISGREG_R8D UINT8_C(8) +#define DISGREG_R9D UINT8_C(9) +#define DISGREG_R10D UINT8_C(10) +#define DISGREG_R11D UINT8_C(11) +#define DISGREG_R12D UINT8_C(12) +#define DISGREG_R13D UINT8_C(13) +#define DISGREG_R14D UINT8_C(14) +#define DISGREG_R15D UINT8_C(15) +/** @} */ + +/** @name 16-bit general register indexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxGenReg and DISOPPARAM::Index.idxGenReg. + * @note Safe to assume same values as the 32-bit and 64-bit general registers. + * @{ + */ +#define DISGREG_AX UINT8_C(0) +#define DISGREG_CX UINT8_C(1) +#define DISGREG_DX UINT8_C(2) +#define DISGREG_BX UINT8_C(3) +#define DISGREG_SP UINT8_C(4) +#define DISGREG_BP UINT8_C(5) +#define DISGREG_SI UINT8_C(6) +#define DISGREG_DI UINT8_C(7) +#define DISGREG_R8W UINT8_C(8) +#define DISGREG_R9W UINT8_C(9) +#define DISGREG_R10W UINT8_C(10) +#define DISGREG_R11W UINT8_C(11) +#define DISGREG_R12W UINT8_C(12) +#define DISGREG_R13W UINT8_C(13) +#define DISGREG_R14W UINT8_C(14) +#define DISGREG_R15W UINT8_C(15) +/** @} */ + +/** @name 8-bit general register indexes. + * This mostly (?) matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxGenReg and DISOPPARAM::Index.idxGenReg. + * @{ + */ +#define DISGREG_AL UINT8_C(0) +#define DISGREG_CL UINT8_C(1) +#define DISGREG_DL UINT8_C(2) +#define DISGREG_BL UINT8_C(3) +#define DISGREG_AH UINT8_C(4) +#define DISGREG_CH UINT8_C(5) +#define DISGREG_DH UINT8_C(6) +#define DISGREG_BH UINT8_C(7) +#define DISGREG_R8B UINT8_C(8) +#define DISGREG_R9B UINT8_C(9) +#define DISGREG_R10B UINT8_C(10) +#define DISGREG_R11B UINT8_C(11) +#define DISGREG_R12B UINT8_C(12) +#define DISGREG_R13B UINT8_C(13) +#define DISGREG_R14B UINT8_C(14) +#define DISGREG_R15B UINT8_C(15) +#define DISGREG_SPL UINT8_C(16) +#define DISGREG_BPL UINT8_C(17) +#define DISGREG_SIL UINT8_C(18) +#define DISGREG_DIL UINT8_C(19) +/** @} */ + +/** @name Segment registerindexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxSegReg. + * @{ + */ +typedef enum +{ + DISSELREG_ES = 0, + DISSELREG_CS = 1, + DISSELREG_SS = 2, + DISSELREG_DS = 3, + DISSELREG_FS = 4, + DISSELREG_GS = 5, + /** End of the valid register index values. */ + DISSELREG_END, + /** The usual 32-bit paranoia. */ + DIS_SEGREG_32BIT_HACK = 0x7fffffff +} DISSELREG; +/** @} */ + +/** @name FPU register indexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxFpuReg. + * @{ + */ +#define DISFPREG_ST0 UINT8_C(0) +#define DISFPREG_ST1 UINT8_C(1) +#define DISFPREG_ST2 UINT8_C(2) +#define DISFPREG_ST3 UINT8_C(3) +#define DISFPREG_ST4 UINT8_C(4) +#define DISFPREG_ST5 UINT8_C(5) +#define DISFPREG_ST6 UINT8_C(6) +#define DISFPREG_ST7 UINT8_C(7) +/** @} */ + +/** @name Control register indexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxCtrlReg. + * @{ + */ +#define DISCREG_CR0 UINT8_C(0) +#define DISCREG_CR1 UINT8_C(1) +#define DISCREG_CR2 UINT8_C(2) +#define DISCREG_CR3 UINT8_C(3) +#define DISCREG_CR4 UINT8_C(4) +#define DISCREG_CR8 UINT8_C(8) +/** @} */ + +/** @name Debug register indexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxDbgReg. + * @{ + */ +#define DISDREG_DR0 UINT8_C(0) +#define DISDREG_DR1 UINT8_C(1) +#define DISDREG_DR2 UINT8_C(2) +#define DISDREG_DR3 UINT8_C(3) +#define DISDREG_DR4 UINT8_C(4) +#define DISDREG_DR5 UINT8_C(5) +#define DISDREG_DR6 UINT8_C(6) +#define DISDREG_DR7 UINT8_C(7) +/** @} */ + +/** @name MMX register indexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxMmxReg. + * @{ + */ +#define DISMREG_MMX0 UINT8_C(0) +#define DISMREG_MMX1 UINT8_C(1) +#define DISMREG_MMX2 UINT8_C(2) +#define DISMREG_MMX3 UINT8_C(3) +#define DISMREG_MMX4 UINT8_C(4) +#define DISMREG_MMX5 UINT8_C(5) +#define DISMREG_MMX6 UINT8_C(6) +#define DISMREG_MMX7 UINT8_C(7) +/** @} */ + +/** @name SSE register indexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxXmmReg. + * @{ + */ +#define DISXREG_XMM0 UINT8_C(0) +#define DISXREG_XMM1 UINT8_C(1) +#define DISXREG_XMM2 UINT8_C(2) +#define DISXREG_XMM3 UINT8_C(3) +#define DISXREG_XMM4 UINT8_C(4) +#define DISXREG_XMM5 UINT8_C(5) +#define DISXREG_XMM6 UINT8_C(6) +#define DISXREG_XMM7 UINT8_C(7) +/** @} */ + + +/** + * Opcode parameter (operand) details. + */ +typedef struct DISOPPARAM +{ + /** A combination of DISUSE_XXX. */ + uint64_t fUse; + /** Immediate value or address, applicable if any of the flags included in + * DISUSE_IMMEDIATE are set in fUse. */ + uint64_t uValue; + /** Disposition. */ + union + { + /** 64-bit displacement, applicable if DISUSE_DISPLACEMENT64 is set in fUse. */ + int64_t i64; + uint64_t u64; + /** 32-bit displacement, applicable if DISUSE_DISPLACEMENT32 or + * DISUSE_RIPDISPLACEMENT32 is set in fUse. */ + int32_t i32; + uint32_t u32; + /** 16-bit displacement, applicable if DISUSE_DISPLACEMENT16 is set in fUse. */ + int32_t i16; + uint32_t u16; + /** 8-bit displacement, applicable if DISUSE_DISPLACEMENT8 is set in fUse. */ + int32_t i8; + uint32_t u8; + } uDisp; + /** The base register from ModR/M or SIB, applicable if DISUSE_BASE is + * set in fUse. */ + union + { + /** General register index (DISGREG_XXX), applicable if DISUSE_REG_GEN8, + * DISUSE_REG_GEN16, DISUSE_REG_GEN32 or DISUSE_REG_GEN64 is set in fUse. */ + uint8_t idxGenReg; + /** FPU stack register index (DISFPREG_XXX), applicable if DISUSE_REG_FP is + * set in fUse. 1:1 indexes. */ + uint8_t idxFpuReg; + /** MMX register index (DISMREG_XXX), applicable if DISUSE_REG_MMX is + * set in fUse. 1:1 indexes. */ + uint8_t idxMmxReg; + /** SSE register index (DISXREG_XXX), applicable if DISUSE_REG_XMM is + * set in fUse. 1:1 indexes. */ + uint8_t idxXmmReg; + /** SSE2 register index (DISYREG_XXX), applicable if DISUSE_REG_YMM is + * set in fUse. 1:1 indexes. */ + uint8_t idxYmmReg; + /** Segment register index (DISSELREG_XXX), applicable if DISUSE_REG_SEG is + * set in fUse. */ + uint8_t idxSegReg; + /** Test register, TR0-TR7, present on early IA32 CPUs, applicable if + * DISUSE_REG_TEST is set in fUse. No index defines for these. */ + uint8_t idxTestReg; + /** Control register index (DISCREG_XXX), applicable if DISUSE_REG_CR is + * set in fUse. 1:1 indexes. */ + uint8_t idxCtrlReg; + /** Debug register index (DISDREG_XXX), applicable if DISUSE_REG_DBG is + * set in fUse. 1:1 indexes. */ + uint8_t idxDbgReg; + } Base; + /** The SIB index register meaning, applicable if DISUSE_INDEX is + * set in fUse. */ + union + { + /** General register index (DISGREG_XXX), applicable if DISUSE_REG_GEN8, + * DISUSE_REG_GEN16, DISUSE_REG_GEN32 or DISUSE_REG_GEN64 is set in fUse. */ + uint8_t idxGenReg; + /** XMM register index (DISXREG_XXX), applicable if DISUSE_REG_XMM + * is set in fUse. */ + uint8_t idxXmmReg; + /** YMM register index (DISXREG_XXX), applicable if DISUSE_REG_YMM + * is set in fUse. */ + uint8_t idxYmmReg; + } Index; + /** 2, 4 or 8, if DISUSE_SCALE is set in fUse. */ + uint8_t uScale; + /** Parameter size. */ + uint8_t cb; + /** Copy of the corresponding DISOPCODE::fParam1 / DISOPCODE::fParam2 / + * DISOPCODE::fParam3. */ + uint32_t fParam; +} DISOPPARAM; +AssertCompileSize(DISOPPARAM, 32); +/** Pointer to opcode parameter. */ +typedef DISOPPARAM *PDISOPPARAM; +/** Pointer to opcode parameter. */ +typedef const DISOPPARAM *PCDISOPPARAM; + + +#if (defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)) && defined(DIS_CORE_ONLY) +# define DISOPCODE_BITFIELD(a_cBits) : a_cBits +#else +# define DISOPCODE_BITFIELD(a_cBits) +#endif + +/** + * Opcode descriptor. + */ +#if !defined(DIS_CORE_ONLY) || defined(DOXYGEN_RUNNING) +typedef struct DISOPCODE +{ +# define DISOPCODE_FORMAT 0 + /** Mnemonic and operand formatting. */ + const char *pszOpcode; + /** Parameter \#1 parser index. */ + uint8_t idxParse1; + /** Parameter \#2 parser index. */ + uint8_t idxParse2; + /** Parameter \#3 parser index. */ + uint8_t idxParse3; + /** Parameter \#4 parser index. */ + uint8_t idxParse4; + /** The opcode identifier. This DIS specific, @see grp_dis_opcodes and + * VBox/disopcode.h. */ + uint16_t uOpcode; + /** Parameter \#1 info, @see grp_dis_opparam. */ + uint16_t fParam1; + /** Parameter \#2 info, @see grp_dis_opparam. */ + uint16_t fParam2; + /** Parameter \#3 info, @see grp_dis_opparam. */ + uint16_t fParam3; + /** Parameter \#4 info, @see grp_dis_opparam. */ + uint16_t fParam4; + /** padding unused */ + uint16_t uPadding; + /** Operand type flags, DISOPTYPE_XXX. */ + uint32_t fOpType; +} DISOPCODE; +#else +# pragma pack(1) +typedef struct DISOPCODE +{ +#if 1 /*!defined(RT_ARCH_X86) && !defined(RT_ARCH_AMD64) - probably not worth it for ~4K, costs 2-3% speed. */ + /* 16 bytes (trick is to make sure the bitfields doesn't cross dwords): */ +# define DISOPCODE_FORMAT 16 + uint32_t fOpType; + uint16_t uOpcode; + uint8_t idxParse1; + uint8_t idxParse2; + uint32_t fParam1 : 12; /* 1st dword: 12+12+8 = 0x20 (32) */ + uint32_t fParam2 : 12; + uint32_t idxParse3 : 8; + uint32_t fParam3 : 12; /* 2nd dword: 12+12+8 = 0x20 (32) */ + uint32_t fParam4 : 12; + uint32_t idxParse4 : 8; +#else /* 15 bytes: */ +# define DISOPCODE_FORMAT 15 + uint64_t uOpcode : 10; /* 1st qword: 10+12+12+12+6+6+6 = 0x40 (64) */ + uint64_t idxParse1 : 6; + uint64_t idxParse2 : 6; + uint64_t idxParse3 : 6; + uint64_t fParam1 : 12; + uint64_t fParam2 : 12; + uint64_t fParam3 : 12; + uint32_t fOpType; + uint16_t fParam4; + uint8_t idxParse4; +#endif +} DISOPCODE; +# pragma pack() +AssertCompile(sizeof(DISOPCODE) == DISOPCODE_FORMAT); +#endif +AssertCompile(DISOPCODE_FORMAT != 15); /* Needs fixing before use as disopcode.h now has more than 1024 opcode values. */ +/** Pointer to const opcode. */ +typedef const struct DISOPCODE *PCDISOPCODE; + + +/** + * Callback for reading instruction bytes. + * + * @returns VBox status code, bytes in DISSTATE::abInstr and byte count in + * DISSTATE::cbCachedInstr. + * @param pDis Pointer to the disassembler state. The user + * argument can be found in DISSTATE::pvUser if needed. + * @param offInstr The offset relative to the start of the instruction. + * + * To get the source address, add this to + * DISSTATE::uInstrAddr. + * + * To calculate the destination buffer address, use it + * as an index into DISSTATE::abInstr. + * + * @param cbMinRead The minimum number of bytes to read. + * @param cbMaxRead The maximum number of bytes that may be read. + */ +typedef DECLCALLBACKTYPE(int, FNDISREADBYTES,(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)); +/** Pointer to a opcode byte reader. */ +typedef FNDISREADBYTES *PFNDISREADBYTES; + +/** Parser callback. + * @remark no DECLCALLBACK() here because it's considered to be internal and + * there is no point in enforcing CDECL. */ +typedef size_t FNDISPARSE(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam); +/** Pointer to a disassembler parser function. */ +typedef FNDISPARSE *PFNDISPARSE; +/** Pointer to a const disassembler parser function pointer. */ +typedef PFNDISPARSE const *PCPFNDISPARSE; + +/** + * The diassembler state and result. + */ +typedef struct DISSTATE +{ + /** The number of valid bytes in abInstr. */ + uint8_t cbCachedInstr; + /** SIB fields. */ + union + { + /** Bitfield view */ + struct + { + uint8_t Base; + uint8_t Index; + uint8_t Scale; + } Bits; + } SIB; + /** ModRM fields. */ + union + { + /** Bitfield view */ + struct + { + uint8_t Rm; + uint8_t Reg; + uint8_t Mod; + } Bits; + } ModRM; + /** The CPU mode (DISCPUMODE). */ + uint8_t uCpuMode; + /** The addressing mode (DISCPUMODE). */ + uint8_t uAddrMode; + /** The operand mode (DISCPUMODE). */ + uint8_t uOpMode; + /** Per instruction prefix settings. */ + uint8_t fPrefix; + /** REX prefix value (64 bits only). */ + uint8_t fRexPrefix; + /** Segment prefix value (DISSELREG). */ + uint8_t idxSegPrefix; + /** Last prefix byte (for SSE2 extension tables). */ + uint8_t bLastPrefix; + /** Last significant opcode byte of instruction. */ + uint8_t bOpCode; + /** The size of the prefix bytes. */ + uint8_t cbPrefix; + /** The instruction size. */ + uint8_t cbInstr; + /** VEX presence flag, destination register and size + * @todo r=bird: There is no VEX presence flage here, just ~vvvv and L. */ + uint8_t bVexDestReg; + /** VEX.W flag */ + uint8_t bVexWFlag; + /** Unused bytes. */ + uint8_t abUnused[1]; + /** Internal: instruction filter */ + uint32_t fFilter; + /** Internal: pointer to disassembly function table */ + PCPFNDISPARSE pfnDisasmFnTable; +#if ARCH_BITS == 32 + uint32_t uPtrPadding1; +#endif + /** Pointer to the current instruction. */ + PCDISOPCODE pCurInstr; +#if ARCH_BITS == 32 + uint32_t uPtrPadding2; +#endif + /** The instruction bytes. */ + uint8_t abInstr[16]; + /** SIB displacment. */ + int32_t i32SibDisp; + + /** Return code set by a worker function like the opcode bytes readers. */ + int32_t rc; + /** The address of the instruction. */ + RTUINTPTR uInstrAddr; + /** Optional read function */ + PFNDISREADBYTES pfnReadBytes; +#if ARCH_BITS == 32 + uint32_t uPadding3; +#endif + /** User data supplied as an argument to the APIs. */ + void *pvUser; +#if ARCH_BITS == 32 + uint32_t uPadding4; +#endif + /** Parameters. */ + DISOPPARAM Param1; + DISOPPARAM Param2; + DISOPPARAM Param3; + DISOPPARAM Param4; +} DISSTATE; +AssertCompileSize(DISSTATE, 0xd8); + +/** @deprecated Use DISSTATE and change Cpu and DisState to Dis. */ +typedef DISSTATE DISCPUSTATE; + + + +DISDECL(int) DISInstrToStr(void const *pvInstr, DISCPUMODE enmCpuMode, + PDISSTATE pDis, uint32_t *pcbInstr, char *pszOutput, size_t cbOutput); +DISDECL(int) DISInstrToStrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser, + PDISSTATE pDis, uint32_t *pcbInstr, char *pszOutput, size_t cbOutput); +DISDECL(int) DISInstrToStrEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, + PFNDISREADBYTES pfnReadBytes, void *pvUser, uint32_t uFilter, + PDISSTATE pDis, uint32_t *pcbInstr, char *pszOutput, size_t cbOutput); + +DISDECL(int) DISInstr(void const *pvInstr, DISCPUMODE enmCpuMode, PDISSTATE pDis, uint32_t *pcbInstr); +DISDECL(int) DISInstrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser, + PDISSTATE pDis, uint32_t *pcbInstr); +DISDECL(int) DISInstrEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t uFilter, + PFNDISREADBYTES pfnReadBytes, void *pvUser, + PDISSTATE pDis, uint32_t *pcbInstr); +DISDECL(int) DISInstrWithPrefetchedBytes(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter, + void const *pvPrefetched, size_t cbPretched, + PFNDISREADBYTES pfnReadBytes, void *pvUser, + PDISSTATE pDis, uint32_t *pcbInstr); + +DISDECL(uint8_t) DISGetParamSize(PCDISSTATE pDis, PCDISOPPARAM pParam); +#if 0 /* unused */ +DISDECL(DISSELREG) DISDetectSegReg(PCDISSTATE pDis, PCDISOPPARAM pParam); +DISDECL(uint8_t) DISQuerySegPrefixByte(PCDISSTATE pDis); +#endif + +#if 0 /* Needs refactoring if we want to use this again, CPUMCTXCORE is history. */ +/** @name Flags returned by DISQueryParamVal (DISQPVPARAMVAL::flags). + * @{ + */ +#define DISQPV_FLAG_8 UINT8_C(0x01) +#define DISQPV_FLAG_16 UINT8_C(0x02) +#define DISQPV_FLAG_32 UINT8_C(0x04) +#define DISQPV_FLAG_64 UINT8_C(0x08) +#define DISQPV_FLAG_FARPTR16 UINT8_C(0x10) +#define DISQPV_FLAG_FARPTR32 UINT8_C(0x20) +/** @} */ + +/** @name Types returned by DISQueryParamVal (DISQPVPARAMVAL::flags). + * @{ */ +#define DISQPV_TYPE_REGISTER UINT8_C(1) +#define DISQPV_TYPE_ADDRESS UINT8_C(2) +#define DISQPV_TYPE_IMMEDIATE UINT8_C(3) +/** @} */ + +typedef struct +{ + union + { + uint8_t val8; + uint16_t val16; + uint32_t val32; + uint64_t val64; + + int8_t i8; + int16_t i16; + int32_t i32; + int64_t i64; + + struct + { + uint16_t sel; + uint32_t offset; + } farptr; + } val; + + uint8_t type; + uint8_t size; + uint8_t flags; +} DISQPVPARAMVAL; +/** Pointer to opcode parameter value. */ +typedef DISQPVPARAMVAL *PDISQPVPARAMVAL; + +/** Indicates which parameter DISQueryParamVal should operate on. */ +typedef enum DISQPVWHICH +{ + DISQPVWHICH_DST = 1, + DISQPVWHICH_SRC, + DISQPVWHAT_32_BIT_HACK = 0x7fffffff +} DISQPVWHICH; +DISDECL(int) DISQueryParamVal(PCPUMCTXCORE pCtx, PCDISSTATE pDis, PCDISOPPARAM pParam, PDISQPVPARAMVAL pParamVal, DISQPVWHICH parmtype); +DISDECL(int) DISQueryParamRegPtr(PCPUMCTXCORE pCtx, PCDISSTATE pDis, PCDISOPPARAM pParam, void **ppReg, size_t *pcbSize); + +DISDECL(int) DISFetchReg8(PCCPUMCTXCORE pCtx, unsigned reg8, uint8_t *pVal); +DISDECL(int) DISFetchReg16(PCCPUMCTXCORE pCtx, unsigned reg16, uint16_t *pVal); +DISDECL(int) DISFetchReg32(PCCPUMCTXCORE pCtx, unsigned reg32, uint32_t *pVal); +DISDECL(int) DISFetchReg64(PCCPUMCTXCORE pCtx, unsigned reg64, uint64_t *pVal); +DISDECL(int) DISFetchRegSeg(PCCPUMCTXCORE pCtx, DISSELREG sel, RTSEL *pVal); +DISDECL(int) DISWriteReg8(PCPUMCTXCORE pRegFrame, unsigned reg8, uint8_t val8); +DISDECL(int) DISWriteReg16(PCPUMCTXCORE pRegFrame, unsigned reg32, uint16_t val16); +DISDECL(int) DISWriteReg32(PCPUMCTXCORE pRegFrame, unsigned reg32, uint32_t val32); +DISDECL(int) DISWriteReg64(PCPUMCTXCORE pRegFrame, unsigned reg64, uint64_t val64); +DISDECL(int) DISWriteRegSeg(PCPUMCTXCORE pCtx, DISSELREG sel, RTSEL val); +DISDECL(int) DISPtrReg8(PCPUMCTXCORE pCtx, unsigned reg8, uint8_t **ppReg); +DISDECL(int) DISPtrReg16(PCPUMCTXCORE pCtx, unsigned reg16, uint16_t **ppReg); +DISDECL(int) DISPtrReg32(PCPUMCTXCORE pCtx, unsigned reg32, uint32_t **ppReg); +DISDECL(int) DISPtrReg64(PCPUMCTXCORE pCtx, unsigned reg64, uint64_t **ppReg); +#endif /* obsolete */ + + +/** + * Try resolve an address into a symbol name. + * + * For use with DISFormatYasmEx(), DISFormatMasmEx() and DISFormatGasEx(). + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success, pszBuf contains the full symbol name. + * @retval VINF_BUFFER_OVERFLOW if pszBuf is too small the symbol name. The + * content of pszBuf is truncated and zero terminated. + * @retval VERR_SYMBOL_NOT_FOUND if no matching symbol was found for the address. + * + * @param pDis Pointer to the disassembler CPU state. + * @param u32Sel The selector value. Use DIS_FMT_SEL_IS_REG, DIS_FMT_SEL_GET_VALUE, + * DIS_FMT_SEL_GET_REG to access this. + * @param uAddress The segment address. + * @param pszBuf Where to store the symbol name + * @param cchBuf The size of the buffer. + * @param poff If not a perfect match, then this is where the offset from the return + * symbol to the specified address is returned. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(int, FNDISGETSYMBOL,(PCDISSTATE pDis, uint32_t u32Sel, RTUINTPTR uAddress, char *pszBuf, size_t cchBuf, + RTINTPTR *poff, void *pvUser)); +/** Pointer to a FNDISGETSYMBOL(). */ +typedef FNDISGETSYMBOL *PFNDISGETSYMBOL; + +/** + * Checks if the FNDISGETSYMBOL argument u32Sel is a register or not. + */ +#define DIS_FMT_SEL_IS_REG(u32Sel) ( !!((u32Sel) & RT_BIT(31)) ) + +/** + * Extracts the selector value from the FNDISGETSYMBOL argument u32Sel. + * @returns Selector value. + */ +#define DIS_FMT_SEL_GET_VALUE(u32Sel) ( (RTSEL)(u32Sel) ) + +/** + * Extracts the register number from the FNDISGETSYMBOL argument u32Sel. + * @returns USE_REG_CS, USE_REG_SS, USE_REG_DS, USE_REG_ES, USE_REG_FS or USE_REG_FS. + */ +#define DIS_FMT_SEL_GET_REG(u32Sel) ( ((u32Sel) >> 16) & 0xf ) + +/** @internal */ +#define DIS_FMT_SEL_FROM_REG(uReg) ( ((uReg) << 16) | RT_BIT(31) | 0xffff ) +/** @internal */ +#define DIS_FMT_SEL_FROM_VALUE(Sel) ( (Sel) & 0xffff ) + + +/** @name Flags for use with DISFormatYasmEx(), DISFormatMasmEx() and DISFormatGasEx(). + * @{ + */ +/** Put the address to the right. */ +#define DIS_FMT_FLAGS_ADDR_RIGHT RT_BIT_32(0) +/** Put the address to the left. */ +#define DIS_FMT_FLAGS_ADDR_LEFT RT_BIT_32(1) +/** Put the address in comments. + * For some assemblers this implies placing it to the right. */ +#define DIS_FMT_FLAGS_ADDR_COMMENT RT_BIT_32(2) +/** Put the instruction bytes to the right of the disassembly. */ +#define DIS_FMT_FLAGS_BYTES_RIGHT RT_BIT_32(3) +/** Put the instruction bytes to the left of the disassembly. */ +#define DIS_FMT_FLAGS_BYTES_LEFT RT_BIT_32(4) +/** Put the instruction bytes in comments. + * For some assemblers this implies placing the bytes to the right. */ +#define DIS_FMT_FLAGS_BYTES_COMMENT RT_BIT_32(5) +/** Put the bytes in square brackets. */ +#define DIS_FMT_FLAGS_BYTES_BRACKETS RT_BIT_32(6) +/** Put spaces between the bytes. */ +#define DIS_FMT_FLAGS_BYTES_SPACED RT_BIT_32(7) +/** Display the relative +/- offset of branch instructions that uses relative addresses, + * and put the target address in parenthesis. */ +#define DIS_FMT_FLAGS_RELATIVE_BRANCH RT_BIT_32(8) +/** Strict assembly. The assembly should, when ever possible, make the + * assembler reproduce the exact same binary. (Refers to the yasm + * strict keyword.) */ +#define DIS_FMT_FLAGS_STRICT RT_BIT_32(9) +/** Checks if the given flags are a valid combination. */ +#define DIS_FMT_FLAGS_IS_VALID(fFlags) \ + ( !((fFlags) & ~UINT32_C(0x000003ff)) \ + && ((fFlags) & (DIS_FMT_FLAGS_ADDR_RIGHT | DIS_FMT_FLAGS_ADDR_LEFT)) != (DIS_FMT_FLAGS_ADDR_RIGHT | DIS_FMT_FLAGS_ADDR_LEFT) \ + && ( !((fFlags) & DIS_FMT_FLAGS_ADDR_COMMENT) \ + || (fFlags & (DIS_FMT_FLAGS_ADDR_RIGHT | DIS_FMT_FLAGS_ADDR_LEFT)) ) \ + && ((fFlags) & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_BYTES_LEFT)) != (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_BYTES_LEFT) \ + && ( !((fFlags) & (DIS_FMT_FLAGS_BYTES_COMMENT | DIS_FMT_FLAGS_BYTES_BRACKETS)) \ + || (fFlags & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_BYTES_LEFT)) ) \ + ) +/** @} */ + +DISDECL(size_t) DISFormatYasm( PCDISSTATE pDis, char *pszBuf, size_t cchBuf); +DISDECL(size_t) DISFormatYasmEx(PCDISSTATE pDis, char *pszBuf, size_t cchBuf, uint32_t fFlags, PFNDISGETSYMBOL pfnGetSymbol, void *pvUser); +DISDECL(size_t) DISFormatMasm( PCDISSTATE pDis, char *pszBuf, size_t cchBuf); +DISDECL(size_t) DISFormatMasmEx(PCDISSTATE pDis, char *pszBuf, size_t cchBuf, uint32_t fFlags, PFNDISGETSYMBOL pfnGetSymbol, void *pvUser); +DISDECL(size_t) DISFormatGas( PCDISSTATE pDis, char *pszBuf, size_t cchBuf); +DISDECL(size_t) DISFormatGasEx( PCDISSTATE pDis, char *pszBuf, size_t cchBuf, uint32_t fFlags, PFNDISGETSYMBOL pfnGetSymbol, void *pvUser); + +/** @todo DISAnnotate(PCDISSTATE pDis, char *pszBuf, size_t cchBuf, register + * reader, memory reader); */ + +DISDECL(bool) DISFormatYasmIsOddEncoding(PDISSTATE pDis); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_dis_h */ + diff --git a/include/VBox/disopcode.h b/include/VBox/disopcode.h new file mode 100644 index 00000000..5732f5c5 --- /dev/null +++ b/include/VBox/disopcode.h @@ -0,0 +1,1469 @@ +/** @file + * Disassembler - Opcodes + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_disopcode_h +#define VBOX_INCLUDED_disopcode_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assert.h> + +#define MODRM_MOD(a) (a>>6) +#define MODRM_REG(a) ((a>>3)&0x7) +#define MODRM_RM(a) (a&0x7) +#define MAKE_MODRM(mod, reg, rm) (((mod&3) << 6) | ((reg&7) << 3) | (rm&7)) + +#define SIB_SCALE(a) (a>>6) +#define SIB_INDEX(a) ((a>>3)&0x7) +#define SIB_BASE(a) (a&0x7) + + +/** @defgroup grp_dis_opcodes Opcodes (DISOPCODE::uOpCode) + * @ingroup grp_dis + * @{ + */ +enum OPCODES +{ +/** @name Full Intel X86 opcode list + * @{ */ + OP_INVALID = 0, + OP_OPSIZE, + OP_ADDRSIZE, + OP_SEG, + OP_REPNE, + OP_REPE, + OP_REX, + OP_LOCK, +#ifndef IN_SLICKEDIT + OP_LAST_PREFIX = OP_LOCK, /**< Last prefix for disassembler. */ +#else + OP_LAST_PREFIX = 7, /**< Last prefix for disassembler. */ +#endif + OP_AND, + OP_OR, + OP_DAA, + OP_SUB, + OP_DAS, + OP_XOR, + OP_AAA, + OP_CMP, + OP_IMM_GRP1, + OP_AAS, + OP_INC, + OP_DEC, + OP_PUSHA, + OP_POPA, + OP_BOUND, + OP_ARPL, + OP_PUSH, + OP_POP, + OP_IMUL, + OP_INSB, + OP_INSWD, + OP_OUTSB, + OP_OUTSWD, + OP_JO, + OP_JNO, + OP_JC, + OP_JNC, + OP_JE, + OP_JNE, + OP_JBE, + OP_JNBE, + OP_JS, + OP_JNS, + OP_JP, + OP_JNP, + OP_JL, + OP_JNL, + OP_JLE, + OP_JNLE, + OP_ADD, + OP_TEST, + OP_XCHG, + OP_MOV, + OP_LEA, + OP_NOP, + OP_CBW, + OP_CWD, + OP_CALL, + OP_WAIT, + OP_PUSHF, + OP_POPF, + OP_SAHF, + OP_LAHF, + OP_MOVSB, + OP_MOVSWD, + OP_CMPSB, + OP_CMPWD, + OP_STOSB, + OP_STOSWD, + OP_LODSB, + OP_LODSWD, + OP_SCASB, + OP_SCASWD, + OP_SHIFT_GRP2, + OP_RETN, + OP_LES, + OP_LDS, + OP_ENTER, + OP_LEAVE, + OP_RETF, + OP_INT1, + OP_INT3, + OP_INT, + OP_INTO, + OP_IRET, + OP_AAM, + OP_AAD, + OP_SALC, + OP_XLAT, + OP_ESCF0, + OP_ESCF1, + OP_ESCF2, + OP_ESCF3, + OP_ESCF4, + OP_ESCF5, + OP_ESCF6, + OP_ESCF7, + OP_LOOPNE, + OP_LOOPE, + OP_LOOP, + OP_JECXZ, + OP_IN, + OP_OUT, + OP_JMP, + OP_2B_ESC, + OP_ADC, + OP_SBB, + OP_HLT, + OP_CMC, + OP_UNARY_GRP3, + OP_CLC, + OP_STC, + OP_CLI, + OP_STI, + OP_CLD, + OP_STD, + OP_INC_GRP4, + OP_IND_GRP5, + OP_GRP6, + OP_GRP7, + OP_LAR, + OP_LSL, + OP_SYSCALL, + OP_CLTS, + OP_SYSRET, + OP_INVD, + OP_WBINVD, + OP_ILLUD2, + OP_FEMMS, + OP_3DNOW, + OP_MOVUPS, + OP_MOVLPS, + OP_MOVHLPS = OP_MOVLPS, /**< @todo OP_MOVHLPS */ + OP_UNPCKLPS, + OP_MOVHPS, + OP_MOVLHPS = OP_MOVHPS, /**< @todo OP_MOVLHPS */ + OP_UNPCKHPS, + OP_PREFETCH_GRP16, + OP_MOV_CR, + OP_MOVAPS, + OP_CVTPI2PS, + OP_MOVNTPS, + OP_CVTTPS2PI, + OP_CVTPS2PI, + OP_UCOMISS, + OP_COMISS, + OP_WRMSR, + OP_RDTSC, + OP_RDTSCP, + OP_RDMSR, + OP_RDPMC, + OP_SYSENTER, + OP_SYSEXIT, + OP_GETSEC, + OP_PAUSE, + OP_CMOVO, + OP_CMOVNO, + OP_CMOVC, + OP_CMOVNC, + OP_CMOVZ, + OP_CMOVNZ, + OP_CMOVBE, + OP_CMOVNBE, + OP_CMOVS, + OP_CMOVNS, + OP_CMOVP, + OP_CMOVNP, + OP_CMOVL, + OP_CMOVNL, + OP_CMOVLE, + OP_CMOVNLE, + OP_MOVMSKPS, + OP_SQRTPS, + OP_RSQRTPS, + OP_RCPPS, + OP_ANDPS, + OP_ANDNPS, + OP_ORPS, + OP_XORPS, + OP_ADDPS, + OP_MULPS, + OP_CVTPS2PD, + OP_CVTDQ2PS, + OP_SUBPS, + OP_MINPS, + OP_DIVPS, + OP_MAXPS, + OP_PUNPCKLBW, + OP_PUNPCKLWD, + OP_PUNPCKLDQ, + OP_PACKSSWB, + OP_PCMPGTB, + OP_PCMPGTW, + OP_PCMPGTD, + OP_PCMPGTQ, + OP_PACKUSWB, + OP_PUNPCKHBW, + OP_PUNPCKHWD, + OP_PUNPCKHDQ, + OP_PACKSSDW, + OP_MOVD, + OP_MOVQ, + OP_PSHUFW, + OP_3B_ESC4, + OP_3B_ESC5, + OP_PCMPEQB, + OP_PCMPEQW, + OP_PCMPEQD, + OP_PCMPEQQ, + OP_SETO, + OP_SETNO, + OP_SETC, + OP_SETNC, + OP_SETE, + OP_SETNE, + OP_SETBE, + OP_SETNBE, + OP_SETS, + OP_SETNS, + OP_SETP, + OP_SETNP, + OP_SETL, + OP_SETNL, + OP_SETLE, + OP_SETNLE, + OP_CPUID, + OP_BT, + OP_SHLD, + OP_RSM, + OP_BTS, + OP_SHRD, + OP_GRP15, + OP_CMPXCHG, + OP_LSS, + OP_BTR, + OP_LFS, + OP_LGS, + OP_MOVZX, + OP_GRP10_INV, + OP_GRP8, + OP_BTC, + OP_BSF, + OP_BSR, + OP_MOVSX, + OP_XADD, + OP_CMPPS, + OP_MOVNTI, + OP_PINSRW, + OP_PEXTRW, + OP_SHUFPS, + OP_GRP9, + OP_BSWAP, + OP_ADDSUBPS, + OP_ADDSUBPD, + OP_PSRLW, + OP_PSRLD, + OP_PSRLQ, + OP_PADDQ, + OP_PMULLW, + OP_PMOVMSKB, + OP_PSUBUSB, + OP_PSUBUSW, + OP_PMINUB, + OP_PAND, + OP_PADDUSB, + OP_PADDUSW, + OP_PMAXUB, + OP_PANDN, + OP_PAVGB, + OP_PSRAW, + OP_PSRAD, + OP_PAVGW, + OP_PMULHUW, + OP_PMULHW, + OP_MOVNTQ, + OP_PSUBSB, + OP_PSUBSW, + OP_PMINSW, + OP_POR, + OP_PADDSB, + OP_PADDSW, + OP_PMAXSW, + OP_PXOR, + OP_LDDQU, + OP_PSLLW, + OP_PSLLD, + OP_PSSQ, + OP_PMULUDQ, + OP_PMADDWD, + OP_PSADBW, + OP_MASKMOVQ, + OP_PSUBB, + OP_PSUBW, + OP_PSUBD, + OP_PSUBQ, + OP_PADDB, + OP_PADDW, + OP_PADDD, + OP_MOVUPD, + OP_MOVLPD, + OP_UNPCKLPD, + OP_UNPCKHPD, + OP_MOVHPD, + OP_MOVAPD, + OP_CVTPI2PD, + OP_MOVNTPD, + OP_CVTTPD2PI, + OP_CVTPD2PI, + OP_UCOMISD, + OP_COMISD, + OP_MOVMSKPD, + OP_SQRTPD, + OP_ANDPD, + OP_ANDNPD, + OP_ORPD, + OP_XORPD, + OP_ADDPD, + OP_MULPD, + OP_CVTPD2PS, + OP_CVTPS2DQ, + OP_SUBPD, + OP_MINPD, + OP_DIVPD, + OP_MAXPD, + OP_GRP12, + OP_GRP13, + OP_GRP14, + OP_GRP17, + OP_EMMS, + OP_MMX_UD78, + OP_MMX_UD79, + OP_MMX_UD7A, + OP_MMX_UD7B, + OP_MMX_UD7C, + OP_MMX_UD7D, + OP_PUNPCKLQDQ, + OP_PUNPCKHQDQ, + OP_MOVDQA, + OP_PSHUFD, + OP_CMPPD, + OP_SHUFPD, + OP_CVTTPD2DQ, + OP_MOVNTDQ, + OP_MOVNTDQA, + OP_PACKUSDW, + OP_PSHUFB, + OP_PHADDW, + OP_PHADDD, + OP_PHADDSW, + OP_HADDPS, + OP_HADDPD, + OP_PMADDUBSW, + OP_PHSUBW, + OP_PHSUBD, + OP_PHSUBSW, + OP_HSUBPS, + OP_HSUBPD, + OP_PSIGNB, + OP_PSIGNW, + OP_PSIGND, + OP_PMULHRSW, + OP_PERMILPS, + OP_PERMILPD, + OP_TESTPS, + OP_TESTPD, + OP_PBLENDVB, + OP_CVTPH2PS, + OP_BLENDVPS, + OP_BLENDVPD, + OP_PERMPS, + OP_PERMD, + OP_PTEST, + OP_BROADCASTSS, + OP_BROADCASTSD, + OP_BROADCASTF128, + OP_PABSB, + OP_PABSW, + OP_PABSD, + OP_PMOVSXBW, + OP_PMOVSXBD, + OP_PMOVSXBQ, + OP_PMOVSXWD, + OP_PMOVSXWQ, + OP_PMOVSXDQ, + OP_PMOVZXBW, + OP_PMOVZXBD, + OP_PMOVZXBQ, + OP_PMOVZXWD, + OP_PMOVZXWQ, + OP_PMOVZXDQ, + OP_PMULDQ, + OP_PMINSB, + OP_PMINSD, + OP_PMINUW, + OP_PMINUD, + OP_PMAXSB, + OP_PMAXSD, + OP_PMAXUW, + OP_PMAXUD, + OP_PMULLD, + OP_PHMINPOSUW, + OP_PSRLVD, + OP_PSRAVD, + OP_PSLLVD, + OP_PBROADCASTD, + OP_PBROADCASTQ, + OP_PBROADCASTI128, + OP_PBROADCASTB, + OP_PBROADCASTW, + OP_PMASKMOVD, + OP_GATHER, + OP_FMADDSUB132PS, + OP_FMSUBADD132PS, + OP_FMADD132PS, + OP_FMADD132SS, + OP_FMSUB132PS, + OP_FMSUB132SS, + OP_FNMADD132PS, + OP_FNMADD132SS, + OP_FNMSUB132PS, + OP_FNMSUB132SS, + OP_FMADDSUB213PS, + OP_FMSUBADD213PS, + OP_FMADD213PS, + OP_FMADD213SS, + OP_FMSUB213PS, + OP_FMSUB213SS, + OP_FNMADD213PS, + OP_FNMADD213SS, + OP_FNMSUB213PS, + OP_FNMSUB213SS, + OP_FMADDSUB231PS, + OP_FMSUBADD231PS, + OP_FMADD231PS, + OP_FMADD231SS, + OP_FMSUB231PS, + OP_FMSUB231SS, + OP_FNMADD231PS, + OP_FNMADD231SS, + OP_FNMSUB231PS, + OP_FNMSUB231SS, + OP_AESIMC, + OP_AESENC, + OP_AESENCLAST, + OP_AESDEC, + OP_AESDECLAST, + OP_MOVBEGM, + OP_MOVBEMG, + OP_CRC32, + OP_POPCNT, + OP_TZCNT, + OP_LZCNT, + OP_ADCX, + OP_ADOX, + OP_ANDN, + OP_BZHI, + OP_BEXTR, + OP_BLSR, + OP_BLSMSK, + OP_BLSI, + OP_PEXT, + OP_PDEP, + OP_SHLX, + OP_SHRX, + OP_SARX, + OP_MULX, + OP_MASKMOVDQU, + OP_MASKMOVPS, + OP_MASKMOVPD, + OP_MOVSD, + OP_CVTSI2SD, + OP_CVTTSD2SI, + OP_CVTSD2SI, + OP_SQRTSD, + OP_ADDSD, + OP_MULSD, + OP_CVTSD2SS, + OP_SUBSD, + OP_MINSD, + OP_DIVSD, + OP_MAXSD, + OP_PSHUFLW, + OP_CMPSD, + OP_MOVDQ2Q, + OP_CVTPD2DQ, + OP_MOVSS, + OP_MOVSLDUP, + OP_MOVDDUP, + OP_MOVSHDUP, + OP_CVTSI2SS, + OP_CVTTSS2SI, + OP_CVTSS2SI, + OP_CVTSS2SD, + OP_SQRTSS, + OP_RSQRTSS, + OP_RCPSS, + OP_ADDSS, + OP_MULSS, + OP_CVTTPS2DQ, + OP_SUBSS, + OP_MINSS, + OP_DIVSS, + OP_MAXSS, + OP_MOVDQU, + OP_PSHUFHW, + OP_CMPSS, + OP_MOVQ2DQ, + OP_CVTDQ2PD, + OP_PERMQ, + OP_PERMPD, + OP_PBLENDD, + OP_PERM2F128, + OP_ROUNDPS, + OP_ROUNDPD, + OP_ROUNDSS, + OP_ROUNDSD, + OP_BLENDPS, + OP_BLENDPD, + OP_PBLENDW, + OP_PALIGNR, + OP_PEXTRB, + OP_PEXTRD, + OP_PEXTRQ, + OP_EXTRACTPS, + OP_INSERTF128, + OP_EXTRACTF128, + OP_CVTPS2PH, + OP_PINSRB, + OP_PINSRD, + OP_PINSRQ, + OP_INSERTPS, + OP_INSERTI128, + OP_EXTRACTI128, + OP_DPPS, + OP_DPPD, + OP_MPSADBW, + OP_PCLMULQDQ, + OP_PERM2I128, + OP_PCMPESTRM, + OP_PCMPESTRI, + OP_PCMPISTRM, + OP_PCMPISTRI, + OP_AESKEYGEN, + OP_RORX, + OP_RDRAND, + OP_RDSEED, + OP_MOVBE, + OP_VEX3B, + OP_VEX2B, +/** @} */ + +/** @name Floating point ops + * @{ */ + OP_FADD, + OP_FMUL, + OP_FCOM, + OP_FCOMP, + OP_FSUB, + OP_FSUBR, + OP_FDIV, + OP_FDIVR, + OP_FLD, + OP_FST, + OP_FSTP, + OP_FLDENV, + OP_FSTENV, + OP_FSTCW, + OP_FXCH, + OP_FNOP, + OP_FCHS, + OP_FABS, + OP_FLD1, + OP_FLDL2T, + OP_FLDL2E, + OP_FLDPI, + OP_FLDLG2, + OP_FLDLN2, + OP_FLDZ, + OP_F2XM1, + OP_FYL2X, + OP_FPTAN, + OP_FPATAN, + OP_FXTRACT, + OP_FREM1, + OP_FDECSTP, + OP_FINCSTP, + OP_FPREM, + OP_FYL2XP1, + OP_FSQRT, + OP_FSINCOS, + OP_FRNDINT, + OP_FSCALE, + OP_FSIN, + OP_FCOS, + OP_FIADD, + OP_FIMUL, + OP_FISUB, + OP_FISUBR, + OP_FIDIV, + OP_FIDIVR, + OP_FCMOVB, + OP_FCMOVE, + OP_FCMOVBE, + OP_FCMOVU, + OP_FUCOMPP, + OP_FILD, + OP_FIST, + OP_FISTP, + OP_FCMOVNB, + OP_FCMOVNE, + OP_FCMOVNBE, + OP_FCMOVNU, + OP_FCLEX, + OP_FINIT, + OP_FUCOMI, + OP_FCOMI, + OP_FRSTOR, + OP_FSAVE, + OP_FNSTSW, + OP_FFREE, + OP_FUCOM, + OP_FUCOMP, + OP_FICOM, + OP_FICOMP, + OP_FADDP, + OP_FMULP, + OP_FCOMPP, + OP_FSUBRP, + OP_FSUBP, + OP_FDIVRP, + OP_FDIVP, + OP_FBLD, + OP_FBSTP, + OP_FCOMIP, + OP_FUCOMIP, +/** @} */ + +/** @name 3DNow! + * @{ */ + OP_PI2FW, + OP_PI2FD, + OP_PF2IW, + OP_PF2ID, + OP_PFPNACC, + OP_PFCMPGE, + OP_PFMIN, + OP_PFRCP, + OP_PFRSQRT, + OP_PFSUB, + OP_PFADD, + OP_PFCMPGT, + OP_PFMAX, + OP_PFRCPIT1, + OP_PFRSQRTIT1, + OP_PFSUBR, + OP_PFACC, + OP_PFCMPEQ, + OP_PFMUL, + OP_PFRCPIT2, + OP_PFMULHRW, + OP_PFSWAPD, + OP_PAVGUSB, + OP_PFNACC, +/** @} */ + OP_ROL, + OP_ROR, + OP_RCL, + OP_RCR, + OP_SHL, + OP_SHR, + OP_SAR, + OP_NOT, + OP_NEG, + OP_MUL, + OP_DIV, + OP_IDIV, + OP_SLDT, + OP_STR, + OP_LLDT, + OP_LTR, + OP_VERR, + OP_VERW, + OP_SGDT, + OP_LGDT, + OP_SIDT, + OP_LIDT, + OP_SMSW, + OP_LMSW, + OP_INVLPG, + OP_CMPXCHG8B, + OP_PSLLQ, + OP_PSRLDQ, + OP_PSLLDQ, + OP_FXSAVE, + OP_FXRSTOR, + OP_LDMXCSR, + OP_STMXCSR, + OP_XSAVE, + OP_XSAVEOPT, + OP_XRSTOR, + OP_XGETBV, + OP_XSETBV, + OP_RDFSBASE, + OP_RDGSBASE, + OP_WRFSBASE, + OP_WRGSBASE, + OP_LFENCE, + OP_MFENCE, + OP_SFENCE, + OP_PREFETCH, + OP_MONITOR, + OP_MWAIT, + OP_CLFLUSH, + OP_CLFLUSHOPT, + OP_MOV_DR, + OP_MOV_TR, + OP_SWAPGS, + OP_UD1, + OP_UD2, +/** @name VT-x instructions + * @{ */ + OP_VMREAD, + OP_VMWRITE, + OP_VMCALL, + OP_VMXON, + OP_VMXOFF, + OP_VMCLEAR, + OP_VMLAUNCH, + OP_VMRESUME, + OP_VMPTRLD, + OP_VMPTRST, + OP_INVEPT, + OP_INVVPID, + OP_INVPCID, + OP_VMFUNC, +/** @} */ +/** @name AMD-V instructions + * @{ */ + OP_VMMCALL, + OP_VMRUN, + OP_VMLOAD, + OP_VMSAVE, + OP_CLGI, + OP_STGI, + OP_INVLPGA, + OP_SKINIT, +/** @} */ +/** @name 64 bits instruction + * @{ */ + OP_MOVSXD, +/** @} */ +/** @name AVX instructions + * @{ */ + /* Manual */ + OP_VSTMXCSR, + OP_VLDMXCSR, + OP_VPACKUSDW, + + /* Generated from tables: */ + OP_VADDPD, + OP_VADDPS, + OP_VADDSD, + OP_VADDSS, + OP_VADDSUBPD, + OP_VADDSUBPS, + OP_VAESDEC, + OP_VAESDECLAST, + OP_VAESENC, + OP_VAESENCLAST, + OP_VAESIMC, + OP_VAESKEYGEN, + OP_VANDNPD, + OP_VANDNPS, + OP_VANDPD, + OP_VANDPS, + OP_VBLENDPD, + OP_VBLENDPS, + OP_VBLENDVPD, + OP_VBLENDVPS, + OP_VBROADCASTF128, + OP_VBROADCASTSD, + OP_VBROADCASTSS, + OP_VCMPSD, + OP_VCMPSS, + OP_VCOMISD, + OP_VCOMISS, + OP_VCVTDQ2PD, + OP_VCVTDQ2PS, + OP_VCVTPD2DQ, + OP_VCVTPD2PS, + OP_VCVTPH2PS, + OP_VCVTPS2DQ, + OP_VCVTPS2PD, + OP_VCVTPS2PH, + OP_VCVTSD2SS, + OP_VCVTSI2SS, + OP_VCVTSS2SD, + OP_VCVTSS2SI, + OP_VCVTTPD2DQ, + OP_VCVTTPS2DQ, + OP_VCVTTSS2SI, + OP_VDIVPD, + OP_VDIVPS, + OP_VDIVSD, + OP_VDIVSS, + OP_VDPPD, + OP_VDPPS, + OP_VEXTRACTF128, + OP_VEXTRACTI128, + OP_VEXTRACTPS, + OP_VFMADD132PS, + OP_VFMADD132SS, + OP_VFMADD213PS, + OP_VFMADD213SS, + OP_VFMADD231PS, + OP_VFMADD231SS, + OP_VFMADDSUB132PS, + OP_VFMADDSUB213PS, + OP_VFMADDSUB231PS, + OP_VFMSUB132PS, + OP_VFMSUB132SS, + OP_VFMSUB213PS, + OP_VFMSUB213SS, + OP_VFMSUB231PS, + OP_VFMSUB231SS, + OP_VFMSUBADD132PS, + OP_VFMSUBADD213PS, + OP_VFMSUBADD231PS, + OP_VFNMADD132PS, + OP_VFNMADD132SS, + OP_VFNMADD213PS, + OP_VFNMADD213SS, + OP_VFNMADD231PS, + OP_VFNMADD231SS, + OP_VFNMSUB132PS, + OP_VFNMSUB132SS, + OP_VFNMSUB213PS, + OP_VFNMSUB213SS, + OP_VFNMSUB231PS, + OP_VFNMSUB231SS, + OP_VGATHER, + OP_VHADDPD, + OP_VHADDPS, + OP_VHSUBPD, + OP_VHSUBPS, + OP_VINSERTF128, + OP_VINSERTI128, + OP_VINSERTPS, + OP_VLDDQU, + OP_VMASKMOVDQU, + OP_VMASKMOVPD, + OP_VMASKMOVPS, + OP_VMAXPD, + OP_VMAXPS, + OP_VMAXSD, + OP_VMAXSS, + OP_VMINPD, + OP_VMINPS, + OP_VMINSD, + OP_VMINSS, + OP_VMOVAPD, + OP_VMOVAPS, + OP_VMOVD, + OP_VMOVDDUP, + OP_VMOVDQA, + OP_VMOVDQU, + OP_VMOVHPD, + OP_VMOVHPS, + OP_VMOVLHPS = OP_VMOVHPS, /**< @todo OP_VMOVHPS */ + OP_VMOVLPD, + OP_VMOVLPS, + OP_VMOVHLPS = OP_VMOVLPS, /**< @todo OP_VMOVLPS */ + OP_VMOVMSKPD, + OP_VMOVMSKPS, + OP_VMOVNTDQ, + OP_VMOVNTDQA, + OP_VMOVNTPD, + OP_VMOVNTPS, + OP_VMOVQ, + OP_VMOVSD, + OP_VMOVSHDUP, + OP_VMOVSLDUP, + OP_VMOVSS, + OP_VMOVUPD, + OP_VMOVUPS, + OP_VMPSADBW, + OP_VMULPD, + OP_VMULPS, + OP_VMULSD, + OP_VMULSS, + OP_VORPD, + OP_VORPS, + OP_VPABSB, + OP_VPABSD, + OP_VPABSW, + OP_VPACKSSDW, + OP_VPACKSSWB, + OP_VPACKUSWB, + OP_VPADDB, + OP_VPADDD, + OP_VPADDQ, + OP_VPADDSB, + OP_VPADDSW, + OP_VPADDUSB, + OP_VPADDUSW, + OP_VPADDW, + OP_VPALIGNR, + OP_VPAND, + OP_VPANDN, + OP_VPAVGB, + OP_VPAVGW, + OP_VPBLENDD, + OP_VPBLENDVB, + OP_VPBLENDW, + OP_VPBROADCASTB, + OP_VPBROADCASTD, + OP_VPBROADCASTI128, + OP_VPBROADCASTQ, + OP_VPBROADCASTW, + OP_VPCLMULQDQ, + OP_VPCMPEQB, + OP_VPCMPEQD, + OP_VPCMPEQQ, + OP_VPCMPEQW, + OP_VPCMPESTRI, + OP_VPCMPESTRM, + OP_VPCMPGTB, + OP_VPCMPGTD, + OP_VPCMPGTQ, + OP_VPCMPGTW, + OP_VPCMPISTRI, + OP_VPCMPISTRM, + OP_VPERM2F128, + OP_VPERM2I128, + OP_VPERMD, + OP_VPERMILPD, + OP_VPERMILPS, + OP_VPERMPD, + OP_VPERMPS, + OP_VPERMQ, + OP_VPEXTRB, + OP_VPEXTRD, + OP_VPEXTRW, + OP_VPEXTRQ, + OP_VPHADDD, + OP_VPHADDSW, + OP_VPHADDW, + OP_VPHMINPOSUW, + OP_VPHSUBD, + OP_VPHSUBSW, + OP_VPHSUBW, + OP_VPINSRB, + OP_VPINSRD, + OP_VPINSRW, + OP_VPINSRQ, + OP_VPMADDUBSW, + OP_VPMADDWD, + OP_VPMASKMOVD, + OP_VPMAXSB, + OP_VPMAXSD, + OP_VPMAXSW, + OP_VPMAXUB, + OP_VPMAXUD, + OP_VPMAXUW, + OP_VPMINSB, + OP_VPMINSD, + OP_VPMINSW, + OP_VPMINUB, + OP_VPMINUD, + OP_VPMINUW, + OP_VPMOVMSKB, + OP_VPMOVSXBW, + OP_VPMOVSXBD, + OP_VPMOVSXBQ, + OP_VPMOVSXWD, + OP_VPMOVSXWQ, + OP_VPMOVSXDQ, + OP_VPMOVZXBW, + OP_VPMOVZXBD, + OP_VPMOVZXBQ, + OP_VPMOVZXWD, + OP_VPMOVZXWQ, + OP_VPMOVZXDQ, + OP_VPMULDQ, + OP_VPMULHRSW, + OP_VPMULHUW, + OP_VPMULHW, + OP_VPMULLD, + OP_VPMULLW, + OP_VPMULUDQ, + OP_VPOR, + OP_VPSADBW, + OP_VPSHUFB, + OP_VPSHUFD, + OP_VPSHUFHW, + OP_VPSHUFLW, + OP_VPSIGNB, + OP_VPSIGND, + OP_VPSIGNW, + OP_VPSLLD, + OP_VPSLLQ, + OP_VPSLLVD, + OP_VPSLLW, + OP_VPSRAD, + OP_VPSRAVD, + OP_VPSRAW, + OP_VPSRLD, + OP_VPSRLQ, + OP_VPSRLVD, + OP_VPSRLW, + OP_VPSUBB, + OP_VPSUBD, + OP_VPSUBQ, + OP_VPSUBSB, + OP_VPSUBSW, + OP_VPSUBUSB, + OP_VPSUBUSW, + OP_VPSUBW, + OP_VPTEST, + OP_VPUNPCKHBW, + OP_VPUNPCKHDQ, + OP_VPUNPCKHQDQ, + OP_VPUNPCKHWD, + OP_VPUNPCKLBW, + OP_VPUNPCKLDQ, + OP_VPUNPCKLQDQ, + OP_VPUNPCKLWD, + OP_VPXOR, + OP_VRCPPS, + OP_VRCPSS, + OP_VROUNDPD, + OP_VROUNDPS, + OP_VROUNDSD, + OP_VROUNDSS, + OP_VRSQRTPS, + OP_VRSQRTSS, + OP_VSHUFPD, + OP_VSHUFPS, + OP_VSQRTPD, + OP_VSQRTPS, + OP_VSQRTSD, + OP_VSQRTSS, + OP_VSUBPD, + OP_VSUBPS, + OP_VSUBSD, + OP_VSUBSS, + OP_VTESTPD, + OP_VTESTPS, + OP_VUCOMISD, + OP_VUCOMISS, + OP_VUNPCKHPD, + OP_VUNPCKHPS, + OP_VUNPCKLPD, + OP_VUNPCKLPS, + OP_VVPACKUSDW, + OP_VXORPD, + OP_VXORPS, + OP_VZEROALL, + +/** @} */ + OP_END_OF_OPCODES +}; +AssertCompile(OP_LOCK == 7); +#if 0 +AssertCompile(OP_END_OF_OPCODES < 1024 /* see 15 byte DISOPCODE variant */); +#endif +/** @} */ + + +/** @defgroup grp_dis_opparam Opcode parameters (DISOPCODE::fParam1, + * DISOPCODE::fParam2, DISOPCODE::fParam3) + * @ingroup grp_dis + * @{ + */ + +/** + * @remarks Register order is important for translations!! + */ +enum OP_PARM +{ + OP_PARM_NONE, + + OP_PARM_REG_EAX, + OP_PARM_REG_GEN32_START = OP_PARM_REG_EAX, + OP_PARM_REG_ECX, + OP_PARM_REG_EDX, + OP_PARM_REG_EBX, + OP_PARM_REG_ESP, + OP_PARM_REG_EBP, + OP_PARM_REG_ESI, + OP_PARM_REG_EDI, + OP_PARM_REG_GEN32_END = OP_PARM_REG_EDI, + + OP_PARM_REG_ES, + OP_PARM_REG_SEG_START = OP_PARM_REG_ES, + OP_PARM_REG_CS, + OP_PARM_REG_SS, + OP_PARM_REG_DS, + OP_PARM_REG_FS, + OP_PARM_REG_GS, + OP_PARM_REG_SEG_END = OP_PARM_REG_GS, + + OP_PARM_REG_AX, + OP_PARM_REG_GEN16_START = OP_PARM_REG_AX, + OP_PARM_REG_CX, + OP_PARM_REG_DX, + OP_PARM_REG_BX, + OP_PARM_REG_SP, + OP_PARM_REG_BP, + OP_PARM_REG_SI, + OP_PARM_REG_DI, + OP_PARM_REG_GEN16_END = OP_PARM_REG_DI, + + OP_PARM_REG_AL, + OP_PARM_REG_GEN8_START = OP_PARM_REG_AL, + OP_PARM_REG_CL, + OP_PARM_REG_DL, + OP_PARM_REG_BL, + OP_PARM_REG_AH, + OP_PARM_REG_CH, + OP_PARM_REG_DH, + OP_PARM_REG_BH, + OP_PARM_REG_GEN8_END = OP_PARM_REG_BH, + + OP_PARM_REGFP_0, + OP_PARM_REG_FP_START = OP_PARM_REGFP_0, + OP_PARM_REGFP_1, + OP_PARM_REGFP_2, + OP_PARM_REGFP_3, + OP_PARM_REGFP_4, + OP_PARM_REGFP_5, + OP_PARM_REGFP_6, + OP_PARM_REGFP_7, + OP_PARM_REG_FP_END = OP_PARM_REGFP_7, + + OP_PARM_NTA, + OP_PARM_T0, + OP_PARM_T1, + OP_PARM_T2, + OP_PARM_1, + + OP_PARM_REX, + OP_PARM_REX_START = OP_PARM_REX, + OP_PARM_REX_B, + OP_PARM_REX_X, + OP_PARM_REX_XB, + OP_PARM_REX_R, + OP_PARM_REX_RB, + OP_PARM_REX_RX, + OP_PARM_REX_RXB, + OP_PARM_REX_W, + OP_PARM_REX_WB, + OP_PARM_REX_WX, + OP_PARM_REX_WXB, + OP_PARM_REX_WR, + OP_PARM_REX_WRB, + OP_PARM_REX_WRX, + OP_PARM_REX_WRXB, + + OP_PARM_REG_RAX, + OP_PARM_REG_GEN64_START = OP_PARM_REG_RAX, + OP_PARM_REG_RCX, + OP_PARM_REG_RDX, + OP_PARM_REG_RBX, + OP_PARM_REG_RSP, + OP_PARM_REG_RBP, + OP_PARM_REG_RSI, + OP_PARM_REG_RDI, + OP_PARM_REG_R8, + OP_PARM_REG_R9, + OP_PARM_REG_R10, + OP_PARM_REG_R11, + OP_PARM_REG_R12, + OP_PARM_REG_R13, + OP_PARM_REG_R14, + OP_PARM_REG_R15, + OP_PARM_REG_GEN64_END = OP_PARM_REG_R15 +}; + + +/* 8-bit GRP aliases (for IEM). */ +#define OP_PARM_AL OP_PARM_REG_AL + +/* GPR aliases for op-size specified register sizes (for IEM). */ +#define OP_PARM_rAX OP_PARM_REG_EAX +#define OP_PARM_rCX OP_PARM_REG_ECX +#define OP_PARM_rDX OP_PARM_REG_EDX +#define OP_PARM_rBX OP_PARM_REG_EBX +#define OP_PARM_rSP OP_PARM_REG_ESP +#define OP_PARM_rBP OP_PARM_REG_EBP +#define OP_PARM_rSI OP_PARM_REG_ESI +#define OP_PARM_rDI OP_PARM_REG_EDI + +/* SREG aliases (for IEM). */ +#define OP_PARM_ES OP_PARM_REG_ES +#define OP_PARM_CS OP_PARM_REG_CS +#define OP_PARM_SS OP_PARM_REG_SS +#define OP_PARM_DS OP_PARM_REG_DS +#define OP_PARM_FS OP_PARM_REG_FS +#define OP_PARM_GS OP_PARM_REG_GS + +/* + * Note! We don't document anything here if we can help it, because it we love + * wasting other peoples time figuring out crypting crap. The new VEX + * stuff of course uphelds this vexing tradition. Aaaaaaaaaaaaaaaaaaarg! + */ + +#define OP_PARM_VTYPE(a) ((unsigned)a & 0xFE0) +#define OP_PARM_VSUBTYPE(a) ((unsigned)a & 0x01F) + +#define OP_PARM_A 0x100 +#define OP_PARM_VARIABLE OP_PARM_A +#define OP_PARM_E 0x120 +#define OP_PARM_F 0x140 +#define OP_PARM_G 0x160 +#define OP_PARM_I 0x180 +#define OP_PARM_J 0x1A0 +#define OP_PARM_M 0x1C0 +#define OP_PARM_O 0x1E0 +#define OP_PARM_R 0x200 +#define OP_PARM_X 0x220 +#define OP_PARM_Y 0x240 + +/* Grouped rare parameters for optimization purposes */ +#define IS_OP_PARM_RARE(a) ((a & 0xF00) >= 0x300) +#define OP_PARM_C 0x300 /* control register */ +#define OP_PARM_D 0x320 /* debug register */ +#define OP_PARM_S 0x340 /* segment register */ +#define OP_PARM_T 0x360 /* test register */ +#define OP_PARM_Q 0x380 +#define OP_PARM_P 0x3A0 /* mmx register */ +#define OP_PARM_W 0x3C0 /* xmm register */ +#define OP_PARM_V 0x3E0 +#define OP_PARM_U 0x400 /* The R/M field of the ModR/M byte selects XMM/YMM register. */ +#define OP_PARM_B 0x420 /* VEX.vvvv field select general purpose register. */ +#define OP_PARM_H 0x440 +#define OP_PARM_L 0x460 + +#define OP_PARM_NONE 0 +#define OP_PARM_a 0x1 /**< Operand to bound instruction. */ +#define OP_PARM_b 0x2 /**< Byte (always). */ +#define OP_PARM_d 0x3 /**< Double word (always). */ +#define OP_PARM_dq 0x4 /**< Double quad word (always). */ +#define OP_PARM_p 0x5 /**< Far pointer (subject to opsize). */ +#define OP_PARM_pd 0x6 /**< 128-bit or 256-bit double precision floating point data. */ +#define OP_PARM_pi 0x7 /**< Quad word MMX register. */ +#define OP_PARM_ps 0x8 /**< 128-bit or 256-bit single precision floating point data. */ +#define OP_PARM_q 0xA /**< Quad word (always). */ +#define OP_PARM_s 0xB /**< Descriptor table size (SIDT/LIDT/SGDT/LGDT). */ +#define OP_PARM_sd 0xC /**< Scalar element of 128-bit double precision floating point data. */ +#define OP_PARM_ss 0xD /**< Scalar element of 128-bit single precision floating point data. */ +#define OP_PARM_v 0xE /**< Word, double word, or quad word depending on opsize. */ +#define OP_PARM_w 0xF /**< Word (always). */ +#define OP_PARM_x 0x10 /**< Double quad word (dq) or quad quad word (qq) depending on opsize. */ +#define OP_PARM_y 0x11 /**< Double word or quad word depending on opsize. */ +#define OP_PARM_z 0x12 /**< Word (16-bit opsize) or double word (32-bit/64-bit opsize). */ +#define OP_PARM_qq 0x13 /**< Quad quad word. */ + + +#define OP_PARM_Ap (OP_PARM_A+OP_PARM_p) +#define OP_PARM_By (OP_PARM_B+OP_PARM_y) +#define OP_PARM_Cd (OP_PARM_C+OP_PARM_d) +#define OP_PARM_Dd (OP_PARM_D+OP_PARM_d) +#define OP_PARM_Eb (OP_PARM_E+OP_PARM_b) +#define OP_PARM_Ed (OP_PARM_E+OP_PARM_d) +#define OP_PARM_Ep (OP_PARM_E+OP_PARM_p) +#define OP_PARM_Ev (OP_PARM_E+OP_PARM_v) +#define OP_PARM_Ew (OP_PARM_E+OP_PARM_w) +#define OP_PARM_Ey (OP_PARM_E+OP_PARM_y) +#define OP_PARM_Fv (OP_PARM_F+OP_PARM_v) +#define OP_PARM_Gb (OP_PARM_G+OP_PARM_b) +#define OP_PARM_Gd (OP_PARM_G+OP_PARM_d) +#define OP_PARM_Gv (OP_PARM_G+OP_PARM_v) +#define OP_PARM_Gw (OP_PARM_G+OP_PARM_w) +#define OP_PARM_Gy (OP_PARM_G+OP_PARM_y) +#define OP_PARM_Hq (OP_PARM_H+OP_PARM_q) +#define OP_PARM_Hps (OP_PARM_H+OP_PARM_ps) +#define OP_PARM_Hpd (OP_PARM_H+OP_PARM_pd) +#define OP_PARM_Hdq (OP_PARM_H+OP_PARM_dq) +#define OP_PARM_Hqq (OP_PARM_H+OP_PARM_qq) +#define OP_PARM_Hsd (OP_PARM_H+OP_PARM_sd) +#define OP_PARM_Hss (OP_PARM_H+OP_PARM_ss) +#define OP_PARM_Hx (OP_PARM_H+OP_PARM_x) +#define OP_PARM_Ib (OP_PARM_I+OP_PARM_b) +#define OP_PARM_Id (OP_PARM_I+OP_PARM_d) +#define OP_PARM_Iq (OP_PARM_I+OP_PARM_q) +#define OP_PARM_Iw (OP_PARM_I+OP_PARM_w) +#define OP_PARM_Iv (OP_PARM_I+OP_PARM_v) +#define OP_PARM_Iz (OP_PARM_I+OP_PARM_z) +#define OP_PARM_Jb (OP_PARM_J+OP_PARM_b) +#define OP_PARM_Jv (OP_PARM_J+OP_PARM_v) +#define OP_PARM_Ma (OP_PARM_M+OP_PARM_a) +#define OP_PARM_Mb (OP_PARM_M+OP_PARM_b) +#define OP_PARM_Mw (OP_PARM_M+OP_PARM_w) +#define OP_PARM_Md (OP_PARM_M+OP_PARM_d) +#define OP_PARM_Mp (OP_PARM_M+OP_PARM_p) +#define OP_PARM_Mq (OP_PARM_M+OP_PARM_q) +#define OP_PARM_Mdq (OP_PARM_M+OP_PARM_dq) +#define OP_PARM_Ms (OP_PARM_M+OP_PARM_s) +#define OP_PARM_Mx (OP_PARM_M+OP_PARM_x) +#define OP_PARM_My (OP_PARM_M+OP_PARM_y) +#define OP_PARM_Mps (OP_PARM_M+OP_PARM_ps) +#define OP_PARM_Mpd (OP_PARM_M+OP_PARM_pd) +#define OP_PARM_Ob (OP_PARM_O+OP_PARM_b) +#define OP_PARM_Ov (OP_PARM_O+OP_PARM_v) +#define OP_PARM_Pq (OP_PARM_P+OP_PARM_q) +#define OP_PARM_Pd (OP_PARM_P+OP_PARM_d) +#define OP_PARM_Qd (OP_PARM_Q+OP_PARM_d) +#define OP_PARM_Qq (OP_PARM_Q+OP_PARM_q) +#define OP_PARM_Rd (OP_PARM_R+OP_PARM_d) +#define OP_PARM_Rw (OP_PARM_R+OP_PARM_w) +#define OP_PARM_Ry (OP_PARM_R+OP_PARM_y) +#define OP_PARM_Sw (OP_PARM_S+OP_PARM_w) +#define OP_PARM_Td (OP_PARM_T+OP_PARM_d) +#define OP_PARM_Ux (OP_PARM_U+OP_PARM_x) +#define OP_PARM_Vq (OP_PARM_V+OP_PARM_q) +#define OP_PARM_Vx (OP_PARM_V+OP_PARM_x) +#define OP_PARM_Vy (OP_PARM_V+OP_PARM_y) +#define OP_PARM_Wq (OP_PARM_W+OP_PARM_q) +/*#define OP_PARM_Ws (OP_PARM_W+OP_PARM_s) - wtf? Same as lgdt (OP_PARM_Ms)?*/ +#define OP_PARM_Wx (OP_PARM_W+OP_PARM_x) +#define OP_PARM_Xb (OP_PARM_X+OP_PARM_b) +#define OP_PARM_Xv (OP_PARM_X+OP_PARM_v) +#define OP_PARM_Yb (OP_PARM_Y+OP_PARM_b) +#define OP_PARM_Yv (OP_PARM_Y+OP_PARM_v) + +#define OP_PARM_Vps (OP_PARM_V+OP_PARM_ps) +#define OP_PARM_Vss (OP_PARM_V+OP_PARM_ss) +#define OP_PARM_Vpd (OP_PARM_V+OP_PARM_pd) +#define OP_PARM_Vdq (OP_PARM_V+OP_PARM_dq) +#define OP_PARM_Wps (OP_PARM_W+OP_PARM_ps) +#define OP_PARM_Wpd (OP_PARM_W+OP_PARM_pd) +#define OP_PARM_Wss (OP_PARM_W+OP_PARM_ss) +#define OP_PARM_Ww (OP_PARM_W+OP_PARM_w) +#define OP_PARM_Wd (OP_PARM_W+OP_PARM_d) +#define OP_PARM_Wq (OP_PARM_W+OP_PARM_q) +#define OP_PARM_Wdq (OP_PARM_W+OP_PARM_dq) +#define OP_PARM_Wqq (OP_PARM_W+OP_PARM_qq) +#define OP_PARM_Ppi (OP_PARM_P+OP_PARM_pi) +#define OP_PARM_Qpi (OP_PARM_Q+OP_PARM_pi) +#define OP_PARM_Qdq (OP_PARM_Q+OP_PARM_dq) +#define OP_PARM_Vsd (OP_PARM_V+OP_PARM_sd) +#define OP_PARM_Wsd (OP_PARM_W+OP_PARM_sd) +#define OP_PARM_Vqq (OP_PARM_V+OP_PARM_qq) +#define OP_PARM_Pdq (OP_PARM_P+OP_PARM_dq) +#define OP_PARM_Ups (OP_PARM_U+OP_PARM_ps) +#define OP_PARM_Upd (OP_PARM_U+OP_PARM_pd) +#define OP_PARM_Udq (OP_PARM_U+OP_PARM_dq) +#define OP_PARM_Lx (OP_PARM_L+OP_PARM_x) + +/* For making IEM / bs3-cpu-generated-1 happy: */ +#define OP_PARM_Ed_WO OP_PARM_Ed /**< Annotates write only operand. */ +#define OP_PARM_Eq (OP_PARM_E+OP_PARM_q) +#define OP_PARM_Eq_WO OP_PARM_Eq /**< Annotates write only operand. */ +#define OP_PARM_Gv_RO OP_PARM_Gv /**< Annotates read only first operand (default is readwrite). */ +#define OP_PARM_HssHi OP_PARM_Hx /**< Register referenced by VEX.vvvv, bits [127:32]. */ +#define OP_PARM_HsdHi OP_PARM_Hx /**< Register referenced by VEX.vvvv, bits [127:64]. */ +#define OP_PARM_HqHi OP_PARM_Hx /**< Register referenced by VEX.vvvv, bits [127:64]. */ +#define OP_PARM_M_RO OP_PARM_M /**< Annotates read only memory of variable operand size (xrstor). */ +#define OP_PARM_M_RW OP_PARM_M /**< Annotates read-write memory of variable operand size (xsave). */ +#define OP_PARM_Mb_RO OP_PARM_Mb /**< Annotates read only memory byte operand. */ +#define OP_PARM_Md_RO OP_PARM_Md /**< Annotates read only memory operand. */ +#define OP_PARM_Md_WO OP_PARM_Md /**< Annotates write only memory operand. */ +#define OP_PARM_Mdq_WO OP_PARM_Mdq /**< Annotates write only memory operand. */ +#define OP_PARM_Mq_WO OP_PARM_Mq /**< Annotates write only memory quad word operand. */ +#define OP_PARM_Mps_WO OP_PARM_Mps /**< Annotates write only memory operand. */ +#define OP_PARM_Mpd_WO OP_PARM_Mpd /**< Annotates write only memory operand. */ +#define OP_PARM_Mx_WO OP_PARM_Mx /**< Annotates write only memory operand. */ +#define OP_PARM_PdZx_WO OP_PARM_Pd /**< Annotates write only operand and zero extends to 64-bit. */ +#define OP_PARM_Pq_WO OP_PARM_Pq /**< Annotates write only operand. */ +#define OP_PARM_Qq_WO OP_PARM_Qq /**< Annotates write only operand. */ +#define OP_PARM_Nq OP_PARM_Qq /**< Missing 'N' class (MMX reg selected by modrm.mem) in disasm. */ +#define OP_PARM_Uq (OP_PARM_U+OP_PARM_q) +#define OP_PARM_UqHi (OP_PARM_U+OP_PARM_dq) +#define OP_PARM_Uss (OP_PARM_U+OP_PARM_ss) +#define OP_PARM_Uss_WO OP_PARM_Uss /**< Annotates write only operand. */ +#define OP_PARM_Usd (OP_PARM_U+OP_PARM_sd) +#define OP_PARM_Usd_WO OP_PARM_Usd /**< Annotates write only operand. */ +#define OP_PARM_Vd (OP_PARM_V+OP_PARM_d) +#define OP_PARM_Vd_WO OP_PARM_Vd /**< Annotates write only operand. */ +#define OP_PARM_VdZx_WO OP_PARM_Vd /**< Annotates that the registers get their upper bits cleared */ +#define OP_PARM_Vdq_WO OP_PARM_Vdq /**< Annotates that only YMM/XMM[127:64] are accessed. */ +#define OP_PARM_Vpd_WO OP_PARM_Vpd /**< Annotates write only operand. */ +#define OP_PARM_Vps_WO OP_PARM_Vps /**< Annotates write only operand. */ +#define OP_PARM_Vq_WO OP_PARM_Vq /**< Annotates write only operand. */ +#define OP_PARM_VqHi OP_PARM_Vdq /**< Annotates that only YMM/XMM[127:64] are accessed. */ +#define OP_PARM_VqHi_WO OP_PARM_Vdq /**< Annotates that only YMM/XMM[127:64] are written. */ +#define OP_PARM_VqZx_WO OP_PARM_Vq /**< Annotates that the registers get their upper bits cleared */ +#define OP_PARM_VsdZx_WO OP_PARM_Vsd /**< Annotates that the registers get their upper bits cleared. */ +#define OP_PARM_VssZx_WO OP_PARM_Vss /**< Annotates that the registers get their upper bits cleared. */ +#define OP_PARM_Vss_WO OP_PARM_Vss /**< Annotates write only operand. */ +#define OP_PARM_Vsd_WO OP_PARM_Vsd /**< Annotates write only operand. */ +#define OP_PARM_Vx_WO OP_PARM_Vx /**< Annotates write only operand. */ +#define OP_PARM_Wpd_WO OP_PARM_Wpd /**< Annotates write only operand. */ +#define OP_PARM_Wps_WO OP_PARM_Wps /**< Annotates write only operand. */ +#define OP_PARM_Wq_WO OP_PARM_Wq /**< Annotates write only operand. */ +#define OP_PARM_WqZxReg_WO OP_PARM_Wq /**< Annotates that register targets get their upper bits cleared. */ +#define OP_PARM_Wss_WO OP_PARM_Wss /**< Annotates write only operand. */ +#define OP_PARM_Wsd_WO OP_PARM_Wsd /**< Annotates write only operand. */ +#define OP_PARM_Wx_WO OP_PARM_Wx /**< Annotates write only operand. */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_disopcode_h */ + diff --git a/include/VBox/err.h b/include/VBox/err.h new file mode 100644 index 00000000..983d9454 --- /dev/null +++ b/include/VBox/err.h @@ -0,0 +1,3148 @@ +/** @file + * VirtualBox Status Codes. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_err_h +#define VBOX_INCLUDED_err_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <iprt/err.h> + + +/** @defgroup grp_err VBox Error Codes + * @{ + */ + +/* SED-START */ + +/** @name Misc. Status Codes + * @{ + */ +/** Failed to allocate VM memory. */ +#define VERR_NO_VM_MEMORY (-1000) +/** RC is toasted and the VMM should be terminated at once, but no need to + * panic about it :-) */ +#define VERR_DONT_PANIC (-1001) +/** Unsupported CPU. */ +#define VERR_UNSUPPORTED_CPU (-1002) +/** Unsupported CPU mode. */ +#define VERR_UNSUPPORTED_CPU_MODE (-1003) +/** Page not present. */ +#define VERR_PAGE_NOT_PRESENT (-1004) +/** Invalid/Corrupted configuration file. */ +#define VERR_CFG_INVALID_FORMAT (-1005) +/** No configuration value exists. */ +#define VERR_CFG_NO_VALUE (-1006) +/** Selector not present. */ +#define VERR_SELECTOR_NOT_PRESENT (-1007) +/** Not code selector. */ +#define VERR_NOT_CODE_SELECTOR (-1008) +/** Not data selector. */ +#define VERR_NOT_DATA_SELECTOR (-1009) +/** Out of selector bounds. */ +#define VERR_OUT_OF_SELECTOR_BOUNDS (-1010) +/** Invalid selector. Usually beyond table limits. */ +#define VERR_INVALID_SELECTOR (-1011) +/** Invalid requested privilege level. */ +#define VERR_INVALID_RPL (-1012) +/** PML4 entry not present. */ +#define VERR_PAGE_MAP_LEVEL4_NOT_PRESENT (-1013) +/** Page directory pointer not present. */ +#define VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT (-1014) +/** Raw mode doesn't support SMP. */ +#define VERR_RAW_MODE_INVALID_SMP (-1015) +/** Invalid VM handle. */ +#define VERR_INVALID_VM_HANDLE (-1016) +/** Invalid VM handle. */ +#define VERR_INVALID_VMCPU_HANDLE (-1017) +/** Invalid Virtual CPU ID. */ +#define VERR_INVALID_CPU_ID (-1018) +/** Too many VCPUs. */ +#define VERR_TOO_MANY_CPUS (-1019) +/** The service was disabled on the host. + * Returned by pfnInit in VBoxService to indicated a non-fatal error that + * should results in the particular service being disabled. */ +#define VERR_SERVICE_DISABLED (-1020) +/** The requested feature is not supported in raw-mode. */ +#define VERR_NOT_SUP_IN_RAW_MODE (-1021) +/** Invalid CPU index. */ +#define VERR_INVALID_CPU_INDEX (-1022) +/** This VirtualBox build does not support raw-mode. */ +#define VERR_RAW_MODE_NOT_SUPPORTED (-1023) +/** Essential fields in the shared VM structure doesn't match the global one. */ +#define VERR_INCONSISTENT_VM_HANDLE (-1024) +/** The VM has been restored. */ +#define VERR_VM_RESTORED (-1025) +/** The requested feature is not supported by NEM. */ +#define VERR_NOT_SUP_BY_NEM (-1026) +/** @} */ + + +/** @name Execution Monitor/Manager (EM) Status Codes + * + * The order of the status codes between VINF_EM_FIRST and VINF_EM_LAST + * are of vital importance. The lower the number the higher importance + * as a scheduling instruction. + * @{ + */ +/** First scheduling related status code. */ +#define VINF_EM_FIRST 1100 +/** Indicating that the VM is being terminated and that the execution + * shall stop. */ +#define VINF_EM_TERMINATE 1100 +/** Hypervisor code was stepped. + * EM will first send this to the debugger, and if the issue isn't + * resolved there it will enter guru meditation. */ +#define VINF_EM_DBG_HYPER_STEPPED 1101 +/** Hit a breakpoint in the hypervisor code, + * EM will first send this to the debugger, and if the issue isn't + * resolved there it will enter guru meditation. */ +#define VINF_EM_DBG_HYPER_BREAKPOINT 1102 +/** Hit a possible assertion in the hypervisor code, + * EM will first send this to the debugger, and if the issue isn't + * resolved there it will enter guru meditation. */ +#define VINF_EM_DBG_HYPER_ASSERTION 1103 +/** Generic debug event, suspend the VM for debugging. */ +#define VINF_EM_DBG_EVENT 1104 +/** Indicating that the VM should be suspended for debugging because + * the developer wants to inspect the VM state. */ +#define VINF_EM_DBG_STOP 1105 +/** Indicating success single stepping and that EM should report that + * event to the debugger. */ +#define VINF_EM_DBG_STEPPED 1106 +/** Indicating that a breakpoint was hit and that EM should notify the debugger + * and in the event there is no debugger fail fatally. */ +#define VINF_EM_DBG_BREAKPOINT 1107 +/** Indicating that EM should single step an instruction. + * The instruction is stepped in the current execution mode (RAW/REM). */ +#define VINF_EM_DBG_STEP 1108 +/** Indicating that the VM is being turned off and that the EM should + * exit to the VM awaiting the destruction request. */ +#define VINF_EM_OFF 1109 +/** Indicating that the VM has been suspended and that the thread + * should wait for request telling it what to do next. */ +#define VINF_EM_SUSPEND 1110 +/** Indicating that the VM has been reset and that scheduling goes + * back to startup defaults. */ +#define VINF_EM_RESET 1111 +/** Indicating that the VM has executed a halt instruction and that + * the emulation thread should wait for an interrupt before resuming + * execution. */ +#define VINF_EM_HALT 1112 +/** Indicating that the VM has been resumed and that the thread should + * start executing. */ +#define VINF_EM_RESUME 1113 +/** Indicating that we've got an out-of-memory condition and that we need + * to take the appropriate actions to deal with this. + * @remarks It might seem odd at first that this has lower priority than VINF_EM_HALT, + * VINF_EM_SUSPEND, and VINF_EM_RESUME. The reason is that these events are + * vital to correctly operating the VM. Also, they can't normally occur together + * with an out-of-memory condition, and even if that should happen the condition + * will be rediscovered before executing any more code. */ +#define VINF_EM_NO_MEMORY 1114 +/** The fatal variant of VINF_EM_NO_MEMORY. */ +#define VERR_EM_NO_MEMORY (-1114) +/** Indicating that a rescheduling to recompiled execution. + * Typically caused by raw-mode executing code which is difficult/slow + * to virtualize rawly. + * @remarks Important to have a higher priority (lower number) than the other rescheduling status codes. */ +#define VINF_EM_RESCHEDULE_REM 1115 +/** Indicating that a rescheduling to vmx-mode execution (HM/NEM). + * Typically caused by REM detecting that hardware-accelerated raw-mode execution is possible. */ +#define VINF_EM_RESCHEDULE_HM 1116 +/** Indicating that a rescheduling to raw-mode execution. + * Typically caused by REM detecting that raw-mode execution is possible. + * @remarks Important to have a higher priority (lower number) than VINF_EM_RESCHEDULE. */ +#define VINF_EM_RESCHEDULE_RAW 1117 +/** Indicating that a rescheduling now is required. Typically caused by + * interrupts having changed the EIP. */ +#define VINF_EM_RESCHEDULE 1118 +/** PARAV call */ +#define VINF_EM_RESCHEDULE_PARAV 1119 +/** Go back into wait for SIPI mode */ +#define VINF_EM_WAIT_SIPI 1120 +/** Last scheduling related status code. (inclusive) */ +#define VINF_EM_LAST 1120 + +/** Reason for leaving RC: Guest trap which couldn't be handled in RC. + * The trap is generally forwarded to the REM and executed there. */ +#define VINF_EM_RAW_GUEST_TRAP 1121 +/** Reason for leaving RC: Interrupted by external interrupt. + * The interrupt needed to be handled by the host OS. */ +#define VINF_EM_RAW_INTERRUPT 1122 +/** Reason for leaving RC: Interrupted by external interrupt while in hypervisor + * code. The interrupt needed to be handled by the host OS and hypervisor + * execution must be resumed. VM state is not complete at this point. */ +#define VINF_EM_RAW_INTERRUPT_HYPER 1123 +/** Reason for leaving RC: A Ring switch was attempted. + * Normal cause of action is to execute this in REM. */ +#define VINF_EM_RAW_RING_SWITCH 1124 +/** Reason for leaving RC: A Ring switch was attempted using software interrupt. + * Normal cause of action is to execute this in REM. */ +#define VINF_EM_RAW_RING_SWITCH_INT 1125 +/** Reason for leaving RC: A privileged instruction was attempted executed. + * Normal cause of action is to execute this in REM. */ +#define VINF_EM_RAW_EXCEPTION_PRIVILEGED 1126 + +/** Reason for leaving RZ: Emulate instruction. */ +#define VINF_EM_RAW_EMULATE_INSTR 1127 +/** Reason for leaving RC: Unhandled TSS write. + * Recompiler gets control. */ +#define VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT 1128 +/** Reason for leaving RC: Unhandled LDT write. + * Recompiler gets control. */ +#define VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT 1129 +/** Reason for leaving RC: Unhandled IDT write. + * Recompiler gets control. */ +#define VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT 1130 +/** Reason for leaving RC: Partly handled GDT write. + * Recompiler gets control. */ +#define VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT 1131 +/** Reason for leaving RC: jump inside generated patch jump. + * Fatal error. */ +#define VERR_EM_RAW_PATCH_CONFLICT (-1133) +/** Reason for leaving RZ: Ring-3 operation pending. */ +#define VINF_EM_RAW_TO_R3 1135 +/** Reason for leaving RZ: Timer pending. */ +#define VINF_EM_RAW_TIMER_PENDING 1136 +/** Reason for leaving RC: Interrupt pending (guest). */ +#define VINF_EM_RAW_INTERRUPT_PENDING 1137 +/** Reason for leaving RC: Encountered a stale selector. */ +#define VINF_EM_RAW_STALE_SELECTOR 1138 +/** Reason for leaving RC: The IRET resuming guest code trapped. */ +#define VINF_EM_RAW_IRET_TRAP 1139 +/** The interpreter was unable to deal with the instruction at hand. */ +#define VERR_EM_INTERPRETER (-1148) +/** Internal EM error caused by an unknown warning or informational status code. */ +#define VERR_EM_INTERNAL_ERROR (-1149) +/** Pending VM request packet. */ +#define VINF_EM_PENDING_REQUEST 1150 +/** Start instruction stepping (debug only). */ +#define VINF_EM_RAW_EMULATE_DBG_STEP 1151 +/** Patch TPR access instruction. */ +#define VINF_EM_HM_PATCH_TPR_INSTR 1152 +/** Unexpected guest mapping conflict detected. */ +#define VERR_EM_UNEXPECTED_MAPPING_CONFLICT (-1154) +/** Reason for leaving RC: A triple-fault condition. Currently, causes + * a guru meditation. */ +#define VINF_EM_TRIPLE_FAULT 1155 +/** The specified execution engine cannot execute guest code in the current + * state. */ +#define VERR_EM_CANNOT_EXEC_GUEST (-1156) +/** Reason for leaving RC: Inject a TRPM event. */ +#define VINF_EM_RAW_INJECT_TRPM_EVENT 1157 +/** Guest tried to trigger a CPU hang. The guest is probably up to no good. */ +#define VERR_EM_GUEST_CPU_HANG (-1158) +/** Reason for leaving RZ: Pending ring-3 IN instruction. */ +#define VINF_EM_PENDING_R3_IOPORT_READ 1159 +/** Reason for leaving RZ: Pending ring-3 OUT instruction. */ +#define VINF_EM_PENDING_R3_IOPORT_WRITE 1160 +/** Trick for resuming EMHistoryExec after a VMCPU_FF_IOM is handled. */ +#define VINF_EM_RESUME_R3_HISTORY_EXEC 1161 +/** Emulate split-lock access on SMP. */ +#define VINF_EM_EMULATE_SPLIT_LOCK 1162 +/** @} */ + + +/** @name Debugging Facility (DBGF) DBGF Status Codes + * @{ + */ +/** The function called requires the caller to be attached as a + * debugger to the VM. */ +#define VERR_DBGF_NOT_ATTACHED (-1200) +/** Someone (including the caller) was already attached as + * debugger to the VM. */ +#define VERR_DBGF_ALREADY_ATTACHED (-1201) +/** Tried to halt a VM or CPU that was already halted. */ +#define VWRN_DBGF_ALREADY_HALTED 1202 +/** The DBGF has no more free breakpoint slots. */ +#define VERR_DBGF_NO_MORE_BP_SLOTS (-1203) +/** The DBGF couldn't find the specified breakpoint. */ +#define VERR_DBGF_BP_NOT_FOUND (-1204) +/** Attempted to enabled a breakpoint which was already enabled. */ +#define VINF_DBGF_BP_ALREADY_ENABLED 1205 +/** Attempted to disabled a breakpoint which was already disabled. */ +#define VINF_DBGF_BP_ALREADY_DISABLED 1206 +/** The breakpoint already exists. */ +#define VINF_DBGF_BP_ALREADY_EXIST 1207 +/** The byte string was not found. */ +#define VERR_DBGF_MEM_NOT_FOUND (-1208) +/** The OS was not detected. */ +#define VERR_DBGF_OS_NOT_DETCTED (-1209) +/** The OS was not detected. */ +#define VINF_DBGF_OS_NOT_DETCTED 1209 +/** The specified register was not found. */ +#define VERR_DBGF_REGISTER_NOT_FOUND (-1210) +/** The value was truncated to fit. + * For queries this means that the register is wider than the queried value. + * For setters this means that the value is wider than the register. */ +#define VINF_DBGF_TRUNCATED_REGISTER 1211 +/** The value was zero extended to fit. + * For queries this means that the register is narrower than the queried value. + * For setters this means that the value is narrower than the register. */ +#define VINF_DBGF_ZERO_EXTENDED_REGISTER 1212 +/** The requested type conversion was not supported. */ +#define VERR_DBGF_UNSUPPORTED_CAST (-1213) +/** The register is read-only and cannot be modified. */ +#define VERR_DBGF_READ_ONLY_REGISTER (-1214) +/** Internal processing error \#1 in the DBGF register code. */ +#define VERR_DBGF_REG_IPE_1 (-1215) +/** Internal processing error \#2 in the DBGF register code. */ +#define VERR_DBGF_REG_IPE_2 (-1216) +/** Unhandled \#DB in hypervisor code. */ +#define VERR_DBGF_HYPER_DB_XCPT (-1217) +/** Internal processing error \#1 in the DBGF stack code. */ +#define VERR_DBGF_STACK_IPE_1 (-1218) +/** Internal processing error \#2 in the DBGF stack code. */ +#define VERR_DBGF_STACK_IPE_2 (-1219) +/** No trace buffer available, please change the VM config. */ +#define VERR_DBGF_NO_TRACE_BUFFER (-1220) +/** Internal processing error \#1 in the DBGF event tracing code. */ +#define VERR_DBGF_TRACER_IPE_1 (-1221) +/** Tried to resume a VM or CPU that is already fully running. */ +#define VWRN_DBGF_ALREADY_RUNNING (-1222) +/** Internal processing error \#1 in the DBGF core code. */ +#define VERR_DBGF_IPE_1 (-1223) +/** Returned by a breakpoint callback when guest execution should be suspended + * and the VM should be dropped into the debugger. */ +#define VINF_DBGF_BP_HALT (1224) +/** The breakpoint owner handle is still used by one or more breakpoints. */ +#define VERR_DBGF_OWNER_BUSY (-1225) +/** Number of tries to add an int3 breakpoint table to the lookup tables reached. */ +#define VERR_DBGF_BP_INT3_ADD_TRIES_REACHED (-1226) +/** Internal processing error \#1 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_1 (-1227) +/** Internal processing error \#2 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_2 (-1228) +/** Internal processing error \#3 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_3 (-1229) +/** Internal processing error \#4 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_4 (-1230) +/** Internal processing error \#5 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_5 (-1231) +/** Internal processing error \#6 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_6 (-1232) +/** Internal processing error \#7 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_7 (-1233) +/** Internal processing error \#8 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_8 (-1234) +/** Internal processing error \#9 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_9 (-1235) +/** Level 2 lookup failed because the L1 lookup table is corrupted. */ +#define VERR_DBGF_BP_L1_LOOKUP_FAILED (-1236) +/** Level 2 lookup failed because the L2 lookup table is corrupted. */ +#define VERR_DBGF_BP_L2_LOOKUP_FAILED (-1237) +/** The DBGF has no more free breakpoint owner handles. */ +#define VERR_DBGF_BP_OWNER_NO_MORE_HANDLES (-1238) +/** Reason for leaving RZ: Defer the owner callback invocation to Ring-3. */ +#define VINF_DBGF_R3_BP_OWNER_DEFER 1239 +/** The breakpoint owner callback returned an invalid status code. */ +#define VERR_DBGF_BP_OWNER_CALLBACK_WRONG_STATUS (-1240) +/** The operation was cancelled. */ +#define VERR_DBGF_CANCELLED (-1241) +/** @} */ + + +/** @name Patch Manager (PATM) Status Codes + * @{ + */ +/** Non fatal Patch Manager analysis phase warning */ +#define VWRN_CONTINUE_ANALYSIS 1400 +/** Non fatal Patch Manager recompile phase warning (mapped to VWRN_CONTINUE_ANALYSIS). */ +#define VWRN_CONTINUE_RECOMPILE VWRN_CONTINUE_ANALYSIS +/** Continue search (mapped to VWRN_CONTINUE_ANALYSIS). */ +#define VWRN_PATM_CONTINUE_SEARCH VWRN_CONTINUE_ANALYSIS +/** Patch installation refused (patch too complex or unsupported instructions ) */ +#define VERR_PATCHING_REFUSED (-1401) +/** Unable to find patch */ +#define VERR_PATCH_NOT_FOUND (-1402) +/** Patch disabled */ +#define VERR_PATCH_DISABLED (-1403) +/** Patch enabled */ +#define VWRN_PATCH_ENABLED 1404 +/** Patch was already disabled */ +#define VERR_PATCH_ALREADY_DISABLED (-1405) +/** Patch was already enabled */ +#define VERR_PATCH_ALREADY_ENABLED (-1406) +/** Patch was removed. */ +#define VWRN_PATCH_REMOVED 1407 + +/** Reason for leaving RC: \#GP with EIP pointing to patch code. */ +#define VINF_PATM_PATCH_TRAP_GP 1408 +/** First leave RC code. */ +#define VINF_PATM_LEAVE_RC_FIRST VINF_PATM_PATCH_TRAP_GP +/** Reason for leaving RC: \#PF with EIP pointing to patch code. */ +#define VINF_PATM_PATCH_TRAP_PF 1409 +/** Reason for leaving RC: int3 with EIP pointing to patch code. */ +#define VINF_PATM_PATCH_INT3 1410 +/** Reason for leaving RC: \#PF for monitored patch page. */ +#define VINF_PATM_CHECK_PATCH_PAGE 1411 +/** Reason for leaving RC: duplicate instruction called at current eip. */ +#define VINF_PATM_DUPLICATE_FUNCTION 1412 +/** Execute one instruction with the recompiler */ +#define VINF_PATCH_EMULATE_INSTR 1413 +/** Reason for leaving RC: attempt to patch MMIO write. */ +#define VINF_PATM_HC_MMIO_PATCH_WRITE 1414 +/** Reason for leaving RC: attempt to patch MMIO read. */ +#define VINF_PATM_HC_MMIO_PATCH_READ 1415 +/** Reason for leaving RC: pending irq after iret that sets IF. */ +#define VINF_PATM_PENDING_IRQ_AFTER_IRET 1416 +/** Last leave RC code. */ +#define VINF_PATM_LEAVE_RC_LAST VINF_PATM_PENDING_IRQ_AFTER_IRET + +/** No conflicts to resolve */ +#define VERR_PATCH_NO_CONFLICT (-1425) +/** Detected unsafe code for patching */ +#define VERR_PATM_UNSAFE_CODE (-1426) +/** Terminate search branch */ +#define VWRN_PATCH_END_BRANCH 1427 +/** Already patched */ +#define VERR_PATM_ALREADY_PATCHED (-1428) +/** Spinlock detection failed. */ +#define VINF_PATM_SPINLOCK_FAILED (1429) +/** Continue execution after patch trap. */ +#define VINF_PATCH_CONTINUE (1430) +/** The patch manager is not used because we're using HM and VT-x/AMD-V. */ +#define VERR_PATM_HM_IPE (-1431) +/** Unexpected trap in patch code. */ +#define VERR_PATM_IPE_TRAP_IN_PATCH_CODE (-1432) + +/** @} */ + + +/** @name Code Scanning and Analysis Manager (CSAM) Status Codes + * @{ + */ +/** Trap not handled */ +#define VWRN_CSAM_TRAP_NOT_HANDLED 1500 +/** Patch installed */ +#define VWRN_CSAM_INSTRUCTION_PATCHED 1501 +/** Page record not found */ +#define VWRN_CSAM_PAGE_NOT_FOUND 1502 +/** Reason for leaving RC: CSAM wants perform a task in ring-3. */ +#define VINF_CSAM_PENDING_ACTION 1503 +/** The CSAM is not used because we're using HM and VT-x/AMD-V. */ +#define VERR_CSAM_HM_IPE (-1504) +/** @} */ + + +/** @name Page Monitor/Manager (PGM) Status Codes + * @{ + */ +/** Attempt to create a GC mapping which conflicts with an existing mapping. */ +#define VERR_PGM_MAPPING_CONFLICT (-1600) +/** The physical handler range has no corresponding RAM range. + * If this is MMIO, see todo above the return. If not MMIO, then it's + * someone else's fault... */ +#define VERR_PGM_HANDLER_PHYSICAL_NO_RAM_RANGE (-1601) +/** Attempt to register an access handler for a virtual range of which a part + * was already handled. */ +#define VERR_PGM_HANDLER_VIRTUAL_CONFLICT (-1602) +/** Attempt to register an access handler for a physical range of which a part + * was already handled. */ +#define VERR_PGM_HANDLER_PHYSICAL_CONFLICT (-1603) +/** Invalid page directory specified to PGM. */ +#define VERR_PGM_INVALID_PAGE_DIRECTORY (-1604) +/** Invalid GC physical address. */ +#define VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS (-1605) +/** Invalid GC physical range. Usually used when a specified range crosses + * a RAM region boundary. */ +#define VERR_PGM_INVALID_GC_PHYSICAL_RANGE (-1606) +/** Specified access handler was not found. */ +#define VERR_PGM_HANDLER_NOT_FOUND (-1607) +/** Attempt to register a RAM range of which parts are already + * covered by existing RAM ranges. */ +#define VERR_PGM_RAM_CONFLICT (-1608) +/** Failed to add new mappings because the current mappings are fixed + * in guest os memory. */ +#define VERR_PGM_MAPPINGS_FIXED (-1609) +/** Failed to fix mappings because of a conflict with the intermediate code. */ +#define VERR_PGM_MAPPINGS_FIX_CONFLICT (-1610) +/** Failed to fix mappings because a mapping rejected the address. */ +#define VERR_PGM_MAPPINGS_FIX_REJECTED (-1611) +/** Failed to fix mappings because the proposed memory area was to small. */ +#define VERR_PGM_MAPPINGS_FIX_TOO_SMALL (-1612) +/** Reason for leaving RZ: The urge to syncing CR3. */ +#define VINF_PGM_SYNC_CR3 1613 +/** Page not marked for dirty bit tracking */ +#define VINF_PGM_NO_DIRTY_BIT_TRACKING 1614 +/** Page fault caused by dirty bit tracking; corrected */ +#define VINF_PGM_HANDLED_DIRTY_BIT_FAULT 1615 +/** Go ahead with the default Read/Write operation. + * This is returned by a R3 physical or virtual handler when it wants the + * PGMPhys[Read|Write] routine do the reading/writing. */ +#define VINF_PGM_HANDLER_DO_DEFAULT 1616 +/** The paging mode of the host is not supported yet. */ +#define VERR_PGM_UNSUPPORTED_HOST_PAGING_MODE (-1617) +/** The physical guest page is a reserved/MMIO page and does not have any HC + * address. */ +#define VERR_PGM_PHYS_PAGE_RESERVED (-1618) +/** No page directory available for the hypervisor. */ +#define VERR_PGM_NO_HYPERVISOR_ADDRESS (-1619) + + +/** The returned shadow page is cached. */ +#define VINF_PGM_CACHED_PAGE 1622 +/** Returned by handler registration, modification and deregistration + * when the shadow PTs could be updated because the guest page + * aliased or/and mapped by multiple PTs. */ +#define VINF_PGM_GCPHYS_ALIASED 1623 +/** SyncPage modified the PDE. + * This is an internal status code used to communicate back to the \#PF handler + * that the PDE was (probably) marked not-present and it should restart the instruction. */ +#define VINF_PGM_SYNCPAGE_MODIFIED_PDE 1625 +/** Physical range crosses dynamic ram chunk boundary; translation to HC ptr not safe. */ +#define VERR_PGM_GCPHYS_RANGE_CROSSES_BOUNDARY (-1626) +/** Conflict between the core memory and the intermediate paging context, try again. + * There are some very special conditions applying to the intermediate paging context + * (used during the world switches), and some times we continuously run into these + * when asking the host kernel for memory during VM init. Let us know if you run into + * this and we'll adjust the code so it tries harder to avoid it. + */ +#define VERR_PGM_INTERMEDIATE_PAGING_CONFLICT (-1627) +/** The shadow paging mode is not supported yet. */ +#define VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE (-1628) +/** The dynamic mapping cache for physical memory failed. */ +#define VERR_PGM_DYNMAP_FAILED (-1629) +/** The auto usage cache for the dynamic mapping set is full. */ +#define VERR_PGM_DYNMAP_FULL_SET (-1630) +/** The initialization of the dynamic mapping cache failed. */ +#define VERR_PGM_DYNMAP_SETUP_ERROR (-1631) +/** The expanding of the dynamic mapping cache failed. */ +#define VERR_PGM_DYNMAP_EXPAND_ERROR (-1632) +/** The page is unassigned (akin to VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS). */ +#define VERR_PGM_PHYS_TLB_UNASSIGNED (-1633) +/** Catch any access and route it thru PGM. */ +#define VERR_PGM_PHYS_TLB_CATCH_ALL (-1634) +/** Catch write access and route it thru PGM. */ +#define VINF_PGM_PHYS_TLB_CATCH_WRITE 1635 +/** Catch write access and route it thru PGM. */ +#define VERR_PGM_PHYS_TLB_CATCH_WRITE (-1635) +/** No CR3 root shadow page table. */ +#define VERR_PGM_NO_CR3_SHADOW_ROOT (-1636) +/** Trying to free a page with an invalid Page ID. */ +#define VERR_PGM_PHYS_INVALID_PAGE_ID (-1637) +/** PGMPhysWrite/Read hit a handler in Ring-0 or raw-mode context. */ +#define VERR_PGM_PHYS_WR_HIT_HANDLER (-1638) +/** Trying to free a page that isn't RAM. */ +#define VERR_PGM_PHYS_NOT_RAM (-1639) +/** Not ROM page. */ +#define VERR_PGM_PHYS_NOT_ROM (-1640) +/** Not MMIO page. */ +#define VERR_PGM_PHYS_NOT_MMIO (-1641) +/** Not MMIO2 page. */ +#define VERR_PGM_PHYS_NOT_MMIO2 (-1642) +/** Already aliased to a different page. */ +#define VERR_PGM_HANDLER_ALREADY_ALIASED (-1643) +/** Already aliased to the same page. */ +#define VINF_PGM_HANDLER_ALREADY_ALIASED (1643) +/** PGM pool flush pending - return to ring 3. */ +#define VINF_PGM_POOL_FLUSH_PENDING (1644) +/** Unable to use the range for a large page. */ +#define VERR_PGM_INVALID_LARGE_PAGE_RANGE (-1645) +/** Don't mess around with ballooned pages. */ +#define VERR_PGM_PHYS_PAGE_BALLOONED (-1646) +/** Internal processing error \#1 in page access handler code. */ +#define VERR_PGM_HANDLER_IPE_1 (-1647) + + +/** pgmPhysPageMapCommon encountered PGMPAGETYPE_MMIO2_ALIAS_MMIO. */ +#define VERR_PGM_MAP_MMIO2_ALIAS_MMIO (-1651) +/** Guest mappings are disabled. */ +#define VERR_PGM_MAPPINGS_DISABLED (-1652) +/** No guest mappings when SMP is enabled. */ +#define VERR_PGM_MAPPINGS_SMP (-1653) +/** Invalid saved page state. */ +#define VERR_PGM_INVALID_SAVED_PAGE_STATE (-1654) +/** Encountered an unexpected page type in the saved state. */ +#define VERR_PGM_LOAD_UNEXPECTED_PAGE_TYPE (-1655) +/** Encountered an unexpected page state in the saved state. */ +#define VERR_PGM_UNEXPECTED_PAGE_STATE (-1656) +/** Couldn't find MMIO2 range from saved state. */ +#define VERR_PGM_SAVED_MMIO2_RANGE_NOT_FOUND (-1657) +/** Couldn't find MMIO2 page from saved state. */ +#define VERR_PGM_SAVED_MMIO2_PAGE_NOT_FOUND (-1658) +/** Couldn't find ROM range from saved state. */ +#define VERR_PGM_SAVED_ROM_RANGE_NOT_FOUND (-1659) +/** Couldn't find ROM page from saved state. */ +#define VERR_PGM_SAVED_ROM_PAGE_NOT_FOUND (-1660) +/** ROM page mismatch between saved state and the VM. */ +#define VERR_PGM_SAVED_ROM_PAGE_PROT (-1661) +/** Unknown saved state record. */ +#define VERR_PGM_SAVED_REC_TYPE (-1662) +/** Internal processing error in the PGM dynmap (r0/rc). */ +#define VERR_PGM_DYNMAP_IPE (-1663) +/** Internal processing error in the PGM handy page allocator. */ +#define VERR_PGM_HANDY_PAGE_IPE (-1664) +/** Failed to map the guest PML4. */ +#define VERR_PGM_PML4_MAPPING (-1665) +/** Failed to obtain a pool page. */ +#define VERR_PGM_POOL_GET_PAGE_FAILED (-1666) +/** A PGM function was called in a mode where it isn't supposed to be used. */ +#define VERR_PGM_NOT_USED_IN_MODE (-1667) +/** The CR3 address specified memory we don't know about. */ +#define VERR_PGM_INVALID_CR3_ADDR (-1668) +/** One or the PDPEs specified memory we don't know about. */ +#define VERR_PGM_INVALID_PDPE_ADDR (-1669) +/** Internal processing error in the PGM physical handler code. */ +#define VERR_PGM_PHYS_HANDLER_IPE (-1670) +/** Internal processing error \#1 in the PGM physial page mapping code. */ +#define VERR_PGM_PHYS_PAGE_MAP_IPE_1 (-1671) +/** Internal processing error \#2 in the PGM physial page mapping code. */ +#define VERR_PGM_PHYS_PAGE_MAP_IPE_2 (-1672) +/** Internal processing error \#3 in the PGM physial page mapping code. */ +#define VERR_PGM_PHYS_PAGE_MAP_IPE_3 (-1673) +/** Internal processing error \#4 in the PGM physial page mapping code. */ +#define VERR_PGM_PHYS_PAGE_MAP_IPE_4 (-1674) +/** Too many loops looking for a page to reuse. */ +#define VERR_PGM_POOL_TOO_MANY_LOOPS (-1675) +/** Internal processing error related to guest mappings. */ +#define VERR_PGM_MAPPING_IPE (-1676) +/** An attempt was made to grow an already maxed out page pool. */ +#define VERR_PGM_POOL_MAXED_OUT_ALREADY (-1677) +/** Internal processing error in the page pool code. */ +#define VERR_PGM_POOL_IPE (-1678) +/** The write monitor is already engaged. */ +#define VERR_PGM_WRITE_MONITOR_ENGAGED (-1679) +/** Failed to get a guest page which is expected to be present. */ +#define VERR_PGM_PHYS_PAGE_GET_IPE (-1680) +/** We were given a NULL pPage parameter. */ +#define VERR_PGM_PHYS_NULL_PAGE_PARAM (-1681) +/** PCI passthru is not supported by this build. */ +#define VERR_PGM_PCI_PASSTHRU_MISCONFIG (-1682) +/** Too many MMIO2 ranges. */ +#define VERR_PGM_TOO_MANY_MMIO2_RANGES (-1683) +/** Internal processing error in the PGM physical page mapping code dealing + * with MMIO2 pages. */ +#define VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE (-1684) +/** Internal processing error in the PGM physcal page handling code related to + * MMIO/MMIO2. */ +#define VERR_PGM_PHYS_MMIO_EX_IPE (-1685) +/** Mode table internal error. */ +#define VERR_PGM_MODE_IPE (-1686) +/** Shadow mode 'none' internal error. */ +#define VERR_PGM_SHW_NONE_IPE (-1687) +/** One or more PAE PDPEs are invalid due to reserved bits being set. */ +#define VERR_PGM_PAE_PDPE_RSVD (-1688) +/** Attemted illegal operation in simplified memory management mode. */ +#define VERR_PGM_NOT_SUPPORTED_FOR_NEM_MODE (-1689) +/** @} */ + + +/** @name Memory Monitor (MM) Status Codes + * @{ + */ +/** Attempt to register a RAM range of which parts are already + * covered by existing RAM ranges. */ +#define VERR_MM_RAM_CONFLICT (-1700) +/** Hypervisor memory allocation failed. */ +#define VERR_MM_HYPER_NO_MEMORY (-1701) +/** A bad trap type ended up in mmGCRamTrap0eHandler. */ +#define VERR_MM_BAD_TRAP_TYPE_IPE (-1702) +/** @} */ + + +/** @name CPU Monitor (CPUM) Status Codes + * @{ + */ +/** The caller shall raise an \#GP(0) exception. */ +#define VERR_CPUM_RAISE_GP_0 (-1750) +/** Incompatible CPUM configuration. */ +#define VERR_CPUM_INCOMPATIBLE_CONFIG (-1751) +/** CPUMR3DisasmInstrCPU unexpectedly failed to determine the hidden + * parts of the CS register. */ +#define VERR_CPUM_HIDDEN_CS_LOAD_ERROR (-1752) +/** Couldn't find the end of CPUID sub-leaves. */ +#define VERR_CPUM_TOO_MANY_CPUID_SUBLEAVES (-1753) +/** CPUM internal processing error \#1. */ +#define VERR_CPUM_IPE_1 (-1754) +/** CPUM internal processing error \#2. */ +#define VERR_CPUM_IPE_2 (-1755) +/** The specified CPU cannot be found in the CPU database. */ +#define VERR_CPUM_DB_CPU_NOT_FOUND (-1756) +/** Invalid CPUMCPU offset in MSR range. */ +#define VERR_CPUM_MSR_BAD_CPUMCPU_OFFSET (-1757) +/** Return to ring-3 to read the MSR there. */ +#define VINF_CPUM_R3_MSR_READ (1758) +/** Return to ring-3 to write the MSR there. */ +#define VINF_CPUM_R3_MSR_WRITE (1759) +/** Too many CPUID leaves. */ +#define VERR_TOO_MANY_CPUID_LEAVES (-1760) +/** Invalid config value. */ +#define VERR_CPUM_INVALID_CONFIG_VALUE (-1761) +/** The loaded XSAVE component mask is not compatible with the host CPU + * or/and VM config. */ +#define VERR_CPUM_INCOMPATIBLE_XSAVE_COMP_MASK (-1762) +/** The loaded XSAVE component mask is not valid. */ +#define VERR_CPUM_INVALID_XSAVE_COMP_MASK (-1763) +/** The loaded XSAVE header is not valid. */ +#define VERR_CPUM_INVALID_XSAVE_HDR (-1764) +/** The loaded XCR0 register value is not valid. */ +#define VERR_CPUM_INVALID_XCR0 (-1765) +/** Indicates that we modified the host CR0 (FPU related). */ +#define VINF_CPUM_HOST_CR0_MODIFIED (1766) +/** Invalid/unsupported nested hardware virtualization configuration. */ +#define VERR_CPUM_INVALID_HWVIRT_CONFIG (-1767) +/** Invalid nested hardware virtualization feature combination. */ +#define VERR_CPUM_INVALID_HWVIRT_FEAT_COMBO (-1768) +/** @} */ + + +/** @name Save State Manager (SSM) Status Codes + * @{ + */ +/** The specified data unit already exist. */ +#define VERR_SSM_UNIT_EXISTS (-1800) +/** The specified data unit wasn't found. */ +#define VERR_SSM_UNIT_NOT_FOUND (-1801) +/** The specified data unit wasn't owned by caller. */ +#define VERR_SSM_UNIT_NOT_OWNER (-1802) + +/** General saved state file integrity error. */ +#define VERR_SSM_INTEGRITY (-1810) +/** The saved state file magic was not recognized. */ +#define VERR_SSM_INTEGRITY_MAGIC (-1811) +/** The saved state file version is not supported. */ +#define VERR_SSM_INTEGRITY_VERSION (-1812) +/** The saved state file size didn't match the one in the header. */ +#define VERR_SSM_INTEGRITY_SIZE (-1813) +/** The CRC of the saved state file did not match. */ +#define VERR_SSM_INTEGRITY_CRC (-1814) +/** The machine uuid field wasn't null. */ +#define VERR_SMM_INTEGRITY_MACHINE (-1815) +/** Saved state header integrity error. */ +#define VERR_SSM_INTEGRITY_HEADER (-1816) +/** Unit header integrity error. */ +#define VERR_SSM_INTEGRITY_UNIT (-1817) +/** Invalid unit magic (internal data tag). */ +#define VERR_SSM_INTEGRITY_UNIT_MAGIC (-1818) +/** The file contained a data unit which no-one wants. */ +#define VERR_SSM_INTEGRITY_UNIT_NOT_FOUND (-1819) +/** Incorrect version numbers in the header. */ +#define VERR_SSM_INTEGRITY_VBOX_VERSION (-1820) +/** Footer integrity error. */ +#define VERR_SSM_INTEGRITY_FOOTER (-1821) +/** Record header integrity error. */ +#define VERR_SSM_INTEGRITY_REC_HDR (-1822) +/** Termination record integrity error. */ +#define VERR_SSM_INTEGRITY_REC_TERM (-1823) +/** Termination record CRC mismatch. */ +#define VERR_SSM_INTEGRITY_REC_TERM_CRC (-1824) +/** Decompression integrity error. */ +#define VERR_SSM_INTEGRITY_DECOMPRESSION (-1825) +/** Saved state directory wintertides error. */ +#define VERR_SSM_INTEGRITY_DIR (-1826) +/** The saved state directory magic is wrong. */ +#define VERR_SSM_INTEGRITY_DIR_MAGIC (-1827) + +/** A data unit in the saved state file was defined but didn't any + * routine for processing it. */ +#define VERR_SSM_NO_LOAD_EXEC (-1830) +/** A restore routine attempted to load more data then the unit contained. */ +#define VERR_SSM_LOADED_TOO_MUCH (-1831) +/** Not in the correct state for the attempted operation. */ +#define VERR_SSM_INVALID_STATE (-1832) +/** Not in the correct state for the attempted operation. */ +#define VERR_SSM_LOADED_TOO_LITTLE (-1833) + +/** Unsupported data unit version. + * A SSM user returns this if it doesn't know the u32Version. */ +#define VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION (-1840) +/** The format of a data unit has changed. + * A SSM user returns this if it's not able to read the format for + * other reasons than u32Version. */ +#define VERR_SSM_DATA_UNIT_FORMAT_CHANGED (-1841) +/** The CPUID instruction returns different information when loading than when saved. + * Normally caused by hardware changes on the host, but could also be caused by + * changes in the BIOS setup. */ +#define VERR_SSM_LOAD_CPUID_MISMATCH (-1842) +/** The RAM size differs between the saved state and the VM config. */ +#define VERR_SSM_LOAD_MEMORY_SIZE_MISMATCH (-1843) +/** The state doesn't match the VM configuration in one or another way. + * (There are certain PCI reconfiguration which the OS could potentially + * do which can cause this problem. Check this out when it happens.) */ +#define VERR_SSM_LOAD_CONFIG_MISMATCH (-1844) +/** The virtual clock frequency differs too much. + * The clock source for the virtual time isn't reliable or the code have changed. */ +#define VERR_SSM_VIRTUAL_CLOCK_HZ (-1845) +/** A timeout occurred while waiting for async IDE operations to finish. */ +#define VERR_SSM_IDE_ASYNC_TIMEOUT (-1846) +/** One of the structure magics was wrong. */ +#define VERR_SSM_STRUCTURE_MAGIC (-1847) +/** The data in the saved state doesn't conform to expectations. */ +#define VERR_SSM_UNEXPECTED_DATA (-1848) +/** Trying to read a 64-bit guest physical address into a 32-bit variable. */ +#define VERR_SSM_GCPHYS_OVERFLOW (-1849) +/** Trying to read a 64-bit guest virtual address into a 32-bit variable. */ +#define VERR_SSM_GCPTR_OVERFLOW (-1850) +/** Vote for another pass. */ +#define VINF_SSM_VOTE_FOR_ANOTHER_PASS 1851 +/** Vote for done tell SSM not to call again until the final pass. */ +#define VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN 1852 +/** Vote for giving up. */ +#define VERR_SSM_VOTE_FOR_GIVING_UP (-1853) +/** Don't call again until the final pass. */ +#define VINF_SSM_DONT_CALL_AGAIN 1854 +/** Giving up a live snapshot/teleportation attempt because of too many + * passes. */ +#define VERR_SSM_TOO_MANY_PASSES (-1855) +/** Giving up a live snapshot/teleportation attempt because the state grew to + * big. */ +#define VERR_SSM_STATE_GREW_TOO_BIG (-1856) +/** Giving up a live snapshot attempt because we're low on disk space. */ +#define VERR_SSM_LOW_ON_DISK_SPACE (-1857) +/** The operation was cancelled. */ +#define VERR_SSM_CANCELLED (-1858) +/** Nothing that can be cancelled. */ +#define VERR_SSM_NO_PENDING_OPERATION (-1859) +/** The operation has already been cancelled. */ +#define VERR_SSM_ALREADY_CANCELLED (-1860) +/** The machine was powered off while saving. */ +#define VERR_SSM_LIVE_POWERED_OFF (-1861) +/** The live snapshot/teleportation operation was aborted because of a guru + * meditation. */ +#define VERR_SSM_LIVE_GURU_MEDITATION (-1862) +/** The live snapshot/teleportation operation was aborted because of a fatal + * runtime error. */ +#define VERR_SSM_LIVE_FATAL_ERROR (-1863) +/** The VM was suspended before or while saving, don't resume execution. */ +#define VINF_SSM_LIVE_SUSPENDED 1864 +/** Complex SSM field fed to SSMR3PutStruct or SSMR3GetStruct. Use the + * extended API. */ +#define VERR_SSM_FIELD_COMPLEX (-1864) +/** Invalid size of a SSM field with the specified transformation. */ +#define VERR_SSM_FIELD_INVALID_SIZE (-1865) +/** The specified field is outside the structure. */ +#define VERR_SSM_FIELD_OUT_OF_BOUNDS (-1866) +/** The field does not follow immediately the previous one. */ +#define VERR_SSM_FIELD_NOT_CONSECUTIVE (-1867) +/** The field contains an invalid callback or transformation index. */ +#define VERR_SSM_FIELD_INVALID_CALLBACK (-1868) +/** The field contains an invalid padding size. */ +#define VERR_SSM_FIELD_INVALID_PADDING_SIZE (-1869) +/** The field contains a value that is out of range. */ +#define VERR_SSM_FIELD_INVALID_VALUE (-1870) +/** Generic stream error. */ +#define VERR_SSM_STREAM_ERROR (-1871) +/** SSM did a callback for a pass we didn't expect. */ +#define VERR_SSM_UNEXPECTED_PASS (-1872) +/** Someone is trying to skip backwards in the stream... */ +#define VERR_SSM_SKIP_BACKWARDS (-1873) +/** Someone is trying to write a memory block which is too big to encode. */ +#define VERR_SSM_MEM_TOO_BIG (-1874) +/** Encountered an bad (/unknown) record type. */ +#define VERR_SSM_BAD_REC_TYPE (-1875) +/** Internal processing error \#1 in SSM code. */ +#define VERR_SSM_IPE_1 (-1876) +/** Internal processing error \#2 in SSM code. */ +#define VERR_SSM_IPE_2 (-1877) +/** Internal processing error \#3 in SSM code. */ +#define VERR_SSM_IPE_3 (-1878) +/** A field contained an transformation that should only be used when loading + * old states. */ +#define VERR_SSM_FIELD_LOAD_ONLY_TRANSFORMATION (-1879) +/** @} */ + + +/** @name Virtual Machine (VM) Status Codes + * @{ + */ +/** The specified at reset handler wasn't found. */ +#define VERR_VM_ATRESET_NOT_FOUND (-1900) +/** Invalid VM request type. + * For the VMR3ReqAlloc() case, the caller just specified an illegal enmType. For + * all the other occurrences it means indicates corruption, broken logic, or stupid + * interface user. */ +#define VERR_VM_REQUEST_INVALID_TYPE (-1901) +/** Invalid VM request state. + * The state of the request packet was not the expected and accepted one(s). Either + * the interface user screwed up, or we've got corruption/broken logic. */ +#define VERR_VM_REQUEST_STATE (-1902) +/** Invalid VM request packet. + * One or more of the VM controlled packet members didn't contain the correct + * values. Some thing's broken. */ +#define VERR_VM_REQUEST_INVALID_PACKAGE (-1903) +/** The status field has not been updated yet as the request is still + * pending completion. Someone queried the iStatus field before the request + * has been fully processed. */ +#define VERR_VM_REQUEST_STATUS_STILL_PENDING (-1904) +/** The request has been freed, don't read the status now. + * Someone is reading the iStatus field of a freed request packet. */ +#define VERR_VM_REQUEST_STATUS_FREED (-1905) +/** A VM api requiring EMT was called from another thread. + * Use the VMR3ReqCall() apis to call it! */ +#define VERR_VM_THREAD_NOT_EMT (-1906) +/** The VM state was invalid for the requested operation. + * Go check the 'VM Statechart Diagram.gif'. */ +#define VERR_VM_INVALID_VM_STATE (-1907) +/** The support driver is not installed. + * On linux, open returned ENOENT. */ +#define VERR_VM_DRIVER_NOT_INSTALLED (-1908) +/** The support driver is not accessible. + * On linux, open returned EPERM. */ +#define VERR_VM_DRIVER_NOT_ACCESSIBLE (-1909) +/** Was not able to load the support driver. + * On linux, open returned ENODEV. */ +#define VERR_VM_DRIVER_LOAD_ERROR (-1910) +/** Was not able to open the support driver. + * Generic open error used when none of the other ones fit. */ +#define VERR_VM_DRIVER_OPEN_ERROR (-1911) +/** The installed support driver doesn't match the version of the user. */ +#define VERR_VM_DRIVER_VERSION_MISMATCH (-1912) +/** Saving the VM state is temporarily not allowed. Try again later. */ +#define VERR_VM_SAVE_STATE_NOT_ALLOWED (-1913) +/** An EMT called an API which cannot be called on such a thread. */ +#define VERR_VM_THREAD_IS_EMT (-1914) +/** Encountered an unexpected VM state. */ +#define VERR_VM_UNEXPECTED_VM_STATE (-1915) +/** Unexpected unstable VM state. */ +#define VERR_VM_UNEXPECTED_UNSTABLE_STATE (-1916) +/** Too many arguments passed to a VM request / request corruption. */ +#define VERR_VM_REQUEST_TOO_MANY_ARGS_IPE (-1917) +/** Fatal EMT wait error. */ +#define VERR_VM_FATAL_WAIT_ERROR (-1918) +/** The VM request was killed at VM termination. */ +#define VERR_VM_REQUEST_KILLED (-1919) +/** @} */ + + +/** @name VBox Remote Desktop Protocol (VRDP) Status Codes + * @{ + */ +/** Successful completion of operation (mapped to generic iprt status code). */ +#define VINF_VRDP_SUCCESS VINF_SUCCESS +/** VRDP transport operation timed out (mapped to generic iprt status code). */ +#define VERR_VRDP_TIMEOUT VERR_TIMEOUT + +/** Unsupported ISO protocol feature */ +#define VERR_VRDP_ISO_UNSUPPORTED (-2000) +/** Security (en/decryption) engine error */ +#define VERR_VRDP_SEC_ENGINE_FAIL (-2001) +/** VRDP protocol violation */ +#define VERR_VRDP_PROTOCOL_ERROR (-2002) +/** Unsupported VRDP protocol feature */ +#define VERR_VRDP_NOT_SUPPORTED (-2003) +/** VRDP protocol violation, client sends less data than expected */ +#define VERR_VRDP_INSUFFICIENT_DATA (-2004) +/** Internal error, VRDP packet is in wrong operation mode */ +#define VERR_VRDP_INVALID_MODE (-2005) +/** Memory allocation failed */ +#define VERR_VRDP_NO_MEMORY (-2006) +/** Client has been rejected */ +#define VERR_VRDP_ACCESS_DENIED (-2007) +/** VRPD receives a packet that is not supported */ +#define VWRN_VRDP_PDU_NOT_SUPPORTED 2008 +/** VRDP script allowed the packet to be processed further */ +#define VINF_VRDP_PROCESS_PDU 2009 +/** VRDP script has completed its task */ +#define VINF_VRDP_OPERATION_COMPLETED 2010 +/** VRDP thread has started OK and will run */ +#define VINF_VRDP_THREAD_STARTED 2011 +/** Framebuffer is resized, terminate send bitmap procedure */ +#define VINF_VRDP_RESIZE_REQUESTED 2012 +/** Output can be enabled for the client. */ +#define VINF_VRDP_OUTPUT_ENABLE 2013 +/** @} */ + + +/** @name Configuration Manager (CFGM) Status Codes + * @{ + */ +/** The integer value was too big for the requested representation. */ +#define VERR_CFGM_INTEGER_TOO_BIG (-2100) +/** Child node was not found. */ +#define VERR_CFGM_CHILD_NOT_FOUND (-2101) +/** Path to child node was invalid (i.e. empty). */ +#define VERR_CFGM_INVALID_CHILD_PATH (-2102) +/** Value not found. */ +#define VERR_CFGM_VALUE_NOT_FOUND (-2103) +/** No parent node specified. */ +#define VERR_CFGM_NO_PARENT (-2104) +/** No node was specified. */ +#define VERR_CFGM_NO_NODE (-2105) +/** The value is not an integer. */ +#define VERR_CFGM_NOT_INTEGER (-2106) +/** The value is not a zero terminated character string. */ +#define VERR_CFGM_NOT_STRING (-2107) +/** The value is not a byte string. */ +#define VERR_CFGM_NOT_BYTES (-2108) +/** The specified string / bytes buffer was to small. Specify a larger one and retry. */ +#define VERR_CFGM_NOT_ENOUGH_SPACE (-2109) +/** The value is not a zero terminated password string. */ +#define VERR_CFGM_NOT_PASSWORD (-2110) +/** The path of a new node contained slashes or was empty. */ +#define VERR_CFGM_INVALID_NODE_PATH (-2160) +/** A new node couldn't be inserted because one with the same name exists. */ +#define VERR_CFGM_NODE_EXISTS (-2161) +/** A new leaf couldn't be inserted because one with the same name exists. */ +#define VERR_CFGM_LEAF_EXISTS (-2162) +/** An unknown config value was encountered. */ +#define VERR_CFGM_CONFIG_UNKNOWN_VALUE (-2163) +/** An unknown config node (key) was encountered. */ +#define VERR_CFGM_CONFIG_UNKNOWN_NODE (-2164) +/** Internal processing error \#1 in CFGM. */ +#define VERR_CFGM_IPE_1 (-2165) +/** @} */ + + +/** @name Time Manager (TM) Status Codes + * @{ + */ +/** The loaded timer state was incorrect. */ +#define VERR_TM_LOAD_STATE (-2200) +/** The timer was not in the correct state for the request operation. */ +#define VERR_TM_INVALID_STATE (-2201) +/** The timer was in a unknown state. Corruption or stupid coding error. */ +#define VERR_TM_UNKNOWN_STATE (-2202) +/** The timer was stuck in an unstable state until we grew impatient and returned. */ +#define VERR_TM_UNSTABLE_STATE (-2203) +/** TM requires GIP. */ +#define VERR_TM_GIP_REQUIRED (-2204) +/** TM does not support the GIP version. */ +#define VERR_TM_GIP_VERSION (-2205) +/** The GIP update interval is too large. */ +#define VERR_TM_GIP_UPDATE_INTERVAL_TOO_BIG (-2206) +/** The timer has a bad clock enum value, probably corruption. */ +#define VERR_TM_TIMER_BAD_CLOCK (-2207) +/** The timer failed to reach a stable state. */ +#define VERR_TM_TIMER_UNSTABLE_STATE (-2208) +/** Attempt to resume a running TSC. */ +#define VERR_TM_TSC_ALREADY_TICKING (-2209) +/** Attempt to pause a paused TSC. */ +#define VERR_TM_TSC_ALREADY_PAUSED (-2210) +/** Invalid value for cVirtualTicking. */ +#define VERR_TM_VIRTUAL_TICKING_IPE (-2211) +/** Max timer limit reached. */ +#define VERR_TM_TOO_MANY_TIMERS (-2212) +/** Invalid timer queue number. */ +#define VERR_TM_INVALID_TIMER_QUEUE (-2213) +/** The timer queue is not longer allowed to grow. */ +#define VERR_TM_TIMER_QUEUE_CANNOT_GROW (-2214) +/** TM internal processing error \#1. */ +#define VERR_TM_IPE_1 (-2291) +/** TM internal processing error \#2. */ +#define VERR_TM_IPE_2 (-2292) +/** TM internal processing error \#3. */ +#define VERR_TM_IPE_3 (-2293) +/** TM internal processing error \#4. */ +#define VERR_TM_IPE_4 (-2294) +/** TM internal processing error \#5. */ +#define VERR_TM_IPE_5 (-2295) +/** TM internal processing error \#6. */ +#define VERR_TM_IPE_6 (-2296) +/** TM internal processing error \#7. */ +#define VERR_TM_IPE_7 (-2297) +/** TM internal processing error \#8. */ +#define VERR_TM_IPE_8 (-2298) +/** TM internal processing error \#9. */ +#define VERR_TM_IPE_9 (-2299) +/** @} */ + + +/** @name Recompiled Execution Manager (REM) Status Codes + * @{ + */ +/** Fatal error in virtual hardware. */ +#define VERR_REM_VIRTUAL_HARDWARE_ERROR (-2300) +/** Fatal error in the recompiler cpu. */ +#define VERR_REM_VIRTUAL_CPU_ERROR (-2301) +/** Recompiler execution was interrupted by forced action. */ +#define VINF_REM_INTERRUPED_FF 2302 +/** Too many similar traps. This is a very useful debug only + * check (we don't do double/triple faults in REM). */ +#define VERR_REM_TOO_MANY_TRAPS (-2304) +/** The REM is out of breakpoint slots. */ +#define VERR_REM_NO_MORE_BP_SLOTS (-2305) +/** The REM could not find any breakpoint on the specified address. */ +#define VERR_REM_BP_NOT_FOUND (-2306) +/** @} */ + + +/** @name Trap Manager / Monitor (TRPM) Status Codes + * @{ + */ +/** No active trap. Cannot query or reset a non-existing trap. */ +#define VERR_TRPM_NO_ACTIVE_TRAP (-2400) +/** Active trap. Cannot assert a new trap when one is already active. */ +#define VERR_TRPM_ACTIVE_TRAP (-2401) +/** Reason for leaving RC: Guest tried to write to our IDT - fatal. + * The VM will be terminated assuming the worst, i.e. that the + * guest has read the idtr register. */ +#define VERR_TRPM_SHADOW_IDT_WRITE (-2402) +/** Reason for leaving RC: Fatal trap in hypervisor. */ +#define VERR_TRPM_DONT_PANIC (-2403) +/** Reason for leaving RC: Double Fault. */ +#define VERR_TRPM_PANIC (-2404) +/** Bad TRPM_TRAP_IN_OP. */ +#define VERR_TRPM_BAD_TRAP_IN_OP (-2405) +/** Internal processing error \#1 in TRPM. */ +#define VERR_TRPM_IPE_1 (-2406) +/** Internal processing error \#2 in TRPM. */ +#define VERR_TRPM_IPE_2 (-2407) +/** Internal processing error \#3 in TRPM. */ +#define VERR_TRPM_IPE_3 (-2408) +/** Got into a part of TRPM that is not used when HM (VT-x/AMD-V) is enabled. */ +#define VERR_TRPM_HM_IPE (-2409) +/** @} */ + + +/** @name Selector Manager / Monitor (SELM) Status Code + * @{ + */ +/** Reason for leaving RC: Guest tried to write to our GDT - fatal. + * The VM will be terminated assuming the worst, i.e. that the + * guest has read the gdtr register. */ +#define VERR_SELM_SHADOW_GDT_WRITE (-2500) +/** Reason for leaving RC: Guest tried to write to our LDT - fatal. + * The VM will be terminated assuming the worst, i.e. that the + * guest has read the ldtr register. */ +#define VERR_SELM_SHADOW_LDT_WRITE (-2501) +/** Reason for leaving RC: Guest tried to write to our TSS - fatal. + * The VM will be terminated assuming the worst, i.e. that the + * guest has read the ltr register. */ +#define VERR_SELM_SHADOW_TSS_WRITE (-2502) +/** Reason for leaving RC: Sync the GDT table to solve a conflict. */ +#define VINF_SELM_SYNC_GDT 2503 +/** No valid TSS present. */ +#define VERR_SELM_NO_TSS (-2504) +/** Invalid guest LDT selector. */ +#define VERR_SELM_INVALID_LDT (-2505) +/** The guest LDT selector is out of bounds. */ +#define VERR_SELM_LDT_OUT_OF_BOUNDS (-2506) +/** Unknown error while reading the guest GDT during shadow table updating. */ +#define VERR_SELM_GDT_READ_ERROR (-2507) +/** The guest GDT so full that we cannot find free space for our own + * selectors. */ +#define VERR_SELM_GDT_TOO_FULL (-2508) +/** Got into a part of SELM that is not used when HM (VT-x/AMD-V) is enabled. */ +#define VERR_SELM_HM_IPE (-2509) +/** @} */ + + +/** @name I/O Manager / Monitor (IOM) Status Code + * @{ + */ +/** The specified I/O port range was invalid. + * It was either empty or it was out of bounds. */ +#define VERR_IOM_INVALID_IOPORT_RANGE (-2600) +/** The specified R0 or RC I/O port range didn't have a corresponding R3 range. + * IOMR3IOPortRegisterR3() must be called first. */ +#define VERR_IOM_NO_R3_IOPORT_RANGE (-2601) +/** The specified I/O port range intruded on an existing range. There is + * a I/O port conflict between two device, or a device tried to register + * the same range twice. */ +#define VERR_IOM_IOPORT_RANGE_CONFLICT (-2602) +/** The I/O port range specified for removal wasn't found or it wasn't contiguous. */ +#define VERR_IOM_IOPORT_RANGE_NOT_FOUND (-2603) +/** The specified I/O port range was owned by some other device(s). Both registration + * and deregistration, but in the first case only RC and R0 ranges. */ +#define VERR_IOM_NOT_IOPORT_RANGE_OWNER (-2604) + +/** The specified MMIO range was invalid. + * It was either empty or it was out of bounds. */ +#define VERR_IOM_INVALID_MMIO_RANGE (-2605) +/** The specified R0 or RC MMIO range didn't have a corresponding R3 range. + * IOMR3MMIORegisterR3() must be called first. */ +#define VERR_IOM_NO_R3_MMIO_RANGE (-2606) +/** The specified MMIO range was owned by some other device(s). Both registration + * and deregistration, but in the first case only RC and R0 ranges. */ +#define VERR_IOM_NOT_MMIO_RANGE_OWNER (-2607) +/** The specified MMIO range intruded on an existing range. There is + * a MMIO conflict between two device, or a device tried to register + * the same range twice. */ +#define VERR_IOM_MMIO_RANGE_CONFLICT (-2608) +/** The MMIO range specified for removal was not found. */ +#define VERR_IOM_MMIO_RANGE_NOT_FOUND (-2609) +/** The MMIO range specified for removal was invalid. The range didn't match + * quite match a set of existing ranges. It's not possible to remove parts of + * a MMIO range, only one or more full ranges. */ +#define VERR_IOM_INCOMPLETE_MMIO_RANGE (-2610) +/** An invalid I/O port size was specified for a read or write operation. */ +#define VERR_IOM_INVALID_IOPORT_SIZE (-2611) +/** The MMIO handler was called for a bogus address! Internal error! */ +#define VERR_IOM_MMIO_HANDLER_BOGUS_CALL (-2612) +/** The MMIO handler experienced a problem with the disassembler. */ +#define VERR_IOM_MMIO_HANDLER_DISASM_ERROR (-2613) +/** The port being read was not present(/unused) and IOM shall return ~0 according to size. */ +#define VERR_IOM_IOPORT_UNUSED (-2614) +/** Unused MMIO register read, fill with 00. */ +#define VINF_IOM_MMIO_UNUSED_00 2615 +/** Unused MMIO register read, fill with FF. */ +#define VINF_IOM_MMIO_UNUSED_FF 2616 + +/** Reason for leaving RZ: I/O port read. */ +#define VINF_IOM_R3_IOPORT_READ 2620 +/** Reason for leaving RZ: I/O port write. */ +#define VINF_IOM_R3_IOPORT_WRITE 2621 +/** Reason for leaving RZ: Pending I/O port write. Since there is also + * VMCPU_FF_IOM for this condition, it's ok to drop this status code for + * some other VINF_EM_XXX statuses. */ +#define VINF_IOM_R3_IOPORT_COMMIT_WRITE 2622 +/** Reason for leaving RZ: MMIO read. */ +#define VINF_IOM_R3_MMIO_READ 2623 +/** Reason for leaving RZ: MMIO write. */ +#define VINF_IOM_R3_MMIO_WRITE 2624 +/** Reason for leaving RZ: MMIO read/write. */ +#define VINF_IOM_R3_MMIO_READ_WRITE 2625 +/** Reason for leaving RZ: Pending MMIO write. Since there is also + * VMCPU_FF_IOM for this condition, it's ok to drop this status code for + * some other VINF_EM_XXX statuses. */ +#define VINF_IOM_R3_MMIO_COMMIT_WRITE 2626 + +/** IOMGCIOPortHandler was given an unexpected opcode. */ +#define VERR_IOM_IOPORT_UNKNOWN_OPCODE (-2630) +/** Internal processing error \#1 in the I/O port code. */ +#define VERR_IOM_IOPORT_IPE_1 (-2631) +/** Internal processing error \#2 in the I/O port code. */ +#define VERR_IOM_IOPORT_IPE_2 (-2632) +/** Internal processing error \#3 in the I/O port code. */ +#define VERR_IOM_IOPORT_IPE_3 (-2633) +/** Internal processing error \#1 in the MMIO code. */ +#define VERR_IOM_MMIO_IPE_1 (-2634) +/** Internal processing error \#2 in the MMIO code. */ +#define VERR_IOM_MMIO_IPE_2 (-2635) +/** Internal processing error \#3 in the MMIO code. */ +#define VERR_IOM_MMIO_IPE_3 (-2636) +/** Got into a part of IOM that is not used when HM (VT-x/AMD-V) is enabled. */ +#define VERR_IOM_HM_IPE (-2637) +/** Internal processing error while merging status codes. */ +#define VERR_IOM_FF_STATUS_IPE (-2638) + +/** Too many I/O port registrations. */ +#define VERR_IOM_TOO_MANY_IOPORT_REGISTRATIONS (-2650) +/** Invalid I/O port handle. */ +#define VERR_IOM_INVALID_IOPORT_HANDLE (-2651) +/** I/O ports are already mapped. */ +#define VERR_IOM_IOPORTS_ALREADY_MAPPED (-2652) +/** I/O ports are not mapped. */ +#define VERR_IOM_IOPORTS_NOT_MAPPED (-2653) + +/** Too many MMIO registrations. */ +#define VERR_IOM_TOO_MANY_MMIO_REGISTRATIONS (-2660) +/** Invalid MMIO handle. */ +#define VERR_IOM_INVALID_MMIO_HANDLE (-2661) +/** MMIO region is already mapped. */ +#define VERR_IOM_MMIO_REGION_ALREADY_MAPPED (-2662) +/** MMIO region is not mapped. */ +#define VERR_IOM_MMIO_REGION_NOT_MAPPED (-2663) +/** @} */ + + +/** @name Virtual Machine Monitor (VMM) Status Codes + * @{ + */ +/** Reason for leaving R0: Hit a ring-0 assertion on EMT. */ +#define VERR_VMM_RING0_ASSERTION (-2701) +/** The hyper CR3 differs between PGM and CPUM. */ +#define VERR_VMM_HYPER_CR3_MISMATCH (-2702) +/** Reason for leaving RZ: Illegal call to ring-3. */ +#define VERR_VMM_RING3_CALL_DISABLED (-2703) +/** The VMMR0.r0 module version does not match VBoxVMM.dll/so/dylib. + * If you just upgraded VirtualBox, please terminate all VMs and make sure + * that neither VBoxNetDHCP nor VBoxNetNAT is running. Then try again. + * If this error persists, try re-installing VirtualBox. */ +#define VERR_VMM_R0_VERSION_MISMATCH (-2704) +/** The VMMRC.rc module version does not match VBoxVMM.dll/so/dylib. + * Re-install if you are a user. Developers should make sure the build is + * complete or try with a clean build. */ +#define VERR_VMM_RC_VERSION_MISMATCH (-2705) +/** VMM long jump error. */ +#define VERR_VMM_LONG_JMP_ERROR (-2709) +/** Reason for leaving RC: Caller the tracer in ring-0. */ +#define VINF_VMM_CALL_TRACER (2712) +/** Internal processing error \#1 in the switcher code. */ +#define VERR_VMM_SWITCHER_IPE_1 (-2713) +/** Reason for leaving RZ: Unknown call to ring-3. */ +#define VINF_VMM_UNKNOWN_RING3_CALL (2714) +/** Attempted to use stub switcher. */ +#define VERR_VMM_SWITCHER_STUB (-2715) +/** HM returned in the wrong state. */ +#define VERR_VMM_WRONG_HM_VMCPU_STATE (-2716) +/** SMAP enabled, but the AC flag was found to be clear - check the kernel + * log for details. */ +#define VERR_VMM_SMAP_BUT_AC_CLEAR (-2717) +/** NEM returned in the wrong state. */ +#define VERR_VMM_WRONG_NEM_VMCPU_STATE (-2718) +/** Got back from vmmR0CallRing3SetJmp with the context hook still enabled. */ +#define VERR_VMM_CONTEXT_HOOK_STILL_ENABLED (-2719) +/** Cannot block in ring-0. */ +#define VERR_VMM_CANNOT_BLOCK (-2720) +/** @} */ + + +/** @name Pluggable Device and Driver Manager (PDM) Status Codes + * @{ + */ +/** An invalid LUN specification was given. */ +#define VERR_PDM_NO_SUCH_LUN (-2800) +/** A device encountered an unknown configuration value. + * This means that the device is potentially misconfigured and the device + * construction or unit attachment failed because of this. */ +#define VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES (-2801) +/** The above driver doesn't export a interface required by a driver being + * attached to it. Typical misconfiguration problem. */ +#define VERR_PDM_MISSING_INTERFACE_ABOVE (-2802) +/** The below driver doesn't export a interface required by the drive + * having attached it. Typical misconfiguration problem. */ +#define VERR_PDM_MISSING_INTERFACE_BELOW (-2803) +/** A device didn't find a required interface with an attached driver. + * Typical misconfiguration problem. */ +#define VERR_PDM_MISSING_INTERFACE (-2804) +/** A driver encountered an unknown configuration value. + * This means that the driver is potentially misconfigured and the driver + * construction failed because of this. */ +#define VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES (-2805) +/** The PCI bus assigned to a device didn't have room for it. + * Either too many devices are configured on the same PCI bus, or there are + * some internal problem where PDM/PCI doesn't free up slots when unplugging devices. */ +#define VERR_PDM_TOO_PCI_MANY_DEVICES (-2806) +/** A queue is out of free items, the queueing operation failed. */ +#define VERR_PDM_NO_QUEUE_ITEMS (-2807) +/** Not possible to attach further drivers to the driver. + * A driver which doesn't support attachments (below of course) will + * return this status code if it found that further drivers were configured + * to be attached to it. */ +#define VERR_PDM_DRVINS_NO_ATTACH (-2808) +/** Not possible to attach drivers to the device. + * A device which doesn't support attachments (below of course) will + * return this status code if it found that drivers were configured + * to be attached to it. */ +#define VERR_PDM_DEVINS_NO_ATTACH (-2809) +/** No attached driver. + * The PDMDRVHLP::pfnAttach and PDMDEVHLP::pfnDriverAttach will return + * this error when no driver was configured to be attached. */ +#define VERR_PDM_NO_ATTACHED_DRIVER (-2810) +/** The media geometry hasn't been set yet, so it cannot be obtained. + * The caller should then calculate the geometry from the media size. */ +#define VERR_PDM_GEOMETRY_NOT_SET (-2811) +/** The media translation hasn't been set yet, so it cannot be obtained. + * The caller should then guess the translation. */ +#define VERR_PDM_TRANSLATION_NOT_SET (-2812) +/** The media is not mounted, operation requires a mounted media. */ +#define VERR_PDM_MEDIA_NOT_MOUNTED (-2813) +/** Mount failed because a media was already mounted. Unmount the media + * and retry the mount. */ +#define VERR_PDM_MEDIA_MOUNTED (-2814) +/** The media is locked and cannot be unmounted. */ +#define VERR_PDM_MEDIA_LOCKED (-2815) +/** No 'Type' attribute in the DrvBlock configuration. + * Misconfiguration. */ +#define VERR_PDM_BLOCK_NO_TYPE (-2816) +/** The 'Type' attribute in the DrvBlock configuration had an unknown value. + * Misconfiguration. */ +#define VERR_PDM_BLOCK_UNKNOWN_TYPE (-2817) +/** The 'Translation' attribute in the DrvBlock configuration had an unknown value. + * Misconfiguration. */ +#define VERR_PDM_BLOCK_UNKNOWN_TRANSLATION (-2818) +/** The block driver type wasn't supported. + * Misconfiguration of the kind you get when attaching a floppy to an IDE controller. */ +#define VERR_PDM_UNSUPPORTED_BLOCK_TYPE (-2819) +/** A attach or prepare mount call failed because the driver already + * had a driver attached. */ +#define VERR_PDM_DRIVER_ALREADY_ATTACHED (-2820) +/** An attempt on detaching a driver without anyone actually being attached, or + * performing any other operation on an attached driver. */ +#define VERR_PDM_NO_DRIVER_ATTACHED (-2821) +/** The attached driver configuration is missing the 'Driver' attribute. */ +#define VERR_PDM_CFG_MISSING_DRIVER_NAME (-2822) +/** The configured driver wasn't found. + * Either the necessary driver modules wasn't loaded, the name was + * misspelled, or it was a misconfiguration. */ +#define VERR_PDM_DRIVER_NOT_FOUND (-2823) +/** The Ring-3 module was already loaded. */ +#define VINF_PDM_ALREADY_LOADED (2824) +/** The name of the module clashed with an existing module. */ +#define VERR_PDM_MODULE_NAME_CLASH (-2825) +/** Couldn't find any export for registration of drivers/devices. */ +#define VERR_PDM_NO_REGISTRATION_EXPORT (-2826) +/** A module name is too long. */ +#define VERR_PDM_MODULE_NAME_TOO_LONG (-2827) +/** Driver name clash. Another driver with the same name as the + * one being registered exists. */ +#define VERR_PDM_DRIVER_NAME_CLASH (-2828) +/** The version of the driver registration structure is unknown + * to this VBox version. Either mixing incompatible versions or + * the structure isn't correctly initialized. */ +#define VERR_PDM_UNKNOWN_DRVREG_VERSION (-2829) +/** Invalid entry in the driver registration structure. */ +#define VERR_PDM_INVALID_DRIVER_REGISTRATION (-2830) +/** Invalid host bit mask. */ +#define VERR_PDM_INVALID_DRIVER_HOST_BITS (-2831) +/** Not possible to detach a driver because the above driver/device + * doesn't support it. The above entity doesn't implement the pfnDetach call. */ +#define VERR_PDM_DRIVER_DETACH_NOT_POSSIBLE (-2832) +/** No PCI Bus is available to register the device with. This is usually a + * misconfiguration or in rare cases a buggy pci device. */ +#define VERR_PDM_NO_PCI_BUS (-2833) +/** The device is not a registered PCI device and thus cannot + * perform any PCI operations. The device forgot to register it self. */ +#define VERR_PDM_NOT_PCI_DEVICE (-2834) + +/** The version of the device registration structure is unknown + * to this VBox version. Either mixing incompatible versions or + * the structure isn't correctly initialized. */ +#define VERR_PDM_UNKNOWN_DEVREG_VERSION (-2835) +/** Invalid entry in the device registration structure. */ +#define VERR_PDM_INVALID_DEVICE_REGISTRATION (-2836) +/** Invalid host bit mask. */ +#define VERR_PDM_INVALID_DEVICE_GUEST_BITS (-2837) +/** The guest bit mask didn't match the guest being loaded. */ +#define VERR_PDM_INVALID_DEVICE_HOST_BITS (-2838) +/** Device name clash. Another device with the same name as the + * one being registered exists. */ +#define VERR_PDM_DEVICE_NAME_CLASH (-2839) +/** The device wasn't found. There was no registered device + * by that name. */ +#define VERR_PDM_DEVICE_NOT_FOUND (-2840) +/** The device instance was not found. */ +#define VERR_PDM_DEVICE_INSTANCE_NOT_FOUND (-2841) +/** The device instance have no base interface. */ +#define VERR_PDM_DEVICE_INSTANCE_NO_IBASE (-2842) +/** The device instance have no such logical unit. */ +#define VERR_PDM_DEVICE_INSTANCE_LUN_NOT_FOUND (-2843) +/** The driver instance could not be found. */ +#define VERR_PDM_DRIVER_INSTANCE_NOT_FOUND (-2844) +/** Logical Unit was not found. */ +#define VERR_PDM_LUN_NOT_FOUND (-2845) +/** The Logical Unit was found, but it had no driver attached to it. */ +#define VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN (-2846) +/** The Logical Unit was found, but it had no driver attached to it. */ +#define VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN 2846 +/** No PIC device instance is registered with the current VM and thus + * the PIC operation cannot be performed. */ +#define VERR_PDM_NO_PIC_INSTANCE (-2847) +/** No APIC device instance is registered with the current VM and thus + * the APIC operation cannot be performed. */ +#define VERR_PDM_NO_APIC_INSTANCE (-2848) +/** No DMAC device instance is registered with the current VM and thus + * the DMA operation cannot be performed. */ +#define VERR_PDM_NO_DMAC_INSTANCE (-2849) +/** No RTC device instance is registered with the current VM and thus + * the RTC or CMOS operation cannot be performed. */ +#define VERR_PDM_NO_RTC_INSTANCE (-2850) +/** Unable to open the host interface due to a sharing violation . */ +#define VERR_PDM_HIF_SHARING_VIOLATION (-2851) +/** Unable to open the host interface. */ +#define VERR_PDM_HIF_OPEN_FAILED (-2852) +/** The device doesn't support runtime driver attaching. + * The PDMDEVREG::pfnAttach callback function is NULL. */ +#define VERR_PDM_DEVICE_NO_RT_ATTACH (-2853) +/** The driver doesn't support runtime driver attaching. + * The PDMDRVREG::pfnAttach callback function is NULL. */ +#define VERR_PDM_DRIVER_NO_RT_ATTACH (-2854) +/** Invalid host interface version. */ +#define VERR_PDM_HIF_INVALID_VERSION (-2855) + +/** The version of the USB device registration structure is unknown + * to this VBox version. Either mixing incompatible versions or + * the structure isn't correctly initialized. */ +#define VERR_PDM_UNKNOWN_USBREG_VERSION (-2856) +/** Invalid entry in the device registration structure. */ +#define VERR_PDM_INVALID_USB_REGISTRATION (-2857) +/** Driver name clash. Another driver with the same name as the + * one being registered exists. */ +#define VERR_PDM_USB_NAME_CLASH (-2858) +/** The USB hub is already registered. */ +#define VERR_PDM_USB_HUB_EXISTS (-2859) +/** Couldn't find any USB hubs to attach the device to. */ +#define VERR_PDM_NO_USB_HUBS (-2860) +/** Couldn't find any free USB ports to attach the device to. */ +#define VERR_PDM_NO_USB_PORTS (-2861) +/** Couldn't find the USB Proxy device. Using OSE? */ +#define VERR_PDM_NO_USBPROXY (-2862) +/** The async completion template is still used. */ +#define VERR_PDM_ASYNC_TEMPLATE_BUSY (-2863) +/** The async completion task is already suspended. */ +#define VERR_PDM_ASYNC_COMPLETION_ALREADY_SUSPENDED (-2864) +/** The async completion task is not suspended. */ +#define VERR_PDM_ASYNC_COMPLETION_NOT_SUSPENDED (-2865) +/** The driver properties were invalid, and as a consequence construction + * failed. Caused my unusable media or similar problems. */ +#define VERR_PDM_DRIVER_INVALID_PROPERTIES (-2866) +/** Too many instances of a device. */ +#define VERR_PDM_TOO_MANY_DEVICE_INSTANCES (-2867) +/** Too many instances of a driver. */ +#define VERR_PDM_TOO_MANY_DRIVER_INSTANCES (-2868) +/** Too many instances of a usb device. */ +#define VERR_PDM_TOO_MANY_USB_DEVICE_INSTANCES (-2869) +/** The device instance structure version has changed. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_DEVINS_VERSION_MISMATCH (-2870) +/** The device helper structure version has changed. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_DEVHLP_VERSION_MISMATCH (-2871) +/** The USB device instance structure version has changed. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_USBINS_VERSION_MISMATCH (-2872) +/** The USB device helper structure version has changed. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_USBHLPR3_VERSION_MISMATCH (-2873) +/** The driver instance structure version has changed. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_DRVINS_VERSION_MISMATCH (-2874) +/** The driver helper structure version has changed. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_DRVHLPR3_VERSION_MISMATCH (-2875) +/** Generic device structure version mismatch. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_DEVICE_VERSION_MISMATCH (-2876) +/** Generic USB device structure version mismatch. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_USBDEV_VERSION_MISMATCH (-2877) +/** Generic driver structure version mismatch. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_DRIVER_VERSION_MISMATCH (-2878) +/** PDMVMMDevHeapR3ToGCPhys failure. */ +#define VERR_PDM_DEV_HEAP_R3_TO_GCPHYS (-2879) +/** A legacy device isn't implementing the HPET notification interface. */ +#define VERR_PDM_HPET_LEGACY_NOTIFY_MISSING (-2880) +/** Internal processing error in the critical section code. */ +#define VERR_PDM_CRITSECT_IPE (-2881) +/** The critical section being deleted was not found. */ +#define VERR_PDM_CRITSECT_NOT_FOUND (-2882) +/** A PDMThread API was called by the wrong thread. */ +#define VERR_PDM_THREAD_INVALID_CALLER (-2883) +/** Internal processing error \#1 in the PDM Thread code. */ +#define VERR_PDM_THREAD_IPE_1 (-2884) +/** Internal processing error \#2 in the PDM Thread code. */ +#define VERR_PDM_THREAD_IPE_2 (-2885) +/** Only one PCI function is supported per PDM device. */ +#define VERR_PDM_ONE_PCI_FUNCTION_PER_DEVICE (-2886) +/** Bad PCI configuration. */ +#define VERR_PDM_BAD_PCI_CONFIG (-2887) +/** Internal processing error # in the PDM device code. */ +#define VERR_PDM_DEV_IPE_1 (-2888) +/** Misconfigured driver chain transformation. */ +#define VERR_PDM_MISCONFIGURED_DRV_TRANSFORMATION (-2889) +/** The driver is already removed, not more transformations possible (at + * present). */ +#define VERR_PDM_CANNOT_TRANSFORM_REMOVED_DRIVER (-2890) +/** The PCI device isn't configured as a busmaster, physical memory access + * rejected. */ +#define VERR_PDM_NOT_PCI_BUS_MASTER (-2891) +/** Got into a part of PDM that is not used when HM (VT-x/AMD-V) is enabled. */ +#define VERR_PDM_HM_IPE (-2892) +/** The I/O request was canceled. */ +#define VERR_PDM_MEDIAEX_IOREQ_CANCELED (-2893) +/** There is not enough room to store the data. */ +#define VERR_PDM_MEDIAEX_IOBUF_OVERFLOW (-2894) +/** There is not enough data to satisfy the request. */ +#define VERR_PDM_MEDIAEX_IOBUF_UNDERRUN (-2895) +/** The I/O request ID is already existing. */ +#define VERR_PDM_MEDIAEX_IOREQID_CONFLICT (-2896) +/** The I/O request ID was not found. */ +#define VERR_PDM_MEDIAEX_IOREQID_NOT_FOUND (-2897) +/** The I/O request is in progress. */ +#define VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS 2898 +/** The I/O request is in an invalid state for this operation. */ +#define VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE (-2899) + +/** Returned by PCI config space callbacks to indicate taking default action. */ +#define VINF_PDM_PCI_DO_DEFAULT (7200) +/** Failed to abort entering a critical section in ring-0. */ +#define VERR_PDM_CRITSECT_ABORT_FAILED (-7201) +/** Too many readers on read/write critical section. */ +#define VERR_PDM_CRITSECTRW_TOO_MANY_READERS (-7202) +/** Too many writes on read/write critical section. */ +#define VERR_PDM_CRITSECTRW_TOO_MANY_WRITERS (-7203) +/** Too many write or write/read recursions on read/write critical section. */ +#define VERR_PDM_CRITSECTRW_TOO_MANY_RECURSIONS (-7204) +/** Internal error in read-write critical section. */ +#define VERR_PDM_CRITSECTRW_IPE (-7205) +/** Misaligned read/write critical section. */ +#define VERR_PDM_CRITSECTRW_MISALIGNED (-7206) +/** @} */ + + +/** @name Host-Guest Communication Manager (HGCM) Status Codes + * @{ + */ +/** Requested service does not exist. */ +#define VERR_HGCM_SERVICE_NOT_FOUND (-2900) +/** Service rejected client connection */ +#define VINF_HGCM_CLIENT_REJECTED 2901 +/** Command address is invalid. */ +#define VERR_HGCM_INVALID_CMD_ADDRESS (-2902) +/** Service will execute the command in background. */ +#define VINF_HGCM_ASYNC_EXECUTE 2903 +/** HGCM could not perform requested operation because of an internal error. */ +#define VERR_HGCM_INTERNAL (-2904) +/** Invalid HGCM client id. */ +#define VERR_HGCM_INVALID_CLIENT_ID (-2905) +/** The HGCM is saving state. */ +#define VINF_HGCM_SAVE_STATE (2906) +/** Requested service already exists. */ +#define VERR_HGCM_SERVICE_EXISTS (-2907) +/** Too many clients for the service. */ +#define VERR_HGCM_TOO_MANY_CLIENTS (-2908) +/** Too many calls to the service from a client. */ +#define VERR_HGCM_TOO_MANY_CLIENT_CALLS (-2909) +/** @} */ + + +/** @name Network Address Translation Driver (DrvNAT) Status Codes + * @{ + */ +/** Failed to convert the specified Guest IP to a binary IP address. + * Malformed input. */ +#define VERR_NAT_REDIR_GUEST_IP (-3001) +/** Failed while setting up a redirector rule. + * There probably is a conflict between the rule and some existing + * service on the computer. */ +#define VERR_NAT_REDIR_SETUP (-3002) +/** @} */ + + +/** @name HostIF Driver (DrvTUN) Status Codes + * @{ + */ +/** The Host Interface Networking init program failed. */ +#define VERR_HOSTIF_INIT_FAILED (-3100) +/** The Host Interface Networking device name is too long. */ +#define VERR_HOSTIF_DEVICE_NAME_TOO_LONG (-3101) +/** The Host Interface Networking name config IOCTL call failed. */ +#define VERR_HOSTIF_IOCTL (-3102) +/** Failed to make the Host Interface Networking handle non-blocking. */ +#define VERR_HOSTIF_BLOCKING (-3103) +/** If a Host Interface Networking filehandle was specified it's not allowed to + * have any init or term programs. */ +#define VERR_HOSTIF_FD_AND_INIT_TERM (-3104) +/** The Host Interface Networking terminate program failed. */ +#define VERR_HOSTIF_TERM_FAILED (-3105) +/** @} */ + + +/** @name VBox HDD Container (VD) Status Codes + * @{ + */ +/** Invalid image type. */ +#define VERR_VD_INVALID_TYPE (-3200) +/** Operation can't be done in current HDD container state. */ +#define VERR_VD_INVALID_STATE (-3201) +/** Configuration value not found. */ +#define VERR_VD_VALUE_NOT_FOUND (-3202) +/** Virtual HDD is not opened. */ +#define VERR_VD_NOT_OPENED (-3203) +/** Requested image is not opened. */ +#define VERR_VD_IMAGE_NOT_FOUND (-3204) +/** Image is read-only. */ +#define VERR_VD_IMAGE_READ_ONLY (-3205) +/** Geometry hasn't been set. */ +#define VERR_VD_GEOMETRY_NOT_SET (-3206) +/** No data for this block in image. */ +#define VERR_VD_BLOCK_FREE (-3207) +/** Differencing and parent images can't be used together due to UUID. */ +#define VERR_VD_UUID_MISMATCH (-3208) +/** Asynchronous I/O request finished. */ +#define VINF_VD_ASYNC_IO_FINISHED 3209 +/** Asynchronous I/O is not finished yet. */ +#define VERR_VD_ASYNC_IO_IN_PROGRESS (-3210) +/** The image is too small or too large for this format. */ +#define VERR_VD_INVALID_SIZE (-3211) +/** Configuration value is unknown. This indicates misconfiguration. */ +#define VERR_VD_UNKNOWN_CFG_VALUES (-3212) +/** Interface is unknown. This indicates misconfiguration. */ +#define VERR_VD_UNKNOWN_INTERFACE (-3213) +/** The DEK for disk encryption is missing. */ +#define VERR_VD_DEK_MISSING (-3214) +/** The provided password to decrypt the DEK was incorrect. */ +#define VERR_VD_PASSWORD_INCORRECT (-3215) +/** Generic: Invalid image file header. Use this for plugins. */ +#define VERR_VD_GEN_INVALID_HEADER (-3220) +/** VDI: Invalid image file header. */ +#define VERR_VD_VDI_INVALID_HEADER (-3230) +/** VDI: Invalid image file header: invalid signature. */ +#define VERR_VD_VDI_INVALID_SIGNATURE (-3231) +/** VDI: Invalid image file header: invalid version. */ +#define VERR_VD_VDI_UNSUPPORTED_VERSION (-3232) +/** Comment string is too long. */ +#define VERR_VD_VDI_COMMENT_TOO_LONG (-3233) +/** VMDK: Invalid image file header. */ +#define VERR_VD_VMDK_INVALID_HEADER (-3240) +/** VMDK: Invalid image file header: invalid version. */ +#define VERR_VD_VMDK_UNSUPPORTED_VERSION (-3241) +/** VMDK: Image property not found. */ +#define VERR_VD_VMDK_VALUE_NOT_FOUND (-3242) +/** VMDK: Operation can't be done in current image state. */ +#define VERR_VD_VMDK_INVALID_STATE (-3243) +/** VMDK: Format is invalid/inconsistent. */ +#define VERR_VD_VMDK_INVALID_FORMAT (-3244) +/** VMDK: Invalid write position. */ +#define VERR_VD_VMDK_INVALID_WRITE (-3245) +/** iSCSI: Invalid header, i.e. dummy for validity check. */ +#define VERR_VD_ISCSI_INVALID_HEADER (-3250) +/** iSCSI: Operation can't be done in current image state. */ +#define VERR_VD_ISCSI_INVALID_STATE (-3251) +/** iSCSI: Invalid device type (not a disk). */ +#define VERR_VD_ISCSI_INVALID_TYPE (-3252) +/** iSCSI: Initiator secret not decrypted */ +#define VERR_VD_ISCSI_SECRET_ENCRYPTED (-3253) +/** VHD: Invalid image file header. */ +#define VERR_VD_VHD_INVALID_HEADER (-3260) +/** Parallels HDD: Invalid image file header. */ +#define VERR_VD_PARALLELS_INVALID_HEADER (-3265) +/** DMG: Invalid image file header. */ +#define VERR_VD_DMG_INVALID_HEADER (-3267) +/** Raw: Invalid image file header. */ +#define VERR_VD_RAW_INVALID_HEADER (-3270) +/** Raw: Invalid image file type. */ +#define VERR_VD_RAW_INVALID_TYPE (-3271) +/** The backend needs more metadata before it can continue. */ +#define VERR_VD_NOT_ENOUGH_METADATA (-3272) +/** Halt the current I/O context until further notification from the backend. */ +#define VERR_VD_IOCTX_HALT (-3273) +/** The disk has a cache attached already. */ +#define VERR_VD_CACHE_ALREADY_EXISTS (-3274) +/** There is no cache attached to the disk. */ +#define VERR_VD_CACHE_NOT_FOUND (-3275) +/** The cache is not up to date with the image. */ +#define VERR_VD_CACHE_NOT_UP_TO_DATE (-3276) +/** The given range does not meet the required alignment. */ +#define VERR_VD_DISCARD_ALIGNMENT_NOT_MET (-3277) +/** The discard operation is not supported for this image. */ +#define VERR_VD_DISCARD_NOT_SUPPORTED (-3278) +/** The image is the correct format but is corrupted. */ +#define VERR_VD_IMAGE_CORRUPTED (-3279) +/** Repairing the image is not supported. */ +#define VERR_VD_IMAGE_REPAIR_NOT_SUPPORTED (-3280) +/** Repairing the image is not possible because the corruption is to severe. */ +#define VERR_VD_IMAGE_REPAIR_IMPOSSIBLE (-3281) +/** Reading from the image was not possible because the offset is out of the image range. + * This usually indicates that there is a minor corruption in the image meta data. */ +#define VERR_VD_READ_OUT_OF_RANGE (-3282) +/** Block read was marked as free in the image and returned as a zero block. */ +#define VINF_VD_NEW_ZEROED_BLOCK 3283 +/** Unable to parse the XML in DMG file. */ +#define VERR_VD_DMG_XML_PARSE_ERROR (-3284) +/** Unable to locate a usable DMG file within the XAR archive. */ +#define VERR_VD_DMG_NOT_FOUND_INSIDE_XAR (-3285) +/** The size of the raw image is not dividable by 512 */ +#define VERR_VD_RAW_SIZE_MODULO_512 (-3286) +/** The size of the raw image is not dividable by 2048 */ +#define VERR_VD_RAW_SIZE_MODULO_2048 (-3287) +/** The size of the raw optical image is too small (<= 32K) */ +#define VERR_VD_RAW_SIZE_OPTICAL_TOO_SMALL (-3288) +/** The size of the raw floppy image is too big (>2.88MB) */ +#define VERR_VD_RAW_SIZE_FLOPPY_TOO_BIG (-3289) +/** Reducing the size is not supported */ +#define VERR_VD_SHRINK_NOT_SUPPORTED (-3290) +/** @} */ + + +/** @name VBox Guest Library (VBGL) Status Codes + * @{ + */ +/** Library was not initialized. */ +#define VERR_VBGL_NOT_INITIALIZED (-3300) +/** Virtual address was not allocated by the library. */ +#define VERR_VBGL_INVALID_ADDR (-3301) +/** IOCtl to VBoxGuest driver failed. */ +#define VERR_VBGL_IOCTL_FAILED (-3302) +/** @} */ + + +/** @name VBox USB (VUSB) Status Codes + * @{ + */ +/** No available ports on the hub. + * This error is returned when a device is attempted created and/or attached + * to a hub which is out of ports. */ +#define VERR_VUSB_NO_PORTS (-3400) +/** The requested operation cannot be performed on a detached USB device. */ +#define VERR_VUSB_DEVICE_NOT_ATTACHED (-3401) +/** Failed to allocate memory for a URB. */ +#define VERR_VUSB_NO_URB_MEMORY (-3402) +/** General failure during URB queuing. + * This will go away when the queueing gets proper status code handling. */ +#define VERR_VUSB_FAILED_TO_QUEUE_URB (-3403) +/** Device creation failed because the USB device name was not found. */ +#define VERR_VUSB_DEVICE_NAME_NOT_FOUND (-3404) +/** Not permitted to open the USB device. + * The user doesn't have access to the device in the usbfs, check the mount options. */ +#define VERR_VUSB_USBFS_PERMISSION (-3405) +/** The requested operation cannot be performed because the device + * is currently being reset. */ +#define VERR_VUSB_DEVICE_IS_RESETTING (-3406) +/** The requested operation cannot be performed because the device + * is currently suspended. */ +#define VERR_VUSB_DEVICE_IS_SUSPENDED (-3407) +/** Not permitted to open the USB device. + * The user doesn't have access to the device node, check group memberships. */ +#define VERR_VUSB_USB_DEVICE_PERMISSION (-3408) +/** @} */ + + +/** @name VBox VGA Status Codes + * @{ + */ +/** One of the custom modes was incorrect. + * The format or bit count of the custom mode value is invalid. */ +#define VERR_VGA_INVALID_CUSTOM_MODE (-3500) +/** The display connector is resizing. */ +#define VINF_VGA_RESIZE_IN_PROGRESS (3501) +/** Unexpected PCI region change during VGA saved state loading. */ +#define VERR_VGA_UNEXPECTED_PCI_REGION_LOAD_CHANGE (-3502) +/** Unabled to locate or load the OpenGL library. */ +#define VERR_VGA_GL_LOAD_FAILURE (-3503) +/** Unabled to locate an OpenGL symbol. */ +#define VERR_VGA_GL_SYMBOL_NOT_FOUND (-3504) +/** @} */ + + +/** @name Internal Networking Status Codes + * @{ + */ +/** The networking interface to filter was not found. */ +#define VERR_INTNET_FLT_IF_NOT_FOUND (-3600) +/** The networking interface to filter was busy (used by someone). */ +#define VERR_INTNET_FLT_IF_BUSY (-3601) +/** Failed to create or connect to a networking interface filter. */ +#define VERR_INTNET_FLT_IF_FAILED (-3602) +/** The network already exists with a different trunk configuration. */ +#define VERR_INTNET_INCOMPATIBLE_TRUNK (-3603) +/** The network already exists with a different security profile (restricted / public). */ +#define VERR_INTNET_INCOMPATIBLE_FLAGS (-3604) +/** Failed to create a virtual network interface instance. */ +#define VERR_INTNET_FLT_VNIC_CREATE_FAILED (-3605) +/** Failed to retrieve a virtual network interface link ID. */ +#define VERR_INTNET_FLT_VNIC_LINK_ID_NOT_FOUND (-3606) +/** Failed to initialize a virtual network interface instance. */ +#define VERR_INTNET_FLT_VNIC_INIT_FAILED (-3607) +/** Failed to open a virtual network interface instance. */ +#define VERR_INTNET_FLT_VNIC_OPEN_FAILED (-3608) +/** Failed to retrieve underlying (lower mac) link. */ +#define VERR_INTNET_FLT_LOWER_LINK_INFO_NOT_FOUND (-3609) +/** Failed to open underlying link instance. */ +#define VERR_INTNET_FLT_LOWER_LINK_OPEN_FAILED (-3610) +/** Failed to get underlying link ID. */ +#define VERR_INTNET_FLT_LOWER_LINK_ID_NOT_FOUND (-3611) +/** @} */ + + +/** @name Support Driver Status Codes + * @{ + */ +/** The component factory was not found. */ +#define VERR_SUPDRV_COMPONENT_NOT_FOUND (-3700) +/** The component factories do not support the requested interface. */ +#define VERR_SUPDRV_INTERFACE_NOT_SUPPORTED (-3701) +/** The service module was not found. */ +#define VERR_SUPDRV_SERVICE_NOT_FOUND (-3702) +/** The host kernel is too old. */ +#define VERR_SUPDRV_KERNEL_TOO_OLD_FOR_VTX (-3703) +/** Bad VTG magic value. */ +#define VERR_SUPDRV_VTG_MAGIC (-3704) +/** Bad VTG bit count value. */ +#define VERR_SUPDRV_VTG_BITS (-3705) +/** Bad VTG header - misc. */ +#define VERR_SUPDRV_VTG_BAD_HDR_MISC (-3706) +/** Bad VTG header - offset. */ +#define VERR_SUPDRV_VTG_BAD_HDR_OFF (-3707) +/** Bad VTG header - offset. */ +#define VERR_SUPDRV_VTG_BAD_HDR_PTR (-3708) +/** Bad VTG header - to low value. */ +#define VERR_SUPDRV_VTG_BAD_HDR_TOO_FEW (-3709) +/** Bad VTG header - to high value. */ +#define VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH (-3710) +/** Bad VTG header - size value is not a multiple of the structure size. */ +#define VERR_SUPDRV_VTG_BAD_HDR_NOT_MULTIPLE (-3711) +/** Bad VTG string table offset. */ +#define VERR_SUPDRV_VTG_STRTAB_OFF (-3712) +/** Bad VTG string. */ +#define VERR_SUPDRV_VTG_BAD_STRING (-3713) +/** VTG string is too long. */ +#define VERR_SUPDRV_VTG_STRING_TOO_LONG (-3714) +/** Bad VTG attribute value. */ +#define VERR_SUPDRV_VTG_BAD_ATTR (-3715) +/** Bad VTG provider descriptor. */ +#define VERR_SUPDRV_VTG_BAD_PROVIDER (-3716) +/** Bad VTG probe descriptor. */ +#define VERR_SUPDRV_VTG_BAD_PROBE (-3717) +/** Bad VTG argument list descriptor. */ +#define VERR_SUPDRV_VTG_BAD_ARGLIST (-3718) +/** Bad VTG probe enabled data. */ +#define VERR_SUPDRV_VTG_BAD_PROBE_ENABLED (-3719) +/** Bad VTG probe location record. */ +#define VERR_SUPDRV_VTG_BAD_PROBE_LOC (-3720) +/** The VTG object for the session or image has already been registered. */ +#define VERR_SUPDRV_VTG_ALREADY_REGISTERED (-3721) +/** A driver may only register one VTG object per session. */ +#define VERR_SUPDRV_VTG_ONLY_ONCE_PER_SESSION (-3722) +/** A tracer has already been registered. */ +#define VERR_SUPDRV_TRACER_ALREADY_REGISTERED (-3723) +/** The session has no tracer associated with it. */ +#define VERR_SUPDRV_TRACER_NOT_REGISTERED (-3724) +/** The tracer has already been opened in this sesssion. */ +#define VERR_SUPDRV_TRACER_ALREADY_OPENED (-3725) +/** The tracer has not been opened. */ +#define VERR_SUPDRV_TRACER_NOT_OPENED (-3726) +/** There is no tracer present. */ +#define VERR_SUPDRV_TRACER_NOT_PRESENT (-3727) +/** The tracer is unloading. */ +#define VERR_SUPDRV_TRACER_UNLOADING (-3728) +/** Another thread in the session is talking to the tracer. */ +#define VERR_SUPDRV_TRACER_SESSION_BUSY (-3729) +/** The tracer cannot open it self in the same session. */ +#define VERR_SUPDRV_TRACER_CANNOT_OPEN_SELF (-3730) +/** Bad argument flags. */ +#define VERR_SUPDRV_TRACER_BAD_ARG_FLAGS (-3731) +/** The session has reached the max number of (user mode) providers. */ +#define VERR_SUPDRV_TRACER_TOO_MANY_PROVIDERS (-3732) +/** The tracepoint provider object is too large. */ +#define VERR_SUPDRV_TRACER_TOO_LARGE (-3733) +/** The probe location array isn't adjacent to the probe enable array. */ +#define VERR_SUPDRV_TRACER_UMOD_NOT_ADJACENT (-3734) +/** The user mode tracepoint provider has too many probe locations and + * probes. */ +#define VERR_SUPDRV_TRACER_UMOD_TOO_MANY_PROBES (-3735) +/** The user mode tracepoint provider string table is too large. */ +#define VERR_SUPDRV_TRACER_UMOD_STRTAB_TOO_BIG (-3736) +/** The user mode tracepoint provider string table offset is bad. */ +#define VERR_SUPDRV_TRACER_UMOD_STRTAB_OFF_BAD (-3737) +/** The VM process was denied access to vboxdrv because someone have managed to + * open the process or its main thread with too broad access rights. */ +#define VERR_SUPDRV_HARDENING_EVIL_HANDLE (-3738) +/** Error opening the ApiPort LPC object. */ +#define VERR_SUPDRV_APIPORT_OPEN_ERROR (-3739) +/** Error enumerating all processes in the session. */ +#define VERR_SUPDRV_SESSION_PROCESS_ENUM_ERROR (-3740) +/** The CSRSS instance associated with the client process could not be + * located. */ +#define VERR_SUPDRV_CSRSS_NOT_FOUND (-3741) +/** Type error opening the ApiPort LPC object. */ +#define VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE (-3742) +/** Failed to measure the TSC delta between two CPUs. */ +#define VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED (-3743) +/** Failed to calculate the TSC frequency. */ +#define VERR_SUPDRV_TSC_FREQ_MEASUREMENT_FAILED (-3744) +/** Failed to get the delta-adjusted TSC value. */ +#define VERR_SUPDRV_TSC_READ_FAILED (-3745) +/** Failed to measure the TSC delta between two CPUs, continue without any + * TSC-delta. */ +#define VWRN_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED 3746 +/** A TSC-delta measurement request is currently being serviced. */ +#define VERR_SUPDRV_TSC_DELTA_MEASUREMENT_BUSY (-3747) +/** The process trying to open VBoxDrv is not a budding VM process (1). */ +#define VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_1 (-3748) +/** The process trying to open VBoxDrv is not a budding VM process (2). */ +#define VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_2 (-3749) + +/** Raw-mode is unavailable courtesy of Hyper-V. */ +#define VERR_SUPDRV_NO_RAW_MODE_HYPER_V_ROOT (-7000) +/** @} */ + + +/** @name Support Library Status Codes + * @{ + */ +/** The specified path was not absolute (hardening). */ +#define VERR_SUPLIB_PATH_NOT_ABSOLUTE (-3750) +/** The specified path was not clean (hardening). */ +#define VERR_SUPLIB_PATH_NOT_CLEAN (-3751) +/** The specified path is too long (hardening). */ +#define VERR_SUPLIB_PATH_TOO_LONG (-3752) +/** The specified path is too short (hardening). */ +#define VERR_SUPLIB_PATH_TOO_SHORT (-3753) +/** The specified path has too many components (hardening). */ +#define VERR_SUPLIB_PATH_TOO_MANY_COMPONENTS (-3754) +/** The specified path is a root path (hardening). */ +#define VERR_SUPLIB_PATH_IS_ROOT (-3755) +/** Failed to enumerate directory (hardening). */ +#define VERR_SUPLIB_DIR_ENUM_FAILED (-3756) +/** Failed to stat a file/dir during enumeration (hardening). */ +#define VERR_SUPLIB_STAT_ENUM_FAILED (-3757) +/** Failed to stat a file/dir (hardening). */ +#define VERR_SUPLIB_STAT_FAILED (-3758) +/** Failed to fstat a native handle (hardening). */ +#define VERR_SUPLIB_FSTAT_FAILED (-3759) +/** Found an illegal symbolic link (hardening). */ +#define VERR_SUPLIB_SYMLINKS_ARE_NOT_PERMITTED (-3760) +/** Found something which isn't a file nor a directory (hardening). */ +#define VERR_SUPLIB_NOT_DIR_NOT_FILE (-3761) +/** The specified path is a directory and not a file (hardening). */ +#define VERR_SUPLIB_IS_DIRECTORY (-3762) +/** The specified path is a file and not a directory (hardening). */ +#define VERR_SUPLIB_IS_FILE (-3763) +/** The path is not the same object as the native handle (hardening). */ +#define VERR_SUPLIB_NOT_SAME_OBJECT (-3764) +/** The owner is not root (hardening). */ +#define VERR_SUPLIB_OWNER_NOT_ROOT (-3765) +/** The group is a non-system group and it has write access (hardening). */ +#define VERR_SUPLIB_WRITE_NON_SYS_GROUP (-3766) +/** The file or directory is world writable (hardening). */ +#define VERR_SUPLIB_WORLD_WRITABLE (-3767) +/** The argv[0] of an internal application does not match the executable image + * path (hardening). */ +#define VERR_SUPLIB_INVALID_ARGV0_INTERNAL (-3768) +/** The internal application does not reside in the correct place (hardening). */ +#define VERR_SUPLIB_INVALID_INTERNAL_APP_DIR (-3769) +/** Unable to establish trusted of VM process (0). */ +#define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0 (-3770) +/** Unable to establish trusted of VM process (1). */ +#define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1 (-3771) +/** Unable to establish trusted of VM process (2). */ +#define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2 (-3772) +/** Unable to establish trusted of VM process (3). */ +#define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_3 (-3773) +/** Unable to establish trusted of VM process (4). */ +#define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_4 (-3774) +/** Unable to establish trusted of VM process (5). */ +#define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_5 (-3775) +/** Unable to make text memory writeable (hardening). */ +#define VERR_SUPLIB_TEXT_NOT_WRITEABLE (-3776) +/** Unable to seal text memory again to protect against write access (hardening). */ +#define VERR_SUPLIB_TEXT_NOT_SEALED (-3777) +/** Unexpected instruction encountered for which there is no patch strategy + * implemented (hardening). */ +#define VERR_SUPLIB_UNEXPECTED_INSTRUCTION (-3778) +/** @} */ + + +/** @name VBox GMM Status Codes + * @{ + */ +/** Unable to allocate more pages from the host system. */ +#define VERR_GMM_OUT_OF_MEMORY (-3801) +/** Hit the global allocation limit. + * If you know there is still sufficient memory available, try raising the limit. */ +#define VERR_GMM_HIT_GLOBAL_LIMIT (-3802) +/** Hit the a VM account limit. */ +#define VERR_GMM_HIT_VM_ACCOUNT_LIMIT (-3803) +/** Attempt to free more memory than what was previously allocated. */ +#define VERR_GMM_ATTEMPT_TO_FREE_TOO_MUCH (-3804) +/** Attempted to report too many pages as deflated. */ +#define VERR_GMM_ATTEMPT_TO_DEFLATE_TOO_MUCH (-3805) +/** The page to be freed or updated was not found. */ +#define VERR_GMM_PAGE_NOT_FOUND (-3806) +/** The specified shared page was not actually private. */ +#define VERR_GMM_PAGE_NOT_PRIVATE (-3807) +/** The specified shared page was not actually shared. */ +#define VERR_GMM_PAGE_NOT_SHARED (-3808) +/** The page to be freed was already freed. */ +#define VERR_GMM_PAGE_ALREADY_FREE (-3809) +/** The page to be updated or freed was noted owned by the caller. */ +#define VERR_GMM_NOT_PAGE_OWNER (-3810) +/** The specified chunk was not found. */ +#define VERR_GMM_CHUNK_NOT_FOUND (-3811) +/** The chunk has already been mapped into the process. */ +#define VERR_GMM_CHUNK_ALREADY_MAPPED (-3812) +/** The chunk to be unmapped isn't actually mapped into the process. */ +#define VERR_GMM_CHUNK_NOT_MAPPED (-3813) +/** The chunk has been mapped too many times already (impossible). */ +#define VERR_GMM_TOO_MANY_CHUNK_MAPPINGS (-3814) +/** The reservation or reservation update was declined - too many VMs, too + * little memory, and/or too low GMM configuration. */ +#define VERR_GMM_MEMORY_RESERVATION_DECLINED (-3815) +/** A GMM sanity check failed. */ +#define VERR_GMM_IS_NOT_SANE (-3816) +/** Inserting a new chunk failed. */ +#define VERR_GMM_CHUNK_INSERT (-3817) +/** Failed to obtain the GMM instance. */ +#define VERR_GMM_INSTANCE (-3818) +/** Bad mutex semaphore flags. */ +#define VERR_GMM_MTX_FLAGS (-3819) +/** Internal processing error in the page allocator. */ +#define VERR_GMM_ALLOC_PAGES_IPE (-3820) +/** Invalid page count given to GMMR3FreePagesPerform. */ +#define VERR_GMM_ACTUAL_PAGES_IPE (-3821) +/** The shared module name is too long. */ +#define VERR_GMM_MODULE_NAME_TOO_LONG (-3822) +/** The shared module version string is too long. */ +#define VERR_GMM_MODULE_VERSION_TOO_LONG (-3823) +/** The shared module has too many regions. */ +#define VERR_GMM_TOO_MANY_REGIONS (-3824) +/** The guest has reported too many modules. */ +#define VERR_GMM_TOO_MANY_PER_VM_MODULES (-3825) +/** The guest has reported too many modules. */ +#define VERR_GMM_TOO_MANY_GLOBAL_MODULES (-3826) +/** The shared module is already registered. */ +#define VINF_GMM_SHARED_MODULE_ALREADY_REGISTERED (3827) +/** The shared module clashed address wise with a previously registered + * module. */ +#define VERR_GMM_SHARED_MODULE_ADDRESS_CLASH (-3828) +/** The shared module was not found. */ +#define VERR_GMM_SHARED_MODULE_NOT_FOUND (-3829) +/** The size of the shared module was out of range. */ +#define VERR_GMM_BAD_SHARED_MODULE_SIZE (-3830) +/** The size of the one or more regions in the shared module was out of + * range. */ +#define VERR_GMM_SHARED_MODULE_BAD_REGIONS_SIZE (-3831) +/** @} */ + + +/** @name VBox GVM Status Codes + * @{ + */ +/** The GVM is out of VM handle space. */ +#define VERR_GVM_TOO_MANY_VMS (-3900) +/** The EMT was not blocked at the time of the call. */ +#define VINF_GVM_NOT_BLOCKED 3901 +/** The EMT was not busy running guest code at the time of the call. */ +#define VINF_GVM_NOT_BUSY_IN_GC 3902 +/** RTThreadYield was called during a GVMMR0SchedPoll call. */ +#define VINF_GVM_YIELDED 3903 +/** @} */ + + +/** @name VBox VMX Status Codes + * @{ + */ +/** VMXON failed; possibly because it was already run before. */ +#define VERR_VMX_VMXON_FAILED (-4000) +/** Invalid VMCS pointer. + * (Can be OR'ed with VERR_VMX_INVALID_VMCS_FIELD.) */ +#define VERR_VMX_INVALID_VMCS_PTR (-4001) +/** Invalid VMCS index or write to read-only element. */ +#define VERR_VMX_INVALID_VMCS_FIELD (-4002) +/** Reserved for future status code that we wish to OR with + * VERR_VMX_INVALID_VMCS_PTR and VERR_VMX_INVALID_VMCS_FIELD. */ +#define VERR_VMX_RESERVED (-4003) +/** Invalid VMXON pointer. */ +#define VERR_VMX_INVALID_VMXON_PTR (-4004) +/** Unable to start VM execution. */ +#define VERR_VMX_UNABLE_TO_START_VM (-4005) +/** Unable to switch due to invalid host state. */ +#define VERR_VMX_INVALID_HOST_STATE (-4006) +/** VMX CPU extension not available in hardware. */ +#define VERR_VMX_NO_VMX (-4009) +/** CPU was incorrectly left in VMX root mode; incompatible with VirtualBox */ +#define VERR_VMX_IN_VMX_ROOT_MODE (-4011) +/** Somebody cleared X86_CR4_VMXE in the CR4 register. */ +#define VERR_VMX_X86_CR4_VMXE_CLEARED (-4012) +/** Failed to enable and lock VT-x features. */ +#define VERR_VMX_MSR_LOCKING_FAILED (-4013) +/** Unable to switch due to invalid guest state. */ +#define VERR_VMX_INVALID_GUEST_STATE (-4014) +/** Unexpected VM exit. */ +#define VERR_VMX_UNEXPECTED_EXIT (-4015) +/** Unexpected VM exception. */ +#define VERR_VMX_UNEXPECTED_EXCEPTION (-4016) +/** Unexpected interruption exit type. */ +#define VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE (-4017) +/** CPU is not in VMX root mode; unexpected when leaving VMX root mode. */ +#define VERR_VMX_NOT_IN_VMX_ROOT_MODE (-4018) +/** Undefined VM exit code. */ +#define VERR_VMX_UNDEFINED_EXIT_CODE (-4019) +/** VMPTRLD failed; possibly because of invalid VMCS launch-state. */ +#define VERR_VMX_VMPTRLD_FAILED (-4021) +/** Invalid VMCS pointer passed to VMLAUNCH/VMRESUME. */ +#define VERR_VMX_INVALID_VMCS_PTR_TO_START_VM (-4022) +/** Internal VMX processing error no 1. */ +#define VERR_VMX_IPE_1 (-4023) +/** Internal VMX processing error no 2. */ +#define VERR_VMX_IPE_2 (-4024) +/** Internal VMX processing error no 3. */ +#define VERR_VMX_IPE_3 (-4025) +/** Internal VMX processing error no 4. */ +#define VERR_VMX_IPE_4 (-4026) +/** Internal VMX processing error no 5. */ +#define VERR_VMX_IPE_5 (-4027) +/** VT-x features for all modes (SMX and non-SMX) disabled by the BIOS. */ +#define VERR_VMX_MSR_ALL_VMX_DISABLED (-4028) +/** VT-x features disabled by the BIOS. */ +#define VERR_VMX_MSR_VMX_DISABLED (-4029) +/** VT-x VMCS field cache invalid. */ +#define VERR_VMX_VMCS_FIELD_CACHE_INVALID (-4030) +/** Failed to set VMXON enable bit while enabling VT-x through the MSR. */ +#define VERR_VMX_MSR_VMX_ENABLE_FAILED (-4031) +/** Failed to enable VMXON-in-SMX bit while enabling VT-x through the MSR. */ +#define VERR_VMX_MSR_SMX_VMX_ENABLE_FAILED (-4032) +/** An operation caused a nested-guest VM-exit. */ +#define VINF_VMX_VMEXIT 4033 +/** Generic VM-entry failure. */ +#define VERR_VMX_VMENTRY_FAILED (-4033) +/** Generic VM-exit failure. */ +#define VERR_VMX_VMEXIT_FAILED (-4034) +/** The requested nested-guest VMX intercept is not active or not in + * nested-guest execution mode. */ +#define VINF_VMX_INTERCEPT_NOT_ACTIVE 4035 +/** The behavior of the instruction/operation is modified/needs modification + * in VMX non-root mode. */ +#define VINF_VMX_MODIFIES_BEHAVIOR 4036 +/** VMLAUNCH/VMRESUME succeeded, can enter nested-guest execution. */ +#define VINF_VMX_VMLAUNCH_VMRESUME 4037 +/** VT-x VMCS launch state invalid. */ +#define VERR_VMX_INVALID_VMCS_LAUNCH_STATE (-4038) +/** Precodition no 0 in hmR0VMXStartVm failed. */ +#define VERR_VMX_STARTVM_PRECOND_0 (-4039) +/** Precodition no 1 in hmR0VMXStartVm failed. */ +#define VERR_VMX_STARTVM_PRECOND_1 (-4040) +/** Precodition no 2 in hmR0VMXStartVm failed. */ +#define VERR_VMX_STARTVM_PRECOND_2 (-4041) +/** Precodition no 3 in hmR0VMXStartVm failed. */ +#define VERR_VMX_STARTVM_PRECOND_3 (-4042) +/** @} */ + + +/** @name VBox SVM Status Codes + * @{ + */ +/** Unable to start VM execution. */ +#define VERR_SVM_UNABLE_TO_START_VM (-4050) +/** AMD-V bit not set in K6_EFER MSR */ +#define VERR_SVM_ILLEGAL_EFER_MSR (-4051) +/** AMD-V CPU extension not available. */ +#define VERR_SVM_NO_SVM (-4052) +/** AMD-V CPU extension disabled (by BIOS). */ +#define VERR_SVM_DISABLED (-4053) +/** AMD-V CPU extension in-use. */ +#define VERR_SVM_IN_USE (-4054) +/** Invalid pVMCB. */ +#define VERR_SVM_INVALID_PVMCB (-4055) +/** Unexpected SVM exit. */ +#define VERR_SVM_UNEXPECTED_EXIT (-4056) +/** Unexpected SVM exception exit. */ +#define VERR_SVM_UNEXPECTED_XCPT_EXIT (-4057) +/** Unexpected SVM patch type. */ +#define VERR_SVM_UNEXPECTED_PATCH_TYPE (-4058) +/** Unable to start VM execution due to an invalid guest state. */ +#define VERR_SVM_INVALID_GUEST_STATE (-4059) +/** Unknown or unrecognized SVM exit. */ +#define VERR_SVM_UNKNOWN_EXIT (-4060) +/** Internal SVM processing error no 1. */ +#define VERR_SVM_IPE_1 (-4061) +/** Internal SVM processing error no 2. */ +#define VERR_SVM_IPE_2 (-4062) +/** Internal SVM processing error no 3. */ +#define VERR_SVM_IPE_3 (-4063) +/** Internal SVM processing error no 4. */ +#define VERR_SVM_IPE_4 (-4064) +/** Internal SVM processing error no 5. */ +#define VERR_SVM_IPE_5 (-4065) +/** The nested-guest \#VMEXIT processing failed, initiate shutdown. */ +#define VERR_SVM_VMEXIT_FAILED (-4066) +/** An operation caused a nested-guest SVM \#VMEXIT. */ +#define VINF_SVM_VMEXIT 4067 +/** VMRUN emulation succeeded, ready to immediately enter the nested-guest. */ +#define VINF_SVM_VMRUN 4068 +/** The requested nested-guest SVM intercept is not active or not in + * nested-guest execution mode. */ +#define VINF_SVM_INTERCEPT_NOT_ACTIVE 4069 +/** Precodition no 0 in hmR0SvmVmRun failed. */ +#define VERR_SVM_VMRUN_PRECOND_0 (-4070) +/** Precodition no 1 in hmR0SvmVmRun failed. */ +#define VERR_SVM_VMRUN_PRECOND_1 (-4071) +/** Precodition no 2 in hmR0SvmVmRun failed. */ +#define VERR_SVM_VMRUN_PRECOND_2 (-4072) +/** Precodition no 3 in hmR0SvmVmRun failed. */ +#define VERR_SVM_VMRUN_PRECOND_3 (-4073) +/** @} */ + + +/** @name VBox HM Status Codes + * @{ + */ +/** Host is about to go into suspend mode. */ +#define VERR_HM_SUSPEND_PENDING (-4100) +/** Conflicting CFGM values. */ +#define VERR_HM_CONFIG_MISMATCH (-4103) +/** Internal processing error in the HM init code. */ +#define VERR_HM_ALREADY_ENABLED_IPE (-4104) +/** Unexpected MSR in the auto-load/store area. */ +#define VERR_HM_UNEXPECTED_LD_ST_MSR (-4105) +/** No 32-bit to 64-bit switcher in place. */ +#define VERR_HM_NO_32_TO_64_SWITCHER (-4106) +/** HMR0Leave was called on the wrong CPU. */ +#define VERR_HM_WRONG_CPU (-4107) +/** Internal processing error \#1 in the HM code. */ +#define VERR_HM_IPE_1 (-4108) +/** Internal processing error \#2 in the HM code. */ +#define VERR_HM_IPE_2 (-4109) +/** Wrong 32/64-bit switcher. */ +#define VERR_HM_WRONG_SWITCHER (-4110) +/** Unknown I/O instruction. */ +#define VERR_HM_UNKNOWN_IO_INSTRUCTION (-4111) +/** Unsupported CPU feature combination. */ +#define VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO (-4112) +/** Internal processing error \#3 in the HM code. */ +#define VERR_HM_IPE_3 (-4113) +/** Internal processing error \#4 in the HM code. */ +#define VERR_HM_IPE_4 (-4114) +/** Internal processing error \#5 in the HM code. */ +#define VERR_HM_IPE_5 (-4115) +/** Invalid HM64ON32OP value. */ +#define VERR_HM_INVALID_HM64ON32OP (-4116) +/** Resume guest execution after injecting a double-fault. */ +#define VINF_HM_DOUBLE_FAULT 4117 +/** Pending exception; continue guest execution. */ +#define VINF_HM_PENDING_XCPT 4118 +/** @} */ + + +/** @name VBox Disassembler Status Codes + * @{ + */ +/** Invalid opcode byte(s) */ +#define VERR_DIS_INVALID_OPCODE (-4200) +/** Generic failure during disassembly. */ +#define VERR_DIS_GEN_FAILURE (-4201) +/** No read callback. */ +#define VERR_DIS_NO_READ_CALLBACK (-4202) +/** Invalid Mod/RM. */ +#define VERR_DIS_INVALID_MODRM (-4203) +/** Invalid parameter index. */ +#define VERR_DIS_INVALID_PARAMETER (-4204) +/** The instruction is too long. */ +#define VERR_DIS_TOO_LONG_INSTR (-4206) +/** @} */ + + +/** @name VBox Webservice Status Codes + * @{ + */ +/** Authentication failed (ISessionManager::logon()) */ +#define VERR_WEB_NOT_AUTHENTICATED (-4300) +/** Invalid format of managed object reference */ +#define VERR_WEB_INVALID_MANAGED_OBJECT_REFERENCE (-4301) +/** Invalid session ID in managed object reference */ +#define VERR_WEB_INVALID_SESSION_ID (-4302) +/** Invalid object ID in managed object reference */ +#define VERR_WEB_INVALID_OBJECT_ID (-4303) +/** Unsupported interface for managed object reference */ +#define VERR_WEB_UNSUPPORTED_INTERFACE (-4304) +/** @} */ + + +/** @name VBox PARAV Status Codes + * @{ + */ +/** Switch back to host */ +#define VINF_PARAV_SWITCH_TO_HOST 4400 + +/** @} */ + +/** @name VBox Video HW Acceleration command status + * @{ + */ +/** command processing is pending, a completion handler will be called */ +#define VINF_VHWA_CMD_PENDING 4500 + +/** @} */ + + +/** @name VBox COM error codes + * + * @remarks Global::vboxStatusCodeToCOM and Global::vboxStatusCodeFromCOM uses + * these for conversion that is lossless with respect to important COM + * status codes. These methods should be moved to the glue library. + * @{ */ +/** Unexpected turn of events. */ +#define VERR_COM_UNEXPECTED (-4600) +/** The base of the VirtualBox COM status codes (the lower value) + * corresponding 1:1 to VBOX_E_XXX. This is the lowest value. */ +#define VERR_COM_VBOX_LOWEST (-4699) +/** Object corresponding to the supplied arguments does not exist. */ +#define VERR_COM_OBJECT_NOT_FOUND (VERR_COM_VBOX_LOWEST + 1) +/** Current virtual machine state prevents the operation. */ +#define VERR_COM_INVALID_VM_STATE (VERR_COM_VBOX_LOWEST + 2) +/** Virtual machine error occurred attempting the operation. */ +#define VERR_COM_VM_ERROR (VERR_COM_VBOX_LOWEST + 3) +/** File not accessible or erroneous file contents. */ +#define VERR_COM_FILE_ERROR (VERR_COM_VBOX_LOWEST + 4) +/** IPRT error. */ +#define VERR_COM_IPRT_ERROR (VERR_COM_VBOX_LOWEST + 5) +/** Pluggable Device Manager error. */ +#define VERR_COM_PDM_ERROR (VERR_COM_VBOX_LOWEST + 6) +/** Current object state prohibits operation. */ +#define VERR_COM_INVALID_OBJECT_STATE (VERR_COM_VBOX_LOWEST + 7) +/** Host operating system related error. */ +#define VERR_COM_HOST_ERROR (VERR_COM_VBOX_LOWEST + 8) +/** Requested operation is not supported. */ +#define VERR_COM_NOT_SUPPORTED (VERR_COM_VBOX_LOWEST + 9) +/** Invalid XML found. */ +#define VERR_COM_XML_ERROR (VERR_COM_VBOX_LOWEST + 10) +/** Current session state prohibits operation. */ +#define VERR_COM_INVALID_SESSION_STATE (VERR_COM_VBOX_LOWEST + 11) +/** Object being in use prohibits operation. */ +#define VERR_COM_OBJECT_IN_USE (VERR_COM_VBOX_LOWEST + 12) +/** Returned by callback methods which does not need to be called + * again because the client does not actually make use of them. */ +#define VERR_COM_DONT_CALL_AGAIN (VERR_COM_VBOX_LOWEST + 13) +/** @} */ + +/** @name VBox VMMDev Status codes + * @{ + */ +/** CPU hotplug events from VMMDev are not monitored by the guest. */ +#define VERR_VMMDEV_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST (-4700) +/** @} */ + +/** @name VBox async I/O manager Status Codes + * @{ + */ +/** Async I/O task is pending, a completion handler will be called. */ +#define VINF_AIO_TASK_PENDING 4800 +/** @} */ + +/** @name VBox Virtual SCSI Status Codes + * @{ + */ +/** LUN type is not supported. */ +#define VERR_VSCSI_LUN_TYPE_NOT_SUPPORTED (-4900) +/** LUN is already/still attached to a device. */ +#define VERR_VSCSI_LUN_ATTACHED_TO_DEVICE (-4901) +/** The specified LUN is invalid. */ +#define VERR_VSCSI_LUN_INVALID (-4902) +/** The LUN is not attached to the device. */ +#define VERR_VSCSI_LUN_NOT_ATTACHED (-4903) +/** The LUN is still busy. */ +#define VERR_VSCSI_LUN_BUSY (-4904) +/** @} */ + +/** @name VBox FAM Status Codes + * @{ + */ +/** FAM failed to open a connection. */ +#define VERR_FAM_OPEN_FAILED (-5000) +/** FAM failed to add a file to the list to be monitored. */ +#define VERR_FAM_MONITOR_FILE_FAILED (-5001) +/** FAM failed to add a directory to the list to be monitored. */ +#define VERR_FAM_MONITOR_DIRECTORY_FAILED (-5002) +/** The connection to the FAM daemon was lost. */ +#define VERR_FAM_CONNECTION_LOST (-5003) +/** @} */ + + +/** @name PCI Bus & Passthrough Status Codes + * @{ + */ +/** RamPreAlloc not set. + * RAM pre-allocation is currently a requirement for PCI passthrough. */ +#define VERR_PCI_PASSTHROUGH_NO_RAM_PREALLOC (-5100) +/** VT-x/AMD-V not active. + * PCI passthrough currently works only if VT-x/AMD-V is active. */ +#define VERR_PCI_PASSTHROUGH_NO_HM (-5101) +/** Nested paging not active. + * PCI passthrough currently works only if nested paging is active. */ +#define VERR_PCI_PASSTHROUGH_NO_NESTED_PAGING (-5102) + +/** Special return code from a PCI I/O region mapping handler that tells the BUS + * that it has done the mapping already. */ +#define VINF_PCI_MAPPING_DONE 5150 +/** @} */ + + +/** @name GVMM Status Codes + * @{ + */ +/** Internal error obtaining the GVMM instance. */ +#define VERR_GVMM_INSTANCE (-5200) +/** GVMM does not support the range of CPUs present/possible on the host. */ +#define VERR_GVMM_HOST_CPU_RANGE (-5201) +/** GVMM ran into some broken IPRT code. */ +#define VERR_GVMM_BROKEN_IPRT (-5202) +/** Internal processing error \#1 in the GVMM code. */ +#define VERR_GVMM_IPE_1 (-5203) +/** Internal processing error \#2 in the GVMM code. */ +#define VERR_GVMM_IPE_2 (-5204) +/** Cannot destroy VM because not all other EMTs have deregistered. */ +#define VERR_GVMM_NOT_ALL_EMTS_DEREGISTERED (-5205) +/** @} */ + + +/** @name IEM Status Codes + * @{ */ +/** The instruction is not yet implemented by IEM. */ +#define VERR_IEM_INSTR_NOT_IMPLEMENTED (-5300) +/** Invalid operand size passed to an IEM function. */ +#define VERR_IEM_INVALID_OPERAND_SIZE (-5301) +/** Invalid address mode passed to an IEM function. */ +#define VERR_IEM_INVALID_ADDRESS_MODE (-5302) +/** Invalid effective segment register number passed to an IEM function. */ +#define VERR_IEM_INVALID_EFF_SEG (-5303) +/** Invalid instruction length passed to an IEM function. */ +#define VERR_IEM_INVALID_INSTR_LENGTH (-5304) +/** Internal status code for indicating that a selector isn't valid (LAR, LSL, + * VERR, VERW). This is not used outside the instruction implementations. */ +#define VINF_IEM_SELECTOR_NOT_OK (5305) +/** Restart the current instruction. For testing only. */ +#define VERR_IEM_RESTART_INSTRUCTION (-5389) +/** This particular aspect of the instruction is not yet implemented by IEM. */ +#define VERR_IEM_ASPECT_NOT_IMPLEMENTED (-5390) +/** Internal processing error \#1 in the IEM code. */ +#define VERR_IEM_IPE_1 (-5391) +/** Internal processing error \#2 in the IEM code. */ +#define VERR_IEM_IPE_2 (-5392) +/** Internal processing error \#3 in the IEM code. */ +#define VERR_IEM_IPE_3 (-5393) +/** Internal processing error \#4 in the IEM code. */ +#define VERR_IEM_IPE_4 (-5394) +/** Internal processing error \#5 in the IEM code. */ +#define VERR_IEM_IPE_5 (-5395) +/** Internal processing error \#6 in the IEM code. */ +#define VERR_IEM_IPE_6 (-5396) +/** Internal processing error \#7 in the IEM code. */ +#define VERR_IEM_IPE_7 (-5397) +/** Internal processing error \#8 in the IEM code. */ +#define VERR_IEM_IPE_8 (-5398) +/** Internal processing error \#9 in the IEM code. */ +#define VERR_IEM_IPE_9 (-5399) +/** @} */ + + +/** @name DBGC Status Codes + * @{ */ +/** Status that causes DBGC to quit. */ +#define VERR_DBGC_QUIT (-5400) +/** Async command pending. */ +#define VWRN_DBGC_CMD_PENDING 5401 +/** The command has already been registered. */ +#define VWRN_DBGC_ALREADY_REGISTERED 5402 +/** The command cannot be deregistered because has not been registered. */ +#define VERR_DBGC_COMMANDS_NOT_REGISTERED (-5403) +/** Unknown breakpoint. */ +#define VERR_DBGC_BP_NOT_FOUND (-5404) +/** The breakpoint already exists. */ +#define VERR_DBGC_BP_EXISTS (-5405) +/** The breakpoint has no command. */ +#define VINF_DBGC_BP_NO_COMMAND 5406 +/** Generic debugger command failure. */ +#define VERR_DBGC_COMMAND_FAILED (-5407) +/** Logic bug in the DBGC code. */ +#define VERR_DBGC_IPE (-5408) + +/** The lowest parse status code. */ +#define VERR_DBGC_PARSE_LOWEST (-5499) +/** Syntax error - too few arguments. */ +#define VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS (VERR_DBGC_PARSE_LOWEST + 0) +/** Syntax error - too many arguments. */ +#define VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS (VERR_DBGC_PARSE_LOWEST + 1) +/** Syntax error - too many arguments for static storage. */ +#define VERR_DBGC_PARSE_ARGUMENT_OVERFLOW (VERR_DBGC_PARSE_LOWEST + 2) +/** Syntax error - expected binary operator. */ +#define VERR_DBGC_PARSE_EXPECTED_BINARY_OP (VERR_DBGC_PARSE_LOWEST + 3) + +/** Syntax error - the argument does not allow a range to be specified. */ +#define VERR_DBGC_PARSE_NO_RANGE_ALLOWED (VERR_DBGC_PARSE_LOWEST + 5) +/** Syntax error - unbalanced quotes. */ +#define VERR_DBGC_PARSE_UNBALANCED_QUOTE (VERR_DBGC_PARSE_LOWEST + 6) +/** Syntax error - unbalanced parenthesis. */ +#define VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS (VERR_DBGC_PARSE_LOWEST + 7) +/** Syntax error - an argument or subargument contains nothing useful. */ +#define VERR_DBGC_PARSE_EMPTY_ARGUMENT (VERR_DBGC_PARSE_LOWEST + 8) +/** Syntax error - invalid operator usage. */ +#define VERR_DBGC_PARSE_UNEXPECTED_OPERATOR (VERR_DBGC_PARSE_LOWEST + 9) +/** Syntax error - invalid numeric value. */ +#define VERR_DBGC_PARSE_INVALID_NUMBER (VERR_DBGC_PARSE_LOWEST + 10) +/** Syntax error - numeric overflow. */ +#define VERR_DBGC_PARSE_NUMBER_TOO_BIG (VERR_DBGC_PARSE_LOWEST + 11) +/** Syntax error - invalid operation attempted. */ +#define VERR_DBGC_PARSE_INVALID_OPERATION (VERR_DBGC_PARSE_LOWEST + 12) +/** Syntax error - function not found. */ +#define VERR_DBGC_PARSE_FUNCTION_NOT_FOUND (VERR_DBGC_PARSE_LOWEST + 13) +/** Syntax error - the specified function is not a function. */ +#define VERR_DBGC_PARSE_NOT_A_FUNCTION (VERR_DBGC_PARSE_LOWEST + 14) +/** Syntax error - out of scratch memory. */ +#define VERR_DBGC_PARSE_NO_SCRATCH (VERR_DBGC_PARSE_LOWEST + 15) +/** Syntax error - out of regular heap memory. */ +#define VERR_DBGC_PARSE_NO_MEMORY (VERR_DBGC_PARSE_LOWEST + 16) +/** Syntax error - incorrect argument type. */ +#define VERR_DBGC_PARSE_INCORRECT_ARG_TYPE (VERR_DBGC_PARSE_LOWEST + 17) +/** Syntax error - an undefined variable was referenced. */ +#define VERR_DBGC_PARSE_VARIABLE_NOT_FOUND (VERR_DBGC_PARSE_LOWEST + 18) +/** Syntax error - a type conversion failed. */ +#define VERR_DBGC_PARSE_CONVERSION_FAILED (VERR_DBGC_PARSE_LOWEST + 19) +/** Syntax error - you hit a debugger feature which isn't implemented yet. + * (Feel free to help implement it.) */ +#define VERR_DBGC_PARSE_NOT_IMPLEMENTED (VERR_DBGC_PARSE_LOWEST + 20) +/** Syntax error - Couldn't satisfy a request for a specific result type. */ +#define VERR_DBGC_PARSE_BAD_RESULT_TYPE (VERR_DBGC_PARSE_LOWEST + 21) +/** Syntax error - Cannot read symbol value, it is a set-only symbol. */ +#define VERR_DBGC_PARSE_WRITEONLY_SYMBOL (VERR_DBGC_PARSE_LOWEST + 22) +/** Syntax error - Invalid command name. */ +#define VERR_DBGC_PARSE_INVALD_COMMAND_NAME (VERR_DBGC_PARSE_LOWEST + 23) +/** Syntax error - Command not found. */ +#define VERR_DBGC_PARSE_COMMAND_NOT_FOUND (VERR_DBGC_PARSE_LOWEST + 24) +/** Syntax error - buggy parser. */ +#define VERR_DBGC_PARSE_BUG (VERR_DBGC_PARSE_LOWEST + 25) +/** @} */ + + +/** @name Support driver/library shared verification status codes. + * @{ */ +/** Process Verification Failure: The memory content does not match the image + * file. */ +#define VERR_SUP_VP_MEMORY_VS_FILE_MISMATCH (-5600) +/** Process Verification Failure: The memory protection of a image file section + * does not match what the section header prescribes. */ +#define VERR_SUP_VP_SECTION_PROTECTION_MISMATCH (-5601) +/** Process Verification Failure: One of the section in the image file is not + * mapped into memory. */ +#define VERR_SUP_VP_SECTION_NOT_MAPPED (-5602) +/** Process Verification Failure: One of the section in the image file is not + * fully mapped into memory. */ +#define VERR_SUP_VP_SECTION_NOT_FULLY_MAPPED (-5603) +/** Process Verification Failure: Bad file alignment value in image header. */ +#define VERR_SUP_VP_BAD_FILE_ALIGNMENT_VALUE (-5604) +/** Process Verification Failure: Bad image base in header. */ +#define VERR_SUP_VP_BAD_IMAGE_BASE (-5605) +/** Process Verification Failure: Bad image signature. */ +#define VERR_SUP_VP_BAD_IMAGE_SIGNATURE (-5606) +/** Process Verification Failure: Bad image size. */ +#define VERR_SUP_VP_BAD_IMAGE_SIZE (-5607) +/** Process Verification Failure: Bad new-header offset in the MZ header. */ +#define VERR_SUP_VP_BAD_MZ_OFFSET (-5608) +/** Process Verification Failure: Bad optional header field. */ +#define VERR_SUP_VP_BAD_OPTIONAL_HEADER (-5609) +/** Process Verification Failure: Bad section alignment value in image + * header. */ +#define VERR_SUP_VP_BAD_SECTION_ALIGNMENT_VALUE (-5610) +/** Process Verification Failure: Bad section raw data size. */ +#define VERR_SUP_VP_BAD_SECTION_FILE_SIZE (-5611) +/** Process Verification Failure: Bad virtual section address. */ +#define VERR_SUP_VP_BAD_SECTION_RVA (-5612) +/** Process Verification Failure: Bad virtual section size. */ +#define VERR_SUP_VP_BAD_SECTION_VIRTUAL_SIZE (-5613) +/** Process Verification Failure: Bad size of image header. */ +#define VERR_SUP_VP_BAD_SIZE_OF_HEADERS (-5614) +/** Process Verification Failure: The process is being debugged. */ +#define VERR_SUP_VP_DEBUGGED (-5615) +/** Process Verification Failure: A DLL was found more than once. */ +#define VERR_SUP_VP_DUPLICATE_DLL_MAPPING (-5616) +/** Process Verification Failure: Image section region is too large. */ +#define VERR_SUP_VP_EMPTY_REGION_TOO_LARGE (-5617) +/** Process Verification Failure: Executable file name and process image name + * does not match up. */ +#define VERR_SUP_VP_EXE_VS_PROC_NAME_MISMATCH (-5618) +/** Process Verification Failure: Found executable memory allocated in the + * process. There is only supposed be executable memory associated with + * image file mappings (DLLs & EXE). */ +#define VERR_SUP_VP_FOUND_EXEC_MEMORY (-5619) +/** Process Verification Failure: There is more than one known executable mapped + * into the process. */ +#define VERR_SUP_VP_FOUND_MORE_THAN_ONE_EXE_MAPPING (-5620) +/** Process Verification Failure: Error closing image file handle. */ +#define VERR_SUP_VP_IMAGE_FILE_CLOSE_ERROR (-5621) +/** Process Verification Failure: Error opening image file. */ +#define VERR_SUP_VP_IMAGE_FILE_OPEN_ERROR (-5622) +/** Process Verification Failure: Error reading image file header. */ +#define VERR_SUP_VP_IMAGE_HDR_READ_ERROR (-5623) +/** Process Verification Failure: Image mapping is bogus as the first region + * has different AllocationBase and BaseAddress values, indicating that a + * section was unmapped or otherwise tampered with. */ +#define VERR_SUP_VP_IMAGE_MAPPING_BASE_ERROR (-5624) +/** Process Verification Failure: Error reading process memory for comparing + * with disk data. */ +#define VERR_SUP_VP_MEMORY_READ_ERROR (-5625) +/** Process Verification Failure: Found no executable mapped into the process + * address space. */ +#define VERR_SUP_VP_NO_FOUND_NO_EXE_MAPPING (-5626) +/** Process Verification Failure: An image mapping failed to report a name. */ +#define VERR_SUP_VP_NO_IMAGE_MAPPING_NAME (-5627) +/** Process Verification Failure: No KERNE32.DLL mapping found. This is + * impossible. */ +#define VERR_SUP_VP_NO_KERNEL32_MAPPING (-5628) +/** Process Verification Failure: Error allocating memory. */ +#define VERR_SUP_VP_NO_MEMORY (-5629) +/** Process Verification Failure: Error allocating state memory or querying + * the system32 path. */ +#define VERR_SUP_VP_NO_MEMORY_STATE (-5630) +/** Process Verification Failure: No NTDLL.DLL mapping found. This is + * impossible. */ +#define VERR_SUP_VP_NO_NTDLL_MAPPING (-5631) +/** Process Verification Failure: A DLL residing outside System32 was found + * in the process. */ +#define VERR_SUP_VP_NON_SYSTEM32_DLL (-5632) +/** Process Verification Failure: An unknown and unwanted DLL was found loaded + * into the process. */ +#define VERR_SUP_VP_NOT_KNOWN_DLL_OR_EXE (-5633) +/** Process Verification Failure: The name of an image file changes between + * mapping regions. */ +#define VERR_SUP_VP_NT_MAPPING_NAME_CHANGED (-5634) +/** Process Verification Failure: Error querying process name. */ +#define VERR_SUP_VP_NT_QI_PROCESS_NM_ERROR (-5635) +/** Process Verification Failure: Error querying thread information. */ +#define VERR_SUP_VP_NT_QI_THREAD_ERROR (-5636) +/** Process Verification Failure: Error query virtual memory information. */ +#define VERR_SUP_VP_NT_QI_VIRTUAL_MEMORY_ERROR (-5637) +/** Process Verification Failure: Error query virtual memory mapping name. */ +#define VERR_SUP_VP_NT_QI_VIRTUAL_MEMORY_NM_ERROR (-5638) +/** Process Verification Failure: Error determining the full path of + * System32. */ +#define VERR_SUP_VP_SYSTEM32_PATH (-5639) +/** Process Verification Failure: The process has more than one thread. */ +#define VERR_SUP_VP_THREAD_NOT_ALONE (-5640) +/** Process Verification Failure: The image mapping is too large (>= 2GB). */ +#define VERR_SUP_VP_TOO_HIGH_REGION_RVA (-5641) +/** Process Verification Failure: The memory region is too large (>= 2GB). */ +#define VERR_SUP_VP_TOO_LARGE_REGION (-5642) +/** Process Verification Failure: There are too many DLLs loaded. */ +#define VERR_SUP_VP_TOO_MANY_DLLS_LOADED (-5643) +/** Process Verification Failure: An image has too many regions. */ +#define VERR_SUP_VP_TOO_MANY_IMAGE_REGIONS (-5644) +/** Process Verification Failure: The process has too many virtual memory + * regions. */ +#define VERR_SUP_VP_TOO_MANY_MEMORY_REGIONS (-5645) +/** Process Verification Failure: An image has too many sections. */ +#define VERR_SUP_VP_TOO_MANY_SECTIONS (-5646) +/** Process Verification Failure: An image is targeting an unexpected + * machine/CPU. */ +#define VERR_SUP_VP_UNEXPECTED_IMAGE_MACHINE (-5647) +/** Process Verification Failure: Unexpected section protection flag + * combination. */ +#define VERR_SUP_VP_UNEXPECTED_SECTION_FLAGS (-5648) +/** Process Verification Failure: Expected the process and exe to have forced + * integrity checking enabled (verifying signatures). */ +#define VERR_SUP_VP_EXE_MISSING_FORCE_INTEGRITY (-5649) +/** Process Verification Failure: Expected the process and exe to have dynamic + * base enabled. */ +#define VERR_SUP_VP_EXE_MISSING_DYNAMIC_BASE (-5650) +/** Process Verification Failure: Expected the process and exe to advertise + * NX compatibility. */ +#define VERR_SUP_VP_EXE_MISSING_NX_COMPAT (-5651) +/** Process Verification Failure: The DllCharacteristics of the process + * does not match the value in the optional header in the exe file. */ +#define VERR_SUP_VP_DLL_CHARECTERISTICS_MISMATCH (-5652) +/** Process Verification Failure: The ImageCharacteristics of the process + * does not match the value in the file header in the exe file. */ +#define VERR_SUP_VP_IMAGE_CHARECTERISTICS_MISMATCH (-5653) +/** Process Verification Failure: Error querying image information. */ +#define VERR_SUP_VP_NT_QI_PROCESS_IMG_INFO_ERROR (-5654) +/** Process Verification Failure: Error querying debug port. */ +#define VERR_SUP_VP_NT_QI_PROCESS_DBG_PORT_ERROR (-5655) +/** WinVerifyTrust failed with an unexpected status code when using the + * catalog-file approach. */ +#define VERR_SUP_VP_WINTRUST_CAT_FAILURE (-5656) +/** The image is required to be signed with the same certificate as the rest + * of VirtualBox. */ +#define VERR_SUP_VP_NOT_SIGNED_WITH_BUILD_CERT (-5657) +/** Internal processing error: Not build certificate. */ +#define VERR_SUP_VP_NOT_BUILD_CERT_IPE (-5658) +/** The image requires to be signed using the kernel-code signing process. */ +#define VERR_SUP_VP_NOT_VALID_KERNEL_CODE_SIGNATURE (-5659) +/** Unexpected number of valid paths. */ +#define VERR_SUP_VP_UNEXPECTED_VALID_PATH_COUNT (-5660) +/** The image is required to force integrity checks. */ +#define VERR_SUP_VP_SIGNATURE_CHECKS_NOT_ENFORCED (-5661) +/** Process Verification Failure: Symantec Endpoint Protection must be + * disabled for the VirtualBox VM processes. + * http://www.symantec.com/connect/articles/creating-application-control-exclusions-symantec-endpoint-protection-121 */ +#define VERR_SUP_VP_SYSFER_DLL (-5662) +/** Process Purification Failure: KERNE32.DLL already mapped into the initial + * process (suspended). */ +#define VERR_SUP_VP_KERNEL32_ALREADY_MAPPED (-5663) +/** Process Purification Failure: NtFreeVirtualMemory failed on a chunk of + * executable memory which shouldn't be present in the process. */ +#define VERR_SUP_VP_FREE_VIRTUAL_MEMORY_FAILED (-5664) +/** Process Purification Failure: Both NtUnmapViewOfSetion and + * NtProtectVirtualMemory failed to get rid of or passify an non-image + * executable mapping. */ +#define VERR_SUP_VP_UNMAP_AND_PROTECT_FAILED (-5665) +/** Process Purification Failure: Unknown memory type of executable memory. */ +#define VERR_SUP_VP_UNKOWN_MEM_TYPE (-5666) +/** The image file is not owned by TrustedInstaller is it should be. */ +#define VERR_SUP_VP_NOT_OWNED_BY_TRUSTED_INSTALLER (-5667) +/** The image is outside the expected range. */ +#define VERR_SUP_VP_IMAGE_TOO_BIG (-5668) +/** Stub process not found so it cannot be revalidated when vboxdrv is opened + * by the VM process. */ +#define VERR_SUP_VP_STUB_NOT_FOUND (-5669) +/** Error opening the stub process for revalidation when vboxdrv is opened by + * the VM process. */ +#define VERR_SUP_VP_STUB_OPEN_ERROR (-5670) +/** Stub process thread not found during revalidation upon vboxdrv opening by + * the VM process. */ +#define VERR_SUP_VP_STUB_THREAD_NOT_FOUND (-5671) +/** Error opening the stub process thread for revalidation when vboxdrv is + * opened by the VM process. */ +#define VERR_SUP_VP_STUB_THREAD_OPEN_ERROR (-5672) +/** Process Purification Failure: NtAllocateVirtualMemory failed to get us + * suitable replacement memory for a chunk of executable memory that + * shouldn't be present in our process. (You will only see this message if you + * got potentially fatally buggy anti-virus software installed.) */ +#define VERR_SUP_VP_REPLACE_VIRTUAL_MEMORY_FAILED (-5673) +/** Error getting the file mode. */ +#define VERR_SUP_VP_FILE_MODE_ERROR (-5674) +/** Error creating an event semaphore for used with asynchronous reads. */ +#define VERR_SUP_VP_CREATE_READ_EVT_SEM_FAILED (-5675) +/** Undesirable module. */ +#define VERR_SUP_VP_UNDESIRABLE_MODULE (-5676) +/** NtQueryObject/Type failed. */ +#define VERR_SUP_VP_QUERY_HANDLE_TYPE (-5677) +/** NtSetInformationObject/NoInherit failed. */ +#define VERR_SUP_VP_SET_HANDLE_NOINHERIT (-5678) + +/** We are in driverless mode. */ +#define VERR_SUP_DRIVERLESS (-5699) +/** We are in driverless mode. */ +#define VINF_SUP_DRIVERLESS 5699 +/** @} */ + +/** @name VBox Extension Pack Status Codes + * @{ + */ +/** The host is not supported. Uninstall the extension pack. + * Returned by the VBOXEXTPACKREG::pfnInstalled. */ +#define VERR_EXTPACK_UNSUPPORTED_HOST_UNINSTALL (-6000) +/** The VirtualBox version is not supported by one of the extension packs. + * + * You have probably upgraded VirtualBox recently. Please upgrade the + * extension packs to versions compatible with this VirtualBox release. + */ +#define VERR_EXTPACK_VBOX_VERSION_MISMATCH (-6001) +/** @} */ + + +/** @name VBox Guest Control Status Codes + * @{ + */ +/** Guest side reported an error. */ +#define VERR_GSTCTL_GUEST_ERROR (-6200) +/** A guest control object has changed its overall status. */ +#define VWRN_GSTCTL_OBJECTSTATE_CHANGED 6220 +/** Guest process is in a wrong state. */ +#define VERR_GSTCTL_PROCESS_WRONG_STATE (-6221) +/** Maximum (context ID) sessions have been reached. */ +#define VERR_GSTCTL_MAX_CID_SESSIONS_REACHED (-6222) +/** Maximum (context ID) objects have been reached. */ +#define VERR_GSTCTL_MAX_CID_OBJECTS_REACHED (-6223) +/** Maximum (context ID object) count has been reached. */ +#define VERR_GSTCTL_MAX_CID_COUNT_REACHED (-6224) +/** Started guest process terminated with an exit code <> 0. */ +#define VERR_GSTCTL_PROCESS_EXIT_CODE (-6225) +/** @} */ + + +/** @name GIM Status Codes + * @{ + */ +/** No GIM provider is configured for this VM. */ +#define VERR_GIM_NOT_ENABLED (-6300) +/** GIM internal processing error \#1. */ +#define VERR_GIM_IPE_1 (-6301) +/** GIM internal processing error \#2. */ +#define VERR_GIM_IPE_2 (-6302) +/** GIM internal processing error \#3. */ +#define VERR_GIM_IPE_3 (-6303) +/** The GIM provider does not support any paravirtualized TSC. */ +#define VERR_GIM_PVTSC_NOT_AVAILABLE (-6304) +/** The guest has not setup use of the paravirtualized TSC. */ +#define VERR_GIM_PVTSC_NOT_ENABLED (-6305) +/** Unknown or invalid GIM provider. */ +#define VERR_GIM_INVALID_PROVIDER (-6306) +/** GIM generic operation failed. */ +#define VERR_GIM_OPERATION_FAILED (-6307) +/** The GIM provider does not support any hypercalls. */ +#define VERR_GIM_HYPERCALLS_NOT_AVAILABLE (-6308) +/** The guest has not setup use of the hypercalls. */ +#define VERR_GIM_HYPERCALLS_NOT_ENABLED (-6309) +/** The GIM device is not registered with GIM when it ought to be. */ +#define VERR_GIM_DEVICE_NOT_REGISTERED (-6310) +/** Hypercall cannot be enabled/performed due to access/permissions/CPL. */ +#define VERR_GIM_HYPERCALL_ACCESS_DENIED (-6311) +/** Failed to read to a memory region while performing a hypercall. */ +#define VERR_GIM_HYPERCALL_MEMORY_READ_FAILED (-6312) +/** Failed to write to a memory region while performing a hypercall. */ +#define VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED (-6313) +/** Generic hypercall operation failure. */ +#define VERR_GIM_HYPERCALL_FAILED (-6314) +/** No debug connection configured. */ +#define VERR_GIM_NO_DEBUG_CONNECTION (-6315) +/** Return to ring-3 to perform the hypercall there. */ +#define VINF_GIM_R3_HYPERCALL 6316 +/** Continuing hypercall at the same RIP, continue guest execution. */ +#define VINF_GIM_HYPERCALL_CONTINUING 6317 +/** Instruction that triggers the hypercall is invalid/unrecognized. */ +#define VERR_GIM_INVALID_HYPERCALL_INSTR (-6318) +/** @} */ + + +/** @name Main API Status Codes + * @{ + */ +/** The configuration constructor in main failed due to a COM error. Check + * the release log of the VM for further details. */ +#define VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR (-6400) +/** The configuration constructor in main failed due to an internal consistency + * error. Consult the release log of the VM for further details. */ +#define VERR_MAIN_CONFIG_CONSTRUCTOR_IPE (-6401) +/** @} */ + + +/** @name VBox Drag and Drop Status Codes + * @{ + */ +/** Guest side reported an error. */ +#define VERR_DND_GUEST_ERROR (-6500) +/** @} */ + + +/** @name Audio Status Codes + * @{ + */ +/** Host backend couldn't be initialized. Happen if the audio server is not + * reachable, audio hardware is not available or similar. We should use the + * NULL audio driver. */ +#define VERR_AUDIO_BACKEND_INIT_FAILED (-6600) +/** No host backend attached / available. */ +#define VERR_AUDIO_BACKEND_NOT_ATTACHED (-6601) +/** No free input streams. */ +#define VERR_AUDIO_NO_FREE_INPUT_STREAMS (-6602) +/** No free output streams. */ +#define VERR_AUDIO_NO_FREE_OUTPUT_STREAMS (-6603) +/** Pending stream disable operation in progress. */ +#define VERR_AUDIO_STREAM_PENDING_DISABLE (-6604) +/** There is more data available. + * This can happen due to a buffer wraparound of a buffer read/write operation. */ +#define VINF_AUDIO_MORE_DATA_AVAILABLE (6605) +/** Stream is not ready for requested operation. */ +#define VERR_AUDIO_STREAM_NOT_READY (-6605) +/** Stream could not be created. + * This might due to missing host (backend) drivers or a host not having the + * required hardware, or that the requested stream configuration + * is not supported by the host backend. */ +#define VERR_AUDIO_STREAM_COULD_NOT_CREATE (-6606) +/** Generic audio device enumeration error. */ +#define VERR_AUDIO_ENUMERATION_FAILED (-6607) +/** Asynchronous stream initialization still on-going. */ +#define VERR_AUDIO_STREAM_INIT_IN_PROGRESS (-6608) +/** Special PDMIHOSTAUDIO::pfnStreamCreate return value for triggering + * calling of PDMIHOSTAUDIO::pfnStreamInitAsync on a worker thread. */ +#define VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED (6609) +/** @} */ + + +/** @name APIC Status Codes + * @{ + */ +/** No pending interrupt. */ +#define VERR_APIC_INTR_NOT_PENDING (-6700) +/** Pending interrupt is masked by TPR. */ +#define VERR_APIC_INTR_MASKED_BY_TPR (-6701) +/** APIC did not accept the interrupt. */ +#define VERR_APIC_INTR_DISCARDED (-6702) +/** @} */ + +/** @name NEM Status Codes + * @{ + */ +/** NEM is not enabled. */ +#define VERR_NEM_NOT_ENABLED (-6800) +/** NEM is not available. */ +#define VERR_NEM_NOT_AVAILABLE (-6801) +/** NEM init failed. */ +#define VERR_NEM_INIT_FAILED (-6802) +/** NEM init failed because of missing kernel API (\#1). */ +#define VERR_NEM_MISSING_KERNEL_API_1 (-6803) +/** NEM can only operate from ring-3. */ +#define VERR_NEM_RING3_ONLY (-6804) +/** NEM failed to create a native VM instance. */ +#define VERR_NEM_VM_CREATE_FAILED (-6805) +/** NEM failed to map page(s) into the VM. */ +#define VERR_NEM_MAP_PAGES_FAILED (-6806) +/** NEM failed to unmap page(s) into the VM. */ +#define VERR_NEM_UNMAP_PAGES_FAILED (-6807) +/** NEM failed to get registers. */ +#define VERR_NEM_GET_REGISTERS_FAILED (-6808) +/** NEM failed to set registers. */ +#define VERR_NEM_SET_REGISTERS_FAILED (-6809) +/** Get register caller must flush the TLB (not an error). */ +#define VERR_NEM_FLUSH_TLB (-6810) +/** Get register caller must flush the TLB. */ +#define VINF_NEM_FLUSH_TLB (6810) +/** NEM failed to set TSC. */ +#define VERR_NEM_SET_TSC (-6811) +/** NEM init failed because of missing kernel API (\#2). */ +#define VERR_NEM_MISSING_KERNEL_API_2 (-6812) +/** NEM init failed because of missing kernel API (\#3). */ +#define VERR_NEM_MISSING_KERNEL_API_3 (-6813) +/** NEM init failed because of missing kernel API (\#4). */ +#define VERR_NEM_MISSING_KERNEL_API_4 (-6814) +/** NEM init failed because of missing kernel API (\#5). */ +#define VERR_NEM_MISSING_KERNEL_API_5 (-6815) +/** NEM failed to query dirty page bitmap. */ +#define VERR_NEM_QUERY_DIRTY_BITMAP_FAILED (-6816) +/** NEM is missing a require feature in the host API. */ +#define VERR_NEM_MISSING_FEATURE (-6817) + +/** NEM internal processing error \#0. */ +#define VERR_NEM_IPE_0 (-6890) +/** NEM internal processing error \#1. */ +#define VERR_NEM_IPE_1 (-6891) +/** NEM internal processing error \#2. */ +#define VERR_NEM_IPE_2 (-6892) +/** NEM internal processing error \#3. */ +#define VERR_NEM_IPE_3 (-6893) +/** NEM internal processing error \#4. */ +#define VERR_NEM_IPE_4 (-6894) +/** NEM internal processing error \#5. */ +#define VERR_NEM_IPE_5 (-6895) +/** NEM internal processing error \#6. */ +#define VERR_NEM_IPE_6 (-6896) +/** NEM internal processing error \#7. */ +#define VERR_NEM_IPE_7 (-6897) +/** NEM internal processing error \#8. */ +#define VERR_NEM_IPE_8 (-6898) +/** NEM internal processing error \#9. */ +#define VERR_NEM_IPE_9 (-6899) +/** @} */ + +/** @name Recording Status Codes + * @{ + */ +/** Codec was not found. */ +#define VERR_RECORDING_CODEC_NOT_FOUND (-6900) +/** Codec initialization failed. */ +#define VERR_RECORDING_CODEC_INIT_FAILED (-6902) +/** Codec is not supported. */ +#define VERR_RECORDING_CODEC_NOT_SUPPORTED (-6903) +/** Format not supported by the codec. */ +#define VERR_RECORDING_FORMAT_NOT_SUPPORTED (-6904) +/** Recording is not possible due to a set restriction. */ +#define VERR_RECORDING_RESTRICTED (-6905) +/** Recording limit (time, size, ...) has been reached. */ +#define VINF_RECORDING_LIMIT_REACHED (6906) +/** Recording limit (time, size, ...) has been reached. */ +#define VERR_RECORDING_LIMIT_REACHED (-6906) +/** Recording has been throttled due to current settings. + * This e.g. can happen when submitting more video frames than + * the current FPS setting allows. */ +#define VINF_RECORDING_THROTTLED (6907) +/** Recording has been throttled due to current settings. + * This e.g. can happen when submitting more video frames than + * the current FPS setting allows. */ +#define VERR_RECORDING_THROTTLED (-6907) +/** Encoding data failed. */ +#define VERR_RECORDING_ENCODING_FAILED (-6908) +/** @} */ + +/** @name Shared Clipboard Status Codes + * @{ + */ +/** Maximum of concurrent clipboard transfers has been reached. */ +#define VERR_SHCLPB_MAX_TRANSFERS_REACHED (-7100) +/** Maximum number of Shared Clipboard objects has been reached. */ +#define VERR_SHCLPB_MAX_OBJECTS_REACHED (-7101) +/** Maximum number of Shared Clipboard lists has been reached. */ +#define VERR_SHCLPB_MAX_LISTS_REACHED (-7102) +/** A Shared Clipboard list handle is invalid. */ +#define VERR_SHCLPB_LIST_HANDLE_INVALID (-7103) +/** A Shared Clipboard objects handle is invalid. */ +#define VERR_SHCLPB_OBJ_HANDLE_INVALID (-7104) +/** Shared Clipboard event ID not found. */ +#define VERR_SHCLPB_EVENT_ID_NOT_FOUND (-7105) +/** Maximum number of Shared Clipboard events for an event source has been reached. */ +#define VERR_SHCLPB_MAX_EVENTS_REACHED (-7106) +/** Shared Clipboard transfer ID not found. */ +#define VERR_SHCLPB_TRANSFER_ID_NOT_FOUND (-7150) +/** @} */ + +/** @name Virtual IOMMU Status Codes + * @{ + */ +/** Failed to read the device table entry from guest memory. */ +#define VERR_IOMMU_DTE_READ_FAILED (-7300) +/** Failed to read the device table entry due to an invalid offset. */ +#define VERR_IOMMU_DTE_BAD_OFFSET (-7301) +/** Address translation failed. */ +#define VERR_IOMMU_ADDR_TRANSLATION_FAILED (-7302) +/** Access denied for the address. */ +#define VERR_IOMMU_ADDR_ACCESS_DENIED (-7303) +/** Remapping failed for the interrupt. */ +#define VERR_IOMMU_INTR_REMAP_FAILED (-7304) +/** Remapping denied for the interrupt (might have caused a PCI target abort). */ +#define VERR_IOMMU_INTR_REMAP_DENIED (-7305) +/** Command not supported. */ +#define VERR_IOMMU_CMD_NOT_SUPPORTED (-7306) +/** Command format (or reserved bits) invalid. */ +#define VERR_IOMMU_CMD_INVALID_FORMAT (-7307) +/** Command hardware failure. */ +#define VERR_IOMMU_CMD_HW_ERROR (-7308) +/** IOMMU device is not present. */ +#define VERR_IOMMU_NOT_PRESENT (-7309) +/** IOMMU instance cannot call itself (for remapping interrupts or translating + * addresses). */ +#define VERR_IOMMU_CANNOT_CALL_SELF (-7310) +/** Address translation disabled (but permission bits apply). */ +#define VINF_IOMMU_ADDR_TRANSLATION_DISABLED 7311 + +/** IOMMU Internal processing error \#0. */ +#define VERR_IOMMU_IPE_0 (-7390) +/** IOMMU Internal processing error \#1. */ +#define VERR_IOMMU_IPE_1 (-7391) +/** IOMMU Internal processing error \#2. */ +#define VERR_IOMMU_IPE_2 (-7392) +/** IOMMU Internal processing error \#3. */ +#define VERR_IOMMU_IPE_3 (-7393) +/** IOMMU Internal processing error \#4. */ +#define VERR_IOMMU_IPE_4 (-7394) +/** IOMMU Internal processing error \#5. */ +#define VERR_IOMMU_IPE_5 (-7395) +/** IOMMU Internal processing error \#6. */ +#define VERR_IOMMU_IPE_6 (-7396) +/** IOMMU Internal processing error \#7. */ +#define VERR_IOMMU_IPE_7 (-7397) +/** IOMMU Internal processing error \#8. */ +#define VERR_IOMMU_IPE_8 (-7398) +/** IOMMU Internal processing error \#9. */ +#define VERR_IOMMU_IPE_9 (-7399) +/** @} */ + +/* SED-END */ + +/** @} */ + + +#endif /* !VBOX_INCLUDED_err_h */ + diff --git a/include/VBox/err.mac b/include/VBox/err.mac new file mode 100644 index 00000000..14f39cb1 --- /dev/null +++ b/include/VBox/err.mac @@ -0,0 +1,1230 @@ +;; @file +; VirtualBox Status Codes. +; +; Automatically generated by err.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%define VERR_NO_VM_MEMORY (-1000) +%define VERR_DONT_PANIC (-1001) +%define VERR_UNSUPPORTED_CPU (-1002) +%define VERR_UNSUPPORTED_CPU_MODE (-1003) +%define VERR_PAGE_NOT_PRESENT (-1004) +%define VERR_CFG_INVALID_FORMAT (-1005) +%define VERR_CFG_NO_VALUE (-1006) +%define VERR_SELECTOR_NOT_PRESENT (-1007) +%define VERR_NOT_CODE_SELECTOR (-1008) +%define VERR_NOT_DATA_SELECTOR (-1009) +%define VERR_OUT_OF_SELECTOR_BOUNDS (-1010) +%define VERR_INVALID_SELECTOR (-1011) +%define VERR_INVALID_RPL (-1012) +%define VERR_PAGE_MAP_LEVEL4_NOT_PRESENT (-1013) +%define VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT (-1014) +%define VERR_RAW_MODE_INVALID_SMP (-1015) +%define VERR_INVALID_VM_HANDLE (-1016) +%define VERR_INVALID_VMCPU_HANDLE (-1017) +%define VERR_INVALID_CPU_ID (-1018) +%define VERR_TOO_MANY_CPUS (-1019) +%define VERR_SERVICE_DISABLED (-1020) +%define VERR_NOT_SUP_IN_RAW_MODE (-1021) +%define VERR_INVALID_CPU_INDEX (-1022) +%define VERR_RAW_MODE_NOT_SUPPORTED (-1023) +%define VERR_INCONSISTENT_VM_HANDLE (-1024) +%define VERR_VM_RESTORED (-1025) +%define VERR_NOT_SUP_BY_NEM (-1026) +%define VINF_EM_FIRST 1100 +%define VINF_EM_TERMINATE 1100 +%define VINF_EM_DBG_HYPER_STEPPED 1101 +%define VINF_EM_DBG_HYPER_BREAKPOINT 1102 +%define VINF_EM_DBG_HYPER_ASSERTION 1103 +%define VINF_EM_DBG_EVENT 1104 +%define VINF_EM_DBG_STOP 1105 +%define VINF_EM_DBG_STEPPED 1106 +%define VINF_EM_DBG_BREAKPOINT 1107 +%define VINF_EM_DBG_STEP 1108 +%define VINF_EM_OFF 1109 +%define VINF_EM_SUSPEND 1110 +%define VINF_EM_RESET 1111 +%define VINF_EM_HALT 1112 +%define VINF_EM_RESUME 1113 +%define VINF_EM_NO_MEMORY 1114 +%define VERR_EM_NO_MEMORY (-1114) +%define VINF_EM_RESCHEDULE_REM 1115 +%define VINF_EM_RESCHEDULE_HM 1116 +%define VINF_EM_RESCHEDULE_RAW 1117 +%define VINF_EM_RESCHEDULE 1118 +%define VINF_EM_RESCHEDULE_PARAV 1119 +%define VINF_EM_WAIT_SIPI 1120 +%define VINF_EM_LAST 1120 +%define VINF_EM_RAW_GUEST_TRAP 1121 +%define VINF_EM_RAW_INTERRUPT 1122 +%define VINF_EM_RAW_INTERRUPT_HYPER 1123 +%define VINF_EM_RAW_RING_SWITCH 1124 +%define VINF_EM_RAW_RING_SWITCH_INT 1125 +%define VINF_EM_RAW_EXCEPTION_PRIVILEGED 1126 +%define VINF_EM_RAW_EMULATE_INSTR 1127 +%define VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT 1128 +%define VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT 1129 +%define VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT 1130 +%define VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT 1131 +%define VERR_EM_RAW_PATCH_CONFLICT (-1133) +%define VINF_EM_RAW_TO_R3 1135 +%define VINF_EM_RAW_TIMER_PENDING 1136 +%define VINF_EM_RAW_INTERRUPT_PENDING 1137 +%define VINF_EM_RAW_STALE_SELECTOR 1138 +%define VINF_EM_RAW_IRET_TRAP 1139 +%define VERR_EM_INTERPRETER (-1148) +%define VERR_EM_INTERNAL_ERROR (-1149) +%define VINF_EM_PENDING_REQUEST 1150 +%define VINF_EM_RAW_EMULATE_DBG_STEP 1151 +%define VINF_EM_HM_PATCH_TPR_INSTR 1152 +%define VERR_EM_UNEXPECTED_MAPPING_CONFLICT (-1154) +%define VINF_EM_TRIPLE_FAULT 1155 +%define VERR_EM_CANNOT_EXEC_GUEST (-1156) +%define VINF_EM_RAW_INJECT_TRPM_EVENT 1157 +%define VERR_EM_GUEST_CPU_HANG (-1158) +%define VINF_EM_PENDING_R3_IOPORT_READ 1159 +%define VINF_EM_PENDING_R3_IOPORT_WRITE 1160 +%define VINF_EM_RESUME_R3_HISTORY_EXEC 1161 +%define VINF_EM_EMULATE_SPLIT_LOCK 1162 +%define VERR_DBGF_NOT_ATTACHED (-1200) +%define VERR_DBGF_ALREADY_ATTACHED (-1201) +%define VWRN_DBGF_ALREADY_HALTED 1202 +%define VERR_DBGF_NO_MORE_BP_SLOTS (-1203) +%define VERR_DBGF_BP_NOT_FOUND (-1204) +%define VINF_DBGF_BP_ALREADY_ENABLED 1205 +%define VINF_DBGF_BP_ALREADY_DISABLED 1206 +%define VINF_DBGF_BP_ALREADY_EXIST 1207 +%define VERR_DBGF_MEM_NOT_FOUND (-1208) +%define VERR_DBGF_OS_NOT_DETCTED (-1209) +%define VINF_DBGF_OS_NOT_DETCTED 1209 +%define VERR_DBGF_REGISTER_NOT_FOUND (-1210) +%define VINF_DBGF_TRUNCATED_REGISTER 1211 +%define VINF_DBGF_ZERO_EXTENDED_REGISTER 1212 +%define VERR_DBGF_UNSUPPORTED_CAST (-1213) +%define VERR_DBGF_READ_ONLY_REGISTER (-1214) +%define VERR_DBGF_REG_IPE_1 (-1215) +%define VERR_DBGF_REG_IPE_2 (-1216) +%define VERR_DBGF_HYPER_DB_XCPT (-1217) +%define VERR_DBGF_STACK_IPE_1 (-1218) +%define VERR_DBGF_STACK_IPE_2 (-1219) +%define VERR_DBGF_NO_TRACE_BUFFER (-1220) +%define VERR_DBGF_TRACER_IPE_1 (-1221) +%define VWRN_DBGF_ALREADY_RUNNING (-1222) +%define VERR_DBGF_IPE_1 (-1223) +%define VINF_DBGF_BP_HALT (1224) +%define VERR_DBGF_OWNER_BUSY (-1225) +%define VERR_DBGF_BP_INT3_ADD_TRIES_REACHED (-1226) +%define VERR_DBGF_BP_IPE_1 (-1227) +%define VERR_DBGF_BP_IPE_2 (-1228) +%define VERR_DBGF_BP_IPE_3 (-1229) +%define VERR_DBGF_BP_IPE_4 (-1230) +%define VERR_DBGF_BP_IPE_5 (-1231) +%define VERR_DBGF_BP_IPE_6 (-1232) +%define VERR_DBGF_BP_IPE_7 (-1233) +%define VERR_DBGF_BP_IPE_8 (-1234) +%define VERR_DBGF_BP_IPE_9 (-1235) +%define VERR_DBGF_BP_L1_LOOKUP_FAILED (-1236) +%define VERR_DBGF_BP_L2_LOOKUP_FAILED (-1237) +%define VERR_DBGF_BP_OWNER_NO_MORE_HANDLES (-1238) +%define VINF_DBGF_R3_BP_OWNER_DEFER 1239 +%define VERR_DBGF_BP_OWNER_CALLBACK_WRONG_STATUS (-1240) +%define VERR_DBGF_CANCELLED (-1241) +%define VWRN_CONTINUE_ANALYSIS 1400 +%define VWRN_CONTINUE_RECOMPILE VWRN_CONTINUE_ANALYSIS +%define VWRN_PATM_CONTINUE_SEARCH VWRN_CONTINUE_ANALYSIS +%define VERR_PATCHING_REFUSED (-1401) +%define VERR_PATCH_NOT_FOUND (-1402) +%define VERR_PATCH_DISABLED (-1403) +%define VWRN_PATCH_ENABLED 1404 +%define VERR_PATCH_ALREADY_DISABLED (-1405) +%define VERR_PATCH_ALREADY_ENABLED (-1406) +%define VWRN_PATCH_REMOVED 1407 +%define VINF_PATM_PATCH_TRAP_GP 1408 +%define VINF_PATM_LEAVE_RC_FIRST VINF_PATM_PATCH_TRAP_GP +%define VINF_PATM_PATCH_TRAP_PF 1409 +%define VINF_PATM_PATCH_INT3 1410 +%define VINF_PATM_CHECK_PATCH_PAGE 1411 +%define VINF_PATM_DUPLICATE_FUNCTION 1412 +%define VINF_PATCH_EMULATE_INSTR 1413 +%define VINF_PATM_HC_MMIO_PATCH_WRITE 1414 +%define VINF_PATM_HC_MMIO_PATCH_READ 1415 +%define VINF_PATM_PENDING_IRQ_AFTER_IRET 1416 +%define VINF_PATM_LEAVE_RC_LAST VINF_PATM_PENDING_IRQ_AFTER_IRET +%define VERR_PATCH_NO_CONFLICT (-1425) +%define VERR_PATM_UNSAFE_CODE (-1426) +%define VWRN_PATCH_END_BRANCH 1427 +%define VERR_PATM_ALREADY_PATCHED (-1428) +%define VINF_PATM_SPINLOCK_FAILED (1429) +%define VINF_PATCH_CONTINUE (1430) +%define VERR_PATM_HM_IPE (-1431) +%define VERR_PATM_IPE_TRAP_IN_PATCH_CODE (-1432) +%define VWRN_CSAM_TRAP_NOT_HANDLED 1500 +%define VWRN_CSAM_INSTRUCTION_PATCHED 1501 +%define VWRN_CSAM_PAGE_NOT_FOUND 1502 +%define VINF_CSAM_PENDING_ACTION 1503 +%define VERR_CSAM_HM_IPE (-1504) +%define VERR_PGM_MAPPING_CONFLICT (-1600) +%define VERR_PGM_HANDLER_PHYSICAL_NO_RAM_RANGE (-1601) +%define VERR_PGM_HANDLER_VIRTUAL_CONFLICT (-1602) +%define VERR_PGM_HANDLER_PHYSICAL_CONFLICT (-1603) +%define VERR_PGM_INVALID_PAGE_DIRECTORY (-1604) +%define VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS (-1605) +%define VERR_PGM_INVALID_GC_PHYSICAL_RANGE (-1606) +%define VERR_PGM_HANDLER_NOT_FOUND (-1607) +%define VERR_PGM_RAM_CONFLICT (-1608) +%define VERR_PGM_MAPPINGS_FIXED (-1609) +%define VERR_PGM_MAPPINGS_FIX_CONFLICT (-1610) +%define VERR_PGM_MAPPINGS_FIX_REJECTED (-1611) +%define VERR_PGM_MAPPINGS_FIX_TOO_SMALL (-1612) +%define VINF_PGM_SYNC_CR3 1613 +%define VINF_PGM_NO_DIRTY_BIT_TRACKING 1614 +%define VINF_PGM_HANDLED_DIRTY_BIT_FAULT 1615 +%define VINF_PGM_HANDLER_DO_DEFAULT 1616 +%define VERR_PGM_UNSUPPORTED_HOST_PAGING_MODE (-1617) +%define VERR_PGM_PHYS_PAGE_RESERVED (-1618) +%define VERR_PGM_NO_HYPERVISOR_ADDRESS (-1619) +%define VINF_PGM_CACHED_PAGE 1622 +%define VINF_PGM_GCPHYS_ALIASED 1623 +%define VINF_PGM_SYNCPAGE_MODIFIED_PDE 1625 +%define VERR_PGM_GCPHYS_RANGE_CROSSES_BOUNDARY (-1626) +%define VERR_PGM_INTERMEDIATE_PAGING_CONFLICT (-1627) +%define VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE (-1628) +%define VERR_PGM_DYNMAP_FAILED (-1629) +%define VERR_PGM_DYNMAP_FULL_SET (-1630) +%define VERR_PGM_DYNMAP_SETUP_ERROR (-1631) +%define VERR_PGM_DYNMAP_EXPAND_ERROR (-1632) +%define VERR_PGM_PHYS_TLB_UNASSIGNED (-1633) +%define VERR_PGM_PHYS_TLB_CATCH_ALL (-1634) +%define VINF_PGM_PHYS_TLB_CATCH_WRITE 1635 +%define VERR_PGM_PHYS_TLB_CATCH_WRITE (-1635) +%define VERR_PGM_NO_CR3_SHADOW_ROOT (-1636) +%define VERR_PGM_PHYS_INVALID_PAGE_ID (-1637) +%define VERR_PGM_PHYS_WR_HIT_HANDLER (-1638) +%define VERR_PGM_PHYS_NOT_RAM (-1639) +%define VERR_PGM_PHYS_NOT_ROM (-1640) +%define VERR_PGM_PHYS_NOT_MMIO (-1641) +%define VERR_PGM_PHYS_NOT_MMIO2 (-1642) +%define VERR_PGM_HANDLER_ALREADY_ALIASED (-1643) +%define VINF_PGM_HANDLER_ALREADY_ALIASED (1643) +%define VINF_PGM_POOL_FLUSH_PENDING (1644) +%define VERR_PGM_INVALID_LARGE_PAGE_RANGE (-1645) +%define VERR_PGM_PHYS_PAGE_BALLOONED (-1646) +%define VERR_PGM_HANDLER_IPE_1 (-1647) +%define VERR_PGM_MAP_MMIO2_ALIAS_MMIO (-1651) +%define VERR_PGM_MAPPINGS_DISABLED (-1652) +%define VERR_PGM_MAPPINGS_SMP (-1653) +%define VERR_PGM_INVALID_SAVED_PAGE_STATE (-1654) +%define VERR_PGM_LOAD_UNEXPECTED_PAGE_TYPE (-1655) +%define VERR_PGM_UNEXPECTED_PAGE_STATE (-1656) +%define VERR_PGM_SAVED_MMIO2_RANGE_NOT_FOUND (-1657) +%define VERR_PGM_SAVED_MMIO2_PAGE_NOT_FOUND (-1658) +%define VERR_PGM_SAVED_ROM_RANGE_NOT_FOUND (-1659) +%define VERR_PGM_SAVED_ROM_PAGE_NOT_FOUND (-1660) +%define VERR_PGM_SAVED_ROM_PAGE_PROT (-1661) +%define VERR_PGM_SAVED_REC_TYPE (-1662) +%define VERR_PGM_DYNMAP_IPE (-1663) +%define VERR_PGM_HANDY_PAGE_IPE (-1664) +%define VERR_PGM_PML4_MAPPING (-1665) +%define VERR_PGM_POOL_GET_PAGE_FAILED (-1666) +%define VERR_PGM_NOT_USED_IN_MODE (-1667) +%define VERR_PGM_INVALID_CR3_ADDR (-1668) +%define VERR_PGM_INVALID_PDPE_ADDR (-1669) +%define VERR_PGM_PHYS_HANDLER_IPE (-1670) +%define VERR_PGM_PHYS_PAGE_MAP_IPE_1 (-1671) +%define VERR_PGM_PHYS_PAGE_MAP_IPE_2 (-1672) +%define VERR_PGM_PHYS_PAGE_MAP_IPE_3 (-1673) +%define VERR_PGM_PHYS_PAGE_MAP_IPE_4 (-1674) +%define VERR_PGM_POOL_TOO_MANY_LOOPS (-1675) +%define VERR_PGM_MAPPING_IPE (-1676) +%define VERR_PGM_POOL_MAXED_OUT_ALREADY (-1677) +%define VERR_PGM_POOL_IPE (-1678) +%define VERR_PGM_WRITE_MONITOR_ENGAGED (-1679) +%define VERR_PGM_PHYS_PAGE_GET_IPE (-1680) +%define VERR_PGM_PHYS_NULL_PAGE_PARAM (-1681) +%define VERR_PGM_PCI_PASSTHRU_MISCONFIG (-1682) +%define VERR_PGM_TOO_MANY_MMIO2_RANGES (-1683) +%define VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE (-1684) +%define VERR_PGM_PHYS_MMIO_EX_IPE (-1685) +%define VERR_PGM_MODE_IPE (-1686) +%define VERR_PGM_SHW_NONE_IPE (-1687) +%define VERR_PGM_PAE_PDPE_RSVD (-1688) +%define VERR_PGM_NOT_SUPPORTED_FOR_NEM_MODE (-1689) +%define VERR_MM_RAM_CONFLICT (-1700) +%define VERR_MM_HYPER_NO_MEMORY (-1701) +%define VERR_MM_BAD_TRAP_TYPE_IPE (-1702) +%define VERR_CPUM_RAISE_GP_0 (-1750) +%define VERR_CPUM_INCOMPATIBLE_CONFIG (-1751) +%define VERR_CPUM_HIDDEN_CS_LOAD_ERROR (-1752) +%define VERR_CPUM_TOO_MANY_CPUID_SUBLEAVES (-1753) +%define VERR_CPUM_IPE_1 (-1754) +%define VERR_CPUM_IPE_2 (-1755) +%define VERR_CPUM_DB_CPU_NOT_FOUND (-1756) +%define VERR_CPUM_MSR_BAD_CPUMCPU_OFFSET (-1757) +%define VINF_CPUM_R3_MSR_READ (1758) +%define VINF_CPUM_R3_MSR_WRITE (1759) +%define VERR_TOO_MANY_CPUID_LEAVES (-1760) +%define VERR_CPUM_INVALID_CONFIG_VALUE (-1761) +%define VERR_CPUM_INCOMPATIBLE_XSAVE_COMP_MASK (-1762) +%define VERR_CPUM_INVALID_XSAVE_COMP_MASK (-1763) +%define VERR_CPUM_INVALID_XSAVE_HDR (-1764) +%define VERR_CPUM_INVALID_XCR0 (-1765) +%define VINF_CPUM_HOST_CR0_MODIFIED (1766) +%define VERR_CPUM_INVALID_HWVIRT_CONFIG (-1767) +%define VERR_CPUM_INVALID_HWVIRT_FEAT_COMBO (-1768) +%define VERR_SSM_UNIT_EXISTS (-1800) +%define VERR_SSM_UNIT_NOT_FOUND (-1801) +%define VERR_SSM_UNIT_NOT_OWNER (-1802) +%define VERR_SSM_INTEGRITY (-1810) +%define VERR_SSM_INTEGRITY_MAGIC (-1811) +%define VERR_SSM_INTEGRITY_VERSION (-1812) +%define VERR_SSM_INTEGRITY_SIZE (-1813) +%define VERR_SSM_INTEGRITY_CRC (-1814) +%define VERR_SMM_INTEGRITY_MACHINE (-1815) +%define VERR_SSM_INTEGRITY_HEADER (-1816) +%define VERR_SSM_INTEGRITY_UNIT (-1817) +%define VERR_SSM_INTEGRITY_UNIT_MAGIC (-1818) +%define VERR_SSM_INTEGRITY_UNIT_NOT_FOUND (-1819) +%define VERR_SSM_INTEGRITY_VBOX_VERSION (-1820) +%define VERR_SSM_INTEGRITY_FOOTER (-1821) +%define VERR_SSM_INTEGRITY_REC_HDR (-1822) +%define VERR_SSM_INTEGRITY_REC_TERM (-1823) +%define VERR_SSM_INTEGRITY_REC_TERM_CRC (-1824) +%define VERR_SSM_INTEGRITY_DECOMPRESSION (-1825) +%define VERR_SSM_INTEGRITY_DIR (-1826) +%define VERR_SSM_INTEGRITY_DIR_MAGIC (-1827) +%define VERR_SSM_NO_LOAD_EXEC (-1830) +%define VERR_SSM_LOADED_TOO_MUCH (-1831) +%define VERR_SSM_INVALID_STATE (-1832) +%define VERR_SSM_LOADED_TOO_LITTLE (-1833) +%define VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION (-1840) +%define VERR_SSM_DATA_UNIT_FORMAT_CHANGED (-1841) +%define VERR_SSM_LOAD_CPUID_MISMATCH (-1842) +%define VERR_SSM_LOAD_MEMORY_SIZE_MISMATCH (-1843) +%define VERR_SSM_LOAD_CONFIG_MISMATCH (-1844) +%define VERR_SSM_VIRTUAL_CLOCK_HZ (-1845) +%define VERR_SSM_IDE_ASYNC_TIMEOUT (-1846) +%define VERR_SSM_STRUCTURE_MAGIC (-1847) +%define VERR_SSM_UNEXPECTED_DATA (-1848) +%define VERR_SSM_GCPHYS_OVERFLOW (-1849) +%define VERR_SSM_GCPTR_OVERFLOW (-1850) +%define VINF_SSM_VOTE_FOR_ANOTHER_PASS 1851 +%define VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN 1852 +%define VERR_SSM_VOTE_FOR_GIVING_UP (-1853) +%define VINF_SSM_DONT_CALL_AGAIN 1854 +%define VERR_SSM_TOO_MANY_PASSES (-1855) +%define VERR_SSM_STATE_GREW_TOO_BIG (-1856) +%define VERR_SSM_LOW_ON_DISK_SPACE (-1857) +%define VERR_SSM_CANCELLED (-1858) +%define VERR_SSM_NO_PENDING_OPERATION (-1859) +%define VERR_SSM_ALREADY_CANCELLED (-1860) +%define VERR_SSM_LIVE_POWERED_OFF (-1861) +%define VERR_SSM_LIVE_GURU_MEDITATION (-1862) +%define VERR_SSM_LIVE_FATAL_ERROR (-1863) +%define VINF_SSM_LIVE_SUSPENDED 1864 +%define VERR_SSM_FIELD_COMPLEX (-1864) +%define VERR_SSM_FIELD_INVALID_SIZE (-1865) +%define VERR_SSM_FIELD_OUT_OF_BOUNDS (-1866) +%define VERR_SSM_FIELD_NOT_CONSECUTIVE (-1867) +%define VERR_SSM_FIELD_INVALID_CALLBACK (-1868) +%define VERR_SSM_FIELD_INVALID_PADDING_SIZE (-1869) +%define VERR_SSM_FIELD_INVALID_VALUE (-1870) +%define VERR_SSM_STREAM_ERROR (-1871) +%define VERR_SSM_UNEXPECTED_PASS (-1872) +%define VERR_SSM_SKIP_BACKWARDS (-1873) +%define VERR_SSM_MEM_TOO_BIG (-1874) +%define VERR_SSM_BAD_REC_TYPE (-1875) +%define VERR_SSM_IPE_1 (-1876) +%define VERR_SSM_IPE_2 (-1877) +%define VERR_SSM_IPE_3 (-1878) +%define VERR_SSM_FIELD_LOAD_ONLY_TRANSFORMATION (-1879) +%define VERR_VM_ATRESET_NOT_FOUND (-1900) +%define VERR_VM_REQUEST_INVALID_TYPE (-1901) +%define VERR_VM_REQUEST_STATE (-1902) +%define VERR_VM_REQUEST_INVALID_PACKAGE (-1903) +%define VERR_VM_REQUEST_STATUS_STILL_PENDING (-1904) +%define VERR_VM_REQUEST_STATUS_FREED (-1905) +%define VERR_VM_THREAD_NOT_EMT (-1906) +%define VERR_VM_INVALID_VM_STATE (-1907) +%define VERR_VM_DRIVER_NOT_INSTALLED (-1908) +%define VERR_VM_DRIVER_NOT_ACCESSIBLE (-1909) +%define VERR_VM_DRIVER_LOAD_ERROR (-1910) +%define VERR_VM_DRIVER_OPEN_ERROR (-1911) +%define VERR_VM_DRIVER_VERSION_MISMATCH (-1912) +%define VERR_VM_SAVE_STATE_NOT_ALLOWED (-1913) +%define VERR_VM_THREAD_IS_EMT (-1914) +%define VERR_VM_UNEXPECTED_VM_STATE (-1915) +%define VERR_VM_UNEXPECTED_UNSTABLE_STATE (-1916) +%define VERR_VM_REQUEST_TOO_MANY_ARGS_IPE (-1917) +%define VERR_VM_FATAL_WAIT_ERROR (-1918) +%define VERR_VM_REQUEST_KILLED (-1919) +%define VINF_VRDP_SUCCESS VINF_SUCCESS +%define VERR_VRDP_TIMEOUT VERR_TIMEOUT +%define VERR_VRDP_ISO_UNSUPPORTED (-2000) +%define VERR_VRDP_SEC_ENGINE_FAIL (-2001) +%define VERR_VRDP_PROTOCOL_ERROR (-2002) +%define VERR_VRDP_NOT_SUPPORTED (-2003) +%define VERR_VRDP_INSUFFICIENT_DATA (-2004) +%define VERR_VRDP_INVALID_MODE (-2005) +%define VERR_VRDP_NO_MEMORY (-2006) +%define VERR_VRDP_ACCESS_DENIED (-2007) +%define VWRN_VRDP_PDU_NOT_SUPPORTED 2008 +%define VINF_VRDP_PROCESS_PDU 2009 +%define VINF_VRDP_OPERATION_COMPLETED 2010 +%define VINF_VRDP_THREAD_STARTED 2011 +%define VINF_VRDP_RESIZE_REQUESTED 2012 +%define VINF_VRDP_OUTPUT_ENABLE 2013 +%define VERR_CFGM_INTEGER_TOO_BIG (-2100) +%define VERR_CFGM_CHILD_NOT_FOUND (-2101) +%define VERR_CFGM_INVALID_CHILD_PATH (-2102) +%define VERR_CFGM_VALUE_NOT_FOUND (-2103) +%define VERR_CFGM_NO_PARENT (-2104) +%define VERR_CFGM_NO_NODE (-2105) +%define VERR_CFGM_NOT_INTEGER (-2106) +%define VERR_CFGM_NOT_STRING (-2107) +%define VERR_CFGM_NOT_BYTES (-2108) +%define VERR_CFGM_NOT_ENOUGH_SPACE (-2109) +%define VERR_CFGM_NOT_PASSWORD (-2110) +%define VERR_CFGM_INVALID_NODE_PATH (-2160) +%define VERR_CFGM_NODE_EXISTS (-2161) +%define VERR_CFGM_LEAF_EXISTS (-2162) +%define VERR_CFGM_CONFIG_UNKNOWN_VALUE (-2163) +%define VERR_CFGM_CONFIG_UNKNOWN_NODE (-2164) +%define VERR_CFGM_IPE_1 (-2165) +%define VERR_TM_LOAD_STATE (-2200) +%define VERR_TM_INVALID_STATE (-2201) +%define VERR_TM_UNKNOWN_STATE (-2202) +%define VERR_TM_UNSTABLE_STATE (-2203) +%define VERR_TM_GIP_REQUIRED (-2204) +%define VERR_TM_GIP_VERSION (-2205) +%define VERR_TM_GIP_UPDATE_INTERVAL_TOO_BIG (-2206) +%define VERR_TM_TIMER_BAD_CLOCK (-2207) +%define VERR_TM_TIMER_UNSTABLE_STATE (-2208) +%define VERR_TM_TSC_ALREADY_TICKING (-2209) +%define VERR_TM_TSC_ALREADY_PAUSED (-2210) +%define VERR_TM_VIRTUAL_TICKING_IPE (-2211) +%define VERR_TM_TOO_MANY_TIMERS (-2212) +%define VERR_TM_INVALID_TIMER_QUEUE (-2213) +%define VERR_TM_TIMER_QUEUE_CANNOT_GROW (-2214) +%define VERR_TM_IPE_1 (-2291) +%define VERR_TM_IPE_2 (-2292) +%define VERR_TM_IPE_3 (-2293) +%define VERR_TM_IPE_4 (-2294) +%define VERR_TM_IPE_5 (-2295) +%define VERR_TM_IPE_6 (-2296) +%define VERR_TM_IPE_7 (-2297) +%define VERR_TM_IPE_8 (-2298) +%define VERR_TM_IPE_9 (-2299) +%define VERR_REM_VIRTUAL_HARDWARE_ERROR (-2300) +%define VERR_REM_VIRTUAL_CPU_ERROR (-2301) +%define VINF_REM_INTERRUPED_FF 2302 +%define VERR_REM_TOO_MANY_TRAPS (-2304) +%define VERR_REM_NO_MORE_BP_SLOTS (-2305) +%define VERR_REM_BP_NOT_FOUND (-2306) +%define VERR_TRPM_NO_ACTIVE_TRAP (-2400) +%define VERR_TRPM_ACTIVE_TRAP (-2401) +%define VERR_TRPM_SHADOW_IDT_WRITE (-2402) +%define VERR_TRPM_DONT_PANIC (-2403) +%define VERR_TRPM_PANIC (-2404) +%define VERR_TRPM_BAD_TRAP_IN_OP (-2405) +%define VERR_TRPM_IPE_1 (-2406) +%define VERR_TRPM_IPE_2 (-2407) +%define VERR_TRPM_IPE_3 (-2408) +%define VERR_TRPM_HM_IPE (-2409) +%define VERR_SELM_SHADOW_GDT_WRITE (-2500) +%define VERR_SELM_SHADOW_LDT_WRITE (-2501) +%define VERR_SELM_SHADOW_TSS_WRITE (-2502) +%define VINF_SELM_SYNC_GDT 2503 +%define VERR_SELM_NO_TSS (-2504) +%define VERR_SELM_INVALID_LDT (-2505) +%define VERR_SELM_LDT_OUT_OF_BOUNDS (-2506) +%define VERR_SELM_GDT_READ_ERROR (-2507) +%define VERR_SELM_GDT_TOO_FULL (-2508) +%define VERR_SELM_HM_IPE (-2509) +%define VERR_IOM_INVALID_IOPORT_RANGE (-2600) +%define VERR_IOM_NO_R3_IOPORT_RANGE (-2601) +%define VERR_IOM_IOPORT_RANGE_CONFLICT (-2602) +%define VERR_IOM_IOPORT_RANGE_NOT_FOUND (-2603) +%define VERR_IOM_NOT_IOPORT_RANGE_OWNER (-2604) +%define VERR_IOM_INVALID_MMIO_RANGE (-2605) +%define VERR_IOM_NO_R3_MMIO_RANGE (-2606) +%define VERR_IOM_NOT_MMIO_RANGE_OWNER (-2607) +%define VERR_IOM_MMIO_RANGE_CONFLICT (-2608) +%define VERR_IOM_MMIO_RANGE_NOT_FOUND (-2609) +%define VERR_IOM_INCOMPLETE_MMIO_RANGE (-2610) +%define VERR_IOM_INVALID_IOPORT_SIZE (-2611) +%define VERR_IOM_MMIO_HANDLER_BOGUS_CALL (-2612) +%define VERR_IOM_MMIO_HANDLER_DISASM_ERROR (-2613) +%define VERR_IOM_IOPORT_UNUSED (-2614) +%define VINF_IOM_MMIO_UNUSED_00 2615 +%define VINF_IOM_MMIO_UNUSED_FF 2616 +%define VINF_IOM_R3_IOPORT_READ 2620 +%define VINF_IOM_R3_IOPORT_WRITE 2621 +%define VINF_IOM_R3_IOPORT_COMMIT_WRITE 2622 +%define VINF_IOM_R3_MMIO_READ 2623 +%define VINF_IOM_R3_MMIO_WRITE 2624 +%define VINF_IOM_R3_MMIO_READ_WRITE 2625 +%define VINF_IOM_R3_MMIO_COMMIT_WRITE 2626 +%define VERR_IOM_IOPORT_UNKNOWN_OPCODE (-2630) +%define VERR_IOM_IOPORT_IPE_1 (-2631) +%define VERR_IOM_IOPORT_IPE_2 (-2632) +%define VERR_IOM_IOPORT_IPE_3 (-2633) +%define VERR_IOM_MMIO_IPE_1 (-2634) +%define VERR_IOM_MMIO_IPE_2 (-2635) +%define VERR_IOM_MMIO_IPE_3 (-2636) +%define VERR_IOM_HM_IPE (-2637) +%define VERR_IOM_FF_STATUS_IPE (-2638) +%define VERR_IOM_TOO_MANY_IOPORT_REGISTRATIONS (-2650) +%define VERR_IOM_INVALID_IOPORT_HANDLE (-2651) +%define VERR_IOM_IOPORTS_ALREADY_MAPPED (-2652) +%define VERR_IOM_IOPORTS_NOT_MAPPED (-2653) +%define VERR_IOM_TOO_MANY_MMIO_REGISTRATIONS (-2660) +%define VERR_IOM_INVALID_MMIO_HANDLE (-2661) +%define VERR_IOM_MMIO_REGION_ALREADY_MAPPED (-2662) +%define VERR_IOM_MMIO_REGION_NOT_MAPPED (-2663) +%define VERR_VMM_RING0_ASSERTION (-2701) +%define VERR_VMM_HYPER_CR3_MISMATCH (-2702) +%define VERR_VMM_RING3_CALL_DISABLED (-2703) +%define VERR_VMM_R0_VERSION_MISMATCH (-2704) +%define VERR_VMM_RC_VERSION_MISMATCH (-2705) +%define VERR_VMM_LONG_JMP_ERROR (-2709) +%define VINF_VMM_CALL_TRACER (2712) +%define VERR_VMM_SWITCHER_IPE_1 (-2713) +%define VINF_VMM_UNKNOWN_RING3_CALL (2714) +%define VERR_VMM_SWITCHER_STUB (-2715) +%define VERR_VMM_WRONG_HM_VMCPU_STATE (-2716) +%define VERR_VMM_SMAP_BUT_AC_CLEAR (-2717) +%define VERR_VMM_WRONG_NEM_VMCPU_STATE (-2718) +%define VERR_VMM_CONTEXT_HOOK_STILL_ENABLED (-2719) +%define VERR_VMM_CANNOT_BLOCK (-2720) +%define VERR_PDM_NO_SUCH_LUN (-2800) +%define VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES (-2801) +%define VERR_PDM_MISSING_INTERFACE_ABOVE (-2802) +%define VERR_PDM_MISSING_INTERFACE_BELOW (-2803) +%define VERR_PDM_MISSING_INTERFACE (-2804) +%define VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES (-2805) +%define VERR_PDM_TOO_PCI_MANY_DEVICES (-2806) +%define VERR_PDM_NO_QUEUE_ITEMS (-2807) +%define VERR_PDM_DRVINS_NO_ATTACH (-2808) +%define VERR_PDM_DEVINS_NO_ATTACH (-2809) +%define VERR_PDM_NO_ATTACHED_DRIVER (-2810) +%define VERR_PDM_GEOMETRY_NOT_SET (-2811) +%define VERR_PDM_TRANSLATION_NOT_SET (-2812) +%define VERR_PDM_MEDIA_NOT_MOUNTED (-2813) +%define VERR_PDM_MEDIA_MOUNTED (-2814) +%define VERR_PDM_MEDIA_LOCKED (-2815) +%define VERR_PDM_BLOCK_NO_TYPE (-2816) +%define VERR_PDM_BLOCK_UNKNOWN_TYPE (-2817) +%define VERR_PDM_BLOCK_UNKNOWN_TRANSLATION (-2818) +%define VERR_PDM_UNSUPPORTED_BLOCK_TYPE (-2819) +%define VERR_PDM_DRIVER_ALREADY_ATTACHED (-2820) +%define VERR_PDM_NO_DRIVER_ATTACHED (-2821) +%define VERR_PDM_CFG_MISSING_DRIVER_NAME (-2822) +%define VERR_PDM_DRIVER_NOT_FOUND (-2823) +%define VINF_PDM_ALREADY_LOADED (2824) +%define VERR_PDM_MODULE_NAME_CLASH (-2825) +%define VERR_PDM_NO_REGISTRATION_EXPORT (-2826) +%define VERR_PDM_MODULE_NAME_TOO_LONG (-2827) +%define VERR_PDM_DRIVER_NAME_CLASH (-2828) +%define VERR_PDM_UNKNOWN_DRVREG_VERSION (-2829) +%define VERR_PDM_INVALID_DRIVER_REGISTRATION (-2830) +%define VERR_PDM_INVALID_DRIVER_HOST_BITS (-2831) +%define VERR_PDM_DRIVER_DETACH_NOT_POSSIBLE (-2832) +%define VERR_PDM_NO_PCI_BUS (-2833) +%define VERR_PDM_NOT_PCI_DEVICE (-2834) +%define VERR_PDM_UNKNOWN_DEVREG_VERSION (-2835) +%define VERR_PDM_INVALID_DEVICE_REGISTRATION (-2836) +%define VERR_PDM_INVALID_DEVICE_GUEST_BITS (-2837) +%define VERR_PDM_INVALID_DEVICE_HOST_BITS (-2838) +%define VERR_PDM_DEVICE_NAME_CLASH (-2839) +%define VERR_PDM_DEVICE_NOT_FOUND (-2840) +%define VERR_PDM_DEVICE_INSTANCE_NOT_FOUND (-2841) +%define VERR_PDM_DEVICE_INSTANCE_NO_IBASE (-2842) +%define VERR_PDM_DEVICE_INSTANCE_LUN_NOT_FOUND (-2843) +%define VERR_PDM_DRIVER_INSTANCE_NOT_FOUND (-2844) +%define VERR_PDM_LUN_NOT_FOUND (-2845) +%define VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN (-2846) +%define VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN 2846 +%define VERR_PDM_NO_PIC_INSTANCE (-2847) +%define VERR_PDM_NO_APIC_INSTANCE (-2848) +%define VERR_PDM_NO_DMAC_INSTANCE (-2849) +%define VERR_PDM_NO_RTC_INSTANCE (-2850) +%define VERR_PDM_HIF_SHARING_VIOLATION (-2851) +%define VERR_PDM_HIF_OPEN_FAILED (-2852) +%define VERR_PDM_DEVICE_NO_RT_ATTACH (-2853) +%define VERR_PDM_DRIVER_NO_RT_ATTACH (-2854) +%define VERR_PDM_HIF_INVALID_VERSION (-2855) +%define VERR_PDM_UNKNOWN_USBREG_VERSION (-2856) +%define VERR_PDM_INVALID_USB_REGISTRATION (-2857) +%define VERR_PDM_USB_NAME_CLASH (-2858) +%define VERR_PDM_USB_HUB_EXISTS (-2859) +%define VERR_PDM_NO_USB_HUBS (-2860) +%define VERR_PDM_NO_USB_PORTS (-2861) +%define VERR_PDM_NO_USBPROXY (-2862) +%define VERR_PDM_ASYNC_TEMPLATE_BUSY (-2863) +%define VERR_PDM_ASYNC_COMPLETION_ALREADY_SUSPENDED (-2864) +%define VERR_PDM_ASYNC_COMPLETION_NOT_SUSPENDED (-2865) +%define VERR_PDM_DRIVER_INVALID_PROPERTIES (-2866) +%define VERR_PDM_TOO_MANY_DEVICE_INSTANCES (-2867) +%define VERR_PDM_TOO_MANY_DRIVER_INSTANCES (-2868) +%define VERR_PDM_TOO_MANY_USB_DEVICE_INSTANCES (-2869) +%define VERR_PDM_DEVINS_VERSION_MISMATCH (-2870) +%define VERR_PDM_DEVHLP_VERSION_MISMATCH (-2871) +%define VERR_PDM_USBINS_VERSION_MISMATCH (-2872) +%define VERR_PDM_USBHLPR3_VERSION_MISMATCH (-2873) +%define VERR_PDM_DRVINS_VERSION_MISMATCH (-2874) +%define VERR_PDM_DRVHLPR3_VERSION_MISMATCH (-2875) +%define VERR_PDM_DEVICE_VERSION_MISMATCH (-2876) +%define VERR_PDM_USBDEV_VERSION_MISMATCH (-2877) +%define VERR_PDM_DRIVER_VERSION_MISMATCH (-2878) +%define VERR_PDM_DEV_HEAP_R3_TO_GCPHYS (-2879) +%define VERR_PDM_HPET_LEGACY_NOTIFY_MISSING (-2880) +%define VERR_PDM_CRITSECT_IPE (-2881) +%define VERR_PDM_CRITSECT_NOT_FOUND (-2882) +%define VERR_PDM_THREAD_INVALID_CALLER (-2883) +%define VERR_PDM_THREAD_IPE_1 (-2884) +%define VERR_PDM_THREAD_IPE_2 (-2885) +%define VERR_PDM_ONE_PCI_FUNCTION_PER_DEVICE (-2886) +%define VERR_PDM_BAD_PCI_CONFIG (-2887) +%define VERR_PDM_DEV_IPE_1 (-2888) +%define VERR_PDM_MISCONFIGURED_DRV_TRANSFORMATION (-2889) +%define VERR_PDM_CANNOT_TRANSFORM_REMOVED_DRIVER (-2890) +%define VERR_PDM_NOT_PCI_BUS_MASTER (-2891) +%define VERR_PDM_HM_IPE (-2892) +%define VERR_PDM_MEDIAEX_IOREQ_CANCELED (-2893) +%define VERR_PDM_MEDIAEX_IOBUF_OVERFLOW (-2894) +%define VERR_PDM_MEDIAEX_IOBUF_UNDERRUN (-2895) +%define VERR_PDM_MEDIAEX_IOREQID_CONFLICT (-2896) +%define VERR_PDM_MEDIAEX_IOREQID_NOT_FOUND (-2897) +%define VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS 2898 +%define VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE (-2899) +%define VINF_PDM_PCI_DO_DEFAULT (7200) +%define VERR_PDM_CRITSECT_ABORT_FAILED (-7201) +%define VERR_PDM_CRITSECTRW_TOO_MANY_READERS (-7202) +%define VERR_PDM_CRITSECTRW_TOO_MANY_WRITERS (-7203) +%define VERR_PDM_CRITSECTRW_TOO_MANY_RECURSIONS (-7204) +%define VERR_PDM_CRITSECTRW_IPE (-7205) +%define VERR_PDM_CRITSECTRW_MISALIGNED (-7206) +%define VERR_HGCM_SERVICE_NOT_FOUND (-2900) +%define VINF_HGCM_CLIENT_REJECTED 2901 +%define VERR_HGCM_INVALID_CMD_ADDRESS (-2902) +%define VINF_HGCM_ASYNC_EXECUTE 2903 +%define VERR_HGCM_INTERNAL (-2904) +%define VERR_HGCM_INVALID_CLIENT_ID (-2905) +%define VINF_HGCM_SAVE_STATE (2906) +%define VERR_HGCM_SERVICE_EXISTS (-2907) +%define VERR_HGCM_TOO_MANY_CLIENTS (-2908) +%define VERR_HGCM_TOO_MANY_CLIENT_CALLS (-2909) +%define VERR_NAT_REDIR_GUEST_IP (-3001) +%define VERR_NAT_REDIR_SETUP (-3002) +%define VERR_HOSTIF_INIT_FAILED (-3100) +%define VERR_HOSTIF_DEVICE_NAME_TOO_LONG (-3101) +%define VERR_HOSTIF_IOCTL (-3102) +%define VERR_HOSTIF_BLOCKING (-3103) +%define VERR_HOSTIF_FD_AND_INIT_TERM (-3104) +%define VERR_HOSTIF_TERM_FAILED (-3105) +%define VERR_VD_INVALID_TYPE (-3200) +%define VERR_VD_INVALID_STATE (-3201) +%define VERR_VD_VALUE_NOT_FOUND (-3202) +%define VERR_VD_NOT_OPENED (-3203) +%define VERR_VD_IMAGE_NOT_FOUND (-3204) +%define VERR_VD_IMAGE_READ_ONLY (-3205) +%define VERR_VD_GEOMETRY_NOT_SET (-3206) +%define VERR_VD_BLOCK_FREE (-3207) +%define VERR_VD_UUID_MISMATCH (-3208) +%define VINF_VD_ASYNC_IO_FINISHED 3209 +%define VERR_VD_ASYNC_IO_IN_PROGRESS (-3210) +%define VERR_VD_INVALID_SIZE (-3211) +%define VERR_VD_UNKNOWN_CFG_VALUES (-3212) +%define VERR_VD_UNKNOWN_INTERFACE (-3213) +%define VERR_VD_DEK_MISSING (-3214) +%define VERR_VD_PASSWORD_INCORRECT (-3215) +%define VERR_VD_GEN_INVALID_HEADER (-3220) +%define VERR_VD_VDI_INVALID_HEADER (-3230) +%define VERR_VD_VDI_INVALID_SIGNATURE (-3231) +%define VERR_VD_VDI_UNSUPPORTED_VERSION (-3232) +%define VERR_VD_VDI_COMMENT_TOO_LONG (-3233) +%define VERR_VD_VMDK_INVALID_HEADER (-3240) +%define VERR_VD_VMDK_UNSUPPORTED_VERSION (-3241) +%define VERR_VD_VMDK_VALUE_NOT_FOUND (-3242) +%define VERR_VD_VMDK_INVALID_STATE (-3243) +%define VERR_VD_VMDK_INVALID_FORMAT (-3244) +%define VERR_VD_VMDK_INVALID_WRITE (-3245) +%define VERR_VD_ISCSI_INVALID_HEADER (-3250) +%define VERR_VD_ISCSI_INVALID_STATE (-3251) +%define VERR_VD_ISCSI_INVALID_TYPE (-3252) +%define VERR_VD_ISCSI_SECRET_ENCRYPTED (-3253) +%define VERR_VD_VHD_INVALID_HEADER (-3260) +%define VERR_VD_PARALLELS_INVALID_HEADER (-3265) +%define VERR_VD_DMG_INVALID_HEADER (-3267) +%define VERR_VD_RAW_INVALID_HEADER (-3270) +%define VERR_VD_RAW_INVALID_TYPE (-3271) +%define VERR_VD_NOT_ENOUGH_METADATA (-3272) +%define VERR_VD_IOCTX_HALT (-3273) +%define VERR_VD_CACHE_ALREADY_EXISTS (-3274) +%define VERR_VD_CACHE_NOT_FOUND (-3275) +%define VERR_VD_CACHE_NOT_UP_TO_DATE (-3276) +%define VERR_VD_DISCARD_ALIGNMENT_NOT_MET (-3277) +%define VERR_VD_DISCARD_NOT_SUPPORTED (-3278) +%define VERR_VD_IMAGE_CORRUPTED (-3279) +%define VERR_VD_IMAGE_REPAIR_NOT_SUPPORTED (-3280) +%define VERR_VD_IMAGE_REPAIR_IMPOSSIBLE (-3281) +%define VERR_VD_READ_OUT_OF_RANGE (-3282) +%define VINF_VD_NEW_ZEROED_BLOCK 3283 +%define VERR_VD_DMG_XML_PARSE_ERROR (-3284) +%define VERR_VD_DMG_NOT_FOUND_INSIDE_XAR (-3285) +%define VERR_VD_RAW_SIZE_MODULO_512 (-3286) +%define VERR_VD_RAW_SIZE_MODULO_2048 (-3287) +%define VERR_VD_RAW_SIZE_OPTICAL_TOO_SMALL (-3288) +%define VERR_VD_RAW_SIZE_FLOPPY_TOO_BIG (-3289) +%define VERR_VD_SHRINK_NOT_SUPPORTED (-3290) +%define VERR_VBGL_NOT_INITIALIZED (-3300) +%define VERR_VBGL_INVALID_ADDR (-3301) +%define VERR_VBGL_IOCTL_FAILED (-3302) +%define VERR_VUSB_NO_PORTS (-3400) +%define VERR_VUSB_DEVICE_NOT_ATTACHED (-3401) +%define VERR_VUSB_NO_URB_MEMORY (-3402) +%define VERR_VUSB_FAILED_TO_QUEUE_URB (-3403) +%define VERR_VUSB_DEVICE_NAME_NOT_FOUND (-3404) +%define VERR_VUSB_USBFS_PERMISSION (-3405) +%define VERR_VUSB_DEVICE_IS_RESETTING (-3406) +%define VERR_VUSB_DEVICE_IS_SUSPENDED (-3407) +%define VERR_VUSB_USB_DEVICE_PERMISSION (-3408) +%define VERR_VGA_INVALID_CUSTOM_MODE (-3500) +%define VINF_VGA_RESIZE_IN_PROGRESS (3501) +%define VERR_VGA_UNEXPECTED_PCI_REGION_LOAD_CHANGE (-3502) +%define VERR_VGA_GL_LOAD_FAILURE (-3503) +%define VERR_VGA_GL_SYMBOL_NOT_FOUND (-3504) +%define VERR_INTNET_FLT_IF_NOT_FOUND (-3600) +%define VERR_INTNET_FLT_IF_BUSY (-3601) +%define VERR_INTNET_FLT_IF_FAILED (-3602) +%define VERR_INTNET_INCOMPATIBLE_TRUNK (-3603) +%define VERR_INTNET_INCOMPATIBLE_FLAGS (-3604) +%define VERR_INTNET_FLT_VNIC_CREATE_FAILED (-3605) +%define VERR_INTNET_FLT_VNIC_LINK_ID_NOT_FOUND (-3606) +%define VERR_INTNET_FLT_VNIC_INIT_FAILED (-3607) +%define VERR_INTNET_FLT_VNIC_OPEN_FAILED (-3608) +%define VERR_INTNET_FLT_LOWER_LINK_INFO_NOT_FOUND (-3609) +%define VERR_INTNET_FLT_LOWER_LINK_OPEN_FAILED (-3610) +%define VERR_INTNET_FLT_LOWER_LINK_ID_NOT_FOUND (-3611) +%define VERR_SUPDRV_COMPONENT_NOT_FOUND (-3700) +%define VERR_SUPDRV_INTERFACE_NOT_SUPPORTED (-3701) +%define VERR_SUPDRV_SERVICE_NOT_FOUND (-3702) +%define VERR_SUPDRV_KERNEL_TOO_OLD_FOR_VTX (-3703) +%define VERR_SUPDRV_VTG_MAGIC (-3704) +%define VERR_SUPDRV_VTG_BITS (-3705) +%define VERR_SUPDRV_VTG_BAD_HDR_MISC (-3706) +%define VERR_SUPDRV_VTG_BAD_HDR_OFF (-3707) +%define VERR_SUPDRV_VTG_BAD_HDR_PTR (-3708) +%define VERR_SUPDRV_VTG_BAD_HDR_TOO_FEW (-3709) +%define VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH (-3710) +%define VERR_SUPDRV_VTG_BAD_HDR_NOT_MULTIPLE (-3711) +%define VERR_SUPDRV_VTG_STRTAB_OFF (-3712) +%define VERR_SUPDRV_VTG_BAD_STRING (-3713) +%define VERR_SUPDRV_VTG_STRING_TOO_LONG (-3714) +%define VERR_SUPDRV_VTG_BAD_ATTR (-3715) +%define VERR_SUPDRV_VTG_BAD_PROVIDER (-3716) +%define VERR_SUPDRV_VTG_BAD_PROBE (-3717) +%define VERR_SUPDRV_VTG_BAD_ARGLIST (-3718) +%define VERR_SUPDRV_VTG_BAD_PROBE_ENABLED (-3719) +%define VERR_SUPDRV_VTG_BAD_PROBE_LOC (-3720) +%define VERR_SUPDRV_VTG_ALREADY_REGISTERED (-3721) +%define VERR_SUPDRV_VTG_ONLY_ONCE_PER_SESSION (-3722) +%define VERR_SUPDRV_TRACER_ALREADY_REGISTERED (-3723) +%define VERR_SUPDRV_TRACER_NOT_REGISTERED (-3724) +%define VERR_SUPDRV_TRACER_ALREADY_OPENED (-3725) +%define VERR_SUPDRV_TRACER_NOT_OPENED (-3726) +%define VERR_SUPDRV_TRACER_NOT_PRESENT (-3727) +%define VERR_SUPDRV_TRACER_UNLOADING (-3728) +%define VERR_SUPDRV_TRACER_SESSION_BUSY (-3729) +%define VERR_SUPDRV_TRACER_CANNOT_OPEN_SELF (-3730) +%define VERR_SUPDRV_TRACER_BAD_ARG_FLAGS (-3731) +%define VERR_SUPDRV_TRACER_TOO_MANY_PROVIDERS (-3732) +%define VERR_SUPDRV_TRACER_TOO_LARGE (-3733) +%define VERR_SUPDRV_TRACER_UMOD_NOT_ADJACENT (-3734) +%define VERR_SUPDRV_TRACER_UMOD_TOO_MANY_PROBES (-3735) +%define VERR_SUPDRV_TRACER_UMOD_STRTAB_TOO_BIG (-3736) +%define VERR_SUPDRV_TRACER_UMOD_STRTAB_OFF_BAD (-3737) +%define VERR_SUPDRV_HARDENING_EVIL_HANDLE (-3738) +%define VERR_SUPDRV_APIPORT_OPEN_ERROR (-3739) +%define VERR_SUPDRV_SESSION_PROCESS_ENUM_ERROR (-3740) +%define VERR_SUPDRV_CSRSS_NOT_FOUND (-3741) +%define VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE (-3742) +%define VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED (-3743) +%define VERR_SUPDRV_TSC_FREQ_MEASUREMENT_FAILED (-3744) +%define VERR_SUPDRV_TSC_READ_FAILED (-3745) +%define VWRN_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED 3746 +%define VERR_SUPDRV_TSC_DELTA_MEASUREMENT_BUSY (-3747) +%define VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_1 (-3748) +%define VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_2 (-3749) +%define VERR_SUPDRV_NO_RAW_MODE_HYPER_V_ROOT (-7000) +%define VERR_SUPLIB_PATH_NOT_ABSOLUTE (-3750) +%define VERR_SUPLIB_PATH_NOT_CLEAN (-3751) +%define VERR_SUPLIB_PATH_TOO_LONG (-3752) +%define VERR_SUPLIB_PATH_TOO_SHORT (-3753) +%define VERR_SUPLIB_PATH_TOO_MANY_COMPONENTS (-3754) +%define VERR_SUPLIB_PATH_IS_ROOT (-3755) +%define VERR_SUPLIB_DIR_ENUM_FAILED (-3756) +%define VERR_SUPLIB_STAT_ENUM_FAILED (-3757) +%define VERR_SUPLIB_STAT_FAILED (-3758) +%define VERR_SUPLIB_FSTAT_FAILED (-3759) +%define VERR_SUPLIB_SYMLINKS_ARE_NOT_PERMITTED (-3760) +%define VERR_SUPLIB_NOT_DIR_NOT_FILE (-3761) +%define VERR_SUPLIB_IS_DIRECTORY (-3762) +%define VERR_SUPLIB_IS_FILE (-3763) +%define VERR_SUPLIB_NOT_SAME_OBJECT (-3764) +%define VERR_SUPLIB_OWNER_NOT_ROOT (-3765) +%define VERR_SUPLIB_WRITE_NON_SYS_GROUP (-3766) +%define VERR_SUPLIB_WORLD_WRITABLE (-3767) +%define VERR_SUPLIB_INVALID_ARGV0_INTERNAL (-3768) +%define VERR_SUPLIB_INVALID_INTERNAL_APP_DIR (-3769) +%define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0 (-3770) +%define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1 (-3771) +%define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2 (-3772) +%define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_3 (-3773) +%define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_4 (-3774) +%define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_5 (-3775) +%define VERR_SUPLIB_TEXT_NOT_WRITEABLE (-3776) +%define VERR_SUPLIB_TEXT_NOT_SEALED (-3777) +%define VERR_SUPLIB_UNEXPECTED_INSTRUCTION (-3778) +%define VERR_GMM_OUT_OF_MEMORY (-3801) +%define VERR_GMM_HIT_GLOBAL_LIMIT (-3802) +%define VERR_GMM_HIT_VM_ACCOUNT_LIMIT (-3803) +%define VERR_GMM_ATTEMPT_TO_FREE_TOO_MUCH (-3804) +%define VERR_GMM_ATTEMPT_TO_DEFLATE_TOO_MUCH (-3805) +%define VERR_GMM_PAGE_NOT_FOUND (-3806) +%define VERR_GMM_PAGE_NOT_PRIVATE (-3807) +%define VERR_GMM_PAGE_NOT_SHARED (-3808) +%define VERR_GMM_PAGE_ALREADY_FREE (-3809) +%define VERR_GMM_NOT_PAGE_OWNER (-3810) +%define VERR_GMM_CHUNK_NOT_FOUND (-3811) +%define VERR_GMM_CHUNK_ALREADY_MAPPED (-3812) +%define VERR_GMM_CHUNK_NOT_MAPPED (-3813) +%define VERR_GMM_TOO_MANY_CHUNK_MAPPINGS (-3814) +%define VERR_GMM_MEMORY_RESERVATION_DECLINED (-3815) +%define VERR_GMM_IS_NOT_SANE (-3816) +%define VERR_GMM_CHUNK_INSERT (-3817) +%define VERR_GMM_INSTANCE (-3818) +%define VERR_GMM_MTX_FLAGS (-3819) +%define VERR_GMM_ALLOC_PAGES_IPE (-3820) +%define VERR_GMM_ACTUAL_PAGES_IPE (-3821) +%define VERR_GMM_MODULE_NAME_TOO_LONG (-3822) +%define VERR_GMM_MODULE_VERSION_TOO_LONG (-3823) +%define VERR_GMM_TOO_MANY_REGIONS (-3824) +%define VERR_GMM_TOO_MANY_PER_VM_MODULES (-3825) +%define VERR_GMM_TOO_MANY_GLOBAL_MODULES (-3826) +%define VINF_GMM_SHARED_MODULE_ALREADY_REGISTERED (3827) +%define VERR_GMM_SHARED_MODULE_ADDRESS_CLASH (-3828) +%define VERR_GMM_SHARED_MODULE_NOT_FOUND (-3829) +%define VERR_GMM_BAD_SHARED_MODULE_SIZE (-3830) +%define VERR_GMM_SHARED_MODULE_BAD_REGIONS_SIZE (-3831) +%define VERR_GVM_TOO_MANY_VMS (-3900) +%define VINF_GVM_NOT_BLOCKED 3901 +%define VINF_GVM_NOT_BUSY_IN_GC 3902 +%define VINF_GVM_YIELDED 3903 +%define VERR_VMX_VMXON_FAILED (-4000) +%define VERR_VMX_INVALID_VMCS_PTR (-4001) +%define VERR_VMX_INVALID_VMCS_FIELD (-4002) +%define VERR_VMX_RESERVED (-4003) +%define VERR_VMX_INVALID_VMXON_PTR (-4004) +%define VERR_VMX_UNABLE_TO_START_VM (-4005) +%define VERR_VMX_INVALID_HOST_STATE (-4006) +%define VERR_VMX_NO_VMX (-4009) +%define VERR_VMX_IN_VMX_ROOT_MODE (-4011) +%define VERR_VMX_X86_CR4_VMXE_CLEARED (-4012) +%define VERR_VMX_MSR_LOCKING_FAILED (-4013) +%define VERR_VMX_INVALID_GUEST_STATE (-4014) +%define VERR_VMX_UNEXPECTED_EXIT (-4015) +%define VERR_VMX_UNEXPECTED_EXCEPTION (-4016) +%define VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE (-4017) +%define VERR_VMX_NOT_IN_VMX_ROOT_MODE (-4018) +%define VERR_VMX_UNDEFINED_EXIT_CODE (-4019) +%define VERR_VMX_VMPTRLD_FAILED (-4021) +%define VERR_VMX_INVALID_VMCS_PTR_TO_START_VM (-4022) +%define VERR_VMX_IPE_1 (-4023) +%define VERR_VMX_IPE_2 (-4024) +%define VERR_VMX_IPE_3 (-4025) +%define VERR_VMX_IPE_4 (-4026) +%define VERR_VMX_IPE_5 (-4027) +%define VERR_VMX_MSR_ALL_VMX_DISABLED (-4028) +%define VERR_VMX_MSR_VMX_DISABLED (-4029) +%define VERR_VMX_VMCS_FIELD_CACHE_INVALID (-4030) +%define VERR_VMX_MSR_VMX_ENABLE_FAILED (-4031) +%define VERR_VMX_MSR_SMX_VMX_ENABLE_FAILED (-4032) +%define VINF_VMX_VMEXIT 4033 +%define VERR_VMX_VMENTRY_FAILED (-4033) +%define VERR_VMX_VMEXIT_FAILED (-4034) +%define VINF_VMX_INTERCEPT_NOT_ACTIVE 4035 +%define VINF_VMX_MODIFIES_BEHAVIOR 4036 +%define VINF_VMX_VMLAUNCH_VMRESUME 4037 +%define VERR_VMX_INVALID_VMCS_LAUNCH_STATE (-4038) +%define VERR_VMX_STARTVM_PRECOND_0 (-4039) +%define VERR_VMX_STARTVM_PRECOND_1 (-4040) +%define VERR_VMX_STARTVM_PRECOND_2 (-4041) +%define VERR_VMX_STARTVM_PRECOND_3 (-4042) +%define VERR_SVM_UNABLE_TO_START_VM (-4050) +%define VERR_SVM_ILLEGAL_EFER_MSR (-4051) +%define VERR_SVM_NO_SVM (-4052) +%define VERR_SVM_DISABLED (-4053) +%define VERR_SVM_IN_USE (-4054) +%define VERR_SVM_INVALID_PVMCB (-4055) +%define VERR_SVM_UNEXPECTED_EXIT (-4056) +%define VERR_SVM_UNEXPECTED_XCPT_EXIT (-4057) +%define VERR_SVM_UNEXPECTED_PATCH_TYPE (-4058) +%define VERR_SVM_INVALID_GUEST_STATE (-4059) +%define VERR_SVM_UNKNOWN_EXIT (-4060) +%define VERR_SVM_IPE_1 (-4061) +%define VERR_SVM_IPE_2 (-4062) +%define VERR_SVM_IPE_3 (-4063) +%define VERR_SVM_IPE_4 (-4064) +%define VERR_SVM_IPE_5 (-4065) +%define VERR_SVM_VMEXIT_FAILED (-4066) +%define VINF_SVM_VMEXIT 4067 +%define VINF_SVM_VMRUN 4068 +%define VINF_SVM_INTERCEPT_NOT_ACTIVE 4069 +%define VERR_SVM_VMRUN_PRECOND_0 (-4070) +%define VERR_SVM_VMRUN_PRECOND_1 (-4071) +%define VERR_SVM_VMRUN_PRECOND_2 (-4072) +%define VERR_SVM_VMRUN_PRECOND_3 (-4073) +%define VERR_HM_SUSPEND_PENDING (-4100) +%define VERR_HM_CONFIG_MISMATCH (-4103) +%define VERR_HM_ALREADY_ENABLED_IPE (-4104) +%define VERR_HM_UNEXPECTED_LD_ST_MSR (-4105) +%define VERR_HM_NO_32_TO_64_SWITCHER (-4106) +%define VERR_HM_WRONG_CPU (-4107) +%define VERR_HM_IPE_1 (-4108) +%define VERR_HM_IPE_2 (-4109) +%define VERR_HM_WRONG_SWITCHER (-4110) +%define VERR_HM_UNKNOWN_IO_INSTRUCTION (-4111) +%define VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO (-4112) +%define VERR_HM_IPE_3 (-4113) +%define VERR_HM_IPE_4 (-4114) +%define VERR_HM_IPE_5 (-4115) +%define VERR_HM_INVALID_HM64ON32OP (-4116) +%define VINF_HM_DOUBLE_FAULT 4117 +%define VINF_HM_PENDING_XCPT 4118 +%define VERR_DIS_INVALID_OPCODE (-4200) +%define VERR_DIS_GEN_FAILURE (-4201) +%define VERR_DIS_NO_READ_CALLBACK (-4202) +%define VERR_DIS_INVALID_MODRM (-4203) +%define VERR_DIS_INVALID_PARAMETER (-4204) +%define VERR_DIS_TOO_LONG_INSTR (-4206) +%define VERR_WEB_NOT_AUTHENTICATED (-4300) +%define VERR_WEB_INVALID_MANAGED_OBJECT_REFERENCE (-4301) +%define VERR_WEB_INVALID_SESSION_ID (-4302) +%define VERR_WEB_INVALID_OBJECT_ID (-4303) +%define VERR_WEB_UNSUPPORTED_INTERFACE (-4304) +%define VINF_PARAV_SWITCH_TO_HOST 4400 +%define VINF_VHWA_CMD_PENDING 4500 +%define VERR_COM_UNEXPECTED (-4600) +%define VERR_COM_VBOX_LOWEST (-4699) +%define VERR_COM_OBJECT_NOT_FOUND (VERR_COM_VBOX_LOWEST + 1) +%define VERR_COM_INVALID_VM_STATE (VERR_COM_VBOX_LOWEST + 2) +%define VERR_COM_VM_ERROR (VERR_COM_VBOX_LOWEST + 3) +%define VERR_COM_FILE_ERROR (VERR_COM_VBOX_LOWEST + 4) +%define VERR_COM_IPRT_ERROR (VERR_COM_VBOX_LOWEST + 5) +%define VERR_COM_PDM_ERROR (VERR_COM_VBOX_LOWEST + 6) +%define VERR_COM_INVALID_OBJECT_STATE (VERR_COM_VBOX_LOWEST + 7) +%define VERR_COM_HOST_ERROR (VERR_COM_VBOX_LOWEST + 8) +%define VERR_COM_NOT_SUPPORTED (VERR_COM_VBOX_LOWEST + 9) +%define VERR_COM_XML_ERROR (VERR_COM_VBOX_LOWEST + 10) +%define VERR_COM_INVALID_SESSION_STATE (VERR_COM_VBOX_LOWEST + 11) +%define VERR_COM_OBJECT_IN_USE (VERR_COM_VBOX_LOWEST + 12) +%define VERR_COM_DONT_CALL_AGAIN (VERR_COM_VBOX_LOWEST + 13) +%define VERR_VMMDEV_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST (-4700) +%define VINF_AIO_TASK_PENDING 4800 +%define VERR_VSCSI_LUN_TYPE_NOT_SUPPORTED (-4900) +%define VERR_VSCSI_LUN_ATTACHED_TO_DEVICE (-4901) +%define VERR_VSCSI_LUN_INVALID (-4902) +%define VERR_VSCSI_LUN_NOT_ATTACHED (-4903) +%define VERR_VSCSI_LUN_BUSY (-4904) +%define VERR_FAM_OPEN_FAILED (-5000) +%define VERR_FAM_MONITOR_FILE_FAILED (-5001) +%define VERR_FAM_MONITOR_DIRECTORY_FAILED (-5002) +%define VERR_FAM_CONNECTION_LOST (-5003) +%define VERR_PCI_PASSTHROUGH_NO_RAM_PREALLOC (-5100) +%define VERR_PCI_PASSTHROUGH_NO_HM (-5101) +%define VERR_PCI_PASSTHROUGH_NO_NESTED_PAGING (-5102) +%define VINF_PCI_MAPPING_DONE 5150 +%define VERR_GVMM_INSTANCE (-5200) +%define VERR_GVMM_HOST_CPU_RANGE (-5201) +%define VERR_GVMM_BROKEN_IPRT (-5202) +%define VERR_GVMM_IPE_1 (-5203) +%define VERR_GVMM_IPE_2 (-5204) +%define VERR_GVMM_NOT_ALL_EMTS_DEREGISTERED (-5205) +%define VERR_IEM_INSTR_NOT_IMPLEMENTED (-5300) +%define VERR_IEM_INVALID_OPERAND_SIZE (-5301) +%define VERR_IEM_INVALID_ADDRESS_MODE (-5302) +%define VERR_IEM_INVALID_EFF_SEG (-5303) +%define VERR_IEM_INVALID_INSTR_LENGTH (-5304) +%define VINF_IEM_SELECTOR_NOT_OK (5305) +%define VERR_IEM_RESTART_INSTRUCTION (-5389) +%define VERR_IEM_ASPECT_NOT_IMPLEMENTED (-5390) +%define VERR_IEM_IPE_1 (-5391) +%define VERR_IEM_IPE_2 (-5392) +%define VERR_IEM_IPE_3 (-5393) +%define VERR_IEM_IPE_4 (-5394) +%define VERR_IEM_IPE_5 (-5395) +%define VERR_IEM_IPE_6 (-5396) +%define VERR_IEM_IPE_7 (-5397) +%define VERR_IEM_IPE_8 (-5398) +%define VERR_IEM_IPE_9 (-5399) +%define VERR_DBGC_QUIT (-5400) +%define VWRN_DBGC_CMD_PENDING 5401 +%define VWRN_DBGC_ALREADY_REGISTERED 5402 +%define VERR_DBGC_COMMANDS_NOT_REGISTERED (-5403) +%define VERR_DBGC_BP_NOT_FOUND (-5404) +%define VERR_DBGC_BP_EXISTS (-5405) +%define VINF_DBGC_BP_NO_COMMAND 5406 +%define VERR_DBGC_COMMAND_FAILED (-5407) +%define VERR_DBGC_IPE (-5408) +%define VERR_DBGC_PARSE_LOWEST (-5499) +%define VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS (VERR_DBGC_PARSE_LOWEST + 0) +%define VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS (VERR_DBGC_PARSE_LOWEST + 1) +%define VERR_DBGC_PARSE_ARGUMENT_OVERFLOW (VERR_DBGC_PARSE_LOWEST + 2) +%define VERR_DBGC_PARSE_EXPECTED_BINARY_OP (VERR_DBGC_PARSE_LOWEST + 3) +%define VERR_DBGC_PARSE_NO_RANGE_ALLOWED (VERR_DBGC_PARSE_LOWEST + 5) +%define VERR_DBGC_PARSE_UNBALANCED_QUOTE (VERR_DBGC_PARSE_LOWEST + 6) +%define VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS (VERR_DBGC_PARSE_LOWEST + 7) +%define VERR_DBGC_PARSE_EMPTY_ARGUMENT (VERR_DBGC_PARSE_LOWEST + 8) +%define VERR_DBGC_PARSE_UNEXPECTED_OPERATOR (VERR_DBGC_PARSE_LOWEST + 9) +%define VERR_DBGC_PARSE_INVALID_NUMBER (VERR_DBGC_PARSE_LOWEST + 10) +%define VERR_DBGC_PARSE_NUMBER_TOO_BIG (VERR_DBGC_PARSE_LOWEST + 11) +%define VERR_DBGC_PARSE_INVALID_OPERATION (VERR_DBGC_PARSE_LOWEST + 12) +%define VERR_DBGC_PARSE_FUNCTION_NOT_FOUND (VERR_DBGC_PARSE_LOWEST + 13) +%define VERR_DBGC_PARSE_NOT_A_FUNCTION (VERR_DBGC_PARSE_LOWEST + 14) +%define VERR_DBGC_PARSE_NO_SCRATCH (VERR_DBGC_PARSE_LOWEST + 15) +%define VERR_DBGC_PARSE_NO_MEMORY (VERR_DBGC_PARSE_LOWEST + 16) +%define VERR_DBGC_PARSE_INCORRECT_ARG_TYPE (VERR_DBGC_PARSE_LOWEST + 17) +%define VERR_DBGC_PARSE_VARIABLE_NOT_FOUND (VERR_DBGC_PARSE_LOWEST + 18) +%define VERR_DBGC_PARSE_CONVERSION_FAILED (VERR_DBGC_PARSE_LOWEST + 19) +%define VERR_DBGC_PARSE_NOT_IMPLEMENTED (VERR_DBGC_PARSE_LOWEST + 20) +%define VERR_DBGC_PARSE_BAD_RESULT_TYPE (VERR_DBGC_PARSE_LOWEST + 21) +%define VERR_DBGC_PARSE_WRITEONLY_SYMBOL (VERR_DBGC_PARSE_LOWEST + 22) +%define VERR_DBGC_PARSE_INVALD_COMMAND_NAME (VERR_DBGC_PARSE_LOWEST + 23) +%define VERR_DBGC_PARSE_COMMAND_NOT_FOUND (VERR_DBGC_PARSE_LOWEST + 24) +%define VERR_DBGC_PARSE_BUG (VERR_DBGC_PARSE_LOWEST + 25) +%define VERR_SUP_VP_MEMORY_VS_FILE_MISMATCH (-5600) +%define VERR_SUP_VP_SECTION_PROTECTION_MISMATCH (-5601) +%define VERR_SUP_VP_SECTION_NOT_MAPPED (-5602) +%define VERR_SUP_VP_SECTION_NOT_FULLY_MAPPED (-5603) +%define VERR_SUP_VP_BAD_FILE_ALIGNMENT_VALUE (-5604) +%define VERR_SUP_VP_BAD_IMAGE_BASE (-5605) +%define VERR_SUP_VP_BAD_IMAGE_SIGNATURE (-5606) +%define VERR_SUP_VP_BAD_IMAGE_SIZE (-5607) +%define VERR_SUP_VP_BAD_MZ_OFFSET (-5608) +%define VERR_SUP_VP_BAD_OPTIONAL_HEADER (-5609) +%define VERR_SUP_VP_BAD_SECTION_ALIGNMENT_VALUE (-5610) +%define VERR_SUP_VP_BAD_SECTION_FILE_SIZE (-5611) +%define VERR_SUP_VP_BAD_SECTION_RVA (-5612) +%define VERR_SUP_VP_BAD_SECTION_VIRTUAL_SIZE (-5613) +%define VERR_SUP_VP_BAD_SIZE_OF_HEADERS (-5614) +%define VERR_SUP_VP_DEBUGGED (-5615) +%define VERR_SUP_VP_DUPLICATE_DLL_MAPPING (-5616) +%define VERR_SUP_VP_EMPTY_REGION_TOO_LARGE (-5617) +%define VERR_SUP_VP_EXE_VS_PROC_NAME_MISMATCH (-5618) +%define VERR_SUP_VP_FOUND_EXEC_MEMORY (-5619) +%define VERR_SUP_VP_FOUND_MORE_THAN_ONE_EXE_MAPPING (-5620) +%define VERR_SUP_VP_IMAGE_FILE_CLOSE_ERROR (-5621) +%define VERR_SUP_VP_IMAGE_FILE_OPEN_ERROR (-5622) +%define VERR_SUP_VP_IMAGE_HDR_READ_ERROR (-5623) +%define VERR_SUP_VP_IMAGE_MAPPING_BASE_ERROR (-5624) +%define VERR_SUP_VP_MEMORY_READ_ERROR (-5625) +%define VERR_SUP_VP_NO_FOUND_NO_EXE_MAPPING (-5626) +%define VERR_SUP_VP_NO_IMAGE_MAPPING_NAME (-5627) +%define VERR_SUP_VP_NO_KERNEL32_MAPPING (-5628) +%define VERR_SUP_VP_NO_MEMORY (-5629) +%define VERR_SUP_VP_NO_MEMORY_STATE (-5630) +%define VERR_SUP_VP_NO_NTDLL_MAPPING (-5631) +%define VERR_SUP_VP_NON_SYSTEM32_DLL (-5632) +%define VERR_SUP_VP_NOT_KNOWN_DLL_OR_EXE (-5633) +%define VERR_SUP_VP_NT_MAPPING_NAME_CHANGED (-5634) +%define VERR_SUP_VP_NT_QI_PROCESS_NM_ERROR (-5635) +%define VERR_SUP_VP_NT_QI_THREAD_ERROR (-5636) +%define VERR_SUP_VP_NT_QI_VIRTUAL_MEMORY_ERROR (-5637) +%define VERR_SUP_VP_NT_QI_VIRTUAL_MEMORY_NM_ERROR (-5638) +%define VERR_SUP_VP_SYSTEM32_PATH (-5639) +%define VERR_SUP_VP_THREAD_NOT_ALONE (-5640) +%define VERR_SUP_VP_TOO_HIGH_REGION_RVA (-5641) +%define VERR_SUP_VP_TOO_LARGE_REGION (-5642) +%define VERR_SUP_VP_TOO_MANY_DLLS_LOADED (-5643) +%define VERR_SUP_VP_TOO_MANY_IMAGE_REGIONS (-5644) +%define VERR_SUP_VP_TOO_MANY_MEMORY_REGIONS (-5645) +%define VERR_SUP_VP_TOO_MANY_SECTIONS (-5646) +%define VERR_SUP_VP_UNEXPECTED_IMAGE_MACHINE (-5647) +%define VERR_SUP_VP_UNEXPECTED_SECTION_FLAGS (-5648) +%define VERR_SUP_VP_EXE_MISSING_FORCE_INTEGRITY (-5649) +%define VERR_SUP_VP_EXE_MISSING_DYNAMIC_BASE (-5650) +%define VERR_SUP_VP_EXE_MISSING_NX_COMPAT (-5651) +%define VERR_SUP_VP_DLL_CHARECTERISTICS_MISMATCH (-5652) +%define VERR_SUP_VP_IMAGE_CHARECTERISTICS_MISMATCH (-5653) +%define VERR_SUP_VP_NT_QI_PROCESS_IMG_INFO_ERROR (-5654) +%define VERR_SUP_VP_NT_QI_PROCESS_DBG_PORT_ERROR (-5655) +%define VERR_SUP_VP_WINTRUST_CAT_FAILURE (-5656) +%define VERR_SUP_VP_NOT_SIGNED_WITH_BUILD_CERT (-5657) +%define VERR_SUP_VP_NOT_BUILD_CERT_IPE (-5658) +%define VERR_SUP_VP_NOT_VALID_KERNEL_CODE_SIGNATURE (-5659) +%define VERR_SUP_VP_UNEXPECTED_VALID_PATH_COUNT (-5660) +%define VERR_SUP_VP_SIGNATURE_CHECKS_NOT_ENFORCED (-5661) +%define VERR_SUP_VP_SYSFER_DLL (-5662) +%define VERR_SUP_VP_KERNEL32_ALREADY_MAPPED (-5663) +%define VERR_SUP_VP_FREE_VIRTUAL_MEMORY_FAILED (-5664) +%define VERR_SUP_VP_UNMAP_AND_PROTECT_FAILED (-5665) +%define VERR_SUP_VP_UNKOWN_MEM_TYPE (-5666) +%define VERR_SUP_VP_NOT_OWNED_BY_TRUSTED_INSTALLER (-5667) +%define VERR_SUP_VP_IMAGE_TOO_BIG (-5668) +%define VERR_SUP_VP_STUB_NOT_FOUND (-5669) +%define VERR_SUP_VP_STUB_OPEN_ERROR (-5670) +%define VERR_SUP_VP_STUB_THREAD_NOT_FOUND (-5671) +%define VERR_SUP_VP_STUB_THREAD_OPEN_ERROR (-5672) +%define VERR_SUP_VP_REPLACE_VIRTUAL_MEMORY_FAILED (-5673) +%define VERR_SUP_VP_FILE_MODE_ERROR (-5674) +%define VERR_SUP_VP_CREATE_READ_EVT_SEM_FAILED (-5675) +%define VERR_SUP_VP_UNDESIRABLE_MODULE (-5676) +%define VERR_SUP_DRIVERLESS (-5699) +%define VINF_SUP_DRIVERLESS 5699 +%define VERR_EXTPACK_UNSUPPORTED_HOST_UNINSTALL (-6000) +%define VERR_EXTPACK_VBOX_VERSION_MISMATCH (-6001) +%define VERR_GSTCTL_GUEST_ERROR (-6200) +%define VWRN_GSTCTL_OBJECTSTATE_CHANGED 6220 +%define VERR_GSTCTL_PROCESS_WRONG_STATE (-6221) +%define VERR_GSTCTL_MAX_CID_SESSIONS_REACHED (-6222) +%define VERR_GSTCTL_MAX_CID_OBJECTS_REACHED (-6223) +%define VERR_GSTCTL_MAX_CID_COUNT_REACHED (-6224) +%define VERR_GSTCTL_PROCESS_EXIT_CODE (-6225) +%define VERR_GIM_NOT_ENABLED (-6300) +%define VERR_GIM_IPE_1 (-6301) +%define VERR_GIM_IPE_2 (-6302) +%define VERR_GIM_IPE_3 (-6303) +%define VERR_GIM_PVTSC_NOT_AVAILABLE (-6304) +%define VERR_GIM_PVTSC_NOT_ENABLED (-6305) +%define VERR_GIM_INVALID_PROVIDER (-6306) +%define VERR_GIM_OPERATION_FAILED (-6307) +%define VERR_GIM_HYPERCALLS_NOT_AVAILABLE (-6308) +%define VERR_GIM_HYPERCALLS_NOT_ENABLED (-6309) +%define VERR_GIM_DEVICE_NOT_REGISTERED (-6310) +%define VERR_GIM_HYPERCALL_ACCESS_DENIED (-6311) +%define VERR_GIM_HYPERCALL_MEMORY_READ_FAILED (-6312) +%define VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED (-6313) +%define VERR_GIM_HYPERCALL_FAILED (-6314) +%define VERR_GIM_NO_DEBUG_CONNECTION (-6315) +%define VINF_GIM_R3_HYPERCALL 6316 +%define VINF_GIM_HYPERCALL_CONTINUING 6317 +%define VERR_GIM_INVALID_HYPERCALL_INSTR (-6318) +%define VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR (-6400) +%define VERR_MAIN_CONFIG_CONSTRUCTOR_IPE (-6401) +%define VERR_GSTDND_GUEST_ERROR (-6500) +%define VERR_AUDIO_BACKEND_INIT_FAILED (-6600) +%define VERR_AUDIO_BACKEND_NOT_ATTACHED (-6601) +%define VERR_AUDIO_NO_FREE_INPUT_STREAMS (-6602) +%define VERR_AUDIO_NO_FREE_OUTPUT_STREAMS (-6603) +%define VERR_AUDIO_STREAM_PENDING_DISABLE (-6604) +%define VINF_AUDIO_MORE_DATA_AVAILABLE (6605) +%define VERR_AUDIO_STREAM_NOT_READY (-6605) +%define VERR_AUDIO_STREAM_COULD_NOT_CREATE (-6606) +%define VERR_AUDIO_ENUMERATION_FAILED (-6607) +%define VERR_AUDIO_STREAM_INIT_IN_PROGRESS (-6608) +%define VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED (6609) +%define VERR_APIC_INTR_NOT_PENDING (-6700) +%define VERR_APIC_INTR_MASKED_BY_TPR (-6701) +%define VERR_APIC_INTR_DISCARDED (-6702) +%define VERR_NEM_NOT_ENABLED (-6800) +%define VERR_NEM_NOT_AVAILABLE (-6801) +%define VERR_NEM_INIT_FAILED (-6802) +%define VERR_NEM_MISSING_KERNEL_API_1 (-6803) +%define VERR_NEM_RING3_ONLY (-6804) +%define VERR_NEM_VM_CREATE_FAILED (-6805) +%define VERR_NEM_MAP_PAGES_FAILED (-6806) +%define VERR_NEM_UNMAP_PAGES_FAILED (-6807) +%define VERR_NEM_GET_REGISTERS_FAILED (-6808) +%define VERR_NEM_SET_REGISTERS_FAILED (-6809) +%define VERR_NEM_FLUSH_TLB (-6810) +%define VINF_NEM_FLUSH_TLB (6810) +%define VERR_NEM_SET_TSC (-6811) +%define VERR_NEM_MISSING_KERNEL_API_2 (-6812) +%define VERR_NEM_MISSING_KERNEL_API_3 (-6813) +%define VERR_NEM_MISSING_KERNEL_API_4 (-6814) +%define VERR_NEM_MISSING_KERNEL_API_5 (-6815) +%define VERR_NEM_QUERY_DIRTY_BITMAP_FAILED (-6816) +%define VERR_NEM_MISSING_FEATURE (-6817) +%define VERR_NEM_IPE_0 (-6890) +%define VERR_NEM_IPE_1 (-6891) +%define VERR_NEM_IPE_2 (-6892) +%define VERR_NEM_IPE_3 (-6893) +%define VERR_NEM_IPE_4 (-6894) +%define VERR_NEM_IPE_5 (-6895) +%define VERR_NEM_IPE_6 (-6896) +%define VERR_NEM_IPE_7 (-6897) +%define VERR_NEM_IPE_8 (-6898) +%define VERR_NEM_IPE_9 (-6899) +%define VERR_RECORDING_CODEC_NOT_FOUND (-6900) +%define VERR_RECORDING_CODEC_INIT_FAILED (-6902) +%define VERR_RECORDING_CODEC_NOT_SUPPORTED (-6903) +%define VERR_RECORDING_FORMAT_NOT_SUPPORTED (-6904) +%define VERR_RECORDING_RESTRICTED (-6905) +%define VINF_RECORDING_LIMIT_REACHED (6906) +%define VERR_RECORDING_LIMIT_REACHED (-6906) +%define VINF_RECORDING_THROTTLED (6907) +%define VERR_RECORDING_THROTTLED (-6907) +%define VERR_RECORDING_ENCODING_FAILED (-6908) +%define VERR_SHCLPB_MAX_TRANSFERS_REACHED (-7100) +%define VERR_SHCLPB_MAX_OBJECTS_REACHED (-7101) +%define VERR_SHCLPB_MAX_LISTS_REACHED (-7102) +%define VERR_SHCLPB_LIST_HANDLE_INVALID (-7103) +%define VERR_SHCLPB_OBJ_HANDLE_INVALID (-7104) +%define VERR_SHCLPB_EVENT_ID_NOT_FOUND (-7105) +%define VERR_SHCLPB_MAX_EVENTS_REACHED (-7106) +%define VERR_SHCLPB_TRANSFER_ID_NOT_FOUND (-7150) +%define VERR_IOMMU_DTE_READ_FAILED (-7300) +%define VERR_IOMMU_DTE_BAD_OFFSET (-7301) +%define VERR_IOMMU_ADDR_TRANSLATION_FAILED (-7302) +%define VERR_IOMMU_ADDR_ACCESS_DENIED (-7303) +%define VERR_IOMMU_INTR_REMAP_FAILED (-7304) +%define VERR_IOMMU_INTR_REMAP_DENIED (-7305) +%define VERR_IOMMU_CMD_NOT_SUPPORTED (-7306) +%define VERR_IOMMU_CMD_INVALID_FORMAT (-7307) +%define VERR_IOMMU_CMD_HW_ERROR (-7308) +%define VERR_IOMMU_NOT_PRESENT (-7309) +%define VERR_IOMMU_CANNOT_CALL_SELF (-7310) +%define VINF_IOMMU_ADDR_TRANSLATION_DISABLED 7311 +%define VERR_IOMMU_IPE_0 (-7390) +%define VERR_IOMMU_IPE_1 (-7391) +%define VERR_IOMMU_IPE_2 (-7392) +%define VERR_IOMMU_IPE_3 (-7393) +%define VERR_IOMMU_IPE_4 (-7394) +%define VERR_IOMMU_IPE_5 (-7395) +%define VERR_IOMMU_IPE_6 (-7396) +%define VERR_IOMMU_IPE_7 (-7397) +%define VERR_IOMMU_IPE_8 (-7398) +%define VERR_IOMMU_IPE_9 (-7399) +%include "iprt/err.mac" diff --git a/include/VBox/err.sed b/include/VBox/err.sed new file mode 100644 index 00000000..3d659927 --- /dev/null +++ b/include/VBox/err.sed @@ -0,0 +1,66 @@ +## @file +# SED script for converting VBox/err.h to .mac. +# + +# +# Copyright (C) 2006-2022 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# The contents of this file may alternatively be used under the terms +# of the Common Development and Distribution License Version 1.0 +# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +# in the VirtualBox 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. +# +# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +# + +# Pass thru the file header and copyright. +1,/^\#ifndef/{ +/^\#ifndef/b next +s/^[/ ]// +s/^\*\//;/ +s/\*/;/g +3s/^.*$/;\n; Automatically generated by err.sed. DO NOT EDIT!\n;/ +b end +} +:next + +# Handle text inside the markers. +/SED-START/,/SED-END/{ + +# if (#define) goto defines +/^[[:space:]]*#[[:space:]]*define/b defines + +} + +# Everything else is deleted! +d +b end + +## +# Convert the defines +:defines +s/^[[:space:]]*#[[:space:]]*define[[:space:]]*\([[:alnum:]_]*\)[[:space:]]*\(.*\)[[:space:]]*$/%define \1 \2/ +b end + +# next expression +:end diff --git a/include/VBox/hgcmsvc.h b/include/VBox/hgcmsvc.h new file mode 100644 index 00000000..eba36f40 --- /dev/null +++ b/include/VBox/hgcmsvc.h @@ -0,0 +1,745 @@ +/** @file + * Host-Guest Communication Manager (HGCM) - Service library definitions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_hgcmsvc_h +#define VBOX_INCLUDED_hgcmsvc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assert.h> +#include <iprt/stdarg.h> +#include <iprt/string.h> +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <iprt/err.h> +#ifdef IN_RING3 +# include <iprt/mem.h> +# include <VBox/err.h> +# include <VBox/vmm/stam.h> +# include <VBox/vmm/dbgf.h> +# include <VBox/vmm/ssm.h> +#endif +#ifdef VBOX_TEST_HGCM_PARMS +# include <iprt/test.h> +#endif + +/** @todo proper comments. */ + +/** + * Service interface version. + * + * Includes layout of both VBOXHGCMSVCFNTABLE and VBOXHGCMSVCHELPERS. + * + * A service can work with these structures if major version + * is equal and minor version of service is <= version of the + * structures. + * + * For example when a new helper is added at the end of helpers + * structure, then the minor version will be increased. All older + * services still can work because they have their old helpers + * unchanged. + * + * Revision history. + * 1.1->2.1 Because the pfnConnect now also has the pvClient parameter. + * 2.1->2.2 Because pfnSaveState and pfnLoadState were added + * 2.2->3.1 Because pfnHostCall is now synchronous, returns rc, and parameters were changed + * 3.1->3.2 Because pfnRegisterExtension was added + * 3.2->3.3 Because pfnDisconnectClient helper was added + * 3.3->4.1 Because the pvService entry and parameter was added + * 4.1->4.2 Because the VBOX_HGCM_SVC_PARM_CALLBACK parameter type was added + * 4.2->5.1 Removed the VBOX_HGCM_SVC_PARM_CALLBACK parameter type, as + * this problem is already solved by service extension callbacks + * 5.1->6.1 Because pfnCall got a new parameter. Also new helpers. (VBox 6.0) + * 6.1->6.2 Because pfnCallComplete starts returning a status code (VBox 6.0). + * 6.2->6.3 Because pfnGetRequestor was added (VBox 6.0). + * 6.3->6.4 Because pfnConnect got an additional parameter (VBox 6.0). + * 6.4->6.5 Because pfnGetVMMDevSessionId was added pfnLoadState got the version + * parameter (VBox 6.0). + * 6.5->7.1 Because pfnNotify was added (VBox 6.0). + * 7.1->8.1 Because pfnCancelled & pfnIsCallCancelled were added (VBox 6.0). + * 8.1->9.1 Because pfnDisconnectClient was (temporarily) removed, and + * acMaxClients and acMaxCallsPerClient added (VBox 6.1.26). + * 9.1->10.1 Because pfnDisconnectClient was added back (VBox 6.1.28). + * 10.1->11.1 Because pVMM added to pfnSaveState & pfnLoadState (VBox 7.0). + */ +#define VBOX_HGCM_SVC_VERSION_MAJOR (0x000b) +#define VBOX_HGCM_SVC_VERSION_MINOR (0x0001) +#define VBOX_HGCM_SVC_VERSION ((VBOX_HGCM_SVC_VERSION_MAJOR << 16) + VBOX_HGCM_SVC_VERSION_MINOR) + + +/** Typed pointer to distinguish a call to service. */ +struct VBOXHGCMCALLHANDLE_TYPEDEF; +typedef struct VBOXHGCMCALLHANDLE_TYPEDEF *VBOXHGCMCALLHANDLE; + +/** Service helpers pointers table. */ +typedef struct VBOXHGCMSVCHELPERS +{ + /** The service has processed the Call request. */ + DECLR3CALLBACKMEMBER(int, pfnCallComplete, (VBOXHGCMCALLHANDLE callHandle, int32_t rc)); + + void *pvInstance; + + /** + * The service disconnects the client. + * + * This can only be used during VBOXHGCMSVCFNTABLE::pfnConnect or + * VBOXHGCMSVCFNTABLE::pfnDisconnect and will fail if called out side that + * context. Using this on the new client during VBOXHGCMSVCFNTABLE::pfnConnect + * is not advisable, it would be better to just return a failure status for that + * and it will be done automatically. (It is not possible to call this method + * on a client passed to VBOXHGCMSVCFNTABLE::pfnDisconnect.) + * + * There will be no VBOXHGCMSVCFNTABLE::pfnDisconnect callback for a client + * disconnected in this manner. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the client ID was not found. + * @retval VERR_INVALID_CONTEXT if not called during connect or disconnect. + * + * @remarks Used by external parties, so don't remove just because we don't use + * it ourselves. + */ + DECLR3CALLBACKMEMBER(int, pfnDisconnectClient, (void *pvInstance, uint32_t idClient)); + + /** + * Check if the @a callHandle is for a call restored and re-submitted from saved state. + * + * @returns true if restored, false if not. + * @param callHandle The call we're checking up on. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsCallRestored, (VBOXHGCMCALLHANDLE callHandle)); + + /** + * Check if the @a callHandle is for a cancelled call. + * + * @returns true if cancelled, false if not. + * @param callHandle The call we're checking up on. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsCallCancelled, (VBOXHGCMCALLHANDLE callHandle)); + + /** Access to STAMR3RegisterV. */ + DECLR3CALLBACKMEMBER(int, pfnStamRegisterV,(void *pvInstance, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list va) + RT_IPRT_FORMAT_ATTR(7, 0)); + /** Access to STAMR3DeregisterV. */ + DECLR3CALLBACKMEMBER(int, pfnStamDeregisterV,(void *pvInstance, const char *pszPatFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0)); + + /** Access to DBGFR3InfoRegisterExternal. */ + DECLR3CALLBACKMEMBER(int, pfnInfoRegister,(void *pvInstance, const char *pszName, const char *pszDesc, + PFNDBGFHANDLEREXT pfnHandler, void *pvUser)); + /** Access to DBGFR3InfoDeregisterExternal. */ + DECLR3CALLBACKMEMBER(int, pfnInfoDeregister,(void *pvInstance, const char *pszName)); + + /** + * Retrieves the VMMDevRequestHeader::fRequestor value. + * + * @returns The field value, VMMDEV_REQUESTOR_LEGACY if not supported by the + * guest, VMMDEV_REQUESTOR_LOWEST if invalid call. + * @param hCall The call we're checking up on. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetRequestor, (VBOXHGCMCALLHANDLE hCall)); + + /** + * Retrieves VMMDevState::idSession. + * + * @returns current VMMDev session ID value. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnGetVMMDevSessionId, (void *pvInstance)); + +} VBOXHGCMSVCHELPERS; + +typedef VBOXHGCMSVCHELPERS *PVBOXHGCMSVCHELPERS; + +#if defined(IN_RING3) || defined(IN_SLICKEDIT) + +/** Wrapper around STAMR3RegisterF. */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(7, 8) +HGCMSvcHlpStamRegister(PVBOXHGCMSVCHELPERS pHlp, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, const char *pszDesc, const char *pszName, ...) +{ + int rc; + va_list va; + va_start(va, pszName); + rc = pHlp->pfnStamRegisterV(pHlp->pvInstance, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va); + va_end(va); + return rc; +} + +/** Wrapper around STAMR3RegisterV. */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(7, 0) +HGCMSvcHlpStamRegisterV(PVBOXHGCMSVCHELPERS pHlp, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list va) +{ + return pHlp->pfnStamRegisterV(pHlp->pvInstance, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va); +} + +/** Wrapper around STAMR3DeregisterF. */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(2, 3) HGCMSvcHlpStamDeregister(PVBOXHGCMSVCHELPERS pHlp, const char *pszPatFmt, ...) +{ + int rc; + va_list va; + va_start(va, pszPatFmt); + rc = pHlp->pfnStamDeregisterV(pHlp->pvInstance, pszPatFmt, va); + va_end(va); + return rc; +} + +/** Wrapper around STAMR3DeregisterV. */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(2, 0) HGCMSvcHlpStamDeregisterV(PVBOXHGCMSVCHELPERS pHlp, const char *pszPatFmt, va_list va) +{ + return pHlp->pfnStamDeregisterV(pHlp->pvInstance, pszPatFmt, va); +} + +/** Wrapper around DBGFR3InfoRegisterExternal. */ +DECLINLINE(int) HGCMSvcHlpInfoRegister(PVBOXHGCMSVCHELPERS pHlp, const char *pszName, const char *pszDesc, + PFNDBGFHANDLEREXT pfnHandler, void *pvUser) +{ + return pHlp->pfnInfoRegister(pHlp->pvInstance, pszName, pszDesc, pfnHandler, pvUser); +} + +/** Wrapper around DBGFR3InfoDeregisterExternal. */ +DECLINLINE(int) HGCMSvcHlpInfoDeregister(PVBOXHGCMSVCHELPERS pHlp, const char *pszName) +{ + return pHlp->pfnInfoDeregister(pHlp->pvInstance, pszName); +} + +#endif /* IN_RING3 */ + + +#define VBOX_HGCM_SVC_PARM_INVALID (0U) +#define VBOX_HGCM_SVC_PARM_32BIT (1U) +#define VBOX_HGCM_SVC_PARM_64BIT (2U) +#define VBOX_HGCM_SVC_PARM_PTR (3U) +#define VBOX_HGCM_SVC_PARM_PAGES (4U) + +/** VBOX_HGCM_SVC_PARM_PAGES specific data. */ +typedef struct VBOXHGCMSVCPARMPAGES +{ + uint32_t cb; + uint16_t cPages; + uint16_t u16Padding; + void **papvPages; +} VBOXHGCMSVCPARMPAGES; +typedef VBOXHGCMSVCPARMPAGES *PVBOXHGCMSVCPARMPAGES; + +typedef struct VBOXHGCMSVCPARM +{ + /** VBOX_HGCM_SVC_PARM_* values. */ + uint32_t type; + + union + { + uint32_t uint32; + uint64_t uint64; + struct + { + uint32_t size; + void *addr; + } pointer; + /** VBOX_HGCM_SVC_PARM_PAGES */ + VBOXHGCMSVCPARMPAGES Pages; + } u; +} VBOXHGCMSVCPARM; + +/** Extract an uint32_t value from an HGCM parameter structure. */ +DECLINLINE(int) HGCMSvcGetU32(VBOXHGCMSVCPARM *pParm, uint32_t *pu32) +{ + int rc = VINF_SUCCESS; + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(pu32, VERR_INVALID_POINTER); + if (pParm->type != VBOX_HGCM_SVC_PARM_32BIT) + rc = VERR_INVALID_PARAMETER; + if (RT_SUCCESS(rc)) + *pu32 = pParm->u.uint32; + return rc; +} + +/** Extract an uint64_t value from an HGCM parameter structure. */ +DECLINLINE(int) HGCMSvcGetU64(VBOXHGCMSVCPARM *pParm, uint64_t *pu64) +{ + int rc = VINF_SUCCESS; + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(pu64, VERR_INVALID_POINTER); + if (pParm->type != VBOX_HGCM_SVC_PARM_64BIT) + rc = VERR_INVALID_PARAMETER; + if (RT_SUCCESS(rc)) + *pu64 = pParm->u.uint64; + return rc; +} + +/** Extract an pointer value from an HGCM parameter structure. */ +DECLINLINE(int) HGCMSvcGetPv(VBOXHGCMSVCPARM *pParm, void **ppv, uint32_t *pcb) +{ + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(ppv, VERR_INVALID_POINTER); + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + if (pParm->type == VBOX_HGCM_SVC_PARM_PTR) + { + *ppv = pParm->u.pointer.addr; + *pcb = pParm->u.pointer.size; + return VINF_SUCCESS; + } + + return VERR_INVALID_PARAMETER; +} + +/** Extract a constant pointer value from an HGCM parameter structure. */ +DECLINLINE(int) HGCMSvcGetPcv(VBOXHGCMSVCPARM *pParm, const void **ppv, uint32_t *pcb) +{ + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(ppv, VERR_INVALID_POINTER); + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + if (pParm->type == VBOX_HGCM_SVC_PARM_PTR) + { + *ppv = (const void *)pParm->u.pointer.addr; + *pcb = pParm->u.pointer.size; + return VINF_SUCCESS; + } + + return VERR_INVALID_PARAMETER; +} + +/** Extract a valid pointer to a non-empty buffer from an HGCM parameter + * structure. */ +DECLINLINE(int) HGCMSvcGetBuf(VBOXHGCMSVCPARM *pParm, void **ppv, uint32_t *pcb) +{ + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(ppv, VERR_INVALID_POINTER); + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + if ( pParm->type == VBOX_HGCM_SVC_PARM_PTR + && RT_VALID_PTR(pParm->u.pointer.addr) + && pParm->u.pointer.size > 0) + { + *ppv = pParm->u.pointer.addr; + *pcb = pParm->u.pointer.size; + return VINF_SUCCESS; + } + + return VERR_INVALID_PARAMETER; +} + +/** Extract a valid pointer to a non-empty constant buffer from an HGCM + * parameter structure. */ +DECLINLINE(int) HGCMSvcGetCBuf(VBOXHGCMSVCPARM *pParm, const void **ppv, uint32_t *pcb) +{ + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(ppv, VERR_INVALID_POINTER); + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + if ( pParm->type == VBOX_HGCM_SVC_PARM_PTR + && RT_VALID_PTR(pParm->u.pointer.addr) + && pParm->u.pointer.size > 0) + { + *ppv = (const void *)pParm->u.pointer.addr; + *pcb = pParm->u.pointer.size; + return VINF_SUCCESS; + } + + return VERR_INVALID_PARAMETER; +} + +/** Extract a string value from an HGCM parameter structure. */ +DECLINLINE(int) HGCMSvcGetStr(VBOXHGCMSVCPARM *pParm, char **ppch, uint32_t *pcb) +{ + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(ppch, VERR_INVALID_POINTER); + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + if ( pParm->type == VBOX_HGCM_SVC_PARM_PTR + && RT_VALID_PTR(pParm->u.pointer.addr) + && pParm->u.pointer.size > 0) + { + int rc = RTStrValidateEncodingEx((char *)pParm->u.pointer.addr, + pParm->u.pointer.size, + RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); + if (RT_FAILURE(rc)) + return rc; + *ppch = (char *)pParm->u.pointer.addr; + *pcb = pParm->u.pointer.size; + return VINF_SUCCESS; + } + + return VERR_INVALID_PARAMETER; +} + +/** Extract a constant string value from an HGCM parameter structure. */ +DECLINLINE(int) HGCMSvcGetCStr(VBOXHGCMSVCPARM *pParm, const char **ppch, uint32_t *pcb) +{ + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(ppch, VERR_INVALID_POINTER); + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + if ( pParm->type == VBOX_HGCM_SVC_PARM_PTR + && RT_VALID_PTR(pParm->u.pointer.addr) + && pParm->u.pointer.size > 0) + { + int rc = RTStrValidateEncodingEx((char *)pParm->u.pointer.addr, + pParm->u.pointer.size, + RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); + if (RT_FAILURE(rc)) + return rc; + *ppch = (char *)pParm->u.pointer.addr; + *pcb = pParm->u.pointer.size; + return VINF_SUCCESS; + } + + return VERR_INVALID_PARAMETER; +} + +/** Extract a constant string value from an HGCM parameter structure. */ +DECLINLINE(int) HGCMSvcGetPsz(VBOXHGCMSVCPARM *pParm, const char **ppch, uint32_t *pcb) +{ + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(ppch, VERR_INVALID_POINTER); + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + if ( pParm->type == VBOX_HGCM_SVC_PARM_PTR + && RT_VALID_PTR(pParm->u.pointer.addr) + && pParm->u.pointer.size > 0) + { + int rc = RTStrValidateEncodingEx((const char *)pParm->u.pointer.addr, + pParm->u.pointer.size, + RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); + if (RT_FAILURE(rc)) + return rc; + *ppch = (const char *)pParm->u.pointer.addr; + *pcb = pParm->u.pointer.size; + return VINF_SUCCESS; + } + + return VERR_INVALID_PARAMETER; +} + +/** Set a uint32_t value to an HGCM parameter structure */ +DECLINLINE(void) HGCMSvcSetU32(VBOXHGCMSVCPARM *pParm, uint32_t u32) +{ + AssertPtr(pParm); + pParm->type = VBOX_HGCM_SVC_PARM_32BIT; + pParm->u.uint32 = u32; +} + +/** Set a uint64_t value to an HGCM parameter structure */ +DECLINLINE(void) HGCMSvcSetU64(VBOXHGCMSVCPARM *pParm, uint64_t u64) +{ + AssertPtr(pParm); + pParm->type = VBOX_HGCM_SVC_PARM_64BIT; + pParm->u.uint64 = u64; +} + +/** Set a pointer value to an HGCM parameter structure */ +DECLINLINE(void) HGCMSvcSetPv(VBOXHGCMSVCPARM *pParm, void *pv, uint32_t cb) +{ + AssertPtr(pParm); + pParm->type = VBOX_HGCM_SVC_PARM_PTR; + pParm->u.pointer.addr = pv; + pParm->u.pointer.size = cb; +} + +/** Set a pointer value to an HGCM parameter structure */ +DECLINLINE(void) HGCMSvcSetStr(VBOXHGCMSVCPARM *pParm, const char *psz) +{ + AssertPtr(pParm); + pParm->type = VBOX_HGCM_SVC_PARM_PTR; + pParm->u.pointer.addr = (void *)psz; + pParm->u.pointer.size = (uint32_t)strlen(psz) + 1; +} + +#ifdef __cplusplus +# ifdef IPRT_INCLUDED_cpp_ministring_h +/** Set a const string value to an HGCM parameter structure */ +DECLINLINE(void) HGCMSvcSetRTCStr(VBOXHGCMSVCPARM *pParm, const RTCString &rString) +{ + AssertPtr(pParm); + pParm->type = VBOX_HGCM_SVC_PARM_PTR; + pParm->u.pointer.addr = (void *)rString.c_str(); + pParm->u.pointer.size = (uint32_t)rString.length() + 1; +} +# endif +#endif + +#if defined(IN_RING3) && defined(VBOX_INCLUDED_vmm_vmmr3vtable_h) + +/** + * Puts (serializes) a VBOXHGCMSVCPARM struct into SSM. + * + * @returns VBox status code. + * @param pParm VBOXHGCMSVCPARM to serialize. + * @param pSSM SSM handle to serialize to. + * @param pVMM The VMM vtable. + */ +DECLINLINE(int) HGCMSvcSSMR3Put(VBOXHGCMSVCPARM *pParm, PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM) +{ + int rc; + + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(pSSM, VERR_INVALID_POINTER); + + rc = pVMM->pfnSSMR3PutU32(pSSM, sizeof(VBOXHGCMSVCPARM)); + AssertRCReturn(rc, rc); + rc = pVMM->pfnSSMR3PutU32(pSSM, pParm->type); + AssertRCReturn(rc, rc); + + switch (pParm->type) + { + case VBOX_HGCM_SVC_PARM_32BIT: + rc = pVMM->pfnSSMR3PutU32(pSSM, pParm->u.uint32); + break; + case VBOX_HGCM_SVC_PARM_64BIT: + rc = pVMM->pfnSSMR3PutU64(pSSM, pParm->u.uint64); + break; + case VBOX_HGCM_SVC_PARM_PTR: + rc = pVMM->pfnSSMR3PutU32(pSSM, pParm->u.pointer.size); + if (RT_SUCCESS(rc)) + rc = pVMM->pfnSSMR3PutMem(pSSM, pParm->u.pointer.addr, pParm->u.pointer.size); + break; + default: + AssertMsgFailed(("Paramter type %RU32 not implemented yet\n", pParm->type)); + rc = VERR_NOT_IMPLEMENTED; + break; + } + + return rc; +} + +/** + * Gets (loads) a VBOXHGCMSVCPARM struct from SSM. + * + * @returns VBox status code. + * @param pParm VBOXHGCMSVCPARM to load into. Must be zero'ed. + * @param pSSM SSM handle to load from. + * @param pVMM The VMM vtable. + */ +DECLINLINE(int) HGCMSvcSSMR3Get(VBOXHGCMSVCPARM *pParm, PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM) +{ + uint32_t cbParm; + int rc; + + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(pSSM, VERR_INVALID_POINTER); + + rc = pVMM->pfnSSMR3GetU32(pSSM, &cbParm); + AssertRCReturn(rc, rc); + AssertReturn(cbParm == sizeof(VBOXHGCMSVCPARM), VERR_SSM_DATA_UNIT_FORMAT_CHANGED); + + rc = pVMM->pfnSSMR3GetU32(pSSM, &pParm->type); + AssertRCReturn(rc, rc); + + switch (pParm->type) + { + case VBOX_HGCM_SVC_PARM_32BIT: + { + rc = pVMM->pfnSSMR3GetU32(pSSM, &pParm->u.uint32); + AssertRCReturn(rc, rc); + break; + } + + case VBOX_HGCM_SVC_PARM_64BIT: + { + rc = pVMM->pfnSSMR3GetU64(pSSM, &pParm->u.uint64); + AssertRCReturn(rc, rc); + break; + } + + case VBOX_HGCM_SVC_PARM_PTR: + { + AssertMsgReturn(pParm->u.pointer.size == 0, + ("Pointer size parameter already in use (or not initialized)\n"), VERR_INVALID_PARAMETER); + + rc = pVMM->pfnSSMR3GetU32(pSSM, &pParm->u.pointer.size); + AssertRCReturn(rc, rc); + + AssertMsgReturn(pParm->u.pointer.addr == NULL, + ("Pointer parameter already in use (or not initialized)\n"), VERR_INVALID_PARAMETER); + + pParm->u.pointer.addr = RTMemAlloc(pParm->u.pointer.size); + AssertPtrReturn(pParm->u.pointer.addr, VERR_NO_MEMORY); + rc = pVMM->pfnSSMR3GetMem(pSSM, pParm->u.pointer.addr, pParm->u.pointer.size); + + AssertRCReturn(rc, rc); + break; + } + + default: + AssertMsgFailedReturn(("Paramter type %RU32 not implemented yet\n", pParm->type), + VERR_NOT_IMPLEMENTED); + break; + } + + return VINF_SUCCESS; +} + +#endif /* IN_RING3 */ + +typedef VBOXHGCMSVCPARM *PVBOXHGCMSVCPARM; + + +/** Service specific extension callback. + * This callback is called by the service to perform service specific operation. + * + * @param pvExtension The extension pointer. + * @param u32Function What the callback is supposed to do. + * @param pvParm The function parameters. + * @param cbParms The size of the function parameters. + */ +typedef DECLCALLBACKTYPE(int, FNHGCMSVCEXT,(void *pvExtension, uint32_t u32Function, void *pvParm, uint32_t cbParms)); +typedef FNHGCMSVCEXT *PFNHGCMSVCEXT; + +/** + * Notification event. + */ +typedef enum HGCMNOTIFYEVENT +{ + HGCMNOTIFYEVENT_INVALID = 0, + HGCMNOTIFYEVENT_POWER_ON, + HGCMNOTIFYEVENT_RESUME, + HGCMNOTIFYEVENT_SUSPEND, + HGCMNOTIFYEVENT_RESET, + HGCMNOTIFYEVENT_POWER_OFF, + HGCMNOTIFYEVENT_END, + HGCMNOTIFYEVENT_32BIT_HACK = 0x7fffffff +} HGCMNOTIFYEVENT; + +/** @name HGCM_CLIENT_CATEGORY_XXX - Client categories + * @{ */ +#define HGCM_CLIENT_CATEGORY_KERNEL 0 /**< Guest kernel mode and legacy client. */ +#define HGCM_CLIENT_CATEGORY_ROOT 1 /**< Guest root or admin client. */ +#define HGCM_CLIENT_CATEGORY_USER 2 /**< Regular guest user client. */ +#define HGCM_CLIENT_CATEGORY_MAX 3 /**< Max number of categories. */ +/** @} */ + + +/** The Service DLL entry points. + * + * HGCM will call the DLL "VBoxHGCMSvcLoad" + * function and the DLL must fill in the VBOXHGCMSVCFNTABLE + * with function pointers. + * + * @note The structure is used in separately compiled binaries so an explicit + * packing is required. + */ +typedef struct VBOXHGCMSVCFNTABLE +{ + /** @name Filled by HGCM + * @{ */ + + /** Size of the structure. */ + uint32_t cbSize; + + /** Version of the structure, including the helpers. (VBOX_HGCM_SVC_VERSION) */ + uint32_t u32Version; + + PVBOXHGCMSVCHELPERS pHelpers; + /** @} */ + + /** @name Filled in by the service. + * @{ */ + + /** Size of client information the service want to have. */ + uint32_t cbClient; + + /** The maximum number of clients per category. Leave entries as zero for defaults. */ + uint32_t acMaxClients[HGCM_CLIENT_CATEGORY_MAX]; + /** The maximum number of concurrent calls per client for each category. + * Leave entries as as zero for default. */ + uint32_t acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_MAX]; + /** The HGCM_CLIENT_CATEGORY_XXX value for legacy clients. + * Defaults to HGCM_CLIENT_CATEGORY_KERNEL. */ + uint32_t idxLegacyClientCategory; + + /** Uninitialize service */ + DECLR3CALLBACKMEMBER(int, pfnUnload, (void *pvService)); + + /** Inform the service about a client connection. */ + DECLR3CALLBACKMEMBER(int, pfnConnect, (void *pvService, uint32_t u32ClientID, void *pvClient, uint32_t fRequestor, bool fRestoring)); + + /** Inform the service that the client wants to disconnect. */ + DECLR3CALLBACKMEMBER(int, pfnDisconnect, (void *pvService, uint32_t u32ClientID, void *pvClient)); + + /** Service entry point. + * Return code is passed to pfnCallComplete callback. + */ + DECLR3CALLBACKMEMBER(void, pfnCall, (void *pvService, VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, + uint32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival)); + /** Informs the service that a call was cancelled by the guest (optional). + * + * This is called for guest calls, connect requests and disconnect requests. + * There is unfortunately no way of obtaining the call handle for a guest call + * or otherwise identify the request, so that's left to the service to figure + * out using VBOXHGCMSVCHELPERS::pfnIsCallCancelled. Because this is an + * asynchronous call, the service may have completed the request already. + */ + DECLR3CALLBACKMEMBER(void, pfnCancelled, (void *pvService, uint32_t idClient, void *pvClient)); + + /** Host Service entry point meant for privileged features invisible to the guest. + * Return code is passed to pfnCallComplete callback. + */ + DECLR3CALLBACKMEMBER(int, pfnHostCall, (void *pvService, uint32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])); + + /** Inform the service about a VM save operation. */ + DECLR3CALLBACKMEMBER(int, pfnSaveState, (void *pvService, uint32_t u32ClientID, void *pvClient, + PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM)); + + /** Inform the service about a VM load operation. */ + DECLR3CALLBACKMEMBER(int, pfnLoadState, (void *pvService, uint32_t u32ClientID, void *pvClient, + PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, uint32_t uVersion)); + + /** Register a service extension callback. */ + DECLR3CALLBACKMEMBER(int, pfnRegisterExtension, (void *pvService, PFNHGCMSVCEXT pfnExtension, void *pvExtension)); + + /** Notification (VM state). */ + DECLR3CALLBACKMEMBER(void, pfnNotify, (void *pvService, HGCMNOTIFYEVENT enmEvent)); + + /** User/instance data pointer for the service. */ + void *pvService; + + /** @} */ +} VBOXHGCMSVCFNTABLE; + + +/** @name HGCM saved state + * @note Need to be here so we can add saved to service which doesn't have it. + * @{ */ +/** HGCM saved state version. */ +#define HGCM_SAVED_STATE_VERSION 3 +/** HGCM saved state version w/o client state indicators. */ +#define HGCM_SAVED_STATE_VERSION_V2 2 +/** @} */ + + +/** Service initialization entry point. */ +typedef DECLCALLBACKTYPE(int, FNVBOXHGCMSVCLOAD,(VBOXHGCMSVCFNTABLE *ptable)); +typedef FNVBOXHGCMSVCLOAD *PFNVBOXHGCMSVCLOAD; +#define VBOX_HGCM_SVCLOAD_NAME "VBoxHGCMSvcLoad" + +#endif /* !VBOX_INCLUDED_hgcmsvc_h */ diff --git a/include/VBox/intnet.h b/include/VBox/intnet.h new file mode 100644 index 00000000..41ee508c --- /dev/null +++ b/include/VBox/intnet.h @@ -0,0 +1,1348 @@ +/** @file + * INTNET - Internal Networking. (DEV,++) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_intnet_h +#define VBOX_INCLUDED_intnet_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/stam.h> +#include <VBox/sup.h> +#include <iprt/assert.h> +#include <iprt/asm.h> + +RT_C_DECLS_BEGIN + + +/** The userspace internal network service identifier. */ +#if defined(RT_OS_DARWIN) && defined(VBOX_WITH_INTNET_SERVICE_IN_R3) +/** The XPC service identififer. */ +# define INTNET_R3_SVC_NAME "org.virtualbox.intnet" +/** The high 32 bits pattern for the "rc" status code field to recognize errors + * where xpc_dictionary_get_int64() might return 0 which could be confused with VINF_SUCCESS. */ +# define INTNET_R3_SVC_RC_PATTERN ((uint64_t)RT_MAKE_U32_FROM_U8('V', 'B', 'O', 'X')) +/** Constructs a signd 64bit value for the given 32-bit status code. */ +# define INTNET_R3_SVC_SET_RC(a_rc) ((INTNET_R3_SVC_RC_PATTERN << 32) | (uint64_t)(a_rc)) +/** Gets the status code from the given 64-bit signed status code value. */ +# define INTNET_R3_SVC_GET_RC(a_RcVal) ((int32_t)(a_RcVal)) +/** Checks whether the given 64-bit signed status code value encodes a valid IPRT/VBOX status code. */ +# define INTNET_R3_SVC_IS_VALID_RC(a_RcVal) (((a_RcVal) >> 32) == INTNET_R3_SVC_RC_PATTERN) +#endif + + +/** + * Generic two-sided ring buffer. + * + * The deal is that there is exactly one writer and one reader. + * When offRead equals offWrite the buffer is empty. In the other + * extreme the writer will not use the last free byte in the buffer. + */ +typedef struct INTNETRINGBUF +{ + /** The offset from this structure to the start of the buffer. */ + uint32_t offStart; + /** The offset from this structure to the end of the buffer. (exclusive). */ + uint32_t offEnd; + /** The current read offset. */ + uint32_t volatile offReadX; + /** Alignment. */ + uint32_t u32Align0; + + /** The committed write offset. */ + uint32_t volatile offWriteCom; + /** Writer internal current write offset. + * This is ahead of offWriteCom when buffer space is handed to a third party for + * data gathering. offWriteCom will be assigned this value by the writer then + * the frame is ready. */ + uint32_t volatile offWriteInt; + /** The number of bytes written (not counting overflows). */ + STAMCOUNTER cbStatWritten; + /** The number of frames written (not counting overflows). */ + STAMCOUNTER cStatFrames; + /** The number of overflows. */ + STAMCOUNTER cOverflows; +} INTNETRINGBUF; +AssertCompileSize(INTNETRINGBUF, 48); +/** Pointer to a ring buffer. */ +typedef INTNETRINGBUF *PINTNETRINGBUF; + +/** The alignment of a ring buffer. */ +#define INTNETRINGBUF_ALIGNMENT sizeof(INTNETHDR) + +/** + * Asserts the sanity of the specified INTNETRINGBUF structure. + */ +#ifdef VBOX_STRICT +# define INTNETRINGBUF_ASSERT_SANITY(pRingBuf) \ + do \ + { \ + AssertPtr(pRingBuf); \ + { \ + uint32_t const offWriteCom = (pRingBuf)->offWriteCom; \ + uint32_t const offRead = (pRingBuf)->offReadX; \ + uint32_t const offWriteInt = (pRingBuf)->offWriteInt; \ + \ + AssertMsg(offWriteCom == RT_ALIGN_32(offWriteCom, INTNETHDR_ALIGNMENT), ("%#x\n", offWriteCom)); \ + AssertMsg(offWriteCom >= (pRingBuf)->offStart, ("%#x %#x\n", offWriteCom, (pRingBuf)->offStart)); \ + AssertMsg(offWriteCom < (pRingBuf)->offEnd, ("%#x %#x\n", offWriteCom, (pRingBuf)->offEnd)); \ + \ + AssertMsg(offRead == RT_ALIGN_32(offRead, INTNETHDR_ALIGNMENT), ("%#x\n", offRead)); \ + AssertMsg(offRead >= (pRingBuf)->offStart, ("%#x %#x\n", offRead, (pRingBuf)->offStart)); \ + AssertMsg(offRead < (pRingBuf)->offEnd, ("%#x %#x\n", offRead, (pRingBuf)->offEnd)); \ + \ + AssertMsg(offWriteInt == RT_ALIGN_32(offWriteInt, INTNETHDR_ALIGNMENT), ("%#x\n", offWriteInt)); \ + AssertMsg(offWriteInt >= (pRingBuf)->offStart, ("%#x %#x\n", offWriteInt, (pRingBuf)->offStart)); \ + AssertMsg(offWriteInt < (pRingBuf)->offEnd, ("%#x %#x\n", offWriteInt, (pRingBuf)->offEnd)); \ + AssertMsg( offRead <= offWriteCom \ + ? offWriteCom <= offWriteInt || offWriteInt < offRead \ + : offWriteCom <= offWriteInt, \ + ("W=%#x W'=%#x R=%#x\n", offWriteCom, offWriteInt, offRead)); \ + } \ + } while (0) +#else +# define INTNETRINGBUF_ASSERT_SANITY(pRingBuf) do { } while (0) +#endif + + + +/** + * A interface buffer. + */ +typedef struct INTNETBUF +{ + /** Magic number (INTNETBUF_MAGIC). */ + uint32_t u32Magic; + /** The size of the entire buffer. */ + uint32_t cbBuf; + /** The size of the send area. */ + uint32_t cbSend; + /** The size of the receive area. */ + uint32_t cbRecv; + /** The receive buffer. */ + INTNETRINGBUF Recv; + /** The send buffer. */ + INTNETRINGBUF Send; + /** Number of times yields help solve an overflow. */ + STAMCOUNTER cStatYieldsOk; + /** Number of times yields didn't help solve an overflow. */ + STAMCOUNTER cStatYieldsNok; + /** Number of lost packets due to overflows. */ + STAMCOUNTER cStatLost; + /** Number of bad frames (both rings). */ + STAMCOUNTER cStatBadFrames; + /** Reserved for future use. */ + STAMCOUNTER aStatReserved[2]; + /** Reserved for future send profiling. */ + STAMPROFILE StatSend1; + /** Reserved for future send profiling. */ + STAMPROFILE StatSend2; + /** Reserved for future receive profiling. */ + STAMPROFILE StatRecv1; + /** Reserved for future receive profiling. */ + STAMPROFILE StatRecv2; + /** Reserved for future profiling. */ + STAMPROFILE StatReserved; +} INTNETBUF; +AssertCompileSize(INTNETBUF, 320); +AssertCompileMemberOffset(INTNETBUF, Recv, 16); +AssertCompileMemberOffset(INTNETBUF, Send, 64); + +/** Pointer to an interface buffer. */ +typedef INTNETBUF *PINTNETBUF; +/** Pointer to a const interface buffer. */ +typedef INTNETBUF const *PCINTNETBUF; + +/** Magic number for INTNETBUF::u32Magic (Sir William Gerald Golding). */ +#define INTNETBUF_MAGIC UINT32_C(0x19110919) + +/** + * Asserts the sanity of the specified INTNETBUF structure. + */ +#define INTNETBUF_ASSERT_SANITY(pBuf) \ + do \ + { \ + AssertPtr(pBuf); \ + Assert((pBuf)->u32Magic == INTNETBUF_MAGIC); \ + { \ + uint32_t const offRecvStart = (pBuf)->Recv.offStart + RT_UOFFSETOF(INTNETBUF, Recv); \ + uint32_t const offRecvEnd = (pBuf)->Recv.offStart + RT_UOFFSETOF(INTNETBUF, Recv); \ + uint32_t const offSendStart = (pBuf)->Send.offStart + RT_UOFFSETOF(INTNETBUF, Send); \ + uint32_t const offSendEnd = (pBuf)->Send.offStart + RT_UOFFSETOF(INTNETBUF, Send); \ + \ + Assert(offRecvEnd > offRecvStart); \ + Assert(offRecvEnd - offRecvStart == (pBuf)->cbRecv); \ + Assert(offRecvStart == sizeof(INTNETBUF)); \ + \ + Assert(offSendEnd > offSendStart); \ + Assert(offSendEnd - offSendStart == (pBuf)->cbSend); \ + Assert(pffSendEnd <= (pBuf)->cbBuf); \ + \ + Assert(offSendStart == offRecvEnd); \ + } \ + } while (0) + + +/** Internal networking interface handle. */ +typedef uint32_t INTNETIFHANDLE; +/** Pointer to an internal networking interface handle. */ +typedef INTNETIFHANDLE *PINTNETIFHANDLE; + +/** Or mask to obscure the handle index. */ +#define INTNET_HANDLE_MAGIC 0x88880000 +/** Mask to extract the handle index. */ +#define INTNET_HANDLE_INDEX_MASK 0xffff +/** The maximum number of handles (exclusive) */ +#define INTNET_HANDLE_MAX 0xffff +/** Invalid handle. */ +#define INTNET_HANDLE_INVALID (0) + + +/** + * The frame header. + * + * The header is intentionally 8 bytes long. It will always + * start at an 8 byte aligned address. Assuming that the buffer + * size is a multiple of 8 bytes, that means that we can guarantee + * that the entire header is contiguous in both virtual and physical + * memory. + */ +typedef struct INTNETHDR +{ + /** The size of the frame. */ + uint32_t cbFrame : 24; + /** Header type. This is currently serving as a magic, it + * can be extended later to encode special command frames and stuff. */ + uint32_t u8Type : 8; + /** The offset from the start of this header to where the actual frame starts. + * This is used to keep the frame it self contiguous in virtual memory and + * thereby both simplify access as well as the descriptor. */ + int32_t offFrame; +} INTNETHDR; +AssertCompileSize(INTNETHDR, 8); +AssertCompileSizeAlignment(INTNETBUF, sizeof(INTNETHDR)); +/** Pointer to a frame header.*/ +typedef INTNETHDR *PINTNETHDR; +/** Pointer to a const frame header.*/ +typedef INTNETHDR const *PCINTNETHDR; + +/** The alignment of a frame header. */ +#define INTNETHDR_ALIGNMENT sizeof(INTNETHDR) +AssertCompile(sizeof(INTNETHDR) == INTNETHDR_ALIGNMENT); +AssertCompile(INTNETHDR_ALIGNMENT <= INTNETRINGBUF_ALIGNMENT); + +/** @name Frame types (INTNETHDR::u8Type). + * @{ */ +/** Normal frames. */ +#define INTNETHDR_TYPE_FRAME 0x42 +/** Padding frames. */ +#define INTNETHDR_TYPE_PADDING 0x53 +/** Generic segment offload frames. + * The frame starts with a PDMNETWORKGSO structure which is followed by the + * header template and data. */ +#define INTNETHDR_TYPE_GSO 0x64 +AssertCompileSize(PDMNETWORKGSO, 8); +/** @} */ + +/** + * Asserts the sanity of the specified INTNETHDR. + */ +#ifdef VBOX_STRICT +#define INTNETHDR_ASSERT_SANITY(pHdr, pRingBuf) \ + do \ + { \ + AssertPtr(pHdr); \ + Assert(RT_ALIGN_PT(pHdr, INTNETHDR_ALIGNMENT, INTNETHDR *) == pHdr); \ + Assert( (pHdr)->u8Type == INTNETHDR_TYPE_FRAME \ + || (pHdr)->u8Type == INTNETHDR_TYPE_GSO \ + || (pHdr)->u8Type == INTNETHDR_TYPE_PADDING); \ + { \ + uintptr_t const offHdr = (uintptr_t)pHdr - (uintptr_t)pRingBuf; \ + uintptr_t const offFrame = offHdr + (pHdr)->offFrame; \ + \ + Assert(offHdr >= (pRingBuf)->offStart); \ + Assert(offHdr < (pRingBuf)->offEnd); \ + \ + /* could do more thorough work here... later, perhaps. */ \ + Assert(offFrame >= (pRingBuf)->offStart); \ + Assert(offFrame < (pRingBuf)->offEnd); \ + } \ + } while (0) +#else +# define INTNETHDR_ASSERT_SANITY(pHdr, pRingBuf) do { } while (0) +#endif + + +/** + * Scatter / Gather segment (internal networking). + */ +typedef struct INTNETSEG +{ + /** The physical address. NIL_RTHCPHYS is not set. */ + RTHCPHYS Phys; + /** Pointer to the segment data. */ + void *pv; + /** The segment size. */ + uint32_t cb; +} INTNETSEG; +/** Pointer to a internal networking frame segment. */ +typedef INTNETSEG *PINTNETSEG; +/** Pointer to a internal networking frame segment. */ +typedef INTNETSEG const *PCINTNETSEG; + + +/** + * Scatter / Gather list (internal networking). + * + * This is used when communicating with the trunk port. + */ +typedef struct INTNETSG +{ + /** Owner data, don't touch! */ + void *pvOwnerData; + /** User data. */ + void *pvUserData; + /** User data 2 in case anyone needs it. */ + void *pvUserData2; + /** GSO context information, set the type to invalid if not relevant. */ + PDMNETWORKGSO GsoCtx; + /** The total length of the scatter gather list. */ + uint32_t cbTotal; + /** The number of users (references). + * This is used by the SGRelease code to decide when it can be freed. */ + uint16_t volatile cUsers; + /** Flags, see INTNETSG_FLAGS_* */ + uint16_t volatile fFlags; +#if ARCH_BITS == 64 + /** Alignment padding. */ + uint16_t uPadding; +#endif + /** The number of segments allocated. */ + uint16_t cSegsAlloc; + /** The number of segments actually used. */ + uint16_t cSegsUsed; + /** Variable sized list of segments. */ + INTNETSEG aSegs[1]; +} INTNETSG; +AssertCompileSizeAlignment(INTNETSG, 8); +/** Pointer to a scatter / gather list. */ +typedef INTNETSG *PINTNETSG; +/** Pointer to a const scatter / gather list. */ +typedef INTNETSG const *PCINTNETSG; + +/** @name INTNETSG::fFlags definitions. + * @{ */ +/** Set if the SG is free. */ +#define INTNETSG_FLAGS_FREE RT_BIT_32(1) +/** Set if the SG is a temporary one that will become invalid upon return. + * Try to finish using it before returning, and if that's not possible copy + * to other buffers. + * When not set, the callee should always free the SG. + * Attempts to free it made by the callee will be quietly ignored. */ +#define INTNETSG_FLAGS_TEMP RT_BIT_32(2) +/** ARP packet, IPv4 + MAC. + * @internal */ +#define INTNETSG_FLAGS_ARP_IPV4 RT_BIT_32(3) +/** Copied to the temporary buffer. + * @internal */ +#define INTNETSG_FLAGS_PKT_CP_IN_TMP RT_BIT_32(4) +/** @} */ + + +/** @name Direction (frame source or destination) + * @{ */ +/** To/From the wire. */ +#define INTNETTRUNKDIR_WIRE RT_BIT_32(0) +/** To/From the host. */ +#define INTNETTRUNKDIR_HOST RT_BIT_32(1) +/** Mask of valid bits. */ +#define INTNETTRUNKDIR_VALID_MASK UINT32_C(3) +/** @} */ + +/** + * Switch decisions returned by INTNETTRUNKSWPORT::pfnPreRecv. + */ +typedef enum INTNETSWDECISION +{ + /** The usual invalid zero value. */ + INTNETSWDECISION_INVALID = 0, + /** Everywhere. */ + INTNETSWDECISION_BROADCAST, + /** Only to the internal network. */ + INTNETSWDECISION_INTNET, + /** Only for the trunk (host/wire). */ + INTNETSWDECISION_TRUNK, + /** Used internally to indicate that the packet cannot be handled in the + * current context. */ + INTNETSWDECISION_BAD_CONTEXT, + /** Used internally to indicate that the packet should be dropped. */ + INTNETSWDECISION_DROP, + /** The usual 32-bit type expansion. */ + INTNETSWDECISION_32BIT_HACK = 0x7fffffff +} INTNETSWDECISION; + + +/** + * Network layer address type. + */ +typedef enum INTNETADDRTYPE +{ + /** The invalid 0 entry. */ + kIntNetAddrType_Invalid = 0, + /** IP version 4. */ + kIntNetAddrType_IPv4, + /** IP version 6. */ + kIntNetAddrType_IPv6, + /** IPX. */ + kIntNetAddrType_IPX, + /** The end of the valid values. */ + kIntNetAddrType_End, + /** The usual 32-bit hack. */ + kIntNetAddrType_32BitHack = 0x7fffffff +} INTNETADDRTYPE; + + +/** Pointer to the interface side of a trunk port. */ +typedef struct INTNETTRUNKIFPORT *PINTNETTRUNKIFPORT; + + +/** + * Special variation of INTNETTRUNKIFPORT::pfnRelease for use with + * INTNETTRUNKSWPORT::pfnDisconnect. + * + * @param pIfPort Pointer to the INTNETTRUNKIFPORT instance. + */ +typedef DECLCALLBACKTYPE(void, FNINTNETTRUNKIFPORTRELEASEBUSY,(PINTNETTRUNKIFPORT pIfPort)); +/** Pointer to a FNINTNETTRUNKIFPORTRELEASEBUSY function. */ +typedef FNINTNETTRUNKIFPORTRELEASEBUSY *PFNINTNETTRUNKIFPORTRELEASEBUSY; + + +/** Pointer to the switch side of a trunk port. */ +typedef struct INTNETTRUNKSWPORT *PINTNETTRUNKSWPORT; +/** + * This is the port on the internal network 'switch', i.e. + * what the driver is connected to. + * + * This is only used for the in-kernel trunk connections. + */ +typedef struct INTNETTRUNKSWPORT +{ + /** Structure version number. (INTNETTRUNKSWPORT_VERSION) */ + uint32_t u32Version; + + /** + * Examine the packet and figure out where it is going. + * + * This method is for making packet switching decisions in contexts where + * pfnRecv cannot be called or is no longer applicable. This method can be + * called from any context. + * + * @returns INTNETSWDECISION_BROADCAST, INTNETSWDECISION_INTNET or + * INTNETSWDECISION_TRUNK. The source is excluded from broadcast & + * trunk, of course. + * + * @param pSwitchPort Pointer to this structure. + * @param pvHdrs Pointer to the packet headers. + * @param cbHdrs Size of the packet headers. This must be at least 6 + * bytes (the destination MAC address), but should if + * possible also include any VLAN tag and network + * layer header (wireless mac address sharing). + * @param fSrc Where this frame comes from. Only one bit should be + * set! + * + * @remarks Will only grab the switch table spinlock (interrupt safe). May + * signal an event semaphore iff we're racing network cleanup. The + * caller must be busy when calling. + */ + DECLR0CALLBACKMEMBER(INTNETSWDECISION, pfnPreRecv,(PINTNETTRUNKSWPORT pSwitchPort, + void const *pvHdrs, size_t cbHdrs, uint32_t fSrc)); + + /** + * Incoming frame. + * + * The frame may be modified when the trunk port on the switch is set to share + * the mac address of the host when hitting the wire. Currently frames + * containing ARP packets are subject to this, later other protocols like + * NDP/ICMPv6 may need editing as well when operating in this mode. The edited + * packet should be forwarded to the host/wire when @c false is returned. + * + * @returns true if we've handled it and it should be dropped. + * false if it should hit the wire/host. + * + * @param pSwitchPort Pointer to this structure. + * @param pvIf Pointer to the interface which received this frame + * if available. Can be NULL. + * @param pSG The (scatter /) gather structure for the frame. This + * will only be use during the call, so a temporary one can + * be used. The Phys member will not be used. + * @param fSrc Where this frame comes from. Exactly one bit shall be + * set! + * + * @remarks Will only grab the switch table spinlock (interrupt safe). Will + * signal event semaphores. The caller must be busy when calling. + * + * @remarks NAT and TAP will use this interface. + * + * @todo Do any of the host require notification before frame modifications? + * If so, we'll add a callback to INTNETTRUNKIFPORT for this + * (pfnSGModifying) and a SG flag. + */ + DECLR0CALLBACKMEMBER(bool, pfnRecv,(PINTNETTRUNKSWPORT pSwitchPort, void *pvIf, PINTNETSG pSG, uint32_t fSrc)); + + /** + * Retain a SG. + * + * @param pSwitchPort Pointer to this structure. + * @param pSG Pointer to the (scatter /) gather structure. + * + * @remarks Will not grab any locks. The caller must be busy when calling. + */ + DECLR0CALLBACKMEMBER(void, pfnSGRetain,(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)); + + /** + * Release a SG. + * + * This is called by the pfnXmit code when done with a SG. This may safe + * be done in an asynchronous manner. + * + * @param pSwitchPort Pointer to this structure. + * @param pSG Pointer to the (scatter /) gather structure. + * + * @remarks May signal an event semaphore later on, currently code won't though. + * The caller is busy when making this call. + */ + DECLR0CALLBACKMEMBER(void, pfnSGRelease,(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)); + + /** + * Selects whether outgoing SGs should have their physical address set. + * + * By enabling physical addresses in the scatter / gather segments it should + * be possible to save some unnecessary address translation and memory locking + * in the network stack. (Internal networking knows the physical address for + * all the INTNETBUF data and that it's locked memory.) There is a negative + * side effects though, frames that crosses page boundaries will require + * multiple scather / gather segments. + * + * @returns The old setting. + * + * @param pSwitchPort Pointer to this structure. + * @param fEnable Whether to enable or disable it. + * + * @remarks Will not grab any locks. The caller must be busy when calling. + */ + DECLR0CALLBACKMEMBER(bool, pfnSetSGPhys,(PINTNETTRUNKSWPORT pSwitchPort, bool fEnable)); + + /** + * Reports the MAC address of the trunk. + * + * This is supposed to be called when creating, connection or reconnecting the + * trunk and when the MAC address is changed by the system admin. + * + * @param pSwitchPort Pointer to this structure. + * @param pMacAddr The MAC address. + * + * @remarks May take a spinlock or two. The caller must be busy when calling. + */ + DECLR0CALLBACKMEMBER(void, pfnReportMacAddress,(PINTNETTRUNKSWPORT pSwitchPort, PCRTMAC pMacAddr)); + + /** + * Reports the promicuousness of the interface. + * + * This is supposed to be called when creating, connection or reconnecting the + * trunk and when the mode is changed by the system admin. + * + * @param pSwitchPort Pointer to this structure. + * @param fPromiscuous True if the host operates the interface in + * promiscuous mode, false if not. + * + * @remarks May take a spinlock or two. The caller must be busy when calling. + */ + DECLR0CALLBACKMEMBER(void, pfnReportPromiscuousMode,(PINTNETTRUNKSWPORT pSwitchPort, bool fPromiscuous)); + + /** + * Reports the GSO capabilities of the host, wire or both. + * + * This is supposed to be used only when creating, connecting or reconnecting + * the trunk. It is assumed that the GSO capabilities are kind of static the + * rest of the time. + * + * @param pSwitchPort Pointer to this structure. + * @param fGsoCapabilities The GSO capability bit mask. The bits + * corresponds to the GSO type with the same value. + * @param fDst The destination mask (INTNETTRUNKDIR_XXX). + * + * @remarks Does not take any locks. The caller must be busy when calling. + */ + DECLR0CALLBACKMEMBER(void, pfnReportGsoCapabilities,(PINTNETTRUNKSWPORT pSwitchPort, uint32_t fGsoCapabilities, uint32_t fDst)); + + /** + * Reports the no-preemption-xmit capabilities of the host and wire. + * + * This is supposed to be used only when creating, connecting or reconnecting + * the trunk. It is assumed that the GSO capabilities are kind of static the + * rest of the time. + * + * @param pSwitchPort Pointer to this structure. + * @param fNoPreemptDsts The destinations (INTNETTRUNKDIR_XXX) which it + * is safe to transmit to with preemption disabled. + * @param fDst The destination mask (INTNETTRUNKDIR_XXX). + * + * @remarks Does not take any locks. The caller must be busy when calling. + */ + DECLR0CALLBACKMEMBER(void, pfnReportNoPreemptDsts,(PINTNETTRUNKSWPORT pSwitchPort, uint32_t fNoPreemptDsts)); + + /** + * Notifications about changes to host IP addresses. + * + * This is used by networks bridged to wifi that share mac with + * the host. Host reports changes to its IP addresses so that L3 + * switching can ingore guests spoofing host's own IP addresses + * + * This callback may be null to indicate we are not interested. + * + * @param pSwitchPort Pointer to this structure. + * @param fAdded Whether address is added of removed. + * @param enmType Address type. + * @param pvAddr Pointer to the address. + */ + DECLR0CALLBACKMEMBER(void, pfnNotifyHostAddress,(PINTNETTRUNKSWPORT pSwitchPort, bool fAdded, + INTNETADDRTYPE enmType, const void *pvAddr)); + + /** + * OS triggered trunk disconnect. + * + * The caller shall must be busy when calling this method to prevent racing the + * network destruction code. This method will always consume this busy reference + * (released via @a pfnReleaseBusy using @a pIfPort). + * + * The caller shall guarantee that there are absolutely no chance of concurrent + * calls to this method on the same instance. + * + * @param pSwitchPort Pointer to this structure. + * @param pIfPort The interface port structure corresponding to @a + * pSwitchPort and which should be used when + * calling @a pfnReleaseBusy. This is required as + * the method may no longer have access to a valid + * @a pIfPort pointer. + * @param pfnReleaseBusy Callback for releasing the callers busy + * reference to it's side of things. + */ + DECLR0CALLBACKMEMBER(void, pfnDisconnect,(PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT pIfPort, + PFNINTNETTRUNKIFPORTRELEASEBUSY pfnReleaseBusy)); + + /** Structure version number. (INTNETTRUNKSWPORT_VERSION) */ + uint32_t u32VersionEnd; +} INTNETTRUNKSWPORT; + +/** + * Version number for the INTNETTRUNKIFPORT::u32Version and + * INTNETTRUNKIFPORT::u32VersionEnd fields. + * + * NB: Version @c 0xA2CDf005 is consumed by 4.x branches for the + * backport of pfnNotifyHostAddress. On the next version bump use + * @c 0xA2CDf006 and remove this reminder. + */ +# define INTNETTRUNKSWPORT_VERSION UINT32_C(0xA2CDf004) + + +/** + * The trunk interface state used set by INTNETTRUNKIFPORT::pfnSetState. + */ +typedef enum INTNETTRUNKIFSTATE +{ + /** The invalid zero entry. */ + INTNETTRUNKIFSTATE_INVALID = 0, + /** The trunk is inactive. No calls to INTNETTRUNKSWPORT::pfnRecv or + * INTNETTRUNKSWPORT::pfnPreRecv. Calling other methods is OK. */ + INTNETTRUNKIFSTATE_INACTIVE, + /** The trunk is active, no restrictions on methods or anything. */ + INTNETTRUNKIFSTATE_ACTIVE, + /** The trunk is about to be disconnected from the internal network. No + * calls to any INTNETRUNKSWPORT methods. */ + INTNETTRUNKIFSTATE_DISCONNECTING, + /** The end of the valid states. */ + INTNETTRUNKIFSTATE_END, + /** The usual 32-bit type blow up hack. */ + INTNETTRUNKIFSTATE_32BIT_HACK = 0x7fffffff +} INTNETTRUNKIFSTATE; + + +/** + * This is the port on the trunk interface, i.e. the driver side which the + * internal network is connected to. + * + * This is only used for the in-kernel trunk connections. + */ +typedef struct INTNETTRUNKIFPORT +{ + /** Structure version number. (INTNETTRUNKIFPORT_VERSION) */ + uint32_t u32Version; + + /** + * Retain the object. + * + * It will normally be called while owning the internal network semaphore. + * + * @param pIfPort Pointer to this structure. + * + * @remarks May own the big mutex, no spinlocks. + */ + DECLR0CALLBACKMEMBER(void, pfnRetain,(PINTNETTRUNKIFPORT pIfPort)); + + /** + * Releases the object. + * + * This must be called for every pfnRetain call. + * + * @param pIfPort Pointer to this structure. + * + * @remarks May own the big mutex, no spinlocks. + */ + DECLR0CALLBACKMEMBER(void, pfnRelease,(PINTNETTRUNKIFPORT pIfPort)); + + /** + * Disconnect from the switch and release the object. + * + * The is the counter action of the + * INTNETTRUNKNETFLTFACTORY::pfnCreateAndConnect method. + * + * @param pIfPort Pointer to this structure. + * + * @remarks Owns the big mutex. + */ + DECLR0CALLBACKMEMBER(void, pfnDisconnectAndRelease,(PINTNETTRUNKIFPORT pIfPort)); + + /** + * Changes the state of the trunk interface. + * + * The interface is created in the inactive state (INTNETTRUNKIFSTATE_INACTIVE). + * When the first connect VM or service is activated, the internal network + * activates the trunk (INTNETTRUNKIFSTATE_ACTIVE). The state may then be set + * back and forth between INACTIVE and ACTIVE as VMs are paused, added and + * removed. + * + * Eventually though, the network is destroyed as a result of there being no + * more VMs left in it and the state is changed to disconnecting + * (INTNETTRUNKIFSTATE_DISCONNECTING) and pfnWaitForIdle is called to make sure + * there are no active calls in either direction when pfnDisconnectAndRelease is + * called. + * + * A typical operation to performed by this method is to enable/disable promiscuous + * mode on the host network interface when entering/leaving the active state. + * + * @returns The previous state. + * + * @param pIfPort Pointer to this structure. + * @param enmState The new state. + * + * @remarks Owns the big mutex. No racing pfnSetState, pfnWaitForIdle, + * pfnDisconnectAndRelease or INTNETTRUNKFACTORY::pfnCreateAndConnect + * calls. + */ + DECLR0CALLBACKMEMBER(INTNETTRUNKIFSTATE, pfnSetState,(PINTNETTRUNKIFPORT pIfPort, INTNETTRUNKIFSTATE enmState)); + + /** + * Notifies when the MAC address of an interface is set or changes. + * + * @param pIfPort Pointer to this structure. + * @param pvIfData Pointer to the trunk's interface data (see + * pfnConnectInterface). + * @param pMac Pointer to the MAC address of the connecting VM NIC. + * + * @remarks Only busy references to the trunk and the interface. + */ + DECLR0CALLBACKMEMBER(void, pfnNotifyMacAddress,(PINTNETTRUNKIFPORT pIfPort, void *pvIfData, PCRTMAC pMac)); + + /** + * Called when an interface is connected to the network. + * + * @returns IPRT status code. + * @param pIfPort Pointer to this structure. + * @param pvIf Opaque pointer to the interface being connected. + * For use INTNETTRUNKSWPORT::pfnRecv. + * @param ppvIfData Pointer to a pointer variable that the trunk + * implementation can use to associate data with the + * interface. This pointer will be passed to the + * pfnXmit, pfnNotifyMacAddress and + * pfnDisconnectInterface methods. + * + * @remarks Owns the big mutex. No racing pfnDisconnectAndRelease. + */ + DECLR0CALLBACKMEMBER(int, pfnConnectInterface,(PINTNETTRUNKIFPORT pIfPort, void *pvIf, void **ppvIfData)); + + /** + * Called when an interface is disconnected from the network. + * + * @param pIfPort Pointer to this structure. + * @param pvIfData Pointer to the trunk's interface data (see + * pfnConnectInterface). + * + * @remarks Owns the big mutex. No racing pfnDisconnectAndRelease. + */ + DECLR0CALLBACKMEMBER(void, pfnDisconnectInterface,(PINTNETTRUNKIFPORT pIfPort, void *pvIfData)); + + /** + * Waits for the interface to become idle. + * + * This method must be called before disconnecting and releasing the object in + * order to prevent racing incoming/outgoing frames and device + * enabling/disabling. + * + * @returns IPRT status code (see RTSemEventWait). + * @param pIfPort Pointer to this structure. + * @param cMillies The number of milliseconds to wait. 0 means + * no waiting at all. Use RT_INDEFINITE_WAIT for + * an indefinite wait. + * + * @remarks Owns the big mutex. No racing pfnDisconnectAndRelease. + */ + DECLR0CALLBACKMEMBER(int, pfnWaitForIdle,(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies)); + + /** + * Transmit a frame. + * + * @return VBox status code. Error generally means we'll drop the frame. + * @param pIfPort Pointer to this structure. + * @param pvIfData Pointer to the trunk's interface data (see + * pfnConnectInterface). + * @param pSG Pointer to the (scatter /) gather structure for the frame. + * This may or may not be a temporary buffer. If it's temporary + * the transmit operation(s) then it's required to make a copy + * of the frame unless it can be transmitted synchronously. + * @param fDst The destination mask. At least one bit will be set. + * + * @remarks No locks. May be called concurrently on several threads. + */ + DECLR0CALLBACKMEMBER(int, pfnXmit,(PINTNETTRUNKIFPORT pIfPort, void *pvIfData, PINTNETSG pSG, uint32_t fDst)); + + /** Structure version number. (INTNETTRUNKIFPORT_VERSION) */ + uint32_t u32VersionEnd; +} INTNETTRUNKIFPORT; + +/** Version number for the INTNETTRUNKIFPORT::u32Version and INTNETTRUNKIFPORT::u32VersionEnd fields. */ +#define INTNETTRUNKIFPORT_VERSION UINT32_C(0xA2CDe001) + + +/** + * The component factory interface for create a network + * interface filter (like VBoxNetFlt). + */ +typedef struct INTNETTRUNKFACTORY +{ + /** + * Release this factory. + * + * SUPR0ComponentQueryFactory (SUPDRVFACTORY::pfnQueryFactoryInterface to be precise) + * will retain a reference to the factory and the caller has to call this method to + * release it once the pfnCreateAndConnect call(s) has been done. + * + * @param pIfFactory Pointer to this structure. + */ + DECLR0CALLBACKMEMBER(void, pfnRelease,(struct INTNETTRUNKFACTORY *pIfFactory)); + + /** + * Create an instance for the specfied host interface and connects it + * to the internal network trunk port. + * + * The initial interface active state is false (suspended). + * + * + * @returns VBox status code. + * @retval VINF_SUCCESS and *ppIfPort set on success. + * @retval VERR_INTNET_FLT_IF_NOT_FOUND if the interface was not found. + * @retval VERR_INTNET_FLT_IF_BUSY if the interface is already connected. + * @retval VERR_INTNET_FLT_IF_FAILED if it failed for some other reason. + * + * @param pIfFactory Pointer to this structure. + * @param pszName The interface name (OS specific). + * @param pSwitchPort Pointer to the port interface on the switch that + * this interface is being connected to. + * @param fFlags Creation flags, see below. + * @param ppIfPort Where to store the pointer to the interface port + * on success. + * + * @remarks Called while owning the network and the out-bound trunk semaphores. + */ + DECLR0CALLBACKMEMBER(int, pfnCreateAndConnect,(struct INTNETTRUNKFACTORY *pIfFactory, const char *pszName, + PINTNETTRUNKSWPORT pSwitchPort, uint32_t fFlags, + PINTNETTRUNKIFPORT *ppIfPort)); +} INTNETTRUNKFACTORY; +/** Pointer to the trunk factory. */ +typedef INTNETTRUNKFACTORY *PINTNETTRUNKFACTORY; + +/** The UUID for the (current) trunk factory. (case sensitive) */ +#define INTNETTRUNKFACTORY_UUID_STR "de504d93-1d1e-4781-8b73-6ea39a0e36a2" + +/** @name INTNETTRUNKFACTORY::pfnCreateAndConnect flags. + * @{ */ +/** Don't put the filtered interface in promiscuous mode. + * This is used for wireless interface since these can misbehave if + * we try to put them in promiscuous mode. (Wireless interfaces are + * normally bridged on level 3 instead of level 2.) */ +#define INTNETTRUNKFACTORY_FLAG_NO_PROMISC RT_BIT_32(0) +/** @} */ + + +/** + * The trunk connection type. + * + * Used by IntNetR0Open and associated interfaces. + */ +typedef enum INTNETTRUNKTYPE +{ + /** Invalid trunk type. */ + kIntNetTrunkType_Invalid = 0, + /** No trunk connection. */ + kIntNetTrunkType_None, + /** We don't care which kind of trunk connection if the network exists, + * if it doesn't exist create it without a connection. */ + kIntNetTrunkType_WhateverNone, + /** VirtualBox host network interface filter driver. + * The trunk name is the name of the host network interface. */ + kIntNetTrunkType_NetFlt, + /** VirtualBox adapter host driver. */ + kIntNetTrunkType_NetAdp, + /** Nat service (ring-0). */ + kIntNetTrunkType_SrvNat, + /** The end of valid types. */ + kIntNetTrunkType_End, + /** The usual 32-bit hack. */ + kIntNetTrunkType_32bitHack = 0x7fffffff +} INTNETTRUNKTYPE; + +/** @name IntNetR0Open flags. + * + * The desired policy options must be specified explicitly, if omitted it is + * understood that whatever is current or default is fine with the caller. + * + * @todo Move the policies out of the flags, use three new parameters. + * + * @{ */ +/** Share the MAC address with the host when sending something to the wire via the trunk. + * This is typically used when the trunk is a NetFlt for a wireless interface. */ +#define INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE RT_BIT_32(0) +/** Require that the current security and promiscuous policies of the network + * is exactly as the ones specified in this open network request. + * + * Use this with INTNET_OPEN_FLAGS_REQUIRE_AS_RESTRICTIVE_POLICIES to prevent + * restrictions from being lifted. If no further policy changes are desired, + * apply the relevant _FIXED flags. */ +#define INTNET_OPEN_FLAGS_REQUIRE_EXACT RT_BIT_32(1) +/** Require that the security and promiscuous policies of the network is at + * least as restrictive as specified this request specifies and prevent them + * being lifted later on. */ +#define INTNET_OPEN_FLAGS_REQUIRE_AS_RESTRICTIVE_POLICIES RT_BIT_32(2) + +/** Network access policy: Fixed if set, changable if clear. */ +#define INTNET_OPEN_FLAGS_ACCESS_FIXED RT_BIT_32(3) +/** Network access policy: Public network. */ +#define INTNET_OPEN_FLAGS_ACCESS_PUBLIC RT_BIT_32(4) +/** Network access policy: Restricted network. */ +#define INTNET_OPEN_FLAGS_ACCESS_RESTRICTED RT_BIT_32(5) + +/** Promiscuous mode policy: Is it fixed or changable by new participants? */ +#define INTNET_OPEN_FLAGS_PROMISC_FIXED RT_BIT_32(6) +/** Promiscuous mode policy: Allow the clients to request it. */ +#define INTNET_OPEN_FLAGS_PROMISC_ALLOW_CLIENTS RT_BIT_32(7) +/** Promiscuous mode policy: Deny the clients from requesting it. */ +#define INTNET_OPEN_FLAGS_PROMISC_DENY_CLIENTS RT_BIT_32(8) +/** Promiscuous mode policy: Allow the trunk-host to request it. */ +#define INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_HOST RT_BIT_32(9) +/** Promiscuous mode policy: Deny the trunk-host from requesting it. */ +#define INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_HOST RT_BIT_32(10) +/** Promiscuous mode policy: Allow the trunk-wire to request it. */ +#define INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_WIRE RT_BIT_32(11) +/** Promiscuous mode policy: Deny the trunk-wire from requesting it. */ +#define INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_WIRE RT_BIT_32(12) + +/** Interface policies: Is it fixed or changable (by admin). + * @note Per interface, not network wide. */ +#define INTNET_OPEN_FLAGS_IF_FIXED RT_BIT_32(13) +/** Interface promiscuous mode policy: Allow the interface to request it. */ +#define INTNET_OPEN_FLAGS_IF_PROMISC_ALLOW RT_BIT_32(14) +/** Interface promiscuous mode policy: Deny the interface from requesting it. */ +#define INTNET_OPEN_FLAGS_IF_PROMISC_DENY RT_BIT_32(15) +/** Interface promiscuous mode policy: See unrelated trunk traffic. */ +#define INTNET_OPEN_FLAGS_IF_PROMISC_SEE_TRUNK RT_BIT_32(16) +/** Interface promiscuous mode policy: No unrelated trunk traffic visible. */ +#define INTNET_OPEN_FLAGS_IF_PROMISC_NO_TRUNK RT_BIT_32(17) + +/** Trunk policy: Fixed if set, changable if clear. + * @remarks The DISABLED options are considered more restrictive by + * INTNET_OPEN_FLAGS_REQUIRE_AS_RESTRICTIVE_POLICIES. */ +#define INTNET_OPEN_FLAGS_TRUNK_FIXED RT_BIT_32(18) +/** Trunk policy: The host end should be enabled. */ +#define INTNET_OPEN_FLAGS_TRUNK_HOST_ENABLED RT_BIT_32(19) +/** Trunk policy: The host end should be disabled. */ +#define INTNET_OPEN_FLAGS_TRUNK_HOST_DISABLED RT_BIT_32(20) +/** Trunk policy: The host should only see packets destined for it. */ +#define INTNET_OPEN_FLAGS_TRUNK_HOST_CHASTE_MODE RT_BIT_32(21) +/** Trunk policy: The host should see all packets. */ +#define INTNET_OPEN_FLAGS_TRUNK_HOST_PROMISC_MODE RT_BIT_32(22) +/** Trunk policy: The wire end should be enabled. */ +#define INTNET_OPEN_FLAGS_TRUNK_WIRE_ENABLED RT_BIT_32(23) +/** Trunk policy: The wire end should be disabled. */ +#define INTNET_OPEN_FLAGS_TRUNK_WIRE_DISABLED RT_BIT_32(24) +/** Trunk policy: The wire should only see packets destined for it. */ +#define INTNET_OPEN_FLAGS_TRUNK_WIRE_CHASTE_MODE RT_BIT_32(25) +/** Trunk policy: The wire should see all packets. */ +#define INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE RT_BIT_32(26) + +/** Used to enable host specific workarounds. + * + * On darwin this will clear ip_tos in DHCP packets when + * INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE is also set. */ +#define INTNET_OPEN_FLAGS_WORKAROUND_1 RT_BIT_32(31) + + +/** The mask of valid flags. */ +#define INTNET_OPEN_FLAGS_MASK UINT32_C(0x83ffffff) +/** The mask of all flags use to fix (lock) settings. */ +#define INTNET_OPEN_FLAGS_FIXED_MASK \ + ( INTNET_OPEN_FLAGS_ACCESS_FIXED \ + | INTNET_OPEN_FLAGS_PROMISC_FIXED \ + | INTNET_OPEN_FLAGS_IF_FIXED \ + | INTNET_OPEN_FLAGS_TRUNK_FIXED ) + +/** The mask of all policy pairs. */ +#define INTNET_OPEN_FLAGS_PAIR_MASK \ + ( INTNET_OPEN_FLAGS_ACCESS_PUBLIC | INTNET_OPEN_FLAGS_ACCESS_RESTRICTED \ + | INTNET_OPEN_FLAGS_PROMISC_ALLOW_CLIENTS | INTNET_OPEN_FLAGS_PROMISC_DENY_CLIENTS \ + | INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_HOST | INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_HOST \ + | INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_WIRE | INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_WIRE \ + | INTNET_OPEN_FLAGS_IF_PROMISC_ALLOW | INTNET_OPEN_FLAGS_IF_PROMISC_DENY \ + | INTNET_OPEN_FLAGS_IF_PROMISC_SEE_TRUNK | INTNET_OPEN_FLAGS_IF_PROMISC_NO_TRUNK \ + | INTNET_OPEN_FLAGS_TRUNK_HOST_ENABLED | INTNET_OPEN_FLAGS_TRUNK_HOST_DISABLED \ + | INTNET_OPEN_FLAGS_TRUNK_HOST_PROMISC_MODE | INTNET_OPEN_FLAGS_TRUNK_HOST_CHASTE_MODE \ + | INTNET_OPEN_FLAGS_TRUNK_WIRE_ENABLED | INTNET_OPEN_FLAGS_TRUNK_WIRE_DISABLED \ + | INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE | INTNET_OPEN_FLAGS_TRUNK_WIRE_CHASTE_MODE \ + ) +/** The mask of all relaxed policy bits. */ +#define INTNET_OPEN_FLAGS_RELAXED_MASK \ + ( INTNET_OPEN_FLAGS_ACCESS_PUBLIC \ + | INTNET_OPEN_FLAGS_PROMISC_ALLOW_CLIENTS \ + | INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_HOST \ + | INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_WIRE \ + | INTNET_OPEN_FLAGS_IF_PROMISC_ALLOW \ + | INTNET_OPEN_FLAGS_IF_PROMISC_SEE_TRUNK \ + | INTNET_OPEN_FLAGS_TRUNK_HOST_ENABLED \ + | INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE \ + | INTNET_OPEN_FLAGS_TRUNK_WIRE_ENABLED \ + | INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE \ + ) +/** The mask of all strict policy bits. */ +#define INTNET_OPEN_FLAGS_STRICT_MASK \ + ( INTNET_OPEN_FLAGS_ACCESS_RESTRICTED \ + | INTNET_OPEN_FLAGS_PROMISC_DENY_CLIENTS \ + | INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_HOST \ + | INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_WIRE \ + | INTNET_OPEN_FLAGS_IF_PROMISC_DENY \ + | INTNET_OPEN_FLAGS_IF_PROMISC_NO_TRUNK \ + | INTNET_OPEN_FLAGS_TRUNK_HOST_DISABLED \ + | INTNET_OPEN_FLAGS_TRUNK_HOST_CHASTE_MODE \ + | INTNET_OPEN_FLAGS_TRUNK_WIRE_DISABLED \ + | INTNET_OPEN_FLAGS_TRUNK_WIRE_CHASTE_MODE \ + ) +/** @} */ + +/** The maximum length of a network name. */ +#define INTNET_MAX_NETWORK_NAME 128 + +/** The maximum length of a trunk name. */ +#define INTNET_MAX_TRUNK_NAME 64 + + +/** + * Request buffer for IntNetR0OpenReq / VMMR0_DO_INTNET_OPEN. + * @see IntNetR0Open. + */ +typedef struct INTNETOPENREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** The network name. (input) */ + char szNetwork[INTNET_MAX_NETWORK_NAME]; + /** What to connect to the trunk port. (input) + * This is specific to the trunk type below. */ + char szTrunk[INTNET_MAX_TRUNK_NAME]; + /** The type of trunk link (NAT, Filter, TAP, etc). (input) */ + INTNETTRUNKTYPE enmTrunkType; + /** Flags, see INTNET_OPEN_FLAGS_*. (input) */ + uint32_t fFlags; + /** The size of the send buffer. (input) */ + uint32_t cbSend; + /** The size of the receive buffer. (input) */ + uint32_t cbRecv; + /** The handle to the network interface. (output) */ + INTNETIFHANDLE hIf; +} INTNETOPENREQ; +/** Pointer to an IntNetR0OpenReq / VMMR0_DO_INTNET_OPEN request buffer. */ +typedef INTNETOPENREQ *PINTNETOPENREQ; + +INTNETR0DECL(int) IntNetR0OpenReq(PSUPDRVSESSION pSession, PINTNETOPENREQ pReq); + + +/** + * Request buffer for IntNetR0IfCloseReq / VMMR0_DO_INTNET_IF_CLOSE. + * @see IntNetR0IfClose. + */ +typedef struct INTNETIFCLOSEREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** The handle to the network interface. */ + INTNETIFHANDLE hIf; +} INTNETIFCLOSEREQ; +/** Pointer to an IntNetR0IfCloseReq / VMMR0_DO_INTNET_IF_CLOSE request + * buffer. */ +typedef INTNETIFCLOSEREQ *PINTNETIFCLOSEREQ; + +INTNETR0DECL(int) IntNetR0IfCloseReq(PSUPDRVSESSION pSession, PINTNETIFCLOSEREQ pReq); + + +/** + * Request buffer for IntNetR0IfGetRing3BufferReq / + * VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS. + * @see IntNetR0IfGetRing3Buffer. + */ +typedef struct INTNETIFGETBUFFERPTRSREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** Handle to the interface. */ + INTNETIFHANDLE hIf; + /** The pointer to the ring-3 buffer. (output) */ + R3PTRTYPE(PINTNETBUF) pRing3Buf; + /** The pointer to the ring-0 buffer. (output) */ + R0PTRTYPE(PINTNETBUF) pRing0Buf; +} INTNETIFGETBUFFERPTRSREQ; +/** Pointer to an IntNetR0IfGetRing3BufferReq / + * VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS request buffer. */ +typedef INTNETIFGETBUFFERPTRSREQ *PINTNETIFGETBUFFERPTRSREQ; + +INTNETR0DECL(int) IntNetR0IfGetBufferPtrsReq(PSUPDRVSESSION pSession, PINTNETIFGETBUFFERPTRSREQ pReq); + + +/** + * Request buffer for IntNetR0IfSetPromiscuousModeReq / + * VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE. + * @see IntNetR0IfSetPromiscuousMode. + */ +typedef struct INTNETIFSETPROMISCUOUSMODEREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** Handle to the interface. */ + INTNETIFHANDLE hIf; + /** The new promiscuous mode. */ + bool fPromiscuous; +} INTNETIFSETPROMISCUOUSMODEREQ; +/** Pointer to an IntNetR0IfSetPromiscuousModeReq / + * VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE request buffer. */ +typedef INTNETIFSETPROMISCUOUSMODEREQ *PINTNETIFSETPROMISCUOUSMODEREQ; + +INTNETR0DECL(int) IntNetR0IfSetPromiscuousModeReq(PSUPDRVSESSION pSession, PINTNETIFSETPROMISCUOUSMODEREQ pReq); + + +/** + * Request buffer for IntNetR0IfSetMacAddressReq / + * VMMR0_DO_INTNET_IF_SET_MAC_ADDRESS. + * @see IntNetR0IfSetMacAddress. + */ +typedef struct INTNETIFSETMACADDRESSREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** Handle to the interface. */ + INTNETIFHANDLE hIf; + /** The new MAC address. */ + RTMAC Mac; +} INTNETIFSETMACADDRESSREQ; +/** Pointer to an IntNetR0IfSetMacAddressReq / + * VMMR0_DO_INTNET_IF_SET_MAC_ADDRESS request buffer. */ +typedef INTNETIFSETMACADDRESSREQ *PINTNETIFSETMACADDRESSREQ; + +INTNETR0DECL(int) IntNetR0IfSetMacAddressReq(PSUPDRVSESSION pSession, PINTNETIFSETMACADDRESSREQ pReq); + + +/** + * Request buffer for IntNetR0IfSetActiveReq / VMMR0_DO_INTNET_IF_SET_ACTIVE. + * @see IntNetR0IfSetActive. + */ +typedef struct INTNETIFSETACTIVEREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** Handle to the interface. */ + INTNETIFHANDLE hIf; + /** The new state. */ + bool fActive; +} INTNETIFSETACTIVEREQ; +/** Pointer to an IntNetR0IfSetActiveReq / VMMR0_DO_INTNET_IF_SET_ACTIVE + * request buffer. */ +typedef INTNETIFSETACTIVEREQ *PINTNETIFSETACTIVEREQ; + +INTNETR0DECL(int) IntNetR0IfSetActiveReq(PSUPDRVSESSION pSession, PINTNETIFSETACTIVEREQ pReq); + + +/** + * Request buffer for IntNetR0IfSendReq / VMMR0_DO_INTNET_IF_SEND. + * @see IntNetR0IfSend. + */ +typedef struct INTNETIFSENDREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** Handle to the interface. */ + INTNETIFHANDLE hIf; +} INTNETIFSENDREQ; +/** Pointer to an IntNetR0IfSend() argument package. */ +typedef INTNETIFSENDREQ *PINTNETIFSENDREQ; + +INTNETR0DECL(int) IntNetR0IfSendReq(PSUPDRVSESSION pSession, PINTNETIFSENDREQ pReq); + + +/** + * Request buffer for IntNetR0IfWaitReq / VMMR0_DO_INTNET_IF_WAIT. + * @see IntNetR0IfWait. + */ +typedef struct INTNETIFWAITREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** Handle to the interface. */ + INTNETIFHANDLE hIf; + /** The number of milliseconds to wait. */ + uint32_t cMillies; +} INTNETIFWAITREQ; +/** Pointer to an IntNetR0IfWaitReq / VMMR0_DO_INTNET_IF_WAIT request buffer. */ +typedef INTNETIFWAITREQ *PINTNETIFWAITREQ; + +INTNETR0DECL(int) IntNetR0IfWaitReq(PSUPDRVSESSION pSession, PINTNETIFWAITREQ pReq); + + +/** + * Request buffer for IntNetR0IfAbortWaitReq / VMMR0_DO_INTNET_IF_ABORT_WAIT. + * @see IntNetR0IfAbortWait. + */ +typedef struct INTNETIFABORTWAITREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** Handle to the interface. */ + INTNETIFHANDLE hIf; + /** Set this to fend off all future IntNetR0Wait calls. */ + bool fNoMoreWaits; +} INTNETIFABORTWAITREQ; +/** Pointer to an IntNetR0IfAbortWaitReq / VMMR0_DO_INTNET_IF_ABORT_WAIT + * request buffer. */ +typedef INTNETIFABORTWAITREQ *PINTNETIFABORTWAITREQ; + +INTNETR0DECL(int) IntNetR0IfAbortWaitReq(PSUPDRVSESSION pSession, PINTNETIFABORTWAITREQ pReq); + + +#if defined(IN_RING0) || defined(IN_INTNET_TESTCASE) +/** @name + * @{ + */ + +INTNETR0DECL(int) IntNetR0Init(void); +INTNETR0DECL(void) IntNetR0Term(void); +INTNETR0DECL(int) IntNetR0Open(PSUPDRVSESSION pSession, const char *pszNetwork, + INTNETTRUNKTYPE enmTrunkType, const char *pszTrunk, uint32_t fFlags, + uint32_t cbSend, uint32_t cbRecv, PINTNETIFHANDLE phIf); +INTNETR0DECL(uint32_t) IntNetR0GetNetworkCount(void); + +INTNETR0DECL(int) IntNetR0IfClose(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession); +INTNETR0DECL(int) IntNetR0IfGetBufferPtrs(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, + R3PTRTYPE(PINTNETBUF) *ppRing3Buf, R0PTRTYPE(PINTNETBUF) *ppRing0Buf); +INTNETR0DECL(int) IntNetR0IfSetPromiscuousMode(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fPromiscuous); +INTNETR0DECL(int) IntNetR0IfSetMacAddress(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, PCRTMAC pMac); +INTNETR0DECL(int) IntNetR0IfSetActive(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fActive); +INTNETR0DECL(int) IntNetR0IfSend(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession); +INTNETR0DECL(int) IntNetR0IfWait(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, uint32_t cMillies); +INTNETR0DECL(int) IntNetR0IfAbortWait(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession); + +/** @} */ +#endif /* IN_RING0 */ + +/** + * Callback function for use with IntNetR3Open to signalling incoming data. + * + * @param hIf Interface handle. + * @param pvUser User parameter. + */ +typedef DECLCALLBACKTYPE(void, FNINTNETIFRECVAVAIL,(INTNETIFHANDLE hIf, void *pvUser)); +/** Pointer to a FNINTNETIFRECVAVAIL callback. */ +typedef FNINTNETIFRECVAVAIL *PFNINTNETIFRECVAVAIL; + +#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3) && defined(IN_RING3) +INTNETR3DECL(int) IntNetR3Open(PSUPDRVSESSION pSession, const char *pszNetwork, + INTNETTRUNKTYPE enmTrunkType, const char *pszTrunk, uint32_t fFlags, + uint32_t cbSend, uint32_t cbRecv, PFNINTNETIFRECVAVAIL pfnRecvAvail, + void *pvUserRecvAvail, PINTNETIFHANDLE phIf); +#endif + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_intnet_h */ diff --git a/include/VBox/intnetinline.h b/include/VBox/intnetinline.h new file mode 100644 index 00000000..adb338ef --- /dev/null +++ b/include/VBox/intnetinline.h @@ -0,0 +1,837 @@ +/* $Id: intnetinline.h $ */ +/** @file + * INTNET - Internal Networking, Inlined Code. (DEV,++) + * + * This is all inlined because it's too tedious to create 2-3 libraries to + * contain it all. Large parts of this header is only accessible from C++ + * sources because of mixed code and variables. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_intnetinline_h +#define VBOX_INCLUDED_intnetinline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/intnet.h> +#include <iprt/string.h> +#include <iprt/assert.h> +#include <iprt/err.h> +#include <VBox/log.h> + + + +/** + * Valid internal networking frame type. + * + * @returns true / false. + * @param u8Type The frame type to check. + */ +DECLINLINE(bool) IntNetIsValidFrameType(uint8_t u8Type) +{ + if (RT_LIKELY( u8Type == INTNETHDR_TYPE_FRAME + || u8Type == INTNETHDR_TYPE_GSO + || u8Type == INTNETHDR_TYPE_PADDING)) + return true; + return false; +} + + +/** + * Partly initializes a scatter / gather buffer, leaving the segments to the + * caller. + * + * @returns Pointer to the start of the frame. + * @param pSG Pointer to the scatter / gather structure. + * @param cbTotal The total size. + * @param cSegs The number of segments. + * @param cSegsUsed The number of used segments. + */ +DECLINLINE(void) IntNetSgInitTempSegs(PINTNETSG pSG, uint32_t cbTotal, unsigned cSegs, unsigned cSegsUsed) +{ + pSG->pvOwnerData = NULL; + pSG->pvUserData = NULL; + pSG->pvUserData2 = NULL; + pSG->cbTotal = cbTotal; + pSG->cUsers = 1; + pSG->fFlags = INTNETSG_FLAGS_TEMP; + pSG->GsoCtx.u8Type = (uint8_t)PDMNETWORKGSOTYPE_INVALID; + pSG->GsoCtx.cbHdrsTotal = 0; + pSG->GsoCtx.cbHdrsSeg = 0; + pSG->GsoCtx.cbMaxSeg= 0; + pSG->GsoCtx.offHdr1 = 0; + pSG->GsoCtx.offHdr2 = 0; + pSG->GsoCtx.u8Unused= 0; +#if ARCH_BITS == 64 + pSG->uPadding = 0; +#endif + pSG->cSegsAlloc = (uint16_t)cSegs; + Assert(pSG->cSegsAlloc == cSegs); + pSG->cSegsUsed = (uint16_t)cSegsUsed; + Assert(pSG->cSegsUsed == cSegsUsed); + Assert(cSegs >= cSegsUsed); +} + + +/** + * Partly initializes a scatter / gather buffer w/ GSO, leaving the segments to + * the caller. + * + * @returns Pointer to the start of the frame. + * @param pSG Pointer to the scatter / gather structure. + * @param cbTotal The total size. + * @param cSegs The number of segments. + * @param cSegsUsed The number of used segments. + * @param pGso The GSO context. + */ +DECLINLINE(void) IntNetSgInitTempSegsGso(PINTNETSG pSG, uint32_t cbTotal, unsigned cSegs, + unsigned cSegsUsed, PCPDMNETWORKGSO pGso) +{ + pSG->pvOwnerData = NULL; + pSG->pvUserData = NULL; + pSG->pvUserData2 = NULL; + pSG->cbTotal = cbTotal; + pSG->cUsers = 1; + pSG->fFlags = INTNETSG_FLAGS_TEMP; + pSG->GsoCtx.u8Type = pGso->u8Type; + pSG->GsoCtx.cbHdrsTotal = pGso->cbHdrsTotal; + pSG->GsoCtx.cbHdrsSeg = pGso->cbHdrsSeg; + pSG->GsoCtx.cbMaxSeg= pGso->cbMaxSeg; + pSG->GsoCtx.offHdr1 = pGso->offHdr1; + pSG->GsoCtx.offHdr2 = pGso->offHdr2; + pSG->GsoCtx.u8Unused= 0; +#if ARCH_BITS == 64 + pSG->uPadding = 0; +#endif + pSG->cSegsAlloc = (uint16_t)cSegs; + Assert(pSG->cSegsAlloc == cSegs); + pSG->cSegsUsed = (uint16_t)cSegsUsed; + Assert(pSG->cSegsUsed == cSegsUsed); + Assert(cSegs >= cSegsUsed); +} + + + +/** + * Initializes a scatter / gather buffer describing a simple linear buffer. + * + * @returns Pointer to the start of the frame. + * @param pSG Pointer to the scatter / gather structure. + * @param pvFrame Pointer to the frame + * @param cbFrame The size of the frame. + */ +DECLINLINE(void) IntNetSgInitTemp(PINTNETSG pSG, void *pvFrame, uint32_t cbFrame) +{ + IntNetSgInitTempSegs(pSG, cbFrame, 1, 1); + pSG->aSegs[0].Phys = NIL_RTHCPHYS; + pSG->aSegs[0].pv = pvFrame; + pSG->aSegs[0].cb = cbFrame; +} + +/** + * Initializes a scatter / gather buffer describing a simple linear buffer. + * + * @returns Pointer to the start of the frame. + * @param pSG Pointer to the scatter / gather structure. + * @param pvFrame Pointer to the frame + * @param cbFrame The size of the frame. + * @param pGso The GSO context. + */ +DECLINLINE(void) IntNetSgInitTempGso(PINTNETSG pSG, void *pvFrame, uint32_t cbFrame, PCPDMNETWORKGSO pGso) +{ + IntNetSgInitTempSegsGso(pSG, cbFrame, 1, 1, pGso); + pSG->aSegs[0].Phys = NIL_RTHCPHYS; + pSG->aSegs[0].pv = pvFrame; + pSG->aSegs[0].cb = cbFrame; +} + + +/** + * Reads an entire SG into a fittingly size buffer. + * + * @param pSG The SG list to read. + * @param pvBuf The buffer to read into (at least pSG->cbTotal in size). + */ +DECLINLINE(void) IntNetSgRead(PCINTNETSG pSG, void *pvBuf) +{ + memcpy(pvBuf, pSG->aSegs[0].pv, pSG->aSegs[0].cb); + if (pSG->cSegsUsed == 1) + Assert(pSG->cbTotal == pSG->aSegs[0].cb); + else + { + uint8_t *pbDst = (uint8_t *)pvBuf + pSG->aSegs[0].cb; + unsigned iSeg = 0; + unsigned const cSegs = pSG->cSegsUsed; + while (++iSeg < cSegs) + { + uint32_t cbSeg = pSG->aSegs[iSeg].cb; + Assert((uintptr_t)pbDst - (uintptr_t)pvBuf + cbSeg <= pSG->cbTotal); + memcpy(pbDst, pSG->aSegs[iSeg].pv, cbSeg); + pbDst += cbSeg; + } + } +} + + +/** + * Reads a portion of an SG into a buffer. + * + * @param pSG The SG list to read. + * @param offSrc The offset to start start copying from. + * @param cbToRead The number of bytes to copy. + * @param pvBuf The buffer to read into, cb or more in size. + */ +DECLINLINE(void) IntNetSgReadEx(PCINTNETSG pSG, uint32_t offSrc, uint32_t cbToRead, void *pvBuf) +{ + uint8_t *pbDst = (uint8_t *)pvBuf; + uint32_t iSeg = 0; + + /* validate assumptions */ + Assert(cbToRead <= pSG->cbTotal); + Assert(offSrc <= pSG->cbTotal); + Assert(offSrc + cbToRead <= pSG->cbTotal); + + /* Find the right segment and copy any bits from within the segment. */ + while (offSrc) + { + uint32_t cbSeg = pSG->aSegs[iSeg].cb; + if (offSrc < cbSeg) + { + uint32_t cbChunk = cbSeg - offSrc; + if (cbChunk >= cbToRead) + { + memcpy(pbDst, (uint8_t const *)pSG->aSegs[iSeg].pv + offSrc, cbToRead); + return; + } + + memcpy(pbDst, (uint8_t const *)pSG->aSegs[iSeg].pv + offSrc, cbChunk); + pbDst += cbChunk; + cbToRead -= cbChunk; + break; + } + + /* advance */ + offSrc -= cbSeg; + iSeg++; + } + + /* We're not at the start of a segment, copy until we're done. */ + for (;;) + { + uint32_t cbSeg = pSG->aSegs[iSeg].cb; + if (cbSeg >= cbToRead) + { + memcpy(pbDst, pSG->aSegs[iSeg].pv, cbToRead); + return; + } + + memcpy(pbDst, pSG->aSegs[iSeg].pv, cbSeg); + pbDst += cbSeg; + cbToRead -= cbSeg; + iSeg++; + Assert(iSeg < pSG->cSegsUsed); + } +} + +#ifdef __cplusplus + +/** + * Get the amount of space available for writing. + * + * @returns Number of available bytes. + * @param pRingBuf The ring buffer. + */ +DECLINLINE(uint32_t) IntNetRingGetWritable(PINTNETRINGBUF pRingBuf) +{ + uint32_t const offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX); + uint32_t const offWriteInt = ASMAtomicUoReadU32(&pRingBuf->offWriteInt); + return offRead <= offWriteInt + ? pRingBuf->offEnd - offWriteInt + offRead - pRingBuf->offStart - 1 + : offRead - offWriteInt - 1; +} + + +/** + * Checks if the ring has more for us to read. + * + * @returns Number of ready bytes. + * @param pRingBuf The ring buffer. + */ +DECLINLINE(bool) IntNetRingHasMoreToRead(PINTNETRINGBUF pRingBuf) +{ + uint32_t const offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX); + uint32_t const offWriteCom = ASMAtomicUoReadU32(&pRingBuf->offWriteCom); + return offRead != offWriteCom; +} + + +/** + * Gets the next frame to read. + * + * @returns Pointer to the next frame. NULL if done. + * @param pRingBuf The ring buffer. + */ +DECLINLINE(PINTNETHDR) IntNetRingGetNextFrameToRead(PINTNETRINGBUF pRingBuf) +{ + uint32_t const offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX); + uint32_t const offWriteCom = ASMAtomicUoReadU32(&pRingBuf->offWriteCom); + if (offRead == offWriteCom) + return NULL; + return (PINTNETHDR)((uint8_t *)pRingBuf + offRead); +} + + +/** + * Get the amount of data ready for reading. + * + * @returns Number of ready bytes. + * @param pRingBuf The ring buffer. + */ +DECLINLINE(uint32_t) IntNetRingGetReadable(PINTNETRINGBUF pRingBuf) +{ + uint32_t const offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX); + uint32_t const offWriteCom = ASMAtomicUoReadU32(&pRingBuf->offWriteCom); + return offRead <= offWriteCom + ? offWriteCom - offRead + : pRingBuf->offEnd - offRead + offWriteCom - pRingBuf->offStart; +} + + +/** + * Calculates the pointer to the frame. + * + * @returns Pointer to the start of the frame. + * @param pHdr Pointer to the packet header + * @param pBuf The buffer the header is within. Only used in strict builds. + */ +DECLINLINE(void *) IntNetHdrGetFramePtr(PCINTNETHDR pHdr, PCINTNETBUF pBuf) +{ + uint8_t *pu8 = (uint8_t *)pHdr + pHdr->offFrame; +#ifdef VBOX_STRICT + const uintptr_t off = (uintptr_t)pu8 - (uintptr_t)pBuf; + Assert(IntNetIsValidFrameType(pHdr->u8Type)); + Assert(off < pBuf->cbBuf); + Assert(off + pHdr->cbFrame <= pBuf->cbBuf); +#endif + NOREF(pBuf); + return pu8; +} + + +/** + * Calculates the pointer to the GSO context. + * + * ASSUMES the frame is a GSO frame. + * + * The GSO context is immediately followed by the headers and payload. The size + * is INTNETBUF::cbFrame - sizeof(PDMNETWORKGSO). + * + * @returns Pointer to the GSO context. + * @param pHdr Pointer to the packet header + * @param pBuf The buffer the header is within. Only used in strict builds. + */ +DECLINLINE(PPDMNETWORKGSO) IntNetHdrGetGsoContext(PCINTNETHDR pHdr, PCINTNETBUF pBuf) +{ + PPDMNETWORKGSO pGso = (PPDMNETWORKGSO)((uint8_t *)pHdr + pHdr->offFrame); +#ifdef VBOX_STRICT + const uintptr_t off = (uintptr_t)pGso - (uintptr_t)pBuf; + Assert(pHdr->u8Type == INTNETHDR_TYPE_GSO); + Assert(off < pBuf->cbBuf); + Assert(off + pHdr->cbFrame <= pBuf->cbBuf); +#endif + NOREF(pBuf); + return pGso; +} + + +/** + * Skips to the next (read) frame in the buffer. + * + * @param pRingBuf The ring buffer in question. + */ +DECLINLINE(void) IntNetRingSkipFrame(PINTNETRINGBUF pRingBuf) +{ + uint32_t const offReadOld = ASMAtomicUoReadU32(&pRingBuf->offReadX); + PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offReadOld); + Assert(offReadOld >= pRingBuf->offStart); + Assert(offReadOld < pRingBuf->offEnd); + Assert(RT_ALIGN_PT(pHdr, INTNETHDR_ALIGNMENT, INTNETHDR *) == pHdr); + Assert(IntNetIsValidFrameType(pHdr->u8Type)); + + /* skip the frame */ + uint32_t offReadNew = offReadOld + pHdr->offFrame + pHdr->cbFrame; + offReadNew = RT_ALIGN_32(offReadNew, INTNETHDR_ALIGNMENT); + Assert(offReadNew <= pRingBuf->offEnd && offReadNew >= pRingBuf->offStart); + if (offReadNew >= pRingBuf->offEnd) + offReadNew = pRingBuf->offStart; + Log2(("IntNetRingSkipFrame: offReadX: %#x -> %#x (1)\n", offReadOld, offReadNew)); +#ifdef INTNET_POISON_READ_FRAMES + memset((uint8_t *)pHdr + pHdr->offFrame, 0xfe, RT_ALIGN_32(pHdr->cbFrame, INTNETHDR_ALIGNMENT)); + memset(pHdr, 0xef, sizeof(*pHdr)); +#endif + ASMAtomicWriteU32(&pRingBuf->offReadX, offReadNew); +} + + +/** + * Allocates a frame in the specified ring. + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pRingBuf The ring buffer. + * @param cbFrame The frame size. + * @param u8Type The header type. + * @param ppHdr Where to return the frame header. + * Don't touch this! + * @param ppvFrame Where to return the frame pointer. + */ +DECLINLINE(int) intnetRingAllocateFrameInternal(PINTNETRINGBUF pRingBuf, uint32_t cbFrame, uint8_t u8Type, + PINTNETHDR *ppHdr, void **ppvFrame) +{ + /* + * Validate input and adjust the input. + */ + INTNETRINGBUF_ASSERT_SANITY(pRingBuf); + Assert(cbFrame >= sizeof(RTMAC) * 2); + + const uint32_t cb = RT_ALIGN_32(cbFrame, INTNETHDR_ALIGNMENT); + uint32_t offWriteInt = ASMAtomicUoReadU32(&pRingBuf->offWriteInt); + uint32_t offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX); + if (offRead <= offWriteInt) + { + /* + * Try fit it all before the end of the buffer. + */ + if (pRingBuf->offEnd - offWriteInt >= cb + sizeof(INTNETHDR)) + { + uint32_t offNew = offWriteInt + cb + sizeof(INTNETHDR); + if (offNew >= pRingBuf->offEnd) + offNew = pRingBuf->offStart; + if (RT_LIKELY(ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt))) + { /* likely */ } else return VERR_WRONG_ORDER; /* race */ + Log2(("intnetRingAllocateFrameInternal: offWriteInt: %#x -> %#x (1) (R=%#x T=%#x S=%#x)\n", offWriteInt, offNew, offRead, u8Type, cbFrame)); + + PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt); + pHdr->u8Type = u8Type; + pHdr->cbFrame = cbFrame; Assert(pHdr->cbFrame == cbFrame); + pHdr->offFrame = sizeof(INTNETHDR); + + *ppHdr = pHdr; + *ppvFrame = pHdr + 1; + return VINF_SUCCESS; + } + /* + * Try fit the frame at the start of the buffer. + * (The header fits before the end of the buffer because of alignment.) + */ + AssertMsg(pRingBuf->offEnd - offWriteInt >= sizeof(INTNETHDR), ("offEnd=%x offWriteInt=%x\n", pRingBuf->offEnd, offWriteInt)); + if (offRead - pRingBuf->offStart > cb) /* not >= ! */ + { + uint32_t offNew = pRingBuf->offStart + cb; + if (RT_LIKELY(ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt))) + { /* likely */ } else return VERR_WRONG_ORDER; /* race */ + Log2(("intnetRingAllocateFrameInternal: offWriteInt: %#x -> %#x (2) (R=%#x T=%#x S=%#x)\n", offWriteInt, offNew, offRead, u8Type, cbFrame)); + + PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt); + pHdr->u8Type = u8Type; + pHdr->cbFrame = cbFrame; Assert(pHdr->cbFrame == cbFrame); + pHdr->offFrame = pRingBuf->offStart - offWriteInt; + + *ppHdr = pHdr; + *ppvFrame = (uint8_t *)pRingBuf + pRingBuf->offStart; + return VINF_SUCCESS; + } + } + /* + * The reader is ahead of the writer, try fit it into that space. + */ + else if (offRead - offWriteInt > cb + sizeof(INTNETHDR)) /* not >= ! */ + { + uint32_t offNew = offWriteInt + cb + sizeof(INTNETHDR); + if (RT_LIKELY(ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt))) + { /* likely */ } else return VERR_WRONG_ORDER; /* race */ + Log2(("intnetRingAllocateFrameInternal: offWriteInt: %#x -> %#x (3) (R=%#x T=%#x S=%#x)\n", offWriteInt, offNew, offRead, u8Type, cbFrame)); + + PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt); + pHdr->u8Type = u8Type; + pHdr->cbFrame = cbFrame; Assert(pHdr->cbFrame == cbFrame); + pHdr->offFrame = sizeof(INTNETHDR); + + *ppHdr = pHdr; + *ppvFrame = pHdr + 1; + return VINF_SUCCESS; + } + + /* (it didn't fit) */ + *ppHdr = NULL; /* shut up gcc, */ + *ppvFrame = NULL; /* ditto. */ + STAM_REL_COUNTER_INC(&pRingBuf->cOverflows); + return VERR_BUFFER_OVERFLOW; +} + + +/** + * Allocates a normal frame in the specified ring. + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pRingBuf The ring buffer. + * @param cbFrame The frame size. + * @param ppHdr Where to return the frame header. + * Don't touch this! + * @param ppvFrame Where to return the frame pointer. + */ +DECLINLINE(int) IntNetRingAllocateFrame(PINTNETRINGBUF pRingBuf, uint32_t cbFrame, PINTNETHDR *ppHdr, void **ppvFrame) +{ + return intnetRingAllocateFrameInternal(pRingBuf, cbFrame, INTNETHDR_TYPE_FRAME, ppHdr, ppvFrame); +} + + +/** + * Allocates a GSO frame in the specified ring. + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pRingBuf The ring buffer. + * @param cbFrame The frame size. + * @param pGso Pointer to the GSO context. + * @param ppHdr Where to return the frame header. + * Don't touch this! + * @param ppvFrame Where to return the frame pointer. + */ +DECLINLINE(int) IntNetRingAllocateGsoFrame(PINTNETRINGBUF pRingBuf, uint32_t cbFrame, PCPDMNETWORKGSO pGso, + PINTNETHDR *ppHdr, void **ppvFrame) +{ + void *pvFrame = NULL; /* gcc maybe used uninitialized */ + int rc = intnetRingAllocateFrameInternal(pRingBuf, cbFrame + sizeof(*pGso), INTNETHDR_TYPE_GSO, ppHdr, &pvFrame); + if (RT_SUCCESS(rc)) + { + PPDMNETWORKGSO pGsoCopy = (PPDMNETWORKGSO)pvFrame; + *pGsoCopy = *pGso; + *ppvFrame = pGsoCopy + 1; + } + return rc; +} + + +/** + * Commits a frame. + * + * Make sure to commit the frames in the order they've been allocated! + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pRingBuf The ring buffer. + * @param pHdr The frame header returned by + * IntNetRingAllocateFrame. + */ +DECLINLINE(void) IntNetRingCommitFrame(PINTNETRINGBUF pRingBuf, PINTNETHDR pHdr) +{ + /* + * Validate input and commit order. + */ + INTNETRINGBUF_ASSERT_SANITY(pRingBuf); + INTNETHDR_ASSERT_SANITY(pHdr, pRingBuf); + Assert(pRingBuf->offWriteCom == ((uintptr_t)pHdr - (uintptr_t)pRingBuf)); + + /* + * Figure out the offWriteCom for this packet and update the ring. + */ + const uint32_t cbFrame = pHdr->cbFrame; + const uint32_t cb = RT_ALIGN_32(cbFrame, INTNETHDR_ALIGNMENT); + uint32_t offWriteCom = (uint32_t)((uintptr_t)pHdr - (uintptr_t)pRingBuf) + + pHdr->offFrame + + cb; + if (offWriteCom >= pRingBuf->offEnd) + { + Assert(offWriteCom == pRingBuf->offEnd); + offWriteCom = pRingBuf->offStart; + } + Log2(("IntNetRingCommitFrame: offWriteCom: %#x -> %#x (R=%#x T=%#x S=%#x)\n", pRingBuf->offWriteCom, offWriteCom, pRingBuf->offReadX, pHdr->u8Type, cbFrame)); + ASMAtomicWriteU32(&pRingBuf->offWriteCom, offWriteCom); + STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbFrame); + STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames); +} + + +/** + * Commits a frame and injects a filler frame if not all of the buffer was used. + * + * Make sure to commit the frames in the order they've been allocated! + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pRingBuf The ring buffer. + * @param pHdr The frame header returned by + * IntNetRingAllocateFrame. + * @param cbUsed The amount of space actually used. This does + * not include the GSO part. + */ +DECLINLINE(void) IntNetRingCommitFrameEx(PINTNETRINGBUF pRingBuf, PINTNETHDR pHdr, size_t cbUsed) +{ + /* + * Validate input and commit order. + */ + INTNETRINGBUF_ASSERT_SANITY(pRingBuf); + INTNETHDR_ASSERT_SANITY(pHdr, pRingBuf); + Assert(pRingBuf->offWriteCom == ((uintptr_t)pHdr - (uintptr_t)pRingBuf)); + + if (pHdr->u8Type == INTNETHDR_TYPE_GSO) + cbUsed += sizeof(PDMNETWORKGSO); + + /* + * Calc the new write commit offset. + */ + const uint32_t cbAlignedFrame = RT_ALIGN_32(pHdr->cbFrame, INTNETHDR_ALIGNMENT); + const uint32_t cbAlignedUsed = RT_ALIGN_32(cbUsed, INTNETHDR_ALIGNMENT); + uint32_t offWriteCom = (uint32_t)((uintptr_t)pHdr - (uintptr_t)pRingBuf) + + pHdr->offFrame + + cbAlignedFrame; + if (offWriteCom >= pRingBuf->offEnd) + { + Assert(offWriteCom == pRingBuf->offEnd); + offWriteCom = pRingBuf->offStart; + } + + /* + * Insert a dummy frame to pad any unused space. + */ + if (cbAlignedFrame != cbAlignedUsed) + { + /** @todo Later: Try unallocate the extra memory. */ + PINTNETHDR pHdrPadding = (PINTNETHDR)((uint8_t *)pHdr + pHdr->offFrame + cbAlignedUsed); + pHdrPadding->u8Type = INTNETHDR_TYPE_PADDING; + pHdrPadding->cbFrame = cbAlignedFrame - cbAlignedUsed - sizeof(INTNETHDR); + Assert(pHdrPadding->cbFrame == cbAlignedFrame - cbAlignedUsed - sizeof(INTNETHDR)); + pHdrPadding->offFrame = sizeof(INTNETHDR); + pHdr->cbFrame = cbUsed; Assert(pHdr->cbFrame == cbUsed); + } + + Log2(("IntNetRingCommitFrameEx: offWriteCom: %#x -> %#x (R=%#x T=%#x S=%#x P=%#x)\n", pRingBuf->offWriteCom, offWriteCom, pRingBuf->offReadX, pHdr->u8Type, pHdr->cbFrame, cbAlignedFrame - cbAlignedUsed)); + ASMAtomicWriteU32(&pRingBuf->offWriteCom, offWriteCom); + STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbUsed); + STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames); +} + + +/** + * Writes a frame to the specified ring. + * + * Make sure you don't have any uncommitted frames when calling this function! + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pRingBuf The ring buffer. + * @param pvFrame The bits to write. + * @param cbFrame How much to write. + */ +DECLINLINE(int) IntNetRingWriteFrame(PINTNETRINGBUF pRingBuf, const void *pvFrame, size_t cbFrame) +{ + /* + * Validate input. + */ + INTNETRINGBUF_ASSERT_SANITY(pRingBuf); + Assert(cbFrame >= sizeof(RTMAC) * 2); + + /* + * Align the size and read the volatile ring buffer variables. + */ + const uint32_t cb = RT_ALIGN_32(cbFrame, INTNETHDR_ALIGNMENT); + uint32_t offWriteInt = ASMAtomicUoReadU32(&pRingBuf->offWriteInt); + uint32_t offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX); + if (offRead <= offWriteInt) + { + /* + * Try fit it all before the end of the buffer. + */ + if (pRingBuf->offEnd - offWriteInt >= cb + sizeof(INTNETHDR)) + { + uint32_t offNew = offWriteInt + cb + sizeof(INTNETHDR); + if (offNew >= pRingBuf->offEnd) + offNew = pRingBuf->offStart; + if (RT_LIKELY(ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt))) + { /* likely */ } else return VERR_WRONG_ORDER; /* race */ + Log2(("IntNetRingWriteFrame: offWriteInt: %#x -> %#x (1)\n", offWriteInt, offNew)); + + PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt); + pHdr->u8Type = INTNETHDR_TYPE_FRAME; + pHdr->cbFrame = cbFrame; Assert(pHdr->cbFrame == cbFrame); + pHdr->offFrame = sizeof(INTNETHDR); + + memcpy(pHdr + 1, pvFrame, cbFrame); + + Log2(("IntNetRingWriteFrame: offWriteCom: %#x -> %#x (1)\n", pRingBuf->offWriteCom, offNew)); + ASMAtomicWriteU32(&pRingBuf->offWriteCom, offNew); + STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbFrame); + STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames); + return VINF_SUCCESS; + } + /* + * Try fit the frame at the start of the buffer. + * (The header fits before the end of the buffer because of alignment.) + */ + AssertMsg(pRingBuf->offEnd - offWriteInt >= sizeof(INTNETHDR), ("offEnd=%x offWriteInt=%x\n", pRingBuf->offEnd, offWriteInt)); + if (offRead - pRingBuf->offStart > cb) /* not >= ! */ + { + uint32_t offNew = pRingBuf->offStart + cb; + if (RT_LIKELY(ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt))) + { /* likely */ } else return VERR_WRONG_ORDER; /* race */ + Log2(("IntNetRingWriteFrame: offWriteInt: %#x -> %#x (2)\n", offWriteInt, offNew)); + + PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt); + pHdr->u8Type = INTNETHDR_TYPE_FRAME; + pHdr->cbFrame = cbFrame; Assert(pHdr->cbFrame == cbFrame); + pHdr->offFrame = pRingBuf->offStart - offWriteInt; + + memcpy((uint8_t *)pRingBuf + pRingBuf->offStart, pvFrame, cbFrame); + + Log2(("IntNetRingWriteFrame: offWriteCom: %#x -> %#x (2)\n", pRingBuf->offWriteCom, offNew)); + ASMAtomicWriteU32(&pRingBuf->offWriteCom, offNew); + STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbFrame); + STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames); + return VINF_SUCCESS; + } + } + /* + * The reader is ahead of the writer, try fit it into that space. + */ + else if (offRead - offWriteInt > cb + sizeof(INTNETHDR)) /* not >= ! */ + { + uint32_t offNew = offWriteInt + cb + sizeof(INTNETHDR); + if (RT_LIKELY(ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt))) + { /* likely */ } else return VERR_WRONG_ORDER; /* race */ + Log2(("IntNetRingWriteFrame: offWriteInt: %#x -> %#x (3)\n", offWriteInt, offNew)); + + PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt); + pHdr->u8Type = INTNETHDR_TYPE_FRAME; + pHdr->cbFrame = cbFrame; Assert(pHdr->cbFrame == cbFrame); + pHdr->offFrame = sizeof(INTNETHDR); + + memcpy(pHdr + 1, pvFrame, cbFrame); + + Log2(("IntNetRingWriteFrame: offWriteCom: %#x -> %#x (3)\n", pRingBuf->offWriteCom, offNew)); + ASMAtomicWriteU32(&pRingBuf->offWriteCom, offNew); + STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbFrame); + STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames); + return VINF_SUCCESS; + } + + /* (it didn't fit) */ + STAM_REL_COUNTER_INC(&pRingBuf->cOverflows); + return VERR_BUFFER_OVERFLOW; +} + + +/** + * Reads the next frame in the buffer and moves the read cursor past it. + * + * @returns Size of the frame in bytes. 0 is returned if nothing in the buffer. + * @param pRingBuf The ring buffer to read from. + * @param pvFrameDst Where to put the frame. The caller is responsible for + * ensuring that there is sufficient space for the frame. + * + * @deprecated Bad interface, do NOT use it! Only for tstIntNetR0. + */ +DECLINLINE(uint32_t) IntNetRingReadAndSkipFrame(PINTNETRINGBUF pRingBuf, void *pvFrameDst) +{ + INTNETRINGBUF_ASSERT_SANITY(pRingBuf); + + uint32_t offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX); + uint32_t const offWriteCom = ASMAtomicUoReadU32(&pRingBuf->offWriteCom); + if (offRead == offWriteCom) + return 0; + + PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offRead); + INTNETHDR_ASSERT_SANITY(pHdr, pRingBuf); + + uint32_t const cbFrame = pHdr->cbFrame; + int32_t const offFrame = pHdr->offFrame; + const void *pvFrameSrc = (uint8_t *)pHdr + offFrame; + memcpy(pvFrameDst, pvFrameSrc, cbFrame); +#ifdef INTNET_POISON_READ_FRAMES + memset((void *)pvFrameSrc, 0xfe, RT_ALIGN_32(cbFrame, INTNETHDR_ALIGNMENT)); + memset(pHdr, 0xef, sizeof(*pHdr)); +#endif + + /* skip the frame */ + offRead += offFrame + cbFrame; + offRead = RT_ALIGN_32(offRead, INTNETHDR_ALIGNMENT); + Assert(offRead <= pRingBuf->offEnd && offRead >= pRingBuf->offStart); + if (offRead >= pRingBuf->offEnd) + offRead = pRingBuf->offStart; + ASMAtomicWriteU32(&pRingBuf->offReadX, offRead); + return cbFrame; +} + + +/** + * Initializes a buffer structure. + * + * @param pIntBuf The internal networking interface buffer. This + * expected to be cleared prior to calling this + * function. + * @param cbBuf The size of the whole buffer. + * @param cbRecv The receive size. + * @param cbSend The send size. + */ +DECLINLINE(void) IntNetBufInit(PINTNETBUF pIntBuf, uint32_t cbBuf, uint32_t cbRecv, uint32_t cbSend) +{ + AssertCompileSizeAlignment(INTNETBUF, INTNETHDR_ALIGNMENT); + AssertCompileSizeAlignment(INTNETBUF, INTNETRINGBUF_ALIGNMENT); + Assert(cbBuf >= sizeof(INTNETBUF) + cbRecv + cbSend); + Assert(RT_ALIGN_32(cbRecv, INTNETRINGBUF_ALIGNMENT) == cbRecv); + Assert(RT_ALIGN_32(cbSend, INTNETRINGBUF_ALIGNMENT) == cbSend); + Assert(ASMMemIsZero(pIntBuf, cbBuf)); + + pIntBuf->u32Magic = INTNETBUF_MAGIC; + pIntBuf->cbBuf = cbBuf; + pIntBuf->cbRecv = cbRecv; + pIntBuf->cbSend = cbSend; + + /* receive ring buffer. */ + uint32_t offBuf = RT_ALIGN_32(sizeof(INTNETBUF), INTNETRINGBUF_ALIGNMENT) - RT_UOFFSETOF(INTNETBUF, Recv); + pIntBuf->Recv.offStart = offBuf; + pIntBuf->Recv.offReadX = offBuf; + pIntBuf->Recv.offWriteInt = offBuf; + pIntBuf->Recv.offWriteCom = offBuf; + pIntBuf->Recv.offEnd = offBuf + cbRecv; + + /* send ring buffer. */ + offBuf += cbRecv + RT_UOFFSETOF(INTNETBUF, Recv) - RT_UOFFSETOF(INTNETBUF, Send); + pIntBuf->Send.offStart = offBuf; + pIntBuf->Send.offReadX = offBuf; + pIntBuf->Send.offWriteCom = offBuf; + pIntBuf->Send.offWriteInt = offBuf; + pIntBuf->Send.offEnd = offBuf + cbSend; + Assert(cbBuf >= offBuf + cbSend); +} + +#endif /* __cplusplus */ + +#endif /* !VBOX_INCLUDED_intnetinline_h */ + diff --git a/include/VBox/iommu-amd.h b/include/VBox/iommu-amd.h new file mode 100644 index 00000000..76558831 --- /dev/null +++ b/include/VBox/iommu-amd.h @@ -0,0 +1,2718 @@ +/** @file + * IOMMU - Input/Output Memory Management Unit (AMD). + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_iommu_amd_h +#define VBOX_INCLUDED_iommu_amd_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + +/** + * @name PCI configuration register offsets. + * In accordance with the AMD spec. + * @{ + */ +#define IOMMU_PCI_OFF_CAP_HDR 0x40 +#define IOMMU_PCI_OFF_BASE_ADDR_REG_LO 0x44 +#define IOMMU_PCI_OFF_BASE_ADDR_REG_HI 0x48 +#define IOMMU_PCI_OFF_RANGE_REG 0x4c +#define IOMMU_PCI_OFF_MISCINFO_REG_0 0x50 +#define IOMMU_PCI_OFF_MISCINFO_REG_1 0x54 +#define IOMMU_PCI_OFF_MSI_CAP_HDR 0x64 +#define IOMMU_PCI_OFF_MSI_ADDR_LO 0x68 +#define IOMMU_PCI_OFF_MSI_ADDR_HI 0x6c +#define IOMMU_PCI_OFF_MSI_DATA 0x70 +#define IOMMU_PCI_OFF_MSI_MAP_CAP_HDR 0x74 +/** @} */ + +/** + * @name MMIO register offsets. + * In accordance with the AMD spec. + * @{ + */ +#define IOMMU_MMIO_OFF_QWORD_TABLE_0_START IOMMU_MMIO_OFF_DEV_TAB_BAR +#define IOMMU_MMIO_OFF_DEV_TAB_BAR 0x00 +#define IOMMU_MMIO_OFF_CMD_BUF_BAR 0x08 +#define IOMMU_MMIO_OFF_EVT_LOG_BAR 0x10 +#define IOMMU_MMIO_OFF_CTRL 0x18 +#define IOMMU_MMIO_OFF_EXCL_BAR 0x20 +#define IOMMU_MMIO_OFF_EXCL_RANGE_LIMIT 0x28 +#define IOMMU_MMIO_OFF_EXT_FEAT 0x30 + +#define IOMMU_MMIO_OFF_PPR_LOG_BAR 0x38 +#define IOMMU_MMIO_OFF_HW_EVT_HI 0x40 +#define IOMMU_MMIO_OFF_HW_EVT_LO 0x48 +#define IOMMU_MMIO_OFF_HW_EVT_STATUS 0x50 + +#define IOMMU_MMIO_OFF_SMI_FLT_FIRST 0x60 +#define IOMMU_MMIO_OFF_SMI_FLT_LAST 0xd8 + +#define IOMMU_MMIO_OFF_GALOG_BAR 0xe0 +#define IOMMU_MMIO_OFF_GALOG_TAIL_ADDR 0xe8 + +#define IOMMU_MMIO_OFF_PPR_LOG_B_BAR 0xf0 +#define IOMMU_MMIO_OFF_PPR_EVT_B_BAR 0xf8 + +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_FIRST 0x100 +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_1 0x100 +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_2 0x108 +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_3 0x110 +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_4 0x118 +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_5 0x120 +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_6 0x128 +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_7 0x130 +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_LAST 0x130 + +#define IOMMU_MMIO_OFF_DEV_SPECIFIC_FEAT 0x138 +#define IOMMU_MMIO_OFF_DEV_SPECIFIC_CTRL 0x140 +#define IOMMU_MMIO_OFF_DEV_SPECIFIC_STATUS 0x148 + +#define IOMMU_MMIO_OFF_MSI_VECTOR_0 0x150 +#define IOMMU_MMIO_OFF_MSI_VECTOR_1 0x154 +#define IOMMU_MMIO_OFF_MSI_CAP_HDR 0x158 +#define IOMMU_MMIO_OFF_MSI_ADDR_LO 0x15c +#define IOMMU_MMIO_OFF_MSI_ADDR_HI 0x160 +#define IOMMU_MMIO_OFF_MSI_DATA 0x164 +#define IOMMU_MMIO_OFF_MSI_MAPPING_CAP_HDR 0x168 + +#define IOMMU_MMIO_OFF_PERF_OPT_CTRL 0x16c + +#define IOMMU_MMIO_OFF_XT_GEN_INTR_CTRL 0x170 +#define IOMMU_MMIO_OFF_XT_PPR_INTR_CTRL 0x178 +#define IOMMU_MMIO_OFF_XT_GALOG_INT_CTRL 0x180 +#define IOMMU_MMIO_OFF_QWORD_TABLE_0_END (IOMMU_MMIO_OFF_XT_GALOG_INT_CTRL + 8) + +#define IOMMU_MMIO_OFF_QWORD_TABLE_1_START IOMMU_MMIO_OFF_MARC_APER_BAR_0 +#define IOMMU_MMIO_OFF_MARC_APER_BAR_0 0x200 +#define IOMMU_MMIO_OFF_MARC_APER_RELOC_0 0x208 +#define IOMMU_MMIO_OFF_MARC_APER_LEN_0 0x210 +#define IOMMU_MMIO_OFF_MARC_APER_BAR_1 0x218 +#define IOMMU_MMIO_OFF_MARC_APER_RELOC_1 0x220 +#define IOMMU_MMIO_OFF_MARC_APER_LEN_1 0x228 +#define IOMMU_MMIO_OFF_MARC_APER_BAR_2 0x230 +#define IOMMU_MMIO_OFF_MARC_APER_RELOC_2 0x238 +#define IOMMU_MMIO_OFF_MARC_APER_LEN_2 0x240 +#define IOMMU_MMIO_OFF_MARC_APER_BAR_3 0x248 +#define IOMMU_MMIO_OFF_MARC_APER_RELOC_3 0x250 +#define IOMMU_MMIO_OFF_MARC_APER_LEN_3 0x258 +#define IOMMU_MMIO_OFF_QWORD_TABLE_1_END (IOMMU_MMIO_OFF_MARC_APER_LEN_3 + 8) + +#define IOMMU_MMIO_OFF_QWORD_TABLE_2_START IOMMU_MMIO_OFF_RSVD_REG +#define IOMMU_MMIO_OFF_RSVD_REG 0x1ff8 + +#define IOMMU_MMIO_OFF_CMD_BUF_HEAD_PTR 0x2000 +#define IOMMU_MMIO_OFF_CMD_BUF_TAIL_PTR 0x2008 +#define IOMMU_MMIO_OFF_EVT_LOG_HEAD_PTR 0x2010 +#define IOMMU_MMIO_OFF_EVT_LOG_TAIL_PTR 0x2018 + +#define IOMMU_MMIO_OFF_STATUS 0x2020 + +#define IOMMU_MMIO_OFF_PPR_LOG_HEAD_PTR 0x2030 +#define IOMMU_MMIO_OFF_PPR_LOG_TAIL_PTR 0x2038 + +#define IOMMU_MMIO_OFF_GALOG_HEAD_PTR 0x2040 +#define IOMMU_MMIO_OFF_GALOG_TAIL_PTR 0x2048 + +#define IOMMU_MMIO_OFF_PPR_LOG_B_HEAD_PTR 0x2050 +#define IOMMU_MMIO_OFF_PPR_LOG_B_TAIL_PTR 0x2058 + +#define IOMMU_MMIO_OFF_EVT_LOG_B_HEAD_PTR 0x2070 +#define IOMMU_MMIO_OFF_EVT_LOG_B_TAIL_PTR 0x2078 + +#define IOMMU_MMIO_OFF_PPR_LOG_AUTO_RESP 0x2080 +#define IOMMU_MMIO_OFF_PPR_LOG_OVERFLOW_EARLY 0x2088 +#define IOMMU_MMIO_OFF_PPR_LOG_B_OVERFLOW_EARLY 0x2090 +#define IOMMU_MMIO_OFF_QWORD_TABLE_2_END (IOMMU_MMIO_OFF_PPR_LOG_B_OVERFLOW_EARLY + 8) +/** @} */ + +/** + * @name MMIO register-access table offsets. + * Each table [first..last] (both inclusive) represents the range of registers + * covered by a distinct register-access table. This is done due to arbitrary large + * gaps in the MMIO register offsets themselves. + * @{ + */ +#define IOMMU_MMIO_OFF_TABLE_0_FIRST 0x00 +#define IOMMU_MMIO_OFF_TABLE_0_LAST 0x258 + +#define IOMMU_MMIO_OFF_TABLE_1_FIRST 0x1ff8 +#define IOMMU_MMIO_OFF_TABLE_1_LAST 0x2090 +/** @} */ + +/** + * @name Commands. + * In accordance with the AMD spec. + * @{ + */ +#define IOMMU_CMD_COMPLETION_WAIT 0x01 +#define IOMMU_CMD_INV_DEV_TAB_ENTRY 0x02 +#define IOMMU_CMD_INV_IOMMU_PAGES 0x03 +#define IOMMU_CMD_INV_IOTLB_PAGES 0x04 +#define IOMMU_CMD_INV_INTR_TABLE 0x05 +#define IOMMU_CMD_PREFETCH_IOMMU_PAGES 0x06 +#define IOMMU_CMD_COMPLETE_PPR_REQ 0x07 +#define IOMMU_CMD_INV_IOMMU_ALL 0x08 +/** @} */ + +/** + * @name Event codes. + * In accordance with the AMD spec. + * @{ + */ +#define IOMMU_EVT_ILLEGAL_DEV_TAB_ENTRY 0x01 +#define IOMMU_EVT_IO_PAGE_FAULT 0x02 +#define IOMMU_EVT_DEV_TAB_HW_ERROR 0x03 +#define IOMMU_EVT_PAGE_TAB_HW_ERROR 0x04 +#define IOMMU_EVT_ILLEGAL_CMD_ERROR 0x05 +#define IOMMU_EVT_COMMAND_HW_ERROR 0x06 +#define IOMMU_EVT_IOTLB_INV_TIMEOUT 0x07 +#define IOMMU_EVT_INVALID_DEV_REQ 0x08 +#define IOMMU_EVT_INVALID_PPR_REQ 0x09 +#define IOMMU_EVT_EVENT_COUNTER_ZERO 0x10 +#define IOMMU_EVT_GUEST_EVENT_FAULT 0x11 +/** @} */ + +/** + * @name IOMMU Capability Header. + * In accordance with the AMD spec. + * @{ + */ +/** CapId: Capability ID. */ +#define IOMMU_BF_CAPHDR_CAP_ID_SHIFT 0 +#define IOMMU_BF_CAPHDR_CAP_ID_MASK UINT32_C(0x000000ff) +/** CapPtr: Capability Pointer. */ +#define IOMMU_BF_CAPHDR_CAP_PTR_SHIFT 8 +#define IOMMU_BF_CAPHDR_CAP_PTR_MASK UINT32_C(0x0000ff00) +/** CapType: Capability Type. */ +#define IOMMU_BF_CAPHDR_CAP_TYPE_SHIFT 16 +#define IOMMU_BF_CAPHDR_CAP_TYPE_MASK UINT32_C(0x00070000) +/** CapRev: Capability Revision. */ +#define IOMMU_BF_CAPHDR_CAP_REV_SHIFT 19 +#define IOMMU_BF_CAPHDR_CAP_REV_MASK UINT32_C(0x00f80000) +/** IoTlbSup: IO TLB Support. */ +#define IOMMU_BF_CAPHDR_IOTLB_SUP_SHIFT 24 +#define IOMMU_BF_CAPHDR_IOTLB_SUP_MASK UINT32_C(0x01000000) +/** HtTunnel: HyperTransport Tunnel translation support. */ +#define IOMMU_BF_CAPHDR_HT_TUNNEL_SHIFT 25 +#define IOMMU_BF_CAPHDR_HT_TUNNEL_MASK UINT32_C(0x02000000) +/** NpCache: Not Present table entries Cached. */ +#define IOMMU_BF_CAPHDR_NP_CACHE_SHIFT 26 +#define IOMMU_BF_CAPHDR_NP_CACHE_MASK UINT32_C(0x04000000) +/** EFRSup: Extended Feature Register (EFR) Supported. */ +#define IOMMU_BF_CAPHDR_EFR_SUP_SHIFT 27 +#define IOMMU_BF_CAPHDR_EFR_SUP_MASK UINT32_C(0x08000000) +/** CapExt: Miscellaneous Information Register Supported . */ +#define IOMMU_BF_CAPHDR_CAP_EXT_SHIFT 28 +#define IOMMU_BF_CAPHDR_CAP_EXT_MASK UINT32_C(0x10000000) +/** Bits 31:29 reserved. */ +#define IOMMU_BF_CAPHDR_RSVD_29_31_SHIFT 29 +#define IOMMU_BF_CAPHDR_RSVD_29_31_MASK UINT32_C(0xe0000000) +RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_CAPHDR_, UINT32_C(0), UINT32_MAX, + (CAP_ID, CAP_PTR, CAP_TYPE, CAP_REV, IOTLB_SUP, HT_TUNNEL, NP_CACHE, EFR_SUP, CAP_EXT, RSVD_29_31)); +/** @} */ + +/** + * @name IOMMU Base Address Low Register. + * In accordance with the AMD spec. + * @{ + */ +/** Enable: Enables access to the address specified in the Base Address Register. */ +#define IOMMU_BF_BASEADDR_LO_ENABLE_SHIFT 0 +#define IOMMU_BF_BASEADDR_LO_ENABLE_MASK UINT32_C(0x00000001) +/** Bits 13:1 reserved. */ +#define IOMMU_BF_BASEADDR_LO_RSVD_1_13_SHIFT 1 +#define IOMMU_BF_BASEADDR_LO_RSVD_1_13_MASK UINT32_C(0x00003ffe) +/** Base Address[31:14]: Low Base address of IOMMU MMIO control registers. */ +#define IOMMU_BF_BASEADDR_LO_ADDR_SHIFT 14 +#define IOMMU_BF_BASEADDR_LO_ADDR_MASK UINT32_C(0xffffc000) +RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_BASEADDR_LO_, UINT32_C(0), UINT32_MAX, + (ENABLE, RSVD_1_13, ADDR)); +/** @} */ + +/** + * @name IOMMU Range Register. + * In accordance with the AMD spec. + * @{ + */ +/** UnitID: HyperTransport Unit ID. */ +#define IOMMU_BF_RANGE_UNIT_ID_SHIFT 0 +#define IOMMU_BF_RANGE_UNIT_ID_MASK UINT32_C(0x0000001f) +/** Bits 6:5 reserved. */ +#define IOMMU_BF_RANGE_RSVD_5_6_SHIFT 5 +#define IOMMU_BF_RANGE_RSVD_5_6_MASK UINT32_C(0x00000060) +/** RngValid: Range valid. */ +#define IOMMU_BF_RANGE_VALID_SHIFT 7 +#define IOMMU_BF_RANGE_VALID_MASK UINT32_C(0x00000080) +/** BusNumber: Device range bus number. */ +#define IOMMU_BF_RANGE_BUS_NUMBER_SHIFT 8 +#define IOMMU_BF_RANGE_BUS_NUMBER_MASK UINT32_C(0x0000ff00) +/** First Device. */ +#define IOMMU_BF_RANGE_FIRST_DEVICE_SHIFT 16 +#define IOMMU_BF_RANGE_FIRST_DEVICE_MASK UINT32_C(0x00ff0000) +/** Last Device. */ +#define IOMMU_BF_RANGE_LAST_DEVICE_SHIFT 24 +#define IOMMU_BF_RANGE_LAST_DEVICE_MASK UINT32_C(0xff000000) +RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_RANGE_, UINT32_C(0), UINT32_MAX, + (UNIT_ID, RSVD_5_6, VALID, BUS_NUMBER, FIRST_DEVICE, LAST_DEVICE)); +/** @} */ + +/** + * @name IOMMU Miscellaneous Information Register 0. + * In accordance with the AMD spec. + * @{ + */ +/** MsiNum: MSI message number. */ +#define IOMMU_BF_MISCINFO_0_MSI_NUM_SHIFT 0 +#define IOMMU_BF_MISCINFO_0_MSI_NUM_MASK UINT32_C(0x0000001f) +/** GvaSize: Guest Virtual Address Size. */ +#define IOMMU_BF_MISCINFO_0_GVA_SIZE_SHIFT 5 +#define IOMMU_BF_MISCINFO_0_GVA_SIZE_MASK UINT32_C(0x000000e0) +/** PaSize: Physical Address Size. */ +#define IOMMU_BF_MISCINFO_0_PA_SIZE_SHIFT 8 +#define IOMMU_BF_MISCINFO_0_PA_SIZE_MASK UINT32_C(0x00007f00) +/** VaSize: Virtual Address Size. */ +#define IOMMU_BF_MISCINFO_0_VA_SIZE_SHIFT 15 +#define IOMMU_BF_MISCINFO_0_VA_SIZE_MASK UINT32_C(0x003f8000) +/** HtAtsResv: HyperTransport ATS Response Address range Reserved. */ +#define IOMMU_BF_MISCINFO_0_HT_ATS_RESV_SHIFT 22 +#define IOMMU_BF_MISCINFO_0_HT_ATS_RESV_MASK UINT32_C(0x00400000) +/** Bits 26:23 reserved. */ +#define IOMMU_BF_MISCINFO_0_RSVD_23_26_SHIFT 23 +#define IOMMU_BF_MISCINFO_0_RSVD_23_26_MASK UINT32_C(0x07800000) +/** MsiNumPPR: Peripheral Page Request MSI message number. */ +#define IOMMU_BF_MISCINFO_0_MSI_NUM_PPR_SHIFT 27 +#define IOMMU_BF_MISCINFO_0_MSI_NUM_PPR_MASK UINT32_C(0xf8000000) +RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_MISCINFO_0_, UINT32_C(0), UINT32_MAX, + (MSI_NUM, GVA_SIZE, PA_SIZE, VA_SIZE, HT_ATS_RESV, RSVD_23_26, MSI_NUM_PPR)); +/** @} */ + +/** + * @name IOMMU Miscellaneous Information Register 1. + * In accordance with the AMD spec. + * @{ + */ +/** MsiNumGA: MSI message number for guest virtual-APIC log. */ +#define IOMMU_BF_MISCINFO_1_MSI_NUM_GA_SHIFT 0 +#define IOMMU_BF_MISCINFO_1_MSI_NUM_GA_MASK UINT32_C(0x0000001f) +/** Bits 31:5 reserved. */ +#define IOMMU_BF_MISCINFO_1_RSVD_5_31_SHIFT 5 +#define IOMMU_BF_MISCINFO_1_RSVD_5_31_MASK UINT32_C(0xffffffe0) +RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_MISCINFO_1_, UINT32_C(0), UINT32_MAX, + (MSI_NUM_GA, RSVD_5_31)); +/** @} */ + +/** + * @name MSI Capability Header Register. + * In accordance with the AMD spec. + * @{ + */ +/** MsiCapId: Capability ID. */ +#define IOMMU_BF_MSI_CAP_HDR_CAP_ID_SHIFT 0 +#define IOMMU_BF_MSI_CAP_HDR_CAP_ID_MASK UINT32_C(0x000000ff) +/** MsiCapPtr: Pointer (PCI config offset) to the next capability. */ +#define IOMMU_BF_MSI_CAP_HDR_CAP_PTR_SHIFT 8 +#define IOMMU_BF_MSI_CAP_HDR_CAP_PTR_MASK UINT32_C(0x0000ff00) +/** MsiEn: Message Signal Interrupt enable. */ +#define IOMMU_BF_MSI_CAP_HDR_EN_SHIFT 16 +#define IOMMU_BF_MSI_CAP_HDR_EN_MASK UINT32_C(0x00010000) +/** MsiMultMessCap: MSI Multi-Message Capability. */ +#define IOMMU_BF_MSI_CAP_HDR_MULTMESS_CAP_SHIFT 17 +#define IOMMU_BF_MSI_CAP_HDR_MULTMESS_CAP_MASK UINT32_C(0x000e0000) +/** MsiMultMessEn: MSI Mult-Message Enable. */ +#define IOMMU_BF_MSI_CAP_HDR_MULTMESS_EN_SHIFT 20 +#define IOMMU_BF_MSI_CAP_HDR_MULTMESS_EN_MASK UINT32_C(0x00700000) +/** Msi64BitEn: MSI 64-bit Enabled. */ +#define IOMMU_BF_MSI_CAP_HDR_64BIT_EN_SHIFT 23 +#define IOMMU_BF_MSI_CAP_HDR_64BIT_EN_MASK UINT32_C(0x00800000) +/** Bits 31:24 reserved. */ +#define IOMMU_BF_MSI_CAP_HDR_RSVD_24_31_SHIFT 24 +#define IOMMU_BF_MSI_CAP_HDR_RSVD_24_31_MASK UINT32_C(0xff000000) +RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_MSI_CAP_HDR_, UINT32_C(0), UINT32_MAX, + (CAP_ID, CAP_PTR, EN, MULTMESS_CAP, MULTMESS_EN, 64BIT_EN, RSVD_24_31)); +/** @} */ + +/** + * @name MSI Mapping Capability Header Register. + * In accordance with the AMD spec. + * @{ + */ +/** MsiMapCapId: Capability ID. */ +#define IOMMU_BF_MSI_MAP_CAPHDR_CAP_ID_SHIFT 0 +#define IOMMU_BF_MSI_MAP_CAPHDR_CAP_ID_MASK UINT32_C(0x000000ff) +/** MsiMapCapPtr: Pointer (PCI config offset) to the next capability. */ +#define IOMMU_BF_MSI_MAP_CAPHDR_CAP_PTR_SHIFT 8 +#define IOMMU_BF_MSI_MAP_CAPHDR_CAP_PTR_MASK UINT32_C(0x0000ff00) +/** MsiMapEn: MSI mapping capability enable. */ +#define IOMMU_BF_MSI_MAP_CAPHDR_EN_SHIFT 16 +#define IOMMU_BF_MSI_MAP_CAPHDR_EN_MASK UINT32_C(0x00010000) +/** MsiMapFixd: MSI interrupt mapping range is not programmable. */ +#define IOMMU_BF_MSI_MAP_CAPHDR_FIXED_SHIFT 17 +#define IOMMU_BF_MSI_MAP_CAPHDR_FIXED_MASK UINT32_C(0x00020000) +/** Bits 18:28 reserved. */ +#define IOMMU_BF_MSI_MAP_CAPHDR_RSVD_18_28_SHIFT 18 +#define IOMMU_BF_MSI_MAP_CAPHDR_RSVD_18_28_MASK UINT32_C(0x07fc0000) +/** MsiMapCapType: MSI mapping capability. */ +#define IOMMU_BF_MSI_MAP_CAPHDR_CAP_TYPE_SHIFT 27 +#define IOMMU_BF_MSI_MAP_CAPHDR_CAP_TYPE_MASK UINT32_C(0xf8000000) +RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_MSI_MAP_CAPHDR_, UINT32_C(0), UINT32_MAX, + (CAP_ID, CAP_PTR, EN, FIXED, RSVD_18_28, CAP_TYPE)); +/** @} */ + +/** + * @name IOMMU Status Register Bits. + * In accordance with the AMD spec. + * @{ + */ +/** EventOverflow: Event log overflow. */ +#define IOMMU_STATUS_EVT_LOG_OVERFLOW RT_BIT_64(0) +/** EventLogInt: Event log interrupt. */ +#define IOMMU_STATUS_EVT_LOG_INTR RT_BIT_64(1) +/** ComWaitInt: Completion wait interrupt. */ +#define IOMMU_STATUS_COMPLETION_WAIT_INTR RT_BIT_64(2) +/** EventLogRun: Event log is running. */ +#define IOMMU_STATUS_EVT_LOG_RUNNING RT_BIT_64(3) +/** CmdBufRun: Command buffer is running. */ +#define IOMMU_STATUS_CMD_BUF_RUNNING RT_BIT_64(4) +/** PprOverflow: Peripheral page request log overflow. */ +#define IOMMU_STATUS_PPR_LOG_OVERFLOW RT_BIT_64(5) +/** PprInt: Peripheral page request log interrupt. */ +#define IOMMU_STATUS_PPR_LOG_INTR RT_BIT_64(6) +/** PprLogRun: Peripheral page request log is running. */ +#define IOMMU_STATUS_PPR_LOG_RUN RT_BIT_64(7) +/** GALogRun: Guest virtual-APIC log is running. */ +#define IOMMU_STATUS_GA_LOG_RUN RT_BIT_64(8) +/** GALOverflow: Guest virtual-APIC log overflow. */ +#define IOMMU_STATUS_GA_LOG_OVERFLOW RT_BIT_64(9) +/** GAInt: Guest virtual-APIC log interrupt. */ +#define IOMMU_STATUS_GA_LOG_INTR RT_BIT_64(10) +/** PprOvrflwB: PPR Log B overflow. */ +#define IOMMU_STATUS_PPR_LOG_B_OVERFLOW RT_BIT_64(11) +/** PprLogActive: PPR Log B is active. */ +#define IOMMU_STATUS_PPR_LOG_B_ACTIVE RT_BIT_64(12) +/** EvtOvrflwB: Event log B overflow. */ +#define IOMMU_STATUS_EVT_LOG_B_OVERFLOW RT_BIT_64(15) +/** EventLogActive: Event log B active. */ +#define IOMMU_STATUS_EVT_LOG_B_ACTIVE RT_BIT_64(16) +/** PprOvrflwEarlyB: PPR log B overflow early warning. */ +#define IOMMU_STATUS_PPR_LOG_B_OVERFLOW_EARLY RT_BIT_64(17) +/** PprOverflowEarly: PPR log overflow early warning. */ +#define IOMMU_STATUS_PPR_LOG_OVERFLOW_EARLY RT_BIT_64(18) +/** @} */ + +/** @name IOMMU_IO_PERM_XXX: IOMMU I/O access permissions bits. + * In accordance with the AMD spec. + * + * These values match the shifted values of the IR and IW field of the DTE and the + * PTE, PDE of the I/O page tables. + * + * @{ */ +#define IOMMU_IO_PERM_NONE (0) +#define IOMMU_IO_PERM_READ RT_BIT_64(0) +#define IOMMU_IO_PERM_WRITE RT_BIT_64(1) +#define IOMMU_IO_PERM_READ_WRITE (IOMMU_IO_PERM_READ | IOMMU_IO_PERM_WRITE) +#define IOMMU_IO_PERM_SHIFT 61 +#define IOMMU_IO_PERM_MASK 0x3 +/** @} */ + +/** @name SYSMGT_TYPE_XXX: System Management Message Enable Types. + * In accordance with the AMD spec. + * @{ */ +#define SYSMGTTYPE_DMA_DENY (0) +#define SYSMGTTYPE_MSG_ALL_ALLOW (1) +#define SYSMGTTYPE_MSG_INT_ALLOW (2) +#define SYSMGTTYPE_DMA_ALLOW (3) +/** @} */ + +/** @name IOMMU_INTR_CTRL_XX: DTE::IntCtl field values. + * These are control bits for handling fixed and arbitrated interrupts. + * In accordance with the AMD spec. + * @{ */ +#define IOMMU_INTR_CTRL_TARGET_ABORT (0) +#define IOMMU_INTR_CTRL_FWD_UNMAPPED (1) +#define IOMMU_INTR_CTRL_REMAP (2) +#define IOMMU_INTR_CTRL_RSVD (3) +/** @} */ + +/** Gets the device table length (in bytes) given the device table pointer. */ +#define IOMMU_GET_DEV_TAB_LEN(a_pDevTab) (((a_pDevTab)->n.u9Size + 1) << X86_PAGE_4K_SHIFT) + +/** + * The Device ID. + * In accordance with VirtualBox's PCI configuration. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint16_t u3Function : 3; /**< Bits 2:0 - Function. */ + RT_GCC_EXTENSION uint16_t u9Device : 9; /**< Bits 11:3 - Device. */ + RT_GCC_EXTENSION uint16_t u4Bus : 4; /**< Bits 15:12 - Bus. */ + } n; + /** The unsigned integer view. */ + uint16_t u; +} DEVICE_ID_T; +AssertCompileSize(DEVICE_ID_T, 2); + +/** + * Device Table Entry (DTE). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u1Valid : 1; /**< Bit 0 - V: Valid. */ + RT_GCC_EXTENSION uint64_t u1TranslationValid : 1; /**< Bit 1 - TV: Translation information Valid. */ + RT_GCC_EXTENSION uint64_t u5Rsvd0 : 5; /**< Bits 6:2 - Reserved. */ + RT_GCC_EXTENSION uint64_t u2Had : 2; /**< Bits 8:7 - HAD: Host Access Dirty. */ + RT_GCC_EXTENSION uint64_t u3Mode : 3; /**< Bits 11:9 - Mode: Paging mode. */ + RT_GCC_EXTENSION uint64_t u40PageTableRootPtrLo : 40; /**< Bits 51:12 - Page Table Root Pointer. */ + RT_GCC_EXTENSION uint64_t u1Ppr : 1; /**< Bit 52 - PPR: Peripheral Page Request. */ + RT_GCC_EXTENSION uint64_t u1GstPprRespPasid : 1; /**< Bit 53 - GRPR: Guest PPR Response with PASID. */ + RT_GCC_EXTENSION uint64_t u1GstIoValid : 1; /**< Bit 54 - GIoV: Guest I/O Protection Valid. */ + RT_GCC_EXTENSION uint64_t u1GstTranslateValid : 1; /**< Bit 55 - GV: Guest translation Valid. */ + RT_GCC_EXTENSION uint64_t u2GstMode : 2; /**< Bits 57:56 - GLX: Guest Paging mode levels. */ + RT_GCC_EXTENSION uint64_t u3GstCr3TableRootPtrLo : 3; /**< Bits 60:58 - GCR3 TRP: Guest CR3 Table Root Ptr (Lo). */ + RT_GCC_EXTENSION uint64_t u1IoRead : 1; /**< Bit 61 - IR: I/O Read permission. */ + RT_GCC_EXTENSION uint64_t u1IoWrite : 1; /**< Bit 62 - IW: I/O Write permission. */ + RT_GCC_EXTENSION uint64_t u1Rsvd0 : 1; /**< Bit 63 - Reserved. */ + RT_GCC_EXTENSION uint64_t u16DomainId : 16; /**< Bits 79:64 - Domain ID. */ + RT_GCC_EXTENSION uint64_t u16GstCr3TableRootPtrMid : 16; /**< Bits 95:80 - GCR3 TRP: Guest CR3 Table Root Ptr (Mid). */ + RT_GCC_EXTENSION uint64_t u1IoTlbEnable : 1; /**< Bit 96 - I: IOTLB Enable (remote). */ + RT_GCC_EXTENSION uint64_t u1SuppressPfEvents : 1; /**< Bit 97 - SE: Suppress Page-fault events. */ + RT_GCC_EXTENSION uint64_t u1SuppressAllPfEvents : 1; /**< Bit 98 - SA: Suppress All Page-fault events. */ + RT_GCC_EXTENSION uint64_t u2IoCtl : 2; /**< Bits 100:99 - IoCtl: Port I/O Control. */ + RT_GCC_EXTENSION uint64_t u1Cache : 1; /**< Bit 101 - Cache: IOTLB Cache Hint. */ + RT_GCC_EXTENSION uint64_t u1SnoopDisable : 1; /**< Bit 102 - SD: Snoop Disable. */ + RT_GCC_EXTENSION uint64_t u1AllowExclusion : 1; /**< Bit 103 - EX: Allow Exclusion. */ + RT_GCC_EXTENSION uint64_t u2SysMgt : 2; /**< Bits 105:104 - SysMgt: System Management message enable. */ + RT_GCC_EXTENSION uint64_t u1Rsvd1 : 1; /**< Bit 106 - Reserved. */ + RT_GCC_EXTENSION uint64_t u21GstCr3TableRootPtrHi : 21; /**< Bits 127:107 - GCR3 TRP: Guest CR3 Table Root Ptr (Hi). */ + RT_GCC_EXTENSION uint64_t u1IntrMapValid : 1; /**< Bit 128 - IV: Interrupt map Valid. */ + RT_GCC_EXTENSION uint64_t u4IntrTableLength : 4; /**< Bits 132:129 - IntTabLen: Interrupt Table Length. */ + RT_GCC_EXTENSION uint64_t u1IgnoreUnmappedIntrs : 1; /**< Bits 133 - IG: Ignore unmapped interrupts. */ + RT_GCC_EXTENSION uint64_t u46IntrTableRootPtr : 46; /**< Bits 179:134 - Interrupt Root Table Pointer. */ + RT_GCC_EXTENSION uint64_t u4Rsvd0 : 4; /**< Bits 183:180 - Reserved. */ + RT_GCC_EXTENSION uint64_t u1InitPassthru : 1; /**< Bits 184 - INIT Pass-through. */ + RT_GCC_EXTENSION uint64_t u1ExtIntPassthru : 1; /**< Bits 185 - External Interrupt Pass-through. */ + RT_GCC_EXTENSION uint64_t u1NmiPassthru : 1; /**< Bits 186 - NMI Pass-through. */ + RT_GCC_EXTENSION uint64_t u1Rsvd2 : 1; /**< Bits 187 - Reserved. */ + RT_GCC_EXTENSION uint64_t u2IntrCtrl : 2; /**< Bits 189:188 - IntCtl: Interrupt Control. */ + RT_GCC_EXTENSION uint64_t u1Lint0Passthru : 1; /**< Bit 190 - Lint0Pass: LINT0 Pass-through. */ + RT_GCC_EXTENSION uint64_t u1Lint1Passthru : 1; /**< Bit 191 - Lint1Pass: LINT1 Pass-through. */ + RT_GCC_EXTENSION uint64_t u32Rsvd0 : 32; /**< Bits 223:192 - Reserved. */ + RT_GCC_EXTENSION uint64_t u22Rsvd0 : 22; /**< Bits 245:224 - Reserved. */ + RT_GCC_EXTENSION uint64_t u1AttrOverride : 1; /**< Bit 246 - AttrV: Attribute Override. */ + RT_GCC_EXTENSION uint64_t u1Mode0FC : 1; /**< Bit 247 - Mode0FC. */ + RT_GCC_EXTENSION uint64_t u8SnoopAttr : 8; /**< Bits 255:248 - Snoop Attribute. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[8]; + /** The 64-bit unsigned integer view. */ + uint64_t au64[4]; +} DTE_T; +AssertCompileSize(DTE_T, 32); +/** Pointer to a device table entry. */ +typedef DTE_T *PDTE_T; +/** Pointer to a const device table entry. */ +typedef DTE_T const *PCDTE_T; + +/** Mask of valid bits for EPHSUP (Enhanced Peripheral Page Request Handling + * Support) feature (bits 52:53). */ +#define IOMMU_DTE_QWORD_0_FEAT_EPHSUP_MASK UINT64_C(0x0030000000000000) + +/** Mask of valid bits for GTSup (Guest Translation Support) feature (bits 55:60, + * bits 80:95). */ +#define IOMMU_DTE_QWORD_0_FEAT_GTSUP_MASK UINT64_C(0x1f80000000000000) +#define IOMMU_DTE_QWORD_1_FEAT_GTSUP_MASK UINT64_C(0x00000000ffff0000) + +/** Mask of valid bits for GIoSup (Guest I/O Protection Support) feature (bit 54). */ +#define IOMMU_DTE_QWORD_0_FEAT_GIOSUP_MASK UINT64_C(0x0040000000000000) + +/** Mask of valid DTE feature bits. */ +#define IOMMU_DTE_QWORD_0_FEAT_MASK ( IOMMU_DTE_QWORD_0_FEAT_EPHSUP_MASK \ + | IOMMU_DTE_QWORD_0_FEAT_GTSUP_MASK \ + | IOMMU_DTE_QWORD_0_FEAT_GIOSUP_MASK) +#define IOMMU_DTE_QWORD_1_FEAT_MASK IOMMU_DTE_QWORD_0_FEAT_GIOSUP_MASK + +/** Mask of all valid DTE bits (including all feature bits). */ +#define IOMMU_DTE_QWORD_0_VALID_MASK UINT64_C(0x7fffffffffffff83) +#define IOMMU_DTE_QWORD_1_VALID_MASK UINT64_C(0xfffffbffffffffff) +#define IOMMU_DTE_QWORD_2_VALID_MASK UINT64_C(0xff0fffffffffffff) +#define IOMMU_DTE_QWORD_3_VALID_MASK UINT64_C(0xffc0000000000000) + +/** Mask of the interrupt table root pointer. */ +#define IOMMU_DTE_IRTE_ROOT_PTR_MASK UINT64_C(0x000fffffffffffc0) +/** Number of bits to shift to get the interrupt root table pointer at + qword 2 (qword 0 being the first one) - 128-byte aligned. */ +#define IOMMU_DTE_IRTE_ROOT_PTR_SHIFT 6 + +/** Maximum encoded IRTE length (exclusive). */ +#define IOMMU_DTE_INTR_TAB_LEN_MAX 12 +/** Gets the interrupt table entries (in bytes) given the DTE pointer. */ +#define IOMMU_DTE_GET_INTR_TAB_ENTRIES(a_pDte) (UINT64_C(1) << (a_pDte)->n.u4IntrTableLength) +/** Gets the interrupt table length (in bytes) given the DTE pointer. */ +#define IOMMU_DTE_GET_INTR_TAB_LEN(a_pDte) (IOMMU_DTE_GET_INTR_TAB_ENTRIES(a_pDte) * sizeof(IRTE_T)) +/** Mask of interrupt control bits. */ +#define IOMMU_DTE_INTR_CTRL_MASK 0x3 +/** Gets the interrupt control bits from the DTE. */ +#define IOMMU_DTE_GET_INTR_CTRL(a_pDte) (((a_pDte)->au64[2] >> 60) & IOMMU_DTE_INTR_CTRL_MASK) +/** Gets the ignore unmapped interrupt bit from DTE. */ +#define IOMMU_DTE_GET_IG(a_pDte) (((a_pDte)->au64[2] >> 5) & 0x1) + +/** + * I/O Page Translation Entry. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u1Present : 1; /**< Bit 0 - PR: Present. */ + RT_GCC_EXTENSION uint64_t u4Ign0 : 4; /**< Bits 4:1 - Ignored. */ + RT_GCC_EXTENSION uint64_t u1Accessed : 1; /**< Bit 5 - A: Accessed. */ + RT_GCC_EXTENSION uint64_t u1Dirty : 1; /**< Bit 6 - D: Dirty. */ + RT_GCC_EXTENSION uint64_t u2Ign0 : 2; /**< Bits 8:7 - Ignored. */ + RT_GCC_EXTENSION uint64_t u3NextLevel : 3; /**< Bits 11:9 - Next Level: Next page translation level. */ + RT_GCC_EXTENSION uint64_t u40PageAddr : 40; /**< Bits 51:12 - Page address. */ + RT_GCC_EXTENSION uint64_t u7Rsvd0 : 7; /**< Bits 58:52 - Reserved. */ + RT_GCC_EXTENSION uint64_t u1UntranslatedAccess : 1; /**< Bit 59 - U: Untranslated Access Only. */ + RT_GCC_EXTENSION uint64_t u1ForceCoherent : 1; /**< Bit 60 - FC: Force Coherent. */ + RT_GCC_EXTENSION uint64_t u1IoRead : 1; /**< Bit 61 - IR: I/O Read permission. */ + RT_GCC_EXTENSION uint64_t u1IoWrite : 1; /**< Bit 62 - IW: I/O Wead permission. */ + RT_GCC_EXTENSION uint64_t u1Ign0 : 1; /**< Bit 63 - Ignored. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOPTE_T; +AssertCompileSize(IOPTE_T, 8); + +/** + * I/O Page Directory Entry. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u1Present : 1; /**< Bit 0 - PR: Present. */ + RT_GCC_EXTENSION uint64_t u4Ign0 : 4; /**< Bits 4:1 - Ignored. */ + RT_GCC_EXTENSION uint64_t u1Accessed : 1; /**< Bit 5 - A: Accessed. */ + RT_GCC_EXTENSION uint64_t u3Ign0 : 3; /**< Bits 8:6 - Ignored. */ + RT_GCC_EXTENSION uint64_t u3NextLevel : 3; /**< Bits 11:9 - Next Level: Next page translation level. */ + RT_GCC_EXTENSION uint64_t u40PageAddr : 40; /**< Bits 51:12 - Page address (Next Table Address). */ + RT_GCC_EXTENSION uint64_t u9Rsvd0 : 9; /**< Bits 60:52 - Reserved. */ + RT_GCC_EXTENSION uint64_t u1IoRead : 1; /**< Bit 61 - IR: I/O Read permission. */ + RT_GCC_EXTENSION uint64_t u1IoWrite : 1; /**< Bit 62 - IW: I/O Wead permission. */ + RT_GCC_EXTENSION uint64_t u1Ign0 : 1; /**< Bit 63 - Ignored. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOPDE_T; +AssertCompileSize(IOPDE_T, 8); + +/** + * I/O Page Table Entity. + * In accordance with the AMD spec. + * + * This a common subset of an DTE.au64[0], PTE and PDE. + * Named as an "entity" to avoid confusing it with PTE. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u1Present : 1; /**< Bit 0 - PR: Present. */ + RT_GCC_EXTENSION uint64_t u8Ign0 : 8; /**< Bits 8:1 - Ignored. */ + RT_GCC_EXTENSION uint64_t u3NextLevel : 3; /**< Bits 11:9 - Mode / Next Level: Next page translation level. */ + RT_GCC_EXTENSION uint64_t u40Addr : 40; /**< Bits 51:12 - Page address. */ + RT_GCC_EXTENSION uint64_t u9Ign0 : 9; /**< Bits 60:52 - Ignored. */ + RT_GCC_EXTENSION uint64_t u1IoRead : 1; /**< Bit 61 - IR: I/O Read permission. */ + RT_GCC_EXTENSION uint64_t u1IoWrite : 1; /**< Bit 62 - IW: I/O Wead permission. */ + RT_GCC_EXTENSION uint64_t u1Ign0 : 1; /**< Bit 63 - Ignored. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOPTENTITY_T; +AssertCompileSize(IOPTENTITY_T, 8); +AssertCompile(sizeof(IOPTENTITY_T) == sizeof(IOPTE_T)); +AssertCompile(sizeof(IOPTENTITY_T) == sizeof(IOPDE_T)); +/** Pointer to an IOPT_ENTITY_T struct. */ +typedef IOPTENTITY_T *PIOPTENTITY_T; +/** Pointer to a const IOPT_ENTITY_T struct. */ +typedef IOPTENTITY_T const *PCIOPTENTITY_T; +/** Mask of the address field. */ +#define IOMMU_PTENTITY_ADDR_MASK UINT64_C(0x000ffffffffff000) +/** Reserved bits in the PDE (bits 60:52). */ +#define IOMMU_PDE_RSVD_MASK UINT64_C(0x1ff0000000000000) +/** Reserved bits in the PTE (bits 58:52 - U, FC bits not reserved). */ +#define IOMMU_PTE_RSVD_MASK UINT64_C(0x07f0000000000000) + +/** + * Interrupt Remapping Table Entry (IRTE) - Basic Format. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u1RemapEnable : 1; /**< Bit 0 - RemapEn: Remap Enable. */ + uint32_t u1SuppressIoPf : 1; /**< Bit 1 - SupIOPF: Suppress I/O Page Fault. */ + uint32_t u3IntrType : 3; /**< Bits 4:2 - IntType: Interrupt Type. */ + uint32_t u1ReqEoi : 1; /**< Bit 5 - RqEoi: Request EOI. */ + uint32_t u1DestMode : 1; /**< Bit 6 - DM: Destination Mode. */ + uint32_t u1GuestMode : 1; /**< Bit 7 - GuestMode. */ + uint32_t u8Dest : 8; /**< Bits 15:8 - Destination. */ + uint32_t u8Vector : 8; /**< Bits 23:16 - Vector. */ + uint32_t u8Rsvd0 : 8; /**< Bits 31:24 - Reserved. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t u32; +} IRTE_T; +AssertCompileSize(IRTE_T, 4); +/** Pointer to an IRTE_T struct. */ +typedef IRTE_T *PIRTE_T; +/** Pointer to a const IRTE_T struct. */ +typedef IRTE_T const *PCIRTE_T; + +/** The IRTE offset corresponds directly to bits 10:0 of the originating MSI + * interrupt message. See AMD IOMMU spec. 2.2.5 "Interrupt Remapping Tables". */ +#define IOMMU_MSI_DATA_IRTE_OFFSET_MASK UINT32_C(0x000007ff) +/** Gets the IRTE offset from the originating MSI interrupt message. */ +#define IOMMU_GET_IRTE_OFF(a_u32MsiData) (((a_u32MsiData) & IOMMU_MSI_DATA_IRTE_OFFSET_MASK) * sizeof(IRTE_T)) + +/** + * Interrupt Remapping Table Entry (IRTE) - Guest Virtual APIC Enabled. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u1RemapEnable : 1; /**< Bit 0 - RemapEn: Remap Enable. */ + uint32_t u1SuppressIoPf : 1; /**< Bit 1 - SupIOPF: Suppress I/O Page Fault. */ + uint32_t u1GALogIntr : 1; /**< Bit 2 - GALogIntr: Guest APIC Log Interrupt. */ + uint32_t u3Rsvd : 3; /**< Bits 5:3 - Reserved. */ + uint32_t u1IsRunning : 1; /**< Bit 6 - IsRun: Hint whether the guest is running. */ + uint32_t u1GuestMode : 1; /**< Bit 7 - GuestMode. */ + uint32_t u8Dest : 8; /**< Bits 15:8 - Destination. */ + uint32_t u8Rsvd0 : 8; /**< Bits 31:16 - Reserved. */ + uint32_t u32GATag : 32; /**< Bits 63:31 - GATag: Tag used when writing to GA log. */ + uint32_t u8Vector : 8; /**< Bits 71:64 - Vector: Interrupt vector. */ + uint32_t u4Reserved : 4; /**< Bits 75:72 - Reserved or ignored depending on RemapEn. */ + uint32_t u20GATableRootPtrLo : 20; /**< Bits 95:76 - Bits [31:12] of Guest vAPIC Table Root Pointer. */ + uint32_t u20GATableRootPtrHi : 20; /**< Bits 115:76 - Bits [51:32] of Guest vAPIC Table Root Pointer. */ + uint32_t u12Rsvd : 12; /**< Bits 127:116 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64[2]; +} IRTE_GVA_T; +AssertCompileSize(IRTE_GVA_T, 16); +/** Pointer to an IRTE_GVA_T struct. */ +typedef IRTE_GVA_T *PIRTE_GVA_T; +/** Pointer to a const IRTE_GVA_T struct. */ +typedef IRTE_GVA_T const *PCIRTE_GVA_T; + +/** + * Command: Generic Command Buffer Entry. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u32Operand1Lo; /**< Bits 31:0 - Operand 1 (Lo). */ + uint32_t u28Operand1Hi : 28; /**< Bits 59:32 - Operand 1 (Hi). */ + uint32_t u4Opcode : 4; /**< Bits 63:60 - Op Code. */ + uint64_t u64Operand2; /**< Bits 127:64 - Operand 2. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_GENERIC_T; +AssertCompileSize(CMD_GENERIC_T, 16); +/** Pointer to a generic command buffer entry. */ +typedef CMD_GENERIC_T *PCMD_GENERIC_T; +/** Pointer to a const generic command buffer entry. */ +typedef CMD_GENERIC_T const *PCCMD_GENERIC_T; + +/** Number of bits to shift the byte offset of a command in the command buffer to + * get its index. */ +#define IOMMU_CMD_GENERIC_SHIFT 4 + +/** + * Command: COMPLETION_WAIT. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u1Store : 1; /**< Bit 0 - S: Completion Store. */ + uint32_t u1Interrupt : 1; /**< Bit 1 - I: Completion Interrupt. */ + uint32_t u1Flush : 1; /**< Bit 2 - F: Flush Queue. */ + uint32_t u29StoreAddrLo : 29; /**< Bits 31:3 - Store Address (Lo). */ + uint32_t u20StoreAddrHi : 20; /**< Bits 51:32 - Store Address (Hi). */ + uint32_t u8Rsvd0 : 8; /**< Bits 59:52 - Reserved. */ + uint32_t u4OpCode : 4; /**< Bits 63:60 - OpCode (Command). */ + uint64_t u64StoreData; /**< Bits 127:64 - Store Data. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_COMWAIT_T; +AssertCompileSize(CMD_COMWAIT_T, 16); +/** Pointer to a completion wait command. */ +typedef CMD_COMWAIT_T *PCMD_COMWAIT_T; +/** Pointer to a const completion wait command. */ +typedef CMD_COMWAIT_T const *PCCMD_COMWAIT_T; +#define IOMMU_CMD_COM_WAIT_QWORD_0_VALID_MASK UINT64_C(0xf00fffffffffffff) + +/** + * Command: INVALIDATE_DEVTAB_ENTRY. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + uint16_t u16Rsvd0; /**< Bits 31:16 - Reserved. */ + uint32_t u28Rsvd0 : 28; /**< Bits 59:32 - Reserved. */ + uint32_t u4OpCode : 4; /**< Bits 63:60 - Op Code (Command). */ + uint64_t u64Rsvd0; /**< Bits 127:64 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_INV_DTE_T; +AssertCompileSize(CMD_INV_DTE_T, 16); +/** Pointer to a invalidate DTE command. */ +typedef CMD_INV_DTE_T *PCMD_INV_DTE_T; +/** Pointer to a const invalidate DTE command. */ +typedef CMD_INV_DTE_T const *PCCMD_INV_DTE_T; +#define IOMMU_CMD_INV_DTE_QWORD_0_VALID_MASK UINT64_C(0xf00000000000ffff) +#define IOMMU_CMD_INV_DTE_QWORD_1_VALID_MASK UINT64_C(0x0000000000000000) + +/** + * Command: INVALIDATE_IOMMU_PAGES. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u20Pasid : 20; /**< Bits 19:0 - PASID: Process Address-Space ID. */ + uint32_t u12Rsvd0 : 12; /**< Bits 31:20 - Reserved. */ + uint32_t u16DomainId : 16; /**< Bits 47:32 - Domain ID. */ + uint32_t u12Rsvd1 : 12; /**< Bits 59:48 - Reserved. */ + uint32_t u4OpCode : 4; /**< Bits 63:60 - Op Code (Command). */ + uint32_t u1Size : 1; /**< Bit 64 - S: Size. */ + uint32_t u1PageDirEntries : 1; /**< Bit 65 - PDE: Page Directory Entries. */ + uint32_t u1GuestOrNested : 1; /**< Bit 66 - GN: Guest (GPA) or Nested (GVA). */ + uint32_t u9Rsvd0 : 9; /**< Bits 75:67 - Reserved. */ + uint32_t u20AddrLo : 20; /**< Bits 95:76 - Address (Lo). */ + uint32_t u32AddrHi; /**< Bits 127:96 - Address (Hi). */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_INV_IOMMU_PAGES_T; +AssertCompileSize(CMD_INV_IOMMU_PAGES_T, 16); +/** Pointer to a invalidate iommu pages command. */ +typedef CMD_INV_IOMMU_PAGES_T *PCMD_INV_IOMMU_PAGES_T; +/** Pointer to a const invalidate iommu pages command. */ +typedef CMD_INV_IOMMU_PAGES_T const *PCCMD_INV_IOMMU_PAGES_T; +#define IOMMU_CMD_INV_IOMMU_PAGES_QWORD_0_VALID_MASK UINT64_C(0xf000ffff000fffff) +#define IOMMU_CMD_INV_IOMMU_PAGES_QWORD_1_VALID_MASK UINT64_C(0xfffffffffffff007) + +/** + * Command: INVALIDATE_IOTLB_PAGES. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + uint8_t u8PasidLo; /**< Bits 23:16 - PASID: Process Address-Space ID (Lo). */ + uint8_t u8MaxPend; /**< Bits 31:24 - Maxpend: Maximum simultaneous in-flight transactions. */ + uint32_t u16QueueId : 16; /**< Bits 47:32 - Queue ID. */ + uint32_t u12PasidHi : 12; /**< Bits 59:48 - PASID: Process Address-Space ID (Hi). */ + uint32_t u4OpCode : 4; /**< Bits 63:60 - Op Code (Command). */ + uint32_t u1Size : 1; /**< Bit 64 - S: Size. */ + uint32_t u1Rsvd0: 1; /**< Bit 65 - Reserved. */ + uint32_t u1GuestOrNested : 1; /**< Bit 66 - GN: Guest (GPA) or Nested (GVA). */ + uint32_t u1Rsvd1 : 1; /**< Bit 67 - Reserved. */ + uint32_t u2Type : 2; /**< Bit 69:68 - Type. */ + uint32_t u6Rsvd0 : 6; /**< Bits 75:70 - Reserved. */ + uint32_t u20AddrLo : 20; /**< Bits 95:76 - Address (Lo). */ + uint32_t u32AddrHi; /**< Bits 127:96 - Address (Hi). */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_INV_IOTLB_PAGES_T; +AssertCompileSize(CMD_INV_IOTLB_PAGES_T, 16); + +/** + * Command: INVALIDATE_INTR_TABLE. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + uint16_t u16Rsvd0; /**< Bits 31:16 - Reserved. */ + uint32_t u32Rsvd0 : 28; /**< Bits 59:32 - Reserved. */ + uint32_t u4OpCode : 4; /**< Bits 63:60 - Op Code (Command). */ + uint64_t u64Rsvd0; /**< Bits 127:64 - Reserved. */ + } u; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_INV_INTR_TABLE_T; +AssertCompileSize(CMD_INV_INTR_TABLE_T, 16); +/** Pointer to a invalidate interrupt table command. */ +typedef CMD_INV_INTR_TABLE_T *PCMD_INV_INTR_TABLE_T; +/** Pointer to a const invalidate interrupt table command. */ +typedef CMD_INV_INTR_TABLE_T const *PCCMD_INV_INTR_TABLE_T; +#define IOMMU_CMD_INV_INTR_TABLE_QWORD_0_VALID_MASK UINT64_C(0xf00000000000ffff) +#define IOMMU_CMD_INV_INTR_TABLE_QWORD_1_VALID_MASK UINT64_C(0x0000000000000000) + +/** + * Command: PREFETCH_IOMMU_PAGES. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + uint8_t u8Rsvd0; /**< Bits 23:16 - Reserved. */ + uint8_t u8PrefCount; /**< Bits 31:24 - PFCount: Number of translations to prefetch. */ + uint32_t u20Pasid : 20; /**< Bits 51:32 - PASID: Process Address-Space ID. */ + uint32_t u8Rsvd1 : 8; /**< Bits 59:52 - Reserved. */ + uint32_t u4OpCode : 4; /**< Bits 63:60 - Op Code (Command). */ + uint32_t u1Size : 1; /**< Bit 64 - S: Size of the prefetched pages. */ + uint32_t u1Rsvd0 : 1; /**< Bit 65 - Reserved. */ + uint32_t u1GuestOrNested : 1; /**< Bit 66 - GN: Guest (GPA) or Nested (GVA). */ + uint32_t u1Rsvd1 : 1; /**< Bit 67 - Reserved. */ + uint32_t u1Invalidate : 1; /**< Bit 68 - Inval: Invalidate prior to prefetch. */ + uint32_t u7Rsvd0 : 7; /**< Bits 75:69 - Reserved */ + uint32_t u20AddrLo : 7; /**< Bits 95:76 - Address (Lo). */ + uint32_t u32AddrHi; /**< Bits 127:96 - Address (Hi). */ + } u; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_PREF_IOMMU_PAGES_T; +AssertCompileSize(CMD_PREF_IOMMU_PAGES_T, 16); +/** Pointer to a invalidate iommu pages command. */ +typedef CMD_PREF_IOMMU_PAGES_T *PCMD_PREF_IOMMU_PAGES_T; +/** Pointer to a const invalidate iommu pages command. */ +typedef CMD_PREF_IOMMU_PAGES_T const *PCCMD_PREF_IOMMU_PAGES_T; +#define IOMMU_CMD_PREF_IOMMU_PAGES_QWORD_0_VALID_MASK UINT64_C(0x780fffffff00ffff) +#define IOMMU_CMD_PREF_IOMMU_PAGES_QWORD_1_VALID_MASK UINT64_C(0xfffffffffffff015) + + +/** + * Command: COMPLETE_PPR_REQ. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + uint16_t u16Rsvd0; /**< Bits 31:16 - Reserved. */ + uint32_t u20Pasid : 20; /**< Bits 51:32 - PASID: Process Address-Space ID. */ + uint32_t u8Rsvd0 : 8; /**< Bits 59:52 - Reserved. */ + uint32_t u4OpCode : 4; /**< Bits 63:60 - Op Code (Command). */ + uint32_t u2Rsvd0 : 2; /**< Bits 65:64 - Reserved. */ + uint32_t u1GuestOrNested : 1; /**< Bit 66 - GN: Guest (GPA) or Nested (GVA). */ + uint32_t u29Rsvd0 : 29; /**< Bits 95:67 - Reserved. */ + uint32_t u16CompletionTag : 16; /**< Bits 111:96 - Completion Tag. */ + uint32_t u16Rsvd1 : 16; /**< Bits 127:112 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_COMPLETE_PPR_REQ_T; +AssertCompileSize(CMD_COMPLETE_PPR_REQ_T, 16); + +/** + * Command: INV_IOMMU_ALL. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u32Rsvd0; /**< Bits 31:0 - Reserved. */ + uint32_t u28Rsvd0 : 28; /**< Bits 59:32 - Reserved. */ + uint32_t u4OpCode : 4; /**< Bits 63:60 - Op Code (Command). */ + uint64_t u64Rsvd0; /**< Bits 127:64 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_INV_IOMMU_ALL_T; +AssertCompileSize(CMD_INV_IOMMU_ALL_T, 16); +/** Pointer to a invalidate IOMMU all command. */ +typedef CMD_INV_IOMMU_ALL_T *PCMD_INV_IOMMU_ALL_T; +/** Pointer to a const invalidate IOMMU all command. */ +typedef CMD_INV_IOMMU_ALL_T const *PCCMD_INV_IOMMU_ALL_T; +#define IOMMU_CMD_INV_IOMMU_ALL_QWORD_0_VALID_MASK UINT64_C(0xf000000000000000) +#define IOMMU_CMD_INV_IOMMU_ALL_QWORD_1_VALID_MASK UINT64_C(0x0000000000000000) + +/** + * Event Log Entry: Generic. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u32Operand1Lo; /**< Bits 31:0 - Operand 1 (Lo). */ + uint32_t u28Operand1Hi : 28; /**< Bits 59:32 - Operand 1 (Hi). */ + uint32_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ + uint32_t u32Operand2Lo; /**< Bits 95:64 - Operand 2 (Lo). */ + uint32_t u32Operand2Hi; /**< Bits 127:96 - Operand 2 (Hi). */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; +} EVT_GENERIC_T; +AssertCompileSize(EVT_GENERIC_T, 16); +/** Number of bits to shift the byte offset of an event entry in the event log + * buffer to get its index. */ +#define IOMMU_EVT_GENERIC_SHIFT 4 +/** Pointer to a generic event log entry. */ +typedef EVT_GENERIC_T *PEVT_GENERIC_T; +/** Pointer to a const generic event log entry. */ +typedef const EVT_GENERIC_T *PCEVT_GENERIC_T; + +/** + * Hardware event types. + * In accordance with the AMD spec. + */ +typedef enum HWEVTTYPE +{ + HWEVTTYPE_RSVD = 0, + HWEVTTYPE_MASTER_ABORT, + HWEVTTYPE_TARGET_ABORT, + HWEVTTYPE_DATA_ERROR +} HWEVTTYPE; +AssertCompileSize(HWEVTTYPE, 4); + +/** + * Event Log Entry: ILLEGAL_DEV_TABLE_ENTRY. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + RT_GCC_EXTENSION uint16_t u4PasidHi : 4; /**< Bits 19:16 - PASID: Process Address-Space ID (Hi). */ + RT_GCC_EXTENSION uint16_t u12Rsvd0 : 12; /**< Bits 31:20 - Reserved. */ + uint16_t u16PasidLo; /**< Bits 47:32 - PASID: Process Address-Space ID (Lo). */ + RT_GCC_EXTENSION uint16_t u1GuestOrNested : 1; /**< Bit 48 - GN: Guest (GPA) or Nested (GVA). */ + RT_GCC_EXTENSION uint16_t u2Rsvd0 : 2; /**< Bits 50:49 - Reserved. */ + RT_GCC_EXTENSION uint16_t u1Interrupt : 1; /**< Bit 51 - I: Interrupt. */ + RT_GCC_EXTENSION uint16_t u1Rsvd0 : 1; /**< Bit 52 - Reserved. */ + RT_GCC_EXTENSION uint16_t u1ReadWrite : 1; /**< Bit 53 - RW: Read/Write. */ + RT_GCC_EXTENSION uint16_t u1Rsvd1 : 1; /**< Bit 54 - Reserved. */ + RT_GCC_EXTENSION uint16_t u1RsvdNotZero : 1; /**< Bit 55 - RZ: Reserved bit not Zero (0=invalid level encoding). */ + RT_GCC_EXTENSION uint16_t u1Translation : 1; /**< Bit 56 - TN: Translation. */ + RT_GCC_EXTENSION uint16_t u3Rsvd0 : 3; /**< Bits 59:57 - Reserved. */ + RT_GCC_EXTENSION uint16_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ + uint64_t u64Addr; /**< Bits 127:64 - Address: I/O Virtual Address (IOVA). */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} EVT_ILLEGAL_DTE_T; +AssertCompileSize(EVT_ILLEGAL_DTE_T, 16); +/** Pointer to an illegal device table entry event. */ +typedef EVT_ILLEGAL_DTE_T *PEVT_ILLEGAL_DTE_T; +/** Pointer to a const illegal device table entry event. */ +typedef EVT_ILLEGAL_DTE_T const *PCEVT_ILLEGAL_DTE_T; + +/** + * Event Log Entry: IO_PAGE_FAULT_EVENT. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + RT_GCC_EXTENSION uint16_t u4PasidHi : 4; /**< Bits 19:16 - PASID: Process Address-Space ID (Hi). */ + RT_GCC_EXTENSION uint16_t u16DomainOrPasidLo; /**< Bits 47:32 - D/P: Domain ID or Process Address-Space ID (Lo). */ + RT_GCC_EXTENSION uint16_t u1GuestOrNested : 1; /**< Bit 48 - GN: Guest (GPA) or Nested (GVA). */ + RT_GCC_EXTENSION uint16_t u1NoExecute : 1; /**< Bit 49 - NX: No Execute. */ + RT_GCC_EXTENSION uint16_t u1User : 1; /**< Bit 50 - US: User/Supervisor. */ + RT_GCC_EXTENSION uint16_t u1Interrupt : 1; /**< Bit 51 - I: Interrupt. */ + RT_GCC_EXTENSION uint16_t u1Present : 1; /**< Bit 52 - PR: Present. */ + RT_GCC_EXTENSION uint16_t u1ReadWrite : 1; /**< Bit 53 - RW: Read/Write. */ + RT_GCC_EXTENSION uint16_t u1PermDenied : 1; /**< Bit 54 - PE: Permission Indicator. */ + RT_GCC_EXTENSION uint16_t u1RsvdNotZero : 1; /**< Bit 55 - RZ: Reserved bit not Zero (0=invalid level encoding). */ + RT_GCC_EXTENSION uint16_t u1Translation : 1; /**< Bit 56 - TN: Translation. */ + RT_GCC_EXTENSION uint16_t u3Rsvd0 : 3; /**< Bit 59:57 - Reserved. */ + RT_GCC_EXTENSION uint16_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ + uint64_t u64Addr; /**< Bits 127:64 - Address: I/O Virtual Address (IOVA). */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} EVT_IO_PAGE_FAULT_T; +AssertCompileSize(EVT_IO_PAGE_FAULT_T, 16); +/** Pointer to an I/O page fault event. */ +typedef EVT_IO_PAGE_FAULT_T *PEVT_IO_PAGE_FAULT_T; +/** Pointer to a const I/O page fault event. */ +typedef EVT_IO_PAGE_FAULT_T const *PCEVT_IO_PAGE_FAULT_T; + + +/** + * Event Log Entry: DEV_TAB_HARDWARE_ERROR. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + uint16_t u16Rsvd0; /**< Bits 31:16 - Reserved. */ + uint32_t u19Rsvd0 : 19; /**< Bits 50:32 - Reserved. */ + uint32_t u1Intr : 1; /**< Bit 51 - I: Interrupt (1=interrupt request, 0=memory request). */ + uint32_t u1Rsvd0 : 1; /**< Bit 52 - Reserved. */ + uint32_t u1ReadWrite : 1; /**< Bit 53 - RW: Read/Write transaction (only meaninful when I=0 and TR=0). */ + uint32_t u2Rsvd0 : 2; /**< Bits 55:54 - Reserved. */ + uint32_t u1Translation : 1; /**< Bit 56 - TR: Translation (1=translation, 0=transaction). */ + uint32_t u2Type : 2; /**< Bits 58:57 - Type: The type of hardware error. */ + uint32_t u1Rsvd1 : 1; /**< Bit 59 - Reserved. */ + uint32_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ + uint64_t u64Addr; /**< Bits 127:64 - Address. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} EVT_DEV_TAB_HW_ERROR_T; +AssertCompileSize(EVT_DEV_TAB_HW_ERROR_T, 16); +/** Pointer to a device table hardware error event. */ +typedef EVT_DEV_TAB_HW_ERROR_T *PEVT_DEV_TAB_HW_ERROR_T; +/** Pointer to a const device table hardware error event. */ +typedef EVT_DEV_TAB_HW_ERROR_T const *PCEVT_DEV_TAB_HW_ERROR_T; + +/** + * Event Log Entry: EVT_PAGE_TAB_HARDWARE_ERROR. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + uint16_t u16Rsvd0; /**< Bits 31:16 - Reserved. */ + uint32_t u16DomainOrPasidLo : 16; /**< Bits 47:32 - D/P: Domain ID or Process Address-Space ID (Lo). */ + uint32_t u1GuestOrNested : 1; /**< Bit 48 - GN: Guest (GPA) or Nested (GVA). */ + uint32_t u2Rsvd0 : 2; /**< Bits 50:49 - Reserved. */ + uint32_t u1Interrupt : 1; /**< Bit 51 - I: Interrupt. */ + uint32_t u1Rsvd0 : 1; /**< Bit 52 - Reserved. */ + uint32_t u1ReadWrite : 1; /**< Bit 53 - RW: Read/Write. */ + uint32_t u2Rsvd1 : 2; /**< Bit 55:54 - Reserved. */ + uint32_t u1Translation : 1; /**< Bit 56 - TR: Translation. */ + uint32_t u2Type : 2; /**< Bits 58:57 - Type: The type of hardware error. */ + uint32_t u1Rsvd1 : 1; /**< Bit 59 - Reserved. */ + uint32_t u4EvtCode : 4; /**< Bit 63:60 - Event code. */ + /** @todo r=ramshankar: Figure 55: PAGE_TAB_HARDWARE_ERROR says Addr[31:3] but + * table 58 mentions Addr[31:4], we just use the full 64-bits. Looks like a + * typo in the figure.See AMD AMD IOMMU spec (3.05-PUB, Jan 2020). */ + uint64_t u64Addr; /** Bits 127:64 - Address: SPA of the page table entry. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} EVT_PAGE_TAB_HW_ERR_T; +AssertCompileSize(EVT_PAGE_TAB_HW_ERR_T, 16); +/** Pointer to a page table hardware error event. */ +typedef EVT_PAGE_TAB_HW_ERR_T *PEVT_PAGE_TAB_HW_ERR_T; +/** Pointer to a const page table hardware error event. */ +typedef EVT_PAGE_TAB_HW_ERR_T const *PCEVT_PAGE_TAB_HW_ERR_T; + +/** + * Event Log Entry: ILLEGAL_COMMAND_ERROR. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u32Rsvd0; /**< Bits 31:0 - Reserved. */ + uint32_t u28Rsvd0 : 28; /**< Bits 47:32 - Reserved. */ + uint32_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ + uint64_t u64Addr; /**< Bits 127:64 - Address: SPA of the invalid command. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} EVT_ILLEGAL_CMD_ERR_T; +AssertCompileSize(EVT_ILLEGAL_CMD_ERR_T, 16); +/** Pointer to an illegal command error event. */ +typedef EVT_ILLEGAL_CMD_ERR_T *PEVT_ILLEGAL_CMD_ERR_T; +/** Pointer to a const illegal command error event. */ +typedef EVT_ILLEGAL_CMD_ERR_T const *PCEVT_ILLEGAL_CMD_ERR_T; + +/** + * Event Log Entry: COMMAND_HARDWARE_ERROR. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u32Rsvd0; /**< Bits 31:0 - Reserved. */ + uint32_t u25Rsvd1 : 25; /**< Bits 56:32 - Reserved. */ + uint32_t u2Type : 2; /**< Bits 58:57 - Type: The type of hardware error. */ + uint32_t u1Rsvd1 : 1; /**< Bit 59 - Reserved. */ + uint32_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ + uint64_t u64Addr; /**< Bits 128:64 - Address: SPA of the attempted access. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} EVT_CMD_HW_ERR_T; +AssertCompileSize(EVT_CMD_HW_ERR_T, 16); +/** Pointer to a command hardware error event. */ +typedef EVT_CMD_HW_ERR_T *PEVT_CMD_HW_ERR_T; +/** Pointer to a const command hardware error event. */ +typedef EVT_CMD_HW_ERR_T const *PCEVT_CMD_HW_ERR_T; + +/** + * Event Log Entry: IOTLB_INV_TIMEOUT. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + uint16_t u16Rsvd0; /**< Bits 31:16 - Reserved.*/ + uint32_t u28Rsvd0 : 28; /**< Bits 59:32 - Reserved. */ + uint32_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ + uint32_t u4Rsvd0 : 4; /**< Bits 67:64 - Reserved. */ + uint32_t u28AddrLo : 28; /**< Bits 95:68 - Address: SPA of the invalidation command that timedout (Lo). */ + uint32_t u32AddrHi; /**< Bits 127:96 - Address: SPA of the invalidation command that timedout (Hi). */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; +} EVT_IOTLB_INV_TIMEOUT_T; +AssertCompileSize(EVT_IOTLB_INV_TIMEOUT_T, 16); + +/** + * Event Log Entry: INVALID_DEVICE_REQUEST. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u16DevId : 16; /***< Bits 15:0 - Device ID. */ + uint32_t u4PasidHi : 4; /***< Bits 19:16 - PASID: Process Address-Space ID (Hi). */ + uint32_t u12Rsvd0 : 12; /***< Bits 31:20 - Reserved. */ + uint32_t u16PasidLo : 16; /***< Bits 47:32 - PASID: Process Address-Space ID (Lo). */ + uint32_t u1GuestOrNested : 1; /***< Bit 48 - GN: Guest (GPA) or Nested (GVA). */ + uint32_t u1User : 1; /***< Bit 49 - US: User/Supervisor. */ + uint32_t u6Rsvd0 : 6; /***< Bits 55:50 - Reserved. */ + uint32_t u1Translation: 1; /***< Bit 56 - TR: Translation. */ + uint32_t u3Type: 3; /***< Bits 59:57 - Type: The type of hardware error. */ + uint32_t u4EvtCode : 4; /***< Bits 63:60 - Event code. */ + uint64_t u64Addr; /***< Bits 127:64 - Address: Translation or access address. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; +} EVT_INVALID_DEV_REQ_T; +AssertCompileSize(EVT_INVALID_DEV_REQ_T, 16); + +/** + * Event Log Entry: EVENT_COUNTER_ZERO. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u32Rsvd0; /**< Bits 31:0 - Reserved. */ + uint32_t u28Rsvd0 : 28; /**< Bits 59:32 - Reserved. */ + uint32_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ + uint32_t u20CounterNoteHi : 20; /**< Bits 83:64 - CounterNote: Counter value for the event counter register (Hi). */ + uint32_t u12Rsvd0 : 12; /**< Bits 95:84 - Reserved. */ + uint32_t u32CounterNoteLo; /**< Bits 127:96 - CounterNote: Counter value for the event cuonter register (Lo). */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; +} EVT_EVENT_COUNTER_ZERO_T; +AssertCompileSize(EVT_EVENT_COUNTER_ZERO_T, 16); + +/** + * IOMMU Capability Header (PCI). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u8CapId : 8; /**< Bits 7:0 - CapId: Capability ID. */ + uint32_t u8CapPtr : 8; /**< Bits 15:8 - CapPtr: Pointer (PCI config offset) to the next capability. */ + uint32_t u3CapType : 3; /**< Bits 18:16 - CapType: Capability Type. */ + uint32_t u5CapRev : 5; /**< Bits 23:19 - CapRev: Capability revision. */ + uint32_t u1IoTlbSup : 1; /**< Bit 24 - IotlbSup: IOTLB Support. */ + uint32_t u1HtTunnel : 1; /**< Bit 25 - HtTunnel: HyperTransport Tunnel translation support. */ + uint32_t u1NpCache : 1; /**< Bit 26 - NpCache: Not Present table entries are cached. */ + uint32_t u1EfrSup : 1; /**< Bit 27 - EFRSup: Extended Feature Register Support. */ + uint32_t u1CapExt : 1; /**< Bit 28 - CapExt: Misc. Information Register 1 Support. */ + uint32_t u3Rsvd0 : 3; /**< Bits 31:29 - Reserved. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t u32; +} IOMMU_CAP_HDR_T; +AssertCompileSize(IOMMU_CAP_HDR_T, 4); + +/** + * IOMMU Base Address (Lo and Hi) Register (PCI). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u1Enable : 1; /**< Bit 1 - Enable: RW1S - Enable IOMMU MMIO region. */ + uint32_t u12Rsvd0 : 12; /**< Bits 13:1 - Reserved. */ + uint32_t u18BaseAddrLo : 18; /**< Bits 31:14 - Base address (Lo) of the MMIO region. */ + uint32_t u32BaseAddrHi; /**< Bits 63:32 - Base address (Hi) of the MMIO region. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[2]; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_BAR_T; +AssertCompileSize(IOMMU_BAR_T, 8); +#define IOMMU_BAR_VALID_MASK UINT64_C(0xffffffffffffc001) + +/** + * IOMMU Range Register (PCI). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u5HtUnitId : 5; /**< Bits 4:0 - UnitID: IOMMU HyperTransport Unit ID (not used). */ + uint32_t u2Rsvd0 : 2; /**< Bits 6:5 - Reserved. */ + uint32_t u1RangeValid : 1; /**< Bit 7 - RngValid: Range Valid. */ + uint32_t u8Bus : 8; /**< Bits 15:8 - BusNumber: Bus number of the first and last device. */ + uint32_t u8FirstDevice : 8; /**< Bits 23:16 - FirstDevice: Device and function number of the first device. */ + uint32_t u8LastDevice: 8; /**< Bits 31:24 - LastDevice: Device and function number of the last device. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t u32; +} IOMMU_RANGE_T; +AssertCompileSize(IOMMU_RANGE_T, 4); + +/** + * Device Table Base Address Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u9Size : 9; /**< Bits 8:0 - Size: Size of the device table. */ + RT_GCC_EXTENSION uint64_t u3Rsvd0 : 3; /**< Bits 11:9 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40Base : 40; /**< Bits 51:12 - DevTabBase: Device table base address. */ + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bits 63:52 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} DEV_TAB_BAR_T; +AssertCompileSize(DEV_TAB_BAR_T, 8); +#define IOMMU_DEV_TAB_BAR_VALID_MASK UINT64_C(0x000ffffffffff1ff) +#define IOMMU_DEV_TAB_SEG_BAR_VALID_MASK UINT64_C(0x000ffffffffff0ff) + +/** + * Command Buffer Base Address Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bits 11:0 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40Base : 40; /**< Bits 51:12 - ComBase: Command buffer base address. */ + RT_GCC_EXTENSION uint64_t u4Rsvd0 : 4; /**< Bits 55:52 - Reserved. */ + RT_GCC_EXTENSION uint64_t u4Len : 4; /**< Bits 59:56 - ComLen: Command buffer length. */ + RT_GCC_EXTENSION uint64_t u4Rsvd1 : 4; /**< Bits 63:60 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} CMD_BUF_BAR_T; +AssertCompileSize(CMD_BUF_BAR_T, 8); +#define IOMMU_CMD_BUF_BAR_VALID_MASK UINT64_C(0x0f0ffffffffff000) + +/** + * Event Log Base Address Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bits 11:0 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40Base : 40; /**< Bits 51:12 - EventBase: Event log base address. */ + RT_GCC_EXTENSION uint64_t u4Rsvd0 : 4; /**< Bits 55:52 - Reserved. */ + RT_GCC_EXTENSION uint64_t u4Len : 4; /**< Bits 59:56 - EventLen: Event log length. */ + RT_GCC_EXTENSION uint64_t u4Rsvd1 : 4; /**< Bits 63:60 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} EVT_LOG_BAR_T; +AssertCompileSize(EVT_LOG_BAR_T, 8); +#define IOMMU_EVT_LOG_BAR_VALID_MASK UINT64_C(0x0f0ffffffffff000) + +/** + * IOMMU Control Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u1IommuEn : 1; /**< Bit 0 - IommuEn: IOMMU Enable. */ + uint32_t u1HtTunEn : 1; /**< Bit 1 - HtTunEn: HyperTransport Tunnel Enable. */ + uint32_t u1EvtLogEn : 1; /**< Bit 2 - EventLogEn: Event Log Enable. */ + uint32_t u1EvtIntrEn : 1; /**< Bit 3 - EventIntEn: Event Log Interrupt Enable. */ + uint32_t u1CompWaitIntrEn : 1; /**< Bit 4 - ComWaitIntEn: Completion Wait Interrupt Enable. */ + uint32_t u3InvTimeOut : 3; /**< Bits 7:5 - InvTimeOut: Invalidation Timeout. */ + uint32_t u1PassPW : 1; /**< Bit 8 - PassPW: Pass Posted Write. */ + uint32_t u1ResPassPW : 1; /**< Bit 9 - ResPassPW: Response Pass Posted Write. */ + uint32_t u1Coherent : 1; /**< Bit 10 - Coherent: HT read request packet Coherent bit. */ + uint32_t u1Isoc : 1; /**< Bit 11 - Isoc: HT read request packet Isochronous bit. */ + uint32_t u1CmdBufEn : 1; /**< Bit 12 - CmdBufEn: Command Buffer Enable. */ + uint32_t u1PprLogEn : 1; /**< Bit 13 - PprLogEn: Peripheral Page Request (PPR) Log Enable. */ + uint32_t u1PprIntrEn : 1; /**< Bit 14 - PprIntrEn: Peripheral Page Request Interrupt Enable. */ + uint32_t u1PprEn : 1; /**< Bit 15 - PprEn: Peripheral Page Request processing Enable. */ + uint32_t u1GstTranslateEn : 1; /**< Bit 16 - GTEn: Guest Translate Enable. */ + uint32_t u1GstVirtApicEn : 1; /**< Bit 17 - GAEn: Guest Virtual-APIC Enable. */ + uint32_t u4Crw : 1; /**< Bits 21:18 - CRW: Intended for future use (not documented). */ + uint32_t u1SmiFilterEn : 1; /**< Bit 22 - SmiFEn: SMI Filter Enable. */ + uint32_t u1SelfWriteBackDis : 1; /**< Bit 23 - SlfWBDis: Self Write-Back Disable. */ + uint32_t u1SmiFilterLogEn : 1; /**< Bit 24 - SmiFLogEn: SMI Filter Log Enable. */ + uint32_t u3GstVirtApicModeEn : 3; /**< Bits 27:25 - GAMEn: Guest Virtual-APIC Mode Enable. */ + uint32_t u1GstLogEn : 1; /**< Bit 28 - GALogEn: Guest Virtual-APIC GA Log Enable. */ + uint32_t u1GstIntrEn : 1; /**< Bit 29 - GAIntEn: Guest Virtual-APIC Interrupt Enable. */ + uint32_t u2DualPprLogEn : 2; /**< Bits 31:30 - DualPprLogEn: Dual Peripheral Page Request Log Enable. */ + uint32_t u2DualEvtLogEn : 2; /**< Bits 33:32 - DualEventLogEn: Dual Event Log Enable. */ + uint32_t u3DevTabSegEn : 3; /**< Bits 36:34 - DevTblSegEn: Device Table Segment Enable. */ + uint32_t u2PrivAbortEn : 2; /**< Bits 38:37 - PrivAbrtEn: Privilege Abort Enable. */ + uint32_t u1PprAutoRespEn : 1; /**< Bit 39 - PprAutoRspEn: Peripheral Page Request Auto Response Enable. */ + uint32_t u1MarcEn : 1; /**< Bit 40 - MarcEn: Memory Address Routing and Control Enable. */ + uint32_t u1BlockStopMarkEn : 1; /**< Bit 41 - BlkStopMarkEn: Block StopMark messages Enable. */ + uint32_t u1PprAutoRespAlwaysOnEn : 1; /**< Bit 42 - PprAutoRspAon:: PPR Auto Response - Always On Enable. */ + uint32_t u1DomainIDPNE : 1; /**< Bit 43 - DomainIDPE: Reserved (not documented). */ + uint32_t u1Rsvd0 : 1; /**< Bit 44 - Reserved. */ + uint32_t u1EnhancedPpr : 1; /**< Bit 45 - EPHEn: Enhanced Peripheral Page Request Handling Enable. */ + uint32_t u2HstAccDirtyBitUpdate : 2; /**< Bits 47:46 - HADUpdate: Access and Dirty Bit updated in host page table. */ + uint32_t u1GstDirtyUpdateDis : 1; /**< Bit 48 - GDUpdateDis: Disable hardare update of Dirty bit in GPT. */ + uint32_t u1Rsvd1 : 1; /**< Bit 49 - Reserved. */ + uint32_t u1X2ApicEn : 1; /**< Bit 50 - XTEn: Enable X2APIC. */ + uint32_t u1X2ApicIntrGenEn : 1; /**< Bit 51 - IntCapXTEn: Enable IOMMU X2APIC Interrupt generation. */ + uint32_t u2Rsvd0 : 2; /**< Bits 53:52 - Reserved. */ + uint32_t u1GstAccessUpdateDis : 1; /**< Bit 54 - GAUpdateDis: Disable hardare update of Access bit in GPT. */ + uint32_t u8Rsvd0 : 8; /**< Bits 63:55 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_CTRL_T; +AssertCompileSize(IOMMU_CTRL_T, 8); +#define IOMMU_CTRL_VALID_MASK UINT64_C(0x004defffffffffff) +#define IOMMU_CTRL_CMD_BUF_EN_MASK UINT64_C(0x0000000000001001) + +/** + * IOMMU Exclusion Base Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u1ExclEnable : 1; /**< Bit 0 - ExEn: Exclusion Range Enable. */ + RT_GCC_EXTENSION uint64_t u1AllowAll : 1; /**< Bit 1 - Allow: Allow All Devices. */ + RT_GCC_EXTENSION uint64_t u10Rsvd0 : 10; /**< Bits 11:2 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40ExclRangeBase : 40; /**< Bits 51:12 - Exclusion Range Base Address. */ + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bits 63:52 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_EXCL_RANGE_BAR_T; +AssertCompileSize(IOMMU_EXCL_RANGE_BAR_T, 8); +#define IOMMU_EXCL_RANGE_BAR_VALID_MASK UINT64_C(0x000ffffffffff003) + +/** + * IOMMU Exclusion Range Limit Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bits 63:52 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40ExclRangeLimit : 40; /**< Bits 51:12 - Exclusion Range Limit Address. */ + RT_GCC_EXTENSION uint64_t u12Rsvd1 : 12; /**< Bits 63:52 - Reserved (treated as 1s). */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_EXCL_RANGE_LIMIT_T; +AssertCompileSize(IOMMU_EXCL_RANGE_LIMIT_T, 8); +#define IOMMU_EXCL_RANGE_LIMIT_VALID_MASK UINT64_C(0x000fffffffffffff) + +/** + * IOMMU Extended Feature Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u1PrefetchSup : 1; /**< Bit 0 - PreFSup: Prefetch Support. */ + uint32_t u1PprSup : 1; /**< Bit 1 - PPRSup: Peripheral Page Request Support. */ + uint32_t u1X2ApicSup : 1; /**< Bit 2 - XTSup: x2Apic Support. */ + uint32_t u1NoExecuteSup : 1; /**< Bit 3 - NXSup: No-Execute and Privilege Level Support. */ + uint32_t u1GstTranslateSup : 1; /**< Bit 4 - GTSup: Guest Translations (for GVAs) Support. */ + uint32_t u1Rsvd0 : 1; /**< Bit 5 - Reserved. */ + uint32_t u1InvAllSup : 1; /**< Bit 6 - IASup: Invalidate-All Support. */ + uint32_t u1GstVirtApicSup : 1; /**< Bit 7 - GASup: Guest Virtual-APIC Support. */ + uint32_t u1HwErrorSup : 1; /**< Bit 8 - HESup: Hardware Error registers Support. */ + uint32_t u1PerfCounterSup : 1; /**< Bit 9 - PCSup: Performance Counter Support. */ + uint32_t u2HostAddrTranslateSize : 2; /**< Bits 11:10 - HATS: Host Address Translation Size. */ + uint32_t u2GstAddrTranslateSize : 2; /**< Bits 13:12 - GATS: Guest Address Translation Size. */ + uint32_t u2GstCr3RootTblLevel : 2; /**< Bits 15:14 - GLXSup: Guest CR3 Root Table Level (Max) Size Support. */ + uint32_t u2SmiFilterSup : 2; /**< Bits 17:16 - SmiFSup: SMI Filter Register Support. */ + uint32_t u3SmiFilterCount : 3; /**< Bits 20:18 - SmiFRC: SMI Filter Register Count. */ + uint32_t u3GstVirtApicModeSup : 3; /**< Bits 23:21 - GAMSup: Guest Virtual-APIC Modes Supported. */ + uint32_t u2DualPprLogSup : 2; /**< Bits 25:24 - DualPprLogSup: Dual Peripheral Page Request Log Support. */ + uint32_t u2Rsvd0 : 2; /**< Bits 27:26 - Reserved. */ + uint32_t u2DualEvtLogSup : 2; /**< Bits 29:28 - DualEventLogSup: Dual Event Log Support. */ + uint32_t u2Rsvd1 : 2; /**< Bits 31:30 - Reserved. */ + uint32_t u5MaxPasidSup : 5; /**< Bits 36:32 - PASMax: Maximum PASID Supported. */ + uint32_t u1UserSupervisorSup : 1; /**< Bit 37 - USSup: User/Supervisor Page Protection Support. */ + uint32_t u2DevTabSegSup : 2; /**< Bits 39:38 - DevTlbSegSup: Segmented Device Table Support. */ + uint32_t u1PprLogOverflowWarn : 1; /**< Bit 40 - PprOvrflwEarlySup: PPR Log Overflow Early Warning Support. */ + uint32_t u1PprAutoRespSup : 1; /**< Bit 41 - PprAutoRspSup: PPR Automatic Response Support. */ + uint32_t u2MarcSup : 2; /**< Bit 43:42 - MarcSup: Memory Access Routing and Control Support. */ + uint32_t u1BlockStopMarkSup : 1; /**< Bit 44 - BlkStopMarkSup: Block StopMark messages Support. */ + uint32_t u1PerfOptSup : 1; /**< Bit 45 - PerfOptSup: IOMMU Performance Optimization Support. */ + uint32_t u1MsiCapMmioSup : 1; /**< Bit 46 - MsiCapMmioSup: MSI Capability Register MMIO Access Support. */ + uint32_t u1Rsvd1 : 1; /**< Bit 47 - Reserved. */ + uint32_t u1GstIoSup : 1; /**< Bit 48 - GIoSup: Guest I/O Protection Support. */ + uint32_t u1HostAccessSup : 1; /**< Bit 49 - HASup: Host Access Support. */ + uint32_t u1EnhancedPprSup : 1; /**< Bit 50 - EPHSup: Enhanced Peripheral Page Request Handling Support. */ + uint32_t u1AttrForwardSup : 1; /**< Bit 51 - AttrFWSup: Attribute Forward Support. */ + uint32_t u1HostDirtySup : 1; /**< Bit 52 - HDSup: Host Dirty Support. */ + uint32_t u1Rsvd2 : 1; /**< Bit 53 - Reserved. */ + uint32_t u1InvIoTlbTypeSup : 1; /**< Bit 54 - InvIotlbTypeSup: Invalidate IOTLB Type Support. */ + uint32_t u6Rsvd0 : 6; /**< Bit 60:55 - Reserved. */ + uint32_t u1GstUpdateDisSup : 1; /**< Bit 61 - GAUpdateDisSup: Disable hardware update on GPT Support. */ + uint32_t u1ForcePhysDstSup : 1; /**< Bit 62 - ForcePhyDestSup: Force Phys. Dst. Mode for Remapped Intr. */ + uint32_t u1Rsvd3 : 1; /**< Bit 63 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_EXT_FEAT_T; +AssertCompileSize(IOMMU_EXT_FEAT_T, 8); + +/** + * Peripheral Page Request Log Base Address Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bit 11:0 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40Base : 40; /**< Bits 51:12 - PPRLogBase: Peripheral Page Request Log Base Address. */ + RT_GCC_EXTENSION uint64_t u4Rsvd0 : 4; /**< Bits 55:52 - Reserved. */ + RT_GCC_EXTENSION uint64_t u4Len : 4; /**< Bits 59:56 - PPRLogLen: Peripheral Page Request Log Length. */ + RT_GCC_EXTENSION uint64_t u4Rsvd1 : 4; /**< Bits 63:60 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} PPR_LOG_BAR_T; +AssertCompileSize(PPR_LOG_BAR_T, 8); +#define IOMMU_PPR_LOG_BAR_VALID_MASK UINT64_C(0x0f0ffffffffff000) + +/** + * IOMMU Hardware Event Upper Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u60FirstOperand : 60; /**< Bits 59:0 - First event code dependent operand. */ + RT_GCC_EXTENSION uint64_t u4EvtCode : 4; /**< Bits 63:60 - Event Code. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_HW_EVT_HI_T; +AssertCompileSize(IOMMU_HW_EVT_HI_T, 8); + +/** + * IOMMU Hardware Event Lower Register (MMIO). + * In accordance with the AMD spec. + */ +typedef uint64_t IOMMU_HW_EVT_LO_T; + +/** + * IOMMU Hardware Event Status (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u1Valid : 1; /**< Bit 0 - HEV: Hardware Event Valid. */ + uint32_t u1Overflow : 1; /**< Bit 1 - HEO: Hardware Event Overflow. */ + uint32_t u30Rsvd0 : 30; /**< Bits 31:2 - Reserved. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_HW_EVT_STATUS_T; +AssertCompileSize(IOMMU_HW_EVT_STATUS_T, 8); +#define IOMMU_HW_EVT_STATUS_VALID_MASK UINT64_C(0x0000000000000003) + +/** + * Guest Virtual-APIC Log Base Address Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bit 11:0 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40Base : 40; /**< Bits 51:12 - GALogBase: Guest Virtual-APIC Log Base Address. */ + RT_GCC_EXTENSION uint64_t u4Rsvd0 : 4; /**< Bits 55:52 - Reserved. */ + RT_GCC_EXTENSION uint64_t u4Len : 4; /**< Bits 59:56 - GALogLen: Guest Virtual-APIC Log Length. */ + RT_GCC_EXTENSION uint64_t u4Rsvd1 : 4; /**< Bits 63:60 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} GALOG_BAR_T; +AssertCompileSize(GALOG_BAR_T, 8); + +/** + * Guest Virtual-APIC Log Tail Address Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u3Rsvd0 : 3; /**< Bits 2:0 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40GALogTailAddr : 48; /**< Bits 51:3 - GATAddr: Guest Virtual-APIC Tail Log Address. */ + RT_GCC_EXTENSION uint64_t u11Rsvd1 : 11; /**< Bits 63:52 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} GALOG_TAIL_ADDR_T; +AssertCompileSize(GALOG_TAIL_ADDR_T, 8); + +/** + * PPR Log B Base Address Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to PPR_LOG_BAR_T. + */ +typedef PPR_LOG_BAR_T PPR_LOG_B_BAR_T; + +/** + * Event Log B Base Address Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to EVT_LOG_BAR_T. + */ +typedef EVT_LOG_BAR_T EVT_LOG_B_BAR_T; + +/** + * Device-specific Feature Extension (DSFX) Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u24DevSpecFeat : 24; /**< Bits 23:0 - DevSpecificFeatSupp: Implementation specific features. */ + uint32_t u4RevMinor : 4; /**< Bits 27:24 - RevMinor: Minor revision identifier. */ + uint32_t u4RevMajor : 4; /**< Bits 31:28 - RevMajor: Major revision identifier. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved.*/ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} DEV_SPECIFIC_FEAT_T; +AssertCompileSize(DEV_SPECIFIC_FEAT_T, 8); + +/** + * Device-specific Control Extension (DSCX) Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u24DevSpecCtrl : 24; /**< Bits 23:0 - DevSpecificFeatCntrl: Implementation specific control. */ + uint32_t u4RevMinor : 4; /**< Bits 27:24 - RevMinor: Minor revision identifier. */ + uint32_t u4RevMajor : 4; /**< Bits 31:28 - RevMajor: Major revision identifier. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved.*/ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} DEV_SPECIFIC_CTRL_T; +AssertCompileSize(DEV_SPECIFIC_CTRL_T, 8); + +/** + * Device-specific Status Extension (DSSX) Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u24DevSpecStatus : 24; /**< Bits 23:0 - DevSpecificFeatStatus: Implementation specific status. */ + uint32_t u4RevMinor : 4; /**< Bits 27:24 - RevMinor: Minor revision identifier. */ + uint32_t u4RevMajor : 4; /**< Bits 31:28 - RevMajor: Major revision identifier. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved.*/ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} DEV_SPECIFIC_STATUS_T; +AssertCompileSize(DEV_SPECIFIC_STATUS_T, 8); + +/** + * MSI Information Register 0 and 1 (PCI) / MSI Vector Register 0 and 1 (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u5MsiNumEvtLog : 5; /**< Bits 4:0 - MsiNum: Event Log MSI message number. */ + uint32_t u3GstVirtAddrSize: 3; /**< Bits 7:5 - GVAsize: Guest Virtual Address Size. */ + uint32_t u7PhysAddrSize : 7; /**< Bits 14:8 - PAsize: Physical Address Size. */ + uint32_t u7VirtAddrSize : 7; /**< Bits 21:15 - VAsize: Virtual Address Size. */ + uint32_t u1HtAtsResv: 1; /**< Bit 22 - HtAtsResv: HyperTransport ATS Response Address range Reserved. */ + uint32_t u4Rsvd0 : 4; /**< Bits 26:23 - Reserved. */ + uint32_t u5MsiNumPpr : 5; /**< Bits 31:27 - MsiNumPPR: Peripheral Page Request MSI message number. */ + uint32_t u5MsiNumGa : 5; /**< Bits 36:32 - MsiNumGa: MSI message number for guest virtual-APIC log. */ + uint32_t u27Rsvd0: 27; /**< Bits 63:37 - Reserved. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[2]; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} MSI_MISC_INFO_T; +AssertCompileSize(MSI_MISC_INFO_T, 8); +/** MSI Vector Register 0 and 1 (MMIO). */ +typedef MSI_MISC_INFO_T MSI_VECTOR_T; +/** Mask of valid bits in MSI Vector Register 1 (or high dword of MSI Misc. + * info). */ +#define IOMMU_MSI_VECTOR_1_VALID_MASK UINT32_C(0x1f) + +/** + * MSI Capability Header Register (PCI + MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u8MsiCapId : 8; /**< Bits 7:0 - MsiCapId: Capability ID. */ + uint32_t u8MsiCapPtr : 8; /**< Bits 15:8 - MsiCapPtr: Pointer (PCI config offset) to the next capability. */ + uint32_t u1MsiEnable : 1; /**< Bit 16 - MsiEn: Message Signal Interrupt Enable. */ + uint32_t u3MsiMultiMessCap : 3; /**< Bits 19:17 - MsiMultMessCap: MSI Multi-Message Capability. */ + uint32_t u3MsiMultiMessEn : 3; /**< Bits 22:20 - MsiMultMessEn: MSI Multi-Message Enable. */ + uint32_t u1Msi64BitEn : 1; /**< Bit 23 - Msi64BitEn: MSI 64-bit Enable. */ + uint32_t u8Rsvd0 : 8; /**< Bits 31:24 - Reserved. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t u32; +} MSI_CAP_HDR_T; +AssertCompileSize(MSI_CAP_HDR_T, 4); +#define IOMMU_MSI_CAP_HDR_MSI_EN_MASK RT_BIT(16) + +/** + * MSI Mapping Capability Header Register (PCI + MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u8MsiMapCapId : 8; /**< Bits 7:0 - MsiMapCapId: MSI Map capability ID. */ + uint32_t u8Rsvd0 : 8; /**< Bits 15:8 - Reserved. */ + uint32_t u1MsiMapEn : 1; /**< Bit 16 - MsiMapEn: MSI Map enable. */ + uint32_t u1MsiMapFixed : 1; /**< Bit 17 - MsiMapFixd: MSI Map fixed. */ + uint32_t u9Rsvd0 : 9; /**< Bits 26:18 - Reserved. */ + uint32_t u5MapCapType : 5; /**< Bits 31:27 - MsiMapCapType: MSI Mapping capability type. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t u32; +} MSI_MAP_CAP_HDR_T; +AssertCompileSize(MSI_MAP_CAP_HDR_T, 4); + +/** + * Performance Optimization Control Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u13Rsvd0 : 13; /**< Bits 12:0 - Reserved. */ + uint32_t u1PerfOptEn : 1; /**< Bit 13 - PerfOptEn: Performance Optimization Enable. */ + uint32_t u17Rsvd0 : 18; /**< Bits 31:14 - Reserved. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t u32; +} IOMMU_PERF_OPT_CTRL_T; +AssertCompileSize(IOMMU_PERF_OPT_CTRL_T, 4); + +/** + * XT (x2APIC) IOMMU General Interrupt Control Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u2Rsvd0 : 2; /**< Bits 1:0 - Reserved.*/ + uint32_t u1X2ApicIntrDstMode : 1; /**< Bit 2 - Destination Mode for general interrupt.*/ + uint32_t u4Rsvd0 : 4; /**< Bits 7:3 - Reserved.*/ + uint32_t u24X2ApicIntrDstLo : 24; /**< Bits 31:8 - Destination for general interrupt (Lo).*/ + uint32_t u8X2ApicIntrVector : 8; /**< Bits 39:32 - Vector for general interrupt.*/ + uint32_t u1X2ApicIntrDeliveryMode : 1; /**< Bit 40 - Delivery Mode for general interrupt.*/ + uint32_t u15Rsvd0 : 15; /**< Bits 55:41 - Reserved.*/ + uint32_t u7X2ApicIntrDstHi : 7; /**< Bits 63:56 - Destination for general interrupt (Hi) .*/ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_XT_GEN_INTR_CTRL_T; +AssertCompileSize(IOMMU_XT_GEN_INTR_CTRL_T, 8); + +/** + * XT (x2APIC) IOMMU General Interrupt Control Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u2Rsvd0 : 2; /**< Bits 1:0 - Reserved.*/ + uint32_t u1X2ApicIntrDstMode : 1; /**< Bit 2 - Destination Mode for the interrupt.*/ + uint32_t u4Rsvd0 : 4; /**< Bits 7:3 - Reserved.*/ + uint32_t u24X2ApicIntrDstLo : 24; /**< Bits 31:8 - Destination for the interrupt (Lo).*/ + uint32_t u8X2ApicIntrVector : 8; /**< Bits 39:32 - Vector for the interrupt.*/ + uint32_t u1X2ApicIntrDeliveryMode : 1; /**< Bit 40 - Delivery Mode for the interrupt.*/ + uint32_t u15Rsvd0 : 15; /**< Bits 55:41 - Reserved.*/ + uint32_t u7X2ApicIntrDstHi : 7; /**< Bits 63:56 - Destination for the interrupt (Hi) .*/ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_XT_INTR_CTRL_T; +AssertCompileSize(IOMMU_XT_INTR_CTRL_T, 8); + +/** + * XT (x2APIC) IOMMU PPR Interrupt Control Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to IOMMU_XT_INTR_CTRL_T. + */ +typedef IOMMU_XT_INTR_CTRL_T IOMMU_XT_PPR_INTR_CTRL_T; + +/** + * XT (x2APIC) IOMMU GA (Guest Address) Log Control Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to IOMMU_XT_INTR_CTRL_T. + */ +typedef IOMMU_XT_INTR_CTRL_T IOMMU_XT_GALOG_INTR_CTRL_T; + +/** + * Memory Access and Routing Control (MARC) Aperture Base Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bits 11:0 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40MarcBaseAddr : 40; /**< Bits 51:12 - MarcBaseAddr: MARC Aperture Base Address. */ + RT_GCC_EXTENSION uint64_t u12Rsvd1 : 12; /**< Bits 63:52 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} MARC_APER_BAR_T; +AssertCompileSize(MARC_APER_BAR_T, 8); + +/** + * Memory Access and Routing Control (MARC) Relocation Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u1RelocEn : 1; /**< Bit 0 - RelocEn: Relocation Enabled. */ + RT_GCC_EXTENSION uint64_t u1ReadOnly : 1; /**< Bit 1 - ReadOnly: Whether only read-only acceses allowed. */ + RT_GCC_EXTENSION uint64_t u10Rsvd0 : 10; /**< Bits 11:2 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40MarcRelocAddr : 40; /**< Bits 51:12 - MarcRelocAddr: MARC Aperture Relocation Address. */ + RT_GCC_EXTENSION uint64_t u12Rsvd1 : 12; /**< Bits 63:52 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} MARC_APER_RELOC_T; +AssertCompileSize(MARC_APER_RELOC_T, 8); + +/** + * Memory Access and Routing Control (MARC) Length Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bits 11:0 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40MarcLength : 40; /**< Bits 51:12 - MarcLength: MARC Aperture Length. */ + RT_GCC_EXTENSION uint64_t u12Rsvd1 : 12; /**< Bits 63:52 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} MARC_APER_LEN_T; + +/** + * Memory Access and Routing Control (MARC) Aperture Register. + * This combines other registers to match the MMIO layout for convenient access. + */ +typedef struct +{ + MARC_APER_BAR_T Base; + MARC_APER_RELOC_T Reloc; + MARC_APER_LEN_T Length; +} MARC_APER_T; +AssertCompileSize(MARC_APER_T, 24); + +/** + * IOMMU Reserved Register (MMIO). + * In accordance with the AMD spec. + * This register is reserved for hardware use (although RW?). + */ +typedef uint64_t IOMMU_RSVD_REG_T; + +/** + * Command Buffer Head Pointer Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t off; /**< Bits 31:0 - Buffer pointer (offset; 16 byte aligned, 512 KB max). */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[2]; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} CMD_BUF_HEAD_PTR_T; +AssertCompileSize(CMD_BUF_HEAD_PTR_T, 8); +#define IOMMU_CMD_BUF_HEAD_PTR_VALID_MASK UINT64_C(0x000000000007fff0) + +/** + * Command Buffer Tail Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T CMD_BUF_TAIL_PTR_T; +#define IOMMU_CMD_BUF_TAIL_PTR_VALID_MASK IOMMU_CMD_BUF_HEAD_PTR_VALID_MASK + +/** + * Event Log Head Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T EVT_LOG_HEAD_PTR_T; +#define IOMMU_EVT_LOG_HEAD_PTR_VALID_MASK IOMMU_CMD_BUF_HEAD_PTR_VALID_MASK + +/** + * Event Log Tail Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T EVT_LOG_TAIL_PTR_T; +#define IOMMU_EVT_LOG_TAIL_PTR_VALID_MASK IOMMU_CMD_BUF_HEAD_PTR_VALID_MASK + + +/** + * IOMMU Status Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u1EvtOverflow : 1; /**< Bit 0 - EventOverflow: Event log overflow. */ + uint32_t u1EvtLogIntr : 1; /**< Bit 1 - EventLogInt: Event log interrupt. */ + uint32_t u1CompWaitIntr : 1; /**< Bit 2 - ComWaitInt: Completion wait interrupt . */ + uint32_t u1EvtLogRunning : 1; /**< Bit 3 - EventLogRun: Event logging is running. */ + uint32_t u1CmdBufRunning : 1; /**< Bit 4 - CmdBufRun: Command buffer is running. */ + uint32_t u1PprOverflow : 1; /**< Bit 5 - PprOverflow: Peripheral Page Request Log (PPR) overflow. */ + uint32_t u1PprIntr : 1; /**< Bit 6 - PprInt: PPR interrupt. */ + uint32_t u1PprLogRunning : 1; /**< Bit 7 - PprLogRun: PPR logging is running. */ + uint32_t u1GstLogRunning : 1; /**< Bit 8 - GALogRun: Guest virtual-APIC logging is running. */ + uint32_t u1GstLogOverflow : 1; /**< Bit 9 - GALOverflow: Guest virtual-APIC log overflow. */ + uint32_t u1GstLogIntr : 1; /**< Bit 10 - GAInt: Guest virtual-APIC log interrupt. */ + uint32_t u1PprOverflowB : 1; /**< Bit 11 - PprOverflowB: PPR log B overflow. */ + uint32_t u1PprLogActive : 1; /**< Bit 12 - PprLogActive: PPR log A is active. */ + uint32_t u2Rsvd0 : 2; /**< Bits 14:13 - Reserved. */ + uint32_t u1EvtOverflowB : 1; /**< Bit 15 - EvtOverflowB: Event log B overflow. */ + uint32_t u1EvtLogActive : 1; /**< Bit 16 - EvtLogActive: Event log A active. */ + uint32_t u1PprOverflowEarlyB : 1; /**< Bit 17 - PprOverflowEarlyB: PPR log B overflow early warning. */ + uint32_t u1PprOverflowEarly : 1; /**< Bit 18 - PprOverflowEarly: PPR log overflow early warning. */ + uint32_t u13Rsvd0 : 13; /**< Bits 31:19 - Reserved. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved . */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[2]; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_STATUS_T; +AssertCompileSize(IOMMU_STATUS_T, 8); +#define IOMMU_STATUS_VALID_MASK UINT64_C(0x0000000000079fff) +#define IOMMU_STATUS_RW1C_MASK UINT64_C(0x0000000000068e67) + +/** + * PPR Log Head Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T PPR_LOG_HEAD_PTR_T; + +/** + * PPR Log Tail Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T PPR_LOG_TAIL_PTR_T; + +/** + * Guest Virtual-APIC Log Head Pointer Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u2Rsvd0 : 2; /**< Bits 2:0 - Reserved. */ + uint32_t u12GALogPtr : 12; /**< Bits 15:3 - Guest Virtual-APIC Log Head or Tail Pointer. */ + uint32_t u16Rsvd0 : 16; /**< Bits 31:16 - Reserved. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[2]; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} GALOG_HEAD_PTR_T; +AssertCompileSize(GALOG_HEAD_PTR_T, 8); + +/** + * Guest Virtual-APIC Log Tail Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to GALOG_HEAD_PTR_T. + */ +typedef GALOG_HEAD_PTR_T GALOG_TAIL_PTR_T; + +/** + * PPR Log B Head Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T PPR_LOG_B_HEAD_PTR_T; + +/** + * PPR Log B Tail Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T PPR_LOG_B_TAIL_PTR_T; + +/** + * Event Log B Head Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T EVT_LOG_B_HEAD_PTR_T; + +/** + * Event Log B Tail Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T EVT_LOG_B_TAIL_PTR_T; + +/** + * PPR Log Auto Response Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u4AutoRespCode : 4; /**< Bits 3:0 - PprAutoRespCode: PPR log Auto Response Code. */ + uint32_t u1AutoRespMaskGen : 1; /**< Bit 4 - PprAutoRespMaskGn: PPR log Auto Response Mask Gen. */ + uint32_t u27Rsvd0 : 27; /**< Bits 31:5 - Reserved. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved.*/ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[2]; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} PPR_LOG_AUTO_RESP_T; +AssertCompileSize(PPR_LOG_AUTO_RESP_T, 8); + +/** + * PPR Log Overflow Early Indicator Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u15Threshold : 15; /**< Bits 14:0 - PprOvrflwEarlyThreshold: Overflow early indicator threshold. */ + uint32_t u15Rsvd0 : 15; /**< Bits 29:15 - Reserved. */ + uint32_t u1IntrEn : 1; /**< Bit 30 - PprOvrflwEarlyIntEn: Overflow early indicator interrupt enable. */ + uint32_t u1Enable : 1; /**< Bit 31 - PprOvrflwEarlyEn: Overflow early indicator enable. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[2]; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} PPR_LOG_OVERFLOW_EARLY_T; +AssertCompileSize(PPR_LOG_OVERFLOW_EARLY_T, 8); + +/** + * PPR Log B Overflow Early Indicator Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to PPR_LOG_OVERFLOW_EARLY_T. + */ +typedef PPR_LOG_OVERFLOW_EARLY_T PPR_LOG_B_OVERFLOW_EARLY_T; + +/** + * ILLEGAL_DEV_TABLE_ENTRY Event Types. + * In accordance with the AMD spec. + */ +typedef enum EVT_ILLEGAL_DTE_TYPE_T +{ + kIllegalDteType_RsvdNotZero = 0, + kIllegalDteType_RsvdIntTabLen, + kIllegalDteType_RsvdIoCtl, + kIllegalDteType_RsvdIntCtl +} EVT_ILLEGAL_DTE_TYPE_T; + +/** + * ILLEGAL_DEV_TABLE_ENTRY Event Types. + * In accordance with the AMD spec. + */ +typedef enum EVT_IO_PAGE_FAULT_TYPE_T +{ + /* Memory transaction. */ + kIoPageFaultType_DteRsvdPagingMode = 0, + kIoPageFaultType_PteInvalidPageSize, + kIoPageFaultType_PteInvalidLvlEncoding, + kIoPageFaultType_SkippedLevelIovaNotZero, + kIoPageFaultType_PteRsvdNotZero, + kIoPageFaultType_PteValidNotSet, + kIoPageFaultType_DteTranslationDisabled, + kIoPageFaultType_PasidInvalidRange, + kIoPageFaultType_PermDenied, + kIoPageFaultType_UserSupervisor, + /* Interrupt remapping */ + kIoPageFaultType_IrteAddrInvalid, + kIoPageFaultType_IrteRsvdNotZero, + kIoPageFaultType_IrteRemapEn, + kIoPageFaultType_IrteRsvdIntType, + kIoPageFaultType_IntrReqAborted, + kIoPageFaultType_IntrWithPasid, + kIoPageFaultType_SmiFilterMismatch, + /* Memory transaction or interrupt remapping. */ + kIoPageFaultType_DevId_Invalid +} EVT_IO_PAGE_FAULT_TYPE_T; + +/** + * IOTLB_INV_TIMEOUT Event Types. + * In accordance with the AMD spec. + */ +typedef enum EVT_IOTLB_INV_TIMEOUT_TYPE_T +{ + InvTimeoutType_NoResponse = 0 +} EVT_IOTLB_INV_TIMEOUT_TYPE_T; + +/** + * INVALID_DEVICE_REQUEST Event Types. + * In accordance with the AMD spec. + */ +typedef enum EVT_INVALID_DEV_REQ_TYPE_T +{ + /* Access. */ + kInvalidDevReqType_ReadOrNonPostedWrite = 0, + kInvalidDevReqType_PretranslatedTransaction, + kInvalidDevReqType_PortIo, + kInvalidDevReqType_SysMgt, + kInvalidDevReqType_IntrRange, + kInvalidDevReqType_RsvdIntrRange, + kInvalidDevReqType_SysMgtAddr, + /* Translation Request. */ + kInvalidDevReqType_TrAccessInvalid, + kInvalidDevReqType_TrDisabled, + kInvalidDevReqType_DevIdInvalid +} EVT_INVALID_DEV_REQ_TYPE_T; + +/** + * INVALID_PPR_REQUEST Event Types. + * In accordance with the AMD spec. + */ +typedef enum EVT_INVALID_PPR_REQ_TYPE_T +{ + kInvalidPprReqType_PriNotSupported, + kInvalidPprReqType_GstTranslateDisabled +} EVT_INVALID_PPR_REQ_TYPE_T; + + +/** @name IVRS format revision field. + * In accordance with the AMD spec. + * @{ */ +/** Fixed: Supports only pre-assigned device IDs and type 10h and 11h IVHD + * blocks. */ +#define ACPI_IVRS_FMT_REV_FIXED 0x1 +/** Mixed: Supports pre-assigned and ACPI HID device naming and all IVHD blocks. */ +#define ACPI_IVRS_FMT_REV_MIXED 0x2 +/** @} */ + +/** @name IVHD special device entry variety field. + * In accordance with the AMD spec. + * @{ */ +/** I/O APIC. */ +#define ACPI_IVHD_VARIETY_IOAPIC 0x1 +/** HPET. */ +#define ACPI_IVHD_VARIETY_HPET 0x2 +/** @} */ + +/** @name IVHD device entry type codes. + * In accordance with the AMD spec. + * @{ */ +/** Reserved. */ +#define ACPI_IVHD_DEVENTRY_TYPE_RSVD 0x0 +/** All: DTE setting applies to all Device IDs. */ +#define ACPI_IVHD_DEVENTRY_TYPE_ALL 0x1 +/** Select: DTE setting applies to the device specified in DevId field. */ +#define ACPI_IVHD_DEVENTRY_TYPE_SELECT 0x2 +/** Start of range: DTE setting applies to all devices from start of range specified + * by the DevId field. */ +#define ACPI_IVHD_DEVENTRY_TYPE_START_RANGE 0x3 +/** End of range: DTE setting from previous type 3 entry applies to all devices + * incl. DevId specified by this entry. */ +#define ACPI_IVHD_DEVENTRY_TYPE_END_RANGE 0x4 +/** @} */ + +/** @name IVHD DTE (Device Table Entry) Settings. + * In accordance with the AMD spec. + * @{ */ +/** INITPass: Identifies a device able to assert INIT interrupts. */ +#define ACPI_IVHD_DTE_INIT_PASS_SHIFT 0 +#define ACPI_IVHD_DTE_INIT_PASS_MASK UINT8_C(0x01) +/** EIntPass: Identifies a device able to assert ExtInt interrupts. */ +#define ACPI_IVHD_DTE_EXTINT_PASS_SHIFT 1 +#define ACPI_IVHD_DTE_EXTINT_PASS_MASK UINT8_C(0x02) +/** NMIPass: Identifies a device able to assert NMI interrupts. */ +#define ACPI_IVHD_DTE_NMI_PASS_SHIFT 2 +#define ACPI_IVHD_DTE_NMI_PASS_MASK UINT8_C(0x04) +/** Bit 3 reserved. */ +#define ACPI_IVHD_DTE_RSVD_3_SHIFT 3 +#define ACPI_IVHD_DTE_RSVD_3_MASK UINT8_C(0x08) +/** SysMgt: Identifies a device able to assert system management messages. */ +#define ACPI_IVHD_DTE_SYS_MGT_SHIFT 4 +#define ACPI_IVHD_DTE_SYS_MGT_MASK UINT8_C(0x30) +/** Lint0Pass: Identifies a device able to assert LINT0 interrupts. */ +#define ACPI_IVHD_DTE_LINT0_PASS_SHIFT 6 +#define ACPI_IVHD_DTE_LINT0_PASS_MASK UINT8_C(0x40) +/** Lint0Pass: Identifies a device able to assert LINT1 interrupts. */ +#define ACPI_IVHD_DTE_LINT1_PASS_SHIFT 7 +#define ACPI_IVHD_DTE_LINT1_PASS_MASK UINT8_C(0x80) +RT_BF_ASSERT_COMPILE_CHECKS(ACPI_IVHD_DTE_, UINT8_C(0), UINT8_MAX, + (INIT_PASS, EXTINT_PASS, NMI_PASS, RSVD_3, SYS_MGT, LINT0_PASS, LINT1_PASS)); +/** @} */ + +/** + * AMD IOMMU: IVHD (I/O Virtualization Hardware Definition) Device Entry (4-byte). + * In accordance with the AMD spec. + */ +#pragma pack(1) +typedef struct ACPIIVHDDEVENTRY4 +{ + uint8_t u8DevEntryType; /**< Device entry type. */ + uint16_t u16DevId; /**< Device ID. */ + uint8_t u8DteSetting; /**< DTE (Device Table Entry) setting. */ +} ACPIIVHDDEVENTRY4; +#pragma pack() +AssertCompileSize(ACPIIVHDDEVENTRY4, 4); + +/** + * AMD IOMMU: IVHD (I/O Virtualization Hardware Definition) Device Entry (8-byte). + * In accordance with the AMD spec. + */ +#pragma pack(1) +typedef struct ACPIIVHDDEVENTRY8 +{ + uint8_t u8DevEntryType; /**< Device entry type. */ + union + { + /** Reserved: When u8DevEntryType is 0x40, 0x41, 0x44 or 0x45 (or 0x49-0x7F). */ + struct + { + uint8_t au8Rsvd0[7]; /**< Reserved (MBZ). */ + } rsvd; + /** Alias Select: When u8DevEntryType is 0x42 or 0x43. */ + struct + { + uint16_t u16DevIdA; /**< Device ID A. */ + uint8_t u8DteSetting; /**< DTE (Device Table Entry) setting. */ + uint8_t u8Rsvd0; /**< Reserved (MBZ). */ + uint16_t u16DevIdB; /**< Device ID B. */ + uint8_t u8Rsvd1; /**< Reserved (MBZ). */ + } alias; + /** Extended Select: When u8DevEntryType is 0x46 or 0x47. */ + struct + { + uint16_t u16DevId; /**< Device ID. */ + uint8_t u8DteSetting; /**< DTE (Device Table Entry) setting. */ + uint32_t u32ExtDteSetting; /**< Extended DTE setting. */ + } ext; + /** Special Device: When u8DevEntryType is 0x48. */ + struct + { + uint16_t u16Rsvd0; /**< Reserved (MBZ). */ + uint8_t u8DteSetting; /**< DTE (Device Table Entry) setting. */ + uint8_t u8Handle; /**< Handle contains I/O APIC ID or HPET number. */ + uint16_t u16DevIdB; /**< Device ID B (I/O APIC or HPET). */ + uint8_t u8Variety; /**< Whether this is the HPET or I/O APIC. */ + } special; + } u; +} ACPIIVHDDEVENTRY8; +#pragma pack() +AssertCompileSize(ACPIIVHDDEVENTRY8, 8); + +/** @name IVHD Type 10h Flags. + * In accordance with the AMD spec. + * @{ */ +/** Peripheral page request support. */ +#define ACPI_IVHD_10H_F_PPR_SUP RT_BIT(7) +/** Prefetch IOMMU pages command support. */ +#define ACPI_IVHD_10H_F_PREF_SUP RT_BIT(6) +/** Coherent control. */ +#define ACPI_IVHD_10H_F_COHERENT RT_BIT(5) +/** Remote IOTLB support. */ +#define ACPI_IVHD_10H_F_IOTLB_SUP RT_BIT(4) +/** Isochronous control. */ +#define ACPI_IVHD_10H_F_ISOC RT_BIT(3) +/** Response Pass Posted Write. */ +#define ACPI_IVHD_10H_F_RES_PASS_PW RT_BIT(2) +/** Pass Posted Write. */ +#define ACPI_IVHD_10H_F_PASS_PW RT_BIT(1) +/** HyperTransport Tunnel. */ +#define ACPI_IVHD_10H_F_HT_TUNNEL RT_BIT(0) +/** @} */ + +/** @name IVRS IVinfo field. + * In accordance with the AMD spec. + * @{ */ +/** EFRSup: Extended Feature Support. */ +#define ACPI_IVINFO_BF_EFR_SUP_SHIFT 0 +#define ACPI_IVINFO_BF_EFR_SUP_MASK UINT32_C(0x00000001) +/** DMA Remap Sup: DMA remapping support (pre-boot DMA protection with + * mandatory remapping of device accessed memory). */ +#define ACPI_IVINFO_BF_DMA_REMAP_SUP_SHIFT 1 +#define ACPI_IVINFO_BF_DMA_REMAP_SUP_MASK UINT32_C(0x00000002) +/** Bits 4:2 reserved. */ +#define ACPI_IVINFO_BF_RSVD_2_4_SHIFT 2 +#define ACPI_IVINFO_BF_RSVD_2_4_MASK UINT32_C(0x0000001c) +/** GVASize: Guest virtual-address size. */ +#define ACPI_IVINFO_BF_GVA_SIZE_SHIFT 5 +#define ACPI_IVINFO_BF_GVA_SIZE_MASK UINT32_C(0x000000e0) +/** PASize: System physical address size. */ +#define ACPI_IVINFO_BF_PA_SIZE_SHIFT 8 +#define ACPI_IVINFO_BF_PA_SIZE_MASK UINT32_C(0x00007f00) +/** VASize: Virtual address size. */ +#define ACPI_IVINFO_BF_VA_SIZE_SHIFT 15 +#define ACPI_IVINFO_BF_VA_SIZE_MASK UINT32_C(0x003f8000) +/** HTAtsResv: HyperTransport ATS-response address translation range reserved. */ +#define ACPI_IVINFO_BF_HT_ATS_RESV_SHIFT 22 +#define ACPI_IVINFO_BF_HT_ATS_RESV_MASK UINT32_C(0x00400000) +/** Bits 31:23 reserved. */ +#define ACPI_IVINFO_BF_RSVD_23_31_SHIFT 23 +#define ACPI_IVINFO_BF_RSVD_23_31_MASK UINT32_C(0xff800000) +RT_BF_ASSERT_COMPILE_CHECKS(ACPI_IVINFO_BF_, UINT32_C(0), UINT32_MAX, + (EFR_SUP, DMA_REMAP_SUP, RSVD_2_4, GVA_SIZE, PA_SIZE, VA_SIZE, HT_ATS_RESV, RSVD_23_31)); +/** @} */ + +/** @name IVHD IOMMU info flags. + * In accordance with the AMD spec. + * @{ */ +/** MSI message number for the event log. */ +#define ACPI_IOMMU_INFO_BF_MSI_NUM_SHIFT 0 +#define ACPI_IOMMU_INFO_BF_MSI_NUM_MASK UINT16_C(0x001f) +/** Bits 7:5 reserved. */ +#define ACPI_IOMMU_INFO_BF_RSVD_5_7_SHIFT 5 +#define ACPI_IOMMU_INFO_BF_RSVD_5_7_MASK UINT16_C(0x00e0) +/** IOMMU HyperTransport Unit ID number. */ +#define ACPI_IOMMU_INFO_BF_UNIT_ID_SHIFT 8 +#define ACPI_IOMMU_INFO_BF_UNIT_ID_MASK UINT16_C(0x1f00) +/** Bits 15:13 reserved. */ +#define ACPI_IOMMU_INFO_BF_RSVD_13_15_SHIFT 13 +#define ACPI_IOMMU_INFO_BF_RSVD_13_15_MASK UINT16_C(0xe000) +RT_BF_ASSERT_COMPILE_CHECKS(ACPI_IOMMU_INFO_BF_, UINT16_C(0), UINT16_MAX, + (MSI_NUM, RSVD_5_7, UNIT_ID, RSVD_13_15)); +/** @} */ + +/** @name IVHD IOMMU feature reporting field. + * In accordance with the AMD spec. + * @{ */ +/** x2APIC supported for peripherals. */ +#define ACPI_IOMMU_FEAT_BF_XT_SUP_SHIFT 0 +#define ACPI_IOMMU_FEAT_BF_XT_SUP_MASK UINT32_C(0x00000001) +/** NX supported for I/O. */ +#define ACPI_IOMMU_FEAT_BF_NX_SUP_SHIFT 1 +#define ACPI_IOMMU_FEAT_BF_NX_SUP_MASK UINT32_C(0x00000002) +/** GT (Guest Translation) supported. */ +#define ACPI_IOMMU_FEAT_BF_GT_SUP_SHIFT 2 +#define ACPI_IOMMU_FEAT_BF_GT_SUP_MASK UINT32_C(0x00000004) +/** GLX (Number of guest CR3 tables) supported. */ +#define ACPI_IOMMU_FEAT_BF_GLX_SUP_SHIFT 3 +#define ACPI_IOMMU_FEAT_BF_GLX_SUP_MASK UINT32_C(0x00000018) +/** IA (INVALIDATE_IOMMU_ALL) command supported. */ +#define ACPI_IOMMU_FEAT_BF_IA_SUP_SHIFT 5 +#define ACPI_IOMMU_FEAT_BF_IA_SUP_MASK UINT32_C(0x00000020) +/** GA (Guest virtual APIC) supported. */ +#define ACPI_IOMMU_FEAT_BF_GA_SUP_SHIFT 6 +#define ACPI_IOMMU_FEAT_BF_GA_SUP_MASK UINT32_C(0x00000040) +/** HE (Hardware error) registers supported. */ +#define ACPI_IOMMU_FEAT_BF_HE_SUP_SHIFT 7 +#define ACPI_IOMMU_FEAT_BF_HE_SUP_MASK UINT32_C(0x00000080) +/** PASMax (maximum PASID) supported. Ignored if PPRSup=0. */ +#define ACPI_IOMMU_FEAT_BF_PAS_MAX_SHIFT 8 +#define ACPI_IOMMU_FEAT_BF_PAS_MAX_MASK UINT32_C(0x00001f00) +/** PNCounters (Number of performance counters per counter bank) supported. */ +#define ACPI_IOMMU_FEAT_BF_PN_COUNTERS_SHIFT 13 +#define ACPI_IOMMU_FEAT_BF_PN_COUNTERS_MASK UINT32_C(0x0001e000) +/** PNBanks (Number of performance counter banks) supported. */ +#define ACPI_IOMMU_FEAT_BF_PN_BANKS_SHIFT 17 +#define ACPI_IOMMU_FEAT_BF_PN_BANKS_MASK UINT32_C(0x007e0000) +/** MSINumPPR (MSI number for peripheral page requests). */ +#define ACPI_IOMMU_FEAT_BF_MSI_NUM_PPR_SHIFT 23 +#define ACPI_IOMMU_FEAT_BF_MSI_NUM_PPR_MASK UINT32_C(0x0f800000) +/** GATS (Guest address translation size). MBZ when GTSup=0. */ +#define ACPI_IOMMU_FEAT_BF_GATS_SHIFT 28 +#define ACPI_IOMMU_FEAT_BF_GATS_MASK UINT32_C(0x30000000) +/** HATS (Host address translation size). */ +#define ACPI_IOMMU_FEAT_BF_HATS_SHIFT 30 +#define ACPI_IOMMU_FEAT_BF_HATS_MASK UINT32_C(0xc0000000) +RT_BF_ASSERT_COMPILE_CHECKS(ACPI_IOMMU_FEAT_BF_, UINT32_C(0), UINT32_MAX, + (XT_SUP, NX_SUP, GT_SUP, GLX_SUP, IA_SUP, GA_SUP, HE_SUP, PAS_MAX, PN_COUNTERS, PN_BANKS, + MSI_NUM_PPR, GATS, HATS)); +/** @} */ + +/** @name IOMMU Extended Feature Register (PCI/MMIO/ACPI). + * In accordance with the AMD spec. + * @{ */ +/** PreFSup: Prefetch support (RO). */ +#define IOMMU_EXT_FEAT_BF_PREF_SUP_SHIFT 0 +#define IOMMU_EXT_FEAT_BF_PREF_SUP_MASK UINT64_C(0x0000000000000001) +/** PPRSup: Peripheral Page Request (PPR) support (RO). */ +#define IOMMU_EXT_FEAT_BF_PPR_SUP_SHIFT 1 +#define IOMMU_EXT_FEAT_BF_PPR_SUP_MASK UINT64_C(0x0000000000000002) +/** XTSup: x2APIC support (RO). */ +#define IOMMU_EXT_FEAT_BF_X2APIC_SUP_SHIFT 2 +#define IOMMU_EXT_FEAT_BF_X2APIC_SUP_MASK UINT64_C(0x0000000000000004) +/** NXSup: No Execute (PMR and PRIV) support (RO). */ +#define IOMMU_EXT_FEAT_BF_NO_EXEC_SUP_SHIFT 3 +#define IOMMU_EXT_FEAT_BF_NO_EXEC_SUP_MASK UINT64_C(0x0000000000000008) +/** GTSup: Guest Translation support (RO). */ +#define IOMMU_EXT_FEAT_BF_GT_SUP_SHIFT 4 +#define IOMMU_EXT_FEAT_BF_GT_SUP_MASK UINT64_C(0x0000000000000010) +/** Bit 5 reserved. */ +#define IOMMU_EXT_FEAT_BF_RSVD_5_SHIFT 5 +#define IOMMU_EXT_FEAT_BF_RSVD_5_MASK UINT64_C(0x0000000000000020) +/** IASup: INVALIDATE_IOMMU_ALL command support (RO). */ +#define IOMMU_EXT_FEAT_BF_IA_SUP_SHIFT 6 +#define IOMMU_EXT_FEAT_BF_IA_SUP_MASK UINT64_C(0x0000000000000040) +/** GASup: Guest virtual-APIC support (RO). */ +#define IOMMU_EXT_FEAT_BF_GA_SUP_SHIFT 7 +#define IOMMU_EXT_FEAT_BF_GA_SUP_MASK UINT64_C(0x0000000000000080) +/** HESup: Hardware error registers support (RO). */ +#define IOMMU_EXT_FEAT_BF_HE_SUP_SHIFT 8 +#define IOMMU_EXT_FEAT_BF_HE_SUP_MASK UINT64_C(0x0000000000000100) +/** PCSup: Performance counters support (RO). */ +#define IOMMU_EXT_FEAT_BF_PC_SUP_SHIFT 9 +#define IOMMU_EXT_FEAT_BF_PC_SUP_MASK UINT64_C(0x0000000000000200) +/** HATS: Host Address Translation Size (RO). */ +#define IOMMU_EXT_FEAT_BF_HATS_SHIFT 10 +#define IOMMU_EXT_FEAT_BF_HATS_MASK UINT64_C(0x0000000000000c00) +/** GATS: Guest Address Translation Size (RO). */ +#define IOMMU_EXT_FEAT_BF_GATS_SHIFT 12 +#define IOMMU_EXT_FEAT_BF_GATS_MASK UINT64_C(0x0000000000003000) +/** GLXSup: Guest CR3 root table level support (RO). */ +#define IOMMU_EXT_FEAT_BF_GLX_SUP_SHIFT 14 +#define IOMMU_EXT_FEAT_BF_GLX_SUP_MASK UINT64_C(0x000000000000c000) +/** SmiFSup: SMI filter register support (RO). */ +#define IOMMU_EXT_FEAT_BF_SMI_FLT_SUP_SHIFT 16 +#define IOMMU_EXT_FEAT_BF_SMI_FLT_SUP_MASK UINT64_C(0x0000000000030000) +/** SmiFRC: SMI filter register count (RO). */ +#define IOMMU_EXT_FEAT_BF_SMI_FLT_REG_CNT_SHIFT 18 +#define IOMMU_EXT_FEAT_BF_SMI_FLT_REG_CNT_MASK UINT64_C(0x00000000001c0000) +/** GAMSup: Guest virtual-APIC modes support (RO). */ +#define IOMMU_EXT_FEAT_BF_GAM_SUP_SHIFT 21 +#define IOMMU_EXT_FEAT_BF_GAM_SUP_MASK UINT64_C(0x0000000000e00000) +/** DualPprLogSup: Dual PPR Log support (RO). */ +#define IOMMU_EXT_FEAT_BF_DUAL_PPR_LOG_SUP_SHIFT 24 +#define IOMMU_EXT_FEAT_BF_DUAL_PPR_LOG_SUP_MASK UINT64_C(0x0000000003000000) +/** Bits 27:26 reserved. */ +#define IOMMU_EXT_FEAT_BF_RSVD_26_27_SHIFT 26 +#define IOMMU_EXT_FEAT_BF_RSVD_26_27_MASK UINT64_C(0x000000000c000000) +/** DualEventLogSup: Dual Event Log support (RO). */ +#define IOMMU_EXT_FEAT_BF_DUAL_EVT_LOG_SUP_SHIFT 28 +#define IOMMU_EXT_FEAT_BF_DUAL_EVT_LOG_SUP_MASK UINT64_C(0x0000000030000000) +/** Bits 31:30 reserved. */ +#define IOMMU_EXT_FEAT_BF_RSVD_30_31_SHIFT 30 +#define IOMMU_EXT_FEAT_BF_RSVD_30_31_MASK UINT64_C(0x00000000c0000000) +/** PASMax: Maximum PASID support (RO). */ +#define IOMMU_EXT_FEAT_BF_PASID_MAX_SHIFT 32 +#define IOMMU_EXT_FEAT_BF_PASID_MAX_MASK UINT64_C(0x0000001f00000000) +/** USSup: User/Supervisor support (RO). */ +#define IOMMU_EXT_FEAT_BF_US_SUP_SHIFT 37 +#define IOMMU_EXT_FEAT_BF_US_SUP_MASK UINT64_C(0x0000002000000000) +/** DevTblSegSup: Segmented Device Table support (RO). */ +#define IOMMU_EXT_FEAT_BF_DEV_TBL_SEG_SUP_SHIFT 38 +#define IOMMU_EXT_FEAT_BF_DEV_TBL_SEG_SUP_MASK UINT64_C(0x000000c000000000) +/** PprOverflwEarlySup: PPR Log Overflow Early warning support (RO). */ +#define IOMMU_EXT_FEAT_BF_PPR_OVERFLOW_EARLY_SHIFT 40 +#define IOMMU_EXT_FEAT_BF_PPR_OVERFLOW_EARLY_MASK UINT64_C(0x0000010000000000) +/** PprAutoRspSup: PPR Automatic Response support (RO). */ +#define IOMMU_EXT_FEAT_BF_PPR_AUTO_RES_SUP_SHIFT 41 +#define IOMMU_EXT_FEAT_BF_PPR_AUTO_RES_SUP_MASK UINT64_C(0x0000020000000000) +/** MarcSup: Memory Access and Routing (MARC) support (RO). */ +#define IOMMU_EXT_FEAT_BF_MARC_SUP_SHIFT 42 +#define IOMMU_EXT_FEAT_BF_MARC_SUP_MASK UINT64_C(0x00000c0000000000) +/** BlkStopMrkSup: Block StopMark message support (RO). */ +#define IOMMU_EXT_FEAT_BF_BLKSTOP_MARK_SUP_SHIFT 44 +#define IOMMU_EXT_FEAT_BF_BLKSTOP_MARK_SUP_MASK UINT64_C(0x0000100000000000) +/** PerfOptSup: IOMMU Performance Optimization support (RO). */ +#define IOMMU_EXT_FEAT_BF_PERF_OPT_SUP_SHIFT 45 +#define IOMMU_EXT_FEAT_BF_PERF_OPT_SUP_MASK UINT64_C(0x0000200000000000) +/** MsiCapMmioSup: MSI-Capability Register MMIO access support (RO). */ +#define IOMMU_EXT_FEAT_BF_MSI_CAP_MMIO_SUP_SHIFT 46 +#define IOMMU_EXT_FEAT_BF_MSI_CAP_MMIO_SUP_MASK UINT64_C(0x0000400000000000) +/** Bit 47 reserved. */ +#define IOMMU_EXT_FEAT_BF_RSVD_47_SHIFT 47 +#define IOMMU_EXT_FEAT_BF_RSVD_47_MASK UINT64_C(0x0000800000000000) +/** GIoSup: Guest I/O Protection support (RO). */ +#define IOMMU_EXT_FEAT_BF_GST_IO_PROT_SUP_SHIFT 48 +#define IOMMU_EXT_FEAT_BF_GST_IO_PROT_SUP_MASK UINT64_C(0x0001000000000000) +/** HASup: Host Access support (RO). */ +#define IOMMU_EXT_FEAT_BF_HST_ACCESS_SUP_SHIFT 49 +#define IOMMU_EXT_FEAT_BF_HST_ACCESS_SUP_MASK UINT64_C(0x0002000000000000) +/** EPHSup: Enhandled PPR Handling support (RO). */ +#define IOMMU_EXT_FEAT_BF_ENHANCED_PPR_SUP_SHIFT 50 +#define IOMMU_EXT_FEAT_BF_ENHANCED_PPR_SUP_MASK UINT64_C(0x0004000000000000) +/** AttrFWSup: Attribute Forward support (RO). */ +#define IOMMU_EXT_FEAT_BF_ATTR_FW_SUP_SHIFT 51 +#define IOMMU_EXT_FEAT_BF_ATTR_FW_SUP_MASK UINT64_C(0x0008000000000000) +/** HDSup: Host Dirty Support (RO). */ +#define IOMMU_EXT_FEAT_BF_HST_DIRTY_SUP_SHIFT 52 +#define IOMMU_EXT_FEAT_BF_HST_DIRTY_SUP_MASK UINT64_C(0x0010000000000000) +/** Bit 53 reserved. */ +#define IOMMU_EXT_FEAT_BF_RSVD_53_SHIFT 53 +#define IOMMU_EXT_FEAT_BF_RSVD_53_MASK UINT64_C(0x0020000000000000) +/** InvIotlbTypeSup: Invalidate IOTLB type support (RO). */ +#define IOMMU_EXT_FEAT_BF_INV_IOTLB_TYPE_SUP_SHIFT 54 +#define IOMMU_EXT_FEAT_BF_INV_IOTLB_TYPE_SUP_MASK UINT64_C(0x0040000000000000) +/** Bits 60:55 reserved. */ +#define IOMMU_EXT_FEAT_BF_RSVD_55_60_SHIFT 55 +#define IOMMU_EXT_FEAT_BF_RSVD_55_60_MASK UINT64_C(0x1f80000000000000) +/** GAUpdateDisSup: Support disabling hardware update on guest page table access + * (RO). */ +#define IOMMU_EXT_FEAT_BF_GA_UPDATE_DIS_SUP_SHIFT 61 +#define IOMMU_EXT_FEAT_BF_GA_UPDATE_DIS_SUP_MASK UINT64_C(0x2000000000000000) +/** ForcePhysDestSup: Force Physical Destination Mode for Remapped Interrupt + * support (RO). */ +#define IOMMU_EXT_FEAT_BF_FORCE_PHYS_DST_SUP_SHIFT 62 +#define IOMMU_EXT_FEAT_BF_FORCE_PHYS_DST_SUP_MASK UINT64_C(0x4000000000000000) +/** Bit 63 reserved. */ +#define IOMMU_EXT_FEAT_BF_RSVD_63_SHIFT 63 +#define IOMMU_EXT_FEAT_BF_RSVD_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_EXT_FEAT_BF_, UINT64_C(0), UINT64_MAX, + (PREF_SUP, PPR_SUP, X2APIC_SUP, NO_EXEC_SUP, GT_SUP, RSVD_5, IA_SUP, GA_SUP, HE_SUP, PC_SUP, + HATS, GATS, GLX_SUP, SMI_FLT_SUP, SMI_FLT_REG_CNT, GAM_SUP, DUAL_PPR_LOG_SUP, RSVD_26_27, + DUAL_EVT_LOG_SUP, RSVD_30_31, PASID_MAX, US_SUP, DEV_TBL_SEG_SUP, PPR_OVERFLOW_EARLY, + PPR_AUTO_RES_SUP, MARC_SUP, BLKSTOP_MARK_SUP, PERF_OPT_SUP, MSI_CAP_MMIO_SUP, RSVD_47, + GST_IO_PROT_SUP, HST_ACCESS_SUP, ENHANCED_PPR_SUP, ATTR_FW_SUP, HST_DIRTY_SUP, RSVD_53, + INV_IOTLB_TYPE_SUP, RSVD_55_60, GA_UPDATE_DIS_SUP, FORCE_PHYS_DST_SUP, RSVD_63)); +/** @} */ + +/** + * IVHD (I/O Virtualization Hardware Definition) Type 10h. + * In accordance with the AMD spec. + */ +#pragma pack(1) +typedef struct ACPIIVHDTYPE10 +{ + uint8_t u8Type; /**< Type: Must be 0x10. */ + uint8_t u8Flags; /**< Flags (see ACPI_IVHD_10H_F_XXX). */ + uint16_t u16Length; /**< Length of IVHD including IVHD device entries. */ + uint16_t u16DeviceId; /**< Device ID of the IOMMU. */ + uint16_t u16CapOffset; /**< Offset in Capability space for control fields of IOMMU. */ + uint64_t u64BaseAddress; /**< Base address of IOMMU control registers in MMIO space. */ + uint16_t u16PciSegmentGroup; /**< PCI segment group number. */ + uint16_t u16IommuInfo; /**< Interrupt number and Unit ID. */ + uint32_t u32Features; /**< IOMMU feature reporting. */ + /* IVHD device entry block follows. */ +} ACPIIVHDTYPE10; +#pragma pack() +AssertCompileSize(ACPIIVHDTYPE10, 24); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u8Type, 0); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u8Flags, 1); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u16Length, 2); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u16DeviceId, 4); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u16CapOffset, 6); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u64BaseAddress, 8); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u16PciSegmentGroup, 16); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u16IommuInfo, 18); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u32Features, 20); + +/** @name IVHD Type 11h Flags. + * In accordance with the AMD spec. + * @{ */ +/** Coherent control. */ +#define ACPI_IVHD_11H_F_COHERENT RT_BIT(5) +/** Remote IOTLB support. */ +#define ACPI_IVHD_11H_F_IOTLB_SUP RT_BIT(4) +/** Isochronous control. */ +#define ACPI_IVHD_11H_F_ISOC RT_BIT(3) +/** Response Pass Posted Write. */ +#define ACPI_IVHD_11H_F_RES_PASS_PW RT_BIT(2) +/** Pass Posted Write. */ +#define ACPI_IVHD_11H_F_PASS_PW RT_BIT(1) +/** HyperTransport Tunnel. */ +#define ACPI_IVHD_11H_F_HT_TUNNEL RT_BIT(0) +/** @} */ + +/** @name IVHD IOMMU Type 11 Attributes field. + * In accordance with the AMD spec. + * @{ */ +/** Bits 12:0 reserved. */ +#define ACPI_IOMMU_ATTR_BF_RSVD_0_12_SHIFT 0 +#define ACPI_IOMMU_ATTR_BF_RSVD_0_12_MASK UINT32_C(0x00001fff) +/** PNCounters: Number of performance counters per counter bank. */ +#define ACPI_IOMMU_ATTR_BF_PN_COUNTERS_SHIFT 13 +#define ACPI_IOMMU_ATTR_BF_PN_COUNTERS_MASK UINT32_C(0x0001e000) +/** PNBanks: Number of performance counter banks. */ +#define ACPI_IOMMU_ATTR_BF_PN_BANKS_SHIFT 17 +#define ACPI_IOMMU_ATTR_BF_PN_BANKS_MASK UINT32_C(0x007e0000) +/** MSINumPPR: MSI number for peripheral page requests (PPR). */ +#define ACPI_IOMMU_ATTR_BF_MSI_NUM_PPR_SHIFT 23 +#define ACPI_IOMMU_ATTR_BF_MSI_NUM_PPR_MASK UINT32_C(0x0f800000) +/** Bits 31:28 reserved. */ +#define ACPI_IOMMU_ATTR_BF_RSVD_28_31_SHIFT 28 +#define ACPI_IOMMU_ATTR_BF_RSVD_28_31_MASK UINT32_C(0xf0000000) +RT_BF_ASSERT_COMPILE_CHECKS(ACPI_IOMMU_ATTR_BF_, UINT32_C(0), UINT32_MAX, + (RSVD_0_12, PN_COUNTERS, PN_BANKS, MSI_NUM_PPR, RSVD_28_31)); +/** @} */ + +/** + * AMD IOMMU: IVHD (I/O Virtualization Hardware Definition) Type 11h. + * In accordance with the AMD spec. + */ +#pragma pack(1) +typedef struct ACPIIVHDTYPE11 +{ + uint8_t u8Type; /**< Type: Must be 0x11. */ + uint8_t u8Flags; /**< Flags. */ + uint16_t u16Length; /**< Length: Size starting from Type fields incl. IVHD device entries. */ + uint16_t u16DeviceId; /**< Device ID of the IOMMU. */ + uint16_t u16CapOffset; /**< Offset in Capability space for control fields of IOMMU. */ + uint64_t u64BaseAddress; /**< Base address of IOMMU control registers in MMIO space. */ + uint16_t u16PciSegmentGroup; /**< PCI segment group number. */ + uint16_t u16IommuInfo; /**< Interrupt number and unit ID. */ + uint32_t u32IommuAttr; /**< IOMMU info. not reported in EFR. */ + uint64_t u64EfrRegister; /**< Extended Feature Register (must be identical to its MMIO shadow). */ + uint64_t u64Rsvd0; /**< Reserved for future. */ + /* IVHD device entry block follows. */ +} ACPIIVHDTYPE11; +#pragma pack() +AssertCompileSize(ACPIIVHDTYPE11, 40); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u8Type, 0); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u8Flags, 1); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u16Length, 2); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u16DeviceId, 4); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u16CapOffset, 6); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u64BaseAddress, 8); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u16PciSegmentGroup, 16); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u16IommuInfo, 18); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u32IommuAttr, 20); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u64EfrRegister, 24); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u64Rsvd0, 32); + +/** + * AMD IOMMU: IVHD (I/O Virtualization Hardware Definition) Type 40h. + * In accordance with the AMD spec. + */ +typedef struct ACPIIVHDTYPE11 ACPIIVHDTYPE40; + +#endif /* !VBOX_INCLUDED_iommu_amd_h */ diff --git a/include/VBox/iommu-intel.h b/include/VBox/iommu-intel.h new file mode 100644 index 00000000..cbf2121c --- /dev/null +++ b/include/VBox/iommu-intel.h @@ -0,0 +1,2915 @@ +/** @file + * IOMMU - Input/Output Memory Management Unit (Intel). + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_iommu_intel_h +#define VBOX_INCLUDED_iommu_intel_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assertcompile.h> +#include <iprt/types.h> + + +/** + * @name MMIO register offsets. + * In accordance with the Intel spec. + * @{ + */ +#define VTD_MMIO_OFF_VER_REG 0x000 /**< Version. */ +#define VTD_MMIO_OFF_CAP_REG 0x008 /**< Capability. */ +#define VTD_MMIO_OFF_ECAP_REG 0x010 /**< Extended Capability. */ +#define VTD_MMIO_OFF_GCMD_REG 0x018 /**< Global Command. */ +#define VTD_MMIO_OFF_GSTS_REG 0x01c /**< Global Status. */ +#define VTD_MMIO_OFF_RTADDR_REG 0x020 /**< Root Table Address. */ +#define VTD_MMIO_OFF_CCMD_REG 0x028 /**< Context Command. */ + +#define VTD_MMIO_OFF_FSTS_REG 0x034 /**< Fault Status.*/ +#define VTD_MMIO_OFF_FECTL_REG 0x038 /**< Fault Event Control.*/ +#define VTD_MMIO_OFF_FEDATA_REG 0x03c /**< Fault Event Data. */ +#define VTD_MMIO_OFF_FEADDR_REG 0x040 /**< Fault Event Address. */ +#define VTD_MMIO_OFF_FEUADDR_REG 0x044 /**< Fault Event Upper Address. */ + +#define VTD_MMIO_OFF_AFLOG_REG 0x058 /**< Advance Fault Log. */ + +#define VTD_MMIO_OFF_PMEN_REG 0x064 /**< Protected Memory Enable (PMEN). */ +#define VTD_MMIO_OFF_PLMBASE_REG 0x068 /**< Protected Low Memory Base. */ +#define VTD_MMIO_OFF_PLMLIMIT_REG 0x06c /**< Protected Low Memory Limit. */ +#define VTD_MMIO_OFF_PHMBASE_REG 0x070 /**< Protected High Memory Base. */ +#define VTD_MMIO_OFF_PHMLIMIT_REG 0x078 /**< Protected High Memory Limit. */ + +#define VTD_MMIO_OFF_IQH_REG 0x080 /**< Invalidation Queue Head. */ +#define VTD_MMIO_OFF_IQT_REG 0x088 /**< Invalidation Queue Tail. */ +#define VTD_MMIO_OFF_IQA_REG 0x090 /**< Invalidation Queue Address. */ +#define VTD_MMIO_OFF_ICS_REG 0x09c /**< Invalidation Completion Status. */ +#define VTD_MMIO_OFF_IECTL_REG 0x0a0 /**< Invalidation Completion Event Control. */ +#define VTD_MMIO_OFF_IEDATA_REG 0x0a4 /**< Invalidation Completion Event Data. */ +#define VTD_MMIO_OFF_IEADDR_REG 0x0a8 /**< Invalidation Completion Event Address. */ +#define VTD_MMIO_OFF_IEUADDR_REG 0x0ac /**< Invalidation Completion Event Upper Address. */ +#define VTD_MMIO_OFF_IQERCD_REG 0x0b0 /**< Invalidation Queue Error Record. */ + +#define VTD_MMIO_OFF_IRTA_REG 0x0b8 /**< Interrupt Remapping Table Address. */ + +#define VTD_MMIO_OFF_PQH_REG 0x0c0 /**< Page Request Queue Head. */ +#define VTD_MMIO_OFF_PQT_REG 0x0c8 /**< Page Request Queue Tail. */ +#define VTD_MMIO_OFF_PQA_REG 0x0d0 /**< Page Request Queue Address. */ +#define VTD_MMIO_OFF_PRS_REG 0x0dc /**< Page Request Status. */ +#define VTD_MMIO_OFF_PECTL_REG 0x0e0 /**< Page Request Event Control. */ +#define VTD_MMIO_OFF_PEDATA_REG 0x0e4 /**< Page Request Event Data. */ +#define VTD_MMIO_OFF_PEADDR_REG 0x0e8 /**< Page Request Event Address. */ +#define VTD_MMIO_OFF_PEUADDR_REG 0x0ec /**< Page Request Event Upper Address. */ + +#define VTD_MMIO_OFF_MTRRCAP_REG 0x100 /**< MTRR Capabliity. */ +#define VTD_MMIO_OFF_MTRRDEF_REG 0x108 /**< MTRR Default Type. */ + +#define VTD_MMIO_OFF_MTRR_FIX64_00000_REG 0x120 /**< Fixed-range MTRR Register for 64K at 00000. */ +#define VTD_MMIO_OFF_MTRR_FIX16K_80000_REG 0x128 /**< Fixed-range MTRR Register for 16K at 80000. */ +#define VTD_MMIO_OFF_MTRR_FIX16K_A0000_REG 0x130 /**< Fixed-range MTRR Register for 16K at a0000. */ +#define VTD_MMIO_OFF_MTRR_FIX4K_C0000_REG 0x138 /**< Fixed-range MTRR Register for 4K at c0000. */ +#define VTD_MMIO_OFF_MTRR_FIX4K_C8000_REG 0x140 /**< Fixed-range MTRR Register for 4K at c8000. */ +#define VTD_MMIO_OFF_MTRR_FIX4K_D0000_REG 0x148 /**< Fixed-range MTRR Register for 4K at d0000. */ +#define VTD_MMIO_OFF_MTRR_FIX4K_D8000_REG 0x150 /**< Fixed-range MTRR Register for 4K at d8000. */ +#define VTD_MMIO_OFF_MTRR_FIX4K_E0000_REG 0x158 /**< Fixed-range MTRR Register for 4K at e0000. */ +#define VTD_MMIO_OFF_MTRR_FIX4K_E8000_REG 0x160 /**< Fixed-range MTRR Register for 4K at e8000. */ +#define VTD_MMIO_OFF_MTRR_FIX4K_F0000_REG 0x168 /**< Fixed-range MTRR Register for 4K at f0000. */ +#define VTD_MMIO_OFF_MTRR_FIX4K_F8000_REG 0x170 /**< Fixed-range MTRR Register for 4K at f8000. */ + +#define VTD_MMIO_OFF_MTRR_PHYSBASE0_REG 0x180 /**< Variable-range MTRR Base 0. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK0_REG 0x188 /**< Variable-range MTRR Mask 0. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE1_REG 0x190 /**< Variable-range MTRR Base 1. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK1_REG 0x198 /**< Variable-range MTRR Mask 1. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE2_REG 0x1a0 /**< Variable-range MTRR Base 2. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK2_REG 0x1a8 /**< Variable-range MTRR Mask 2. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE3_REG 0x1b0 /**< Variable-range MTRR Base 3. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK3_REG 0x1b8 /**< Variable-range MTRR Mask 3. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE4_REG 0x1c0 /**< Variable-range MTRR Base 4. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK4_REG 0x1c8 /**< Variable-range MTRR Mask 4. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE5_REG 0x1d0 /**< Variable-range MTRR Base 5. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK5_REG 0x1d8 /**< Variable-range MTRR Mask 5. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE6_REG 0x1e0 /**< Variable-range MTRR Base 6. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK6_REG 0x1e8 /**< Variable-range MTRR Mask 6. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE7_REG 0x1f0 /**< Variable-range MTRR Base 7. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK7_REG 0x1f8 /**< Variable-range MTRR Mask 7. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE8_REG 0x200 /**< Variable-range MTRR Base 8. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK8_REG 0x208 /**< Variable-range MTRR Mask 8. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE9_REG 0x210 /**< Variable-range MTRR Base 9. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK9_REG 0x218 /**< Variable-range MTRR Mask 9. */ + +#define VTD_MMIO_OFF_VCCAP_REG 0xe00 /**< Virtual Command Capability. */ +#define VTD_MMIO_OFF_VCMD_REG 0xe10 /**< Virtual Command. */ +#define VTD_MMIO_OFF_VCMDRSVD_REG 0xe18 /**< Reserved for future for Virtual Command. */ +#define VTD_MMIO_OFF_VCRSP_REG 0xe20 /**< Virtual Command Response. */ +#define VTD_MMIO_OFF_VCRSPRSVD_REG 0xe28 /**< Reserved for future for Virtual Command Response. */ +/** @} */ + + +/** @name Root Entry. + * In accordance with the Intel spec. + * @{ */ +/** P: Present. */ +#define VTD_BF_0_ROOT_ENTRY_P_SHIFT 0 +#define VTD_BF_0_ROOT_ENTRY_P_MASK UINT64_C(0x0000000000000001) +/** R: Reserved (bits 11:1). */ +#define VTD_BF_0_ROOT_ENTRY_RSVD_11_1_SHIFT 1 +#define VTD_BF_0_ROOT_ENTRY_RSVD_11_1_MASK UINT64_C(0x0000000000000ffe) +/** CTP: Context-Table Pointer. */ +#define VTD_BF_0_ROOT_ENTRY_CTP_SHIFT 12 +#define VTD_BF_0_ROOT_ENTRY_CTP_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_ROOT_ENTRY_, UINT64_C(0), UINT64_MAX, + (P, RSVD_11_1, CTP)); + +/** Root Entry. */ +typedef struct VTD_ROOT_ENTRY_T +{ + /** The qwords in the root entry. */ + uint64_t au64[2]; +} VTD_ROOT_ENTRY_T; +/** Pointer to a root entry. */ +typedef VTD_ROOT_ENTRY_T *PVTD_ROOT_ENTRY_T; +/** Pointer to a const root entry. */ +typedef VTD_ROOT_ENTRY_T const *PCVTD_ROOT_ENTRY_T; + +/* Root Entry: Qword 0 valid mask. */ +#define VTD_ROOT_ENTRY_0_VALID_MASK (VTD_BF_0_ROOT_ENTRY_P_MASK | VTD_BF_0_ROOT_ENTRY_CTP_MASK) +/* Root Entry: Qword 1 valid mask. */ +#define VTD_ROOT_ENTRY_1_VALID_MASK UINT64_C(0) +/** @} */ + + +/** @name Scalable-mode Root Entry. + * In accordance with the Intel spec. + * @{ */ +/** LP: Lower Present. */ +#define VTD_BF_0_SM_ROOT_ENTRY_LP_SHIFT 0 +#define VTD_BF_0_SM_ROOT_ENTRY_LP_MASK UINT64_C(0x0000000000000001) +/** R: Reserved (bits 11:1). */ +#define VTD_BF_0_SM_ROOT_ENTRY_RSVD_11_1_SHIFT 1 +#define VTD_BF_0_SM_ROOT_ENTRY_RSVD_11_1_MASK UINT64_C(0x0000000000000ffe) +/** LCTP: Lower Context-Table Pointer */ +#define VTD_BF_0_SM_ROOT_ENTRY_LCTP_SHIFT 12 +#define VTD_BF_0_SM_ROOT_ENTRY_LCTP_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_SM_ROOT_ENTRY_, UINT64_C(0), UINT64_MAX, + (LP, RSVD_11_1, LCTP)); + +/** UP: Upper Present. */ +#define VTD_BF_1_SM_ROOT_ENTRY_UP_SHIFT 0 +#define VTD_BF_1_SM_ROOT_ENTRY_UP_MASK UINT64_C(0x0000000000000001) +/** R: Reserved (bits 11:1). */ +#define VTD_BF_1_SM_ROOT_ENTRY_RSVD_11_1_SHIFT 1 +#define VTD_BF_1_SM_ROOT_ENTRY_RSVD_11_1_MASK UINT64_C(0x0000000000000ffe) +/** UCTP: Upper Context-Table Pointer. */ +#define VTD_BF_1_SM_ROOT_ENTRY_UCTP_SHIFT 12 +#define VTD_BF_1_SM_ROOT_ENTRY_UCTP_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_SM_ROOT_ENTRY_, UINT64_C(0), UINT64_MAX, + (UP, RSVD_11_1, UCTP)); + +/** Scalable-mode root entry. */ +typedef struct VTD_SM_ROOT_ENTRY_T +{ + /** The lower scalable-mode root entry. */ + uint64_t uLower; + /** The upper scalable-mode root entry. */ + uint64_t uUpper; +} VTD_SM_ROOT_ENTRY_T; +/** Pointer to a scalable-mode root entry. */ +typedef VTD_SM_ROOT_ENTRY_T *PVTD_SM_ROOT_ENTRY_T; +/** Pointer to a const scalable-mode root entry. */ +typedef VTD_SM_ROOT_ENTRY_T const *PCVTD_SM_ROOT_ENTRY_T; +/** @} */ + + +/** @name Context Entry. + * In accordance with the Intel spec. + * @{ */ +/** P: Present. */ +#define VTD_BF_0_CONTEXT_ENTRY_P_SHIFT 0 +#define VTD_BF_0_CONTEXT_ENTRY_P_MASK UINT64_C(0x0000000000000001) +/** FPD: Fault Processing Disable. */ +#define VTD_BF_0_CONTEXT_ENTRY_FPD_SHIFT 1 +#define VTD_BF_0_CONTEXT_ENTRY_FPD_MASK UINT64_C(0x0000000000000002) +/** TT: Translation Type. */ +#define VTD_BF_0_CONTEXT_ENTRY_TT_SHIFT 2 +#define VTD_BF_0_CONTEXT_ENTRY_TT_MASK UINT64_C(0x000000000000000c) +/** R: Reserved (bits 11:4). */ +#define VTD_BF_0_CONTEXT_ENTRY_RSVD_11_4_SHIFT 4 +#define VTD_BF_0_CONTEXT_ENTRY_RSVD_11_4_MASK UINT64_C(0x0000000000000ff0) +/** SLPTPTR: Second Level Page Translation Pointer. */ +#define VTD_BF_0_CONTEXT_ENTRY_SLPTPTR_SHIFT 12 +#define VTD_BF_0_CONTEXT_ENTRY_SLPTPTR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_CONTEXT_ENTRY_, UINT64_C(0), UINT64_MAX, + (P, FPD, TT, RSVD_11_4, SLPTPTR)); + +/** AW: Address Width. */ +#define VTD_BF_1_CONTEXT_ENTRY_AW_SHIFT 0 +#define VTD_BF_1_CONTEXT_ENTRY_AW_MASK UINT64_C(0x0000000000000007) +/** IGN: Ignored (bits 6:3). */ +#define VTD_BF_1_CONTEXT_ENTRY_IGN_6_3_SHIFT 3 +#define VTD_BF_1_CONTEXT_ENTRY_IGN_6_3_MASK UINT64_C(0x0000000000000078) +/** R: Reserved (bit 7). */ +#define VTD_BF_1_CONTEXT_ENTRY_RSVD_7_SHIFT 7 +#define VTD_BF_1_CONTEXT_ENTRY_RSVD_7_MASK UINT64_C(0x0000000000000080) +/** DID: Domain Identifier. */ +#define VTD_BF_1_CONTEXT_ENTRY_DID_SHIFT 8 +#define VTD_BF_1_CONTEXT_ENTRY_DID_MASK UINT64_C(0x0000000000ffff00) +/** R: Reserved (bits 63:24). */ +#define VTD_BF_1_CONTEXT_ENTRY_RSVD_63_24_SHIFT 24 +#define VTD_BF_1_CONTEXT_ENTRY_RSVD_63_24_MASK UINT64_C(0xffffffffff000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_CONTEXT_ENTRY_, UINT64_C(0), UINT64_MAX, + (AW, IGN_6_3, RSVD_7, DID, RSVD_63_24)); + +/** Context Entry. */ +typedef struct VTD_CONTEXT_ENTRY_T +{ + /** The qwords in the context entry. */ + uint64_t au64[2]; +} VTD_CONTEXT_ENTRY_T; +/** Pointer to a context entry. */ +typedef VTD_CONTEXT_ENTRY_T *PVTD_CONTEXT_ENTRY_T; +/** Pointer to a const context entry. */ +typedef VTD_CONTEXT_ENTRY_T const *PCVTD_CONTEXT_ENTRY_T; +AssertCompileSize(VTD_CONTEXT_ENTRY_T, 16); + +/** Context Entry: Qword 0 valid mask. */ +#define VTD_CONTEXT_ENTRY_0_VALID_MASK ( VTD_BF_0_CONTEXT_ENTRY_P_MASK \ + | VTD_BF_0_CONTEXT_ENTRY_FPD_MASK \ + | VTD_BF_0_CONTEXT_ENTRY_TT_MASK \ + | VTD_BF_0_CONTEXT_ENTRY_SLPTPTR_MASK) +/** Context Entry: Qword 1 valid mask. */ +#define VTD_CONTEXT_ENTRY_1_VALID_MASK ( VTD_BF_1_CONTEXT_ENTRY_AW_MASK \ + | VTD_BF_1_CONTEXT_ENTRY_IGN_6_3_MASK \ + | VTD_BF_1_CONTEXT_ENTRY_DID_MASK) + +/** Translation Type: Untranslated requests uses second-level paging. */ +#define VTD_TT_UNTRANSLATED_SLP 0 +/** Translation Type: Untranslated requests requires device-TLB support. */ +#define VTD_TT_UNTRANSLATED_DEV_TLB 1 +/** Translation Type: Untranslated requests are pass-through. */ +#define VTD_TT_UNTRANSLATED_PT 2 +/** Translation Type: Reserved. */ +#define VTD_TT_RSVD 3 +/** @} */ + + +/** @name Scalable-mode Context Entry. + * In accordance with the Intel spec. + * @{ */ +/** P: Present. */ +#define VTD_BF_0_SM_CONTEXT_ENTRY_P_SHIFT 0 +#define VTD_BF_0_SM_CONTEXT_ENTRY_P_MASK UINT64_C(0x0000000000000001) +/** FPD: Fault Processing Disable. */ +#define VTD_BF_0_SM_CONTEXT_ENTRY_FPD_SHIFT 1 +#define VTD_BF_0_SM_CONTEXT_ENTRY_FPD_MASK UINT64_C(0x0000000000000002) +/** DTE: Device-TLB Enable. */ +#define VTD_BF_0_SM_CONTEXT_ENTRY_DTE_SHIFT 2 +#define VTD_BF_0_SM_CONTEXT_ENTRY_DTE_MASK UINT64_C(0x0000000000000004) +/** PASIDE: PASID Enable. */ +#define VTD_BF_0_SM_CONTEXT_ENTRY_PASIDE_SHIFT 3 +#define VTD_BF_0_SM_CONTEXT_ENTRY_PASIDE_MASK UINT64_C(0x0000000000000008) +/** PRE: Page Request Enable. */ +#define VTD_BF_0_SM_CONTEXT_ENTRY_PRE_SHIFT 4 +#define VTD_BF_0_SM_CONTEXT_ENTRY_PRE_MASK UINT64_C(0x0000000000000010) +/** R: Reserved (bits 8:5). */ +#define VTD_BF_0_SM_CONTEXT_ENTRY_RSVD_8_5_SHIFT 5 +#define VTD_BF_0_SM_CONTEXT_ENTRY_RSVD_8_5_MASK UINT64_C(0x00000000000001e0) +/** PDTS: PASID Directory Size. */ +#define VTD_BF_0_SM_CONTEXT_ENTRY_PDTS_SHIFT 9 +#define VTD_BF_0_SM_CONTEXT_ENTRY_PDTS_MASK UINT64_C(0x0000000000000e00) +/** PASIDDIRPTR: PASID Directory Pointer. */ +#define VTD_BF_0_SM_CONTEXT_ENTRY_PASIDDIRPTR_SHIFT 12 +#define VTD_BF_0_SM_CONTEXT_ENTRY_PASIDDIRPTR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_SM_CONTEXT_ENTRY_, UINT64_C(0), UINT64_MAX, + (P, FPD, DTE, PASIDE, PRE, RSVD_8_5, PDTS, PASIDDIRPTR)); + +/** RID_PASID: Requested Id to PASID assignment. */ +#define VTD_BF_1_SM_CONTEXT_ENTRY_RID_PASID_SHIFT 0 +#define VTD_BF_1_SM_CONTEXT_ENTRY_RID_PASID_MASK UINT64_C(0x00000000000fffff) +/** RID_PRIV: Requested Id to PrivilegeModeRequested assignment. */ +#define VTD_BF_1_SM_CONTEXT_ENTRY_RID_PRIV_SHIFT 20 +#define VTD_BF_1_SM_CONTEXT_ENTRY_RID_PRIV_MASK UINT64_C(0x0000000000100000) +/** R: Reserved (bits 63:21). */ +#define VTD_BF_1_SM_CONTEXT_ENTRY_RSVD_63_21_SHIFT 21 +#define VTD_BF_1_SM_CONTEXT_ENTRY_RSVD_63_21_MASK UINT64_C(0xffffffffffe00000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_SM_CONTEXT_ENTRY_, UINT64_C(0), UINT64_MAX, + (RID_PASID, RID_PRIV, RSVD_63_21)); + +/** Scalable-mode Context Entry. */ +typedef struct VTD_SM_CONTEXT_ENTRY_T +{ + /** The qwords in the scalable-mode context entry. */ + uint64_t au64[4]; +} VTD_SM_CONTEXT_ENTRY_T; +/** Pointer to a scalable-mode context entry. */ +typedef VTD_SM_CONTEXT_ENTRY_T *PVTD_SM_CONTEXT_ENTRY_T; +/** Pointer to a const scalable-mode context entry. */ +typedef VTD_SM_CONTEXT_ENTRY_T const *PCVTD_SM_CONTEXT_ENTRY_T; +/** @} */ + + +/** @name Scalable-mode PASID Directory Entry. + * In accordance with the Intel spec. + * @{ */ +/** P: Present. */ +#define VTD_BF_SM_PASID_DIR_ENTRY_P_SHIFT 0 +#define VTD_BF_SM_PASID_DIR_ENTRY_P_MASK UINT64_C(0x0000000000000001) +/** FPD: Fault Processing Disable. */ +#define VTD_BF_SM_PASID_DIR_ENTRY_FPD_SHIFT 1 +#define VTD_BF_SM_PASID_DIR_ENTRY_FPD_MASK UINT64_C(0x0000000000000002) +/** R: Reserved (bits 11:2). */ +#define VTD_BF_SM_PASID_DIR_ENTRY_RSVD_11_2_SHIFT 2 +#define VTD_BF_SM_PASID_DIR_ENTRY_RSVD_11_2_MASK UINT64_C(0x0000000000000ffc) +/** SMPTBLPTR: Scalable Mode PASID Table Pointer. */ +#define VTD_BF_SM_PASID_DIR_ENTRY_SMPTBLPTR_SHIFT 12 +#define VTD_BF_SM_PASID_DIR_ENTRY_SMPTBLPTR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_SM_PASID_DIR_ENTRY_, UINT64_C(0), UINT64_MAX, + (P, FPD, RSVD_11_2, SMPTBLPTR)); + +/** Scalable-mode PASID Directory Entry. */ +typedef struct VTD_SM_PASID_DIR_ENTRY_T +{ + /** The scalable-mode PASID directory entry. */ + uint64_t u; +} VTD_SM_PASID_DIR_ENTRY_T; +/** Pointer to a scalable-mode PASID directory entry. */ +typedef VTD_SM_PASID_DIR_ENTRY_T *PVTD_SM_PASID_DIR_ENTRY_T; +/** Pointer to a const scalable-mode PASID directory entry. */ +typedef VTD_SM_PASID_DIR_ENTRY_T const *PCVTD_SM_PASID_DIR_ENTRY_T; +/** @} */ + + +/** @name Scalable-mode PASID Table Entry. + * In accordance with the Intel spec. + * @{ */ +/** P: Present. */ +#define VTD_BF_0_SM_PASID_TBL_ENTRY_P_SHIFT 0 +#define VTD_BF_0_SM_PASID_TBL_ENTRY_P_MASK UINT64_C(0x0000000000000001) +/** FPD: Fault Processing Disable. */ +#define VTD_BF_0_SM_PASID_TBL_ENTRY_FPD_SHIFT 1 +#define VTD_BF_0_SM_PASID_TBL_ENTRY_FPD_MASK UINT64_C(0x0000000000000002) +/** AW: Address Width. */ +#define VTD_BF_0_SM_PASID_TBL_ENTRY_AW_SHIFT 2 +#define VTD_BF_0_SM_PASID_TBL_ENTRY_AW_MASK UINT64_C(0x000000000000001c) +/** SLEE: Second-Level Execute Enable. */ +#define VTD_BF_0_SM_PASID_TBL_ENTRY_SLEE_SHIFT 5 +#define VTD_BF_0_SM_PASID_TBL_ENTRY_SLEE_MASK UINT64_C(0x0000000000000020) +/** PGTT: PASID Granular Translation Type. */ +#define VTD_BF_0_SM_PASID_TBL_ENTRY_PGTT_SHIFT 6 +#define VTD_BF_0_SM_PASID_TBL_ENTRY_PGTT_MASK UINT64_C(0x00000000000001c0) +/** SLADE: Second-Level Address/Dirty Enable. */ +#define VTD_BF_0_SM_PASID_TBL_ENTRY_SLADE_SHIFT 9 +#define VTD_BF_0_SM_PASID_TBL_ENTRY_SLADE_MASK UINT64_C(0x0000000000000200) +/** R: Reserved (bits 11:10). */ +#define VTD_BF_0_SM_PASID_TBL_ENTRY_RSVD_11_10_SHIFT 10 +#define VTD_BF_0_SM_PASID_TBL_ENTRY_RSVD_11_10_MASK UINT64_C(0x0000000000000c00) +/** SLPTPTR: Second-Level Page Table Pointer. */ +#define VTD_BF_0_SM_PASID_TBL_ENTRY_SLPTPTR_SHIFT 12 +#define VTD_BF_0_SM_PASID_TBL_ENTRY_SLPTPTR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_SM_PASID_TBL_ENTRY_, UINT64_C(0), UINT64_MAX, + (P, FPD, AW, SLEE, PGTT, SLADE, RSVD_11_10, SLPTPTR)); + +/** DID: Domain Identifer. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_DID_SHIFT 0 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_DID_MASK UINT64_C(0x000000000000ffff) +/** R: Reserved (bits 22:16). */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_RSVD_22_16_SHIFT 16 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_RSVD_22_16_MASK UINT64_C(0x00000000007f0000) +/** PWSNP: Page-Walk Snoop. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PWSNP_SHIFT 23 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PWSNP_MASK UINT64_C(0x0000000000800000) +/** PGSNP: Page Snoop. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PGSNP_SHIFT 24 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PGSNP_MASK UINT64_C(0x0000000001000000) +/** CD: Cache Disable. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_CD_SHIFT 25 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_CD_MASK UINT64_C(0x0000000002000000) +/** EMTE: Extended Memory Type Enable. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_EMTE_SHIFT 26 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_EMTE_MASK UINT64_C(0x0000000004000000) +/** EMT: Extended Memory Type. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_EMT_SHIFT 27 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_EMT_MASK UINT64_C(0x0000000038000000) +/** PWT: Page-Level Write Through. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PWT_SHIFT 30 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PWT_MASK UINT64_C(0x0000000040000000) +/** PCD: Page-Level Cache Disable. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PCD_SHIFT 31 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PCD_MASK UINT64_C(0x0000000080000000) +/** PAT: Page Attribute Table. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PAT_SHIFT 32 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PAT_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_SM_PASID_TBL_ENTRY_, UINT64_C(0), UINT64_MAX, + (DID, RSVD_22_16, PWSNP, PGSNP, CD, EMTE, EMT, PWT, PCD, PAT)); + +/** SRE: Supervisor Request Enable. */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_SRE_SHIFT 0 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_SRE_MASK UINT64_C(0x0000000000000001) +/** ERE: Execute Request Enable. */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_ERE_SHIFT 1 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_ERE_MASK UINT64_C(0x0000000000000002) +/** FLPM: First Level Paging Mode. */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_FLPM_SHIFT 2 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_FLPM_MASK UINT64_C(0x000000000000000c) +/** WPE: Write Protect Enable. */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_WPE_SHIFT 4 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_WPE_MASK UINT64_C(0x0000000000000010) +/** NXE: No-Execute Enable. */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_NXE_SHIFT 5 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_NXE_MASK UINT64_C(0x0000000000000020) +/** SMEP: Supervisor Mode Execute Prevent. */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_SMPE_SHIFT 6 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_SMPE_MASK UINT64_C(0x0000000000000040) +/** EAFE: Extended Accessed Flag Enable. */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_EAFE_SHIFT 7 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_EAFE_MASK UINT64_C(0x0000000000000080) +/** R: Reserved (bits 11:8). */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_RSVD_11_8_SHIFT 8 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_RSVD_11_8_MASK UINT64_C(0x0000000000000f00) +/** FLPTPTR: First Level Page Table Pointer. */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_FLPTPTR_SHIFT 12 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_FLPTPTR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_2_SM_PASID_TBL_ENTRY_, UINT64_C(0), UINT64_MAX, + (SRE, ERE, FLPM, WPE, NXE, SMPE, EAFE, RSVD_11_8, FLPTPTR)); + +/** Scalable-mode PASID Table Entry. */ +typedef struct VTD_SM_PASID_TBL_ENTRY_T +{ + /** The qwords in the scalable-mode PASID table entry. */ + uint64_t au64[8]; +} VTD_SM_PASID_TBL_ENTRY_T; +/** Pointer to a scalable-mode PASID table entry. */ +typedef VTD_SM_PASID_TBL_ENTRY_T *PVTD_SM_PASID_TBL_ENTRY_T; +/** Pointer to a const scalable-mode PASID table entry. */ +typedef VTD_SM_PASID_TBL_ENTRY_T const *PCVTD_SM_PASID_TBL_ENTRY_T; +/** @} */ + + +/** @name First-Level Paging Entry. + * In accordance with the Intel spec. + * @{ */ +/** P: Present. */ +#define VTD_BF_FLP_ENTRY_P_SHIFT 0 +#define VTD_BF_FLP_ENTRY_P_MASK UINT64_C(0x0000000000000001) +/** R/W: Read/Write. */ +#define VTD_BF_FLP_ENTRY_RW_SHIFT 1 +#define VTD_BF_FLP_ENTRY_RW_MASK UINT64_C(0x0000000000000002) +/** U/S: User/Supervisor. */ +#define VTD_BF_FLP_ENTRY_US_SHIFT 2 +#define VTD_BF_FLP_ENTRY_US_MASK UINT64_C(0x0000000000000004) +/** PWT: Page-Level Write Through. */ +#define VTD_BF_FLP_ENTRY_PWT_SHIFT 3 +#define VTD_BF_FLP_ENTRY_PWT_MASK UINT64_C(0x0000000000000008) +/** PC: Page-Level Cache Disable. */ +#define VTD_BF_FLP_ENTRY_PCD_SHIFT 4 +#define VTD_BF_FLP_ENTRY_PCD_MASK UINT64_C(0x0000000000000010) +/** A: Accessed. */ +#define VTD_BF_FLP_ENTRY_A_SHIFT 5 +#define VTD_BF_FLP_ENTRY_A_MASK UINT64_C(0x0000000000000020) +/** IGN: Ignored (bit 6). */ +#define VTD_BF_FLP_ENTRY_IGN_6_SHIFT 6 +#define VTD_BF_FLP_ENTRY_IGN_6_MASK UINT64_C(0x0000000000000040) +/** R: Reserved (bit 7). */ +#define VTD_BF_FLP_ENTRY_RSVD_7_SHIFT 7 +#define VTD_BF_FLP_ENTRY_RSVD_7_MASK UINT64_C(0x0000000000000080) +/** IGN: Ignored (bits 9:8). */ +#define VTD_BF_FLP_ENTRY_IGN_9_8_SHIFT 8 +#define VTD_BF_FLP_ENTRY_IGN_9_8_MASK UINT64_C(0x0000000000000300) +/** EA: Extended Accessed. */ +#define VTD_BF_FLP_ENTRY_EA_SHIFT 10 +#define VTD_BF_FLP_ENTRY_EA_MASK UINT64_C(0x0000000000000400) +/** IGN: Ignored (bit 11). */ +#define VTD_BF_FLP_ENTRY_IGN_11_SHIFT 11 +#define VTD_BF_FLP_ENTRY_IGN_11_MASK UINT64_C(0x0000000000000800) +/** ADDR: Address. */ +#define VTD_BF_FLP_ENTRY_ADDR_SHIFT 12 +#define VTD_BF_FLP_ENTRY_ADDR_MASK UINT64_C(0x000ffffffffff000) +/** IGN: Ignored (bits 62:52). */ +#define VTD_BF_FLP_ENTRY_IGN_62_52_SHIFT 52 +#define VTD_BF_FLP_ENTRY_IGN_62_52_MASK UINT64_C(0x7ff0000000000000) +/** XD: Execute Disabled. */ +#define VTD_BF_FLP_ENTRY_XD_SHIFT 63 +#define VTD_BF_FLP_ENTRY_XD_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_FLP_ENTRY_, UINT64_C(0), UINT64_MAX, + (P, RW, US, PWT, PCD, A, IGN_6, RSVD_7, IGN_9_8, EA, IGN_11, ADDR, IGN_62_52, XD)); +/** @} */ + + +/** @name Second-Level PML5E. + * In accordance with the Intel spec. + * @{ */ +/** R: Read. */ +#define VTD_BF_SL_PML5E_R_SHIFT 0 +#define VTD_BF_SL_PML5E_R_MASK UINT64_C(0x0000000000000001) +/** W: Write. */ +#define VTD_BF_SL_PML5E_W_SHIFT 1 +#define VTD_BF_SL_PML5E_W_MASK UINT64_C(0x0000000000000002) +/** X: Execute. */ +#define VTD_BF_SL_PML5E_X_SHIFT 2 +#define VTD_BF_SL_PML5E_X_MASK UINT64_C(0x0000000000000004) +/** IGN: Ignored (bits 6:3). */ +#define VTD_BF_SL_PML5E_IGN_6_3_SHIFT 3 +#define VTD_BF_SL_PML5E_IGN_6_3_MASK UINT64_C(0x0000000000000078) +/** R: Reserved (bit 7). */ +#define VTD_BF_SL_PML5E_RSVD_7_SHIFT 7 +#define VTD_BF_SL_PML5E_RSVD_7_MASK UINT64_C(0x0000000000000080) +/** A: Accessed. */ +#define VTD_BF_SL_PML5E_A_SHIFT 8 +#define VTD_BF_SL_PML5E_A_MASK UINT64_C(0x0000000000000100) +/** IGN: Ignored (bits 10:9). */ +#define VTD_BF_SL_PML5E_IGN_10_9_SHIFT 9 +#define VTD_BF_SL_PML5E_IGN_10_9_MASK UINT64_C(0x0000000000000600) +/** R: Reserved (bit 11). */ +#define VTD_BF_SL_PML5E_RSVD_11_SHIFT 11 +#define VTD_BF_SL_PML5E_RSVD_11_MASK UINT64_C(0x0000000000000800) +/** ADDR: Address. */ +#define VTD_BF_SL_PML5E_ADDR_SHIFT 12 +#define VTD_BF_SL_PML5E_ADDR_MASK UINT64_C(0x000ffffffffff000) +/** IGN: Ignored (bits 61:52). */ +#define VTD_BF_SL_PML5E_IGN_61_52_SHIFT 52 +#define VTD_BF_SL_PML5E_IGN_61_52_MASK UINT64_C(0x3ff0000000000000) +/** R: Reserved (bit 62). */ +#define VTD_BF_SL_PML5E_RSVD_62_SHIFT 62 +#define VTD_BF_SL_PML5E_RSVD_62_MASK UINT64_C(0x4000000000000000) +/** IGN: Ignored (bit 63). */ +#define VTD_BF_SL_PML5E_IGN_63_SHIFT 63 +#define VTD_BF_SL_PML5E_IGN_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_SL_PML5E_, UINT64_C(0), UINT64_MAX, + (R, W, X, IGN_6_3, RSVD_7, A, IGN_10_9, RSVD_11, ADDR, IGN_61_52, RSVD_62, IGN_63)); + +/** Second-level PML5E valid mask. */ +#define VTD_SL_PML5E_VALID_MASK ( VTD_BF_SL_PML5E_R_MASK | VTD_BF_SL_PML5E_W_MASK \ + | VTD_BF_SL_PML5E_X_MASK | VTD_BF_SL_PML5E_IGN_6_3_MASK \ + | VTD_BF_SL_PML5E_A_MASK | VTD_BF_SL_PML5E_IGN_10_9_MASK \ + | VTD_BF_SL_PML5E_ADDR_MASK | VTD_BF_SL_PML5E_IGN_61_52_MASK \ + | VTD_BF_SL_PML5E_IGN_63_MASK) +/** @} */ + + +/** @name Second-Level PML4E. + * In accordance with the Intel spec. + * @{ */ +/** R: Read. */ +#define VTD_BF_SL_PML4E_R_SHIFT 0 +#define VTD_BF_SL_PML4E_R_MASK UINT64_C(0x0000000000000001) +/** W: Write. */ +#define VTD_BF_SL_PML4E_W_SHIFT 1 +#define VTD_BF_SL_PML4E_W_MASK UINT64_C(0x0000000000000002) +/** X: Execute. */ +#define VTD_BF_SL_PML4E_X_SHIFT 2 +#define VTD_BF_SL_PML4E_X_MASK UINT64_C(0x0000000000000004) +/** IGN: Ignored (bits 6:3). */ +#define VTD_BF_SL_PML4E_IGN_6_3_SHIFT 3 +#define VTD_BF_SL_PML4E_IGN_6_3_MASK UINT64_C(0x0000000000000078) +/** R: Reserved (bit 7). */ +#define VTD_BF_SL_PML4E_RSVD_7_SHIFT 7 +#define VTD_BF_SL_PML4E_RSVD_7_MASK UINT64_C(0x0000000000000080) +/** A: Accessed. */ +#define VTD_BF_SL_PML4E_A_SHIFT 8 +#define VTD_BF_SL_PML4E_A_MASK UINT64_C(0x0000000000000100) +/** IGN: Ignored (bits 10:9). */ +#define VTD_BF_SL_PML4E_IGN_10_9_SHIFT 9 +#define VTD_BF_SL_PML4E_IGN_10_9_MASK UINT64_C(0x0000000000000600) +/** R: Reserved (bit 11). */ +#define VTD_BF_SL_PML4E_RSVD_11_SHIFT 11 +#define VTD_BF_SL_PML4E_RSVD_11_MASK UINT64_C(0x0000000000000800) +/** ADDR: Address. */ +#define VTD_BF_SL_PML4E_ADDR_SHIFT 12 +#define VTD_BF_SL_PML4E_ADDR_MASK UINT64_C(0x000ffffffffff000) +/** IGN: Ignored (bits 61:52). */ +#define VTD_BF_SL_PML4E_IGN_61_52_SHIFT 52 +#define VTD_BF_SL_PML4E_IGN_61_52_MASK UINT64_C(0x3ff0000000000000) +/** R: Reserved (bit 62). */ +#define VTD_BF_SL_PML4E_RSVD_62_SHIFT 62 +#define VTD_BF_SL_PML4E_RSVD_62_MASK UINT64_C(0x4000000000000000) +/** IGN: Ignored (bit 63). */ +#define VTD_BF_SL_PML4E_IGN_63_SHIFT 63 +#define VTD_BF_SL_PML4E_IGN_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_SL_PML4E_, UINT64_C(0), UINT64_MAX, + (R, W, X, IGN_6_3, RSVD_7, A, IGN_10_9, RSVD_11, ADDR, IGN_61_52, RSVD_62, IGN_63)); + +/** Second-level PML4E valid mask. */ +#define VTD_SL_PML4E_VALID_MASK VTD_SL_PML5E_VALID_MASK +/** @} */ + + +/** @name Second-Level PDPE (1GB Page). + * In accordance with the Intel spec. + * @{ */ +/** R: Read. */ +#define VTD_BF_SL_PDPE1G_R_SHIFT 0 +#define VTD_BF_SL_PDPE1G_R_MASK UINT64_C(0x0000000000000001) +/** W: Write. */ +#define VTD_BF_SL_PDPE1G_W_SHIFT 1 +#define VTD_BF_SL_PDPE1G_W_MASK UINT64_C(0x0000000000000002) +/** X: Execute. */ +#define VTD_BF_SL_PDPE1G_X_SHIFT 2 +#define VTD_BF_SL_PDPE1G_X_MASK UINT64_C(0x0000000000000004) +/** EMT: Extended Memory Type. */ +#define VTD_BF_SL_PDPE1G_EMT_SHIFT 3 +#define VTD_BF_SL_PDPE1G_EMT_MASK UINT64_C(0x0000000000000038) +/** IPAT: Ignore PAT (Page Attribute Table). */ +#define VTD_BF_SL_PDPE1G_IPAT_SHIFT 6 +#define VTD_BF_SL_PDPE1G_IPAT_MASK UINT64_C(0x0000000000000040) +/** PS: Page Size (MB1). */ +#define VTD_BF_SL_PDPE1G_PS_SHIFT 7 +#define VTD_BF_SL_PDPE1G_PS_MASK UINT64_C(0x0000000000000080) +/** A: Accessed. */ +#define VTD_BF_SL_PDPE1G_A_SHIFT 8 +#define VTD_BF_SL_PDPE1G_A_MASK UINT64_C(0x0000000000000100) +/** D: Dirty. */ +#define VTD_BF_SL_PDPE1G_D_SHIFT 9 +#define VTD_BF_SL_PDPE1G_D_MASK UINT64_C(0x0000000000000200) +/** IGN: Ignored (bit 10). */ +#define VTD_BF_SL_PDPE1G_IGN_10_SHIFT 10 +#define VTD_BF_SL_PDPE1G_IGN_10_MASK UINT64_C(0x0000000000000400) +/** R: Reserved (bit 11). */ +#define VTD_BF_SL_PDPE1G_RSVD_11_SHIFT 11 +#define VTD_BF_SL_PDPE1G_RSVD_11_MASK UINT64_C(0x0000000000000800) +/** R: Reserved (bits 29:12). */ +#define VTD_BF_SL_PDPE1G_RSVD_29_12_SHIFT 12 +#define VTD_BF_SL_PDPE1G_RSVD_29_12_MASK UINT64_C(0x000000003ffff000) +/** ADDR: Address of 1GB page. */ +#define VTD_BF_SL_PDPE1G_ADDR_SHIFT 30 +#define VTD_BF_SL_PDPE1G_ADDR_MASK UINT64_C(0x000fffffc0000000) +/** IGN: Ignored (bits 61:52). */ +#define VTD_BF_SL_PDPE1G_IGN_61_52_SHIFT 52 +#define VTD_BF_SL_PDPE1G_IGN_61_52_MASK UINT64_C(0x3ff0000000000000) +/** R: Reserved (bit 62). */ +#define VTD_BF_SL_PDPE1G_RSVD_62_SHIFT 62 +#define VTD_BF_SL_PDPE1G_RSVD_62_MASK UINT64_C(0x4000000000000000) +/** IGN: Ignored (bit 63). */ +#define VTD_BF_SL_PDPE1G_IGN_63_SHIFT 63 +#define VTD_BF_SL_PDPE1G_IGN_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_SL_PDPE1G_, UINT64_C(0), UINT64_MAX, + (R, W, X, EMT, IPAT, PS, A, D, IGN_10, RSVD_11, RSVD_29_12, ADDR, IGN_61_52, RSVD_62, IGN_63)); + +/** Second-level PDPE (1GB Page) valid mask. */ +#define VTD_SL_PDPE1G_VALID_MASK ( VTD_BF_SL_PDPE1G_R_MASK | VTD_BF_SL_PDPE1G_W_MASK \ + | VTD_BF_SL_PDPE1G_X_MASK | VTD_BF_SL_PDPE1G_EMT_MASK \ + | VTD_BF_SL_PDPE1G_IPAT_MASK | VTD_BF_SL_PDPE1G_PS_MASK \ + | VTD_BF_SL_PDPE1G_A_MASK | VTD_BF_SL_PDPE1G_D_MASK \ + | VTD_BF_SL_PDPE1G_IGN_10_MASK | VTD_BF_SL_PDPE1G_ADDR_MASK \ + | VTD_BF_SL_PDPE1G_IGN_61_52_MASK | VTD_BF_SL_PDPE1G_IGN_63_MASK) +/** @} */ + + +/** @name Second-Level PDPE. + * In accordance with the Intel spec. + * @{ */ +/** R: Read. */ +#define VTD_BF_SL_PDPE_R_SHIFT 0 +#define VTD_BF_SL_PDPE_R_MASK UINT64_C(0x0000000000000001) +/** W: Write. */ +#define VTD_BF_SL_PDPE_W_SHIFT 1 +#define VTD_BF_SL_PDPE_W_MASK UINT64_C(0x0000000000000002) +/** X: Execute. */ +#define VTD_BF_SL_PDPE_X_SHIFT 2 +#define VTD_BF_SL_PDPE_X_MASK UINT64_C(0x0000000000000004) +/** IGN: Ignored (bits 6:3). */ +#define VTD_BF_SL_PDPE_IGN_6_3_SHIFT 3 +#define VTD_BF_SL_PDPE_IGN_6_3_MASK UINT64_C(0x0000000000000078) +/** PS: Page Size (MBZ). */ +#define VTD_BF_SL_PDPE_PS_SHIFT 7 +#define VTD_BF_SL_PDPE_PS_MASK UINT64_C(0x0000000000000080) +/** A: Accessed. */ +#define VTD_BF_SL_PDPE_A_SHIFT 8 +#define VTD_BF_SL_PDPE_A_MASK UINT64_C(0x0000000000000100) +/** IGN: Ignored (bits 10:9). */ +#define VTD_BF_SL_PDPE_IGN_10_9_SHIFT 9 +#define VTD_BF_SL_PDPE_IGN_10_9_MASK UINT64_C(0x0000000000000600) +/** R: Reserved (bit 11). */ +#define VTD_BF_SL_PDPE_RSVD_11_SHIFT 11 +#define VTD_BF_SL_PDPE_RSVD_11_MASK UINT64_C(0x0000000000000800) +/** ADDR: Address of second-level PDT. */ +#define VTD_BF_SL_PDPE_ADDR_SHIFT 12 +#define VTD_BF_SL_PDPE_ADDR_MASK UINT64_C(0x000ffffffffff000) +/** IGN: Ignored (bits 61:52). */ +#define VTD_BF_SL_PDPE_IGN_61_52_SHIFT 52 +#define VTD_BF_SL_PDPE_IGN_61_52_MASK UINT64_C(0x3ff0000000000000) +/** R: Reserved (bit 62). */ +#define VTD_BF_SL_PDPE_RSVD_62_SHIFT 62 +#define VTD_BF_SL_PDPE_RSVD_62_MASK UINT64_C(0x4000000000000000) +/** IGN: Ignored (bit 63). */ +#define VTD_BF_SL_PDPE_IGN_63_SHIFT 63 +#define VTD_BF_SL_PDPE_IGN_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_SL_PDPE_, UINT64_C(0), UINT64_MAX, + (R, W, X, IGN_6_3, PS, A, IGN_10_9, RSVD_11, ADDR, IGN_61_52, RSVD_62, IGN_63)); + +/** Second-level PDPE valid mask. */ +#define VTD_SL_PDPE_VALID_MASK ( VTD_BF_SL_PDPE_R_MASK | VTD_BF_SL_PDPE_W_MASK \ + | VTD_BF_SL_PDPE_X_MASK | VTD_BF_SL_PDPE_IGN_6_3_MASK \ + | VTD_BF_SL_PDPE_PS_MASK | VTD_BF_SL_PDPE_A_MASK \ + | VTD_BF_SL_PDPE_IGN_10_9_MASK | VTD_BF_SL_PDPE_ADDR_MASK \ + | VTD_BF_SL_PDPE_IGN_61_52_MASK | VTD_BF_SL_PDPE_IGN_63_MASK) +/** @} */ + + +/** @name Second-Level PDE (2MB Page). + * In accordance with the Intel spec. + * @{ */ +/** R: Read. */ +#define VTD_BF_SL_PDE2M_R_SHIFT 0 +#define VTD_BF_SL_PDE2M_R_MASK UINT64_C(0x0000000000000001) +/** W: Write. */ +#define VTD_BF_SL_PDE2M_W_SHIFT 1 +#define VTD_BF_SL_PDE2M_W_MASK UINT64_C(0x0000000000000002) +/** X: Execute. */ +#define VTD_BF_SL_PDE2M_X_SHIFT 2 +#define VTD_BF_SL_PDE2M_X_MASK UINT64_C(0x0000000000000004) +/** EMT: Extended Memory Type. */ +#define VTD_BF_SL_PDE2M_EMT_SHIFT 3 +#define VTD_BF_SL_PDE2M_EMT_MASK UINT64_C(0x0000000000000038) +/** IPAT: Ignore PAT (Page Attribute Table). */ +#define VTD_BF_SL_PDE2M_IPAT_SHIFT 6 +#define VTD_BF_SL_PDE2M_IPAT_MASK UINT64_C(0x0000000000000040) +/** PS: Page Size (MB1). */ +#define VTD_BF_SL_PDE2M_PS_SHIFT 7 +#define VTD_BF_SL_PDE2M_PS_MASK UINT64_C(0x0000000000000080) +/** A: Accessed. */ +#define VTD_BF_SL_PDE2M_A_SHIFT 8 +#define VTD_BF_SL_PDE2M_A_MASK UINT64_C(0x0000000000000100) +/** D: Dirty. */ +#define VTD_BF_SL_PDE2M_D_SHIFT 9 +#define VTD_BF_SL_PDE2M_D_MASK UINT64_C(0x0000000000000200) +/** IGN: Ignored (bit 10). */ +#define VTD_BF_SL_PDE2M_IGN_10_SHIFT 10 +#define VTD_BF_SL_PDE2M_IGN_10_MASK UINT64_C(0x0000000000000400) +/** R: Reserved (bit 11). */ +#define VTD_BF_SL_PDE2M_RSVD_11_SHIFT 11 +#define VTD_BF_SL_PDE2M_RSVD_11_MASK UINT64_C(0x0000000000000800) +/** R: Reserved (bits 20:12). */ +#define VTD_BF_SL_PDE2M_RSVD_20_12_SHIFT 12 +#define VTD_BF_SL_PDE2M_RSVD_20_12_MASK UINT64_C(0x00000000001ff000) +/** ADDR: Address of 2MB page. */ +#define VTD_BF_SL_PDE2M_ADDR_SHIFT 21 +#define VTD_BF_SL_PDE2M_ADDR_MASK UINT64_C(0x000fffffffe00000) +/** IGN: Ignored (bits 61:52). */ +#define VTD_BF_SL_PDE2M_IGN_61_52_SHIFT 52 +#define VTD_BF_SL_PDE2M_IGN_61_52_MASK UINT64_C(0x3ff0000000000000) +/** R: Reserved (bit 62). */ +#define VTD_BF_SL_PDE2M_RSVD_62_SHIFT 62 +#define VTD_BF_SL_PDE2M_RSVD_62_MASK UINT64_C(0x4000000000000000) +/** IGN: Ignored (bit 63). */ +#define VTD_BF_SL_PDE2M_IGN_63_SHIFT 63 +#define VTD_BF_SL_PDE2M_IGN_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_SL_PDE2M_, UINT64_C(0), UINT64_MAX, + (R, W, X, EMT, IPAT, PS, A, D, IGN_10, RSVD_11, RSVD_20_12, ADDR, IGN_61_52, RSVD_62, IGN_63)); + +/** Second-level PDE (2MB page) valid mask. */ +#define VTD_SL_PDE2M_VALID_MASK ( VTD_BF_SL_PDE2M_R_MASK | VTD_BF_SL_PDE2M_W_MASK \ + | VTD_BF_SL_PDE2M_X_MASK | VTD_BF_SL_PDE2M_EMT_MASK \ + | VTD_BF_SL_PDE2M_IPAT_MASK | VTD_BF_SL_PDE2M_PS_MASK \ + | VTD_BF_SL_PDE2M_A_MASK | VTD_BF_SL_PDE2M_D_MASK \ + | VTD_BF_SL_PDE2M_IGN_10_MASK | VTD_BF_SL_PDE2M_ADDR_MASK \ + | VTD_BF_SL_PDE2M_IGN_61_52_MASK | VTD_BF_SL_PDE2M_IGN_63_MASK) +/** @} */ + + +/** @name Second-Level PDE. + * In accordance with the Intel spec. + * @{ */ +/** R: Read. */ +#define VTD_BF_SL_PDE_R_SHIFT 0 +#define VTD_BF_SL_PDE_R_MASK UINT64_C(0x0000000000000001) +/** W: Write. */ +#define VTD_BF_SL_PDE_W_SHIFT 1 +#define VTD_BF_SL_PDE_W_MASK UINT64_C(0x0000000000000002) +/** X: Execute. */ +#define VTD_BF_SL_PDE_X_SHIFT 2 +#define VTD_BF_SL_PDE_X_MASK UINT64_C(0x0000000000000004) +/** IGN: Ignored (bits 6:3). */ +#define VTD_BF_SL_PDE_IGN_6_3_SHIFT 3 +#define VTD_BF_SL_PDE_IGN_6_3_MASK UINT64_C(0x0000000000000078) +/** PS: Page Size (MBZ). */ +#define VTD_BF_SL_PDE_PS_SHIFT 7 +#define VTD_BF_SL_PDE_PS_MASK UINT64_C(0x0000000000000080) +/** A: Accessed. */ +#define VTD_BF_SL_PDE_A_SHIFT 8 +#define VTD_BF_SL_PDE_A_MASK UINT64_C(0x0000000000000100) +/** IGN: Ignored (bits 10:9). */ +#define VTD_BF_SL_PDE_IGN_10_9_SHIFT 9 +#define VTD_BF_SL_PDE_IGN_10_9_MASK UINT64_C(0x0000000000000600) +/** R: Reserved (bit 11). */ +#define VTD_BF_SL_PDE_RSVD_11_SHIFT 11 +#define VTD_BF_SL_PDE_RSVD_11_MASK UINT64_C(0x0000000000000800) +/** ADDR: Address of second-level PT. */ +#define VTD_BF_SL_PDE_ADDR_SHIFT 12 +#define VTD_BF_SL_PDE_ADDR_MASK UINT64_C(0x000ffffffffff000) +/** IGN: Ignored (bits 61:52). */ +#define VTD_BF_SL_PDE_IGN_61_52_SHIFT 52 +#define VTD_BF_SL_PDE_IGN_61_52_MASK UINT64_C(0x3ff0000000000000) +/** R: Reserved (bit 62). */ +#define VTD_BF_SL_PDE_RSVD_62_SHIFT 62 +#define VTD_BF_SL_PDE_RSVD_62_MASK UINT64_C(0x4000000000000000) +/** IGN: Ignored (bit 63). */ +#define VTD_BF_SL_PDE_IGN_63_SHIFT 63 +#define VTD_BF_SL_PDE_IGN_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_SL_PDE_, UINT64_C(0), UINT64_MAX, + (R, W, X, IGN_6_3, PS, A, IGN_10_9, RSVD_11, ADDR, IGN_61_52, RSVD_62, IGN_63)); + +/** Second-level PDE valid mask. */ +#define VTD_SL_PDE_VALID_MASK ( VTD_BF_SL_PDE_R_MASK | VTD_BF_SL_PDE_W_MASK \ + | VTD_BF_SL_PDE_X_MASK | VTD_BF_SL_PDE_IGN_6_3_MASK \ + | VTD_BF_SL_PDE_PS_MASK | VTD_BF_SL_PDE_A_MASK \ + | VTD_BF_SL_PDE_IGN_10_9_MASK | VTD_BF_SL_PDE_ADDR_MASK \ + | VTD_BF_SL_PDE_IGN_61_52_MASK | VTD_BF_SL_PDE_IGN_63_MASK) +/** @} */ + + +/** @name Second-Level PTE. + * In accordance with the Intel spec. + * @{ */ +/** R: Read. */ +#define VTD_BF_SL_PTE_R_SHIFT 0 +#define VTD_BF_SL_PTE_R_MASK UINT64_C(0x0000000000000001) +/** W: Write. */ +#define VTD_BF_SL_PTE_W_SHIFT 1 +#define VTD_BF_SL_PTE_W_MASK UINT64_C(0x0000000000000002) +/** X: Execute. */ +#define VTD_BF_SL_PTE_X_SHIFT 2 +#define VTD_BF_SL_PTE_X_MASK UINT64_C(0x0000000000000004) +/** EMT: Extended Memory Type. */ +#define VTD_BF_SL_PTE_EMT_SHIFT 3 +#define VTD_BF_SL_PTE_EMT_MASK UINT64_C(0x0000000000000038) +/** IPAT: Ignore PAT (Page Attribute Table). */ +#define VTD_BF_SL_PTE_IPAT_SHIFT 6 +#define VTD_BF_SL_PTE_IPAT_MASK UINT64_C(0x0000000000000040) +/** IGN: Ignored (bit 7). */ +#define VTD_BF_SL_PTE_IGN_7_SHIFT 7 +#define VTD_BF_SL_PTE_IGN_7_MASK UINT64_C(0x0000000000000080) +/** A: Accessed. */ +#define VTD_BF_SL_PTE_A_SHIFT 8 +#define VTD_BF_SL_PTE_A_MASK UINT64_C(0x0000000000000100) +/** D: Dirty. */ +#define VTD_BF_SL_PTE_D_SHIFT 9 +#define VTD_BF_SL_PTE_D_MASK UINT64_C(0x0000000000000200) +/** IGN: Ignored (bit 10). */ +#define VTD_BF_SL_PTE_IGN_10_SHIFT 10 +#define VTD_BF_SL_PTE_IGN_10_MASK UINT64_C(0x0000000000000400) +/** R: Reserved (bit 11). */ +#define VTD_BF_SL_PTE_RSVD_11_SHIFT 11 +#define VTD_BF_SL_PTE_RSVD_11_MASK UINT64_C(0x0000000000000800) +/** ADDR: Address of 4K page. */ +#define VTD_BF_SL_PTE_ADDR_SHIFT 12 +#define VTD_BF_SL_PTE_ADDR_MASK UINT64_C(0x000ffffffffff000) +/** IGN: Ignored (bits 61:52). */ +#define VTD_BF_SL_PTE_IGN_61_52_SHIFT 52 +#define VTD_BF_SL_PTE_IGN_61_52_MASK UINT64_C(0x3ff0000000000000) +/** R: Reserved (bit 62). */ +#define VTD_BF_SL_PTE_RSVD_62_SHIFT 62 +#define VTD_BF_SL_PTE_RSVD_62_MASK UINT64_C(0x4000000000000000) +/** IGN: Ignored (bit 63). */ +#define VTD_BF_SL_PTE_IGN_63_SHIFT 63 +#define VTD_BF_SL_PTE_IGN_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_SL_PTE_, UINT64_C(0), UINT64_MAX, + (R, W, X, EMT, IPAT, IGN_7, A, D, IGN_10, RSVD_11, ADDR, IGN_61_52, RSVD_62, IGN_63)); + +/** Second-level PTE valid mask. */ +#define VTD_SL_PTE_VALID_MASK ( VTD_BF_SL_PTE_R_MASK | VTD_BF_SL_PTE_W_MASK \ + | VTD_BF_SL_PTE_X_MASK | VTD_BF_SL_PTE_EMT_MASK \ + | VTD_BF_SL_PTE_IPAT_MASK | VTD_BF_SL_PTE_IGN_7_MASK \ + | VTD_BF_SL_PTE_A_MASK | VTD_BF_SL_PTE_D_MASK \ + | VTD_BF_SL_PTE_IGN_10_MASK | VTD_BF_SL_PTE_ADDR_MASK \ + | VTD_BF_SL_PTE_IGN_61_52_MASK | VTD_BF_SL_PTE_IGN_63_MASK) +/** @} */ + + +/** @name Fault Record. + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 11:0). */ +#define VTD_BF_0_FAULT_RECORD_RSVD_11_0_SHIFT 0 +#define VTD_BF_0_FAULT_RECORD_RSVD_11_0_MASK UINT64_C(0x0000000000000fff) +/** FI: Fault Information. */ +#define VTD_BF_0_FAULT_RECORD_FI_SHIFT 12 +#define VTD_BF_0_FAULT_RECORD_FI_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_FAULT_RECORD_, UINT64_C(0), UINT64_MAX, + (RSVD_11_0, FI)); + +/** SID: Source identifier. */ +#define VTD_BF_1_FAULT_RECORD_SID_SHIFT 0 +#define VTD_BF_1_FAULT_RECORD_SID_MASK UINT64_C(0x000000000000ffff) +/** R: Reserved (bits 28:16). */ +#define VTD_BF_1_FAULT_RECORD_RSVD_28_16_SHIFT 16 +#define VTD_BF_1_FAULT_RECORD_RSVD_28_16_MASK UINT64_C(0x000000001fff0000) +/** PRIV: Privilege Mode Requested. */ +#define VTD_BF_1_FAULT_RECORD_PRIV_SHIFT 29 +#define VTD_BF_1_FAULT_RECORD_PRIV_MASK UINT64_C(0x0000000020000000) +/** EXE: Execute Permission Requested. */ +#define VTD_BF_1_FAULT_RECORD_EXE_SHIFT 30 +#define VTD_BF_1_FAULT_RECORD_EXE_MASK UINT64_C(0x0000000040000000) +/** PP: PASID Present. */ +#define VTD_BF_1_FAULT_RECORD_PP_SHIFT 31 +#define VTD_BF_1_FAULT_RECORD_PP_MASK UINT64_C(0x0000000080000000) +/** FR: Fault Reason. */ +#define VTD_BF_1_FAULT_RECORD_FR_SHIFT 32 +#define VTD_BF_1_FAULT_RECORD_FR_MASK UINT64_C(0x000000ff00000000) +/** PV: PASID Value. */ +#define VTD_BF_1_FAULT_RECORD_PV_SHIFT 40 +#define VTD_BF_1_FAULT_RECORD_PV_MASK UINT64_C(0x0fffff0000000000) +/** AT: Address Type. */ +#define VTD_BF_1_FAULT_RECORD_AT_SHIFT 60 +#define VTD_BF_1_FAULT_RECORD_AT_MASK UINT64_C(0x3000000000000000) +/** T: Type. */ +#define VTD_BF_1_FAULT_RECORD_T_SHIFT 62 +#define VTD_BF_1_FAULT_RECORD_T_MASK UINT64_C(0x4000000000000000) +/** R: Reserved (bit 127). */ +#define VTD_BF_1_FAULT_RECORD_RSVD_63_SHIFT 63 +#define VTD_BF_1_FAULT_RECORD_RSVD_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_FAULT_RECORD_, UINT64_C(0), UINT64_MAX, + (SID, RSVD_28_16, PRIV, EXE, PP, FR, PV, AT, T, RSVD_63)); + +/** Fault record. */ +typedef struct VTD_FAULT_RECORD_T +{ + /** The qwords in the fault record. */ + uint64_t au64[2]; +} VTD_FAULT_RECORD_T; +/** Pointer to a fault record. */ +typedef VTD_FAULT_RECORD_T *PVTD_FAULT_RECORD_T; +/** Pointer to a const fault record. */ +typedef VTD_FAULT_RECORD_T const *PCVTD_FAULT_RECORD_T; +/** @} */ + + +/** @name Interrupt Remapping Table Entry (IRTE) for Remapped Interrupts. + * In accordance with the Intel spec. + * @{ */ +/** P: Present. */ +#define VTD_BF_0_IRTE_P_SHIFT 0 +#define VTD_BF_0_IRTE_P_MASK UINT64_C(0x0000000000000001) +/** FPD: Fault Processing Disable. */ +#define VTD_BF_0_IRTE_FPD_SHIFT 1 +#define VTD_BF_0_IRTE_FPD_MASK UINT64_C(0x0000000000000002) +/** DM: Destination Mode (0=physical, 1=logical). */ +#define VTD_BF_0_IRTE_DM_SHIFT 2 +#define VTD_BF_0_IRTE_DM_MASK UINT64_C(0x0000000000000004) +/** RH: Redirection Hint. */ +#define VTD_BF_0_IRTE_RH_SHIFT 3 +#define VTD_BF_0_IRTE_RH_MASK UINT64_C(0x0000000000000008) +/** TM: Trigger Mode. */ +#define VTD_BF_0_IRTE_TM_SHIFT 4 +#define VTD_BF_0_IRTE_TM_MASK UINT64_C(0x0000000000000010) +/** DLM: Delivery Mode. */ +#define VTD_BF_0_IRTE_DLM_SHIFT 5 +#define VTD_BF_0_IRTE_DLM_MASK UINT64_C(0x00000000000000e0) +/** AVL: Available. */ +#define VTD_BF_0_IRTE_AVAIL_SHIFT 8 +#define VTD_BF_0_IRTE_AVAIL_MASK UINT64_C(0x0000000000000f00) +/** R: Reserved (bits 14:12). */ +#define VTD_BF_0_IRTE_RSVD_14_12_SHIFT 12 +#define VTD_BF_0_IRTE_RSVD_14_12_MASK UINT64_C(0x0000000000007000) +/** IM: IRTE Mode. */ +#define VTD_BF_0_IRTE_IM_SHIFT 15 +#define VTD_BF_0_IRTE_IM_MASK UINT64_C(0x0000000000008000) +/** V: Vector. */ +#define VTD_BF_0_IRTE_V_SHIFT 16 +#define VTD_BF_0_IRTE_V_MASK UINT64_C(0x0000000000ff0000) +/** R: Reserved (bits 31:24). */ +#define VTD_BF_0_IRTE_RSVD_31_24_SHIFT 24 +#define VTD_BF_0_IRTE_RSVD_31_24_MASK UINT64_C(0x00000000ff000000) +/** DST: Desination Id. */ +#define VTD_BF_0_IRTE_DST_SHIFT 32 +#define VTD_BF_0_IRTE_DST_MASK UINT64_C(0xffffffff00000000) +/** R: Reserved (bits 39:32) when EIME=0. */ +#define VTD_BF_0_IRTE_RSVD_39_32_SHIFT 32 +#define VTD_BF_0_IRTE_RSVD_39_32_MASK UINT64_C(0x000000ff00000000) +/** DST_XAPIC: Destination Id when EIME=0. */ +#define VTD_BF_0_IRTE_DST_XAPIC_SHIFT 40 +#define VTD_BF_0_IRTE_DST_XAPIC_MASK UINT64_C(0x0000ff0000000000) +/** R: Reserved (bits 63:48) when EIME=0. */ +#define VTD_BF_0_IRTE_RSVD_63_48_SHIFT 48 +#define VTD_BF_0_IRTE_RSVD_63_48_MASK UINT64_C(0xffff000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_IRTE_, UINT64_C(0), UINT64_MAX, + (P, FPD, DM, RH, TM, DLM, AVAIL, RSVD_14_12, IM, V, RSVD_31_24, DST)); +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_IRTE_, UINT64_C(0), UINT64_MAX, + (P, FPD, DM, RH, TM, DLM, AVAIL, RSVD_14_12, IM, V, RSVD_31_24, RSVD_39_32, DST_XAPIC, RSVD_63_48)); + +/** SID: Source Identifier. */ +#define VTD_BF_1_IRTE_SID_SHIFT 0 +#define VTD_BF_1_IRTE_SID_MASK UINT64_C(0x000000000000ffff) +/** SQ: Source-Id Qualifier. */ +#define VTD_BF_1_IRTE_SQ_SHIFT 16 +#define VTD_BF_1_IRTE_SQ_MASK UINT64_C(0x0000000000030000) +/** SVT: Source Validation Type. */ +#define VTD_BF_1_IRTE_SVT_SHIFT 18 +#define VTD_BF_1_IRTE_SVT_MASK UINT64_C(0x00000000000c0000) +/** R: Reserved (bits 127:84). */ +#define VTD_BF_1_IRTE_RSVD_63_20_SHIFT 20 +#define VTD_BF_1_IRTE_RSVD_63_20_MASK UINT64_C(0xfffffffffff00000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_IRTE_, UINT64_C(0), UINT64_MAX, + (SID, SQ, SVT, RSVD_63_20)); + +/** IRTE: Qword 0 valid mask when EIME=1. */ +#define VTD_IRTE_0_X2APIC_VALID_MASK ( VTD_BF_0_IRTE_P_MASK | VTD_BF_0_IRTE_FPD_MASK \ + | VTD_BF_0_IRTE_DM_MASK | VTD_BF_0_IRTE_RH_MASK \ + | VTD_BF_0_IRTE_TM_MASK | VTD_BF_0_IRTE_DLM_MASK \ + | VTD_BF_0_IRTE_AVAIL_MASK | VTD_BF_0_IRTE_IM_MASK \ + | VTD_BF_0_IRTE_V_MASK | VTD_BF_0_IRTE_DST_MASK) +/** IRTE: Qword 0 valid mask when EIME=0. */ +#define VTD_IRTE_0_XAPIC_VALID_MASK ( VTD_BF_0_IRTE_P_MASK | VTD_BF_0_IRTE_FPD_MASK \ + | VTD_BF_0_IRTE_DM_MASK | VTD_BF_0_IRTE_RH_MASK \ + | VTD_BF_0_IRTE_TM_MASK | VTD_BF_0_IRTE_DLM_MASK \ + | VTD_BF_0_IRTE_AVAIL_MASK | VTD_BF_0_IRTE_IM_MASK \ + | VTD_BF_0_IRTE_V_MASK | VTD_BF_0_IRTE_DST_XAPIC_MASK) +/** IRTE: Qword 1 valid mask. */ +#define VTD_IRTE_1_VALID_MASK ( VTD_BF_1_IRTE_SID_MASK | VTD_BF_1_IRTE_SQ_MASK \ + | VTD_BF_1_IRTE_SVT_MASK) + +/** Interrupt Remapping Table Entry (IRTE) for remapped interrupts. */ +typedef struct VTD_IRTE_T +{ + /** The qwords in the IRTE. */ + uint64_t au64[2]; +} VTD_IRTE_T; +/** Pointer to an IRTE. */ +typedef VTD_IRTE_T *PVTD_IRTE_T; +/** Pointer to a const IRTE. */ +typedef VTD_IRTE_T const *PCVTD_IRTE_T; + +/** IRTE SVT: No validation required. */ +#define VTD_IRTE_SVT_NONE 0 +/** IRTE SVT: Validate using a mask derived from SID and SQT. */ +#define VTD_IRTE_SVT_VALIDATE_MASK 1 +/** IRTE SVT: Validate using Bus range in the SID. */ +#define VTD_IRTE_SVT_VALIDATE_BUS_RANGE 2 +/** IRTE SVT: Reserved. */ +#define VTD_IRTE_SVT_VALIDATE_RSVD 3 +/** @} */ + + +/** @name Version Register (VER_REG). + * In accordance with the Intel spec. + * @{ */ +/** Min: Minor Version Number. */ +#define VTD_BF_VER_REG_MIN_SHIFT 0 +#define VTD_BF_VER_REG_MIN_MASK UINT32_C(0x0000000f) +/** Max: Major Version Number. */ +#define VTD_BF_VER_REG_MAX_SHIFT 4 +#define VTD_BF_VER_REG_MAX_MASK UINT32_C(0x000000f0) +/** R: Reserved (bits 31:8). */ +#define VTD_BF_VER_REG_RSVD_31_8_SHIFT 8 +#define VTD_BF_VER_REG_RSVD_31_8_MASK UINT32_C(0xffffff00) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_VER_REG_, UINT32_C(0), UINT32_MAX, + (MIN, MAX, RSVD_31_8)); +/** RW: Read/write mask. */ +#define VTD_VER_REG_RW_MASK UINT32_C(0) +/** @} */ + + +/** @name Capability Register (CAP_REG). + * In accordance with the Intel spec. + * @{ */ +/** ND: Number of domains supported. */ +#define VTD_BF_CAP_REG_ND_SHIFT 0 +#define VTD_BF_CAP_REG_ND_MASK UINT64_C(0x0000000000000007) +/** AFL: Advanced Fault Logging. */ +#define VTD_BF_CAP_REG_AFL_SHIFT 3 +#define VTD_BF_CAP_REG_AFL_MASK UINT64_C(0x0000000000000008) +/** RWBF: Required Write-Buffer Flushing. */ +#define VTD_BF_CAP_REG_RWBF_SHIFT 4 +#define VTD_BF_CAP_REG_RWBF_MASK UINT64_C(0x0000000000000010) +/** PLMR: Protected Low-Memory Region. */ +#define VTD_BF_CAP_REG_PLMR_SHIFT 5 +#define VTD_BF_CAP_REG_PLMR_MASK UINT64_C(0x0000000000000020) +/** PHMR: Protected High-Memory Region. */ +#define VTD_BF_CAP_REG_PHMR_SHIFT 6 +#define VTD_BF_CAP_REG_PHMR_MASK UINT64_C(0x0000000000000040) +/** CM: Caching Mode. */ +#define VTD_BF_CAP_REG_CM_SHIFT 7 +#define VTD_BF_CAP_REG_CM_MASK UINT64_C(0x0000000000000080) +/** SAGAW: Supported Adjusted Guest Address Widths. */ +#define VTD_BF_CAP_REG_SAGAW_SHIFT 8 +#define VTD_BF_CAP_REG_SAGAW_MASK UINT64_C(0x0000000000001f00) +/** R: Reserved (bits 15:13). */ +#define VTD_BF_CAP_REG_RSVD_15_13_SHIFT 13 +#define VTD_BF_CAP_REG_RSVD_15_13_MASK UINT64_C(0x000000000000e000) +/** MGAW: Maximum Guest Address Width. */ +#define VTD_BF_CAP_REG_MGAW_SHIFT 16 +#define VTD_BF_CAP_REG_MGAW_MASK UINT64_C(0x00000000003f0000) +/** ZLR: Zero Length Read. */ +#define VTD_BF_CAP_REG_ZLR_SHIFT 22 +#define VTD_BF_CAP_REG_ZLR_MASK UINT64_C(0x0000000000400000) +/** DEP: Deprecated MBZ. Reserved (bit 23). */ +#define VTD_BF_CAP_REG_RSVD_23_SHIFT 23 +#define VTD_BF_CAP_REG_RSVD_23_MASK UINT64_C(0x0000000000800000) +/** FRO: Fault-recording Register Offset. */ +#define VTD_BF_CAP_REG_FRO_SHIFT 24 +#define VTD_BF_CAP_REG_FRO_MASK UINT64_C(0x00000003ff000000) +/** SLLPS: Second Level Large Page Support. */ +#define VTD_BF_CAP_REG_SLLPS_SHIFT 34 +#define VTD_BF_CAP_REG_SLLPS_MASK UINT64_C(0x0000003c00000000) +/** R: Reserved (bit 38). */ +#define VTD_BF_CAP_REG_RSVD_38_SHIFT 38 +#define VTD_BF_CAP_REG_RSVD_38_MASK UINT64_C(0x0000004000000000) +/** PSI: Page Selective Invalidation. */ +#define VTD_BF_CAP_REG_PSI_SHIFT 39 +#define VTD_BF_CAP_REG_PSI_MASK UINT64_C(0x0000008000000000) +/** NFR: Number of Fault-recording Registers. */ +#define VTD_BF_CAP_REG_NFR_SHIFT 40 +#define VTD_BF_CAP_REG_NFR_MASK UINT64_C(0x0000ff0000000000) +/** MAMV: Maximum Address Mask Value. */ +#define VTD_BF_CAP_REG_MAMV_SHIFT 48 +#define VTD_BF_CAP_REG_MAMV_MASK UINT64_C(0x003f000000000000) +/** DWD: Write Draining. */ +#define VTD_BF_CAP_REG_DWD_SHIFT 54 +#define VTD_BF_CAP_REG_DWD_MASK UINT64_C(0x0040000000000000) +/** DRD: Read Draining. */ +#define VTD_BF_CAP_REG_DRD_SHIFT 55 +#define VTD_BF_CAP_REG_DRD_MASK UINT64_C(0x0080000000000000) +/** FL1GP: First Level 1 GB Page Support. */ +#define VTD_BF_CAP_REG_FL1GP_SHIFT 56 +#define VTD_BF_CAP_REG_FL1GP_MASK UINT64_C(0x0100000000000000) +/** R: Reserved (bits 58:57). */ +#define VTD_BF_CAP_REG_RSVD_58_57_SHIFT 57 +#define VTD_BF_CAP_REG_RSVD_58_57_MASK UINT64_C(0x0600000000000000) +/** PI: Posted Interrupt Support. */ +#define VTD_BF_CAP_REG_PI_SHIFT 59 +#define VTD_BF_CAP_REG_PI_MASK UINT64_C(0x0800000000000000) +/** FL5LP: First Level 5-level Paging Support. */ +#define VTD_BF_CAP_REG_FL5LP_SHIFT 60 +#define VTD_BF_CAP_REG_FL5LP_MASK UINT64_C(0x1000000000000000) +/** R: Reserved (bit 61). */ +#define VTD_BF_CAP_REG_RSVD_61_SHIFT 61 +#define VTD_BF_CAP_REG_RSVD_61_MASK UINT64_C(0x2000000000000000) +/** ESIRTPS: Enhanced Set Interrupt Root Table Pointer Support. */ +#define VTD_BF_CAP_REG_ESIRTPS_SHIFT 62 +#define VTD_BF_CAP_REG_ESIRTPS_MASK UINT64_C(0x4000000000000000) +/** : Enhanced Set Root Table Pointer Support. */ +#define VTD_BF_CAP_REG_ESRTPS_SHIFT 63 +#define VTD_BF_CAP_REG_ESRTPS_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_CAP_REG_, UINT64_C(0), UINT64_MAX, + (ND, AFL, RWBF, PLMR, PHMR, CM, SAGAW, RSVD_15_13, MGAW, ZLR, RSVD_23, FRO, SLLPS, RSVD_38, PSI, NFR, + MAMV, DWD, DRD, FL1GP, RSVD_58_57, PI, FL5LP, RSVD_61, ESIRTPS, ESRTPS)); + +/** RW: Read/write mask. */ +#define VTD_CAP_REG_RW_MASK UINT64_C(0) +/** @} */ + + +/** @name Extended Capability Register (ECAP_REG). + * In accordance with the Intel spec. + * @{ */ +/** C: Page-walk Coherence. */ +#define VTD_BF_ECAP_REG_C_SHIFT 0 +#define VTD_BF_ECAP_REG_C_MASK UINT64_C(0x0000000000000001) +/** QI: Queued Invalidation Support. */ +#define VTD_BF_ECAP_REG_QI_SHIFT 1 +#define VTD_BF_ECAP_REG_QI_MASK UINT64_C(0x0000000000000002) +/** DT: Device-TLB Support. */ +#define VTD_BF_ECAP_REG_DT_SHIFT 2 +#define VTD_BF_ECAP_REG_DT_MASK UINT64_C(0x0000000000000004) +/** IR: Interrupt Remapping Support. */ +#define VTD_BF_ECAP_REG_IR_SHIFT 3 +#define VTD_BF_ECAP_REG_IR_MASK UINT64_C(0x0000000000000008) +/** EIM: Extended Interrupt Mode. */ +#define VTD_BF_ECAP_REG_EIM_SHIFT 4 +#define VTD_BF_ECAP_REG_EIM_MASK UINT64_C(0x0000000000000010) +/** DEP: Deprecated MBZ. Reserved (bit 5). */ +#define VTD_BF_ECAP_REG_RSVD_5_SHIFT 5 +#define VTD_BF_ECAP_REG_RSVD_5_MASK UINT64_C(0x0000000000000020) +/** PT: Pass Through. */ +#define VTD_BF_ECAP_REG_PT_SHIFT 6 +#define VTD_BF_ECAP_REG_PT_MASK UINT64_C(0x0000000000000040) +/** SC: Snoop Control. */ +#define VTD_BF_ECAP_REG_SC_SHIFT 7 +#define VTD_BF_ECAP_REG_SC_MASK UINT64_C(0x0000000000000080) +/** IRO: IOTLB Register Offset. */ +#define VTD_BF_ECAP_REG_IRO_SHIFT 8 +#define VTD_BF_ECAP_REG_IRO_MASK UINT64_C(0x000000000003ff00) +/** R: Reserved (bits 19:18). */ +#define VTD_BF_ECAP_REG_RSVD_19_18_SHIFT 18 +#define VTD_BF_ECAP_REG_RSVD_19_18_MASK UINT64_C(0x00000000000c0000) +/** MHMV: Maximum Handle Mask Value. */ +#define VTD_BF_ECAP_REG_MHMV_SHIFT 20 +#define VTD_BF_ECAP_REG_MHMV_MASK UINT64_C(0x0000000000f00000) +/** DEP: Deprecated MBZ. Reserved (bit 24). */ +#define VTD_BF_ECAP_REG_RSVD_24_SHIFT 24 +#define VTD_BF_ECAP_REG_RSVD_24_MASK UINT64_C(0x0000000001000000) +/** MTS: Memory Type Support. */ +#define VTD_BF_ECAP_REG_MTS_SHIFT 25 +#define VTD_BF_ECAP_REG_MTS_MASK UINT64_C(0x0000000002000000) +/** NEST: Nested Translation Support. */ +#define VTD_BF_ECAP_REG_NEST_SHIFT 26 +#define VTD_BF_ECAP_REG_NEST_MASK UINT64_C(0x0000000004000000) +/** R: Reserved (bit 27). */ +#define VTD_BF_ECAP_REG_RSVD_27_SHIFT 27 +#define VTD_BF_ECAP_REG_RSVD_27_MASK UINT64_C(0x0000000008000000) +/** DEP: Deprecated MBZ. Reserved (bit 28). */ +#define VTD_BF_ECAP_REG_RSVD_28_SHIFT 28 +#define VTD_BF_ECAP_REG_RSVD_28_MASK UINT64_C(0x0000000010000000) +/** PRS: Page Request Support. */ +#define VTD_BF_ECAP_REG_PRS_SHIFT 29 +#define VTD_BF_ECAP_REG_PRS_MASK UINT64_C(0x0000000020000000) +/** ERS: Execute Request Support. */ +#define VTD_BF_ECAP_REG_ERS_SHIFT 30 +#define VTD_BF_ECAP_REG_ERS_MASK UINT64_C(0x0000000040000000) +/** SRS: Supervisor Request Support. */ +#define VTD_BF_ECAP_REG_SRS_SHIFT 31 +#define VTD_BF_ECAP_REG_SRS_MASK UINT64_C(0x0000000080000000) +/** R: Reserved (bit 32). */ +#define VTD_BF_ECAP_REG_RSVD_32_SHIFT 32 +#define VTD_BF_ECAP_REG_RSVD_32_MASK UINT64_C(0x0000000100000000) +/** NWFS: No Write Flag Support. */ +#define VTD_BF_ECAP_REG_NWFS_SHIFT 33 +#define VTD_BF_ECAP_REG_NWFS_MASK UINT64_C(0x0000000200000000) +/** EAFS: Extended Accessed Flags Support. */ +#define VTD_BF_ECAP_REG_EAFS_SHIFT 34 +#define VTD_BF_ECAP_REG_EAFS_MASK UINT64_C(0x0000000400000000) +/** PSS: PASID Size Supported. */ +#define VTD_BF_ECAP_REG_PSS_SHIFT 35 +#define VTD_BF_ECAP_REG_PSS_MASK UINT64_C(0x000000f800000000) +/** PASID: Process Address Space ID Support. */ +#define VTD_BF_ECAP_REG_PASID_SHIFT 40 +#define VTD_BF_ECAP_REG_PASID_MASK UINT64_C(0x0000010000000000) +/** DIT: Device-TLB Invalidation Throttle. */ +#define VTD_BF_ECAP_REG_DIT_SHIFT 41 +#define VTD_BF_ECAP_REG_DIT_MASK UINT64_C(0x0000020000000000) +/** PDS: Page-request Drain Support. */ +#define VTD_BF_ECAP_REG_PDS_SHIFT 42 +#define VTD_BF_ECAP_REG_PDS_MASK UINT64_C(0x0000040000000000) +/** SMTS: Scalable-Mode Translation Support. */ +#define VTD_BF_ECAP_REG_SMTS_SHIFT 43 +#define VTD_BF_ECAP_REG_SMTS_MASK UINT64_C(0x0000080000000000) +/** VCS: Virtual Command Support. */ +#define VTD_BF_ECAP_REG_VCS_SHIFT 44 +#define VTD_BF_ECAP_REG_VCS_MASK UINT64_C(0x0000100000000000) +/** SLADS: Second-Level Accessed/Dirty Support. */ +#define VTD_BF_ECAP_REG_SLADS_SHIFT 45 +#define VTD_BF_ECAP_REG_SLADS_MASK UINT64_C(0x0000200000000000) +/** SLTS: Second-Level Translation Support. */ +#define VTD_BF_ECAP_REG_SLTS_SHIFT 46 +#define VTD_BF_ECAP_REG_SLTS_MASK UINT64_C(0x0000400000000000) +/** FLTS: First-Level Translation Support. */ +#define VTD_BF_ECAP_REG_FLTS_SHIFT 47 +#define VTD_BF_ECAP_REG_FLTS_MASK UINT64_C(0x0000800000000000) +/** SMPWCS: Scalable-Mode Page-Walk Coherency Support. */ +#define VTD_BF_ECAP_REG_SMPWCS_SHIFT 48 +#define VTD_BF_ECAP_REG_SMPWCS_MASK UINT64_C(0x0001000000000000) +/** RPS: RID-PASID Support. */ +#define VTD_BF_ECAP_REG_RPS_SHIFT 49 +#define VTD_BF_ECAP_REG_RPS_MASK UINT64_C(0x0002000000000000) +/** R: Reserved (bits 51:50). */ +#define VTD_BF_ECAP_REG_RSVD_51_50_SHIFT 50 +#define VTD_BF_ECAP_REG_RSVD_51_50_MASK UINT64_C(0x000c000000000000) +/** ADMS: Abort DMA Mode Support. */ +#define VTD_BF_ECAP_REG_ADMS_SHIFT 52 +#define VTD_BF_ECAP_REG_ADMS_MASK UINT64_C(0x0010000000000000) +/** RPRIVS: RID_PRIV Support. */ +#define VTD_BF_ECAP_REG_RPRIVS_SHIFT 53 +#define VTD_BF_ECAP_REG_RPRIVS_MASK UINT64_C(0x0020000000000000) +/** R: Reserved (bits 63:54). */ +#define VTD_BF_ECAP_REG_RSVD_63_54_SHIFT 54 +#define VTD_BF_ECAP_REG_RSVD_63_54_MASK UINT64_C(0xffc0000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_ECAP_REG_, UINT64_C(0), UINT64_MAX, + (C, QI, DT, IR, EIM, RSVD_5, PT, SC, IRO, RSVD_19_18, MHMV, RSVD_24, MTS, NEST, RSVD_27, RSVD_28, + PRS, ERS, SRS, RSVD_32, NWFS, EAFS, PSS, PASID, DIT, PDS, SMTS, VCS, SLADS, SLTS, FLTS, SMPWCS, RPS, + RSVD_51_50, ADMS, RPRIVS, RSVD_63_54)); + +/** RW: Read/write mask. */ +#define VTD_ECAP_REG_RW_MASK UINT64_C(0) +/** @} */ + + +/** @name Global Command Register (GCMD_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 22:0). */ +#define VTD_BF_GCMD_REG_RSVD_22_0_SHIFT 0 +#define VTD_BF_GCMD_REG_RSVD_22_0_MASK UINT32_C(0x007fffff) +/** CFI: Compatibility Format Interrupt. */ +#define VTD_BF_GCMD_REG_CFI_SHIFT 23 +#define VTD_BF_GCMD_REG_CFI_MASK UINT32_C(0x00800000) +/** SIRTP: Set Interrupt Table Remap Pointer. */ +#define VTD_BF_GCMD_REG_SIRTP_SHIFT 24 +#define VTD_BF_GCMD_REG_SIRTP_MASK UINT32_C(0x01000000) +/** IRE: Interrupt Remap Enable. */ +#define VTD_BF_GCMD_REG_IRE_SHIFT 25 +#define VTD_BF_GCMD_REG_IRE_MASK UINT32_C(0x02000000) +/** QIE: Queued Invalidation Enable. */ +#define VTD_BF_GCMD_REG_QIE_SHIFT 26 +#define VTD_BF_GCMD_REG_QIE_MASK UINT32_C(0x04000000) +/** WBF: Write Buffer Flush. */ +#define VTD_BF_GCMD_REG_WBF_SHIFT 27 +#define VTD_BF_GCMD_REG_WBF_MASK UINT32_C(0x08000000) +/** EAFL: Enable Advance Fault Logging. */ +#define VTD_BF_GCMD_REG_EAFL_SHIFT 28 +#define VTD_BF_GCMD_REG_EAFL_MASK UINT32_C(0x10000000) +/** SFL: Set Fault Log. */ +#define VTD_BF_GCMD_REG_SFL_SHIFT 29 +#define VTD_BF_GCMD_REG_SFL_MASK UINT32_C(0x20000000) +/** SRTP: Set Root Table Pointer. */ +#define VTD_BF_GCMD_REG_SRTP_SHIFT 30 +#define VTD_BF_GCMD_REG_SRTP_MASK UINT32_C(0x40000000) +/** TE: Translation Enable. */ +#define VTD_BF_GCMD_REG_TE_SHIFT 31 +#define VTD_BF_GCMD_REG_TE_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_GCMD_REG_, UINT32_C(0), UINT32_MAX, + (RSVD_22_0, CFI, SIRTP, IRE, QIE, WBF, EAFL, SFL, SRTP, TE)); + +/** RW: Read/write mask. */ +#define VTD_GCMD_REG_RW_MASK ( VTD_BF_GCMD_REG_TE_MASK | VTD_BF_GCMD_REG_SRTP_MASK \ + | VTD_BF_GCMD_REG_SFL_MASK | VTD_BF_GCMD_REG_EAFL_MASK \ + | VTD_BF_GCMD_REG_WBF_MASK | VTD_BF_GCMD_REG_QIE_MASK \ + | VTD_BF_GCMD_REG_IRE_MASK | VTD_BF_GCMD_REG_SIRTP_MASK \ + | VTD_BF_GCMD_REG_CFI_MASK) +/** @} */ + + +/** @name Global Status Register (GSTS_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 22:0). */ +#define VTD_BF_GSTS_REG_RSVD_22_0_SHIFT 0 +#define VTD_BF_GSTS_REG_RSVD_22_0_MASK UINT32_C(0x007fffff) +/** CFIS: Compatibility Format Interrupt Status. */ +#define VTD_BF_GSTS_REG_CFIS_SHIFT 23 +#define VTD_BF_GSTS_REG_CFIS_MASK UINT32_C(0x00800000) +/** IRTPS: Interrupt Remapping Table Pointer Status. */ +#define VTD_BF_GSTS_REG_IRTPS_SHIFT 24 +#define VTD_BF_GSTS_REG_IRTPS_MASK UINT32_C(0x01000000) +/** IRES: Interrupt Remapping Enable Status. */ +#define VTD_BF_GSTS_REG_IRES_SHIFT 25 +#define VTD_BF_GSTS_REG_IRES_MASK UINT32_C(0x02000000) +/** QIES: Queued Invalidation Enable Status. */ +#define VTD_BF_GSTS_REG_QIES_SHIFT 26 +#define VTD_BF_GSTS_REG_QIES_MASK UINT32_C(0x04000000) +/** WBFS: Write Buffer Flush Status. */ +#define VTD_BF_GSTS_REG_WBFS_SHIFT 27 +#define VTD_BF_GSTS_REG_WBFS_MASK UINT32_C(0x08000000) +/** AFLS: Advanced Fault Logging Status. */ +#define VTD_BF_GSTS_REG_AFLS_SHIFT 28 +#define VTD_BF_GSTS_REG_AFLS_MASK UINT32_C(0x10000000) +/** FLS: Fault Log Status. */ +#define VTD_BF_GSTS_REG_FLS_SHIFT 29 +#define VTD_BF_GSTS_REG_FLS_MASK UINT32_C(0x20000000) +/** RTPS: Root Table Pointer Status. */ +#define VTD_BF_GSTS_REG_RTPS_SHIFT 30 +#define VTD_BF_GSTS_REG_RTPS_MASK UINT32_C(0x40000000) +/** TES: Translation Enable Status. */ +#define VTD_BF_GSTS_REG_TES_SHIFT 31 +#define VTD_BF_GSTS_REG_TES_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_GSTS_REG_, UINT32_C(0), UINT32_MAX, + (RSVD_22_0, CFIS, IRTPS, IRES, QIES, WBFS, AFLS, FLS, RTPS, TES)); + +/** RW: Read/write mask. */ +#define VTD_GSTS_REG_RW_MASK UINT32_C(0) +/** @} */ + + +/** @name Root Table Address Register (RTADDR_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 9:0). */ +#define VTD_BF_RTADDR_REG_RSVD_9_0_SHIFT 0 +#define VTD_BF_RTADDR_REG_RSVD_9_0_MASK UINT64_C(0x00000000000003ff) +/** TTM: Translation Table Mode. */ +#define VTD_BF_RTADDR_REG_TTM_SHIFT 10 +#define VTD_BF_RTADDR_REG_TTM_MASK UINT64_C(0x0000000000000c00) +/** RTA: Root Table Address. */ +#define VTD_BF_RTADDR_REG_RTA_SHIFT 12 +#define VTD_BF_RTADDR_REG_RTA_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_RTADDR_REG_, UINT64_C(0), UINT64_MAX, + (RSVD_9_0, TTM, RTA)); + +/** RW: Read/write mask. */ +#define VTD_RTADDR_REG_RW_MASK UINT64_C(0xfffffffffffffc00) + +/** RTADDR_REG.TTM: Legacy mode. */ +#define VTD_TTM_LEGACY_MODE 0 +/** RTADDR_REG.TTM: Scalable mode. */ +#define VTD_TTM_SCALABLE_MODE 1 +/** RTADDR_REG.TTM: Reserved. */ +#define VTD_TTM_RSVD 2 +/** RTADDR_REG.TTM: Abort DMA mode. */ +#define VTD_TTM_ABORT_DMA_MODE 3 +/** @} */ + + +/** @name Context Command Register (CCMD_REG). + * In accordance with the Intel spec. + * @{ */ +/** DID: Domain-ID. */ +#define VTD_BF_CCMD_REG_DID_SHIFT 0 +#define VTD_BF_CCMD_REG_DID_MASK UINT64_C(0x000000000000ffff) +/** SID: Source-ID. */ +#define VTD_BF_CCMD_REG_SID_SHIFT 16 +#define VTD_BF_CCMD_REG_SID_MASK UINT64_C(0x00000000ffff0000) +/** FM: Function Mask. */ +#define VTD_BF_CCMD_REG_FM_SHIFT 32 +#define VTD_BF_CCMD_REG_FM_MASK UINT64_C(0x0000000300000000) +/** R: Reserved (bits 58:34). */ +#define VTD_BF_CCMD_REG_RSVD_58_34_SHIFT 34 +#define VTD_BF_CCMD_REG_RSVD_58_34_MASK UINT64_C(0x07fffffc00000000) +/** CAIG: Context Actual Invalidation Granularity. */ +#define VTD_BF_CCMD_REG_CAIG_SHIFT 59 +#define VTD_BF_CCMD_REG_CAIG_MASK UINT64_C(0x1800000000000000) +/** CIRG: Context Invalidation Request Granularity. */ +#define VTD_BF_CCMD_REG_CIRG_SHIFT 61 +#define VTD_BF_CCMD_REG_CIRG_MASK UINT64_C(0x6000000000000000) +/** ICC: Invalidation Context Cache. */ +#define VTD_BF_CCMD_REG_ICC_SHIFT 63 +#define VTD_BF_CCMD_REG_ICC_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_CCMD_REG_, UINT64_C(0), UINT64_MAX, + (DID, SID, FM, RSVD_58_34, CAIG, CIRG, ICC)); + +/** RW: Read/write mask. */ +#define VTD_CCMD_REG_RW_MASK ( VTD_BF_CCMD_REG_DID_MASK | VTD_BF_CCMD_REG_SID_MASK \ + | VTD_BF_CCMD_REG_FM_MASK | VTD_BF_CCMD_REG_CIRG_MASK \ + | VTD_BF_CCMD_REG_ICC_MASK) +/** @} */ + + +/** @name IOTLB Invalidation Register (IOTLB_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 31:0). */ +#define VTD_BF_IOTLB_REG_RSVD_31_0_SHIFT 0 +#define VTD_BF_IOTLB_REG_RSVD_31_0_MASK UINT64_C(0x00000000ffffffff) +/** DID: Domain-ID. */ +#define VTD_BF_IOTLB_REG_DID_SHIFT 32 +#define VTD_BF_IOTLB_REG_DID_MASK UINT64_C(0x0000ffff00000000) +/** DW: Draining Writes. */ +#define VTD_BF_IOTLB_REG_DW_SHIFT 48 +#define VTD_BF_IOTLB_REG_DW_MASK UINT64_C(0x0001000000000000) +/** DR: Draining Reads. */ +#define VTD_BF_IOTLB_REG_DR_SHIFT 49 +#define VTD_BF_IOTLB_REG_DR_MASK UINT64_C(0x0002000000000000) +/** R: Reserved (bits 56:50). */ +#define VTD_BF_IOTLB_REG_RSVD_56_50_SHIFT 50 +#define VTD_BF_IOTLB_REG_RSVD_56_50_MASK UINT64_C(0x01fc000000000000) +/** IAIG: IOTLB Actual Invalidation Granularity. */ +#define VTD_BF_IOTLB_REG_IAIG_SHIFT 57 +#define VTD_BF_IOTLB_REG_IAIG_MASK UINT64_C(0x0600000000000000) +/** R: Reserved (bit 59). */ +#define VTD_BF_IOTLB_REG_RSVD_59_SHIFT 59 +#define VTD_BF_IOTLB_REG_RSVD_59_MASK UINT64_C(0x0800000000000000) +/** IIRG: IOTLB Invalidation Request Granularity. */ +#define VTD_BF_IOTLB_REG_IIRG_SHIFT 60 +#define VTD_BF_IOTLB_REG_IIRG_MASK UINT64_C(0x3000000000000000) +/** R: Reserved (bit 62). */ +#define VTD_BF_IOTLB_REG_RSVD_62_SHIFT 62 +#define VTD_BF_IOTLB_REG_RSVD_62_MASK UINT64_C(0x4000000000000000) +/** IVT: Invalidate IOTLB. */ +#define VTD_BF_IOTLB_REG_IVT_SHIFT 63 +#define VTD_BF_IOTLB_REG_IVT_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IOTLB_REG_, UINT64_C(0), UINT64_MAX, + (RSVD_31_0, DID, DW, DR, RSVD_56_50, IAIG, RSVD_59, IIRG, RSVD_62, IVT)); + +/** RW: Read/write mask. */ +#define VTD_IOTLB_REG_RW_MASK ( VTD_BF_IOTLB_REG_DID_MASK | VTD_BF_IOTLB_REG_DW_MASK \ + | VTD_BF_IOTLB_REG_DR_MASK | VTD_BF_IOTLB_REG_IIRG_MASK \ + | VTD_BF_IOTLB_REG_IVT_MASK) +/** @} */ + + +/** @name Invalidate Address Register (IVA_REG). + * In accordance with the Intel spec. + * @{ */ +/** AM: Address Mask. */ +#define VTD_BF_IVA_REG_AM_SHIFT 0 +#define VTD_BF_IVA_REG_AM_MASK UINT64_C(0x000000000000003f) +/** IH: Invalidation Hint. */ +#define VTD_BF_IVA_REG_IH_SHIFT 6 +#define VTD_BF_IVA_REG_IH_MASK UINT64_C(0x0000000000000040) +/** R: Reserved (bits 11:7). */ +#define VTD_BF_IVA_REG_RSVD_11_7_SHIFT 7 +#define VTD_BF_IVA_REG_RSVD_11_7_MASK UINT64_C(0x0000000000000f80) +/** ADDR: Address. */ +#define VTD_BF_IVA_REG_ADDR_SHIFT 12 +#define VTD_BF_IVA_REG_ADDR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IVA_REG_, UINT64_C(0), UINT64_MAX, + (AM, IH, RSVD_11_7, ADDR)); + +/** RW: Read/write mask. */ +#define VTD_IVA_REG_RW_MASK ( VTD_BF_IVA_REG_AM_MASK | VTD_BF_IVA_REG_IH_MASK \ + | VTD_BF_IVA_REG_ADDR_MASK) +/** @} */ + + +/** @name Fault Status Register (FSTS_REG). + * In accordance with the Intel spec. + * @{ */ +/** PFO: Primary Fault Overflow. */ +#define VTD_BF_FSTS_REG_PFO_SHIFT 0 +#define VTD_BF_FSTS_REG_PFO_MASK UINT32_C(0x00000001) +/** PPF: Primary Pending Fault. */ +#define VTD_BF_FSTS_REG_PPF_SHIFT 1 +#define VTD_BF_FSTS_REG_PPF_MASK UINT32_C(0x00000002) +/** AFO: Advanced Fault Overflow. */ +#define VTD_BF_FSTS_REG_AFO_SHIFT 2 +#define VTD_BF_FSTS_REG_AFO_MASK UINT32_C(0x00000004) +/** APF: Advanced Pending Fault. */ +#define VTD_BF_FSTS_REG_APF_SHIFT 3 +#define VTD_BF_FSTS_REG_APF_MASK UINT32_C(0x00000008) +/** IQE: Invalidation Queue Error. */ +#define VTD_BF_FSTS_REG_IQE_SHIFT 4 +#define VTD_BF_FSTS_REG_IQE_MASK UINT32_C(0x00000010) +/** ICE: Invalidation Completion Error. */ +#define VTD_BF_FSTS_REG_ICE_SHIFT 5 +#define VTD_BF_FSTS_REG_ICE_MASK UINT32_C(0x00000020) +/** ITE: Invalidation Timeout Error. */ +#define VTD_BF_FSTS_REG_ITE_SHIFT 6 +#define VTD_BF_FSTS_REG_ITE_MASK UINT32_C(0x00000040) +/** DEP: Deprecated MBZ. Reserved (bit 7). */ +#define VTD_BF_FSTS_REG_RSVD_7_SHIFT 7 +#define VTD_BF_FSTS_REG_RSVD_7_MASK UINT32_C(0x00000080) +/** FRI: Fault Record Index. */ +#define VTD_BF_FSTS_REG_FRI_SHIFT 8 +#define VTD_BF_FSTS_REG_FRI_MASK UINT32_C(0x0000ff00) +/** R: Reserved (bits 31:16). */ +#define VTD_BF_FSTS_REG_RSVD_31_16_SHIFT 16 +#define VTD_BF_FSTS_REG_RSVD_31_16_MASK UINT32_C(0xffff0000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_FSTS_REG_, UINT32_C(0), UINT32_MAX, + (PFO, PPF, AFO, APF, IQE, ICE, ITE, RSVD_7, FRI, RSVD_31_16)); + +/** RW: Read/write mask. */ +#define VTD_FSTS_REG_RW_MASK ( VTD_BF_FSTS_REG_PFO_MASK | VTD_BF_FSTS_REG_AFO_MASK \ + | VTD_BF_FSTS_REG_APF_MASK | VTD_BF_FSTS_REG_IQE_MASK \ + | VTD_BF_FSTS_REG_ICE_MASK | VTD_BF_FSTS_REG_ITE_MASK) +/** RW1C: Read-only-status, Write-1-to-clear status mask. */ +#define VTD_FSTS_REG_RW1C_MASK ( VTD_BF_FSTS_REG_PFO_MASK | VTD_BF_FSTS_REG_AFO_MASK \ + | VTD_BF_FSTS_REG_APF_MASK | VTD_BF_FSTS_REG_IQE_MASK \ + | VTD_BF_FSTS_REG_ICE_MASK | VTD_BF_FSTS_REG_ITE_MASK) +/** @} */ + + +/** @name Fault Event Control Register (FECTL_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 29:0). */ +#define VTD_BF_FECTL_REG_RSVD_29_0_SHIFT 0 +#define VTD_BF_FECTL_REG_RSVD_29_0_MASK UINT32_C(0x3fffffff) +/** IP: Interrupt Pending. */ +#define VTD_BF_FECTL_REG_IP_SHIFT 30 +#define VTD_BF_FECTL_REG_IP_MASK UINT32_C(0x40000000) +/** IM: Interrupt Mask. */ +#define VTD_BF_FECTL_REG_IM_SHIFT 31 +#define VTD_BF_FECTL_REG_IM_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_FECTL_REG_, UINT32_C(0), UINT32_MAX, + (RSVD_29_0, IP, IM)); + +/** RW: Read/write mask. */ +#define VTD_FECTL_REG_RW_MASK VTD_BF_FECTL_REG_IM_MASK +/** @} */ + + +/** @name Fault Event Data Register (FEDATA_REG). + * In accordance with the Intel spec. + * @{ */ +/** IMD: Interrupt Message Data. */ +#define VTD_BF_FEDATA_REG_IMD_SHIFT 0 +#define VTD_BF_FEDATA_REG_IMD_MASK UINT32_C(0x0000ffff) +/** R: Reserved (bits 31:16). VT-d specs. prior to 2021 had EIMD here. */ +#define VTD_BF_FEDATA_REG_RSVD_31_16_SHIFT 16 +#define VTD_BF_FEDATA_REG_RSVD_31_16_MASK UINT32_C(0xffff0000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_FEDATA_REG_, UINT32_C(0), UINT32_MAX, + (IMD, RSVD_31_16)); + +/** RW: Read/write mask, see 5.1.6 "Remapping Hardware Event Interrupt + * Programming". */ +#define VTD_FEDATA_REG_RW_MASK UINT32_C(0x000001ff) +/** @} */ + + +/** @name Fault Event Address Register (FEADDR_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 1:0). */ +#define VTD_BF_FEADDR_REG_RSVD_1_0_SHIFT 0 +#define VTD_BF_FEADDR_REG_RSVD_1_0_MASK UINT32_C(0x00000003) +/** MA: Message Address. */ +#define VTD_BF_FEADDR_REG_MA_SHIFT 2 +#define VTD_BF_FEADDR_REG_MA_MASK UINT32_C(0xfffffffc) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_FEADDR_REG_, UINT32_C(0), UINT32_MAX, + (RSVD_1_0, MA)); + +/** RW: Read/write mask. */ +#define VTD_FEADDR_REG_RW_MASK VTD_BF_FEADDR_REG_MA_MASK +/** @} */ + + +/** @name Fault Event Upper Address Register (FEUADDR_REG). + * In accordance with the Intel spec. + * @{ */ +/** MUA: Message Upper Address. */ +#define VTD_BF_FEUADDR_REG_MA_SHIFT 0 +#define VTD_BF_FEUADDR_REG_MA_MASK UINT32_C(0xffffffff) + +/** RW: Read/write mask. */ +#define VTD_FEUADDR_REG_RW_MASK VTD_BF_FEUADDR_REG_MA_MASK +/** @} */ + + +/** @name Fault Recording Register (FRCD_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 11:0). */ +#define VTD_BF_0_FRCD_REG_RSVD_11_0_SHIFT 0 +#define VTD_BF_0_FRCD_REG_RSVD_11_0_MASK UINT64_C(0x0000000000000fff) +/** FI: Fault Info. */ +#define VTD_BF_0_FRCD_REG_FI_SHIFT 12 +#define VTD_BF_0_FRCD_REG_FI_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_FRCD_REG_, UINT64_C(0), UINT64_MAX, + (RSVD_11_0, FI)); + +/** SID: Source Identifier. */ +#define VTD_BF_1_FRCD_REG_SID_SHIFT 0 +#define VTD_BF_1_FRCD_REG_SID_MASK UINT64_C(0x000000000000ffff) +/** R: Reserved (bits 27:16). */ +#define VTD_BF_1_FRCD_REG_RSVD_27_16_SHIFT 16 +#define VTD_BF_1_FRCD_REG_RSVD_27_16_MASK UINT64_C(0x000000000fff0000) +/** T2: Type bit 2. */ +#define VTD_BF_1_FRCD_REG_T2_SHIFT 28 +#define VTD_BF_1_FRCD_REG_T2_MASK UINT64_C(0x0000000010000000) +/** PRIV: Privilege Mode. */ +#define VTD_BF_1_FRCD_REG_PRIV_SHIFT 29 +#define VTD_BF_1_FRCD_REG_PRIV_MASK UINT64_C(0x0000000020000000) +/** EXE: Execute Permission Requested. */ +#define VTD_BF_1_FRCD_REG_EXE_SHIFT 30 +#define VTD_BF_1_FRCD_REG_EXE_MASK UINT64_C(0x0000000040000000) +/** PP: PASID Present. */ +#define VTD_BF_1_FRCD_REG_PP_SHIFT 31 +#define VTD_BF_1_FRCD_REG_PP_MASK UINT64_C(0x0000000080000000) +/** FR: Fault Reason. */ +#define VTD_BF_1_FRCD_REG_FR_SHIFT 32 +#define VTD_BF_1_FRCD_REG_FR_MASK UINT64_C(0x000000ff00000000) +/** PV: PASID Value. */ +#define VTD_BF_1_FRCD_REG_PV_SHIFT 40 +#define VTD_BF_1_FRCD_REG_PV_MASK UINT64_C(0x0fffff0000000000) +/** AT: Address Type. */ +#define VTD_BF_1_FRCD_REG_AT_SHIFT 60 +#define VTD_BF_1_FRCD_REG_AT_MASK UINT64_C(0x3000000000000000) +/** T1: Type bit 1. */ +#define VTD_BF_1_FRCD_REG_T1_SHIFT 62 +#define VTD_BF_1_FRCD_REG_T1_MASK UINT64_C(0x4000000000000000) +/** F: Fault. */ +#define VTD_BF_1_FRCD_REG_F_SHIFT 63 +#define VTD_BF_1_FRCD_REG_F_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_FRCD_REG_, UINT64_C(0), UINT64_MAX, + (SID, RSVD_27_16, T2, PRIV, EXE, PP, FR, PV, AT, T1, F)); + +/** RW: Read/write mask. */ +#define VTD_FRCD_REG_LO_RW_MASK UINT64_C(0) +#define VTD_FRCD_REG_HI_RW_MASK VTD_BF_1_FRCD_REG_F_MASK +/** RW1C: Read-only-status, Write-1-to-clear status mask. */ +#define VTD_FRCD_REG_LO_RW1C_MASK UINT64_C(0) +#define VTD_FRCD_REG_HI_RW1C_MASK VTD_BF_1_FRCD_REG_F_MASK +/** @} */ + + +/** + * VT-d faulted address translation request types (FRCD_REG::T2). + * In accordance with the Intel spec. + */ +typedef enum VTDREQTYPE +{ + VTDREQTYPE_WRITE = 0, /**< Memory access write request. */ + VTDREQTYPE_PAGE, /**< Page translation request. */ + VTDREQTYPE_READ, /**< Memory access read request. */ + VTDREQTYPE_ATOMIC_OP /**< Memory access atomic operation. */ +} VTDREQTYPE; +/** Pointer to a VTDREQTYPE. */ +typedef VTDREQTYPE *PVTDREQTYPE; + + +/** @name Advanced Fault Log Register (AFLOG_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 8:0). */ +#define VTD_BF_0_AFLOG_REG_RSVD_8_0_SHIFT 0 +#define VTD_BF_0_AFLOG_REG_RSVD_8_0_MASK UINT64_C(0x00000000000001ff) +/** FLS: Fault Log Size. */ +#define VTD_BF_0_AFLOG_REG_FLS_SHIFT 9 +#define VTD_BF_0_AFLOG_REG_FLS_MASK UINT64_C(0x0000000000000e00) +/** FLA: Fault Log Address. */ +#define VTD_BF_0_AFLOG_REG_FLA_SHIFT 12 +#define VTD_BF_0_AFLOG_REG_FLA_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_AFLOG_REG_, UINT64_C(0), UINT64_MAX, + (RSVD_8_0, FLS, FLA)); + +/** RW: Read/write mask. */ +#define VTD_AFLOG_REG_RW_MASK (VTD_BF_0_AFLOG_REG_FLS_MASK | VTD_BF_0_AFLOG_REG_FLA_MASK) +/** @} */ + + +/** @name Protected Memory Enable Register (PMEN_REG). + * In accordance with the Intel spec. + * @{ */ +/** PRS: Protected Region Status. */ +#define VTD_BF_PMEN_REG_PRS_SHIFT 0 +#define VTD_BF_PMEN_REG_PRS_MASK UINT32_C(0x00000001) +/** R: Reserved (bits 30:1). */ +#define VTD_BF_PMEN_REG_RSVD_30_1_SHIFT 1 +#define VTD_BF_PMEN_REG_RSVD_30_1_MASK UINT32_C(0x7ffffffe) +/** EPM: Enable Protected Memory. */ +#define VTD_BF_PMEN_REG_EPM_SHIFT 31 +#define VTD_BF_PMEN_REG_EPM_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_PMEN_REG_, UINT32_C(0), UINT32_MAX, + (PRS, RSVD_30_1, EPM)); + +/** RW: Read/write mask. */ +#define VTD_PMEN_REG_RW_MASK VTD_BF_PMEN_REG_EPM_MASK +/** @} */ + + +/** @name Invalidation Queue Head Register (IQH_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 3:0). */ +#define VTD_BF_IQH_REG_RSVD_3_0_SHIFT 0 +#define VTD_BF_IQH_REG_RSVD_3_0_MASK UINT64_C(0x000000000000000f) +/** QH: Queue Head. */ +#define VTD_BF_IQH_REG_QH_SHIFT 4 +#define VTD_BF_IQH_REG_QH_MASK UINT64_C(0x000000000007fff0) +/** R: Reserved (bits 63:19). */ +#define VTD_BF_IQH_REG_RSVD_63_19_SHIFT 19 +#define VTD_BF_IQH_REG_RSVD_63_19_MASK UINT64_C(0xfffffffffff80000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IQH_REG_, UINT64_C(0), UINT64_MAX, + (RSVD_3_0, QH, RSVD_63_19)); + +/** RW: Read/write mask. */ +#define VTD_IQH_REG_RW_MASK UINT64_C(0x0) +/** @} */ + + +/** @name Invalidation Queue Tail Register (IQT_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 3:0). */ +#define VTD_BF_IQT_REG_RSVD_3_0_SHIFT 0 +#define VTD_BF_IQT_REG_RSVD_3_0_MASK UINT64_C(0x000000000000000f) +/** QH: Queue Tail. */ +#define VTD_BF_IQT_REG_QT_SHIFT 4 +#define VTD_BF_IQT_REG_QT_MASK UINT64_C(0x000000000007fff0) +/** R: Reserved (bits 63:19). */ +#define VTD_BF_IQT_REG_RSVD_63_19_SHIFT 19 +#define VTD_BF_IQT_REG_RSVD_63_19_MASK UINT64_C(0xfffffffffff80000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IQT_REG_, UINT64_C(0), UINT64_MAX, + (RSVD_3_0, QT, RSVD_63_19)); + +/** RW: Read/write mask. */ +#define VTD_IQT_REG_RW_MASK VTD_BF_IQT_REG_QT_MASK +/** @} */ + + +/** @name Invalidation Queue Address Register (IQA_REG). + * In accordance with the Intel spec. + * @{ */ +/** QS: Queue Size. */ +#define VTD_BF_IQA_REG_QS_SHIFT 0 +#define VTD_BF_IQA_REG_QS_MASK UINT64_C(0x0000000000000007) +/** R: Reserved (bits 10:3). */ +#define VTD_BF_IQA_REG_RSVD_10_3_SHIFT 3 +#define VTD_BF_IQA_REG_RSVD_10_3_MASK UINT64_C(0x00000000000007f8) +/** DW: Descriptor Width. */ +#define VTD_BF_IQA_REG_DW_SHIFT 11 +#define VTD_BF_IQA_REG_DW_MASK UINT64_C(0x0000000000000800) +/** IQA: Invalidation Queue Base Address. */ +#define VTD_BF_IQA_REG_IQA_SHIFT 12 +#define VTD_BF_IQA_REG_IQA_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IQA_REG_, UINT64_C(0), UINT64_MAX, + (QS, RSVD_10_3, DW, IQA)); + +/** RW: Read/write mask. */ +#define VTD_IQA_REG_RW_MASK ( VTD_BF_IQA_REG_QS_MASK | VTD_BF_IQA_REG_DW_MASK \ + | VTD_BF_IQA_REG_IQA_MASK) +/** DW: 128-bit descriptor. */ +#define VTD_IQA_REG_DW_128_BIT 0 +/** DW: 256-bit descriptor. */ +#define VTD_IQA_REG_DW_256_BIT 1 +/** @} */ + + +/** @name Invalidation Completion Status Register (ICS_REG). + * In accordance with the Intel spec. + * @{ */ +/** IWC: Invalidation Wait Descriptor Complete. */ +#define VTD_BF_ICS_REG_IWC_SHIFT 0 +#define VTD_BF_ICS_REG_IWC_MASK UINT32_C(0x00000001) +/** R: Reserved (bits 31:1). */ +#define VTD_BF_ICS_REG_RSVD_31_1_SHIFT 1 +#define VTD_BF_ICS_REG_RSVD_31_1_MASK UINT32_C(0xfffffffe) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_ICS_REG_, UINT32_C(0), UINT32_MAX, + (IWC, RSVD_31_1)); + +/** RW: Read/write mask. */ +#define VTD_ICS_REG_RW_MASK VTD_BF_ICS_REG_IWC_MASK +/** RW1C: Read-only-status, Write-1-to-clear status mask. */ +#define VTD_ICS_REG_RW1C_MASK VTD_BF_ICS_REG_IWC_MASK +/** @} */ + + +/** @name Invalidation Event Control Register (IECTL_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 29:0). */ +#define VTD_BF_IECTL_REG_RSVD_29_0_SHIFT 0 +#define VTD_BF_IECTL_REG_RSVD_29_0_MASK UINT32_C(0x3fffffff) +/** IP: Interrupt Pending. */ +#define VTD_BF_IECTL_REG_IP_SHIFT 30 +#define VTD_BF_IECTL_REG_IP_MASK UINT32_C(0x40000000) +/** IM: Interrupt Mask. */ +#define VTD_BF_IECTL_REG_IM_SHIFT 31 +#define VTD_BF_IECTL_REG_IM_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IECTL_REG_, UINT32_C(0), UINT32_MAX, + (RSVD_29_0, IP, IM)); + +/** RW: Read/write mask. */ +#define VTD_IECTL_REG_RW_MASK VTD_BF_IECTL_REG_IM_MASK +/** @} */ + + +/** @name Invalidation Event Data Register (IEDATA_REG). + * In accordance with the Intel spec. + * @{ */ +/** IMD: Interrupt Message Data. */ +#define VTD_BF_IEDATA_REG_IMD_SHIFT 0 +#define VTD_BF_IEDATA_REG_IMD_MASK UINT32_C(0x0000ffff) +/** R: Reserved (bits 31:16). VT-d specs. prior to 2021 had EIMD here. */ +#define VTD_BF_IEDATA_REG_RSVD_31_16_SHIFT 16 +#define VTD_BF_IEDATA_REG_RSVD_31_16_MASK UINT32_C(0xffff0000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IEDATA_REG_, UINT32_C(0), UINT32_MAX, + (IMD, RSVD_31_16)); + +/** RW: Read/write mask, see 5.1.6 "Remapping Hardware Event Interrupt + * Programming". */ +#define VTD_IEDATA_REG_RW_MASK UINT32_C(0x000001ff) +/** @} */ + + +/** @name Invalidation Event Address Register (IEADDR_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 1:0). */ +#define VTD_BF_IEADDR_REG_RSVD_1_0_SHIFT 0 +#define VTD_BF_IEADDR_REG_RSVD_1_0_MASK UINT32_C(0x00000003) +/** MA: Message Address. */ +#define VTD_BF_IEADDR_REG_MA_SHIFT 2 +#define VTD_BF_IEADDR_REG_MA_MASK UINT32_C(0xfffffffc) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IEADDR_REG_, UINT32_C(0), UINT32_MAX, + (RSVD_1_0, MA)); + +/** RW: Read/write mask. */ +#define VTD_IEADDR_REG_RW_MASK VTD_BF_IEADDR_REG_MA_MASK +/** @} */ + + +/** @name Invalidation Event Upper Address Register (IEUADDR_REG). + * @{ */ +/** MUA: Message Upper Address. */ +#define VTD_BF_IEUADDR_REG_MUA_SHIFT 0 +#define VTD_BF_IEUADDR_REG_MUA_MASK UINT32_C(0xffffffff) + +/** RW: Read/write mask. */ +#define VTD_IEUADDR_REG_RW_MASK VTD_BF_IEUADDR_REG_MUA_MASK +/** @} */ + + +/** @name Invalidation Queue Error Record Register (IQERCD_REG). + * In accordance with the Intel spec. + * @{ */ +/** IQEI: Invalidation Queue Error Info. */ +#define VTD_BF_IQERCD_REG_IQEI_SHIFT 0 +#define VTD_BF_IQERCD_REG_IQEI_MASK UINT64_C(0x000000000000000f) +/** R: Reserved (bits 31:4). */ +#define VTD_BF_IQERCD_REG_RSVD_31_4_SHIFT 4 +#define VTD_BF_IQERCD_REG_RSVD_31_4_MASK UINT64_C(0x00000000fffffff0) +/** ITESID: Invalidation Timeout Error Source Identifier. */ +#define VTD_BF_IQERCD_REG_ITESID_SHIFT 32 +#define VTD_BF_IQERCD_REG_ITESID_MASK UINT64_C(0x0000ffff00000000) +/** ICESID: Invalidation Completion Error Source Identifier. */ +#define VTD_BF_IQERCD_REG_ICESID_SHIFT 48 +#define VTD_BF_IQERCD_REG_ICESID_MASK UINT64_C(0xffff000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IQERCD_REG_, UINT64_C(0), UINT64_MAX, + (IQEI, RSVD_31_4, ITESID, ICESID)); + +/** RW: Read/write mask. */ +#define VTD_IQERCD_REG_RW_MASK UINT64_C(0) + +/** Invalidation Queue Error Information. */ +typedef enum VTDIQEI +{ + VTDIQEI_INFO_NOT_AVAILABLE, + VTDIQEI_INVALID_TAIL_PTR, + VTDIQEI_FETCH_DESCRIPTOR_ERR, + VTDIQEI_INVALID_DESCRIPTOR_TYPE, + VTDIQEI_RSVD_FIELD_VIOLATION, + VTDIQEI_INVALID_DESCRIPTOR_WIDTH, + VTDIQEI_QUEUE_TAIL_MISALIGNED, + VTDIQEI_INVALID_TTM +} VTDIQEI; +/** @} */ + + +/** @name Interrupt Remapping Table Address Register (IRTA_REG). + * In accordance with the Intel spec. + * @{ */ +/** S: Size. */ +#define VTD_BF_IRTA_REG_S_SHIFT 0 +#define VTD_BF_IRTA_REG_S_MASK UINT64_C(0x000000000000000f) +/** R: Reserved (bits 10:4). */ +#define VTD_BF_IRTA_REG_RSVD_10_4_SHIFT 4 +#define VTD_BF_IRTA_REG_RSVD_10_4_MASK UINT64_C(0x00000000000007f0) +/** EIME: Extended Interrupt Mode Enable. */ +#define VTD_BF_IRTA_REG_EIME_SHIFT 11 +#define VTD_BF_IRTA_REG_EIME_MASK UINT64_C(0x0000000000000800) +/** IRTA: Interrupt Remapping Table Address. */ +#define VTD_BF_IRTA_REG_IRTA_SHIFT 12 +#define VTD_BF_IRTA_REG_IRTA_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IRTA_REG_, UINT64_C(0), UINT64_MAX, + (S, RSVD_10_4, EIME, IRTA)); + +/** RW: Read/write mask. */ +#define VTD_IRTA_REG_RW_MASK ( VTD_BF_IRTA_REG_S_MASK | VTD_BF_IRTA_REG_EIME_MASK \ + | VTD_BF_IRTA_REG_IRTA_MASK) +/** IRTA_REG: Get number of interrupt entries. */ +#define VTD_IRTA_REG_GET_ENTRY_COUNT(a) (UINT32_C(1) << (1 + ((a) & VTD_BF_IRTA_REG_S_MASK))) +/** @} */ + + +/** @name Page Request Queue Head Register (PQH_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 4:0). */ +#define VTD_BF_PQH_REG_RSVD_4_0_SHIFT 0 +#define VTD_BF_PQH_REG_RSVD_4_0_MASK UINT64_C(0x000000000000001f) +/** PQH: Page Queue Head. */ +#define VTD_BF_PQH_REG_PQH_SHIFT 5 +#define VTD_BF_PQH_REG_PQH_MASK UINT64_C(0x000000000007ffe0) +/** R: Reserved (bits 63:19). */ +#define VTD_BF_PQH_REG_RSVD_63_19_SHIFT 19 +#define VTD_BF_PQH_REG_RSVD_63_19_MASK UINT64_C(0xfffffffffff80000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_PQH_REG_, UINT64_C(0), UINT64_MAX, + (RSVD_4_0, PQH, RSVD_63_19)); + +/** RW: Read/write mask. */ +#define VTD_PQH_REG_RW_MASK VTD_BF_PQH_REG_PQH_MASK +/** @} */ + + +/** @name Page Request Queue Tail Register (PQT_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 4:0). */ +#define VTD_BF_PQT_REG_RSVD_4_0_SHIFT 0 +#define VTD_BF_PQT_REG_RSVD_4_0_MASK UINT64_C(0x000000000000001f) +/** PQT: Page Queue Tail. */ +#define VTD_BF_PQT_REG_PQT_SHIFT 5 +#define VTD_BF_PQT_REG_PQT_MASK UINT64_C(0x000000000007ffe0) +/** R: Reserved (bits 63:19). */ +#define VTD_BF_PQT_REG_RSVD_63_19_SHIFT 19 +#define VTD_BF_PQT_REG_RSVD_63_19_MASK UINT64_C(0xfffffffffff80000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_PQT_REG_, UINT64_C(0), UINT64_MAX, + (RSVD_4_0, PQT, RSVD_63_19)); + +/** RW: Read/write mask. */ +#define VTD_PQT_REG_RW_MASK VTD_BF_PQT_REG_PQT_MASK +/** @} */ + + +/** @name Page Request Queue Address Register (PQA_REG). + * In accordance with the Intel spec. + * @{ */ +/** PQS: Page Queue Size. */ +#define VTD_BF_PQA_REG_PQS_SHIFT 0 +#define VTD_BF_PQA_REG_PQS_MASK UINT64_C(0x0000000000000007) +/** R: Reserved bits (11:3). */ +#define VTD_BF_PQA_REG_RSVD_11_3_SHIFT 3 +#define VTD_BF_PQA_REG_RSVD_11_3_MASK UINT64_C(0x0000000000000ff8) +/** PQA: Page Request Queue Base Address. */ +#define VTD_BF_PQA_REG_PQA_SHIFT 12 +#define VTD_BF_PQA_REG_PQA_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_PQA_REG_, UINT64_C(0), UINT64_MAX, + (PQS, RSVD_11_3, PQA)); + +/** RW: Read/write mask. */ +#define VTD_PQA_REG_RW_MASK (VTD_BF_PQA_REG_PQS_MASK | VTD_BF_PQA_REG_PQA_MASK) +/** @} */ + + +/** @name Page Request Status Register (PRS_REG). + * In accordance with the Intel spec. + * @{ */ +/** PPR: Pending Page Request. */ +#define VTD_BF_PRS_REG_PPR_SHIFT 0 +#define VTD_BF_PRS_REG_PPR_MASK UINT64_C(0x00000001) +/** PRO: Page Request Overflow. */ +#define VTD_BF_PRS_REG_PRO_SHIFT 1 +#define VTD_BF_PRS_REG_PRO_MASK UINT64_C(0x00000002) +/** R: Reserved (bits 31:2). */ +#define VTD_BF_PRS_REG_RSVD_31_2_SHIFT 2 +#define VTD_BF_PRS_REG_RSVD_31_2_MASK UINT64_C(0xfffffffc) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_PRS_REG_, UINT32_C(0), UINT32_MAX, + (PPR, PRO, RSVD_31_2)); + +/** RW: Read/write mask. */ +#define VTD_PRS_REG_RW_MASK (VTD_BF_PRS_REG_PPR_MASK | VTD_BF_PRS_REG_PRO_MASK) +/** RW1C: Read-only-status, Write-1-to-clear status mask. */ +#define VTD_PRS_REG_RW1C_MASK (VTD_BF_PRS_REG_PPR_MASK | VTD_BF_PRS_REG_PRO_MASK) +/** @} */ + + +/** @name Page Request Event Control Register (PECTL_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 29:0). */ +#define VTD_BF_PECTL_REG_RSVD_29_0_SHIFT 0 +#define VTD_BF_PECTL_REG_RSVD_29_0_MASK UINT32_C(0x3fffffff) +/** IP: Interrupt Pending. */ +#define VTD_BF_PECTL_REG_IP_SHIFT 30 +#define VTD_BF_PECTL_REG_IP_MASK UINT32_C(0x40000000) +/** IM: Interrupt Mask. */ +#define VTD_BF_PECTL_REG_IM_SHIFT 31 +#define VTD_BF_PECTL_REG_IM_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_PECTL_REG_, UINT32_C(0), UINT32_MAX, + (RSVD_29_0, IP, IM)); + +/** RW: Read/write mask. */ +#define VTD_PECTL_REG_RW_MASK VTD_BF_PECTL_REG_IM_MASK +/** @} */ + + +/** @name Page Request Event Data Register (PEDATA_REG). + * In accordance with the Intel spec. + * @{ */ +/** IMD: Interrupt Message Data. */ +#define VTD_BF_PEDATA_REG_IMD_SHIFT 0 +#define VTD_BF_PEDATA_REG_IMD_MASK UINT32_C(0x0000ffff) +/** R: Reserved (bits 31:16). VT-d specs. prior to 2021 had EIMD here. */ +#define VTD_BF_PEDATA_REG_RSVD_31_16_SHIFT 16 +#define VTD_BF_PEDATA_REG_RSVD_31_16_MASK UINT32_C(0xffff0000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_PEDATA_REG_, UINT32_C(0), UINT32_MAX, + (IMD, RSVD_31_16)); + +/** RW: Read/write mask, see 5.1.6 "Remapping Hardware Event Interrupt + * Programming". */ +#define VTD_PEDATA_REG_RW_MASK UINT32_C(0x000001ff) +/** @} */ + + +/** @name Page Request Event Address Register (PEADDR_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 1:0). */ +#define VTD_BF_PEADDR_REG_RSVD_1_0_SHIFT 0 +#define VTD_BF_PEADDR_REG_RSVD_1_0_MASK UINT32_C(0x00000003) +/** MA: Message Address. */ +#define VTD_BF_PEADDR_REG_MA_SHIFT 2 +#define VTD_BF_PEADDR_REG_MA_MASK UINT32_C(0xfffffffc) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_PEADDR_REG_, UINT32_C(0), UINT32_MAX, + (RSVD_1_0, MA)); + +/** RW: Read/write mask. */ +#define VTD_PEADDR_REG_RW_MASK VTD_BF_PEADDR_REG_MA_MASK +/** @} */ + + + +/** @name Page Request Event Upper Address Register (PEUADDR_REG). + * In accordance with the Intel spec. + * @{ */ +/** MA: Message Address. */ +#define VTD_BF_PEUADDR_REG_MUA_SHIFT 0 +#define VTD_BF_PEUADDR_REG_MUA_MASK UINT32_C(0xffffffff) + +/** RW: Read/write mask. */ +#define VTD_PEUADDR_REG_RW_MASK VTD_BF_PEUADDR_REG_MUA_MASK +/** @} */ + + +/** @name MTRR Capability Register (MTRRCAP_REG). + * In accordance with the Intel spec. + * @{ */ +/** VCNT: Variable MTRR Count. */ +#define VTD_BF_MTRRCAP_REG_VCNT_SHIFT 0 +#define VTD_BF_MTRRCAP_REG_VCNT_MASK UINT64_C(0x00000000000000ff) +/** FIX: Fixed range MTRRs Supported. */ +#define VTD_BF_MTRRCAP_REG_FIX_SHIFT 8 +#define VTD_BF_MTRRCAP_REG_FIX_MASK UINT64_C(0x0000000000000100) +/** R: Reserved (bit 9). */ +#define VTD_BF_MTRRCAP_REG_RSVD_9_SHIFT 9 +#define VTD_BF_MTRRCAP_REG_RSVD_9_MASK UINT64_C(0x0000000000000200) +/** WC: Write Combining. */ +#define VTD_BF_MTRRCAP_REG_WC_SHIFT 10 +#define VTD_BF_MTRRCAP_REG_WC_MASK UINT64_C(0x0000000000000400) +/** R: Reserved (bits 63:11). */ +#define VTD_BF_MTRRCAP_REG_RSVD_63_11_SHIFT 11 +#define VTD_BF_MTRRCAP_REG_RSVD_63_11_MASK UINT64_C(0xfffffffffffff800) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_MTRRCAP_REG_, UINT64_C(0), UINT64_MAX, + (VCNT, FIX, RSVD_9, WC, RSVD_63_11)); + +/** RW: Read/write mask. */ +#define VTD_MTRRCAP_REG_RW_MASK UINT64_C(0) +/** @} */ + + +/** @name MTRR Default Type Register (MTRRDEF_REG). + * In accordance with the Intel spec. + * @{ */ +/** TYPE: Default Memory Type. */ +#define VTD_BF_MTRRDEF_REG_TYPE_SHIFT 0 +#define VTD_BF_MTRRDEF_REG_TYPE_MASK UINT64_C(0x00000000000000ff) +/** R: Reserved (bits 9:8). */ +#define VTD_BF_MTRRDEF_REG_RSVD_9_8_SHIFT 8 +#define VTD_BF_MTRRDEF_REG_RSVD_9_8_MASK UINT64_C(0x0000000000000300) +/** FE: Fixed Range MTRR Enable. */ +#define VTD_BF_MTRRDEF_REG_FE_SHIFT 10 +#define VTD_BF_MTRRDEF_REG_FE_MASK UINT64_C(0x0000000000000400) +/** E: MTRR Enable. */ +#define VTD_BF_MTRRDEF_REG_E_SHIFT 11 +#define VTD_BF_MTRRDEF_REG_E_MASK UINT64_C(0x0000000000000800) +/** R: Reserved (bits 63:12). */ +#define VTD_BF_MTRRDEF_REG_RSVD_63_12_SHIFT 12 +#define VTD_BF_MTRRDEF_REG_RSVD_63_12_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_MTRRDEF_REG_, UINT64_C(0), UINT64_MAX, + (TYPE, RSVD_9_8, FE, E, RSVD_63_12)); + +/** RW: Read/write mask. */ +#define VTD_MTRRDEF_REG_RW_MASK ( VTD_BF_MTRRDEF_REG_TYPE_MASK | VTD_BF_MTRRDEF_REG_FE_MASK \ + | VTD_BF_MTRRDEF_REG_E_MASK) +/** @} */ + + +/** @name Virtual Command Capability Register (VCCAP_REG). + * In accordance with the Intel spec. + * @{ */ +/** PAS: PASID Support. */ +#define VTD_BF_VCCAP_REG_PAS_SHIFT 0 +#define VTD_BF_VCCAP_REG_PAS_MASK UINT64_C(0x0000000000000001) +/** R: Reserved (bits 63:1). */ +#define VTD_BF_VCCAP_REG_RSVD_63_1_SHIFT 1 +#define VTD_BF_VCCAP_REG_RSVD_63_1_MASK UINT64_C(0xfffffffffffffffe) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_VCCAP_REG_, UINT64_C(0), UINT64_MAX, + (PAS, RSVD_63_1)); + +/** RW: Read/write mask. */ +#define VTD_VCCAP_REG_RW_MASK UINT64_C(0) +/** @} */ + + +/** @name Virtual Command Extended Operand Register (VCMD_EO_REG). + * In accordance with the Intel spec. + * @{ */ +/** OB: Operand B. */ +#define VTD_BF_VCMD_EO_REG_OB_SHIFT 0 +#define VTD_BF_VCMD_EO_REG_OB_MASK UINT32_C(0xffffffffffffffff) + +/** RW: Read/write mask. */ +#define VTD_VCMD_EO_REG_RW_MASK VTD_BF_VCMD_EO_REG_OB_MASK +/** @} */ + + +/** @name Virtual Command Register (VCMD_REG). + * In accordance with the Intel spec. + * @{ */ +/** CMD: Command. */ +#define VTD_BF_VCMD_REG_CMD_SHIFT 0 +#define VTD_BF_VCMD_REG_CMD_MASK UINT64_C(0x00000000000000ff) +/** OP: Operand. */ +#define VTD_BF_VCMD_REG_OP_SHIFT 8 +#define VTD_BF_VCMD_REG_OP_MASK UINT64_C(0xffffffffffffff00) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_VCMD_REG_, UINT64_C(0), UINT64_MAX, + (CMD, OP)); + +/** RW: Read/write mask. */ +#define VTD_VCMD_REG_RW_MASK (VTD_BF_VCMD_REG_CMD_MASK | VTD_BF_VCMD_REG_OP_MASK) +/** @} */ + + +/** @name Virtual Command Response Register (VCRSP_REG). + * In accordance with the Intel spec. + * @{ */ +/** IP: In Progress. */ +#define VTD_BF_VCRSP_REG_IP_SHIFT 0 +#define VTD_BF_VCRSP_REG_IP_MASK UINT64_C(0x0000000000000001) +/** SC: Status Code. */ +#define VTD_BF_VCRSP_REG_SC_SHIFT 1 +#define VTD_BF_VCRSP_REG_SC_MASK UINT64_C(0x0000000000000006) +/** R: Reserved (bits 7:3). */ +#define VTD_BF_VCRSP_REG_RSVD_7_3_SHIFT 3 +#define VTD_BF_VCRSP_REG_RSVD_7_3_MASK UINT64_C(0x00000000000000f8) +/** RSLT: Result. */ +#define VTD_BF_VCRSP_REG_RSLT_SHIFT 8 +#define VTD_BF_VCRSP_REG_RSLT_MASK UINT64_C(0xffffffffffffff00) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_VCRSP_REG_, UINT64_C(0), UINT64_MAX, + (IP, SC, RSVD_7_3, RSLT)); + +/** RW: Read/write mask. */ +#define VTD_VCRSP_REG_RW_MASK UINT64_C(0) +/** @} */ + + +/** @name Generic Invalidation Descriptor. + * In accordance with the Intel spec. + * Non-reserved fields here are common to all invalidation descriptors. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_GENERIC_INV_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_GENERIC_INV_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** R: Reserved (bits 8:4). */ +#define VTD_BF_0_GENERIC_INV_DSC_RSVD_8_4_SHIFT 4 +#define VTD_BF_0_GENERIC_INV_DSC_RSVD_8_4_MASK UINT64_C(0x00000000000001f0) +/** Type (Hi). */ +#define VTD_BF_0_GENERIC_INV_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_GENERIC_INV_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** R: Reserved (bits 63:12). */ +#define VTD_BF_0_GENERIC_INV_DSC_RSVD_63_12_SHIFT 12 +#define VTD_BF_0_GENERIC_INV_DSC_RSVD_63_12_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_GENERIC_INV_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, RSVD_8_4, TYPE_HI, RSVD_63_12)); + +/** GENERIC_INV_DSC: Type. */ +#define VTD_GENERIC_INV_DSC_GET_TYPE(a) ((((a) & VTD_BF_0_GENERIC_INV_DSC_TYPE_HI_MASK) >> 5) \ + | ((a) & VTD_BF_0_GENERIC_INV_DSC_TYPE_LO_MASK)) +/** @} */ + + +/** @name Context-Cache Invalidation Descriptor (cc_inv_dsc). + * In accordance with the Intel spec. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_CC_INV_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_CC_INV_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** G: Granularity. */ +#define VTD_BF_0_CC_INV_DSC_G_SHIFT 4 +#define VTD_BF_0_CC_INV_DSC_G_MASK UINT64_C(0x0000000000000030) +/** R: Reserved (bits 8:6). */ +#define VTD_BF_0_CC_INV_DSC_RSVD_8_6_SHIFT 6 +#define VTD_BF_0_CC_INV_DSC_RSVD_8_6_MASK UINT64_C(0x00000000000001c0) +/** Type (Hi). */ +#define VTD_BF_0_CC_INV_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_CC_INV_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** R: Reserved (bits 15:12). */ +#define VTD_BF_0_CC_INV_DSC_RSVD_15_12_SHIFT 12 +#define VTD_BF_0_CC_INV_DSC_RSVD_15_12_MASK UINT64_C(0x000000000000f000) +/** DID: Domain Id. */ +#define VTD_BF_0_CC_INV_DSC_DID_SHIFT 16 +#define VTD_BF_0_CC_INV_DSC_DID_MASK UINT64_C(0x00000000ffff0000) +/** SID: Source Id. */ +#define VTD_BF_0_CC_INV_DSC_SID_SHIFT 32 +#define VTD_BF_0_CC_INV_DSC_SID_MASK UINT64_C(0x0000ffff00000000) +/** FM: Function Mask. */ +#define VTD_BF_0_CC_INV_DSC_FM_SHIFT 48 +#define VTD_BF_0_CC_INV_DSC_FM_MASK UINT64_C(0x0003000000000000) +/** R: Reserved (bits 63:50). */ +#define VTD_BF_0_CC_INV_DSC_RSVD_63_50_SHIFT 50 +#define VTD_BF_0_CC_INV_DSC_RSVD_63_50_MASK UINT64_C(0xfffc000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_CC_INV_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, G, RSVD_8_6, TYPE_HI, RSVD_15_12, DID, SID, FM, RSVD_63_50)); +/** @} */ + + +/** @name PASID-Cache Invalidation Descriptor (pc_inv_dsc). + * In accordance with the Intel spec. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_PC_INV_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_PC_INV_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** G: Granularity. */ +#define VTD_BF_0_PC_INV_DSC_G_SHIFT 4 +#define VTD_BF_0_PC_INV_DSC_G_MASK UINT64_C(0x0000000000000030) +/** R: Reserved (bits 8:6). */ +#define VTD_BF_0_PC_INV_DSC_RSVD_8_6_SHIFT 6 +#define VTD_BF_0_PC_INV_DSC_RSVD_8_6_MASK UINT64_C(0x00000000000001c0) +/** Type (Hi). */ +#define VTD_BF_0_PC_INV_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_PC_INV_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** R: Reserved (bits 15:12). */ +#define VTD_BF_0_PC_INV_DSC_RSVD_15_12_SHIFT 12 +#define VTD_BF_0_PC_INV_DSC_RSVD_15_12_MASK UINT64_C(0x000000000000f000) +/** DID: Domain Id. */ +#define VTD_BF_0_PC_INV_DSC_DID_SHIFT 16 +#define VTD_BF_0_PC_INV_DSC_DID_MASK UINT64_C(0x00000000ffff0000) +/** PASID: Process Address-Space Id. */ +#define VTD_BF_0_PC_INV_DSC_PASID_SHIFT 32 +#define VTD_BF_0_PC_INV_DSC_PASID_MASK UINT64_C(0x000fffff00000000) +/** R: Reserved (bits 63:52). */ +#define VTD_BF_0_PC_INV_DSC_RSVD_63_52_SHIFT 52 +#define VTD_BF_0_PC_INV_DSC_RSVD_63_52_MASK UINT64_C(0xfff0000000000000) + +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_PC_INV_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, G, RSVD_8_6, TYPE_HI, RSVD_15_12, DID, PASID, RSVD_63_52)); +/** @} */ + + +/** @name IOTLB Invalidate Descriptor (iotlb_inv_dsc). + * In accordance with the Intel spec. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_IOTLB_INV_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_IOTLB_INV_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** G: Granularity. */ +#define VTD_BF_0_IOTLB_INV_DSC_G_SHIFT 4 +#define VTD_BF_0_IOTLB_INV_DSC_G_MASK UINT64_C(0x0000000000000030) +/** DW: Drain Writes. */ +#define VTD_BF_0_IOTLB_INV_DSC_DW_SHIFT 6 +#define VTD_BF_0_IOTLB_INV_DSC_DW_MASK UINT64_C(0x0000000000000040) +/** DR: Drain Reads. */ +#define VTD_BF_0_IOTLB_INV_DSC_DR_SHIFT 7 +#define VTD_BF_0_IOTLB_INV_DSC_DR_MASK UINT64_C(0x0000000000000080) +/** R: Reserved (bit 8). */ +#define VTD_BF_0_IOTLB_INV_DSC_RSVD_8_SHIFT 8 +#define VTD_BF_0_IOTLB_INV_DSC_RSVD_8_MASK UINT64_C(0x0000000000000100) +/** Type (Hi). */ +#define VTD_BF_0_IOTLB_INV_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_IOTLB_INV_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** R: Reserved (bits 15:12). */ +#define VTD_BF_0_IOTLB_INV_DSC_RSVD_15_12_SHIFT 12 +#define VTD_BF_0_IOTLB_INV_DSC_RSVD_15_12_MASK UINT64_C(0x000000000000f000) +/** DID: Domain Id. */ +#define VTD_BF_0_IOTLB_INV_DSC_DID_SHIFT 16 +#define VTD_BF_0_IOTLB_INV_DSC_DID_MASK UINT64_C(0x00000000ffff0000) +/** R: Reserved (bits 63:32). */ +#define VTD_BF_0_IOTLB_INV_DSC_RSVD_63_32_SHIFT 32 +#define VTD_BF_0_IOTLB_INV_DSC_RSVD_63_32_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_IOTLB_INV_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, G, DW, DR, RSVD_8, TYPE_HI, RSVD_15_12, DID, RSVD_63_32)); + +/** AM: Address Mask. */ +#define VTD_BF_1_IOTLB_INV_DSC_AM_SHIFT 0 +#define VTD_BF_1_IOTLB_INV_DSC_AM_MASK UINT64_C(0x000000000000003f) +/** IH: Invalidation Hint. */ +#define VTD_BF_1_IOTLB_INV_DSC_IH_SHIFT 6 +#define VTD_BF_1_IOTLB_INV_DSC_IH_MASK UINT64_C(0x0000000000000040) +/** R: Reserved (bits 11:7). */ +#define VTD_BF_1_IOTLB_INV_DSC_RSVD_11_7_SHIFT 7 +#define VTD_BF_1_IOTLB_INV_DSC_RSVD_11_7_MASK UINT64_C(0x0000000000000f80) +/** ADDR: Address. */ +#define VTD_BF_1_IOTLB_INV_DSC_ADDR_SHIFT 12 +#define VTD_BF_1_IOTLB_INV_DSC_ADDR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_IOTLB_INV_DSC_, UINT64_C(0), UINT64_MAX, + (AM, IH, RSVD_11_7, ADDR)); +/** @} */ + + +/** @name PASID-based IOTLB Invalidate Descriptor (p_iotlb_inv_dsc). + * In accordance with the Intel spec. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_P_IOTLB_INV_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_P_IOTLB_INV_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** G: Granularity. */ +#define VTD_BF_0_P_IOTLB_INV_DSC_G_SHIFT 4 +#define VTD_BF_0_P_IOTLB_INV_DSC_G_MASK UINT64_C(0x0000000000000030) +/** R: Reserved (bits 8:6). */ +#define VTD_BF_0_P_IOTLB_INV_DSC_RSVD_8_6_SHIFT 6 +#define VTD_BF_0_P_IOTLB_INV_DSC_RSVD_8_6_MASK UINT64_C(0x00000000000001c0) +/** Type (Hi). */ +#define VTD_BF_0_P_IOTLB_INV_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_P_IOTLB_INV_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** R: Reserved (bits 15:12). */ +#define VTD_BF_0_P_IOTLB_INV_DSC_RSVD_15_12_SHIFT 12 +#define VTD_BF_0_P_IOTLB_INV_DSC_RSVD_15_12_MASK UINT64_C(0x000000000000f000) +/** DID: Domain Id. */ +#define VTD_BF_0_P_IOTLB_INV_DSC_DID_SHIFT 16 +#define VTD_BF_0_P_IOTLB_INV_DSC_DID_MASK UINT64_C(0x00000000ffff0000) +/** PASID: Process Address-Space Id. */ +#define VTD_BF_0_P_IOTLB_INV_DSC_PASID_SHIFT 32 +#define VTD_BF_0_P_IOTLB_INV_DSC_PASID_MASK UINT64_C(0x000fffff00000000) +/** R: Reserved (bits 63:52). */ +#define VTD_BF_0_P_IOTLB_INV_DSC_RSVD_63_52_SHIFT 52 +#define VTD_BF_0_P_IOTLB_INV_DSC_RSVD_63_52_MASK UINT64_C(0xfff0000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_P_IOTLB_INV_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, G, RSVD_8_6, TYPE_HI, RSVD_15_12, DID, PASID, RSVD_63_52)); + + +/** AM: Address Mask. */ +#define VTD_BF_1_P_IOTLB_INV_DSC_AM_SHIFT 0 +#define VTD_BF_1_P_IOTLB_INV_DSC_AM_MASK UINT64_C(0x000000000000003f) +/** IH: Invalidation Hint. */ +#define VTD_BF_1_P_IOTLB_INV_DSC_IH_SHIFT 6 +#define VTD_BF_1_P_IOTLB_INV_DSC_IH_MASK UINT64_C(0x0000000000000040) +/** R: Reserved (bits 11:7). */ +#define VTD_BF_1_P_IOTLB_INV_DSC_RSVD_11_7_SHIFT 7 +#define VTD_BF_1_P_IOTLB_INV_DSC_RSVD_11_7_MASK UINT64_C(0x0000000000000f80) +/** ADDR: Address. */ +#define VTD_BF_1_P_IOTLB_INV_DSC_ADDR_SHIFT 12 +#define VTD_BF_1_P_IOTLB_INV_DSC_ADDR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_P_IOTLB_INV_DSC_, UINT64_C(0), UINT64_MAX, + (AM, IH, RSVD_11_7, ADDR)); +/** @} */ + + +/** @name Device-TLB Invalidate Descriptor (dev_tlb_inv_dsc). + * In accordance with the Intel spec. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_DEV_TLB_INV_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_DEV_TLB_INV_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** R: Reserved (bits 8:4). */ +#define VTD_BF_0_DEV_TLB_INV_DSC_RSVD_8_4_SHIFT 4 +#define VTD_BF_0_DEV_TLB_INV_DSC_RSVD_8_4_MASK UINT64_C(0x00000000000001f0) +/** Type (Hi). */ +#define VTD_BF_0_DEV_TLB_INV_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_DEV_TLB_INV_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** PFSID: Physical-Function Source Id (Lo). */ +#define VTD_BF_0_DEV_TLB_INV_DSC_PFSID_LO_SHIFT 12 +#define VTD_BF_0_DEV_TLB_INV_DSC_PFSID_LO_MASK UINT64_C(0x000000000000f000) +/** MIP: Max Invalidations Pending. */ +#define VTD_BF_0_DEV_TLB_INV_DSC_MIP_SHIFT 16 +#define VTD_BF_0_DEV_TLB_INV_DSC_MIP_MASK UINT64_C(0x00000000001f0000) +/** R: Reserved (bits 31:21). */ +#define VTD_BF_0_DEV_TLB_INV_DSC_RSVD_31_21_SHIFT 21 +#define VTD_BF_0_DEV_TLB_INV_DSC_RSVD_31_21_MASK UINT64_C(0x00000000ffe00000) +/** SID: Source Id. */ +#define VTD_BF_0_DEV_TLB_INV_DSC_SID_SHIFT 32 +#define VTD_BF_0_DEV_TLB_INV_DSC_SID_MASK UINT64_C(0x0000ffff00000000) +/** R: Reserved (bits 51:48). */ +#define VTD_BF_0_DEV_TLB_INV_DSC_RSVD_51_48_SHIFT 48 +#define VTD_BF_0_DEV_TLB_INV_DSC_RSVD_51_48_MASK UINT64_C(0x000f000000000000) +/** PFSID: Physical-Function Source Id (Hi). */ +#define VTD_BF_0_DEV_TLB_INV_DSC_PFSID_HI_SHIFT 52 +#define VTD_BF_0_DEV_TLB_INV_DSC_PFSID_HI_MASK UINT64_C(0xfff0000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_DEV_TLB_INV_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, RSVD_8_4, TYPE_HI, PFSID_LO, MIP, RSVD_31_21, SID, RSVD_51_48, PFSID_HI)); + +/** S: Size. */ +#define VTD_BF_1_DEV_TLB_INV_DSC_S_SHIFT 0 +#define VTD_BF_1_DEV_TLB_INV_DSC_S_MASK UINT64_C(0x0000000000000001) +/** R: Reserved (bits 11:1). */ +#define VTD_BF_1_DEV_TLB_INV_DSC_RSVD_11_1_SHIFT 1 +#define VTD_BF_1_DEV_TLB_INV_DSC_RSVD_11_1_MASK UINT64_C(0x0000000000000ffe) +/** ADDR: Address. */ +#define VTD_BF_1_DEV_TLB_INV_DSC_ADDR_SHIFT 12 +#define VTD_BF_1_DEV_TLB_INV_DSC_ADDR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_DEV_TLB_INV_DSC_, UINT64_C(0), UINT64_MAX, + (S, RSVD_11_1, ADDR)); +/** @} */ + + +/** @name PASID-based-device-TLB Invalidate Descriptor (p_dev_tlb_inv_dsc). + * In accordance with the Intel spec. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_P_DEV_TLB_INV_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_P_DEV_TLB_INV_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** MIP: Max Invalidations Pending. */ +#define VTD_BF_0_P_DEV_TLB_INV_DSC_MIP_SHIFT 4 +#define VTD_BF_0_P_DEV_TLB_INV_DSC_MIP_MASK UINT64_C(0x00000000000001f0) +/** Type (Hi). */ +#define VTD_BF_0_P_DEV_TLB_INV_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_P_DEV_TLB_INV_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** PFSID: Physical-Function Source Id (Lo). */ +#define VTD_BF_0_P_DEV_TLB_INV_DSC_PFSID_LO_SHIFT 12 +#define VTD_BF_0_P_DEV_TLB_INV_DSC_PFSID_LO_MASK UINT64_C(0x000000000000f000) +/** SID: Source Id. */ +#define VTD_BF_0_P_DEV_TLB_INV_DSC_SID_SHIFT 16 +#define VTD_BF_0_P_DEV_TLB_INV_DSC_SID_MASK UINT64_C(0x00000000ffff0000) +/** PASID: Process Address-Space Id. */ +#define VTD_BF_0_P_DEV_TLB_INV_DSC_PASID_SHIFT 32 +#define VTD_BF_0_P_DEV_TLB_INV_DSC_PASID_MASK UINT64_C(0x000fffff00000000) +/** PFSID: Physical-Function Source Id (Hi). */ +#define VTD_BF_0_P_DEV_TLB_INV_DSC_PFSID_HI_SHIFT 52 +#define VTD_BF_0_P_DEV_TLB_INV_DSC_PFSID_HI_MASK UINT64_C(0xfff0000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_P_DEV_TLB_INV_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, MIP, TYPE_HI, PFSID_LO, SID, PASID, PFSID_HI)); + +/** G: Granularity. */ +#define VTD_BF_1_P_DEV_TLB_INV_DSC_G_SHIFT 0 +#define VTD_BF_1_P_DEV_TLB_INV_DSC_G_MASK UINT64_C(0x0000000000000001) +/** R: Reserved (bits 10:1). */ +#define VTD_BF_1_P_DEV_TLB_INV_DSC_RSVD_10_1_SHIFT 1 +#define VTD_BF_1_P_DEV_TLB_INV_DSC_RSVD_10_1_MASK UINT64_C(0x00000000000007fe) +/** S: Size. */ +#define VTD_BF_1_P_DEV_TLB_INV_DSC_S_SHIFT 11 +#define VTD_BF_1_P_DEV_TLB_INV_DSC_S_MASK UINT64_C(0x0000000000000800) +/** ADDR: Address. */ +#define VTD_BF_1_P_DEV_TLB_INV_DSC_ADDR_SHIFT 12 +#define VTD_BF_1_P_DEV_TLB_INV_DSC_ADDR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_P_DEV_TLB_INV_DSC_, UINT64_C(0), UINT64_MAX, + (G, RSVD_10_1, S, ADDR)); +/** @} */ + + +/** @name Interrupt Entry Cache Invalidate Descriptor (iec_inv_dsc). + * In accordance with the Intel spec. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_IEC_INV_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_IEC_INV_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** G: Granularity. */ +#define VTD_BF_0_IEC_INV_DSC_G_SHIFT 4 +#define VTD_BF_0_IEC_INV_DSC_G_MASK UINT64_C(0x0000000000000010) +/** R: Reserved (bits 8:5). */ +#define VTD_BF_0_IEC_INV_DSC_RSVD_8_5_SHIFT 5 +#define VTD_BF_0_IEC_INV_DSC_RSVD_8_5_MASK UINT64_C(0x00000000000001e0) +/** Type (Hi). */ +#define VTD_BF_0_IEC_INV_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_IEC_INV_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** R: Reserved (bits 26:12). */ +#define VTD_BF_0_IEC_INV_DSC_RSVD_26_12_SHIFT 12 +#define VTD_BF_0_IEC_INV_DSC_RSVD_26_12_MASK UINT64_C(0x0000000007fff000) +/** IM: Index Mask. */ +#define VTD_BF_0_IEC_INV_DSC_IM_SHIFT 27 +#define VTD_BF_0_IEC_INV_DSC_IM_MASK UINT64_C(0x00000000f8000000) +/** IIDX: Interrupt Index. */ +#define VTD_BF_0_IEC_INV_DSC_IIDX_SHIFT 32 +#define VTD_BF_0_IEC_INV_DSC_IIDX_MASK UINT64_C(0x0000ffff00000000) +/** R: Reserved (bits 63:48). */ +#define VTD_BF_0_IEC_INV_DSC_RSVD_63_48_SHIFT 48 +#define VTD_BF_0_IEC_INV_DSC_RSVD_63_48_MASK UINT64_C(0xffff000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_IEC_INV_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, G, RSVD_8_5, TYPE_HI, RSVD_26_12, IM, IIDX, RSVD_63_48)); +/** @} */ + + +/** @name Invalidation Wait Descriptor (inv_wait_dsc). + * In accordance with the Intel spec. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_INV_WAIT_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_INV_WAIT_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** IF: Interrupt Flag. */ +#define VTD_BF_0_INV_WAIT_DSC_IF_SHIFT 4 +#define VTD_BF_0_INV_WAIT_DSC_IF_MASK UINT64_C(0x0000000000000010) +/** SW: Status Write. */ +#define VTD_BF_0_INV_WAIT_DSC_SW_SHIFT 5 +#define VTD_BF_0_INV_WAIT_DSC_SW_MASK UINT64_C(0x0000000000000020) +/** FN: Fence Flag. */ +#define VTD_BF_0_INV_WAIT_DSC_FN_SHIFT 6 +#define VTD_BF_0_INV_WAIT_DSC_FN_MASK UINT64_C(0x0000000000000040) +/** PD: Page-Request Drain. */ +#define VTD_BF_0_INV_WAIT_DSC_PD_SHIFT 7 +#define VTD_BF_0_INV_WAIT_DSC_PD_MASK UINT64_C(0x0000000000000080) +/** R: Reserved (bit 8). */ +#define VTD_BF_0_INV_WAIT_DSC_RSVD_8_SHIFT 8 +#define VTD_BF_0_INV_WAIT_DSC_RSVD_8_MASK UINT64_C(0x0000000000000100) +/** Type (Hi). */ +#define VTD_BF_0_INV_WAIT_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_INV_WAIT_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** R: Reserved (bits 31:12). */ +#define VTD_BF_0_INV_WAIT_DSC_RSVD_31_12_SHIFT 12 +#define VTD_BF_0_INV_WAIT_DSC_RSVD_31_12_MASK UINT64_C(0x00000000fffff000) +/** STDATA: Status Data. */ +#define VTD_BF_0_INV_WAIT_DSC_STDATA_SHIFT 32 +#define VTD_BF_0_INV_WAIT_DSC_STDATA_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_INV_WAIT_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, IF, SW, FN, PD, RSVD_8, TYPE_HI, RSVD_31_12, STDATA)); + +/** R: Reserved (bits 1:0). */ +#define VTD_BF_1_INV_WAIT_DSC_RSVD_1_0_SHIFT 0 +#define VTD_BF_1_INV_WAIT_DSC_RSVD_1_0_MASK UINT64_C(0x0000000000000003) +/** STADDR: Status Address. */ +#define VTD_BF_1_INV_WAIT_DSC_STADDR_SHIFT 2 +#define VTD_BF_1_INV_WAIT_DSC_STADDR_MASK UINT64_C(0xfffffffffffffffc) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_INV_WAIT_DSC_, UINT64_C(0), UINT64_MAX, + (RSVD_1_0, STADDR)); + +/* INV_WAIT_DSC: Qword 0 valid mask. */ +#define VTD_INV_WAIT_DSC_0_VALID_MASK ( VTD_BF_0_INV_WAIT_DSC_TYPE_LO_MASK \ + | VTD_BF_0_INV_WAIT_DSC_IF_MASK \ + | VTD_BF_0_INV_WAIT_DSC_SW_MASK \ + | VTD_BF_0_INV_WAIT_DSC_FN_MASK \ + | VTD_BF_0_INV_WAIT_DSC_PD_MASK \ + | VTD_BF_0_INV_WAIT_DSC_TYPE_HI_MASK \ + | VTD_BF_0_INV_WAIT_DSC_STDATA_MASK) +/* INV_WAIT_DSC: Qword 1 valid mask. */ +#define VTD_INV_WAIT_DSC_1_VALID_MASK VTD_BF_1_INV_WAIT_DSC_STADDR_MASK +/** @} */ + + +/** @name Invalidation descriptor types. + * In accordance with the Intel spec. + * @{ */ +#define VTD_CC_INV_DSC_TYPE 1 +#define VTD_IOTLB_INV_DSC_TYPE 2 +#define VTD_DEV_TLB_INV_DSC_TYPE 3 +#define VTD_IEC_INV_DSC_TYPE 4 +#define VTD_INV_WAIT_DSC_TYPE 5 +#define VTD_P_IOTLB_INV_DSC_TYPE 6 +#define VTD_PC_INV_DSC_TYPE 7 +#define VTD_P_DEV_TLB_INV_DSC_TYPE 8 +/** @} */ + + +/** @name Remappable Format Interrupt Request. + * In accordance with the Intel spec. + * @{ */ +/** IGN: Ignored (bits 1:0). */ +#define VTD_BF_REMAPPABLE_MSI_ADDR_IGN_1_0_SHIFT 0 +#define VTD_BF_REMAPPABLE_MSI_ADDR_IGN_1_0_MASK UINT32_C(0x00000003) +/** Handle (Hi). */ +#define VTD_BF_REMAPPABLE_MSI_ADDR_HANDLE_HI_SHIFT 2 +#define VTD_BF_REMAPPABLE_MSI_ADDR_HANDLE_HI_MASK UINT32_C(0x00000004) +/** SHV: Subhandle Valid. */ +#define VTD_BF_REMAPPABLE_MSI_ADDR_SHV_SHIFT 3 +#define VTD_BF_REMAPPABLE_MSI_ADDR_SHV_MASK UINT32_C(0x00000008) +/** Interrupt format. */ +#define VTD_BF_REMAPPABLE_MSI_ADDR_INTR_FMT_SHIFT 4 +#define VTD_BF_REMAPPABLE_MSI_ADDR_INTR_FMT_MASK UINT32_C(0x00000010) +/** Handle (Lo). */ +#define VTD_BF_REMAPPABLE_MSI_ADDR_HANDLE_LO_SHIFT 5 +#define VTD_BF_REMAPPABLE_MSI_ADDR_HANDLE_LO_MASK UINT32_C(0x000fffe0) +/** Address. */ +#define VTD_BF_REMAPPABLE_MSI_ADDR_ADDR_SHIFT 20 +#define VTD_BF_REMAPPABLE_MSI_ADDR_ADDR_MASK UINT32_C(0xfff00000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_REMAPPABLE_MSI_ADDR_, UINT32_C(0), UINT32_MAX, + (IGN_1_0, HANDLE_HI, SHV, INTR_FMT, HANDLE_LO, ADDR)); + +/** Subhandle. */ +#define VTD_BF_REMAPPABLE_MSI_DATA_SUBHANDLE_SHIFT 0 +#define VTD_BF_REMAPPABLE_MSI_DATA_SUBHANDLE_MASK UINT32_C(0x0000ffff) +/** R: Reserved (bits 31:16). */ +#define VTD_BF_REMAPPABLE_MSI_DATA_RSVD_31_16_SHIFT 16 +#define VTD_BF_REMAPPABLE_MSI_DATA_RSVD_31_16_MASK UINT32_C(0xffff0000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_REMAPPABLE_MSI_DATA_, UINT32_C(0), UINT32_MAX, + (SUBHANDLE, RSVD_31_16)); + +/** Remappable MSI Address: Valid mask. */ +#define VTD_REMAPPABLE_MSI_ADDR_VALID_MASK UINT32_MAX +/** Remappable MSI Data: Valid mask. */ +#define VTD_REMAPPABLE_MSI_DATA_VALID_MASK VTD_BF_REMAPPABLE_MSI_DATA_SUBHANDLE_MASK + +/** Interrupt format: Compatibility. */ +#define VTD_INTR_FORMAT_COMPAT 0 +/** Interrupt format: Remappable. */ +#define VTD_INTR_FORMAT_REMAPPABLE 1 +/** @} */ + + +/** @name Interrupt Remapping Fault Conditions. + * In accordance with the Intel spec. + * @{ */ +typedef enum VTDIRFAULT +{ + /** Reserved bits invalid in remappable interrupt. */ + VTDIRFAULT_REMAPPABLE_INTR_RSVD = 0x20, + + /** Interrupt index for remappable interrupt exceeds table size or referenced + * address above host address width (HAW) */ + VTDIRFAULT_INTR_INDEX_INVALID = 0x21, + + /** The IRTE is not present. */ + VTDIRFAULT_IRTE_NOT_PRESENT = 0x22, + /** Reading IRTE from memory failed. */ + VTDIRFAULT_IRTE_READ_FAILED = 0x23, + /** IRTE reserved bits invalid for an IRTE with Present bit set. */ + VTDIRFAULT_IRTE_PRESENT_RSVD = 0x24, + + /** Compatibility format interrupt (CFI) blocked due to EIME being enabled or CFIs + * were disabled. */ + VTDIRFAULT_CFI_BLOCKED = 0x25, + + /** IRTE SID, SVT, SQ bits invalid for an IRTE with Present bit set. */ + VTDIRFAULT_IRTE_PRESENT_INVALID = 0x26, + + /** Reading posted interrupt descriptor (PID) failed. */ + VTDIRFAULT_PID_READ_FAILED = 0x27, + /** PID reserved bits invalid. */ + VTDIRFAULT_PID_RSVD = 0x28, + + /** Untranslated interrupt requested (without PASID) is invalid. */ + VTDIRFAULT_IR_WITHOUT_PASID_INVALID = 0x29 +} VTDIRFAULT; +AssertCompileSize(VTDIRFAULT, 4); +/** @} */ + + +/** @name Address Translation Fault Conditions. + * In accordance with the Intel spec. + * @{ */ +typedef enum VTDATFAULT +{ + /* Legacy root table faults (LRT). */ + VTDATFAULT_LRT_1 = 0x8, + VTDATFAULT_LRT_2 = 0x1, + VTDATFAULT_LRT_3 = 0xa, + + /* Legacy Context-Table Faults (LCT). */ + VTDATFAULT_LCT_1 = 0x9, + VTDATFAULT_LCT_2 = 0x2, + VTDATFAULT_LCT_3 = 0xb, + VTDATFAULT_LCT_4_1 = 0x3, + VTDATFAULT_LCT_4_2 = 0x3, + VTDATFAULT_LCT_4_3 = 0x3, + VTDATFAULT_LCT_5 = 0xd, + + /* Legacy Second-Level Table Faults (LSL). */ + VTDATFAULT_LSL_1 = 0x7, + VTDATFAULT_LSL_2 = 0xc, + + /* Legacy General Faults (LGN). */ + VTDATFAULT_LGN_1_1 = 0x4, + VTDATFAULT_LGN_1_2 = 0x4, + VTDATFAULT_LGN_1_3 = 0x4, + VTDATFAULT_LGN_2 = 0x5, + VTDATFAULT_LGN_3 = 0x6, + VTDATFAULT_LGN_4 = 0xe, + + /* Root-Table Address Register Faults (RTA). */ + VTDATFAULT_RTA_1_1 = 0x30, + VTDATFAULT_RTA_1_2 = 0x30, + VTDATFAULT_RTA_1_3 = 0x30, + VTDATFAULT_RTA_2 = 0x31, + VTDATFAULT_RTA_3 = 0x32, + VTDATFAULT_RTA_4 = 0x33, + + /* Scalable-Mode Root-Table Faults (SRT). */ + VTDATFAULT_SRT_1 = 0x38, + VTDATFAULT_SRT_2 = 0x39, + VTDATFAULT_SRT_3 = 0x3a, + + /* Scalable-Mode Context-Table Faults (SCT). */ + VTDATFAULT_SCT_1 = 0x40, + VTDATFAULT_SCT_2 = 0x41, + VTDATFAULT_SCT_3 = 0x42, + VTDATFAULT_SCT_4_1 = 0x43, + VTDATFAULT_SCT_4_2 = 0x43, + VTDATFAULT_SCT_5 = 0x44, + VTDATFAULT_SCT_6 = 0x45, + VTDATFAULT_SCT_7 = 0x46, + VTDATFAULT_SCT_8 = 0x47, + VTDATFAULT_SCT_9 = 0x48, + + /* Scalable-Mode PASID-Directory Faults (SPD). */ + VTDATFAULT_SPD_1 = 0x50, + VTDATFAULT_SPD_2 = 0x51, + VTDATFAULT_SPD_3 = 0x52, + + /* Scalable-Mode PASID-Table Faults (SPT). */ + VTDATFAULT_SPT_1 = 0x58, + VTDATFAULT_SPT_2 = 0x59, + VTDATFAULT_SPT_3 = 0x5a, + VTDATFAULT_SPT_4_1 = 0x5b, + VTDATFAULT_SPT_4_2 = 0x5b, + VTDATFAULT_SPT_4_3 = 0x5b, + VTDATFAULT_SPT_4_4 = 0x5b, + VTDATFAULT_SPT_5 = 0x5c, + VTDATFAULT_SPT_6 = 0x5d, + + /* Scalable-Mode First-Level Table Faults (SFL). */ + VTDATFAULT_SFL_1 = 0x70, + VTDATFAULT_SFL_2 = 0x71, + VTDATFAULT_SFL_3 = 0x72, + VTDATFAULT_SFL_4 = 0x73, + VTDATFAULT_SFL_5 = 0x74, + VTDATFAULT_SFL_6 = 0x75, + VTDATFAULT_SFL_7 = 0x76, + VTDATFAULT_SFL_8 = 0x77, + VTDATFAULT_SFL_9 = 0x90, + VTDATFAULT_SFL_10 = 0x91, + + /* Scalable-Mode Second-Level Table Faults (SSL). */ + VTDATFAULT_SSL_1 = 0x78, + VTDATFAULT_SSL_2 = 0x79, + VTDATFAULT_SSL_3 = 0x7a, + VTDATFAULT_SSL_4 = 0x7b, + VTDATFAULT_SSL_5 = 0x7c, + VTDATFAULT_SSL_6 = 0x7d, + + /* Scalable-Mode General Faults (SGN). */ + VTDATFAULT_SGN_1 = 0x80, + VTDATFAULT_SGN_2 = 0x81, + VTDATFAULT_SGN_3 = 0x82, + VTDATFAULT_SGN_4_1 = 0x83, + VTDATFAULT_SGN_4_2 = 0x83, + VTDATFAULT_SGN_5 = 0x84, + VTDATFAULT_SGN_6 = 0x85, + VTDATFAULT_SGN_7 = 0x86, + VTDATFAULT_SGN_8 = 0x87, + VTDATFAULT_SGN_9 = 0x88, + VTDATFAULT_SGN_10 = 0x89 +} VTDATFAULT; +AssertCompileSize(VTDATFAULT, 4); +/** @} */ + + +/** @name ACPI_DMAR_F_XXX: DMA Remapping Reporting Structure Flags. + * In accordance with the Intel spec. + * @{ */ +/** INTR_REMAP: Interrupt remapping supported. */ +#define ACPI_DMAR_F_INTR_REMAP RT_BIT(0) +/** X2APIC_OPT_OUT: Request system software to opt-out of enabling x2APIC. */ +#define ACPI_DMAR_F_X2APIC_OPT_OUT RT_BIT(1) +/** DMA_CTRL_PLATFORM_OPT_IN_FLAG: Firmware initiated DMA restricted to reserved + * memory regions (RMRR). */ +#define ACPI_DMAR_F_DMA_CTRL_PLATFORM_OPT_IN RT_BIT(2) +/** @} */ + + +/** @name ACPI_DRHD_F_XXX: DMA-Remapping Hardware Unit Definition Flags. + * In accordance with the Intel spec. + * @{ */ +/** INCLUDE_PCI_ALL: All PCI devices under scope. */ +#define ACPI_DRHD_F_INCLUDE_PCI_ALL RT_BIT(0) +/** @} */ + + +/** + * DRHD: DMA-Remapping Hardware Unit Definition. + * In accordance with the Intel spec. + */ +#pragma pack(1) +typedef struct ACPIDRHD +{ + /** Type (must be 0=DRHD). */ + uint16_t uType; + /** Length (must be 16 + size of device scope structure). */ + uint16_t cbLength; + /** Flags, see ACPI_DRHD_F_XXX. */ + uint8_t fFlags; + /** Reserved (MBZ). */ + uint8_t bRsvd; + /** PCI segment number. */ + uint16_t uPciSegment; + /** Register Base Address (MMIO). */ + uint64_t uRegBaseAddr; + /* Device Scope[] Structures follow. */ +} ACPIDRHD; +#pragma pack() +AssertCompileSize(ACPIDRHD, 16); +AssertCompileMemberOffset(ACPIDRHD, cbLength, 2); +AssertCompileMemberOffset(ACPIDRHD, fFlags, 4); +AssertCompileMemberOffset(ACPIDRHD, uPciSegment, 6); +AssertCompileMemberOffset(ACPIDRHD, uRegBaseAddr, 8); + + +/** @name ACPIDMARDEVSCOPE_TYPE_XXX: Device Type. + * In accordance with the Intel spec. + * @{ */ +#define ACPIDMARDEVSCOPE_TYPE_PCI_ENDPOINT 1 +#define ACPIDMARDEVSCOPE_TYPE_PCI_SUB_HIERARCHY 2 +#define ACPIDMARDEVSCOPE_TYPE_IOAPIC 3 +#define ACPIDMARDEVSCOPE_TYPE_MSI_CAP_HPET 4 +#define ACPIDMARDEVSCOPE_TYPE_ACPI_NAMESPACE_DEV 5 +/** @} */ + + +/** + * ACPI Device Scope Structure - PCI device path. + * In accordance with the Intel spec. + */ +typedef struct ACPIDEVSCOPEPATH +{ + /** PCI device number. */ + uint8_t uDevice; + /** PCI function number. */ + uint8_t uFunction; +} ACPIDEVSCOPEPATH; +AssertCompileSize(ACPIDEVSCOPEPATH, 2); + + +/** + * Device Scope Structure. + * In accordance with the Intel spec. + */ +#pragma pack(1) +typedef struct ACPIDMARDEVSCOPE +{ + /** Type, see ACPIDMARDEVSCOPE_TYPE_XXX. */ + uint8_t uType; + /** Length (must be 6 + size of auPath field). */ + uint8_t cbLength; + /** Reserved (MBZ). */ + uint8_t abRsvd[2]; + /** Enumeration ID (for I/O APIC, HPET and ACPI namespace devices). */ + uint8_t idEnum; + /** First bus number for this device. */ + uint8_t uStartBusNum; + /** Hierarchical path from the Host Bridge to the device. */ + ACPIDEVSCOPEPATH Path; +} ACPIDMARDEVSCOPE; +#pragma pack() +AssertCompileMemberOffset(ACPIDMARDEVSCOPE, cbLength, 1); +AssertCompileMemberOffset(ACPIDMARDEVSCOPE, idEnum, 4); +AssertCompileMemberOffset(ACPIDMARDEVSCOPE, uStartBusNum, 5); +AssertCompileMemberOffset(ACPIDMARDEVSCOPE, Path, 6); + +/** ACPI DMAR revision (not the OEM revision field). + * In accordance with the Intel spec. */ +#define ACPI_DMAR_REVISION 1 + + +#endif /* !VBOX_INCLUDED_iommu_intel_h */ + diff --git a/include/VBox/log.h b/include/VBox/log.h new file mode 100644 index 00000000..9a2fe937 --- /dev/null +++ b/include/VBox/log.h @@ -0,0 +1,1239 @@ +/** @file + * VirtualBox - Logging. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_log_h +#define VBOX_INCLUDED_log_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* + * Set the default loggroup. + */ +#ifndef LOG_GROUP +# define LOG_GROUP LOG_GROUP_DEFAULT +#endif + +#include <iprt/log.h> + + +/** @defgroup grp_rt_vbox_log VBox Logging + * @ingroup grp_rt_vbox + * @{ + */ + +/** PC port for debug output */ +#define RTLOG_DEBUG_PORT 0x504 + +/** + * VirtualBox Logging Groups. + * (Remember to update LOGGROUP_NAMES!) + * + * @remark It should be pretty obvious, but just to have + * mentioned it, the values are sorted alphabetically (using the + * english alphabet) except for _DEFAULT which is always first. + * + * If anyone might be wondering what the alphabet looks like: + * A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ + */ +typedef enum VBOXLOGGROUP +{ + /** The default VBox group. */ + LOG_GROUP_DEFAULT = RTLOGGROUP_FIRST_USER, + /** Audio mixer group. */ + LOG_GROUP_AUDIO_MIXER, + /** Audio mixer buffer group. */ + LOG_GROUP_AUDIO_MIXER_BUFFER, + /** Audio test group. */ + LOG_GROUP_AUDIO_TEST, + /** Auto-logon group. */ + LOG_GROUP_AUTOLOGON, + /** CFGM group. */ + LOG_GROUP_CFGM, + /** CPUM group. */ + LOG_GROUP_CPUM, + /** CSAM group. */ + LOG_GROUP_CSAM, + /** Debug Console group. */ + LOG_GROUP_DBGC, + /** DBGF group. */ + LOG_GROUP_DBGF, + /** DBGF info group. */ + LOG_GROUP_DBGF_INFO, + /** The debugger gui. */ + LOG_GROUP_DBGG, + /** Generic Device group. */ + LOG_GROUP_DEV, + /** AC97 Device group. */ + LOG_GROUP_DEV_AC97, + /** ACPI Device group. */ + LOG_GROUP_DEV_ACPI, + /** AHCI Device group. */ + LOG_GROUP_DEV_AHCI, + /** APIC Device group. */ + LOG_GROUP_DEV_APIC, + /** BusLogic SCSI host adapter group. */ + LOG_GROUP_DEV_BUSLOGIC, + /** DMA Controller group. */ + LOG_GROUP_DEV_DMA, + /** NS DP8390 Ethernet Device group. */ + LOG_GROUP_DEV_DP8390, + /** Gigabit Ethernet Device group. */ + LOG_GROUP_DEV_E1000, + /** Extensible Firmware Interface Device group. */ + LOG_GROUP_DEV_EFI, + /** USB EHCI Device group. */ + LOG_GROUP_DEV_EHCI, + /** 3C501 Ethernet Device group. */ + LOG_GROUP_DEV_ELNK, + /** Floppy Controller Device group. */ + LOG_GROUP_DEV_FDC, + /** Flash Device group. */ + LOG_GROUP_DEV_FLASH, + /** Guest Interface Manager Device group. */ + LOG_GROUP_DEV_GIM, + /** HDA Device group. */ + LOG_GROUP_DEV_HDA, + /** HDA Codec Device group. */ + LOG_GROUP_DEV_HDA_CODEC, + /** High Precision Event Timer Device group. */ + LOG_GROUP_DEV_HPET, + /** IDE Device group. */ + LOG_GROUP_DEV_IDE, + /** The internal networking IP stack Device group. */ + LOG_GROUP_DEV_INIP, + /** I/O APIC Device group. */ + LOG_GROUP_DEV_IOAPIC, + /** IOMMU Device group. */ + LOG_GROUP_DEV_IOMMU, + /** KeyBoard Controller Device group. */ + LOG_GROUP_DEV_KBD, + /** Low Pin Count Device group. */ + LOG_GROUP_DEV_LPC, + /** LsiLogic SCSI controller Device group. */ + LOG_GROUP_DEV_LSILOGICSCSI, + /** NVMe Device group. */ + LOG_GROUP_DEV_NVME, + /** USB OHCI Device group. */ + LOG_GROUP_DEV_OHCI, + /** Parallel Device group */ + LOG_GROUP_DEV_PARALLEL, + /** PC Device group. */ + LOG_GROUP_DEV_PC, + /** PC Architecture Device group. */ + LOG_GROUP_DEV_PC_ARCH, + /** PC BIOS Device group. */ + LOG_GROUP_DEV_PC_BIOS, + /** PCI Device group. */ + LOG_GROUP_DEV_PCI, + /** PCI Raw Device group. */ + LOG_GROUP_DEV_PCI_RAW, + /** PCNet Device group. */ + LOG_GROUP_DEV_PCNET, + /** PIC Device group. */ + LOG_GROUP_DEV_PIC, + /** PIT Device group. */ + LOG_GROUP_DEV_PIT, + /** QEMU firmware config Device group. */ + LOG_GROUP_DEV_QEMUFWCFG, + /** RTC Device group. */ + LOG_GROUP_DEV_RTC, + /** SB16 Device group. */ + LOG_GROUP_DEV_SB16, + /** Serial Device group */ + LOG_GROUP_DEV_SERIAL, + /** System Management Controller Device group. */ + LOG_GROUP_DEV_SMC, + /** Trusted Platform Module Device group. */ + LOG_GROUP_DEV_TPM, + /** VGA Device group. */ + LOG_GROUP_DEV_VGA, + /** Virtio PCI Device group. */ + LOG_GROUP_DEV_VIRTIO, + /** Virtio Network Device group. */ + LOG_GROUP_DEV_VIRTIO_NET, + /** VMM Device group. */ + LOG_GROUP_DEV_VMM, + /** VMM Device group for backdoor logging. */ + LOG_GROUP_DEV_VMM_BACKDOOR, + /** VMM Device group for logging guest backdoor logging to stderr. */ + LOG_GROUP_DEV_VMM_STDERR, + /** VMSVGA Device group. */ + LOG_GROUP_DEV_VMSVGA, + /** USB xHCI Device group. */ + LOG_GROUP_DEV_XHCI, + /** Disassembler group. */ + LOG_GROUP_DIS, + /** Generic driver group. */ + LOG_GROUP_DRV, + /** ACPI driver group */ + LOG_GROUP_DRV_ACPI, + /** Audio driver group */ + LOG_GROUP_DRV_AUDIO, + /** Block driver group. */ + LOG_GROUP_DRV_BLOCK, + /** Char driver group. */ + LOG_GROUP_DRV_CHAR, + /** Cloud tunnel driver group. */ + LOG_GROUP_DRV_CTUN, + /** Disk integrity driver group. */ + LOG_GROUP_DRV_DISK_INTEGRITY, + /** Video Display driver group. */ + LOG_GROUP_DRV_DISPLAY, + /** Floppy media driver group. */ + LOG_GROUP_DRV_FLOPPY, + /** Host Audio driver group. */ + LOG_GROUP_DRV_HOST_AUDIO, + /** Host Base block driver group. */ + LOG_GROUP_DRV_HOST_BASE, + /** Host DVD block driver group. */ + LOG_GROUP_DRV_HOST_DVD, + /** Host floppy block driver group. */ + LOG_GROUP_DRV_HOST_FLOPPY, + /** Host Parallel Driver group */ + LOG_GROUP_DRV_HOST_PARALLEL, + /** Host Serial Driver Group */ + LOG_GROUP_DRV_HOST_SERIAL, + /** The internal networking transport driver group. */ + LOG_GROUP_DRV_INTNET, + /** ISO (CD/DVD) media driver group. */ + LOG_GROUP_DRV_ISO, + /** Keyboard Queue driver group. */ + LOG_GROUP_DRV_KBD_QUEUE, + /** lwIP IP stack driver group. */ + LOG_GROUP_DRV_LWIP, + /** Video Miniport driver group. */ + LOG_GROUP_DRV_MINIPORT, + /** Mouse driver group. */ + LOG_GROUP_DRV_MOUSE, + /** Mouse Queue driver group. */ + LOG_GROUP_DRV_MOUSE_QUEUE, + /** Named Pipe stream driver group. */ + LOG_GROUP_DRV_NAMEDPIPE, + /** NAT network transport driver group */ + LOG_GROUP_DRV_NAT, + /** Raw image driver group */ + LOG_GROUP_DRV_RAW_IMAGE, + /** SCSI driver group. */ + LOG_GROUP_DRV_SCSI, + /** Host SCSI driver group. */ + LOG_GROUP_DRV_SCSIHOST, + /** TCP socket stream driver group. */ + LOG_GROUP_DRV_TCP, + /** Trusted Platform Module Emulation driver group. */ + LOG_GROUP_DRV_TPM_EMU, + /** Trusted Platform Module Host driver group. */ + LOG_GROUP_DRV_TPM_HOST, + /** Async transport driver group */ + LOG_GROUP_DRV_TRANSPORT_ASYNC, + /** TUN network transport driver group */ + LOG_GROUP_DRV_TUN, + /** UDP socket stream driver group. */ + LOG_GROUP_DRV_UDP, + /** UDP tunnet network transport driver group. */ + LOG_GROUP_DRV_UDPTUNNEL, + /** USB Proxy driver group. */ + LOG_GROUP_DRV_USBPROXY, + /** VBoxHDD media driver group. */ + LOG_GROUP_DRV_VBOXHDD, + /** VBox HDD container media driver group. */ + LOG_GROUP_DRV_VD, + /** The VMNET networking driver group. */ + LOG_GROUP_DRV_VMNET, + /** VRDE audio driver group. */ + LOG_GROUP_DRV_VRDE_AUDIO, + /** Virtual Switch transport driver group */ + LOG_GROUP_DRV_VSWITCH, + /** VUSB driver group */ + LOG_GROUP_DRV_VUSB, + /** EM group. */ + LOG_GROUP_EM, + /** FTM group. */ + LOG_GROUP_FTM, + /** GIM group. */ + LOG_GROUP_GIM, + /** GMM group. */ + LOG_GROUP_GMM, + /** Guest control. */ + LOG_GROUP_GUEST_CONTROL, + /** Guest drag'n drop. */ + LOG_GROUP_GUEST_DND, + /** GUI group. */ + LOG_GROUP_GUI, + /** GVMM group. */ + LOG_GROUP_GVMM, + /** HGCM group */ + LOG_GROUP_HGCM, + /** HGSMI group */ + LOG_GROUP_HGSMI, + /** HM group. */ + LOG_GROUP_HM, + /** IEM group. */ + LOG_GROUP_IEM, + /** IEM AMD-V group. */ + LOG_GROUP_IEM_SVM, + /** IEM VT-x group. */ + LOG_GROUP_IEM_VMX, + /** I/O buffer management group. */ + LOG_GROUP_IOBUFMGMT, + /** IOM group. */ + LOG_GROUP_IOM, + /** IOM group, I/O port part. */ + LOG_GROUP_IOM_IOPORT, + /** IOM group, MMIO part. */ + LOG_GROUP_IOM_MMIO, + /** XPCOM IPC group. */ + LOG_GROUP_IPC, + /** lwIP group. */ + LOG_GROUP_LWIP, + /** lwIP group, api_lib.c API_LIB_DEBUG */ + LOG_GROUP_LWIP_API_LIB, + /** lwIP group, api_msg.c API_MSG_DEBUG */ + LOG_GROUP_LWIP_API_MSG, + /** lwIP group, etharp.c ETHARP_DEBUG */ + LOG_GROUP_LWIP_ETHARP, + /** lwIP group, icmp.c ICMP_DEBUG */ + LOG_GROUP_LWIP_ICMP, + /** lwIP group, igmp.c IGMP_DEBUG */ + LOG_GROUP_LWIP_IGMP, + /** lwIP group, inet.c INET_DEBUG */ + LOG_GROUP_LWIP_INET, + /** lwIP group, IP_DEBUG (sic!) */ + LOG_GROUP_LWIP_IP4, + /** lwIP group, ip_frag.c IP_REASS_DEBUG (sic!) */ + LOG_GROUP_LWIP_IP4_REASS, + /** lwIP group, IP6_DEBUG */ + LOG_GROUP_LWIP_IP6, + /** lwIP group, mem.c MEM_DEBUG */ + LOG_GROUP_LWIP_MEM, + /** lwIP group, memp.c MEMP_DEBUG */ + LOG_GROUP_LWIP_MEMP, + /** lwIP group, netif.c NETIF_DEBUG */ + LOG_GROUP_LWIP_NETIF, + /** lwIP group, pbuf.c PBUF_DEBUG */ + LOG_GROUP_LWIP_PBUF, + /** lwIP group, raw.c RAW_DEBUG */ + LOG_GROUP_LWIP_RAW, + /** lwIP group, sockets.c SOCKETS_DEBUG */ + LOG_GROUP_LWIP_SOCKETS, + /** lwIP group, SYS_DEBUG */ + LOG_GROUP_LWIP_SYS, + /** lwIP group, TCP_DEBUG */ + LOG_GROUP_LWIP_TCP, + /** lwIP group, TCP_CWND_DEBUG (congestion window) */ + LOG_GROUP_LWIP_TCP_CWND, + /** lwIP group, tcp_in.c TCP_FR_DEBUG (fast retransmit) */ + LOG_GROUP_LWIP_TCP_FR, + /** lwIP group, tcp_in.c TCP_INPUT_DEBUG */ + LOG_GROUP_LWIP_TCP_INPUT, + /** lwIP group, tcp_out.c TCP_OUTPUT_DEBUG */ + LOG_GROUP_LWIP_TCP_OUTPUT, + /** lwIP group, TCP_QLEN_DEBUG */ + LOG_GROUP_LWIP_TCP_QLEN, + /** lwIP group, TCP_RST_DEBUG */ + LOG_GROUP_LWIP_TCP_RST, + /** lwIP group, TCP_RTO_DEBUG (retransmit) */ + LOG_GROUP_LWIP_TCP_RTO, + /** lwIP group, tcp_in.c TCP_WND_DEBUG (window updates) */ + LOG_GROUP_LWIP_TCP_WND, + /** lwIP group, tcpip.c TCPIP_DEBUG */ + LOG_GROUP_LWIP_TCPIP, + /** lwIP group, timers.c TIMERS_DEBUG */ + LOG_GROUP_LWIP_TIMERS, + /** lwIP group, udp.c UDP_DEBUG */ + LOG_GROUP_LWIP_UDP, + /** Main group. */ + LOG_GROUP_MAIN, + /** Main group, IAdditionsFacility. */ + LOG_GROUP_MAIN_ADDITIONSFACILITY, + /** Main group, IAppliance. */ + LOG_GROUP_MAIN_APPLIANCE, + /** Main group, IAudioAdapter. */ + LOG_GROUP_MAIN_AUDIOADAPTER, + /** Main group, IAudioDevice. */ + LOG_GROUP_MAIN_AUDIODEVICE, + /** Main group, IAudioSettings. */ + LOG_GROUP_MAIN_AUDIOSETTINGS, + /** Main group, IBandwidthControl. */ + LOG_GROUP_MAIN_BANDWIDTHCONTROL, + /** Main group, IBandwidthGroup. */ + LOG_GROUP_MAIN_BANDWIDTHGROUP, + /** Main group, IBIOSSettings. */ + LOG_GROUP_MAIN_BIOSSETTINGS, + /** Main group, IBooleanFormValue. */ + LOG_GROUP_MAIN_BOOLEANFORMVALUE, + /** Main group, ICertificate. */ + LOG_GROUP_MAIN_CERTIFICATE, + /** Main group, IChoiceFormValue. */ + LOG_GROUP_MAIN_CHOICEFORMVALUE, + /** Main group, ICloudClient. */ + LOG_GROUP_MAIN_CLOUDCLIENT, + /** Main group, ICloudMachine. */ + LOG_GROUP_MAIN_CLOUDMACHINE, + /** Main group, ICloudNetwork. */ + LOG_GROUP_MAIN_CLOUDNETWORK, + /** Main group, ICloudNetworkEnvironmentInfo */ + LOG_GROUP_MAIN_CLOUDNETWORKENVIRONMENTINFO, + /** Main group, ICloudNetworkGatewayInfo */ + LOG_GROUP_MAIN_CLOUDNETWORKGATEWAYINFO, + /** Main group, ICloudProfile. */ + LOG_GROUP_MAIN_CLOUDPROFILE, + /** Main group, ICloudProfileChangedEvent. */ + LOG_GROUP_MAIN_CLOUDPROFILECHANGEDEVENT, + /** Main group, ICloudProfileRegisteredEvent. */ + LOG_GROUP_MAIN_CLOUDPROFILEREGISTEREDEVENT, + /** Main group, ICloudProvider. */ + LOG_GROUP_MAIN_CLOUDPROVIDER, + /** Main group, ICloudProviderManager. */ + LOG_GROUP_MAIN_CLOUDPROVIDERMANAGER, + /** Main group, IConsole. */ + LOG_GROUP_MAIN_CONSOLE, + /** Main group, ICPUProfile. */ + LOG_GROUP_MAIN_CPUPROFILE, + /** Main group, IDataModel. */ + LOG_GROUP_MAIN_DATAMODEL, + /** Main group, IDataStream. */ + LOG_GROUP_MAIN_DATASTREAM, + /** Main group, IDHCPConfig. */ + LOG_GROUP_MAIN_DHCPCONFIG, + /** Main group, IDHCPGlobalConfig. */ + LOG_GROUP_MAIN_DHCPGLOBALCONFIG, + /** Main group, IDHCPGroupCondition. */ + LOG_GROUP_MAIN_DHCPGROUPCONDITION, + /** Main group, IDHCPGroupConfig. */ + LOG_GROUP_MAIN_DHCPGROUPCONFIG, + /** Main group, IDHCPIndividualConfig. */ + LOG_GROUP_MAIN_DHCPINDIVIDUALCONFIG, + /** Main group, IDHCPServer. */ + LOG_GROUP_MAIN_DHCPSERVER, + /** Main group, IDirectory. */ + LOG_GROUP_MAIN_DIRECTORY, + /** Main group, IDisplay. */ + LOG_GROUP_MAIN_DISPLAY, + /** Main group, IDisplaySourceBitmap. */ + LOG_GROUP_MAIN_DISPLAYSOURCEBITMAP, + /** Main group, IDnDBase. */ + LOG_GROUP_MAIN_DNDBASE, + /** Main group, IDnDSource. */ + LOG_GROUP_MAIN_DNDSOURCE, + /** Main group, IDnDTarget. */ + LOG_GROUP_MAIN_DNDTARGET, + /** Main group, IEmulatedUSB. */ + LOG_GROUP_MAIN_EMULATEDUSB, + /** Main group, IEvent. */ + LOG_GROUP_MAIN_EVENT, + /** Main group, IEventListener. */ + LOG_GROUP_MAIN_EVENTLISTENER, + /** Main group, IEventSource. */ + LOG_GROUP_MAIN_EVENTSOURCE, + /** Main group, IExtPack. */ + LOG_GROUP_MAIN_EXTPACK, + /** Main group, IExtPackBase. */ + LOG_GROUP_MAIN_EXTPACKBASE, + /** Main group, IExtPackFile. */ + LOG_GROUP_MAIN_EXTPACKFILE, + /** Main group, IExtPackManager. */ + LOG_GROUP_MAIN_EXTPACKMANAGER, + /** Main group, IExtPackPlugIn. */ + LOG_GROUP_MAIN_EXTPACKPLUGIN, + /** Main group, IFile. */ + LOG_GROUP_MAIN_FILE, + /** Main group, IForm. */ + LOG_GROUP_MAIN_FORM, + /** Main group, IFormValue. */ + LOG_GROUP_MAIN_FORMVALUE, + /** Main group, IFramebuffer. */ + LOG_GROUP_MAIN_FRAMEBUFFER, + /** Main group, IFramebufferOverlay. */ + LOG_GROUP_MAIN_FRAMEBUFFEROVERLAY, + /** Main group, IFsInfo. */ + LOG_GROUP_MAIN_FSINFO, + /** Main group, IFsObjInfo. */ + LOG_GROUP_MAIN_FSOBJINFO, + /** Main group, IGraphicsAdapter. */ + LOG_GROUP_MAIN_GRAPHICSADAPTER, + /** Main group, IGuest. */ + LOG_GROUP_MAIN_GUEST, + /** Main group, IGuestDebugControl. */ + LOG_GROUP_MAIN_GUESTDEBUGCONTROL, + /** Main group, IGuestDirectory. */ + LOG_GROUP_MAIN_GUESTDIRECTORY, + /** Main group, IGuestDnDSource. */ + LOG_GROUP_MAIN_GUESTDNDSOURCE, + /** Main group, IGuestDnDTarget. */ + LOG_GROUP_MAIN_GUESTDNDTARGET, + /** Main group, IGuestErrorInfo. */ + LOG_GROUP_MAIN_GUESTERRORINFO, + /** Main group, IGuestFile. */ + LOG_GROUP_MAIN_GUESTFILE, + /** Main group, IGuestFileEvent. */ + LOG_GROUP_MAIN_GUESTFILEEVENT, + /** Main group, IGuestFileIOEvent. */ + LOG_GROUP_MAIN_GUESTFILEIOEVENT, + /** Main group, IGuestFsInfo. */ + LOG_GROUP_MAIN_GUESTFSINFO, + /** Main group, IGuestFsObjInfo. */ + LOG_GROUP_MAIN_GUESTFSOBJINFO, + /** Main group, IGuestOSType. */ + LOG_GROUP_MAIN_GUESTOSTYPE, + /** Main group, IGuestProcess. */ + LOG_GROUP_MAIN_GUESTPROCESS, + /** Main group, IGuestProcessEvent. */ + LOG_GROUP_MAIN_GUESTPROCESSEVENT, + /** Main group, IGuestProcessIOEvent. */ + LOG_GROUP_MAIN_GUESTPROCESSIOEVENT, + /** Main group, IGuestScreenInfo. */ + LOG_GROUP_MAIN_GUESTSCREENINFO, + /** Main group, IGuestSession. */ + LOG_GROUP_MAIN_GUESTSESSION, + /** Main group, IGuestSessionEvent. */ + LOG_GROUP_MAIN_GUESTSESSIONEVENT, + /** Main group, IHost. */ + LOG_GROUP_MAIN_HOST, + /** Main group, IHostAudioDevice. */ + LOG_GROUP_MAIN_HOSTAUDIODEVICE, + /** Main group, IHostDrive. */ + LOG_GROUP_MAIN_HOSTDRIVE, + /** Main group, IHostDriveList. */ + LOG_GROUP_MAIN_HOSTDRIVELIST, + /** Main group, IHostDrivePartition. */ + LOG_GROUP_MAIN_HOSTDRIVEPARTITION, + /** Main group, IHostNetworkInterface. */ + LOG_GROUP_MAIN_HOSTNETWORKINTERFACE, + /** Main group, IHostOnlyNetwork. */ + LOG_GROUP_MAIN_HOSTONLYNETWORK, + /** Main group, IHostUpdateAgent. */ + LOG_GROUP_MAIN_HOSTUPDATEAGENT, + /** Main group, IHostUSBDevice. */ + LOG_GROUP_MAIN_HOSTUSBDEVICE, + /** Main group, IHostUSBDeviceFilter. */ + LOG_GROUP_MAIN_HOSTUSBDEVICEFILTER, + /** Main group, IHostVideoInputDevice. */ + LOG_GROUP_MAIN_HOSTVIDEOINPUTDEVICE, + /** Main group, IInternalMachineControl. */ + LOG_GROUP_MAIN_INTERNALMACHINECONTROL, + /** Main group, IInternalSessionControl. */ + LOG_GROUP_MAIN_INTERNALSESSIONCONTROL, + /** Main group, IKeyboard. */ + LOG_GROUP_MAIN_KEYBOARD, + /** Main group, IMachine. */ + LOG_GROUP_MAIN_MACHINE, + /** Main group, IMachineDebugger. */ + LOG_GROUP_MAIN_MACHINEDEBUGGER, + /** Main group, IMachineEvent. */ + LOG_GROUP_MAIN_MACHINEEVENT, + /** Main group, IMedium. */ + LOG_GROUP_MAIN_MEDIUM, + /** Main group, IMediumAttachment. */ + LOG_GROUP_MAIN_MEDIUMATTACHMENT, + /** Main group, IMediumFormat. */ + LOG_GROUP_MAIN_MEDIUMFORMAT, + /** Main group, IMediumIO. */ + LOG_GROUP_MAIN_MEDIUMIO, + /** Main group, IMouse. */ + LOG_GROUP_MAIN_MOUSE, + /** Main group, IMousePointerShape. */ + LOG_GROUP_MAIN_MOUSEPOINTERSHAPE, + /** Main group, INATEngine. */ + LOG_GROUP_MAIN_NATENGINE, + /** Main group, INATNetwork. */ + LOG_GROUP_MAIN_NATNETWORK, + /** Main group, INetworkAdapter. */ + LOG_GROUP_MAIN_NETWORKADAPTER, + /** Main group, INvramStore. */ + LOG_GROUP_MAIN_NVRAMSTORE, + /** Main group, IParallelPort. */ + LOG_GROUP_MAIN_PARALLELPORT, + /** Main group, IPCIAddress. */ + LOG_GROUP_MAIN_PCIADDRESS, + /** Main group, IPCIDeviceAttachment. */ + LOG_GROUP_MAIN_PCIDEVICEATTACHMENT, + /** Main group, IPerformanceCollector. */ + LOG_GROUP_MAIN_PERFORMANCECOLLECTOR, + /** Main group, IPerformanceMetric. */ + LOG_GROUP_MAIN_PERFORMANCEMETRIC, + /** Main group, IProcess. */ + LOG_GROUP_MAIN_PROCESS, + /** Main group, IProgress. */ + LOG_GROUP_MAIN_PROGRESS, + /** Main group, IProgressCreatedEvent. */ + LOG_GROUP_MAIN_PROGRESSCREATEDEVENT, + /** Main group, IProgressEvent. */ + LOG_GROUP_MAIN_PROGRESSEVENT, + /** Main group, IRangedIntegerFormValue. */ + LOG_GROUP_MAIN_RANGEDINTEGERFORMVALUE, + /** Main group, IRecordingScreenSettings. */ + LOG_GROUP_MAIN_RECORDINGSCREENSETTINGS, + /** Main group, IRecordingSettings. */ + LOG_GROUP_MAIN_RECORDINGSETTINGS, + /** Main group, IReusableEvent. */ + LOG_GROUP_MAIN_REUSABLEEVENT, + /** Main group, ISerialPort. */ + LOG_GROUP_MAIN_SERIALPORT, + /** Main group, ISession. */ + LOG_GROUP_MAIN_SESSION, + /** Main group, ISharedFolder. */ + LOG_GROUP_MAIN_SHAREDFOLDER, + /** Main group, ISnapshot. */ + LOG_GROUP_MAIN_SNAPSHOT, + /** Main group, ISnapshotEvent. */ + LOG_GROUP_MAIN_SNAPSHOTEVENT, + /** Main group, IStorageController. */ + LOG_GROUP_MAIN_STORAGECONTROLLER, + /** Main group, IStringArray. */ + LOG_GROUP_MAIN_STRINGARRAY, + /** Main group, IStringFormValue. */ + LOG_GROUP_MAIN_STRINGFORMVALUE, + /** Main group, ISystemProperties. */ + LOG_GROUP_MAIN_SYSTEMPROPERTIES, + /** Main group, threaded tasks. */ + LOG_GROUP_MAIN_THREAD_TASK, + /** Main group, IToken. */ + LOG_GROUP_MAIN_TOKEN, + /** Main group, ITrustedPlatformModule. */ + LOG_GROUP_MAIN_TRUSTEDPLATFORMMODULE, + /** Main group, IUefiVariableStore. */ + LOG_GROUP_MAIN_UEFIVARIABLESTORE, + /** Main group, IUnattended. */ + LOG_GROUP_MAIN_UNATTENDED, + /** Main group, IUpdateAgent. */ + LOG_GROUP_MAIN_UPDATEAGENT, + /** Main group, IUpdateAgentAvailableEvent. */ + LOG_GROUP_MAIN_UPDATEAGENTAVAILABLEEVENT, + /** Main group, IUpdateAgentErrorEvent. */ + LOG_GROUP_MAIN_UPDATEAGENTERROREVENT, + /** Main group, IUpdateAgentEvent. */ + LOG_GROUP_MAIN_UPDATEAGENTEVENT, + /** Main group, IUpdateAgentSettingsChangedEvent. */ + LOG_GROUP_MAIN_UPDATEAGENTSETTINGSCHANGEDEVENT, + /** Main group, IUpdateAgentStateChangedEvent. */ + LOG_GROUP_MAIN_UPDATEAGENTSTATECHANGEDEVENT, + /** Main group, IUSBController. */ + LOG_GROUP_MAIN_USBCONTROLLER, + /** Main group, IUSBDevice. */ + LOG_GROUP_MAIN_USBDEVICE, + /** Main group, IUSBDeviceFilter. */ + LOG_GROUP_MAIN_USBDEVICEFILTER, + /** Main group, IUSBDeviceFilters. */ + LOG_GROUP_MAIN_USBDEVICEFILTERS, + /** Main group, IUSBProxyBackend. */ + LOG_GROUP_MAIN_USBPROXYBACKEND, + /** Main group, IVBoxSVC. */ + LOG_GROUP_MAIN_VBOXSVC, + /** Main group, IVetoEvent. */ + LOG_GROUP_MAIN_VETOEVENT, + /** Main group, IVFSExplorer. */ + LOG_GROUP_MAIN_VFSEXPLORER, + /** Main group, IVirtualBox. */ + LOG_GROUP_MAIN_VIRTUALBOX, + /** Main group, IVirtualBoxClient. */ + LOG_GROUP_MAIN_VIRTUALBOXCLIENT, + /** Main group, IVirtualBoxSDS. */ + LOG_GROUP_MAIN_VIRTUALBOXSDS, + /** Main group, IVirtualSystemDescription. */ + LOG_GROUP_MAIN_VIRTUALSYSTEMDESCRIPTION, + /** Main group, IVirtualSystemDescriptionForm. */ + LOG_GROUP_MAIN_VIRTUALSYSTEMDESCRIPTIONFORM, + /** Main group, VMM device interfaces. */ + LOG_GROUP_MAIN_VMMDEVINTERFACES, + /** Main group, IVRDEServer. */ + LOG_GROUP_MAIN_VRDESERVER, + /** Main group, IVRDEServerInfo. */ + LOG_GROUP_MAIN_VRDESERVERINFO, + /** Misc. group intended for external use only. */ + LOG_GROUP_MISC, + /** MM group. */ + LOG_GROUP_MM, + /** MM group. */ + LOG_GROUP_MM_HEAP, + /** MM group. */ + LOG_GROUP_MM_HYPER, + /** MM Hypervisor Heap group. */ + LOG_GROUP_MM_HYPER_HEAP, + /** MM Physical/Ram group. */ + LOG_GROUP_MM_PHYS, + /** MM Page pool group. */ + LOG_GROUP_MM_POOL, + /** The NAT service group */ + LOG_GROUP_NAT_SERVICE, + /** NEM group. */ + LOG_GROUP_NEM, + /** The network adaptor driver group. */ + LOG_GROUP_NET_ADP_DRV, + /** The DHCP network service deamon. */ + LOG_GROUP_NET_DHCPD, + /** The network filter driver group. */ + LOG_GROUP_NET_FLT_DRV, + /** The common network service group */ + LOG_GROUP_NET_SERVICE, + /** Network traffic shaper driver group. */ + LOG_GROUP_NET_SHAPER, + /** PATM group. */ + LOG_GROUP_PATM, + /** PDM group. */ + LOG_GROUP_PDM, + /** PDM Async completion group. */ + LOG_GROUP_PDM_ASYNC_COMPLETION, + /** PDM Block cache group. */ + LOG_GROUP_PDM_BLK_CACHE, + /** PDM critical section group. */ + LOG_GROUP_PDM_CRITSECT, + /** PDM read/write critical section group. */ + LOG_GROUP_PDM_CRITSECTRW, + /** PDM Device group. */ + LOG_GROUP_PDM_DEVICE, + /** PDM Driver group. */ + LOG_GROUP_PDM_DRIVER, + /** PDM Loader group. */ + LOG_GROUP_PDM_LDR, + /** PDM Queue group. */ + LOG_GROUP_PDM_QUEUE, + /** PDM Task group. */ + LOG_GROUP_PDM_TASK, + /** PDM Thread group. */ + LOG_GROUP_PDM_THREAD, + /** PGM group. */ + LOG_GROUP_PGM, + /** PGM dynamic mapping group. */ + LOG_GROUP_PGM_DYNMAP, + /** PGM physical group. */ + LOG_GROUP_PGM_PHYS, + /** PGM physical access group. */ + LOG_GROUP_PGM_PHYS_ACCESS, + /** PGM shadow page pool group. */ + LOG_GROUP_PGM_POOL, + /** PGM shared paging group. */ + LOG_GROUP_PGM_SHARED, + /** Audio + video recording. */ + LOG_GROUP_RECORDING, + /** REM group. */ + LOG_GROUP_REM, + /** REM disassembly handler group. */ + LOG_GROUP_REM_DISAS, + /** REM access handler group. */ + LOG_GROUP_REM_HANDLER, + /** REM I/O port access group. */ + LOG_GROUP_REM_IOPORT, + /** REM MMIO access group. */ + LOG_GROUP_REM_MMIO, + /** REM Printf. */ + LOG_GROUP_REM_PRINTF, + /** REM running group. */ + LOG_GROUP_REM_RUN, + /** SELM group. */ + LOG_GROUP_SELM, + /** Shared clipboard host service group. */ + LOG_GROUP_SHARED_CLIPBOARD, + /** Chromium OpenGL host service group. */ + LOG_GROUP_SHARED_CROPENGL, + /** Shared folders host service group. */ + LOG_GROUP_SHARED_FOLDERS, + /** OpenGL host service group. */ + LOG_GROUP_SHARED_OPENGL, + /** The internal networking service group. */ + LOG_GROUP_SRV_INTNET, + /** SSM group. */ + LOG_GROUP_SSM, + /** STAM group. */ + LOG_GROUP_STAM, + /** SUP group. */ + LOG_GROUP_SUP, + /** SUPport driver group. */ + LOG_GROUP_SUP_DRV, + /** TM group. */ + LOG_GROUP_TM, + /** TRPM group. */ + LOG_GROUP_TRPM, + /** USB cardreader group. */ + LOG_GROUP_USB_CARDREADER, + /** USB driver group. */ + LOG_GROUP_USB_DRV, + /** USBFilter group. */ + LOG_GROUP_USB_FILTER, + /** USB keyboard device group. */ + LOG_GROUP_USB_KBD, + /** USB mouse/tablet device group. */ + LOG_GROUP_USB_MOUSE, + /** MSD USB device group. */ + LOG_GROUP_USB_MSD, + /** USB remote support. */ + LOG_GROUP_USB_REMOTE, + /** USB webcam. */ + LOG_GROUP_USB_WEBCAM, + /** VBox Guest Additions Library. */ + LOG_GROUP_VBGL, + /** Generic virtual disk layer. */ + LOG_GROUP_VD, + /** CUE/BIN virtual disk backend. */ + LOG_GROUP_VD_CUE, + /** DMG virtual disk backend. */ + LOG_GROUP_VD_DMG, + /** iSCSI virtual disk backend. */ + LOG_GROUP_VD_ISCSI, + /** Parallels HDD virtual disk backend. */ + LOG_GROUP_VD_PARALLELS, + /** QCOW virtual disk backend. */ + LOG_GROUP_VD_QCOW, + /** QED virtual disk backend. */ + LOG_GROUP_VD_QED, + /** Raw virtual disk backend. */ + LOG_GROUP_VD_RAW, + /** VDI virtual disk backend. */ + LOG_GROUP_VD_VDI, + /** VHD virtual disk backend. */ + LOG_GROUP_VD_VHD, + /** VHDX virtual disk backend. */ + LOG_GROUP_VD_VHDX, + /** VMDK virtual disk backend. */ + LOG_GROUP_VD_VMDK, + /** VBox Guest Additions Driver (VBoxGuest). */ + LOG_GROUP_VGDRV, + /** VM group. */ + LOG_GROUP_VM, + /** VMM group. */ + LOG_GROUP_VMM, + /** VRDE group */ + LOG_GROUP_VRDE, + /** VRDP group */ + LOG_GROUP_VRDP, + /** VSCSI group */ + LOG_GROUP_VSCSI, + /** Webservice group. */ + LOG_GROUP_WEBSERVICE + /* !!!ALPHABETICALLY!!! */ +} VBOXLOGGROUP; + + +/** @def VBOX_LOGGROUP_NAMES + * VirtualBox Logging group names. + * + * Must correspond 100% to LOGGROUP! + * Don't forget commas! + * + * @remark It should be pretty obvious, but just to have + * mentioned it, the values are sorted alphabetically (using the + * english alphabet) except for _DEFAULT which is always first. + * + * If anyone might be wondering what the alphabet looks like: + * a b c d e f g h i j k l m n o p q r s t u v w x y z + */ +#define VBOX_LOGGROUP_NAMES \ +{ \ + RT_LOGGROUP_NAMES, \ + "DEFAULT", \ + "AUDIO_MIXER", \ + "AUDIO_MIXER_BUFFER", \ + "AUDIO_TEST", \ + "AUTOLOGON", \ + "CFGM", \ + "CPUM", \ + "CSAM", \ + "DBGC", \ + "DBGF", \ + "DBGF_INFO", \ + "DBGG", \ + "DEV", \ + "DEV_AC97", \ + "DEV_ACPI", \ + "DEV_AHCI", \ + "DEV_APIC", \ + "DEV_BUSLOGIC", \ + "DEV_DMA", \ + "DEV_DP8390", \ + "DEV_E1000", \ + "DEV_EFI", \ + "DEV_EHCI", \ + "DEV_ELNK", \ + "DEV_FDC", \ + "DEV_FLASH", \ + "DEV_GIM", \ + "DEV_HDA", \ + "DEV_HDA_CODEC", \ + "DEV_HPET", \ + "DEV_IDE", \ + "DEV_INIP", \ + "DEV_IOAPIC", \ + "DEV_IOMMU", \ + "DEV_KBD", \ + "DEV_LPC", \ + "DEV_LSILOGICSCSI", \ + "DEV_NVME", \ + "DEV_OHCI", \ + "DEV_PARALLEL", \ + "DEV_PC", \ + "DEV_PC_ARCH", \ + "DEV_PC_BIOS", \ + "DEV_PCI", \ + "DEV_PCI_RAW", \ + "DEV_PCNET", \ + "DEV_PIC", \ + "DEV_PIT", \ + "DEV_QEMUFWCFG", \ + "DEV_RTC", \ + "DEV_SB16", \ + "DEV_SERIAL", \ + "DEV_SMC", \ + "DEV_TPM", \ + "DEV_VGA", \ + "DEV_VIRTIO", \ + "DEV_VIRTIO_NET", \ + "DEV_VMM", \ + "DEV_VMM_BACKDOOR", \ + "DEV_VMM_STDERR", \ + "DEV_VMSVGA", \ + "DEV_XHCI", \ + "DIS", \ + "DRV", \ + "DRV_ACPI", \ + "DRV_AUDIO", \ + "DRV_BLOCK", \ + "DRV_CHAR", \ + "DRV_CTUN", \ + "DRV_DISK_INTEGRITY", \ + "DRV_DISPLAY", \ + "DRV_FLOPPY", \ + "DRV_HOST_AUDIO", \ + "DRV_HOST_BASE", \ + "DRV_HOST_DVD", \ + "DRV_HOST_FLOPPY", \ + "DRV_HOST_PARALLEL", \ + "DRV_HOST_SERIAL", \ + "DRV_INTNET", \ + "DRV_ISO", \ + "DRV_KBD_QUEUE", \ + "DRV_LWIP", \ + "DRV_MINIPORT", \ + "DRV_MOUSE", \ + "DRV_MOUSE_QUEUE", \ + "DRV_NAMEDPIPE", \ + "DRV_NAT", \ + "DRV_RAW_IMAGE", \ + "DRV_SCSI", \ + "DRV_SCSIHOST", \ + "DRV_TCP", \ + "DRV_TPM_EMU", \ + "DRV_TPM_HOST", \ + "DRV_TRANSPORT_ASYNC", \ + "DRV_TUN", \ + "DRV_UDP", \ + "DRV_UDPTUNNEL", \ + "DRV_USBPROXY", \ + "DRV_VBOXHDD", \ + "DRV_VD", \ + "DRV_VMNET", \ + "DRV_VRDE_AUDIO", \ + "DRV_VSWITCH", \ + "DRV_VUSB", \ + "EM", \ + "FTM", \ + "GIM", \ + "GMM", \ + "GUEST_CONTROL", \ + "GUEST_DND", \ + "GUI", \ + "GVMM", \ + "HGCM", \ + "HGSMI", \ + "HM", \ + "IEM", \ + "IEM_SVM", \ + "IEM_VMX", \ + "IOBUFMGMT", \ + "IOM", \ + "IOM_IOPORT", \ + "IOM_MMIO", \ + "IPC", \ + "LWIP", \ + "LWIP_API_LIB", \ + "LWIP_API_MSG", \ + "LWIP_ETHARP", \ + "LWIP_ICMP", \ + "LWIP_IGMP", \ + "LWIP_INET", \ + "LWIP_IP4", \ + "LWIP_IP4_REASS", \ + "LWIP_IP6", \ + "LWIP_MEM", \ + "LWIP_MEMP", \ + "LWIP_NETIF", \ + "LWIP_PBUF", \ + "LWIP_RAW", \ + "LWIP_SOCKETS", \ + "LWIP_SYS", \ + "LWIP_TCP", \ + "LWIP_TCP_CWND", \ + "LWIP_TCP_FR", \ + "LWIP_TCP_INPUT", \ + "LWIP_TCP_OUTPUT", \ + "LWIP_TCP_QLEN", \ + "LWIP_TCP_RST", \ + "LWIP_TCP_RTO", \ + "LWIP_TCP_WND", \ + "LWIP_TCPIP", \ + "LWIP_TIMERS", \ + "LWIP_UDP", \ + "MAIN", \ + "MAIN_ADDITIONSFACILITY", \ + "MAIN_APPLIANCE", \ + "MAIN_AUDIOADAPTER", \ + "MAIN_AUDIODEVICE", \ + "MAIN_AUDIOSETTINGS", \ + "MAIN_BANDWIDTHCONTROL", \ + "MAIN_BANDWIDTHGROUP", \ + "MAIN_BIOSSETTINGS", \ + "MAIN_BOOLEANFORMVALUE", \ + "MAIN_CERTIFICATE", \ + "MAIN_CHOICEFORMVALUE", \ + "MAIN_CLOUDCLIENT", \ + "MAIN_CLOUDMACHINE", \ + "MAIN_CLOUDNETWORK", \ + "MAIN_CLOUDNETWORKENVIRONMENTINFO", \ + "MAIN_CLOUDNETWORKGATEWAYINFO", \ + "MAIN_CLOUDPROFILE", \ + "MAIN_CLOUDPROFILECHANGEDEVENT", \ + "MAIN_CLOUDPROFILEREGISTEREDEVENT", \ + "MAIN_CLOUDPROVIDER", \ + "MAIN_CLOUDPROVIDERMANAGER", \ + "MAIN_CONSOLE", \ + "MAIN_CPUPROFILE", \ + "MAIN_DATAMODEL", \ + "MAIN_DATASTREAM", \ + "MAIN_DHCPCONFIG", \ + "MAIN_DHCPGLOBALCONFIG", \ + "MAIN_DHCPGROUPCONDITION", \ + "MAIN_DHCPGROUPCONFIG", \ + "MAIN_DHCPINDIVIDUALCONFIG", \ + "MAIN_DHCPSERVER", \ + "MAIN_DIRECTORY", \ + "MAIN_DISPLAY", \ + "MAIN_DISPLAYSOURCEBITMAP", \ + "MAIN_DNDBASE", \ + "MAIN_DNDSOURCE", \ + "MAIN_DNDTARGET", \ + "MAIN_EMULATEDUSB", \ + "MAIN_EVENT", \ + "MAIN_EVENTLISTENER", \ + "MAIN_EVENTSOURCE", \ + "MAIN_EXTPACK", \ + "MAIN_EXTPACKBASE", \ + "MAIN_EXTPACKFILE", \ + "MAIN_EXTPACKMANAGER", \ + "MAIN_EXTPACKPLUGIN", \ + "MAIN_FILE", \ + "MAIN_FORM", \ + "MAIN_FORMVALUE", \ + "MAIN_FRAMEBUFFER", \ + "MAIN_FRAMEBUFFEROVERLAY", \ + "MAIN_FSINFO", \ + "MAIN_FSOBJINFO", \ + "MAIN_GRAPHICSADAPTER", \ + "MAIN_GUEST", \ + "MAIN_GUESTDEBUGCONTROL", \ + "MAIN_GUESTDIRECTORY", \ + "MAIN_GUESTDNDSOURCE", \ + "MAIN_GUESTDNDTARGET", \ + "MAIN_GUESTERRORINFO", \ + "MAIN_GUESTFILE", \ + "MAIN_GUESTFILEEVENT", \ + "MAIN_GUESTFILEIOEVENT", \ + "MAIN_GUESTFSINFO", \ + "MAIN_GUESTFSOBJINFO", \ + "MAIN_GUESTOSTYPE", \ + "MAIN_GUESTPROCESS", \ + "MAIN_GUESTPROCESSEVENT", \ + "MAIN_GUESTPROCESSIOEVENT", \ + "MAIN_GUESTSCREENINFO", \ + "MAIN_GUESTSESSION", \ + "MAIN_GUESTSESSIONEVENT", \ + "MAIN_HOST", \ + "MAIN_HOSTAUDIODEVICE", \ + "MAIN_HOSTDRIVE", \ + "MAIN_HOSTDRIVELIST", \ + "MAIN_HOSTDRIVEPARTITION", \ + "MAIN_HOSTNETWORKINTERFACE", \ + "MAIN_HOSTONLYNETWORK", \ + "MAIN_HOSTUPDATEAGENT", \ + "MAIN_HOSTUSBDEVICE", \ + "MAIN_HOSTUSBDEVICEFILTER", \ + "MAIN_HOSTVIDEOINPUTDEVICE", \ + "MAIN_INTERNALMACHINECONTROL", \ + "MAIN_INTERNALSESSIONCONTROL", \ + "MAIN_KEYBOARD", \ + "MAIN_MACHINE", \ + "MAIN_MACHINEDEBUGGER", \ + "MAIN_MACHINEEVENT", \ + "MAIN_MEDIUM", \ + "MAIN_MEDIUMATTACHMENT", \ + "MAIN_MEDIUMFORMAT", \ + "MAIN_MEDIUMIO", \ + "MAIN_MOUSE", \ + "MAIN_MOUSEPOINTERSHAPE", \ + "MAIN_NATENGINE", \ + "MAIN_NATNETWORK", \ + "MAIN_NETWORKADAPTER", \ + "MAIN_NVRAMSTORE", \ + "MAIN_PARALLELPORT", \ + "MAIN_PCIADDRESS", \ + "MAIN_PCIDEVICEATTACHMENT", \ + "MAIN_PERFORMANCECOLLECTOR", \ + "MAIN_PERFORMANCEMETRIC", \ + "MAIN_PROCESS", \ + "MAIN_PROGRESS", \ + "MAIN_PROGRESSCREATEDEVENT", \ + "MAIN_PROGRESSEVENT", \ + "MAIN_RANGEDINTEGERFORMVALUE", \ + "MAIN_RECORDINGSCREENSETTINGS", \ + "MAIN_RECORDINGSETTINGS", \ + "MAIN_REUSABLEEVENT", \ + "MAIN_SERIALPORT", \ + "MAIN_SESSION", \ + "MAIN_SHAREDFOLDER", \ + "MAIN_SNAPSHOT", \ + "MAIN_SNAPSHOTEVENT", \ + "MAIN_STORAGECONTROLLER", \ + "MAIN_STRINGARRAY", \ + "MAIN_STRINGFORMVALUE", \ + "MAIN_SYSTEMPROPERTIES", \ + "MAIN_THREAD_TASK", \ + "MAIN_TOKEN", \ + "MAIN_TRUSTEDPLATFORMMODULE", \ + "MAIN_UEFIVARIABLESTORE", \ + "MAIN_UNATTENDED", \ + "MAIN_UPDATEAGENT", \ + "MAIN_UPDATEAGENTAVAILABLEEVENT", \ + "MAIN_UPDATEAGENTERROREVENT", \ + "MAIN_UPDATEAGENTEVENT", \ + "MAIN_UPDATEAGENTSETTINGSCHANGEDEVENT", \ + "MAIN_UPDATEAGENTSTATECHANGEDEVENT", \ + "MAIN_USBCONTROLLER", \ + "MAIN_USBDEVICE", \ + "MAIN_USBDEVICEFILTER", \ + "MAIN_USBDEVICEFILTERS", \ + "MAIN_USBPROXYBACKEND", \ + "MAIN_VBOXSVC", \ + "MAIN_VETOEVENT", \ + "MAIN_VFSEXPLORER", \ + "MAIN_VIRTUALBOX", \ + "MAIN_VIRTUALBOXCLIENT", \ + "MAIN_VIRTUALBOXSDS", \ + "MAIN_VIRTUALSYSTEMDESCRIPTION", \ + "MAIN_VIRTUALSYSTEMDESCRIPTIONFORM", \ + "MAIN_VMMDEVINTERFACES", \ + "MAIN_VRDESERVER", \ + "MAIN_VRDESERVERINFO", \ + "MISC", \ + "MM", \ + "MM_HEAP", \ + "MM_HYPER", \ + "MM_HYPER_HEAP", \ + "MM_PHYS", \ + "MM_POOL", \ + "NAT_SERVICE", \ + "NEM", \ + "NET_ADP_DRV", \ + "NET_DHCPD", \ + "NET_FLT_DRV", \ + "NET_SERVICE", \ + "NET_SHAPER", \ + "PATM", \ + "PDM", \ + "PDM_ASYNC_COMPLETION", \ + "PDM_BLK_CACHE", \ + "PDM_CRITSECT", \ + "PDM_CRITSECTRW", \ + "PDM_DEVICE", \ + "PDM_DRIVER", \ + "PDM_LDR", \ + "PDM_QUEUE", \ + "PDM_TASK", \ + "PDM_THREAD", \ + "PGM", \ + "PGM_DYNMAP", \ + "PGM_PHYS", \ + "PGM_PHYS_ACCESS", \ + "PGM_POOL", \ + "PGM_SHARED", \ + "RECORDING", \ + "REM", \ + "REM_DISAS", \ + "REM_HANDLER", \ + "REM_IOPORT", \ + "REM_MMIO", \ + "REM_PRINTF", \ + "REM_RUN", \ + "SELM", \ + "SHARED_CLIPBOARD", \ + "SHARED_CROPENGL", \ + "SHARED_FOLDERS", \ + "SHARED_OPENGL", \ + "SRV_INTNET", \ + "SSM", \ + "STAM", \ + "SUP", \ + "SUP_DRV", \ + "TM", \ + "TRPM", \ + "USB_CARDREADER", \ + "USB_DRV", \ + "USB_FILTER", \ + "USB_KBD", \ + "USB_MOUSE", \ + "USB_MSD", \ + "USB_REMOTE", \ + "USB_WEBCAM", \ + "VBGL", \ + "VD", \ + "VD_CUE", \ + "VD_DMG", \ + "VD_ISCSI", \ + "VD_PARALLELS", \ + "VD_QCOW", \ + "VD_QED", \ + "VD_RAW", \ + "VD_VDI", \ + "VD_VHD", \ + "VD_VHDX", \ + "VD_VMDK", \ + "VGDRV", \ + "VM", \ + "VMM", \ + "VRDE", \ + "VRDP", \ + "VSCSI", \ + "WEBSERVICE", \ +} + +/** @} */ +#endif /* !VBOX_INCLUDED_log_h */ diff --git a/include/VBox/msi.h b/include/VBox/msi.h new file mode 100644 index 00000000..34aae831 --- /dev/null +++ b/include/VBox/msi.h @@ -0,0 +1,287 @@ +/** @file + * MSI - Message signalled interrupts support. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_msi_h +#define VBOX_INCLUDED_msi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <iprt/assert.h> + +#include <VBox/pci.h> + +/* Constants for Intel APIC MSI messages */ +#define VBOX_MSI_DATA_VECTOR_SHIFT 0 +#define VBOX_MSI_DATA_VECTOR_MASK 0x000000ff +#define VBOX_MSI_DATA_VECTOR(v) (((v) << VBOX_MSI_DATA_VECTOR_SHIFT) & \ + VBOX_MSI_DATA_VECTOR_MASK) +#define VBOX_MSI_DATA_DELIVERY_MODE_SHIFT 8 +#define VBOX_MSI_DATA_DELIVERY_FIXED (0 << VBOX_MSI_DATA_DELIVERY_MODE_SHIFT) +#define VBOX_MSI_DATA_DELIVERY_LOWPRI (1 << VBOX_MSI_DATA_DELIVERY_MODE_SHIFT) + +#define VBOX_MSI_DATA_LEVEL_SHIFT 14 +#define VBOX_MSI_DATA_LEVEL_DEASSERT (0 << VBOX_MSI_DATA_LEVEL_SHIFT) +#define VBOX_MSI_DATA_LEVEL_ASSERT (1 << VBOX_MSI_DATA_LEVEL_SHIFT) + +#define VBOX_MSI_DATA_TRIGGER_SHIFT 15 +#define VBOX_MSI_DATA_TRIGGER_EDGE (0 << VBOX_MSI_DATA_TRIGGER_SHIFT) +#define VBOX_MSI_DATA_TRIGGER_LEVEL (1 << VBOX_MSI_DATA_TRIGGER_SHIFT) + +/** + * MSI Interrupt Delivery modes. + * In accordance with the Intel spec. + * See Intel spec. "10.11.2 Message Data Register Format". + */ +#define VBOX_MSI_DELIVERY_MODE_FIXED (0) +#define VBOX_MSI_DELIVERY_MODE_LOWEST_PRIO (1) +#define VBOX_MSI_DELIVERY_MODE_SMI (2) +#define VBOX_MSI_DELIVERY_MODE_NMI (4) +#define VBOX_MSI_DELIVERY_MODE_INIT (5) +#define VBOX_MSI_DELIVERY_MODE_EXT_INT (7) + +/** + * MSI region, actually same as LAPIC MMIO region, but listens on bus, + * not CPU, accesses. + */ +#define VBOX_MSI_ADDR_BASE 0xfee00000 +#define VBOX_MSI_ADDR_SIZE 0x100000 + +#define VBOX_MSI_ADDR_SHIFT 20 + +#define VBOX_MSI_ADDR_DEST_MODE_SHIFT 2 +#define VBOX_MSI_ADDR_DEST_MODE_PHYSICAL (0 << VBOX_MSI_ADDR_DEST_MODE_SHIFT) +#define VBOX_MSI_ADDR_DEST_MODE_LOGICAL (1 << VBOX_MSI_ADDR_DEST_MODE_SHIFT) + +#define VBOX_MSI_ADDR_REDIRECTION_SHIFT 3 +#define VBOX_MSI_ADDR_REDIRECTION_CPU (0 << VBOX_MSI_ADDR_REDIRECTION_SHIFT) + /* dedicated cpu */ +#define VBOX_MSI_ADDR_REDIRECTION_LOWPRI (1 << VBOX_MSI_ADDR_REDIRECTION_SHIFT) + /* lowest priority */ + +#define VBOX_MSI_ADDR_DEST_ID_SHIFT 12 +#define VBOX_MSI_ADDR_DEST_ID_MASK 0x00ffff0 +#define VBOX_MSI_ADDR_DEST_ID(dest) (((dest) << VBOX_MSI_ADDR_DEST_ID_SHIFT) & \ + VBOX_MSI_ADDR_DEST_ID_MASK) +#define VBOX_MSI_ADDR_EXT_DEST_ID(dest) ((dest) & 0xffffff00) + +#define VBOX_MSI_ADDR_IR_EXT_INT (1 << 4) +#define VBOX_MSI_ADDR_IR_SHV (1 << 3) +#define VBOX_MSI_ADDR_IR_INDEX1(index) ((index & 0x8000) >> 13) +#define VBOX_MSI_ADDR_IR_INDEX2(index) ((index & 0x7fff) << 5) + +/* Maximum number of vectors, per device/function */ +#define VBOX_MSI_MAX_ENTRIES 32 + +/* Offsets in MSI PCI capability structure (VBOX_PCI_CAP_ID_MSI) */ +#define VBOX_MSI_CAP_MESSAGE_CONTROL 0x02 +#define VBOX_MSI_CAP_MESSAGE_ADDRESS_32 0x04 +#define VBOX_MSI_CAP_MESSAGE_ADDRESS_LO 0x04 +#define VBOX_MSI_CAP_MESSAGE_ADDRESS_HI 0x08 +#define VBOX_MSI_CAP_MESSAGE_DATA_32 0x08 +#define VBOX_MSI_CAP_MESSAGE_DATA_64 0x0c +#define VBOX_MSI_CAP_MASK_BITS_32 0x0c +#define VBOX_MSI_CAP_PENDING_BITS_32 0x10 +#define VBOX_MSI_CAP_MASK_BITS_64 0x10 +#define VBOX_MSI_CAP_PENDING_BITS_64 0x14 + +/* We implement MSI with per-vector masking */ +#define VBOX_MSI_CAP_SIZE_32 0x14 +#define VBOX_MSI_CAP_SIZE_64 0x18 + +/** + * MSI-X differs from MSI by the fact that a dedicated physical page (in device + * memory) is assigned for MSI-X table, and Pending Bit Array (PBA), which is + * recommended to be separated from the main table by at least 2K. + * + * @{ + */ +/** Size of a MSI-X page */ +#define VBOX_MSIX_PAGE_SIZE 0x1000 +/** Pending interrupts (PBA) */ +#define VBOX_MSIX_PAGE_PENDING (VBOX_MSIX_PAGE_SIZE / 2) +/** Maximum number of vectors, per device/function */ +#define VBOX_MSIX_MAX_ENTRIES 2048 +/** Size of MSI-X PCI capability */ +#define VBOX_MSIX_CAP_SIZE 12 +/** Offsets in MSI-X PCI capability structure (VBOX_PCI_CAP_ID_MSIX) */ +#define VBOX_MSIX_CAP_MESSAGE_CONTROL 0x02 +#define VBOX_MSIX_TABLE_BIROFFSET 0x04 +#define VBOX_MSIX_PBA_BIROFFSET 0x08 +/** Size of single MSI-X table entry */ +#define VBOX_MSIX_ENTRY_SIZE 16 +/** @} */ + +/** + * MSI Address Register. + */ +typedef union MSIADDR +{ + /* + * Intel and AMD xAPIC format. + * See Intel spec. 10.11.1 "Message Address Register Format". + * This also conforms to the AMD IOMMU spec. which omits specifying + * individual fields but specifies reserved bits. + */ + struct + { + uint32_t u2Ign0 : 2; /**< Bits 1:0 - Ignored (read as 0, writes ignored). */ + uint32_t u1DestMode : 1; /**< Bit 2 - DM: Destination Mode. */ + uint32_t u1RedirHint : 1; /**< Bit 3 - RH: Redirection Hint. */ + uint32_t u8Rsvd0 : 8; /**< Bits 11:4 - Reserved. */ + uint32_t u8DestId : 8; /**< Bits 19:12 - Destination Id. */ + uint32_t u12Addr : 12; /**< Bits 31:20 - Address. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved. */ + } n; + + /* + * Intel x2APIC Format. + * See Intel VT-d spec. 5.1.6.2 "Programming in Intel 64 x2APIC Mode". + */ + struct + { + uint32_t u2Ign0 : 2; /**< Bits 1:0 - Ignored (read as 0, writes ignored). */ + uint32_t u1DestMode : 1; /**< Bit 2 - DM: Destination Mode. */ + uint32_t u1RedirHint : 1; /**< Bit 3 - RH: Redirection Hint. */ + uint32_t u8Rsvd0 : 8; /**< Bits 11:4 - Reserved. */ + uint32_t u8DestIdLo : 8; /**< Bits 19:12 - Destination Id (bits 7:0). */ + uint32_t u12Addr : 12; /**< Bits 31:20 - Address. */ + uint32_t u8Rsvd : 8; /**< Bits 39:32 - Reserved. */ + uint32_t u24DestIdHi : 24; /**< Bits 63:40 - Destination Id (bits 31:8). */ + } x2apic; + + /* + * Intel IOMMU Remappable Interrupt Format. + * See Intel VT-d spec. 5.1.2.2 "Interrupt Requests in Remappable Format". + */ + struct + { + uint32_t u2Ign0 : 2; /**< Bits 1:0 - Ignored (read as 0, writes ignored). */ + uint32_t u1IntrIndexHi : 1; /**< Bit 2 - Interrupt Index[15]. */ + uint32_t fShv : 1; /**< Bit 3 - Sub-Handle Valid. */ + uint32_t fIntrFormat : 1; /**< Bit 4 - Interrupt Format (1=remappable, 0=compatibility). */ + uint32_t u14IntrIndexLo : 15; /**< Bits 19:5 - Interrupt Index[14:0]. */ + uint32_t u12Addr : 12; /**< Bits 31:20 - Address. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved. */ + } dmar_remap; + + /** The 32-bit unsigned integer view. */ + uint32_t au32[2]; + + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} MSIADDR; +AssertCompileSize(MSIADDR, 8); +/** Pointer to an MSI address register. */ +typedef MSIADDR *PMSIADDR; +/** Pointer to a const MSI address register. */ +typedef MSIADDR const *PCMSIADDR; + +/** Mask of valid bits in the MSI address register. According to the AMD IOMMU spec. + * and presumably the PCI spec., the top 32-bits are not reserved. From a PCI/IOMMU + * standpoint this makes sense. However, when dealing with the CPU side of things + * we might want to ensure the upper bits are reserved. Does x86/x64 really + * support a 64-bit MSI address? */ +#define VBOX_MSI_ADDR_VALID_MASK UINT64_C(0xfffffffffffffffc) +#define VBOX_MSI_ADDR_ADDR_MASK UINT64_C(0x00000000fff00000) + +/** + * MSI Data Register. + */ +typedef union MSIDATA +{ + /* + * Intel and AMD xAPIC format. + * See Intel spec. 10.11.2 "Message Data Register Format". + * This also conforms to the AMD IOMMU spec. which omits specifying + * individual fields but specifies reserved bits. + */ + struct + { + uint32_t u8Vector : 8; /**< Bits 7:0 - Vector. */ + uint32_t u3DeliveryMode : 3; /**< Bits 10:8 - Delivery Mode. */ + uint32_t u3Rsvd0 : 3; /**< Bits 13:11 - Reserved. */ + uint32_t u1Level : 1; /**< Bit 14 - Level. */ + uint32_t u1TriggerMode : 1; /**< Bit 15 - Trigger Mode (0=edge, 1=level). */ + uint32_t u16Rsvd0 : 16; /**< Bits 31:16 - Reserved. */ + } n; + + /* + * Intel x2APIC Format. + * See Intel VT-d spec. 5.1.6.2 "Programming in Intel 64 x2APIC Mode". + */ + struct + { + uint32_t u8Vector : 8; /**< Bits 7:0 - Vector. */ + uint32_t u1DeliveryMode : 1; /**< Bit 8 - Delivery Mode (0=fixed, 1=lowest priority). */ + uint32_t u23Rsvd0 : 23; /**< Bits 31:9 - Reserved. */ + } x2apic; + + /* + * Intel IOMMU Remappable Interrupt Format. + * See Intel VT-d spec. 5.1.2.2 "Interrupt Requests in Remappable Format". + */ + struct + { + uint16_t u16SubHandle; + uint16_t u16Rsvd0; + } dmar_remap; + + /** The 32-bit unsigned integer view. */ + uint32_t u32; +} MSIDATA; +AssertCompileSize(MSIDATA, 4); +/** Pointer to an MSI data register. */ +typedef MSIDATA *PMSIDATA; +/** Pointer to a const MSI data register. */ +typedef MSIDATA const *PCMSIDATA; + +/** Mask of valid bits in the MSI data register. */ +#define VBOX_MSI_DATA_VALID_MASK UINT64_C(0x000000000000ffff) + +/** + * MSI Message (Address and Data Register Pair). + */ +typedef struct MSIMSG +{ + /** The MSI Address Register. */ + MSIADDR Addr; + /** The MSI Data Register. */ + MSIDATA Data; +} MSIMSG; + +#endif /* !VBOX_INCLUDED_msi_h */ diff --git a/include/VBox/nasm.mac b/include/VBox/nasm.mac new file mode 100644 index 00000000..13abd88b --- /dev/null +++ b/include/VBox/nasm.mac @@ -0,0 +1,44 @@ +;; @file +; Global NASM macros +; +; @deprecated Use VBox/asmdefs.mac +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef __VBox_nasm_mac__ +%define __VBox_nasm_mac__ + +%include "VBox/asmdefs.mac" + +%endif + diff --git a/include/VBox/ostypes.h b/include/VBox/ostypes.h new file mode 100644 index 00000000..8b82da43 --- /dev/null +++ b/include/VBox/ostypes.h @@ -0,0 +1,305 @@ +/** @file + * VirtualBox - Global Guest Operating System definition. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_ostypes_h +#define VBOX_INCLUDED_ostypes_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> + +RT_C_DECLS_BEGIN + +/** + * Global list of guest operating system types. + * + * They are grouped into families. A family identifer is always has + * mod 0x10000 == 0. New entries can be added, however other components + * depend on the values (e.g. the Qt GUI and guest additions) so the + * existing values MUST stay the same. + */ +typedef enum VBOXOSTYPE +{ + VBOXOSTYPE_Unknown = 0, + VBOXOSTYPE_Unknown_x64 = 0x00100, + + /** @name DOS and it's descendants + * @{ */ + VBOXOSTYPE_DOS = 0x10000, + VBOXOSTYPE_Win31 = 0x15000, + VBOXOSTYPE_Win9x = 0x20000, + VBOXOSTYPE_Win95 = 0x21000, + VBOXOSTYPE_Win98 = 0x22000, + VBOXOSTYPE_WinMe = 0x23000, + VBOXOSTYPE_WinNT = 0x30000, + VBOXOSTYPE_WinNT_x64 = 0x30100, + VBOXOSTYPE_WinNT3x = 0x30800, + VBOXOSTYPE_WinNT4 = 0x31000, + VBOXOSTYPE_Win2k = 0x32000, + VBOXOSTYPE_WinXP = 0x33000, + VBOXOSTYPE_WinXP_x64 = 0x33100, + VBOXOSTYPE_Win2k3 = 0x34000, + VBOXOSTYPE_Win2k3_x64 = 0x34100, + VBOXOSTYPE_WinVista = 0x35000, + VBOXOSTYPE_WinVista_x64 = 0x35100, + VBOXOSTYPE_Win2k8 = 0x36000, + VBOXOSTYPE_Win2k8_x64 = 0x36100, + VBOXOSTYPE_Win7 = 0x37000, + VBOXOSTYPE_Win7_x64 = 0x37100, + VBOXOSTYPE_Win8 = 0x38000, + VBOXOSTYPE_Win8_x64 = 0x38100, + VBOXOSTYPE_Win2k12_x64 = 0x39100, + VBOXOSTYPE_Win81 = 0x3A000, + VBOXOSTYPE_Win81_x64 = 0x3A100, + VBOXOSTYPE_Win10 = 0x3B000, + VBOXOSTYPE_Win10_x64 = 0x3B100, + VBOXOSTYPE_Win2k16_x64 = 0x3C100, + VBOXOSTYPE_Win2k19_x64 = 0x3D100, + VBOXOSTYPE_Win11_x64 = 0x3E100, + VBOXOSTYPE_Win2k22_x64 = 0x3F100, + VBOXOSTYPE_OS2 = 0x40000, + VBOXOSTYPE_OS2Warp3 = 0x41000, + VBOXOSTYPE_OS2Warp4 = 0x42000, + VBOXOSTYPE_OS2Warp45 = 0x43000, + VBOXOSTYPE_ECS = 0x44000, + VBOXOSTYPE_ArcaOS = 0x45000, + VBOXOSTYPE_OS21x = 0x48000, + /** @} */ + /** @name Unixy related OSes + * @{ */ + VBOXOSTYPE_Linux = 0x50000, + VBOXOSTYPE_Linux_x64 = 0x50100, + VBOXOSTYPE_Linux22 = 0x51000, + VBOXOSTYPE_Linux24 = 0x52000, + VBOXOSTYPE_Linux24_x64 = 0x52100, + VBOXOSTYPE_Linux26 = 0x53000, + VBOXOSTYPE_Linux26_x64 = 0x53100, + VBOXOSTYPE_ArchLinux = 0x54000, + VBOXOSTYPE_ArchLinux_x64 = 0x54100, + VBOXOSTYPE_Debian = 0x55000, + VBOXOSTYPE_Debian_x64 = 0x55100, + VBOXOSTYPE_Debian31 = 0x55001, // 32-bit only + VBOXOSTYPE_Debian4 = 0x55002, + VBOXOSTYPE_Debian4_x64 = 0x55102, + VBOXOSTYPE_Debian5 = 0x55003, + VBOXOSTYPE_Debian5_x64 = 0x55103, + VBOXOSTYPE_Debian6 = 0x55004, + VBOXOSTYPE_Debian6_x64 = 0x55104, + VBOXOSTYPE_Debian7 = 0x55005, + VBOXOSTYPE_Debian7_x64 = 0x55105, + VBOXOSTYPE_Debian8 = 0x55006, + VBOXOSTYPE_Debian8_x64 = 0x55106, + VBOXOSTYPE_Debian9 = 0x55007, + VBOXOSTYPE_Debian9_x64 = 0x55107, + VBOXOSTYPE_Debian10 = 0x55008, + VBOXOSTYPE_Debian10_x64 = 0x55108, + VBOXOSTYPE_Debian11 = 0x55009, + VBOXOSTYPE_Debian11_x64 = 0x55109, + VBOXOSTYPE_Debian_latest_x64 = VBOXOSTYPE_Debian11_x64, + VBOXOSTYPE_OpenSUSE = 0x56000, + VBOXOSTYPE_OpenSUSE_x64 = 0x56100, + VBOXOSTYPE_OpenSUSE_Leap_x64 = 0x56101, // 64-bit only + VBOXOSTYPE_OpenSUSE_Tumbleweed = 0x56002, + VBOXOSTYPE_OpenSUSE_Tumbleweed_x64 = 0x56102, + VBOXOSTYPE_SUSE_LE = 0x56003, + VBOXOSTYPE_SUSE_LE_x64 = 0x56103, + VBOXOSTYPE_FedoraCore = 0x57000, + VBOXOSTYPE_FedoraCore_x64 = 0x57100, + VBOXOSTYPE_Gentoo = 0x58000, + VBOXOSTYPE_Gentoo_x64 = 0x58100, + VBOXOSTYPE_Mandriva = 0x59000, + VBOXOSTYPE_Mandriva_x64 = 0x59100, + VBOXOSTYPE_OpenMandriva_Lx = 0x59001, + VBOXOSTYPE_OpenMandriva_Lx_x64 = 0x59101, + VBOXOSTYPE_PCLinuxOS = 0x59002, + VBOXOSTYPE_PCLinuxOS_x64 = 0x59102, + VBOXOSTYPE_Mageia = 0x59003, + VBOXOSTYPE_Mageia_x64 = 0x59103, + VBOXOSTYPE_RedHat = 0x5A000, + VBOXOSTYPE_RedHat_x64 = 0x5A100, + VBOXOSTYPE_RedHat3 = 0x5A001, + VBOXOSTYPE_RedHat3_x64 = 0x5A101, + VBOXOSTYPE_RedHat4 = 0x5A002, + VBOXOSTYPE_RedHat4_x64 = 0x5A102, + VBOXOSTYPE_RedHat5 = 0x5A003, + VBOXOSTYPE_RedHat5_x64 = 0x5A103, + VBOXOSTYPE_RedHat6 = 0x5A004, + VBOXOSTYPE_RedHat6_x64 = 0x5A104, + VBOXOSTYPE_RedHat7_x64 = 0x5A105, // 64-bit only + VBOXOSTYPE_RedHat8_x64 = 0x5A106, // 64-bit only + VBOXOSTYPE_RedHat9_x64 = 0x5A107, // 64-bit only + VBOXOSTYPE_RedHat_latest_x64 = VBOXOSTYPE_RedHat9_x64, + VBOXOSTYPE_Turbolinux = 0x5B000, + VBOXOSTYPE_Turbolinux_x64 = 0x5B100, + VBOXOSTYPE_Ubuntu = 0x5C000, + VBOXOSTYPE_Ubuntu_x64 = 0x5C100, + VBOXOSTYPE_Xubuntu = 0x5C001, + VBOXOSTYPE_Xubuntu_x64 = 0x5C101, + VBOXOSTYPE_Lubuntu = 0x5C002, + VBOXOSTYPE_Lubuntu_x64 = 0x5C102, + VBOXOSTYPE_Ubuntu10_LTS = 0x5C003, + VBOXOSTYPE_Ubuntu10_LTS_x64 = 0x5C103, + VBOXOSTYPE_Ubuntu10 = 0x5C004, + VBOXOSTYPE_Ubuntu10_x64 = 0x5C104, + VBOXOSTYPE_Ubuntu11 = 0x5C005, + VBOXOSTYPE_Ubuntu11_x64 = 0x5C105, + VBOXOSTYPE_Ubuntu12_LTS = 0x5C006, + VBOXOSTYPE_Ubuntu12_LTS_x64 = 0x5C106, + VBOXOSTYPE_Ubuntu12 = 0x5C007, + VBOXOSTYPE_Ubuntu12_x64 = 0x5C107, + VBOXOSTYPE_Ubuntu13 = 0x5C008, + VBOXOSTYPE_Ubuntu13_x64 = 0x5C108, + VBOXOSTYPE_Ubuntu14_LTS = 0x5C009, + VBOXOSTYPE_Ubuntu14_LTS_x64 = 0x5C109, + VBOXOSTYPE_Ubuntu14 = 0x5C00a, + VBOXOSTYPE_Ubuntu14_x64 = 0x5C10a, + VBOXOSTYPE_Ubuntu15 = 0x5C00b, + VBOXOSTYPE_Ubuntu15_x64 = 0x5C10b, + VBOXOSTYPE_Ubuntu16_LTS = 0x5C00c, + VBOXOSTYPE_Ubuntu16_LTS_x64 = 0x5C10c, + VBOXOSTYPE_Ubuntu16 = 0x5C00d, + VBOXOSTYPE_Ubuntu16_x64 = 0x5C10d, + VBOXOSTYPE_Ubuntu17 = 0x5C00e, + VBOXOSTYPE_Ubuntu17_x64 = 0x5C10e, + VBOXOSTYPE_Ubuntu18_LTS = 0x5C00f, + VBOXOSTYPE_Ubuntu18_LTS_x64 = 0x5C10f, + VBOXOSTYPE_Ubuntu18 = 0x5C010, + VBOXOSTYPE_Ubuntu18_x64 = 0x5C110, + VBOXOSTYPE_Ubuntu19 = 0x5C011, + VBOXOSTYPE_Ubuntu19_x64 = 0x5C111, + VBOXOSTYPE_Ubuntu20_LTS_x64 = 0x5C112, // 64-bit only + VBOXOSTYPE_Ubuntu20_x64 = 0x5C113, // 64-bit only + VBOXOSTYPE_Ubuntu21_x64 = 0x5C114, // 64-bit only + VBOXOSTYPE_Ubuntu22_LTS_x64 = 0x5C115, // 64-bit only + VBOXOSTYPE_Ubuntu22_x64 = 0x5C116, // 64-bit only + VBOXOSTYPE_Ubuntu_latest_x64 = VBOXOSTYPE_Ubuntu22_x64, + VBOXOSTYPE_Xandros = 0x5D000, + VBOXOSTYPE_Xandros_x64 = 0x5D100, + VBOXOSTYPE_Oracle = 0x5E000, + VBOXOSTYPE_Oracle_x64 = 0x5E100, + VBOXOSTYPE_Oracle4 = 0x5E001, + VBOXOSTYPE_Oracle4_x64 = 0x5E101, + VBOXOSTYPE_Oracle5 = 0x5E002, + VBOXOSTYPE_Oracle5_x64 = 0x5E102, + VBOXOSTYPE_Oracle6 = 0x5E003, + VBOXOSTYPE_Oracle6_x64 = 0x5E103, + VBOXOSTYPE_Oracle7_x64 = 0x5E104, // 64-bit only + VBOXOSTYPE_Oracle8_x64 = 0x5E105, // 64-bit only + VBOXOSTYPE_Oracle9_x64 = 0x5E106, // 64-bit only + VBOXOSTYPE_Oracle_latest_x64 = VBOXOSTYPE_Oracle9_x64, + VBOXOSTYPE_FreeBSD = 0x60000, + VBOXOSTYPE_FreeBSD_x64 = 0x60100, + VBOXOSTYPE_OpenBSD = 0x61000, + VBOXOSTYPE_OpenBSD_x64 = 0x61100, + VBOXOSTYPE_NetBSD = 0x62000, + VBOXOSTYPE_NetBSD_x64 = 0x62100, + VBOXOSTYPE_Netware = 0x70000, + VBOXOSTYPE_Solaris = 0x80000, // Solaris 10U7 (5/09) and earlier + VBOXOSTYPE_Solaris_x64 = 0x80100, // Solaris 10U7 (5/09) and earlier + VBOXOSTYPE_Solaris10U8_or_later = 0x80001, + VBOXOSTYPE_Solaris10U8_or_later_x64 = 0x80101, + VBOXOSTYPE_OpenSolaris = 0x81000, + VBOXOSTYPE_OpenSolaris_x64 = 0x81100, + VBOXOSTYPE_Solaris11_x64 = 0x82100, + VBOXOSTYPE_L4 = 0x90000, + VBOXOSTYPE_QNX = 0xA0000, + VBOXOSTYPE_MacOS = 0xB0000, + VBOXOSTYPE_MacOS_x64 = 0xB0100, + VBOXOSTYPE_MacOS106 = 0xB2000, + VBOXOSTYPE_MacOS106_x64 = 0xB2100, + VBOXOSTYPE_MacOS107_x64 = 0xB3100, + VBOXOSTYPE_MacOS108_x64 = 0xB4100, + VBOXOSTYPE_MacOS109_x64 = 0xB5100, + VBOXOSTYPE_MacOS1010_x64 = 0xB6100, + VBOXOSTYPE_MacOS1011_x64 = 0xB7100, + VBOXOSTYPE_MacOS1012_x64 = 0xB8100, + VBOXOSTYPE_MacOS1013_x64 = 0xB9100, + /** @} */ + /** @name Other OSes and stuff + * @{ */ + VBOXOSTYPE_JRockitVE = 0xC0000, + VBOXOSTYPE_Haiku = 0xD0000, + VBOXOSTYPE_Haiku_x64 = 0xD0100, + VBOXOSTYPE_VBoxBS_x64 = 0xE0100, + /** @} */ + + /** OS type mask. */ + VBOXOSTYPE_OsTypeMask = 0x00fff000, + + /** @name Architecture Type + * @{ */ + /** Mask containing the architecture value. */ + VBOXOSTYPE_ArchitectureMask = 0x00f00, + /** Architecture value for 16-bit and 32-bit x86. */ + VBOXOSTYPE_x86 = 0x00000, + /** Architecture value for 64-bit x86 (AMD64). */ + VBOXOSTYPE_x64 = 0x00100, + /** Architecture value for 32-bit ARM. */ + VBOXOSTYPE_arm32 = 0x00200, + /** Architecture value for 64-bit ARM. */ + VBOXOSTYPE_arm64 = 0x00300, + /** Architecture value for unknown or unsupported architectures. */ + VBOXOSTYPE_UnknownArch = 0x00f00, + /** @} */ + + /** The usual 32-bit hack. */ + VBOXOSTYPE_32BIT_HACK = 0x7fffffff +} VBOXOSTYPE; + + +/** + * Global list of guest OS families. + */ +typedef enum VBOXOSFAMILY +{ + VBOXOSFAMILY_Unknown = 0, + VBOXOSFAMILY_Windows32 = 1, + VBOXOSFAMILY_Windows64 = 2, + VBOXOSFAMILY_Linux32 = 3, + VBOXOSFAMILY_Linux64 = 4, + VBOXOSFAMILY_FreeBSD32 = 5, + VBOXOSFAMILY_FreeBSD64 = 6, + VBOXOSFAMILY_Solaris32 = 7, + VBOXOSFAMILY_Solaris64 = 8, + VBOXOSFAMILY_MacOSX32 = 9, + VBOXOSFAMILY_MacOSX64 = 10, + /** The usual 32-bit hack. */ + VBOXOSFAMILY_32BIT_HACK = 0x7fffffff +} VBOXOSFAMILY; + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_ostypes_h */ diff --git a/include/VBox/param.h b/include/VBox/param.h new file mode 100644 index 00000000..fb6e5ddc --- /dev/null +++ b/include/VBox/param.h @@ -0,0 +1,229 @@ +/** @file + * VirtualBox Parameter Definitions. (VMM,+) + * + * param.mac is generated from this file by running 'kmk incs' in the root. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_param_h +#define VBOX_INCLUDED_param_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/param.h> +#include <iprt/cdefs.h> + + +/** @defgroup grp_vbox_param VBox Parameter Definition + * @{ + */ + +/** The guest page size (x86). */ +#define GUEST_PAGE_SIZE 0x1000 +/** The guest page offset mask (x86). + * @note If one-complementing this, always put a typecast after the operator! */ +#define GUEST_PAGE_OFFSET_MASK 0xfff +/** The guest page shift (x86). */ +#define GUEST_PAGE_SHIFT 12 + +/** Host page size. */ +#define HOST_PAGE_SIZE PAGE_SIZE +/** Host page offset mask. + * @note If one-complementing this, always put a typecast after the operator! */ +#define HOST_PAGE_OFFSET_MASK PAGE_OFFSET_MASK +/** Host page shift. */ +#define HOST_PAGE_SHIFT PAGE_SHIFT + + +/** The maximum number of pages that can be allocated and mapped + * by various MM, PGM and SUP APIs. */ +#if ARCH_BITS == 64 +# define VBOX_MAX_ALLOC_PAGE_COUNT (_512M / PAGE_SIZE) +#else +# define VBOX_MAX_ALLOC_PAGE_COUNT (_256M / PAGE_SIZE) +#endif + +/** @def VBOX_WITH_PAGE_SHARING + * Enables the page sharing code. + * @remarks This must match GMMR0Init; currently we only support page fusion on + * all 64-bit hosts except Mac OS X */ +#if ( HC_ARCH_BITS == 64 /* ASM-NOINC */ \ + && (defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_WINDOWS)) ) /* ASM-NOINC */ \ + || defined(DOXYGEN_RUNNING) /* ASM-NOINC */ +# define VBOX_WITH_PAGE_SHARING /* ASM-NOINC */ +#endif /* ASM-NOINC */ + + +/** @defgroup grp_vbox_param_mm Memory Monitor Parameters + * @{ + */ +/** Initial address of Hypervisor Memory Area. + * MUST BE PAGE TABLE ALIGNED! */ +#define MM_HYPER_AREA_ADDRESS UINT32_C(0xa0000000) + +/** The max size of the hypervisor memory area. */ +#define MM_HYPER_AREA_MAX_SIZE (40U * _1M) /**< @todo Readjust when floating RAMRANGEs have been implemented. Used to be 20 * _1MB */ + +/** Maximum number of bytes we can dynamically map into the hypervisor region. + * This must be a power of 2 number of pages! + */ +#define MM_HYPER_DYNAMIC_SIZE (16U * PAGE_SIZE) + +/** The minimum guest RAM size in bytes. */ +#define MM_RAM_MIN UINT32_C(0x00400000) +/** The maximum guest RAM size in bytes. */ +#if HC_ARCH_BITS == 64 +# define MM_RAM_MAX UINT64_C(0x20000000000) +#else +# define MM_RAM_MAX UINT64_C(0x000E0000000) +#endif +/** The minimum guest RAM size in MBs. */ +#define MM_RAM_MIN_IN_MB UINT32_C(4) +/** The maximum guest RAM size in MBs. */ +#if HC_ARCH_BITS == 64 +# define MM_RAM_MAX_IN_MB UINT32_C(2097152) +#else +# define MM_RAM_MAX_IN_MB UINT32_C(3584) +#endif +/** The default size of the below 4GB RAM hole. */ +#define MM_RAM_HOLE_SIZE_DEFAULT (512U * _1M) +/** The maximum 64-bit MMIO BAR size. + * @remarks There isn't really any limit here other than the size of the + * tracking structures we need (around 1/256 of the size). */ +#if HC_ARCH_BITS == 64 +# define MM_MMIO_64_MAX _1T +#else +# define MM_MMIO_64_MAX (_1G64 * 16) +#endif +/** The maximum 32-bit MMIO BAR size. */ +#define MM_MMIO_32_MAX _2G + +/** @} */ + +/** @defgroup grp_vbox_param_pdm Pluggable Device Manager Parameters + * @{ + */ +/** Max number of network shaper groups. */ +#define PDM_NET_SHAPER_MAX_GROUPS 32 +/** Max length of a network shaper group name (excluding terminator). */ +#define PDM_NET_SHAPER_MAX_NAME_LEN 63 +/** @} */ + + +/** @defgroup grp_vbox_param_pgm Page Manager Parameters + * @{ + */ +/** The number of handy pages. + * This should be a power of two. */ +#define PGM_HANDY_PAGES 128 +/** The threshold at which allocation of more handy pages is flagged. */ +#define PGM_HANDY_PAGES_SET_FF 32 +/** The threshold at which we will allocate more when in ring-3. + * This is must be smaller than both PGM_HANDY_PAGES_SET_FF and + * PGM_HANDY_PAGES_MIN. */ +#define PGM_HANDY_PAGES_R3_ALLOC 8 +/** The threshold at which we will allocate more when in ring-0 or raw mode. + * The idea is that we should never go below this threshold while in ring-0 or + * raw mode because of PGM_HANDY_PAGES_RZ_TO_R3. However, should this happen and + * we are actually out of memory, we will have 8 page to get out of whatever + * code we're executing. + * + * This is must be smaller than both PGM_HANDY_PAGES_SET_FF and + * PGM_HANDY_PAGES_MIN. */ +#define PGM_HANDY_PAGES_RZ_ALLOC 8 +/** The threshold at which we force return to R3 ASAP. + * The idea is that this should be large enough to get out of any code and up to + * the main EM loop when we are out of memory. + * This must be less or equal to PGM_HANDY_PAGES_MIN. */ +#define PGM_HANDY_PAGES_RZ_TO_R3 24 +/** The minimum number of handy pages (after allocation). + * This must be greater or equal to PGM_HANDY_PAGES_SET_FF. + * Another name would be PGM_HANDY_PAGES_EXTRA_RESERVATION or _PARANOIA. :-) */ +#define PGM_HANDY_PAGES_MIN 32 +/** @} */ + + +/** @defgroup grp_vbox_param_vmm VMM Parameters + * @{ + */ +/** VMM stack size. */ +#ifdef RT_OS_DARWIN +# define VMM_STACK_SIZE 16384U +#else +# define VMM_STACK_SIZE 8192U +#endif +/** Min number of Virtual CPUs. */ +#define VMM_MIN_CPU_COUNT 1 +/** Max number of Virtual CPUs. */ +#define VMM_MAX_CPU_COUNT 64 + +/** @} */ + + +/** @defgroup grp_vbox_pci PCI Identifiers + * @{ */ +/** VirtualBox PCI vendor ID. */ +#define VBOX_PCI_VENDORID (0x80ee) + +/** @name VirtualBox graphics card identifiers + * @{ */ +#define VBOX_VENDORID VBOX_PCI_VENDORID /**< @todo wonderful choice of name! Please squeeze a _VGA_ or something in there, please. */ +#define VBOX_DEVICEID (0xbeef) /**< @todo ditto. */ +#define VBOX_VESA_VENDORID VBOX_PCI_VENDORID +#define VBOX_VESA_DEVICEID (0xbeef) +/** @} */ + +/** @name VMMDev PCI card identifiers + * @{ */ +#define VMMDEV_VENDORID VBOX_PCI_VENDORID +#define VMMDEV_DEVICEID (0xcafe) +/** @} */ + +/** @} */ + + +/** @defgroup grp_vbox_param_misc Misc + * @{ */ + +/** The maximum size of a generic segment offload (GSO) frame. This limit is + * imposed by the 16-bit frame size in internal networking header. */ +#define VBOX_MAX_GSO_SIZE 0xfff0 + +/** @} */ + + +/** @} */ + +#endif /* !VBOX_INCLUDED_param_h */ + diff --git a/include/VBox/param.mac b/include/VBox/param.mac new file mode 100644 index 00000000..b35a5f45 --- /dev/null +++ b/include/VBox/param.mac @@ -0,0 +1,98 @@ +;; @file +; VirtualBox Parameter Definitions. (VMM,+) +; +; Automatically generated by various.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef VBOX_INCLUDED_param_h +%define VBOX_INCLUDED_param_h +%ifndef RT_WITHOUT_PRAGMA_ONCE +%endif +%define GUEST_PAGE_SIZE 0x1000 +%define GUEST_PAGE_OFFSET_MASK 0xfff +%define GUEST_PAGE_SHIFT 12 +%define HOST_PAGE_SIZE PAGE_SIZE +%define HOST_PAGE_OFFSET_MASK PAGE_OFFSET_MASK +%define HOST_PAGE_SHIFT PAGE_SHIFT +%if ARCH_BITS == 64 + %define VBOX_MAX_ALLOC_PAGE_COUNT (_512M / PAGE_SIZE) +%else + %define VBOX_MAX_ALLOC_PAGE_COUNT (_256M / PAGE_SIZE) +%endif +%define MM_HYPER_AREA_ADDRESS 0xa0000000 +%define MM_HYPER_AREA_MAX_SIZE (40U * _1M) +%define MM_HYPER_DYNAMIC_SIZE (16U * PAGE_SIZE) +%define MM_RAM_MIN 0x00400000 +%if HC_ARCH_BITS == 64 + %define MM_RAM_MAX 0x20000000000 +%else + %define MM_RAM_MAX 0x000E0000000 +%endif +%define MM_RAM_MIN_IN_MB 4 +%if HC_ARCH_BITS == 64 + %define MM_RAM_MAX_IN_MB 2097152 +%else + %define MM_RAM_MAX_IN_MB 3584 +%endif +%define MM_RAM_HOLE_SIZE_DEFAULT (512U * _1M) +%if HC_ARCH_BITS == 64 + %define MM_MMIO_64_MAX _1T +%else + %define MM_MMIO_64_MAX (_1G64 * 16) +%endif +%define MM_MMIO_32_MAX _2G +%define PDM_NET_SHAPER_MAX_GROUPS 32 +%define PDM_NET_SHAPER_MAX_NAME_LEN 63 +%define PGM_HANDY_PAGES 128 +%define PGM_HANDY_PAGES_SET_FF 32 +%define PGM_HANDY_PAGES_R3_ALLOC 8 +%define PGM_HANDY_PAGES_RZ_ALLOC 8 +%define PGM_HANDY_PAGES_RZ_TO_R3 24 +%define PGM_HANDY_PAGES_MIN 32 +%ifdef RT_OS_DARWIN + %define VMM_STACK_SIZE 16384 +%else + %define VMM_STACK_SIZE 8192 +%endif +%define VMM_MIN_CPU_COUNT 1 +%define VMM_MAX_CPU_COUNT 64 +%define VBOX_PCI_VENDORID (0x80ee) +%define VBOX_VENDORID VBOX_PCI_VENDORID +%define VBOX_DEVICEID (0xbeef) +%define VBOX_VESA_VENDORID VBOX_PCI_VENDORID +%define VBOX_VESA_DEVICEID (0xbeef) +%define VMMDEV_VENDORID VBOX_PCI_VENDORID +%define VMMDEV_DEVICEID (0xcafe) +%define VBOX_MAX_GSO_SIZE 0xfff0 +%endif diff --git a/include/VBox/pci.h b/include/VBox/pci.h new file mode 100644 index 00000000..8d5054fe --- /dev/null +++ b/include/VBox/pci.h @@ -0,0 +1,827 @@ +/** @file + * PCI - The PCI Controller And Devices Constants. (DEV) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_pci_h +#define VBOX_INCLUDED_pci_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <iprt/assert.h> + +/** @defgroup grp_pci PCI - The PCI Controller. + * @ingroup grp_devdrv + * @{ + */ + +/** @name PCI device classes. + * @{ */ +#define VBOX_PCI_CLASS_UNCLASSIFIED 0x00 +#define VBOX_PCI_CLASS_MASS_STORAGE 0x01 +#define VBOX_PCI_CLASS_NETWORK 0x02 +#define VBOX_PCI_CLASS_DISPLAY 0x03 +#define VBOX_PCI_CLASS_MULTI_MEDIA 0x04 +#define VBOX_PCI_CLASS_MEMORY 0x05 +#define VBOX_PCI_CLASS_BRIDGE 0x06 +#define VBOX_PCI_CLASS_COMM 0x07 +#define VBOX_PCI_CLASS_SYSTEM 0x08 +#define VBOX_PCI_CLASS_INPUT 0x09 +#define VBOX_PCI_CLASS_DOCKING_STATION 0x0a +#define VBOX_PCI_CLASS_PROCESSOR 0x0b +#define VBOX_PCI_CLASS_SERIAL_BUS 0x0c +#define VBOX_PCI_CLASS_WIRELESS 0x0d +#define VBOX_PCI_CLASS_INTELLIGENT 0x0e +#define VBOX_PCI_CLASS_SAT_COMM 0x0f +#define VBOX_PCI_CLASS_ENCRYPTION 0x10 +#define VBOX_PCI_CLASS_SIG_PROC 0x11 +#define VBOX_PCI_CLASS_PROC_ACCEL 0x12 +#define VBOX_PCI_CLASS_NON_ESS_INSTR 0x13 +#define VBOX_PCI_CLASS_CO_PROCESSOR 0x40 +#define VBOX_PCI_CLASS_UNASSIGNED 0xff +/** @} */ + +/** @name PCI device sub-classes. + * @{ */ +#define VBOX_PCI_SUB_UNCLASSIFIED_NON_VGA 0x00 +#define VBOX_PCI_SUB_UNCLASSIFIED_VGA 0x01 + +#define VBOX_PCI_SUB_MASS_STORAGE_SCSI_BUS 0x00 +#define VBOX_PCI_SUB_MASS_STORAGE_IDE 0x01 +#define VBOX_PCI_SUB_MASS_STORAGE_FLOPPY 0x02 +#define VBOX_PCI_SUB_MASS_STORAGE_IPI_BUS 0x03 +#define VBOX_PCI_SUB_MASS_STORAGE_RAID 0x04 +#define VBOX_PCI_SUB_MASS_STORAGE_ATA 0x05 +#define VBOX_PCI_SUB_MASS_STORAGE_SATA 0x06 +#define VBOX_PCI_SUB_MASS_STORAGE_SCSI 0x07 +#define VBOX_PCI_SUB_MASS_STORAGE_NVME 0x08 +#define VBOX_PCI_SUB_MASS_STORAGE_OTHER 0x80 + +#define VBOX_PCI_SUB_NETWORK_ETHERNET 0x00 +#define VBOX_PCI_SUB_NETWORK_TOKEN_RING 0x01 +#define VBOX_PCI_SUB_NETWORK_FDDI 0x02 +#define VBOX_PCI_SUB_NETWORK_ATM 0x03 +#define VBOX_PCI_SUB_NETWORK_ISDN 0x04 +#define VBOX_PCI_SUB_NETWORK_WORLD_FIP 0x05 +#define VBOX_PCI_SUB_NETWORK_PICMG 0x06 +#define VBOX_PCI_SUB_NETWORK_INFINIBAND 0x07 +#define VBOX_PCI_SUB_NETWORK_FABRIC 0x08 +#define VBOX_PCI_SUB_NETWORK_OTHER 0x80 + +#define VBOX_PCI_SUB_DISPLAY_VGA 0x00 +#define VBOX_PCI_SUB_DISPLAY_XGA 0x01 +#define VBOX_PCI_SUB_DISPLAY_3D 0x02 +#define VBOX_PCI_SUB_DISPLAY_OTHER 0x80 + +#define VBOX_PCI_SUB_MULTI_MEDIA_MM_VIDEO 0x00 +#define VBOX_PCI_SUB_MULTI_MEDIA_MM_AUDIO 0x01 +#define VBOX_PCI_SUB_MULTI_MEDIA_TELE 0x02 +#define VBOX_PCI_SUB_MULTI_MEDIA_AUDIO 0x03 +#define VBOX_PCI_SUB_MULTI_MEDIA_OTHER 0x80 + +#define VBOX_PCI_SUB_MEMORY_RAM 0x00 +#define VBOX_PCI_SUB_MEMORY_FLASH 0x01 +#define VBOX_PCI_SUB_MEMORY_OTHER 0x80 + +#define VBOX_PCI_SUB_BRIDGE_HOST 0x00 +#define VBOX_PCI_SUB_BRIDGE_ISA 0x01 +#define VBOX_PCI_SUB_BRIDGE_EISA 0x02 +#define VBOX_PCI_SUB_BRIDGE_MCA 0x03 +#define VBOX_PCI_SUB_BRIDGE_PCI 0x04 +#define VBOX_PCI_SUB_BRIDGE_PCMCIA 0x05 +#define VBOX_PCI_SUB_BRIDGE_NUBUS 0x06 +#define VBOX_PCI_SUB_BRIDGE_CARDBUS 0x07 +#define VBOX_PCI_SUB_BRIDGE_RACEWAY 0x08 +#define VBOX_PCI_SUB_BRIDGE_SEMI_PCI 0x09 +#define VBOX_PCI_SUB_BRIDGE_INFINIBAND_PCI 0x0a +#define VBOX_PCI_SUB_BRIDGE_OTHER 0x80 + +#define VBOX_PCI_SUB_COMM_SERIAL 0x00 +#define VBOX_PCI_SUB_COMM_PARALLEL 0x01 +#define VBOX_PCI_SUB_COMM_MULTIPORT_SERIAL 0x02 +#define VBOX_PCI_SUB_COMM_MODEM 0x03 +#define VBOX_PCI_SUB_COMM_GBIP 0x04 +#define VBOX_PCI_SUB_COMM_SMART_CARD 0x05 +#define VBOX_PCI_SUB_COMM_OTHER 0x80 + +#define VBOX_PCI_SUB_SYSTEM_PIC 0x00 +#define VBOX_PCI_SUB_SYSTEM_DMA 0x01 +#define VBOX_PCI_SUB_SYSTEM_TIMER 0x02 +#define VBOX_PCI_SUB_SYSTEM_RTC 0x03 +#define VBOX_PCI_SUB_SYSTEM_PCI_HOTPLUG 0x04 +#define VBOX_PCI_SUB_SYSTEM_SD_HOST 0x05 +#define VBOX_PCI_SUB_SYSTEM_IOMMU 0x06 +#define VBOX_PCI_SUB_SYSTEM_OTHER 0x80 + +#define VBOX_PCI_SUB_INPUT_KEYBOARD 0x00 +#define VBOX_PCI_SUB_INPUT_PEN 0x01 +#define VBOX_PCI_SUB_INPUT_MOUSE 0x02 +#define VBOX_PCI_SUB_INPUT_SCANNER 0x03 +#define VBOX_PCI_SUB_INPUT_GAMEPORT 0x04 +#define VBOX_PCI_SUB_INPUT_OTHER 0x80 + +#define VBOX_PCI_SUB_DOCKING_ST_GENERIC 0x00 +#define VBOX_PCI_SUB_DOCKING_ST_OTHER 0x80 + +#define VBOX_PCI_SUB_PROCESSOR_386 0x00 +#define VBOX_PCI_SUB_PROCESSOR_486 0x01 +#define VBOX_PCI_SUB_PROCESSOR_PENTIUM 0x02 +#define VBOX_PCI_SUB_PROCESSOR_PENTIUM_PRO 0x03 +#define VBOX_PCI_SUB_PROCESSOR_ALPHA 0x10 +#define VBOX_PCI_SUB_PROCESSOR_POWERPC 0x20 +#define VBOX_PCI_SUB_PROCESSOR_MIPS 0x30 +#define VBOX_PCI_SUB_PROCESSOR_CO_PROC 0x40 +#define VBOX_PCI_SUB_PROCESSOR_OTHER 0x80 + +#define VBOX_PCI_SUB_SERIAL_BUS_FIREWIRE 0x00 +#define VBOX_PCI_SUB_SERIAL_BUS_ACCESS 0x01 +#define VBOX_PCI_SUB_SERIAL_BUS_SSA 0x02 +#define VBOX_PCI_SUB_SERIAL_BUS_USB 0x03 +#define VBOX_PCI_SUB_SERIAL_BUS_FIBRE 0x04 +#define VBOX_PCI_SUB_SERIAL_BUS_SMBUS 0x05 +#define VBOX_PCI_SUB_SERIAL_BUS_INFINIBAND 0x06 +#define VBOX_PCI_SUB_SERIAL_BUS_IPMI 0x07 +#define VBOX_PCI_SUB_SERIAL_BUS_SERCOS 0x08 +#define VBOX_PCI_SUB_SERIAL_BUS_CANBUS 0x09 +#define VBOX_PCI_SUB_SERIAL_BUS_OTHER 0x80 + +#define VBOX_PCI_SUB_WIRELESS_IRDA 0x00 +#define VBOX_PCI_SUB_WIRELESS_IR 0x01 +#define VBOX_PCI_SUB_WIRELESS_RF 0x10 +#define VBOX_PCI_SUB_WIRELESS_BLUETOOTH 0x11 +#define VBOX_PCI_SUB_WIRELESS_BROADBAND 0x12 +#define VBOX_PCI_SUB_WIRELESS_ETH_8021A 0x20 +#define VBOX_PCI_SUB_WIRELESS_ETH_8021B 0x21 +#define VBOX_PCI_SUB_WIRELESS_OTHER 0x80 + +#define VBOX_PCI_SUB_INTELLIGENT_I20 0x00 + +#define VBOX_PCI_SUB_SAT_COMM_TV 0x01 +#define VBOX_PCI_SUB_SAT_COMM_AUDIO 0x02 +#define VBOX_PCI_SUB_SAT_COMM_VOICE 0x03 +#define VBOX_PCI_SUB_SAT_COMM_DATA 0x04 + +#define VBOX_PCI_SUB_ENCRYPT_NETWORK 0x00 +#define VBOX_PCI_SUB_ENCRYPT_ENTERTAINMENT 0x01 +#define VBOX_PCI_SUB_ENCRYPT_OTHER 0x80 + +#define VBOX_PCI_SUB_SIG_PROC_DPIO 0x00 +#define VBOX_PCI_SUB_SIG_PROC_PERF_COUNTERS 0x01 +#define VBOX_PCI_SUB_SIG_PROC_COMM_SYNC 0x10 +#define VBOX_PCI_SUB_SIG_PROC_MANAGEMENT 0x20 +#define VBOX_PCI_SUB_SIG_PROC_OTHER 0x80 +/** @} */ + +/** + * PCI configuration word 4 (command) and word 6 (status). + */ +typedef enum PCICONFIGCOMMAND +{ + /** Supports/uses memory accesses. */ + PCI_COMMAND_IOACCESS = 0x0001, + PCI_COMMAND_MEMACCESS = 0x0002, + PCI_COMMAND_BUSMASTER = 0x0004 +} PCICONFIGCOMMAND; + + +/** + * PCI Address space specification. + * This is used when registering a I/O region. + */ +/** + * Defined by the PCI specification. + */ +typedef enum PCIADDRESSSPACE +{ + /** Memory. */ + PCI_ADDRESS_SPACE_MEM = 0x00, + /** I/O space. */ + PCI_ADDRESS_SPACE_IO = 0x01, + /** 32-bit BAR. */ + PCI_ADDRESS_SPACE_BAR32 = 0x00, + /** 64-bit BAR. */ + PCI_ADDRESS_SPACE_BAR64 = 0x04, + /** Prefetch memory. */ + PCI_ADDRESS_SPACE_MEM_PREFETCH = 0x08 +} PCIADDRESSSPACE; + + +/** + * PCI Memory Request with Address Type. + * In accordance with the PCI ATS spec. + * See PCI ATS spec. 2.1."Memory Requests with Address Type". + */ +typedef enum PCIADDRTYPE +{ + /** Untranslated request. */ + PCIADDRTYPE_UNTRANSLATED = 0x0, + /** Translation request. */ + PCIADDRTYPE_TRANSLATION, + /** Translated requested. */ + PCIADDRTYPE_TRANSLATED, + /** Reserved. */ + PCIADDRTYPE_RSVD +} PCIADDRTYPE; + + +/** @name PCI Configuration Space Registers + * @{ */ +/* Commented out values common for different header types */ +/* Common part of the header */ +#define VBOX_PCI_VENDOR_ID 0x00 /**< 16-bit RO */ +#define VBOX_PCI_DEVICE_ID 0x02 /**< 16-bit RO */ +#define VBOX_PCI_COMMAND 0x04 /**< 16-bit RW, some bits RO */ +#define VBOX_PCI_STATUS 0x06 /**< 16-bit RW, some bits RO */ +#define VBOX_PCI_REVISION_ID 0x08 /**< 8-bit RO - - device revision */ +#define VBOX_PCI_CLASS_PROG 0x09 /**< 8-bit RO - - register-level programming class code (device specific). */ +#define VBOX_PCI_CLASS_SUB 0x0a /**< 8-bit RO - - sub-class code. */ +#define VBOX_PCI_CLASS_DEVICE VBOX_PCI_CLASS_SUB +#define VBOX_PCI_CLASS_BASE 0x0b /**< 8-bit RO - - base class code. */ +#define VBOX_PCI_CACHE_LINE_SIZE 0x0c /**< 8-bit RW - - system cache line size */ +#define VBOX_PCI_LATENCY_TIMER 0x0d /**< 8-bit RW - - master latency timer, hardwired to 0 for PCIe */ +#define VBOX_PCI_HEADER_TYPE 0x0e /**< 8-bit RO - - header type (0 - device, 1 - bridge, 2 - CardBus bridge) */ +#define VBOX_PCI_BIST 0x0f /**< 8-bit RW - - built-in self test control */ +#define VBOX_PCI_CAPABILITY_LIST 0x34 /**< 8-bit RO? - - linked list of new capabilities implemented by the device, 2 bottom bits reserved */ +#define VBOX_PCI_INTERRUPT_LINE 0x3c /**< 8-bit RW - - interrupt line. */ +#define VBOX_PCI_INTERRUPT_PIN 0x3d /**< 8-bit RO - - interrupt pin. */ + +/* Type 0 header, device */ +#define VBOX_PCI_BASE_ADDRESS_0 0x10 /**< 32-bit RW */ +#define VBOX_PCI_BASE_ADDRESS_1 0x14 /**< 32-bit RW */ +#define VBOX_PCI_BASE_ADDRESS_2 0x18 /**< 32-bit RW */ +#define VBOX_PCI_BASE_ADDRESS_3 0x1c /**< 32-bit RW */ +#define VBOX_PCI_BASE_ADDRESS_4 0x20 /**< 32-bit RW */ +#define VBOX_PCI_BASE_ADDRESS_5 0x24 /**< 32-bit RW */ +#define VBOX_PCI_CARDBUS_CIS 0x28 /**< 32-bit ?? */ +#define VBOX_PCI_SUBSYSTEM_VENDOR_ID 0x2c /**< 16-bit RO */ +#define VBOX_PCI_SUBSYSTEM_ID 0x2e /**< 16-bit RO */ +#define VBOX_PCI_ROM_ADDRESS 0x30 /**< 32-bit ?? */ +/* #define VBOX_PCI_CAPABILITY_LIST 0x34 */ /**< 8-bit? ?? */ +#define VBOX_PCI_RESERVED_35 0x35 /**< 8-bit ?? - - reserved */ +#define VBOX_PCI_RESERVED_36 0x36 /**< 8-bit ?? - - reserved */ +#define VBOX_PCI_RESERVED_37 0x37 /**< 8-bit ?? - - reserved */ +#define VBOX_PCI_RESERVED_38 0x38 /**< 32-bit ?? - - reserved */ +/* #define VBOX_PCI_INTERRUPT_LINE 0x3c */ /**< 8-bit RW - - interrupt line. */ +/* #define VBOX_PCI_INTERRUPT_PIN 0x3d */ /**< 8-bit RO - - interrupt pin. */ +#define VBOX_PCI_MIN_GNT 0x3e /**< 8-bit RO - - burst period length (in 1/4 microsecond units) */ +#define VBOX_PCI_MAX_LAT 0x3f /**< 8-bit RO - - how often the device needs access to the PCI bus (in 1/4 microsecond units) */ + +/* Type 1 header, PCI-to-PCI bridge */ +/* #define VBOX_PCI_BASE_ADDRESS_0 0x10 */ /**< 32-bit RW */ +/* #define VBOX_PCI_BASE_ADDRESS_1 0x14 */ /**< 32-bit RW */ +#define VBOX_PCI_PRIMARY_BUS 0x18 /**< 8-bit ?? - - primary bus number. */ +#define VBOX_PCI_SECONDARY_BUS 0x19 /**< 8-bit ?? - - secondary bus number. */ +#define VBOX_PCI_SUBORDINATE_BUS 0x1a /**< 8-bit ?? - - highest subordinate bus number. (behind the bridge) */ +#define VBOX_PCI_SEC_LATENCY_TIMER 0x1b /**< 8-bit ?? - - secondary latency timer. */ +#define VBOX_PCI_IO_BASE 0x1c /**< 8-bit ?? - - I/O range base. */ +#define VBOX_PCI_IO_LIMIT 0x1d /**< 8-bit ?? - - I/O range limit. */ +#define VBOX_PCI_SEC_STATUS 0x1e /**< 16-bit ?? - - secondary status register. */ +#define VBOX_PCI_MEMORY_BASE 0x20 /**< 16-bit ?? - - memory range base. */ +#define VBOX_PCI_MEMORY_LIMIT 0x22 /**< 16-bit ?? - - memory range limit. */ +#define VBOX_PCI_PREF_MEMORY_BASE 0x24 /**< 16-bit ?? - - prefetchable memory range base. */ +#define VBOX_PCI_PREF_MEMORY_LIMIT 0x26 /**< 16-bit ?? - - prefetchable memory range limit. */ +#define VBOX_PCI_PREF_BASE_UPPER32 0x28 /**< 32-bit ?? - - prefetchable memory range high base.*/ +#define VBOX_PCI_PREF_LIMIT_UPPER32 0x2c /**< 32-bit ?? - - prefetchable memory range high limit. */ +#define VBOX_PCI_IO_BASE_UPPER16 0x30 /**< 16-bit ?? - - memory range high base. */ +#define VBOX_PCI_IO_LIMIT_UPPER16 0x32 /**< 16-bit ?? - - memory range high limit. */ +/* #define VBOX_PCI_CAPABILITY_LIST 0x34 */ /**< 8-bit? ?? */ +/* #define VBOX_PCI_RESERVED_35 0x35 */ /**< 8-bit ?? - - reserved */ +/* #define VBOX_PCI_RESERVED_36 0x36 */ /**< 8-bit ?? - - reserved */ +/* #define VBOX_PCI_RESERVED_37 0x37 */ /**< 8-bit ?? - - reserved */ +#define VBOX_PCI_ROM_ADDRESS_BR 0x38 /**< 32-bit ?? - - expansion ROM base address */ +#define VBOX_PCI_BRIDGE_CONTROL 0x3e /**< 16-bit? ?? - - bridge control */ + +/* Type 2 header, PCI-to-CardBus bridge */ +#define VBOX_PCI_CARDBUS_BASE_ADDRESS 0x10 /**< 32-bit RW - - CardBus Socket/ExCa base address */ +#define VBOX_PCI_CARDBUS_CAPLIST 0x14 /**< 8-bit RO? - - offset of capabilities list */ +#define VBOX_PCI_CARDBUS_RESERVED_15 0x15 /**< 8-bit ?? - - reserved */ +#define VBOX_PCI_CARDBUS_SEC_STATUS 0x16 /**< 16-bit ?? - - secondary status */ +#define VBOX_PCI_CARDBUS_PCIBUS_NUMBER 0x18 /**< 8-bit ?? - - PCI bus number */ +#define VBOX_PCI_CARDBUS_CARDBUS_NUMBER 0x19 /**< 8-bit ?? - - CardBus bus number */ +/* #define VBOX_PCI_SUBORDINATE_BUS 0x1a */ /**< 8-bit ?? - - highest subordinate bus number. (behind the bridge) */ +/* #define VBOX_PCI_SEC_LATENCY_TIMER 0x1b */ /**< 8-bit ?? - - secondary latency timer. */ +#define VBOX_PCI_CARDBUS_MEMORY_BASE0 0x1c /**< 32-bit RW - - memory base address 0 */ +#define VBOX_PCI_CARDBUS_MEMORY_LIMIT0 0x20 /**< 32-bit RW - - memory limit 0 */ +#define VBOX_PCI_CARDBUS_MEMORY_BASE1 0x24 /**< 32-bit RW - - memory base address 1 */ +#define VBOX_PCI_CARDBUS_MEMORY_LIMIT1 0x28 /**< 32-bit RW - - memory limit 1 */ +#define VBOX_PCI_CARDBUS_IO_BASE0 0x2c /**< 32-bit RW - - IO base address 0 */ +#define VBOX_PCI_CARDBUS_IO_LIMIT0 0x30 /**< 32-bit RW - - IO limit 0 */ +#define VBOX_PCI_CARDBUS_IO_BASE1 0x34 /**< 32-bit RW - - IO base address 1 */ +#define VBOX_PCI_CARDBUS_IO_LIMIT1 0x38 /**< 32-bit RW - - IO limit 1 */ +/* #define VBOX_PCI_INTERRUPT_LINE 0x3c */ /**< 8-bit RW - - interrupt line. */ +/* #define VBOX_PCI_INTERRUPT_PIN 0x3d */ /**< 8-bit RO - - interrupt pin. */ +/* #define VBOX_PCI_BRIDGE_CONTROL 0x3e */ /**< 16-bit? ?? - - bridge control */ +/** @} */ + + +/* Possible values in status bitmask */ +#define VBOX_PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ +#define VBOX_PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ +#define VBOX_PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ +#define VBOX_PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ +#define VBOX_PCI_STATUS_PARITY 0x100 /* Detected parity error */ +#define VBOX_PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ +#define VBOX_PCI_STATUS_DEVSEL_FAST 0x000 +#define VBOX_PCI_STATUS_DEVSEL_MEDIUM 0x200 +#define VBOX_PCI_STATUS_DEVSEL_SLOW 0x400 +#define VBOX_PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */ +#define VBOX_PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */ +#define VBOX_PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */ +#define VBOX_PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */ +#define VBOX_PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */ + + +/* Command bitmask */ +#define VBOX_PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ +#define VBOX_PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ +#define VBOX_PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ +#define VBOX_PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */ +#define VBOX_PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ +#define VBOX_PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ +#define VBOX_PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ +#define VBOX_PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ +#define VBOX_PCI_COMMAND_SERR 0x100 /* Enable SERR */ +#define VBOX_PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ +#define VBOX_PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ + + +/* Capability list values (capability offset 0) */ +/* Next value pointer in offset 1, or 0 if none */ +#define VBOX_PCI_CAP_ID_PM 0x01 /* Power Management */ +#define VBOX_PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ +#define VBOX_PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ +#define VBOX_PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ +#define VBOX_PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ +#define VBOX_PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ +#define VBOX_PCI_CAP_ID_PCIX 0x07 /* PCI-X */ +#define VBOX_PCI_CAP_ID_HT 0x08 /* HyperTransport */ +#define VBOX_PCI_CAP_ID_VNDR 0x09 /* Vendor specific */ +#define VBOX_PCI_CAP_ID_DBG 0x0A /* Debug port */ +#define VBOX_PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */ +#define VBOX_PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ +#define VBOX_PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ +#define VBOX_PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ +#define VBOX_PCI_CAP_ID_SECURE 0x0F /* Secure device (?) */ +#define VBOX_PCI_CAP_ID_EXP 0x10 /* PCI Express */ +#define VBOX_PCI_CAP_ID_MSIX 0x11 /* MSI-X */ +#define VBOX_PCI_CAP_ID_SATA 0x12 /* Serial-ATA HBA */ +#define VBOX_PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */ + +/* Extended Capabilities (PCI-X 2.0 and Express), start at 0x100, next - bits [20..32] */ +#define VBOX_PCI_EXT_CAP_ID_ERR 0x01 /* Advanced Error Reporting */ +#define VBOX_PCI_EXT_CAP_ID_VC 0x02 /* Virtual Channel */ +#define VBOX_PCI_EXT_CAP_ID_DSN 0x03 /* Device Serial Number */ +#define VBOX_PCI_EXT_CAP_ID_PWR 0x04 /* Power Budgeting */ +#define VBOX_PCI_EXT_CAP_ID_RCLINK 0x05 /* Root Complex Link Declaration */ +#define VBOX_PCI_EXT_CAP_ID_RCILINK 0x06 /* Root Complex Internal Link Declaration */ +#define VBOX_PCI_EXT_CAP_ID_RCECOLL 0x07 /* Root Complex Event Collector */ +#define VBOX_PCI_EXT_CAP_ID_MFVC 0x08 /* Multi-Function Virtual Channel */ +#define VBOX_PCI_EXT_CAP_ID_RBCB 0x0a /* Root Bridge Control Block */ +#define VBOX_PCI_EXT_CAP_ID_VNDR 0x0b /* Vendor specific */ +#define VBOX_PCI_EXT_CAP_ID_ACS 0x0d /* Access Controls */ +#define VBOX_PCI_EXT_CAP_ID_ARI 0x0e +#define VBOX_PCI_EXT_CAP_ID_ATS 0x0f +#define VBOX_PCI_EXT_CAP_ID_SRIOV 0x10 + + +/* MSI flags, aka Message Control (2 bytes, capability offset 2) */ +#define VBOX_PCI_MSI_FLAGS_ENABLE 0x0001 /* MSI feature enabled */ +#define VBOX_PCI_MSI_FLAGS_64BIT 0x0080 /* 64-bit addresses allowed */ +#define VBOX_PCI_MSI_FLAGS_MASKBIT 0x0100 /* Per-vector masking support */ +/* Encoding for 3-bit patterns for message queue (per chapter 6.8.1 of PCI spec), + someone very similar to log_2(). + 000 1 + 001 2 + 010 4 + 011 8 + 100 16 + 101 32 + 110 Reserved + 111 Reserved */ +#define VBOX_PCI_MSI_FLAGS_QSIZE 0x0070 /* Message queue size configured (i.e. vectors per device allocated) */ +#define VBOX_PCI_MSI_FLAGS_QMASK 0x000e /* Maximum queue size available (i.e. vectors per device possible) */ + +/* MSI-X flags (2 bytes, capability offset 2) */ +#define VBOX_PCI_MSIX_FLAGS_ENABLE 0x8000 /* MSI-X enable */ +#define VBOX_PCI_MSIX_FLAGS_FUNCMASK 0x4000 /* Function mask */ + +/* Power management flags (2 bytes, capability offset 2) */ +#define VBOX_PCI_PM_CAP_VER_MASK 0x0007 /* Version mask */ +#define VBOX_PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */ +#define VBOX_PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */ +#define VBOX_PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */ +#define VBOX_PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxilliary power support mask */ +#define VBOX_PCI_PM_CAP_D1 0x0200 /* D1 power state support */ +#define VBOX_PCI_PM_CAP_D2 0x0400 /* D2 power state support */ +#define VBOX_PCI_PM_CAP_PME 0x0800 /* PME pin supported */ +#define VBOX_PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */ +#define VBOX_PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */ +#define VBOX_PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */ +#define VBOX_PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */ +#define VBOX_PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */ +#define VBOX_PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */ + +/* Power management control flags (2 bytes, capability offset 4) */ +#define VBOX_PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */ +#define VBOX_PCI_PM_CTRL_NO_SOFT_RESET 0x0008 /* No reset for D3hot->D0 */ +#define VBOX_PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */ +#define VBOX_PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */ +#define VBOX_PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */ +#define VBOX_PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */ + +/* PCI-X config flags (2 bytes, capability offset 2) */ +#define VBOX_PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */ +#define VBOX_PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */ +#define VBOX_PCI_X_CMD_MAX_OUTSTANDING_SPLIT_TRANS 0x0070 +#define VBOX_PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */ +#define VBOX_PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */ +#define VBOX_PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */ +#define VBOX_PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */ +#define VBOX_PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ + +/* PCI-X config flags (4 bytes, capability offset 4) */ +#define VBOX_PCI_X_STATUS_DEVFN 0x000000ff /* A copy of devfn */ +#define VBOX_PCI_X_STATUS_BUS 0x0000ff00 /* A copy of bus nr */ +#define VBOX_PCI_X_STATUS_64BIT 0x00010000 /* 64-bit device */ +#define VBOX_PCI_X_STATUS_133MHZ 0x00020000 /* 133 MHz capable */ +#define VBOX_PCI_X_STATUS_SPL_DISC 0x00040000 /* Split Completion Discarded */ +#define VBOX_PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split Completion */ +#define VBOX_PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity, 0 = simple device, 1 = bridge device */ +#define VBOX_PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memory Read Count, 0 = 512 bytes, 1 = 1024, 2 = 2048, 3 = 4096 */ +#define VBOX_PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed Max Outstanding Split Transactions */ +#define VBOX_PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumulative Read Size */ +#define VBOX_PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Completion Error Msg */ +#define VBOX_PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */ +#define VBOX_PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */ + +/* PCI Express config flags (2 bytes, capability offset 2) */ +#define VBOX_PCI_EXP_FLAGS_VERS 0x000f /* Capability version */ +#define VBOX_PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */ +#define VBOX_PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */ +#define VBOX_PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */ +#define VBOX_PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */ +#define VBOX_PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */ +#define VBOX_PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ +#define VBOX_PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */ +#define VBOX_PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIE Bridge */ +#define VBOX_PCI_EXP_TYPE_ROOT_INT_EP 0x9 /* Root Complex Integrated Endpoint */ +#define VBOX_PCI_EXP_TYPE_ROOT_EC 0xa /* Root Complex Event Collector */ +#define VBOX_PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ +#define VBOX_PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ + +/* PCI Express device capabilities (4 bytes, capability offset 4) */ +#define VBOX_PCI_EXP_DEVCAP_PAYLOAD 0x07 /* Max_Payload_Size */ +#define VBOX_PCI_EXP_DEVCAP_PHANTOM 0x18 /* Phantom functions */ +#define VBOX_PCI_EXP_DEVCAP_EXT_TAG 0x20 /* Extended tags */ +#define VBOX_PCI_EXP_DEVCAP_L0S 0x1c0 /* L0s Acceptable Latency */ +#define VBOX_PCI_EXP_DEVCAP_L1 0xe00 /* L1 Acceptable Latency */ +#define VBOX_PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */ +#define VBOX_PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */ +#define VBOX_PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */ +#define VBOX_PCI_EXP_DEVCAP_RBE 0x8000 /* Role-Based Error Reporting */ +#define VBOX_PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */ +#define VBOX_PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */ +#define VBOX_PCI_EXP_DEVCAP_FLRESET 0x10000000 /* Function-Level Reset */ + +/* PCI Express device control (2 bytes, capability offset 8) */ +#define VBOX_PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ +#define VBOX_PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ +#define VBOX_PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */ +#define VBOX_PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */ +#define VBOX_PCI_EXP_DEVCTL_RELAXED 0x0010 /* Enable Relaxed Ordering */ +#define VBOX_PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */ +#define VBOX_PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */ +#define VBOX_PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */ +#define VBOX_PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */ +#define VBOX_PCI_EXP_DEVCTL_NOSNOOP 0x0800 /* Enable No Snoop */ +#define VBOX_PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ +#define VBOX_PCI_EXP_DEVCTL_BCRE 0x8000 /* Bridge Configuration Retry Enable */ +#define VBOX_PCI_EXP_DEVCTL_FLRESET 0x8000 /* Function-Level Reset [bit shared with BCRE] */ + +/* PCI Express device status (2 bytes, capability offset 10) */ +#define VBOX_PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */ +#define VBOX_PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */ +#define VBOX_PCI_EXP_DEVSTA_FED 0x04 /* Fatal Error Detected */ +#define VBOX_PCI_EXP_DEVSTA_URD 0x08 /* Unsupported Request Detected */ +#define VBOX_PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */ +#define VBOX_PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */ + +/* PCI Express link capabilities (4 bytes, capability offset 12) */ +#define VBOX_PCI_EXP_LNKCAP_SPEED 0x0000f /* Maximum Link Speed */ +#define VBOX_PCI_EXP_LNKCAP_WIDTH 0x003f0 /* Maximum Link Width */ +#define VBOX_PCI_EXP_LNKCAP_ASPM 0x00c00 /* Active State Power Management */ +#define VBOX_PCI_EXP_LNKCAP_L0S 0x07000 /* L0s Acceptable Latency */ +#define VBOX_PCI_EXP_LNKCAP_L1 0x38000 /* L1 Acceptable Latency */ +#define VBOX_PCI_EXP_LNKCAP_CLOCKPM 0x40000 /* Clock Power Management */ +#define VBOX_PCI_EXP_LNKCAP_SURPRISE 0x80000 /* Surprise Down Error Reporting */ +#define VBOX_PCI_EXP_LNKCAP_DLLA 0x100000 /* Data Link Layer Active Reporting */ +#define VBOX_PCI_EXP_LNKCAP_LBNC 0x200000 /* Link Bandwidth Notification Capability */ +#define VBOX_PCI_EXP_LNKCAP_PORT 0xff000000 /* Port Number */ + +/* PCI Express link control (2 bytes, capability offset 16) */ +#define VBOX_PCI_EXP_LNKCTL_ASPM 0x0003 /* ASPM Control */ +#define VBOX_PCI_EXP_LNKCTL_RCB 0x0008 /* Read Completion Boundary */ +#define VBOX_PCI_EXP_LNKCTL_DISABLE 0x0010 /* Link Disable */ +#define VBOX_PCI_EXP_LNKCTL_RETRAIN 0x0020 /* Retrain Link */ +#define VBOX_PCI_EXP_LNKCTL_CLOCK 0x0040 /* Common Clock Configuration */ +#define VBOX_PCI_EXP_LNKCTL_XSYNCH 0x0080 /* Extended Synch */ +#define VBOX_PCI_EXP_LNKCTL_CLOCKPM 0x0100 /* Clock Power Management */ +#define VBOX_PCI_EXP_LNKCTL_HWAUTWD 0x0200 /* Hardware Autonomous Width Disable */ +#define VBOX_PCI_EXP_LNKCTL_BWMIE 0x0400 /* Bandwidth Mgmt Interrupt Enable */ +#define VBOX_PCI_EXP_LNKCTL_AUTBWIE 0x0800 /* Autonomous Bandwidth Mgmt Interrupt Enable */ + +/* PCI Express link status (2 bytes, capability offset 18) */ +#define VBOX_PCI_EXP_LNKSTA_SPEED 0x000f /* Negotiated Link Speed */ +#define VBOX_PCI_EXP_LNKSTA_WIDTH 0x03f0 /* Negotiated Link Width */ +#define VBOX_PCI_EXP_LNKSTA_TR_ERR 0x0400 /* Training Error (obsolete) */ +#define VBOX_PCI_EXP_LNKSTA_TRAIN 0x0800 /* Link Training */ +#define VBOX_PCI_EXP_LNKSTA_SL_CLK 0x1000 /* Slot Clock Configuration */ +#define VBOX_PCI_EXP_LNKSTA_DL_ACT 0x2000 /* Data Link Layer in DL_Active State */ +#define VBOX_PCI_EXP_LNKSTA_BWMGMT 0x4000 /* Bandwidth Mgmt Status */ +#define VBOX_PCI_EXP_LNKSTA_AUTBW 0x8000 /* Autonomous Bandwidth Mgmt Status */ + +/* PCI Express slot capabilities (4 bytes, capability offset 20) */ +#define VBOX_PCI_EXP_SLTCAP_ATNB 0x0001 /* Attention Button Present */ +#define VBOX_PCI_EXP_SLTCAP_PWRC 0x0002 /* Power Controller Present */ +#define VBOX_PCI_EXP_SLTCAP_MRL 0x0004 /* MRL Sensor Present */ +#define VBOX_PCI_EXP_SLTCAP_ATNI 0x0008 /* Attention Indicator Present */ +#define VBOX_PCI_EXP_SLTCAP_PWRI 0x0010 /* Power Indicator Present */ +#define VBOX_PCI_EXP_SLTCAP_HPS 0x0020 /* Hot-Plug Surprise */ +#define VBOX_PCI_EXP_SLTCAP_HPC 0x0040 /* Hot-Plug Capable */ +#define VBOX_PCI_EXP_SLTCAP_PWR_VAL 0x00007f80 /* Slot Power Limit Value */ +#define VBOX_PCI_EXP_SLTCAP_PWR_SCL 0x00018000 /* Slot Power Limit Scale */ +#define VBOX_PCI_EXP_SLTCAP_INTERLOCK 0x020000 /* Electromechanical Interlock Present */ +#define VBOX_PCI_EXP_SLTCAP_NOCMDCOMP 0x040000 /* No Command Completed Support */ +#define VBOX_PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */ + +/* PCI Express slot control (2 bytes, capability offset 24) */ +#define VBOX_PCI_EXP_SLTCTL_ATNB 0x0001 /* Attention Button Pressed Enable */ +#define VBOX_PCI_EXP_SLTCTL_PWRF 0x0002 /* Power Fault Detected Enable */ +#define VBOX_PCI_EXP_SLTCTL_MRLS 0x0004 /* MRL Sensor Changed Enable */ +#define VBOX_PCI_EXP_SLTCTL_PRSD 0x0008 /* Presence Detect Changed Enable */ +#define VBOX_PCI_EXP_SLTCTL_CMDC 0x0010 /* Command Completed Interrupt Enable */ +#define VBOX_PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable */ +#define VBOX_PCI_EXP_SLTCTL_ATNI 0x00c0 /* Attention Indicator Control */ +#define VBOX_PCI_EXP_SLTCTL_PWRI 0x0300 /* Power Indicator Control */ +#define VBOX_PCI_EXP_SLTCTL_PWRC 0x0400 /* Power Controller Control */ +#define VBOX_PCI_EXP_SLTCTL_INTERLOCK 0x0800 /* Electromechanical Interlock Control */ +#define VBOX_PCI_EXP_SLTCTL_LLCHG 0x1000 /* Data Link Layer State Changed Enable */ + +/* PCI Express slot status (2 bytes, capability offset 26) */ +#define VBOX_PCI_EXP_SLTSTA_ATNB 0x0001 /* Attention Button Pressed */ +#define VBOX_PCI_EXP_SLTSTA_PWRF 0x0002 /* Power Fault Detected */ +#define VBOX_PCI_EXP_SLTSTA_MRLS 0x0004 /* MRL Sensor Changed */ +#define VBOX_PCI_EXP_SLTSTA_PRSD 0x0008 /* Presence Detect Changed */ +#define VBOX_PCI_EXP_SLTSTA_CMDC 0x0010 /* Command Completed */ +#define VBOX_PCI_EXP_SLTSTA_MRL_ST 0x0020 /* MRL Sensor State */ +#define VBOX_PCI_EXP_SLTSTA_PRES 0x0040 /* Presence Detect State */ +#define VBOX_PCI_EXP_SLTSTA_INTERLOCK 0x0080 /* Electromechanical Interlock Status */ +#define VBOX_PCI_EXP_SLTSTA_LLCHG 0x0100 /* Data Link Layer State Changed */ + +/* PCI Express root control (2 bytes, capability offset 28) */ +#define VBOX_PCI_EXP_RTCTL_SECEE 0x0001 /* System Error on Correctable Error */ +#define VBOX_PCI_EXP_RTCTL_SENFEE 0x0002 /* System Error on Non-Fatal Error */ +#define VBOX_PCI_EXP_RTCTL_SEFEE 0x0004 /* System Error on Fatal Error */ +#define VBOX_PCI_EXP_RTCTL_PMEIE 0x0008 /* PME Interrupt Enable */ +#define VBOX_PCI_EXP_RTCTL_CRSVIS 0x0010 /* Configuration Request Retry Status Visible to SW */ + +/* PCI Express root capabilities (2 bytes, capability offset 30) */ +#define VBOX_PCI_EXP_RTCAP_CRSVIS 0x0010 /* Configuration Request Retry Status Visible to SW */ + +/* PCI Express root status (4 bytes, capability offset 32) */ +#define VBOX_PCI_EXP_RTSTA_PME_REQID 0x0000ffff /* PME Requester ID */ +#define VBOX_PCI_EXP_RTSTA_PME_STATUS 0x00010000 /* PME Status */ +#define VBOX_PCI_EXP_RTSTA_PME_PENDING 0x00020000 /* PME is Pending */ + + +/** Fixed I/O region number for ROM. */ +#define VBOX_PCI_ROM_SLOT 6 +/** Max number of I/O regions. */ +#define VBOX_PCI_NUM_REGIONS 7 + +#define PCI_ROM_SLOT VBOX_PCI_ROM_SLOT /**< deprecated */ +#define PCI_NUM_REGIONS VBOX_PCI_NUM_REGIONS /**< deprecated */ + +/** Number of functions per device. */ +#define VBOX_PCI_MAX_FUNCTIONS 8 +/** Number of devices per bus. */ +#define VBOX_PCI_MAX_DEVICES 32 +/** The function number mask for a device+function number. */ +#define VBOX_PCI_DEVFN_FUN_MASK 0x7 +/** The device number shift count for a device+function number. */ +#define VBOX_PCI_DEVFN_DEV_SHIFT 3 +/** The device number mask for a device+function number. */ +#define VBOX_PCI_DEVFN_DEV_MASK 0x1f +/** The bus number shift count for a bus+device+function number. */ +#define VBOX_PCI_BUS_SHIFT 0x8 +/** The bus number mask a bus+device+function number. */ +#define VBOX_PCI_BUS_MASK 0xff +/** Make a device+function number. */ +#define VBOX_PCI_DEVFN_MAKE(a_uPciDevNo, a_uPciFunNo) ( ((a_uPciDevNo) << VBOX_PCI_DEVFN_DEV_SHIFT) \ + | ((a_uPciFunNo) & VBOX_PCI_DEVFN_FUN_MASK)) + +/** Checks whether the PCIBDF is valid. */ +#define PCIBDF_IS_VALID(a_uBusDevFn) (!((a_uBusDevFn) & PCI_BDF_F_INVALID)) +/** Make a PCIBDF given the bus and device:function. */ +#define PCIBDF_MAKE(a_uBus, a_uDevFn) (((a_uBus) << VBOX_PCI_BUS_SHIFT) | (a_uDevFn)) + +/** Southbridge I/O APIC (when IOMMU is enabled): Bus. */ +#define VBOX_PCI_BUS_SB_IOAPIC 0 +/** Southbridge I/O APIC (when IOMMU is enabled): Device. */ +#define VBOX_PCI_DEV_SB_IOAPIC 0x14 +/** Southbridge I/O APIC (when IOMMU is enabled): Function. */ +#define VBOX_PCI_FN_SB_IOAPIC 0 +/** PCI BDF (hardcoded by linux guests) reserved for the SB I/O APIC when using VMs + * with an AMD IOMMU. */ +#define VBOX_PCI_BDF_SB_IOAPIC PCIBDF_MAKE(VBOX_PCI_BUS_SB_IOAPIC, \ + VBOX_PCI_DEVFN_MAKE(VBOX_PCI_DEV_SB_IOAPIC, VBOX_PCI_FN_SB_IOAPIC)) + +/** + * A PCI PASID (Process Address Space ID). + * + * A PASID is 20 bits wide. We use bit 31 to indicate the PASID is invalid or not + * present. + */ +typedef uint32_t PCIPASID; +/** PCIPASID: Valid. */ +#define PCIPASID_F_VALID RT_BIT(31) +/** Nil PCIPASID value. */ +#define NIL_PCIPASID UINT32_C(0) +/** Returns whether the PCI PASID is valid. */ +#define PCIPASID_IS_VALID(a) (((a) & PCIPASID_F_VALID) != 0) +/** Returns the PASID value of a PCI PASID. */ +#define PCIPASID_VAL(a) ((a) & UINT32_C(0xfffff)) + + +#if defined(__cplusplus) && defined(IN_RING3) +/* For RTStrPrintf(). */ +# include <iprt/string.h> + +/** + * Class representing PCI address. PCI device consist of + * bus, device and function numbers. Generally device PCI + * address could be changed during runtime, but only by + * an OS PCI driver. + * + * @remarks C++ classes (structs included) are not generally accepted in + * VMM devices or drivers. An exception may be granted for this class + * if it's contained to ring-3 and that this is a one time exception + * which sets no precedent. + */ +struct PCIBusAddress +{ + /** @todo: think if we'll need domain, which is higher + * word of the address. */ + int miBus; + int miDevice; + int miFn; + + PCIBusAddress() + { + clear(); + } + + PCIBusAddress(int iBus, int iDevice, int iFn) + { + init(iBus, iDevice, iFn); + } + + PCIBusAddress(int32_t iAddr) + { + clear(); + fromLong(iAddr); + } + + PCIBusAddress& clear() + { + miBus = miDevice = miFn = -1; + return *this; + } + + void init(int iBus, int iDevice, int iFn) + { + miBus = iBus; + miDevice = iDevice; + miFn = iFn; + } + + void init(const PCIBusAddress &a) + { + miBus = a.miBus; + miDevice = a.miDevice; + miFn = a.miFn; + } + + bool operator<(const PCIBusAddress &a) const + { + if (miBus < a.miBus) + return true; + + if (miBus > a.miBus) + return false; + + if (miDevice < a.miDevice) + return true; + + if (miDevice > a.miDevice) + return false; + + if (miFn < a.miFn) + return true; + + if (miFn > a.miFn) + return false; + + return false; + } + + bool operator==(const PCIBusAddress &a) const + { + return (miBus == a.miBus) + && (miDevice == a.miDevice) + && (miFn == a.miFn); + } + + bool operator!=(const PCIBusAddress &a) const + { + return (miBus != a.miBus) + || (miDevice != a.miDevice) + || (miFn != a.miFn); + } + + bool valid() const + { + return (miBus != -1) + && (miDevice != -1) + && (miFn != -1); + } + + int32_t asLong() const + { + Assert(valid()); + return (miBus << 8) | (miDevice << 3) | miFn; + } + + PCIBusAddress& fromLong(int32_t value) + { + miBus = (value >> 8) & 0xff; + miDevice = (value & 0xff) >> 3; + miFn = (value & 7); + return *this; + } + + /** Create string representation of this PCI address. */ + bool format(char* szBuf, int32_t cBufSize) + { + if (cBufSize < (/* bus */ 2 + /* : */ 1 + /* device */ 2 + /* . */ 1 + /* function*/ 1 + /* \0 */1)) + return false; + + if (valid()) + RTStrPrintf(szBuf, cBufSize, "%02x:%02x.%01x", miBus, miDevice, miFn); + else + RTStrPrintf(szBuf, cBufSize, "%s", "<bad>"); + + return true; + } + + static const size_t cMaxAddrSize = 10; +}; + +#endif /* __cplusplus && IN_RING3 */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_pci_h */ diff --git a/include/VBox/rawpci.h b/include/VBox/rawpci.h new file mode 100644 index 00000000..290983c0 --- /dev/null +++ b/include/VBox/rawpci.h @@ -0,0 +1,618 @@ +/** @file + * Raw PCI Devices (aka PCI pass-through). (VMM) + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_rawpci_h +#define VBOX_INCLUDED_rawpci_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/sup.h> + +RT_C_DECLS_BEGIN + +/** + * Handle for the raw PCI device. + */ +typedef uint32_t PCIRAWDEVHANDLE; + +/** + * Handle for the ISR. + */ +typedef uint32_t PCIRAWISRHANDLE; + +/** + * Physical memory action enumeration. + */ +typedef enum PCIRAWMEMINFOACTION +{ + /** Pages mapped. */ + PCIRAW_MEMINFO_MAP, + /** Pages unmapped. */ + PCIRAW_MEMINFO_UNMAP, + /** The usual 32-bit type blow up. */ + PCIRAW_MEMINFO_32BIT_HACK = 0x7fffffff +} PCIRAWMEMINFOACTION; + +/** + * Per-VM capability flag bits. + */ +typedef enum PCIRAWVMFLAGS +{ + /** If we can use IOMMU in this VM. */ + PCIRAW_VMFLAGS_HAS_IOMMU = (1 << 0), + PCIRAW_VMFLAGS_32BIT_HACK = 0x7fffffff +} PCIRAWVMFLAGS; + +/* Forward declaration. */ +struct RAWPCIPERVM; + +/** + * Callback to notify raw PCI subsystem about mapping/unmapping of + * host pages to the guest. Typical usecase is to register physical + * RAM pages with IOMMU, so that it could allow DMA for PCI devices + * directly from the guest RAM. + * Region shall be one or more contigous (both host and guest) pages + * of physical memory. + * + * @returns VBox status code. + * + * @param pVmData The per VM data. + * @param HCPhysStart Physical address of region start on the host. + * @param GCPhysStart Physical address of region start on the guest. + * @param cbMem Region size in bytes. + * @param enmAction Action performed (i.e. if page was mapped + * or unmapped). + */ +typedef DECLCALLBACKTYPE(int, FNRAWPCICONTIGPHYSMEMINFO,(struct RAWPCIPERVM *pVmData, RTHCPHYS HCPhysStart, + RTGCPHYS GCPhysStart, uint64_t cbMem, PCIRAWMEMINFOACTION enmAction)); +typedef FNRAWPCICONTIGPHYSMEMINFO *PFNRAWPCICONTIGPHYSMEMINFO; + +/** Data being part of the VM structure. */ +typedef struct RAWPCIPERVM +{ + /** Shall only be interpreted by the host PCI driver. */ + RTR0PTR pDriverData; + /** Callback called when mapping of host pages to the guest changes. */ + PFNRAWPCICONTIGPHYSMEMINFO pfnContigMemInfo; + /** Flags describing VM capabilities (such as IOMMU presence). */ + uint32_t fVmCaps; +} RAWPCIPERVM; +typedef RAWPCIPERVM *PRAWPCIPERVM; + +/** Parameters buffer for PCIRAWR0_DO_OPEN_DEVICE call */ +typedef struct +{ + /* in */ + uint32_t PciAddress; + uint32_t fFlags; + /* out */ + PCIRAWDEVHANDLE Device; + uint32_t fDevFlags; +} PCIRAWREQOPENDEVICE; + +/** Parameters buffer for PCIRAWR0_DO_CLOSE_DEVICE call */ +typedef struct +{ + /* in */ + uint32_t fFlags; +} PCIRAWREQCLOSEDEVICE; + +/** Parameters buffer for PCIRAWR0_DO_GET_REGION_INFO call */ +typedef struct +{ + /* in */ + int32_t iRegion; + /* out */ + RTGCPHYS RegionStart; + uint64_t u64RegionSize; + bool fPresent; + uint32_t fFlags; +} PCIRAWREQGETREGIONINFO; + +/** Parameters buffer for PCIRAWR0_DO_MAP_REGION call. */ +typedef struct +{ + /* in */ + RTGCPHYS StartAddress; + uint64_t iRegionSize; + int32_t iRegion; + uint32_t fFlags; + /* out */ + RTR3PTR pvAddressR3; + RTR0PTR pvAddressR0; +} PCIRAWREQMAPREGION; + +/** Parameters buffer for PCIRAWR0_DO_UNMAP_REGION call. */ +typedef struct +{ + /* in */ + RTGCPHYS StartAddress; + uint64_t iRegionSize; + RTR3PTR pvAddressR3; + RTR0PTR pvAddressR0; + int32_t iRegion; +} PCIRAWREQUNMAPREGION; + +/** Parameters buffer for PCIRAWR0_DO_PIO_WRITE call. */ +typedef struct +{ + /* in */ + uint16_t iPort; + uint16_t cb; + uint32_t iValue; +} PCIRAWREQPIOWRITE; + +/** Parameters buffer for PCIRAWR0_DO_PIO_READ call. */ +typedef struct +{ + /* in */ + uint16_t iPort; + uint16_t cb; + /* out */ + uint32_t iValue; +} PCIRAWREQPIOREAD; + +/** Memory operand. */ +typedef struct +{ + union + { + uint8_t u8; + uint16_t u16; + uint32_t u32; + uint64_t u64; + } u; + uint8_t cb; +} PCIRAWMEMLOC; + +/** Parameters buffer for PCIRAWR0_DO_MMIO_WRITE call. */ +typedef struct +{ + /* in */ + RTR0PTR Address; + PCIRAWMEMLOC Value; +} PCIRAWREQMMIOWRITE; + +/** Parameters buffer for PCIRAWR0_DO_MMIO_READ call. */ +typedef struct +{ + /* in */ + RTR0PTR Address; + /* inout (Value.cb is in) */ + PCIRAWMEMLOC Value; +} PCIRAWREQMMIOREAD; + +/* Parameters buffer for PCIRAWR0_DO_PCICFG_WRITE call. */ +typedef struct +{ + /* in */ + uint32_t iOffset; + PCIRAWMEMLOC Value; +} PCIRAWREQPCICFGWRITE; + +/** Parameters buffer for PCIRAWR0_DO_PCICFG_READ call. */ +typedef struct +{ + /* in */ + uint32_t iOffset; + /* inout (Value.cb is in) */ + PCIRAWMEMLOC Value; +} PCIRAWREQPCICFGREAD; + +/** Parameters buffer for PCIRAWR0_DO_GET_IRQ call. */ +typedef struct PCIRAWREQGETIRQ +{ + /* in */ + int64_t iTimeout; + /* out */ + int32_t iIrq; +} PCIRAWREQGETIRQ; + +/** Parameters buffer for PCIRAWR0_DO_POWER_STATE_CHANGE call. */ +typedef struct PCIRAWREQPOWERSTATECHANGE +{ + /* in */ + uint32_t iState; + /* in/out */ + uint64_t u64Param; +} PCIRAWREQPOWERSTATECHANGE; + +/** + * Request buffer use for communication with the driver. + */ +typedef struct PCIRAWSENDREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. + */ + PSUPDRVSESSION pSession; + /** Request type. */ + int32_t iRequest; + /** Host device request targetted to. */ + PCIRAWDEVHANDLE TargetDevice; + /** Call parameters. */ + union + { + PCIRAWREQOPENDEVICE aOpenDevice; + PCIRAWREQCLOSEDEVICE aCloseDevice; + PCIRAWREQGETREGIONINFO aGetRegionInfo; + PCIRAWREQMAPREGION aMapRegion; + PCIRAWREQUNMAPREGION aUnmapRegion; + PCIRAWREQPIOWRITE aPioWrite; + PCIRAWREQPIOREAD aPioRead; + PCIRAWREQMMIOWRITE aMmioWrite; + PCIRAWREQMMIOREAD aMmioRead; + PCIRAWREQPCICFGWRITE aPciCfgWrite; + PCIRAWREQPCICFGREAD aPciCfgRead; + PCIRAWREQGETIRQ aGetIrq; + PCIRAWREQPOWERSTATECHANGE aPowerStateChange; + } u; +} PCIRAWSENDREQ; +typedef PCIRAWSENDREQ *PPCIRAWSENDREQ; + +/** + * Operations performed by the driver. + */ +typedef enum PCIRAWR0OPERATION +{ + /* Open device. */ + PCIRAWR0_DO_OPEN_DEVICE, + /* Close device. */ + PCIRAWR0_DO_CLOSE_DEVICE, + /* Get PCI region info. */ + PCIRAWR0_DO_GET_REGION_INFO, + /* Map PCI region into VM address space. */ + PCIRAWR0_DO_MAP_REGION, + /* Unmap PCI region from VM address space. */ + PCIRAWR0_DO_UNMAP_REGION, + /* Perform PIO write. */ + PCIRAWR0_DO_PIO_WRITE, + /* Perform PIO read. */ + PCIRAWR0_DO_PIO_READ, + /* Perform MMIO write. */ + PCIRAWR0_DO_MMIO_WRITE, + /* Perform MMIO read. */ + PCIRAWR0_DO_MMIO_READ, + /* Perform PCI config write. */ + PCIRAWR0_DO_PCICFG_WRITE, + /* Perform PCI config read. */ + PCIRAWR0_DO_PCICFG_READ, + /* Get next IRQ for the device. */ + PCIRAWR0_DO_GET_IRQ, + /* Enable getting IRQs for the device. */ + PCIRAWR0_DO_ENABLE_IRQ, + /* Disable getting IRQs for the device. */ + PCIRAWR0_DO_DISABLE_IRQ, + /* Notify driver about guest power state change. */ + PCIRAWR0_DO_POWER_STATE_CHANGE, + /** The usual 32-bit type blow up. */ + PCIRAWR0_DO_32BIT_HACK = 0x7fffffff +} PCIRAWR0OPERATION; + +/** + * Power state enumeration. + */ +typedef enum PCIRAWPOWERSTATE +{ + /* Power on. */ + PCIRAW_POWER_ON, + /* Power off. */ + PCIRAW_POWER_OFF, + /* Suspend. */ + PCIRAW_POWER_SUSPEND, + /* Resume. */ + PCIRAW_POWER_RESUME, + /* Reset. */ + PCIRAW_POWER_RESET, + /** The usual 32-bit type blow up. */ + PCIRAW_POWER_32BIT_HACK = 0x7fffffff +} PCIRAWPOWERSTATE; + + +/** Forward declarations. */ +typedef struct RAWPCIFACTORY *PRAWPCIFACTORY; +typedef struct RAWPCIDEVPORT *PRAWPCIDEVPORT; + +/** + * Interrupt service routine callback. + * + * @returns if interrupt was processed. + * + * @param pvContext Opaque user data passed to the handler. + * @param iIrq Interrupt number. + */ +typedef DECLCALLBACKTYPE(bool, FNRAWPCIISR,(void *pvContext, int32_t iIrq)); +typedef FNRAWPCIISR *PFNRAWPCIISR; + +/** + * This is the port on the device interface, i.e. the driver side which the + * host device is connected to. + * + * This is only used for the in-kernel PCI device connections. + */ +typedef struct RAWPCIDEVPORT +{ + /** Structure version number. (RAWPCIDEVPORT_VERSION) */ + uint32_t u32Version; + + /** + * Init device. + * + * @param pPort Pointer to this structure. + * @param fFlags Initialization flags. + */ + DECLR0CALLBACKMEMBER(int, pfnInit,(PRAWPCIDEVPORT pPort, + uint32_t fFlags)); + + + /** + * Deinit device. + * + * @param pPort Pointer to this structure. + * @param fFlags Initialization flags. + */ + DECLR0CALLBACKMEMBER(int, pfnDeinit,(PRAWPCIDEVPORT pPort, + uint32_t fFlags)); + + + /** + * Destroy device. + * + * @param pPort Pointer to this structure. + */ + DECLR0CALLBACKMEMBER(int, pfnDestroy,(PRAWPCIDEVPORT pPort)); + + /** + * Get PCI region info. + * + * @param pPort Pointer to this structure. + * @param iRegion Region number. + * @param pRegionStart Where to start the region address. + * @param pu64RegionSize Where to store the region size. + * @param pfPresent Where to store if the region is present. + * @param pfFlags Where to store the flags. + */ + DECLR0CALLBACKMEMBER(int, pfnGetRegionInfo,(PRAWPCIDEVPORT pPort, + int32_t iRegion, + RTHCPHYS *pRegionStart, + uint64_t *pu64RegionSize, + bool *pfPresent, + uint32_t *pfFlags)); + + + /** + * Map PCI region. + * + * @param pPort Pointer to this structure. + * @param iRegion Region number. + * @param RegionStart Region start. + * @param u64RegionSize Region size. + * @param fFlags Flags. + * @param pRegionBaseR0 Where to store the R0 address. + */ + DECLR0CALLBACKMEMBER(int, pfnMapRegion,(PRAWPCIDEVPORT pPort, + int32_t iRegion, + RTHCPHYS RegionStart, + uint64_t u64RegionSize, + int32_t fFlags, + RTR0PTR *pRegionBaseR0)); + + /** + * Unmap PCI region. + * + * @param pPort Pointer to this structure. + * @param iRegion Region number. + * @param RegionStart Region start. + * @param u64RegionSize Region size. + * @param RegionBase Base address. + */ + DECLR0CALLBACKMEMBER(int, pfnUnmapRegion,(PRAWPCIDEVPORT pPort, + int32_t iRegion, + RTHCPHYS RegionStart, + uint64_t u64RegionSize, + RTR0PTR RegionBase)); + + /** + * Read device PCI register. + * + * @param pPort Pointer to this structure. + * @param Register PCI register. + * @param pValue Read value (with desired read width). + */ + DECLR0CALLBACKMEMBER(int, pfnPciCfgRead,(PRAWPCIDEVPORT pPort, + uint32_t Register, + PCIRAWMEMLOC *pValue)); + + + /** + * Write device PCI register. + * + * @param pPort Pointer to this structure. + * @param Register PCI register. + * @param pValue Write value (with desired write width). + */ + DECLR0CALLBACKMEMBER(int, pfnPciCfgWrite,(PRAWPCIDEVPORT pPort, + uint32_t Register, + PCIRAWMEMLOC *pValue)); + + /** + * Request to register interrupt handler. + * + * @param pPort Pointer to this structure. + * @param pfnHandler Pointer to the handler. + * @param pIrqContext Context passed to the handler. + * @param phIsr Handle for the ISR, . + */ + DECLR0CALLBACKMEMBER(int, pfnRegisterIrqHandler,(PRAWPCIDEVPORT pPort, + PFNRAWPCIISR pfnHandler, + void* pIrqContext, + PCIRAWISRHANDLE *phIsr)); + + /** + * Request to unregister interrupt handler. + * + * @param pPort Pointer to this structure. + * @param hIsr Handle of ISR to unregister (retured by earlier pfnRegisterIrqHandler). + */ + DECLR0CALLBACKMEMBER(int, pfnUnregisterIrqHandler,(PRAWPCIDEVPORT pPort, + PCIRAWISRHANDLE hIsr)); + + /** + * Power state change notification. + * + * @param pPort Pointer to this structure. + * @param aState New power state. + * @param pu64Param State-specific in/out parameter. + */ + DECLR0CALLBACKMEMBER(int, pfnPowerStateChange,(PRAWPCIDEVPORT pPort, + PCIRAWPOWERSTATE aState, + uint64_t *pu64Param)); + + /** Structure version number. (RAWPCIDEVPORT_VERSION) */ + uint32_t u32VersionEnd; +} RAWPCIDEVPORT; +/** Version number for the RAWPCIDEVPORT::u32Version and RAWPCIIFPORT::u32VersionEnd fields. */ +#define RAWPCIDEVPORT_VERSION UINT32_C(0xAFBDCC02) + +/** + * The component factory interface for create a raw PCI interfaces. + */ +typedef struct RAWPCIFACTORY +{ + /** + * Release this factory. + * + * SUPR0ComponentQueryFactory (SUPDRVFACTORY::pfnQueryFactoryInterface to be precise) + * will retain a reference to the factory and the caller has to call this method to + * release it once the pfnCreateAndConnect call(s) has been done. + * + * @param pFactory Pointer to this structure. + */ + DECLR0CALLBACKMEMBER(void, pfnRelease,(PRAWPCIFACTORY pFactory)); + + /** + * Create an instance for the specfied host PCI card and connects it + * to the driver. + * + * + * @returns VBox status code. + * + * @param pFactory Pointer to this structure. + * @param u32HostAddress Address of PCI device on the host. + * @param fFlags Creation flags. + * @param pVmCtx Context of VM where device is created. + * @param ppDevPort Where to store the pointer to the device port + * on success. + * @param pfDevFlags Where to store the device flags. + * + */ + DECLR0CALLBACKMEMBER(int, pfnCreateAndConnect,(PRAWPCIFACTORY pFactory, + uint32_t u32HostAddress, + uint32_t fFlags, + PRAWPCIPERVM pVmCtx, + PRAWPCIDEVPORT *ppDevPort, + uint32_t *pfDevFlags)); + + + /** + * Initialize per-VM data related to PCI passthrough. + * + * @returns VBox status code. + * + * @param pFactory Pointer to this structure. + * @param pVM The cross context VM structure. + * @param pVmData Pointer to PCI data. + */ + DECLR0CALLBACKMEMBER(int, pfnInitVm,(PRAWPCIFACTORY pFactory, + PVM pVM, + PRAWPCIPERVM pVmData)); + + /** + * Deinitialize per-VM data related to PCI passthrough. + * + * @returns VBox status code. + * + * @param pFactory Pointer to this structure. + * @param pVM The cross context VM structure. + * @param pVmData Pointer to PCI data. + */ + DECLR0CALLBACKMEMBER(void, pfnDeinitVm,(PRAWPCIFACTORY pFactory, + PVM pVM, + PRAWPCIPERVM pVmData)); +} RAWPCIFACTORY; + +#define RAWPCIFACTORY_UUID_STR "ea089839-4171-476f-adfb-9e7ab1cbd0fb" + +/** + * Flags passed to pfnPciDeviceConstructStart(), to notify driver + * about options to be used to open device. + */ +typedef enum PCIRAWDRIVERFLAGS +{ + /** If runtime shall try to detach host driver. */ + PCIRAWDRIVERRFLAG_DETACH_HOST_DRIVER = (1 << 0), + /** The usual 32-bit type blow up. */ + PCIRAWDRIVERRFLAG_32BIT_HACK = 0x7fffffff +} PCIRAWDRIVERFLAGS; + +/** + * Flags used to describe PCI region, matches to PCIADDRESSSPACE + * in pci.h. + */ +typedef enum PCIRAWADDRESSSPACE +{ + /** Memory. */ + PCIRAW_ADDRESS_SPACE_MEM = 0x00, + /** I/O space. */ + PCIRAW_ADDRESS_SPACE_IO = 0x01, + /** 32-bit BAR. */ + PCIRAW_ADDRESS_SPACE_BAR32 = 0x00, + /** 64-bit BAR. */ + PCIRAW_ADDRESS_SPACE_BAR64 = 0x04, + /** Prefetch memory. */ + PCIRAW_ADDRESS_SPACE_MEM_PREFETCH = 0x08, + /** The usual 32-bit type blow up. */ + PCIRAW_ADDRESS_SPACE_32BIT_HACK = 0x7fffffff +} PCIRAWADDRESSSPACE; + +RT_C_DECLS_END + +/* #define VBOX_WITH_SHARED_PCI_INTERRUPTS */ + +#endif /* !VBOX_INCLUDED_rawpci_h */ diff --git a/include/VBox/scsi.h b/include/VBox/scsi.h new file mode 100644 index 00000000..1acf1f3c --- /dev/null +++ b/include/VBox/scsi.h @@ -0,0 +1,339 @@ +/** @file + * VirtualBox - SCSI declarations. (DEV,+) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_scsi_h +#define VBOX_INCLUDED_scsi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assert.h> + +/** + * @todo: Remove when the splitting code was removed from DevATA. + * The limit doesn't belong here but is specific for each host platform. + */ +#ifdef RT_OS_FREEBSD +/* The cam subsystem doesn't allow more */ +# define SCSI_MAX_BUFFER_SIZE (64 * _1K) +#else +# define SCSI_MAX_BUFFER_SIZE (100 * _1K) +#endif + +/** + * SCSI command opcode identifiers. + * + * SCSI-3, so far for CD/DVD Logical Units, from Table 49 of the MMC-3 draft standard. + */ +typedef enum SCSICMD +{ + SCSI_BLANK = 0xa1, + SCSI_CLOSE_TRACK_SESSION = 0x5b, + SCSI_ERASE_10 = 0x2c, + SCSI_FORMAT_UNIT = 0x04, + SCSI_GET_CONFIGURATION = 0x46, + SCSI_GET_EVENT_STATUS_NOTIFICATION = 0x4a, + SCSI_GET_PERFORMANCE = 0xac, + /** Inquiry command. */ + SCSI_INQUIRY = 0x12, + SCSI_LOAD_UNLOAD_MEDIUM = 0xa6, + SCSI_MECHANISM_STATUS = 0xbd, + SCSI_MODE_SELECT_10 = 0x55, + SCSI_MODE_SENSE_10 = 0x5a, + SCSI_PAUSE_RESUME = 0x4b, + SCSI_PLAY_AUDIO_10 = 0x45, + SCSI_PLAY_AUDIO_12 = 0xa5, + SCSI_PLAY_AUDIO_MSF = 0x47, + SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1e, + /** Read(10) command. */ + SCSI_READ_10 = 0x28, + SCSI_READ_12 = 0xa8, + SCSI_READ_BUFFER = 0x3c, + SCSI_READ_BUFFER_CAPACITY = 0x5c, + /** Read Capacity(6) command. */ + SCSI_READ_CAPACITY = 0x25, + SCSI_READ_CD = 0xbe, + SCSI_READ_CD_MSF = 0xb9, + SCSI_READ_DISC_INFORMATION = 0x51, + SCSI_READ_DVD_STRUCTURE = 0xad, + SCSI_READ_FORMAT_CAPACITIES = 0x23, + SCSI_READ_SUBCHANNEL = 0x42, + SCSI_READ_TOC_PMA_ATIP = 0x43, + SCSI_READ_TRACK_INFORMATION = 0x52, + SCSI_REPAIR_TRACK = 0x58, + SCSI_REPORT_KEY = 0xa4, + SCSI_REQUEST_SENSE = 0x03, + SCSI_RESERVE_TRACK = 0x53, + SCSI_SCAN = 0xba, + SCSI_SEEK_10 = 0x2b, + SCSI_SEND_CUE_SHEET = 0x5d, + SCSI_SEND_DVD_STRUCTURE = 0xbf, + SCSI_SEND_EVENT = 0xa2, + SCSI_SEND_KEY = 0xa3, + SCSI_SEND_OPC_INFORMATION = 0x54, + SCSI_SET_CD_SPEED = 0xbb, + SCSI_SET_READ_AHEAD = 0xa7, + SCSI_SET_STREAMING = 0xb6, + SCSI_START_STOP_UNIT = 0x1b, + SCSI_LOAD_UNLOAD = 0x1b, + SCSI_STOP_PLAY_SCAN = 0x4e, + /** Synchronize Cache command. */ + SCSI_SYNCHRONIZE_CACHE = 0x35, + SCSI_TEST_UNIT_READY = 0x00, + SCSI_VERIFY_10 = 0x2f, + /** Write(10) command. */ + SCSI_WRITE_10 = 0x2a, + SCSI_WRITE_12 = 0xaa, + SCSI_WRITE_AND_VERIFY_10 = 0x2e, + SCSI_WRITE_BUFFER = 0x3b, + + /** Mode Select(6) command */ + SCSI_MODE_SELECT_6 = 0x15, + /** Mode Sense(6) command */ + SCSI_MODE_SENSE_6 = 0x1a, + /** Report LUNs command. */ + SCSI_REPORT_LUNS = 0xa0, + SCSI_REPORT_DENSITY = 0x44, + /** Rezero Unit command. Obsolete for ages now, but used by cdrecord. */ + SCSI_REZERO_UNIT = 0x01, + SCSI_REWIND = 0x01, + SCSI_SERVICE_ACTION_IN_16 = 0x9e, + SCSI_READ_16 = 0x88, + SCSI_WRITE_16 = 0x8a, + SCSI_READ_6 = 0x08, + SCSI_WRITE_6 = 0x0a, + SCSI_LOG_SENSE = 0x4d, + SCSI_UNMAP = 0x42, + SCSI_RESERVE_6 = 0x16, + SCSI_RELEASE_6 = 0x17, + SCSI_RESERVE_10 = 0x56, + SCSI_RELEASE_10 = 0x57, + SCSI_READ_BLOCK_LIMITS = 0x05, + SCSI_MAINTENANCE_IN = 0xa3 +} SCSICMD; + +/** + * Service action in opcode identifiers + */ +typedef enum SCSISVCACTIONIN +{ + SCSI_SVC_ACTION_IN_READ_CAPACITY_16 = 0x10 +} SCSISVCACTIONIN; + +/** + * Maintenance in opcode identifiers + */ +typedef enum SCSIMAINTENANCEIN +{ + SCSI_MAINTENANCE_IN_REPORT_SUPP_OPC = 0x0c +} SCSIMAINTENANCEIN; + +/* Mode page codes for mode sense/select commands. */ +#define SCSI_MODEPAGE_ERROR_RECOVERY 0x01 +#define SCSI_MODEPAGE_WRITE_PARAMETER 0x05 +#define SCSI_MODEPAGE_CD_STATUS 0x2a + + +/* Page control codes. */ +#define SCSI_PAGECONTROL_CURRENT 0x00 +#define SCSI_PAGECONTROL_CHANGEABLE 0x01 +#define SCSI_PAGECONTROL_DEFAULT 0x02 +#define SCSI_PAGECONTROL_SAVED 0x03 + + +/* Status codes */ +#define SCSI_STATUS_OK 0x00 +#define SCSI_STATUS_CHECK_CONDITION 0x02 +#define SCSI_STATUS_CONDITION_MET 0x04 +#define SCSI_STATUS_BUSY 0x08 +#define SCSI_STATUS_INTERMEDIATE 0x10 +#define SCSI_STATUS_DATA_UNDEROVER_RUN 0x12 +#define SCSI_STATUS_INTERMEDIATE_CONDITION_MET 0x14 +#define SCSI_STATUS_RESERVATION_CONFLICT 0x18 +#define SCSI_STATUS_COMMAND_TERMINATED 0x22 +#define SCSI_STATUS_QUEUE_FULL 0x28 +#define SCSI_STATUS_ACA_ACTIVE 0x30 +#define SCSI_STATUS_TASK_ABORTED 0x40 + +/* Sense data response codes - This is the first byte in the sense data */ +#define SCSI_SENSE_RESPONSE_CODE_CURR_FIXED 0x70 +#define SCSI_SENSE_RESPONSE_CODE_DEFERRED_FIXED 0x71 +#define SCSI_SENSE_RESPONSE_CODE_CURR_DESC 0x72 +#define SCSI_SENSE_RESPONSE_CODE_DEFERRED_DESC 0x73 + +/* Sense keys */ +#define SCSI_SENSE_NONE 0 +#define SCSI_SENSE_RECOVERED_ERROR 1 +#define SCSI_SENSE_NOT_READY 2 +#define SCSI_SENSE_MEDIUM_ERROR 3 +#define SCSI_SENSE_HARDWARE_ERROR 4 +#define SCSI_SENSE_ILLEGAL_REQUEST 5 +#define SCSI_SENSE_UNIT_ATTENTION 6 +#define SCSI_SENSE_DATA_PROTECT 7 +#define SCSI_SENSE_BLANK_CHECK 8 +#define SCSI_SENSE_VENDOR_SPECIFIC 9 +#define SCSI_SENSE_COPY_ABORTED 10 +#define SCSI_SENSE_ABORTED_COMMAND 11 +#define SCSI_SENSE_VOLUME_OVERFLOW 13 +#define SCSI_SENSE_MISCOMPARE 14 + +/* Additional sense bit flags (to be ORed with sense key). */ +#define SCSI_SENSE_FLAG_FILEMARK 0x80 +#define SCSI_SENSE_FLAG_EOM 0x40 +#define SCSI_SENSE_FLAG_ILI 0x20 + +/* Additional sense keys */ +#define SCSI_ASC_NONE 0x00 +#define SCSI_ASC_WRITE_ERROR 0x0c +#define SCSI_ASC_READ_ERROR 0x11 +#define SCSI_ASC_ILLEGAL_OPCODE 0x20 +#define SCSI_ASC_LOGICAL_BLOCK_OOR 0x21 +#define SCSI_ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED 0x25 +#define SCSI_ASC_WRITE_PROTECTED 0x27 +#define SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 +#define SCSI_ASC_POWER_ON_RESET_BUS_DEVICE_RESET_OCCURRED 0x29 +#define SCSI_ASC_CANNOT_READ_MEDIUM 0x30 +#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3a +#define SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 +#define SCSI_ASC_INTERNAL_TARGET_FAILURE 0x44 +#define SCSI_ASC_INVALID_MESSAGE 0x49 +#define SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED 0x53 +#define SCSI_ASC_LOGICAL_UNIT_DOES_NOT_RESPOND_TO_SELECTION 0x00 +#define SCSI_ASC_SYSTEM_RESOURCE_FAILURE 0x55 +#define SCSI_ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64 +#define SCSI_ASC_COMMAND_TO_LOGICAL_UNIT_FAILED 0x6E + +/** Additional sense code qualifiers (ASCQ). */ +/* NB: The ASC/ASCQ combination determines the full meaning. */ +#define SCSI_ASCQ_SYSTEM_BUFFER_FULL 0x01 +#define SCSI_ASCQ_POWER_ON_RESET_BUS_DEVICE_RESET_OCCURRED 0x00 +#define SCSI_ASCQ_END_OF_DATA_DETECTED 0x05 +#define SCSI_ASCQ_FILEMARK_DETECTED 0x01 +#define SCSI_ASCQ_EOP_EOM_DETECTED 0x02 +#define SCSI_ASCQ_SETMARK_DETECTED 0x03 +#define SCSI_ASCQ_BOP_BOM_DETECTED 0x04 +#define SCSI_ASCQ_UNKNOWN_FORMAT 0x01 +#define SCSI_ASCQ_INCOMPATIBLE_FORMAT 0x02 +#define SCSI_ASCQ_COPY_TARGET_DEVICE_DATA_OVERRUN 0x0d + +/** @name SCSI_INQUIRY + * @{ + */ + +/** Length of the SCSI INQUIRY vendor identifier (without termination). */ +#define SCSI_INQUIRY_VENDOR_ID_LENGTH 8 +/** Length of the SCSI INQUIRY product identifier (without termination). */ +#define SCSI_INQUIRY_PRODUCT_ID_LENGTH 16 +/** Length of the SCSI INQUIRY revision identifier (without termination). */ +#define SCSI_INQUIRY_REVISION_LENGTH 4 + +#pragma pack(1) +typedef struct SCSIINQUIRYCDB +{ + unsigned u8Cmd : 8; + unsigned fEVPD : 1; + unsigned u4Reserved : 4; + unsigned u3LUN : 3; + unsigned u8PageCode : 8; + unsigned u8Reserved : 8; + uint8_t cbAlloc; + uint8_t u8Control; +} SCSIINQUIRYCDB; +#pragma pack() +AssertCompileSize(SCSIINQUIRYCDB, 6); +typedef SCSIINQUIRYCDB *PSCSIINQUIRYCDB; +typedef const SCSIINQUIRYCDB *PCSCSIINQUIRYCDB; + +#pragma pack(1) +typedef struct SCSIINQUIRYDATA +{ + unsigned u5PeripheralDeviceType : 5; /**< 0x00 / 00 */ + unsigned u3PeripheralQualifier : 3; + unsigned u6DeviceTypeModifier : 7; /**< 0x01 */ + unsigned fRMB : 1; + unsigned u3AnsiVersion : 3; /**< 0x02 */ + unsigned u3EcmaVersion : 3; + unsigned u2IsoVersion : 2; + unsigned u4ResponseDataFormat : 4; /**< 0x03 */ + unsigned u2Reserved0 : 2; + unsigned fTrmlOP : 1; + unsigned fAEC : 1; + unsigned cbAdditional : 8; /**< 0x04 */ + unsigned u8Reserved1 : 8; /**< 0x05 */ + unsigned u8Reserved2 : 8; /**< 0x06 */ + unsigned fSftRe : 1; /**< 0x07 */ + unsigned fCmdQue : 1; + unsigned fReserved3 : 1; + unsigned fLinked : 1; + unsigned fSync : 1; + unsigned fWBus16 : 1; + unsigned fWBus32 : 1; + unsigned fRelAdr : 1; + int8_t achVendorId[SCSI_INQUIRY_VENDOR_ID_LENGTH]; /**< 0x08 */ + int8_t achProductId[SCSI_INQUIRY_PRODUCT_ID_LENGTH]; /**< 0x10 */ + int8_t achProductLevel[SCSI_INQUIRY_REVISION_LENGTH]; /**< 0x20 */ + uint8_t abVendorSpecific[20]; /**< 0x24/36 - Optional it seems. */ + uint8_t abReserved4[40]; + uint8_t abVendorSpecificParameters[1]; /**< 0x60/96 - Variable size. */ +} SCSIINQUIRYDATA; +#pragma pack() +AssertCompileSize(SCSIINQUIRYDATA, 97); +typedef SCSIINQUIRYDATA *PSCSIINQUIRYDATA; +typedef const SCSIINQUIRYDATA *PCSCSIINQUIRYDATA; + +#define SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED 0x00 +#define SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_BUT_SUPPORTED 0x01 +#define SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED 0x03 + +#define SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS 0x00 +#define SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_SEQUENTIAL_ACCESS 0x01 +#define SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_CD_DVD 0x05 +#define SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_UNKNOWN 0x1f + +/** @} */ + +#if defined(IN_RING3) && (defined(LOG_ENABLED) || defined(RT_STRICT)) +const char * SCSICmdText(uint8_t uCmd); +const char * SCSIStatusText(uint8_t uStatus); +const char * SCSISenseText(uint8_t uSense); +const char * SCSISenseExtText(uint8_t uASC, uint8_t uASCQ); +int SCSILogModePage(char *pszBuf, size_t cchBuffer, uint8_t *pbModePage, + size_t cbModePage); +int SCSILogCueSheet(char *pszBuf, size_t cchBuffer, uint8_t *pbCueSheet, + size_t cbCueSheet); +#endif + +#endif /* !VBOX_INCLUDED_scsi_h */ diff --git a/include/VBox/scsiinline.h b/include/VBox/scsiinline.h new file mode 100644 index 00000000..c27a1f67 --- /dev/null +++ b/include/VBox/scsiinline.h @@ -0,0 +1,246 @@ +/* $Id: scsiinline.h $ */ +/** @file + * VirtualBox: SCSI inline helpers used by devices, drivers, etc. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_scsiinline_h +#define VBOX_INCLUDED_scsiinline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/stdint.h> + +/** @defgroup grp_scsi_inline The SCSI inline helpers + * @{ + */ + + +/** + * Converts a given 16bit value to big endian and stores it in the given buffer. + * + * @returns nothing. + * @param pbBuf The buffer to store the value into. + * @param u16Val The value to store. + */ +DECLINLINE(void) scsiH2BE_U16(uint8_t *pbBuf, uint16_t u16Val) +{ + pbBuf[0] = u16Val >> 8; + pbBuf[1] = u16Val; +} + + +/** + * Converts a given 24bit value to big endian and stores it in the given buffer. + * + * @returns nothing. + * @param pbBuf The buffer to store the value into. + * @param u32Val The value to store. + */ +DECLINLINE(void) scsiH2BE_U24(uint8_t *pbBuf, uint32_t u32Val) +{ + pbBuf[0] = u32Val >> 16; + pbBuf[1] = u32Val >> 8; + pbBuf[2] = u32Val; +} + + +/** + * Converts a given 32bit value to big endian and stores it in the given buffer. + * + * @returns nothing. + * @param pbBuf The buffer to store the value into. + * @param u32Val The value to store. + */ +DECLINLINE(void) scsiH2BE_U32(uint8_t *pbBuf, uint32_t u32Val) +{ + pbBuf[0] = u32Val >> 24; + pbBuf[1] = u32Val >> 16; + pbBuf[2] = u32Val >> 8; + pbBuf[3] = u32Val; +} + + +/** + * Converts a given 64bit value to big endian and stores it in the given buffer. + * + * @returns nothing. + * @param pbBuf The buffer to store the value into. + * @param u64Val The value to store. + */ +DECLINLINE(void) scsiH2BE_U64(uint8_t *pbBuf, uint64_t u64Val) +{ + pbBuf[0] = u64Val >> 56; + pbBuf[1] = u64Val >> 48; + pbBuf[2] = u64Val >> 40; + pbBuf[3] = u64Val >> 32; + pbBuf[4] = u64Val >> 24; + pbBuf[5] = u64Val >> 16; + pbBuf[6] = u64Val >> 8; + pbBuf[7] = u64Val; +} + +/** + * Returns a 16bit value read from the given buffer converted to host endianess. + * + * @returns The converted 16bit value. + * @param pbBuf The buffer to read the value from. + */ +DECLINLINE(uint16_t) scsiBE2H_U16(const uint8_t *pbBuf) +{ + return (pbBuf[0] << 8) | pbBuf[1]; +} + + +/** + * Returns a 24bit value read from the given buffer converted to host endianess. + * + * @returns The converted 24bit value as a 32bit unsigned integer. + * @param pbBuf The buffer to read the value from. + */ +DECLINLINE(uint32_t) scsiBE2H_U24(const uint8_t *pbBuf) +{ + return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2]; +} + + +/** + * Returns a 32bit value read from the given buffer converted to host endianess. + * + * @returns The converted 32bit value. + * @param pbBuf The buffer to read the value from. + */ +DECLINLINE(uint32_t) scsiBE2H_U32(const uint8_t *pbBuf) +{ + return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3]; +} + + +/** + * Returns a 64bit value read from the given buffer converted to host endianess. + * + * @returns The converted 64bit value. + * @param pbBuf The buffer to read the value from. + */ +DECLINLINE(uint64_t) scsiBE2H_U64(const uint8_t *pbBuf) +{ + return ((uint64_t)pbBuf[0] << 56) + | ((uint64_t)pbBuf[1] << 48) + | ((uint64_t)pbBuf[2] << 40) + | ((uint64_t)pbBuf[3] << 32) + | ((uint64_t)pbBuf[4] << 24) + | ((uint64_t)pbBuf[5] << 16) + | ((uint64_t)pbBuf[6] << 8) + | (uint64_t)pbBuf[7]; +} + + +/** + * Converts the given LBA number to the MSF (Minutes:Seconds:Frames) format + * and stores it in the given buffer. + * + * @returns nothing. + * @param pbBuf The buffer to store the value into. + * @param iLBA The LBA to convert. + */ +DECLINLINE(void) scsiLBA2MSF(uint8_t *pbBuf, uint32_t iLBA) +{ + iLBA += 150; + pbBuf[0] = (iLBA / 75) / 60; + pbBuf[1] = (iLBA / 75) % 60; + pbBuf[2] = iLBA % 75; +} + + +/** + * Converts a MSF formatted address value read from the given buffer + * to an LBA number. + * + * @returns The LBA number. + * @param pbBuf The buffer to read the MSF formatted address + * from. + */ +DECLINLINE(uint32_t) scsiMSF2LBA(const uint8_t *pbBuf) +{ + return (pbBuf[0] * 60 + pbBuf[1]) * 75 + pbBuf[2] - 150; +} + + +/** + * Copies a given string to the given destination padding all unused space + * in the destination with spaces. + * + * @returns nothing. + * @param pbDst Where to store the string padded with spaces. + * @param pbSrc The string to copy. + * @param cbSize Size of the destination buffer. + */ +DECLINLINE(void) scsiPadStr(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize) +{ + uint32_t i; + for (i = 0; i < cbSize; i++) + { + if (*pbSrc) + pbDst[i] = *pbSrc++; + else + pbDst[i] = ' '; + } +} + + +/** + * Copies a given string to the given destination padding all unused space + * in the destination with spaces. + * + * @returns nothing. + * @param pbDst Where to store the string padded with spaces. + * @param pbSrc The string to copy. + * @param cbSize Size of the destination buffer. + */ +DECLINLINE(void) scsiPadStrS(int8_t *pbDst, const char *pbSrc, uint32_t cbSize) +{ + uint32_t i; + for (i = 0; i < cbSize; i++) + { + if (*pbSrc) + pbDst[i] = *pbSrc++; + else + pbDst[i] = ' '; + } +} + +/** @} */ + +#endif /* !VBOX_INCLUDED_scsiinline_h */ + diff --git a/include/VBox/settings.h b/include/VBox/settings.h new file mode 100644 index 00000000..866a9818 --- /dev/null +++ b/include/VBox/settings.h @@ -0,0 +1,1539 @@ +/** @file + * Settings file data structures. + * + * These structures are created by the settings file loader and filled with values + * copied from the raw XML data. This was all new with VirtualBox 3.1 and allows us + * to finally make the XML reader version-independent and read VirtualBox XML files + * from earlier and even newer (future) versions without requiring complicated, + * tedious and error-prone XSLT conversions. + * + * It is this file that defines all structures that map VirtualBox global and + * machine settings to XML files. These structures are used by the rest of Main, + * even though this header file does not require anything else in Main. + * + * Note: Headers in Main code have been tweaked to only declare the structures + * defined here so that this header need only be included from code files that + * actually use these structures. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_settings_h +#define VBOX_INCLUDED_settings_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/time.h> + +#include "VBox/com/VirtualBox.h" + +#include <VBox/com/Guid.h> +#include <VBox/com/string.h> +#include <VBox/VBoxCryptoIf.h> + +#include <list> +#include <map> +#include <vector> + +/** + * Maximum depth of a medium tree, to prevent stack overflows. + * XPCOM has a relatively low stack size for its workers, and we have + * to avoid crashes due to exceeding the limit both on reading and + * writing config files. The bottleneck is in libxml2. + * Data point: a release and asan build could both handle 3800 on Debian 10. + */ +#define SETTINGS_MEDIUM_DEPTH_MAX 300 + +/** + * Maximum depth of the snapshot tree, to prevent stack overflows. + * XPCOM has a relatively low stack size for its workers, and we have + * to avoid crashes due to exceeding the limit both on reading and + * writing config files. The bottleneck is reading config files with + * deep snapshot nesting, as libxml2 needs quite some stack space. + * Data point: a release and asan build could both handle 1300 on Debian 10. + */ +#define SETTINGS_SNAPSHOT_DEPTH_MAX 250 + +namespace xml +{ + class ElementNode; +} + +namespace settings +{ + +class ConfigFileError; + +//////////////////////////////////////////////////////////////////////////////// +// +// Structures shared between Machine XML and VirtualBox.xml +// +//////////////////////////////////////////////////////////////////////////////// + +typedef std::map<com::Utf8Str, com::Utf8Str> StringsMap; +typedef std::list<com::Utf8Str> StringsList; + +/** + * USB device filter definition. This struct is used both in MainConfigFile + * (for global USB filters) and MachineConfigFile (for machine filters). + * + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct USBDeviceFilter +{ + USBDeviceFilter(); + + bool operator==(const USBDeviceFilter&u) const; + + com::Utf8Str strName; + bool fActive; + com::Utf8Str strVendorId, + strProductId, + strRevision, + strManufacturer, + strProduct, + strSerialNumber, + strPort; + USBDeviceFilterAction_T action; // only used with host USB filters + com::Utf8Str strRemote; // irrelevant for host USB objects + uint32_t ulMaskedInterfaces; // irrelevant for host USB objects +}; + +typedef std::list<USBDeviceFilter> USBDeviceFiltersList; + +struct Medium; +typedef std::list<Medium> MediaList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct Medium +{ + Medium(); + + bool operator==(const Medium &m) const; + + com::Guid uuid; + com::Utf8Str strLocation; + com::Utf8Str strDescription; + + // the following are for hard disks only: + com::Utf8Str strFormat; + bool fAutoReset; // optional, only for diffs, default is false + StringsMap properties; + MediumType_T hdType; + + MediaList llChildren; // only used with hard disks + + static const struct Medium Empty; +}; + +/** + * A media registry. Starting with VirtualBox 3.3, this can appear in both the + * VirtualBox.xml file as well as machine XML files with settings version 1.11 + * or higher, so these lists are now in ConfigFileBase. + * + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct MediaRegistry +{ + bool operator==(const MediaRegistry &m) const; + + MediaList llHardDisks, + llDvdImages, + llFloppyImages; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct NATRule +{ + NATRule(); + + bool operator==(const NATRule &r) const; + + com::Utf8Str strName; + NATProtocol_T proto; + uint16_t u16HostPort; + com::Utf8Str strHostIP; + uint16_t u16GuestPort; + com::Utf8Str strGuestIP; +}; +typedef std::map<com::Utf8Str, NATRule> NATRulesMap; + +struct NATHostLoopbackOffset +{ + NATHostLoopbackOffset(); + + bool operator==(const NATHostLoopbackOffset &o) const; + + bool operator==(const com::Utf8Str& strAddr) + { + return strLoopbackHostAddress == strAddr; + } + + bool operator==(uint32_t off) + { + return u32Offset == off; + } + + /** Note: 128/8 is only acceptable */ + com::Utf8Str strLoopbackHostAddress; + uint32_t u32Offset; +}; + +typedef std::list<NATHostLoopbackOffset> NATLoopbackOffsetList; + +typedef std::vector<uint8_t> IconBlob; + +/** + * Common base class for both MainConfigFile and MachineConfigFile + * which contains some common logic for both. + */ +class ConfigFileBase +{ +public: + bool fileExists(); + SettingsVersion_T getSettingsVersion(); + + void copyBaseFrom(const ConfigFileBase &b); + +protected: + ConfigFileBase(const com::Utf8Str *pstrFilename); + /* Note: this copy constructor doesn't create a full copy of other, cause + * the file based stuff (xml doc) could not be copied. */ + ConfigFileBase(const ConfigFileBase &other); + + ~ConfigFileBase(); + + typedef enum {Error, HardDisk, DVDImage, FloppyImage} MediaType; + + static const char *stringifyMediaType(MediaType t); + SettingsVersion_T parseVersion(const com::Utf8Str &strVersion, + const xml::ElementNode *pElm); + void parseUUID(com::Guid &guid, + const com::Utf8Str &strUUID, + const xml::ElementNode *pElm) const; + void parseTimestamp(RTTIMESPEC ×tamp, + const com::Utf8Str &str, + const xml::ElementNode *pElm) const; + void parseBase64(IconBlob &binary, + const com::Utf8Str &str, + const xml::ElementNode *pElm) const; + com::Utf8Str stringifyTimestamp(const RTTIMESPEC &tm) const; + void toBase64(com::Utf8Str &str, + const IconBlob &binary) const; + + void readExtraData(const xml::ElementNode &elmExtraData, + StringsMap &map); + void readUSBDeviceFilters(const xml::ElementNode &elmDeviceFilters, + USBDeviceFiltersList &ll); + void readMediumOne(MediaType t, const xml::ElementNode &elmMedium, Medium &med); + void readMedium(MediaType t, const xml::ElementNode &elmMedium, Medium &med); + void readMediaRegistry(const xml::ElementNode &elmMediaRegistry, MediaRegistry &mr); + void readNATForwardRulesMap(const xml::ElementNode &elmParent, NATRulesMap &mapRules); + void readNATLoopbacks(const xml::ElementNode &elmParent, NATLoopbackOffsetList &llLoopBacks); + + void setVersionAttribute(xml::ElementNode &elm); + void specialBackupIfFirstBump(); + void createStubDocument(); + + void buildExtraData(xml::ElementNode &elmParent, const StringsMap &me); + void buildUSBDeviceFilters(xml::ElementNode &elmParent, + const USBDeviceFiltersList &ll, + bool fHostMode); + void buildMedium(MediaType t, + xml::ElementNode &elmMedium, + const Medium &med); + void buildMediaRegistry(xml::ElementNode &elmParent, + const MediaRegistry &mr); + void buildNATForwardRulesMap(xml::ElementNode &elmParent, const NATRulesMap &mapRules); + void buildNATLoopbacks(xml::ElementNode &elmParent, const NATLoopbackOffsetList &natLoopbackList); + void clearDocument(); + + struct Data; + Data *m; + + friend class ConfigFileError; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// VirtualBox.xml structures +// +//////////////////////////////////////////////////////////////////////////////// + +struct USBDeviceSource +{ + com::Utf8Str strName; + com::Utf8Str strBackend; + com::Utf8Str strAddress; + StringsMap properties; +}; + +typedef std::list<USBDeviceSource> USBDeviceSourcesList; + +#ifdef VBOX_WITH_UPDATE_AGENT +struct UpdateAgent +{ + UpdateAgent(); + + bool fEnabled; + UpdateChannel_T enmChannel; + uint32_t uCheckFreqSeconds; + com::Utf8Str strRepoUrl; + com::Utf8Str strLastCheckDate; + uint32_t uCheckCount; +}; +#endif /* VBOX_WITH_UPDATE_AGENT */ + +struct Host +{ + USBDeviceFiltersList llUSBDeviceFilters; + USBDeviceSourcesList llUSBDeviceSources; +#ifdef VBOX_WITH_UPDATE_AGENT + UpdateAgent updateHost; + /** @todo Add handling for ExtPack and Guest Additions updates here later. See @bugref{7983}. */ +#endif /* VBOX_WITH_UPDATE_AGENT */ +}; + +struct SystemProperties +{ + SystemProperties(); + + com::Utf8Str strDefaultMachineFolder; + com::Utf8Str strDefaultHardDiskFolder; + com::Utf8Str strDefaultHardDiskFormat; + com::Utf8Str strVRDEAuthLibrary; + com::Utf8Str strWebServiceAuthLibrary; + com::Utf8Str strDefaultVRDEExtPack; + com::Utf8Str strDefaultCryptoExtPack; + com::Utf8Str strAutostartDatabasePath; + com::Utf8Str strDefaultAdditionsISO; + com::Utf8Str strDefaultFrontend; + com::Utf8Str strLoggingLevel; + com::Utf8Str strProxyUrl; + uint32_t uProxyMode; /**< ProxyMode_T */ + uint32_t uLogHistoryCount; + bool fExclusiveHwVirt; + com::Utf8Str strLanguageId; +}; + +struct MachineRegistryEntry +{ + com::Guid uuid; + com::Utf8Str strSettingsFile; +}; + +typedef std::list<MachineRegistryEntry> MachinesRegistry; + +struct DhcpOptValue +{ + DhcpOptValue(); + DhcpOptValue(const com::Utf8Str &aText, DHCPOptionEncoding_T aEncoding = DHCPOptionEncoding_Normal); + + com::Utf8Str strValue; + DHCPOptionEncoding_T enmEncoding; +}; + +typedef std::map<DHCPOption_T, DhcpOptValue> DhcpOptionMap; +typedef DhcpOptionMap::value_type DhcpOptValuePair; +typedef DhcpOptionMap::iterator DhcpOptIterator; +typedef DhcpOptionMap::const_iterator DhcpOptConstIterator; + +struct DHCPGroupCondition +{ + DHCPGroupCondition(); + + bool fInclusive; + DHCPGroupConditionType_T enmType; + com::Utf8Str strValue; +}; +typedef std::vector<DHCPGroupCondition> DHCPGroupConditionVec; + + +struct DHCPConfig +{ + DHCPConfig(); + + DhcpOptionMap mapOptions; + uint32_t secMinLeaseTime; + uint32_t secDefaultLeaseTime; + uint32_t secMaxLeaseTime; + com::Utf8Str strForcedOptions; + com::Utf8Str strSuppressedOptions; +}; + +struct DHCPGroupConfig : DHCPConfig +{ + DHCPGroupConfig(); + + com::Utf8Str strName; + DHCPGroupConditionVec vecConditions; +}; +typedef std::vector<DHCPGroupConfig> DHCPGroupConfigVec; + +struct DHCPIndividualConfig : DHCPConfig +{ + DHCPIndividualConfig(); + + com::Utf8Str strMACAddress; + com::Utf8Str strVMName; + uint32_t uSlot; + com::Utf8Str strFixedAddress; +}; +typedef std::map<com::Utf8Str, DHCPIndividualConfig> DHCPIndividualConfigMap; + +struct DHCPServer +{ + DHCPServer(); + + com::Utf8Str strNetworkName; + com::Utf8Str strIPAddress; + com::Utf8Str strIPLower; + com::Utf8Str strIPUpper; + bool fEnabled; + DHCPConfig globalConfig; + DHCPGroupConfigVec vecGroupConfigs; + DHCPIndividualConfigMap mapIndividualConfigs; +}; +typedef std::list<DHCPServer> DHCPServersList; + + +/** + * NAT Networking settings (NAT service). + */ +struct NATNetwork +{ + NATNetwork(); + + com::Utf8Str strNetworkName; + com::Utf8Str strIPv4NetworkCidr; + com::Utf8Str strIPv6Prefix; + bool fEnabled; + bool fIPv6Enabled; + bool fAdvertiseDefaultIPv6Route; + bool fNeedDhcpServer; + uint32_t u32HostLoopback6Offset; + NATLoopbackOffsetList llHostLoopbackOffsetList; + NATRulesMap mapPortForwardRules4; + NATRulesMap mapPortForwardRules6; +}; + +typedef std::list<NATNetwork> NATNetworksList; + +#ifdef VBOX_WITH_VMNET +/** + * HostOnly Networking settings. + */ +struct HostOnlyNetwork +{ + HostOnlyNetwork(); + + com::Guid uuid; + com::Utf8Str strNetworkName; + com::Utf8Str strNetworkMask; + com::Utf8Str strIPLower; + com::Utf8Str strIPUpper; + bool fEnabled; +}; + +typedef std::list<HostOnlyNetwork> HostOnlyNetworksList; +#endif /* VBOX_WITH_VMNET */ + +#ifdef VBOX_WITH_CLOUD_NET +/** + * Cloud Networking settings. + */ +struct CloudNetwork +{ + CloudNetwork(); + + com::Utf8Str strNetworkName; + com::Utf8Str strProviderShortName; + com::Utf8Str strProfileName; + com::Utf8Str strNetworkId; + bool fEnabled; +}; + +typedef std::list<CloudNetwork> CloudNetworksList; +#endif /* VBOX_WITH_CLOUD_NET */ + + +class MainConfigFile : public ConfigFileBase +{ +public: + MainConfigFile(const com::Utf8Str *pstrFilename); + + void readMachineRegistry(const xml::ElementNode &elmMachineRegistry); + void readNATNetworks(const xml::ElementNode &elmNATNetworks); +#ifdef VBOX_WITH_VMNET + void readHostOnlyNetworks(const xml::ElementNode &elmHostOnlyNetworks); +#endif /* VBOX_WITH_VMNET */ +#ifdef VBOX_WITH_CLOUD_NET + void readCloudNetworks(const xml::ElementNode &elmCloudNetworks); +#endif /* VBOX_WITH_CLOUD_NET */ + + void write(const com::Utf8Str strFilename); + + Host host; + SystemProperties systemProperties; + MediaRegistry mediaRegistry; + MachinesRegistry llMachines; + DHCPServersList llDhcpServers; + NATNetworksList llNATNetworks; +#ifdef VBOX_WITH_VMNET + HostOnlyNetworksList llHostOnlyNetworks; +#endif /* VBOX_WITH_VMNET */ +#ifdef VBOX_WITH_CLOUD_NET + CloudNetworksList llCloudNetworks; +#endif /* VBOX_WITH_CLOUD_NET */ + StringsMap mapExtraDataItems; + +private: + void bumpSettingsVersionIfNeeded(); + void buildUSBDeviceSources(xml::ElementNode &elmParent, const USBDeviceSourcesList &ll); + void readUSBDeviceSources(const xml::ElementNode &elmDeviceSources, USBDeviceSourcesList &ll); + void buildDHCPServers(xml::ElementNode &elmDHCPServers, DHCPServersList const &ll); + void buildDHCPOptions(xml::ElementNode &elmOptions, DHCPConfig const &rConfig, bool fIgnoreSubnetMask); + void readDHCPServers(const xml::ElementNode &elmDHCPServers); + void readDHCPOptions(DHCPConfig &rConfig, const xml::ElementNode &elmOptions, bool fIgnoreSubnetMask); + bool convertGuiProxySettings(const com::Utf8Str &strUIProxySettings); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// Machine XML structures +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct VRDESettings +{ + VRDESettings(); + + bool areDefaultSettings(SettingsVersion_T sv) const; + + bool operator==(const VRDESettings& v) const; + + bool fEnabled; + AuthType_T authType; + uint32_t ulAuthTimeout; + com::Utf8Str strAuthLibrary; + bool fAllowMultiConnection, + fReuseSingleConnection; + com::Utf8Str strVrdeExtPack; + StringsMap mapProperties; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct BIOSSettings +{ + BIOSSettings(); + + bool areDefaultSettings() const; + + bool operator==(const BIOSSettings &d) const; + + bool fACPIEnabled, + fIOAPICEnabled, + fLogoFadeIn, + fLogoFadeOut, + fPXEDebugEnabled, + fSmbiosUuidLittleEndian; + uint32_t ulLogoDisplayTime; + BIOSBootMenuMode_T biosBootMenuMode; + APICMode_T apicMode; // requires settings version 1.16 (VirtualBox 5.1) + int64_t llTimeOffset; + com::Utf8Str strLogoImagePath; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct TpmSettings +{ + TpmSettings(); + + bool areDefaultSettings() const; + + bool operator==(const TpmSettings &d) const; + + TpmType_T tpmType; + com::Utf8Str strLocation; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct NvramSettings +{ + NvramSettings(); + + bool areDefaultSettings() const; + + bool operator==(const NvramSettings &d) const; + + com::Utf8Str strNvramPath; + com::Utf8Str strKeyId; + com::Utf8Str strKeyStore; +}; + +/** List for keeping a recording feature list. */ +typedef std::map<RecordingFeature_T, bool> RecordingFeatureMap; + +/** + * Recording settings for a single screen (e.g. virtual monitor). + * + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct RecordingScreenSettings +{ + RecordingScreenSettings(uint32_t idScreen = UINT32_MAX); + + virtual ~RecordingScreenSettings(); + + void applyDefaults(void); + + bool areDefaultSettings(void) const; + + bool isFeatureEnabled(RecordingFeature_T enmFeature) const; + + static const char *getDefaultOptions(void); + + static int featuresFromString(const com::Utf8Str &strFeatures, RecordingFeatureMap &featureMap); + + static void featuresToString(const RecordingFeatureMap &featureMap, com::Utf8Str &strFeatures); + + static int audioCodecFromString(const com::Utf8Str &strCodec, RecordingAudioCodec_T &enmCodec); + + static void audioCodecToString(const RecordingAudioCodec_T &enmCodec, com::Utf8Str &strCodec); + + static int videoCodecFromString(const com::Utf8Str &strCodec, RecordingVideoCodec_T &enmCodec); + + static void videoCodecToString(const RecordingVideoCodec_T &enmCodec, com::Utf8Str &strCodec); + + bool operator==(const RecordingScreenSettings &d) const; + + /** Screen ID. + * UINT32_MAX if not set. */ + uint32_t idScreen; + /** Whether to record this screen or not. */ + bool fEnabled; // requires settings version 1.14 (VirtualBox 4.3) + /** Destination to record to. */ + RecordingDestination_T enmDest; + /** Which features are enable or not. */ + RecordingFeatureMap featureMap; // requires settings version 1.19 (VirtualBox 7.0) + /** Maximum time (in s) to record. If set to 0, no time limit is set. */ + uint32_t ulMaxTimeS; // requires settings version 1.14 (VirtualBox 4.3) + /** Options string for hidden / advanced / experimental features. + * Use RecordingScreenSettings::getDefaultOptions(). */ + com::Utf8Str strOptions; // new since VirtualBox 5.2. + + /** + * Structure holding settings for audio recording. + */ + struct Audio + { + /** The audio codec type to use. */ + RecordingAudioCodec_T enmCodec; // requires settings version 1.19 (VirtualBox 7.0) + /** Codec deadline to use. */ + RecordingCodecDeadline_T enmDeadline; // requires settings version 1.19 (VirtualBox 7.0) + /** Rate control mode to use. */ + RecordingRateControlMode_T + enmRateCtlMode;// requires settings version 1.19 (VirtualBox 7.0) + /** Hz rate. */ + uint16_t uHz; // requires settings version 1.19 (VirtualBox 7.0) + /** Bits per sample. */ + uint8_t cBits; // requires settings version 1.19 (VirtualBox 7.0) + /** Number of audio channels. */ + uint8_t cChannels; // requires settings version 1.19 (VirtualBox 7.0) + } Audio; + + /** + * Structure holding settings for video recording. + */ + struct Video + { + /** The codec to use. */ + RecordingVideoCodec_T enmCodec; // requires settings version 1.19 (VirtualBox 7.0) + /** Codec deadline to use. */ + RecordingCodecDeadline_T enmDeadline; // requires settings version 1.19 (VirtualBox 7.0) + /** Rate control mode to use. */ + RecordingRateControlMode_T + enmRateCtlMode; // requires settings version 1.19 (VirtualBox 7.0) + /** Rate control mode to use. */ + RecordingVideoScalingMode_T + enmScalingMode; // requires settings version 1.19 (VirtualBox 7.0) + /** Target frame width in pixels (X). */ + uint32_t ulWidth; // requires settings version 1.14 (VirtualBox 4.3) + /** Target frame height in pixels (Y). */ + uint32_t ulHeight; // requires settings version 1.14 (VirtualBox 4.3) + /** Encoding rate. */ + uint32_t ulRate; // requires settings version 1.14 (VirtualBox 4.3) + /** Frames per second (FPS). */ + uint32_t ulFPS; // requires settings version 1.14 (VirtualBox 4.3) + } Video; + + /** + * Structure holding settings if the destination is a file. + */ + struct File + { + /** Maximum size (in MB) the file is allowed to have. + * When reaching the limit, recording will stop. 0 means no limit. */ + uint32_t ulMaxSizeMB; // requires settings version 1.14 (VirtualBox 4.3) + /** Absolute file name path to use for recording. + * When empty, this is considered as being the default setting. */ + com::Utf8Str strName; // requires settings version 1.14 (VirtualBox 4.3) + } File; +}; + +/** Map for keeping settings per virtual screen. + * The key specifies the screen ID. */ +typedef std::map<uint32_t, RecordingScreenSettings> RecordingScreenSettingsMap; + +/** + * Common recording settings, shared among all per-screen recording settings. + * + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct RecordingCommonSettings +{ + RecordingCommonSettings(); + + void applyDefaults(void); + + bool areDefaultSettings(void) const; + + bool operator==(const RecordingCommonSettings &d) const; + + /** Whether recording as a whole is enabled or disabled. */ + bool fEnabled; // requires settings version 1.14 (VirtualBox 4.3) +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct RecordingSettings +{ + RecordingSettings(); + + void applyDefaults(void); + + bool areDefaultSettings(void) const; + + bool operator==(const RecordingSettings &that) const; + + /** Common settings for all per-screen recording settings. */ + RecordingCommonSettings common; + /** Map of handled recording screen settings. + * The key specifies the screen ID. */ + RecordingScreenSettingsMap mapScreens; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct GraphicsAdapter +{ + GraphicsAdapter(); + + bool areDefaultSettings() const; + + bool operator==(const GraphicsAdapter &g) const; + + GraphicsControllerType_T graphicsControllerType; + uint32_t ulVRAMSizeMB; + uint32_t cMonitors; + bool fAccelerate3D, + fAccelerate2DVideo; // requires settings version 1.8 (VirtualBox 3.1) +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct USBController +{ + USBController(); + + bool operator==(const USBController &u) const; + + com::Utf8Str strName; + USBControllerType_T enmType; +}; + +typedef std::list<USBController> USBControllerList; + +struct USB +{ + USB(); + + bool operator==(const USB &u) const; + + /** List of USB controllers present. */ + USBControllerList llUSBControllers; + /** List of USB device filters. */ + USBDeviceFiltersList llDeviceFilters; +}; + +struct NAT +{ + NAT(); + + bool areDNSDefaultSettings() const; + bool areAliasDefaultSettings() const; + bool areTFTPDefaultSettings() const; + bool areLocalhostReachableDefaultSettings(SettingsVersion_T sv) const; + bool areDefaultSettings(SettingsVersion_T sv) const; + + bool operator==(const NAT &n) const; + + com::Utf8Str strNetwork; + com::Utf8Str strBindIP; + uint32_t u32Mtu; + uint32_t u32SockRcv; + uint32_t u32SockSnd; + uint32_t u32TcpRcv; + uint32_t u32TcpSnd; + com::Utf8Str strTFTPPrefix; + com::Utf8Str strTFTPBootFile; + com::Utf8Str strTFTPNextServer; + bool fDNSPassDomain; + bool fDNSProxy; + bool fDNSUseHostResolver; + bool fAliasLog; + bool fAliasProxyOnly; + bool fAliasUseSamePorts; + bool fLocalhostReachable; + NATRulesMap mapRules; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct NetworkAdapter +{ + NetworkAdapter(); + + bool areGenericDriverDefaultSettings() const; + bool areDefaultSettings(SettingsVersion_T sv) const; + bool areDisabledDefaultSettings(SettingsVersion_T sv) const; + + bool operator==(const NetworkAdapter &n) const; + + uint32_t ulSlot; + + NetworkAdapterType_T type; + bool fEnabled; + com::Utf8Str strMACAddress; + bool fCableConnected; + uint32_t ulLineSpeed; + NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy; + bool fTraceEnabled; + com::Utf8Str strTraceFile; + + NetworkAttachmentType_T mode; + NAT nat; + com::Utf8Str strBridgedName; + com::Utf8Str strHostOnlyName; +#ifdef VBOX_WITH_VMNET + com::Utf8Str strHostOnlyNetworkName; +#endif /* VBOX_WITH_VMNET */ + com::Utf8Str strInternalNetworkName; + com::Utf8Str strGenericDriver; + StringsMap genericProperties; + com::Utf8Str strNATNetworkName; +#ifdef VBOX_WITH_CLOUD_NET + com::Utf8Str strCloudNetworkName; +#endif /* VBOX_WITH_CLOUD_NET */ + uint32_t ulBootPriority; + com::Utf8Str strBandwidthGroup; // requires settings version 1.13 (VirtualBox 4.2) +}; + +typedef std::list<NetworkAdapter> NetworkAdaptersList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct SerialPort +{ + SerialPort(); + + bool operator==(const SerialPort &n) const; + + uint32_t ulSlot; + + bool fEnabled; + uint32_t ulIOBase; + uint32_t ulIRQ; + PortMode_T portMode; + com::Utf8Str strPath; + bool fServer; + UartType_T uartType; +}; + +typedef std::list<SerialPort> SerialPortsList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct ParallelPort +{ + ParallelPort(); + + bool operator==(const ParallelPort &d) const; + + uint32_t ulSlot; + + bool fEnabled; + uint32_t ulIOBase; + uint32_t ulIRQ; + com::Utf8Str strPath; +}; + +typedef std::list<ParallelPort> ParallelPortsList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct AudioAdapter +{ + AudioAdapter(); + + bool areDefaultSettings(SettingsVersion_T sv) const; + + bool operator==(const AudioAdapter &a) const; + + bool fEnabled; + bool fEnabledIn; + bool fEnabledOut; + AudioControllerType_T controllerType; + AudioCodecType_T codecType; + AudioDriverType_T driverType; + settings::StringsMap properties; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct SharedFolder +{ + SharedFolder(); + + bool operator==(const SharedFolder &a) const; + + com::Utf8Str strName, + strHostPath; + bool fWritable; + bool fAutoMount; + com::Utf8Str strAutoMountPoint; +}; + +typedef std::list<SharedFolder> SharedFoldersList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct GuestProperty +{ + GuestProperty(); + + bool operator==(const GuestProperty &g) const; + + com::Utf8Str strName, + strValue; + uint64_t timestamp; + com::Utf8Str strFlags; +}; + +typedef std::list<GuestProperty> GuestPropertiesList; + +typedef std::map<uint32_t, DeviceType_T> BootOrderMap; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct CpuIdLeaf +{ + CpuIdLeaf(); + + bool operator==(const CpuIdLeaf &c) const; + + uint32_t idx; + uint32_t idxSub; + uint32_t uEax; + uint32_t uEbx; + uint32_t uEcx; + uint32_t uEdx; +}; + +typedef std::list<CpuIdLeaf> CpuIdLeafsList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct Cpu +{ + Cpu(); + + bool operator==(const Cpu &c) const; + + uint32_t ulId; +}; + +typedef std::list<Cpu> CpuList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct BandwidthGroup +{ + BandwidthGroup(); + + bool operator==(const BandwidthGroup &i) const; + + com::Utf8Str strName; + uint64_t cMaxBytesPerSec; + BandwidthGroupType_T enmType; +}; + +typedef std::list<BandwidthGroup> BandwidthGroupList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct IOSettings +{ + IOSettings(); + + bool areIOCacheDefaultSettings() const; + bool areDefaultSettings() const; + + bool operator==(const IOSettings &i) const; + + bool fIOCacheEnabled; + uint32_t ulIOCacheSize; + BandwidthGroupList llBandwidthGroups; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct HostPCIDeviceAttachment +{ + HostPCIDeviceAttachment(); + + bool operator==(const HostPCIDeviceAttachment &a) const; + + com::Utf8Str strDeviceName; + uint32_t uHostAddress; + uint32_t uGuestAddress; +}; + +typedef std::list<HostPCIDeviceAttachment> HostPCIDeviceAttachmentList; + +/** + * A device attached to a storage controller. This can either be a + * hard disk or a DVD drive or a floppy drive and also specifies + * which medium is "in" the drive; as a result, this is a combination + * of the Main IMedium and IMediumAttachment interfaces. + * + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct AttachedDevice +{ + AttachedDevice(); + + bool operator==(const AttachedDevice &a) const; + + DeviceType_T deviceType; // only HardDisk, DVD or Floppy are allowed + + // DVDs can be in pass-through mode: + bool fPassThrough; + + // Whether guest-triggered eject of DVDs will keep the medium in the + // VM config or not: + bool fTempEject; + + // Whether the medium is non-rotational: + bool fNonRotational; + + // Whether the medium supports discarding unused blocks: + bool fDiscard; + + // Whether the medium is hot-pluggable: + bool fHotPluggable; + + int32_t lPort; + int32_t lDevice; + + // if an image file is attached to the device (ISO, RAW, or hard disk image such as VDI), + // this is its UUID; it depends on deviceType which media registry this then needs to + // be looked up in. If no image file (only permitted for DVDs and floppies), then the UUID is NULL + com::Guid uuid; + + // for DVDs and floppies, the attachment can also be a host device: + com::Utf8Str strHostDriveSrc; // if != NULL, value of <HostDrive>/@src + + // Bandwidth group the device is attached to. + com::Utf8Str strBwGroup; +}; + +typedef std::list<AttachedDevice> AttachedDevicesList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct StorageController +{ + StorageController(); + + bool operator==(const StorageController &s) const; + + com::Utf8Str strName; + StorageBus_T storageBus; // _SATA, _SCSI, _IDE, _SAS + StorageControllerType_T controllerType; + uint32_t ulPortCount; + uint32_t ulInstance; + bool fUseHostIOCache; + bool fBootable; + + // only for when controllerType == StorageControllerType_IntelAhci: + int32_t lIDE0MasterEmulationPort, + lIDE0SlaveEmulationPort, + lIDE1MasterEmulationPort, + lIDE1SlaveEmulationPort; + + AttachedDevicesList llAttachedDevices; +}; + +typedef std::list<StorageController> StorageControllersList; + +/** + * We wrap the storage controllers list into an extra struct so we can + * use an undefined struct without needing std::list<> in all the headers. + * + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct Storage +{ + bool operator==(const Storage &s) const; + + StorageControllersList llStorageControllers; +}; + +/** + * Representation of Machine hardware; this is used in the MachineConfigFile.hardwareMachine + * field. + * + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct Hardware +{ + Hardware(); + + bool areParavirtDefaultSettings(SettingsVersion_T sv) const; + bool areBootOrderDefaultSettings() const; + bool areDisplayDefaultSettings() const; + bool areAllNetworkAdaptersDefaultSettings(SettingsVersion_T sv) const; + + bool operator==(const Hardware&) const; + + com::Utf8Str strVersion; // hardware version, optional + com::Guid uuid; // hardware uuid, optional (null). + + bool fHardwareVirt, + fNestedPaging, + fLargePages, + fVPID, + fUnrestrictedExecution, + fHardwareVirtForce, + fUseNativeApi, + fSyntheticCpu, + fTripleFaultReset, + fPAE, + fAPIC, // requires settings version 1.16 (VirtualBox 5.1) + 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. + bool fL1DFlushOnSched ; //< added out of cycle, after 1.16 was out. + bool fL1DFlushOnVMEntry ; //< added out of cycle, after 1.16 was out. + bool fMDSClearOnSched; //< added out of cycle, after 1.16 was out. + bool fMDSClearOnVMEntry; //< added out of cycle, after 1.16 was out. + bool fNestedHWVirt; //< requires settings version 1.17 (VirtualBox 6.0) + bool fVirtVmsaveVmload; //< requires settings version 1.18 (VirtualBox 6.1) + typedef enum LongModeType { LongMode_Enabled, LongMode_Disabled, LongMode_Legacy } LongModeType; + LongModeType enmLongMode; + uint32_t cCPUs; + bool fCpuHotPlug; // requires settings version 1.10 (VirtualBox 3.2) + CpuList llCpus; // requires settings version 1.10 (VirtualBox 3.2) + bool fHPETEnabled; // requires settings version 1.10 (VirtualBox 3.2) + uint32_t ulCpuExecutionCap; // requires settings version 1.11 (VirtualBox 3.3) + uint32_t uCpuIdPortabilityLevel; // requires settings version 1.15 (VirtualBox 5.0) + com::Utf8Str strCpuProfile; // requires settings version 1.16 (VirtualBox 5.1) + + CpuIdLeafsList llCpuIdLeafs; + + uint32_t ulMemorySizeMB; + + BootOrderMap mapBootOrder; // item 0 has highest priority + + FirmwareType_T firmwareType; // requires settings version 1.9 (VirtualBox 3.1) + + PointingHIDType_T pointingHIDType; // requires settings version 1.10 (VirtualBox 3.2) + KeyboardHIDType_T keyboardHIDType; // requires settings version 1.10 (VirtualBox 3.2) + + ChipsetType_T chipsetType; // requires settings version 1.11 (VirtualBox 4.0) + IommuType_T iommuType; // requires settings version 1.19 (VirtualBox 6.2) + ParavirtProvider_T paravirtProvider; // requires settings version 1.15 (VirtualBox 4.4) + com::Utf8Str strParavirtDebug; // requires settings version 1.16 (VirtualBox 5.1) + + bool fEmulatedUSBCardReader; // 1.12 (VirtualBox 4.1) + + VRDESettings vrdeSettings; + + BIOSSettings biosSettings; + NvramSettings nvramSettings; + GraphicsAdapter graphicsAdapter; + USB usbSettings; + TpmSettings tpmSettings; // requires settings version 1.19 (VirtualBox 6.2) + NetworkAdaptersList llNetworkAdapters; + SerialPortsList llSerialPorts; + ParallelPortsList llParallelPorts; + AudioAdapter audioAdapter; + Storage storage; + + // technically these two have no business in the hardware section, but for some + // clever reason <Hardware> is where they are in the XML.... + SharedFoldersList llSharedFolders; + + ClipboardMode_T clipboardMode; + bool fClipboardFileTransfersEnabled; + + DnDMode_T dndMode; + + uint32_t ulMemoryBalloonSize; + bool fPageFusionEnabled; + + GuestPropertiesList llGuestProperties; + + IOSettings ioSettings; // requires settings version 1.10 (VirtualBox 3.2) + HostPCIDeviceAttachmentList pciAttachments; // requires settings version 1.12 (VirtualBox 4.1) + + com::Utf8Str strDefaultFrontend; // requires settings version 1.14 (VirtualBox 4.3) +}; + +/** + * Settings that has to do with debugging. + */ +struct Debugging +{ + Debugging(); + + bool areDefaultSettings() const; + + bool operator==(const Debugging &rOther) const; + + bool fTracingEnabled; + bool fAllowTracingToAccessVM; + com::Utf8Str strTracingConfig; + GuestDebugProvider_T enmDbgProvider; + GuestDebugIoProvider_T enmIoProvider; + com::Utf8Str strAddress; + uint32_t ulPort; +}; + +/** + * Settings that has to do with autostart. + */ +struct Autostart +{ + Autostart(); + + bool areDefaultSettings() const; + + bool operator==(const Autostart &rOther) const; + + bool fAutostartEnabled; + uint32_t uAutostartDelay; + AutostopType_T enmAutostopType; +}; + +struct Snapshot; +typedef std::list<Snapshot> SnapshotsList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct Snapshot +{ + Snapshot(); + + bool operator==(const Snapshot &s) const; + + com::Guid uuid; + com::Utf8Str strName, + strDescription; // optional + RTTIMESPEC timestamp; + + com::Utf8Str strStateFile; // for online snapshots only + + Hardware hardware; + + Debugging debugging; + Autostart autostart; + RecordingSettings recordingSettings; + + SnapshotsList llChildSnapshots; + + static const struct Snapshot Empty; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct MachineUserData +{ + MachineUserData(); + + bool operator==(const MachineUserData &c) const; + + com::Utf8Str strName; + bool fDirectoryIncludesUUID; + bool fNameSync; + com::Utf8Str strDescription; + StringsList llGroups; + com::Utf8Str strOsType; + com::Utf8Str strSnapshotFolder; + bool fTeleporterEnabled; + uint32_t uTeleporterPort; + com::Utf8Str strTeleporterAddress; + com::Utf8Str strTeleporterPassword; + bool fRTCUseUTC; + IconBlob ovIcon; + VMProcPriority_T enmVMPriority; +}; + + +/** + * MachineConfigFile represents an XML machine configuration. All the machine settings + * that go out to the XML (or are read from it) are in here. + * + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by Machine::saveSettings(), or otherwise your settings + * might never get saved. + */ +class MachineConfigFile : public ConfigFileBase +{ +public: + com::Guid uuid; + + enum + { + ParseState_NotParsed, + ParseState_PasswordError, + ParseState_Parsed + } enmParseState; + + MachineUserData machineUserData; + + com::Utf8Str strStateKeyId; + com::Utf8Str strStateKeyStore; + com::Utf8Str strStateFile; + bool fCurrentStateModified; // optional, default is true + RTTIMESPEC timeLastStateChange; // optional, defaults to now + bool fAborted; // optional, default is false + + com::Guid uuidCurrentSnapshot; + + Hardware hardwareMachine; + MediaRegistry mediaRegistry; + Debugging debugging; + Autostart autostart; + RecordingSettings recordingSettings; + + StringsMap mapExtraDataItems; + + SnapshotsList llFirstSnapshot; // first snapshot or empty list if there's none + + com::Utf8Str strKeyId; + com::Utf8Str strKeyStore; // if not empty, the encryption is used + com::Utf8Str strLogKeyId; + com::Utf8Str strLogKeyStore; + + MachineConfigFile(const com::Utf8Str *pstrFilename, + PCVBOXCRYPTOIF pCryptoIf = NULL, + const char *pszPassword = NULL); + + bool operator==(const MachineConfigFile &m) const; + + bool canHaveOwnMediaRegistry() const; + + void importMachineXML(const xml::ElementNode &elmMachine); + + void write(const com::Utf8Str &strFilename, PCVBOXCRYPTOIF pCryptoIf = NULL, const char *pszPassword = NULL); + + enum + { + BuildMachineXML_IncludeSnapshots = 0x01, + BuildMachineXML_WriteVBoxVersionAttribute = 0x02, + BuildMachineXML_SkipRemovableMedia = 0x04, + BuildMachineXML_MediaRegistry = 0x08, + BuildMachineXML_SuppressSavedState = 0x10 + }; + + void copyEncryptionSettingsFrom(const MachineConfigFile &other); + void buildMachineXML(xml::ElementNode &elmMachine, + uint32_t fl, + std::list<xml::ElementNode*> *pllElementsWithUuidAttributes); + + static bool isAudioDriverAllowedOnThisHost(AudioDriverType_T enmDrvType); + static AudioDriverType_T getHostDefaultAudioDriver(); + +private: + void readNetworkAdapters(const xml::ElementNode &elmHardware, NetworkAdaptersList &ll); + void readAttachedNetworkMode(const xml::ElementNode &pelmMode, bool fEnabled, NetworkAdapter &nic); + void readCpuIdTree(const xml::ElementNode &elmCpuid, CpuIdLeafsList &ll); + void readCpuTree(const xml::ElementNode &elmCpu, CpuList &ll); + void readSerialPorts(const xml::ElementNode &elmUART, SerialPortsList &ll); + void readParallelPorts(const xml::ElementNode &elmLPT, ParallelPortsList &ll); + void readAudioAdapter(const xml::ElementNode &elmAudioAdapter, AudioAdapter &aa); + void readGuestProperties(const xml::ElementNode &elmGuestProperties, Hardware &hw); + void readStorageControllerAttributes(const xml::ElementNode &elmStorageController, StorageController &sctl); + void readHardware(const xml::ElementNode &elmHardware, Hardware &hw); + void readHardDiskAttachments_pre1_7(const xml::ElementNode &elmHardDiskAttachments, Storage &strg); + void readStorageControllers(const xml::ElementNode &elmStorageControllers, Storage &strg); + void readDVDAndFloppies_pre1_9(const xml::ElementNode &elmHardware, Storage &strg); + void readTeleporter(const xml::ElementNode &elmTeleporter, MachineUserData &userData); + void readDebugging(const xml::ElementNode &elmDbg, Debugging &dbg); + void readAutostart(const xml::ElementNode &elmAutostart, Autostart &autostrt); + void readRecordingSettings(const xml::ElementNode &elmRecording, uint32_t cMonitors, RecordingSettings &recording); + void readGroups(const xml::ElementNode &elmGroups, StringsList &llGroups); + bool readSnapshot(const com::Guid &curSnapshotUuid, const xml::ElementNode &elmSnapshot, Snapshot &snap); + void convertOldOSType_pre1_5(com::Utf8Str &str); + void readMachine(const xml::ElementNode &elmMachine); + void readMachineEncrypted(const xml::ElementNode &elmMachine, PCVBOXCRYPTOIF pCryptoIf, const char *pszPassword); + + void buildHardwareXML(xml::ElementNode &elmParent, const Hardware &hw, uint32_t fl, std::list<xml::ElementNode*> *pllElementsWithUuidAttributes); + void buildNetworkXML(NetworkAttachmentType_T mode, bool fEnabled, xml::ElementNode &elmParent, const NetworkAdapter &nic); + void buildStorageControllersXML(xml::ElementNode &elmParent, + const Storage &st, + bool fSkipRemovableMedia, + std::list<xml::ElementNode*> *pllElementsWithUuidAttributes); + void buildDebuggingXML(xml::ElementNode &elmParent, const Debugging &dbg); + void buildAutostartXML(xml::ElementNode &elmParent, const Autostart &autostrt); + void buildRecordingXML(xml::ElementNode &elmParent, const RecordingSettings &recording); + void buildGroupsXML(xml::ElementNode &elmParent, const StringsList &llGroups); + void buildSnapshotXML(xml::ElementNode &elmParent, const Snapshot &snap); + + void buildMachineEncryptedXML(xml::ElementNode &elmMachine, + uint32_t fl, + std::list<xml::ElementNode*> *pllElementsWithUuidAttributes, + PCVBOXCRYPTOIF pCryptoIf, + const char *pszPassword); + + void bumpSettingsVersionIfNeeded(); +}; + +} // namespace settings + + +#endif /* !VBOX_INCLUDED_settings_h */ diff --git a/include/VBox/shflsvc.h b/include/VBox/shflsvc.h new file mode 100644 index 00000000..725eae76 --- /dev/null +++ b/include/VBox/shflsvc.h @@ -0,0 +1,2151 @@ +/** @file + * Shared Folders - Common header for host service and guest clients. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_shflsvc_h +#define VBOX_INCLUDED_shflsvc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef IN_MODULE +# include <VBox/VMMDevCoreTypes.h> +# include <VBox/VBoxGuestCoreTypes.h> +#endif +#include <iprt/string.h> +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <iprt/fs.h> +#include <iprt/assert.h> +#include <iprt/errcore.h> +#if defined(IN_RING3) || (defined(IN_RING0) && defined(RT_OS_DARWIN)) +# include <iprt/mem.h> +#endif +#include <iprt/utf16.h> + + + +/** @defgroup grp_vbox_shfl Shared Folder Interface Definition. + * + * Structures shared between guest and the service can be relocated and use + * offsets to point to variable length parts. + * + * Shared folders protocol works with handles. Before doing any action on a + * file system object, one have to obtain the object handle via a SHFL_FN_CREATE + * request. A handle must be closed with SHFL_FN_CLOSE. + * + * @{ + */ + +/** @name Some bit flag manipulation macros. + * @{ */ +#ifndef BIT_FLAG +#define BIT_FLAG(__Field,__Flag) ((__Field) & (__Flag)) +#endif + +#ifndef BIT_FLAG_SET +#define BIT_FLAG_SET(__Field,__Flag) ((__Field) |= (__Flag)) +#endif + +#ifndef BIT_FLAG_CLEAR +#define BIT_FLAG_CLEAR(__Field,__Flag) ((__Field) &= ~(__Flag)) +#endif +/** @} */ + + +/** @name Shared Folders service functions. (guest) + * @{ + */ +/** Query mappings changes. + * @note Description is currently misleading, it will always return all + * current mappings with SHFL_MS_NEW status. Only modification is the + * SHFL_MF_AUTOMOUNT flag that causes filtering out non-auto mounts. */ +#define SHFL_FN_QUERY_MAPPINGS (1) +/** Query the name of a map. */ +#define SHFL_FN_QUERY_MAP_NAME (2) +/** Open/create object. */ +#define SHFL_FN_CREATE (3) +/** Close object handle. */ +#define SHFL_FN_CLOSE (4) +/** Read object content. */ +#define SHFL_FN_READ (5) +/** Write new object content. */ +#define SHFL_FN_WRITE (6) +/** Lock/unlock a range in the object. */ +#define SHFL_FN_LOCK (7) +/** List object content. */ +#define SHFL_FN_LIST (8) +/** Query/set object information. */ +#define SHFL_FN_INFORMATION (9) +/** Remove object */ +#define SHFL_FN_REMOVE (11) +/** Map folder (legacy) */ +#define SHFL_FN_MAP_FOLDER_OLD (12) +/** Unmap folder */ +#define SHFL_FN_UNMAP_FOLDER (13) +/** Rename object (possibly moving it to another directory) */ +#define SHFL_FN_RENAME (14) +/** Flush file */ +#define SHFL_FN_FLUSH (15) +/** @todo macl, a description, please. */ +#define SHFL_FN_SET_UTF8 (16) +/** Map folder */ +#define SHFL_FN_MAP_FOLDER (17) +/** Read symlink destination. + * @since VBox 4.0 */ +#define SHFL_FN_READLINK (18) /**< @todo rename to SHFL_FN_READ_LINK (see struct capitalization) */ +/** Create symlink. + * @since VBox 4.0 */ +#define SHFL_FN_SYMLINK (19) +/** Ask host to show symlinks + * @since VBox 4.0 */ +#define SHFL_FN_SET_SYMLINKS (20) +/** Query information about a map. + * @since VBox 6.0 */ +#define SHFL_FN_QUERY_MAP_INFO (21) +/** Wait for changes to the mappings. + * @since VBox 6.0 */ +#define SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES (22) +/** Cancel all waits for changes to the mappings for the calling client. + * The wait calls will return VERR_CANCELLED. + * @since VBox 6.0 */ +#define SHFL_FN_CANCEL_MAPPINGS_CHANGES_WAITS (23) +/** Sets the file size. + * @since VBox 6.0 */ +#define SHFL_FN_SET_FILE_SIZE (24) +/** Queries supported features. + * @since VBox 6.0.6 */ +#define SHFL_FN_QUERY_FEATURES (25) +/** Copies a file to another. + * @since VBox 6.0.6 */ +#define SHFL_FN_COPY_FILE (26) +/** Copies part of a file to another. + * @since VBox 6.0.6 */ +#define SHFL_FN_COPY_FILE_PART (27) +/** Close handle to (optional) and remove object by path. + * This function is tailored for Windows guests. + * @since VBox 6.0.8 */ +#define SHFL_FN_CLOSE_AND_REMOVE (28) +/** Set the host error code style. + * This is for more efficiently getting the correct error status when the host + * and guest OS types differs and it won't happen naturally. + * @since VBox 6.0.10 */ +#define SHFL_FN_SET_ERROR_STYLE (29) +/** The last function number. */ +#define SHFL_FN_LAST SHFL_FN_SET_ERROR_STYLE +/** @} */ + + +/** @name Shared Folders service functions. (host) + * @{ + */ +/** Add shared folder mapping. */ +#define SHFL_FN_ADD_MAPPING (1) +/** Remove shared folder mapping. */ +#define SHFL_FN_REMOVE_MAPPING (2) +/** Set the led status light address. */ +#define SHFL_FN_SET_STATUS_LED (3) +/** Allow the guest to create symbolic links + * @since VBox 4.0 */ +#define SHFL_FN_ALLOW_SYMLINKS_CREATE (4) +/** @} */ + + +/** Root handle for a mapping. Root handles are unique. + * + * @note Function parameters structures consider the root handle as 32 bit + * value. If the typedef will be changed, then function parameters must be + * changed accordingly. All those parameters are marked with SHFLROOT in + * comments. + */ +typedef uint32_t SHFLROOT; + +/** NIL shared folder root handle. */ +#define SHFL_ROOT_NIL ((SHFLROOT)~0) + + +/** A shared folders handle for an opened object. */ +typedef uint64_t SHFLHANDLE; + +#define SHFL_HANDLE_NIL ((SHFLHANDLE)~0LL) +#define SHFL_HANDLE_ROOT ((SHFLHANDLE)0LL) + +/** Hardcoded maximum length (in chars) of a shared folder name. */ +#define SHFL_MAX_LEN (256) +/** Hardcoded maximum number of shared folder mapping available to the guest. */ +#define SHFL_MAX_MAPPINGS (64) + + +/** @name Shared Folders strings. They can be either UTF-8 or UTF-16. + * @{ + */ + +/** + * Shared folder string buffer structure. + */ +typedef struct _SHFLSTRING +{ + /** Allocated size of the String member in bytes. */ + uint16_t u16Size; + + /** Length of string without trailing nul in bytes. */ + uint16_t u16Length; + + /** UTF-8 or UTF-16 string. Nul terminated. */ + union + { +#if 1 + char ach[1]; /**< UTF-8 but with a type that makes some more sense. */ + uint8_t utf8[1]; + RTUTF16 utf16[1]; + uint16_t ucs2[1]; /**< misnomer, use utf16. */ +#else + uint8_t utf8[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + RTUTF16 utf16[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + RTUTF16 ucs2[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; /**< misnomer, use utf16. */ +#endif + } String; +} SHFLSTRING; +AssertCompileSize(RTUTF16, 2); +AssertCompileSize(SHFLSTRING, 6); +AssertCompileMemberOffset(SHFLSTRING, String, 4); +/** The size of SHFLSTRING w/o the string part. */ +#define SHFLSTRING_HEADER_SIZE 4 +AssertCompileMemberOffset(SHFLSTRING, String, SHFLSTRING_HEADER_SIZE); + +/** Pointer to a shared folder string buffer. */ +typedef SHFLSTRING *PSHFLSTRING; +/** Pointer to a const shared folder string buffer. */ +typedef const SHFLSTRING *PCSHFLSTRING; + +/** Calculate size of the string. */ +DECLINLINE(uint32_t) ShflStringSizeOfBuffer(PCSHFLSTRING pString) +{ + return pString ? (uint32_t)(SHFLSTRING_HEADER_SIZE + pString->u16Size) : 0; +} + +DECLINLINE(uint32_t) ShflStringLength(PCSHFLSTRING pString) +{ + return pString ? pString->u16Length : 0; +} + +DECLINLINE(PSHFLSTRING) ShflStringInitBuffer(void *pvBuffer, uint32_t u32Size) +{ + PSHFLSTRING pString = NULL; + const uint32_t u32HeaderSize = SHFLSTRING_HEADER_SIZE; + + /* + * Check that the buffer size is big enough to hold a zero sized string + * and is not too big to fit into 16 bit variables. + */ + if (u32Size >= u32HeaderSize && u32Size - u32HeaderSize <= 0xFFFF) + { + pString = (PSHFLSTRING)pvBuffer; + pString->u16Size = (uint16_t)(u32Size - u32HeaderSize); + pString->u16Length = 0; + if (pString->u16Size >= sizeof(pString->String.ucs2[0])) + pString->String.ucs2[0] = 0; + else if (pString->u16Size >= sizeof(pString->String.utf8[0])) + pString->String.utf8[0] = 0; + } + + return pString; +} + +/** + * Helper for copying one string into another. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW and pDst->u16Length set to source length. + * @param pDst The destination string. + * @param pSrc The source string. + * @param cbTerm The size of the string terminator. + */ +DECLINLINE(int) ShflStringCopy(PSHFLSTRING pDst, PCSHFLSTRING pSrc, size_t cbTerm) +{ + int rc = VINF_SUCCESS; + if (pDst->u16Size >= pSrc->u16Length + cbTerm) + { + memcpy(&pDst->String, &pSrc->String, pSrc->u16Length); + switch (cbTerm) + { + default: + case 2: pDst->String.ach[pSrc->u16Length + 1] = '\0'; RT_FALL_THROUGH(); + case 1: pDst->String.ach[pSrc->u16Length + 0] = '\0'; break; + case 0: break; + } + } + else + rc = VERR_BUFFER_OVERFLOW; + pDst->u16Length = pSrc->u16Length; + return rc; +} + +#if defined(IN_RING3) \ + || (defined(IN_RING0) && defined(RT_OS_DARWIN)) + +/** + * Duplicates a string using RTMemAlloc as allocator. + * + * @returns Copy, NULL if out of memory. + * @param pSrc The source string. + */ +DECLINLINE(PSHFLSTRING) ShflStringDup(PCSHFLSTRING pSrc) +{ + PSHFLSTRING pDst = (PSHFLSTRING)RTMemAlloc(SHFLSTRING_HEADER_SIZE + pSrc->u16Size); + if (pDst) + { + pDst->u16Length = pSrc->u16Length; + pDst->u16Size = pSrc->u16Size; + memcpy(&pDst->String, &pSrc->String, pSrc->u16Size); + } + return pDst; +} + +/** + * Duplicates a UTF-16 string using RTMemAlloc as allocator. + * + * The returned string will be using UTF-16 encoding too. + * + * @returns Pointer to copy on success - pass to RTMemFree to free. + * NULL if out of memory. + * @param pwszSrc The source string. Encoding is not checked. + */ +DECLINLINE(PSHFLSTRING) ShflStringDupUtf16(PCRTUTF16 pwszSrc) +{ + size_t cwcSrc = RTUtf16Len(pwszSrc); + if (cwcSrc < UINT16_MAX / sizeof(RTUTF16)) + { + PSHFLSTRING pDst = (PSHFLSTRING)RTMemAlloc(SHFLSTRING_HEADER_SIZE + (cwcSrc + 1) * sizeof(RTUTF16)); + if (pDst) + { + pDst->u16Length = (uint16_t)(cwcSrc * sizeof(RTUTF16)); + pDst->u16Size = (uint16_t)((cwcSrc + 1) * sizeof(RTUTF16)); + memcpy(&pDst->String, pwszSrc, (cwcSrc + 1) * sizeof(RTUTF16)); + return pDst; + } + } + AssertFailed(); + return NULL; +} + +/** + * Duplicates a UTF-8 string using RTMemAlloc as allocator. + * + * The returned string will be using UTF-8 encoding too. + * + * @returns Pointer to copy on success - pass to RTMemFree to free. + * NULL if out of memory. + * @param pszSrc The source string. Encoding is not checked. + */ +DECLINLINE(PSHFLSTRING) ShflStringDupUtf8(const char *pszSrc) +{ + size_t cchSrc = strlen(pszSrc); + if (cchSrc < UINT16_MAX) + { + PSHFLSTRING pDst = (PSHFLSTRING)RTMemAlloc(SHFLSTRING_HEADER_SIZE + cchSrc + 1); + if (pDst) + { + pDst->u16Length = (uint16_t)cchSrc; + pDst->u16Size = (uint16_t)(cchSrc + 1); + memcpy(&pDst->String, pszSrc, cchSrc + 1); + return pDst; + } + } + AssertFailed(); + return NULL; +} + +/** + * Creates a UTF-16 duplicate of the UTF-8 string @a pszSrc using RTMemAlloc as + * allocator. + * + * @returns Pointer to copy on success - pass to RTMemFree to free. + * NULL if out of memory or invalid UTF-8 encoding. + * @param pszSrc The source string. + */ +DECLINLINE(PSHFLSTRING) ShflStringDupUtf8AsUtf16(const char *pszSrc) +{ + size_t cwcConversion = 0; + int rc = RTStrCalcUtf16LenEx(pszSrc, RTSTR_MAX, &cwcConversion); + if ( RT_SUCCESS(rc) + && cwcConversion < UINT16_MAX / sizeof(RTUTF16)) + { + PSHFLSTRING pDst = (PSHFLSTRING)RTMemAlloc(SHFLSTRING_HEADER_SIZE + (cwcConversion + 1) * sizeof(RTUTF16)); + if (pDst) + { + PRTUTF16 pwszDst = pDst->String.ucs2; + pDst->u16Size = (uint16_t)((cwcConversion + 1) * sizeof(RTUTF16)); + rc = RTStrToUtf16Ex(pszSrc, RTSTR_MAX, &pwszDst, cwcConversion + 1, &cwcConversion); + AssertRC(rc); + if (RT_SUCCESS(rc)) + { + pDst->u16Length = (uint16_t)(cwcConversion * sizeof(RTUTF16)); + return pDst; + } + RTMemFree(pDst); + } + } + AssertMsgFailed(("rc=%Rrc cwcConversion=%#x\n", rc, cwcConversion)); + return NULL; +} + +/** + * Copies a UTF-8 string to a buffer as UTF-16. + * + * @returns IPRT status code. + * @param pDst The destination buffer. + * @param pszSrc The source string. + * @param cchSrc The source string length, or RTSTR_MAX. + */ +DECLINLINE(int) ShflStringCopyUtf8AsUtf16(PSHFLSTRING pDst, const char *pszSrc, size_t cchSrc) +{ + int rc; + size_t cwcDst = 0; + if (pDst->u16Size >= sizeof(RTUTF16)) + { + PRTUTF16 pwszDst = pDst->String.utf16; + rc = RTStrToUtf16Ex(pszSrc, cchSrc, &pwszDst, pDst->u16Size / sizeof(RTUTF16), &cwcDst); + } + else + { + RTStrCalcUtf16LenEx(pszSrc, cchSrc, &cwcDst); + rc = VERR_BUFFER_OVERFLOW; + } + pDst->u16Length = (uint16_t)(cwcDst * sizeof(RTUTF16)); + return rc != VERR_BUFFER_OVERFLOW || cwcDst < UINT16_MAX / sizeof(RTUTF16) ? rc : VERR_TOO_MUCH_DATA; +} + +/** + * Copies a UTF-8 string buffer to another buffer as UTF-16 + * + * @returns IPRT status code. + * @param pDst The destination buffer (UTF-16). + * @param pSrc The source buffer (UTF-8). + */ +DECLINLINE(int) ShflStringCopyUtf8BufAsUtf16(PSHFLSTRING pDst, PCSHFLSTRING pSrc) +{ + return ShflStringCopyUtf8AsUtf16(pDst, pSrc->String.ach, pSrc->u16Length); +} + +/** + * Copies a UTF-16 string to a buffer as UTF-8 + * + * @returns IPRT status code. + * @param pDst The destination buffer. + * @param pwszSrc The source string. + * @param cwcSrc The source string length, or RTSTR_MAX. + */ +DECLINLINE(int) ShflStringCopyUtf16AsUtf8(PSHFLSTRING pDst, PCRTUTF16 pwszSrc, size_t cwcSrc) +{ + int rc; + size_t cchDst = 0; + if (pDst->u16Size > 0) + { + char *pszDst = pDst->String.ach; + rc = RTUtf16ToUtf8Ex(pwszSrc, cwcSrc, &pszDst, pDst->u16Size, &cchDst); + } + else + { + RTUtf16CalcUtf8LenEx(pwszSrc, cwcSrc, &cchDst); + rc = VERR_BUFFER_OVERFLOW; + } + pDst->u16Length = (uint16_t)cchDst; + return rc != VERR_BUFFER_OVERFLOW || cchDst < UINT16_MAX ? rc : VERR_TOO_MUCH_DATA; +} + +/** + * Copies a UTF-16 string buffer to another buffer as UTF-8 + * + * @returns IPRT status code. + * @param pDst The destination buffer (UTF-8). + * @param pSrc The source buffer (UTF-16). + */ +DECLINLINE(int) ShflStringCopyUtf16BufAsUtf8(PSHFLSTRING pDst, PCSHFLSTRING pSrc) +{ + return ShflStringCopyUtf16AsUtf8(pDst, pSrc->String.utf16, pSrc->u16Length / sizeof(RTUTF16)); +} + +#endif /* IN_RING3 */ + +/** + * Validates a HGCM string output parameter. + * + * @returns true if valid, false if not. + * + * @param pString The string buffer pointer. + * @param cbBuf The buffer size from the parameter. + */ +DECLINLINE(bool) ShflStringIsValidOut(PCSHFLSTRING pString, uint32_t cbBuf) +{ + if (RT_LIKELY(cbBuf > RT_UOFFSETOF(SHFLSTRING, String))) + if (RT_LIKELY((uint32_t)pString->u16Size + RT_UOFFSETOF(SHFLSTRING, String) <= cbBuf)) + if (RT_LIKELY(pString->u16Length < pString->u16Size)) + return true; + return false; +} + +/** + * Validates a HGCM string input parameter. + * + * @returns true if valid, false if not. + * + * @param pString The string buffer pointer. + * @param cbBuf The buffer size from the parameter. + * @param fUtf8Not16 Set if UTF-8 encoding, clear if UTF-16 encoding. + */ +DECLINLINE(bool) ShflStringIsValidIn(PCSHFLSTRING pString, uint32_t cbBuf, bool fUtf8Not16) +{ + int rc; + if (RT_LIKELY(cbBuf > RT_UOFFSETOF(SHFLSTRING, String))) + { + if (RT_LIKELY((uint32_t)pString->u16Size + RT_UOFFSETOF(SHFLSTRING, String) <= cbBuf)) + { + if (fUtf8Not16) + { + /* UTF-8: */ + if (RT_LIKELY(pString->u16Length < pString->u16Size)) + { + rc = RTStrValidateEncodingEx((const char *)&pString->String.utf8[0], pString->u16Length + 1, + RTSTR_VALIDATE_ENCODING_EXACT_LENGTH | RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); + if (RT_SUCCESS(rc)) + return true; + } + } + else + { + /* UTF-16: */ + if (RT_LIKELY(!(pString->u16Length & 1))) + { + if (RT_LIKELY((uint32_t)sizeof(RTUTF16) + pString->u16Length <= pString->u16Size)) + { + rc = RTUtf16ValidateEncodingEx(&pString->String.ucs2[0], pString->u16Length / 2 + 1, + RTSTR_VALIDATE_ENCODING_EXACT_LENGTH + | RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); + if (RT_SUCCESS(rc)) + return true; + } + } + } + } + } + return false; +} + +/** + * Validates an optional HGCM string input parameter. + * + * @returns true if valid, false if not. + * + * @param pString The string buffer pointer. Can be NULL. + * @param cbBuf The buffer size from the parameter. + * @param fUtf8Not16 Set if UTF-8 encoding, clear if UTF-16 encoding. + */ +DECLINLINE(bool) ShflStringIsValidOrNullIn(PCSHFLSTRING pString, uint32_t cbBuf, bool fUtf8Not16) +{ + if (pString) + return ShflStringIsValidIn(pString, cbBuf, fUtf8Not16); + if (RT_LIKELY(cbBuf == 0)) + return true; + return false; +} + +/** Macro for passing as string as a HGCM parmeter (pointer) */ +#define SHFLSTRING_TO_HGMC_PARAM(a_pParam, a_pString) \ + do { \ + (a_pParam)->type = VBOX_HGCM_SVC_PARM_PTR; \ + (a_pParam)->u.pointer.addr = (a_pString); \ + (a_pParam)->u.pointer.size = ShflStringSizeOfBuffer(a_pString); \ + } while (0) + +/** @} */ + + +/** + * The available additional information in a SHFLFSOBJATTR object. + */ +typedef enum SHFLFSOBJATTRADD +{ + /** No additional information is available / requested. */ + SHFLFSOBJATTRADD_NOTHING = 1, + /** The additional unix attributes (SHFLFSOBJATTR::u::Unix) are + * available / requested. */ + SHFLFSOBJATTRADD_UNIX, + /** The additional extended attribute size (SHFLFSOBJATTR::u::EASize) is + * available / requested. */ + SHFLFSOBJATTRADD_EASIZE, + /** The last valid item (inclusive). + * The valid range is SHFLFSOBJATTRADD_NOTHING thru + * SHFLFSOBJATTRADD_LAST. */ + SHFLFSOBJATTRADD_LAST = SHFLFSOBJATTRADD_EASIZE, + + /** The usual 32-bit hack. */ + SHFLFSOBJATTRADD_32BIT_SIZE_HACK = 0x7fffffff +} SHFLFSOBJATTRADD; + + +/* Assert sizes of the IRPT types we're using below. */ +AssertCompileSize(RTFMODE, 4); +AssertCompileSize(RTFOFF, 8); +AssertCompileSize(RTINODE, 8); +AssertCompileSize(RTTIMESPEC, 8); +AssertCompileSize(RTDEV, 4); +AssertCompileSize(RTUID, 4); + +/** + * Shared folder filesystem object attributes. + */ +#pragma pack(1) +typedef struct SHFLFSOBJATTR +{ + /** Mode flags (st_mode). RTFS_UNIX_*, RTFS_TYPE_*, and RTFS_DOS_*. + * @remarks We depend on a number of RTFS_ defines to remain unchanged. + * Fortuntately, these are depending on windows, dos and unix + * standard values, so this shouldn't be much of a pain. */ + RTFMODE fMode; + + /** The additional attributes available. */ + SHFLFSOBJATTRADD enmAdditional; + + /** + * Additional attributes. + * + * Unless explicitly specified to an API, the API can provide additional + * data as it is provided by the underlying OS. + */ + union SHFLFSOBJATTRUNION + { + /** Additional Unix Attributes + * These are available when SHFLFSOBJATTRADD is set in fUnix. + */ + struct SHFLFSOBJATTRUNIX + { + /** The user owning the filesystem object (st_uid). + * This field is ~0U if not supported. */ + RTUID uid; + + /** The group the filesystem object is assigned (st_gid). + * This field is ~0U if not supported. */ + RTGID gid; + + /** Number of hard links to this filesystem object (st_nlink). + * This field is 1 if the filesystem doesn't support hardlinking or + * the information isn't available. + */ + uint32_t cHardlinks; + + /** The device number of the device which this filesystem object resides on (st_dev). + * This field is 0 if this information is not available. */ + RTDEV INodeIdDevice; + + /** The unique identifier (within the filesystem) of this filesystem object (st_ino). + * Together with INodeIdDevice, this field can be used as a OS wide unique id + * when both their values are not 0. + * This field is 0 if the information is not available. */ + RTINODE INodeId; + + /** User flags (st_flags). + * This field is 0 if this information is not available. */ + uint32_t fFlags; + + /** The current generation number (st_gen). + * This field is 0 if this information is not available. */ + uint32_t GenerationId; + + /** The device number of a character or block device type object (st_rdev). + * This field is 0 if the file isn't of a character or block device type and + * when the OS doesn't subscribe to the major+minor device idenfication scheme. */ + RTDEV Device; + } Unix; + + /** + * Extended attribute size. + */ + struct SHFLFSOBJATTREASIZE + { + /** Size of EAs. */ + RTFOFF cb; + } EASize; + } u; +} SHFLFSOBJATTR; +#pragma pack() +AssertCompileSize(SHFLFSOBJATTR, 44); +/** Pointer to a shared folder filesystem object attributes structure. */ +typedef SHFLFSOBJATTR *PSHFLFSOBJATTR; +/** Pointer to a const shared folder filesystem object attributes structure. */ +typedef const SHFLFSOBJATTR *PCSHFLFSOBJATTR; + + +/** + * Filesystem object information structure. + */ +#pragma pack(1) +typedef struct SHFLFSOBJINFO +{ + /** Logical size (st_size). + * For normal files this is the size of the file. + * For symbolic links, this is the length of the path name contained + * in the symbolic link. + * For other objects this fields needs to be specified. + */ + RTFOFF cbObject; + + /** Disk allocation size (st_blocks * DEV_BSIZE). */ + RTFOFF cbAllocated; + + /** Time of last access (st_atime). + * @remarks Here (and other places) we depend on the IPRT timespec to + * remain unchanged. */ + RTTIMESPEC AccessTime; + + /** Time of last data modification (st_mtime). */ + RTTIMESPEC ModificationTime; + + /** Time of last status change (st_ctime). + * If not available this is set to ModificationTime. + */ + RTTIMESPEC ChangeTime; + + /** Time of file birth (st_birthtime). + * If not available this is set to ChangeTime. + */ + RTTIMESPEC BirthTime; + + /** Attributes. */ + SHFLFSOBJATTR Attr; + +} SHFLFSOBJINFO; +#pragma pack() +AssertCompileSize(SHFLFSOBJINFO, 92); +/** Pointer to a shared folder filesystem object information structure. */ +typedef SHFLFSOBJINFO *PSHFLFSOBJINFO; +/** Pointer to a const shared folder filesystem object information + * structure. */ +typedef const SHFLFSOBJINFO *PCSHFLFSOBJINFO; + + +/** + * Copy file system objinfo from IPRT to shared folder format. + * + * @param pDst The shared folder structure. + * @param pSrc The IPRT structure. + */ +DECLINLINE(void) vbfsCopyFsObjInfoFromIprt(PSHFLFSOBJINFO pDst, PCRTFSOBJINFO pSrc) +{ + pDst->cbObject = pSrc->cbObject; + pDst->cbAllocated = pSrc->cbAllocated; + pDst->AccessTime = pSrc->AccessTime; + pDst->ModificationTime = pSrc->ModificationTime; + 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) + { + default: + case RTFSOBJATTRADD_NOTHING: + pDst->Attr.enmAdditional = SHFLFSOBJATTRADD_NOTHING; + break; + + case RTFSOBJATTRADD_UNIX: + pDst->Attr.enmAdditional = SHFLFSOBJATTRADD_UNIX; + pDst->Attr.u.Unix.uid = pSrc->Attr.u.Unix.uid; + pDst->Attr.u.Unix.gid = pSrc->Attr.u.Unix.gid; + pDst->Attr.u.Unix.cHardlinks = pSrc->Attr.u.Unix.cHardlinks; + pDst->Attr.u.Unix.INodeIdDevice = pSrc->Attr.u.Unix.INodeIdDevice; + pDst->Attr.u.Unix.INodeId = pSrc->Attr.u.Unix.INodeId; + pDst->Attr.u.Unix.fFlags = pSrc->Attr.u.Unix.fFlags; + pDst->Attr.u.Unix.GenerationId = pSrc->Attr.u.Unix.GenerationId; + pDst->Attr.u.Unix.Device = pSrc->Attr.u.Unix.Device; + break; + + case RTFSOBJATTRADD_EASIZE: + pDst->Attr.enmAdditional = SHFLFSOBJATTRADD_EASIZE; + pDst->Attr.u.EASize.cb = pSrc->Attr.u.EASize.cb; + break; + } +} + + +/** Result of an open/create request. + * Along with handle value the result code + * identifies what has happened while + * trying to open the object. + */ +typedef enum _SHFLCREATERESULT +{ + SHFL_NO_RESULT, + /** Specified path does not exist. */ + SHFL_PATH_NOT_FOUND, + /** Path to file exists, but the last component does not. */ + SHFL_FILE_NOT_FOUND, + /** File already exists and either has been opened or not. */ + SHFL_FILE_EXISTS, + /** New file was created. */ + SHFL_FILE_CREATED, + /** Existing file was replaced or overwritten. */ + SHFL_FILE_REPLACED, + /** Blow the type up to 32-bit. */ + SHFL_32BIT_HACK = 0x7fffffff +} SHFLCREATERESULT; +AssertCompile(SHFL_NO_RESULT == 0); +AssertCompileSize(SHFLCREATERESULT, 4); + + +/** @name Open/create flags. + * @{ + */ + +/** No flags. Initialization value. */ +#define SHFL_CF_NONE (0x00000000) + +/** Lookup only the object, do not return a handle. All other flags are ignored. */ +#define SHFL_CF_LOOKUP (0x00000001) + +/** Open parent directory of specified object. + * Useful for the corresponding Windows FSD flag + * and for opening paths like \\dir\\*.* to search the 'dir'. + * @todo possibly not needed??? + */ +#define SHFL_CF_OPEN_TARGET_DIRECTORY (0x00000002) + +/** Create/open a directory. */ +#define SHFL_CF_DIRECTORY (0x00000004) + +/** Open/create action to do if object exists + * and if the object does not exists. + * REPLACE file means atomically DELETE and CREATE. + * OVERWRITE file means truncating the file to 0 and + * setting new size. + * When opening an existing directory REPLACE and OVERWRITE + * actions are considered invalid, and cause returning + * FILE_EXISTS with NIL handle. + */ +#define SHFL_CF_ACT_MASK_IF_EXISTS (0x000000F0) +#define SHFL_CF_ACT_MASK_IF_NEW (0x00000F00) + +/** What to do if object exists. */ +#define SHFL_CF_ACT_OPEN_IF_EXISTS (0x00000000) +#define SHFL_CF_ACT_FAIL_IF_EXISTS (0x00000010) +#define SHFL_CF_ACT_REPLACE_IF_EXISTS (0x00000020) +#define SHFL_CF_ACT_OVERWRITE_IF_EXISTS (0x00000030) + +/** What to do if object does not exist. */ +#define SHFL_CF_ACT_CREATE_IF_NEW (0x00000000) +#define SHFL_CF_ACT_FAIL_IF_NEW (0x00000100) + +/** Read/write requested access for the object. */ +#define SHFL_CF_ACCESS_MASK_RW (0x00003000) + +/** No access requested. */ +#define SHFL_CF_ACCESS_NONE (0x00000000) +/** Read access requested. */ +#define SHFL_CF_ACCESS_READ (0x00001000) +/** Write access requested. */ +#define SHFL_CF_ACCESS_WRITE (0x00002000) +/** Read/Write access requested. */ +#define SHFL_CF_ACCESS_READWRITE (SHFL_CF_ACCESS_READ | SHFL_CF_ACCESS_WRITE) + +/** Requested share access for the object. */ +#define SHFL_CF_ACCESS_MASK_DENY (0x0000C000) + +/** Allow any access. */ +#define SHFL_CF_ACCESS_DENYNONE (0x00000000) +/** Do not allow read. */ +#define SHFL_CF_ACCESS_DENYREAD (0x00004000) +/** Do not allow write. */ +#define SHFL_CF_ACCESS_DENYWRITE (0x00008000) +/** Do not allow access. */ +#define SHFL_CF_ACCESS_DENYALL (SHFL_CF_ACCESS_DENYREAD | SHFL_CF_ACCESS_DENYWRITE) + +/** Requested access to attributes of the object. */ +#define SHFL_CF_ACCESS_MASK_ATTR (0x00030000) + +/** No access requested. */ +#define SHFL_CF_ACCESS_ATTR_NONE (0x00000000) +/** Read access requested. */ +#define SHFL_CF_ACCESS_ATTR_READ (0x00010000) +/** Write access requested. */ +#define SHFL_CF_ACCESS_ATTR_WRITE (0x00020000) +/** Read/Write access requested. */ +#define SHFL_CF_ACCESS_ATTR_READWRITE (SHFL_CF_ACCESS_ATTR_READ | SHFL_CF_ACCESS_ATTR_WRITE) + +/** The file is opened in append mode. Ignored if SHFL_CF_ACCESS_WRITE is not set. */ +#define SHFL_CF_ACCESS_APPEND (0x00040000) + +/** @} */ + +#pragma pack(1) +typedef struct _SHFLCREATEPARMS +{ + /* Returned handle of opened object. */ + SHFLHANDLE Handle; + + /* Returned result of the operation */ + SHFLCREATERESULT Result; + + /* SHFL_CF_* */ + uint32_t CreateFlags; + + /* Attributes of object to create and + * returned actual attributes of opened/created object. + */ + SHFLFSOBJINFO Info; + +} SHFLCREATEPARMS; +#pragma pack() + +typedef SHFLCREATEPARMS *PSHFLCREATEPARMS; + + +/** @name Shared Folders mappings. + * @{ + */ + +/** The mapping has been added since last query. */ +#define SHFL_MS_NEW (1) +/** The mapping has been deleted since last query. */ +#define SHFL_MS_DELETED (2) + +typedef struct _SHFLMAPPING +{ + /** Mapping status. + * @note Currently always set to SHFL_MS_NEW. */ + uint32_t u32Status; + /** Root handle. */ + SHFLROOT root; +} SHFLMAPPING; +/** Pointer to a SHFLMAPPING structure. */ +typedef SHFLMAPPING *PSHFLMAPPING; + +/** @} */ + + +/** @name Shared Folder directory information + * @{ + */ + +typedef struct _SHFLDIRINFO +{ + /** Full information about the object. */ + SHFLFSOBJINFO Info; + /** The length of the short field (number of RTUTF16 chars). + * It is 16-bit for reasons of alignment. */ + uint16_t cucShortName; + /** The short name for 8.3 compatibility. + * Empty string if not available. + */ + RTUTF16 uszShortName[14]; + /** @todo malc, a description, please. */ + SHFLSTRING name; +} SHFLDIRINFO, *PSHFLDIRINFO; + + +/** + * Shared folder filesystem properties. + */ +typedef struct SHFLFSPROPERTIES +{ + /** The maximum size of a filesystem object name. + * This does not include the '\\0'. */ + uint32_t cbMaxComponent; + + /** True if the filesystem is remote. + * False if the filesystem is local. */ + bool fRemote; + + /** True if the filesystem is case sensitive. + * False if the filesystem is case insensitive. */ + bool fCaseSensitive; + + /** True if the filesystem is mounted read only. + * False if the filesystem is mounted read write. */ + bool fReadOnly; + + /** True if the filesystem can encode unicode object names. + * False if it can't. */ + bool fSupportsUnicode; + + /** True if the filesystem is compresses. + * False if it isn't or we don't know. */ + bool fCompressed; + + /** True if the filesystem compresses of individual files. + * False if it doesn't or we don't know. */ + bool fFileCompression; + + /** @todo more? */ +} SHFLFSPROPERTIES; +AssertCompileSize(SHFLFSPROPERTIES, 12); +/** Pointer to a shared folder filesystem properties structure. */ +typedef SHFLFSPROPERTIES *PSHFLFSPROPERTIES; +/** Pointer to a const shared folder filesystem properties structure. */ +typedef SHFLFSPROPERTIES const *PCSHFLFSPROPERTIES; + + +/** + * Copy file system properties from IPRT to shared folder format. + * + * @param pDst The shared folder structure. + * @param pSrc The IPRT structure. + */ +DECLINLINE(void) vbfsCopyFsPropertiesFromIprt(PSHFLFSPROPERTIES pDst, PCRTFSPROPERTIES pSrc) +{ + RT_ZERO(*pDst); /* zap the implicit padding. */ + pDst->cbMaxComponent = pSrc->cbMaxComponent; + pDst->fRemote = pSrc->fRemote; + pDst->fCaseSensitive = pSrc->fCaseSensitive; + pDst->fReadOnly = pSrc->fReadOnly; + pDst->fSupportsUnicode = pSrc->fSupportsUnicode; + pDst->fCompressed = pSrc->fCompressed; + pDst->fFileCompression = pSrc->fFileCompression; +} + + +typedef struct _SHFLVOLINFO +{ + RTFOFF ullTotalAllocationBytes; + RTFOFF ullAvailableAllocationBytes; + uint32_t ulBytesPerAllocationUnit; + uint32_t ulBytesPerSector; + uint32_t ulSerial; + SHFLFSPROPERTIES fsProperties; +} SHFLVOLINFO, *PSHFLVOLINFO; + +/** @} */ + + +/** @defgroup grp_vbox_shfl_params Function parameter structures. + * @{ + */ + +/** @name SHFL_FN_QUERY_MAPPINGS + * @{ + */ +/** Validation mask. Needs to be adjusted + * whenever a new SHFL_MF_ flag is added. */ +#define SHFL_MF_MASK (0x00000011) +/** UTF-16 enconded strings. */ +#define SHFL_MF_UCS2 (0x00000000) +/** Guest uses UTF8 strings, if not set then the strings are unicode (UCS2). */ +#define SHFL_MF_UTF8 (0x00000001) +/** Just handle the auto-mounted folders. */ +#define SHFL_MF_AUTOMOUNT (0x00000010) + +/** Parameters structure. */ +typedef struct _VBoxSFQueryMappings +{ + VBGLIOCHGCMCALL callInfo; + + /** 32bit, in: + * Flags describing various client needs. + */ + HGCMFunctionParameter flags; + + /** 32bit, in/out: + * Number of mappings the client expects. + * This is the number of elements in the + * mappings array. + */ + HGCMFunctionParameter numberOfMappings; + + /** pointer, in/out: + * Points to array of SHFLMAPPING structures. + */ + HGCMFunctionParameter mappings; + +} VBoxSFQueryMappings; + +/** Number of parameters */ +#define SHFL_CPARMS_QUERY_MAPPINGS (3) +/** @} */ + + +/** @name SHFL_FN_QUERY_MAP_NAME + * @{ + */ + +/** Parameters structure. */ +typedef struct _VBoxSFQueryMapName +{ + VBGLIOCHGCMCALL callInfo; + + /** 32bit, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** pointer, in/out: + * Points to SHFLSTRING buffer. + */ + HGCMFunctionParameter name; + +} VBoxSFQueryMapName; + +/** Number of parameters */ +#define SHFL_CPARMS_QUERY_MAP_NAME (2) +/** @} */ + + +/** @name SHFL_FN_MAP_FOLDER_OLD + * @{ + */ + +/** Parameters structure. */ +typedef struct _VBoxSFMapFolder_Old +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: + * Points to SHFLSTRING buffer. + */ + HGCMFunctionParameter path; + + /** pointer, out: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** pointer, in: RTUTF16 + * Path delimiter + */ + HGCMFunctionParameter delimiter; + +} VBoxSFMapFolder_Old; + +/** Number of parameters */ +#define SHFL_CPARMS_MAP_FOLDER_OLD (3) +/** @} */ + + +/** @name SHFL_FN_MAP_FOLDER + * @{ + */ + +/** SHFL_FN_MAP_FOLDER parameters. */ +typedef struct VBoxSFParmMapFolder +{ + /** pointer, in: SHFLSTRING with the name of the folder to map. */ + HGCMFunctionParameter pStrName; + /** value32, out: The root ID (SHFLROOT) of the mapping. */ + HGCMFunctionParameter id32Root; + /** value32, in: Path delimiter code point. */ + HGCMFunctionParameter uc32Delimiter; + /** value32, in: case senstive flag */ + HGCMFunctionParameter fCaseSensitive; +} VBoxSFParmMapFolder; + +/** Parameters structure. */ +typedef struct _VBoxSFMapFolder +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: + * Points to SHFLSTRING buffer. + */ + HGCMFunctionParameter path; + + /** pointer, out: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** pointer, in: RTUTF16 + * Path delimiter + */ + HGCMFunctionParameter delimiter; + + /** pointer, in: SHFLROOT + * Case senstive flag + */ + HGCMFunctionParameter fCaseSensitive; + +} VBoxSFMapFolder; + +/** Number of parameters */ +#define SHFL_CPARMS_MAP_FOLDER (4) +/** @} */ + + +/** @name SHFL_FN_UNMAP_FOLDER + * @{ + */ + +/** SHFL_FN_UNMAP_FOLDER parameters. */ +typedef struct VBoxSFParmUnmapFolder +{ + /** value32, in: SHFLROOT of the mapping to unmap */ + HGCMFunctionParameter id32Root; +} VBoxSFParmUnmapFolder; + +/** Parameters structure. */ +typedef struct _VBoxSFUnmapFolder +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + +} VBoxSFUnmapFolder; + +/** Number of parameters */ +#define SHFL_CPARMS_UNMAP_FOLDER (1) +/** @} */ + + +/** @name SHFL_FN_CREATE + * @{ + */ + +/** SHFL_FN_CREATE parameters. */ +typedef struct VBoxSFParmCreate +{ + /** value32, in: SHFLROOT + * Root handle of the mapping which name is queried. */ + HGCMFunctionParameter id32Root; + /** pointer, in: Points to SHFLSTRING buffer. */ + HGCMFunctionParameter pStrPath; + /** pointer, in/out: Points to SHFLCREATEPARMS buffer. */ + HGCMFunctionParameter pCreateParms; +} VBoxSFParmCreate; + +/** Parameters structure. */ +typedef struct _VBoxSFCreate +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** pointer, in: + * Points to SHFLSTRING buffer. + */ + HGCMFunctionParameter path; + + /** pointer, in/out: + * Points to SHFLCREATEPARMS buffer. + */ + HGCMFunctionParameter parms; + +} VBoxSFCreate; + +/** Number of parameters */ +#define SHFL_CPARMS_CREATE (3) +/** @} */ + + +/** @name SHFL_FN_CLOSE + * @{ + */ + +/** SHFL_FN_CLOSE parameters. */ +typedef struct VBoxSFParmClose +{ + /** value32, in: SHFLROOT of the mapping with the handle. */ + HGCMFunctionParameter id32Root; + /** value64, in: SHFLHANDLE of object to close. */ + HGCMFunctionParameter u64Handle; +} VBoxSFParmClose; + +/** Parameters structure. */ +typedef struct _VBoxSFClose +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + + /** value64, in: + * SHFLHANDLE of object to close. + */ + HGCMFunctionParameter handle; + +} VBoxSFClose; + +/** Number of parameters */ +#define SHFL_CPARMS_CLOSE (2) +/** @} */ + + +/** @name SHFL_FN_READ + * @{ + */ + +/** SHFL_FN_READ parameters. */ +typedef struct VBoxSFParmRead +{ + /** value32, in: SHFLROOT of the mapping with the handle. */ + HGCMFunctionParameter id32Root; + /** value64, in: SHFLHANDLE of object to read from . */ + HGCMFunctionParameter u64Handle; + /** value64, in: Offset to start reading from. */ + HGCMFunctionParameter off64Read; + /** value32, in/out: How much to try read / Actually read. */ + HGCMFunctionParameter cb32Read; + /** pointer, out: Buffer to return the data in. */ + HGCMFunctionParameter pBuf; +} VBoxSFParmRead; + +/** Parameters structure. */ +typedef struct _VBoxSFRead +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** value64, in: + * SHFLHANDLE of object to read from. + */ + HGCMFunctionParameter handle; + + /** value64, in: + * Offset to read from. + */ + HGCMFunctionParameter offset; + + /** value64, in/out: + * Bytes to read/How many were read. + */ + HGCMFunctionParameter cb; + + /** pointer, out: + * Buffer to place data to. + */ + HGCMFunctionParameter buffer; + +} VBoxSFRead; + +/** Number of parameters */ +#define SHFL_CPARMS_READ (5) +/** @} */ + + +/** @name SHFL_FN_WRITE + * @{ + */ + +/** SHFL_FN_WRITE parameters. */ +typedef struct VBoxSFParmWrite +{ + /** value32, in: SHFLROOT of the mapping with the handle. */ + HGCMFunctionParameter id32Root; + /** value64, in: SHFLHANDLE of object to write to. */ + HGCMFunctionParameter u64Handle; + /** value64, in/out: Offset to start writing at / New offset. + * @note The new offset isn't necessarily off + cb for files opened with + * SHFL_CF_ACCESS_APPEND since other parties (host programs, other VMs, + * other computers) could have extended the file since the last time the + * guest got a fresh size statistic. So, this helps the guest avoiding + * a stat call to check the actual size. */ + HGCMFunctionParameter off64Write; + /** value32, in/out: How much to try write / Actually written. */ + HGCMFunctionParameter cb32Write; + /** pointer, out: Buffer to return the data in. */ + HGCMFunctionParameter pBuf; +} VBoxSFParmWrite; + +/** Parameters structure. */ +typedef struct _VBoxSFWrite +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** value64, in: + * SHFLHANDLE of object to write to. + */ + HGCMFunctionParameter handle; + + /** value64, in/out: + * Offset to write to/New offset. + * @note The new offset isn't necessarily off + cb for files opened with + * SHFL_CF_ACCESS_APPEND since other parties (host programs, other VMs, + * other computers) could have extended the file since the last time the + * guest got a fresh size statistic. So, this helps the guest avoiding + * a stat call to check the actual size. + */ + HGCMFunctionParameter offset; + + /** value64, in/out: + * Bytes to write/How many were written. + */ + HGCMFunctionParameter cb; + + /** pointer, in: + * Data to write. + */ + HGCMFunctionParameter buffer; + +} VBoxSFWrite; + +/** Number of parameters */ +#define SHFL_CPARMS_WRITE (5) +/** @} */ + + +/** @name SHFL_FN_LOCK + * @remarks Lock owner is the HGCM client. + * @{ + */ + +/** Lock mode bit mask. */ +#define SHFL_LOCK_MODE_MASK (0x3) +/** Cancel lock on the given range. */ +#define SHFL_LOCK_CANCEL (0x0) +/** Acquire read only lock. Prevent write to the range. */ +#define SHFL_LOCK_SHARED (0x1) +/** Acquire write lock. Prevent both write and read to the range. */ +#define SHFL_LOCK_EXCLUSIVE (0x2) + +/** Do not wait for lock if it can not be acquired at the time. */ +#define SHFL_LOCK_NOWAIT (0x0) +/** Wait and acquire lock. */ +#define SHFL_LOCK_WAIT (0x4) + +/** Lock the specified range. */ +#define SHFL_LOCK_PARTIAL (0x0) +/** Lock entire object. */ +#define SHFL_LOCK_ENTIRE (0x8) + +/** Parameters structure. */ +typedef struct _VBoxSFLock +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** value64, in: + * SHFLHANDLE of object to be locked. + */ + HGCMFunctionParameter handle; + + /** value64, in: + * Starting offset of lock range. + */ + HGCMFunctionParameter offset; + + /** value64, in: + * Length of range. + */ + HGCMFunctionParameter length; + + /** value32, in: + * Lock flags SHFL_LOCK_*. + */ + HGCMFunctionParameter flags; + +} VBoxSFLock; + +/** Number of parameters */ +#define SHFL_CPARMS_LOCK (5) +/** @} */ + + +/** @name SHFL_FN_FLUSH + * @{ + */ + +/** SHFL_FN_FLUSH parameters. */ +typedef struct VBoxSFParmFlush +{ + /** value32, in: SHFLROOT of the mapping with the handle. */ + HGCMFunctionParameter id32Root; + /** value64, in: SHFLHANDLE of object to flush. */ + HGCMFunctionParameter u64Handle; +} VBoxSFParmFlush; + +/** Parameters structure. */ +typedef struct _VBoxSFFlush +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** value64, in: + * SHFLHANDLE of object to be locked. + */ + HGCMFunctionParameter handle; + +} VBoxSFFlush; + +/** Number of parameters */ +#define SHFL_CPARMS_FLUSH (2) +/** @} */ + + +/** @name SHFL_FN_SET_UTF8 + * @{ */ +/** NUmber of parameters for SHFL_FN_SET_UTF8. */ +#define SHFL_CPARMS_SET_UTF8 (0) +/** @} */ + + +/** @name SHFL_FN_LIST + * @remarks Listing information includes variable length RTDIRENTRY[EX] + * structures. + * @{ + */ + +/** @todo might be necessary for future. */ +#define SHFL_LIST_NONE 0 +#define SHFL_LIST_RETURN_ONE 1 +#define SHFL_LIST_RESTART 2 + +/** SHFL_FN_LIST parameters. */ +typedef struct VBoxSFParmList +{ + /** value32, in: SHFLROOT of the mapping the handle belongs to. */ + HGCMFunctionParameter id32Root; + /** value64, in: SHFLHANDLE of the directory. */ + HGCMFunctionParameter u64Handle; + /** value32, in: List flags SHFL_LIST_XXX. */ + HGCMFunctionParameter f32Flags; + /** value32, in/out: Input buffer size / Returned bytes count. */ + HGCMFunctionParameter cb32Buffer; + /** pointer, in[optional]: SHFLSTRING filter string (full path). */ + HGCMFunctionParameter pStrFilter; + /** pointer, out: Buffer to return listing information in (SHFLDIRINFO). + * When SHFL_LIST_RETURN_ONE is not specfied, multiple record may be + * returned, deriving the entry size using SHFLDIRINFO::name.u16Size. */ + HGCMFunctionParameter pBuffer; + /** value32, out: Set to 0 if the listing is done, 1 if there are more entries. + * @note Must be set to zero on call as it was declared in/out parameter and + * may be used as such again. */ + HGCMFunctionParameter f32More; + /** value32, out: Number of entries returned. */ + HGCMFunctionParameter c32Entries; +} VBoxSFParmList; + + +/** Parameters structure. */ +typedef struct _VBoxSFList +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** value64, in: + * SHFLHANDLE of object to be listed. + */ + HGCMFunctionParameter handle; + + /** value32, in: + * List flags SHFL_LIST_*. + */ + HGCMFunctionParameter flags; + + /** value32, in/out: + * Bytes to be used for listing information/How many bytes were used. + */ + HGCMFunctionParameter cb; + + /** pointer, in/optional + * Points to SHFLSTRING buffer that specifies a search path. + */ + HGCMFunctionParameter path; + + /** pointer, out: + * Buffer to place listing information to. (SHFLDIRINFO) + */ + HGCMFunctionParameter buffer; + + /** value32, in/out: + * Indicates a key where the listing must be resumed. + * in: 0 means start from begin of object. + * out: 0 means listing completed. + */ + HGCMFunctionParameter resumePoint; + + /** pointer, out: + * Number of files returned + */ + HGCMFunctionParameter cFiles; + +} VBoxSFList; + +/** Number of parameters */ +#define SHFL_CPARMS_LIST (8) +/** @} */ + + +/** @name SHFL_FN_READLINK + * @{ + */ + +/** SHFL_FN_READLINK parameters. */ +typedef struct VBoxSFParmReadLink +{ + /** value32, in: SHFLROOT of the mapping which the symlink is read. */ + HGCMFunctionParameter id32Root; + /** pointer, in: SHFLSTRING full path to the symlink. */ + HGCMFunctionParameter pStrPath; + /** pointer, out: Buffer to place the symlink target into. + * @note Buffer contains UTF-8 characters on success, regardless of the + * UTF-8/UTF-16 setting of the connection. Will be zero terminated. + * + * @todo r=bird: This should've been a string! + * @todo r=bird: There should've been a byte count returned! */ + HGCMFunctionParameter pBuffer; +} VBoxSFParmReadLink; + +/** Parameters structure. */ +typedef struct _VBoxSFReadLink +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** pointer, in: + * Points to SHFLSTRING buffer. + */ + HGCMFunctionParameter path; + + /** pointer, out: + * Buffer to place data to. + * @note Buffer contains UTF-8 characters on success, regardless of the + * UTF-8/UTF-16 setting of the connection. Will be zero terminated. + */ + HGCMFunctionParameter buffer; + +} VBoxSFReadLink; + +/** Number of parameters */ +#define SHFL_CPARMS_READLINK (3) +/** @} */ + + +/** @name SHFL_FN_INFORMATION + * @{ + */ + +/** Mask of Set/Get bit. */ +#define SHFL_INFO_MODE_MASK (0x1) +/** Get information */ +#define SHFL_INFO_GET (0x0) +/** Set information */ +#define SHFL_INFO_SET (0x1) + +/** Get name of the object. */ +#define SHFL_INFO_NAME (0x2) +/** Set size of object (extend/trucate); only applies to file objects */ +#define SHFL_INFO_SIZE (0x4) +/** Get/Set file object info. */ +#define SHFL_INFO_FILE (0x8) +/** Get volume information. */ +#define SHFL_INFO_VOLUME (0x10) + +/** @todo different file info structures */ + +/** SHFL_FN_INFORMATION parameters. */ +typedef struct VBoxSFParmInformation +{ + /** value32, in: SHFLROOT of the mapping the handle belongs to. */ + HGCMFunctionParameter id32Root; + /** value64, in: SHFLHANDLE of object to be queried/set. */ + HGCMFunctionParameter u64Handle; + /** value32, in: SHFL_INFO_XXX */ + HGCMFunctionParameter f32Flags; + /** value32, in/out: Bytes to be used for information/How many bytes were used. */ + HGCMFunctionParameter cb32; + /** pointer, in/out: Information to be set/get (SHFLFSOBJINFO, SHFLVOLINFO, or SHFLSTRING). + * Do not forget to set the SHFLFSOBJINFO::Attr::enmAdditional for Get operation as well. */ + HGCMFunctionParameter pInfo; +} VBoxSFParmInformation; + + +/** Parameters structure. */ +typedef struct _VBoxSFInformation +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** value64, in: + * SHFLHANDLE of object to be listed. + */ + HGCMFunctionParameter handle; + + /** value32, in: + * SHFL_INFO_* + */ + HGCMFunctionParameter flags; + + /** value32, in/out: + * Bytes to be used for information/How many bytes were used. + */ + HGCMFunctionParameter cb; + + /** pointer, in/out: + * Information to be set/get (SHFLFSOBJINFO or SHFLSTRING). Do not forget + * to set the SHFLFSOBJINFO::Attr::enmAdditional for Get operation as well. + */ + HGCMFunctionParameter info; + +} VBoxSFInformation; + +/** Number of parameters */ +#define SHFL_CPARMS_INFORMATION (5) +/** @} */ + + +/** @name SHFL_FN_REMOVE + * @{ + */ + +#define SHFL_REMOVE_FILE (0x1) +#define SHFL_REMOVE_DIR (0x2) +#define SHFL_REMOVE_SYMLINK (0x4) + +/** SHFL_FN_REMOVE parameters. */ +typedef struct VBoxSFParmRemove +{ + /** value32, in: SHFLROOT of the mapping the path is relative to. */ + HGCMFunctionParameter id32Root; + /** pointer, in: Points to SHFLSTRING buffer. */ + HGCMFunctionParameter pStrPath; + /** value32, in: SHFL_REMOVE_XXX */ + HGCMFunctionParameter f32Flags; +} VBoxSFParmRemove; + +/** Parameters structure. */ +typedef struct _VBoxSFRemove +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** pointer, in: + * Points to SHFLSTRING buffer. + */ + HGCMFunctionParameter path; + + /** value32, in: + * remove flags (file/directory) + */ + HGCMFunctionParameter flags; + +} VBoxSFRemove; + +#define SHFL_CPARMS_REMOVE (3) +/** @} */ + + +/** @name SHFL_FN_CLOSE_AND_REMOVE + * Extends SHFL_FN_REMOVE with a 4th handle parameter that can be nil. + * @{ + */ +/** SHFL_FN_CLOSE_AND_REMOVE parameters. */ +typedef struct VBoxSFParmCloseAndRemove +{ + /** value32, in: SHFLROOT of the mapping the path is relative to. */ + HGCMFunctionParameter id32Root; + /** pointer, in: Points to SHFLSTRING buffer. */ + HGCMFunctionParameter pStrPath; + /** value32, in: SHFL_REMOVE_XXX */ + HGCMFunctionParameter f32Flags; + /** value64, in: SHFLHANDLE to the object to be removed & close, optional. */ + HGCMFunctionParameter u64Handle; +} VBoxSFParmCloseAndRemove; +/** Number of parameters */ +#define SHFL_CPARMS_CLOSE_AND_REMOVE (4) +AssertCompileSize(VBoxSFParmCloseAndRemove, SHFL_CPARMS_CLOSE_AND_REMOVE * sizeof(HGCMFunctionParameter)); +/** @} */ + + +/** @name SHFL_FN_RENAME + * @{ + */ + +#define SHFL_RENAME_FILE (0x1) +#define SHFL_RENAME_DIR (0x2) +#define SHFL_RENAME_REPLACE_IF_EXISTS (0x4) + +/** SHFL_FN_RENAME parameters. */ +typedef struct VBoxSFParmRename +{ + /** value32, in: SHFLROOT of the mapping the paths are relative to. */ + HGCMFunctionParameter id32Root; + /** pointer, in: SHFLSTRING giving the source (old) path. */ + HGCMFunctionParameter pStrSrcPath; + /** pointer, in: SHFLSTRING giving the destination (new) path. */ + HGCMFunctionParameter pStrDstPath; + /** value32, in: SHFL_RENAME_XXX */ + HGCMFunctionParameter f32Flags; +} VBoxSFParmRename; + +/** Parameters structure. */ +typedef struct _VBoxSFRename +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** pointer, in: + * Points to SHFLSTRING src. + */ + HGCMFunctionParameter src; + + /** pointer, in: + * Points to SHFLSTRING dest. + */ + HGCMFunctionParameter dest; + + /** value32, in: + * rename flags (file/directory) + */ + HGCMFunctionParameter flags; + +} VBoxSFRename; + +#define SHFL_CPARMS_RENAME (4) +/** @} */ + + +/** @name SHFL_FN_SYMLINK + * @{ + */ + +/** Parameters structure. */ +typedef struct VBoxSFParmCreateSymlink +{ + /** value32, in: SHFLROOT of the mapping the symlink should be created on. */ + HGCMFunctionParameter id32Root; + /** pointer, in: SHFLSTRING giving the path to the symlink. */ + HGCMFunctionParameter pStrSymlink; + /** pointer, in: SHFLSTRING giving the target. */ + HGCMFunctionParameter pStrTarget; + /** pointer, out: SHFLFSOBJINFO buffer to be filled with info about the created symlink. */ + HGCMFunctionParameter pInfo; +} VBoxSFParmCreateSymlink; + +/** Parameters structure. */ +typedef struct _VBoxSFSymlink +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** pointer, in: + * Points to SHFLSTRING of path for the new symlink. + */ + HGCMFunctionParameter newPath; + + /** pointer, in: + * Points to SHFLSTRING of destination for symlink. + */ + HGCMFunctionParameter oldPath; + + /** pointer, out: + * Information about created symlink. + */ + HGCMFunctionParameter info; + +} VBoxSFSymlink; + +#define SHFL_CPARMS_SYMLINK (4) +/** @} */ + + +/** @name SHFL_FN_SET_SYMLINKS + * @{ */ +/** NUmber of parameters for SHFL_FN_SET_SYMLINKS. */ +#define SHFL_CPARMS_SET_SYMLINKS (0) +/** @} */ + + +/** @name SHFL_FN_QUERY_MAP_INFO + * @{ + */ +/** Query flag: Guest prefers drive letters as mount points. */ +#define SHFL_MIQF_DRIVE_LETTER RT_BIT_64(0) +/** Query flag: Guest prefers paths as mount points. */ +#define SHFL_MIQF_PATH RT_BIT_64(1) + +/** Set if writable. */ +#define SHFL_MIF_WRITABLE RT_BIT_64(0) +/** Indicates that the mapping should be auto-mounted. */ +#define SHFL_MIF_AUTO_MOUNT RT_BIT_64(1) +/** Set if host is case insensitive. */ +#define SHFL_MIF_HOST_ICASE RT_BIT_64(2) +/** Set if guest is case insensitive. */ +#define SHFL_MIF_GUEST_ICASE RT_BIT_64(3) +/** Symbolic link creation is allowed. */ +#define SHFL_MIF_SYMLINK_CREATION RT_BIT_64(4) + +/** Parameters structure. */ +typedef struct VBoxSFQueryMapInfo +{ + /** Common header. */ + VBGLIOCHGCMCALL callInfo; + /** 32-bit, in: SHFLROOT - root handle of the mapping to query. */ + HGCMFunctionParameter root; + /** pointer, in/out: SHFLSTRING buffer for the name. */ + HGCMFunctionParameter name; + /** pointer, in/out: SHFLSTRING buffer for the auto mount point. */ + HGCMFunctionParameter mountPoint; + /** 64-bit, in: SHFL_MIQF_XXX; out: SHFL_MIF_XXX. */ + HGCMFunctionParameter flags; + /** 32-bit, out: Root ID version number - root handle reuse guard. */ + HGCMFunctionParameter rootIdVersion; +} VBoxSFQueryMapInfo; +/** Number of parameters */ +#define SHFL_CPARMS_QUERY_MAP_INFO (5) +/** @} */ + + +/** @name SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES + * + * Returns VINF_SUCCESS on change and VINF_TRY_AGAIN when restored from saved + * state. If the guest makes too many calls (max 64) VERR_OUT_OF_RESOURCES will + * be returned. + * + * @{ + */ +/** Parameters structure. */ +typedef struct VBoxSFWaitForMappingsChanges +{ + /** Common header. */ + VBGLIOCHGCMCALL callInfo; + /** 32-bit, in/out: The mappings configuration version. + * On input the client sets it to the last config it knows about, on return + * it holds the current version. */ + HGCMFunctionParameter version; +} VBoxSFWaitForMappingsChanges; +/** Number of parameters */ +#define SHFL_CPARMS_WAIT_FOR_MAPPINGS_CHANGES (1) +/** @} */ + + +/** @name SHFL_FN_CANCEL_MAPPINGS_CHANGES_WAITS + * @{ + */ +/** Number of parameters */ +#define SHFL_CPARMS_CANCEL_MAPPINGS_CHANGES_WAITS (0) +/** @} */ + + +/** @name SHFL_FN_SET_FILE_SIZE + * @{ + */ +/** SHFL_FN_SET_FILE_SIZE parameters. */ +typedef struct VBoxSFParmSetFileSize +{ + /** value32, in: SHFLROOT of the mapping the handle belongs to. */ + HGCMFunctionParameter id32Root; + /** value64, in: SHFLHANDLE of the file to change the size of. */ + HGCMFunctionParameter u64Handle; + /** value64, in: The new file size. */ + HGCMFunctionParameter cb64NewSize; +} VBoxSFParmSetFileSize; +/** Number of parameters */ +#define SHFL_CPARMS_SET_FILE_SIZE (3) +/** @} */ + + +/** @name SHFL_FN_QUERY_FEATURES + * @{ */ +/** SHFL_FN_QUERY_FEATURES parameters. */ +typedef struct VBoxSFParmQueryFeatures +{ + /** value64, out: Feature flags, SHFL_FEATURE_XXX. */ + HGCMFunctionParameter f64Features; + /** value32, out: The ordinal of the last valid function */ + HGCMFunctionParameter u32LastFunction; +} VBoxSFParmQueryFeatures; +/** Number of parameters for SHFL_FN_QUERY_FEATURES. */ +#define SHFL_CPARMS_QUERY_FEATURES (2) + +/** The write functions updates the file offset upon return. + * This can be helpful for files open in append mode. */ +#define SHFL_FEATURE_WRITE_UPDATES_OFFSET RT_BIT_64(0) +/** @} */ + + +/** @name SHFL_FN_COPY_FILE + * @{ */ +/** SHFL_FN_COPY_FILE parameters. */ +typedef struct VBoxSFParmCopyFile +{ + /** value32, in: SHFLROOT of the mapping the source handle belongs to. */ + HGCMFunctionParameter id32RootSrc; + /** pointer, in: SHFLSTRING giving the source file path. */ + HGCMFunctionParameter pStrPathSrc; + + /** value32, in: SHFLROOT of the mapping the destination handle belongs to. */ + HGCMFunctionParameter id32RootDst; + /** pointer, in: SHFLSTRING giving the destination file path. */ + HGCMFunctionParameter pStrPathDst; + + /** value32, in: Reserved for the future, must be zero. */ + HGCMFunctionParameter f32Flags; +} VBoxSFParmCopyFile; +/** Number of parameters for SHFL_FN_COPY_FILE. */ +#define SHFL_CPARMS_COPY_FILE (5) +/** @} */ + + +/** @name SHFL_FN_COPY_FILE_PART + * @{ */ +/** SHFL_FN_COPY_FILE_PART parameters. */ +typedef struct VBoxSFParmCopyFilePart +{ + /** value32, in: SHFLROOT of the mapping the source handle belongs to. */ + HGCMFunctionParameter id32RootSrc; + /** value64, in: SHFLHANDLE of the source file. */ + HGCMFunctionParameter u64HandleSrc; + /** value64, in: The source file offset. */ + HGCMFunctionParameter off64Src; + + /** value32, in: SHFLROOT of the mapping the destination handle belongs to. */ + HGCMFunctionParameter id32RootDst; + /** value64, in: SHFLHANDLE of the destination file. */ + HGCMFunctionParameter u64HandleDst; + /** value64, in: The destination file offset. */ + HGCMFunctionParameter off64Dst; + + /** value64, in/out: The number of bytes to copy on input / bytes actually copied. */ + HGCMFunctionParameter cb64ToCopy; + /** value32, in: Reserved for the future, must be zero. */ + HGCMFunctionParameter f32Flags; +} VBoxSFParmCopyFilePart; +/** Number of parameters for SHFL_FN_COPY_FILE_PART. */ +#define SHFL_CPARMS_COPY_FILE_PART (8) +/** @} */ + + +/** @name SHFL_FN_SET_ERROR_STYLE + * @{ */ +/** The defined error styles. */ +typedef enum SHFLERRORSTYLE +{ + kShflErrorStyle_Invalid = 0, + kShflErrorStyle_Windows, + kShflErrorStyle_Linux, + kShflErrorStyle_End, + kShflErrorStyle_32BitHack = 0x7fffffff +} SHFLERRORSTYLE; +/** The native error style. */ +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) +# define SHFLERRORSTYLE_NATIVE kShflErrorStyle_Windows +#else +# define SHFLERRORSTYLE_NATIVE kShflErrorStyle_Linux +#endif + +/** SHFL_FN_SET_ERROR_STYLE parameters. */ +typedef struct VBoxSFParmSetErrorStyle +{ + /** value32, in: The style, SHFLERRORSTYLE. */ + HGCMFunctionParameter u32Style; + /** value32, in: Reserved for the future, must be zero. */ + HGCMFunctionParameter u32Reserved; +} VBoxSFParmSetErrorStyle; +/** Number of parameters for SHFL_FN_SET_ERROR_STYLE. */ +#define SHFL_CPARMS_SET_ERROR_STYLE (2) +/** @} */ + + +/** @name SHFL_FN_ADD_MAPPING + * @note Host call, no guest structure is used. + * @{ + */ + +/** mapping is writable */ +#define SHFL_ADD_MAPPING_F_WRITABLE (RT_BIT_32(0)) +/** mapping is automounted by the guest */ +#define SHFL_ADD_MAPPING_F_AUTOMOUNT (RT_BIT_32(1)) +/** allow the guest to create symlinks */ +#define SHFL_ADD_MAPPING_F_CREATE_SYMLINKS (RT_BIT_32(2)) +/** mapping is actually missing on the host */ +#define SHFL_ADD_MAPPING_F_MISSING (RT_BIT_32(3)) + +#define SHFL_CPARMS_ADD_MAPPING (4) +/** @} */ + + +/** @name SHFL_FN_REMOVE_MAPPING + * @note Host call, no guest structure is used. + * @{ + */ + +#define SHFL_CPARMS_REMOVE_MAPPING (1) +/** @} */ + + +/** @name SHFL_FN_SET_STATUS_LED + * @note Host call, no guest structure is used. + * @{ + */ + +#define SHFL_CPARMS_SET_STATUS_LED (1) +/** @} */ + + +/** @} */ +/** @} */ + +#endif /* !VBOX_INCLUDED_shflsvc_h */ + diff --git a/include/VBox/sup.h b/include/VBox/sup.h new file mode 100644 index 00000000..258134fa --- /dev/null +++ b/include/VBox/sup.h @@ -0,0 +1,2832 @@ +/** @file + * SUP - Support Library. (HDrv) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_sup_h +#define VBOX_INCLUDED_sup_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <iprt/assert.h> +#include <iprt/stdarg.h> +#include <iprt/cpuset.h> +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# include <iprt/asm-amd64-x86.h> +#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM64) +# include <iprt/asm-arm.h> +#endif + +RT_C_DECLS_BEGIN + +struct VTGOBJHDR; +struct VTGPROBELOC; + + +/** @defgroup grp_sup The Support Library API + * @{ + */ + +/** + * Physical page descriptor. + */ +#pragma pack(4) /* space is more important. */ +typedef struct SUPPAGE +{ + /** Physical memory address. */ + RTHCPHYS Phys; + /** Reserved entry for internal use by the caller. */ + RTHCUINTPTR uReserved; +} SUPPAGE; +#pragma pack() +/** Pointer to a page descriptor. */ +typedef SUPPAGE *PSUPPAGE; +/** Pointer to a const page descriptor. */ +typedef const SUPPAGE *PCSUPPAGE; + +/** + * The paging mode. + * + * @remarks Users are making assumptions about the order here! + */ +typedef enum SUPPAGINGMODE +{ + /** The usual invalid entry. + * This is returned by SUPR3GetPagingMode() */ + SUPPAGINGMODE_INVALID = 0, + /** Normal 32-bit paging, no global pages */ + SUPPAGINGMODE_32_BIT, + /** Normal 32-bit paging with global pages. */ + SUPPAGINGMODE_32_BIT_GLOBAL, + /** PAE mode, no global pages, no NX. */ + SUPPAGINGMODE_PAE, + /** PAE mode with global pages. */ + SUPPAGINGMODE_PAE_GLOBAL, + /** PAE mode with NX, no global pages. */ + SUPPAGINGMODE_PAE_NX, + /** PAE mode with global pages and NX. */ + SUPPAGINGMODE_PAE_GLOBAL_NX, + /** AMD64 mode, no global pages. */ + SUPPAGINGMODE_AMD64, + /** AMD64 mode with global pages, no NX. */ + SUPPAGINGMODE_AMD64_GLOBAL, + /** AMD64 mode with NX, no global pages. */ + SUPPAGINGMODE_AMD64_NX, + /** AMD64 mode with global pages and NX. */ + SUPPAGINGMODE_AMD64_GLOBAL_NX +} SUPPAGINGMODE; + + +/** @name Flags returned by SUPR0GetKernelFeatures(). + * @{ + */ +/** GDT is read-only. */ +#define SUPKERNELFEATURES_GDT_READ_ONLY RT_BIT(0) +/** SMAP is possibly enabled. */ +#define SUPKERNELFEATURES_SMAP RT_BIT(1) +/** GDT is read-only but the writable GDT can be fetched by SUPR0GetCurrentGdtRw(). */ +#define SUPKERNELFEATURES_GDT_NEED_WRITABLE RT_BIT(2) +/** @} */ + +/** + * An VT-x control MSR. + * @sa VMXCTLSMSR. + */ +typedef union SUPVMXCTLSMSR +{ + uint64_t u; + struct + { + /** Bits set here _must_ be set in the corresponding VM-execution controls. */ + uint32_t allowed0; + /** Bits cleared here _must_ be cleared in the corresponding VM-execution controls. */ + uint32_t allowed1; + } n; +} SUPVMXCTLSMSR; +AssertCompileSize(SUPVMXCTLSMSR, sizeof(uint64_t)); + +/** + * Hardware-virtualization MSRs. + */ +typedef struct SUPHWVIRTMSRS +{ + union + { + /** @sa VMXMSRS */ + struct + { + uint64_t u64FeatCtrl; + uint64_t u64Basic; + /** Pin-based VM-execution controls. */ + SUPVMXCTLSMSR PinCtls; + /** Processor-based VM-execution controls. */ + SUPVMXCTLSMSR ProcCtls; + /** Secondary processor-based VM-execution controls. */ + SUPVMXCTLSMSR ProcCtls2; + /** VM-exit controls. */ + SUPVMXCTLSMSR ExitCtls; + /** VM-entry controls. */ + SUPVMXCTLSMSR EntryCtls; + /** True pin-based VM-execution controls. */ + SUPVMXCTLSMSR TruePinCtls; + /** True processor-based VM-execution controls. */ + SUPVMXCTLSMSR TrueProcCtls; + /** True VM-entry controls. */ + SUPVMXCTLSMSR TrueEntryCtls; + /** True VM-exit controls. */ + SUPVMXCTLSMSR TrueExitCtls; + uint64_t u64Misc; + uint64_t u64Cr0Fixed0; + uint64_t u64Cr0Fixed1; + uint64_t u64Cr4Fixed0; + uint64_t u64Cr4Fixed1; + uint64_t u64VmcsEnum; + uint64_t u64VmFunc; + uint64_t u64EptVpidCaps; + uint64_t u64ProcCtls3; + uint64_t u64ExitCtls2; + uint64_t au64Reserved[7]; + } vmx; + struct + { + uint64_t u64MsrHwcr; + uint64_t u64MsrSmmAddr; + uint64_t u64MsrSmmMask; + uint64_t u64Padding[25]; + } svm; + } u; +} SUPHWVIRTMSRS; +AssertCompileSize(SUPHWVIRTMSRS, 224); +/** Pointer to a hardware-virtualization MSRs struct. */ +typedef SUPHWVIRTMSRS *PSUPHWVIRTMSRS; +/** Pointer to a hardware-virtualization MSRs struct. */ +typedef const SUPHWVIRTMSRS *PCSUPHWVIRTMSRS; + + +/** + * Usermode probe context information. + */ +typedef struct SUPDRVTRACERUSRCTX +{ + /** The probe ID from the VTG location record. */ + uint32_t idProbe; + /** 32 if X86, 64 if AMD64. */ + uint8_t cBits; + /** Reserved padding. */ + uint8_t abReserved[3]; + /** Data which format is dictated by the cBits member. */ + union + { + /** X86 context info. */ + struct + { + uint32_t uVtgProbeLoc; /**< Location record address. */ + uint32_t aArgs[20]; /**< Raw arguments. */ + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint16_t cs; + uint16_t ss; + uint16_t ds; + uint16_t es; + uint16_t fs; + uint16_t gs; + } X86; + + /** AMD64 context info. */ + struct + { + uint64_t uVtgProbeLoc; /**< Location record address. */ + uint64_t aArgs[10]; /**< Raw arguments. */ + uint64_t rip; + uint64_t rflags; + uint64_t rax; + uint64_t rcx; + uint64_t rdx; + uint64_t rbx; + uint64_t rsp; + uint64_t rbp; + uint64_t rsi; + uint64_t rdi; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + } Amd64; + } u; +} SUPDRVTRACERUSRCTX; +/** Pointer to the usermode probe context information. */ +typedef SUPDRVTRACERUSRCTX *PSUPDRVTRACERUSRCTX; +/** Pointer to the const usermode probe context information. */ +typedef SUPDRVTRACERUSRCTX const *PCSUPDRVTRACERUSRCTX; + +/** + * The result of a modification operation (SUPMSRPROBEROP_MODIFY or + * SUPMSRPROBEROP_MODIFY_FASTER). + */ +typedef struct SUPMSRPROBERMODIFYRESULT +{ + /** The MSR value prior to the modifications. Valid if fBeforeGp is false */ + uint64_t uBefore; + /** The value that was written. Valid if fBeforeGp is false */ + uint64_t uWritten; + /** The MSR value after the modifications. Valid if AfterGp is false. */ + uint64_t uAfter; + /** Set if we GPed reading the MSR before the modification. */ + bool fBeforeGp; + /** Set if we GPed while trying to write the modified value. + * This is set when fBeforeGp is true. */ + bool fModifyGp; + /** Set if we GPed while trying to read the MSR after the modification. + * This is set when fBeforeGp is true. */ + bool fAfterGp; + /** Set if we GPed while trying to restore the MSR after the modification. + * This is set when fBeforeGp is true. */ + bool fRestoreGp; + /** Structure size alignment padding. */ + bool afReserved[4]; +} SUPMSRPROBERMODIFYRESULT, *PSUPMSRPROBERMODIFYRESULT; + + +/** + * The CPU state. + */ +typedef enum SUPGIPCPUSTATE +{ + /** Invalid CPU state / unused CPU entry. */ + SUPGIPCPUSTATE_INVALID = 0, + /** The CPU is not present. */ + SUPGIPCPUSTATE_ABSENT, + /** The CPU is offline. */ + SUPGIPCPUSTATE_OFFLINE, + /** The CPU is online. */ + SUPGIPCPUSTATE_ONLINE, + /** Force 32-bit enum type. */ + SUPGIPCPUSTATE_32_BIT_HACK = 0x7fffffff +} SUPGIPCPUSTATE; + +/** + * Per CPU data. + */ +typedef struct SUPGIPCPU +{ + /** Update transaction number. + * This number is incremented at the start and end of each update. It follows + * thusly that odd numbers indicates update in progress, while even numbers + * indicate stable data. Use this to make sure that the data items you fetch + * are consistent. */ + volatile uint32_t u32TransactionId; + /** The interval in TSC ticks between two NanoTS updates. + * This is the average interval over the last 2, 4 or 8 updates + a little slack. + * The slack makes the time go a tiny tiny bit slower and extends the interval enough + * to avoid ending up with too many 1ns increments. */ + volatile uint32_t u32UpdateIntervalTSC; + /** Current nanosecond timestamp. */ + volatile uint64_t u64NanoTS; + /** The TSC at the time of u64NanoTS. */ + volatile uint64_t u64TSC; + /** Current CPU Frequency. */ + volatile uint64_t u64CpuHz; + /** The TSC delta with reference to the master TSC, subtract from RDTSC. */ + volatile int64_t i64TSCDelta; + /** Number of errors during updating. + * Typical errors are under/overflows. */ + volatile uint32_t cErrors; + /** Index of the head item in au32TSCHistory. */ + volatile uint32_t iTSCHistoryHead; + /** Array of recent TSC interval deltas. + * The most recent item is at index iTSCHistoryHead. + * This history is used to calculate u32UpdateIntervalTSC. + */ + volatile uint32_t au32TSCHistory[8]; + /** The interval between the last two NanoTS updates. (experiment for now) */ + volatile uint32_t u32PrevUpdateIntervalNS; + + /** Reserved for future per processor data. */ + volatile uint32_t u32Reserved; + /** The TSC value read while doing TSC delta measurements across CPUs. */ + volatile uint64_t u64TSCSample; + /** Reserved for future per processor data. */ + volatile uint32_t au32Reserved1[3]; + + /** The CPU state. */ + SUPGIPCPUSTATE volatile enmState; + /** The host CPU ID of this CPU (the SUPGIPCPU is indexed by APIC ID). */ + RTCPUID idCpu; + /** The CPU set index of this CPU. */ + int16_t iCpuSet; + /** CPU group number (always zero, except on windows). */ + uint16_t iCpuGroup; + /** CPU group member number (same as iCpuSet, except on windows). */ + uint16_t iCpuGroupMember; + /** The APIC ID of this CPU. */ + uint16_t idApic; + /** @todo Add topology/NUMA info. */ + uint32_t iReservedForNumaNode; +} SUPGIPCPU; +AssertCompileSize(RTCPUID, 4); +AssertCompileSize(SUPGIPCPU, 128); +AssertCompileMemberAlignment(SUPGIPCPU, u64NanoTS, 8); +AssertCompileMemberAlignment(SUPGIPCPU, u64TSC, 8); +AssertCompileMemberAlignment(SUPGIPCPU, u64TSCSample, 8); + +/** Pointer to per cpu data. + * @remark there is no const version of this typedef, see g_pSUPGlobalInfoPage for details. */ +typedef SUPGIPCPU *PSUPGIPCPU; + +/** + * CPU group information. + * @remarks Windows only. + */ +typedef struct SUPGIPCPUGROUP +{ + /** Current number of CPUs in this group. */ + uint16_t volatile cMembers; + /** Maximum number of CPUs in the group. */ + uint16_t cMaxMembers; + /** The CPU set index of the members. This table has cMaxMembers entries. + * @note For various reasons, entries from cMembers and up to cMaxMembers are + * may change as the host OS does set dynamic assignments during CPU + * hotplugging. */ + int16_t aiCpuSetIdxs[1]; +} SUPGIPCPUGROUP; +/** Pointer to a GIP CPU group structure. */ +typedef SUPGIPCPUGROUP *PSUPGIPCPUGROUP; +/** Pointer to a const GIP CPU group structure. */ +typedef SUPGIPCPUGROUP const *PCSUPGIPCPUGROUP; + +/** + * The rules concerning the applicability of SUPGIPCPU::i64TscDelta. + */ +typedef enum SUPGIPUSETSCDELTA +{ + /** Value for SUPGIPMODE_ASYNC_TSC. */ + SUPGIPUSETSCDELTA_NOT_APPLICABLE = 0, + /** The OS specific part of SUPDrv (or the user) claims the TSC is as + * good as zero. */ + SUPGIPUSETSCDELTA_ZERO_CLAIMED, + /** The differences in RDTSC output between the CPUs/cores/threads should + * be considered zero for all practical purposes. */ + SUPGIPUSETSCDELTA_PRACTICALLY_ZERO, + /** The differences in RDTSC output between the CPUs/cores/threads are a few + * hundred ticks or less. (Probably not worth calling ASMGetApicId two times + * just to apply deltas.) */ + SUPGIPUSETSCDELTA_ROUGHLY_ZERO, + /** Significant differences in RDTSC output between the CPUs/cores/threads, + * deltas must be applied. */ + SUPGIPUSETSCDELTA_NOT_ZERO, + /** End of valid values (exclusive). */ + SUPGIPUSETSCDELTA_END, + /** Make sure the type is 32-bit sized. */ + SUPGIPUSETSCDELTA_32BIT_HACK = 0x7fffffff +} SUPGIPUSETSCDELTA; + + +/** @name SUPGIPGETCPU_XXX - methods that aCPUs can be indexed. + * + * @note Linux offers information via selector 0x78, and Windows via selector + * 0x53. But since they both support RDTSCP as well, and because most + * CPUs now have RDTSCP, we prefer it over LSL. We can implement more + * alternatives if it becomes necessary. + * + * @{ + */ +/** Use ASMGetApicId (or equivalent) and translate the result via + * aiCpuFromApicId. */ +#define SUPGIPGETCPU_APIC_ID RT_BIT_32(0) +/** Use RDTSCP and translate the first RTCPUSET_MAX_CPUS of ECX via + * aiCpuFromCpuSetIdx. + * + * Linux stores the RTMpCpuId() value in ECX[11:0] and NUMA node number in + * ECX[12:31]. Solaris only stores RTMpCpuId() in ECX. On both systems + * RTMpCpuId() == RTMpCpuIdToSetIndex(RTMpCpuId()). RTCPUSET_MAX_CPUS is + * currently 64, 256 or 1024 in size, which lower than + * 4096, so there shouldn't be any range issues. */ +#define SUPGIPGETCPU_RDTSCP_MASK_MAX_SET_CPUS RT_BIT_32(1) +/** Subtract the max IDT size from IDTR.LIMIT, extract the + * first RTCPUSET_MAX_CPUS and translate it via aiCpuFromCpuSetIdx. + * + * Darwin stores the RTMpCpuId() (== RTMpCpuIdToSetIndex(RTMpCpuId())) + * value in the IDT limit. The masking is a precaution against what linux + * does with RDTSCP. */ +#define SUPGIPGETCPU_IDTR_LIMIT_MASK_MAX_SET_CPUS RT_BIT_32(2) +/** Windows specific RDTSCP variant, where CH gives you the group and CL gives + * you the CPU number within that group. + * + * Use SUPGLOBALINFOPAGE::aidFirstCpuFromCpuGroup to get the group base CPU set + * index, then translate the sum of thru aiCpuFromCpuSetIdx to find the aCPUs + * entry. + * + * @note The group number is actually 16-bit wide (ECX[23:8]), but we simplify + * it since we only support 256 CPUs/groups at the moment. + */ +#define SUPGIPGETCPU_RDTSCP_GROUP_IN_CH_NUMBER_IN_CL RT_BIT_32(3) +/** Can use CPUID[0xb].EDX and translate the result via aiCpuFromApicId. */ +#define SUPGIPGETCPU_APIC_ID_EXT_0B RT_BIT_32(4) +/** Can use CPUID[0x8000001e].EAX and translate the result via aiCpuFromApicId. */ +#define SUPGIPGETCPU_APIC_ID_EXT_8000001E RT_BIT_32(5) +/** @} */ + +/** @def SUPGIP_MAX_CPU_GROUPS + * Maximum number of CPU groups. */ +#if RTCPUSET_MAX_CPUS >= 256 +# define SUPGIP_MAX_CPU_GROUPS 256 +#else +# define SUPGIP_MAX_CPU_GROUPS RTCPUSET_MAX_CPUS +#endif + +/** + * Global Information Page. + * + * This page contains useful information and can be mapped into any + * process or VM. It can be accessed thru the g_pSUPGlobalInfoPage + * pointer when a session is open. + */ +typedef struct SUPGLOBALINFOPAGE +{ + /** Magic (SUPGLOBALINFOPAGE_MAGIC). */ + uint32_t u32Magic; + /** The GIP version. */ + uint32_t u32Version; + + /** The GIP update mode, see SUPGIPMODE. */ + uint32_t u32Mode; + /** The number of entries in the CPU table. + * (This can work as RTMpGetArraySize().) */ + uint16_t cCpus; + /** The size of the GIP in pages. */ + uint16_t cPages; + /** The update frequency of the of the NanoTS. */ + volatile uint32_t u32UpdateHz; + /** The update interval in nanoseconds. (10^9 / u32UpdateHz) */ + volatile uint32_t u32UpdateIntervalNS; + /** The timestamp of the last time we update the update frequency. */ + volatile uint64_t u64NanoTSLastUpdateHz; + /** The TSC frequency of the system. */ + uint64_t u64CpuHz; + /** The number of CPUs that are online. */ + volatile uint16_t cOnlineCpus; + /** The number of CPUs present in the system. */ + volatile uint16_t cPresentCpus; + /** The highest number of CPUs possible. */ + uint16_t cPossibleCpus; + /** The highest number of CPU groups possible. */ + uint16_t cPossibleCpuGroups; + /** The max CPU ID (RTMpGetMaxCpuId). */ + RTCPUID idCpuMax; + /** The applicability of SUPGIPCPU::i64TscDelta. */ + SUPGIPUSETSCDELTA enmUseTscDelta; + /** Mask of SUPGIPGETCPU_XXX values that indicates different ways that aCPU + * can be accessed from ring-3 and raw-mode context. */ + uint32_t fGetGipCpu; + /** GIP flags, see SUPGIP_FLAGS_XXX. */ + volatile uint32_t fFlags; + /** The set of online CPUs. */ + RTCPUSET OnlineCpuSet; +#if RTCPUSET_MAX_CPUS < 1024 + uint64_t abOnlineCpuSetPadding[(1024 - RTCPUSET_MAX_CPUS) / 64]; +#endif + /** The set of present CPUs. */ + RTCPUSET PresentCpuSet; +#if RTCPUSET_MAX_CPUS < 1024 + uint64_t abPresentCpuSetPadding[(1024 - RTCPUSET_MAX_CPUS) / 64]; +#endif + /** The set of possible CPUs. */ + RTCPUSET PossibleCpuSet; +#if RTCPUSET_MAX_CPUS < 1024 + uint64_t abPossibleCpuSetPadding[(1024 - RTCPUSET_MAX_CPUS) / 64]; +#endif + + /** Padding / reserved space for future data. */ + uint32_t au32Padding1[48]; + + /** Table indexed by the CPU APIC ID to get the CPU table index. */ + uint16_t aiCpuFromApicId[4096]; + /** CPU set index to CPU table index. */ + uint16_t aiCpuFromCpuSetIdx[1024]; + /** Table indexed by CPU group to containing offsets to SUPGIPCPUGROUP + * structures, invalid entries are set to UINT32_MAX. The offsets are relative + * to the start of this structure. + * @note Windows only. The other hosts sets all entries to UINT32_MAX! */ + uint32_t aoffCpuGroup[SUPGIP_MAX_CPU_GROUPS]; + + /** Array of per-cpu data. + * This is index by ApicId via the aiCpuFromApicId table. + * + * The clock and frequency information is updated for all CPUs if @c u32Mode + * is SUPGIPMODE_ASYNC_TSC. If @c u32Mode is SUPGIPMODE_SYNC_TSC only the first + * entry is updated. If @c u32Mode is SUPGIPMODE_SYNC_TSC the TSC frequency in + * @c u64CpuHz is copied to all CPUs. */ + SUPGIPCPU aCPUs[1]; +} SUPGLOBALINFOPAGE; +AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, u64NanoTSLastUpdateHz, 8); +AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, OnlineCpuSet, 64); +AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, PresentCpuSet, 64); +AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, PossibleCpuSet, 64); +#if defined(RT_ARCH_SPARC) || defined(RT_ARCH_SPARC64) /* ?? needed ?? */ +AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, aCPUs, 32); +#else +AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, aCPUs, 128); +#endif + +/** Pointer to the global info page. + * @remark there is no const version of this typedef, see g_pSUPGlobalInfoPage for details. */ +typedef SUPGLOBALINFOPAGE *PSUPGLOBALINFOPAGE; + + +/** The value of the SUPGLOBALINFOPAGE::u32Magic field. (Soryo Fuyumi) */ +#define SUPGLOBALINFOPAGE_MAGIC 0x19590106 +/** The GIP version. + * Upper 16 bits is the major version. Major version is only changed with + * incompatible changes in the GIP. */ +#define SUPGLOBALINFOPAGE_VERSION 0x000a0000 + +/** + * SUPGLOBALINFOPAGE::u32Mode values. + */ +typedef enum SUPGIPMODE +{ + /** The usual invalid null entry. */ + SUPGIPMODE_INVALID = 0, + /** The TSC of the cores and cpus in the system is in sync. */ + SUPGIPMODE_SYNC_TSC, + /** Each core has it's own TSC. */ + SUPGIPMODE_ASYNC_TSC, + /** The TSC of the cores are non-stop and have a constant frequency. */ + SUPGIPMODE_INVARIANT_TSC, + /** End of valid GIP mode values (exclusive). */ + SUPGIPMODE_END, + /** The usual 32-bit hack. */ + SUPGIPMODE_32BIT_HACK = 0x7fffffff +} SUPGIPMODE; + +/** Pointer to the Global Information Page. + * + * This pointer is valid as long as SUPLib has a open session. Anyone using + * the page must treat this pointer as highly volatile and not trust it beyond + * one transaction. + * + * @remark The GIP page is read-only to everyone but the support driver and + * is actually mapped read only everywhere but in ring-0. However + * it is not marked 'const' as this might confuse compilers into + * thinking that values doesn't change even if members are marked + * as volatile. Thus, there is no PCSUPGLOBALINFOPAGE type. + */ +#if defined(IN_SUP_R3) || defined(IN_SUP_R0) +extern DECLEXPORT(PSUPGLOBALINFOPAGE) g_pSUPGlobalInfoPage; + +#elif !defined(IN_RING0) || defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS) || defined(VBOX_WITH_KMOD_WRAPPED_R0_MODS) +extern DECLIMPORT(PSUPGLOBALINFOPAGE) g_pSUPGlobalInfoPage; + +#else /* IN_RING0 && !RT_OS_WINDOWS */ +# if !defined(__GNUC__) || defined(RT_OS_DARWIN) || !defined(RT_ARCH_AMD64) +# define g_pSUPGlobalInfoPage (&g_SUPGlobalInfoPage) +# else +# define g_pSUPGlobalInfoPage (SUPGetGIPHlp()) +/** Workaround for ELF+GCC problem on 64-bit hosts. + * (GCC emits a mov with a R_X86_64_32 reloc, we need R_X86_64_64.) */ +DECLINLINE(PSUPGLOBALINFOPAGE) SUPGetGIPHlp(void) +{ + PSUPGLOBALINFOPAGE pGIP; + __asm__ __volatile__ ("movabs $g_SUPGlobalInfoPage,%0\n\t" + : "=a" (pGIP)); + return pGIP; +} +# endif +/** The GIP. + * We save a level of indirection by exporting the GIP instead of a variable + * pointing to it. */ +extern DECLIMPORT(SUPGLOBALINFOPAGE) g_SUPGlobalInfoPage; +#endif + +/** + * Gets the GIP pointer. + * + * @returns Pointer to the GIP or NULL. + */ +SUPDECL(PSUPGLOBALINFOPAGE) SUPGetGIP(void); + +/** @name SUPGIP_FLAGS_XXX - SUPR3GipSetFlags flags. + * @{ */ +/** Enable GIP test mode. */ +#define SUPGIP_FLAGS_TESTING_ENABLE RT_BIT_32(0) +/** Valid mask of flags that can be set through the ioctl. */ +#define SUPGIP_FLAGS_VALID_MASK RT_BIT_32(0) +/** GIP test mode needs to be checked (e.g. when enabled or being disabled). */ +#define SUPGIP_FLAGS_TESTING RT_BIT_32(24) +/** Prepare to start GIP test mode. */ +#define SUPGIP_FLAGS_TESTING_START RT_BIT_32(25) +/** Prepare to stop GIP test mode. */ +#define SUPGIP_FLAGS_TESTING_STOP RT_BIT_32(26) +/** @} */ + +/** @internal */ +SUPDECL(PSUPGIPCPU) SUPGetGipCpuPtrForAsyncMode(PSUPGLOBALINFOPAGE pGip); +SUPDECL(uint64_t) SUPGetCpuHzFromGipForAsyncMode(PSUPGLOBALINFOPAGE pGip); +SUPDECL(bool) SUPIsTscFreqCompatible(uint64_t uCpuHz, uint64_t *puGipCpuHz, bool fRelax); +SUPDECL(bool) SUPIsTscFreqCompatibleEx(uint64_t uBaseCpuHz, uint64_t uCpuHz, bool fRelax); + + +/** + * Gets CPU entry of the calling CPU. + * + * @returns Pointer to the CPU entry on success, NULL on failure. + * @param pGip The GIP pointer. + */ +DECLINLINE(PSUPGIPCPU) SUPGetGipCpuPtr(PSUPGLOBALINFOPAGE pGip) +{ + if (RT_LIKELY( pGip + && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC)) + { + switch (pGip->u32Mode) + { + case SUPGIPMODE_INVARIANT_TSC: + case SUPGIPMODE_SYNC_TSC: + return &pGip->aCPUs[0]; + case SUPGIPMODE_ASYNC_TSC: + return SUPGetGipCpuPtrForAsyncMode(pGip); + default: break; /* shut up gcc */ + } + } + AssertFailed(); + return NULL; +} + +/** + * Gets the TSC frequency of the calling CPU. + * + * @returns TSC frequency, UINT64_MAX on failure (asserted). + * @param pGip The GIP pointer. + */ +DECLINLINE(uint64_t) SUPGetCpuHzFromGip(PSUPGLOBALINFOPAGE pGip) +{ + if (RT_LIKELY( pGip + && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC)) + { + switch (pGip->u32Mode) + { + case SUPGIPMODE_INVARIANT_TSC: + case SUPGIPMODE_SYNC_TSC: + return pGip->aCPUs[0].u64CpuHz; + case SUPGIPMODE_ASYNC_TSC: + return SUPGetCpuHzFromGipForAsyncMode(pGip); + default: break; /* shut up gcc */ + } + } + AssertFailed(); + return UINT64_MAX; +} + + +/** + * Gets the TSC frequency of the specified CPU. + * + * @returns TSC frequency, UINT64_MAX on failure (asserted). + * @param pGip The GIP pointer. + * @param iCpuSet The CPU set index of the CPU in question. + */ +DECLINLINE(uint64_t) SUPGetCpuHzFromGipBySetIndex(PSUPGLOBALINFOPAGE pGip, uint32_t iCpuSet) +{ + if (RT_LIKELY( pGip + && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC)) + { + switch (pGip->u32Mode) + { + case SUPGIPMODE_INVARIANT_TSC: + case SUPGIPMODE_SYNC_TSC: + return pGip->aCPUs[0].u64CpuHz; + case SUPGIPMODE_ASYNC_TSC: + if (RT_LIKELY(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))) + { + uint16_t iCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]; + if (RT_LIKELY(iCpu < pGip->cCpus)) + return pGip->aCPUs[iCpu].u64CpuHz; + } + break; + default: break; /* shut up gcc */ + } + } + AssertFailed(); + return UINT64_MAX; +} + + +/** + * Gets the pointer to the per CPU data for a CPU given by its set index. + * + * @returns Pointer to the corresponding per CPU structure, or NULL if invalid. + * @param pGip The GIP pointer. + * @param iCpuSet The CPU set index of the CPU which we want. + */ +DECLINLINE(PSUPGIPCPU) SUPGetGipCpuBySetIndex(PSUPGLOBALINFOPAGE pGip, uint32_t iCpuSet) +{ + if (RT_LIKELY( pGip + && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC)) + { + if (RT_LIKELY(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))) + { + uint16_t iCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]; + if (RT_LIKELY(iCpu < pGip->cCpus)) + return &pGip->aCPUs[iCpu]; + } + } + return NULL; +} + + +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) || defined(RT_ARCH_ARM64) ||defined(RT_ARCH_ARM32) + +/** @internal */ +SUPDECL(uint64_t) SUPReadTscWithDelta(PSUPGLOBALINFOPAGE pGip); + +/** + * Read the host TSC value and applies the TSC delta if appropriate. + * + * @returns the TSC value. + * @remarks Requires GIP to be initialized and valid. + */ +DECLINLINE(uint64_t) SUPReadTsc(void) +{ +# if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) /** @todo portme: ring-0 arm. */ + return ASMReadTSC(); +# else + PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; + if (!pGip || pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO) + return ASMReadTSC(); + return SUPReadTscWithDelta(pGip); +# endif +} + +#endif /* X86 || AMD64 || ARM */ + +/** @internal */ +SUPDECL(int64_t) SUPGetTscDeltaSlow(PSUPGLOBALINFOPAGE pGip); + +/** + * Gets the TSC delta for the current CPU. + * + * @returns The TSC delta value (will not return the special INT64_MAX value). + * @param pGip The GIP, NULL is okay in ring-3. + * @remarks Requires GIP to be initialized and valid if pGip isn't NULL. + */ +DECLINLINE(int64_t) SUPGetTscDelta(PSUPGLOBALINFOPAGE pGip) +{ +#ifdef IN_RING3 + if (!pGip || pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO) +#else + if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO) +#endif + return 0; + return SUPGetTscDeltaSlow(pGip); +} + + +/** + * Gets the TSC delta for a given CPU. + * + * @returns The TSC delta value (will not return the special INT64_MAX value). + * @param iCpuSet The CPU set index of the CPU which TSC delta we want. + * @remarks Requires GIP to be initialized and valid. + */ +DECLINLINE(int64_t) SUPGetTscDeltaByCpuSetIndex(uint32_t iCpuSet) +{ + PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; + if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO) + return 0; + if (RT_LIKELY(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))) + { + uint16_t iCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]; + if (RT_LIKELY(iCpu < pGip->cCpus)) + { + int64_t iTscDelta = pGip->aCPUs[iCpu].i64TSCDelta; + if (iTscDelta != INT64_MAX) + return iTscDelta; + } + } + AssertFailed(); + return 0; +} + + +/** + * Checks if the TSC delta is available for a given CPU (if TSC-deltas are + * relevant). + * + * @returns true if it's okay to read the TSC, false otherwise. + * + * @param iCpuSet The CPU set index of the CPU which TSC delta we check. + * @remarks Requires GIP to be initialized and valid. + */ +DECLINLINE(bool) SUPIsTscDeltaAvailableForCpuSetIndex(uint32_t iCpuSet) +{ + PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; + if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO) + return true; + if (RT_LIKELY(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))) + { + uint16_t iCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]; + if (RT_LIKELY(iCpu < pGip->cCpus)) + { + int64_t iTscDelta = pGip->aCPUs[iCpu].i64TSCDelta; + if (iTscDelta != INT64_MAX) + return true; + } + } + return false; +} + + +/** + * Gets the descriptive GIP mode name. + * + * @returns The name. + * @param pGip Pointer to the GIP. + */ +DECLINLINE(const char *) SUPGetGIPModeName(PSUPGLOBALINFOPAGE pGip) +{ + AssertReturn(pGip, NULL); + switch (pGip->u32Mode) + { + case SUPGIPMODE_INVARIANT_TSC: return "Invariant"; + case SUPGIPMODE_SYNC_TSC: return "Synchronous"; + case SUPGIPMODE_ASYNC_TSC: return "Asynchronous"; + case SUPGIPMODE_INVALID: return "Invalid"; + default: return "???"; + } +} + + +/** + * Gets the descriptive TSC-delta enum name. + * + * @returns The name. + * @param pGip Pointer to the GIP. + */ +DECLINLINE(const char *) SUPGetGIPTscDeltaModeName(PSUPGLOBALINFOPAGE pGip) +{ + AssertReturn(pGip, NULL); + switch (pGip->enmUseTscDelta) + { + case SUPGIPUSETSCDELTA_NOT_APPLICABLE: return "Not Applicable"; + case SUPGIPUSETSCDELTA_ZERO_CLAIMED: return "Zero Claimed"; + case SUPGIPUSETSCDELTA_PRACTICALLY_ZERO: return "Practically Zero"; + case SUPGIPUSETSCDELTA_ROUGHLY_ZERO: return "Roughly Zero"; + case SUPGIPUSETSCDELTA_NOT_ZERO: return "Not Zero"; + default: return "???"; + } +} + + +/** + * Request for generic VMMR0Entry calls. + */ +typedef struct SUPVMMR0REQHDR +{ + /** The magic. (SUPVMMR0REQHDR_MAGIC) */ + uint32_t u32Magic; + /** The size of the request. */ + uint32_t cbReq; +} SUPVMMR0REQHDR; +/** Pointer to a ring-0 request header. */ +typedef SUPVMMR0REQHDR *PSUPVMMR0REQHDR; +/** the SUPVMMR0REQHDR::u32Magic value (Ethan Iverson - The Bad Plus). */ +#define SUPVMMR0REQHDR_MAGIC UINT32_C(0x19730211) + + +/** For the fast ioctl path. + * @{ + */ +/** @see VMMR0_DO_HM_RUN. */ +#define SUP_VMMR0_DO_HM_RUN 0 +/** @see VMMR0_DO_NEM_RUN */ +#define SUP_VMMR0_DO_NEM_RUN 1 +/** @see VMMR0_DO_NOP */ +#define SUP_VMMR0_DO_NOP 2 +/** @} */ + +/** SUPR3QueryVTCaps capability flags. + * @{ + */ +/** AMD-V support. */ +#define SUPVTCAPS_AMD_V RT_BIT(0) +/** VT-x support. */ +#define SUPVTCAPS_VT_X RT_BIT(1) +/** Nested paging is supported. */ +#define SUPVTCAPS_NESTED_PAGING RT_BIT(2) +/** VT-x: Unrestricted guest execution is supported. */ +#define SUPVTCAPS_VTX_UNRESTRICTED_GUEST RT_BIT(3) +/** VT-x: VMCS shadowing is supported. */ +#define SUPVTCAPS_VTX_VMCS_SHADOWING RT_BIT(4) +/** AMD-V: Virtualized VMSAVE/VMLOAD is supported. */ +#define SUPVTCAPS_AMDV_VIRT_VMSAVE_VMLOAD RT_BIT(5) +/** @} */ + +/** + * Request for generic FNSUPR0SERVICEREQHANDLER calls. + */ +typedef struct SUPR0SERVICEREQHDR +{ + /** The magic. (SUPR0SERVICEREQHDR_MAGIC) */ + uint32_t u32Magic; + /** The size of the request. */ + uint32_t cbReq; +} SUPR0SERVICEREQHDR; +/** Pointer to a ring-0 service request header. */ +typedef SUPR0SERVICEREQHDR *PSUPR0SERVICEREQHDR; +/** the SUPVMMR0REQHDR::u32Magic value (Esbjoern Svensson - E.S.P.). */ +#define SUPR0SERVICEREQHDR_MAGIC UINT32_C(0x19640416) + + +/** + * Creates a single release event semaphore. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param phEvent Where to return the handle to the event semaphore. + */ +SUPDECL(int) SUPSemEventCreate(PSUPDRVSESSION pSession, PSUPSEMEVENT phEvent); + +/** + * Closes a single release event semaphore handle. + * + * @returns VBox status code. + * @retval VINF_OBJECT_DESTROYED if the semaphore was destroyed. + * @retval VINF_SUCCESS if the handle was successfully closed but the semaphore + * object remained alive because of other references. + * + * @param pSession The session handle of the caller. + * @param hEvent The handle. Nil is quietly ignored. + */ +SUPDECL(int) SUPSemEventClose(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent); + +/** + * Signals a single release event semaphore. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEvent The semaphore handle. + */ +SUPDECL(int) SUPSemEventSignal(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent); + +#ifdef IN_RING0 +/** + * Waits on a single release event semaphore, not interruptible. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEvent The semaphore handle. + * @param cMillies The number of milliseconds to wait. + * @remarks Not available in ring-3. + */ +SUPDECL(int) SUPSemEventWait(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint32_t cMillies); +#endif + +/** + * Waits on a single release event semaphore, interruptible. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEvent The semaphore handle. + * @param cMillies The number of milliseconds to wait. + */ +SUPDECL(int) SUPSemEventWaitNoResume(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint32_t cMillies); + +/** + * Waits on a single release event semaphore, interruptible. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEvent The semaphore handle. + * @param uNsTimeout The deadline given on the RTTimeNanoTS() clock. + */ +SUPDECL(int) SUPSemEventWaitNsAbsIntr(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint64_t uNsTimeout); + +/** + * Waits on a single release event semaphore, interruptible. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEvent The semaphore handle. + * @param cNsTimeout The number of nanoseconds to wait. + */ +SUPDECL(int) SUPSemEventWaitNsRelIntr(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint64_t cNsTimeout); + +/** + * Gets the best timeout resolution that SUPSemEventWaitNsAbsIntr and + * SUPSemEventWaitNsAbsIntr can do. + * + * @returns The resolution in nanoseconds. + * @param pSession The session handle of the caller. + */ +SUPDECL(uint32_t) SUPSemEventGetResolution(PSUPDRVSESSION pSession); + + +/** + * Creates a multiple release event semaphore. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param phEventMulti Where to return the handle to the event semaphore. + */ +SUPDECL(int) SUPSemEventMultiCreate(PSUPDRVSESSION pSession, PSUPSEMEVENTMULTI phEventMulti); + +/** + * Closes a multiple release event semaphore handle. + * + * @returns VBox status code. + * @retval VINF_OBJECT_DESTROYED if the semaphore was destroyed. + * @retval VINF_SUCCESS if the handle was successfully closed but the semaphore + * object remained alive because of other references. + * + * @param pSession The session handle of the caller. + * @param hEventMulti The handle. Nil is quietly ignored. + */ +SUPDECL(int) SUPSemEventMultiClose(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti); + +/** + * Signals a multiple release event semaphore. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEventMulti The semaphore handle. + */ +SUPDECL(int) SUPSemEventMultiSignal(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti); + +/** + * Resets a multiple release event semaphore. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEventMulti The semaphore handle. + */ +SUPDECL(int) SUPSemEventMultiReset(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti); + +#ifdef IN_RING0 +/** + * Waits on a multiple release event semaphore, not interruptible. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEventMulti The semaphore handle. + * @param cMillies The number of milliseconds to wait. + * @remarks Not available in ring-3. + */ +SUPDECL(int) SUPSemEventMultiWait(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies); +#endif + +/** + * Waits on a multiple release event semaphore, interruptible. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEventMulti The semaphore handle. + * @param cMillies The number of milliseconds to wait. + */ +SUPDECL(int) SUPSemEventMultiWaitNoResume(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies); + +/** + * Waits on a multiple release event semaphore, interruptible. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEventMulti The semaphore handle. + * @param uNsTimeout The deadline given on the RTTimeNanoTS() clock. + */ +SUPDECL(int) SUPSemEventMultiWaitNsAbsIntr(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint64_t uNsTimeout); + +/** + * Waits on a multiple release event semaphore, interruptible. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEventMulti The semaphore handle. + * @param cNsTimeout The number of nanoseconds to wait. + */ +SUPDECL(int) SUPSemEventMultiWaitNsRelIntr(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint64_t cNsTimeout); + +/** + * Gets the best timeout resolution that SUPSemEventMultiWaitNsAbsIntr and + * SUPSemEventMultiWaitNsRelIntr can do. + * + * @returns The resolution in nanoseconds. + * @param pSession The session handle of the caller. + */ +SUPDECL(uint32_t) SUPSemEventMultiGetResolution(PSUPDRVSESSION pSession); + + +#ifdef IN_RING3 + +/** @defgroup grp_sup_r3 SUP Host Context Ring-3 API + * @{ + */ + +/** + * Installs the support library. + * + * @returns VBox status code. + */ +SUPR3DECL(int) SUPR3Install(void); + +/** + * Uninstalls the support library. + * + * @returns VBox status code. + */ +SUPR3DECL(int) SUPR3Uninstall(void); + +/** + * Trusted main entry point. + * + * This is exported as "TrustedMain" by the dynamic libraries which contains the + * "real" application binary for which the hardened stub is built. The entry + * point is invoked upon successful initialization of the support library and + * runtime. + * + * @returns main kind of exit code. + * @param argc The argument count. + * @param argv The argument vector. + * @param envp The environment vector. + */ +typedef DECLCALLBACKTYPE(int, FNSUPTRUSTEDMAIN,(int argc, char **argv, char **envp)); +/** Pointer to FNSUPTRUSTEDMAIN(). */ +typedef FNSUPTRUSTEDMAIN *PFNSUPTRUSTEDMAIN; + +/** Which operation failed. */ +typedef enum SUPINITOP +{ + /** Invalid. */ + kSupInitOp_Invalid = 0, + /** Installation integrity error. */ + kSupInitOp_Integrity, + /** Setuid related. */ + kSupInitOp_RootCheck, + /** Driver related. */ + kSupInitOp_Driver, + /** IPRT init related. */ + kSupInitOp_IPRT, + /** Miscellaneous. */ + kSupInitOp_Misc, + /** Place holder. */ + kSupInitOp_End +} SUPINITOP; + +/** + * Trusted error entry point, optional. + * + * This is exported as "TrustedError" by the dynamic libraries which contains + * the "real" application binary for which the hardened stub is built. The + * hardened main() must specify SUPSECMAIN_FLAGS_TRUSTED_ERROR when calling + * SUPR3HardenedMain. + * + * @param pszWhere Where the error occurred (function name). + * @param enmWhat Which operation went wrong. + * @param rc The status code. + * @param pszMsgFmt Error message format string. + * @param va The message format arguments. + */ +typedef DECLCALLBACKTYPE(void, FNSUPTRUSTEDERROR,(const char *pszWhere, SUPINITOP enmWhat, int rc, + const char *pszMsgFmt, va_list va)) RT_IPRT_FORMAT_ATTR(4, 0); +/** Pointer to FNSUPTRUSTEDERROR. */ +typedef FNSUPTRUSTEDERROR *PFNSUPTRUSTEDERROR; + +/** + * Secure main. + * + * This is used for the set-user-ID-on-execute binaries on unixy systems + * and when using the open-vboxdrv-via-root-service setup on Windows. + * + * This function will perform the integrity checks of the VirtualBox + * installation, open the support driver, open the root service (later), + * and load the DLL corresponding to \a pszProgName and execute its main + * function. + * + * @returns Return code appropriate for main(). + * + * @param pszProgName The program name. This will be used to figure out which + * DLL/SO/DYLIB to load and execute. + * @param fFlags SUPSECMAIN_FLAGS_XXX. + * @param argc The argument count. + * @param argv The argument vector. + * @param envp The environment vector. + */ +DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int argc, char **argv, char **envp); + +/** @name SUPSECMAIN_FLAGS_XXX - SUPR3HardenedMain flags. + * @{ */ +/** Don't open the device. (Intended for VirtualBox without -startvm.) */ +#define SUPSECMAIN_FLAGS_DONT_OPEN_DEV RT_BIT_32(0) +/** The hardened DLL has a "TrustedError" function (see FNSUPTRUSTEDERROR). */ +#define SUPSECMAIN_FLAGS_TRUSTED_ERROR RT_BIT_32(1) +/** Hack for making VirtualBoxVM use VirtualBox.dylib on Mac OS X. + * @note Not used since 6.0 */ +#define SUPSECMAIN_FLAGS_OSX_VM_APP RT_BIT_32(2) +/** The first process. + * @internal */ +#define SUPSECMAIN_FLAGS_FIRST_PROCESS RT_BIT_32(3) +/** Program binary location mask. */ +#define SUPSECMAIN_FLAGS_LOC_MASK UINT32_C(0x00000030) +/** Default binary location is the application binary directory. Does + * not need to be given explicitly (it's 0). */ +#define SUPSECMAIN_FLAGS_LOC_APP_BIN UINT32_C(0x00000000) +/** The binary is located in the testcase directory instead of the + * default application binary directory. */ +#define SUPSECMAIN_FLAGS_LOC_TESTCASE UINT32_C(0x00000010) +/** The binary is located in a nested application bundle under Resources/ in the + * main Mac OS X application (think Resources/VirtualBoxVM.app). */ +#define SUPSECMAIN_FLAGS_LOC_OSX_HLP_APP UINT32_C(0x00000020) +/** Force driverless mode. */ +#define SUPSECMAIN_FLAGS_DRIVERLESS RT_BIT_32(8) +/** Driverless IEM-only mode is allowed, so don't fail fatally just because + * the VBox support driver is unavailable. */ +#define SUPSECMAIN_FLAGS_DRIVERLESS_IEM_ALLOWED RT_BIT_32(9) +#ifdef VBOX_WITH_DRIVERLESS_NEM_FALLBACK +/** Driverless NEM is a fallback posibility, so don't fail fatally just + * because the VBox support driver is unavailable. + * This may imply checking NEM requirements, depending on the host. + * @note Not supported on Windows. */ +# define SUPSECMAIN_FLAGS_DRIVERLESS_NEM_FALLBACK RT_BIT_32(10) +#endif + +/** @} */ + +/** + * Initializes the support library. + * + * Each successful call to SUPR3Init() or SUPR3InitEx must be countered by a + * call to SUPR3Term(false). + * + * @returns VBox status code. + * @param ppSession Where to store the session handle. Defaults to NULL. + */ +SUPR3DECL(int) SUPR3Init(PSUPDRVSESSION *ppSession); + +/** + * Initializes the support library, extended version. + * + * Each successful call to SUPR3Init() or SUPR3InitEx must be countered by a + * call to SUPR3Term(false). + * + * @returns VBox status code. + * @param fFlags SUPR3INIT_F_XXX + * @param ppSession Where to store the session handle. Defaults to NULL. + */ +SUPR3DECL(int) SUPR3InitEx(uint32_t fFlags, PSUPDRVSESSION *ppSession); +/** @name SUPR3INIT_F_XXX - Flags for SUPR3InitEx + * @{ */ +/** Unrestricted access. */ +#define SUPR3INIT_F_UNRESTRICTED RT_BIT_32(0) +/** Limited access (for Main). */ +#define SUPR3INIT_F_LIMITED RT_BIT_32(1) +/** Force driverless mode. */ +#define SUPR3INIT_F_DRIVERLESS RT_BIT_32(2) +/** Allow driverless IEM mode if the VBox support driver is unavailable. + * @see SUPSECMAIN_FLAGS_DRIVERLESS_IEM_ALLOWED */ +#define SUPR3INIT_F_DRIVERLESS_IEM_ALLOWED RT_BIT_32(3) +#ifdef VBOX_WITH_DRIVERLESS_NEM_FALLBACK +/** Allow driverless NEM mode as fallback if the VBox support driver is unavailable. + * @see SUPSECMAIN_FLAGS_DRIVERLESS_NEM_FALLBACK */ +# define SUPR3INIT_F_DRIVERLESS_NEM_FALLBACK RT_BIT_32(4) +#endif +/** Mask with all the flags that may trigger driverless mode. */ +#ifdef VBOX_WITH_DRIVERLESS_NEM_FALLBACK +# define SUPR3INIT_F_DRIVERLESS_MASK UINT32_C(0x0000001c) +#else +# define SUPR3INIT_F_DRIVERLESS_MASK UINT32_C(0x0000000c) +#endif +/** @} */ + +/** + * Terminates the support library. + * + * @returns VBox status code. + * @param fForced Forced termination. This means to ignore the + * init call count and just terminated. + */ +#ifdef __cplusplus +SUPR3DECL(int) SUPR3Term(bool fForced = false); +#else +SUPR3DECL(int) SUPR3Term(int fForced); +#endif + +/** + * Check if the support library is operating in driverless mode. + * + * @returns true/false accordingly. + * @see SUPR3INIT_F_DRIVERLESS_IEM_ALLOWED, + * SUPR3INIT_F_DRIVERLESS_NEM_FALLBACK + */ +SUPR3DECL(bool) SUPR3IsDriverless(void); + +/** + * Sets the ring-0 VM handle for use with fast IOCtls. + * + * @returns VBox status code. + * @param pVMR0 The ring-0 VM handle. + * NIL_RTR0PTR can be used to unset the handle when the + * VM is about to be destroyed. + */ +SUPR3DECL(int) SUPR3SetVMForFastIOCtl(PVMR0 pVMR0); + +/** + * Calls the HC R0 VMM entry point. + * See VMMR0Entry() for more details. + * + * @returns error code specific to uFunction. + * @param pVMR0 Pointer to the Ring-0 (Host Context) mapping of the VM structure. + * @param idCpu The virtual CPU ID. + * @param uOperation Operation to execute. + * @param pvArg Argument. + */ +SUPR3DECL(int) SUPR3CallVMMR0(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, void *pvArg); + +/** + * Variant of SUPR3CallVMMR0, except that this takes the fast ioclt path + * regardsless of compile-time defaults. + * + * @returns VBox status code. + * @param pVMR0 The ring-0 VM handle. + * @param uOperation The operation; only the SUP_VMMR0_DO_* ones are valid. + * @param idCpu The virtual CPU ID. + */ +SUPR3DECL(int) SUPR3CallVMMR0Fast(PVMR0 pVMR0, unsigned uOperation, VMCPUID idCpu); + +/** + * Calls the HC R0 VMM entry point, in a safer but slower manner than + * SUPR3CallVMMR0. When entering using this call the R0 components can call + * into the host kernel (i.e. use the SUPR0 and RT APIs). + * + * See VMMR0Entry() for more details. + * + * @returns error code specific to uFunction. + * @param pVMR0 Pointer to the Ring-0 (Host Context) mapping of the VM structure. + * @param idCpu The virtual CPU ID. + * @param uOperation Operation to execute. + * @param u64Arg Constant argument. + * @param pReqHdr Pointer to a request header. Optional. + * This will be copied in and out of kernel space. There currently is a size + * limit on this, just below 4KB. + */ +SUPR3DECL(int) SUPR3CallVMMR0Ex(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr); + +/** + * Calls a ring-0 service. + * + * The operation and the request packet is specific to the service. + * + * @returns error code specific to uFunction. + * @param pszService The service name. + * @param cchService The length of the service name. + * @param uOperation The request number. + * @param u64Arg Constant argument. + * @param pReqHdr Pointer to a request header. Optional. + * This will be copied in and out of kernel space. There currently is a size + * limit on this, just below 4KB. + */ +SUPR3DECL(int) SUPR3CallR0Service(const char *pszService, size_t cchService, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr); + +/** Which logger. */ +typedef enum SUPLOGGER +{ + SUPLOGGER_DEBUG = 1, + SUPLOGGER_RELEASE +} SUPLOGGER; + +/** + * Changes the settings of the specified ring-0 logger. + * + * @returns VBox status code. + * @param enmWhich Which logger. + * @param pszFlags The flags settings. + * @param pszGroups The groups settings. + * @param pszDest The destination specificier. + */ +SUPR3DECL(int) SUPR3LoggerSettings(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest); + +/** + * Creates a ring-0 logger instance. + * + * @returns VBox status code. + * @param enmWhich Which logger to create. + * @param pszFlags The flags settings. + * @param pszGroups The groups settings. + * @param pszDest The destination specificier. + */ +SUPR3DECL(int) SUPR3LoggerCreate(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest); + +/** + * Destroys a ring-0 logger instance. + * + * @returns VBox status code. + * @param enmWhich Which logger. + */ +SUPR3DECL(int) SUPR3LoggerDestroy(SUPLOGGER enmWhich); + +/** + * Queries the paging mode of the host OS. + * + * @returns The paging mode. + */ +SUPR3DECL(SUPPAGINGMODE) SUPR3GetPagingMode(void); + +/** + * Allocate zero-filled pages. + * + * Use this to allocate a number of pages suitable for seeding / locking. + * Call SUPR3PageFree() to free the pages once done with them. + * + * @returns VBox status. + * @param cPages Number of pages to allocate. + * @param fFlags SUP_PAGE_ALLOC_F_XXX + * @param ppvPages Where to store the base pointer to the allocated pages. + */ +SUPR3DECL(int) SUPR3PageAlloc(size_t cPages, uint32_t fFlags, void **ppvPages); + +/** @name SUP_PAGE_ALLOC_F_XXX - SUPR3PageAlloc flags. + * @{ */ +/** Use large pages if available. */ +#define SUP_PAGE_ALLOC_F_LARGE_PAGES RT_BIT_32(0) +/** Advice that the allocated pages will probably be locked by + * RTR0MemObjLockUser later, so play nice if needed. */ +#define SUP_PAGE_ALLOC_F_FOR_LOCKING RT_BIT_32(1) +/** Mask of valid flags. */ +#define SUP_PAGE_ALLOC_F_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** + * Frees pages allocated with SUPR3PageAlloc(). + * + * @returns VBox status. + * @param pvPages Pointer returned by SUPR3PageAlloc(). + * @param cPages Number of pages that was allocated. + */ +SUPR3DECL(int) SUPR3PageFree(void *pvPages, size_t cPages); + +/** + * Allocate non-zeroed, locked, pages with user and, optionally, kernel + * mappings. + * + * Use SUPR3PageFreeEx() to free memory allocated with this function. + * + * @returns VBox status code. + * @param cPages The number of pages to allocate. + * @param fFlags Flags, reserved. Must be zero. + * @param ppvPages Where to store the address of the user mapping. + * @param pR0Ptr Where to store the address of the kernel mapping. + * NULL if no kernel mapping is desired. + * @param paPages Where to store the physical addresses of each page. + * Optional. + */ +SUPR3DECL(int) SUPR3PageAllocEx(size_t cPages, uint32_t fFlags, void **ppvPages, PRTR0PTR pR0Ptr, PSUPPAGE paPages); + +/** + * Maps a portion of a ring-3 only allocation into kernel space. + * + * @returns VBox status code. + * + * @param pvR3 The address SUPR3PageAllocEx return. + * @param off Offset to start mapping at. Must be page aligned. + * @param cb Number of bytes to map. Must be page aligned. + * @param fFlags Flags, must be zero. + * @param pR0Ptr Where to store the address on success. + * + */ +SUPR3DECL(int) SUPR3PageMapKernel(void *pvR3, uint32_t off, uint32_t cb, uint32_t fFlags, PRTR0PTR pR0Ptr); + +/** + * Changes the protection of + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if the OS doesn't allow us to change page level + * protection. See also RTR0MemObjProtect. + * + * @param pvR3 The ring-3 address SUPR3PageAllocEx returned. + * @param R0Ptr The ring-0 address SUPR3PageAllocEx returned if it + * is desired that the corresponding ring-0 page + * mappings should change protection as well. Pass + * NIL_RTR0PTR if the ring-0 pages should remain + * unaffected. + * @param off Offset to start at which to start chagning the page + * level protection. Must be page aligned. + * @param cb Number of bytes to change. Must be page aligned. + * @param fProt The new page level protection, either a combination + * of RTMEM_PROT_READ, RTMEM_PROT_WRITE and + * RTMEM_PROT_EXEC, or just RTMEM_PROT_NONE. + */ +SUPR3DECL(int) SUPR3PageProtect(void *pvR3, RTR0PTR R0Ptr, uint32_t off, uint32_t cb, uint32_t fProt); + +/** + * Free pages allocated by SUPR3PageAllocEx. + * + * @returns VBox status code. + * @param pvPages The address of the user mapping. + * @param cPages The number of pages. + */ +SUPR3DECL(int) SUPR3PageFreeEx(void *pvPages, size_t cPages); + +/** + * Allocated memory with page aligned memory with a contiguous and locked physical + * memory backing below 4GB. + * + * @returns Pointer to the allocated memory (virtual address). + * *pHCPhys is set to the physical address of the memory. + * If ppvR0 isn't NULL, *ppvR0 is set to the ring-0 mapping. + * The returned memory must be freed using SUPR3ContFree(). + * @returns NULL on failure. + * @param cPages Number of pages to allocate. + * @param pR0Ptr Where to store the ring-0 mapping of the allocation. (optional) + * @param pHCPhys Where to store the physical address of the memory block. + * + * @remark This 2nd version of this API exists because we're not able to map the + * ring-3 mapping executable on WIN64. This is a serious problem in regard to + * the world switchers. + */ +SUPR3DECL(void *) SUPR3ContAlloc(size_t cPages, PRTR0PTR pR0Ptr, PRTHCPHYS pHCPhys); + +/** + * Frees memory allocated with SUPR3ContAlloc(). + * + * @returns VBox status code. + * @param pv Pointer to the memory block which should be freed. + * @param cPages Number of pages to be freed. + */ +SUPR3DECL(int) SUPR3ContFree(void *pv, size_t cPages); + +/** + * Allocated non contiguous physical memory below 4GB. + * + * The memory isn't zeroed. + * + * @returns VBox status code. + * @returns NULL on failure. + * @param cPages Number of pages to allocate. + * @param ppvPages Where to store the pointer to the allocated memory. + * The pointer stored here on success must be passed to + * SUPR3LowFree when the memory should be released. + * @param ppvPagesR0 Where to store the ring-0 pointer to the allocated memory. optional. + * @param paPages Where to store the physical addresses of the individual pages. + */ +SUPR3DECL(int) SUPR3LowAlloc(size_t cPages, void **ppvPages, PRTR0PTR ppvPagesR0, PSUPPAGE paPages); + +/** + * Frees memory allocated with SUPR3LowAlloc(). + * + * @returns VBox status code. + * @param pv Pointer to the memory block which should be freed. + * @param cPages Number of pages that was allocated. + */ +SUPR3DECL(int) SUPR3LowFree(void *pv, size_t cPages); + +/** + * Load a module into R0 HC. + * + * This will verify the file integrity in a similar manner as + * SUPR3HardenedVerifyFile before loading it. + * + * @returns VBox status code. + * @param pszFilename The path to the image file. + * @param pszModule The module name. Max 32 bytes. + * @param ppvImageBase Where to store the image address. + * @param pErrInfo Where to return extended error information. + * Optional. + */ +SUPR3DECL(int) SUPR3LoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase, PRTERRINFO pErrInfo); + +/** + * Load a module into R0 HC. + * + * This will verify the file integrity in a similar manner as + * SUPR3HardenedVerifyFile before loading it. + * + * @returns VBox status code. + * @param pszFilename The path to the image file. + * @param pszModule The module name. Max 32 bytes. + * @param pszSrvReqHandler The name of the service request handler entry + * point. See FNSUPR0SERVICEREQHANDLER. + * @param ppvImageBase Where to store the image address. + */ +SUPR3DECL(int) SUPR3LoadServiceModule(const char *pszFilename, const char *pszModule, + const char *pszSrvReqHandler, void **ppvImageBase); + +/** + * Frees a R0 HC module. + * + * @returns VBox status code. + * @param pvImageBase The base address of the image to free. + * @remark This will not actually 'free' the module, there are of course usage counting. + */ +SUPR3DECL(int) SUPR3FreeModule(void *pvImageBase); + +/** + * Lock down the module loader interface. + * + * This will lock down the module loader interface. No new modules can be + * loaded and all loaded modules can no longer be freed. + * + * @returns VBox status code. + * @param pErrInfo Where to return extended error information. + * Optional. + */ +SUPR3DECL(int) SUPR3LockDownLoader(PRTERRINFO pErrInfo); + +/** + * Get the address of a symbol in a ring-0 module. + * + * @returns VBox status code. + * @param pvImageBase The base address of the image to search. + * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a + * ordinal value rather than a string pointer. + * @param ppvValue Where to store the symbol value. + */ +SUPR3DECL(int) SUPR3GetSymbolR0(void *pvImageBase, const char *pszSymbol, void **ppvValue); + +/** + * Load R0 HC VMM code. + * + * @returns VBox status code. + * @deprecated Use SUPR3LoadModule(pszFilename, "VMMR0.r0", &pvImageBase) + * @param pszFilename Full path to the VMMR0.r0 file (silly). + * @param pErrInfo Where to return extended error information. + * Optional. + */ +SUPR3DECL(int) SUPR3LoadVMM(const char *pszFilename, PRTERRINFO pErrInfo); + +/** + * Unloads R0 HC VMM code. + * + * @returns VBox status code. + * @deprecated Use SUPR3FreeModule(). + */ +SUPR3DECL(int) SUPR3UnloadVMM(void); + +/** + * Get the physical address of the GIP. + * + * @returns VBox status code. + * @param pHCPhys Where to store the physical address of the GIP. + */ +SUPR3DECL(int) SUPR3GipGetPhys(PRTHCPHYS pHCPhys); + +/** + * Initializes only the bits relevant for the SUPR3HardenedVerify* APIs. + * + * This is for users that don't necessarily need to initialize the whole of + * SUPLib. There is no harm in calling this one more time. + * + * @returns VBox status code. + * @remarks Currently not counted, so only call once. + */ +SUPR3DECL(int) SUPR3HardenedVerifyInit(void); + +/** + * Reverses the effect of SUPR3HardenedVerifyInit if SUPR3InitEx hasn't been + * called. + * + * Ignored if the support library was initialized using SUPR3Init or + * SUPR3InitEx. + * + * @returns VBox status code. + */ +SUPR3DECL(int) SUPR3HardenedVerifyTerm(void); + +/** + * Verifies the integrity of a file, and optionally opens it. + * + * The integrity check is for whether the file is suitable for loading into + * the hypervisor or VM process. The integrity check may include verifying + * the authenticode/elfsign/whatever signature of the file, which can take + * a little while. + * + * @returns VBox status code. On failure it will have printed a LogRel message. + * + * @param pszFilename The file. + * @param pszWhat For the LogRel on failure. + * @param phFile Where to store the handle to the opened file. This is optional, pass NULL + * if the file should not be opened. + * @deprecated Write a new one. + */ +SUPR3DECL(int) SUPR3HardenedVerifyFile(const char *pszFilename, const char *pszWhat, PRTFILE phFile); + +/** + * Verifies the integrity of a the current process, including the image + * location and that the invocation was absolute. + * + * This must currently be called after initializing the runtime. The intended + * audience is set-uid-to-root applications, root services and similar. + * + * @returns VBox status code. On failure + * message. + * @param pszArgv0 The first argument to main(). + * @param fInternal Set this to @c true if this is an internal + * VirtualBox application. Otherwise pass @c false. + * @param pErrInfo Where to return extended error information. + */ +SUPR3DECL(int) SUPR3HardenedVerifySelf(const char *pszArgv0, bool fInternal, PRTERRINFO pErrInfo); + +/** + * Verifies the integrity of an installation directory. + * + * The integrity check verifies that the directory cannot be tampered with by + * normal users on the system. On Unix this translates to root ownership and + * no symbolic linking. + * + * @returns VBox status code. On failure a message will be stored in @a pszErr. + * + * @param pszDirPath The directory path. + * @param fRecursive Whether the check should be recursive or + * not. When set, all sub-directores will be checked, + * including files (@a fCheckFiles is ignored). + * @param fCheckFiles Whether to apply the same basic integrity check to + * the files in the directory as the directory itself. + * @param pErrInfo Where to return extended error information. + * Optional. + */ +SUPR3DECL(int) SUPR3HardenedVerifyDir(const char *pszDirPath, bool fRecursive, bool fCheckFiles, PRTERRINFO pErrInfo); + +/** + * Verifies the integrity of a plug-in module. + * + * This is similar to SUPR3HardenedLdrLoad, except it does not load the module + * and that the module does not have to be shipped with VirtualBox. + * + * @returns VBox status code. On failure a message will be stored in @a pszErr. + * + * @param pszFilename The filename of the plug-in module (nothing can be + * omitted here). + * @param pErrInfo Where to return extended error information. + * Optional. + */ +SUPR3DECL(int) SUPR3HardenedVerifyPlugIn(const char *pszFilename, PRTERRINFO pErrInfo); + +/** + * Same as RTLdrLoad() but will verify the files it loads (hardened builds). + * + * Will add dll suffix if missing and try load the file. + * + * @returns iprt status code. + * @param pszFilename Image filename. This must have a path. + * @param phLdrMod Where to store the handle to the loaded module. + * @param fFlags See RTLDRLOAD_FLAGS_XXX. + * @param pErrInfo Where to return extended error information. + * Optional. + */ +SUPR3DECL(int) SUPR3HardenedLdrLoad(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo); + +/** + * Same as RTLdrLoadAppPriv() but it will verify the files it loads (hardened + * builds). + * + * Will add dll suffix to the file if missing, then look for it in the + * architecture dependent application directory. + * + * @returns iprt status code. + * @param pszFilename Image filename. + * @param phLdrMod Where to store the handle to the loaded module. + * @param fFlags See RTLDRLOAD_FLAGS_XXX. + * @param pErrInfo Where to return extended error information. + * Optional. + */ +SUPR3DECL(int) SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo); + +/** + * Same as RTLdrLoad() but will verify the files it loads (hardened builds). + * + * This differs from SUPR3HardenedLdrLoad() in that it can load modules from + * extension packs and anything else safely installed on the system, provided + * they pass the hardening tests. + * + * @returns iprt status code. + * @param pszFilename The full path to the module, with extension. + * @param phLdrMod Where to store the handle to the loaded module. + * @param pErrInfo Where to return extended error information. + * Optional. + */ +SUPR3DECL(int) SUPR3HardenedLdrLoadPlugIn(const char *pszFilename, PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo); + +/** + * Check if the host kernel can run in VMX root mode. + * + * @returns VINF_SUCCESS if supported, error code indicating why if not. + * @param ppszWhy Where to return an explanatory message on failure. + */ +SUPR3DECL(int) SUPR3QueryVTxSupported(const char **ppszWhy); + +/** + * Return VT-x/AMD-V capabilities. + * + * @returns VINF_SUCCESS if supported, error code indicating why if not. + * @param pfCaps Pointer to capability dword (out). + * @todo Intended for main, which means we need to relax the privilege requires + * when accessing certain vboxdrv functions. + */ +SUPR3DECL(int) SUPR3QueryVTCaps(uint32_t *pfCaps); + +/** + * Check if NEM is supported when no VT-x/AMD-V is indicated by the CPU. + * + * This is really only for the windows case where we're running in a root + * partition and isn't allowed to use the hardware directly. + * + * @returns True if NEM API support, false if not. + */ +SUPR3DECL(bool) SUPR3IsNemSupportedWhenNoVtxOrAmdV(void); + +/** + * Open the tracer. + * + * @returns VBox status code. + * @param uCookie Cookie identifying the tracer we expect to talk to. + * @param uArg Tracer specific open argument. + */ +SUPR3DECL(int) SUPR3TracerOpen(uint32_t uCookie, uintptr_t uArg); + +/** + * Closes the tracer. + * + * @returns VBox status code. + */ +SUPR3DECL(int) SUPR3TracerClose(void); + +/** + * Perform an I/O request on the tracer. + * + * @returns VBox status. + * @param uCmd The tracer command. + * @param uArg The argument. + * @param piRetVal Where to store the tracer return value. + */ +SUPR3DECL(int) SUPR3TracerIoCtl(uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal); + +/** + * Registers the user module with the tracer. + * + * @returns VBox status code. + * @param hModNative Native module handle. Pass ~(uintptr_t)0 if not + * at hand. + * @param pszModule The module name. + * @param pVtgHdr The VTG header. + * @param uVtgHdrAddr The address to which the VTG header is loaded + * in the relevant execution context. + * @param fFlags See SUP_TRACER_UMOD_FLAGS_XXX + */ +SUPR3DECL(int) SUPR3TracerRegisterModule(uintptr_t hModNative, const char *pszModule, struct VTGOBJHDR *pVtgHdr, + RTUINTPTR uVtgHdrAddr, uint32_t fFlags); + +/** + * Deregisters the user module. + * + * @returns VBox status code. + * @param pVtgHdr The VTG header. + */ +SUPR3DECL(int) SUPR3TracerDeregisterModule(struct VTGOBJHDR *pVtgHdr); + +/** + * Fire the probe. + * + * @param pVtgProbeLoc The probe location record. + * @param uArg0 Raw probe argument 0. + * @param uArg1 Raw probe argument 1. + * @param uArg2 Raw probe argument 2. + * @param uArg3 Raw probe argument 3. + * @param uArg4 Raw probe argument 4. + */ +SUPDECL(void) SUPTracerFireProbe(struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2, + uintptr_t uArg3, uintptr_t uArg4); + +/** + * Attempts to read the value of an MSR. + * + * @returns VBox status code. + * @param uMsr The MSR to read. + * @param idCpu The CPU to read it on, NIL_RTCPUID if it doesn't + * matter which CPU. + * @param puValue Where to return the value. + * @param pfGp Where to store the \#GP indicator for the read + * operation. + */ +SUPR3DECL(int) SUPR3MsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue, bool *pfGp); + +/** + * Attempts to write to an MSR. + * + * @returns VBox status code. + * @param uMsr The MSR to write to. + * @param idCpu The CPU to wrtie it on, NIL_RTCPUID if it + * doesn't matter which CPU. + * @param uValue The value to write. + * @param pfGp Where to store the \#GP indicator for the write + * operation. + */ +SUPR3DECL(int) SUPR3MsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue, bool *pfGp); + +/** + * Attempts to modify the value of an MSR. + * + * @returns VBox status code. + * @param uMsr The MSR to modify. + * @param idCpu The CPU to modify it on, NIL_RTCPUID if it + * doesn't matter which CPU. + * @param fAndMask The bits to keep in the current MSR value. + * @param fOrMask The bits to set before writing. + * @param pResult The result buffer. + */ +SUPR3DECL(int) SUPR3MsrProberModify(uint32_t uMsr, RTCPUID idCpu, uint64_t fAndMask, uint64_t fOrMask, + PSUPMSRPROBERMODIFYRESULT pResult); + +/** + * Attempts to modify the value of an MSR, extended version. + * + * @returns VBox status code. + * @param uMsr The MSR to modify. + * @param idCpu The CPU to modify it on, NIL_RTCPUID if it + * doesn't matter which CPU. + * @param fAndMask The bits to keep in the current MSR value. + * @param fOrMask The bits to set before writing. + * @param fFaster If set to @c true some cache/tlb invalidation is + * skipped, otherwise behave like + * SUPR3MsrProberModify. + * @param pResult The result buffer. + */ +SUPR3DECL(int) SUPR3MsrProberModifyEx(uint32_t uMsr, RTCPUID idCpu, uint64_t fAndMask, uint64_t fOrMask, bool fFaster, + PSUPMSRPROBERMODIFYRESULT pResult); + +/** + * Resume built-in keyboard on MacBook Air and Pro hosts. + * + * @returns VBox status code. + */ +SUPR3DECL(int) SUPR3ResumeSuspendedKeyboards(void); + +/** + * Measure the TSC-delta for the specified CPU. + * + * @returns VBox status code. + * @param idCpu The CPU to measure the TSC-delta for. + * @param fAsync Whether the measurement is asynchronous, returns + * immediately after signalling a measurement + * request. + * @param fForce Whether to perform a measurement even if the + * specified CPU has a (possibly) valid TSC delta. + * @param cRetries Number of times to retry failed delta + * measurements. + * @param cMsWaitRetry Number of milliseconds to wait between retries. + */ +SUPR3DECL(int) SUPR3TscDeltaMeasure(RTCPUID idCpu, bool fAsync, bool fForce, uint8_t cRetries, uint8_t cMsWaitRetry); + +/** + * Reads the delta-adjust TSC value. + * + * @returns VBox status code. + * @param puTsc Where to store the read TSC value. + * @param pidApic Where to store the APIC ID of the CPU where the TSC + * was read (optional, can be NULL). + */ +SUPR3DECL(int) SUPR3ReadTsc(uint64_t *puTsc, uint16_t *pidApic); + +/** + * Modifies the GIP flags. + * + * @returns VBox status code. + * @param fOrMask The OR mask of the GIP flags, see SUPGIP_FLAGS_XXX. + * @param fAndMask The AND mask of the GIP flags, see SUPGIP_FLAGS_XXX. + */ +SUPR3DECL(int) SUPR3GipSetFlags(uint32_t fOrMask, uint32_t fAndMask); + +/** + * Return processor microcode revision, if applicable. + * + * @returns VINF_SUCCESS if supported, error code indicating why if not. + * @param puMicrocodeRev Pointer to microcode revision dword (out). + */ +SUPR3DECL(int) SUPR3QueryMicrocodeRev(uint32_t *puMicrocodeRev); + +/** + * Gets hardware-virtualization MSRs of the CPU, if available. + * + * @returns VINF_SUCCESS if available, error code indicating why if not. + * @param pHwvirtMsrs Where to store the hardware-virtualization MSRs. + * @param fForceRequery Whether to force complete re-querying of MSRs (rather + * than fetching cached values when available). + */ +SUPR3DECL(int) SUPR3GetHwvirtMsrs(PSUPHWVIRTMSRS pHwvirtMsrs, bool fForceRequery); + +/** @} */ +#endif /* IN_RING3 */ + + +/** @name User mode module flags (SUPR3TracerRegisterModule & SUP_IOCTL_TRACER_UMOD_REG). + * @{ */ +/** Executable image. */ +#define SUP_TRACER_UMOD_FLAGS_EXE UINT32_C(1) +/** Shared library (DLL, DYLIB, SO, etc). */ +#define SUP_TRACER_UMOD_FLAGS_SHARED UINT32_C(2) +/** Image type mask. */ +#define SUP_TRACER_UMOD_FLAGS_TYPE_MASK UINT32_C(3) +/** @} */ + + +#ifdef IN_RING0 +/** @defgroup grp_sup_r0 SUP Host Context Ring-0 API + * @{ + */ + +/** + * Security objectype. + */ +typedef enum SUPDRVOBJTYPE +{ + /** The usual invalid object. */ + SUPDRVOBJTYPE_INVALID = 0, + /** A Virtual Machine instance. */ + SUPDRVOBJTYPE_VM, + /** Internal network. */ + SUPDRVOBJTYPE_INTERNAL_NETWORK, + /** Internal network interface. */ + SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE, + /** Single release event semaphore. */ + SUPDRVOBJTYPE_SEM_EVENT, + /** Multiple release event semaphore. */ + SUPDRVOBJTYPE_SEM_EVENT_MULTI, + /** Raw PCI device. */ + SUPDRVOBJTYPE_RAW_PCI_DEVICE, + /** The first invalid object type in this end. */ + SUPDRVOBJTYPE_END, + /** The usual 32-bit type size hack. */ + SUPDRVOBJTYPE_32_BIT_HACK = 0x7ffffff +} SUPDRVOBJTYPE; + +/** + * Object destructor callback. + * This is called for reference counted objectes when the count reaches 0. + * + * @param pvObj The object pointer. + * @param pvUser1 The first user argument. + * @param pvUser2 The second user argument. + */ +typedef DECLCALLBACKTYPE(void, FNSUPDRVDESTRUCTOR,(void *pvObj, void *pvUser1, void *pvUser2)); +/** Pointer to a FNSUPDRVDESTRUCTOR(). */ +typedef FNSUPDRVDESTRUCTOR *PFNSUPDRVDESTRUCTOR; + +/** + * Service request callback function. + * + * @returns VBox status code. + * @param pSession The caller's session. + * @param uOperation The operation identifier. + * @param u64Arg 64-bit integer argument. + * @param pReqHdr The request header. Input / Output. Optional. + */ +typedef DECLCALLBACKTYPE(int, FNSUPR0SERVICEREQHANDLER,(PSUPDRVSESSION pSession, uint32_t uOperation, + uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)); +/** Pointer to a FNR0SERVICEREQHANDLER(). */ +typedef R0PTRTYPE(FNSUPR0SERVICEREQHANDLER *) PFNSUPR0SERVICEREQHANDLER; + +/** + * Symbol entry for a wrapped module (SUPLDRWRAPPEDMODULE). + */ +typedef struct SUPLDRWRAPMODSYMBOL +{ + /** The symbol namel. */ + const char *pszSymbol; + /** The symbol address/value. */ + PFNRT pfnValue; +} SUPLDRWRAPMODSYMBOL; +/** Pointer to a symbol entry for a wrapped module. */ +typedef SUPLDRWRAPMODSYMBOL const *PCSUPLDRWRAPMODSYMBOL; + +/** + * Registration structure for SUPR0LdrRegisterWrapperModule. + * + * This is used to register a .r0 module when loaded manually as a native kernel + * module/extension/driver/whatever. + */ +typedef struct SUPLDRWRAPPEDMODULE +{ + /** Magic value (SUPLDRWRAPPEDMODULE_MAGIC). */ + uint32_t uMagic; + /** The structure version. */ + uint16_t uVersion; + /** SUPLDRWRAPPEDMODULE_F_XXX. */ + uint16_t fFlags; + + /** As close as possible to the start of the image. */ + void *pvImageStart; + /** As close as possible to the end of the image. */ + void *pvImageEnd; + + /** @name Standar entry points + * @{ */ + /** Pointer to the module initialization function (optional). */ + DECLCALLBACKMEMBER(int, pfnModuleInit,(void *hMod)); + /** Pointer to the module termination function (optional). */ + DECLCALLBACKMEMBER(void, pfnModuleTerm,(void *hMod)); + /** The VMMR0EntryFast entry point for VMMR0. */ + PFNRT pfnVMMR0EntryFast; + /** The VMMR0EntryEx entry point for VMMR0. */ + PFNRT pfnVMMR0EntryEx; + /** The service request handler entry point. */ + PFNSUPR0SERVICEREQHANDLER pfnServiceReqHandler; + /** @} */ + + /** The symbol table. */ + PCSUPLDRWRAPMODSYMBOL paSymbols; + /** Number of symbols. */ + uint32_t cSymbols; + + /** The normal VBox module name. */ + char szName[32]; + /** Repeating the magic value here (SUPLDRWRAPPEDMODULE_MAGIC). */ + uint32_t uEndMagic; +} SUPLDRWRAPPEDMODULE; +/** Pointer to the wrapped module registration structure. */ +typedef SUPLDRWRAPPEDMODULE const *PCSUPLDRWRAPPEDMODULE; + +/** Magic value for the wrapped module structure (Doris lessing). */ +#define SUPLDRWRAPPEDMODULE_MAGIC UINT32_C(0x19191117) +/** Current SUPLDRWRAPPEDMODULE structure version. */ +#define SUPLDRWRAPPEDMODULE_VERSION UINT16_C(0x0001) + +/** Set if this is the VMMR0 module. */ +#define SUPLDRWRAPPEDMODULE_F_VMMR0 UINT16_C(0x0001) + + +SUPR0DECL(void *) SUPR0ObjRegister(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType, PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2); +SUPR0DECL(int) SUPR0ObjAddRef(void *pvObj, PSUPDRVSESSION pSession); +SUPR0DECL(int) SUPR0ObjAddRefEx(void *pvObj, PSUPDRVSESSION pSession, bool fNoBlocking); +SUPR0DECL(int) SUPR0ObjRelease(void *pvObj, PSUPDRVSESSION pSession); +SUPR0DECL(int) SUPR0ObjVerifyAccess(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName); + +SUPR0DECL(PVM) SUPR0GetSessionVM(PSUPDRVSESSION pSession); +SUPR0DECL(PGVM) SUPR0GetSessionGVM(PSUPDRVSESSION pSession); +SUPR0DECL(int) SUPR0SetSessionVM(PSUPDRVSESSION pSession, PGVM pGVM, PVM pVM); +SUPR0DECL(RTUID) SUPR0GetSessionUid(PSUPDRVSESSION pSession); + +SUPR0DECL(int) SUPR0LockMem(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t cPages, PRTHCPHYS paPages); +SUPR0DECL(int) SUPR0UnlockMem(PSUPDRVSESSION pSession, RTR3PTR pvR3); +SUPR0DECL(int) SUPR0ContAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS pHCPhys); +SUPR0DECL(int) SUPR0ContFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr); +SUPR0DECL(int) SUPR0LowAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS paPages); +SUPR0DECL(int) SUPR0LowFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr); +SUPR0DECL(int) SUPR0MemAlloc(PSUPDRVSESSION pSession, uint32_t cb, PRTR0PTR ppvR0, PRTR3PTR ppvR3); +SUPR0DECL(int) SUPR0MemGetPhys(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr, PSUPPAGE paPages); +SUPR0DECL(int) SUPR0MemFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr); +SUPR0DECL(int) SUPR0PageAllocEx(PSUPDRVSESSION pSession, uint32_t cPages, uint32_t fFlags, PRTR3PTR ppvR3, PRTR0PTR ppvR0, PRTHCPHYS paPages); +SUPR0DECL(int) SUPR0PageMapKernel(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t offSub, uint32_t cbSub, uint32_t fFlags, PRTR0PTR ppvR0); +SUPR0DECL(int) SUPR0PageProtect(PSUPDRVSESSION pSession, RTR3PTR pvR3, RTR0PTR pvR0, uint32_t offSub, uint32_t cbSub, uint32_t fProt); +SUPR0DECL(int) SUPR0PageFree(PSUPDRVSESSION pSession, RTR3PTR pvR3); +SUPR0DECL(int) SUPR0GipMap(PSUPDRVSESSION pSession, PRTR3PTR ppGipR3, PRTHCPHYS pHCPhysGip); +SUPR0DECL(int) SUPR0LdrLock(PSUPDRVSESSION pSession); +SUPR0DECL(int) SUPR0LdrUnlock(PSUPDRVSESSION pSession); +SUPR0DECL(bool) SUPR0LdrIsLockOwnerByMod(void *hMod, bool fWantToHear); +SUPR0DECL(int) SUPR0LdrModByName(PSUPDRVSESSION pSession, const char *pszName, void **phMod); +SUPR0DECL(int) SUPR0LdrModRetain(PSUPDRVSESSION pSession, void *hMod); +SUPR0DECL(int) SUPR0LdrModRelease(PSUPDRVSESSION pSession, void *hMod); +#ifdef RT_OS_LINUX +SUPR0DECL(int) SUPDrvLinuxLdrRegisterWrappedModule(PCSUPLDRWRAPPEDMODULE pWrappedModInfo, const char *pszLnxModName, void **phMod); +SUPR0DECL(int) SUPDrvLinuxLdrDeregisterWrappedModule(PCSUPLDRWRAPPEDMODULE pWrappedModInfo, void **phMod); +#endif +SUPR0DECL(int) SUPR0GetVTSupport(uint32_t *pfCaps); +SUPR0DECL(int) SUPR0GetHwvirtMsrs(PSUPHWVIRTMSRS pMsrs, uint32_t fCaps, bool fForce); +SUPR0DECL(int) SUPR0GetSvmUsability(bool fInitSvm); +SUPR0DECL(int) SUPR0GetVmxUsability(bool *pfIsSmxModeAmbiguous); +SUPR0DECL(int) SUPR0GetCurrentGdtRw(RTHCUINTPTR *pGdtRw); +SUPR0DECL(int) SUPR0QueryVTCaps(PSUPDRVSESSION pSession, uint32_t *pfCaps); +SUPR0DECL(int) SUPR0GipUnmap(PSUPDRVSESSION pSession); +SUPR0DECL(int) SUPR0QueryUcodeRev(PSUPDRVSESSION pSession, uint32_t *puMicrocodeRev); +SUPR0DECL(SUPPAGINGMODE) SUPR0GetPagingMode(void); +SUPR0DECL(RTCCUINTREG) SUPR0ChangeCR4(RTCCUINTREG fOrMask, RTCCUINTREG fAndMask); +SUPR0DECL(int) SUPR0EnableVTx(bool fEnable); +SUPR0DECL(bool) SUPR0SuspendVTxOnCpu(void); +SUPR0DECL(void) SUPR0ResumeVTxOnCpu(bool fSuspended); +#define SUP_TSCDELTA_MEASURE_F_FORCE RT_BIT_32(0) +#define SUP_TSCDELTA_MEASURE_F_ASYNC RT_BIT_32(1) +#define SUP_TSCDELTA_MEASURE_F_VALID_MASK UINT32_C(0x00000003) +SUPR0DECL(int) SUPR0TscDeltaMeasureBySetIndex(PSUPDRVSESSION pSession, uint32_t iCpuSet, uint32_t fFlags, + RTMSINTERVAL cMsWaitRetry, RTMSINTERVAL cMsWaitThread, uint32_t cTries); + +SUPR0DECL(void) SUPR0BadContext(PSUPDRVSESSION pSession, const char *pszFile, uint32_t uLine, const char *pszExpr); + +#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) +/** + * Translates a physical address to a virtual mapping (valid up to end of page). + * @returns VBox status code. + * @param HCPhys The physical address, must be page aligned. + * @param ppv Where to store the mapping address on success. + */ +SUPR0DECL(int) SUPR0HCPhysToVirt(RTHCPHYS HCPhys, void **ppv); +#endif + +/** Context structure returned by SUPR0IoCtlSetup for use with + * SUPR0IoCtlPerform and cleaned up by SUPR0IoCtlCleanup. */ +typedef struct SUPR0IOCTLCTX *PSUPR0IOCTLCTX; + +/** + * Sets up a I/O control context for the given handle. + * + * @returns VBox status code. + * @param pSession The support driver session. + * @param hHandle The handle. + * @param fFlags Flag, MBZ. + * @param ppCtx Where the context is returned. + */ +SUPR0DECL(int) SUPR0IoCtlSetupForHandle(PSUPDRVSESSION pSession, intptr_t hHandle, uint32_t fFlags, PSUPR0IOCTLCTX *ppCtx); + +/** + * Cleans up the I/O control context when done. + * + * This won't close the handle passed to SUPR0IoCtlSetupForHandle. + * + * @returns VBox status code. + * @param pCtx The I/O control context to cleanup. + */ +SUPR0DECL(int) SUPR0IoCtlCleanup(PSUPR0IOCTLCTX pCtx); + +/** + * Performs an I/O control operation. + * + * @returns VBox status code. + * @param pCtx The I/O control context returned by + * SUPR0IoCtlSetupForHandle. + * @param uFunction The I/O control function to perform. + * @param pvInput Pointer to input buffer (ring-0). + * @param pvInputUser Ring-3 pointer corresponding to @a pvInput. + * @param cbInput The amount of input. If zero, both input pointers + * are expected to be NULL. + * @param pvOutput Pointer to output buffer (ring-0). + * @param pvOutputUser Ring-3 pointer corresponding to @a pvInput. + * @param cbOutput The amount of input. If zero, both input pointers + * are expected to be NULL. + * @param piNativeRc Where to return the native return code. When + * specified the VBox status code will typically be + * VINF_SUCCESS and the caller have to consult this for + * the actual result of the operation. (This saves + * pointless status code conversion.) Optional. + * + * @note On unix systems where there is only one set of buffers possible, + * pass the same pointers as input and output. + */ +SUPR0DECL(int) SUPR0IoCtlPerform(PSUPR0IOCTLCTX pCtx, uintptr_t uFunction, + void *pvInput, RTR3PTR pvInputUser, size_t cbInput, + void *pvOutput, RTR3PTR pvOutputUser, size_t cbOutput, + int32_t *piNativeRc); + +/** + * Writes to the debugger and/or kernel log, va_list version. + * + * The length of the formatted message is somewhat limited, so keep things short + * and to the point. + * + * @returns Number of bytes written, mabye. + * @param pszFormat IPRT format string. + * @param va Arguments referenced by the format string. + */ +SUPR0DECL(int) SUPR0PrintfV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Writes to the debugger and/or kernel log. + * + * The length of the formatted message is somewhat limited, so keep things short + * and to the point. + * + * @returns Number of bytes written, mabye. + * @param pszFormat IPRT format string. + * @param ... Arguments referenced by the format string. + */ +#if defined(__GNUC__) && defined(__inline__) +/* Define it as static for GCC as it cannot inline functions using va_start() anyway, + and linux redefines __inline__ to always inlining forcing gcc to issue an error. */ +static int __attribute__((__unused__)) +#else +DECLINLINE(int) +#endif +RT_IPRT_FORMAT_ATTR(1, 2) SUPR0Printf(const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + SUPR0PrintfV(pszFormat, va); + va_end(va); + return 0; +} + +/* HACK ALERT! See above. */ +#ifdef SUPR0PRINTF_UNDO_INLINE_HACK +# define __inline__ inline +#endif + +#ifdef IN_RING0 +/** Debug printf macro. This also exist in SUPLib, see SUPLibInternal.h. */ +# ifdef DEBUG +# define SUP_DPRINTF(a) SUPR0Printf a +# else +# define SUP_DPRINTF(a) do { } while (0) +# endif +#endif + +/** + * Returns configuration flags of the host kernel. + * + * @returns Combination of SUPKERNELFEATURES_XXX flags. + */ +SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void); + +/** + * Notification from R0 VMM prior to loading the guest-FPU register state. + * + * @returns Whether the host-FPU register state has been saved by the host kernel. + * @param fCtxHook Whether thread-context hooks are enabled. + * + * @remarks Called with preemption disabled. + */ +SUPR0DECL(bool) SUPR0FpuBegin(bool fCtxHook); + +/** + * Notification from R0 VMM after saving the guest-FPU register state (and + * potentially restoring the host-FPU register state) in ring-0. + * + * @param fCtxHook Whether thread-context hooks are enabled. + * + * @remarks Called with preemption disabled. + */ +SUPR0DECL(void) SUPR0FpuEnd(bool fCtxHook); + +/** @copydoc RTLogDefaultInstanceEx + * @remarks To allow overriding RTLogDefaultInstanceEx locally. */ +SUPR0DECL(struct RTLOGGER *) SUPR0DefaultLogInstanceEx(uint32_t fFlagsAndGroup); +/** @copydoc RTLogGetDefaultInstanceEx + * @remarks To allow overriding RTLogGetDefaultInstanceEx locally. */ +SUPR0DECL(struct RTLOGGER *) SUPR0GetDefaultLogInstanceEx(uint32_t fFlagsAndGroup); +/** @copydoc RTLogRelGetDefaultInstanceEx + * @remarks To allow overriding RTLogRelGetDefaultInstanceEx locally. */ +SUPR0DECL(struct RTLOGGER *) SUPR0GetDefaultLogRelInstanceEx(uint32_t fFlagsAndGroup); + + +/** @name Absolute symbols + * Take the address of these, don't try call them. + * @{ */ +SUPR0DECL(void) SUPR0AbsIs64bit(void); +SUPR0DECL(void) SUPR0Abs64bitKernelCS(void); +SUPR0DECL(void) SUPR0Abs64bitKernelSS(void); +SUPR0DECL(void) SUPR0Abs64bitKernelDS(void); +SUPR0DECL(void) SUPR0AbsKernelCS(void); +SUPR0DECL(void) SUPR0AbsKernelSS(void); +SUPR0DECL(void) SUPR0AbsKernelDS(void); +SUPR0DECL(void) SUPR0AbsKernelES(void); +SUPR0DECL(void) SUPR0AbsKernelFS(void); +SUPR0DECL(void) SUPR0AbsKernelGS(void); +/** @} */ + +/** + * Support driver component factory. + * + * Component factories are registered by drivers that provides services + * such as the host network interface filtering and access to the host + * TCP/IP stack. + * + * @remark Module dependencies and making sure that a component doesn't + * get unloaded while in use, is the sole responsibility of the + * driver/kext/whatever implementing the component. + */ +typedef struct SUPDRVFACTORY +{ + /** The (unique) name of the component factory. */ + char szName[56]; + /** + * Queries a factory interface. + * + * The factory interface is specific to each component and will be be + * found in the header(s) for the component alongside its UUID. + * + * @returns Pointer to the factory interfaces on success, NULL on failure. + * + * @param pSupDrvFactory Pointer to this structure. + * @param pSession The SUPDRV session making the query. + * @param pszInterfaceUuid The UUID of the factory interface. + */ + DECLR0CALLBACKMEMBER(void *, pfnQueryFactoryInterface,(struct SUPDRVFACTORY const *pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)); +} SUPDRVFACTORY; +/** Pointer to a support driver factory. */ +typedef SUPDRVFACTORY *PSUPDRVFACTORY; +/** Pointer to a const support driver factory. */ +typedef SUPDRVFACTORY const *PCSUPDRVFACTORY; + +SUPR0DECL(int) SUPR0ComponentRegisterFactory(PSUPDRVSESSION pSession, PCSUPDRVFACTORY pFactory); +SUPR0DECL(int) SUPR0ComponentDeregisterFactory(PSUPDRVSESSION pSession, PCSUPDRVFACTORY pFactory); +SUPR0DECL(int) SUPR0ComponentQueryFactory(PSUPDRVSESSION pSession, const char *pszName, const char *pszInterfaceUuid, void **ppvFactoryIf); + + +/** @name Tracing + * @{ */ + +/** + * Tracer data associated with a provider. + */ +typedef union SUPDRVTRACERDATA +{ + /** Generic */ + uint64_t au64[2]; + + /** DTrace data. */ + struct + { + /** Provider ID. */ + uintptr_t idProvider; + /** The number of trace points provided. */ + uint32_t volatile cProvidedProbes; + /** Whether we've invalidated this bugger. */ + bool fZombie; + } DTrace; +} SUPDRVTRACERDATA; +/** Pointer to the tracer data associated with a provider. */ +typedef SUPDRVTRACERDATA *PSUPDRVTRACERDATA; + +/** + * Probe location info for ring-0. + * + * Since we cannot trust user tracepoint modules, we need to duplicate the probe + * ID and enabled flag in ring-0. + */ +typedef struct SUPDRVPROBELOC +{ + /** The probe ID. */ + uint32_t idProbe; + /** Whether it's enabled or not. */ + bool fEnabled; +} SUPDRVPROBELOC; +/** Pointer to a ring-0 probe location record. */ +typedef SUPDRVPROBELOC *PSUPDRVPROBELOC; + +/** + * Probe info for ring-0. + * + * Since we cannot trust user tracepoint modules, we need to duplicate the + * probe enable count. + */ +typedef struct SUPDRVPROBEINFO +{ + /** The number of times this probe has been enabled. */ + uint32_t volatile cEnabled; +} SUPDRVPROBEINFO; +/** Pointer to a ring-0 probe info record. */ +typedef SUPDRVPROBEINFO *PSUPDRVPROBEINFO; + +/** + * Support driver tracepoint provider core. + */ +typedef struct SUPDRVVDTPROVIDERCORE +{ + /** The tracer data member. */ + SUPDRVTRACERDATA TracerData; + /** Pointer to the provider name (a copy that's always available). */ + const char *pszName; + /** Pointer to the module name (a copy that's always available). */ + const char *pszModName; + + /** The provider descriptor. */ + struct VTGDESCPROVIDER *pDesc; + /** The VTG header. */ + struct VTGOBJHDR *pHdr; + + /** The size of the entries in the pvProbeLocsEn table. */ + uint8_t cbProbeLocsEn; + /** The actual module bit count (corresponds to cbProbeLocsEn). */ + uint8_t cBits; + /** Set if this is a Umod, otherwise clear. */ + bool fUmod; + /** Explicit alignment padding (paranoia). */ + uint8_t abAlignment[ARCH_BITS == 32 ? 1 : 5]; + + /** The probe locations used for descriptive purposes. */ + struct VTGPROBELOC const *paProbeLocsRO; + /** Pointer to the probe location array where the enable flag needs + * flipping. For kernel providers, this will always be SUPDRVPROBELOC, + * while user providers can either be 32-bit or 64-bit. Use + * cbProbeLocsEn to calculate the address of an entry. */ + void *pvProbeLocsEn; + /** Pointer to the probe array containing the enabled counts. */ + uint32_t *pacProbeEnabled; + + /** The ring-0 probe location info for user tracepoint modules. + * This is NULL if fUmod is false. */ + PSUPDRVPROBELOC paR0ProbeLocs; + /** The ring-0 probe info for user tracepoint modules. + * This is NULL if fUmod is false. */ + PSUPDRVPROBEINFO paR0Probes; + +} SUPDRVVDTPROVIDERCORE; +/** Pointer to a tracepoint provider core structure. */ +typedef SUPDRVVDTPROVIDERCORE *PSUPDRVVDTPROVIDERCORE; + +/** Pointer to a tracer registration record. */ +typedef struct SUPDRVTRACERREG const *PCSUPDRVTRACERREG; +/** + * Support driver tracer registration record. + */ +typedef struct SUPDRVTRACERREG +{ + /** Magic value (SUPDRVTRACERREG_MAGIC). */ + uint32_t u32Magic; + /** Version (SUPDRVTRACERREG_VERSION). */ + uint32_t u32Version; + + /** + * Fire off a kernel probe. + * + * @param pVtgProbeLoc The probe location record. + * @param uArg0 The first raw probe argument. + * @param uArg1 The second raw probe argument. + * @param uArg2 The third raw probe argument. + * @param uArg3 The fourth raw probe argument. + * @param uArg4 The fifth raw probe argument. + * + * @remarks SUPR0TracerFireProbe will do a tail jump thru this member, so + * no extra stack frames will be added. + * @remarks This does not take a 'this' pointer argument because it doesn't map + * well onto VTG or DTrace. + * + */ + DECLR0CALLBACKMEMBER(void, pfnProbeFireKernel, (struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2, + uintptr_t uArg3, uintptr_t uArg4)); + + /** + * Fire off a user-mode probe. + * + * @param pThis Pointer to the registration record. + * + * @param pVtgProbeLoc The probe location record. + * @param pSession The user session. + * @param pCtx The usermode context info. + * @param pVtgHdr The VTG header (read-only). + * @param pProbeLocRO The read-only probe location record . + */ + DECLR0CALLBACKMEMBER(void, pfnProbeFireUser, (PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, PCSUPDRVTRACERUSRCTX pCtx, + struct VTGOBJHDR const *pVtgHdr, struct VTGPROBELOC const *pProbeLocRO)); + + /** + * Opens up the tracer. + * + * @returns VBox status code. + * @param pThis Pointer to the registration record. + * @param pSession The session doing the opening. + * @param uCookie A cookie (magic) unique to the tracer, so it can + * fend off incompatible clients. + * @param uArg Tracer specific argument. + * @param puSessionData Pointer to the session data variable. This must be + * set to a non-zero value on success. + */ + DECLR0CALLBACKMEMBER(int, pfnTracerOpen, (PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uint32_t uCookie, uintptr_t uArg, + uintptr_t *puSessionData)); + + /** + * I/O control style tracer communication method. + * + * + * @returns VBox status code. + * @param pThis Pointer to the registration record. + * @param pSession The session. + * @param uSessionData The session data value. + * @param uCmd The tracer specific command. + * @param uArg The tracer command specific argument. + * @param piRetVal The tracer specific return value. + */ + DECLR0CALLBACKMEMBER(int, pfnTracerIoCtl, (PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData, + uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)); + + /** + * Cleans up data the tracer has associated with a session. + * + * @param pThis Pointer to the registration record. + * @param pSession The session handle. + * @param uSessionData The data assoicated with the session. + */ + DECLR0CALLBACKMEMBER(void, pfnTracerClose, (PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData)); + + /** + * Registers a provider. + * + * @returns VBox status code. + * @param pThis Pointer to the registration record. + * @param pCore The provider core data. + * + * @todo Kernel vs. Userland providers. + */ + DECLR0CALLBACKMEMBER(int, pfnProviderRegister, (PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)); + + /** + * Attempts to deregisters a provider. + * + * @returns VINF_SUCCESS or VERR_TRY_AGAIN. If the latter, the provider + * should be made as harmless as possible before returning as the + * VTG object and associated code will be unloaded upon return. + * + * @param pThis Pointer to the registration record. + * @param pCore The provider core data. + */ + DECLR0CALLBACKMEMBER(int, pfnProviderDeregister, (PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)); + + /** + * Make another attempt at unregister a busy provider. + * + * @returns VINF_SUCCESS or VERR_TRY_AGAIN. + * @param pThis Pointer to the registration record. + * @param pCore The provider core data. + */ + DECLR0CALLBACKMEMBER(int, pfnProviderDeregisterZombie, (PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)); + + /** End marker (SUPDRVTRACERREG_MAGIC). */ + uintptr_t uEndMagic; +} SUPDRVTRACERREG; + +/** Tracer magic (Kenny Garrett). */ +#define SUPDRVTRACERREG_MAGIC UINT32_C(0x19601009) +/** Tracer registration structure version. */ +#define SUPDRVTRACERREG_VERSION RT_MAKE_U32(0, 1) + +/** Pointer to a trace helper structure. */ +typedef struct SUPDRVTRACERHLP const *PCSUPDRVTRACERHLP; +/** + * Helper structure. + */ +typedef struct SUPDRVTRACERHLP +{ + /** The structure version (SUPDRVTRACERHLP_VERSION). */ + uintptr_t uVersion; + + /** @todo ... */ + + /** End marker (SUPDRVTRACERHLP_VERSION) */ + uintptr_t uEndVersion; +} SUPDRVTRACERHLP; +/** Tracer helper structure version. */ +#define SUPDRVTRACERHLP_VERSION RT_MAKE_U32(0, 1) + +SUPR0DECL(int) SUPR0TracerRegisterImpl(void *hMod, PSUPDRVSESSION pSession, PCSUPDRVTRACERREG pReg, PCSUPDRVTRACERHLP *ppHlp); +SUPR0DECL(int) SUPR0TracerDeregisterImpl(void *hMod, PSUPDRVSESSION pSession); +SUPR0DECL(int) SUPR0TracerRegisterDrv(PSUPDRVSESSION pSession, struct VTGOBJHDR *pVtgHdr, const char *pszName); +SUPR0DECL(void) SUPR0TracerDeregisterDrv(PSUPDRVSESSION pSession); +SUPR0DECL(int) SUPR0TracerRegisterModule(void *hMod, struct VTGOBJHDR *pVtgHdr); +SUPR0DECL(void) SUPR0TracerFireProbe(struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2, + uintptr_t uArg3, uintptr_t uArg4); +SUPR0DECL(void) SUPR0TracerUmodProbeFire(PSUPDRVSESSION pSession, PSUPDRVTRACERUSRCTX pCtx); +/** @} */ + + +/** @defgroup grp_sup_r0_idc The IDC Interface + * @{ + */ + +/** The current SUPDRV IDC version. + * This follows the usual high word / low word rules, i.e. high word is the + * major number and it signifies incompatible interface changes. */ +#define SUPDRV_IDC_VERSION UINT32_C(0x00010000) + +/** + * Inter-Driver Communication Handle. + */ +typedef union SUPDRVIDCHANDLE +{ + /** Padding for opaque usage. + * Must be greater or equal in size than the private struct. */ + void *apvPadding[4]; +#ifdef SUPDRVIDCHANDLEPRIVATE_DECLARED + /** The private view. */ + struct SUPDRVIDCHANDLEPRIVATE s; +#endif +} SUPDRVIDCHANDLE; +/** Pointer to a handle. */ +typedef SUPDRVIDCHANDLE *PSUPDRVIDCHANDLE; + +SUPR0DECL(int) SUPR0IdcOpen(PSUPDRVIDCHANDLE pHandle, uint32_t uReqVersion, uint32_t uMinVersion, + uint32_t *puSessionVersion, uint32_t *puDriverVersion, uint32_t *puDriverRevision); +SUPR0DECL(int) SUPR0IdcCall(PSUPDRVIDCHANDLE pHandle, uint32_t iReq, void *pvReq, uint32_t cbReq); +SUPR0DECL(int) SUPR0IdcClose(PSUPDRVIDCHANDLE pHandle); +SUPR0DECL(PSUPDRVSESSION) SUPR0IdcGetSession(PSUPDRVIDCHANDLE pHandle); +SUPR0DECL(int) SUPR0IdcComponentRegisterFactory(PSUPDRVIDCHANDLE pHandle, PCSUPDRVFACTORY pFactory); +SUPR0DECL(int) SUPR0IdcComponentDeregisterFactory(PSUPDRVIDCHANDLE pHandle, PCSUPDRVFACTORY pFactory); + +/** @} */ + +/** @name Ring-0 module entry points. + * + * These can be exported by ring-0 modules SUP are told to load. + * + * @{ */ +DECLEXPORT(int) ModuleInit(void *hMod); +DECLEXPORT(void) ModuleTerm(void *hMod); +/** @} */ + + +/** @} */ +#endif + + +/** @name Trust Anchors and Certificates + * @{ */ + +/** + * Trust anchor table entry (in generated Certificates.cpp). + */ +typedef struct SUPTAENTRY +{ + /** Pointer to the raw bytes. */ + const unsigned char *pch; + /** Number of bytes. */ + unsigned cb; +} SUPTAENTRY; +/** Pointer to a trust anchor table entry. */ +typedef SUPTAENTRY const *PCSUPTAENTRY; + +/** Macro for simplifying generating the trust anchor tables. */ +#define SUPTAENTRY_GEN(a_abTA) { &a_abTA[0], sizeof(a_abTA) } + +/** All certificates we know. */ +extern SUPTAENTRY const g_aSUPAllTAs[]; +/** Number of entries in g_aSUPAllTAs. */ +extern unsigned const g_cSUPAllTAs; + +/** Software publisher certificate roots (Authenticode). */ +extern SUPTAENTRY const g_aSUPSpcRootTAs[]; +/** Number of entries in g_aSUPSpcRootTAs. */ +extern unsigned const g_cSUPSpcRootTAs; + +/** Kernel root certificates used by Windows. */ +extern SUPTAENTRY const g_aSUPNtKernelRootTAs[]; +/** Number of entries in g_aSUPNtKernelRootTAs. */ +extern unsigned const g_cSUPNtKernelRootTAs; + +/** Timestamp root certificates trusted by Windows. */ +extern SUPTAENTRY const g_aSUPTimestampTAs[]; +/** Number of entries in g_aSUPTimestampTAs. */ +extern unsigned const g_cSUPTimestampTAs; + +/** Root certificates trusted by Apple code signing. */ +extern SUPTAENTRY const g_aSUPAppleRootTAs[]; +/** Number of entries in g_cSUPAppleRootTAs. */ +extern unsigned const g_cSUPAppleRootTAs; + +/** TAs we trust (the build certificate, Oracle VirtualBox). */ +extern SUPTAENTRY const g_aSUPTrustedTAs[]; +/** Number of entries in g_aSUPTrustedTAs. */ +extern unsigned const g_cSUPTrustedTAs; + +/** Supplemental certificates, like cross signing certificates. */ +extern SUPTAENTRY const g_aSUPSupplementalTAs[]; +/** Number of entries in g_aSUPTrustedTAs. */ +extern unsigned const g_cSUPSupplementalTAs; + +/** The build certificate. */ +extern const unsigned char g_abSUPBuildCert[]; +/** The size of the build certificate. */ +extern const unsigned g_cbSUPBuildCert; + +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_sup_h */ + diff --git a/include/VBox/sup.mac b/include/VBox/sup.mac new file mode 100644 index 00000000..5b1b5f00 --- /dev/null +++ b/include/VBox/sup.mac @@ -0,0 +1,157 @@ +; $Id: sup.mac $ +;; @file +; SUP - Support Library, assembly definitions. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_sup_mac +%define ___VBox_sup_mac + +struc SUPGIPCPU + .u32TransactionId resd 1 + .u32UpdateIntervalTSC resd 1 + .u64NanoTS resq 1 + .u64TSC resq 1 + .u64CpuHz resq 1 + .i64TSCDelta resq 1 + .cErrors resd 1 + .iTSCHistoryHead resd 1 + .au32TSCHistory resd 8 + .u32PrevUpdateIntervalNS resd 1 + .u32Reserved resd 1 + .u64TSCSample resq 1 + .au32Reserved1 resd 3 + .enmState resd 1 + .idCpu resd 1 + .iCpuSet resw 1 + .iCpuGroup resw 1 + .iCpuGroupMember resw 1 + .idApic resw 1 + .iReservedForNumaNode resd 1 +endstruc + +%define SUPGIPUSETSCDELTA_NOT_APPLICABLE 0 +%define SUPGIPUSETSCDELTA_ZERO_CLAIMED 1 +%define SUPGIPUSETSCDELTA_PRACTICALLY_ZERO 2 +%define SUPGIPUSETSCDELTA_ROUGHLY_ZERO 3 +%define SUPGIPUSETSCDELTA_NOT_ZERO 4 + +%define SUPGIPGETCPU_APIC_ID 1 +%define SUPGIPGETCPU_RDTSCP_MASK_MAX_SET_CPUS 2 +%define SUPGIPGETCPU_IDTR_LIMIT_MASK_MAX_SET_CPUS 4 +%define SUPGIPGETCPU_RDTSCP_GROUP_IN_CH_NUMBER_IN_CL 8 +%define SUPGIPGETCPU_APIC_ID_EXT_0B 16 +%define SUPGIPGETCPU_APIC_ID_EXT_8000001E 32 + + +%define SUPGLOBALINFOPAGE_MAGIC 0x19590106 +struc SUPGLOBALINFOPAGE + .u32Magic resd 1 + .u32Version resd 1 + .u32Mode resd 1 + .cCpus resw 1 + .cPages resw 1 + .u32UpdateHz resd 1 + .u32UpdateIntervalNS resd 1 + .u64NanoTSLastUpdateHz resq 1 + .u64CpuHz resq 1 + .cOnlineCpus resw 1 + .cPresentCpus resw 1 + .cPossibleCpus resw 1 + .cPossibleCpuGroups resw 1 + .idCpuMax resd 1 + .enmUseTscDelta resd 1 + .fGetGipCpu resd 1 + .fFlags resd 1 + .OnlineCpuSet resq 16 + .PresentCpuSet resq 16 + .PossibleCpuSet resq 16 + .au32Padding1 resd 48 + .aiCpuFromApicId resw 4096 + .aiCpuFromCpuSetIdx resw 1024 + .aoffCpuGroup resd 256 + .aCPUs resb SUPGIPCPU_size +endstruc + +struc SUPDRVTRACERUSRCTX32 + .idProbe resd 1 + .cBits resb 1 + .abReserved resb 3 + .u.X86.uVtgProbeLoc resd 1 + .u.X86.aArgs resd 20 + .u.X86.eip resd 1 + .u.X86.eflags resd 1 + .u.X86.eax resd 1 + .u.X86.ecx resd 1 + .u.X86.edx resd 1 + .u.X86.ebx resd 1 + .u.X86.esp resd 1 + .u.X86.ebp resd 1 + .u.X86.esi resd 1 + .u.X86.edi resd 1 + .u.X86.cs resw 1 + .u.X86.ss resw 1 + .u.X86.ds resw 1 + .u.X86.es resw 1 + .u.X86.fs resw 1 + .u.X86.gs resw 1 +endstruc + +struc SUPDRVTRACERUSRCTX64 + .idProbe resd 1 + .cBits resb 1 + .abReserved resb 3 + .u.Amd64.uVtgProbeLoc resq 1 + .u.Amd64.aArgs resq 10 + .u.Amd64.rip resq 1 + .u.Amd64.rflags resq 1 + .u.Amd64.rax resq 1 + .u.Amd64.rcx resq 1 + .u.Amd64.rdx resq 1 + .u.Amd64.rbx resq 1 + .u.Amd64.rsp resq 1 + .u.Amd64.rbp resq 1 + .u.Amd64.rsi resq 1 + .u.Amd64.rdi resq 1 + .u.Amd64.r8 resq 1 + .u.Amd64.r9 resq 1 + .u.Amd64.r10 resq 1 + .u.Amd64.r11 resq 1 + .u.Amd64.r12 resq 1 + .u.Amd64.r13 resq 1 + .u.Amd64.r14 resq 1 + .u.Amd64.r15 resq 1 +endstruc + +%endif + diff --git a/include/VBox/types.h b/include/VBox/types.h new file mode 100644 index 00000000..9b7e1cf5 --- /dev/null +++ b/include/VBox/types.h @@ -0,0 +1,1258 @@ +/** @file + * VirtualBox - Types. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_types_h +#define VBOX_INCLUDED_types_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <iprt/types.h> + + +/** @defgroup grp_types VBox Basic Types + * @{ + */ + + +/** @defgroup grp_types_both Common Guest and Host Context Basic Types + * @{ + */ + + +/** @defgroup grp_types_hc Host Context Basic Types + * @{ + */ + +/** @} */ + + +/** @defgroup grp_types_gc Guest Context Basic Types + * @{ + */ + +/** @} */ + + +/** Pointer to per support driver session data. + * (The data is a R0 entity and private to the the R0 SUP part. All + * other should consider this a sort of handle.) */ +typedef R0PTRTYPE(struct SUPDRVSESSION *) PSUPDRVSESSION; + +/** Event semaphore handle. Ring-0 / ring-3. */ +typedef R0PTRTYPE(struct SUPSEMEVENTHANDLE *) SUPSEMEVENT; +/** Pointer to an event semaphore handle. */ +typedef SUPSEMEVENT *PSUPSEMEVENT; +/** Nil event semaphore handle. */ +#define NIL_SUPSEMEVENT ((SUPSEMEVENT)0) + +/** Multiple release event semaphore handle. Ring-0 / ring-3. */ +typedef R0PTRTYPE(struct SUPSEMEVENTMULTIHANDLE *) SUPSEMEVENTMULTI; +/** Pointer to an multiple release event semaphore handle. */ +typedef SUPSEMEVENTMULTI *PSUPSEMEVENTMULTI; +/** Nil multiple release event semaphore handle. */ +#define NIL_SUPSEMEVENTMULTI ((SUPSEMEVENTMULTI)0) + + +/** Pointer to a ring-3 VMM API vtable. */ +typedef R3PTRTYPE(const struct VMMR3VTABLE *) PCVMMR3VTABLE; + +/** Pointer to a VM. */ +typedef struct VM *PVM; +/** Pointer to a const VM. */ +typedef const struct VM *PCVM; +/** Pointer to a VM - Ring-0 Ptr. */ +typedef R0PTRTYPE(struct VM *) PVMR0; +/** Pointer to a VM - Ring-3 Ptr. */ +typedef R3PTRTYPE(struct VM *) PVMR3; +/** Pointer to a VM - RC Ptr. */ +typedef RCPTRTYPE(struct VM *) PVMRC; + +/** Pointer to a virtual CPU structure. */ +typedef struct VMCPU * PVMCPU; +/** Pointer to a const virtual CPU structure. */ +typedef const struct VMCPU * PCVMCPU; +/** Pointer to a virtual CPU structure - Ring-3 Ptr. */ +typedef R3PTRTYPE(struct VMCPU *) PVMCPUR3; +/** Pointer to a virtual CPU structure - Ring-0 Ptr. */ +typedef R0PTRTYPE(struct VMCPU *) PVMCPUR0; +/** Pointer to a virtual CPU structure - RC Ptr. */ +typedef RCPTRTYPE(struct VMCPU *) PVMCPURC; + +/** Pointer to a ring-0 (global) VM structure. */ +typedef R0PTRTYPE(struct GVM *) PGVM; +/** Pointer to a const ring-0 (global) VM structure. */ +typedef R0PTRTYPE(const struct GVM *) PCGVM; +/** Pointer to a GVMCPU structure. */ +typedef R0PTRTYPE(struct GVMCPU *) PGVMCPU; +/** Pointer to a const GVMCPU structure. */ +typedef R0PTRTYPE(struct GVMCPU const *) PCGVMCPU; + +/** Pointer to a ring-3 (user mode) VM structure. */ +typedef R3PTRTYPE(struct UVM *) PUVM; + +/** Pointer to a ring-3 (user mode) VMCPU structure. */ +typedef R3PTRTYPE(struct UVMCPU *) PUVMCPU; + +/** Pointer to a context specific VM derived structure. + * This is PGVM in ring-0 and plain PVM in ring-3. */ +#ifdef IN_RING0 +typedef PGVM PVMCC; +#else +typedef PVM PVMCC; +#endif +/** Pointer to a const context specific VM derived structure. + * This is PCGVM in ring-0 and plain PCVM in ring-3. */ +#ifdef IN_RING0 +typedef PCGVM PCVMCC; +#else +typedef PCVM PCVMCC; +#endif +/** Pointer to a context specific VMCPUM derived structure. + * This is PGVMCPU in ring-0 and plain PVMCPU in ring-3. */ +#ifdef IN_RING0 +typedef PGVMCPU PVMCPUCC; +#else +typedef PVMCPU PVMCPUCC; +#endif +/** Pointer to a const context specific VMCPU derived structure. + * This is PCGVMCPU in ring-0 and plain PCVMCPU in ring-3. */ +#ifdef IN_RING0 +typedef PCGVMCPU PCVMCPUCC; +#else +typedef PCVMCPU PCVMCPUCC; +#endif + +/** Virtual CPU ID. */ +typedef uint32_t VMCPUID; +/** Pointer to a virtual CPU ID. */ +typedef VMCPUID *PVMCPUID; +/** @name Special CPU ID values. + * Most of these are for request scheduling. + * + * @{ */ +/** All virtual CPUs. */ +#define VMCPUID_ALL UINT32_C(0xfffffff2) +/** All virtual CPUs, descending order. */ +#define VMCPUID_ALL_REVERSE UINT32_C(0xfffffff3) +/** Any virtual CPU. + * Intended for scheduling a VM request or some other task. */ +#define VMCPUID_ANY UINT32_C(0xfffffff4) +/** Any virtual CPU; always queue for future execution. + * Intended for scheduling a VM request or some other task. */ +#define VMCPUID_ANY_QUEUE UINT32_C(0xfffffff5) +/** The NIL value. */ +#define NIL_VMCPUID UINT32_C(0xfffffffd) +/** @} */ + +/** + * Virtual CPU set. + */ +typedef struct VMCPUSET +{ + /** The bitmap data. */ + uint32_t au32Bitmap[8 /*256/32*/]; +} VMCPUSET; +/** Pointer to a Virtual CPU set. */ +typedef VMCPUSET *PVMCPUSET; +/** Pointer to a const Virtual CPU set. */ +typedef VMCPUSET const *PCVMCPUSET; + + +/** + * VM State + */ +typedef enum VMSTATE +{ + /** The VM is being created. */ + VMSTATE_CREATING = 0, + /** The VM is created. */ + VMSTATE_CREATED, + /** The VM state is being loaded from file. */ + VMSTATE_LOADING, + /** The VM is being powered on */ + VMSTATE_POWERING_ON, + /** The VM is being resumed. */ + VMSTATE_RESUMING, + /** The VM is runnning. */ + VMSTATE_RUNNING, + /** Live save: The VM is running and the state is being saved. */ + VMSTATE_RUNNING_LS, + /** Fault Tolerance: The VM is running and the state is being synced. */ + VMSTATE_RUNNING_FT, + /** The VM is being reset. */ + VMSTATE_RESETTING, + /** Live save: The VM is being reset and immediately suspended. */ + VMSTATE_RESETTING_LS, + /** The VM is being soft/warm reset. */ + VMSTATE_SOFT_RESETTING, + /** Live save: The VM is being soft/warm reset (not suspended afterwards). */ + VMSTATE_SOFT_RESETTING_LS, + /** The VM is being suspended. */ + VMSTATE_SUSPENDING, + /** Live save: The VM is being suspended during a live save operation, either as + * part of the normal flow or VMR3Reset. */ + VMSTATE_SUSPENDING_LS, + /** Live save: The VM is being suspended by VMR3Suspend during live save. */ + VMSTATE_SUSPENDING_EXT_LS, + /** The VM is suspended. */ + VMSTATE_SUSPENDED, + /** Live save: The VM has been suspended and is waiting for the live save + * operation to move on. */ + VMSTATE_SUSPENDED_LS, + /** Live save: The VM has been suspended by VMR3Suspend during a live save. */ + VMSTATE_SUSPENDED_EXT_LS, + /** The VM is suspended and its state is being saved by EMT(0). (See SSM) */ + VMSTATE_SAVING, + /** The VM is being debugged. (See DBGF.) */ + VMSTATE_DEBUGGING, + /** Live save: The VM is being debugged while the live phase is going on. */ + VMSTATE_DEBUGGING_LS, + /** The VM is being powered off. */ + VMSTATE_POWERING_OFF, + /** Live save: The VM is being powered off and the save cancelled. */ + VMSTATE_POWERING_OFF_LS, + /** The VM is switched off, awaiting destruction. */ + VMSTATE_OFF, + /** Live save: Waiting for cancellation and transition to VMSTATE_OFF. */ + VMSTATE_OFF_LS, + /** The VM is powered off because of a fatal error. */ + VMSTATE_FATAL_ERROR, + /** Live save: Waiting for cancellation and transition to FatalError. */ + VMSTATE_FATAL_ERROR_LS, + /** The VM is in guru meditation over a fatal failure. */ + VMSTATE_GURU_MEDITATION, + /** Live save: Waiting for cancellation and transition to GuruMeditation. */ + VMSTATE_GURU_MEDITATION_LS, + /** The VM is screwed because of a failed state loading. */ + VMSTATE_LOAD_FAILURE, + /** The VM is being destroyed. */ + VMSTATE_DESTROYING, + /** Terminated. */ + VMSTATE_TERMINATED, + /** hack forcing the size of the enum to 32-bits. */ + VMSTATE_MAKE_32BIT_HACK = 0x7fffffff +} VMSTATE; + +/** @def VBOXSTRICTRC_STRICT_ENABLED + * Indicates that VBOXSTRICTRC is in strict mode. + */ +#if defined(__cplusplus) \ + && ARCH_BITS == 64 /* cdecl requires classes and structs as hidden params. */ \ + && !defined(_MSC_VER) /* trouble similar to 32-bit gcc. */ \ + && ( defined(RT_STRICT) \ + || defined(VBOX_STRICT) \ + || defined(DEBUG) \ + || defined(DOXYGEN_RUNNING) ) +# define VBOXSTRICTRC_STRICT_ENABLED 1 +#endif + +/** We need RTERR_STRICT_RC. */ +#if defined(VBOXSTRICTRC_STRICT_ENABLED) && !defined(RTERR_STRICT_RC) +# define RTERR_STRICT_RC 1 +#endif + +/** + * Strict VirtualBox status code. + * + * This is normally an 32-bit integer and the only purpose of the type is to + * highlight the special handling that is required. But in strict build it is a + * class that causes compilation and runtime errors for some of the incorrect + * handling. + */ +#ifdef VBOXSTRICTRC_STRICT_ENABLED +struct VBOXSTRICTRC +{ +protected: + /** The status code. */ + int32_t m_rc; + +public: + /** Default constructor setting the status to VERR_IPE_UNINITIALIZED_STATUS. */ + VBOXSTRICTRC() +#ifdef VERR_IPE_UNINITIALIZED_STATUS + : m_rc(VERR_IPE_UNINITIALIZED_STATUS) +#else + : m_rc(-233 /*VERR_IPE_UNINITIALIZED_STATUS*/) +#endif + { + } + + /** Constructor for normal integer status codes. */ + VBOXSTRICTRC(int32_t const rc) + : m_rc(rc) + { + } + + /** Getter that VBOXSTRICTRC_VAL can use. */ + int32_t getValue() const { return m_rc; } + + /** @name Comparison operators + * @{ */ + bool operator==(int32_t rc) const { return m_rc == rc; } + bool operator!=(int32_t rc) const { return m_rc != rc; } + bool operator<=(int32_t rc) const { return m_rc <= rc; } + bool operator>=(int32_t rc) const { return m_rc >= rc; } + bool operator<(int32_t rc) const { return m_rc < rc; } + bool operator>(int32_t rc) const { return m_rc > rc; } + + bool operator==(const VBOXSTRICTRC &rRc) const { return m_rc == rRc.m_rc; } + bool operator!=(const VBOXSTRICTRC &rRc) const { return m_rc != rRc.m_rc; } + bool operator<=(const VBOXSTRICTRC &rRc) const { return m_rc <= rRc.m_rc; } + bool operator>=(const VBOXSTRICTRC &rRc) const { return m_rc >= rRc.m_rc; } + bool operator<(const VBOXSTRICTRC &rRc) const { return m_rc < rRc.m_rc; } + bool operator>(const VBOXSTRICTRC &rRc) const { return m_rc > rRc.m_rc; } + /** @} */ + + /** Special automatic cast for RT_SUCCESS_NP. */ + operator RTErrStrictType2() const { return RTErrStrictType2(m_rc); } + +private: + /** @name Constructors that will prevent some of the bad types. + * @{ */ + VBOXSTRICTRC(uint8_t rc) : m_rc(-999) { NOREF(rc); } + VBOXSTRICTRC(uint16_t rc) : m_rc(-999) { NOREF(rc); } + VBOXSTRICTRC(uint32_t rc) : m_rc(-999) { NOREF(rc); } + VBOXSTRICTRC(uint64_t rc) : m_rc(-999) { NOREF(rc); } + + VBOXSTRICTRC(int8_t rc) : m_rc(-999) { NOREF(rc); } + VBOXSTRICTRC(int16_t rc) : m_rc(-999) { NOREF(rc); } + VBOXSTRICTRC(int64_t rc) : m_rc(-999) { NOREF(rc); } + /** @} */ +}; +# ifdef _MSC_VER +# pragma warning(disable:4190) +# endif +#else +typedef int32_t VBOXSTRICTRC; +#endif + +/** @def VBOXSTRICTRC_VAL + * Explicit getter. + * @param rcStrict The strict VirtualBox status code. + */ +#ifdef VBOXSTRICTRC_STRICT_ENABLED +# define VBOXSTRICTRC_VAL(rcStrict) ( (rcStrict).getValue() ) +#else +# define VBOXSTRICTRC_VAL(rcStrict) (rcStrict) +#endif + +/** @def VBOXSTRICTRC_TODO + * Returns that needs dealing with. + * @param rcStrict The strict VirtualBox status code. + */ +#define VBOXSTRICTRC_TODO(rcStrict) VBOXSTRICTRC_VAL(rcStrict) + + +/** A cross context I/O port range handle. */ +typedef uint64_t IOMIOPORTHANDLE; +/** Pointer to a cross context I/O port handle. */ +typedef IOMIOPORTHANDLE *PIOMIOPORTHANDLE; +/** A NIL I/O port handle. */ +#define NIL_IOMIOPORTHANDLE ((uint64_t)UINT64_MAX) + +/** A cross context MMIO range handle. */ +typedef uint64_t IOMMMIOHANDLE; +/** Pointer to a cross context MMIO handle. */ +typedef IOMMMIOHANDLE *PIOMMMIOHANDLE; +/** A NIL MMIO handle. */ +#define NIL_IOMMMIOHANDLE ((uint64_t)UINT64_MAX) + +/** A cross context MMIO2 range handle. */ +typedef uint64_t PGMMMIO2HANDLE; +/** Pointer to a cross context MMIO2 handle. */ +typedef PGMMMIO2HANDLE *PPGMMMIO2HANDLE; +/** A NIL MMIO2 handle. */ +#define NIL_PGMMMIO2HANDLE ((uint64_t)UINT64_MAX) + +/** Pointer to a PDM Base Interface. */ +typedef struct PDMIBASE *PPDMIBASE; +/** Pointer to a pointer to a PDM Base Interface. */ +typedef PPDMIBASE *PPPDMIBASE; + +/** Pointer to a PDM device instance for the current context. */ +#ifdef IN_RING3 +typedef struct PDMDEVINSR3 *PPDMDEVINS; +#elif defined(IN_RING0) || defined(DOXYGEN_RUNNING) +typedef struct PDMDEVINSR0 *PPDMDEVINS; +#else +typedef struct PDMDEVINSRC *PPDMDEVINS; +#endif +/** Pointer to a pointer a PDM device instance for the current context. */ +typedef PPDMDEVINS *PPPDMDEVINS; +/** R3 pointer to a PDM device instance. */ +typedef R3PTRTYPE(struct PDMDEVINSR3 *) PPDMDEVINSR3; +/** R0 pointer to a PDM device instance. */ +typedef R0PTRTYPE(struct PDMDEVINSR0 *) PPDMDEVINSR0; +/** RC pointer to a PDM device instance. */ +typedef RCPTRTYPE(struct PDMDEVINSRC *) PPDMDEVINSRC; + +/** Pointer to a PDM PCI device structure. */ +typedef struct PDMPCIDEV *PPDMPCIDEV; +/** Pointer to a const PDM PCI device structure. */ +typedef const struct PDMPCIDEV *PCPDMPCIDEV; + +/** Pointer to a PDM USB Device Instance. */ +typedef struct PDMUSBINS *PPDMUSBINS; +/** Pointer to a pointer to a PDM USB Device Instance. */ +typedef PPDMUSBINS *PPPDMUSBINS; + +/** Pointer to a PDM Driver Instance. */ +typedef struct PDMDRVINS *PPDMDRVINS; +/** Pointer to a pointer to a PDM Driver Instance. */ +typedef PPDMDRVINS *PPPDMDRVINS; +/** R3 pointer to a PDM Driver Instance. */ +typedef R3PTRTYPE(PPDMDRVINS) PPDMDRVINSR3; +/** R0 pointer to a PDM Driver Instance. */ +typedef R0PTRTYPE(PPDMDRVINS) PPDMDRVINSR0; +/** RC pointer to a PDM Driver Instance. */ +typedef RCPTRTYPE(PPDMDRVINS) PPDMDRVINSRC; + +/** Pointer to a PDM Service Instance. */ +typedef struct PDMSRVINS *PPDMSRVINS; +/** Pointer to a pointer to a PDM Service Instance. */ +typedef PPDMSRVINS *PPPDMSRVINS; + +/** Pointer to a PDM critical section. */ +typedef union PDMCRITSECT *PPDMCRITSECT; +/** Pointer to a const PDM critical section. */ +typedef const union PDMCRITSECT *PCPDMCRITSECT; + +/** Pointer to a PDM read/write critical section. */ +typedef union PDMCRITSECTRW *PPDMCRITSECTRW; +/** Pointer to a const PDM read/write critical section. */ +typedef union PDMCRITSECTRW const *PCPDMCRITSECTRW; + +/** PDM queue handle. */ +typedef uint64_t PDMQUEUEHANDLE; +/** Pointer to a PDM queue handle. */ +typedef PDMQUEUEHANDLE *PPDMQUEUEHANDLE; +/** NIL PDM queue handle. */ +#define NIL_PDMQUEUEHANDLE ((PDMQUEUEHANDLE)UINT64_MAX) + +/** R3 pointer to a timer. */ +typedef R3PTRTYPE(struct TMTIMER *) PTMTIMERR3; +/** Pointer to a R3 pointer to a timer. */ +typedef PTMTIMERR3 *PPTMTIMERR3; + +/** R0 pointer to a timer. */ +typedef R0PTRTYPE(struct TMTIMER *) PTMTIMERR0; +/** Pointer to a R3 pointer to a timer. */ +typedef PTMTIMERR0 *PPTMTIMERR0; + +/** RC pointer to a timer. */ +typedef RCPTRTYPE(struct TMTIMER *) PTMTIMERRC; +/** Pointer to a RC pointer to a timer. */ +typedef PTMTIMERRC *PPTMTIMERRC; + +/** Pointer to a timer. */ +typedef CTX_SUFF(PTMTIMER) PTMTIMER; +/** Pointer to a pointer to a timer. */ +typedef PTMTIMER *PPTMTIMER; + +/** A cross context timer handle. */ +typedef uint64_t TMTIMERHANDLE; +/** Pointer to a cross context timer handle. */ +typedef TMTIMERHANDLE *PTMTIMERHANDLE; +/** A NIL timer handle. */ +#define NIL_TMTIMERHANDLE ((uint64_t)UINT64_MAX) + +/** SSM Operation handle. */ +typedef struct SSMHANDLE *PSSMHANDLE; +/** Pointer to a const SSM stream method table. */ +typedef struct SSMSTRMOPS const *PCSSMSTRMOPS; + +/** Pointer to a CPUMCTX. */ +typedef struct CPUMCTX *PCPUMCTX; +/** Pointer to a const CPUMCTX. */ +typedef const struct CPUMCTX *PCCPUMCTX; + +/** Pointer to a selector register. */ +typedef struct CPUMSELREG *PCPUMSELREG; +/** Pointer to a const selector register. */ +typedef const struct CPUMSELREG *PCCPUMSELREG; + +/** Pointer to selector hidden registers. + * @deprecated Replaced by PCPUMSELREG */ +typedef struct CPUMSELREG *PCPUMSELREGHID; +/** Pointer to const selector hidden registers. + * @deprecated Replaced by PCCPUMSELREG */ +typedef const struct CPUMSELREG *PCCPUMSELREGHID; + +/** A cross context DBGF tracer event source handle. */ +typedef uint64_t DBGFTRACEREVTSRC; +/** Pointer to a cross context DBGF tracer event source handle. */ +typedef DBGFTRACEREVTSRC *PDBGFTRACEREVTSRC; +/** A NIL DBGF tracer event source handle. */ +#define NIL_DBGFTRACEREVTSRC ((uint64_t)UINT64_MAX) + +/** Pointer to a DBGF tracer instance for the current context. */ +#ifdef IN_RING3 +typedef struct DBGFTRACERINSR3 *PDBGFTRACERINSCC; +#elif defined(IN_RING0) || defined(DOXYGEN_RUNNING) +typedef struct DBGFTRACERINSR0 *PDBGFTRACERINSCC; +#else +typedef struct DBGFTRACERINSRC *PDBGFTRACERINSCC; +#endif +/** Pointer to a pointer a DBGF tracer instance for the current context. */ +typedef PDBGFTRACERINSCC *PPDBGFTRACERINSCC; +/** R3 pointer to a DBGF tracer instance. */ +typedef R3PTRTYPE(struct DBGFTRACERINSR3 *) PDBGFTRACERINSR3; +/** R0 pointer to a DBGF tracer instance. */ +typedef R0PTRTYPE(struct DBGFTRACERINSR0 *) PDBGFTRACERINSR0; +/** RC pointer to a DBGF tracer instance. */ +typedef RCPTRTYPE(struct DBGFTRACERINSRC *) PDBGFTRACERINSRC; + +/** A cross context DBGF breakpoint owner handle. */ +typedef uint32_t DBGFBPOWNER; +/** Pointer to a cross context DBGF breakpoint owner handle. */ +typedef DBGFBPOWNER *PDBGFBPOWNER; +/** A NIL DBGF breakpoint owner handle. */ +#define NIL_DBGFBPOWNER ((uint32_t)UINT32_MAX) + +/** A cross context DBGF breakpoint handle. */ +typedef uint32_t DBGFBP; +/** Pointer to a cross context DBGF breakpoint handle. */ +typedef DBGFBP *PDBGFBP; +/** A NIL DBGF breakpoint handle. */ +#define NIL_DBGFBP ((uint32_t)UINT32_MAX) + +/** A sample report handle. */ +typedef struct DBGFSAMPLEREPORTINT *DBGFSAMPLEREPORT; +/** Pointer to a sample report handle. */ +typedef DBGFSAMPLEREPORT *PDBGFSAMPLEREPORT; +/** @} */ + + +/** @defgroup grp_types_idt Interrupt Descriptor Table Entry. + * @todo This all belongs in x86.h! + * @{ */ + +/** @todo VBOXIDT -> VBOXDESCIDT, skip the complex variations. We'll never use them. */ + +/** IDT Entry, Task Gate view. */ +#pragma pack(1) /* paranoia */ +typedef struct VBOXIDTE_TASKGATE +{ + /** Reserved. */ + unsigned u16Reserved1 : 16; + /** Task Segment Selector. */ + unsigned u16TSS : 16; + /** More reserved. */ + unsigned u8Reserved2 : 8; + /** Fixed value bit 0 - Set to 1. */ + unsigned u1Fixed0 : 1; + /** Busy bit. */ + unsigned u1Busy : 1; + /** Fixed value bit 2 - Set to 1. */ + unsigned u1Fixed1 : 1; + /** Fixed value bit 3 - Set to 0. */ + unsigned u1Fixed2 : 1; + /** Fixed value bit 4 - Set to 0. */ + unsigned u1Fixed3 : 1; + /** Descriptor Privilege level. */ + unsigned u2DPL : 2; + /** Present flag. */ + unsigned u1Present : 1; + /** Reserved. */ + unsigned u16Reserved3 : 16; +} VBOXIDTE_TASKGATE; +#pragma pack() +/** Pointer to IDT Entry, Task gate view. */ +typedef VBOXIDTE_TASKGATE *PVBOXIDTE_TASKGATE; + + +/** IDT Entry, Intertupt gate view. */ +#pragma pack(1) /* paranoia */ +typedef struct VBOXIDTE_INTERRUPTGATE +{ + /** Low offset word. */ + unsigned u16OffsetLow : 16; + /** Segment Selector. */ + unsigned u16SegSel : 16; + /** Reserved. */ + unsigned u5Reserved2 : 5; + /** Fixed value bit 0 - Set to 0. */ + unsigned u1Fixed0 : 1; + /** Fixed value bit 1 - Set to 0. */ + unsigned u1Fixed1 : 1; + /** Fixed value bit 2 - Set to 0. */ + unsigned u1Fixed2 : 1; + /** Fixed value bit 3 - Set to 0. */ + unsigned u1Fixed3 : 1; + /** Fixed value bit 4 - Set to 1. */ + unsigned u1Fixed4 : 1; + /** Fixed value bit 5 - Set to 1. */ + unsigned u1Fixed5 : 1; + /** Gate size, 1 = 32 bits, 0 = 16 bits. */ + unsigned u132BitGate : 1; + /** Fixed value bit 5 - Set to 0. */ + unsigned u1Fixed6 : 1; + /** Descriptor Privilege level. */ + unsigned u2DPL : 2; + /** Present flag. */ + unsigned u1Present : 1; + /** High offset word. */ + unsigned u16OffsetHigh : 16; +} VBOXIDTE_INTERRUPTGATE; +#pragma pack() +/** Pointer to IDT Entry, Interrupt gate view. */ +typedef VBOXIDTE_INTERRUPTGATE *PVBOXIDTE_INTERRUPTGATE; + +/** IDT Entry, Trap Gate view. */ +#pragma pack(1) /* paranoia */ +typedef struct VBOXIDTE_TRAPGATE +{ + /** Low offset word. */ + unsigned u16OffsetLow : 16; + /** Segment Selector. */ + unsigned u16SegSel : 16; + /** Reserved. */ + unsigned u5Reserved2 : 5; + /** Fixed value bit 0 - Set to 0. */ + unsigned u1Fixed0 : 1; + /** Fixed value bit 1 - Set to 0. */ + unsigned u1Fixed1 : 1; + /** Fixed value bit 2 - Set to 0. */ + unsigned u1Fixed2 : 1; + /** Fixed value bit 3 - Set to 1. */ + unsigned u1Fixed3 : 1; + /** Fixed value bit 4 - Set to 1. */ + unsigned u1Fixed4 : 1; + /** Fixed value bit 5 - Set to 1. */ + unsigned u1Fixed5 : 1; + /** Gate size, 1 = 32 bits, 0 = 16 bits. */ + unsigned u132BitGate : 1; + /** Fixed value bit 5 - Set to 0. */ + unsigned u1Fixed6 : 1; + /** Descriptor Privilege level. */ + unsigned u2DPL : 2; + /** Present flag. */ + unsigned u1Present : 1; + /** High offset word. */ + unsigned u16OffsetHigh : 16; +} VBOXIDTE_TRAPGATE; +#pragma pack() +/** Pointer to IDT Entry, Trap Gate view. */ +typedef VBOXIDTE_TRAPGATE *PVBOXIDTE_TRAPGATE; + +/** IDT Entry Generic view. */ +#pragma pack(1) /* paranoia */ +typedef struct VBOXIDTE_GENERIC +{ + /** Low offset word. */ + unsigned u16OffsetLow : 16; + /** Segment Selector. */ + unsigned u16SegSel : 16; + /** Reserved. */ + unsigned u5Reserved : 5; + /** IDT Type part one (not used for task gate). */ + unsigned u3Type1 : 3; + /** IDT Type part two. */ + unsigned u5Type2 : 5; + /** Descriptor Privilege level. */ + unsigned u2DPL : 2; + /** Present flag. */ + unsigned u1Present : 1; + /** High offset word. */ + unsigned u16OffsetHigh : 16; +} VBOXIDTE_GENERIC; +#pragma pack() +/** Pointer to IDT Entry Generic view. */ +typedef VBOXIDTE_GENERIC *PVBOXIDTE_GENERIC; + +/** IDT Type1 value. (Reserved for task gate!) */ +#define VBOX_IDTE_TYPE1 0 +/** IDT Type2 value - Task gate. */ +#define VBOX_IDTE_TYPE2_TASK 0x5 +/** IDT Type2 value - 16 bit interrupt gate. */ +#define VBOX_IDTE_TYPE2_INT_16 0x6 +/** IDT Type2 value - 32 bit interrupt gate. */ +#define VBOX_IDTE_TYPE2_INT_32 0xe +/** IDT Type2 value - 16 bit trap gate. */ +#define VBOX_IDTE_TYPE2_TRAP_16 0x7 +/** IDT Type2 value - 32 bit trap gate. */ +#define VBOX_IDTE_TYPE2_TRAP_32 0xf + +/** IDT Entry. */ +#pragma pack(1) /* paranoia */ +typedef union VBOXIDTE +{ + /** Task gate view. */ + VBOXIDTE_TASKGATE Task; + /** Trap gate view. */ + VBOXIDTE_TRAPGATE Trap; + /** Interrupt gate view. */ + VBOXIDTE_INTERRUPTGATE Int; + /** Generic IDT view. */ + VBOXIDTE_GENERIC Gen; + + /** 8 bit unsigned integer view. */ + uint8_t au8[8]; + /** 16 bit unsigned integer view. */ + uint16_t au16[4]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; + /** 64 bit unsigned integer view. */ + uint64_t au64; +} VBOXIDTE; +#pragma pack() +/** Pointer to IDT Entry. */ +typedef VBOXIDTE *PVBOXIDTE; +/** Pointer to IDT Entry. */ +typedef VBOXIDTE const *PCVBOXIDTE; + +/** IDT Entry, 64-bit mode, Intertupt gate view. */ +#pragma pack(1) /* paranoia */ +typedef struct VBOXIDTE64_INTERRUPTGATE +{ + /** Low offset word. */ + unsigned u16OffsetLow : 16; + /** Segment Selector. */ + unsigned u16SegSel : 16; + /** Interrupt Stack Table Index. */ + unsigned u3Ist : 3; + /** Fixed value bit 0 - Set to 0. */ + unsigned u1Fixed0 : 1; + /** Fixed value bit 1 - Set to 0. */ + unsigned u1Fixed1 : 1; + /** Fixed value bit 2 - Set to 0. */ + unsigned u1Fixed2 : 1; + /** Fixed value bit 3 - Set to 0. */ + unsigned u1Fixed3 : 1; + /** Fixed value bit 4 - Set to 0. */ + unsigned u1Fixed4 : 1; + /** Fixed value bit 5 - Set to 0. */ + unsigned u1Fixed5 : 1; + /** Fixed value bit 6 - Set to 1. */ + unsigned u1Fixed6 : 1; + /** Fixed value bit 7 - Set to 1. */ + unsigned u1Fixed7 : 1; + /** Gate size, 1 = 32 bits, 0 = 16 bits. */ + unsigned u132BitGate : 1; + /** Fixed value bit 5 - Set to 0. */ + unsigned u1Fixed8 : 1; + /** Descriptor Privilege level. */ + unsigned u2DPL : 2; + /** Present flag. */ + unsigned u1Present : 1; + /** High offset word. */ + unsigned u16OffsetHigh : 16; + /** Offset bits 32..63. */ + unsigned u32OffsetHigh64; + /** Reserved. */ + unsigned u32Reserved; +} VBOXIDTE64_INTERRUPTGATE; +#pragma pack() +/** Pointer to IDT Entry, 64-bit mode, Interrupt gate view. */ +typedef VBOXIDTE64_INTERRUPTGATE *PVBOXIDTE64_INTERRUPTGATE; + +/** IDT Entry, 64-bit mode, Trap gate view. */ +#pragma pack(1) /* paranoia */ +typedef struct VBOXIDTE64_TRAPGATE +{ + /** Low offset word. */ + unsigned u16OffsetLow : 16; + /** Segment Selector. */ + unsigned u16SegSel : 16; + /** Interrupt Stack Table Index. */ + unsigned u3Ist : 3; + /** Fixed value bit 0 - Set to 0. */ + unsigned u1Fixed0 : 1; + /** Fixed value bit 1 - Set to 0. */ + unsigned u1Fixed1 : 1; + /** Fixed value bit 2 - Set to 0. */ + unsigned u1Fixed2 : 1; + /** Fixed value bit 3 - Set to 0. */ + unsigned u1Fixed3 : 1; + /** Fixed value bit 4 - Set to 0. */ + unsigned u1Fixed4 : 1; + /** Fixed value bit 5 - Set to 1. */ + unsigned u1Fixed5 : 1; + /** Fixed value bit 6 - Set to 1. */ + unsigned u1Fixed6 : 1; + /** Fixed value bit 7 - Set to 1. */ + unsigned u1Fixed7 : 1; + /** Gate size, 1 = 32 bits, 0 = 16 bits. */ + unsigned u132BitGate : 1; + /** Fixed value bit 5 - Set to 0. */ + unsigned u1Fixed8 : 1; + /** Descriptor Privilege level. */ + unsigned u2DPL : 2; + /** Present flag. */ + unsigned u1Present : 1; + /** High offset word. */ + unsigned u16OffsetHigh : 16; + /** Offset bits 32..63. */ + unsigned u32OffsetHigh64; + /** Reserved. */ + unsigned u32Reserved; +} VBOXIDTE64_TRAPGATE; +#pragma pack() +/** Pointer to IDT Entry, 64-bit mode, Trap gate view. */ +typedef VBOXIDTE64_TRAPGATE *PVBOXIDTE64_TRAPGATE; + +/** IDT Entry, 64-bit mode, Generic view. */ +#pragma pack(1) /* paranoia */ +typedef struct VBOXIDTE64_GENERIC +{ + /** Low offset word. */ + unsigned u16OffsetLow : 16; + /** Segment Selector. */ + unsigned u16SegSel : 16; + /** Reserved. */ + unsigned u3Ist : 3; + /** Fixed value bit 0 - Set to 0. */ + unsigned u1Fixed0 : 1; + /** Fixed value bit 1 - Set to 0. */ + unsigned u1Fixed1 : 1; + /** IDT Type part one (not used for task gate). */ + unsigned u3Type1 : 3; + /** IDT Type part two. */ + unsigned u5Type2 : 5; + /** Descriptor Privilege level. */ + unsigned u2DPL : 2; + /** Present flag. */ + unsigned u1Present : 1; + /** High offset word. */ + unsigned u16OffsetHigh : 16; + /** Offset bits 32..63. */ + unsigned u32OffsetHigh64; + /** Reserved. */ + unsigned u32Reserved; +} VBOXIDTE64_GENERIC; +#pragma pack() +/** Pointer to IDT Entry, 64-bit mode, Generic view. */ +typedef VBOXIDTE64_GENERIC *PVBOXIDTE64_GENERIC; + +/** IDT Entry, 64-bit mode. */ +#pragma pack(1) /* paranoia */ +typedef union VBOXIDTE64 +{ + /** Trap gate view. */ + VBOXIDTE64_TRAPGATE Trap; + /** Interrupt gate view. */ + VBOXIDTE64_INTERRUPTGATE Int; + /** Generic IDT view. */ + VBOXIDTE64_GENERIC Gen; + + /** 8 bit unsigned integer view. */ + uint8_t au8[16]; + /** 16 bit unsigned integer view. */ + uint16_t au16[8]; + /** 32 bit unsigned integer view. */ + uint32_t au32[4]; + /** 64 bit unsigned integer view. */ + uint64_t au64[2]; +} VBOXIDTE64; +#pragma pack() +/** Pointer to IDT Entry. */ +typedef VBOXIDTE64 *PVBOXIDTE64; +/** Pointer to IDT Entry. */ +typedef VBOXIDTE64 const *PCVBOXIDTE64; + +#pragma pack(1) +/** IDTR */ +typedef struct VBOXIDTR +{ + /** Size of the IDT. */ + uint16_t cbIdt; + /** Address of the IDT. */ + uint64_t pIdt; +} VBOXIDTR, *PVBOXIDTR; +#pragma pack() + + +/** @def VBOXIDTE_OFFSET + * Return the offset of an IDT entry. + */ +#define VBOXIDTE_OFFSET(desc) \ + ( ((uint32_t)((desc).Gen.u16OffsetHigh) << 16) \ + | ( (desc).Gen.u16OffsetLow ) ) + +/** @def VBOXIDTE64_OFFSET + * Return the offset of an IDT entry. + */ +#define VBOXIDTE64_OFFSET(desc) \ + ( ((uint64_t)((desc).Gen.u32OffsetHigh64) << 32) \ + | ((uint32_t)((desc).Gen.u16OffsetHigh) << 16) \ + | ( (desc).Gen.u16OffsetLow ) ) + +#pragma pack(1) +/** GDTR */ +typedef struct VBOXGDTR +{ + /** Size of the GDT. */ + uint16_t cbGdt; + /** Address of the GDT. */ + uint64_t pGdt; +} VBOXGDTR; +#pragma pack() +/** Pointer to GDTR. */ +typedef VBOXGDTR *PVBOXGDTR; + +/** @} */ + + +/** + * 32-bit Task Segment used in raw mode. + * @todo Move this to SELM! Use X86TSS32 instead. + */ +#pragma pack(1) +typedef struct VBOXTSS +{ + /** 0x00 - Back link to previous task. (static) */ + RTSEL selPrev; + uint16_t padding1; + /** 0x04 - Ring-0 stack pointer. (static) */ + uint32_t esp0; + /** 0x08 - Ring-0 stack segment. (static) */ + RTSEL ss0; + uint16_t padding_ss0; + /** 0x0c - Ring-1 stack pointer. (static) */ + uint32_t esp1; + /** 0x10 - Ring-1 stack segment. (static) */ + RTSEL ss1; + uint16_t padding_ss1; + /** 0x14 - Ring-2 stack pointer. (static) */ + uint32_t esp2; + /** 0x18 - Ring-2 stack segment. (static) */ + RTSEL ss2; + uint16_t padding_ss2; + /** 0x1c - Page directory for the task. (static) */ + uint32_t cr3; + /** 0x20 - EIP before task switch. */ + uint32_t eip; + /** 0x24 - EFLAGS before task switch. */ + uint32_t eflags; + /** 0x28 - EAX before task switch. */ + uint32_t eax; + /** 0x2c - ECX before task switch. */ + uint32_t ecx; + /** 0x30 - EDX before task switch. */ + uint32_t edx; + /** 0x34 - EBX before task switch. */ + uint32_t ebx; + /** 0x38 - ESP before task switch. */ + uint32_t esp; + /** 0x3c - EBP before task switch. */ + uint32_t ebp; + /** 0x40 - ESI before task switch. */ + uint32_t esi; + /** 0x44 - EDI before task switch. */ + uint32_t edi; + /** 0x48 - ES before task switch. */ + RTSEL es; + uint16_t padding_es; + /** 0x4c - CS before task switch. */ + RTSEL cs; + uint16_t padding_cs; + /** 0x50 - SS before task switch. */ + RTSEL ss; + uint16_t padding_ss; + /** 0x54 - DS before task switch. */ + RTSEL ds; + uint16_t padding_ds; + /** 0x58 - FS before task switch. */ + RTSEL fs; + uint16_t padding_fs; + /** 0x5c - GS before task switch. */ + RTSEL gs; + uint16_t padding_gs; + /** 0x60 - LDTR before task switch. */ + RTSEL selLdt; + uint16_t padding_ldt; + /** 0x64 - Debug trap flag */ + uint16_t fDebugTrap; + /** 0x66 - Offset relative to the TSS of the start of the I/O Bitmap + * and the end of the interrupt redirection bitmap. */ + uint16_t offIoBitmap; + /** 0x68 - 32 bytes for the virtual interrupt redirection bitmap. (VME) */ + uint8_t IntRedirBitmap[32]; +} VBOXTSS; +#pragma pack() +/** Pointer to task segment. */ +typedef VBOXTSS *PVBOXTSS; +/** Pointer to const task segment. */ +typedef const VBOXTSS *PCVBOXTSS; + + +/** Pointer to a callback method table provided by the VM API user. */ +typedef struct VMM2USERMETHODS const *PCVMM2USERMETHODS; + + +/** + * Data transport buffer (scatter/gather) + */ +typedef struct PDMDATASEG +{ + /** Length of buffer in entry. */ + size_t cbSeg; + /** Pointer to the start of the buffer. */ + void *pvSeg; +} PDMDATASEG; +/** Pointer to a data transport segment. */ +typedef PDMDATASEG *PPDMDATASEG; +/** Pointer to a const data transport segment. */ +typedef PDMDATASEG const *PCPDMDATASEG; + + +/** + * Forms of generic segment offloading. + */ +typedef enum PDMNETWORKGSOTYPE +{ + /** Invalid zero value. */ + PDMNETWORKGSOTYPE_INVALID = 0, + /** TCP/IPv4 - no CWR/ECE encoding. */ + PDMNETWORKGSOTYPE_IPV4_TCP, + /** TCP/IPv6 - no CWR/ECE encoding. */ + PDMNETWORKGSOTYPE_IPV6_TCP, + /** UDP/IPv4. */ + PDMNETWORKGSOTYPE_IPV4_UDP, + /** UDP/IPv6. */ + PDMNETWORKGSOTYPE_IPV6_UDP, + /** TCP/IPv6 over IPv4 tunneling - no CWR/ECE encoding. + * The header offsets and sizes relates to IPv4 and TCP, the IPv6 header is + * figured out as needed. + * @todo Needs checking against facts, this is just an outline of the idea. */ + PDMNETWORKGSOTYPE_IPV4_IPV6_TCP, + /** UDP/IPv6 over IPv4 tunneling. + * The header offsets and sizes relates to IPv4 and UDP, the IPv6 header is + * figured out as needed. + * @todo Needs checking against facts, this is just an outline of the idea. */ + PDMNETWORKGSOTYPE_IPV4_IPV6_UDP, + /** The end of valid GSO types. */ + PDMNETWORKGSOTYPE_END +} PDMNETWORKGSOTYPE; + + +/** + * Generic segment offloading context. + * + * We generally follow the E1000 specs wrt to which header fields we change. + * However the GSO type implies where the checksum fields are and that they are + * always updated from scratch (no half done pseudo checksums). + * + * @remarks This is part of the internal network GSO packets. Take great care + * when making changes. The size is expected to be exactly 8 bytes. + * + * @ingroup grp_pdm + */ +typedef struct PDMNETWORKGSO +{ + /** The type of segmentation offloading we're performing (PDMNETWORKGSOTYPE). */ + uint8_t u8Type; + /** The total header size. */ + uint8_t cbHdrsTotal; + /** The max segment size (MSS) to apply. */ + uint16_t cbMaxSeg; + + /** Offset of the first header (IPv4 / IPv6). 0 if not not needed. */ + uint8_t offHdr1; + /** Offset of the second header (TCP / UDP). 0 if not not needed. */ + uint8_t offHdr2; + /** The header size used for segmentation (equal to offHdr2 in UFO). */ + uint8_t cbHdrsSeg; + /** Unused. */ + uint8_t u8Unused; +} PDMNETWORKGSO; +/** Pointer to a GSO context. + * @ingroup grp_pdm */ +typedef PDMNETWORKGSO *PPDMNETWORKGSO; +/** Pointer to a const GSO context. + * @ingroup grp_pdm */ +typedef PDMNETWORKGSO const *PCPDMNETWORKGSO; + +/** Pointer to a PDM filter handle. + * @ingroup grp_pdm_net_shaper */ +typedef struct PDMNSFILTER *PPDMNSFILTER; +/** Pointer to a network shaper. + * @ingroup grp_pdm_net_shaper */ +typedef struct PDMNETSHAPER *PPDMNETSHAPER; + + +/** + * The current ROM page protection. + * + * @remarks This is part of the saved state. + * @ingroup grp_pgm + */ +typedef enum PGMROMPROT +{ + /** The customary invalid value. */ + PGMROMPROT_INVALID = 0, + /** Read from the virgin ROM page, ignore writes. + * Map the virgin page, use write access handler to ignore writes. */ + PGMROMPROT_READ_ROM_WRITE_IGNORE, + /** Read from the virgin ROM page, write to the shadow RAM. + * Map the virgin page, use write access handler to change the shadow RAM. */ + PGMROMPROT_READ_ROM_WRITE_RAM, + /** Read from the shadow ROM page, ignore writes. + * Map the shadow page read-only, use write access handler to ignore writes. */ + PGMROMPROT_READ_RAM_WRITE_IGNORE, + /** Read from the shadow ROM page, ignore writes. + * Map the shadow page read-write, disabled write access handler. */ + PGMROMPROT_READ_RAM_WRITE_RAM, + /** The end of valid values. */ + PGMROMPROT_END, + /** The usual 32-bit type size hack. */ + PGMROMPROT_32BIT_HACK = 0x7fffffff +} PGMROMPROT; + + +/** + * Page mapping lock. + * @ingroup grp_pgm + */ +typedef struct PGMPAGEMAPLOCK +{ +#if defined(IN_RC) + /** The locked page. */ + void *pvPage; + /** Pointer to the CPU that made the mapping. + * In ring-0 and raw-mode context we don't intend to ever allow long term + * locking and this is a way of making sure we're still on the same CPU. */ + PVMCPU pVCpu; +#else + /** Pointer to the PGMPAGE and lock type. + * bit-0 abuse: set=write, clear=read. */ + uintptr_t uPageAndType; +/** Read lock type value. */ +# define PGMPAGEMAPLOCK_TYPE_READ ((uintptr_t)0) +/** Write lock type value. */ +# define PGMPAGEMAPLOCK_TYPE_WRITE ((uintptr_t)1) +/** Lock type mask. */ +# define PGMPAGEMAPLOCK_TYPE_MASK ((uintptr_t)1) + /** Pointer to the PGMCHUNKR3MAP. */ + void *pvMap; +#endif +} PGMPAGEMAPLOCK; +/** Pointer to a page mapping lock. + * @ingroup grp_pgm */ +typedef PGMPAGEMAPLOCK *PPGMPAGEMAPLOCK; + + +/** Pointer to a info helper callback structure. */ +typedef struct DBGFINFOHLP *PDBGFINFOHLP; +/** Pointer to a const info helper callback structure. */ +typedef const struct DBGFINFOHLP *PCDBGFINFOHLP; + +/** Pointer to a const register descriptor. */ +typedef struct DBGFREGDESC const *PCDBGFREGDESC; + + +/** Configuration manager tree node - A key. */ +typedef struct CFGMNODE *PCFGMNODE; + +/** Configuration manager tree leaf - A value. */ +typedef struct CFGMLEAF *PCFGMLEAF; + + +/** + * CPU modes. + */ +typedef enum CPUMMODE +{ + /** The usual invalid zero entry. */ + CPUMMODE_INVALID = 0, + /** Real mode. */ + CPUMMODE_REAL, + /** Protected mode (32-bit). */ + CPUMMODE_PROTECTED, + /** Long mode (64-bit). */ + CPUMMODE_LONG +} CPUMMODE; + + +/** + * CPU mode flags (DISSTATE::mode). + */ +typedef enum DISCPUMODE +{ + DISCPUMODE_INVALID = 0, + DISCPUMODE_16BIT, + DISCPUMODE_32BIT, + DISCPUMODE_64BIT, + /** hack forcing the size of the enum to 32-bits. */ + DISCPUMODE_MAKE_32BIT_HACK = 0x7fffffff +} DISCPUMODE; + +/** Pointer to the disassembler state. */ +typedef struct DISSTATE *PDISSTATE; +/** Pointer to a const disassembler state. */ +typedef struct DISSTATE const *PCDISSTATE; + +/** @deprecated PDISSTATE and change pCpu and pDisState to pDis. */ +typedef PDISSTATE PDISCPUSTATE; +/** @deprecated PCDISSTATE and change pCpu and pDisState to pDis. */ +typedef PCDISSTATE PCDISCPUSTATE; + + +/** + * Shared region description (needed by GMM and others, thus global). + * @ingroup grp_vmmdev + */ +typedef struct VMMDEVSHAREDREGIONDESC +{ + RTGCPTR64 GCRegionAddr; + uint32_t cbRegion; + uint32_t u32Alignment; +} VMMDEVSHAREDREGIONDESC; + + +/** + * A PCI bus:device:function (BDF) identifier. + * + * All 16 bits of a BDF are valid according to the PCI spec. We need one extra bit + * to determine whether the BDF is valid in interfaces where the BDF may be + * optional. + */ +typedef uint32_t PCIBDF; +/** PCIBDF flag: Invalid. */ +#define PCI_BDF_F_INVALID RT_BIT(31) +/** Nil PCIBDF value. */ +#define NIL_PCIBDF PCI_BDF_F_INVALID + +/** Pointer to an MSI message struct. */ +typedef struct MSIMSG *PMSIMSG; +/** Pointer to a const MSI message struct. */ +typedef const struct MSIMSG *PCMSIMSG; + + +/** @} */ + +#endif /* !VBOX_INCLUDED_types_h */ diff --git a/include/VBox/usb.h b/include/VBox/usb.h new file mode 100644 index 00000000..e83b7661 --- /dev/null +++ b/include/VBox/usb.h @@ -0,0 +1,280 @@ +/** @file + * USB - Universal Serial Bus. (DEV,Main?) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_usb_h +#define VBOX_INCLUDED_usb_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_usblib_usb USB Device Structures & Types + * @ingroup grp_usblib + * @{ + */ + +/** + * The USB host device state. + */ +typedef enum USBDEVICESTATE +{ + /** The device is unsupported. */ + USBDEVICESTATE_UNSUPPORTED = 1, + /** The device is in use by the host. */ + USBDEVICESTATE_USED_BY_HOST, + /** The device is in use by the host but could perhaps be captured even so. */ + USBDEVICESTATE_USED_BY_HOST_CAPTURABLE, + /** The device is not used by the host or any guest. */ + USBDEVICESTATE_UNUSED, + /** The device is held by the proxy for later guest usage. */ + USBDEVICESTATE_HELD_BY_PROXY, + /** The device in use by a guest. */ + USBDEVICESTATE_USED_BY_GUEST, + /** The usual 32-bit hack. */ + USBDEVICESTATE_32BIT_HACK = 0x7fffffff +} USBDEVICESTATE; + + +/** + * The USB device speed. + */ +typedef enum USBDEVICESPEED +{ + /** Unknown. */ + USBDEVICESPEED_UNKNOWN = 0, + /** Low speed (1.5 Mbit/s). */ + USBDEVICESPEED_LOW, + /** Full speed (12 Mbit/s). */ + USBDEVICESPEED_FULL, + /** High speed (480 Mbit/s). */ + USBDEVICESPEED_HIGH, + /** Variable speed - USB 2.5 / wireless. */ + USBDEVICESPEED_VARIABLE, + /** Super speed - USB 3.0 (5Gbit/s). */ + USBDEVICESPEED_SUPER, + /** The usual 32-bit hack. */ + USBDEVICESPEED_32BIT_HACK = 0x7fffffff +} USBDEVICESPEED; + + +/** + * USB host device description. + * Used for enumeration of USB devices. + */ +typedef struct USBDEVICE +{ + /** If linked, this is the pointer to the next device in the list. */ + struct USBDEVICE *pNext; + /** If linked doubly, this is the pointer to the prev device in the list. */ + struct USBDEVICE *pPrev; + /** Manufacturer string. */ + const char *pszManufacturer; + /** Product string. */ + const char *pszProduct; + /** Serial number string. */ + const char *pszSerialNumber; + /** The address of the device. */ + const char *pszAddress; + /** The backend to use for this device. */ + const char *pszBackend; + + /** Vendor ID. */ + uint16_t idVendor; + /** Product ID. */ + uint16_t idProduct; + /** Revision, integer part. */ + uint16_t bcdDevice; + /** USB version number. */ + uint16_t bcdUSB; + /** Device class. */ + uint8_t bDeviceClass; + /** Device subclass. */ + uint8_t bDeviceSubClass; + /** Device protocol */ + uint8_t bDeviceProtocol; + /** Number of configurations. */ + uint8_t bNumConfigurations; + /** The device state. */ + USBDEVICESTATE enmState; + /** The device speed. */ + USBDEVICESPEED enmSpeed; + /** Serial hash. */ + uint64_t u64SerialHash; + /** The USB Bus number. */ + uint8_t bBus; + /** The port number. */ + uint8_t bPort; + /** The hub+port path. */ + char *pszPortPath; +#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) + /** Device number. */ + uint8_t bDevNum; +#endif +#ifdef RT_OS_WINDOWS + /** Alternate address. Can be NULL. */ + char *pszAltAddress; + /** The hub name. */ + char *pszHubName; +#endif +#ifdef RT_OS_SOLARIS + /** The /devices path of the device. */ + char *pszDevicePath; + /** Do we have a partial or full device descriptor here. */ + bool fPartialDescriptor; +#endif +} USBDEVICE; +/** Pointer to a USB device. */ +typedef USBDEVICE *PUSBDEVICE; +/** Pointer to a const USB device. */ +typedef USBDEVICE *PCUSBDEVICE; + + +#ifdef VBOX_USB_H_INCL_DESCRIPTORS /* for the time being, since this may easily conflict with system headers */ + +/** + * USB device descriptor. + */ +#pragma pack(1) +typedef struct USBDESCHDR +{ + /** The descriptor length. */ + uint8_t bLength; + /** The descriptor type. */ + uint8_t bDescriptorType; +} USBDESCHDR; +#pragma pack() +/** Pointer to an USB descriptor header. */ +typedef USBDESCHDR *PUSBDESCHDR; + +/** @name Descriptor Type values (bDescriptorType) + * {@ */ +#if !defined(USB_DT_DEVICE) && !defined(USB_DT_ENDPOINT) +# define USB_DT_DEVICE 0x01 +# define USB_DT_CONFIG 0x02 +# define USB_DT_STRING 0x03 +# define USB_DT_INTERFACE 0x04 +# define USB_DT_ENDPOINT 0x05 + +# define USB_DT_HID 0x21 +# define USB_DT_REPORT 0x22 +# define USB_DT_PHYSICAL 0x23 +# define USB_DT_HUB 0x29 +#endif +/** @} */ + + +/** + * USB device descriptor. + */ +#pragma pack(1) +typedef struct USBDEVICEDESC +{ + /** The descriptor length. (Usually sizeof(USBDEVICEDESC).) */ + uint8_t bLength; + /** The descriptor type. (USB_DT_DEVICE) */ + uint8_t bDescriptorType; + /** USB version number. */ + uint16_t bcdUSB; + /** Device class. */ + uint8_t bDeviceClass; + /** Device subclass. */ + uint8_t bDeviceSubClass; + /** Device protocol */ + uint8_t bDeviceProtocol; + /** The max packet size of the default control pipe. */ + uint8_t bMaxPacketSize0; + /** Vendor ID. */ + uint16_t idVendor; + /** Product ID. */ + uint16_t idProduct; + /** Revision, integer part. */ + uint16_t bcdDevice; + /** Manufacturer string index. */ + uint8_t iManufacturer; + /** Product string index. */ + uint8_t iProduct; + /** Serial number string index. */ + uint8_t iSerialNumber; + /** Number of configurations. */ + uint8_t bNumConfigurations; +} USBDEVICEDESC; +#pragma pack() +/** Pointer to an USB device descriptor. */ +typedef USBDEVICEDESC *PUSBDEVICEDESC; + +/** @name Class codes (bDeviceClass) + * @{ */ +#ifndef USB_HUB_CLASSCODE +# define USB_HUB_CLASSCODE 0x09 +#endif +/** @} */ + +/** + * USB configuration descriptor. + */ +#pragma pack(1) +typedef struct USBCONFIGDESC +{ + /** The descriptor length. (Usually sizeof(USBCONFIGDESC).) */ + uint8_t bLength; + /** The descriptor type. (USB_DT_CONFIG) */ + uint8_t bDescriptorType; + /** The length of the configuration descriptor plus all associated descriptors. */ + uint16_t wTotalLength; + /** Number of interfaces. */ + uint8_t bNumInterfaces; + /** Configuration number. (For SetConfiguration().) */ + uint8_t bConfigurationValue; + /** Configuration description string. */ + uint8_t iConfiguration; + /** Configuration characteristics. */ + uint8_t bmAttributes; + /** Maximum power consumption of the USB device in this config. */ + uint8_t MaxPower; +} USBCONFIGDESC; +#pragma pack() +/** Pointer to an USB configuration descriptor. */ +typedef USBCONFIGDESC *PUSBCONFIGDESC; + +#endif /* VBOX_USB_H_INCL_DESCRIPTORS */ + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_usb_h */ + diff --git a/include/VBox/usbfilter.h b/include/VBox/usbfilter.h new file mode 100644 index 00000000..3f7f15ca --- /dev/null +++ b/include/VBox/usbfilter.h @@ -0,0 +1,271 @@ +/** @file + * USBFilter - USB Filter constructs shared by kernel and user mode. + * (DEV,HDrv,Main) + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_usbfilter_h +#define VBOX_INCLUDED_usbfilter_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assert.h> +#include <VBox/cdefs.h> +#include <VBox/usb.h> + + +/** @defgroup grp_usbfilter USBFilter - USB Filter constructs shared by kernel and user mode + * @ingroup grp_usblib + * @{ + */ + +/** + * How to match a field. + * + * @remarks This is a binary interface (drivers). + */ +typedef enum USBFILTERMATCH +{ + /** The usual invalid first zero value. */ + USBFILTERMATCH_INVALID = 0, + /** Ignore this field (always matching). + * Device Data: No value present. */ + USBFILTERMATCH_IGNORE, + /** Only require this field to be present on the device. */ + USBFILTERMATCH_PRESENT, + + /** Numeric Field: The first numeric field matching method. */ + USBFILTERMATCH_NUM_FIRST, + /** Numeric Field: Exact match, required to be present. */ + USBFILTERMATCH_NUM_EXACT = USBFILTERMATCH_NUM_FIRST, + /** Numeric Field: Exact match or not present. */ + USBFILTERMATCH_NUM_EXACT_NP, + /** Numeric Field: Expression match, required to be present. + * The expression is represented as a string. */ + USBFILTERMATCH_NUM_EXPRESSION, + /** Numeric Field: Expression match or not present. + * The expression is represented as a string. */ + USBFILTERMATCH_NUM_EXPRESSION_NP, + /** Numeric Field: The last numeric field matching method (inclusive). */ + USBFILTERMATCH_NUM_LAST = USBFILTERMATCH_NUM_EXPRESSION_NP, + + /** String Field: The first string field matching method. */ + USBFILTERMATCH_STR_FIRST, + /** String Field: Exact match, required to be present. */ + USBFILTERMATCH_STR_EXACT = USBFILTERMATCH_STR_FIRST, + /** String Field: Exact match or not present. */ + USBFILTERMATCH_STR_EXACT_NP, + /** String Field: Pattern match, required to be present.*/ + USBFILTERMATCH_STR_PATTERN, + /** String Field: Pattern match or not present.*/ + USBFILTERMATCH_STR_PATTERN_NP, + /** String Field: The last string field matching method (inclusive). */ + USBFILTERMATCH_STR_LAST = USBFILTERMATCH_STR_PATTERN_NP, + + /** The end of valid matching methods (exclusive). */ + USBFILTERMATCH_END +} USBFILTERMATCH; +AssertCompile(USBFILTERMATCH_END == 11); + + +/** + * A USB filter field. + * + * @remarks This is a binary interface (drivers). + */ +typedef struct USBFILTERFIELD +{ + /** The matching method. (USBFILTERMATCH) */ + uint16_t enmMatch; + /** The field value or offset into the string table. + * The enmMatch field decides which it is. */ + uint16_t u16Value; +} USBFILTERFIELD; +AssertCompileSize(USBFILTERFIELD, 4); +/** Pointer to a USB filter field. */ +typedef USBFILTERFIELD *PUSBFILTERFIELD; +/** Pointer to a const USBFILTERFIELD. */ +typedef const USBFILTERFIELD *PCUSBFILTERFIELD; + + +/** + * USB filter field index. + * + * This is used as an index into the USBFILTER::aFields array. + * + * @remarks This is a binary interface (drivers). + */ +typedef enum USBFILTERIDX +{ + /** idVendor (= 0) */ + USBFILTERIDX_VENDOR_ID = 0, + /** idProduct (= 1) */ + USBFILTERIDX_PRODUCT_ID, + /** bcdDevice (= 2)*/ + USBFILTERIDX_DEVICE_REV, + USBFILTERIDX_DEVICE = USBFILTERIDX_DEVICE_REV, + /** bDeviceClass (= 3) */ + USBFILTERIDX_DEVICE_CLASS, + /** bDeviceSubClass (= 4) */ + USBFILTERIDX_DEVICE_SUB_CLASS, + /** bDeviceProtocol (= 5) */ + USBFILTERIDX_DEVICE_PROTOCOL, + /** bBus (= 6 )*/ + USBFILTERIDX_BUS, + /** bPort (=7) */ + USBFILTERIDX_PORT, + /** Manufacturer string. (=8) */ + USBFILTERIDX_MANUFACTURER_STR, + /** Product string. (=9) */ + USBFILTERIDX_PRODUCT_STR, + /** SerialNumber string. (=10) */ + USBFILTERIDX_SERIAL_NUMBER_STR, + /** The end of the USB filter fields (exclusive). */ + USBFILTERIDX_END +} USBFILTERIDX; +AssertCompile(USBFILTERIDX_END == 11); + + +/** + * USB Filter types. + * + * The filters types are list in priority order, i.e. highest priority first. + * + * @remarks This is a binary interface (drivers). + */ +typedef enum USBFILTERTYPE +{ + /** The usual invalid first zero value. */ + USBFILTERTYPE_INVALID = 0, + /** The first valid entry. */ + USBFILTERTYPE_FIRST, + /** A one-shot ignore filter that's installed when releasing a device. + * This filter will be automatically removedwhen the device re-appears, + * or when ring-3 decides that time is up, or if ring-3 dies upon us. */ + USBFILTERTYPE_ONESHOT_IGNORE = USBFILTERTYPE_FIRST, + /** A one-shot capture filter that's installed when hijacking a device that's already plugged. + * This filter will be automatically removed when the device re-appears, + * or when ring-3 decides that time is up, or if ring-3 dies upon us. */ + USBFILTERTYPE_ONESHOT_CAPTURE, + /** Ignore filter. + * This picks out devices that shouldn't be captured. */ + USBFILTERTYPE_IGNORE, + /** A normal capture filter. + * When a device matching the filter is attach, we'll take it. */ + USBFILTERTYPE_CAPTURE, + /** The end of the valid filter types (exclusive). */ + USBFILTERTYPE_END, + /** The usual 32-bit hack. */ + USBFILTERTYPE_32BIT_HACK = 0x7fffffff +} USBFILTERTYPE; +AssertCompileSize(USBFILTERTYPE, 4); +AssertCompile(USBFILTERTYPE_END == 5); + + +/** + * USB Filter. + * + * Consider the an abstract data type, use the methods below to access it. + * + * @remarks This is a binary interface (drivers). + */ +typedef struct USBFILTER +{ + /** Magic number (USBFILTER_MAGIC). */ + uint32_t u32Magic; + /** The filter type. */ + USBFILTERTYPE enmType; + /** The filter fields. + * This array is indexed by USBFILTERIDX */ + USBFILTERFIELD aFields[USBFILTERIDX_END]; + /** Offset to the end of the string table (last terminator). (used to speed up things) */ + uint32_t offCurEnd; + /** String table. + * This is used for string and numeric patterns. */ + char achStrTab[256]; +} USBFILTER; +AssertCompileSize(USBFILTER, 312); + +/** Pointer to a USBLib filter. */ +typedef USBFILTER *PUSBFILTER; +/** Pointer to a const USBLib filter. */ +typedef const USBFILTER *PCUSBFILTER; + +/** USBFILTER::u32Magic (Yasuhiro Nightow). */ +#define USBFILTER_MAGIC UINT32_C(0x19670408) + + +RT_C_DECLS_BEGIN + +USBLIB_DECL(void) USBFilterInit(PUSBFILTER pFilter, USBFILTERTYPE enmType); +USBLIB_DECL(void) USBFilterClone(PUSBFILTER pFilter, PCUSBFILTER pToClone); +USBLIB_DECL(void) USBFilterDelete(PUSBFILTER pFilter); +USBLIB_DECL(int) USBFilterValidate(PCUSBFILTER pFilter); +USBLIB_DECL(bool) USBFilterMatch(PCUSBFILTER pFilter, PCUSBFILTER pDevice); +USBLIB_DECL(int) USBFilterMatchRated(PCUSBFILTER pFilter, PCUSBFILTER pDevice); +USBLIB_DECL(bool) USBFilterMatchDevice(PCUSBFILTER pFilter, PCUSBDEVICE pDevice); +USBLIB_DECL(bool) USBFilterIsIdentical(PCUSBFILTER pFilter, PCUSBFILTER pFilter2); + +USBLIB_DECL(int) USBFilterSetFilterType(PUSBFILTER pFilter, USBFILTERTYPE enmType); +USBLIB_DECL(int) USBFilterSetIgnore(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx); +USBLIB_DECL(int) USBFilterSetPresentOnly(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx); +USBLIB_DECL(int) USBFilterSetNumExact(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, uint16_t u16Value, bool fMustBePresent); +USBLIB_DECL(int) USBFilterSetNumExpression(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszExpression, bool fMustBePresent); +USBLIB_DECL(int) USBFilterSetStringExact(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszValue, + bool fMustBePresent, bool fPurge); +USBLIB_DECL(int) USBFilterSetStringPattern(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszPattern, bool fMustBePresent); +USBLIB_DECL(int) USBFilterSetMustBePresent(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, bool fMustBePresent); + +USBLIB_DECL(USBFILTERTYPE) USBFilterGetFilterType(PCUSBFILTER pFilter); +USBLIB_DECL(USBFILTERMATCH) USBFilterGetMatchingMethod(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx); +USBLIB_DECL(int) USBFilterQueryNum(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, uint16_t *pu16Value); +USBLIB_DECL(int) USBFilterGetNum(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx); +USBLIB_DECL(int) USBFilterQueryString(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, char *pszBuf, size_t cchBuf); +USBLIB_DECL(const char *) USBFilterGetString(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx); +USBLIB_DECL(ssize_t) USBFilterGetStringLen(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx); + +USBLIB_DECL(bool) USBFilterHasAnySubstatialCriteria(PCUSBFILTER pFilter); +USBLIB_DECL(bool) USBFilterIsNumericField(USBFILTERIDX enmFieldIdx); +USBLIB_DECL(bool) USBFilterIsStringField(USBFILTERIDX enmFieldIdx); +USBLIB_DECL(bool) USBFilterIsMethodUsingNumericValue(USBFILTERMATCH enmMatchingMethod); +USBLIB_DECL(bool) USBFilterIsMethodUsingStringValue(USBFILTERMATCH enmMatchingMethod); +USBLIB_DECL(bool) USBFilterIsMethodNumeric(USBFILTERMATCH enmMatchingMethod); +USBLIB_DECL(bool) USBFilterIsMethodString(USBFILTERMATCH enmMatchingMethod); + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_usbfilter_h */ diff --git a/include/VBox/usblib-darwin.h b/include/VBox/usblib-darwin.h new file mode 100644 index 00000000..f74d5f92 --- /dev/null +++ b/include/VBox/usblib-darwin.h @@ -0,0 +1,72 @@ +/** @file + * USBLib - Library for wrapping up the VBoxUSB functionality, Darwin flavor. + * (DEV,HDrv,Main) + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_usblib_darwin_h +#define VBOX_INCLUDED_usblib_darwin_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/usbfilter.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_usblib_darwin Darwin USB Specifics + * @ingroup grp_usblib + * @{ + */ + +/** @name VBoxUSB specific device properties. + * VBoxUSB makes use of the OWNER property for communicating between the probe and + * start stage. + * USBProxyServiceDarwin makes use of all of them to correctly determine the state + * of the device. + * @{ */ +/** Contains the pid of the current client. If 0, the kernel is the current client. */ +#define VBOXUSB_CLIENT_KEY "VBoxUSB-Client" +/** Contains the pid of the filter owner (i.e. the VBoxSVC pid). */ +#define VBOXUSB_OWNER_KEY "VBoxUSB-Owner" +/** Contains the ID of the matching filter. */ +#define VBOXUSB_FILTER_KEY "VBoxUSB-Filter" +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_usblib_darwin_h */ + diff --git a/include/VBox/usblib-solaris.h b/include/VBox/usblib-solaris.h new file mode 100644 index 00000000..3cc900bb --- /dev/null +++ b/include/VBox/usblib-solaris.h @@ -0,0 +1,288 @@ +/** @file + * USBLib - Library for wrapping up the VBoxUSB functionality, Solaris flavor. + * (DEV,HDrv,Main) + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_usblib_solaris_h +#define VBOX_INCLUDED_usblib_solaris_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/usbfilter.h> +#include <VBox/vusb.h> +#include <sys/types.h> +#include <sys/ioccom.h> +#include <sys/param.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_usblib_solaris Solaris USB Specifics + * @ingroup grp_usblib + * @{ + */ + +/** @name VBoxUSB specific IOCtls. + * VBoxUSB uses them for resetting USB devices requests from userland. + * USBProxyService/Device makes use of them to communicate with VBoxUSB. + * @{ */ + +/** Ring-3 request wrapper for big requests. + * + * This is necessary because the ioctl number scheme on many Unixy OSes (esp. Solaris) + * only allows a relatively small size to be encoded into the request. So, for big + * request this generic form is used instead. */ +typedef struct VBOXUSBREQ +{ + /** Magic value (VBOXUSB(MON)_MAGIC). */ + uint32_t u32Magic; + /** The size of the data buffer (In & Out). */ + uint32_t cbData; + /** Result code of the request filled by driver. */ + int32_t rc; + /** The user address of the data buffer. */ + RTR3PTR pvDataR3; +} VBOXUSBREQ; +/** Pointer to a request wrapper for solaris. */ +typedef VBOXUSBREQ *PVBOXUSBREQ; +/** Pointer to a const request wrapper for solaris. */ +typedef const VBOXUSBREQ *PCVBOXUSBREQ; + +#pragma pack(1) +typedef struct +{ + /* Pointer to the Filter. */ + USBFILTER Filter; + /* Where to store the added Filter (Id). */ + uintptr_t uId; +} VBOXUSBREQ_ADD_FILTER; + +typedef struct +{ + /* Pointer to Filter (Id) to be removed. */ + uintptr_t uId; +} VBOXUSBREQ_REMOVE_FILTER; + +typedef struct +{ + /** Whether to re-attach the driver. */ + bool fReattach; + /* Physical path of the USB device. */ + char szDevicePath[1]; +} VBOXUSBREQ_RESET_DEVICE; + +typedef struct +{ + /* Where to store the instance. */ + int *pInstance; + /* Physical path of the USB device. */ + char szDevicePath[1]; +} VBOXUSBREQ_DEVICE_INSTANCE; + +typedef struct +{ + /** Where to store the instance. */ + int Instance; + /* Where to store the client path. */ + char szClientPath[MAXPATHLEN]; + /** Device identifier (VendorId:ProductId:Release:StaticPath) */ + char szDeviceIdent[MAXPATHLEN+48]; + /** Callback from monitor specifying client consumer (VM) credentials */ + DECLR0CALLBACKMEMBER(int, pfnSetConsumerCredentials,(RTPROCESS Process, int Instance, void *pvReserved)); +} VBOXUSBREQ_CLIENT_INFO, *PVBOXUSBREQ_CLIENT_INFO; +typedef VBOXUSBREQ_CLIENT_INFO VBOXUSB_CLIENT_INFO; +typedef PVBOXUSBREQ_CLIENT_INFO PVBOXUSB_CLIENT_INFO; + +/** Isoc packet descriptor (Must mirror exactly Solaris USBA's usb_isoc_pkt_descr_t) */ +typedef struct +{ + ushort_t cbPkt; /* Size of the packet */ + ushort_t cbActPkt; /* Size of the packet actually transferred */ + VUSBSTATUS enmStatus; /* Per frame transfer status */ +} VUSBISOC_PKT_DESC; + +/** VBoxUSB IOCtls */ +typedef struct +{ + void *pvUrbR3; /* Pointer to userland URB (untouched by kernel driver) */ + uint8_t bEndpoint; /* Endpoint address */ + VUSBXFERTYPE enmType; /* Xfer type */ + VUSBDIRECTION enmDir; /* Xfer direction */ + VUSBSTATUS enmStatus; /* URB status */ + bool fShortOk; /* Whether receiving less data than requested is acceptable. */ + size_t cbData; /* Size of the data */ + void *pvData; /* Pointer to the data */ + uint32_t cIsocPkts; /* Number of Isoc packets */ + VUSBISOC_PKT_DESC aIsocPkts[8]; /* Array of Isoc packet descriptors */ +} VBOXUSBREQ_URB, *PVBOXUSBREQ_URB; + +typedef struct +{ + uint8_t bEndpoint; /* Endpoint address */ +} VBOXUSBREQ_CLEAR_EP, *PVBOXUSBREQ_CLEAR_EP; + + +typedef struct +{ + uint8_t bConfigValue; /* Configuration value */ +} VBOXUSBREQ_SET_CONFIG, *PVBOXUSBREQ_SET_CONFIG; +typedef VBOXUSBREQ_SET_CONFIG VBOXUSBREQ_GET_CONFIG; +typedef PVBOXUSBREQ_SET_CONFIG PVBOXUSBREQ_GET_CONFIG; + +typedef struct +{ + uint8_t bInterface; /* Interface number */ + uint8_t bAlternate; /* Alternate setting */ +} VBOXUSBREQ_SET_INTERFACE, *PVBOXUSBREQ_SET_INTERFACE; + +typedef enum +{ + /** Close device not a reset. */ + VBOXUSB_RESET_LEVEL_CLOSE = 0, + /** Hard reset resulting in device replug behaviour. */ + VBOXUSB_RESET_LEVEL_REATTACH = 2, + /** Device-level reset. */ + VBOXUSB_RESET_LEVEL_SOFT = 4 +} VBOXUSB_RESET_LEVEL; + +typedef struct +{ + VBOXUSB_RESET_LEVEL ResetLevel; /* Reset level after closing */ +} VBOXUSBREQ_CLOSE_DEVICE, *PVBOXUSBREQ_CLOSE_DEVICE; + +typedef struct +{ + uint8_t bEndpoint; /* Endpoint address */ +} VBOXUSBREQ_ABORT_PIPE, *PVBOXUSBREQ_ABORT_PIPE; + +typedef struct +{ + uint32_t u32Major; /* Driver major number */ + uint32_t u32Minor; /* Driver minor number */ +} VBOXUSBREQ_GET_VERSION, *PVBOXUSBREQ_GET_VERSION; + +#pragma pack() + +/** The VBOXUSBREQ::u32Magic value for VBoxUSBMon. */ +#define VBOXUSBMON_MAGIC 0xba5eba11 +/** The VBOXUSBREQ::u32Magic value for VBoxUSB.*/ +#define VBOXUSB_MAGIC 0x601fba11 +/** The USBLib entry point for userland. */ +#define VBOXUSB_DEVICE_NAME "/dev/vboxusbmon" + +/** The USBMonitor Major version. */ +#define VBOXUSBMON_VERSION_MAJOR 2 +/** The USBMonitor Minor version. */ +#define VBOXUSBMON_VERSION_MINOR 1 + +/** The USB Major version. */ +#define VBOXUSB_VERSION_MAJOR 1 +/** The USB Minor version. */ +#define VBOXUSB_VERSION_MINOR 1 + +#ifdef RT_ARCH_AMD64 +# define VBOXUSB_IOCTL_FLAG 128 +#elif defined(RT_ARCH_X86) +# define VBOXUSB_IOCTL_FLAG 0 +#else +# error "dunno which arch this is!" +#endif + +/** USB driver name*/ +#define VBOXUSB_DRIVER_NAME "vboxusb" + +/* No automatic buffering, size limited to 255 bytes => use VBOXUSBREQ for everything. */ +#define VBOXUSB_IOCTL_CODE(Function, Size) _IOWRN('V', (Function) | VBOXUSB_IOCTL_FLAG, sizeof(VBOXUSBREQ)) +#define VBOXUSB_IOCTL_CODE_FAST(Function) _IO( 'V', (Function) | VBOXUSB_IOCTL_FLAG) +#define VBOXUSB_IOCTL_STRIP_SIZE(Code) (Code) + +#define VBOXUSBMON_IOCTL_ADD_FILTER VBOXUSB_IOCTL_CODE(1, (sizeof(VBoxUSBAddFilterReq))) +#define VBOXUSBMON_IOCTL_REMOVE_FILTER VBOXUSB_IOCTL_CODE(2, (sizeof(VBoxUSBRemoveFilterReq))) +#define VBOXUSBMON_IOCTL_RESET_DEVICE VBOXUSB_IOCTL_CODE(3, (sizeof(VBOXUSBREQ_RESET_DEVICE))) +#define VBOXUSBMON_IOCTL_DEVICE_INSTANCE VBOXUSB_IOCTL_CODE(4, (sizeof(VBOXUSBREQ_DEVICE_INSTANCE))) +#define VBOXUSBMON_IOCTL_CLIENT_INFO VBOXUSB_IOCTL_CODE(5, (sizeof(VBOXUSBREQ_CLIENT_PATH))) +#define VBOXUSBMON_IOCTL_GET_VERSION VBOXUSB_IOCTL_CODE(6, (sizeof(VBOXUSBREQ_GET_VERSION))) + +/* VBoxUSB ioctls */ +#define VBOXUSB_IOCTL_SEND_URB VBOXUSB_IOCTL_CODE(20, (sizeof(VBOXUSBREQ_URB))) /* 1072146796 */ +#define VBOXUSB_IOCTL_REAP_URB VBOXUSB_IOCTL_CODE(21, (sizeof(VBOXUSBREQ_URB))) /* 1072146795 */ +#define VBOXUSB_IOCTL_CLEAR_EP VBOXUSB_IOCTL_CODE(22, (sizeof(VBOXUSBREQ_CLEAR_EP))) /* 1072146794 */ +#define VBOXUSB_IOCTL_SET_CONFIG VBOXUSB_IOCTL_CODE(23, (sizeof(VBOXUSBREQ_SET_CONFIG))) /* 1072146793 */ +#define VBOXUSB_IOCTL_SET_INTERFACE VBOXUSB_IOCTL_CODE(24, (sizeof(VBOXUSBREQ_SET_INTERFACE))) /* 1072146792 */ +#define VBOXUSB_IOCTL_CLOSE_DEVICE VBOXUSB_IOCTL_CODE(25, (sizeof(VBOXUSBREQ_CLOSE_DEVICE))) /* 1072146791 0xc0185699 */ +#define VBOXUSB_IOCTL_ABORT_PIPE VBOXUSB_IOCTL_CODE(26, (sizeof(VBOXUSBREQ_ABORT_PIPE))) /* 1072146790 */ +#define VBOXUSB_IOCTL_GET_CONFIG VBOXUSB_IOCTL_CODE(27, (sizeof(VBOXUSBREQ_GET_CONFIG))) /* 1072146789 */ +#define VBOXUSB_IOCTL_GET_VERSION VBOXUSB_IOCTL_CODE(28, (sizeof(VBOXUSBREQ_GET_VERSION))) /* 1072146788 */ + +/** @} */ + +/* USBLibHelper data for resetting the device. */ +typedef struct VBOXUSBHELPERDATA_RESET +{ + /** Path of the USB device. */ + const char *pszDevicePath; + /** Re-enumerate or not. */ + bool fHardReset; +} VBOXUSBHELPERDATA_RESET; +typedef VBOXUSBHELPERDATA_RESET *PVBOXUSBHELPERDATA_RESET; +typedef const VBOXUSBHELPERDATA_RESET *PCVBOXUSBHELPERDATA_RESET; + +/* USBLibHelper data for device hijacking. */ +typedef struct VBOXUSBHELPERDATA_ALIAS +{ + /** Vendor ID. */ + uint16_t idVendor; + /** Product ID. */ + uint16_t idProduct; + /** Revision, integer part. */ + uint16_t bcdDevice; + /** Path of the USB device. */ + const char *pszDevicePath; +} VBOXUSBHELPERDATA_ALIAS; +typedef VBOXUSBHELPERDATA_ALIAS *PVBOXUSBHELPERDATA_ALIAS; +typedef const VBOXUSBHELPERDATA_ALIAS *PCVBOXUSBHELPERDATA_ALIAS; + +USBLIB_DECL(int) USBLibResetDevice(char *pszDevicePath, bool fReattach); +USBLIB_DECL(int) USBLibDeviceInstance(char *pszDevicePath, int *pInstance); +USBLIB_DECL(int) USBLibGetClientInfo(char *pszDeviceIdent, char **ppszClientPath, int *pInstance); +USBLIB_DECL(int) USBLibAddDeviceAlias(PUSBDEVICE pDevice); +USBLIB_DECL(int) USBLibRemoveDeviceAlias(PUSBDEVICE pDevice); +/*USBLIB_DECL(int) USBLibConfigureDevice(PUSBDEVICE pDevice);*/ + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_usblib_solaris_h */ + diff --git a/include/VBox/usblib-win.h b/include/VBox/usblib-win.h new file mode 100644 index 00000000..24b26c6d --- /dev/null +++ b/include/VBox/usblib-win.h @@ -0,0 +1,309 @@ +/** @file + * USBLib - Library for wrapping up the VBoxUSB functionality, Windows flavor. + * (DEV,HDrv,Main) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_usblib_win_h +#define VBOX_INCLUDED_usblib_win_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <VBox/usb.h> + +#include <initguid.h> + + +/** @defgroup grp_usblib_win Windows USB Specifics + * @ingroup grp_usblib + * @{ + */ + +// {6068EB61-98E7-4c98-9E20-1F068295909A} +DEFINE_GUID(GUID_CLASS_VBOXUSB, 0x873fdf, 0xCAFE, 0x80EE, 0xaa, 0x5e, 0x0, 0xc0, 0x4f, 0xb1, 0x72, 0xb); + +#define USBFLT_SERVICE_NAME "\\\\.\\VBoxUSBFlt" +#define USBFLT_NTDEVICE_NAME_STRING L"\\Device\\VBoxUSBFlt" +#define USBFLT_SYMBOLIC_NAME_STRING L"\\DosDevices\\VBoxUSBFlt" + +#define USBMON_SERVICE_NAME_W L"VBoxUSBMon" +#define USBMON_DEVICE_NAME "\\\\.\\VBoxUSBMon" +#define USBMON_DEVICE_NAME_NT L"\\Device\\VBoxUSBMon" +#define USBMON_DEVICE_NAME_DOS L"\\DosDevices\\VBoxUSBMon" + +/* + * IOCtl numbers. + * We're using the Win32 type of numbers here, thus the macros below. + */ + +#ifndef CTL_CODE +# if defined(RT_OS_WINDOWS) +# define CTL_CODE(DeviceType, Function, Method, Access) \ + ( ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) +#else /* unix: */ +# define CTL_CODE(DeviceType, Function, Method_ignored, Access_ignored) \ + ( (3 << 30) | ((DeviceType) << 8) | (Function) | (sizeof(SUPDRVIOCTLDATA) << 16) ) +# endif +#endif +#ifndef METHOD_BUFFERED +# define METHOD_BUFFERED 0 +#endif +#ifndef FILE_WRITE_ACCESS +# define FILE_WRITE_ACCESS 0x0002 +#endif +#ifndef FILE_DEVICE_UNKNOWN +# define FILE_DEVICE_UNKNOWN 0x00000022 +#endif + +#define USBMON_MAJOR_VERSION 5 +#define USBMON_MINOR_VERSION 0 + +#define USBDRV_MAJOR_VERSION 5 +#define USBDRV_MINOR_VERSION 0 + +#define SUPUSB_IOCTL_TEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x601, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_GET_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x603, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_SEND_URB CTL_CODE(FILE_DEVICE_UNKNOWN, 0x607, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_USB_RESET CTL_CODE(FILE_DEVICE_UNKNOWN, 0x608, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_USB_SELECT_INTERFACE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x609, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_USB_SET_CONFIG CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60A, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_USB_CLAIM_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60B, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_USB_RELEASE_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60C, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_IS_OPERATIONAL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60D, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_USB_CLEAR_ENDPOINT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60E, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_GET_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60F, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_USB_ABORT_ENDPOINT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x610, METHOD_BUFFERED, FILE_WRITE_ACCESS) + +#define SUPUSBFLT_IOCTL_GET_NUM_DEVICES CTL_CODE(FILE_DEVICE_UNKNOWN, 0x602, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_USB_CHANGE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x604, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_DISABLE_CAPTURE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x605, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_ENABLE_CAPTURE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x606, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_IGNORE_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60F, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_GET_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x610, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_ADD_FILTER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x611, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_REMOVE_FILTER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x612, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_CAPTURE_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x613, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_RELEASE_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x614, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_RUN_FILTERS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x615, METHOD_BUFFERED, FILE_WRITE_ACCESS) +/* Used to be SUPUSBFLT_IOCTL_SET_NOTIFY_EVENT, 0x616 */ +#define SUPUSBFLT_IOCTL_GET_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x617, METHOD_BUFFERED, FILE_WRITE_ACCESS) + +#pragma pack(4) + +#define MAX_FILTER_NAME 128 +#define MAX_USB_SERIAL_STRING 64 + +/* a user-mode handle that could be used for retriving device information + * from the monitor driver */ +typedef void* HVBOXUSBDEVUSR; + +typedef struct +{ + HVBOXUSBDEVUSR hDevice; +} USBSUP_GETDEV, *PUSBSUP_GETDEV; + +typedef struct +{ + USBDEVICESTATE enmState; +} USBSUP_GETDEV_MON, *PUSBSUP_GETDEV_MON; + +typedef struct +{ + uint32_t u32Major; + uint32_t u32Minor; +} USBSUP_VERSION, *PUSBSUP_VERSION; + + +typedef struct USBSUP_FLTADDOUT +{ + uintptr_t uId; /* The ID. */ + int rc; /* The return code. */ +} USBSUP_FLTADDOUT, *PUSBSUP_FLTADDOUT; + +typedef struct +{ + uint16_t usVendorId; + uint16_t usProductId; + uint16_t usRevision; +} USBSUP_CAPTURE, *PUSBSUP_CAPTURE; + +typedef USBSUP_CAPTURE USBSUP_RELEASE; +typedef PUSBSUP_CAPTURE PUSBSUP_RELEASE; + +typedef struct +{ + uint8_t bInterfaceNumber; + uint8_t fClaimed; +} USBSUP_CLAIMDEV, *PUSBSUP_CLAIMDEV; + +typedef USBSUP_CLAIMDEV USBSUP_RELEASEDEV; +typedef PUSBSUP_CLAIMDEV PUSBSUP_RELEASEDEV; + +typedef struct +{ + uint32_t cUSBDevices; +} USBSUP_GETNUMDEV, *PUSBSUP_GETNUMDEV; + +typedef struct +{ + uint8_t fUSBChange; + uint32_t cUSBStateChange; +} USBSUP_USB_CHANGE, *PUSBSUP_USB_CHANGE; + +typedef struct +{ + uint8_t bConfigurationValue; +} USBSUP_SET_CONFIG, *PUSBSUP_SET_CONFIG; + +typedef struct +{ + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; +} USBSUP_SELECT_INTERFACE, *PUSBSUP_SELECT_INTERFACE; + +typedef struct +{ + uint8_t bEndpoint; +} USBSUP_CLEAR_ENDPOINT, *PUSBSUP_CLEAR_ENDPOINT; + +typedef enum +{ + USBSUP_TRANSFER_TYPE_CTRL = 0, + USBSUP_TRANSFER_TYPE_ISOC = 1, + USBSUP_TRANSFER_TYPE_BULK = 2, + USBSUP_TRANSFER_TYPE_INTR = 3, + USBSUP_TRANSFER_TYPE_MSG = 4 +} USBSUP_TRANSFER_TYPE; + +typedef enum +{ + USBSUP_DIRECTION_SETUP = 0, + USBSUP_DIRECTION_IN = 1, + USBSUP_DIRECTION_OUT = 2 +} USBSUP_DIRECTION; + +typedef enum +{ + USBSUP_FLAG_NONE = 0, + USBSUP_FLAG_SHORT_OK = 1 +} USBSUP_XFER_FLAG; + +typedef enum +{ + USBSUP_XFER_OK = 0, + USBSUP_XFER_STALL = 1, + USBSUP_XFER_DNR = 2, + USBSUP_XFER_CRC = 3, + USBSUP_XFER_NAC = 4, + USBSUP_XFER_UNDERRUN = 5, + USBSUP_XFER_OVERRUN = 6 +} USBSUP_ERROR; + +typedef struct USBSUP_ISOCPKT +{ + uint16_t cb; /* [in/out] packet size/size transferred */ + uint16_t off; /* [in] offset of packet in buffer */ + USBSUP_ERROR stat; /* [out] packet status */ +} USBSUP_ISOCPKT; + +typedef struct +{ + USBSUP_TRANSFER_TYPE type; /* [in] USBSUP_TRANSFER_TYPE_XXX */ + uint32_t ep; /* [in] index to dev->pipe */ + USBSUP_DIRECTION dir; /* [in] USBSUP_DIRECTION_XXX */ + USBSUP_XFER_FLAG flags; /* [in] USBSUP_FLAG_XXX */ + USBSUP_ERROR error; /* [out] USBSUP_XFER_XXX */ + size_t len; /* [in/out] may change */ + void *buf; /* [in/out] depends on dir */ + uint32_t numIsoPkts; /* [in] number of isochronous packets (8 max) */ + USBSUP_ISOCPKT aIsoPkts[8]; /* [in/out] isochronous packet descriptors */ +} USBSUP_URB, *PUSBSUP_URB; + +typedef struct +{ + union + { + /* in: event handle */ + void* hEvent; + /* out: result */ + int rc; + } u; +} USBSUP_SET_NOTIFY_EVENT, *PUSBSUP_SET_NOTIFY_EVENT; + +typedef struct +{ + uint16_t usVendorId; + uint16_t usProductId; + uint16_t usRevision; + uint16_t usAlignment; + char DrvKeyName[512]; +} USBSUP_DEVID, *PUSBSUP_DEVID; + +#pragma pack() /* paranoia */ + + +RT_C_DECLS_BEGIN + +#ifdef IN_RING3 + +/** @defgroup grp_usblib_r3 USBLIB Host Context Ring 3 API + * @{ + */ + +/** + * Return all attached USB devices. + * + * @returns VBox status code + * @param ppDevices Receives pointer to list of devices + * @param pcbNumDevices Number of USB devices in the list + */ +USBLIB_DECL(int) USBLibGetDevices(PUSBDEVICE *ppDevices, uint32_t *pcbNumDevices); + +USBLIB_DECL(int) USBLibWaitChange(RTMSINTERVAL cMillies); + +USBLIB_DECL(int) USBLibInterruptWaitChange(void); + +USBLIB_DECL(int) USBLibRunFilters(void); + +/** @} */ +#endif + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_usblib_win_h */ + diff --git a/include/VBox/usblib.h b/include/VBox/usblib.h new file mode 100644 index 00000000..13fc690e --- /dev/null +++ b/include/VBox/usblib.h @@ -0,0 +1,196 @@ +/** @file + * USBLib - Library for wrapping up the VBoxUSB functionality. (DEV,HDrv,Main) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_usblib_h +#define VBOX_INCLUDED_usblib_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <VBox/usb.h> +#include <VBox/usbfilter.h> +#include <iprt/ctype.h> +#include <iprt/string.h> + +#ifdef RT_OS_WINDOWS +# include <VBox/usblib-win.h> +#endif +#ifdef RT_OS_SOLARIS +# include <VBox/usblib-solaris.h> +#endif +#ifdef RT_OS_DARWIN +# include <VBox/usblib-darwin.h> +#endif +/** @todo merge the usblib-win.h interface into the darwin and linux ports where suitable. */ + +RT_C_DECLS_BEGIN +/** @defgroup grp_usblib USBLib - USB Support Library + * This module implements the basic low-level OS interfaces and common USB code. + * @{ + */ + +#ifdef IN_RING3 +/** + * Initializes the USBLib component. + * + * The USBLib keeps a per process connection to the kernel driver + * and all USBLib users within a process will share the same + * connection. USBLib does reference counting to make sure that + * the connection remains open until all users has called USBLibTerm(). + * + * @returns VBox status code. + * + * @remark The users within the process are responsible for not calling + * this function at the same time (because I'm lazy). + */ +USBLIB_DECL(int) USBLibInit(void); + +/** + * Terminates the USBLib component. + * + * Must match successful USBLibInit calls. + * + * @returns VBox status code. + */ +USBLIB_DECL(int) USBLibTerm(void); + +/** + * Adds a filter. + * + * This function will validate and transfer the specified filter + * to the kernel driver and make it start using it. The kernel + * driver will return a filter id that this function passes on + * to its caller. + * + * The kernel driver will associate the added filter with the + * calling process and automatically remove all filters when + * the process terminates the connection to it or dies. + * + * @returns Filter id for passing to USBLibRemoveFilter on success. + * @returns NULL on failure. + * + * @param pFilter The filter to add. + */ +USBLIB_DECL(void *) USBLibAddFilter(PCUSBFILTER pFilter); + +/** + * Removes a filter. + * + * @param pvId The ID returned by USBLibAddFilter. + */ +USBLIB_DECL(void) USBLibRemoveFilter(void *pvId); + +/** + * Calculate the hash of the serial string. + * + * 64bit FNV1a, chosen because it is designed to hash in to a power of two + * space, and is much quicker and simpler than, say, a half MD4. + * + * @returns the hash. + * @param pszSerial The serial string. + */ +USBLIB_DECL(uint64_t) USBLibHashSerial(const char *pszSerial); + +#endif /* IN_RING3 */ + +/** + * Purge string of non-UTF-8 encodings and control characters. + * + * Control characters creates problems when presented to the user and currently + * also when used in XML settings. So, we must purge them in the USB vendor, + * product, and serial number strings. + * + * @returns String length (excluding terminator). + * @param psz The string to purge. + * + * @remarks The return string may be shorter than the input, left over space + * after the end of the string will be filled with zeros. + */ +DECLINLINE(size_t) USBLibPurgeEncoding(char *psz) +{ + if (psz) + { + size_t offSrc; + + /* Beat it into valid UTF-8 encoding. */ + RTStrPurgeEncoding(psz); + + /* Look for control characters. */ + for (offSrc = 0; ; offSrc++) + { + char ch = psz[offSrc]; + if (RT_UNLIKELY(RT_C_IS_CNTRL(ch) && ch != '\0')) + { + /* Found a control character! Replace tab by space and remove all others. */ + size_t offDst = offSrc; + for (;; offSrc++) + { + ch = psz[offSrc]; + if (RT_C_IS_CNTRL(ch) && ch != '\0') + { + if (ch == '\t') + ch = ' '; + else + continue; + } + psz[offDst++] = ch; + if (ch == '\0') + break; + } + + /* Wind back to the zero terminator and zero fill any gap to make + USBFilterValidate happy. (offSrc is at zero terminator too.) */ + offDst--; + while (offSrc > offDst) + psz[offSrc--] = '\0'; + + return offDst; + } + if (ch == '\0') + break; + } + return offSrc; + } + return 0; +} + + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_usblib_h */ + diff --git a/include/VBox/various.sed b/include/VBox/various.sed new file mode 100644 index 00000000..8797b029 --- /dev/null +++ b/include/VBox/various.sed @@ -0,0 +1,148 @@ +# $Id: various.sed $ +## @file +# Converts some C header elements into nasm/yasm syntax. +# +# This is used by 'incs' in /Maintenance.kmk (/Makefile.kmk). +# + +# +# Copyright (C) 2006-2022 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# The contents of this file may alternatively be used under the terms +# of the Common Development and Distribution License Version 1.0 +# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +# in the VirtualBox 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. +# +# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +# + +# Pass thru the file header and copyright. +1,/^\#ifndef/{ +/^\#ifndef/b next +s/^[/ ]// +s/^\*\//;/ +s/\*/;/g +4s/^.*$/; Automatically generated by various.sed. DO NOT EDIT!/ +b end +} +:next + +# Check for markers (typically in comments). +/ASM-INC/basm-inc +/ASM-NOINC/basm-noinc + +# Newline escapes. +:check-newline-escape +/\\$/!bno-more-newline-escapes +N +b check-newline-escape +:no-more-newline-escapes + +# Strip comments and trailing space. +s/[[:space:]][[:space:]]*\/\*.*$//g +s/[[:space:]][[:space:]]*\/\/.*$//g +s/[[:space:]][[:space:]]*$//g + +# Try identify the statement. +/#[[:space:]]*define[[:space:]]/bdefine +/#[[:space:]]*ifdef[[:space:]]/bifdef +/#[[:space:]]*ifndef[[:space:]]/bifndef +/#[[:space:]]*if[[:space:]]/bif +/#[[:space:]]*elif[[:space:]]/belif +/#[[:space:]]*else$/belse +/#[[:space:]]*endif$/bendif + +# Not recognized, drop it. +:asm-noinc +d +b end + +# +# Defines needs some extra massaging to work in yasm. +# Things like trailing type indicators ('U', 'ULL' ++) does not go down well. +# +:define +/\$/d +s/#\([[:space:]]*\)define/\1%define/ + +s/\([[:space:]]0[xX][0-9a-fA-F][0-9a-fA-F]*\)U$/\1/ +s/\([[:space:]]0[xX][0-9a-fA-F][0-9a-fA-F]*\)U\([[:space:]]*\))$/\1\2)/ +s/\([[:space:]][0-9][0-9]*\)U[[:space:]]*$/\1/ +s/\([[:space:]][0-9][0-9]*\)U\([[:space:]]*\))$/\1\2)/ + +s/\([[:space:]]0[xX][0-9a-fA-F][0-9a-fA-F]*\)UL$/\1/ +s/\([[:space:]]0[xX][0-9a-fA-F][0-9a-fA-F]*\)UL\([[:space:]]*\))$/\1\2)/ +s/\([[:space:]][0-9][0-9]*\)UL[[:space:]]*$/\1/ +s/\([[:space:]][0-9][0-9]*\)UL\([[:space:]]*\))$/\1\2)/ + +s/\([[:space:]]0[xX][0-9a-fA-F][0-9a-fA-F]*\)ULL$/\1/ +s/\([[:space:]]0[xX][0-9a-fA-F][0-9a-fA-F]*\)ULL\([[:space:]]*\))$/\1\2)/ +s/\([[:space:]][0-9][0-9]*\)ULL[[:space:]]*$/\1/ +s/\([[:space:]][0-9][0-9]*\)ULL\([[:space:]]*\))$/\1\2)/ + +s/UINT64_C([[:space:]]*\(0[xX][0-9a-fA-F][0-9a-fA-F]*\)[[:space:]]*)/\1/ +s/UINT64_C([[:space:]]*\([0-9][0-9]*\)[[:space:]]*)/\1/ +s/UINT32_C([[:space:]]*\(0[xX][0-9a-fA-F][0-9a-fA-F]*\)[[:space:]]*)/\1/ +s/UINT32_C([[:space:]]*\([0-9][0-9]*\)[[:space:]]*)/\1/ +s/UINT16_C([[:space:]]*\(0[xX][0-9a-fA-F][0-9a-fA-F]*\)[[:space:]]*)/\1/ +s/UINT16_C([[:space:]]*\([0-9][0-9]*\)[[:space:]]*)/\1/ +s/UINT8_C([[:space:]]*\(0[xX][0-9a-fA-F][0-9a-fA-F]*\)[[:space:]]*)/\1/ +s/UINT8_C([[:space:]]*\([0-9][0-9]*\)[[:space:]]*)/\1/ + +b end + +# +# Conditional statements, 1:1. +# +:ifdef +s/#\([[:space:]]*\)ifdef/\1%ifdef/ +b end + +:ifndef +s/#\([[:space:]]*\)ifndef/\1%ifndef/ +b end + +:if +s/#\([[:space:]]*\)if/\1%if/ +b end + +:elif +s/#\([[:space:]]*\)elif/\1%elif/ +b end + +:else +s/#\([[:space:]]*\)else.*$/\1%else/ +b end + +:endif +s/#\([[:space:]]*\)endif.*$/\1%endif/ +b end + +# +# Assembly statement... may need adjusting when used. +# +:asm-inc +b end + +:end + diff --git a/include/VBox/vd-cache-backend.h b/include/VBox/vd-cache-backend.h new file mode 100644 index 00000000..c2d7163f --- /dev/null +++ b/include/VBox/vd-cache-backend.h @@ -0,0 +1,332 @@ +/** @file + * Internal hard disk format support API for VBoxHDD cache images. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vd_cache_backend_h +#define VBOX_INCLUDED_vd_cache_backend_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vd.h> +#include <VBox/vd-common.h> +#include <VBox/vd-ifs-internal.h> + +/** + * Cache format backend interface used by VBox HDD Container implementation. + */ +typedef struct VDCACHEBACKEND +{ + /** Structure version. VD_CACHEBACKEND_VERSION defines the current version. */ + uint32_t u32Version; + /** The name of the backend (constant string). */ + const char *pszBackendName; + /** The capabilities of the backend. */ + uint64_t uBackendCaps; + + /** + * Pointer to a NULL-terminated array of strings, containing the supported + * file extensions. Note that some backends do not work on files, so this + * pointer may just contain NULL. + */ + const char * const *papszFileExtensions; + + /** + * Pointer to an array of structs describing each supported config key. + * Terminated by a NULL config key. Note that some backends do not support + * the configuration interface, so this pointer may just contain NULL. + * Mandatory if the backend sets VD_CAP_CONFIG. + */ + PCVDCONFIGINFO paConfigInfo; + + /** + * Probes the given image. + * + * @returns VBox status code. + * @param pszFilename Name of the image file. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + */ + DECLR3CALLBACKMEMBER(int, pfnProbe, (const char *pszFilename, PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage)); + + /** + * Open a cache image. + * + * @returns VBox status code. + * @param pszFilename Name of the image file to open. Guaranteed to be available and + * unchanged during the lifetime of this image. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param ppBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(int, pfnOpen, (const char *pszFilename, unsigned uOpenFlags, + PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage, + void **ppBackendData)); + + /** + * Create a cache image. + * + * @returns VBox status code. + * @param pszFilename Name of the image file to create. Guaranteed to be available and + * unchanged during the lifetime of this image. + * @param cbSize Image size in bytes. + * @param uImageFlags Flags specifying special image features. + * @param pszComment Pointer to image comment. NULL is ok. + * @param pUuid New UUID of the image. Not NULL. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param uPercentStart Starting value for progress percentage. + * @param uPercentSpan Span for varying progress percentage. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + * @param ppBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(int, pfnCreate, (const char *pszFilename, uint64_t cbSize, + unsigned uImageFlags, const char *pszComment, + PCRTUUID pUuid, unsigned uOpenFlags, + unsigned uPercentStart, unsigned uPercentSpan, + PVDINTERFACE pVDIfsDisk, + PVDINTERFACE pVDIfsImage, + PVDINTERFACE pVDIfsOperation, + void **ppBackendData)); + + /** + * Close a cache image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param fDelete If true, delete the image from the host disk. + */ + DECLR3CALLBACKMEMBER(int, pfnClose, (void *pBackendData, bool fDelete)); + + /** + * Start a read request. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param uOffset The offset of the virtual disk to read from. + * @param cbToRead How many bytes to read. + * @param pIoCtx I/O context associated with this request. + * @param pcbActuallyRead Pointer to returned number of bytes read. + */ + DECLR3CALLBACKMEMBER(int, pfnRead, (void *pBackendData, uint64_t uOffset, size_t cbToRead, + PVDIOCTX pIoCtx, size_t *pcbActuallyRead)); + + /** + * Start a write request. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param uOffset The offset of the virtual disk to write to. + * @param cbToWrite How many bytes to write. + * @param pIoCtx I/O context associated with this request. + * @param pcbWriteProcess Pointer to returned number of bytes that could + * be processed. In case the function returned + * VERR_VD_BLOCK_FREE this is the number of bytes + * that could be written in a full block write, + * when prefixed/postfixed by the appropriate + * amount of (previously read) padding data. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite, (void *pBackendData, uint64_t uOffset, size_t cbToWrite, + PVDIOCTX pIoCtx, size_t *pcbWriteProcess)); + + /** + * Flush data to disk. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pIoCtx I/O context associated with this request. + */ + DECLR3CALLBACKMEMBER(int, pfnFlush, (void *pBackendData, PVDIOCTX pIoCtx)); + + /** + * Discards the given amount of bytes from the cache. + * + * @returns VBox status code. + * @retval VERR_VD_DISCARD_ALIGNMENT_NOT_MET if the range doesn't meet the required alignment + * for the discard. + * @param pBackendData Opaque state data for this image. + * @param pIoCtx I/O context associated with this request. + * @param uOffset The offset of the first byte to discard. + * @param cbDiscard How many bytes to discard. + */ + DECLR3CALLBACKMEMBER(int, pfnDiscard, (void *pBackendData, PVDIOCTX pIoCtx, + uint64_t uOffset, size_t cbDiscard, + size_t *pcbPreAllocated, + size_t *pcbPostAllocated, + size_t *pcbActuallyDiscarded, + void **ppbmAllocationBitmap, + unsigned fDiscard)); + + /** + * Get the version of a cache image. + * + * @returns version of cache image. + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(unsigned, pfnGetVersion, (void *pBackendData)); + + /** + * Get the capacity of a cache image. + * + * @returns size of cache image in bytes. + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnGetSize, (void *pBackendData)); + + /** + * Get the file size of a cache image. + * + * @returns size of cache image in bytes. + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnGetFileSize, (void *pBackendData)); + + /** + * Get the image flags of a cache image. + * + * @returns image flags of cache image. + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(unsigned, pfnGetImageFlags, (void *pBackendData)); + + /** + * Get the open flags of a cache image. + * + * @returns open flags of cache image. + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(unsigned, pfnGetOpenFlags, (void *pBackendData)); + + /** + * Set the open flags of a cache image. May cause the image to be locked + * in a different mode or be reopened (which can fail). + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param uOpenFlags New open flags for this image. + */ + DECLR3CALLBACKMEMBER(int, pfnSetOpenFlags, (void *pBackendData, unsigned uOpenFlags)); + + /** + * Get comment of a cache image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pszComment Where to store the comment. + * @param cbComment Size of the comment buffer. + */ + DECLR3CALLBACKMEMBER(int, pfnGetComment, (void *pBackendData, char *pszComment, size_t cbComment)); + + /** + * Set comment of a cache image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pszComment Where to get the comment from. NULL resets comment. + * The comment is silently truncated if the image format + * limit is exceeded. + */ + DECLR3CALLBACKMEMBER(int, pfnSetComment, (void *pBackendData, const char *pszComment)); + + /** + * Get UUID of a cache image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to store the image UUID. + */ + DECLR3CALLBACKMEMBER(int, pfnGetUuid, (void *pBackendData, PRTUUID pUuid)); + + /** + * Set UUID of a cache image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to get the image UUID from. + */ + DECLR3CALLBACKMEMBER(int, pfnSetUuid, (void *pBackendData, PCRTUUID pUuid)); + + /** + * Get last modification UUID of a cache image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to store the image modification UUID. + */ + DECLR3CALLBACKMEMBER(int, pfnGetModificationUuid, (void *pBackendData, PRTUUID pUuid)); + + /** + * Set last modification UUID of a cache image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to get the image modification UUID from. + */ + DECLR3CALLBACKMEMBER(int, pfnSetModificationUuid, (void *pBackendData, PCRTUUID pUuid)); + + /** + * Dump information about a cache image. + * + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(void, pfnDump, (void *pBackendData)); + + /** Returns a human readable hard disk location string given a + * set of hard disk configuration keys. The returned string is an + * equivalent of the full file path for image-based hard disks. + * Mandatory for backends with no VD_CAP_FILE and NULL otherwise. */ + DECLR3CALLBACKMEMBER(int, pfnComposeLocation, (PVDINTERFACE pConfig, char **pszLocation)); + + /** Returns a human readable hard disk name string given a + * set of hard disk configuration keys. The returned string is an + * equivalent of the file name part in the full file path for + * image-based hard disks. Mandatory for backends with no + * VD_CAP_FILE and NULL otherwise. */ + DECLR3CALLBACKMEMBER(int, pfnComposeName, (PVDINTERFACE pConfig, char **pszName)); + + /** Initialization safty marker. */ + uint32_t u32VersionEnd; + +} VDCACHEBACKEND; +/** Pointer to VD cache backend. */ +typedef VDCACHEBACKEND *PVDCACHEBACKEND; +/** Constant pointer to VD backend. */ +typedef const VDCACHEBACKEND *PCVDCACHEBACKEND; + +/** The current version of the VDCACHEBACKEND structure. */ +#define VD_CACHEBACKEND_VERSION VD_VERSION_MAKE(0xff03, 1, 0) + +#endif /* !VBOX_INCLUDED_vd_cache_backend_h */ diff --git a/include/VBox/vd-common.h b/include/VBox/vd-common.h new file mode 100644 index 00000000..6c65e13a --- /dev/null +++ b/include/VBox/vd-common.h @@ -0,0 +1,76 @@ +/** @file + * VD: common definitions for the registration, backend and interface structures. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vd_common_h +#define VBOX_INCLUDED_vd_common_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + +/** Makes a VD structure version out of an unique magic value and major & + * minor version numbers. + * + * @returns 32-bit structure version number. + * + * @param uMagic 16-bit magic value. This must be unique. + * @param uMajor 12-bit major version number. Structures with different + * major numbers are not compatible. + * @param uMinor 4-bit minor version number. When only the minor version + * differs, the structures will be 100% backwards + * compatible. + */ +#define VD_VERSION_MAKE(uMagic, uMajor, uMinor) \ + ( ((uint32_t)(uMagic) << 16) | ((uint32_t)((uMajor) & 0xff) << 4) | ((uint32_t)((uMinor) & 0xf) << 0) ) + +/** Checks if @a uVerMagic1 is compatible with @a uVerMagic2. + * + * @returns true / false. + * @param uVerMagic1 Typically the runtime version of the struct. This must + * have the same magic and major version as @a uVerMagic2 + * and the minor version must be greater or equal to that + * of @a uVerMagic2. + * @param uVerMagic2 Typically the version the code was compiled against. + * + * @remarks The parameters will be referenced more than once. + */ +#define VD_VERSION_ARE_COMPATIBLE(uVerMagic1, uVerMagic2) \ + ( (uVerMagic1) == (uVerMagic2) \ + || ( (uVerMagic1) >= (uVerMagic2) \ + && ((uVerMagic1) & UINT32_C(0xfffffff0)) == ((uVerMagic2) & UINT32_C(0xfffffff0)) ) \ + ) + +#endif /* !VBOX_INCLUDED_vd_common_h */ diff --git a/include/VBox/vd-filter-backend.h b/include/VBox/vd-filter-backend.h new file mode 100644 index 00000000..ab45253f --- /dev/null +++ b/include/VBox/vd-filter-backend.h @@ -0,0 +1,122 @@ +/** @file + * Internal VD filter backend interface. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vd_filter_backend_h +#define VBOX_INCLUDED_vd_filter_backend_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vd.h> +#include <VBox/vd-common.h> +#include <VBox/vd-ifs-internal.h> + +/** + * VD filter backend interface. + */ +typedef struct VDFILTERBACKEND +{ + /** Structure version. VD_FLTBACKEND_VERSION defines the current version. */ + uint32_t u32Version; + /** The name of the backend (constant string). */ + const char *pszBackendName; + + /** + * Pointer to an array of structs describing each supported config key. + * Terminated by a NULL config key. Note that some backends do not support + * the configuration interface, so this pointer may just contain NULL. + * Mandatory if the backend sets VD_CAP_CONFIG. + */ + PCVDCONFIGINFO paConfigInfo; + + /** + * Creates a new filter instance. + * + * @returns VBox status code. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param fFlags Subset of VD_FILTER_FLAGS_*. + * @param pVDIfsFilter Pointer to the per-filter VD interface list. + * @param ppvBackendData Opaque state data for this filter instance. + */ + DECLR3CALLBACKMEMBER(int, pfnCreate, (PVDINTERFACE pVDIfsDisk, uint32_t fFlags, + PVDINTERFACE pVDIfsFilter, + void **ppvBackendData)); + + /** + * Destroys a filter instance. + * + * @returns VBox status code. + * @param pvBackendData Opaque state data for the filter instance to destroy. + */ + DECLR3CALLBACKMEMBER(int, pfnDestroy, (void *pvBackendData)); + + /** + * Filters the data of a read from the image chain. The filter is applied + * after everything was read. + * + * @returns VBox status code. + * @param pvBackendData Opaque state data for the filter instance. + * @param uOffset Start offset of the read. + * @param cbRead Number of bytes read. + * @param pIoCtx The I/O context holding the read data. + */ + DECLR3CALLBACKMEMBER(int, pfnFilterRead, (void *pvBackendData, uint64_t uOffset, size_t cbRead, + PVDIOCTX pIoCtx)); + + /** + * Filters the data of a write to the image chain. The filter is applied + * before everything is written. + * + * @returns VBox status code. + * @param pvBackendData Opaque state data for the filter instance. + * @param uOffset Start offset of the write. + * @param cbWrite Number of bytes to be written. + * @param pIoCtx The I/O context holding the data to write. + */ + DECLR3CALLBACKMEMBER(int, pfnFilterWrite, (void *pvBackendData, uint64_t uOffset, size_t cbWrite, + PVDIOCTX pIoCtx)); + + /** Initialization safty marker. */ + uint32_t u32VersionEnd; +} VDFILTERBACKEND; +/** Pointer to VD filter backend. */ +typedef VDFILTERBACKEND *PVDFILTERBACKEND; +/** Constant pointer to a VD filter backend. */ +typedef const VDFILTERBACKEND *PCVDFILTERBACKEND; + +/** The current version of the VDFILTERBACKEND structure. */ +#define VD_FLTBACKEND_VERSION VD_VERSION_MAKE(0xff02, 1, 0) + +#endif /* !VBOX_INCLUDED_vd_filter_backend_h */ diff --git a/include/VBox/vd-ifs-internal.h b/include/VBox/vd-ifs-internal.h new file mode 100644 index 00000000..7bff7642 --- /dev/null +++ b/include/VBox/vd-ifs-internal.h @@ -0,0 +1,710 @@ +/** @file + * VD Container API - internal interfaces. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vd_ifs_internal_h +#define VBOX_INCLUDED_vd_ifs_internal_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/sg.h> +#include <VBox/vd-ifs.h> + +RT_C_DECLS_BEGIN + +/** @addtogroup grp_vd + * @internal + * @{ */ + +/** + * Read data callback. + * + * @return VBox status code. + * @return VERR_VD_NOT_OPENED if no image is opened in HDD container. + * @param pvUser The opaque data passed for the operation. + * @param uOffset Offset of first reading byte from start of disk. + * Must be aligned to a sector boundary. + * @param pvBuffer Pointer to buffer for reading data. + * @param cbBuffer Number of bytes to read. + * Must be aligned to a sector boundary. + */ +typedef DECLCALLBACKTYPE(int, FNVDPARENTREAD,(void *pvUser, uint64_t uOffset, void *pvBuffer, size_t cbBuffer)); +/** Pointer to a FNVDPARENTREAD. */ +typedef FNVDPARENTREAD *PFNVDPARENTREAD; + +/** + * Interface to get the parent state. + * + * Per-operation interface. Optional, present only if there is a parent, and + * used only internally for compacting. + */ +typedef struct VDINTERFACEPARENTSTATE +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Read data callback, see FNVDPARENTREAD for details. + */ + PFNVDPARENTREAD pfnParentRead; + +} VDINTERFACEPARENTSTATE, *PVDINTERFACEPARENTSTATE; + + +/** + * Get parent state interface from interface list. + * + * @return Pointer to the first parent state interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACEPARENTSTATE) VDIfParentStateGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_PARENTSTATE); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_PARENTSTATE) + && (pIf->cbSize == sizeof(VDINTERFACEPARENTSTATE))), + ("Not a parent state interface"), NULL); + + return (PVDINTERFACEPARENTSTATE)pIf; +} + +/** Forward declaration. Only visible in the VBoxHDD module. */ +/** I/O context */ +typedef struct VDIOCTX *PVDIOCTX; +/** Storage backend handle. */ +typedef struct VDIOSTORAGE *PVDIOSTORAGE; +/** Pointer to a storage backend handle. */ +typedef PVDIOSTORAGE *PPVDIOSTORAGE; + +/** + * Completion callback for meta/userdata reads or writes. + * + * @return VBox status code. + * VINF_SUCCESS if everything was successful and the transfer can continue. + * VERR_VD_ASYNC_IO_IN_PROGRESS if there is another data transfer pending. + * @param pBackendData The opaque backend data. + * @param pIoCtx I/O context associated with this request. + * @param pvUser Opaque user data passed during a read/write request. + * @param rcReq Status code for the completed request. + */ +typedef DECLCALLBACKTYPE(int, FNVDXFERCOMPLETED,(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)); +/** Pointer to FNVDXFERCOMPLETED() */ +typedef FNVDXFERCOMPLETED *PFNVDXFERCOMPLETED; + +/** Metadata transfer handle. */ +typedef struct VDMETAXFER *PVDMETAXFER; +/** Pointer to a metadata transfer handle. */ +typedef PVDMETAXFER *PPVDMETAXFER; + + +/** + * Internal I/O interface between the generic VD layer and the backends. + * + * Per-image. Always passed to backends. + */ +typedef struct VDINTERFACEIOINT +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Open callback + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pszLocation Name of the location to open. + * @param fOpen Flags for opening the backend. + * See RTFILE_O_* \#defines, inventing another set + * of open flags is not worth the mapping effort. + * @param ppStorage Where to store the storage handle. + */ + DECLR3CALLBACKMEMBER(int, pfnOpen, (void *pvUser, const char *pszLocation, + uint32_t fOpen, PPVDIOSTORAGE ppStorage)); + + /** + * Close callback. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pStorage The storage handle to close. + */ + DECLR3CALLBACKMEMBER(int, pfnClose, (void *pvUser, PVDIOSTORAGE pStorage)); + + /** + * Delete callback. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pcszFilename Name of the file to delete. + */ + DECLR3CALLBACKMEMBER(int, pfnDelete, (void *pvUser, const char *pcszFilename)); + + /** + * Move callback. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pcszSrc The path to the source file. + * @param pcszDst The path to the destination file. + * This file will be created. + * @param fMove A combination of the RTFILEMOVE_* flags. + */ + DECLR3CALLBACKMEMBER(int, pfnMove, (void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)); + + /** + * Returns the free space on a disk. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pcszFilename Name of a file to identify the disk. + * @param pcbFreeSpace Where to store the free space of the disk. + */ + DECLR3CALLBACKMEMBER(int, pfnGetFreeSpace, (void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)); + + /** + * Returns the last modification timestamp of a file. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pcszFilename Name of a file to identify the disk. + * @param pModificationTime Where to store the timestamp of the file. + */ + DECLR3CALLBACKMEMBER(int, pfnGetModificationTime, (void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)); + + /** + * Returns the size of the opened storage backend. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pStorage The storage handle to get the size from. + * @param pcbSize Where to store the size of the storage backend. + */ + DECLR3CALLBACKMEMBER(int, pfnGetSize, (void *pvUser, PVDIOSTORAGE pStorage, + uint64_t *pcbSize)); + + /** + * Sets the size of the opened storage backend if possible. + * + * @return VBox status code. + * @retval VERR_NOT_SUPPORTED if the backend does not support this operation. + * @param pvUser The opaque data passed on container creation. + * @param pStorage The storage handle. + * @param cbSize The new size of the image. + * + * @note Depending on the host the underlying storage (backing file, etc.) + * might not have all required storage allocated (sparse file) which + * can delay writes or fail with a not enough free space error if there + * is not enough space on the storage medium when writing to the range for + * the first time. + * Use VDINTERFACEIOINT::pfnSetAllocationSize to make sure the storage is + * really alloacted. + */ + DECLR3CALLBACKMEMBER(int, pfnSetSize, (void *pvUser, PVDIOSTORAGE pStorage, + uint64_t cbSize)); + + /** + * Sets the size of the opened storage backend making sure the given size + * is really allocated. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pStorage The storage handle. + * @param cbSize The new size of the image. + * @param fFlags Flags for controlling the allocation strategy. + * Reserved for future use, MBZ. + * @param pIfProgress Progress interface (optional). + * @param uPercentStart Progress starting point. + * @param uPercentSpan Length of operation in percent. + */ + DECLR3CALLBACKMEMBER(int, pfnSetAllocationSize, (void *pvUser, PVDIOSTORAGE pStorage, + uint64_t cbSize, uint32_t fFlags, + PVDINTERFACEPROGRESS pIfProgress, + unsigned uPercentStart, unsigned uPercentSpan)); + + /** + * Initiate a read request for user data. + * + * @return VBox status code. + * @param pvUser The opaque user data passed on container creation. + * @param pStorage The storage handle. + * @param uOffset The offset to start reading from. + * @param pIoCtx I/O context passed in the read/write callback. + * @param cbRead How many bytes to read. + */ + DECLR3CALLBACKMEMBER(int, pfnReadUser, (void *pvUser, PVDIOSTORAGE pStorage, + uint64_t uOffset, PVDIOCTX pIoCtx, + size_t cbRead)); + + /** + * Initiate a write request for user data. + * + * @return VBox status code. + * @param pvUser The opaque user data passed on container creation. + * @param pStorage The storage handle. + * @param uOffset The offset to start writing to. + * @param pIoCtx I/O context passed in the read/write callback. + * @param cbWrite How many bytes to write. + * @param pfnCompleted Completion callback. + * @param pvCompleteUser Opaque user data passed in the completion callback. + */ + DECLR3CALLBACKMEMBER(int, pfnWriteUser, (void *pvUser, PVDIOSTORAGE pStorage, + uint64_t uOffset, PVDIOCTX pIoCtx, + size_t cbWrite, + PFNVDXFERCOMPLETED pfnComplete, + void *pvCompleteUser)); + + /** + * Reads metadata from storage. + * The current I/O context will be halted. + * + * @returns VBox status code. + * @param pvUser The opaque user data passed on container creation. + * @param pStorage The storage handle. + * @param uOffset Offset to start reading from. + * @param pvBuffer Where to store the data. + * @param cbBuffer How many bytes to read. + * @param pIoCtx The I/O context which triggered the read. + * @param ppMetaXfer Where to store the metadata transfer handle on success. + * @param pfnCompleted Completion callback. + * @param pvCompleteUser Opaque user data passed in the completion callback. + * + * @note If pIoCtx is NULL the metadata read is handled synchronously + * i.e. the call returns only if the data is available in the given + * buffer. ppMetaXfer, pfnCompleted and pvCompleteUser are ignored in that case. + * Use the synchronous version only when opening/closing the image + * or when doing certain operations like resizing, compacting or repairing + * the disk. + */ + DECLR3CALLBACKMEMBER(int, pfnReadMeta, (void *pvUser, PVDIOSTORAGE pStorage, + uint64_t uOffset, void *pvBuffer, + size_t cbBuffer, PVDIOCTX pIoCtx, + PPVDMETAXFER ppMetaXfer, + PFNVDXFERCOMPLETED pfnComplete, + void *pvCompleteUser)); + + /** + * Writes metadata to storage. + * + * @returns VBox status code. + * @param pvUser The opaque user data passed on container creation. + * @param pStorage The storage handle. + * @param uOffset Offset to start writing to. + * @param pvBuffer Written data. + * @param cbBuffer How many bytes to write. + * @param pIoCtx The I/O context which triggered the write. + * @param pfnCompleted Completion callback. + * @param pvCompleteUser Opaque user data passed in the completion callback. + * + * @sa VDINTERFACEIOINT::pfnReadMeta + */ + DECLR3CALLBACKMEMBER(int, pfnWriteMeta, (void *pvUser, PVDIOSTORAGE pStorage, + uint64_t uOffset, const void *pvBuffer, + size_t cbBuffer, PVDIOCTX pIoCtx, + PFNVDXFERCOMPLETED pfnComplete, + void *pvCompleteUser)); + + /** + * Releases a metadata transfer handle. + * The free space can be used for another transfer. + * + * @returns nothing. + * @param pvUser The opaque user data passed on container creation. + * @param pMetaXfer The metadata transfer handle to release. + */ + DECLR3CALLBACKMEMBER(void, pfnMetaXferRelease, (void *pvUser, PVDMETAXFER pMetaXfer)); + + /** + * Initiates a flush request. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pStorage The storage handle to flush. + * @param pIoCtx I/O context which triggered the flush. + * @param pfnCompleted Completion callback. + * @param pvCompleteUser Opaque user data passed in the completion callback. + * + * @sa VDINTERFACEIOINT::pfnReadMeta + */ + DECLR3CALLBACKMEMBER(int, pfnFlush, (void *pvUser, PVDIOSTORAGE pStorage, + PVDIOCTX pIoCtx, + PFNVDXFERCOMPLETED pfnComplete, + void *pvCompleteUser)); + + /** + * Copies a buffer into the I/O context. + * + * @return Number of bytes copied. + * @param pvUser The opaque user data passed on container creation. + * @param pIoCtx I/O context to copy the data to. + * @param pvBuffer Buffer to copy. + * @param cbBuffer Number of bytes to copy. + */ + DECLR3CALLBACKMEMBER(size_t, pfnIoCtxCopyTo, (void *pvUser, PVDIOCTX pIoCtx, + const void *pvBuffer, size_t cbBuffer)); + + /** + * Copies data from the I/O context into a buffer. + * + * @return Number of bytes copied. + * @param pvUser The opaque user data passed on container creation. + * @param pIoCtx I/O context to copy the data from. + * @param pvBuffer Destination buffer. + * @param cbBuffer Number of bytes to copy. + */ + DECLR3CALLBACKMEMBER(size_t, pfnIoCtxCopyFrom, (void *pvUser, PVDIOCTX pIoCtx, + void *pvBuffer, size_t cbBuffer)); + + /** + * Sets the buffer of the given context to a specific byte. + * + * @return Number of bytes set. + * @param pvUser The opaque user data passed on container creation. + * @param pIoCtx I/O context to copy the data from. + * @param ch The byte to set. + * @param cbSet Number of bytes to set. + */ + DECLR3CALLBACKMEMBER(size_t, pfnIoCtxSet, (void *pvUser, PVDIOCTX pIoCtx, + int ch, size_t cbSet)); + + /** + * Creates a segment array from the I/O context data buffer. + * + * @returns Number of bytes the array describes. + * @param pvUser The opaque user data passed on container creation. + * @param pIoCtx I/O context to copy the data from. + * @param paSeg The uninitialized segment array. + * If NULL pcSeg will contain the number of segments needed + * to describe the requested amount of data. + * @param pcSeg The number of segments the given array has. + * This will hold the actual number of entries needed upon return. + * @param cbData Number of bytes the new array should describe. + */ + DECLR3CALLBACKMEMBER(size_t, pfnIoCtxSegArrayCreate, (void *pvUser, PVDIOCTX pIoCtx, + PRTSGSEG paSeg, unsigned *pcSeg, + size_t cbData)); + /** + * Marks the given number of bytes as completed and continues the I/O context. + * + * @returns nothing. + * @param pvUser The opaque user data passed on container creation. + * @param pIoCtx The I/O context. + * @param rcReq Status code the request completed with. + * @param cbCompleted Number of bytes completed. + */ + DECLR3CALLBACKMEMBER(void, pfnIoCtxCompleted, (void *pvUser, PVDIOCTX pIoCtx, + int rcReq, size_t cbCompleted)); + + /** + * Returns whether the given I/O context must be treated synchronously. + * + * @returns true if the I/O context must be processed synchronously + * false otherwise. + * @param pvUser The opaque user data passed on container creation. + * @param pIoCtx The I/O context. + */ + DECLR3CALLBACKMEMBER(bool, pfnIoCtxIsSynchronous, (void *pvUser, PVDIOCTX pIoCtx)); + + /** + * Returns whether the user buffer of the I/O context is complete zero + * from to current position upto the given number of bytes. + * + * @returns true if the I/O context user buffer consists solely of zeros + * false otherwise. + * @param pvUser The opaque user data passed on container creation. + * @param pIoCtx The I/O context. + * @param cbCheck Number of bytes to check for zeros. + * @param fAdvance Flag whether to advance the buffer pointer if true + * is returned. + */ + DECLR3CALLBACKMEMBER(bool, pfnIoCtxIsZero, (void *pvUser, PVDIOCTX pIoCtx, + size_t cbCheck, bool fAdvance)); + + /** + * Returns the data unit size, i.e. the smallest size for a transfer. + * (similar to the sector size of disks). + * + * @returns The data unit size. + * @param pvUser The opaque user data passed on container creation. + * @param pIoCtx The I/O context. + */ + DECLR3CALLBACKMEMBER(size_t, pfnIoCtxGetDataUnitSize, (void *pvUser, PVDIOCTX pIoCtx)); + +} VDINTERFACEIOINT, *PVDINTERFACEIOINT; + +/** + * Get internal I/O interface from interface list. + * + * @return Pointer to the first internal I/O interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACEIOINT) VDIfIoIntGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_IOINT); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_IOINT) + && (pIf->cbSize == sizeof(VDINTERFACEIOINT))), + ("Not an internal I/O interface"), NULL); + + return (PVDINTERFACEIOINT)pIf; +} + +DECLINLINE(int) vdIfIoIntFileOpen(PVDINTERFACEIOINT pIfIoInt, const char *pszFilename, + uint32_t fOpen, PPVDIOSTORAGE ppStorage) +{ + return pIfIoInt->pfnOpen(pIfIoInt->Core.pvUser, pszFilename, fOpen, ppStorage); +} + +DECLINLINE(int) vdIfIoIntFileClose(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage) +{ + return pIfIoInt->pfnClose(pIfIoInt->Core.pvUser, pStorage); +} + +DECLINLINE(int) vdIfIoIntFileDelete(PVDINTERFACEIOINT pIfIoInt, const char *pszFilename) +{ + return pIfIoInt->pfnDelete(pIfIoInt->Core.pvUser, pszFilename); +} + +DECLINLINE(int) vdIfIoIntFileMove(PVDINTERFACEIOINT pIfIoInt, const char *pszSrc, + const char *pszDst, unsigned fMove) +{ + return pIfIoInt->pfnMove(pIfIoInt->Core.pvUser, pszSrc, pszDst, fMove); +} + +DECLINLINE(int) vdIfIoIntFileGetFreeSpace(PVDINTERFACEIOINT pIfIoInt, const char *pszFilename, + int64_t *pcbFree) +{ + return pIfIoInt->pfnGetFreeSpace(pIfIoInt->Core.pvUser, pszFilename, pcbFree); +} + +DECLINLINE(int) vdIfIoIntFileGetModificationTime(PVDINTERFACEIOINT pIfIoInt, const char *pcszFilename, + PRTTIMESPEC pModificationTime) +{ + return pIfIoInt->pfnGetModificationTime(pIfIoInt->Core.pvUser, pcszFilename, + pModificationTime); +} + +DECLINLINE(int) vdIfIoIntFileGetSize(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t *pcbSize) +{ + return pIfIoInt->pfnGetSize(pIfIoInt->Core.pvUser, pStorage, pcbSize); +} + +DECLINLINE(int) vdIfIoIntFileSetSize(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t cbSize) +{ + return pIfIoInt->pfnSetSize(pIfIoInt->Core.pvUser, pStorage, cbSize); +} + +DECLINLINE(int) vdIfIoIntFileSetAllocationSize(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t cbSize, uint32_t fFlags, + PVDINTERFACEPROGRESS pIfProgress, + unsigned uPercentStart, unsigned uPercentSpan) +{ + return pIfIoInt->pfnSetAllocationSize(pIfIoInt->Core.pvUser, pStorage, cbSize, fFlags, + pIfProgress, uPercentStart, uPercentSpan); +} + +DECLINLINE(int) vdIfIoIntFileWriteSync(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t uOffset, const void *pvBuffer, size_t cbBuffer) +{ + return pIfIoInt->pfnWriteMeta(pIfIoInt->Core.pvUser, pStorage, + uOffset, pvBuffer, cbBuffer, NULL, + NULL, NULL); +} + +DECLINLINE(int) vdIfIoIntFileReadSync(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t uOffset, void *pvBuffer, size_t cbBuffer) +{ + return pIfIoInt->pfnReadMeta(pIfIoInt->Core.pvUser, pStorage, + uOffset, pvBuffer, cbBuffer, NULL, + NULL, NULL, NULL); +} + +DECLINLINE(int) vdIfIoIntFileFlushSync(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage) +{ + return pIfIoInt->pfnFlush(pIfIoInt->Core.pvUser, pStorage, NULL, NULL, NULL); +} + +DECLINLINE(int) vdIfIoIntFileReadUser(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t uOffset, PVDIOCTX pIoCtx, size_t cbRead) +{ + return pIfIoInt->pfnReadUser(pIfIoInt->Core.pvUser, pStorage, + uOffset, pIoCtx, cbRead); +} + +DECLINLINE(int) vdIfIoIntFileWriteUser(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t uOffset, PVDIOCTX pIoCtx, size_t cbWrite, + PFNVDXFERCOMPLETED pfnComplete, + void *pvCompleteUser) +{ + return pIfIoInt->pfnWriteUser(pIfIoInt->Core.pvUser, pStorage, + uOffset, pIoCtx, cbWrite, pfnComplete, + pvCompleteUser); +} + +DECLINLINE(int) vdIfIoIntFileReadMeta(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t uOffset, void *pvBuffer, + size_t cbBuffer, PVDIOCTX pIoCtx, + PPVDMETAXFER ppMetaXfer, + PFNVDXFERCOMPLETED pfnComplete, + void *pvCompleteUser) +{ + return pIfIoInt->pfnReadMeta(pIfIoInt->Core.pvUser, pStorage, + uOffset, pvBuffer, cbBuffer, pIoCtx, + ppMetaXfer, pfnComplete, pvCompleteUser); +} + +DECLINLINE(int) vdIfIoIntFileWriteMeta(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t uOffset, void *pvBuffer, + size_t cbBuffer, PVDIOCTX pIoCtx, + PFNVDXFERCOMPLETED pfnComplete, + void *pvCompleteUser) +{ + return pIfIoInt->pfnWriteMeta(pIfIoInt->Core.pvUser, pStorage, + uOffset, pvBuffer, cbBuffer, pIoCtx, + pfnComplete, pvCompleteUser); +} + +DECLINLINE(void) vdIfIoIntMetaXferRelease(PVDINTERFACEIOINT pIfIoInt, PVDMETAXFER pMetaXfer) +{ + pIfIoInt->pfnMetaXferRelease(pIfIoInt->Core.pvUser, pMetaXfer); +} + +DECLINLINE(int) vdIfIoIntFileFlush(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + PVDIOCTX pIoCtx, PFNVDXFERCOMPLETED pfnComplete, + void *pvCompleteUser) +{ + return pIfIoInt->pfnFlush(pIfIoInt->Core.pvUser, pStorage, pIoCtx, pfnComplete, + pvCompleteUser); +} + +DECLINLINE(size_t) vdIfIoIntIoCtxCopyTo(PVDINTERFACEIOINT pIfIoInt, PVDIOCTX pIoCtx, + const void *pvBuffer, size_t cbBuffer) +{ + return pIfIoInt->pfnIoCtxCopyTo(pIfIoInt->Core.pvUser, pIoCtx, pvBuffer, cbBuffer); +} + +DECLINLINE(size_t) vdIfIoIntIoCtxCopyFrom(PVDINTERFACEIOINT pIfIoInt, PVDIOCTX pIoCtx, + void *pvBuffer, size_t cbBuffer) +{ + return pIfIoInt->pfnIoCtxCopyFrom(pIfIoInt->Core.pvUser, pIoCtx, pvBuffer, cbBuffer); +} + +DECLINLINE(size_t) vdIfIoIntIoCtxSet(PVDINTERFACEIOINT pIfIoInt, PVDIOCTX pIoCtx, + int ch, size_t cbSet) +{ + return pIfIoInt->pfnIoCtxSet(pIfIoInt->Core.pvUser, pIoCtx, ch, cbSet); +} + +DECLINLINE(size_t) vdIfIoIntIoCtxSegArrayCreate(PVDINTERFACEIOINT pIfIoInt, PVDIOCTX pIoCtx, + PRTSGSEG paSeg, unsigned *pcSeg, + size_t cbData) +{ + return pIfIoInt->pfnIoCtxSegArrayCreate(pIfIoInt->Core.pvUser, pIoCtx, paSeg, pcSeg, cbData); +} + +DECLINLINE(bool) vdIfIoIntIoCtxIsSynchronous(PVDINTERFACEIOINT pIfIoInt, PVDIOCTX pIoCtx) +{ + return pIfIoInt->pfnIoCtxIsSynchronous(pIfIoInt->Core.pvUser, pIoCtx); +} + +DECLINLINE(bool) vdIfIoIntIoCtxIsZero(PVDINTERFACEIOINT pIfIoInt, PVDIOCTX pIoCtx, + size_t cbCheck, bool fAdvance) +{ + return pIfIoInt->pfnIoCtxIsZero(pIfIoInt->Core.pvUser, pIoCtx, cbCheck, fAdvance); +} + +DECLINLINE(size_t) vdIfIoIntIoCtxGetDataUnitSize(PVDINTERFACEIOINT pIfIoInt, PVDIOCTX pIoCtx) +{ + return pIfIoInt->pfnIoCtxGetDataUnitSize(pIfIoInt->Core.pvUser, pIoCtx); +} + +/** + * Interface for the metadata traverse callback. + * + * Per-operation interface. Present only for the metadata traverse callback. + */ +typedef struct VDINTERFACETRAVERSEMETADATA +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Traverse callback. + * + * @returns VBox status code. + * @param pvUser The opaque data passed for the operation. + * @param pvMetadataChunk Pointer to a chunk of the image metadata. + * @param cbMetadataChunk Size of the metadata chunk + */ + DECLR3CALLBACKMEMBER(int, pfnMetadataCallback, (void *pvUser, const void *pvMetadataChunk, + size_t cbMetadataChunk)); + +} VDINTERFACETRAVERSEMETADATA, *PVDINTERFACETRAVERSEMETADATA; + + +/** + * Get parent state interface from interface list. + * + * @return Pointer to the first parent state interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACETRAVERSEMETADATA) VDIfTraverseMetadataGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_TRAVERSEMETADATA); + + /* Check that the interface descriptor the correct interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_TRAVERSEMETADATA) + && (pIf->cbSize == sizeof(VDINTERFACETRAVERSEMETADATA))), + ("Not a traverse metadata interface"), NULL); + + return (PVDINTERFACETRAVERSEMETADATA)pIf; +} + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vd_ifs_internal_h */ diff --git a/include/VBox/vd-ifs.h b/include/VBox/vd-ifs.h new file mode 100644 index 00000000..87dec3f3 --- /dev/null +++ b/include/VBox/vd-ifs.h @@ -0,0 +1,1765 @@ +/** @file + * VD Container API - interfaces. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vd_ifs_h +#define VBOX_INCLUDED_vd_ifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assert.h> +#include <iprt/string.h> +#include <iprt/mem.h> +#include <iprt/file.h> +#include <iprt/net.h> +#include <iprt/sg.h> +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <VBox/err.h> + +RT_C_DECLS_BEGIN + +/** @addtogroup grp_vd + * @{ */ + +/** Interface header magic. */ +#define VDINTERFACE_MAGIC UINT32_C(0x19701015) + +/** + * Supported interface types. + */ +typedef enum VDINTERFACETYPE +{ + /** First valid interface. */ + VDINTERFACETYPE_FIRST = 0, + /** Interface to pass error message to upper layers. Per-disk. */ + VDINTERFACETYPE_ERROR = VDINTERFACETYPE_FIRST, + /** Interface for I/O operations. Per-image. */ + VDINTERFACETYPE_IO, + /** Interface for progress notification. Per-operation. */ + VDINTERFACETYPE_PROGRESS, + /** Interface for configuration information. Per-image. */ + VDINTERFACETYPE_CONFIG, + /** Interface for TCP network stack. Per-image. */ + VDINTERFACETYPE_TCPNET, + /** Interface for getting parent image state. Per-operation. */ + VDINTERFACETYPE_PARENTSTATE, + /** Interface for synchronizing accesses from several threads. Per-disk. */ + VDINTERFACETYPE_THREADSYNC, + /** Interface for I/O between the generic VBoxHDD code and the backend. Per-image (internal). + * This interface is completely internal and must not be used elsewhere. */ + VDINTERFACETYPE_IOINT, + /** Interface to query the use of block ranges on the disk. Per-operation. */ + VDINTERFACETYPE_QUERYRANGEUSE, + /** Interface for the metadata traverse callback. Per-operation. */ + VDINTERFACETYPE_TRAVERSEMETADATA, + /** Interface for crypto operations. Per-filter. */ + VDINTERFACETYPE_CRYPTO, + /** invalid interface. */ + VDINTERFACETYPE_INVALID +} VDINTERFACETYPE; + +/** + * Common structure for all interfaces and at the beginning of all types. + */ +typedef struct VDINTERFACE +{ + uint32_t u32Magic; + /** Human readable interface name. */ + const char *pszInterfaceName; + /** Pointer to the next common interface structure. */ + struct VDINTERFACE *pNext; + /** Interface type. */ + VDINTERFACETYPE enmInterface; + /** Size of the interface. */ + size_t cbSize; + /** Opaque user data which is passed on every call. */ + void *pvUser; +} VDINTERFACE; +/** Pointer to a VDINTERFACE. */ +typedef VDINTERFACE *PVDINTERFACE; +/** Pointer to a const VDINTERFACE. */ +typedef const VDINTERFACE *PCVDINTERFACE; + +/** + * Helper functions to handle interface lists. + * + * @note These interface lists are used consistently to pass per-disk, + * per-image and/or per-operation callbacks. Those three purposes are strictly + * separate. See the individual interface declarations for what context they + * apply to. The caller is responsible for ensuring that the lifetime of the + * interface descriptors is appropriate for the category of interface. + */ + +/** + * Get a specific interface from a list of interfaces specified by the type. + * + * @return Pointer to the matching interface or NULL if none was found. + * @param pVDIfs Pointer to the VD interface list. + * @param enmInterface Interface to search for. + */ +DECLINLINE(PVDINTERFACE) VDInterfaceGet(PVDINTERFACE pVDIfs, VDINTERFACETYPE enmInterface) +{ + AssertMsgReturn( enmInterface >= VDINTERFACETYPE_FIRST + && enmInterface < VDINTERFACETYPE_INVALID, + ("enmInterface=%u", enmInterface), NULL); + + while (pVDIfs) + { + AssertMsgBreak(pVDIfs->u32Magic == VDINTERFACE_MAGIC, + ("u32Magic=%#x\n", pVDIfs->u32Magic)); + + if (pVDIfs->enmInterface == enmInterface) + return pVDIfs; + pVDIfs = pVDIfs->pNext; + } + + /* No matching interface was found. */ + return NULL; +} + +/** + * Add an interface to a list of interfaces. + * + * @return VBox status code. + * @param pInterface Pointer to an unitialized common interface structure. + * @param pszName Name of the interface. + * @param enmInterface Type of the interface. + * @param pvUser Opaque user data passed on every function call. + * @param cbInterface The interface size. + * @param ppVDIfs Pointer to the VD interface list. + */ +DECLINLINE(int) VDInterfaceAdd(PVDINTERFACE pInterface, const char *pszName, VDINTERFACETYPE enmInterface, void *pvUser, + size_t cbInterface, PVDINTERFACE *ppVDIfs) +{ + /* Argument checks. */ + AssertMsgReturn( enmInterface >= VDINTERFACETYPE_FIRST + && enmInterface < VDINTERFACETYPE_INVALID, + ("enmInterface=%u", enmInterface), VERR_INVALID_PARAMETER); + + AssertPtrReturn(ppVDIfs, VERR_INVALID_PARAMETER); + + /* Fill out interface descriptor. */ + pInterface->u32Magic = VDINTERFACE_MAGIC; + pInterface->cbSize = cbInterface; + pInterface->pszInterfaceName = pszName; + pInterface->enmInterface = enmInterface; + pInterface->pvUser = pvUser; + pInterface->pNext = *ppVDIfs; + + /* Remember the new start of the list. */ + *ppVDIfs = pInterface; + + return VINF_SUCCESS; +} + +/** + * Removes an interface from a list of interfaces. + * + * @return VBox status code + * @param pInterface Pointer to an initialized common interface structure to remove. + * @param ppVDIfs Pointer to the VD interface list to remove from. + */ +DECLINLINE(int) VDInterfaceRemove(PVDINTERFACE pInterface, PVDINTERFACE *ppVDIfs) +{ + int rc = VERR_NOT_FOUND; + + /* Argument checks. */ + AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER); + AssertPtrReturn(ppVDIfs, VERR_INVALID_PARAMETER); + + if (*ppVDIfs) + { + PVDINTERFACE pPrev = NULL; + PVDINTERFACE pCurr = *ppVDIfs; + + while ( pCurr + && (pCurr != pInterface)) + { + pPrev = pCurr; + pCurr = pCurr->pNext; + } + + /* First interface */ + if (!pPrev) + { + *ppVDIfs = pCurr->pNext; + rc = VINF_SUCCESS; + } + else if (pCurr) + { + Assert(pPrev->pNext == pCurr); + pPrev->pNext = pCurr->pNext; + rc = VINF_SUCCESS; + } + } + + return rc; +} + +/** + * Interface to deliver error messages (and also informational messages) + * to upper layers. + * + * Per-disk interface. Optional, but think twice if you want to miss the + * opportunity of reporting better human-readable error messages. + */ +typedef struct VDINTERFACEERROR +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Error message callback. Must be able to accept special IPRT format + * strings. + * + * @param pvUser The opaque data passed on container creation. + * @param rc The VBox error code. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(void, pfnError, (void *pvUser, int rc, RT_SRC_POS_DECL, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + + /** + * Informational message callback. May be NULL. Used e.g. in + * VDDumpImages(). Must be able to accept special IPRT format strings. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pszFormat Message format string. + * @param va Message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnMessage, (void *pvUser, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0)); + +} VDINTERFACEERROR, *PVDINTERFACEERROR; + +/** + * Get error interface from interface list. + * + * @return Pointer to the first error interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACEERROR) VDIfErrorGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_ERROR); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_ERROR) + && (pIf->cbSize == sizeof(VDINTERFACEERROR))), + ("Not an error interface\n"), NULL); + + return (PVDINTERFACEERROR)pIf; +} + +/** + * Signal an error to the frontend. + * + * @returns VBox status code. + * @param pIfError The error interface. + * @param rc The status code. + * @param SRC_POS The position in the source code. + * @param pszFormat The format string to pass. + * @param ... Arguments to the format string. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 7) vdIfError(PVDINTERFACEERROR pIfError, int rc, RT_SRC_POS_DECL, + const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + if (pIfError) + pIfError->pfnError(pIfError->Core.pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va); + va_end(va); + +#if defined(LOG_ENABLED) && defined(Log) + va_start(va, pszFormat); + Log(("vdIfError: %N\n", pszFormat, &va)); + va_end(va); +#endif + return rc; +} + +/** + * Signal an informational message to the frontend. + * + * @returns VBox status code. + * @param pIfError The error interface. + * @param pszFormat The format string to pass. + * @param ... Arguments to the format string. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(2, 3) vdIfErrorMessage(PVDINTERFACEERROR pIfError, const char *pszFormat, ...) +{ + int rc = VINF_SUCCESS; + va_list va; + va_start(va, pszFormat); + if (pIfError && pIfError->pfnMessage) + rc = pIfError->pfnMessage(pIfError->Core.pvUser, pszFormat, va); + va_end(va); + +#if defined(LOG_ENABLED) && defined(Log) + va_start(va, pszFormat); + Log(("vdIfErrorMessage: %N\n", pszFormat, &va)); + va_end(va); +#endif + return rc; +} + +/** + * Completion callback which is called by the interface owner + * to inform the backend that a task finished. + * + * @return VBox status code. + * @param pvUser Opaque user data which is passed on request submission. + * @param rcReq Status code of the completed request. + */ +typedef DECLCALLBACKTYPE(int, FNVDCOMPLETED,(void *pvUser, int rcReq)); +/** Pointer to FNVDCOMPLETED() */ +typedef FNVDCOMPLETED *PFNVDCOMPLETED; + +/** + * Support interface for I/O + * + * Per-image. Optional as input. + */ +typedef struct VDINTERFACEIO +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Open callback + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pszLocation Name of the location to open. + * @param fOpen Flags for opening the backend. + * See RTFILE_O_* \#defines, inventing another set + * of open flags is not worth the mapping effort. + * @param pfnCompleted The callback which is called whenever a task + * completed. The backend has to pass the user data + * of the request initiator (ie the one who calls + * VDAsyncRead or VDAsyncWrite) in pvCompletion + * if this is NULL. + * @param ppvStorage Where to store the opaque storage handle. + */ + DECLR3CALLBACKMEMBER(int, pfnOpen, (void *pvUser, const char *pszLocation, + uint32_t fOpen, + PFNVDCOMPLETED pfnCompleted, + void **ppvStorage)); + + /** + * Close callback. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pvStorage The opaque storage handle to close. + */ + DECLR3CALLBACKMEMBER(int, pfnClose, (void *pvUser, void *pvStorage)); + + /** + * Delete callback. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pcszFilename Name of the file to delete. + */ + DECLR3CALLBACKMEMBER(int, pfnDelete, (void *pvUser, const char *pcszFilename)); + + /** + * Move callback. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pcszSrc The path to the source file. + * @param pcszDst The path to the destination file. + * This file will be created. + * @param fMove A combination of the RTFILEMOVE_* flags. + */ + DECLR3CALLBACKMEMBER(int, pfnMove, (void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)); + + /** + * Returns the free space on a disk. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pcszFilename Name of a file to identify the disk. + * @param pcbFreeSpace Where to store the free space of the disk. + */ + DECLR3CALLBACKMEMBER(int, pfnGetFreeSpace, (void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)); + + /** + * Returns the last modification timestamp of a file. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pcszFilename Name of a file to identify the disk. + * @param pModificationTime Where to store the timestamp of the file. + */ + DECLR3CALLBACKMEMBER(int, pfnGetModificationTime, (void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)); + + /** + * Returns the size of the opened storage backend. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pvStorage The opaque storage handle to get the size from. + * @param pcb Where to store the size of the storage backend. + */ + DECLR3CALLBACKMEMBER(int, pfnGetSize, (void *pvUser, void *pvStorage, uint64_t *pcb)); + + /** + * Sets the size of the opened storage backend if possible. + * + * @return VBox status code. + * @retval VERR_NOT_SUPPORTED if the backend does not support this operation. + * @param pvUser The opaque data passed on container creation. + * @param pvStorage The opaque storage handle to set the size for. + * @param cb The new size of the image. + * + * @note Depending on the host the underlying storage (backing file, etc.) + * might not have all required storage allocated (sparse file) which + * can delay writes or fail with a not enough free space error if there + * is not enough space on the storage medium when writing to the range for + * the first time. + * Use VDINTERFACEIO::pfnSetAllocationSize to make sure the storage is + * really alloacted. + */ + DECLR3CALLBACKMEMBER(int, pfnSetSize, (void *pvUser, void *pvStorage, uint64_t cb)); + + /** + * Sets the size of the opened storage backend making sure the given size + * is really allocated. + * + * @return VBox status code. + * @retval VERR_NOT_SUPPORTED if the implementer of the interface doesn't support + * this method. + * @param pvUser The opaque data passed on container creation. + * @param pvStorage The storage handle. + * @param cbSize The new size of the image. + * @param fFlags Flags for controlling the allocation strategy. + * Reserved for future use, MBZ. + */ + DECLR3CALLBACKMEMBER(int, pfnSetAllocationSize, (void *pvUser, void *pvStorage, + uint64_t cbSize, uint32_t fFlags)); + + /** + * Synchronous write callback. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pvStorage The storage handle to use. + * @param off The offset to start from. + * @param pvBuf Pointer to the bits need to be written. + * @param cbToWrite How many bytes to write. + * @param pcbWritten Where to store how many bytes were actually written. + */ + DECLR3CALLBACKMEMBER(int, pfnWriteSync, (void *pvUser, void *pvStorage, uint64_t off, + const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)); + + /** + * Synchronous read callback. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pvStorage The storage handle to use. + * @param off The offset to start from. + * @param pvBuf Where to store the read bits. + * @param cbToRead How many bytes to read. + * @param pcbRead Where to store how many bytes were actually read. + */ + DECLR3CALLBACKMEMBER(int, pfnReadSync, (void *pvUser, void *pvStorage, uint64_t off, + void *pvBuf, size_t cbToRead, size_t *pcbRead)); + + /** + * Flush data to the storage backend. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pvStorage The storage handle to flush. + */ + DECLR3CALLBACKMEMBER(int, pfnFlushSync, (void *pvUser, void *pvStorage)); + + /** + * Initiate an asynchronous read request. + * + * @return VBox status code. + * @param pvUser The opaque user data passed on container creation. + * @param pvStorage The storage handle. + * @param uOffset The offset to start reading from. + * @param paSegments Scatter gather list to store the data in. + * @param cSegments Number of segments in the list. + * @param cbRead How many bytes to read. + * @param pvCompletion The opaque user data which is returned upon completion. + * @param ppTask Where to store the opaque task handle. + */ + DECLR3CALLBACKMEMBER(int, pfnReadAsync, (void *pvUser, void *pvStorage, uint64_t uOffset, + PCRTSGSEG paSegments, size_t cSegments, + size_t cbRead, void *pvCompletion, + void **ppTask)); + + /** + * Initiate an asynchronous write request. + * + * @return VBox status code. + * @param pvUser The opaque user data passed on conatiner creation. + * @param pvStorage The storage handle. + * @param uOffset The offset to start writing to. + * @param paSegments Scatter gather list of the data to write + * @param cSegments Number of segments in the list. + * @param cbWrite How many bytes to write. + * @param pvCompletion The opaque user data which is returned upon completion. + * @param ppTask Where to store the opaque task handle. + */ + DECLR3CALLBACKMEMBER(int, pfnWriteAsync, (void *pvUser, void *pvStorage, uint64_t uOffset, + PCRTSGSEG paSegments, size_t cSegments, + size_t cbWrite, void *pvCompletion, + void **ppTask)); + + /** + * Initiates an async flush request. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pvStorage The storage handle to flush. + * @param pvCompletion The opaque user data which is returned upon completion. + * @param ppTask Where to store the opaque task handle. + */ + DECLR3CALLBACKMEMBER(int, pfnFlushAsync, (void *pvUser, void *pvStorage, + void *pvCompletion, void **ppTask)); + +} VDINTERFACEIO, *PVDINTERFACEIO; + +/** + * Get I/O interface from interface list. + * + * @return Pointer to the first I/O interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACEIO) VDIfIoGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_IO); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_IO) + && (pIf->cbSize == sizeof(VDINTERFACEIO))), + ("Not a I/O interface"), NULL); + + return (PVDINTERFACEIO)pIf; +} + +DECLINLINE(int) vdIfIoFileOpen(PVDINTERFACEIO pIfIo, const char *pszFilename, + uint32_t fOpen, PFNVDCOMPLETED pfnCompleted, + void **ppStorage) +{ + return pIfIo->pfnOpen(pIfIo->Core.pvUser, pszFilename, fOpen, pfnCompleted, ppStorage); +} + +DECLINLINE(int) vdIfIoFileClose(PVDINTERFACEIO pIfIo, void *pStorage) +{ + return pIfIo->pfnClose(pIfIo->Core.pvUser, pStorage); +} + +DECLINLINE(int) vdIfIoFileDelete(PVDINTERFACEIO pIfIo, const char *pszFilename) +{ + return pIfIo->pfnDelete(pIfIo->Core.pvUser, pszFilename); +} + +DECLINLINE(int) vdIfIoFileMove(PVDINTERFACEIO pIfIo, const char *pszSrc, + const char *pszDst, unsigned fMove) +{ + return pIfIo->pfnMove(pIfIo->Core.pvUser, pszSrc, pszDst, fMove); +} + +DECLINLINE(int) vdIfIoFileGetFreeSpace(PVDINTERFACEIO pIfIo, const char *pszFilename, + int64_t *pcbFree) +{ + return pIfIo->pfnGetFreeSpace(pIfIo->Core.pvUser, pszFilename, pcbFree); +} + +DECLINLINE(int) vdIfIoFileGetModificationTime(PVDINTERFACEIO pIfIo, const char *pcszFilename, + PRTTIMESPEC pModificationTime) +{ + return pIfIo->pfnGetModificationTime(pIfIo->Core.pvUser, pcszFilename, + pModificationTime); +} + +DECLINLINE(int) vdIfIoFileGetSize(PVDINTERFACEIO pIfIo, void *pStorage, + uint64_t *pcbSize) +{ + return pIfIo->pfnGetSize(pIfIo->Core.pvUser, pStorage, pcbSize); +} + +DECLINLINE(int) vdIfIoFileSetSize(PVDINTERFACEIO pIfIo, void *pStorage, + uint64_t cbSize) +{ + return pIfIo->pfnSetSize(pIfIo->Core.pvUser, pStorage, cbSize); +} + +DECLINLINE(int) vdIfIoFileWriteSync(PVDINTERFACEIO pIfIo, void *pStorage, + uint64_t uOffset, const void *pvBuffer, size_t cbBuffer, + size_t *pcbWritten) +{ + return pIfIo->pfnWriteSync(pIfIo->Core.pvUser, pStorage, uOffset, + pvBuffer, cbBuffer, pcbWritten); +} + +DECLINLINE(int) vdIfIoFileReadSync(PVDINTERFACEIO pIfIo, void *pStorage, + uint64_t uOffset, void *pvBuffer, size_t cbBuffer, + size_t *pcbRead) +{ + return pIfIo->pfnReadSync(pIfIo->Core.pvUser, pStorage, uOffset, + pvBuffer, cbBuffer, pcbRead); +} + +DECLINLINE(int) vdIfIoFileFlushSync(PVDINTERFACEIO pIfIo, void *pStorage) +{ + return pIfIo->pfnFlushSync(pIfIo->Core.pvUser, pStorage); +} + +/** + * Create a VFS stream handle around a VD I/O interface. + * + * The I/O interface will not be closed or free by the stream, the caller will + * do so after it is done with the stream and has released the instances of the + * I/O stream object returned by this API. + * + * @return VBox status code. + * @param pVDIfsIo Pointer to the VD I/O interface. + * @param pvStorage The storage argument to pass to the interface + * methods. + * @param fFlags RTFILE_O_XXX, access mask requied. + * @param phVfsIos Where to return the VFS I/O stream handle on + * success. + */ +VBOXDDU_DECL(int) VDIfCreateVfsStream(PVDINTERFACEIO pVDIfsIo, void *pvStorage, uint32_t fFlags, PRTVFSIOSTREAM phVfsIos); + +struct VDINTERFACEIOINT; + +/** + * Create a VFS file handle around a VD I/O interface. + * + * The I/O interface will not be closed or free by the VFS file, the caller will + * do so after it is done with the VFS file and has released the instances of + * the VFS object returned by this API. + * + * @return VBox status code. + * @param pVDIfs Pointer to the VD I/O interface. If NULL, then @a + * pVDIfsInt must be specified. + * @param pVDIfsInt Pointer to the internal VD I/O interface. If NULL, + * then @ pVDIfs must be specified. + * @param pvStorage The storage argument to pass to the interface + * methods. + * @param fFlags RTFILE_O_XXX, access mask requied. + * @param phVfsFile Where to return the VFS file handle on success. + */ +VBOXDDU_DECL(int) VDIfCreateVfsFile(PVDINTERFACEIO pVDIfs, struct VDINTERFACEIOINT *pVDIfsInt, void *pvStorage, + uint32_t fFlags, PRTVFSFILE phVfsFile); + +/** + * Creates an VD I/O interface wrapper around an IPRT VFS I/O stream. + * + * @return VBox status code. + * @param hVfsIos The IPRT VFS I/O stream handle. The handle will be + * retained by the returned I/O interface (released on + * close or destruction). + * @param fAccessMode The access mode (RTFILE_O_ACCESS_MASK) to accept. + * @param ppIoIf Where to return the pointer to the VD I/O interface. + * This must be passed to VDIfDestroyFromVfsStream(). + */ +VBOXDDU_DECL(int) VDIfCreateFromVfsStream(RTVFSIOSTREAM hVfsIos, uint32_t fAccessMode, PVDINTERFACEIO *ppIoIf); + +/** + * Destroys the VD I/O interface returned by VDIfCreateFromVfsStream. + * + * @returns VBox status code. + * @param pIoIf The I/O interface pointer returned by + * VDIfCreateFromVfsStream. NULL will be quietly + * ignored. + */ +VBOXDDU_DECL(int) VDIfDestroyFromVfsStream(PVDINTERFACEIO pIoIf); + + +/** + * Callback which provides progress information about a currently running + * lengthy operation. + * + * @return VBox status code. + * @param pvUser The opaque user data associated with this interface. + * @param uPercentage Completion percentage. + */ +typedef DECLCALLBACKTYPE(int, FNVDPROGRESS,(void *pvUser, unsigned uPercentage)); +/** Pointer to FNVDPROGRESS() */ +typedef FNVDPROGRESS *PFNVDPROGRESS; + +/** + * Progress notification interface + * + * Per-operation. Optional. + */ +typedef struct VDINTERFACEPROGRESS +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Progress notification callbacks. + */ + PFNVDPROGRESS pfnProgress; + +} VDINTERFACEPROGRESS, *PVDINTERFACEPROGRESS; + +/** Initializer for VDINTERFACEPROGRESS. */ +#define VDINTERFACEPROGRESS_INITALIZER(a_pfnProgress) { { 0, NULL, NULL, VDINTERFACETYPE_INVALID, 0, NULL }, a_pfnProgress } + +/** + * Get progress interface from interface list. + * + * @return Pointer to the first progress interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACEPROGRESS) VDIfProgressGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_PROGRESS); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_PROGRESS) + && (pIf->cbSize == sizeof(VDINTERFACEPROGRESS))), + ("Not a progress interface"), NULL); + + return (PVDINTERFACEPROGRESS)pIf; +} + +/** + * Signal new progress information to the frontend. + * + * @returns VBox status code. + * @param pIfProgress The progress interface. + * @param uPercentage Completion percentage. + */ +DECLINLINE(int) vdIfProgress(PVDINTERFACEPROGRESS pIfProgress, unsigned uPercentage) +{ + if (pIfProgress) + return pIfProgress->pfnProgress(pIfProgress->Core.pvUser, uPercentage); + return VINF_SUCCESS; +} + +/** + * Configuration information interface + * + * Per-image. Optional for most backends, but mandatory for images which do + * not operate on files (including standard block or character devices). + */ +typedef struct VDINTERFACECONFIG +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Validates that the keys are within a set of valid names. + * + * @return true if all key names are found in pszzAllowed. + * @return false if not. + * @param pvUser The opaque user data associated with this interface. + * @param pszzValid List of valid key names separated by '\\0' and ending with + * a double '\\0'. + */ + DECLR3CALLBACKMEMBER(bool, pfnAreKeysValid, (void *pvUser, const char *pszzValid)); + + /** + * Retrieves the length of the string value associated with a key (including + * the terminator, for compatibility with CFGMR3QuerySize). + * + * @return VBox status code. + * VERR_CFGM_VALUE_NOT_FOUND means that the key is not known. + * @param pvUser The opaque user data associated with this interface. + * @param pszName Name of the key to query. + * @param pcbValue Where to store the value length. Non-NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnQuerySize, (void *pvUser, const char *pszName, size_t *pcbValue)); + + /** + * Query the string value associated with a key. + * + * @return VBox status code. + * VERR_CFGM_VALUE_NOT_FOUND means that the key is not known. + * VERR_CFGM_NOT_ENOUGH_SPACE means that the buffer is not big enough. + * @param pvUser The opaque user data associated with this interface. + * @param pszName Name of the key to query. + * @param pszValue Pointer to buffer where to store value. + * @param cchValue Length of value buffer. + */ + DECLR3CALLBACKMEMBER(int, pfnQuery, (void *pvUser, const char *pszName, char *pszValue, size_t cchValue)); + + /** + * Query the bytes value associated with a key. + * + * @return VBox status code. + * VERR_CFGM_VALUE_NOT_FOUND means that the key is not known. + * VERR_CFGM_NOT_ENOUGH_SPACE means that the buffer is not big enough. + * @param pvUser The opaque user data associated with this interface. + * @param pszName Name of the key to query. + * @param ppvData Pointer to buffer where to store the data. + * @param cbData Length of data buffer. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryBytes, (void *pvUser, const char *pszName, void *ppvData, size_t cbData)); + + /** + * Set a named property to a specified string value, optionally creating if it doesn't exist. + * + * @return VBox status code. + * VERR_CFGM_VALUE_NOT_FOUND means that the key is not known and fCreate flag was not set. + * @param pvUser The opaque user data associated with this interface. + * @param fCreate Create property if it doesn't exist (if property exists, it is not an error) + * @param pszName Name of the key to query. + * @param pszValue String value to set the name property to. + */ + DECLR3CALLBACKMEMBER(int, pfnUpdate, (void *pvUser, bool fCreate, + const char *pszName, const char *pszValue)); + +} VDINTERFACECONFIG, *PVDINTERFACECONFIG; + +/** + * Get configuration information interface from interface list. + * + * @return Pointer to the first configuration information interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACECONFIG) VDIfConfigGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_CONFIG); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_CONFIG) + && (pIf->cbSize == sizeof(VDINTERFACECONFIG))), + ("Not a config interface"), NULL); + + return (PVDINTERFACECONFIG)pIf; +} + +/** + * Query configuration, validates that the keys are within a set of valid names. + * + * @return true if all key names are found in pszzAllowed. + * @return false if not. + * @param pCfgIf Pointer to configuration callback table. + * @param pszzValid List of valid names separated by '\\0' and ending with + * a double '\\0'. + */ +DECLINLINE(bool) VDCFGAreKeysValid(PVDINTERFACECONFIG pCfgIf, const char *pszzValid) +{ + return pCfgIf->pfnAreKeysValid(pCfgIf->Core.pvUser, pszzValid); +} + +/** + * Checks whether a given key is existing. + * + * @return true if the key exists. + * @return false if the key does not exist. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of the key. + */ +DECLINLINE(bool) VDCFGIsKeyExisting(PVDINTERFACECONFIG pCfgIf, const char *pszName) +{ + size_t cb = 0; + int rc = pCfgIf->pfnQuerySize(pCfgIf->Core.pvUser, pszName, &cb); + return rc == VERR_CFGM_VALUE_NOT_FOUND ? false : true; +} + +/** + * Query configuration, unsigned 64-bit integer value with default. + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of an integer value + * @param pu64 Where to store the value. Set to default on failure. + * @param u64Def The default value. + */ +DECLINLINE(int) VDCFGQueryU64Def(PVDINTERFACECONFIG pCfgIf, + const char *pszName, uint64_t *pu64, + uint64_t u64Def) +{ + char aszBuf[32]; + int rc = pCfgIf->pfnQuery(pCfgIf->Core.pvUser, pszName, aszBuf, sizeof(aszBuf)); + if (RT_SUCCESS(rc)) + { + rc = RTStrToUInt64Full(aszBuf, 0, pu64); + } + else if (rc == VERR_CFGM_VALUE_NOT_FOUND) + { + rc = VINF_SUCCESS; + *pu64 = u64Def; + } + return rc; +} + +/** + * Query configuration, unsigned 64-bit integer value. + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of an integer value + * @param pu64 Where to store the value. + */ +DECLINLINE(int) VDCFGQueryU64(PVDINTERFACECONFIG pCfgIf, const char *pszName, + uint64_t *pu64) +{ + char aszBuf[32]; + int rc = pCfgIf->pfnQuery(pCfgIf->Core.pvUser, pszName, aszBuf, sizeof(aszBuf)); + if (RT_SUCCESS(rc)) + { + rc = RTStrToUInt64Full(aszBuf, 0, pu64); + } + + return rc; +} + +/** + * Query configuration, unsigned 32-bit integer value with default. + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of an integer value + * @param pu32 Where to store the value. Set to default on failure. + * @param u32Def The default value. + */ +DECLINLINE(int) VDCFGQueryU32Def(PVDINTERFACECONFIG pCfgIf, + const char *pszName, uint32_t *pu32, + uint32_t u32Def) +{ + uint64_t u64; + int rc = VDCFGQueryU64Def(pCfgIf, pszName, &u64, u32Def); + if (RT_SUCCESS(rc)) + { + if (!(u64 & UINT64_C(0xffffffff00000000))) + *pu32 = (uint32_t)u64; + else + rc = VERR_CFGM_INTEGER_TOO_BIG; + } + return rc; +} + +/** + * Query configuration, bool value with default. + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of an integer value + * @param pf Where to store the value. Set to default on failure. + * @param fDef The default value. + */ +DECLINLINE(int) VDCFGQueryBoolDef(PVDINTERFACECONFIG pCfgIf, + const char *pszName, bool *pf, + bool fDef) +{ + uint64_t u64; + int rc = VDCFGQueryU64Def(pCfgIf, pszName, &u64, fDef); + if (RT_SUCCESS(rc)) + *pf = u64 ? true : false; + return rc; +} + +/** + * Query configuration, bool value. + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of an integer value + * @param pf Where to store the value. + */ +DECLINLINE(int) VDCFGQueryBool(PVDINTERFACECONFIG pCfgIf, const char *pszName, + bool *pf) +{ + uint64_t u64; + int rc = VDCFGQueryU64(pCfgIf, pszName, &u64); + if (RT_SUCCESS(rc)) + *pf = u64 ? true : false; + return rc; +} + +/** + * Query configuration, dynamically allocated (RTMemAlloc) zero terminated + * character value. + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of an zero terminated character value + * @param ppszString Where to store the string pointer. Not set on failure. + * Free this using RTMemFree(). + */ +DECLINLINE(int) VDCFGQueryStringAlloc(PVDINTERFACECONFIG pCfgIf, + const char *pszName, char **ppszString) +{ + size_t cb; + int rc = pCfgIf->pfnQuerySize(pCfgIf->Core.pvUser, pszName, &cb); + if (RT_SUCCESS(rc)) + { + char *pszString = (char *)RTMemAlloc(cb); + if (pszString) + { + rc = pCfgIf->pfnQuery(pCfgIf->Core.pvUser, pszName, pszString, cb); + if (RT_SUCCESS(rc)) + *ppszString = pszString; + else + RTMemFree(pszString); + } + else + rc = VERR_NO_MEMORY; + } + return rc; +} + +/** + * Query configuration, dynamically allocated (RTMemAlloc) zero terminated + * character value with default. + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of an zero terminated character value + * @param ppszString Where to store the string pointer. Not set on failure. + * Free this using RTMemFree(). + * @param pszDef The default value. + */ +DECLINLINE(int) VDCFGQueryStringAllocDef(PVDINTERFACECONFIG pCfgIf, + const char *pszName, + char **ppszString, + const char *pszDef) +{ + size_t cb; + int rc = pCfgIf->pfnQuerySize(pCfgIf->Core.pvUser, pszName, &cb); + if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT) + { + cb = strlen(pszDef) + 1; + rc = VINF_SUCCESS; + } + if (RT_SUCCESS(rc)) + { + char *pszString = (char *)RTMemAlloc(cb); + if (pszString) + { + rc = pCfgIf->pfnQuery(pCfgIf->Core.pvUser, pszName, pszString, cb); + if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT) + { + memcpy(pszString, pszDef, cb); + rc = VINF_SUCCESS; + } + if (RT_SUCCESS(rc)) + *ppszString = pszString; + else + RTMemFree(pszString); + } + else + rc = VERR_NO_MEMORY; + } + return rc; +} + +/** + * Query configuration, dynamically allocated (RTMemAlloc) byte string value. + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of an zero terminated character value + * @param ppvData Where to store the byte string pointer. Not set on failure. + * Free this using RTMemFree(). + * @param pcbData Where to store the byte string length. + */ +DECLINLINE(int) VDCFGQueryBytesAlloc(PVDINTERFACECONFIG pCfgIf, + const char *pszName, void **ppvData, size_t *pcbData) +{ + size_t cb; + int rc = pCfgIf->pfnQuerySize(pCfgIf->Core.pvUser, pszName, &cb); + if (RT_SUCCESS(rc)) + { + char *pbData; + Assert(cb); + + pbData = (char *)RTMemAlloc(cb); + if (pbData) + { + if(pCfgIf->pfnQueryBytes) + rc = pCfgIf->pfnQueryBytes(pCfgIf->Core.pvUser, pszName, pbData, cb); + else + rc = pCfgIf->pfnQuery(pCfgIf->Core.pvUser, pszName, pbData, cb); + + if (RT_SUCCESS(rc)) + { + *ppvData = pbData; + /* Exclude terminator if the byte data was obtained using the string query callback. */ + *pcbData = cb; + if (!pCfgIf->pfnQueryBytes) + (*pcbData)--; + } + else + RTMemFree(pbData); + } + else + rc = VERR_NO_MEMORY; + } + return rc; +} + +/** + * Set property value to string (optionally create if non-existent). + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param fCreate Create the property if it doesn't exist + * @param pszName Name of property + * @param pszValue String value to assign to property + */ +DECLINLINE(int) VDCFGUpdate(PVDINTERFACECONFIG pCfgIf, bool fCreate, const char *pszName, const char *pszValue) +{ + int rc = pCfgIf->pfnUpdate(pCfgIf->Core.pvUser, fCreate, pszName, pszValue); + return rc; +} + +/** + * Set property value to Unsigned Int 64-bit (optionally create if non-existent). + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param fCreate Create the property if it doesn't exist + * @param pszName Name of property + * @param u64Value 64-bit unsigned value to save with property. + */ + +DECLINLINE(int) VDCFGUpdateU64(PVDINTERFACECONFIG pCfgIf, bool fCreate, const char *pszName, uint64_t u64Value) +{ + int rc = 0; + char pszValue[21]; + (void) RTStrPrintf(pszValue, sizeof(pszValue), "%RU64", u64Value); + rc = VDCFGUpdate(pCfgIf, fCreate, pszName, pszValue); + return rc; +} + + + +/** Forward declaration of a VD socket. */ +typedef struct VDSOCKETINT *VDSOCKET; +/** Pointer to a VD socket. */ +typedef VDSOCKET *PVDSOCKET; +/** Nil socket handle. */ +#define NIL_VDSOCKET ((VDSOCKET)0) + +/** Connect flag to indicate that the backend wants to use the extended + * socket I/O multiplexing call. This might not be supported on all configurations + * (internal networking and iSCSI) + * and the backend needs to take appropriate action. + */ +#define VD_INTERFACETCPNET_CONNECT_EXTENDED_SELECT RT_BIT_32(0) + +/** @name Select events + * @{ */ +/** Readable without blocking. */ +#define VD_INTERFACETCPNET_EVT_READ RT_BIT_32(0) +/** Writable without blocking. */ +#define VD_INTERFACETCPNET_EVT_WRITE RT_BIT_32(1) +/** Error condition, hangup, exception or similar. */ +#define VD_INTERFACETCPNET_EVT_ERROR RT_BIT_32(2) +/** Hint for the select that getting interrupted while waiting is more likely. + * The interface implementation can optimize the waiting strategy based on this. + * It is assumed that it is more likely to get one of the above socket events + * instead of being interrupted if the flag is not set. */ +#define VD_INTERFACETCPNET_HINT_INTERRUPT RT_BIT_32(3) +/** Mask of the valid bits. */ +#define VD_INTERFACETCPNET_EVT_VALID_MASK UINT32_C(0x0000000f) +/** @} */ + +/** + * TCP network stack interface + * + * Per-image. Mandatory for backends which have the VD_CAP_TCPNET bit set. + */ +typedef struct VDINTERFACETCPNET +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Creates a socket. The socket is not connected if this succeeds. + * + * @return iprt status code. + * @retval VERR_NOT_SUPPORTED if the combination of flags is not supported. + * @param fFlags Combination of the VD_INTERFACETCPNET_CONNECT_* \#defines. + * @param phVdSock Where to store the handle. + */ + DECLR3CALLBACKMEMBER(int, pfnSocketCreate, (uint32_t fFlags, PVDSOCKET phVdSock)); + + /** + * Destroys the socket. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + */ + DECLR3CALLBACKMEMBER(int, pfnSocketDestroy, (VDSOCKET hVdSock)); + + /** + * Connect as a client to a TCP port. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer).. + * @param pszAddress The address to connect to. + * @param uPort The port to connect to. + * @param cMillies Number of milliseconds to wait for the connect attempt to complete. + * Use RT_INDEFINITE_WAIT to wait for ever. + * Use RT_SOCKETCONNECT_DEFAULT_WAIT to wait for the default time + * configured on the running system. + */ + DECLR3CALLBACKMEMBER(int, pfnClientConnect, (VDSOCKET hVdSock, const char *pszAddress, uint32_t uPort, + RTMSINTERVAL cMillies)); + + /** + * Close a TCP connection. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + */ + DECLR3CALLBACKMEMBER(int, pfnClientClose, (VDSOCKET hVdSock)); + + /** + * Returns whether the socket is currently connected to the client. + * + * @returns true if the socket is connected. + * false otherwise. + * @param hVdSock Socket handle (/ pointer). + */ + DECLR3CALLBACKMEMBER(bool, pfnIsClientConnected, (VDSOCKET hVdSock)); + + /** + * Socket I/O multiplexing. + * Checks if the socket is ready for reading. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param cMillies Number of milliseconds to wait for the socket. + * Use RT_INDEFINITE_WAIT to wait for ever. + */ + DECLR3CALLBACKMEMBER(int, pfnSelectOne, (VDSOCKET hVdSock, RTMSINTERVAL cMillies)); + + /** + * Receive data from a socket. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param pvBuffer Where to put the data we read. + * @param cbBuffer Read buffer size. + * @param pcbRead Number of bytes read. + * If NULL the entire buffer will be filled upon successful return. + * If not NULL a partial read can be done successfully. + */ + DECLR3CALLBACKMEMBER(int, pfnRead, (VDSOCKET hVdSock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)); + + /** + * Send data to a socket. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite, (VDSOCKET hVdSock, const void *pvBuffer, size_t cbBuffer)); + + /** + * Send data from scatter/gather buffer to a socket. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param pSgBuf Scatter/gather buffer to write data to socket. + */ + DECLR3CALLBACKMEMBER(int, pfnSgWrite, (VDSOCKET hVdSock, PCRTSGBUF pSgBuf)); + + /** + * Receive data from a socket - not blocking. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param pvBuffer Where to put the data we read. + * @param cbBuffer Read buffer size. + * @param pcbRead Number of bytes read. + */ + DECLR3CALLBACKMEMBER(int, pfnReadNB, (VDSOCKET hVdSock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)); + + /** + * Send data to a socket - not blocking. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + * @param pcbWritten Number of bytes written. + */ + DECLR3CALLBACKMEMBER(int, pfnWriteNB, (VDSOCKET hVdSock, const void *pvBuffer, size_t cbBuffer, size_t *pcbWritten)); + + /** + * Send data from scatter/gather buffer to a socket - not blocking. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param pSgBuf Scatter/gather buffer to write data to socket. + * @param pcbWritten Number of bytes written. + */ + DECLR3CALLBACKMEMBER(int, pfnSgWriteNB, (VDSOCKET hVdSock, PRTSGBUF pSgBuf, size_t *pcbWritten)); + + /** + * Flush socket write buffers. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + */ + DECLR3CALLBACKMEMBER(int, pfnFlush, (VDSOCKET hVdSock)); + + /** + * Enables or disables delaying sends to coalesce packets. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param fEnable When set to true enables coalescing. + */ + DECLR3CALLBACKMEMBER(int, pfnSetSendCoalescing, (VDSOCKET hVdSock, bool fEnable)); + + /** + * Gets the address of the local side. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param pAddr Where to store the local address on success. + */ + DECLR3CALLBACKMEMBER(int, pfnGetLocalAddress, (VDSOCKET hVdSock, PRTNETADDR pAddr)); + + /** + * Gets the address of the other party. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param pAddr Where to store the peer address on success. + */ + DECLR3CALLBACKMEMBER(int, pfnGetPeerAddress, (VDSOCKET hVdSock, PRTNETADDR pAddr)); + + /** + * Socket I/O multiplexing - extended version which can be woken up. + * Checks if the socket is ready for reading or writing. + * + * @return iprt status code. + * @retval VERR_INTERRUPTED if the thread was woken up by a pfnPoke call. + * @param hVdSock VD Socket handle(/pointer). + * @param fEvents Mask of events to wait for. + * @param pfEvents Where to store the received events. + * @param cMillies Number of milliseconds to wait for the socket. + * Use RT_INDEFINITE_WAIT to wait for ever. + */ + DECLR3CALLBACKMEMBER(int, pfnSelectOneEx, (VDSOCKET hVdSock, uint32_t fEvents, + uint32_t *pfEvents, RTMSINTERVAL cMillies)); + + /** + * Wakes up the thread waiting in pfnSelectOneEx. + * + * @return iprt status code. + * @param hVdSock VD Socket handle(/pointer). + */ + DECLR3CALLBACKMEMBER(int, pfnPoke, (VDSOCKET hVdSock)); + +} VDINTERFACETCPNET, *PVDINTERFACETCPNET; + +/** + * Get TCP network stack interface from interface list. + * + * @return Pointer to the first TCP network stack interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACETCPNET) VDIfTcpNetGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_TCPNET); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_TCPNET) + && (pIf->cbSize == sizeof(VDINTERFACETCPNET))), + ("Not a TCP net interface"), NULL); + + return (PVDINTERFACETCPNET)pIf; +} + + +/** + * Interface to synchronize concurrent accesses by several threads. + * + * @note The scope of this interface is to manage concurrent accesses after + * the HDD container has been created, and they must stop before destroying the + * container. Opening or closing images is covered by the synchronization, but + * that does not mean it is safe to close images while a thread executes + * #VDMerge or #VDCopy operating on these images. Making them safe would require + * the lock to be held during the entire operation, which prevents other + * concurrent acitivities. + * + * @note Right now this is kept as simple as possible, and does not even + * attempt to provide enough information to allow e.g. concurrent write + * accesses to different areas of the disk. The reason is that it is very + * difficult to predict which area of a disk is affected by a write, + * especially when different image formats are mixed. Maybe later a more + * sophisticated interface will be provided which has the necessary information + * about worst case affected areas. + * + * Per-disk interface. Optional, needed if the disk is accessed concurrently + * by several threads, e.g. when merging diff images while a VM is running. + */ +typedef struct VDINTERFACETHREADSYNC +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Start a read operation. + */ + DECLR3CALLBACKMEMBER(int, pfnStartRead, (void *pvUser)); + + /** + * Finish a read operation. + */ + DECLR3CALLBACKMEMBER(int, pfnFinishRead, (void *pvUser)); + + /** + * Start a write operation. + */ + DECLR3CALLBACKMEMBER(int, pfnStartWrite, (void *pvUser)); + + /** + * Finish a write operation. + */ + DECLR3CALLBACKMEMBER(int, pfnFinishWrite, (void *pvUser)); + +} VDINTERFACETHREADSYNC, *PVDINTERFACETHREADSYNC; + +/** + * Get thread synchronization interface from interface list. + * + * @return Pointer to the first thread synchronization interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACETHREADSYNC) VDIfThreadSyncGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_THREADSYNC); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_THREADSYNC) + && (pIf->cbSize == sizeof(VDINTERFACETHREADSYNC))), + ("Not a thread synchronization interface"), NULL); + + return (PVDINTERFACETHREADSYNC)pIf; +} + +/** + * Interface to query usage of disk ranges. + * + * Per-operation interface. Optional. + */ +typedef struct VDINTERFACEQUERYRANGEUSE +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Query use of a disk range. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryRangeUse, (void *pvUser, uint64_t off, uint64_t cb, + bool *pfUsed)); + +} VDINTERFACEQUERYRANGEUSE, *PVDINTERFACEQUERYRANGEUSE; + +/** + * Get query range use interface from interface list. + * + * @return Pointer to the first thread synchronization interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACEQUERYRANGEUSE) VDIfQueryRangeUseGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_QUERYRANGEUSE); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_QUERYRANGEUSE) + && (pIf->cbSize == sizeof(VDINTERFACEQUERYRANGEUSE))), + ("Not a query range use interface"), NULL); + + return (PVDINTERFACEQUERYRANGEUSE)pIf; +} + +DECLINLINE(int) vdIfQueryRangeUse(PVDINTERFACEQUERYRANGEUSE pIfQueryRangeUse, uint64_t off, uint64_t cb, + bool *pfUsed) +{ + return pIfQueryRangeUse->pfnQueryRangeUse(pIfQueryRangeUse->Core.pvUser, off, cb, pfUsed); +} + + +/** + * Interface used to retrieve keys for cryptographic operations. + * + * Per-module interface. Optional but cryptographic modules might fail and + * return an error if this is not present. + */ +typedef struct VDINTERFACECRYPTO +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Retains a key identified by the ID. The caller will only hold a reference + * to the key and must not modify the key buffer in any way. + * + * @returns VBox status code. + * @param pvUser The opaque user data associated with this interface. + * @param pszId The alias/id for the key to retrieve. + * @param ppbKey Where to store the pointer to the key buffer on success. + * @param pcbKey Where to store the size of the key in bytes on success. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyRetain, (void *pvUser, const char *pszId, const uint8_t **ppbKey, size_t *pcbKey)); + + /** + * Releases one reference of the key identified by the given identifier. + * The caller must not access the key buffer after calling this operation. + * + * @returns VBox status code. + * @param pvUser The opaque user data associated with this interface. + * @param pszId The alias/id for the key to release. + * + * @note It is advised to release the key whenever it is not used anymore so + * the entity storing the key can do anything to make retrieving the key + * from memory more difficult like scrambling the memory buffer for + * instance. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyRelease, (void *pvUser, const char *pszId)); + + /** + * Gets a reference to the password identified by the given ID to open a key store supplied through the config interface. + * + * @returns VBox status code. + * @param pvUser The opaque user data associated with this interface. + * @param pszId The alias/id for the password to retain. + * @param ppszPassword Where to store the password to unlock the key store on success. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyStorePasswordRetain, (void *pvUser, const char *pszId, const char **ppszPassword)); + + /** + * Releases a reference of the password previously acquired with VDINTERFACECRYPTO::pfnKeyStorePasswordRetain() + * identified by the given ID. + * + * @returns VBox status code. + * @param pvUser The opaque user data associated with this interface. + * @param pszId The alias/id for the password to release. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyStorePasswordRelease, (void *pvUser, const char *pszId)); + + /** + * Saves a key store. + * + * @returns VBox status code. + * @param pvUser The opaque user data associated with this interface. + * @param pvKeyStore The key store to save. + * @param cbKeyStore Size of the key store in bytes. + * + * @note The format is filter specific and should be treated as binary data. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyStoreSave, (void *pvUser, const void *pvKeyStore, size_t cbKeyStore)); + + /** + * Returns the parameters after the key store was loaded successfully. + * + * @returns VBox status code. + * @param pvUser The opaque user data associated with this interface. + * @param pszCipher The cipher identifier the DEK is used for. + * @param pbDek The raw DEK which was contained in the key store loaded by + * VDINTERFACECRYPTO::pfnKeyStoreLoad(). + * @param cbDek The size of the DEK. + * + * @note The provided pointer to the DEK is only valid until this call returns. + * The content might change afterwards with out notice (when scrambling the key + * for further protection for example) or might be even freed. + * + * @note This method is optional and can be NULL if the caller does not require the + * parameters. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyStoreReturnParameters, (void *pvUser, const char *pszCipher, + const uint8_t *pbDek, size_t cbDek)); + +} VDINTERFACECRYPTO, *PVDINTERFACECRYPTO; + + +/** + * Get error interface from interface list. + * + * @return Pointer to the first error interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACECRYPTO) VDIfCryptoGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_CRYPTO); + + /* Check that the interface descriptor is a crypto interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_CRYPTO) + && (pIf->cbSize == sizeof(VDINTERFACECRYPTO))), + ("Not an crypto interface\n"), NULL); + + return (PVDINTERFACECRYPTO)pIf; +} + +/** + * Retains a key identified by the ID. The caller will only hold a reference + * to the key and must not modify the key buffer in any way. + * + * @returns VBox status code. + * @param pIfCrypto Pointer to the crypto interface. + * @param pszId The alias/id for the key to retrieve. + * @param ppbKey Where to store the pointer to the key buffer on success. + * @param pcbKey Where to store the size of the key in bytes on success. + */ +DECLINLINE(int) vdIfCryptoKeyRetain(PVDINTERFACECRYPTO pIfCrypto, const char *pszId, const uint8_t **ppbKey, size_t *pcbKey) +{ + return pIfCrypto->pfnKeyRetain(pIfCrypto->Core.pvUser, pszId, ppbKey, pcbKey); +} + +/** + * Releases one reference of the key identified by the given identifier. + * The caller must not access the key buffer after calling this operation. + * + * @returns VBox status code. + * @param pIfCrypto Pointer to the crypto interface. + * @param pszId The alias/id for the key to release. + * + * @note It is advised to release the key whenever it is not used anymore so + * the entity storing the key can do anything to make retrieving the key + * from memory more difficult like scrambling the memory buffer for + * instance. + */ +DECLINLINE(int) vdIfCryptoKeyRelease(PVDINTERFACECRYPTO pIfCrypto, const char *pszId) +{ + return pIfCrypto->pfnKeyRelease(pIfCrypto->Core.pvUser, pszId); +} + +/** + * Gets a reference to the password identified by the given ID to open a key store supplied through the config interface. + * + * @returns VBox status code. + * @param pIfCrypto Pointer to the crypto interface. + * @param pszId The alias/id for the password to retain. + * @param ppszPassword Where to store the password to unlock the key store on success. + */ +DECLINLINE(int) vdIfCryptoKeyStorePasswordRetain(PVDINTERFACECRYPTO pIfCrypto, const char *pszId, const char **ppszPassword) +{ + return pIfCrypto->pfnKeyStorePasswordRetain(pIfCrypto->Core.pvUser, pszId, ppszPassword); +} + +/** + * Releases a reference of the password previously acquired with VDINTERFACECRYPTO::pfnKeyStorePasswordRetain() + * identified by the given ID. + * + * @returns VBox status code. + * @param pIfCrypto Pointer to the crypto interface. + * @param pszId The alias/id for the password to release. + */ +DECLINLINE(int) vdIfCryptoKeyStorePasswordRelease(PVDINTERFACECRYPTO pIfCrypto, const char *pszId) +{ + return pIfCrypto->pfnKeyStorePasswordRelease(pIfCrypto->Core.pvUser, pszId); +} + +/** + * Saves a key store. + * + * @returns VBox status code. + * @param pIfCrypto Pointer to the crypto interface. + * @param pvKeyStore The key store to save. + * @param cbKeyStore Size of the key store in bytes. + * + * @note The format is filter specific and should be treated as binary data. + */ +DECLINLINE(int) vdIfCryptoKeyStoreSave(PVDINTERFACECRYPTO pIfCrypto, const void *pvKeyStore, size_t cbKeyStore) +{ + return pIfCrypto->pfnKeyStoreSave(pIfCrypto->Core.pvUser, pvKeyStore, cbKeyStore); +} + +/** + * Returns the parameters after the key store was loaded successfully. + * + * @returns VBox status code. + * @param pIfCrypto Pointer to the crypto interface. + * @param pszCipher The cipher identifier the DEK is used for. + * @param pbDek The raw DEK which was contained in the key store loaded by + * VDINTERFACECRYPTO::pfnKeyStoreLoad(). + * @param cbDek The size of the DEK. + * + * @note The provided pointer to the DEK is only valid until this call returns. + * The content might change afterwards with out notice (when scrambling the key + * for further protection for example) or might be even freed. + * + * @note This method is optional and can be NULL if the caller does not require the + * parameters. + */ +DECLINLINE(int) vdIfCryptoKeyStoreReturnParameters(PVDINTERFACECRYPTO pIfCrypto, const char *pszCipher, + const uint8_t *pbDek, size_t cbDek) +{ + if (pIfCrypto->pfnKeyStoreReturnParameters) + return pIfCrypto->pfnKeyStoreReturnParameters(pIfCrypto->Core.pvUser, pszCipher, pbDek, cbDek); + + return VINF_SUCCESS; +} + + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_vd_ifs_h */ diff --git a/include/VBox/vd-image-backend.h b/include/VBox/vd-image-backend.h new file mode 100644 index 00000000..163720c9 --- /dev/null +++ b/include/VBox/vd-image-backend.h @@ -0,0 +1,617 @@ +/** @file + * VD: Image backend interface. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vd_image_backend_h +#define VBOX_INCLUDED_vd_image_backend_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vd.h> +#include <VBox/vd-common.h> +#include <VBox/vd-ifs-internal.h> + + +/** @name VBox HDD backend write flags + * @{ + */ +/** Do not allocate a new block on this write. This is just an advisory + * flag. The backend may still decide in some circumstances that it wants + * to ignore this flag (which may cause extra dynamic image expansion). */ +#define VD_WRITE_NO_ALLOC RT_BIT(1) +/** @}*/ + +/** @name VBox HDD backend discard flags + * @{ + */ +/** Don't discard block but mark the given range as unused + * (usually by writing 0's to it). + * This doesn't require the range to be aligned on a block boundary but + * the image size might not be decreased. */ +#define VD_DISCARD_MARK_UNUSED RT_BIT(0) +/** @}*/ + +/** @name VBox HDD backend metadata traverse flags + * @{ + */ +/** Include per block metadata while traversing the metadata. + * This might take much longer instead of traversing just global metadata. */ +#define VD_TRAVERSE_METADATA_INCLUDE_PER_BLOCK_METADATA RT_BIT(0) +/** @}*/ + +/** + * Image format backend interface used by VBox HDD Container implementation. + */ +typedef struct VDIMAGEBACKEND +{ + /** Structure version. VD_IMGBACKEND_VERSION defines the current version. */ + uint32_t u32Version; + /** The name of the backend (constant string). */ + const char *pszBackendName; + /** The capabilities of the backend. */ + uint64_t uBackendCaps; + + /** + * Pointer to a NULL-terminated array, containing the supported + * file extensions. Note that some backends do not work on files, so this + * pointer may just contain NULL. + */ + PCVDFILEEXTENSION paFileExtensions; + + /** + * Pointer to an array of structs describing each supported config key. + * Terminated by a NULL config key. Note that some backends do not support + * the configuration interface, so this pointer may just contain NULL. + * Mandatory if the backend sets VD_CAP_CONFIG. + */ + PCVDCONFIGINFO paConfigInfo; + + /** + * Check whether the file is supported by the backend. + * + * @returns VBox status code. + * @param pszFilename Name of the image file. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param enmDesiredType The desired image type, VDTYPE_INVALID if anything goes. + * @param penmType Returns the supported device type on success. + */ + DECLR3CALLBACKMEMBER(int, pfnProbe, (const char *pszFilename, PVDINTERFACE pVDIfsDisk, + PVDINTERFACE pVDIfsImage, VDTYPE enmDesiredType, VDTYPE *penmType)); + + /** + * Open a disk image. + * + * @returns VBox status code. + * @param pszFilename Name of the image file to open. Guaranteed to be available and + * unchanged during the lifetime of this image. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param enmType Requested type of the image. + * @param ppBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(int, pfnOpen, (const char *pszFilename, unsigned uOpenFlags, + PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage, + VDTYPE enmType, void **ppBackendData)); + + /** + * Create a disk image. + * + * @returns VBox status code. + * @param pszFilename Name of the image file to create. Guaranteed to be available and + * unchanged during the lifetime of this image. + * @param cbSize Image size in bytes. + * @param uImageFlags Flags specifying special image features. + * @param pszComment Pointer to image comment. NULL is ok. + * @param pPCHSGeometry Physical drive geometry CHS <= (16383,16,255). + * @param pLCHSGeometry Logical drive geometry CHS <= (1024,255,63). + * @param pUuid New UUID of the image. Not NULL. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param uPercentStart Starting value for progress percentage. + * @param uPercentSpan Span for varying progress percentage. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + * @param enmType Requested type of the image. + * @param ppBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(int, pfnCreate, (const char *pszFilename, uint64_t cbSize, + unsigned uImageFlags, const char *pszComment, + PCVDGEOMETRY pPCHSGeometry, + PCVDGEOMETRY pLCHSGeometry, + PCRTUUID pUuid, unsigned uOpenFlags, + unsigned uPercentStart, unsigned uPercentSpan, + PVDINTERFACE pVDIfsDisk, + PVDINTERFACE pVDIfsImage, + PVDINTERFACE pVDIfsOperation, + VDTYPE enmType, + void **ppBackendData)); + + /** + * Rename a disk image. Only needs to work as long as the operating + * system's rename file functionality is usable. If an attempt is made to + * rename an image to a location on another disk/filesystem, this function + * may just fail with an appropriate error code (not changing the opened + * image data at all). Also works only on images which actually refer to + * regular files. May be NULL. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pszFilename New name of the image file. Guaranteed to be available and + * unchanged during the lifetime of this image. + */ + DECLR3CALLBACKMEMBER(int, pfnRename, (void *pBackendData, const char *pszFilename)); + + /** + * Close a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param fDelete If true, delete the image from the host disk. + */ + DECLR3CALLBACKMEMBER(int, pfnClose, (void *pBackendData, bool fDelete)); + + /** + * Start a read request. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param uOffset The offset of the virtual disk to read from. + * @param cbToRead How many bytes to read. + * @param pIoCtx I/O context associated with this request. + * @param pcbActuallyRead Pointer to returned number of bytes read. + */ + DECLR3CALLBACKMEMBER(int, pfnRead, (void *pBackendData, uint64_t uOffset, size_t cbToRead, + PVDIOCTX pIoCtx, size_t *pcbActuallyRead)); + + /** + * Start a write request. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param uOffset The offset of the virtual disk to write to. + * @param cbToWrite How many bytes to write. + * @param pIoCtx I/O context associated with this request. + * @param pcbWriteProcess Pointer to returned number of bytes that could + * be processed. In case the function returned + * VERR_VD_BLOCK_FREE this is the number of bytes + * that could be written in a full block write, + * when prefixed/postfixed by the appropriate + * amount of (previously read) padding data. + * @param pcbPreRead Pointer to the returned amount of data that must + * be prefixed to perform a full block write. + * @param pcbPostRead Pointer to the returned amount of data that must + * be postfixed to perform a full block write. + * @param fWrite Flags which affect write behavior. Combination + * of the VD_WRITE_* flags. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite, (void *pBackendData, uint64_t uOffset, size_t cbToWrite, + PVDIOCTX pIoCtx, + size_t *pcbWriteProcess, size_t *pcbPreRead, + size_t *pcbPostRead, unsigned fWrite)); + + /** + * Flush data to disk. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pIoCtx I/O context associated with this request. + */ + DECLR3CALLBACKMEMBER(int, pfnFlush, (void *pBackendData, PVDIOCTX pIoCtx)); + + /** + * Discards the given amount of bytes decreasing the size of the image if possible + * + * @returns VBox status code. + * @retval VERR_VD_DISCARD_ALIGNMENT_NOT_MET if the range doesn't meet the required alignment + * for the discard. + * @param pBackendData Opaque state data for this image. + * @param pIoCtx I/O context associated with this request. + * @param uOffset The offset of the first byte to discard. + * @param cbDiscard How many bytes to discard. + * @param pcbPreAllocated Pointer to the returned amount of bytes that must + * be discarded before the range to perform a full + * block discard. + * @param pcbPostAllocated Pointer to the returned amount of bytes that must + * be discarded after the range to perform a full + * block discard. + * @param pcbActuallyDiscarded Pointer to the returned amount of bytes which + * could be actually discarded. + * @param ppbmAllocationBitmap Where to store the pointer to the allocation bitmap + * if VERR_VD_DISCARD_ALIGNMENT_NOT_MET is returned or NULL + * if the allocation bitmap should be returned. + * @param fDiscard Flags which affect discard behavior. Combination + * of the VD_DISCARD_* flags. + */ + DECLR3CALLBACKMEMBER(int, pfnDiscard, (void *pBackendData, PVDIOCTX pIoCtx, + uint64_t uOffset, size_t cbDiscard, + size_t *pcbPreAllocated, + size_t *pcbPostAllocated, + size_t *pcbActuallyDiscarded, + void **ppbmAllocationBitmap, + unsigned fDiscard)); + + /** + * Get the version of a disk image. + * + * @returns version of disk image. + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(unsigned, pfnGetVersion, (void *pBackendData)); + + /** + * Get the file size of a disk image. + * + * @returns size of disk image in bytes. + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnGetFileSize, (void *pBackendData)); + + /** + * Get virtual disk PCHS geometry stored in a disk image. + * + * @returns VBox status code. + * @returns VERR_VD_GEOMETRY_NOT_SET if no geometry present in the image. + * @param pBackendData Opaque state data for this image. + * @param pPCHSGeometry Where to store the geometry. Not NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnGetPCHSGeometry, (void *pBackendData, PVDGEOMETRY pPCHSGeometry)); + + /** + * Set virtual disk PCHS geometry stored in a disk image. + * Only called if geometry is different than before. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pPCHSGeometry Where to load the geometry from. Not NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnSetPCHSGeometry, (void *pBackendData, PCVDGEOMETRY pPCHSGeometry)); + + /** + * Get virtual disk LCHS geometry stored in a disk image. + * + * @returns VBox status code. + * @returns VERR_VD_GEOMETRY_NOT_SET if no geometry present in the image. + * @param pBackendData Opaque state data for this image. + * @param pLCHSGeometry Where to store the geometry. Not NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnGetLCHSGeometry, (void *pBackendData, PVDGEOMETRY pLCHSGeometry)); + + /** + * Set virtual disk LCHS geometry stored in a disk image. + * Only called if geometry is different than before. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pLCHSGeometry Where to load the geometry from. Not NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnSetLCHSGeometry, (void *pBackendData, PCVDGEOMETRY pLCHSGeometry)); + + /** + * Returns a region list for the disk image if supported, optional. + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if region lists are not supported for this kind of image. + * @param pBackendData Opaque state data for this image. + * @param ppRegionList Where to store the pointer to the region list on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryRegions, (void *pBackendData, PCVDREGIONLIST *ppRegionList)); + + /** + * Releases the region list acquired with VDIMAGEBACKEND::pfnQueryRegions() before. + * + * @returns nothing. + * @param pBackendData Opaque state data for this image. + * @param pRegionList The region list to release. + */ + DECLR3CALLBACKMEMBER(void, pfnRegionListRelease, (void *pBackendData, PCVDREGIONLIST pRegionList)); + + /** + * Get the image flags of a disk image. + * + * @returns image flags of disk image (VD_IMAGE_FLAGS_XXX). + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(unsigned, pfnGetImageFlags, (void *pBackendData)); + + /** + * Get the open flags of a disk image. + * + * @returns open flags of disk image (VD_OPEN_FLAGS_XXX). + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(unsigned, pfnGetOpenFlags, (void *pBackendData)); + + /** + * Set the open flags of a disk image. + * + * May cause the image to be locked in a different mode or be reopened (which + * can fail). + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param uOpenFlags New open flags for this image (VD_OPEN_FLAGS_XXX). + */ + DECLR3CALLBACKMEMBER(int, pfnSetOpenFlags, (void *pBackendData, unsigned uOpenFlags)); + + /** + * Get comment of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pszComment Where to store the comment. + * @param cbComment Size of the comment buffer. + */ + DECLR3CALLBACKMEMBER(int, pfnGetComment, (void *pBackendData, char *pszComment, size_t cbComment)); + + /** + * Set comment of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pszComment Where to get the comment from. NULL resets comment. + * The comment is silently truncated if the image format + * limit is exceeded. + */ + DECLR3CALLBACKMEMBER(int, pfnSetComment, (void *pBackendData, const char *pszComment)); + + /** + * Get UUID of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to store the image UUID. + */ + DECLR3CALLBACKMEMBER(int, pfnGetUuid, (void *pBackendData, PRTUUID pUuid)); + + /** + * Set UUID of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to get the image UUID from. + */ + DECLR3CALLBACKMEMBER(int, pfnSetUuid, (void *pBackendData, PCRTUUID pUuid)); + + /** + * Get last modification UUID of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to store the image modification UUID. + */ + DECLR3CALLBACKMEMBER(int, pfnGetModificationUuid, (void *pBackendData, PRTUUID pUuid)); + + /** + * Set last modification UUID of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to get the image modification UUID from. + */ + DECLR3CALLBACKMEMBER(int, pfnSetModificationUuid, (void *pBackendData, PCRTUUID pUuid)); + + /** + * Get parent UUID of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to store the parent image UUID. + */ + DECLR3CALLBACKMEMBER(int, pfnGetParentUuid, (void *pBackendData, PRTUUID pUuid)); + + /** + * Set parent UUID of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to get the parent image UUID from. + */ + DECLR3CALLBACKMEMBER(int, pfnSetParentUuid, (void *pBackendData, PCRTUUID pUuid)); + + /** + * Get parent modification UUID of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to store the parent image modification UUID. + */ + DECLR3CALLBACKMEMBER(int, pfnGetParentModificationUuid, (void *pBackendData, PRTUUID pUuid)); + + /** + * Set parent modification UUID of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to get the parent image modification UUID from. + */ + DECLR3CALLBACKMEMBER(int, pfnSetParentModificationUuid, (void *pBackendData, PCRTUUID pUuid)); + + /** + * Dump information about a disk image. + * + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(void, pfnDump, (void *pBackendData)); + + /** + * Get a time stamp of a disk image. May be NULL. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pTimestamp Where to store the time stamp. + */ + DECLR3CALLBACKMEMBER(int, pfnGetTimestamp, (void *pBackendData, PRTTIMESPEC pTimestamp)); + + /** + * Get the parent time stamp of a disk image. May be NULL. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pTimestamp Where to store the time stamp. + */ + DECLR3CALLBACKMEMBER(int, pfnGetParentTimestamp, (void *pBackendData, PRTTIMESPEC pTimestamp)); + + /** + * Set the parent time stamp of a disk image. May be NULL. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pTimestamp Where to get the time stamp from. + */ + DECLR3CALLBACKMEMBER(int, pfnSetParentTimestamp, (void *pBackendData, PCRTTIMESPEC pTimestamp)); + + /** + * Get the relative path to parent image. May be NULL. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param ppszParentFilename Where to store the path. + */ + DECLR3CALLBACKMEMBER(int, pfnGetParentFilename, (void *pBackendData, char **ppszParentFilename)); + + /** + * Set the relative path to parent image. May be NULL. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pszParentFilename Where to get the path from. + */ + DECLR3CALLBACKMEMBER(int, pfnSetParentFilename, (void *pBackendData, const char *pszParentFilename)); + + /** Returns a human readable hard disk location string given a + * set of hard disk configuration keys. The returned string is an + * equivalent of the full file path for image-based hard disks. + * Mandatory for backends with no VD_CAP_FILE and NULL otherwise. */ + DECLR3CALLBACKMEMBER(int, pfnComposeLocation, (PVDINTERFACE pConfig, char **pszLocation)); + + /** Returns a human readable hard disk name string given a + * set of hard disk configuration keys. The returned string is an + * equivalent of the file name part in the full file path for + * image-based hard disks. Mandatory for backends with no + * VD_CAP_FILE and NULL otherwise. */ + DECLR3CALLBACKMEMBER(int, pfnComposeName, (PVDINTERFACE pConfig, char **pszName)); + + /** + * Compact the image. The pointer may be NULL, indicating that this + * isn't supported yet (for file-based images) or not necessary. + * + * @returns VBox status code. + * @returns VERR_NOT_SUPPORTED if this image cannot be compacted yet. + * @param pBackendData Opaque state data for this image. + * @param uPercentStart Starting value for progress percentage. + * @param uPercentSpan Span for varying progress percentage. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ + DECLR3CALLBACKMEMBER(int, pfnCompact, (void *pBackendData, + unsigned uPercentStart, unsigned uPercentSpan, + PVDINTERFACE pVDIfsDisk, + PVDINTERFACE pVDIfsImage, + PVDINTERFACE pVDIfsOperation)); + + /** + * Resize the image. The pointer may be NULL, indicating that this + * isn't supported yet (for file-based images) or not necessary. + * + * @returns VBox status code. + * @returns VERR_NOT_SUPPORTED if this image cannot be resized yet. + * @param pBackendData Opaque state data for this image. + * @param cbSize New size of the image. + * @param pPCHSGeometry Pointer to the new physical disk geometry <= (16383,16,63). Not NULL. + * @param pLCHSGeometry Pointer to the new logical disk geometry <= (x,255,63). Not NULL. + * @param uPercentStart Starting value for progress percentage. + * @param uPercentSpan Span for varying progress percentage. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ + DECLR3CALLBACKMEMBER(int, pfnResize, (void *pBackendData, + uint64_t cbSize, + PCVDGEOMETRY pPCHSGeometry, + PCVDGEOMETRY pLCHSGeometry, + unsigned uPercentStart, unsigned uPercentSpan, + PVDINTERFACE pVDIfsDisk, + PVDINTERFACE pVDIfsImage, + PVDINTERFACE pVDIfsOperation)); + + /** + * Try to repair the given image. + * + * @returns VBox status code. + * @param pszFilename Name of the image file. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param fFlags Combination of the VD_REPAIR_* flags. + */ + DECLR3CALLBACKMEMBER(int, pfnRepair, (const char *pszFilename, PVDINTERFACE pVDIfsDisk, + PVDINTERFACE pVDIfsImage, uint32_t fFlags)); + + /** + * Traverse all metadata of the opened image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param fFlags Traverse flags, combination of VD_TRAVERSE_METDATA_* defines. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ + DECLR3CALLBACKMEMBER(int, pfnTraverseMetadata, (void *pBackendData, uint32_t fFlags, + PVDINTERFACE pVDIfsDisk, + PVDINTERFACE pVDIfsImage, + PVDINTERFACE pVDIfsOperation)); + + /** Initialization safty marker. */ + uint32_t u32VersionEnd; + +} VDIMAGEBACKEND; + +/** Pointer to VD backend. */ +typedef VDIMAGEBACKEND *PVDIMAGEBACKEND; +/** Constant pointer to VD backend. */ +typedef const VDIMAGEBACKEND *PCVDIMAGEBACKEND; + +/** The current version of the VDIMAGEBACKEND structure. */ +#define VD_IMGBACKEND_VERSION VD_VERSION_MAKE(0xff01, 3, 0) + +/** @copydoc VDIMAGEBACKEND::pfnComposeLocation */ +DECLCALLBACK(int) genericFileComposeLocation(PVDINTERFACE pConfig, char **pszLocation); +/** @copydoc VDIMAGEBACKEND::pfnComposeName */ +DECLCALLBACK(int) genericFileComposeName(PVDINTERFACE pConfig, char **pszName); + +#endif /* !VBOX_INCLUDED_vd_image_backend_h */ diff --git a/include/VBox/vd-plugin.h b/include/VBox/vd-plugin.h new file mode 100644 index 00000000..f165f1cf --- /dev/null +++ b/include/VBox/vd-plugin.h @@ -0,0 +1,106 @@ +/** @file + * VD: Plugin support API. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vd_plugin_h +#define VBOX_INCLUDED_vd_plugin_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vd.h> +#include <VBox/vd-common.h> +#include <VBox/vd-image-backend.h> +#include <VBox/vd-cache-backend.h> +#include <VBox/vd-filter-backend.h> + +/** + * Backend register callbacks structure. + */ +typedef struct VDBACKENDREGISTER +{ + /** Interface version. + * This is set to VD_BACKENDREG_CB_VERSION. */ + uint32_t u32Version; + + /** + * Registers a new image backend. + * + * @returns VBox status code. + * @param pvUser Opaque user data given in the plugin load callback. + * @param pBackend The image backend to register. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterImage, (void *pvUser, PCVDIMAGEBACKEND pBackend)); + + /** + * Registers a new cache backend. + * + * @returns VBox status code. + * @param pvUser Opaque user data given in the plugin load callback. + * @param pBackend The cache backend to register. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterCache, (void *pvUser, PCVDCACHEBACKEND pBackend)); + + /** + * Registers a new filter plugin. + * @param pvUser Opaque user data given in the plugin load callback. + * @param pBackend The filter backend to register. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterFilter, (void *pvUser, PCVDFILTERBACKEND pBackend)); + +} VDBACKENDREGISTER; +/** Pointer to a backend register callbacks structure. */ +typedef VDBACKENDREGISTER *PVDBACKENDREGISTER; + +/** Current version of the VDBACKENDREGISTER structure. */ +#define VD_BACKENDREG_CB_VERSION VD_VERSION_MAKE(0xff00, 1, 0) + +/** + * Initialization entry point called by the generic VD layer when + * a plugin is loaded. + * + * @returns VBox status code. + * @param pvUser Opaque user data passed in the register callbacks. + * @param pRegisterCallbacks Pointer to the register callbacks structure. + */ +typedef DECLCALLBACKTYPE(int, FNVDPLUGINLOAD,(void *pvUser, PVDBACKENDREGISTER pRegisterCallbacks)); +typedef FNVDPLUGINLOAD *PFNVDPLUGINLOAD; +#define VD_PLUGIN_LOAD_NAME "VDPluginLoad" + +/** The prefix to identify Storage Plugins. */ +#define VD_PLUGIN_PREFIX "VDPlugin" +/** The size of the prefix excluding the '\\0' terminator. */ +#define VD_PLUGIN_PREFIX_LENGTH (sizeof(VD_PLUGIN_PREFIX)-1) + +#endif /* !VBOX_INCLUDED_vd_plugin_h */ diff --git a/include/VBox/vd.h b/include/VBox/vd.h new file mode 100644 index 00000000..7013846e --- /dev/null +++ b/include/VBox/vd.h @@ -0,0 +1,1847 @@ +/** @file + * VBox HDD Container API. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vd_h +#define VBOX_INCLUDED_vd_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assert.h> +#include <iprt/string.h> +#include <iprt/mem.h> +#include <iprt/file.h> +#include <iprt/net.h> +#include <iprt/sg.h> +#include <iprt/vfs.h> +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <VBox/vdmedia.h> +#include <VBox/vd-ifs.h> + +RT_C_DECLS_BEGIN + +#ifdef IN_RING0 +# error "There are no VBox HDD Container APIs available in Ring-0 Host Context!" +#endif + +/** @defgroup grp_vd Virtual Disk Container + * @{ + */ + +/** Current VMDK image version. */ +#define VMDK_IMAGE_VERSION (0x0001) + +/** Current VDI image major version. */ +#define VDI_IMAGE_VERSION_MAJOR (0x0001) +/** Current VDI image minor version. */ +#define VDI_IMAGE_VERSION_MINOR (0x0001) +/** Current VDI image version. */ +#define VDI_IMAGE_VERSION ((VDI_IMAGE_VERSION_MAJOR << 16) | VDI_IMAGE_VERSION_MINOR) + +/** Get VDI major version from combined version. */ +#define VDI_GET_VERSION_MAJOR(uVer) ((uVer) >> 16) +/** Get VDI minor version from combined version. */ +#define VDI_GET_VERSION_MINOR(uVer) ((uVer) & 0xffff) + +/** Placeholder for specifying the last opened image. */ +#define VD_LAST_IMAGE 0xffffffffU + +/** Placeholder for VDCopyEx to indicate that the image content is unknown. */ +#define VD_IMAGE_CONTENT_UNKNOWN 0xffffffffU + +/** @name VBox HDD container image flags + * Same values as MediumVariant API enum. + * @{ + */ +/** No flags. */ +#define VD_IMAGE_FLAGS_NONE (0) +/** Fixed image. */ +#define VD_IMAGE_FLAGS_FIXED (0x10000) +/** Diff image. Mutually exclusive with fixed image. */ +#define VD_IMAGE_FLAGS_DIFF (0x20000) +/** VMDK: Split image into 2GB extents. */ +#define VD_VMDK_IMAGE_FLAGS_SPLIT_2G (0x0001) +/** VMDK: Raw disk image (giving access to a number of host partitions). */ +#define VD_VMDK_IMAGE_FLAGS_RAWDISK (0x0002) +/** VMDK: stream optimized image, read only. */ +#define VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED (0x0004) +/** VMDK: ESX variant, use in addition to other flags. */ +#define VD_VMDK_IMAGE_FLAGS_ESX (0x0008) +/** VDI: Fill new blocks with zeroes while expanding image file. Only valid + * for newly created images, never set for opened existing images. */ +#define VD_VDI_IMAGE_FLAGS_ZERO_EXPAND (0x0100) + +/** Mask of valid image flags for VMDK. */ +#define VD_VMDK_IMAGE_FLAGS_MASK ( VD_IMAGE_FLAGS_FIXED | VD_IMAGE_FLAGS_DIFF | VD_IMAGE_FLAGS_NONE \ + | VD_VMDK_IMAGE_FLAGS_SPLIT_2G | VD_VMDK_IMAGE_FLAGS_RAWDISK \ + | VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED | VD_VMDK_IMAGE_FLAGS_ESX) + +/** Mask of valid image flags for VDI. */ +#define VD_VDI_IMAGE_FLAGS_MASK (VD_IMAGE_FLAGS_FIXED | VD_IMAGE_FLAGS_DIFF | VD_IMAGE_FLAGS_NONE | VD_VDI_IMAGE_FLAGS_ZERO_EXPAND) + +/** Mask of all valid image flags for all formats. */ +#define VD_IMAGE_FLAGS_MASK (VD_VMDK_IMAGE_FLAGS_MASK | VD_VDI_IMAGE_FLAGS_MASK) + +/** Default image flags. */ +#define VD_IMAGE_FLAGS_DEFAULT (VD_IMAGE_FLAGS_NONE) +/** @} */ + +/** @name VD image repair flags + * @{ + */ +/** Don't repair the image but check what needs to be done. */ +#define VD_REPAIR_DRY_RUN RT_BIT_32(0) + +/** Mask of all valid repair flags. */ +#define VD_REPAIR_FLAGS_MASK (VD_REPAIR_DRY_RUN) +/** @} */ + +/** @name VD image VFS file flags + * @{ + */ +/** Destroy the VD disk container when the VFS file is released. */ +#define VD_VFSFILE_DESTROY_ON_RELEASE RT_BIT_32(0) + +/** Mask of all valid repair flags. */ +#define VD_VFSFILE_FLAGS_MASK (VD_VFSFILE_DESTROY_ON_RELEASE) +/** @} */ + +/** @name VDISKRAW_XXX - VBox raw disk or partition flags + * @{ + */ +/** No special treatment. */ +#define VDISKRAW_NORMAL 0 +/** Whether this is a raw disk (where the partition information is ignored) or + * not. Valid only in the raw disk descriptor. */ +#define VDISKRAW_DISK RT_BIT(0) +/** Open the corresponding raw disk or partition for reading only, no matter + * how the image is created or opened. */ +#define VDISKRAW_READONLY RT_BIT(1) +/** @} */ + +/** + * Auxiliary type for describing partitions on raw disks. + * + * The entries must be in ascending order (as far as uStart is concerned), and + * must not overlap. Note that this does not correspond 1:1 to partitions, it is + * describing the general meaning of contiguous areas on the disk. + */ +typedef struct VDISKRAWPARTDESC +{ + /** Device to use for this partition/data area. Can be the disk device if + * the offset field is set appropriately. If this is NULL, then this + * partition will not be accessible to the guest. The size of the data area + * must still be set correctly. */ + char *pszRawDevice; + /** Pointer to the partitioning info. NULL means this is a regular data + * area on disk, non-NULL denotes data which should be copied to the + * partition data overlay. */ + void *pvPartitionData; + /** Offset where the data starts in this device. */ + uint64_t offStartInDevice; + /** Offset where the data starts in the disk. */ + uint64_t offStartInVDisk; + /** Size of the data area. */ + uint64_t cbData; + /** Flags for special treatment, see VDISKRAW_XXX. */ + uint32_t uFlags; +} VDISKRAWPARTDESC, *PVDISKRAWPARTDESC; + +/** + * Auxiliary data structure for difference between GPT and MBR disks. + */ +typedef enum VDISKPARTTYPE +{ + VDISKPARTTYPE_MBR = 0, + VDISKPARTTYPE_GPT +} VDISKPARTTYPE; + +/** + * Auxiliary data structure for creating raw disks. + */ +typedef struct VDISKRAW +{ + /** Signature for structure. Must be 'R', 'A', 'W', '\\0'. Actually a trick + * to make logging of the comment string produce sensible results. */ + char szSignature[4]; + /** Flags for special treatment, see VDISKRAW_XXX. */ + uint32_t uFlags; + /** Filename for the raw disk. Ignored for partitioned raw disks. + * For Linux e.g. /dev/sda, and for Windows e.g. //./PhysicalDisk0. */ + char *pszRawDisk; + /** Partitioning type of the disk */ + VDISKPARTTYPE enmPartitioningType; + /** Number of entries in the partition descriptor array. */ + uint32_t cPartDescs; + /** Pointer to the partition descriptor array. */ + PVDISKRAWPARTDESC pPartDescs; +} VDISKRAW, *PVDISKRAW; + + +/** @name VBox HDD container image open mode flags + * @{ + */ +/** Try to open image in read/write exclusive access mode if possible, or in read-only elsewhere. */ +#define VD_OPEN_FLAGS_NORMAL 0 +/** Open image in read-only mode with sharing access with others. */ +#define VD_OPEN_FLAGS_READONLY RT_BIT(0) +/** Honor zero block writes instead of ignoring them whenever possible. + * This is not supported by all formats. It is silently ignored in this case. */ +#define VD_OPEN_FLAGS_HONOR_ZEROES RT_BIT(1) +/** Honor writes of the same data instead of ignoring whenever possible. + * This is handled generically, and is only meaningful for differential image + * formats. It is silently ignored otherwise. */ +#define VD_OPEN_FLAGS_HONOR_SAME RT_BIT(2) +/** Do not perform the base/diff image check on open. This does NOT imply + * opening the image as readonly (would break e.g. adding UUIDs to VMDK files + * created by other products). Images opened with this flag should only be + * used for querying information, and nothing else. */ +#define VD_OPEN_FLAGS_INFO RT_BIT(3) +/** Open image for asynchronous access. Only available if VD_CAP_ASYNC_IO is + * set. VDOpen fails with VERR_NOT_SUPPORTED if this operation is not supported for + * this kind of image. */ +#define VD_OPEN_FLAGS_ASYNC_IO RT_BIT(4) +/** Allow sharing of the image for writable images. May be ignored if the + * format backend doesn't support this type of concurrent access. */ +#define VD_OPEN_FLAGS_SHAREABLE RT_BIT(5) +/** Ask the backend to switch to sequential accesses if possible. Opening + * will not fail if it cannot do this, the flag will be simply ignored. */ +#define VD_OPEN_FLAGS_SEQUENTIAL RT_BIT(6) +/** Allow the discard operation if supported. Only available if VD_CAP_DISCARD + * is set. VDOpen fails with VERR_VD_DISCARD_NOT_SUPPORTED if discarding is not + * supported. */ +#define VD_OPEN_FLAGS_DISCARD RT_BIT(7) +/** Ignore all flush requests to workaround certain filesystems which are slow + * when writing a lot of cached data to the medium. + * Use with extreme care as a host crash can result in completely corrupted and + * unusable images. + */ +#define VD_OPEN_FLAGS_IGNORE_FLUSH RT_BIT(8) +/** + * Return VINF_VD_NEW_ZEROED_BLOCK for reads from unallocated blocks. + * The caller who uses the flag has to make sure that the read doesn't cross + * a block boundary. Because the block size can differ between images reading one + * sector at a time is the safest solution. + */ +#define VD_OPEN_FLAGS_INFORM_ABOUT_ZERO_BLOCKS RT_BIT(9) +/** + * Don't do unnecessary consistency checks when opening the image. + * Only valid when the image is opened in readonly because inconsistencies + * can lead to corrupted images in read-write mode. + */ +#define VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS RT_BIT(10) +/** Mask of valid flags. */ +#define VD_OPEN_FLAGS_MASK (VD_OPEN_FLAGS_NORMAL | VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_HONOR_ZEROES | VD_OPEN_FLAGS_HONOR_SAME | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_DISCARD | VD_OPEN_FLAGS_IGNORE_FLUSH | VD_OPEN_FLAGS_INFORM_ABOUT_ZERO_BLOCKS | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS) +/** @}*/ + +/** @name VBox HDD container filter flags + * @{ + */ +/** The filter is applied during writes. */ +#define VD_FILTER_FLAGS_WRITE RT_BIT(0) +/** The filter is applied during reads. */ +#define VD_FILTER_FLAGS_READ RT_BIT(1) +/** Open the filter in info mode. */ +#define VD_FILTER_FLAGS_INFO RT_BIT(2) +/** Default set of filter flags. */ +#define VD_FILTER_FLAGS_DEFAULT (VD_FILTER_FLAGS_WRITE | VD_FILTER_FLAGS_READ) +/** Mask of valid flags. */ +#define VD_FILTER_FLAGS_MASK (VD_FILTER_FLAGS_WRITE | VD_FILTER_FLAGS_READ | VD_FILTER_FLAGS_INFO) +/** @} */ + +/** + * Helper functions to handle open flags. + */ + +/** + * Translate VD_OPEN_FLAGS_* to RTFile open flags. + * + * @return RTFile open flags. + * @param fOpenFlags VD_OPEN_FLAGS_* open flags. + * @param fCreate Flag that the file should be created. + */ +DECLINLINE(uint32_t) VDOpenFlagsToFileOpenFlags(unsigned fOpenFlags, bool fCreate) +{ + uint32_t fOpen; + AssertMsg(!(fOpenFlags & VD_OPEN_FLAGS_READONLY) || !fCreate, ("Image can't be opened readonly while being created\n")); + + if (fOpenFlags & VD_OPEN_FLAGS_READONLY) + fOpen = RTFILE_O_READ | RTFILE_O_DENY_NONE; + else + { + fOpen = RTFILE_O_READWRITE; + + if (fOpenFlags & VD_OPEN_FLAGS_SHAREABLE) + fOpen |= RTFILE_O_DENY_NONE; + else + fOpen |= RTFILE_O_DENY_WRITE; + } + + if (!fCreate) + fOpen |= RTFILE_O_OPEN; + else + fOpen |= RTFILE_O_CREATE | RTFILE_O_NOT_CONTENT_INDEXED; + + return fOpen; +} + + +/** @name VBox HDD container backend capability flags + * @{ + */ +/** Supports UUIDs as expected by VirtualBox code. */ +#define VD_CAP_UUID RT_BIT(0) +/** Supports creating fixed size images, allocating all space instantly. */ +#define VD_CAP_CREATE_FIXED RT_BIT(1) +/** Supports creating dynamically growing images, allocating space on demand. */ +#define VD_CAP_CREATE_DYNAMIC RT_BIT(2) +/** Supports creating images split in chunks of a bit less than 2GBytes. */ +#define VD_CAP_CREATE_SPLIT_2G RT_BIT(3) +/** Supports being used as differencing image format backend. */ +#define VD_CAP_DIFF RT_BIT(4) +/** Supports asynchronous I/O operations for at least some configurations. */ +#define VD_CAP_ASYNC RT_BIT(5) +/** The backend operates on files. The caller needs to know to handle the + * location appropriately. */ +#define VD_CAP_FILE RT_BIT(6) +/** The backend uses the config interface. The caller needs to know how to + * provide the mandatory configuration parts this way. */ +#define VD_CAP_CONFIG RT_BIT(7) +/** The backend uses the network stack interface. The caller has to provide + * the appropriate interface. */ +#define VD_CAP_TCPNET RT_BIT(8) +/** The backend supports VFS (virtual filesystem) functionality since it uses + * VDINTERFACEIO exclusively for all file operations. */ +#define VD_CAP_VFS RT_BIT(9) +/** The backend supports the discard operation. */ +#define VD_CAP_DISCARD RT_BIT(10) +/** This is a frequently used backend. */ +#define VD_CAP_PREFERRED RT_BIT(11) +/** @}*/ + +/** @name Configuration interface key handling flags. + * @{ + */ +/** Mandatory config key. Not providing a value for this key will cause + * the backend to fail. */ +#define VD_CFGKEY_MANDATORY RT_BIT(0) +/** Expert config key. Not showing it by default in the GUI is is probably + * a good idea, as the average user won't understand it easily. */ +#define VD_CFGKEY_EXPERT RT_BIT(1) +/** Key only need at media creation, not to be retained in registry. + * Should not be exposed in the GUI */ +#define VD_CFGKEY_CREATEONLY RT_BIT(2) +/** @}*/ + + +/** + * Configuration value type for configuration information interface. + */ +typedef enum VDCFGVALUETYPE +{ + /** Integer value. */ + VDCFGVALUETYPE_INTEGER = 1, + /** String value. */ + VDCFGVALUETYPE_STRING, + /** Bytestring value. */ + VDCFGVALUETYPE_BYTES +} VDCFGVALUETYPE; + + +/** + * Structure describing configuration keys required/supported by a backend + * through the config interface. + */ +typedef struct VDCONFIGINFO +{ + /** Key name of the configuration. */ + const char *pszKey; + /** Pointer to default value (descriptor). NULL if no useful default value + * can be specified. */ + const char *pszDefaultValue; + /** Value type for this key. */ + VDCFGVALUETYPE enmValueType; + /** Key handling flags (a combination of VD_CFGKEY_* flags). */ + uint64_t uKeyFlags; +} VDCONFIGINFO; + +/** Pointer to structure describing configuration keys. */ +typedef VDCONFIGINFO *PVDCONFIGINFO; + +/** Pointer to const structure describing configuration keys. */ +typedef const VDCONFIGINFO *PCVDCONFIGINFO; + +/** + * Structure describing a file extension. + */ +typedef struct VDFILEEXTENSION +{ + /** Pointer to the NULL-terminated string containing the extension. */ + const char *pszExtension; + /** The device type the extension supports. */ + VDTYPE enmType; +} VDFILEEXTENSION; + +/** Pointer to a structure describing a file extension. */ +typedef VDFILEEXTENSION *PVDFILEEXTENSION; + +/** Pointer to a const structure describing a file extension. */ +typedef const VDFILEEXTENSION *PCVDFILEEXTENSION; + +/** + * Data structure for returning a list of backend capabilities. + */ +typedef struct VDBACKENDINFO +{ + /** Name of the backend. Must be unique even with case insensitive comparison. */ + const char *pszBackend; + /** Capabilities of the backend (a combination of the VD_CAP_* flags). */ + uint64_t uBackendCaps; + /** Pointer to a NULL-terminated array of strings, containing the supported + * file extensions. Note that some backends do not work on files, so this + * pointer may just contain NULL. */ + PCVDFILEEXTENSION paFileExtensions; + /** Pointer to an array of structs describing each supported config key. + * Terminated by a NULL config key. Note that some backends do not support + * the configuration interface, so this pointer may just contain NULL. + * Mandatory if the backend sets VD_CAP_CONFIG. */ + PCVDCONFIGINFO paConfigInfo; + /** Returns a human readable hard disk location string given a + * set of hard disk configuration keys. The returned string is an + * equivalent of the full file path for image-based hard disks. + * Mandatory for backends with no VD_CAP_FILE and NULL otherwise. */ + DECLR3CALLBACKMEMBER(int, pfnComposeLocation, (PVDINTERFACE pConfig, char **pszLocation)); + /** Returns a human readable hard disk name string given a + * set of hard disk configuration keys. The returned string is an + * equivalent of the file name part in the full file path for + * image-based hard disks. Mandatory for backends with no + * VD_CAP_FILE and NULL otherwise. */ + DECLR3CALLBACKMEMBER(int, pfnComposeName, (PVDINTERFACE pConfig, char **pszName)); +} VDBACKENDINFO, *PVDBACKENDINFO; + +/** + * Data structure for returning a list of filter capabilities. + */ +typedef struct VDFILTERINFO +{ + /** Name of the filter. Must be unique even with case insensitive comparison. */ + const char *pszFilter; + /** Pointer to an array of structs describing each supported config key. + * Terminated by a NULL config key. Note that some filters do not support + * the configuration interface, so this pointer may just contain NULL. */ + PCVDCONFIGINFO paConfigInfo; +} VDFILTERINFO, *PVDFILTERINFO; + + +/** + * Request completion callback for the async read/write API. + */ +typedef DECLCALLBACKTYPE(void, FNVDASYNCTRANSFERCOMPLETE,(void *pvUser1, void *pvUser2, int rcReq)); +/** Pointer to a transfer compelte callback. */ +typedef FNVDASYNCTRANSFERCOMPLETE *PFNVDASYNCTRANSFERCOMPLETE; + +/** + * VD Container main structure. + */ +/* Forward declaration, VDISK structure is visible only inside VD module. */ +struct VDISK; +typedef struct VDISK VDISK; +typedef VDISK *PVDISK; + +/** + * Initializes HDD backends. + * + * @returns VBox status code. + */ +VBOXDDU_DECL(int) VDInit(void); + +/** + * Destroys loaded HDD backends. + * + * @returns VBox status code. + */ +VBOXDDU_DECL(int) VDShutdown(void); + +/** + * Loads a single plugin given by filename. + * + * @returns VBox status code. + * @param pszFilename The plugin filename to load. + */ +VBOXDDU_DECL(int) VDPluginLoadFromFilename(const char *pszFilename); + +/** + * Load all plugins from a given path. + * + * @returns VBox statuse code. + * @param pszPath The path to load plugins from. + */ +VBOXDDU_DECL(int) VDPluginLoadFromPath(const char *pszPath); + +/** + * Unloads a single plugin given by filename. + * + * @returns VBox status code. + * @param pszFilename The plugin filename to unload. + */ +VBOXDDU_DECL(int) VDPluginUnloadFromFilename(const char *pszFilename); + +/** + * Unload all plugins from a given path. + * + * @returns VBox statuse code. + * @param pszPath The path to unload plugins from. + */ +VBOXDDU_DECL(int) VDPluginUnloadFromPath(const char *pszPath); + +/** + * Lists all HDD backends and their capabilities in a caller-provided buffer. + * + * @return VBox status code. + * VERR_BUFFER_OVERFLOW if not enough space is passed. + * @param cEntriesAlloc Number of list entries available. + * @param pEntries Pointer to array for the entries. + * @param pcEntriesUsed Number of entries returned. + */ +VBOXDDU_DECL(int) VDBackendInfo(unsigned cEntriesAlloc, PVDBACKENDINFO pEntries, + unsigned *pcEntriesUsed); + +/** + * Lists the capabilities of a backend identified by its name. + * + * @return VBox status code. + * @param pszBackend The backend name (case insensitive). + * @param pEntry Pointer to an entry. + */ +VBOXDDU_DECL(int) VDBackendInfoOne(const char *pszBackend, PVDBACKENDINFO pEntry); + +/** + * Lists all filters and their capabilities in a caller-provided buffer. + * + * @return VBox status code. + * VERR_BUFFER_OVERFLOW if not enough space is passed. + * @param cEntriesAlloc Number of list entries available. + * @param pEntries Pointer to array for the entries. + * @param pcEntriesUsed Number of entries returned. + */ +VBOXDDU_DECL(int) VDFilterInfo(unsigned cEntriesAlloc, PVDFILTERINFO pEntries, + unsigned *pcEntriesUsed); + +/** + * Lists the capabilities of a filter identified by its name. + * + * @return VBox status code. + * @param pszFilter The filter name (case insensitive). + * @param pEntry Pointer to an entry. + */ +VBOXDDU_DECL(int) VDFilterInfoOne(const char *pszFilter, PVDFILTERINFO pEntry); + +/** + * Allocates and initializes an empty HDD container. + * No image files are opened. + * + * @return VBox status code. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param enmType Type of the image container. + * @param ppDisk Where to store the reference to HDD container. + */ +VBOXDDU_DECL(int) VDCreate(PVDINTERFACE pVDIfsDisk, VDTYPE enmType, PVDISK *ppDisk); + +/** + * Destroys HDD container. + * If container has opened image files they will be closed. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + */ +VBOXDDU_DECL(int) VDDestroy(PVDISK pDisk); + +/** + * Try to get the backend name which can use this image. + * + * @return VBox status code. + * VINF_SUCCESS if a plugin was found. + * ppszFormat contains the string which can be used as backend name. + * VERR_NOT_SUPPORTED if no backend was found. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pszFilename Name of the image file for which the backend is queried. + * @param enmDesiredType The desired image type, VDTYPE_INVALID if anything goes. + * @param ppszFormat Receives pointer of the UTF-8 string which contains the format name. + * The returned pointer must be freed using RTStrFree(). + * @param penmType Where to store the type of the image. + */ +VBOXDDU_DECL(int) VDGetFormat(PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage, + const char *pszFilename, VDTYPE enmDesiredType, + char **ppszFormat, VDTYPE *penmType); + +/** + * Opens an image file. + * + * The first opened image file in HDD container must have a base image type, + * others (next opened images) must be differencing or undo images. + * Linkage is checked for differencing image to be consistent with the previously opened image. + * When another differencing image is opened and the last image was opened in read/write access + * mode, then the last image is reopened in read-only with deny write sharing mode. This allows + * other processes to use images in read-only mode too. + * + * Note that the image is opened in read-only mode if a read/write open is not possible. + * Use VDIsReadOnly to check open mode. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + * @param pszBackend Name of the image file backend to use (case insensitive). + * @param pszFilename Name of the image file to open. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param pVDIfsImage Pointer to the per-image VD interface list. + */ +VBOXDDU_DECL(int) VDOpen(PVDISK pDisk, const char *pszBackend, + const char *pszFilename, unsigned uOpenFlags, + PVDINTERFACE pVDIfsImage); + +/** + * Opens a cache image. + * + * @return VBox status code. + * @param pDisk Pointer to the HDD container which should use the cache image. + * @param pszBackend Name of the cache file backend to use (case insensitive). + * @param pszFilename Name of the cache image to open. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param pVDIfsCache Pointer to the per-cache VD interface list. + */ +VBOXDDU_DECL(int) VDCacheOpen(PVDISK pDisk, const char *pszBackend, + const char *pszFilename, unsigned uOpenFlags, + PVDINTERFACE pVDIfsCache); + +/** + * Adds a filter to the disk. + * + * @returns VBox status code. + * @param pDisk Pointer to the HDD container which should use the filter. + * @param pszFilter Name of the filter backend to use (case insensitive). + * @param fFlags Flags which apply to the filter, combination of VD_FILTER_FLAGS_* + * defines. + * @param pVDIfsFilter Pointer to the per-filter VD interface list. + */ +VBOXDDU_DECL(int) VDFilterAdd(PVDISK pDisk, const char *pszFilter, uint32_t fFlags, + PVDINTERFACE pVDIfsFilter); + +/** + * Creates and opens a new base image file. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + * @param pszBackend Name of the image file backend to use (case insensitive). + * @param pszFilename Name of the image file to create. + * @param cbSize Image size in bytes. + * @param uImageFlags Flags specifying special image features. + * @param pszComment Pointer to image comment. NULL is ok. + * @param pPCHSGeometry Pointer to physical disk geometry <= (16383,16,63). Not NULL. + * @param pLCHSGeometry Pointer to logical disk geometry <= (x,255,63). Not NULL. + * @param pUuid New UUID of the image. If NULL, a new UUID is created. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ +VBOXDDU_DECL(int) VDCreateBase(PVDISK pDisk, const char *pszBackend, + const char *pszFilename, uint64_t cbSize, + unsigned uImageFlags, const char *pszComment, + PCVDGEOMETRY pPCHSGeometry, + PCVDGEOMETRY pLCHSGeometry, + PCRTUUID pUuid, unsigned uOpenFlags, + PVDINTERFACE pVDIfsImage, + PVDINTERFACE pVDIfsOperation); + +/** + * Creates and opens a new differencing image file in HDD container. + * See comments for VDOpen function about differencing images. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + * @param pszBackend Name of the image file backend to use (case insensitive). + * @param pszFilename Name of the differencing image file to create. + * @param uImageFlags Flags specifying special image features. + * @param pszComment Pointer to image comment. NULL is ok. + * @param pUuid New UUID of the image. If NULL, a new UUID is created. + * @param pParentUuid New parent UUID of the image. If NULL, the UUID is queried automatically. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ +VBOXDDU_DECL(int) VDCreateDiff(PVDISK pDisk, const char *pszBackend, + const char *pszFilename, unsigned uImageFlags, + const char *pszComment, PCRTUUID pUuid, + PCRTUUID pParentUuid, unsigned uOpenFlags, + PVDINTERFACE pVDIfsImage, + PVDINTERFACE pVDIfsOperation); + +/** + * Creates and opens new cache image file in HDD container. + * + * @return VBox status code. + * @param pDisk Name of the cache file backend to use (case insensitive). + * @param pszBackend Name of the image file backend to use (case insensitive). + * @param pszFilename Name of the differencing cache file to create. + * @param cbSize Maximum size of the cache. + * @param uImageFlags Flags specifying special cache features. + * @param pszComment Pointer to image comment. NULL is ok. + * @param pUuid New UUID of the image. If NULL, a new UUID is created. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param pVDIfsCache Pointer to the per-cache VD interface list. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ +VBOXDDU_DECL(int) VDCreateCache(PVDISK pDisk, const char *pszBackend, + const char *pszFilename, uint64_t cbSize, + unsigned uImageFlags, const char *pszComment, + PCRTUUID pUuid, unsigned uOpenFlags, + PVDINTERFACE pVDIfsCache, PVDINTERFACE pVDIfsOperation); + +/** + * Merges two images (not necessarily with direct parent/child relationship). + * As a side effect the source image and potentially the other images which + * are also merged to the destination are deleted from both the disk and the + * images in the HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImageFrom Image number to merge from, counts from 0. 0 is always base image of container. + * @param nImageTo Image number to merge to, counts from 0. 0 is always base image of container. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ +VBOXDDU_DECL(int) VDMerge(PVDISK pDisk, unsigned nImageFrom, + unsigned nImageTo, PVDINTERFACE pVDIfsOperation); + +/** + * Copies an image from one HDD container to another - extended version. + * + * The copy is opened in the target HDD container. It is possible to convert + * between different image formats, because the backend for the destination may + * be different from the source. If both the source and destination reference + * the same HDD container, then the image is moved (by copying/deleting or + * renaming) to the new location. The source container is unchanged if the move + * operation fails, otherwise the image at the new location is opened in the + * same way as the old one was. + * + * @note The read/write accesses across disks are not synchronized, just the + * accesses to each disk. Once there is a use case which requires a defined + * read/write behavior in this situation this needs to be extended. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * + * @param pDiskFrom Pointer to source HDD container. + * @param nImage Image number, counts from 0. 0 is always base image + * of container. + * @param pDiskTo Pointer to destination HDD container. + * @param pszBackend Name of the image file backend to use (may be NULL + * to use the same as the source, case insensitive). + * @param pszFilename New name of the image (may be NULL to specify that + * the copy destination is the destination container, + * or if pDiskFrom == pDiskTo, i.e. when moving). + * @param fMoveByRename If true, attempt to perform a move by renaming (if + * successful the new size is ignored). + * @param cbSize New image size (0 means leave unchanged). + * @param nImageFromSame The number of the last image in the source chain + * having the same content as the image in the + * destination chain given by nImageToSame or + * VD_IMAGE_CONTENT_UNKNOWN to indicate that the + * content of both containers is unknown. See the + * notes for further information. + * @param nImageToSame The number of the last image in the destination + * chain having the same content as the image in the + * source chain given by nImageFromSame or + * VD_IMAGE_CONTENT_UNKNOWN to indicate that the + * content of both containers is unknown. See the notes + * for further information. + * @param uImageFlags Flags specifying special destination image features. + * @param pDstUuid New UUID of the destination image. If NULL, a new + * UUID is created. This parameter is used if and only + * if a true copy is created. In all rename/move cases + * or copy to existing image cases the modification + * UUIDs are copied over. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * Only used if the destination image is created. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + * @param pDstVDIfsImage Pointer to the per-image VD interface list, for the + * destination image. + * @param pDstVDIfsOperation Pointer to the per-operation VD interface list, + * for the destination operation. + * + * @note Using nImageFromSame and nImageToSame can lead to a significant speedup + * when copying an image but can also lead to a corrupted copy if used + * incorrectly. It is mainly useful when cloning a chain of images and it + * is known that the virtual disk content of the two chains is exactly the + * same upto a certain image. Example: + * Imagine the chain of images which consist of a base and one diff + * image. Copying the chain starts with the base image. When copying + * the first diff image VDCopy() will read the data from the diff of + * the source chain and probably from the base image again in case the + * diff doesn't has data for the block. However the block will be + * optimized away because VDCopy() reads data from the base image of + * the destination chain compares the to and suppresses the write + * because the data is unchanged. For a lot of diff images this will be + * a huge waste of I/O bandwidth if the diff images contain only few + * changes. Because it is known that the base image of the source and + * the destination chain have the same content it is enough to check + * the diff image for changed data and copy it to the destination diff + * image which is achieved with nImageFromSame and nImageToSame. + * Setting both to 0 can suppress a lot of I/O. + */ +VBOXDDU_DECL(int) VDCopyEx(PVDISK pDiskFrom, unsigned nImage, PVDISK pDiskTo, + const char *pszBackend, const char *pszFilename, + bool fMoveByRename, uint64_t cbSize, + unsigned nImageFromSame, unsigned nImageToSame, + unsigned uImageFlags, PCRTUUID pDstUuid, + unsigned uOpenFlags, PVDINTERFACE pVDIfsOperation, + PVDINTERFACE pDstVDIfsImage, + PVDINTERFACE pDstVDIfsOperation); + +/** + * Copies an image from one HDD container to another. + * The copy is opened in the target HDD container. + * It is possible to convert between different image formats, because the + * backend for the destination may be different from the source. + * If both the source and destination reference the same HDD container, + * then the image is moved (by copying/deleting or renaming) to the new location. + * The source container is unchanged if the move operation fails, otherwise + * the image at the new location is opened in the same way as the old one was. + * + * @note The read/write accesses across disks are not synchronized, just the + * accesses to each disk. Once there is a use case which requires a defined + * read/write behavior in this situation this needs to be extended. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDiskFrom Pointer to source HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pDiskTo Pointer to destination HDD container. + * @param pszBackend Name of the image file backend to use (may be NULL to use the same as the source, case insensitive). + * @param pszFilename New name of the image (may be NULL to specify that the + * copy destination is the destination container, or + * if pDiskFrom == pDiskTo, i.e. when moving). + * @param fMoveByRename If true, attempt to perform a move by renaming (if successful the new size is ignored). + * @param cbSize New image size (0 means leave unchanged). + * @param uImageFlags Flags specifying special destination image features. + * @param pDstUuid New UUID of the destination image. If NULL, a new UUID is created. + * This parameter is used if and only if a true copy is created. + * In all rename/move cases or copy to existing image cases the modification UUIDs are copied over. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * Only used if the destination image is created. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + * @param pDstVDIfsImage Pointer to the per-image VD interface list, for the + * destination image. + * @param pDstVDIfsOperation Pointer to the per-operation VD interface list, + * for the destination operation. + */ +VBOXDDU_DECL(int) VDCopy(PVDISK pDiskFrom, unsigned nImage, PVDISK pDiskTo, + const char *pszBackend, const char *pszFilename, + bool fMoveByRename, uint64_t cbSize, + unsigned uImageFlags, PCRTUUID pDstUuid, + unsigned uOpenFlags, PVDINTERFACE pVDIfsOperation, + PVDINTERFACE pDstVDIfsImage, + PVDINTERFACE pDstVDIfsOperation); + +/** + * Optimizes the storage consumption of an image. Typically the unused blocks + * have to be wiped with zeroes to achieve a substantial reduced storage use. + * Another optimization done is reordering the image blocks, which can provide + * a significant performance boost, as reads and writes tend to use less random + * file offsets. + * + * @note Compaction is treated as a single operation with regard to thread + * synchronization, which means that it potentially blocks other activities for + * a long time. The complexity of compaction would grow even more if concurrent + * accesses have to be handled. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @return VERR_VD_IMAGE_READ_ONLY if image is not writable. + * @return VERR_NOT_SUPPORTED if this kind of image can be compacted, but + * this isn't supported yet. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ +VBOXDDU_DECL(int) VDCompact(PVDISK pDisk, unsigned nImage, PVDINTERFACE pVDIfsOperation); + +/** + * Resizes the given disk image to the given size. It is OK if there are + * multiple images open in the container. In this case the last disk image + * will be resized. + * + * @return VBox status + * @return VERR_VD_IMAGE_READ_ONLY if image is not writable. + * @return VERR_NOT_SUPPORTED if this kind of image can't be compacted. + * + * @param pDisk Pointer to the HDD container. + * @param cbSize New size of the image. + * @param pPCHSGeometry Pointer to the new physical disk geometry <= (16383,16,63). Not NULL. + * @param pLCHSGeometry Pointer to the new logical disk geometry <= (x,255,63). Not NULL. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ +VBOXDDU_DECL(int) VDResize(PVDISK pDisk, uint64_t cbSize, + PCVDGEOMETRY pPCHSGeometry, + PCVDGEOMETRY pLCHSGeometry, + PVDINTERFACE pVDIfsOperation); + +/** + * Prepares the given disk for use by the added filters. This applies to all + * opened images in the chain which might be opened read/write temporary. + * + * @return VBox status code. + * + * @param pDisk Pointer to the HDD container. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ +VBOXDDU_DECL(int) VDPrepareWithFilters(PVDISK pDisk, PVDINTERFACE pVDIfsOperation); + +/** + * Closes the last opened image file in HDD container. + * If previous image file was opened in read-only mode (the normal case) and + * the last opened image is in read-write mode then the previous image will be + * reopened in read/write mode. + * + * @return VBox status code. + * @return VERR_VD_NOT_OPENED if no image is opened in HDD container. + * @param pDisk Pointer to HDD container. + * @param fDelete If true, delete the image from the host disk. + */ +VBOXDDU_DECL(int) VDClose(PVDISK pDisk, bool fDelete); + +/** + * Removes the last added filter in the HDD container from the specified chain. + * + * @return VBox status code. + * @retval VERR_VD_NOT_OPENED if no filter is present for the disk. + * @param pDisk Pointer to HDD container. + * @param fFlags Combination of VD_FILTER_FLAGS_* defines. + */ +VBOXDDU_DECL(int) VDFilterRemove(PVDISK pDisk, uint32_t fFlags); + +/** + * Closes the currently opened cache image file in HDD container. + * + * @return VBox status code. + * @return VERR_VD_NOT_OPENED if no cache is opened in HDD container. + * @param pDisk Pointer to HDD container. + * @param fDelete If true, delete the image from the host disk. + */ +VBOXDDU_DECL(int) VDCacheClose(PVDISK pDisk, bool fDelete); + +/** + * Closes all opened image files in HDD container. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + */ +VBOXDDU_DECL(int) VDCloseAll(PVDISK pDisk); + +/** + * Removes all filters of the given HDD container. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + */ +VBOXDDU_DECL(int) VDFilterRemoveAll(PVDISK pDisk); + +/** + * Read data from virtual HDD. + * + * @return VBox status code. + * @retval VERR_VD_NOT_OPENED if no image is opened in HDD container. + * @param pDisk Pointer to HDD container. + * @param uOffset Offset of first reading byte from start of disk. + * Must be aligned to a sector boundary. + * @param pvBuf Pointer to buffer for reading data. + * @param cbRead Number of bytes to read. + * Must be aligned to a sector boundary. + */ +VBOXDDU_DECL(int) VDRead(PVDISK pDisk, uint64_t uOffset, void *pvBuf, size_t cbRead); + +/** + * Write data to virtual HDD. + * + * @return VBox status code. + * @retval VERR_VD_NOT_OPENED if no image is opened in HDD container. + * @param pDisk Pointer to HDD container. + * @param uOffset Offset of first writing byte from start of disk. + * Must be aligned to a sector boundary. + * @param pvBuf Pointer to buffer for writing data. + * @param cbWrite Number of bytes to write. + * Must be aligned to a sector boundary. + */ +VBOXDDU_DECL(int) VDWrite(PVDISK pDisk, uint64_t uOffset, const void *pvBuf, size_t cbWrite); + +/** + * Make sure the on disk representation of a virtual HDD is up to date. + * + * @return VBox status code. + * @retval VERR_VD_NOT_OPENED if no image is opened in HDD container. + * @param pDisk Pointer to HDD container. + */ +VBOXDDU_DECL(int) VDFlush(PVDISK pDisk); + +/** + * Get number of opened images in HDD container. + * + * @return Number of opened images for HDD container. 0 if no images have been opened. + * @param pDisk Pointer to HDD container. + */ +VBOXDDU_DECL(unsigned) VDGetCount(PVDISK pDisk); + +/** + * Get read/write mode of HDD container. + * + * @return Virtual disk ReadOnly status. + * @return true if no image is opened in HDD container. + * @param pDisk Pointer to HDD container. + */ +VBOXDDU_DECL(bool) VDIsReadOnly(PVDISK pDisk); + +/** + * Get sector size of an image in HDD container. + * + * @return Virtual disk sector size in bytes. + * @return 0 if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + */ +VBOXDDU_DECL(uint32_t) VDGetSectorSize(PVDISK pDisk, unsigned nImage); + +/** + * Get total capacity of an image in HDD container. + * + * @return Virtual disk size in bytes. + * @return 0 if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + */ +VBOXDDU_DECL(uint64_t) VDGetSize(PVDISK pDisk, unsigned nImage); + +/** + * Get total file size of an image in HDD container. + * + * @return Virtual disk size in bytes. + * @return 0 if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + */ +VBOXDDU_DECL(uint64_t) VDGetFileSize(PVDISK pDisk, unsigned nImage); + +/** + * Get virtual disk PCHS geometry of an image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @return VERR_VD_GEOMETRY_NOT_SET if no geometry present in the HDD container. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pPCHSGeometry Where to store PCHS geometry. Not NULL. + */ +VBOXDDU_DECL(int) VDGetPCHSGeometry(PVDISK pDisk, unsigned nImage, PVDGEOMETRY pPCHSGeometry); + +/** + * Store virtual disk PCHS geometry of an image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pPCHSGeometry Where to load PCHS geometry from. Not NULL. + */ +VBOXDDU_DECL(int) VDSetPCHSGeometry(PVDISK pDisk, unsigned nImage, PCVDGEOMETRY pPCHSGeometry); + +/** + * Get virtual disk LCHS geometry of an image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @return VERR_VD_GEOMETRY_NOT_SET if no geometry present in the HDD container. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pLCHSGeometry Where to store LCHS geometry. Not NULL. + */ +VBOXDDU_DECL(int) VDGetLCHSGeometry(PVDISK pDisk, unsigned nImage, PVDGEOMETRY pLCHSGeometry); + +/** + * Store virtual disk LCHS geometry of an image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pLCHSGeometry Where to load LCHS geometry from. Not NULL. + */ +VBOXDDU_DECL(int) VDSetLCHSGeometry(PVDISK pDisk, unsigned nImage, PCVDGEOMETRY pLCHSGeometry); + +/** + * Queries the available regions of an image in the given VD container. + * + * @return VBox status code. + * @retval VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @retval VERR_NOT_SUPPORTED if the image backend doesn't support region lists. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param fFlags Combination of VD_REGION_LIST_F_* flags. + * @param ppRegionList Where to store the pointer to the region list on success, must be freed + * with VDRegionListFree(). + */ +VBOXDDU_DECL(int) VDQueryRegions(PVDISK pDisk, unsigned nImage, uint32_t fFlags, + PPVDREGIONLIST ppRegionList); + +/** + * Frees a region list previously queried with VDQueryRegions(). + * + * @return nothing. + * @param pRegionList The region list to free. + */ +VBOXDDU_DECL(void) VDRegionListFree(PVDREGIONLIST pRegionList); + +/** + * Get version of image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param puVersion Where to store the image version. + */ +VBOXDDU_DECL(int) VDGetVersion(PVDISK pDisk, unsigned nImage, unsigned *puVersion); + +/** + * List the capabilities of image backend in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to the HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pBackendInfo Where to store the backend information. + */ +VBOXDDU_DECL(int) VDBackendInfoSingle(PVDISK pDisk, unsigned nImage, PVDBACKENDINFO pBackendInfo); + +/** + * Get flags of image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param puImageFlags Where to store the image flags. + */ +VBOXDDU_DECL(int) VDGetImageFlags(PVDISK pDisk, unsigned nImage, unsigned *puImageFlags); + +/** + * Get open flags of image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param puOpenFlags Where to store the image open flags. + */ +VBOXDDU_DECL(int) VDGetOpenFlags(PVDISK pDisk, unsigned nImage, unsigned *puOpenFlags); + +/** + * Set open flags of image in HDD container. + * This operation may cause file locking changes and/or files being reopened. + * Note that in case of unrecoverable error all images in HDD container will be closed. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + */ +VBOXDDU_DECL(int) VDSetOpenFlags(PVDISK pDisk, unsigned nImage, unsigned uOpenFlags); + +/** + * Get base filename of image in HDD container. Some image formats use + * other filenames as well, so don't use this for anything but informational + * purposes. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @return VERR_BUFFER_OVERFLOW if pszFilename buffer too small to hold filename. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pszFilename Where to store the image file name. + * @param cbFilename Size of buffer pszFilename points to. + */ +VBOXDDU_DECL(int) VDGetFilename(PVDISK pDisk, unsigned nImage, char *pszFilename, unsigned cbFilename); + +/** + * Get the comment line of image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @return VERR_BUFFER_OVERFLOW if pszComment buffer too small to hold comment text. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pszComment Where to store the comment string of image. NULL is ok. + * @param cbComment The size of pszComment buffer. 0 is ok. + */ +VBOXDDU_DECL(int) VDGetComment(PVDISK pDisk, unsigned nImage, char *pszComment, unsigned cbComment); + +/** + * Changes the comment line of image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pszComment New comment string (UTF-8). NULL is allowed to reset the comment. + */ +VBOXDDU_DECL(int) VDSetComment(PVDISK pDisk, unsigned nImage, const char *pszComment); + +/** + * Get UUID of image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pUuid Where to store the image UUID. + */ +VBOXDDU_DECL(int) VDGetUuid(PVDISK pDisk, unsigned nImage, PRTUUID pUuid); + +/** + * Set the image's UUID. Should not be used by normal applications. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pUuid New UUID of the image. If NULL, a new UUID is created. + */ +VBOXDDU_DECL(int) VDSetUuid(PVDISK pDisk, unsigned nImage, PCRTUUID pUuid); + +/** + * Get last modification UUID of image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pUuid Where to store the image modification UUID. + */ +VBOXDDU_DECL(int) VDGetModificationUuid(PVDISK pDisk, unsigned nImage, PRTUUID pUuid); + +/** + * Set the image's last modification UUID. Should not be used by normal applications. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pUuid New modification UUID of the image. If NULL, a new UUID is created. + */ +VBOXDDU_DECL(int) VDSetModificationUuid(PVDISK pDisk, unsigned nImage, PCRTUUID pUuid); + +/** + * Get parent UUID of image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of the container. + * @param pUuid Where to store the parent image UUID. + */ +VBOXDDU_DECL(int) VDGetParentUuid(PVDISK pDisk, unsigned nImage, PRTUUID pUuid); + +/** + * Set the image's parent UUID. Should not be used by normal applications. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pUuid New parent UUID of the image. If NULL, a new UUID is created. + */ +VBOXDDU_DECL(int) VDSetParentUuid(PVDISK pDisk, unsigned nImage, PCRTUUID pUuid); + + +/** + * Debug helper - dumps all opened images in HDD container into the log file. + * + * @param pDisk Pointer to HDD container. + */ +VBOXDDU_DECL(void) VDDumpImages(PVDISK pDisk); + + +/** + * Discards unused ranges given as a list. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + * @param paRanges The array of ranges to discard. + * @param cRanges Number of entries in the array. + * + * @note In contrast to VDCompact() the ranges are always discarded even if they + * appear to contain data. This method is mainly used to implement TRIM support. + */ +VBOXDDU_DECL(int) VDDiscardRanges(PVDISK pDisk, PCRTRANGE paRanges, unsigned cRanges); + + +/** + * Start an asynchronous read request. + * + * @return VBox status code. + * @param pDisk Pointer to the HDD container. + * @param off The offset of the virtual disk to read from. + * @param cbRead How many bytes to read. + * @param pSgBuf Pointer to the S/G buffer to read into. + * @param pfnComplete Completion callback. + * @param pvUser1 User data which is passed on completion. + * @param pvUser2 User data which is passed on completion. + */ +VBOXDDU_DECL(int) VDAsyncRead(PVDISK pDisk, uint64_t off, size_t cbRead, + PCRTSGBUF pSgBuf, + PFNVDASYNCTRANSFERCOMPLETE pfnComplete, + void *pvUser1, void *pvUser2); + + +/** + * Start an asynchronous write request. + * + * @return VBox status code. + * @param pDisk Pointer to the HDD container. + * @param off The offset of the virtual disk to write to. + * @param cbWrite How many bytes to write. + * @param pSgBuf Pointer to the S/G buffer to write from. + * @param pfnComplete Completion callback. + * @param pvUser1 User data which is passed on completion. + * @param pvUser2 User data which is passed on completion. + */ +VBOXDDU_DECL(int) VDAsyncWrite(PVDISK pDisk, uint64_t off, size_t cbWrite, + PCRTSGBUF pSgBuf, + PFNVDASYNCTRANSFERCOMPLETE pfnComplete, + void *pvUser1, void *pvUser2); + + +/** + * Start an asynchronous flush request. + * + * @return VBox status code. + * @param pDisk Pointer to the HDD container. + * @param pfnComplete Completion callback. + * @param pvUser1 User data which is passed on completion. + * @param pvUser2 User data which is passed on completion. + */ +VBOXDDU_DECL(int) VDAsyncFlush(PVDISK pDisk, + PFNVDASYNCTRANSFERCOMPLETE pfnComplete, + void *pvUser1, void *pvUser2); + +/** + * Start an asynchronous discard request. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + * @param paRanges The array of ranges to discard. + * @param cRanges Number of entries in the array. + * @param pfnComplete Completion callback. + * @param pvUser1 User data which is passed on completion. + * @param pvUser2 User data which is passed on completion. + */ +VBOXDDU_DECL(int) VDAsyncDiscardRanges(PVDISK pDisk, PCRTRANGE paRanges, unsigned cRanges, + PFNVDASYNCTRANSFERCOMPLETE pfnComplete, + void *pvUser1, void *pvUser2); + +/** + * Tries to repair a corrupted image. + * + * @return VBox status code. + * @retval VERR_VD_IMAGE_REPAIR_NOT_SUPPORTED if the backend does not support repairing the image. + * @retval VERR_VD_IMAGE_REPAIR_IMPOSSIBLE if the corruption is to severe to repair the image. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pszFilename Name of the image file to repair. + * @param pszBackend The backend to use. + * @param fFlags Combination of the VD_REPAIR_* flags. + */ +VBOXDDU_DECL(int) VDRepair(PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage, + const char *pszFilename, const char *pszBackend, uint32_t fFlags); + +/** + * Create a VFS file handle from the given HDD container. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + * @param fFlags Combination of the VD_VFSFILE_* flags. + * @param phVfsFile Where to store the handle to the VFS file on + * success. + */ +VBOXDDU_DECL(int) VDCreateVfsFileFromDisk(PVDISK pDisk, uint32_t fFlags, + PRTVFSFILE phVfsFile); + + + +/** @defgroup grp_vd_ifs_def Default implementations for certain VD interfaces. + * @{ + */ +/** Internal per interface instance data. */ +typedef struct VDIFINSTINT *VDIFINST; +/** Pointer to the per instance interface data. */ +typedef VDIFINST *PVDIFINST; + +/** + * Creates a new VD TCP/IP interface instance and adds it to the given interface list. + * + * @returns VBox status code. + * @param phTcpNetInst Where to store the TCP/IP interface handle on success. + * @param ppVdIfs Pointer to the VD interface list. + */ +VBOXDDU_DECL(int) VDIfTcpNetInstDefaultCreate(PVDIFINST phTcpNetInst, PVDINTERFACE *ppVdIfs); + +/** + * Destroys the given VD TCP/IP interface instance. + * + * @returns nothing. + * @param hTcpNetInst The TCP/IP interface instance handle. + */ +VBOXDDU_DECL(void) VDIfTcpNetInstDefaultDestroy(VDIFINST hTcpNetInst); +/** @} */ + + + +/** @defgroup grp_vd_ioiter I/O iterator + * @{ + */ + +/** Read metadata coming before each main data block addressed in the segment. */ +#define VD_IOITER_SEG_F_PRE_METADATA RT_BIT_32(0) +/** Read the main user data of each addressed block in the segment. */ +#define VD_IOITER_SEG_F_MAIN_DATA RT_BIT_32(1) +/** Read metadata coming after each main data block addressed in the segment. */ +#define VD_IOITER_SEG_F_POST_METADATA RT_BIT_32(2) +/** Read checksum data of each data block addressed in the segment. */ +#define VD_IOITER_SEG_F_CHKSUM RT_BIT_32(3) +/** Read all available data for each addressed block in the segment. */ +#define VD_IOITER_SEG_F_AVAILABLE RT_BIT_32(4) + +/** The offset and size members in the segments use byte granularity instead of a + * block address and number of blocks respectively. */ +#define VDIOITER_F_BYTE_OFFSET_AND_SIZE RT_BIT_32(0) + +/** + * VD I/O iterator segment. + */ +typedef struct VDIOITERSEG +{ + /** Start offset for this segment. */ + uint64_t offStartSeg; + /** Size of the segment (bytes or blocks). */ + uint64_t cSizeSeg; + /** Flags for this segment, see VD_IOITER_SEG_F_*. */ + uint32_t fFlags; +} VDIOITERSEG; +/** Pointer to a I/O iterator segment. */ +typedef VDIOITERSEG *PVDIOITERSEG; +/** Pointer to a constant I/O iterator segment. */ +typedef VDIOITERSEG *PCVDIOITERSEG; + +/** I/O iterator handle. */ +typedef struct VDIOITERINT *VDIOITER; +/** Pointer to a I/O iterator handle. */ +typedef VDIOITER *PVDIOITER; + +/** + * Create a new I/O iterator. + * + * @returns VBox status code. + * @param pDisk The disk to create the iterator for. + * @param phVdIoIter Where to store the handle to the I/O iterator on success. + * @param paIoIterSegs The segments for the iterator, can be destroyed after the call. + * @param cIoIterSegs Number of segments. + * @param fFlags Flags for the iterator, see VDIOITER_F_* + */ +VBOXDDU_DECL(int) VDIoIterCreate(PVDISK pDisk, PVDIOITER phVdIoIter, PCVDIOITERSEG paIoIterSegs, + uint32_t cIoIterSegs, uint32_t fFlags); + +/** + * Retains the reference count of the given I/O iterator. + * + * @returns New reference count. + * @param hVdIoIter The I/O iterator handle. + */ +VBOXDDU_DECL(uint32_t) VDIoIterRetain(VDIOITER hVdIoIter); + +/** + * Releases the reference count of the given I/O iterator. + * + * @returns New reference count, on 0 the iterator is destroyed. + * @param hVdIoIter The I/O iterator handle. + */ +VBOXDDU_DECL(uint32_t) VDIoIterRelease(VDIOITER hVdIoIter); + +/** + * Returns the number of segments in the given I/O iterator. + * + * @returns Number of segments. + * @param hVdIoIter The I/O iterator handle. + */ +VBOXDDU_DECL(uint32_t) VDIoIterGetSegmentCount(VDIOITER hVdIoIter); + +/** + * Returns the flags of the given I/O iterator. + * + * @returns Flags. + * @param hVdIoIter The I/O iterator handle. + */ +VBOXDDU_DECL(uint32_t) VDIoIterGetFlags(VDIOITER hVdIoIter); + +/** + * Queries the properties of the given segment for the given I/O iterator. + * + * @returns VBox status code. + * @param hVdIoIter The I/O iterator handle. + * @param idx The segment index to query. + * @param pSegment Where to store the segment properties on success. + */ +VBOXDDU_DECL(int) VDIoIterQuerySegment(VDIOITER hVdIoIter, uint32_t idx, PVDIOITERSEG pSegment); + +/** @} */ + + +/** @defgroup grp_vd_io_buf I/O buffer management API. + * @{ + */ + +/** VD I/O buffer manager handle. */ +typedef struct VDIOBUFMGRINT *VDIOBUFMGR; +/** Pointer to VD I/O buffer manager handle. */ +typedef VDIOBUFMGR *PVDIOBUFMGR; + +/** VD I/O buffer handle. */ +typedef struct VDIOBUFINT *VDIOBUF; +/** Pointer to a VD I/O buffer handle. */ +typedef VDIOBUF *PVDIOBUF; + +/** Default I/O buffer manager flags. */ +#define VD_IOBUFMGR_F_DEFAULT (0) +/** I/O buffer memory needs to be non pageable (for example because it contains sensitive data + * which shouldn't end up in swap unencrypted). */ +#define VD_IOBUFMGR_F_REQUIRE_NOT_PAGABLE RT_BIT(0) + +/** Pointer to VD I/O buffer callbacks. */ +typedef struct VDIOBUFCALLBACKS *PVDIOBUFCALLBACKS; +/** Pointer to const VD I/O buffer callbacks. */ +typedef const struct VDIOBUFCALLBACKS *PCVDIOBUFCALLBACKS; + +/** + * VD I/O buffer callbacks. + */ +typedef struct VDIOBUFCALLBACKS +{ + /** + * Copy data from the memory buffer of the caller to the callees memory buffer for the given request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOBUF_OVERFLOW if there is not enough room to store the data. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoBuf The I/O request handle. + * @param pvIoBufAlloc The allocator specific memory for this request. + * @param offDst The destination offset from the start to write the data to. + * @param pSgBuf The S/G buffer to read the data from. + * @param cbCopy How many bytes to copy. + */ + DECLR3CALLBACKMEMBER(int, pfnIoBufCopyFromBuf, (PVDIOBUFCALLBACKS pInterface, VDIOBUF hIoBuf, + void *pvIoBufAlloc, uint32_t offDst, PRTSGBUF pSgBuf, + size_t cbCopy)); + + /** + * Copy data to the memory buffer of the caller from the callees memory buffer for the given request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOBUF_UNDERRUN if there is not enough data to copy from the buffer. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoBuf The I/O request handle. + * @param pvIoBufAlloc The allocator specific memory for this request. + * @param offSrc The offset from the start of the buffer to read the data from. + * @param pSgBuf The S/G buffer to write the data to. + * @param cbCopy How many bytes to copy. + */ + DECLR3CALLBACKMEMBER(int, pfnIoBufCopyToBuf, (PVDIOBUFCALLBACKS pInterface, VDIOBUF hIoBuf, + void *pvIoBufAlloc, uint32_t offSrc, PRTSGBUF pSgBuf, + size_t cbCopy)); + + /** + * Queries a pointer to the memory buffer for the request from the drive/device above. + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if this is not supported for this request. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoBuf The I/O request handle. + * @param pvIoBufAlloc The allocator specific memory for this request. + * @param offBuf The offset from the start of the buffer to get the buffer address. + * @param cbBuf The number of bytes requested. + * @param ppvBuf Where to store the pointer to the guest buffer on success. + * @param pcbBuf Where to store the size of the buffer on success. + * + * @note This is an optional feature of the entity implementing this interface to avoid overhead + * by copying the data between buffers. If NULL it is not supported at all and the caller + * has to resort to VDIOBUFCALLBACKS::pfnIoBufCopyToBuf and VDIOBUFCALLBACKS::pfnIoBufCopyFromBuf. + * The same holds when VERR_NOT_SUPPORTED is returned. + * + * On the upside the caller of this interface might not call this method at all and just + * use the before mentioned methods to copy the data between the buffers. + */ + DECLR3CALLBACKMEMBER(int, pfnIoBufQueryBuf, (PVDIOBUFCALLBACKS pInterface, VDIOBUF hIoBuf, + void *pvIoBufAlloc, uint32_t offBuf, size_t cbBuf, + void **ppvBuf, size_t *pcbBuf)); + +} VDIOBUFCALLBACKS; + +/** + * Creates a new I/O buffer manager. + * + * @returns VBox status code. + * @param phIoBufMgr Where to store the handle to the I/O buffer manager on success. + * @param cbMax The maximum amount of I/O memory to allow. Trying to allocate more than + * this will lead to out of memory errors. 0 for "unlimited" size (only restriction + * is the available memory on the host). + * @param fFlags Combination of VD_IOBUFMGR_F_*. + * @param pIoBufClbks Memory copy callbacks between source and target memory regions, optional. + * When NULL all I/O buffers must be allocated with a valid S/G buffer laying out the + * memory. + * @param cbIoBufAlloc How much to allocate extra in the I/O buffer for private use. + */ +VBOXDDU_DECL(int) VDIoBufMgrCreate(PVDIOBUFMGR phIoBufMgr, size_t cbMax, uint32_t fFlags, + PVDIOBUFCALLBACKS pIoBufClbks, size_t cbIoBufAlloc); + +/** + * Destroys the given I/O buffer manager. + * + * @returns VBox status code. + * @retval VERR_INVALID_STATE if there are still buffers allocated by the given manager. + * @param hIoBufMgr The I/O buffer manager. + */ +VBOXDDU_DECL(int) VDIoBufMgrDestroy(VDIOBUFMGR hIoBufMgr); + +/** + * Allocate a new I/O buffer handle. + * + * @returns VBox status code. + * @param hIoBufMgr The I/O buffer manager to use. + * @param phIoBuf Where to store the I/O buffer handle on success. + * @param ppvIoBufAlloc Where to store the pointe to the private party on success. + * @param pSgBuf The S/G buffer to use, optional. If NULL the I/O buffer callbacks + * supplied when creating the owning manager are used to transfer the + * data. + * @param cbBuf Size of the buffer in bytes. + */ +VBOXDDU_DECL(int) VDIoBufMgrAllocBuf(VDIOBUFMGR hIoBufMgr, PVDIOBUF phIoBuf, void **ppvIoBufAlloc, + PCRTSGBUF pSgBuf, size_t cbBuf); + +/** + * Retains the I/O buffer reference count. + * + * @returns New reference count. + * @param hIoBuf The I/O buffer handle. + */ +VBOXDDU_DECL(uint32_t) VDIoBufRetain(VDIOBUF hIoBuf); + +/** + * Releases the given I/O buffer reference. + * + * @returns New reference count, on 0 the I/O buffer is destroyed. + * @param hIoBuf The I/O buffer handle. + */ +VBOXDDU_DECL(uint32_t) VDIoBufRelease(VDIOBUF hIoBuf); + +/** @} */ + + +/** @defgroup grp_vd_ioqueue I/O queues + * @{ + */ + +/** VD I/O queue handle. */ +typedef struct VDIOQUEUEINT *VDIOQUEUE; +/** Pointer to an VD I/O queue handle. */ +typedef VDIOQUEUE *PVDIOQUEUE; + +/** VD I/O queue request handle. */ +typedef struct VDIOREQINT *VDIOREQ; +/** Pointer to an VD I/O queue request handle. */ +typedef VDIOREQ *PVDIOREQ; + +/** A I/O request ID. */ +typedef uint64_t VDIOREQID; + +/** + * I/O request type. + */ +typedef enum VDIOREQTYPE +{ + /** Invalid request type. */ + VDIOREQTYPE_INVALID = 0, + /** Read request. */ + VDIOREQTYPE_READ, + /** Write request. */ + VDIOREQTYPE_WRITE, + /** Flush request. */ + VDIOREQTYPE_FLUSH, + /** Discard request. */ + VDIOREQTYPE_DISCARD, + /** 32bit hack. */ + VDIOREQTYPE_32BIT_HACK = 0x7fffffff +} VDIOREQTYPE; +/** Pointer to a request type. */ +typedef VDIOREQTYPE *PVDIOREQTYPE; + +/** + * I/O queue request completion callback. + * + * @returns nothing. + * @param hVdIoQueue The VD I/O queue handle. + * @param pDisk The disk the queue is attached to. + * @param hVdIoReq The VD I/O request which completed. + * @param pvVdIoReq Pointer to the allocator specific memory for this request. + * @param rcReq The completion status code. + */ +typedef DECLCALLBACKTYPE(void, FNVDIOQUEUEREQCOMPLETE,(VDIOQUEUE hVdIoQueue, PVDISK pDisk, + VDIOREQ hVdIoReq, void *pvVdIoReq, int rcReq)); +/** Pointer to a VD I/O queue request completion callback. */ +typedef FNVDIOQUEUEREQCOMPLETE *PFNVDIOQUEUEREQCOMPLETE; + + +/** + * Creates a new I/O queue. + * + * @returns VBox status code. + * @param phVdIoQueue Where to store the handle to the I/O queue on success. + * @param pfnIoReqComplete The completion handle to call when a request on the specified queue completes. + * @param cbIoReqAlloc The extra amount of memory to allocate and associate with allocated requests + * for use by the caller. + * @param iPriority The priority of the queue from 0..UINT32_MAX. The lower the number the higher + * the priority of the queue. + */ +VBOXDDU_DECL(int) VDIoQueueCreate(PVDIOQUEUE phVdIoQueue, PFNVDIOQUEUEREQCOMPLETE pfnIoReqComplete, + size_t cbIoReqAlloc, uint32_t iPriority); + +/** + * Destroys the given I/O queue. + * + * @returns VBox status code. + * @param hVdIoQueue The I/O queue handle. + */ +VBOXDDU_DECL(int) VDIoQueueDestroy(VDIOQUEUE hVdIoQueue); + +/** + * Attaches the given I/O queue to the given virtual disk container. + * + * @returns VBox status code. + * @param pDisk The disk container handle. + * @param hVdIoQueue The I/O queue to attach. + */ +VBOXDDU_DECL(int) VDIoQueueAttach(PVDISK pDisk, VDIOQUEUE hVdIoQueue); + +/** + * Detaches the given I/O queue from the currently attached disk container. + * + * @returns VBox status code. + * @param hVdIoQueue The I/O queue. + * @param fPurge Flag whether to cancel all active requests on this queue + * before detaching. + */ +VBOXDDU_DECL(int) VDIoQueueDetach(VDIOQUEUE hVdIoQueue, bool fPurge); + +/** + * Purges all requests on the given queue. + * + * @returns VBox status code. + * @param hVdIoQueue The I/O queue. + */ +VBOXDDU_DECL(int) VDIoQueuePurge(VDIOQUEUE hVdIoQueue); + +/** + * Allocates a new request from the given queue. + * + * @returns VBox status code. + * @param hVdIoQueue The I/O queue. + * @param phVdIoReq Where to store the handle of the request on success. + * @param ppvVdIoReq Where to store the pointer to the allocator usable memory on success. + * @param uIoReqId The request ID to assign to the request for canceling. + */ +VBOXDDU_DECL(int) VDIoQueueReqAlloc(VDIOQUEUE hVdIoQueue, PVDIOREQ phVdIoReq, + void **ppvVdIoReq, VDIOREQID uIoReqId); + +/** + * Frees a given non active request. + * + * @returns VBox status code. + * @param hVdIoReq The I/O request to free. + */ +VBOXDDU_DECL(int) VDIoQueueReqFree(VDIOREQ hVdIoReq); + +/** + * Cancels an active request by the given request ID. + * + * @returns VBox status code. + * @param hVdIoQueue The I/O queue to cancel the request on. + * @param uIoReqId The request ID. + */ +VBOXDDU_DECL(int) VDIoQueueReqCancelById(VDIOQUEUE hVdIoQueue, VDIOREQID uIoReqId); + +/** + * Cancels an active request by the given handle. + * + * @returns VBox status code. + * @param hVdIoReq The I/O request handle to cancel. + */ +VBOXDDU_DECL(int) VDIoQueueReqCancelByHandle(VDIOREQ hVdIoReq); + +/** + * Submit a new request to the queue the request was allocated from. + * + * @returns VBox status code. + * @param hVdIoReq The I/O request handle to submit. + * @param enmType The type of the request. + * @param hVdIoIter The iterator to use, NULL for flush requests. + * @param hVdIoBuf The I/O buffer handle to use, NULL for flush and discard requests. + */ +VBOXDDU_DECL(int) VDIoQueueReqSubmit(VDIOREQ hVdIoReq, VDIOREQTYPE enmType, + VDIOITER hVdIoIter, VDIOBUF hVdIoBuf); + +/** @} */ + + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_vd_h */ + diff --git a/include/VBox/vdmedia.h b/include/VBox/vdmedia.h new file mode 100644 index 00000000..89886efb --- /dev/null +++ b/include/VBox/vdmedia.h @@ -0,0 +1,226 @@ +/** @file + * Virtual Disk Container API - Media type definitions shared with PDM. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vdmedia_h +#define VBOX_INCLUDED_vdmedia_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/** @name VD container type. + * @{ + */ +typedef enum VDTYPE +{ + /** Invalid. */ + VDTYPE_INVALID = 0, + /** HardDisk */ + VDTYPE_HDD, + /** Any kind of optical disc (CD/DVD etc.). */ + VDTYPE_OPTICAL_DISC, + /** Floppy. */ + VDTYPE_FLOPPY +} VDTYPE; +/** @}*/ + +/** @name VD medium type. + * @{ + */ +typedef enum VDMEDIUMTYPE +{ + /** Invalid. */ + VDMEDIUMTYPE_INVALID = 0, + /** HardDisk (spinning platter or SSD). */ + VDMEDIUMTYPE_HDD, + /** CD-ROM */ + VDMEDIUMTYPE_CDROM, + /** DVD-ROM */ + VDMEDIUMTYPE_DVDROM, + /** BluRay. */ + VDMEDIUMTYPE_BD, + /** 360KB 5 1/4" floppy. */ + VDMEDIUMTYPE_FLOPPY_360, + /** 720KB 3 1/2" floppy. */ + VDMEDIUMTYPE_FLOPPY_720, + /** 1.2MB 5 1/4" floppy. */ + VDMEDIUMTYPE_FLOPPY_1_20, + /** 1.44MB 3 1/2" floppy. */ + VDMEDIUMTYPE_FLOPPY_1_44, + /** 2.88MB 3 1/2" floppy. */ + VDMEDIUMTYPE_FLOPPY_2_88, + /** Fake disk that can take up to 15.6 MB images. + * C=255, H=2, S=63. */ + VDMEDIUMTYPE_FLOPPY_FAKE_15_6, + /** Fake disk that can take up to 63.5 MB images. + * C=255, H=2, S=255. */ + VDMEDIUMTYPE_FLOPPY_FAKE_63_5 +} VDMEDIUMTYPE; +/** @} */ + +/** Check if the given medium type is a floppy. */ +#define VDMEDIUMTYPE_IS_FLOPPY(a_enmType) ( (a_enmType) >= VDMEDIUMTYPE_FLOPPY_360 && (a_enmType) <= VDMEDIUMTYPE_FLOPPY_2_88 ) + +/** + * Disk geometry. + */ +typedef struct VDGEOMETRY +{ + /** Number of cylinders. */ + uint32_t cCylinders; + /** Number of heads. */ + uint32_t cHeads; + /** Number of sectors. */ + uint32_t cSectors; +} VDGEOMETRY; + +/** Pointer to disk geometry. */ +typedef VDGEOMETRY *PVDGEOMETRY; +/** Pointer to constant disk geometry. */ +typedef const VDGEOMETRY *PCVDGEOMETRY; + +/** + * Disk region data form known to us from various standards. + */ +typedef enum VDREGIONDATAFORM +{ + /** Invalid data form. */ + VDREGIONDATAFORM_INVALID = 0, + /** Raw data, no standardized format. */ + VDREGIONDATAFORM_RAW, + /** CD-DA (audio CD), 2352 bytes of data. */ + VDREGIONDATAFORM_CDDA, + /** CDDA data is pause. */ + VDREGIONDATAFORM_CDDA_PAUSE, + /** Mode 1 with 2048 bytes sector size. */ + VDREGIONDATAFORM_MODE1_2048, + /** Mode 1 with 2352 bytes sector size. */ + VDREGIONDATAFORM_MODE1_2352, + /** Mode 1 with 0 bytes sector size (generated by the drive). */ + VDREGIONDATAFORM_MODE1_0, + /** XA Mode with 2336 bytes sector size. */ + VDREGIONDATAFORM_XA_2336, + /** XA Mode with 2352 bytes sector size. */ + VDREGIONDATAFORM_XA_2352, + /** XA Mode with 0 bytes sector size (generated by the drive). */ + VDREGIONDATAFORM_XA_0, + /** Mode 2 with 2336 bytes sector size. */ + VDREGIONDATAFORM_MODE2_2336, + /** Mode 2 with 2352 bytes sector size. */ + VDREGIONDATAFORM_MODE2_2352, + /** Mode 2 with 0 bytes sector size (generated by the drive). */ + VDREGIONDATAFORM_MODE2_0 +} VDREGIONDATAFORM; +/** Pointer to a region data form. */ +typedef VDREGIONDATAFORM *PVDREGIONDATAFORM; +/** Pointer to a const region data form. */ +typedef const VDREGIONDATAFORM PCVDREGIONDATAFORM; + +/** + * Disk region metadata forms known to us. + */ +typedef enum VDREGIONMETADATAFORM +{ + /** Invalid metadata form. */ + VDREGIONMETADATAFORM_INVALID = 0, + /** No metadata assined to the region. */ + VDREGIONMETADATAFORM_NONE, + /** Raw metadata, no standardized format. */ + VDREGIONMETADATAFORM_RAW +} VDREGIONMETADATAFORM; +/** Pointer to a region metadata form. */ +typedef VDREGIONMETADATAFORM *PVDREGIONMETADATAFORM; +/** Pointer to a const region metadata form. */ +typedef const VDREGIONMETADATAFORM PCVDREGIONMETADATAFORM; + +/** + * Disk region descriptor. + */ +typedef struct VDREGIONDESC +{ + /** Start of the region in bytes or LBA number (depending on the flag in the + * list header). */ + uint64_t offRegion; + /** Overall size of the region in bytes or number of blocks (depending on the + * flag in the list header). */ + uint64_t cRegionBlocksOrBytes; + /** Size of one block in bytes, containing user and metadata. */ + uint64_t cbBlock; + /** User data form of the block. */ + VDREGIONDATAFORM enmDataForm; + /** Metadata form of the block. */ + VDREGIONMETADATAFORM enmMetadataForm; + /** Size of the data block in bytes. */ + uint64_t cbData; + /** Size of the metadata in a block in bytes. */ + uint64_t cbMetadata; +} VDREGIONDESC; +/** Pointer to a region descriptor. */ +typedef VDREGIONDESC *PVDREGIONDESC; +/** Pointer to a constant region descriptor. */ +typedef const VDREGIONDESC *PCVDREGIONDESC; + +/** + * Disk region list. + */ +typedef struct VDREGIONLIST +{ + /** Flags valid for the region list. */ + uint32_t fFlags; + /** Number of regions in the descriptor array. */ + uint32_t cRegions; + /** Region descriptors - variable in size. */ + VDREGIONDESC aRegions[RT_FLEXIBLE_ARRAY_NESTED]; +} VDREGIONLIST; +/** Pointer to a region list. */ +typedef VDREGIONLIST *PVDREGIONLIST; +/** Pointer to a constant region list. */ +typedef const VDREGIONLIST *PCVDREGIONLIST; +/** Pointer to a region list pointer. */ +typedef PVDREGIONLIST *PPVDREGIONLIST; + +/** @name Valid region list flags. + * @{ + */ +/** When set the region start offset and size are given in numbers of blocks + * instead of byte offsets and sizes. */ +#define VD_REGION_LIST_F_LOC_SIZE_BLOCKS RT_BIT_32(0) +/** Mask of all valid flags. */ +#define VD_REGION_LIST_F_VALID (VD_REGION_LIST_F_LOC_SIZE_BLOCKS) +/** @} */ + +#endif /* !VBOX_INCLUDED_vdmedia_h */ + diff --git a/include/VBox/version.h b/include/VBox/version.h new file mode 100644 index 00000000..256e3a0c --- /dev/null +++ b/include/VBox/version.h @@ -0,0 +1,166 @@ +/** @file + * VBox Version Management. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_version_h +#define VBOX_INCLUDED_version_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Product info. */ +#include <product-generated.h> +#include <version-generated.h> + +#ifdef RC_INVOKED +/* Some versions of RC has trouble with cdefs.h, so we duplicate these two here. */ +# define RT_STR(str) #str +# define RT_XSTR(str) RT_STR(str) +#else /* !RC_INVOKED */ + +/** Combined version number. */ +# define VBOX_VERSION (VBOX_VERSION_MAJOR << 16 | VBOX_VERSION_MINOR) +/** Get minor version from combined version. */ +# define VBOX_GET_VERSION_MINOR(uVer) ((uVer) & 0xffff) +/** Get major version from combined version. */ +# define VBOX_GET_VERSION_MAJOR(uVer) ((uVer) >> 16) + +/** + * Make a full version number. + * + * The returned number can be used in normal integer comparsions and will yield + * the expected results. + * + * @param uMajor The major version number. + * @param uMinor The minor version number. + * @param uBuild The build number. + * @returns Full version number. + */ +# define VBOX_FULL_VERSION_MAKE(uMajor, uMinor, uBuild) \ + ( (uint32_t)((uMajor) & 0xff) << 24 \ + | (uint32_t)((uMinor) & 0xff) << 16 \ + | (uint32_t)((uBuild) & 0xffff) \ + ) + +/** Combined version number. */ +# define VBOX_FULL_VERSION \ + VBOX_FULL_VERSION_MAKE(VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD) +/** Get the major version number from a VBOX_FULL_VERSION style number. */ +# define VBOX_FULL_VERSION_GET_MAJOR(uFullVer) ( ((uFullVer) >> 24) & 0xffU ) +/** Get the minor version number from a VBOX_FULL_VERSION style number. */ +# define VBOX_FULL_VERSION_GET_MINOR(uFullVer) ( ((uFullVer) >> 16) & 0xffU ) +/** Get the build version number from a VBOX_FULL_VERSION style number. */ +# define VBOX_FULL_VERSION_GET_BUILD(uFullVer) ( ((uFullVer) ) & 0xffffU ) + +/** + * Make a short version number for use in 16 bit version fields. + * + * The returned number can be used in normal integer comparsions and will yield + * the expected results. + * + * @param uMajor The major version number. + * @param uMinor The minor version number. + * @returns Short version number. + */ +# define VBOX_SHORT_VERSION_MAKE(uMajor, uMinor) \ + ( (uint16_t)((uMajor) & 0xff) << 8 \ + | (uint16_t)((uMinor) & 0xff) \ + ) + +/** Combined short version number. */ +# define VBOX_SHORT_VERSION \ + VBOX_SHORT_VERSION_MAKE(VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR) +/** Get the major version number from a VBOX_SHORT_VERSION style number. */ +# define VBOX_SHORT_VERSION_GET_MAJOR(uShortVer) ( ((uShortVer) >> 8) & 0xffU ) +/** Get the minor version number from a VBOX_SHORT_VERSION style number. */ +# define VBOX_SHORT_VERSION_GET_MINOR(uShortVer) ( (uShortVer) & 0xffU ) + +#endif /* !RC_INVOKED */ + +/** @name Prefined strings for Windows resource files + * @{ */ +#define VBOX_RC_COMPANY_NAME VBOX_VENDOR +#define VBOX_RC_LEGAL_COPYRIGHT "Copyright (C) 2009-" VBOX_C_YEAR " Oracle Corporation\0" +#define VBOX_RC_PRODUCT_NAME VBOX_PRODUCT +#define VBOX_RC_PRODUCT_NAME_GA VBOX_PRODUCT " Guest Additions" +#define VBOX_RC_PRODUCT_NAME_PUEL_EXTPACK VBOX_PRODUCT " Extension Pack" +#define VBOX_RC_PRODUCT_NAME_DTRACE_EXTPACK VBOX_PRODUCT " VBoxDTrace Extension Pack" +#define VBOX_RC_PRODUCT_NAME_STR VBOX_RC_PRODUCT_NAME "\0" +#define VBOX_RC_PRODUCT_NAME_GA_STR VBOX_RC_PRODUCT_NAME_GA "\0" +#define VBOX_RC_PRODUCT_NAME_PUEL_EXTPACK_STR VBOX_RC_PRODUCT_NAME_PUEL_EXTPACK "\0" +#define VBOX_RC_PRODUCT_NAME_DTRACE_EXTPACK_STR VBOX_RC_PRODUCT_NAME_DTRACE_EXTPACK "\0" +#define VBOX_RC_PRODUCT_VERSION VBOX_VERSION_MAJOR , VBOX_VERSION_MINOR , VBOX_VERSION_BUILD , VBOX_SVN_REV_MOD_5K +#define VBOX_RC_FILE_VERSION VBOX_VERSION_MAJOR , VBOX_VERSION_MINOR , VBOX_VERSION_BUILD , VBOX_SVN_REV_MOD_5K +#ifndef VBOX_VERSION_PRERELEASE +# define VBOX_RC_PRODUCT_VERSION_STR RT_XSTR(VBOX_VERSION_MAJOR) "." RT_XSTR(VBOX_VERSION_MINOR) "." RT_XSTR(VBOX_VERSION_BUILD) "." RT_XSTR(VBOX_SVN_REV) "\0" +# define VBOX_RC_FILE_VERSION_STR RT_XSTR(VBOX_VERSION_MAJOR) "." RT_XSTR(VBOX_VERSION_MINOR) "." RT_XSTR(VBOX_VERSION_BUILD) "." RT_XSTR(VBOX_SVN_REV) "\0" +#else +# define VBOX_RC_PRODUCT_VERSION_STR RT_XSTR(VBOX_VERSION_MAJOR) "." RT_XSTR(VBOX_VERSION_MINOR) "." RT_XSTR(VBOX_VERSION_BUILD) "." RT_XSTR(VBOX_SVN_REV) " (" VBOX_VERSION_PRERELEASE ")\0" +# define VBOX_RC_FILE_VERSION_STR RT_XSTR(VBOX_VERSION_MAJOR) "." RT_XSTR(VBOX_VERSION_MINOR) "." RT_XSTR(VBOX_VERSION_BUILD) "." RT_XSTR(VBOX_SVN_REV) " (" VBOX_VERSION_PRERELEASE ")\0" +#endif +#define VBOX_RC_FILE_OS VOS_NT_WINDOWS32 +#define VBOX_RC_TYPE_DLL VFT_DLL +#define VBOX_RC_TYPE_APP VFT_APP +#define VBOX_RC_TYPE_DRV VFT_DRV +/* Flags and extra strings depending on the build type and who's building. */ +#if defined(DEBUG) || defined(LOG_ENABLED) || defined(RT_STRICT) || defined(VBOX_STRICT) || defined(VBOX_WITH_STATISTICS) +# define VBOX_RC_FILE_FLAGS_DEBUG VS_FF_DEBUG +#else +# define VBOX_RC_FILE_FLAGS_DEBUG 0 +#endif +#if VBOX_VERSION_MINOR >= 51 || defined(VBOX_VERSION_PRERELEASE) +# define VBOX_RC_FILE_FLAGS_PRERELEASE VS_FF_PRERELEASE +#else +# define VBOX_RC_FILE_FLAGS_PRERELEASE 0 +#endif +#if defined(VBOX_BUILD_SERVER_BUILD) && (VBOX_VERSION_MINOR & 1) == 0 +# define VBOX_RC_FILE_FLAGS_BUILD 0 +# define VBOX_RC_MORE_STRINGS +#elif defined(VBOX_BUILD_SERVER_BUILD) +# define VBOX_RC_FILE_FLAGS_BUILD VS_FF_SPECIALBUILD +# define VBOX_RC_MORE_STRINGS VALUE "SpecialBuild", "r" RT_XSTR(VBOX_SVN_REV) "\0" +#else +# define VBOX_RC_FILE_FLAGS_BUILD VS_FF_PRIVATEBUILD +# ifdef VBOX_PRIVATE_BUILD_DESC +# define VBOX_RC_MORE_STRINGS VALUE "PrivateBuild", VBOX_PRIVATE_BUILD_DESC "\0" +# else +# define VBOX_RC_MORE_STRINGS VALUE "PrivateBuild", "r" RT_XSTR(VBOX_SVN_REV) "\0" +# error +# endif +#endif +#define VBOX_RC_FILE_FLAGS (VBOX_RC_FILE_FLAGS_DEBUG | VBOX_RC_FILE_FLAGS_PRERELEASE | VBOX_RC_FILE_FLAGS_BUILD) +/** @} */ + +#endif /* !VBOX_INCLUDED_version_h */ + diff --git a/include/VBox/vmm/Makefile.kup b/include/VBox/vmm/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/VBox/vmm/Makefile.kup diff --git a/include/VBox/vmm/apic.h b/include/VBox/vmm/apic.h new file mode 100644 index 00000000..6e9c3673 --- /dev/null +++ b/include/VBox/vmm/apic.h @@ -0,0 +1,107 @@ +/** @file + * APIC - Advanced Programmable Interrupt Controller. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_apic_h +#define VBOX_INCLUDED_vmm_apic_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/apic.h> +struct PDMDEVREGCB; + +/** @defgroup grp_apic The local APIC VMM API + * @ingroup grp_vmm + * @{ + */ + +RT_C_DECLS_BEGIN + +#ifdef VBOX_INCLUDED_vmm_pdmdev_h +extern const PDMDEVREG g_DeviceAPIC; +#endif + +/* These functions are exported as they are called from external modules (recompiler). */ +VMMDECL(void) APICUpdatePendingInterrupts(PVMCPUCC pVCpu); +VMMDECL(int) APICGetTpr(PCVMCPUCC pVCpu, uint8_t *pu8Tpr, bool *pfPending, uint8_t *pu8PendingIntr); +VMMDECL(int) APICSetTpr(PVMCPUCC pVCpu, uint8_t u8Tpr); + +/* These functions are VMM internal. */ +VMM_INT_DECL(bool) APICIsEnabled(PCVMCPUCC pVCpu); +VMM_INT_DECL(bool) APICGetHighestPendingInterrupt(PVMCPUCC pVCpu, uint8_t *pu8PendingIntr); +VMM_INT_DECL(bool) APICQueueInterruptToService(PVMCPUCC pVCpu, uint8_t u8PendingIntr); +VMM_INT_DECL(void) APICDequeueInterruptFromService(PVMCPUCC pVCpu, uint8_t u8PendingIntr); +VMM_INT_DECL(VBOXSTRICTRC) APICReadMsr(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t *pu64Value); +VMM_INT_DECL(VBOXSTRICTRC) APICWriteMsr(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t u64Value); +VMM_INT_DECL(int) APICGetTimerFreq(PVMCC pVM, uint64_t *pu64Value); +VMM_INT_DECL(VBOXSTRICTRC) APICLocalInterrupt(PVMCPUCC pVCpu, uint8_t u8Pin, uint8_t u8Level, int rcRZ); +VMM_INT_DECL(uint64_t) APICGetBaseMsrNoCheck(PCVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) APICGetBaseMsr(PVMCPUCC pVCpu, uint64_t *pu64Value); +VMM_INT_DECL(int) APICSetBaseMsr(PVMCPUCC pVCpu, uint64_t u64BaseMsr); +VMM_INT_DECL(int) APICGetInterrupt(PVMCPUCC pVCpu, uint8_t *pu8Vector, uint32_t *pu32TagSrc); +VMM_INT_DECL(int) APICBusDeliver(PVMCC pVM, uint8_t uDest, uint8_t uDestMode, uint8_t uDeliveryMode, uint8_t uVector, + uint8_t uPolarity, uint8_t uTriggerMode, uint32_t uTagSrc); +VMM_INT_DECL(int) APICGetApicPageForCpu(PCVMCPUCC pVCpu, PRTHCPHYS pHCPhys, PRTR0PTR pR0Ptr, PRTR3PTR pR3Ptr); + +/** @name Hyper-V interface (Ring-3 and all-context API). + * @{ */ +#ifdef IN_RING3 +VMMR3_INT_DECL(void) APICR3HvSetCompatMode(PVM pVM, bool fHyperVCompatMode); +#endif +VMM_INT_DECL(void) APICHvSendInterrupt(PVMCPUCC pVCpu, uint8_t uVector, bool fAutoEoi, XAPICTRIGGERMODE enmTriggerMode); +VMM_INT_DECL(VBOXSTRICTRC) APICHvSetTpr(PVMCPUCC pVCpu, uint8_t uTpr); +VMM_INT_DECL(uint8_t) APICHvGetTpr(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) APICHvSetIcr(PVMCPUCC pVCpu, uint64_t uIcr); +VMM_INT_DECL(uint64_t) APICHvGetIcr(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) APICHvSetEoi(PVMCPUCC pVCpu, uint32_t uEoi); +/** @} */ + +#ifdef IN_RING3 +/** @defgroup grp_apic_r3 The APIC Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(int) APICR3RegisterDevice(struct PDMDEVREGCB *pCallbacks); +VMMR3_INT_DECL(void) APICR3InitIpi(PVMCPU pVCpu); +VMMR3_INT_DECL(void) APICR3HvEnable(PVM pVM); +/** @} */ +#endif /* IN_RING3 */ + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_apic_h */ + diff --git a/include/VBox/vmm/cfgm.h b/include/VBox/vmm/cfgm.h new file mode 100644 index 00000000..7a84dd94 --- /dev/null +++ b/include/VBox/vmm/cfgm.h @@ -0,0 +1,245 @@ +/** @file + * CFGM - Configuration Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cfgm_h +#define VBOX_INCLUDED_vmm_cfgm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/stdarg.h> + +/** @defgroup grp_cfgm The Configuration Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * Configuration manager value type. + */ +typedef enum CFGMVALUETYPE +{ + /** Integer value. */ + CFGMVALUETYPE_INTEGER = 1, + /** String value. */ + CFGMVALUETYPE_STRING, + /** Bytestring value. */ + CFGMVALUETYPE_BYTES, + /** Password value, same as String but hides the content in dump. */ + CFGMVALUETYPE_PASSWORD +} CFGMVALUETYPE; +/** Pointer to configuration manager property type. */ +typedef CFGMVALUETYPE *PCFGMVALUETYPE; + + + +RT_C_DECLS_BEGIN + +#ifdef IN_RING3 +/** @defgroup grp_cfgm_r3 The CFGM Host Context Ring-3 API + * @{ + */ + +typedef enum CFGMCONFIGTYPE +{ + /** pvConfig points to nothing, use defaults. */ + CFGMCONFIGTYPE_NONE = 0, + /** pvConfig points to a IMachine interface. */ + CFGMCONFIGTYPE_IMACHINE +} CFGMCONFIGTYPE; + + +/** + * CFGM init callback for constructing the configuration tree. + * + * This is called from the emulation thread, and the one interfacing the VM + * can make any necessary per-thread initializations at this point. + * + * @returns VBox status code. + * @param pUVM The user mode VM handle. + * @param pVM The cross context VM structure. + * @param pVMM The VMM R3 vtable. + * @param pvUser The argument supplied to VMR3Create(). + */ +typedef DECLCALLBACKTYPE(int, FNCFGMCONSTRUCTOR,(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNCFGMCONSTRUCTOR(). */ +typedef FNCFGMCONSTRUCTOR *PFNCFGMCONSTRUCTOR; + +VMMR3DECL(int) CFGMR3Init(PVM pVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUser); +VMMR3DECL(int) CFGMR3Term(PVM pVM); +VMMR3DECL(int) CFGMR3ConstructDefaultTree(PVM pVM); + +VMMR3DECL(PCFGMNODE) CFGMR3CreateTree(PUVM pUVM); +VMMR3DECL(int) CFGMR3DestroyTree(PCFGMNODE pRoot); +VMMR3DECL(void) CFGMR3Dump(PCFGMNODE pRoot); +VMMR3DECL(int) CFGMR3DuplicateSubTree(PCFGMNODE pRoot, PCFGMNODE *ppCopy); +VMMR3DECL(int) CFGMR3ReplaceSubTree(PCFGMNODE pRoot, PCFGMNODE pNewRoot); +VMMR3DECL(int) CFGMR3InsertSubTree(PCFGMNODE pNode, const char *pszName, PCFGMNODE pSubTree, PCFGMNODE *ppChild); +VMMR3DECL(int) CFGMR3InsertNode(PCFGMNODE pNode, const char *pszName, PCFGMNODE *ppChild); +VMMR3DECL(int) CFGMR3InsertNodeF(PCFGMNODE pNode, PCFGMNODE *ppChild, + const char *pszNameFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); +VMMR3DECL(int) CFGMR3InsertNodeFV(PCFGMNODE pNode, PCFGMNODE *ppChild, + const char *pszNameFormat, va_list Args) RT_IPRT_FORMAT_ATTR(3, 0); +VMMR3DECL(void) CFGMR3SetRestrictedRoot(PCFGMNODE pNode); +VMMR3DECL(void) CFGMR3RemoveNode(PCFGMNODE pNode); +VMMR3DECL(int) CFGMR3InsertInteger(PCFGMNODE pNode, const char *pszName, uint64_t u64Integer); +VMMR3DECL(int) CFGMR3InsertString(PCFGMNODE pNode, const char *pszName, const char *pszString); +VMMR3DECL(int) CFGMR3InsertStringN(PCFGMNODE pNode, const char *pszName, const char *pszString, size_t cchString); +VMMR3DECL(int) CFGMR3InsertStringF(PCFGMNODE pNode, const char *pszName, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); +VMMR3DECL(int) CFGMR3InsertStringFV(PCFGMNODE pNode, const char *pszName, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); +VMMR3DECL(int) CFGMR3InsertStringW(PCFGMNODE pNode, const char *pszName, PCRTUTF16 pwszValue); +VMMR3DECL(int) CFGMR3InsertBytes(PCFGMNODE pNode, const char *pszName, const void *pvBytes, size_t cbBytes); +VMMR3DECL(int) CFGMR3InsertPassword(PCFGMNODE pNode, const char *pszName, const char *pszString); +VMMR3DECL(int) CFGMR3InsertPasswordN(PCFGMNODE pNode, const char *pszName, const char *pszString, size_t cchString); +VMMR3DECL(int) CFGMR3InsertValue(PCFGMNODE pNode, PCFGMLEAF pValue); +VMMR3DECL(int) CFGMR3RemoveValue(PCFGMNODE pNode, const char *pszName); + +/** @name CFGMR3CopyTree flags. + * @{ */ +/** Reserved value disposition \#0. */ +#define CFGM_COPY_FLAGS_RESERVED_VALUE_DISP_0 UINT32_C(0x00000000) +/** Reserved value disposition \#1. */ +#define CFGM_COPY_FLAGS_RESERVED_VALUE_DISP_1 UINT32_C(0x00000001) +/** Replace exiting values. */ +#define CFGM_COPY_FLAGS_REPLACE_VALUES UINT32_C(0x00000002) +/** Ignore exiting values. */ +#define CFGM_COPY_FLAGS_IGNORE_EXISTING_VALUES UINT32_C(0x00000003) +/** Value disposition mask. */ +#define CFGM_COPY_FLAGS_VALUE_DISP_MASK UINT32_C(0x00000003) + +/** Replace exiting keys. */ +#define CFGM_COPY_FLAGS_RESERVED_KEY_DISP UINT32_C(0x00000000) +/** Replace exiting keys. */ +#define CFGM_COPY_FLAGS_MERGE_KEYS UINT32_C(0x00000010) +/** Replace exiting keys. */ +#define CFGM_COPY_FLAGS_REPLACE_KEYS UINT32_C(0x00000020) +/** Ignore existing keys. */ +#define CFGM_COPY_FLAGS_IGNORE_EXISTING_KEYS UINT32_C(0x00000030) +/** Key disposition. */ +#define CFGM_COPY_FLAGS_KEY_DISP_MASK UINT32_C(0x00000030) +/** @} */ +VMMR3DECL(int) CFGMR3CopyTree(PCFGMNODE pDstTree, PCFGMNODE pSrcTree, uint32_t fFlags); + +VMMR3DECL(bool) CFGMR3Exists( PCFGMNODE pNode, const char *pszName); +VMMR3DECL(int) CFGMR3QueryType( PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType); +VMMR3DECL(int) CFGMR3QuerySize( PCFGMNODE pNode, const char *pszName, size_t *pcb); +VMMR3DECL(int) CFGMR3QueryInteger( PCFGMNODE pNode, const char *pszName, uint64_t *pu64); +VMMR3DECL(int) CFGMR3QueryIntegerDef( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def); +VMMR3DECL(int) CFGMR3QueryString( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString); +VMMR3DECL(int) CFGMR3QueryStringDef( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef); +VMMR3DECL(int) CFGMR3QueryPassword( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString); +VMMR3DECL(int) CFGMR3QueryPasswordDef( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef); +VMMR3DECL(int) CFGMR3QueryBytes( PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData); + + +/** @name Helpers + * @{ + */ +VMMR3DECL(int) CFGMR3QueryU64( PCFGMNODE pNode, const char *pszName, uint64_t *pu64); +VMMR3DECL(int) CFGMR3QueryU64Def( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def); +VMMR3DECL(int) CFGMR3QueryS64( PCFGMNODE pNode, const char *pszName, int64_t *pi64); +VMMR3DECL(int) CFGMR3QueryS64Def( PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def); +VMMR3DECL(int) CFGMR3QueryU32( PCFGMNODE pNode, const char *pszName, uint32_t *pu32); +VMMR3DECL(int) CFGMR3QueryU32Def( PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def); +VMMR3DECL(int) CFGMR3QueryS32( PCFGMNODE pNode, const char *pszName, int32_t *pi32); +VMMR3DECL(int) CFGMR3QueryS32Def( PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def); +VMMR3DECL(int) CFGMR3QueryU16( PCFGMNODE pNode, const char *pszName, uint16_t *pu16); +VMMR3DECL(int) CFGMR3QueryU16Def( PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def); +VMMR3DECL(int) CFGMR3QueryS16( PCFGMNODE pNode, const char *pszName, int16_t *pi16); +VMMR3DECL(int) CFGMR3QueryS16Def( PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def); +VMMR3DECL(int) CFGMR3QueryU8( PCFGMNODE pNode, const char *pszName, uint8_t *pu8); +VMMR3DECL(int) CFGMR3QueryU8Def( PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def); +VMMR3DECL(int) CFGMR3QueryS8( PCFGMNODE pNode, const char *pszName, int8_t *pi8); +VMMR3DECL(int) CFGMR3QueryS8Def( PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def); +VMMR3DECL(int) CFGMR3QueryBool( PCFGMNODE pNode, const char *pszName, bool *pf); +VMMR3DECL(int) CFGMR3QueryBoolDef( PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef); +VMMR3DECL(int) CFGMR3QueryPort( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort); +VMMR3DECL(int) CFGMR3QueryPortDef( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef); +VMMR3DECL(int) CFGMR3QueryUInt( PCFGMNODE pNode, const char *pszName, unsigned int *pu); +VMMR3DECL(int) CFGMR3QueryUIntDef( PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef); +VMMR3DECL(int) CFGMR3QuerySInt( PCFGMNODE pNode, const char *pszName, signed int *pi); +VMMR3DECL(int) CFGMR3QuerySIntDef( PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef); +VMMR3DECL(int) CFGMR3QueryGCPtr( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr); +VMMR3DECL(int) CFGMR3QueryGCPtrDef( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef); +VMMR3DECL(int) CFGMR3QueryGCPtrU( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr); +VMMR3DECL(int) CFGMR3QueryGCPtrUDef( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef); +VMMR3DECL(int) CFGMR3QueryGCPtrS( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr); +VMMR3DECL(int) CFGMR3QueryGCPtrSDef( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef); +VMMR3DECL(int) CFGMR3QueryStringAlloc( PCFGMNODE pNode, const char *pszName, char **ppszString); +VMMR3DECL(int) CFGMR3QueryStringAllocDef(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef); + +/** @} */ + +/** @name Tree Navigation and Enumeration. + * @{ + */ +VMMR3DECL(PCFGMNODE) CFGMR3GetRoot(PVM pVM); +VMMR3DECL(PCFGMNODE) CFGMR3GetRootU(PUVM pUVM); +VMMR3DECL(PCFGMNODE) CFGMR3GetParent(PCFGMNODE pNode); +VMMR3DECL(PCFGMNODE) CFGMR3GetParentEx(PVM pVM, PCFGMNODE pNode); +VMMR3DECL(PCFGMNODE) CFGMR3GetChild(PCFGMNODE pNode, const char *pszPath); +VMMR3DECL(PCFGMNODE) CFGMR3GetChildF(PCFGMNODE pNode, const char *pszPathFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); +VMMR3DECL(PCFGMNODE) CFGMR3GetChildFV(PCFGMNODE pNode, const char *pszPathFormat, va_list Args) RT_IPRT_FORMAT_ATTR(3, 0); +VMMR3DECL(PCFGMNODE) CFGMR3GetFirstChild(PCFGMNODE pNode); +VMMR3DECL(PCFGMNODE) CFGMR3GetNextChild(PCFGMNODE pCur); +VMMR3DECL(int) CFGMR3GetName(PCFGMNODE pCur, char *pszName, size_t cchName); +VMMR3DECL(size_t) CFGMR3GetNameLen(PCFGMNODE pCur); +VMMR3DECL(bool) CFGMR3AreChildrenValid(PCFGMNODE pNode, const char *pszzValid); +VMMR3DECL(PCFGMLEAF) CFGMR3GetFirstValue(PCFGMNODE pCur); +VMMR3DECL(PCFGMLEAF) CFGMR3GetNextValue(PCFGMLEAF pCur); +VMMR3DECL(int) CFGMR3GetValueName(PCFGMLEAF pCur, char *pszName, size_t cchName); +VMMR3DECL(size_t) CFGMR3GetValueNameLen(PCFGMLEAF pCur); +VMMR3DECL(CFGMVALUETYPE) CFGMR3GetValueType(PCFGMLEAF pCur); +VMMR3DECL(bool) CFGMR3AreValuesValid(PCFGMNODE pNode, const char *pszzValid); +VMMR3DECL(int) CFGMR3ValidateConfig(PCFGMNODE pNode, const char *pszNode, + const char *pszValidValues, const char *pszValidNodes, + const char *pszWho, uint32_t uInstance); + +/** @} */ + + +/** @} */ +#endif /* IN_RING3 */ + + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_cfgm_h */ + diff --git a/include/VBox/vmm/cpuidcall.h b/include/VBox/vmm/cpuidcall.h new file mode 100644 index 00000000..8bcdb8da --- /dev/null +++ b/include/VBox/vmm/cpuidcall.h @@ -0,0 +1,107 @@ +/** @file + * VM - The Virtual Machine, CPU Host Call Interface (AMD64 & x86 only). + * + * @note cpuidcall.mac is generated from this file by running 'kmk incs' in the root. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cpuidcall_h +#define VBOX_INCLUDED_vmm_cpuidcall_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + + +/** @defgroup grp_cpuidcall VBox CPUID Host Call Interface (AMD64 & x86) + * + * This describes an interface using CPUID for calling the host from within the + * VM. This is chiefly intended for nested VM debugging at present and is + * therefore disabled by default. + * + * @{ */ + +/** Fixed EAX value for all requests (big-endian 'VBox'). */ +#define VBOX_CPUID_REQ_EAX_FIXED UINT32_C(0x56426f78) +/** Fixed portion of ECX for all requests. */ +#define VBOX_CPUID_REQ_ECX_FIXED UINT32_C(0xc0de0000) +/** Fixed portion of ECX for all requests. */ +#define VBOX_CPUID_REQ_ECX_FIXED_MASK UINT32_C(0xffff0000) +/** Function part of ECX for requests. */ +#define VBOX_CPUID_REQ_ECX_FN_MASK UINT32_C(0x0000ffff) + +/** Generic ECX return value. */ +#define VBOX_CPUID_RESP_GEN_ECX UINT32_C(0x19410612) +/** Generic EDX return value. */ +#define VBOX_CPUID_RESP_GEN_EDX UINT32_C(0x19400412) +/** Generic EBX return value. */ +#define VBOX_CPUID_RESP_GEN_EBX UINT32_C(0x19450508) + +/** @name Function \#1: Interface ID check and max function. + * + * Input: EDX & EBX content is unused and ignored. Best set to zero. + * + * Result: EAX:EDX:EBX forms the little endian string "VBox RuleZ!\0". + * ECX contains the max function number acccepted. + * @{ */ +#define VBOX_CPUID_FN_ID UINT32_C(0x0001) +#define VBOX_CPUID_RESP_ID_EAX UINT32_C(0x786f4256) +#define VBOX_CPUID_RESP_ID_EDX UINT32_C(0x6c755220) +#define VBOX_CPUID_RESP_ID_EBX UINT32_C(0x00215A65) +#define VBOX_CPUID_RESP_ID_ECX UINT32_C(0x00000002) +/** @} */ + +/** Function \#2: Write string to host Log. + * + * Input: EDX gives the number of bytes to log (max 2MB). + * EBX indicates the log to write to: 0 for debug, 1 for release. + * RSI is the FLAT pointer to the UTF-8 string to log. + * + * Output: EAX contains IPRT status code. ECX, EDX and EBX are set to the + * generic their response values (VBOX_CPUID_RESP_GEN_XXX). RSI is + * advanced EDX bytes on success. + * + * Except: May raise \#PF when reading the string. RSI and EDX is then be + * updated to the point where the page fault triggered, allowing paging + * in of logging buffer and such like. + * + * @note Buffer is not accessed if the target logger isn't enabled. + */ +#define VBOX_CPUID_FN_LOG UINT32_C(0x0002) + + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_cpuidcall_h */ + diff --git a/include/VBox/vmm/cpuidcall.mac b/include/VBox/vmm/cpuidcall.mac new file mode 100644 index 00000000..5965550c --- /dev/null +++ b/include/VBox/vmm/cpuidcall.mac @@ -0,0 +1,55 @@ +;; @file +; VM - The Virtual Machine, CPU Host Call Interface (AMD64 & x86 only). +; +; Automatically generated by various.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef VBOX_INCLUDED_vmm_cpuidcall_h +%define VBOX_INCLUDED_vmm_cpuidcall_h +%ifndef RT_WITHOUT_PRAGMA_ONCE +%endif +%define VBOX_CPUID_REQ_EAX_FIXED 0x56426f78 +%define VBOX_CPUID_REQ_ECX_FIXED 0xc0de0000 +%define VBOX_CPUID_REQ_ECX_FIXED_MASK 0xffff0000 +%define VBOX_CPUID_REQ_ECX_FN_MASK 0x0000ffff +%define VBOX_CPUID_RESP_GEN_ECX 0x19410612 +%define VBOX_CPUID_RESP_GEN_EDX 0x19400412 +%define VBOX_CPUID_RESP_GEN_EBX 0x19450508 +%define VBOX_CPUID_FN_ID 0x0001 +%define VBOX_CPUID_RESP_ID_EAX 0x786f4256 +%define VBOX_CPUID_RESP_ID_EDX 0x6c755220 +%define VBOX_CPUID_RESP_ID_EBX 0x00215A65 +%define VBOX_CPUID_RESP_ID_ECX 0x00000002 +%define VBOX_CPUID_FN_LOG 0x0002 +%endif diff --git a/include/VBox/vmm/cpum.h b/include/VBox/vmm/cpum.h new file mode 100644 index 00000000..1f5f28e3 --- /dev/null +++ b/include/VBox/vmm/cpum.h @@ -0,0 +1,3248 @@ +/** @file + * CPUM - CPU Monitor(/ Manager). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cpum_h +#define VBOX_INCLUDED_vmm_cpum_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/x86.h> +#include <VBox/types.h> +#include <VBox/vmm/cpumctx.h> +#include <VBox/vmm/stam.h> +#include <VBox/vmm/vmapi.h> +#include <VBox/vmm/hm_svm.h> +#include <VBox/vmm/hm_vmx.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_cpum The CPU Monitor / Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * CPUID feature to set or clear. + */ +typedef enum CPUMCPUIDFEATURE +{ + CPUMCPUIDFEATURE_INVALID = 0, + /** The APIC feature bit. (Std+Ext) + * Note! There is a per-cpu flag for masking this CPUID feature bit when the + * APICBASE.ENABLED bit is zero. So, this feature is only set/cleared + * at VM construction time like all the others. This didn't used to be + * that way, this is new with 5.1. */ + CPUMCPUIDFEATURE_APIC, + /** The sysenter/sysexit feature bit. (Std) */ + CPUMCPUIDFEATURE_SEP, + /** The SYSCALL/SYSEXIT feature bit (64 bits mode only for Intel CPUs). (Ext) */ + CPUMCPUIDFEATURE_SYSCALL, + /** The PAE feature bit. (Std+Ext) */ + CPUMCPUIDFEATURE_PAE, + /** The NX feature bit. (Ext) */ + CPUMCPUIDFEATURE_NX, + /** The LAHF/SAHF feature bit (64 bits mode only). (Ext) */ + CPUMCPUIDFEATURE_LAHF, + /** The LONG MODE feature bit. (Ext) */ + CPUMCPUIDFEATURE_LONG_MODE, + /** The x2APIC feature bit. (Std) */ + CPUMCPUIDFEATURE_X2APIC, + /** The RDTSCP feature bit. (Ext) */ + CPUMCPUIDFEATURE_RDTSCP, + /** The Hypervisor Present bit. (Std) */ + CPUMCPUIDFEATURE_HVP, + /** The speculation control feature bits. (StExt) */ + CPUMCPUIDFEATURE_SPEC_CTRL, + /** 32bit hackishness. */ + CPUMCPUIDFEATURE_32BIT_HACK = 0x7fffffff +} CPUMCPUIDFEATURE; + +/** + * CPU Vendor. + */ +typedef enum CPUMCPUVENDOR +{ + CPUMCPUVENDOR_INVALID = 0, + CPUMCPUVENDOR_INTEL, + CPUMCPUVENDOR_AMD, + CPUMCPUVENDOR_VIA, + CPUMCPUVENDOR_CYRIX, + CPUMCPUVENDOR_SHANGHAI, + CPUMCPUVENDOR_HYGON, + CPUMCPUVENDOR_UNKNOWN, + /** 32bit hackishness. */ + CPUMCPUVENDOR_32BIT_HACK = 0x7fffffff +} CPUMCPUVENDOR; + + +/** + * X86 and AMD64 CPU microarchitectures and in processor generations. + * + * @remarks The separation here is sometimes a little bit too finely grained, + * and the differences is more like processor generation than micro + * arch. This can be useful, so we'll provide functions for getting at + * more coarse grained info. + */ +typedef enum CPUMMICROARCH +{ + kCpumMicroarch_Invalid = 0, + + kCpumMicroarch_Intel_First, + + kCpumMicroarch_Intel_8086 = kCpumMicroarch_Intel_First, + kCpumMicroarch_Intel_80186, + kCpumMicroarch_Intel_80286, + kCpumMicroarch_Intel_80386, + kCpumMicroarch_Intel_80486, + kCpumMicroarch_Intel_P5, + + kCpumMicroarch_Intel_P6_Core_Atom_First, + kCpumMicroarch_Intel_P6 = kCpumMicroarch_Intel_P6_Core_Atom_First, + kCpumMicroarch_Intel_P6_II, + kCpumMicroarch_Intel_P6_III, + + kCpumMicroarch_Intel_P6_M_Banias, + kCpumMicroarch_Intel_P6_M_Dothan, + kCpumMicroarch_Intel_Core_Yonah, /**< Core, also known as Enhanced Pentium M. */ + + kCpumMicroarch_Intel_Core2_First, + kCpumMicroarch_Intel_Core2_Merom = kCpumMicroarch_Intel_Core2_First, /**< 65nm, Merom/Conroe/Kentsfield/Tigerton */ + kCpumMicroarch_Intel_Core2_Penryn, /**< 45nm, Penryn/Wolfdale/Yorkfield/Harpertown */ + kCpumMicroarch_Intel_Core2_End, + + kCpumMicroarch_Intel_Core7_First, + kCpumMicroarch_Intel_Core7_Nehalem = kCpumMicroarch_Intel_Core7_First, + kCpumMicroarch_Intel_Core7_Westmere, + kCpumMicroarch_Intel_Core7_SandyBridge, + kCpumMicroarch_Intel_Core7_IvyBridge, + kCpumMicroarch_Intel_Core7_Haswell, + kCpumMicroarch_Intel_Core7_Broadwell, + kCpumMicroarch_Intel_Core7_Skylake, + kCpumMicroarch_Intel_Core7_KabyLake, + kCpumMicroarch_Intel_Core7_CoffeeLake, + kCpumMicroarch_Intel_Core7_WhiskeyLake, + kCpumMicroarch_Intel_Core7_CascadeLake, + kCpumMicroarch_Intel_Core7_CannonLake, /**< Limited 10nm. */ + kCpumMicroarch_Intel_Core7_CometLake, /**< 10th gen, 14nm desktop + high power mobile. */ + kCpumMicroarch_Intel_Core7_IceLake, /**< 10th gen, 10nm mobile and some Xeons. Actually 'Sunny Cove' march. */ + kCpumMicroarch_Intel_Core7_SunnyCove = kCpumMicroarch_Intel_Core7_IceLake, + kCpumMicroarch_Intel_Core7_RocketLake, /**< 11th gen, 14nm desktop + high power mobile. Aka 'Cypress Cove', backport of 'Willow Cove' to 14nm. */ + kCpumMicroarch_Intel_Core7_CypressCove = kCpumMicroarch_Intel_Core7_RocketLake, + kCpumMicroarch_Intel_Core7_TigerLake, /**< 11th gen, 10nm mobile. Actually 'Willow Cove' march. */ + kCpumMicroarch_Intel_Core7_WillowCove = kCpumMicroarch_Intel_Core7_TigerLake, + kCpumMicroarch_Intel_Core7_AlderLake, /**< 12th gen, 10nm all platforms(?). */ + kCpumMicroarch_Intel_Core7_SapphireRapids, /**< 12th? gen, 10nm server? */ + kCpumMicroarch_Intel_Core7_End, + + kCpumMicroarch_Intel_Atom_First, + kCpumMicroarch_Intel_Atom_Bonnell = kCpumMicroarch_Intel_Atom_First, + kCpumMicroarch_Intel_Atom_Lincroft, /**< Second generation bonnell (44nm). */ + kCpumMicroarch_Intel_Atom_Saltwell, /**< 32nm shrink of Bonnell. */ + kCpumMicroarch_Intel_Atom_Silvermont, /**< 22nm */ + kCpumMicroarch_Intel_Atom_Airmount, /**< 14nm */ + kCpumMicroarch_Intel_Atom_Goldmont, /**< 14nm */ + kCpumMicroarch_Intel_Atom_GoldmontPlus, /**< 14nm */ + kCpumMicroarch_Intel_Atom_Unknown, + kCpumMicroarch_Intel_Atom_End, + + + kCpumMicroarch_Intel_Phi_First, + kCpumMicroarch_Intel_Phi_KnightsFerry = kCpumMicroarch_Intel_Phi_First, + kCpumMicroarch_Intel_Phi_KnightsCorner, + kCpumMicroarch_Intel_Phi_KnightsLanding, + kCpumMicroarch_Intel_Phi_KnightsHill, + kCpumMicroarch_Intel_Phi_KnightsMill, + kCpumMicroarch_Intel_Phi_End, + + kCpumMicroarch_Intel_P6_Core_Atom_End, + + kCpumMicroarch_Intel_NB_First, + kCpumMicroarch_Intel_NB_Willamette = kCpumMicroarch_Intel_NB_First, /**< 180nm */ + kCpumMicroarch_Intel_NB_Northwood, /**< 130nm */ + kCpumMicroarch_Intel_NB_Prescott, /**< 90nm */ + kCpumMicroarch_Intel_NB_Prescott2M, /**< 90nm */ + kCpumMicroarch_Intel_NB_CedarMill, /**< 65nm */ + kCpumMicroarch_Intel_NB_Gallatin, /**< 90nm Xeon, Pentium 4 Extreme Edition ("Emergency Edition"). */ + kCpumMicroarch_Intel_NB_Unknown, + kCpumMicroarch_Intel_NB_End, + + kCpumMicroarch_Intel_Unknown, + kCpumMicroarch_Intel_End, + + kCpumMicroarch_AMD_First, + kCpumMicroarch_AMD_Am286 = kCpumMicroarch_AMD_First, + kCpumMicroarch_AMD_Am386, + kCpumMicroarch_AMD_Am486, + kCpumMicroarch_AMD_Am486Enh, /**< Covers Am5x86 as well. */ + kCpumMicroarch_AMD_K5, + kCpumMicroarch_AMD_K6, + + kCpumMicroarch_AMD_K7_First, + kCpumMicroarch_AMD_K7_Palomino = kCpumMicroarch_AMD_K7_First, + kCpumMicroarch_AMD_K7_Spitfire, + kCpumMicroarch_AMD_K7_Thunderbird, + kCpumMicroarch_AMD_K7_Morgan, + kCpumMicroarch_AMD_K7_Thoroughbred, + kCpumMicroarch_AMD_K7_Barton, + kCpumMicroarch_AMD_K7_Unknown, + kCpumMicroarch_AMD_K7_End, + + kCpumMicroarch_AMD_K8_First, + kCpumMicroarch_AMD_K8_130nm = kCpumMicroarch_AMD_K8_First, /**< 130nm Clawhammer, Sledgehammer, Newcastle, Paris, Odessa, Dublin */ + kCpumMicroarch_AMD_K8_90nm, /**< 90nm shrink */ + kCpumMicroarch_AMD_K8_90nm_DualCore, /**< 90nm with two cores. */ + kCpumMicroarch_AMD_K8_90nm_AMDV, /**< 90nm with AMD-V (usually) and two cores (usually). */ + kCpumMicroarch_AMD_K8_65nm, /**< 65nm shrink. */ + kCpumMicroarch_AMD_K8_End, + + kCpumMicroarch_AMD_K10, + kCpumMicroarch_AMD_K10_Lion, + kCpumMicroarch_AMD_K10_Llano, + kCpumMicroarch_AMD_Bobcat, + kCpumMicroarch_AMD_Jaguar, + + kCpumMicroarch_AMD_15h_First, + kCpumMicroarch_AMD_15h_Bulldozer = kCpumMicroarch_AMD_15h_First, + kCpumMicroarch_AMD_15h_Piledriver, + kCpumMicroarch_AMD_15h_Steamroller, /**< Yet to be released, might have different family. */ + kCpumMicroarch_AMD_15h_Excavator, /**< Yet to be released, might have different family. */ + kCpumMicroarch_AMD_15h_Unknown, + kCpumMicroarch_AMD_15h_End, + + kCpumMicroarch_AMD_16h_First, + kCpumMicroarch_AMD_16h_End, + + kCpumMicroarch_AMD_Zen_First, + kCpumMicroarch_AMD_Zen_Ryzen = kCpumMicroarch_AMD_Zen_First, + kCpumMicroarch_AMD_Zen_End, + + kCpumMicroarch_AMD_Unknown, + kCpumMicroarch_AMD_End, + + kCpumMicroarch_Hygon_First, + kCpumMicroarch_Hygon_Dhyana = kCpumMicroarch_Hygon_First, + kCpumMicroarch_Hygon_Unknown, + kCpumMicroarch_Hygon_End, + + kCpumMicroarch_VIA_First, + kCpumMicroarch_Centaur_C6 = kCpumMicroarch_VIA_First, + kCpumMicroarch_Centaur_C2, + kCpumMicroarch_Centaur_C3, + kCpumMicroarch_VIA_C3_M2, + kCpumMicroarch_VIA_C3_C5A, /**< 180nm Samuel - Cyrix III, C3, 1GigaPro. */ + kCpumMicroarch_VIA_C3_C5B, /**< 150nm Samuel 2 - Cyrix III, C3, 1GigaPro, Eden ESP, XP 2000+. */ + kCpumMicroarch_VIA_C3_C5C, /**< 130nm Ezra - C3, Eden ESP. */ + kCpumMicroarch_VIA_C3_C5N, /**< 130nm Ezra-T - C3. */ + kCpumMicroarch_VIA_C3_C5XL, /**< 130nm Nehemiah - C3, Eden ESP, Eden-N. */ + kCpumMicroarch_VIA_C3_C5P, /**< 130nm Nehemiah+ - C3. */ + kCpumMicroarch_VIA_C7_C5J, /**< 90nm Esther - C7, C7-D, C7-M, Eden, Eden ULV. */ + kCpumMicroarch_VIA_Isaiah, + kCpumMicroarch_VIA_Unknown, + kCpumMicroarch_VIA_End, + + kCpumMicroarch_Shanghai_First, + kCpumMicroarch_Shanghai_Wudaokou = kCpumMicroarch_Shanghai_First, + kCpumMicroarch_Shanghai_Unknown, + kCpumMicroarch_Shanghai_End, + + kCpumMicroarch_Cyrix_First, + kCpumMicroarch_Cyrix_5x86 = kCpumMicroarch_Cyrix_First, + kCpumMicroarch_Cyrix_M1, + kCpumMicroarch_Cyrix_MediaGX, + kCpumMicroarch_Cyrix_MediaGXm, + kCpumMicroarch_Cyrix_M2, + kCpumMicroarch_Cyrix_Unknown, + kCpumMicroarch_Cyrix_End, + + kCpumMicroarch_NEC_First, + kCpumMicroarch_NEC_V20 = kCpumMicroarch_NEC_First, + kCpumMicroarch_NEC_V30, + kCpumMicroarch_NEC_End, + + kCpumMicroarch_Unknown, + + kCpumMicroarch_32BitHack = 0x7fffffff +} CPUMMICROARCH; + + +/** Predicate macro for catching netburst CPUs. */ +#define CPUMMICROARCH_IS_INTEL_NETBURST(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_Intel_NB_First && (a_enmMicroarch) <= kCpumMicroarch_Intel_NB_End) + +/** Predicate macro for catching Core7 CPUs. */ +#define CPUMMICROARCH_IS_INTEL_CORE7(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_Intel_Core7_First && (a_enmMicroarch) <= kCpumMicroarch_Intel_Core7_End) + +/** Predicate macro for catching Core 2 CPUs. */ +#define CPUMMICROARCH_IS_INTEL_CORE2(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_Intel_Core2_First && (a_enmMicroarch) <= kCpumMicroarch_Intel_Core2_End) + +/** Predicate macro for catching Atom CPUs, Silvermont and upwards. */ +#define CPUMMICROARCH_IS_INTEL_SILVERMONT_PLUS(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_Intel_Atom_Silvermont && (a_enmMicroarch) <= kCpumMicroarch_Intel_Atom_End) + +/** Predicate macro for catching AMD Family OFh CPUs (aka K8). */ +#define CPUMMICROARCH_IS_AMD_FAM_0FH(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_AMD_K8_First && (a_enmMicroarch) <= kCpumMicroarch_AMD_K8_End) + +/** Predicate macro for catching AMD Family 10H CPUs (aka K10). */ +#define CPUMMICROARCH_IS_AMD_FAM_10H(a_enmMicroarch) ((a_enmMicroarch) == kCpumMicroarch_AMD_K10) + +/** Predicate macro for catching AMD Family 11H CPUs (aka Lion). */ +#define CPUMMICROARCH_IS_AMD_FAM_11H(a_enmMicroarch) ((a_enmMicroarch) == kCpumMicroarch_AMD_K10_Lion) + +/** Predicate macro for catching AMD Family 12H CPUs (aka Llano). */ +#define CPUMMICROARCH_IS_AMD_FAM_12H(a_enmMicroarch) ((a_enmMicroarch) == kCpumMicroarch_AMD_K10_Llano) + +/** Predicate macro for catching AMD Family 14H CPUs (aka Bobcat). */ +#define CPUMMICROARCH_IS_AMD_FAM_14H(a_enmMicroarch) ((a_enmMicroarch) == kCpumMicroarch_AMD_Bobcat) + +/** Predicate macro for catching AMD Family 15H CPUs (bulldozer and it's + * decendants). */ +#define CPUMMICROARCH_IS_AMD_FAM_15H(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_AMD_15h_First && (a_enmMicroarch) <= kCpumMicroarch_AMD_15h_End) + +/** Predicate macro for catching AMD Family 16H CPUs. */ +#define CPUMMICROARCH_IS_AMD_FAM_16H(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_AMD_16h_First && (a_enmMicroarch) <= kCpumMicroarch_AMD_16h_End) + +/** Predicate macro for catching AMD Zen Family CPUs. */ +#define CPUMMICROARCH_IS_AMD_FAM_ZEN(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_AMD_Zen_First && (a_enmMicroarch) <= kCpumMicroarch_AMD_Zen_End) + + +/** + * CPUID leaf. + * + * @remarks This structure is used by the patch manager and is therefore + * more or less set in stone. + */ +typedef struct CPUMCPUIDLEAF +{ + /** The leaf number. */ + uint32_t uLeaf; + /** The sub-leaf number. */ + uint32_t uSubLeaf; + /** Sub-leaf mask. This is 0 when sub-leaves aren't used. */ + uint32_t fSubLeafMask; + + /** The EAX value. */ + uint32_t uEax; + /** The EBX value. */ + uint32_t uEbx; + /** The ECX value. */ + uint32_t uEcx; + /** The EDX value. */ + uint32_t uEdx; + + /** Flags. */ + uint32_t fFlags; +} CPUMCPUIDLEAF; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMCPUIDLEAF, 32); +#endif +/** Pointer to a CPUID leaf. */ +typedef CPUMCPUIDLEAF *PCPUMCPUIDLEAF; +/** Pointer to a const CPUID leaf. */ +typedef CPUMCPUIDLEAF const *PCCPUMCPUIDLEAF; + +/** @name CPUMCPUIDLEAF::fFlags + * @{ */ +/** Indicates working intel leaf 0xb where the lower 8 ECX bits are not modified + * and EDX containing the extended APIC ID. */ +#define CPUMCPUIDLEAF_F_INTEL_TOPOLOGY_SUBLEAVES RT_BIT_32(0) +/** The leaf contains an APIC ID that needs changing to that of the current CPU. */ +#define CPUMCPUIDLEAF_F_CONTAINS_APIC_ID RT_BIT_32(1) +/** The leaf contains an OSXSAVE which needs individual handling on each CPU. */ +#define CPUMCPUIDLEAF_F_CONTAINS_OSXSAVE RT_BIT_32(2) +/** The leaf contains an APIC feature bit which is tied to APICBASE.EN. */ +#define CPUMCPUIDLEAF_F_CONTAINS_APIC RT_BIT_32(3) +/** Mask of the valid flags. */ +#define CPUMCPUIDLEAF_F_VALID_MASK UINT32_C(0xf) +/** @} */ + +/** + * Method used to deal with unknown CPUID leaves. + * @remarks Used in patch code. + */ +typedef enum CPUMUNKNOWNCPUID +{ + /** Invalid zero value. */ + CPUMUNKNOWNCPUID_INVALID = 0, + /** Use given default values (DefCpuId). */ + CPUMUNKNOWNCPUID_DEFAULTS, + /** Return the last standard leaf. + * Intel Sandy Bridge has been observed doing this. */ + CPUMUNKNOWNCPUID_LAST_STD_LEAF, + /** Return the last standard leaf, with ecx observed. + * Intel Sandy Bridge has been observed doing this. */ + CPUMUNKNOWNCPUID_LAST_STD_LEAF_WITH_ECX, + /** The register values are passed thru unmodified. */ + CPUMUNKNOWNCPUID_PASSTHRU, + /** End of valid value. */ + CPUMUNKNOWNCPUID_END, + /** Ensure 32-bit type. */ + CPUMUNKNOWNCPUID_32BIT_HACK = 0x7fffffff +} CPUMUNKNOWNCPUID; +/** Pointer to unknown CPUID leaf method. */ +typedef CPUMUNKNOWNCPUID *PCPUMUNKNOWNCPUID; + + +/** + * The register set returned by a CPUID operation. + */ +typedef struct CPUMCPUID +{ + uint32_t uEax; + uint32_t uEbx; + uint32_t uEcx; + uint32_t uEdx; +} CPUMCPUID; +/** Pointer to a CPUID leaf. */ +typedef CPUMCPUID *PCPUMCPUID; +/** Pointer to a const CPUID leaf. */ +typedef const CPUMCPUID *PCCPUMCPUID; + + +/** + * MSR read functions. + */ +typedef enum CPUMMSRRDFN +{ + /** Invalid zero value. */ + kCpumMsrRdFn_Invalid = 0, + /** Return the CPUMMSRRANGE::uValue. */ + kCpumMsrRdFn_FixedValue, + /** Alias to the MSR range starting at the MSR given by + * CPUMMSRRANGE::uValue. Must be used in pair with + * kCpumMsrWrFn_MsrAlias. */ + kCpumMsrRdFn_MsrAlias, + /** Write only register, GP all read attempts. */ + kCpumMsrRdFn_WriteOnly, + + kCpumMsrRdFn_Ia32P5McAddr, + kCpumMsrRdFn_Ia32P5McType, + kCpumMsrRdFn_Ia32TimestampCounter, + kCpumMsrRdFn_Ia32PlatformId, /**< Takes real CPU value for reference. */ + kCpumMsrRdFn_Ia32ApicBase, + kCpumMsrRdFn_Ia32FeatureControl, + kCpumMsrRdFn_Ia32BiosSignId, /**< Range value returned. */ + kCpumMsrRdFn_Ia32SmmMonitorCtl, + kCpumMsrRdFn_Ia32PmcN, + kCpumMsrRdFn_Ia32MonitorFilterLineSize, + kCpumMsrRdFn_Ia32MPerf, + kCpumMsrRdFn_Ia32APerf, + kCpumMsrRdFn_Ia32MtrrCap, /**< Takes real CPU value for reference. */ + kCpumMsrRdFn_Ia32MtrrPhysBaseN, /**< Takes register number. */ + kCpumMsrRdFn_Ia32MtrrPhysMaskN, /**< Takes register number. */ + kCpumMsrRdFn_Ia32MtrrFixed, /**< Takes CPUMCPU offset. */ + kCpumMsrRdFn_Ia32MtrrDefType, + kCpumMsrRdFn_Ia32Pat, + kCpumMsrRdFn_Ia32SysEnterCs, + kCpumMsrRdFn_Ia32SysEnterEsp, + kCpumMsrRdFn_Ia32SysEnterEip, + kCpumMsrRdFn_Ia32McgCap, + kCpumMsrRdFn_Ia32McgStatus, + kCpumMsrRdFn_Ia32McgCtl, + kCpumMsrRdFn_Ia32DebugCtl, + kCpumMsrRdFn_Ia32SmrrPhysBase, + kCpumMsrRdFn_Ia32SmrrPhysMask, + kCpumMsrRdFn_Ia32PlatformDcaCap, + kCpumMsrRdFn_Ia32CpuDcaCap, + kCpumMsrRdFn_Ia32Dca0Cap, + kCpumMsrRdFn_Ia32PerfEvtSelN, /**< Range value indicates the register number. */ + kCpumMsrRdFn_Ia32PerfStatus, /**< Range value returned. */ + kCpumMsrRdFn_Ia32PerfCtl, /**< Range value returned. */ + kCpumMsrRdFn_Ia32FixedCtrN, /**< Takes register number of start of range. */ + kCpumMsrRdFn_Ia32PerfCapabilities, /**< Takes reference value. */ + kCpumMsrRdFn_Ia32FixedCtrCtrl, + kCpumMsrRdFn_Ia32PerfGlobalStatus, /**< Takes reference value. */ + kCpumMsrRdFn_Ia32PerfGlobalCtrl, + kCpumMsrRdFn_Ia32PerfGlobalOvfCtrl, + kCpumMsrRdFn_Ia32PebsEnable, + kCpumMsrRdFn_Ia32ClockModulation, /**< Range value returned. */ + kCpumMsrRdFn_Ia32ThermInterrupt, /**< Range value returned. */ + kCpumMsrRdFn_Ia32ThermStatus, /**< Range value returned. */ + kCpumMsrRdFn_Ia32Therm2Ctl, /**< Range value returned. */ + kCpumMsrRdFn_Ia32MiscEnable, /**< Range value returned. */ + kCpumMsrRdFn_Ia32McCtlStatusAddrMiscN, /**< Takes bank number. */ + kCpumMsrRdFn_Ia32McNCtl2, /**< Takes register number of start of range. */ + kCpumMsrRdFn_Ia32DsArea, + kCpumMsrRdFn_Ia32TscDeadline, + kCpumMsrRdFn_Ia32X2ApicN, + kCpumMsrRdFn_Ia32DebugInterface, + kCpumMsrRdFn_Ia32VmxBasic, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxPinbasedCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxProcbasedCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxExitCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxEntryCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxMisc, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxCr0Fixed0, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxCr0Fixed1, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxCr4Fixed0, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxCr4Fixed1, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxVmcsEnum, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxProcBasedCtls2, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxEptVpidCap, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxTruePinbasedCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxTrueProcbasedCtls, /**< Takes real value as reference. */ + 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, + kCpumMsrRdFn_Amd64LongSyscallTarget, + kCpumMsrRdFn_Amd64CompSyscallTarget, + kCpumMsrRdFn_Amd64SyscallFlagMask, + kCpumMsrRdFn_Amd64FsBase, + kCpumMsrRdFn_Amd64GsBase, + kCpumMsrRdFn_Amd64KernelGsBase, + kCpumMsrRdFn_Amd64TscAux, + + kCpumMsrRdFn_IntelEblCrPowerOn, + kCpumMsrRdFn_IntelI7CoreThreadCount, + kCpumMsrRdFn_IntelP4EbcHardPowerOn, + kCpumMsrRdFn_IntelP4EbcSoftPowerOn, + kCpumMsrRdFn_IntelP4EbcFrequencyId, + kCpumMsrRdFn_IntelP6FsbFrequency, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelPlatformInfo, + kCpumMsrRdFn_IntelFlexRatio, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelPkgCStConfigControl, + kCpumMsrRdFn_IntelPmgIoCaptureBase, + kCpumMsrRdFn_IntelLastBranchFromToN, + kCpumMsrRdFn_IntelLastBranchFromN, + kCpumMsrRdFn_IntelLastBranchToN, + kCpumMsrRdFn_IntelLastBranchTos, + kCpumMsrRdFn_IntelBblCrCtl, + kCpumMsrRdFn_IntelBblCrCtl3, + kCpumMsrRdFn_IntelI7TemperatureTarget, /**< Range value returned. */ + kCpumMsrRdFn_IntelI7MsrOffCoreResponseN,/**< Takes register number. */ + kCpumMsrRdFn_IntelI7MiscPwrMgmt, + kCpumMsrRdFn_IntelP6CrN, + kCpumMsrRdFn_IntelCpuId1FeatureMaskEcdx, + kCpumMsrRdFn_IntelCpuId1FeatureMaskEax, + kCpumMsrRdFn_IntelCpuId80000001FeatureMaskEcdx, + kCpumMsrRdFn_IntelI7SandyAesNiCtl, + kCpumMsrRdFn_IntelI7TurboRatioLimit, /**< Returns range value. */ + kCpumMsrRdFn_IntelI7LbrSelect, + kCpumMsrRdFn_IntelI7SandyErrorControl, + kCpumMsrRdFn_IntelI7VirtualLegacyWireCap,/**< Returns range value. */ + kCpumMsrRdFn_IntelI7PowerCtl, + kCpumMsrRdFn_IntelI7SandyPebsNumAlt, + kCpumMsrRdFn_IntelI7PebsLdLat, + kCpumMsrRdFn_IntelI7PkgCnResidencyN, /**< Takes C-state number. */ + kCpumMsrRdFn_IntelI7CoreCnResidencyN, /**< Takes C-state number. */ + kCpumMsrRdFn_IntelI7SandyVrCurrentConfig,/**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7SandyVrMiscConfig, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7SandyRaplPowerUnit, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7SandyPkgCnIrtlN, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7SandyPkgC2Residency, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPkgPowerLimit, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPkgEnergyStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPkgPerfStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPkgPowerInfo, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplDramPowerLimit, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplDramEnergyStatus,/**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplDramPerfStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplDramPowerInfo, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp0PowerLimit, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp0EnergyStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp0Policy, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp0PerfStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp1PowerLimit, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp1EnergyStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp1Policy, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7IvyConfigTdpNominal, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7IvyConfigTdpLevel1, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7IvyConfigTdpLevel2, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7IvyConfigTdpControl, + kCpumMsrRdFn_IntelI7IvyTurboActivationRatio, + kCpumMsrRdFn_IntelI7UncPerfGlobalCtrl, + kCpumMsrRdFn_IntelI7UncPerfGlobalStatus, + kCpumMsrRdFn_IntelI7UncPerfGlobalOvfCtrl, + kCpumMsrRdFn_IntelI7UncPerfFixedCtrCtrl, + kCpumMsrRdFn_IntelI7UncPerfFixedCtr, + kCpumMsrRdFn_IntelI7UncCBoxConfig, + kCpumMsrRdFn_IntelI7UncArbPerfCtrN, + kCpumMsrRdFn_IntelI7UncArbPerfEvtSelN, + kCpumMsrRdFn_IntelI7SmiCount, + kCpumMsrRdFn_IntelCore2EmttmCrTablesN, /**< Range value returned. */ + kCpumMsrRdFn_IntelCore2SmmCStMiscInfo, + kCpumMsrRdFn_IntelCore1ExtConfig, + kCpumMsrRdFn_IntelCore1DtsCalControl, + kCpumMsrRdFn_IntelCore2PeciControl, + kCpumMsrRdFn_IntelAtSilvCoreC1Recidency, + + kCpumMsrRdFn_P6LastBranchFromIp, + kCpumMsrRdFn_P6LastBranchToIp, + kCpumMsrRdFn_P6LastIntFromIp, + kCpumMsrRdFn_P6LastIntToIp, + + kCpumMsrRdFn_AmdFam15hTscRate, + kCpumMsrRdFn_AmdFam15hLwpCfg, + kCpumMsrRdFn_AmdFam15hLwpCbAddr, + kCpumMsrRdFn_AmdFam10hMc4MiscN, + kCpumMsrRdFn_AmdK8PerfCtlN, + kCpumMsrRdFn_AmdK8PerfCtrN, + kCpumMsrRdFn_AmdK8SysCfg, /**< Range value returned. */ + kCpumMsrRdFn_AmdK8HwCr, + kCpumMsrRdFn_AmdK8IorrBaseN, + kCpumMsrRdFn_AmdK8IorrMaskN, + kCpumMsrRdFn_AmdK8TopOfMemN, + kCpumMsrRdFn_AmdK8NbCfg1, + kCpumMsrRdFn_AmdK8McXcptRedir, + kCpumMsrRdFn_AmdK8CpuNameN, + kCpumMsrRdFn_AmdK8HwThermalCtrl, /**< Range value returned. */ + kCpumMsrRdFn_AmdK8SwThermalCtrl, + kCpumMsrRdFn_AmdK8FidVidControl, /**< Range value returned. */ + kCpumMsrRdFn_AmdK8FidVidStatus, /**< Range value returned. */ + kCpumMsrRdFn_AmdK8McCtlMaskN, + kCpumMsrRdFn_AmdK8SmiOnIoTrapN, + kCpumMsrRdFn_AmdK8SmiOnIoTrapCtlSts, + kCpumMsrRdFn_AmdK8IntPendingMessage, + kCpumMsrRdFn_AmdK8SmiTriggerIoCycle, + kCpumMsrRdFn_AmdFam10hMmioCfgBaseAddr, + kCpumMsrRdFn_AmdFam10hTrapCtlMaybe, + kCpumMsrRdFn_AmdFam10hPStateCurLimit, /**< Returns range value. */ + kCpumMsrRdFn_AmdFam10hPStateControl, /**< Returns range value. */ + kCpumMsrRdFn_AmdFam10hPStateStatus, /**< Returns range value. */ + kCpumMsrRdFn_AmdFam10hPStateN, /**< Returns range value. This isn't an register index! */ + kCpumMsrRdFn_AmdFam10hCofVidControl, /**< Returns range value. */ + kCpumMsrRdFn_AmdFam10hCofVidStatus, /**< Returns range value. */ + kCpumMsrRdFn_AmdFam10hCStateIoBaseAddr, + kCpumMsrRdFn_AmdFam10hCpuWatchdogTimer, + kCpumMsrRdFn_AmdK8SmmBase, + kCpumMsrRdFn_AmdK8SmmAddr, + kCpumMsrRdFn_AmdK8SmmMask, + kCpumMsrRdFn_AmdK8VmCr, + kCpumMsrRdFn_AmdK8IgnNe, + kCpumMsrRdFn_AmdK8SmmCtl, + kCpumMsrRdFn_AmdK8VmHSavePa, + kCpumMsrRdFn_AmdFam10hVmLockKey, + kCpumMsrRdFn_AmdFam10hSmmLockKey, + kCpumMsrRdFn_AmdFam10hLocalSmiStatus, + kCpumMsrRdFn_AmdFam10hOsVisWrkIdLength, + kCpumMsrRdFn_AmdFam10hOsVisWrkStatus, + kCpumMsrRdFn_AmdFam16hL2IPerfCtlN, + kCpumMsrRdFn_AmdFam16hL2IPerfCtrN, + kCpumMsrRdFn_AmdFam15hNorthbridgePerfCtlN, + kCpumMsrRdFn_AmdFam15hNorthbridgePerfCtrN, + kCpumMsrRdFn_AmdK7MicrocodeCtl, /**< Returns range value. */ + kCpumMsrRdFn_AmdK7ClusterIdMaybe, /**< Returns range value. */ + kCpumMsrRdFn_AmdK8CpuIdCtlStd07hEbax, + kCpumMsrRdFn_AmdK8CpuIdCtlStd06hEcx, + kCpumMsrRdFn_AmdK8CpuIdCtlStd01hEdcx, + kCpumMsrRdFn_AmdK8CpuIdCtlExt01hEdcx, + kCpumMsrRdFn_AmdK8PatchLevel, /**< Returns range value. */ + kCpumMsrRdFn_AmdK7DebugStatusMaybe, + kCpumMsrRdFn_AmdK7BHTraceBaseMaybe, + kCpumMsrRdFn_AmdK7BHTracePtrMaybe, + kCpumMsrRdFn_AmdK7BHTraceLimitMaybe, + kCpumMsrRdFn_AmdK7HardwareDebugToolCfgMaybe, + kCpumMsrRdFn_AmdK7FastFlushCountMaybe, + kCpumMsrRdFn_AmdK7NodeId, + kCpumMsrRdFn_AmdK7DrXAddrMaskN, /**< Takes register index. */ + kCpumMsrRdFn_AmdK7Dr0DataMatchMaybe, + kCpumMsrRdFn_AmdK7Dr0DataMaskMaybe, + kCpumMsrRdFn_AmdK7LoadStoreCfg, + kCpumMsrRdFn_AmdK7InstrCacheCfg, + kCpumMsrRdFn_AmdK7DataCacheCfg, + kCpumMsrRdFn_AmdK7BusUnitCfg, + kCpumMsrRdFn_AmdK7DebugCtl2Maybe, + kCpumMsrRdFn_AmdFam15hFpuCfg, + kCpumMsrRdFn_AmdFam15hDecoderCfg, + kCpumMsrRdFn_AmdFam10hBusUnitCfg2, + kCpumMsrRdFn_AmdFam15hCombUnitCfg, + kCpumMsrRdFn_AmdFam15hCombUnitCfg2, + kCpumMsrRdFn_AmdFam15hCombUnitCfg3, + kCpumMsrRdFn_AmdFam15hExecUnitCfg, + kCpumMsrRdFn_AmdFam15hLoadStoreCfg2, + kCpumMsrRdFn_AmdFam10hIbsFetchCtl, + kCpumMsrRdFn_AmdFam10hIbsFetchLinAddr, + kCpumMsrRdFn_AmdFam10hIbsFetchPhysAddr, + kCpumMsrRdFn_AmdFam10hIbsOpExecCtl, + kCpumMsrRdFn_AmdFam10hIbsOpRip, + kCpumMsrRdFn_AmdFam10hIbsOpData, + kCpumMsrRdFn_AmdFam10hIbsOpData2, + kCpumMsrRdFn_AmdFam10hIbsOpData3, + kCpumMsrRdFn_AmdFam10hIbsDcLinAddr, + kCpumMsrRdFn_AmdFam10hIbsDcPhysAddr, + kCpumMsrRdFn_AmdFam10hIbsCtl, + kCpumMsrRdFn_AmdFam14hIbsBrTarget, + + kCpumMsrRdFn_Gim, + + /** End of valid MSR read function indexes. */ + kCpumMsrRdFn_End +} CPUMMSRRDFN; + +/** + * MSR write functions. + */ +typedef enum CPUMMSRWRFN +{ + /** Invalid zero value. */ + kCpumMsrWrFn_Invalid = 0, + /** Writes are ignored, the fWrGpMask is observed though. */ + kCpumMsrWrFn_IgnoreWrite, + /** Writes cause GP(0) to be raised, the fWrGpMask should be UINT64_MAX. */ + kCpumMsrWrFn_ReadOnly, + /** Alias to the MSR range starting at the MSR given by + * CPUMMSRRANGE::uValue. Must be used in pair with + * kCpumMsrRdFn_MsrAlias. */ + kCpumMsrWrFn_MsrAlias, + + kCpumMsrWrFn_Ia32P5McAddr, + kCpumMsrWrFn_Ia32P5McType, + kCpumMsrWrFn_Ia32TimestampCounter, + kCpumMsrWrFn_Ia32ApicBase, + kCpumMsrWrFn_Ia32FeatureControl, + kCpumMsrWrFn_Ia32BiosSignId, + kCpumMsrWrFn_Ia32BiosUpdateTrigger, + kCpumMsrWrFn_Ia32SmmMonitorCtl, + kCpumMsrWrFn_Ia32PmcN, + kCpumMsrWrFn_Ia32MonitorFilterLineSize, + kCpumMsrWrFn_Ia32MPerf, + kCpumMsrWrFn_Ia32APerf, + kCpumMsrWrFn_Ia32MtrrPhysBaseN, /**< Takes register number. */ + kCpumMsrWrFn_Ia32MtrrPhysMaskN, /**< Takes register number. */ + kCpumMsrWrFn_Ia32MtrrFixed, /**< Takes CPUMCPU offset. */ + kCpumMsrWrFn_Ia32MtrrDefType, + kCpumMsrWrFn_Ia32Pat, + kCpumMsrWrFn_Ia32SysEnterCs, + kCpumMsrWrFn_Ia32SysEnterEsp, + kCpumMsrWrFn_Ia32SysEnterEip, + kCpumMsrWrFn_Ia32McgStatus, + kCpumMsrWrFn_Ia32McgCtl, + kCpumMsrWrFn_Ia32DebugCtl, + kCpumMsrWrFn_Ia32SmrrPhysBase, + kCpumMsrWrFn_Ia32SmrrPhysMask, + kCpumMsrWrFn_Ia32PlatformDcaCap, + kCpumMsrWrFn_Ia32Dca0Cap, + kCpumMsrWrFn_Ia32PerfEvtSelN, /**< Range value indicates the register number. */ + kCpumMsrWrFn_Ia32PerfStatus, + kCpumMsrWrFn_Ia32PerfCtl, + kCpumMsrWrFn_Ia32FixedCtrN, /**< Takes register number of start of range. */ + kCpumMsrWrFn_Ia32PerfCapabilities, + kCpumMsrWrFn_Ia32FixedCtrCtrl, + kCpumMsrWrFn_Ia32PerfGlobalStatus, + kCpumMsrWrFn_Ia32PerfGlobalCtrl, + kCpumMsrWrFn_Ia32PerfGlobalOvfCtrl, + kCpumMsrWrFn_Ia32PebsEnable, + kCpumMsrWrFn_Ia32ClockModulation, + kCpumMsrWrFn_Ia32ThermInterrupt, + kCpumMsrWrFn_Ia32ThermStatus, + kCpumMsrWrFn_Ia32Therm2Ctl, + kCpumMsrWrFn_Ia32MiscEnable, + kCpumMsrWrFn_Ia32McCtlStatusAddrMiscN, /**< Takes bank number. */ + kCpumMsrWrFn_Ia32McNCtl2, /**< Takes register number of start of range. */ + kCpumMsrWrFn_Ia32DsArea, + kCpumMsrWrFn_Ia32TscDeadline, + kCpumMsrWrFn_Ia32X2ApicN, + kCpumMsrWrFn_Ia32DebugInterface, + kCpumMsrWrFn_Ia32SpecCtrl, + kCpumMsrWrFn_Ia32PredCmd, + kCpumMsrWrFn_Ia32FlushCmd, + + kCpumMsrWrFn_Amd64Efer, + kCpumMsrWrFn_Amd64SyscallTarget, + kCpumMsrWrFn_Amd64LongSyscallTarget, + kCpumMsrWrFn_Amd64CompSyscallTarget, + kCpumMsrWrFn_Amd64SyscallFlagMask, + kCpumMsrWrFn_Amd64FsBase, + kCpumMsrWrFn_Amd64GsBase, + kCpumMsrWrFn_Amd64KernelGsBase, + kCpumMsrWrFn_Amd64TscAux, + kCpumMsrWrFn_IntelEblCrPowerOn, + kCpumMsrWrFn_IntelP4EbcHardPowerOn, + kCpumMsrWrFn_IntelP4EbcSoftPowerOn, + kCpumMsrWrFn_IntelP4EbcFrequencyId, + kCpumMsrWrFn_IntelFlexRatio, + kCpumMsrWrFn_IntelPkgCStConfigControl, + kCpumMsrWrFn_IntelPmgIoCaptureBase, + kCpumMsrWrFn_IntelLastBranchFromToN, + kCpumMsrWrFn_IntelLastBranchFromN, + kCpumMsrWrFn_IntelLastBranchToN, + kCpumMsrWrFn_IntelLastBranchTos, + kCpumMsrWrFn_IntelBblCrCtl, + kCpumMsrWrFn_IntelBblCrCtl3, + kCpumMsrWrFn_IntelI7TemperatureTarget, + kCpumMsrWrFn_IntelI7MsrOffCoreResponseN, /**< Takes register number. */ + kCpumMsrWrFn_IntelI7MiscPwrMgmt, + kCpumMsrWrFn_IntelP6CrN, + kCpumMsrWrFn_IntelCpuId1FeatureMaskEcdx, + kCpumMsrWrFn_IntelCpuId1FeatureMaskEax, + kCpumMsrWrFn_IntelCpuId80000001FeatureMaskEcdx, + kCpumMsrWrFn_IntelI7SandyAesNiCtl, + kCpumMsrWrFn_IntelI7TurboRatioLimit, + kCpumMsrWrFn_IntelI7LbrSelect, + kCpumMsrWrFn_IntelI7SandyErrorControl, + kCpumMsrWrFn_IntelI7PowerCtl, + kCpumMsrWrFn_IntelI7SandyPebsNumAlt, + kCpumMsrWrFn_IntelI7PebsLdLat, + kCpumMsrWrFn_IntelI7SandyVrCurrentConfig, + kCpumMsrWrFn_IntelI7SandyVrMiscConfig, + kCpumMsrWrFn_IntelI7SandyRaplPowerUnit, /**< R/O but found writable bits on a Silvermont CPU here. */ + kCpumMsrWrFn_IntelI7SandyPkgCnIrtlN, + kCpumMsrWrFn_IntelI7SandyPkgC2Residency, /**< R/O but found writable bits on a Silvermont CPU here. */ + kCpumMsrWrFn_IntelI7RaplPkgPowerLimit, + kCpumMsrWrFn_IntelI7RaplDramPowerLimit, + kCpumMsrWrFn_IntelI7RaplPp0PowerLimit, + kCpumMsrWrFn_IntelI7RaplPp0Policy, + kCpumMsrWrFn_IntelI7RaplPp1PowerLimit, + kCpumMsrWrFn_IntelI7RaplPp1Policy, + kCpumMsrWrFn_IntelI7IvyConfigTdpControl, + kCpumMsrWrFn_IntelI7IvyTurboActivationRatio, + kCpumMsrWrFn_IntelI7UncPerfGlobalCtrl, + kCpumMsrWrFn_IntelI7UncPerfGlobalStatus, + kCpumMsrWrFn_IntelI7UncPerfGlobalOvfCtrl, + kCpumMsrWrFn_IntelI7UncPerfFixedCtrCtrl, + kCpumMsrWrFn_IntelI7UncPerfFixedCtr, + kCpumMsrWrFn_IntelI7UncArbPerfCtrN, + kCpumMsrWrFn_IntelI7UncArbPerfEvtSelN, + kCpumMsrWrFn_IntelCore2EmttmCrTablesN, + kCpumMsrWrFn_IntelCore2SmmCStMiscInfo, + kCpumMsrWrFn_IntelCore1ExtConfig, + kCpumMsrWrFn_IntelCore1DtsCalControl, + kCpumMsrWrFn_IntelCore2PeciControl, + + kCpumMsrWrFn_P6LastIntFromIp, + kCpumMsrWrFn_P6LastIntToIp, + + kCpumMsrWrFn_AmdFam15hTscRate, + kCpumMsrWrFn_AmdFam15hLwpCfg, + kCpumMsrWrFn_AmdFam15hLwpCbAddr, + kCpumMsrWrFn_AmdFam10hMc4MiscN, + kCpumMsrWrFn_AmdK8PerfCtlN, + kCpumMsrWrFn_AmdK8PerfCtrN, + kCpumMsrWrFn_AmdK8SysCfg, + kCpumMsrWrFn_AmdK8HwCr, + kCpumMsrWrFn_AmdK8IorrBaseN, + kCpumMsrWrFn_AmdK8IorrMaskN, + kCpumMsrWrFn_AmdK8TopOfMemN, + kCpumMsrWrFn_AmdK8NbCfg1, + kCpumMsrWrFn_AmdK8McXcptRedir, + kCpumMsrWrFn_AmdK8CpuNameN, + kCpumMsrWrFn_AmdK8HwThermalCtrl, + kCpumMsrWrFn_AmdK8SwThermalCtrl, + kCpumMsrWrFn_AmdK8FidVidControl, + kCpumMsrWrFn_AmdK8McCtlMaskN, + kCpumMsrWrFn_AmdK8SmiOnIoTrapN, + kCpumMsrWrFn_AmdK8SmiOnIoTrapCtlSts, + kCpumMsrWrFn_AmdK8IntPendingMessage, + kCpumMsrWrFn_AmdK8SmiTriggerIoCycle, + kCpumMsrWrFn_AmdFam10hMmioCfgBaseAddr, + kCpumMsrWrFn_AmdFam10hTrapCtlMaybe, + kCpumMsrWrFn_AmdFam10hPStateControl, + kCpumMsrWrFn_AmdFam10hPStateStatus, + kCpumMsrWrFn_AmdFam10hPStateN, + kCpumMsrWrFn_AmdFam10hCofVidControl, + kCpumMsrWrFn_AmdFam10hCofVidStatus, + kCpumMsrWrFn_AmdFam10hCStateIoBaseAddr, + kCpumMsrWrFn_AmdFam10hCpuWatchdogTimer, + kCpumMsrWrFn_AmdK8SmmBase, + kCpumMsrWrFn_AmdK8SmmAddr, + kCpumMsrWrFn_AmdK8SmmMask, + kCpumMsrWrFn_AmdK8VmCr, + kCpumMsrWrFn_AmdK8IgnNe, + kCpumMsrWrFn_AmdK8SmmCtl, + kCpumMsrWrFn_AmdK8VmHSavePa, + kCpumMsrWrFn_AmdFam10hVmLockKey, + kCpumMsrWrFn_AmdFam10hSmmLockKey, + kCpumMsrWrFn_AmdFam10hLocalSmiStatus, + kCpumMsrWrFn_AmdFam10hOsVisWrkIdLength, + kCpumMsrWrFn_AmdFam10hOsVisWrkStatus, + kCpumMsrWrFn_AmdFam16hL2IPerfCtlN, + kCpumMsrWrFn_AmdFam16hL2IPerfCtrN, + kCpumMsrWrFn_AmdFam15hNorthbridgePerfCtlN, + kCpumMsrWrFn_AmdFam15hNorthbridgePerfCtrN, + kCpumMsrWrFn_AmdK7MicrocodeCtl, + kCpumMsrWrFn_AmdK7ClusterIdMaybe, + kCpumMsrWrFn_AmdK8CpuIdCtlStd07hEbax, + kCpumMsrWrFn_AmdK8CpuIdCtlStd06hEcx, + kCpumMsrWrFn_AmdK8CpuIdCtlStd01hEdcx, + kCpumMsrWrFn_AmdK8CpuIdCtlExt01hEdcx, + kCpumMsrWrFn_AmdK8PatchLoader, + kCpumMsrWrFn_AmdK7DebugStatusMaybe, + kCpumMsrWrFn_AmdK7BHTraceBaseMaybe, + kCpumMsrWrFn_AmdK7BHTracePtrMaybe, + kCpumMsrWrFn_AmdK7BHTraceLimitMaybe, + kCpumMsrWrFn_AmdK7HardwareDebugToolCfgMaybe, + kCpumMsrWrFn_AmdK7FastFlushCountMaybe, + kCpumMsrWrFn_AmdK7NodeId, + kCpumMsrWrFn_AmdK7DrXAddrMaskN, /**< Takes register index. */ + kCpumMsrWrFn_AmdK7Dr0DataMatchMaybe, + kCpumMsrWrFn_AmdK7Dr0DataMaskMaybe, + kCpumMsrWrFn_AmdK7LoadStoreCfg, + kCpumMsrWrFn_AmdK7InstrCacheCfg, + kCpumMsrWrFn_AmdK7DataCacheCfg, + kCpumMsrWrFn_AmdK7BusUnitCfg, + kCpumMsrWrFn_AmdK7DebugCtl2Maybe, + kCpumMsrWrFn_AmdFam15hFpuCfg, + kCpumMsrWrFn_AmdFam15hDecoderCfg, + kCpumMsrWrFn_AmdFam10hBusUnitCfg2, + kCpumMsrWrFn_AmdFam15hCombUnitCfg, + kCpumMsrWrFn_AmdFam15hCombUnitCfg2, + kCpumMsrWrFn_AmdFam15hCombUnitCfg3, + kCpumMsrWrFn_AmdFam15hExecUnitCfg, + kCpumMsrWrFn_AmdFam15hLoadStoreCfg2, + kCpumMsrWrFn_AmdFam10hIbsFetchCtl, + kCpumMsrWrFn_AmdFam10hIbsFetchLinAddr, + kCpumMsrWrFn_AmdFam10hIbsFetchPhysAddr, + kCpumMsrWrFn_AmdFam10hIbsOpExecCtl, + kCpumMsrWrFn_AmdFam10hIbsOpRip, + kCpumMsrWrFn_AmdFam10hIbsOpData, + kCpumMsrWrFn_AmdFam10hIbsOpData2, + kCpumMsrWrFn_AmdFam10hIbsOpData3, + kCpumMsrWrFn_AmdFam10hIbsDcLinAddr, + kCpumMsrWrFn_AmdFam10hIbsDcPhysAddr, + kCpumMsrWrFn_AmdFam10hIbsCtl, + kCpumMsrWrFn_AmdFam14hIbsBrTarget, + + kCpumMsrWrFn_Gim, + + /** End of valid MSR write function indexes. */ + kCpumMsrWrFn_End +} CPUMMSRWRFN; + +/** + * MSR range. + */ +typedef struct CPUMMSRRANGE +{ + /** The first MSR. [0] */ + uint32_t uFirst; + /** The last MSR. [4] */ + uint32_t uLast; + /** The read function (CPUMMSRRDFN). [8] */ + uint16_t enmRdFn; + /** The write function (CPUMMSRWRFN). [10] */ + uint16_t enmWrFn; + /** The offset of the 64-bit MSR value relative to the start of CPUMCPU. + * UINT16_MAX if not used by the read and write functions. [12] */ + uint32_t offCpumCpu : 24; + /** Reserved for future hacks. [15] */ + uint32_t fReserved : 8; + /** The init/read value. [16] + * When enmRdFn is kCpumMsrRdFn_INIT_VALUE, this is the value returned on RDMSR. + * offCpumCpu must be UINT16_MAX in that case, otherwise it must be a valid + * offset into CPUM. */ + uint64_t uValue; + /** The bits to ignore when writing. [24] */ + uint64_t fWrIgnMask; + /** The bits that will cause a GP(0) when writing. [32] + * This is always checked prior to calling the write function. Using + * UINT64_MAX effectively marks the MSR as read-only. */ + uint64_t fWrGpMask; + /** The register name, if applicable. [40] */ + char szName[56]; + + /** The number of reads. */ + STAMCOUNTER cReads; + /** The number of writes. */ + STAMCOUNTER cWrites; + /** The number of times ignored bits were written. */ + STAMCOUNTER cIgnoredBits; + /** The number of GPs generated. */ + STAMCOUNTER cGps; +} CPUMMSRRANGE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMMSRRANGE, 128); +#endif +/** Pointer to an MSR range. */ +typedef CPUMMSRRANGE *PCPUMMSRRANGE; +/** Pointer to a const MSR range. */ +typedef CPUMMSRRANGE const *PCCPUMMSRRANGE; + + +/** + * MSRs which are required while exploding features. + */ +typedef struct CPUMMSRS +{ + union + { + VMXMSRS vmx; + SVMMSRS svm; + } hwvirt; +} CPUMMSRS; +/** Pointer to an CPUMMSRS struct. */ +typedef CPUMMSRS *PCPUMMSRS; +/** Pointer to a const CPUMMSRS struct. */ +typedef CPUMMSRS const *PCCPUMMSRS; + + +/** + * CPU features and quirks. + * This is mostly exploded CPUID info. + */ +typedef struct CPUMFEATURES +{ + /** The CPU vendor (CPUMCPUVENDOR). */ + uint8_t enmCpuVendor; + /** The CPU family. */ + uint8_t uFamily; + /** The CPU model. */ + uint8_t uModel; + /** The CPU stepping. */ + uint8_t uStepping; + /** The microarchitecture. */ +#ifndef VBOX_FOR_DTRACE_LIB + CPUMMICROARCH enmMicroarch; +#else + uint32_t enmMicroarch; +#endif + /** The maximum physical address width of the CPU. */ + uint8_t cMaxPhysAddrWidth; + /** The maximum linear address width of the CPU. */ + uint8_t cMaxLinearAddrWidth; + /** Max size of the extended state (or FPU state if no XSAVE). */ + uint16_t cbMaxExtendedState; + + /** Supports MSRs. */ + uint32_t fMsr : 1; + /** Supports the page size extension (4/2 MB pages). */ + uint32_t fPse : 1; + /** Supports 36-bit page size extension (4 MB pages can map memory above + * 4GB). */ + uint32_t fPse36 : 1; + /** Supports physical address extension (PAE). */ + uint32_t fPae : 1; + /** Supports page-global extension (PGE). */ + uint32_t fPge : 1; + /** Page attribute table (PAT) support (page level cache control). */ + uint32_t fPat : 1; + /** Supports the FXSAVE and FXRSTOR instructions. */ + uint32_t fFxSaveRstor : 1; + /** Supports the XSAVE and XRSTOR instructions. */ + uint32_t fXSaveRstor : 1; + /** Supports the XSAVEOPT instruction. */ + uint32_t fXSaveOpt : 1; + /** The XSAVE/XRSTOR bit in CR4 has been set (only applicable for host!). */ + uint32_t fOpSysXSaveRstor : 1; + /** Supports MMX. */ + uint32_t fMmx : 1; + /** Supports AMD extensions to MMX instructions. */ + uint32_t fAmdMmxExts : 1; + /** Supports SSE. */ + uint32_t fSse : 1; + /** Supports SSE2. */ + uint32_t fSse2 : 1; + /** Supports SSE3. */ + uint32_t fSse3 : 1; + /** Supports SSSE3. */ + uint32_t fSsse3 : 1; + /** Supports SSE4.1. */ + uint32_t fSse41 : 1; + /** Supports SSE4.2. */ + uint32_t fSse42 : 1; + /** Supports AVX. */ + uint32_t fAvx : 1; + /** Supports AVX2. */ + uint32_t fAvx2 : 1; + /** Supports AVX512 foundation. */ + uint32_t fAvx512Foundation : 1; + /** Supports RDTSC. */ + uint32_t fTsc : 1; + /** Intel SYSENTER/SYSEXIT support */ + uint32_t fSysEnter : 1; + /** First generation APIC. */ + uint32_t fApic : 1; + /** Second generation APIC. */ + uint32_t fX2Apic : 1; + /** Hypervisor present. */ + uint32_t fHypervisorPresent : 1; + /** MWAIT & MONITOR instructions supported. */ + uint32_t fMonitorMWait : 1; + /** MWAIT Extensions present. */ + uint32_t fMWaitExtensions : 1; + /** Supports CMPXCHG16B in 64-bit mode. */ + uint32_t fMovCmpXchg16b : 1; + /** Supports CLFLUSH. */ + uint32_t fClFlush : 1; + /** Supports CLFLUSHOPT. */ + uint32_t fClFlushOpt : 1; + /** Supports IA32_PRED_CMD.IBPB. */ + uint32_t fIbpb : 1; + /** Supports IA32_SPEC_CTRL.IBRS. */ + uint32_t fIbrs : 1; + /** Supports IA32_SPEC_CTRL.STIBP. */ + uint32_t fStibp : 1; + /** Supports IA32_FLUSH_CMD. */ + uint32_t fFlushCmd : 1; + /** Supports IA32_ARCH_CAP. */ + uint32_t fArchCap : 1; + /** Supports MD_CLEAR functionality (VERW, IA32_FLUSH_CMD). */ + uint32_t fMdsClear : 1; + /** Supports PCID. */ + uint32_t fPcid : 1; + /** Supports INVPCID. */ + uint32_t fInvpcid : 1; + /** Supports read/write FSGSBASE instructions. */ + uint32_t fFsGsBase : 1; + /** Supports BMI1 instructions (ANDN, BEXTR, BLSI, BLSMSK, BLSR, and TZCNT). */ + uint32_t fBmi1 : 1; + /** Supports BMI2 instructions (BZHI, MULX, PDEP, PEXT, RORX, SARX, SHRX, + * and SHLX). */ + uint32_t fBmi2 : 1; + /** Supports POPCNT instruction. */ + uint32_t fPopCnt : 1; + /** Supports RDRAND instruction. */ + uint32_t fRdRand : 1; + /** Supports RDSEED instruction. */ + uint32_t fRdSeed : 1; + /** Supports Hardware Lock Elision (HLE). */ + uint32_t fHle : 1; + /** Supports Restricted Transactional Memory (RTM - XBEGIN, XEND, XABORT). */ + uint32_t fRtm : 1; + /** Supports PCLMULQDQ instruction. */ + uint32_t fPclMul : 1; + /** Supports AES-NI (six AESxxx instructions). */ + uint32_t fAesNi : 1; + /** Support MOVBE instruction. */ + uint32_t fMovBe : 1; + + /** Supports AMD 3DNow instructions. */ + uint32_t f3DNow : 1; + /** Supports the 3DNow/AMD64 prefetch instructions (could be nops). */ + uint32_t f3DNowPrefetch : 1; + + /** AMD64: Supports long mode. */ + uint32_t fLongMode : 1; + /** AMD64: SYSCALL/SYSRET support. */ + uint32_t fSysCall : 1; + /** AMD64: No-execute page table bit. */ + uint32_t fNoExecute : 1; + /** AMD64: Supports LAHF & SAHF instructions in 64-bit mode. */ + uint32_t fLahfSahf : 1; + /** AMD64: Supports RDTSCP. */ + uint32_t fRdTscP : 1; + /** AMD64: Supports MOV CR8 in 32-bit code (lock prefix hack). */ + uint32_t fMovCr8In32Bit : 1; + /** AMD64: Supports XOP (similar to VEX3/AVX). */ + uint32_t fXop : 1; + /** AMD64: Supports ABM, i.e. the LZCNT instruction. */ + uint32_t fAbm : 1; + /** AMD64: Supports TBM (BEXTR, BLCFILL, BLCI, BLCIC, BLCMSK, BLCS, + * BLSFILL, BLSIC, T1MSKC, and TZMSK). */ + uint32_t fTbm : 1; + + /** Indicates that FPU instruction and data pointers may leak. + * This generally applies to recent AMD CPUs, where the FPU IP and DP pointer + * is only saved and restored if an exception is pending. */ + uint32_t fLeakyFxSR : 1; + + /** AMD64: Supports AMD SVM. */ + uint32_t fSvm : 1; + + /** 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; + + /** MSR_IA32_ARCH_CAPABILITIES: RDCL_NO (bit 0). + * @remarks Only safe use after CPUM ring-0 init! */ + uint32_t fArchRdclNo : 1; + /** MSR_IA32_ARCH_CAPABILITIES: IBRS_ALL (bit 1). + * @remarks Only safe use after CPUM ring-0 init! */ + uint32_t fArchIbrsAll : 1; + /** MSR_IA32_ARCH_CAPABILITIES: RSB Override (bit 2). + * @remarks Only safe use after CPUM ring-0 init! */ + uint32_t fArchRsbOverride : 1; + /** MSR_IA32_ARCH_CAPABILITIES: RSB Override (bit 3). + * @remarks Only safe use after CPUM ring-0 init! */ + uint32_t fArchVmmNeedNotFlushL1d : 1; + /** MSR_IA32_ARCH_CAPABILITIES: MDS_NO (bit 4). + * @remarks Only safe use after CPUM ring-0 init! */ + uint32_t fArchMdsNo : 1; + + /** Alignment padding / reserved for future use (96 bits total, plus 12 bytes + * prior to the bit fields -> total of 24 bytes) */ + uint32_t fPadding0 : 26; + + + /** @name SVM + * @{ */ + /** SVM: Supports Nested-paging. */ + uint32_t fSvmNestedPaging : 1; + /** SVM: Support LBR (Last Branch Record) virtualization. */ + uint32_t fSvmLbrVirt : 1; + /** SVM: Supports SVM lock. */ + uint32_t fSvmSvmLock : 1; + /** SVM: Supports Next RIP save. */ + uint32_t fSvmNextRipSave : 1; + /** SVM: Supports TSC rate MSR. */ + uint32_t fSvmTscRateMsr : 1; + /** SVM: Supports VMCB clean bits. */ + uint32_t fSvmVmcbClean : 1; + /** SVM: Supports Flush-by-ASID. */ + uint32_t fSvmFlusbByAsid : 1; + /** SVM: Supports decode assist. */ + uint32_t fSvmDecodeAssists : 1; + /** SVM: Supports Pause filter. */ + uint32_t fSvmPauseFilter : 1; + /** SVM: Supports Pause filter threshold. */ + uint32_t fSvmPauseFilterThreshold : 1; + /** SVM: Supports AVIC (Advanced Virtual Interrupt Controller). */ + uint32_t fSvmAvic : 1; + /** SVM: Supports Virtualized VMSAVE/VMLOAD. */ + uint32_t fSvmVirtVmsaveVmload : 1; + /** SVM: Supports VGIF (Virtual Global Interrupt Flag). */ + uint32_t fSvmVGif : 1; + /** SVM: Supports GMET (Guest Mode Execute Trap Extension). */ + uint32_t fSvmGmet : 1; + /** SVM: Supports SSSCheck (SVM Supervisor Shadow Stack). */ + uint32_t fSvmSSSCheck : 1; + /** SVM: Supports SPEC_CTRL virtualization. */ + uint32_t fSvmSpecCtrl : 1; + /** SVM: Supports HOST_MCE_OVERRIDE. */ + uint32_t fSvmHostMceOverride : 1; + /** SVM: Supports TlbiCtl (INVLPGB/TLBSYNC in VMCB and TLBSYNC intercept). */ + uint32_t fSvmTlbiCtl : 1; + /** SVM: Padding / reserved for future features (64 bits total w/ max ASID). */ + uint32_t fSvmPadding0 : 14; + /** SVM: Maximum supported ASID. */ + uint32_t uSvmMaxAsid; + /** @} */ + + + /** VMX: Maximum physical address width. */ + uint32_t cVmxMaxPhysAddrWidth : 8; + + /** @name VMX basic controls. + * @{ */ + /** VMX: Supports INS/OUTS VM-exit instruction info. */ + uint32_t fVmxInsOutInfo : 1; + /** @} */ + + /** @name VMX Pin-based controls. + * @{ */ + /** VMX: Supports external interrupt VM-exit. */ + uint32_t fVmxExtIntExit : 1; + /** VMX: Supports NMI VM-exit. */ + uint32_t fVmxNmiExit : 1; + /** VMX: Supports Virtual NMIs. */ + uint32_t fVmxVirtNmi : 1; + /** VMX: Supports preemption timer. */ + uint32_t fVmxPreemptTimer : 1; + /** VMX: Supports posted interrupts. */ + uint32_t fVmxPostedInt : 1; + /** @} */ + + /** @name VMX Processor-based controls. + * @{ */ + /** VMX: Supports Interrupt-window exiting. */ + uint32_t fVmxIntWindowExit : 1; + /** VMX: Supports TSC offsetting. */ + uint32_t fVmxTscOffsetting : 1; + /** VMX: Supports HLT exiting. */ + uint32_t fVmxHltExit : 1; + /** VMX: Supports INVLPG exiting. */ + uint32_t fVmxInvlpgExit : 1; + /** VMX: Supports MWAIT exiting. */ + uint32_t fVmxMwaitExit : 1; + /** VMX: Supports RDPMC exiting. */ + uint32_t fVmxRdpmcExit : 1; + /** VMX: Supports RDTSC exiting. */ + uint32_t fVmxRdtscExit : 1; + /** VMX: Supports CR3-load exiting. */ + uint32_t fVmxCr3LoadExit : 1; + /** VMX: Supports CR3-store exiting. */ + uint32_t fVmxCr3StoreExit : 1; + /** VMX: Supports tertiary processor-based VM-execution controls. */ + uint32_t fVmxTertiaryExecCtls : 1; + /** VMX: Supports CR8-load exiting. */ + uint32_t fVmxCr8LoadExit : 1; + /** VMX: Supports CR8-store exiting. */ + uint32_t fVmxCr8StoreExit : 1; + /** VMX: Supports TPR shadow. */ + uint32_t fVmxUseTprShadow : 1; + /** VMX: Supports NMI-window exiting. */ + uint32_t fVmxNmiWindowExit : 1; + /** VMX: Supports Mov-DRx exiting. */ + uint32_t fVmxMovDRxExit : 1; + /** VMX: Supports Unconditional I/O exiting. */ + uint32_t fVmxUncondIoExit : 1; + /** VMX: Supportgs I/O bitmaps. */ + uint32_t fVmxUseIoBitmaps : 1; + /** VMX: Supports Monitor Trap Flag. */ + uint32_t fVmxMonitorTrapFlag : 1; + /** VMX: Supports MSR bitmap. */ + uint32_t fVmxUseMsrBitmaps : 1; + /** VMX: Supports MONITOR exiting. */ + uint32_t fVmxMonitorExit : 1; + /** VMX: Supports PAUSE exiting. */ + uint32_t fVmxPauseExit : 1; + /** VMX: Supports secondary processor-based VM-execution controls. */ + uint32_t fVmxSecondaryExecCtls : 1; + /** @} */ + + /** @name VMX Secondary processor-based controls. + * @{ */ + /** VMX: Supports virtualize-APIC access. */ + uint32_t fVmxVirtApicAccess : 1; + /** VMX: Supports EPT (Extended Page Tables). */ + uint32_t fVmxEpt : 1; + /** VMX: Supports descriptor-table exiting. */ + uint32_t fVmxDescTableExit : 1; + /** VMX: Supports RDTSCP. */ + uint32_t fVmxRdtscp : 1; + /** VMX: Supports virtualize-x2APIC mode. */ + uint32_t fVmxVirtX2ApicMode : 1; + /** VMX: Supports VPID. */ + uint32_t fVmxVpid : 1; + /** VMX: Supports WBIND exiting. */ + uint32_t fVmxWbinvdExit : 1; + /** VMX: Supports Unrestricted guest. */ + uint32_t fVmxUnrestrictedGuest : 1; + /** VMX: Supports APIC-register virtualization. */ + uint32_t fVmxApicRegVirt : 1; + /** VMX: Supports virtual-interrupt delivery. */ + uint32_t fVmxVirtIntDelivery : 1; + /** VMX: Supports Pause-loop exiting. */ + uint32_t fVmxPauseLoopExit : 1; + /** VMX: Supports RDRAND exiting. */ + uint32_t fVmxRdrandExit : 1; + /** VMX: Supports INVPCID. */ + uint32_t fVmxInvpcid : 1; + /** VMX: Supports VM functions. */ + uint32_t fVmxVmFunc : 1; + /** VMX: Supports VMCS shadowing. */ + uint32_t fVmxVmcsShadowing : 1; + /** VMX: Supports RDSEED exiting. */ + uint32_t fVmxRdseedExit : 1; + /** VMX: Supports PML. */ + uint32_t fVmxPml : 1; + /** VMX: Supports EPT-violations \#VE. */ + uint32_t fVmxEptXcptVe : 1; + /** VMX: Supports conceal VMX from PT. */ + uint32_t fVmxConcealVmxFromPt : 1; + /** VMX: Supports XSAVES/XRSTORS. */ + uint32_t fVmxXsavesXrstors : 1; + /** VMX: Supports mode-based execute control for EPT. */ + uint32_t fVmxModeBasedExecuteEpt : 1; + /** VMX: Supports sub-page write permissions for EPT. */ + uint32_t fVmxSppEpt : 1; + /** VMX: Supports Intel PT to output guest-physical addresses for EPT. */ + uint32_t fVmxPtEpt : 1; + /** VMX: Supports TSC scaling. */ + uint32_t fVmxUseTscScaling : 1; + /** VMX: Supports TPAUSE, UMONITOR, or UMWAIT. */ + uint32_t fVmxUserWaitPause : 1; + /** VMX: Supports enclave (ENCLV) exiting. */ + uint32_t fVmxEnclvExit : 1; + /** @} */ + + /** @name VMX Tertiary processor-based controls. + * @{ */ + /** VMX: Supports LOADIWKEY exiting. */ + uint32_t fVmxLoadIwKeyExit : 1; + /** @} */ + + /** @name VMX VM-entry controls. + * @{ */ + /** VMX: Supports load-debug controls on VM-entry. */ + uint32_t fVmxEntryLoadDebugCtls : 1; + /** VMX: Supports IA32e mode guest. */ + uint32_t fVmxIa32eModeGuest : 1; + /** VMX: Supports load guest EFER MSR on VM-entry. */ + uint32_t fVmxEntryLoadEferMsr : 1; + /** VMX: Supports load guest PAT MSR on VM-entry. */ + uint32_t fVmxEntryLoadPatMsr : 1; + /** @} */ + + /** @name VMX VM-exit controls. + * @{ */ + /** VMX: Supports save debug controls on VM-exit. */ + uint32_t fVmxExitSaveDebugCtls : 1; + /** VMX: Supports host-address space size. */ + uint32_t fVmxHostAddrSpaceSize : 1; + /** VMX: Supports acknowledge external interrupt on VM-exit. */ + uint32_t fVmxExitAckExtInt : 1; + /** VMX: Supports save guest PAT MSR on VM-exit. */ + uint32_t fVmxExitSavePatMsr : 1; + /** VMX: Supports load hsot PAT MSR on VM-exit. */ + uint32_t fVmxExitLoadPatMsr : 1; + /** VMX: Supports save guest EFER MSR on VM-exit. */ + uint32_t fVmxExitSaveEferMsr : 1; + /** VMX: Supports load host EFER MSR on VM-exit. */ + uint32_t fVmxExitLoadEferMsr : 1; + /** VMX: Supports save VMX preemption timer on VM-exit. */ + uint32_t fVmxSavePreemptTimer : 1; + /** VMX: Supports secondary VM-exit controls. */ + uint32_t fVmxSecondaryExitCtls : 1; + /** @} */ + + /** @name VMX Miscellaneous data. + * @{ */ + /** VMX: Supports storing EFER.LMA into IA32e-mode guest field on VM-exit. */ + uint32_t fVmxExitSaveEferLma : 1; + /** VMX: Whether Intel PT (Processor Trace) is supported in VMX mode or not. */ + uint32_t fVmxPt : 1; + /** VMX: Supports VMWRITE to any valid VMCS field incl. read-only fields, otherwise + * VMWRITE cannot modify read-only VM-exit information fields. */ + uint32_t fVmxVmwriteAll : 1; + /** VMX: Supports injection of software interrupts, ICEBP on VM-entry for zero + * length instructions. */ + uint32_t fVmxEntryInjectSoftInt : 1; + /** @} */ + + /** VMX: Padding / reserved for future features. */ + uint32_t fVmxPadding0 : 16; + /** VMX: Padding / reserved for future, making it a total of 128 bits. */ + uint32_t fVmxPadding1; +} CPUMFEATURES; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMFEATURES, 48); +#endif +/** Pointer to a CPU feature structure. */ +typedef CPUMFEATURES *PCPUMFEATURES; +/** Pointer to a const CPU feature structure. */ +typedef CPUMFEATURES const *PCCPUMFEATURES; + +/** + * Chameleon wrapper structure for the host CPU features. + * + * This is used for the globally readable g_CpumHostFeatures variable, which is + * initialized once during VMMR0 load for ring-0 and during CPUMR3Init in + * ring-3. To reflect this immutability after load/init, we use this wrapper + * structure to switch it between const and non-const depending on the context. + * Only two files sees it as non-const (CPUMR0.cpp and CPUM.cpp). + */ +typedef struct CPUHOSTFEATURES +{ + CPUMFEATURES +#ifndef CPUM_WITH_NONCONST_HOST_FEATURES + const +#endif + s; +} CPUHOSTFEATURES; +/** Pointer to a const host CPU feature structure. */ +typedef CPUHOSTFEATURES const *PCCPUHOSTFEATURES; + +/** Host CPU features. + * @note In ring-3, only valid after CPUMR3Init. In ring-0, valid after + * module init. */ +extern CPUHOSTFEATURES g_CpumHostFeatures; + + +/** + * CPU database entry. + */ +typedef struct CPUMDBENTRY +{ + /** The CPU name. */ + const char *pszName; + /** The full CPU name. */ + const char *pszFullName; + /** The CPU vendor (CPUMCPUVENDOR). */ + uint8_t enmVendor; + /** The CPU family. */ + uint8_t uFamily; + /** The CPU model. */ + uint8_t uModel; + /** The CPU stepping. */ + uint8_t uStepping; + /** The microarchitecture. */ + CPUMMICROARCH enmMicroarch; + /** Scalable bus frequency used for reporting other frequencies. */ + uint64_t uScalableBusFreq; + /** Flags - CPUMDB_F_XXX. */ + uint32_t fFlags; + /** The maximum physical address with of the CPU. This should correspond to + * the value in CPUID leaf 0x80000008 when present. */ + uint8_t cMaxPhysAddrWidth; + /** The MXCSR mask. */ + uint32_t fMxCsrMask; + /** Pointer to an array of CPUID leaves. */ + PCCPUMCPUIDLEAF paCpuIdLeaves; + /** The number of CPUID leaves in the array paCpuIdLeaves points to. */ + uint32_t cCpuIdLeaves; + /** The method used to deal with unknown CPUID leaves. */ + CPUMUNKNOWNCPUID enmUnknownCpuId; + /** The default unknown CPUID value. */ + CPUMCPUID DefUnknownCpuId; + + /** MSR mask. Several microarchitectures ignore the higher bits of ECX in + * the RDMSR and WRMSR instructions. */ + uint32_t fMsrMask; + + /** The number of ranges in the table pointed to b paMsrRanges. */ + uint32_t cMsrRanges; + /** MSR ranges for this CPU. */ + PCCPUMMSRRANGE paMsrRanges; +} CPUMDBENTRY; +/** Pointer to a const CPU database entry. */ +typedef CPUMDBENTRY const *PCCPUMDBENTRY; + +/** @name CPUMDB_F_XXX - CPUDBENTRY::fFlags + * @{ */ +/** Should execute all in IEM. + * @todo Implement this - currently done in Main... */ +#define CPUMDB_F_EXECUTE_ALL_IN_IEM RT_BIT_32(0) +/** @} */ + + + +#ifndef VBOX_FOR_DTRACE_LIB + +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) +VMMDECL(int) CPUMCpuIdCollectLeavesX86(PCPUMCPUIDLEAF *ppaLeaves, uint32_t *pcLeaves); +VMMDECL(CPUMCPUVENDOR) CPUMCpuIdDetectX86VendorEx(uint32_t uEAX, uint32_t uEBX, uint32_t uECX, uint32_t uEDX); +#endif + +VMM_INT_DECL(bool) CPUMAssertGuestRFlagsCookie(PVM pVM, PVMCPU pVCpu); + + +/** @name Guest Register Getters. + * @{ */ +VMMDECL(void) CPUMGetGuestGDTR(PCVMCPU pVCpu, PVBOXGDTR pGDTR); +VMMDECL(RTGCPTR) CPUMGetGuestIDTR(PCVMCPU pVCpu, uint16_t *pcbLimit); +VMMDECL(RTSEL) CPUMGetGuestTR(PCVMCPU pVCpu, PCPUMSELREGHID pHidden); +VMMDECL(RTSEL) CPUMGetGuestLDTR(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestLdtrEx(PCVMCPU pVCpu, uint64_t *pGCPtrBase, uint32_t *pcbLimit); +VMMDECL(uint64_t) CPUMGetGuestCR0(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestCR2(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestCR3(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestCR4(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestCR8(PCVMCPUCC pVCpu); +VMMDECL(int) CPUMGetGuestCRx(PCVMCPUCC pVCpu, unsigned iReg, uint64_t *pValue); +VMMDECL(uint32_t) CPUMGetGuestEFlags(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEIP(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestRIP(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEAX(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEBX(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestECX(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEDX(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestESI(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEDI(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestESP(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEBP(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestCS(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestDS(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestES(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestFS(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestGS(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestSS(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestFlatPC(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestFlatSP(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR0(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR1(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR2(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR3(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR6(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR7(PCVMCPU pVCpu); +VMMDECL(int) CPUMGetGuestDRx(PCVMCPU pVCpu, uint32_t iReg, uint64_t *pValue); +VMMDECL(void) CPUMGetGuestCpuId(PVMCPUCC pVCpu, uint32_t iLeaf, uint32_t iSubLeaf, int f64BitMode, + uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx); +VMMDECL(uint64_t) CPUMGetGuestEFER(PCVMCPU pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestIa32FeatCtrl(PCVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestIa32MtrrCap(PCVMCPU pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestIa32SmmMonitorCtl(PCVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestIa32VmxEptVpidCap(PCVMCPUCC pVCpu); +VMMDECL(VBOXSTRICTRC) CPUMQueryGuestMsr(PVMCPUCC pVCpu, uint32_t idMsr, uint64_t *puValue); +VMMDECL(VBOXSTRICTRC) CPUMSetGuestMsr(PVMCPUCC pVCpu, uint32_t idMsr, uint64_t uValue); +VMMDECL(CPUMCPUVENDOR) CPUMGetGuestCpuVendor(PVM pVM); +VMMDECL(CPUMMICROARCH) CPUMGetGuestMicroarch(PCVM pVM); +VMMDECL(void) CPUMGetGuestAddrWidths(PCVM pVM, uint8_t *pcPhysAddrWidth, uint8_t *pcLinearAddrWidth); +VMMDECL(CPUMCPUVENDOR) CPUMGetHostCpuVendor(PVM pVM); +VMMDECL(CPUMMICROARCH) CPUMGetHostMicroarch(PCVM pVM); +/** @} */ + +/** @name Guest Register Setters. + * @{ */ +VMMDECL(int) CPUMSetGuestGDTR(PVMCPU pVCpu, uint64_t GCPtrBase, uint16_t cbLimit); +VMMDECL(int) CPUMSetGuestIDTR(PVMCPU pVCpu, uint64_t GCPtrBase, uint16_t cbLimit); +VMMDECL(int) CPUMSetGuestTR(PVMCPU pVCpu, uint16_t tr); +VMMDECL(int) CPUMSetGuestLDTR(PVMCPU pVCpu, uint16_t ldtr); +VMMDECL(int) CPUMSetGuestCR0(PVMCPUCC pVCpu, uint64_t cr0); +VMMDECL(int) CPUMSetGuestCR2(PVMCPU pVCpu, uint64_t cr2); +VMMDECL(int) CPUMSetGuestCR3(PVMCPU pVCpu, uint64_t cr3); +VMMDECL(int) CPUMSetGuestCR4(PVMCPU pVCpu, uint64_t cr4); +VMMDECL(int) CPUMSetGuestDR0(PVMCPUCC pVCpu, uint64_t uDr0); +VMMDECL(int) CPUMSetGuestDR1(PVMCPUCC pVCpu, uint64_t uDr1); +VMMDECL(int) CPUMSetGuestDR2(PVMCPUCC pVCpu, uint64_t uDr2); +VMMDECL(int) CPUMSetGuestDR3(PVMCPUCC pVCpu, uint64_t uDr3); +VMMDECL(int) CPUMSetGuestDR6(PVMCPU pVCpu, uint64_t uDr6); +VMMDECL(int) CPUMSetGuestDR7(PVMCPUCC pVCpu, uint64_t uDr7); +VMMDECL(int) CPUMSetGuestDRx(PVMCPUCC pVCpu, uint32_t iReg, uint64_t Value); +VMM_INT_DECL(int) CPUMSetGuestXcr0(PVMCPUCC pVCpu, uint64_t uNewValue); +VMMDECL(int) CPUMSetGuestEFlags(PVMCPU pVCpu, uint32_t eflags); +VMMDECL(int) CPUMSetGuestEIP(PVMCPU pVCpu, uint32_t eip); +VMMDECL(int) CPUMSetGuestEAX(PVMCPU pVCpu, uint32_t eax); +VMMDECL(int) CPUMSetGuestEBX(PVMCPU pVCpu, uint32_t ebx); +VMMDECL(int) CPUMSetGuestECX(PVMCPU pVCpu, uint32_t ecx); +VMMDECL(int) CPUMSetGuestEDX(PVMCPU pVCpu, uint32_t edx); +VMMDECL(int) CPUMSetGuestESI(PVMCPU pVCpu, uint32_t esi); +VMMDECL(int) CPUMSetGuestEDI(PVMCPU pVCpu, uint32_t edi); +VMMDECL(int) CPUMSetGuestESP(PVMCPU pVCpu, uint32_t esp); +VMMDECL(int) CPUMSetGuestEBP(PVMCPU pVCpu, uint32_t ebp); +VMMDECL(int) CPUMSetGuestCS(PVMCPU pVCpu, uint16_t cs); +VMMDECL(int) CPUMSetGuestDS(PVMCPU pVCpu, uint16_t ds); +VMMDECL(int) CPUMSetGuestES(PVMCPU pVCpu, uint16_t es); +VMMDECL(int) CPUMSetGuestFS(PVMCPU pVCpu, uint16_t fs); +VMMDECL(int) CPUMSetGuestGS(PVMCPU pVCpu, uint16_t gs); +VMMDECL(int) CPUMSetGuestSS(PVMCPU pVCpu, uint16_t ss); +VMMDECL(void) CPUMSetGuestEFER(PVMCPU pVCpu, uint64_t val); +VMMR3_INT_DECL(void) CPUMR3SetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature); +VMMR3_INT_DECL(void) CPUMR3ClearGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature); +VMMR3_INT_DECL(bool) CPUMR3GetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature); +VMMDECL(bool) CPUMSetGuestCpuIdPerCpuApicFeature(PVMCPU pVCpu, bool fVisible); +VMMDECL(void) CPUMSetGuestCtx(PVMCPU pVCpu, const PCPUMCTX pCtx); +VMM_INT_DECL(void) CPUMSetGuestTscAux(PVMCPUCC pVCpu, uint64_t uValue); +VMM_INT_DECL(uint64_t) CPUMGetGuestTscAux(PVMCPUCC pVCpu); +VMM_INT_DECL(void) CPUMSetGuestSpecCtrl(PVMCPUCC pVCpu, uint64_t uValue); +VMM_INT_DECL(uint64_t) CPUMGetGuestSpecCtrl(PVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestCR4ValidMask(PVM pVM); +VMM_INT_DECL(void) CPUMSetGuestPaePdpes(PVMCPU pVCpu, PCX86PDPE paPaePdpes); +VMM_INT_DECL(void) CPUMGetGuestPaePdpes(PVMCPU pVCpu, PX86PDPE paPaePdpes); +/** @} */ + + +/** @name Misc Guest Predicate Functions. + * @{ */ +VMMDECL(bool) CPUMIsGuestIn64BitCode(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestNXEnabled(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestPageSizeExtEnabled(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestPagingEnabled(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestR0WriteProtEnabled(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInRealMode(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInRealOrV86Mode(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInProtectedMode(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInPagedProtectedMode(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInLongMode(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInPAEMode(PCVMCPU pVCpu); +/** @} */ + +/** @name Nested Hardware-Virtualization Helpers. + * @{ */ +VMM_INT_DECL(bool) CPUMIsGuestPhysIntrEnabled(PVMCPU pVCpu); +VMM_INT_DECL(bool) CPUMIsGuestVirtIntrEnabled(PVMCPU pVCpu); +VMM_INT_DECL(uint64_t) CPUMApplyNestedGuestTscOffset(PCVMCPU pVCpu, uint64_t uTscValue); +VMM_INT_DECL(uint64_t) CPUMRemoveNestedGuestTscOffset(PCVMCPU pVCpu, uint64_t uTscValue); + +/* SVM helpers. */ +VMM_INT_DECL(bool) CPUMIsGuestSvmPhysIntrEnabled(PCVMCPU pVCpu, PCCPUMCTX pCtx); +VMM_INT_DECL(bool) CPUMIsGuestSvmVirtIntrEnabled(PCVMCPU pVCpu, PCCPUMCTX pCtx); +VMM_INT_DECL(uint8_t) CPUMGetGuestSvmVirtIntrVector(PCCPUMCTX pCtx); +VMM_INT_DECL(void) CPUMSvmVmExitRestoreHostState(PVMCPUCC pVCpu, PCPUMCTX pCtx); +VMM_INT_DECL(void) CPUMSvmVmRunSaveHostState(PCPUMCTX pCtx, uint8_t cbInstr); +VMM_INT_DECL(bool) CPUMIsSvmIoInterceptSet(void *pvIoBitmap, uint16_t u16Port, SVMIOIOTYPE enmIoType, uint8_t cbReg, + uint8_t cAddrSizeBits, uint8_t iEffSeg, bool fRep, bool fStrIo, + PSVMIOIOEXITINFO pIoExitInfo); +VMM_INT_DECL(int) CPUMGetSvmMsrpmOffsetAndBit(uint32_t idMsr, uint16_t *pbOffMsrpm, uint8_t *puMsrpmBit); + +/* VMX helpers. */ +VMM_INT_DECL(bool) CPUMIsGuestVmxVmcsFieldValid(PVMCC pVM, uint64_t u64VmcsField); +VMM_INT_DECL(bool) CPUMIsGuestVmxIoInterceptSet(PCVMCPU pVCpu, uint16_t u16Port, uint8_t cbAccess); +VMM_INT_DECL(bool) CPUMIsGuestVmxMovToCr3InterceptSet(PVMCPU pVCpu, uint64_t uNewCr3); +VMM_INT_DECL(bool) CPUMIsGuestVmxVmreadVmwriteInterceptSet(PCVMCPU pVCpu, uint32_t uExitReason, uint64_t u64FieldEnc); +VMM_INT_DECL(int) CPUMStartGuestVmxPremptTimer(PVMCPUCC pVCpu, uint32_t uTimer, uint8_t cShift, uint64_t *pu64EntryTick); +VMM_INT_DECL(int) CPUMStopGuestVmxPremptTimer(PVMCPUCC pVCpu); +VMM_INT_DECL(uint32_t) CPUMGetVmxMsrPermission(void const *pvMsrBitmap, uint32_t idMsr); +VMM_INT_DECL(bool) CPUMIsGuestVmxEptPagingEnabled(PCVMCPUCC pVCpu); +VMM_INT_DECL(bool) CPUMIsGuestVmxEptPaePagingEnabled(PCVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestVmxApicAccessPageAddr(PCVMCPUCC pVCpu); +/** @} */ + +/** @name Externalized State Helpers. + * @{ */ +/** @def CPUM_ASSERT_NOT_EXTRN + * Macro for asserting that @a a_fNotExtrn are present. + * + * @param a_pVCpu The cross context virtual CPU structure of the calling EMT. + * @param a_fNotExtrn Mask of CPUMCTX_EXTRN_XXX bits to check. + * + * @remarks Requires VMCPU_INCL_CPUM_GST_CTX to be defined. + */ +#define CPUM_ASSERT_NOT_EXTRN(a_pVCpu, a_fNotExtrn) \ + AssertMsg(!((a_pVCpu)->cpum.GstCtx.fExtrn & (a_fNotExtrn)), \ + ("%#RX64; a_fNotExtrn=%#RX64\n", (a_pVCpu)->cpum.GstCtx.fExtrn, (a_fNotExtrn))) + +/** @def CPUMCTX_ASSERT_NOT_EXTRN + * Macro for asserting that @a a_fNotExtrn are present in @a a_pCtx. + * + * @param a_pCtx The CPU context of the calling EMT. + * @param a_fNotExtrn Mask of CPUMCTX_EXTRN_XXX bits to check. + */ +#define CPUMCTX_ASSERT_NOT_EXTRN(a_pCtx, a_fNotExtrn) \ + AssertMsg(!((a_pCtx)->fExtrn & (a_fNotExtrn)), \ + ("%#RX64; a_fNotExtrn=%#RX64\n", (a_pCtx)->fExtrn, (a_fNotExtrn))) + +/** @def CPUM_IMPORT_EXTRN_RET + * Macro for making sure the state specified by @a fExtrnImport is present, + * calling CPUMImportGuestStateOnDemand() to get it if necessary. + * + * Will return if CPUMImportGuestStateOnDemand() fails. + * + * @param a_pVCpu The cross context virtual CPU structure of the calling EMT. + * @param a_fExtrnImport Mask of CPUMCTX_EXTRN_XXX bits to get. + * @thread EMT(a_pVCpu) + * + * @remarks Requires VMCPU_INCL_CPUM_GST_CTX to be defined. + */ +#define CPUM_IMPORT_EXTRN_RET(a_pVCpu, a_fExtrnImport) \ + do { \ + if (!((a_pVCpu)->cpum.GstCtx.fExtrn & (a_fExtrnImport))) \ + { /* already present, consider this likely */ } \ + else \ + { \ + int rcCpumImport = CPUMImportGuestStateOnDemand(a_pVCpu, a_fExtrnImport); \ + AssertRCReturn(rcCpumImport, rcCpumImport); \ + } \ + } while (0) + +/** @def CPUM_IMPORT_EXTRN_RCSTRICT + * Macro for making sure the state specified by @a fExtrnImport is present, + * calling CPUMImportGuestStateOnDemand() to get it if necessary. + * + * Will update a_rcStrict if CPUMImportGuestStateOnDemand() fails. + * + * @param a_pVCpu The cross context virtual CPU structure of the calling EMT. + * @param a_fExtrnImport Mask of CPUMCTX_EXTRN_XXX bits to get. + * @param a_rcStrict Strict status code variable to update on failure. + * @thread EMT(a_pVCpu) + * + * @remarks Requires VMCPU_INCL_CPUM_GST_CTX to be defined. + */ +#define CPUM_IMPORT_EXTRN_RCSTRICT(a_pVCpu, a_fExtrnImport, a_rcStrict) \ + do { \ + if (!((a_pVCpu)->cpum.GstCtx.fExtrn & (a_fExtrnImport))) \ + { /* already present, consider this likely */ } \ + else \ + { \ + int rcCpumImport = CPUMImportGuestStateOnDemand(a_pVCpu, a_fExtrnImport); \ + AssertStmt(RT_SUCCESS(rcCpumImport) || RT_FAILURE_NP(a_rcStrict), a_rcStrict = rcCpumImport); \ + } \ + } while (0) + +VMM_INT_DECL(int) CPUMImportGuestStateOnDemand(PVMCPUCC pVCpu, uint64_t fExtrnImport); +/** @} */ + +#if !defined(IPRT_WITHOUT_NAMED_UNIONS_AND_STRUCTS) || defined(DOXYGEN_RUNNING) +/** @name Inlined Guest Getters and predicates Functions. + * @{ */ + +/** + * Gets valid CR0 bits for the guest. + * + * @returns Valid CR0 bits. + */ +DECLINLINE(uint64_t) CPUMGetGuestCR0ValidMask(void) +{ + return ( X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS + | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM + | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG); +} + +/** + * Tests if the guest is running in real mode or not. + * + * @returns true if in real mode, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInRealModeEx(PCCPUMCTX pCtx) +{ + return !(pCtx->cr0 & X86_CR0_PE); +} + +/** + * Tests if the guest is running in real or virtual 8086 mode. + * + * @returns @c true if it is, @c false if not. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInRealOrV86ModeEx(PCCPUMCTX pCtx) +{ + return !(pCtx->cr0 & X86_CR0_PE) + || pCtx->eflags.Bits.u1VM; /* Cannot be set in long mode. Intel spec 2.3.1 "System Flags and Fields in IA-32e Mode". */ +} + +/** + * Tests if the guest is running in virtual 8086 mode. + * + * @returns @c true if it is, @c false if not. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInV86ModeEx(PCCPUMCTX pCtx) +{ + return (pCtx->eflags.Bits.u1VM == 1); +} + +/** + * Tests if the guest is running in paged protected or not. + * + * @returns true if in paged protected mode, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInPagedProtectedModeEx(PCPUMCTX pCtx) +{ + return (pCtx->cr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG); +} + +/** + * Tests if the guest is running in long mode or not. + * + * @returns true if in long mode, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInLongModeEx(PCCPUMCTX pCtx) +{ + return (pCtx->msrEFER & MSR_K6_EFER_LMA) == MSR_K6_EFER_LMA; +} + +VMM_INT_DECL(bool) CPUMIsGuestIn64BitCodeSlow(PCPUMCTX pCtx); + +/** + * Tests if the guest is running in 64 bits mode or not. + * + * @returns true if in 64 bits protected mode, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestIn64BitCodeEx(PCPUMCTX pCtx) +{ + if (!(pCtx->msrEFER & MSR_K6_EFER_LMA)) + return false; + if (!CPUMSELREG_ARE_HIDDEN_PARTS_VALID(NULL, &pCtx->cs)) + return CPUMIsGuestIn64BitCodeSlow(pCtx); + return pCtx->cs.Attr.n.u1Long; +} + +/** + * Tests if the guest has paging enabled or not. + * + * @returns true if paging is enabled, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestPagingEnabledEx(PCCPUMCTX pCtx) +{ + return !!(pCtx->cr0 & X86_CR0_PG); +} + +/** + * Tests if PAE paging is enabled given the relevant control registers. + * + * @returns @c true if in PAE mode, @c false otherwise. + * @param uCr0 The CR0 value. + * @param uCr4 The CR4 value. + * @param uEferMsr The EFER value. + */ +DECLINLINE(bool) CPUMIsPaePagingEnabled(uint64_t uCr0, uint64_t uCr4, uint64_t uEferMsr) +{ + /* Intel mentions EFER.LMA and EFER.LME in different parts of their spec. We shall use EFER.LMA rather + than EFER.LME as it reflects if the CPU has entered paging with EFER.LME set. */ + return ( (uCr4 & X86_CR4_PAE) + && (uCr0 & X86_CR0_PG) + && !(uEferMsr & MSR_K6_EFER_LMA)); +} + +/** + * Tests if the guest is running in PAE mode or not. + * + * @returns @c true if in PAE mode, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInPAEModeEx(PCCPUMCTX pCtx) +{ + return CPUMIsPaePagingEnabled(pCtx->cr0, pCtx->cr4, pCtx->msrEFER); +} + +/** + * Tests if the guest has AMD SVM enabled or not. + * + * @returns true if SMV is enabled, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestSvmEnabled(PCCPUMCTX pCtx) +{ + return RT_BOOL(pCtx->msrEFER & MSR_K6_EFER_SVME); +} + +/** + * Tests if the guest has Intel VT-x enabled or not. + * + * @returns true if VMX is enabled, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxEnabled(PCCPUMCTX pCtx) +{ + return RT_BOOL(pCtx->cr4 & X86_CR4_VMXE); +} + +/** + * Returns the guest's global-interrupt (GIF) flag. + * + * @returns true when global-interrupts are enabled, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMGetGuestGif(PCCPUMCTX pCtx) +{ + return pCtx->hwvirt.fGif; +} + +/** + * Sets the guest's global-interrupt flag (GIF). + * + * @param pCtx Current CPU context. + * @param fGif The value to set. + */ +DECLINLINE(void) CPUMSetGuestGif(PCPUMCTX pCtx, bool fGif) +{ + pCtx->hwvirt.fGif = fGif; +} + +/** + * Checks if we're in an "interrupt shadow", i.e. after a STI, POP SS or MOV SS. + * + * This also inhibit NMIs, except perhaps for nested guests. + * + * @returns true if interrupts are inhibited by interrupt shadow, false if not. + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + * @note Does NOT clear CPUMCTX_INHIBIT_SHADOW when CPUMCTX::uRipInhibitInt + * differs from CPUMCTX::rip. + */ +DECLINLINE(bool) CPUMIsInInterruptShadow(PCCPUMCTX pCtx) +{ + if (!(pCtx->eflags.uBoth & CPUMCTX_INHIBIT_SHADOW)) + return false; + + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + return pCtx->uRipInhibitInt == pCtx->rip; +} + +/** + * Checks if we're in an "interrupt shadow", i.e. after a STI, POP SS or MOV SS, + * updating the state if stale. + * + * This also inhibit NMIs, except perhaps for nested guests. + * + * @retval true if interrupts are inhibited by interrupt shadow. + * @retval false if not. + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + */ +DECLINLINE(bool) CPUMIsInInterruptShadowWithUpdate(PCPUMCTX pCtx) +{ + if (!(pCtx->eflags.uBoth & CPUMCTX_INHIBIT_SHADOW)) + return false; + + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + if (pCtx->uRipInhibitInt == pCtx->rip) + return true; + + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_SHADOW; + return false; +} + +/** + * Checks if we're in an "interrupt shadow" due to a POP SS or MOV SS + * instruction. + * + * This also inhibit NMIs, except perhaps for nested guests. + * + * @retval true if interrupts are inhibited due to POP/MOV SS. + * @retval false if not. + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + * @note Does NOT clear CPUMCTX_INHIBIT_SHADOW when CPUMCTX::uRipInhibitInt + * differs from CPUMCTX::rip. + * @note Both CPUMIsInInterruptShadowAfterSti() and this function may return + * true depending on the execution engine being used. + */ +DECLINLINE(bool) CPUMIsInInterruptShadowAfterSs(PCCPUMCTX pCtx) +{ + if (!(pCtx->eflags.uBoth & CPUMCTX_INHIBIT_SHADOW_SS)) + return false; + + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + return pCtx->uRipInhibitInt == pCtx->rip; +} + +/** + * Checks if we're in an "interrupt shadow" due to an STI instruction. + * + * This also inhibit NMIs, except perhaps for nested guests. + * + * @retval true if interrupts are inhibited due to STI. + * @retval false if not. + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + * @note Does NOT clear CPUMCTX_INHIBIT_SHADOW when CPUMCTX::uRipInhibitInt + * differs from CPUMCTX::rip. + * @note Both CPUMIsInInterruptShadowAfterSs() and this function may return + * true depending on the execution engine being used. + */ +DECLINLINE(bool) CPUMIsInInterruptShadowAfterSti(PCCPUMCTX pCtx) +{ + if (!(pCtx->eflags.uBoth & CPUMCTX_INHIBIT_SHADOW_STI)) + return false; + + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + return pCtx->uRipInhibitInt == pCtx->rip; +} + +/** + * Sets the "interrupt shadow" flag, after a STI, POP SS or MOV SS instruction. + * + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + */ +DECLINLINE(void) CPUMSetInInterruptShadow(PCPUMCTX pCtx) +{ + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW; + pCtx->uRipInhibitInt = pCtx->rip; +} + +/** + * Sets the "interrupt shadow" flag, after a STI, POP SS or MOV SS instruction, + * extended version. + * + * @param pCtx Current guest CPU context. + * @param rip The RIP for which it is inhibited. + */ +DECLINLINE(void) CPUMSetInInterruptShadowEx(PCPUMCTX pCtx, uint64_t rip) +{ + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW; + pCtx->uRipInhibitInt = rip; +} + +/** + * Sets the "interrupt shadow" flag after a POP SS or MOV SS instruction. + * + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + */ +DECLINLINE(void) CPUMSetInInterruptShadowSs(PCPUMCTX pCtx) +{ + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW_SS; + pCtx->uRipInhibitInt = pCtx->rip; +} + +/** + * Sets the "interrupt shadow" flag after an STI instruction. + * + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + */ +DECLINLINE(void) CPUMSetInInterruptShadowSti(PCPUMCTX pCtx) +{ + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW_STI; + pCtx->uRipInhibitInt = pCtx->rip; +} + +/** + * Clears the "interrupt shadow" flag. + * + * @param pCtx Current guest CPU context. + */ +DECLINLINE(void) CPUMClearInterruptShadow(PCPUMCTX pCtx) +{ + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_SHADOW; +} + +/** + * Update the "interrupt shadow" flag. + * + * @param pCtx Current guest CPU context. + * @param fInhibited The new state. + * @note Requires pCtx->rip to be up to date. + */ +DECLINLINE(void) CPUMUpdateInterruptShadow(PCPUMCTX pCtx, bool fInhibited) +{ + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + if (!fInhibited) + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_SHADOW; + else + { + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW; + pCtx->uRipInhibitInt = pCtx->rip; + } +} + +/** + * Update the "interrupt shadow" flag, extended version. + * + * @returns fInhibited. + * @param pCtx Current guest CPU context. + * @param fInhibited The new state. + * @param rip The RIP for which it is inhibited. + */ +DECLINLINE(bool) CPUMUpdateInterruptShadowEx(PCPUMCTX pCtx, bool fInhibited, uint64_t rip) +{ + if (!fInhibited) + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_SHADOW; + else + { + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW; + pCtx->uRipInhibitInt = rip; + } + return fInhibited; +} + +/** + * Update the two "interrupt shadow" flags separately, extended version. + * + * @param pCtx Current guest CPU context. + * @param fInhibitedBySs The new state for the MOV SS & POP SS aspect. + * @param fInhibitedBySti The new state for the STI aspect. + * @param rip The RIP for which it is inhibited. + */ +DECLINLINE(void) CPUMUpdateInterruptShadowSsStiEx(PCPUMCTX pCtx, bool fInhibitedBySs, bool fInhibitedBySti, uint64_t rip) +{ + if (!(fInhibitedBySs | fInhibitedBySti)) + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_SHADOW; + else + { + pCtx->eflags.uBoth |= (fInhibitedBySs ? CPUMCTX_INHIBIT_SHADOW_SS : UINT32_C(0)) + | (fInhibitedBySti ? CPUMCTX_INHIBIT_SHADOW_STI : UINT32_C(0)); + pCtx->uRipInhibitInt = rip; + } +} + +/* VMX forward declarations used by extended function versions: */ +DECLINLINE(bool) CPUMIsGuestInVmxNonRootMode(PCCPUMCTX pCtx); +DECLINLINE(bool) CPUMIsGuestVmxPinCtlsSet(PCCPUMCTX pCtx, uint32_t uPinCtls); +DECLINLINE(bool) CPUMIsGuestVmxVirtNmiBlocking(PCCPUMCTX pCtx); +DECLINLINE(void) CPUMSetGuestVmxVirtNmiBlocking(PCPUMCTX pCtx, bool fBlocking); + +/** + * Checks whether interrupts, include NMIs, are inhibited by pending NMI + * delivery. + * + * This only checks the inhibit mask. + * + * @retval true if interrupts are inhibited by NMI handling. + * @retval false if interrupts are not inhibited by NMI handling. + * @param pCtx Current guest CPU context. + */ +DECLINLINE(bool) CPUMAreInterruptsInhibitedByNmi(PCCPUMCTX pCtx) +{ + return (pCtx->eflags.uBoth & CPUMCTX_INHIBIT_NMI) != 0; +} + +/** + * Extended version of CPUMAreInterruptsInhibitedByNmi() that takes VMX non-root + * mode into account when check whether interrupts are inhibited by NMI. + * + * @retval true if interrupts are inhibited by NMI handling. + * @retval false if interrupts are not inhibited by NMI handling. + * @param pCtx Current guest CPU context. + */ +DECLINLINE(bool) CPUMAreInterruptsInhibitedByNmiEx(PCCPUMCTX pCtx) +{ + /* See CPUMUpdateInterruptInhibitingByNmiEx for comments. */ + if ( !CPUMIsGuestInVmxNonRootMode(pCtx) + || !CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)) + return CPUMAreInterruptsInhibitedByNmi(pCtx); + return CPUMIsGuestVmxVirtNmiBlocking(pCtx); +} + +/** + * Marks interrupts, include NMIs, as inhibited by pending NMI delivery. + * + * @param pCtx Current guest CPU context. + */ +DECLINLINE(void) CPUMSetInterruptInhibitingByNmi(PCPUMCTX pCtx) +{ + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_NMI; +} + +/** + * Extended version of CPUMSetInterruptInhibitingByNmi() that takes VMX non-root + * mode into account when marking interrupts as inhibited by NMI. + * + * @param pCtx Current guest CPU context. + */ +DECLINLINE(void) CPUMSetInterruptInhibitingByNmiEx(PCPUMCTX pCtx) +{ + /* See CPUMUpdateInterruptInhibitingByNmiEx for comments. */ + if ( !CPUMIsGuestInVmxNonRootMode(pCtx) + || !CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)) + CPUMSetInterruptInhibitingByNmi(pCtx); + else + CPUMSetGuestVmxVirtNmiBlocking(pCtx, true); +} + +/** + * Marks interrupts, include NMIs, as no longer inhibited by pending NMI + * delivery. + * + * @param pCtx Current guest CPU context. + */ +DECLINLINE(void) CPUMClearInterruptInhibitingByNmi(PCPUMCTX pCtx) +{ + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_NMI; +} + +/** + * Extended version of CPUMClearInterruptInhibitingByNmi() that takes VMX + * non-root mode into account when doing the updating. + * + * @param pCtx Current guest CPU context. + */ +DECLINLINE(void) CPUMClearInterruptInhibitingByNmiEx(PCPUMCTX pCtx) +{ + /* See CPUMUpdateInterruptInhibitingByNmiEx for comments. */ + if ( !CPUMIsGuestInVmxNonRootMode(pCtx) + || !CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)) + CPUMClearInterruptInhibitingByNmi(pCtx); + else + CPUMSetGuestVmxVirtNmiBlocking(pCtx, false); +} + +/** + * Update whether interrupts, include NMIs, are inhibited by pending NMI + * delivery. + * + * @param pCtx Current guest CPU context. + * @param fInhibited The new state. + */ +DECLINLINE(void) CPUMUpdateInterruptInhibitingByNmi(PCPUMCTX pCtx, bool fInhibited) +{ + if (!fInhibited) + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_NMI; + else + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_NMI; +} + +/** + * Extended version of CPUMUpdateInterruptInhibitingByNmi() that takes VMX + * non-root mode into account when doing the updating. + * + * @param pCtx Current guest CPU context. + * @param fInhibited The new state. + */ +DECLINLINE(void) CPUMUpdateInterruptInhibitingByNmiEx(PCPUMCTX pCtx, bool fInhibited) +{ + /* + * Set the state of guest-NMI blocking in any of the following cases: + * - We're not executing a nested-guest. + * - We're executing an SVM nested-guest[1]. + * - We're executing a VMX nested-guest without virtual-NMIs enabled. + * + * [1] -- SVM does not support virtual-NMIs or virtual-NMI blocking. + * SVM hypervisors must track NMI blocking themselves by intercepting + * the IRET instruction after injection of an NMI. + */ + if ( !CPUMIsGuestInVmxNonRootMode(pCtx) + || !CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)) + CPUMUpdateInterruptInhibitingByNmi(pCtx, fInhibited); + /* + * Set the state of virtual-NMI blocking, if we are executing a + * VMX nested-guest with virtual-NMIs enabled. + */ + else + CPUMSetGuestVmxVirtNmiBlocking(pCtx, fInhibited); +} + + +/** + * Checks if we are executing inside an SVM nested hardware-virtualized guest. + * + * @returns @c true if in SVM nested-guest mode, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInSvmNestedHwVirtMode(PCCPUMCTX pCtx) +{ + /* + * With AMD-V, the VMRUN intercept is a pre-requisite to entering SVM guest-mode. + * See AMD spec. 15.5 "VMRUN instruction" subsection "Canonicalization and Consistency Checks". + */ +#ifndef IN_RC + if ( pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM + || !(pCtx->hwvirt.svm.Vmcb.ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_VMRUN)) + return false; + return true; +#else + NOREF(pCtx); + return false; +#endif +} + +/** + * Checks if the guest is in VMX non-root operation. + * + * @returns @c true if in VMX non-root operation, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInVmxNonRootMode(PCCPUMCTX pCtx) +{ +#ifndef IN_RC + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_VMX) + return false; + Assert(!pCtx->hwvirt.vmx.fInVmxNonRootMode || pCtx->hwvirt.vmx.fInVmxRootMode); + return pCtx->hwvirt.vmx.fInVmxNonRootMode; +#else + NOREF(pCtx); + return false; +#endif +} + +/** + * Checks if we are executing inside an SVM or VMX nested hardware-virtualized + * guest. + * + * @returns @c true if in nested-guest mode, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInNestedHwvirtMode(PCCPUMCTX pCtx) +{ +#if 0 + return CPUMIsGuestInVmxNonRootMode(pCtx) || CPUMIsGuestInSvmNestedHwVirtMode(pCtx); +#else + if (pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_NONE) + return false; + if (pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_VMX) + { + Assert(!pCtx->hwvirt.vmx.fInVmxNonRootMode || pCtx->hwvirt.vmx.fInVmxRootMode); + return pCtx->hwvirt.vmx.fInVmxNonRootMode; + } + Assert(pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_SVM); + return RT_BOOL(pCtx->hwvirt.svm.Vmcb.ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_VMRUN); +#endif +} + +/** + * Checks if we are executing inside an SVM or VMX nested hardware-virtualized + * guest. + * + * @retval CPUMHWVIRT_NONE if not in SVM or VMX non-root mode. + * @retval CPUMHWVIRT_VMX if in VMX non-root mode. + * @retval CPUMHWVIRT_SVM if in SVM non-root mode. + * @param pCtx Current CPU context. + */ +DECLINLINE(CPUMHWVIRT) CPUMGetGuestInNestedHwvirtMode(PCCPUMCTX pCtx) +{ + if (pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_NONE) + return CPUMHWVIRT_NONE; + if (pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_VMX) + { + Assert(!pCtx->hwvirt.vmx.fInVmxNonRootMode || pCtx->hwvirt.vmx.fInVmxRootMode); + return pCtx->hwvirt.vmx.fInVmxNonRootMode ? CPUMHWVIRT_VMX : CPUMHWVIRT_NONE; + } + Assert(pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_SVM); + return pCtx->hwvirt.svm.Vmcb.ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_VMRUN ? CPUMHWVIRT_SVM : CPUMHWVIRT_NONE; +} + +/** + * Checks if the guest is in VMX root operation. + * + * @returns @c true if in VMX root operation, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInVmxRootMode(PCCPUMCTX pCtx) +{ +#ifndef IN_RC + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_VMX) + return false; + return pCtx->hwvirt.vmx.fInVmxRootMode; +#else + NOREF(pCtx); + return false; +#endif +} + +# ifndef IN_RC + +/** + * Checks if the nested-guest VMCB has the specified ctrl/instruction intercept + * active. + * + * @returns @c true if in intercept is set, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param fIntercept The SVM control/instruction intercept, see + * SVM_CTRL_INTERCEPT_*. + */ +DECLINLINE(bool) CPUMIsGuestSvmCtrlInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint64_t fIntercept) +{ + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint64_t u64Intercepts; + if (!HMGetGuestSvmCtrlIntercepts(pVCpu, &u64Intercepts)) + u64Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u64InterceptCtrl; + return RT_BOOL(u64Intercepts & fIntercept); +} + +/** + * Checks if the nested-guest VMCB has the specified CR read intercept active. + * + * @returns @c true if in intercept is set, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param uCr The CR register number (0 to 15). + */ +DECLINLINE(bool) CPUMIsGuestSvmReadCRxInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uCr) +{ + Assert(uCr < 16); + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint16_t u16Intercepts; + if (!HMGetGuestSvmReadCRxIntercepts(pVCpu, &u16Intercepts)) + u16Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u16InterceptRdCRx; + return RT_BOOL(u16Intercepts & (UINT16_C(1) << uCr)); +} + +/** + * Checks if the nested-guest VMCB has the specified CR write intercept active. + * + * @returns @c true if in intercept is set, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param uCr The CR register number (0 to 15). + */ +DECLINLINE(bool) CPUMIsGuestSvmWriteCRxInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uCr) +{ + Assert(uCr < 16); + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint16_t u16Intercepts; + if (!HMGetGuestSvmWriteCRxIntercepts(pVCpu, &u16Intercepts)) + u16Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u16InterceptWrCRx; + return RT_BOOL(u16Intercepts & (UINT16_C(1) << uCr)); +} + +/** + * Checks if the nested-guest VMCB has the specified DR read intercept active. + * + * @returns @c true if in intercept is set, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param uDr The DR register number (0 to 15). + */ +DECLINLINE(bool) CPUMIsGuestSvmReadDRxInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uDr) +{ + Assert(uDr < 16); + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint16_t u16Intercepts; + if (!HMGetGuestSvmReadDRxIntercepts(pVCpu, &u16Intercepts)) + u16Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u16InterceptRdDRx; + return RT_BOOL(u16Intercepts & (UINT16_C(1) << uDr)); +} + +/** + * Checks if the nested-guest VMCB has the specified DR write intercept active. + * + * @returns @c true if in intercept is set, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param uDr The DR register number (0 to 15). + */ +DECLINLINE(bool) CPUMIsGuestSvmWriteDRxInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uDr) +{ + Assert(uDr < 16); + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint16_t u16Intercepts; + if (!HMGetGuestSvmWriteDRxIntercepts(pVCpu, &u16Intercepts)) + u16Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u16InterceptWrDRx; + return RT_BOOL(u16Intercepts & (UINT16_C(1) << uDr)); +} + +/** + * Checks if the nested-guest VMCB has the specified exception intercept active. + * + * @returns @c true if in intercept is active, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param uVector The exception / interrupt vector. + */ +DECLINLINE(bool) CPUMIsGuestSvmXcptInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uVector) +{ + Assert(uVector <= X86_XCPT_LAST); + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint32_t u32Intercepts; + if (!HMGetGuestSvmXcptIntercepts(pVCpu, &u32Intercepts)) + u32Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u32InterceptXcpt; + return RT_BOOL(u32Intercepts & RT_BIT(uVector)); +} + +/** + * Checks if the nested-guest VMCB has virtual-interrupt masking enabled. + * + * @returns @c true if virtual-interrupts are masked, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * + * @remarks Should only be called when SVM feature is exposed to the guest. + */ +DECLINLINE(bool) CPUMIsGuestSvmVirtIntrMasking(PCVMCPU pVCpu, PCCPUMCTX pCtx) +{ + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + bool fVIntrMasking; + if (!HMGetGuestSvmVirtIntrMasking(pVCpu, &fVIntrMasking)) + fVIntrMasking = pCtx->hwvirt.svm.Vmcb.ctrl.IntCtrl.n.u1VIntrMasking; + return fVIntrMasking; +} + +/** + * Checks if the nested-guest VMCB has nested-paging enabled. + * + * @returns @c true if nested-paging is enabled, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * + * @remarks Should only be called when SVM feature is exposed to the guest. + */ +DECLINLINE(bool) CPUMIsGuestSvmNestedPagingEnabled(PCVMCPU pVCpu, PCCPUMCTX pCtx) +{ + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + bool fNestedPaging; + if (!HMGetGuestSvmNestedPaging(pVCpu, &fNestedPaging)) + fNestedPaging = pCtx->hwvirt.svm.Vmcb.ctrl.NestedPagingCtrl.n.u1NestedPaging; + return fNestedPaging; +} + +/** + * Gets the nested-guest VMCB pause-filter count. + * + * @returns The pause-filter count. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * + * @remarks Should only be called when SVM feature is exposed to the guest. + */ +DECLINLINE(uint16_t) CPUMGetGuestSvmPauseFilterCount(PCVMCPU pVCpu, PCCPUMCTX pCtx) +{ + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint16_t u16PauseFilterCount; + if (!HMGetGuestSvmPauseFilterCount(pVCpu, &u16PauseFilterCount)) + u16PauseFilterCount = pCtx->hwvirt.svm.Vmcb.ctrl.u16PauseFilterCount; + return u16PauseFilterCount; +} + +/** + * Updates the NextRIP (NRIP) field in the nested-guest VMCB. + * + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param cbInstr The length of the current instruction in bytes. + * + * @remarks Should only be called when SVM feature is exposed to the guest. + */ +DECLINLINE(void) CPUMGuestSvmUpdateNRip(PVMCPU pVCpu, PCPUMCTX pCtx, uint8_t cbInstr) +{ + RT_NOREF(pVCpu); + Assert(pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_SVM); + pCtx->hwvirt.svm.Vmcb.ctrl.u64NextRIP = pCtx->rip + cbInstr; +} + +/** + * Checks whether one of the given Pin-based VM-execution controls are set when + * executing a nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uPinCtls The Pin-based VM-execution controls to check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uPinCtl. + */ +DECLINLINE(bool) CPUMIsGuestVmxPinCtlsSet(PCCPUMCTX pCtx, uint32_t uPinCtls) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32PinCtls & uPinCtls); +} + +/** + * Checks whether one of the given Processor-based VM-execution controls are set + * when executing a nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uProcCtls The Processor-based VM-execution controls to check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uProcCtls. + */ +DECLINLINE(bool) CPUMIsGuestVmxProcCtlsSet(PCCPUMCTX pCtx, uint32_t uProcCtls) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32ProcCtls & uProcCtls); +} + +/** + * Checks whether one of the given Secondary Processor-based VM-execution controls + * are set when executing a nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uProcCtls2 The Secondary Processor-based VM-execution controls to + * check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uProcCtls2. + */ +DECLINLINE(bool) CPUMIsGuestVmxProcCtls2Set(PCCPUMCTX pCtx, uint32_t uProcCtls2) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32ProcCtls2 & uProcCtls2); +} + +/** + * Checks whether one of the given Tertiary Processor-based VM-execution controls + * are set when executing a nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uProcCtls3 The Tertiary Processor-based VM-execution controls to + * check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uProcCtls3. + */ +DECLINLINE(bool) CPUMIsGuestVmxProcCtls3Set(PCCPUMCTX pCtx, uint64_t uProcCtls3) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u64ProcCtls3.u & uProcCtls3); +} + +/** + * Checks whether one of the given VM-exit controls are set when executing a + * nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uExitCtls The VM-exit controls to check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uExitCtls. + */ +DECLINLINE(bool) CPUMIsGuestVmxExitCtlsSet(PCCPUMCTX pCtx, uint32_t uExitCtls) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32ExitCtls & uExitCtls); +} + +/** + * Checks whether one of the given VM-entry controls are set when executing a + * nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uEntryCtls The VM-entry controls to check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uEntryCtls. + */ +DECLINLINE(bool) CPUMIsGuestVmxEntryCtlsSet(PCCPUMCTX pCtx, uint32_t uEntryCtls) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32EntryCtls & uEntryCtls); +} + +/** + * Checks whether events injected in the nested-guest are subject to VM-exit checks. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxInterceptEvents(PCCPUMCTX pCtx) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return pCtx->hwvirt.vmx.fInterceptEvents; +} + +/** + * Sets whether events injected in the nested-guest are subject to VM-exit checks. + * + * @param pCtx Current CPU context. + * @param fIntercept Whether to subject injected events to VM-exits or not. + */ +DECLINLINE(void) CPUMSetGuestVmxInterceptEvents(PCPUMCTX pCtx, bool fInterceptEvents) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + pCtx->hwvirt.vmx.fInterceptEvents = fInterceptEvents; +} + +/** + * Checks whether the given exception causes a VM-exit. + * + * The exception type include hardware exceptions, software exceptions (#BP, #OF) + * and privileged software exceptions (#DB generated by INT1/ICEBP). + * + * Software interrupts do -not- cause VM-exits and hence must not be used with this + * function. + * + * @returns @c true if the exception causes a VM-exit, @c false otherwise. + * @param pCtx Current CPU context. + * @param uVector The exception vector. + * @param uErrCode The error code associated with the exception. Pass 0 if not + * applicable. + */ +DECLINLINE(bool) CPUMIsGuestVmxXcptInterceptSet(PCCPUMCTX pCtx, uint8_t uVector, uint32_t uErrCode) +{ + Assert(uVector <= X86_XCPT_LAST); + + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + + /* NMIs have a dedicated VM-execution control for causing VM-exits. */ + if (uVector == X86_XCPT_NMI) + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32PinCtls & VMX_PIN_CTLS_NMI_EXIT); + + /* Page-faults are subject to masking using its error code. */ + uint32_t fXcptBitmap = pCtx->hwvirt.vmx.Vmcs.u32XcptBitmap; + if (uVector == X86_XCPT_PF) + { + uint32_t const fXcptPFMask = pCtx->hwvirt.vmx.Vmcs.u32XcptPFMask; + uint32_t const fXcptPFMatch = pCtx->hwvirt.vmx.Vmcs.u32XcptPFMatch; + if ((uErrCode & fXcptPFMask) != fXcptPFMatch) + fXcptBitmap ^= RT_BIT(X86_XCPT_PF); + } + + /* Consult the exception bitmap for all other exceptions. */ + if (fXcptBitmap & RT_BIT(uVector)) + return true; + return false; +} + + +/** + * Checks whether the guest is in VMX non-root mode and using EPT paging. + * + * @returns @c true if in VMX non-root operation with EPT, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxEptPagingEnabledEx(PCCPUMCTX pCtx) +{ + return CPUMIsGuestInVmxNonRootMode(pCtx) + && CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_EPT); +} + + +/** + * Implements VMSucceed for VMX instruction success. + * + * @param pCtx Current CPU context. + */ +DECLINLINE(void) CPUMSetGuestVmxVmSucceed(PCPUMCTX pCtx) +{ + pCtx->eflags.uBoth &= ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF); +} + +/** + * Implements VMFailInvalid for VMX instruction failure. + * + * @param pCtx Current CPU context. + */ +DECLINLINE(void) CPUMSetGuestVmxVmFailInvalid(PCPUMCTX pCtx) +{ + pCtx->eflags.uBoth &= ~(X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF); + pCtx->eflags.uBoth |= X86_EFL_CF; +} + +/** + * Implements VMFailValid for VMX instruction failure. + * + * @param pCtx Current CPU context. + * @param enmInsErr The VM instruction error. + */ +DECLINLINE(void) CPUMSetGuestVmxVmFailValid(PCPUMCTX pCtx, VMXINSTRERR enmInsErr) +{ + pCtx->eflags.uBoth &= ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF); + pCtx->eflags.uBoth |= X86_EFL_ZF; + pCtx->hwvirt.vmx.Vmcs.u32RoVmInstrError = enmInsErr; +} + +/** + * Implements VMFail for VMX instruction failure. + * + * @param pCtx Current CPU context. + * @param enmInsErr The VM instruction error. + */ +DECLINLINE(void) CPUMSetGuestVmxVmFail(PCPUMCTX pCtx, VMXINSTRERR enmInsErr) +{ + if (pCtx->hwvirt.vmx.GCPhysVmcs != NIL_RTGCPHYS) + CPUMSetGuestVmxVmFailValid(pCtx, enmInsErr); + else + CPUMSetGuestVmxVmFailInvalid(pCtx); +} + +/** + * Returns the guest-physical address of the APIC-access page when executing a + * nested-guest. + * + * @returns The APIC-access page guest-physical address. + * @param pCtx Current CPU context. + */ +DECLINLINE(uint64_t) CPUMGetGuestVmxApicAccessPageAddrEx(PCCPUMCTX pCtx) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return pCtx->hwvirt.vmx.Vmcs.u64AddrApicAccess.u; +} + +/** + * Gets the nested-guest CR0 subject to the guest/host mask and the read-shadow. + * + * @returns The nested-guest CR0. + * @param pCtx Current CPU context. + * @param fGstHostMask The CR0 guest/host mask to use. + */ +DECLINLINE(uint64_t) CPUMGetGuestVmxMaskedCr0(PCCPUMCTX pCtx, uint64_t fGstHostMask) +{ + /* + * For each CR0 bit owned by the host, the corresponding bit from the + * CR0 read shadow is loaded. For each CR0 bit that is not owned by the host, + * the corresponding bit from the guest CR0 is loaded. + * + * See Intel Spec. 25.3 "Changes To Instruction Behavior In VMX Non-root Operation". + */ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + uint64_t const uGstCr0 = pCtx->cr0; + uint64_t const fReadShadow = pCtx->hwvirt.vmx.Vmcs.u64Cr0ReadShadow.u; + return (fReadShadow & fGstHostMask) | (uGstCr0 & ~fGstHostMask); +} + +/** + * Gets the nested-guest CR4 subject to the guest/host mask and the read-shadow. + * + * @returns The nested-guest CR4. + * @param pCtx Current CPU context. + * @param fGstHostMask The CR4 guest/host mask to use. + */ +DECLINLINE(uint64_t) CPUMGetGuestVmxMaskedCr4(PCCPUMCTX pCtx, uint64_t fGstHostMask) +{ + /* + * For each CR4 bit owned by the host, the corresponding bit from the + * CR4 read shadow is loaded. For each CR4 bit that is not owned by the host, + * the corresponding bit from the guest CR4 is loaded. + * + * See Intel Spec. 25.3 "Changes To Instruction Behavior In VMX Non-root Operation". + */ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + uint64_t const uGstCr4 = pCtx->cr4; + uint64_t const fReadShadow = pCtx->hwvirt.vmx.Vmcs.u64Cr4ReadShadow.u; + return (fReadShadow & fGstHostMask) | (uGstCr4 & ~fGstHostMask); +} + +/** + * Checks whether the LMSW access causes a VM-exit or not. + * + * @returns @c true if the LMSW access causes a VM-exit, @c false otherwise. + * @param pCtx Current CPU context. + * @param uNewMsw The LMSW source operand (the Machine Status Word). + */ +DECLINLINE(bool) CPUMIsGuestVmxLmswInterceptSet(PCCPUMCTX pCtx, uint16_t uNewMsw) +{ + /* + * LMSW VM-exits are subject to the CR0 guest/host mask and the CR0 read shadow. + * + * See Intel spec. 24.6.6 "Guest/Host Masks and Read Shadows for CR0 and CR4". + * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally". + */ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + + uint32_t const fGstHostMask = (uint32_t)pCtx->hwvirt.vmx.Vmcs.u64Cr0Mask.u; + uint32_t const fReadShadow = (uint32_t)pCtx->hwvirt.vmx.Vmcs.u64Cr0ReadShadow.u; + + /* + * LMSW can never clear CR0.PE but it may set it. Hence, we handle the + * CR0.PE case first, before the rest of the bits in the MSW. + * + * If CR0.PE is owned by the host and CR0.PE differs between the + * MSW (source operand) and the read-shadow, we must cause a VM-exit. + */ + if ( (fGstHostMask & X86_CR0_PE) + && (uNewMsw & X86_CR0_PE) + && !(fReadShadow & X86_CR0_PE)) + return true; + + /* + * If CR0.MP, CR0.EM or CR0.TS is owned by the host, and the corresponding + * bits differ between the MSW (source operand) and the read-shadow, we must + * cause a VM-exit. + */ + uint32_t const fGstHostLmswMask = fGstHostMask & (X86_CR0_MP | X86_CR0_EM | X86_CR0_TS); + if ((fReadShadow & fGstHostLmswMask) != (uNewMsw & fGstHostLmswMask)) + return true; + + return false; +} + +/** + * Checks whether the Mov-to-CR0/CR4 access causes a VM-exit or not. + * + * @returns @c true if the Mov CRX access causes a VM-exit, @c false otherwise. + * @param pCtx Current CPU context. + * @param iCrReg The control register number (must be 0 or 4). + * @param uNewCrX The CR0/CR4 value being written. + */ +DECLINLINE(bool) CPUMIsGuestVmxMovToCr0Cr4InterceptSet(PCCPUMCTX pCtx, uint8_t iCrReg, uint64_t uNewCrX) +{ + /* + * For any CR0/CR4 bit owned by the host (in the CR0/CR4 guest/host mask), if the + * corresponding bits differ between the source operand and the read-shadow, + * we must cause a VM-exit. + * + * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally". + */ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + Assert(iCrReg == 0 || iCrReg == 4); + + uint64_t fGstHostMask; + uint64_t fReadShadow; + if (iCrReg == 0) + { + fGstHostMask = pCtx->hwvirt.vmx.Vmcs.u64Cr0Mask.u; + fReadShadow = pCtx->hwvirt.vmx.Vmcs.u64Cr0ReadShadow.u; + } + else + { + fGstHostMask = pCtx->hwvirt.vmx.Vmcs.u64Cr4Mask.u; + fReadShadow = pCtx->hwvirt.vmx.Vmcs.u64Cr4ReadShadow.u; + } + + if ((fReadShadow & fGstHostMask) != (uNewCrX & fGstHostMask)) + { + Assert(fGstHostMask != 0); + return true; + } + + return false; +} + +/** + * Returns whether the guest has an active, current VMCS. + * + * @returns @c true if the guest has an active, current VMCS, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxCurrentVmcsValid(PCCPUMCTX pCtx) +{ + return pCtx->hwvirt.vmx.GCPhysVmcs != NIL_RTGCPHYS; +} + +# endif /* !IN_RC */ + +/** + * Checks whether the VMX nested-guest is in a state to receive physical (APIC) + * interrupts. + * + * @returns @c true if it's ready, @c false otherwise. + * @param pCtx The guest-CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxPhysIntrEnabled(PCCPUMCTX pCtx) +{ +#ifdef IN_RC + AssertReleaseFailedReturn(false); +#else + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + if (CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT)) + return true; + return RT_BOOL(pCtx->eflags.u & X86_EFL_IF); +#endif +} + +/** + * Checks whether the VMX nested-guest is blocking virtual-NMIs. + * + * @returns @c true if it's blocked, @c false otherwise. + * @param pCtx The guest-CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxVirtNmiBlocking(PCCPUMCTX pCtx) +{ +#ifdef IN_RC + RT_NOREF(pCtx); + AssertReleaseFailedReturn(false); +#else + /* + * Return the state of virtual-NMI blocking, if we are executing a + * VMX nested-guest with virtual-NMIs enabled. + */ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + Assert(CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)); + return pCtx->hwvirt.vmx.fVirtNmiBlocking; +#endif +} + +/** + * Sets or clears VMX nested-guest virtual-NMI blocking. + * + * @param pCtx The guest-CPU context. + * @param fBlocking Whether virtual-NMI blocking is in effect or not. + */ +DECLINLINE(void) CPUMSetGuestVmxVirtNmiBlocking(PCPUMCTX pCtx, bool fBlocking) +{ +#ifdef IN_RC + RT_NOREF2(pCtx, fBlocking); + AssertReleaseFailedReturnVoid(); +#else + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + Assert(CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)); + pCtx->hwvirt.vmx.fVirtNmiBlocking = fBlocking; +#endif +} + +/** + * Checks whether the VMX nested-guest is in a state to receive virtual interrupts + * (those injected with the "virtual-interrupt delivery" feature). + * + * @returns @c true if it's ready, @c false otherwise. + * @param pCtx The guest-CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxVirtIntrEnabled(PCCPUMCTX pCtx) +{ +#ifdef IN_RC + RT_NOREF2(pCtx); + AssertReleaseFailedReturn(false); +#else + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->eflags.u & X86_EFL_IF); +#endif +} + +/** @} */ +#endif /* !IPRT_WITHOUT_NAMED_UNIONS_AND_STRUCTS || DOXYGEN_RUNNING */ + + + +/** @name Hypervisor Register Getters. + * @{ */ +VMMDECL(RTGCUINTREG) CPUMGetHyperDR0(PVMCPU pVCpu); +VMMDECL(RTGCUINTREG) CPUMGetHyperDR1(PVMCPU pVCpu); +VMMDECL(RTGCUINTREG) CPUMGetHyperDR2(PVMCPU pVCpu); +VMMDECL(RTGCUINTREG) CPUMGetHyperDR3(PVMCPU pVCpu); +VMMDECL(RTGCUINTREG) CPUMGetHyperDR6(PVMCPU pVCpu); +VMMDECL(RTGCUINTREG) CPUMGetHyperDR7(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetHyperCR3(PVMCPU pVCpu); +/** @} */ + +/** @name Hypervisor Register Setters. + * @{ */ +VMMDECL(void) CPUMSetHyperCR3(PVMCPU pVCpu, uint32_t cr3); +VMMDECL(void) CPUMSetHyperDR0(PVMCPU pVCpu, RTGCUINTREG uDr0); +VMMDECL(void) CPUMSetHyperDR1(PVMCPU pVCpu, RTGCUINTREG uDr1); +VMMDECL(void) CPUMSetHyperDR2(PVMCPU pVCpu, RTGCUINTREG uDr2); +VMMDECL(void) CPUMSetHyperDR3(PVMCPU pVCpu, RTGCUINTREG uDr3); +VMMDECL(void) CPUMSetHyperDR6(PVMCPU pVCpu, RTGCUINTREG uDr6); +VMMDECL(void) CPUMSetHyperDR7(PVMCPU pVCpu, RTGCUINTREG uDr7); +VMMDECL(int) CPUMRecalcHyperDRx(PVMCPUCC pVCpu, uint8_t iGstReg); +/** @} */ + +VMMDECL(PCPUMCTX) CPUMQueryGuestCtxPtr(PVMCPU pVCpu); +#ifdef VBOX_INCLUDED_vmm_cpumctx_h +VMM_INT_DECL(PCPUMCTXMSRS) CPUMQueryGuestCtxMsrsPtr(PVMCPU pVCpu); +#endif + +/** @name Changed flags. + * These flags are used to keep track of which important register that + * have been changed since last they were reset. The only one allowed + * to clear them is REM! + * + * @todo This is obsolete, but remains as it will be refactored for coordinating + * IEM and NEM/HM later. Probably. + * @{ + */ +#define CPUM_CHANGED_FPU_REM RT_BIT(0) +#define CPUM_CHANGED_CR0 RT_BIT(1) +#define CPUM_CHANGED_CR4 RT_BIT(2) +#define CPUM_CHANGED_GLOBAL_TLB_FLUSH RT_BIT(3) +#define CPUM_CHANGED_CR3 RT_BIT(4) +#define CPUM_CHANGED_GDTR RT_BIT(5) +#define CPUM_CHANGED_IDTR RT_BIT(6) +#define CPUM_CHANGED_LDTR RT_BIT(7) +#define CPUM_CHANGED_TR RT_BIT(8) /**@< Currently unused. */ +#define CPUM_CHANGED_SYSENTER_MSR RT_BIT(9) +#define CPUM_CHANGED_HIDDEN_SEL_REGS RT_BIT(10) /**@< Currently unused. */ +#define CPUM_CHANGED_CPUID RT_BIT(11) +#define CPUM_CHANGED_ALL ( CPUM_CHANGED_FPU_REM \ + | CPUM_CHANGED_CR0 \ + | CPUM_CHANGED_CR4 \ + | CPUM_CHANGED_GLOBAL_TLB_FLUSH \ + | CPUM_CHANGED_CR3 \ + | CPUM_CHANGED_GDTR \ + | CPUM_CHANGED_IDTR \ + | CPUM_CHANGED_LDTR \ + | CPUM_CHANGED_TR \ + | CPUM_CHANGED_SYSENTER_MSR \ + | CPUM_CHANGED_HIDDEN_SEL_REGS \ + | CPUM_CHANGED_CPUID ) +/** @} */ + +VMMDECL(void) CPUMSetChangedFlags(PVMCPU pVCpu, uint32_t fChangedAdd); +VMMDECL(bool) CPUMSupportsXSave(PVM pVM); +VMMDECL(bool) CPUMIsHostUsingSysEnter(PVM pVM); +VMMDECL(bool) CPUMIsHostUsingSysCall(PVM pVM); +VMMDECL(bool) CPUMIsGuestFPUStateActive(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestFPUStateLoaded(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsHostFPUStateSaved(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestDebugStateActive(PVMCPU pVCpu); +VMMDECL(void) CPUMDeactivateGuestDebugState(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsHyperDebugStateActive(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestCPL(PVMCPU pVCpu); +VMMDECL(CPUMMODE) CPUMGetGuestMode(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestCodeBits(PVMCPU pVCpu); +VMMDECL(DISCPUMODE) CPUMGetGuestDisMode(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestMxCsrMask(PVM pVM); +VMMDECL(uint64_t) CPUMGetGuestScalableBusFrequency(PVM pVM); +VMMDECL(uint64_t) CPUMGetGuestEferMsrValidMask(PVM pVM); +VMMDECL(int) CPUMIsGuestEferMsrWriteValid(PVM pVM, uint64_t uCr0, uint64_t uOldEfer, uint64_t uNewEfer, + uint64_t *puValidEfer); +VMMDECL(void) CPUMSetGuestEferMsrNoChecks(PVMCPUCC pVCpu, uint64_t uOldEfer, uint64_t uValidEfer); +VMMDECL(bool) CPUMIsPatMsrValid(uint64_t uValue); + + +/** Guest CPU interruptibility level, see CPUMGetGuestInterruptibility(). */ +typedef enum CPUMINTERRUPTIBILITY +{ + CPUMINTERRUPTIBILITY_INVALID = 0, + CPUMINTERRUPTIBILITY_UNRESTRAINED, + CPUMINTERRUPTIBILITY_VIRT_INT_DISABLED, + CPUMINTERRUPTIBILITY_INT_DISABLED, + CPUMINTERRUPTIBILITY_INT_INHIBITED, /**< @todo rename as it inhibits NMIs too. */ + CPUMINTERRUPTIBILITY_NMI_INHIBIT, + CPUMINTERRUPTIBILITY_GLOBAL_INHIBIT, + CPUMINTERRUPTIBILITY_END, + CPUMINTERRUPTIBILITY_32BIT_HACK = 0x7fffffff +} CPUMINTERRUPTIBILITY; + +VMM_INT_DECL(CPUMINTERRUPTIBILITY) CPUMGetGuestInterruptibility(PVMCPU pVCpu); + +/** @name Typical scalable bus frequency values. + * @{ */ +/** Special internal value indicating that we don't know the frequency. + * @internal */ +#define CPUM_SBUSFREQ_UNKNOWN UINT64_C(1) +#define CPUM_SBUSFREQ_100MHZ UINT64_C(100000000) +#define CPUM_SBUSFREQ_133MHZ UINT64_C(133333333) +#define CPUM_SBUSFREQ_167MHZ UINT64_C(166666666) +#define CPUM_SBUSFREQ_200MHZ UINT64_C(200000000) +#define CPUM_SBUSFREQ_267MHZ UINT64_C(266666666) +#define CPUM_SBUSFREQ_333MHZ UINT64_C(333333333) +#define CPUM_SBUSFREQ_400MHZ UINT64_C(400000000) +/** @} */ + + +#ifdef IN_RING3 +/** @defgroup grp_cpum_r3 The CPUM ring-3 API + * @{ + */ + +VMMR3DECL(int) CPUMR3Init(PVM pVM); +VMMR3DECL(int) CPUMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3DECL(void) CPUMR3LogCpuIdAndMsrFeatures(PVM pVM); +VMMR3DECL(void) CPUMR3Relocate(PVM pVM); +VMMR3DECL(int) CPUMR3Term(PVM pVM); +VMMR3DECL(void) CPUMR3Reset(PVM pVM); +VMMR3DECL(void) CPUMR3ResetCpu(PVM pVM, PVMCPU pVCpu); +VMMDECL(bool) CPUMR3IsStateRestorePending(PVM pVM); +VMMR3DECL(int) CPUMR3SetCR4Feature(PVM pVM, RTHCUINTREG fOr, RTHCUINTREG fAnd); + +VMMR3DECL(int) CPUMR3CpuIdInsert(PVM pVM, PCPUMCPUIDLEAF pNewLeaf); +VMMR3DECL(int) CPUMR3CpuIdGetLeaf(PVM pVM, PCPUMCPUIDLEAF pLeaf, uint32_t uLeaf, uint32_t uSubLeaf); +VMMR3_INT_DECL(PCCPUMCPUIDLEAF) CPUMR3CpuIdGetPtr(PVM pVM, uint32_t *pcLeaves); +VMMDECL(CPUMMICROARCH) CPUMCpuIdDetermineX86MicroarchEx(CPUMCPUVENDOR enmVendor, uint8_t bFamily, + uint8_t bModel, uint8_t bStepping); +VMMDECL(const char *) CPUMMicroarchName(CPUMMICROARCH enmMicroarch); +VMMR3DECL(int) CPUMR3CpuIdDetectUnknownLeafMethod(PCPUMUNKNOWNCPUID penmUnknownMethod, PCPUMCPUID pDefUnknown); +VMMR3DECL(const char *) CPUMR3CpuIdUnknownLeafMethodName(CPUMUNKNOWNCPUID enmUnknownMethod); +VMMR3DECL(const char *) CPUMCpuVendorName(CPUMCPUVENDOR enmVendor); +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) +VMMR3DECL(uint32_t) CPUMR3DeterminHostMxCsrMask(void); +#endif + +VMMR3DECL(int) CPUMR3MsrRangesInsert(PVM pVM, PCCPUMMSRRANGE pNewRange); + +VMMR3DECL(uint32_t) CPUMR3DbGetEntries(void); +/** Pointer to CPUMR3DbGetEntries. */ +typedef DECLCALLBACKPTR(uint32_t, PFNCPUMDBGETENTRIES, (void)); +VMMR3DECL(PCCPUMDBENTRY) CPUMR3DbGetEntryByIndex(uint32_t idxCpuDb); +/** Pointer to CPUMR3DbGetEntryByIndex. */ +typedef DECLCALLBACKPTR(PCCPUMDBENTRY, PFNCPUMDBGETENTRYBYINDEX, (uint32_t idxCpuDb)); +VMMR3DECL(PCCPUMDBENTRY) CPUMR3DbGetEntryByName(const char *pszName); +/** Pointer to CPUMR3DbGetEntryByName. */ +typedef DECLCALLBACKPTR(PCCPUMDBENTRY, PFNCPUMDBGETENTRYBYNAME, (const char *pszName)); + +VMMR3_INT_DECL(void) CPUMR3NemActivateGuestDebugState(PVMCPUCC pVCpu); +VMMR3_INT_DECL(void) CPUMR3NemActivateHyperDebugState(PVMCPUCC pVCpu); +/** @} */ +#endif /* IN_RING3 */ + +#ifdef IN_RING0 +/** @defgroup grp_cpum_r0 The CPUM ring-0 API + * @{ + */ +VMMR0_INT_DECL(int) CPUMR0ModuleInit(void); +VMMR0_INT_DECL(int) CPUMR0ModuleTerm(void); +VMMR0_INT_DECL(void) CPUMR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(int) CPUMR0InitVM(PVMCC pVM); +DECLASM(void) CPUMR0RegisterVCpuThread(PVMCPUCC pVCpu); +DECLASM(void) CPUMR0TouchHostFpu(void); +VMMR0_INT_DECL(int) CPUMR0Trap07Handler(PVMCC pVM, PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) CPUMR0LoadGuestFPU(PVMCC pVM, PVMCPUCC pVCpu); +VMMR0_INT_DECL(bool) CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) CPUMR0SaveHostDebugState(PVMCC pVM, PVMCPUCC pVCpu); +VMMR0_INT_DECL(bool) CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(PVMCPUCC pVCpu, bool fDr6); +VMMR0_INT_DECL(bool) CPUMR0DebugStateMaybeSaveGuest(PVMCPUCC pVCpu, bool fDr6); + +VMMR0_INT_DECL(void) CPUMR0LoadGuestDebugState(PVMCPUCC pVCpu, bool fDr6); +VMMR0_INT_DECL(void) CPUMR0LoadHyperDebugState(PVMCPUCC pVCpu, bool fDr6); +/** @} */ +#endif /* IN_RING0 */ + +/** @defgroup grp_cpum_rz The CPUM raw-mode and ring-0 context API + * @{ + */ +VMMRZ_INT_DECL(void) CPUMRZFpuStatePrepareHostCpuForUse(PVMCPUCC pVCpu); +VMMRZ_INT_DECL(void) CPUMRZFpuStateActualizeForRead(PVMCPUCC pVCpu); +VMMRZ_INT_DECL(void) CPUMRZFpuStateActualizeForChange(PVMCPUCC pVCpu); +VMMRZ_INT_DECL(void) CPUMRZFpuStateActualizeSseForRead(PVMCPUCC pVCpu); +VMMRZ_INT_DECL(void) CPUMRZFpuStateActualizeAvxForRead(PVMCPUCC pVCpu); +/** @} */ + + +#endif /* !VBOX_FOR_DTRACE_LIB */ +/** @} */ +RT_C_DECLS_END + + +#endif /* !VBOX_INCLUDED_vmm_cpum_h */ + diff --git a/include/VBox/vmm/cpum.mac b/include/VBox/vmm/cpum.mac new file mode 100644 index 00000000..dac92f61 --- /dev/null +++ b/include/VBox/vmm/cpum.mac @@ -0,0 +1,275 @@ +;; @file +; CPUM - CPU Monitor, Assembly header file. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_vmm_cpum_mac__ +%define ___VBox_vmm_cpum_mac__ + +%include "iprt/asmdefs.mac" + + +;; +; The volatile XSAVE components when VBOX_WITH_KERNEL_USING_XMM is active. +; @note ASSUMED to be at the most 32-bit in width at the moment. +%ifdef VBOX_WITH_KERNEL_USING_XMM + %define CPUM_VOLATILE_XSAVE_GUEST_COMPONENTS (XSAVE_C_SSE | XSAVE_C_YMM | XSAVE_C_ZMM_HI256 | XSAVE_C_ZMM_16HI) +%endif + +;; +; CPUID leaf. +; @remarks This structure is used by the patch manager and can only be extended +; by adding to the end of it. +struc CPUMCPUIDLEAF + .uLeaf resd 1 + .uSubLeaf resd 1 + .fSubLeafMask resd 1 + .uEax resd 1 + .uEbx resd 1 + .uEcx resd 1 + .uEdx resd 1 + .fFlags resd 1 +endstruc +%define CPUMCPUIDLEAF_F_INTEL_TOPOLOGY_SUBLEAVES RT_BIT_32(0) +%define CPUMCPUIDLEAF_F_CONTAINS_APIC_ID RT_BIT_32(1) +%define CPUMCPUIDLEAF_F_CONTAINS_OSXSAVE RT_BIT_32(2) +%define CPUMCPUIDLEAF_F_CONTAINS_APIC RT_BIT_32(3) + + +;; +; For the default CPUID leaf value. +; @remarks This is used by the patch manager and cannot be modified in any way. +struc CPUMCPUID + .uEax resd 1 + .uEbx resd 1 + .uEcx resd 1 + .uEdx resd 1 +endstruc + + +;; @name Method used to deal with unknown CPUID leaves. +;; @{ +%define CPUMUNKNOWNCPUID_DEFAULTS 1 +%define CPUMUNKNOWNCPUID_LAST_STD_LEAF 2 +%define CPUMUNKNOWNCPUID_LAST_STD_LEAF_WITH_ECX 3 +%define CPUMUNKNOWNCPUID_PASSTHRU 4 +;; @} + + +%define XSTATE_SIZE 8192 + +;; Note! Updates here must be reflected in CPUMInternal.mac too! +struc CPUMCTX + .eax resq 1 + .ecx resq 1 + .edx resq 1 + .ebx resq 1 + .esp resq 1 + .ebp resq 1 + .esi resq 1 + .edi resq 1 + .r8 resq 1 + .r9 resq 1 + .r10 resq 1 + .r11 resq 1 + .r12 resq 1 + .r13 resq 1 + .r14 resq 1 + .r15 resq 1 + .es.Sel resw 1 + .es.PaddingSel resw 1 + .es.ValidSel resw 1 + .es.fFlags resw 1 + .es.u64Base resq 1 + .es.u32Limit resd 1 + .es.Attr resd 1 + .cs.Sel resw 1 + .cs.PaddingSel resw 1 + .cs.ValidSel resw 1 + .cs.fFlags resw 1 + .cs.u64Base resq 1 + .cs.u32Limit resd 1 + .cs.Attr resd 1 + .ss.Sel resw 1 + .ss.PaddingSel resw 1 + .ss.ValidSel resw 1 + .ss.fFlags resw 1 + .ss.u64Base resq 1 + .ss.u32Limit resd 1 + .ss.Attr resd 1 + .ds.Sel resw 1 + .ds.PaddingSel resw 1 + .ds.ValidSel resw 1 + .ds.fFlags resw 1 + .ds.u64Base resq 1 + .ds.u32Limit resd 1 + .ds.Attr resd 1 + .fs.Sel resw 1 + .fs.PaddingSel resw 1 + .fs.ValidSel resw 1 + .fs.fFlags resw 1 + .fs.u64Base resq 1 + .fs.u32Limit resd 1 + .fs.Attr resd 1 + .gs.Sel resw 1 + .gs.PaddingSel resw 1 + .gs.ValidSel resw 1 + .gs.fFlags resw 1 + .gs.u64Base resq 1 + .gs.u32Limit resd 1 + .gs.Attr resd 1 + .ldtr.Sel resw 1 + .ldtr.PaddingSel resw 1 + .ldtr.ValidSel resw 1 + .ldtr.fFlags resw 1 + .ldtr.u64Base resq 1 + .ldtr.u32Limit resd 1 + .ldtr.Attr resd 1 + .tr.Sel resw 1 + .tr.PaddingSel resw 1 + .tr.ValidSel resw 1 + .tr.fFlags resw 1 + .tr.u64Base resq 1 + .tr.u32Limit resd 1 + .tr.Attr resd 1 + alignb 8 + .eip resq 1 + .eflags resq 1 + .fExtrn resq 1 + .uRipInhibitInt resq 1 + .cr0 resq 1 + .cr2 resq 1 + .cr3 resq 1 + .cr4 resq 1 + .dr resq 8 + .gdtrPadding resw 3 + .gdtr resw 0 + .gdtr.cbGdt resw 1 + .gdtr.pGdt resq 1 + .idtrPadding resw 3 + .idtr resw 0 + .idtr.cbIdt resw 1 + .idtr.pIdt resq 1 + .SysEnter.cs resb 8 + .SysEnter.eip resb 8 + .SysEnter.esp resb 8 + .msrEFER resb 8 + .msrSTAR resb 8 + .msrPAT resb 8 + .msrLSTAR resb 8 + .msrCSTAR resb 8 + .msrSFMASK resb 8 + .msrKERNELGSBASE resb 8 + + alignb 32 + .aPaePdpes resq 4 + + alignb 8 + .aXcr resq 2 + .fXStateMask resq 1 + .fUsedFpuGuest resb 1 + alignb 8 + .aoffXState resw 64 + alignb 256 + .abXState resb 0x4000-0x300 + .XState EQU .abXState + + alignb 4096 + .hwvirt resb 0 + .hwvirt.svm resb 0 + .hwvirt.vmx resb 0 + + .hwvirt.svm.Vmcb EQU .hwvirt.svm + .hwvirt.svm.abMsrBitmap EQU (.hwvirt.svm.Vmcb + 0x1000) + .hwvirt.svm.abIoBitmap EQU (.hwvirt.svm.abMsrBitmap + 0x2000) + .hwvirt.svm.uMsrHSavePa EQU (.hwvirt.svm.abIoBitmap + 0x3000) ; resq 1 + .hwvirt.svm.GCPhysVmcb EQU (.hwvirt.svm.uMsrHSavePa + 8) ; resq 1 + alignb 8 + .hwvirt.svm.HostState EQU (.hwvirt.svm.GCPhysVmcb + 8) ; resb 184 + .hwvirt.svm.uPrevPauseTick EQU (.hwvirt.svm.HostState + 184) ; resq 1 + .hwvirt.svm.cPauseFilter EQU (.hwvirt.svm.uPrevPauseTick + 8) ; resw 1 + .hwvirt.svm.cPauseFilterThreshold EQU (.hwvirt.svm.cPauseFilter + 2) ; resw 1 + .hwvirt.svm.fInterceptEvents EQU (.hwvirt.svm.cPauseFilterThreshold + 2) ; resb 1 + + .hwvirt.vmx.Vmcs resb 0x1000 + .hwvirt.vmx.ShadowVmcs resb 0x1000 + .hwvirt.vmx.abVmreadBitmap resb 0x1000 + .hwvirt.vmx.abVmwriteBitmap resb 0x1000 + .hwvirt.vmx.aEntryMsrLoadArea resb 0x2000 + .hwvirt.vmx.aExitMsrStoreArea resb 0x2000 + .hwvirt.vmx.aExitMsrLoadArea resb 0x2000 + .hwvirt.vmx.abMsrBitmap resb 0x1000 + .hwvirt.vmx.abIoBitmap resb 0x1000+0x1000 + alignb 8 + .hwvirt.vmx.GCPhysVmxon resq 1 + .hwvirt.vmx.GCPhysVmcs resq 1 + .hwvirt.vmx.GCPhysShadowVmcs resq 1 + .hwvirt.vmx.enmDiag resd 1 + .hwvirt.vmx.enmAbort resd 1 + .hwvirt.vmx.uDiagAux resq 1 + .hwvirt.vmx.uAbortAux resd 1 + .hwvirt.vmx.fInVmxRootMode resb 1 + .hwvirt.vmx.fInVmxNonRootMode resb 1 + .hwvirt.vmx.fInterceptEvents resb 1 + .hwvirt.vmx.fNmiUnblockingIret resb 1 + .hwvirt.vmx.uFirstPauseLoopTick resq 1 + .hwvirt.vmx.uPrevPauseTick resq 1 + .hwvirt.vmx.uEntryTick resq 1 + .hwvirt.vmx.offVirtApicWrite resw 1 + .hwvirt.vmx.fVirtNmiBlocking resb 1 + alignb 8 + .hwvirt.vmx.Msrs resb 224 + + alignb 8 + .hwvirt.enmHwvirt resd 1 + .hwvirt.fGif resb 1 + alignb 4 + .hwvirt.fSavedInhibit resd 1 + alignb 64 +endstruc + + +%define CPUMSELREG_FLAGS_VALID 0x0001 +%define CPUMSELREG_FLAGS_STALE 0x0002 +%define CPUMSELREG_FLAGS_VALID_MASK 0x0003 + + +;; +; Guest MSR state. +struc CPUMCTXMSRS + .au64 resq 64 +endstruc + + +%endif + diff --git a/include/VBox/vmm/cpumctx-v1_6.h b/include/VBox/vmm/cpumctx-v1_6.h new file mode 100644 index 00000000..fe6d30db --- /dev/null +++ b/include/VBox/vmm/cpumctx-v1_6.h @@ -0,0 +1,263 @@ +/** @file + * CPUM - CPU Monitor(/ Manager), Context Structures from v1.6 (saved state). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cpumctx_v1_6_h +#define VBOX_INCLUDED_vmm_cpumctx_v1_6_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/x86.h> +#include <VBox/vmm/cpumctx.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_cpum_ctx_v1_6 The CPUM Context Structures from v1.6 + * @ingroup grp_cpum + * @{ + */ + +#pragma pack(1) +/** IDTR from version 1.6 */ +typedef struct VBOXIDTR_VER1_6 +{ + /** Size of the IDT. */ + uint16_t cbIdt; + /** Address of the IDT. */ + uint32_t pIdt; +} VBOXIDTR_VER1_6; +#pragma pack() + +#pragma pack(1) +/** GDTR from version 1.6 */ +typedef struct VBOXGDTR_VER1_6 +{ + /** Size of the GDT. */ + uint16_t cbGdt; + /** Address of the GDT. */ + uint32_t pGdt; +} VBOXGDTR_VER1_6; +#pragma pack() + + +/** + * Selector hidden registers, for version 1.6 saved state. + */ +typedef struct CPUMSELREGHID_VER1_6 +{ + /** Base register. */ + uint32_t u32Base; + /** Limit (expanded). */ + uint32_t u32Limit; + /** Flags. + * This is the high 32-bit word of the descriptor entry. + * Only the flags, dpl and type are used. */ + X86DESCATTR Attr; +} CPUMSELREGHID_VER1_6; + +/** + * CPU context, for version 1.6 saved state. + * @remarks PATM uses this, which is why it has to be here. + */ +# pragma pack(1) +typedef struct CPUMCTX_VER1_6 +{ + /** FPU state. (16-byte alignment) + * @todo This doesn't have to be in X86FXSTATE on CPUs without fxsr - we need a type for the + * actual format or convert it (waste of time). */ + X86FXSTATE fpu; + + /** CPUMCTXCORE Part. + * @{ */ + union + { + uint32_t edi; + uint64_t rdi; + } CPUM_UNION_NM(rdi); + union + { + uint32_t esi; + uint64_t rsi; + } CPUM_UNION_NM(rsi); + union + { + uint32_t ebp; + uint64_t rbp; + } CPUM_UNION_NM(rbp); + union + { + uint32_t eax; + uint64_t rax; + } CPUM_UNION_NM(rax); + union + { + uint32_t ebx; + uint64_t rbx; + } CPUM_UNION_NM(rbx); + union + { + uint32_t edx; + uint64_t rdx; + } CPUM_UNION_NM(rdx); + union + { + uint32_t ecx; + uint64_t rcx; + } CPUM_UNION_NM(rcx); + /** @note We rely on the exact layout, because we use lss esp, [] in the + * switcher. */ + uint32_t esp; + RTSEL ss; + RTSEL ssPadding; + /* Note: no overlap with esp here. */ + uint64_t rsp_notused; + + RTSEL gs; + RTSEL gsPadding; + RTSEL fs; + RTSEL fsPadding; + RTSEL es; + RTSEL esPadding; + RTSEL ds; + RTSEL dsPadding; + RTSEL cs; + RTSEL csPadding[3]; /**< 3 words to force 8 byte alignment for the remainder. */ + + union + { + X86EFLAGS eflags; + X86RFLAGS rflags; + } CPUM_UNION_NM(rflags); + union + { + uint32_t eip; + uint64_t rip; + } CPUM_UNION_NM(rip); + + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + + /** Hidden selector registers. + * @{ */ + CPUMSELREGHID_VER1_6 esHid; + CPUMSELREGHID_VER1_6 csHid; + CPUMSELREGHID_VER1_6 ssHid; + CPUMSELREGHID_VER1_6 dsHid; + CPUMSELREGHID_VER1_6 fsHid; + CPUMSELREGHID_VER1_6 gsHid; + /** @} */ + + /** @} */ + + /** Control registers. + * @{ */ + uint64_t cr0; + uint64_t cr2; + uint64_t cr3; + uint64_t cr4; + uint64_t cr8; + /** @} */ + + /** Debug registers. + * @{ */ + uint64_t dr0; + uint64_t dr1; + uint64_t dr2; + uint64_t dr3; + uint64_t dr4; /**< @todo remove dr4 and dr5. */ + uint64_t dr5; + uint64_t dr6; + uint64_t dr7; + /* DR8-15 are currently not supported */ + /** @} */ + + /** Global Descriptor Table register. */ + VBOXGDTR_VER1_6 gdtr; + uint16_t gdtrPadding; + uint32_t gdtrPadding64;/** @todo fix this hack */ + /** Interrupt Descriptor Table register. */ + VBOXIDTR_VER1_6 idtr; + uint16_t idtrPadding; + uint32_t idtrPadding64;/** @todo fix this hack */ + /** The task register. + * Only the guest context uses all the members. */ + RTSEL ldtr; + RTSEL ldtrPadding; + /** The task register. + * Only the guest context uses all the members. */ + RTSEL tr; + RTSEL trPadding; + + /** The sysenter msr registers. + * This member is not used by the hypervisor context. */ + CPUMSYSENTER SysEnter; + + /** System MSRs. + * @{ */ + uint64_t msrEFER; + uint64_t msrSTAR; + uint64_t msrPAT; + uint64_t msrLSTAR; + uint64_t msrCSTAR; + uint64_t msrSFMASK; + uint64_t msrFSBASE; + uint64_t msrGSBASE; + uint64_t msrKERNELGSBASE; + /** @} */ + + /** Hidden selector registers. + * @{ */ + CPUMSELREGHID_VER1_6 ldtrHid; + CPUMSELREGHID_VER1_6 trHid; + /** @} */ + + /** padding to get 32byte aligned size. */ + uint32_t padding[2]; +} CPUMCTX_VER1_6; +# pragma pack() + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_cpumctx_v1_6_h */ + diff --git a/include/VBox/vmm/cpumctx.h b/include/VBox/vmm/cpumctx.h new file mode 100644 index 00000000..fd8a4fec --- /dev/null +++ b/include/VBox/vmm/cpumctx.h @@ -0,0 +1,1116 @@ +/** @file + * CPUM - CPU Monitor(/ Manager), Context Structures. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cpumctx_h +#define VBOX_INCLUDED_vmm_cpumctx_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef VBOX_FOR_DTRACE_LIB +# include <iprt/x86.h> +# include <VBox/types.h> +# include <VBox/vmm/hm_svm.h> +# include <VBox/vmm/hm_vmx.h> +#else +# pragma D depends_on library x86.d +#endif + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_cpum_ctx The CPUM Context Structures + * @ingroup grp_cpum + * @{ + */ + +/** + * Selector hidden registers. + */ +typedef struct CPUMSELREG +{ + /** The selector register. */ + RTSEL Sel; + /** Padding, don't use. */ + RTSEL PaddingSel; + /** The selector which info resides in u64Base, u32Limit and Attr, provided + * that CPUMSELREG_FLAGS_VALID is set. */ + RTSEL ValidSel; + /** Flags, see CPUMSELREG_FLAGS_XXX. */ + uint16_t fFlags; + + /** Base register. + * + * Long mode remarks: + * - Unused in long mode for CS, DS, ES, SS + * - 32 bits for FS & GS; FS(GS)_BASE msr used for the base address + * - 64 bits for TR & LDTR + */ + uint64_t u64Base; + /** Limit (expanded). */ + uint32_t u32Limit; + /** Flags. + * This is the high 32-bit word of the descriptor entry. + * Only the flags, dpl and type are used. */ + X86DESCATTR Attr; +} CPUMSELREG; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMSELREG, 24); +#endif + +/** @name CPUMSELREG_FLAGS_XXX - CPUMSELREG::fFlags values. + * @{ */ +#define CPUMSELREG_FLAGS_VALID UINT16_C(0x0001) +#define CPUMSELREG_FLAGS_STALE UINT16_C(0x0002) +#define CPUMSELREG_FLAGS_VALID_MASK UINT16_C(0x0003) +/** @} */ + +/** Checks if the hidden parts of the selector register are valid. */ +#define CPUMSELREG_ARE_HIDDEN_PARTS_VALID(a_pVCpu, a_pSelReg) \ + ( ((a_pSelReg)->fFlags & CPUMSELREG_FLAGS_VALID) \ + && (a_pSelReg)->ValidSel == (a_pSelReg)->Sel ) + +/** Old type used for the hidden register part. + * @deprecated */ +typedef CPUMSELREG CPUMSELREGHID; + +/** + * The sysenter register set. + */ +typedef struct CPUMSYSENTER +{ + /** Ring 0 cs. + * This value + 8 is the Ring 0 ss. + * This value + 16 is the Ring 3 cs. + * This value + 24 is the Ring 3 ss. + */ + uint64_t cs; + /** Ring 0 eip. */ + uint64_t eip; + /** Ring 0 esp. */ + uint64_t esp; +} CPUMSYSENTER; + +/** @def CPUM_UNION_NM + * For compilers (like DTrace) that does not grok nameless unions, we have a + * little hack to make them palatable. + */ +/** @def CPUM_STRUCT_NM + * For compilers (like DTrace) that does not grok nameless structs (it is + * non-standard C++), we have a little hack to make them palatable. + */ +#ifdef VBOX_FOR_DTRACE_LIB +# define CPUM_UNION_NM(a_Nm) a_Nm +# define CPUM_STRUCT_NM(a_Nm) a_Nm +#elif defined(IPRT_WITHOUT_NAMED_UNIONS_AND_STRUCTS) +# define CPUM_UNION_NM(a_Nm) a_Nm +# define CPUM_STRUCT_NM(a_Nm) a_Nm +#else +# define CPUM_UNION_NM(a_Nm) +# define CPUM_STRUCT_NM(a_Nm) +#endif +/** @def CPUM_UNION_STRUCT_NM + * Combines CPUM_UNION_NM and CPUM_STRUCT_NM to avoid hitting the right side of + * the screen in the compile time assertions. + */ +#define CPUM_UNION_STRUCT_NM(a_UnionNm, a_StructNm) CPUM_UNION_NM(a_UnionNm .) CPUM_STRUCT_NM(a_StructNm) + +/** A general register (union). */ +typedef union CPUMCTXGREG +{ + /** Natural unsigned integer view. */ + uint64_t u; + /** 64-bit view. */ + uint64_t u64; + /** 32-bit view. */ + uint32_t u32; + /** 16-bit view. */ + uint16_t u16; + /** 8-bit view. */ + uint8_t u8; + /** 8-bit low/high view. */ + RT_GCC_EXTENSION struct + { + /** Low byte (al, cl, dl, bl, ++). */ + uint8_t bLo; + /** High byte in the first word - ah, ch, dh, bh. */ + uint8_t bHi; + } CPUM_STRUCT_NM(s); +} CPUMCTXGREG; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMCTXGREG, 8); +AssertCompileMemberOffset(CPUMCTXGREG, CPUM_STRUCT_NM(s.) bLo, 0); +AssertCompileMemberOffset(CPUMCTXGREG, CPUM_STRUCT_NM(s.) bHi, 1); +#endif + + + +/** + * SVM Host-state area (Nested Hw.virt - VirtualBox's layout). + * + * @warning Exercise caution while modifying the layout of this struct. It's + * part of VM saved states. + */ +#pragma pack(1) +typedef struct SVMHOSTSTATE +{ + uint64_t uEferMsr; + uint64_t uCr0; + uint64_t uCr4; + uint64_t uCr3; + uint64_t uRip; + uint64_t uRsp; + uint64_t uRax; + X86RFLAGS rflags; + CPUMSELREG es; + CPUMSELREG cs; + CPUMSELREG ss; + CPUMSELREG ds; + VBOXGDTR gdtr; + VBOXIDTR idtr; + uint8_t abPadding[4]; +} SVMHOSTSTATE; +#pragma pack() +/** Pointer to the SVMHOSTSTATE structure. */ +typedef SVMHOSTSTATE *PSVMHOSTSTATE; +/** Pointer to a const SVMHOSTSTATE structure. */ +typedef const SVMHOSTSTATE *PCSVMHOSTSTATE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSizeAlignment(SVMHOSTSTATE, 8); +AssertCompileSize(SVMHOSTSTATE, 184); +#endif + + +/** + * CPU hardware virtualization types. + */ +typedef enum +{ + CPUMHWVIRT_NONE = 0, + CPUMHWVIRT_VMX, + CPUMHWVIRT_SVM, + CPUMHWVIRT_32BIT_HACK = 0x7fffffff +} CPUMHWVIRT; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMHWVIRT, 4); +#endif + +/** Number of EFLAGS bits we put aside for the hardware EFLAGS, with the bits + * above this we use for storing internal state not visible to the guest. + * + * Using a value less than 32 here means some code bloat when loading and + * fetching the hardware EFLAGS value. Comparing VMMR0.r0 text size when + * compiling release build using gcc 11.3.1 on linux: + * - 32 bits: 2475709 bytes + * - 24 bits: 2482069 bytes; +6360 bytes. + * - 22 bits: 2482261 bytes; +6552 bytes. + * Same for windows (virtual size of .text): + * - 32 bits: 1498502 bytes + * - 24 bits: 1502278 bytes; +3776 bytes. + * - 22 bits: 1502198 bytes; +3696 bytes. + * + * In addition we pass pointer the 32-bit EFLAGS to a number of IEM assembly + * functions, so it would be safer to not store anything in the lower 32 bits. + * OTOH, we'd sooner discover buggy assembly code by doing so, as we've had one + * example of accidental EFLAGS trashing by these functions already. + * + * It would be more efficient for IEM to store the interrupt shadow bit (and + * anything else that needs to be cleared at the same time) in the 30:22 bit + * range, because that would allow using a simple AND imm32 instruction on x86 + * and a MOVN imm16,16 instruction to load the constant on ARM64 (assuming the + * other flag needing clearing is RF (bit 16)). Putting it in the 63:32 range + * means we that on x86 we'll either use a memory variant of AND or require a + * separate load instruction for the immediate, whereas on ARM we'll need more + * instructions to construct the immediate value. + * + * Comparing the instruction exit thruput via the bs2-test-1 testcase, there + * seems to be little difference between 32 and 24 here (best results out of 9 + * runs on Linux/VT-x). So, unless the results are really wrong and there is + * clear drop in thruput, it would on the whole make the most sense to use 24 + * here. + * + * Update: We need more than 8 bits because of DBGF, so using 22 now. + */ +#define CPUMX86EFLAGS_HW_BITS 22 +/** Mask for the hardware EFLAGS bits, 64-bit version. */ +#define CPUMX86EFLAGS_HW_MASK_64 (RT_BIT_64(CPUMX86EFLAGS_HW_BITS) - UINT64_C(1)) +/** Mask for the hardware EFLAGS bits, 32-bit version. */ +#if CPUMX86EFLAGS_HW_BITS == 32 +# define CPUMX86EFLAGS_HW_MASK_32 UINT32_MAX +#elif CPUMX86EFLAGS_HW_BITS < 32 && CPUMX86EFLAGS_HW_BITS >= 22 +# define CPUMX86EFLAGS_HW_MASK_32 (RT_BIT_32(CPUMX86EFLAGS_HW_BITS) - UINT32_C(1)) +#else +# error "Misconfigured CPUMX86EFLAGS_HW_BITS value!" +#endif + +/** Mask of internal flags kept with EFLAGS, 64-bit version. + * Bits 22-24 are taken by CPUMCTX_INHIBIT_SHADOW_SS, CPUMCTX_INHIBIT_SHADOW_STI + * and CPUMCTX_INHIBIT_NMI, bits 25-28 are for CPUMCTX_DBG_HIT_DRX_MASK, and + * bits 29-30 are for DBGF events and breakpoints. + * + * @todo The two DBGF bits could be merged. The NMI inhibiting could move to + * bit 32 or higher as it isn't automatically cleared on instruction + * completion (except for iret). + */ +#define CPUMX86EFLAGS_INT_MASK_64 UINT64_C(0x00000000ffc00000) +/** Mask of internal flags kept with EFLAGS, 32-bit version. */ +#define CPUMX86EFLAGS_INT_MASK_32 UINT32_C(0xffc00000) + + +/** + * CPUM EFLAGS. + * + * This differs from X86EFLAGS in that we could use bits 31:22 for internal + * purposes, see CPUMX86EFLAGS_HW_BITS. + */ +typedef union CPUMX86EFLAGS +{ + /** The full unsigned view, both hardware and VBox bits. */ + uint32_t uBoth; + /** The plain unsigned view of the hardware bits. */ +#if CPUMX86EFLAGS_HW_BITS == 32 + uint32_t u; +#else + uint32_t u : CPUMX86EFLAGS_HW_BITS; +#endif +#ifndef VBOX_FOR_DTRACE_LIB + /** The bitfield view. */ + X86EFLAGSBITS Bits; +#endif +} CPUMX86EFLAGS; +/** Pointer to CPUM EFLAGS. */ +typedef CPUMX86EFLAGS *PCPUMX86EFLAGS; +/** Pointer to const CPUM EFLAGS. */ +typedef const CPUMX86EFLAGS *PCCPUMX86EFLAGS; + +/** + * CPUM RFLAGS. + * + * This differs from X86EFLAGS in that we use could be using bits 63:22 for + * internal purposes, see CPUMX86EFLAGS_HW_BITS. + */ +typedef union CPUMX86RFLAGS +{ + /** The full unsigned view, both hardware and VBox bits. */ + uint64_t uBoth; + /** The plain unsigned view of the hardware bits. */ +#if CPUMX86EFLAGS_HW_BITS == 32 + uint32_t u; +#else + uint32_t u : CPUMX86EFLAGS_HW_BITS; +#endif +#ifndef VBOX_FOR_DTRACE_LIB + /** The bitfield view. */ + X86EFLAGSBITS Bits; +#endif +} CPUMX86RFLAGS; +/** Pointer to CPUM RFLAGS. */ +typedef CPUMX86RFLAGS *PCPUMX86RFLAGS; +/** Pointer to const CPUM RFLAGS. */ +typedef const CPUMX86RFLAGS *PCCPUMX86RFLAGS; + + +/** + * CPU context. + */ +#pragma pack(1) /* for VBOXIDTR / VBOXGDTR. */ +typedef struct CPUMCTX +{ + /** General purpose registers. */ + union /* no tag! */ + { + /** The general purpose register array view, indexed by X86_GREG_XXX. */ + CPUMCTXGREG aGRegs[16]; + + /** 64-bit general purpose register view. */ + RT_GCC_EXTENSION struct /* no tag! */ + { + uint64_t rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15; + } CPUM_STRUCT_NM(qw); + /** 64-bit general purpose register view. */ + RT_GCC_EXTENSION struct /* no tag! */ + { + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + } CPUM_STRUCT_NM(qw2); + /** 32-bit general purpose register view. */ + RT_GCC_EXTENSION struct /* no tag! */ + { + uint32_t eax, u32Pad00, ecx, u32Pad01, edx, u32Pad02, ebx, u32Pad03, + esp, u32Pad04, ebp, u32Pad05, esi, u32Pad06, edi, u32Pad07, + r8d, u32Pad08, r9d, u32Pad09, r10d, u32Pad10, r11d, u32Pad11, + r12d, u32Pad12, r13d, u32Pad13, r14d, u32Pad14, r15d, u32Pad15; + } CPUM_STRUCT_NM(dw); + /** 16-bit general purpose register view. */ + RT_GCC_EXTENSION struct /* no tag! */ + { + uint16_t ax, au16Pad00[3], cx, au16Pad01[3], dx, au16Pad02[3], bx, au16Pad03[3], + sp, au16Pad04[3], bp, au16Pad05[3], si, au16Pad06[3], di, au16Pad07[3], + r8w, au16Pad08[3], r9w, au16Pad09[3], r10w, au16Pad10[3], r11w, au16Pad11[3], + r12w, au16Pad12[3], r13w, au16Pad13[3], r14w, au16Pad14[3], r15w, au16Pad15[3]; + } CPUM_STRUCT_NM(w); + RT_GCC_EXTENSION struct /* no tag! */ + { + uint8_t al, ah, abPad00[6], cl, ch, abPad01[6], dl, dh, abPad02[6], bl, bh, abPad03[6], + spl, abPad04[7], bpl, abPad05[7], sil, abPad06[7], dil, abPad07[7], + r8l, abPad08[7], r9l, abPad09[7], r10l, abPad10[7], r11l, abPad11[7], + r12l, abPad12[7], r13l, abPad13[7], r14l, abPad14[7], r15l, abPad15[7]; + } CPUM_STRUCT_NM(b); + } CPUM_UNION_NM(g); + + /** Segment registers. */ + union /* no tag! */ + { + /** The segment register array view, indexed by X86_SREG_XXX. */ + CPUMSELREG aSRegs[6]; + /** The named segment register view. */ + RT_GCC_EXTENSION struct /* no tag! */ + { + CPUMSELREG es, cs, ss, ds, fs, gs; + } CPUM_STRUCT_NM(n); + } CPUM_UNION_NM(s); + + /** The task register. + * Only the guest context uses all the members. */ + CPUMSELREG ldtr; + /** The task register. + * Only the guest context uses all the members. */ + CPUMSELREG tr; + + /** The program counter. */ + union + { + uint16_t ip; + uint32_t eip; + uint64_t rip; + } CPUM_UNION_NM(rip); + + /** The flags register. */ + union + { + CPUMX86EFLAGS eflags; + CPUMX86RFLAGS rflags; + } CPUM_UNION_NM(rflags); + + /** 0x150 - Externalized state tracker, CPUMCTX_EXTRN_XXX. */ + uint64_t fExtrn; + + /** The RIP value an interrupt shadow is/was valid for. */ + uint64_t uRipInhibitInt; + + /** @name Control registers. + * @{ */ + uint64_t cr0; + uint64_t cr2; + uint64_t cr3; + uint64_t cr4; + /** @} */ + + /** Debug registers. + * @remarks DR4 and DR5 should not be used since they are aliases for + * DR6 and DR7 respectively on both AMD and Intel CPUs. + * @remarks DR8-15 are currently not supported by AMD or Intel, so + * neither do we. + */ + uint64_t dr[8]; + + /** Padding before the structure so the 64-bit member is correctly aligned. + * @todo fix this structure! */ + uint16_t gdtrPadding[3]; + /** Global Descriptor Table register. */ + VBOXGDTR gdtr; + + /** Padding before the structure so the 64-bit member is correctly aligned. + * @todo fix this structure! */ + uint16_t idtrPadding[3]; + /** Interrupt Descriptor Table register. */ + VBOXIDTR idtr; + + /** The sysenter msr registers. + * This member is not used by the hypervisor context. */ + CPUMSYSENTER SysEnter; + + /** @name System MSRs. + * @{ */ + uint64_t msrEFER; /**< @todo move EFER up to the crX registers for better cacheline mojo */ + uint64_t msrSTAR; /**< Legacy syscall eip, cs & ss. */ + uint64_t msrPAT; /**< Page attribute table. */ + uint64_t msrLSTAR; /**< 64 bits mode syscall rip. */ + uint64_t msrCSTAR; /**< Compatibility mode syscall rip. */ + uint64_t msrSFMASK; /**< syscall flag mask. */ + uint64_t msrKERNELGSBASE; /**< swapgs exchange value. */ + /** @} */ + + uint64_t au64Unused[2]; + + /** 0x240 - PAE PDPTEs. */ + X86PDPE aPaePdpes[4]; + + /** 0x260 - The XCR0..XCR1 registers. */ + uint64_t aXcr[2]; + /** 0x270 - The mask to pass to XSAVE/XRSTOR in EDX:EAX. If zero we use + * FXSAVE/FXRSTOR (since bit 0 will always be set, we only need to test it). */ + uint64_t fXStateMask; + /** 0x278 - Mirror of CPUMCPU::fUseFlags[CPUM_USED_FPU_GUEST]. */ + bool fUsedFpuGuest; + uint8_t afUnused[7]; + + /* ---- Start of members not zeroed at reset. ---- */ + + /** 0x280 - State component offsets into pXState, UINT16_MAX if not present. + * @note Everything before this member will be memset to zero during reset. */ + uint16_t aoffXState[64]; + /** 0x300 - The extended state (FPU/SSE/AVX/AVX-2/XXXX). + * Aligned on 256 byte boundrary (min req is currently 64 bytes). */ + union /* no tag */ + { + X86XSAVEAREA XState; + /** Byte view for simple indexing and space allocation. */ + uint8_t abXState[0x4000 - 0x300]; + } CPUM_UNION_NM(u); + + /** 0x4000 - Hardware virtualization state. + * @note This is page aligned, so an full page member comes first in the + * substructures. */ + struct + { + union /* no tag! */ + { + struct + { + /** 0x4000 - Cache of the nested-guest VMCB. */ + SVMVMCB Vmcb; + /** 0x5000 - The MSRPM (MSR Permission bitmap). + * + * This need not be physically contiguous pages because we use the one from + * HMPHYSCPU while executing the nested-guest using hardware-assisted SVM. + * This one is just used for caching the bitmap from guest physical memory. + * + * @todo r=bird: This is not used directly by AMD-V hardware, so it doesn't + * really need to even be page aligned. + * + * Also, couldn't we just access the guest page directly when we need to, + * or do we have to use a cached copy of it? */ + uint8_t abMsrBitmap[SVM_MSRPM_PAGES * X86_PAGE_SIZE]; + /** 0x7000 - The IOPM (IO Permission bitmap). + * + * This need not be physically contiguous pages because we re-use the ring-0 + * allocated IOPM while executing the nested-guest using hardware-assisted SVM + * because it's identical (we trap all IO accesses). + * + * This one is just used for caching the IOPM from guest physical memory in + * case the guest hypervisor allows direct access to some IO ports. + * + * @todo r=bird: This is not used directly by AMD-V hardware, so it doesn't + * really need to even be page aligned. + * + * Also, couldn't we just access the guest page directly when we need to, + * or do we have to use a cached copy of it? */ + uint8_t abIoBitmap[SVM_IOPM_PAGES * X86_PAGE_SIZE]; + + /** 0xa000 - MSR holding physical address of the Guest's Host-state. */ + uint64_t uMsrHSavePa; + /** 0xa008 - Guest physical address of the nested-guest VMCB. */ + RTGCPHYS GCPhysVmcb; + /** 0xa010 - Guest's host-state save area. */ + SVMHOSTSTATE HostState; + /** 0xa0c8 - Guest TSC time-stamp of when the previous PAUSE instr. was + * executed. */ + uint64_t uPrevPauseTick; + /** 0xa0d0 - Pause filter count. */ + uint16_t cPauseFilter; + /** 0xa0d2 - Pause filter threshold. */ + uint16_t cPauseFilterThreshold; + /** 0xa0d4 - Whether the injected event is subject to event intercepts. */ + bool fInterceptEvents; + /** 0xa0d5 - Padding. */ + bool afPadding[3]; + } svm; + + struct + { + /** 0x4000 - The current VMCS. */ + VMXVVMCS Vmcs; + /** 0X5000 - The shadow VMCS. */ + VMXVVMCS ShadowVmcs; + /** 0x6000 - The VMREAD bitmap. + * @todo r=bird: Do we really need to keep copies for these? Couldn't we just + * access the guest memory directly as needed? */ + uint8_t abVmreadBitmap[VMX_V_VMREAD_VMWRITE_BITMAP_SIZE]; + /** 0x7000 - The VMWRITE bitmap. + * @todo r=bird: Do we really need to keep copies for these? Couldn't we just + * access the guest memory directly as needed? */ + uint8_t abVmwriteBitmap[VMX_V_VMREAD_VMWRITE_BITMAP_SIZE]; + /** 0x8000 - The VM-entry MSR-load area. */ + VMXAUTOMSR aEntryMsrLoadArea[VMX_V_AUTOMSR_AREA_SIZE / sizeof(VMXAUTOMSR)]; + /** 0xa000 - The VM-exit MSR-store area. */ + VMXAUTOMSR aExitMsrStoreArea[VMX_V_AUTOMSR_AREA_SIZE / sizeof(VMXAUTOMSR)]; + /** 0xc000 - The VM-exit MSR-load area. */ + VMXAUTOMSR aExitMsrLoadArea[VMX_V_AUTOMSR_AREA_SIZE / sizeof(VMXAUTOMSR)]; + /** 0xe000 - The MSR permission bitmap. + * @todo r=bird: Do we really need to keep copies for these? Couldn't we just + * access the guest memory directly as needed? */ + uint8_t abMsrBitmap[VMX_V_MSR_BITMAP_SIZE]; + /** 0xf000 - The I/O permission bitmap. + * @todo r=bird: Do we really need to keep copies for these? Couldn't we just + * access the guest memory directly as needed? */ + uint8_t abIoBitmap[VMX_V_IO_BITMAP_A_SIZE + VMX_V_IO_BITMAP_B_SIZE]; + + /** 0x11000 - Guest physical address of the VMXON region. */ + RTGCPHYS GCPhysVmxon; + /** 0x11008 - Guest physical address of the current VMCS pointer. */ + RTGCPHYS GCPhysVmcs; + /** 0x11010 - Guest physical address of the shadow VMCS pointer. */ + RTGCPHYS GCPhysShadowVmcs; + /** 0x11018 - Last emulated VMX instruction/VM-exit diagnostic. */ + VMXVDIAG enmDiag; + /** 0x1101c - VMX abort reason. */ + VMXABORT enmAbort; + /** 0x11020 - Last emulated VMX instruction/VM-exit diagnostic auxiliary info. + * (mainly used for info. that's not part of the VMCS). */ + uint64_t uDiagAux; + /** 0x11028 - VMX abort auxiliary info. */ + uint32_t uAbortAux; + /** 0x1102c - Whether the guest is in VMX root mode. */ + bool fInVmxRootMode; + /** 0x1102d - Whether the guest is in VMX non-root mode. */ + bool fInVmxNonRootMode; + /** 0x1102e - Whether the injected events are subjected to event intercepts. */ + bool fInterceptEvents; + /** 0x1102f - Whether blocking of NMI (or virtual-NMIs) was in effect in VMX + * non-root mode before execution of IRET. */ + bool fNmiUnblockingIret; + /** 0x11030 - Guest TSC timestamp of the first PAUSE instruction that is + * considered to be the first in a loop. */ + uint64_t uFirstPauseLoopTick; + /** 0x11038 - Guest TSC timestamp of the previous PAUSE instruction. */ + uint64_t uPrevPauseTick; + /** 0x11040 - Guest TSC timestamp of VM-entry (used for VMX-preemption + * timer). */ + uint64_t uEntryTick; + /** 0x11048 - Virtual-APIC write offset (until trap-like VM-exit). */ + uint16_t offVirtApicWrite; + /** 0x1104a - Whether virtual-NMI blocking is in effect. */ + bool fVirtNmiBlocking; + /** 0x1104b - Padding. */ + uint8_t abPadding0[5]; + /** 0x11050 - Guest VMX MSRs. */ + VMXMSRS Msrs; + } vmx; + } CPUM_UNION_NM(s); + + /** 0x11130 - Hardware virtualization type currently in use. */ + CPUMHWVIRT enmHwvirt; + /** 0x11134 - Global interrupt flag - AMD only (always true on Intel). */ + bool fGif; + /** 0x11135 - Padding. */ + bool afPadding0[3]; + /** 0x11138 - A subset of guest inhibit flags (CPUMCTX_INHIBIT_XXX) that are + * saved while running the nested-guest. */ + uint32_t fSavedInhibit; + /** 0x1113c - Pad to 64 byte boundary. */ + uint8_t abPadding1[4]; + } hwvirt; +} CPUMCTX; +#pragma pack() + +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSizeAlignment(CPUMCTX, 64); +AssertCompileSizeAlignment(CPUMCTX, 32); +AssertCompileSizeAlignment(CPUMCTX, 16); +AssertCompileSizeAlignment(CPUMCTX, 8); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rax, 0x0000); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rcx, 0x0008); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rdx, 0x0010); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rbx, 0x0018); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rsp, 0x0020); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rbp, 0x0028); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rsi, 0x0030); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rdi, 0x0038); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r8, 0x0040); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r9, 0x0048); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r10, 0x0050); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r11, 0x0058); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r12, 0x0060); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r13, 0x0068); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r14, 0x0070); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r15, 0x0078); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) es, 0x0080); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) cs, 0x0098); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) ss, 0x00b0); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) ds, 0x00c8); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) fs, 0x00e0); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) gs, 0x00f8); +AssertCompileMemberOffset(CPUMCTX, ldtr, 0x0110); +AssertCompileMemberOffset(CPUMCTX, tr, 0x0128); +AssertCompileMemberOffset(CPUMCTX, rip, 0x0140); +AssertCompileMemberOffset(CPUMCTX, rflags, 0x0148); +AssertCompileMemberOffset(CPUMCTX, fExtrn, 0x0150); +AssertCompileMemberOffset(CPUMCTX, uRipInhibitInt, 0x0158); +AssertCompileMemberOffset(CPUMCTX, cr0, 0x0160); +AssertCompileMemberOffset(CPUMCTX, cr2, 0x0168); +AssertCompileMemberOffset(CPUMCTX, cr3, 0x0170); +AssertCompileMemberOffset(CPUMCTX, cr4, 0x0178); +AssertCompileMemberOffset(CPUMCTX, dr, 0x0180); +AssertCompileMemberOffset(CPUMCTX, gdtr, 0x01c0+6); +AssertCompileMemberOffset(CPUMCTX, idtr, 0x01d0+6); +AssertCompileMemberOffset(CPUMCTX, SysEnter, 0x01e0); +AssertCompileMemberOffset(CPUMCTX, msrEFER, 0x01f8); +AssertCompileMemberOffset(CPUMCTX, msrSTAR, 0x0200); +AssertCompileMemberOffset(CPUMCTX, msrPAT, 0x0208); +AssertCompileMemberOffset(CPUMCTX, msrLSTAR, 0x0210); +AssertCompileMemberOffset(CPUMCTX, msrCSTAR, 0x0218); +AssertCompileMemberOffset(CPUMCTX, msrSFMASK, 0x0220); +AssertCompileMemberOffset(CPUMCTX, msrKERNELGSBASE, 0x0228); +AssertCompileMemberOffset(CPUMCTX, aPaePdpes, 0x0240); +AssertCompileMemberOffset(CPUMCTX, aXcr, 0x0260); +AssertCompileMemberOffset(CPUMCTX, fXStateMask, 0x0270); +AssertCompileMemberOffset(CPUMCTX, fUsedFpuGuest, 0x0278); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(u.) XState, 0x0300); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(u.) abXState, 0x0300); +AssertCompileMemberAlignment(CPUMCTX, CPUM_UNION_NM(u.) XState, 0x0100); +/* Only do spot checks for hwvirt */ +AssertCompileMemberAlignment(CPUMCTX, hwvirt, 0x1000); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) svm.Vmcb, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) svm.abMsrBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) svm.abIoBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.Vmcs, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.ShadowVmcs, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.abVmreadBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.abVmwriteBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.aEntryMsrLoadArea, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.aExitMsrStoreArea, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.aExitMsrLoadArea, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.abMsrBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.abIoBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.Msrs, 8); +AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) svm.abIoBitmap, 0x7000); +AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) svm.fInterceptEvents, 0xa0d4); +AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.abIoBitmap, 0xf000); +AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.fVirtNmiBlocking, 0x1104a); +AssertCompileMemberOffset(CPUMCTX, hwvirt.enmHwvirt, 0x11130); +AssertCompileMemberOffset(CPUMCTX, hwvirt.fGif, 0x11134); +AssertCompileMemberOffset(CPUMCTX, hwvirt.fSavedInhibit, 0x11138); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_NM(g.) aGRegs); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r0); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rcx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r1); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r2); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r3); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r4); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r5); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r6); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r7); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) eax); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rcx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) ecx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) edx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) ebx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) esp); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) ebp); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) esi); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) edi); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r8, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r8d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r9, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r9d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r10, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r10d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r11, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r11d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r12, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r12d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r13, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r13d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r14, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r14d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r15, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r15d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) ax); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rcx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) cx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) dx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) bx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) sp); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) bp); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) si); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) di); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r8, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r8w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r9, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r9w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r10, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r10w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r11, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r11w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r12, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r12w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r13, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r13w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r14, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r14w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r15, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r15w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) al); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rcx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) cl); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) dl); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) bl); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) spl); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) bpl); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) sil); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) dil); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r8, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r8l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r9, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r9l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r10, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r10l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r11, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r11l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r12, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r12l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r13, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r13l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r14, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r14l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r15, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r15l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) es, CPUMCTX, CPUM_UNION_NM(s.) aSRegs); +# ifndef _MSC_VER +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xAX]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rcx, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xCX]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdx, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xDX]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbx, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xBX]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsp, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xSP]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbp, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xBP]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsi, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xSI]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdi, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xDI]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r8, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x8]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r9, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x9]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r10, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x10]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r11, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x11]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r12, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x12]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r13, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x13]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r14, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x14]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r15, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x15]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) es, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_ES]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) cs, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_CS]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) ss, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_SS]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) ds, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_DS]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) fs, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_FS]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) gs, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_GS]); +# endif + + +/** + * Calculates the pointer to the given extended state component. + * + * @returns Pointer of type @a a_PtrType + * @param a_pCtx Pointer to the context. + * @param a_iCompBit The extended state component bit number. This bit + * must be set in CPUMCTX::fXStateMask. + * @param a_PtrType The pointer type of the extended state component. + * + */ +#if defined(VBOX_STRICT) && defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define CPUMCTX_XSAVE_C_PTR(a_pCtx, a_iCompBit, a_PtrType) \ + ([](PCCPUMCTX a_pLambdaCtx) -> a_PtrType \ + { \ + AssertCompile((a_iCompBit) < 64U); \ + AssertMsg(a_pLambdaCtx->fXStateMask & RT_BIT_64(a_iCompBit), (#a_iCompBit "\n")); \ + AssertMsg(a_pLambdaCtx->aoffXState[(a_iCompBit)] != UINT16_MAX, (#a_iCompBit "\n")); \ + return (a_PtrType)(&a_pLambdaCtx->abXState[a_pLambdaCtx->aoffXState[(a_iCompBit)]]); \ + }(a_pCtx)) +#elif defined(VBOX_STRICT) && defined(__GNUC__) +# define CPUMCTX_XSAVE_C_PTR(a_pCtx, a_iCompBit, a_PtrType) \ + __extension__ (\ + { \ + AssertCompile((a_iCompBit) < 64U); \ + AssertMsg((a_pCtx)->fXStateMask & RT_BIT_64(a_iCompBit), (#a_iCompBit "\n")); \ + AssertMsg((a_pCtx)->aoffXState[(a_iCompBit)] != UINT16_MAX, (#a_iCompBit "\n")); \ + (a_PtrType)(&(a_pCtx)->abXState[(a_pCtx)->aoffXState[(a_iCompBit)]]); \ + }) +#else +# define CPUMCTX_XSAVE_C_PTR(a_pCtx, a_iCompBit, a_PtrType) \ + ((a_PtrType)(&(a_pCtx)->abXState[(a_pCtx)->aoffXState[(a_iCompBit)]])) +#endif + +/** + * Gets the first selector register of a CPUMCTX. + * + * Use this with X86_SREG_COUNT to loop thru the selector registers. + */ +# define CPUMCTX_FIRST_SREG(a_pCtx) (&(a_pCtx)->es) + +#endif /* !VBOX_FOR_DTRACE_LIB */ + + +/** @name CPUMCTX_EXTRN_XXX + * Used for parts of the CPUM state that is externalized and needs fetching + * before use. + * + * @{ */ +/** External state keeper: Invalid. */ +#define CPUMCTX_EXTRN_KEEPER_INVALID UINT64_C(0x0000000000000000) +/** External state keeper: HM. */ +#define CPUMCTX_EXTRN_KEEPER_HM UINT64_C(0x0000000000000001) +/** External state keeper: NEM. */ +#define CPUMCTX_EXTRN_KEEPER_NEM UINT64_C(0x0000000000000002) +/** External state keeper: REM. */ +#define CPUMCTX_EXTRN_KEEPER_REM UINT64_C(0x0000000000000003) +/** External state keeper mask. */ +#define CPUMCTX_EXTRN_KEEPER_MASK UINT64_C(0x0000000000000003) + +/** The RIP register value is kept externally. */ +#define CPUMCTX_EXTRN_RIP UINT64_C(0x0000000000000004) +/** The RFLAGS register values are kept externally. */ +#define CPUMCTX_EXTRN_RFLAGS UINT64_C(0x0000000000000008) + +/** The RAX register value is kept externally. */ +#define CPUMCTX_EXTRN_RAX UINT64_C(0x0000000000000010) +/** The RCX register value is kept externally. */ +#define CPUMCTX_EXTRN_RCX UINT64_C(0x0000000000000020) +/** The RDX register value is kept externally. */ +#define CPUMCTX_EXTRN_RDX UINT64_C(0x0000000000000040) +/** The RBX register value is kept externally. */ +#define CPUMCTX_EXTRN_RBX UINT64_C(0x0000000000000080) +/** The RSP register value is kept externally. */ +#define CPUMCTX_EXTRN_RSP UINT64_C(0x0000000000000100) +/** The RBP register value is kept externally. */ +#define CPUMCTX_EXTRN_RBP UINT64_C(0x0000000000000200) +/** The RSI register value is kept externally. */ +#define CPUMCTX_EXTRN_RSI UINT64_C(0x0000000000000400) +/** The RDI register value is kept externally. */ +#define CPUMCTX_EXTRN_RDI UINT64_C(0x0000000000000800) +/** The R8 thru R15 register values are kept externally. */ +#define CPUMCTX_EXTRN_R8_R15 UINT64_C(0x0000000000001000) +/** General purpose registers mask. */ +#define CPUMCTX_EXTRN_GPRS_MASK UINT64_C(0x0000000000001ff0) + +/** The ES register values are kept externally. */ +#define CPUMCTX_EXTRN_ES UINT64_C(0x0000000000002000) +/** The CS register values are kept externally. */ +#define CPUMCTX_EXTRN_CS UINT64_C(0x0000000000004000) +/** The SS register values are kept externally. */ +#define CPUMCTX_EXTRN_SS UINT64_C(0x0000000000008000) +/** The DS register values are kept externally. */ +#define CPUMCTX_EXTRN_DS UINT64_C(0x0000000000010000) +/** The FS register values are kept externally. */ +#define CPUMCTX_EXTRN_FS UINT64_C(0x0000000000020000) +/** The GS register values are kept externally. */ +#define CPUMCTX_EXTRN_GS UINT64_C(0x0000000000040000) +/** Segment registers (includes CS). */ +#define CPUMCTX_EXTRN_SREG_MASK UINT64_C(0x000000000007e000) +/** Converts a X86_XREG_XXX index to a CPUMCTX_EXTRN_xS mask. */ +#define CPUMCTX_EXTRN_SREG_FROM_IDX(a_SRegIdx) RT_BIT_64((a_SRegIdx) + 13) +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompile(CPUMCTX_EXTRN_SREG_FROM_IDX(X86_SREG_ES) == CPUMCTX_EXTRN_ES); +AssertCompile(CPUMCTX_EXTRN_SREG_FROM_IDX(X86_SREG_CS) == CPUMCTX_EXTRN_CS); +AssertCompile(CPUMCTX_EXTRN_SREG_FROM_IDX(X86_SREG_DS) == CPUMCTX_EXTRN_DS); +AssertCompile(CPUMCTX_EXTRN_SREG_FROM_IDX(X86_SREG_FS) == CPUMCTX_EXTRN_FS); +AssertCompile(CPUMCTX_EXTRN_SREG_FROM_IDX(X86_SREG_GS) == CPUMCTX_EXTRN_GS); +#endif + +/** The GDTR register values are kept externally. */ +#define CPUMCTX_EXTRN_GDTR UINT64_C(0x0000000000080000) +/** The IDTR register values are kept externally. */ +#define CPUMCTX_EXTRN_IDTR UINT64_C(0x0000000000100000) +/** The LDTR register values are kept externally. */ +#define CPUMCTX_EXTRN_LDTR UINT64_C(0x0000000000200000) +/** The TR register values are kept externally. */ +#define CPUMCTX_EXTRN_TR UINT64_C(0x0000000000400000) +/** Table register mask. */ +#define CPUMCTX_EXTRN_TABLE_MASK UINT64_C(0x0000000000780000) + +/** The CR0 register value is kept externally. */ +#define CPUMCTX_EXTRN_CR0 UINT64_C(0x0000000000800000) +/** The CR2 register value is kept externally. */ +#define CPUMCTX_EXTRN_CR2 UINT64_C(0x0000000001000000) +/** The CR3 register value is kept externally. */ +#define CPUMCTX_EXTRN_CR3 UINT64_C(0x0000000002000000) +/** The CR4 register value is kept externally. */ +#define CPUMCTX_EXTRN_CR4 UINT64_C(0x0000000004000000) +/** Control register mask. */ +#define CPUMCTX_EXTRN_CR_MASK UINT64_C(0x0000000007800000) +/** The TPR/CR8 register value is kept externally. */ +#define CPUMCTX_EXTRN_APIC_TPR UINT64_C(0x0000000008000000) +/** The EFER register value is kept externally. */ +#define CPUMCTX_EXTRN_EFER UINT64_C(0x0000000010000000) + +/** The DR0, DR1, DR2 and DR3 register values are kept externally. */ +#define CPUMCTX_EXTRN_DR0_DR3 UINT64_C(0x0000000020000000) +/** The DR6 register value is kept externally. */ +#define CPUMCTX_EXTRN_DR6 UINT64_C(0x0000000040000000) +/** The DR7 register value is kept externally. */ +#define CPUMCTX_EXTRN_DR7 UINT64_C(0x0000000080000000) +/** Debug register mask. */ +#define CPUMCTX_EXTRN_DR_MASK UINT64_C(0x00000000e0000000) + +/** The XSAVE_C_X87 state is kept externally. */ +#define CPUMCTX_EXTRN_X87 UINT64_C(0x0000000100000000) +/** The XSAVE_C_SSE, XSAVE_C_YMM, XSAVE_C_ZMM_HI256, XSAVE_C_ZMM_16HI and + * XSAVE_C_OPMASK state is kept externally. */ +#define CPUMCTX_EXTRN_SSE_AVX UINT64_C(0x0000000200000000) +/** The state of XSAVE components not covered by CPUMCTX_EXTRN_X87 and + * CPUMCTX_EXTRN_SEE_AVX is kept externally. */ +#define CPUMCTX_EXTRN_OTHER_XSAVE UINT64_C(0x0000000400000000) +/** The state of XCR0 and XCR1 register values are kept externally. */ +#define CPUMCTX_EXTRN_XCRx UINT64_C(0x0000000800000000) + + +/** The KERNEL GS BASE MSR value is kept externally. */ +#define CPUMCTX_EXTRN_KERNEL_GS_BASE UINT64_C(0x0000001000000000) +/** The STAR, LSTAR, CSTAR and SFMASK MSR values are kept externally. */ +#define CPUMCTX_EXTRN_SYSCALL_MSRS UINT64_C(0x0000002000000000) +/** The SYSENTER_CS, SYSENTER_EIP and SYSENTER_ESP MSR values are kept externally. */ +#define CPUMCTX_EXTRN_SYSENTER_MSRS UINT64_C(0x0000004000000000) +/** The TSC_AUX MSR is kept externally. */ +#define CPUMCTX_EXTRN_TSC_AUX UINT64_C(0x0000008000000000) +/** All other stateful MSRs not covered by CPUMCTX_EXTRN_EFER, + * CPUMCTX_EXTRN_KERNEL_GS_BASE, CPUMCTX_EXTRN_SYSCALL_MSRS, + * CPUMCTX_EXTRN_SYSENTER_MSRS, and CPUMCTX_EXTRN_TSC_AUX. */ +#define CPUMCTX_EXTRN_OTHER_MSRS UINT64_C(0x0000010000000000) + +/** Mask of all the MSRs. */ +#define CPUMCTX_EXTRN_ALL_MSRS ( CPUMCTX_EXTRN_EFER | CPUMCTX_EXTRN_KERNEL_GS_BASE | CPUMCTX_EXTRN_SYSCALL_MSRS \ + | CPUMCTX_EXTRN_SYSENTER_MSRS | CPUMCTX_EXTRN_TSC_AUX | CPUMCTX_EXTRN_OTHER_MSRS) + +/** Hardware-virtualization (SVM or VMX) state is kept externally. */ +#define CPUMCTX_EXTRN_HWVIRT UINT64_C(0x0000020000000000) + +/** Inhibit maskable interrupts (VMCPU_FF_INHIBIT_INTERRUPTS) */ +#define CPUMCTX_EXTRN_INHIBIT_INT UINT64_C(0x0000040000000000) +/** Inhibit non-maskable interrupts (VMCPU_FF_BLOCK_NMIS). */ +#define CPUMCTX_EXTRN_INHIBIT_NMI UINT64_C(0x0000080000000000) + +/** Mask of bits the keepers can use for state tracking. */ +#define CPUMCTX_EXTRN_KEEPER_STATE_MASK UINT64_C(0xffff000000000000) + +/** NEM/Win: Event injection (known was interruption) pending state. */ +#define CPUMCTX_EXTRN_NEM_WIN_EVENT_INJECT UINT64_C(0x0001000000000000) +/** NEM/Win: Mask. */ +#define CPUMCTX_EXTRN_NEM_WIN_MASK UINT64_C(0x0001000000000000) + +/** HM/SVM: Nested-guest interrupt pending (VMCPU_FF_INTERRUPT_NESTED_GUEST). */ +#define CPUMCTX_EXTRN_HM_SVM_HWVIRT_VIRQ UINT64_C(0x0001000000000000) +/** HM/SVM: Mask. */ +#define CPUMCTX_EXTRN_HM_SVM_MASK UINT64_C(0x0001000000000000) + +/** All CPUM state bits, not including keeper specific ones. */ +#define CPUMCTX_EXTRN_ALL UINT64_C(0x00000ffffffffffc) +/** All CPUM state bits, including keeper specific ones. */ +#define CPUMCTX_EXTRN_ABSOLUTELY_ALL UINT64_C(0xfffffffffffffffc) +/** @} */ + + +/** @name CPUMCTX_INHIBIT_XXX - Interrupt inhibiting flags. + * @{ */ +/** Interrupt shadow following MOV SS or POP SS. + * + * When this in effect, both maskable and non-maskable interrupts are blocked + * from delivery for one instruction. Same for certain debug exceptions too, + * unlike the STI variant. + * + * It is implementation specific whether a sequence of two or more of these + * instructions will have any effect on the instruction following the last one + * of them. */ +#define CPUMCTX_INHIBIT_SHADOW_SS RT_BIT_32(0 + CPUMX86EFLAGS_HW_BITS) +/** Interrupt shadow following STI. + * Same as CPUMCTX_INHIBIT_SHADOW_SS but without blocking any debug exceptions. */ +#define CPUMCTX_INHIBIT_SHADOW_STI RT_BIT_32(1 + CPUMX86EFLAGS_HW_BITS) +/** Mask combining STI and SS shadowing. */ +#define CPUMCTX_INHIBIT_SHADOW (CPUMCTX_INHIBIT_SHADOW_SS | CPUMCTX_INHIBIT_SHADOW_STI) + +/** Interrupts blocked by NMI delivery. This condition is cleared by IRET. + * + * Section "6.7 NONMASKABLE INTERRUPT (NMI)" in Intel SDM Vol 3A states that + * "The processor also invokes certain hardware conditions to ensure that no + * other interrupts, including NMI interrupts, are received until the NMI + * handler has completed executing." This flag indicates that these + * conditions are currently active. + * + * @todo this does not really need to be in the lower 32-bits of EFLAGS. + */ +#define CPUMCTX_INHIBIT_NMI RT_BIT_32(2 + CPUMX86EFLAGS_HW_BITS) + +/** Mask containing all the interrupt inhibit bits. */ +#define CPUMCTX_INHIBIT_ALL_MASK (CPUMCTX_INHIBIT_SHADOW_SS | CPUMCTX_INHIBIT_SHADOW_STI | CPUMCTX_INHIBIT_NMI) +AssertCompile(CPUMCTX_INHIBIT_ALL_MASK < UINT32_MAX); +/** @} */ + +/** @name CPUMCTX_DBG_XXX - Pending debug events. + * @{ */ +/** Hit guest DR0 breakpoint. */ +#define CPUMCTX_DBG_HIT_DR0 RT_BIT_32(CPUMCTX_DBG_HIT_DR0_BIT) +#define CPUMCTX_DBG_HIT_DR0_BIT (3 + CPUMX86EFLAGS_HW_BITS) +/** Hit guest DR1 breakpoint. */ +#define CPUMCTX_DBG_HIT_DR1 RT_BIT_32(CPUMCTX_DBG_HIT_DR1_BIT) +#define CPUMCTX_DBG_HIT_DR1_BIT (4 + CPUMX86EFLAGS_HW_BITS) +/** Hit guest DR2 breakpoint. */ +#define CPUMCTX_DBG_HIT_DR2 RT_BIT_32(CPUMCTX_DBG_HIT_DR2_BIT) +#define CPUMCTX_DBG_HIT_DR2_BIT (5 + CPUMX86EFLAGS_HW_BITS) +/** Hit guest DR3 breakpoint. */ +#define CPUMCTX_DBG_HIT_DR3 RT_BIT_32(CPUMCTX_DBG_HIT_DR3_BIT) +#define CPUMCTX_DBG_HIT_DR3_BIT (6 + CPUMX86EFLAGS_HW_BITS) +/** Shift for the CPUMCTX_DBG_HIT_DRx bits. */ +#define CPUMCTX_DBG_HIT_DRX_SHIFT CPUMCTX_DBG_HIT_DR0_BIT +/** Mask of all guest pending DR0-DR3 breakpoint indicators. */ +#define CPUMCTX_DBG_HIT_DRX_MASK (CPUMCTX_DBG_HIT_DR0 | CPUMCTX_DBG_HIT_DR1 | CPUMCTX_DBG_HIT_DR2 | CPUMCTX_DBG_HIT_DR3) +/** DBGF event/breakpoint pending. */ +#define CPUMCTX_DBG_DBGF_EVENT RT_BIT_32(CPUMCTX_DBG_DBGF_EVENT_BIT) +#define CPUMCTX_DBG_DBGF_EVENT_BIT (7 + CPUMX86EFLAGS_HW_BITS) +/** DBGF event/breakpoint pending. */ +#define CPUMCTX_DBG_DBGF_BP RT_BIT_32(CPUMCTX_DBG_DBGF_BP_BIT) +#define CPUMCTX_DBG_DBGF_BP_BIT (8 + CPUMX86EFLAGS_HW_BITS) +/** Mask of all DBGF indicators. */ +#define CPUMCTX_DBG_DBGF_MASK (CPUMCTX_DBG_DBGF_EVENT | CPUMCTX_DBG_DBGF_BP) +AssertCompile((CPUMCTX_DBG_HIT_DRX_MASK | CPUMCTX_DBG_DBGF_MASK) < UINT32_MAX); +/** @} */ + + + +/** + * Additional guest MSRs (i.e. not part of the CPU context structure). + * + * @remarks Never change the order here because of the saved stated! The size + * can in theory be changed, but keep older VBox versions in mind. + */ +typedef union CPUMCTXMSRS +{ + struct + { + uint64_t TscAux; /**< MSR_K8_TSC_AUX */ + uint64_t MiscEnable; /**< MSR_IA32_MISC_ENABLE */ + uint64_t MtrrDefType; /**< IA32_MTRR_DEF_TYPE */ + uint64_t MtrrFix64K_00000; /**< IA32_MTRR_FIX16K_80000 */ + uint64_t MtrrFix16K_80000; /**< IA32_MTRR_FIX16K_80000 */ + uint64_t MtrrFix16K_A0000; /**< IA32_MTRR_FIX16K_A0000 */ + uint64_t MtrrFix4K_C0000; /**< IA32_MTRR_FIX4K_C0000 */ + uint64_t MtrrFix4K_C8000; /**< IA32_MTRR_FIX4K_C8000 */ + uint64_t MtrrFix4K_D0000; /**< IA32_MTRR_FIX4K_D0000 */ + uint64_t MtrrFix4K_D8000; /**< IA32_MTRR_FIX4K_D8000 */ + uint64_t MtrrFix4K_E0000; /**< IA32_MTRR_FIX4K_E0000 */ + uint64_t MtrrFix4K_E8000; /**< IA32_MTRR_FIX4K_E8000 */ + 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; +/** Pointer to the guest MSR state. */ +typedef CPUMCTXMSRS *PCPUMCTXMSRS; +/** Pointer to the const guest MSR state. */ +typedef const CPUMCTXMSRS *PCCPUMCTXMSRS; + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_cpumctx_h */ + diff --git a/include/VBox/vmm/cpumdis.h b/include/VBox/vmm/cpumdis.h new file mode 100644 index 00000000..ee09e7b5 --- /dev/null +++ b/include/VBox/vmm/cpumdis.h @@ -0,0 +1,61 @@ +/** @file + * CPUM - Disassembler. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cpumdis_h +#define VBOX_INCLUDED_vmm_cpumdis_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/cpum.h> +#include <iprt/x86.h> +#include <VBox/dis.h> + + +RT_C_DECLS_BEGIN +/** @addtogroup grp_cpum + * @{ + */ + +#ifdef IN_RING3 +VMMR3DECL(int) CPUMR3DisasmInstrCPU(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, RTGCPTR GCPtrPC, PDISCPUSTATE pCpu, const char *pszPrefix); +#endif + +/** @} */ +RT_C_DECLS_END + + +#endif /* !VBOX_INCLUDED_vmm_cpumdis_h */ + diff --git a/include/VBox/vmm/dbgf.h b/include/VBox/vmm/dbgf.h new file mode 100644 index 00000000..a961a3a5 --- /dev/null +++ b/include/VBox/vmm/dbgf.h @@ -0,0 +1,3192 @@ +/** @file + * DBGF - Debugger Facility. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_dbgf_h +#define VBOX_INCLUDED_vmm_dbgf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/log.h> /* LOG_ENABLED */ +#include <VBox/vmm/vmm.h> +#include <VBox/vmm/dbgfsel.h> + +#include <iprt/stdarg.h> +#include <iprt/dbg.h> + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_dbgf The Debugger Facility API + * @ingroup grp_vmm + * @{ + */ + +/** @defgroup grp_dbgf_r0 The R0 DBGF API + * @{ + */ +VMMR0_INT_DECL(void) DBGFR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(void) DBGFR0CleanupVM(PGVM pGVM); + +/** + * Request buffer for DBGFR0TracerCreateReqHandler / VMMR0_DO_DBGF_TRACER_CREATE. + * @see DBGFR0TracerCreateReqHandler. + */ +typedef struct DBGFTRACERCREATEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Where to return the address of the ring-3 tracer instance. */ + PDBGFTRACERINSR3 pTracerInsR3; + + /** Number of bytes for the shared event ring buffer. */ + uint32_t cbRingBuf; + + /** Set if the raw-mode component is desired. */ + bool fRCEnabled; + /** Explicit padding. */ + bool afReserved[3]; + +} DBGFTRACERCREATEREQ; +/** Pointer to a DBGFR0TracerCreate / VMMR0_DO_DBGF_TRACER_CREATE request buffer. */ +typedef DBGFTRACERCREATEREQ *PDBGFTRACERCREATEREQ; + +VMMR0_INT_DECL(int) DBGFR0TracerCreateReqHandler(PGVM pGVM, PDBGFTRACERCREATEREQ pReq); + +/** + * Request buffer for DBGFR0BpInitReqHandler / VMMR0_DO_DBGF_BP_INIT and + * DBGFR0BpPortIoInitReqHandler / VMMR0_DO_DBGF_BP_PORTIO_INIT. + * @see DBGFR0BpInitReqHandler, DBGFR0BpPortIoInitReqHandler. + */ +typedef struct DBGFBPINITREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Ring-3 pointer of the L1 lookup table on success. */ + R3PTRTYPE(volatile uint32_t *) paBpLocL1R3; +} DBGFBPINITREQ; +/** Pointer to a DBGFR0BpInitReqHandler / VMMR0_DO_DBGF_BP_INIT request buffer. */ +typedef DBGFBPINITREQ *PDBGFBPINITREQ; + +VMMR0_INT_DECL(int) DBGFR0BpInitReqHandler(PGVM pGVM, PDBGFBPINITREQ pReq); +VMMR0_INT_DECL(int) DBGFR0BpPortIoInitReqHandler(PGVM pGVM, PDBGFBPINITREQ pReq); + +/** + * Request buffer for DBGFR0BpOwnerInitReqHandler / VMMR0_DO_DBGF_BP_OWNER_INIT. + * @see DBGFR0BpOwnerInitReqHandler. + */ +typedef struct DBGFBPOWNERINITREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Ring-3 pointer of the breakpoint owner table on success. */ + R3PTRTYPE(void *) paBpOwnerR3; +} DBGFBPOWNERINITREQ; +/** Pointer to a DBGFR0BpOwnerInitReqHandler / VMMR0_DO_DBGF_BP_INIT request buffer. */ +typedef DBGFBPOWNERINITREQ *PDBGFBPOWNERINITREQ; + +VMMR0_INT_DECL(int) DBGFR0BpOwnerInitReqHandler(PGVM pGVM, PDBGFBPOWNERINITREQ pReq); + +/** + * Request buffer for DBGFR0BpChunkAllocReqHandler / VMMR0_DO_DBGF_CHUNK_ALLOC. + * @see DBGFR0BpChunkAllocReqHandler. + */ +typedef struct DBGFBPCHUNKALLOCREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Ring-3 pointer of the chunk base on success. */ + R3PTRTYPE(void *) pChunkBaseR3; + + /** The chunk ID to allocate. */ + uint32_t idChunk; +} DBGFBPCHUNKALLOCREQ; +/** Pointer to a DBGFR0BpChunkAllocReqHandler / VMMR0_DO_DBGF_CHUNK_ALLOC request buffer. */ +typedef DBGFBPCHUNKALLOCREQ *PDBGFBPCHUNKALLOCREQ; + +VMMR0_INT_DECL(int) DBGFR0BpChunkAllocReqHandler(PGVM pGVM, PDBGFBPCHUNKALLOCREQ pReq); + +/** + * Request buffer for DBGFR0BpL2TblChunkAllocReqHandler / VMMR0_DO_DBGF_L2_TBL_CHUNK_ALLOC. + * @see DBGFR0BpL2TblChunkAllocReqHandler. + */ +typedef struct DBGFBPL2TBLCHUNKALLOCREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Ring-3 pointer of the chunk base on success. */ + R3PTRTYPE(void *) pChunkBaseR3; + + /** The chunk ID to allocate. */ + uint32_t idChunk; +} DBGFBPL2TBLCHUNKALLOCREQ; +/** Pointer to a DBGFR0BpChunkAllocReqHandler / VMMR0_DO_DBGF_L2_TBL_CHUNK_ALLOC request buffer. */ +typedef DBGFBPL2TBLCHUNKALLOCREQ *PDBGFBPL2TBLCHUNKALLOCREQ; + +VMMR0_INT_DECL(int) DBGFR0BpL2TblChunkAllocReqHandler(PGVM pGVM, PDBGFBPL2TBLCHUNKALLOCREQ pReq); +/** @} */ + + +#ifdef IN_RING3 + +/** + * Mixed address. + */ +typedef struct DBGFADDRESS +{ + /** The flat address. */ + RTGCUINTPTR FlatPtr; + /** The selector offset address. */ + RTGCUINTPTR off; + /** The selector. DBGF_SEL_FLAT is a legal value. */ + RTSEL Sel; + /** Flags describing further details about the address. */ + uint16_t fFlags; +} DBGFADDRESS; +/** Pointer to a mixed address. */ +typedef DBGFADDRESS *PDBGFADDRESS; +/** Pointer to a const mixed address. */ +typedef const DBGFADDRESS *PCDBGFADDRESS; + +/** @name DBGFADDRESS Flags. + * @{ */ +/** A 16:16 far address. */ +#define DBGFADDRESS_FLAGS_FAR16 0 +/** A 16:32 far address. */ +#define DBGFADDRESS_FLAGS_FAR32 1 +/** A 16:64 far address. */ +#define DBGFADDRESS_FLAGS_FAR64 2 +/** A flat address. */ +#define DBGFADDRESS_FLAGS_FLAT 3 +/** A physical address. */ +#define DBGFADDRESS_FLAGS_PHYS 4 +/** A ring-0 host address (internal use only). */ +#define DBGFADDRESS_FLAGS_RING0 5 +/** The address type mask. */ +#define DBGFADDRESS_FLAGS_TYPE_MASK 7 + +/** Set if the address is valid. */ +#define DBGFADDRESS_FLAGS_VALID RT_BIT(3) + +/** Checks if the mixed address is flat or not. */ +#define DBGFADDRESS_IS_FLAT(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_FLAT ) +/** Checks if the mixed address is flat or not. */ +#define DBGFADDRESS_IS_PHYS(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_PHYS ) +/** Checks if the mixed address is far 16:16 or not. */ +#define DBGFADDRESS_IS_FAR16(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_FAR16 ) +/** Checks if the mixed address is far 16:32 or not. */ +#define DBGFADDRESS_IS_FAR32(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_FAR32 ) +/** Checks if the mixed address is far 16:64 or not. */ +#define DBGFADDRESS_IS_FAR64(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_FAR64 ) +/** Checks if the mixed address is any kind of far address. */ +#define DBGFADDRESS_IS_FAR(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) <= DBGFADDRESS_FLAGS_FAR64 ) +/** Checks if the mixed address host context ring-0 (special). */ +#define DBGFADDRESS_IS_R0_HC(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_RING0 ) +/** Checks if the mixed address a virtual guest context address (incl HMA). */ +#define DBGFADDRESS_IS_VIRT_GC(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) <= DBGFADDRESS_FLAGS_FLAT ) +/** Checks if the mixed address is valid. */ +#define DBGFADDRESS_IS_VALID(pAddress) RT_BOOL((pAddress)->fFlags & DBGFADDRESS_FLAGS_VALID) +/** @} */ + +VMMR3DECL(int) DBGFR3AddrFromSelOff(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, RTSEL Sel, RTUINTPTR off); +VMMR3DECL(int) DBGFR3AddrFromSelInfoOff(PUVM pUVM, PDBGFADDRESS pAddress, PCDBGFSELINFO pSelInfo, RTUINTPTR off); +VMMR3DECL(PDBGFADDRESS) DBGFR3AddrFromFlat(PUVM pUVM, PDBGFADDRESS pAddress, RTGCUINTPTR FlatPtr); +VMMR3DECL(PDBGFADDRESS) DBGFR3AddrFromPhys(PUVM pUVM, PDBGFADDRESS pAddress, RTGCPHYS PhysAddr); +VMMR3_INT_DECL(PDBGFADDRESS) DBGFR3AddrFromHostR0(PDBGFADDRESS pAddress, RTR0UINTPTR R0Ptr); +VMMR3DECL(bool) DBGFR3AddrIsValid(PUVM pUVM, PCDBGFADDRESS pAddress); +VMMR3DECL(int) DBGFR3AddrToPhys(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, PRTGCPHYS pGCPhys); +VMMR3DECL(int) DBGFR3AddrToHostPhys(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, PRTHCPHYS pHCPhys); +VMMR3DECL(int) DBGFR3AddrToVolatileR3Ptr(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, bool fReadOnly, void **ppvR3Ptr); +VMMR3DECL(PDBGFADDRESS) DBGFR3AddrAdd(PDBGFADDRESS pAddress, RTGCUINTPTR uAddend); +VMMR3DECL(PDBGFADDRESS) DBGFR3AddrSub(PDBGFADDRESS pAddress, RTGCUINTPTR uSubtrahend); + +#endif /* IN_RING3 */ + + + +/** + * VMM Debug Event Type. + */ +typedef enum DBGFEVENTTYPE +{ + /** Halt completed. + * This notifies that a halt command have been successfully completed. + */ + DBGFEVENT_HALT_DONE = 0, + /** Detach completed. + * This notifies that the detach command have been successfully completed. + */ + DBGFEVENT_DETACH_DONE, + /** The command from the debugger is not recognized. + * This means internal error or half implemented features. + */ + DBGFEVENT_INVALID_COMMAND, + + /** Fatal error. + * This notifies a fatal error in the VMM and that the debugger get's a + * chance to first hand information about the the problem. + */ + DBGFEVENT_FATAL_ERROR, + /** Breakpoint Hit. + * This notifies that a breakpoint installed by the debugger was hit. The + * identifier of the breakpoint can be found in the DBGFEVENT::u::Bp::iBp member. + */ + DBGFEVENT_BREAKPOINT, + /** I/O port breakpoint. + * @todo not yet implemented. */ + DBGFEVENT_BREAKPOINT_IO, + /** MMIO breakpoint. + * @todo not yet implemented. */ + DBGFEVENT_BREAKPOINT_MMIO, + /** Breakpoint Hit in the Hypervisor. + * This notifies that a breakpoint installed by the debugger was hit. The + * identifier of the breakpoint can be found in the DBGFEVENT::u::Bp::iBp member. + * @todo raw-mode: remove this + */ + DBGFEVENT_BREAKPOINT_HYPER, + /** Assertion in the Hypervisor (breakpoint instruction). + * This notifies that a breakpoint instruction was hit in the hypervisor context. + */ + DBGFEVENT_ASSERTION_HYPER, + /** Single Stepped. + * This notifies that a single step operation was completed. + */ + DBGFEVENT_STEPPED, + /** Single Stepped. + * This notifies that a hypervisor single step operation was completed. + */ + DBGFEVENT_STEPPED_HYPER, + /** The developer have used the DBGFSTOP macro or the PDMDeviceDBGFSTOP function + * to bring up the debugger at a specific place. + */ + DBGFEVENT_DEV_STOP, + /** The VM is powering off. + * When this notification is received, the debugger thread should detach ASAP. + */ + DBGFEVENT_POWERING_OFF, + + /** Hardware Interrupt break. + * @todo not yet implemented. */ + DBGFEVENT_INTERRUPT_HARDWARE, + /** Software Interrupt break. + * @todo not yet implemented. */ + DBGFEVENT_INTERRUPT_SOFTWARE, + + /** The first selectable event. + * Whether the debugger wants or doesn't want these events can be configured + * via DBGFR3xxx and queried via DBGFR3yyy. */ + DBGFEVENT_FIRST_SELECTABLE, + /** Tripple fault. */ + DBGFEVENT_TRIPLE_FAULT = DBGFEVENT_FIRST_SELECTABLE, + + /** @name Exception events + * The exception events normally represents guest exceptions, but depending on + * the execution mode some virtualization exceptions may occure (no nested + * paging, raw-mode, ++). When necessary, we will request additional VM exits. + * @{ */ + DBGFEVENT_XCPT_FIRST, /**< The first exception event. */ + DBGFEVENT_XCPT_DE /**< 0x00 - \#DE - Fault - NoErr - Integer divide error (zero/overflow). */ + = DBGFEVENT_XCPT_FIRST, + DBGFEVENT_XCPT_DB, /**< 0x01 - \#DB - trap/fault - NoErr - debug event. */ + DBGFEVENT_XCPT_02, /**< 0x02 - Reserved for NMI, see interrupt events. */ + DBGFEVENT_XCPT_BP, /**< 0x03 - \#BP - Trap - NoErr - Breakpoint, INT 3 instruction. */ + DBGFEVENT_XCPT_OF, /**< 0x04 - \#OF - Trap - NoErr - Overflow, INTO instruction. */ + DBGFEVENT_XCPT_BR, /**< 0x05 - \#BR - Fault - NoErr - BOUND Range Exceeded, BOUND instruction. */ + DBGFEVENT_XCPT_UD, /**< 0x06 - \#UD - Fault - NoErr - Undefined(/Invalid) Opcode. */ + DBGFEVENT_XCPT_NM, /**< 0x07 - \#NM - Fault - NoErr - Device not available, FP or (F)WAIT instruction. */ + DBGFEVENT_XCPT_DF, /**< 0x08 - \#DF - Abort - Err=0 - Double fault. */ + DBGFEVENT_XCPT_09, /**< 0x09 - Int9 - Fault - NoErr - Coprocessor Segment Overrun (obsolete). */ + DBGFEVENT_XCPT_TS, /**< 0x0a - \#TS - Fault - ErrCd - Invalid TSS, Taskswitch or TSS access. */ + DBGFEVENT_XCPT_NP, /**< 0x0b - \#NP - Fault - ErrCd - Segment not present. */ + DBGFEVENT_XCPT_SS, /**< 0x0c - \#SS - Fault - ErrCd - Stack-Segment fault. */ + DBGFEVENT_XCPT_GP, /**< 0x0d - \#GP - Fault - ErrCd - General protection fault. */ + DBGFEVENT_XCPT_PF, /**< 0x0e - \#PF - Fault - ErrCd - Page fault. - interrupt gate!!! */ + DBGFEVENT_XCPT_0f, /**< 0x0f - Rsvd - Resvd - Resvd - Intel Reserved. */ + DBGFEVENT_XCPT_MF, /**< 0x10 - \#MF - Fault - NoErr - x86 FPU Floating-Point Error (Math fault), FP or (F)WAIT instruction. */ + DBGFEVENT_XCPT_AC, /**< 0x11 - \#AC - Fault - Err=0 - Alignment Check. */ + DBGFEVENT_XCPT_MC, /**< 0x12 - \#MC - Abort - NoErr - Machine Check. */ + DBGFEVENT_XCPT_XF, /**< 0x13 - \#XF - Fault - NoErr - SIMD Floating-Point Exception. */ + DBGFEVENT_XCPT_VE, /**< 0x14 - \#VE - Fault - Noerr - Virtualization exception. */ + DBGFEVENT_XCPT_15, /**< 0x15 - Intel Reserved. */ + DBGFEVENT_XCPT_16, /**< 0x16 - Intel Reserved. */ + DBGFEVENT_XCPT_17, /**< 0x17 - Intel Reserved. */ + DBGFEVENT_XCPT_18, /**< 0x18 - Intel Reserved. */ + DBGFEVENT_XCPT_19, /**< 0x19 - Intel Reserved. */ + DBGFEVENT_XCPT_1a, /**< 0x1a - Intel Reserved. */ + DBGFEVENT_XCPT_1b, /**< 0x1b - Intel Reserved. */ + DBGFEVENT_XCPT_1c, /**< 0x1c - Intel Reserved. */ + DBGFEVENT_XCPT_1d, /**< 0x1d - Intel Reserved. */ + DBGFEVENT_XCPT_SX, /**< 0x1e - \#SX - Fault - ErrCd - Security Exception. */ + DBGFEVENT_XCPT_1f, /**< 0x1f - Intel Reserved. */ + DBGFEVENT_XCPT_LAST /**< The last exception event. */ + = DBGFEVENT_XCPT_1f, + /** @} */ + + /** @name Instruction events + * The instruction events exerts all possible effort to intercept the + * relevant instructions. However, in some execution modes we won't be able + * to catch them. So it goes. + * @{ */ + DBGFEVENT_INSTR_FIRST, /**< The first VM instruction event. */ + DBGFEVENT_INSTR_HALT /**< Instruction: HALT */ + = DBGFEVENT_INSTR_FIRST, + DBGFEVENT_INSTR_MWAIT, /**< Instruction: MWAIT */ + DBGFEVENT_INSTR_MONITOR, /**< Instruction: MONITOR */ + DBGFEVENT_INSTR_CPUID, /**< Instruction: CPUID (missing stuff in raw-mode). */ + DBGFEVENT_INSTR_INVD, /**< Instruction: INVD */ + DBGFEVENT_INSTR_WBINVD, /**< Instruction: WBINVD */ + DBGFEVENT_INSTR_INVLPG, /**< Instruction: INVLPG */ + DBGFEVENT_INSTR_RDTSC, /**< Instruction: RDTSC */ + DBGFEVENT_INSTR_RDTSCP, /**< Instruction: RDTSCP */ + DBGFEVENT_INSTR_RDPMC, /**< Instruction: RDPMC */ + DBGFEVENT_INSTR_RDMSR, /**< Instruction: RDMSR */ + DBGFEVENT_INSTR_WRMSR, /**< Instruction: WRMSR */ + DBGFEVENT_INSTR_CRX_READ, /**< Instruction: CRx read instruction (missing smsw in raw-mode, and reads in general in VT-x). */ + DBGFEVENT_INSTR_CRX_WRITE, /**< Instruction: CRx write */ + DBGFEVENT_INSTR_DRX_READ, /**< Instruction: DRx read */ + DBGFEVENT_INSTR_DRX_WRITE, /**< Instruction: DRx write */ + DBGFEVENT_INSTR_PAUSE, /**< Instruction: PAUSE instruction (not in raw-mode). */ + DBGFEVENT_INSTR_XSETBV, /**< Instruction: XSETBV */ + DBGFEVENT_INSTR_SIDT, /**< Instruction: SIDT */ + DBGFEVENT_INSTR_LIDT, /**< Instruction: LIDT */ + DBGFEVENT_INSTR_SGDT, /**< Instruction: SGDT */ + DBGFEVENT_INSTR_LGDT, /**< Instruction: LGDT */ + DBGFEVENT_INSTR_SLDT, /**< Instruction: SLDT */ + DBGFEVENT_INSTR_LLDT, /**< Instruction: LLDT */ + DBGFEVENT_INSTR_STR, /**< Instruction: STR */ + DBGFEVENT_INSTR_LTR, /**< Instruction: LTR */ + DBGFEVENT_INSTR_GETSEC, /**< Instruction: GETSEC */ + DBGFEVENT_INSTR_RSM, /**< Instruction: RSM */ + DBGFEVENT_INSTR_RDRAND, /**< Instruction: RDRAND */ + DBGFEVENT_INSTR_RDSEED, /**< Instruction: RDSEED */ + DBGFEVENT_INSTR_XSAVES, /**< Instruction: XSAVES */ + DBGFEVENT_INSTR_XRSTORS, /**< Instruction: XRSTORS */ + DBGFEVENT_INSTR_VMM_CALL, /**< Instruction: VMCALL (intel) or VMMCALL (AMD) */ + DBGFEVENT_INSTR_LAST_COMMON /**< Instruction: the last common event. */ + = DBGFEVENT_INSTR_VMM_CALL, + DBGFEVENT_INSTR_VMX_FIRST, /**< Instruction: VT-x - First. */ + DBGFEVENT_INSTR_VMX_VMCLEAR /**< Instruction: VT-x VMCLEAR */ + = DBGFEVENT_INSTR_VMX_FIRST, + DBGFEVENT_INSTR_VMX_VMLAUNCH, /**< Instruction: VT-x VMLAUNCH */ + DBGFEVENT_INSTR_VMX_VMPTRLD, /**< Instruction: VT-x VMPTRLD */ + DBGFEVENT_INSTR_VMX_VMPTRST, /**< Instruction: VT-x VMPTRST */ + DBGFEVENT_INSTR_VMX_VMREAD, /**< Instruction: VT-x VMREAD */ + DBGFEVENT_INSTR_VMX_VMRESUME, /**< Instruction: VT-x VMRESUME */ + DBGFEVENT_INSTR_VMX_VMWRITE, /**< Instruction: VT-x VMWRITE */ + DBGFEVENT_INSTR_VMX_VMXOFF, /**< Instruction: VT-x VMXOFF */ + DBGFEVENT_INSTR_VMX_VMXON, /**< Instruction: VT-x VMXON */ + DBGFEVENT_INSTR_VMX_VMFUNC, /**< Instruction: VT-x VMFUNC */ + DBGFEVENT_INSTR_VMX_INVEPT, /**< Instruction: VT-x INVEPT */ + DBGFEVENT_INSTR_VMX_INVVPID, /**< Instruction: VT-x INVVPID */ + DBGFEVENT_INSTR_VMX_INVPCID, /**< Instruction: VT-x INVPCID */ + DBGFEVENT_INSTR_VMX_LAST /**< Instruction: VT-x - Last. */ + = DBGFEVENT_INSTR_VMX_INVPCID, + DBGFEVENT_INSTR_SVM_FIRST, /**< Instruction: AMD-V - first */ + DBGFEVENT_INSTR_SVM_VMRUN /**< Instruction: AMD-V VMRUN */ + = DBGFEVENT_INSTR_SVM_FIRST, + DBGFEVENT_INSTR_SVM_VMLOAD, /**< Instruction: AMD-V VMLOAD */ + DBGFEVENT_INSTR_SVM_VMSAVE, /**< Instruction: AMD-V VMSAVE */ + DBGFEVENT_INSTR_SVM_STGI, /**< Instruction: AMD-V STGI */ + DBGFEVENT_INSTR_SVM_CLGI, /**< Instruction: AMD-V CLGI */ + DBGFEVENT_INSTR_SVM_LAST /**< Instruction: The last ADM-V VM exit event. */ + = DBGFEVENT_INSTR_SVM_CLGI, + DBGFEVENT_INSTR_LAST /**< Instruction: The last instruction event. */ + = DBGFEVENT_INSTR_SVM_LAST, + /** @} */ + + + /** @name VM exit events. + * VM exits events for VT-x and AMD-V execution mode. Many of the VM exits + * behind these events are also directly translated into instruction events, but + * the difference here is that the exit events will not try provoke the exits. + * @{ */ + DBGFEVENT_EXIT_FIRST, /**< The first VM exit event. */ + DBGFEVENT_EXIT_TASK_SWITCH /**< Exit: Task switch. */ + = DBGFEVENT_EXIT_FIRST, + DBGFEVENT_EXIT_HALT, /**< Exit: HALT instruction. */ + DBGFEVENT_EXIT_MWAIT, /**< Exit: MWAIT instruction. */ + DBGFEVENT_EXIT_MONITOR, /**< Exit: MONITOR instruction. */ + DBGFEVENT_EXIT_CPUID, /**< Exit: CPUID instruction (missing stuff in raw-mode). */ + DBGFEVENT_EXIT_INVD, /**< Exit: INVD instruction. */ + DBGFEVENT_EXIT_WBINVD, /**< Exit: WBINVD instruction. */ + DBGFEVENT_EXIT_INVLPG, /**< Exit: INVLPG instruction. */ + DBGFEVENT_EXIT_RDTSC, /**< Exit: RDTSC instruction. */ + DBGFEVENT_EXIT_RDTSCP, /**< Exit: RDTSCP instruction. */ + DBGFEVENT_EXIT_RDPMC, /**< Exit: RDPMC instruction. */ + DBGFEVENT_EXIT_RDMSR, /**< Exit: RDMSR instruction. */ + DBGFEVENT_EXIT_WRMSR, /**< Exit: WRMSR instruction. */ + DBGFEVENT_EXIT_CRX_READ, /**< Exit: CRx read instruction (missing smsw in raw-mode, and reads in general in VT-x). */ + DBGFEVENT_EXIT_CRX_WRITE, /**< Exit: CRx write instruction. */ + DBGFEVENT_EXIT_DRX_READ, /**< Exit: DRx read instruction. */ + DBGFEVENT_EXIT_DRX_WRITE, /**< Exit: DRx write instruction. */ + DBGFEVENT_EXIT_PAUSE, /**< Exit: PAUSE instruction (not in raw-mode). */ + DBGFEVENT_EXIT_XSETBV, /**< Exit: XSETBV instruction. */ + DBGFEVENT_EXIT_SIDT, /**< Exit: SIDT instruction. */ + DBGFEVENT_EXIT_LIDT, /**< Exit: LIDT instruction. */ + DBGFEVENT_EXIT_SGDT, /**< Exit: SGDT instruction. */ + DBGFEVENT_EXIT_LGDT, /**< Exit: LGDT instruction. */ + DBGFEVENT_EXIT_SLDT, /**< Exit: SLDT instruction. */ + DBGFEVENT_EXIT_LLDT, /**< Exit: LLDT instruction. */ + DBGFEVENT_EXIT_STR, /**< Exit: STR instruction. */ + DBGFEVENT_EXIT_LTR, /**< Exit: LTR instruction. */ + DBGFEVENT_EXIT_GETSEC, /**< Exit: GETSEC instruction. */ + DBGFEVENT_EXIT_RSM, /**< Exit: RSM instruction. */ + DBGFEVENT_EXIT_RDRAND, /**< Exit: RDRAND instruction. */ + DBGFEVENT_EXIT_RDSEED, /**< Exit: RDSEED instruction. */ + DBGFEVENT_EXIT_XSAVES, /**< Exit: XSAVES instruction. */ + DBGFEVENT_EXIT_XRSTORS, /**< Exit: XRSTORS instruction. */ + DBGFEVENT_EXIT_VMM_CALL, /**< Exit: VMCALL (intel) or VMMCALL (AMD) instruction. */ + DBGFEVENT_EXIT_LAST_COMMON /**< Exit: the last common event. */ + = DBGFEVENT_EXIT_VMM_CALL, + DBGFEVENT_EXIT_VMX_FIRST, /**< Exit: VT-x - First. */ + DBGFEVENT_EXIT_VMX_VMCLEAR /**< Exit: VT-x VMCLEAR instruction. */ + = DBGFEVENT_EXIT_VMX_FIRST, + DBGFEVENT_EXIT_VMX_VMLAUNCH, /**< Exit: VT-x VMLAUNCH instruction. */ + DBGFEVENT_EXIT_VMX_VMPTRLD, /**< Exit: VT-x VMPTRLD instruction. */ + DBGFEVENT_EXIT_VMX_VMPTRST, /**< Exit: VT-x VMPTRST instruction. */ + DBGFEVENT_EXIT_VMX_VMREAD, /**< Exit: VT-x VMREAD instruction. */ + DBGFEVENT_EXIT_VMX_VMRESUME, /**< Exit: VT-x VMRESUME instruction. */ + DBGFEVENT_EXIT_VMX_VMWRITE, /**< Exit: VT-x VMWRITE instruction. */ + DBGFEVENT_EXIT_VMX_VMXOFF, /**< Exit: VT-x VMXOFF instruction. */ + DBGFEVENT_EXIT_VMX_VMXON, /**< Exit: VT-x VMXON instruction. */ + DBGFEVENT_EXIT_VMX_VMFUNC, /**< Exit: VT-x VMFUNC instruction. */ + DBGFEVENT_EXIT_VMX_INVEPT, /**< Exit: VT-x INVEPT instruction. */ + DBGFEVENT_EXIT_VMX_INVVPID, /**< Exit: VT-x INVVPID instruction. */ + DBGFEVENT_EXIT_VMX_INVPCID, /**< Exit: VT-x INVPCID instruction. */ + DBGFEVENT_EXIT_VMX_EPT_VIOLATION, /**< Exit: VT-x EPT violation. */ + DBGFEVENT_EXIT_VMX_EPT_MISCONFIG, /**< Exit: VT-x EPT misconfiguration. */ + DBGFEVENT_EXIT_VMX_VAPIC_ACCESS, /**< Exit: VT-x Virtual APIC page access. */ + DBGFEVENT_EXIT_VMX_VAPIC_WRITE, /**< Exit: VT-x Virtual APIC write. */ + DBGFEVENT_EXIT_VMX_LAST /**< Exit: VT-x - Last. */ + = DBGFEVENT_EXIT_VMX_VAPIC_WRITE, + DBGFEVENT_EXIT_SVM_FIRST, /**< Exit: AMD-V - first */ + DBGFEVENT_EXIT_SVM_VMRUN /**< Exit: AMD-V VMRUN instruction. */ + = DBGFEVENT_EXIT_SVM_FIRST, + DBGFEVENT_EXIT_SVM_VMLOAD, /**< Exit: AMD-V VMLOAD instruction. */ + DBGFEVENT_EXIT_SVM_VMSAVE, /**< Exit: AMD-V VMSAVE instruction. */ + DBGFEVENT_EXIT_SVM_STGI, /**< Exit: AMD-V STGI instruction. */ + DBGFEVENT_EXIT_SVM_CLGI, /**< Exit: AMD-V CLGI instruction. */ + DBGFEVENT_EXIT_SVM_LAST /**< Exit: The last ADM-V VM exit event. */ + = DBGFEVENT_EXIT_SVM_CLGI, + DBGFEVENT_EXIT_LAST /**< Exit: The last VM exit event. */ + = DBGFEVENT_EXIT_SVM_LAST, + /** @} */ + + + /** @name Misc VT-x and AMD-V execution events. + * @{ */ + DBGFEVENT_VMX_SPLIT_LOCK, /**< VT-x: Split-lock \#AC triggered by host having detection enabled. */ + /** @} */ + + + /** Access to an unassigned I/O port. + * @todo not yet implemented. */ + DBGFEVENT_IOPORT_UNASSIGNED, + /** Access to an unused I/O port on a device. + * @todo not yet implemented. */ + DBGFEVENT_IOPORT_UNUSED, + /** Unassigned memory event. + * @todo not yet implemented. */ + DBGFEVENT_MEMORY_UNASSIGNED, + /** Attempt to write to unshadowed ROM. + * @todo not yet implemented. */ + DBGFEVENT_MEMORY_ROM_WRITE, + + /** Windows guest reported BSOD via hyperv MSRs. */ + DBGFEVENT_BSOD_MSR, + /** Windows guest reported BSOD via EFI variables. */ + DBGFEVENT_BSOD_EFI, + /** Windows guest reported BSOD via VMMDev. */ + DBGFEVENT_BSOD_VMMDEV, + + /** End of valid event values. */ + DBGFEVENT_END, + /** The usual 32-bit hack. */ + DBGFEVENT_32BIT_HACK = 0x7fffffff +} DBGFEVENTTYPE; +AssertCompile(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST == 0x1f); + +/** + * The context of an event. + */ +typedef enum DBGFEVENTCTX +{ + /** The usual invalid entry. */ + DBGFEVENTCTX_INVALID = 0, + /** Raw mode. */ + DBGFEVENTCTX_RAW, + /** Recompiled mode. */ + DBGFEVENTCTX_REM, + /** VMX / AVT mode. */ + DBGFEVENTCTX_HM, + /** Hypervisor context. */ + DBGFEVENTCTX_HYPER, + /** Other mode */ + DBGFEVENTCTX_OTHER, + + /** The usual 32-bit hack */ + DBGFEVENTCTX_32BIT_HACK = 0x7fffffff +} DBGFEVENTCTX; + +/** + * VMM Debug Event. + */ +typedef struct DBGFEVENT +{ + /** Type. */ + DBGFEVENTTYPE enmType; + /** Context */ + DBGFEVENTCTX enmCtx; + /** The vCPU/EMT which generated the event. */ + VMCPUID idCpu; + /** Reserved. */ + uint32_t uReserved; + /** Type specific data. */ + union + { + /** Fatal error details. */ + struct + { + /** The GC return code. */ + int rc; + } FatalError; + + /** Source location. */ + struct + { + /** File name. */ + R3PTRTYPE(const char *) pszFile; + /** Function name. */ + R3PTRTYPE(const char *) pszFunction; + /** Message. */ + R3PTRTYPE(const char *) pszMessage; + /** Line number. */ + unsigned uLine; + } Src; + + /** Assertion messages. */ + struct + { + /** The first message. */ + R3PTRTYPE(const char *) pszMsg1; + /** The second message. */ + R3PTRTYPE(const char *) pszMsg2; + } Assert; + + /** Breakpoint. */ + struct DBGFEVENTBP + { + /** The handle of the breakpoint which was hit. */ + DBGFBP hBp; + } Bp; + + /** Generic debug event. */ + struct DBGFEVENTGENERIC + { + /** Number of arguments. */ + uint8_t cArgs; + /** Alignment padding. */ + uint8_t uPadding[7]; + /** Arguments. */ + uint64_t auArgs[5]; + } Generic; + + /** Padding for ensuring that the structure is 8 byte aligned. */ + uint64_t au64Padding[6]; + } u; +} DBGFEVENT; +AssertCompileSizeAlignment(DBGFEVENT, 8); +AssertCompileSize(DBGFEVENT, 64); +/** Pointer to VMM Debug Event. */ +typedef DBGFEVENT *PDBGFEVENT; +/** Pointer to const VMM Debug Event. */ +typedef const DBGFEVENT *PCDBGFEVENT; + +#ifdef IN_RING3 /* The event API only works in ring-3. */ + +/** @def DBGFSTOP + * Stops the debugger raising a DBGFEVENT_DEVELOPER_STOP event. + * + * @returns VBox status code which must be propagated up to EM if not VINF_SUCCESS. + * @param pVM The cross context VM structure. + */ +# ifdef VBOX_STRICT +# define DBGFSTOP(pVM) DBGFR3EventSrc(pVM, DBGFEVENT_DEV_STOP, __FILE__, __LINE__, __PRETTY_FUNCTION__, NULL) +# else +# define DBGFSTOP(pVM) VINF_SUCCESS +# endif + +VMMR3_INT_DECL(int) DBGFR3Init(PVM pVM); +VMMR3_INT_DECL(int) DBGFR3Term(PVM pVM); +VMMR3DECL(void) DBGFR3TermUVM(PUVM pUVM); +VMMR3_INT_DECL(void) DBGFR3PowerOff(PVM pVM); +VMMR3_INT_DECL(void) DBGFR3Relocate(PVM pVM, RTGCINTPTR offDelta); + +VMMR3_INT_DECL(int) DBGFR3VMMForcedAction(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(VBOXSTRICTRC) DBGFR3EventHandlePending(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) DBGFR3Event(PVM pVM, DBGFEVENTTYPE enmEvent); +VMMR3DECL(int) DBGFR3EventSrc(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, + const char *pszFunction, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(6, 7); +VMMR3DECL(int) DBGFR3EventSrcV(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, + const char *pszFunction, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(6, 0); +VMMR3_INT_DECL(int) DBGFR3EventAssertion(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszMsg1, const char *pszMsg2); +VMMR3_INT_DECL(int) DBGFR3EventBreakpoint(PVM pVM, DBGFEVENTTYPE enmEvent); + +VMMR3_INT_DECL(int) DBGFR3PrgStep(PVMCPU pVCpu); + +VMMR3DECL(int) DBGFR3Attach(PUVM pUVM); +VMMR3DECL(int) DBGFR3Detach(PUVM pUVM); +VMMR3DECL(int) DBGFR3EventWait(PUVM pUVM, RTMSINTERVAL cMillies, PDBGFEVENT pEvent); +VMMR3DECL(int) DBGFR3Halt(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(bool) DBGFR3IsHalted(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) DBGFR3QueryWaitable(PUVM pUVM); +VMMR3DECL(int) DBGFR3Resume(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) DBGFR3InjectNMI(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) DBGFR3Step(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) DBGFR3StepEx(PUVM pUVM, VMCPUID idCpu, uint32_t fFlags, PCDBGFADDRESS pStopPcAddr, + PCDBGFADDRESS pStopPopAddr, RTGCUINTPTR cbStopPop, uint32_t cMaxSteps); + +/** @name DBGF_STEP_F_XXX - Flags for DBGFR3StepEx. + * + * @note The stop filters are not applied to the starting instruction. + * + * @{ */ +/** Step into CALL, INT, SYSCALL and SYSENTER instructions. */ +#define DBGF_STEP_F_INTO RT_BIT_32(0) +/** Step over CALL, INT, SYSCALL and SYSENTER instruction when considering + * what's "next". */ +#define DBGF_STEP_F_OVER RT_BIT_32(1) + +/** Stop on the next CALL, INT, SYSCALL, SYSENTER instruction. */ +#define DBGF_STEP_F_STOP_ON_CALL RT_BIT_32(8) +/** Stop on the next RET, IRET, SYSRET, SYSEXIT instruction. */ +#define DBGF_STEP_F_STOP_ON_RET RT_BIT_32(9) +/** Stop after the next RET, IRET, SYSRET, SYSEXIT instruction. */ +#define DBGF_STEP_F_STOP_AFTER_RET RT_BIT_32(10) +/** Stop on the given address. + * The comparison will be made using effective (flat) addresses. */ +#define DBGF_STEP_F_STOP_ON_ADDRESS RT_BIT_32(11) +/** Stop when the stack pointer pops to or past the given address. + * The comparison will be made using effective (flat) addresses. */ +#define DBGF_STEP_F_STOP_ON_STACK_POP RT_BIT_32(12) +/** Mask of stop filter flags. */ +#define DBGF_STEP_F_STOP_FILTER_MASK UINT32_C(0x00001f00) + +/** Mask of valid flags. */ +#define DBGF_STEP_F_VALID_MASK UINT32_C(0x00001f03) +/** @} */ + +/** + * Event configuration array element, see DBGFR3EventConfigEx. + */ +typedef struct DBGFEVENTCONFIG +{ + /** The event to configure */ + DBGFEVENTTYPE enmType; + /** The new state. */ + bool fEnabled; + /** Unused. */ + uint8_t abUnused[3]; +} DBGFEVENTCONFIG; +/** Pointer to an event config. */ +typedef DBGFEVENTCONFIG *PDBGFEVENTCONFIG; +/** Pointer to a const event config. */ +typedef const DBGFEVENTCONFIG *PCDBGFEVENTCONFIG; + +VMMR3DECL(int) DBGFR3EventConfigEx(PUVM pUVM, PCDBGFEVENTCONFIG paConfigs, size_t cConfigs); +VMMR3DECL(int) DBGFR3EventConfig(PUVM pUVM, DBGFEVENTTYPE enmEvent, bool fEnabled); +VMMR3DECL(bool) DBGFR3EventIsEnabled(PUVM pUVM, DBGFEVENTTYPE enmEvent); +VMMR3DECL(int) DBGFR3EventQuery(PUVM pUVM, PDBGFEVENTCONFIG paConfigs, size_t cConfigs); + +/** @name DBGFINTERRUPTSTATE_XXX - interrupt break state. + * @{ */ +#define DBGFINTERRUPTSTATE_DISABLED 0 +#define DBGFINTERRUPTSTATE_ENABLED 1 +#define DBGFINTERRUPTSTATE_DONT_TOUCH 2 +/** @} */ + +/** + * Interrupt break state configuration entry. + */ +typedef struct DBGFINTERRUPTCONFIG +{ + /** The interrupt number. */ + uint8_t iInterrupt; + /** The hardware interrupt state (DBGFINTERRUPTSTATE_XXX). */ + uint8_t enmHardState; + /** The software interrupt state (DBGFINTERRUPTSTATE_XXX). */ + uint8_t enmSoftState; +} DBGFINTERRUPTCONFIG; +/** Pointer to an interrupt break state config entyr. */ +typedef DBGFINTERRUPTCONFIG *PDBGFINTERRUPTCONFIG; +/** Pointer to a const interrupt break state config entyr. */ +typedef DBGFINTERRUPTCONFIG const *PCDBGFINTERRUPTCONFIG; + +VMMR3DECL(int) DBGFR3InterruptConfigEx(PUVM pUVM, PCDBGFINTERRUPTCONFIG paConfigs, size_t cConfigs); +VMMR3DECL(int) DBGFR3InterruptHardwareConfig(PUVM pUVM, uint8_t iInterrupt, bool fEnabled); +VMMR3DECL(int) DBGFR3InterruptSoftwareConfig(PUVM pUVM, uint8_t iInterrupt, bool fEnabled); +VMMR3DECL(int) DBGFR3InterruptHardwareIsEnabled(PUVM pUVM, uint8_t iInterrupt); +VMMR3DECL(int) DBGFR3InterruptSoftwareIsEnabled(PUVM pUVM, uint8_t iInterrupt); + +#endif /* IN_RING3 */ + +/** @def DBGF_IS_EVENT_ENABLED + * Checks if a selectable debug event is enabled or not (fast). + * + * @returns true/false. + * @param a_pVM Pointer to the cross context VM structure. + * @param a_enmEvent The selectable event to check. + * @remarks Only for use internally in the VMM. Use DBGFR3EventIsEnabled elsewhere. + */ +#if defined(VBOX_STRICT) && defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define DBGF_IS_EVENT_ENABLED(a_pVM, a_enmEvent) \ + ([](PVM a_pLambdaVM, DBGFEVENTTYPE a_enmLambdaEvent) -> bool { \ + Assert( a_enmLambdaEvent >= DBGFEVENT_FIRST_SELECTABLE \ + || a_enmLambdaEvent == DBGFEVENT_INTERRUPT_HARDWARE \ + || a_enmLambdaEvent == DBGFEVENT_INTERRUPT_SOFTWARE); \ + Assert(a_enmLambdaEvent < DBGFEVENT_END); \ + return ASMBitTest(&a_pLambdaVM->dbgf.ro.bmSelectedEvents, a_enmLambdaEvent); \ + }(a_pVM, a_enmEvent)) +#elif defined(VBOX_STRICT) && defined(__GNUC__) +# define DBGF_IS_EVENT_ENABLED(a_pVM, a_enmEvent) \ + __extension__ ({ \ + Assert( (a_enmEvent) >= DBGFEVENT_FIRST_SELECTABLE \ + || (a_enmEvent) == DBGFEVENT_INTERRUPT_HARDWARE \ + || (a_enmEvent) == DBGFEVENT_INTERRUPT_SOFTWARE); \ + Assert((a_enmEvent) < DBGFEVENT_END); \ + ASMBitTest(&(a_pVM)->dbgf.ro.bmSelectedEvents, (a_enmEvent)); \ + }) +#else +# define DBGF_IS_EVENT_ENABLED(a_pVM, a_enmEvent) \ + ASMBitTest(&(a_pVM)->dbgf.ro.bmSelectedEvents, (a_enmEvent)) +#endif + + +/** @def DBGF_IS_HARDWARE_INT_ENABLED + * Checks if hardware interrupt interception is enabled or not for an interrupt. + * + * @returns true/false. + * @param a_pVM Pointer to the cross context VM structure. + * @param a_iInterrupt Interrupt to check. + * @remarks Only for use internally in the VMM. Use + * DBGFR3InterruptHardwareIsEnabled elsewhere. + */ +#define DBGF_IS_HARDWARE_INT_ENABLED(a_pVM, a_iInterrupt) \ + ASMBitTest(&(a_pVM)->dbgf.ro.bmHardIntBreakpoints, (uint8_t)(a_iInterrupt)) + +/** @def DBGF_IS_SOFTWARE_INT_ENABLED + * Checks if software interrupt interception is enabled or not for an interrupt. + * + * @returns true/false. + * @param a_pVM Pointer to the cross context VM structure. + * @param a_iInterrupt Interrupt to check. + * @remarks Only for use internally in the VMM. Use + * DBGFR3InterruptSoftwareIsEnabled elsewhere. + */ +#define DBGF_IS_SOFTWARE_INT_ENABLED(a_pVM, a_iInterrupt) \ + ASMBitTest(&(a_pVM)->dbgf.ro.bmSoftIntBreakpoints, (uint8_t)(a_iInterrupt)) + + + +/** Breakpoint type. */ +typedef enum DBGFBPTYPE +{ + /** Invalid breakpoint type. */ + DBGFBPTYPE_INVALID = 0, + /** Debug register. */ + DBGFBPTYPE_REG, + /** INT 3 instruction. */ + DBGFBPTYPE_INT3, + /** Port I/O breakpoint. */ + DBGFBPTYPE_PORT_IO, + /** Memory mapped I/O breakpoint. */ + DBGFBPTYPE_MMIO, + /** ensure 32-bit size. */ + DBGFBPTYPE_32BIT_HACK = 0x7fffffff +} DBGFBPTYPE; + + +/** @name DBGFBPIOACCESS_XXX - I/O (port + mmio) access types. + * @{ */ +/** Byte sized read accesses. */ +#define DBGFBPIOACCESS_READ_BYTE UINT32_C(0x00000001) +/** Word sized accesses. */ +#define DBGFBPIOACCESS_READ_WORD UINT32_C(0x00000002) +/** Double word sized accesses. */ +#define DBGFBPIOACCESS_READ_DWORD UINT32_C(0x00000004) +/** Quad word sized accesses - not available for I/O ports. */ +#define DBGFBPIOACCESS_READ_QWORD UINT32_C(0x00000008) +/** Other sized accesses - not available for I/O ports. */ +#define DBGFBPIOACCESS_READ_OTHER UINT32_C(0x00000010) +/** Read mask. */ +#define DBGFBPIOACCESS_READ_MASK UINT32_C(0x0000001f) + +/** Byte sized write accesses. */ +#define DBGFBPIOACCESS_WRITE_BYTE UINT32_C(0x00000100) +/** Word sized write accesses. */ +#define DBGFBPIOACCESS_WRITE_WORD UINT32_C(0x00000200) +/** Double word sized write accesses. */ +#define DBGFBPIOACCESS_WRITE_DWORD UINT32_C(0x00000400) +/** Quad word sized write accesses - not available for I/O ports. */ +#define DBGFBPIOACCESS_WRITE_QWORD UINT32_C(0x00000800) +/** Other sized write accesses - not available for I/O ports. */ +#define DBGFBPIOACCESS_WRITE_OTHER UINT32_C(0x00001000) +/** Write mask. */ +#define DBGFBPIOACCESS_WRITE_MASK UINT32_C(0x00001f00) + +/** All kind of access (read, write, all sizes). */ +#define DBGFBPIOACCESS_ALL UINT32_C(0x00001f1f) +/** All kind of access for MMIO (read, write, all sizes). */ +#define DBGFBPIOACCESS_ALL_MMIO DBGFBPIOACCESS_ALL +/** All kind of access (read, write, all sizes). */ +#define DBGFBPIOACCESS_ALL_PORT_IO UINT32_C(0x00000303) + +/** The acceptable mask for I/O ports. */ +#define DBGFBPIOACCESS_VALID_MASK_PORT_IO UINT32_C(0x00000303) +/** The acceptable mask for MMIO. */ +#define DBGFBPIOACCESS_VALID_MASK_MMIO UINT32_C(0x00001f1f) +/** @} */ + +/** + * The visible breakpoint state (read-only). + */ +typedef struct DBGFBPPUB +{ + /** The number of breakpoint hits. */ + uint64_t cHits; + /** The hit number which starts to trigger the breakpoint. */ + uint64_t iHitTrigger; + /** The hit number which stops triggering the breakpoint (disables it). + * Use ~(uint64_t)0 if it should never stop. */ + uint64_t iHitDisable; + /** The breakpoint owner handle (a nil owner defers the breakpoint to the + * debugger). */ + DBGFBPOWNER hOwner; + /** Breakpoint type stored as a 16bit integer to stay within size limits. */ + uint16_t u16Type; + /** Breakpoint flags. */ + uint16_t fFlags; + + /** Union of type specific data. */ + union + { + /** The flat GC address breakpoint address for REG and INT3 breakpoints. */ + RTGCUINTPTR GCPtr; + + /** Debug register data. */ + struct DBGFBPREG + { + /** The flat GC address of the breakpoint. */ + RTGCUINTPTR GCPtr; + /** The debug register number. */ + uint8_t iReg; + /** The access type (one of the X86_DR7_RW_* value). */ + uint8_t fType; + /** The access size. */ + uint8_t cb; + } Reg; + + /** INT3 breakpoint data. */ + struct DBGFBPINT3 + { + /** The flat GC address of the breakpoint. */ + RTGCUINTPTR GCPtr; + /** The physical address of the breakpoint. */ + RTGCPHYS PhysAddr; + /** The byte value we replaced by the INT 3 instruction. */ + uint8_t bOrg; + } Int3; + + /** I/O port breakpoint data. */ + struct DBGFBPPORTIO + { + /** The first port. */ + RTIOPORT uPort; + /** The number of ports. */ + RTIOPORT cPorts; + /** Valid DBGFBPIOACCESS_XXX selection, max DWORD size. */ + uint32_t fAccess; + } PortIo; + + /** Memory mapped I/O breakpoint data. */ + struct DBGFBPMMIO + { + /** The first MMIO address. */ + RTGCPHYS PhysAddr; + /** The size of the MMIO range in bytes. */ + uint32_t cb; + /** Valid DBGFBPIOACCESS_XXX selection, max QWORD size. */ + uint32_t fAccess; + } Mmio; + + /** Padding to the anticipated size. */ + uint64_t u64Padding[3]; + } u; +} DBGFBPPUB; +AssertCompileSize(DBGFBPPUB, 64 - 8); +AssertCompileMembersAtSameOffset(DBGFBPPUB, u.GCPtr, DBGFBPPUB, u.Reg.GCPtr); +AssertCompileMembersAtSameOffset(DBGFBPPUB, u.GCPtr, DBGFBPPUB, u.Int3.GCPtr); + +/** Pointer to the visible breakpoint state. */ +typedef DBGFBPPUB *PDBGFBPPUB; +/** Pointer to a const visible breakpoint state. */ +typedef const DBGFBPPUB *PCDBGFBPPUB; + +/** Sets the DBGFPUB::u16Type member. */ +#define DBGF_BP_PUB_MAKE_TYPE(a_enmType) ((uint16_t)(a_enmType)) +/** Returns the type of the DBGFPUB::u16Type member. */ +#define DBGF_BP_PUB_GET_TYPE(a_pBp) ((DBGFBPTYPE)((a_pBp)->u16Type)) +/** Returns the enabled status of DBGFPUB::fFlags member. */ +#define DBGF_BP_PUB_IS_ENABLED(a_pBp) RT_BOOL((a_pBp)->fFlags & DBGF_BP_F_ENABLED) +/** Returns whether DBGF_BP_F_HIT_EXEC_BEFORE is set for DBGFPUB::fFlags. */ +#define DBGF_BP_PUB_IS_EXEC_BEFORE(a_pBp) RT_BOOL((a_pBp)->fFlags & DBGF_BP_F_HIT_EXEC_BEFORE) +/** Returns whether DBGF_BP_F_HIT_EXEC_AFTER is set for DBGFPUB::fFlags. */ +#define DBGF_BP_PUB_IS_EXEC_AFTER(a_pBp) RT_BOOL((a_pBp)->fFlags & DBGF_BP_F_HIT_EXEC_AFTER) + + +/** @name Possible DBGFBPPUB::fFlags flags. + * @{ */ +/** Default flags, breakpoint is enabled and hits before the instruction is executed. */ +#define DBGF_BP_F_DEFAULT (DBGF_BP_F_ENABLED | DBGF_BP_F_HIT_EXEC_BEFORE) +/** Flag whether the breakpoint is enabled currently. */ +#define DBGF_BP_F_ENABLED RT_BIT(0) +/** Flag indicating whether the action assoicated with the breakpoint should be carried out + * before the instruction causing the breakpoint to hit was executed. */ +#define DBGF_BP_F_HIT_EXEC_BEFORE RT_BIT(1) +/** Flag indicating whether the action assoicated with the breakpoint should be carried out + * after the instruction causing the breakpoint to hit was executed. */ +#define DBGF_BP_F_HIT_EXEC_AFTER RT_BIT(2) +/** The acceptable flags mask. */ +#define DBGF_BP_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ + + +/** + * Breakpoint hit handler. + * + * @returns Strict VBox status code. + * @retval VINF_SUCCESS if the breakpoint was handled and guest execution can resume. + * @retval VINF_DBGF_BP_HALT if guest execution should be stopped and the debugger should be invoked. + * @retval VINF_DBGF_R3_BP_OWNER_DEFER return to ring-3 and invoke the owner callback there again. + * + * @param pVM The cross-context VM structure pointer. + * @param idCpu ID of the vCPU triggering the breakpoint. + * @param pvUserBp User argument of the set breakpoint. + * @param hBp The breakpoint handle. + * @param pBpPub Pointer to the readonly public state of the breakpoint. + * @param fFlags Flags indicating when the handler was called (DBGF_BP_F_HIT_EXEC_BEFORE vs DBGF_BP_F_HIT_EXEC_AFTER). + * + * @remarks The handler is called on the EMT of vCPU triggering the breakpoint and no locks are held. + * @remarks Any status code returned other than the ones mentioned will send the VM straight into a + * guru meditation. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNDBGFBPHIT,(PVM pVM, VMCPUID idCpu, void *pvUserBp, DBGFBP hBp, PCDBGFBPPUB pBpPub, + uint16_t fFlags)); +/** Pointer to a FNDBGFBPHIT(). */ +typedef FNDBGFBPHIT *PFNDBGFBPHIT; + + +/** + * I/O breakpoint hit handler. + * + * @returns Strict VBox status code. + * @retval VINF_SUCCESS if the breakpoint was handled and guest execution can resume. + * @retval VINF_DBGF_BP_HALT if guest execution should be stopped and the debugger should be invoked. + * @retval VINF_DBGF_R3_BP_OWNER_DEFER return to ring-3 and invoke the owner callback there again. + * + * @param pVM The cross-context VM structure pointer. + * @param idCpu ID of the vCPU triggering the breakpoint. + * @param pvUserBp User argument of the set breakpoint. + * @param hBp The breakpoint handle. + * @param pBpPub Pointer to the readonly public state of the breakpoint. + * @param fFlags Flags indicating when the handler was called (DBGF_BP_F_HIT_EXEC_BEFORE vs DBGF_BP_F_HIT_EXEC_AFTER). + * @param fAccess Access flags, see DBGFBPIOACCESS_XXX. + * @param uAddr The address of the access, for port I/O this will hold the port number. + * @param uValue The value read or written (the value for reads is only valid when DBGF_BP_F_HIT_EXEC_AFTER is set). + * + * @remarks The handler is called on the EMT of vCPU triggering the breakpoint and no locks are held. + * @remarks Any status code returned other than the ones mentioned will send the VM straight into a + * guru meditation. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNDBGFBPIOHIT,(PVM pVM, VMCPUID idCpu, void *pvUserBp, DBGFBP hBp, PCDBGFBPPUB pBpPub, + uint16_t fFlags, uint32_t fAccess, uint64_t uAddr, uint64_t uValue)); +/** Pointer to a FNDBGFBPIOHIT(). */ +typedef FNDBGFBPIOHIT *PFNDBGFBPIOHIT; + + +#ifdef IN_RING3 +/** @defgroup grp_dbgf_bp_r3 The DBGF Breakpoint Host Context Ring-3 API + * @{ */ +VMMR3DECL(int) DBGFR3BpOwnerCreate(PUVM pUVM, PFNDBGFBPHIT pfnBpHit, PFNDBGFBPIOHIT pfnBpIoHit, PDBGFBPOWNER phBpOwner); +VMMR3DECL(int) DBGFR3BpOwnerDestroy(PUVM pUVM, DBGFBPOWNER hBpOwner); + +VMMR3DECL(int) DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, + uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetInt3Ex(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, + VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, uint16_t fFlags, + uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, + uint64_t iHitDisable, uint8_t fType, uint8_t cb, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetRegEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, + PCDBGFADDRESS pAddress, uint16_t fFlags, + uint64_t iHitTrigger, uint64_t iHitDisable, + uint8_t fType, uint8_t cb, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, + uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess, + uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetPortIoEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, + RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess, + uint32_t fFlags, uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetMmio(PUVM pUVM, RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess, + uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetMmioEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, + RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess, + uint32_t fFlags, uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpClear(PUVM pUVM, DBGFBP hBp); +VMMR3DECL(int) DBGFR3BpEnable(PUVM pUVM, DBGFBP hBp); +VMMR3DECL(int) DBGFR3BpDisable(PUVM pUVM, DBGFBP hBp); + +/** + * Breakpoint enumeration callback function. + * + * @returns VBox status code. + * The enumeration stops on failure status and VINF_CALLBACK_RETURN. + * @param pUVM The user mode VM handle. + * @param pvUser The user argument. + * @param hBp The breakpoint handle. + * @param pBpPub Pointer to the public breakpoint information. (readonly) + */ +typedef DECLCALLBACKTYPE(int, FNDBGFBPENUM,(PUVM pUVM, void *pvUser, DBGFBP hBp, PCDBGFBPPUB pBpPub)); +/** Pointer to a breakpoint enumeration callback function. */ +typedef FNDBGFBPENUM *PFNDBGFBPENUM; + +VMMR3DECL(int) DBGFR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser); + +VMMR3_INT_DECL(int) DBGFR3BpHit(PVM pVM, PVMCPU pVCpu); +/** @} */ +#endif /* !IN_RING3 */ + + +#if defined(IN_RING0) || defined(DOXYGEN_RUNNING) +/** @defgroup grp_dbgf_bp_r0 The DBGF Breakpoint Host Context Ring-0 API + * @{ */ +VMMR0_INT_DECL(int) DBGFR0BpOwnerSetUpContext(PGVM pGVM, DBGFBPOWNER hBpOwner, PFNDBGFBPHIT pfnBpHit, PFNDBGFBPIOHIT pfnBpIoHit); +VMMR0_INT_DECL(int) DBGFR0BpOwnerDestroyContext(PGVM pGVM, DBGFBPOWNER hBpOwner); + +VMMR0_INT_DECL(int) DBGFR0BpSetUpContext(PGVM pGVM, DBGFBP hBp, void *pvUser); +VMMR0_INT_DECL(int) DBGFR0BpDestroyContext(PGVM pGVM, DBGFBP hBp); +/** @} */ +#endif /* IN_RING0 || DOXYGEN_RUNNING */ + +VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR7(PVM pVM); +VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR0(PVM pVM); +VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR1(PVM pVM); +VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR2(PVM pVM); +VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR3(PVM pVM); +VMM_INT_DECL(bool) DBGFBpIsHwArmed(PVM pVM); +VMM_INT_DECL(bool) DBGFBpIsHwIoArmed(PVM pVM); +VMM_INT_DECL(bool) DBGFBpIsInt3Armed(PVM pVM); +VMM_INT_DECL(bool) DBGFIsStepping(PVMCPU pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) DBGFBpCheckInstruction(PVMCC pVM, PVMCPUCC pVCpu, RTGCPTR GCPtrPC); +VMM_INT_DECL(VBOXSTRICTRC) DBGFBpCheckIo(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, RTIOPORT uIoPort, uint8_t cbValue); +VMM_INT_DECL(uint32_t) DBGFBpCheckIo2(PVMCC pVM, PVMCPUCC pVCpu, RTIOPORT uIoPort, uint8_t cbValue); +VMM_INT_DECL(VBOXSTRICTRC) DBGFBpCheckPortIo(PVMCC pVM, PVMCPU pVCpu, RTIOPORT uIoPort, + uint32_t fAccess, uint32_t uValue, bool fBefore); +VMM_INT_DECL(VBOXSTRICTRC) DBGFEventGenericWithArgs(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmEvent, DBGFEVENTCTX enmCtx, + unsigned cArgs, ...); +VMM_INT_DECL(int) DBGFTrap01Handler(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, RTGCUINTREG uDr6, bool fAltStepping); +VMM_INT_DECL(VBOXSTRICTRC) DBGFTrap03Handler(PVMCC pVM, PVMCPUCC pVCpu, PCPUMCTX pCtx); + + +#ifdef IN_RING3 /* The CPU mode API only works in ring-3. */ +VMMR3DECL(CPUMMODE) DBGFR3CpuGetMode(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(VMCPUID) DBGFR3CpuGetCount(PUVM pUVM); +VMMR3DECL(bool) DBGFR3CpuIsIn64BitCode(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(bool) DBGFR3CpuIsInV86Code(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(const char *) DBGFR3CpuGetState(PUVM pUVM, VMCPUID idCpu); +#endif + + + +#ifdef IN_RING3 /* The info callbacks API only works in ring-3. */ + +struct RTGETOPTSTATE; +union RTGETOPTUNION; + +/** + * Info helper callback structure. + */ +typedef struct DBGFINFOHLP +{ + /** + * Print formatted string. + * + * @param pHlp Pointer to this structure. + * @param pszFormat The format string. + * @param ... Arguments. + */ + DECLCALLBACKMEMBER(void, pfnPrintf,(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(2, 3); + + /** + * Print formatted string. + * + * @param pHlp Pointer to this structure. + * @param pszFormat The format string. + * @param args Argument list. + */ + DECLCALLBACKMEMBER(void, pfnPrintfV,(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)) RT_IPRT_FORMAT_ATTR(2, 0); + + /** + * Report getopt parsing trouble + * + * @param pHlp Pointer to this structure. + * @param rc The RTGetOpt return value. + * @param pValueUnion The value union. + * @param pState The getopt state. + */ + DECLCALLBACKMEMBER(void, pfnGetOptError,(PCDBGFINFOHLP pHlp, int rc, union RTGETOPTUNION *pValueUnion, + struct RTGETOPTSTATE *pState)); +} DBGFINFOHLP; + + +/** + * Info handler, device version. + * + * @param pDevIns The device instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param pszArgs Argument string. Optional and specific to the handler. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFHANDLERDEV,(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)); +/** Pointer to a FNDBGFHANDLERDEV function. */ +typedef FNDBGFHANDLERDEV *PFNDBGFHANDLERDEV; + +/** + * Info handler, driver version. + * + * @param pDrvIns The driver instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param pszArgs Argument string. Optional and specific to the handler. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFHANDLERDRV,(PPDMDRVINS pDrvIns, PCDBGFINFOHLP pHlp, const char *pszArgs)); +/** Pointer to a FNDBGFHANDLERDRV function. */ +typedef FNDBGFHANDLERDRV *PFNDBGFHANDLERDRV; + +/** + * Info handler, internal version. + * + * @param pVM The cross context VM structure. + * @param pHlp Callback functions for doing output. + * @param pszArgs Argument string. Optional and specific to the handler. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFHANDLERINT,(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)); +/** Pointer to a FNDBGFHANDLERINT function. */ +typedef FNDBGFHANDLERINT *PFNDBGFHANDLERINT; + +/** + * Info handler, external version. + * + * @param pvUser User argument. + * @param pHlp Callback functions for doing output. + * @param pszArgs Argument string. Optional and specific to the handler. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFHANDLEREXT,(void *pvUser, PCDBGFINFOHLP pHlp, const char *pszArgs)); +/** Pointer to a FNDBGFHANDLEREXT function. */ +typedef FNDBGFHANDLEREXT *PFNDBGFHANDLEREXT; + +/** + * Info handler, device version with argv. + * + * @param pDevIns The device instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param cArgs Number of arguments. + * @param papszArgs Argument vector. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFINFOARGVDEV,(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)); +/** Pointer to a FNDBGFINFOARGVDEV function. */ +typedef FNDBGFINFOARGVDEV *PFNDBGFINFOARGVDEV; + +/** + * Info handler, USB device version with argv. + * + * @param pUsbIns The USB device instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param cArgs Number of arguments. + * @param papszArgs Argument vector. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFINFOARGVUSB,(PPDMUSBINS pUsbIns, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)); +/** Pointer to a FNDBGFINFOARGVUSB function. */ +typedef FNDBGFINFOARGVUSB *PFNDBGFINFOARGVUSB; + +/** + * Info handler, driver version with argv. + * + * @param pDrvIns The driver instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param cArgs Number of arguments. + * @param papszArgs Argument vector. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFINFOARGVDRV,(PPDMDRVINS pDrvIns, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)); +/** Pointer to a FNDBGFINFOARGVDRV function. */ +typedef FNDBGFINFOARGVDRV *PFNDBGFINFOARGVDRV; + +/** + * Info handler, internal version with argv. + * + * @param pVM The cross context VM structure. + * @param pHlp Callback functions for doing output. + * @param cArgs Number of arguments. + * @param papszArgs Argument vector. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFINFOARGVINT,(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)); +/** Pointer to a FNDBGFINFOARGVINT function. */ +typedef FNDBGFINFOARGVINT *PFNDBGFINFOARGVINT; + +/** + * Info handler, external version with argv. + * + * @param pvUser User argument. + * @param pHlp Callback functions for doing output. + * @param cArgs Number of arguments. + * @param papszArgs Argument vector. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFINFOARGVEXT,(void *pvUser, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)); +/** Pointer to a FNDBGFINFOARGVEXT function. */ +typedef FNDBGFINFOARGVEXT *PFNDBGFINFOARGVEXT; + + +/** @name Flags for the info registration functions. + * @{ */ +/** The handler must run on the EMT. */ +#define DBGFINFO_FLAGS_RUN_ON_EMT RT_BIT(0) +/** Call on all EMTs when a specific isn't specified. */ +#define DBGFINFO_FLAGS_ALL_EMTS RT_BIT(1) +/** @} */ + +VMMR3_INT_DECL(int) DBGFR3InfoRegisterDevice(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDEV pfnHandler, PPDMDEVINS pDevIns); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterDriver(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler, PPDMDRVINS pDrvIns); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterInternal(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERINT pfnHandler); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterInternalEx(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERINT pfnHandler, uint32_t fFlags); +VMMR3DECL(int) DBGFR3InfoRegisterExternal(PUVM pUVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLEREXT pfnHandler, void *pvUser); + +VMMR3_INT_DECL(int) DBGFR3InfoRegisterDeviceArgv(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDEV pfnHandler, PPDMDEVINS pDevIns); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterDriverArgv(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDRV pfnHandler, PPDMDRVINS pDrvIns); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterUsbArgv(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVUSB pfnHandler, PPDMUSBINS pUsbIns); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterInternalArgv(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVINT pfnHandler, uint32_t fFlags); +VMMR3DECL(int) DBGFR3InfoRegisterExternalArgv(PUVM pUVM, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVEXT pfnHandler, void *pvUser); + +VMMR3_INT_DECL(int) DBGFR3InfoDeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName); +VMMR3_INT_DECL(int) DBGFR3InfoDeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName); +VMMR3_INT_DECL(int) DBGFR3InfoDeregisterUsb(PVM pVM, PPDMUSBINS pDrvIns, const char *pszName); +VMMR3_INT_DECL(int) DBGFR3InfoDeregisterInternal(PVM pVM, const char *pszName); +VMMR3DECL(int) DBGFR3InfoDeregisterExternal(PUVM pUVM, const char *pszName); + +VMMR3DECL(int) DBGFR3Info(PUVM pUVM, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp); +VMMR3DECL(int) DBGFR3InfoEx(PUVM pUVM, VMCPUID idCpu, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp); +VMMR3DECL(int) DBGFR3InfoLogRel(PUVM pUVM, const char *pszName, const char *pszArgs); +VMMR3DECL(int) DBGFR3InfoStdErr(PUVM pUVM, const char *pszName, const char *pszArgs); +VMMR3_INT_DECL(int) DBGFR3InfoMulti(PVM pVM, const char *pszIncludePat, const char *pszExcludePat, + const char *pszSepFmt, PCDBGFINFOHLP pHlp); + +/** @def DBGFR3_INFO_LOG + * Display a piece of info writing to the log if enabled. + * + * This is for execution on EMTs and will only show the items on the calling + * EMT. This is to avoid deadlocking against other CPUs if a rendezvous is + * initiated in parallel to this call. (Besides, nobody really wants or need + * info for the other EMTs when using this macro.) + * + * @param a_pVM The shared VM handle. + * @param a_pVCpu The cross context per CPU structure of the calling EMT. + * @param a_pszName The identifier of the info to display. + * @param a_pszArgs Arguments to the info handler. + */ +#ifdef LOG_ENABLED +# define DBGFR3_INFO_LOG(a_pVM, a_pVCpu, a_pszName, a_pszArgs) \ + do { \ + if (LogIsEnabled()) \ + DBGFR3InfoEx((a_pVM)->pUVM, (a_pVCpu)->idCpu, a_pszName, a_pszArgs, NULL); \ + } while (0) +#else +# define DBGFR3_INFO_LOG(a_pVM, a_pVCpu, a_pszName, a_pszArgs) do { } while (0) +#endif + +/** @def DBGFR3_INFO_LOG_SAFE + * Display a piece of info (rendezvous safe) writing to the log if enabled. + * + * @param a_pVM The shared VM handle. + * @param a_pszName The identifier of the info to display. + * @param a_pszArgs Arguments to the info handler. + * + * @remarks Use DBGFR3_INFO_LOG where ever possible! + */ +#ifdef LOG_ENABLED +# define DBGFR3_INFO_LOG_SAFE(a_pVM, a_pszName, a_pszArgs) \ + do { \ + if (LogIsEnabled()) \ + DBGFR3Info((a_pVM)->pUVM, a_pszName, a_pszArgs, NULL); \ + } while (0) +#else +# define DBGFR3_INFO_LOG_SAFE(a_pVM, a_pszName, a_pszArgs) do { } while (0) +#endif + +/** + * Enumeration callback for use with DBGFR3InfoEnum. + * + * @returns VBox status code. + * A status code indicating failure will end the enumeration + * and DBGFR3InfoEnum will return with that status code. + * @param pUVM The user mode VM handle. + * @param pszName Info identifier name. + * @param pszDesc The description. + * @param pvUser User parameter. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFINFOENUM,(PUVM pUVM, const char *pszName, const char *pszDesc, void *pvUser)); +/** Pointer to a FNDBGFINFOENUM function. */ +typedef FNDBGFINFOENUM *PFNDBGFINFOENUM; + +VMMR3DECL(int) DBGFR3InfoEnum(PUVM pUVM, PFNDBGFINFOENUM pfnCallback, void *pvUser); +VMMR3DECL(PCDBGFINFOHLP) DBGFR3InfoLogHlp(void); +VMMR3DECL(PCDBGFINFOHLP) DBGFR3InfoLogRelHlp(void); +VMMR3DECL(void) DBGFR3InfoGenericGetOptError(PCDBGFINFOHLP pHlp, int rc, union RTGETOPTUNION *pValueUnion, + struct RTGETOPTSTATE *pState); + +#endif /* IN_RING3 */ + + +#ifdef IN_RING3 /* The log contrl API only works in ring-3. */ +VMMR3DECL(int) DBGFR3LogModifyGroups(PUVM pUVM, const char *pszGroupSettings); +VMMR3DECL(int) DBGFR3LogModifyFlags(PUVM pUVM, const char *pszFlagSettings); +VMMR3DECL(int) DBGFR3LogModifyDestinations(PUVM pUVM, const char *pszDestSettings); +#endif /* IN_RING3 */ + +#ifdef IN_RING3 /* The debug information management APIs only works in ring-3. */ + +/** Max length (including '\\0') of a symbol name. */ +#define DBGF_SYMBOL_NAME_LENGTH 512 + +/** + * Debug symbol. + */ +typedef struct DBGFSYMBOL +{ + /** Symbol value (address). */ + RTGCUINTPTR Value; + /** Symbol size. */ + uint32_t cb; + /** Symbol Flags. (reserved). */ + uint32_t fFlags; + /** Symbol name. */ + char szName[DBGF_SYMBOL_NAME_LENGTH]; +} DBGFSYMBOL; +/** Pointer to debug symbol. */ +typedef DBGFSYMBOL *PDBGFSYMBOL; +/** Pointer to const debug symbol. */ +typedef const DBGFSYMBOL *PCDBGFSYMBOL; + +/** + * Debug line number information. + */ +typedef struct DBGFLINE +{ + /** Address. */ + RTGCUINTPTR Address; + /** Line number. */ + uint32_t uLineNo; + /** Filename. */ + char szFilename[260]; +} DBGFLINE; +/** Pointer to debug line number. */ +typedef DBGFLINE *PDBGFLINE; +/** Pointer to const debug line number. */ +typedef const DBGFLINE *PCDBGFLINE; + +/** @name Address spaces aliases. + * @{ */ +/** The guest global address space. */ +#define DBGF_AS_GLOBAL ((RTDBGAS)-1) +/** The guest kernel address space. + * This is usually resolves to the same as DBGF_AS_GLOBAL. */ +#define DBGF_AS_KERNEL ((RTDBGAS)-2) +/** The physical address space. */ +#define DBGF_AS_PHYS ((RTDBGAS)-3) +/** Raw-mode context. */ +#define DBGF_AS_RC ((RTDBGAS)-4) +/** Ring-0 context. */ +#define DBGF_AS_R0 ((RTDBGAS)-5) +/** Raw-mode context and then global guest context. + * When used for looking up information, it works as if the call was first made + * with DBGF_AS_RC and then on failure with DBGF_AS_GLOBAL. When called for + * making address space changes, it works as if DBGF_AS_RC was used. */ +#define DBGF_AS_RC_AND_GC_GLOBAL ((RTDBGAS)-6) + +/** The first special one. */ +#define DBGF_AS_FIRST DBGF_AS_RC_AND_GC_GLOBAL +/** The last special one. */ +#define DBGF_AS_LAST DBGF_AS_GLOBAL +#endif +/** The number of special address space handles. */ +#define DBGF_AS_COUNT (6U) +#ifdef IN_RING3 +/** Converts an alias handle to an array index. */ +#define DBGF_AS_ALIAS_2_INDEX(hAlias) \ + ( (uintptr_t)(hAlias) - (uintptr_t)DBGF_AS_FIRST ) +/** Predicat macro that check if the specified handle is an alias. */ +#define DBGF_AS_IS_ALIAS(hAlias) \ + ( DBGF_AS_ALIAS_2_INDEX(hAlias) < DBGF_AS_COUNT ) +/** Predicat macro that check if the specified alias is a fixed one or not. */ +#define DBGF_AS_IS_FIXED_ALIAS(hAlias) \ + ( DBGF_AS_ALIAS_2_INDEX(hAlias) < (uintptr_t)DBGF_AS_PHYS - (uintptr_t)DBGF_AS_FIRST + 1U ) + +/** @} */ + +VMMR3DECL(RTDBGCFG) DBGFR3AsGetConfig(PUVM pUVM); + +VMMR3DECL(int) DBGFR3AsAdd(PUVM pUVM, RTDBGAS hDbgAs, RTPROCESS ProcId); +VMMR3DECL(int) DBGFR3AsDelete(PUVM pUVM, RTDBGAS hDbgAs); +VMMR3DECL(int) DBGFR3AsSetAlias(PUVM pUVM, RTDBGAS hAlias, RTDBGAS hAliasFor); +VMMR3DECL(RTDBGAS) DBGFR3AsResolve(PUVM pUVM, RTDBGAS hAlias); +VMMR3DECL(RTDBGAS) DBGFR3AsResolveAndRetain(PUVM pUVM, RTDBGAS hAlias); +VMMR3DECL(RTDBGAS) DBGFR3AsQueryByName(PUVM pUVM, const char *pszName); +VMMR3DECL(RTDBGAS) DBGFR3AsQueryByPid(PUVM pUVM, RTPROCESS ProcId); + +VMMR3DECL(int) DBGFR3AsLoadImage(PUVM pUVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName, + RTLDRARCH enmArch, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags); +VMMR3DECL(int) DBGFR3AsLoadMap(PUVM pUVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, RTGCUINTPTR uSubtrahend, uint32_t fFlags); +VMMR3DECL(int) DBGFR3AsLinkModule(PUVM pUVM, RTDBGAS hDbgAs, RTDBGMOD hMod, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags); +VMMR3DECL(int) DBGFR3AsUnlinkModuleByName(PUVM pUVM, RTDBGAS hDbgAs, const char *pszModName); + +VMMR3DECL(int) DBGFR3AsSymbolByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, uint32_t fFlags, + PRTGCINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod); +VMMR3DECL(PRTDBGSYMBOL) DBGFR3AsSymbolByAddrA(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, uint32_t Flags, + PRTGCINTPTR poffDisp, PRTDBGMOD phMod); +VMMR3DECL(int) DBGFR3AsSymbolByName(PUVM pUVM, RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod); + +VMMR3DECL(int) DBGFR3AsLineByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, + PRTGCINTPTR poffDisp, PRTDBGLINE pLine, PRTDBGMOD phMod); +VMMR3DECL(PRTDBGLINE) DBGFR3AsLineByAddrA(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, + PRTGCINTPTR poffDisp, PRTDBGMOD phMod); + +/** @name DBGFMOD_PE_F_XXX - flags for + * @{ */ +/** NT 3.1 images were a little different, so make allowances for that. */ +#define DBGFMODINMEM_F_PE_NT31 RT_BIT_32(0) +/** No container fallback. */ +#define DBGFMODINMEM_F_NO_CONTAINER_FALLBACK RT_BIT_32(1) +/** No in-memory reader fallback. */ +#define DBGFMODINMEM_F_NO_READER_FALLBACK RT_BIT_32(2) +/** Valid flags. */ +#define DBGFMODINMEM_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ +VMMR3DECL(int) DBGFR3ModInMem(PUVM pUVM, PCDBGFADDRESS pImageAddr, uint32_t fFlags, const char *pszName, + const char *pszFilename, RTLDRARCH enmArch, uint32_t cbImage, + PRTDBGMOD phDbgMod, PRTERRINFO pErrInfo); + +#endif /* IN_RING3 */ + +#ifdef IN_RING3 /* The stack API only works in ring-3. */ + +/** Pointer to stack frame info. */ +typedef struct DBGFSTACKFRAME *PDBGFSTACKFRAME; +/** Pointer to const stack frame info. */ +typedef struct DBGFSTACKFRAME const *PCDBGFSTACKFRAME; +/** + * Info about a stack frame. + */ +typedef struct DBGFSTACKFRAME +{ + /** Frame number. */ + uint32_t iFrame; + /** Frame flags (DBGFSTACKFRAME_FLAGS_XXX). */ + uint32_t fFlags; + /** The stack address of the frame. + * The off member is [e|r]sp and the Sel member is ss. */ + DBGFADDRESS AddrStack; + /** The program counter (PC) address of the frame. + * The off member is [e|r]ip and the Sel member is cs. */ + DBGFADDRESS AddrPC; + /** Pointer to the symbol nearest the program counter (PC). NULL if not found. */ + PRTDBGSYMBOL pSymPC; + /** Pointer to the linenumber nearest the program counter (PC). NULL if not found. */ + PRTDBGLINE pLinePC; + /** The frame address. + * The off member is [e|r]bp and the Sel member is ss. */ + DBGFADDRESS AddrFrame; + /** The way this frame returns to the next one. */ + RTDBGRETURNTYPE enmReturnType; + + /** The way the next frame returns. + * Only valid when DBGFSTACKFRAME_FLAGS_UNWIND_INFO_RET is set. */ + RTDBGRETURNTYPE enmReturnFrameReturnType; + /** The return frame address. + * The off member is [e|r]bp and the Sel member is ss. */ + DBGFADDRESS AddrReturnFrame; + /** The return stack address. + * The off member is [e|r]sp and the Sel member is ss. */ + DBGFADDRESS AddrReturnStack; + + /** The program counter (PC) address which the frame returns to. + * The off member is [e|r]ip and the Sel member is cs. */ + DBGFADDRESS AddrReturnPC; + /** Pointer to the symbol nearest the return PC. NULL if not found. */ + PRTDBGSYMBOL pSymReturnPC; + /** Pointer to the linenumber nearest the return PC. NULL if not found. */ + PRTDBGLINE pLineReturnPC; + + /** 32-bytes of stack arguments. */ + union + { + /** 64-bit view */ + uint64_t au64[4]; + /** 32-bit view */ + uint32_t au32[8]; + /** 16-bit view */ + uint16_t au16[16]; + /** 8-bit view */ + uint8_t au8[32]; + } Args; + + /** Number of registers values we can be sure about. + * @note This is generally zero in the first frame. */ + uint32_t cSureRegs; + /** Registers we can be sure about (length given by cSureRegs). */ + struct DBGFREGVALEX *paSureRegs; + + /** Pointer to the next frame. + * Might not be used in some cases, so consider it internal. */ + PCDBGFSTACKFRAME pNextInternal; + /** Pointer to the first frame. + * Might not be used in some cases, so consider it internal. */ + PCDBGFSTACKFRAME pFirstInternal; +} DBGFSTACKFRAME; + +/** @name DBGFSTACKFRAME_FLAGS_XXX - DBGFSTACKFRAME Flags. + * @{ */ +/** This is the last stack frame we can read. + * This flag is not set if the walk stop because of max dept or recursion. */ +# define DBGFSTACKFRAME_FLAGS_LAST RT_BIT(1) +/** This is the last record because we detected a loop. */ +# define DBGFSTACKFRAME_FLAGS_LOOP RT_BIT(2) +/** This is the last record because we reached the maximum depth. */ +# define DBGFSTACKFRAME_FLAGS_MAX_DEPTH RT_BIT(3) +/** 16-bit frame. */ +# define DBGFSTACKFRAME_FLAGS_16BIT RT_BIT(4) +/** 32-bit frame. */ +# define DBGFSTACKFRAME_FLAGS_32BIT RT_BIT(5) +/** 64-bit frame. */ +# define DBGFSTACKFRAME_FLAGS_64BIT RT_BIT(6) +/** Real mode or V86 frame. */ +# define DBGFSTACKFRAME_FLAGS_REAL_V86 RT_BIT(7) +/** Is a trap frame (NT term). */ +# define DBGFSTACKFRAME_FLAGS_TRAP_FRAME RT_BIT(8) + +/** Used Odd/even heuristics for far/near return. */ +# define DBGFSTACKFRAME_FLAGS_USED_ODD_EVEN RT_BIT(29) +/** Set if we used unwind info to construct the frame. (Kind of internal.) */ +# define DBGFSTACKFRAME_FLAGS_USED_UNWIND_INFO RT_BIT(30) +/** Internal: Unwind info used for the return frame. */ +# define DBGFSTACKFRAME_FLAGS_UNWIND_INFO_RET RT_BIT(31) +/** @} */ + +/** @name DBGFCODETYPE + * @{ */ +typedef enum DBGFCODETYPE +{ + /** The usual invalid 0 value. */ + DBGFCODETYPE_INVALID = 0, + /** Stack walk for guest code. */ + DBGFCODETYPE_GUEST, + /** Stack walk for hypervisor code. */ + DBGFCODETYPE_HYPER, + /** Stack walk for ring 0 code. */ + DBGFCODETYPE_RING0, + /** The usual 32-bit blowup. */ + DBGFCODETYPE_32BIT_HACK = 0x7fffffff +} DBGFCODETYPE; +/** @} */ + +VMMR3DECL(int) DBGFR3StackWalkBegin(PUVM pUVM, VMCPUID idCpu, DBGFCODETYPE enmCodeType, + PCDBGFSTACKFRAME *ppFirstFrame); +VMMR3DECL(int) DBGFR3StackWalkBeginEx(PUVM pUVM, VMCPUID idCpu, DBGFCODETYPE enmCodeType, PCDBGFADDRESS pAddrFrame, + PCDBGFADDRESS pAddrStack,PCDBGFADDRESS pAddrPC, + RTDBGRETURNTYPE enmReturnType, PCDBGFSTACKFRAME *ppFirstFrame); +VMMR3DECL(PCDBGFSTACKFRAME) DBGFR3StackWalkNext(PCDBGFSTACKFRAME pCurrent); +VMMR3DECL(void) DBGFR3StackWalkEnd(PCDBGFSTACKFRAME pFirstFrame); + +#endif /* IN_RING3 */ + + +#ifdef IN_RING3 /* The disassembly API only works in ring-3. */ + +/** @name Flags to pass to DBGFR3DisasInstrEx(). + * @{ */ +/** Disassemble the current guest instruction, with annotations. */ +#define DBGF_DISAS_FLAGS_CURRENT_GUEST RT_BIT(0) +/** No annotations for current context. */ +#define DBGF_DISAS_FLAGS_NO_ANNOTATION RT_BIT(2) +/** No symbol lookup. */ +#define DBGF_DISAS_FLAGS_NO_SYMBOLS RT_BIT(3) +/** No instruction bytes. */ +#define DBGF_DISAS_FLAGS_NO_BYTES RT_BIT(4) +/** No address in the output. */ +#define DBGF_DISAS_FLAGS_NO_ADDRESS RT_BIT(5) +/** Disassemble original unpatched bytes (PATM). */ +#define DBGF_DISAS_FLAGS_UNPATCHED_BYTES RT_BIT(7) +/** Annotate patched instructions. */ +#define DBGF_DISAS_FLAGS_ANNOTATE_PATCHED RT_BIT(8) +/** Disassemble in the default mode of the specific context. */ +#define DBGF_DISAS_FLAGS_DEFAULT_MODE UINT32_C(0x00000000) +/** Disassemble in 16-bit mode. */ +#define DBGF_DISAS_FLAGS_16BIT_MODE UINT32_C(0x10000000) +/** Disassemble in 16-bit mode with real mode address translation. */ +#define DBGF_DISAS_FLAGS_16BIT_REAL_MODE UINT32_C(0x20000000) +/** Disassemble in 32-bit mode. */ +#define DBGF_DISAS_FLAGS_32BIT_MODE UINT32_C(0x30000000) +/** Disassemble in 64-bit mode. */ +#define DBGF_DISAS_FLAGS_64BIT_MODE UINT32_C(0x40000000) +/** The disassembly mode mask. */ +#define DBGF_DISAS_FLAGS_MODE_MASK UINT32_C(0x70000000) +/** Mask containing the valid flags. */ +#define DBGF_DISAS_FLAGS_VALID_MASK UINT32_C(0x700001ff) +/** @} */ + +/** Special flat selector. */ +#define DBGF_SEL_FLAT 1 + +VMMR3DECL(int) DBGFR3DisasInstrEx(PUVM pUVM, VMCPUID idCpu, RTSEL Sel, RTGCPTR GCPtr, uint32_t fFlags, + char *pszOutput, uint32_t cbOutput, uint32_t *pcbInstr); +VMMR3_INT_DECL(int) DBGFR3DisasInstrCurrent(PVMCPU pVCpu, char *pszOutput, uint32_t cbOutput); +VMMR3DECL(int) DBGFR3DisasInstrCurrentLogInternal(PVMCPU pVCpu, const char *pszPrefix); + +/** @def DBGFR3_DISAS_INSTR_CUR_LOG + * Disassembles the current guest context instruction and writes it to the log. + * All registers and data will be displayed. Addresses will be attempted resolved to symbols. + */ +#ifdef LOG_ENABLED +# define DBGFR3_DISAS_INSTR_CUR_LOG(pVCpu, pszPrefix) \ + do { \ + if (LogIsEnabled()) \ + DBGFR3DisasInstrCurrentLogInternal(pVCpu, pszPrefix); \ + } while (0) +#else +# define DBGFR3_DISAS_INSTR_CUR_LOG(pVCpu, pszPrefix) do { } while (0) +#endif + +VMMR3DECL(int) DBGFR3DisasInstrLogInternal(PVMCPU pVCpu, RTSEL Sel, RTGCPTR GCPtr, const char *pszPrefix); + +/** @def DBGFR3_DISAS_INSTR_LOG + * Disassembles the specified guest context instruction and writes it to the log. + * Addresses will be attempted resolved to symbols. + * @thread Any EMT. + */ +# ifdef LOG_ENABLED +# define DBGFR3_DISAS_INSTR_LOG(pVCpu, Sel, GCPtr, pszPrefix) \ + do { \ + if (LogIsEnabled()) \ + DBGFR3DisasInstrLogInternal(pVCpu, Sel, GCPtr, pszPrefix); \ + } while (0) +# else +# define DBGFR3_DISAS_INSTR_LOG(pVCpu, Sel, GCPtr, pszPrefix) do { } while (0) +# endif +#endif + + +#ifdef IN_RING3 +VMMR3DECL(int) DBGFR3MemScan(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, RTGCUINTPTR cbRange, RTGCUINTPTR uAlign, + const void *pvNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress); +VMMR3DECL(int) DBGFR3MemRead(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void *pvBuf, size_t cbRead); +VMMR3DECL(int) DBGFR3MemReadString(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cbBuf); +VMMR3DECL(int) DBGFR3MemWrite(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void const *pvBuf, size_t cbRead); +#endif + + +/** @name Flags for DBGFR3PagingDumpEx, PGMR3DumpHierarchyHCEx and + * PGMR3DumpHierarchyGCEx + * @{ */ +/** The CR3 from the current CPU state. */ +#define DBGFPGDMP_FLAGS_CURRENT_CR3 RT_BIT_32(0) +/** The current CPU paging mode (PSE, PAE, LM, EPT, NX). */ +#define DBGFPGDMP_FLAGS_CURRENT_MODE RT_BIT_32(1) +/** Whether PSE is enabled (!DBGFPGDMP_FLAGS_CURRENT_STATE). + * Same value as X86_CR4_PSE. */ +#define DBGFPGDMP_FLAGS_PSE RT_BIT_32(4) /* */ +/** Whether PAE is enabled (!DBGFPGDMP_FLAGS_CURRENT_STATE). + * Same value as X86_CR4_PAE. */ +#define DBGFPGDMP_FLAGS_PAE RT_BIT_32(5) /* */ +/** Whether LME is enabled (!DBGFPGDMP_FLAGS_CURRENT_STATE). + * Same value as MSR_K6_EFER_LME. */ +#define DBGFPGDMP_FLAGS_LME RT_BIT_32(8) +/** Whether nested paging is enabled (!DBGFPGDMP_FLAGS_CURRENT_STATE). */ +#define DBGFPGDMP_FLAGS_NP RT_BIT_32(9) +/** Whether extended nested page tables are enabled + * (!DBGFPGDMP_FLAGS_CURRENT_STATE). */ +#define DBGFPGDMP_FLAGS_EPT RT_BIT_32(10) +/** Whether no-execution is enabled (!DBGFPGDMP_FLAGS_CURRENT_STATE). + * Same value as MSR_K6_EFER_NXE. */ +#define DBGFPGDMP_FLAGS_NXE RT_BIT_32(11) +/** Whether to print the CR3. */ +#define DBGFPGDMP_FLAGS_PRINT_CR3 RT_BIT_32(27) +/** Whether to print the header. */ +#define DBGFPGDMP_FLAGS_HEADER RT_BIT_32(28) +/** Whether to dump additional page information. */ +#define DBGFPGDMP_FLAGS_PAGE_INFO RT_BIT_32(29) +/** Dump the shadow tables if set. + * Cannot be used together with DBGFPGDMP_FLAGS_GUEST. */ +#define DBGFPGDMP_FLAGS_SHADOW RT_BIT_32(30) +/** Dump the guest tables if set. + * Cannot be used together with DBGFPGDMP_FLAGS_SHADOW. */ +#define DBGFPGDMP_FLAGS_GUEST RT_BIT_32(31) +/** Mask of valid bits. */ +#define DBGFPGDMP_FLAGS_VALID_MASK UINT32_C(0xf8000f33) +/** The mask of bits controlling the paging mode. */ +#define DBGFPGDMP_FLAGS_MODE_MASK UINT32_C(0x00000f32) +/** @} */ +VMMDECL(int) DBGFR3PagingDumpEx(PUVM pUVM, VMCPUID idCpu, uint32_t fFlags, uint64_t cr3, uint64_t u64FirstAddr, + uint64_t u64LastAddr, uint32_t cMaxDepth, PCDBGFINFOHLP pHlp); + + +/** @name DBGFR3SelQueryInfo flags. + * @{ */ +/** Get the info from the guest descriptor table. + * @note This is more or less a given now when raw-mode was kicked out. */ +#define DBGFSELQI_FLAGS_DT_GUEST UINT32_C(0) +/** If currently executing in in 64-bit mode, blow up data selectors. */ +#define DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE UINT32_C(2) +/** @} */ +VMMR3DECL(int) DBGFR3SelQueryInfo(PUVM pUVM, VMCPUID idCpu, RTSEL Sel, uint32_t fFlags, PDBGFSELINFO pSelInfo); + + +/** + * Register identifiers. + */ +typedef enum DBGFREG +{ + /* General purpose registers: */ + DBGFREG_AL = 0, + DBGFREG_AX = DBGFREG_AL, + DBGFREG_EAX = DBGFREG_AL, + DBGFREG_RAX = DBGFREG_AL, + + DBGFREG_CL, + DBGFREG_CX = DBGFREG_CL, + DBGFREG_ECX = DBGFREG_CL, + DBGFREG_RCX = DBGFREG_CL, + + DBGFREG_DL, + DBGFREG_DX = DBGFREG_DL, + DBGFREG_EDX = DBGFREG_DL, + DBGFREG_RDX = DBGFREG_DL, + + DBGFREG_BL, + DBGFREG_BX = DBGFREG_BL, + DBGFREG_EBX = DBGFREG_BL, + DBGFREG_RBX = DBGFREG_BL, + + DBGFREG_SPL, + DBGFREG_SP = DBGFREG_SPL, + DBGFREG_ESP = DBGFREG_SPL, + DBGFREG_RSP = DBGFREG_SPL, + + DBGFREG_BPL, + DBGFREG_BP = DBGFREG_BPL, + DBGFREG_EBP = DBGFREG_BPL, + DBGFREG_RBP = DBGFREG_BPL, + + DBGFREG_SIL, + DBGFREG_SI = DBGFREG_SIL, + DBGFREG_ESI = DBGFREG_SIL, + DBGFREG_RSI = DBGFREG_SIL, + + DBGFREG_DIL, + DBGFREG_DI = DBGFREG_DIL, + DBGFREG_EDI = DBGFREG_DIL, + DBGFREG_RDI = DBGFREG_DIL, + + DBGFREG_R8, + DBGFREG_R8B = DBGFREG_R8, + DBGFREG_R8W = DBGFREG_R8, + DBGFREG_R8D = DBGFREG_R8, + + DBGFREG_R9, + DBGFREG_R9B = DBGFREG_R9, + DBGFREG_R9W = DBGFREG_R9, + DBGFREG_R9D = DBGFREG_R9, + + DBGFREG_R10, + DBGFREG_R10B = DBGFREG_R10, + DBGFREG_R10W = DBGFREG_R10, + DBGFREG_R10D = DBGFREG_R10, + + DBGFREG_R11, + DBGFREG_R11B = DBGFREG_R11, + DBGFREG_R11W = DBGFREG_R11, + DBGFREG_R11D = DBGFREG_R11, + + DBGFREG_R12, + DBGFREG_R12B = DBGFREG_R12, + DBGFREG_R12W = DBGFREG_R12, + DBGFREG_R12D = DBGFREG_R12, + + DBGFREG_R13, + DBGFREG_R13B = DBGFREG_R13, + DBGFREG_R13W = DBGFREG_R13, + DBGFREG_R13D = DBGFREG_R13, + + DBGFREG_R14, + DBGFREG_R14B = DBGFREG_R14, + DBGFREG_R14W = DBGFREG_R14, + DBGFREG_R14D = DBGFREG_R14, + + DBGFREG_R15, + DBGFREG_R15B = DBGFREG_R15, + DBGFREG_R15W = DBGFREG_R15, + DBGFREG_R15D = DBGFREG_R15, + + /* Segments and other special registers: */ + DBGFREG_CS, + DBGFREG_CS_ATTR, + DBGFREG_CS_BASE, + DBGFREG_CS_LIMIT, + + DBGFREG_DS, + DBGFREG_DS_ATTR, + DBGFREG_DS_BASE, + DBGFREG_DS_LIMIT, + + DBGFREG_ES, + DBGFREG_ES_ATTR, + DBGFREG_ES_BASE, + DBGFREG_ES_LIMIT, + + DBGFREG_FS, + DBGFREG_FS_ATTR, + DBGFREG_FS_BASE, + DBGFREG_FS_LIMIT, + + DBGFREG_GS, + DBGFREG_GS_ATTR, + DBGFREG_GS_BASE, + DBGFREG_GS_LIMIT, + + DBGFREG_SS, + DBGFREG_SS_ATTR, + DBGFREG_SS_BASE, + DBGFREG_SS_LIMIT, + + DBGFREG_IP, + DBGFREG_EIP = DBGFREG_IP, + DBGFREG_RIP = DBGFREG_IP, + + DBGFREG_FLAGS, + DBGFREG_EFLAGS = DBGFREG_FLAGS, + DBGFREG_RFLAGS = DBGFREG_FLAGS, + + /* FPU: */ + DBGFREG_FCW, + DBGFREG_FSW, + DBGFREG_FTW, + DBGFREG_FOP, + DBGFREG_FPUIP, + DBGFREG_FPUCS, + DBGFREG_FPUDP, + DBGFREG_FPUDS, + DBGFREG_MXCSR, + DBGFREG_MXCSR_MASK, + + DBGFREG_ST0, + DBGFREG_ST1, + DBGFREG_ST2, + DBGFREG_ST3, + DBGFREG_ST4, + DBGFREG_ST5, + DBGFREG_ST6, + DBGFREG_ST7, + + DBGFREG_MM0, + DBGFREG_MM1, + DBGFREG_MM2, + DBGFREG_MM3, + DBGFREG_MM4, + DBGFREG_MM5, + DBGFREG_MM6, + DBGFREG_MM7, + + /* SSE: */ + DBGFREG_XMM0, + DBGFREG_XMM1, + DBGFREG_XMM2, + DBGFREG_XMM3, + DBGFREG_XMM4, + DBGFREG_XMM5, + DBGFREG_XMM6, + DBGFREG_XMM7, + DBGFREG_XMM8, + DBGFREG_XMM9, + DBGFREG_XMM10, + DBGFREG_XMM11, + DBGFREG_XMM12, + DBGFREG_XMM13, + DBGFREG_XMM14, + DBGFREG_XMM15, + /** @todo add XMM aliases. */ + + /* AVX: */ + DBGFREG_YMM0, + DBGFREG_YMM1, + DBGFREG_YMM2, + DBGFREG_YMM3, + DBGFREG_YMM4, + DBGFREG_YMM5, + DBGFREG_YMM6, + DBGFREG_YMM7, + DBGFREG_YMM8, + DBGFREG_YMM9, + DBGFREG_YMM10, + DBGFREG_YMM11, + DBGFREG_YMM12, + DBGFREG_YMM13, + DBGFREG_YMM14, + DBGFREG_YMM15, + + /* System registers: */ + DBGFREG_GDTR_BASE, + DBGFREG_GDTR_LIMIT, + DBGFREG_IDTR_BASE, + DBGFREG_IDTR_LIMIT, + DBGFREG_LDTR, + DBGFREG_LDTR_ATTR, + DBGFREG_LDTR_BASE, + DBGFREG_LDTR_LIMIT, + DBGFREG_TR, + DBGFREG_TR_ATTR, + DBGFREG_TR_BASE, + DBGFREG_TR_LIMIT, + + DBGFREG_CR0, + DBGFREG_CR2, + DBGFREG_CR3, + DBGFREG_CR4, + DBGFREG_CR8, + + DBGFREG_DR0, + DBGFREG_DR1, + DBGFREG_DR2, + DBGFREG_DR3, + DBGFREG_DR6, + DBGFREG_DR7, + + /* MSRs: */ + DBGFREG_MSR_IA32_APICBASE, + DBGFREG_MSR_IA32_CR_PAT, + DBGFREG_MSR_IA32_PERF_STATUS, + DBGFREG_MSR_IA32_SYSENTER_CS, + DBGFREG_MSR_IA32_SYSENTER_EIP, + DBGFREG_MSR_IA32_SYSENTER_ESP, + DBGFREG_MSR_IA32_TSC, + DBGFREG_MSR_K6_EFER, + DBGFREG_MSR_K6_STAR, + DBGFREG_MSR_K8_CSTAR, + DBGFREG_MSR_K8_FS_BASE, + DBGFREG_MSR_K8_GS_BASE, + DBGFREG_MSR_K8_KERNEL_GS_BASE, + DBGFREG_MSR_K8_LSTAR, + DBGFREG_MSR_K8_SF_MASK, + DBGFREG_MSR_K8_TSC_AUX, + + /** The number of registers to pass to DBGFR3RegQueryAll. */ + DBGFREG_ALL_COUNT, + + /* Misc aliases that doesn't need be part of the 'all' query: */ + DBGFREG_AH = DBGFREG_ALL_COUNT, + DBGFREG_CH, + DBGFREG_DH, + DBGFREG_BH, + DBGFREG_GDTR, + DBGFREG_IDTR, + + /** The end of the registers. */ + DBGFREG_END, + /** The usual 32-bit type hack. */ + DBGFREG_32BIT_HACK = 0x7fffffff +} DBGFREG; +/** Pointer to a register identifier. */ +typedef DBGFREG *PDBGFREG; +/** Pointer to a const register identifier. */ +typedef DBGFREG const *PCDBGFREG; + +/** + * Register value type. + */ +typedef enum DBGFREGVALTYPE +{ + DBGFREGVALTYPE_INVALID = 0, + /** Unsigned 8-bit register value. */ + DBGFREGVALTYPE_U8, + /** Unsigned 16-bit register value. */ + DBGFREGVALTYPE_U16, + /** Unsigned 32-bit register value. */ + DBGFREGVALTYPE_U32, + /** Unsigned 64-bit register value. */ + DBGFREGVALTYPE_U64, + /** Unsigned 128-bit register value. */ + DBGFREGVALTYPE_U128, + /** Unsigned 256-bit register value. */ + DBGFREGVALTYPE_U256, + /** Unsigned 512-bit register value. */ + DBGFREGVALTYPE_U512, + /** Long double register value. */ + DBGFREGVALTYPE_R80, + /** Descriptor table register value. */ + DBGFREGVALTYPE_DTR, + /** End of the valid register value types. */ + DBGFREGVALTYPE_END, + /** The usual 32-bit type hack. */ + DBGFREGVALTYPE_32BIT_HACK = 0x7fffffff +} DBGFREGVALTYPE; +/** Pointer to a register value type. */ +typedef DBGFREGVALTYPE *PDBGFREGVALTYPE; + +/** + * A generic register value type. + */ +typedef union DBGFREGVAL +{ + uint64_t au64[8]; /**< The 64-bit array view. First because of the initializer. */ + uint32_t au32[16]; /**< The 32-bit array view. */ + uint16_t au16[32]; /**< The 16-bit array view. */ + uint8_t au8[64]; /**< The 8-bit array view. */ + + uint8_t u8; /**< The 8-bit view. */ + uint16_t u16; /**< The 16-bit view. */ + uint32_t u32; /**< The 32-bit view. */ + uint64_t u64; /**< The 64-bit view. */ + RTUINT128U u128; /**< The 128-bit view. */ + RTUINT256U u256; /**< The 256-bit view. */ + RTUINT512U u512; /**< The 512-bit view. */ + RTFLOAT80U r80; /**< The 80-bit floating point view. */ + RTFLOAT80U2 r80Ex; /**< The 80-bit floating point view v2. */ + /** GDTR or LDTR (DBGFREGVALTYPE_DTR). */ + struct + { + /** The table address. */ + uint64_t u64Base; + /** The table limit (length minus 1). */ + uint32_t u32Limit; /**< @todo Limit should be uint16_t */ + } dtr; +} DBGFREGVAL; +/** Pointer to a generic register value type. */ +typedef DBGFREGVAL *PDBGFREGVAL; +/** Pointer to a const generic register value type. */ +typedef DBGFREGVAL const *PCDBGFREGVAL; + +/** Initialize a DBGFREGVAL variable to all zeros. */ +#define DBGFREGVAL_INITIALIZE_ZERO { { 0, 0, 0, 0, 0, 0, 0, 0 } } +/** Initialize a DBGFREGVAL variable to all bits set . */ +#define DBGFREGVAL_INITIALIZE_FFFF { { UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX } } + +/** + * Extended register value, including register ID and type. + * + * This is currently only used by the stack walker. + */ +typedef struct DBGFREGVALEX +{ + /** The register value. */ + DBGFREGVAL Value; + /** The register value type. */ + DBGFREGVALTYPE enmType; + /** The register ID, DBGFREG_END if not applicable. */ + DBGFREG enmReg; + /** Pointer to read-only register name string if no register ID could be found. */ + const char *pszName; +} DBGFREGVALEX; +/** Pointer to an extended register value struct. */ +typedef DBGFREGVALEX *PDBGFREGVALEX; +/** Pointer to a const extended register value struct. */ +typedef DBGFREGVALEX const *PCDBGFREGVALEX; + + +VMMDECL(ssize_t) DBGFR3RegFormatValue(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType, bool fSpecial); +VMMDECL(ssize_t) DBGFR3RegFormatValueEx(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType, + unsigned uBase, signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Register sub-field descriptor. + */ +typedef struct DBGFREGSUBFIELD +{ + /** The name of the sub-field. NULL is used to terminate the array. */ + const char *pszName; + /** The index of the first bit. Ignored if pfnGet is set. */ + uint8_t iFirstBit; + /** The number of bits. Mandatory. */ + uint8_t cBits; + /** The shift count. Not applied when pfnGet is set, but used to + * calculate the minimum type. */ + int8_t cShift; + /** Sub-field flags, DBGFREGSUBFIELD_FLAGS_XXX. */ + uint8_t fFlags; + /** Getter (optional). + * @remarks Does not take the device lock or anything like that. + */ + DECLCALLBACKMEMBER(int, pfnGet,(void *pvUser, struct DBGFREGSUBFIELD const *pSubField, PRTUINT128U puValue)); + /** Setter (optional). + * @remarks Does not take the device lock or anything like that. + */ + DECLCALLBACKMEMBER(int, pfnSet,(void *pvUser, struct DBGFREGSUBFIELD const *pSubField, RTUINT128U uValue, RTUINT128U fMask)); +} DBGFREGSUBFIELD; +/** Pointer to a const register sub-field descriptor. */ +typedef DBGFREGSUBFIELD const *PCDBGFREGSUBFIELD; + +/** @name DBGFREGSUBFIELD_FLAGS_XXX + * @{ */ +/** The sub-field is read-only. */ +#define DBGFREGSUBFIELD_FLAGS_READ_ONLY UINT8_C(0x01) +/** @} */ + +/** Macro for creating a read-write sub-field entry without getters. */ +#define DBGFREGSUBFIELD_RW(a_szName, a_iFirstBit, a_cBits, a_cShift) \ + { a_szName, a_iFirstBit, a_cBits, a_cShift, 0 /*fFlags*/, NULL /*pfnGet*/, NULL /*pfnSet*/ } +/** Macro for creating a read-write sub-field entry with getters. */ +#define DBGFREGSUBFIELD_RW_SG(a_szName, a_cBits, a_cShift, a_pfnGet, a_pfnSet) \ + { a_szName, 0 /*iFirstBit*/, a_cBits, a_cShift, 0 /*fFlags*/, a_pfnGet, a_pfnSet } +/** Macro for creating a read-only sub-field entry without getters. */ +#define DBGFREGSUBFIELD_RO(a_szName, a_iFirstBit, a_cBits, a_cShift) \ + { a_szName, a_iFirstBit, a_cBits, a_cShift, DBGFREGSUBFIELD_FLAGS_READ_ONLY, NULL /*pfnGet*/, NULL /*pfnSet*/ } +/** Macro for creating a terminator sub-field entry. */ +#define DBGFREGSUBFIELD_TERMINATOR() \ + { NULL, 0, 0, 0, 0, NULL, NULL } + +/** + * Register alias descriptor. + */ +typedef struct DBGFREGALIAS +{ + /** The alias name. NULL is used to terminate the array. */ + const char *pszName; + /** Set to a valid type if the alias has a different type. */ + DBGFREGVALTYPE enmType; +} DBGFREGALIAS; +/** Pointer to a const register alias descriptor. */ +typedef DBGFREGALIAS const *PCDBGFREGALIAS; + +/** + * Register descriptor. + */ +typedef struct DBGFREGDESC +{ + /** The normal register name. */ + const char *pszName; + /** The register identifier if this is a CPU register. */ + DBGFREG enmReg; + /** The default register type. */ + DBGFREGVALTYPE enmType; + /** Flags, see DBGFREG_FLAGS_XXX. */ + uint32_t fFlags; + /** The internal register indicator. + * For CPU registers this is the offset into the CPUMCTX structure, + * thuse the 'off' prefix. */ + uint32_t offRegister; + /** Getter. + * @remarks Does not take the device lock or anything like that. + */ + DECLCALLBACKMEMBER(int, pfnGet,(void *pvUser, struct DBGFREGDESC const *pDesc, PDBGFREGVAL pValue)); + /** Setter. + * @remarks Does not take the device lock or anything like that. + */ + DECLCALLBACKMEMBER(int, pfnSet,(void *pvUser, struct DBGFREGDESC const *pDesc, PCDBGFREGVAL pValue, PCDBGFREGVAL pfMask)); + /** Aliases (optional). */ + PCDBGFREGALIAS paAliases; + /** Sub fields (optional). */ + PCDBGFREGSUBFIELD paSubFields; +} DBGFREGDESC; + +/** @name Macros for constructing DBGFREGDESC arrays. + * @{ */ +#define DBGFREGDESC_RW(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, 0 /*fFlags*/, a_offRegister, a_pfnGet, a_pfnSet, NULL /*paAlises*/, NULL /*paSubFields*/ } +#define DBGFREGDESC_RO(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, DBGFREG_FLAGS_READ_ONLY, a_offRegister, a_pfnGet, a_pfnSet, NULL /*paAlises*/, NULL /*paSubFields*/ } +#define DBGFREGDESC_RW_A(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, 0 /*fFlags*/, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, NULL /*paSubFields*/ } +#define DBGFREGDESC_RO_A(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, DBGFREG_FLAGS_READ_ONLY, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, NULL /*paSubFields*/ } +#define DBGFREGDESC_RW_S(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paSubFields) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, 0 /*fFlags*/, a_offRegister, a_pfnGet, a_pfnSet, /*paAliases*/, a_paSubFields } +#define DBGFREGDESC_RO_S(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paSubFields) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, DBGFREG_FLAGS_READ_ONLY, a_offRegister, a_pfnGet, a_pfnSet, /*paAliases*/, a_paSubFields } +#define DBGFREGDESC_RW_AS(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, a_paSubFields) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, 0 /*fFlags*/, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, a_paSubFields } +#define DBGFREGDESC_RO_AS(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, a_paSubFields) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, DBGFREG_FLAGS_READ_ONLY, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, a_paSubFields } +#define DBGFREGDESC_TERMINATOR() \ + { NULL, DBGFREG_END, DBGFREGVALTYPE_INVALID, 0, 0, NULL, NULL, NULL, NULL } +/** @} */ + + +/** @name DBGFREG_FLAGS_XXX + * @{ */ +/** The register is read-only. */ +#define DBGFREG_FLAGS_READ_ONLY RT_BIT_32(0) +/** @} */ + +/** + * Entry in a batch query or set operation. + */ +typedef struct DBGFREGENTRY +{ + /** The register identifier. */ + DBGFREG enmReg; + /** The size of the value in bytes. */ + DBGFREGVALTYPE enmType; + /** The register value. The valid view is indicated by enmType. */ + DBGFREGVAL Val; +} DBGFREGENTRY; +/** Pointer to a register entry in a batch operation. */ +typedef DBGFREGENTRY *PDBGFREGENTRY; +/** Pointer to a const register entry in a batch operation. */ +typedef DBGFREGENTRY const *PCDBGFREGENTRY; + +/** Used with DBGFR3Reg* to indicate the hypervisor register set instead of the + * guest. */ +#define DBGFREG_HYPER_VMCPUID UINT32_C(0x01000000) + +VMMR3DECL(int) DBGFR3RegCpuQueryU8( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint8_t *pu8); +VMMR3DECL(int) DBGFR3RegCpuQueryU16( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint16_t *pu16); +VMMR3DECL(int) DBGFR3RegCpuQueryU32( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint32_t *pu32); +VMMR3DECL(int) DBGFR3RegCpuQueryU64( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t *pu64); +VMMR3DECL(int) DBGFR3RegCpuQueryU128(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint128_t *pu128); +/*VMMR3DECL(int) DBGFR3RegCpuQueryLrd( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, long double *plrd);*/ +VMMR3DECL(int) DBGFR3RegCpuQueryXdtr(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t *pu64Base, uint16_t *pu16Limit); +#if 0 +VMMR3DECL(int) DBGFR3RegCpuQueryBatch(PUVM pUVM,VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs); +VMMR3DECL(int) DBGFR3RegCpuQueryAll( PUVM pUVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs); + +VMMR3DECL(int) DBGFR3RegCpuSetU8( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint8_t u8); +VMMR3DECL(int) DBGFR3RegCpuSetU16( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint16_t u16); +VMMR3DECL(int) DBGFR3RegCpuSetU32( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint32_t u32); +VMMR3DECL(int) DBGFR3RegCpuSetU64( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t u64); +VMMR3DECL(int) DBGFR3RegCpuSetU128( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint128_t u128); +VMMR3DECL(int) DBGFR3RegCpuSetLrd( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, long double lrd); +VMMR3DECL(int) DBGFR3RegCpuSetBatch( PUVM pUVM, VMCPUID idCpu, PCDBGFREGENTRY paRegs, size_t cRegs); +#endif + +VMMR3DECL(const char *) DBGFR3RegCpuName(PUVM pUVM, DBGFREG enmReg, DBGFREGVALTYPE enmType); + +VMMR3_INT_DECL(int) DBGFR3RegRegisterCpu(PVM pVM, PVMCPU pVCpu, PCDBGFREGDESC paRegisters, bool fGuestRegs); +VMMR3_INT_DECL(int) DBGFR3RegRegisterDevice(PVM pVM, PCDBGFREGDESC paRegisters, PPDMDEVINS pDevIns, + const char *pszPrefix, uint32_t iInstance); + +/** + * Entry in a named batch query or set operation. + */ +typedef struct DBGFREGENTRYNM +{ + /** The register name. */ + const char *pszName; + /** The size of the value in bytes. */ + DBGFREGVALTYPE enmType; + /** The register value. The valid view is indicated by enmType. */ + DBGFREGVAL Val; +} DBGFREGENTRYNM; +/** Pointer to a named register entry in a batch operation. */ +typedef DBGFREGENTRYNM *PDBGFREGENTRYNM; +/** Pointer to a const named register entry in a batch operation. */ +typedef DBGFREGENTRYNM const *PCDBGFREGENTRYNM; + +VMMR3DECL(int) DBGFR3RegNmValidate( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg); + +VMMR3DECL(int) DBGFR3RegNmQuery( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType); +VMMR3DECL(int) DBGFR3RegNmQueryU8( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint8_t *pu8); +VMMR3DECL(int) DBGFR3RegNmQueryU16( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint16_t *pu16); +VMMR3DECL(int) DBGFR3RegNmQueryU32( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint32_t *pu32); +VMMR3DECL(int) DBGFR3RegNmQueryU64( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64); +VMMR3DECL(int) DBGFR3RegNmQueryU128(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, PRTUINT128U pu128); +/*VMMR3DECL(int) DBGFR3RegNmQueryLrd( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, long double *plrd);*/ +VMMR3DECL(int) DBGFR3RegNmQueryXdtr(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64Base, uint16_t *pu16Limit); +VMMR3DECL(int) DBGFR3RegNmQueryBatch(PUVM pUVM,VMCPUID idDefCpu, PDBGFREGENTRYNM paRegs, size_t cRegs); +VMMR3DECL(int) DBGFR3RegNmQueryAllCount(PUVM pUVM, size_t *pcRegs); +VMMR3DECL(int) DBGFR3RegNmQueryAll( PUVM pUVM, PDBGFREGENTRYNM paRegs, size_t cRegs); + +VMMR3DECL(int) DBGFR3RegNmSet( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType); +VMMR3DECL(int) DBGFR3RegNmSetU8( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint8_t u8); +VMMR3DECL(int) DBGFR3RegNmSetU16( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint16_t u16); +VMMR3DECL(int) DBGFR3RegNmSetU32( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint32_t u32); +VMMR3DECL(int) DBGFR3RegNmSetU64( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint64_t u64); +VMMR3DECL(int) DBGFR3RegNmSetU128( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, RTUINT128U u128); +VMMR3DECL(int) DBGFR3RegNmSetLrd( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, long double lrd); +VMMR3DECL(int) DBGFR3RegNmSetBatch( PUVM pUVM, VMCPUID idDefCpu, PCDBGFREGENTRYNM paRegs, size_t cRegs); + +/** @todo add enumeration methods. */ + +VMMR3DECL(int) DBGFR3RegPrintf( PUVM pUVM, VMCPUID idDefCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, ...); +VMMR3DECL(int) DBGFR3RegPrintfV(PUVM pUVM, VMCPUID idDefCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, va_list va); + + +#ifdef IN_RING3 + +/** + * Guest OS digger interface identifier. + * + * This is for use together with PDBGFR3QueryInterface and is used to + * obtain access to optional interfaces. + */ +typedef enum DBGFOSINTERFACE +{ + /** The usual invalid entry. */ + DBGFOSINTERFACE_INVALID = 0, + /** Process info. */ + DBGFOSINTERFACE_PROCESS, + /** Thread info. */ + DBGFOSINTERFACE_THREAD, + /** Kernel message log - DBGFOSIDMESG. */ + DBGFOSINTERFACE_DMESG, + /** Windows NT specifics (for the communication with the KD debugger stub). */ + DBGFOSINTERFACE_WINNT, + /** The end of the valid entries. */ + DBGFOSINTERFACE_END, + /** The usual 32-bit type blowup. */ + DBGFOSINTERFACE_32BIT_HACK = 0x7fffffff +} DBGFOSINTERFACE; +/** Pointer to a Guest OS digger interface identifier. */ +typedef DBGFOSINTERFACE *PDBGFOSINTERFACE; +/** Pointer to a const Guest OS digger interface identifier. */ +typedef DBGFOSINTERFACE const *PCDBGFOSINTERFACE; + + +/** + * Guest OS Digger Registration Record. + * + * This is used with the DBGFR3OSRegister() API. + */ +typedef struct DBGFOSREG +{ + /** Magic value (DBGFOSREG_MAGIC). */ + uint32_t u32Magic; + /** Flags. Reserved. */ + uint32_t fFlags; + /** The size of the instance data. */ + uint32_t cbData; + /** Operative System name. */ + char szName[24]; + + /** + * Constructs the instance. + * + * @returns VBox status code. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(int, pfnConstruct,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)); + + /** + * Destroys the instance. + * + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(void, pfnDestruct,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)); + + /** + * Probes the guest memory for OS finger prints. + * + * No setup or so is performed, it will be followed by a call to pfnInit + * or pfnRefresh that should take care of that. + * + * @returns true if is an OS handled by this module, otherwise false. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(bool, pfnProbe,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)); + + /** + * Initializes a fresly detected guest, loading symbols and such useful stuff. + * + * This is called after pfnProbe. + * + * @returns VBox status code. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(int, pfnInit,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)); + + /** + * Refreshes symbols and stuff following a redetection of the same OS. + * + * This is called after pfnProbe. + * + * @returns VBox status code. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(int, pfnRefresh,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)); + + /** + * Terminates an OS when a new (or none) OS has been detected, + * and before destruction. + * + * This is called after pfnProbe and if needed before pfnDestruct. + * + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(void, pfnTerm,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)); + + /** + * Queries the version of the running OS. + * + * This is only called after pfnInit(). + * + * @returns VBox status code. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + * @param pszVersion Where to store the version string. + * @param cchVersion The size of the version string buffer. + */ + DECLCALLBACKMEMBER(int, pfnQueryVersion,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData, char *pszVersion, size_t cchVersion)); + + /** + * Queries the pointer to a interface. + * + * This is called after pfnProbe. + * + * The returned interface must be valid until pfnDestruct is called. Two calls + * to this method with the same @a enmIf value must return the same pointer. + * + * @returns Pointer to the interface if available, NULL if not available. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + * @param enmIf The interface identifier. + */ + DECLCALLBACKMEMBER(void *, pfnQueryInterface,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData, DBGFOSINTERFACE enmIf)); + + /** + * Stack unwind assist callback. + * + * This is only called after pfnInit(). + * + * @returns VBox status code (allocation error or something of similar fatality). + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + * @param idCpu The CPU that's unwinding it's stack. + * @param pFrame The current frame. Okay to modify it a little. + * @param pState The unwind state. Okay to modify it. + * @param pInitialCtx The initial register context. + * @param hAs The address space being used for the unwind. + * @param puScratch Scratch area (initialized to zero, no dtor). + */ + DECLCALLBACKMEMBER(int, pfnStackUnwindAssist,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData, VMCPUID idCpu, PDBGFSTACKFRAME pFrame, + PRTDBGUNWINDSTATE pState, PCCPUMCTX pInitialCtx, RTDBGAS hAs, + uint64_t *puScratch)); + + /** Trailing magic (DBGFOSREG_MAGIC). */ + uint32_t u32EndMagic; +} DBGFOSREG; +/** Pointer to a Guest OS digger registration record. */ +typedef DBGFOSREG *PDBGFOSREG; +/** Pointer to a const Guest OS digger registration record. */ +typedef DBGFOSREG const *PCDBGFOSREG; + +/** Magic value for DBGFOSREG::u32Magic and DBGFOSREG::u32EndMagic. (Hitomi Kanehara) */ +#define DBGFOSREG_MAGIC 0x19830808 + + +/** + * Interface for querying kernel log messages (DBGFOSINTERFACE_DMESG). + */ +typedef struct DBGFOSIDMESG +{ + /** Trailing magic (DBGFOSIDMESG_MAGIC). */ + uint32_t u32Magic; + + /** + * Query the kernel log. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the messages could not be located. + * @retval VERR_INVALID_STATE if the messages was found to have unknown/invalid + * format. + * @retval VERR_BUFFER_OVERFLOW if the buffer isn't large enough, pcbActual + * will be set to the required buffer size. The buffer, however, will + * be filled with as much data as it can hold (properly zero terminated + * of course). + * + * @param pThis Pointer to the interface structure. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param fFlags Flags reserved for future use, MBZ. + * @param cMessages The number of messages to retrieve, counting from the + * end of the log (i.e. like tail), use UINT32_MAX for all. + * @param pszBuf The output buffer. + * @param cbBuf The buffer size. + * @param pcbActual Where to store the number of bytes actually returned, + * including zero terminator. On VERR_BUFFER_OVERFLOW this + * holds the necessary buffer size. Optional. + */ + DECLCALLBACKMEMBER(int, pfnQueryKernelLog,(struct DBGFOSIDMESG *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, uint32_t fFlags, + uint32_t cMessages, char *pszBuf, size_t cbBuf, size_t *pcbActual)); + /** Trailing magic (DBGFOSIDMESG_MAGIC). */ + uint32_t u32EndMagic; +} DBGFOSIDMESG; +/** Pointer to the interface for query kernel log messages (DBGFOSINTERFACE_DMESG). */ +typedef DBGFOSIDMESG *PDBGFOSIDMESG; +/** Magic value for DBGFOSIDMESG::32Magic and DBGFOSIDMESG::u32EndMagic. (Kenazburo Oe) */ +#define DBGFOSIDMESG_MAGIC UINT32_C(0x19350131) + + +/** + * Interface for querying Windows NT guest specifics (DBGFOSINTERFACE_WINNT). + */ +typedef struct DBGFOSIWINNT +{ + /** Trailing magic (DBGFOSIWINNT_MAGIC). */ + uint32_t u32Magic; + + /** + * Queries version information. + * + * @returns VBox status code. + * @param pThis Pointer to the interface structure. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param puVersMajor Where to store the major version part, optional. + * @param puVersMinor Where to store the minor version part, optional. + * @param puBuildNumber Where to store the build number, optional. + * @param pf32Bit Where to store the flag whether this is a 32bit Windows NT, optional. + */ + DECLCALLBACKMEMBER(int, pfnQueryVersion,(struct DBGFOSIWINNT *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, + uint32_t *puVersMajor, uint32_t *puVersMinor, + uint32_t *puBuildNumber, bool *pf32Bit)); + + /** + * Queries some base kernel pointers. + * + * @returns VBox status code. + * @param pThis Pointer to the interface structure. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pGCPtrKernBase Where to store the kernel base on success. + * @param pGCPtrPsLoadedModuleList Where to store the pointer to the laoded module list head on success. + */ + DECLCALLBACKMEMBER(int, pfnQueryKernelPtrs,(struct DBGFOSIWINNT *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, + PRTGCUINTPTR pGCPtrKernBase, PRTGCUINTPTR pGCPtrPsLoadedModuleList)); + + /** + * Queries KPCR and KPCRB pointers for the given vCPU. + * + * @returns VBox status code. + * @param pThis Pointer to the interface structure. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param idCpu The vCPU to query the KPCR/KPCRB for. + * @param pKpcr Where to store the KPCR pointer on success, optional. + * @param pKpcrb Where to store the KPCR pointer on success, optional. + */ + DECLCALLBACKMEMBER(int, pfnQueryKpcrForVCpu,(struct DBGFOSIWINNT *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, VMCPUID idCpu, + PRTGCUINTPTR pKpcr, PRTGCUINTPTR pKpcrb)); + + /** + * Queries the current thread for the given vCPU. + * + * @returns VBox status code. + * @param pThis Pointer to the interface structure. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param idCpu The vCPU to query the KPCR/KPCRB for. + * @param pCurThrd Where to store the CurrentThread pointer on success. + */ + DECLCALLBACKMEMBER(int, pfnQueryCurThrdForVCpu,(struct DBGFOSIWINNT *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, VMCPUID idCpu, + PRTGCUINTPTR pCurThrd)); + + /** Trailing magic (DBGFOSIWINNT_MAGIC). */ + uint32_t u32EndMagic; +} DBGFOSIWINNT; +/** Pointer to the interface for query kernel log messages (DBGFOSINTERFACE_WINNT). */ +typedef DBGFOSIWINNT *PDBGFOSIWINNT; +/** Magic value for DBGFOSIWINNT::32Magic and DBGFOSIWINNT::u32EndMagic. (Dave Cutler) */ +#define DBGFOSIWINNT_MAGIC UINT32_C(0x19420313) + + +VMMR3DECL(int) DBGFR3OSRegister(PUVM pUVM, PCDBGFOSREG pReg); +VMMR3DECL(int) DBGFR3OSDeregister(PUVM pUVM, PCDBGFOSREG pReg); +VMMR3DECL(int) DBGFR3OSDetect(PUVM pUVM, char *pszName, size_t cchName); +VMMR3DECL(int) DBGFR3OSQueryNameAndVersion(PUVM pUVM, char *pszName, size_t cchName, char *pszVersion, size_t cchVersion); +VMMR3DECL(void *) DBGFR3OSQueryInterface(PUVM pUVM, DBGFOSINTERFACE enmIf); + + +VMMR3DECL(int) DBGFR3CoreWrite(PUVM pUVM, const char *pszFilename, bool fReplaceFile); + + + +/** @defgroup grp_dbgf_plug_in The DBGF Plug-in Interface + * @{ + */ + +/** The plug-in module name prefix. */ +# define DBGF_PLUG_IN_PREFIX "DbgPlugIn" + +/** The name of the plug-in entry point (FNDBGFPLUGIN) */ +# define DBGF_PLUG_IN_ENTRYPOINT "DbgPlugInEntry" + +/** + * DBGF plug-in operations. + */ +typedef enum DBGFPLUGINOP +{ + /** The usual invalid first value. */ + DBGFPLUGINOP_INVALID, + /** Initialize the plug-in for a VM, register all the stuff. + * The plug-in will be unloaded on failure. + * uArg: The full VirtualBox version, see VBox/version.h. */ + DBGFPLUGINOP_INIT, + /** Terminate the plug-ing for a VM, deregister all the stuff. + * The plug-in will be unloaded after this call regardless of the return + * code. */ + DBGFPLUGINOP_TERM, + /** The usual 32-bit hack. */ + DBGFPLUGINOP_32BIT_HACK = 0x7fffffff +} DBGFPLUGINOP; + +/** + * DBGF plug-in main entry point. + * + * @returns VBox status code. + * + * @param enmOperation The operation. + * @param pUVM The user mode VM handle. This may be NULL. + * @param pVMM The VMM function table. + * @param uArg Extra argument. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFPLUGIN,(DBGFPLUGINOP enmOperation, PUVM pUVM, PCVMMR3VTABLE pVMM, uintptr_t uArg)); +/** Pointer to a FNDBGFPLUGIN. */ +typedef FNDBGFPLUGIN *PFNDBGFPLUGIN; + +/** @copydoc FNDBGFPLUGIN */ +DECLEXPORT(int) DbgPlugInEntry(DBGFPLUGINOP enmOperation, PUVM pUVM, PCVMMR3VTABLE pVMM, uintptr_t uArg); + +VMMR3DECL(int) DBGFR3PlugInLoad(PUVM pUVM, const char *pszPlugIn, char *pszActual, size_t cbActual, PRTERRINFO pErrInfo); +VMMR3DECL(int) DBGFR3PlugInUnload(PUVM pUVM, const char *pszName); +VMMR3DECL(void) DBGFR3PlugInLoadAll(PUVM pUVM); +VMMR3DECL(void) DBGFR3PlugInUnloadAll(PUVM pUVM); + +/** @} */ + + +/** @defgroup grp_dbgf_types The DBGF type system Interface. + * @{ + */ + +/** A few forward declarations. */ +/** Pointer to a type registration structure. */ +typedef struct DBGFTYPEREG *PDBGFTYPEREG; +/** Pointer to a const type registration structure. */ +typedef const struct DBGFTYPEREG *PCDBGFTYPEREG; +/** Pointer to a typed buffer. */ +typedef struct DBGFTYPEVAL *PDBGFTYPEVAL; + +/** + * DBGF built-in types. + */ +typedef enum DBGFTYPEBUILTIN +{ + /** The usual invalid first value. */ + DBGFTYPEBUILTIN_INVALID, + /** Unsigned 8bit integer. */ + DBGFTYPEBUILTIN_UINT8, + /** Signed 8bit integer. */ + DBGFTYPEBUILTIN_INT8, + /** Unsigned 16bit integer. */ + DBGFTYPEBUILTIN_UINT16, + /** Signed 16bit integer. */ + DBGFTYPEBUILTIN_INT16, + /** Unsigned 32bit integer. */ + DBGFTYPEBUILTIN_UINT32, + /** Signed 32bit integer. */ + DBGFTYPEBUILTIN_INT32, + /** Unsigned 64bit integer. */ + DBGFTYPEBUILTIN_UINT64, + /** Signed 64bit integer. */ + DBGFTYPEBUILTIN_INT64, + /** 32bit Guest pointer */ + DBGFTYPEBUILTIN_PTR32, + /** 64bit Guest pointer */ + DBGFTYPEBUILTIN_PTR64, + /** Guest pointer - size depends on the guest bitness */ + DBGFTYPEBUILTIN_PTR, + /** Type indicating a size, like size_t this can have different sizes + * on 32bit and 64bit systems */ + DBGFTYPEBUILTIN_SIZE, + /** 32bit float. */ + DBGFTYPEBUILTIN_FLOAT32, + /** 64bit float (also known as double). */ + DBGFTYPEBUILTIN_FLOAT64, + /** Compund types like structs and unions. */ + DBGFTYPEBUILTIN_COMPOUND, + /** The usual 32-bit hack. */ + DBGFTYPEBUILTIN_32BIT_HACK = 0x7fffffff +} DBGFTYPEBUILTIN; +/** Pointer to a built-in type. */ +typedef DBGFTYPEBUILTIN *PDBGFTYPEBUILTIN; +/** Pointer to a const built-in type. */ +typedef const DBGFTYPEBUILTIN *PCDBGFTYPEBUILTIN; + +/** + * DBGF type value buffer. + */ +typedef union DBGFTYPEVALBUF +{ + uint8_t u8; + int8_t i8; + uint16_t u16; + int16_t i16; + uint32_t u32; + int32_t i32; + uint64_t u64; + int64_t i64; + float f32; + double f64; + uint64_t size; /* For the built-in size_t which can be either 32-bit or 64-bit. */ + RTGCPTR GCPtr; + /** For embedded structs. */ + PDBGFTYPEVAL pVal; +} DBGFTYPEVALBUF; +/** Pointer to a value. */ +typedef DBGFTYPEVALBUF *PDBGFTYPEVALBUF; + +/** + * DBGF type value entry. + */ +typedef struct DBGFTYPEVALENTRY +{ + /** DBGF built-in type. */ + DBGFTYPEBUILTIN enmType; + /** Size of the type. */ + size_t cbType; + /** Number of entries, for arrays this can be > 1. */ + uint32_t cEntries; + /** Value buffer, depends on whether this is an array. */ + union + { + /** Single value. */ + DBGFTYPEVALBUF Val; + /** Pointer to the array of values. */ + PDBGFTYPEVALBUF pVal; + } Buf; +} DBGFTYPEVALENTRY; +/** Pointer to a type value entry. */ +typedef DBGFTYPEVALENTRY *PDBGFTYPEVALENTRY; +/** Pointer to a const type value entry. */ +typedef const DBGFTYPEVALENTRY *PCDBGFTYPEVALENTRY; + +/** + * DBGF typed value. + */ +typedef struct DBGFTYPEVAL +{ + /** Pointer to the registration structure for this type. */ + PCDBGFTYPEREG pTypeReg; + /** Number of value entries. */ + uint32_t cEntries; + /** Variable sized array of value entries. */ + DBGFTYPEVALENTRY aEntries[1]; +} DBGFTYPEVAL; + +/** + * DBGF type variant. + */ +typedef enum DBGFTYPEVARIANT +{ + /** The usual invalid first value. */ + DBGFTYPEVARIANT_INVALID, + /** A struct. */ + DBGFTYPEVARIANT_STRUCT, + /** Union. */ + DBGFTYPEVARIANT_UNION, + /** Alias for an existing type. */ + DBGFTYPEVARIANT_ALIAS, + /** The usual 32-bit hack. */ + DBGFTYPEVARIANT_32BIT_HACK = 0x7fffffff +} DBGFTYPEVARIANT; + +/** @name DBGFTYPEREGMEMBER Flags. + * @{ */ +/** The member is an array with a fixed size. */ +# define DBGFTYPEREGMEMBER_F_ARRAY RT_BIT_32(0) +/** The member denotes a pointer. */ +# define DBGFTYPEREGMEMBER_F_POINTER RT_BIT_32(1) +/** @} */ + +/** + * DBGF type member. + */ +typedef struct DBGFTYPEREGMEMBER +{ + /** Name of the member. */ + const char *pszName; + /** Flags for this member, see DBGFTYPEREGMEMBER_F_XXX. */ + uint32_t fFlags; + /** Type identifier. */ + const char *pszType; + /** The number of elements in the array, only valid for arrays. */ + uint32_t cElements; +} DBGFTYPEREGMEMBER; +/** Pointer to a member. */ +typedef DBGFTYPEREGMEMBER *PDBGFTYPEREGMEMBER; +/** Pointer to a const member. */ +typedef const DBGFTYPEREGMEMBER *PCDBGFTYPEREGMEMBER; + +/** @name DBGFTYPEREG Flags. + * @{ */ +/** The type is a packed structure. */ +# define DBGFTYPEREG_F_PACKED RT_BIT_32(0) +/** @} */ + +/** + * New type registration structure. + */ +typedef struct DBGFTYPEREG +{ + /** Name of the type. */ + const char *pszType; + /** The type variant. */ + DBGFTYPEVARIANT enmVariant; + /** Some registration flags, see DBGFTYPEREG_F_XXX. */ + uint32_t fFlags; + /** Number of members this type has, only valid for structs or unions. */ + uint32_t cMembers; + /** Pointer to the member fields, only valid for structs or unions. */ + PCDBGFTYPEREGMEMBER paMembers; + /** Name of the aliased type for aliases. */ + const char *pszAliasedType; +} DBGFTYPEREG; + +/** + * DBGF typed value dumper callback. + * + * @returns VBox status code. Any non VINF_SUCCESS status code will abort the dumping. + * + * @param off The byte offset of the entry from the start of the type. + * @param pszField The name of the field for the value. + * @param iLvl The current level. + * @param enmType The type enum. + * @param cbType Size of the type. + * @param pValBuf Pointer to the value buffer. + * @param cValBufs Number of value buffers (for arrays). + * @param pvUser Opaque user data. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFR3TYPEVALDUMP,(uint32_t off, const char *pszField, uint32_t iLvl, + DBGFTYPEBUILTIN enmType, size_t cbType, + PDBGFTYPEVALBUF pValBuf, uint32_t cValBufs, void *pvUser)); +/** Pointer to a FNDBGFR3TYPEVALDUMP. */ +typedef FNDBGFR3TYPEVALDUMP *PFNDBGFR3TYPEVALDUMP; + +/** + * DBGF type information dumper callback. + * + * @returns VBox status code. Any non VINF_SUCCESS status code will abort the dumping. + * + * @param off The byte offset of the entry from the start of the type. + * @param pszField The name of the field for the value. + * @param iLvl The current level. + * @param pszType The type of the field. + * @param fTypeFlags Flags for this type, see DBGFTYPEREGMEMBER_F_XXX. + * @param cElements Number of for the field ( > 0 for arrays). + * @param pvUser Opaque user data. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFR3TYPEDUMP,(uint32_t off, const char *pszField, uint32_t iLvl, + const char *pszType, uint32_t fTypeFlags, + uint32_t cElements, void *pvUser)); +/** Pointer to a FNDBGFR3TYPEDUMP. */ +typedef FNDBGFR3TYPEDUMP *PFNDBGFR3TYPEDUMP; + +VMMR3DECL(int) DBGFR3TypeRegister( PUVM pUVM, uint32_t cTypes, PCDBGFTYPEREG paTypes); +VMMR3DECL(int) DBGFR3TypeDeregister(PUVM pUVM, const char *pszType); +VMMR3DECL(int) DBGFR3TypeQueryReg( PUVM pUVM, const char *pszType, PCDBGFTYPEREG *ppTypeReg); + +VMMR3DECL(int) DBGFR3TypeQuerySize( PUVM pUVM, const char *pszType, size_t *pcbType); +VMMR3DECL(int) DBGFR3TypeSetSize( PUVM pUVM, const char *pszType, size_t cbType); +VMMR3DECL(int) DBGFR3TypeDumpEx( PUVM pUVM, const char *pszType, uint32_t fFlags, + uint32_t cLvlMax, PFNDBGFR3TYPEDUMP pfnDump, void *pvUser); +VMMR3DECL(int) DBGFR3TypeQueryValByType(PUVM pUVM, PCDBGFADDRESS pAddress, const char *pszType, + PDBGFTYPEVAL *ppVal); +VMMR3DECL(void) DBGFR3TypeValFree(PDBGFTYPEVAL pVal); +VMMR3DECL(int) DBGFR3TypeValDumpEx(PUVM pUVM, PCDBGFADDRESS pAddress, const char *pszType, uint32_t fFlags, + uint32_t cLvlMax, FNDBGFR3TYPEVALDUMP pfnDump, void *pvUser); + +/** @} */ + + +/** @defgroup grp_dbgf_flow The DBGF control flow graph Interface. + * @{ + */ + +/** A DBGF control flow graph handle. */ +typedef struct DBGFFLOWINT *DBGFFLOW; +/** Pointer to a DBGF control flow graph handle. */ +typedef DBGFFLOW *PDBGFFLOW; +/** A DBGF control flow graph basic block handle. */ +typedef struct DBGFFLOWBBINT *DBGFFLOWBB; +/** Pointer to a DBGF control flow graph basic block handle. */ +typedef DBGFFLOWBB *PDBGFFLOWBB; +/** A DBGF control flow graph branch table handle. */ +typedef struct DBGFFLOWBRANCHTBLINT *DBGFFLOWBRANCHTBL; +/** Pointer to a DBGF flow control graph branch table handle. */ +typedef DBGFFLOWBRANCHTBL *PDBGFFLOWBRANCHTBL; +/** A DBGF control flow graph iterator. */ +typedef struct DBGFFLOWITINT *DBGFFLOWIT; +/** Pointer to a control flow graph iterator. */ +typedef DBGFFLOWIT *PDBGFFLOWIT; +/** A DBGF control flow graph branch table iterator. */ +typedef struct DBGFFLOWBRANCHTBLITINT *DBGFFLOWBRANCHTBLIT; +/** Pointer to a control flow graph branch table iterator. */ +typedef DBGFFLOWBRANCHTBLIT *PDBGFFLOWBRANCHTBLIT; + +/** @name DBGFFLOWBB Flags. + * @{ */ +/** The basic block is the entry into the owning control flow graph. */ +#define DBGF_FLOW_BB_F_ENTRY RT_BIT_32(0) +/** The basic block was not populated because the limit was reached. */ +#define DBGF_FLOW_BB_F_EMPTY RT_BIT_32(1) +/** The basic block is not complete because an error happened during disassembly. */ +#define DBGF_FLOW_BB_F_INCOMPLETE_ERR RT_BIT_32(2) +/** The basic block is reached through a branch table. */ +#define DBGF_FLOW_BB_F_BRANCH_TABLE RT_BIT_32(3) +/** The basic block consists only of a single call instruction because + * DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB was given. */ +#define DBGF_FLOW_BB_F_CALL_INSN RT_BIT_32(4) +/** The branch target of the call instruction could be deduced and can be queried with + * DBGFR3FlowBbGetBranchAddress(). May only be available when DBGF_FLOW_BB_F_CALL_INSN + * is set. */ +#define DBGF_FLOW_BB_F_CALL_INSN_TARGET_KNOWN RT_BIT_32(5) +/** @} */ + +/** @name Flags controlling the creating of a control flow graph. + * @{ */ +/** Default options. */ +#define DBGF_FLOW_CREATE_F_DEFAULT 0 +/** Tries to resolve indirect branches, useful for code using + * jump tables generated for large switch statements by some compilers. */ +#define DBGF_FLOW_CREATE_F_TRY_RESOLVE_INDIRECT_BRANCHES RT_BIT_32(0) +/** Call instructions are placed in a separate basic block. */ +#define DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB RT_BIT_32(1) +/** @} */ + +/** + * DBGF control graph basic block end type. + */ +typedef enum DBGFFLOWBBENDTYPE +{ + /** Invalid type. */ + DBGFFLOWBBENDTYPE_INVALID = 0, + /** Basic block is the exit block and has no successor. */ + DBGFFLOWBBENDTYPE_EXIT, + /** Basic block is the last disassembled block because the + * maximum amount to disassemble was reached but is not an + * exit block - no successors. + */ + DBGFFLOWBBENDTYPE_LAST_DISASSEMBLED, + /** Unconditional control flow change because the successor is referenced by multiple + * basic blocks. - 1 successor. */ + DBGFFLOWBBENDTYPE_UNCOND, + /** Unconditional control flow change because of an direct branch - 1 successor. */ + DBGFFLOWBBENDTYPE_UNCOND_JMP, + /** Unconditional control flow change because of an indirect branch - n successors. */ + DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP, + /** Conditional control flow change - 2 successors. */ + DBGFFLOWBBENDTYPE_COND, + /** 32bit hack. */ + DBGFFLOWBBENDTYPE_32BIT_HACK = 0x7fffffff +} DBGFFLOWBBENDTYPE; + +/** + * DBGF control flow graph iteration order. + */ +typedef enum DBGFFLOWITORDER +{ + /** Invalid order. */ + DBGFFLOWITORDER_INVALID = 0, + /** From lowest to highest basic block start address. */ + DBGFFLOWITORDER_BY_ADDR_LOWEST_FIRST, + /** From highest to lowest basic block start address. */ + DBGFFLOWITORDER_BY_ADDR_HIGHEST_FIRST, + /** Depth first traversing starting from the entry block. */ + DBGFFLOWITORDER_DEPTH_FRIST, + /** Breadth first traversing starting from the entry block. */ + DBGFFLOWITORDER_BREADTH_FIRST, + /** Usual 32bit hack. */ + DBGFFLOWITORDER_32BIT_HACK = 0x7fffffff +} DBGFFLOWITORDER; +/** Pointer to a iteration order enum. */ +typedef DBGFFLOWITORDER *PDBGFFLOWITORDER; + + +VMMR3DECL(int) DBGFR3FlowCreate(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddressStart, uint32_t cbDisasmMax, + uint32_t fFlagsFlow, uint32_t fFlagsDisasm, PDBGFFLOW phFlow); +VMMR3DECL(uint32_t) DBGFR3FlowRetain(DBGFFLOW hFlow); +VMMR3DECL(uint32_t) DBGFR3FlowRelease(DBGFFLOW hFlow); +VMMR3DECL(int) DBGFR3FlowQueryStartBb(DBGFFLOW hFlow, PDBGFFLOWBB phFlowBb); +VMMR3DECL(int) DBGFR3FlowQueryBbByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBB phFlowBb); +VMMR3DECL(int) DBGFR3FlowQueryBranchTblByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBRANCHTBL phFlowBranchTbl); +VMMR3DECL(uint32_t) DBGFR3FlowGetBbCount(DBGFFLOW hFlow); +VMMR3DECL(uint32_t) DBGFR3FlowGetBranchTblCount(DBGFFLOW hFlow); +VMMR3DECL(uint32_t) DBGFR3FlowGetCallInsnCount(DBGFFLOW hFlow); + +VMMR3DECL(uint32_t) DBGFR3FlowBbRetain(DBGFFLOWBB hFlowBb); +VMMR3DECL(uint32_t) DBGFR3FlowBbRelease(DBGFFLOWBB hFlowBb); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetStartAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrStart); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetEndAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrEnd); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetBranchAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrTarget); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetFollowingAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrFollow); +VMMR3DECL(DBGFFLOWBBENDTYPE) DBGFR3FlowBbGetType(DBGFFLOWBB hFlowBb); +VMMR3DECL(uint32_t) DBGFR3FlowBbGetInstrCount(DBGFFLOWBB hFlowBb); +VMMR3DECL(uint32_t) DBGFR3FlowBbGetFlags(DBGFFLOWBB hFlowBb); +VMMR3DECL(int) DBGFR3FlowBbQueryBranchTbl(DBGFFLOWBB hFlowBb, PDBGFFLOWBRANCHTBL phBranchTbl); +VMMR3DECL(int) DBGFR3FlowBbQueryError(DBGFFLOWBB hFlowBb, const char **ppszErr); +VMMR3DECL(int) DBGFR3FlowBbQueryInstr(DBGFFLOWBB hFlowBb, uint32_t idxInstr, PDBGFADDRESS pAddrInstr, + uint32_t *pcbInstr, const char **ppszInstr); +VMMR3DECL(int) DBGFR3FlowBbQuerySuccessors(DBGFFLOWBB hFlowBb, PDBGFFLOWBB phFlowBbFollow, + PDBGFFLOWBB phFlowBbTarget); +VMMR3DECL(uint32_t) DBGFR3FlowBbGetRefBbCount(DBGFFLOWBB hFlowBb); +VMMR3DECL(int) DBGFR3FlowBbGetRefBb(DBGFFLOWBB hFlowBb, PDBGFFLOWBB pahFlowBbRef, uint32_t cRef); + +VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRetain(DBGFFLOWBRANCHTBL hFlowBranchTbl); +VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRelease(DBGFFLOWBRANCHTBL hFlowBranchTbl); +VMMR3DECL(uint32_t) DBGFR3FlowBranchTblGetSlots(DBGFFLOWBRANCHTBL hFlowBranchTbl); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetStartAddress(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS pAddrStart); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetAddrAtSlot(DBGFFLOWBRANCHTBL hFlowBranchTbl, uint32_t idxSlot, PDBGFADDRESS pAddrSlot); +VMMR3DECL(int) DBGFR3FlowBranchTblQueryAddresses(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS paAddrs, uint32_t cAddrs); + +VMMR3DECL(int) DBGFR3FlowItCreate(DBGFFLOW hFlow, DBGFFLOWITORDER enmOrder, PDBGFFLOWIT phFlowIt); +VMMR3DECL(void) DBGFR3FlowItDestroy(DBGFFLOWIT hFlowIt); +VMMR3DECL(DBGFFLOWBB) DBGFR3FlowItNext(DBGFFLOWIT hFlowIt); +VMMR3DECL(int) DBGFR3FlowItReset(DBGFFLOWIT hFlowIt); + +VMMR3DECL(int) DBGFR3FlowBranchTblItCreate(DBGFFLOW hFlow, DBGFFLOWITORDER enmOrder, PDBGFFLOWBRANCHTBLIT phFlowBranchTblIt); +VMMR3DECL(void) DBGFR3FlowBranchTblItDestroy(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt); +VMMR3DECL(DBGFFLOWBRANCHTBL) DBGFR3FlowBranchTblItNext(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt); +VMMR3DECL(int) DBGFR3FlowBranchTblItReset(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt); + +/** @} */ + + +/** @defgroup grp_dbgf_misc Misc DBGF interfaces. + * @{ */ +VMMR3DECL(VBOXSTRICTRC) DBGFR3ReportBugCheck(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmEvent, uint64_t uBugCheck, + uint64_t uP1, uint64_t uP2, uint64_t uP3, uint64_t uP4); +VMMR3DECL(int) DBGFR3FormatBugCheck(PUVM pUVM, char *pszDetails, size_t cbDetails, + uint64_t uP0, uint64_t uP1, uint64_t uP2, uint64_t uP3, uint64_t uP4); +/** @} */ +#endif /* IN_RING3 */ + + +/** @defgroup grp_dbgf_tracer DBGF event tracing. + * @{ */ +#ifdef IN_RING3 +VMMR3_INT_DECL(int) DBGFR3TracerRegisterEvtSrc(PVM pVM, const char *pszName, PDBGFTRACEREVTSRC phEvtSrc); +VMMR3_INT_DECL(int) DBGFR3TracerDeregisterEvtSrc(PVM pVM, DBGFTRACEREVTSRC hEvtSrc); +VMMR3_INT_DECL(int) DBGFR3TracerEvtIoPortCreate(PVM pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTIOPORT cPorts, uint32_t fFlags, + uint32_t iPciRegion); +VMMR3_INT_DECL(int) DBGFR3TracerEvtMmioCreate(PVM pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTGCPHYS cbRegion, uint32_t fFlags, + uint32_t iPciRegion); +#endif + +VMM_INT_DECL(int) DBGFTracerEvtMmioMap(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTGCPHYS GCPhysMmio); +VMM_INT_DECL(int) DBGFTracerEvtMmioUnmap(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion); +VMM_INT_DECL(int) DBGFTracerEvtMmioRead(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTGCPHYS offMmio, const void *pvVal, size_t cbVal); +VMM_INT_DECL(int) DBGFTracerEvtMmioWrite(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTGCPHYS offMmio, const void *pvVal, size_t cbVal); +VMM_INT_DECL(int) DBGFTracerEvtMmioFill(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTGCPHYS offMmio, uint32_t u32Item, uint32_t cbItem, uint32_t cItems); +VMM_INT_DECL(int) DBGFTracerEvtIoPortMap(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts, RTIOPORT IoPortBase); +VMM_INT_DECL(int) DBGFTracerEvtIoPortUnmap(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts); +VMM_INT_DECL(int) DBGFTracerEvtIoPortRead(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts, RTIOPORT offPort, const void *pvVal, size_t cbVal); +VMM_INT_DECL(int) DBGFTracerEvtIoPortReadStr(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts, RTIOPORT offPort, const void *pv, size_t cb, + uint32_t cTransfersReq, uint32_t cTransfersRet); +VMM_INT_DECL(int) DBGFTracerEvtIoPortWrite(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts, RTIOPORT offPort, const void *pvVal, size_t cbVal); +VMM_INT_DECL(int) DBGFTracerEvtIoPortWriteStr(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts, RTIOPORT offPort, const void *pv, size_t cb, + uint32_t cTransfersReq, uint32_t cTransfersRet); +VMM_INT_DECL(int) DBGFTracerEvtIrq(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, int32_t iIrq, int32_t fIrqLvl); +VMM_INT_DECL(int) DBGFTracerEvtIoApicMsi(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, RTGCPHYS GCPhys, uint32_t u32Val); +VMM_INT_DECL(int) DBGFTracerEvtGCPhysRead(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, RTGCPHYS GCPhys, const void *pvBuf, size_t cbRead); +VMM_INT_DECL(int) DBGFTracerEvtGCPhysWrite(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite); +/** @} */ + + +/** @defgroup grp_dbgf_sample_report DBGF sample report. + * @{ */ + +/** + * Callback which provides progress information about a currently running + * lengthy operation. + * + * @return VBox status code. + * @retval VERR_DBGF_CANCELLED to cancel the operation. + * @param pvUser The opaque user data associated with this interface. + * @param uPercentage Completion percentage. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFPROGRESS,(void *pvUser, unsigned uPercentage)); +/** Pointer to FNDBGFPROGRESS() */ +typedef FNDBGFPROGRESS *PFNDBGFPROGRESS; + +/** @name Flags to pass to DBGFR3SampleReportCreate(). + * @{ */ +/** The report creates the call stack in reverse order (bottom to top). */ +#define DBGF_SAMPLE_REPORT_F_STACK_REVERSE RT_BIT(0) +/** Mask containing the valid flags. */ +#define DBGF_SAMPLE_REPORT_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +VMMR3DECL(int) DBGFR3SampleReportCreate(PUVM pUVM, uint32_t cSampleIntervalMs, uint32_t fFlags, PDBGFSAMPLEREPORT phSample); +VMMR3DECL(uint32_t) DBGFR3SampleReportRetain(DBGFSAMPLEREPORT hSample); +VMMR3DECL(uint32_t) DBGFR3SampleReportRelease(DBGFSAMPLEREPORT hSample); +VMMR3DECL(int) DBGFR3SampleReportStart(DBGFSAMPLEREPORT hSample, uint64_t cSampleUs, PFNDBGFPROGRESS pfnProgress, void *pvUser); +VMMR3DECL(int) DBGFR3SampleReportStop(DBGFSAMPLEREPORT hSample); +VMMR3DECL(int) DBGFR3SampleReportDumpToFile(DBGFSAMPLEREPORT hSample, const char *pszFilename); +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_dbgf_h */ + diff --git a/include/VBox/vmm/dbgfcorefmt.h b/include/VBox/vmm/dbgfcorefmt.h new file mode 100644 index 00000000..c2b0cd5e --- /dev/null +++ b/include/VBox/vmm/dbgfcorefmt.h @@ -0,0 +1,188 @@ +/** @file + * DBGF - Debugger Facility, VM Core File Format. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_dbgfcorefmt_h +#define VBOX_INCLUDED_vmm_dbgfcorefmt_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/cpumctx.h> +#include <iprt/assertcompile.h> + + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_dbgf_corefmt VM Core File Format + * @ingroup grp_dbgf + * + * @todo Add description of the core file format and how the structures in this + * file relate to it. Point to X86XSAVEAREA in x86.h for the CPU's + * FPU/SSE/AVX/XXX state. + * @todo Add the note names. + * + * @{ + */ + +/** DBGCORECOREDESCRIPTOR::u32Magic. */ +#define DBGFCORE_MAGIC UINT32_C(0xc01ac0de) +/** DBGCORECOREDESCRIPTOR::u32FmtVersion. */ +#define DBGFCORE_FMT_VERSION UINT32_C(0x00010006) + +/** + * An x86 segment selector. + */ +typedef struct DBGFCORESEL +{ + uint64_t uBase; + uint32_t uLimit; + uint32_t uAttr; + uint16_t uSel; + uint16_t uReserved0; + uint32_t uReserved1; +} DBGFCORESEL; +AssertCompileSizeAlignment(DBGFCORESEL, 8); + +/** + * A gdtr/ldtr descriptor. + */ +typedef struct DBGFCOREXDTR +{ + uint64_t uAddr; + uint32_t cb; + uint32_t uReserved0; +} DBGFCOREXDTR; +AssertCompileSizeAlignment(DBGFCOREXDTR, 8); + +/** + * A simpler to parse CPU dump than CPUMCTX. + * + * Please bump DBGFCORE_FMT_VERSION by 1 if you make any changes to this + * structure. + */ +typedef struct DBGFCORECPU +{ + uint64_t rax; + uint64_t rbx; + uint64_t rcx; + uint64_t rdx; + uint64_t rsi; + uint64_t rdi; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rip; + uint64_t rsp; + uint64_t rbp; + uint64_t rflags; + DBGFCORESEL cs; + DBGFCORESEL ds; + DBGFCORESEL es; + DBGFCORESEL fs; + DBGFCORESEL gs; + DBGFCORESEL ss; + uint64_t cr0; + uint64_t cr2; + uint64_t cr3; + uint64_t cr4; + uint64_t dr[8]; + DBGFCOREXDTR gdtr; + DBGFCOREXDTR idtr; + DBGFCORESEL ldtr; + DBGFCORESEL tr; + struct + { + uint64_t cs; + uint64_t eip; + uint64_t esp; + } sysenter; + uint64_t msrEFER; + uint64_t msrSTAR; + uint64_t msrPAT; + uint64_t msrLSTAR; + uint64_t msrCSTAR; + uint64_t msrSFMASK; + uint64_t msrKernelGSBase; + uint64_t msrApicBase; + uint64_t msrTscAux; + uint64_t aXcr[2]; + uint32_t cbExt; + uint32_t uPadding0; + X86XSAVEAREA ext; +} DBGFCORECPU; +/** Pointer to a DBGF-core CPU. */ +typedef DBGFCORECPU *PDBGFCORECPU; +/** Pointer to the const DBGF-core CPU. */ +typedef const DBGFCORECPU *PCDBGFCORECPU; +AssertCompileMemberAlignment(DBGFCORECPU, cr0, 8); +AssertCompileMemberAlignment(DBGFCORECPU, msrEFER, 8); +AssertCompileMemberAlignment(DBGFCORECPU, ext, 8); +AssertCompileSizeAlignment(DBGFCORECPU, 8); + +/** + * The DBGF Core descriptor. + */ +typedef struct DBGFCOREDESCRIPTOR +{ + /** The core file magic (DBGFCORE_MAGIC) */ + uint32_t u32Magic; + /** The core file format version (DBGFCORE_FMT_VERSION). */ + uint32_t u32FmtVersion; + /** Size of this structure (sizeof(DBGFCOREDESCRIPTOR)). */ + uint32_t cbSelf; + /** VirtualBox version. */ + uint32_t u32VBoxVersion; + /** VirtualBox revision. */ + uint32_t u32VBoxRevision; + /** Number of CPUs. */ + uint32_t cCpus; +} DBGFCOREDESCRIPTOR; +AssertCompileSizeAlignment(DBGFCOREDESCRIPTOR, 8); +/** Pointer to DBGFCOREDESCRIPTOR data. */ +typedef DBGFCOREDESCRIPTOR *PDBGFCOREDESCRIPTOR; + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_dbgfcorefmt_h */ + diff --git a/include/VBox/vmm/dbgfflowtrace.h b/include/VBox/vmm/dbgfflowtrace.h new file mode 100644 index 00000000..4906fe7e --- /dev/null +++ b/include/VBox/vmm/dbgfflowtrace.h @@ -0,0 +1,400 @@ +/** @file + * DBGF - Debugger Facility, Guest execution flow tracing. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_dbgfflowtrace_h +#define VBOX_INCLUDED_vmm_dbgfflowtrace_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/dbgf.h> + +RT_C_DECLS_BEGIN +/** @defgroup grp_dbgf_flowtrace Guest Execution Flow Tracing + * @ingroup grp_dbgf + * + * @{ + */ + +/** A DBGF flow trace module handle. */ +typedef struct DBGFFLOWTRACEMODINT *DBGFFLOWTRACEMOD; +/** Pointer to a DBGF flow trace module handle. */ +typedef DBGFFLOWTRACEMOD *PDBGFFLOWTRACEMOD; +/** A DBGF flow trace probe handle. */ +typedef struct DBGFFLOWTRACEPROBEINT *DBGFFLOWTRACEPROBE; +/** Pointer to a DBGF flow trace state probe handle. */ +typedef DBGFFLOWTRACEPROBE *PDBGFFLOWTRACEPROBE; +/** A DBGF flow trace report handle. */ +typedef struct DBGFFLOWTRACEREPORTINT *DBGFFLOWTRACEREPORT; +/** Pointer to a DBGF flow trace report handle. */ +typedef DBGFFLOWTRACEREPORT *PDBGFFLOWTRACEREPORT; +/** A DBGF flow trace record handle. */ +typedef struct DBGFFLOWTRACERECORDINT *DBGFFLOWTRACERECORD; +/** Pointer to a DBGF flow trace record handle. */ +typedef DBGFFLOWTRACERECORD *PDBGFFLOWTRACERECORD; + + +/** Pointer to a flow trace probe entry. */ +typedef struct DBGFFLOWTRACEPROBEENTRY *PDBGFFLOWTRACEPROBEENTRY; +/** Pointer to a const flow trace probe entry. */ +typedef const struct DBGFFLOWTRACEPROBEENTRY *PCDBGFFLOWTRACEPROBEENTRY; + +/** @name Flags controlling the type of the addition of a single probe. + * @{ */ +/** Default options. */ +#define DBGF_FLOW_TRACE_PROBE_ADD_F_DEFAULT DBGF_FLOW_TRACE_PROBE_ADD_F_BEFORE_EXEC +/** Collects the data specified by the data probe before the instruction is executed. */ +#define DBGF_FLOW_TRACE_PROBE_ADD_F_BEFORE_EXEC RT_BIT_32(0) +/** Collects the data specified by the data probe after the instruction was executed. */ +#define DBGF_FLOW_TRACE_PROBE_ADD_F_AFTER_EXEC RT_BIT_32(1) +/** Mask of all valid flags. */ +#define DBGF_FLOW_TRACE_PROBE_ADD_F_VALID_MASK ( DBGF_FLOW_TRACE_PROBE_ADD_F_BEFORE_EXEC \ + | DBGF_FLOW_TRACE_PROBE_ADD_F_AFTER_EXEC) +/** @} */ + + +/** + * Probe entry type. + */ +typedef enum DBGFFLOWTRACEPROBEENTRYTYPE +{ + /** Invalid type. */ + DBGFFLOWTRACEPROBEENTRYTYPE_INVALID = 0, + /** Register. */ + DBGFFLOWTRACEPROBEENTRYTYPE_REG, + /** Constant memory buffer pointer. */ + DBGFFLOWTRACEPROBEENTRYTYPE_CONST_MEM, + /** Indirect memory buffer pointer, obtained from the base and index register + * and a constant scale. */ + DBGFFLOWTRACEPROBEENTRYTYPE_INDIRECT_MEM, + /** Callback. */ + DBGFFLOWTRACEPROBEENTRYTYPE_CALLBACK, + /** Halt in the debugger when the entry is collected. */ + DBGFFLOWTRACEPROBEENTRYTYPE_DEBUGGER, + /** 32bit hack. */ + DBGFFLOWTRACEPROBEENTRYTYPE_32BIT_HACK = 0x7fffffff +} DBGFFLOWTRACEPROBEENTRYTYPE; + + +/** + * Register descriptor for a probe entry. + */ +typedef struct DBGFFLOWTRACEPROBEENTRYREG +{ + /** The register name - see DBGFR3RegNm*. */ + const char *pszName; + /** The size of the value in bytes. */ + DBGFREGVALTYPE enmType; +} DBGFFLOWTRACEPROBEENTRYREG; +/** Pointer to data probe register entry. */ +typedef DBGFFLOWTRACEPROBEENTRYREG *PDBGFFLOWTRACEPROBEENTRYREG; +/** Pointer to a const probe register entry. */ +typedef const DBGFFLOWTRACEPROBEENTRYREG *PCDBGFFLOWTRACEPROBEENTRYREG; + + +/** + * Flow trace probe callback. + * + * @returns VBox status code, any error aborts continuing fetching the data for the + * probe containing this callback. + * @param pUVM The usermode VM handle. + * @param idCpu The ID of the vCPU the probe as fired. + * @param hFlowTraceMod The handle to the flow trace module the probe was fired for. + * @param pAddrProbe The guest address the probe was fired at. + * @param hFlowTraceProbe The flow trace probe handle.this callback is in. + * @param pProbeEntry The probe entry this callback is part of. + * @param pvUser The opaque user data for the callback. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFFLOWTRACEPROBECALLBACK, (PUVM pUVM, VMCPUID idCpu, DBGFFLOWTRACEMOD hFlowTraceMod, + PCDBGFADDRESS pAddrProbe, DBGFFLOWTRACEPROBE hFlowTraceProbe, + PCDBGFFLOWTRACEPROBEENTRY pProbeEntry, + void *pvUser)); +/** Pointer to a flow trace probe callback. */ +typedef FNDBGFFLOWTRACEPROBECALLBACK *PFNDBGFFLOWTRACEPROBECALLBACK; + + +/** + * Trace flow probe entry. + */ +typedef struct DBGFFLOWTRACEPROBEENTRY +{ + /** Entry type. */ + DBGFFLOWTRACEPROBEENTRYTYPE enmType; + /** Description for this entry, optional. */ + const char *pszDesc; + /** The data based on the entry type. */ + union + { + /** Register. */ + DBGFFLOWTRACEPROBEENTRYREG Reg; + /** Constant memory pointer. */ + struct + { + /** The address of the memory buffer. */ + DBGFADDRESS AddrMem; + /** Number of bytes to log. */ + size_t cbMem; + } ConstMem; + /** Indirect memory */ + struct + { + /** The base register. */ + DBGFFLOWTRACEPROBEENTRYREG RegBase; + /** The index register. */ + DBGFFLOWTRACEPROBEENTRYREG RegIndex; + /** The scale to apply to the index. */ + uint8_t uScale; + /** A constant offset which is applied at the end. */ + RTGCINTPTR iOffset; + /** Number of bytes to log. */ + size_t cbMem; + } IndirectMem; + /** Callback. */ + struct + { + /** The callback to call. */ + PFNDBGFFLOWTRACEPROBECALLBACK pfnCallback; + /** The opaque user data to provide. */ + void *pvUser; + } Callback; + } Type; +} DBGFFLOWTRACEPROBEENTRY; + + +/** + * Flow trace probe value. + */ +typedef struct DBGFFLOWTRACEPROBEVAL +{ + /** Pointer to the flow trace probe entry this value is for. */ + PCDBGFFLOWTRACEPROBEENTRY pProbeEntry; + /** Data based on the type in the entry. */ + union + { + /** Register value. */ + DBGFREGENTRYNM Reg; + /** Memory value (constant pointer or indirect). */ + struct + { + /** The guest address logged. */ + DBGFADDRESS Addr; + /** Pointer to the data logged. */ + const void *pvBuf; + /** Number of bytes logged. */ + size_t cbBuf; + } Mem; + } Type; +} DBGFFLOWTRACEPROBEVAL; +/** Pointer to a flow trace probe value. */ +typedef DBGFFLOWTRACEPROBEVAL *PDBGFFLOWTRACEPROBEVAL; +/** Pointer to a const flow trace probe value. */ +typedef const DBGFFLOWTRACEPROBEVAL *PCDBGFFLOWTRACEPROBEVAL; + +/** + * Flow trace report filter operation. + */ +typedef enum DBGFFLOWTRACEREPORTFILTEROP +{ + /** Invalid filter operation. */ + DBGFFLOWTRACEREPORTFILTEROP_INVALID = 0, + /** All filters must match with the record. */ + DBGFFLOWTRACEREPORTFILTEROP_AND, + /** Only one filter must match with the record. */ + DBGFFLOWTRACEREPORTFILTEROP_OR, + /** 32bit hack. */ + DBGFFLOWTRACEREPORTFILTEROP_32BIT_HACK = 0x7fffffff +} DBGFFLOWTRACEREPORTFILTEROP; + + +/** + * Flow trace report filter type. + */ +typedef enum DBGFFLOWTRACEREPORTFILTERTYPE +{ + /** Invalid filter type. */ + DBGFFLOWTRACEREPORTFILTERTYPE_INVALID = 0, + /** Filter by sequence number. */ + DBGFFLOWTRACEREPORTFILTERTYPE_SEQ_NUM, + /** Filter by timestamp. */ + DBGFFLOWTRACEREPORTFILTERTYPE_TIMESTAMP, + /** Filter by probe address. */ + DBGFFLOWTRACEREPORTFILTERTYPE_ADDR, + /** Filter by CPU ID. */ + DBGFFLOWTRACEREPORTFILTERTYPE_VMCPU_ID, + /** Filter by specific probe data. */ + DBGFFLOWTRACEREPORTFILTERTYPE_PROBE_DATA, + /** 32bit hack. */ + DBGFFLOWTRACEREPORTFILTERTYPE_32BIT_HACK = 0x7fffffff +} DBGFFLOWTRACEREPORTFILTERTYPE; + + +/** + * Flow trace report filter. + */ +typedef struct DBGFFLOWTRACEREPORTFILTER +{ + /** Filter type. */ + DBGFFLOWTRACEREPORTFILTERTYPE enmType; + /** Filter data, type dependent. */ + struct + { + /** Sequence number filtering. */ + struct + { + /** Sequence number filtering, start value. */ + uint64_t u64SeqNoFirst; + /** Sequence number filtering, last value. */ + uint64_t u64SeqNoLast; + } SeqNo; + /** Timestamp filtering. */ + struct + { + /** Start value. */ + uint64_t u64TsFirst; + /** Last value. */ + uint64_t u64TsLast; + } Timestamp; + /** Probe address filtering. */ + struct + { + /** Start address. */ + DBGFADDRESS AddrStart; + /** Last address. */ + DBGFADDRESS AddrLast; + } Addr; + /** vCPU id filtering. */ + struct + { + /** Start CPU id. */ + VMCPUID idCpuStart; + /** Last CPU id. */ + VMCPUID idCpuLast; + } VCpuId; + /** Probe data filtering. */ + struct + { + /** Pointer to the probe value array. */ + PCDBGFFLOWTRACEPROBEVAL paVal; + /** Number of entries in the array for filtering. */ + uint32_t cVals; + /** Flag whether to look into the common values or the probe specific ones. */ + bool fValCmn; + } ProbeData; + } Type; +} DBGFFLOWTRACEREPORTFILTER; +/** Pointer to a flow trace report filter. */ +typedef DBGFFLOWTRACEREPORTFILTER *PDBGFFLOWTRACEREPORTFILTER; + + +/** @name Flags controlling filtering records. + * @{ */ +/** Add records which don't match the filter. */ +#define DBGF_FLOW_TRACE_REPORT_FILTER_F_REVERSE RT_BIT_32(0) +/** Mask of all valid flags. */ +#define DBGF_FLOW_TRACE_REPORT_FILTER_F_VALID (DBGF_FLOW_TRACE_REPORT_FILTER_F_REVERSE) +/** @} */ + + +/** + * Flow trace report enumeration callback. + * + * @returns VBox status code, any non VINF_SUCCESS code aborts the enumeration and is returned + * by DBGFR3FlowTraceReportEnumRecords(). + * @param hFlowTraceReport The flow trace report handle being enumerated. + * @param hFlowTraceRecord The flow trace record handle. + * @param pvUser Opaque user data given in DBGFR3FlowTraceReportEnumRecords(). + */ +typedef DECLCALLBACKTYPE(int, FNDBGFFLOWTRACEREPORTENUMCLBK,(DBGFFLOWTRACEREPORT hFlowTraceReport, + DBGFFLOWTRACERECORD hFlowTraceRecord, + void *pvUser)); +/** Pointer to a record enumeration callback. */ +typedef FNDBGFFLOWTRACEREPORTENUMCLBK *PFNDBGFFLOWTRACEREPORTENUMCLBK; + + +VMMR3DECL(int) DBGFR3FlowTraceModCreate(PUVM pUVM, VMCPUID idCpu, + DBGFFLOWTRACEPROBE hFlowTraceProbeCommon, + PDBGFFLOWTRACEMOD phFlowTraceMod); +VMMR3DECL(int) DBGFR3FlowTraceModCreateFromFlowGraph(PUVM pUVM, VMCPUID idCpu, DBGFFLOW hFlow, + DBGFFLOWTRACEPROBE hFlowTraceProbeCommon, + DBGFFLOWTRACEPROBE hFlowTraceProbeEntry, + DBGFFLOWTRACEPROBE hFlowTraceProbeRegular, + DBGFFLOWTRACEPROBE hFlowTraceProbeExit, + PDBGFFLOWTRACEMOD phFlowTraceMod); +VMMR3DECL(uint32_t) DBGFR3FlowTraceModRetain(DBGFFLOWTRACEMOD hFlowTraceMod); +VMMR3DECL(uint32_t) DBGFR3FlowTraceModRelease(DBGFFLOWTRACEMOD hFlowTraceMod); +VMMR3DECL(int) DBGFR3FlowTraceModEnable(DBGFFLOWTRACEMOD hFlowTraceMod, uint32_t cHits, uint32_t cRecordsMax); +VMMR3DECL(int) DBGFR3FlowTraceModDisable(DBGFFLOWTRACEMOD hFlowTraceMod); +VMMR3DECL(int) DBGFR3FlowTraceModQueryReport(DBGFFLOWTRACEMOD hFlowTraceMod, + PDBGFFLOWTRACEREPORT phFlowTraceReport); +VMMR3DECL(int) DBGFR3FlowTraceModClear(DBGFFLOWTRACEMOD hFlowTraceMod); +VMMR3DECL(int) DBGFR3FlowTraceModAddProbe(DBGFFLOWTRACEMOD hFlowTraceMod, PCDBGFADDRESS pAddrProbe, + DBGFFLOWTRACEPROBE hFlowTraceProbe, uint32_t fFlags); + +VMMR3DECL(int) DBGFR3FlowTraceProbeCreate(PUVM pUVM, const char *pszDescr, PDBGFFLOWTRACEPROBE phFlowTraceProbe); +VMMR3DECL(uint32_t) DBGFR3FlowTraceProbeRetain(DBGFFLOWTRACEPROBE hFlowTraceProbe); +VMMR3DECL(uint32_t) DBGFR3FlowTraceProbeRelease(DBGFFLOWTRACEPROBE hFlowTraceProbe); +VMMR3DECL(int) DBGFR3FlowTraceProbeEntriesAdd(DBGFFLOWTRACEPROBE hFlowTraceProbe, + PCDBGFFLOWTRACEPROBEENTRY paEntries, uint32_t cEntries); + +VMMR3DECL(uint32_t) DBGFR3FlowTraceReportRetain(DBGFFLOWTRACEREPORT hFlowTraceReport); +VMMR3DECL(uint32_t) DBGFR3FlowTraceReportRelease(DBGFFLOWTRACEREPORT hFlowTraceReport); +VMMR3DECL(uint32_t) DBGFR3FlowTraceReportGetRecordCount(DBGFFLOWTRACEREPORT hFlowTraceReport); +VMMR3DECL(int) DBGFR3FlowTraceReportQueryRecord(DBGFFLOWTRACEREPORT hFlowTraceReport, uint32_t idxRec, PDBGFFLOWTRACERECORD phFlowTraceRec); +VMMR3DECL(int) DBGFR3FlowTraceReportQueryFiltered(DBGFFLOWTRACEREPORT hFlowTraceReport, uint32_t fFlags, + PDBGFFLOWTRACEREPORTFILTER paFilters, uint32_t cFilters, + DBGFFLOWTRACEREPORTFILTEROP enmOp, + PDBGFFLOWTRACEREPORT phFlowTraceReportFiltered); +VMMR3DECL(int) DBGFR3FlowTraceReportEnumRecords(DBGFFLOWTRACEREPORT hFlowTraceReport, + PFNDBGFFLOWTRACEREPORTENUMCLBK pfnEnum, + void *pvUser); + +VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordRetain(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordRelease(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(uint64_t) DBGFR3FlowTraceRecordGetSeqNo(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(uint64_t) DBGFR3FlowTraceRecordGetTimestamp(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowTraceRecordGetAddr(DBGFFLOWTRACERECORD hFlowTraceRecord, PDBGFADDRESS pAddr); +VMMR3DECL(DBGFFLOWTRACEPROBE) DBGFR3FlowTraceRecordGetProbe(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordGetValCount(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordGetValCommonCount(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(PCDBGFFLOWTRACEPROBEVAL) DBGFR3FlowTraceRecordGetVals(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(PCDBGFFLOWTRACEPROBEVAL) DBGFR3FlowTraceRecordGetValsCommon(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(VMCPUID) DBGFR3FlowTraceRecordGetCpuId(DBGFFLOWTRACERECORD hFlowTraceRecord); + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_dbgfflowtrace_h */ + diff --git a/include/VBox/vmm/dbgfsel.h b/include/VBox/vmm/dbgfsel.h new file mode 100644 index 00000000..a531ec6f --- /dev/null +++ b/include/VBox/vmm/dbgfsel.h @@ -0,0 +1,117 @@ +/** @file + * DBGF - Debugger Facility, selector interface partly shared with SELM. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_dbgfsel_h +#define VBOX_INCLUDED_vmm_dbgfsel_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/x86.h> + + +/** @addtogroup grp_dbgf + * @{ */ + +/** + * Selector information structure. + */ +typedef struct DBGFSELINFO +{ + /** The base address. + * For gate descriptors, this is the target address. */ + RTGCPTR GCPtrBase; + /** The limit (-1). + * For gate descriptors, this is set to zero. */ + RTGCUINTPTR cbLimit; + /** The raw descriptor. */ + union + { + X86DESC Raw; + X86DESC64 Raw64; + } u; + /** The selector. */ + RTSEL Sel; + /** The target selector for a gate. + * This is 0 if non-gate descriptor. */ + RTSEL SelGate; + /** Flags. */ + uint32_t fFlags; +} DBGFSELINFO; +/** Pointer to a SELM selector information struct. */ +typedef DBGFSELINFO *PDBGFSELINFO; +/** Pointer to a const SELM selector information struct. */ +typedef const DBGFSELINFO *PCDBGFSELINFO; + +/** @name DBGFSELINFO::fFlags + * @{ */ +/** The CPU is in real mode. */ +#define DBGFSELINFO_FLAGS_REAL_MODE RT_BIT_32(0) +/** The CPU is in protected mode. */ +#define DBGFSELINFO_FLAGS_PROT_MODE RT_BIT_32(1) +/** The CPU is in long mode. */ +#define DBGFSELINFO_FLAGS_LONG_MODE RT_BIT_32(2) +/** The selector is a hyper selector. + * @todo remove me! */ +#define DBGFSELINFO_FLAGS_HYPER RT_BIT_32(3) +/** The selector is a gate selector. */ +#define DBGFSELINFO_FLAGS_GATE RT_BIT_32(4) +/** The selector is invalid. */ +#define DBGFSELINFO_FLAGS_INVALID RT_BIT_32(5) +/** The selector not present. */ +#define DBGFSELINFO_FLAGS_NOT_PRESENT RT_BIT_32(6) +/** @} */ + + +/** + * Tests whether the selector info describes an expand-down selector or now. + * + * @returns true / false. + * @param pSelInfo The selector info. + */ +DECLINLINE(bool) DBGFSelInfoIsExpandDown(PCDBGFSELINFO pSelInfo) +{ + return (pSelInfo)->u.Raw.Gen.u1DescType + && ((pSelInfo)->u.Raw.Gen.u4Type & (X86_SEL_TYPE_DOWN | X86_SEL_TYPE_CODE)) == X86_SEL_TYPE_DOWN; +} + + +VMMR3DECL(int) DBGFR3SelInfoValidateCS(PCDBGFSELINFO pSelInfo, RTSEL SelCPL); + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_dbgfsel_h */ + diff --git a/include/VBox/vmm/dbgftrace.h b/include/VBox/vmm/dbgftrace.h new file mode 100644 index 00000000..254cc677 --- /dev/null +++ b/include/VBox/vmm/dbgftrace.h @@ -0,0 +1,168 @@ +/** @file + * DBGF - Debugger Facility. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_dbgftrace_h +#define VBOX_INCLUDED_vmm_dbgftrace_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/trace.h> +#include <VBox/types.h> + +RT_C_DECLS_BEGIN +/** @defgroup grp_dbgf_trace Tracing + * @ingroup grp_dbgf + * + * @{ + */ + +#if (defined(RTTRACE_ENABLED) || defined(DBGFTRACE_ENABLED)) && !defined(DBGFTRACE_DISABLED) +# undef DBGFTRACE_ENABLED +# undef DBGFTRACE_DISABLED +# define DBGFTRACE_ENABLED +#else +# undef DBGFTRACE_ENABLED +# undef DBGFTRACE_DISABLED +# define DBGFTRACE_DISABLED +#endif + +VMMDECL(int) DBGFR3TraceConfig(PVM pVM, const char *pszConfig); + + +/** @name VMM Internal Trace Macros + * @remarks The user of these macros is responsible of including VBox/vmm/vm.h. + * @{ + */ +/** + * Records a 64-bit unsigned integer together with a tag string. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_U64_TAG(a_pVM, a_u64, a_pszTag) \ + do { RTTraceBufAddMsgF((a_pVM)->CTX_SUFF(hTraceBuf), "%'llu %s", (a_u64), (a_pszTag)); } while (0) +#else +# define DBGFTRACE_U64_TAG(a_pVM, a_u64, a_pszTag) do { } while (0) +#endif + +/** + * Records a 64-bit unsigned integer together with two tag strings. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_U64_TAG2(a_pVM, a_u64, a_pszTag1, a_pszTag2) \ + do { RTTraceBufAddMsgF((a_pVM)->CTX_SUFF(hTraceBuf), "%'llu %s %s", (a_u64), (a_pszTag1), (a_pszTag2)); } while (0) +#else +# define DBGFTRACE_U64_TAG2(a_pVM, a_u64, a_pszTag1, a_pszTag2) do { } while (0) +#endif + +#ifdef RT_COMPILER_SUPPORTS_VA_ARGS +/** + * Add a custom string (req. variadict macro support). + */ +# ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_CUSTOM(a_pVM, ...) \ + do { RTTraceBufAddMsgF((a_pVM)->CTX_SUFF(hTraceBuf), __VA_ARGS__); } while (0) +# else +# define DBGFTRACE_CUSTOM(a_pVM, ...) do { } while (0) +# endif +#endif + +/** + * Records the current source position. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_POS(a_pVM) \ + do { RTTraceBufAddPos((a_pVM)->CTX_SUFF(hTraceBuf), RT_SRC_POS); } while (0) +#else +# define DBGFTRACE_POS(a_pVM) do { } while (0) +#endif + +/** + * Records the current source position along with a 64-bit unsigned integer. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_POS_U64(a_pVM, a_u64) \ + do { RTTraceBufAddPosMsgF((a_pVM)->CTX_SUFF(hTraceBuf), RT_SRC_POS, "%'llu", (a_u64)); } while (0) +#else +# define DBGFTRACE_POS_U64(a_pVM, a_u64) do { } while (0) +#endif +/** @} */ + + +/** @name Tracing Macros for PDM Devices, Drivers and USB Devices. + * @{ + */ + +/** + * Get the trace buffer handle. + * @param a_pIns The instance (pDevIns, pDrvIns or pUsbIns). + */ +#define DBGFTRACE_PDM_TRACEBUF(a_pIns) ( (a_pIns)->CTX_SUFF(pHlp)->pfnDBGFTraceBuf((a_pIns)) ) + +/** + * Records a tagged 64-bit unsigned integer. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_PDM_U64_TAG(a_pIns, a_u64, a_pszTag) \ + do { RTTraceBufAddMsgF(DBGFTRACE_PDM_TRACEBUF(a_pIns), "%'llu %s", (a_u64), (a_pszTag)); } while (0) +#else +# define DBGFTRACE_PDM_U64_TAG(a_pIns, a_u64, a_pszTag) do { } while (0) +#endif + +/** + * Records the current source position. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_PDM_POS(a_pIns) \ + do { RTTraceBufAddPos(DBGFTRACE_PDM_TRACEBUF(a_pIns), RT_SRC_POS); } while (0) +#else +# define DBGFTRACE_PDM_POS(a_pIns) do { } while (0) +#endif + +/** + * Records the current source position along with a 64-bit unsigned integer. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_PDM_POS_U64(a_pIns, a_u64) \ + do { RTTraceBufAddPosMsgF(DBGFTRACE_PDM_TRACEBUF(a_pIns), RT_SRC_POS, "%'llu", (a_u64)); } while (0) +#else +# define DBGFTRACE_PDM_POS_U64(a_pIns, a_u64) do { } while (0) +#endif +/** @} */ + + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_dbgftrace_h */ diff --git a/include/VBox/vmm/em.h b/include/VBox/vmm/em.h new file mode 100644 index 00000000..6ea1b65e --- /dev/null +++ b/include/VBox/vmm/em.h @@ -0,0 +1,345 @@ +/** @file + * EM - Execution Monitor. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_em_h +#define VBOX_INCLUDED_vmm_em_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/trpm.h> +#include <VBox/vmm/vmapi.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_em The Execution Monitor / Manager API + * @ingroup grp_vmm + * @{ + */ + +/** Enable to allow V86 code to run in raw mode. */ +#define VBOX_RAW_V86 + +/** + * The Execution Manager State. + * + * @remarks This is used in the saved state! + */ +typedef enum EMSTATE +{ + /** Not yet started. */ + EMSTATE_NONE = 1, + /** Raw-mode execution. */ + EMSTATE_RAW, + /** Hardware accelerated raw-mode execution. */ + EMSTATE_HM, + /** Executing in IEM. */ + EMSTATE_IEM, + /** Recompiled mode execution. */ + EMSTATE_REM, + /** Execution is halted. (waiting for interrupt) */ + EMSTATE_HALTED, + /** Application processor execution is halted. (waiting for startup IPI (SIPI)) */ + EMSTATE_WAIT_SIPI, + /** Execution is suspended. */ + EMSTATE_SUSPENDED, + /** The VM is terminating. */ + EMSTATE_TERMINATING, + /** Guest debug event from raw-mode is being processed. */ + EMSTATE_DEBUG_GUEST_RAW, + /** Guest debug event from hardware accelerated mode is being processed. */ + EMSTATE_DEBUG_GUEST_HM, + /** Guest debug event from interpreted execution mode is being processed. */ + EMSTATE_DEBUG_GUEST_IEM, + /** Guest debug event from recompiled-mode is being processed. */ + EMSTATE_DEBUG_GUEST_REM, + /** Hypervisor debug event being processed. */ + EMSTATE_DEBUG_HYPER, + /** The VM has encountered a fatal error. (And everyone is panicing....) */ + EMSTATE_GURU_MEDITATION, + /** Executing in IEM, falling back on REM if we cannot switch back to HM or + * RAW after a short while. */ + EMSTATE_IEM_THEN_REM, + /** Executing in native (API) execution monitor. */ + EMSTATE_NEM, + /** Guest debug event from NEM mode is being processed. */ + EMSTATE_DEBUG_GUEST_NEM, + /** Just a hack to ensure that we get a 32-bit integer. */ + EMSTATE_MAKE_32BIT_HACK = 0x7fffffff +} EMSTATE; + + +/** + * EMInterpretInstructionCPU execution modes. + */ +typedef enum +{ + /** Only supervisor code (CPL=0). */ + EMCODETYPE_SUPERVISOR, + /** User-level code only. */ + EMCODETYPE_USER, + /** Supervisor and user-level code (use with great care!). */ + EMCODETYPE_ALL, + /** Just a hack to ensure that we get a 32-bit integer. */ + EMCODETYPE_32BIT_HACK = 0x7fffffff +} EMCODETYPE; + +VMM_INT_DECL(EMSTATE) EMGetState(PVMCPU pVCpu); +VMM_INT_DECL(void) EMSetState(PVMCPU pVCpu, EMSTATE enmNewState); + +/** @name Callback handlers for instruction emulation functions. + * These are placed here because IOM wants to use them as well. + * @{ + */ +typedef DECLCALLBACKTYPE(uint32_t, FNEMULATEPARAM2UINT32,(void *pvParam1, uint64_t val2)); +typedef FNEMULATEPARAM2UINT32 *PFNEMULATEPARAM2UINT32; +typedef DECLCALLBACKTYPE(uint32_t, FNEMULATEPARAM2,(void *pvParam1, size_t val2)); +typedef FNEMULATEPARAM2 *PFNEMULATEPARAM2; +typedef DECLCALLBACKTYPE(uint32_t, FNEMULATEPARAM3,(void *pvParam1, uint64_t val2, size_t val3)); +typedef FNEMULATEPARAM3 *PFNEMULATEPARAM3; +typedef DECLCALLBACKTYPE(int, FNEMULATELOCKPARAM2,(void *pvParam1, uint64_t val2, RTGCUINTREG32 *pf)); +typedef FNEMULATELOCKPARAM2 *PFNEMULATELOCKPARAM2; +typedef DECLCALLBACKTYPE(int, FNEMULATELOCKPARAM3,(void *pvParam1, uint64_t val2, size_t cb, RTGCUINTREG32 *pf)); +typedef FNEMULATELOCKPARAM3 *PFNEMULATELOCKPARAM3; +/** @} */ + +VMMDECL(void) EMSetHypercallInstructionsEnabled(PVMCPU pVCpu, bool fEnabled); +VMMDECL(bool) EMAreHypercallInstructionsEnabled(PVMCPU pVCpu); +VMM_INT_DECL(bool) EMShouldContinueAfterHalt(PVMCPU pVCpu, PCPUMCTX pCtx); +VMM_INT_DECL(bool) EMMonitorWaitShouldContinue(PVMCPU pVCpu, PCPUMCTX pCtx); +VMM_INT_DECL(int) EMMonitorWaitPrepare(PVMCPU pVCpu, uint64_t rax, uint64_t rcx, uint64_t rdx, RTGCPHYS GCPhys); +VMM_INT_DECL(void) EMMonitorWaitClear(PVMCPU pVCpu); +VMM_INT_DECL(bool) EMMonitorIsArmed(PVMCPU pVCpu); +VMM_INT_DECL(unsigned) EMMonitorWaitIsActive(PVMCPU pVCpu); +VMM_INT_DECL(int) EMMonitorWaitPerform(PVMCPU pVCpu, uint64_t rax, uint64_t rcx); +VMM_INT_DECL(int) EMUnhaltAndWakeUp(PVMCC pVM, PVMCPUCC pVCpuDst); +VMMRZ_INT_DECL(VBOXSTRICTRC) EMRZSetPendingIoPortWrite(PVMCPU pVCpu, RTIOPORT uPort, uint8_t cbInstr, uint8_t cbValue, uint32_t uValue); +VMMRZ_INT_DECL(VBOXSTRICTRC) EMRZSetPendingIoPortRead(PVMCPU pVCpu, RTIOPORT uPort, uint8_t cbInstr, uint8_t cbValue); + +/** + * Common defined exit types that EM knows what to do about. + * + * These should be used instead of the VT-x, SVM or NEM specific ones for exits + * worth optimizing. + */ +typedef enum EMEXITTYPE +{ + EMEXITTYPE_INVALID = 0, + EMEXITTYPE_IO_PORT_READ, + EMEXITTYPE_IO_PORT_WRITE, + EMEXITTYPE_IO_PORT_STR_READ, + EMEXITTYPE_IO_PORT_STR_WRITE, + EMEXITTYPE_MMIO, + EMEXITTYPE_MMIO_READ, + EMEXITTYPE_MMIO_WRITE, + EMEXITTYPE_MSR_READ, + EMEXITTYPE_MSR_WRITE, + EMEXITTYPE_CPUID, + EMEXITTYPE_RDTSC, + EMEXITTYPE_MOV_CRX, + EMEXITTYPE_MOV_DRX, + EMEXITTYPE_VMREAD, + EMEXITTYPE_VMWRITE, + + /** @name Raw-mode only (for now), keep at end. + * @{ */ + EMEXITTYPE_INVLPG, + EMEXITTYPE_LLDT, + EMEXITTYPE_RDPMC, + EMEXITTYPE_CLTS, + EMEXITTYPE_STI, + EMEXITTYPE_INT, + EMEXITTYPE_SYSCALL, + EMEXITTYPE_SYSENTER, + EMEXITTYPE_HLT + /** @} */ +} EMEXITTYPE; +AssertCompileSize(EMEXITTYPE, 4); + +/** @name EMEXIT_F_XXX - EM exit flags. + * + * The flags the exit type are combined to a 32-bit number using the + * EMEXIT_MAKE_FT() macro. + * + * @{ */ +#define EMEXIT_F_TYPE_MASK UINT32_C(0x00000fff) /**< The exit type mask. */ +#define EMEXIT_F_KIND_EM UINT32_C(0x00000000) /**< EMEXITTYPE */ +#define EMEXIT_F_KIND_VMX UINT32_C(0x00001000) /**< VT-x exit codes. */ +#define EMEXIT_F_KIND_SVM UINT32_C(0x00002000) /**< SVM exit codes. */ +#define EMEXIT_F_KIND_NEM UINT32_C(0x00003000) /**< NEMEXITTYPE */ +#define EMEXIT_F_KIND_XCPT UINT32_C(0x00004000) /**< Exception numbers (raw-mode). */ +#define EMEXIT_F_KIND_MASK UINT32_C(0x00007000) +#define EMEXIT_F_CS_EIP UINT32_C(0x00010000) /**< The PC is EIP in the low dword and CS in the high. */ +#define EMEXIT_F_UNFLATTENED_PC UINT32_C(0x00020000) /**< The PC hasn't had CS.BASE added to it. */ +/** HM is calling (from ring-0). Preemption is currently disabled or we're using preemption hooks. */ +#define EMEXIT_F_HM UINT32_C(0x00040000) +/** Combines flags and exit type into EMHistoryAddExit() input. */ +#define EMEXIT_MAKE_FT(a_fFlags, a_uType) ((a_fFlags) | (uint32_t)(a_uType)) +/** @} */ + +typedef enum EMEXITACTION +{ + /** The record is free. */ + EMEXITACTION_FREE_RECORD = 0, + /** Take normal action on the exit. */ + EMEXITACTION_NORMAL, + /** Take normal action on the exit, already probed and found nothing. */ + EMEXITACTION_NORMAL_PROBED, + /** Do a probe execution. */ + EMEXITACTION_EXEC_PROBE, + /** Execute using EMEXITREC::cMaxInstructionsWithoutExit. */ + EMEXITACTION_EXEC_WITH_MAX +} EMEXITACTION; +AssertCompileSize(EMEXITACTION, 4); + +/** + * Accumulative exit record. + * + * This could perhaps be squeezed down a bit, but there isn't too much point. + * We'll probably need more data as time goes by. + */ +typedef struct EMEXITREC +{ + /** The flat PC of the exit. */ + uint64_t uFlatPC; + /** Flags and type, see EMEXIT_MAKE_FT. */ + uint32_t uFlagsAndType; + /** The action to take (EMEXITACTION). */ + uint8_t enmAction; + uint8_t bUnused; + /** Maximum number of instructions to execute without hitting an exit. */ + uint16_t cMaxInstructionsWithoutExit; + /** The exit number (EMCPU::iNextExit) at which it was last updated. */ + uint64_t uLastExitNo; + /** Number of hits. */ + uint64_t cHits; +} EMEXITREC; +AssertCompileSize(EMEXITREC, 32); +/** Pointer to an accumulative exit record. */ +typedef EMEXITREC *PEMEXITREC; +/** Pointer to a const accumulative exit record. */ +typedef EMEXITREC const *PCEMEXITREC; + +VMM_INT_DECL(PCEMEXITREC) EMHistoryAddExit(PVMCPUCC pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC, uint64_t uTimestamp); +#ifdef IN_RC +VMMRC_INT_DECL(void) EMRCHistoryAddExitCsEip(PVMCPU pVCpu, uint32_t uFlagsAndType, uint16_t uCs, uint32_t uEip, + uint64_t uTimestamp); +#endif +VMM_INT_DECL(void) EMHistoryUpdatePC(PVMCPUCC pVCpu, uint64_t uFlatPC, bool fFlattened); +VMM_INT_DECL(PCEMEXITREC) EMHistoryUpdateFlagsAndType(PVMCPUCC pVCpu, uint32_t uFlagsAndType); +VMM_INT_DECL(PCEMEXITREC) EMHistoryUpdateFlagsAndTypeAndPC(PVMCPUCC pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC); +VMM_INT_DECL(VBOXSTRICTRC) EMHistoryExec(PVMCPUCC pVCpu, PCEMEXITREC pExitRec, uint32_t fWillExit); + + +/** @name Deprecated interpretation related APIs (use IEM). + * @{ */ +VMM_INT_DECL(int) EMInterpretDisasCurrent(PVMCPUCC pVCpu, PDISCPUSTATE pCpu, unsigned *pcbInstr); +VMM_INT_DECL(int) EMInterpretDisasOneEx(PVMCPUCC pVCpu, RTGCUINTPTR GCPtrInstr, + PDISCPUSTATE pDISState, unsigned *pcbInstr); +VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInstruction(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInstructionDisasState(PVMCPUCC pVCpu, PDISCPUSTATE pDis, uint64_t rip); +/** @} */ + + +/** @name EM_ONE_INS_FLAGS_XXX - flags for EMR3HmSingleInstruction (et al). + * @{ */ +/** Return when CS:RIP changes or some other important event happens. + * This means running whole REP and LOOP $ sequences for instance. */ +#define EM_ONE_INS_FLAGS_RIP_CHANGE RT_BIT_32(0) +/** Mask of valid flags. */ +#define EM_ONE_INS_FLAGS_MASK UINT32_C(0x00000001) +/** @} */ + + +#ifdef IN_RING0 +/** @defgroup grp_em_r0 The EM Host Context Ring-0 API + * @{ */ +VMMR0_INT_DECL(int) EMR0InitVM(PGVM pGVM); +/** @} */ +#endif + + +#ifdef IN_RING3 +/** @defgroup grp_em_r3 The EM Host Context Ring-3 API + * @{ + */ + +/** + * Command argument for EMR3RawSetMode(). + * + * It's possible to extend this interface to change several + * execution modes at once should the need arise. + */ +typedef enum EMEXECPOLICY +{ + /** The customary invalid zero entry. */ + EMEXECPOLICY_INVALID = 0, + /** Whether to recompile ring-0 code or execute it in raw/hm. */ + EMEXECPOLICY_RECOMPILE_RING0, + /** Whether to recompile ring-3 code or execute it in raw/hm. */ + EMEXECPOLICY_RECOMPILE_RING3, + /** Whether to only use IEM for execution. */ + EMEXECPOLICY_IEM_ALL, + /** End of valid value (not included). */ + EMEXECPOLICY_END, + /** The customary 32-bit type blowup. */ + EMEXECPOLICY_32BIT_HACK = 0x7fffffff +} EMEXECPOLICY; +VMMR3DECL(int) EMR3SetExecutionPolicy(PUVM pUVM, EMEXECPOLICY enmPolicy, bool fEnforce); +VMMR3DECL(int) EMR3QueryExecutionPolicy(PUVM pUVM, EMEXECPOLICY enmPolicy, bool *pfEnforced); +VMMR3DECL(int) EMR3QueryMainExecutionEngine(PUVM pUVM, uint8_t *pbMainExecutionEngine); + +VMMR3_INT_DECL(int) EMR3Init(PVM pVM); +VMMR3_INT_DECL(int) EMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3_INT_DECL(void) EMR3Relocate(PVM pVM); +VMMR3_INT_DECL(void) EMR3ResetCpu(PVMCPU pVCpu); +VMMR3_INT_DECL(void) EMR3Reset(PVM pVM); +VMMR3_INT_DECL(int) EMR3Term(PVM pVM); +VMMR3DECL(DECL_NO_RETURN(void)) EMR3FatalError(PVMCPU pVCpu, int rc); +VMMR3_INT_DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(int) EMR3CheckRawForcedActions(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(VBOXSTRICTRC) EMR3HmSingleInstruction(PVM pVM, PVMCPU pVCpu, uint32_t fFlags); + +/** @} */ +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_em_h */ + diff --git a/include/VBox/vmm/gcm.h b/include/VBox/vmm/gcm.h new file mode 100644 index 00000000..0b3102c7 --- /dev/null +++ b/include/VBox/vmm/gcm.h @@ -0,0 +1,95 @@ +/** @file + * GCM - Guest Compatibility Manager. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_gcm_h +#define VBOX_INCLUDED_vmm_gcm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <VBox/param.h> + +#include <VBox/vmm/cpum.h> +#include <VBox/vmm/pdmifs.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_gcm The Guest Compatibility Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * GCM Fixer Identifiers. + * @remarks Part of saved state! + */ +typedef enum GCMFIXERID +{ + /** None. */ + GCMFIXER_NONE = 0, + /** DOS division by zero, the worst. Includes Windows 3.x. */ + GCMFIXER_DBZ_DOS = RT_BIT(0), + /** OS/2 (any version) division by zero. */ + GCMFIXER_DBZ_OS2 = RT_BIT(1), + /** Windows 9x division by zero. */ + GCMFIXER_DBZ_WIN9X = RT_BIT(2), + /** 32-bit hack. */ + GCMFIXER_32BIT_HACK = 0x7fffffff +} GCMFIXERID; +AssertCompileSize(GCMFIXERID, sizeof(uint32_t)); + + +#ifdef IN_RING3 +/** @defgroup grp_gcm_r3 The GCM Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(int) GCMR3Init(PVM pVM); +VMMR3_INT_DECL(void) GCMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) GCMR3Term(PVM pVM); +VMMR3_INT_DECL(void) GCMR3Reset(PVM pVM); +/** @} */ +#endif /* IN_RING3 */ + +VMMDECL(bool) GCMIsEnabled(PVM pVM); +VMM_INT_DECL(bool) GCMShouldTrapXcptDE(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) GCMXcptDE(PVMCPUCC pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr); +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_gcm_h */ + diff --git a/include/VBox/vmm/gim.h b/include/VBox/vmm/gim.h new file mode 100644 index 00000000..b62e1a1e --- /dev/null +++ b/include/VBox/vmm/gim.h @@ -0,0 +1,218 @@ +/** @file + * GIM - Guest Interface Manager. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_gim_h +#define VBOX_INCLUDED_vmm_gim_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <VBox/param.h> + +#include <VBox/vmm/cpum.h> +#include <VBox/vmm/pdmifs.h> + +/** The value used to specify that VirtualBox must use the newest + * implementation version of the GIM provider. */ +#define GIM_VERSION_LATEST UINT32_C(0) + +RT_C_DECLS_BEGIN + +/** @defgroup grp_gim The Guest Interface Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * GIM Provider Identifiers. + * @remarks Part of saved state! + */ +typedef enum GIMPROVIDERID +{ + /** None. */ + GIMPROVIDERID_NONE = 0, + /** Minimal. */ + GIMPROVIDERID_MINIMAL, + /** Microsoft Hyper-V. */ + GIMPROVIDERID_HYPERV, + /** Linux KVM Interface. */ + GIMPROVIDERID_KVM +} GIMPROVIDERID; +AssertCompileSize(GIMPROVIDERID, sizeof(uint32_t)); + + +/** + * A GIM MMIO2 region record. + */ +typedef struct GIMMMIO2REGION +{ + /** The region index. */ + uint8_t iRegion; + /** Whether an RC mapping is required. */ + bool fRCMapping; + /** Whether this region has been registered. */ + bool fRegistered; + /** Whether this region is currently mapped. */ + bool fMapped; + /** Size of the region (must be page aligned). */ + uint32_t cbRegion; + /** The host ring-0 address of the first page in the region. */ + R0PTRTYPE(void *) pvPageR0; + /** The host ring-3 address of the first page in the region. */ + R3PTRTYPE(void *) pvPageR3; +# ifdef VBOX_WITH_RAW_MODE_KEEP + /** The ring-context address of the first page in the region. */ + RCPTRTYPE(void *) pvPageRC; + RTRCPTR RCPtrAlignment0; +# endif + /** The guest-physical address of the first page in the region. */ + RTGCPHYS GCPhysPage; + /** The MMIO2 handle. */ + PGMMMIO2HANDLE hMmio2; + /** The description of the region. */ + char szDescription[32]; +} GIMMMIO2REGION; +/** Pointer to a GIM MMIO2 region. */ +typedef GIMMMIO2REGION *PGIMMMIO2REGION; +/** Pointer to a const GIM MMIO2 region. */ +typedef GIMMMIO2REGION const *PCGIMMMIO2REGION; +AssertCompileMemberAlignment(GIMMMIO2REGION, pvPageR0, 8); +AssertCompileMemberAlignment(GIMMMIO2REGION, GCPhysPage, 8); + +/** + * Debug data buffer available callback over the GIM debug connection. + * + * @param pVM The cross context VM structure. + */ +typedef DECLCALLBACKTYPE(void, FNGIMDEBUGBUFAVAIL,(PVM pVM)); +/** Pointer to GIM debug buffer available callback. */ +typedef FNGIMDEBUGBUFAVAIL *PFNGIMDEBUGBUFAVAIL; + +/** + * GIM debug setup. + * + * These are parameters/options filled in by the GIM provider and passed along + * to the GIM device. + */ +typedef struct GIMDEBUGSETUP +{ + /** The callback to invoke when the receive buffer has data. */ + PFNGIMDEBUGBUFAVAIL pfnDbgRecvBufAvail; + /** The size of the receive buffer as specified by the GIM provider. */ + uint32_t cbDbgRecvBuf; +} GIMDEBUGSETUP; +/** Pointer to a GIM debug setup struct. */ +typedef struct GIMDEBUGSETUP *PGIMDEBUGSETUP; +/** Pointer to a const GIM debug setup struct. */ +typedef struct GIMDEBUGSETUP const *PCGGIMDEBUGSETUP; + +/** + * GIM debug structure (common to the GIM device and GIM). + * + * This is used to exchanging data between the GIM provider and the GIM device. + */ +typedef struct GIMDEBUG +{ + /** The receive buffer. */ + void *pvDbgRecvBuf; + /** The debug I/O stream driver. */ + PPDMISTREAM pDbgDrvStream; + /** Number of bytes pending to be read from the receive buffer. */ + size_t cbDbgRecvBufRead; + /** The flag synchronizing reads of the receive buffer from EMT. */ + volatile bool fDbgRecvBufRead; + /** The receive thread wakeup semaphore. */ + RTSEMEVENTMULTI hDbgRecvThreadSem; +} GIMDEBUG; +/** Pointer to a GIM debug struct. */ +typedef struct GIMDEBUG *PGIMDEBUG; +/** Pointer to a const GIM debug struct. */ +typedef struct GIMDEBUG const *PCGIMDEBUG; + + +#ifdef IN_RC +/** @defgroup grp_gim_rc The GIM Raw-mode Context API + * @{ + */ +/** @} */ +#endif /* IN_RC */ + +#ifdef IN_RING0 +/** @defgroup grp_gim_r0 The GIM Host Context Ring-0 API + * @{ + */ +VMMR0_INT_DECL(int) GIMR0InitVM(PVMCC pVM); +VMMR0_INT_DECL(int) GIMR0TermVM(PVMCC pVM); +VMMR0_INT_DECL(int) GIMR0UpdateParavirtTsc(PVMCC pVM, uint64_t u64Offset); +/** @} */ +#endif /* IN_RING0 */ + + +#ifdef IN_RING3 +/** @defgroup grp_gim_r3 The GIM Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(int) GIMR3Init(PVM pVM); +VMMR3_INT_DECL(int) GIMR3InitCompleted(PVM pVM); +VMMR3_INT_DECL(void) GIMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) GIMR3Term(PVM pVM); +VMMR3_INT_DECL(void) GIMR3Reset(PVM pVM); +VMMR3DECL(void) GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevInsR3, PGIMDEBUG pDbg); +VMMR3DECL(int) GIMR3GetDebugSetup(PVM pVM, PGIMDEBUGSETUP pDbgSetup); +/** @} */ +#endif /* IN_RING3 */ + +VMMDECL(bool) GIMIsEnabled(PVM pVM); +VMMDECL(GIMPROVIDERID) GIMGetProvider(PVM pVM); +VMMDECL(PGIMMMIO2REGION) GIMGetMmio2Regions(PVMCC pVM, uint32_t *pcRegions); +VMM_INT_DECL(bool) GIMIsParavirtTscEnabled(PVMCC pVM); +VMM_INT_DECL(bool) GIMAreHypercallsEnabled(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) GIMHypercall(PVMCPUCC pVCpu, PCPUMCTX pCtx); +VMM_INT_DECL(VBOXSTRICTRC) GIMHypercallEx(PVMCPUCC pVCpu, PCPUMCTX pCtx, unsigned uDisOpcode, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) GIMExecHypercallInstr(PVMCPUCC pVCpu, PCPUMCTX pCtx, uint8_t *pcbInstr); +VMM_INT_DECL(VBOXSTRICTRC) GIMXcptUD(PVMCPUCC pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr); +VMM_INT_DECL(bool) GIMShouldTrapXcptUD(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) GIMReadMsr(PVMCPUCC pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue); +VMM_INT_DECL(VBOXSTRICTRC) GIMWriteMsr(PVMCPUCC pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uValue, uint64_t uRawValue); +VMM_INT_DECL(int) GIMQueryHypercallOpcodeBytes(PVM pVM, void *pvBuf, size_t cbBuf, + size_t *pcbWritten, uint16_t *puDisOpcode); +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_gim_h */ + diff --git a/include/VBox/vmm/gmm.h b/include/VBox/vmm/gmm.h new file mode 100644 index 00000000..4839b737 --- /dev/null +++ b/include/VBox/vmm/gmm.h @@ -0,0 +1,828 @@ +/** @file + * GMM - The Global Memory Manager. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_gmm_h +#define VBOX_INCLUDED_vmm_gmm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/gvmm.h> +#include <VBox/sup.h> +#include <VBox/param.h> +#include <VBox/ostypes.h> +#include <iprt/avl.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_gmm GMM - The Global Memory Manager + * @ingroup grp_vmm + * @{ + */ + +/** @def IN_GMM_R0 + * Used to indicate whether we're inside the same link module as the ring 0 + * part of the Global Memory Manager or not. + */ +#ifdef DOXYGEN_RUNNING +# define IN_GMM_R0 +#endif +/** @def GMMR0DECL + * Ring 0 GMM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_GMM_R0 +# define GMMR0DECL(type) DECLEXPORT(type) VBOXCALL +#else +# define GMMR0DECL(type) DECLIMPORT(type) VBOXCALL +#endif + +/** @def IN_GMM_R3 + * Used to indicate whether we're inside the same link module as the ring 3 + * part of the Global Memory Manager or not. + */ +#ifdef DOXYGEN_RUNNING +# define IN_GMM_R3 +#endif +/** @def GMMR3DECL + * Ring 3 GMM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_GMM_R3 +# define GMMR3DECL(type) DECLEXPORT(type) VBOXCALL +#else +# define GMMR3DECL(type) DECLIMPORT(type) VBOXCALL +#endif + + +/** The chunk shift. (2^21 = 2 MB) */ +#define GMM_CHUNK_SHIFT 21 +/** The allocation chunk size. */ +#define GMM_CHUNK_SIZE (1U << GMM_CHUNK_SHIFT) +/** The allocation chunk size in (guest) pages. */ +#define GMM_CHUNK_NUM_PAGES (1U << (GMM_CHUNK_SHIFT - GUEST_PAGE_SHIFT)) +/** The shift factor for converting a page id into a chunk id. */ +#define GMM_CHUNKID_SHIFT (GMM_CHUNK_SHIFT - GUEST_PAGE_SHIFT) +/** The last valid Chunk ID value. */ +#define GMM_CHUNKID_LAST (GMM_PAGEID_LAST >> GMM_CHUNKID_SHIFT) +/** The last valid Page ID value. */ +#define GMM_PAGEID_LAST UINT32_C(0xfffffff0) +/** Mask out the page index from the Page ID. */ +#define GMM_PAGEID_IDX_MASK ((1U << GMM_CHUNKID_SHIFT) - 1) +/** The NIL Chunk ID value. */ +#define NIL_GMM_CHUNKID 0 +/** The NIL Page ID value. */ +#define NIL_GMM_PAGEID 0 + +#if 0 /* wrong - these are guest page pfns and not page ids! */ +/** Special Page ID used by unassigned pages. */ +#define GMM_PAGEID_UNASSIGNED 0x0fffffffU +/** Special Page ID used by unsharable pages. + * Like MMIO2, shadow and heap. This is for later, obviously. */ +#define GMM_PAGEID_UNSHARABLE 0x0ffffffeU +/** The end of the valid Page IDs. This is the first special one. */ +#define GMM_PAGEID_END 0x0ffffff0U +#endif + + +/** @def GMM_GCPHYS_LAST + * The last of the valid guest physical address as it applies to GMM pages. + * + * This must reflect the constraints imposed by the RTGCPHYS type and + * the guest page frame number used internally in GMMPAGE. + * + * @note Note this corresponds to GMM_PAGE_PFN_LAST. */ +#if HC_ARCH_BITS == 64 +# define GMM_GCPHYS_LAST UINT64_C(0x00000fffffff0000) /* 2^44 (16TB) - 0x10000 */ +#else +# define GMM_GCPHYS_LAST UINT64_C(0x0000000fffff0000) /* 2^36 (64GB) - 0x10000 */ +#endif + +/** + * Over-commitment policy. + */ +typedef enum GMMOCPOLICY +{ + /** The usual invalid 0 value. */ + GMMOCPOLICY_INVALID = 0, + /** No over-commitment, fully backed. + * The GMM guarantees that it will be able to allocate all of the + * guest RAM for a VM with OC policy. */ + GMMOCPOLICY_NO_OC, + /** to-be-determined. */ + GMMOCPOLICY_TBD, + /** The end of the valid policy range. */ + GMMOCPOLICY_END, + /** The usual 32-bit hack. */ + GMMOCPOLICY_32BIT_HACK = 0x7fffffff +} GMMOCPOLICY; + +/** + * VM / Memory priority. + */ +typedef enum GMMPRIORITY +{ + /** The usual invalid 0 value. */ + GMMPRIORITY_INVALID = 0, + /** High. + * When ballooning, ask these VMs last. + * When running out of memory, try not to interrupt these VMs. */ + GMMPRIORITY_HIGH, + /** Normal. + * When ballooning, don't wait to ask these. + * When running out of memory, pause, save and/or kill these VMs. */ + GMMPRIORITY_NORMAL, + /** Low. + * When ballooning, maximize these first. + * When running out of memory, save or kill these VMs. */ + GMMPRIORITY_LOW, + /** The end of the valid priority range. */ + GMMPRIORITY_END, + /** The custom 32-bit type blowup. */ + GMMPRIORITY_32BIT_HACK = 0x7fffffff +} GMMPRIORITY; + + +/** + * GMM Memory Accounts. + */ +typedef enum GMMACCOUNT +{ + /** The customary invalid zero entry. */ + GMMACCOUNT_INVALID = 0, + /** Account with the base allocations. */ + GMMACCOUNT_BASE, + /** Account with the shadow allocations. */ + GMMACCOUNT_SHADOW, + /** Account with the fixed allocations. */ + GMMACCOUNT_FIXED, + /** The end of the valid values. */ + GMMACCOUNT_END, + /** The usual 32-bit value to finish it off. */ + GMMACCOUNT_32BIT_HACK = 0x7fffffff +} GMMACCOUNT; + + +/** + * Balloon actions. + */ +typedef enum +{ + /** Invalid zero entry. */ + GMMBALLOONACTION_INVALID = 0, + /** Inflate the balloon. */ + GMMBALLOONACTION_INFLATE, + /** Deflate the balloon. */ + GMMBALLOONACTION_DEFLATE, + /** Puncture the balloon because of VM reset. */ + GMMBALLOONACTION_RESET, + /** End of the valid actions. */ + GMMBALLOONACTION_END, + /** hack forcing the size of the enum to 32-bits. */ + GMMBALLOONACTION_MAKE_32BIT_HACK = 0x7fffffff +} GMMBALLOONACTION; + + +/** + * A page descriptor for use when freeing pages. + * See GMMR0FreePages, GMMR0BalloonedPages. + */ +typedef struct GMMFREEPAGEDESC +{ + /** The Page ID of the page to be freed. */ + uint32_t idPage; +} GMMFREEPAGEDESC; +/** Pointer to a page descriptor for freeing pages. */ +typedef GMMFREEPAGEDESC *PGMMFREEPAGEDESC; + + +/** + * A page descriptor for use when updating and allocating pages. + * + * This is a bit complicated because we want to do as much as possible + * with the same structure. + */ +typedef struct GMMPAGEDESC +{ + /** The physical address of the page. + * + * @input GMMR0AllocateHandyPages expects the guest physical address + * to update the GMMPAGE structure with. Pass GMM_GCPHYS_UNSHAREABLE + * when appropriate and NIL_GMMPAGEDESC_PHYS when the page wasn't used + * for any specific guest address. + * + * GMMR0AllocatePage expects the guest physical address to put in + * the GMMPAGE structure for the page it allocates for this entry. + * Pass NIL_GMMPAGEDESC_PHYS and GMM_GCPHYS_UNSHAREABLE as above. + * + * @output The host physical address of the allocated page. + * NIL_GMMPAGEDESC_PHYS on allocation failure. + * + * ASSUMES: sizeof(RTHCPHYS) >= sizeof(RTGCPHYS) and that physical addresses are + * limited to 63 or fewer bits (52 by AMD64 arch spec). + */ + RT_GCC_EXTENSION + RTHCPHYS HCPhysGCPhys : 63; + /** Set if the memory was zeroed. */ + RT_GCC_EXTENSION + RTHCPHYS fZeroed : 1; + + /** The Page ID. + * + * @input GMMR0AllocateHandyPages expects the Page ID of the page to + * update here. NIL_GMM_PAGEID means no page should be updated. + * + * GMMR0AllocatePages requires this to be initialized to + * NIL_GMM_PAGEID currently. + * + * @output The ID of the page, NIL_GMM_PAGEID if the allocation failed. + */ + uint32_t idPage; + + /** The Page ID of the shared page was replaced by this page. + * + * @input GMMR0AllocateHandyPages expects this to indicate a shared + * page that has been replaced by this page and should have its + * reference counter decremented and perhaps be freed up. Use + * NIL_GMM_PAGEID if no shared page was involved. + * + * All other APIs expects NIL_GMM_PAGEID here. + * + * @output All APIs sets this to NIL_GMM_PAGEID. + */ + uint32_t idSharedPage; +} GMMPAGEDESC; +AssertCompileSize(GMMPAGEDESC, 16); +/** Pointer to a page allocation. */ +typedef GMMPAGEDESC *PGMMPAGEDESC; + +/** Special NIL value for GMMPAGEDESC::HCPhysGCPhys. */ +#define NIL_GMMPAGEDESC_PHYS UINT64_C(0x7fffffffffffffff) + +/** GMMPAGEDESC::HCPhysGCPhys value that indicates that the page is unsharable. + * @note This corresponds to GMM_PAGE_PFN_UNSHAREABLE. */ +#if HC_ARCH_BITS == 64 +# define GMM_GCPHYS_UNSHAREABLE UINT64_C(0x00000fffffff1000) +#else +# define GMM_GCPHYS_UNSHAREABLE UINT64_C(0x0000000fffff1000) +#endif + + +/** + * The allocation sizes. + */ +typedef struct GMMVMSIZES +{ + /** The number of pages of base memory. + * This is the sum of RAM, ROMs and handy pages. */ + uint64_t cBasePages; + /** The number of pages for the shadow pool. (Can be squeezed for memory.) */ + uint32_t cShadowPages; + /** The number of pages for fixed allocations like MMIO2 and the hyper heap. */ + uint32_t cFixedPages; +} GMMVMSIZES; +/** Pointer to a GMMVMSIZES. */ +typedef GMMVMSIZES *PGMMVMSIZES; + + +/** + * GMM VM statistics. + */ +typedef struct GMMVMSTATS +{ + /** The reservations. */ + GMMVMSIZES Reserved; + /** The actual allocations. + * This includes both private and shared page allocations. */ + GMMVMSIZES Allocated; + + /** The current number of private pages. */ + uint64_t cPrivatePages; + /** The current number of shared pages. */ + uint64_t cSharedPages; + /** The current number of ballooned pages. */ + uint64_t cBalloonedPages; + /** The max number of pages that can be ballooned. */ + uint64_t cMaxBalloonedPages; + /** The number of pages we've currently requested the guest to give us. + * This is 0 if no pages currently requested. */ + uint64_t cReqBalloonedPages; + /** The number of pages the guest has given us in response to the request. + * This is not reset on request completed and may be used in later decisions. */ + uint64_t cReqActuallyBalloonedPages; + /** The number of pages we've currently requested the guest to take back. */ + uint64_t cReqDeflatePages; + /** The number of shareable module tracked by this VM. */ + uint32_t cShareableModules; + + /** The current over-commitment policy. */ + GMMOCPOLICY enmPolicy; + /** The VM priority for arbitrating VMs in low and out of memory situation. + * Like which VMs to start squeezing first. */ + GMMPRIORITY enmPriority; + /** Whether ballooning is enabled or not. */ + bool fBallooningEnabled; + /** Whether shared paging is enabled or not. */ + bool fSharedPagingEnabled; + /** Whether the VM is allowed to allocate memory or not. + * This is used when the reservation update request fails or when the VM has + * been told to suspend/save/die in an out-of-memory case. */ + bool fMayAllocate; + /** Explicit alignment. */ + bool afReserved[1]; + + +} GMMVMSTATS; + + +/** + * The GMM statistics. + */ +typedef struct GMMSTATS +{ + /** The maximum number of pages we're allowed to allocate + * (GMM::cMaxPages). */ + uint64_t cMaxPages; + /** The number of pages that has been reserved (GMM::cReservedPages). */ + uint64_t cReservedPages; + /** The number of pages that we have over-committed in reservations + * (GMM::cOverCommittedPages). */ + uint64_t cOverCommittedPages; + /** The number of actually allocated (committed if you like) pages + * (GMM::cAllocatedPages). */ + uint64_t cAllocatedPages; + /** The number of pages that are shared. A subset of cAllocatedPages. + * (GMM::cSharedPages) */ + uint64_t cSharedPages; + /** The number of pages that are actually shared between VMs. + * (GMM:cDuplicatePages) */ + uint64_t cDuplicatePages; + /** The number of pages that are shared that has been left behind by + * VMs not doing proper cleanups (GMM::cLeftBehindSharedPages). */ + uint64_t cLeftBehindSharedPages; + /** The number of current ballooned pages (GMM::cBalloonedPages). */ + uint64_t cBalloonedPages; + /** The number of allocation chunks (GMM::cChunks). */ + uint32_t cChunks; + /** The number of freed chunks ever (GMM::cFreedChunks). */ + uint32_t cFreedChunks; + /** The number of shareable modules (GMM:cShareableModules). */ + uint64_t cShareableModules; + /** The current chunk freeing generation use by the per-VM TLB validation (GMM::idFreeGeneration). */ + uint64_t idFreeGeneration; + /** Space reserved for later. */ + uint64_t au64Reserved[1]; + + /** Statistics for the specified VM. (Zero filled if not requested.) */ + GMMVMSTATS VMStats; +} GMMSTATS; +/** Pointer to the GMM statistics. */ +typedef GMMSTATS *PGMMSTATS; +/** Const pointer to the GMM statistics. */ +typedef const GMMSTATS *PCGMMSTATS; + + +GMMR0DECL(int) GMMR0Init(void); +GMMR0DECL(void) GMMR0Term(void); +GMMR0DECL(int) GMMR0InitPerVMData(PGVM pGVM); +GMMR0DECL(void) GMMR0CleanupVM(PGVM pGVM); +GMMR0DECL(int) GMMR0InitialReservation(PGVM pGVM, VMCPUID idCpu, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages, + GMMOCPOLICY enmPolicy, GMMPRIORITY enmPriority); +GMMR0DECL(int) GMMR0UpdateReservation(PGVM pGVM, VMCPUID idCpu, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages); +GMMR0DECL(int) GMMR0AllocateHandyPages(PGVM pGVM, VMCPUID idCpu, uint32_t cPagesToUpdate, + uint32_t cPagesToAlloc, PGMMPAGEDESC paPages); +GMMR0DECL(int) GMMR0AllocatePages(PGVM pGVM, VMCPUID idCpu, uint32_t cPages, PGMMPAGEDESC paPages, GMMACCOUNT enmAccount); +GMMR0DECL(int) GMMR0AllocateLargePage(PGVM pGVM, VMCPUID idCpu, uint32_t cbPage, uint32_t *pIdPage, RTHCPHYS *pHCPhys); +GMMR0DECL(int) GMMR0FreePages(PGVM pGVM, VMCPUID idCpu, uint32_t cPages, PGMMFREEPAGEDESC paPages, GMMACCOUNT enmAccount); +GMMR0DECL(int) GMMR0FreeLargePage(PGVM pGVM, VMCPUID idCpu, uint32_t idPage); +GMMR0DECL(int) GMMR0BalloonedPages(PGVM pGVM, VMCPUID idCpu, GMMBALLOONACTION enmAction, uint32_t cBalloonedPages); +GMMR0DECL(int) GMMR0MapUnmapChunk(PGVM pGVM, uint32_t idChunkMap, uint32_t idChunkUnmap, PRTR3PTR ppvR3); +GMMR0DECL(int) GMMR0PageIdToVirt(PGVM pGVM, uint32_t idPage, void **ppv); +GMMR0DECL(int) GMMR0RegisterSharedModule(PGVM pGVM, VMCPUID idCpu, VBOXOSFAMILY enmGuestOS, char *pszModuleName, + char *pszVersion, RTGCPTR GCBaseAddr, uint32_t cbModule, uint32_t cRegions, + struct VMMDEVSHAREDREGIONDESC const *paRegions); +GMMR0DECL(int) GMMR0UnregisterSharedModule(PGVM pGVM, VMCPUID idCpu, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule); +GMMR0DECL(int) GMMR0UnregisterAllSharedModules(PGVM pGVM, VMCPUID idCpu); +GMMR0DECL(int) GMMR0CheckSharedModules(PGVM pGVM, VMCPUID idCpu); +GMMR0DECL(int) GMMR0ResetSharedModules(PGVM pGVM, VMCPUID idCpu); +GMMR0DECL(int) GMMR0QueryStatistics(PGMMSTATS pStats, PSUPDRVSESSION pSession); +GMMR0DECL(int) GMMR0ResetStatistics(PCGMMSTATS pStats, PSUPDRVSESSION pSession); + +/** + * Request buffer for GMMR0InitialReservationReq / VMMR0_DO_GMM_INITIAL_RESERVATION. + * @see GMMR0InitialReservation + */ +typedef struct GMMINITIALRESERVATIONREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + uint64_t cBasePages; /**< @see GMMR0InitialReservation */ + uint32_t cShadowPages; /**< @see GMMR0InitialReservation */ + uint32_t cFixedPages; /**< @see GMMR0InitialReservation */ + GMMOCPOLICY enmPolicy; /**< @see GMMR0InitialReservation */ + GMMPRIORITY enmPriority; /**< @see GMMR0InitialReservation */ +} GMMINITIALRESERVATIONREQ; +/** Pointer to a GMMR0InitialReservationReq / VMMR0_DO_GMM_INITIAL_RESERVATION request buffer. */ +typedef GMMINITIALRESERVATIONREQ *PGMMINITIALRESERVATIONREQ; + +GMMR0DECL(int) GMMR0InitialReservationReq(PGVM pGVM, VMCPUID idCpu, PGMMINITIALRESERVATIONREQ pReq); + + +/** + * Request buffer for GMMR0UpdateReservationReq / VMMR0_DO_GMM_UPDATE_RESERVATION. + * @see GMMR0UpdateReservation + */ +typedef struct GMMUPDATERESERVATIONREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + uint64_t cBasePages; /**< @see GMMR0UpdateReservation */ + uint32_t cShadowPages; /**< @see GMMR0UpdateReservation */ + uint32_t cFixedPages; /**< @see GMMR0UpdateReservation */ +} GMMUPDATERESERVATIONREQ; +/** Pointer to a GMMR0InitialReservationReq / VMMR0_DO_GMM_INITIAL_RESERVATION request buffer. */ +typedef GMMUPDATERESERVATIONREQ *PGMMUPDATERESERVATIONREQ; + +GMMR0DECL(int) GMMR0UpdateReservationReq(PGVM pGVM, VMCPUID idCpu, PGMMUPDATERESERVATIONREQ pReq); + + +/** + * Request buffer for GMMR0AllocatePagesReq / VMMR0_DO_GMM_ALLOCATE_PAGES. + * @see GMMR0AllocatePages. + */ +typedef struct GMMALLOCATEPAGESREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The account to charge the allocation to. */ + GMMACCOUNT enmAccount; + /** The number of pages to allocate. */ + uint32_t cPages; + /** Array of page descriptors. */ + GMMPAGEDESC aPages[1]; +} GMMALLOCATEPAGESREQ; +/** Pointer to a GMMR0AllocatePagesReq / VMMR0_DO_GMM_ALLOCATE_PAGES request buffer. */ +typedef GMMALLOCATEPAGESREQ *PGMMALLOCATEPAGESREQ; + +GMMR0DECL(int) GMMR0AllocatePagesReq(PGVM pGVM, VMCPUID idCpu, PGMMALLOCATEPAGESREQ pReq); + + +/** + * Request buffer for GMMR0FreePagesReq / VMMR0_DO_GMM_FREE_PAGES. + * @see GMMR0FreePages. + */ +typedef struct GMMFREEPAGESREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The account this relates to. */ + GMMACCOUNT enmAccount; + /** The number of pages to free. */ + uint32_t cPages; + /** Array of free page descriptors. */ + GMMFREEPAGEDESC aPages[1]; +} GMMFREEPAGESREQ; +/** Pointer to a GMMR0FreePagesReq / VMMR0_DO_GMM_FREE_PAGES request buffer. */ +typedef GMMFREEPAGESREQ *PGMMFREEPAGESREQ; + +GMMR0DECL(int) GMMR0FreePagesReq(PGVM pGVM, VMCPUID idCpu, PGMMFREEPAGESREQ pReq); + +/** + * Request buffer for GMMR0BalloonedPagesReq / VMMR0_DO_GMM_BALLOONED_PAGES. + * @see GMMR0BalloonedPages. + */ +typedef struct GMMBALLOONEDPAGESREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The number of ballooned pages. */ + uint32_t cBalloonedPages; + /** Inflate or deflate the balloon. */ + GMMBALLOONACTION enmAction; +} GMMBALLOONEDPAGESREQ; +/** Pointer to a GMMR0BalloonedPagesReq / VMMR0_DO_GMM_BALLOONED_PAGES request buffer. */ +typedef GMMBALLOONEDPAGESREQ *PGMMBALLOONEDPAGESREQ; + +GMMR0DECL(int) GMMR0BalloonedPagesReq(PGVM pGVM, VMCPUID idCpu, PGMMBALLOONEDPAGESREQ pReq); + + +/** + * Request buffer for GMMR0QueryHypervisorMemoryStatsReq / VMMR0_DO_GMM_QUERY_VMM_MEM_STATS. + * @see GMMR0QueryHypervisorMemoryStatsReq. + */ +typedef struct GMMMEMSTATSREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The number of allocated pages (out). */ + uint64_t cAllocPages; + /** The number of free pages (out). */ + uint64_t cFreePages; + /** The number of ballooned pages (out). */ + uint64_t cBalloonedPages; + /** The number of shared pages (out). */ + uint64_t cSharedPages; + /** Maximum nr of pages (out). */ + uint64_t cMaxPages; +} GMMMEMSTATSREQ; +/** Pointer to a GMMR0QueryHypervisorMemoryStatsReq / VMMR0_DO_GMM_QUERY_HYPERVISOR_MEM_STATS request buffer. */ +typedef GMMMEMSTATSREQ *PGMMMEMSTATSREQ; + +GMMR0DECL(int) GMMR0QueryHypervisorMemoryStatsReq(PGMMMEMSTATSREQ pReq); +GMMR0DECL(int) GMMR0QueryMemoryStatsReq(PGVM pGVM, VMCPUID idCpu, PGMMMEMSTATSREQ pReq); + +/** + * Request buffer for GMMR0MapUnmapChunkReq / VMMR0_DO_GMM_MAP_UNMAP_CHUNK. + * @see GMMR0MapUnmapChunk + */ +typedef struct GMMMAPUNMAPCHUNKREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The chunk to map, NIL_GMM_CHUNKID if unmap only. (IN) */ + uint32_t idChunkMap; + /** The chunk to unmap, NIL_GMM_CHUNKID if map only. (IN) */ + uint32_t idChunkUnmap; + /** Where the mapping address is returned. (OUT) */ + RTR3PTR pvR3; +} GMMMAPUNMAPCHUNKREQ; +/** Pointer to a GMMR0MapUnmapChunkReq / VMMR0_DO_GMM_MAP_UNMAP_CHUNK request buffer. */ +typedef GMMMAPUNMAPCHUNKREQ *PGMMMAPUNMAPCHUNKREQ; + +GMMR0DECL(int) GMMR0MapUnmapChunkReq(PGVM pGVM, PGMMMAPUNMAPCHUNKREQ pReq); + + +/** + * Request buffer for GMMR0FreeLargePageReq / VMMR0_DO_GMM_FREE_LARGE_PAGE. + * @see GMMR0FreeLargePage. + */ +typedef struct GMMFREELARGEPAGEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The Page ID. */ + uint32_t idPage; +} GMMFREELARGEPAGEREQ; +/** Pointer to a GMMR0FreePagesReq / VMMR0_DO_GMM_FREE_PAGES request buffer. */ +typedef GMMFREELARGEPAGEREQ *PGMMFREELARGEPAGEREQ; + +GMMR0DECL(int) GMMR0FreeLargePageReq(PGVM pGVM, VMCPUID idCpu, PGMMFREELARGEPAGEREQ pReq); + +/** Maximum length of the shared module name string, terminator included. */ +#define GMM_SHARED_MODULE_MAX_NAME_STRING 128 +/** Maximum length of the shared module version string, terminator included. */ +#define GMM_SHARED_MODULE_MAX_VERSION_STRING 16 + +/** + * Request buffer for GMMR0RegisterSharedModuleReq / VMMR0_DO_GMM_REGISTER_SHARED_MODULE. + * @see GMMR0RegisterSharedModule. + */ +typedef struct GMMREGISTERSHAREDMODULEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Shared module size. */ + uint32_t cbModule; + /** Number of included region descriptors */ + uint32_t cRegions; + /** Base address of the shared module. */ + RTGCPTR64 GCBaseAddr; + /** Guest OS type. */ + VBOXOSFAMILY enmGuestOS; + /** return code. */ + uint32_t rc; + /** Module name */ + char szName[GMM_SHARED_MODULE_MAX_NAME_STRING]; + /** Module version */ + char szVersion[GMM_SHARED_MODULE_MAX_VERSION_STRING]; + /** Shared region descriptor(s). */ + VMMDEVSHAREDREGIONDESC aRegions[1]; +} GMMREGISTERSHAREDMODULEREQ; +/** Pointer to a GMMR0RegisterSharedModuleReq / VMMR0_DO_GMM_REGISTER_SHARED_MODULE request buffer. */ +typedef GMMREGISTERSHAREDMODULEREQ *PGMMREGISTERSHAREDMODULEREQ; + +GMMR0DECL(int) GMMR0RegisterSharedModuleReq(PGVM pGVM, VMCPUID idCpu, PGMMREGISTERSHAREDMODULEREQ pReq); + +/** + * Shared region descriptor + */ +typedef struct GMMSHAREDREGIONDESC +{ + /** The page offset where the region starts. */ + uint32_t off; + /** Region size - adjusted by the region offset and rounded up to a + * page. */ + uint32_t cb; + /** Pointer to physical GMM page ID array. */ + uint32_t *paidPages; +} GMMSHAREDREGIONDESC; +/** Pointer to a GMMSHAREDREGIONDESC. */ +typedef GMMSHAREDREGIONDESC *PGMMSHAREDREGIONDESC; + + +/** + * Shared module registration info (global) + */ +typedef struct GMMSHAREDMODULE +{ + /** Tree node (keyed by a hash of name & version). */ + AVLLU32NODECORE Core; + /** Shared module size. */ + uint32_t cbModule; + /** Number of included region descriptors */ + uint32_t cRegions; + /** Number of users (VMs). */ + uint32_t cUsers; + /** Guest OS family type. */ + VBOXOSFAMILY enmGuestOS; + /** Module name */ + char szName[GMM_SHARED_MODULE_MAX_NAME_STRING]; + /** Module version */ + char szVersion[GMM_SHARED_MODULE_MAX_VERSION_STRING]; + /** Shared region descriptor(s). */ + GMMSHAREDREGIONDESC aRegions[1]; +} GMMSHAREDMODULE; +/** Pointer to a GMMSHAREDMODULE. */ +typedef GMMSHAREDMODULE *PGMMSHAREDMODULE; + +/** + * Page descriptor for GMMR0SharedModuleCheckRange + */ +typedef struct GMMSHAREDPAGEDESC +{ + /** HC Physical address (in/out) */ + RTHCPHYS HCPhys; + /** GC Physical address (in) */ + RTGCPHYS GCPhys; + /** GMM page id. (in/out) */ + uint32_t idPage; + /** CRC32 of the page in strict builds (0 if page not available). + * In non-strict build this serves as structure alignment. */ + uint32_t u32StrictChecksum; +} GMMSHAREDPAGEDESC; +/** Pointer to a GMMSHAREDPAGEDESC. */ +typedef GMMSHAREDPAGEDESC *PGMMSHAREDPAGEDESC; + +GMMR0DECL(int) GMMR0SharedModuleCheckPage(PGVM pGVM, PGMMSHAREDMODULE pModule, uint32_t idxRegion, uint32_t idxPage, + PGMMSHAREDPAGEDESC pPageDesc); + +/** + * Request buffer for GMMR0UnregisterSharedModuleReq / VMMR0_DO_GMM_UNREGISTER_SHARED_MODULE. + * @see GMMR0UnregisterSharedModule. + */ +typedef struct GMMUNREGISTERSHAREDMODULEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Shared module size. */ + uint32_t cbModule; + /** Align at 8 byte boundary. */ + uint32_t u32Alignment; + /** Base address of the shared module. */ + RTGCPTR64 GCBaseAddr; + /** Module name */ + char szName[GMM_SHARED_MODULE_MAX_NAME_STRING]; + /** Module version */ + char szVersion[GMM_SHARED_MODULE_MAX_VERSION_STRING]; +} GMMUNREGISTERSHAREDMODULEREQ; +/** Pointer to a GMMR0UnregisterSharedModuleReq / VMMR0_DO_GMM_UNREGISTER_SHARED_MODULE request buffer. */ +typedef GMMUNREGISTERSHAREDMODULEREQ *PGMMUNREGISTERSHAREDMODULEREQ; + +GMMR0DECL(int) GMMR0UnregisterSharedModuleReq(PGVM pGVM, VMCPUID idCpu, PGMMUNREGISTERSHAREDMODULEREQ pReq); + +#if defined(VBOX_STRICT) && HC_ARCH_BITS == 64 +/** + * Request buffer for GMMR0FindDuplicatePageReq / VMMR0_DO_GMM_FIND_DUPLICATE_PAGE. + * @see GMMR0FindDuplicatePage. + */ +typedef struct GMMFINDDUPLICATEPAGEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Page id. */ + uint32_t idPage; + /** Duplicate flag (out) */ + bool fDuplicate; +} GMMFINDDUPLICATEPAGEREQ; +/** Pointer to a GMMR0FindDuplicatePageReq / VMMR0_DO_GMM_FIND_DUPLICATE_PAGE request buffer. */ +typedef GMMFINDDUPLICATEPAGEREQ *PGMMFINDDUPLICATEPAGEREQ; + +GMMR0DECL(int) GMMR0FindDuplicatePageReq(PGVM pGVM, PGMMFINDDUPLICATEPAGEREQ pReq); +#endif /* VBOX_STRICT && HC_ARCH_BITS == 64 */ + + +/** + * Request buffer for GMMR0QueryStatisticsReq / VMMR0_DO_GMM_QUERY_STATISTICS. + * @see GMMR0QueryStatistics. + */ +typedef struct GMMQUERYSTATISTICSSREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The support driver session. */ + PSUPDRVSESSION pSession; + /** The statistics. */ + GMMSTATS Stats; +} GMMQUERYSTATISTICSSREQ; +/** Pointer to a GMMR0QueryStatisticsReq / VMMR0_DO_GMM_QUERY_STATISTICS + * request buffer. */ +typedef GMMQUERYSTATISTICSSREQ *PGMMQUERYSTATISTICSSREQ; + +GMMR0DECL(int) GMMR0QueryStatisticsReq(PGVM pGVM, PGMMQUERYSTATISTICSSREQ pReq); + + +/** + * Request buffer for GMMR0ResetStatisticsReq / VMMR0_DO_GMM_RESET_STATISTICS. + * @see GMMR0ResetStatistics. + */ +typedef struct GMMRESETSTATISTICSSREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The support driver session. */ + PSUPDRVSESSION pSession; + /** The statistics to reset. + * Any non-zero entry will be reset (if permitted). */ + GMMSTATS Stats; +} GMMRESETSTATISTICSSREQ; +/** Pointer to a GMMR0ResetStatisticsReq / VMMR0_DO_GMM_RESET_STATISTICS + * request buffer. */ +typedef GMMRESETSTATISTICSSREQ *PGMMRESETSTATISTICSSREQ; + +GMMR0DECL(int) GMMR0ResetStatisticsReq(PGVM pGVM, PGMMRESETSTATISTICSSREQ pReq); + + + +#ifdef IN_RING3 +/** @defgroup grp_gmm_r3 The Global Memory Manager Ring-3 API Wrappers + * @{ + */ +GMMR3DECL(int) GMMR3InitialReservation(PVM pVM, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages, + GMMOCPOLICY enmPolicy, GMMPRIORITY enmPriority); +GMMR3DECL(int) GMMR3UpdateReservation(PVM pVM, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages); +GMMR3DECL(int) GMMR3AllocatePagesPrepare(PVM pVM, PGMMALLOCATEPAGESREQ *ppReq, uint32_t cPages, GMMACCOUNT enmAccount); +GMMR3DECL(int) GMMR3AllocatePagesPerform(PVM pVM, PGMMALLOCATEPAGESREQ pReq); +GMMR3DECL(void) GMMR3AllocatePagesCleanup(PGMMALLOCATEPAGESREQ pReq); +GMMR3DECL(int) GMMR3FreePagesPrepare(PVM pVM, PGMMFREEPAGESREQ *ppReq, uint32_t cPages, GMMACCOUNT enmAccount); +GMMR3DECL(void) GMMR3FreePagesRePrep(PVM pVM, PGMMFREEPAGESREQ pReq, uint32_t cPages, GMMACCOUNT enmAccount); +GMMR3DECL(int) GMMR3FreePagesPerform(PVM pVM, PGMMFREEPAGESREQ pReq, uint32_t cActualPages); +GMMR3DECL(void) GMMR3FreePagesCleanup(PGMMFREEPAGESREQ pReq); +GMMR3DECL(void) GMMR3FreeAllocatedPages(PVM pVM, GMMALLOCATEPAGESREQ const *pAllocReq); +GMMR3DECL(int) GMMR3AllocateLargePage(PVM pVM, uint32_t cbPage); +GMMR3DECL(int) GMMR3FreeLargePage(PVM pVM, uint32_t idPage); +GMMR3DECL(int) GMMR3MapUnmapChunk(PVM pVM, uint32_t idChunkMap, uint32_t idChunkUnmap, PRTR3PTR ppvR3); +GMMR3DECL(int) GMMR3QueryHypervisorMemoryStats(PVM pVM, uint64_t *pcTotalAllocPages, uint64_t *pcTotalFreePages, uint64_t *pcTotalBalloonPages, uint64_t *puTotalBalloonSize); +GMMR3DECL(int) GMMR3QueryMemoryStats(PVM pVM, uint64_t *pcAllocPages, uint64_t *pcMaxPages, uint64_t *pcBalloonPages); +GMMR3DECL(int) GMMR3BalloonedPages(PVM pVM, GMMBALLOONACTION enmAction, uint32_t cBalloonedPages); +GMMR3DECL(int) GMMR3RegisterSharedModule(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq); +GMMR3DECL(int) GMMR3UnregisterSharedModule(PVM pVM, PGMMUNREGISTERSHAREDMODULEREQ pReq); +GMMR3DECL(int) GMMR3CheckSharedModules(PVM pVM); +GMMR3DECL(int) GMMR3ResetSharedModules(PVM pVM); + +# if defined(VBOX_STRICT) && HC_ARCH_BITS == 64 +GMMR3DECL(bool) GMMR3IsDuplicatePage(PVM pVM, uint32_t idPage); +# endif + +/** @} */ +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_gmm_h */ + diff --git a/include/VBox/vmm/gvm.h b/include/VBox/vmm/gvm.h new file mode 100644 index 00000000..8efdcc24 --- /dev/null +++ b/include/VBox/vmm/gvm.h @@ -0,0 +1,351 @@ +/* $Id: gvm.h $ */ +/** @file + * GVM - The Global VM Data. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_gvm_h +#define VBOX_INCLUDED_vmm_gvm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef USING_VMM_COMMON_DEFS +# error "Compile job does not include VMM_COMMON_DEFS from src/VBox/Config.kmk - make sure you really need to include this file!" +#endif +#include <VBox/types.h> +#include <VBox/vmm/vm.h> +#include <VBox/param.h> +#include <iprt/thread.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_gvmcpu GVMCPU - The Global VMCPU Data + * @ingroup grp_vmm + * @{ + */ + +#if defined(__cplusplus) && !defined(GVM_C_STYLE_STRUCTURES) +typedef struct GVMCPU : public VMCPU +#else +typedef struct GVMCPU +#endif +{ +#if !defined(__cplusplus) || defined(GVM_C_STYLE_STRUCTURES) + VMCPU s; +#endif + + /** VCPU id (0 - (pVM->cCpus - 1). */ + VMCPUID idCpu; + /** Padding. */ + uint32_t uPadding0; + + /** Handle to the EMT thread. */ + RTNATIVETHREAD hEMT; + + /** Pointer to the global (ring-0) VM structure this CPU belongs to. */ + R0PTRTYPE(PGVM) pGVM; + /** Pointer to the GVM structure, for CTX_SUFF use in VMMAll code. */ + PGVM pVMR0; + /** The ring-3 address of this structure (only VMCPU part). */ + PVMCPUR3 pVCpuR3; + + /** Padding so the noisy stuff on a 64 byte boundrary. + * @note Keeping this working for 32-bit header syntax checking. */ + uint8_t abPadding1[HC_ARCH_BITS == 32 ? 40 : 24]; + + /** Which host CPU ID is this EMT running on. + * Only valid when in RC or HMR0 with scheduling disabled. */ + RTCPUID volatile idHostCpu; + /** The CPU set index corresponding to idHostCpu, UINT32_MAX if not valid. + * @remarks Best to make sure iHostCpuSet shares cache line with idHostCpu! */ + uint32_t volatile iHostCpuSet; + + /** Padding so gvmm starts on a 64 byte boundrary. + * @note Keeping this working for 32-bit header syntax checking. */ + uint8_t abPadding2[56]; + + /** The GVMM per vcpu data. */ + union + { +#ifdef VMM_INCLUDED_SRC_VMMR0_GVMMR0Internal_h + struct GVMMPERVCPU s; +#endif + uint8_t padding[256]; + } gvmm; + + /** The HM per vcpu data. */ + union + { +#if defined(VMM_INCLUDED_SRC_include_HMInternal_h) && defined(IN_RING0) + struct HMR0PERVCPU s; +#endif + uint8_t padding[1024]; + } hmr0; + +#ifdef VBOX_WITH_NEM_R0 + /** The NEM per vcpu data. */ + union + { +# if defined(VMM_INCLUDED_SRC_include_NEMInternal_h) && defined(IN_RING0) + struct NEMR0PERVCPU s; +# endif + uint8_t padding[64]; + } nemr0; +#endif + + union + { +#if defined(VMM_INCLUDED_SRC_include_VMMInternal_h) && defined(IN_RING0) + struct VMMR0PERVCPU s; +#endif + uint8_t padding[896]; + } vmmr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_PGMInternal_h) && defined(IN_RING0) + struct PGMR0PERVCPU s; +#endif + uint8_t padding[64]; + } pgmr0; + + /** Padding the structure size to page boundrary. */ +#ifdef VBOX_WITH_NEM_R0 + uint8_t abPadding3[16384 - 64*2 - 256 - 1024 - 64 - 896 - 64]; +#else + uint8_t abPadding3[16384 - 64*2 - 256 - 1024 - 896 - 64]; +#endif +} GVMCPU; +#if RT_GNUC_PREREQ(4, 6) && defined(__cplusplus) +# pragma GCC diagnostic push +#endif +#if RT_GNUC_PREREQ(4, 3) && defined(__cplusplus) +# pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif +AssertCompileMemberAlignment(GVMCPU, idCpu, 16384); +AssertCompileMemberAlignment(GVMCPU, gvmm, 64); +#ifdef VBOX_WITH_NEM_R0 +AssertCompileMemberAlignment(GVMCPU, nemr0, 64); +#endif +AssertCompileSizeAlignment(GVMCPU, 16384); +#if RT_GNUC_PREREQ(4, 6) && defined(__cplusplus) +# pragma GCC diagnostic pop +#endif + +/** @} */ + +/** @defgroup grp_gvm GVM - The Global VM Data + * @ingroup grp_vmm + * @{ + */ + +/** + * The Global VM Data. + * + * This is a ring-0 only structure where we put items we don't need to + * share with ring-3 or GC, like for instance various RTR0MEMOBJ handles. + * + * Unlike VM, there are no special alignment restrictions here. The + * paddings are checked by compile time assertions. + */ +#if defined(__cplusplus) && !defined(GVM_C_STYLE_STRUCTURES) +typedef struct GVM : public VM +#else +typedef struct GVM +#endif +{ +#if !defined(__cplusplus) || defined(GVM_C_STYLE_STRUCTURES) + VM s; +#endif + /** Magic / eye-catcher (GVM_MAGIC). */ + uint32_t u32Magic; + /** The global VM handle for this VM. */ + uint32_t hSelf; + /** Pointer to this structure (for validation purposes). */ + PGVM pSelf; + /** The ring-3 mapping of the VM structure. */ + PVMR3 pVMR3; + /** The support driver session the VM is associated with. */ + PSUPDRVSESSION pSession; + /** Number of Virtual CPUs, i.e. how many entries there are in aCpus. + * Same same as VM::cCpus. */ + uint32_t cCpus; + /** Padding so gvmm starts on a 64 byte boundrary. */ + uint8_t abPadding[HC_ARCH_BITS == 32 ? 12 + 28 : 28]; + + /** The GVMM per vm data. */ + union + { +#ifdef VMM_INCLUDED_SRC_VMMR0_GVMMR0Internal_h + struct GVMMPERVM s; +#endif + uint8_t padding[4352]; + } gvmm; + + /** The GMM per vm data. */ + union + { +#ifdef VMM_INCLUDED_SRC_VMMR0_GMMR0Internal_h + struct GMMPERVM s; +#endif + uint8_t padding[1024]; + } gmm; + + /** The HM per vm data. */ + union + { +#if defined(VMM_INCLUDED_SRC_include_HMInternal_h) && defined(IN_RING0) + struct HMR0PERVM s; +#endif + uint8_t padding[256]; + } hmr0; + +#ifdef VBOX_WITH_NEM_R0 + /** The NEM per vcpu data. */ + union + { +# if defined(VMM_INCLUDED_SRC_include_NEMInternal_h) && defined(IN_RING0) + struct NEMR0PERVM s; +# endif + uint8_t padding[256]; + } nemr0; +#endif + + /** The RAWPCIVM per vm data. */ + union + { +#ifdef VBOX_INCLUDED_rawpci_h + struct RAWPCIPERVM s; +#endif + uint8_t padding[64]; + } rawpci; + + union + { +#if defined(VMM_INCLUDED_SRC_include_PDMInternal_h) && defined(IN_RING0) + struct PDMR0PERVM s; +#endif + uint8_t padding[3008]; + } pdmr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_PGMInternal_h) && defined(IN_RING0) + struct PGMR0PERVM s; +#endif + uint8_t padding[1920]; + } pgmr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_IOMInternal_h) && defined(IN_RING0) + struct IOMR0PERVM s; +#endif + uint8_t padding[512]; + } iomr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_APICInternal_h) && defined(IN_RING0) + struct APICR0PERVM s; +#endif + uint8_t padding[64]; + } apicr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_DBGFInternal_h) && defined(IN_RING0) + struct DBGFR0PERVM s; +#endif + uint8_t padding[1024]; + } dbgfr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_TMInternal_h) && defined(IN_RING0) + TMR0PERVM s; +#endif + uint8_t padding[192]; + } tmr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_VMMInternal_h) && defined(IN_RING0) + VMMR0PERVM s; +#endif + uint8_t padding[704]; + } vmmr0; + + /** Padding so aCpus starts on a page boundrary. */ +#ifdef VBOX_WITH_NEM_R0 + uint8_t abPadding2[16384 - 64 - 4352 - 1024 - 256 - 256 - 64 - 3008 - 1920 - 512 - 64 - 1024 - 192 - 704 - sizeof(PGVMCPU) * VMM_MAX_CPU_COUNT]; +#else + uint8_t abPadding2[16384 - 64 - 4352 - 1024 - 256 - 64 - 3008 - 1920 - 512 - 64 - 1024 - 192 - 704 - sizeof(PGVMCPU) * VMM_MAX_CPU_COUNT]; +#endif + + /** For simplifying CPU enumeration in VMMAll code. */ + PGVMCPU apCpusR0[VMM_MAX_CPU_COUNT]; + + /** GVMCPU array for the configured number of virtual CPUs. */ + GVMCPU aCpus[1]; +} GVM; +#if 0 +#if RT_GNUC_PREREQ(4, 6) && defined(__cplusplus) +# pragma GCC diagnostic push +#endif +#if RT_GNUC_PREREQ(4, 3) && defined(__cplusplus) +# pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif +AssertCompileMemberAlignment(GVM, u32Magic, 64); +AssertCompileMemberAlignment(GVM, gvmm, 64); +AssertCompileMemberAlignment(GVM, gmm, 64); +#ifdef VBOX_WITH_NEM_R0 +AssertCompileMemberAlignment(GVM, nemr0, 64); +#endif +AssertCompileMemberAlignment(GVM, rawpci, 64); +AssertCompileMemberAlignment(GVM, pdmr0, 64); +AssertCompileMemberAlignment(GVM, aCpus, 16384); +AssertCompileSizeAlignment(GVM, 16384); +#if RT_GNUC_PREREQ(4, 6) && defined(__cplusplus) +# pragma GCC diagnostic pop +#endif +#endif + +/** The GVM::u32Magic value (Wayne Shorter). */ +#define GVM_MAGIC 0x19330825 + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_gvm_h */ + diff --git a/include/VBox/vmm/gvm.mac b/include/VBox/vmm/gvm.mac new file mode 100644 index 00000000..af43f6ed --- /dev/null +++ b/include/VBox/vmm/gvm.mac @@ -0,0 +1,118 @@ +;; @file +; GVM - The Global VM Data. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_vmm_gvm_mac +%define ___VBox_vmm_gvm_mac + +%include "VBox/vmm/vm.mac" + +struc GVMCPU + .s resb VMCPU_size + + .idCpu resd 1 + + alignb 8 + .hEMT RTR0PTR_RES 1 + .pGVM RTR0PTR_RES 1 + .pVMR0 RTR0PTR_RES 1 + .pVCpuR3 RTR3PTR_RES 1 + + alignb 64 + .idHostCpu resd 1 + .iHostCpuSet resd 1 + + alignb 64 + .gvmm resb 256 + alignb 64 + .hmr0 resb 1024 +%ifdef VBOX_WITH_NEM_R0 + .nemr0 resb 64 +%endif + alignb 64 + .vmmr0 resb 896 + alignb 64 + .pgmr0 resb 64 + alignb 16384 +endstruc + + +struc GVM + .s resb VM_size + + .u32Magic resd 1 + .hSelf resd 1 + alignb 8 + .pSelf RTR0PTR_RES 1 + .pVMR3 RTR3PTR_RES 1 + .pSession RTR0PTR_RES 1 + .cCpus resd 1 + + alignb 64 + .gvmm resb 4352 + alignb 64 + .gmm resb 1024 + alignb 64 + .hmr0 resb 256 +%ifdef VBOX_WITH_NEM_R0 + alignb 64 + .nemr0 resb 256 +%endif + alignb 64 + .rawpci resb 64 + alignb 64 + .pdmr0 resb 3008 + alignb 64 + .pgmr0 resb 1920 + alignb 64 + .iomr0 resb 512 + alignb 64 + .apicr0 resb 64 + alignb 64 + .dbgfr0 resb 1024 + alignb 64 + .tmr0 resb 128 + + times ((($ + VMM_MAX_CPU_COUNT * RTR0PTR_CB + 16383) & ~16383) - ($ + VMM_MAX_CPU_COUNT * RTR0PTR_CB)) resb 1 + .apCpusR0 RTR0PTR_RES VMM_MAX_CPU_COUNT + + alignb 16384 + .aCpus resb GVMCPU_size +endstruc + +%define GVM_MAGIC 0x19330825 + + +%endif + diff --git a/include/VBox/vmm/gvmm.h b/include/VBox/vmm/gvmm.h new file mode 100644 index 00000000..788c41d4 --- /dev/null +++ b/include/VBox/vmm/gvmm.h @@ -0,0 +1,364 @@ +/* $Id: gvmm.h $ */ +/** @file + * GVMM - The Global VM Manager. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_gvmm_h +#define VBOX_INCLUDED_vmm_gvmm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/stam.h> +#include <VBox/sup.h> +#include <VBox/param.h> +#include <iprt/cpuset.h> /* RTCPUSET_MAX_CPUS */ + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_gvmm GVMM - The Global VM Manager. + * @ingroup grp_vmm + * @{ + */ + +/** @def IN_GVMM_R0 + * Used to indicate whether we're inside the same link module as the ring 0 + * part of the Global VM Manager or not. + */ +#ifdef DOXYGEN_RUNNING +# define IN_GVMM_R0 +#endif +/** @def GVMMR0DECL + * Ring 0 VM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_GVMM_R0 +# define GVMMR0DECL(type) DECLEXPORT(type) VBOXCALL +#else +# define GVMMR0DECL(type) DECLIMPORT(type) VBOXCALL +#endif + +/** @def NIL_GVM_HANDLE + * The nil GVM VM handle value (VM::hSelf). + */ +#define NIL_GVM_HANDLE 0 + + +/** + * The scheduler statistics + */ +typedef struct GVMMSTATSSCHED +{ + /** The number of calls to GVMMR0SchedHalt. */ + uint64_t cHaltCalls; + /** The number of times we did go to sleep in GVMMR0SchedHalt. */ + uint64_t cHaltBlocking; + /** The number of times we timed out in GVMMR0SchedHalt. */ + uint64_t cHaltTimeouts; + /** The number of times we didn't go to sleep in GVMMR0SchedHalt. */ + uint64_t cHaltNotBlocking; + /** The number of wake ups done during GVMMR0SchedHalt. */ + uint64_t cHaltWakeUps; + + /** The number of calls to GVMMR0WakeUp. */ + uint64_t cWakeUpCalls; + /** The number of times the EMT thread wasn't actually halted when GVMMR0WakeUp + * was called. */ + uint64_t cWakeUpNotHalted; + /** The number of wake ups done during GVMMR0WakeUp (not counting the explicit + * one). */ + uint64_t cWakeUpWakeUps; + + /** The number of calls to GVMMR0Poke. */ + uint64_t cPokeCalls; + /** The number of times the EMT thread wasn't actually busy when + * GVMMR0Poke was called. */ + uint64_t cPokeNotBusy; + + /** The number of calls to GVMMR0SchedPoll. */ + uint64_t cPollCalls; + /** The number of times the EMT has halted in a GVMMR0SchedPoll call. */ + uint64_t cPollHalts; + /** The number of wake ups done during GVMMR0SchedPoll. */ + uint64_t cPollWakeUps; + + uint64_t u64Alignment; /**< padding */ +} GVMMSTATSSCHED; +/** Pointer to the GVMM scheduler statistics. */ +typedef GVMMSTATSSCHED *PGVMMSTATSSCHED; + +/** + * Per host cpu statistics. + */ +typedef struct GVMMSTATSHOSTCPU +{ + /** The CPU ID. */ + RTCPUID idCpu; + /** The CPU's set index. */ + uint32_t idxCpuSet; + /** The desired PPT frequency. */ + uint32_t uDesiredHz; + /** The current PPT timer frequency. */ + uint32_t uTimerHz; + /** The number of times the PPT was changed. */ + uint32_t cChanges; + /** The number of times the PPT was started. */ + uint32_t cStarts; +} GVMMSTATSHOSTCPU; +/** Pointer to the GVMM per host CPU statistics. */ +typedef GVMMSTATSHOSTCPU *PGVMMSTATSHOSTCPU; + +/** + * Per VCpu statistics + */ +typedef struct GVMMSTATSVMCPU +{ + uint32_t cWakeUpTimerHits; + uint32_t cWakeUpTimerMisses; + uint32_t cWakeUpTimerCanceled; + uint32_t cWakeUpTimerSameCpu; + STAMPROFILE Start; + STAMPROFILE Stop; +} GVMMSTATSVMCPU; +/** Ptoiner to the GVMM per VCpu statistics. */ +typedef GVMMSTATSVMCPU *PGVMMSTATSVMCPU; + +/** + * The GVMM statistics. + */ +typedef struct GVMMSTATS +{ + /** The VM statistics if a VM was specified. */ + GVMMSTATSSCHED SchedVM; + /** The sum statistics of all VMs accessible to the caller. */ + GVMMSTATSSCHED SchedSum; + /** The number of VMs accessible to the caller. */ + uint32_t cVMs; + /** The number of emulation threads in those VMs. */ + uint32_t cEMTs; + /** Padding. */ + uint32_t u32Padding; + /** The number of valid entries in aHostCpus. */ + uint32_t cHostCpus; + /** Per EMT statistics for the specified VM, zero if non specified. */ + GVMMSTATSVMCPU aVCpus[VMM_MAX_CPU_COUNT]; + /** Per host CPU statistics. */ + GVMMSTATSHOSTCPU aHostCpus[RTCPUSET_MAX_CPUS]; +} GVMMSTATS; +/** Pointer to the GVMM statistics. */ +typedef GVMMSTATS *PGVMMSTATS; +/** Const pointer to the GVMM statistics. */ +typedef const GVMMSTATS *PCGVMMSTATS; + +/** + * Per-VM callback for GVMMR0EnumVMs. + * + * @note This is called while holding the VM used list lock, so only suitable + * for quick and simple jobs! + * + * @returns VINF_SUCCESS to continue the enumeration, anything stops it and + * returns the status code. + * @param pGVM The VM + * @param pvUser The user parameter. + * */ +typedef DECLCALLBACKTYPE(int, FNGVMMR0ENUMCALLBACK,(PGVM pGVM, void *pvUser)); +/** Pointer to an VM enumeration callback function. */ +typedef FNGVMMR0ENUMCALLBACK *PFNGVMMR0ENUMCALLBACK; + +/** + * Worker thread IDs. + */ +typedef enum GVMMWORKERTHREAD +{ + /** The usual invalid zero value. */ + GVMMWORKERTHREAD_INVALID = 0, + /** PGM handy page allocator thread. */ + GVMMWORKERTHREAD_PGM_ALLOCATOR, + /** End of valid worker thread values. */ + GVMMWORKERTHREAD_END, + /** Make sure the type size is 32 bits. */ + GVMMWORKERTHREAD_32_BIT_HACK = 0x7fffffff +} GVMMWORKERTHREAD; + +GVMMR0DECL(int) GVMMR0Init(void); +GVMMR0DECL(void) GVMMR0Term(void); +GVMMR0DECL(int) GVMMR0SetConfig(PSUPDRVSESSION pSession, const char *pszName, uint64_t u64Value); +GVMMR0DECL(int) GVMMR0QueryConfig(PSUPDRVSESSION pSession, const char *pszName, uint64_t *pu64Value); + +GVMMR0DECL(int) GVMMR0CreateVM(PSUPDRVSESSION pSession, uint32_t cCpus, PVMCC *ppVM); +GVMMR0DECL(int) GVMMR0InitVM(PGVM pGVM); +GVMMR0DECL(void) GVMMR0DoneInitVM(PGVM pGVM); +GVMMR0DECL(bool) GVMMR0DoingTermVM(PGVM pGVM); +GVMMR0DECL(int) GVMMR0DestroyVM(PGVM pGVM); +GVMMR0DECL(int) GVMMR0RegisterVCpu(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0DeregisterVCpu(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0RegisterWorkerThread(PGVM pGVM, GVMMWORKERTHREAD enmWorker, RTNATIVETHREAD hThreadR3); +GVMMR0DECL(int) GVMMR0DeregisterWorkerThread(PGVM pGVM, GVMMWORKERTHREAD enmWorker); +GVMMR0DECL(PGVM) GVMMR0ByHandle(uint32_t hGVM); +GVMMR0DECL(int) GVMMR0ValidateGVM(PGVM pGVM); +GVMMR0DECL(int) GVMMR0ValidateGVMandEMT(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0ValidateGVMandEMTorWorker(PGVM pGVM, VMCPUID idCpu, GVMMWORKERTHREAD enmWorker); +GVMMR0DECL(PVMCC) GVMMR0GetVMByEMT(RTNATIVETHREAD hEMT); +GVMMR0DECL(PGVMCPU) GVMMR0GetGVCpuByEMT(RTNATIVETHREAD hEMT); +GVMMR0DECL(PGVMCPU) GVMMR0GetGVCpuByGVMandEMT(PGVM pGVM, RTNATIVETHREAD hEMT); +GVMMR0DECL(RTNATIVETHREAD) GVMMR0GetRing3ThreadForSelf(PGVM pGVM); +GVMMR0DECL(RTHCPHYS) GVMMR0ConvertGVMPtr2HCPhys(PGVM pGVM, void *pv); +GVMMR0DECL(int) GVMMR0SchedHalt(PGVM pGVM, PGVMCPU pGVCpu, uint64_t u64ExpireGipTime); +GVMMR0DECL(int) GVMMR0SchedHaltReq(PGVM pGVM, VMCPUID idCpu, uint64_t u64ExpireGipTime); +GVMMR0DECL(int) GVMMR0SchedWakeUp(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0SchedWakeUpEx(PGVM pGVM, VMCPUID idCpu, bool fTakeUsedLock); +GVMMR0DECL(int) GVMMR0SchedWakeUpNoGVMNoLock(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0SchedPoke(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0SchedPokeEx(PGVM pGVM, VMCPUID idCpu, bool fTakeUsedLock); +GVMMR0DECL(int) GVMMR0SchedPokeNoGVMNoLock(PVMCC pVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0SchedWakeUpAndPokeCpus(PGVM pGVM, PCVMCPUSET pSleepSet, PCVMCPUSET pPokeSet); +GVMMR0DECL(int) GVMMR0SchedPoll(PGVM pGVM, VMCPUID idCpu, bool fYield); +GVMMR0DECL(void) GVMMR0SchedUpdatePeriodicPreemptionTimer(PGVM pGVM, RTCPUID idHostCpu, uint32_t uHz); +GVMMR0DECL(int) GVMMR0EnumVMs(PFNGVMMR0ENUMCALLBACK pfnCallback, void *pvUser); +GVMMR0DECL(int) GVMMR0QueryStatistics(PGVMMSTATS pStats, PSUPDRVSESSION pSession, PGVM pGVM); +GVMMR0DECL(int) GVMMR0ResetStatistics(PCGVMMSTATS pStats, PSUPDRVSESSION pSession, PGVM pGVM); + + +/** + * Request packet for calling GVMMR0CreateVM. + */ +typedef struct GVMMCREATEVMREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** The support driver session. (IN) */ + PSUPDRVSESSION pSession; + /** Number of virtual CPUs for the new VM. (IN) */ + uint32_t cCpus; + /** Pointer to the ring-3 mapping of the shared VM structure on return. (OUT) */ + PVMR3 pVMR3; + /** Pointer to the ring-0 mapping of the shared VM structure on return. (OUT) */ + PVMR0 pVMR0; +} GVMMCREATEVMREQ; +/** Pointer to a GVMMR0CreateVM request packet. */ +typedef GVMMCREATEVMREQ *PGVMMCREATEVMREQ; + +GVMMR0DECL(int) GVMMR0CreateVMReq(PGVMMCREATEVMREQ pReq, PSUPDRVSESSION pSession); + + +/** + * Request packet for calling GVMMR0RegisterWorkerThread. + */ +typedef struct GVMMREGISTERWORKERTHREADREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Ring-3 native thread handle of the caller. (IN) */ + RTNATIVETHREAD hNativeThreadR3; +} GVMMREGISTERWORKERTHREADREQ; +/** Pointer to a GVMMR0RegisterWorkerThread request packet. */ +typedef GVMMREGISTERWORKERTHREADREQ *PGVMMREGISTERWORKERTHREADREQ; + + +/** + * Request buffer for GVMMR0SchedWakeUpAndPokeCpusReq / VMMR0_DO_GVMM_SCHED_WAKE_UP_AND_POKE_CPUS. + * @see GVMMR0SchedWakeUpAndPokeCpus. + */ +typedef struct GVMMSCHEDWAKEUPANDPOKECPUSREQ /* nice and unreadable... */ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The sleeper set. */ + VMCPUSET SleepSet; + /** The set of virtual CPUs to poke. */ + VMCPUSET PokeSet; +} GVMMSCHEDWAKEUPANDPOKECPUSREQ; +/** Pointer to a GVMMR0QueryStatisticsReq / VMMR0_DO_GVMM_QUERY_STATISTICS request buffer. */ +typedef GVMMSCHEDWAKEUPANDPOKECPUSREQ *PGVMMSCHEDWAKEUPANDPOKECPUSREQ; + +GVMMR0DECL(int) GVMMR0SchedWakeUpAndPokeCpusReq(PGVM pGVM, PGVMMSCHEDWAKEUPANDPOKECPUSREQ pReq); + + +/** + * Request buffer for GVMMR0QueryStatisticsReq / VMMR0_DO_GVMM_QUERY_STATISTICS. + * @see GVMMR0QueryStatistics. + */ +typedef struct GVMMQUERYSTATISTICSSREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The support driver session. */ + PSUPDRVSESSION pSession; + /** The statistics. */ + GVMMSTATS Stats; +} GVMMQUERYSTATISTICSSREQ; +/** Pointer to a GVMMR0QueryStatisticsReq / VMMR0_DO_GVMM_QUERY_STATISTICS request buffer. */ +typedef GVMMQUERYSTATISTICSSREQ *PGVMMQUERYSTATISTICSSREQ; + +GVMMR0DECL(int) GVMMR0QueryStatisticsReq(PGVM pGVM, PGVMMQUERYSTATISTICSSREQ pReq, PSUPDRVSESSION pSession); + + +/** + * Request buffer for GVMMR0ResetStatisticsReq / VMMR0_DO_GVMM_RESET_STATISTICS. + * @see GVMMR0ResetStatistics. + */ +typedef struct GVMMRESETSTATISTICSSREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The support driver session. */ + PSUPDRVSESSION pSession; + /** The statistics to reset. + * Any non-zero entry will be reset (if permitted). */ + GVMMSTATS Stats; +} GVMMRESETSTATISTICSSREQ; +/** Pointer to a GVMMR0ResetStatisticsReq / VMMR0_DO_GVMM_RESET_STATISTICS request buffer. */ +typedef GVMMRESETSTATISTICSSREQ *PGVMMRESETSTATISTICSSREQ; + +GVMMR0DECL(int) GVMMR0ResetStatisticsReq(PGVM pGVM, PGVMMRESETSTATISTICSSREQ pReq, PSUPDRVSESSION pSession); + + +#ifdef IN_RING3 +VMMR3_INT_DECL(int) GVMMR3CreateVM(PUVM pUVM, uint32_t cCpus, PSUPDRVSESSION pSession, PVM *ppVM, PRTR0PTR ppVMR0); +VMMR3_INT_DECL(int) GVMMR3DestroyVM(PUVM pUVM, PVM pVM); +VMMR3_INT_DECL(int) GVMMR3RegisterVCpu(PVM pVM, VMCPUID idCpu); +VMMR3_INT_DECL(int) GVMMR3DeregisterVCpu(PVM pVM, VMCPUID idCpu); +VMMR3_INT_DECL(int) GVMMR3RegisterWorkerThread(PVM pVM, GVMMWORKERTHREAD enmWorker); +VMMR3_INT_DECL(int) GVMMR3DeregisterWorkerThread(PVM pVM, GVMMWORKERTHREAD enmWorker); +#endif + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_gvmm_h */ + diff --git a/include/VBox/vmm/hm.h b/include/VBox/vmm/hm.h new file mode 100644 index 00000000..2dc1d976 --- /dev/null +++ b/include/VBox/vmm/hm.h @@ -0,0 +1,336 @@ +/** @file + * HM - Intel/AMD VM Hardware Assisted Virtualization Manager (VMM) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_hm_h +#define VBOX_INCLUDED_vmm_hm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/pgm.h> +#include <VBox/vmm/cpum.h> +#include <VBox/vmm/vmm.h> +#include <VBox/vmm/hm_svm.h> +#include <VBox/vmm/hm_vmx.h> +#include <VBox/vmm/trpm.h> +#include <iprt/mp.h> + + +/** @defgroup grp_hm The Hardware Assisted Virtualization Manager API + * @ingroup grp_vmm + * @{ + */ + +RT_C_DECLS_BEGIN + +/** + * Checks whether HM (VT-x/AMD-V) is being used by this VM. + * + * @retval true if used. + * @retval false if software virtualization (raw-mode) or NEM is used. + * + * @param a_pVM The cross context VM structure. + * @deprecated Please use VM_IS_RAW_MODE_ENABLED, VM_IS_HM_OR_NEM_ENABLED, or + * VM_IS_HM_ENABLED instead. + * @internal + */ +#if defined(VBOX_STRICT) && defined(IN_RING3) +# define HMIsEnabled(a_pVM) HMIsEnabledNotMacro(a_pVM) +#else +# define HMIsEnabled(a_pVM) ((a_pVM)->fHMEnabled) +#endif + +/** + * Checks whether raw-mode context is required for HM purposes + * + * @retval true if required by HM for doing switching the cpu to 64-bit mode. + * @retval false if not required by HM. + * + * @param a_pVM The cross context VM structure. + * @internal + */ +#if HC_ARCH_BITS == 64 +# define HMIsRawModeCtxNeeded(a_pVM) (false) +#else +# define HMIsRawModeCtxNeeded(a_pVM) ((a_pVM)->fHMNeedRawModeCtx) +#endif + +/** + * Checks whether we're in the special hardware virtualization context. + * @returns true / false. + * @param a_pVCpu The caller's cross context virtual CPU structure. + * @thread EMT + */ +#ifdef IN_RING0 +# define HMIsInHwVirtCtx(a_pVCpu) (VMCPU_GET_STATE(a_pVCpu) == VMCPUSTATE_STARTED_HM) +#else +# define HMIsInHwVirtCtx(a_pVCpu) (false) +#endif + +/** + * Checks whether we're in the special hardware virtualization context and we + * cannot perform long jump without guru meditating and possibly messing up the + * host and/or guest state. + * + * This is after we've turned interrupts off and such. + * + * @returns true / false. + * @param a_pVCpu The caller's cross context virtual CPU structure. + * @thread EMT + */ +#ifdef IN_RING0 +# define HMIsInHwVirtNoLongJmpCtx(a_pVCpu) (VMCPU_GET_STATE(a_pVCpu) == VMCPUSTATE_STARTED_EXEC) +#else +# define HMIsInHwVirtNoLongJmpCtx(a_pVCpu) (false) +#endif + +/** @name All-context HM API. + * @{ */ +VMMDECL(bool) HMIsEnabledNotMacro(PVM pVM); +VMMDECL(bool) HMCanExecuteGuest(PVMCC pVM, PVMCPUCC pVCpu, PCCPUMCTX pCtx); +VMM_INT_DECL(int) HMInvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCVirt); +VMM_INT_DECL(bool) HMHasPendingIrq(PVMCC pVM); +VMM_INT_DECL(bool) HMSetSingleInstruction(PVMCC pVM, PVMCPUCC pVCpu, bool fEnable); +VMM_INT_DECL(bool) HMIsSvmActive(PVM pVM); +VMM_INT_DECL(bool) HMIsVmxActive(PVM pVM); +VMM_INT_DECL(const char *) HMGetVmxDiagDesc(VMXVDIAG enmDiag); +VMM_INT_DECL(const char *) HMGetVmxExitName(uint32_t uExit); +VMM_INT_DECL(const char *) HMGetSvmExitName(uint32_t uExit); +VMM_INT_DECL(void) HMDumpHwvirtVmxState(PVMCPU pVCpu); +VMM_INT_DECL(void) HMHCChangedPagingMode(PVM pVM, PVMCPUCC pVCpu, PGMMODE enmShadowMode, PGMMODE enmGuestMode); +VMM_INT_DECL(void) HMGetVmxMsrsFromHwvirtMsrs(PCSUPHWVIRTMSRS pMsrs, PVMXMSRS pVmxMsrs); +VMM_INT_DECL(void) HMGetSvmMsrsFromHwvirtMsrs(PCSUPHWVIRTMSRS pMsrs, PSVMMSRS pSvmMsrs); +/** @} */ + +/** @name All-context VMX helpers. + * + * These are hardware-assisted VMX functions (used by IEM/REM/CPUM and HM). Helpers + * based purely on the Intel VT-x specification (used by IEM/REM and HM) can be + * found in CPUM. + * @{ */ +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +VMM_INT_DECL(bool) HMIsSubjectToVmxPreemptTimerErratum(void); +#endif +VMM_INT_DECL(bool) HMCanExecuteVmxGuest(PVMCC pVM, PVMCPUCC pVCpu, PCCPUMCTX pCtx); +VMM_INT_DECL(TRPMEVENT) HMVmxEventTypeToTrpmEventType(uint32_t uIntInfo); +VMM_INT_DECL(uint32_t) HMTrpmEventTypeToVmxEventType(uint8_t uVector, TRPMEVENT enmTrpmEvent, bool fIcebp); +/** @} */ + +/** @name All-context SVM helpers. + * + * These are hardware-assisted SVM functions (used by IEM/REM/CPUM and HM). Helpers + * based purely on the AMD SVM specification (used by IEM/REM and HM) can be found + * in CPUM. + * @{ */ +VMM_INT_DECL(TRPMEVENT) HMSvmEventToTrpmEventType(PCSVMEVENT pSvmEvent, uint8_t uVector); +/** @} */ + +#ifndef IN_RC + +/** @name R0, R3 HM (VMX/SVM agnostic) handlers. + * @{ */ +VMM_INT_DECL(int) HMFlushTlb(PVMCPU pVCpu); +VMM_INT_DECL(int) HMFlushTlbOnAllVCpus(PVMCC pVM); +VMM_INT_DECL(int) HMInvalidatePageOnAllVCpus(PVMCC pVM, RTGCPTR GCVirt); +VMM_INT_DECL(int) HMInvalidatePhysPage(PVMCC pVM, RTGCPHYS GCPhys); +VMM_INT_DECL(bool) HMAreNestedPagingAndFullGuestExecEnabled(PVMCC pVM); +VMM_INT_DECL(bool) HMIsLongModeAllowed(PVMCC pVM); +VMM_INT_DECL(bool) HMIsNestedPagingActive(PVMCC pVM); +VMM_INT_DECL(bool) HMIsMsrBitmapActive(PVM pVM); +# ifdef VBOX_WITH_NESTED_HWVIRT_VMX +VMM_INT_DECL(void) HMNotifyVmxNstGstVmexit(PVMCPU pVCpu); +VMM_INT_DECL(void) HMNotifyVmxNstGstCurrentVmcsChanged(PVMCPU pVCpu); +# endif +/** @} */ + +/** @name R0, R3 SVM handlers. + * @{ */ +VMM_INT_DECL(bool) HMIsSvmVGifActive(PCVMCC pVM); +# ifdef VBOX_WITH_NESTED_HWVIRT_SVM +VMM_INT_DECL(void) HMNotifySvmNstGstVmexit(PVMCPUCC pVCpu, PCPUMCTX pCtx); +# endif +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +VMM_INT_DECL(int) HMIsSubjectToSvmErratum170(uint32_t *pu32Family, uint32_t *pu32Model, uint32_t *pu32Stepping); +# endif +VMM_INT_DECL(int) HMHCMaybeMovTprSvmHypercall(PVMCC pVM, PVMCPUCC pVCpu); +/** @} */ + +#else /* Nops in RC: */ + +/** @name RC HM (VMX/SVM agnostic) handlers. + * @{ */ +# define HMFlushTlb(pVCpu) do { } while (0) +# define HMFlushTlbOnAllVCpus(pVM) do { } while (0) +# define HMInvalidatePageOnAllVCpus(pVM, GCVirt) do { } while (0) +# define HMInvalidatePhysPage(pVM, GCVirt) do { } while (0) +# define HMAreNestedPagingAndFullGuestExecEnabled(pVM) false +# define HMIsLongModeAllowed(pVM) false +# define HMIsNestedPagingActive(pVM) false +# define HMIsMsrBitmapsActive(pVM) false +/** @} */ + +/** @name RC SVM handlers. + * @{ */ +# define HMIsSvmVGifActive(pVM) false +# define HMNotifySvmNstGstVmexit(pVCpu, pCtx) do { } while (0) +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# define HMIsSubjectToSvmErratum170(puFamily, puModel, puStepping) false +# endif +# define HMHCMaybeMovTprSvmHypercall(pVM, pVCpu) do { } while (0) +/** @} */ + +#endif + +/** @name HMVMX_READ_XXX - Flags for reading auxiliary VM-exit VMCS fields. + * + * These flags allow reading VMCS fields that are not necessarily part of the + * guest-CPU state but are needed while handling VM-exits. + * + * @note If you add any fields here, make sure to update VMXR0GetExitAuxInfo. + * + * @{ + */ +#define HMVMX_READ_IDT_VECTORING_INFO RT_BIT_32(0) +#define HMVMX_READ_IDT_VECTORING_ERROR_CODE RT_BIT_32(1) +#define HMVMX_READ_EXIT_QUALIFICATION RT_BIT_32(2) +#define HMVMX_READ_EXIT_INSTR_LEN RT_BIT_32(3) +#define HMVMX_READ_EXIT_INTERRUPTION_INFO RT_BIT_32(4) +#define HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE RT_BIT_32(5) +#define HMVMX_READ_EXIT_INSTR_INFO RT_BIT_32(6) +#define HMVMX_READ_GUEST_LINEAR_ADDR RT_BIT_32(7) +#define HMVMX_READ_GUEST_PHYSICAL_ADDR RT_BIT_32(8) +#define HMVMX_READ_GUEST_PENDING_DBG_XCPTS RT_BIT_32(9) + +/** All the VMCS fields required for processing of exception/NMI VM-exits. */ +#define HMVMX_READ_XCPT_INFO ( HMVMX_READ_EXIT_INTERRUPTION_INFO \ + | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE \ + | HMVMX_READ_EXIT_INSTR_LEN \ + | HMVMX_READ_IDT_VECTORING_INFO \ + | HMVMX_READ_IDT_VECTORING_ERROR_CODE) + +/** Mask of all valid HMVMX_READ_XXX flags. */ +#define HMVMX_READ_VALID_MASK ( HMVMX_READ_IDT_VECTORING_INFO \ + | HMVMX_READ_IDT_VECTORING_ERROR_CODE \ + | HMVMX_READ_EXIT_QUALIFICATION \ + | HMVMX_READ_EXIT_INSTR_LEN \ + | HMVMX_READ_EXIT_INTERRUPTION_INFO \ + | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE \ + | HMVMX_READ_EXIT_INSTR_INFO \ + | HMVMX_READ_GUEST_LINEAR_ADDR \ + | HMVMX_READ_GUEST_PHYSICAL_ADDR \ + | HMVMX_READ_GUEST_PENDING_DBG_XCPTS) +/** @} */ + +#ifdef IN_RING0 +/** @defgroup grp_hm_r0 The HM ring-0 Context API + * @{ + */ +/** + * HM VM-exit auxiliary info. + */ +typedef union +{ + /** VMX VM-exit auxiliary info. */ + VMXEXITAUX Vmx; + /** SVM \#VMEXIT auxiliary info. */ + SVMEXITAUX Svm; +} HMEXITAUX; +/** Pointer to HM-exit auxiliary info union. */ +typedef HMEXITAUX *PHMEXITAUX; +/** Pointer to a const HM-exit auxiliary info union. */ +typedef const HMEXITAUX *PCHMEXITAUX; + +VMMR0_INT_DECL(int) HMR0Init(void); +VMMR0_INT_DECL(int) HMR0Term(void); +VMMR0_INT_DECL(int) HMR0InitVM(PVMCC pVM); +VMMR0_INT_DECL(int) HMR0TermVM(PVMCC pVM); +VMMR0_INT_DECL(int) HMR0EnableAllCpus(PVMCC pVM); +# ifdef VBOX_WITH_RAW_MODE +VMMR0_INT_DECL(int) HMR0EnterSwitcher(PVMCC pVM, VMMSWITCHER enmSwitcher, bool *pfVTxDisabled); +VMMR0_INT_DECL(void) HMR0LeaveSwitcher(PVMCC pVM, bool fVTxDisabled); +# endif + +VMMR0_INT_DECL(int) HMR0SetupVM(PVMCC pVM); +VMMR0_INT_DECL(int) HMR0RunGuestCode(PVMCC pVM, PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) HMR0Enter(PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) HMR0LeaveCpu(PVMCPUCC pVCpu); +VMMR0_INT_DECL(void) HMR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, void *pvUser); +VMMR0_INT_DECL(void) HMR0NotifyCpumUnloadedGuestFpuState(PVMCPUCC VCpu); +VMMR0_INT_DECL(void) HMR0NotifyCpumModifiedHostCr0(PVMCPUCC VCpu); +VMMR0_INT_DECL(bool) HMR0SuspendPending(void); +VMMR0_INT_DECL(int) HMR0InvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCVirt); +VMMR0_INT_DECL(int) HMR0ImportStateOnDemand(PVMCPUCC pVCpu, uint64_t fWhat); +VMMR0_INT_DECL(int) HMR0GetExitAuxInfo(PVMCPUCC pVCpu, PHMEXITAUX pHmExitAux, uint32_t fWhat); +/** @} */ +#endif /* IN_RING0 */ + + +#ifdef IN_RING3 +/** @defgroup grp_hm_r3 The HM ring-3 Context API + * @{ + */ +VMMR3DECL(bool) HMR3IsEnabled(PUVM pUVM); +VMMR3DECL(bool) HMR3IsNestedPagingActive(PUVM pUVM); +VMMR3DECL(bool) HMR3AreVirtApicRegsEnabled(PUVM pUVM); +VMMR3DECL(bool) HMR3IsPostedIntrsEnabled(PUVM pUVM); +VMMR3DECL(bool) HMR3IsVpidActive(PUVM pUVM); +VMMR3DECL(bool) HMR3IsUXActive(PUVM pUVM); +VMMR3DECL(bool) HMR3IsSvmEnabled(PUVM pUVM); +VMMR3DECL(bool) HMR3IsVmxEnabled(PUVM pUVM); + +VMMR3_INT_DECL(int) HMR3Init(PVM pVM); +VMMR3_INT_DECL(int) HMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3_INT_DECL(void) HMR3Relocate(PVM pVM); +VMMR3_INT_DECL(int) HMR3Term(PVM pVM); +VMMR3_INT_DECL(void) HMR3Reset(PVM pVM); +VMMR3_INT_DECL(void) HMR3ResetCpu(PVMCPU pVCpu); +VMMR3_INT_DECL(void) HMR3CheckError(PVM pVM, int iStatusCode); +VMMR3_INT_DECL(void) HMR3NotifyDebugEventChanged(PVM pVM); +VMMR3_INT_DECL(void) HMR3NotifyDebugEventChangedPerCpu(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(bool) HMR3IsActive(PCVMCPU pVCpu); +VMMR3_INT_DECL(int) HMR3EnablePatching(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem); +VMMR3_INT_DECL(int) HMR3DisablePatching(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem); +VMMR3_INT_DECL(int) HMR3PatchTprInstr(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(bool) HMR3IsRescheduleRequired(PVM pVM, PCCPUMCTX pCtx); +VMMR3_INT_DECL(bool) HMR3IsVmxPreemptionTimerUsed(PVM pVM); +/** @} */ +#endif /* IN_RING3 */ + +/** @} */ +RT_C_DECLS_END + + +#endif /* !VBOX_INCLUDED_vmm_hm_h */ + diff --git a/include/VBox/vmm/hm_svm.h b/include/VBox/vmm/hm_svm.h new file mode 100644 index 00000000..403480c5 --- /dev/null +++ b/include/VBox/vmm/hm_svm.h @@ -0,0 +1,1169 @@ +/** @file + * HM - SVM (AMD-V) Structures and Definitions. (VMM) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_hm_svm_h +#define VBOX_INCLUDED_vmm_hm_svm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/assert.h> +#include <iprt/asm.h> + +#ifdef RT_OS_SOLARIS +# undef ES +# undef CS +# undef DS +# undef SS +# undef FS +# undef GS +#endif + +/** @defgroup grp_hm_svm SVM (AMD-V) Types and Definitions + * @ingroup grp_hm + * @{ + */ + +/** @name SVM generic / convenient defines. + * @{ + */ +/** Number of pages required for the VMCB. */ +#define SVM_VMCB_PAGES 1 +/** Number of pages required for the MSR permission bitmap. */ +#define SVM_MSRPM_PAGES 2 +/** Number of pages required for the IO permission bitmap. */ +#define SVM_IOPM_PAGES 3 +/** @} */ + +/* + * Ugly! + * When compiling the recompiler, its own svm.h defines clash with + * the following defines. Avoid just the duplicates here as we still + * require other definitions and structures in this header. + */ +#ifndef IN_REM_R3 +/** @name SVM_EXIT_XXX - SVM Basic Exit Reasons. + * @{ + */ +/** Invalid guest state in VMCB. */ +# define SVM_EXIT_INVALID (uint64_t)(-1) +/** Read from CR0-CR15. */ +# define SVM_EXIT_READ_CR0 0x0 +# define SVM_EXIT_READ_CR1 0x1 +# define SVM_EXIT_READ_CR2 0x2 +# define SVM_EXIT_READ_CR3 0x3 +# define SVM_EXIT_READ_CR4 0x4 +# define SVM_EXIT_READ_CR5 0x5 +# define SVM_EXIT_READ_CR6 0x6 +# define SVM_EXIT_READ_CR7 0x7 +# define SVM_EXIT_READ_CR8 0x8 +# define SVM_EXIT_READ_CR9 0x9 +# define SVM_EXIT_READ_CR10 0xa +# define SVM_EXIT_READ_CR11 0xb +# define SVM_EXIT_READ_CR12 0xc +# define SVM_EXIT_READ_CR13 0xd +# define SVM_EXIT_READ_CR14 0xe +# define SVM_EXIT_READ_CR15 0xf +/** Writes to CR0-CR15. */ +# define SVM_EXIT_WRITE_CR0 0x10 +# define SVM_EXIT_WRITE_CR1 0x11 +# define SVM_EXIT_WRITE_CR2 0x12 +# define SVM_EXIT_WRITE_CR3 0x13 +# define SVM_EXIT_WRITE_CR4 0x14 +# define SVM_EXIT_WRITE_CR5 0x15 +# define SVM_EXIT_WRITE_CR6 0x16 +# define SVM_EXIT_WRITE_CR7 0x17 +# define SVM_EXIT_WRITE_CR8 0x18 +# define SVM_EXIT_WRITE_CR9 0x19 +# define SVM_EXIT_WRITE_CR10 0x1a +# define SVM_EXIT_WRITE_CR11 0x1b +# define SVM_EXIT_WRITE_CR12 0x1c +# define SVM_EXIT_WRITE_CR13 0x1d +# define SVM_EXIT_WRITE_CR14 0x1e +# define SVM_EXIT_WRITE_CR15 0x1f +/** Read from DR0-DR15. */ +# define SVM_EXIT_READ_DR0 0x20 +# define SVM_EXIT_READ_DR1 0x21 +# define SVM_EXIT_READ_DR2 0x22 +# define SVM_EXIT_READ_DR3 0x23 +# define SVM_EXIT_READ_DR4 0x24 +# define SVM_EXIT_READ_DR5 0x25 +# define SVM_EXIT_READ_DR6 0x26 +# define SVM_EXIT_READ_DR7 0x27 +# define SVM_EXIT_READ_DR8 0x28 +# define SVM_EXIT_READ_DR9 0x29 +# define SVM_EXIT_READ_DR10 0x2a +# define SVM_EXIT_READ_DR11 0x2b +# define SVM_EXIT_READ_DR12 0x2c +# define SVM_EXIT_READ_DR13 0x2d +# define SVM_EXIT_READ_DR14 0x2e +# define SVM_EXIT_READ_DR15 0x2f +/** Writes to DR0-DR15. */ +# define SVM_EXIT_WRITE_DR0 0x30 +# define SVM_EXIT_WRITE_DR1 0x31 +# define SVM_EXIT_WRITE_DR2 0x32 +# define SVM_EXIT_WRITE_DR3 0x33 +# define SVM_EXIT_WRITE_DR4 0x34 +# define SVM_EXIT_WRITE_DR5 0x35 +# define SVM_EXIT_WRITE_DR6 0x36 +# define SVM_EXIT_WRITE_DR7 0x37 +# define SVM_EXIT_WRITE_DR8 0x38 +# define SVM_EXIT_WRITE_DR9 0x39 +# define SVM_EXIT_WRITE_DR10 0x3a +# define SVM_EXIT_WRITE_DR11 0x3b +# define SVM_EXIT_WRITE_DR12 0x3c +# define SVM_EXIT_WRITE_DR13 0x3d +# define SVM_EXIT_WRITE_DR14 0x3e +# define SVM_EXIT_WRITE_DR15 0x3f +/* Exception 0-31. */ +# define SVM_EXIT_XCPT_0 0x40 +# define SVM_EXIT_XCPT_1 0x41 +# define SVM_EXIT_XCPT_2 0x42 +# define SVM_EXIT_XCPT_3 0x43 +# define SVM_EXIT_XCPT_4 0x44 +# define SVM_EXIT_XCPT_5 0x45 +# define SVM_EXIT_XCPT_6 0x46 +# define SVM_EXIT_XCPT_7 0x47 +# define SVM_EXIT_XCPT_8 0x48 +# define SVM_EXIT_XCPT_9 0x49 +# define SVM_EXIT_XCPT_10 0x4a +# define SVM_EXIT_XCPT_11 0x4b +# define SVM_EXIT_XCPT_12 0x4c +# define SVM_EXIT_XCPT_13 0x4d +# define SVM_EXIT_XCPT_14 0x4e +# define SVM_EXIT_XCPT_15 0x4f +# define SVM_EXIT_XCPT_16 0x50 +# define SVM_EXIT_XCPT_17 0x51 +# define SVM_EXIT_XCPT_18 0x52 +# define SVM_EXIT_XCPT_19 0x53 +# define SVM_EXIT_XCPT_20 0x54 +# define SVM_EXIT_XCPT_21 0x55 +# define SVM_EXIT_XCPT_22 0x56 +# define SVM_EXIT_XCPT_23 0x57 +# define SVM_EXIT_XCPT_24 0x58 +# define SVM_EXIT_XCPT_25 0x59 +# define SVM_EXIT_XCPT_26 0x5a +# define SVM_EXIT_XCPT_27 0x5b +# define SVM_EXIT_XCPT_28 0x5c +# define SVM_EXIT_XCPT_29 0x5d +# define SVM_EXIT_XCPT_30 0x5e +# define SVM_EXIT_XCPT_31 0x5f +/* Exception (more readable) */ +# define SVM_EXIT_XCPT_DE SVM_EXIT_XCPT_0 +# define SVM_EXIT_XCPT_DB SVM_EXIT_XCPT_1 +# define SVM_EXIT_XCPT_NMI SVM_EXIT_XCPT_2 +# define SVM_EXIT_XCPT_BP SVM_EXIT_XCPT_3 +# define SVM_EXIT_XCPT_OF SVM_EXIT_XCPT_4 +# define SVM_EXIT_XCPT_BR SVM_EXIT_XCPT_5 +# define SVM_EXIT_XCPT_UD SVM_EXIT_XCPT_6 +# define SVM_EXIT_XCPT_NM SVM_EXIT_XCPT_7 +# define SVM_EXIT_XCPT_DF SVM_EXIT_XCPT_8 +# define SVM_EXIT_XCPT_CO_SEG_OVERRUN SVM_EXIT_XCPT_9 +# define SVM_EXIT_XCPT_TS SVM_EXIT_XCPT_10 +# define SVM_EXIT_XCPT_NP SVM_EXIT_XCPT_11 +# define SVM_EXIT_XCPT_SS SVM_EXIT_XCPT_12 +# define SVM_EXIT_XCPT_GP SVM_EXIT_XCPT_13 +# define SVM_EXIT_XCPT_PF SVM_EXIT_XCPT_14 +# define SVM_EXIT_XCPT_MF SVM_EXIT_XCPT_16 +# define SVM_EXIT_XCPT_AC SVM_EXIT_XCPT_17 +# define SVM_EXIT_XCPT_MC SVM_EXIT_XCPT_18 +# define SVM_EXIT_XCPT_XF SVM_EXIT_XCPT_19 +# define SVM_EXIT_XCPT_VE SVM_EXIT_XCPT_20 +# define SVM_EXIT_XCPT_SX SVM_EXIT_XCPT_30 +/** Physical maskable interrupt. */ +# define SVM_EXIT_INTR 0x60 +/** Non-maskable interrupt. */ +# define SVM_EXIT_NMI 0x61 +/** System Management interrupt. */ +# define SVM_EXIT_SMI 0x62 +/** Physical INIT signal. */ +# define SVM_EXIT_INIT 0x63 +/** Virtual interrupt. */ +# define SVM_EXIT_VINTR 0x64 +/** Write to CR0 that changed any bits other than CR0.TS or CR0.MP. */ +# define SVM_EXIT_CR0_SEL_WRITE 0x65 +/** IDTR read. */ +# define SVM_EXIT_IDTR_READ 0x66 +/** GDTR read. */ +# define SVM_EXIT_GDTR_READ 0x67 +/** LDTR read. */ +# define SVM_EXIT_LDTR_READ 0x68 +/** TR read. */ +# define SVM_EXIT_TR_READ 0x69 +/** IDTR write. */ +# define SVM_EXIT_IDTR_WRITE 0x6a +/** GDTR write. */ +# define SVM_EXIT_GDTR_WRITE 0x6b +/** LDTR write. */ +# define SVM_EXIT_LDTR_WRITE 0x6c +/** TR write. */ +# define SVM_EXIT_TR_WRITE 0x6d +/** RDTSC instruction. */ +# define SVM_EXIT_RDTSC 0x6e +/** RDPMC instruction. */ +# define SVM_EXIT_RDPMC 0x6f +/** PUSHF instruction. */ +# define SVM_EXIT_PUSHF 0x70 +/** POPF instruction. */ +# define SVM_EXIT_POPF 0x71 +/** CPUID instruction. */ +# define SVM_EXIT_CPUID 0x72 +/** RSM instruction. */ +# define SVM_EXIT_RSM 0x73 +/** IRET instruction. */ +# define SVM_EXIT_IRET 0x74 +/** Software interrupt (INTn instructions). */ +# define SVM_EXIT_SWINT 0x75 +/** INVD instruction. */ +# define SVM_EXIT_INVD 0x76 +/** PAUSE instruction. */ +# define SVM_EXIT_PAUSE 0x77 +/** HLT instruction. */ +# define SVM_EXIT_HLT 0x78 +/** INVLPG instructions. */ +# define SVM_EXIT_INVLPG 0x79 +/** INVLPGA instruction. */ +# define SVM_EXIT_INVLPGA 0x7a +/** IN or OUT accessing protected port (the EXITINFO1 field provides more information). */ +# define SVM_EXIT_IOIO 0x7b +/** RDMSR or WRMSR access to protected MSR. */ +# define SVM_EXIT_MSR 0x7c +/** task switch. */ +# define SVM_EXIT_TASK_SWITCH 0x7d +/** FP legacy handling enabled, and processor is frozen in an x87/mmx instruction waiting for an interrupt. */ +# define SVM_EXIT_FERR_FREEZE 0x7e +/** Shutdown. */ +# define SVM_EXIT_SHUTDOWN 0x7f +/** VMRUN instruction. */ +# define SVM_EXIT_VMRUN 0x80 +/** VMMCALL instruction. */ +# define SVM_EXIT_VMMCALL 0x81 +/** VMLOAD instruction. */ +# define SVM_EXIT_VMLOAD 0x82 +/** VMSAVE instruction. */ +# define SVM_EXIT_VMSAVE 0x83 +/** STGI instruction. */ +# define SVM_EXIT_STGI 0x84 +/** CLGI instruction. */ +# define SVM_EXIT_CLGI 0x85 +/** SKINIT instruction. */ +# define SVM_EXIT_SKINIT 0x86 +/** RDTSCP instruction. */ +# define SVM_EXIT_RDTSCP 0x87 +/** ICEBP instruction. */ +# define SVM_EXIT_ICEBP 0x88 +/** WBINVD instruction. */ +# define SVM_EXIT_WBINVD 0x89 +/** MONITOR instruction. */ +# define SVM_EXIT_MONITOR 0x8a +/** MWAIT instruction. */ +# define SVM_EXIT_MWAIT 0x8b +/** MWAIT instruction, when armed. */ +# define SVM_EXIT_MWAIT_ARMED 0x8c +/** XSETBV instruction. */ +# define SVM_EXIT_XSETBV 0x8d +/** RDPRU instruction. */ +# define SVM_EXIT_RDPRU 0x8e +/** Write to EFER (after guest instruction completes). */ +# define SVM_EXIT_WRITE_EFER_TRAP 0x8f +/** Write to CR0-CR15 (after guest instruction completes). */ +# define SVM_EXIT_WRITE_CR0_TRAP 0x90 +# define SVM_EXIT_WRITE_CR1_TRAP 0x91 +# define SVM_EXIT_WRITE_CR2_TRAP 0x92 +# define SVM_EXIT_WRITE_CR3_TRAP 0x93 +# define SVM_EXIT_WRITE_CR4_TRAP 0x94 +# define SVM_EXIT_WRITE_CR5_TRAP 0x95 +# define SVM_EXIT_WRITE_CR6_TRAP 0x96 +# define SVM_EXIT_WRITE_CR7_TRAP 0x97 +# define SVM_EXIT_WRITE_CR8_TRAP 0x98 +# define SVM_EXIT_WRITE_CR9_TRAP 0x99 +# define SVM_EXIT_WRITE_CR10_TRAP 0x9a +# define SVM_EXIT_WRITE_CR11_TRAP 0x9b +# define SVM_EXIT_WRITE_CR12_TRAP 0x9c +# define SVM_EXIT_WRITE_CR13_TRAP 0x9d +# define SVM_EXIT_WRITE_CR14_TRAP 0x9e +# define SVM_EXIT_WRITE_CR15_TRAP 0x9f +/** MCOMMIT instruction. */ +# define SVM_EXIT_MCOMMIT 0xa3 + +/** Nested paging: host-level page fault occurred (EXITINFO1 contains fault errorcode; EXITINFO2 contains the guest physical address causing the fault). */ +# define SVM_EXIT_NPF 0x400 +/** AVIC: Virtual IPI delivery not completed. */ +# define SVM_EXIT_AVIC_INCOMPLETE_IPI 0x401 +/** AVIC: Attempted access by guest to a vAPIC register not handled by AVIC + * hardware. */ +# define SVM_EXIT_AVIC_NOACCEL 0x402 +/** The maximum possible exit value. */ +# define SVM_EXIT_MAX (SVM_EXIT_AVIC_NOACCEL) +/** @} */ +#endif /* !IN_REM_R3*/ + + +/** @name SVMVMCB.u64ExitInfo2 for task switches + * @{ + */ +/** Set to 1 if the task switch was caused by an IRET; else cleared to 0. */ +#define SVM_EXIT2_TASK_SWITCH_IRET RT_BIT_64(36) +/** Set to 1 if the task switch was caused by a far jump; else cleared to 0. */ +#define SVM_EXIT2_TASK_SWITCH_JUMP RT_BIT_64(38) +/** Set to 1 if the task switch has an error code; else cleared to 0. */ +#define SVM_EXIT2_TASK_SWITCH_HAS_ERROR_CODE RT_BIT_64(44) +/** The value of EFLAGS.RF that would be saved in the outgoing TSS if the task switch were not intercepted. */ +#define SVM_EXIT2_TASK_SWITCH_EFLAGS_RF RT_BIT_64(48) +/** @} */ + +/** @name SVMVMCB.u64ExitInfo1 for MSR accesses + * @{ + */ +/** The access was a read MSR. */ +#define SVM_EXIT1_MSR_READ 0x0 +/** The access was a write MSR. */ +#define SVM_EXIT1_MSR_WRITE 0x1 +/** @} */ + +/** @name SVMVMCB.u64ExitInfo1 for Mov CRx accesses. + * @{ + */ +/** The mask of whether the access was via a Mov CRx instruction. */ +#define SVM_EXIT1_MOV_CRX_MASK RT_BIT_64(63) +/** The mask for the GPR number of the Mov CRx instruction. */ +#define SVM_EXIT1_MOV_CRX_GPR_NUMBER 0xf +/** @} */ + +/** @name SVMVMCB.u64ExitInfo1 for Mov DRx accesses. + * @{ + */ +/** The mask for the GPR number of the Mov DRx instruction. */ +#define SVM_EXIT1_MOV_DRX_GPR_NUMBER 0xf +/** @} */ + +/** @name SVMVMCB.ctrl.u64InterceptCtrl + * @{ + */ +/** Intercept INTR (physical maskable interrupt). */ +#define SVM_CTRL_INTERCEPT_INTR RT_BIT_64(0) +/** Intercept NMI. */ +#define SVM_CTRL_INTERCEPT_NMI RT_BIT_64(1) +/** Intercept SMI. */ +#define SVM_CTRL_INTERCEPT_SMI RT_BIT_64(2) +/** Intercept INIT. */ +#define SVM_CTRL_INTERCEPT_INIT RT_BIT_64(3) +/** Intercept VINTR (virtual maskable interrupt). */ +#define SVM_CTRL_INTERCEPT_VINTR RT_BIT_64(4) +/** Intercept CR0 writes that change bits other than CR0.TS or CR0.MP */ +#define SVM_CTRL_INTERCEPT_CR0_SEL_WRITE RT_BIT_64(5) +/** Intercept reads of IDTR. */ +#define SVM_CTRL_INTERCEPT_IDTR_READS RT_BIT_64(6) +/** Intercept reads of GDTR. */ +#define SVM_CTRL_INTERCEPT_GDTR_READS RT_BIT_64(7) +/** Intercept reads of LDTR. */ +#define SVM_CTRL_INTERCEPT_LDTR_READS RT_BIT_64(8) +/** Intercept reads of TR. */ +#define SVM_CTRL_INTERCEPT_TR_READS RT_BIT_64(9) +/** Intercept writes of IDTR. */ +#define SVM_CTRL_INTERCEPT_IDTR_WRITES RT_BIT_64(10) +/** Intercept writes of GDTR. */ +#define SVM_CTRL_INTERCEPT_GDTR_WRITES RT_BIT_64(11) +/** Intercept writes of LDTR. */ +#define SVM_CTRL_INTERCEPT_LDTR_WRITES RT_BIT_64(12) +/** Intercept writes of TR. */ +#define SVM_CTRL_INTERCEPT_TR_WRITES RT_BIT_64(13) +/** Intercept RDTSC instruction. */ +#define SVM_CTRL_INTERCEPT_RDTSC RT_BIT_64(14) +/** Intercept RDPMC instruction. */ +#define SVM_CTRL_INTERCEPT_RDPMC RT_BIT_64(15) +/** Intercept PUSHF instruction. */ +#define SVM_CTRL_INTERCEPT_PUSHF RT_BIT_64(16) +/** Intercept POPF instruction. */ +#define SVM_CTRL_INTERCEPT_POPF RT_BIT_64(17) +/** Intercept CPUID instruction. */ +#define SVM_CTRL_INTERCEPT_CPUID RT_BIT_64(18) +/** Intercept RSM instruction. */ +#define SVM_CTRL_INTERCEPT_RSM RT_BIT_64(19) +/** Intercept IRET instruction. */ +#define SVM_CTRL_INTERCEPT_IRET RT_BIT_64(20) +/** Intercept INTn instruction. */ +#define SVM_CTRL_INTERCEPT_INTN RT_BIT_64(21) +/** Intercept INVD instruction. */ +#define SVM_CTRL_INTERCEPT_INVD RT_BIT_64(22) +/** Intercept PAUSE instruction. */ +#define SVM_CTRL_INTERCEPT_PAUSE RT_BIT_64(23) +/** Intercept HLT instruction. */ +#define SVM_CTRL_INTERCEPT_HLT RT_BIT_64(24) +/** Intercept INVLPG instruction. */ +#define SVM_CTRL_INTERCEPT_INVLPG RT_BIT_64(25) +/** Intercept INVLPGA instruction. */ +#define SVM_CTRL_INTERCEPT_INVLPGA RT_BIT_64(26) +/** IOIO_PROT Intercept IN/OUT accesses to selected ports. */ +#define SVM_CTRL_INTERCEPT_IOIO_PROT RT_BIT_64(27) +/** MSR_PROT Intercept RDMSR or WRMSR accesses to selected MSRs. */ +#define SVM_CTRL_INTERCEPT_MSR_PROT RT_BIT_64(28) +/** Intercept task switches. */ +#define SVM_CTRL_INTERCEPT_TASK_SWITCH RT_BIT_64(29) +/** FERR_FREEZE: intercept processor "freezing" during legacy FERR handling. */ +#define SVM_CTRL_INTERCEPT_FERR_FREEZE RT_BIT_64(30) +/** Intercept shutdown events. */ +#define SVM_CTRL_INTERCEPT_SHUTDOWN RT_BIT_64(31) +/** Intercept VMRUN instruction. */ +#define SVM_CTRL_INTERCEPT_VMRUN RT_BIT_64(32 + 0) +/** Intercept VMMCALL instruction. */ +#define SVM_CTRL_INTERCEPT_VMMCALL RT_BIT_64(32 + 1) +/** Intercept VMLOAD instruction. */ +#define SVM_CTRL_INTERCEPT_VMLOAD RT_BIT_64(32 + 2) +/** Intercept VMSAVE instruction. */ +#define SVM_CTRL_INTERCEPT_VMSAVE RT_BIT_64(32 + 3) +/** Intercept STGI instruction. */ +#define SVM_CTRL_INTERCEPT_STGI RT_BIT_64(32 + 4) +/** Intercept CLGI instruction. */ +#define SVM_CTRL_INTERCEPT_CLGI RT_BIT_64(32 + 5) +/** Intercept SKINIT instruction. */ +#define SVM_CTRL_INTERCEPT_SKINIT RT_BIT_64(32 + 6) +/** Intercept RDTSCP instruction. */ +#define SVM_CTRL_INTERCEPT_RDTSCP RT_BIT_64(32 + 7) +/** Intercept ICEBP instruction. */ +#define SVM_CTRL_INTERCEPT_ICEBP RT_BIT_64(32 + 8) +/** Intercept WBINVD instruction. */ +#define SVM_CTRL_INTERCEPT_WBINVD RT_BIT_64(32 + 9) +/** Intercept MONITOR instruction. */ +#define SVM_CTRL_INTERCEPT_MONITOR RT_BIT_64(32 + 10) +/** Intercept MWAIT instruction unconditionally. */ +#define SVM_CTRL_INTERCEPT_MWAIT RT_BIT_64(32 + 11) +/** Intercept MWAIT instruction when armed. */ +#define SVM_CTRL_INTERCEPT_MWAIT_ARMED RT_BIT_64(32 + 12) +/** Intercept XSETBV instruction. */ +#define SVM_CTRL_INTERCEPT_XSETBV RT_BIT_64(32 + 13) +/** Intercept RDPRU instruction. */ +#define SVM_CTRL_INTERCEPT_RDPRU RT_BIT_64(32 + 14) +/** Intercept EFER writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_EFER_WRITES_TRAP RT_BIT_64(32 + 15) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR0_WRITES_TRAP RT_BIT_64(32 + 16) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR1_WRITES_TRAP RT_BIT_64(32 + 17) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR2_WRITES_TRAP RT_BIT_64(32 + 18) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR3_WRITES_TRAP RT_BIT_64(32 + 19) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR4_WRITES_TRAP RT_BIT_64(32 + 20) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR5_WRITES_TRAP RT_BIT_64(32 + 21) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR6_WRITES_TRAP RT_BIT_64(32 + 22) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR7_WRITES_TRAP RT_BIT_64(32 + 23) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR8_WRITES_TRAP RT_BIT_64(32 + 24) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR9_WRITES_TRAP RT_BIT_64(32 + 25) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR10_WRITES_TRAP RT_BIT_64(32 + 26) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR11_WRITES_TRAP RT_BIT_64(32 + 27) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR12_WRITES_TRAP RT_BIT_64(32 + 28) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR13_WRITES_TRAP RT_BIT_64(32 + 29) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR14_WRITES_TRAP RT_BIT_64(32 + 30) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR15_WRITES_TRAP RT_BIT_64(32 + 31) +/** @} */ + +/** @name SVMINTCTRL.u3Type + * @{ + */ +/** External or virtual interrupt. */ +#define SVM_EVENT_EXTERNAL_IRQ 0 +/** Non-maskable interrupt. */ +#define SVM_EVENT_NMI 2 +/** Exception; fault or trap. */ +#define SVM_EVENT_EXCEPTION 3 +/** Software interrupt. */ +#define SVM_EVENT_SOFTWARE_INT 4 +/** @} */ + +/** @name SVMVMCB.ctrl.TLBCtrl.n.u8TLBFlush + * @{ + */ +/** Flush nothing. */ +#define SVM_TLB_FLUSH_NOTHING 0 +/** Flush entire TLB (host+guest entries) */ +#define SVM_TLB_FLUSH_ENTIRE 1 +/** Flush this guest's TLB entries (by ASID) */ +#define SVM_TLB_FLUSH_SINGLE_CONTEXT 3 +/** Flush this guest's non-global TLB entries (by ASID) */ +#define SVM_TLB_FLUSH_SINGLE_CONTEXT_RETAIN_GLOBALS 7 +/** @} */ + +/** + * SVM selector/segment register type. + */ +typedef struct +{ + uint16_t u16Sel; + uint16_t u16Attr; + uint32_t u32Limit; + uint64_t u64Base; /**< Only lower 32 bits are implemented for CS, DS, ES & SS. */ +} SVMSELREG; +AssertCompileSize(SVMSELREG, 16); +/** Pointer to the SVMSELREG struct. */ +typedef SVMSELREG *PSVMSELREG; +/** Pointer to a const SVMSELREG struct. */ +typedef const SVMSELREG *PCSVMSELREG; + +/** + * SVM GDTR/IDTR type. + */ +typedef struct +{ + uint16_t u16Reserved0; + uint16_t u16Reserved1; + uint32_t u32Limit; /**< Only lower 16 bits are implemented. */ + uint64_t u64Base; +} SVMXDTR; +AssertCompileSize(SVMXDTR, 16); +typedef SVMXDTR SVMIDTR; +typedef SVMXDTR SVMGDTR; +/** Pointer to the SVMXDTR struct. */ +typedef SVMXDTR *PSVMXDTR; +/** Pointer to a const SVMXDTR struct. */ +typedef const SVMXDTR *PCSVMXDTR; + +/** + * SVM Event injection structure (EVENTINJ and EXITINTINFO). + */ +typedef union +{ + struct + { + uint32_t u8Vector : 8; + uint32_t u3Type : 3; + uint32_t u1ErrorCodeValid : 1; + uint32_t u19Reserved : 19; + uint32_t u1Valid : 1; + uint32_t u32ErrorCode : 32; + } n; + uint64_t u; +} SVMEVENT; +/** Pointer to the SVMEVENT union. */ +typedef SVMEVENT *PSVMEVENT; +/** Pointer to a const SVMEVENT union. */ +typedef const SVMEVENT *PCSVMEVENT; + +/** Gets the event type given an SVMEVENT parameter. */ +#define SVM_EVENT_GET_TYPE(a_SvmEvent) (((a_SvmEvent) >> 8) & 7) + +/** + * SVM Interrupt control structure (Virtual Interrupt Control). + */ +typedef union +{ + struct + { + uint32_t u8VTPR : 8; /* V_TPR */ + uint32_t u1VIrqPending : 1; /* V_IRQ */ + uint32_t u1VGif : 1; /* VGIF */ + uint32_t u6Reserved : 6; + uint32_t u4VIntrPrio : 4; /* V_INTR_PRIO */ + uint32_t u1IgnoreTPR : 1; /* V_IGN_TPR */ + uint32_t u3Reserved : 3; + uint32_t u1VIntrMasking : 1; /* V_INTR_MASKING */ + uint32_t u1VGifEnable : 1; /* VGIF enable */ + uint32_t u5Reserved : 5; + uint32_t u1AvicEnable : 1; /* AVIC enable */ + uint32_t u8VIntrVector : 8; /* V_INTR_VECTOR */ + uint32_t u24Reserved : 24; + } n; + uint64_t u; +} SVMINTCTRL; +/** Pointer to an SVMINTCTRL structure. */ +typedef SVMINTCTRL *PSVMINTCTRL; +/** Pointer to a const SVMINTCTRL structure. */ +typedef const SVMINTCTRL *PCSVMINTCTRL; + +/** + * SVM TLB control structure. + */ +typedef union +{ + struct + { + uint32_t u32ASID : 32; + uint32_t u8TLBFlush : 8; + uint32_t u24Reserved : 24; + } n; + uint64_t u; +} SVMTLBCTRL; + +/** + * SVM IOIO exit info. structure (EXITINFO1 for IOIO intercepts). + */ +typedef union +{ + struct + { + uint32_t u1Type : 1; /**< Bit 0: 0 = out, 1 = in */ + uint32_t u1Reserved : 1; /**< Bit 1: Reserved */ + uint32_t u1Str : 1; /**< Bit 2: String I/O (1) or not (0). */ + uint32_t u1Rep : 1; /**< Bit 3: Repeat prefixed string I/O. */ + uint32_t u1Op8 : 1; /**< Bit 4: 8-bit operand. */ + uint32_t u1Op16 : 1; /**< Bit 5: 16-bit operand. */ + uint32_t u1Op32 : 1; /**< Bit 6: 32-bit operand. */ + uint32_t u1Addr16 : 1; /**< Bit 7: 16-bit address size. */ + uint32_t u1Addr32 : 1; /**< Bit 8: 32-bit address size. */ + uint32_t u1Addr64 : 1; /**< Bit 9: 64-bit address size. */ + uint32_t u3Seg : 3; /**< Bits 12:10: Effective segment number. Added w/ decode assist in APM v3.17. */ + uint32_t u3Reserved : 3; + uint32_t u16Port : 16; /**< Bits 31:16: Port number. */ + } n; + uint32_t u; +} SVMIOIOEXITINFO; +/** Pointer to an SVM IOIO exit info. structure. */ +typedef SVMIOIOEXITINFO *PSVMIOIOEXITINFO; +/** Pointer to a const SVM IOIO exit info. structure. */ +typedef const SVMIOIOEXITINFO *PCSVMIOIOEXITINFO; + +/** 8-bit IO transfer. */ +#define SVM_IOIO_8_BIT_OP RT_BIT_32(4) +/** 16-bit IO transfer. */ +#define SVM_IOIO_16_BIT_OP RT_BIT_32(5) +/** 32-bit IO transfer. */ +#define SVM_IOIO_32_BIT_OP RT_BIT_32(6) +/** Number of bits to shift right to get the operand sizes. */ +#define SVM_IOIO_OP_SIZE_SHIFT 4 +/** Mask of all possible IO transfer sizes. */ +#define SVM_IOIO_OP_SIZE_MASK (SVM_IOIO_8_BIT_OP | SVM_IOIO_16_BIT_OP | SVM_IOIO_32_BIT_OP) +/** 16-bit address for the IO buffer. */ +#define SVM_IOIO_16_BIT_ADDR RT_BIT_32(7) +/** 32-bit address for the IO buffer. */ +#define SVM_IOIO_32_BIT_ADDR RT_BIT_32(8) +/** 64-bit address for the IO buffer. */ +#define SVM_IOIO_64_BIT_ADDR RT_BIT_32(9) +/** Number of bits to shift right to get the address sizes. */ +#define SVM_IOIO_ADDR_SIZE_SHIFT 7 +/** Mask of all the IO address sizes. */ +#define SVM_IOIO_ADDR_SIZE_MASK (SVM_IOIO_16_BIT_ADDR | SVM_IOIO_32_BIT_ADDR | SVM_IOIO_64_BIT_ADDR) +/** Number of bits to shift right to get the IO port number. */ +#define SVM_IOIO_PORT_SHIFT 16 +/** IO write. */ +#define SVM_IOIO_WRITE 0 +/** IO read. */ +#define SVM_IOIO_READ 1 +/** + * SVM IOIO transfer type. + */ +typedef enum +{ + SVMIOIOTYPE_OUT = SVM_IOIO_WRITE, + SVMIOIOTYPE_IN = SVM_IOIO_READ +} SVMIOIOTYPE; + +/** + * SVM AVIC. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Reserved0 : 12; + RT_GCC_EXTENSION uint64_t u40Addr : 40; + RT_GCC_EXTENSION uint64_t u12Reserved1 : 12; + } n; + uint64_t u; +} SVMAVIC; +AssertCompileSize(SVMAVIC, 8); + +/** + * SVM AVIC PHYSICAL_TABLE pointer. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u8LastGuestCoreId : 8; + RT_GCC_EXTENSION uint64_t u4Reserved : 4; + RT_GCC_EXTENSION uint64_t u40Addr : 40; + RT_GCC_EXTENSION uint64_t u12Reserved : 12; + } n; + uint64_t u; +} SVMAVICPHYS; +AssertCompileSize(SVMAVICPHYS, 8); + +/** + * SVM Nested Paging struct. + */ +typedef union +{ + struct + { + uint32_t u1NestedPaging : 1; + uint32_t u1Sev : 1; + uint32_t u1SevEs : 1; + uint32_t u29Reserved : 29; + } n; + uint64_t u; +} SVMNP; +AssertCompileSize(SVMNP, 8); + +/** + * SVM Interrupt shadow struct. + */ +typedef union +{ + struct + { + uint32_t u1IntShadow : 1; + uint32_t u1GuestIntMask : 1; + uint32_t u30Reserved : 30; + } n; + uint64_t u; +} SVMINTSHADOW; +AssertCompileSize(SVMINTSHADOW, 8); + +/** + * SVM LBR virtualization struct. + */ +typedef union +{ + struct + { + uint32_t u1LbrVirt : 1; + uint32_t u1VirtVmsaveVmload : 1; + uint32_t u30Reserved : 30; + } n; + uint64_t u; +} SVMLBRVIRT; +AssertCompileSize(SVMLBRVIRT, 8); + +/** Maximum number of bytes in the Guest-instruction bytes field. */ +#define SVM_CTRL_GUEST_INSTR_BYTES_MAX 15 + +/** + * SVM VMCB control area. + */ +#pragma pack(1) +typedef struct +{ + /** Offset 0x00 - Intercept reads of CR0-CR15. */ + uint16_t u16InterceptRdCRx; + /** Offset 0x02 - Intercept writes to CR0-CR15. */ + uint16_t u16InterceptWrCRx; + /** Offset 0x04 - Intercept reads of DR0-DR15. */ + uint16_t u16InterceptRdDRx; + /** Offset 0x06 - Intercept writes to DR0-DR15. */ + uint16_t u16InterceptWrDRx; + /** Offset 0x08 - Intercept exception vectors 0-31. */ + uint32_t u32InterceptXcpt; + /** Offset 0x0c - Intercept control. */ + uint64_t u64InterceptCtrl; + /** Offset 0x14-0x3f - Reserved. */ + uint8_t u8Reserved0[0x3c - 0x14]; + /** Offset 0x3c - PAUSE filter threshold. */ + uint16_t u16PauseFilterThreshold; + /** Offset 0x3e - PAUSE intercept filter count. */ + uint16_t u16PauseFilterCount; + /** Offset 0x40 - Physical address of IOPM. */ + uint64_t u64IOPMPhysAddr; + /** Offset 0x48 - Physical address of MSRPM. */ + uint64_t u64MSRPMPhysAddr; + /** Offset 0x50 - TSC Offset. */ + uint64_t u64TSCOffset; + /** Offset 0x58 - TLB control field. */ + SVMTLBCTRL TLBCtrl; + /** Offset 0x60 - Interrupt control field. */ + SVMINTCTRL IntCtrl; + /** Offset 0x68 - Interrupt shadow. */ + SVMINTSHADOW IntShadow; + /** Offset 0x70 - Exit code. */ + uint64_t u64ExitCode; + /** Offset 0x78 - Exit info 1. */ + uint64_t u64ExitInfo1; + /** Offset 0x80 - Exit info 2. */ + uint64_t u64ExitInfo2; + /** Offset 0x88 - Exit Interrupt info. */ + SVMEVENT ExitIntInfo; + /** Offset 0x90 - Nested Paging control. */ + SVMNP NestedPagingCtrl; + /** Offset 0x98 - AVIC APIC BAR. */ + SVMAVIC AvicBar; + /** Offset 0xa0-0xa7 - Reserved. */ + uint8_t u8Reserved1[0xa8 - 0xa0]; + /** Offset 0xa8 - Event injection. */ + SVMEVENT EventInject; + /** Offset 0xb0 - Host CR3 for nested paging. */ + uint64_t u64NestedPagingCR3; + /** Offset 0xb8 - LBR Virtualization. */ + SVMLBRVIRT LbrVirt; + /** Offset 0xc0 - VMCB Clean Bits. */ + uint32_t u32VmcbCleanBits; + uint32_t u32Reserved0; + /** Offset 0xc8 - Next sequential instruction pointer. */ + uint64_t u64NextRIP; + /** Offset 0xd0 - Number of bytes fetched. */ + uint8_t cbInstrFetched; + /** Offset 0xd1 - Guest instruction bytes. */ + uint8_t abInstr[SVM_CTRL_GUEST_INSTR_BYTES_MAX]; + /** Offset 0xe0 - AVIC APIC_BACKING_PAGE pointer. */ + SVMAVIC AvicBackingPagePtr; + /** Offset 0xe8-0xef - Reserved. */ + uint8_t u8Reserved2[0xf0 - 0xe8]; + /** Offset 0xf0 - AVIC LOGICAL_TABLE pointer. */ + SVMAVIC AvicLogicalTablePtr; + /** Offset 0xf8 - AVIC PHYSICAL_TABLE pointer. */ + SVMAVICPHYS AvicPhysicalTablePtr; +} SVMVMCBCTRL; +#pragma pack() +/** Pointer to the SVMVMCBSTATESAVE structure. */ +typedef SVMVMCBCTRL *PSVMVMCBCTRL; +/** Pointer to a const SVMVMCBSTATESAVE structure. */ +typedef const SVMVMCBCTRL *PCSVMVMCBCTRL; +AssertCompileSize(SVMVMCBCTRL, 0x100); +AssertCompileMemberOffset(SVMVMCBCTRL, u16InterceptRdCRx, 0x00); +AssertCompileMemberOffset(SVMVMCBCTRL, u16InterceptWrCRx, 0x02); +AssertCompileMemberOffset(SVMVMCBCTRL, u16InterceptRdDRx, 0x04); +AssertCompileMemberOffset(SVMVMCBCTRL, u16InterceptWrDRx, 0x06); +AssertCompileMemberOffset(SVMVMCBCTRL, u32InterceptXcpt, 0x08); +AssertCompileMemberOffset(SVMVMCBCTRL, u64InterceptCtrl, 0x0c); +AssertCompileMemberOffset(SVMVMCBCTRL, u8Reserved0, 0x14); +AssertCompileMemberOffset(SVMVMCBCTRL, u16PauseFilterThreshold, 0x3c); +AssertCompileMemberOffset(SVMVMCBCTRL, u16PauseFilterCount, 0x3e); +AssertCompileMemberOffset(SVMVMCBCTRL, u64IOPMPhysAddr, 0x40); +AssertCompileMemberOffset(SVMVMCBCTRL, u64MSRPMPhysAddr, 0x48); +AssertCompileMemberOffset(SVMVMCBCTRL, u64TSCOffset, 0x50); +AssertCompileMemberOffset(SVMVMCBCTRL, TLBCtrl, 0x58); +AssertCompileMemberOffset(SVMVMCBCTRL, IntCtrl, 0x60); +AssertCompileMemberOffset(SVMVMCBCTRL, IntShadow, 0x68); +AssertCompileMemberOffset(SVMVMCBCTRL, u64ExitCode, 0x70); +AssertCompileMemberOffset(SVMVMCBCTRL, u64ExitInfo1, 0x78); +AssertCompileMemberOffset(SVMVMCBCTRL, u64ExitInfo2, 0x80); +AssertCompileMemberOffset(SVMVMCBCTRL, ExitIntInfo, 0x88); +AssertCompileMemberOffset(SVMVMCBCTRL, NestedPagingCtrl, 0x90); +AssertCompileMemberOffset(SVMVMCBCTRL, AvicBar, 0x98); +AssertCompileMemberOffset(SVMVMCBCTRL, u8Reserved1, 0xa0); +AssertCompileMemberOffset(SVMVMCBCTRL, EventInject, 0xa8); +AssertCompileMemberOffset(SVMVMCBCTRL, u64NestedPagingCR3, 0xb0); +AssertCompileMemberOffset(SVMVMCBCTRL, LbrVirt, 0xb8); +AssertCompileMemberOffset(SVMVMCBCTRL, u32VmcbCleanBits, 0xc0); +AssertCompileMemberOffset(SVMVMCBCTRL, u64NextRIP, 0xc8); +AssertCompileMemberOffset(SVMVMCBCTRL, cbInstrFetched, 0xd0); +AssertCompileMemberOffset(SVMVMCBCTRL, abInstr, 0xd1); +AssertCompileMemberOffset(SVMVMCBCTRL, AvicBackingPagePtr, 0xe0); +AssertCompileMemberOffset(SVMVMCBCTRL, u8Reserved2, 0xe8); +AssertCompileMemberOffset(SVMVMCBCTRL, AvicLogicalTablePtr, 0xf0); +AssertCompileMemberOffset(SVMVMCBCTRL, AvicPhysicalTablePtr, 0xf8); +AssertCompileMemberSize(SVMVMCBCTRL, abInstr, 0x0f); + +/** + * SVM VMCB state save area. + */ +#pragma pack(1) +typedef struct +{ + /** Offset 0x400 - Guest ES register + hidden parts. */ + SVMSELREG ES; + /** Offset 0x410 - Guest CS register + hidden parts. */ + SVMSELREG CS; + /** Offset 0x420 - Guest SS register + hidden parts. */ + SVMSELREG SS; + /** Offset 0x430 - Guest DS register + hidden parts. */ + SVMSELREG DS; + /** Offset 0x440 - Guest FS register + hidden parts. */ + SVMSELREG FS; + /** Offset 0x450 - Guest GS register + hidden parts. */ + SVMSELREG GS; + /** Offset 0x460 - Guest GDTR register. */ + SVMGDTR GDTR; + /** Offset 0x470 - Guest LDTR register + hidden parts. */ + SVMSELREG LDTR; + /** Offset 0x480 - Guest IDTR register. */ + SVMIDTR IDTR; + /** Offset 0x490 - Guest TR register + hidden parts. */ + SVMSELREG TR; + /** Offset 0x4A0-0x4CA - Reserved. */ + uint8_t u8Reserved0[0x4cb - 0x4a0]; + /** Offset 0x4CB - CPL. */ + uint8_t u8CPL; + /** Offset 0x4CC-0x4CF - Reserved. */ + uint8_t u8Reserved1[0x4d0 - 0x4cc]; + /** Offset 0x4D0 - EFER. */ + uint64_t u64EFER; + /** Offset 0x4D8-0x547 - Reserved. */ + uint8_t u8Reserved2[0x548 - 0x4d8]; + /** Offset 0x548 - CR4. */ + uint64_t u64CR4; + /** Offset 0x550 - CR3. */ + uint64_t u64CR3; + /** Offset 0x558 - CR0. */ + uint64_t u64CR0; + /** Offset 0x560 - DR7. */ + uint64_t u64DR7; + /** Offset 0x568 - DR6. */ + uint64_t u64DR6; + /** Offset 0x570 - RFLAGS. */ + uint64_t u64RFlags; + /** Offset 0x578 - RIP. */ + uint64_t u64RIP; + /** Offset 0x580-0x5D7 - Reserved. */ + uint8_t u8Reserved3[0x5d8 - 0x580]; + /** Offset 0x5D8 - RSP. */ + uint64_t u64RSP; + /** Offset 0x5E0-0x5F7 - Reserved. */ + uint8_t u8Reserved4[0x5f8 - 0x5e0]; + /** Offset 0x5F8 - RAX. */ + uint64_t u64RAX; + /** Offset 0x600 - STAR. */ + uint64_t u64STAR; + /** Offset 0x608 - LSTAR. */ + uint64_t u64LSTAR; + /** Offset 0x610 - CSTAR. */ + uint64_t u64CSTAR; + /** Offset 0x618 - SFMASK. */ + uint64_t u64SFMASK; + /** Offset 0x620 - KernelGSBase. */ + uint64_t u64KernelGSBase; + /** Offset 0x628 - SYSENTER_CS. */ + uint64_t u64SysEnterCS; + /** Offset 0x630 - SYSENTER_ESP. */ + uint64_t u64SysEnterESP; + /** Offset 0x638 - SYSENTER_EIP. */ + uint64_t u64SysEnterEIP; + /** Offset 0x640 - CR2. */ + uint64_t u64CR2; + /** Offset 0x648-0x667 - Reserved. */ + uint8_t u8Reserved5[0x668 - 0x648]; + /** Offset 0x668 - PAT (Page Attribute Table) MSR. */ + uint64_t u64PAT; + /** Offset 0x670 - DBGCTL. */ + uint64_t u64DBGCTL; + /** Offset 0x678 - BR_FROM. */ + uint64_t u64BR_FROM; + /** Offset 0x680 - BR_TO. */ + uint64_t u64BR_TO; + /** Offset 0x688 - LASTEXCPFROM. */ + uint64_t u64LASTEXCPFROM; + /** Offset 0x690 - LASTEXCPTO. */ + uint64_t u64LASTEXCPTO; +} SVMVMCBSTATESAVE; +#pragma pack() +/** Pointer to the SVMVMCBSTATESAVE structure. */ +typedef SVMVMCBSTATESAVE *PSVMVMCBSTATESAVE; +/** Pointer to a const SVMVMCBSTATESAVE structure. */ +typedef const SVMVMCBSTATESAVE *PCSVMVMCBSTATESAVE; +AssertCompileSize(SVMVMCBSTATESAVE, 0x298); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, ES, 0x400 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, CS, 0x410 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, SS, 0x420 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, DS, 0x430 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, FS, 0x440 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, GS, 0x450 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, GDTR, 0x460 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, LDTR, 0x470 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, IDTR, 0x480 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, TR, 0x490 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved0, 0x4a0 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8CPL, 0x4cb - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved1, 0x4cc - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64EFER, 0x4d0 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved2, 0x4d8 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64CR4, 0x548 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64CR3, 0x550 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64CR0, 0x558 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64DR7, 0x560 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64DR6, 0x568 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64RFlags, 0x570 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64RIP, 0x578 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved3, 0x580 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64RSP, 0x5d8 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved4, 0x5e0 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64RAX, 0x5f8 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64STAR, 0x600 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64LSTAR, 0x608 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64CSTAR, 0x610 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64SFMASK, 0x618 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64KernelGSBase, 0x620 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64SysEnterCS, 0x628 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64SysEnterESP, 0x630 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64SysEnterEIP, 0x638 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64CR2, 0x640 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved5, 0x648 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64PAT, 0x668 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64DBGCTL, 0x670 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64BR_FROM, 0x678 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64BR_TO, 0x680 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64LASTEXCPFROM, 0x688 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64LASTEXCPTO, 0x690 - 0x400); + +/** + * SVM VM Control Block. (VMCB) + */ +#pragma pack(1) +typedef struct SVMVMCB +{ + /** Offset 0x00 - Control area. */ + SVMVMCBCTRL ctrl; + /** Offset 0x100-0x3FF - Reserved. */ + uint8_t u8Reserved0[0x400 - 0x100]; + /** Offset 0x400 - State save area. */ + SVMVMCBSTATESAVE guest; + /** Offset 0x698-0xFFF- Reserved. */ + uint8_t u8Reserved1[0x1000 - 0x698]; +} SVMVMCB; +#pragma pack() +/** Pointer to the SVMVMCB structure. */ +typedef SVMVMCB *PSVMVMCB; +/** Pointer to a const SVMVMCB structure. */ +typedef const SVMVMCB *PCSVMVMCB; +AssertCompileMemberOffset(SVMVMCB, ctrl, 0x00); +AssertCompileMemberOffset(SVMVMCB, u8Reserved0, 0x100); +AssertCompileMemberOffset(SVMVMCB, guest, 0x400); +AssertCompileMemberOffset(SVMVMCB, u8Reserved1, 0x698); +AssertCompileSize(SVMVMCB, 0x1000); + +/** + * SVM MSRs. + */ +typedef struct SVMMSRS +{ + /** HWCR MSR. */ + uint64_t u64MsrHwcr; + /** Reserved for future. */ + uint64_t u64Padding[27]; +} SVMMSRS; +AssertCompileSizeAlignment(SVMMSRS, 8); +AssertCompileSize(SVMMSRS, 224); +/** Pointer to a SVMMSRS struct. */ +typedef SVMMSRS *PSVMMSRS; +/** Pointer to a const SVMMSRS struct. */ +typedef const SVMMSRS *PCSVMMSRS; + +/** + * SVM VM-exit auxiliary information. + * + * This includes information that isn't necessarily stored in the guest-CPU + * context but provided as part of \#VMEXITs. + */ +typedef struct +{ + uint64_t u64ExitCode; + uint64_t u64ExitInfo1; + uint64_t u64ExitInfo2; + SVMEVENT ExitIntInfo; +} SVMEXITAUX; +/** Pointer to a SVMEXITAUX struct. */ +typedef SVMEXITAUX *PSVMEXITAUX; +/** Pointer to a const SVMEXITAUX struct. */ +typedef const SVMEXITAUX *PCSVMEXITAUX; + +/** + * Segment attribute conversion between CPU and AMD-V VMCB format. + * + * The CPU format of the segment attribute is described in X86DESCATTRBITS + * which is 16-bits (i.e. includes 4 bits of the segment limit). + * + * The AMD-V VMCB format the segment attribute is compact 12-bits (strictly + * only the attribute bits and nothing else). Upper 4-bits are unused. + */ +#define HMSVM_CPU_2_VMCB_SEG_ATTR(a) ( ((a) & 0xff) | (((a) & 0xf000) >> 4) ) +#define HMSVM_VMCB_2_CPU_SEG_ATTR(a) ( ((a) & 0xff) | (((a) & 0x0f00) << 4) ) + +/** @def HMSVM_SEG_REG_COPY_TO_VMCB + * Copies the specified segment register to a VMCB from a virtual CPU context. + * + * @param a_pCtx The virtual-CPU context. + * @param a_pVmcbStateSave Pointer to the VMCB state-save area. + * @param a_REG The segment register in the VMCB state-save + * struct (ES/CS/SS/DS). + * @param a_reg The segment register in the virtual CPU struct + * (es/cs/ss/ds). + */ +#define HMSVM_SEG_REG_COPY_TO_VMCB(a_pCtx, a_pVmcbStateSave, a_REG, a_reg) \ + do \ + { \ + Assert((a_pCtx)->a_reg.fFlags & CPUMSELREG_FLAGS_VALID); \ + Assert((a_pCtx)->a_reg.ValidSel == (a_pCtx)->a_reg.Sel); \ + (a_pVmcbStateSave)->a_REG.u16Sel = (a_pCtx)->a_reg.Sel; \ + (a_pVmcbStateSave)->a_REG.u32Limit = (a_pCtx)->a_reg.u32Limit; \ + (a_pVmcbStateSave)->a_REG.u64Base = (a_pCtx)->a_reg.u64Base; \ + (a_pVmcbStateSave)->a_REG.u16Attr = HMSVM_CPU_2_VMCB_SEG_ATTR((a_pCtx)->a_reg.Attr.u); \ + } while (0) + +/** @def HMSVM_SEG_REG_COPY_FROM_VMCB + * Copies the specified segment register from the VMCB to a virtual CPU + * context. + * + * @param a_pCtx The virtual-CPU context. + * @param a_pVmcbStateSave Pointer to the VMCB state-save area. + * @param a_REG The segment register in the VMCB state-save + * struct (ES/CS/SS/DS). + * @param a_reg The segment register in the virtual CPU struct + * (es/ds/ss/ds). + */ +#define HMSVM_SEG_REG_COPY_FROM_VMCB(a_pCtx, a_pVmcbStateSave, a_REG, a_reg) \ + do \ + { \ + (a_pCtx)->a_reg.Sel = (a_pVmcbStateSave)->a_REG.u16Sel; \ + (a_pCtx)->a_reg.ValidSel = (a_pVmcbStateSave)->a_REG.u16Sel; \ + (a_pCtx)->a_reg.fFlags = CPUMSELREG_FLAGS_VALID; \ + (a_pCtx)->a_reg.u32Limit = (a_pVmcbStateSave)->a_REG.u32Limit; \ + (a_pCtx)->a_reg.u64Base = (a_pVmcbStateSave)->a_REG.u64Base; \ + (a_pCtx)->a_reg.Attr.u = HMSVM_VMCB_2_CPU_SEG_ATTR((a_pVmcbStateSave)->a_REG.u16Attr); \ + } while (0) + + +/** @defgroup grp_hm_svm_hwexec SVM Hardware-assisted execution Helpers + * + * These functions are only here because the inline functions in cpum.h calls them. + * Don't add any more functions here unless there is no other option. + * @{ + */ +VMM_INT_DECL(bool) HMGetGuestSvmCtrlIntercepts(PCVMCPU pVCpu, uint64_t *pu64Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmReadCRxIntercepts(PCVMCPU pVCpu, uint16_t *pu16Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmWriteCRxIntercepts(PCVMCPU pVCpu, uint16_t *pu16Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmReadDRxIntercepts(PCVMCPU pVCpu, uint16_t *pu16Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmWriteDRxIntercepts(PCVMCPU pVCpu, uint16_t *pu16Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmXcptIntercepts(PCVMCPU pVCpu, uint32_t *pu32Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmVirtIntrMasking(PCVMCPU pVCpu, bool *pfVIntrMasking); +VMM_INT_DECL(bool) HMGetGuestSvmNestedPaging(PCVMCPU pVCpu, bool *pfNestedPagingCtrl); +VMM_INT_DECL(bool) HMGetGuestSvmPauseFilterCount(PCVMCPU pVCpu, uint16_t *pu16PauseFilterCount); +VMM_INT_DECL(bool) HMGetGuestSvmTscOffset(PCVMCPU pVCpu, uint64_t *pu64TscOffset); +/** @} */ + + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_hm_svm_h */ + diff --git a/include/VBox/vmm/hm_vmx.h b/include/VBox/vmm/hm_vmx.h new file mode 100644 index 00000000..95794dca --- /dev/null +++ b/include/VBox/vmm/hm_vmx.h @@ -0,0 +1,4644 @@ +/** @file + * HM - VMX Structures and Definitions. (VMM) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_hm_vmx_h +#define VBOX_INCLUDED_vmm_hm_vmx_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/x86.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_hm_vmx VMX Types and Definitions + * @ingroup grp_hm + * @{ + */ + +/** @name Host-state MSR lazy-restoration flags. + * @{ + */ +/** The host MSRs have been saved. */ +#define VMX_LAZY_MSRS_SAVED_HOST RT_BIT(0) +/** The guest MSRs are loaded and in effect. */ +#define VMX_LAZY_MSRS_LOADED_GUEST RT_BIT(1) +/** @} */ + +/** @name VMX HM-error codes for VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO. + * UFC = Unsupported Feature Combination. + * @{ + */ +/** Unsupported pin-based VM-execution controls combo. */ +#define VMX_UFC_CTRL_PIN_EXEC 1 +/** Unsupported processor-based VM-execution controls combo. */ +#define VMX_UFC_CTRL_PROC_EXEC 2 +/** Unsupported move debug register VM-exit combo. */ +#define VMX_UFC_CTRL_PROC_MOV_DRX_EXIT 3 +/** Unsupported VM-entry controls combo. */ +#define VMX_UFC_CTRL_ENTRY 4 +/** Unsupported VM-exit controls combo. */ +#define VMX_UFC_CTRL_EXIT 5 +/** MSR storage capacity of the VMCS autoload/store area is not sufficient + * for storing host MSRs. */ +#define VMX_UFC_INSUFFICIENT_HOST_MSR_STORAGE 6 +/** MSR storage capacity of the VMCS autoload/store area is not sufficient + * for storing guest MSRs. */ +#define VMX_UFC_INSUFFICIENT_GUEST_MSR_STORAGE 7 +/** Invalid VMCS size. */ +#define VMX_UFC_INVALID_VMCS_SIZE 8 +/** Unsupported secondary processor-based VM-execution controls combo. */ +#define VMX_UFC_CTRL_PROC_EXEC2 9 +/** Invalid unrestricted-guest execution controls combo. */ +#define VMX_UFC_INVALID_UX_COMBO 10 +/** EPT flush type not supported. */ +#define VMX_UFC_EPT_FLUSH_TYPE_UNSUPPORTED 11 +/** EPT paging structure memory type is not write-back. */ +#define VMX_UFC_EPT_MEM_TYPE_NOT_WB 12 +/** EPT requires INVEPT instr. support but it's not available. */ +#define VMX_UFC_EPT_INVEPT_UNAVAILABLE 13 +/** EPT requires page-walk length of 4. */ +#define VMX_UFC_EPT_PAGE_WALK_LENGTH_UNSUPPORTED 14 +/** VMX VMWRITE all feature exposed to the guest but not supported on host. */ +#define VMX_UFC_GST_HOST_VMWRITE_ALL 15 +/** LBR stack size cannot be determined for the current CPU. */ +#define VMX_UFC_LBR_STACK_SIZE_UNKNOWN 16 +/** LBR stack size of the CPU exceeds our buffer size. */ +#define VMX_UFC_LBR_STACK_SIZE_OVERFLOW 17 +/** @} */ + +/** @name VMX HM-error codes for VERR_VMX_VMCS_FIELD_CACHE_INVALID. + * VCI = VMCS-field Cache Invalid. + * @{ + */ +/** Cache of VM-entry controls invalid. */ +#define VMX_VCI_CTRL_ENTRY 300 +/** Cache of VM-exit controls invalid. */ +#define VMX_VCI_CTRL_EXIT 301 +/** Cache of pin-based VM-execution controls invalid. */ +#define VMX_VCI_CTRL_PIN_EXEC 302 +/** Cache of processor-based VM-execution controls invalid. */ +#define VMX_VCI_CTRL_PROC_EXEC 303 +/** Cache of secondary processor-based VM-execution controls invalid. */ +#define VMX_VCI_CTRL_PROC_EXEC2 304 +/** Cache of exception bitmap invalid. */ +#define VMX_VCI_CTRL_XCPT_BITMAP 305 +/** Cache of TSC offset invalid. */ +#define VMX_VCI_CTRL_TSC_OFFSET 306 +/** Cache of tertiary processor-based VM-execution controls invalid. */ +#define VMX_VCI_CTRL_PROC_EXEC3 307 +/** @} */ + +/** @name VMX HM-error codes for VERR_VMX_INVALID_GUEST_STATE. + * IGS = Invalid Guest State. + * @{ + */ +/** An error occurred while checking invalid-guest-state. */ +#define VMX_IGS_ERROR 500 +/** The invalid guest-state checks did not find any reason why. */ +#define VMX_IGS_REASON_NOT_FOUND 501 +/** CR0 fixed1 bits invalid. */ +#define VMX_IGS_CR0_FIXED1 502 +/** CR0 fixed0 bits invalid. */ +#define VMX_IGS_CR0_FIXED0 503 +/** CR0.PE and CR0.PE invalid VT-x/host combination. */ +#define VMX_IGS_CR0_PG_PE_COMBO 504 +/** CR4 fixed1 bits invalid. */ +#define VMX_IGS_CR4_FIXED1 505 +/** CR4 fixed0 bits invalid. */ +#define VMX_IGS_CR4_FIXED0 506 +/** Reserved bits in VMCS' DEBUGCTL MSR field not set to 0 when + * VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG is used. */ +#define VMX_IGS_DEBUGCTL_MSR_RESERVED 507 +/** CR0.PG not set for long-mode when not using unrestricted guest. */ +#define VMX_IGS_CR0_PG_LONGMODE 508 +/** CR4.PAE not set for long-mode guest when not using unrestricted guest. */ +#define VMX_IGS_CR4_PAE_LONGMODE 509 +/** CR4.PCIDE set for 32-bit guest. */ +#define VMX_IGS_CR4_PCIDE 510 +/** VMCS' DR7 reserved bits not set to 0. */ +#define VMX_IGS_DR7_RESERVED 511 +/** VMCS' PERF_GLOBAL MSR reserved bits not set to 0. */ +#define VMX_IGS_PERF_GLOBAL_MSR_RESERVED 512 +/** VMCS' EFER MSR reserved bits not set to 0. */ +#define VMX_IGS_EFER_MSR_RESERVED 513 +/** VMCS' EFER MSR.LMA does not match the IA32e mode guest control. */ +#define VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH 514 +/** VMCS' EFER MSR.LMA does not match EFER.LME of the guest when using paging + * without unrestricted guest. */ +#define VMX_IGS_EFER_LMA_LME_MISMATCH 515 +/** CS.Attr.P bit invalid. */ +#define VMX_IGS_CS_ATTR_P_INVALID 516 +/** CS.Attr reserved bits not set to 0. */ +#define VMX_IGS_CS_ATTR_RESERVED 517 +/** CS.Attr.G bit invalid. */ +#define VMX_IGS_CS_ATTR_G_INVALID 518 +/** CS is unusable. */ +#define VMX_IGS_CS_ATTR_UNUSABLE 519 +/** CS and SS DPL unequal. */ +#define VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL 520 +/** CS and SS DPL mismatch. */ +#define VMX_IGS_CS_SS_ATTR_DPL_MISMATCH 521 +/** CS Attr.Type invalid. */ +#define VMX_IGS_CS_ATTR_TYPE_INVALID 522 +/** CS and SS RPL unequal. */ +#define VMX_IGS_SS_CS_RPL_UNEQUAL 523 +/** SS.Attr.DPL and SS RPL unequal. */ +#define VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL 524 +/** SS.Attr.DPL invalid for segment type. */ +#define VMX_IGS_SS_ATTR_DPL_INVALID 525 +/** SS.Attr.Type invalid. */ +#define VMX_IGS_SS_ATTR_TYPE_INVALID 526 +/** SS.Attr.P bit invalid. */ +#define VMX_IGS_SS_ATTR_P_INVALID 527 +/** SS.Attr reserved bits not set to 0. */ +#define VMX_IGS_SS_ATTR_RESERVED 528 +/** SS.Attr.G bit invalid. */ +#define VMX_IGS_SS_ATTR_G_INVALID 529 +/** DS.Attr.A bit invalid. */ +#define VMX_IGS_DS_ATTR_A_INVALID 530 +/** DS.Attr.P bit invalid. */ +#define VMX_IGS_DS_ATTR_P_INVALID 531 +/** DS.Attr.DPL and DS RPL unequal. */ +#define VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL 532 +/** DS.Attr reserved bits not set to 0. */ +#define VMX_IGS_DS_ATTR_RESERVED 533 +/** DS.Attr.G bit invalid. */ +#define VMX_IGS_DS_ATTR_G_INVALID 534 +/** DS.Attr.Type invalid. */ +#define VMX_IGS_DS_ATTR_TYPE_INVALID 535 +/** ES.Attr.A bit invalid. */ +#define VMX_IGS_ES_ATTR_A_INVALID 536 +/** ES.Attr.P bit invalid. */ +#define VMX_IGS_ES_ATTR_P_INVALID 537 +/** ES.Attr.DPL and DS RPL unequal. */ +#define VMX_IGS_ES_ATTR_DPL_RPL_UNEQUAL 538 +/** ES.Attr reserved bits not set to 0. */ +#define VMX_IGS_ES_ATTR_RESERVED 539 +/** ES.Attr.G bit invalid. */ +#define VMX_IGS_ES_ATTR_G_INVALID 540 +/** ES.Attr.Type invalid. */ +#define VMX_IGS_ES_ATTR_TYPE_INVALID 541 +/** FS.Attr.A bit invalid. */ +#define VMX_IGS_FS_ATTR_A_INVALID 542 +/** FS.Attr.P bit invalid. */ +#define VMX_IGS_FS_ATTR_P_INVALID 543 +/** FS.Attr.DPL and DS RPL unequal. */ +#define VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL 544 +/** FS.Attr reserved bits not set to 0. */ +#define VMX_IGS_FS_ATTR_RESERVED 545 +/** FS.Attr.G bit invalid. */ +#define VMX_IGS_FS_ATTR_G_INVALID 546 +/** FS.Attr.Type invalid. */ +#define VMX_IGS_FS_ATTR_TYPE_INVALID 547 +/** GS.Attr.A bit invalid. */ +#define VMX_IGS_GS_ATTR_A_INVALID 548 +/** GS.Attr.P bit invalid. */ +#define VMX_IGS_GS_ATTR_P_INVALID 549 +/** GS.Attr.DPL and DS RPL unequal. */ +#define VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL 550 +/** GS.Attr reserved bits not set to 0. */ +#define VMX_IGS_GS_ATTR_RESERVED 551 +/** GS.Attr.G bit invalid. */ +#define VMX_IGS_GS_ATTR_G_INVALID 552 +/** GS.Attr.Type invalid. */ +#define VMX_IGS_GS_ATTR_TYPE_INVALID 553 +/** V86 mode CS.Base invalid. */ +#define VMX_IGS_V86_CS_BASE_INVALID 554 +/** V86 mode CS.Limit invalid. */ +#define VMX_IGS_V86_CS_LIMIT_INVALID 555 +/** V86 mode CS.Attr invalid. */ +#define VMX_IGS_V86_CS_ATTR_INVALID 556 +/** V86 mode SS.Base invalid. */ +#define VMX_IGS_V86_SS_BASE_INVALID 557 +/** V86 mode SS.Limit invalid. */ +#define VMX_IGS_V86_SS_LIMIT_INVALID 558 +/** V86 mode SS.Attr invalid. */ +#define VMX_IGS_V86_SS_ATTR_INVALID 559 +/** V86 mode DS.Base invalid. */ +#define VMX_IGS_V86_DS_BASE_INVALID 560 +/** V86 mode DS.Limit invalid. */ +#define VMX_IGS_V86_DS_LIMIT_INVALID 561 +/** V86 mode DS.Attr invalid. */ +#define VMX_IGS_V86_DS_ATTR_INVALID 562 +/** V86 mode ES.Base invalid. */ +#define VMX_IGS_V86_ES_BASE_INVALID 563 +/** V86 mode ES.Limit invalid. */ +#define VMX_IGS_V86_ES_LIMIT_INVALID 564 +/** V86 mode ES.Attr invalid. */ +#define VMX_IGS_V86_ES_ATTR_INVALID 565 +/** V86 mode FS.Base invalid. */ +#define VMX_IGS_V86_FS_BASE_INVALID 566 +/** V86 mode FS.Limit invalid. */ +#define VMX_IGS_V86_FS_LIMIT_INVALID 567 +/** V86 mode FS.Attr invalid. */ +#define VMX_IGS_V86_FS_ATTR_INVALID 568 +/** V86 mode GS.Base invalid. */ +#define VMX_IGS_V86_GS_BASE_INVALID 569 +/** V86 mode GS.Limit invalid. */ +#define VMX_IGS_V86_GS_LIMIT_INVALID 570 +/** V86 mode GS.Attr invalid. */ +#define VMX_IGS_V86_GS_ATTR_INVALID 571 +/** Longmode CS.Base invalid. */ +#define VMX_IGS_LONGMODE_CS_BASE_INVALID 572 +/** Longmode SS.Base invalid. */ +#define VMX_IGS_LONGMODE_SS_BASE_INVALID 573 +/** Longmode DS.Base invalid. */ +#define VMX_IGS_LONGMODE_DS_BASE_INVALID 574 +/** Longmode ES.Base invalid. */ +#define VMX_IGS_LONGMODE_ES_BASE_INVALID 575 +/** SYSENTER ESP is not canonical. */ +#define VMX_IGS_SYSENTER_ESP_NOT_CANONICAL 576 +/** SYSENTER EIP is not canonical. */ +#define VMX_IGS_SYSENTER_EIP_NOT_CANONICAL 577 +/** PAT MSR invalid. */ +#define VMX_IGS_PAT_MSR_INVALID 578 +/** PAT MSR reserved bits not set to 0. */ +#define VMX_IGS_PAT_MSR_RESERVED 579 +/** GDTR.Base is not canonical. */ +#define VMX_IGS_GDTR_BASE_NOT_CANONICAL 580 +/** IDTR.Base is not canonical. */ +#define VMX_IGS_IDTR_BASE_NOT_CANONICAL 581 +/** GDTR.Limit invalid. */ +#define VMX_IGS_GDTR_LIMIT_INVALID 582 +/** IDTR.Limit invalid. */ +#define VMX_IGS_IDTR_LIMIT_INVALID 583 +/** Longmode RIP is invalid. */ +#define VMX_IGS_LONGMODE_RIP_INVALID 584 +/** RFLAGS reserved bits not set to 0. */ +#define VMX_IGS_RFLAGS_RESERVED 585 +/** RFLAGS RA1 reserved bits not set to 1. */ +#define VMX_IGS_RFLAGS_RESERVED1 586 +/** RFLAGS.VM (V86 mode) invalid. */ +#define VMX_IGS_RFLAGS_VM_INVALID 587 +/** RFLAGS.IF invalid. */ +#define VMX_IGS_RFLAGS_IF_INVALID 588 +/** Activity state invalid. */ +#define VMX_IGS_ACTIVITY_STATE_INVALID 589 +/** Activity state HLT invalid when SS.Attr.DPL is not zero. */ +#define VMX_IGS_ACTIVITY_STATE_HLT_INVALID 590 +/** Activity state ACTIVE invalid when block-by-STI or MOV SS. */ +#define VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID 591 +/** Activity state SIPI WAIT invalid. */ +#define VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID 592 +/** Interruptibility state reserved bits not set to 0. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED 593 +/** Interruptibility state cannot be block-by-STI -and- MOV SS. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID 594 +/** Interruptibility state block-by-STI invalid for EFLAGS. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID 595 +/** Interruptibility state invalid while trying to deliver external + * interrupt. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID 596 +/** Interruptibility state block-by-MOVSS invalid while trying to deliver an + * NMI. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID 597 +/** Interruptibility state block-by-SMI invalid when CPU is not in SMM. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID 598 +/** Interruptibility state block-by-SMI invalid when trying to enter SMM. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID 599 +/** Interruptibility state block-by-STI (maybe) invalid when trying to + * deliver an NMI. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID 600 +/** Interruptibility state block-by-NMI invalid when virtual-NMIs control is + * active. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID 601 +/** Pending debug exceptions reserved bits not set to 0. */ +#define VMX_IGS_PENDING_DEBUG_RESERVED 602 +/** Longmode pending debug exceptions reserved bits not set to 0. */ +#define VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED 603 +/** Pending debug exceptions.BS bit is not set when it should be. */ +#define VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET 604 +/** Pending debug exceptions.BS bit is not clear when it should be. */ +#define VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR 605 +/** VMCS link pointer reserved bits not set to 0. */ +#define VMX_IGS_VMCS_LINK_PTR_RESERVED 606 +/** TR cannot index into LDT, TI bit MBZ. */ +#define VMX_IGS_TR_TI_INVALID 607 +/** LDTR cannot index into LDT. TI bit MBZ. */ +#define VMX_IGS_LDTR_TI_INVALID 608 +/** TR.Base is not canonical. */ +#define VMX_IGS_TR_BASE_NOT_CANONICAL 609 +/** FS.Base is not canonical. */ +#define VMX_IGS_FS_BASE_NOT_CANONICAL 610 +/** GS.Base is not canonical. */ +#define VMX_IGS_GS_BASE_NOT_CANONICAL 611 +/** LDTR.Base is not canonical. */ +#define VMX_IGS_LDTR_BASE_NOT_CANONICAL 612 +/** TR is unusable. */ +#define VMX_IGS_TR_ATTR_UNUSABLE 613 +/** TR.Attr.S bit invalid. */ +#define VMX_IGS_TR_ATTR_S_INVALID 614 +/** TR is not present. */ +#define VMX_IGS_TR_ATTR_P_INVALID 615 +/** TR.Attr reserved bits not set to 0. */ +#define VMX_IGS_TR_ATTR_RESERVED 616 +/** TR.Attr.G bit invalid. */ +#define VMX_IGS_TR_ATTR_G_INVALID 617 +/** Longmode TR.Attr.Type invalid. */ +#define VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID 618 +/** TR.Attr.Type invalid. */ +#define VMX_IGS_TR_ATTR_TYPE_INVALID 619 +/** CS.Attr.S invalid. */ +#define VMX_IGS_CS_ATTR_S_INVALID 620 +/** CS.Attr.DPL invalid. */ +#define VMX_IGS_CS_ATTR_DPL_INVALID 621 +/** PAE PDPTE reserved bits not set to 0. */ +#define VMX_IGS_PAE_PDPTE_RESERVED 623 +/** VMCS link pointer does not point to a shadow VMCS. */ +#define VMX_IGS_VMCS_LINK_PTR_NOT_SHADOW 624 +/** VMCS link pointer to a shadow VMCS with invalid VMCS revision identifer. */ +#define VMX_IGS_VMCS_LINK_PTR_SHADOW_VMCS_ID_INVALID 625 +/** @} */ + +/** @name VMX VMCS-Read cache indices. + * @{ + */ +#define VMX_VMCS_GUEST_ES_BASE_CACHE_IDX 0 +#define VMX_VMCS_GUEST_CS_BASE_CACHE_IDX 1 +#define VMX_VMCS_GUEST_SS_BASE_CACHE_IDX 2 +#define VMX_VMCS_GUEST_DS_BASE_CACHE_IDX 3 +#define VMX_VMCS_GUEST_FS_BASE_CACHE_IDX 4 +#define VMX_VMCS_GUEST_GS_BASE_CACHE_IDX 5 +#define VMX_VMCS_GUEST_LDTR_BASE_CACHE_IDX 6 +#define VMX_VMCS_GUEST_TR_BASE_CACHE_IDX 7 +#define VMX_VMCS_GUEST_GDTR_BASE_CACHE_IDX 8 +#define VMX_VMCS_GUEST_IDTR_BASE_CACHE_IDX 9 +#define VMX_VMCS_GUEST_RSP_CACHE_IDX 10 +#define VMX_VMCS_GUEST_RIP_CACHE_IDX 11 +#define VMX_VMCS_GUEST_SYSENTER_ESP_CACHE_IDX 12 +#define VMX_VMCS_GUEST_SYSENTER_EIP_CACHE_IDX 13 +#define VMX_VMCS_RO_EXIT_QUALIFICATION_CACHE_IDX 14 +#define VMX_VMCS_RO_GUEST_LINEAR_ADDR_CACHE_IDX 15 +#define VMX_VMCS_MAX_CACHE_IDX (VMX_VMCS_RO_GUEST_LINEAR_ADDR_CACHE_IDX + 1) +#define VMX_VMCS_GUEST_CR3_CACHE_IDX 16 +#define VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX (VMX_VMCS_GUEST_CR3_CACHE_IDX + 1) +/** @} */ + + +/** @name VMX Extended Page Tables (EPT) Common Bits. + * @{ */ +/** Bit 0 - Readable (we often think of it as present). */ +#define EPT_E_BIT_READ 0 +#define EPT_E_READ RT_BIT_64(EPT_E_BIT_READ) /**< @see EPT_E_BIT_READ */ +/** Bit 1 - Writable. */ +#define EPT_E_BIT_WRITE 1 +#define EPT_E_WRITE RT_BIT_64(EPT_E_BIT_WRITE) /**< @see EPT_E_BIT_WRITE */ +/** Bit 2 - Executable. + * @note This controls supervisor instruction fetching if mode-based + * execution control is enabled. */ +#define EPT_E_BIT_EXECUTE 2 +#define EPT_E_EXECUTE RT_BIT_64(EPT_E_BIT_EXECUTE) /**< @see EPT_E_BIT_EXECUTE */ +/** Bits 3-5 - Memory type mask (leaf only, MBZ). + * The memory type is only applicable for leaf entries and MBZ for + * non-leaf (causes miconfiguration exit). */ +#define EPT_E_MEMTYPE_MASK UINT64_C(0x0038) +/** Bits 3-5 - Memory type shifted mask. */ +#define EPT_E_MEMTYPE_SMASK UINT64_C(0x0007) +/** Bits 3-5 - Memory type shift count. */ +#define EPT_E_MEMTYPE_SHIFT 3 +/** Bits 3-5 - Memory type: UC (Uncacheable). */ +#define EPT_E_MEMTYPE_UC (UINT64_C(0) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: WC (Write Combining). */ +#define EPT_E_MEMTYPE_WC (UINT64_C(1) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: Invalid (2). */ +#define EPT_E_MEMTYPE_INVALID_2 (UINT64_C(2) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: Invalid (3). */ +#define EPT_E_MEMTYPE_INVALID_3 (UINT64_C(3) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: WT (Write Through). */ +#define EPT_E_MEMTYPE_WT (UINT64_C(4) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: WP (Write Protected). */ +#define EPT_E_MEMTYPE_WP (UINT64_C(5) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: WB (Write Back). */ +#define EPT_E_MEMTYPE_WB (UINT64_C(6) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: Invalid (7). */ +#define EPT_E_MEMTYPE_INVALID_7 (UINT64_C(7) << EPT_E_MEMTYPE_SHIFT) +/** Bit 6 - Ignore page attribute table (leaf, MBZ). */ +#define EPT_E_BIT_IGNORE_PAT 6 +#define EPT_E_IGNORE_PAT RT_BIT_64(EPT_E_BIT_IGNORE_PAT) /**< @see EPT_E_BIT_IGNORE_PAT */ +/** Bit 7 - Leaf entry (MBZ in PML4, ignored in PT). */ +#define EPT_E_BIT_LEAF 7 +#define EPT_E_LEAF RT_BIT_64(EPT_E_BIT_LEAF) /**< @see EPT_E_BIT_LEAF */ +/** Bit 8 - Accessed (all levels). + * @note Ignored and not written when EPTP bit 6 is 0. */ +#define EPT_E_BIT_ACCESSED 8 +#define EPT_E_ACCESSED RT_BIT_64(EPT_E_BIT_ACCESSED) /**< @see EPT_E_BIT_ACCESSED */ +/** Bit 9 - Dirty (leaf only). + * @note Ignored and not written when EPTP bit 6 is 0. */ +#define EPT_E_BIT_DIRTY 9 +#define EPT_E_DIRTY RT_BIT_64(EPT_E_BIT_DIRTY) /**< @see EPT_E_BIT_DIRTY */ +/** Bit 10 - Executable for usermode. + * @note This ignored if mode-based execution control is disabled. */ +#define EPT_E_BIT_USER_EXECUTE 10 +#define EPT_E_USER_EXECUTE RT_BIT_64(EPT_E_BIT_USER_EXECUTE) /**< @see EPT_E_BIT_USER_EXECUTE */ +/* Bit 11 is always ignored. */ +/** Bits 12-51 - Physical Page number of the next level. */ +#define EPT_E_PG_MASK UINT64_C(0x000ffffffffff000) +/** Bit 58 - Page-write access (leaf only, ignored). + * @note Ignored if EPT page-write control is disabled. */ +#define EPT_E_BIT_PAGING_WRITE 58 +#define EPT_E_PAGING_WRITE RT_BIT_64(EPT_E_BIT_PAGING_WRITE) /**< @see EPT_E_BIT_PAGING_WRITE*/ +/* Bit 59 is always ignored. */ +/** Bit 60 - Supervisor shadow stack (leaf only, ignored). + * @note Ignored if EPT bit 7 is 0. */ +#define EPT_E_BIT_SUPER_SHW_STACK 60 +#define EPT_E_SUPER_SHW_STACK RT_BIT_64(EPT_E_BIT_SUPER_SHW_STACK) /**< @see EPT_E_BIT_SUPER_SHW_STACK */ +/** Bit 61 - Sub-page write permission (leaf only, ignored). + * @note Ignored if sub-page write permission for EPT is disabled. */ +#define EPT_E_BIT_SUBPAGE_WRITE_PERM 61 +#define EPT_E_SUBPAGE_WRITE_PERM RT_BIT_64(EPT_E_BIT_SUBPAGE_WRITE_PERM) /**< @see EPT_E_BIT_SUBPAGE_WRITE_PERM*/ +/* Bit 62 is always ignored. */ +/** Bit 63 - Suppress \#VE (leaf only, ignored). + * @note Ignored if EPT violation to \#VE conversion is disabled. */ +#define EPT_E_BIT_SUPPRESS_VE 63 +#define EPT_E_SUPPRESS_VE RT_BIT_64(EPT_E_BIT_SUPPRESS_VE) /**< @see EPT_E_BIT_SUPPRESS_VE */ +/** @} */ + + +/**@name Bit fields for common EPT attributes. + @{ */ +/** Read access. */ +#define VMX_BF_EPT_PT_READ_SHIFT 0 +#define VMX_BF_EPT_PT_READ_MASK UINT64_C(0x0000000000000001) +/** Write access. */ +#define VMX_BF_EPT_PT_WRITE_SHIFT 1 +#define VMX_BF_EPT_PT_WRITE_MASK UINT64_C(0x0000000000000002) +/** Execute access or execute access for supervisor-mode linear-addresses. */ +#define VMX_BF_EPT_PT_EXECUTE_SHIFT 2 +#define VMX_BF_EPT_PT_EXECUTE_MASK UINT64_C(0x0000000000000004) +/** EPT memory type. */ +#define VMX_BF_EPT_PT_MEMTYPE_SHIFT 3 +#define VMX_BF_EPT_PT_MEMTYPE_MASK UINT64_C(0x0000000000000038) +/** Ignore PAT. */ +#define VMX_BF_EPT_PT_IGNORE_PAT_SHIFT 6 +#define VMX_BF_EPT_PT_IGNORE_PAT_MASK UINT64_C(0x0000000000000040) +/** Ignored (bit 7). */ +#define VMX_BF_EPT_PT_IGN_7_SHIFT 7 +#define VMX_BF_EPT_PT_IGN_7_MASK UINT64_C(0x0000000000000080) +/** Accessed flag. */ +#define VMX_BF_EPT_PT_ACCESSED_SHIFT 8 +#define VMX_BF_EPT_PT_ACCESSED_MASK UINT64_C(0x0000000000000100) +/** Dirty flag. */ +#define VMX_BF_EPT_PT_DIRTY_SHIFT 9 +#define VMX_BF_EPT_PT_DIRTY_MASK UINT64_C(0x0000000000000200) +/** Execute access for user-mode linear addresses. */ +#define VMX_BF_EPT_PT_EXECUTE_USER_SHIFT 10 +#define VMX_BF_EPT_PT_EXECUTE_USER_MASK UINT64_C(0x0000000000000400) +/** Ignored (bit 59:11). */ +#define VMX_BF_EPT_PT_IGN_59_11_SHIFT 11 +#define VMX_BF_EPT_PT_IGN_59_11_MASK UINT64_C(0x0ffffffffffff800) +/** Supervisor shadow stack. */ +#define VMX_BF_EPT_PT_SUPER_SHW_STACK_SHIFT 60 +#define VMX_BF_EPT_PT_SUPER_SHW_STACK_MASK UINT64_C(0x1000000000000000) +/** Ignored (bits 62:61). */ +#define VMX_BF_EPT_PT_IGN_62_61_SHIFT 61 +#define VMX_BF_EPT_PT_IGN_62_61_MASK UINT64_C(0x6000000000000000) +/** Suppress \#VE. */ +#define VMX_BF_EPT_PT_SUPPRESS_VE_SHIFT 63 +#define VMX_BF_EPT_PT_SUPPRESS_VE_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EPT_PT_, UINT64_C(0), UINT64_MAX, + (READ, WRITE, EXECUTE, MEMTYPE, IGNORE_PAT, IGN_7, ACCESSED, DIRTY, EXECUTE_USER, IGN_59_11, + SUPER_SHW_STACK, IGN_62_61, SUPPRESS_VE)); +/** @} */ + + +/** @name VMX Extended Page Tables (EPT) Structures + * @{ + */ + +/** + * Number of page table entries in the EPT. (PDPTE/PDE/PTE) + */ +#define EPT_PG_ENTRIES X86_PG_PAE_ENTRIES + +/** + * EPT present mask. + * These are ONLY the common bits in all EPT page-table entries which does + * not rely on any CPU feature. It isn't necessarily the complete mask (e.g. when + * mode-based excute control is active). + */ +#define EPT_PRESENT_MASK (EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE) + +/** + * EPT Page Directory Pointer Entry. Bit view. + * In accordance with the VT-x spec. + * + * @todo uint64_t isn't safe for bitfields (gcc pedantic warnings, and IIRC, + * this did cause trouble with one compiler/version). + */ +typedef struct EPTPML4EBITS +{ + /** Present bit. */ + RT_GCC_EXTENSION uint64_t u1Present : 1; + /** Writable bit. */ + RT_GCC_EXTENSION uint64_t u1Write : 1; + /** Executable bit. */ + RT_GCC_EXTENSION uint64_t u1Execute : 1; + /** Reserved (must be 0). */ + RT_GCC_EXTENSION uint64_t u5Reserved : 5; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u4Available : 4; + /** Physical address of the next level (PD). Restricted by maximum physical address width of the cpu. */ + RT_GCC_EXTENSION uint64_t u40PhysAddr : 40; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u12Available : 12; +} EPTPML4EBITS; +AssertCompileSize(EPTPML4EBITS, 8); + +/** Bits 12-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PML4E_PG_MASK X86_PML4E_PG_MASK +/** The page shift to get the PML4 index. */ +#define EPT_PML4_SHIFT X86_PML4_SHIFT +/** The PML4 index mask (apply to a shifted page address). */ +#define EPT_PML4_MASK X86_PML4_MASK +/** Bits - - EPT - PML4 MBZ mask. */ +#define EPT_PML4E_MBZ_MASK UINT64_C(0x00000000000000f8) +/** Mask of all possible EPT PML4E attribute bits. */ +#define EPT_PML4E_ATTR_MASK (EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_ACCESSED | EPT_E_USER_EXECUTE) + +/** + * EPT PML4E. + * In accordance with the VT-x spec. + */ +typedef union EPTPML4E +{ +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + EPTPML4EBITS n; +#endif + /** Unsigned integer view. */ + X86PGPAEUINT u; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} EPTPML4E; +AssertCompileSize(EPTPML4E, 8); +/** Pointer to a PML4 table entry. */ +typedef EPTPML4E *PEPTPML4E; +/** Pointer to a const PML4 table entry. */ +typedef const EPTPML4E *PCEPTPML4E; + +/** + * EPT PML4 Table. + * In accordance with the VT-x spec. + */ +typedef struct EPTPML4 +{ + EPTPML4E a[EPT_PG_ENTRIES]; +} EPTPML4; +AssertCompileSize(EPTPML4, 0x1000); +/** Pointer to an EPT PML4 Table. */ +typedef EPTPML4 *PEPTPML4; +/** Pointer to a const EPT PML4 Table. */ +typedef const EPTPML4 *PCEPTPML4; + + +/** + * EPT Page Directory Pointer Entry. Bit view. + * In accordance with the VT-x spec. + */ +typedef struct EPTPDPTEBITS +{ + /** Present bit. */ + RT_GCC_EXTENSION uint64_t u1Present : 1; + /** Writable bit. */ + RT_GCC_EXTENSION uint64_t u1Write : 1; + /** Executable bit. */ + RT_GCC_EXTENSION uint64_t u1Execute : 1; + /** Reserved (must be 0). */ + RT_GCC_EXTENSION uint64_t u5Reserved : 5; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u4Available : 4; + /** Physical address of the next level (PD). Restricted by maximum physical address width of the cpu. */ + RT_GCC_EXTENSION uint64_t u40PhysAddr : 40; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u12Available : 12; +} EPTPDPTEBITS; +AssertCompileSize(EPTPDPTEBITS, 8); + +/** Bit 7 - - EPT - PDPTE maps a 1GB page. */ +#define EPT_PDPTE1G_SIZE_MASK RT_BIT_64(7) +/** Bits 12-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PDPTE_PG_MASK X86_PDPE_PG_MASK +/** Bits 30-51 - - EPT - Physical Page number of the 1G large page. */ +#define EPT_PDPTE1G_PG_MASK X86_PDPE1G_PG_MASK + +/** The page shift to get the PDPT index. */ +#define EPT_PDPT_SHIFT X86_PDPT_SHIFT +/** The PDPT index mask (apply to a shifted page address). */ +#define EPT_PDPT_MASK X86_PDPT_MASK_AMD64 +/** Bits 3-7 - - EPT - PDPTE MBZ Mask. */ +#define EPT_PDPTE_MBZ_MASK UINT64_C(0x00000000000000f8) +/** Bits 12-29 - - EPT - 1GB PDPTE MBZ Mask. */ +#define EPT_PDPTE1G_MBZ_MASK UINT64_C(0x000000003ffff000) +/** Mask of all possible EPT PDPTE (1GB) attribute bits. */ +#define EPT_PDPTE1G_ATTR_MASK ( EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_MEMTYPE_MASK | EPT_E_IGNORE_PAT \ + | EPT_E_ACCESSED | EPT_E_DIRTY | EPT_E_USER_EXECUTE) +/** Mask of all possible EPT PDPTE attribute bits. */ +#define EPT_PDPTE_ATTR_MASK (EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_ACCESSED | EPT_E_USER_EXECUTE) +/** */ + +/** + * EPT Page Directory Pointer. + * In accordance with the VT-x spec. + */ +typedef union EPTPDPTE +{ +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + EPTPDPTEBITS n; +#endif + /** Unsigned integer view. */ + X86PGPAEUINT u; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} EPTPDPTE; +AssertCompileSize(EPTPDPTE, 8); +/** Pointer to an EPT Page Directory Pointer Entry. */ +typedef EPTPDPTE *PEPTPDPTE; +/** Pointer to a const EPT Page Directory Pointer Entry. */ +typedef const EPTPDPTE *PCEPTPDPTE; + +/** + * EPT Page Directory Pointer Table. + * In accordance with the VT-x spec. + */ +typedef struct EPTPDPT +{ + EPTPDPTE a[EPT_PG_ENTRIES]; +} EPTPDPT; +AssertCompileSize(EPTPDPT, 0x1000); +/** Pointer to an EPT Page Directory Pointer Table. */ +typedef EPTPDPT *PEPTPDPT; +/** Pointer to a const EPT Page Directory Pointer Table. */ +typedef const EPTPDPT *PCEPTPDPT; + + +/** + * EPT Page Directory Table Entry. Bit view. + * In accordance with the VT-x spec. + */ +typedef struct EPTPDEBITS +{ + /** Present bit. */ + RT_GCC_EXTENSION uint64_t u1Present : 1; + /** Writable bit. */ + RT_GCC_EXTENSION uint64_t u1Write : 1; + /** Executable bit. */ + RT_GCC_EXTENSION uint64_t u1Execute : 1; + /** Reserved (must be 0). */ + RT_GCC_EXTENSION uint64_t u4Reserved : 4; + /** Big page (must be 0 here). */ + RT_GCC_EXTENSION uint64_t u1Size : 1; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u4Available : 4; + /** Physical address of page table. Restricted by maximum physical address width of the cpu. */ + RT_GCC_EXTENSION uint64_t u40PhysAddr : 40; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u12Available : 12; +} EPTPDEBITS; +AssertCompileSize(EPTPDEBITS, 8); + +/** Bits 12-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PDE_PG_MASK X86_PDE_PAE_PG_MASK +/** The page shift to get the PD index. */ +#define EPT_PD_SHIFT X86_PD_PAE_SHIFT +/** The PD index mask (apply to a shifted page address). */ +#define EPT_PD_MASK X86_PD_PAE_MASK +/** Bits 3-7 - EPT - PDE MBZ Mask. */ +#define EPT_PDE_MBZ_MASK UINT64_C(0x00000000000000f8) +/** Mask of all possible EPT PDE (2M) attribute bits. */ +#define EPT_PDE2M_ATTR_MASK ( EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_MEMTYPE_MASK | EPT_E_IGNORE_PAT \ + | EPT_E_ACCESSED | EPT_E_DIRTY | EPT_E_USER_EXECUTE) +/** Mask of all possible EPT PDE attribute bits. */ +#define EPT_PDE_ATTR_MASK (EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_ACCESSED | EPT_E_USER_EXECUTE) + + +/** + * EPT 2MB Page Directory Table Entry. Bit view. + * In accordance with the VT-x spec. + */ +typedef struct EPTPDE2MBITS +{ + /** Present bit. */ + RT_GCC_EXTENSION uint64_t u1Present : 1; + /** Writable bit. */ + RT_GCC_EXTENSION uint64_t u1Write : 1; + /** Executable bit. */ + RT_GCC_EXTENSION uint64_t u1Execute : 1; + /** EPT Table Memory Type. MBZ for non-leaf nodes. */ + RT_GCC_EXTENSION uint64_t u3EMT : 3; + /** Ignore PAT memory type */ + RT_GCC_EXTENSION uint64_t u1IgnorePAT : 1; + /** Big page (must be 1 here). */ + RT_GCC_EXTENSION uint64_t u1Size : 1; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u4Available : 4; + /** Reserved (must be 0). */ + RT_GCC_EXTENSION uint64_t u9Reserved : 9; + /** Physical address of the 2MB page. Restricted by maximum physical address width of the cpu. */ + RT_GCC_EXTENSION uint64_t u31PhysAddr : 31; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u12Available : 12; +} EPTPDE2MBITS; +AssertCompileSize(EPTPDE2MBITS, 8); + +/** Bits 21-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PDE2M_PG_MASK X86_PDE2M_PAE_PG_MASK +/** Bits 20-12 - - EPT - PDE 2M MBZ Mask. */ +#define EPT_PDE2M_MBZ_MASK UINT64_C(0x00000000001ff000) + + +/** + * EPT Page Directory Table Entry. + * In accordance with the VT-x spec. + */ +typedef union EPTPDE +{ +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + EPTPDEBITS n; + /** 2MB view (big). */ + EPTPDE2MBITS b; +#endif + /** Unsigned integer view. */ + X86PGPAEUINT u; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} EPTPDE; +AssertCompileSize(EPTPDE, 8); +/** Pointer to an EPT Page Directory Table Entry. */ +typedef EPTPDE *PEPTPDE; +/** Pointer to a const EPT Page Directory Table Entry. */ +typedef const EPTPDE *PCEPTPDE; + +/** + * EPT Page Directory Table. + * In accordance with the VT-x spec. + */ +typedef struct EPTPD +{ + EPTPDE a[EPT_PG_ENTRIES]; +} EPTPD; +AssertCompileSize(EPTPD, 0x1000); +/** Pointer to an EPT Page Directory Table. */ +typedef EPTPD *PEPTPD; +/** Pointer to a const EPT Page Directory Table. */ +typedef const EPTPD *PCEPTPD; + +/** + * EPT Page Table Entry. Bit view. + * In accordance with the VT-x spec. + */ +typedef struct EPTPTEBITS +{ + /** 0 - Present bit. + * @remarks This is a convenience "misnomer". The bit actually indicates read access + * and the CPU will consider an entry with any of the first three bits set + * as present. Since all our valid entries will have this bit set, it can + * be used as a present indicator and allow some code sharing. */ + RT_GCC_EXTENSION uint64_t u1Present : 1; + /** 1 - Writable bit. */ + RT_GCC_EXTENSION uint64_t u1Write : 1; + /** 2 - Executable bit. */ + RT_GCC_EXTENSION uint64_t u1Execute : 1; + /** 5:3 - EPT Memory Type. MBZ for non-leaf nodes. */ + RT_GCC_EXTENSION uint64_t u3EMT : 3; + /** 6 - Ignore PAT memory type */ + RT_GCC_EXTENSION uint64_t u1IgnorePAT : 1; + /** 11:7 - Available for software. */ + RT_GCC_EXTENSION uint64_t u5Available : 5; + /** 51:12 - Physical address of page. Restricted by maximum physical + * address width of the cpu. */ + RT_GCC_EXTENSION uint64_t u40PhysAddr : 40; + /** 63:52 - Available for software. */ + RT_GCC_EXTENSION uint64_t u12Available : 12; +} EPTPTEBITS; +AssertCompileSize(EPTPTEBITS, 8); + +/** Bits 12-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PTE_PG_MASK X86_PTE_PAE_PG_MASK +/** The page shift to get the EPT PTE index. */ +#define EPT_PT_SHIFT X86_PT_PAE_SHIFT +/** The EPT PT index mask (apply to a shifted page address). */ +#define EPT_PT_MASK X86_PT_PAE_MASK +/** No bits - - EPT - PTE MBZ bits. */ +#define EPT_PTE_MBZ_MASK UINT64_C(0x0000000000000000) +/** Mask of all possible EPT PTE attribute bits. */ +#define EPT_PTE_ATTR_MASK ( EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_MEMTYPE_MASK | EPT_E_IGNORE_PAT \ + | EPT_E_ACCESSED | EPT_E_USER_EXECUTE) + + +/** + * EPT Page Table Entry. + * In accordance with the VT-x spec. + */ +typedef union EPTPTE +{ +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + EPTPTEBITS n; +#endif + /** Unsigned integer view. */ + X86PGPAEUINT u; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} EPTPTE; +AssertCompileSize(EPTPTE, 8); +/** Pointer to an EPT Page Directory Table Entry. */ +typedef EPTPTE *PEPTPTE; +/** Pointer to a const EPT Page Directory Table Entry. */ +typedef const EPTPTE *PCEPTPTE; + +/** + * EPT Page Table. + * In accordance with the VT-x spec. + */ +typedef struct EPTPT +{ + EPTPTE a[EPT_PG_ENTRIES]; +} EPTPT; +AssertCompileSize(EPTPT, 0x1000); +/** Pointer to an extended page table. */ +typedef EPTPT *PEPTPT; +/** Pointer to a const extended table. */ +typedef const EPTPT *PCEPTPT; + +/** EPTP page mask for the EPT PML4 table. */ +#define EPT_EPTP_PG_MASK X86_CR3_AMD64_PAGE_MASK +/** @} */ + +/** + * VMX VPID flush types. + * Valid enum members are in accordance with the VT-x spec. + */ +typedef enum +{ + /** Invalidate a specific page. */ + VMXTLBFLUSHVPID_INDIV_ADDR = 0, + /** Invalidate one context (specific VPID). */ + VMXTLBFLUSHVPID_SINGLE_CONTEXT = 1, + /** Invalidate all contexts (all VPIDs). */ + VMXTLBFLUSHVPID_ALL_CONTEXTS = 2, + /** Invalidate a single VPID context retaining global mappings. */ + VMXTLBFLUSHVPID_SINGLE_CONTEXT_RETAIN_GLOBALS = 3, + /** Unsupported by VirtualBox. */ + VMXTLBFLUSHVPID_NOT_SUPPORTED = 0xbad0, + /** Unsupported by CPU. */ + VMXTLBFLUSHVPID_NONE = 0xbad1 +} VMXTLBFLUSHVPID; +AssertCompileSize(VMXTLBFLUSHVPID, 4); +/** Mask of all valid INVVPID flush types. */ +#define VMX_INVVPID_VALID_MASK ( VMXTLBFLUSHVPID_INDIV_ADDR \ + | VMXTLBFLUSHVPID_SINGLE_CONTEXT \ + | VMXTLBFLUSHVPID_ALL_CONTEXTS \ + | VMXTLBFLUSHVPID_SINGLE_CONTEXT_RETAIN_GLOBALS) + +/** + * VMX EPT flush types. + * @note Valid enums values are in accordance with the VT-x spec. + */ +typedef enum +{ + /** Invalidate one context (specific EPT). */ + VMXTLBFLUSHEPT_SINGLE_CONTEXT = 1, + /* Invalidate all contexts (all EPTs) */ + VMXTLBFLUSHEPT_ALL_CONTEXTS = 2, + /** Unsupported by VirtualBox. */ + VMXTLBFLUSHEPT_NOT_SUPPORTED = 0xbad0, + /** Unsupported by CPU. */ + VMXTLBFLUSHEPT_NONE = 0xbad1 +} VMXTLBFLUSHEPT; +AssertCompileSize(VMXTLBFLUSHEPT, 4); +/** Mask of all valid INVEPT flush types. */ +#define VMX_INVEPT_VALID_MASK ( VMXTLBFLUSHEPT_SINGLE_CONTEXT \ + | VMXTLBFLUSHEPT_ALL_CONTEXTS) + +/** + * VMX Posted Interrupt Descriptor. + * In accordance with the VT-x spec. + */ +typedef struct VMXPOSTEDINTRDESC +{ + uint32_t aVectorBitmap[8]; + uint32_t fOutstandingNotification : 1; + uint32_t uReserved0 : 31; + uint8_t au8Reserved0[28]; +} VMXPOSTEDINTRDESC; +AssertCompileMemberSize(VMXPOSTEDINTRDESC, aVectorBitmap, 32); +AssertCompileSize(VMXPOSTEDINTRDESC, 64); +/** Pointer to a posted interrupt descriptor. */ +typedef VMXPOSTEDINTRDESC *PVMXPOSTEDINTRDESC; +/** Pointer to a const posted interrupt descriptor. */ +typedef const VMXPOSTEDINTRDESC *PCVMXPOSTEDINTRDESC; + +/** + * VMX VMCS revision identifier. + * In accordance with the VT-x spec. + */ +typedef union +{ + struct + { + /** Revision identifier. */ + uint32_t u31RevisionId : 31; + /** Whether this is a shadow VMCS. */ + uint32_t fIsShadowVmcs : 1; + } n; + /* The unsigned integer view. */ + uint32_t u; +} VMXVMCSREVID; +AssertCompileSize(VMXVMCSREVID, 4); +/** Pointer to the VMXVMCSREVID union. */ +typedef VMXVMCSREVID *PVMXVMCSREVID; +/** Pointer to a const VMXVMCSREVID union. */ +typedef const VMXVMCSREVID *PCVMXVMCSREVID; + +/** + * VMX VM-exit instruction information. + * In accordance with the VT-x spec. + */ +typedef union +{ + /** Plain unsigned int representation. */ + uint32_t u; + + /** INS and OUTS information. */ + struct + { + uint32_t u7Reserved0 : 7; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + uint32_t u5Reserved1 : 5; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + uint32_t uReserved2 : 14; + } StrIo; + + /** INVEPT, INVPCID, INVVPID information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u5Undef0 : 5; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Cleared to 0. */ + uint32_t u1Cleared0 : 1; + uint32_t u4Undef0 : 4; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Register 2 (X86_GREG_XXX). */ + uint32_t iReg2 : 4; + } Inv; + + /** VMCLEAR, VMPTRLD, VMPTRST, VMXON, XRSTORS, XSAVES information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u5Reserved0 : 5; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Cleared to 0. */ + uint32_t u1Cleared0 : 1; + uint32_t u4Reserved0 : 4; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Register 2 (X86_GREG_XXX). */ + uint32_t iReg2 : 4; + } VmxXsave; + + /** LIDT, LGDT, SIDT, SGDT information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u5Undef0 : 5; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Always cleared to 0. */ + uint32_t u1Cleared0 : 1; + /** Operand size; 0=16-bit, 1=32-bit, undefined for 64-bit. */ + uint32_t uOperandSize : 1; + uint32_t u3Undef0 : 3; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Instruction identity (VMX_INSTR_ID_XXX). */ + uint32_t u2InstrId : 2; + uint32_t u2Undef0 : 2; + } GdtIdt; + + /** LLDT, LTR, SLDT, STR information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u1Undef0 : 1; + /** Register 1 (X86_GREG_XXX). */ + uint32_t iReg1 : 4; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Memory/Register - Always cleared to 0 to indicate memory operand. */ + uint32_t fIsRegOperand : 1; + uint32_t u4Undef0 : 4; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Instruction identity (VMX_INSTR_ID_XXX). */ + uint32_t u2InstrId : 2; + uint32_t u2Undef0 : 2; + } LdtTr; + + /** RDRAND, RDSEED information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Undef0 : 2; + /** Destination register (X86_GREG_XXX). */ + uint32_t iReg1 : 4; + uint32_t u4Undef0 : 4; + /** Operand size; 0=16-bit, 1=32-bit, 2=64-bit, 3=unused. */ + uint32_t u2OperandSize : 2; + uint32_t u19Def0 : 20; + } RdrandRdseed; + + /** VMREAD, VMWRITE information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u1Undef0 : 1; + /** Register 1 (X86_GREG_XXX). */ + uint32_t iReg1 : 4; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Memory or register operand. */ + uint32_t fIsRegOperand : 1; + /** Operand size; 0=16-bit, 1=32-bit, 2=64-bit, 3=unused. */ + uint32_t u4Undef0 : 4; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Register 2 (X86_GREG_XXX). */ + uint32_t iReg2 : 4; + } VmreadVmwrite; + + struct + { + uint32_t u2Undef0 : 3; + /** First XMM register operand. */ + uint32_t u4XmmReg1 : 4; + uint32_t u23Undef1 : 21; + /** Second XMM register operand. */ + uint32_t u4XmmReg2 : 4; + } LoadIwkey; + + /** This is a combination field of all instruction information. Note! Not all field + * combinations are valid (e.g., iReg1 is undefined for memory operands) and + * specialized fields are overwritten by their generic counterparts (e.g. no + * instruction identity field). */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u1Undef0 : 1; + /** Register 1 (X86_GREG_XXX). */ + uint32_t iReg1 : 4; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Memory/Register - Always cleared to 0 to indicate memory operand. */ + uint32_t fIsRegOperand : 1; + /** Operand size; 0=16-bit, 1=32-bit, 2=64-bit, 3=unused. */ + uint32_t uOperandSize : 2; + uint32_t u2Undef0 : 2; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Register 2 (X86_GREG_XXX) or instruction identity. */ + uint32_t iReg2 : 4; + } All; +} VMXEXITINSTRINFO; +AssertCompileSize(VMXEXITINSTRINFO, 4); +/** Pointer to a VMX VM-exit instruction info. struct. */ +typedef VMXEXITINSTRINFO *PVMXEXITINSTRINFO; +/** Pointer to a const VMX VM-exit instruction info. struct. */ +typedef const VMXEXITINSTRINFO *PCVMXEXITINSTRINFO; + + +/** @name VM-entry failure reported in Exit qualification. + * See Intel spec. 26.7 "VM-entry failures during or after loading guest-state". + * @{ + */ +/** No errors during VM-entry. */ +#define VMX_ENTRY_FAIL_QUAL_NO_ERROR (0) +/** Not used. */ +#define VMX_ENTRY_FAIL_QUAL_NOT_USED (1) +/** Error while loading PDPTEs. */ +#define VMX_ENTRY_FAIL_QUAL_PDPTE (2) +/** NMI injection when blocking-by-STI is set. */ +#define VMX_ENTRY_FAIL_QUAL_NMI_INJECT (3) +/** Invalid VMCS link pointer. */ +#define VMX_ENTRY_FAIL_QUAL_VMCS_LINK_PTR (4) +/** @} */ + + +/** @name VMXMSRPM_XXX - VMX MSR-bitmap permissions. + * These are -not- specified by Intel but used internally by VirtualBox. + * @{ */ +/** Guest software reads of this MSR must not cause a VM-exit. */ +#define VMXMSRPM_ALLOW_RD RT_BIT(0) +/** Guest software reads of this MSR must cause a VM-exit. */ +#define VMXMSRPM_EXIT_RD RT_BIT(1) +/** Guest software writes to this MSR must not cause a VM-exit. */ +#define VMXMSRPM_ALLOW_WR RT_BIT(2) +/** Guest software writes to this MSR must cause a VM-exit. */ +#define VMXMSRPM_EXIT_WR RT_BIT(3) +/** Guest software reads or writes of this MSR must not cause a VM-exit. */ +#define VMXMSRPM_ALLOW_RD_WR (VMXMSRPM_ALLOW_RD | VMXMSRPM_ALLOW_WR) +/** Guest software reads or writes of this MSR must cause a VM-exit. */ +#define VMXMSRPM_EXIT_RD_WR (VMXMSRPM_EXIT_RD | VMXMSRPM_EXIT_WR) +/** Mask of valid MSR read permissions. */ +#define VMXMSRPM_RD_MASK (VMXMSRPM_ALLOW_RD | VMXMSRPM_EXIT_RD) +/** Mask of valid MSR write permissions. */ +#define VMXMSRPM_WR_MASK (VMXMSRPM_ALLOW_WR | VMXMSRPM_EXIT_WR) +/** Mask of valid MSR permissions. */ +#define VMXMSRPM_MASK (VMXMSRPM_RD_MASK | VMXMSRPM_WR_MASK) +/** */ +/** Gets whether the MSR permission is valid or not. */ +#define VMXMSRPM_IS_FLAG_VALID(a_Msrpm) ( (a_Msrpm) != 0 \ + && ((a_Msrpm) & ~VMXMSRPM_MASK) == 0 \ + && ((a_Msrpm) & VMXMSRPM_RD_MASK) != VMXMSRPM_RD_MASK \ + && ((a_Msrpm) & VMXMSRPM_WR_MASK) != VMXMSRPM_WR_MASK) +/** @} */ + +/** + * VMX MSR autoload/store slot. + * In accordance with the VT-x spec. + */ +typedef struct VMXAUTOMSR +{ + /** The MSR Id. */ + uint32_t u32Msr; + /** Reserved (MBZ). */ + uint32_t u32Reserved; + /** The MSR value. */ + uint64_t u64Value; +} VMXAUTOMSR; +AssertCompileSize(VMXAUTOMSR, 16); +/** Pointer to an MSR load/store element. */ +typedef VMXAUTOMSR *PVMXAUTOMSR; +/** Pointer to a const MSR load/store element. */ +typedef const VMXAUTOMSR *PCVMXAUTOMSR; + +/** VMX auto load-store MSR (VMXAUTOMSR) offset mask. */ +#define VMX_AUTOMSR_OFFSET_MASK 0xf + +/** + * VMX tagged-TLB flush types. + */ +typedef enum +{ + VMXTLBFLUSHTYPE_EPT, + VMXTLBFLUSHTYPE_VPID, + VMXTLBFLUSHTYPE_EPT_VPID, + VMXTLBFLUSHTYPE_NONE +} VMXTLBFLUSHTYPE; +/** Pointer to a VMXTLBFLUSHTYPE enum. */ +typedef VMXTLBFLUSHTYPE *PVMXTLBFLUSHTYPE; +/** Pointer to a const VMXTLBFLUSHTYPE enum. */ +typedef const VMXTLBFLUSHTYPE *PCVMXTLBFLUSHTYPE; + +/** + * VMX controls MSR. + * In accordance with the VT-x spec. + */ +typedef union +{ + struct + { + /** Bits set here -must- be set in the corresponding VM-execution controls. */ + uint32_t allowed0; + /** Bits cleared here -must- be cleared in the corresponding VM-execution + * controls. */ + uint32_t allowed1; + } n; + uint64_t u; +} VMXCTLSMSR; +AssertCompileSize(VMXCTLSMSR, 8); +/** Pointer to a VMXCTLSMSR union. */ +typedef VMXCTLSMSR *PVMXCTLSMSR; +/** Pointer to a const VMXCTLSMSR union. */ +typedef const VMXCTLSMSR *PCVMXCTLSMSR; + +/** + * VMX MSRs. + */ +typedef struct VMXMSRS +{ + /** Basic information. */ + uint64_t u64Basic; + /** Pin-based VM-execution controls. */ + VMXCTLSMSR PinCtls; + /** Processor-based VM-execution controls. */ + VMXCTLSMSR ProcCtls; + /** Secondary processor-based VM-execution controls. */ + VMXCTLSMSR ProcCtls2; + /** VM-exit controls. */ + VMXCTLSMSR ExitCtls; + /** VM-entry controls. */ + VMXCTLSMSR EntryCtls; + /** True pin-based VM-execution controls. */ + VMXCTLSMSR TruePinCtls; + /** True processor-based VM-execution controls. */ + VMXCTLSMSR TrueProcCtls; + /** True VM-entry controls. */ + VMXCTLSMSR TrueEntryCtls; + /** True VM-exit controls. */ + VMXCTLSMSR TrueExitCtls; + /** Miscellaneous data. */ + uint64_t u64Misc; + /** CR0 fixed-0 - bits set here must be set in VMX operation. */ + uint64_t u64Cr0Fixed0; + /** CR0 fixed-1 - bits clear here must be clear in VMX operation. */ + uint64_t u64Cr0Fixed1; + /** CR4 fixed-0 - bits set here must be set in VMX operation. */ + uint64_t u64Cr4Fixed0; + /** CR4 fixed-1 - bits clear here must be clear in VMX operation. */ + uint64_t u64Cr4Fixed1; + /** VMCS enumeration. */ + uint64_t u64VmcsEnum; + /** VM Functions. */ + uint64_t u64VmFunc; + /** EPT, VPID capabilities. */ + uint64_t u64EptVpidCaps; + /** Tertiary processor-based VM-execution controls. */ + uint64_t u64ProcCtls3; + /** Secondary VM-exit controls. */ + uint64_t u64ExitCtls2; + /** Reserved for future. */ + uint64_t a_u64Reserved[8]; +} VMXMSRS; +AssertCompileSizeAlignment(VMXMSRS, 8); +AssertCompileSize(VMXMSRS, 224); +/** Pointer to a VMXMSRS struct. */ +typedef VMXMSRS *PVMXMSRS; +/** Pointer to a const VMXMSRS struct. */ +typedef const VMXMSRS *PCVMXMSRS; + + +/** + * LBR MSRs. + */ +typedef struct LBRMSRS +{ + /** List of LastBranch-From-IP MSRs. */ + uint64_t au64BranchFromIpMsr[32]; + /** List of LastBranch-To-IP MSRs. */ + uint64_t au64BranchToIpMsr[32]; + /** The MSR containing the index to the most recent branch record. */ + uint64_t uBranchTosMsr; +} LBRMSRS; +AssertCompileSizeAlignment(LBRMSRS, 8); +/** Pointer to a VMXMSRS struct. */ +typedef LBRMSRS *PLBRMSRS; +/** Pointer to a const VMXMSRS struct. */ +typedef const LBRMSRS *PCLBRMSRS; + + +/** @name VMX Basic Exit Reasons. + * In accordance with the VT-x spec. + * Update g_aVMExitHandlers if new VM-exit reasons are added. + * @{ + */ +/** Invalid exit code */ +#define VMX_EXIT_INVALID (-1) +/** Exception or non-maskable interrupt (NMI). */ +#define VMX_EXIT_XCPT_OR_NMI 0 +/** External interrupt. */ +#define VMX_EXIT_EXT_INT 1 +/** Triple fault. */ +#define VMX_EXIT_TRIPLE_FAULT 2 +/** INIT signal. */ +#define VMX_EXIT_INIT_SIGNAL 3 +/** Start-up IPI (SIPI). */ +#define VMX_EXIT_SIPI 4 +/** I/O system-management interrupt (SMI). */ +#define VMX_EXIT_IO_SMI 5 +/** Other SMI. */ +#define VMX_EXIT_SMI 6 +/** Interrupt window exiting. */ +#define VMX_EXIT_INT_WINDOW 7 +/** NMI window exiting. */ +#define VMX_EXIT_NMI_WINDOW 8 +/** Task switch. */ +#define VMX_EXIT_TASK_SWITCH 9 +/** CPUID. */ +#define VMX_EXIT_CPUID 10 +/** GETSEC. */ +#define VMX_EXIT_GETSEC 11 +/** HLT. */ +#define VMX_EXIT_HLT 12 +/** INVD. */ +#define VMX_EXIT_INVD 13 +/** INVLPG. */ +#define VMX_EXIT_INVLPG 14 +/** RDPMC. */ +#define VMX_EXIT_RDPMC 15 +/** RDTSC. */ +#define VMX_EXIT_RDTSC 16 +/** RSM in SMM. */ +#define VMX_EXIT_RSM 17 +/** VMCALL. */ +#define VMX_EXIT_VMCALL 18 +/** VMCLEAR. */ +#define VMX_EXIT_VMCLEAR 19 +/** VMLAUNCH. */ +#define VMX_EXIT_VMLAUNCH 20 +/** VMPTRLD. */ +#define VMX_EXIT_VMPTRLD 21 +/** VMPTRST. */ +#define VMX_EXIT_VMPTRST 22 +/** VMREAD. */ +#define VMX_EXIT_VMREAD 23 +/** VMRESUME. */ +#define VMX_EXIT_VMRESUME 24 +/** VMWRITE. */ +#define VMX_EXIT_VMWRITE 25 +/** VMXOFF. */ +#define VMX_EXIT_VMXOFF 26 +/** VMXON. */ +#define VMX_EXIT_VMXON 27 +/** Control-register accesses. */ +#define VMX_EXIT_MOV_CRX 28 +/** Debug-register accesses. */ +#define VMX_EXIT_MOV_DRX 29 +/** I/O instruction. */ +#define VMX_EXIT_IO_INSTR 30 +/** RDMSR. */ +#define VMX_EXIT_RDMSR 31 +/** WRMSR. */ +#define VMX_EXIT_WRMSR 32 +/** VM-entry failure due to invalid guest state. */ +#define VMX_EXIT_ERR_INVALID_GUEST_STATE 33 +/** VM-entry failure due to MSR loading. */ +#define VMX_EXIT_ERR_MSR_LOAD 34 +/** MWAIT. */ +#define VMX_EXIT_MWAIT 36 +/** VM-exit due to monitor trap flag. */ +#define VMX_EXIT_MTF 37 +/** MONITOR. */ +#define VMX_EXIT_MONITOR 39 +/** PAUSE. */ +#define VMX_EXIT_PAUSE 40 +/** VM-entry failure due to machine-check. */ +#define VMX_EXIT_ERR_MACHINE_CHECK 41 +/** TPR below threshold. Guest software executed MOV to CR8. */ +#define VMX_EXIT_TPR_BELOW_THRESHOLD 43 +/** VM-exit due to guest accessing physical address in the APIC-access page. */ +#define VMX_EXIT_APIC_ACCESS 44 +/** VM-exit due to EOI virtualization. */ +#define VMX_EXIT_VIRTUALIZED_EOI 45 +/** Access to GDTR/IDTR using LGDT, LIDT, SGDT or SIDT. */ +#define VMX_EXIT_GDTR_IDTR_ACCESS 46 +/** Access to LDTR/TR due to LLDT, LTR, SLDT, or STR. */ +#define VMX_EXIT_LDTR_TR_ACCESS 47 +/** EPT violation. */ +#define VMX_EXIT_EPT_VIOLATION 48 +/** EPT misconfiguration. */ +#define VMX_EXIT_EPT_MISCONFIG 49 +/** INVEPT. */ +#define VMX_EXIT_INVEPT 50 +/** RDTSCP. */ +#define VMX_EXIT_RDTSCP 51 +/** VMX-preemption timer expired. */ +#define VMX_EXIT_PREEMPT_TIMER 52 +/** INVVPID. */ +#define VMX_EXIT_INVVPID 53 +/** WBINVD. */ +#define VMX_EXIT_WBINVD 54 +/** XSETBV. */ +#define VMX_EXIT_XSETBV 55 +/** Guest completed write to virtual-APIC. */ +#define VMX_EXIT_APIC_WRITE 56 +/** RDRAND. */ +#define VMX_EXIT_RDRAND 57 +/** INVPCID. */ +#define VMX_EXIT_INVPCID 58 +/** VMFUNC. */ +#define VMX_EXIT_VMFUNC 59 +/** ENCLS. */ +#define VMX_EXIT_ENCLS 60 +/** RDSEED. */ +#define VMX_EXIT_RDSEED 61 +/** Page-modification log full. */ +#define VMX_EXIT_PML_FULL 62 +/** XSAVES. */ +#define VMX_EXIT_XSAVES 63 +/** XRSTORS. */ +#define VMX_EXIT_XRSTORS 64 +/** SPP-related event (SPP miss or misconfiguration). */ +#define VMX_EXIT_SPP_EVENT 66 +/* UMWAIT. */ +#define VMX_EXIT_UMWAIT 67 +/** TPAUSE. */ +#define VMX_EXIT_TPAUSE 68 +/** LOADIWKEY. */ +#define VMX_EXIT_LOADIWKEY 69 +/** The maximum VM-exit value (inclusive). */ +#define VMX_EXIT_MAX (VMX_EXIT_LOADIWKEY) +/** @} */ + + +/** @name VM Instruction Errors. + * In accordance with the VT-x spec. + * See Intel spec. "30.4 VM Instruction Error Numbers" + * @{ + */ +typedef enum +{ + /** VMCALL executed in VMX root operation. */ + VMXINSTRERR_VMCALL_VMXROOTMODE = 1, + /** VMCLEAR with invalid physical address. */ + VMXINSTRERR_VMCLEAR_INVALID_PHYSADDR = 2, + /** VMCLEAR with VMXON pointer. */ + VMXINSTRERR_VMCLEAR_VMXON_PTR = 3, + /** VMLAUNCH with non-clear VMCS. */ + VMXINSTRERR_VMLAUNCH_NON_CLEAR_VMCS = 4, + /** VMRESUME with non-launched VMCS. */ + VMXINSTRERR_VMRESUME_NON_LAUNCHED_VMCS = 5, + /** VMRESUME after VMXOFF (VMXOFF and VMXON between VMLAUNCH and VMRESUME). */ + VMXINSTRERR_VMRESUME_AFTER_VMXOFF = 6, + /** VM-entry with invalid control field(s). */ + VMXINSTRERR_VMENTRY_INVALID_CTLS = 7, + /** VM-entry with invalid host-state field(s). */ + VMXINSTRERR_VMENTRY_INVALID_HOST_STATE = 8, + /** VMPTRLD with invalid physical address. */ + VMXINSTRERR_VMPTRLD_INVALID_PHYSADDR = 9, + /** VMPTRLD with VMXON pointer. */ + VMXINSTRERR_VMPTRLD_VMXON_PTR = 10, + /** VMPTRLD with incorrect VMCS revision identifier. */ + VMXINSTRERR_VMPTRLD_INCORRECT_VMCS_REV = 11, + /** VMREAD from unsupported VMCS component. */ + VMXINSTRERR_VMREAD_INVALID_COMPONENT = 12, + /** VMWRITE to unsupported VMCS component. */ + VMXINSTRERR_VMWRITE_INVALID_COMPONENT = 12, + /** VMWRITE to read-only VMCS component. */ + VMXINSTRERR_VMWRITE_RO_COMPONENT = 13, + /** VMXON executed in VMX root operation. */ + VMXINSTRERR_VMXON_IN_VMXROOTMODE = 15, + /** VM-entry with invalid executive-VMCS pointer. */ + VMXINSTRERR_VMENTRY_EXEC_VMCS_INVALID_PTR = 16, + /** VM-entry with non-launched executive VMCS. */ + VMXINSTRERR_VMENTRY_EXEC_VMCS_NON_LAUNCHED = 17, + /** VM-entry with executive-VMCS pointer not VMXON pointer. */ + VMXINSTRERR_VMENTRY_EXEC_VMCS_PTR = 18, + /** VMCALL with non-clear VMCS. */ + VMXINSTRERR_VMCALL_NON_CLEAR_VMCS = 19, + /** VMCALL with invalid VM-exit control fields. */ + VMXINSTRERR_VMCALL_INVALID_EXITCTLS = 20, + /** VMCALL with incorrect MSEG revision identifier. */ + VMXINSTRERR_VMCALL_INVALID_MSEG_ID = 22, + /** VMXOFF under dual-monitor treatment of SMIs and SMM. */ + VMXINSTRERR_VMXOFF_DUAL_MON = 23, + /** VMCALL with invalid SMM-monitor features. */ + VMXINSTRERR_VMCALL_INVALID_SMMCTLS = 24, + /** VM-entry with invalid VM-execution control fields in executive VMCS. */ + VMXINSTRERR_VMENTRY_EXEC_VMCS_INVALID_CTLS = 25, + /** VM-entry with events blocked by MOV SS. */ + VMXINSTRERR_VMENTRY_BLOCK_MOVSS = 26, + /** Invalid operand to INVEPT/INVVPID. */ + VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND = 28 +} VMXINSTRERR; +/** @} */ + + +/** @name VMX abort reasons. + * In accordance with the VT-x spec. + * See Intel spec. "27.7 VMX Aborts". + * Update HMGetVmxAbortDesc() if new reasons are added. + * @{ + */ +typedef enum +{ + /** None - don't use this / uninitialized value. */ + VMXABORT_NONE = 0, + /** VMX abort caused during saving of guest MSRs. */ + VMXABORT_SAVE_GUEST_MSRS = 1, + /** VMX abort caused during host PDPTE checks. */ + VMXBOART_HOST_PDPTE = 2, + /** VMX abort caused due to current VMCS being corrupted. */ + VMXABORT_CURRENT_VMCS_CORRUPT = 3, + /** VMX abort caused during loading of host MSRs. */ + VMXABORT_LOAD_HOST_MSR = 4, + /** VMX abort caused due to a machine-check exception during VM-exit. */ + VMXABORT_MACHINE_CHECK_XCPT = 5, + /** VMX abort caused due to invalid return from long mode. */ + VMXABORT_HOST_NOT_IN_LONG_MODE = 6, + /* Type size hack. */ + VMXABORT_32BIT_HACK = 0x7fffffff +} VMXABORT; +AssertCompileSize(VMXABORT, 4); +/** @} */ + + +/** @name VMX MSR - Basic VMX information. + * @{ + */ +/** VMCS (and related regions) memory type - Uncacheable. */ +#define VMX_BASIC_MEM_TYPE_UC 0 +/** VMCS (and related regions) memory type - Write back. */ +#define VMX_BASIC_MEM_TYPE_WB 6 +/** Width of physical addresses used for VMCS and associated memory regions + * (1=32-bit, 0=processor's physical address width). */ +#define VMX_BASIC_PHYSADDR_WIDTH_32BIT RT_BIT_64(48) + +/** Bit fields for MSR_IA32_VMX_BASIC. */ +/** VMCS revision identifier used by the processor. */ +#define VMX_BF_BASIC_VMCS_ID_SHIFT 0 +#define VMX_BF_BASIC_VMCS_ID_MASK UINT64_C(0x000000007fffffff) +/** Bit 31 is reserved and RAZ. */ +#define VMX_BF_BASIC_RSVD_32_SHIFT 31 +#define VMX_BF_BASIC_RSVD_32_MASK UINT64_C(0x0000000080000000) +/** VMCS size in bytes. */ +#define VMX_BF_BASIC_VMCS_SIZE_SHIFT 32 +#define VMX_BF_BASIC_VMCS_SIZE_MASK UINT64_C(0x00001fff00000000) +/** Bits 45:47 are reserved. */ +#define VMX_BF_BASIC_RSVD_45_47_SHIFT 45 +#define VMX_BF_BASIC_RSVD_45_47_MASK UINT64_C(0x0000e00000000000) +/** Width of physical addresses used for the VMCS and associated memory regions + * (always 0 on CPUs that support Intel 64 architecture). */ +#define VMX_BF_BASIC_PHYSADDR_WIDTH_SHIFT 48 +#define VMX_BF_BASIC_PHYSADDR_WIDTH_MASK UINT64_C(0x0001000000000000) +/** Dual-monitor treatment of SMI and SMM supported. */ +#define VMX_BF_BASIC_DUAL_MON_SHIFT 49 +#define VMX_BF_BASIC_DUAL_MON_MASK UINT64_C(0x0002000000000000) +/** Memory type that must be used for the VMCS and associated memory regions. */ +#define VMX_BF_BASIC_VMCS_MEM_TYPE_SHIFT 50 +#define VMX_BF_BASIC_VMCS_MEM_TYPE_MASK UINT64_C(0x003c000000000000) +/** VM-exit instruction information for INS/OUTS. */ +#define VMX_BF_BASIC_VMCS_INS_OUTS_SHIFT 54 +#define VMX_BF_BASIC_VMCS_INS_OUTS_MASK UINT64_C(0x0040000000000000) +/** Whether 'true' VMX controls MSRs are supported for handling of default1 class + * bits in VMX control MSRs. */ +#define VMX_BF_BASIC_TRUE_CTLS_SHIFT 55 +#define VMX_BF_BASIC_TRUE_CTLS_MASK UINT64_C(0x0080000000000000) +/** Whether VM-entry can delivery error code for all hardware exception vectors. */ +#define VMX_BF_BASIC_XCPT_ERRCODE_SHIFT 56 +#define VMX_BF_BASIC_XCPT_ERRCODE_MASK UINT64_C(0x0100000000000000) +/** Bits 57:63 are reserved and RAZ. */ +#define VMX_BF_BASIC_RSVD_56_63_SHIFT 57 +#define VMX_BF_BASIC_RSVD_56_63_MASK UINT64_C(0xfe00000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_BASIC_, UINT64_C(0), UINT64_MAX, + (VMCS_ID, RSVD_32, VMCS_SIZE, RSVD_45_47, PHYSADDR_WIDTH, DUAL_MON, VMCS_MEM_TYPE, + VMCS_INS_OUTS, TRUE_CTLS, XCPT_ERRCODE, RSVD_56_63)); +/** @} */ + + +/** @name VMX MSR - Miscellaneous data. + * @{ + */ +/** Whether VM-exit stores EFER.LMA into the "IA32e mode guest" field. */ +#define VMX_MISC_EXIT_SAVE_EFER_LMA RT_BIT(5) +/** Whether Intel PT is supported in VMX operation. */ +#define VMX_MISC_INTEL_PT RT_BIT(14) +/** Whether VMWRITE to any valid VMCS field incl. read-only fields, otherwise + * VMWRITE cannot modify read-only VM-exit information fields. */ +#define VMX_MISC_VMWRITE_ALL RT_BIT(29) +/** Whether VM-entry can inject software interrupts, INT1 (ICEBP) with 0-length + * instructions. */ +#define VMX_MISC_ENTRY_INJECT_SOFT_INT RT_BIT(30) +/** Maximum number of MSRs in the auto-load/store MSR areas, (n+1) * 512. */ +#define VMX_MISC_MAX_MSRS(a_MiscMsr) (512 * (RT_BF_GET((a_MiscMsr), VMX_BF_MISC_MAX_MSRS) + 1)) +/** Maximum CR3-target count supported by the CPU. */ +#define VMX_MISC_CR3_TARGET_COUNT(a_MiscMsr) (((a) >> 16) & 0xff) + +/** Bit fields for MSR_IA32_VMX_MISC. */ +/** Relationship between the preemption timer and tsc. */ +#define VMX_BF_MISC_PREEMPT_TIMER_TSC_SHIFT 0 +#define VMX_BF_MISC_PREEMPT_TIMER_TSC_MASK UINT64_C(0x000000000000001f) +/** Whether VM-exit stores EFER.LMA into the "IA32e mode guest" field. */ +#define VMX_BF_MISC_EXIT_SAVE_EFER_LMA_SHIFT 5 +#define VMX_BF_MISC_EXIT_SAVE_EFER_LMA_MASK UINT64_C(0x0000000000000020) +/** Activity states supported by the implementation. */ +#define VMX_BF_MISC_ACTIVITY_STATES_SHIFT 6 +#define VMX_BF_MISC_ACTIVITY_STATES_MASK UINT64_C(0x00000000000001c0) +/** Bits 9:13 is reserved and RAZ. */ +#define VMX_BF_MISC_RSVD_9_13_SHIFT 9 +#define VMX_BF_MISC_RSVD_9_13_MASK UINT64_C(0x0000000000003e00) +/** Whether Intel PT (Processor Trace) can be used in VMX operation. */ +#define VMX_BF_MISC_INTEL_PT_SHIFT 14 +#define VMX_BF_MISC_INTEL_PT_MASK UINT64_C(0x0000000000004000) +/** Whether RDMSR can be used to read IA32_SMBASE MSR in SMM. */ +#define VMX_BF_MISC_SMM_READ_SMBASE_MSR_SHIFT 15 +#define VMX_BF_MISC_SMM_READ_SMBASE_MSR_MASK UINT64_C(0x0000000000008000) +/** Number of CR3 target values supported by the processor. (0-256) */ +#define VMX_BF_MISC_CR3_TARGET_SHIFT 16 +#define VMX_BF_MISC_CR3_TARGET_MASK UINT64_C(0x0000000001ff0000) +/** Maximum number of MSRs in the VMCS. */ +#define VMX_BF_MISC_MAX_MSRS_SHIFT 25 +#define VMX_BF_MISC_MAX_MSRS_MASK UINT64_C(0x000000000e000000) +/** Whether IA32_SMM_MONITOR_CTL MSR can be modified to allow VMXOFF to block + * SMIs. */ +#define VMX_BF_MISC_VMXOFF_BLOCK_SMI_SHIFT 28 +#define VMX_BF_MISC_VMXOFF_BLOCK_SMI_MASK UINT64_C(0x0000000010000000) +/** Whether VMWRITE to any valid VMCS field incl. read-only fields, otherwise + * VMWRITE cannot modify read-only VM-exit information fields. */ +#define VMX_BF_MISC_VMWRITE_ALL_SHIFT 29 +#define VMX_BF_MISC_VMWRITE_ALL_MASK UINT64_C(0x0000000020000000) +/** Whether VM-entry can inject software interrupts, INT1 (ICEBP) with 0-length + * instructions. */ +#define VMX_BF_MISC_ENTRY_INJECT_SOFT_INT_SHIFT 30 +#define VMX_BF_MISC_ENTRY_INJECT_SOFT_INT_MASK UINT64_C(0x0000000040000000) +/** Bit 31 is reserved and RAZ. */ +#define VMX_BF_MISC_RSVD_31_SHIFT 31 +#define VMX_BF_MISC_RSVD_31_MASK UINT64_C(0x0000000080000000) +/** 32-bit MSEG revision ID used by the processor. */ +#define VMX_BF_MISC_MSEG_ID_SHIFT 32 +#define VMX_BF_MISC_MSEG_ID_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_MISC_, UINT64_C(0), UINT64_MAX, + (PREEMPT_TIMER_TSC, EXIT_SAVE_EFER_LMA, ACTIVITY_STATES, RSVD_9_13, INTEL_PT, SMM_READ_SMBASE_MSR, + CR3_TARGET, MAX_MSRS, VMXOFF_BLOCK_SMI, VMWRITE_ALL, ENTRY_INJECT_SOFT_INT, RSVD_31, MSEG_ID)); +/** @} */ + +/** @name VMX MSR - VMCS enumeration. + * Bit fields for MSR_IA32_VMX_VMCS_ENUM. + * @{ + */ +/** Bit 0 is reserved and RAZ. */ +#define VMX_BF_VMCS_ENUM_RSVD_0_SHIFT 0 +#define VMX_BF_VMCS_ENUM_RSVD_0_MASK UINT64_C(0x0000000000000001) +/** Highest index value used in VMCS field encoding. */ +#define VMX_BF_VMCS_ENUM_HIGHEST_IDX_SHIFT 1 +#define VMX_BF_VMCS_ENUM_HIGHEST_IDX_MASK UINT64_C(0x00000000000003fe) +/** Bit 10:63 is reserved and RAZ. */ +#define VMX_BF_VMCS_ENUM_RSVD_10_63_SHIFT 10 +#define VMX_BF_VMCS_ENUM_RSVD_10_63_MASK UINT64_C(0xfffffffffffffc00) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_VMCS_ENUM_, UINT64_C(0), UINT64_MAX, + (RSVD_0, HIGHEST_IDX, RSVD_10_63)); +/** @} */ + + +/** @name VMX MSR - VM Functions. + * Bit fields for MSR_IA32_VMX_VMFUNC. + * @{ + */ +/** EPTP-switching function changes the value of the EPTP to one chosen from the EPTP list. */ +#define VMX_BF_VMFUNC_EPTP_SWITCHING_SHIFT 0 +#define VMX_BF_VMFUNC_EPTP_SWITCHING_MASK UINT64_C(0x0000000000000001) +/** Bits 1:63 are reserved and RAZ. */ +#define VMX_BF_VMFUNC_RSVD_1_63_SHIFT 1 +#define VMX_BF_VMFUNC_RSVD_1_63_MASK UINT64_C(0xfffffffffffffffe) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_VMFUNC_, UINT64_C(0), UINT64_MAX, + (EPTP_SWITCHING, RSVD_1_63)); +/** @} */ + + +/** @name VMX MSR - EPT/VPID capabilities. + * @{ + */ +/** Supports execute-only translations by EPT. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_RWX_X_ONLY RT_BIT_64(0) +/** Supports page-walk length of 4. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_4 RT_BIT_64(6) +/** Supports page-walk length of 5. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_5 RT_BIT_64(7) +/** Supports EPT paging-structure memory type to be uncacheable. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_MEMTYPE_UC RT_BIT_64(8) +/** Supports EPT paging structure memory type to be write-back. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_MEMTYPE_WB RT_BIT_64(14) +/** Supports EPT PDE to map a 2 MB page. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_PDE_2M RT_BIT_64(16) +/** Supports EPT PDPTE to map a 1 GB page. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_PDPTE_1G RT_BIT_64(17) +/** Supports INVEPT instruction. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVEPT RT_BIT_64(20) +/** Supports accessed and dirty flags for EPT. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_ACCESS_DIRTY RT_BIT_64(21) +/** Supports advanced VM-exit info. for EPT violations. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_ADVEXITINFO_EPT_VIOLATION RT_BIT_64(22) +/** Supports supervisor shadow-stack control. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_SUPER_SHW_STACK RT_BIT_64(23) +/** Supports single-context INVEPT type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_SINGLE_CONTEXT RT_BIT_64(25) +/** Supports all-context INVEPT type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS RT_BIT_64(26) +/** Supports INVVPID instruction. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVVPID RT_BIT_64(32) +/** Supports individual-address INVVPID type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR RT_BIT_64(40) +/** Supports single-context INVVPID type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT RT_BIT_64(41) +/** Supports all-context INVVPID type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_ALL_CONTEXTS RT_BIT_64(42) +/** Supports singe-context-retaining-globals INVVPID type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT_RETAIN_GLOBALS RT_BIT_64(43) + +/** Bit fields for MSR_IA32_VMX_EPT_VPID_CAP. */ +#define VMX_BF_EPT_VPID_CAP_EXEC_ONLY_SHIFT 0 +#define VMX_BF_EPT_VPID_CAP_EXEC_ONLY_MASK UINT64_C(0x0000000000000001) +#define VMX_BF_EPT_VPID_CAP_RSVD_1_5_SHIFT 1 +#define VMX_BF_EPT_VPID_CAP_RSVD_1_5_MASK UINT64_C(0x000000000000003e) +#define VMX_BF_EPT_VPID_CAP_PAGE_WALK_LENGTH_4_SHIFT 6 +#define VMX_BF_EPT_VPID_CAP_PAGE_WALK_LENGTH_4_MASK UINT64_C(0x0000000000000040) +#define VMX_BF_EPT_VPID_CAP_RSVD_7_SHIFT 7 +#define VMX_BF_EPT_VPID_CAP_RSVD_7_MASK UINT64_C(0x0000000000000080) +#define VMX_BF_EPT_VPID_CAP_MEMTYPE_UC_SHIFT 8 +#define VMX_BF_EPT_VPID_CAP_MEMTYPE_UC_MASK UINT64_C(0x0000000000000100) +#define VMX_BF_EPT_VPID_CAP_RSVD_9_13_SHIFT 9 +#define VMX_BF_EPT_VPID_CAP_RSVD_9_13_MASK UINT64_C(0x0000000000003e00) +#define VMX_BF_EPT_VPID_CAP_MEMTYPE_WB_SHIFT 14 +#define VMX_BF_EPT_VPID_CAP_MEMTYPE_WB_MASK UINT64_C(0x0000000000004000) +#define VMX_BF_EPT_VPID_CAP_RSVD_15_SHIFT 15 +#define VMX_BF_EPT_VPID_CAP_RSVD_15_MASK UINT64_C(0x0000000000008000) +#define VMX_BF_EPT_VPID_CAP_PDE_2M_SHIFT 16 +#define VMX_BF_EPT_VPID_CAP_PDE_2M_MASK UINT64_C(0x0000000000010000) +#define VMX_BF_EPT_VPID_CAP_PDPTE_1G_SHIFT 17 +#define VMX_BF_EPT_VPID_CAP_PDPTE_1G_MASK UINT64_C(0x0000000000020000) +#define VMX_BF_EPT_VPID_CAP_RSVD_18_19_SHIFT 18 +#define VMX_BF_EPT_VPID_CAP_RSVD_18_19_MASK UINT64_C(0x00000000000c0000) +#define VMX_BF_EPT_VPID_CAP_INVEPT_SHIFT 20 +#define VMX_BF_EPT_VPID_CAP_INVEPT_MASK UINT64_C(0x0000000000100000) +#define VMX_BF_EPT_VPID_CAP_ACCESS_DIRTY_SHIFT 21 +#define VMX_BF_EPT_VPID_CAP_ACCESS_DIRTY_MASK UINT64_C(0x0000000000200000) +#define VMX_BF_EPT_VPID_CAP_ADVEXITINFO_EPT_VIOLATION_SHIFT 22 +#define VMX_BF_EPT_VPID_CAP_ADVEXITINFO_EPT_VIOLATION_MASK UINT64_C(0x0000000000400000) +#define VMX_BF_EPT_VPID_CAP_SUPER_SHW_STACK_SHIFT 23 +#define VMX_BF_EPT_VPID_CAP_SUPER_SHW_STACK_MASK UINT64_C(0x0000000000800000) +#define VMX_BF_EPT_VPID_CAP_RSVD_24_SHIFT 24 +#define VMX_BF_EPT_VPID_CAP_RSVD_24_MASK UINT64_C(0x0000000001000000) +#define VMX_BF_EPT_VPID_CAP_INVEPT_SINGLE_CTX_SHIFT 25 +#define VMX_BF_EPT_VPID_CAP_INVEPT_SINGLE_CTX_MASK UINT64_C(0x0000000002000000) +#define VMX_BF_EPT_VPID_CAP_INVEPT_ALL_CTX_SHIFT 26 +#define VMX_BF_EPT_VPID_CAP_INVEPT_ALL_CTX_MASK UINT64_C(0x0000000004000000) +#define VMX_BF_EPT_VPID_CAP_RSVD_27_31_SHIFT 27 +#define VMX_BF_EPT_VPID_CAP_RSVD_27_31_MASK UINT64_C(0x00000000f8000000) +#define VMX_BF_EPT_VPID_CAP_INVVPID_SHIFT 32 +#define VMX_BF_EPT_VPID_CAP_INVVPID_MASK UINT64_C(0x0000000100000000) +#define VMX_BF_EPT_VPID_CAP_RSVD_33_39_SHIFT 33 +#define VMX_BF_EPT_VPID_CAP_RSVD_33_39_MASK UINT64_C(0x000000fe00000000) +#define VMX_BF_EPT_VPID_CAP_INVVPID_INDIV_ADDR_SHIFT 40 +#define VMX_BF_EPT_VPID_CAP_INVVPID_INDIV_ADDR_MASK UINT64_C(0x0000010000000000) +#define VMX_BF_EPT_VPID_CAP_INVVPID_SINGLE_CTX_SHIFT 41 +#define VMX_BF_EPT_VPID_CAP_INVVPID_SINGLE_CTX_MASK UINT64_C(0x0000020000000000) +#define VMX_BF_EPT_VPID_CAP_INVVPID_ALL_CTX_SHIFT 42 +#define VMX_BF_EPT_VPID_CAP_INVVPID_ALL_CTX_MASK UINT64_C(0x0000040000000000) +#define VMX_BF_EPT_VPID_CAP_INVVPID_SINGLE_CTX_RETAIN_GLOBALS_SHIFT 43 +#define VMX_BF_EPT_VPID_CAP_INVVPID_SINGLE_CTX_RETAIN_GLOBALS_MASK UINT64_C(0x0000080000000000) +#define VMX_BF_EPT_VPID_CAP_RSVD_44_63_SHIFT 44 +#define VMX_BF_EPT_VPID_CAP_RSVD_44_63_MASK UINT64_C(0xfffff00000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EPT_VPID_CAP_, UINT64_C(0), UINT64_MAX, + (EXEC_ONLY, RSVD_1_5, PAGE_WALK_LENGTH_4, RSVD_7, MEMTYPE_UC, RSVD_9_13, MEMTYPE_WB, RSVD_15, PDE_2M, + PDPTE_1G, RSVD_18_19, INVEPT, ACCESS_DIRTY, ADVEXITINFO_EPT_VIOLATION, SUPER_SHW_STACK, RSVD_24, + INVEPT_SINGLE_CTX, INVEPT_ALL_CTX, RSVD_27_31, INVVPID, RSVD_33_39, INVVPID_INDIV_ADDR, + INVVPID_SINGLE_CTX, INVVPID_ALL_CTX, INVVPID_SINGLE_CTX_RETAIN_GLOBALS, RSVD_44_63)); +/** @} */ + + +/** @name Extended Page Table Pointer (EPTP) + * In accordance with the VT-x spec. + * See Intel spec. 23.6.11 "Extended-Page-Table Pointer (EPTP)". + * @{ + */ +/** EPTP memory type: Uncachable. */ +#define VMX_EPTP_MEMTYPE_UC 0 +/** EPTP memory type: Write Back. */ +#define VMX_EPTP_MEMTYPE_WB 6 +/** Page-walk length for PML4 (4-level paging). */ +#define VMX_EPTP_PAGE_WALK_LENGTH_4 3 + +/** Bit fields for EPTP. */ +#define VMX_BF_EPTP_MEMTYPE_SHIFT 0 +#define VMX_BF_EPTP_MEMTYPE_MASK UINT64_C(0x0000000000000007) +#define VMX_BF_EPTP_PAGE_WALK_LENGTH_SHIFT 3 +#define VMX_BF_EPTP_PAGE_WALK_LENGTH_MASK UINT64_C(0x0000000000000038) +#define VMX_BF_EPTP_ACCESS_DIRTY_SHIFT 6 +#define VMX_BF_EPTP_ACCESS_DIRTY_MASK UINT64_C(0x0000000000000040) +#define VMX_BF_EPTP_SUPER_SHW_STACK_SHIFT 7 +#define VMX_BF_EPTP_SUPER_SHW_STACK_MASK UINT64_C(0x0000000000000080) +#define VMX_BF_EPTP_RSVD_8_11_SHIFT 8 +#define VMX_BF_EPTP_RSVD_8_11_MASK UINT64_C(0x0000000000000f00) +#define VMX_BF_EPTP_PML4_TABLE_ADDR_SHIFT 12 +#define VMX_BF_EPTP_PML4_TABLE_ADDR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EPTP_, UINT64_C(0), UINT64_MAX, + (MEMTYPE, PAGE_WALK_LENGTH, ACCESS_DIRTY, SUPER_SHW_STACK, RSVD_8_11, PML4_TABLE_ADDR)); + +/* Mask of valid EPTP bits sans physically non-addressable bits. */ +#define VMX_EPTP_VALID_MASK ( VMX_BF_EPTP_MEMTYPE_MASK \ + | VMX_BF_EPTP_PAGE_WALK_LENGTH_MASK \ + | VMX_BF_EPTP_ACCESS_DIRTY_MASK \ + | VMX_BF_EPTP_SUPER_SHW_STACK_MASK \ + | VMX_BF_EPTP_PML4_TABLE_ADDR_MASK) +/** @} */ + + +/** @name VMCS fields and encoding. + * + * When adding a new field: + * - Always add it to g_aVmcsFields. + * - Consider if it needs to be added to VMXVVMCS. + * @{ + */ +/** 16-bit control fields. */ +#define VMX_VMCS16_VPID 0x0000 +#define VMX_VMCS16_POSTED_INT_NOTIFY_VECTOR 0x0002 +#define VMX_VMCS16_EPTP_INDEX 0x0004 +#define VMX_VMCS16_HLAT_PREFIX_SIZE 0x0006 + +/** 16-bit guest-state fields. */ +#define VMX_VMCS16_GUEST_ES_SEL 0x0800 +#define VMX_VMCS16_GUEST_CS_SEL 0x0802 +#define VMX_VMCS16_GUEST_SS_SEL 0x0804 +#define VMX_VMCS16_GUEST_DS_SEL 0x0806 +#define VMX_VMCS16_GUEST_FS_SEL 0x0808 +#define VMX_VMCS16_GUEST_GS_SEL 0x080a +#define VMX_VMCS16_GUEST_LDTR_SEL 0x080c +#define VMX_VMCS16_GUEST_TR_SEL 0x080e +#define VMX_VMCS16_GUEST_INTR_STATUS 0x0810 +#define VMX_VMCS16_GUEST_PML_INDEX 0x0812 + +/** 16-bits host-state fields. */ +#define VMX_VMCS16_HOST_ES_SEL 0x0c00 +#define VMX_VMCS16_HOST_CS_SEL 0x0c02 +#define VMX_VMCS16_HOST_SS_SEL 0x0c04 +#define VMX_VMCS16_HOST_DS_SEL 0x0c06 +#define VMX_VMCS16_HOST_FS_SEL 0x0c08 +#define VMX_VMCS16_HOST_GS_SEL 0x0c0a +#define VMX_VMCS16_HOST_TR_SEL 0x0c0c + +/** 64-bit control fields. */ +#define VMX_VMCS64_CTRL_IO_BITMAP_A_FULL 0x2000 +#define VMX_VMCS64_CTRL_IO_BITMAP_A_HIGH 0x2001 +#define VMX_VMCS64_CTRL_IO_BITMAP_B_FULL 0x2002 +#define VMX_VMCS64_CTRL_IO_BITMAP_B_HIGH 0x2003 +#define VMX_VMCS64_CTRL_MSR_BITMAP_FULL 0x2004 +#define VMX_VMCS64_CTRL_MSR_BITMAP_HIGH 0x2005 +#define VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL 0x2006 +#define VMX_VMCS64_CTRL_EXIT_MSR_STORE_HIGH 0x2007 +#define VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL 0x2008 +#define VMX_VMCS64_CTRL_EXIT_MSR_LOAD_HIGH 0x2009 +#define VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL 0x200a +#define VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_HIGH 0x200b +#define VMX_VMCS64_CTRL_EXEC_VMCS_PTR_FULL 0x200c +#define VMX_VMCS64_CTRL_EXEC_VMCS_PTR_HIGH 0x200d +#define VMX_VMCS64_CTRL_EXEC_PML_ADDR_FULL 0x200e +#define VMX_VMCS64_CTRL_EXEC_PML_ADDR_HIGH 0x200f +#define VMX_VMCS64_CTRL_TSC_OFFSET_FULL 0x2010 +#define VMX_VMCS64_CTRL_TSC_OFFSET_HIGH 0x2011 +#define VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL 0x2012 +#define VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_HIGH 0x2013 +#define VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL 0x2014 +#define VMX_VMCS64_CTRL_APIC_ACCESSADDR_HIGH 0x2015 +#define VMX_VMCS64_CTRL_POSTED_INTR_DESC_FULL 0x2016 +#define VMX_VMCS64_CTRL_POSTED_INTR_DESC_HIGH 0x2017 +#define VMX_VMCS64_CTRL_VMFUNC_CTRLS_FULL 0x2018 +#define VMX_VMCS64_CTRL_VMFUNC_CTRLS_HIGH 0x2019 +#define VMX_VMCS64_CTRL_EPTP_FULL 0x201a +#define VMX_VMCS64_CTRL_EPTP_HIGH 0x201b +#define VMX_VMCS64_CTRL_EOI_BITMAP_0_FULL 0x201c +#define VMX_VMCS64_CTRL_EOI_BITMAP_0_HIGH 0x201d +#define VMX_VMCS64_CTRL_EOI_BITMAP_1_FULL 0x201e +#define VMX_VMCS64_CTRL_EOI_BITMAP_1_HIGH 0x201f +#define VMX_VMCS64_CTRL_EOI_BITMAP_2_FULL 0x2020 +#define VMX_VMCS64_CTRL_EOI_BITMAP_2_HIGH 0x2021 +#define VMX_VMCS64_CTRL_EOI_BITMAP_3_FULL 0x2022 +#define VMX_VMCS64_CTRL_EOI_BITMAP_3_HIGH 0x2023 +#define VMX_VMCS64_CTRL_EPTP_LIST_FULL 0x2024 +#define VMX_VMCS64_CTRL_EPTP_LIST_HIGH 0x2025 +#define VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL 0x2026 +#define VMX_VMCS64_CTRL_VMREAD_BITMAP_HIGH 0x2027 +#define VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL 0x2028 +#define VMX_VMCS64_CTRL_VMWRITE_BITMAP_HIGH 0x2029 +#define VMX_VMCS64_CTRL_VE_XCPT_INFO_ADDR_FULL 0x202a +#define VMX_VMCS64_CTRL_VE_XCPT_INFO_ADDR_HIGH 0x202b +#define VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_FULL 0x202c +#define VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_HIGH 0x202d +#define VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_FULL 0x202e +#define VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_HIGH 0x202f +#define VMX_VMCS64_CTRL_SPPTP_FULL 0x2030 +#define VMX_VMCS64_CTRL_SPPTP_HIGH 0x2031 +#define VMX_VMCS64_CTRL_TSC_MULTIPLIER_FULL 0x2032 +#define VMX_VMCS64_CTRL_TSC_MULTIPLIER_HIGH 0x2033 +#define VMX_VMCS64_CTRL_PROC_EXEC3_FULL 0x2034 +#define VMX_VMCS64_CTRL_PROC_EXEC3_HIGH 0x2035 +#define VMX_VMCS64_CTRL_ENCLV_EXITING_BITMAP_FULL 0x2036 +#define VMX_VMCS64_CTRL_ENCLV_EXITING_BITMAP_HIGH 0x2037 +#define VMX_VMCS64_CTRL_PCONFIG_EXITING_BITMAP_FULL 0x203e +#define VMX_VMCS64_CTRL_PCONFIG_EXITING_BITMAP_HIGH 0x203f +#define VMX_VMCS64_CTRL_HLAT_PTR_FULL 0x2040 +#define VMX_VMCS64_CTRL_HLAT_PTR_HIGH 0x2041 +#define VMX_VMCS64_CTRL_EXIT2_FULL 0x2044 +#define VMX_VMCS64_CTRL_EXIT2_HIGH 0x2045 + +/** 64-bit read-only data fields. */ +#define VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL 0x2400 +#define VMX_VMCS64_RO_GUEST_PHYS_ADDR_HIGH 0x2401 + +/** 64-bit guest-state fields. */ +#define VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL 0x2800 +#define VMX_VMCS64_GUEST_VMCS_LINK_PTR_HIGH 0x2801 +#define VMX_VMCS64_GUEST_DEBUGCTL_FULL 0x2802 +#define VMX_VMCS64_GUEST_DEBUGCTL_HIGH 0x2803 +#define VMX_VMCS64_GUEST_PAT_FULL 0x2804 +#define VMX_VMCS64_GUEST_PAT_HIGH 0x2805 +#define VMX_VMCS64_GUEST_EFER_FULL 0x2806 +#define VMX_VMCS64_GUEST_EFER_HIGH 0x2807 +#define VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL 0x2808 +#define VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_HIGH 0x2809 +#define VMX_VMCS64_GUEST_PDPTE0_FULL 0x280a +#define VMX_VMCS64_GUEST_PDPTE0_HIGH 0x280b +#define VMX_VMCS64_GUEST_PDPTE1_FULL 0x280c +#define VMX_VMCS64_GUEST_PDPTE1_HIGH 0x280d +#define VMX_VMCS64_GUEST_PDPTE2_FULL 0x280e +#define VMX_VMCS64_GUEST_PDPTE2_HIGH 0x280f +#define VMX_VMCS64_GUEST_PDPTE3_FULL 0x2810 +#define VMX_VMCS64_GUEST_PDPTE3_HIGH 0x2811 +#define VMX_VMCS64_GUEST_BNDCFGS_FULL 0x2812 +#define VMX_VMCS64_GUEST_BNDCFGS_HIGH 0x2813 +#define VMX_VMCS64_GUEST_RTIT_CTL_FULL 0x2814 +#define VMX_VMCS64_GUEST_RTIT_CTL_HIGH 0x2815 +#define VMX_VMCS64_GUEST_PKRS_FULL 0x2818 +#define VMX_VMCS64_GUEST_PKRS_HIGH 0x2819 + +/** 64-bit host-state fields. */ +#define VMX_VMCS64_HOST_PAT_FULL 0x2c00 +#define VMX_VMCS64_HOST_PAT_HIGH 0x2c01 +#define VMX_VMCS64_HOST_EFER_FULL 0x2c02 +#define VMX_VMCS64_HOST_EFER_HIGH 0x2c03 +#define VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_FULL 0x2c04 +#define VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_HIGH 0x2c05 +#define VMX_VMCS64_HOST_PKRS_FULL 0x2c06 +#define VMX_VMCS64_HOST_PKRS_HIGH 0x2c07 + +/** 32-bit control fields. */ +#define VMX_VMCS32_CTRL_PIN_EXEC 0x4000 +#define VMX_VMCS32_CTRL_PROC_EXEC 0x4002 +#define VMX_VMCS32_CTRL_EXCEPTION_BITMAP 0x4004 +#define VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK 0x4006 +#define VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH 0x4008 +#define VMX_VMCS32_CTRL_CR3_TARGET_COUNT 0x400a +#define VMX_VMCS32_CTRL_EXIT 0x400c +#define VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT 0x400e +#define VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT 0x4010 +#define VMX_VMCS32_CTRL_ENTRY 0x4012 +#define VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT 0x4014 +#define VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO 0x4016 +#define VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE 0x4018 +#define VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH 0x401a +#define VMX_VMCS32_CTRL_TPR_THRESHOLD 0x401c +#define VMX_VMCS32_CTRL_PROC_EXEC2 0x401e +#define VMX_VMCS32_CTRL_PLE_GAP 0x4020 +#define VMX_VMCS32_CTRL_PLE_WINDOW 0x4022 + +/** 32-bits read-only fields. */ +#define VMX_VMCS32_RO_VM_INSTR_ERROR 0x4400 +#define VMX_VMCS32_RO_EXIT_REASON 0x4402 +#define VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO 0x4404 +#define VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE 0x4406 +#define VMX_VMCS32_RO_IDT_VECTORING_INFO 0x4408 +#define VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE 0x440a +#define VMX_VMCS32_RO_EXIT_INSTR_LENGTH 0x440c +#define VMX_VMCS32_RO_EXIT_INSTR_INFO 0x440e + +/** 32-bit guest-state fields. */ +#define VMX_VMCS32_GUEST_ES_LIMIT 0x4800 +#define VMX_VMCS32_GUEST_CS_LIMIT 0x4802 +#define VMX_VMCS32_GUEST_SS_LIMIT 0x4804 +#define VMX_VMCS32_GUEST_DS_LIMIT 0x4806 +#define VMX_VMCS32_GUEST_FS_LIMIT 0x4808 +#define VMX_VMCS32_GUEST_GS_LIMIT 0x480a +#define VMX_VMCS32_GUEST_LDTR_LIMIT 0x480c +#define VMX_VMCS32_GUEST_TR_LIMIT 0x480e +#define VMX_VMCS32_GUEST_GDTR_LIMIT 0x4810 +#define VMX_VMCS32_GUEST_IDTR_LIMIT 0x4812 +#define VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS 0x4814 +#define VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS 0x4816 +#define VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS 0x4818 +#define VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS 0x481a +#define VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS 0x481c +#define VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS 0x481e +#define VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS 0x4820 +#define VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS 0x4822 +#define VMX_VMCS32_GUEST_INT_STATE 0x4824 +#define VMX_VMCS32_GUEST_ACTIVITY_STATE 0x4826 +#define VMX_VMCS32_GUEST_SMBASE 0x4828 +#define VMX_VMCS32_GUEST_SYSENTER_CS 0x482a +#define VMX_VMCS32_PREEMPT_TIMER_VALUE 0x482e + +/** 32-bit host-state fields. */ +#define VMX_VMCS32_HOST_SYSENTER_CS 0x4C00 + +/** Natural-width control fields. */ +#define VMX_VMCS_CTRL_CR0_MASK 0x6000 +#define VMX_VMCS_CTRL_CR4_MASK 0x6002 +#define VMX_VMCS_CTRL_CR0_READ_SHADOW 0x6004 +#define VMX_VMCS_CTRL_CR4_READ_SHADOW 0x6006 +#define VMX_VMCS_CTRL_CR3_TARGET_VAL0 0x6008 +#define VMX_VMCS_CTRL_CR3_TARGET_VAL1 0x600a +#define VMX_VMCS_CTRL_CR3_TARGET_VAL2 0x600c +#define VMX_VMCS_CTRL_CR3_TARGET_VAL3 0x600e + +/** Natural-width read-only data fields. */ +#define VMX_VMCS_RO_EXIT_QUALIFICATION 0x6400 +#define VMX_VMCS_RO_IO_RCX 0x6402 +#define VMX_VMCS_RO_IO_RSI 0x6404 +#define VMX_VMCS_RO_IO_RDI 0x6406 +#define VMX_VMCS_RO_IO_RIP 0x6408 +#define VMX_VMCS_RO_GUEST_LINEAR_ADDR 0x640a + +/** Natural-width guest-state fields. */ +#define VMX_VMCS_GUEST_CR0 0x6800 +#define VMX_VMCS_GUEST_CR3 0x6802 +#define VMX_VMCS_GUEST_CR4 0x6804 +#define VMX_VMCS_GUEST_ES_BASE 0x6806 +#define VMX_VMCS_GUEST_CS_BASE 0x6808 +#define VMX_VMCS_GUEST_SS_BASE 0x680a +#define VMX_VMCS_GUEST_DS_BASE 0x680c +#define VMX_VMCS_GUEST_FS_BASE 0x680e +#define VMX_VMCS_GUEST_GS_BASE 0x6810 +#define VMX_VMCS_GUEST_LDTR_BASE 0x6812 +#define VMX_VMCS_GUEST_TR_BASE 0x6814 +#define VMX_VMCS_GUEST_GDTR_BASE 0x6816 +#define VMX_VMCS_GUEST_IDTR_BASE 0x6818 +#define VMX_VMCS_GUEST_DR7 0x681a +#define VMX_VMCS_GUEST_RSP 0x681c +#define VMX_VMCS_GUEST_RIP 0x681e +#define VMX_VMCS_GUEST_RFLAGS 0x6820 +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS 0x6822 +#define VMX_VMCS_GUEST_SYSENTER_ESP 0x6824 +#define VMX_VMCS_GUEST_SYSENTER_EIP 0x6826 +#define VMX_VMCS_GUEST_S_CET 0x6828 +#define VMX_VMCS_GUEST_SSP 0x682a +#define VMX_VMCS_GUEST_INTR_SSP_TABLE_ADDR 0x682c + +/** Natural-width host-state fields. */ +#define VMX_VMCS_HOST_CR0 0x6c00 +#define VMX_VMCS_HOST_CR3 0x6c02 +#define VMX_VMCS_HOST_CR4 0x6c04 +#define VMX_VMCS_HOST_FS_BASE 0x6c06 +#define VMX_VMCS_HOST_GS_BASE 0x6c08 +#define VMX_VMCS_HOST_TR_BASE 0x6c0a +#define VMX_VMCS_HOST_GDTR_BASE 0x6c0c +#define VMX_VMCS_HOST_IDTR_BASE 0x6c0e +#define VMX_VMCS_HOST_SYSENTER_ESP 0x6c10 +#define VMX_VMCS_HOST_SYSENTER_EIP 0x6c12 +#define VMX_VMCS_HOST_RSP 0x6c14 +#define VMX_VMCS_HOST_RIP 0x6c16 +#define VMX_VMCS_HOST_S_CET 0x6c18 +#define VMX_VMCS_HOST_SSP 0x6c1a +#define VMX_VMCS_HOST_INTR_SSP_TABLE_ADDR 0x6c1c + +#define VMX_VMCS16_GUEST_SEG_SEL(a_iSegReg) (VMX_VMCS16_GUEST_ES_SEL + (a_iSegReg) * 2) +#define VMX_VMCS_GUEST_SEG_BASE(a_iSegReg) (VMX_VMCS_GUEST_ES_BASE + (a_iSegReg) * 2) +#define VMX_VMCS32_GUEST_SEG_LIMIT(a_iSegReg) (VMX_VMCS32_GUEST_ES_LIMIT + (a_iSegReg) * 2) +#define VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(a_iSegReg) (VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS + (a_iSegReg) * 2) + +/** + * VMCS field. + * In accordance with the VT-x spec. + */ +typedef union +{ + struct + { + /** The access type; 0=full, 1=high of 64-bit fields. */ + uint32_t fAccessType : 1; + /** The index. */ + uint32_t u8Index : 8; + /** The type; 0=control, 1=VM-exit info, 2=guest-state, 3=host-state. */ + uint32_t u2Type : 2; + /** Reserved (MBZ). */ + uint32_t u1Reserved0 : 1; + /** The width; 0=16-bit, 1=64-bit, 2=32-bit, 3=natural-width. */ + uint32_t u2Width : 2; + /** Reserved (MBZ). */ + uint32_t u18Reserved0 : 18; + } n; + + /* The unsigned integer view. */ + uint32_t u; +} VMXVMCSFIELD; +AssertCompileSize(VMXVMCSFIELD, 4); +/** Pointer to a VMCS field. */ +typedef VMXVMCSFIELD *PVMXVMCSFIELD; +/** Pointer to a const VMCS field. */ +typedef const VMXVMCSFIELD *PCVMXVMCSFIELD; + +/** VMCS field: Mask of reserved bits (bits 63:15 MBZ), bit 12 is not included! */ +#define VMX_VMCSFIELD_RSVD_MASK UINT64_C(0xffffffffffff8000) + +/** Bits fields for a VMCS field. */ +#define VMX_BF_VMCSFIELD_ACCESS_TYPE_SHIFT 0 +#define VMX_BF_VMCSFIELD_ACCESS_TYPE_MASK UINT32_C(0x00000001) +#define VMX_BF_VMCSFIELD_INDEX_SHIFT 1 +#define VMX_BF_VMCSFIELD_INDEX_MASK UINT32_C(0x000003fe) +#define VMX_BF_VMCSFIELD_TYPE_SHIFT 10 +#define VMX_BF_VMCSFIELD_TYPE_MASK UINT32_C(0x00000c00) +#define VMX_BF_VMCSFIELD_RSVD_12_SHIFT 12 +#define VMX_BF_VMCSFIELD_RSVD_12_MASK UINT32_C(0x00001000) +#define VMX_BF_VMCSFIELD_WIDTH_SHIFT 13 +#define VMX_BF_VMCSFIELD_WIDTH_MASK UINT32_C(0x00006000) +#define VMX_BF_VMCSFIELD_RSVD_15_31_SHIFT 15 +#define VMX_BF_VMCSFIELD_RSVD_15_31_MASK UINT32_C(0xffff8000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_VMCSFIELD_, UINT32_C(0), UINT32_MAX, + (ACCESS_TYPE, INDEX, TYPE, RSVD_12, WIDTH, RSVD_15_31)); + +/** + * VMCS field encoding: Access type. + * In accordance with the VT-x spec. + */ +typedef enum +{ + VMXVMCSFIELDACCESS_FULL = 0, + VMXVMCSFIELDACCESS_HIGH +} VMXVMCSFIELDACCESS; +AssertCompileSize(VMXVMCSFIELDACCESS, 4); +/** VMCS field encoding type: Full. */ +#define VMX_VMCSFIELD_ACCESS_FULL 0 +/** VMCS field encoding type: High. */ +#define VMX_VMCSFIELD_ACCESS_HIGH 1 + +/** + * VMCS field encoding: Type. + * In accordance with the VT-x spec. + */ +typedef enum +{ + VMXVMCSFIELDTYPE_CONTROL = 0, + VMXVMCSFIELDTYPE_VMEXIT_INFO, + VMXVMCSFIELDTYPE_GUEST_STATE, + VMXVMCSFIELDTYPE_HOST_STATE +} VMXVMCSFIELDTYPE; +AssertCompileSize(VMXVMCSFIELDTYPE, 4); +/** VMCS field encoding type: Control. */ +#define VMX_VMCSFIELD_TYPE_CONTROL 0 +/** VMCS field encoding type: VM-exit information / read-only fields. */ +#define VMX_VMCSFIELD_TYPE_VMEXIT_INFO 1 +/** VMCS field encoding type: Guest-state. */ +#define VMX_VMCSFIELD_TYPE_GUEST_STATE 2 +/** VMCS field encoding type: Host-state. */ +#define VMX_VMCSFIELD_TYPE_HOST_STATE 3 + +/** + * VMCS field encoding: Width. + * In accordance with the VT-x spec. + */ +typedef enum +{ + VMXVMCSFIELDWIDTH_16BIT = 0, + VMXVMCSFIELDWIDTH_64BIT, + VMXVMCSFIELDWIDTH_32BIT, + VMXVMCSFIELDWIDTH_NATURAL +} VMXVMCSFIELDWIDTH; +AssertCompileSize(VMXVMCSFIELDWIDTH, 4); +/** VMCS field encoding width: 16-bit. */ +#define VMX_VMCSFIELD_WIDTH_16BIT 0 +/** VMCS field encoding width: 64-bit. */ +#define VMX_VMCSFIELD_WIDTH_64BIT 1 +/** VMCS field encoding width: 32-bit. */ +#define VMX_VMCSFIELD_WIDTH_32BIT 2 +/** VMCS field encoding width: Natural width. */ +#define VMX_VMCSFIELD_WIDTH_NATURAL 3 +/** @} */ + + +/** @name VM-entry instruction length. + * @{ */ +/** The maximum valid value for VM-entry instruction length while injecting a + * software interrupt, software exception or privileged software exception. */ +#define VMX_ENTRY_INSTR_LEN_MAX 15 +/** @} */ + + +/** @name VM-entry register masks. + * @{ */ +/** CR0 bits ignored on VM-entry while loading guest CR0 (ET, CD, NW, bits 6:15, + * bit 17 and bits 19:28). */ +#define VMX_ENTRY_GUEST_CR0_IGNORE_MASK UINT64_C(0x7ffaffd0) +/** DR7 bits set here are always cleared on VM-entry while loading guest DR7 (bit + * 12, bits 14:15). */ +#define VMX_ENTRY_GUEST_DR7_MBZ_MASK UINT64_C(0xd000) +/** DR7 bits set here are always set on VM-entry while loading guest DR7 (bit + * 10). */ +#define VMX_ENTRY_GUEST_DR7_MB1_MASK UINT64_C(0x400) +/** @} */ + + +/** @name VM-exit register masks. + * @{ */ +/** CR0 bits ignored on VM-exit while loading host CR0 (ET, CD, NW, bits 6:15, + * bit 17, bits 19:28 and bits 32:63). */ +#define VMX_EXIT_HOST_CR0_IGNORE_MASK UINT64_C(0xffffffff7ffaffd0) +/** @} */ + + +/** @name Pin-based VM-execution controls. + * @{ + */ +/** External interrupt exiting. */ +#define VMX_PIN_CTLS_EXT_INT_EXIT RT_BIT(0) +/** NMI exiting. */ +#define VMX_PIN_CTLS_NMI_EXIT RT_BIT(3) +/** Virtual NMIs. */ +#define VMX_PIN_CTLS_VIRT_NMI RT_BIT(5) +/** Activate VMX preemption timer. */ +#define VMX_PIN_CTLS_PREEMPT_TIMER RT_BIT(6) +/** Process interrupts with the posted-interrupt notification vector. */ +#define VMX_PIN_CTLS_POSTED_INT RT_BIT(7) +/** Default1 class when true capability MSRs are not supported. */ +#define VMX_PIN_CTLS_DEFAULT1 UINT32_C(0x00000016) + +/** Bit fields for MSR_IA32_VMX_PINBASED_CTLS and Pin-based VM-execution + * controls field in the VMCS. */ +#define VMX_BF_PIN_CTLS_EXT_INT_EXIT_SHIFT 0 +#define VMX_BF_PIN_CTLS_EXT_INT_EXIT_MASK UINT32_C(0x00000001) +#define VMX_BF_PIN_CTLS_RSVD_1_2_SHIFT 1 +#define VMX_BF_PIN_CTLS_RSVD_1_2_MASK UINT32_C(0x00000006) +#define VMX_BF_PIN_CTLS_NMI_EXIT_SHIFT 3 +#define VMX_BF_PIN_CTLS_NMI_EXIT_MASK UINT32_C(0x00000008) +#define VMX_BF_PIN_CTLS_RSVD_4_SHIFT 4 +#define VMX_BF_PIN_CTLS_RSVD_4_MASK UINT32_C(0x00000010) +#define VMX_BF_PIN_CTLS_VIRT_NMI_SHIFT 5 +#define VMX_BF_PIN_CTLS_VIRT_NMI_MASK UINT32_C(0x00000020) +#define VMX_BF_PIN_CTLS_PREEMPT_TIMER_SHIFT 6 +#define VMX_BF_PIN_CTLS_PREEMPT_TIMER_MASK UINT32_C(0x00000040) +#define VMX_BF_PIN_CTLS_POSTED_INT_SHIFT 7 +#define VMX_BF_PIN_CTLS_POSTED_INT_MASK UINT32_C(0x00000080) +#define VMX_BF_PIN_CTLS_RSVD_8_31_SHIFT 8 +#define VMX_BF_PIN_CTLS_RSVD_8_31_MASK UINT32_C(0xffffff00) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_PIN_CTLS_, UINT32_C(0), UINT32_MAX, + (EXT_INT_EXIT, RSVD_1_2, NMI_EXIT, RSVD_4, VIRT_NMI, PREEMPT_TIMER, POSTED_INT, RSVD_8_31)); +/** @} */ + + +/** @name Processor-based VM-execution controls. + * @{ + */ +/** VM-exit as soon as RFLAGS.IF=1 and no blocking is active. */ +#define VMX_PROC_CTLS_INT_WINDOW_EXIT RT_BIT(2) +/** Use timestamp counter offset. */ +#define VMX_PROC_CTLS_USE_TSC_OFFSETTING RT_BIT(3) +/** VM-exit when executing the HLT instruction. */ +#define VMX_PROC_CTLS_HLT_EXIT RT_BIT(7) +/** VM-exit when executing the INVLPG instruction. */ +#define VMX_PROC_CTLS_INVLPG_EXIT RT_BIT(9) +/** VM-exit when executing the MWAIT instruction. */ +#define VMX_PROC_CTLS_MWAIT_EXIT RT_BIT(10) +/** VM-exit when executing the RDPMC instruction. */ +#define VMX_PROC_CTLS_RDPMC_EXIT RT_BIT(11) +/** VM-exit when executing the RDTSC/RDTSCP instruction. */ +#define VMX_PROC_CTLS_RDTSC_EXIT RT_BIT(12) +/** VM-exit when executing the MOV to CR3 instruction. (forced to 1 on the + * 'first' VT-x capable CPUs; this actually includes the newest Nehalem CPUs) */ +#define VMX_PROC_CTLS_CR3_LOAD_EXIT RT_BIT(15) +/** VM-exit when executing the MOV from CR3 instruction. (forced to 1 on the + * 'first' VT-x capable CPUs; this actually includes the newest Nehalem CPUs) */ +#define VMX_PROC_CTLS_CR3_STORE_EXIT RT_BIT(16) +/** Whether the secondary processor based VM-execution controls are used. */ +#define VMX_PROC_CTLS_USE_TERTIARY_CTLS RT_BIT(17) +/** VM-exit on CR8 loads. */ +#define VMX_PROC_CTLS_CR8_LOAD_EXIT RT_BIT(19) +/** VM-exit on CR8 stores. */ +#define VMX_PROC_CTLS_CR8_STORE_EXIT RT_BIT(20) +/** Use TPR shadow. */ +#define VMX_PROC_CTLS_USE_TPR_SHADOW RT_BIT(21) +/** VM-exit when virtual NMI blocking is disabled. */ +#define VMX_PROC_CTLS_NMI_WINDOW_EXIT RT_BIT(22) +/** VM-exit when executing a MOV DRx instruction. */ +#define VMX_PROC_CTLS_MOV_DR_EXIT RT_BIT(23) +/** VM-exit when executing IO instructions. */ +#define VMX_PROC_CTLS_UNCOND_IO_EXIT RT_BIT(24) +/** Use IO bitmaps. */ +#define VMX_PROC_CTLS_USE_IO_BITMAPS RT_BIT(25) +/** Monitor trap flag. */ +#define VMX_PROC_CTLS_MONITOR_TRAP_FLAG RT_BIT(27) +/** Use MSR bitmaps. */ +#define VMX_PROC_CTLS_USE_MSR_BITMAPS RT_BIT(28) +/** VM-exit when executing the MONITOR instruction. */ +#define VMX_PROC_CTLS_MONITOR_EXIT RT_BIT(29) +/** VM-exit when executing the PAUSE instruction. */ +#define VMX_PROC_CTLS_PAUSE_EXIT RT_BIT(30) +/** Whether the secondary processor based VM-execution controls are used. */ +#define VMX_PROC_CTLS_USE_SECONDARY_CTLS RT_BIT(31) +/** Default1 class when true-capability MSRs are not supported. */ +#define VMX_PROC_CTLS_DEFAULT1 UINT32_C(0x0401e172) + +/** Bit fields for MSR_IA32_VMX_PROCBASED_CTLS and Processor-based VM-execution + * controls field in the VMCS. */ +#define VMX_BF_PROC_CTLS_RSVD_0_1_SHIFT 0 +#define VMX_BF_PROC_CTLS_RSVD_0_1_MASK UINT32_C(0x00000003) +#define VMX_BF_PROC_CTLS_INT_WINDOW_EXIT_SHIFT 2 +#define VMX_BF_PROC_CTLS_INT_WINDOW_EXIT_MASK UINT32_C(0x00000004) +#define VMX_BF_PROC_CTLS_USE_TSC_OFFSETTING_SHIFT 3 +#define VMX_BF_PROC_CTLS_USE_TSC_OFFSETTING_MASK UINT32_C(0x00000008) +#define VMX_BF_PROC_CTLS_RSVD_4_6_SHIFT 4 +#define VMX_BF_PROC_CTLS_RSVD_4_6_MASK UINT32_C(0x00000070) +#define VMX_BF_PROC_CTLS_HLT_EXIT_SHIFT 7 +#define VMX_BF_PROC_CTLS_HLT_EXIT_MASK UINT32_C(0x00000080) +#define VMX_BF_PROC_CTLS_RSVD_8_SHIFT 8 +#define VMX_BF_PROC_CTLS_RSVD_8_MASK UINT32_C(0x00000100) +#define VMX_BF_PROC_CTLS_INVLPG_EXIT_SHIFT 9 +#define VMX_BF_PROC_CTLS_INVLPG_EXIT_MASK UINT32_C(0x00000200) +#define VMX_BF_PROC_CTLS_MWAIT_EXIT_SHIFT 10 +#define VMX_BF_PROC_CTLS_MWAIT_EXIT_MASK UINT32_C(0x00000400) +#define VMX_BF_PROC_CTLS_RDPMC_EXIT_SHIFT 11 +#define VMX_BF_PROC_CTLS_RDPMC_EXIT_MASK UINT32_C(0x00000800) +#define VMX_BF_PROC_CTLS_RDTSC_EXIT_SHIFT 12 +#define VMX_BF_PROC_CTLS_RDTSC_EXIT_MASK UINT32_C(0x00001000) +#define VMX_BF_PROC_CTLS_RSVD_13_14_SHIFT 13 +#define VMX_BF_PROC_CTLS_RSVD_13_14_MASK UINT32_C(0x00006000) +#define VMX_BF_PROC_CTLS_CR3_LOAD_EXIT_SHIFT 15 +#define VMX_BF_PROC_CTLS_CR3_LOAD_EXIT_MASK UINT32_C(0x00008000) +#define VMX_BF_PROC_CTLS_CR3_STORE_EXIT_SHIFT 16 +#define VMX_BF_PROC_CTLS_CR3_STORE_EXIT_MASK UINT32_C(0x00010000) +#define VMX_BF_PROC_CTLS_USE_TERTIARY_CTLS_SHIFT 17 +#define VMX_BF_PROC_CTLS_USE_TERTIARY_CTLS_MASK UINT32_C(0x00020000) +#define VMX_BF_PROC_CTLS_RSVD_18_SHIFT 18 +#define VMX_BF_PROC_CTLS_RSVD_18_MASK UINT32_C(0x00040000) +#define VMX_BF_PROC_CTLS_CR8_LOAD_EXIT_SHIFT 19 +#define VMX_BF_PROC_CTLS_CR8_LOAD_EXIT_MASK UINT32_C(0x00080000) +#define VMX_BF_PROC_CTLS_CR8_STORE_EXIT_SHIFT 20 +#define VMX_BF_PROC_CTLS_CR8_STORE_EXIT_MASK UINT32_C(0x00100000) +#define VMX_BF_PROC_CTLS_USE_TPR_SHADOW_SHIFT 21 +#define VMX_BF_PROC_CTLS_USE_TPR_SHADOW_MASK UINT32_C(0x00200000) +#define VMX_BF_PROC_CTLS_NMI_WINDOW_EXIT_SHIFT 22 +#define VMX_BF_PROC_CTLS_NMI_WINDOW_EXIT_MASK UINT32_C(0x00400000) +#define VMX_BF_PROC_CTLS_MOV_DR_EXIT_SHIFT 23 +#define VMX_BF_PROC_CTLS_MOV_DR_EXIT_MASK UINT32_C(0x00800000) +#define VMX_BF_PROC_CTLS_UNCOND_IO_EXIT_SHIFT 24 +#define VMX_BF_PROC_CTLS_UNCOND_IO_EXIT_MASK UINT32_C(0x01000000) +#define VMX_BF_PROC_CTLS_USE_IO_BITMAPS_SHIFT 25 +#define VMX_BF_PROC_CTLS_USE_IO_BITMAPS_MASK UINT32_C(0x02000000) +#define VMX_BF_PROC_CTLS_RSVD_26_SHIFT 26 +#define VMX_BF_PROC_CTLS_RSVD_26_MASK UINT32_C(0x4000000) +#define VMX_BF_PROC_CTLS_MONITOR_TRAP_FLAG_SHIFT 27 +#define VMX_BF_PROC_CTLS_MONITOR_TRAP_FLAG_MASK UINT32_C(0x08000000) +#define VMX_BF_PROC_CTLS_USE_MSR_BITMAPS_SHIFT 28 +#define VMX_BF_PROC_CTLS_USE_MSR_BITMAPS_MASK UINT32_C(0x10000000) +#define VMX_BF_PROC_CTLS_MONITOR_EXIT_SHIFT 29 +#define VMX_BF_PROC_CTLS_MONITOR_EXIT_MASK UINT32_C(0x20000000) +#define VMX_BF_PROC_CTLS_PAUSE_EXIT_SHIFT 30 +#define VMX_BF_PROC_CTLS_PAUSE_EXIT_MASK UINT32_C(0x40000000) +#define VMX_BF_PROC_CTLS_USE_SECONDARY_CTLS_SHIFT 31 +#define VMX_BF_PROC_CTLS_USE_SECONDARY_CTLS_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_PROC_CTLS_, UINT32_C(0), UINT32_MAX, + (RSVD_0_1, INT_WINDOW_EXIT, USE_TSC_OFFSETTING, RSVD_4_6, HLT_EXIT, RSVD_8, INVLPG_EXIT, + MWAIT_EXIT, RDPMC_EXIT, RDTSC_EXIT, RSVD_13_14, CR3_LOAD_EXIT, CR3_STORE_EXIT, USE_TERTIARY_CTLS, + RSVD_18, CR8_LOAD_EXIT, CR8_STORE_EXIT, USE_TPR_SHADOW, NMI_WINDOW_EXIT, MOV_DR_EXIT, UNCOND_IO_EXIT, + USE_IO_BITMAPS, RSVD_26, MONITOR_TRAP_FLAG, USE_MSR_BITMAPS, MONITOR_EXIT, PAUSE_EXIT, + USE_SECONDARY_CTLS)); +/** @} */ + + +/** @name Secondary Processor-based VM-execution controls. + * @{ + */ +/** Virtualize APIC accesses. */ +#define VMX_PROC_CTLS2_VIRT_APIC_ACCESS RT_BIT(0) +/** EPT supported/enabled. */ +#define VMX_PROC_CTLS2_EPT RT_BIT(1) +/** Descriptor table instructions cause VM-exits. */ +#define VMX_PROC_CTLS2_DESC_TABLE_EXIT RT_BIT(2) +/** RDTSCP supported/enabled. */ +#define VMX_PROC_CTLS2_RDTSCP RT_BIT(3) +/** Virtualize x2APIC mode. */ +#define VMX_PROC_CTLS2_VIRT_X2APIC_MODE RT_BIT(4) +/** VPID supported/enabled. */ +#define VMX_PROC_CTLS2_VPID RT_BIT(5) +/** VM-exit when executing the WBINVD instruction. */ +#define VMX_PROC_CTLS2_WBINVD_EXIT RT_BIT(6) +/** Unrestricted guest execution. */ +#define VMX_PROC_CTLS2_UNRESTRICTED_GUEST RT_BIT(7) +/** APIC register virtualization. */ +#define VMX_PROC_CTLS2_APIC_REG_VIRT RT_BIT(8) +/** Virtual-interrupt delivery. */ +#define VMX_PROC_CTLS2_VIRT_INT_DELIVERY RT_BIT(9) +/** A specified number of pause loops cause a VM-exit. */ +#define VMX_PROC_CTLS2_PAUSE_LOOP_EXIT RT_BIT(10) +/** VM-exit when executing RDRAND instructions. */ +#define VMX_PROC_CTLS2_RDRAND_EXIT RT_BIT(11) +/** Enables INVPCID instructions. */ +#define VMX_PROC_CTLS2_INVPCID RT_BIT(12) +/** Enables VMFUNC instructions. */ +#define VMX_PROC_CTLS2_VMFUNC RT_BIT(13) +/** Enables VMCS shadowing. */ +#define VMX_PROC_CTLS2_VMCS_SHADOWING RT_BIT(14) +/** Enables ENCLS VM-exits. */ +#define VMX_PROC_CTLS2_ENCLS_EXIT RT_BIT(15) +/** VM-exit when executing RDSEED. */ +#define VMX_PROC_CTLS2_RDSEED_EXIT RT_BIT(16) +/** Enables page-modification logging. */ +#define VMX_PROC_CTLS2_PML RT_BIT(17) +/** Controls whether EPT-violations may cause \#VE instead of exits. */ +#define VMX_PROC_CTLS2_EPT_XCPT_VE RT_BIT(18) +/** Conceal VMX non-root operation from Intel processor trace (PT). */ +#define VMX_PROC_CTLS2_CONCEAL_VMX_FROM_PT RT_BIT(19) +/** Enables XSAVES/XRSTORS instructions. */ +#define VMX_PROC_CTLS2_XSAVES_XRSTORS RT_BIT(20) +/** Enables supervisor/user mode based EPT execute permission for linear + * addresses. */ +#define VMX_PROC_CTLS2_MODE_BASED_EPT_PERM RT_BIT(22) +/** Enables EPT write permissions to be specified at granularity of 128 bytes. */ +#define VMX_PROC_CTLS2_SPP_EPT RT_BIT(23) +/** Intel PT output addresses are treated as guest-physical addresses and + * translated using EPT. */ +#define VMX_PROC_CTLS2_PT_EPT RT_BIT(24) +/** Use TSC scaling. */ +#define VMX_PROC_CTLS2_TSC_SCALING RT_BIT(25) +/** Enables TPAUSE, UMONITOR and UMWAIT instructions. */ +#define VMX_PROC_CTLS2_USER_WAIT_PAUSE RT_BIT(26) +/** Enables consulting ENCLV-exiting bitmap when executing ENCLV. */ +#define VMX_PROC_CTLS2_ENCLV_EXIT RT_BIT(28) + +/** Bit fields for MSR_IA32_VMX_PROCBASED_CTLS2 and Secondary processor-based + * VM-execution controls field in the VMCS. */ +#define VMX_BF_PROC_CTLS2_VIRT_APIC_ACCESS_SHIFT 0 +#define VMX_BF_PROC_CTLS2_VIRT_APIC_ACCESS_MASK UINT32_C(0x00000001) +#define VMX_BF_PROC_CTLS2_EPT_SHIFT 1 +#define VMX_BF_PROC_CTLS2_EPT_MASK UINT32_C(0x00000002) +#define VMX_BF_PROC_CTLS2_DESC_TABLE_EXIT_SHIFT 2 +#define VMX_BF_PROC_CTLS2_DESC_TABLE_EXIT_MASK UINT32_C(0x00000004) +#define VMX_BF_PROC_CTLS2_RDTSCP_SHIFT 3 +#define VMX_BF_PROC_CTLS2_RDTSCP_MASK UINT32_C(0x00000008) +#define VMX_BF_PROC_CTLS2_VIRT_X2APIC_MODE_SHIFT 4 +#define VMX_BF_PROC_CTLS2_VIRT_X2APIC_MODE_MASK UINT32_C(0x00000010) +#define VMX_BF_PROC_CTLS2_VPID_SHIFT 5 +#define VMX_BF_PROC_CTLS2_VPID_MASK UINT32_C(0x00000020) +#define VMX_BF_PROC_CTLS2_WBINVD_EXIT_SHIFT 6 +#define VMX_BF_PROC_CTLS2_WBINVD_EXIT_MASK UINT32_C(0x00000040) +#define VMX_BF_PROC_CTLS2_UNRESTRICTED_GUEST_SHIFT 7 +#define VMX_BF_PROC_CTLS2_UNRESTRICTED_GUEST_MASK UINT32_C(0x00000080) +#define VMX_BF_PROC_CTLS2_APIC_REG_VIRT_SHIFT 8 +#define VMX_BF_PROC_CTLS2_APIC_REG_VIRT_MASK UINT32_C(0x00000100) +#define VMX_BF_PROC_CTLS2_VIRT_INT_DELIVERY_SHIFT 9 +#define VMX_BF_PROC_CTLS2_VIRT_INT_DELIVERY_MASK UINT32_C(0x00000200) +#define VMX_BF_PROC_CTLS2_PAUSE_LOOP_EXIT_SHIFT 10 +#define VMX_BF_PROC_CTLS2_PAUSE_LOOP_EXIT_MASK UINT32_C(0x00000400) +#define VMX_BF_PROC_CTLS2_RDRAND_EXIT_SHIFT 11 +#define VMX_BF_PROC_CTLS2_RDRAND_EXIT_MASK UINT32_C(0x00000800) +#define VMX_BF_PROC_CTLS2_INVPCID_SHIFT 12 +#define VMX_BF_PROC_CTLS2_INVPCID_MASK UINT32_C(0x00001000) +#define VMX_BF_PROC_CTLS2_VMFUNC_SHIFT 13 +#define VMX_BF_PROC_CTLS2_VMFUNC_MASK UINT32_C(0x00002000) +#define VMX_BF_PROC_CTLS2_VMCS_SHADOWING_SHIFT 14 +#define VMX_BF_PROC_CTLS2_VMCS_SHADOWING_MASK UINT32_C(0x00004000) +#define VMX_BF_PROC_CTLS2_ENCLS_EXIT_SHIFT 15 +#define VMX_BF_PROC_CTLS2_ENCLS_EXIT_MASK UINT32_C(0x00008000) +#define VMX_BF_PROC_CTLS2_RDSEED_EXIT_SHIFT 16 +#define VMX_BF_PROC_CTLS2_RDSEED_EXIT_MASK UINT32_C(0x00010000) +#define VMX_BF_PROC_CTLS2_PML_SHIFT 17 +#define VMX_BF_PROC_CTLS2_PML_MASK UINT32_C(0x00020000) +#define VMX_BF_PROC_CTLS2_EPT_VE_SHIFT 18 +#define VMX_BF_PROC_CTLS2_EPT_VE_MASK UINT32_C(0x00040000) +#define VMX_BF_PROC_CTLS2_CONCEAL_VMX_FROM_PT_SHIFT 19 +#define VMX_BF_PROC_CTLS2_CONCEAL_VMX_FROM_PT_MASK UINT32_C(0x00080000) +#define VMX_BF_PROC_CTLS2_XSAVES_XRSTORS_SHIFT 20 +#define VMX_BF_PROC_CTLS2_XSAVES_XRSTORS_MASK UINT32_C(0x00100000) +#define VMX_BF_PROC_CTLS2_RSVD_21_SHIFT 21 +#define VMX_BF_PROC_CTLS2_RSVD_21_MASK UINT32_C(0x00200000) +#define VMX_BF_PROC_CTLS2_MODE_BASED_EPT_PERM_SHIFT 22 +#define VMX_BF_PROC_CTLS2_MODE_BASED_EPT_PERM_MASK UINT32_C(0x00400000) +#define VMX_BF_PROC_CTLS2_SPP_EPT_SHIFT 23 +#define VMX_BF_PROC_CTLS2_SPP_EPT_MASK UINT32_C(0x00800000) +#define VMX_BF_PROC_CTLS2_PT_EPT_SHIFT 24 +#define VMX_BF_PROC_CTLS2_PT_EPT_MASK UINT32_C(0x01000000) +#define VMX_BF_PROC_CTLS2_TSC_SCALING_SHIFT 25 +#define VMX_BF_PROC_CTLS2_TSC_SCALING_MASK UINT32_C(0x02000000) +#define VMX_BF_PROC_CTLS2_USER_WAIT_PAUSE_SHIFT 26 +#define VMX_BF_PROC_CTLS2_USER_WAIT_PAUSE_MASK UINT32_C(0x04000000) +#define VMX_BF_PROC_CTLS2_RSVD_27_SHIFT 27 +#define VMX_BF_PROC_CTLS2_RSVD_27_MASK UINT32_C(0x08000000) +#define VMX_BF_PROC_CTLS2_ENCLV_EXIT_SHIFT 28 +#define VMX_BF_PROC_CTLS2_ENCLV_EXIT_MASK UINT32_C(0x10000000) +#define VMX_BF_PROC_CTLS2_RSVD_29_31_SHIFT 29 +#define VMX_BF_PROC_CTLS2_RSVD_29_31_MASK UINT32_C(0xe0000000) + +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_PROC_CTLS2_, UINT32_C(0), UINT32_MAX, + (VIRT_APIC_ACCESS, EPT, DESC_TABLE_EXIT, RDTSCP, VIRT_X2APIC_MODE, VPID, WBINVD_EXIT, + UNRESTRICTED_GUEST, APIC_REG_VIRT, VIRT_INT_DELIVERY, PAUSE_LOOP_EXIT, RDRAND_EXIT, INVPCID, VMFUNC, + VMCS_SHADOWING, ENCLS_EXIT, RDSEED_EXIT, PML, EPT_VE, CONCEAL_VMX_FROM_PT, XSAVES_XRSTORS, RSVD_21, + MODE_BASED_EPT_PERM, SPP_EPT, PT_EPT, TSC_SCALING, USER_WAIT_PAUSE, RSVD_27, ENCLV_EXIT, + RSVD_29_31)); +/** @} */ + + +/** @name Tertiary Processor-based VM-execution controls. + * @{ + */ +/** VM-exit when executing LOADIWKEY. */ +#define VMX_PROC_CTLS3_LOADIWKEY_EXIT RT_BIT_64(0) + +/** Bit fields for Tertiary processor-based VM-execution controls field in the VMCS. */ +#define VMX_BF_PROC_CTLS3_LOADIWKEY_EXIT_SHIFT 0 +#define VMX_BF_PROC_CTLS3_LOADIWKEY_EXIT_MASK UINT64_C(0x0000000000000001) +#define VMX_BF_PROC_CTLS3_RSVD_1_63_SHIFT 1 +#define VMX_BF_PROC_CTLS3_RSVD_1_63_MASK UINT64_C(0xfffffffffffffffe) + +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_PROC_CTLS3_, UINT64_C(0), UINT64_MAX, + (LOADIWKEY_EXIT, RSVD_1_63)); +/** @} */ + + +/** @name VM-entry controls. + * @{ + */ +/** Load guest debug controls (dr7 & IA32_DEBUGCTL_MSR) (forced to 1 on the + * 'first' VT-x capable CPUs; this actually includes the newest Nehalem CPUs) */ +#define VMX_ENTRY_CTLS_LOAD_DEBUG RT_BIT(2) +/** 64-bit guest mode. Must be 0 for CPUs that don't support AMD64. */ +#define VMX_ENTRY_CTLS_IA32E_MODE_GUEST RT_BIT(9) +/** In SMM mode after VM-entry. */ +#define VMX_ENTRY_CTLS_ENTRY_TO_SMM RT_BIT(10) +/** Disable dual treatment of SMI and SMM; must be zero for VM-entry outside of SMM. */ +#define VMX_ENTRY_CTLS_DEACTIVATE_DUAL_MON RT_BIT(11) +/** Whether the guest IA32_PERF_GLOBAL_CTRL MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_PERF_MSR RT_BIT(13) +/** Whether the guest IA32_PAT MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_PAT_MSR RT_BIT(14) +/** Whether the guest IA32_EFER MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_EFER_MSR RT_BIT(15) +/** Whether the guest IA32_BNDCFGS MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_BNDCFGS_MSR RT_BIT(16) +/** Whether to conceal VMX from Intel PT (Processor Trace). */ +#define VMX_ENTRY_CTLS_CONCEAL_VMX_FROM_PT RT_BIT(17) +/** Whether the guest IA32_RTIT MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_RTIT_CTL_MSR RT_BIT(18) +/** Whether the guest CET-related MSRs and SPP are loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_CET_STATE RT_BIT(20) +/** Whether the guest IA32_PKRS MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_PKRS_MSR RT_BIT(22) +/** Default1 class when true-capability MSRs are not supported. */ +#define VMX_ENTRY_CTLS_DEFAULT1 UINT32_C(0x000011ff) + +/** Bit fields for MSR_IA32_VMX_ENTRY_CTLS and VM-entry controls field in the + * VMCS. */ +#define VMX_BF_ENTRY_CTLS_RSVD_0_1_SHIFT 0 +#define VMX_BF_ENTRY_CTLS_RSVD_0_1_MASK UINT32_C(0x00000003) +#define VMX_BF_ENTRY_CTLS_LOAD_DEBUG_SHIFT 2 +#define VMX_BF_ENTRY_CTLS_LOAD_DEBUG_MASK UINT32_C(0x00000004) +#define VMX_BF_ENTRY_CTLS_RSVD_3_8_SHIFT 3 +#define VMX_BF_ENTRY_CTLS_RSVD_3_8_MASK UINT32_C(0x000001f8) +#define VMX_BF_ENTRY_CTLS_IA32E_MODE_GUEST_SHIFT 9 +#define VMX_BF_ENTRY_CTLS_IA32E_MODE_GUEST_MASK UINT32_C(0x00000200) +#define VMX_BF_ENTRY_CTLS_ENTRY_SMM_SHIFT 10 +#define VMX_BF_ENTRY_CTLS_ENTRY_SMM_MASK UINT32_C(0x00000400) +#define VMX_BF_ENTRY_CTLS_DEACTIVATE_DUAL_MON_SHIFT 11 +#define VMX_BF_ENTRY_CTLS_DEACTIVATE_DUAL_MON_MASK UINT32_C(0x00000800) +#define VMX_BF_ENTRY_CTLS_RSVD_12_SHIFT 12 +#define VMX_BF_ENTRY_CTLS_RSVD_12_MASK UINT32_C(0x00001000) +#define VMX_BF_ENTRY_CTLS_LOAD_PERF_MSR_SHIFT 13 +#define VMX_BF_ENTRY_CTLS_LOAD_PERF_MSR_MASK UINT32_C(0x00002000) +#define VMX_BF_ENTRY_CTLS_LOAD_PAT_MSR_SHIFT 14 +#define VMX_BF_ENTRY_CTLS_LOAD_PAT_MSR_MASK UINT32_C(0x00004000) +#define VMX_BF_ENTRY_CTLS_LOAD_EFER_MSR_SHIFT 15 +#define VMX_BF_ENTRY_CTLS_LOAD_EFER_MSR_MASK UINT32_C(0x00008000) +#define VMX_BF_ENTRY_CTLS_LOAD_BNDCFGS_MSR_SHIFT 16 +#define VMX_BF_ENTRY_CTLS_LOAD_BNDCFGS_MSR_MASK UINT32_C(0x00010000) +#define VMX_BF_ENTRY_CTLS_CONCEAL_VMX_FROM_PT_SHIFT 17 +#define VMX_BF_ENTRY_CTLS_CONCEAL_VMX_FROM_PT_MASK UINT32_C(0x00020000) +#define VMX_BF_ENTRY_CTLS_LOAD_RTIT_CTL_MSR_SHIFT 18 +#define VMX_BF_ENTRY_CTLS_LOAD_RTIT_CTL_MSR_MASK UINT32_C(0x00040000) +#define VMX_BF_ENTRY_CTLS_RSVD_19_SHIFT 19 +#define VMX_BF_ENTRY_CTLS_RSVD_19_MASK UINT32_C(0x00080000) +#define VMX_BF_ENTRY_CTLS_LOAD_CET_SHIFT 20 +#define VMX_BF_ENTRY_CTLS_LOAD_CET_MASK UINT32_C(0x00100000) +#define VMX_BF_ENTRY_CTLS_RSVD_21_SHIFT 21 +#define VMX_BF_ENTRY_CTLS_RSVD_21_MASK UINT32_C(0x00200000) +#define VMX_BF_ENTRY_CTLS_LOAD_PKRS_MSR_SHIFT 22 +#define VMX_BF_ENTRY_CTLS_LOAD_PKRS_MSR_MASK UINT32_C(0x00400000) +#define VMX_BF_ENTRY_CTLS_RSVD_23_31_SHIFT 23 +#define VMX_BF_ENTRY_CTLS_RSVD_23_31_MASK UINT32_C(0xff800000) + +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_ENTRY_CTLS_, UINT32_C(0), UINT32_MAX, + (RSVD_0_1, LOAD_DEBUG, RSVD_3_8, IA32E_MODE_GUEST, ENTRY_SMM, DEACTIVATE_DUAL_MON, RSVD_12, + LOAD_PERF_MSR, LOAD_PAT_MSR, LOAD_EFER_MSR, LOAD_BNDCFGS_MSR, CONCEAL_VMX_FROM_PT, + LOAD_RTIT_CTL_MSR, RSVD_19, LOAD_CET, RSVD_21, LOAD_PKRS_MSR, RSVD_23_31)); +/** @} */ + + +/** @name VM-exit controls. + * @{ + */ +/** Save guest debug controls (dr7 & IA32_DEBUGCTL_MSR) (forced to 1 on the + * 'first' VT-x capable CPUs; this actually includes the newest Nehalem CPUs) */ +#define VMX_EXIT_CTLS_SAVE_DEBUG RT_BIT(2) +/** Return to long mode after a VM-exit. */ +#define VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE RT_BIT(9) +/** Whether the host IA32_PERF_GLOBAL_CTRL MSR is loaded on VM-exit. */ +#define VMX_EXIT_CTLS_LOAD_PERF_MSR RT_BIT(12) +/** Acknowledge external interrupts with the irq controller if one caused a VM-exit. */ +#define VMX_EXIT_CTLS_ACK_EXT_INT RT_BIT(15) +/** Whether the guest IA32_PAT MSR is saved on VM-exit. */ +#define VMX_EXIT_CTLS_SAVE_PAT_MSR RT_BIT(18) +/** Whether the host IA32_PAT MSR is loaded on VM-exit. */ +#define VMX_EXIT_CTLS_LOAD_PAT_MSR RT_BIT(19) +/** Whether the guest IA32_EFER MSR is saved on VM-exit. */ +#define VMX_EXIT_CTLS_SAVE_EFER_MSR RT_BIT(20) +/** Whether the host IA32_EFER MSR is loaded on VM-exit. */ +#define VMX_EXIT_CTLS_LOAD_EFER_MSR RT_BIT(21) +/** Whether the value of the VMX preemption timer is saved on every VM-exit. */ +#define VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER RT_BIT(22) +/** Whether IA32_BNDCFGS MSR is cleared on VM-exit. */ +#define VMX_EXIT_CTLS_CLEAR_BNDCFGS_MSR RT_BIT(23) +/** Whether to conceal VMX from Intel PT. */ +#define VMX_EXIT_CTLS_CONCEAL_VMX_FROM_PT RT_BIT(24) +/** Whether IA32_RTIT_CTL MSR is cleared on VM-exit. */ +#define VMX_EXIT_CTLS_CLEAR_RTIT_CTL_MSR RT_BIT(25) +/** Whether CET-related MSRs and SPP are loaded on VM-exit. */ +#define VMX_EXIT_CTLS_LOAD_CET_STATE RT_BIT(28) +/** Whether the host IA32_PKRS MSR is loaded on VM-exit. */ +#define VMX_EXIT_CTLS_LOAD_PKRS_MSR RT_BIT(29) +/** Whether the host IA32_PERF_GLOBAL_CTRL MSR is saved on VM-exit. */ +#define VMX_EXIT_CTLS_SAVE_PERF_MSR RT_BIT(30) +/** Whether secondary VM-exit controls are used. */ +#define VMX_EXIT_CTLS_USE_SECONDARY_CTLS RT_BIT(31) +/** Default1 class when true-capability MSRs are not supported. */ +#define VMX_EXIT_CTLS_DEFAULT1 UINT32_C(0x00036dff) + +/** Bit fields for MSR_IA32_VMX_EXIT_CTLS and VM-exit controls field in the + * VMCS. */ +#define VMX_BF_EXIT_CTLS_RSVD_0_1_SHIFT 0 +#define VMX_BF_EXIT_CTLS_RSVD_0_1_MASK UINT32_C(0x00000003) +#define VMX_BF_EXIT_CTLS_SAVE_DEBUG_SHIFT 2 +#define VMX_BF_EXIT_CTLS_SAVE_DEBUG_MASK UINT32_C(0x00000004) +#define VMX_BF_EXIT_CTLS_RSVD_3_8_SHIFT 3 +#define VMX_BF_EXIT_CTLS_RSVD_3_8_MASK UINT32_C(0x000001f8) +#define VMX_BF_EXIT_CTLS_HOST_ADDR_SPACE_SIZE_SHIFT 9 +#define VMX_BF_EXIT_CTLS_HOST_ADDR_SPACE_SIZE_MASK UINT32_C(0x00000200) +#define VMX_BF_EXIT_CTLS_RSVD_10_11_SHIFT 10 +#define VMX_BF_EXIT_CTLS_RSVD_10_11_MASK UINT32_C(0x00000c00) +#define VMX_BF_EXIT_CTLS_LOAD_PERF_MSR_SHIFT 12 +#define VMX_BF_EXIT_CTLS_LOAD_PERF_MSR_MASK UINT32_C(0x00001000) +#define VMX_BF_EXIT_CTLS_RSVD_13_14_SHIFT 13 +#define VMX_BF_EXIT_CTLS_RSVD_13_14_MASK UINT32_C(0x00006000) +#define VMX_BF_EXIT_CTLS_ACK_EXT_INT_SHIFT 15 +#define VMX_BF_EXIT_CTLS_ACK_EXT_INT_MASK UINT32_C(0x00008000) +#define VMX_BF_EXIT_CTLS_RSVD_16_17_SHIFT 16 +#define VMX_BF_EXIT_CTLS_RSVD_16_17_MASK UINT32_C(0x00030000) +#define VMX_BF_EXIT_CTLS_SAVE_PAT_MSR_SHIFT 18 +#define VMX_BF_EXIT_CTLS_SAVE_PAT_MSR_MASK UINT32_C(0x00040000) +#define VMX_BF_EXIT_CTLS_LOAD_PAT_MSR_SHIFT 19 +#define VMX_BF_EXIT_CTLS_LOAD_PAT_MSR_MASK UINT32_C(0x00080000) +#define VMX_BF_EXIT_CTLS_SAVE_EFER_MSR_SHIFT 20 +#define VMX_BF_EXIT_CTLS_SAVE_EFER_MSR_MASK UINT32_C(0x00100000) +#define VMX_BF_EXIT_CTLS_LOAD_EFER_MSR_SHIFT 21 +#define VMX_BF_EXIT_CTLS_LOAD_EFER_MSR_MASK UINT32_C(0x00200000) +#define VMX_BF_EXIT_CTLS_SAVE_PREEMPT_TIMER_SHIFT 22 +#define VMX_BF_EXIT_CTLS_SAVE_PREEMPT_TIMER_MASK UINT32_C(0x00400000) +#define VMX_BF_EXIT_CTLS_CLEAR_BNDCFGS_MSR_SHIFT 23 +#define VMX_BF_EXIT_CTLS_CLEAR_BNDCFGS_MSR_MASK UINT32_C(0x00800000) +#define VMX_BF_EXIT_CTLS_CONCEAL_VMX_FROM_PT_SHIFT 24 +#define VMX_BF_EXIT_CTLS_CONCEAL_VMX_FROM_PT_MASK UINT32_C(0x01000000) +#define VMX_BF_EXIT_CTLS_CLEAR_RTIT_CTL_MSR_SHIFT 25 +#define VMX_BF_EXIT_CTLS_CLEAR_RTIT_CTL_MSR_MASK UINT32_C(0x02000000) +#define VMX_BF_EXIT_CTLS_RSVD_26_27_SHIFT 26 +#define VMX_BF_EXIT_CTLS_RSVD_26_27_MASK UINT32_C(0x0c000000) +#define VMX_BF_EXIT_CTLS_LOAD_CET_SHIFT 28 +#define VMX_BF_EXIT_CTLS_LOAD_CET_MASK UINT32_C(0x10000000) +#define VMX_BF_EXIT_CTLS_LOAD_PKRS_MSR_SHIFT 29 +#define VMX_BF_EXIT_CTLS_LOAD_PKRS_MSR_MASK UINT32_C(0x20000000) +#define VMX_BF_EXIT_CTLS_SAVE_PERF_MSR_SHIFT 30 +#define VMX_BF_EXIT_CTLS_SAVE_PERF_MSR_MASK UINT32_C(0x40000000) +#define VMX_BF_EXIT_CTLS_USE_SECONDARY_CTLS_SHIFT 31 +#define VMX_BF_EXIT_CTLS_USE_SECONDARY_CTLS_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_CTLS_, UINT32_C(0), UINT32_MAX, + (RSVD_0_1, SAVE_DEBUG, RSVD_3_8, HOST_ADDR_SPACE_SIZE, RSVD_10_11, LOAD_PERF_MSR, RSVD_13_14, + ACK_EXT_INT, RSVD_16_17, SAVE_PAT_MSR, LOAD_PAT_MSR, SAVE_EFER_MSR, LOAD_EFER_MSR, + SAVE_PREEMPT_TIMER, CLEAR_BNDCFGS_MSR, CONCEAL_VMX_FROM_PT, CLEAR_RTIT_CTL_MSR, RSVD_26_27, + LOAD_CET, LOAD_PKRS_MSR, SAVE_PERF_MSR, USE_SECONDARY_CTLS)); +/** @} */ + + +/** @name VM-exit reason. + * @{ + */ +#define VMX_EXIT_REASON_BASIC(a) ((a) & 0xffff) +#define VMX_EXIT_REASON_HAS_ENTRY_FAILED(a) (((a) >> 31) & 1) +#define VMX_EXIT_REASON_ENTRY_FAILED RT_BIT(31) + +/** Bit fields for VM-exit reason. */ +/** The exit reason. */ +#define VMX_BF_EXIT_REASON_BASIC_SHIFT 0 +#define VMX_BF_EXIT_REASON_BASIC_MASK UINT32_C(0x0000ffff) +/** Bits 16:26 are reseved and MBZ. */ +#define VMX_BF_EXIT_REASON_RSVD_16_26_SHIFT 16 +#define VMX_BF_EXIT_REASON_RSVD_16_26_MASK UINT32_C(0x07ff0000) +/** Whether the VM-exit was incident to enclave mode. */ +#define VMX_BF_EXIT_REASON_ENCLAVE_MODE_SHIFT 27 +#define VMX_BF_EXIT_REASON_ENCLAVE_MODE_MASK UINT32_C(0x08000000) +/** Pending MTF (Monitor Trap Flag) during VM-exit (only applicable in SMM mode). */ +#define VMX_BF_EXIT_REASON_SMM_PENDING_MTF_SHIFT 28 +#define VMX_BF_EXIT_REASON_SMM_PENDING_MTF_MASK UINT32_C(0x10000000) +/** VM-exit from VMX root operation (only possible with SMM). */ +#define VMX_BF_EXIT_REASON_VMX_ROOT_MODE_SHIFT 29 +#define VMX_BF_EXIT_REASON_VMX_ROOT_MODE_MASK UINT32_C(0x20000000) +/** Bit 30 is reserved and MBZ. */ +#define VMX_BF_EXIT_REASON_RSVD_30_SHIFT 30 +#define VMX_BF_EXIT_REASON_RSVD_30_MASK UINT32_C(0x40000000) +/** Whether VM-entry failed (currently only happens during loading guest-state + * or MSRs or machine check exceptions). */ +#define VMX_BF_EXIT_REASON_ENTRY_FAILED_SHIFT 31 +#define VMX_BF_EXIT_REASON_ENTRY_FAILED_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_REASON_, UINT32_C(0), UINT32_MAX, + (BASIC, RSVD_16_26, ENCLAVE_MODE, SMM_PENDING_MTF, VMX_ROOT_MODE, RSVD_30, ENTRY_FAILED)); +/** @} */ + + +/** @name VM-entry interruption information. + * @{ + */ +#define VMX_ENTRY_INT_INFO_IS_VALID(a) (((a) >> 31) & 1) +#define VMX_ENTRY_INT_INFO_VECTOR(a) ((a) & 0xff) +#define VMX_ENTRY_INT_INFO_TYPE_SHIFT 8 +#define VMX_ENTRY_INT_INFO_TYPE(a) (((a) >> 8) & 7) +#define VMX_ENTRY_INT_INFO_ERROR_CODE_VALID RT_BIT(11) +#define VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(a) (((a) >> 11) & 1) +#define VMX_ENTRY_INT_INFO_NMI_UNBLOCK_IRET 12 +#define VMX_ENTRY_INT_INFO_IS_NMI_UNBLOCK_IRET(a) (((a) >> 12) & 1) +#define VMX_ENTRY_INT_INFO_VALID RT_BIT(31) +#define VMX_ENTRY_INT_INFO_IS_VALID(a) (((a) >> 31) & 1) +/** Construct an VM-entry interruption information field from a VM-exit interruption + * info value (same except that bit 12 is reserved). */ +#define VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(a) ((a) & ~RT_BIT(12)) +/** Construct a VM-entry interruption information field from an IDT-vectoring + * information field (same except that bit 12 is reserved). */ +#define VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(a) ((a) & ~RT_BIT(12)) +/** If the VM-entry interruption information field indicates a page-fault. */ +#define VMX_ENTRY_INT_INFO_IS_XCPT_PF(a) (((a) & ( VMX_BF_ENTRY_INT_INFO_VALID_MASK \ + | VMX_BF_ENTRY_INT_INFO_TYPE_MASK \ + | VMX_BF_ENTRY_INT_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT) \ + | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_PF))) +/** If the VM-entry interruption information field indicates an external + * interrupt. */ +#define VMX_ENTRY_INT_INFO_IS_EXT_INT(a) (((a) & ( VMX_BF_ENTRY_INT_INFO_VALID_MASK \ + | VMX_BF_ENTRY_INT_INFO_TYPE_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_EXT_INT))) +/** If the VM-entry interruption information field indicates an NMI. */ +#define VMX_ENTRY_INT_INFO_IS_XCPT_NMI(a) (((a) & ( VMX_BF_ENTRY_INT_INFO_VALID_MASK \ + | VMX_BF_ENTRY_INT_INFO_TYPE_MASK \ + | VMX_BF_ENTRY_INT_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_NMI) \ + | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_NMI))) + +/** Bit fields for VM-entry interruption information. */ +/** The VM-entry interruption vector. */ +#define VMX_BF_ENTRY_INT_INFO_VECTOR_SHIFT 0 +#define VMX_BF_ENTRY_INT_INFO_VECTOR_MASK UINT32_C(0x000000ff) +/** The VM-entry interruption type (see VMX_ENTRY_INT_INFO_TYPE_XXX). */ +#define VMX_BF_ENTRY_INT_INFO_TYPE_SHIFT 8 +#define VMX_BF_ENTRY_INT_INFO_TYPE_MASK UINT32_C(0x00000700) +/** Whether this event has an error code. */ +#define VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID_SHIFT 11 +#define VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID_MASK UINT32_C(0x00000800) +/** Bits 12:30 are reserved and MBZ. */ +#define VMX_BF_ENTRY_INT_INFO_RSVD_12_30_SHIFT 12 +#define VMX_BF_ENTRY_INT_INFO_RSVD_12_30_MASK UINT32_C(0x7ffff000) +/** Whether this VM-entry interruption info is valid. */ +#define VMX_BF_ENTRY_INT_INFO_VALID_SHIFT 31 +#define VMX_BF_ENTRY_INT_INFO_VALID_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_ENTRY_INT_INFO_, UINT32_C(0), UINT32_MAX, + (VECTOR, TYPE, ERR_CODE_VALID, RSVD_12_30, VALID)); +/** @} */ + + +/** @name VM-entry exception error code. + * @{ */ +/** Error code valid mask. */ +/** @todo r=ramshankar: Intel spec. 26.2.1.3 "VM-Entry Control Fields" states that + * bits 31:15 MBZ. However, Intel spec. 6.13 "Error Code" states "To keep the + * stack aligned for doubleword pushes, the upper half of the error code is + * reserved" which implies bits 31:16 MBZ (and not 31:15) which is what we + * use below. */ +#define VMX_ENTRY_INT_XCPT_ERR_CODE_VALID_MASK UINT32_C(0xffff) +/** @} */ + +/** @name VM-entry interruption information types. + * @{ + */ +#define VMX_ENTRY_INT_INFO_TYPE_EXT_INT 0 +#define VMX_ENTRY_INT_INFO_TYPE_RSVD 1 +#define VMX_ENTRY_INT_INFO_TYPE_NMI 2 +#define VMX_ENTRY_INT_INFO_TYPE_HW_XCPT 3 +#define VMX_ENTRY_INT_INFO_TYPE_SW_INT 4 +#define VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT 5 +#define VMX_ENTRY_INT_INFO_TYPE_SW_XCPT 6 +#define VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT 7 +/** @} */ + + +/** @name VM-entry interruption information vector types for + * VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT. + * @{ */ +#define VMX_ENTRY_INT_INFO_VECTOR_MTF 0 +/** @} */ + + +/** @name VM-exit interruption information. + * @{ + */ +#define VMX_EXIT_INT_INFO_VECTOR(a) ((a) & 0xff) +#define VMX_EXIT_INT_INFO_TYPE_SHIFT 8 +#define VMX_EXIT_INT_INFO_TYPE(a) (((a) >> 8) & 7) +#define VMX_EXIT_INT_INFO_ERROR_CODE_VALID RT_BIT(11) +#define VMX_EXIT_INT_INFO_IS_ERROR_CODE_VALID(a) (((a) >> 11) & 1) +#define VMX_EXIT_INT_INFO_NMI_UNBLOCK_IRET 12 +#define VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET(a) (((a) >> 12) & 1) +#define VMX_EXIT_INT_INFO_VALID RT_BIT(31) +#define VMX_EXIT_INT_INFO_IS_VALID(a) (((a) >> 31) & 1) + +/** If the VM-exit interruption information field indicates an page-fault. */ +#define VMX_EXIT_INT_INFO_IS_XCPT_PF(a) (((a) & ( VMX_BF_EXIT_INT_INFO_VALID_MASK \ + | VMX_BF_EXIT_INT_INFO_TYPE_MASK \ + | VMX_BF_EXIT_INT_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, X86_XCPT_PF))) +/** If the VM-exit interruption information field indicates an double-fault. */ +#define VMX_EXIT_INT_INFO_IS_XCPT_DF(a) (((a) & ( VMX_BF_EXIT_INT_INFO_VALID_MASK \ + | VMX_BF_EXIT_INT_INFO_TYPE_MASK \ + | VMX_BF_EXIT_INT_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, X86_XCPT_DF))) +/** If the VM-exit interruption information field indicates an NMI. */ +#define VMX_EXIT_INT_INFO_IS_XCPT_NMI(a) (((a) & ( VMX_BF_EXIT_INT_INFO_VALID_MASK \ + | VMX_BF_EXIT_INT_INFO_TYPE_MASK \ + | VMX_BF_EXIT_INT_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_NMI) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, X86_XCPT_NMI))) + + +/** Bit fields for VM-exit interruption infomration. */ +/** The VM-exit interruption vector. */ +#define VMX_BF_EXIT_INT_INFO_VECTOR_SHIFT 0 +#define VMX_BF_EXIT_INT_INFO_VECTOR_MASK UINT32_C(0x000000ff) +/** The VM-exit interruption type (see VMX_EXIT_INT_INFO_TYPE_XXX). */ +#define VMX_BF_EXIT_INT_INFO_TYPE_SHIFT 8 +#define VMX_BF_EXIT_INT_INFO_TYPE_MASK UINT32_C(0x00000700) +/** Whether this event has an error code. */ +#define VMX_BF_EXIT_INT_INFO_ERR_CODE_VALID_SHIFT 11 +#define VMX_BF_EXIT_INT_INFO_ERR_CODE_VALID_MASK UINT32_C(0x00000800) +/** Whether NMI-unblocking due to IRET is active. */ +#define VMX_BF_EXIT_INT_INFO_NMI_UNBLOCK_IRET_SHIFT 12 +#define VMX_BF_EXIT_INT_INFO_NMI_UNBLOCK_IRET_MASK UINT32_C(0x00001000) +/** Bits 13:30 is reserved (MBZ). */ +#define VMX_BF_EXIT_INT_INFO_RSVD_13_30_SHIFT 13 +#define VMX_BF_EXIT_INT_INFO_RSVD_13_30_MASK UINT32_C(0x7fffe000) +/** Whether this VM-exit interruption info is valid. */ +#define VMX_BF_EXIT_INT_INFO_VALID_SHIFT 31 +#define VMX_BF_EXIT_INT_INFO_VALID_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_INT_INFO_, UINT32_C(0), UINT32_MAX, + (VECTOR, TYPE, ERR_CODE_VALID, NMI_UNBLOCK_IRET, RSVD_13_30, VALID)); +/** @} */ + + +/** @name VM-exit interruption information types. + * @{ + */ +#define VMX_EXIT_INT_INFO_TYPE_EXT_INT 0 +#define VMX_EXIT_INT_INFO_TYPE_NMI 2 +#define VMX_EXIT_INT_INFO_TYPE_HW_XCPT 3 +#define VMX_EXIT_INT_INFO_TYPE_SW_INT 4 +#define VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT 5 +#define VMX_EXIT_INT_INFO_TYPE_SW_XCPT 6 +#define VMX_EXIT_INT_INFO_TYPE_UNUSED 7 +/** @} */ + + +/** @name VM-exit instruction identity. + * + * These are found in VM-exit instruction information fields for certain + * instructions. + * @{ */ +typedef uint32_t VMXINSTRID; +/** Whether the instruction ID field is valid. */ +#define VMXINSTRID_VALID RT_BIT_32(31) +/** Whether the instruction's primary operand in the Mod R/M byte (bits 0:3) is a + * read or write. */ +#define VMXINSTRID_MODRM_PRIMARY_OP_W RT_BIT_32(30) +/** Gets whether the instruction ID is valid or not. */ +#define VMXINSTRID_IS_VALID(a) (((a) >> 31) & 1) +#define VMXINSTRID_IS_MODRM_PRIMARY_OP_W(a) (((a) >> 30) & 1) +/** Gets the instruction ID. */ +#define VMXINSTRID_GET_ID(a) ((a) & ~(VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W)) +/** No instruction ID info. */ +#define VMXINSTRID_NONE 0 + +/** The OR'd rvalues are from the VT-x spec (valid bit is VBox specific): */ +#define VMXINSTRID_SGDT (0x0 | VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W) +#define VMXINSTRID_SIDT (0x1 | VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W) +#define VMXINSTRID_LGDT (0x2 | VMXINSTRID_VALID) +#define VMXINSTRID_LIDT (0x3 | VMXINSTRID_VALID) + +#define VMXINSTRID_SLDT (0x0 | VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W) +#define VMXINSTRID_STR (0x1 | VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W) +#define VMXINSTRID_LLDT (0x2 | VMXINSTRID_VALID) +#define VMXINSTRID_LTR (0x3 | VMXINSTRID_VALID) + +/** The following IDs are used internally (some for logging, others for conveying + * the ModR/M primary operand write bit): */ +#define VMXINSTRID_VMLAUNCH (0x10 | VMXINSTRID_VALID) +#define VMXINSTRID_VMRESUME (0x11 | VMXINSTRID_VALID) +#define VMXINSTRID_VMREAD (0x12 | VMXINSTRID_VALID) +#define VMXINSTRID_VMWRITE (0x13 | VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W) +#define VMXINSTRID_IO_IN (0x14 | VMXINSTRID_VALID) +#define VMXINSTRID_IO_INS (0x15 | VMXINSTRID_VALID) +#define VMXINSTRID_IO_OUT (0x16 | VMXINSTRID_VALID) +#define VMXINSTRID_IO_OUTS (0x17 | VMXINSTRID_VALID) +#define VMXINSTRID_MOV_TO_DRX (0x18 | VMXINSTRID_VALID) +#define VMXINSTRID_MOV_FROM_DRX (0x19 | VMXINSTRID_VALID) +/** @} */ + + +/** @name IDT-vectoring information. + * @{ + */ +#define VMX_IDT_VECTORING_INFO_VECTOR(a) ((a) & 0xff) +#define VMX_IDT_VECTORING_INFO_TYPE_SHIFT 8 +#define VMX_IDT_VECTORING_INFO_TYPE(a) (((a) >> 8) & 7) +#define VMX_IDT_VECTORING_INFO_ERROR_CODE_VALID RT_BIT(11) +#define VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(a) (((a) >> 11) & 1) +#define VMX_IDT_VECTORING_INFO_IS_VALID(a) (((a) >> 31) & 1) +#define VMX_IDT_VECTORING_INFO_VALID RT_BIT(31) + +/** Construct an IDT-vectoring information field from an VM-entry interruption + * information field (same except that bit 12 is reserved). */ +#define VMX_IDT_VECTORING_INFO_FROM_ENTRY_INT_INFO(a) ((a) & ~RT_BIT(12)) +/** If the IDT-vectoring information field indicates a page-fault. */ +#define VMX_IDT_VECTORING_INFO_IS_XCPT_PF(a) (((a) & ( VMX_BF_IDT_VECTORING_INFO_VALID_MASK \ + | VMX_BF_IDT_VECTORING_INFO_TYPE_MASK \ + | VMX_BF_IDT_VECTORING_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_TYPE, VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT) \ + | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_VECTOR, X86_XCPT_PF))) +/** If the IDT-vectoring information field indicates an NMI. */ +#define VMX_IDT_VECTORING_INFO_IS_XCPT_NMI(a) (((a) & ( VMX_BF_IDT_VECTORING_INFO_VALID_MASK \ + | VMX_BF_IDT_VECTORING_INFO_TYPE_MASK \ + | VMX_BF_IDT_VECTORING_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_TYPE, VMX_IDT_VECTORING_INFO_TYPE_NMI) \ + | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_VECTOR, X86_XCPT_NMI))) + + +/** Bit fields for IDT-vectoring information. */ +/** The IDT-vectoring info vector. */ +#define VMX_BF_IDT_VECTORING_INFO_VECTOR_SHIFT 0 +#define VMX_BF_IDT_VECTORING_INFO_VECTOR_MASK UINT32_C(0x000000ff) +/** The IDT-vectoring info type (see VMX_IDT_VECTORING_INFO_TYPE_XXX). */ +#define VMX_BF_IDT_VECTORING_INFO_TYPE_SHIFT 8 +#define VMX_BF_IDT_VECTORING_INFO_TYPE_MASK UINT32_C(0x00000700) +/** Whether the event has an error code. */ +#define VMX_BF_IDT_VECTORING_INFO_ERR_CODE_VALID_SHIFT 11 +#define VMX_BF_IDT_VECTORING_INFO_ERR_CODE_VALID_MASK UINT32_C(0x00000800) +/** Bit 12 is undefined. */ +#define VMX_BF_IDT_VECTORING_INFO_UNDEF_12_SHIFT 12 +#define VMX_BF_IDT_VECTORING_INFO_UNDEF_12_MASK UINT32_C(0x00001000) +/** Bits 13:30 is reserved (MBZ). */ +#define VMX_BF_IDT_VECTORING_INFO_RSVD_13_30_SHIFT 13 +#define VMX_BF_IDT_VECTORING_INFO_RSVD_13_30_MASK UINT32_C(0x7fffe000) +/** Whether this IDT-vectoring info is valid. */ +#define VMX_BF_IDT_VECTORING_INFO_VALID_SHIFT 31 +#define VMX_BF_IDT_VECTORING_INFO_VALID_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_IDT_VECTORING_INFO_, UINT32_C(0), UINT32_MAX, + (VECTOR, TYPE, ERR_CODE_VALID, UNDEF_12, RSVD_13_30, VALID)); +/** @} */ + + +/** @name IDT-vectoring information vector types. + * @{ + */ +#define VMX_IDT_VECTORING_INFO_TYPE_EXT_INT 0 +#define VMX_IDT_VECTORING_INFO_TYPE_NMI 2 +#define VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT 3 +#define VMX_IDT_VECTORING_INFO_TYPE_SW_INT 4 +#define VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT 5 +#define VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT 6 +#define VMX_IDT_VECTORING_INFO_TYPE_UNUSED 7 +/** @} */ + + +/** @name TPR threshold. + * @{ */ +/** Mask of the TPR threshold field (bits 31:4 MBZ). */ +#define VMX_TPR_THRESHOLD_MASK UINT32_C(0xf) + +/** Bit fields for TPR threshold. */ +#define VMX_BF_TPR_THRESHOLD_TPR_SHIFT 0 +#define VMX_BF_TPR_THRESHOLD_TPR_MASK UINT32_C(0x0000000f) +#define VMX_BF_TPR_THRESHOLD_RSVD_4_31_SHIFT 4 +#define VMX_BF_TPR_THRESHOLD_RSVD_4_31_MASK UINT32_C(0xfffffff0) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_TPR_THRESHOLD_, UINT32_C(0), UINT32_MAX, + (TPR, RSVD_4_31)); +/** @} */ + + +/** @name Guest-activity states. + * @{ + */ +/** The logical processor is active. */ +#define VMX_VMCS_GUEST_ACTIVITY_ACTIVE 0x0 +/** The logical processor is inactive, because it executed a HLT instruction. */ +#define VMX_VMCS_GUEST_ACTIVITY_HLT 0x1 +/** The logical processor is inactive, because of a triple fault or other serious error. */ +#define VMX_VMCS_GUEST_ACTIVITY_SHUTDOWN 0x2 +/** The logical processor is inactive, because it's waiting for a startup-IPI */ +#define VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT 0x3 +/** @} */ + + +/** @name Guest-interruptibility states. + * @{ + */ +#define VMX_VMCS_GUEST_INT_STATE_BLOCK_STI RT_BIT(0) +#define VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS RT_BIT(1) +#define VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI RT_BIT(2) +#define VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI RT_BIT(3) +#define VMX_VMCS_GUEST_INT_STATE_ENCLAVE RT_BIT(4) + +/** Mask of the guest-interruptibility state field (bits 31:5 MBZ). */ +#define VMX_VMCS_GUEST_INT_STATE_MASK UINT32_C(0x1f) +/** @} */ + + +/** @name Exit qualification for debug exceptions. + * @{ + */ +/** Hardware breakpoint 0 was met. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP0 RT_BIT_64(0) +/** Hardware breakpoint 1 was met. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP1 RT_BIT_64(1) +/** Hardware breakpoint 2 was met. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP2 RT_BIT_64(2) +/** Hardware breakpoint 3 was met. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP3 RT_BIT_64(3) +/** Debug register access detected. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BD RT_BIT_64(13) +/** A debug exception would have been triggered by single-step execution mode. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BS RT_BIT_64(14) +/** Mask of all valid bits. */ +#define VMX_VMCS_EXIT_QUAL_VALID_MASK ( VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP0 \ + | VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP1 \ + | VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP2 \ + | VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP3 \ + | VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BD \ + | VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BS) + +/** Bit fields for Exit qualifications due to debug exceptions. */ +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP0_SHIFT 0 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP0_MASK UINT64_C(0x0000000000000001) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP1_SHIFT 1 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP1_MASK UINT64_C(0x0000000000000002) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP2_SHIFT 2 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP2_MASK UINT64_C(0x0000000000000004) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP3_SHIFT 3 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP3_MASK UINT64_C(0x0000000000000008) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_RSVD_4_12_SHIFT 4 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_RSVD_4_12_MASK UINT64_C(0x0000000000001ff0) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BD_SHIFT 13 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BD_MASK UINT64_C(0x0000000000002000) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BS_SHIFT 14 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BS_MASK UINT64_C(0x0000000000004000) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_RSVD_15_63_SHIFT 15 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_RSVD_15_63_MASK UINT64_C(0xffffffffffff8000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_DEBUG_XCPT_, UINT64_C(0), UINT64_MAX, + (BP0, BP1, BP2, BP3, RSVD_4_12, BD, BS, RSVD_15_63)); +/** @} */ + +/** @name Exit qualification for Mov DRx. + * @{ + */ +/** 0-2: Debug register number */ +#define VMX_EXIT_QUAL_DRX_REGISTER(a) ((a) & 7) +/** 3: Reserved; cleared to 0. */ +#define VMX_EXIT_QUAL_DRX_RES1(a) (((a) >> 3) & 1) +/** 4: Direction of move (0 = write, 1 = read) */ +#define VMX_EXIT_QUAL_DRX_DIRECTION(a) (((a) >> 4) & 1) +/** 5-7: Reserved; cleared to 0. */ +#define VMX_EXIT_QUAL_DRX_RES2(a) (((a) >> 5) & 7) +/** 8-11: General purpose register number. */ +#define VMX_EXIT_QUAL_DRX_GENREG(a) (((a) >> 8) & 0xf) + +/** Bit fields for Exit qualification due to Mov DRx. */ +#define VMX_BF_EXIT_QUAL_DRX_REGISTER_SHIFT 0 +#define VMX_BF_EXIT_QUAL_DRX_REGISTER_MASK UINT64_C(0x0000000000000007) +#define VMX_BF_EXIT_QUAL_DRX_RSVD_1_SHIFT 3 +#define VMX_BF_EXIT_QUAL_DRX_RSVD_1_MASK UINT64_C(0x0000000000000008) +#define VMX_BF_EXIT_QUAL_DRX_DIRECTION_SHIFT 4 +#define VMX_BF_EXIT_QUAL_DRX_DIRECTION_MASK UINT64_C(0x0000000000000010) +#define VMX_BF_EXIT_QUAL_DRX_RSVD_5_7_SHIFT 5 +#define VMX_BF_EXIT_QUAL_DRX_RSVD_5_7_MASK UINT64_C(0x00000000000000e0) +#define VMX_BF_EXIT_QUAL_DRX_GENREG_SHIFT 8 +#define VMX_BF_EXIT_QUAL_DRX_GENREG_MASK UINT64_C(0x0000000000000f00) +#define VMX_BF_EXIT_QUAL_DRX_RSVD_12_63_SHIFT 12 +#define VMX_BF_EXIT_QUAL_DRX_RSVD_12_63_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_DRX_, UINT64_C(0), UINT64_MAX, + (REGISTER, RSVD_1, DIRECTION, RSVD_5_7, GENREG, RSVD_12_63)); +/** @} */ + + +/** @name Exit qualification for debug exceptions types. + * @{ + */ +#define VMX_EXIT_QUAL_DRX_DIRECTION_WRITE 0 +#define VMX_EXIT_QUAL_DRX_DIRECTION_READ 1 +/** @} */ + + +/** @name Exit qualification for control-register accesses. + * @{ + */ +/** 0-3: Control register number (0 for CLTS & LMSW) */ +#define VMX_EXIT_QUAL_CRX_REGISTER(a) ((a) & 0xf) +/** 4-5: Access type. */ +#define VMX_EXIT_QUAL_CRX_ACCESS(a) (((a) >> 4) & 3) +/** 6: LMSW operand type memory (1 for memory, 0 for register). */ +#define VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(a) (((a) >> 6) & 1) +/** 7: Reserved; cleared to 0. */ +#define VMX_EXIT_QUAL_CRX_RES1(a) (((a) >> 7) & 1) +/** 8-11: General purpose register number (0 for CLTS & LMSW). */ +#define VMX_EXIT_QUAL_CRX_GENREG(a) (((a) >> 8) & 0xf) +/** 12-15: Reserved; cleared to 0. */ +#define VMX_EXIT_QUAL_CRX_RES2(a) (((a) >> 12) & 0xf) +/** 16-31: LMSW source data (else 0). */ +#define VMX_EXIT_QUAL_CRX_LMSW_DATA(a) (((a) >> 16) & 0xffff) + +/** Bit fields for Exit qualification for control-register accesses. */ +#define VMX_BF_EXIT_QUAL_CRX_REGISTER_SHIFT 0 +#define VMX_BF_EXIT_QUAL_CRX_REGISTER_MASK UINT64_C(0x000000000000000f) +#define VMX_BF_EXIT_QUAL_CRX_ACCESS_SHIFT 4 +#define VMX_BF_EXIT_QUAL_CRX_ACCESS_MASK UINT64_C(0x0000000000000030) +#define VMX_BF_EXIT_QUAL_CRX_LMSW_OP_SHIFT 6 +#define VMX_BF_EXIT_QUAL_CRX_LMSW_OP_MASK UINT64_C(0x0000000000000040) +#define VMX_BF_EXIT_QUAL_CRX_RSVD_7_SHIFT 7 +#define VMX_BF_EXIT_QUAL_CRX_RSVD_7_MASK UINT64_C(0x0000000000000080) +#define VMX_BF_EXIT_QUAL_CRX_GENREG_SHIFT 8 +#define VMX_BF_EXIT_QUAL_CRX_GENREG_MASK UINT64_C(0x0000000000000f00) +#define VMX_BF_EXIT_QUAL_CRX_RSVD_12_15_SHIFT 12 +#define VMX_BF_EXIT_QUAL_CRX_RSVD_12_15_MASK UINT64_C(0x000000000000f000) +#define VMX_BF_EXIT_QUAL_CRX_LMSW_DATA_SHIFT 16 +#define VMX_BF_EXIT_QUAL_CRX_LMSW_DATA_MASK UINT64_C(0x00000000ffff0000) +#define VMX_BF_EXIT_QUAL_CRX_RSVD_32_63_SHIFT 32 +#define VMX_BF_EXIT_QUAL_CRX_RSVD_32_63_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_CRX_, UINT64_C(0), UINT64_MAX, + (REGISTER, ACCESS, LMSW_OP, RSVD_7, GENREG, RSVD_12_15, LMSW_DATA, RSVD_32_63)); +/** @} */ + + +/** @name Exit qualification for control-register access types. + * @{ + */ +#define VMX_EXIT_QUAL_CRX_ACCESS_WRITE 0 +#define VMX_EXIT_QUAL_CRX_ACCESS_READ 1 +#define VMX_EXIT_QUAL_CRX_ACCESS_CLTS 2 +#define VMX_EXIT_QUAL_CRX_ACCESS_LMSW 3 +/** @} */ + + +/** @name Exit qualification for task switch. + * @{ + */ +#define VMX_EXIT_QUAL_TASK_SWITCH_SELECTOR(a) ((a) & 0xffff) +#define VMX_EXIT_QUAL_TASK_SWITCH_TYPE(a) (((a) >> 30) & 0x3) +/** Task switch caused by a call instruction. */ +#define VMX_EXIT_QUAL_TASK_SWITCH_TYPE_CALL 0 +/** Task switch caused by an iret instruction. */ +#define VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IRET 1 +/** Task switch caused by a jmp instruction. */ +#define VMX_EXIT_QUAL_TASK_SWITCH_TYPE_JMP 2 +/** Task switch caused by an interrupt gate. */ +#define VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT 3 + +/** Bit fields for Exit qualification for task switches. */ +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_NEW_TSS_SHIFT 0 +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_NEW_TSS_MASK UINT64_C(0x000000000000ffff) +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_RSVD_16_29_SHIFT 16 +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_RSVD_16_29_MASK UINT64_C(0x000000003fff0000) +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_SOURCE_SHIFT 30 +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_SOURCE_MASK UINT64_C(0x00000000c0000000) +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_RSVD_32_63_SHIFT 32 +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_RSVD_32_63_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_TASK_SWITCH_, UINT64_C(0), UINT64_MAX, + (NEW_TSS, RSVD_16_29, SOURCE, RSVD_32_63)); +/** @} */ + + +/** @name Exit qualification for EPT violations. + * @{ + */ +/** Set if acess causing the violation was a data read. */ +#define VMX_EXIT_QUAL_EPT_ACCESS_READ RT_BIT_64(0) +/** Set if acess causing the violation was a data write. */ +#define VMX_EXIT_QUAL_EPT_ACCESS_WRITE RT_BIT_64(1) +/** Set if the violation was caused by an instruction fetch. */ +#define VMX_EXIT_QUAL_EPT_ACCESS_INSTR_FETCH RT_BIT_64(2) +/** AND of the read bit of all EPT structures. */ +#define VMX_EXIT_QUAL_EPT_ENTRY_READ RT_BIT_64(3) +/** AND of the write bit of all EPT structures. */ +#define VMX_EXIT_QUAL_EPT_ENTRY_WRITE RT_BIT_64(4) +/** AND of the execute bit of all EPT structures. */ +#define VMX_EXIT_QUAL_EPT_ENTRY_EXECUTE RT_BIT_64(5) +/** And of the execute bit of all EPT structures for user-mode addresses + * (requires mode-based execute control). */ +#define VMX_EXIT_QUAL_EPT_ENTRY_EXECUTE_USER RT_BIT_64(6) +/** Set if the guest linear address field is valid. */ +#define VMX_EXIT_QUAL_EPT_LINEAR_ADDR_VALID RT_BIT_64(7) +/** If bit 7 is one: (reserved otherwise) + * 1 - violation due to physical address access. + * 0 - violation caused by page walk or access/dirty bit updates. + */ +#define VMX_EXIT_QUAL_EPT_LINEAR_TO_PHYS_ADDR RT_BIT_64(8) +/** If bit 7, 8 and advanced VM-exit info. for EPT is one: (reserved otherwise) + * 1 - linear address is user-mode address. + * 0 - linear address is supervisor-mode address. + */ +#define VMX_EXIT_QUAL_EPT_LINEAR_ADDR_USER RT_BIT_64(9) +/** If bit 7, 8 and advanced VM-exit info. for EPT is one: (reserved otherwise) + * 1 - linear address translates to read-only page. + * 0 - linear address translates to read-write page. + */ +#define VMX_EXIT_QUAL_EPT_LINEAR_ADDR_RO RT_BIT_64(10) +/** If bit 7, 8 and advanced VM-exit info. for EPT is one: (reserved otherwise) + * 1 - linear address translates to executable-disabled page. + * 0 - linear address translates to executable page. + */ +#define VMX_EXIT_QUAL_EPT_LINEAR_ADDR_XD RT_BIT_64(11) +/** NMI unblocking due to IRET. */ +#define VMX_EXIT_QUAL_EPT_NMI_UNBLOCK_IRET RT_BIT_64(12) +/** Set if acess causing the violation was a shadow-stack access. */ +#define VMX_EXIT_QUAL_EPT_ACCESS_SHW_STACK RT_BIT_64(13) +/** If supervisor-shadow stack is enabled: (reserved otherwise) + * 1 - supervisor shadow-stack access allowed. + * 0 - supervisor shadow-stack access disallowed. + */ +#define VMX_EXIT_QUAL_EPT_ENTRY_SHW_STACK_SUPER RT_BIT_64(14) +/** Set if access is related to trace output by Intel PT (reserved otherwise). */ +#define VMX_EXIT_QUAL_EPT_ACCESS_PT_TRACE RT_BIT_64(16) + +/** Checks whether NMI unblocking due to IRET. */ +#define VMX_EXIT_QUAL_EPT_IS_NMI_UNBLOCK_IRET(a) (((a) >> 12) & 1) + +/** Bit fields for Exit qualification for EPT violations. */ +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_READ_SHIFT 0 +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_READ_MASK UINT64_C(0x0000000000000001) +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_WRITE_SHIFT 1 +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_WRITE_MASK UINT64_C(0x0000000000000002) +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_INSTR_FETCH_SHIFT 2 +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_INSTR_FETCH_MASK UINT64_C(0x0000000000000004) +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_READ_SHIFT 3 +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_READ_MASK UINT64_C(0x0000000000000008) +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_WRITE_SHIFT 4 +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_WRITE_MASK UINT64_C(0x0000000000000010) +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_EXECUTE_SHIFT 5 +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_EXECUTE_MASK UINT64_C(0x0000000000000020) +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_EXECUTE_USER_SHIFT 6 +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_EXECUTE_USER_MASK UINT64_C(0x0000000000000040) +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_VALID_SHIFT 7 +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_VALID_MASK UINT64_C(0x0000000000000080) +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_TO_PHYS_ADDR_SHIFT 8 +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_TO_PHYS_ADDR_MASK UINT64_C(0x0000000000000100) +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_USER_SHIFT 9 +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_USER_MASK UINT64_C(0x0000000000000200) +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_RO_SHIFT 10 +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_RO_MASK UINT64_C(0x0000000000000400) +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_XD_SHIFT 11 +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_XD_MASK UINT64_C(0x0000000000000800) +#define VMX_BF_EXIT_QUAL_EPT_NMI_UNBLOCK_IRET_SHIFT 12 +#define VMX_BF_EXIT_QUAL_EPT_NMI_UNBLOCK_IRET_MASK UINT64_C(0x0000000000001000) +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_SHW_STACK_SHIFT 13 +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_SHW_STACK_MASK UINT64_C(0x0000000000002000) +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_SHW_STACK_SUPER_SHIFT 14 +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_SHW_STACK_SUPER_MASK UINT64_C(0x0000000000004000) +#define VMX_BF_EXIT_QUAL_EPT_RSVD_15_SHIFT 15 +#define VMX_BF_EXIT_QUAL_EPT_RSVD_15_MASK UINT64_C(0x0000000000008000) +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_PT_TRACE_SHIFT 16 +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_PT_TRACE_MASK UINT64_C(0x0000000000010000) +#define VMX_BF_EXIT_QUAL_EPT_RSVD_17_63_SHIFT 17 +#define VMX_BF_EXIT_QUAL_EPT_RSVD_17_63_MASK UINT64_C(0xfffffffffffe0000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_EPT_, UINT64_C(0), UINT64_MAX, + (ACCESS_READ, ACCESS_WRITE, ACCESS_INSTR_FETCH, ENTRY_READ, ENTRY_WRITE, ENTRY_EXECUTE, + ENTRY_EXECUTE_USER, LINEAR_ADDR_VALID, LINEAR_TO_PHYS_ADDR, LINEAR_ADDR_USER, LINEAR_ADDR_RO, + LINEAR_ADDR_XD, NMI_UNBLOCK_IRET, ACCESS_SHW_STACK, ENTRY_SHW_STACK_SUPER, RSVD_15, + ACCESS_PT_TRACE, RSVD_17_63)); +/** @} */ + + +/** @name Exit qualification for I/O instructions. + * @{ + */ +/** 0-2: IO operation size 0(=1 byte), 1(=2 bytes) and 3(=4 bytes). */ +#define VMX_EXIT_QUAL_IO_SIZE(a) ((a) & 7) +/** 3: IO operation direction. */ +#define VMX_EXIT_QUAL_IO_DIRECTION(a) (((a) >> 3) & 1) +/** 4: String IO operation (INS / OUTS). */ +#define VMX_EXIT_QUAL_IO_IS_STRING(a) (((a) >> 4) & 1) +/** 5: Repeated IO operation. */ +#define VMX_EXIT_QUAL_IO_IS_REP(a) (((a) >> 5) & 1) +/** 6: Operand encoding. */ +#define VMX_EXIT_QUAL_IO_ENCODING(a) (((a) >> 6) & 1) +/** 16-31: IO Port (0-0xffff). */ +#define VMX_EXIT_QUAL_IO_PORT(a) (((a) >> 16) & 0xffff) + +/** Bit fields for Exit qualification for I/O instructions. */ +#define VMX_BF_EXIT_QUAL_IO_WIDTH_SHIFT 0 +#define VMX_BF_EXIT_QUAL_IO_WIDTH_MASK UINT64_C(0x0000000000000007) +#define VMX_BF_EXIT_QUAL_IO_DIRECTION_SHIFT 3 +#define VMX_BF_EXIT_QUAL_IO_DIRECTION_MASK UINT64_C(0x0000000000000008) +#define VMX_BF_EXIT_QUAL_IO_IS_STRING_SHIFT 4 +#define VMX_BF_EXIT_QUAL_IO_IS_STRING_MASK UINT64_C(0x0000000000000010) +#define VMX_BF_EXIT_QUAL_IO_IS_REP_SHIFT 5 +#define VMX_BF_EXIT_QUAL_IO_IS_REP_MASK UINT64_C(0x0000000000000020) +#define VMX_BF_EXIT_QUAL_IO_ENCODING_SHIFT 6 +#define VMX_BF_EXIT_QUAL_IO_ENCODING_MASK UINT64_C(0x0000000000000040) +#define VMX_BF_EXIT_QUAL_IO_RSVD_7_15_SHIFT 7 +#define VMX_BF_EXIT_QUAL_IO_RSVD_7_15_MASK UINT64_C(0x000000000000ff80) +#define VMX_BF_EXIT_QUAL_IO_PORT_SHIFT 16 +#define VMX_BF_EXIT_QUAL_IO_PORT_MASK UINT64_C(0x00000000ffff0000) +#define VMX_BF_EXIT_QUAL_IO_RSVD_32_63_SHIFT 32 +#define VMX_BF_EXIT_QUAL_IO_RSVD_32_63_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_IO_, UINT64_C(0), UINT64_MAX, + (WIDTH, DIRECTION, IS_STRING, IS_REP, ENCODING, RSVD_7_15, PORT, RSVD_32_63)); +/** @} */ + + +/** @name Exit qualification for I/O instruction types. + * @{ + */ +#define VMX_EXIT_QUAL_IO_DIRECTION_OUT 0 +#define VMX_EXIT_QUAL_IO_DIRECTION_IN 1 +/** @} */ + + +/** @name Exit qualification for I/O instruction encoding. + * @{ + */ +#define VMX_EXIT_QUAL_IO_ENCODING_DX 0 +#define VMX_EXIT_QUAL_IO_ENCODING_IMM 1 +/** @} */ + + +/** @name Exit qualification for APIC-access VM-exits from linear and + * guest-physical accesses. + * @{ + */ +/** 0-11: If the APIC-access VM-exit is due to a linear access, the offset of + * access within the APIC page. */ +#define VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(a) ((a) & 0xfff) +/** 12-15: Access type. */ +#define VMX_EXIT_QUAL_APIC_ACCESS_TYPE(a) (((a) & 0xf000) >> 12) +/* Rest reserved. */ + +/** Bit fields for Exit qualification for APIC-access VM-exits. */ +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_OFFSET_SHIFT 0 +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_OFFSET_MASK UINT64_C(0x0000000000000fff) +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_TYPE_SHIFT 12 +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_TYPE_MASK UINT64_C(0x000000000000f000) +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_RSVD_16_63_SHIFT 16 +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_RSVD_16_63_MASK UINT64_C(0xffffffffffff0000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_APIC_ACCESS_, UINT64_C(0), UINT64_MAX, + (OFFSET, TYPE, RSVD_16_63)); +/** @} */ + + +/** @name Exit qualification for linear address APIC-access types. + * @{ + */ +/** Linear access for a data read during instruction execution. */ +#define VMX_APIC_ACCESS_TYPE_LINEAR_READ 0 +/** Linear access for a data write during instruction execution. */ +#define VMX_APIC_ACCESS_TYPE_LINEAR_WRITE 1 +/** Linear access for an instruction fetch. */ +#define VMX_APIC_ACCESS_TYPE_LINEAR_INSTR_FETCH 2 +/** Linear read/write access during event delivery. */ +#define VMX_APIC_ACCESS_TYPE_LINEAR_EVENT_DELIVERY 3 +/** Physical read/write access during event delivery. */ +#define VMX_APIC_ACCESS_TYPE_PHYSICAL_EVENT_DELIVERY 10 +/** Physical access for an instruction fetch or during instruction execution. */ +#define VMX_APIC_ACCESS_TYPE_PHYSICAL_INSTR 15 + +/** + * APIC-access type. + * In accordance with the VT-x spec. + */ +typedef enum +{ + VMXAPICACCESS_LINEAR_READ = VMX_APIC_ACCESS_TYPE_LINEAR_READ, + VMXAPICACCESS_LINEAR_WRITE = VMX_APIC_ACCESS_TYPE_LINEAR_WRITE, + VMXAPICACCESS_LINEAR_INSTR_FETCH = VMX_APIC_ACCESS_TYPE_LINEAR_INSTR_FETCH, + VMXAPICACCESS_LINEAR_EVENT_DELIVERY = VMX_APIC_ACCESS_TYPE_LINEAR_EVENT_DELIVERY, + VMXAPICACCESS_PHYSICAL_EVENT_DELIVERY = VMX_APIC_ACCESS_TYPE_PHYSICAL_EVENT_DELIVERY, + VMXAPICACCESS_PHYSICAL_INSTR = VMX_APIC_ACCESS_TYPE_PHYSICAL_INSTR +} VMXAPICACCESS; +AssertCompileSize(VMXAPICACCESS, 4); +/** @} */ + + +/** @name VMX_BF_XXTR_INSINFO_XXX - VMX_EXIT_XDTR_ACCESS instruction information. + * Found in VMX_VMCS32_RO_EXIT_INSTR_INFO. + * @{ + */ +/** Address calculation scaling field (powers of two). */ +#define VMX_BF_XDTR_INSINFO_SCALE_SHIFT 0 +#define VMX_BF_XDTR_INSINFO_SCALE_MASK UINT32_C(0x00000003) +/** Bits 2 thru 6 are undefined. */ +#define VMX_BF_XDTR_INSINFO_UNDEF_2_6_SHIFT 2 +#define VMX_BF_XDTR_INSINFO_UNDEF_2_6_MASK UINT32_C(0x0000007c) +/** Address size, only 0(=16), 1(=32) and 2(=64) are defined. + * @remarks anyone's guess why this is a 3 bit field... */ +#define VMX_BF_XDTR_INSINFO_ADDR_SIZE_SHIFT 7 +#define VMX_BF_XDTR_INSINFO_ADDR_SIZE_MASK UINT32_C(0x00000380) +/** Bit 10 is defined as zero. */ +#define VMX_BF_XDTR_INSINFO_ZERO_10_SHIFT 10 +#define VMX_BF_XDTR_INSINFO_ZERO_10_MASK UINT32_C(0x00000400) +/** Operand size, either (1=)32-bit or (0=)16-bit, but get this, it's undefined + * for exits from 64-bit code as the operand size there is fixed. */ +#define VMX_BF_XDTR_INSINFO_OP_SIZE_SHIFT 11 +#define VMX_BF_XDTR_INSINFO_OP_SIZE_MASK UINT32_C(0x00000800) +/** Bits 12 thru 14 are undefined. */ +#define VMX_BF_XDTR_INSINFO_UNDEF_12_14_SHIFT 12 +#define VMX_BF_XDTR_INSINFO_UNDEF_12_14_MASK UINT32_C(0x00007000) +/** Applicable segment register (X86_SREG_XXX values). */ +#define VMX_BF_XDTR_INSINFO_SREG_SHIFT 15 +#define VMX_BF_XDTR_INSINFO_SREG_MASK UINT32_C(0x00038000) +/** Index register (X86_GREG_XXX values). Undefined if HAS_INDEX_REG is clear. */ +#define VMX_BF_XDTR_INSINFO_INDEX_REG_SHIFT 18 +#define VMX_BF_XDTR_INSINFO_INDEX_REG_MASK UINT32_C(0x003c0000) +/** Is VMX_BF_XDTR_INSINFO_INDEX_REG_XXX valid (=1) or not (=0). */ +#define VMX_BF_XDTR_INSINFO_HAS_INDEX_REG_SHIFT 22 +#define VMX_BF_XDTR_INSINFO_HAS_INDEX_REG_MASK UINT32_C(0x00400000) +/** Base register (X86_GREG_XXX values). Undefined if HAS_BASE_REG is clear. */ +#define VMX_BF_XDTR_INSINFO_BASE_REG_SHIFT 23 +#define VMX_BF_XDTR_INSINFO_BASE_REG_MASK UINT32_C(0x07800000) +/** Is VMX_XDTR_INSINFO_BASE_REG_XXX valid (=1) or not (=0). */ +#define VMX_BF_XDTR_INSINFO_HAS_BASE_REG_SHIFT 27 +#define VMX_BF_XDTR_INSINFO_HAS_BASE_REG_MASK UINT32_C(0x08000000) +/** The instruction identity (VMX_XDTR_INSINFO_II_XXX values). */ +#define VMX_BF_XDTR_INSINFO_INSTR_ID_SHIFT 28 +#define VMX_BF_XDTR_INSINFO_INSTR_ID_MASK UINT32_C(0x30000000) +#define VMX_XDTR_INSINFO_II_SGDT 0 /**< Instruction ID: SGDT */ +#define VMX_XDTR_INSINFO_II_SIDT 1 /**< Instruction ID: SIDT */ +#define VMX_XDTR_INSINFO_II_LGDT 2 /**< Instruction ID: LGDT */ +#define VMX_XDTR_INSINFO_II_LIDT 3 /**< Instruction ID: LIDT */ +/** Bits 30 & 31 are undefined. */ +#define VMX_BF_XDTR_INSINFO_UNDEF_30_31_SHIFT 30 +#define VMX_BF_XDTR_INSINFO_UNDEF_30_31_MASK UINT32_C(0xc0000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_XDTR_INSINFO_, UINT32_C(0), UINT32_MAX, + (SCALE, UNDEF_2_6, ADDR_SIZE, ZERO_10, OP_SIZE, UNDEF_12_14, SREG, INDEX_REG, HAS_INDEX_REG, + BASE_REG, HAS_BASE_REG, INSTR_ID, UNDEF_30_31)); +/** @} */ + + +/** @name VMX_BF_YYTR_INSINFO_XXX - VMX_EXIT_TR_ACCESS instruction information. + * Found in VMX_VMCS32_RO_EXIT_INSTR_INFO. + * This is similar to VMX_BF_XDTR_INSINFO_XXX. + * @{ + */ +/** Address calculation scaling field (powers of two). */ +#define VMX_BF_YYTR_INSINFO_SCALE_SHIFT 0 +#define VMX_BF_YYTR_INSINFO_SCALE_MASK UINT32_C(0x00000003) +/** Bit 2 is undefined. */ +#define VMX_BF_YYTR_INSINFO_UNDEF_2_SHIFT 2 +#define VMX_BF_YYTR_INSINFO_UNDEF_2_MASK UINT32_C(0x00000004) +/** Register operand 1. Undefined if VMX_YYTR_INSINFO_HAS_REG1 is clear. */ +#define VMX_BF_YYTR_INSINFO_REG1_SHIFT 3 +#define VMX_BF_YYTR_INSINFO_REG1_MASK UINT32_C(0x00000078) +/** Address size, only 0(=16), 1(=32) and 2(=64) are defined. + * @remarks anyone's guess why this is a 3 bit field... */ +#define VMX_BF_YYTR_INSINFO_ADDR_SIZE_SHIFT 7 +#define VMX_BF_YYTR_INSINFO_ADDR_SIZE_MASK UINT32_C(0x00000380) +/** Is VMX_YYTR_INSINFO_REG1_XXX valid (=1) or not (=0). */ +#define VMX_BF_YYTR_INSINFO_HAS_REG1_SHIFT 10 +#define VMX_BF_YYTR_INSINFO_HAS_REG1_MASK UINT32_C(0x00000400) +/** Bits 11 thru 14 are undefined. */ +#define VMX_BF_YYTR_INSINFO_UNDEF_11_14_SHIFT 11 +#define VMX_BF_YYTR_INSINFO_UNDEF_11_14_MASK UINT32_C(0x00007800) +/** Applicable segment register (X86_SREG_XXX values). */ +#define VMX_BF_YYTR_INSINFO_SREG_SHIFT 15 +#define VMX_BF_YYTR_INSINFO_SREG_MASK UINT32_C(0x00038000) +/** Index register (X86_GREG_XXX values). Undefined if HAS_INDEX_REG is clear. */ +#define VMX_BF_YYTR_INSINFO_INDEX_REG_SHIFT 18 +#define VMX_BF_YYTR_INSINFO_INDEX_REG_MASK UINT32_C(0x003c0000) +/** Is VMX_YYTR_INSINFO_INDEX_REG_XXX valid (=1) or not (=0). */ +#define VMX_BF_YYTR_INSINFO_HAS_INDEX_REG_SHIFT 22 +#define VMX_BF_YYTR_INSINFO_HAS_INDEX_REG_MASK UINT32_C(0x00400000) +/** Base register (X86_GREG_XXX values). Undefined if HAS_BASE_REG is clear. */ +#define VMX_BF_YYTR_INSINFO_BASE_REG_SHIFT 23 +#define VMX_BF_YYTR_INSINFO_BASE_REG_MASK UINT32_C(0x07800000) +/** Is VMX_YYTR_INSINFO_BASE_REG_XXX valid (=1) or not (=0). */ +#define VMX_BF_YYTR_INSINFO_HAS_BASE_REG_SHIFT 27 +#define VMX_BF_YYTR_INSINFO_HAS_BASE_REG_MASK UINT32_C(0x08000000) +/** The instruction identity (VMX_YYTR_INSINFO_II_XXX values) */ +#define VMX_BF_YYTR_INSINFO_INSTR_ID_SHIFT 28 +#define VMX_BF_YYTR_INSINFO_INSTR_ID_MASK UINT32_C(0x30000000) +#define VMX_YYTR_INSINFO_II_SLDT 0 /**< Instruction ID: SLDT */ +#define VMX_YYTR_INSINFO_II_STR 1 /**< Instruction ID: STR */ +#define VMX_YYTR_INSINFO_II_LLDT 2 /**< Instruction ID: LLDT */ +#define VMX_YYTR_INSINFO_II_LTR 3 /**< Instruction ID: LTR */ +/** Bits 30 & 31 are undefined. */ +#define VMX_BF_YYTR_INSINFO_UNDEF_30_31_SHIFT 30 +#define VMX_BF_YYTR_INSINFO_UNDEF_30_31_MASK UINT32_C(0xc0000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_YYTR_INSINFO_, UINT32_C(0), UINT32_MAX, + (SCALE, UNDEF_2, REG1, ADDR_SIZE, HAS_REG1, UNDEF_11_14, SREG, INDEX_REG, HAS_INDEX_REG, + BASE_REG, HAS_BASE_REG, INSTR_ID, UNDEF_30_31)); +/** @} */ + + +/** @name Format of Pending-Debug-Exceptions. + * Bits 4-11, 13, 15 and 17-63 are reserved. + * Similar to DR6 except bit 12 (breakpoint enabled) and bit 16 (RTM) are both + * possibly valid here but not in DR6. + * @{ + */ +/** Hardware breakpoint 0 was met. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP0 RT_BIT_64(0) +/** Hardware breakpoint 1 was met. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP1 RT_BIT_64(1) +/** Hardware breakpoint 2 was met. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP2 RT_BIT_64(2) +/** Hardware breakpoint 3 was met. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP3 RT_BIT_64(3) +/** At least one data or IO breakpoint was hit. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_EN_BP RT_BIT_64(12) +/** A debug exception would have been triggered by single-step execution mode. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS RT_BIT_64(14) +/** A debug exception occurred inside an RTM region. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_RTM RT_BIT_64(16) +/** Mask of valid bits. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_VALID_MASK ( VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP0 \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP1 \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP2 \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP3 \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_EN_BP \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS \ + | VMX_VMCS_GUEST_PENDING_DEBUG_RTM) +#define VMX_VMCS_GUEST_PENDING_DEBUG_RTM_MASK ( VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_EN_BP \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS \ + | VMX_VMCS_GUEST_PENDING_DEBUG_RTM) +/** Bit fields for Pending debug exceptions. */ +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP0_SHIFT 0 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP0_MASK UINT64_C(0x0000000000000001) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP1_SHIFT 1 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP1_MASK UINT64_C(0x0000000000000002) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP2_SHIFT 2 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP2_MASK UINT64_C(0x0000000000000004) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP3_SHIFT 3 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP3_MASK UINT64_C(0x0000000000000008) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_4_11_SHIFT 4 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_4_11_MASK UINT64_C(0x0000000000000ff0) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_EN_BP_SHIFT 12 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_EN_BP_MASK UINT64_C(0x0000000000001000) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_13_SHIFT 13 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_13_MASK UINT64_C(0x0000000000002000) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BS_SHIFT 14 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BS_MASK UINT64_C(0x0000000000004000) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_15_SHIFT 15 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_15_MASK UINT64_C(0x0000000000008000) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RTM_SHIFT 16 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RTM_MASK UINT64_C(0x0000000000010000) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_17_63_SHIFT 17 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_17_63_MASK UINT64_C(0xfffffffffffe0000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_VMCS_PENDING_DBG_XCPT_, UINT64_C(0), UINT64_MAX, + (BP0, BP1, BP2, BP3, RSVD_4_11, EN_BP, RSVD_13, BS, RSVD_15, RTM, RSVD_17_63)); +/** @} */ + + +/** + * VM-exit auxiliary information. + * + * This includes information that isn't necessarily stored in the guest-CPU + * context but provided as part of VM-exits. + */ +typedef struct +{ + /** The VM-exit reason. */ + uint32_t uReason; + /** The Exit qualification field. */ + uint64_t u64Qual; + /** The Guest-linear address field. */ + uint64_t u64GuestLinearAddr; + /** The Guest-physical address field. */ + uint64_t u64GuestPhysAddr; + /** The guest pending-debug exceptions. */ + uint64_t u64GuestPendingDbgXcpts; + /** The VM-exit instruction length. */ + uint32_t cbInstr; + /** The VM-exit instruction information. */ + VMXEXITINSTRINFO InstrInfo; + /** VM-exit interruption information. */ + uint32_t uExitIntInfo; + /** VM-exit interruption error code. */ + uint32_t uExitIntErrCode; + /** IDT-vectoring information. */ + uint32_t uIdtVectoringInfo; + /** IDT-vectoring error code. */ + uint32_t uIdtVectoringErrCode; +} VMXEXITAUX; +/** Pointer to a VMXEXITAUX struct. */ +typedef VMXEXITAUX *PVMXEXITAUX; +/** Pointer to a const VMXEXITAUX struct. */ +typedef const VMXEXITAUX *PCVMXEXITAUX; + + +/** @defgroup grp_hm_vmx_virt VMX virtualization. + * @{ + */ + +/** @name Virtual VMX MSR - Miscellaneous data. + * @{ */ +/** Number of CR3-target values supported. */ +#define VMX_V_CR3_TARGET_COUNT 4 +/** Activity states supported. */ +#define VMX_V_GUEST_ACTIVITY_STATE_MASK (VMX_VMCS_GUEST_ACTIVITY_HLT | VMX_VMCS_GUEST_ACTIVITY_SHUTDOWN) +/** VMX preemption-timer shift (Core i7-2600 taken as reference). */ +#define VMX_V_PREEMPT_TIMER_SHIFT 5 +/** Maximum number of MSRs in the auto-load/store MSR areas, (n+1) * 512. */ +#define VMX_V_AUTOMSR_COUNT_MAX 0 +/** SMM MSEG revision ID. */ +#define VMX_V_MSEG_REV_ID 0 +/** @} */ + +/** @name VMX_V_VMCS_STATE_XXX - Virtual VMCS launch state. + * @{ */ +/** VMCS launch state clear. */ +#define VMX_V_VMCS_LAUNCH_STATE_CLEAR RT_BIT(0) +/** VMCS launch state active. */ +#define VMX_V_VMCS_LAUNCH_STATE_ACTIVE RT_BIT(1) +/** VMCS launch state current. */ +#define VMX_V_VMCS_LAUNCH_STATE_CURRENT RT_BIT(2) +/** VMCS launch state launched. */ +#define VMX_V_VMCS_LAUNCH_STATE_LAUNCHED RT_BIT(3) +/** The mask of valid VMCS launch states. */ +#define VMX_V_VMCS_LAUNCH_STATE_MASK ( VMX_V_VMCS_LAUNCH_STATE_CLEAR \ + | VMX_V_VMCS_LAUNCH_STATE_ACTIVE \ + | VMX_V_VMCS_LAUNCH_STATE_CURRENT \ + | VMX_V_VMCS_LAUNCH_STATE_LAUNCHED) +/** @} */ + +/** CR0 bits set here must always be set when in VMX operation. */ +#define VMX_V_CR0_FIXED0 (X86_CR0_PE | X86_CR0_NE | X86_CR0_PG) +/** CR0 bits set here must always be set when in VMX non-root operation with + * unrestricted-guest control enabled. */ +#define VMX_V_CR0_FIXED0_UX (X86_CR0_NE) +/** CR0 bits cleared here must always be cleared when in VMX operation. */ +#define VMX_V_CR0_FIXED1 UINT32_C(0xffffffff) +/** CR4 bits set here must always be set when in VMX operation. */ +#define VMX_V_CR4_FIXED0 (X86_CR4_VMXE) + +/** Virtual VMCS revision ID. Bump this arbitarily chosen identifier if incompatible + * changes to the layout of VMXVVMCS is done. Bit 31 MBZ. */ +#define VMX_V_VMCS_REVISION_ID UINT32_C(0x40000001) +AssertCompile(!(VMX_V_VMCS_REVISION_ID & RT_BIT(31))); + +/** The size of the virtual VMCS region (we use the maximum allowed size to avoid + * complications when teleporation may be implemented). */ +#define VMX_V_VMCS_SIZE X86_PAGE_4K_SIZE +/** The size of the virtual VMCS region (in pages). */ +#define VMX_V_VMCS_PAGES 1 + +/** The size of the virtual shadow VMCS region. */ +#define VMX_V_SHADOW_VMCS_SIZE VMX_V_VMCS_SIZE +/** The size of the virtual shadow VMCS region (in pages). */ +#define VMX_V_SHADOW_VMCS_PAGES VMX_V_VMCS_PAGES + +/** The size of the Virtual-APIC page (in bytes). */ +#define VMX_V_VIRT_APIC_SIZE X86_PAGE_4K_SIZE +/** The size of the Virtual-APIC page (in pages). */ +#define VMX_V_VIRT_APIC_PAGES 1 + +/** The size of the VMREAD/VMWRITE bitmap (in bytes). */ +#define VMX_V_VMREAD_VMWRITE_BITMAP_SIZE X86_PAGE_4K_SIZE +/** The size of the VMREAD/VMWRITE-bitmap (in pages). */ +#define VMX_V_VMREAD_VMWRITE_BITMAP_PAGES 1 + +/** The size of the MSR bitmap (in bytes). */ +#define VMX_V_MSR_BITMAP_SIZE X86_PAGE_4K_SIZE +/** The size of the MSR bitmap (in pages). */ +#define VMX_V_MSR_BITMAP_PAGES 1 + +/** The size of I/O bitmap A (in bytes). */ +#define VMX_V_IO_BITMAP_A_SIZE X86_PAGE_4K_SIZE +/** The size of I/O bitmap A (in pages). */ +#define VMX_V_IO_BITMAP_A_PAGES 1 + +/** The size of I/O bitmap B (in bytes). */ +#define VMX_V_IO_BITMAP_B_SIZE X86_PAGE_4K_SIZE +/** The size of I/O bitmap B (in pages). */ +#define VMX_V_IO_BITMAP_B_PAGES 1 + +/** The size of the auto-load/store MSR area (in bytes). */ +#define VMX_V_AUTOMSR_AREA_SIZE ((512 * (VMX_V_AUTOMSR_COUNT_MAX + 1)) * sizeof(VMXAUTOMSR)) +/* Assert that the size is page aligned or adjust the VMX_V_AUTOMSR_AREA_PAGES macro below. */ +AssertCompile(RT_ALIGN_Z(VMX_V_AUTOMSR_AREA_SIZE, X86_PAGE_4K_SIZE) == VMX_V_AUTOMSR_AREA_SIZE); +/** The size of the auto-load/store MSR area (in pages). */ +#define VMX_V_AUTOMSR_AREA_PAGES ((VMX_V_AUTOMSR_AREA_SIZE) >> X86_PAGE_4K_SHIFT) + +/** The highest index value used for supported virtual VMCS field encoding. */ +#define VMX_V_VMCS_MAX_INDEX RT_BF_GET(VMX_VMCS64_CTRL_EXIT2_HIGH, VMX_BF_VMCSFIELD_INDEX) + +/** + * Virtual VM-exit information. + * + * This is a convenience structure that bundles some VM-exit information related + * fields together. + */ +typedef struct +{ + /** The VM-exit reason. */ + uint32_t uReason; + /** The VM-exit instruction length. */ + uint32_t cbInstr; + /** The VM-exit instruction information. */ + VMXEXITINSTRINFO InstrInfo; + /** The VM-exit instruction ID. */ + VMXINSTRID uInstrId; + + /** The Exit qualification field. */ + uint64_t u64Qual; + /** The Guest-linear address field. */ + uint64_t u64GuestLinearAddr; + /** The Guest-physical address field. */ + uint64_t u64GuestPhysAddr; + /** The guest pending-debug exceptions. */ + uint64_t u64GuestPendingDbgXcpts; + /** The effective guest-linear address if @a InstrInfo indicates a memory-based + * instruction VM-exit. */ + RTGCPTR GCPtrEffAddr; +} VMXVEXITINFO; +/** Pointer to the VMXVEXITINFO struct. */ +typedef VMXVEXITINFO *PVMXVEXITINFO; +/** Pointer to a const VMXVEXITINFO struct. */ +typedef const VMXVEXITINFO *PCVMXVEXITINFO; +AssertCompileMemberAlignment(VMXVEXITINFO, u64Qual, 8); + +/** Initialize a VMXVEXITINFO structure from only an exit reason. */ +#define VMXVEXITINFO_INIT_ONLY_REASON(a_uReason) \ + { (a_uReason), 0, { 0 }, VMXINSTRID_NONE, 0, 0, 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason and instruction length (no info). */ +#define VMXVEXITINFO_INIT_WITH_INSTR_LEN(a_uReason, a_cbInstr) \ + { (a_uReason), (a_cbInstr), { 0 }, VMXINSTRID_NONE, 0, 0, 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason and exit qualification. */ +#define VMXVEXITINFO_INIT_WITH_QUAL(a_uReason, a_uQual) \ + { (a_uReason), 0, { 0 }, VMXINSTRID_NONE, (a_uQual), 0, 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction info and length. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO(a_uReason, a_uQual, a_uInstrInfo, a_cbInstr) \ + { (a_uReason), (a_cbInstr), { a_uInstrInfo }, VMXINSTRID_NONE, (a_uQual), 0, 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction info and length all copied from a VMXTRANSIENT structure. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_FROM_TRANSIENT(a_pVmxTransient) \ + VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO((a_pVmxTransient)->uExitReason, \ + (a_pVmxTransient)->uExitQual, \ + (a_pVmxTransient)->ExitInstrInfo.u, \ + (a_pVmxTransient)->cbExitInstr) + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction length (no info). */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN(a_uReason, a_uQual, a_cbInstr) \ + { (a_uReason), (a_cbInstr), { 0 }, VMXINSTRID_NONE, (a_uQual), 0, 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification and + * instruction length (no info) all copied from a VMXTRANSIENT structure. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN_FROM_TRANSIENT(a_pVmxTransient) \ + VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN((a_pVmxTransient)->uExitReason, \ + (a_pVmxTransient)->uExitQual, \ + (a_pVmxTransient)->cbExitInstr) + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction info, instruction length and guest linear address. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_AND_LIN_ADDR(a_uReason, a_uQual, a_uInstrInfo, \ + a_cbInstr, a_uGstLinAddr) \ + { (a_uReason), (a_cbInstr), { (a_uInstrInfo) }, VMXINSTRID_NONE, (a_uQual), (a_uGstLinAddr), 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction info, instruction length and guest linear address all copied + * from a VMXTRANSIENT structure. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_AND_LIN_ADDR_FROM_TRANSIENT(a_pVmxTransient) \ + VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_AND_LIN_ADDR((a_pVmxTransient)->uExitReason, \ + (a_pVmxTransient)->uExitQual, \ + (a_pVmxTransient)->ExitInstrInfo.u, \ + (a_pVmxTransient)->cbExitInstr, \ + (a_pVmxTransient)->uGuestLinearAddr) + +/** Initialize a VMXVEXITINFO structure from exit reason and pending debug + * exceptions. */ +#define VMXVEXITINFO_INIT_WITH_DBG_XCPTS(a_uReason, a_uPendingDbgXcpts) \ + { (a_uReason), 0, { 0 }, VMXINSTRID_NONE, 0, 0, 0, (a_uPendingDbgXcpts), 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason and pending debug + * exceptions both copied from a VMXTRANSIENT structure. */ +#define VMXVEXITINFO_INIT_WITH_DBG_XCPTS_FROM_TRANSIENT(a_pVmxTransient) \ + VMXVEXITINFO_INIT_WITH_DBG_XCPTS((a_pVmxTransient)->uExitReason, (a_pVmxTransient)->uGuestPendingDbgXcpts) + + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction length, guest linear address and guest physical address. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN_AND_GST_ADDRESSES(a_uReason, a_uQual, a_cbInstr, \ + a_uGstLinAddr, a_uGstPhysAddr) \ + { (a_uReason), (a_cbInstr), { 0 }, VMXINSTRID_NONE, (a_uQual), (a_uGstLinAddr), (a_uGstPhysAddr), 0, 0 } + + +/** + * Virtual VM-exit information for events. + * + * This is a convenience structure that bundles some event-based VM-exit information + * related fields together that are not included in VMXVEXITINFO. + * + * This is kept as a separate structure and not included in VMXVEXITINFO, to make it + * easier to distinguish that IEM VM-exit handlers will set one or more of the + * following fields in the virtual VMCS. Including it in the VMXVEXITINFO will not + * make it ovbious which fields may get set (or cleared). + */ +typedef struct +{ + /** VM-exit interruption information. */ + uint32_t uExitIntInfo; + /** VM-exit interruption error code. */ + uint32_t uExitIntErrCode; + /** IDT-vectoring information. */ + uint32_t uIdtVectoringInfo; + /** IDT-vectoring error code. */ + uint32_t uIdtVectoringErrCode; +} VMXVEXITEVENTINFO; +/** Pointer to the VMXVEXITEVENTINFO struct. */ +typedef VMXVEXITEVENTINFO *PVMXVEXITEVENTINFO; +/** Pointer to a const VMXVEXITEVENTINFO struct. */ +typedef const VMXVEXITEVENTINFO *PCVMXVEXITEVENTINFO; + +/** Initialize a VMXVEXITEVENTINFO. */ +#define VMXVEXITEVENTINFO_INIT(a_uExitIntInfo, a_uExitIntErrCode, a_uIdtVectoringInfo, a_uIdtVectoringErrCode) \ + { (a_uExitIntInfo), (a_uExitIntErrCode), (a_uIdtVectoringInfo), (a_uIdtVectoringErrCode) } + +/** Initialize a VMXVEXITEVENTINFO with VM-exit interruption info and VM-exit + * interruption error code. */ +#define VMXVEXITEVENTINFO_INIT_ONLY_INT(a_uExitIntInfo, a_uExitIntErrCode) \ + VMXVEXITEVENTINFO_INIT(a_uExitIntInfo, a_uExitIntErrCode, 0, 0) + +/** Initialize a VMXVEXITEVENTINFO with IDT vectoring info and IDT + * vectoring error code. */ +#define VMXVEXITEVENTINFO_INIT_ONLY_IDT(a_uIdtVectoringInfo, a_uIdtVectoringErrCode) \ + VMXVEXITEVENTINFO_INIT(0, 0, a_uIdtVectoringInfo, a_uIdtVectoringErrCode) + +/** + * Virtual VMCS. + * + * This is our custom format. Relevant fields from this VMCS will be merged into the + * actual/shadow VMCS when we execute nested-guest code using hardware-assisted + * VMX. + * + * The first 8 bytes must be in accordance with the Intel VT-x spec. + * See Intel spec. 24.2 "Format of the VMCS Region". + * + * The offset and size of the VMCS state field (@a fVmcsState) is also fixed (not by + * the Intel spec. but for our own requirements) as we use it to offset into guest + * memory. + * + * Although the guest is supposed to access the VMCS only through the execution of + * VMX instructions (VMREAD, VMWRITE etc.), since the VMCS may reside in guest + * memory (e.g, active but not current VMCS), for saved-states compatibility, and + * for teleportation purposes, any newly added fields should be added to the + * appropriate reserved sections or at the end of the structure. + * + * We always treat natural-width fields as 64-bit in our implementation since + * it's easier, allows for teleporation in the future and does not affect guest + * software. + * + * @note Any fields that are added or modified here, make sure to update the + * corresponding fields in IEM (g_aoffVmcsMap), the corresponding saved + * state structure in CPUM (g_aVmxHwvirtVmcs) and bump the SSM version. + * Also consider updating CPUMIsGuestVmxVmcsFieldValid and cpumR3InfoVmxVmcs. + */ +#pragma pack(1) +typedef struct +{ + /** @name Header. + * @{ + */ + VMXVMCSREVID u32VmcsRevId; /**< 0x000 - VMX VMCS revision identifier. */ + VMXABORT enmVmxAbort; /**< 0x004 - VMX-abort indicator. */ + uint8_t fVmcsState; /**< 0x008 - VMCS launch state, see VMX_V_VMCS_LAUNCH_STATE_XXX. */ + uint8_t au8Padding0[3]; /**< 0x009 - Reserved for future. */ + uint32_t au32Reserved0[12]; /**< 0x00c - Reserved for future. */ + /** @} */ + + /** @name Read-only fields. + * @{ */ + /** 16-bit fields. */ + uint16_t u16Reserved0[14]; /**< 0x03c - Reserved for future. */ + + /** 32-bit fields. */ + uint32_t u32RoVmInstrError; /**< 0x058 - VM-instruction error. */ + uint32_t u32RoExitReason; /**< 0x05c - VM-exit reason. */ + uint32_t u32RoExitIntInfo; /**< 0x060 - VM-exit interruption information. */ + uint32_t u32RoExitIntErrCode; /**< 0x064 - VM-exit interruption error code. */ + uint32_t u32RoIdtVectoringInfo; /**< 0x068 - IDT-vectoring information. */ + uint32_t u32RoIdtVectoringErrCode; /**< 0x06c - IDT-vectoring error code. */ + uint32_t u32RoExitInstrLen; /**< 0x070 - VM-exit instruction length. */ + uint32_t u32RoExitInstrInfo; /**< 0x074 - VM-exit instruction information. */ + uint32_t au32RoReserved2[16]; /**< 0x078 - Reserved for future. */ + + /** 64-bit fields. */ + RTUINT64U u64RoGuestPhysAddr; /**< 0x0b8 - Guest-physical address. */ + RTUINT64U au64Reserved1[8]; /**< 0x0c0 - Reserved for future. */ + + /** Natural-width fields. */ + RTUINT64U u64RoExitQual; /**< 0x100 - Exit qualification. */ + RTUINT64U u64RoIoRcx; /**< 0x108 - I/O RCX. */ + RTUINT64U u64RoIoRsi; /**< 0x110 - I/O RSI. */ + RTUINT64U u64RoIoRdi; /**< 0x118 - I/O RDI. */ + RTUINT64U u64RoIoRip; /**< 0x120 - I/O RIP. */ + RTUINT64U u64RoGuestLinearAddr; /**< 0x128 - Guest-linear address. */ + RTUINT64U au64Reserved5[16]; /**< 0x130 - Reserved for future. */ + /** @} */ + + /** @name Control fields. + * @{ */ + /** 16-bit fields. */ + uint16_t u16Vpid; /**< 0x1b0 - Virtual processor ID. */ + uint16_t u16PostIntNotifyVector; /**< 0x1b2 - Posted interrupt notify vector. */ + uint16_t u16EptpIndex; /**< 0x1b4 - EPTP index. */ + uint16_t u16HlatPrefixSize; /**< 0x1b6 - HLAT prefix size. */ + uint16_t au16Reserved0[12]; /**< 0x1b8 - Reserved for future. */ + + /** 32-bit fields. */ + uint32_t u32PinCtls; /**< 0x1d0 - Pin-based VM-execution controls. */ + uint32_t u32ProcCtls; /**< 0x1d4 - Processor-based VM-execution controls. */ + uint32_t u32XcptBitmap; /**< 0x1d8 - Exception bitmap. */ + uint32_t u32XcptPFMask; /**< 0x1dc - Page-fault exception error mask. */ + uint32_t u32XcptPFMatch; /**< 0x1e0 - Page-fault exception error match. */ + uint32_t u32Cr3TargetCount; /**< 0x1e4 - CR3-target count. */ + uint32_t u32ExitCtls; /**< 0x1e8 - VM-exit controls. */ + uint32_t u32ExitMsrStoreCount; /**< 0x1ec - VM-exit MSR store count. */ + uint32_t u32ExitMsrLoadCount; /**< 0x1f0 - VM-exit MSR load count. */ + uint32_t u32EntryCtls; /**< 0x1f4 - VM-entry controls. */ + uint32_t u32EntryMsrLoadCount; /**< 0x1f8 - VM-entry MSR load count. */ + uint32_t u32EntryIntInfo; /**< 0x1fc - VM-entry interruption information. */ + uint32_t u32EntryXcptErrCode; /**< 0x200 - VM-entry exception error code. */ + uint32_t u32EntryInstrLen; /**< 0x204 - VM-entry instruction length. */ + uint32_t u32TprThreshold; /**< 0x208 - TPR-threshold. */ + uint32_t u32ProcCtls2; /**< 0x20c - Secondary-processor based VM-execution controls. */ + uint32_t u32PleGap; /**< 0x210 - Pause-loop exiting Gap. */ + uint32_t u32PleWindow; /**< 0x214 - Pause-loop exiting Window. */ + uint32_t au32Reserved1[16]; /**< 0x218 - Reserved for future. */ + + /** 64-bit fields. */ + RTUINT64U u64AddrIoBitmapA; /**< 0x258 - I/O bitmap A address. */ + RTUINT64U u64AddrIoBitmapB; /**< 0x260 - I/O bitmap B address. */ + RTUINT64U u64AddrMsrBitmap; /**< 0x268 - MSR bitmap address. */ + RTUINT64U u64AddrExitMsrStore; /**< 0x270 - VM-exit MSR-store area address. */ + RTUINT64U u64AddrExitMsrLoad; /**< 0x278 - VM-exit MSR-load area address. */ + RTUINT64U u64AddrEntryMsrLoad; /**< 0x280 - VM-entry MSR-load area address. */ + RTUINT64U u64ExecVmcsPtr; /**< 0x288 - Executive-VMCS pointer. */ + RTUINT64U u64AddrPml; /**< 0x290 - Page-modification log address (PML). */ + RTUINT64U u64TscOffset; /**< 0x298 - TSC offset. */ + RTUINT64U u64AddrVirtApic; /**< 0x2a0 - Virtual-APIC address. */ + RTUINT64U u64AddrApicAccess; /**< 0x2a8 - APIC-access address. */ + RTUINT64U u64AddrPostedIntDesc; /**< 0x2b0 - Posted-interrupt descriptor address. */ + RTUINT64U u64VmFuncCtls; /**< 0x2b8 - VM-functions control. */ + RTUINT64U u64EptPtr; /**< 0x2c0 - EPT pointer. */ + RTUINT64U u64EoiExitBitmap0; /**< 0x2c8 - EOI-exit bitmap 0. */ + RTUINT64U u64EoiExitBitmap1; /**< 0x2d0 - EOI-exit bitmap 1. */ + RTUINT64U u64EoiExitBitmap2; /**< 0x2d8 - EOI-exit bitmap 2. */ + RTUINT64U u64EoiExitBitmap3; /**< 0x2e0 - EOI-exit bitmap 3. */ + RTUINT64U u64AddrEptpList; /**< 0x2e8 - EPTP-list address. */ + RTUINT64U u64AddrVmreadBitmap; /**< 0x2f0 - VMREAD-bitmap address. */ + RTUINT64U u64AddrVmwriteBitmap; /**< 0x2f8 - VMWRITE-bitmap address. */ + RTUINT64U u64AddrXcptVeInfo; /**< 0x300 - Virtualization-exception information address. */ + RTUINT64U u64XssExitBitmap; /**< 0x308 - XSS-exiting bitmap. */ + RTUINT64U u64EnclsExitBitmap; /**< 0x310 - ENCLS-exiting bitmap address. */ + RTUINT64U u64SppTablePtr; /**< 0x318 - Sub-page-permission-table pointer (SPPTP). */ + RTUINT64U u64TscMultiplier; /**< 0x320 - TSC multiplier. */ + RTUINT64U u64ProcCtls3; /**< 0x328 - Tertiary-Processor based VM-execution controls. */ + RTUINT64U u64EnclvExitBitmap; /**< 0x330 - ENCLV-exiting bitmap. */ + RTUINT64U u64PconfigExitBitmap; /**< 0x338 - PCONFIG-exiting bitmap. */ + RTUINT64U u64HlatPtr; /**< 0x340 - HLAT pointer. */ + RTUINT64U u64ExitCtls2; /**< 0x348 - Secondary VM-exit controls. */ + RTUINT64U au64Reserved0[10]; /**< 0x350 - Reserved for future. */ + + /** Natural-width fields. */ + RTUINT64U u64Cr0Mask; /**< 0x3a0 - CR0 guest/host Mask. */ + RTUINT64U u64Cr4Mask; /**< 0x3a8 - CR4 guest/host Mask. */ + RTUINT64U u64Cr0ReadShadow; /**< 0x3b0 - CR0 read shadow. */ + RTUINT64U u64Cr4ReadShadow; /**< 0x3b8 - CR4 read shadow. */ + RTUINT64U u64Cr3Target0; /**< 0x3c0 - CR3-target value 0. */ + RTUINT64U u64Cr3Target1; /**< 0x3c8 - CR3-target value 1. */ + RTUINT64U u64Cr3Target2; /**< 0x3d0 - CR3-target value 2. */ + RTUINT64U u64Cr3Target3; /**< 0x3d8 - CR3-target value 3. */ + RTUINT64U au64Reserved4[32]; /**< 0x3e0 - Reserved for future. */ + /** @} */ + + /** @name Host-state fields. + * @{ */ + /** 16-bit fields. */ + /* Order of [Es..Gs] fields below must match [X86_SREG_ES..X86_SREG_GS]. */ + RTSEL HostEs; /**< 0x4e0 - Host ES selector. */ + RTSEL HostCs; /**< 0x4e2 - Host CS selector. */ + RTSEL HostSs; /**< 0x4e4 - Host SS selector. */ + RTSEL HostDs; /**< 0x4e6 - Host DS selector. */ + RTSEL HostFs; /**< 0x4e8 - Host FS selector. */ + RTSEL HostGs; /**< 0x4ea - Host GS selector. */ + RTSEL HostTr; /**< 0x4ec - Host TR selector. */ + uint16_t au16Reserved2[13]; /**< 0x4ee - Reserved for future. */ + + /** 32-bit fields. */ + uint32_t u32HostSysenterCs; /**< 0x508 - Host SYSENTER CS. */ + uint32_t au32Reserved4[11]; /**< 0x50c - Reserved for future. */ + + /** 64-bit fields. */ + RTUINT64U u64HostPatMsr; /**< 0x538 - Host PAT MSR. */ + RTUINT64U u64HostEferMsr; /**< 0x540 - Host EFER MSR. */ + RTUINT64U u64HostPerfGlobalCtlMsr; /**< 0x548 - Host global performance-control MSR. */ + RTUINT64U u64HostPkrsMsr; /**< 0x550 - Host PKRS MSR. */ + RTUINT64U au64Reserved3[15]; /**< 0x558 - Reserved for future. */ + + /** Natural-width fields. */ + RTUINT64U u64HostCr0; /**< 0x5d0 - Host CR0. */ + RTUINT64U u64HostCr3; /**< 0x5d8 - Host CR3. */ + RTUINT64U u64HostCr4; /**< 0x5e0 - Host CR4. */ + RTUINT64U u64HostFsBase; /**< 0x5e8 - Host FS base. */ + RTUINT64U u64HostGsBase; /**< 0x5f0 - Host GS base. */ + RTUINT64U u64HostTrBase; /**< 0x5f8 - Host TR base. */ + RTUINT64U u64HostGdtrBase; /**< 0x600 - Host GDTR base. */ + RTUINT64U u64HostIdtrBase; /**< 0x608 - Host IDTR base. */ + RTUINT64U u64HostSysenterEsp; /**< 0x610 - Host SYSENTER ESP base. */ + RTUINT64U u64HostSysenterEip; /**< 0x618 - Host SYSENTER ESP base. */ + RTUINT64U u64HostRsp; /**< 0x620 - Host RSP. */ + RTUINT64U u64HostRip; /**< 0x628 - Host RIP. */ + RTUINT64U u64HostSCetMsr; /**< 0x630 - Host S_CET MSR. */ + RTUINT64U u64HostSsp; /**< 0x638 - Host SSP. */ + RTUINT64U u64HostIntrSspTableAddrMsr; /**< 0x640 - Host Interrupt SSP table address MSR. */ + RTUINT64U au64Reserved7[29]; /**< 0x648 - Reserved for future. */ + /** @} */ + + /** @name Guest-state fields. + * @{ */ + /** 16-bit fields. */ + /* Order of [Es..Gs] fields below must match [X86_SREG_ES..X86_SREG_GS]. */ + RTSEL GuestEs; /**< 0x730 - Guest ES selector. */ + RTSEL GuestCs; /**< 0x732 - Guest ES selector. */ + RTSEL GuestSs; /**< 0x734 - Guest ES selector. */ + RTSEL GuestDs; /**< 0x736 - Guest ES selector. */ + RTSEL GuestFs; /**< 0x738 - Guest ES selector. */ + RTSEL GuestGs; /**< 0x73a - Guest ES selector. */ + RTSEL GuestLdtr; /**< 0x73c - Guest LDTR selector. */ + RTSEL GuestTr; /**< 0x73e - Guest TR selector. */ + uint16_t u16GuestIntStatus; /**< 0x740 - Guest interrupt status (virtual-interrupt delivery). */ + uint16_t u16PmlIndex; /**< 0x742 - PML index. */ + uint16_t au16Reserved1[14]; /**< 0x744 - Reserved for future. */ + + /** 32-bit fields. */ + /* Order of [Es..Gs] fields below must match [X86_SREG_ES..X86_SREG_GS]. */ + uint32_t u32GuestEsLimit; /**< 0x760 - Guest ES limit. */ + uint32_t u32GuestCsLimit; /**< 0x764 - Guest CS limit. */ + uint32_t u32GuestSsLimit; /**< 0x768 - Guest SS limit. */ + uint32_t u32GuestDsLimit; /**< 0x76c - Guest DS limit. */ + uint32_t u32GuestFsLimit; /**< 0x770 - Guest FS limit. */ + uint32_t u32GuestGsLimit; /**< 0x774 - Guest GS limit. */ + uint32_t u32GuestLdtrLimit; /**< 0x778 - Guest LDTR limit. */ + uint32_t u32GuestTrLimit; /**< 0x77c - Guest TR limit. */ + uint32_t u32GuestGdtrLimit; /**< 0x780 - Guest GDTR limit. */ + uint32_t u32GuestIdtrLimit; /**< 0x784 - Guest IDTR limit. */ + uint32_t u32GuestEsAttr; /**< 0x788 - Guest ES attributes. */ + uint32_t u32GuestCsAttr; /**< 0x78c - Guest CS attributes. */ + uint32_t u32GuestSsAttr; /**< 0x790 - Guest SS attributes. */ + uint32_t u32GuestDsAttr; /**< 0x794 - Guest DS attributes. */ + uint32_t u32GuestFsAttr; /**< 0x798 - Guest FS attributes. */ + uint32_t u32GuestGsAttr; /**< 0x79c - Guest GS attributes. */ + uint32_t u32GuestLdtrAttr; /**< 0x7a0 - Guest LDTR attributes. */ + uint32_t u32GuestTrAttr; /**< 0x7a4 - Guest TR attributes. */ + uint32_t u32GuestIntrState; /**< 0x7a8 - Guest interruptibility state. */ + uint32_t u32GuestActivityState; /**< 0x7ac - Guest activity state. */ + uint32_t u32GuestSmBase; /**< 0x7b0 - Guest SMBASE. */ + uint32_t u32GuestSysenterCS; /**< 0x7b4 - Guest SYSENTER CS. */ + uint32_t u32PreemptTimer; /**< 0x7b8 - Preemption timer value. */ + uint32_t au32Reserved3[11]; /**< 0x7bc - Reserved for future. */ + + /** 64-bit fields. */ + RTUINT64U u64VmcsLinkPtr; /**< 0x7e8 - VMCS link pointer. */ + RTUINT64U u64GuestDebugCtlMsr; /**< 0x7f0 - Guest debug-control MSR. */ + RTUINT64U u64GuestPatMsr; /**< 0x7f8 - Guest PAT MSR. */ + RTUINT64U u64GuestEferMsr; /**< 0x800 - Guest EFER MSR. */ + RTUINT64U u64GuestPerfGlobalCtlMsr; /**< 0x808 - Guest global performance-control MSR. */ + RTUINT64U u64GuestPdpte0; /**< 0x810 - Guest PDPTE 0. */ + RTUINT64U u64GuestPdpte1; /**< 0x818 - Guest PDPTE 0. */ + RTUINT64U u64GuestPdpte2; /**< 0x820 - Guest PDPTE 1. */ + RTUINT64U u64GuestPdpte3; /**< 0x828 - Guest PDPTE 2. */ + RTUINT64U u64GuestBndcfgsMsr; /**< 0x830 - Guest Bounds config MPX MSR (Intel Memory Protection Extensions). */ + RTUINT64U u64GuestRtitCtlMsr; /**< 0x838 - Guest RTIT control MSR (Intel Real Time Instruction Trace). */ + RTUINT64U u64GuestPkrsMsr; /**< 0x840 - Guest PKRS MSR. */ + RTUINT64U au64Reserved2[31]; /**< 0x848 - Reserved for future. */ + + /** Natural-width fields. */ + RTUINT64U u64GuestCr0; /**< 0x940 - Guest CR0. */ + RTUINT64U u64GuestCr3; /**< 0x948 - Guest CR3. */ + RTUINT64U u64GuestCr4; /**< 0x950 - Guest CR4. */ + RTUINT64U u64GuestEsBase; /**< 0x958 - Guest ES base. */ + RTUINT64U u64GuestCsBase; /**< 0x960 - Guest CS base. */ + RTUINT64U u64GuestSsBase; /**< 0x968 - Guest SS base. */ + RTUINT64U u64GuestDsBase; /**< 0x970 - Guest DS base. */ + RTUINT64U u64GuestFsBase; /**< 0x978 - Guest FS base. */ + RTUINT64U u64GuestGsBase; /**< 0x980 - Guest GS base. */ + RTUINT64U u64GuestLdtrBase; /**< 0x988 - Guest LDTR base. */ + RTUINT64U u64GuestTrBase; /**< 0x990 - Guest TR base. */ + RTUINT64U u64GuestGdtrBase; /**< 0x998 - Guest GDTR base. */ + RTUINT64U u64GuestIdtrBase; /**< 0x9a0 - Guest IDTR base. */ + RTUINT64U u64GuestDr7; /**< 0x9a8 - Guest DR7. */ + RTUINT64U u64GuestRsp; /**< 0x9b0 - Guest RSP. */ + RTUINT64U u64GuestRip; /**< 0x9b8 - Guest RIP. */ + RTUINT64U u64GuestRFlags; /**< 0x9c0 - Guest RFLAGS. */ + RTUINT64U u64GuestPendingDbgXcpts; /**< 0x9c8 - Guest pending debug exceptions. */ + RTUINT64U u64GuestSysenterEsp; /**< 0x9d0 - Guest SYSENTER ESP. */ + RTUINT64U u64GuestSysenterEip; /**< 0x9d8 - Guest SYSENTER EIP. */ + RTUINT64U u64GuestSCetMsr; /**< 0x9e0 - Guest S_CET MSR. */ + RTUINT64U u64GuestSsp; /**< 0x9e8 - Guest SSP. */ + RTUINT64U u64GuestIntrSspTableAddrMsr; /**< 0x9f0 - Guest Interrupt SSP table address MSR. */ + RTUINT64U au64Reserved6[29]; /**< 0x9f8 - Reserved for future. */ + /** @} */ + + /** 0xae0 - Padding / reserved for future use. */ + uint8_t abPadding[X86_PAGE_4K_SIZE - 0xae0]; +} VMXVVMCS; +#pragma pack() +/** Pointer to the VMXVVMCS struct. */ +typedef VMXVVMCS *PVMXVVMCS; +/** Pointer to a const VMXVVMCS struct. */ +typedef const VMXVVMCS *PCVMXVVMCS; +AssertCompileSize(VMXVVMCS, X86_PAGE_4K_SIZE); +AssertCompileMemberSize(VMXVVMCS, fVmcsState, sizeof(uint8_t)); +AssertCompileMemberOffset(VMXVVMCS, enmVmxAbort, 0x004); +AssertCompileMemberOffset(VMXVVMCS, fVmcsState, 0x008); +AssertCompileMemberOffset(VMXVVMCS, u32RoVmInstrError, 0x058); +AssertCompileMemberOffset(VMXVVMCS, u64RoGuestPhysAddr, 0x0b8); +AssertCompileMemberOffset(VMXVVMCS, u64RoExitQual, 0x100); +AssertCompileMemberOffset(VMXVVMCS, u16Vpid, 0x1b0); +AssertCompileMemberOffset(VMXVVMCS, u32PinCtls, 0x1d0); +AssertCompileMemberOffset(VMXVVMCS, u64AddrIoBitmapA, 0x258); +AssertCompileMemberOffset(VMXVVMCS, u64Cr0Mask, 0x3a0); +AssertCompileMemberOffset(VMXVVMCS, HostEs, 0x4e0); +AssertCompileMemberOffset(VMXVVMCS, u32HostSysenterCs, 0x508); +AssertCompileMemberOffset(VMXVVMCS, u64HostPatMsr, 0x538); +AssertCompileMemberOffset(VMXVVMCS, u64HostCr0, 0x5d0); +AssertCompileMemberOffset(VMXVVMCS, GuestEs, 0x730); +AssertCompileMemberOffset(VMXVVMCS, u32GuestEsLimit, 0x760); +AssertCompileMemberOffset(VMXVVMCS, u64VmcsLinkPtr, 0x7e8); +AssertCompileMemberOffset(VMXVVMCS, u64GuestCr0, 0x940); + +/** + * Virtual VMX-instruction and VM-exit diagnostics. + * + * These are not the same as VM instruction errors that are enumerated in the Intel + * spec. These are purely internal, fine-grained definitions used for diagnostic + * purposes and are not reported to guest software under the VM-instruction error + * field in its VMCS. + * + * @note Members of this enum are used as array indices, so no gaps are allowed. + * Please update g_apszVmxVDiagDesc when you add new fields to this enum. + */ +typedef enum +{ + /* Internal processing errors. */ + kVmxVDiag_None = 0, + kVmxVDiag_Ipe_1, + kVmxVDiag_Ipe_2, + kVmxVDiag_Ipe_3, + kVmxVDiag_Ipe_4, + kVmxVDiag_Ipe_5, + kVmxVDiag_Ipe_6, + kVmxVDiag_Ipe_7, + kVmxVDiag_Ipe_8, + kVmxVDiag_Ipe_9, + kVmxVDiag_Ipe_10, + kVmxVDiag_Ipe_11, + kVmxVDiag_Ipe_12, + kVmxVDiag_Ipe_13, + kVmxVDiag_Ipe_14, + kVmxVDiag_Ipe_15, + kVmxVDiag_Ipe_16, + /* VMXON. */ + kVmxVDiag_Vmxon_A20M, + kVmxVDiag_Vmxon_Cpl, + kVmxVDiag_Vmxon_Cr0Fixed0, + kVmxVDiag_Vmxon_Cr0Fixed1, + kVmxVDiag_Vmxon_Cr4Fixed0, + kVmxVDiag_Vmxon_Cr4Fixed1, + kVmxVDiag_Vmxon_Intercept, + kVmxVDiag_Vmxon_LongModeCS, + kVmxVDiag_Vmxon_MsrFeatCtl, + kVmxVDiag_Vmxon_PtrAbnormal, + kVmxVDiag_Vmxon_PtrAlign, + kVmxVDiag_Vmxon_PtrMap, + kVmxVDiag_Vmxon_PtrReadPhys, + kVmxVDiag_Vmxon_PtrWidth, + kVmxVDiag_Vmxon_RealOrV86Mode, + kVmxVDiag_Vmxon_ShadowVmcs, + kVmxVDiag_Vmxon_VmxAlreadyRoot, + kVmxVDiag_Vmxon_Vmxe, + kVmxVDiag_Vmxon_VmcsRevId, + kVmxVDiag_Vmxon_VmxRootCpl, + /* VMXOFF. */ + kVmxVDiag_Vmxoff_Cpl, + kVmxVDiag_Vmxoff_Intercept, + kVmxVDiag_Vmxoff_LongModeCS, + kVmxVDiag_Vmxoff_RealOrV86Mode, + kVmxVDiag_Vmxoff_Vmxe, + kVmxVDiag_Vmxoff_VmxRoot, + /* VMPTRLD. */ + kVmxVDiag_Vmptrld_Cpl, + kVmxVDiag_Vmptrld_LongModeCS, + kVmxVDiag_Vmptrld_PtrAbnormal, + kVmxVDiag_Vmptrld_PtrAlign, + kVmxVDiag_Vmptrld_PtrMap, + kVmxVDiag_Vmptrld_PtrReadPhys, + kVmxVDiag_Vmptrld_PtrVmxon, + kVmxVDiag_Vmptrld_PtrWidth, + kVmxVDiag_Vmptrld_RealOrV86Mode, + kVmxVDiag_Vmptrld_RevPtrReadPhys, + kVmxVDiag_Vmptrld_ShadowVmcs, + kVmxVDiag_Vmptrld_VmcsRevId, + kVmxVDiag_Vmptrld_VmxRoot, + /* VMPTRST. */ + kVmxVDiag_Vmptrst_Cpl, + kVmxVDiag_Vmptrst_LongModeCS, + kVmxVDiag_Vmptrst_PtrMap, + kVmxVDiag_Vmptrst_RealOrV86Mode, + kVmxVDiag_Vmptrst_VmxRoot, + /* VMCLEAR. */ + kVmxVDiag_Vmclear_Cpl, + kVmxVDiag_Vmclear_LongModeCS, + kVmxVDiag_Vmclear_PtrAbnormal, + kVmxVDiag_Vmclear_PtrAlign, + kVmxVDiag_Vmclear_PtrMap, + kVmxVDiag_Vmclear_PtrReadPhys, + kVmxVDiag_Vmclear_PtrVmxon, + kVmxVDiag_Vmclear_PtrWidth, + kVmxVDiag_Vmclear_RealOrV86Mode, + kVmxVDiag_Vmclear_VmxRoot, + /* VMWRITE. */ + kVmxVDiag_Vmwrite_Cpl, + kVmxVDiag_Vmwrite_FieldInvalid, + kVmxVDiag_Vmwrite_FieldRo, + kVmxVDiag_Vmwrite_LinkPtrInvalid, + kVmxVDiag_Vmwrite_LongModeCS, + kVmxVDiag_Vmwrite_PtrInvalid, + kVmxVDiag_Vmwrite_PtrMap, + kVmxVDiag_Vmwrite_RealOrV86Mode, + kVmxVDiag_Vmwrite_VmxRoot, + /* VMREAD. */ + kVmxVDiag_Vmread_Cpl, + kVmxVDiag_Vmread_FieldInvalid, + kVmxVDiag_Vmread_LinkPtrInvalid, + kVmxVDiag_Vmread_LongModeCS, + kVmxVDiag_Vmread_PtrInvalid, + kVmxVDiag_Vmread_PtrMap, + kVmxVDiag_Vmread_RealOrV86Mode, + kVmxVDiag_Vmread_VmxRoot, + /* INVVPID. */ + kVmxVDiag_Invvpid_Cpl, + kVmxVDiag_Invvpid_DescRsvd, + kVmxVDiag_Invvpid_LongModeCS, + kVmxVDiag_Invvpid_RealOrV86Mode, + kVmxVDiag_Invvpid_TypeInvalid, + kVmxVDiag_Invvpid_Type0InvalidAddr, + kVmxVDiag_Invvpid_Type0InvalidVpid, + kVmxVDiag_Invvpid_Type1InvalidVpid, + kVmxVDiag_Invvpid_Type3InvalidVpid, + kVmxVDiag_Invvpid_VmxRoot, + /* INVEPT. */ + kVmxVDiag_Invept_Cpl, + kVmxVDiag_Invept_DescRsvd, + kVmxVDiag_Invept_EptpInvalid, + kVmxVDiag_Invept_LongModeCS, + kVmxVDiag_Invept_RealOrV86Mode, + kVmxVDiag_Invept_TypeInvalid, + kVmxVDiag_Invept_VmxRoot, + /* VMLAUNCH/VMRESUME. */ + kVmxVDiag_Vmentry_AddrApicAccess, + kVmxVDiag_Vmentry_AddrApicAccessEqVirtApic, + kVmxVDiag_Vmentry_AddrApicAccessHandlerReg, + kVmxVDiag_Vmentry_AddrEntryMsrLoad, + kVmxVDiag_Vmentry_AddrExitMsrLoad, + kVmxVDiag_Vmentry_AddrExitMsrStore, + kVmxVDiag_Vmentry_AddrIoBitmapA, + kVmxVDiag_Vmentry_AddrIoBitmapB, + kVmxVDiag_Vmentry_AddrMsrBitmap, + kVmxVDiag_Vmentry_AddrVirtApicPage, + kVmxVDiag_Vmentry_AddrVmcsLinkPtr, + kVmxVDiag_Vmentry_AddrVmreadBitmap, + kVmxVDiag_Vmentry_AddrVmwriteBitmap, + kVmxVDiag_Vmentry_ApicRegVirt, + kVmxVDiag_Vmentry_BlocKMovSS, + kVmxVDiag_Vmentry_Cpl, + kVmxVDiag_Vmentry_Cr3TargetCount, + kVmxVDiag_Vmentry_EntryCtlsAllowed1, + kVmxVDiag_Vmentry_EntryCtlsDisallowed0, + kVmxVDiag_Vmentry_EntryInstrLen, + kVmxVDiag_Vmentry_EntryInstrLenZero, + kVmxVDiag_Vmentry_EntryIntInfoErrCodePe, + kVmxVDiag_Vmentry_EntryIntInfoErrCodeVec, + kVmxVDiag_Vmentry_EntryIntInfoTypeVecRsvd, + kVmxVDiag_Vmentry_EntryXcptErrCodeRsvd, + kVmxVDiag_Vmentry_EptpAccessDirty, + kVmxVDiag_Vmentry_EptpPageWalkLength, + kVmxVDiag_Vmentry_EptpMemType, + kVmxVDiag_Vmentry_EptpRsvd, + kVmxVDiag_Vmentry_ExitCtlsAllowed1, + kVmxVDiag_Vmentry_ExitCtlsDisallowed0, + kVmxVDiag_Vmentry_GuestActStateHlt, + kVmxVDiag_Vmentry_GuestActStateRsvd, + kVmxVDiag_Vmentry_GuestActStateShutdown, + kVmxVDiag_Vmentry_GuestActStateSsDpl, + kVmxVDiag_Vmentry_GuestActStateStiMovSs, + kVmxVDiag_Vmentry_GuestCr0Fixed0, + kVmxVDiag_Vmentry_GuestCr0Fixed1, + kVmxVDiag_Vmentry_GuestCr0PgPe, + kVmxVDiag_Vmentry_GuestCr3, + kVmxVDiag_Vmentry_GuestCr4Fixed0, + kVmxVDiag_Vmentry_GuestCr4Fixed1, + kVmxVDiag_Vmentry_GuestDebugCtl, + kVmxVDiag_Vmentry_GuestDr7, + kVmxVDiag_Vmentry_GuestEferMsr, + kVmxVDiag_Vmentry_GuestEferMsrRsvd, + kVmxVDiag_Vmentry_GuestGdtrBase, + kVmxVDiag_Vmentry_GuestGdtrLimit, + kVmxVDiag_Vmentry_GuestIdtrBase, + kVmxVDiag_Vmentry_GuestIdtrLimit, + kVmxVDiag_Vmentry_GuestIntStateEnclave, + kVmxVDiag_Vmentry_GuestIntStateExtInt, + kVmxVDiag_Vmentry_GuestIntStateNmi, + kVmxVDiag_Vmentry_GuestIntStateRFlagsSti, + kVmxVDiag_Vmentry_GuestIntStateRsvd, + kVmxVDiag_Vmentry_GuestIntStateSmi, + kVmxVDiag_Vmentry_GuestIntStateStiMovSs, + kVmxVDiag_Vmentry_GuestIntStateVirtNmi, + kVmxVDiag_Vmentry_GuestPae, + kVmxVDiag_Vmentry_GuestPatMsr, + kVmxVDiag_Vmentry_GuestPcide, + kVmxVDiag_Vmentry_GuestPdpte, + kVmxVDiag_Vmentry_GuestPndDbgXcptBsNoTf, + kVmxVDiag_Vmentry_GuestPndDbgXcptBsTf, + kVmxVDiag_Vmentry_GuestPndDbgXcptRsvd, + kVmxVDiag_Vmentry_GuestPndDbgXcptRtm, + kVmxVDiag_Vmentry_GuestRip, + kVmxVDiag_Vmentry_GuestRipRsvd, + kVmxVDiag_Vmentry_GuestRFlagsIf, + kVmxVDiag_Vmentry_GuestRFlagsRsvd, + kVmxVDiag_Vmentry_GuestRFlagsVm, + kVmxVDiag_Vmentry_GuestSegAttrCsDefBig, + kVmxVDiag_Vmentry_GuestSegAttrCsDplEqSs, + kVmxVDiag_Vmentry_GuestSegAttrCsDplLtSs, + kVmxVDiag_Vmentry_GuestSegAttrCsDplZero, + kVmxVDiag_Vmentry_GuestSegAttrCsType, + kVmxVDiag_Vmentry_GuestSegAttrCsTypeRead, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeCs, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeDs, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeEs, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeFs, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeGs, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeSs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplCs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplDs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplEs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplFs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplGs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplSs, + kVmxVDiag_Vmentry_GuestSegAttrGranCs, + kVmxVDiag_Vmentry_GuestSegAttrGranDs, + kVmxVDiag_Vmentry_GuestSegAttrGranEs, + kVmxVDiag_Vmentry_GuestSegAttrGranFs, + kVmxVDiag_Vmentry_GuestSegAttrGranGs, + kVmxVDiag_Vmentry_GuestSegAttrGranSs, + kVmxVDiag_Vmentry_GuestSegAttrLdtrDescType, + kVmxVDiag_Vmentry_GuestSegAttrLdtrGran, + kVmxVDiag_Vmentry_GuestSegAttrLdtrPresent, + kVmxVDiag_Vmentry_GuestSegAttrLdtrRsvd, + kVmxVDiag_Vmentry_GuestSegAttrLdtrType, + kVmxVDiag_Vmentry_GuestSegAttrPresentCs, + kVmxVDiag_Vmentry_GuestSegAttrPresentDs, + kVmxVDiag_Vmentry_GuestSegAttrPresentEs, + kVmxVDiag_Vmentry_GuestSegAttrPresentFs, + kVmxVDiag_Vmentry_GuestSegAttrPresentGs, + kVmxVDiag_Vmentry_GuestSegAttrPresentSs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdCs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdDs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdEs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdFs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdGs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdSs, + kVmxVDiag_Vmentry_GuestSegAttrSsDplEqRpl, + kVmxVDiag_Vmentry_GuestSegAttrSsDplZero, + kVmxVDiag_Vmentry_GuestSegAttrSsType, + kVmxVDiag_Vmentry_GuestSegAttrTrDescType, + kVmxVDiag_Vmentry_GuestSegAttrTrGran, + kVmxVDiag_Vmentry_GuestSegAttrTrPresent, + kVmxVDiag_Vmentry_GuestSegAttrTrRsvd, + kVmxVDiag_Vmentry_GuestSegAttrTrType, + kVmxVDiag_Vmentry_GuestSegAttrTrUnusable, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccCs, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccDs, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccEs, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccFs, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccGs, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccSs, + kVmxVDiag_Vmentry_GuestSegAttrV86Cs, + kVmxVDiag_Vmentry_GuestSegAttrV86Ds, + kVmxVDiag_Vmentry_GuestSegAttrV86Es, + kVmxVDiag_Vmentry_GuestSegAttrV86Fs, + kVmxVDiag_Vmentry_GuestSegAttrV86Gs, + kVmxVDiag_Vmentry_GuestSegAttrV86Ss, + kVmxVDiag_Vmentry_GuestSegBaseCs, + kVmxVDiag_Vmentry_GuestSegBaseDs, + kVmxVDiag_Vmentry_GuestSegBaseEs, + kVmxVDiag_Vmentry_GuestSegBaseFs, + kVmxVDiag_Vmentry_GuestSegBaseGs, + kVmxVDiag_Vmentry_GuestSegBaseLdtr, + kVmxVDiag_Vmentry_GuestSegBaseSs, + kVmxVDiag_Vmentry_GuestSegBaseTr, + kVmxVDiag_Vmentry_GuestSegBaseV86Cs, + kVmxVDiag_Vmentry_GuestSegBaseV86Ds, + kVmxVDiag_Vmentry_GuestSegBaseV86Es, + kVmxVDiag_Vmentry_GuestSegBaseV86Fs, + kVmxVDiag_Vmentry_GuestSegBaseV86Gs, + kVmxVDiag_Vmentry_GuestSegBaseV86Ss, + kVmxVDiag_Vmentry_GuestSegLimitV86Cs, + kVmxVDiag_Vmentry_GuestSegLimitV86Ds, + kVmxVDiag_Vmentry_GuestSegLimitV86Es, + kVmxVDiag_Vmentry_GuestSegLimitV86Fs, + kVmxVDiag_Vmentry_GuestSegLimitV86Gs, + kVmxVDiag_Vmentry_GuestSegLimitV86Ss, + kVmxVDiag_Vmentry_GuestSegSelCsSsRpl, + kVmxVDiag_Vmentry_GuestSegSelLdtr, + kVmxVDiag_Vmentry_GuestSegSelTr, + kVmxVDiag_Vmentry_GuestSysenterEspEip, + kVmxVDiag_Vmentry_VmcsLinkPtrCurVmcs, + kVmxVDiag_Vmentry_VmcsLinkPtrReadPhys, + kVmxVDiag_Vmentry_VmcsLinkPtrRevId, + kVmxVDiag_Vmentry_VmcsLinkPtrShadow, + kVmxVDiag_Vmentry_HostCr0Fixed0, + kVmxVDiag_Vmentry_HostCr0Fixed1, + kVmxVDiag_Vmentry_HostCr3, + kVmxVDiag_Vmentry_HostCr4Fixed0, + kVmxVDiag_Vmentry_HostCr4Fixed1, + kVmxVDiag_Vmentry_HostCr4Pae, + kVmxVDiag_Vmentry_HostCr4Pcide, + kVmxVDiag_Vmentry_HostCsTr, + kVmxVDiag_Vmentry_HostEferMsr, + kVmxVDiag_Vmentry_HostEferMsrRsvd, + kVmxVDiag_Vmentry_HostGuestLongMode, + kVmxVDiag_Vmentry_HostGuestLongModeNoCpu, + kVmxVDiag_Vmentry_HostLongMode, + kVmxVDiag_Vmentry_HostPatMsr, + kVmxVDiag_Vmentry_HostRip, + kVmxVDiag_Vmentry_HostRipRsvd, + kVmxVDiag_Vmentry_HostSel, + kVmxVDiag_Vmentry_HostSegBase, + kVmxVDiag_Vmentry_HostSs, + kVmxVDiag_Vmentry_HostSysenterEspEip, + kVmxVDiag_Vmentry_IoBitmapAPtrReadPhys, + kVmxVDiag_Vmentry_IoBitmapBPtrReadPhys, + kVmxVDiag_Vmentry_LongModeCS, + kVmxVDiag_Vmentry_MsrBitmapPtrReadPhys, + kVmxVDiag_Vmentry_MsrLoad, + kVmxVDiag_Vmentry_MsrLoadCount, + kVmxVDiag_Vmentry_MsrLoadPtrReadPhys, + kVmxVDiag_Vmentry_MsrLoadRing3, + kVmxVDiag_Vmentry_MsrLoadRsvd, + kVmxVDiag_Vmentry_NmiWindowExit, + kVmxVDiag_Vmentry_PinCtlsAllowed1, + kVmxVDiag_Vmentry_PinCtlsDisallowed0, + kVmxVDiag_Vmentry_ProcCtlsAllowed1, + kVmxVDiag_Vmentry_ProcCtlsDisallowed0, + kVmxVDiag_Vmentry_ProcCtls2Allowed1, + kVmxVDiag_Vmentry_ProcCtls2Disallowed0, + kVmxVDiag_Vmentry_PtrInvalid, + kVmxVDiag_Vmentry_PtrShadowVmcs, + kVmxVDiag_Vmentry_RealOrV86Mode, + kVmxVDiag_Vmentry_SavePreemptTimer, + kVmxVDiag_Vmentry_TprThresholdRsvd, + kVmxVDiag_Vmentry_TprThresholdVTpr, + kVmxVDiag_Vmentry_VirtApicPagePtrReadPhys, + kVmxVDiag_Vmentry_VirtIntDelivery, + kVmxVDiag_Vmentry_VirtNmi, + kVmxVDiag_Vmentry_VirtX2ApicTprShadow, + kVmxVDiag_Vmentry_VirtX2ApicVirtApic, + kVmxVDiag_Vmentry_VmcsClear, + kVmxVDiag_Vmentry_VmcsLaunch, + kVmxVDiag_Vmentry_VmreadBitmapPtrReadPhys, + kVmxVDiag_Vmentry_VmwriteBitmapPtrReadPhys, + kVmxVDiag_Vmentry_VmxRoot, + kVmxVDiag_Vmentry_Vpid, + kVmxVDiag_Vmexit_HostPdpte, + kVmxVDiag_Vmexit_MsrLoad, + kVmxVDiag_Vmexit_MsrLoadCount, + kVmxVDiag_Vmexit_MsrLoadPtrReadPhys, + kVmxVDiag_Vmexit_MsrLoadRing3, + kVmxVDiag_Vmexit_MsrLoadRsvd, + kVmxVDiag_Vmexit_MsrStore, + kVmxVDiag_Vmexit_MsrStoreCount, + kVmxVDiag_Vmexit_MsrStorePtrReadPhys, + kVmxVDiag_Vmexit_MsrStorePtrWritePhys, + kVmxVDiag_Vmexit_MsrStoreRing3, + kVmxVDiag_Vmexit_MsrStoreRsvd, + kVmxVDiag_Vmexit_VirtApicPagePtrWritePhys, + /* Last member for determining array index limit. */ + kVmxVDiag_End +} VMXVDIAG; +AssertCompileSize(VMXVDIAG, 4); + +/** @} */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_hm_vmx_h */ + diff --git a/include/VBox/vmm/hm_vmx.mac b/include/VBox/vmm/hm_vmx.mac new file mode 100644 index 00000000..15373887 --- /dev/null +++ b/include/VBox/vmm/hm_vmx.mac @@ -0,0 +1,163 @@ +;; @file +; HM - VMX Structures and Definitions. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%define VMX_VMCS_GUEST_FIELD_ES 0800h +%define VMX_VMCS_GUEST_FIELD_CS 0802h +%define VMX_VMCS_GUEST_FIELD_SS 0804h +%define VMX_VMCS_GUEST_FIELD_DS 0806h +%define VMX_VMCS_GUEST_FIELD_FS 0808h +%define VMX_VMCS_GUEST_FIELD_GS 080Ah +%define VMX_VMCS_GUEST_FIELD_LDTR 080Ch +%define VMX_VMCS_GUEST_FIELD_TR 080Eh +%define VMX_VMCS_HOST_FIELD_ES 0C00h +%define VMX_VMCS_HOST_FIELD_CS 0C02h +%define VMX_VMCS_HOST_FIELD_SS 0C04h +%define VMX_VMCS_HOST_FIELD_DS 0C06h +%define VMX_VMCS_HOST_FIELD_FS 0C08h +%define VMX_VMCS_HOST_FIELD_GS 0C0Ah +%define VMX_VMCS_HOST_FIELD_TR 0C0Ch +%define VMX_VMCS_CTRL_IO_BITMAP_A_FULL 02000h +%define VMX_VMCS_CTRL_IO_BITMAP_A_HIGH 02001h +%define VMX_VMCS_CTRL_IO_BITMAP_B_FULL 02002h +%define VMX_VMCS_CTRL_IO_BITMAP_B_HIGH 02003h +%define VMX_VMCS_CTRL_MSR_BITMAP_FULL 02004h +%define VMX_VMCS_CTRL_MSR_BITMAP_HIGH 02005h +%define VMX_VMCS_CTRL_VMEXIT_MSR_STORE_FULL 02006h +%define VMX_VMCS_CTRL_VMEXIT_MSR_STORE_HIGH 02007h +%define VMX_VMCS_CTRL_VMEXIT_MSR_LOAD_FULL 02008h +%define VMX_VMCS_CTRL_VMEXIT_MSR_LOAD_HIGH 02009h +%define VMX_VMCS_CTRL_VMENTRY_MSR_LOAD_FULL 0200Ah +%define VMX_VMCS_CTRL_VMENTRY_MSR_LOAD_HIGH 0200Bh +%define VMX_VMCS_CTRL_EXEC_VMCS_PTR_FULL 0200Ch +%define VMX_VMCS_CTRL_EXEC_VMCS_PTR_HIGH 0200Dh +%define VMX_VMCS_CTRL_TSC_OFFSET_FULL 02010h +%define VMX_VMCS_CTRL_TSC_OFFSET_HIGH 02011h +%define VMX_VMCS_CTRL_VAPIC_PAGEADDR_FULL 02012h +%define VMX_VMCS_CTRL_VAPIC_PAGEADDR_HIGH 02013h +%define VMX_VMCS_GUEST_LINK_PTR_FULL 02800h +%define VMX_VMCS_GUEST_LINK_PTR_HIGH 02801h +%define VMX_VMCS_GUEST_DEBUGCTL_FULL 02802h +%define VMX_VMCS_GUEST_DEBUGCTL_HIGH 02803h +%define VMX_VMCS_CTRL_PIN_EXEC 04000h +%define VMX_VMCS_CTRL_PROC_EXEC 04002h +%define VMX_VMCS_CTRL_EXCEPTION_BITMAP 04004h +%define VMX_VMCS_CTRL_PAGEFAULT_ERROR_MASK 04006h +%define VMX_VMCS_CTRL_PAGEFAULT_ERROR_MATCH 04008h +%define VMX_VMCS_CTRL_CR3_TARGET_COUNT 0400Ah +%define VMX_VMCS_CTRL_EXIT 0400Ch +%define VMX_VMCS_CTRL_EXIT_MSR_STORE_COUNT 0400Eh +%define VMX_VMCS_CTRL_EXIT_MSR_LOAD_COUNT 04010h +%define VMX_VMCS_CTRL_ENTRY 04012h +%define VMX_VMCS_CTRL_ENTRY_MSR_LOAD_COUNT 04014h +%define VMX_VMCS_CTRL_ENTRY_IRQ_INFO 04016h +%define VMX_VMCS_CTRL_ENTRY_EXCEPTION_ERRCODE 04018h +%define VMX_VMCS_CTRL_ENTRY_INSTR_LENGTH 0401Ah +%define VMX_VMCS_CTRL_TRP_TRESHOLD 0401Ch +%define VMX_VMCS_RO_VM_INSTR_ERROR 04400h +%define VMX_VMCS_RO_EXIT_REASON 04402h +%define VMX_VMCS_RO_EXIT_INTERRUPTION_INFO 04404h +%define VMX_VMCS_RO_EXIT_INTERRUPTION_ERRCODE 04406h +%define VMX_VMCS_RO_IDT_INFO 04408h +%define VMX_VMCS_RO_IDT_ERRCODE 0440Ah +%define VMX_VMCS_RO_EXIT_INSTR_LENGTH 0440Ch +%define VMX_VMCS_RO_EXIT_INSTR_INFO 0440Eh +%define VMX_VMCS_GUEST_ES_LIMIT 04800h +%define VMX_VMCS_GUEST_CS_LIMIT 04802h +%define VMX_VMCS_GUEST_SS_LIMIT 04804h +%define VMX_VMCS_GUEST_DS_LIMIT 04806h +%define VMX_VMCS_GUEST_FS_LIMIT 04808h +%define VMX_VMCS_GUEST_GS_LIMIT 0480Ah +%define VMX_VMCS_GUEST_LDTR_LIMIT 0480Ch +%define VMX_VMCS_GUEST_TR_LIMIT 0480Eh +%define VMX_VMCS_GUEST_GDTR_LIMIT 04810h +%define VMX_VMCS_GUEST_IDTR_LIMIT 04812h +%define VMX_VMCS_GUEST_ES_ACCESS_RIGHTS 04814h +%define VMX_VMCS_GUEST_CS_ACCESS_RIGHTS 04816h +%define VMX_VMCS_GUEST_SS_ACCESS_RIGHTS 04818h +%define VMX_VMCS_GUEST_DS_ACCESS_RIGHTS 0481Ah +%define VMX_VMCS_GUEST_FS_ACCESS_RIGHTS 0481Ch +%define VMX_VMCS_GUEST_GS_ACCESS_RIGHTS 0481Eh +%define VMX_VMCS_GUEST_LDTR_ACCESS_RIGHTS 04820h +%define VMX_VMCS_GUEST_TR_ACCESS_RIGHTS 04822h +%define VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE 04824h +%define VMX_VMCS_GUEST_ACTIVITY_STATE 04826h +%define VMX_VMCS_GUEST_SYSENTER_CS 0482Ah +%define VMX_VMCS_CTRL_CR0_MASK 06000h +%define VMX_VMCS_CTRL_CR4_MASK 06002h +%define VMX_VMCS_CTRL_CR0_READ_SHADOW 06004h +%define VMX_VMCS_CTRL_CR4_READ_SHADOW 06006h +%define VMX_VMCS_CTRL_CR3_TARGET_VAL0 06008h +%define VMX_VMCS_CTRL_CR3_TARGET_VAL1 0600Ah +%define VMX_VMCS_CTRL_CR3_TARGET_VAL2 0600Ch +%define VMX_VMCS_CTRL_CR3_TARGET_VAL31 0600Eh +%define VMX_VMCS_RO_EXIT_QUALIFICATION 06400h +%define VMX_VMCS_RO_IO_RCX 06402h +%define VMX_VMCS_RO_IO_RSX 06404h +%define VMX_VMCS_RO_IO_RDI 06406h +%define VMX_VMCS_RO_IO_RIP 06408h +%define VMX_VMCS_GUEST_LINEAR_ADDR 0640Ah +%define VMX_VMCS64_GUEST_CR0 06800h +%define VMX_VMCS64_GUEST_CR3 06802h +%define VMX_VMCS64_GUEST_CR4 06804h +%define VMX_VMCS64_GUEST_ES_BASE 06806h +%define VMX_VMCS64_GUEST_CS_BASE 06808h +%define VMX_VMCS64_GUEST_SS_BASE 0680Ah +%define VMX_VMCS64_GUEST_DS_BASE 0680Ch +%define VMX_VMCS64_GUEST_FS_BASE 0680Eh +%define VMX_VMCS64_GUEST_GS_BASE 06810h +%define VMX_VMCS64_GUEST_LDTR_BASE 06812h +%define VMX_VMCS64_GUEST_TR_BASE 06814h +%define VMX_VMCS64_GUEST_GDTR_BASE 06816h +%define VMX_VMCS64_GUEST_IDTR_BASE 06818h +%define VMX_VMCS64_GUEST_DR7 0681Ah +%define VMX_VMCS64_GUEST_RSP 0681Ch +%define VMX_VMCS64_GUEST_RIP 0681Eh +%define VMX_VMCS64_GUEST_RFLAGS 06820h +%define VMX_VMCS_GUEST_DEBUG_EXCEPTIONS 06822h +%define VMX_VMCS64_GUEST_SYSENTER_ESP 06824h +%define VMX_VMCS64_GUEST_SYSENTER_EIP 06826h +%define VMX_VMCS_HOST_CR0 06C00h +%define VMX_VMCS_HOST_CR3 06C02h +%define VMX_VMCS_HOST_CR4 06C04h +%define VMX_VMCS_HOST_FS_BASE 06C06h +%define VMX_VMCS_HOST_GS_BASE 06C08h +%define VMX_VMCS_HOST_TR_BASE 06C0Ah +%define VMX_VMCS_HOST_GDTR_BASE 06C0Ch +%define VMX_VMCS_HOST_IDTR_BASE 06C0Eh +%define VMX_VMCS_HOST_SYSENTER_ESP 06C10h +%define VMX_VMCS_HOST_SYSENTER_EIP 06C12h +%define VMX_VMCS_HOST_RSP 06C14h +%define VMX_VMCS_HOST_RIP 06C16h + diff --git a/include/VBox/vmm/hmvmxinline.h b/include/VBox/vmm/hmvmxinline.h new file mode 100644 index 00000000..a0103786 --- /dev/null +++ b/include/VBox/vmm/hmvmxinline.h @@ -0,0 +1,1172 @@ +/** @file + * HM - VMX Structures and Definitions. (VMM) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_hmvmxinline_h +#define VBOX_INCLUDED_vmm_hmvmxinline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/hm_vmx.h> +#include <VBox/err.h> + +/* In Visual C++ versions prior to 2012, the vmx intrinsics are only available + when targeting AMD64. */ +#if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2010 && defined(RT_ARCH_AMD64) +# include <iprt/sanitized/intrin.h> +/* We always want them as intrinsics, no functions. */ +# pragma intrinsic(__vmx_on) +# pragma intrinsic(__vmx_off) +# pragma intrinsic(__vmx_vmclear) +# pragma intrinsic(__vmx_vmptrld) +# pragma intrinsic(__vmx_vmread) +# pragma intrinsic(__vmx_vmwrite) +# define VMX_USE_MSC_INTRINSICS 1 +#else +# define VMX_USE_MSC_INTRINSICS 0 +#endif + +/** + * Whether we think the assembler supports VMX instructions. + * + * Guess that GCC 5 should have sufficient recent enough binutils. + */ +#if RT_INLINE_ASM_GNU_STYLE && RT_GNUC_PREREQ(5,0) +# define VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS 1 +#else +# define VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS 0 +#endif + +/** Whether we can use the subsection trick to put error handling code + * elsewhere. */ +#if VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS && defined(__ELF__) +# define VMX_USE_GNU_STYLE_INLINE_SECTION_TRICK 1 +#else +# define VMX_USE_GNU_STYLE_INLINE_SECTION_TRICK 0 +#endif + +/* Skip checking VMREAD/VMWRITE failures on non-strict builds. */ +#ifndef VBOX_STRICT +# define VBOX_WITH_VMREAD_VMWRITE_NOCHECK +#endif + + +/** @defgroup grp_hm_vmx_inline VMX Inline Helpers + * @ingroup grp_hm_vmx + * @{ + */ +/** + * Gets the effective width of a VMCS field given it's encoding adjusted for + * HIGH/FULL access for 64-bit fields. + * + * @returns The effective VMCS field width. + * @param uFieldEnc The VMCS field encoding. + * + * @remarks Warning! This function does not verify the encoding is for a valid and + * supported VMCS field. + */ +DECLINLINE(uint8_t) VMXGetVmcsFieldWidthEff(uint32_t uFieldEnc) +{ + /* Only the "HIGH" parts of all 64-bit fields have bit 0 set. */ + if (uFieldEnc & RT_BIT(0)) + return VMXVMCSFIELDWIDTH_32BIT; + + /* Bits 13:14 contains the width of the VMCS field, see VMXVMCSFIELDWIDTH_XXX. */ + return (uFieldEnc >> 13) & 0x3; +} + + +/** + * Returns whether the given VMCS field is a read-only VMCS field or not. + * + * @returns @c true if it's a read-only field, @c false otherwise. + * @param uFieldEnc The VMCS field encoding. + * + * @remarks Warning! This function does not verify that the encoding is for a valid + * and/or supported VMCS field. + */ +DECLINLINE(bool) VMXIsVmcsFieldReadOnly(uint32_t uFieldEnc) +{ + /* See Intel spec. B.4.2 "Natural-Width Read-Only Data Fields". */ + return (RT_BF_GET(uFieldEnc, VMX_BF_VMCSFIELD_TYPE) == VMXVMCSFIELDTYPE_VMEXIT_INFO); +} + + +/** + * Returns whether the given VM-entry interruption-information type is valid or not. + * + * @returns @c true if it's a valid type, @c false otherwise. + * @param fSupportsMTF Whether the Monitor-Trap Flag CPU feature is supported. + * @param uType The VM-entry interruption-information type. + */ +DECLINLINE(bool) VMXIsEntryIntInfoTypeValid(bool fSupportsMTF, uint8_t uType) +{ + /* See Intel spec. 26.2.1.3 "VM-Entry Control Fields". */ + switch (uType) + { + case VMX_ENTRY_INT_INFO_TYPE_EXT_INT: + case VMX_ENTRY_INT_INFO_TYPE_NMI: + case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT: + case VMX_ENTRY_INT_INFO_TYPE_SW_INT: + case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT: + case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT: return true; + case VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT: return fSupportsMTF; + default: + return false; + } +} + + +/** + * Returns whether the given VM-entry interruption-information vector and type + * combination is valid or not. + * + * @returns @c true if it's a valid vector/type combination, @c false otherwise. + * @param uVector The VM-entry interruption-information vector. + * @param uType The VM-entry interruption-information type. + * + * @remarks Warning! This function does not validate the type field individually. + * Use it after verifying type is valid using HMVmxIsEntryIntInfoTypeValid. + */ +DECLINLINE(bool) VMXIsEntryIntInfoVectorValid(uint8_t uVector, uint8_t uType) +{ + /* See Intel spec. 26.2.1.3 "VM-Entry Control Fields". */ + if ( uType == VMX_ENTRY_INT_INFO_TYPE_NMI + && uVector != X86_XCPT_NMI) + return false; + if ( uType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT + && uVector > X86_XCPT_LAST) + return false; + if ( uType == VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT + && uVector != VMX_ENTRY_INT_INFO_VECTOR_MTF) + return false; + return true; +} + + +/** + * Returns whether or not the VM-exit is trap-like or fault-like. + * + * @returns @c true if it's a trap-like VM-exit, @c false otherwise. + * @param uExitReason The VM-exit reason. + * + * @remarks Warning! This does not validate the VM-exit reason. + */ +DECLINLINE(bool) VMXIsVmexitTrapLike(uint32_t uExitReason) +{ + /* + * Trap-like VM-exits - The instruction causing the VM-exit completes before the + * VM-exit occurs. + * + * Fault-like VM-exits - The instruction causing the VM-exit is not completed before + * the VM-exit occurs. + * + * See Intel spec. 25.5.2 "Monitor Trap Flag". + * See Intel spec. 29.1.4 "EOI Virtualization". + * See Intel spec. 29.4.3.3 "APIC-Write VM Exits". + * See Intel spec. 29.1.2 "TPR Virtualization". + */ + /** @todo NSTVMX: r=ramshankar: What about VM-exits due to debug traps (single-step, + * I/O breakpoints, data breakpoints), debug exceptions (data breakpoint) + * delayed by MovSS blocking, machine-check exceptions. */ + switch (uExitReason) + { + case VMX_EXIT_MTF: + case VMX_EXIT_VIRTUALIZED_EOI: + case VMX_EXIT_APIC_WRITE: + case VMX_EXIT_TPR_BELOW_THRESHOLD: + return true; + } + return false; +} + + +/** + * Returns whether the VM-entry is vectoring or not given the VM-entry interruption + * information field. + * + * @returns @c true if the VM-entry is vectoring, @c false otherwise. + * @param uEntryIntInfo The VM-entry interruption information field. + * @param pEntryIntInfoType The VM-entry interruption information type field. + * Optional, can be NULL. Only updated when this + * function returns @c true. + */ +DECLINLINE(bool) VMXIsVmentryVectoring(uint32_t uEntryIntInfo, uint8_t *pEntryIntInfoType) +{ + /* + * The definition of what is a vectoring VM-entry is taken + * from Intel spec. 26.6 "Special Features of VM Entry". + */ + if (!VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo)) + return false; + + /* Scope and keep variable defines on top to satisy archaic c89 nonsense. */ + { + uint8_t const uType = VMX_ENTRY_INT_INFO_TYPE(uEntryIntInfo); + switch (uType) + { + case VMX_ENTRY_INT_INFO_TYPE_EXT_INT: + case VMX_ENTRY_INT_INFO_TYPE_NMI: + case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT: + case VMX_ENTRY_INT_INFO_TYPE_SW_INT: + case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT: + case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT: + { + if (pEntryIntInfoType) + *pEntryIntInfoType = uType; + return true; + } + } + } + return false; +} + + +/** + * Gets the description for a VMX abort reason. + * + * @returns The descriptive string. + * @param enmAbort The VMX abort reason. + */ +DECLINLINE(const char *) VMXGetAbortDesc(VMXABORT enmAbort) +{ + switch (enmAbort) + { + case VMXABORT_NONE: return "VMXABORT_NONE"; + case VMXABORT_SAVE_GUEST_MSRS: return "VMXABORT_SAVE_GUEST_MSRS"; + case VMXBOART_HOST_PDPTE: return "VMXBOART_HOST_PDPTE"; + case VMXABORT_CURRENT_VMCS_CORRUPT: return "VMXABORT_CURRENT_VMCS_CORRUPT"; + case VMXABORT_LOAD_HOST_MSR: return "VMXABORT_LOAD_HOST_MSR"; + case VMXABORT_MACHINE_CHECK_XCPT: return "VMXABORT_MACHINE_CHECK_XCPT"; + case VMXABORT_HOST_NOT_IN_LONG_MODE: return "VMXABORT_HOST_NOT_IN_LONG_MODE"; + default: + break; + } + return "Unknown/invalid"; +} + + +/** + * Gets the description for a virtual VMCS state. + * + * @returns The descriptive string. + * @param fVmcsState The virtual-VMCS state. + */ +DECLINLINE(const char *) VMXGetVmcsStateDesc(uint8_t fVmcsState) +{ + switch (fVmcsState) + { + case VMX_V_VMCS_LAUNCH_STATE_CLEAR: return "Clear"; + case VMX_V_VMCS_LAUNCH_STATE_LAUNCHED: return "Launched"; + default: return "Unknown"; + } +} + + +/** + * Gets the description for a VM-entry interruption information event type. + * + * @returns The descriptive string. + * @param uType The event type. + */ +DECLINLINE(const char *) VMXGetEntryIntInfoTypeDesc(uint8_t uType) +{ + switch (uType) + { + case VMX_ENTRY_INT_INFO_TYPE_EXT_INT: return "External Interrupt"; + case VMX_ENTRY_INT_INFO_TYPE_NMI: return "NMI"; + case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT: return "Hardware Exception"; + case VMX_ENTRY_INT_INFO_TYPE_SW_INT: return "Software Interrupt"; + case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT: return "Priv. Software Exception"; + case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT: return "Software Exception"; + case VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT: return "Other Event"; + default: + break; + } + return "Unknown/invalid"; +} + + +/** + * Gets the description for a VM-exit interruption information event type. + * + * @returns The descriptive string. + * @param uType The event type. + */ +DECLINLINE(const char *) VMXGetExitIntInfoTypeDesc(uint8_t uType) +{ + switch (uType) + { + case VMX_EXIT_INT_INFO_TYPE_EXT_INT: return "External Interrupt"; + case VMX_EXIT_INT_INFO_TYPE_NMI: return "NMI"; + case VMX_EXIT_INT_INFO_TYPE_HW_XCPT: return "Hardware Exception"; + case VMX_EXIT_INT_INFO_TYPE_SW_INT: return "Software Interrupt"; + case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT: return "Priv. Software Exception"; + case VMX_EXIT_INT_INFO_TYPE_SW_XCPT: return "Software Exception"; + default: + break; + } + return "Unknown/invalid"; +} + + +/** + * Gets the description for an IDT-vectoring information event type. + * + * @returns The descriptive string. + * @param uType The event type. + */ +DECLINLINE(const char *) VMXGetIdtVectoringInfoTypeDesc(uint8_t uType) +{ + switch (uType) + { + case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT: return "External Interrupt"; + case VMX_IDT_VECTORING_INFO_TYPE_NMI: return "NMI"; + case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT: return "Hardware Exception"; + case VMX_IDT_VECTORING_INFO_TYPE_SW_INT: return "Software Interrupt"; + case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT: return "Priv. Software Exception"; + case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT: return "Software Exception"; + default: + break; + } + return "Unknown/invalid"; +} + + +/** @} */ + + +/** @defgroup grp_hm_vmx_asm VMX Assembly Helpers + * @{ + */ +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) + +/** + * Dispatches an NMI to the host. + */ +DECLASM(int) VMXDispatchHostNmi(void); + + +/** + * Executes VMXON. + * + * @returns VBox status code. + * @param HCPhysVmxOn Physical address of VMXON structure. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(int) VMXEnable(RTHCPHYS HCPhysVmxOn); +#else +DECLINLINE(int) VMXEnable(RTHCPHYS HCPhysVmxOn) +{ +# if VMX_USE_MSC_INTRINSICS + unsigned char rcMsc = __vmx_on(&HCPhysVmxOn); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return rcMsc == 2 ? VERR_VMX_INVALID_VMXON_PTR : VERR_VMX_VMXON_FAILED; + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + int rc; + __asm__ __volatile__ ( + "pushq %2 \n\t" + ".byte 0xf3, 0x0f, 0xc7, 0x34, 0x24 # VMXON [esp] \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMXON_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_VMXON_FAILED)", %0 \n\t" + "2: \n\t" + "add $8, %%rsp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"(HCPhysVmxOn) /* don't allow direct memory reference here, */ + /* this would not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# else + int rc; + __asm__ __volatile__ ( + "push %3 \n\t" + "push %2 \n\t" + ".byte 0xf3, 0x0f, 0xc7, 0x34, 0x24 # VMXON [esp] \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMXON_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_VMXON_FAILED)", %0 \n\t" + "2: \n\t" + "add $8, %%esp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"((uint32_t)HCPhysVmxOn), /* don't allow direct memory reference here, */ + "ir"((uint32_t)(HCPhysVmxOn >> 32)) /* this would not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# endif + +# elif defined(RT_ARCH_X86) + int rc = VINF_SUCCESS; + __asm + { + push dword ptr [HCPhysVmxOn + 4] + push dword ptr [HCPhysVmxOn] + _emit 0xf3 + _emit 0x0f + _emit 0xc7 + _emit 0x34 + _emit 0x24 /* VMXON [esp] */ + jnc vmxon_good + mov dword ptr [rc], VERR_VMX_INVALID_VMXON_PTR + jmp the_end + +vmxon_good: + jnz the_end + mov dword ptr [rc], VERR_VMX_VMXON_FAILED +the_end: + add esp, 8 + } + return rc; + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMXOFF. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(void) VMXDisable(void); +#else +DECLINLINE(void) VMXDisable(void) +{ +# if VMX_USE_MSC_INTRINSICS + __vmx_off(); + +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ ( + ".byte 0x0f, 0x01, 0xc4 # VMXOFF \n\t" + ); + +# elif defined(RT_ARCH_X86) + __asm + { + _emit 0x0f + _emit 0x01 + _emit 0xc4 /* VMXOFF */ + } + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMCLEAR. + * + * @returns VBox status code. + * @param HCPhysVmcs Physical address of VM control structure. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs); +#else +DECLINLINE(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs) +{ +# if VMX_USE_MSC_INTRINSICS + unsigned char rcMsc = __vmx_vmclear(&HCPhysVmcs); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return VERR_VMX_INVALID_VMCS_PTR; + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + int rc; + __asm__ __volatile__ ( + "pushq %2 \n\t" + ".byte 0x66, 0x0f, 0xc7, 0x34, 0x24 # VMCLEAR [esp] \n\t" + "jnc 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "1: \n\t" + "add $8, %%rsp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"(HCPhysVmcs) /* don't allow direct memory reference here, */ + /* this would not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# else + int rc; + __asm__ __volatile__ ( + "push %3 \n\t" + "push %2 \n\t" + ".byte 0x66, 0x0f, 0xc7, 0x34, 0x24 # VMCLEAR [esp] \n\t" + "jnc 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "1: \n\t" + "add $8, %%esp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"((uint32_t)HCPhysVmcs), /* don't allow direct memory reference here, */ + "ir"((uint32_t)(HCPhysVmcs >> 32)) /* this would not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# endif + +# elif defined(RT_ARCH_X86) + int rc = VINF_SUCCESS; + __asm + { + push dword ptr [HCPhysVmcs + 4] + push dword ptr [HCPhysVmcs] + _emit 0x66 + _emit 0x0f + _emit 0xc7 + _emit 0x34 + _emit 0x24 /* VMCLEAR [esp] */ + jnc success + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR +success: + add esp, 8 + } + return rc; + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMPTRLD. + * + * @returns VBox status code. + * @param HCPhysVmcs Physical address of VMCS structure. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(int) VMXLoadVmcs(RTHCPHYS HCPhysVmcs); +#else +DECLINLINE(int) VMXLoadVmcs(RTHCPHYS HCPhysVmcs) +{ +# if VMX_USE_MSC_INTRINSICS + unsigned char rcMsc = __vmx_vmptrld(&HCPhysVmcs); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return VERR_VMX_INVALID_VMCS_PTR; + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + int rc; + __asm__ __volatile__ ( + "pushq %2 \n\t" + ".byte 0x0f, 0xc7, 0x34, 0x24 # VMPTRLD [esp] \n\t" + "jnc 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "1: \n\t" + "add $8, %%rsp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"(HCPhysVmcs) /* don't allow direct memory reference here, */ + /* this will not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# else + int rc; + __asm__ __volatile__ ( + "push %3 \n\t" + "push %2 \n\t" + ".byte 0x0f, 0xc7, 0x34, 0x24 # VMPTRLD [esp] \n\t" + "jnc 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "1: \n\t" + "add $8, %%esp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"((uint32_t)HCPhysVmcs), /* don't allow direct memory reference here, */ + "ir"((uint32_t)(HCPhysVmcs >> 32)) /* this will not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# endif + +# elif defined(RT_ARCH_X86) + int rc = VINF_SUCCESS; + __asm + { + push dword ptr [HCPhysVmcs + 4] + push dword ptr [HCPhysVmcs] + _emit 0x0f + _emit 0xc7 + _emit 0x34 + _emit 0x24 /* VMPTRLD [esp] */ + jnc success + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR +success: + add esp, 8 + } + return rc; + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMPTRST. + * + * @returns VBox status code. + * @param pHCPhysVmcs Where to store the physical address of the current + * VMCS. + */ +DECLASM(int) VMXGetCurrentVmcs(RTHCPHYS *pHCPhysVmcs); + + +/** + * Executes VMWRITE for a 32-bit field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uFieldEnc VMCS field encoding. + * @param u32Val The 32-bit value to set. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(int) VMXWriteVmcs32(uint32_t uFieldEnc, uint32_t u32Val); +#else +DECLINLINE(int) VMXWriteVmcs32(uint32_t uFieldEnc, uint32_t u32Val) +{ +# if VMX_USE_MSC_INTRINSICS +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __vmx_vmwrite(uFieldEnc, u32Val); + return VINF_SUCCESS; +# else + unsigned char rcMsc = __vmx_vmwrite(uFieldEnc, u32Val); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD; +# endif + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__ ( + ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t" + : + :"a"(uFieldEnc), + "d"(u32Val) + ); + return VINF_SUCCESS; +# else + int rc; + __asm__ __volatile__ ( + ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t" + "2: \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "a"(uFieldEnc), + "d"(u32Val) + ); + return rc; +# endif + +# elif defined(RT_ARCH_X86) + int rc = VINF_SUCCESS; + __asm + { + push dword ptr [u32Val] + mov eax, [uFieldEnc] + _emit 0x0f + _emit 0x79 + _emit 0x04 + _emit 0x24 /* VMWRITE eax, [esp] */ + jnc valid_vmcs + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR + jmp the_end +valid_vmcs: + jnz the_end + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_FIELD +the_end: + add esp, 4 + } + return rc; + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMWRITE for a 64-bit field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uFieldEnc The VMCS field encoding. + * @param u64Val The 16, 32 or 64-bit value to set. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +#if defined(RT_ARCH_X86) || (RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS) +DECLASM(int) VMXWriteVmcs64(uint32_t uFieldEnc, uint64_t u64Val); +#else +DECLINLINE(int) VMXWriteVmcs64(uint32_t uFieldEnc, uint64_t u64Val) +{ +# if VMX_USE_MSC_INTRINSICS +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __vmx_vmwrite(uFieldEnc, u64Val); + return VINF_SUCCESS; +# else + unsigned char rcMsc = __vmx_vmwrite(uFieldEnc, u64Val); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD; +# endif + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__ ( + ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t" + : + :"a"(uFieldEnc), + "d"(u64Val) + ); + return VINF_SUCCESS; +# else + int rc; + __asm__ __volatile__ ( + ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t" + "2: \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "a"(uFieldEnc), + "d"(u64Val) + ); + return rc; +# endif + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMWRITE for a 16-bit VMCS field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uVmcsField The VMCS field. + * @param u16Val The 16-bit value to set. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +DECLINLINE(int) VMXWriteVmcs16(uint32_t uVmcsField, uint16_t u16Val) +{ + AssertMsg(RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH) == VMX_VMCSFIELD_WIDTH_16BIT, ("%#RX32\n", uVmcsField)); + return VMXWriteVmcs32(uVmcsField, u16Val); +} + + +/** + * Executes VMWRITE for a natural-width VMCS field. + */ +#ifdef RT_ARCH_AMD64 +# define VMXWriteVmcsNw VMXWriteVmcs64 +#else +# define VMXWriteVmcsNw VMXWriteVmcs32 +#endif + + +/** + * Invalidate a page using INVEPT. + * + * @returns VBox status code. + * @param enmFlush Type of flush. + * @param pDescriptor Pointer to the descriptor. + */ +DECLASM(int) VMXR0InvEPT(VMXTLBFLUSHEPT enmFlush, uint64_t *pDescriptor); + + +/** + * Invalidate a page using INVVPID. + * + * @returns VBox status code. + * @param enmFlush Type of flush. + * @param pDescriptor Pointer to the descriptor. + */ +DECLASM(int) VMXR0InvVPID(VMXTLBFLUSHVPID enmFlush, uint64_t *pDescriptor); + + +/** + * Executes VMREAD for a 32-bit field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uFieldEnc The VMCS field encoding. + * @param pData Where to store VMCS field value. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(int) VMXReadVmcs32(uint32_t uFieldEnc, uint32_t *pData); +#else +DECLINLINE(int) VMXReadVmcs32(uint32_t uFieldEnc, uint32_t *pData) +{ +# if VMX_USE_MSC_INTRINSICS +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + uint64_t u64Tmp = 0; + __vmx_vmread(uFieldEnc, &u64Tmp); + *pData = (uint32_t)u64Tmp; + return VINF_SUCCESS; +# else + unsigned char rcMsc; + uint64_t u64Tmp; + rcMsc = __vmx_vmread(uFieldEnc, &u64Tmp); + *pData = (uint32_t)u64Tmp; + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD; +# endif + +# elif VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS + RTCCUINTREG uTmp = 0; +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__("vmread %[uField],%[uDst]" + : [uDst] "=mr" (uTmp) + : [uField] "r" ((RTCCUINTREG)uFieldEnc)); + *pData = (uint32_t)uTmp; + return VINF_SUCCESS; +# else +#if 0 + int rc; + __asm__ __volatile__("vmread %[uField],%[uDst]\n\t" + "movl %[rcSuccess],%[rc]\n\t" +# if VMX_USE_GNU_STYLE_INLINE_SECTION_TRICK + "jna 1f\n\t" + ".section .text.vmread_failures, \"ax?\"\n\t" + "1:\n\t" + "movl %[rcInvalidVmcsPtr],%[rc]\n\t" + "jnz 2f\n\t" + "movl %[rcInvalidVmcsField],%[rc]\n\t" + "2:\n\t" + "jmp 3f\n\t" + ".previous\n\t" + "3:\n\t" +# else + "ja 1f\n\t" + "movl %[rcInvalidVmcsPtr],%[rc]\n\t" + "jnz 1f\n\t" + "movl %[rcInvalidVmcsField],%[rc]\n\t" + "1:\n\t" +# endif + : [uDst] "=mr" (uTmp) + , [rc] "=r" (rc) + : [uField] "r" ((RTCCUINTREG)uFieldEnc) + , [rcSuccess] "i" (VINF_SUCCESS) + , [rcInvalidVmcsPtr] "i" (VERR_VMX_INVALID_VMCS_PTR) + , [rcInvalidVmcsField] "i" (VERR_VMX_INVALID_VMCS_FIELD)); + *pData = uTmp; + return rc; +#else + int fSuccess, fFieldError; + __asm__ __volatile__("vmread %[uField],%[uDst]" + : [uDst] "=mr" (uTmp) + , "=@cca" (fSuccess) + , "=@ccnc" (fFieldError) + : [uField] "r" ((RTCCUINTREG)uFieldEnc)); + *pData = uTmp; + return RT_LIKELY(fSuccess) ? VINF_SUCCESS : fFieldError ? VERR_VMX_INVALID_VMCS_FIELD : VERR_VMX_INVALID_VMCS_PTR; +#endif +# endif + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__ ( + ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t" + :"=d"(*pData) + :"a"(uFieldEnc), + "d"(0) + ); + return VINF_SUCCESS; +# else + int rc; + __asm__ __volatile__ ( + "movl $" RT_XSTR(VINF_SUCCESS)", %0 \n\t" + ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t" + "2: \n\t" + :"=&r"(rc), + "=d"(*pData) + :"a"(uFieldEnc), + "d"(0) + ); + return rc; +# endif + +# elif defined(RT_ARCH_X86) + int rc = VINF_SUCCESS; + __asm + { + sub esp, 4 + mov dword ptr [esp], 0 + mov eax, [uFieldEnc] + _emit 0x0f + _emit 0x78 + _emit 0x04 + _emit 0x24 /* VMREAD eax, [esp] */ + mov edx, pData + pop dword ptr [edx] + jnc valid_vmcs + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR + jmp the_end +valid_vmcs: + jnz the_end + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_FIELD +the_end: + } + return rc; + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMREAD for a 64-bit field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uFieldEnc The VMCS field encoding. + * @param pData Where to store VMCS field value. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +#if defined(RT_ARCH_X86) || (RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS) +DECLASM(int) VMXReadVmcs64(uint32_t uFieldEnc, uint64_t *pData); +#else +DECLINLINE(int) VMXReadVmcs64(uint32_t uFieldEnc, uint64_t *pData) +{ +# if VMX_USE_MSC_INTRINSICS +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __vmx_vmread(uFieldEnc, pData); + return VINF_SUCCESS; +# else + unsigned char rcMsc; + rcMsc = __vmx_vmread(uFieldEnc, pData); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD; +# endif + +# elif VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS + uint64_t uTmp = 0; +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__("vmreadq %[uField],%[uDst]" + : [uDst] "=m" (uTmp) + : [uField] "r" ((uint64_t)uFieldEnc)); + *pData = uTmp; + return VINF_SUCCESS; +# elif 0 + int rc; + __asm__ __volatile__("vmreadq %[uField],%[uDst]\n\t" + "movl %[rcSuccess],%[rc]\n\t" +# if VMX_USE_GNU_STYLE_INLINE_SECTION_TRICK + "jna 1f\n\t" + ".section .text.vmread_failures, \"ax?\"\n\t" + "1:\n\t" + "movl %[rcInvalidVmcsPtr],%[rc]\n\t" + "jnz 2f\n\t" + "movl %[rcInvalidVmcsField],%[rc]\n\t" + "2:\n\t" + "jmp 3f\n\t" + ".previous\n\t" + "3:\n\t" +# else + "ja 1f\n\t" + "movl %[rcInvalidVmcsPtr],%[rc]\n\t" + "jnz 1f\n\t" + "movl %[rcInvalidVmcsField],%[rc]\n\t" + "1:\n\t" +# endif + : [uDst] "=mr" (uTmp) + , [rc] "=r" (rc) + : [uField] "r" ((uint64_t)uFieldEnc) + , [rcSuccess] "i" (VINF_SUCCESS) + , [rcInvalidVmcsPtr] "i" (VERR_VMX_INVALID_VMCS_PTR) + , [rcInvalidVmcsField] "i" (VERR_VMX_INVALID_VMCS_FIELD) + ); + *pData = uTmp; + return rc; +# else + int fSuccess, fFieldError; + __asm__ __volatile__("vmread %[uField],%[uDst]" + : [uDst] "=mr" (uTmp) + , "=@cca" (fSuccess) + , "=@ccnc" (fFieldError) + : [uField] "r" ((RTCCUINTREG)uFieldEnc)); + *pData = uTmp; + return RT_LIKELY(fSuccess) ? VINF_SUCCESS : fFieldError ? VERR_VMX_INVALID_VMCS_FIELD : VERR_VMX_INVALID_VMCS_PTR; +# endif + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__ ( + ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t" + :"=d"(*pData) + :"a"(uFieldEnc), + "d"(0) + ); + return VINF_SUCCESS; +# else + int rc; + __asm__ __volatile__ ( + "movl $" RT_XSTR(VINF_SUCCESS)", %0 \n\t" + ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t" + "2: \n\t" + :"=&r"(rc), + "=d"(*pData) + :"a"(uFieldEnc), + "d"(0) + ); + return rc; +# endif + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMREAD for a 16-bit field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uVmcsField The VMCS field. + * @param pData Where to store VMCS field value. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +DECLINLINE(int) VMXReadVmcs16(uint32_t uVmcsField, uint16_t *pData) +{ + uint32_t u32Tmp; + int rc; + AssertMsg(RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH) == VMX_VMCSFIELD_WIDTH_16BIT, ("%#RX32\n", uVmcsField)); + rc = VMXReadVmcs32(uVmcsField, &u32Tmp); + *pData = (uint16_t)u32Tmp; + return rc; +} + + +/** + * Executes VMREAD for a natural-width VMCS field. + */ +#ifdef RT_ARCH_AMD64 +# define VMXReadVmcsNw VMXReadVmcs64 +#else +# define VMXReadVmcsNw VMXReadVmcs32 +#endif + +#endif /* RT_ARCH_AMD64 || RT_ARCH_X86 */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_hmvmxinline_h */ + diff --git a/include/VBox/vmm/iem.h b/include/VBox/vmm/iem.h new file mode 100644 index 00000000..ef50970d --- /dev/null +++ b/include/VBox/vmm/iem.h @@ -0,0 +1,422 @@ +/** @file + * IEM - Interpreted Execution Manager. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_iem_h +#define VBOX_INCLUDED_vmm_iem_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/trpm.h> +#ifdef VBOX_WITH_NESTED_HWVIRT_VMX +# include <VBox/vmm/hm_vmx.h> +#endif +#include <iprt/assert.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_iem The Interpreted Execution Manager API. + * @ingroup grp_vmm + * @{ + */ + +/** @name IEMXCPTRAISEINFO_XXX - Extra info. on a recursive exception situation. + * + * This is primarily used by HM for working around a PGM limitation (see + * @bugref{6607}) and special NMI/IRET handling. In the future, this may be + * used for diagnostics. + * + * @{ + */ +typedef uint32_t IEMXCPTRAISEINFO; +/** Pointer to a IEMXCPTINFO type. */ +typedef IEMXCPTRAISEINFO *PIEMXCPTRAISEINFO; +/** No addition info. available. */ +#define IEMXCPTRAISEINFO_NONE RT_BIT_32(0) +/** Delivery of a \#AC caused another \#AC. */ +#define IEMXCPTRAISEINFO_AC_AC RT_BIT_32(1) +/** Delivery of a \#PF caused another \#PF. */ +#define IEMXCPTRAISEINFO_PF_PF RT_BIT_32(2) +/** Delivery of a \#PF caused some contributory exception. */ +#define IEMXCPTRAISEINFO_PF_CONTRIBUTORY_XCPT RT_BIT_32(3) +/** Delivery of an external interrupt caused an exception. */ +#define IEMXCPTRAISEINFO_EXT_INT_XCPT RT_BIT_32(4) +/** Delivery of an external interrupt caused an \#PF. */ +#define IEMXCPTRAISEINFO_EXT_INT_PF RT_BIT_32(5) +/** Delivery of a software interrupt caused an exception. */ +#define IEMXCPTRAISEINFO_SOFT_INT_XCPT RT_BIT_32(6) +/** Delivery of an NMI caused an exception. */ +#define IEMXCPTRAISEINFO_NMI_XCPT RT_BIT_32(7) +/** Delivery of an NMI caused a \#PF. */ +#define IEMXCPTRAISEINFO_NMI_PF RT_BIT_32(8) +/** Can re-execute the instruction at CS:RIP. */ +#define IEMXCPTRAISEINFO_CAN_REEXEC_INSTR RT_BIT_32(9) +/** @} */ + + +/** @name IEMXCPTRAISE_XXX - Ways to handle a recursive exception condition. + * @{ */ +typedef enum IEMXCPTRAISE +{ + /** Raise the current (second) exception. */ + IEMXCPTRAISE_CURRENT_XCPT = 0, + /** Re-raise the previous (first) event (for HM, unused by IEM). */ + IEMXCPTRAISE_PREV_EVENT, + /** Re-execute instruction at CS:RIP (for HM, unused by IEM). */ + IEMXCPTRAISE_REEXEC_INSTR, + /** Raise a \#DF exception. */ + IEMXCPTRAISE_DOUBLE_FAULT, + /** Raise a triple fault. */ + IEMXCPTRAISE_TRIPLE_FAULT, + /** Cause a CPU hang. */ + IEMXCPTRAISE_CPU_HANG, + /** Invalid sequence of events. */ + IEMXCPTRAISE_INVALID = 0x7fffffff +} IEMXCPTRAISE; +/** Pointer to a IEMXCPTRAISE type. */ +typedef IEMXCPTRAISE *PIEMXCPTRAISE; +/** @} */ + + +/** @name Operand or addressing mode. + * @{ */ +typedef uint8_t IEMMODE; +#define IEMMODE_16BIT 0 +#define IEMMODE_32BIT 1 +#define IEMMODE_64BIT 2 +/** @} */ + + +/** @name IEM_XCPT_FLAGS_XXX - flags for iemRaiseXcptOrInt. + * @{ */ +/** CPU exception. */ +#define IEM_XCPT_FLAGS_T_CPU_XCPT RT_BIT_32(0) +/** External interrupt (from PIC, APIC, whatever). */ +#define IEM_XCPT_FLAGS_T_EXT_INT RT_BIT_32(1) +/** Software interrupt (int or into, not bound). + * Returns to the following instruction */ +#define IEM_XCPT_FLAGS_T_SOFT_INT RT_BIT_32(2) +/** Takes an error code. */ +#define IEM_XCPT_FLAGS_ERR RT_BIT_32(3) +/** Takes a CR2. */ +#define IEM_XCPT_FLAGS_CR2 RT_BIT_32(4) +/** Generated by the breakpoint instruction. */ +#define IEM_XCPT_FLAGS_BP_INSTR RT_BIT_32(5) +/** Generated by a DRx instruction breakpoint and RF should be cleared. */ +#define IEM_XCPT_FLAGS_DRx_INSTR_BP RT_BIT_32(6) +/** Generated by the icebp instruction. */ +#define IEM_XCPT_FLAGS_ICEBP_INSTR RT_BIT_32(7) +/** Generated by the overflow instruction. */ +#define IEM_XCPT_FLAGS_OF_INSTR RT_BIT_32(8) +/** @} */ + + +/** @name IEMTARGETCPU_XXX - IEM target CPU specification. + * + * This is a gross simpliciation of CPUMMICROARCH for dealing with really old + * CPUs which didn't have much in the way of hinting at supported instructions + * and features. This slowly changes with the introduction of CPUID with the + * Intel Pentium. + * + * @{ + */ +/** The dynamic target CPU mode is for getting thru the BIOS and then use + * the debugger or modifying instruction behaviour (e.g. HLT) to switch to a + * different target CPU. */ +#define IEMTARGETCPU_DYNAMIC UINT32_C(0) +/** Intel 8086/8088. */ +#define IEMTARGETCPU_8086 UINT32_C(1) +/** NEC V20/V30. + * @remarks must be between 8086 and 80186. */ +#define IEMTARGETCPU_V20 UINT32_C(2) +/** Intel 80186/80188. */ +#define IEMTARGETCPU_186 UINT32_C(3) +/** Intel 80286. */ +#define IEMTARGETCPU_286 UINT32_C(4) +/** Intel 80386. */ +#define IEMTARGETCPU_386 UINT32_C(5) +/** Intel 80486. */ +#define IEMTARGETCPU_486 UINT32_C(6) +/** Intel Pentium . */ +#define IEMTARGETCPU_PENTIUM UINT32_C(7) +/** Intel PentiumPro. */ +#define IEMTARGETCPU_PPRO UINT32_C(8) +/** A reasonably current CPU, probably newer than the pentium pro when it comes + * to the feature set and behaviour. Generally the CPUID info and CPU vendor + * dicates the behaviour here. */ +#define IEMTARGETCPU_CURRENT UINT32_C(9) +/** @} */ + + +/** @name IEM status codes. + * + * Not quite sure how this will play out in the end, just aliasing safe status + * codes for now. + * + * @{ */ +#define VINF_IEM_RAISED_XCPT VINF_EM_RESCHEDULE +/** @} */ + + +/** The CPUMCTX_EXTRN_XXX mask required to be cleared when interpreting anything. + * IEM will ASSUME the caller of IEM APIs has ensured these are already present. */ +#define IEM_CPUMCTX_EXTRN_MUST_MASK ( CPUMCTX_EXTRN_GPRS_MASK \ + | CPUMCTX_EXTRN_RIP \ + | CPUMCTX_EXTRN_RFLAGS \ + | CPUMCTX_EXTRN_SS \ + | CPUMCTX_EXTRN_CS \ + | CPUMCTX_EXTRN_CR0 \ + | CPUMCTX_EXTRN_CR3 \ + | CPUMCTX_EXTRN_CR4 \ + | CPUMCTX_EXTRN_APIC_TPR \ + | CPUMCTX_EXTRN_EFER \ + | CPUMCTX_EXTRN_DR7 ) +/** The CPUMCTX_EXTRN_XXX mask needed when injecting an exception/interrupt. + * IEM will import missing bits, callers are encouraged to make these registers + * available prior to injection calls if fetching state anyway. */ +#define IEM_CPUMCTX_EXTRN_XCPT_MASK ( IEM_CPUMCTX_EXTRN_MUST_MASK \ + | CPUMCTX_EXTRN_CR2 \ + | CPUMCTX_EXTRN_SREG_MASK \ + | CPUMCTX_EXTRN_TABLE_MASK ) +/** The CPUMCTX_EXTRN_XXX mask required to be cleared when calling any + * IEMExecDecoded API not using memory. IEM will ASSUME the caller of IEM + * APIs has ensured these are already present. + * @note ASSUMES execution engine has checked for instruction breakpoints + * during decoding. */ +#define IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK ( CPUMCTX_EXTRN_RIP \ + | CPUMCTX_EXTRN_RFLAGS \ + | CPUMCTX_EXTRN_SS /* for CPL */ \ + | CPUMCTX_EXTRN_CS /* for mode */ \ + | CPUMCTX_EXTRN_CR0 /* for mode */ \ + | CPUMCTX_EXTRN_EFER /* for mode */ ) +/** The CPUMCTX_EXTRN_XXX mask required to be cleared when calling any + * IEMExecDecoded API using memory. IEM will ASSUME the caller of IEM + * APIs has ensured these are already present. + * @note ASSUMES execution engine has checked for instruction breakpoints + * during decoding. */ +#define IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK ( IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK \ + | CPUMCTX_EXTRN_CR3 /* for page tables */ \ + | CPUMCTX_EXTRN_CR4 /* for mode paging mode */ \ + | CPUMCTX_EXTRN_DR7 /* for memory breakpoints */ ) + +#ifdef VBOX_WITH_NESTED_HWVIRT_VMX +/** The CPUMCTX_EXTRN_XXX mask needed when calling IEMExecDecodedVmlaunchVmresume(). + * IEM will ASSUME the caller has ensured these are already present. */ +# define IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK ( IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK \ + | CPUMCTX_EXTRN_CR2 \ + | CPUMCTX_EXTRN_HWVIRT ) + +/** The CPUMCTX_EXTRN_XXX mask that the IEM VM-exit code will import on-demand when + * needed, primarily because there are several IEM VM-exit interface functions and + * some of which may not cause a VM-exit at all. + * + * This is currently unused, but keeping it here in case we can get away a bit more + * fine-grained state handling. + * + * @note Update HM_CHANGED_VMX_VMEXIT_MASK if something here changes. */ +# define IEM_CPUMCTX_EXTRN_VMX_VMEXIT_MASK ( CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4 \ + | CPUMCTX_EXTRN_DR7 | CPUMCTX_EXTRN_DR6 \ + | CPUMCTX_EXTRN_EFER \ + | CPUMCTX_EXTRN_SYSENTER_MSRS \ + | CPUMCTX_EXTRN_OTHER_MSRS /* for PAT MSR */ \ + | CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_RFLAGS \ + | CPUMCTX_EXTRN_SREG_MASK \ + | CPUMCTX_EXTRN_TR \ + | CPUMCTX_EXTRN_LDTR | CPUMCTX_EXTRN_GDTR | CPUMCTX_EXTRN_IDTR \ + | CPUMCTX_EXTRN_HWVIRT ) +#endif + +#ifdef VBOX_WITH_NESTED_HWVIRT_SVM +/** The CPUMCTX_EXTRN_XXX mask needed when calling IEMExecSvmVmexit(). + * IEM will ASSUME the caller has ensured these are already present. */ +# define IEM_CPUMCTX_EXTRN_SVM_VMEXIT_MASK ( CPUMCTX_EXTRN_RSP \ + | CPUMCTX_EXTRN_RAX \ + | CPUMCTX_EXTRN_RIP \ + | CPUMCTX_EXTRN_RFLAGS \ + | CPUMCTX_EXTRN_CS \ + | CPUMCTX_EXTRN_SS \ + | CPUMCTX_EXTRN_DS \ + | CPUMCTX_EXTRN_ES \ + | CPUMCTX_EXTRN_GDTR \ + | CPUMCTX_EXTRN_IDTR \ + | CPUMCTX_EXTRN_CR_MASK \ + | CPUMCTX_EXTRN_EFER \ + | CPUMCTX_EXTRN_DR6 \ + | CPUMCTX_EXTRN_DR7 \ + | CPUMCTX_EXTRN_OTHER_MSRS \ + | CPUMCTX_EXTRN_HWVIRT \ + | CPUMCTX_EXTRN_APIC_TPR \ + | CPUMCTX_EXTRN_HM_SVM_HWVIRT_VIRQ) + +/** The CPUMCTX_EXTRN_XXX mask needed when calling IEMExecDecodedVmrun(). + * IEM will ASSUME the caller has ensured these are already present. */ +# define IEM_CPUMCTX_EXTRN_SVM_VMRUN_MASK IEM_CPUMCTX_EXTRN_SVM_VMEXIT_MASK +#endif + +VMMDECL(VBOXSTRICTRC) IEMExecOne(PVMCPUCC pVCpu); +VMMDECL(VBOXSTRICTRC) IEMExecOneEx(PVMCPUCC pVCpu, uint32_t *pcbWritten); +VMMDECL(VBOXSTRICTRC) IEMExecOneWithPrefetchedByPC(PVMCPUCC pVCpu, uint64_t OpcodeBytesPC, + const void *pvOpcodeBytes, size_t cbOpcodeBytes); +VMMDECL(VBOXSTRICTRC) IEMExecOneBypassEx(PVMCPUCC pVCpu, uint32_t *pcbWritten); +VMMDECL(VBOXSTRICTRC) IEMExecOneBypassWithPrefetchedByPC(PVMCPUCC pVCpu, uint64_t OpcodeBytesPC, + const void *pvOpcodeBytes, size_t cbOpcodeBytes); +VMMDECL(VBOXSTRICTRC) IEMExecOneIgnoreLock(PVMCPUCC pVCpu); +VMMDECL(VBOXSTRICTRC) IEMExecLots(PVMCPUCC pVCpu, uint32_t cMaxInstructions, uint32_t cPollRate, uint32_t *pcInstructions); +/** Statistics returned by IEMExecForExits. */ +typedef struct IEMEXECFOREXITSTATS +{ + uint32_t cInstructions; + uint32_t cExits; + uint32_t cMaxExitDistance; + uint32_t cReserved; +} IEMEXECFOREXITSTATS; +/** Pointer to statistics returned by IEMExecForExits. */ +typedef IEMEXECFOREXITSTATS *PIEMEXECFOREXITSTATS; +VMMDECL(VBOXSTRICTRC) IEMExecForExits(PVMCPUCC pVCpu, uint32_t fWillExit, uint32_t cMinInstructions, uint32_t cMaxInstructions, + uint32_t cMaxInstructionsWithoutExits, PIEMEXECFOREXITSTATS pStats); +VMMDECL(VBOXSTRICTRC) IEMInjectTrpmEvent(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) IEMInjectTrap(PVMCPUCC pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType, uint16_t uErrCode, RTGCPTR uCr2, + uint8_t cbInstr); + +VMM_INT_DECL(int) IEMBreakpointSet(PVM pVM, RTGCPTR GCPtrBp); +VMM_INT_DECL(int) IEMBreakpointClear(PVM pVM, RTGCPTR GCPtrBp); + +VMM_INT_DECL(void) IEMTlbInvalidateAll(PVMCPUCC pVCpu); +VMM_INT_DECL(void) IEMTlbInvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCPtr); +VMM_INT_DECL(void) IEMTlbInvalidateAllPhysical(PVMCPUCC pVCpu); +VMM_INT_DECL(void) IEMTlbInvalidateAllPhysicalAllCpus(PVMCC pVM, VMCPUID idCpuCaller); +VMM_INT_DECL(bool) IEMGetCurrentXcpt(PVMCPUCC pVCpu, uint8_t *puVector, uint32_t *pfFlags, uint32_t *puErr, + uint64_t *puCr2); +VMM_INT_DECL(IEMXCPTRAISE) IEMEvaluateRecursiveXcpt(PVMCPUCC pVCpu, uint32_t fPrevFlags, uint8_t uPrevVector, uint32_t fCurFlags, + uint8_t uCurVector, PIEMXCPTRAISEINFO pXcptRaiseInfo); + +/** @name Given Instruction Interpreters + * @{ */ +VMM_INT_DECL(VBOXSTRICTRC) IEMExecStringIoWrite(PVMCPUCC pVCpu, uint8_t cbValue, IEMMODE enmAddrMode, + bool fRepPrefix, uint8_t cbInstr, uint8_t iEffSeg, bool fIoChecked); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecStringIoRead(PVMCPUCC pVCpu, uint8_t cbValue, IEMMODE enmAddrMode, + bool fRepPrefix, uint8_t cbInstr, bool fIoChecked); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedOut(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t u16Port, bool fImm, uint8_t cbReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedIn(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t u16Port, bool fImm, uint8_t cbReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMovCRxWrite(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iCrReg, uint8_t iGReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMovCRxRead(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMovDRxWrite(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iDrReg, uint8_t iGReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMovDRxRead(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iGReg, uint8_t iDrReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedClts(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedLmsw(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t uValue, RTGCPTR GCPtrEffDst); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedXsetbv(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedWbinvd(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvd(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvlpg(PVMCPUCC pVCpu, uint8_t cbInstr, RTGCPTR GCPtrPage); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvpcid(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrDesc, + uint64_t uType); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedCpuid(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedRdpmc(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedRdtsc(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedRdtscp(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedRdmsr(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedWrmsr(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMonitor(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMwait(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedHlt(PVMCPUCC pVCpu, uint8_t cbInstr); + +#ifdef VBOX_WITH_NESTED_HWVIRT_SVM +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedClgi(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedStgi(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmload(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmsave(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvlpga(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmrun(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecSvmVmexit(PVMCPUCC pVCpu, uint64_t uExitCode, uint64_t uExitInfo1, uint64_t uExitInfo2); +#endif + +#ifdef VBOX_WITH_NESTED_HWVIRT_VMX +VMM_INT_DECL(void) IEMReadVmxVmcsField(PCVMXVVMCS pVmcs, uint64_t u64VmcsField, uint64_t *pu64Dst); +VMM_INT_DECL(void) IEMWriteVmxVmcsField(PVMXVVMCS pVmcs, uint64_t u64VmcsField, uint64_t u64Val); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVirtApicAccessMsr(PVMCPUCC pVCpu, uint32_t idMsr, uint64_t *pu64Val, bool fWrite); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitApicWrite(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitPreemptTimer(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitExtInt(PVMCPUCC pVCpu, uint8_t uVector, bool fIntPending); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitXcpt(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo, PCVMXVEXITEVENTINFO pExitEventInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitXcptNmi(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitTripleFault(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitStartupIpi(PVMCPUCC pVCpu, uint8_t uVector); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitInstrWithInfo(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitInstr(PVMCPUCC pVCpu, uint32_t uExitReason, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitTrapLike(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitTaskSwitch(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo, PCVMXVEXITEVENTINFO pExitEventInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitApicAccess(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo, PCVMXVEXITEVENTINFO pExitEventInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexit(PVMCPUCC pVCpu, uint32_t uExitReason, uint64_t uExitQual); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmread(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmwrite(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmptrld(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmptrst(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmclear(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmlaunchVmresume(PVMCPUCC pVCpu, uint8_t cbInstr, VMXINSTRID uInstrId); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmxon(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmxoff(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvvpid(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +# ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvept(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitEptViolation(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo, PCVMXVEXITEVENTINFO pExitEventInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitEptMisconfig(PVMCPUCC pVCpu, RTGCPHYS GCPhysAddr, PCVMXVEXITEVENTINFO pExitEventInfo); +# endif +#endif +/** @} */ + +/** @defgroup grp_iem_r3 The IEM Host Context Ring-3 API. + * @{ + */ +VMMR0_INT_DECL(int) IEMR0InitVM(PGVM pGVM); +/** @} */ + + +/** @defgroup grp_iem_r3 The IEM Host Context Ring-3 API. + * @{ + */ +VMMR3DECL(int) IEMR3Init(PVM pVM); +VMMR3DECL(int) IEMR3Term(PVM pVM); +VMMR3DECL(void) IEMR3Relocate(PVM pVM); +VMMR3_INT_DECL(VBOXSTRICTRC) IEMR3ProcessForceFlag(PVM pVM, PVMCPUCC pVCpu, VBOXSTRICTRC rcStrict); +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_iem_h */ + diff --git a/include/VBox/vmm/iom.h b/include/VBox/vmm/iom.h new file mode 100644 index 00000000..a2ff5891 --- /dev/null +++ b/include/VBox/vmm/iom.h @@ -0,0 +1,550 @@ +/** @file + * IOM - Input / Output Monitor. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_iom_h +#define VBOX_INCLUDED_vmm_iom_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/dis.h> +#include <VBox/vmm/dbgf.h> + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_iom The Input / Ouput Monitor API + * @ingroup grp_vmm + * @{ + */ + +/** @def IOM_NO_PDMINS_CHECKS + * Until all devices have been fully adjusted to PDM style, the pPdmIns + * parameter is not checked by IOM. + * @todo Check this again, now. + */ +#define IOM_NO_PDMINS_CHECKS + +/** + * Macro for checking if an I/O or MMIO emulation call succeeded. + * + * This macro shall only be used with the IOM APIs where it's mentioned + * in the return value description. And there it must be used to correctly + * determine if the call succeeded and things like the RIP needs updating. + * + * + * @returns Success indicator (true/false). + * + * @param rc The status code. This may be evaluated + * more than once! + * + * @remarks To avoid making assumptions about the layout of the + * VINF_EM_FIRST...VINF_EM_LAST range we're checking explicitly for + * each exact exception. However, for efficiency we ASSUME that the + * VINF_EM_LAST is smaller than most of the relevant status codes. We + * also ASSUME that the VINF_EM_RESCHEDULE_REM status code is the + * most frequent status code we'll enounter in this range. + * + * @todo Will have to add VINF_EM_DBG_HYPER_BREAKPOINT if the + * I/O port and MMIO breakpoints should trigger before + * the I/O is done. Currently, we don't implement these + * kind of breakpoints. + */ +#ifdef IN_RING3 +# define IOM_SUCCESS(rc) ( (rc) == VINF_SUCCESS \ + || ( (rc) <= VINF_EM_LAST \ + && (rc) != VINF_EM_RESCHEDULE_REM \ + && (rc) >= VINF_EM_FIRST \ + && (rc) != VINF_EM_RESCHEDULE_RAW \ + && (rc) != VINF_EM_RESCHEDULE_HM \ + ) \ + ) +#else +# define IOM_SUCCESS(rc) ( (rc) == VINF_SUCCESS \ + || ( (rc) <= VINF_EM_LAST \ + && (rc) != VINF_EM_RESCHEDULE_REM \ + && (rc) >= VINF_EM_FIRST \ + && (rc) != VINF_EM_RESCHEDULE_RAW \ + && (rc) != VINF_EM_RESCHEDULE_HM \ + ) \ + || (rc) == VINF_IOM_R3_IOPORT_COMMIT_WRITE \ + || (rc) == VINF_IOM_R3_MMIO_COMMIT_WRITE \ + ) +#endif + +/** @name IOMMMIO_FLAGS_XXX + * @{ */ +/** Pass all reads thru unmodified. */ +#define IOMMMIO_FLAGS_READ_PASSTHRU UINT32_C(0x00000000) +/** All read accesses are DWORD sized (32-bit). */ +#define IOMMMIO_FLAGS_READ_DWORD UINT32_C(0x00000001) +/** All read accesses are DWORD (32-bit) or QWORD (64-bit) sized. + * Only accesses that are both QWORD sized and aligned are performed as QWORD. + * All other access will be done DWORD fashion (because it is way simpler). */ +#define IOMMMIO_FLAGS_READ_DWORD_QWORD UINT32_C(0x00000002) +/** The read access mode mask. */ +#define IOMMMIO_FLAGS_READ_MODE UINT32_C(0x00000003) + +/** Pass all writes thru unmodified. */ +#define IOMMMIO_FLAGS_WRITE_PASSTHRU UINT32_C(0x00000000) +/** All write accesses are DWORD (32-bit) sized and unspecified bytes are + * written as zero. */ +#define IOMMMIO_FLAGS_WRITE_DWORD_ZEROED UINT32_C(0x00000010) +/** All write accesses are either DWORD (32-bit) or QWORD (64-bit) sized, + * missing bytes will be written as zero. Only accesses that are both QWORD + * sized and aligned are performed as QWORD, all other accesses will be done + * DWORD fashion (because it's way simpler). */ +#define IOMMMIO_FLAGS_WRITE_DWORD_QWORD_ZEROED UINT32_C(0x00000020) +/** All write accesses are DWORD (32-bit) sized and unspecified bytes are + * read from the device first as DWORDs. + * @remarks This isn't how it happens on real hardware, but it allows + * simplifications of devices where reads doesn't change the device + * state in any way. */ +#define IOMMMIO_FLAGS_WRITE_DWORD_READ_MISSING UINT32_C(0x00000030) +/** All write accesses are DWORD (32-bit) or QWORD (64-bit) sized and + * unspecified bytes are read from the device first as DWORDs. Only accesses + * that are both QWORD sized and aligned are performed as QWORD, all other + * accesses will be done DWORD fashion (because it's way simpler). + * @remarks This isn't how it happens on real hardware, but it allows + * simplifications of devices where reads doesn't change the device + * state in any way. */ +#define IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING UINT32_C(0x00000040) +/** All write accesses are DWORD (32-bit) sized and aligned, attempts at other + * accesses are ignored. + * @remarks E1000, APIC */ +#define IOMMMIO_FLAGS_WRITE_ONLY_DWORD UINT32_C(0x00000050) +/** All write accesses are DWORD (32-bit) or QWORD (64-bit) sized and aligned, + * attempts at other accesses are ignored. + * @remarks Seemingly required by AHCI (although I doubt it's _really_ + * required as EM/REM doesn't do the right thing in ring-3 anyway, + * esp. not in raw-mode). */ +#define IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD UINT32_C(0x00000060) +/** The read access mode mask. */ +#define IOMMMIO_FLAGS_WRITE_MODE UINT32_C(0x00000070) + +/** Whether to do a DBGSTOP on complicated reads. + * What this includes depends on the read mode, but generally all misaligned + * reads as well as word and byte reads and maybe qword reads. */ +#define IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_READ UINT32_C(0x00000100) +/** Whether to do a DBGSTOP on complicated writes. + * This depends on the write mode, but generally all writes where we have to + * supply bytes (zero them or read them). */ +#define IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_WRITE UINT32_C(0x00000200) + +/** Pass the absolute physical address (GC) to the callback rather than the + * relative one. + * @note New-style only, is implicit in old-style interface. */ +#define IOMMMIO_FLAGS_ABS UINT32_C(0x00001000) + +/** Mask of valid flags. */ +#define IOMMMIO_FLAGS_VALID_MASK UINT32_C(0x00001373) +/** @} */ + +/** + * Checks whether the write mode allows aligned QWORD accesses to be passed + * thru to the device handler. + * @param a_fFlags The MMIO handler flags. + */ +#define IOMMMIO_DOES_WRITE_MODE_ALLOW_QWORD(a_fFlags) \ + ( ((a_fFlags) & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_DWORD_QWORD_ZEROED \ + || ((a_fFlags) & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING \ + || ((a_fFlags) & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD ) + + +/** + * Port I/O Handler for IN operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * @returns VERR_IOM_IOPORT_UNUSED if the port is really unused and a ~0 value should be returned. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param uPort Port number used for the IN operation. + * @param pu32 Where to store the result. This is always a 32-bit + * variable regardless of what @a cb might say. + * @param cb Number of bytes read. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMIOPORTIN,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)); +/** Pointer to a FNIOMIOPORTIN(). */ +typedef FNIOMIOPORTIN *PFNIOMIOPORTIN; + +/** + * Port I/O Handler for string IN operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * @returns VERR_IOM_IOPORT_UNUSED if the port is really unused and a ~0 value should be returned. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param uPort Port number used for the IN operation. + * @param pbDst Pointer to the destination buffer. + * @param pcTransfers Pointer to the number of transfer units to read, on + * return remaining transfer units. + * @param cb Size of the transfer unit (1, 2 or 4 bytes). + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMIOPORTINSTRING,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint8_t *pbDst, + uint32_t *pcTransfers, unsigned cb)); +/** Pointer to a FNIOMIOPORTINSTRING(). */ +typedef FNIOMIOPORTINSTRING *PFNIOMIOPORTINSTRING; + +/** + * Port I/O Handler for OUT operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param uPort Port number used for the OUT operation. + * @param u32 The value to output. + * @param cb The value size in bytes. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMIOPORTOUT,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)); +/** Pointer to a FNIOMIOPORTOUT(). */ +typedef FNIOMIOPORTOUT *PFNIOMIOPORTOUT; + +/** + * Port I/O Handler for string OUT operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param uPort Port number used for the OUT operation. + * @param pbSrc Pointer to the source buffer. + * @param pcTransfers Pointer to the number of transfer units to write, on + * return remaining transfer units. + * @param cb Size of the transfer unit (1, 2 or 4 bytes). + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMIOPORTOUTSTRING,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, const uint8_t *pbSrc, + uint32_t *pcTransfers, unsigned cb)); +/** Pointer to a FNIOMIOPORTOUTSTRING(). */ +typedef FNIOMIOPORTOUTSTRING *PFNIOMIOPORTOUTSTRING; + + +/** + * Port I/O Handler for IN operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * @returns VERR_IOM_IOPORT_UNUSED if the port is really unused and a ~0 value should be returned. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param offPort The port number if IOM_IOPORT_F_ABS is used, otherwise + * relative to the mapping base. + * @param pu32 Where to store the result. This is always a 32-bit + * variable regardless of what @a cb might say. + * @param cb Number of bytes read. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMIOPORTNEWIN,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, + uint32_t *pu32, unsigned cb)); +/** Pointer to a FNIOMIOPORTNEWIN(). */ +typedef FNIOMIOPORTNEWIN *PFNIOMIOPORTNEWIN; + +/** + * Port I/O Handler for string IN operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * @returns VERR_IOM_IOPORT_UNUSED if the port is really unused and a ~0 value should be returned. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param offPort The port number if IOM_IOPORT_F_ABS is used, otherwise + * relative to the mapping base. + * @param pbDst Pointer to the destination buffer. + * @param pcTransfers Pointer to the number of transfer units to read, on + * return remaining transfer units. + * @param cb Size of the transfer unit (1, 2 or 4 bytes). + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMIOPORTNEWINSTRING,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint8_t *pbDst, + uint32_t *pcTransfers, unsigned cb)); +/** Pointer to a FNIOMIOPORTNEWINSTRING(). */ +typedef FNIOMIOPORTNEWINSTRING *PFNIOMIOPORTNEWINSTRING; + +/** + * Port I/O Handler for OUT operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param offPort The port number if IOM_IOPORT_F_ABS is used, otherwise + * relative to the mapping base. + * @param u32 The value to output. + * @param cb The value size in bytes. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMIOPORTNEWOUT,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, + uint32_t u32, unsigned cb)); +/** Pointer to a FNIOMIOPORTNEWOUT(). */ +typedef FNIOMIOPORTNEWOUT *PFNIOMIOPORTNEWOUT; + +/** + * Port I/O Handler for string OUT operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param offPort The port number if IOM_IOPORT_F_ABS is used, otherwise + * relative to the mapping base. + * @param pbSrc Pointer to the source buffer. + * @param pcTransfers Pointer to the number of transfer units to write, on + * return remaining transfer units. + * @param cb Size of the transfer unit (1, 2 or 4 bytes). + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMIOPORTNEWOUTSTRING,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, + const uint8_t *pbSrc, uint32_t *pcTransfers, unsigned cb)); +/** Pointer to a FNIOMIOPORTNEWOUTSTRING(). */ +typedef FNIOMIOPORTNEWOUTSTRING *PFNIOMIOPORTNEWOUTSTRING; + +/** + * I/O port description. + * + * If both pszIn and pszOut are NULL, the entry is considered a terminator. + */ +typedef struct IOMIOPORTDESC +{ + /** Brief description / name of the IN port. */ + const char *pszIn; + /** Brief description / name of the OUT port. */ + const char *pszOut; + /** Detailed description of the IN port, optional. */ + const char *pszInDetail; + /** Detialed description of the OUT port, optional. */ + const char *pszOutDetail; +} IOMIOPORTDESC; +/** Pointer to an I/O port description. */ +typedef IOMIOPORTDESC const *PCIOMIOPORTDESC; + + +/** + * Memory mapped I/O Handler for read operations. + * + * @returns VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param GCPhysAddr Physical address (in GC) where the read starts. + * @param pv Where to store the result. + * @param cb Number of bytes read. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMMMIOREAD,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)); +/** Pointer to a FNIOMMMIOREAD(). */ +typedef FNIOMMMIOREAD *PFNIOMMMIOREAD; + +/** + * Memory mapped I/O Handler for write operations. + * + * @returns VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param GCPhysAddr Physical address (in GC) where the read starts. + * @param pv Where to fetch the result. + * @param cb Number of bytes to write. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMMMIOWRITE,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)); +/** Pointer to a FNIOMMMIOWRITE(). */ +typedef FNIOMMMIOWRITE *PFNIOMMMIOWRITE; + +/** + * Memory mapped I/O Handler for memset operations, actually for REP STOS* instructions handling. + * + * @returns VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param GCPhysAddr Physical address (in GC) where the write starts. + * @param u32Item Byte/Word/Dword data to fill. + * @param cbItem Size of data in u32Item parameter, restricted to 1/2/4 bytes. + * @param cItems Number of iterations. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMMMIOFILL,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, + uint32_t u32Item, unsigned cbItem, unsigned cItems)); +/** Pointer to a FNIOMMMIOFILL(). */ +typedef FNIOMMMIOFILL *PFNIOMMMIOFILL; + + +/** + * Memory mapped I/O Handler for read operations. + * + * @returns Strict VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param off Offset into the mapping of the read, + * or the physical address if IOMMMIO_FLAGS_ABS is active. + * @param pv Where to store the result. + * @param cb Number of bytes read. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMMMIONEWREAD,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, uint32_t cb)); +/** Pointer to a FNIOMMMIONEWREAD(). */ +typedef FNIOMMMIONEWREAD *PFNIOMMMIONEWREAD; + +/** + * Memory mapped I/O Handler for write operations. + * + * @returns Strict VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param off Offset into the mapping of the write, + * or the physical address if IOMMMIO_FLAGS_ABS is active. + * @param pv Where to fetch the result. + * @param cb Number of bytes to write. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMMMIONEWWRITE,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, + void const *pv, uint32_t cb)); +/** Pointer to a FNIOMMMIONEWWRITE(). */ +typedef FNIOMMMIONEWWRITE *PFNIOMMMIONEWWRITE; + +/** + * Memory mapped I/O Handler for memset operations, actually for REP STOS* instructions handling. + * + * @returns Strict VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param off Offset into the mapping of the fill, + * or the physical address if IOMMMIO_FLAGS_ABS is active. + * @param u32Item Byte/Word/Dword data to fill. + * @param cbItem Size of data in u32Item parameter, restricted to 1/2/4 bytes. + * @param cItems Number of iterations. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMMMIONEWFILL,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, + uint32_t u32Item, uint32_t cbItem, uint32_t cItems)); +/** Pointer to a FNIOMMMIONEWFILL(). */ +typedef FNIOMMMIONEWFILL *PFNIOMMMIONEWFILL; + +VMMDECL(VBOXSTRICTRC) IOMIOPortRead(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t *pu32Value, size_t cbValue); +VMMDECL(VBOXSTRICTRC) IOMIOPortWrite(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t u32Value, size_t cbValue); +VMM_INT_DECL(VBOXSTRICTRC) IOMIOPortReadString(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, void *pvDst, + uint32_t *pcTransfers, unsigned cb); +VMM_INT_DECL(VBOXSTRICTRC) IOMIOPortWriteString(PVMCC pVM, PVMCPU pVCpu, RTIOPORT uPort, void const *pvSrc, + uint32_t *pcTransfers, unsigned cb); +VMM_INT_DECL(VBOXSTRICTRC) IOMR0MmioPhysHandler(PVMCC pVM, PVMCPUCC pVCpu, uint32_t uErrorCode, RTGCPHYS GCPhysFault); +VMMDECL(int) IOMMmioMapMmio2Page(PVMCC pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS offRegion, + uint64_t hMmio2, RTGCPHYS offMmio2, uint64_t fPageFlags); +VMMR0_INT_DECL(int) IOMR0MmioMapMmioHCPage(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint64_t fPageFlags); +VMMDECL(int) IOMMmioResetRegion(PVMCC pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion); + + +/** @name IOM_IOPORT_F_XXX - Flags for IOMR3IoPortCreate() and PDMDevHlpIoPortCreateEx(). + * @{ */ +/** Pass the absolute I/O port to the callback rather than the relative one. */ +#define IOM_IOPORT_F_ABS RT_BIT_32(0) +/** Valid flags for IOMR3IoPortCreate(). */ +#define IOM_IOPORT_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +#ifdef IN_RING3 +/** @defgroup grp_iom_r3 The IOM Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(int) IOMR3Init(PVM pVM); +VMMR3_INT_DECL(int) IOMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3_INT_DECL(void) IOMR3Reset(PVM pVM); +VMMR3_INT_DECL(void) IOMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) IOMR3Term(PVM pVM); + +VMMR3_INT_DECL(int) IOMR3IoPortCreate(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT cPorts, uint32_t fFlags, PPDMPCIDEV pPciDev, + uint32_t iPciRegion, PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, RTR3PTR pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts); +VMMR3_INT_DECL(int) IOMR3IoPortMap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, RTIOPORT Port); +VMMR3_INT_DECL(int) IOMR3IoPortUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts); +VMMR3_INT_DECL(int) IOMR3IoPortValidateHandle(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts); +VMMR3_INT_DECL(uint32_t) IOMR3IoPortGetMappingAddress(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts); + +VMMR3_INT_DECL(int) IOMR3MmioCreate(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS cbRegion, uint32_t fFlags, PPDMPCIDEV pPciDev, + uint32_t iPciRegion, PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, + PFNIOMMMIONEWFILL pfnFill, void *pvUser, const char *pszDesc, PIOMMMIOHANDLE phRegion); +VMMR3_INT_DECL(int) IOMR3MmioMap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys); +VMMR3_INT_DECL(int) IOMR3MmioUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion); +VMMR3_INT_DECL(int) IOMR3MmioReduce(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion); +VMMR3_INT_DECL(int) IOMR3MmioValidateHandle(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion); +VMMR3_INT_DECL(RTGCPHYS) IOMR3MmioGetMappingAddress(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion); + +VMMR3_INT_DECL(VBOXSTRICTRC) IOMR3ProcessForceFlag(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rcStrict); + +VMMR3_INT_DECL(void) IOMR3NotifyBreakpointCountChange(PVM pVM, bool fPortIo, bool fMmio); +VMMR3_INT_DECL(void) IOMR3NotifyDebugEventChange(PVM pVM, DBGFEVENT enmEvent, bool fEnabled); +/** @} */ +#endif /* IN_RING3 */ + + +#if defined(IN_RING0) || defined(DOXYGEN_RUNNING) +/** @defgroup grpm_iom_r0 The IOM Host Context Ring-0 API + * @{ */ +VMMR0_INT_DECL(void) IOMR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(int) IOMR0InitVM(PGVM pGVM); +VMMR0_INT_DECL(void) IOMR0CleanupVM(PGVM pGVM); + +VMMR0_INT_DECL(int) IOMR0IoPortSetUpContext(PGVM pGVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, void *pvUser); +VMMR0_INT_DECL(int) IOMR0IoPortGrowRegistrationTables(PGVM pGVM, uint64_t cMinEntries); +VMMR0_INT_DECL(int) IOMR0IoPortGrowStatisticsTable(PGVM pGVM, uint64_t cMinEntries); +VMMR0_INT_DECL(int) IOMR0IoPortSyncStatisticsIndices(PGVM pGVM); + +VMMR0_INT_DECL(int) IOMR0MmioSetUpContext(PGVM pGVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIONEWWRITE pfnWrite, + PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser); +VMMR0_INT_DECL(int) IOMR0MmioGrowRegistrationTables(PGVM pGVM, uint64_t cMinEntries); +VMMR0_INT_DECL(int) IOMR0MmioGrowStatisticsTable(PGVM pGVM, uint64_t cMinEntries); +VMMR0_INT_DECL(int) IOMR0MmioSyncStatisticsIndices(PGVM pGVM); + +/** @} */ +#endif /* IN_RING0 || DOXYGEN_RUNNING */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_iom_h */ + diff --git a/include/VBox/vmm/mm.h b/include/VBox/vmm/mm.h new file mode 100644 index 00000000..540ba6d2 --- /dev/null +++ b/include/VBox/vmm/mm.h @@ -0,0 +1,244 @@ +/** @file + * MM - The Memory Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_mm_h +#define VBOX_INCLUDED_vmm_mm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/x86.h> +#include <VBox/sup.h> +#include <iprt/stdarg.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_mm The Memory Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * Memory Allocation Tags. + * For use with MMHyperAlloc(), MMR3HeapAlloc(), MMR3HeapAllocEx(), + * MMR3HeapAllocZ() and MMR3HeapAllocZEx(). + * + * @remark Don't forget to update the dump command in MMHeap.cpp! + */ +typedef enum MMTAG +{ + MM_TAG_INVALID = 0, + + MM_TAG_CFGM, + MM_TAG_CFGM_BYTES, + MM_TAG_CFGM_STRING, + MM_TAG_CFGM_USER, + + MM_TAG_CSAM, + MM_TAG_CSAM_PATCH, + + MM_TAG_CPUM_CTX, + MM_TAG_CPUM_CPUID, + MM_TAG_CPUM_MSRS, + + MM_TAG_DBGF, + MM_TAG_DBGF_AS, + MM_TAG_DBGF_CORE_WRITE, + MM_TAG_DBGF_INFO, + MM_TAG_DBGF_LINE, + MM_TAG_DBGF_LINE_DUP, + MM_TAG_DBGF_MODULE, + MM_TAG_DBGF_OS, + MM_TAG_DBGF_REG, + MM_TAG_DBGF_STACK, + MM_TAG_DBGF_SYMBOL, + MM_TAG_DBGF_SYMBOL_DUP, + MM_TAG_DBGF_TYPE, + MM_TAG_DBGF_TRACER, + MM_TAG_DBGF_FLOWTRACE, + + MM_TAG_EM, + + MM_TAG_IEM, + + MM_TAG_IOM, + MM_TAG_IOM_STATS, + + MM_TAG_MM, + MM_TAG_MM_LOOKUP_GUEST, + MM_TAG_MM_LOOKUP_PHYS, + MM_TAG_MM_LOOKUP_VIRT, + MM_TAG_MM_PAGE, + + MM_TAG_PARAV, + + MM_TAG_PATM, + MM_TAG_PATM_PATCH, + + MM_TAG_PDM, + MM_TAG_PDM_ASYNC_COMPLETION, + MM_TAG_PDM_DEVICE, + MM_TAG_PDM_DEVICE_DESC, + MM_TAG_PDM_DEVICE_USER, + MM_TAG_PDM_DRIVER, + MM_TAG_PDM_DRIVER_DESC, + MM_TAG_PDM_DRIVER_USER, + MM_TAG_PDM_USB, + MM_TAG_PDM_USB_DESC, + MM_TAG_PDM_USB_USER, + MM_TAG_PDM_LUN, +#ifdef VBOX_WITH_NETSHAPER + MM_TAG_PDM_NET_SHAPER, +#endif /* VBOX_WITH_NETSHAPER */ + MM_TAG_PDM_QUEUE, + MM_TAG_PDM_THREAD, + + MM_TAG_PGM, + MM_TAG_PGM_CHUNK_MAPPING, + MM_TAG_PGM_HANDLERS, + MM_TAG_PGM_HANDLER_TYPES, + MM_TAG_PGM_MAPPINGS, + MM_TAG_PGM_PHYS, + MM_TAG_PGM_POOL, + + MM_TAG_REM, + + MM_TAG_SELM, + + MM_TAG_SSM, + + MM_TAG_STAM, + + MM_TAG_TM, + + MM_TAG_TRPM, + + MM_TAG_VM, + MM_TAG_VM_REQ, + + MM_TAG_VMM, + + MM_TAG_HM, + + MM_TAG_32BIT_HACK = 0x7fffffff +} MMTAG; + + + + +/** @defgroup grp_mm_hyper Hypervisor Memory Management + * @{ */ + +VMMDECL(RTR0PTR) MMHyperR3ToR0(PVM pVM, RTR3PTR R3Ptr); + +#ifndef IN_RING3 +VMMDECL(void *) MMHyperR3ToCC(PVM pVM, RTR3PTR R3Ptr); +#else +DECLINLINE(void *) MMHyperR3ToCC(PVM pVM, RTR3PTR R3Ptr) +{ + NOREF(pVM); + return R3Ptr; +} +#endif + + +/** @def MMHYPER_RC_ASSERT_RCPTR + * Asserts that an address is either NULL or inside the hypervisor memory area. + * This assertion only works while IN_RC, it's a NOP everywhere else. + * @thread The Emulation Thread. + */ +#define MMHYPER_RC_ASSERT_RCPTR(pVM, RCPtr) do { } while (0) + +/** @} */ + + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +/** @defgroup grp_mm_r3 The MM Host Context Ring-3 API + * @{ + */ + +VMMR3DECL(int) MMR3InitUVM(PUVM pUVM); +VMMR3DECL(int) MMR3Init(PVM pVM); +VMMR3DECL(int) MMR3InitPaging(PVM pVM); +VMMR3DECL(int) MMR3Term(PVM pVM); +VMMR3DECL(void) MMR3TermUVM(PUVM pUVM); +VMMR3DECL(int) MMR3ReserveHandyPages(PVM pVM, uint32_t cHandyPages); +VMMR3DECL(int) MMR3IncreaseBaseReservation(PVM pVM, uint64_t cAddBasePages); +VMMR3DECL(int) MMR3AdjustFixedReservation(PVM pVM, int32_t cDeltaFixedPages, const char *pszDesc); +VMMR3DECL(int) MMR3UpdateShadowReservation(PVM pVM, uint32_t cShadowPages); +/** @} */ + + +/** @defgroup grp_mm_phys Guest Physical Memory Manager + * @todo retire this group, elimintating or moving MMR3PhysGetRamSize to PGMPhys. + * @{ */ +VMMR3DECL(uint64_t) MMR3PhysGetRamSize(PVM pVM); +VMMR3DECL(uint32_t) MMR3PhysGetRamSizeBelow4GB(PVM pVM); +VMMR3DECL(uint64_t) MMR3PhysGetRamSizeAbove4GB(PVM pVM); +VMMR3DECL(uint32_t) MMR3PhysGet4GBRamHoleSize(PVM pVM); +/** @} */ + + +/** @defgroup grp_mm_heap Heap Manager + * @{ */ +VMMR3DECL(void *) MMR3HeapAlloc(PVM pVM, MMTAG enmTag, size_t cbSize); +VMMR3DECL(void *) MMR3HeapAllocU(PUVM pUVM, MMTAG enmTag, size_t cbSize); +VMMR3DECL(int) MMR3HeapAllocEx(PVM pVM, MMTAG enmTag, size_t cbSize, void **ppv); +VMMR3DECL(int) MMR3HeapAllocExU(PUVM pUVM, MMTAG enmTag, size_t cbSize, void **ppv); +VMMR3DECL(void *) MMR3HeapAllocZ(PVM pVM, MMTAG enmTag, size_t cbSize); +VMMR3DECL(void *) MMR3HeapAllocZU(PUVM pUVM, MMTAG enmTag, size_t cbSize); +VMMR3DECL(int) MMR3HeapAllocZEx(PVM pVM, MMTAG enmTag, size_t cbSize, void **ppv); +VMMR3DECL(int) MMR3HeapAllocZExU(PUVM pUVM, MMTAG enmTag, size_t cbSize, void **ppv); +VMMR3DECL(void *) MMR3HeapRealloc(void *pv, size_t cbNewSize); +VMMR3DECL(char *) MMR3HeapStrDup(PVM pVM, MMTAG enmTag, const char *psz); +VMMR3DECL(char *) MMR3HeapStrDupU(PUVM pUVM, MMTAG enmTag, const char *psz); +VMMR3DECL(char *) MMR3HeapAPrintf(PVM pVM, MMTAG enmTag, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); +VMMR3DECL(char *) MMR3HeapAPrintfU(PUVM pUVM, MMTAG enmTag, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); +VMMR3DECL(char *) MMR3HeapAPrintfV(PVM pVM, MMTAG enmTag, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); +VMMR3DECL(char *) MMR3HeapAPrintfVU(PUVM pUVM, MMTAG enmTag, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); +VMMR3DECL(void) MMR3HeapFree(void *pv); +/** @} */ + +#endif /* IN_RING3 || DOXYGEN_RUNNING */ + + +/** @} */ +RT_C_DECLS_END + + +#endif /* !VBOX_INCLUDED_vmm_mm_h */ + diff --git a/include/VBox/vmm/nem.h b/include/VBox/vmm/nem.h new file mode 100644 index 00000000..3004efa5 --- /dev/null +++ b/include/VBox/vmm/nem.h @@ -0,0 +1,256 @@ +/** @file + * NEM - The Native Execution Manager. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_nem_h +#define VBOX_INCLUDED_vmm_nem_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/vmapi.h> +#include <VBox/vmm/pgm.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_nem The Native Execution Manager API + * @ingroup grp_vmm + * @{ + */ + +/** @defgroup grp_nem_r3 The NEM ring-3 Context API + * @{ + */ +VMMR3_INT_DECL(int) NEMR3InitConfig(PVM pVM); +VMMR3_INT_DECL(int) NEMR3Init(PVM pVM, bool fFallback, bool fForced); +VMMR3_INT_DECL(int) NEMR3InitAfterCPUM(PVM pVM); +#ifdef IN_RING3 +VMMR3_INT_DECL(int) NEMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +#endif +VMMR3_INT_DECL(int) NEMR3Term(PVM pVM); +VMMR3DECL(bool) NEMR3IsEnabled(PUVM pVM); +VMMR3_INT_DECL(bool) NEMR3NeedSpecialTscMode(PVM pVM); +VMMR3_INT_DECL(void) NEMR3Reset(PVM pVM); +VMMR3_INT_DECL(void) NEMR3ResetCpu(PVMCPU pVCpu, bool fInitIpi); +VMMR3DECL(const char *) NEMR3GetExitName(uint32_t uExit); +VMMR3_INT_DECL(VBOXSTRICTRC) NEMR3RunGC(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(bool) NEMR3CanExecuteGuest(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(bool) NEMR3SetSingleInstruction(PVM pVM, PVMCPU pVCpu, bool fEnable); +VMMR3_INT_DECL(void) NEMR3NotifyFF(PVM pVM, PVMCPU pVCpu, uint32_t fFlags); + +/** + * Checks if dirty page tracking for MMIO2 ranges is supported. + * + * If it is, PGM will not install a physical write access handler for the MMIO2 + * region and instead just forward dirty bit queries NEMR3QueryMmio2DirtyBits. + * The enable/disable control of the tracking will be ignored, and PGM will + * always set NEM_NOTIFY_PHYS_MMIO_EX_F_TRACK_DIRTY_PAGES for such ranges. + * + * @retval true if supported. + * @retval false if not. + * @param pVM The cross context VM structure. + */ +VMMR3_INT_DECL(bool) NEMR3IsMmio2DirtyPageTrackingSupported(PVM pVM); + +/** + * Worker for PGMR3PhysMmio2QueryAndResetDirtyBitmap. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param GCPhys The address of the MMIO2 range. + * @param cb The size of the MMIO2 range. + * @param uNemRange The NEM internal range number. + * @param pvBitmap The output bitmap. Must be 8-byte aligned. Ignored + * when @a cbBitmap is zero. + * @param cbBitmap The size of the bitmap. Must be the size of the whole + * MMIO2 range, rounded up to the nearest 8 bytes. + * When zero only a reset is done. + */ +VMMR3_INT_DECL(int) NEMR3PhysMmio2QueryAndResetDirtyBitmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t uNemRange, + void *pvBitmap, size_t cbBitmap); + +VMMR3_INT_DECL(int) NEMR3NotifyPhysRamRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvR3, + uint8_t *pu2State, uint32_t *puNemRange); +VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExMapEarly(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags, + void *pvRam, void *pvMmio2, uint8_t *pu2State, uint32_t *puNemRange); +VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExMapLate(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags, + void *pvRam, void *pvMmio2, uint32_t *puNemRange); +VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExUnmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags, + void *pvRam, void *pvMmio2, uint8_t *pu2State, uint32_t *puNemRange); +/** @name Flags for NEMR3NotifyPhysMmioExMap and NEMR3NotifyPhysMmioExUnmap. + * @{ */ +/** Set if the range is replacing RAM rather that unused space. */ +#define NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE RT_BIT(0) +/** Set if it's MMIO2 being mapped or unmapped. */ +#define NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2 RT_BIT(1) +/** Set if MMIO2 and dirty page tracking is configured. */ +#define NEM_NOTIFY_PHYS_MMIO_EX_F_TRACK_DIRTY_PAGES RT_BIT(2) +/** @} */ + +/** + * Called very early during ROM registration, basically so an existing RAM range + * can be adjusted if desired. + * + * It will be succeeded by a number of NEMHCNotifyPhysPageProtChanged() + * calls and finally a call to NEMR3NotifyPhysRomRegisterLate(). + * + * @returns VBox status code + * @param pVM The cross context VM structure. + * @param GCPhys The ROM address (page aligned). + * @param cb The size (page aligned). + * @param pvPages Pointer to the ROM (RAM) pages in simplified mode + * when NEM_NOTIFY_PHYS_ROM_F_REPLACE is set, otherwise + * NULL. + * @param fFlags NEM_NOTIFY_PHYS_ROM_F_XXX. + * @param pu2State New page state or UINT8_MAX to leave as-is. + * @param puNemRange Access to the relevant PGMRAMRANGE::uNemRange field. + */ +VMMR3_INT_DECL(int) NEMR3NotifyPhysRomRegisterEarly(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvPages, + uint32_t fFlags, uint8_t *pu2State, uint32_t *puNemRange); + +/** + * Called after the ROM range has been fully completed. + * + * This will be preceeded by a NEMR3NotifyPhysRomRegisterEarly() call as well a + * number of NEMHCNotifyPhysPageProtChanged calls. + * + * @returns VBox status code + * @param pVM The cross context VM structure. + * @param GCPhys The ROM address (page aligned). + * @param cb The size (page aligned). + * @param pvPages Pointer to the ROM pages. + * @param fFlags NEM_NOTIFY_PHYS_ROM_F_XXX. + * @param pu2State Where to return the new NEM page state, UINT8_MAX + * for unchanged. + * @param puNemRange Access to the relevant PGMRAMRANGE::uNemRange field. + */ +VMMR3_INT_DECL(int) NEMR3NotifyPhysRomRegisterLate(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvPages, + uint32_t fFlags, uint8_t *pu2State, uint32_t *puNemRange); + +/** @name Flags for NEMR3NotifyPhysRomRegisterEarly and NEMR3NotifyPhysRomRegisterLate. + * @{ */ +/** Set if the range is replacing RAM rather that unused space. */ +#define NEM_NOTIFY_PHYS_ROM_F_REPLACE RT_BIT(1) +/** Set if it's MMIO2 being mapped or unmapped. */ +#define NEM_NOTIFY_PHYS_ROM_F_SHADOW RT_BIT(2) +/** @} */ + +/** + * Called when the A20 state changes. + * + * Windows: Hyper-V doesn't seem to offer a simple way of implementing the A20 + * line features of PCs. So, we do a very minimal emulation of the HMA to make + * DOS happy. + * + * @param pVCpu The CPU the A20 state changed on. + * @param fEnabled Whether it was enabled (true) or disabled. + */ +VMMR3_INT_DECL(void) NEMR3NotifySetA20(PVMCPU pVCpu, bool fEnabled); +VMMR3_INT_DECL(void) NEMR3NotifyDebugEventChanged(PVM pVM); +VMMR3_INT_DECL(void) NEMR3NotifyDebugEventChangedPerCpu(PVM pVM, PVMCPU pVCpu); +/** @} */ + + +/** @defgroup grp_nem_r0 The NEM ring-0 Context API + * @{ */ +VMMR0_INT_DECL(int) NEMR0Init(void); +VMMR0_INT_DECL(void) NEMR0Term(void); +VMMR0_INT_DECL(int) NEMR0InitVM(PGVM pGVM); +VMMR0_INT_DECL(int) NEMR0InitVMPart2(PGVM pGVM); +VMMR0_INT_DECL(void) NEMR0CleanupVM(PGVM pGVM); +VMMR0_INT_DECL(int) NEMR0MapPages(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0UnmapPages(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0ExportState(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0ImportState(PGVM pGVM, VMCPUID idCpu, uint64_t fWhat); +VMMR0_INT_DECL(int) NEMR0QueryCpuTick(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0ResumeCpuTickOnAll(PGVM pGVM, VMCPUID idCpu, uint64_t uPausedTscValue); +VMMR0_INT_DECL(VBOXSTRICTRC) NEMR0RunGuestCode(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0UpdateStatistics(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0DoExperiment(PGVM pGVM, VMCPUID idCpu, uint64_t u64Arg); +#ifdef RT_OS_WINDOWS +VMMR0_INT_DECL(int) NEMR0WinGetPartitionId(PGVM pGVM, uintptr_t uHandle); +#endif +/** @} */ + + +/** @defgroup grp_nem_hc The NEM Host Context API + * @{ + */ +VMM_INT_DECL(bool) NEMHCIsLongModeAllowed(PVMCC pVM); +VMM_INT_DECL(uint32_t) NEMHCGetFeatures(PVMCC pVM); +VMM_INT_DECL(int) NEMImportStateOnDemand(PVMCPUCC pVCpu, uint64_t fWhat); + +/** @name NEM_FEAT_F_XXX - Features supported by the NEM backend + * @{ */ +/** NEM backend uses nested paging for the guest. */ +#define NEM_FEAT_F_NESTED_PAGING RT_BIT(0) +/** NEM backend uses full (unrestricted) guest execution. */ +#define NEM_FEAT_F_FULL_GST_EXEC RT_BIT(1) +/** NEM backend offers an xsave/xrstor interface. */ +#define NEM_FEAT_F_XSAVE_XRSTOR RT_BIT(2) +/** @} */ + +VMM_INT_DECL(void) NEMHCNotifyHandlerPhysicalRegister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb); +VMM_INT_DECL(void) NEMHCNotifyHandlerPhysicalDeregister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb, + RTR3PTR pvMemR3, uint8_t *pu2State); +VMM_INT_DECL(void) NEMHCNotifyHandlerPhysicalModify(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhysOld, + RTGCPHYS GCPhysNew, RTGCPHYS cb, bool fRestoreAsRAM); + +VMM_INT_DECL(int) NEMHCNotifyPhysPageAllocated(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt, + PGMPAGETYPE enmType, uint8_t *pu2State); +VMM_INT_DECL(void) NEMHCNotifyPhysPageProtChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, RTR3PTR pvR3, uint32_t fPageProt, + PGMPAGETYPE enmType, uint8_t *pu2State); +VMM_INT_DECL(void) NEMHCNotifyPhysPageChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhysPrev, RTHCPHYS HCPhysNew, + RTR3PTR pvNewR3, uint32_t fPageProt, PGMPAGETYPE enmType, uint8_t *pu2State); +/** @name NEM_PAGE_PROT_XXX - Page protection + * @{ */ +#define NEM_PAGE_PROT_NONE UINT32_C(0) /**< All access causes VM exits. */ +#define NEM_PAGE_PROT_READ RT_BIT(0) /**< Read access. */ +#define NEM_PAGE_PROT_EXECUTE RT_BIT(1) /**< Execute access. */ +#define NEM_PAGE_PROT_WRITE RT_BIT(2) /**< write access. */ +/** @} */ + +VMM_INT_DECL(int) NEMHCQueryCpuTick(PVMCPUCC pVCpu, uint64_t *pcTicks, uint32_t *puAux); +VMM_INT_DECL(int) NEMHCResumeCpuTickOnAll(PVMCC pVM, PVMCPUCC pVCpu, uint64_t uPausedTscValue); + +/** @} */ + +/** @} */ +RT_C_DECLS_END + + +#endif /* !VBOX_INCLUDED_vmm_nem_h */ + diff --git a/include/VBox/vmm/pdm.h b/include/VBox/vmm/pdm.h new file mode 100644 index 00000000..be46e570 --- /dev/null +++ b/include/VBox/vmm/pdm.h @@ -0,0 +1,54 @@ +/** @file + * PDM - Pluggable Device Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdm_h +#define VBOX_INCLUDED_vmm_pdm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/pdmapi.h> +#include <VBox/vmm/pdmqueue.h> +#include <VBox/vmm/pdmcritsect.h> +#include <VBox/vmm/pdmcritsectrw.h> +#include <VBox/vmm/pdmthread.h> +#include <VBox/vmm/pdmifs.h> +#include <VBox/vmm/pdmdrv.h> +#include <VBox/vmm/pdmdev.h> +#include <VBox/vmm/pdmusb.h> +#include <VBox/vmm/pdmsrv.h> + +#endif /* !VBOX_INCLUDED_vmm_pdm_h */ + diff --git a/include/VBox/vmm/pdmapi.h b/include/VBox/vmm/pdmapi.h new file mode 100644 index 00000000..bf25f043 --- /dev/null +++ b/include/VBox/vmm/pdmapi.h @@ -0,0 +1,393 @@ +/** @file + * PDM - Pluggable Device Manager, Core API. + * + * The 'Core API' has been put in a different header because everyone + * is currently including pdm.h. So, pdm.h is for including all of the + * PDM stuff, while pdmapi.h is for the core stuff. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmapi_h +#define VBOX_INCLUDED_vmm_pdmapi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/pdmcommon.h> +#ifdef IN_RING3 +# include <VBox/vmm/vmapi.h> +#endif +#include <VBox/sup.h> + +struct PDMDEVMODREGR0; + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm The Pluggable Device Manager API + * @ingroup grp_vmm + * @{ + */ + +VMMDECL(int) PDMGetInterrupt(PVMCPUCC pVCpu, uint8_t *pu8Interrupt); +VMMDECL(int) PDMIsaSetIrq(PVMCC pVM, uint8_t u8Irq, uint8_t u8Level, uint32_t uTagSrc); +VMM_INT_DECL(bool) PDMHasIoApic(PVM pVM); +VMM_INT_DECL(bool) PDMHasApic(PVM pVM); +VMM_INT_DECL(PPDMDEVINS) PDMDeviceRing0IdxToInstance(PVMCC pVM, uint64_t idxR0Device); +VMM_INT_DECL(int) PDMIoApicSetIrq(PVM pVM, PCIBDF uBusDevFn, uint8_t u8Irq, uint8_t u8Level, uint32_t uTagSrc); +VMM_INT_DECL(void) PDMIoApicBroadcastEoi(PVMCC pVM, uint8_t uVector); +VMM_INT_DECL(void) PDMIoApicSendMsi(PVMCC pVM, PCIBDF uBusDevFn, PCMSIMSG pMsi, uint32_t uTagSrc); +VMM_INT_DECL(int) PDMVmmDevHeapR3ToGCPhys(PVM pVM, RTR3PTR pv, RTGCPHYS *pGCPhys); +VMM_INT_DECL(bool) PDMVmmDevHeapIsEnabled(PVM pVM); + +/** + * Mapping/unmapping callback for an VMMDev heap allocation. + * + * @param pVM The cross context VM structure. + * @param pvAllocation The allocation address (ring-3). + * @param GCPhysAllocation The guest physical address of the mapping if + * it's being mapped, NIL_RTGCPHYS if it's being + * unmapped. + */ +typedef DECLCALLBACKTYPE(void, FNPDMVMMDEVHEAPNOTIFY,(PVM pVM, void *pvAllocation, RTGCPHYS GCPhysAllocation)); +/** Pointer (ring-3) to a FNPDMVMMDEVHEAPNOTIFY function. */ +typedef R3PTRTYPE(FNPDMVMMDEVHEAPNOTIFY *) PFNPDMVMMDEVHEAPNOTIFY; + + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +/** @defgroup grp_pdm_r3 The PDM Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(int) PDMR3InitUVM(PUVM pUVM); +VMMR3_INT_DECL(int) PDMR3LdrLoadVMMR0U(PUVM pUVM); +VMMR3_INT_DECL(int) PDMR3Init(PVM pVM); +VMMR3_INT_DECL(int) PDMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3DECL(void) PDMR3PowerOn(PVM pVM); +VMMR3_INT_DECL(bool) PDMR3GetResetInfo(PVM pVM, uint32_t fOverride, uint32_t *pfResetFlags); +VMMR3_INT_DECL(void) PDMR3ResetCpu(PVMCPU pVCpu); +VMMR3_INT_DECL(void) PDMR3Reset(PVM pVM); +VMMR3_INT_DECL(void) PDMR3MemSetup(PVM pVM, bool fAtReset); +VMMR3_INT_DECL(void) PDMR3SoftReset(PVM pVM, uint32_t fResetFlags); +VMMR3_INT_DECL(void) PDMR3Suspend(PVM pVM); +VMMR3_INT_DECL(void) PDMR3Resume(PVM pVM); +VMMR3DECL(void) PDMR3PowerOff(PVM pVM); +VMMR3_INT_DECL(void) PDMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) PDMR3Term(PVM pVM); +VMMR3_INT_DECL(void) PDMR3TermUVM(PUVM pUVM); +VMMR3_INT_DECL(bool) PDMR3HasLoadedState(PVM pVM); + +/** PDM loader context indicator. */ +typedef enum PDMLDRCTX +{ + /** Invalid zero value. */ + PDMLDRCTX_INVALID = 0, + /** Ring-0 context. */ + PDMLDRCTX_RING_0, + /** Ring-3 context. */ + PDMLDRCTX_RING_3, + /** Raw-mode context. */ + PDMLDRCTX_RAW_MODE, + /** End of valid context values. */ + PDMLDRCTX_END, + /** 32-bit type hack. */ + PDMLDRCTX_32BIT_HACK = 0x7fffffff +} PDMLDRCTX; + +/** + * Module enumeration callback function. + * + * @returns VBox status. + * Failure will stop the search and return the return code. + * Warnings will be ignored and not returned. + * @param pVM The cross context VM structure. + * @param pszFilename Module filename. + * @param pszName Module name. (short and unique) + * @param ImageBase Address where to executable image is loaded. + * @param cbImage Size of the executable image. + * @param enmCtx The context the module is loaded into. + * @param pvArg User argument. + */ +typedef DECLCALLBACKTYPE(int, FNPDMR3ENUM,(PVM pVM, const char *pszFilename, const char *pszName, + RTUINTPTR ImageBase, size_t cbImage, PDMLDRCTX enmCtx, void *pvArg)); +/** Pointer to a FNPDMR3ENUM() function. */ +typedef FNPDMR3ENUM *PFNPDMR3ENUM; +VMMR3DECL(int) PDMR3LdrEnumModules(PVM pVM, PFNPDMR3ENUM pfnCallback, void *pvArg); +VMMR3_INT_DECL(void) PDMR3LdrRelocateU(PUVM pUVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) PDMR3LdrLoadR0(PUVM pUVM, const char *pszModule, const char *pszSearchPath); +VMMR3_INT_DECL(int) PDMR3LdrGetSymbolR3(PVM pVM, const char *pszModule, const char *pszSymbol, void **ppvValue); +VMMR3DECL(int) PDMR3LdrGetSymbolR0(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue); +VMMR3DECL(int) PDMR3LdrGetSymbolR0Lazy(PVM pVM, const char *pszModule, const char *pszSearchPath, const char *pszSymbol, PRTR0PTR ppvValue); +VMMR3DECL(int) PDMR3LdrLoadRC(PVM pVM, const char *pszFilename, const char *pszName); +VMMR3DECL(int) PDMR3LdrGetSymbolRC(PVM pVM, const char *pszModule, const char *pszSymbol, PRTRCPTR pRCPtrValue); +VMMR3DECL(int) PDMR3LdrGetSymbolRCLazy(PVM pVM, const char *pszModule, const char *pszSearchPath, const char *pszSymbol, + PRTRCPTR pRCPtrValue); +VMMR3_INT_DECL(int) PDMR3LdrQueryRCModFromPC(PVM pVM, RTRCPTR uPC, + char *pszModName, size_t cchModName, PRTRCPTR pMod, + char *pszNearSym1, size_t cchNearSym1, PRTRCPTR pNearSym1, + char *pszNearSym2, size_t cchNearSym2, PRTRCPTR pNearSym2); +VMMR3_INT_DECL(int) PDMR3LdrQueryR0ModFromPC(PVM pVM, RTR0PTR uPC, + char *pszModName, size_t cchModName, PRTR0PTR pMod, + char *pszNearSym1, size_t cchNearSym1, PRTR0PTR pNearSym1, + char *pszNearSym2, size_t cchNearSym2, PRTR0PTR pNearSym2); +VMMR3_INT_DECL(int) PDMR3LdrGetInterfaceSymbols(PVM pVM, void *pvInterface, size_t cbInterface, + const char *pszModule, const char *pszSearchPath, + const char *pszSymPrefix, const char *pszSymList, + bool fRing0OrRC); + +VMMR3DECL(int) PDMR3QueryDevice(PUVM pUVM, const char *pszDevice, unsigned iInstance, PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3QueryDeviceLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3QueryLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3QueryDriverOnLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, + const char *pszDriver, PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3DeviceAttach(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags, + PPDMIBASE *ppBase); +VMMR3DECL(int) PDMR3DeviceDetach(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags); +VMMR3_INT_DECL(PPDMCRITSECT) PDMR3DevGetCritSect(PVM pVM, PPDMDEVINS pDevIns); +VMMR3DECL(int) PDMR3DriverAttach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, uint32_t fFlags, + PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3DriverDetach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, + const char *pszDriver, unsigned iOccurrence, uint32_t fFlags); +VMMR3DECL(int) PDMR3DriverReattach(PUVM pVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, + const char *pszDriver, unsigned iOccurrence, uint32_t fFlags, PCFGMNODE pCfg, + PPPDMIBASE ppBase); +VMMR3DECL(void) PDMR3DmaRun(PVM pVM); + +VMMR3_INT_DECL(int) PDMR3VmmDevHeapAlloc(PVM pVM, size_t cbSize, PFNPDMVMMDEVHEAPNOTIFY pfnNotify, RTR3PTR *ppv); +VMMR3_INT_DECL(int) PDMR3VmmDevHeapFree(PVM pVM, RTR3PTR pv); +VMMR3_INT_DECL(int) PDMR3TracingConfig(PVM pVM, const char *pszName, size_t cchName, bool fEnable, bool fApply); +VMMR3_INT_DECL(bool) PDMR3TracingAreAll(PVM pVM, bool fEnabled); +VMMR3_INT_DECL(int) PDMR3TracingQueryConfig(PVM pVM, char *pszConfig, size_t cbConfig); +/** @} */ +#endif /* IN_RING3 */ + + + +/** @defgroup grp_pdm_rc The PDM Raw-Mode Context API + * @{ + */ +/** @} */ + + + +/** @defgroup grp_pdm_r0 The PDM Ring-0 Context API + * @{ + */ +VMMR0_INT_DECL(void) PDMR0Init(void *hMod); +VMMR0DECL(int) PDMR0DeviceRegisterModule(void *hMod, struct PDMDEVMODREGR0 *pModReg); +VMMR0DECL(int) PDMR0DeviceDeregisterModule(void *hMod, struct PDMDEVMODREGR0 *pModReg); + +VMMR0_INT_DECL(void) PDMR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(void) PDMR0CleanupVM(PGVM pGVM); + +/** + * Request buffer for PDMR0DriverCallReqHandler / VMMR0_DO_PDM_DRIVER_CALL_REQ_HANDLER. + * @see PDMR0DriverCallReqHandler. + */ +typedef struct PDMDRIVERCALLREQHANDLERREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The driver instance. */ + PPDMDRVINSR0 pDrvInsR0; + /** The operation. */ + uint32_t uOperation; + /** Explicit alignment padding. */ + uint32_t u32Alignment; + /** Optional 64-bit integer argument. */ + uint64_t u64Arg; +} PDMDRIVERCALLREQHANDLERREQ; +/** Pointer to a PDMR0DriverCallReqHandler / VMMR0_DO_PDM_DRIVER_CALL_REQ_HANDLER + * request buffer. */ +typedef PDMDRIVERCALLREQHANDLERREQ *PPDMDRIVERCALLREQHANDLERREQ; + +VMMR0_INT_DECL(int) PDMR0DriverCallReqHandler(PGVM pGVM, PPDMDRIVERCALLREQHANDLERREQ pReq); + + +/** + * Request buffer for PDMR0DeviceCreateReqHandler / VMMR0_DO_PDM_DEVICE_CREATE. + * @see PDMR0DeviceCreateReqHandler. + */ +typedef struct PDMDEVICECREATEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Where to return the address of the ring-3 device instance. */ + PPDMDEVINSR3 pDevInsR3; + + /** Copy of PDMDEVREGR3::fFlags for matching with PDMDEVREGR0::fFlags. */ + uint32_t fFlags; + /** Copy of PDMDEVREGR3::fClass for matching with PDMDEVREGR0::fFlags. */ + uint32_t fClass; + /** Copy of PDMDEVREGR3::cMaxInstances for matching with + * PDMDEVREGR0::cMaxInstances. */ + uint32_t cMaxInstances; + /** Copy of PDMDEVREGR3::uSharedVersion for matching with + * PDMDEVREGR0::uSharedVersion. */ + uint32_t uSharedVersion; + /** Copy of PDMDEVREGR3::cbInstanceShared for matching with + * PDMDEVREGR0::cbInstanceShared. */ + uint32_t cbInstanceShared; + /** Copy of PDMDEVREGR3::cbInstanceCC. */ + uint32_t cbInstanceR3; + /** Copy of PDMDEVREGR3::cbInstanceRC for matching with + * PDMDEVREGR0::cbInstanceRC. */ + uint32_t cbInstanceRC; + /** Copy of PDMDEVREGR3::cMaxPciDevices for matching with + * PDMDEVREGR0::cMaxPciDevices. */ + uint16_t cMaxPciDevices; + /** Copy of PDMDEVREGR3::cMaxMsixVectors for matching with + * PDMDEVREGR0::cMaxMsixVectors. */ + uint16_t cMaxMsixVectors; + + /** The device instance ordinal. */ + uint32_t iInstance; + /** Set if the raw-mode component is desired. */ + bool fRCEnabled; + /** Explicit padding. */ + bool afReserved[3]; + /** DBGF tracer event source handle if configured. */ + DBGFTRACEREVTSRC hDbgfTracerEvtSrc; + + /** In: Device name. */ + char szDevName[32]; + /** In: The module name (no path). */ + char szModName[32]; +} PDMDEVICECREATEREQ; +/** Pointer to a PDMR0DeviceCreate / VMMR0_DO_PDM_DEVICE_CREATE request buffer. */ +typedef PDMDEVICECREATEREQ *PPDMDEVICECREATEREQ; + +VMMR0_INT_DECL(int) PDMR0DeviceCreateReqHandler(PGVM pGVM, PPDMDEVICECREATEREQ pReq); + +/** + * The ring-0 device call to make. + */ +typedef enum PDMDEVICEGENCALL +{ + PDMDEVICEGENCALL_INVALID = 0, + PDMDEVICEGENCALL_CONSTRUCT, + PDMDEVICEGENCALL_DESTRUCT, + PDMDEVICEGENCALL_REQUEST, + PDMDEVICEGENCALL_END, + PDMDEVICEGENCALL_32BIT_HACK = 0x7fffffff +} PDMDEVICEGENCALL; + +/** + * Request buffer for PDMR0DeviceGenCallReqHandler / VMMR0_DO_PDM_DEVICE_GEN_CALL. + * @see PDMR0DeviceGenCallReqHandler. + */ +typedef struct PDMDEVICEGENCALLREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The ring-3 device instance. */ + PPDMDEVINSR3 pDevInsR3; + /** The ring-0 device handle. */ + uint32_t idxR0Device; + /** The call to make. */ + PDMDEVICEGENCALL enmCall; + union + { + /** PDMDEVICEGENCALL_REQUEST: */ + struct + { + /** The request argument. */ + uint64_t uArg; + /** The request number. */ + uint32_t uReq; + } Req; + /** Size padding. */ + uint64_t au64[3]; + } Params; +} PDMDEVICEGENCALLREQ; +/** Pointer to a PDMR0DeviceGenCallReqHandler / VMMR0_DO_PDM_DEVICE_GEN_CALL request buffer. */ +typedef PDMDEVICEGENCALLREQ *PPDMDEVICEGENCALLREQ; + +VMMR0_INT_DECL(int) PDMR0DeviceGenCallReqHandler(PGVM pGVM, PPDMDEVICEGENCALLREQ pReq, VMCPUID idCpu); + +/** + * Request buffer for PDMR0DeviceCompatSetCritSectReqHandler / VMMR0_DO_PDM_DEVICE_COMPAT_SET_CRITSECT + * @see PDMR0DeviceCompatSetCritSectReqHandler. + */ +typedef struct PDMDEVICECOMPATSETCRITSECTREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The ring-3 device instance. */ + PPDMDEVINSR3 pDevInsR3; + /** The ring-0 device handle. */ + uint32_t idxR0Device; + /** The critical section address (ring-3). */ + R3PTRTYPE(PPDMCRITSECT) pCritSectR3; +} PDMDEVICECOMPATSETCRITSECTREQ; +/** Pointer to a PDMR0DeviceGenCallReqHandler / VMMR0_DO_PDM_DEVICE_GEN_CALL request buffer. */ +typedef PDMDEVICECOMPATSETCRITSECTREQ *PPDMDEVICECOMPATSETCRITSECTREQ; + +VMMR0_INT_DECL(int) PDMR0DeviceCompatSetCritSectReqHandler(PGVM pGVM, PPDMDEVICECOMPATSETCRITSECTREQ pReq); + + +/** + * Request buffer for PDMR0QueueCreateReqHandler / VMMR0_DO_PDM_QUEUE_CREATE. + * @see PDMR0QueueCreateReqHandler. + */ +typedef struct PDMQUEUECREATEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + + /** Number of queue items. */ + uint32_t cItems; + /** Queue item size. */ + uint32_t cbItem; + /** Owner type (PDMQUEUETYPE). */ + uint32_t enmType; + /** The ring-3 owner pointer. */ + RTR3PTR pvOwner; + /** The ring-3 callback function address. */ + RTR3PTR pfnCallback; + /** The queue name. */ + char szName[40]; + + /** Output: The queue handle. */ + PDMQUEUEHANDLE hQueue; +} PDMQUEUECREATEREQ; +/** Pointer to a PDMR0QueueCreateReqHandler / VMMR0_DO_PDM_QUEUE_CREATE request buffer. */ +typedef PDMQUEUECREATEREQ *PPDMQUEUECREATEREQ; + +VMMR0_INT_DECL(int) PDMR0QueueCreateReqHandler(PGVM pGVM, PPDMQUEUECREATEREQ pReq); + +/** @} */ + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmapi_h */ diff --git a/include/VBox/vmm/pdmasynccompletion.h b/include/VBox/vmm/pdmasynccompletion.h new file mode 100644 index 00000000..f46d7910 --- /dev/null +++ b/include/VBox/vmm/pdmasynccompletion.h @@ -0,0 +1,160 @@ +/** @file + * PDM - Pluggable Device Manager, Async I/O Completion. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmasynccompletion_h +#define VBOX_INCLUDED_vmm_pdmasynccompletion_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/sg.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_async_completion The PDM Async I/O Completion API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer to a PDM async completion template handle. */ +typedef struct PDMASYNCCOMPLETIONTEMPLATE *PPDMASYNCCOMPLETIONTEMPLATE; +/** Pointer to a PDM async completion template handle pointer. */ +typedef PPDMASYNCCOMPLETIONTEMPLATE *PPPDMASYNCCOMPLETIONTEMPLATE; + +/** Pointer to a PDM async completion task handle. */ +typedef struct PDMASYNCCOMPLETIONTASK *PPDMASYNCCOMPLETIONTASK; +/** Pointer to a PDM async completion task handle pointer. */ +typedef PPDMASYNCCOMPLETIONTASK *PPPDMASYNCCOMPLETIONTASK; + +/** Pointer to a PDM async completion endpoint handle. */ +typedef struct PDMASYNCCOMPLETIONENDPOINT *PPDMASYNCCOMPLETIONENDPOINT; +/** Pointer to a PDM async completion endpoint handle pointer. */ +typedef PPDMASYNCCOMPLETIONENDPOINT *PPPDMASYNCCOMPLETIONENDPOINT; + + +/** + * Completion callback for devices. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMASYNCCOMPLETEDEV,(PPDMDEVINS pDevIns, void *pvUser, int rc)); +/** Pointer to a FNPDMASYNCCOMPLETEDEV(). */ +typedef FNPDMASYNCCOMPLETEDEV *PFNPDMASYNCCOMPLETEDEV; + + +/** + * Completion callback for drivers. + * + * @param pDrvIns The driver instance. + * @param pvTemplateUser User argument given when creating the template. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMASYNCCOMPLETEDRV,(PPDMDRVINS pDrvIns, void *pvTemplateUser, void *pvUser, int rc)); +/** Pointer to a FNPDMASYNCCOMPLETEDRV(). */ +typedef FNPDMASYNCCOMPLETEDRV *PFNPDMASYNCCOMPLETEDRV; + + +/** + * Completion callback for USB devices. + * + * @param pUsbIns The USB device instance. + * @param pvUser User argument. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMASYNCCOMPLETEUSB,(PPDMUSBINS pUsbIns, void *pvUser, int rc)); +/** Pointer to a FNPDMASYNCCOMPLETEUSB(). */ +typedef FNPDMASYNCCOMPLETEUSB *PFNPDMASYNCCOMPLETEUSB; + + +/** + * Completion callback for internal. + * + * @param pVM The cross context VM structure. + * @param pvUser User argument for the task. + * @param pvUser2 User argument for the template. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMASYNCCOMPLETEINT,(PVM pVM, void *pvUser, void *pvUser2, int rc)); +/** Pointer to a FNPDMASYNCCOMPLETEINT(). */ +typedef FNPDMASYNCCOMPLETEINT *PFNPDMASYNCCOMPLETEINT; + +VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateInternal(PVM pVM, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, + PFNPDMASYNCCOMPLETEINT pfnCompleted, void *pvUser2, const char *pszDesc); +VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroy(PPDMASYNCCOMPLETIONTEMPLATE pTemplate); +VMMR3DECL(int) PDMR3AsyncCompletionEpCreateForFile(PPPDMASYNCCOMPLETIONENDPOINT ppEndpoint, + const char *pszFilename, uint32_t fFlags, + PPDMASYNCCOMPLETIONTEMPLATE pTemplate); + +/** @defgroup grp_pdmacep_file_flags Flags for PDMR3AsyncCompletionEpCreateForFile + * @{ */ +/** Open the file in read-only mode. */ +#define PDMACEP_FILE_FLAGS_READ_ONLY RT_BIT_32(0) +/** Whether the file should not be write protected. + * The default is to protect the file against writes by other processes + * when opened in read/write mode to prevent data corruption by + * concurrent access which can occur if the local writeback cache is enabled. + */ +#define PDMACEP_FILE_FLAGS_DONT_LOCK RT_BIT_32(2) +/** Open the endpoint with the host cache enabled. */ +#define PDMACEP_FILE_FLAGS_HOST_CACHE_ENABLED RT_BIT_32(3) +/** @} */ + +VMMR3DECL(void) PDMR3AsyncCompletionEpClose(PPDMASYNCCOMPLETIONENDPOINT pEndpoint); +VMMR3DECL(int) PDMR3AsyncCompletionEpRead(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbRead, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask); +VMMR3DECL(int) PDMR3AsyncCompletionEpWrite(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbWrite, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask); +VMMR3DECL(int) PDMR3AsyncCompletionEpFlush(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser, PPPDMASYNCCOMPLETIONTASK ppTask); +VMMR3DECL(int) PDMR3AsyncCompletionEpGetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t *pcbSize); +VMMR3DECL(int) PDMR3AsyncCompletionEpSetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cbSize); +VMMR3DECL(int) PDMR3AsyncCompletionEpSetBwMgr(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, const char *pszBwMgr); +VMMR3DECL(int) PDMR3AsyncCompletionTaskCancel(PPDMASYNCCOMPLETIONTASK pTask); +VMMR3DECL(int) PDMR3AsyncCompletionBwMgrSetMaxForFile(PUVM pUVM, const char *pszBwMgr, uint32_t cbMaxNew); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmasynccompletion_h */ + diff --git a/include/VBox/vmm/pdmasynctask.h b/include/VBox/vmm/pdmasynctask.h new file mode 100644 index 00000000..422f9727 --- /dev/null +++ b/include/VBox/vmm/pdmasynctask.h @@ -0,0 +1,74 @@ +/** @file + * PDM - Pluggable Device Manager, Async Task. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmasynctask_h +#define VBOX_INCLUDED_vmm_pdmasynctask_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_async_task The PDM Async Task API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer to a PDM async task template handle. */ +typedef struct PDMASYNCTASKTEMPLATE *PPDMASYNCTASKTEMPLATE; +/** Pointer to a PDM async task template handle pointer. */ +typedef PPDMASYNCTASKTEMPLATE *PPPDMASYNCTASKTEMPLATE; + +/** Pointer to a PDM async task handle. */ +typedef struct PDMASYNCTASK *PPDMASYNCTASK; +/** Pointer to a PDM async task handle pointer. */ +typedef PPDMASYNCTASK *PPPDMASYNCTASK; + +/* This should be similar to VMReq, only difference there will be a pool + of worker threads instead of EMT. The actual implementation should be + made in IPRT so we can reuse it for other stuff later. The reason why + it should be put in PDM is because we need to manage it wrt to VM + state changes (need exception - add a flag for this). */ + +/** @} */ + + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmasynctask_h */ + diff --git a/include/VBox/vmm/pdmaudiohostenuminline.h b/include/VBox/vmm/pdmaudiohostenuminline.h new file mode 100644 index 00000000..538c3bd6 --- /dev/null +++ b/include/VBox/vmm/pdmaudiohostenuminline.h @@ -0,0 +1,463 @@ +/* $Id: pdmaudiohostenuminline.h $ */ +/** @file + * PDM - Audio Helpers for host audio device enumeration, Inlined Code. (DEV,++) + * + * This is all inlined because it's too tedious to create a couple libraries to + * contain it all (same bad excuse as for intnetinline.h & pdmnetinline.h). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmaudiohostenuminline_h +#define VBOX_INCLUDED_vmm_pdmaudiohostenuminline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/err.h> +#include <VBox/log.h> +#include <VBox/vmm/pdmaudioifs.h> +#include <VBox/vmm/pdmaudioinline.h> + +#include <iprt/assert.h> +#include <iprt/mem.h> +#include <iprt/string.h> + + +/** @defgroup grp_pdm_audio_host_enum_inline The PDM Host Audio Enumeration Helper APIs + * @ingroup grp_pdm + * @{ + */ + + +/** + * Allocates a host audio device for an enumeration result. + * + * @returns Newly allocated audio device, or NULL on failure. + * @param cb The total device structure size. This must be at least the + * size of PDMAUDIOHOSTDEV. The idea is that the caller extends + * the PDMAUDIOHOSTDEV structure and appends additional data + * after it in its private structure. + * @param cbName The number of bytes to allocate for the name field + * (including the terminator). Pass zero if RTStrAlloc and + * friends will be used. + * @param cbId The number of bytes to allocate for the ID field. Pass + * zero if RTStrAlloc and friends will be used. + */ +DECLINLINE(PPDMAUDIOHOSTDEV) PDMAudioHostDevAlloc(size_t cb, size_t cbName, size_t cbId) +{ + AssertReturn(cb >= sizeof(PDMAUDIOHOSTDEV), NULL); + AssertReturn(cb < _4M, NULL); + AssertReturn(cbName < _4K, NULL); + AssertReturn(cbId < _16K, NULL); + + PPDMAUDIOHOSTDEV pDev = (PPDMAUDIOHOSTDEV)RTMemAllocZ(RT_ALIGN_Z(cb + cbName + cbId, 64)); + if (pDev) + { + pDev->uMagic = PDMAUDIOHOSTDEV_MAGIC; + pDev->cbSelf = (uint32_t)cb; + RTListInit(&pDev->ListEntry); + if (cbName) + pDev->pszName = (char *)pDev + cb; + if (cbId) + pDev->pszId = (char *)pDev + cb + cbName; + } + return pDev; +} + +/** + * Frees a host audio device allocated by PDMAudioHostDevAlloc. + * + * @param pDev The device to free. NULL is ignored. + */ +DECLINLINE(void) PDMAudioHostDevFree(PPDMAUDIOHOSTDEV pDev) +{ + if (pDev) + { + Assert(pDev->uMagic == PDMAUDIOHOSTDEV_MAGIC); + pDev->uMagic = ~PDMAUDIOHOSTDEV_MAGIC; + pDev->cbSelf = 0; + + if (pDev->fFlags & PDMAUDIOHOSTDEV_F_NAME_ALLOC) + { + RTStrFree(pDev->pszName); + pDev->pszName = NULL; + } + + if (pDev->fFlags & PDMAUDIOHOSTDEV_F_ID_ALLOC) + { + RTStrFree(pDev->pszId); + pDev->pszId = NULL; + } + + RTMemFree(pDev); + } +} + +/** + * Duplicates a host audio device enumeration entry. + * + * @returns Duplicated audio device entry on success, or NULL on failure. + * @param pDev The audio device enum entry to duplicate. + * @param fOnlyCoreData + */ +DECLINLINE(PPDMAUDIOHOSTDEV) PDMAudioHostDevDup(PCPDMAUDIOHOSTDEV pDev, bool fOnlyCoreData) +{ + AssertPtrReturn(pDev, NULL); + Assert(pDev->uMagic == PDMAUDIOHOSTDEV_MAGIC); + Assert(fOnlyCoreData || !(pDev->fFlags & PDMAUDIOHOSTDEV_F_NO_DUP)); + + uint32_t cbToDup = fOnlyCoreData ? sizeof(PDMAUDIOHOSTDEV) : pDev->cbSelf; + AssertReturn(cbToDup >= sizeof(*pDev), NULL); + + PPDMAUDIOHOSTDEV pDevDup = PDMAudioHostDevAlloc(cbToDup, 0, 0); + if (pDevDup) + { + memcpy(pDevDup, pDev, cbToDup); + RTListInit(&pDevDup->ListEntry); + pDevDup->cbSelf = cbToDup; + + if (pDev->pszName) + { + uintptr_t off; + if ( (pDevDup->fFlags & PDMAUDIOHOSTDEV_F_NAME_ALLOC) + || (off = (uintptr_t)pDev->pszName - (uintptr_t)pDev) >= pDevDup->cbSelf) + { + pDevDup->fFlags |= PDMAUDIOHOSTDEV_F_NAME_ALLOC; + pDevDup->pszName = RTStrDup(pDev->pszName); + AssertReturnStmt(pDevDup->pszName, PDMAudioHostDevFree(pDevDup), NULL); + } + else + pDevDup->pszName = (char *)pDevDup + off; + } + + if (pDev->pszId) + { + uintptr_t off; + if ( (pDevDup->fFlags & PDMAUDIOHOSTDEV_F_ID_ALLOC) + || (off = (uintptr_t)pDev->pszId - (uintptr_t)pDev) >= pDevDup->cbSelf) + { + pDevDup->fFlags |= PDMAUDIOHOSTDEV_F_ID_ALLOC; + pDevDup->pszId = RTStrDup(pDev->pszId); + AssertReturnStmt(pDevDup->pszId, PDMAudioHostDevFree(pDevDup), NULL); + } + else + pDevDup->pszId = (char *)pDevDup + off; + } + } + + return pDevDup; +} + +/** + * Initializes a host audio device enumeration. + * + * @param pDevEnm The enumeration to initialize. + */ +DECLINLINE(void) PDMAudioHostEnumInit(PPDMAUDIOHOSTENUM pDevEnm) +{ + AssertPtr(pDevEnm); + + pDevEnm->uMagic = PDMAUDIOHOSTENUM_MAGIC; + pDevEnm->cDevices = 0; + RTListInit(&pDevEnm->LstDevices); +} + +/** + * Deletes the host audio device enumeration and frees all device entries + * associated with it. + * + * The user must call PDMAudioHostEnumInit again to use it again. + * + * @param pDevEnm The host audio device enumeration to delete. + */ +DECLINLINE(void) PDMAudioHostEnumDelete(PPDMAUDIOHOSTENUM pDevEnm) +{ + if (pDevEnm) + { + AssertPtr(pDevEnm); + AssertReturnVoid(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC); + + PPDMAUDIOHOSTDEV pDev, pDevNext; + RTListForEachSafe(&pDevEnm->LstDevices, pDev, pDevNext, PDMAUDIOHOSTDEV, ListEntry) + { + RTListNodeRemove(&pDev->ListEntry); + + PDMAudioHostDevFree(pDev); + + pDevEnm->cDevices--; + } + + /* Sanity. */ + Assert(RTListIsEmpty(&pDevEnm->LstDevices)); + Assert(pDevEnm->cDevices == 0); + + pDevEnm->uMagic = ~PDMAUDIOHOSTENUM_MAGIC; + } +} + +/** + * Adds an audio device to a device enumeration. + * + * @param pDevEnm Device enumeration to add device to. + * @param pDev Device to add. The pointer will be owned by the device enumeration then. + */ +DECLINLINE(void) PDMAudioHostEnumAppend(PPDMAUDIOHOSTENUM pDevEnm, PPDMAUDIOHOSTDEV pDev) +{ + AssertPtr(pDevEnm); + AssertPtr(pDev); + Assert(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC); + + RTListAppend(&pDevEnm->LstDevices, &pDev->ListEntry); + pDevEnm->cDevices++; +} + +/** + * Appends copies of matching host device entries from one to another enumeration. + * + * @returns VBox status code. + * @param pDstDevEnm The target to append copies of matching device to. + * @param pSrcDevEnm The source to copy matching devices from. + * @param enmUsage The usage to match for copying. + * Use PDMAUDIODIR_INVALID to match all entries. + * @param fOnlyCoreData Set this to only copy the PDMAUDIOHOSTDEV part. + * Careful with passing @c false here as not all + * backends have data that can be copied. + */ +DECLINLINE(int) PDMAudioHostEnumCopy(PPDMAUDIOHOSTENUM pDstDevEnm, PCPDMAUDIOHOSTENUM pSrcDevEnm, + PDMAUDIODIR enmUsage, bool fOnlyCoreData) +{ + AssertPtrReturn(pDstDevEnm, VERR_INVALID_POINTER); + AssertReturn(pDstDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, VERR_WRONG_ORDER); + + AssertPtrReturn(pSrcDevEnm, VERR_INVALID_POINTER); + AssertReturn(pSrcDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, VERR_WRONG_ORDER); + + PPDMAUDIOHOSTDEV pSrcDev; + RTListForEach(&pSrcDevEnm->LstDevices, pSrcDev, PDMAUDIOHOSTDEV, ListEntry) + { + if ( enmUsage == pSrcDev->enmUsage + || enmUsage == PDMAUDIODIR_INVALID /*all*/) + { + PPDMAUDIOHOSTDEV pDstDev = PDMAudioHostDevDup(pSrcDev, fOnlyCoreData); + AssertReturn(pDstDev, VERR_NO_MEMORY); + + PDMAudioHostEnumAppend(pDstDevEnm, pDstDev); + } + } + + return VINF_SUCCESS; +} + +/** + * Moves all the device entries from one enumeration to another, destroying the + * former. + * + * @returns VBox status code. + * @param pDstDevEnm The target to put move @a pSrcDevEnm to. This + * does not need to be initialized, but if it is it + * must not have any device entries. + * @param pSrcDevEnm The source to move from. This will be empty + * upon successful return. + */ +DECLINLINE(int) PDMAudioHostEnumMove(PPDMAUDIOHOSTENUM pDstDevEnm, PPDMAUDIOHOSTENUM pSrcDevEnm) +{ + AssertPtrReturn(pDstDevEnm, VERR_INVALID_POINTER); + AssertReturn(pDstDevEnm->uMagic != PDMAUDIOHOSTENUM_MAGIC || pDstDevEnm->cDevices == 0, VERR_WRONG_ORDER); + + AssertPtrReturn(pSrcDevEnm, VERR_INVALID_POINTER); + AssertReturn(pSrcDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, VERR_WRONG_ORDER); + + pDstDevEnm->uMagic = PDMAUDIOHOSTENUM_MAGIC; + RTListInit(&pDstDevEnm->LstDevices); + pDstDevEnm->cDevices = pSrcDevEnm->cDevices; + if (pSrcDevEnm->cDevices) + { + PPDMAUDIOHOSTDEV pCur; + while ((pCur = RTListRemoveFirst(&pSrcDevEnm->LstDevices, PDMAUDIOHOSTDEV, ListEntry)) != NULL) + RTListAppend(&pDstDevEnm->LstDevices, &pCur->ListEntry); + } + return VINF_SUCCESS; +} + +/** + * Get the default device with the given usage. + * + * This assumes that only one default device per usage is set, if there should + * be more than one, the first one is returned. + * + * @returns Default device if found, or NULL if not. + * @param pDevEnm Device enumeration to get default device for. + * @param enmUsage Usage to get default device for. + * Pass PDMAUDIODIR_INVALID to get the first device with + * either PDMAUDIOHOSTDEV_F_DEFAULT_OUT or + * PDMAUDIOHOSTDEV_F_DEFAULT_IN set. + */ +DECLINLINE(PPDMAUDIOHOSTDEV) PDMAudioHostEnumGetDefault(PCPDMAUDIOHOSTENUM pDevEnm, PDMAUDIODIR enmUsage) +{ + AssertPtrReturn(pDevEnm, NULL); + AssertReturn(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, NULL); + + Assert(enmUsage == PDMAUDIODIR_IN || enmUsage == PDMAUDIODIR_OUT || enmUsage == PDMAUDIODIR_INVALID); + uint32_t const fFlags = enmUsage == PDMAUDIODIR_IN ? PDMAUDIOHOSTDEV_F_DEFAULT_IN + : enmUsage == PDMAUDIODIR_OUT ? PDMAUDIOHOSTDEV_F_DEFAULT_OUT + : enmUsage == PDMAUDIODIR_INVALID ? PDMAUDIOHOSTDEV_F_DEFAULT_IN | PDMAUDIOHOSTDEV_F_DEFAULT_OUT + : 0; + + PPDMAUDIOHOSTDEV pDev; + RTListForEach(&pDevEnm->LstDevices, pDev, PDMAUDIOHOSTDEV, ListEntry) + { + if (pDev->fFlags & fFlags) + { + Assert(pDev->enmUsage == enmUsage || pDev->enmUsage == PDMAUDIODIR_DUPLEX || enmUsage == PDMAUDIODIR_INVALID); + return pDev; + } + } + + return NULL; +} + +/** + * Get the number of device with the given usage. + * + * @returns Number of matching devices. + * @param pDevEnm Device enumeration to get default device for. + * @param enmUsage Usage to count devices for. + * Pass PDMAUDIODIR_INVALID to get the total number of devices. + */ +DECLINLINE(uint32_t) PDMAudioHostEnumCountMatching(PCPDMAUDIOHOSTENUM pDevEnm, PDMAUDIODIR enmUsage) +{ + AssertPtrReturn(pDevEnm, 0); + AssertReturn(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, 0); + + if (enmUsage == PDMAUDIODIR_INVALID) + return pDevEnm->cDevices; + + uint32_t cDevs = 0; + PPDMAUDIOHOSTDEV pDev; + RTListForEach(&pDevEnm->LstDevices, pDev, PDMAUDIOHOSTDEV, ListEntry) + { + if (enmUsage == pDev->enmUsage) + cDevs++; + } + + return cDevs; +} + +/** The max string length for all PDMAUDIOHOSTDEV_F_XXX. + * @sa PDMAudioHostDevFlagsToString */ +#define PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN sizeof("DEFAULT_OUT DEFAULT_IN HOTPLUG BUGGY IGNORE LOCKED DEAD NAME_ALLOC ID_ALLOC NO_DUP ") + +/** + * Converts an audio device flags to a string. + * + * @returns + * @param pszDst Destination buffer with a size of at least + * PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN bytes (including + * the string terminator). + * @param fFlags Audio flags (PDMAUDIOHOSTDEV_F_XXX) to convert. + */ +DECLINLINE(const char *) PDMAudioHostDevFlagsToString(char pszDst[PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN], uint32_t fFlags) +{ + static const struct { const char *pszMnemonic; uint32_t cchMnemonic; uint32_t fFlag; } s_aFlags[] = + { + { RT_STR_TUPLE("DEFAULT_OUT "), PDMAUDIOHOSTDEV_F_DEFAULT_OUT }, + { RT_STR_TUPLE("DEFAULT_IN "), PDMAUDIOHOSTDEV_F_DEFAULT_IN }, + { RT_STR_TUPLE("HOTPLUG "), PDMAUDIOHOSTDEV_F_HOTPLUG }, + { RT_STR_TUPLE("BUGGY "), PDMAUDIOHOSTDEV_F_BUGGY }, + { RT_STR_TUPLE("IGNORE "), PDMAUDIOHOSTDEV_F_IGNORE }, + { RT_STR_TUPLE("LOCKED "), PDMAUDIOHOSTDEV_F_LOCKED }, + { RT_STR_TUPLE("DEAD "), PDMAUDIOHOSTDEV_F_DEAD }, + { RT_STR_TUPLE("NAME_ALLOC "), PDMAUDIOHOSTDEV_F_NAME_ALLOC }, + { RT_STR_TUPLE("ID_ALLOC "), PDMAUDIOHOSTDEV_F_ID_ALLOC }, + { RT_STR_TUPLE("NO_DUP "), PDMAUDIOHOSTDEV_F_NO_DUP }, + }; + size_t offDst = 0; + for (uint32_t i = 0; i < RT_ELEMENTS(s_aFlags); i++) + if (fFlags & s_aFlags[i].fFlag) + { + fFlags &= ~s_aFlags[i].fFlag; + memcpy(&pszDst[offDst], s_aFlags[i].pszMnemonic, s_aFlags[i].cchMnemonic); + offDst += s_aFlags[i].cchMnemonic; + } + Assert(fFlags == 0); + Assert(offDst < PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN); + + if (offDst) + pszDst[offDst - 1] = '\0'; + else + memcpy(pszDst, "NONE", sizeof("NONE")); + return pszDst; +} + +/** + * Logs an audio device enumeration. + * + * @param pDevEnm Device enumeration to log. + * @param pszDesc Logging description (prefix). + */ +DECLINLINE(void) PDMAudioHostEnumLog(PCPDMAUDIOHOSTENUM pDevEnm, const char *pszDesc) +{ +#ifdef LOG_ENABLED + AssertPtrReturnVoid(pDevEnm); + AssertPtrReturnVoid(pszDesc); + AssertReturnVoid(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC); + + if (LogIsEnabled()) + { + LogFunc(("%s: %RU32 devices\n", pszDesc, pDevEnm->cDevices)); + + PPDMAUDIOHOSTDEV pDev; + RTListForEach(&pDevEnm->LstDevices, pDev, PDMAUDIOHOSTDEV, ListEntry) + { + char szFlags[PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN]; + LogFunc(("Device '%s':\n", pDev->pszName)); + LogFunc((" ID = %s\n", pDev->pszId ? pDev->pszId : "<none>")); + LogFunc((" Usage = %s\n", PDMAudioDirGetName(pDev->enmUsage))); + LogFunc((" Flags = %s\n", PDMAudioHostDevFlagsToString(szFlags, pDev->fFlags))); + LogFunc((" Input channels = %RU8\n", pDev->cMaxInputChannels)); + LogFunc((" Output channels = %RU8\n", pDev->cMaxOutputChannels)); + LogFunc((" cbExtra = %RU32 bytes\n", pDev->cbSelf - sizeof(PDMAUDIOHOSTDEV))); + } + } +#else + RT_NOREF(pDevEnm, pszDesc); +#endif +} + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmaudiohostenuminline_h */ diff --git a/include/VBox/vmm/pdmaudioifs.h b/include/VBox/vmm/pdmaudioifs.h new file mode 100644 index 00000000..11735f25 --- /dev/null +++ b/include/VBox/vmm/pdmaudioifs.h @@ -0,0 +1,1567 @@ +/** @file + * PDM - Pluggable Device Manager, Audio interfaces. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +/** @page pg_pdm_audio PDM Audio + * + * PDM provides audio device emulations and their driver chains with the + * interfaces they need to communicate with each other. + * + * + * @section sec_pdm_audio_overview Overview + * +@startuml +skinparam componentStyle rectangle + +node VM { + [Music Player App] --> [Guest Audio Driver] + [Recording App] <-- [Guest Audio Driver] +} + +component "DevAudio (DevHda / DevIchAc97 / DevSB16)" as DevAudio { + [Output DMA Engine] + [Input DMA Engine] + () LUN0 + () LUN1 + + component "AudioMixer" { + component "Output Sink" { + () "Output Stream #0" as DrvStreamOut0 + () "Output Stream #1" as DrvStreamOut1 + [Output Mixer Buffer] --> DrvStreamOut0 + [Output Mixer Buffer] --> DrvStreamOut1 + [Output DMA Engine] --> [Output Mixer Buffer] + DrvStreamOut0 --> LUN0 + DrvStreamOut1 --> LUN1 + } + component "Input Sink" { + () "Input Stream #2" as DrvStreamIn0 + () "Input Stream #3" as DrvStreamIn1 + [Input Mixer Buffer] <-- DrvStreamIn0 + [Input Mixer Buffer] <-- DrvStreamIn1 + [Input DMA Engine] --> [Input Mixer Buffer] + DrvStreamIn0 <-- LUN0 + DrvStreamIn1 <-- LUN1 + } + } +} +[Guest Audio Driver] <..> DevAudio : " MMIO or Port I/O, DMA" + +node "Driver Chain #0" { + component "DrvAudio#0" { + () PDMIHOSTAUDIOPORT0 + () PDMIAUDIOCONNECTOR0 + } + component "DrvHostAudioWasApi" { + () PDMIHOSTAUDIO0 + } +} +PDMIHOSTAUDIOPORT0 <--> PDMIHOSTAUDIO0 + +node "Driver Chain #1" { + component "DrvAudio#1" { + () PDMIAUDIOCONNECTOR1 + () PDMIHOSTAUDIOPORT1 + } + component "DrvAudioVRDE" { + () PDMIHOSTAUDIO1 + } +} +note bottom of DrvAudioVRDE + The backend driver is sometimes not configured if the component it represents + is not configured for the VM. However, Main will still set up the LUN but + with just DrvAudio attached to simplify runtime activation of the component. + In the meanwhile, the DrvAudio instance works as if DrvHostAudioNull were attached. +end note + +LUN1 <--> PDMIAUDIOCONNECTOR1 +LUN0 <--> PDMIAUDIOCONNECTOR0 + +PDMIHOSTAUDIOPORT1 <--> PDMIHOSTAUDIO1 + +@enduml + * + * Actors: + * - An audio device implementation: "DevAudio" + * - Mixer instance (AudioMixer.cpp) with one or more mixer + * sinks: "Output Sink", "Input Sink" + * - One DMA engine teamed up with each mixer sink: "Output DMA + * Engine", "Input DMA Engine" + * - The audio driver "DrvAudio" instances attached to LUN0 and LUN1 + * respectively: "DrvAudio#0", "DrvAudio#1" + * - The Windows host audio driver attached to "DrvAudio0": "DrvHostAudioWas" + * - The VRDE/VRDP host audio driver attached to "DrvAudio1": "DrvAudioVRDE" + * + * Both "Output Sink" and "Input Sink" talks to all the attached driver chains + * ("DrvAudio #0" and "DrvAudio #1"), but using different PDMAUDIOSTREAM + * instances. There can be an arbritrary number of driver chains attached to an + * audio device, the mixer sinks will multiplex output to each of them and blend + * input from all of them, taking care of format and rate conversions. The + * mixer and mixer sinks does not fit into the PDM device/driver model, because + * a driver can only have exactly one or zero other drivers attached, so it is + * implemented as a separate component that all the audio devices share (see + * AudioMixer.h, AudioMixer.cpp, AudioMixBuffer.h and AudioMixBuffer.cpp). + * + * The driver chains attached to LUN0, LUN1, ... LUNn typically have two + * drivers attached, first DrvAudio and then a backend driver like + * DrvHostAudioWasApi, DrvHostAudioPulseAudio, or DrvAudioVRDE. DrvAudio + * exposes PDMIAUDIOCONNECTOR upwards towards the device and mixer component, + * and PDMIHOSTAUDIOPORT downwards towards DrvHostAudioWasApi and the other + * backends. + * + * The backend exposes the PDMIHOSTAUDIO upwards towards DrvAudio. It is + * possible, though, to only have the DrvAudio instance and not backend, in + * which case DrvAudio works as if the NULL backend was attached. Main does + * such setups when the main component we're interfacing with isn't currently + * active, as this simplifies runtime activation. + * + * The purpose of DrvAudio is to make the work of the backend as simple as + * possible and try avoid needing to write the same code over and over again for + * each backend. It takes care of: + * - Stream creation, operation, re-initialization and destruction. + * - Pre-buffering. + * - Thread pool. + * + * The purpose of a host audio driver (aka backend) is to interface with the + * host audio system (or other audio systems like VRDP and video recording). + * The backend will optionally provide a list of host audio devices, switch + * between them, and monitor changes to them. By default our host backends use + * the default host device and will trigger stream re-initialization if this + * changes while we're using it. + * + * + * @section sec_pdm_audio_device Virtual Audio Device + * + * The virtual device translates the settings of the emulated device into mixing + * sinks with sample format, sample rate, volume control, and whatnot. + * + * It also implements a DMA engine for transfering samples to (input) or from + * (output) the guest memory. The starting and stopping of the DMA engines are + * communicated to the associated mixing sinks and by then onto the + * PDMAUDIOSTREAM instance for each driver chain. A RTCIRCBUF is used as an + * intermediary between the DMA engine and the asynchronous worker thread of the + * mixing sink. + * + * + * @section sec_pdm_audio_mixing Audio Mixing + * + * The audio mixer is a mandatory component in an audio device. It consists of + * a mixer and one or more sinks with mixer buffers. The sinks are typically + * one per virtual output/input connector, so for instance you could have a + * device with a "PCM Output" sink and a "PCM Input" sink. + * + * The audio mixer takes care of: + * - Much of the driver chain (LUN) management work. + * - Multiplexing output to each active driver chain. + * - Blending input from each active driver chain into a single audio + * stream. + * - Do format conversion (it uses signed 32-bit PCM internally) between + * the audio device and all of the LUNs (no common format needed). + * - Do sample rate conversions between the device rate and that of the + * individual driver chains. + * - Apply the volume settings of the device to the audio stream. + * - Provide the asynchronous thread that pushes data from the device's + * internal DMA buffer and all the way to the backend for output sinks, + * and vice versa for input. + * + * The term active LUNs above means that not all LUNs will actually produce + * (input) or consume (output) audio. The mixer checks the return of + * PDMIHOSTAUDIO::pfnStreamGetState each time it's processing samples to see + * which streams are currently active and which aren't. Inactive streams are + * ignored. + * + * For more info: @ref pg_audio_mixer, @ref pg_audio_mixing_buffers + * + * The AudioMixer API reference can be found here: + * - @ref grp_pdm_ifs_audio_mixing + * - @ref grp_pdm_ifs_audio_mixing_buffers + * + * + * @section sec_pdm_audio_timing Timing + * + * Handling audio data in a virtual environment is hard, as the human perception + * is very sensitive to the slightest cracks and stutters in the audible data, + * and the task of playing back and recording audio is in the real-time domain. + * + * The virtual machine is not executed with any real-time guarentees, only best + * effort, mainly because it is subject to preemptive scheduling on the host + * side. The audio processing done on the guest side is typically also subject + * to preemptive scheduling on the guest side and available CPU processing power + * there. + * + * Thus, the guest may be lagging behind because the host prioritizes other + * processes/threads over the virtual machine. This will, if it's too servere, + * cause the virtual machine to speed up it's time sense while it's trying to + * catch up. So, we can easily have a bit of a seesaw execution going on here, + * where in the playback case, the guest produces data too slowly for while and + * then switches to producing it too quickly for a while to catch up. + * + * Our working principle is that the backends and the guest are producing and + * consuming samples at the same rate, but we have to deal with the uneven + * execution. + * + * To deal with this we employ (by default) 300ms of backend buffer and + * pre-buffer 150ms of that for both input and output audio streams. This means + * we have about 150ms worth of samples to feed to the host audio device should + * the virtual machine be starving and lagging behind. Likewise, we have about + * 150ms of buffer space will can fill when the VM is in a catch-up mode. Now, + * 300ms and 150 ms isn't much for the purpose of glossing over + * scheduling/timing differences here, but we can't do too much more or the lag + * will grow rather annoying. The pre-buffering is implemented by DrvAudio. + * + * In addition to the backend buffer that defaults to 300ms, we have the + * internal DMA buffer of the device and the mixing buffer of the mixing sink. + * The latter two are typically rather small, sized to fit the anticipated DMA + * period currently in use by the guest. + */ + +#ifndef VBOX_INCLUDED_vmm_pdmaudioifs_h +#define VBOX_INCLUDED_vmm_pdmaudioifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assertcompile.h> +#include <iprt/critsect.h> +#include <iprt/circbuf.h> +#include <iprt/list.h> +#include <iprt/path.h> + +#include <VBox/types.h> +#include <VBox/vmm/pdmcommon.h> +#include <VBox/vmm/stam.h> + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_pdm_ifs_audio PDM Audio Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + +/** The maximum number of channels PDM supports. */ +#define PDMAUDIO_MAX_CHANNELS 12 + +/** + * Audio direction. + */ +typedef enum PDMAUDIODIR +{ + /** Invalid zero value as per usual (guards against using unintialized values). */ + PDMAUDIODIR_INVALID = 0, + /** Unknown direction. */ + PDMAUDIODIR_UNKNOWN, + /** Input. */ + PDMAUDIODIR_IN, + /** Output. */ + PDMAUDIODIR_OUT, + /** Duplex handling. */ + PDMAUDIODIR_DUPLEX, + /** End of valid values. */ + PDMAUDIODIR_END, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIODIR_32BIT_HACK = 0x7fffffff +} PDMAUDIODIR; + + +/** @name PDMAUDIOHOSTDEV_F_XXX + * @{ */ +/** No flags set. */ +#define PDMAUDIOHOSTDEV_F_NONE UINT32_C(0) +/** The default input (capture/recording) device (for the user). */ +#define PDMAUDIOHOSTDEV_F_DEFAULT_IN RT_BIT_32(0) +/** The default output (playback) device (for the user). */ +#define PDMAUDIOHOSTDEV_F_DEFAULT_OUT RT_BIT_32(1) +/** The device can be removed at any time and we have to deal with it. */ +#define PDMAUDIOHOSTDEV_F_HOTPLUG RT_BIT_32(2) +/** The device is known to be buggy and needs special treatment. */ +#define PDMAUDIOHOSTDEV_F_BUGGY RT_BIT_32(3) +/** Ignore the device, no matter what. */ +#define PDMAUDIOHOSTDEV_F_IGNORE RT_BIT_32(4) +/** The device is present but marked as locked by some other application. */ +#define PDMAUDIOHOSTDEV_F_LOCKED RT_BIT_32(5) +/** The device is present but not in an alive state (dead). */ +#define PDMAUDIOHOSTDEV_F_DEAD RT_BIT_32(6) +/** Set if the PDMAUDIOHOSTDEV::pszName is allocated. */ +#define PDMAUDIOHOSTDEV_F_NAME_ALLOC RT_BIT_32(29) +/** Set if the PDMAUDIOHOSTDEV::pszId is allocated. */ +#define PDMAUDIOHOSTDEV_F_ID_ALLOC RT_BIT_32(30) +/** Set if the extra backend specific data cannot be duplicated. */ +#define PDMAUDIOHOSTDEV_F_NO_DUP RT_BIT_32(31) +/** @} */ + +/** + * Audio device type. + */ +typedef enum PDMAUDIODEVICETYPE +{ + /** Invalid zero value as per usual (guards against using unintialized values). */ + PDMAUDIODEVICETYPE_INVALID = 0, + /** Unknown device type. This is the default. */ + PDMAUDIODEVICETYPE_UNKNOWN, + /** Dummy device; for backends which are not able to report + * actual device information (yet). */ + PDMAUDIODEVICETYPE_DUMMY, + /** The device is built into the host (non-removable). */ + PDMAUDIODEVICETYPE_BUILTIN, + /** The device is an (external) USB device. */ + PDMAUDIODEVICETYPE_USB, + /** End of valid values. */ + PDMAUDIODEVICETYPE_END, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIODEVICETYPE_32BIT_HACK = 0x7fffffff +} PDMAUDIODEVICETYPE; + +/** + * Host audio device info, part of enumeration result. + * + * @sa PDMAUDIOHOSTENUM, PDMIHOSTAUDIO::pfnGetDevices + */ +typedef struct PDMAUDIOHOSTDEV +{ + /** List entry (like PDMAUDIOHOSTENUM::LstDevices). */ + RTLISTNODE ListEntry; + /** Magic value (PDMAUDIOHOSTDEV_MAGIC). */ + uint32_t uMagic; + /** Size of this structure and whatever backend specific data that follows it. */ + uint32_t cbSelf; + /** The device type. */ + PDMAUDIODEVICETYPE enmType; + /** Usage of the device. */ + PDMAUDIODIR enmUsage; + /** Device flags, PDMAUDIOHOSTDEV_F_XXX. */ + uint32_t fFlags; + /** Maximum number of input audio channels the device supports. */ + uint8_t cMaxInputChannels; + /** Maximum number of output audio channels the device supports. */ + uint8_t cMaxOutputChannels; + uint8_t abAlignment[ARCH_BITS == 32 ? 2 + 8 : 2 + 8]; + /** Backend specific device identifier, can be NULL, used to select device. + * This can either point into some non-public part of this structure or to a + * RTStrAlloc allocation. PDMAUDIOHOSTDEV_F_ID_ALLOC is set in the latter + * case. + * @sa PDMIHOSTAUDIO::pfnSetDevice */ + char *pszId; + /** The friendly device name. */ + char *pszName; +} PDMAUDIOHOSTDEV; +AssertCompileSizeAlignment(PDMAUDIOHOSTDEV, 16); +/** Pointer to audio device info (enumeration result). */ +typedef PDMAUDIOHOSTDEV *PPDMAUDIOHOSTDEV; +/** Pointer to a const audio device info (enumeration result). */ +typedef PDMAUDIOHOSTDEV const *PCPDMAUDIOHOSTDEV; + +/** Magic value for PDMAUDIOHOSTDEV. */ +#define PDMAUDIOHOSTDEV_MAGIC PDM_VERSION_MAKE(0xa0d0, 3, 0) + + +/** + * A host audio device enumeration result. + * + * @sa PDMIHOSTAUDIO::pfnGetDevices + */ +typedef struct PDMAUDIOHOSTENUM +{ + /** Magic value (PDMAUDIOHOSTENUM_MAGIC). */ + uint32_t uMagic; + /** Number of audio devices in the list. */ + uint32_t cDevices; + /** List of audio devices (PDMAUDIOHOSTDEV). */ + RTLISTANCHOR LstDevices; +} PDMAUDIOHOSTENUM; +/** Pointer to an audio device enumeration result. */ +typedef PDMAUDIOHOSTENUM *PPDMAUDIOHOSTENUM; +/** Pointer to a const audio device enumeration result. */ +typedef PDMAUDIOHOSTENUM const *PCPDMAUDIOHOSTENUM; + +/** Magic for the host audio device enumeration. */ +#define PDMAUDIOHOSTENUM_MAGIC PDM_VERSION_MAKE(0xa0d1, 1, 0) + + +/** + * Audio configuration (static) of an audio host backend. + */ +typedef struct PDMAUDIOBACKENDCFG +{ + /** The backend's friendly name. */ + char szName[32]; + /** The size of the backend specific stream data (in bytes). */ + uint32_t cbStream; + /** PDMAUDIOBACKEND_F_XXX. */ + uint32_t fFlags; + /** Number of concurrent output (playback) streams supported on the host. + * UINT32_MAX for unlimited concurrent streams, 0 if no concurrent input streams are supported. */ + uint32_t cMaxStreamsOut; + /** Number of concurrent input (recording) streams supported on the host. + * UINT32_MAX for unlimited concurrent streams, 0 if no concurrent input streams are supported. */ + uint32_t cMaxStreamsIn; +} PDMAUDIOBACKENDCFG; +/** Pointer to a static host audio audio configuration. */ +typedef PDMAUDIOBACKENDCFG *PPDMAUDIOBACKENDCFG; + +/** @name PDMAUDIOBACKEND_F_XXX - PDMAUDIOBACKENDCFG::fFlags + * @{ */ +/** PDMIHOSTAUDIO::pfnStreamConfigHint should preferably be called on a + * worker thread rather than EMT as it may take a good while. */ +#define PDMAUDIOBACKEND_F_ASYNC_HINT RT_BIT_32(0) +/** PDMIHOSTAUDIO::pfnStreamDestroy and any preceeding + * PDMIHOSTAUDIO::pfnStreamControl/DISABLE should be preferably be called on a + * worker thread rather than EMT as it may take a good while. */ +#define PDMAUDIOBACKEND_F_ASYNC_STREAM_DESTROY RT_BIT_32(1) +/** @} */ + + +/** + * Audio path: input sources and playback destinations. + * + * Think of this as the name of the socket you plug the virtual audio stream + * jack into. + * + * @note Not quite sure what the purpose of this type is. It used to be two + * separate enums (PDMAUDIOPLAYBACKDST & PDMAUDIORECSRC) without overlapping + * values and most commonly used in a union (PDMAUDIODSTSRCUNION). The output + * values were designated "channel" (e.g. "Front channel"), whereas this was not + * done to the input ones. So, I'm (bird) a little confused what the actual + * meaning was. + */ +typedef enum PDMAUDIOPATH +{ + /** Customary invalid zero value. */ + PDMAUDIOPATH_INVALID = 0, + + /** Unknown path / Doesn't care. */ + PDMAUDIOPATH_UNKNOWN, + + /** First output value. */ + PDMAUDIOPATH_OUT_FIRST, + /** Output: Front. */ + PDMAUDIOPATH_OUT_FRONT = PDMAUDIOPATH_OUT_FIRST, + /** Output: Center / LFE (Subwoofer). */ + PDMAUDIOPATH_OUT_CENTER_LFE, + /** Output: Rear. */ + PDMAUDIOPATH_OUT_REAR, + /** Last output value (inclusive) */ + PDMAUDIOPATH_OUT_END = PDMAUDIOPATH_OUT_REAR, + + /** First input value. */ + PDMAUDIOPATH_IN_FIRST, + /** Input: Microphone. */ + PDMAUDIOPATH_IN_MIC = PDMAUDIOPATH_IN_FIRST, + /** Input: CD. */ + PDMAUDIOPATH_IN_CD, + /** Input: Video-In. */ + PDMAUDIOPATH_IN_VIDEO, + /** Input: AUX. */ + PDMAUDIOPATH_IN_AUX, + /** Input: Line-In. */ + PDMAUDIOPATH_IN_LINE, + /** Input: Phone-In. */ + PDMAUDIOPATH_IN_PHONE, + /** Last intput value (inclusive). */ + PDMAUDIOPATH_IN_LAST = PDMAUDIOPATH_IN_PHONE, + + /** End of valid values. */ + PDMAUDIOPATH_END, + /** Hack to blow the typ up to 32 bits. */ + PDMAUDIOPATH_32BIT_HACK = 0x7fffffff +} PDMAUDIOPATH; + + +/** + * Standard speaker channel IDs. + */ +typedef enum PDMAUDIOCHANNELID +{ + /** Invalid zero value as per usual (guards against using unintialized values). */ + PDMAUDIOCHANNELID_INVALID = 0, + + /** Unused channel - fill with zero when encoding, ignore when decoding. */ + PDMAUDIOCHANNELID_UNUSED_ZERO, + /** Unused channel - fill with silence when encoding, ignore when decoding. */ + PDMAUDIOCHANNELID_UNUSED_SILENCE, + + /** Unknown channel ID (unable to map to PDM terms). */ + PDMAUDIOCHANNELID_UNKNOWN, + + /** The first ID in the standard WAV-file assignment block. */ + PDMAUDIOCHANNELID_FIRST_STANDARD, + /** Front left channel (FR). */ + PDMAUDIOCHANNELID_FRONT_LEFT = PDMAUDIOCHANNELID_FIRST_STANDARD, + /** Front right channel (FR). */ + PDMAUDIOCHANNELID_FRONT_RIGHT, + /** Front center channel (FC). */ + PDMAUDIOCHANNELID_FRONT_CENTER, + /** Mono channel (alias for front center). */ + PDMAUDIOCHANNELID_MONO = PDMAUDIOCHANNELID_FRONT_CENTER, + /** Low frequency effects (subwoofer) channel. */ + PDMAUDIOCHANNELID_LFE, + /** Rear left channel (BL). */ + PDMAUDIOCHANNELID_REAR_LEFT, + /** Rear right channel (BR). */ + PDMAUDIOCHANNELID_REAR_RIGHT, + /** Front left of center channel (FLC). */ + PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER, + /** Front right of center channel (FLR). */ + PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER, + /** Rear center channel (BC). */ + PDMAUDIOCHANNELID_REAR_CENTER, + /** Side left channel (SL). */ + PDMAUDIOCHANNELID_SIDE_LEFT, + /** Side right channel (SR). */ + PDMAUDIOCHANNELID_SIDE_RIGHT, + /** Top center (TC). */ + PDMAUDIOCHANNELID_TOP_CENTER, + /** Front left height channel (TFL). */ + PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT, + /** Front center height channel (TFC). */ + PDMAUDIOCHANNELID_FRONT_CENTER_HEIGHT, + /** Front right height channel (TFR). */ + PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT, + /** Rear left height channel (TBL). */ + PDMAUDIOCHANNELID_REAR_LEFT_HEIGHT, + /** Rear center height channel (TBC). */ + PDMAUDIOCHANNELID_REAR_CENTER_HEIGHT, + /** Rear right height channel (TBR). */ + PDMAUDIOCHANNELID_REAR_RIGHT_HEIGHT, + /** The end of the standard WAV-file assignment block. */ + PDMAUDIOCHANNELID_END_STANDARD, + + /** End of valid values. */ + PDMAUDIOCHANNELID_END = PDMAUDIOCHANNELID_END_STANDARD, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIOCHANNELID_32BIT_HACK = 0x7fffffff +} PDMAUDIOCHANNELID; +AssertCompile(PDMAUDIOCHANNELID_FRONT_LEFT - PDMAUDIOCHANNELID_FIRST_STANDARD == 0); +AssertCompile(PDMAUDIOCHANNELID_LFE - PDMAUDIOCHANNELID_FIRST_STANDARD == 3); +AssertCompile(PDMAUDIOCHANNELID_REAR_CENTER - PDMAUDIOCHANNELID_FIRST_STANDARD == 8); +AssertCompile(PDMAUDIOCHANNELID_REAR_RIGHT_HEIGHT - PDMAUDIOCHANNELID_FIRST_STANDARD == 17); + + +/** + * Properties of audio streams for host/guest for in or out directions. + */ +typedef struct PDMAUDIOPCMPROPS +{ + /** The frame size. */ + uint8_t cbFrame; + /** Shift count used with PDMAUDIOPCMPROPS_F2B and PDMAUDIOPCMPROPS_B2F. + * Depends on number of stream channels and the stream format being used, calc + * value using PDMAUDIOPCMPROPS_MAKE_SHIFT. + * @sa PDMAUDIOSTREAMCFG_B2F, PDMAUDIOSTREAMCFG_F2B */ + uint8_t cShiftX; + /** Sample width (in bytes). */ + RT_GCC_EXTENSION + uint8_t cbSampleX : 4; + /** Number of audio channels. */ + RT_GCC_EXTENSION + uint8_t cChannelsX : 4; + /** Signed or unsigned sample. */ + bool fSigned : 1; + /** Whether the endianness is swapped or not. */ + bool fSwapEndian : 1; + /** Raw mixer frames, only applicable for signed 64-bit samples. + * The raw mixer samples are really just signed 32-bit samples stored as 64-bit + * integers without any change in the value. + * + * @todo Get rid of this, only VRDE needs it an it should use the common + * mixer code rather than cooking its own stuff. */ + bool fRaw : 1; + /** Sample frequency in Hertz (Hz). */ + uint32_t uHz; + /** PDMAUDIOCHANNELID mappings for each channel. + * This ASSUMES all channels uses the same sample size. */ + uint8_t aidChannels[PDMAUDIO_MAX_CHANNELS]; + /** Padding the structure up to 32 bytes. */ + uint32_t auPadding[3]; +} PDMAUDIOPCMPROPS; +AssertCompileSize(PDMAUDIOPCMPROPS, 32); +AssertCompileSizeAlignment(PDMAUDIOPCMPROPS, 8); +/** Pointer to audio stream properties. */ +typedef PDMAUDIOPCMPROPS *PPDMAUDIOPCMPROPS; +/** Pointer to const audio stream properties. */ +typedef PDMAUDIOPCMPROPS const *PCPDMAUDIOPCMPROPS; + +/** @name Macros for use with PDMAUDIOPCMPROPS + * @{ */ +/** Initializer for PDMAUDIOPCMPROPS. + * @note The default channel mapping here is very simple and doesn't always + * match that of PDMAudioPropsInit and PDMAudioPropsInitEx. */ +#define PDMAUDIOPCMPROPS_INITIALIZER(a_cbSample, a_fSigned, a_cChannels, a_uHz, a_fSwapEndian) \ + { \ + (uint8_t)((a_cbSample) * (a_cChannels)), PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(a_cbSample, a_cChannels), \ + (uint8_t)(a_cbSample), (uint8_t)(a_cChannels), a_fSigned, a_fSwapEndian, false /*fRaw*/, a_uHz, \ + /*aidChannels =*/ { \ + (a_cChannels) > 1 ? PDMAUDIOCHANNELID_FRONT_LEFT : PDMAUDIOCHANNELID_MONO, \ + (a_cChannels) >= 2 ? PDMAUDIOCHANNELID_FRONT_RIGHT : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 3 ? PDMAUDIOCHANNELID_FRONT_CENTER : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 4 ? PDMAUDIOCHANNELID_LFE : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 5 ? PDMAUDIOCHANNELID_REAR_LEFT : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 6 ? PDMAUDIOCHANNELID_REAR_RIGHT : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 7 ? PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 8 ? PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 9 ? PDMAUDIOCHANNELID_REAR_CENTER : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 10 ? PDMAUDIOCHANNELID_SIDE_LEFT : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 11 ? PDMAUDIOCHANNELID_SIDE_RIGHT : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 12 ? PDMAUDIOCHANNELID_UNKNOWN : PDMAUDIOCHANNELID_INVALID, \ + }, \ + /* auPadding = */ { 0, 0, 0 } \ + } + +/** Calculates the cShift value of given sample bits and audio channels. + * @note Does only support mono/stereo channels for now, for non-stereo/mono we + * returns a special value which the two conversion functions detect + * and make them fall back on cbSample * cChannels. */ +#define PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels) \ + ( RT_IS_POWER_OF_TWO((unsigned)((cChannels) * (cbSample))) \ + ? (uint8_t)(ASMBitFirstSetU32((unsigned)((cChannels) * (cbSample))) - 1) : (uint8_t)UINT8_MAX ) +/** Calculates the cShift value of a PDMAUDIOPCMPROPS structure. */ +#define PDMAUDIOPCMPROPS_MAKE_SHIFT(pProps) \ + PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS((pProps)->cbSampleX, (pProps)->cChannelsX) +/** Converts (audio) frames to bytes. + * @note Requires properly initialized properties, i.e. cbFrames correctly calculated + * and cShift set using PDMAUDIOPCMPROPS_MAKE_SHIFT. */ +#define PDMAUDIOPCMPROPS_F2B(pProps, cFrames) \ + ( (pProps)->cShiftX != UINT8_MAX ? (cFrames) << (pProps)->cShiftX : (cFrames) * (pProps)->cbFrame ) +/** Converts bytes to (audio) frames. + * @note Requires properly initialized properties, i.e. cbFrames correctly calculated + * and cShift set using PDMAUDIOPCMPROPS_MAKE_SHIFT. */ +#define PDMAUDIOPCMPROPS_B2F(pProps, cb) \ + ( (pProps)->cShiftX != UINT8_MAX ? (cb) >> (pProps)->cShiftX : (cb) / (pProps)->cbFrame ) +/** @} */ + +/** + * An audio stream configuration. + */ +typedef struct PDMAUDIOSTREAMCFG +{ + /** The stream's PCM properties. */ + PDMAUDIOPCMPROPS Props; + /** Direction of the stream. */ + PDMAUDIODIR enmDir; + /** Destination / source path. */ + PDMAUDIOPATH enmPath; + /** Device emulation-specific data needed for the audio connector. */ + struct + { + /** Scheduling hint set by the device emulation about when this stream is being served on average (in ms). + * Can be 0 if not hint given or some other mechanism (e.g. callbacks) is being used. */ + uint32_t cMsSchedulingHint; + } Device; + /** + * Backend-specific data for the stream. + * On input (requested configuration) those values are set by the audio connector to let the backend know what we expect. + * On output (acquired configuration) those values reflect the values set and used by the backend. + * Set by the backend on return. Not all backends support all values / features. + */ + struct + { + /** Period size of the stream (in audio frames). + * This value reflects the number of audio frames in between each hardware interrupt on the + * backend (host) side. 0 if not set / available by the backend. */ + uint32_t cFramesPeriod; + /** (Ring) buffer size (in audio frames). Often is a multiple of cFramesPeriod. + * 0 if not set / available by the backend. */ + uint32_t cFramesBufferSize; + /** Pre-buffering size (in audio frames). Frames needed in buffer before the stream becomes active (pre buffering). + * The bigger this value is, the more latency for the stream will occur. + * 0 if not set / available by the backend. UINT32_MAX if not defined (yet). */ + uint32_t cFramesPreBuffering; + } Backend; + /** Friendly name of the stream. */ + char szName[64]; +} PDMAUDIOSTREAMCFG; +AssertCompileSizeAlignment(PDMAUDIOSTREAMCFG, 8); +/** Pointer to audio stream configuration keeper. */ +typedef PDMAUDIOSTREAMCFG *PPDMAUDIOSTREAMCFG; +/** Pointer to a const audio stream configuration keeper. */ +typedef PDMAUDIOSTREAMCFG const *PCPDMAUDIOSTREAMCFG; + +/** Converts (audio) frames to bytes. */ +#define PDMAUDIOSTREAMCFG_F2B(pCfg, frames) PDMAUDIOPCMPROPS_F2B(&(pCfg)->Props, (frames)) +/** Converts bytes to (audio) frames. */ +#define PDMAUDIOSTREAMCFG_B2F(pCfg, cb) PDMAUDIOPCMPROPS_B2F(&(pCfg)->Props, (cb)) + +/** + * Audio stream commands. + * + * Used in the audio connector as well as in the actual host backends. + */ +typedef enum PDMAUDIOSTREAMCMD +{ + /** Invalid zero value as per usual (guards against using unintialized values). */ + PDMAUDIOSTREAMCMD_INVALID = 0, + /** Enables the stream. */ + PDMAUDIOSTREAMCMD_ENABLE, + /** Pauses the stream. + * This is currently only issued when the VM is suspended (paused). + * @remarks This is issued by DrvAudio, never by the mixer or devices. */ + PDMAUDIOSTREAMCMD_PAUSE, + /** Resumes the stream. + * This is currently only issued when the VM is resumed. + * @remarks This is issued by DrvAudio, never by the mixer or devices. */ + PDMAUDIOSTREAMCMD_RESUME, + /** Drain the stream, that is, play what's in the buffers and then stop. + * + * There will be no more samples written after this command is issued. + * PDMIAUDIOCONNECTOR::pfnStreamIterate will drive progress for DrvAudio and + * calls to PDMIHOSTAUDIO::pfnStreamPlay with a zero sized buffer will provide + * the backend with a way to drive it forwards. These calls will come at a + * frequency set by the device and be on an asynchronous I/O thread. + * + * A DISABLE command maybe submitted if the device/mixer wants to re-enable the + * stream while it's still draining or if it gets impatient and thinks the + * draining has been going on too long, in which case the stream should stop + * immediately. + * + * @note This should not wait for the stream to finish draining, just change + * the state. (The caller could be an EMT and it must not block for + * hundreds of milliseconds of buffer to finish draining.) + * + * @note Does not apply to input streams. Backends should refuse such requests. */ + PDMAUDIOSTREAMCMD_DRAIN, + /** Stops the stream immediately w/o any draining. */ + PDMAUDIOSTREAMCMD_DISABLE, + /** End of valid values. */ + PDMAUDIOSTREAMCMD_END, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIOSTREAMCMD_32BIT_HACK = 0x7fffffff +} PDMAUDIOSTREAMCMD; + +/** + * Backend status. + */ +typedef enum PDMAUDIOBACKENDSTS +{ + /** Unknown/invalid status. */ + PDMAUDIOBACKENDSTS_UNKNOWN = 0, + /** No backend attached. */ + PDMAUDIOBACKENDSTS_NOT_ATTACHED, + /** The backend is in its initialization phase. + * Not all backends support this status. */ + PDMAUDIOBACKENDSTS_INITIALIZING, + /** The backend has stopped its operation. */ + PDMAUDIOBACKENDSTS_STOPPED, + /** The backend is up and running. */ + PDMAUDIOBACKENDSTS_RUNNING, + /** The backend ran into an error and is unable to recover. + * A manual re-initialization might help. */ + PDMAUDIOBACKENDSTS_ERROR, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIOBACKENDSTS_32BIT_HACK = 0x7fffffff +} PDMAUDIOBACKENDSTS; + +/** + * PDM audio stream state. + * + * This is all the mixer/device needs. The PDMAUDIOSTREAM_STS_XXX stuff will + * become DrvAudio internal state once the backend stuff is destilled out of it. + * + * @note The value order is significant, don't change it willy-nilly. + */ +typedef enum PDMAUDIOSTREAMSTATE +{ + /** Invalid state value. */ + PDMAUDIOSTREAMSTATE_INVALID = 0, + /** The stream is not operative and cannot be enabled. */ + PDMAUDIOSTREAMSTATE_NOT_WORKING, + /** The stream needs to be re-initialized by the device/mixer + * (i.e. call PDMIAUDIOCONNECTOR::pfnStreamReInit). */ + PDMAUDIOSTREAMSTATE_NEED_REINIT, + /** The stream is inactive (not enabled). */ + PDMAUDIOSTREAMSTATE_INACTIVE, + /** The stream is enabled but nothing to read/write. + * @todo not sure if we need this variant... */ + PDMAUDIOSTREAMSTATE_ENABLED, + /** The stream is enabled and captured samples can be read. */ + PDMAUDIOSTREAMSTATE_ENABLED_READABLE, + /** The stream is enabled and samples can be written for playback. */ + PDMAUDIOSTREAMSTATE_ENABLED_WRITABLE, + /** End of valid states. */ + PDMAUDIOSTREAMSTATE_END, + /** Make sure the type is 32-bit wide. */ + PDMAUDIOSTREAMSTATE_32BIT_HACK = 0x7fffffff +} PDMAUDIOSTREAMSTATE; + +/** @name PDMAUDIOSTREAM_CREATE_F_XXX + * @{ */ +/** Does not need any mixing buffers, the device takes care of all conversion. + * @note this is now default and assumed always set. */ +#define PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF RT_BIT_32(0) +/** @} */ + +/** @name PDMAUDIOSTREAM_WARN_FLAGS_XXX + * @{ */ +/** No stream warning flags set. */ +#define PDMAUDIOSTREAM_WARN_FLAGS_NONE 0 +/** Warned about a disabled stream. */ +#define PDMAUDIOSTREAM_WARN_FLAGS_DISABLED RT_BIT(0) +/** @} */ + +/** + * An input or output audio stream. + */ +typedef struct PDMAUDIOSTREAM +{ + /** Critical section protecting the stream. + * + * When not otherwise stated, DrvAudio will enter this before calling the + * backend. The backend and device/mixer can normally safely enter it prior to + * a DrvAudio call, however not to pfnStreamDestroy, pfnStreamRelease or + * anything that may access the stream list. + * + * @note Lock ordering: + * - After DRVAUDIO::CritSectGlobals. + * - Before DRVAUDIO::CritSectHotPlug. */ + RTCRITSECT CritSect; + /** Stream configuration. */ + PDMAUDIOSTREAMCFG Cfg; + /** Magic value (PDMAUDIOSTREAM_MAGIC). */ + uint32_t uMagic; + /** Size (in bytes) of the backend-specific stream data. */ + uint32_t cbBackend; + /** Warnings shown already in the release log. + * See PDMAUDIOSTREAM_WARN_FLAGS_XXX. */ + uint32_t fWarningsShown; +} PDMAUDIOSTREAM; +/** Pointer to an audio stream. */ +typedef struct PDMAUDIOSTREAM *PPDMAUDIOSTREAM; +/** Pointer to a const audio stream. */ +typedef struct PDMAUDIOSTREAM const *PCPDMAUDIOSTREAM; + +/** Magic value for PDMAUDIOSTREAM. */ +#define PDMAUDIOSTREAM_MAGIC PDM_VERSION_MAKE(0xa0d3, 5, 0) + + + +/** Pointer to a audio connector interface. */ +typedef struct PDMIAUDIOCONNECTOR *PPDMIAUDIOCONNECTOR; + +/** + * Audio connector interface (up). + */ +typedef struct PDMIAUDIOCONNECTOR +{ + /** + * Enables or disables the given audio direction for this driver. + * + * When disabled, assiociated output streams consume written audio without passing them further down to the backends. + * Associated input streams then return silence when read from those. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmDir Audio direction to enable or disable driver for. + * @param fEnable Whether to enable or disable the specified audio direction. + * + * @note Be very careful when using this function, as this could + * violate / run against the (global) VM settings. See @bugref{9882}. + */ + DECLR3CALLBACKMEMBER(int, pfnEnable, (PPDMIAUDIOCONNECTOR pInterface, PDMAUDIODIR enmDir, bool fEnable)); + + /** + * Returns whether the given audio direction for this driver is enabled or not. + * + * @returns True if audio is enabled for the given direction, false if not. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmDir Audio direction to retrieve enabled status for. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsEnabled, (PPDMIAUDIOCONNECTOR pInterface, PDMAUDIODIR enmDir)); + + /** + * Retrieves the current configuration of the host audio backend. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pCfg Where to store the host audio backend configuration data. + */ + DECLR3CALLBACKMEMBER(int, pfnGetConfig, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg)); + + /** + * Retrieves the current status of the host audio backend. + * + * @returns Status of the host audio backend. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmDir Audio direction to check host audio backend for. Specify PDMAUDIODIR_DUPLEX for the overall + * backend status. + */ + DECLR3CALLBACKMEMBER(PDMAUDIOBACKENDSTS, pfnGetStatus, (PPDMIAUDIOCONNECTOR pInterface, PDMAUDIODIR enmDir)); + + /** + * Gives the audio drivers a hint about a typical configuration. + * + * This is a little hack for windows (and maybe other hosts) where stream + * creation can take a relatively long time, making it very unsuitable for EMT. + * The audio backend can use this hint to cache pre-configured stream setups, + * so that when the guest actually wants to play something EMT won't be blocked + * configuring host audio. + * + * @param pInterface Pointer to this interface. + * @param pCfg The typical configuration. Can be modified by the + * drivers in unspecified ways. + */ + DECLR3CALLBACKMEMBER(void, pfnStreamConfigHint, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAMCFG pCfg)); + + /** + * Creates an audio stream. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param fFlags PDMAUDIOSTREAM_CREATE_F_XXX. + * @param pCfgReq The requested stream configuration. The actual stream + * configuration can be found in pStream->Cfg on success. + * @param ppStream Pointer where to return the created audio stream on + * success. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamCreate, (PPDMIAUDIOCONNECTOR pInterface, uint32_t fFlags, PCPDMAUDIOSTREAMCFG pCfgReq, + PPDMAUDIOSTREAM *ppStream)); + + + /** + * Destroys an audio stream. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + * @param fImmediate Whether to immdiately stop and destroy a draining + * stream (@c true), or to allow it to complete + * draining first (@c false) if that's feasable. + * The latter depends on the draining stage and what + * the backend is capable of. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamDestroy, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, bool fImmediate)); + + /** + * Re-initializes the stream in response to PDMAUDIOSTREAM_STS_NEED_REINIT. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream The audio stream needing re-initialization. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamReInit, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Adds a reference to the specified audio stream. + * + * @returns New reference count. UINT32_MAX on error. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream adding the reference to. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamRetain, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Releases a reference from the specified stream. + * + * @returns New reference count. UINT32_MAX on error. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream releasing a reference from. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamRelease, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Controls a specific audio stream. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + * @param enmStreamCmd The stream command to issue. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamControl, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, + PDMAUDIOSTREAMCMD enmStreamCmd)); + + /** + * Processes stream data. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamIterate, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Returns the state of a specific audio stream (destilled status). + * + * @returns PDMAUDIOSTREAMSTATE value. + * @retval PDMAUDIOSTREAMSTATE_INVALID if the input isn't valid (w/ assertion). + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(PDMAUDIOSTREAMSTATE, pfnStreamGetState, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Returns the number of bytes that can be written to an audio output stream. + * + * @returns Number of bytes writable data. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetWritable, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Plays (writes to) an audio output stream. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream to read from. + * @param pvBuf Audio data to be written. + * @param cbBuf Number of bytes to be written. + * @param pcbWritten Bytes of audio data written. Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamPlay, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, + const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)); + + /** + * Returns the number of bytes that can be read from an input stream. + * + * @returns Number of bytes of readable data. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetReadable, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Captures (reads) samples from an audio input stream. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream to write to. + * @param pvBuf Where to store the read data. + * @param cbBuf Number of bytes to read. + * @param pcbRead Bytes of audio data read. Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamCapture, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, + void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)); +} PDMIAUDIOCONNECTOR; + +/** PDMIAUDIOCONNECTOR interface ID. */ +#define PDMIAUDIOCONNECTOR_IID "2900fe2a-6aeb-4953-ac12-f8965612f446" + + +/** + * Host audio backend specific stream data. + * + * The backend will put this as the first member of it's own data structure. + */ +typedef struct PDMAUDIOBACKENDSTREAM +{ + /** Magic value (PDMAUDIOBACKENDSTREAM_MAGIC). */ + uint32_t uMagic; + /** Explicit zero padding - do not touch! */ + uint32_t uReserved; + /** Pointer to the stream this backend data is associated with. */ + PPDMAUDIOSTREAM pStream; + /** Reserved for future use (zeroed) - do not touch. */ + void *apvReserved[2]; +} PDMAUDIOBACKENDSTREAM; +/** Pointer to host audio specific stream data! */ +typedef PDMAUDIOBACKENDSTREAM *PPDMAUDIOBACKENDSTREAM; + +/** Magic value for PDMAUDIOBACKENDSTREAM. */ +#define PDMAUDIOBACKENDSTREAM_MAGIC PDM_VERSION_MAKE(0xa0d4, 1, 0) + +/** + * Host audio (backend) stream state returned by PDMIHOSTAUDIO::pfnStreamGetState. + */ +typedef enum PDMHOSTAUDIOSTREAMSTATE +{ + /** Invalid zero value, as per usual. */ + PDMHOSTAUDIOSTREAMSTATE_INVALID = 0, + /** The stream is being initialized. + * This should also be used when switching to a new device and the stream + * stops to work with the old device while the new one being configured. */ + PDMHOSTAUDIOSTREAMSTATE_INITIALIZING, + /** The stream does not work (async init failed, audio subsystem gone + * fishing, or similar). */ + PDMHOSTAUDIOSTREAMSTATE_NOT_WORKING, + /** Backend is working okay. */ + PDMHOSTAUDIOSTREAMSTATE_OKAY, + /** Backend is working okay, but currently draining the stream. */ + PDMHOSTAUDIOSTREAMSTATE_DRAINING, + /** Backend is working but doesn't want any commands or data reads/writes. */ + PDMHOSTAUDIOSTREAMSTATE_INACTIVE, + /** End of valid values. */ + PDMHOSTAUDIOSTREAMSTATE_END, + /** Blow the type up to 32 bits. */ + PDMHOSTAUDIOSTREAMSTATE_32BIT_HACK = 0x7fffffff +} PDMHOSTAUDIOSTREAMSTATE; + + +/** Pointer to a host audio interface. */ +typedef struct PDMIHOSTAUDIO *PPDMIHOSTAUDIO; + +/** + * PDM host audio interface. + */ +typedef struct PDMIHOSTAUDIO +{ + /** + * Returns the host backend's configuration (backend). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pBackendCfg Where to store the backend audio configuration to. + */ + DECLR3CALLBACKMEMBER(int, pfnGetConfig, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)); + + /** + * Returns (enumerates) host audio device information (optional). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pDeviceEnum Where to return the enumerated audio devices. + */ + DECLR3CALLBACKMEMBER(int, pfnGetDevices, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHOSTENUM pDeviceEnum)); + + /** + * Changes the output or input device. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param enmDir The direction to set the device for: PDMAUDIODIR_IN, + * PDMAUDIODIR_OUT or PDMAUDIODIR_DUPLEX (both the + * previous). + * @param pszId The PDMAUDIOHOSTDEV::pszId value of the device to + * use, or NULL / empty string for the default device. + */ + DECLR3CALLBACKMEMBER(int, pfnSetDevice, (PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir, const char *pszId)); + + /** + * Returns the current status from the audio backend (optional). + * + * @returns PDMAUDIOBACKENDSTS enum. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmDir Audio direction to get status for. Pass PDMAUDIODIR_DUPLEX for overall status. + */ + DECLR3CALLBACKMEMBER(PDMAUDIOBACKENDSTS, pfnGetStatus, (PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)); + + /** + * Callback for genric on-worker-thread requests initiated by the backend itself. + * + * This is the counterpart to PDMIHOSTAUDIOPORT::pfnDoOnWorkerThread that will + * be invoked on a worker thread when the backend requests it - optional. + * + * This does not return a value, so the backend must keep track of + * failure/success on its own. + * + * This method is optional. A non-NULL will, together with pfnStreamInitAsync + * and PDMAUDIOBACKEND_F_ASYNC_HINT, force DrvAudio to create the thread pool. + * + * @param pInterface Pointer to this interface. + * @param pStream Optionally a backend stream if specified in the + * PDMIHOSTAUDIOPORT::pfnDoOnWorkerThread() call. + * @param uUser User specific value as specified in the + * PDMIHOSTAUDIOPORT::pfnDoOnWorkerThread() call. + * @param pvUser User specific pointer as specified in the + * PDMIHOSTAUDIOPORT::pfnDoOnWorkerThread() call. + */ + DECLR3CALLBACKMEMBER(void, pfnDoOnWorkerThread,(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, + uintptr_t uUser, void *pvUser)); + + /** + * Gives the audio backend a hint about a typical configuration (optional). + * + * This is a little hack for windows (and maybe other hosts) where stream + * creation can take a relatively long time, making it very unsuitable for EMT. + * The audio backend can use this hint to cache pre-configured stream setups, + * so that when the guest actually wants to play something EMT won't be blocked + * configuring host audio. + * + * The backend can return PDMAUDIOBACKEND_F_ASYNC_HINT in + * PDMIHOSTAUDIO::pfnGetConfig to avoid having EMT making this call and thereby + * speeding up VM construction. + * + * @param pInterface Pointer to this interface. + * @param pCfg The typical configuration. (Feel free to change it + * to the actual stream config that would be used, + * however caller will probably ignore this.) + */ + DECLR3CALLBACKMEMBER(void, pfnStreamConfigHint, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAMCFG pCfg)); + + /** + * Creates an audio stream using the requested stream configuration. + * + * If a backend is not able to create this configuration, it will return its + * best match in the acquired configuration structure on success. + * + * @returns VBox status code. + * @retval VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED if + * PDMIHOSTAUDIO::pfnStreamInitAsync should be called. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream. + * @param pCfgReq The requested stream configuration. + * @param pCfgAcq The acquired stream configuration - output. This is + * the same as @a *pCfgReq when called, the + * implementation will adjust it to make the actual + * stream configuration as needed. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamCreate, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, + PCPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)); + + /** + * Asynchronous stream initialization step, optional. + * + * This is called on a worker thread iff the PDMIHOSTAUDIO::pfnStreamCreate + * method returns VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to audio stream to continue + * initialization of. + * @param fDestroyed Set to @c true if the stream has been destroyed + * before the worker thread got to making this + * call. The backend should just ready the stream + * for destruction in that case. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamInitAsync, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, bool fDestroyed)); + + /** + * Destroys an audio stream. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface containing the called function. + * @param pStream Pointer to audio stream. + * @param fImmediate Whether to immdiately stop and destroy a draining + * stream (@c true), or to allow it to complete + * draining first (@c false) if that's feasable. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamDestroy, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, bool fImmediate)); + + /** + * Called from PDMIHOSTAUDIOPORT::pfnNotifyDeviceChanged so the backend can start + * the device change for a stream. + * + * This is mainly to avoid the need for a list of streams in the backend. + * + * @param pInterface Pointer to this interface. + * @param pStream Pointer to audio stream (locked). + * @param pvUser Backend specific parameter from the call to + * PDMIHOSTAUDIOPORT::pfnNotifyDeviceChanged. + */ + DECLR3CALLBACKMEMBER(void, pfnStreamNotifyDeviceChanged,(PPDMIHOSTAUDIO pInterface, + PPDMAUDIOBACKENDSTREAM pStream, void *pvUser)); + + /** + * Enables (starts) the stream. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream to enable. + * @sa PDMAUDIOSTREAMCMD_ENABLE + */ + DECLR3CALLBACKMEMBER(int, pfnStreamEnable, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Disables (stops) the stream immediately. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream to disable. + * @sa PDMAUDIOSTREAMCMD_DISABLE + */ + DECLR3CALLBACKMEMBER(int, pfnStreamDisable, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Pauses the stream - called when the VM is suspended. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream to pause. + * @sa PDMAUDIOSTREAMCMD_PAUSE + */ + DECLR3CALLBACKMEMBER(int, pfnStreamPause, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Resumes a paused stream - called when the VM is resumed. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream to resume. + * @sa PDMAUDIOSTREAMCMD_RESUME + */ + DECLR3CALLBACKMEMBER(int, pfnStreamResume, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Drain the stream, that is, play what's in the buffers and then stop. + * + * There will be no more samples written after this command is issued. + * PDMIHOSTAUDIO::pfnStreamPlay with a zero sized buffer will provide the + * backend with a way to drive it forwards. These calls will come at a + * frequency set by the device and be on an asynchronous I/O thread. + * + * The PDMIHOSTAUDIO::pfnStreamDisable method maybe called if the device/mixer + * wants to re-enable the stream while it's still draining or if it gets + * impatient and thinks the draining has been going on too long, in which case + * the stream should stop immediately. + * + * @note This should not wait for the stream to finish draining, just change + * the state. (The caller could be an EMT and it must not block for + * hundreds of milliseconds of buffer to finish draining.) + * + * @note Does not apply to input streams. Backends should refuse such + * requests. + * + * @returns VBox status code. + * @retval VERR_WRONG_ORDER if not output stream. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream to drain. + * @sa PDMAUDIOSTREAMCMD_DRAIN + */ + DECLR3CALLBACKMEMBER(int, pfnStreamDrain, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Returns the current state of the given backend stream. + * + * @returns PDMHOSTAUDIOSTREAMSTATE value. + * @retval PDMHOSTAUDIOSTREAMSTATE_INVALID if invalid stream. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(PDMHOSTAUDIOSTREAMSTATE, pfnStreamGetState, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Returns the number of buffered bytes that hasn't been played yet (optional). + * + * Is not valid on an input stream, implementions shall assert and return zero. + * + * @returns Number of pending bytes. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream. + * + * @todo This is no longer not used by DrvAudio and can probably be removed. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetPending, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Returns the amount which is writable to the audio (output) stream. + * + * @returns Number of writable bytes. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetWritable, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Plays (writes to) an audio (output) stream. + * + * This is always called with data in the buffer, except after + * PDMAUDIOSTREAMCMD_DRAIN is issued when it's called every so often to assist + * the backend with moving the draining operation forward (kind of like + * PDMIAUDIOCONNECTOR::pfnStreamIterate). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + * @param pvBuf Pointer to audio data buffer to play. This will be NULL + * when called to assist draining the stream. + * @param cbBuf The number of bytes of audio data to play. This will be + * zero when called to assist draining the stream. + * @param pcbWritten Where to return the actual number of bytes played. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamPlay, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, + const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)); + + /** + * Returns the amount which is readable from the audio (input) stream. + * + * @returns For non-raw layout streams: Number of readable bytes. + * for raw layout streams : Number of readable audio frames. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetReadable, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Captures (reads from) an audio (input) stream. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + * @param pvBuf Buffer where to store read audio data. + * @param cbBuf Size of the audio data buffer in bytes. + * @param pcbRead Where to return the number of bytes actually captured. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamCapture, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, + void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)); +} PDMIHOSTAUDIO; + +/** PDMIHOSTAUDIO interface ID. */ +#define PDMIHOSTAUDIO_IID "c0875b91-a4f9-48be-8595-31d27048432d" + + +/** Pointer to a audio notify from host interface. */ +typedef struct PDMIHOSTAUDIOPORT *PPDMIHOSTAUDIOPORT; + +/** + * PDM host audio port interface, upwards sibling of PDMIHOSTAUDIO. + */ +typedef struct PDMIHOSTAUDIOPORT +{ + /** + * Ask DrvAudio to call PDMIHOSTAUDIO::pfnDoOnWorkerThread on a worker thread. + * + * Generic method for doing asynchronous work using the DrvAudio thread pool. + * + * This function will not wait for PDMIHOSTAUDIO::pfnDoOnWorkerThread to + * complete, but returns immediately after submitting the request to the thread + * pool. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Optional backend stream structure to pass along. The + * reference count will be increased till the call + * completes to make sure the stream stays valid. + * @param uUser User specific value. + * @param pvUser User specific pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnDoOnWorkerThread,(PPDMIHOSTAUDIOPORT pInterface, PPDMAUDIOBACKENDSTREAM pStream, + uintptr_t uUser, void *pvUser)); + + /** + * The device for the given direction changed. + * + * The driver above backend (DrvAudio) will call the backend back + * (PDMIHOSTAUDIO::pfnStreamNotifyDeviceChanged) for all open streams in the + * given direction. (This ASSUMES the backend uses one output device and one + * input devices for all streams.) + * + * @param pInterface Pointer to this interface. + * @param enmDir The audio direction. + * @param pvUser Backend specific parameter for + * PDMIHOSTAUDIO::pfnStreamNotifyDeviceChanged. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyDeviceChanged,(PPDMIHOSTAUDIOPORT pInterface, PDMAUDIODIR enmDir, void *pvUser)); + + /** + * Notification that the stream is about to change device in a bit. + * + * This will assume PDMAUDIOSTREAM_STS_PREPARING_SWITCH will be set when + * PDMIHOSTAUDIO::pfnStreamGetStatus is next called and change the stream state + * accordingly. + * + * @param pInterface Pointer to this interface. + * @param pStream The stream that changed device (backend variant). + */ + DECLR3CALLBACKMEMBER(void, pfnStreamNotifyPreparingDeviceSwitch,(PPDMIHOSTAUDIOPORT pInterface, + PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * The stream has changed its device and left the + * PDMAUDIOSTREAM_STS_PREPARING_SWITCH state (if it entered it at all). + * + * @param pInterface Pointer to this interface. + * @param pStream The stream that changed device (backend variant). + * @param fReInit Set if a re-init is required, clear if not. + */ + DECLR3CALLBACKMEMBER(void, pfnStreamNotifyDeviceChanged,(PPDMIHOSTAUDIOPORT pInterface, + PPDMAUDIOBACKENDSTREAM pStream, bool fReInit)); + + /** + * One or more audio devices have changed in some way. + * + * The upstream driver/device should re-evaluate the devices they're using. + * + * @todo r=bird: The upstream driver/device does not know which host audio + * devices they are using. This is mainly for triggering enumeration and + * logging of the audio devices. + * + * @param pInterface Pointer to this interface. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyDevicesChanged,(PPDMIHOSTAUDIOPORT pInterface)); +} PDMIHOSTAUDIOPORT; + +/** PDMIHOSTAUDIOPORT interface ID. */ +#define PDMIHOSTAUDIOPORT_IID "92ea5169-8271-402d-99a7-9de26a52acaf" + + +/** + * Audio mixer controls. + * + * @note This isn't part of any official PDM interface as such, it's more of a + * common thing that all the devices seem to need. + */ +typedef enum PDMAUDIOMIXERCTL +{ + /** Invalid zero value as per usual (guards against using unintialized values). */ + PDMAUDIOMIXERCTL_INVALID = 0, + /** Unknown mixer control. */ + PDMAUDIOMIXERCTL_UNKNOWN, + /** Master volume. */ + PDMAUDIOMIXERCTL_VOLUME_MASTER, + /** Front. */ + PDMAUDIOMIXERCTL_FRONT, + /** Center / LFE (Subwoofer). */ + PDMAUDIOMIXERCTL_CENTER_LFE, + /** Rear. */ + PDMAUDIOMIXERCTL_REAR, + /** Line-In. */ + PDMAUDIOMIXERCTL_LINE_IN, + /** Microphone-In. */ + PDMAUDIOMIXERCTL_MIC_IN, + /** End of valid values. */ + PDMAUDIOMIXERCTL_END, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIOMIXERCTL_32BIT_HACK = 0x7fffffff +} PDMAUDIOMIXERCTL; + +/** + * Audio volume parameters. + * + * @note This isn't part of any official PDM interface any more (it used to be + * used to PDMIAUDIOCONNECTOR). It's currently only used by the mixer API. + */ +typedef struct PDMAUDIOVOLUME +{ + /** Set to @c true if this stream is muted, @c false if not. */ + bool fMuted; + /** The volume for each channel. + * The values zero is the most silent one (although not quite muted), and 255 + * the loudest. */ + uint8_t auChannels[PDMAUDIO_MAX_CHANNELS]; +} PDMAUDIOVOLUME; +/** Pointer to audio volume settings. */ +typedef PDMAUDIOVOLUME *PPDMAUDIOVOLUME; +/** Pointer to const audio volume settings. */ +typedef PDMAUDIOVOLUME const *PCPDMAUDIOVOLUME; + +/** Defines the minimum volume allowed. */ +#define PDMAUDIO_VOLUME_MIN (0) +/** Defines the maximum volume allowed. */ +#define PDMAUDIO_VOLUME_MAX (255) +/** Initializator for max volume on all channels. */ +#define PDMAUDIOVOLUME_INITIALIZER_MAX \ + { /* .fMuted = */ false, \ + /* .auChannels = */ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } } + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmaudioifs_h */ + diff --git a/include/VBox/vmm/pdmaudioinline.h b/include/VBox/vmm/pdmaudioinline.h new file mode 100644 index 00000000..5d3175c0 --- /dev/null +++ b/include/VBox/vmm/pdmaudioinline.h @@ -0,0 +1,1507 @@ +/* $Id: pdmaudioinline.h $ */ +/** @file + * PDM - Audio Helpers, Inlined Code. (DEV,++) + * + * This is all inlined because it's too tedious to create a couple libraries to + * contain it all (same bad excuse as for intnetinline.h & pdmnetinline.h). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmaudioinline_h +#define VBOX_INCLUDED_vmm_pdmaudioinline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/err.h> +#include <VBox/log.h> +#include <VBox/vmm/pdmaudioifs.h> + +#include <iprt/asm.h> +#include <iprt/asm-math.h> +#include <iprt/assert.h> +#include <iprt/mem.h> +#include <iprt/string.h> + + +/** @defgroup grp_pdm_audio_inline The PDM Audio Helper APIs + * @ingroup grp_pdm + * @{ + */ + + +/** + * Gets the name of an audio direction enum value. + * + * @returns Pointer to read-only name string on success, "bad" if passed an + * invalid enum value. + * @param enmDir The audio direction value to name. + */ +DECLINLINE(const char *) PDMAudioDirGetName(PDMAUDIODIR enmDir) +{ + switch (enmDir) + { + case PDMAUDIODIR_INVALID: return "invalid"; + case PDMAUDIODIR_UNKNOWN: return "unknown"; + case PDMAUDIODIR_IN: return "input"; + case PDMAUDIODIR_OUT: return "output"; + case PDMAUDIODIR_DUPLEX: return "duplex"; + + /* no default */ + case PDMAUDIODIR_END: + case PDMAUDIODIR_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Invalid audio direction %d\n", enmDir), "bad"); +} + +/** + * Gets the name of an audio mixer control enum value. + * + * @returns Pointer to read-only name, "bad" if invalid input. + * @param enmMixerCtl The audio mixer control value. + */ +DECLINLINE(const char *) PDMAudioMixerCtlGetName(PDMAUDIOMIXERCTL enmMixerCtl) +{ + switch (enmMixerCtl) + { + case PDMAUDIOMIXERCTL_INVALID: return "Invalid"; + case PDMAUDIOMIXERCTL_UNKNOWN: return "Unknown"; + case PDMAUDIOMIXERCTL_VOLUME_MASTER: return "Master Volume"; + case PDMAUDIOMIXERCTL_FRONT: return "Front"; + case PDMAUDIOMIXERCTL_CENTER_LFE: return "Center / LFE"; + case PDMAUDIOMIXERCTL_REAR: return "Rear"; + case PDMAUDIOMIXERCTL_LINE_IN: return "Line-In"; + case PDMAUDIOMIXERCTL_MIC_IN: return "Microphone-In"; + + /* no default */ + case PDMAUDIOMIXERCTL_END: + case PDMAUDIOMIXERCTL_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Invalid mixer control %ld\n", enmMixerCtl), "bad"); +} + +/** + * Gets the name of a path enum value. + * + * @returns Pointer to read-only name, "bad" if invalid input. + * @param enmPath The path value to name. + */ +DECLINLINE(const char *) PDMAudioPathGetName(PDMAUDIOPATH enmPath) +{ + switch (enmPath) + { + case PDMAUDIOPATH_INVALID: return "invalid"; + case PDMAUDIOPATH_UNKNOWN: return "unknown"; + + case PDMAUDIOPATH_OUT_FRONT: return "front"; + case PDMAUDIOPATH_OUT_CENTER_LFE: return "center-lfe"; + case PDMAUDIOPATH_OUT_REAR: return "rear"; + + case PDMAUDIOPATH_IN_MIC: return "mic"; + case PDMAUDIOPATH_IN_CD: return "cd"; + case PDMAUDIOPATH_IN_VIDEO: return "video-in"; + case PDMAUDIOPATH_IN_AUX: return "aux-in"; + case PDMAUDIOPATH_IN_LINE: return "line-in"; + case PDMAUDIOPATH_IN_PHONE: return "phone"; + + /* no default */ + case PDMAUDIOPATH_END: + case PDMAUDIOPATH_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Unknown enmPath=%d\n", enmPath), "bad"); +} + +/** + * Gets the name of a channel. + * + * @returns Pointer to read-only name, "bad" if invalid input. + * @param enmChannelId The channel ID to name. + */ +DECLINLINE(const char *) PDMAudioChannelIdGetName(PDMAUDIOCHANNELID enmChannelId) +{ + switch (enmChannelId) + { + case PDMAUDIOCHANNELID_INVALID: return "invalid"; + case PDMAUDIOCHANNELID_UNUSED_ZERO: return "unused-zero"; + case PDMAUDIOCHANNELID_UNUSED_SILENCE: return "unused-silence"; + case PDMAUDIOCHANNELID_UNKNOWN: return "unknown"; + + case PDMAUDIOCHANNELID_FRONT_LEFT: return "FL"; + case PDMAUDIOCHANNELID_FRONT_RIGHT: return "FR"; + case PDMAUDIOCHANNELID_FRONT_CENTER: return "FC"; + case PDMAUDIOCHANNELID_LFE: return "LFE"; + case PDMAUDIOCHANNELID_REAR_LEFT: return "BL"; + case PDMAUDIOCHANNELID_REAR_RIGHT: return "BR"; + case PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER: return "FLC"; + case PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER: return "FRC"; + case PDMAUDIOCHANNELID_REAR_CENTER: return "BC"; + case PDMAUDIOCHANNELID_SIDE_LEFT: return "SL"; + case PDMAUDIOCHANNELID_SIDE_RIGHT: return "SR"; + case PDMAUDIOCHANNELID_TOP_CENTER: return "TC"; + case PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT: return "TFL"; + case PDMAUDIOCHANNELID_FRONT_CENTER_HEIGHT: return "TFC"; + case PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT: return "TFR"; + case PDMAUDIOCHANNELID_REAR_LEFT_HEIGHT: return "TBL"; + case PDMAUDIOCHANNELID_REAR_CENTER_HEIGHT: return "TBC"; + case PDMAUDIOCHANNELID_REAR_RIGHT_HEIGHT: return "TBR"; + + /* no default */ + case PDMAUDIOCHANNELID_END: + case PDMAUDIOCHANNELID_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Unknown enmChannelId=%d\n", enmChannelId), "bad"); +} + + +/********************************************************************************************************************************* +* Volume Helpers * +*********************************************************************************************************************************/ + +/** + * Initializes a PDMAUDIOVOLUME structure to max. + * + * @param pVol The structure to initialize. + */ +DECLINLINE(void) PDMAudioVolumeInitMax(PPDMAUDIOVOLUME pVol) +{ + pVol->fMuted = false; + for (uintptr_t i = 0; i < RT_ELEMENTS(pVol->auChannels); i++) + pVol->auChannels[i] = PDMAUDIO_VOLUME_MAX; +} + + +/** + * Initializes a PDMAUDIOVOLUME structure from a simple stereo setting. + * + * The additional channels will simply be assigned the higer of the two. + * + * @param pVol The structure to initialize. + * @param fMuted Muted. + * @param bLeft The left channel volume. + * @param bRight The right channel volume. + */ +DECLINLINE(void) PDMAudioVolumeInitFromStereo(PPDMAUDIOVOLUME pVol, bool fMuted, uint8_t bLeft, uint8_t bRight) +{ + pVol->fMuted = fMuted; + pVol->auChannels[0] = bLeft; + pVol->auChannels[1] = bRight; + + uint8_t const bOther = RT_MAX(bLeft, bRight); + for (uintptr_t i = 2; i < RT_ELEMENTS(pVol->auChannels); i++) + pVol->auChannels[i] = bOther; +} + + +/** + * Combines two volume settings (typically master and sink). + * + * @param pVol Where to return the combined volume + * @param pVol1 The first volume settings to combine. + * @param pVol2 The second volume settings. + */ +DECLINLINE(void) PDMAudioVolumeCombine(PPDMAUDIOVOLUME pVol, PCPDMAUDIOVOLUME pVol1, PCPDMAUDIOVOLUME pVol2) +{ + if (pVol1->fMuted || pVol2->fMuted) + { + pVol->fMuted = true; + for (uintptr_t i = 0; i < RT_ELEMENTS(pVol->auChannels); i++) + pVol->auChannels[i] = 0; + } + else + { + pVol->fMuted = false; + /** @todo Very crude implementation for now -- needs more work! (At least + * when used in audioMixerSinkUpdateVolume it was considered as such.) */ + for (uintptr_t i = 0; i < RT_ELEMENTS(pVol->auChannels); i++) + { +#if 0 /* bird: I think the shift variant should produce the exact same result, w/o two conditionals per iteration. */ + /* 255 * 255 / 255 = 0xFF (255) */ + /* 17 * 127 / 255 = 8 */ + /* 39 * 39 / 255 = 5 */ + pVol->auChannels[i] = (uint8_t)( (RT_MAX(pVol1->auChannels[i], 1U) * RT_MAX(pVol2->auChannels[i], 1U)) + / PDMAUDIO_VOLUME_MAX); +#else + /* (((255 + 1) * (255 + 1)) >> 8) - 1 = 0xFF (255) */ + /* ((( 17 + 1) * (127 + 1)) >> 8) - 1 = 0x8 (8) */ + /* ((( 39 + 1) * ( 39 + 1)) >> 8) - 1 = 0x5 (5) */ + pVol->auChannels[i] = (uint8_t)((((1U + pVol1->auChannels[i]) * (1U + pVol2->auChannels[i])) >> 8) - 1U); +#endif + } + } +} + + +/********************************************************************************************************************************* +* PCM Property Helpers * +*********************************************************************************************************************************/ + +/** + * Assigns default channel IDs according to the channel count. + * + * The assignments are taken from the standard speaker channel layouts table + * in the wikipedia article on surround sound: + * https://en.wikipedia.org/wiki/Surround_sound#Standard_speaker_channels + */ +DECLINLINE(void) PDMAudioPropsSetDefaultChannelIds(PPDMAUDIOPCMPROPS pProps) +{ + unsigned cChannels = pProps->cChannelsX; + switch (cChannels) + { + case 1: + pProps->aidChannels[0] = PDMAUDIOCHANNELID_MONO; + break; + case 2: + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + break; + case 3: /* 2.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_LFE; + break; + case 4: /* 4.0 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_REAR_RIGHT; + break; + case 5: /* 4.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_CENTER; + break; + case 6: /* 5.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT; + break; + case 7: /* 6.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_REAR_CENTER; + break; + case 8: /* 7.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER; + pProps->aidChannels[7] = PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER; + break; + case 9: /* 9.0 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_SIDE_LEFT; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_SIDE_RIGHT; + pProps->aidChannels[7] = PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT; + pProps->aidChannels[8] = PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT; + break; + case 10: /* 9.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_SIDE_LEFT; + pProps->aidChannels[7] = PDMAUDIOCHANNELID_SIDE_RIGHT; + pProps->aidChannels[8] = PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT; + pProps->aidChannels[9] = PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT; + break; + case 11: /* 11.0 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER; + pProps->aidChannels[7] = PDMAUDIOCHANNELID_SIDE_LEFT; + pProps->aidChannels[8] = PDMAUDIOCHANNELID_SIDE_RIGHT; + pProps->aidChannels[9] = PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT; + pProps->aidChannels[10]= PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT; + break; + default: + AssertFailed(); + cChannels = 12; + RT_FALL_THROUGH(); + case 12: /* 11.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER; + pProps->aidChannels[7] = PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER; + pProps->aidChannels[8] = PDMAUDIOCHANNELID_SIDE_LEFT; + pProps->aidChannels[9] = PDMAUDIOCHANNELID_SIDE_RIGHT; + pProps->aidChannels[10]= PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT; + pProps->aidChannels[11]= PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT; + break; + case 0: + break; + } + AssertCompile(RT_ELEMENTS(pProps->aidChannels) >= 12); + + while (cChannels < RT_ELEMENTS(pProps->aidChannels)) + pProps->aidChannels[cChannels++] = PDMAUDIOCHANNELID_INVALID; +} + + +/** + * Initialize PCM audio properties. + */ +DECLINLINE(void) PDMAudioPropsInit(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample, bool fSigned, uint8_t cChannels, uint32_t uHz) +{ + pProps->cbFrame = cbSample * cChannels; + pProps->cbSampleX = cbSample; + pProps->cChannelsX = cChannels; + pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels); + pProps->fSigned = fSigned; + pProps->fSwapEndian = false; + pProps->fRaw = false; + pProps->uHz = uHz; + + Assert(pProps->cbFrame == (uint32_t)cbSample * cChannels); + Assert(pProps->cbSampleX == cbSample); + Assert(pProps->cChannelsX == cChannels); + + PDMAudioPropsSetDefaultChannelIds(pProps); +} + +/** + * Initialize PCM audio properties, extended version. + */ +DECLINLINE(void) PDMAudioPropsInitEx(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample, bool fSigned, uint8_t cChannels, uint32_t uHz, + bool fLittleEndian, bool fRaw) +{ + Assert(!fRaw || cbSample == sizeof(int64_t)); + pProps->cbFrame = cbSample * cChannels; + pProps->cbSampleX = cbSample; + pProps->cChannelsX = cChannels; + pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels); + pProps->fSigned = fSigned; +#ifdef RT_LITTLE_ENDIAN + pProps->fSwapEndian = !fLittleEndian; +#else + pProps->fSwapEndian = fLittleEndian; +#endif + pProps->fRaw = fRaw; + pProps->uHz = uHz; + + Assert(pProps->cbFrame == (uint32_t)cbSample * cChannels); + Assert(pProps->cbSampleX == cbSample); + Assert(pProps->cChannelsX == cChannels); + + PDMAudioPropsSetDefaultChannelIds(pProps); +} + +/** + * Modifies the channel count. + * + * @note This will reset the channel IDs to defaults. + * + * @param pProps The PCM properties to update. + * @param cChannels The new channel count. + */ +DECLINLINE(void) PDMAudioPropsSetChannels(PPDMAUDIOPCMPROPS pProps, uint8_t cChannels) +{ + Assert(cChannels > 0); Assert(cChannels < 16); + pProps->cChannelsX = cChannels; + pProps->cbFrame = pProps->cbSampleX * cChannels; + pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pProps->cbSampleX, cChannels); + + PDMAudioPropsSetDefaultChannelIds(pProps); +} + +/** + * Modifies the sample size. + * + * @param pProps The PCM properties to update. + * @param cbSample The new sample size (in bytes). + */ +DECLINLINE(void) PDMAudioPropsSetSampleSize(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample) +{ + Assert(cbSample == 1 || cbSample == 2 || cbSample == 4 || cbSample == 8); + pProps->cbSampleX = cbSample; + pProps->cbFrame = cbSample * pProps->cChannelsX; + pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, pProps->cChannelsX); +} + +/** + * Gets the bitrate. + * + * Divide the result by 8 to get the byte rate. + * + * @returns Bit rate. + * @param pProps PCM properties to calculate bitrate for. + */ +DECLINLINE(uint32_t) PDMAudioPropsGetBitrate(PCPDMAUDIOPCMPROPS pProps) +{ + Assert(pProps->cbFrame == pProps->cbSampleX * pProps->cChannelsX); + return pProps->cbFrame * pProps->uHz * 8; +} + +/** + * Gets the number of channels. + * @returns The channel count. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(uint8_t) PDMAudioPropsChannels(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->cChannelsX; +} + +/** + * Gets the sample size in bytes. + * @returns Number of bytes per sample. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(uint8_t) PDMAudioPropsSampleSize(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->cbSampleX; +} + +/** + * Gets the sample size in bits. + * @returns Number of bits per sample. + * @param pProps The PCM properties. + */ +DECLINLINE(uint8_t) PDMAudioPropsSampleBits(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->cbSampleX * 8; +} + +/** + * Gets the frame size in bytes. + * @returns Number of bytes per frame. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(uint8_t) PDMAudioPropsFrameSize(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->cbFrame; +} + +/** + * Gets the frequency. + * @returns Frequency. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(uint32_t) PDMAudioPropsHz(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->uHz; +} + +/** + * Checks if the format is signed or unsigned. + * @returns true if signed, false if unsigned. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(bool) PDMAudioPropsIsSigned(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->fSigned; +} + +/** + * Checks if the format is little-endian or not. + * @returns true if little-endian (or if 8-bit), false if big-endian. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(bool) PDMAudioPropsIsLittleEndian(PCPDMAUDIOPCMPROPS pProps) +{ +#ifdef RT_LITTLE_ENDIAN + return !pProps->fSwapEndian || pProps->cbSampleX < 2; +#else + return pProps->fSwapEndian || pProps->cbSampleX < 2; +#endif +} + +/** + * Checks if the format is big-endian or not. + * @returns true if big-endian (or if 8-bit), false if little-endian. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(bool) PDMAudioPropsIsBigEndian(PCPDMAUDIOPCMPROPS pProps) +{ +#ifdef RT_LITTLE_ENDIAN + return pProps->fSwapEndian || pProps->cbSampleX < 2; +#else + return !pProps->fSwapEndian || pProps->cbSampleX < 2; +#endif +} + +/** + * Rounds down the given byte amount to the nearest frame boundrary. + * + * @returns Rounded byte amount. + * @param pProps PCM properties to use. + * @param cb The size (in bytes) to round. + */ +DECLINLINE(uint32_t) PDMAudioPropsFloorBytesToFrame(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + return PDMAUDIOPCMPROPS_F2B(pProps, PDMAUDIOPCMPROPS_B2F(pProps, cb)); +} + +/** + * Rounds up the given byte amount to the nearest frame boundrary. + * + * @returns Rounded byte amount. + * @param pProps PCM properties to use. + * @param cb The size (in bytes) to round. + */ +DECLINLINE(uint32_t) PDMAudioPropsRoundUpBytesToFrame(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + uint32_t const cbFrame = PDMAudioPropsFrameSize(pProps); + AssertReturn(cbFrame, 0); + return PDMAUDIOPCMPROPS_F2B(pProps, PDMAUDIOPCMPROPS_B2F(pProps, cb + cbFrame - 1)); +} + +/** + * Checks if the given size is aligned on a frame boundrary. + * + * @returns @c true if properly aligned, @c false if not. + * @param pProps PCM properties to use. + * @param cb The size (in bytes) to check. + */ +DECLINLINE(bool) PDMAudioPropsIsSizeAligned(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, false); + uint32_t const cbFrame = PDMAudioPropsFrameSize(pProps); + AssertReturn(cbFrame, false); + return cb % cbFrame == 0; +} + +/** + * Converts bytes to frames (rounding down of course). + * + * @returns Number of frames. + * @param pProps PCM properties to use. + * @param cb The number of bytes to convert. + */ +DECLINLINE(uint32_t) PDMAudioPropsBytesToFrames(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + return PDMAUDIOPCMPROPS_B2F(pProps, cb); +} + +/** + * Converts bytes to milliseconds. + * + * @return Number milliseconds @a cb takes to play or record. + * @param pProps PCM properties to use. + * @param cb The number of bytes to convert. + * + * @note Rounds up the result. + */ +DECLINLINE(uint64_t) PDMAudioPropsBytesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + + /* Check parameters to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + { + const unsigned cbFrame = PDMAudioPropsFrameSize(pProps); + if (cbFrame) + { + /* Round cb up to closest frame size: */ + cb = (cb + cbFrame - 1) / cbFrame; + + /* Convert to milliseconds. */ + return (cb * (uint64_t)RT_MS_1SEC + uHz - 1) / uHz; + } + } + return 0; +} + +/** + * Converts bytes to microseconds. + * + * @return Number microseconds @a cb takes to play or record. + * @param pProps PCM properties to use. + * @param cb The number of bytes to convert. + * + * @note Rounds up the result. + */ +DECLINLINE(uint64_t) PDMAudioPropsBytesToMicro(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + + /* Check parameters to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + { + const unsigned cbFrame = PDMAudioPropsFrameSize(pProps); + if (cbFrame) + { + /* Round cb up to closest frame size: */ + cb = (cb + cbFrame - 1) / cbFrame; + + /* Convert to microseconds. */ + return (cb * (uint64_t)RT_US_1SEC + uHz - 1) / uHz; + } + } + return 0; +} + +/** + * Converts bytes to nanoseconds. + * + * @return Number nanoseconds @a cb takes to play or record. + * @param pProps PCM properties to use. + * @param cb The number of bytes to convert. + * + * @note Rounds up the result. + */ +DECLINLINE(uint64_t) PDMAudioPropsBytesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + + /* Check parameters to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + { + const unsigned cbFrame = PDMAudioPropsFrameSize(pProps); + if (cbFrame) + { + /* Round cb up to closest frame size: */ + cb = (cb + cbFrame - 1) / cbFrame; + + /* Convert to nanoseconds. */ + return (cb * (uint64_t)RT_NS_1SEC + uHz - 1) / uHz; + } + } + return 0; +} + +/** + * Converts bytes to nanoseconds, 64-bit version. + * + * @return Number nanoseconds @a cb takes to play or record. + * @param pProps PCM properties to use. + * @param cb The number of bytes to convert (64-bit). + * + * @note Rounds up the result. + */ +DECLINLINE(uint64_t) PDMAudioPropsBytesToNano64(PCPDMAUDIOPCMPROPS pProps, uint64_t cb) +{ + AssertPtrReturn(pProps, 0); + + /* Check parameters to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + { + const unsigned cbFrame = PDMAudioPropsFrameSize(pProps); + if (cbFrame) + { + /* Round cb up to closest frame size: */ + cb = (cb + cbFrame - 1) / cbFrame; + + /* Convert to nanoseconds. */ + return (cb * RT_NS_1SEC + uHz - 1) / uHz; + } + } + return 0; +} + +/** + * Converts frames to bytes. + * + * @returns Number of bytes. + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @sa PDMAUDIOPCMPROPS_F2B + */ +DECLINLINE(uint32_t) PDMAudioPropsFramesToBytes(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) +{ + AssertPtrReturn(pProps, 0); + return PDMAUDIOPCMPROPS_F2B(pProps, cFrames); +} + +/** + * Converts frames to milliseconds. + * + * @returns milliseconds. + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @note No rounding here, result is floored. + */ +DECLINLINE(uint64_t) PDMAudioPropsFramesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) +{ + AssertPtrReturn(pProps, 0); + + /* Check input to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + return ASMMultU32ByU32DivByU32(cFrames, RT_MS_1SEC, uHz); + return 0; +} + +/** + * Converts frames to milliseconds, but not returning more than @a cMsMax + * + * This is a convenience for logging and such. + * + * @returns milliseconds (32-bit). + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @param cMsMax Max return value (32-bit). + * @note No rounding here, result is floored. + */ +DECLINLINE(uint32_t) PDMAudioPropsFramesToMilliMax(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames, uint32_t cMsMax) +{ + AssertPtrReturn(pProps, 0); + + /* Check input to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + { + uint32_t const cMsResult = ASMMultU32ByU32DivByU32(cFrames, RT_MS_1SEC, uHz); + return RT_MIN(cMsResult, cMsMax); + } + return 0; +} + +/** + * Converts frames to microseconds. + * + * @returns microseconds. + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @note No rounding here, result is floored. + */ +DECLINLINE(uint64_t) PDMAudioPropsFramesToMicro(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) +{ + AssertPtrReturn(pProps, 0); + + /* Check input to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + return ASMMultU32ByU32DivByU32(cFrames, RT_US_1SEC, uHz); + return 0; +} + +/** + * Converts frames to nanoseconds. + * + * @returns Nanoseconds. + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @note No rounding here, result is floored. + */ +DECLINLINE(uint64_t) PDMAudioPropsFramesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) +{ + AssertPtrReturn(pProps, 0); + + /* Check input to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + return ASMMultU32ByU32DivByU32(cFrames, RT_NS_1SEC, uHz); + return 0; +} + +/** + * Converts frames to NT ticks (100 ns units). + * + * @returns NT ticks. + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @note No rounding here, result is floored. + */ +DECLINLINE(uint64_t) PDMAudioPropsFramesToNtTicks(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) +{ + AssertPtrReturn(pProps, 0); + + /* Check input to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + return ASMMultU32ByU32DivByU32(cFrames, RT_NS_1SEC / 100, uHz); + return 0; +} + +/** + * Converts milliseconds to frames. + * + * @returns Number of frames + * @param pProps The PCM properties to use. + * @param cMs The number of milliseconds to convert. + * + * @note The result is rounded rather than floored (hysterical raisins). + */ +DECLINLINE(uint32_t) PDMAudioPropsMilliToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs) +{ + AssertPtrReturn(pProps, 0); + + uint32_t const uHz = pProps->uHz; + uint32_t cFrames; + if (cMs < RT_MS_1SEC) + cFrames = 0; + else + { + cFrames = cMs / RT_MS_1SEC * uHz; + cMs %= RT_MS_1SEC; + } + cFrames += (ASMMult2xU32RetU64(uHz, (uint32_t)cMs) + RT_MS_1SEC - 1) / RT_MS_1SEC; + return cFrames; +} + +/** + * Converts milliseconds to bytes. + * + * @returns Number of bytes (frame aligned). + * @param pProps The PCM properties to use. + * @param cMs The number of milliseconds to convert. + * + * @note The result is rounded rather than floored (hysterical raisins). + */ +DECLINLINE(uint32_t) PDMAudioPropsMilliToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs) +{ + return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsMilliToFrames(pProps, cMs)); +} + +/** + * Converts nanoseconds to frames. + * + * @returns Number of frames. + * @param pProps The PCM properties to use. + * @param cNs The number of nanoseconds to convert. + * + * @note The result is rounded rather than floored (hysterical raisins). + */ +DECLINLINE(uint32_t) PDMAudioPropsNanoToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs) +{ + AssertPtrReturn(pProps, 0); + + uint32_t const uHz = pProps->uHz; + uint32_t cFrames; + if (cNs < RT_NS_1SEC) + cFrames = 0; + else + { + cFrames = cNs / RT_NS_1SEC * uHz; + cNs %= RT_NS_1SEC; + } + cFrames += (ASMMult2xU32RetU64(uHz, (uint32_t)cNs) + RT_NS_1SEC - 1) / RT_NS_1SEC; + return cFrames; +} + +/** + * Converts nanoseconds to frames, 64-bit return. + * + * @returns Number of frames (64-bit). + * @param pProps The PCM properties to use. + * @param cNs The number of nanoseconds to convert. + * + * @note The result is floored! + */ +DECLINLINE(uint64_t) PDMAudioPropsNanoToFrames64(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs) +{ + AssertPtrReturn(pProps, 0); + + uint32_t const uHz = pProps->uHz; + uint64_t cFrames; + if (cNs < RT_NS_1SEC) + cFrames = 0; + else + { + cFrames = cNs / RT_NS_1SEC * uHz; + cNs %= RT_NS_1SEC; + } + cFrames += ASMMult2xU32RetU64(uHz, (uint32_t)cNs) / RT_NS_1SEC; + return cFrames; +} + +/** + * Converts nanoseconds to bytes. + * + * @returns Number of bytes (frame aligned). + * @param pProps The PCM properties to use. + * @param cNs The number of nanoseconds to convert. + * + * @note The result is rounded rather than floored (hysterical raisins). + */ +DECLINLINE(uint32_t) PDMAudioPropsNanoToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs) +{ + return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsNanoToFrames(pProps, cNs)); +} + +/** + * Converts nanoseconds to bytes, 64-bit version. + * + * @returns Number of bytes (frame aligned), 64-bit. + * @param pProps The PCM properties to use. + * @param cNs The number of nanoseconds to convert. + * + * @note The result is floored. + */ +DECLINLINE(uint64_t) PDMAudioPropsNanoToBytes64(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs) +{ + return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsNanoToFrames(pProps, cNs)); +} + +/** + * Clears a sample buffer by the given amount of audio frames with silence (according to the format + * given by the PCM properties). + * + * @param pProps The PCM properties to apply. + * @param pvBuf The buffer to clear. + * @param cbBuf The buffer size in bytes. + * @param cFrames The number of audio frames to clear. Capped at @a cbBuf + * if exceeding the buffer. If the size is an unaligned + * number of frames, the extra bytes may be left + * uninitialized in some configurations. + */ +DECLINLINE(void) PDMAudioPropsClearBuffer(PCPDMAUDIOPCMPROPS pProps, void *pvBuf, size_t cbBuf, uint32_t cFrames) +{ + /* + * Validate input + */ + AssertPtrReturnVoid(pProps); + Assert(pProps->cbSampleX); + if (!cbBuf || !cFrames) + return; + AssertPtrReturnVoid(pvBuf); + + /* + * Decide how much needs clearing. + */ + size_t cbToClear = PDMAudioPropsFramesToBytes(pProps, cFrames); + AssertStmt(cbToClear <= cbBuf, cbToClear = cbBuf); + + Log2Func(("pProps=%p, pvBuf=%p, cFrames=%RU32, fSigned=%RTbool, cbSample=%RU8\n", + pProps, pvBuf, cFrames, pProps->fSigned, pProps->cbSampleX)); + + /* + * Do the job. + */ + if (pProps->fSigned) + RT_BZERO(pvBuf, cbToClear); + else /* Unsigned formats. */ + { + switch (pProps->cbSampleX) + { + case 1: /* 8 bit */ + memset(pvBuf, 0x80, cbToClear); + break; + + case 2: /* 16 bit */ + { + uint16_t *pu16Dst = (uint16_t *)pvBuf; + uint16_t const u16Offset = !pProps->fSwapEndian ? UINT16_C(0x8000) : UINT16_C(0x80); + cbBuf /= sizeof(*pu16Dst); + while (cbBuf-- > 0) + *pu16Dst++ = u16Offset; + break; + } + + case 4: /* 32 bit */ + ASMMemFill32(pvBuf, cbToClear & ~(size_t)(sizeof(uint32_t) - 1), + !pProps->fSwapEndian ? UINT32_C(0x80000000) : UINT32_C(0x80)); + break; + + default: + AssertMsgFailed(("Invalid bytes per sample: %RU8\n", pProps->cbSampleX)); + } + } +} + +/** + * Checks if the given buffer is silence. + * + * @param pProps The PCM properties to use checking the buffer. + * @param pvBuf The buffer to check. + * @param cbBuf The number of bytes to check (must be frame aligned). + */ +DECLINLINE(bool) PDMAudioPropsIsBufferSilence(PCPDMAUDIOPCMPROPS pProps, void const *pvBuf, size_t cbBuf) +{ + /* + * Validate input + */ + AssertPtrReturn(pProps, false); + if (!cbBuf) + return false; + AssertPtrReturn(pvBuf, false); + + /* + * Do the job. + */ + if (pProps->fSigned) + return ASMMemIsZero(pvBuf, cbBuf); + + switch (pProps->cbSampleX) + { + case 1: /* 8 bit */ + return ASMMemIsAllU8(pvBuf, cbBuf, 0x80); + + case 2: /* 16 bit */ + { + uint16_t const *pu16 = (uint16_t const *)pvBuf; + uint16_t const u16Offset = !pProps->fSwapEndian ? UINT16_C(0x8000) : UINT16_C(0x80); + cbBuf /= sizeof(*pu16); + while (cbBuf-- > 0) + if (*pu16 != u16Offset) + return false; + return true; + } + + case 4: /* 32 bit */ + { + uint32_t const *pu32 = (uint32_t const *)pvBuf; + uint32_t const u32Offset = !pProps->fSwapEndian ? UINT32_C(0x80000000) : UINT32_C(0x80); + cbBuf /= sizeof(*pu32); + while (cbBuf-- > 0) + if (*pu32 != u32Offset) + return false; + return true; + } + + default: + AssertMsgFailed(("Invalid bytes per sample: %RU8\n", pProps->cbSampleX)); + return false; + } +} + +/** + * Compares two sets of PCM properties. + * + * @returns @c true if the same, @c false if not. + * @param pProps1 The first set of properties to compare. + * @param pProps2 The second set of properties to compare. + */ +DECLINLINE(bool) PDMAudioPropsAreEqual(PCPDMAUDIOPCMPROPS pProps1, PCPDMAUDIOPCMPROPS pProps2) +{ + uintptr_t idxCh; + AssertPtrReturn(pProps1, false); + AssertPtrReturn(pProps2, false); + + if (pProps1 == pProps2) /* If the pointers match, take a shortcut. */ + return true; + + if (pProps1->uHz != pProps2->uHz) + return false; + if (pProps1->cChannelsX != pProps2->cChannelsX) + return false; + if (pProps1->cbSampleX != pProps2->cbSampleX) + return false; + if (pProps1->fSigned != pProps2->fSigned) + return false; + if (pProps1->fSwapEndian != pProps2->fSwapEndian) + return false; + if (pProps1->fRaw != pProps2->fRaw) + return false; + + idxCh = pProps1->cChannelsX; + while (idxCh-- > 0) + if (pProps1->aidChannels[idxCh] != pProps2->aidChannels[idxCh]) + return false; + + return true; +} + +/** + * Checks whether the given PCM properties are valid or not. + * + * @returns true/false accordingly. + * @param pProps The PCM properties to check. + * + * @remarks This just performs a generic check of value ranges. + * + * @sa PDMAudioStrmCfgIsValid + */ +DECLINLINE(bool) PDMAudioPropsAreValid(PCPDMAUDIOPCMPROPS pProps) +{ + AssertPtrReturn(pProps, false); + + /* Channels. */ + if ( pProps->cChannelsX != 0 + && pProps->cChannelsX <= PDMAUDIO_MAX_CHANNELS + /* Sample size. */ + && ( pProps->cbSampleX == 1 + || pProps->cbSampleX == 2 + || pProps->cbSampleX == 4 + || (pProps->cbSampleX == 8 && pProps->fRaw)) + /* Hertz rate. */ + && pProps->uHz >= 1000 + && pProps->uHz < 1000000 + /* Raw format: Here we only support int64_t as sample size currently, if enabled. */ + && ( !pProps->fRaw + || (pProps->fSigned && pProps->cbSampleX == sizeof(int64_t))) + ) + { + /* A few more sanity checks to see if the structure has been properly initialized (via PDMAudioPropsInit[Ex]). */ + AssertMsgReturn(pProps->cShiftX == PDMAUDIOPCMPROPS_MAKE_SHIFT(pProps), + ("cShift=%u cbSample=%u cChannels=%u\n", pProps->cShiftX, pProps->cbSampleX, pProps->cChannelsX), + false); + AssertMsgReturn(pProps->cbFrame == pProps->cbSampleX * pProps->cChannelsX, + ("cbFrame=%u cbSample=%u cChannels=%u\n", pProps->cbFrame, pProps->cbSampleX, pProps->cChannelsX), + false); + + return true; + } + + return false; +} + +/** + * Get number of bytes per frame. + * + * @returns Number of bytes per audio frame. + * @param pProps PCM properties to use. + * @sa PDMAUDIOPCMPROPS_F2B + */ +DECLINLINE(uint32_t) PDMAudioPropsBytesPerFrame(PCPDMAUDIOPCMPROPS pProps) +{ + return PDMAUDIOPCMPROPS_F2B(pProps, 1 /*cFrames*/); +} + +/** + * Prints PCM properties to the debug log. + * + * @param pProps PCM properties to use. + */ +DECLINLINE(void) PDMAudioPropsLog(PCPDMAUDIOPCMPROPS pProps) +{ + AssertPtrReturnVoid(pProps); + + Log(("uHz=%RU32, cChannels=%RU8, cBits=%RU8%s", + pProps->uHz, pProps->cChannelsX, pProps->cbSampleX * 8, pProps->fSigned ? "S" : "U")); +} + +/** Max necessary buffer space for PDMAudioPropsToString */ +#define PDMAUDIOPROPSTOSTRING_MAX sizeof("16ch S64 4294967296Hz swap raw") + +/** + * Formats the PCM audio properties into a string buffer. + * + * @returns pszDst + * @param pProps PCM properties to use. + * @param pszDst The destination buffer. + * @param cchDst The size of the destination buffer. Recommended to be at + * least PDMAUDIOPROPSTOSTRING_MAX bytes. + */ +DECLINLINE(char *) PDMAudioPropsToString(PCPDMAUDIOPCMPROPS pProps, char *pszDst, size_t cchDst) +{ + /* 2ch S64 44100Hz swap raw */ + RTStrPrintf(pszDst, cchDst, "%uch %c%u %RU32Hz%s%s", + PDMAudioPropsChannels(pProps), PDMAudioPropsIsSigned(pProps) ? 'S' : 'U', PDMAudioPropsSampleBits(pProps), + PDMAudioPropsHz(pProps), pProps->fSwapEndian ? " swap" : "", pProps->fRaw ? " raw" : ""); + return pszDst; +} + + +/********************************************************************************************************************************* +* Stream Configuration Helpers * +*********************************************************************************************************************************/ + +/** + * Initializes a stream configuration from PCM properties. + * + * @returns VBox status code. + * @param pCfg The stream configuration to initialize. + * @param pProps The PCM properties to use. + */ +DECLINLINE(int) PDMAudioStrmCfgInitWithProps(PPDMAUDIOSTREAMCFG pCfg, PCPDMAUDIOPCMPROPS pProps) +{ + AssertPtrReturn(pProps, VERR_INVALID_POINTER); + AssertPtrReturn(pCfg, VERR_INVALID_POINTER); + + RT_ZERO(*pCfg); + pCfg->Backend.cFramesPreBuffering = UINT32_MAX; /* Explicitly set to "undefined". */ + + memcpy(&pCfg->Props, pProps, sizeof(PDMAUDIOPCMPROPS)); + + return VINF_SUCCESS; +} + +/** + * Checks whether stream configuration matches the given PCM properties. + * + * @returns @c true if equal, @c false if not. + * @param pCfg The stream configuration. + * @param pProps The PCM properties to match with. + */ +DECLINLINE(bool) PDMAudioStrmCfgMatchesProps(PCPDMAUDIOSTREAMCFG pCfg, PCPDMAUDIOPCMPROPS pProps) +{ + AssertPtrReturn(pCfg, false); + return PDMAudioPropsAreEqual(pProps, &pCfg->Props); +} + +/** + * Checks whether two stream configuration matches. + * + * @returns @c true if equal, @c false if not. + * @param pCfg1 The first stream configuration. + * @param pCfg2 The second stream configuration. + */ +DECLINLINE(bool) PDMAudioStrmCfgEquals(PCPDMAUDIOSTREAMCFG pCfg1, PCPDMAUDIOSTREAMCFG pCfg2) +{ + if (!pCfg1 || !pCfg2) + return false; + if (pCfg1 == pCfg2) + return pCfg1 != NULL; + if (PDMAudioPropsAreEqual(&pCfg1->Props, &pCfg2->Props)) + return pCfg1->enmDir == pCfg2->enmDir + && pCfg1->enmPath == pCfg2->enmPath + && pCfg1->Device.cMsSchedulingHint == pCfg2->Device.cMsSchedulingHint + && pCfg1->Backend.cFramesPeriod == pCfg2->Backend.cFramesPeriod + && pCfg1->Backend.cFramesBufferSize == pCfg2->Backend.cFramesBufferSize + && pCfg1->Backend.cFramesPreBuffering == pCfg2->Backend.cFramesPreBuffering + && strcmp(pCfg1->szName, pCfg2->szName) == 0; + return false; +} + +/** + * Frees an audio stream allocated by PDMAudioStrmCfgDup(). + * + * @param pCfg The stream configuration to free. + */ +DECLINLINE(void) PDMAudioStrmCfgFree(PPDMAUDIOSTREAMCFG pCfg) +{ + if (pCfg) + RTMemFree(pCfg); +} + +/** + * Checks whether the given stream configuration is valid or not. + * + * @returns true/false accordingly. + * @param pCfg Stream configuration to check. + * + * @remarks This just performs a generic check of value ranges. Further, it + * will assert if the input is invalid. + * + * @sa PDMAudioPropsAreValid + */ +DECLINLINE(bool) PDMAudioStrmCfgIsValid(PCPDMAUDIOSTREAMCFG pCfg) +{ + AssertPtrReturn(pCfg, false); + AssertMsgReturn(pCfg->enmDir >= PDMAUDIODIR_UNKNOWN && pCfg->enmDir < PDMAUDIODIR_END, ("%d\n", pCfg->enmDir), false); + return PDMAudioPropsAreValid(&pCfg->Props); +} + +/** + * Copies one stream configuration to another. + * + * @returns VBox status code. + * @param pDstCfg The destination stream configuration. + * @param pSrcCfg The source stream configuration. + */ +DECLINLINE(int) PDMAudioStrmCfgCopy(PPDMAUDIOSTREAMCFG pDstCfg, PCPDMAUDIOSTREAMCFG pSrcCfg) +{ + AssertPtrReturn(pDstCfg, VERR_INVALID_POINTER); + AssertPtrReturn(pSrcCfg, VERR_INVALID_POINTER); + + /* This used to be VBOX_STRICT only and return VERR_INVALID_PARAMETER, but + that's making release builds work differently from debug & strict builds, + which is a terrible idea: */ + Assert(PDMAudioStrmCfgIsValid(pSrcCfg)); + + memcpy(pDstCfg, pSrcCfg, sizeof(PDMAUDIOSTREAMCFG)); + + return VINF_SUCCESS; +} + +/** + * Duplicates an audio stream configuration. + * + * @returns Pointer to duplicate on success, NULL on failure. Must be freed + * using PDMAudioStrmCfgFree(). + * + * @param pCfg The audio stream configuration to duplicate. + */ +DECLINLINE(PPDMAUDIOSTREAMCFG) PDMAudioStrmCfgDup(PCPDMAUDIOSTREAMCFG pCfg) +{ + AssertPtrReturn(pCfg, NULL); + + PPDMAUDIOSTREAMCFG pDst = (PPDMAUDIOSTREAMCFG)RTMemAllocZ(sizeof(PDMAUDIOSTREAMCFG)); + if (pDst) + { + int rc = PDMAudioStrmCfgCopy(pDst, pCfg); + if (RT_SUCCESS(rc)) + return pDst; + + PDMAudioStrmCfgFree(pDst); + } + return NULL; +} + +/** + * Logs an audio stream configuration. + * + * @param pCfg The stream configuration to log. + */ +DECLINLINE(void) PDMAudioStrmCfgLog(PCPDMAUDIOSTREAMCFG pCfg) +{ + if (pCfg) + LogFunc(("szName=%s enmDir=%RU32 uHz=%RU32 cBits=%RU8%s cChannels=%RU8\n", pCfg->szName, pCfg->enmDir, + pCfg->Props.uHz, pCfg->Props.cbSampleX * 8, pCfg->Props.fSigned ? "S" : "U", pCfg->Props.cChannelsX)); +} + +/** + * Converts a stream command enum value to a string. + * + * @returns Pointer to read-only stream command name on success, + * "bad" if invalid command value. + * @param enmCmd The stream command to name. + */ +DECLINLINE(const char *) PDMAudioStrmCmdGetName(PDMAUDIOSTREAMCMD enmCmd) +{ + switch (enmCmd) + { + case PDMAUDIOSTREAMCMD_INVALID: return "Invalid"; + case PDMAUDIOSTREAMCMD_ENABLE: return "Enable"; + case PDMAUDIOSTREAMCMD_DISABLE: return "Disable"; + case PDMAUDIOSTREAMCMD_PAUSE: return "Pause"; + case PDMAUDIOSTREAMCMD_RESUME: return "Resume"; + case PDMAUDIOSTREAMCMD_DRAIN: return "Drain"; + case PDMAUDIOSTREAMCMD_END: + case PDMAUDIOSTREAMCMD_32BIT_HACK: + break; + /* no default! */ + } + AssertMsgFailedReturn(("Invalid stream command %d\n", enmCmd), "bad"); +} + +/** Max necessary buffer space for PDMAudioStrmCfgToString */ +#define PDMAUDIOSTRMCFGTOSTRING_MAX \ + sizeof("'01234567890123456789012345678901234567890123456789012345678901234' unknown 16ch S64 4294967295Hz swap raw, 9999999ms buffer, 9999999ms period, 9999999ms pre-buffer, 4294967295ms sched, center-lfe") + +/** + * Formats an audio stream configuration. + * + * @param pCfg The stream configuration to stringify. + * @param pszDst The destination buffer. + * @param cbDst The size of the destination buffer. Recommend this be + * at least PDMAUDIOSTRMCFGTOSTRING_MAX bytes. + */ +DECLINLINE(const char *) PDMAudioStrmCfgToString(PCPDMAUDIOSTREAMCFG pCfg, char *pszDst, size_t cbDst) +{ + /* 'front' output 2ch 44100Hz raw, 300ms buffer, 75ms period, 150ms pre-buffer, 10ms sched */ + RTStrPrintf(pszDst, cbDst, + "'%s' %s %uch %c%u %RU32Hz%s%s, %RU32ms buffer, %RU32ms period, %RU32ms pre-buffer, %RU32ms sched%s%s", + pCfg->szName, PDMAudioDirGetName(pCfg->enmDir), PDMAudioPropsChannels(&pCfg->Props), + PDMAudioPropsIsSigned(&pCfg->Props) ? 'S' : 'U', PDMAudioPropsSampleBits(&pCfg->Props), + PDMAudioPropsHz(&pCfg->Props), pCfg->Props.fSwapEndian ? " swap" : "", pCfg->Props.fRaw ? " raw" : "", + PDMAudioPropsFramesToMilliMax(&pCfg->Props, pCfg->Backend.cFramesBufferSize, 9999999), + PDMAudioPropsFramesToMilliMax(&pCfg->Props, pCfg->Backend.cFramesPeriod, 9999999), + PDMAudioPropsFramesToMilliMax(&pCfg->Props, pCfg->Backend.cFramesPreBuffering, 9999999), + pCfg->Device.cMsSchedulingHint, + pCfg->enmPath == PDMAUDIOPATH_UNKNOWN ? "" : ", ", + pCfg->enmPath == PDMAUDIOPATH_UNKNOWN ? "" : PDMAudioPathGetName(pCfg->enmPath) ); + return pszDst; +} + + +/********************************************************************************************************************************* +* Stream Status Helpers * +*********************************************************************************************************************************/ + +/** + * Converts a audio stream state enum value to a string. + * + * @returns Pointer to read-only audio stream state string on success, + * "illegal" if invalid command value. + * @param enmStreamState The state to convert. + */ +DECLINLINE(const char *) PDMAudioStreamStateGetName(PDMAUDIOSTREAMSTATE enmStreamState) +{ + switch (enmStreamState) + { + case PDMAUDIOSTREAMSTATE_INVALID: return "invalid"; + case PDMAUDIOSTREAMSTATE_NOT_WORKING: return "not-working"; + case PDMAUDIOSTREAMSTATE_NEED_REINIT: return "need-reinit"; + case PDMAUDIOSTREAMSTATE_INACTIVE: return "inactive"; + case PDMAUDIOSTREAMSTATE_ENABLED: return "enabled"; + case PDMAUDIOSTREAMSTATE_ENABLED_READABLE: return "enabled-readable"; + case PDMAUDIOSTREAMSTATE_ENABLED_WRITABLE: return "enabled-writable"; + /* no default: */ + case PDMAUDIOSTREAMSTATE_END: + case PDMAUDIOSTREAMSTATE_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Invalid audio stream state: %d\n", enmStreamState), "illegal"); +} + +/** + * Converts a host audio (backend) stream state enum value to a string. + * + * @returns Pointer to read-only host audio stream state string on success, + * "illegal" if invalid command value. + * @param enmHostAudioStreamState The state to convert. + */ +DECLINLINE(const char *) PDMHostAudioStreamStateGetName(PDMHOSTAUDIOSTREAMSTATE enmHostAudioStreamState) +{ + switch (enmHostAudioStreamState) + { + case PDMHOSTAUDIOSTREAMSTATE_INVALID: return "invalid"; + case PDMHOSTAUDIOSTREAMSTATE_INITIALIZING: return "initializing"; + case PDMHOSTAUDIOSTREAMSTATE_NOT_WORKING: return "not-working"; + case PDMHOSTAUDIOSTREAMSTATE_OKAY: return "okay"; + case PDMHOSTAUDIOSTREAMSTATE_DRAINING: return "draining"; + case PDMHOSTAUDIOSTREAMSTATE_INACTIVE: return "inactive"; + /* no default: */ + case PDMHOSTAUDIOSTREAMSTATE_END: + case PDMHOSTAUDIOSTREAMSTATE_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Invalid host audio stream state: %d\n", enmHostAudioStreamState), "illegal"); +} + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmaudioinline_h */ diff --git a/include/VBox/vmm/pdmblkcache.h b/include/VBox/vmm/pdmblkcache.h new file mode 100644 index 00000000..c9ff51d1 --- /dev/null +++ b/include/VBox/vmm/pdmblkcache.h @@ -0,0 +1,432 @@ +/** @file + * PDM - Pluggable Device Manager, Block cache. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmblkcache_h +#define VBOX_INCLUDED_vmm_pdmblkcache_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/sg.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_blk_cache The PDM Block Cache API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer to a PDM block cache. */ +typedef struct PDMBLKCACHE *PPDMBLKCACHE; +/** Pointer to a PDM block cache pointer. */ +typedef PPDMBLKCACHE *PPPDMBLKCACHE; + +/** I/O transfer handle. */ +typedef struct PDMBLKCACHEIOXFER *PPDMBLKCACHEIOXFER; + +/** + * Block cache I/O request transfer direction. + */ +typedef enum PDMBLKCACHEXFERDIR +{ + /** Read */ + PDMBLKCACHEXFERDIR_READ = 0, + /** Write */ + PDMBLKCACHEXFERDIR_WRITE, + /** Flush */ + PDMBLKCACHEXFERDIR_FLUSH, + /** Discard */ + PDMBLKCACHEXFERDIR_DISCARD +} PDMBLKCACHEXFERDIR; + +/** + * Completion callback for drivers. + * + * @param pDrvIns The driver instance. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMBLKCACHEXFERCOMPLETEDRV,(PPDMDRVINS pDrvIns, void *pvUser, int rc)); +/** Pointer to a FNPDMBLKCACHEXFERCOMPLETEDRV(). */ +typedef FNPDMBLKCACHEXFERCOMPLETEDRV *PFNPDMBLKCACHEXFERCOMPLETEDRV; + +/** + * I/O enqueue callback for drivers. + * + * @param pDrvIns The driver instance. + * @param enmXferDir Transfer direction. + * @param off Transfer offset. + * @param cbXfer Transfer size. + * @param pSgBuf Scather / gather buffer for the transfer. + * @param hIoXfer I/O transfer handle to ping on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDRV,(PPDMDRVINS pDrvIns, PDMBLKCACHEXFERDIR enmXferDir, uint64_t off, + size_t cbXfer, PCRTSGBUF pSgBuf, PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDRV(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDRV *PFNPDMBLKCACHEXFERENQUEUEDRV; + +/** + * Discard enqueue callback for drivers. + * + * @param pDrvIns The driver instance. + * @param paRanges Ranges to discard. + * @param cRanges Number of range entries. + * @param hIoXfer I/O handle to return on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDISCARDDRV,(PPDMDRVINS pDrvIns, PCRTRANGE paRanges, unsigned cRanges, + PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDISCARDDRV(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDISCARDDRV *PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV; + +/** + * Completion callback for devices. + * + * @param pDevIns The device instance. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMBLKCACHEXFERCOMPLETEDEV,(PPDMDEVINS pDevIns, void *pvUser, int rc)); +/** Pointer to a FNPDMBLKCACHEXFERCOMPLETEDEV(). */ +typedef FNPDMBLKCACHEXFERCOMPLETEDEV *PFNPDMBLKCACHEXFERCOMPLETEDEV; + +/** + * I/O enqueue callback for devices. + * + * @param pDevIns The device instance. + * @param enmXferDir Transfer direction. + * @param off Transfer offset. + * @param cbXfer Transfer size. + * @param pSgBuf Scather / gather buffer for the transfer. + * @param hIoXfer I/O transfer handle to ping on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDEV,(PPDMDEVINS pDevIns, PDMBLKCACHEXFERDIR enmXferDir, uint64_t off, + size_t cbXfer, PCRTSGBUF pSgBuf, PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDEV(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDEV *PFNPDMBLKCACHEXFERENQUEUEDEV; + +/** + * Discard enqueue callback for devices. + * + * @param pDevIns The device instance. + * @param paRanges Ranges to discard. + * @param cRanges Number of range entries. + * @param hIoXfer I/O handle to return on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDISCARDDEV,(PPDMDEVINS pDevIns, PCRTRANGE paRanges, unsigned cRanges, + PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDISCARDDEV(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDISCARDDEV *PFNPDMBLKCACHEXFERENQUEUEDISCARDDEV; + +/** + * Completion callback for drivers. + * + * @param pvUserInt User argument given to PDMR3BlkCacheRetainInt. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMBLKCACHEXFERCOMPLETEINT,(void *pvUserInt, void *pvUser, int rc)); +/** Pointer to a FNPDMBLKCACHEXFERCOMPLETEINT(). */ +typedef FNPDMBLKCACHEXFERCOMPLETEINT *PFNPDMBLKCACHEXFERCOMPLETEINT; + +/** + * I/O enqueue callback for internal users. + * + * @param pvUser User data. + * @param enmXferDir Transfer direction. + * @param off Transfer offset. + * @param cbXfer Transfer size. + * @param pSgBuf Scather / gather buffer for the transfer. + * @param hIoXfer I/O transfer handle to ping on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEINT,(void *pvUser, PDMBLKCACHEXFERDIR enmXferDir, uint64_t off, + size_t cbXfer, PCRTSGBUF pSgBuf, PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEINT(). */ +typedef FNPDMBLKCACHEXFERENQUEUEINT *PFNPDMBLKCACHEXFERENQUEUEINT; + +/** + * Discard enqueue callback for VMM internal users. + * + * @param pvUser User data. + * @param paRanges Ranges to discard. + * @param cRanges Number of range entries. + * @param hIoXfer I/O handle to return on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDISCARDINT,(void *pvUser, PCRTRANGE paRanges, unsigned cRanges, + PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDISCARDINT(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDISCARDINT *PFNPDMBLKCACHEXFERENQUEUEDISCARDINT; + +/** + * Completion callback for USB devices. + * + * @param pUsbIns The USB device instance. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMBLKCACHEXFERCOMPLETEUSB,(PPDMUSBINS pUsbIns, void *pvUser, int rc)); +/** Pointer to a FNPDMBLKCACHEXFERCOMPLETEUSB(). */ +typedef FNPDMBLKCACHEXFERCOMPLETEUSB *PFNPDMBLKCACHEXFERCOMPLETEUSB; + +/** + * I/O enqueue callback for USB devices. + * + * @param pUsbIns The USB device instance. + * @param enmXferDir Transfer direction. + * @param off Transfer offset. + * @param cbXfer Transfer size. + * @param pSgBuf Scather / gather buffer for the transfer. + * @param hIoXfer I/O transfer handle to ping on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEUSB,(PPDMUSBINS pUsbIns, PDMBLKCACHEXFERDIR enmXferDir, uint64_t off, + size_t cbXfer, PCRTSGBUF pSgBuf, PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEUSB(). */ +typedef FNPDMBLKCACHEXFERENQUEUEUSB *PFNPDMBLKCACHEXFERENQUEUEUSB; + +/** + * Discard enqueue callback for USB devices. + * + * @param pUsbIns The USB device instance. + * @param paRanges Ranges to discard. + * @param cRanges Number of range entries. + * @param hIoXfer I/O handle to return on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDISCARDUSB,(PPDMUSBINS pUsbIns, PCRTRANGE paRanges, unsigned cRanges, + PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDISCARDUSB(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDISCARDUSB *PFNPDMBLKCACHEXFERENQUEUEDISCARDUSB; + +/** + * Create a block cache user for a driver instance. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pDrvIns The driver instance. + * @param ppBlkCache Where to store the handle to the block cache. + * @param pfnXferComplete The I/O transfer complete callback. + * @param pfnXferEnqueue The I/O request enqueue callback. + * @param pfnXferEnqueueDiscard The discard request enqueue callback. + * @param pcszId Unique ID used to identify the user. + */ +VMMR3DECL(int) PDMR3BlkCacheRetainDriver(PVM pVM, PPDMDRVINS pDrvIns, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEDRV pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEDRV pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV pfnXferEnqueueDiscard, + const char *pcszId); + +/** + * Create a block cache user for a device instance. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pDevIns The device instance. + * @param ppBlkCache Where to store the handle to the block cache. + * @param pfnXferComplete The I/O transfer complete callback. + * @param pfnXferEnqueue The I/O request enqueue callback. + * @param pfnXferEnqueueDiscard The discard request enqueue callback. + * @param pcszId Unique ID used to identify the user. + */ +VMMR3DECL(int) PDMR3BlkCacheRetainDevice(PVM pVM, PPDMDEVINS pDevIns, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEDEV pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEDEV pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDDEV pfnXferEnqueueDiscard, + const char *pcszId); + +/** + * Create a block cache user for a USB instance. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pUsbIns The USB device instance. + * @param ppBlkCache Where to store the handle to the block cache. + * @param pfnXferComplete The I/O transfer complete callback. + * @param pfnXferEnqueue The I/O request enqueue callback. + * @param pfnXferEnqueueDiscard The discard request enqueue callback. + * @param pcszId Unique ID used to identify the user. + */ +VMMR3DECL(int) PDMR3BlkCacheRetainUsb(PVM pVM, PPDMUSBINS pUsbIns, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEUSB pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEUSB pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDUSB pfnXferEnqueueDiscard, + const char *pcszId); + +/** + * Create a block cache user for internal use by VMM. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pvUser Opaque user data. + * @param ppBlkCache Where to store the handle to the block cache. + * @param pfnXferComplete The I/O transfer complete callback. + * @param pfnXferEnqueue The I/O request enqueue callback. + * @param pfnXferEnqueueDiscard The discard request enqueue callback. + * @param pcszId Unique ID used to identify the user. + */ +VMMR3DECL(int) PDMR3BlkCacheRetainInt(PVM pVM, void *pvUser, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEINT pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEINT pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDINT pfnXferEnqueueDiscard, + const char *pcszId); + +/** + * Releases a block cache handle. + * + * @returns nothing. + * @param pBlkCache Block cache handle. + */ +VMMR3DECL(void) PDMR3BlkCacheRelease(PPDMBLKCACHE pBlkCache); + +/** + * Releases all block cache handles for a device instance. + * + * @returns nothing. + * @param pVM The cross context VM structure. + * @param pDevIns The device instance. + */ +VMMR3DECL(void) PDMR3BlkCacheReleaseDevice(PVM pVM, PPDMDEVINS pDevIns); + +/** + * Releases all block cache handles for a driver instance. + * + * @returns nothing. + * @param pVM The cross context VM structure. + * @param pDrvIns The driver instance. + */ +VMMR3DECL(void) PDMR3BlkCacheReleaseDriver(PVM pVM, PPDMDRVINS pDrvIns); + +/** + * Releases all block cache handles for a USB device instance. + * + * @returns nothing. + * @param pVM The cross context VM structure. + * @param pUsbIns The USB device instance. + */ +VMMR3DECL(void) PDMR3BlkCacheReleaseUsb(PVM pVM, PPDMUSBINS pUsbIns); + +/** + * Creates a read task on the given endpoint. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + * @param off Where to start reading from. + * @param pSgBuf Scatter gather buffer store the data in. + * @param cbRead The overall number of bytes to read. + * @param pvUser Opaque user data returned in the completion callback + * upon completion of the read. + */ +VMMR3DECL(int) PDMR3BlkCacheRead(PPDMBLKCACHE pBlkCache, uint64_t off, PCRTSGBUF pSgBuf, size_t cbRead, void *pvUser); + +/** + * Creates a write task on the given endpoint. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + * @param off Where to start writing at. + * @param pSgBuf Scatter gather buffer gather the data from. + * @param cbWrite The overall number of bytes to write. + * @param pvUser Opaque user data returned in the completion callback + * upon completion of the task. + */ +VMMR3DECL(int) PDMR3BlkCacheWrite(PPDMBLKCACHE pBlkCache, uint64_t off, PCRTSGBUF pSgBuf, size_t cbWrite, void *pvUser); + +/** + * Creates a flush task on the given endpoint. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + * @param pvUser Opaque user data returned in the completion callback + * upon completion of the task. + */ +VMMR3DECL(int) PDMR3BlkCacheFlush(PPDMBLKCACHE pBlkCache, void *pvUser); + +/** + * Discards the given ranges from the cache. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + * @param paRanges Array of ranges to discard. + * @param cRanges Number of ranges in the array. + * @param pvUser Opaque user data returned in the completion callback + * upon completion of the task. + */ +VMMR3DECL(int) PDMR3BlkCacheDiscard(PPDMBLKCACHE pBlkCache, PCRTRANGE paRanges, unsigned cRanges, void *pvUser); + +/** + * Notify the cache of a complete I/O transfer. + * + * @returns nothing. + * @param pBlkCache The cache instance. + * @param hIoXfer The I/O transfer handle which completed. + * @param rcIoXfer The status code of the completed request. + */ +VMMR3DECL(void) PDMR3BlkCacheIoXferComplete(PPDMBLKCACHE pBlkCache, PPDMBLKCACHEIOXFER hIoXfer, int rcIoXfer); + +/** + * Suspends the block cache. + * + * The cache waits until all I/O transfers completed and stops to enqueue new + * requests after the call returned but will not accept reads, write or flushes + * either. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + */ +VMMR3DECL(int) PDMR3BlkCacheSuspend(PPDMBLKCACHE pBlkCache); + +/** + * Resumes operation of the block cache. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + */ +VMMR3DECL(int) PDMR3BlkCacheResume(PPDMBLKCACHE pBlkCache); + +/** + * Clears the block cache and removes all entries. + * + * The cache waits until all I/O transfers completed. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + */ +VMMR3DECL(int) PDMR3BlkCacheClear(PPDMBLKCACHE pBlkCache); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmblkcache_h */ + diff --git a/include/VBox/vmm/pdmcardreaderinfs.h b/include/VBox/vmm/pdmcardreaderinfs.h new file mode 100644 index 00000000..c0949c9d --- /dev/null +++ b/include/VBox/vmm/pdmcardreaderinfs.h @@ -0,0 +1,136 @@ +/* $Id: pdmcardreaderinfs.h $ */ +/** @file + * cardreaderinfs - interface between USB Card Reader device and its driver. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmcardreaderinfs_h +#define VBOX_INCLUDED_vmm_pdmcardreaderinfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + + +/** @defgroup grp_pdm_ifs_cardreader PDM USB Card Reader Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + + +typedef struct PDMICARDREADER_IO_REQUEST +{ + uint32_t u32Protocol; /**< Protocol identifier */ + uint32_t cbPciLength; /**< Protocol Control Information Length */ + /* 'cbPciLength - 8' bytes of control info may follow. */ +} PDMICARDREADER_IO_REQUEST; + +typedef struct PDMICARDREADER_READERSTATE +{ + char *pszReaderName; + uint32_t u32CurrentState; /**< Current state of reader at time of call. */ + uint32_t u32EventState; /**< State of reader after state change */ + uint32_t cbAtr; /**< Number of bytes in the returned ATR. */ + uint8_t au8Atr[36]; /**< Atr of inserted card, (extra alignment bytes) */ +} PDMICARDREADER_READERSTATE; + + +#define PDMICARDREADERDOWN_IID "78d65378-889c-4418-8bc2-7a89a5af2817" +typedef struct PDMICARDREADERDOWN PDMICARDREADERDOWN; +typedef PDMICARDREADERDOWN *PPDMICARDREADERDOWN; +struct PDMICARDREADERDOWN +{ + DECLR3CALLBACKMEMBER(int, pfnEstablishContext,(PPDMICARDREADERDOWN pInterface)); + DECLR3CALLBACKMEMBER(int, pfnConnect,(PPDMICARDREADERDOWN pInterface, void *pvUser, const char *pszCardReaderName, + uint32_t u32ShareMode, uint32_t u32PreferredProtocols)); + DECLR3CALLBACKMEMBER(int, pfnDisconnect,(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t u32Disposition)); + DECLR3CALLBACKMEMBER(int, pfnStatus,(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t cchReaderName, uint32_t cbAtrLen)); + DECLR3CALLBACKMEMBER(int, pfnReleaseContext,(PPDMICARDREADERDOWN pInterface, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnGetStatusChange,(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t u32Timeout, + PDMICARDREADER_READERSTATE *paReaderStats, uint32_t cReaderStats)); + DECLR3CALLBACKMEMBER(int, pfnBeginTransaction,(PPDMICARDREADERDOWN pInterface, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnEndTransaction,(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t u32Disposition)); + DECLR3CALLBACKMEMBER(int, pfnTransmit,(PPDMICARDREADERDOWN pInterface, void *pvUser, + const PDMICARDREADER_IO_REQUEST *pioSendRequest, + const uint8_t *pu8SendBuffer, uint32_t cbSendBuffer, uint32_t cbRecvBuffer)); + /** + * Up level provides pvInBuffer of cbInBuffer bytes to call SCardControl, also it specify bytes it expects to receive + * @note Device/driver implementation should copy buffers before execution in + * async mode, and both layers shouldn't expect permanent storage for the + * buffer. + */ + DECLR3CALLBACKMEMBER(int, pfnControl,(PPDMICARDREADERDOWN pInterface, void *pvUser, + uint32_t u32ControlCode, const void *pvInBuffer, + uint32_t cbInBuffer, uint32_t cbOutBuffer)); + /** + * This function ask driver to provide attribute (dwAttribId) and provide limit (cbAttrib) of buffer size for attribute value, + * Callback UpGetAttrib returns buffer containing the value and altered size of the buffer. + */ + DECLR3CALLBACKMEMBER(int, pfnGetAttr,(PPDMICARDREADERDOWN pInterface, void *pvUser, + uint32_t u32AttribId, uint32_t cbAttrib)); + DECLR3CALLBACKMEMBER(int, pfnSetAttr,(PPDMICARDREADERDOWN pInterface, void *pvUser, + uint32_t u32AttribId, const void *pvAttrib, uint32_t cbAttrib)); +}; + +#define PDMICARDREADERUP_IID "c0d7498e-0635-48ca-aab1-b11b6a55cf7d" +typedef struct PDMICARDREADERUP PDMICARDREADERUP; +typedef PDMICARDREADERUP *PPDMICARDREADERUP; +struct PDMICARDREADERUP +{ + DECLR3CALLBACKMEMBER(int, pfnEstablishContext,(PPDMICARDREADERUP pInterface, int32_t lSCardRc)); + DECLR3CALLBACKMEMBER(int, pfnStatus,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + char *pszReaderName, uint32_t cchReaderName, uint32_t u32CardState, + uint32_t u32Protocol, uint8_t *pu8Atr, uint32_t cbAtr)); + DECLR3CALLBACKMEMBER(int, pfnConnect,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + uint32_t u32ActiveProtocol)); + DECLR3CALLBACKMEMBER(int, pfnDisconnect,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc)); + DECLR3CALLBACKMEMBER(int, pfnSetStatusChange,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + PDMICARDREADER_READERSTATE *paReaderStats, uint32_t cReaderStats)); + DECLR3CALLBACKMEMBER(int, pfnBeginTransaction,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc)); + DECLR3CALLBACKMEMBER(int, pfnEndTransaction,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc)); + /* Note: pioRecvPci stack variable */ + DECLR3CALLBACKMEMBER(int, pfnTransmit,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + const PDMICARDREADER_IO_REQUEST *pioRecvPci, + uint8_t *pu8RecvBuffer, uint32_t cbRecvBuffer)); + DECLR3CALLBACKMEMBER(int, pfnControl,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + uint32_t u32ControlCode, void *pvOutBuffer, uint32_t cbOutBuffer)); + DECLR3CALLBACKMEMBER(int, pfnGetAttrib,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + uint32_t u32AttribId, void *pvAttrib, uint32_t cbAttrib)); + DECLR3CALLBACKMEMBER(int, pfnSetAttrib,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, uint32_t u32AttribId)); +}; + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmcardreaderinfs_h */ + diff --git a/include/VBox/vmm/pdmcommon.h b/include/VBox/vmm/pdmcommon.h new file mode 100644 index 00000000..7257ff0b --- /dev/null +++ b/include/VBox/vmm/pdmcommon.h @@ -0,0 +1,192 @@ +/** @file + * PDM - Pluggable Device Manager, Common Definitions & Types. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmcommon_h +#define VBOX_INCLUDED_vmm_pdmcommon_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + + +/** @defgroup grp_pdm_common Common Definitions & Types + * @ingroup grp_pdm + * + * Not all the types here are "common", they are here to work around header + * ordering issues. + * + * @{ + */ + +/** Makes a PDM structure version out of an unique magic value and major & + * minor version numbers. + * + * @returns 32-bit structure version number. + * + * @param uMagic 16-bit magic value. This must be unique. + * @param uMajor 12-bit major version number. Structures with different + * major numbers are not compatible. + * @param uMinor 4-bit minor version number. When only the minor version + * differs, the structures will be 100% backwards + * compatible. + */ +#define PDM_VERSION_MAKE(uMagic, uMajor, uMinor) \ + ( ((uint32_t)(uMagic) << 16) | ((uint32_t)((uMajor) & 0xff) << 4) | ((uint32_t)((uMinor) & 0xf) << 0) ) + +/** + * Version of PDM_VERSION_MAKE that's compatible with the preprocessor. + * + * @returns 32-bit structure version number. + * + * @param uMagic 16-bit magic value, no suffix. This must be unique. + * @param uMajor 12-bit major version number, no suffix. Structures with + * different major numbers are not compatible. + * @param uMinor 4-bit minor version number, no suffix. When only the + * minor version differs, the structures will be 100% + * backwards compatible. + */ +#define PDM_VERSION_MAKE_PP(uMagic, uMajor, uMinor) \ + ( (UINT32_C(uMagic) << 16) | ((UINT32_C(uMajor) & UINT32_C(0xff)) << 4) | ((UINT32_C(uMinor) & UINT32_C(0xf)) << 0) ) + +/** Checks if @a uVerMagic1 is compatible with @a uVerMagic2. + * + * @returns true / false. + * @param uVerMagic1 Typically the runtime version of the struct. This must + * have the same magic and major version as @a uVerMagic2 + * and the minor version must be greater or equal to that + * of @a uVerMagic2. + * @param uVerMagic2 Typically the version the code was compiled against. + * + * @remarks The parameters will be referenced more than once. + */ +#define PDM_VERSION_ARE_COMPATIBLE(uVerMagic1, uVerMagic2) \ + ( (uVerMagic1) == (uVerMagic2) \ + || ( (uVerMagic1) >= (uVerMagic2) \ + && ((uVerMagic1) & UINT32_C(0xfffffff0)) == ((uVerMagic2) & UINT32_C(0xfffffff0)) ) \ + ) + + +/** @name PDM Attach/Detach Callback Flags. + * Used by PDMDeviceAttach, PDMDeviceDetach, PDMDriverAttach, PDMDriverDetach, + * FNPDMDEVATTACH, FNPDMDEVDETACH, FNPDMDRVATTACH, FNPDMDRVDETACH and + * FNPDMDRVCONSTRUCT. + * @{ */ +/** The attach/detach command is not a hotplug event. */ +#define PDM_TACH_FLAGS_NOT_HOT_PLUG RT_BIT_32(0) +/** Indicates that no attach or detach callbacks should be made. + * This is mostly for internal use. */ +#define PDM_TACH_FLAGS_NO_CALLBACKS RT_BIT_32(1) +/** @} */ + + +/** + * Is asynchronous handling of suspend or power off notification completed? + * + * This is called to check whether the USB device has quiesced. Don't deadlock. + * Avoid blocking. Do NOT wait for anything. + * + * @returns true if done, false if more work to be done. + * + * @param pUsbIns The USB device instance. + * + * @thread EMT(0) + */ +typedef DECLCALLBACKTYPE(bool, FNPDMUSBASYNCNOTIFY,(PPDMUSBINS pUsbIns)); +/** Pointer to a FNPDMUSBASYNCNOTIFY. */ +typedef FNPDMUSBASYNCNOTIFY *PFNPDMUSBASYNCNOTIFY; + +/** + * Is asynchronous handling of suspend or power off notification completed? + * + * This is called to check whether the device has quiesced. Don't deadlock. + * Avoid blocking. Do NOT wait for anything. + * + * @returns true if done, false if more work to be done. + * + * @param pDevIns The device instance. + * @remarks The caller will enter the device critical section. + * @thread EMT(0) + */ +typedef DECLCALLBACKTYPE(bool, FNPDMDEVASYNCNOTIFY,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVASYNCNOTIFY. */ +typedef FNPDMDEVASYNCNOTIFY *PFNPDMDEVASYNCNOTIFY; + +/** + * Is asynchronous handling of suspend or power off notification completed? + * + * This is called to check whether the driver has quiesced. Don't deadlock. + * Avoid blocking. Do NOT wait for anything. + * + * @returns true if done, false if more work to be done. + * + * @param pDrvIns The driver instance. + * + * @thread EMT(0) + */ +typedef DECLCALLBACKTYPE(bool, FNPDMDRVASYNCNOTIFY,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVASYNCNOTIFY. */ +typedef FNPDMDRVASYNCNOTIFY *PFNPDMDRVASYNCNOTIFY; + + +/** + * The ring-0 driver request handler. + * + * @returns VBox status code. PDMDevHlpCallR0 will return this. + * @param pDevIns The device instance (the ring-0 mapping). + * @param uOperation The operation. + * @param u64Arg Optional integer argument for the operation. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDEVREQHANDLERR0,(PPDMDEVINS pDevIns, uint32_t uOperation, uint64_t u64Arg)); +/** Ring-0 pointer to a FNPDMDEVREQHANDLERR0. */ +typedef R0PTRTYPE(FNPDMDEVREQHANDLERR0 *) PFNPDMDEVREQHANDLERR0; + +/** + * The ring-0 driver request handler. + * + * @returns VBox status code. PDMDrvHlpCallR0 will return this. + * @param pDrvIns The driver instance (the ring-0 mapping). + * @param uOperation The operation. + * @param u64Arg Optional integer argument for the operation. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDRVREQHANDLERR0,(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg)); +/** Ring-0 pointer to a FNPDMDRVREQHANDLERR0. */ +typedef R0PTRTYPE(FNPDMDRVREQHANDLERR0 *) PFNPDMDRVREQHANDLERR0; + + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmcommon_h */ + diff --git a/include/VBox/vmm/pdmcritsect.h b/include/VBox/vmm/pdmcritsect.h new file mode 100644 index 00000000..79445ecb --- /dev/null +++ b/include/VBox/vmm/pdmcritsect.h @@ -0,0 +1,143 @@ +/** @file + * PDM - Pluggable Device Manager, Critical Sections. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmcritsect_h +#define VBOX_INCLUDED_vmm_pdmcritsect_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/critsect.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_critsect The PDM Critical Section API + * @ingroup grp_pdm + * @{ + */ + +/** + * A PDM critical section. + * Initialize using PDMDRVHLP::pfnCritSectInit(). + */ +typedef union PDMCRITSECT +{ + /** Padding. */ + uint8_t padding[HC_ARCH_BITS == 32 ? 0xc0 : 0x100]; +#ifdef PDMCRITSECTINT_DECLARED + /** The internal structure (not normally visible). */ + struct PDMCRITSECTINT s; +#endif +} PDMCRITSECT; + +VMMR3_INT_DECL(int) PDMR3CritSectBothTerm(PVM pVM); +VMMR3_INT_DECL(void) PDMR3CritSectLeaveAll(PVM pVM); +VMM_INT_DECL(void) PDMCritSectBothFF(PVMCC pVM, PVMCPUCC pVCpu); + + +VMMR3DECL(uint32_t) PDMR3CritSectCountOwned(PVM pVM, char *pszNames, size_t cbNames); + +VMMR3DECL(int) PDMR3CritSectInit(PVM pVM, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(6, 7); +VMMR3DECL(int) PDMR3CritSectEnterEx(PVM pVM, PPDMCRITSECT pCritSect, bool fCallRing3); +VMMR3DECL(bool) PDMR3CritSectYield(PVM pVM, PPDMCRITSECT pCritSect); +VMMR3DECL(const char *) PDMR3CritSectName(PCPDMCRITSECT pCritSect); +VMMR3DECL(int) PDMR3CritSectDelete(PVM pVM, PPDMCRITSECT pCritSect); +#if defined(IN_RING0) || defined(IN_RING3) +VMMDECL(int) PDMHCCritSectScheduleExitEvent(PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal); +#endif + +VMMDECL(DECL_CHECK_RETURN_NOT_R3(int)) + PDMCritSectEnter(PVMCC pVM, PPDMCRITSECT pCritSect, int rcBusy); +VMMDECL(DECL_CHECK_RETURN_NOT_R3(int)) + PDMCritSectEnterDebug(PVMCC pVM, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(DECL_CHECK_RETURN(int)) + PDMCritSectTryEnter(PVMCC pVM, PPDMCRITSECT pCritSect); +VMMDECL(DECL_CHECK_RETURN(int)) + PDMCritSectTryEnterDebug(PVMCC pVM, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(int) PDMCritSectLeave(PVMCC pVM, PPDMCRITSECT pCritSect); + +VMMDECL(bool) PDMCritSectIsOwner(PVMCC pVM, PCPDMCRITSECT pCritSect); +VMMDECL(bool) PDMCritSectIsOwnerEx(PVMCPUCC pVCpu, PCPDMCRITSECT pCritSect); +VMMDECL(bool) PDMCritSectIsInitialized(PCPDMCRITSECT pCritSect); +VMMDECL(bool) PDMCritSectHasWaiters(PVMCC pVM, PCPDMCRITSECT pCritSect); +VMMDECL(uint32_t) PDMCritSectGetRecursion(PCPDMCRITSECT pCritSect); + +VMMR3DECL(PPDMCRITSECT) PDMR3CritSectGetNop(PVM pVM); + +/* Strict build: Remap the two enter calls to the debug versions. */ +#ifdef VBOX_STRICT +# ifdef IPRT_INCLUDED_asm_h +# define PDMCritSectEnter(a_pVM, pCritSect, rcBusy) PDMCritSectEnterDebug((a_pVM), (pCritSect), (rcBusy), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMCritSectTryEnter(a_pVM, pCritSect) PDMCritSectTryEnterDebug((a_pVM), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define PDMCritSectEnter(a_pVM, pCritSect, rcBusy) PDMCritSectEnterDebug((a_pVM), (pCritSect), (rcBusy), 0, RT_SRC_POS) +# define PDMCritSectTryEnter(a_pVM, pCritSect) PDMCritSectTryEnterDebug((a_pVM), (pCritSect), 0, RT_SRC_POS) +# endif +#endif + +/** @def PDM_CRITSECT_RELEASE_ASSERT_RC + * Helper for PDMCritSectEnter w/ rcBusy VINF_SUCCESS when there is no way + * to forward failures to the caller. */ +#define PDM_CRITSECT_RELEASE_ASSERT_RC(a_pVM, a_pCritSect, a_rc) \ + AssertReleaseMsg(RT_SUCCESS(a_rc), ("pVM=%p pCritSect=%p: %Rrc\n", (a_pVM), (a_pCritSect), (a_rc))) + +/** @def PDM_CRITSECT_RELEASE_ASSERT_RC_DEV + * Helper for PDMCritSectEnter w/ rcBusy VINF_SUCCESS when there is no way + * to forward failures to the caller, device edition. */ +#define PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(a_pDevIns, a_pCritSect, a_rc) \ + AssertReleaseMsg(RT_SUCCESS(a_rc), ("pDevIns=%p pCritSect=%p: %Rrc\n", (a_pDevIns), (a_pCritSect), (a_rc))) + +/** @def PDM_CRITSECT_RELEASE_ASSERT_RC_DRV + * Helper for PDMCritSectEnter w/ rcBusy VINF_SUCCESS when there is no way + * to forward failures to the caller, driver edition. */ +#define PDM_CRITSECT_RELEASE_ASSERT_RC_DRV(a_pDrvIns, a_pCritSect, a_rc) \ + AssertReleaseMsg(RT_SUCCESS(a_rc), ("pDrvIns=%p pCritSect=%p: %Rrc\n", (a_pDrvIns), (a_pCritSect), (a_rc))) + +/** @def PDM_CRITSECT_RELEASE_ASSERT_RC_USB + * Helper for PDMCritSectEnter w/ rcBusy VINF_SUCCESS when there is no way + * to forward failures to the caller, USB device edition. */ +#define PDM_CRITSECT_RELEASE_ASSERT_RC_USB(a_pUsbIns, a_pCritSect, a_rc) \ + AssertReleaseMsg(RT_SUCCESS(a_rc), ("pUsbIns=%p pCritSect=%p: %Rrc\n", (a_pUsbIns), (a_pCritSect), (a_rc))) + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmcritsect_h */ + diff --git a/include/VBox/vmm/pdmcritsectrw.h b/include/VBox/vmm/pdmcritsectrw.h new file mode 100644 index 00000000..8b3eb319 --- /dev/null +++ b/include/VBox/vmm/pdmcritsectrw.h @@ -0,0 +1,111 @@ +/** @file + * PDM - Pluggable Device Manager, Read/Write Critical Section. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmcritsectrw_h +#define VBOX_INCLUDED_vmm_pdmcritsectrw_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_critsectrw The PDM Read/Write Critical Section API + * @ingroup grp_pdm + * @{ + */ + +/** + * A PDM read/write critical section. + * Initialize using PDMDRVHLP::pfnCritSectRwInit(). + */ +typedef union PDMCRITSECTRW +{ + /** Padding. */ + uint8_t padding[HC_ARCH_BITS == 32 ? 0xc0 : 0x100]; +#ifdef PDMCRITSECTRWINT_DECLARED + /** The internal structure (not normally visible). */ + struct PDMCRITSECTRWINT s; +#endif +} PDMCRITSECTRW; + +VMMR3DECL(int) PDMR3CritSectRwInit(PVM pVM, PPDMCRITSECTRW pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(6, 7); +VMMR3DECL(int) PDMR3CritSectRwDelete(PVM pVM, PPDMCRITSECTRW pCritSect); +VMMR3DECL(const char *) PDMR3CritSectRwName(PCPDMCRITSECTRW pCritSect); +VMMR3DECL(int) PDMR3CritSectRwEnterSharedEx(PVM pVM, PPDMCRITSECTRW pThis, bool fCallRing3); +VMMR3DECL(int) PDMR3CritSectRwEnterExclEx(PVM pVM, PPDMCRITSECTRW pThis, bool fCallRing3); + +VMMDECL(int) PDMCritSectRwEnterShared(PVMCC pVM, PPDMCRITSECTRW pCritSect, int rcBusy); +VMMDECL(int) PDMCritSectRwEnterSharedDebug(PVMCC pVM, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(int) PDMCritSectRwTryEnterShared(PVMCC pVM, PPDMCRITSECTRW pCritSect); +VMMDECL(int) PDMCritSectRwTryEnterSharedDebug(PVMCC pVM, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(int) PDMCritSectRwLeaveShared(PVMCC pVM, PPDMCRITSECTRW pCritSect); +VMMDECL(int) PDMCritSectRwEnterExcl(PVMCC pVM, PPDMCRITSECTRW pCritSect, int rcBusy); +VMMDECL(int) PDMCritSectRwEnterExclDebug(PVMCC pVM, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(int) PDMCritSectRwTryEnterExcl(PVMCC pVM, PPDMCRITSECTRW pCritSect); +VMMDECL(int) PDMCritSectRwTryEnterExclDebug(PVMCC pVM, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(int) PDMCritSectRwLeaveExcl(PVMCC pVM, PPDMCRITSECTRW pCritSect); + +VMMDECL(bool) PDMCritSectRwIsWriteOwner(PVMCC pVM, PPDMCRITSECTRW pCritSect); +VMMDECL(bool) PDMCritSectRwIsReadOwner(PVMCC pVM, PPDMCRITSECTRW pCritSect, bool fWannaHear); +VMMDECL(uint32_t) PDMCritSectRwGetWriteRecursion(PPDMCRITSECTRW pCritSect); +VMMDECL(uint32_t) PDMCritSectRwGetWriterReadRecursion(PPDMCRITSECTRW pCritSect); +VMMDECL(uint32_t) PDMCritSectRwGetReadCount(PPDMCRITSECTRW pCritSect); +VMMDECL(bool) PDMCritSectRwIsInitialized(PCPDMCRITSECTRW pCritSect); + +/* Lock strict build: Remap the three enter calls to the debug versions. */ +#ifdef VBOX_STRICT +# ifdef IPRT_INCLUDED_asm_h +# define PDMCritSectRwEnterExcl(a_pVM, pCritSect, rcBusy) PDMCritSectRwEnterExclDebug((a_pVM), pCritSect, rcBusy, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMCritSectRwTryEnterExcl(a_pVM, pCritSect) PDMCritSectRwTryEnterExclDebug((a_pVM), pCritSect, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMCritSectRwEnterShared(a_pVM, pCritSect, rcBusy) PDMCritSectRwEnterSharedDebug((a_pVM), pCritSect, rcBusy, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMCritSectRwTryEnterShared(a_pVM, pCritSect) PDMCritSectRwTryEnterSharedDebug((a_pVM), pCritSect, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define PDMCritSectRwEnterExcl(a_pVM, pCritSect, rcBusy) PDMCritSectRwEnterExclDebug((a_pVM), pCritSect, rcBusy, 0, RT_SRC_POS) +# define PDMCritSectRwTryEnterExcl(a_pVM, pCritSect) PDMCritSectRwTryEnterExclDebug((a_pVM), pCritSect, 0, RT_SRC_POS) +# define PDMCritSectRwEnterShared(a_pVM, pCritSect, rcBusy) PDMCritSectRwEnterSharedDebug((a_pVM), pCritSect, rcBusy, 0, RT_SRC_POS) +# define PDMCritSectRwTryEnterShared(a_pVM, pCritSect) PDMCritSectRwTryEnterSharedDebug((a_pVM), pCritSect, 0, RT_SRC_POS) +# endif +#endif + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmcritsectrw_h */ + diff --git a/include/VBox/vmm/pdmdev.h b/include/VBox/vmm/pdmdev.h new file mode 100644 index 00000000..fd92fef8 --- /dev/null +++ b/include/VBox/vmm/pdmdev.h @@ -0,0 +1,9690 @@ +/** @file + * PDM - Pluggable Device Manager, Devices. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmdev_h +#define VBOX_INCLUDED_vmm_pdmdev_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/pdmcritsect.h> +#include <VBox/vmm/pdmcritsectrw.h> +#include <VBox/vmm/pdmqueue.h> +#include <VBox/vmm/pdmtask.h> +#ifdef IN_RING3 +# include <VBox/vmm/pdmthread.h> +#endif +#include <VBox/vmm/pdmifs.h> +#include <VBox/vmm/pdmins.h> +#include <VBox/vmm/pdmcommon.h> +#include <VBox/vmm/pdmpcidev.h> +#include <VBox/vmm/iom.h> +#include <VBox/vmm/mm.h> +#include <VBox/vmm/tm.h> +#include <VBox/vmm/ssm.h> +#include <VBox/vmm/cfgm.h> +#include <VBox/vmm/cpum.h> +#include <VBox/vmm/dbgf.h> +#include <VBox/vmm/pgm.h> /* PGMR3HandlerPhysicalTypeRegister() argument types. */ +#include <VBox/vmm/gim.h> +#include <VBox/err.h> /* VINF_EM_DBG_STOP, also 120+ source files expecting this. */ +#include <VBox/msi.h> +#include <iprt/stdarg.h> +#include <iprt/list.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_device The PDM Devices API + * @ingroup grp_pdm + * @{ + */ + +/** + * Construct a device instance for a VM. + * + * @returns VBox status. + * @param pDevIns The device instance data. If the registration structure + * is needed, it can be accessed thru pDevIns->pReg. + * @param iInstance Instance number. Use this to figure out which registers + * and such to use. The instance number is also found in + * pDevIns->iInstance, but since it's likely to be + * frequently used PDM passes it as parameter. + * @param pCfg Configuration node handle for the driver. This is + * expected to be in high demand in the constructor and is + * therefore passed as an argument. When using it at other + * times, it can be found in pDevIns->pCfg. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDEVCONSTRUCT,(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)); +/** Pointer to a FNPDMDEVCONSTRUCT() function. */ +typedef FNPDMDEVCONSTRUCT *PFNPDMDEVCONSTRUCT; + +/** + * Destruct a device instance. + * + * Most VM resources are freed by the VM. This callback is provided so that any non-VM + * resources can be freed correctly. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * + * @remarks The device critical section is not entered. The routine may delete + * the critical section, so the caller cannot exit it. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDEVDESTRUCT,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVDESTRUCT() function. */ +typedef FNPDMDEVDESTRUCT *PFNPDMDEVDESTRUCT; + +/** + * Device relocation callback. + * + * This is called when the instance data has been relocated in raw-mode context + * (RC). It is also called when the RC hypervisor selects changes. The device + * must fixup all necessary pointers and re-query all interfaces to other RC + * devices and drivers. + * + * Before the RC code is executed the first time, this function will be called + * with a 0 delta so RC pointer calculations can be one in one place. + * + * @param pDevIns Pointer to the device instance. + * @param offDelta The relocation delta relative to the old location. + * + * @remarks A relocation CANNOT fail. + * + * @remarks The device critical section is not entered. The relocations should + * not normally require any locking. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVRELOCATE,(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)); +/** Pointer to a FNPDMDEVRELOCATE() function. */ +typedef FNPDMDEVRELOCATE *PFNPDMDEVRELOCATE; + +/** + * Power On notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVPOWERON,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVPOWERON() function. */ +typedef FNPDMDEVPOWERON *PFNPDMDEVPOWERON; + +/** + * Reset notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVRESET,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVRESET() function. */ +typedef FNPDMDEVRESET *PFNPDMDEVRESET; + +/** + * Soft reset notification. + * + * This is mainly for emulating the 286 style protected mode exits, in which + * most devices should remain in their current state. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * @param fFlags PDMVMRESET_F_XXX (only bits relevant to soft resets). + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVSOFTRESET,(PPDMDEVINS pDevIns, uint32_t fFlags)); +/** Pointer to a FNPDMDEVSOFTRESET() function. */ +typedef FNPDMDEVSOFTRESET *PFNPDMDEVSOFTRESET; + +/** @name PDMVMRESET_F_XXX - VM reset flags. + * These flags are used both for FNPDMDEVSOFTRESET and for hardware signalling + * reset via PDMDevHlpVMReset. + * @{ */ +/** Unknown reason. */ +#define PDMVMRESET_F_UNKNOWN UINT32_C(0x00000000) +/** GIM triggered reset. */ +#define PDMVMRESET_F_GIM UINT32_C(0x00000001) +/** The last source always causing hard resets. */ +#define PDMVMRESET_F_LAST_ALWAYS_HARD PDMVMRESET_F_GIM +/** ACPI triggered reset. */ +#define PDMVMRESET_F_ACPI UINT32_C(0x0000000c) +/** PS/2 system port A (92h) reset. */ +#define PDMVMRESET_F_PORT_A UINT32_C(0x0000000d) +/** Keyboard reset. */ +#define PDMVMRESET_F_KBD UINT32_C(0x0000000e) +/** Tripple fault. */ +#define PDMVMRESET_F_TRIPLE_FAULT UINT32_C(0x0000000f) +/** Reset source mask. */ +#define PDMVMRESET_F_SRC_MASK UINT32_C(0x0000000f) +/** @} */ + +/** + * Suspend notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * @thread EMT(0) + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVSUSPEND,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVSUSPEND() function. */ +typedef FNPDMDEVSUSPEND *PFNPDMDEVSUSPEND; + +/** + * Resume notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVRESUME,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVRESUME() function. */ +typedef FNPDMDEVRESUME *PFNPDMDEVRESUME; + +/** + * Power Off notification. + * + * This is always called when VMR3PowerOff is called. + * There will be no callback when hot plugging devices. + * + * @param pDevIns The device instance data. + * @thread EMT(0) + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVPOWEROFF,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVPOWEROFF() function. */ +typedef FNPDMDEVPOWEROFF *PFNPDMDEVPOWEROFF; + +/** + * Attach command. + * + * This is called to let the device attach to a driver for a specified LUN + * at runtime. This is not called during VM construction, the device + * constructor has to attach to all the available drivers. + * + * This is like plugging in the keyboard or mouse after turning on the PC. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iLUN The logical unit which is being attached. + * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDEVATTACH,(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)); +/** Pointer to a FNPDMDEVATTACH() function. */ +typedef FNPDMDEVATTACH *PFNPDMDEVATTACH; + +/** + * Detach notification. + * + * This is called when a driver is detaching itself from a LUN of the device. + * The device should adjust its state to reflect this. + * + * This is like unplugging the network cable to use it for the laptop or + * something while the PC is still running. + * + * @param pDevIns The device instance. + * @param iLUN The logical unit which is being detached. + * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVDETACH,(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)); +/** Pointer to a FNPDMDEVDETACH() function. */ +typedef FNPDMDEVDETACH *PFNPDMDEVDETACH; + +/** + * Query the base interface of a logical unit. + * + * @returns VBOX status code. + * @param pDevIns The device instance. + * @param iLUN The logicial unit to query. + * @param ppBase Where to store the pointer to the base interface of the LUN. + * + * @remarks The device critical section is not entered. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDEVQUERYINTERFACE,(PPDMDEVINS pDevIns, unsigned iLUN, PPDMIBASE *ppBase)); +/** Pointer to a FNPDMDEVQUERYINTERFACE() function. */ +typedef FNPDMDEVQUERYINTERFACE *PFNPDMDEVQUERYINTERFACE; + +/** + * Init complete notification (after ring-0 & RC init since 5.1). + * + * This can be done to do communication with other devices and other + * initialization which requires everything to be in place. + * + * @returns VBOX status code. + * @param pDevIns The device instance. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDEVINITCOMPLETE,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVINITCOMPLETE() function. */ +typedef FNPDMDEVINITCOMPLETE *PFNPDMDEVINITCOMPLETE; + + +/** + * The context of a pfnMemSetup call. + */ +typedef enum PDMDEVMEMSETUPCTX +{ + /** Invalid zero value. */ + PDMDEVMEMSETUPCTX_INVALID = 0, + /** After construction. */ + PDMDEVMEMSETUPCTX_AFTER_CONSTRUCTION, + /** After reset. */ + PDMDEVMEMSETUPCTX_AFTER_RESET, + /** Type size hack. */ + PDMDEVMEMSETUPCTX_32BIT_HACK = 0x7fffffff +} PDMDEVMEMSETUPCTX; + + +/** + * PDM Device Registration Structure. + * + * This structure is used when registering a device from VBoxInitDevices() in HC + * Ring-3. PDM will continue use till the VM is terminated. + * + * @note The first part is the same in every context. + */ +typedef struct PDMDEVREGR3 +{ + /** Structure version. PDM_DEVREGR3_VERSION defines the current version. */ + uint32_t u32Version; + /** Reserved, must be zero. */ + uint32_t uReserved0; + /** Device name, must match the ring-3 one. */ + char szName[32]; + /** Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */ + uint32_t fFlags; + /** Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */ + uint32_t fClass; + /** Maximum number of instances (per VM). */ + uint32_t cMaxInstances; + /** The shared data structure version number. */ + uint32_t uSharedVersion; + /** Size of the instance data. */ + uint32_t cbInstanceShared; + /** Size of the ring-0 instance data. */ + uint32_t cbInstanceCC; + /** Size of the raw-mode instance data. */ + uint32_t cbInstanceRC; + /** Max number of PCI devices. */ + uint16_t cMaxPciDevices; + /** Max number of MSI-X vectors in any of the PCI devices. */ + uint16_t cMaxMsixVectors; + /** The description of the device. The UTF-8 string pointed to shall, like this structure, + * remain unchanged from registration till VM destruction. */ + const char *pszDescription; + + /** Name of the raw-mode context module (no path). + * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */ + const char *pszRCMod; + /** Name of the ring-0 module (no path). + * Only evalutated if PDM_DEVREG_FLAGS_R0 is set. */ + const char *pszR0Mod; + + /** Construct instance - required. */ + PFNPDMDEVCONSTRUCT pfnConstruct; + /** Destruct instance - optional. + * Critical section NOT entered (will be destroyed). */ + PFNPDMDEVDESTRUCT pfnDestruct; + /** Relocation command - optional. + * Critical section NOT entered. */ + PFNPDMDEVRELOCATE pfnRelocate; + /** + * Memory setup callback. + * + * @param pDevIns The device instance data. + * @param enmCtx Indicates the context of the call. + * @remarks The critical section is entered prior to calling this method. + */ + DECLR3CALLBACKMEMBER(void, pfnMemSetup, (PPDMDEVINS pDevIns, PDMDEVMEMSETUPCTX enmCtx)); + /** Power on notification - optional. + * Critical section is entered. */ + PFNPDMDEVPOWERON pfnPowerOn; + /** Reset notification - optional. + * Critical section is entered. */ + PFNPDMDEVRESET pfnReset; + /** Suspend notification - optional. + * Critical section is entered. */ + PFNPDMDEVSUSPEND pfnSuspend; + /** Resume notification - optional. + * Critical section is entered. */ + PFNPDMDEVRESUME pfnResume; + /** Attach command - optional. + * Critical section is entered. */ + PFNPDMDEVATTACH pfnAttach; + /** Detach notification - optional. + * Critical section is entered. */ + PFNPDMDEVDETACH pfnDetach; + /** Query a LUN base interface - optional. + * Critical section is NOT entered. */ + PFNPDMDEVQUERYINTERFACE pfnQueryInterface; + /** Init complete notification - optional. + * Critical section is entered. */ + PFNPDMDEVINITCOMPLETE pfnInitComplete; + /** Power off notification - optional. + * Critical section is entered. */ + PFNPDMDEVPOWEROFF pfnPowerOff; + /** Software system reset notification - optional. + * Critical section is entered. */ + PFNPDMDEVSOFTRESET pfnSoftReset; + + /** @name Reserved for future extensions, must be zero. + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnReserved0, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved1, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved2, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved3, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved4, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved5, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved6, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved7, (PPDMDEVINS pDevIns)); + /** @} */ + + /** Initialization safty marker. */ + uint32_t u32VersionEnd; +} PDMDEVREGR3; +/** Pointer to a PDM Device Structure. */ +typedef PDMDEVREGR3 *PPDMDEVREGR3; +/** Const pointer to a PDM Device Structure. */ +typedef PDMDEVREGR3 const *PCPDMDEVREGR3; +/** Current DEVREGR3 version number. */ +#define PDM_DEVREGR3_VERSION PDM_VERSION_MAKE(0xffff, 4, 0) + + +/** PDM Device Flags. + * @{ */ +/** This flag is used to indicate that the device has a R0 component. */ +#define PDM_DEVREG_FLAGS_R0 UINT32_C(0x00000001) +/** Requires the ring-0 component, ignore configuration values. */ +#define PDM_DEVREG_FLAGS_REQUIRE_R0 UINT32_C(0x00000002) +/** Requires the ring-0 component, ignore configuration values. */ +#define PDM_DEVREG_FLAGS_OPT_IN_R0 UINT32_C(0x00000004) + +/** This flag is used to indicate that the device has a RC component. */ +#define PDM_DEVREG_FLAGS_RC UINT32_C(0x00000010) +/** Requires the raw-mode component, ignore configuration values. */ +#define PDM_DEVREG_FLAGS_REQUIRE_RC UINT32_C(0x00000020) +/** Requires the raw-mode component, ignore configuration values. */ +#define PDM_DEVREG_FLAGS_OPT_IN_RC UINT32_C(0x00000040) + +/** Convenience: PDM_DEVREG_FLAGS_R0 + PDM_DEVREG_FLAGS_RC */ +#define PDM_DEVREG_FLAGS_RZ (PDM_DEVREG_FLAGS_R0 | PDM_DEVREG_FLAGS_RC) + +/** @def PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT + * The bit count for the current host. + * @note Superfluous, but still around for hysterical raisins. */ +#if HC_ARCH_BITS == 32 +# define PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT UINT32_C(0x00000100) +#elif HC_ARCH_BITS == 64 +# define PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT UINT32_C(0x00000200) +#else +# error Unsupported HC_ARCH_BITS value. +#endif +/** The host bit count mask. */ +#define PDM_DEVREG_FLAGS_HOST_BITS_MASK UINT32_C(0x00000300) + +/** The device support only 32-bit guests. */ +#define PDM_DEVREG_FLAGS_GUEST_BITS_32 UINT32_C(0x00001000) +/** The device support only 64-bit guests. */ +#define PDM_DEVREG_FLAGS_GUEST_BITS_64 UINT32_C(0x00002000) +/** The device support both 32-bit & 64-bit guests. */ +#define PDM_DEVREG_FLAGS_GUEST_BITS_32_64 UINT32_C(0x00003000) +/** @def PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT + * The guest bit count for the current compilation. */ +#if GC_ARCH_BITS == 32 +# define PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT PDM_DEVREG_FLAGS_GUEST_BITS_32 +#elif GC_ARCH_BITS == 64 +# define PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT PDM_DEVREG_FLAGS_GUEST_BITS_32_64 +#else +# error Unsupported GC_ARCH_BITS value. +#endif +/** The guest bit count mask. */ +#define PDM_DEVREG_FLAGS_GUEST_BITS_MASK UINT32_C(0x00003000) + +/** A convenience. */ +#define PDM_DEVREG_FLAGS_DEFAULT_BITS (PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT) + +/** Indicates that the device needs to be notified before the drivers when suspending. */ +#define PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION UINT32_C(0x00010000) +/** Indicates that the device needs to be notified before the drivers when powering off. */ +#define PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION UINT32_C(0x00020000) +/** Indicates that the device needs to be notified before the drivers when resetting. */ +#define PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION UINT32_C(0x00040000) + +/** This flag is used to indicate that the device has been converted to the + * new device style. */ +#define PDM_DEVREG_FLAGS_NEW_STYLE UINT32_C(0x80000000) + +/** @} */ + + +/** PDM Device Classes. + * The order is important, lower bit earlier instantiation. + * @{ */ +/** Architecture device. */ +#define PDM_DEVREG_CLASS_ARCH RT_BIT(0) +/** Architecture BIOS device. */ +#define PDM_DEVREG_CLASS_ARCH_BIOS RT_BIT(1) +/** PCI bus brigde. */ +#define PDM_DEVREG_CLASS_BUS_PCI RT_BIT(2) +/** PCI built-in device (e.g. PCI root complex devices). */ +#define PDM_DEVREG_CLASS_PCI_BUILTIN RT_BIT(3) +/** Input device (mouse, keyboard, joystick, HID, ...). */ +#define PDM_DEVREG_CLASS_INPUT RT_BIT(4) +/** Interrupt controller (PIC). */ +#define PDM_DEVREG_CLASS_PIC RT_BIT(5) +/** Interval controoler (PIT). */ +#define PDM_DEVREG_CLASS_PIT RT_BIT(6) +/** RTC/CMOS. */ +#define PDM_DEVREG_CLASS_RTC RT_BIT(7) +/** DMA controller. */ +#define PDM_DEVREG_CLASS_DMA RT_BIT(8) +/** VMM Device. */ +#define PDM_DEVREG_CLASS_VMM_DEV RT_BIT(9) +/** Graphics device, like VGA. */ +#define PDM_DEVREG_CLASS_GRAPHICS RT_BIT(10) +/** Storage controller device. */ +#define PDM_DEVREG_CLASS_STORAGE RT_BIT(11) +/** Network interface controller. */ +#define PDM_DEVREG_CLASS_NETWORK RT_BIT(12) +/** Audio. */ +#define PDM_DEVREG_CLASS_AUDIO RT_BIT(13) +/** USB HIC. */ +#define PDM_DEVREG_CLASS_BUS_USB RT_BIT(14) +/** ACPI. */ +#define PDM_DEVREG_CLASS_ACPI RT_BIT(15) +/** Serial controller device. */ +#define PDM_DEVREG_CLASS_SERIAL RT_BIT(16) +/** Parallel controller device */ +#define PDM_DEVREG_CLASS_PARALLEL RT_BIT(17) +/** Host PCI pass-through device */ +#define PDM_DEVREG_CLASS_HOST_DEV RT_BIT(18) +/** Misc devices (always last). */ +#define PDM_DEVREG_CLASS_MISC RT_BIT(31) +/** @} */ + + +/** + * PDM Device Registration Structure, ring-0. + * + * This structure is used when registering a device from VBoxInitDevices() in HC + * Ring-0. PDM will continue use till the VM is terminated. + */ +typedef struct PDMDEVREGR0 +{ + /** Structure version. PDM_DEVREGR0_VERSION defines the current version. */ + uint32_t u32Version; + /** Reserved, must be zero. */ + uint32_t uReserved0; + /** Device name, must match the ring-3 one. */ + char szName[32]; + /** Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */ + uint32_t fFlags; + /** Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */ + uint32_t fClass; + /** Maximum number of instances (per VM). */ + uint32_t cMaxInstances; + /** The shared data structure version number. */ + uint32_t uSharedVersion; + /** Size of the instance data. */ + uint32_t cbInstanceShared; + /** Size of the ring-0 instance data. */ + uint32_t cbInstanceCC; + /** Size of the raw-mode instance data. */ + uint32_t cbInstanceRC; + /** Max number of PCI devices. */ + uint16_t cMaxPciDevices; + /** Max number of MSI-X vectors in any of the PCI devices. */ + uint16_t cMaxMsixVectors; + /** The description of the device. The UTF-8 string pointed to shall, like this structure, + * remain unchanged from registration till VM destruction. */ + const char *pszDescription; + + /** + * Early construction callback (optional). + * + * This is called right after the device instance structure has been allocated + * and before the ring-3 constructor gets called. + * + * @returns VBox status code. + * @param pDevIns The device instance data. + * @note The destructure is always called, regardless of the return status. + */ + DECLR0CALLBACKMEMBER(int, pfnEarlyConstruct, (PPDMDEVINS pDevIns)); + + /** + * Regular construction callback (optional). + * + * This is called after (or during) the ring-3 constructor. + * + * @returns VBox status code. + * @param pDevIns The device instance data. + * @note The destructure is always called, regardless of the return status. + */ + DECLR0CALLBACKMEMBER(int, pfnConstruct, (PPDMDEVINS pDevIns)); + + /** + * Destructor (optional). + * + * This is called after the ring-3 destruction. This is not called if ring-3 + * fails to trigger it (e.g. process is killed or crashes). + * + * @param pDevIns The device instance data. + */ + DECLR0CALLBACKMEMBER(void, pfnDestruct, (PPDMDEVINS pDevIns)); + + /** + * Final destructor (optional). + * + * This is called right before the memory is freed, which happens when the + * VM/GVM object is destroyed. This is always called. + * + * @param pDevIns The device instance data. + */ + DECLR0CALLBACKMEMBER(void, pfnFinalDestruct, (PPDMDEVINS pDevIns)); + + /** + * Generic request handler (optional). + * + * @param pDevIns The device instance data. + * @param uReq Device specific request. + * @param uArg Request argument. + */ + DECLR0CALLBACKMEMBER(int, pfnRequest, (PPDMDEVINS pDevIns, uint32_t uReq, uint64_t uArg)); + + /** @name Reserved for future extensions, must be zero. + * @{ */ + DECLR0CALLBACKMEMBER(int, pfnReserved0, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved1, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved2, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved3, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved4, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved5, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved6, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved7, (PPDMDEVINS pDevIns)); + /** @} */ + + /** Initialization safty marker. */ + uint32_t u32VersionEnd; +} PDMDEVREGR0; +/** Pointer to a ring-0 PDM device registration structure. */ +typedef PDMDEVREGR0 *PPDMDEVREGR0; +/** Pointer to a const ring-0 PDM device registration structure. */ +typedef PDMDEVREGR0 const *PCPDMDEVREGR0; +/** Current DEVREGR0 version number. */ +#define PDM_DEVREGR0_VERSION PDM_VERSION_MAKE(0xff80, 1, 0) + + +/** + * PDM Device Registration Structure, raw-mode + * + * At the moment, this structure is mostly here to match the other two contexts. + */ +typedef struct PDMDEVREGRC +{ + /** Structure version. PDM_DEVREGRC_VERSION defines the current version. */ + uint32_t u32Version; + /** Reserved, must be zero. */ + uint32_t uReserved0; + /** Device name, must match the ring-3 one. */ + char szName[32]; + /** Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */ + uint32_t fFlags; + /** Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */ + uint32_t fClass; + /** Maximum number of instances (per VM). */ + uint32_t cMaxInstances; + /** The shared data structure version number. */ + uint32_t uSharedVersion; + /** Size of the instance data. */ + uint32_t cbInstanceShared; + /** Size of the ring-0 instance data. */ + uint32_t cbInstanceCC; + /** Size of the raw-mode instance data. */ + uint32_t cbInstanceRC; + /** Max number of PCI devices. */ + uint16_t cMaxPciDevices; + /** Max number of MSI-X vectors in any of the PCI devices. */ + uint16_t cMaxMsixVectors; + /** The description of the device. The UTF-8 string pointed to shall, like this structure, + * remain unchanged from registration till VM destruction. */ + const char *pszDescription; + + /** + * Constructor callback. + * + * This is called much later than both the ring-0 and ring-3 constructors, since + * raw-mode v2 require a working VMM to run actual code. + * + * @returns VBox status code. + * @param pDevIns The device instance data. + * @note The destructure is always called, regardless of the return status. + */ + DECLRGCALLBACKMEMBER(int, pfnConstruct, (PPDMDEVINS pDevIns)); + + /** @name Reserved for future extensions, must be zero. + * @{ */ + DECLRCCALLBACKMEMBER(int, pfnReserved0, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved1, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved2, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved3, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved4, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved5, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved6, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved7, (PPDMDEVINS pDevIns)); + /** @} */ + + /** Initialization safty marker. */ + uint32_t u32VersionEnd; +} PDMDEVREGRC; +/** Pointer to a raw-mode PDM device registration structure. */ +typedef PDMDEVREGRC *PPDMDEVREGRC; +/** Pointer to a const raw-mode PDM device registration structure. */ +typedef PDMDEVREGRC const *PCPDMDEVREGRC; +/** Current DEVREGRC version number. */ +#define PDM_DEVREGRC_VERSION PDM_VERSION_MAKE(0xff81, 1, 0) + + + +/** @def PDM_DEVREG_VERSION + * Current DEVREG version number. */ +/** @typedef PDMDEVREGR3 + * A current context PDM device registration structure. */ +/** @typedef PPDMDEVREGR3 + * Pointer to a current context PDM device registration structure. */ +/** @typedef PCPDMDEVREGR3 + * Pointer to a const current context PDM device registration structure. */ +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +# define PDM_DEVREG_VERSION PDM_DEVREGR3_VERSION +typedef PDMDEVREGR3 PDMDEVREG; +typedef PPDMDEVREGR3 PPDMDEVREG; +typedef PCPDMDEVREGR3 PCPDMDEVREG; +#elif defined(IN_RING0) +# define PDM_DEVREG_VERSION PDM_DEVREGR0_VERSION +typedef PDMDEVREGR0 PDMDEVREG; +typedef PPDMDEVREGR0 PPDMDEVREG; +typedef PCPDMDEVREGR0 PCPDMDEVREG; +#elif defined(IN_RC) +# define PDM_DEVREG_VERSION PDM_DEVREGRC_VERSION +typedef PDMDEVREGRC PDMDEVREG; +typedef PPDMDEVREGRC PPDMDEVREG; +typedef PCPDMDEVREGRC PCPDMDEVREG; +#else +# error "Not IN_RING3, IN_RING0 or IN_RC" +#endif + + +/** + * Device registrations for ring-0 modules. + * + * This structure is used directly and must therefore reside in persistent + * memory (i.e. the data section). + */ +typedef struct PDMDEVMODREGR0 +{ + /** The structure version (PDM_DEVMODREGR0_VERSION). */ + uint32_t u32Version; + /** Number of devices in the array papDevRegs points to. */ + uint32_t cDevRegs; + /** Pointer to device registration structures. */ + PCPDMDEVREGR0 *papDevRegs; + /** The ring-0 module handle - PDM internal, fingers off. */ + void *hMod; + /** List entry - PDM internal, fingers off. */ + RTLISTNODE ListEntry; +} PDMDEVMODREGR0; +/** Pointer to device registriations for a ring-0 module. */ +typedef PDMDEVMODREGR0 *PPDMDEVMODREGR0; +/** Current PDMDEVMODREGR0 version number. */ +#define PDM_DEVMODREGR0_VERSION PDM_VERSION_MAKE(0xff85, 1, 0) + + +/** @name IRQ Level for use with the *SetIrq APIs. + * @{ + */ +/** Assert the IRQ (can assume value 1). */ +#define PDM_IRQ_LEVEL_HIGH RT_BIT(0) +/** Deassert the IRQ (can assume value 0). */ +#define PDM_IRQ_LEVEL_LOW 0 +/** flip-flop - deassert and then assert the IRQ again immediately (PIC) / + * automatically deasserts it after delivery to the APIC (IOAPIC). + * @note Only suitable for edge trigger interrupts. */ +#define PDM_IRQ_LEVEL_FLIP_FLOP (RT_BIT(1) | PDM_IRQ_LEVEL_HIGH) +/** @} */ + +/** + * Registration record for MSI/MSI-X emulation. + */ +typedef struct PDMMSIREG +{ + /** Number of MSI interrupt vectors, 0 if MSI not supported */ + uint16_t cMsiVectors; + /** Offset of MSI capability */ + uint8_t iMsiCapOffset; + /** Offset of next capability to MSI */ + uint8_t iMsiNextOffset; + /** If we support 64-bit MSI addressing */ + bool fMsi64bit; + /** If we do not support per-vector masking */ + bool fMsiNoMasking; + + /** Number of MSI-X interrupt vectors, 0 if MSI-X not supported */ + uint16_t cMsixVectors; + /** Offset of MSI-X capability */ + uint8_t iMsixCapOffset; + /** Offset of next capability to MSI-X */ + uint8_t iMsixNextOffset; + /** Value of PCI BAR (base addresss register) assigned by device for MSI-X page access */ + uint8_t iMsixBar; +} PDMMSIREG; +typedef PDMMSIREG *PPDMMSIREG; + +/** + * PCI Bus registration structure. + * All the callbacks, except the PCIBIOS hack, are working on PCI devices. + */ +typedef struct PDMPCIBUSREGR3 +{ + /** Structure version number. PDM_PCIBUSREGR3_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Registers the device with the default PCI bus. + * + * @returns VBox status code. + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param fFlags Reserved for future use, PDMPCIDEVREG_F_MBZ. + * @param uPciDevNo PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, or a specific + * device number (0-31). + * @param uPciFunNo PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, or a specific + * function number (0-7). + * @param pszName Device name (static but not unique). + * + * @remarks Caller enters the PDM critical section. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags, + uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)); + + /** + * Initialize MSI or MSI-X emulation support in a PCI device. + * + * This cannot handle all corner cases of the MSI/MSI-X spec, but for the + * vast majority of device emulation it covers everything necessary. It's + * fully automatic, taking care of all BAR and config space requirements, + * and interrupt delivery is done using PDMDevHlpPCISetIrq and friends. + * When MSI/MSI-X is enabled then the iIrq parameter is redefined to take + * the vector number (otherwise it has the usual INTA-D meaning for PCI). + * + * A device not using this can still offer MSI/MSI-X. In this case it's + * completely up to the device (in the MSI-X case) to create/register the + * necessary MMIO BAR, handle all config space/BAR updating and take care + * of delivering the interrupts appropriately. + * + * @returns VBox status code. + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param pMsiReg MSI emulation registration structure + * @remarks Caller enters the PDM critical section. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterMsiR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PPDMMSIREG pMsiReg)); + + /** + * Registers a I/O region (memory mapped or I/O ports) for a PCI device. + * + * @returns VBox status code. + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param enmType PCI_ADDRESS_SPACE_MEM, PCI_ADDRESS_SPACE_IO or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally with + * PCI_ADDRESS_SPACE_BAR64 or'ed in. + * @param fFlags PDMPCIDEV_IORGN_F_XXX. + * @param hHandle An I/O port, MMIO or MMIO2 handle according to + * @a fFlags, UINT64_MAX if no handle is passed + * (old style). + * @param pfnMapUnmap Callback for doing the mapping. Optional if a handle + * is given. + * @remarks Caller enters the PDM critical section. + */ + DECLR3CALLBACKMEMBER(int, pfnIORegionRegisterR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, + RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, uint32_t fFlags, + uint64_t hHandle, PFNPCIIOREGIONMAP pfnMapUnmap)); + + /** + * Register PCI configuration space read/write intercept callbacks. + * + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param pfnRead Pointer to the user defined PCI config read function. + * @param pfnWrite Pointer to the user defined PCI config write function. + * to call default PCI config write function. Can be NULL. + * @remarks Caller enters the PDM critical section. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(void, pfnInterceptConfigAccesses,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + PFNPCICONFIGREAD pfnRead, PFNPCICONFIGWRITE pfnWrite)); + + /** + * Perform a PCI configuration space write, bypassing interception. + * + * This is for devices that make use of PDMDevHlpPCIInterceptConfigAccesses(). + * + * @returns Strict VBox status code (mainly DBGFSTOP). + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device which config space is being read. + * @param uAddress The config space address. + * @param cb The size of the read: 1, 2 or 4 bytes. + * @param u32Value The value to write. + * @note The caller (PDM) does not enter the PDM critsect, but it is possible + * that the (root) bus will have done that already. + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnConfigWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t u32Value)); + + /** + * Perform a PCI configuration space read, bypassing interception. + * + * This is for devices that make use of PDMDevHlpPCIInterceptConfigAccesses(). + * + * @returns Strict VBox status code (mainly DBGFSTOP). + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device which config space is being read. + * @param uAddress The config space address. + * @param cb The size of the read: 1, 2 or 4 bytes. + * @param pu32Value Where to return the value. + * @note The caller (PDM) does not enter the PDM critsect, but it is possible + * that the (root) bus will have done that already. + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnConfigRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t *pu32Value)); + + /** + * Set the IRQ for a PCI device. + * + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @remarks Caller enters the PDM critical section. + */ + DECLR3CALLBACKMEMBER(void, pfnSetIrqR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** Marks the end of the structure with PDM_PCIBUSREGR3_VERSION. */ + uint32_t u32EndVersion; +} PDMPCIBUSREGR3; +/** Pointer to a PCI bus registration structure. */ +typedef PDMPCIBUSREGR3 *PPDMPCIBUSREGR3; +/** Current PDMPCIBUSREGR3 version number. */ +#define PDM_PCIBUSREGR3_VERSION PDM_VERSION_MAKE(0xff86, 2, 0) + +/** + * PCI Bus registration structure for ring-0. + */ +typedef struct PDMPCIBUSREGR0 +{ + /** Structure version number. PDM_PCIBUSREGR0_VERSION defines the current version. */ + uint32_t u32Version; + /** The PCI bus number (from ring-3 registration). */ + uint32_t iBus; + /** + * Set the IRQ for a PCI device. + * + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @remarks Caller enters the PDM critical section. + */ + DECLR0CALLBACKMEMBER(void, pfnSetIrq,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)); + /** Marks the end of the structure with PDM_PCIBUSREGR0_VERSION. */ + uint32_t u32EndVersion; +} PDMPCIBUSREGR0; +/** Pointer to a PCI bus ring-0 registration structure. */ +typedef PDMPCIBUSREGR0 *PPDMPCIBUSREGR0; +/** Current PDMPCIBUSREGR0 version number. */ +#define PDM_PCIBUSREGR0_VERSION PDM_VERSION_MAKE(0xff87, 1, 0) + +/** + * PCI Bus registration structure for raw-mode. + */ +typedef struct PDMPCIBUSREGRC +{ + /** Structure version number. PDM_PCIBUSREGRC_VERSION defines the current version. */ + uint32_t u32Version; + /** The PCI bus number (from ring-3 registration). */ + uint32_t iBus; + /** + * Set the IRQ for a PCI device. + * + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @remarks Caller enters the PDM critical section. + */ + DECLRCCALLBACKMEMBER(void, pfnSetIrq,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)); + /** Marks the end of the structure with PDM_PCIBUSREGRC_VERSION. */ + uint32_t u32EndVersion; +} PDMPCIBUSREGRC; +/** Pointer to a PCI bus raw-mode registration structure. */ +typedef PDMPCIBUSREGRC *PPDMPCIBUSREGRC; +/** Current PDMPCIBUSREGRC version number. */ +#define PDM_PCIBUSREGRC_VERSION PDM_VERSION_MAKE(0xff88, 1, 0) + +/** PCI bus registration structure for the current context. */ +typedef CTX_SUFF(PDMPCIBUSREG) PDMPCIBUSREGCC; +/** Pointer to a PCI bus registration structure for the current context. */ +typedef CTX_SUFF(PPDMPCIBUSREG) PPDMPCIBUSREGCC; +/** PCI bus registration structure version for the current context. */ +#define PDM_PCIBUSREGCC_VERSION CTX_MID(PDM_PCIBUSREG,_VERSION) + + +/** + * PCI Bus RC helpers. + */ +typedef struct PDMPCIHLPRC +{ + /** Structure version. PDM_PCIHLPRC_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set an ISA IRQ. + * + * @param pDevIns PCI device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLRCCALLBACKMEMBER(void, pfnIsaSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Set an I/O-APIC IRQ. + * + * @param pDevIns PCI device instance. + * @param uBusDevFn The bus:device:function of the device initiating the + * IRQ. Pass NIL_PCIBDF when it's not a PCI device or + * interrupt. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLRCCALLBACKMEMBER(void, pfnIoApicSetIrq,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Send an MSI. + * + * @param pDevIns PCI device instance. + * @param uBusDevFn The bus:device:function of the device initiating the + * MSI. Cannot be NIL_PCIBDF. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLRCCALLBACKMEMBER(void, pfnIoApicSendMsi,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, PCMSIMSG pMsi, uint32_t uTagSrc)); + + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The PCI device instance. + * @param rc What to return if we fail to acquire the lock. + * + * @sa PDMCritSectEnter + */ + DECLRCCALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLRCCALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Gets a bus by it's PDM ordinal (typically the parent bus). + * + * @returns Pointer to the device instance of the bus. + * @param pDevIns The PCI bus device instance. + * @param idxPdmBus The PDM ordinal value of the bus to get. + */ + DECLRCCALLBACKMEMBER(PPDMDEVINS, pfnGetBusByNo,(PPDMDEVINS pDevIns, uint32_t idxPdmBus)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIHLPRC; +/** Pointer to PCI helpers. */ +typedef RCPTRTYPE(PDMPCIHLPRC *) PPDMPCIHLPRC; +/** Pointer to const PCI helpers. */ +typedef RCPTRTYPE(const PDMPCIHLPRC *) PCPDMPCIHLPRC; + +/** Current PDMPCIHLPRC version number. */ +#define PDM_PCIHLPRC_VERSION PDM_VERSION_MAKE(0xfffd, 4, 0) + + +/** + * PCI Bus R0 helpers. + */ +typedef struct PDMPCIHLPR0 +{ + /** Structure version. PDM_PCIHLPR0_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set an ISA IRQ. + * + * @param pDevIns PCI device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLR0CALLBACKMEMBER(void, pfnIsaSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Set an I/O-APIC IRQ. + * + * @param pDevIns PCI device instance. + * @param uBusDevFn The bus:device:function of the device initiating the + * IRQ. Pass NIL_PCIBDF when it's not a PCI device or + * interrupt. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLR0CALLBACKMEMBER(void, pfnIoApicSetIrq,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Send an MSI. + * + * @param pDevIns PCI device instance. + * @param uBusDevFn The bus:device:function of the device initiating the + * MSI. Cannot be NIL_PCIBDF. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLR0CALLBACKMEMBER(void, pfnIoApicSendMsi,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The PCI device instance. + * @param rc What to return if we fail to acquire the lock. + * + * @sa PDMCritSectEnter + */ + DECLR0CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLR0CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Gets a bus by it's PDM ordinal (typically the parent bus). + * + * @returns Pointer to the device instance of the bus. + * @param pDevIns The PCI bus device instance. + * @param idxPdmBus The PDM ordinal value of the bus to get. + */ + DECLR0CALLBACKMEMBER(PPDMDEVINS, pfnGetBusByNo,(PPDMDEVINS pDevIns, uint32_t idxPdmBus)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIHLPR0; +/** Pointer to PCI helpers. */ +typedef R0PTRTYPE(PDMPCIHLPR0 *) PPDMPCIHLPR0; +/** Pointer to const PCI helpers. */ +typedef R0PTRTYPE(const PDMPCIHLPR0 *) PCPDMPCIHLPR0; + +/** Current PDMPCIHLPR0 version number. */ +#define PDM_PCIHLPR0_VERSION PDM_VERSION_MAKE(0xfffc, 6, 0) + +/** + * PCI device helpers. + */ +typedef struct PDMPCIHLPR3 +{ + /** Structure version. PDM_PCIHLPR3_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set an ISA IRQ. + * + * @param pDevIns The PCI device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnIsaSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Set an I/O-APIC IRQ. + * + * @param pDevIns The PCI device instance. + * @param uBusDevFn The bus:device:function of the device initiating the + * IRQ. Pass NIL_PCIBDF when it's not a PCI device or + * interrupt. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnIoApicSetIrq,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Send an MSI. + * + * @param pDevIns PCI device instance. + * @param uBusDevFn The bus:device:function of the device initiating the + * MSI. Cannot be NIL_PCIBDF. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnIoApicSendMsi,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns Fatal error on failure. + * @param pDevIns The PCI device instance. + * @param rc Dummy for making the interface identical to the RC and R0 versions. + * + * @sa PDMCritSectEnter + */ + DECLR3CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLR3CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Gets a bus by it's PDM ordinal (typically the parent bus). + * + * @returns Pointer to the device instance of the bus. + * @param pDevIns The PCI bus device instance. + * @param idxPdmBus The PDM ordinal value of the bus to get. + */ + DECLR3CALLBACKMEMBER(PPDMDEVINS, pfnGetBusByNo,(PPDMDEVINS pDevIns, uint32_t idxPdmBus)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIHLPR3; +/** Pointer to PCI helpers. */ +typedef R3PTRTYPE(PDMPCIHLPR3 *) PPDMPCIHLPR3; +/** Pointer to const PCI helpers. */ +typedef R3PTRTYPE(const PDMPCIHLPR3 *) PCPDMPCIHLPR3; + +/** Current PDMPCIHLPR3 version number. */ +#define PDM_PCIHLPR3_VERSION PDM_VERSION_MAKE(0xfffb, 5, 0) + + +/** @name PDMIOMMU_MEM_F_XXX - IOMMU memory access transaction flags. + * These flags are used for memory access transactions via the IOMMU interface. + * @{ */ +/** Memory read. */ +#define PDMIOMMU_MEM_F_READ RT_BIT_32(0) +/** Memory write. */ +#define PDMIOMMU_MEM_F_WRITE RT_BIT_32(1) +/** Valid flag mask. */ +#define PDMIOMMU_MEM_F_VALID_MASK (PDMIOMMU_MEM_F_READ | PDMIOMMU_MEM_F_WRITE) +/** @} */ + +/** + * IOMMU registration structure for ring-0. + */ +typedef struct PDMIOMMUREGR0 +{ + /** Structure version number. PDM_IOMMUREG_VERSION defines the current + * version. */ + uint32_t u32Version; + /** Index into the PDM IOMMU array (PDM::aIommus) from ring-3. */ + uint32_t idxIommu; + + /** + * Translates the physical address for a memory transaction through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param uIova The I/O virtual address being accessed. + * @param cbIova The size of the access. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param pGCPhysSpa Where to store the translated system physical address. + * @param pcbContiguous Where to store the number of contiguous bytes translated + * and permission-checked. + * + * @thread Any. + */ + DECLR0CALLBACKMEMBER(int, pfnMemAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, uint64_t uIova, size_t cbIova, + uint32_t fFlags, PRTGCPHYS pGCPhysSpa, size_t *pcbContiguous)); + + /** + * Translates in bulk physical page addresses for memory transactions through the + * IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param cIovas The number of I/O virtual addresses being accessed. + * @param pauIovas The I/O virtual addresses being accessed. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param paGCPhysSpa Where to store the translated system physical page + * addresses. + * + * @thread Any. + */ + DECLR0CALLBACKMEMBER(int, pfnMemBulkAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, size_t cIovas, uint64_t const *pauIovas, + uint32_t fFlags, PRTGCPHYS paGCPhysSpa)); + + /** + * Performs an interrupt remap request through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param pMsiIn The source MSI. + * @param pMsiOut Where to store the remapped MSI. + * + * @thread Any. + */ + DECLR0CALLBACKMEMBER(int, pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t idDevice, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUREGR0; +/** Pointer to a IOMMU registration structure. */ +typedef PDMIOMMUREGR0 *PPDMIOMMUREGR0; + +/** Current PDMIOMMUREG version number. */ +#define PDM_IOMMUREGR0_VERSION PDM_VERSION_MAKE(0xff10, 3, 0) + + +/** + * IOMMU registration structure for raw-mode. + */ +typedef struct PDMIOMMUREGRC +{ + /** Structure version number. PDM_IOMMUREG_VERSION defines the current + * version. */ + uint32_t u32Version; + /** Index into the PDM IOMMU array (PDM::aIommus) from ring-3. */ + uint32_t idxIommu; + + /** + * Translates the physical address for a memory transaction through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param uIova The I/O virtual address being accessed. + * @param cbIova The size of the access. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param pGCPhysSpa Where to store the translated system physical address. + * @param pcbContiguous Where to store the number of contiguous bytes translated + * and permission-checked. + * + * @thread Any. + */ + DECLRCCALLBACKMEMBER(int, pfnMemAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, uint64_t uIova, size_t cbIova, + uint32_t fFlags, PRTGCPHYS pGCPhysSpa, size_t *pcbContiguous)); + + /** + * Translates in bulk physical page addresses for memory transactions through the + * IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param cIovas The number of I/O virtual addresses being accessed. + * @param pauIovas The I/O virtual addresses being accessed. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param paGCPhysSpa Where to store the translated system physical page + * addresses. + * + * @thread Any. + */ + DECLRCCALLBACKMEMBER(int, pfnMemBulkAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, size_t cIovas, uint64_t const *pauIovas, + uint32_t fFlags, PRTGCPHYS paGCPhysSpa)); + + /** + * Performs an interrupt remap request through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param pMsiIn The source MSI. + * @param pMsiOut Where to store the remapped MSI. + * + * @thread Any. + */ + DECLRCCALLBACKMEMBER(int, pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t idDevice, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUREGRC; +/** Pointer to a IOMMU registration structure. */ +typedef PDMIOMMUREGRC *PPDMIOMMUREGRC; + +/** Current PDMIOMMUREG version number. */ +#define PDM_IOMMUREGRC_VERSION PDM_VERSION_MAKE(0xff11, 3, 0) + + +/** + * IOMMU registration structure for ring-3. + */ +typedef struct PDMIOMMUREGR3 +{ + /** Structure version number. PDM_IOMMUREG_VERSION defines the current + * version. */ + uint32_t u32Version; + /** Padding. */ + uint32_t uPadding0; + + /** + * Translates the physical address for a memory transaction through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param uIova The I/O virtual address being accessed. + * @param cbIova The size of the access. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param pGCPhysSpa Where to store the translated system physical address. + * @param pcbContiguous Where to store the number of contiguous bytes translated + * and permission-checked. + * + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnMemAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, uint64_t uIova, size_t cbIova, + uint32_t fFlags, PRTGCPHYS pGCPhysSpa, size_t *pcbContiguous)); + + /** + * Translates in bulk physical page addresses for memory transactions through the + * IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param cIovas The number of I/O virtual addresses being accessed. + * @param pauIovas The I/O virtual addresses being accessed. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param paGCPhysSpa Where to store the translated system physical page + * addresses. + * + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnMemBulkAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, size_t cIovas, uint64_t const *pauIovas, + uint32_t fFlags, PRTGCPHYS paGCPhysSpa)); + + /** + * Performs an interrupt remap request through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param pMsiIn The source MSI. + * @param pMsiOut Where to store the remapped MSI. + * + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t idDevice, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUREGR3; +/** Pointer to a IOMMU registration structure. */ +typedef PDMIOMMUREGR3 *PPDMIOMMUREGR3; + +/** Current PDMIOMMUREG version number. */ +#define PDM_IOMMUREGR3_VERSION PDM_VERSION_MAKE(0xff12, 3, 0) + +/** IOMMU registration structure for the current context. */ +typedef CTX_SUFF(PDMIOMMUREG) PDMIOMMUREGCC; +/** Pointer to an IOMMU registration structure for the current context. */ +typedef CTX_SUFF(PPDMIOMMUREG) PPDMIOMMUREGCC; +/** IOMMU registration structure version for the current context. */ +#define PDM_IOMMUREGCC_VERSION CTX_MID(PDM_IOMMUREG,_VERSION) + + +/** + * IOMMU helpers for ring-0. + */ +typedef struct PDMIOMMUHLPR0 +{ + /** Structure version. PDM_IOMMUHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The PCI device instance. + * @param rc What to return if we fail to acquire the lock. + * + * @sa PDMCritSectEnter + */ + DECLR0CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLR0CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Check whether the calling thread owns the PDM lock. + * + * @returns @c true if the PDM lock is owned, @c false otherwise. + * @param pDevIns The PCI device instance. + */ + DECLR0CALLBACKMEMBER(bool, pfnLockIsOwner,(PPDMDEVINS pDevIns)); + + /** + * Send an MSI (when generated by the IOMMU device itself). + * + * @param pDevIns PCI device instance. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR0CALLBACKMEMBER(void, pfnSendMsi,(PPDMDEVINS pDevIns, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUHLPR0; +/** Pointer to IOMMU helpers for ring-0. */ +typedef PDMIOMMUHLPR0 *PPDMIOMMUHLPR0; +/** Pointer to const IOMMU helpers for ring-0. */ +typedef const PDMIOMMUHLPR0 *PCPDMIOMMUHLPR0; + +/** Current PDMIOMMUHLPR0 version number. */ +#define PDM_IOMMUHLPR0_VERSION PDM_VERSION_MAKE(0xff13, 5, 0) + + +/** + * IOMMU helpers for raw-mode. + */ +typedef struct PDMIOMMUHLPRC +{ + /** Structure version. PDM_IOMMUHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The PCI device instance. + * @param rc What to return if we fail to acquire the lock. + * + * @sa PDMCritSectEnter + */ + DECLRCCALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLRCCALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Check whether the threads owns the PDM lock. + * + * @returns @c true if the PDM lock is owned, @c false otherwise. + * @param pDevIns The PCI device instance. + */ + DECLRCCALLBACKMEMBER(bool, pfnLockIsOwner,(PPDMDEVINS pDevIns)); + + /** + * Send an MSI (when generated by the IOMMU device itself). + * + * @param pDevIns PCI device instance. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLRCCALLBACKMEMBER(void, pfnSendMsi,(PPDMDEVINS pDevIns, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUHLPRC; +/** Pointer to IOMMU helpers for raw-mode. */ +typedef PDMIOMMUHLPRC *PPDMIOMMUHLPRC; +/** Pointer to const IOMMU helpers for raw-mode. */ +typedef const PDMIOMMUHLPRC *PCPDMIOMMUHLPRC; + +/** Current PDMIOMMUHLPRC version number. */ +#define PDM_IOMMUHLPRC_VERSION PDM_VERSION_MAKE(0xff14, 5, 0) + + +/** + * IOMMU helpers for ring-3. + */ +typedef struct PDMIOMMUHLPR3 +{ + /** Structure version. PDM_IOMMUHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The PCI device instance. + * @param rc What to return if we fail to acquire the lock. + * + * @sa PDMCritSectEnter + */ + DECLR3CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLR3CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Check whether the threads owns the PDM lock. + * + * @returns @c true if the PDM lock is owned, @c false otherwise. + * @param pDevIns The PCI device instance. + */ + DECLR3CALLBACKMEMBER(bool, pfnLockIsOwner,(PPDMDEVINS pDevIns)); + + /** + * Send an MSI (when generated by the IOMMU device itself). + * + * @param pDevIns PCI device instance. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnSendMsi,(PPDMDEVINS pDevIns, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUHLPR3; +/** Pointer to IOMMU helpers for raw-mode. */ +typedef PDMIOMMUHLPR3 *PPDMIOMMUHLPR3; +/** Pointer to const IOMMU helpers for raw-mode. */ +typedef const PDMIOMMUHLPR3 *PCPDMIOMMUHLPR3; + +/** Current PDMIOMMUHLPR3 version number. */ +#define PDM_IOMMUHLPR3_VERSION PDM_VERSION_MAKE(0xff15, 5, 0) + + +/** + * Programmable Interrupt Controller registration structure (all contexts). + */ +typedef struct PDMPICREG +{ + /** Structure version number. PDM_PICREG_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set the an IRQ. + * + * @param pDevIns Device instance of the PIC. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @remarks Caller enters the PDM critical section. + */ + DECLCALLBACKMEMBER(void, pfnSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Get a pending interrupt. + * + * @returns Pending interrupt number. + * @param pDevIns Device instance of the PIC. + * @param puTagSrc Where to return the IRQ tag and source. + * @remarks Caller enters the PDM critical section. + */ + DECLCALLBACKMEMBER(int, pfnGetInterrupt,(PPDMDEVINS pDevIns, uint32_t *puTagSrc)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPICREG; +/** Pointer to a PIC registration structure. */ +typedef PDMPICREG *PPDMPICREG; + +/** Current PDMPICREG version number. */ +#define PDM_PICREG_VERSION PDM_VERSION_MAKE(0xfffa, 3, 0) + +/** + * PIC helpers, same in all contexts. + */ +typedef struct PDMPICHLP +{ + /** Structure version. PDM_PICHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set the interrupt force action flag. + * + * @param pDevIns Device instance of the PIC. + */ + DECLCALLBACKMEMBER(void, pfnSetInterruptFF,(PPDMDEVINS pDevIns)); + + /** + * Clear the interrupt force action flag. + * + * @param pDevIns Device instance of the PIC. + */ + DECLCALLBACKMEMBER(void, pfnClearInterruptFF,(PPDMDEVINS pDevIns)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The PIC device instance. + * @param rc What to return if we fail to acquire the lock. + * + * @sa PDMCritSectEnter + */ + DECLCALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PIC device instance. + */ + DECLCALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPICHLP; +/** Pointer to PIC helpers. */ +typedef PDMPICHLP *PPDMPICHLP; +/** Pointer to const PIC helpers. */ +typedef const PDMPICHLP *PCPDMPICHLP; + +/** Current PDMPICHLP version number. */ +#define PDM_PICHLP_VERSION PDM_VERSION_MAKE(0xfff9, 3, 0) + + +/** + * Firmware registration structure. + */ +typedef struct PDMFWREG +{ + /** Struct version+magic number (PDM_FWREG_VERSION). */ + uint32_t u32Version; + + /** + * Checks whether this is a hard or soft reset. + * + * The current definition of soft reset is what the PC BIOS does when CMOS[0xF] + * is 5, 9 or 0xA. + * + * @returns true if hard reset, false if soft. + * @param pDevIns Device instance of the firmware. + * @param fFlags PDMRESET_F_XXX passed to the PDMDevHlpVMReset API. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsHardReset,(PPDMDEVINS pDevIns, uint32_t fFlags)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMFWREG; +/** Pointer to a FW registration structure. */ +typedef PDMFWREG *PPDMFWREG; +/** Pointer to a const FW registration structure. */ +typedef PDMFWREG const *PCPDMFWREG; + +/** Current PDMFWREG version number. */ +#define PDM_FWREG_VERSION PDM_VERSION_MAKE(0xffdd, 1, 0) + +/** + * Firmware R3 helpers. + */ +typedef struct PDMFWHLPR3 +{ + /** Structure version. PDM_FWHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMFWHLPR3; + +/** Pointer to FW R3 helpers. */ +typedef R3PTRTYPE(PDMFWHLPR3 *) PPDMFWHLPR3; +/** Pointer to const FW R3 helpers. */ +typedef R3PTRTYPE(const PDMFWHLPR3 *) PCPDMFWHLPR3; + +/** Current PDMFWHLPR3 version number. */ +#define PDM_FWHLPR3_VERSION PDM_VERSION_MAKE(0xffdb, 1, 0) + + +/** + * APIC mode argument for apicR3SetCpuIdFeatureLevel. + * + * Also used in saved-states, CFGM don't change existing values. + */ +typedef enum PDMAPICMODE +{ + /** Invalid 0 entry. */ + PDMAPICMODE_INVALID = 0, + /** No APIC. */ + PDMAPICMODE_NONE, + /** Standard APIC (X86_CPUID_FEATURE_EDX_APIC). */ + PDMAPICMODE_APIC, + /** Intel X2APIC (X86_CPUID_FEATURE_ECX_X2APIC). */ + PDMAPICMODE_X2APIC, + /** The usual 32-bit paranoia. */ + PDMAPICMODE_32BIT_HACK = 0x7fffffff +} PDMAPICMODE; + +/** + * APIC irq argument for pfnSetInterruptFF and pfnClearInterruptFF. + */ +typedef enum PDMAPICIRQ +{ + /** Invalid 0 entry. */ + PDMAPICIRQ_INVALID = 0, + /** Normal hardware interrupt. */ + PDMAPICIRQ_HARDWARE, + /** NMI. */ + PDMAPICIRQ_NMI, + /** SMI. */ + PDMAPICIRQ_SMI, + /** ExtINT (HW interrupt via PIC). */ + PDMAPICIRQ_EXTINT, + /** Interrupt arrived, needs to be updated to the IRR. */ + PDMAPICIRQ_UPDATE_PENDING, + /** The usual 32-bit paranoia. */ + PDMAPICIRQ_32BIT_HACK = 0x7fffffff +} PDMAPICIRQ; + + +/** + * I/O APIC registration structure (all contexts). + */ +typedef struct PDMIOAPICREG +{ + /** Struct version+magic number (PDM_IOAPICREG_VERSION). */ + uint32_t u32Version; + + /** + * Set an IRQ. + * + * @param pDevIns Device instance of the I/O APIC. + * @param uBusDevFn The bus:device:function of the device initiating the + * IRQ. Can be NIL_PCIBDF. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * + * @remarks Caller enters the PDM critical section + * Actually, as per 2018-07-21 this isn't true (bird). + */ + DECLCALLBACKMEMBER(void, pfnSetIrq,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Send a MSI. + * + * @param pDevIns Device instance of the I/O APIC. + * @param uBusDevFn The bus:device:function of the device initiating the + * MSI. Cannot be NIL_PCIBDF. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + * + * @remarks Caller enters the PDM critical section + * Actually, as per 2018-07-21 this isn't true (bird). + */ + DECLCALLBACKMEMBER(void, pfnSendMsi,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** + * Set the EOI for an interrupt vector. + * + * @param pDevIns Device instance of the I/O APIC. + * @param u8Vector The vector. + * + * @remarks Caller enters the PDM critical section + * Actually, as per 2018-07-21 this isn't true (bird). + */ + DECLCALLBACKMEMBER(void, pfnSetEoi,(PPDMDEVINS pDevIns, uint8_t u8Vector)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOAPICREG; +/** Pointer to an APIC registration structure. */ +typedef PDMIOAPICREG *PPDMIOAPICREG; + +/** Current PDMAPICREG version number. */ +#define PDM_IOAPICREG_VERSION PDM_VERSION_MAKE(0xfff2, 8, 0) + + +/** + * IOAPIC helpers, same in all contexts. + */ +typedef struct PDMIOAPICHLP +{ + /** Structure version. PDM_IOAPICHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Private interface between the IOAPIC and APIC. + * + * @returns status code. + * @param pDevIns Device instance of the IOAPIC. + * @param u8Dest See APIC implementation. + * @param u8DestMode See APIC implementation. + * @param u8DeliveryMode See APIC implementation. + * @param uVector See APIC implementation. + * @param u8Polarity See APIC implementation. + * @param u8TriggerMode See APIC implementation. + * @param uTagSrc The IRQ tag and source (for tracing). + * + * @sa APICBusDeliver() + */ + DECLCALLBACKMEMBER(int, pfnApicBusDeliver,(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode, uint8_t u8DeliveryMode, + uint8_t uVector, uint8_t u8Polarity, uint8_t u8TriggerMode, uint32_t uTagSrc)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The IOAPIC device instance. + * @param rc What to return if we fail to acquire the lock. + * + * @sa PDMCritSectEnter + */ + DECLCALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The IOAPIC device instance. + */ + DECLCALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Checks if the calling thread owns the PDM lock. + * + * @param pDevIns The IOAPIC device instance. + */ + DECLCALLBACKMEMBER(bool, pfnLockIsOwner,(PPDMDEVINS pDevIns)); + + /** + * Private interface between the IOAPIC and IOMMU. + * + * @returns status code. + * @param pDevIns Device instance of the IOAPIC. + * @param idDevice The device identifier (bus, device, function). + * @param pMsiIn The source MSI. + * @param pMsiOut Where to store the remapped MSI (only updated when + * VINF_SUCCESS is returned). + */ + DECLCALLBACKMEMBER(int, pfnIommuMsiRemap,(PPDMDEVINS pDevIns, uint16_t idDevice, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOAPICHLP; +/** Pointer to IOAPIC helpers. */ +typedef PDMIOAPICHLP * PPDMIOAPICHLP; +/** Pointer to const IOAPIC helpers. */ +typedef const PDMIOAPICHLP * PCPDMIOAPICHLP; + +/** Current PDMIOAPICHLP version number. */ +#define PDM_IOAPICHLP_VERSION PDM_VERSION_MAKE(0xfff0, 3, 1) + + +/** + * HPET registration structure. + */ +typedef struct PDMHPETREG +{ + /** Struct version+magic number (PDM_HPETREG_VERSION). */ + uint32_t u32Version; +} PDMHPETREG; +/** Pointer to an HPET registration structure. */ +typedef PDMHPETREG *PPDMHPETREG; + +/** Current PDMHPETREG version number. */ +#define PDM_HPETREG_VERSION PDM_VERSION_MAKE(0xffe2, 1, 0) + +/** + * HPET RC helpers. + * + * @remarks Keep this around in case HPET will need PDM interaction in again RC + * at some later point. + */ +typedef struct PDMHPETHLPRC +{ + /** Structure version. PDM_HPETHLPRC_VERSION defines the current version. */ + uint32_t u32Version; + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMHPETHLPRC; + +/** Pointer to HPET RC helpers. */ +typedef RCPTRTYPE(PDMHPETHLPRC *) PPDMHPETHLPRC; +/** Pointer to const HPET RC helpers. */ +typedef RCPTRTYPE(const PDMHPETHLPRC *) PCPDMHPETHLPRC; + +/** Current PDMHPETHLPRC version number. */ +#define PDM_HPETHLPRC_VERSION PDM_VERSION_MAKE(0xffee, 2, 0) + + +/** + * HPET R0 helpers. + * + * @remarks Keep this around in case HPET will need PDM interaction in again R0 + * at some later point. + */ +typedef struct PDMHPETHLPR0 +{ + /** Structure version. PDM_HPETHLPR0_VERSION defines the current version. */ + uint32_t u32Version; + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMHPETHLPR0; + +/** Pointer to HPET R0 helpers. */ +typedef R0PTRTYPE(PDMHPETHLPR0 *) PPDMHPETHLPR0; +/** Pointer to const HPET R0 helpers. */ +typedef R0PTRTYPE(const PDMHPETHLPR0 *) PCPDMHPETHLPR0; + +/** Current PDMHPETHLPR0 version number. */ +#define PDM_HPETHLPR0_VERSION PDM_VERSION_MAKE(0xffed, 2, 0) + +/** + * HPET R3 helpers. + */ +typedef struct PDMHPETHLPR3 +{ + /** Structure version. PDM_HPETHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set legacy mode on PIT and RTC. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to set legacy mode. + * @param pDevIns Device instance of the HPET. + * @param fActivated Whether legacy mode is activated or deactivated. + */ + DECLR3CALLBACKMEMBER(int, pfnSetLegacyMode,(PPDMDEVINS pDevIns, bool fActivated)); + + + /** + * Set IRQ, bypassing ISA bus override rules. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to set legacy mode. + * @param pDevIns Device instance of the HPET. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + */ + DECLR3CALLBACKMEMBER(int, pfnSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMHPETHLPR3; + +/** Pointer to HPET R3 helpers. */ +typedef R3PTRTYPE(PDMHPETHLPR3 *) PPDMHPETHLPR3; +/** Pointer to const HPET R3 helpers. */ +typedef R3PTRTYPE(const PDMHPETHLPR3 *) PCPDMHPETHLPR3; + +/** Current PDMHPETHLPR3 version number. */ +#define PDM_HPETHLPR3_VERSION PDM_VERSION_MAKE(0xffec, 3, 0) + + +/** + * Raw PCI device registration structure. + */ +typedef struct PDMPCIRAWREG +{ + /** Struct version+magic number (PDM_PCIRAWREG_VERSION). */ + uint32_t u32Version; + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIRAWREG; +/** Pointer to a raw PCI registration structure. */ +typedef PDMPCIRAWREG *PPDMPCIRAWREG; + +/** Current PDMPCIRAWREG version number. */ +#define PDM_PCIRAWREG_VERSION PDM_VERSION_MAKE(0xffe1, 1, 0) + +/** + * Raw PCI device raw-mode context helpers. + */ +typedef struct PDMPCIRAWHLPRC +{ + /** Structure version and magic number (PDM_PCIRAWHLPRC_VERSION). */ + uint32_t u32Version; + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIRAWHLPRC; +/** Pointer to a raw PCI deviec raw-mode context helper structure. */ +typedef RCPTRTYPE(PDMPCIRAWHLPRC *) PPDMPCIRAWHLPRC; +/** Pointer to a const raw PCI deviec raw-mode context helper structure. */ +typedef RCPTRTYPE(const PDMPCIRAWHLPRC *) PCPDMPCIRAWHLPRC; + +/** Current PDMPCIRAWHLPRC version number. */ +#define PDM_PCIRAWHLPRC_VERSION PDM_VERSION_MAKE(0xffe0, 1, 0) + +/** + * Raw PCI device ring-0 context helpers. + */ +typedef struct PDMPCIRAWHLPR0 +{ + /** Structure version and magic number (PDM_PCIRAWHLPR0_VERSION). */ + uint32_t u32Version; + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIRAWHLPR0; +/** Pointer to a raw PCI deviec ring-0 context helper structure. */ +typedef R0PTRTYPE(PDMPCIRAWHLPR0 *) PPDMPCIRAWHLPR0; +/** Pointer to a const raw PCI deviec ring-0 context helper structure. */ +typedef R0PTRTYPE(const PDMPCIRAWHLPR0 *) PCPDMPCIRAWHLPR0; + +/** Current PDMPCIRAWHLPR0 version number. */ +#define PDM_PCIRAWHLPR0_VERSION PDM_VERSION_MAKE(0xffdf, 1, 0) + + +/** + * Raw PCI device ring-3 context helpers. + */ +typedef struct PDMPCIRAWHLPR3 +{ + /** Undefined structure version and magic number. */ + uint32_t u32Version; + + /** + * Gets the address of the RC raw PCI device helpers. + * + * This should be called at both construction and relocation time to obtain + * the correct address of the RC helpers. + * + * @returns RC pointer to the raw PCI device helpers. + * @param pDevIns Device instance of the raw PCI device. + */ + DECLR3CALLBACKMEMBER(PCPDMPCIRAWHLPRC, pfnGetRCHelpers,(PPDMDEVINS pDevIns)); + + /** + * Gets the address of the R0 raw PCI device helpers. + * + * This should be called at both construction and relocation time to obtain + * the correct address of the R0 helpers. + * + * @returns R0 pointer to the raw PCI device helpers. + * @param pDevIns Device instance of the raw PCI device. + */ + DECLR3CALLBACKMEMBER(PCPDMPCIRAWHLPR0, pfnGetR0Helpers,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIRAWHLPR3; +/** Pointer to raw PCI R3 helpers. */ +typedef R3PTRTYPE(PDMPCIRAWHLPR3 *) PPDMPCIRAWHLPR3; +/** Pointer to const raw PCI R3 helpers. */ +typedef R3PTRTYPE(const PDMPCIRAWHLPR3 *) PCPDMPCIRAWHLPR3; + +/** Current PDMPCIRAWHLPR3 version number. */ +#define PDM_PCIRAWHLPR3_VERSION PDM_VERSION_MAKE(0xffde, 1, 0) + + +#ifdef IN_RING3 + +/** + * DMA Transfer Handler. + * + * @returns Number of bytes transferred. + * @param pDevIns The device instance that registered the handler. + * @param pvUser User pointer. + * @param uChannel Channel number. + * @param off DMA position. + * @param cb Block size. + * @remarks The device lock is take before the callback (in fact, the locks of + * DMA devices and the DMA controller itself are taken). + */ +typedef DECLCALLBACKTYPE(uint32_t, FNDMATRANSFERHANDLER,(PPDMDEVINS pDevIns, void *pvUser, unsigned uChannel, + uint32_t off, uint32_t cb)); +/** Pointer to a FNDMATRANSFERHANDLER(). */ +typedef FNDMATRANSFERHANDLER *PFNDMATRANSFERHANDLER; + +/** + * DMA Controller registration structure. + */ +typedef struct PDMDMAREG +{ + /** Structure version number. PDM_DMACREG_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Execute pending transfers. + * + * @returns A more work indiciator. I.e. 'true' if there is more to be done, and 'false' if all is done. + * @param pDevIns Device instance of the DMAC. + * @remarks No locks held, called on EMT(0) as a form of serialization. + */ + DECLR3CALLBACKMEMBER(bool, pfnRun,(PPDMDEVINS pDevIns)); + + /** + * Register transfer function for DMA channel. + * + * @param pDevIns Device instance of the DMAC. + * @param uChannel Channel number. + * @param pDevInsHandler The device instance of the device making the + * regstration (will be passed to the callback). + * @param pfnTransferHandler Device specific transfer function. + * @param pvUser User pointer to be passed to the callback. + * @remarks No locks held, called on an EMT. + */ + DECLR3CALLBACKMEMBER(void, pfnRegister,(PPDMDEVINS pDevIns, unsigned uChannel, PPDMDEVINS pDevInsHandler, + PFNDMATRANSFERHANDLER pfnTransferHandler, void *pvUser)); + + /** + * Read memory + * + * @returns Number of bytes read. + * @param pDevIns Device instance of the DMAC. + * @param uChannel Channel number. + * @param pvBuffer Pointer to target buffer. + * @param off DMA position. + * @param cbBlock Block size. + * @remarks No locks held, called on an EMT. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnReadMemory,(PPDMDEVINS pDevIns, unsigned uChannel, void *pvBuffer, uint32_t off, uint32_t cbBlock)); + + /** + * Write memory + * + * @returns Number of bytes written. + * @param pDevIns Device instance of the DMAC. + * @param uChannel Channel number. + * @param pvBuffer Memory to write. + * @param off DMA position. + * @param cbBlock Block size. + * @remarks No locks held, called on an EMT. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnWriteMemory,(PPDMDEVINS pDevIns, unsigned uChannel, const void *pvBuffer, uint32_t off, uint32_t cbBlock)); + + /** + * Set the DREQ line. + * + * @param pDevIns Device instance of the DMAC. + * @param uChannel Channel number. + * @param uLevel Level of the line. + * @remarks No locks held, called on an EMT. + */ + DECLR3CALLBACKMEMBER(void, pfnSetDREQ,(PPDMDEVINS pDevIns, unsigned uChannel, unsigned uLevel)); + + /** + * Get channel mode + * + * @returns Channel mode. + * @param pDevIns Device instance of the DMAC. + * @param uChannel Channel number. + * @remarks No locks held, called on an EMT. + */ + DECLR3CALLBACKMEMBER(uint8_t, pfnGetChannelMode,(PPDMDEVINS pDevIns, unsigned uChannel)); + +} PDMDMACREG; +/** Pointer to a DMAC registration structure. */ +typedef PDMDMACREG *PPDMDMACREG; + +/** Current PDMDMACREG version number. */ +#define PDM_DMACREG_VERSION PDM_VERSION_MAKE(0xffeb, 2, 0) + + +/** + * DMA Controller device helpers. + */ +typedef struct PDMDMACHLP +{ + /** Structure version. PDM_DMACHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /* to-be-defined */ + +} PDMDMACHLP; +/** Pointer to DMAC helpers. */ +typedef PDMDMACHLP *PPDMDMACHLP; +/** Pointer to const DMAC helpers. */ +typedef const PDMDMACHLP *PCPDMDMACHLP; + +/** Current PDMDMACHLP version number. */ +#define PDM_DMACHLP_VERSION PDM_VERSION_MAKE(0xffea, 1, 0) + +#endif /* IN_RING3 */ + + + +/** + * RTC registration structure. + */ +typedef struct PDMRTCREG +{ + /** Structure version number. PDM_RTCREG_VERSION defines the current version. */ + uint32_t u32Version; + uint32_t u32Alignment; /**< structure size alignment. */ + + /** + * Write to a CMOS register and update the checksum if necessary. + * + * @returns VBox status code. + * @param pDevIns Device instance of the RTC. + * @param iReg The CMOS register index. + * @param u8Value The CMOS register value. + * @remarks Caller enters the device critical section. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMDEVINS pDevIns, unsigned iReg, uint8_t u8Value)); + + /** + * Read a CMOS register. + * + * @returns VBox status code. + * @param pDevIns Device instance of the RTC. + * @param iReg The CMOS register index. + * @param pu8Value Where to store the CMOS register value. + * @remarks Caller enters the device critical section. + */ + DECLR3CALLBACKMEMBER(int, pfnRead,(PPDMDEVINS pDevIns, unsigned iReg, uint8_t *pu8Value)); + +} PDMRTCREG; +/** Pointer to a RTC registration structure. */ +typedef PDMRTCREG *PPDMRTCREG; +/** Pointer to a const RTC registration structure. */ +typedef const PDMRTCREG *PCPDMRTCREG; + +/** Current PDMRTCREG version number. */ +#define PDM_RTCREG_VERSION PDM_VERSION_MAKE(0xffe9, 2, 0) + + +/** + * RTC device helpers. + */ +typedef struct PDMRTCHLP +{ + /** Structure version. PDM_RTCHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /* to-be-defined */ + +} PDMRTCHLP; +/** Pointer to RTC helpers. */ +typedef PDMRTCHLP *PPDMRTCHLP; +/** Pointer to const RTC helpers. */ +typedef const PDMRTCHLP *PCPDMRTCHLP; + +/** Current PDMRTCHLP version number. */ +#define PDM_RTCHLP_VERSION PDM_VERSION_MAKE(0xffe8, 1, 0) + + + +/** @name Flags for PCI I/O region registration + * @{ */ +/** No handle is passed. */ +#define PDMPCIDEV_IORGN_F_NO_HANDLE UINT32_C(0x00000000) +/** An I/O port handle is passed. */ +#define PDMPCIDEV_IORGN_F_IOPORT_HANDLE UINT32_C(0x00000001) +/** An MMIO range handle is passed. */ +#define PDMPCIDEV_IORGN_F_MMIO_HANDLE UINT32_C(0x00000002) +/** An MMIO2 handle is passed. */ +#define PDMPCIDEV_IORGN_F_MMIO2_HANDLE UINT32_C(0x00000003) +/** Handle type mask. */ +#define PDMPCIDEV_IORGN_F_HANDLE_MASK UINT32_C(0x00000003) +/** New-style (mostly wrt callbacks). */ +#define PDMPCIDEV_IORGN_F_NEW_STYLE UINT32_C(0x00000004) +/** Mask of valid flags. */ +#define PDMPCIDEV_IORGN_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ + + +/** @name Flags for the guest physical read/write helpers + * @{ */ +/** Default flag with no indication whether the data is processed by the device or just passed through. */ +#define PDM_DEVHLP_PHYS_RW_F_DEFAULT UINT32_C(0x00000000) +/** The data is user data which is just passed through between the guest and the source or destination and not processed + * by the device in any way. */ +#define PDM_DEVHLP_PHYS_RW_F_DATA_USER RT_BIT_32(0) +/** The data is metadata and being processed by the device in some way. */ +#define PDM_DEVHLP_PHYS_RW_F_DATA_META RT_BIT_32(1) +/** @} */ + + +#ifdef IN_RING3 + +/** @name Special values for PDMDEVHLPR3::pfnPCIRegister parameters. + * @{ */ +/** Same device number (and bus) as the previous PCI device registered with the PDM device. + * This is handy when registering multiple PCI device functions and the device + * number is left up to the PCI bus. In order to facilitate one PDM device + * instance for each PCI function, this searches earlier PDM device + * instances as well. */ +# define PDMPCIDEVREG_DEV_NO_SAME_AS_PREV UINT8_C(0xfd) +/** Use the first unused device number (all functions must be unused). */ +# define PDMPCIDEVREG_DEV_NO_FIRST_UNUSED UINT8_C(0xfe) +/** Use the first unused device function. */ +# define PDMPCIDEVREG_FUN_NO_FIRST_UNUSED UINT8_C(0xff) + +/** The device and function numbers are not mandatory, just suggestions. */ +# define PDMPCIDEVREG_F_NOT_MANDATORY_NO RT_BIT_32(0) +/** Registering a PCI bridge device. */ +# define PDMPCIDEVREG_F_PCI_BRIDGE RT_BIT_32(1) +/** Valid flag mask. */ +# define PDMPCIDEVREG_F_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** Current PDMDEVHLPR3 version number. */ +#define PDM_DEVHLPR3_VERSION PDM_VERSION_MAKE_PP(0xffe7, 65, 0) + +/** + * PDM Device API. + */ +typedef struct PDMDEVHLPR3 +{ + /** Structure version. PDM_DEVHLPR3_VERSION defines the current version. */ + uint32_t u32Version; + + /** @name I/O ports + * @{ */ + /** + * Creates a range of I/O ports for a device. + * + * The I/O port range must be mapped in a separately call. Any ring-0 and + * raw-mode context callback handlers needs to be set up in the respective + * contexts. + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param cPorts Number of ports to register. + * @param fFlags IOM_IOPORT_F_XXX. + * @param pPciDev The PCI device the range is associated with, if + * applicable. + * @param iPciRegion The PCI device region in the high 16-bit word and + * sub-region in the low 16-bit word. UINT32_MAX if NA. + * @param pfnOut Pointer to function which is gonna handle OUT + * operations. Optional. + * @param pfnIn Pointer to function which is gonna handle IN operations. + * Optional. + * @param pfnOutStr Pointer to function which is gonna handle string OUT + * operations. Optional. + * @param pfnInStr Pointer to function which is gonna handle string IN + * operations. Optional. + * @param pvUser User argument to pass to the callbacks. + * @param pszDesc Pointer to description string. This must not be freed. + * @param paExtDescs Extended per-port descriptions, optional. Partial range + * coverage is allowed. This must not be freed. + * @param phIoPorts Where to return the I/O port range handle. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpIoPortSetUpContext, PDMDevHlpIoPortMap, + * PDMDevHlpIoPortUnmap. + */ + DECLR3CALLBACKMEMBER(int, pfnIoPortCreateEx,(PPDMDEVINS pDevIns, RTIOPORT cPorts, uint32_t fFlags, PPDMPCIDEV pPciDev, + uint32_t iPciRegion, PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, RTR3PTR pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts)); + + /** + * Maps an I/O port range. + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hIoPorts The I/O port range handle. + * @param Port Where to map the range. + * @sa PDMDevHlpIoPortUnmap, PDMDevHlpIoPortSetUpContext, + * PDMDevHlpIoPortCreate, PDMDevHlpIoPortCreateEx. + */ + DECLR3CALLBACKMEMBER(int, pfnIoPortMap,(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, RTIOPORT Port)); + + /** + * Unmaps an I/O port range. + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hIoPorts The I/O port range handle. + * @sa PDMDevHlpIoPortMap, PDMDevHlpIoPortSetUpContext, + * PDMDevHlpIoPortCreate, PDMDevHlpIoPortCreateEx. + */ + DECLR3CALLBACKMEMBER(int, pfnIoPortUnmap,(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts)); + + /** + * Gets the mapping address of the I/O port range @a hIoPorts. + * + * @returns Mapping address (0..65535) or UINT32_MAX if not mapped (or invalid + * parameters). + * @param pDevIns The device instance to register the ports with. + * @param hIoPorts The I/O port range handle. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnIoPortGetMappingAddress,(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts)); + + /** + * Writes to an I/O port register. + * + * @returns Strict VBox status code. Informational status codes other than the one documented + * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success. + * @retval VINF_SUCCESS Success. + * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the + * status code must be passed on to EM. + * + * @param pDevIns The device instance to register the ports with. + * @param Port The port to write to. + * @param u32Value The value to write. + * @param cbValue The size of the register to read in bytes. 1, 2 or 4 bytes. + * + * @thread EMT + * @todo r=aeichner This is only used by DevPCI.cpp to write the ELCR of the PIC. This shouldn't be done that way + * and removed again as soon as possible (no time right now)... + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnIoPortWrite,(PPDMDEVINS pDevIns, RTIOPORT Port, uint32_t u32Value, size_t cbValue)); + /** @} */ + + /** @name MMIO + * @{ */ + /** + * Creates a memory mapped I/O (MMIO) region for a device. + * + * The MMIO region must be mapped in a separately call. Any ring-0 and + * raw-mode context callback handlers needs to be set up in the respective + * contexts. + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param cbRegion The size of the region in bytes. + * @param fFlags Flags, IOMMMIO_FLAGS_XXX. + * @param pPciDev The PCI device the range is associated with, if + * applicable. + * @param iPciRegion The PCI device region in the high 16-bit word and + * sub-region in the low 16-bit word. UINT32_MAX if NA. + * @param pfnWrite Pointer to function which is gonna handle Write + * operations. + * @param pfnRead Pointer to function which is gonna handle Read + * operations. + * @param pfnFill Pointer to function which is gonna handle Fill/memset + * operations. (optional) + * @param pvUser User argument to pass to the callbacks. + * @param pszDesc Pointer to description string. This must not be freed. + * @param phRegion Where to return the MMIO region handle. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpMmioSetUpContext, PDMDevHlpMmioMap, PDMDevHlpMmioUnmap. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioCreateEx,(PPDMDEVINS pDevIns, RTGCPHYS cbRegion, + uint32_t fFlags, PPDMPCIDEV pPciDev, uint32_t iPciRegion, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, + void *pvUser, const char *pszDesc, PIOMMMIOHANDLE phRegion)); + + /** + * Maps a memory mapped I/O (MMIO) region (into the guest physical address space). + * + * @returns VBox status. + * @param pDevIns The device instance the region is associated with. + * @param hRegion The MMIO region handle. + * @param GCPhys Where to map the region. + * @note An MMIO range may overlap with base memory if a lot of RAM is + * configured for the VM, in which case we'll drop the base memory + * pages. Presently we will make no attempt to preserve anything that + * happens to be present in the base memory that is replaced, this is + * technically incorrect but it's just not worth the effort to do + * right, at least not at this point. + * @sa PDMDevHlpMmioUnmap, PDMDevHlpMmioCreate, PDMDevHlpMmioCreateEx, + * PDMDevHlpMmioSetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnMmioMap,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys)); + + /** + * Unmaps a memory mapped I/O (MMIO) region. + * + * @returns VBox status. + * @param pDevIns The device instance the region is associated with. + * @param hRegion The MMIO region handle. + * @sa PDMDevHlpMmioMap, PDMDevHlpMmioCreate, PDMDevHlpMmioCreateEx, + * PDMDevHlpMmioSetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnMmioUnmap,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)); + + /** + * Reduces the length of a MMIO range. + * + * This is for implementations of PDMPCIDEV::pfnRegionLoadChangeHookR3 and will + * only work during saved state restore. It will not call the PCI bus code, as + * that is expected to restore the saved resource configuration. + * + * It just adjusts the mapping length of the region so that when pfnMmioMap is + * called it will only map @a cbRegion bytes and not the value set during + * registration. + * + * @return VBox status code. + * @param pDevIns The device owning the range. + * @param hRegion The MMIO region handle. + * @param cbRegion The new size, must be smaller. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioReduce,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion)); + + /** + * Gets the mapping address of the MMIO region @a hRegion. + * + * @returns Mapping address, NIL_RTGCPHYS if not mapped (or invalid parameters). + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO region handle. + */ + DECLR3CALLBACKMEMBER(RTGCPHYS, pfnMmioGetMappingAddress,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)); + /** @} */ + + /** @name MMIO2 + * @{ */ + /** + * Creates a MMIO2 region. + * + * As mentioned elsewhere, MMIO2 is just RAM spelled differently. It's RAM + * associated with a device. It is also non-shared memory with a permanent + * ring-3 mapping and page backing (presently). + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param pPciDev The PCI device the region is associated with, or + * NULL if no PCI device association. + * @param iPciRegion The region number. Use the PCI region number as + * this must be known to the PCI bus device too. If + * it's not associated with the PCI device, then + * any number up to UINT8_MAX is fine. + * @param cbRegion The size (in bytes) of the region. + * @param fFlags PGMPHYS_MMIO2_FLAGS_XXX (see pgm.h). + * @param pszDesc Pointer to description string. This must not be + * freed. + * @param ppvMapping Where to store the address of the ring-3 mapping + * of the memory. + * @param phRegion Where to return the MMIO2 region handle. + * + * @thread EMT(0) + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2Create,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iPciRegion, RTGCPHYS cbRegion, + uint32_t fFlags, const char *pszDesc, void **ppvMapping, PPGMMMIO2HANDLE phRegion)); + + /** + * Destroys a MMIO2 region, unmapping it and freeing the memory. + * + * Any physical access handlers registered for the region must be deregistered + * before calling this function. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param hRegion The MMIO2 region handle. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2Destroy,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion)); + + /** + * Maps a MMIO2 region (into the guest physical address space). + * + * @returns VBox status. + * @param pDevIns The device instance the region is associated with. + * @param hRegion The MMIO2 region handle. + * @param GCPhys Where to map the region. + * @note A MMIO2 region overlap with base memory if a lot of RAM is + * configured for the VM, in which case we'll drop the base memory + * pages. Presently we will make no attempt to preserve anything that + * happens to be present in the base memory that is replaced, this is + * technically incorrect but it's just not worth the effort to do + * right, at least not at this point. + * @sa PDMDevHlpMmio2Unmap, PDMDevHlpMmio2Create, PDMDevHlpMmio2SetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2Map,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, RTGCPHYS GCPhys)); + + /** + * Unmaps a MMIO2 region. + * + * @returns VBox status. + * @param pDevIns The device instance the region is associated with. + * @param hRegion The MMIO2 region handle. + * @sa PDMDevHlpMmio2Map, PDMDevHlpMmio2Create, PDMDevHlpMmio2SetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2Unmap,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion)); + + /** + * Reduces the length of a MMIO range. + * + * This is for implementations of PDMPCIDEV::pfnRegionLoadChangeHookR3 and will + * only work during saved state restore. It will not call the PCI bus code, as + * that is expected to restore the saved resource configuration. + * + * It just adjusts the mapping length of the region so that when pfnMmioMap is + * called it will only map @a cbRegion bytes and not the value set during + * registration. + * + * @return VBox status code. + * @param pDevIns The device owning the range. + * @param hRegion The MMIO2 region handle. + * @param cbRegion The new size, must be smaller. + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2Reduce,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, RTGCPHYS cbRegion)); + + /** + * Gets the mapping address of the MMIO region @a hRegion. + * + * @returns Mapping address, NIL_RTGCPHYS if not mapped (or invalid parameters). + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO2 region handle. + */ + DECLR3CALLBACKMEMBER(RTGCPHYS, pfnMmio2GetMappingAddress,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion)); + + /** + * Queries and resets the dirty bitmap for an MMIO2 region. + * + * The MMIO2 region must have been created with the + * PGMPHYS_MMIO2_FLAGS_TRACK_DIRTY_PAGES flag for this to work. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param hRegion The MMIO2 region handle. + * @param pvBitmap Where to return the bitmap. Must be 8-byte aligned. + * Can be NULL if only resetting the tracking is desired. + * @param cbBitmap The bitmap size. One bit per page in the region, + * rounded up to 8-bytes. If pvBitmap is NULL this must + * also be zero. + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2QueryAndResetDirtyBitmap, (PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, + void *pvBitmap, size_t cbBitmap)); + + /** + * Controls the dirty page tracking for an MMIO2 region. + * + * The MMIO2 region must have been created with the + * PGMPHYS_MMIO2_FLAGS_TRACK_DIRTY_PAGES flag for this to work. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param hRegion The MMIO2 region handle. + * @param fEnabled When set to @c true the dirty page tracking will be + * enabled if currently disabled (bitmap is reset). When + * set to @c false the dirty page tracking will be + * disabled. + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2ControlDirtyPageTracking, (PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, bool fEnabled)); + + /** + * Changes the number of an MMIO2 or pre-registered MMIO region. + * + * This should only be used to deal with saved state problems, so there is no + * convenience inline wrapper for this method. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param hRegion The MMIO2 region handle. + * @param iNewRegion The new region index. + * + * @sa @bugref{9359} + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2ChangeRegionNo,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, uint32_t iNewRegion)); + + /** + * Mapping an MMIO2 page in place of an MMIO page for direct access. + * + * This is a special optimization used by the VGA device. Call + * PDMDevHlpMmioResetRegion() to undo the mapping. + * + * @returns VBox status code. This API may return VINF_SUCCESS even if no + * remapping is made. + * @retval VERR_SEM_BUSY in ring-0 if we cannot get the IOM lock. + * + * @param pDevIns The device instance @a hRegion and @a hMmio2 are + * associated with. + * @param hRegion The handle to the MMIO region. + * @param offRegion The offset into @a hRegion of the page to be + * remapped. + * @param hMmio2 The MMIO2 handle. + * @param offMmio2 Offset into @a hMmio2 of the page to be use for the + * mapping. + * @param fPageFlags Page flags to set. Must be (X86_PTE_RW | X86_PTE_P) + * for the time being. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioMapMmio2Page,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS offRegion, + uint64_t hMmio2, RTGCPHYS offMmio2, uint64_t fPageFlags)); + + /** + * Reset a previously modified MMIO region; restore the access flags. + * + * This undoes the effects of PDMDevHlpMmioMapMmio2Page() and is currently only + * intended for some ancient VGA hack. However, it would be great to extend it + * beyond VT-x and/or nested-paging. + * + * @returns VBox status code. + * + * @param pDevIns The device instance @a hRegion is associated with. + * @param hRegion The handle to the MMIO region. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioResetRegion, (PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)); + /** @} */ + + /** + * Register a ROM (BIOS) region. + * + * It goes without saying that this is read-only memory. The memory region must be + * in unassigned memory. I.e. from the top of the address space or on the PC in + * the 0xa0000-0xfffff range. + * + * @returns VBox status. + * @param pDevIns The device instance owning the ROM region. + * @param GCPhysStart First physical address in the range. + * Must be page aligned! + * @param cbRange The size of the range (in bytes). + * Must be page aligned! + * @param pvBinary Pointer to the binary data backing the ROM image. + * @param cbBinary The size of the binary pointer. This must + * be equal or smaller than @a cbRange. + * @param fFlags PGMPHYS_ROM_FLAGS_XXX (see pgm.h). + * @param pszDesc Pointer to description string. This must not be freed. + * + * @remark There is no way to remove the rom, automatically on device cleanup or + * manually from the device yet. At present I doubt we need such features... + */ + DECLR3CALLBACKMEMBER(int, pfnROMRegister,(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, + const void *pvBinary, uint32_t cbBinary, uint32_t fFlags, const char *pszDesc)); + + /** + * Changes the protection of shadowed ROM mapping. + * + * This is intented for use by the system BIOS, chipset or device in question to + * change the protection of shadowed ROM code after init and on reset. + * + * @param pDevIns The device instance. + * @param GCPhysStart Where the mapping starts. + * @param cbRange The size of the mapping. + * @param enmProt The new protection type. + */ + DECLR3CALLBACKMEMBER(int, pfnROMProtectShadow,(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, PGMROMPROT enmProt)); + + /** + * Register a save state data unit. + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * @param pszBefore Name of data unit which we should be put in + * front of. Optional (NULL). + * + * @param pfnLivePrep Prepare live save callback, optional. + * @param pfnLiveExec Execute live save callback, optional. + * @param pfnLiveVote Vote live save callback, optional. + * + * @param pfnSavePrep Prepare save callback, optional. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnSaveDone Done save callback, optional. + * + * @param pfnLoadPrep Prepare load callback, optional. + * @param pfnLoadExec Execute load callback, optional. + * @param pfnLoadDone Done load callback, optional. + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + */ + DECLR3CALLBACKMEMBER(int, pfnSSMRegister,(PPDMDEVINS pDevIns, uint32_t uVersion, size_t cbGuess, const char *pszBefore, + PFNSSMDEVLIVEPREP pfnLivePrep, PFNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVLIVEVOTE pfnLiveVote, + PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone, + PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone)); + + /** + * Register a save state data unit for backward compatibility. + * + * This is for migrating from an old device name to a new one or for merging + * devices. It will only help loading old saved states. + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param pszOldName The old unit name. + * @param pfnLoadPrep Prepare load callback, optional. + * @param pfnLoadExec Execute load callback, optional. + * @param pfnLoadDone Done load callback, optional. + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + */ + DECLR3CALLBACKMEMBER(int, pfnSSMRegisterLegacy,(PPDMDEVINS pDevIns, const char *pszOldName, PFNSSMDEVLOADPREP pfnLoadPrep, + PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone)); + + /** @name Exported SSM Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnSSMPutStruct,(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStructEx,(PSSMHANDLE pSSM, const void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutBool,(PSSMHANDLE pSSM, bool fBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU8,(PSSMHANDLE pSSM, uint8_t u8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS8,(PSSMHANDLE pSSM, int8_t i8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU16,(PSSMHANDLE pSSM, uint16_t u16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS16,(PSSMHANDLE pSSM, int16_t i16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU32,(PSSMHANDLE pSSM, uint32_t u32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS32,(PSSMHANDLE pSSM, int32_t i32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU64,(PSSMHANDLE pSSM, uint64_t u64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS64,(PSSMHANDLE pSSM, int64_t i64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU128,(PSSMHANDLE pSSM, uint128_t u128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS128,(PSSMHANDLE pSSM, int128_t i128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutUInt,(PSSMHANDLE pSSM, RTUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSInt,(PSSMHANDLE pSSM, RTINT i)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUInt,(PSSMHANDLE pSSM, RTGCUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntReg,(PSSMHANDLE pSSM, RTGCUINTREG u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys32,(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys64,(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys,(PSSMHANDLE pSSM, RTGCPHYS GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPtr,(PSSMHANDLE pSSM, RTGCPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntPtr,(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutRCPtr,(PSSMHANDLE pSSM, RTRCPTR RCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutIOPort,(PSSMHANDLE pSSM, RTIOPORT IOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSel,(PSSMHANDLE pSSM, RTSEL Sel)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutMem,(PSSMHANDLE pSSM, const void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStrZ,(PSSMHANDLE pSSM, const char *psz)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStruct,(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStructEx,(PSSMHANDLE pSSM, void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBool,(PSSMHANDLE pSSM, bool *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBoolV,(PSSMHANDLE pSSM, bool volatile *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8,(PSSMHANDLE pSSM, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8V,(PSSMHANDLE pSSM, uint8_t volatile *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8,(PSSMHANDLE pSSM, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8V,(PSSMHANDLE pSSM, int8_t volatile *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16,(PSSMHANDLE pSSM, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16V,(PSSMHANDLE pSSM, uint16_t volatile *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16,(PSSMHANDLE pSSM, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16V,(PSSMHANDLE pSSM, int16_t volatile *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32,(PSSMHANDLE pSSM, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32V,(PSSMHANDLE pSSM, uint32_t volatile *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32,(PSSMHANDLE pSSM, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32V,(PSSMHANDLE pSSM, int32_t volatile *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64,(PSSMHANDLE pSSM, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64V,(PSSMHANDLE pSSM, uint64_t volatile *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64,(PSSMHANDLE pSSM, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64V,(PSSMHANDLE pSSM, int64_t volatile *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128,(PSSMHANDLE pSSM, uint128_t *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128V,(PSSMHANDLE pSSM, uint128_t volatile *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128,(PSSMHANDLE pSSM, int128_t *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128V,(PSSMHANDLE pSSM, int128_t volatile *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32,(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32V,(PSSMHANDLE pSSM, RTGCPHYS32 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64,(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64V,(PSSMHANDLE pSSM, RTGCPHYS64 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys,(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhysV,(PSSMHANDLE pSSM, RTGCPHYS volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetUInt,(PSSMHANDLE pSSM, PRTUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSInt,(PSSMHANDLE pSSM, PRTINT pi)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUInt,(PSSMHANDLE pSSM, PRTGCUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntReg,(PSSMHANDLE pSSM, PRTGCUINTREG pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPtr,(PSSMHANDLE pSSM, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntPtr,(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetRCPtr,(PSSMHANDLE pSSM, PRTRCPTR pRCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetIOPort,(PSSMHANDLE pSSM, PRTIOPORT pIOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSel,(PSSMHANDLE pSSM, PRTSEL pSel)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetMem,(PSSMHANDLE pSSM, void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZ,(PSSMHANDLE pSSM, char *psz, size_t cbMax)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZEx,(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkip,(PSSMHANDLE pSSM, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkipToEndOfUnit,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadError,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadErrorV,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgError,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgErrorV,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMHandleGetStatus,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(SSMAFTER, pfnSSMHandleGetAfter,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(bool, pfnSSMHandleIsLiveSave,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleMaxDowntime,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleHostBits,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleRevision,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleVersion,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(const char *, pfnSSMHandleHostOSAndArch,(PSSMHANDLE pSSM)); + /** @} */ + + /** + * Creates a timer w/ a cross context handle. + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param enmClock The clock to use on this timer. + * @param pfnCallback Callback function. + * @param pvUser User argument for the callback. + * @param fFlags Flags, see TMTIMER_FLAGS_*. + * @param pszDesc Pointer to description string which must stay around + * until the timer is fully destroyed (i.e. a bit after TMTimerDestroy()). + * @param phTimer Where to store the timer handle on success. + * @remarks Caller enters the device critical section prior to invoking the + * callback. + */ + DECLR3CALLBACKMEMBER(int, pfnTimerCreate,(PPDMDEVINS pDevIns, TMCLOCK enmClock, PFNTMTIMERDEV pfnCallback, + void *pvUser, uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer)); + + /** @name Timer handle method wrappers + * @{ */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromMicro,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromMilli,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGet,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGetFreq,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGetNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(bool, pfnTimerIsActive,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(bool, pfnTimerIsLockOwner,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnTimerLockClock,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, int rcBusy)); + /** Takes the clock lock then enters the specified critical section. */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnTimerLockClock2,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR3CALLBACKMEMBER(int, pfnTimerSet,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t uExpire)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetFrequencyHint,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint32_t uHz)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetMicro,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetMillies,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetRelative,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now)); + DECLR3CALLBACKMEMBER(int, pfnTimerStop,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(void, pfnTimerUnlockClock,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(void, pfnTimerUnlockClock2,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetCritSect,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnTimerSave,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnTimerLoad,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnTimerDestroy,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + /** @sa TMR3TimerSkip */ + DECLR3CALLBACKMEMBER(int, pfnTimerSkipLoad,(PSSMHANDLE pSSM, bool *pfActive)); + /** @} */ + + /** + * Get the real world UTC time adjusted for VM lag, user offset and warpdrive. + * + * @returns pTime. + * @param pDevIns The device instance. + * @param pTime Where to store the time. + */ + DECLR3CALLBACKMEMBER(PRTTIMESPEC, pfnTMUtcNow,(PPDMDEVINS pDevIns, PRTTIMESPEC pTime)); + + /** @name Exported CFGM Functions. + * @{ */ + DECLR3CALLBACKMEMBER(bool, pfnCFGMExists,( PCFGMNODE pNode, const char *pszName)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryType,( PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySize,( PCFGMNODE pNode, const char *pszName, size_t *pcb)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryInteger,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryIntegerDef,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryString,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringDef,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPassword,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPasswordDef,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBytes,( PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64Def,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64,( PCFGMNODE pNode, const char *pszName, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64Def,( PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32Def,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32,( PCFGMNODE pNode, const char *pszName, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32Def,( PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16Def,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16,( PCFGMNODE pNode, const char *pszName, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16Def,( PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8Def,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8,( PCFGMNODE pNode, const char *pszName, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8Def,( PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBool,( PCFGMNODE pNode, const char *pszName, bool *pf)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBoolDef,( PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPort,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPortDef,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUInt,( PCFGMNODE pNode, const char *pszName, unsigned int *pu)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUIntDef,( PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySInt,( PCFGMNODE pNode, const char *pszName, signed int *pi)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySIntDef,( PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtr,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrDef,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrU,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrUDef,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrS,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrSDef,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAlloc,( PCFGMNODE pNode, const char *pszName, char **ppszString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAllocDef,(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetParent,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChild,(PCFGMNODE pNode, const char *pszPath)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildF,(PCFGMNODE pNode, const char *pszPathFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildFV,(PCFGMNODE pNode, const char *pszPathFormat, va_list Args) RT_IPRT_FORMAT_ATTR(3, 0)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetFirstChild,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetNextChild,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetName,(PCFGMNODE pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetNameLen,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreChildrenValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetFirstValue,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetNextValue,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetValueName,(PCFGMLEAF pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetValueNameLen,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(CFGMVALUETYPE, pfnCFGMGetValueType,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreValuesValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(int, pfnCFGMValidateConfig,(PCFGMNODE pNode, const char *pszNode, + const char *pszValidValues, const char *pszValidNodes, + const char *pszWho, uint32_t uInstance)); + /** @} */ + + /** + * Read physical memory. + * + * @returns VINF_SUCCESS (for now). + * @param pDevIns The device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * Write to physical memory. + * + * @returns VINF_SUCCESS for now, and later maybe VERR_EM_MEMORY. + * @param pDevIns The device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * Requests the mapping of a guest page into ring-3. + * + * When you're done with the page, call pfnPhysReleasePageMappingLock() ASAP to + * release it. + * + * This API will assume your intention is to write to the page, and will + * therefore replace shared and zero pages. If you do not intend to modify the + * page, use the pfnPhysGCPhys2CCPtrReadOnly() API. + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical + * backing or if the page has any active access handlers. The caller + * must fall back on using PGMR3PhysWriteExternal. + * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address. + * + * @param pDevIns The device instance. + * @param GCPhys The guest physical address of the page that + * should be mapped. + * @param fFlags Flags reserved for future use, MBZ. + * @param ppv Where to store the address corresponding to + * GCPhys. + * @param pLock Where to store the lock information that + * pfnPhysReleasePageMappingLock needs. + * + * @remark Avoid calling this API from within critical sections (other than the + * PGM one) because of the deadlock risk when we have to delegating the + * task to an EMT. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysGCPhys2CCPtr,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t fFlags, void **ppv, + PPGMPAGEMAPLOCK pLock)); + + /** + * Requests the mapping of a guest page into ring-3, external threads. + * + * When you're done with the page, call pfnPhysReleasePageMappingLock() ASAP to + * release it. + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical + * backing or if the page as an active ALL access handler. The caller + * must fall back on using PGMPhysRead. + * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address. + * + * @param pDevIns The device instance. + * @param GCPhys The guest physical address of the page that + * should be mapped. + * @param fFlags Flags reserved for future use, MBZ. + * @param ppv Where to store the address corresponding to + * GCPhys. + * @param pLock Where to store the lock information that + * pfnPhysReleasePageMappingLock needs. + * + * @remark Avoid calling this API from within critical sections. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysGCPhys2CCPtrReadOnly,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t fFlags, + void const **ppv, PPGMPAGEMAPLOCK pLock)); + + /** + * Release the mapping of a guest page. + * + * This is the counter part of pfnPhysGCPhys2CCPtr and + * pfnPhysGCPhys2CCPtrReadOnly. + * + * @param pDevIns The device instance. + * @param pLock The lock structure initialized by the mapping + * function. + */ + DECLR3CALLBACKMEMBER(void, pfnPhysReleasePageMappingLock,(PPDMDEVINS pDevIns, PPGMPAGEMAPLOCK pLock)); + + /** + * Read guest physical memory by virtual address. + * + * @param pDevIns The device instance. + * @param pvDst Where to put the read bits. + * @param GCVirtSrc Guest virtual address to start reading from. + * @param cb How many bytes to read. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysReadGCVirt,(PPDMDEVINS pDevIns, void *pvDst, RTGCPTR GCVirtSrc, size_t cb)); + + /** + * Write to guest physical memory by virtual address. + * + * @param pDevIns The device instance. + * @param GCVirtDst Guest virtual address to write to. + * @param pvSrc What to write. + * @param cb How many bytes to write. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysWriteGCVirt,(PPDMDEVINS pDevIns, RTGCPTR GCVirtDst, const void *pvSrc, size_t cb)); + + /** + * Convert a guest virtual address to a guest physical address. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPtr Guest virtual address. + * @param pGCPhys Where to store the GC physical address + * corresponding to GCPtr. + * @thread The emulation thread. + * @remark Careful with page boundaries. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysGCPtr2GCPhys, (PPDMDEVINS pDevIns, RTGCPTR GCPtr, PRTGCPHYS pGCPhys)); + + /** + * Checks if a GC physical address is a normal page, + * i.e. not ROM, MMIO or reserved. + * + * @returns true if normal. + * @returns false if invalid, ROM, MMIO or reserved page. + * @param pDevIns The device instance. + * @param GCPhys The physical address to check. + */ + DECLR3CALLBACKMEMBER(bool, pfnPhysIsGCPhysNormal,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys)); + + /** + * Inflate or deflate a memory balloon + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param fInflate Inflate or deflate memory balloon + * @param cPages Number of pages to free + * @param paPhysPage Array of guest physical addresses + */ + DECLR3CALLBACKMEMBER(int, pfnPhysChangeMemBalloon,(PPDMDEVINS pDevIns, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage)); + + /** + * Allocate memory which is associated with current VM instance + * and automatically freed on it's destruction. + * + * @returns Pointer to allocated memory. The memory is *NOT* zero-ed. + * @param pDevIns The device instance. + * @param cb Number of bytes to allocate. + */ + DECLR3CALLBACKMEMBER(void *, pfnMMHeapAlloc,(PPDMDEVINS pDevIns, size_t cb)); + + /** + * Allocate memory which is associated with current VM instance + * and automatically freed on it's destruction. The memory is ZEROed. + * + * @returns Pointer to allocated memory. The memory is *NOT* zero-ed. + * @param pDevIns The device instance. + * @param cb Number of bytes to allocate. + */ + DECLR3CALLBACKMEMBER(void *, pfnMMHeapAllocZ,(PPDMDEVINS pDevIns, size_t cb)); + + /** + * Allocating string printf. + * + * @returns Pointer to the string. + * @param pDevIns The device instance. + * @param enmTag The statistics tag. + * @param pszFormat The format string. + * @param va Format arguments. + */ + DECLR3CALLBACKMEMBER(char *, pfnMMHeapAPrintfV,(PPDMDEVINS pDevIns, MMTAG enmTag, const char *pszFormat, va_list va)); + + /** + * Free memory allocated with pfnMMHeapAlloc() and pfnMMHeapAllocZ(). + * + * @param pDevIns The device instance. + * @param pv Pointer to the memory to free. + */ + DECLR3CALLBACKMEMBER(void, pfnMMHeapFree,(PPDMDEVINS pDevIns, void *pv)); + + /** + * Returns the physical RAM size of the VM. + * + * @returns RAM size in bytes. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnMMPhysGetRamSize,(PPDMDEVINS pDevIns)); + + /** + * Returns the physical RAM size of the VM below the 4GB boundary. + * + * @returns RAM size in bytes. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnMMPhysGetRamSizeBelow4GB,(PPDMDEVINS pDevIns)); + + /** + * Returns the physical RAM size of the VM above the 4GB boundary. + * + * @returns RAM size in bytes. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnMMPhysGetRamSizeAbove4GB,(PPDMDEVINS pDevIns)); + + /** + * Gets the VM state. + * + * @returns VM state. + * @param pDevIns The device instance. + * @thread Any thread (just keep in mind that it's volatile info). + */ + DECLR3CALLBACKMEMBER(VMSTATE, pfnVMState, (PPDMDEVINS pDevIns)); + + /** + * Checks if the VM was teleported and hasn't been fully resumed yet. + * + * @returns true / false. + * @param pDevIns The device instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnVMTeleportedAndNotFullyResumedYet,(PPDMDEVINS pDevIns)); + + /** + * Set the VM error message + * + * @returns rc. + * @param pDevIns The device instance. + * @param rc VBox status code. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetErrorV,(PPDMDEVINS pDevIns, int rc, RT_SRC_POS_DECL, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetRuntimeErrorV,(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(4, 0)); + + /** + * Special interface for implementing a HLT-like port on a device. + * + * This can be called directly from device code, provide the device is trusted + * to access the VMM directly. Since we may not have an accurate register set + * and the caller certainly shouldn't (device code does not access CPU + * registers), this function will return when interrupts are pending regardless + * of the actual EFLAGS.IF state. + * + * @returns VBox error status (never informational statuses). + * @param pDevIns The device instance. + * @param idCpu The id of the calling EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnVMWaitForDeviceReady,(PPDMDEVINS pDevIns, VMCPUID idCpu)); + + /** + * Wakes up a CPU that has called PDMDEVHLPR3::pfnVMWaitForDeviceReady. + * + * @returns VBox error status (never informational statuses). + * @param pDevIns The device instance. + * @param idCpu The id of the calling EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnVMNotifyCpuDeviceReady,(PPDMDEVINS pDevIns, VMCPUID idCpu)); + + /** + * Convenience wrapper for VMR3ReqCallU. + * + * This assumes (1) you're calling a function that returns an VBox status code + * and that you do not wish to wait for it to complete. + * + * @returns VBox status code returned by VMR3ReqCallVU. + * + * @param pDevIns The device instance. + * @param idDstCpu The destination CPU(s). Either a specific CPU ID or + * one of the following special values: + * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param Args Argument vector. + * + * @remarks See remarks on VMR3ReqCallVU. + */ + DECLR3CALLBACKMEMBER(int, pfnVMReqCallNoWaitV,(PPDMDEVINS pDevIns, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, va_list Args)); + + /** + * Convenience wrapper for VMR3ReqCallU. + * + * This assumes (1) you're calling a function that returns void, (2) that you + * wish to wait for ever for it to return, and (3) that it's priority request + * that can be safely be handled during async suspend and power off. + * + * @returns VBox status code of VMR3ReqCallVU. + * + * @param pDevIns The device instance. + * @param idDstCpu The destination CPU(s). Either a specific CPU ID or + * one of the following special values: + * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param Args Argument vector. + * + * @remarks See remarks on VMR3ReqCallVU. + */ + DECLR3CALLBACKMEMBER(int, pfnVMReqPriorityCallWaitV,(PPDMDEVINS pDevIns, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, va_list Args)); + + /** + * Stops the VM and enters the debugger to look at the guest state. + * + * Use the PDMDeviceDBGFStop() inline function with the RT_SRC_POS macro instead of + * invoking this function directly. + * + * @returns VBox status code which must be passed up to the VMM. + * @param pDevIns The device instance. + * @param pszFile Filename of the assertion location. + * @param iLine The linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + * @param pszFormat Message. (optional) + * @param args Message parameters. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFStopV,(PPDMDEVINS pDevIns, const char *pszFile, unsigned iLine, const char *pszFunction, + const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(5, 0)); + + /** + * Register a info handler with DBGF. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszName The identifier of the info. + * @param pszDesc The description of the info and any arguments + * the handler may take. + * @param pfnHandler The handler function to be called to display the + * info. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFInfoRegister,(PPDMDEVINS pDevIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDEV pfnHandler)); + + /** + * Register a info handler with DBGF, argv style. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszName The identifier of the info. + * @param pszDesc The description of the info and any arguments + * the handler may take. + * @param pfnHandler The handler function to be called to display the + * info. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFInfoRegisterArgv,(PPDMDEVINS pDevIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDEV pfnHandler)); + + /** + * Registers a set of registers for a device. + * + * The @a pvUser argument of the getter and setter callbacks will be + * @a pDevIns. The register names will be prefixed by the device name followed + * immediately by the instance number. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param paRegisters The register descriptors. + * + * @remarks The device critical section is NOT entered prior to working the + * callbacks registered via this helper! + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFRegRegister,(PPDMDEVINS pDevIns, PCDBGFREGDESC paRegisters)); + + /** + * Gets the trace buffer handle. + * + * This is used by the macros found in VBox/vmm/dbgftrace.h and is not + * really inteded for direct usage, thus no inline wrapper function. + * + * @returns Trace buffer handle or NIL_RTTRACEBUF. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(RTTRACEBUF, pfnDBGFTraceBuf,(PPDMDEVINS pDevIns)); + + /** + * Report a bug check. + * + * @returns + * @param pDevIns The device instance. + * @param enmEvent The kind of BSOD event this is. + * @param uBugCheck The bug check number. + * @param uP1 The bug check parameter \#1. + * @param uP2 The bug check parameter \#2. + * @param uP3 The bug check parameter \#3. + * @param uP4 The bug check parameter \#4. + * + * @thread EMT + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnDBGFReportBugCheck,(PPDMDEVINS pDevIns, DBGFEVENTTYPE enmEvent, uint64_t uBugCheck, + uint64_t uP1, uint64_t uP2, uint64_t uP3, uint64_t uP4)); + + /** + * Write core dump of the guest. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszFilename The name of the file to which the guest core + * dump should be written. + * @param fReplaceFile Whether to replace the file or not. + * + * @remarks The VM may need to be suspended before calling this function in + * order to truly stop all device threads and drivers. This function + * only synchronizes EMTs. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFCoreWrite,(PPDMDEVINS pDevIns, const char *pszFilename, bool fReplaceFile)); + + /** + * Gets the logger info helper. + * The returned info helper will unconditionally write all output to the log. + * + * @returns Pointer to the logger info helper. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PCDBGFINFOHLP, pfnDBGFInfoLogHlp,(PPDMDEVINS pDevIns)); + + /** + * Queries a 64-bit register value. + * + * @retval VINF_SUCCESS + * @retval VERR_INVALID_VM_HANDLE + * @retval VERR_INVALID_CPU_ID + * @retval VERR_DBGF_REGISTER_NOT_FOUND + * @retval VERR_DBGF_UNSUPPORTED_CAST + * @retval VINF_DBGF_TRUNCATED_REGISTER + * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER + * + * @param pDevIns The device instance. + * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not + * applicable. Can be OR'ed with + * DBGFREG_HYPER_VMCPUID. + * @param pszReg The register that's being queried. Except for + * CPU registers, this must be on the form + * "set.reg[.sub]". + * @param pu64 Where to store the register value. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFRegNmQueryU64,(PPDMDEVINS pDevIns, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64)); + + /** + * Format a set of registers. + * + * This is restricted to registers from one CPU, that specified by @a idCpu. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param idCpu The CPU ID of any CPU registers that may be + * printed, pass VMCPUID_ANY if not applicable. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pszFormat The format string. Register names are given by + * %VR{name}, they take no arguments. + * @param va Other format arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFRegPrintfV,(PPDMDEVINS pDevIns, VMCPUID idCpu, char *pszBuf, size_t cbBuf, + const char *pszFormat, va_list va)); + + /** + * Registers a statistics sample. + * + * @param pDevIns Device instance of the DMA. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is + * pointing at. + * @param pszName Sample name, unix path style. If this does not + * start with a '/', the default prefix will be + * prepended, otherwise it will be used as-is. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegister,(PPDMDEVINS pDevIns, void *pvSample, STAMTYPE enmType, const char *pszName, STAMUNIT enmUnit, const char *pszDesc)); + + /** + * Same as pfnSTAMRegister except that the name is specified in a + * RTStrPrintfV like fashion. + * + * @returns VBox status. + * @param pDevIns Device instance of the DMA. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is + * pointing at. + * @param enmVisibility Visibility type specifying whether unused + * statistics should be visible or not. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + * @param pszName Sample name format string, unix path style. If + * this does not start with a '/', the default + * prefix will be prepended, otherwise it will be + * used as-is. + * @param args Arguments to the format string. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegisterV,(PPDMDEVINS pDevIns, void *pvSample, STAMTYPE enmType, + STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, const char *pszDesc, + const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(7, 0)); + + /** + * Registers a PCI device with the default PCI bus. + * + * If a PDM device has more than one PCI device, they must be registered in the + * order of PDMDEVINSR3::apPciDevs. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. + * This must be kept in the instance data. + * The PCI configuration must be initialized before registration. + * @param fFlags 0, PDMPCIDEVREG_F_PCI_BRIDGE or + * PDMPCIDEVREG_F_NOT_MANDATORY_NO. + * @param uPciDevNo PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, + * PDMPCIDEVREG_DEV_NO_SAME_AS_PREV, or a specific + * device number (0-31). This will be ignored if + * the CFGM configuration contains a PCIDeviceNo + * value. + * @param uPciFunNo PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, or a specific + * function number (0-7). This will be ignored if + * the CFGM configuration contains a PCIFunctionNo + * value. + * @param pszName Device name, if NULL PDMDEVREG::szName is used. + * The pointer is saved, so don't free or changed. + * @note The PCI device configuration is now implicit from the apPciDevs + * index, meaning that the zero'th entry is the primary one and + * subsequent uses CFGM subkeys "PciDev1", "PciDev2" and so on. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIRegister,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags, + uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)); + + /** + * Initialize MSI or MSI-X emulation support for the given PCI device. + * + * @see PDMPCIBUSREG::pfnRegisterMsiR3 for details. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device. NULL is an alias for the first + * one registered. + * @param pMsiReg MSI emulation registration structure. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIRegisterMsi,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PPDMMSIREG pMsiReg)); + + /** + * Registers a I/O region (memory mapped or I/O ports) for a PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param enmType PCI_ADDRESS_SPACE_MEM, PCI_ADDRESS_SPACE_IO or PCI_ADDRESS_SPACE_MEM_PREFETCH. + * @param fFlags PDMPCIDEV_IORGN_F_XXX. + * @param hHandle An I/O port, MMIO or MMIO2 handle according to + * @a fFlags, UINT64_MAX if no handle is passed + * (old style). + * @param pfnMapUnmap Callback for doing the mapping, optional when a + * handle is specified. The callback will be + * invoked holding only the PDM lock. The device + * lock will _not_ be taken (due to lock order). + */ + DECLR3CALLBACKMEMBER(int, pfnPCIIORegionRegister,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, + RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, uint32_t fFlags, + uint64_t hHandle, PFNPCIIOREGIONMAP pfnMapUnmap)); + + /** + * Register PCI configuration space read/write callbacks. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param pfnRead Pointer to the user defined PCI config read function. + * to call default PCI config read function. Can be NULL. + * @param pfnWrite Pointer to the user defined PCI config write function. + * @remarks The callbacks will be invoked holding the PDM lock. The device lock + * is NOT take because that is very likely be a lock order violation. + * @thread EMT(0) + * @note Only callable during VM creation. + * @sa PDMDevHlpPCIConfigRead, PDMDevHlpPCIConfigWrite + */ + DECLR3CALLBACKMEMBER(int, pfnPCIInterceptConfigAccesses,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + PFNPCICONFIGREAD pfnRead, PFNPCICONFIGWRITE pfnWrite)); + + /** + * Perform a PCI configuration space write. + * + * This is for devices that make use of PDMDevHlpPCIInterceptConfigAccesses(). + * + * @returns Strict VBox status code (mainly DBGFSTOP). + * @param pDevIns The device instance. + * @param pPciDev The PCI device which config space is being read. + * @param uAddress The config space address. + * @param cb The size of the read: 1, 2 or 4 bytes. + * @param u32Value The value to write. + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnPCIConfigWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t u32Value)); + + /** + * Perform a PCI configuration space read. + * + * This is for devices that make use of PDMDevHlpPCIInterceptConfigAccesses(). + * + * @returns Strict VBox status code (mainly DBGFSTOP). + * @param pDevIns The device instance. + * @param pPciDev The PCI device which config space is being read. + * @param uAddress The config space address. + * @param cb The size of the read: 1, 2 or 4 bytes. + * @param pu32Value Where to return the value. + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnPCIConfigRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t *pu32Value)); + + /** + * Bus master physical memory read. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * Bus master physical memory write. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * Requests the mapping of a guest page into ring-3 in preparation for a bus master + * physical memory write operation. + * + * Refer pfnPhysGCPhys2CCPtr() for further details. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys The guest physical address of the page that should be + * mapped. + * @param fFlags Flags reserved for future use, MBZ. + * @param ppv Where to store the address corresponding to GCPhys. + * @param pLock Where to store the lock information that + * pfnPhysReleasePageMappingLock needs. + * + * @remarks Avoid calling this API from within critical sections (other than the PGM + * one) because of the deadlock risk when we have to delegating the task to + * an EMT. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysGCPhys2CCPtr,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, uint32_t fFlags, + void **ppv, PPGMPAGEMAPLOCK pLock)); + + /** + * Requests the mapping of a guest page into ring-3, external threads, in prepartion + * for a bus master physical memory read operation. + * + * Refer pfnPhysGCPhys2CCPtrReadOnly() for further details. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys The guest physical address of the page that + * should be mapped. + * @param fFlags Flags reserved for future use, MBZ. + * @param ppv Where to store the address corresponding to + * GCPhys. + * @param pLock Where to store the lock information that + * pfnPhysReleasePageMappingLock needs. + * + * @remarks Avoid calling this API from within critical sections. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysGCPhys2CCPtrReadOnly,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, + uint32_t fFlags, void const **ppv, PPGMPAGEMAPLOCK pLock)); + + /** + * Requests the mapping of multiple guest pages into ring-3 in prepartion for a bus + * master physical memory write operation. + * + * When you're done with the pages, call pfnPhysBulkReleasePageMappingLocks() + * ASAP to release them. + * + * Refer pfnPhysBulkGCPhys2CCPtr() for further details. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param cPages Number of pages to lock. + * @param paGCPhysPages The guest physical address of the pages that + * should be mapped (@a cPages entries). + * @param fFlags Flags reserved for future use, MBZ. + * @param papvPages Where to store the ring-3 mapping addresses + * corresponding to @a paGCPhysPages. + * @param paLocks Where to store the locking information that + * pfnPhysBulkReleasePageMappingLock needs (@a cPages + * in length). + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysBulkGCPhys2CCPtr,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t cPages, + PCRTGCPHYS paGCPhysPages, uint32_t fFlags, void **papvPages, + PPGMPAGEMAPLOCK paLocks)); + + /** + * Requests the mapping of multiple guest pages into ring-3 in preparation for a bus + * master physical memory read operation. + * + * When you're done with the pages, call pfnPhysBulkReleasePageMappingLocks() + * ASAP to release them. + * + * Refer pfnPhysBulkGCPhys2CCPtrReadOnly() for further details. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param cPages Number of pages to lock. + * @param paGCPhysPages The guest physical address of the pages that + * should be mapped (@a cPages entries). + * @param fFlags Flags reserved for future use, MBZ. + * @param papvPages Where to store the ring-3 mapping addresses + * corresponding to @a paGCPhysPages. + * @param paLocks Where to store the lock information that + * pfnPhysReleasePageMappingLock needs (@a cPages + * in length). + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysBulkGCPhys2CCPtrReadOnly,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t cPages, + PCRTGCPHYS paGCPhysPages, uint32_t fFlags, + void const **papvPages, PPGMPAGEMAPLOCK paLocks)); + + /** + * Sets the IRQ for the given PCI device. + * + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnPCISetIrq,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)); + + /** + * Sets the IRQ for the given PCI device, but doesn't wait for EMT to process + * the request when not called from EMT. + * + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnPCISetIrqNoWait,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)); + + /** + * Set ISA IRQ for a device. + * + * @param pDevIns The device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnISASetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** + * Set the ISA IRQ for a device, but don't wait for EMT to process + * the request when not called from EMT. + * + * @param pDevIns The device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnISASetIrqNoWait,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** + * Attaches a driver (chain) to the device. + * + * The first call for a LUN this will serve as a registration of the LUN. The pBaseInterface and + * the pszDesc string will be registered with that LUN and kept around for PDMR3QueryDeviceLun(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iLun The logical unit to attach. + * @param pBaseInterface Pointer to the base interface for that LUN. (device side / down) + * @param ppBaseInterface Where to store the pointer to the base interface. (driver side / up) + * @param pszDesc Pointer to a string describing the LUN. This string must remain valid + * for the live of the device instance. + */ + DECLR3CALLBACKMEMBER(int, pfnDriverAttach,(PPDMDEVINS pDevIns, uint32_t iLun, PPDMIBASE pBaseInterface, + PPDMIBASE *ppBaseInterface, const char *pszDesc)); + + /** + * Detaches an attached driver (chain) from the device again. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pDrvIns The driver instance to detach. + * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines. + */ + DECLR3CALLBACKMEMBER(int, pfnDriverDetach,(PPDMDEVINS pDevIns, PPDMDRVINS pDrvIns, uint32_t fFlags)); + + /** + * Reconfigures the driver chain for a LUN, detaching any driver currently + * present there. + * + * Caller will have attach it, of course. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iLun The logical unit to reconfigure. + * @param cDepth The depth of the driver chain. Determins the + * size of @a papszDrivers and @a papConfigs. + * @param papszDrivers The names of the drivers to configure in the + * chain, first entry is the one immediately + * below the device/LUN + * @param papConfigs The configurations for each of the drivers + * in @a papszDrivers array. NULL entries + * corresponds to empty 'Config' nodes. This + * function will take ownership of non-NULL + * CFGM sub-trees and set the array member to + * NULL, so the caller can do cleanups on + * failure. This parameter is optional. + * @param fFlags Reserved, MBZ. + */ + DECLR3CALLBACKMEMBER(int, pfnDriverReconfigure,(PPDMDEVINS pDevIns, uint32_t iLun, uint32_t cDepth, + const char * const *papszDrivers, PCFGMNODE *papConfigs, uint32_t fFlags)); + + /** @name Exported PDM Queue Functions + * @{ */ + /** + * Create a queue. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param cbItem The size of a queue item. + * @param cItems The number of items in the queue. + * @param cMilliesInterval The number of milliseconds between polling the queue. + * If 0 then the emulation thread will be notified whenever an item arrives. + * @param pfnCallback The consumer function. + * @param fRZEnabled Set if the queue should work in RC and R0. + * @param pszName The queue base name. The instance number will be + * appended automatically. + * @param phQueue Where to store the queue handle on success. + * @thread EMT(0) + * @remarks The device critical section will NOT be entered before calling the + * callback. No locks will be held, but for now it's safe to assume + * that only one EMT will do queue callbacks at any one time. + */ + DECLR3CALLBACKMEMBER(int, pfnQueueCreate,(PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDEV pfnCallback, bool fRZEnabled, const char *pszName, + PDMQUEUEHANDLE *phQueue)); + + DECLR3CALLBACKMEMBER(PPDMQUEUEITEMCORE, pfnQueueAlloc,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)); + DECLR3CALLBACKMEMBER(int, pfnQueueInsert,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)); + DECLR3CALLBACKMEMBER(bool, pfnQueueFlushIfNecessary,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)); + /** @} */ + + /** @name PDM Task + * @{ */ + /** + * Create an asynchronous ring-3 task. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param fFlags PDMTASK_F_XXX + * @param pszName The function name or similar. Used for statistics, + * so no slashes. + * @param pfnCallback The task function. + * @param pvUser User argument for the task function. + * @param phTask Where to return the task handle. + * @thread EMT(0) + */ + DECLR3CALLBACKMEMBER(int, pfnTaskCreate,(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszName, + PFNPDMTASKDEV pfnCallback, void *pvUser, PDMTASKHANDLE *phTask)); + /** + * Triggers the running the given task. + * + * @returns VBox status code. + * @retval VINF_ALREADY_POSTED is the task is already pending. + * @param pDevIns The device instance. + * @param hTask The task to trigger. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnTaskTrigger,(PPDMDEVINS pDevIns, PDMTASKHANDLE hTask)); + /** @} */ + + /** @name SUP Event Semaphore Wrappers (single release / auto reset) + * These semaphores can be signalled from ring-0. + * @{ */ + /** @sa SUPSemEventCreate */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventCreate,(PPDMDEVINS pDevIns, PSUPSEMEVENT phEvent)); + /** @sa SUPSemEventClose */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventClose,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent)); + /** @sa SUPSemEventSignal */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventSignal,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent)); + /** @sa SUPSemEventWaitNoResume */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventWaitNoResume,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint32_t cMillies)); + /** @sa SUPSemEventWaitNsAbsIntr */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventWaitNsAbsIntr,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t uNsTimeout)); + /** @sa SUPSemEventWaitNsRelIntr */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventWaitNsRelIntr,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t cNsTimeout)); + /** @sa SUPSemEventGetResolution */ + DECLR3CALLBACKMEMBER(uint32_t, pfnSUPSemEventGetResolution,(PPDMDEVINS pDevIns)); + /** @} */ + + /** @name SUP Multi Event Semaphore Wrappers (multiple release / manual reset) + * These semaphores can be signalled from ring-0. + * @{ */ + /** @sa SUPSemEventMultiCreate */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiCreate,(PPDMDEVINS pDevIns, PSUPSEMEVENTMULTI phEventMulti)); + /** @sa SUPSemEventMultiClose */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiClose,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti)); + /** @sa SUPSemEventMultiSignal */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiSignal,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti)); + /** @sa SUPSemEventMultiReset */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiReset,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti)); + /** @sa SUPSemEventMultiWaitNoResume */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNoResume,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies)); + /** @sa SUPSemEventMultiWaitNsAbsIntr */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNsAbsIntr,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t uNsTimeout)); + /** @sa SUPSemEventMultiWaitNsRelIntr */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNsRelIntr,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t cNsTimeout)); + /** @sa SUPSemEventMultiGetResolution */ + DECLR3CALLBACKMEMBER(uint32_t, pfnSUPSemEventMultiGetResolution,(PPDMDEVINS pDevIns)); + /** @} */ + + /** + * Initializes a PDM critical section. + * + * The PDM critical sections are derived from the IPRT critical sections, but + * works in RC and R0 as well. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect Pointer to the critical section. + * @param SRC_POS Use RT_SRC_POS. + * @param pszNameFmt Format string for naming the critical section. + * For statistics and lock validation. + * @param va Arguments for the format string. + */ + DECLR3CALLBACKMEMBER(int, pfnCritSectInit,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + + /** + * Gets the NOP critical section. + * + * @returns The ring-3 address of the NOP critical section. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PPDMCRITSECT, pfnCritSectGetNop,(PPDMDEVINS pDevIns)); + + /** + * Changes the device level critical section from the automatically created + * default to one desired by the device constructor. + * + * For ring-0 and raw-mode capable devices, the call must be repeated in each of + * the additional contexts. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect The critical section to use. NULL is not + * valid, instead use the NOP critical + * section. + */ + DECLR3CALLBACKMEMBER(int, pfnSetDeviceCritSect,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLR3CALLBACKMEMBER(bool, pfnCritSectYield,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR3CALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectScheduleExitEvent,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal)); + DECLR3CALLBACKMEMBER(int, pfnCritSectDelete,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + /** @} */ + + /** @name Exported PDM Read/Write Critical Section Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnCritSectRwInit,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwDelete,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLR3CALLBACKMEMBER(int, pfnCritSectRwEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwTryEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwTryEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwLeaveShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLR3CALLBACKMEMBER(int, pfnCritSectRwEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwTryEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwTryEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwLeaveExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLR3CALLBACKMEMBER(bool, pfnCritSectRwIsWriteOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectRwIsReadOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, bool fWannaHear)); + DECLR3CALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriteRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriterReadRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(uint32_t, pfnCritSectRwGetReadCount,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectRwIsInitialized,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + /** @} */ + + /** + * Creates a PDM thread. + * + * This differs from the RTThreadCreate() API in that PDM takes care of suspending, + * resuming, and destroying the thread as the VM state changes. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param ppThread Where to store the thread 'handle'. + * @param pvUser The user argument to the thread function. + * @param pfnThread The thread function. + * @param pfnWakeup The wakup callback. This is called on the EMT + * thread when a state change is pending. + * @param cbStack See RTThreadCreate. + * @param enmType See RTThreadCreate. + * @param pszName See RTThreadCreate. + * @remarks The device critical section will NOT be entered prior to invoking + * the function pointers. + */ + DECLR3CALLBACKMEMBER(int, pfnThreadCreate,(PPDMDEVINS pDevIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDEV pfnThread, + PFNPDMTHREADWAKEUPDEV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)); + + /** @name Exported PDM Thread Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnThreadDestroy,(PPDMTHREAD pThread, int *pRcThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmSuspending,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmRunning,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadSleep,(PPDMTHREAD pThread, RTMSINTERVAL cMillies)); + DECLR3CALLBACKMEMBER(int, pfnThreadSuspend,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadResume,(PPDMTHREAD pThread)); + /** @} */ + + /** + * Set up asynchronous handling of a suspend, reset or power off notification. + * + * This shall only be called when getting the notification. It must be called + * for each one. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pfnAsyncNotify The callback. + * @thread EMT(0) + * @remarks The caller will enter the device critical section prior to invoking + * the callback. + */ + DECLR3CALLBACKMEMBER(int, pfnSetAsyncNotification, (PPDMDEVINS pDevIns, PFNPDMDEVASYNCNOTIFY pfnAsyncNotify)); + + /** + * Notify EMT(0) that the device has completed the asynchronous notification + * handling. + * + * This can be called at any time, spurious calls will simply be ignored. + * + * @param pDevIns The device instance. + * @thread Any + */ + DECLR3CALLBACKMEMBER(void, pfnAsyncNotificationCompleted, (PPDMDEVINS pDevIns)); + + /** + * Register the RTC device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pRtcReg Pointer to a RTC registration structure. + * @param ppRtcHlp Where to store the pointer to the helper + * functions. + */ + DECLR3CALLBACKMEMBER(int, pfnRTCRegister,(PPDMDEVINS pDevIns, PCPDMRTCREG pRtcReg, PCPDMRTCHLP *ppRtcHlp)); + + /** + * Register a PCI Bus. + * + * @returns VBox status code, but the positive values 0..31 are used to indicate + * bus number rather than informational status codes. + * @param pDevIns The device instance. + * @param pPciBusReg Pointer to PCI bus registration structure. + * @param ppPciHlp Where to store the pointer to the PCI Bus + * helpers. + * @param piBus Where to return the PDM bus number. Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIBusRegister,(PPDMDEVINS pDevIns, PPDMPCIBUSREGR3 pPciBusReg, + PCPDMPCIHLPR3 *ppPciHlp, uint32_t *piBus)); + + /** + * Register the IOMMU device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIommuReg Pointer to a IOMMU registration structure. + * @param ppIommuHlp Where to store the pointer to the ring-3 IOMMU + * helpers. + * @param pidxIommu Where to return the IOMMU index. Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnIommuRegister,(PPDMDEVINS pDevIns, PPDMIOMMUREGR3 pIommuReg, PCPDMIOMMUHLPR3 *ppIommuHlp, + uint32_t *pidxIommu)); + + /** + * Register the PIC device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPicReg Pointer to a PIC registration structure. + * @param ppPicHlp Where to store the pointer to the ring-3 PIC + * helpers. + * @sa PDMDevHlpPICSetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnPICRegister,(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLP *ppPicHlp)); + + /** + * Register the APIC device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(int, pfnApicRegister,(PPDMDEVINS pDevIns)); + + /** + * Register the I/O APIC device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIoApicReg Pointer to a I/O APIC registration structure. + * @param ppIoApicHlp Where to store the pointer to the IOAPIC + * helpers. + */ + DECLR3CALLBACKMEMBER(int, pfnIoApicRegister,(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLP *ppIoApicHlp)); + + /** + * Register the HPET device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pHpetReg Pointer to a HPET registration structure. + * @param ppHpetHlpR3 Where to store the pointer to the HPET + * helpers. + */ + DECLR3CALLBACKMEMBER(int, pfnHpetRegister,(PPDMDEVINS pDevIns, PPDMHPETREG pHpetReg, PCPDMHPETHLPR3 *ppHpetHlpR3)); + + /** + * Register a raw PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciRawReg Pointer to a raw PCI registration structure. + * @param ppPciRawHlpR3 Where to store the pointer to the raw PCI + * device helpers. + */ + DECLR3CALLBACKMEMBER(int, pfnPciRawRegister,(PPDMDEVINS pDevIns, PPDMPCIRAWREG pPciRawReg, PCPDMPCIRAWHLPR3 *ppPciRawHlpR3)); + + /** + * Register the DMA device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pDmacReg Pointer to a DMAC registration structure. + * @param ppDmacHlp Where to store the pointer to the DMA helpers. + */ + DECLR3CALLBACKMEMBER(int, pfnDMACRegister,(PPDMDEVINS pDevIns, PPDMDMACREG pDmacReg, PCPDMDMACHLP *ppDmacHlp)); + + /** + * Register transfer function for DMA channel. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param uChannel Channel number. + * @param pfnTransferHandler Device specific transfer callback function. + * @param pvUser User pointer to pass to the callback. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnDMARegister,(PPDMDEVINS pDevIns, unsigned uChannel, PFNDMATRANSFERHANDLER pfnTransferHandler, void *pvUser)); + + /** + * Read memory. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param uChannel Channel number. + * @param pvBuffer Pointer to target buffer. + * @param off DMA position. + * @param cbBlock Block size. + * @param pcbRead Where to store the number of bytes which was + * read. optional. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnDMAReadMemory,(PPDMDEVINS pDevIns, unsigned uChannel, void *pvBuffer, uint32_t off, uint32_t cbBlock, uint32_t *pcbRead)); + + /** + * Write memory. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param uChannel Channel number. + * @param pvBuffer Memory to write. + * @param off DMA position. + * @param cbBlock Block size. + * @param pcbWritten Where to store the number of bytes which was + * written. optional. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnDMAWriteMemory,(PPDMDEVINS pDevIns, unsigned uChannel, const void *pvBuffer, uint32_t off, uint32_t cbBlock, uint32_t *pcbWritten)); + + /** + * Set the DREQ line. + * + * @returns VBox status code. + * @param pDevIns Device instance. + * @param uChannel Channel number. + * @param uLevel Level of the line. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnDMASetDREQ,(PPDMDEVINS pDevIns, unsigned uChannel, unsigned uLevel)); + + /** + * Get channel mode. + * + * @returns Channel mode. See specs. + * @param pDevIns The device instance. + * @param uChannel Channel number. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(uint8_t, pfnDMAGetChannelMode,(PPDMDEVINS pDevIns, unsigned uChannel)); + + /** + * Schedule DMA execution. + * + * @param pDevIns The device instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(void, pfnDMASchedule,(PPDMDEVINS pDevIns)); + + /** + * Write CMOS value and update the checksum(s). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iReg The CMOS register index. + * @param u8Value The CMOS register value. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnCMOSWrite,(PPDMDEVINS pDevIns, unsigned iReg, uint8_t u8Value)); + + /** + * Read CMOS value. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iReg The CMOS register index. + * @param pu8Value Where to store the CMOS register value. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnCMOSRead,(PPDMDEVINS pDevIns, unsigned iReg, uint8_t *pu8Value)); + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDevIns The device instance. + * @param pszFile Filename of the assertion location. + * @param iLine The linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertEMT,(PPDMDEVINS pDevIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDevIns The device instance. + * @param pszFile Filename of the assertion location. + * @param iLine The linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertOther,(PPDMDEVINS pDevIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Resolves the symbol for a raw-mode context interface. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pvInterface The interface structure. + * @param cbInterface The size of the interface structure. + * @param pszSymPrefix What to prefix the symbols in the list with + * before resolving them. This must start with + * 'dev' and contain the driver name. + * @param pszSymList List of symbols corresponding to the interface. + * There is generally a there is generally a define + * holding this list associated with the interface + * definition (INTERFACE_SYM_LIST). For more + * details see PDMR3LdrGetInterfaceSymbols. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnLdrGetRCInterfaceSymbols,(PPDMDEVINS pDevIns, void *pvInterface, size_t cbInterface, + const char *pszSymPrefix, const char *pszSymList)); + + /** + * Resolves the symbol for a ring-0 context interface. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pvInterface The interface structure. + * @param cbInterface The size of the interface structure. + * @param pszSymPrefix What to prefix the symbols in the list with + * before resolving them. This must start with + * 'dev' and contain the driver name. + * @param pszSymList List of symbols corresponding to the interface. + * There is generally a there is generally a define + * holding this list associated with the interface + * definition (INTERFACE_SYM_LIST). For more + * details see PDMR3LdrGetInterfaceSymbols. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnLdrGetR0InterfaceSymbols,(PPDMDEVINS pDevIns, void *pvInterface, size_t cbInterface, + const char *pszSymPrefix, const char *pszSymList)); + + /** + * Calls the PDMDEVREGR0::pfnRequest callback (in ring-0 context). + * + * @returns VBox status code. + * @retval VERR_INVALID_FUNCTION if the callback member is NULL. + * @retval VERR_ACCESS_DENIED if the device isn't ring-0 capable. + * + * @param pDevIns The device instance. + * @param uOperation The operation to perform. + * @param u64Arg 64-bit integer argument. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnCallR0,(PPDMDEVINS pDevIns, uint32_t uOperation, uint64_t u64Arg)); + + /** + * Gets the reason for the most recent VM suspend. + * + * @returns The suspend reason. VMSUSPENDREASON_INVALID is returned if no + * suspend has been made or if the pDevIns is invalid. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(VMSUSPENDREASON, pfnVMGetSuspendReason,(PPDMDEVINS pDevIns)); + + /** + * Gets the reason for the most recent VM resume. + * + * @returns The resume reason. VMRESUMEREASON_INVALID is returned if no + * resume has been made or if the pDevIns is invalid. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(VMRESUMEREASON, pfnVMGetResumeReason,(PPDMDEVINS pDevIns)); + + /** + * Requests the mapping of multiple guest page into ring-3. + * + * When you're done with the pages, call pfnPhysBulkReleasePageMappingLocks() + * ASAP to release them. + * + * This API will assume your intention is to write to the pages, and will + * therefore replace shared and zero pages. If you do not intend to modify the + * pages, use the pfnPhysBulkGCPhys2CCPtrReadOnly() API. + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_PGM_PHYS_PAGE_RESERVED if any of the pages has no physical + * backing or if any of the pages the page has any active access + * handlers. The caller must fall back on using PGMR3PhysWriteExternal. + * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if @a paGCPhysPages contains + * an invalid physical address. + * + * @param pDevIns The device instance. + * @param cPages Number of pages to lock. + * @param paGCPhysPages The guest physical address of the pages that + * should be mapped (@a cPages entries). + * @param fFlags Flags reserved for future use, MBZ. + * @param papvPages Where to store the ring-3 mapping addresses + * corresponding to @a paGCPhysPages. + * @param paLocks Where to store the locking information that + * pfnPhysBulkReleasePageMappingLock needs (@a cPages + * in length). + * + * @remark Avoid calling this API from within critical sections (other than the + * PGM one) because of the deadlock risk when we have to delegating the + * task to an EMT. + * @thread Any. + * @since 6.0.6 + */ + DECLR3CALLBACKMEMBER(int, pfnPhysBulkGCPhys2CCPtr,(PPDMDEVINS pDevIns, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + uint32_t fFlags, void **papvPages, PPGMPAGEMAPLOCK paLocks)); + + /** + * Requests the mapping of multiple guest page into ring-3, for reading only. + * + * When you're done with the pages, call pfnPhysBulkReleasePageMappingLocks() + * ASAP to release them. + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_PGM_PHYS_PAGE_RESERVED if any of the pages has no physical + * backing or if any of the pages the page has an active ALL access + * handler. The caller must fall back on using PGMR3PhysWriteExternal. + * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if @a paGCPhysPages contains + * an invalid physical address. + * + * @param pDevIns The device instance. + * @param cPages Number of pages to lock. + * @param paGCPhysPages The guest physical address of the pages that + * should be mapped (@a cPages entries). + * @param fFlags Flags reserved for future use, MBZ. + * @param papvPages Where to store the ring-3 mapping addresses + * corresponding to @a paGCPhysPages. + * @param paLocks Where to store the lock information that + * pfnPhysReleasePageMappingLock needs (@a cPages + * in length). + * + * @remark Avoid calling this API from within critical sections. + * @thread Any. + * @since 6.0.6 + */ + DECLR3CALLBACKMEMBER(int, pfnPhysBulkGCPhys2CCPtrReadOnly,(PPDMDEVINS pDevIns, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + uint32_t fFlags, void const **papvPages, PPGMPAGEMAPLOCK paLocks)); + + /** + * Release the mappings of multiple guest pages. + * + * This is the counter part of pfnPhysBulkGCPhys2CCPtr and + * pfnPhysBulkGCPhys2CCPtrReadOnly. + * + * @param pDevIns The device instance. + * @param cPages Number of pages to unlock. + * @param paLocks The lock structures initialized by the mapping + * function (@a cPages in length). + * @thread Any. + * @since 6.0.6 + */ + DECLR3CALLBACKMEMBER(void, pfnPhysBulkReleasePageMappingLocks,(PPDMDEVINS pDevIns, uint32_t cPages, PPGMPAGEMAPLOCK paLocks)); + + /** + * Returns the micro architecture used for the guest. + * + * @returns CPU micro architecture enum. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(CPUMMICROARCH, pfnCpuGetGuestMicroarch,(PPDMDEVINS pDevIns)); + + /** + * Get the number of physical and linear address bits supported by the guest. + * + * @param pDevIns The device instance. + * @param pcPhysAddrWidth Where to store the number of physical address bits + * supported by the guest. + * @param pcLinearAddrWidth Where to store the number of linear address bits + * supported by the guest. + */ + DECLR3CALLBACKMEMBER(void, pfnCpuGetGuestAddrWidths,(PPDMDEVINS pDevIns, uint8_t *pcPhysAddrWidth, + uint8_t *pcLinearAddrWidth)); + + /** + * Gets the scalable bus frequency. + * + * The bus frequency is used as a base in several MSRs that gives the CPU and + * other frequency ratios. + * + * @returns Scalable bus frequency in Hz. Will not return CPUM_SBUSFREQ_UNKNOWN. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnCpuGetGuestScalableBusFrequency,(PPDMDEVINS pDevIns)); + + /** Space reserved for future members. + * @{ */ + /** + * Deregister zero or more samples given their name prefix. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszPrefix The name prefix of the samples to remove. If this does + * not start with a '/', the default prefix will be + * prepended, otherwise it will be used as-is. + */ + DECLR3CALLBACKMEMBER(int, pfnSTAMDeregisterByPrefix,(PPDMDEVINS pDevIns, const char *pszPrefix)); + DECLR3CALLBACKMEMBER(void, pfnReserved2,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved3,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved4,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved5,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved6,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved7,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved8,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved9,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved10,(void)); + /** @} */ + + + /** API available to trusted devices only. + * + * These APIs are providing unrestricted access to the guest and the VM, + * or they are interacting intimately with PDM. + * + * @{ + */ + + /** + * Gets the user mode VM handle. Restricted API. + * + * @returns User mode VM Handle. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PUVM, pfnGetUVM,(PPDMDEVINS pDevIns)); + + /** + * Gets the global VM handle. Restricted API. + * + * @returns VM Handle. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PVMCC, pfnGetVM,(PPDMDEVINS pDevIns)); + + /** + * Gets the VMCPU handle. Restricted API. + * + * @returns VMCPU Handle. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PVMCPU, pfnGetVMCPU,(PPDMDEVINS pDevIns)); + + /** + * The the VM CPU ID of the current thread (restricted API). + * + * @returns The VMCPUID of the calling thread, NIL_VMCPUID if not EMT. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(VMCPUID, pfnGetCurrentCpuId,(PPDMDEVINS pDevIns)); + + /** + * Registers the VMM device heap or notifies about mapping/unmapping. + * + * This interface serves three purposes: + * + * -# Register the VMM device heap during device construction + * for the HM to use. + * -# Notify PDM/HM that it's mapped into guest address + * space (i.e. usable). + * -# Notify PDM/HM that it is being unmapped from the guest + * address space (i.e. not usable). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys The physical address if mapped, NIL_RTGCPHYS if + * not mapped. + * @param pvHeap Ring 3 heap pointer. + * @param cbHeap Size of the heap. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterVMMDevHeap,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbHeap)); + + /** + * Registers the firmware (BIOS, EFI) device with PDM. + * + * The firmware provides a callback table and gets a special PDM helper table. + * There can only be one firmware device for a VM. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pFwReg Firmware registration structure. + * @param ppFwHlp Where to return the firmware helper structure. + * @remarks Only valid during device construction. + * @thread EMT(0) + */ + DECLR3CALLBACKMEMBER(int, pfnFirmwareRegister,(PPDMDEVINS pDevIns, PCPDMFWREG pFwReg, PCPDMFWHLPR3 *ppFwHlp)); + + /** + * Resets the VM. + * + * @returns The appropriate VBox status code to pass around on reset. + * @param pDevIns The device instance. + * @param fFlags PDMVMRESET_F_XXX flags. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVMReset,(PPDMDEVINS pDevIns, uint32_t fFlags)); + + /** + * Suspends the VM. + * + * @returns The appropriate VBox status code to pass around on suspend. + * @param pDevIns The device instance. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSuspend,(PPDMDEVINS pDevIns)); + + /** + * Suspends, saves and powers off the VM. + * + * @returns The appropriate VBox status code to pass around. + * @param pDevIns The device instance. + * @thread An emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSuspendSaveAndPowerOff,(PPDMDEVINS pDevIns)); + + /** + * Power off the VM. + * + * @returns The appropriate VBox status code to pass around on power off. + * @param pDevIns The device instance. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVMPowerOff,(PPDMDEVINS pDevIns)); + + /** + * Checks if the Gate A20 is enabled or not. + * + * @returns true if A20 is enabled. + * @returns false if A20 is disabled. + * @param pDevIns The device instance. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnA20IsEnabled,(PPDMDEVINS pDevIns)); + + /** + * Enables or disables the Gate A20. + * + * @param pDevIns The device instance. + * @param fEnable Set this flag to enable the Gate A20; clear it + * to disable. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnA20Set,(PPDMDEVINS pDevIns, bool fEnable)); + + /** + * Get the specified CPUID leaf for the virtual CPU associated with the calling + * thread. + * + * @param pDevIns The device instance. + * @param iLeaf The CPUID leaf to get. + * @param pEax Where to store the EAX value. + * @param pEbx Where to store the EBX value. + * @param pEcx Where to store the ECX value. + * @param pEdx Where to store the EDX value. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(void, pfnGetCpuId,(PPDMDEVINS pDevIns, uint32_t iLeaf, uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx)); + + /** + * Gets the main execution engine for the VM. + * + * @returns VM_EXEC_ENGINE_XXX + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint8_t, pfnGetMainExecutionEngine,(PPDMDEVINS pDevIns)); + + /** + * Get the current virtual clock time in a VM. The clock frequency must be + * queried separately. + * + * @returns Current clock time. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGet,(PPDMDEVINS pDevIns)); + + /** + * Get the frequency of the virtual clock. + * + * @returns The clock frequency (not variable at run-time). + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetFreq,(PPDMDEVINS pDevIns)); + + /** + * Get the current virtual clock time in a VM, in nanoseconds. + * + * @returns Current clock time (in ns). + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetNano,(PPDMDEVINS pDevIns)); + + /** + * Get the timestamp frequency. + * + * @returns Number of ticks per second. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMCpuTicksPerSecond,(PPDMDEVINS pDevIns)); + + /** + * Gets the support driver session. + * + * This is intended for working with the semaphore API. + * + * @returns Support driver session handle. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PSUPDRVSESSION, pfnGetSupDrvSession,(PPDMDEVINS pDevIns)); + + /** + * Queries a generic object from the VMM user. + * + * @returns Pointer to the object if found, NULL if not. + * @param pDevIns The device instance. + * @param pUuid The UUID of what's being queried. The UUIDs and + * the usage conventions are defined by the user. + * + * @note It is strictly forbidden to call this internally in VBox! This + * interface is exclusively for hacks in externally developed devices. + */ + DECLR3CALLBACKMEMBER(void *, pfnQueryGenericUserObject,(PPDMDEVINS pDevIns, PCRTUUID pUuid)); + + /** + * Register a physical page access handler type. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param enmKind The kind of access handler. + * @param pfnHandler Pointer to the ring-3 handler callback. + * @param pszDesc The type description. + * @param phType Where to return the type handle (cross context safe). + * @sa PDMDevHlpPGMHandlerPhysicalTypeSetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnPGMHandlerPhysicalTypeRegister, (PPDMDEVINS pDevIns, PGMPHYSHANDLERKIND enmKind, + PFNPGMPHYSHANDLER pfnHandler, + const char *pszDesc, PPGMPHYSHANDLERTYPE phType)); + + /** + * Register a access handler for a physical range. + * + * @returns VBox status code. + * @retval VINF_SUCCESS when successfully installed. + * @retval VINF_PGM_GCPHYS_ALIASED when the shadow PTs could be updated because + * the guest page aliased or/and mapped by multiple PTs. A CR3 sync has been + * flagged together with a pool clearing. + * @retval VERR_PGM_HANDLER_PHYSICAL_CONFLICT if the range conflicts with an existing + * one. A debug assertion is raised. + * + * @param pDevIns The device instance. + * @param GCPhys Start physical address. + * @param GCPhysLast Last physical address. (inclusive) + * @param hType The handler type registration handle. + * @param pszDesc Description of this handler. If NULL, the type + * description will be used instead. + * @note There is no @a uUser argument, because it will be set to the pDevIns + * in the context the handler is called. + */ + DECLR3CALLBACKMEMBER(int, pfnPGMHandlerPhysicalRegister, (PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, + PGMPHYSHANDLERTYPE hType, R3PTRTYPE(const char *) pszDesc)); + + /** + * Deregister a physical page access handler. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys Start physical address. + */ + DECLR3CALLBACKMEMBER(int, pfnPGMHandlerPhysicalDeregister,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys)); + + /** + * Temporarily turns off the access monitoring of a page within a monitored + * physical write/all page access handler region. + * + * Use this when no further \#PFs are required for that page. Be aware that + * a page directory sync might reset the flags, and turn on access monitoring + * for the page. + * + * The caller must do required page table modifications. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys The start address of the access handler. This + * must be a fully page aligned range or we risk + * messing up other handlers installed for the + * start and end pages. + * @param GCPhysPage The physical address of the page to turn off + * access monitoring for. + */ + DECLR3CALLBACKMEMBER(int, pfnPGMHandlerPhysicalPageTempOff,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage)); + + /** + * Resets any modifications to individual pages in a physical page access + * handler region. + * + * This is used in pair with PGMHandlerPhysicalPageTempOff(), + * PGMHandlerPhysicalPageAliasMmio2() or PGMHandlerPhysicalPageAliasHC(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys The start address of the handler regions, i.e. what you + * passed to PGMR3HandlerPhysicalRegister(), + * PGMHandlerPhysicalRegisterEx() or + * PGMHandlerPhysicalModify(). + */ + DECLR3CALLBACKMEMBER(int, pfnPGMHandlerPhysicalReset,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys)); + + /** + * Registers the guest memory range that can be used for patching. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPtrPatchMem Patch memory range. + * @param cbPatchMem Size of the memory range. + */ + DECLR3CALLBACKMEMBER(int, pfnVMMRegisterPatchMemory, (PPDMDEVINS pDevIns, RTGCPTR GCPtrPatchMem, uint32_t cbPatchMem)); + + /** + * Deregisters the guest memory range that can be used for patching. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPtrPatchMem Patch memory range. + * @param cbPatchMem Size of the memory range. + */ + DECLR3CALLBACKMEMBER(int, pfnVMMDeregisterPatchMemory, (PPDMDEVINS pDevIns, RTGCPTR GCPtrPatchMem, uint32_t cbPatchMem)); + + /** + * Registers a new shared module for the VM + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param enmGuestOS Guest OS type. + * @param pszModuleName Module name. + * @param pszVersion Module version. + * @param GCBaseAddr Module base address. + * @param cbModule Module size. + * @param cRegions Number of shared region descriptors. + * @param paRegions Shared region(s). + */ + DECLR3CALLBACKMEMBER(int, pfnSharedModuleRegister,(PPDMDEVINS pDevIns, VBOXOSFAMILY enmGuestOS, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule, + uint32_t cRegions, VMMDEVSHAREDREGIONDESC const *paRegions)); + + /** + * Unregisters a shared module for the VM + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszModuleName Module name. + * @param pszVersion Module version. + * @param GCBaseAddr Module base address. + * @param cbModule Module size. + */ + DECLR3CALLBACKMEMBER(int, pfnSharedModuleUnregister,(PPDMDEVINS pDevIns, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule)); + + /** + * Query the state of a page in a shared module + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPtrPage Page address. + * @param pfShared Shared status (out). + * @param pfPageFlags Page flags (out). + */ + DECLR3CALLBACKMEMBER(int, pfnSharedModuleGetPageState, (PPDMDEVINS pDevIns, RTGCPTR GCPtrPage, bool *pfShared, uint64_t *pfPageFlags)); + + /** + * Check all registered modules for changes. + * + * @returns VBox status code. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(int, pfnSharedModuleCheckAll,(PPDMDEVINS pDevIns)); + + /** + * Query the interface of the top level driver on a LUN. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszDevice Device name. + * @param iInstance Device instance. + * @param iLun The Logical Unit to obtain the interface of. + * @param ppBase Where to store the base interface pointer. + * + * @remark We're not doing any locking ATM, so don't try call this at times when the + * device chain is known to be updated. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryLun,(PPDMDEVINS pDevIns, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMIBASE ppBase)); + + /** + * Registers the GIM device with VMM. + * + * @param pDevIns Pointer to the GIM device instance. + * @param pDbg Pointer to the GIM device debug structure, can be + * NULL. + */ + DECLR3CALLBACKMEMBER(void, pfnGIMDeviceRegister,(PPDMDEVINS pDevIns, PGIMDEBUG pDbg)); + + /** + * Gets debug setup specified by the provider. + * + * @returns VBox status code. + * @param pDevIns Pointer to the GIM device instance. + * @param pDbgSetup Where to store the debug setup details. + */ + DECLR3CALLBACKMEMBER(int, pfnGIMGetDebugSetup,(PPDMDEVINS pDevIns, PGIMDEBUGSETUP pDbgSetup)); + + /** + * Returns the array of MMIO2 regions that are expected to be registered and + * later mapped into the guest-physical address space for the GIM provider + * configured for the VM. + * + * @returns Pointer to an array of GIM MMIO2 regions, may return NULL. + * @param pDevIns Pointer to the GIM device instance. + * @param pcRegions Where to store the number of items in the array. + * + * @remarks The caller does not own and therefore must -NOT- try to free the + * returned pointer. + */ + DECLR3CALLBACKMEMBER(PGIMMMIO2REGION, pfnGIMGetMmio2Regions,(PPDMDEVINS pDevIns, uint32_t *pcRegions)); + + /** @} */ + + /** Just a safety precaution. (PDM_DEVHLPR3_VERSION) */ + uint32_t u32TheEnd; +} PDMDEVHLPR3; +#endif /* !IN_RING3 || DOXYGEN_RUNNING */ +/** Pointer to the R3 PDM Device API. */ +typedef R3PTRTYPE(struct PDMDEVHLPR3 *) PPDMDEVHLPR3; +/** Pointer to the R3 PDM Device API, const variant. */ +typedef R3PTRTYPE(const struct PDMDEVHLPR3 *) PCPDMDEVHLPR3; + + +/** + * PDM Device API - RC Variant. + */ +typedef struct PDMDEVHLPRC +{ + /** Structure version. PDM_DEVHLPRC_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Sets up raw-mode context callback handlers for an I/O port range. + * + * The range must have been registered in ring-3 first using + * PDMDevHlpIoPortCreate() or PDMDevHlpIoPortCreateEx(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hIoPorts The I/O port range handle. + * @param pfnOut Pointer to function which is gonna handle OUT + * operations. Optional. + * @param pfnIn Pointer to function which is gonna handle IN operations. + * Optional. + * @param pfnOutStr Pointer to function which is gonna handle string OUT + * operations. Optional. + * @param pfnInStr Pointer to function which is gonna handle string IN + * operations. Optional. + * @param pvUser User argument to pass to the callbacks. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpIoPortCreate, PDMDevHlpIoPortCreateEx, PDMDevHlpIoPortMap, + * PDMDevHlpIoPortUnmap. + */ + DECLRCCALLBACKMEMBER(int, pfnIoPortSetUpContextEx,(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, + void *pvUser)); + + /** + * Sets up raw-mode context callback handlers for an MMIO region. + * + * The region must have been registered in ring-3 first using + * PDMDevHlpMmioCreate() or PDMDevHlpMmioCreateEx(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO region handle. + * @param pfnWrite Pointer to function which is gonna handle Write + * operations. + * @param pfnRead Pointer to function which is gonna handle Read + * operations. + * @param pfnFill Pointer to function which is gonna handle Fill/memset + * operations. (optional) + * @param pvUser User argument to pass to the callbacks. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpMmioCreate, PDMDevHlpMmioCreateEx, PDMDevHlpMmioMap, + * PDMDevHlpMmioUnmap. + */ + DECLRCCALLBACKMEMBER(int, pfnMmioSetUpContextEx,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIONEWWRITE pfnWrite, + PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser)); + + /** + * Sets up a raw-mode mapping for an MMIO2 region. + * + * The region must have been created in ring-3 first using + * PDMDevHlpMmio2Create(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO2 region handle. + * @param offSub Start of what to map into raw-mode. Must be page aligned. + * @param cbSub Number of bytes to map into raw-mode. Must be page + * aligned. Zero is an alias for everything. + * @param ppvMapping Where to return the mapping corresponding to @a offSub. + * @thread EMT(0) + * @note Only available at VM creation time. + * + * @sa PDMDevHlpMmio2Create(). + */ + DECLRCCALLBACKMEMBER(int, pfnMmio2SetUpContext,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, + size_t offSub, size_t cbSub, void **ppvMapping)); + + /** + * Bus master physical memory read from the given PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLRCCALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, + void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * Bus master physical memory write from the given PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLRCCALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, + const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * Set the IRQ for the given PCI device. + * + * @param pDevIns Device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLRCCALLBACKMEMBER(void, pfnPCISetIrq,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)); + + /** + * Set ISA IRQ for a device. + * + * @param pDevIns Device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLRCCALLBACKMEMBER(void, pfnISASetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** + * Read physical memory. + * + * @returns VINF_SUCCESS (for now). + * @param pDevIns Device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + */ + DECLRCCALLBACKMEMBER(int, pfnPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * Write to physical memory. + * + * @returns VINF_SUCCESS for now, and later maybe VERR_EM_MEMORY. + * @param pDevIns Device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + */ + DECLRCCALLBACKMEMBER(int, pfnPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * Checks if the Gate A20 is enabled or not. + * + * @returns true if A20 is enabled. + * @returns false if A20 is disabled. + * @param pDevIns Device instance. + * @thread The emulation thread. + */ + DECLRCCALLBACKMEMBER(bool, pfnA20IsEnabled,(PPDMDEVINS pDevIns)); + + /** + * Gets the VM state. + * + * @returns VM state. + * @param pDevIns The device instance. + * @thread Any thread (just keep in mind that it's volatile info). + */ + DECLRCCALLBACKMEMBER(VMSTATE, pfnVMState, (PPDMDEVINS pDevIns)); + + /** + * Gets the VM handle. Restricted API. + * + * @returns VM Handle. + * @param pDevIns Device instance. + */ + DECLRCCALLBACKMEMBER(PVMCC, pfnGetVM,(PPDMDEVINS pDevIns)); + + /** + * Gets the VMCPU handle. Restricted API. + * + * @returns VMCPU Handle. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(PVMCPUCC, pfnGetVMCPU,(PPDMDEVINS pDevIns)); + + /** + * The the VM CPU ID of the current thread (restricted API). + * + * @returns The VMCPUID of the calling thread, NIL_VMCPUID if not EMT. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(VMCPUID, pfnGetCurrentCpuId,(PPDMDEVINS pDevIns)); + + /** + * Gets the main execution engine for the VM. + * + * @returns VM_EXEC_ENGINE_XXX + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(uint8_t, pfnGetMainExecutionEngine,(PPDMDEVINS pDevIns)); + + /** + * Get the current virtual clock time in a VM. The clock frequency must be + * queried separately. + * + * @returns Current clock time. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(uint64_t, pfnTMTimeVirtGet,(PPDMDEVINS pDevIns)); + + /** + * Get the frequency of the virtual clock. + * + * @returns The clock frequency (not variable at run-time). + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetFreq,(PPDMDEVINS pDevIns)); + + /** + * Get the current virtual clock time in a VM, in nanoseconds. + * + * @returns Current clock time (in ns). + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetNano,(PPDMDEVINS pDevIns)); + + /** + * Gets the NOP critical section. + * + * @returns The ring-3 address of the NOP critical section. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(PPDMCRITSECT, pfnCritSectGetNop,(PPDMDEVINS pDevIns)); + + /** + * Changes the device level critical section from the automatically created + * default to one desired by the device constructor. + * + * Must first be done in ring-3. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect The critical section to use. NULL is not + * valid, instead use the NOP critical + * section. + */ + DECLRCCALLBACKMEMBER(int, pfnSetDeviceCritSect,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLRCCALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLRCCALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + /** @} */ + + /** @name Exported PDM Read/Write Critical Section Functions + * @{ */ + DECLRCCALLBACKMEMBER(int, pfnCritSectRwEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwTryEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwTryEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwLeaveShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLRCCALLBACKMEMBER(int, pfnCritSectRwEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwTryEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwTryEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwLeaveExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLRCCALLBACKMEMBER(bool, pfnCritSectRwIsWriteOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectRwIsReadOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, bool fWannaHear)); + DECLRCCALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriteRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriterReadRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(uint32_t, pfnCritSectRwGetReadCount,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectRwIsInitialized,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + /** @} */ + + /** + * Gets the trace buffer handle. + * + * This is used by the macros found in VBox/vmm/dbgftrace.h and is not + * really inteded for direct usage, thus no inline wrapper function. + * + * @returns Trace buffer handle or NIL_RTTRACEBUF. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(RTTRACEBUF, pfnDBGFTraceBuf,(PPDMDEVINS pDevIns)); + + /** + * Sets up the PCI bus for the raw-mode context. + * + * This must be called after ring-3 has registered the PCI bus using + * PDMDevHlpPCIBusRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciBusReg The PCI bus registration information for raw-mode, + * considered volatile. + * @param ppPciHlp Where to return the raw-mode PCI bus helpers. + */ + DECLRCCALLBACKMEMBER(int, pfnPCIBusSetUpContext,(PPDMDEVINS pDevIns, PPDMPCIBUSREGRC pPciBusReg, PCPDMPCIHLPRC *ppPciHlp)); + + /** + * Sets up the IOMMU for the raw-mode context. + * + * This must be called after ring-3 has registered the IOMMU using + * PDMDevHlpIommuRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIommuReg The IOMMU registration information for raw-mode, + * considered volatile. + * @param ppIommuHlp Where to return the raw-mode IOMMU helpers. + */ + DECLRCCALLBACKMEMBER(int, pfnIommuSetUpContext,(PPDMDEVINS pDevIns, PPDMIOMMUREGRC pIommuReg, PCPDMIOMMUHLPRC *ppIommuHlp)); + + /** + * Sets up the PIC for the ring-0 context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpPICRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPicReg The PIC registration information for ring-0, + * considered volatile and copied. + * @param ppPicHlp Where to return the ring-0 PIC helpers. + */ + DECLRCCALLBACKMEMBER(int, pfnPICSetUpContext,(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLP *ppPicHlp)); + + /** + * Sets up the APIC for the raw-mode context. + * + * This must be called after ring-3 has registered the APIC using + * PDMDevHlpApicRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(int, pfnApicSetUpContext,(PPDMDEVINS pDevIns)); + + /** + * Sets up the IOAPIC for the ring-0 context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpIoApicRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIoApicReg The PIC registration information for ring-0, + * considered volatile and copied. + * @param ppIoApicHlp Where to return the ring-0 IOAPIC helpers. + */ + DECLRCCALLBACKMEMBER(int, pfnIoApicSetUpContext,(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLP *ppIoApicHlp)); + + /** + * Sets up the HPET for the raw-mode context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpHpetRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pHpetReg The PIC registration information for raw-mode, + * considered volatile and copied. + * @param ppHpetHlp Where to return the raw-mode HPET helpers. + */ + DECLRCCALLBACKMEMBER(int, pfnHpetSetUpContext,(PPDMDEVINS pDevIns, PPDMHPETREG pHpetReg, PCPDMHPETHLPRC *ppHpetHlp)); + + /** Space reserved for future members. + * @{ */ + DECLRCCALLBACKMEMBER(void, pfnReserved1,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved2,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved3,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved4,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved5,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved6,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved7,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved8,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved9,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved10,(void)); + /** @} */ + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDEVHLPRC; +/** Pointer PDM Device RC API. */ +typedef RGPTRTYPE(struct PDMDEVHLPRC *) PPDMDEVHLPRC; +/** Pointer PDM Device RC API. */ +typedef RGPTRTYPE(const struct PDMDEVHLPRC *) PCPDMDEVHLPRC; + +/** Current PDMDEVHLP version number. */ +#define PDM_DEVHLPRC_VERSION PDM_VERSION_MAKE(0xffe6, 19, 0) + + +/** + * PDM Device API - R0 Variant. + */ +typedef struct PDMDEVHLPR0 +{ + /** Structure version. PDM_DEVHLPR0_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Sets up ring-0 callback handlers for an I/O port range. + * + * The range must have been created in ring-3 first using + * PDMDevHlpIoPortCreate() or PDMDevHlpIoPortCreateEx(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hIoPorts The I/O port range handle. + * @param pfnOut Pointer to function which is gonna handle OUT + * operations. Optional. + * @param pfnIn Pointer to function which is gonna handle IN operations. + * Optional. + * @param pfnOutStr Pointer to function which is gonna handle string OUT + * operations. Optional. + * @param pfnInStr Pointer to function which is gonna handle string IN + * operations. Optional. + * @param pvUser User argument to pass to the callbacks. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpIoPortCreate(), PDMDevHlpIoPortCreateEx(), + * PDMDevHlpIoPortMap(), PDMDevHlpIoPortUnmap(). + */ + DECLR0CALLBACKMEMBER(int, pfnIoPortSetUpContextEx,(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, + void *pvUser)); + + /** + * Sets up ring-0 callback handlers for an MMIO region. + * + * The region must have been created in ring-3 first using + * PDMDevHlpMmioCreate(), PDMDevHlpMmioCreateEx(), PDMDevHlpMmioCreateAndMap(), + * PDMDevHlpMmioCreateExAndMap() or PDMDevHlpPCIIORegionCreateMmio(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO region handle. + * @param pfnWrite Pointer to function which is gonna handle Write + * operations. + * @param pfnRead Pointer to function which is gonna handle Read + * operations. + * @param pfnFill Pointer to function which is gonna handle Fill/memset + * operations. (optional) + * @param pvUser User argument to pass to the callbacks. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpMmioCreate(), PDMDevHlpMmioCreateEx(), PDMDevHlpMmioMap(), + * PDMDevHlpMmioUnmap(). + */ + DECLR0CALLBACKMEMBER(int, pfnMmioSetUpContextEx,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIONEWWRITE pfnWrite, + PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser)); + + /** + * Sets up a ring-0 mapping for an MMIO2 region. + * + * The region must have been created in ring-3 first using + * PDMDevHlpMmio2Create(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO2 region handle. + * @param offSub Start of what to map into ring-0. Must be page aligned. + * @param cbSub Number of bytes to map into ring-0. Must be page + * aligned. Zero is an alias for everything. + * @param ppvMapping Where to return the mapping corresponding to @a offSub. + * + * @thread EMT(0) + * @note Only available at VM creation time. + * + * @sa PDMDevHlpMmio2Create(). + */ + DECLR0CALLBACKMEMBER(int, pfnMmio2SetUpContext,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, size_t offSub, size_t cbSub, + void **ppvMapping)); + + /** + * Bus master physical memory read from the given PCI device. + * + * @returns VINF_SUCCESS or VERR_PDM_NOT_PCI_BUS_MASTER, later maybe + * VERR_EM_MEMORY. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR0CALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, + void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * Bus master physical memory write from the given PCI device. + * + * @returns VINF_SUCCESS or VERR_PDM_NOT_PCI_BUS_MASTER, later maybe + * VERR_EM_MEMORY. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR0CALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, + const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * Set the IRQ for the given PCI device. + * + * @param pDevIns Device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR0CALLBACKMEMBER(void, pfnPCISetIrq,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)); + + /** + * Set ISA IRQ for a device. + * + * @param pDevIns Device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR0CALLBACKMEMBER(void, pfnISASetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** + * Read physical memory. + * + * @returns VINF_SUCCESS (for now). + * @param pDevIns Device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + */ + DECLR0CALLBACKMEMBER(int, pfnPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * Write to physical memory. + * + * @returns VINF_SUCCESS for now, and later maybe VERR_EM_MEMORY. + * @param pDevIns Device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + */ + DECLR0CALLBACKMEMBER(int, pfnPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * Checks if the Gate A20 is enabled or not. + * + * @returns true if A20 is enabled. + * @returns false if A20 is disabled. + * @param pDevIns Device instance. + * @thread The emulation thread. + */ + DECLR0CALLBACKMEMBER(bool, pfnA20IsEnabled,(PPDMDEVINS pDevIns)); + + /** + * Gets the VM state. + * + * @returns VM state. + * @param pDevIns The device instance. + * @thread Any thread (just keep in mind that it's volatile info). + */ + DECLR0CALLBACKMEMBER(VMSTATE, pfnVMState, (PPDMDEVINS pDevIns)); + + /** + * Gets the VM handle. Restricted API. + * + * @returns VM Handle. + * @param pDevIns Device instance. + */ + DECLR0CALLBACKMEMBER(PVMCC, pfnGetVM,(PPDMDEVINS pDevIns)); + + /** + * Gets the VMCPU handle. Restricted API. + * + * @returns VMCPU Handle. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(PVMCPUCC, pfnGetVMCPU,(PPDMDEVINS pDevIns)); + + /** + * The the VM CPU ID of the current thread (restricted API). + * + * @returns The VMCPUID of the calling thread, NIL_VMCPUID if not EMT. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(VMCPUID, pfnGetCurrentCpuId,(PPDMDEVINS pDevIns)); + + /** + * Gets the main execution engine for the VM. + * + * @returns VM_EXEC_ENGINE_XXX + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(uint8_t, pfnGetMainExecutionEngine,(PPDMDEVINS pDevIns)); + + /** @name Timer handle method wrappers + * @{ */ + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerFromMicro,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs)); + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerFromMilli,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs)); + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerFromNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs)); + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerGet,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerGetFreq,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerGetNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(bool, pfnTimerIsActive,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(bool, pfnTimerIsLockOwner,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(VBOXSTRICTRC, pfnTimerLockClock,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, int rcBusy)); + /** Takes the clock lock then enters the specified critical section. */ + DECLR0CALLBACKMEMBER(VBOXSTRICTRC, pfnTimerLockClock2,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR0CALLBACKMEMBER(int, pfnTimerSet,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t uExpire)); + DECLR0CALLBACKMEMBER(int, pfnTimerSetFrequencyHint,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint32_t uHz)); + DECLR0CALLBACKMEMBER(int, pfnTimerSetMicro,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext)); + DECLR0CALLBACKMEMBER(int, pfnTimerSetMillies,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)); + DECLR0CALLBACKMEMBER(int, pfnTimerSetNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext)); + DECLR0CALLBACKMEMBER(int, pfnTimerSetRelative,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now)); + DECLR0CALLBACKMEMBER(int, pfnTimerStop,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(void, pfnTimerUnlockClock,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(void, pfnTimerUnlockClock2,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + /** @} */ + + /** + * Get the current virtual clock time in a VM. The clock frequency must be + * queried separately. + * + * @returns Current clock time. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGet,(PPDMDEVINS pDevIns)); + + /** + * Get the frequency of the virtual clock. + * + * @returns The clock frequency (not variable at run-time). + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetFreq,(PPDMDEVINS pDevIns)); + + /** + * Get the current virtual clock time in a VM, in nanoseconds. + * + * @returns Current clock time (in ns). + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetNano,(PPDMDEVINS pDevIns)); + + /** @name Exported PDM Queue Functions + * @{ */ + DECLR0CALLBACKMEMBER(PPDMQUEUEITEMCORE, pfnQueueAlloc,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)); + DECLR0CALLBACKMEMBER(int, pfnQueueInsert,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)); + DECLR0CALLBACKMEMBER(bool, pfnQueueFlushIfNecessary,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)); + /** @} */ + + /** @name PDM Task + * @{ */ + /** + * Triggers the running the given task. + * + * @returns VBox status code. + * @retval VINF_ALREADY_POSTED is the task is already pending. + * @param pDevIns The device instance. + * @param hTask The task to trigger. + * @thread Any thread. + */ + DECLR0CALLBACKMEMBER(int, pfnTaskTrigger,(PPDMDEVINS pDevIns, PDMTASKHANDLE hTask)); + /** @} */ + + /** @name SUP Event Semaphore Wrappers (single release / auto reset) + * These semaphores can be signalled from ring-0. + * @{ */ + /** @sa SUPSemEventSignal */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventSignal,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent)); + /** @sa SUPSemEventWaitNoResume */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventWaitNoResume,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint32_t cMillies)); + /** @sa SUPSemEventWaitNsAbsIntr */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventWaitNsAbsIntr,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t uNsTimeout)); + /** @sa SUPSemEventWaitNsRelIntr */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventWaitNsRelIntr,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t cNsTimeout)); + /** @sa SUPSemEventGetResolution */ + DECLR0CALLBACKMEMBER(uint32_t, pfnSUPSemEventGetResolution,(PPDMDEVINS pDevIns)); + /** @} */ + + /** @name SUP Multi Event Semaphore Wrappers (multiple release / manual reset) + * These semaphores can be signalled from ring-0. + * @{ */ + /** @sa SUPSemEventMultiSignal */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventMultiSignal,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti)); + /** @sa SUPSemEventMultiReset */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventMultiReset,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti)); + /** @sa SUPSemEventMultiWaitNoResume */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNoResume,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies)); + /** @sa SUPSemEventMultiWaitNsAbsIntr */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNsAbsIntr,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t uNsTimeout)); + /** @sa SUPSemEventMultiWaitNsRelIntr */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNsRelIntr,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t cNsTimeout)); + /** @sa SUPSemEventMultiGetResolution */ + DECLR0CALLBACKMEMBER(uint32_t, pfnSUPSemEventMultiGetResolution,(PPDMDEVINS pDevIns)); + /** @} */ + + /** + * Gets the NOP critical section. + * + * @returns The ring-3 address of the NOP critical section. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(PPDMCRITSECT, pfnCritSectGetNop,(PPDMDEVINS pDevIns)); + + /** + * Changes the device level critical section from the automatically created + * default to one desired by the device constructor. + * + * Must first be done in ring-3. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect The critical section to use. NULL is not + * valid, instead use the NOP critical + * section. + */ + DECLR0CALLBACKMEMBER(int, pfnSetDeviceCritSect,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLR0CALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR0CALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectScheduleExitEvent,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal)); + /** @} */ + + /** @name Exported PDM Read/Write Critical Section Functions + * @{ */ + DECLR0CALLBACKMEMBER(int, pfnCritSectRwEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwTryEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwTryEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwLeaveShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLR0CALLBACKMEMBER(int, pfnCritSectRwEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwTryEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwTryEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwLeaveExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLR0CALLBACKMEMBER(bool, pfnCritSectRwIsWriteOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectRwIsReadOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, bool fWannaHear)); + DECLR0CALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriteRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriterReadRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(uint32_t, pfnCritSectRwGetReadCount,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectRwIsInitialized,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + /** @} */ + + /** + * Gets the trace buffer handle. + * + * This is used by the macros found in VBox/vmm/dbgftrace.h and is not + * really inteded for direct usage, thus no inline wrapper function. + * + * @returns Trace buffer handle or NIL_RTTRACEBUF. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(RTTRACEBUF, pfnDBGFTraceBuf,(PPDMDEVINS pDevIns)); + + /** + * Sets up the PCI bus for the ring-0 context. + * + * This must be called after ring-3 has registered the PCI bus using + * PDMDevHlpPCIBusRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciBusReg The PCI bus registration information for ring-0, + * considered volatile and copied. + * @param ppPciHlp Where to return the ring-0 PCI bus helpers. + */ + DECLR0CALLBACKMEMBER(int, pfnPCIBusSetUpContext,(PPDMDEVINS pDevIns, PPDMPCIBUSREGR0 pPciBusReg, PCPDMPCIHLPR0 *ppPciHlp)); + + /** + * Sets up the IOMMU for the ring-0 context. + * + * This must be called after ring-3 has registered the IOMMU using + * PDMDevHlpIommuRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIommuReg The IOMMU registration information for ring-0, + * considered volatile and copied. + * @param ppIommuHlp Where to return the ring-0 IOMMU helpers. + */ + DECLR0CALLBACKMEMBER(int, pfnIommuSetUpContext,(PPDMDEVINS pDevIns, PPDMIOMMUREGR0 pIommuReg, PCPDMIOMMUHLPR0 *ppIommuHlp)); + + /** + * Sets up the PIC for the ring-0 context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpPICRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPicReg The PIC registration information for ring-0, + * considered volatile and copied. + * @param ppPicHlp Where to return the ring-0 PIC helpers. + */ + DECLR0CALLBACKMEMBER(int, pfnPICSetUpContext,(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLP *ppPicHlp)); + + /** + * Sets up the APIC for the ring-0 context. + * + * This must be called after ring-3 has registered the APIC using + * PDMDevHlpApicRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(int, pfnApicSetUpContext,(PPDMDEVINS pDevIns)); + + /** + * Sets up the IOAPIC for the ring-0 context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpIoApicRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIoApicReg The PIC registration information for ring-0, + * considered volatile and copied. + * @param ppIoApicHlp Where to return the ring-0 IOAPIC helpers. + */ + DECLR0CALLBACKMEMBER(int, pfnIoApicSetUpContext,(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLP *ppIoApicHlp)); + + /** + * Sets up the HPET for the ring-0 context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpHpetRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pHpetReg The PIC registration information for ring-0, + * considered volatile and copied. + * @param ppHpetHlp Where to return the ring-0 HPET helpers. + */ + DECLR0CALLBACKMEMBER(int, pfnHpetSetUpContext,(PPDMDEVINS pDevIns, PPDMHPETREG pHpetReg, PCPDMHPETHLPR0 *ppHpetHlp)); + + /** + * Sets up a physical page access handler type for ring-0 callbacks. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param enmKind The kind of access handler. + * @param pfnHandler Pointer to the ring-0 handler callback. NULL if + * the ring-3 handler should be called. + * @param pfnPfHandler The name of the ring-0 \#PF handler, NULL if the + * ring-3 handler should be called. + * @param pszDesc The type description. + * @param hType The type handle registered in ring-3 already. + * @sa PDMDevHlpPGMHandlerPhysicalTypeRegister + */ + DECLR0CALLBACKMEMBER(int, pfnPGMHandlerPhysicalTypeSetUpContext, (PPDMDEVINS pDevIns, PGMPHYSHANDLERKIND enmKind, + PFNPGMPHYSHANDLER pfnHandler, + PFNPGMRZPHYSPFHANDLER pfnPfHandler, + const char *pszDesc, PGMPHYSHANDLERTYPE hType)); + + /** + * Temporarily turns off the access monitoring of a page within a monitored + * physical write/all page access handler region. + * + * Use this when no further \#PFs are required for that page. Be aware that + * a page directory sync might reset the flags, and turn on access monitoring + * for the page. + * + * The caller must do required page table modifications. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys The start address of the access handler. This + * must be a fully page aligned range or we risk + * messing up other handlers installed for the + * start and end pages. + * @param GCPhysPage The physical address of the page to turn off + * access monitoring for. + */ + DECLR0CALLBACKMEMBER(int, pfnPGMHandlerPhysicalPageTempOff,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage)); + + /** + * Mapping an MMIO2 page in place of an MMIO page for direct access. + * + * This is a special optimization used by the VGA device. Call + * PDMDevHlpMmioResetRegion() to undo the mapping. + * + * @returns VBox status code. This API may return VINF_SUCCESS even if no + * remapping is made. + * @retval VERR_SEM_BUSY in ring-0 if we cannot get the IOM lock. + * + * @param pDevIns The device instance @a hRegion and @a hMmio2 are + * associated with. + * @param hRegion The handle to the MMIO region. + * @param offRegion The offset into @a hRegion of the page to be + * remapped. + * @param hMmio2 The MMIO2 handle. + * @param offMmio2 Offset into @a hMmio2 of the page to be use for the + * mapping. + * @param fPageFlags Page flags to set. Must be (X86_PTE_RW | X86_PTE_P) + * for the time being. + */ + DECLR0CALLBACKMEMBER(int, pfnMmioMapMmio2Page,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS offRegion, + uint64_t hMmio2, RTGCPHYS offMmio2, uint64_t fPageFlags)); + + /** + * Reset a previously modified MMIO region; restore the access flags. + * + * This undoes the effects of PDMDevHlpMmioMapMmio2Page() and is currently only + * intended for some ancient VGA hack. However, it would be great to extend it + * beyond VT-x and/or nested-paging. + * + * @returns VBox status code. + * + * @param pDevIns The device instance @a hRegion is associated with. + * @param hRegion The handle to the MMIO region. + */ + DECLR0CALLBACKMEMBER(int, pfnMmioResetRegion, (PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)); + + /** + * Returns the array of MMIO2 regions that are expected to be registered and + * later mapped into the guest-physical address space for the GIM provider + * configured for the VM. + * + * @returns Pointer to an array of GIM MMIO2 regions, may return NULL. + * @param pDevIns Pointer to the GIM device instance. + * @param pcRegions Where to store the number of items in the array. + * + * @remarks The caller does not own and therefore must -NOT- try to free the + * returned pointer. + */ + DECLR0CALLBACKMEMBER(PGIMMMIO2REGION, pfnGIMGetMmio2Regions,(PPDMDEVINS pDevIns, uint32_t *pcRegions)); + + /** Space reserved for future members. + * @{ */ + DECLR0CALLBACKMEMBER(void, pfnReserved1,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved2,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved3,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved4,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved5,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved6,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved7,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved8,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved9,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved10,(void)); + /** @} */ + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDEVHLPR0; +/** Pointer PDM Device R0 API. */ +typedef R0PTRTYPE(struct PDMDEVHLPR0 *) PPDMDEVHLPR0; +/** Pointer PDM Device GC API. */ +typedef R0PTRTYPE(const struct PDMDEVHLPR0 *) PCPDMDEVHLPR0; + +/** Current PDMDEVHLP version number. */ +#define PDM_DEVHLPR0_VERSION PDM_VERSION_MAKE(0xffe5, 27, 0) + + +/** + * PDM Device Instance. + */ +typedef struct PDMDEVINSR3 +{ + /** Structure version. PDM_DEVINSR3_VERSION defines the current version. */ + uint32_t u32Version; + /** Device instance number. */ + uint32_t iInstance; + /** Size of the ring-3, raw-mode and shared bits. */ + uint32_t cbRing3; + /** Set if ring-0 context is enabled. */ + bool fR0Enabled; + /** Set if raw-mode context is enabled. */ + bool fRCEnabled; + /** Alignment padding. */ + bool afReserved[2]; + /** Pointer the HC PDM Device API. */ + PCPDMDEVHLPR3 pHlpR3; + /** Pointer to the shared device instance data. */ + RTR3PTR pvInstanceDataR3; + /** Pointer to the device instance data for ring-3. */ + RTR3PTR pvInstanceDataForR3; + /** The critical section for the device. + * + * TM and IOM will enter this critical section before calling into the device + * code. PDM will when doing power on, power off, reset, suspend and resume + * notifications. SSM will currently not, but this will be changed later on. + * + * The device gets a critical section automatically assigned to it before + * the constructor is called. If the constructor wishes to use a different + * critical section, it calls PDMDevHlpSetDeviceCritSect() to change it + * very early on. + */ + R3PTRTYPE(PPDMCRITSECT) pCritSectRoR3; + /** Pointer to device registration structure. */ + R3PTRTYPE(PCPDMDEVREG) pReg; + /** Configuration handle. */ + R3PTRTYPE(PCFGMNODE) pCfg; + /** The base interface of the device. + * + * The device constructor initializes this if it has any + * device level interfaces to export. To obtain this interface + * call PDMR3QueryDevice(). */ + PDMIBASE IBase; + + /** Tracing indicator. */ + uint32_t fTracing; + /** The tracing ID of this device. */ + uint32_t idTracing; + + /** Ring-3 pointer to the raw-mode device instance. */ + R3PTRTYPE(struct PDMDEVINSRC *) pDevInsForRCR3; + /** Raw-mode address of the raw-mode device instance. */ + RTRGPTR pDevInsForRC; + /** Ring-3 pointer to the raw-mode instance data. */ + RTR3PTR pvInstanceDataForRCR3; + + /** PCI device structure size. */ + uint32_t cbPciDev; + /** Number of PCI devices in apPciDevs. */ + uint32_t cPciDevs; + /** Pointer to the PCI devices for this device. + * (Allocated after the shared instance data.) + * @note If we want to extend this beyond 8 sub-functions/devices, those 1 or + * two devices ever needing it can use cbPciDev and do the address + * calculations that for entries 8+. */ + R3PTRTYPE(struct PDMPCIDEV *) apPciDevs[8]; + + /** Temporarily. */ + R0PTRTYPE(struct PDMDEVINSR0 *) pDevInsR0RemoveMe; + /** Temporarily. */ + RTR0PTR pvInstanceDataR0; + /** Temporarily. */ + RTRCPTR pvInstanceDataRC; + /** Align the internal data more naturally. */ + uint32_t au32Padding[HC_ARCH_BITS == 32 ? 13 : 11]; + + /** Internal data. */ + union + { +#ifdef PDMDEVINSINT_DECLARED + PDMDEVINSINTR3 s; +#endif + uint8_t padding[HC_ARCH_BITS == 32 ? 0x40 : 0x90]; + } Internal; + + /** Device instance data for ring-3. The size of this area is defined + * in the PDMDEVREG::cbInstanceR3 field. */ + char achInstanceData[8]; +} PDMDEVINSR3; + +/** Current PDMDEVINSR3 version number. */ +#define PDM_DEVINSR3_VERSION PDM_VERSION_MAKE(0xff82, 4, 0) + +/** Converts a pointer to the PDMDEVINSR3::IBase to a pointer to PDMDEVINS. */ +#define PDMIBASE_2_PDMDEV(pInterface) ( (PPDMDEVINS)((char *)(pInterface) - RT_UOFFSETOF(PDMDEVINS, IBase)) ) + + +/** + * PDM ring-0 device instance. + */ +typedef struct PDMDEVINSR0 +{ + /** Structure version. PDM_DEVINSR0_VERSION defines the current version. */ + uint32_t u32Version; + /** Device instance number. */ + uint32_t iInstance; + + /** Pointer the HC PDM Device API. */ + PCPDMDEVHLPR0 pHlpR0; + /** Pointer to the shared device instance data. */ + RTR0PTR pvInstanceDataR0; + /** Pointer to the device instance data for ring-0. */ + RTR0PTR pvInstanceDataForR0; + /** The critical section for the device. + * + * TM and IOM will enter this critical section before calling into the device + * code. PDM will when doing power on, power off, reset, suspend and resume + * notifications. SSM will currently not, but this will be changed later on. + * + * The device gets a critical section automatically assigned to it before + * the constructor is called. If the constructor wishes to use a different + * critical section, it calls PDMDevHlpSetDeviceCritSect() to change it + * very early on. + */ + R0PTRTYPE(PPDMCRITSECT) pCritSectRoR0; + /** Pointer to the ring-0 device registration structure. */ + R0PTRTYPE(PCPDMDEVREGR0) pReg; + /** Ring-3 address of the ring-3 device instance. */ + R3PTRTYPE(struct PDMDEVINSR3 *) pDevInsForR3; + /** Ring-0 pointer to the ring-3 device instance. */ + R0PTRTYPE(struct PDMDEVINSR3 *) pDevInsForR3R0; + /** Ring-0 pointer to the ring-3 instance data. */ + RTR0PTR pvInstanceDataForR3R0; + /** Raw-mode address of the raw-mode device instance. */ + RGPTRTYPE(struct PDMDEVINSRC *) pDevInsForRC; + /** Ring-0 pointer to the raw-mode device instance. */ + R0PTRTYPE(struct PDMDEVINSRC *) pDevInsForRCR0; + /** Ring-0 pointer to the raw-mode instance data. */ + RTR0PTR pvInstanceDataForRCR0; + + /** PCI device structure size. */ + uint32_t cbPciDev; + /** Number of PCI devices in apPciDevs. */ + uint32_t cPciDevs; + /** Pointer to the PCI devices for this device. + * (Allocated after the shared instance data.) + * @note If we want to extend this beyond 8 sub-functions/devices, those 1 or + * two devices ever needing it can use cbPciDev and do the address + * calculations that for entries 8+. */ + R0PTRTYPE(struct PDMPCIDEV *) apPciDevs[8]; + + /** Align the internal data more naturally. */ + uint32_t au32Padding[HC_ARCH_BITS == 32 ? 3 : 2 + 4]; + + /** Internal data. */ + union + { +#ifdef PDMDEVINSINT_DECLARED + PDMDEVINSINTR0 s; +#endif + uint8_t padding[HC_ARCH_BITS == 32 ? 0x40 : 0x80]; + } Internal; + + /** Device instance data for ring-0. The size of this area is defined + * in the PDMDEVREG::cbInstanceR0 field. */ + char achInstanceData[8]; +} PDMDEVINSR0; + +/** Current PDMDEVINSR0 version number. */ +#define PDM_DEVINSR0_VERSION PDM_VERSION_MAKE(0xff83, 4, 0) + + +/** + * PDM raw-mode device instance. + */ +typedef struct PDMDEVINSRC +{ + /** Structure version. PDM_DEVINSRC_VERSION defines the current version. */ + uint32_t u32Version; + /** Device instance number. */ + uint32_t iInstance; + + /** Pointer the HC PDM Device API. */ + PCPDMDEVHLPRC pHlpRC; + /** Pointer to the shared device instance data. */ + RTRGPTR pvInstanceDataRC; + /** Pointer to the device instance data for raw-mode. */ + RTRGPTR pvInstanceDataForRC; + /** The critical section for the device. + * + * TM and IOM will enter this critical section before calling into the device + * code. PDM will when doing power on, power off, reset, suspend and resume + * notifications. SSM will currently not, but this will be changed later on. + * + * The device gets a critical section automatically assigned to it before + * the constructor is called. If the constructor wishes to use a different + * critical section, it calls PDMDevHlpSetDeviceCritSect() to change it + * very early on. + */ + RGPTRTYPE(PPDMCRITSECT) pCritSectRoRC; + /** Pointer to the raw-mode device registration structure. */ + RGPTRTYPE(PCPDMDEVREGRC) pReg; + + /** PCI device structure size. */ + uint32_t cbPciDev; + /** Number of PCI devices in apPciDevs. */ + uint32_t cPciDevs; + /** Pointer to the PCI devices for this device. + * (Allocated after the shared instance data.) */ + RGPTRTYPE(struct PDMPCIDEV *) apPciDevs[8]; + + /** Align the internal data more naturally. */ + uint32_t au32Padding[14]; + + /** Internal data. */ + union + { +#ifdef PDMDEVINSINT_DECLARED + PDMDEVINSINTRC s; +#endif + uint8_t padding[0x10]; + } Internal; + + /** Device instance data for ring-0. The size of this area is defined + * in the PDMDEVREG::cbInstanceR0 field. */ + char achInstanceData[8]; +} PDMDEVINSRC; + +/** Current PDMDEVINSR0 version number. */ +#define PDM_DEVINSRC_VERSION PDM_VERSION_MAKE(0xff84, 4, 0) + + +/** @def PDM_DEVINS_VERSION + * Current PDMDEVINS version number. */ +/** @typedef PDMDEVINS + * The device instance structure for the current context. */ +#ifdef IN_RING3 +# define PDM_DEVINS_VERSION PDM_DEVINSR3_VERSION +typedef PDMDEVINSR3 PDMDEVINS; +#elif defined(IN_RING0) +# define PDM_DEVINS_VERSION PDM_DEVINSR0_VERSION +typedef PDMDEVINSR0 PDMDEVINS; +#elif defined(IN_RC) +# define PDM_DEVINS_VERSION PDM_DEVINSRC_VERSION +typedef PDMDEVINSRC PDMDEVINS; +#else +# error "Missing context defines: IN_RING0, IN_RING3, IN_RC" +#endif + +/** + * Get the pointer to an PCI device. + * @note Returns NULL if @a a_idxPciDev is out of bounds. + */ +#define PDMDEV_GET_PPCIDEV(a_pDevIns, a_idxPciDev) \ + ( (uintptr_t)(a_idxPciDev) < RT_ELEMENTS((a_pDevIns)->apPciDevs) ? (a_pDevIns)->apPciDevs[(uintptr_t)(a_idxPciDev)] \ + : PDMDEV_CALC_PPCIDEV(a_pDevIns, a_idxPciDev) ) + +/** + * Calc the pointer to of a given PCI device. + * @note Returns NULL if @a a_idxPciDev is out of bounds. + */ +#define PDMDEV_CALC_PPCIDEV(a_pDevIns, a_idxPciDev) \ + ( (uintptr_t)(a_idxPciDev) < (a_pDevIns)->cPciDevs \ + ? (PPDMPCIDEV)((uint8_t *)((a_pDevIns)->apPciDevs[0]) + (a_pDevIns->cbPciDev) * (uintptr_t)(a_idxPciDev)) \ + : (PPDMPCIDEV)NULL ) + + +/** + * Checks the structure versions of the device instance and device helpers, + * returning if they are incompatible. + * + * This is for use in the constructor. + * + * @param pDevIns The device instance pointer. + */ +#define PDMDEV_CHECK_VERSIONS_RETURN(pDevIns) \ + do \ + { \ + PPDMDEVINS pDevInsTypeCheck = (pDevIns); NOREF(pDevInsTypeCheck); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pDevIns)->u32Version, PDM_DEVINS_VERSION), \ + ("DevIns=%#x mine=%#x\n", (pDevIns)->u32Version, PDM_DEVINS_VERSION), \ + VERR_PDM_DEVINS_VERSION_MISMATCH); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pDevIns)->CTX_SUFF(pHlp)->u32Version, CTX_MID(PDM_DEVHLP,_VERSION)), \ + ("DevHlp=%#x mine=%#x\n", (pDevIns)->CTX_SUFF(pHlp)->u32Version, CTX_MID(PDM_DEVHLP,_VERSION)), \ + VERR_PDM_DEVHLP_VERSION_MISMATCH); \ + } while (0) + +/** + * Quietly checks the structure versions of the device instance and device + * helpers, returning if they are incompatible. + * + * This is for use in the destructor. + * + * @param pDevIns The device instance pointer. + */ +#define PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns) \ + do \ + { \ + PPDMDEVINS pDevInsTypeCheck = (pDevIns); NOREF(pDevInsTypeCheck); \ + if (RT_LIKELY(PDM_VERSION_ARE_COMPATIBLE((pDevIns)->u32Version, PDM_DEVINS_VERSION) )) \ + { /* likely */ } else return VERR_PDM_DEVINS_VERSION_MISMATCH; \ + if (RT_LIKELY(PDM_VERSION_ARE_COMPATIBLE((pDevIns)->CTX_SUFF(pHlp)->u32Version, CTX_MID(PDM_DEVHLP,_VERSION)) )) \ + { /* likely */ } else return VERR_PDM_DEVHLP_VERSION_MISMATCH; \ + } while (0) + +/** + * Wrapper around CFGMR3ValidateConfig for the root config for use in the + * constructor - returns on failure. + * + * This should be invoked after having initialized the instance data + * sufficiently for the correct operation of the destructor. The destructor is + * always called! + * + * @param pDevIns Pointer to the PDM device instance. + * @param pszValidValues Patterns describing the valid value names. See + * RTStrSimplePatternMultiMatch for details on the + * pattern syntax. + * @param pszValidNodes Patterns describing the valid node (key) names. + * Pass empty string if no valid nodes. + */ +#define PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, pszValidValues, pszValidNodes) \ + do \ + { \ + int rcValCfg = pDevIns->pHlpR3->pfnCFGMValidateConfig((pDevIns)->pCfg, "/", pszValidValues, pszValidNodes, \ + (pDevIns)->pReg->szName, (pDevIns)->iInstance); \ + if (RT_SUCCESS(rcValCfg)) \ + { /* likely */ } else return rcValCfg; \ + } while (0) + +/** @def PDMDEV_ASSERT_EMT + * Assert that the current thread is the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMDEV_ASSERT_EMT(pDevIns) pDevIns->pHlpR3->pfnAssertEMT(pDevIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMDEV_ASSERT_EMT(pDevIns) do { } while (0) +#endif + +/** @def PDMDEV_ASSERT_OTHER + * Assert that the current thread is NOT the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMDEV_ASSERT_OTHER(pDevIns) pDevIns->pHlpR3->pfnAssertOther(pDevIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMDEV_ASSERT_OTHER(pDevIns) do { } while (0) +#endif + +/** @def PDMDEV_ASSERT_VMLOCK_OWNER + * Assert that the current thread is owner of the VM lock. + */ +#ifdef VBOX_STRICT +# define PDMDEV_ASSERT_VMLOCK_OWNER(pDevIns) pDevIns->pHlpR3->pfnAssertVMLock(pDevIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMDEV_ASSERT_VMLOCK_OWNER(pDevIns) do { } while (0) +#endif + +/** @def PDMDEV_SET_ERROR + * Set the VM error. See PDMDevHlpVMSetError() for printf like message formatting. + */ +#define PDMDEV_SET_ERROR(pDevIns, rc, pszError) \ + PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, "%s", pszError) + +/** @def PDMDEV_SET_RUNTIME_ERROR + * Set the VM runtime error. See PDMDevHlpVMSetRuntimeError() for printf like message formatting. + */ +#define PDMDEV_SET_RUNTIME_ERROR(pDevIns, fFlags, pszErrorId, pszError) \ + PDMDevHlpVMSetRuntimeError(pDevIns, fFlags, pszErrorId, "%s", pszError) + +/** @def PDMDEVINS_2_RCPTR + * Converts a PDM Device instance pointer to a RC PDM Device instance pointer. + */ +#ifdef IN_RC +# define PDMDEVINS_2_RCPTR(pDevIns) (pDevIns) +#else +# define PDMDEVINS_2_RCPTR(pDevIns) ( (pDevIns)->pDevInsForRC ) +#endif + +/** @def PDMDEVINS_2_R3PTR + * Converts a PDM Device instance pointer to a R3 PDM Device instance pointer. + */ +#ifdef IN_RING3 +# define PDMDEVINS_2_R3PTR(pDevIns) (pDevIns) +#else +# define PDMDEVINS_2_R3PTR(pDevIns) ( (pDevIns)->pDevInsForR3 ) +#endif + +/** @def PDMDEVINS_2_R0PTR + * Converts a PDM Device instance pointer to a R0 PDM Device instance pointer. + */ +#ifdef IN_RING0 +# define PDMDEVINS_2_R0PTR(pDevIns) (pDevIns) +#else +# define PDMDEVINS_2_R0PTR(pDevIns) ( (pDevIns)->pDevInsR0RemoveMe ) +#endif + +/** @def PDMDEVINS_DATA_2_R0_REMOVE_ME + * Converts a PDM device instance data pointer to a ring-0 one. + * @deprecated + */ +#ifdef IN_RING0 +# define PDMDEVINS_DATA_2_R0_REMOVE_ME(pDevIns, pvCC) (pvCC) +#else +# define PDMDEVINS_DATA_2_R0_REMOVE_ME(pDevIns, pvCC) ( (pDevIns)->pvInstanceDataR0 + (uintptr_t)(pvCC) - (uintptr_t)(pDevIns)->CTX_SUFF(pvInstanceData) ) +#endif + + +/** @def PDMDEVINS_2_DATA + * This is a safer edition of PDMINS_2_DATA that checks that the size of the + * target type is same as PDMDEVREG::cbInstanceShared in strict builds. + * + * @note Do no use this macro in common code working on a core structure which + * device specific code has expanded. + */ +#if defined(VBOX_STRICT) && defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define PDMDEVINS_2_DATA(a_pDevIns, a_PtrType) \ + ([](PPDMDEVINS a_pLambdaDevIns) -> a_PtrType \ + { \ + a_PtrType pLambdaRet = (a_PtrType)(a_pLambdaDevIns)->CTX_SUFF(pvInstanceData); \ + Assert(sizeof(*pLambdaRet) == a_pLambdaDevIns->pReg->cbInstanceShared); \ + return pLambdaRet; \ + }(a_pDevIns)) +#else +# define PDMDEVINS_2_DATA(a_pDevIns, a_PtrType) ( (a_PtrType)(a_pDevIns)->CTX_SUFF(pvInstanceData) ) +#endif + +/** @def PDMDEVINS_2_DATA_CC + * This is a safer edition of PDMINS_2_DATA_CC that checks that the size of the + * target type is same as PDMDEVREG::cbInstanceCC in strict builds. + * + * @note Do no use this macro in common code working on a core structure which + * device specific code has expanded. + */ +#if defined(VBOX_STRICT) && defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define PDMDEVINS_2_DATA_CC(a_pDevIns, a_PtrType) \ + ([](PPDMDEVINS a_pLambdaDevIns) -> a_PtrType \ + { \ + a_PtrType pLambdaRet = (a_PtrType)&(a_pLambdaDevIns)->achInstanceData[0]; \ + Assert(sizeof(*pLambdaRet) == a_pLambdaDevIns->pReg->cbInstanceCC); \ + return pLambdaRet; \ + }(a_pDevIns)) +#else +# define PDMDEVINS_2_DATA_CC(a_pDevIns, a_PtrType) ( (a_PtrType)(void *)&(a_pDevIns)->achInstanceData[0] ) +#endif + + +#ifdef IN_RING3 + +/** + * Combines PDMDevHlpIoPortCreate() & PDMDevHlpIoPortMap(). + */ +DECLINLINE(int) PDMDevHlpIoPortCreateAndMap(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, PFNIOMIOPORTNEWOUT pfnOut, + PFNIOMIOPORTNEWIN pfnIn, const char *pszDesc, PCIOMIOPORTDESC paExtDescs, + PIOMIOPORTHANDLE phIoPorts) +{ + int rc = pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0, NULL, UINT32_MAX, + pfnOut, pfnIn, NULL, NULL, NULL, pszDesc, paExtDescs, phIoPorts); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnIoPortMap(pDevIns, *phIoPorts, Port); + return rc; +} + +/** + * Combines PDMDevHlpIoPortCreate() & PDMDevHlpIoPortMap(), but with pvUser. + */ +DECLINLINE(int) PDMDevHlpIoPortCreateUAndMap(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, PFNIOMIOPORTNEWOUT pfnOut, + PFNIOMIOPORTNEWIN pfnIn, void *pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + int rc = pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0, NULL, UINT32_MAX, + pfnOut, pfnIn, NULL, NULL, pvUser, pszDesc, paExtDescs, phIoPorts); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnIoPortMap(pDevIns, *phIoPorts, Port); + return rc; +} + +/** + * Combines PDMDevHlpIoPortCreate() & PDMDevHlpIoPortMap(), but with flags. + */ +DECLINLINE(int) PDMDevHlpIoPortCreateFlagsAndMap(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, uint32_t fFlags, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + int rc = pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, fFlags, NULL, UINT32_MAX, + pfnOut, pfnIn, NULL, NULL, NULL, pszDesc, paExtDescs, phIoPorts); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnIoPortMap(pDevIns, *phIoPorts, Port); + return rc; +} + +/** + * Combines PDMDevHlpIoPortCreateEx() & PDMDevHlpIoPortMap(). + */ +DECLINLINE(int) PDMDevHlpIoPortCreateExAndMap(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, uint32_t fFlags, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, void *pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + int rc = pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, fFlags, NULL, UINT32_MAX, + pfnOut, pfnIn, pfnOutStr, pfnInStr, pvUser, pszDesc, paExtDescs, phIoPorts); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnIoPortMap(pDevIns, *phIoPorts, Port); + return rc; +} + +/** + * @sa PDMDevHlpIoPortCreateEx + */ +DECLINLINE(int) PDMDevHlpIoPortCreate(PPDMDEVINS pDevIns, RTIOPORT cPorts, PPDMPCIDEV pPciDev, uint32_t iPciRegion, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, void *pvUser, const char *pszDesc, + PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + return pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0, pPciDev, iPciRegion, + pfnOut, pfnIn, NULL, NULL, pvUser, pszDesc, paExtDescs, phIoPorts); +} + + +/** + * @sa PDMDevHlpIoPortCreateEx + */ +DECLINLINE(int) PDMDevHlpIoPortCreateIsa(PPDMDEVINS pDevIns, RTIOPORT cPorts, PFNIOMIOPORTNEWOUT pfnOut, + PFNIOMIOPORTNEWIN pfnIn, void *pvUser, const char *pszDesc, + PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + return pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0, NULL, UINT32_MAX, + pfnOut, pfnIn, NULL, NULL, pvUser, pszDesc, paExtDescs, phIoPorts); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIoPortCreateEx + */ +DECLINLINE(int) PDMDevHlpIoPortCreateEx(PPDMDEVINS pDevIns, RTIOPORT cPorts, uint32_t fFlags, PPDMPCIDEV pPciDev, + uint32_t iPciRegion, PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, void *pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + return pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, fFlags, pPciDev, iPciRegion, + pfnOut, pfnIn, pfnOutStr, pfnInStr, pvUser, pszDesc, paExtDescs, phIoPorts); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIoPortMap + */ +DECLINLINE(int) PDMDevHlpIoPortMap(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, RTIOPORT Port) +{ + return pDevIns->pHlpR3->pfnIoPortMap(pDevIns, hIoPorts, Port); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIoPortUnmap + */ +DECLINLINE(int) PDMDevHlpIoPortUnmap(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts) +{ + return pDevIns->pHlpR3->pfnIoPortUnmap(pDevIns, hIoPorts); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIoPortGetMappingAddress + */ +DECLINLINE(uint32_t) PDMDevHlpIoPortGetMappingAddress(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts) +{ + return pDevIns->pHlpR3->pfnIoPortGetMappingAddress(pDevIns, hIoPorts); +} + + +#endif /* IN_RING3 */ +#if !defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @sa PDMDevHlpIoPortSetUpContextEx + */ +DECLINLINE(int) PDMDevHlpIoPortSetUpContext(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, void *pvUser) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnIoPortSetUpContextEx(pDevIns, hIoPorts, pfnOut, pfnIn, NULL, NULL, pvUser); +} + +/** + * @copydoc PDMDEVHLPR0::pfnIoPortSetUpContextEx + */ +DECLINLINE(int) PDMDevHlpIoPortSetUpContextEx(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, void *pvUser) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnIoPortSetUpContextEx(pDevIns, hIoPorts, pfnOut, pfnIn, pfnOutStr, pfnInStr, pvUser); +} + +#endif /* !IN_RING3 || DOXYGEN_RUNNING */ +#ifdef IN_RING3 + +/** + * @sa PDMDevHlpMmioCreateEx + */ +DECLINLINE(int) PDMDevHlpMmioCreate(PPDMDEVINS pDevIns, RTGCPHYS cbRegion, PPDMPCIDEV pPciDev, uint32_t iPciRegion, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, void *pvUser, + uint32_t fFlags, const char *pszDesc, PIOMMMIOHANDLE phRegion) +{ + return pDevIns->pHlpR3->pfnMmioCreateEx(pDevIns, cbRegion, fFlags, pPciDev, iPciRegion, + pfnWrite, pfnRead, NULL, pvUser, pszDesc, phRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioCreateEx + */ +DECLINLINE(int) PDMDevHlpMmioCreateEx(PPDMDEVINS pDevIns, RTGCPHYS cbRegion, + uint32_t fFlags, PPDMPCIDEV pPciDev, uint32_t iPciRegion, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, + void *pvUser, const char *pszDesc, PIOMMMIOHANDLE phRegion) +{ + return pDevIns->pHlpR3->pfnMmioCreateEx(pDevIns, cbRegion, fFlags, pPciDev, iPciRegion, + pfnWrite, pfnRead, pfnFill, pvUser, pszDesc, phRegion); +} + +/** + * @sa PDMDevHlpMmioCreate and PDMDevHlpMmioMap + */ +DECLINLINE(int) PDMDevHlpMmioCreateAndMap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS cbRegion, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, + uint32_t fFlags, const char *pszDesc, PIOMMMIOHANDLE phRegion) +{ + int rc = pDevIns->pHlpR3->pfnMmioCreateEx(pDevIns, cbRegion, fFlags, NULL /*pPciDev*/, UINT32_MAX /*iPciRegion*/, + pfnWrite, pfnRead, NULL /*pfnFill*/, NULL /*pvUser*/, pszDesc, phRegion); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnMmioMap(pDevIns, *phRegion, GCPhys); + return rc; +} + +/** + * @sa PDMDevHlpMmioCreateEx and PDMDevHlpMmioMap + */ +DECLINLINE(int) PDMDevHlpMmioCreateExAndMap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS cbRegion, uint32_t fFlags, + PPDMPCIDEV pPciDev, uint32_t iPciRegion, PFNIOMMMIONEWWRITE pfnWrite, + PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser, + const char *pszDesc, PIOMMMIOHANDLE phRegion) +{ + int rc = pDevIns->pHlpR3->pfnMmioCreateEx(pDevIns, cbRegion, fFlags, pPciDev, iPciRegion, + pfnWrite, pfnRead, pfnFill, pvUser, pszDesc, phRegion); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnMmioMap(pDevIns, *phRegion, GCPhys); + return rc; +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioMap + */ +DECLINLINE(int) PDMDevHlpMmioMap(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys) +{ + return pDevIns->pHlpR3->pfnMmioMap(pDevIns, hRegion, GCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioUnmap + */ +DECLINLINE(int) PDMDevHlpMmioUnmap(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion) +{ + return pDevIns->pHlpR3->pfnMmioUnmap(pDevIns, hRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioReduce + */ +DECLINLINE(int) PDMDevHlpMmioReduce(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion) +{ + return pDevIns->pHlpR3->pfnMmioReduce(pDevIns, hRegion, cbRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioGetMappingAddress + */ +DECLINLINE(RTGCPHYS) PDMDevHlpMmioGetMappingAddress(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion) +{ + return pDevIns->pHlpR3->pfnMmioGetMappingAddress(pDevIns, hRegion); +} + +#endif /* IN_RING3 */ +#if !defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @sa PDMDevHlpMmioSetUpContextEx + */ +DECLINLINE(int) PDMDevHlpMmioSetUpContext(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, void *pvUser) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnMmioSetUpContextEx(pDevIns, hRegion, pfnWrite, pfnRead, NULL, pvUser); +} + +/** + * @copydoc PDMDEVHLPR0::pfnMmioSetUpContextEx + */ +DECLINLINE(int) PDMDevHlpMmioSetUpContextEx(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIONEWWRITE pfnWrite, + PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnMmioSetUpContextEx(pDevIns, hRegion, pfnWrite, pfnRead, pfnFill, pvUser); +} + +#endif /* !IN_RING3 || DOXYGEN_RUNNING */ +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2Create + */ +DECLINLINE(int) PDMDevHlpMmio2Create(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iPciRegion, RTGCPHYS cbRegion, + uint32_t fFlags, const char *pszDesc, void **ppvMapping, PPGMMMIO2HANDLE phRegion) +{ + return pDevIns->pHlpR3->pfnMmio2Create(pDevIns, pPciDev, iPciRegion, cbRegion, fFlags, pszDesc, ppvMapping, phRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2Map + */ +DECLINLINE(int) PDMDevHlpMmio2Map(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, RTGCPHYS GCPhys) +{ + return pDevIns->pHlpR3->pfnMmio2Map(pDevIns, hRegion, GCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2Unmap + */ +DECLINLINE(int) PDMDevHlpMmio2Unmap(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion) +{ + return pDevIns->pHlpR3->pfnMmio2Unmap(pDevIns, hRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2Reduce + */ +DECLINLINE(int) PDMDevHlpMmio2Reduce(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, RTGCPHYS cbRegion) +{ + return pDevIns->pHlpR3->pfnMmio2Reduce(pDevIns, hRegion, cbRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2GetMappingAddress + */ +DECLINLINE(RTGCPHYS) PDMDevHlpMmio2GetMappingAddress(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion) +{ + return pDevIns->pHlpR3->pfnMmio2GetMappingAddress(pDevIns, hRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2QueryAndResetDirtyBitmap + */ +DECLINLINE(int) PDMDevHlpMmio2QueryAndResetDirtyBitmap(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, + void *pvBitmap, size_t cbBitmap) +{ + return pDevIns->pHlpR3->pfnMmio2QueryAndResetDirtyBitmap(pDevIns, hRegion, pvBitmap, cbBitmap); +} + +/** + * Reset the dirty bitmap tracking for an MMIO2 region. + * + * The MMIO2 region must have been created with the + * PGMPHYS_MMIO2_FLAGS_TRACK_DIRTY_PAGES flag for this to work. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param hRegion The MMIO2 region handle. + */ +DECLINLINE(int) PDMDevHlpMmio2ResetDirtyBitmap(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion) +{ + return pDevIns->pHlpR3->pfnMmio2QueryAndResetDirtyBitmap(pDevIns, hRegion, NULL, 0); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2ControlDirtyPageTracking + */ +DECLINLINE(int) PDMDevHlpMmio2ControlDirtyPageTracking(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, bool fEnabled) +{ + return pDevIns->pHlpR3->pfnMmio2ControlDirtyPageTracking(pDevIns, hRegion, fEnabled); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnMmioMapMmio2Page + */ +DECLINLINE(int) PDMDevHlpMmioMapMmio2Page(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS offRegion, + uint64_t hMmio2, RTGCPHYS offMmio2, uint64_t fPageFlags) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnMmioMapMmio2Page(pDevIns, hRegion, offRegion, hMmio2, offMmio2, fPageFlags); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioResetRegion + */ +DECLINLINE(int) PDMDevHlpMmioResetRegion(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnMmioResetRegion(pDevIns, hRegion); +} + +#if !defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @copydoc PDMDEVHLPR0::pfnMmio2SetUpContext + */ +DECLINLINE(int) PDMDevHlpMmio2SetUpContext(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, + size_t offSub, size_t cbSub, void **ppvMapping) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnMmio2SetUpContext(pDevIns, hRegion, offSub, cbSub, ppvMapping); +} + +#endif /* !IN_RING3 || DOXYGEN_RUNNING */ +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnROMRegister + */ +DECLINLINE(int) PDMDevHlpROMRegister(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, + const void *pvBinary, uint32_t cbBinary, uint32_t fFlags, const char *pszDesc) +{ + return pDevIns->pHlpR3->pfnROMRegister(pDevIns, GCPhysStart, cbRange, pvBinary, cbBinary, fFlags, pszDesc); +} + +/** + * @copydoc PDMDEVHLPR3::pfnROMProtectShadow + */ +DECLINLINE(int) PDMDevHlpROMProtectShadow(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, PGMROMPROT enmProt) +{ + return pDevIns->pHlpR3->pfnROMProtectShadow(pDevIns, GCPhysStart, cbRange, enmProt); +} + +/** + * Register a save state data unit. + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnLoadExec Execute load callback, optional. + */ +DECLINLINE(int) PDMDevHlpSSMRegister(PPDMDEVINS pDevIns, uint32_t uVersion, size_t cbGuess, + PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVLOADEXEC pfnLoadExec) +{ + return pDevIns->pHlpR3->pfnSSMRegister(pDevIns, uVersion, cbGuess, NULL /*pszBefore*/, + NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveDone*/, + NULL /*pfnSavePrep*/, pfnSaveExec, NULL /*pfnSaveDone*/, + NULL /*pfnLoadPrep*/, pfnLoadExec, NULL /*pfnLoadDone*/); +} + +/** + * Register a save state data unit with a live save callback as well. + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * @param pfnLiveExec Execute live callback, optional. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnLoadExec Execute load callback, optional. + */ +DECLINLINE(int) PDMDevHlpSSMRegister3(PPDMDEVINS pDevIns, uint32_t uVersion, size_t cbGuess, + PFNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVLOADEXEC pfnLoadExec) +{ + return pDevIns->pHlpR3->pfnSSMRegister(pDevIns, uVersion, cbGuess, NULL /*pszBefore*/, + NULL /*pfnLivePrep*/, pfnLiveExec, NULL /*pfnLiveDone*/, + NULL /*pfnSavePrep*/, pfnSaveExec, NULL /*pfnSaveDone*/, + NULL /*pfnLoadPrep*/, pfnLoadExec, NULL /*pfnLoadDone*/); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSSMRegister + */ +DECLINLINE(int) PDMDevHlpSSMRegisterEx(PPDMDEVINS pDevIns, uint32_t uVersion, size_t cbGuess, const char *pszBefore, + PFNSSMDEVLIVEPREP pfnLivePrep, PFNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVLIVEVOTE pfnLiveVote, + PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone, + PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone) +{ + return pDevIns->pHlpR3->pfnSSMRegister(pDevIns, uVersion, cbGuess, pszBefore, + pfnLivePrep, pfnLiveExec, pfnLiveVote, + pfnSavePrep, pfnSaveExec, pfnSaveDone, + pfnLoadPrep, pfnLoadExec, pfnLoadDone); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSSMRegisterLegacy + */ +DECLINLINE(int) PDMDevHlpSSMRegisterLegacy(PPDMDEVINS pDevIns, const char *pszOldName, PFNSSMDEVLOADPREP pfnLoadPrep, + PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone) +{ + return pDevIns->pHlpR3->pfnSSMRegisterLegacy(pDevIns, pszOldName, pfnLoadPrep, pfnLoadExec, pfnLoadDone); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerCreate + */ +DECLINLINE(int) PDMDevHlpTimerCreate(PPDMDEVINS pDevIns, TMCLOCK enmClock, PFNTMTIMERDEV pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer) +{ + return pDevIns->pHlpR3->pfnTimerCreate(pDevIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, phTimer); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnTimerFromMicro + */ +DECLINLINE(uint64_t) PDMDevHlpTimerFromMicro(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerFromMicro(pDevIns, hTimer, cMicroSecs); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerFromMilli + */ +DECLINLINE(uint64_t) PDMDevHlpTimerFromMilli(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerFromMilli(pDevIns, hTimer, cMilliSecs); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerFromNano + */ +DECLINLINE(uint64_t) PDMDevHlpTimerFromNano(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerFromNano(pDevIns, hTimer, cNanoSecs); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerGet + */ +DECLINLINE(uint64_t) PDMDevHlpTimerGet(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerGet(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerGetFreq + */ +DECLINLINE(uint64_t) PDMDevHlpTimerGetFreq(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerGetFreq(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerGetNano + */ +DECLINLINE(uint64_t) PDMDevHlpTimerGetNano(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerGetNano(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerIsActive + */ +DECLINLINE(bool) PDMDevHlpTimerIsActive(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerIsActive(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerIsLockOwner + */ +DECLINLINE(bool) PDMDevHlpTimerIsLockOwner(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerIsLockOwner(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerLockClock + */ +DECLINLINE(VBOXSTRICTRC) PDMDevHlpTimerLockClock(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, int rcBusy) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerLockClock(pDevIns, hTimer, rcBusy); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerLockClock2 + */ +DECLINLINE(VBOXSTRICTRC) PDMDevHlpTimerLockClock2(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect, int rcBusy) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerLockClock2(pDevIns, hTimer, pCritSect, rcBusy); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSet + */ +DECLINLINE(int) PDMDevHlpTimerSet(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t uExpire) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSet(pDevIns, hTimer, uExpire); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetFrequencyHint + */ +DECLINLINE(int) PDMDevHlpTimerSetFrequencyHint(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint32_t uHz) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSetFrequencyHint(pDevIns, hTimer, uHz); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetMicro + */ +DECLINLINE(int) PDMDevHlpTimerSetMicro(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSetMicro(pDevIns, hTimer, cMicrosToNext); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetMillies + */ +DECLINLINE(int) PDMDevHlpTimerSetMillies(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSetMillies(pDevIns, hTimer, cMilliesToNext); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetNano + */ +DECLINLINE(int) PDMDevHlpTimerSetNano(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSetNano(pDevIns, hTimer, cNanosToNext); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetRelative + */ +DECLINLINE(int) PDMDevHlpTimerSetRelative(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSetRelative(pDevIns, hTimer, cTicksToNext, pu64Now); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerStop + */ +DECLINLINE(int) PDMDevHlpTimerStop(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerStop(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerUnlockClock + */ +DECLINLINE(void) PDMDevHlpTimerUnlockClock(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + pDevIns->CTX_SUFF(pHlp)->pfnTimerUnlockClock(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerUnlockClock2 + */ +DECLINLINE(void) PDMDevHlpTimerUnlockClock2(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect) +{ + pDevIns->CTX_SUFF(pHlp)->pfnTimerUnlockClock2(pDevIns, hTimer, pCritSect); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetCritSect + */ +DECLINLINE(int) PDMDevHlpTimerSetCritSect(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect) +{ + return pDevIns->pHlpR3->pfnTimerSetCritSect(pDevIns, hTimer, pCritSect); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSave + */ +DECLINLINE(int) PDMDevHlpTimerSave(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM) +{ + return pDevIns->pHlpR3->pfnTimerSave(pDevIns, hTimer, pSSM); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerLoad + */ +DECLINLINE(int) PDMDevHlpTimerLoad(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM) +{ + return pDevIns->pHlpR3->pfnTimerLoad(pDevIns, hTimer, pSSM); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerDestroy + */ +DECLINLINE(int) PDMDevHlpTimerDestroy(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->pHlpR3->pfnTimerDestroy(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTMUtcNow + */ +DECLINLINE(PRTTIMESPEC) PDMDevHlpTMUtcNow(PPDMDEVINS pDevIns, PRTTIMESPEC pTime) +{ + return pDevIns->pHlpR3->pfnTMUtcNow(pDevIns, pTime); +} + +#endif + +/** + * Read physical memory - unknown data usage. + * + * @returns VINF_SUCCESS (for now). + * @param pDevIns The device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPhysRead(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysRead(pDevIns, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Write to physical memory - unknown data usage. + * + * @returns VINF_SUCCESS for now, and later maybe VERR_EM_MEMORY. + * @param pDevIns The device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPhysWrite(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Read physical memory - reads meta data processed by the device. + * + * @returns VINF_SUCCESS (for now). + * @param pDevIns The device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPhysReadMeta(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysRead(pDevIns, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Write to physical memory - written data was created/altered by the device. + * + * @returns VINF_SUCCESS for now, and later maybe VERR_EM_MEMORY. + * @param pDevIns The device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPhysWriteMeta(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Read physical memory - read data will not be touched by the device. + * + * @returns VINF_SUCCESS (for now). + * @param pDevIns The device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPhysReadUser(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysRead(pDevIns, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +/** + * Write to physical memory - written data was not touched/created by the device. + * + * @returns VINF_SUCCESS for now, and later maybe VERR_EM_MEMORY. + * @param pDevIns The device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPhysWriteUser(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnPhysGCPhys2CCPtr + */ +DECLINLINE(int) PDMDevHlpPhysGCPhys2CCPtr(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t fFlags, void **ppv, PPGMPAGEMAPLOCK pLock) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysGCPhys2CCPtr(pDevIns, GCPhys, fFlags, ppv, pLock); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysGCPhys2CCPtrReadOnly + */ +DECLINLINE(int) PDMDevHlpPhysGCPhys2CCPtrReadOnly(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t fFlags, void const **ppv, + PPGMPAGEMAPLOCK pLock) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysGCPhys2CCPtrReadOnly(pDevIns, GCPhys, fFlags, ppv, pLock); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysReleasePageMappingLock + */ +DECLINLINE(void) PDMDevHlpPhysReleasePageMappingLock(PPDMDEVINS pDevIns, PPGMPAGEMAPLOCK pLock) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPhysReleasePageMappingLock(pDevIns, pLock); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysBulkGCPhys2CCPtr + */ +DECLINLINE(int) PDMDevHlpPhysBulkGCPhys2CCPtr(PPDMDEVINS pDevIns, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + uint32_t fFlags, void **papvPages, PPGMPAGEMAPLOCK paLocks) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysBulkGCPhys2CCPtr(pDevIns, cPages, paGCPhysPages, fFlags, papvPages, paLocks); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysBulkGCPhys2CCPtrReadOnly + */ +DECLINLINE(int) PDMDevHlpPhysBulkGCPhys2CCPtrReadOnly(PPDMDEVINS pDevIns, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + uint32_t fFlags, void const **papvPages, PPGMPAGEMAPLOCK paLocks) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysBulkGCPhys2CCPtrReadOnly(pDevIns, cPages, paGCPhysPages, fFlags, papvPages, paLocks); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysBulkReleasePageMappingLocks + */ +DECLINLINE(void) PDMDevHlpPhysBulkReleasePageMappingLocks(PPDMDEVINS pDevIns, uint32_t cPages, PPGMPAGEMAPLOCK paLocks) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPhysBulkReleasePageMappingLocks(pDevIns, cPages, paLocks); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysIsGCPhysNormal + */ +DECLINLINE(bool) PDMDevHlpPhysIsGCPhysNormal(PPDMDEVINS pDevIns, RTGCPHYS GCPhys) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysIsGCPhysNormal(pDevIns, GCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysChangeMemBalloon + */ +DECLINLINE(int) PDMDevHlpPhysChangeMemBalloon(PPDMDEVINS pDevIns, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysChangeMemBalloon(pDevIns, fInflate, cPages, paPhysPage); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCpuGetGuestMicroarch + */ +DECLINLINE(CPUMMICROARCH) PDMDevHlpCpuGetGuestMicroarch(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCpuGetGuestMicroarch(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCpuGetGuestScalableBusFrequency + */ +DECLINLINE(uint64_t) PDMDevHlpCpuGetGuestScalableBusFrequency(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCpuGetGuestScalableBusFrequency(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCpuGetGuestAddrWidths + */ +DECLINLINE(void) PDMDevHlpCpuGetGuestAddrWidths(PPDMDEVINS pDevIns, uint8_t *pcPhysAddrWidth, uint8_t *pcLinearAddrWidth) +{ + pDevIns->CTX_SUFF(pHlp)->pfnCpuGetGuestAddrWidths(pDevIns, pcPhysAddrWidth, pcLinearAddrWidth); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysReadGCVirt + */ +DECLINLINE(int) PDMDevHlpPhysReadGCVirt(PPDMDEVINS pDevIns, void *pvDst, RTGCPTR GCVirtSrc, size_t cb) +{ + return pDevIns->pHlpR3->pfnPhysReadGCVirt(pDevIns, pvDst, GCVirtSrc, cb); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysWriteGCVirt + */ +DECLINLINE(int) PDMDevHlpPhysWriteGCVirt(PPDMDEVINS pDevIns, RTGCPTR GCVirtDst, const void *pvSrc, size_t cb) +{ + return pDevIns->pHlpR3->pfnPhysWriteGCVirt(pDevIns, GCVirtDst, pvSrc, cb); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysGCPtr2GCPhys + */ +DECLINLINE(int) PDMDevHlpPhysGCPtr2GCPhys(PPDMDEVINS pDevIns, RTGCPTR GCPtr, PRTGCPHYS pGCPhys) +{ + return pDevIns->pHlpR3->pfnPhysGCPtr2GCPhys(pDevIns, GCPtr, pGCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMHeapAlloc + */ +DECLINLINE(void *) PDMDevHlpMMHeapAlloc(PPDMDEVINS pDevIns, size_t cb) +{ + return pDevIns->pHlpR3->pfnMMHeapAlloc(pDevIns, cb); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMHeapAllocZ + */ +DECLINLINE(void *) PDMDevHlpMMHeapAllocZ(PPDMDEVINS pDevIns, size_t cb) +{ + return pDevIns->pHlpR3->pfnMMHeapAllocZ(pDevIns, cb); +} + +/** + * Allocating string printf. + * + * @returns Pointer to the string. + * @param pDevIns The device instance. + * @param enmTag The statistics tag. + * @param pszFormat The format string. + * @param ... Format arguments. + */ +DECLINLINE(char *) RT_IPRT_FORMAT_ATTR(2, 3) PDMDevHlpMMHeapAPrintf(PPDMDEVINS pDevIns, MMTAG enmTag, const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + char *psz = pDevIns->pHlpR3->pfnMMHeapAPrintfV(pDevIns, enmTag, pszFormat, va); + va_end(va); + + return psz; +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMHeapFree + */ +DECLINLINE(void) PDMDevHlpMMHeapFree(PPDMDEVINS pDevIns, void *pv) +{ + pDevIns->pHlpR3->pfnMMHeapFree(pDevIns, pv); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMPhysGetRamSize + */ +DECLINLINE(uint64_t) PDMDevHlpMMPhysGetRamSize(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnMMPhysGetRamSize(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMPhysGetRamSizeBelow4GB + */ +DECLINLINE(uint32_t) PDMDevHlpMMPhysGetRamSizeBelow4GB(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnMMPhysGetRamSizeBelow4GB(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMPhysGetRamSizeAbove4GB + */ +DECLINLINE(uint64_t) PDMDevHlpMMPhysGetRamSizeAbove4GB(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnMMPhysGetRamSizeAbove4GB(pDevIns); +} +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnVMState + */ +DECLINLINE(VMSTATE) PDMDevHlpVMState(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnVMState(pDevIns); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnVMTeleportedAndNotFullyResumedYet + */ +DECLINLINE(bool) PDMDevHlpVMTeleportedAndNotFullyResumedYet(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMTeleportedAndNotFullyResumedYet(pDevIns); +} + +/** + * Set the VM error message + * + * @returns rc. + * @param pDevIns The device instance. + * @param rc VBox status code. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + * @sa VMSetError + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 7) PDMDevHlpVMSetError(PPDMDEVINS pDevIns, const int rc, RT_SRC_POS_DECL, + const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + pDevIns->CTX_SUFF(pHlp)->pfnVMSetErrorV(pDevIns, rc, RT_SRC_POS_ARGS, pszFormat, va); + va_end(va); + return rc; +} + +/** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + * @sa VMSetRuntimeError + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(4, 5) PDMDevHlpVMSetRuntimeError(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, ...) +{ + va_list va; + int rc; + va_start(va, pszFormat); + rc = pDevIns->CTX_SUFF(pHlp)->pfnVMSetRuntimeErrorV(pDevIns, fFlags, pszErrorId, pszFormat, va); + va_end(va); + return rc; +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMWaitForDeviceReady + */ +DECLINLINE(int) PDMDevHlpVMWaitForDeviceReady(PPDMDEVINS pDevIns, VMCPUID idCpu) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnVMWaitForDeviceReady(pDevIns, idCpu); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMNotifyCpuDeviceReady + */ +DECLINLINE(int) PDMDevHlpVMNotifyCpuDeviceReady(PPDMDEVINS pDevIns, VMCPUID idCpu) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnVMNotifyCpuDeviceReady(pDevIns, idCpu); +} + +/** + * Convenience wrapper for VMR3ReqCallU. + * + * This assumes (1) you're calling a function that returns an VBox status code + * and that you do not wish to wait for it to complete. + * + * @returns VBox status code returned by VMR3ReqCallVU. + * + * @param pDevIns The device instance. + * @param idDstCpu The destination CPU(s). Either a specific CPU ID or + * one of the following special values: + * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param ... Argument list. + * + * @remarks See remarks on VMR3ReqCallVU. + */ +DECLINLINE(int) PDMDevHlpVMReqCallNoWait(PPDMDEVINS pDevIns, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...) +{ + va_list Args; + va_start(Args, cArgs); + int rc = pDevIns->CTX_SUFF(pHlp)->pfnVMReqCallNoWaitV(pDevIns, idDstCpu, pfnFunction, cArgs, Args); + va_end(Args); + return rc; +} + +/** + * Convenience wrapper for VMR3ReqCallU. + * + * This assumes (1) you're calling a function that returns void, (2) that you + * wish to wait for ever for it to return, and (3) that it's priority request + * that can be safely be handled during async suspend and power off. + * + * @returns VBox status code of VMR3ReqCallVU. + * + * @param pDevIns The device instance. + * @param idDstCpu The destination CPU(s). Either a specific CPU ID or + * one of the following special values: + * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param ... Argument list. + * + * @remarks See remarks on VMR3ReqCallVU. + */ +DECLINLINE(int) PDMDevHlpVMReqPriorityCallWait(PPDMDEVINS pDevIns, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...) +{ + va_list Args; + va_start(Args, cArgs); + int rc = pDevIns->CTX_SUFF(pHlp)->pfnVMReqPriorityCallWaitV(pDevIns, idDstCpu, pfnFunction, cArgs, Args); + va_end(Args); + return rc; +} + +#endif /* IN_RING3 */ + +/** + * VBOX_STRICT wrapper for pHlp->pfnDBGFStopV. + * + * @returns VBox status code which must be passed up to the VMM. This will be + * VINF_SUCCESS in non-strict builds. + * @param pDevIns The device instance. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Message. (optional) + * @param ... Message parameters. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(5, 6) PDMDevHlpDBGFStop(PPDMDEVINS pDevIns, RT_SRC_POS_DECL, const char *pszFormat, ...) +{ +#ifdef VBOX_STRICT +# ifdef IN_RING3 + int rc; + va_list args; + va_start(args, pszFormat); + rc = pDevIns->pHlpR3->pfnDBGFStopV(pDevIns, RT_SRC_POS_ARGS, pszFormat, args); + va_end(args); + return rc; +# else + NOREF(pDevIns); + NOREF(pszFile); + NOREF(iLine); + NOREF(pszFunction); + NOREF(pszFormat); + return VINF_EM_DBG_STOP; +# endif +#else + NOREF(pDevIns); + NOREF(pszFile); + NOREF(iLine); + NOREF(pszFunction); + NOREF(pszFormat); + return VINF_SUCCESS; +#endif +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFInfoRegister + */ +DECLINLINE(int) PDMDevHlpDBGFInfoRegister(PPDMDEVINS pDevIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDEV pfnHandler) +{ + return pDevIns->pHlpR3->pfnDBGFInfoRegister(pDevIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFInfoRegisterArgv + */ +DECLINLINE(int) PDMDevHlpDBGFInfoRegisterArgv(PPDMDEVINS pDevIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDEV pfnHandler) +{ + return pDevIns->pHlpR3->pfnDBGFInfoRegisterArgv(pDevIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFRegRegister + */ +DECLINLINE(int) PDMDevHlpDBGFRegRegister(PPDMDEVINS pDevIns, PCDBGFREGDESC paRegisters) +{ + return pDevIns->pHlpR3->pfnDBGFRegRegister(pDevIns, paRegisters); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFReportBugCheck + */ +DECLINLINE(VBOXSTRICTRC) PDMDevHlpDBGFReportBugCheck(PPDMDEVINS pDevIns, DBGFEVENTTYPE enmEvent, uint64_t uBugCheck, + uint64_t uP1, uint64_t uP2, uint64_t uP3, uint64_t uP4) +{ + return pDevIns->pHlpR3->pfnDBGFReportBugCheck(pDevIns, enmEvent, uBugCheck, uP1, uP2, uP3, uP4); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFCoreWrite + */ +DECLINLINE(int) PDMDevHlpDBGFCoreWrite(PPDMDEVINS pDevIns, const char *pszFilename, bool fReplaceFile) +{ + return pDevIns->pHlpR3->pfnDBGFCoreWrite(pDevIns, pszFilename, fReplaceFile); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFInfoLogHlp + */ +DECLINLINE(PCDBGFINFOHLP) PDMDevHlpDBGFInfoLogHlp(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnDBGFInfoLogHlp(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFRegNmQueryU64 + */ +DECLINLINE(int) PDMDevHlpDBGFRegNmQueryU64(PPDMDEVINS pDevIns, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64) +{ + return pDevIns->pHlpR3->pfnDBGFRegNmQueryU64(pDevIns, idDefCpu, pszReg, pu64); +} + + /** + * Format a set of registers. + * + * This is restricted to registers from one CPU, that specified by @a idCpu. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param idCpu The CPU ID of any CPU registers that may be + * printed, pass VMCPUID_ANY if not applicable. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pszFormat The format string. Register names are given by + * %VR{name}, they take no arguments. + * @param ... Argument list. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(4, 5) PDMDevHlpDBGFRegPrintf(PPDMDEVINS pDevIns, VMCPUID idCpu, char *pszBuf, size_t cbBuf, + const char *pszFormat, ...) +{ + va_list Args; + va_start(Args, pszFormat); + int rc = pDevIns->pHlpR3->pfnDBGFRegPrintfV(pDevIns, idCpu, pszBuf, cbBuf, pszFormat, Args); + va_end(Args); + return rc; +} + +/** + * @copydoc PDMDEVHLPR3::pfnSTAMRegister + */ +DECLINLINE(void) PDMDevHlpSTAMRegister(PPDMDEVINS pDevIns, void *pvSample, STAMTYPE enmType, const char *pszName, STAMUNIT enmUnit, const char *pszDesc) +{ + pDevIns->pHlpR3->pfnSTAMRegister(pDevIns, pvSample, enmType, pszName, enmUnit, pszDesc); +} + +/** + * Same as pfnSTAMRegister except that the name is specified in a + * RTStrPrintf like fashion. + * + * @returns VBox status. + * @param pDevIns Device instance of the DMA. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is + * pointing at. + * @param enmVisibility Visibility type specifying whether unused + * statistics should be visible or not. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + * @param pszName Sample name format string, unix path style. If + * this does not start with a '/', the default + * prefix will be prepended, otherwise it will be + * used as-is. + * @param ... Arguments to the format string. + */ +DECLINLINE(void) RT_IPRT_FORMAT_ATTR(7, 8) PDMDevHlpSTAMRegisterF(PPDMDEVINS pDevIns, void *pvSample, STAMTYPE enmType, + STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, ...) +{ + va_list va; + va_start(va, pszName); + pDevIns->pHlpR3->pfnSTAMRegisterV(pDevIns, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va); + va_end(va); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSTAMDeregisterByPrefix + */ +DECLINLINE(int) PDMDevHlpSTAMDeregisterByPrefix(PPDMDEVINS pDevIns, const char *pszPrefix) +{ + return pDevIns->pHlpR3->pfnSTAMDeregisterByPrefix(pDevIns, pszPrefix); +} + +/** + * Registers the device with the default PCI bus. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. + * This must be kept in the instance data. + * The PCI configuration must be initialized before registration. + */ +DECLINLINE(int) PDMDevHlpPCIRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev) +{ + return pDevIns->pHlpR3->pfnPCIRegister(pDevIns, pPciDev, 0 /*fFlags*/, + PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, NULL); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIRegister + */ +DECLINLINE(int) PDMDevHlpPCIRegisterEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags, + uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName) +{ + return pDevIns->pHlpR3->pfnPCIRegister(pDevIns, pPciDev, fFlags, uPciDevNo, uPciFunNo, pszName); +} + +/** + * Initialize MSI emulation support for the first PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pMsiReg MSI emulation registration structure. + */ +DECLINLINE(int) PDMDevHlpPCIRegisterMsi(PPDMDEVINS pDevIns, PPDMMSIREG pMsiReg) +{ + return pDevIns->pHlpR3->pfnPCIRegisterMsi(pDevIns, NULL, pMsiReg); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIRegisterMsi + */ +DECLINLINE(int) PDMDevHlpPCIRegisterMsiEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PPDMMSIREG pMsiReg) +{ + return pDevIns->pHlpR3->pfnPCIRegisterMsi(pDevIns, pPciDev, pMsiReg); +} + +/** + * Registers a I/O port region for the default PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param hIoPorts Handle to the I/O port region. + */ +DECLINLINE(int) PDMDevHlpPCIIORegionRegisterIo(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cbRegion, IOMIOPORTHANDLE hIoPorts) +{ + return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, NULL, iRegion, cbRegion, PCI_ADDRESS_SPACE_IO, + PDMPCIDEV_IORGN_F_IOPORT_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, hIoPorts, NULL); +} + +/** + * Registers a I/O port region for the default PCI device, custom map/unmap. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param pfnMapUnmap Callback for doing the mapping, optional. The + * callback will be invoked holding only the PDM lock. + * The device lock will _not_ be taken (due to lock + * order). + */ +DECLINLINE(int) PDMDevHlpPCIIORegionRegisterIoCustom(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cbRegion, + PFNPCIIOREGIONMAP pfnMapUnmap) +{ + return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, NULL, iRegion, cbRegion, PCI_ADDRESS_SPACE_IO, + PDMPCIDEV_IORGN_F_NO_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + UINT64_MAX, pfnMapUnmap); +} + +/** + * Combines PDMDevHlpIoPortCreate and PDMDevHlpPCIIORegionRegisterIo, creating + * and registering an I/O port region for the default PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance to register the ports with. + * @param cPorts The count of I/O ports in the region (the size). + * @param iPciRegion The PCI device region. + * @param pfnOut Pointer to function which is gonna handle OUT + * operations. Optional. + * @param pfnIn Pointer to function which is gonna handle IN operations. + * Optional. + * @param pvUser User argument to pass to the callbacks. + * @param pszDesc Pointer to description string. This must not be freed. + * @param paExtDescs Extended per-port descriptions, optional. Partial range + * coverage is allowed. This must not be freed. + * @param phIoPorts Where to return the I/O port range handle. + * + */ +DECLINLINE(int) PDMDevHlpPCIIORegionCreateIo(PPDMDEVINS pDevIns, uint32_t iPciRegion, RTIOPORT cPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, void *pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) + +{ + int rc = pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0 /*fFlags*/, pDevIns->apPciDevs[0], iPciRegion << 16, + pfnOut, pfnIn, NULL, NULL, pvUser, pszDesc, paExtDescs, phIoPorts); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, pDevIns->apPciDevs[0], iPciRegion, cPorts, PCI_ADDRESS_SPACE_IO, + PDMPCIDEV_IORGN_F_IOPORT_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + *phIoPorts, NULL /*pfnMapUnmap*/); + return rc; +} + +/** + * Registers an MMIO region for the default PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param enmType PCI_ADDRESS_SPACE_MEM or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param hMmioRegion Handle to the MMIO region. + * @param pfnMapUnmap Callback for doing the mapping, optional. The + * callback will be invoked holding only the PDM lock. + * The device lock will _not_ be taken (due to lock + * order). + */ +DECLINLINE(int) PDMDevHlpPCIIORegionRegisterMmio(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, + IOMMMIOHANDLE hMmioRegion, PFNPCIIOREGIONMAP pfnMapUnmap) +{ + return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, NULL, iRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + hMmioRegion, pfnMapUnmap); +} + +/** + * Registers an MMIO region for the default PCI device, extended version. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param enmType PCI_ADDRESS_SPACE_MEM or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param hMmioRegion Handle to the MMIO region. + * @param pfnMapUnmap Callback for doing the mapping, optional. The + * callback will be invoked holding only the PDM lock. + * The device lock will _not_ be taken (due to lock + * order). + */ +DECLINLINE(int) PDMDevHlpPCIIORegionRegisterMmioEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, + RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, IOMMMIOHANDLE hMmioRegion, + PFNPCIIOREGIONMAP pfnMapUnmap) +{ + return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, pPciDev, iRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + hMmioRegion, pfnMapUnmap); +} + +/** + * Combines PDMDevHlpMmioCreate and PDMDevHlpPCIIORegionRegisterMmio, creating + * and registering an MMIO region for the default PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance to register the ports with. + * @param cbRegion The size of the region in bytes. + * @param iPciRegion The PCI device region. + * @param enmType PCI_ADDRESS_SPACE_MEM or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param fFlags Flags, IOMMMIO_FLAGS_XXX. + * @param pfnWrite Pointer to function which is gonna handle Write + * operations. + * @param pfnRead Pointer to function which is gonna handle Read + * operations. + * @param pvUser User argument to pass to the callbacks. + * @param pszDesc Pointer to description string. This must not be freed. + * @param phRegion Where to return the MMIO region handle. + * + */ +DECLINLINE(int) PDMDevHlpPCIIORegionCreateMmio(PPDMDEVINS pDevIns, uint32_t iPciRegion, RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, void *pvUser, + uint32_t fFlags, const char *pszDesc, PIOMMMIOHANDLE phRegion) + +{ + int rc = pDevIns->pHlpR3->pfnMmioCreateEx(pDevIns, cbRegion, fFlags, pDevIns->apPciDevs[0], iPciRegion << 16, + pfnWrite, pfnRead, NULL /*pfnFill*/, pvUser, pszDesc, phRegion); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, pDevIns->apPciDevs[0], iPciRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + *phRegion, NULL /*pfnMapUnmap*/); + return rc; +} + + +/** + * Registers an MMIO2 region for the default PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param enmType PCI_ADDRESS_SPACE_MEM or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param hMmio2Region Handle to the MMIO2 region. + */ +DECLINLINE(int) PDMDevHlpPCIIORegionRegisterMmio2(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cbRegion, + PCIADDRESSSPACE enmType, PGMMMIO2HANDLE hMmio2Region) +{ + return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, NULL, iRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO2_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + hMmio2Region, NULL); +} + +/** + * Combines PDMDevHlpMmio2Create and PDMDevHlpPCIIORegionRegisterMmio2, creating + * and registering an MMIO2 region for the default PCI device, extended edition. + * + * @returns VBox status code. + * @param pDevIns The device instance to register the ports with. + * @param cbRegion The size of the region in bytes. + * @param iPciRegion The PCI device region. + * @param enmType PCI_ADDRESS_SPACE_MEM or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param pszDesc Pointer to description string. This must not be freed. + * @param ppvMapping Where to store the address of the ring-3 mapping of + * the memory. + * @param phRegion Where to return the MMIO2 region handle. + * + */ +DECLINLINE(int) PDMDevHlpPCIIORegionCreateMmio2(PPDMDEVINS pDevIns, uint32_t iPciRegion, RTGCPHYS cbRegion, + PCIADDRESSSPACE enmType, const char *pszDesc, + void **ppvMapping, PPGMMMIO2HANDLE phRegion) + +{ + int rc = pDevIns->pHlpR3->pfnMmio2Create(pDevIns, pDevIns->apPciDevs[0], iPciRegion << 16, cbRegion, 0 /*fFlags*/, + pszDesc, ppvMapping, phRegion); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, pDevIns->apPciDevs[0], iPciRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO2_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + *phRegion, NULL /*pfnCallback*/); + return rc; +} + +/** + * Combines PDMDevHlpMmio2Create and PDMDevHlpPCIIORegionRegisterMmio2, creating + * and registering an MMIO2 region for the default PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance to register the ports with. + * @param cbRegion The size of the region in bytes. + * @param iPciRegion The PCI device region. + * @param enmType PCI_ADDRESS_SPACE_MEM or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param fMmio2Flags PGMPHYS_MMIO2_FLAGS_XXX (see pgm.h). + * @param pfnMapUnmap Callback for doing the mapping, optional. The + * callback will be invoked holding only the PDM lock. + * The device lock will _not_ be taken (due to lock + * order). + * @param pszDesc Pointer to description string. This must not be freed. + * @param ppvMapping Where to store the address of the ring-3 mapping of + * the memory. + * @param phRegion Where to return the MMIO2 region handle. + * + */ +DECLINLINE(int) PDMDevHlpPCIIORegionCreateMmio2Ex(PPDMDEVINS pDevIns, uint32_t iPciRegion, RTGCPHYS cbRegion, + PCIADDRESSSPACE enmType, uint32_t fMmio2Flags, PFNPCIIOREGIONMAP pfnMapUnmap, + const char *pszDesc, void **ppvMapping, PPGMMMIO2HANDLE phRegion) + +{ + int rc = pDevIns->pHlpR3->pfnMmio2Create(pDevIns, pDevIns->apPciDevs[0], iPciRegion << 16, cbRegion, fMmio2Flags, + pszDesc, ppvMapping, phRegion); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, pDevIns->apPciDevs[0], iPciRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO2_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + *phRegion, pfnMapUnmap); + return rc; +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIInterceptConfigAccesses + */ +DECLINLINE(int) PDMDevHlpPCIInterceptConfigAccesses(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + PFNPCICONFIGREAD pfnRead, PFNPCICONFIGWRITE pfnWrite) +{ + return pDevIns->pHlpR3->pfnPCIInterceptConfigAccesses(pDevIns, pPciDev, pfnRead, pfnWrite); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIConfigRead + */ +DECLINLINE(VBOXSTRICTRC) PDMDevHlpPCIConfigRead(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t uAddress, + unsigned cb, uint32_t *pu32Value) +{ + return pDevIns->pHlpR3->pfnPCIConfigRead(pDevIns, pPciDev, uAddress, cb, pu32Value); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIConfigWrite + */ +DECLINLINE(VBOXSTRICTRC) PDMDevHlpPCIConfigWrite(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t uAddress, + unsigned cb, uint32_t u32Value) +{ + return pDevIns->pHlpR3->pfnPCIConfigWrite(pDevIns, pPciDev, uAddress, cb, u32Value); +} + +#endif /* IN_RING3 */ + +/** + * Bus master physical memory read from the default PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysRead(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, NULL, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Bus master physical memory read - unknown data usage. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysReadEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, pPciDev, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Bus master physical memory read from the default PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysReadMeta(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, NULL, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Bus master physical memory read - reads meta data processed by the device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysReadMetaEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, pPciDev, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Bus master physical memory read from the default PCI device - read data will not be touched by the device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysReadUser(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, NULL, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +/** + * Bus master physical memory read - read data will not be touched by the device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysReadUserEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, pPciDev, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +/** + * Bus master physical memory write from the default PCI device - unknown data usage. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWrite(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, NULL, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Bus master physical memory write - unknown data usage. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWriteEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, pPciDev, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Bus master physical memory write from the default PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWriteMeta(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, NULL, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Bus master physical memory write - written data was created/altered by the device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWriteMetaEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, pPciDev, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Bus master physical memory write from the default PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWriteUser(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, NULL, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +/** + * Bus master physical memory write - written data was not touched/created by the device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWriteUserEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, pPciDev, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +#ifdef IN_RING3 +/** + * @copydoc PDMDEVHLPR3::pfnPCIPhysGCPhys2CCPtr + */ +DECLINLINE(int) PDMDevHlpPCIPhysGCPhys2CCPtr(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, uint32_t fFlags, + void **ppv, PPGMPAGEMAPLOCK pLock) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysGCPhys2CCPtr(pDevIns, pPciDev, GCPhys, fFlags, ppv, pLock); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIPhysGCPhys2CCPtrReadOnly + */ +DECLINLINE(int) PDMDevHlpPCIPhysGCPhys2CCPtrReadOnly(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, uint32_t fFlags, + void const **ppv, PPGMPAGEMAPLOCK pLock) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysGCPhys2CCPtrReadOnly(pDevIns, pPciDev, GCPhys, fFlags, ppv, pLock); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIPhysBulkGCPhys2CCPtr + */ +DECLINLINE(int) PDMDevHlpPCIPhysBulkGCPhys2CCPtr(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t cPages, + PCRTGCPHYS paGCPhysPages, uint32_t fFlags, void **papvPages, + PPGMPAGEMAPLOCK paLocks) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysBulkGCPhys2CCPtr(pDevIns, pPciDev, cPages, paGCPhysPages, fFlags, papvPages, + paLocks); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIPhysBulkGCPhys2CCPtrReadOnly + */ +DECLINLINE(int) PDMDevHlpPCIPhysBulkGCPhys2CCPtrReadOnly(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t cPages, + PCRTGCPHYS paGCPhysPages, uint32_t fFlags, void const **papvPages, + PPGMPAGEMAPLOCK paLocks) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysBulkGCPhys2CCPtrReadOnly(pDevIns, pPciDev, cPages, paGCPhysPages, fFlags, + papvPages, paLocks); +} +#endif /* IN_RING3 */ + +/** + * Sets the IRQ for the default PCI device. + * + * @param pDevIns The device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ +DECLINLINE(void) PDMDevHlpPCISetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, NULL, iIrq, iLevel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCISetIrq + */ +DECLINLINE(void) PDMDevHlpPCISetIrqEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, pPciDev, iIrq, iLevel); +} + +/** + * Sets the IRQ for the given PCI device, but doesn't wait for EMT to process + * the request when not called from EMT. + * + * @param pDevIns The device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. + * @thread Any thread, but will involve the emulation thread. + */ +DECLINLINE(void) PDMDevHlpPCISetIrqNoWait(PPDMDEVINS pDevIns, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, NULL, iIrq, iLevel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCISetIrqNoWait + */ +DECLINLINE(void) PDMDevHlpPCISetIrqNoWaitEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, pPciDev, iIrq, iLevel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnISASetIrq + */ +DECLINLINE(void) PDMDevHlpISASetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnISASetIrq(pDevIns, iIrq, iLevel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnISASetIrqNoWait + */ +DECLINLINE(void) PDMDevHlpISASetIrqNoWait(PPDMDEVINS pDevIns, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnISASetIrq(pDevIns, iIrq, iLevel); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnDriverAttach + */ +DECLINLINE(int) PDMDevHlpDriverAttach(PPDMDEVINS pDevIns, uint32_t iLun, PPDMIBASE pBaseInterface, PPDMIBASE *ppBaseInterface, const char *pszDesc) +{ + return pDevIns->pHlpR3->pfnDriverAttach(pDevIns, iLun, pBaseInterface, ppBaseInterface, pszDesc); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDriverDetach + */ +DECLINLINE(int) PDMDevHlpDriverDetach(PPDMDEVINS pDevIns, PPDMDRVINS pDrvIns, uint32_t fFlags) +{ + return pDevIns->pHlpR3->pfnDriverDetach(pDevIns, pDrvIns, fFlags); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDriverReconfigure + */ +DECLINLINE(int) PDMDevHlpDriverReconfigure(PPDMDEVINS pDevIns, uint32_t iLun, uint32_t cDepth, + const char * const *papszDrivers, PCFGMNODE *papConfigs, uint32_t fFlags) +{ + return pDevIns->pHlpR3->pfnDriverReconfigure(pDevIns, iLun, cDepth, papszDrivers, papConfigs, fFlags); +} + +/** + * Reconfigures with a single driver reattachement, no config, noflags. + * @sa PDMDevHlpDriverReconfigure + */ +DECLINLINE(int) PDMDevHlpDriverReconfigure1(PPDMDEVINS pDevIns, uint32_t iLun, const char *pszDriver0) +{ + return pDevIns->pHlpR3->pfnDriverReconfigure(pDevIns, iLun, 1, &pszDriver0, NULL, 0); +} + +/** + * Reconfigures with a two drivers reattachement, no config, noflags. + * @sa PDMDevHlpDriverReconfigure + */ +DECLINLINE(int) PDMDevHlpDriverReconfigure2(PPDMDEVINS pDevIns, uint32_t iLun, const char *pszDriver0, const char *pszDriver1) +{ + char const * apszDrivers[2]; + apszDrivers[0] = pszDriver0; + apszDrivers[1] = pszDriver1; + return pDevIns->pHlpR3->pfnDriverReconfigure(pDevIns, iLun, 2, apszDrivers, NULL, 0); +} + +/** + * @copydoc PDMDEVHLPR3::pfnQueueCreate + */ +DECLINLINE(int) PDMDevHlpQueueCreate(PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDEV pfnCallback, bool fRZEnabled, const char *pszName, PDMQUEUEHANDLE *phQueue) +{ + return pDevIns->pHlpR3->pfnQueueCreate(pDevIns, cbItem, cItems, cMilliesInterval, pfnCallback, fRZEnabled, pszName, phQueue); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnQueueAlloc + */ +DECLINLINE(PPDMQUEUEITEMCORE) PDMDevHlpQueueAlloc(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnQueueAlloc(pDevIns, hQueue); +} + +/** + * @copydoc PDMDEVHLPR3::pfnQueueInsert + */ +DECLINLINE(int) PDMDevHlpQueueInsert(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnQueueInsert(pDevIns, hQueue, pItem); +} + +/** + * @copydoc PDMDEVHLPR3::pfnQueueFlushIfNecessary + */ +DECLINLINE(bool) PDMDevHlpQueueFlushIfNecessary(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnQueueFlushIfNecessary(pDevIns, hQueue); +} + +#ifdef IN_RING3 +/** + * @copydoc PDMDEVHLPR3::pfnTaskCreate + */ +DECLINLINE(int) PDMDevHlpTaskCreate(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszName, + PFNPDMTASKDEV pfnCallback, void *pvUser, PDMTASKHANDLE *phTask) +{ + return pDevIns->pHlpR3->pfnTaskCreate(pDevIns, fFlags, pszName, pfnCallback, pvUser, phTask); +} +#endif + +/** + * @copydoc PDMDEVHLPR3::pfnTaskTrigger + */ +DECLINLINE(int) PDMDevHlpTaskTrigger(PPDMDEVINS pDevIns, PDMTASKHANDLE hTask) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTaskTrigger(pDevIns, hTask); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventCreate + */ +DECLINLINE(int) PDMDevHlpSUPSemEventCreate(PPDMDEVINS pDevIns, PSUPSEMEVENT phEvent) +{ + return pDevIns->pHlpR3->pfnSUPSemEventCreate(pDevIns, phEvent); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventClose + */ +DECLINLINE(int) PDMDevHlpSUPSemEventClose(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent) +{ + return pDevIns->pHlpR3->pfnSUPSemEventClose(pDevIns, hEvent); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventSignal + */ +DECLINLINE(int) PDMDevHlpSUPSemEventSignal(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventSignal(pDevIns, hEvent); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventWaitNoResume + */ +DECLINLINE(int) PDMDevHlpSUPSemEventWaitNoResume(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint32_t cMillies) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventWaitNoResume(pDevIns, hEvent, cMillies); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventWaitNsAbsIntr + */ +DECLINLINE(int) PDMDevHlpSUPSemEventWaitNsAbsIntr(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t uNsTimeout) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventWaitNsAbsIntr(pDevIns, hEvent, uNsTimeout); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventWaitNsRelIntr + */ +DECLINLINE(int) PDMDevHlpSUPSemEventWaitNsRelIntr(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t cNsTimeout) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventWaitNsRelIntr(pDevIns, hEvent, cNsTimeout); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventGetResolution + */ +DECLINLINE(uint32_t) PDMDevHlpSUPSemEventGetResolution(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventGetResolution(pDevIns); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiCreate + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiCreate(PPDMDEVINS pDevIns, PSUPSEMEVENTMULTI phEventMulti) +{ + return pDevIns->pHlpR3->pfnSUPSemEventMultiCreate(pDevIns, phEventMulti); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiClose + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiClose(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti) +{ + return pDevIns->pHlpR3->pfnSUPSemEventMultiClose(pDevIns, hEventMulti); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiSignal + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiSignal(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiSignal(pDevIns, hEventMulti); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiReset + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiReset(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiReset(pDevIns, hEventMulti); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiWaitNoResume + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiWaitNoResume(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiWaitNsRelIntr(pDevIns, hEventMulti, cMillies); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiWaitNsAbsIntr + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiWaitNsAbsIntr(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t uNsTimeout) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiWaitNsAbsIntr(pDevIns, hEventMulti, uNsTimeout); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiWaitNsRelIntr + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiWaitNsRelIntr(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t cNsTimeout) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiWaitNsRelIntr(pDevIns, hEventMulti, cNsTimeout); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiGetResolution + */ +DECLINLINE(uint32_t) PDMDevHlpSUPSemEventMultiGetResolution(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiGetResolution(pDevIns); +} + +#ifdef IN_RING3 + +/** + * Initializes a PDM critical section. + * + * The PDM critical sections are derived from the IPRT critical sections, but + * works in RC and R0 as well. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect Pointer to the critical section. + * @param SRC_POS Use RT_SRC_POS. + * @param pszNameFmt Format string for naming the critical section. + * For statistics and lock validation. + * @param ... Arguments for the format string. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 7) PDMDevHlpCritSectInit(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, ...) +{ + int rc; + va_list va; + va_start(va, pszNameFmt); + rc = pDevIns->pHlpR3->pfnCritSectInit(pDevIns, pCritSect, RT_SRC_POS_ARGS, pszNameFmt, va); + va_end(va); + return rc; +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnCritSectGetNop + */ +DECLINLINE(PPDMCRITSECT) PDMDevHlpCritSectGetNop(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectGetNop(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSetDeviceCritSect + */ +DECLINLINE(int) PDMDevHlpSetDeviceCritSect(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSetDeviceCritSect(pDevIns, pCritSect); +} + +/** + * Enters a PDM critical section. + * + * @returns VINF_SUCCESS if entered successfully. + * @returns rcBusy when encountering a busy critical section in RC/R0. + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pDevIns The device instance. + * @param pCritSect The PDM critical section to enter. + * @param rcBusy The status code to return when we're in RC or R0 + * and the section is busy. Pass VINF_SUCCESS to + * acquired the critical section thru a ring-3 + * call if necessary. + * + * @note Even callers setting @a rcBusy to VINF_SUCCESS must either handle + * possible failures in ring-0 or at least apply + * PDM_CRITSECT_RELEASE_ASSERT_RC_DEV() to the return value of this + * function. + * + * @sa PDMCritSectEnter + */ +DECLINLINE(DECL_CHECK_RETURN(int)) PDMDevHlpCritSectEnter(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectEnter(pDevIns, pCritSect, rcBusy); +} + +/** + * Enters a PDM critical section, with location information for debugging. + * + * @returns VINF_SUCCESS if entered successfully. + * @returns rcBusy when encountering a busy critical section in RC/R0. + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pDevIns The device instance. + * @param pCritSect The PDM critical section to enter. + * @param rcBusy The status code to return when we're in RC or R0 + * and the section is busy. Pass VINF_SUCCESS to + * acquired the critical section thru a ring-3 + * call if necessary. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where to lock is being + * acquired from. Optional. + * @sa PDMCritSectEnterDebug + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectEnterDebug(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectEnterDebug(pDevIns, pCritSect, rcBusy, uId, RT_SRC_POS_ARGS); +} + +/** + * Try enter a critical section. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pDevIns The device instance. + * @param pCritSect The critical section. + * @sa PDMCritSectTryEnter + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectTryEnter(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectTryEnter(pDevIns, pCritSect); +} + +/** + * Try enter a critical section, with location information for debugging. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pDevIns The device instance. + * @param pCritSect The critical section. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where to lock is being + * acquired from. Optional. + * @sa PDMCritSectTryEnterDebug + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectTryEnterDebug(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectTryEnterDebug(pDevIns, pCritSect, uId, RT_SRC_POS_ARGS); +} + +/** + * Leaves a critical section entered with PDMCritSectEnter(). + * + * @returns Indication whether we really exited the critical section. + * @retval VINF_SUCCESS if we really exited. + * @retval VINF_SEM_NESTED if we only reduced the nesting count. + * @retval VERR_NOT_OWNER if you somehow ignore release assertions. + * + * @param pDevIns The device instance. + * @param pCritSect The PDM critical section to leave. + * @sa PDMCritSectLeave + */ +DECLINLINE(int) PDMDevHlpCritSectLeave(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectLeave(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectIsOwner + */ +DECLINLINE(bool) PDMDevHlpCritSectIsOwner(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectIsOwner(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectIsInitialized + */ +DECLINLINE(bool) PDMDevHlpCritSectIsInitialized(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectIsInitialized(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectHasWaiters + */ +DECLINLINE(bool) PDMDevHlpCritSectHasWaiters(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectHasWaiters(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectGetRecursion + */ +DECLINLINE(uint32_t) PDMDevHlpCritSectGetRecursion(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectGetRecursion(pDevIns, pCritSect); +} + +#if defined(IN_RING3) || defined(IN_RING0) +/** + * @see PDMHCCritSectScheduleExitEvent + */ +DECLINLINE(int) PDMDevHlpCritSectScheduleExitEvent(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectScheduleExitEvent(pDevIns, pCritSect, hEventToSignal); +} +#endif + +/* Strict build: Remap the two enter calls to the debug versions. */ +#ifdef VBOX_STRICT +# ifdef IPRT_INCLUDED_asm_h +# define PDMDevHlpCritSectEnter(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectEnterDebug((pDevIns), (pCritSect), (rcBusy), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMDevHlpCritSectTryEnter(pDevIns, pCritSect) PDMDevHlpCritSectTryEnterDebug((pDevIns), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define PDMDevHlpCritSectEnter(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectEnterDebug((pDevIns), (pCritSect), (rcBusy), 0, RT_SRC_POS) +# define PDMDevHlpCritSectTryEnter(pDevIns, pCritSect) PDMDevHlpCritSectTryEnterDebug((pDevIns), (pCritSect), 0, RT_SRC_POS) +# endif +#endif + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * Deletes the critical section. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect The PDM critical section to destroy. + * @sa PDMR3CritSectDelete + */ +DECLINLINE(int) PDMDevHlpCritSectDelete(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect) +{ + return pDevIns->pHlpR3->pfnCritSectDelete(pDevIns, pCritSect); +} + +/** + * Initializes a PDM read/write critical section. + * + * The PDM read/write critical sections are derived from the IPRT critical + * sections, but works in RC and R0 as well. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect Pointer to the read/write critical section. + * @param SRC_POS Use RT_SRC_POS. + * @param pszNameFmt Format string for naming the critical section. + * For statistics and lock validation. + * @param ... Arguments for the format string. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 7) PDMDevHlpCritSectRwInit(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, ...) +{ + int rc; + va_list va; + va_start(va, pszNameFmt); + rc = pDevIns->pHlpR3->pfnCritSectRwInit(pDevIns, pCritSect, RT_SRC_POS_ARGS, pszNameFmt, va); + va_end(va); + return rc; +} + +/** + * Deletes the read/write critical section. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect The PDM read/write critical section to destroy. + * @sa PDMR3CritSectRwDelete + */ +DECLINLINE(int) PDMDevHlpCritSectRwDelete(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->pHlpR3->pfnCritSectRwDelete(pDevIns, pCritSect); +} + +#endif /* IN_RING3 */ + +/** + * @sa PDMCritSectRwEnterShared, PDM_CRITSECT_RELEASE_ASSERT_RC_DEV + */ +DECLINLINE(DECL_CHECK_RETURN(int)) PDMDevHlpCritSectRwEnterShared(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwEnterShared(pDevIns, pCritSect, rcBusy); +} + +/** + * @sa PDMCritSectRwEnterSharedDebug, PDM_CRITSECT_RELEASE_ASSERT_RC_DEV + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwEnterSharedDebug(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwEnterSharedDebug(pDevIns, pCritSect, rcBusy, uId, RT_SRC_POS_ARGS); +} + +/** + * @sa PDMCritSectRwTryEnterShared + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwTryEnterShared(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwTryEnterShared(pDevIns, pCritSect); +} + +/** + * @sa PDMCritSectRwTryEnterSharedDebug + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwTryEnterSharedDebug(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwTryEnterSharedDebug(pDevIns, pCritSect, uId, RT_SRC_POS_ARGS); +} + +/** + * @sa PDMCritSectRwLeaveShared + */ +DECLINLINE(int) PDMDevHlpCritSectRwLeaveShared(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwLeaveShared(pDevIns, pCritSect); +} + +/** + * @sa PDMCritSectRwEnterExcl, PDM_CRITSECT_RELEASE_ASSERT_RC_DEV + */ +DECLINLINE(DECL_CHECK_RETURN(int)) PDMDevHlpCritSectRwEnterExcl(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwEnterExcl(pDevIns, pCritSect, rcBusy); +} + +/** + * @sa PDMCritSectRwEnterExclDebug, PDM_CRITSECT_RELEASE_ASSERT_RC_DEV + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwEnterExclDebug(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwEnterExclDebug(pDevIns, pCritSect, rcBusy, uId, RT_SRC_POS_ARGS); +} + +/** + * @sa PDMCritSectRwTryEnterExcl + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwTryEnterExcl(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwTryEnterExcl(pDevIns, pCritSect); +} + +/** + * @sa PDMCritSectRwTryEnterExclDebug + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwTryEnterExclDebug(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwTryEnterExclDebug(pDevIns, pCritSect, uId, RT_SRC_POS_ARGS); +} + +/** + * @sa PDMCritSectRwLeaveExcl + */ +DECLINLINE(int) PDMDevHlpCritSectRwLeaveExcl(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwLeaveExcl(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectRwIsWriteOwner + */ +DECLINLINE(bool) PDMDevHlpCritSectRwIsWriteOwner(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwIsWriteOwner(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectRwIsReadOwner + */ +DECLINLINE(bool) PDMDevHlpCritSectRwIsReadOwner(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, bool fWannaHear) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwIsReadOwner(pDevIns, pCritSect, fWannaHear); +} + +/** + * @see PDMCritSectRwGetWriteRecursion + */ +DECLINLINE(uint32_t) PDMDevHlpCritSectRwGetWriteRecursion(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwGetWriteRecursion(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectRwGetWriterReadRecursion + */ +DECLINLINE(uint32_t) PDMDevHlpCritSectRwGetWriterReadRecursion(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwGetWriterReadRecursion(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectRwGetReadCount + */ +DECLINLINE(uint32_t) PDMDevHlpCritSectRwGetReadCount(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwGetReadCount(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectRwIsInitialized + */ +DECLINLINE(bool) PDMDevHlpCritSectRwIsInitialized(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwIsInitialized(pDevIns, pCritSect); +} + +/* Strict build: Remap the two enter calls to the debug versions. */ +#ifdef VBOX_STRICT +# ifdef IPRT_INCLUDED_asm_h +# define PDMDevHlpCritSectRwEnterShared(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectRwEnterSharedDebug((pDevIns), (pCritSect), (rcBusy), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMDevHlpCritSectRwTryEnterShared(pDevIns, pCritSect) PDMDevHlpCritSectRwTryEnterSharedDebug((pDevIns), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMDevHlpCritSectRwEnterExcl(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectRwEnterExclDebug((pDevIns), (pCritSect), (rcBusy), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMDevHlpCritSectRwTryEnterExcl(pDevIns, pCritSect) PDMDevHlpCritSectRwTryEnterExclDebug((pDevIns), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define PDMDevHlpCritSectRwEnterShared(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectRwEnterSharedDebug((pDevIns), (pCritSect), (rcBusy), 0, RT_SRC_POS) +# define PDMDevHlpCritSectRwTryEnterShared(pDevIns, pCritSect) PDMDevHlpCritSectRwTryEnterSharedDebug((pDevIns), (pCritSect), 0, RT_SRC_POS) +# define PDMDevHlpCritSectRwEnterExcl(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectRwEnterExclDebug((pDevIns), (pCritSect), (rcBusy), 0, RT_SRC_POS) +# define PDMDevHlpCritSectRwTryEnterExcl(pDevIns, pCritSect) PDMDevHlpCritSectRwTryEnterExclDebug((pDevIns), (pCritSect), 0, RT_SRC_POS) +# endif +#endif + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @copydoc PDMDEVHLPR3::pfnThreadCreate + */ +DECLINLINE(int) PDMDevHlpThreadCreate(PPDMDEVINS pDevIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDEV pfnThread, + PFNPDMTHREADWAKEUPDEV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName) +{ + return pDevIns->pHlpR3->pfnThreadCreate(pDevIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName); +} + +/** + * @copydoc PDMR3ThreadDestroy + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadDestroy(PPDMDEVINS pDevIns, PPDMTHREAD pThread, int *pRcThread) +{ + return pDevIns->pHlpR3->pfnThreadDestroy(pThread, pRcThread); +} + +/** + * @copydoc PDMR3ThreadIAmSuspending + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadIAmSuspending(PPDMDEVINS pDevIns, PPDMTHREAD pThread) +{ + return pDevIns->pHlpR3->pfnThreadIAmSuspending(pThread); +} + +/** + * @copydoc PDMR3ThreadIAmRunning + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadIAmRunning(PPDMDEVINS pDevIns, PPDMTHREAD pThread) +{ + return pDevIns->pHlpR3->pfnThreadIAmRunning(pThread); +} + +/** + * @copydoc PDMR3ThreadSleep + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadSleep(PPDMDEVINS pDevIns, PPDMTHREAD pThread, RTMSINTERVAL cMillies) +{ + return pDevIns->pHlpR3->pfnThreadSleep(pThread, cMillies); +} + +/** + * @copydoc PDMR3ThreadSuspend + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadSuspend(PPDMDEVINS pDevIns, PPDMTHREAD pThread) +{ + return pDevIns->pHlpR3->pfnThreadSuspend(pThread); +} + +/** + * @copydoc PDMR3ThreadResume + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadResume(PPDMDEVINS pDevIns, PPDMTHREAD pThread) +{ + return pDevIns->pHlpR3->pfnThreadResume(pThread); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSetAsyncNotification + */ +DECLINLINE(int) PDMDevHlpSetAsyncNotification(PPDMDEVINS pDevIns, PFNPDMDEVASYNCNOTIFY pfnAsyncNotify) +{ + return pDevIns->pHlpR3->pfnSetAsyncNotification(pDevIns, pfnAsyncNotify); +} + +/** + * @copydoc PDMDEVHLPR3::pfnAsyncNotificationCompleted + */ +DECLINLINE(void) PDMDevHlpAsyncNotificationCompleted(PPDMDEVINS pDevIns) +{ + pDevIns->pHlpR3->pfnAsyncNotificationCompleted(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnA20Set + */ +DECLINLINE(void) PDMDevHlpA20Set(PPDMDEVINS pDevIns, bool fEnable) +{ + pDevIns->pHlpR3->pfnA20Set(pDevIns, fEnable); +} + +/** + * @copydoc PDMDEVHLPR3::pfnRTCRegister + */ +DECLINLINE(int) PDMDevHlpRTCRegister(PPDMDEVINS pDevIns, PCPDMRTCREG pRtcReg, PCPDMRTCHLP *ppRtcHlp) +{ + return pDevIns->pHlpR3->pfnRTCRegister(pDevIns, pRtcReg, ppRtcHlp); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIBusRegister + */ +DECLINLINE(int) PDMDevHlpPCIBusRegister(PPDMDEVINS pDevIns, PPDMPCIBUSREGR3 pPciBusReg, PCPDMPCIHLPR3 *ppPciHlp, uint32_t *piBus) +{ + return pDevIns->pHlpR3->pfnPCIBusRegister(pDevIns, pPciBusReg, ppPciHlp, piBus); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIommuRegister + */ +DECLINLINE(int) PDMDevHlpIommuRegister(PPDMDEVINS pDevIns, PPDMIOMMUREGR3 pIommuReg, PCPDMIOMMUHLPR3 *ppIommuHlp, uint32_t *pidxIommu) +{ + return pDevIns->pHlpR3->pfnIommuRegister(pDevIns, pIommuReg, ppIommuHlp, pidxIommu); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPICRegister + */ +DECLINLINE(int) PDMDevHlpPICRegister(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLP *ppPicHlp) +{ + return pDevIns->pHlpR3->pfnPICRegister(pDevIns, pPicReg, ppPicHlp); +} + +/** + * @copydoc PDMDEVHLPR3::pfnApicRegister + */ +DECLINLINE(int) PDMDevHlpApicRegister(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnApicRegister(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIoApicRegister + */ +DECLINLINE(int) PDMDevHlpIoApicRegister(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLP *ppIoApicHlp) +{ + return pDevIns->pHlpR3->pfnIoApicRegister(pDevIns, pIoApicReg, ppIoApicHlp); +} + +/** + * @copydoc PDMDEVHLPR3::pfnHpetRegister + */ +DECLINLINE(int) PDMDevHlpHpetRegister(PPDMDEVINS pDevIns, PPDMHPETREG pHpetReg, PCPDMHPETHLPR3 *ppHpetHlpR3) +{ + return pDevIns->pHlpR3->pfnHpetRegister(pDevIns, pHpetReg, ppHpetHlpR3); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPciRawRegister + */ +DECLINLINE(int) PDMDevHlpPciRawRegister(PPDMDEVINS pDevIns, PPDMPCIRAWREG pPciRawReg, PCPDMPCIRAWHLPR3 *ppPciRawHlpR3) +{ + return pDevIns->pHlpR3->pfnPciRawRegister(pDevIns, pPciRawReg, ppPciRawHlpR3); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMACRegister + */ +DECLINLINE(int) PDMDevHlpDMACRegister(PPDMDEVINS pDevIns, PPDMDMACREG pDmacReg, PCPDMDMACHLP *ppDmacHlp) +{ + return pDevIns->pHlpR3->pfnDMACRegister(pDevIns, pDmacReg, ppDmacHlp); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMARegister + */ +DECLINLINE(int) PDMDevHlpDMARegister(PPDMDEVINS pDevIns, unsigned uChannel, PFNDMATRANSFERHANDLER pfnTransferHandler, void *pvUser) +{ + return pDevIns->pHlpR3->pfnDMARegister(pDevIns, uChannel, pfnTransferHandler, pvUser); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMAReadMemory + */ +DECLINLINE(int) PDMDevHlpDMAReadMemory(PPDMDEVINS pDevIns, unsigned uChannel, void *pvBuffer, uint32_t off, uint32_t cbBlock, uint32_t *pcbRead) +{ + return pDevIns->pHlpR3->pfnDMAReadMemory(pDevIns, uChannel, pvBuffer, off, cbBlock, pcbRead); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMAWriteMemory + */ +DECLINLINE(int) PDMDevHlpDMAWriteMemory(PPDMDEVINS pDevIns, unsigned uChannel, const void *pvBuffer, uint32_t off, uint32_t cbBlock, uint32_t *pcbWritten) +{ + return pDevIns->pHlpR3->pfnDMAWriteMemory(pDevIns, uChannel, pvBuffer, off, cbBlock, pcbWritten); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMASetDREQ + */ +DECLINLINE(int) PDMDevHlpDMASetDREQ(PPDMDEVINS pDevIns, unsigned uChannel, unsigned uLevel) +{ + return pDevIns->pHlpR3->pfnDMASetDREQ(pDevIns, uChannel, uLevel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMAGetChannelMode + */ +DECLINLINE(uint8_t) PDMDevHlpDMAGetChannelMode(PPDMDEVINS pDevIns, unsigned uChannel) +{ + return pDevIns->pHlpR3->pfnDMAGetChannelMode(pDevIns, uChannel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMASchedule + */ +DECLINLINE(void) PDMDevHlpDMASchedule(PPDMDEVINS pDevIns) +{ + pDevIns->pHlpR3->pfnDMASchedule(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCMOSWrite + */ +DECLINLINE(int) PDMDevHlpCMOSWrite(PPDMDEVINS pDevIns, unsigned iReg, uint8_t u8Value) +{ + return pDevIns->pHlpR3->pfnCMOSWrite(pDevIns, iReg, u8Value); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCMOSRead + */ +DECLINLINE(int) PDMDevHlpCMOSRead(PPDMDEVINS pDevIns, unsigned iReg, uint8_t *pu8Value) +{ + return pDevIns->pHlpR3->pfnCMOSRead(pDevIns, iReg, pu8Value); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCallR0 + */ +DECLINLINE(int) PDMDevHlpCallR0(PPDMDEVINS pDevIns, uint32_t uOperation, uint64_t u64Arg) +{ + return pDevIns->pHlpR3->pfnCallR0(pDevIns, uOperation, u64Arg); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMGetSuspendReason + */ +DECLINLINE(VMSUSPENDREASON) PDMDevHlpVMGetSuspendReason(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMGetSuspendReason(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMGetResumeReason + */ +DECLINLINE(VMRESUMEREASON) PDMDevHlpVMGetResumeReason(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMGetResumeReason(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnGetUVM + */ +DECLINLINE(PUVM) PDMDevHlpGetUVM(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetUVM(pDevIns); +} + +#endif /* IN_RING3 || DOXYGEN_RUNNING */ + +#if !defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @copydoc PDMDEVHLPR0::pfnPCIBusSetUpContext + */ +DECLINLINE(int) PDMDevHlpPCIBusSetUpContext(PPDMDEVINS pDevIns, CTX_SUFF(PPDMPCIBUSREG) pPciBusReg, CTX_SUFF(PCPDMPCIHLP) *ppPciHlp) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIBusSetUpContext(pDevIns, pPciBusReg, ppPciHlp); +} + +/** + * @copydoc PDMDEVHLPR0::pfnIommuSetUpContext + */ +DECLINLINE(int) PDMDevHlpIommuSetUpContext(PPDMDEVINS pDevIns, CTX_SUFF(PPDMIOMMUREG) pIommuReg, CTX_SUFF(PCPDMIOMMUHLP) *ppIommuHlp) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnIommuSetUpContext(pDevIns, pIommuReg, ppIommuHlp); +} + +/** + * @copydoc PDMDEVHLPR0::pfnPICSetUpContext + */ +DECLINLINE(int) PDMDevHlpPICSetUpContext(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLP *ppPicHlp) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPICSetUpContext(pDevIns, pPicReg, ppPicHlp); +} + +/** + * @copydoc PDMDEVHLPR0::pfnApicSetUpContext + */ +DECLINLINE(int) PDMDevHlpApicSetUpContext(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnApicSetUpContext(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR0::pfnIoApicSetUpContext + */ +DECLINLINE(int) PDMDevHlpIoApicSetUpContext(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLP *ppIoApicHlp) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnIoApicSetUpContext(pDevIns, pIoApicReg, ppIoApicHlp); +} + +/** + * @copydoc PDMDEVHLPR0::pfnHpetSetUpContext + */ +DECLINLINE(int) PDMDevHlpHpetSetUpContext(PPDMDEVINS pDevIns, PPDMHPETREG pHpetReg, CTX_SUFF(PCPDMHPETHLP) *ppHpetHlp) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnHpetSetUpContext(pDevIns, pHpetReg, ppHpetHlp); +} + +#endif /* !IN_RING3 || DOXYGEN_RUNNING */ + +/** + * @copydoc PDMDEVHLPR3::pfnGetVM + */ +DECLINLINE(PVMCC) PDMDevHlpGetVM(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetVM(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnGetVMCPU + */ +DECLINLINE(PVMCPUCC) PDMDevHlpGetVMCPU(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetVMCPU(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnGetCurrentCpuId + */ +DECLINLINE(VMCPUID) PDMDevHlpGetCurrentCpuId(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetCurrentCpuId(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTMTimeVirtGet + */ +DECLINLINE(uint64_t) PDMDevHlpTMTimeVirtGet(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTMTimeVirtGet(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTMTimeVirtGetFreq + */ +DECLINLINE(uint64_t) PDMDevHlpTMTimeVirtGetFreq(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTMTimeVirtGetFreq(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTMTimeVirtGetFreq + */ +DECLINLINE(uint64_t) PDMDevHlpTMTimeVirtGetNano(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTMTimeVirtGetNano(pDevIns); +} + +#ifdef IN_RING3 +/** + * @copydoc PDMDEVHLPR3::pfnTMCpuTicksPerSecond + */ +DECLINLINE(uint64_t) PDMDevHlpTMCpuTicksPerSecond(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTMCpuTicksPerSecond(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnRegisterVMMDevHeap + */ +DECLINLINE(int) PDMDevHlpRegisterVMMDevHeap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbHeap) +{ + return pDevIns->pHlpR3->pfnRegisterVMMDevHeap(pDevIns, GCPhys, pvHeap, cbHeap); +} + +/** + * @copydoc PDMDEVHLPR3::pfnFirmwareRegister + */ +DECLINLINE(int) PDMDevHlpFirmwareRegister(PPDMDEVINS pDevIns, PCPDMFWREG pFwReg, PCPDMFWHLPR3 *ppFwHlp) +{ + return pDevIns->pHlpR3->pfnFirmwareRegister(pDevIns, pFwReg, ppFwHlp); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMReset + */ +DECLINLINE(int) PDMDevHlpVMReset(PPDMDEVINS pDevIns, uint32_t fFlags) +{ + return pDevIns->pHlpR3->pfnVMReset(pDevIns, fFlags); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMSuspend + */ +DECLINLINE(int) PDMDevHlpVMSuspend(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMSuspend(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMSuspendSaveAndPowerOff + */ +DECLINLINE(int) PDMDevHlpVMSuspendSaveAndPowerOff(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMSuspendSaveAndPowerOff(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMPowerOff + */ +DECLINLINE(int) PDMDevHlpVMPowerOff(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMPowerOff(pDevIns); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnA20IsEnabled + */ +DECLINLINE(bool) PDMDevHlpA20IsEnabled(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnA20IsEnabled(pDevIns); +} + +#ifdef IN_RING3 +/** + * @copydoc PDMDEVHLPR3::pfnGetCpuId + */ +DECLINLINE(void) PDMDevHlpGetCpuId(PPDMDEVINS pDevIns, uint32_t iLeaf, uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx) +{ + pDevIns->pHlpR3->pfnGetCpuId(pDevIns, iLeaf, pEax, pEbx, pEcx, pEdx); +} +#endif + +/** + * @copydoc PDMDEVHLPR3::pfnGetMainExecutionEngine + */ +DECLINLINE(uint8_t) PDMDevHlpGetMainExecutionEngine(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetMainExecutionEngine(pDevIns); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnGetSupDrvSession + */ +DECLINLINE(PSUPDRVSESSION) PDMDevHlpGetSupDrvSession(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnGetSupDrvSession(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnQueryGenericUserObject + */ +DECLINLINE(void *) PDMDevHlpQueryGenericUserObject(PPDMDEVINS pDevIns, PCRTUUID pUuid) +{ + return pDevIns->pHlpR3->pfnQueryGenericUserObject(pDevIns, pUuid); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPGMHandlerPhysicalTypeRegister + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalTypeRegister(PPDMDEVINS pDevIns, PGMPHYSHANDLERKIND enmKind, + PFNPGMPHYSHANDLER pfnHandler, const char *pszDesc, + PPGMPHYSHANDLERTYPE phType) +{ + return pDevIns->pHlpR3->pfnPGMHandlerPhysicalTypeRegister(pDevIns, enmKind, pfnHandler, pszDesc, phType); +} + +#elif defined(IN_RING0) + +/** + * @copydoc PDMDEVHLPR0::pfnPGMHandlerPhysicalTypeSetUpContext + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalTypeSetUpContext(PPDMDEVINS pDevIns, PGMPHYSHANDLERKIND enmKind, + PFNPGMPHYSHANDLER pfnHandler, PFNPGMRZPHYSPFHANDLER pfnPfHandler, + const char *pszDesc, PGMPHYSHANDLERTYPE hType) +{ + return pDevIns->pHlpR0->pfnPGMHandlerPhysicalTypeSetUpContext(pDevIns, enmKind, pfnHandler, pfnPfHandler, pszDesc, hType); +} + +#endif +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnPGMHandlerPhysicalRegister + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalRegister(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, + PGMPHYSHANDLERTYPE hType, R3PTRTYPE(const char *) pszDesc) +{ + return pDevIns->pHlpR3->pfnPGMHandlerPhysicalRegister(pDevIns, GCPhys, GCPhysLast, hType, pszDesc); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPGMHandlerPhysicalDeregister + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalDeregister(PPDMDEVINS pDevIns, RTGCPHYS GCPhys) +{ + return pDevIns->pHlpR3->pfnPGMHandlerPhysicalDeregister(pDevIns, GCPhys); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnPGMHandlerPhysicalPageTempOff + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalPageTempOff(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPGMHandlerPhysicalPageTempOff(pDevIns, GCPhys, GCPhysPage); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnPGMHandlerPhysicalReset + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalReset(PPDMDEVINS pDevIns, RTGCPHYS GCPhys) +{ + return pDevIns->pHlpR3->pfnPGMHandlerPhysicalReset(pDevIns, GCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMMRegisterPatchMemory + */ +DECLINLINE(int) PDMDevHlpVMMRegisterPatchMemory(PPDMDEVINS pDevIns, RTGCPTR GCPtrPatchMem, uint32_t cbPatchMem) +{ + return pDevIns->pHlpR3->pfnVMMRegisterPatchMemory(pDevIns, GCPtrPatchMem, cbPatchMem); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMMDeregisterPatchMemory + */ +DECLINLINE(int) PDMDevHlpVMMDeregisterPatchMemory(PPDMDEVINS pDevIns, RTGCPTR GCPtrPatchMem, uint32_t cbPatchMem) +{ + return pDevIns->pHlpR3->pfnVMMDeregisterPatchMemory(pDevIns, GCPtrPatchMem, cbPatchMem); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSharedModuleRegister + */ +DECLINLINE(int) PDMDevHlpSharedModuleRegister(PPDMDEVINS pDevIns, VBOXOSFAMILY enmGuestOS, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule, + uint32_t cRegions, VMMDEVSHAREDREGIONDESC const *paRegions) +{ + return pDevIns->pHlpR3->pfnSharedModuleRegister(pDevIns, enmGuestOS, pszModuleName, pszVersion, + GCBaseAddr, cbModule, cRegions, paRegions); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSharedModuleUnregister + */ +DECLINLINE(int) PDMDevHlpSharedModuleUnregister(PPDMDEVINS pDevIns, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule) +{ + return pDevIns->pHlpR3->pfnSharedModuleUnregister(pDevIns, pszModuleName, pszVersion, GCBaseAddr, cbModule); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSharedModuleGetPageState + */ +DECLINLINE(int) PDMDevHlpSharedModuleGetPageState(PPDMDEVINS pDevIns, RTGCPTR GCPtrPage, bool *pfShared, + uint64_t *pfPageFlags) +{ + return pDevIns->pHlpR3->pfnSharedModuleGetPageState(pDevIns, GCPtrPage, pfShared, pfPageFlags); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSharedModuleCheckAll + */ +DECLINLINE(int) PDMDevHlpSharedModuleCheckAll(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnSharedModuleCheckAll(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnQueryLun + */ +DECLINLINE(int) PDMDevHlpQueryLun(PPDMDEVINS pDevIns, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase) +{ + return pDevIns->pHlpR3->pfnQueryLun(pDevIns, pszDevice, iInstance, iLun, ppBase); +} + +/** + * @copydoc PDMDEVHLPR3::pfnGIMDeviceRegister + */ +DECLINLINE(void) PDMDevHlpGIMDeviceRegister(PPDMDEVINS pDevIns, PGIMDEBUG pDbg) +{ + pDevIns->pHlpR3->pfnGIMDeviceRegister(pDevIns, pDbg); +} + +/** + * @copydoc PDMDEVHLPR3::pfnGIMGetDebugSetup + */ +DECLINLINE(int) PDMDevHlpGIMGetDebugSetup(PPDMDEVINS pDevIns, PGIMDEBUGSETUP pDbgSetup) +{ + return pDevIns->pHlpR3->pfnGIMGetDebugSetup(pDevIns, pDbgSetup); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnGIMGetMmio2Regions + */ +DECLINLINE(PGIMMMIO2REGION) PDMDevHlpGIMGetMmio2Regions(PPDMDEVINS pDevIns, uint32_t *pcRegions) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGIMGetMmio2Regions(pDevIns, pcRegions); +} + +#ifdef IN_RING3 + +/** Wrapper around SSMR3GetU32 for simplifying getting enum values saved as uint32_t. */ +# define PDMDEVHLP_SSM_GET_ENUM32_RET(a_pHlp, a_pSSM, a_enmDst, a_EnumType) \ + do { \ + uint32_t u32GetEnumTmp = 0; \ + int rcGetEnum32Tmp = (a_pHlp)->pfnSSMGetU32((a_pSSM), &u32GetEnumTmp); \ + AssertRCReturn(rcGetEnum32Tmp, rcGetEnum32Tmp); \ + (a_enmDst) = (a_EnumType)u32GetEnumTmp; \ + AssertCompile(sizeof(a_EnumType) == sizeof(u32GetEnumTmp)); \ + } while (0) + +/** Wrapper around SSMR3GetU8 for simplifying getting enum values saved as uint8_t. */ +# define PDMDEVHLP_SSM_GET_ENUM8_RET(a_pHlp, a_pSSM, a_enmDst, a_EnumType) \ + do { \ + uint8_t bGetEnumTmp = 0; \ + int rcGetEnum32Tmp = (a_pHlp)->pfnSSMGetU8((a_pSSM), &bGetEnumTmp); \ + AssertRCReturn(rcGetEnum32Tmp, rcGetEnum32Tmp); \ + (a_enmDst) = (a_EnumType)bGetEnumTmp; \ + } while (0) + +#endif /* IN_RING3 */ + +/** Pointer to callbacks provided to the VBoxDeviceRegister() call. */ +typedef struct PDMDEVREGCB *PPDMDEVREGCB; + +/** + * Callbacks for VBoxDeviceRegister(). + */ +typedef struct PDMDEVREGCB +{ + /** Interface version. + * This is set to PDM_DEVREG_CB_VERSION. */ + uint32_t u32Version; + + /** + * Registers a device with the current VM instance. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param pReg Pointer to the device registration record. + * This data must be permanent and readonly. + */ + DECLR3CALLBACKMEMBER(int, pfnRegister,(PPDMDEVREGCB pCallbacks, PCPDMDEVREG pReg)); +} PDMDEVREGCB; + +/** Current version of the PDMDEVREGCB structure. */ +#define PDM_DEVREG_CB_VERSION PDM_VERSION_MAKE(0xffe3, 1, 0) + + +/** + * The VBoxDevicesRegister callback function. + * + * PDM will invoke this function after loading a device module and letting + * the module decide which devices to register and how to handle conflicts. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param u32Version VBox version number. + */ +typedef DECLCALLBACKTYPE(int, FNPDMVBOXDEVICESREGISTER,(PPDMDEVREGCB pCallbacks, uint32_t u32Version)); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmdev_h */ diff --git a/include/VBox/vmm/pdmdrv.h b/include/VBox/vmm/pdmdrv.h new file mode 100644 index 00000000..6c0ee40f --- /dev/null +++ b/include/VBox/vmm/pdmdrv.h @@ -0,0 +1,2497 @@ +/** @file + * PDM - Pluggable Device Manager, Drivers. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmdrv_h +#define VBOX_INCLUDED_vmm_pdmdrv_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/pdmqueue.h> +#include <VBox/vmm/pdmcritsect.h> +#include <VBox/vmm/pdmifs.h> +#include <VBox/vmm/pdmins.h> +#include <VBox/vmm/pdmcommon.h> +#ifdef IN_RING3 +# include <VBox/vmm/pdmthread.h> +# include <VBox/vmm/pdmasynccompletion.h> +# include <VBox/vmm/pdmblkcache.h> +#endif +#include <VBox/vmm/tm.h> +#include <VBox/vmm/ssm.h> +#include <VBox/vmm/cfgm.h> +#include <VBox/vmm/dbgf.h> +#include <VBox/vmm/mm.h> +#include <iprt/stdarg.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_driver The PDM Drivers API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer const PDM Driver API, ring-3. */ +typedef R3PTRTYPE(struct PDMDRVHLPR3 const *) PCPDMDRVHLPR3; +/** Pointer const PDM Driver API, ring-0. */ +typedef R0PTRTYPE(struct PDMDRVHLPR0 const *) PCPDMDRVHLPR0; +/** Pointer const PDM Driver API, raw-mode context. */ +typedef RCPTRTYPE(struct PDMDRVHLPRC const *) PCPDMDRVHLPRC; + + +/** + * Construct a driver instance for a VM. + * + * @returns VBox status. + * @param pDrvIns The driver instance data. If the registration structure + * is needed, it can be accessed thru pDrvIns->pReg. + * @param pCfg Configuration node handle for the driver. This is + * expected to be in high demand in the constructor and is + * therefore passed as an argument. When using it at other + * times, it can be accessed via pDrvIns->pCfg. + * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDRVCONSTRUCT,(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)); +/** Pointer to a FNPDMDRVCONSTRUCT() function. */ +typedef FNPDMDRVCONSTRUCT *PFNPDMDRVCONSTRUCT; + +/** + * Destruct a driver instance. + * + * Most VM resources are freed by the VM. This callback is provided so that + * any non-VM resources can be freed correctly. + * + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVDESTRUCT,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVDESTRUCT() function. */ +typedef FNPDMDRVDESTRUCT *PFNPDMDRVDESTRUCT; + +/** + * Driver relocation callback. + * + * This is called when the instance data has been relocated in raw-mode context + * (RC). It is also called when the RC hypervisor selects changes. The driver + * must fixup all necessary pointers and re-query all interfaces to other RC + * devices and drivers. + * + * Before the RC code is executed the first time, this function will be called + * with a 0 delta so RC pointer calculations can be one in one place. + * + * @param pDrvIns Pointer to the driver instance. + * @param offDelta The relocation delta relative to the old location. + * + * @remark A relocation CANNOT fail. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVRELOCATE,(PPDMDRVINS pDrvIns, RTGCINTPTR offDelta)); +/** Pointer to a FNPDMDRVRELOCATE() function. */ +typedef FNPDMDRVRELOCATE *PFNPDMDRVRELOCATE; + +/** + * Driver I/O Control interface. + * + * This is used by external components, such as the COM interface, to + * communicate with a driver using a driver specific interface. Generally, + * the driver interfaces are used for this task. + * + * @returns VBox status code. + * @param pDrvIns Pointer to the driver instance. + * @param uFunction Function to perform. + * @param pvIn Pointer to input data. + * @param cbIn Size of input data. + * @param pvOut Pointer to output data. + * @param cbOut Size of output data. + * @param pcbOut Where to store the actual size of the output data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDRVIOCTL,(PPDMDRVINS pDrvIns, uint32_t uFunction, + void *pvIn, uint32_t cbIn, + void *pvOut, uint32_t cbOut, uint32_t *pcbOut)); +/** Pointer to a FNPDMDRVIOCTL() function. */ +typedef FNPDMDRVIOCTL *PFNPDMDRVIOCTL; + +/** + * Power On notification. + * + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVPOWERON,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVPOWERON() function. */ +typedef FNPDMDRVPOWERON *PFNPDMDRVPOWERON; + +/** + * Reset notification. + * + * @returns VBox status. + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVRESET,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVRESET() function. */ +typedef FNPDMDRVRESET *PFNPDMDRVRESET; + +/** + * Suspend notification. + * + * @returns VBox status. + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVSUSPEND,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVSUSPEND() function. */ +typedef FNPDMDRVSUSPEND *PFNPDMDRVSUSPEND; + +/** + * Resume notification. + * + * @returns VBox status. + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVRESUME,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVRESUME() function. */ +typedef FNPDMDRVRESUME *PFNPDMDRVRESUME; + +/** + * Power Off notification. + * + * This is always called when VMR3PowerOff is called. + * There will be no callback when hot plugging devices or when replumbing the driver + * stack. + * + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVPOWEROFF,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVPOWEROFF() function. */ +typedef FNPDMDRVPOWEROFF *PFNPDMDRVPOWEROFF; + +/** + * Attach command. + * + * This is called to let the driver attach to a driver at runtime. This is not + * called during VM construction, the driver constructor have to do this by + * calling PDMDrvHlpAttach. + * + * This is like plugging in the keyboard or mouse after turning on the PC. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDRVATTACH,(PPDMDRVINS pDrvIns, uint32_t fFlags)); +/** Pointer to a FNPDMDRVATTACH() function. */ +typedef FNPDMDRVATTACH *PFNPDMDRVATTACH; + +/** + * Detach notification. + * + * This is called when a driver below it in the chain is detaching itself + * from it. The driver should adjust it's state to reflect this. + * + * This is like ejecting a cdrom or floppy. + * + * @param pDrvIns The driver instance. + * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG or 0. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVDETACH,(PPDMDRVINS pDrvIns, uint32_t fFlags)); +/** Pointer to a FNPDMDRVDETACH() function. */ +typedef FNPDMDRVDETACH *PFNPDMDRVDETACH; + + + +/** + * PDM Driver Registration Structure. + * + * This structure is used when registering a driver from VBoxInitDrivers() (in + * host ring-3 context). PDM will continue use till the VM is terminated. + */ +typedef struct PDMDRVREG +{ + /** Structure version. PDM_DRVREG_VERSION defines the current version. */ + uint32_t u32Version; + /** Driver name. */ + char szName[32]; + /** Name of the raw-mode context module (no path). + * Only evalutated if PDM_DRVREG_FLAGS_RC is set. */ + char szRCMod[32]; + /** Name of the ring-0 module (no path). + * Only evalutated if PDM_DRVREG_FLAGS_R0 is set. */ + char szR0Mod[32]; + /** The description of the driver. The UTF-8 string pointed to shall, like this structure, + * remain unchanged from registration till VM destruction. */ + const char *pszDescription; + + /** Flags, combination of the PDM_DRVREG_FLAGS_* \#defines. */ + uint32_t fFlags; + /** Driver class(es), combination of the PDM_DRVREG_CLASS_* \#defines. */ + uint32_t fClass; + /** Maximum number of instances (per VM). */ + uint32_t cMaxInstances; + /** Size of the instance data. */ + uint32_t cbInstance; + + /** Construct instance - required. */ + PFNPDMDRVCONSTRUCT pfnConstruct; + /** Destruct instance - optional. */ + PFNPDMDRVDESTRUCT pfnDestruct; + /** Relocation command - optional. */ + PFNPDMDRVRELOCATE pfnRelocate; + /** I/O control - optional. */ + PFNPDMDRVIOCTL pfnIOCtl; + /** Power on notification - optional. */ + PFNPDMDRVPOWERON pfnPowerOn; + /** Reset notification - optional. */ + PFNPDMDRVRESET pfnReset; + /** Suspend notification - optional. */ + PFNPDMDRVSUSPEND pfnSuspend; + /** Resume notification - optional. */ + PFNPDMDRVRESUME pfnResume; + /** Attach command - optional. */ + PFNPDMDRVATTACH pfnAttach; + /** Detach notification - optional. */ + PFNPDMDRVDETACH pfnDetach; + /** Power off notification - optional. */ + PFNPDMDRVPOWEROFF pfnPowerOff; + /** @todo */ + PFNRT pfnSoftReset; + /** Initialization safty marker. */ + uint32_t u32VersionEnd; +} PDMDRVREG; +/** Pointer to a PDM Driver Structure. */ +typedef PDMDRVREG *PPDMDRVREG; +/** Const pointer to a PDM Driver Structure. */ +typedef PDMDRVREG const *PCPDMDRVREG; + +/** Current DRVREG version number. */ +#define PDM_DRVREG_VERSION PDM_VERSION_MAKE(0xf0ff, 1, 0) + +/** PDM Driver Flags. + * @{ */ +/** @def PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT + * The bit count for the current host. */ +#if HC_ARCH_BITS == 32 +# define PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT UINT32_C(0x00000001) +#elif HC_ARCH_BITS == 64 +# define PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT UINT32_C(0x00000002) +#else +# error Unsupported HC_ARCH_BITS value. +#endif +/** The host bit count mask. */ +#define PDM_DRVREG_FLAGS_HOST_BITS_MASK UINT32_C(0x00000003) +/** This flag is used to indicate that the driver has a RC component. */ +#define PDM_DRVREG_FLAGS_RC UINT32_C(0x00000010) +/** This flag is used to indicate that the driver has a R0 component. */ +#define PDM_DRVREG_FLAGS_R0 UINT32_C(0x00000020) + +/** @} */ + + +/** PDM Driver Classes. + * @{ */ +/** Mouse input driver. */ +#define PDM_DRVREG_CLASS_MOUSE RT_BIT(0) +/** Keyboard input driver. */ +#define PDM_DRVREG_CLASS_KEYBOARD RT_BIT(1) +/** Display driver. */ +#define PDM_DRVREG_CLASS_DISPLAY RT_BIT(2) +/** Network transport driver. */ +#define PDM_DRVREG_CLASS_NETWORK RT_BIT(3) +/** Block driver. */ +#define PDM_DRVREG_CLASS_BLOCK RT_BIT(4) +/** Media driver. */ +#define PDM_DRVREG_CLASS_MEDIA RT_BIT(5) +/** Mountable driver. */ +#define PDM_DRVREG_CLASS_MOUNTABLE RT_BIT(6) +/** Audio driver. */ +#define PDM_DRVREG_CLASS_AUDIO RT_BIT(7) +/** VMMDev driver. */ +#define PDM_DRVREG_CLASS_VMMDEV RT_BIT(8) +/** Status driver. */ +#define PDM_DRVREG_CLASS_STATUS RT_BIT(9) +/** ACPI driver. */ +#define PDM_DRVREG_CLASS_ACPI RT_BIT(10) +/** USB related driver. */ +#define PDM_DRVREG_CLASS_USB RT_BIT(11) +/** ISCSI Transport related driver. */ +#define PDM_DRVREG_CLASS_ISCSITRANSPORT RT_BIT(12) +/** Char driver. */ +#define PDM_DRVREG_CLASS_CHAR RT_BIT(13) +/** Stream driver. */ +#define PDM_DRVREG_CLASS_STREAM RT_BIT(14) +/** SCSI driver. */ +#define PDM_DRVREG_CLASS_SCSI RT_BIT(15) +/** Generic raw PCI device driver. */ +#define PDM_DRVREG_CLASS_PCIRAW RT_BIT(16) +/** @} */ + + +/** + * PDM Driver Instance. + * + * @implements PDMIBASE + */ +typedef struct PDMDRVINS +{ + /** Structure version. PDM_DRVINS_VERSION defines the current version. */ + uint32_t u32Version; + /** Driver instance number. */ + uint32_t iInstance; + + /** Pointer the PDM Driver API. */ + RCPTRTYPE(PCPDMDRVHLPRC) pHlpRC; + /** Pointer to driver instance data. */ + RCPTRTYPE(void *) pvInstanceDataRC; + + /** Pointer the PDM Driver API. */ + R0PTRTYPE(PCPDMDRVHLPR0) pHlpR0; + /** Pointer to driver instance data. */ + R0PTRTYPE(void *) pvInstanceDataR0; + + /** Pointer the PDM Driver API. */ + R3PTRTYPE(PCPDMDRVHLPR3) pHlpR3; + /** Pointer to driver instance data. */ + R3PTRTYPE(void *) pvInstanceDataR3; + + /** Pointer to driver registration structure. */ + R3PTRTYPE(PCPDMDRVREG) pReg; + /** Configuration handle. */ + R3PTRTYPE(PCFGMNODE) pCfg; + + /** Pointer to the base interface of the device/driver instance above. */ + R3PTRTYPE(PPDMIBASE) pUpBase; + /** Pointer to the base interface of the driver instance below. */ + R3PTRTYPE(PPDMIBASE) pDownBase; + + /** The base interface of the driver. + * The driver constructor initializes this. */ + PDMIBASE IBase; + + /** Tracing indicator. */ + uint32_t fTracing; + /** The tracing ID of this device. */ + uint32_t idTracing; +#if HC_ARCH_BITS == 32 + /** Align the internal data more naturally. */ + uint32_t au32Padding[HC_ARCH_BITS == 32 ? 7 : 0]; +#endif + + /** Internal data. */ + union + { +#ifdef PDMDRVINSINT_DECLARED + PDMDRVINSINT s; +#endif + uint8_t padding[HC_ARCH_BITS == 32 ? 40 + 32 : 72 + 24]; + } Internal; + + /** Driver instance data. The size of this area is defined + * in the PDMDRVREG::cbInstanceData field. */ + char achInstanceData[4]; +} PDMDRVINS; + +/** Current DRVREG version number. */ +#define PDM_DRVINS_VERSION PDM_VERSION_MAKE(0xf0fe, 2, 0) + +/** Converts a pointer to the PDMDRVINS::IBase to a pointer to PDMDRVINS. */ +#define PDMIBASE_2_PDMDRV(pInterface) ( (PPDMDRVINS)((char *)(pInterface) - RT_UOFFSETOF(PDMDRVINS, IBase)) ) + +/** @def PDMDRVINS_2_RCPTR + * Converts a PDM Driver instance pointer a RC PDM Driver instance pointer. + */ +#define PDMDRVINS_2_RCPTR(pDrvIns) ( (RCPTRTYPE(PPDMDRVINS))((RTRCUINTPTR)(pDrvIns)->pvInstanceDataRC - (RTRCUINTPTR)RT_UOFFSETOF(PDMDRVINS, achInstanceData)) ) + +/** @def PDMDRVINS_2_R3PTR + * Converts a PDM Driver instance pointer a R3 PDM Driver instance pointer. + */ +#define PDMDRVINS_2_R3PTR(pDrvIns) ( (R3PTRTYPE(PPDMDRVINS))((RTHCUINTPTR)(pDrvIns)->pvInstanceDataR3 - RT_UOFFSETOF(PDMDRVINS, achInstanceData)) ) + +/** @def PDMDRVINS_2_R0PTR + * Converts a PDM Driver instance pointer a R0 PDM Driver instance pointer. + */ +#define PDMDRVINS_2_R0PTR(pDrvIns) ( (R0PTRTYPE(PPDMDRVINS))((RTR0UINTPTR)(pDrvIns)->pvInstanceDataR0 - RT_UOFFSETOF(PDMDRVINS, achInstanceData)) ) + + + +/** + * Checks the structure versions of the drive instance and driver helpers, + * returning if they are incompatible. + * + * Intended for the constructor. + * + * @param pDrvIns Pointer to the PDM driver instance. + */ +#define PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns) \ + do \ + { \ + PPDMDRVINS pDrvInsTypeCheck = (pDrvIns); NOREF(pDrvInsTypeCheck); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pDrvIns)->u32Version, PDM_DRVINS_VERSION), \ + ("DrvIns=%#x mine=%#x\n", (pDrvIns)->u32Version, PDM_DRVINS_VERSION), \ + VERR_PDM_DRVINS_VERSION_MISMATCH); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pDrvIns)->pHlpR3->u32Version, PDM_DRVHLPR3_VERSION), \ + ("DrvHlp=%#x mine=%#x\n", (pDrvIns)->pHlpR3->u32Version, PDM_DRVHLPR3_VERSION), \ + VERR_PDM_DRVHLPR3_VERSION_MISMATCH); \ + } while (0) + +/** + * Quietly checks the structure versions of the drive instance and driver + * helpers, returning if they are incompatible. + * + * Intended for the destructor. + * + * @param pDrvIns Pointer to the PDM driver instance. + */ +#define PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns) \ + do \ + { \ + PPDMDRVINS pDrvInsTypeCheck = (pDrvIns); NOREF(pDrvInsTypeCheck); \ + if (RT_LIKELY( PDM_VERSION_ARE_COMPATIBLE((pDrvIns)->u32Version, PDM_DRVINS_VERSION) \ + && PDM_VERSION_ARE_COMPATIBLE((pDrvIns)->pHlpR3->u32Version, PDM_DRVHLPR3_VERSION)) ) \ + { /* likely */ } else return; \ + } while (0) + +/** + * Wrapper around CFGMR3ValidateConfig for the root config for use in the + * constructor - returns on failure. + * + * This should be invoked after having initialized the instance data + * sufficiently for the correct operation of the destructor. The destructor is + * always called! + * + * @param pDrvIns Pointer to the PDM driver instance. + * @param pszValidValues Patterns describing the valid value names. See + * RTStrSimplePatternMultiMatch for details on the + * pattern syntax. + * @param pszValidNodes Patterns describing the valid node (key) names. + * Pass empty string if no valid nodess. + */ +#define PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, pszValidValues, pszValidNodes) \ + do \ + { \ + int rcValCfg = pDrvIns->pHlpR3->pfnCFGMValidateConfig((pDrvIns)->pCfg, "/", pszValidValues, pszValidNodes, \ + (pDrvIns)->pReg->szName, (pDrvIns)->iInstance); \ + if (RT_SUCCESS(rcValCfg)) \ + { /* likely */ } else return rcValCfg; \ + } while (0) + + + +/** + * USB hub registration structure. + */ +typedef struct PDMUSBHUBREG +{ + /** Structure version number. PDM_USBHUBREG_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Request the hub to attach of the specified device. + * + * @returns VBox status code. + * @param pDrvIns The hub instance. + * @param pUsbIns The device to attach. + * @param pszCaptureFilename Path to the file for USB traffic capturing, optional. + * @param piPort Where to store the port number the device was attached to. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnAttachDevice,(PPDMDRVINS pDrvIns, PPDMUSBINS pUsbIns, const char *pszCaptureFilename, uint32_t *piPort)); + + /** + * Request the hub to detach of the specified device. + * + * The device has previously been attached to the hub with the + * pfnAttachDevice call. This call is not currently expected to + * fail. + * + * @returns VBox status code. + * @param pDrvIns The hub instance. + * @param pUsbIns The device to detach. + * @param iPort The port number returned by the attach call. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnDetachDevice,(PPDMDRVINS pDrvIns, PPDMUSBINS pUsbIns, uint32_t iPort)); + + /** Counterpart to u32Version, same value. */ + uint32_t u32TheEnd; +} PDMUSBHUBREG; +/** Pointer to a const USB hub registration structure. */ +typedef const PDMUSBHUBREG *PCPDMUSBHUBREG; + +/** Current PDMUSBHUBREG version number. */ +#define PDM_USBHUBREG_VERSION PDM_VERSION_MAKE(0xf0fd, 2, 0) + + +/** + * USB hub helpers. + * This is currently just a place holder. + */ +typedef struct PDMUSBHUBHLP +{ + /** Structure version. PDM_USBHUBHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMUSBHUBHLP; +/** Pointer to PCI helpers. */ +typedef PDMUSBHUBHLP *PPDMUSBHUBHLP; +/** Pointer to const PCI helpers. */ +typedef const PDMUSBHUBHLP *PCPDMUSBHUBHLP; +/** Pointer to const PCI helpers pointer. */ +typedef PCPDMUSBHUBHLP *PPCPDMUSBHUBHLP; + +/** Current PDMUSBHUBHLP version number. */ +#define PDM_USBHUBHLP_VERSION PDM_VERSION_MAKE(0xf0fc, 1, 0) + + +/** + * PDM Driver API - raw-mode context variant. + */ +typedef struct PDMDRVHLPRC +{ + /** Structure version. PDM_DRVHLPRC_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLRCCALLBACKMEMBER(bool, pfnAssertEMT,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLRCCALLBACKMEMBER(bool, pfnAssertOther,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLRCCALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLRCCALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + /** @} */ + + /** + * Obtains bandwidth in a bandwidth group. + * + * @returns True if bandwidth was allocated, false if not. + * @param pDrvIns The driver instance. + * @param pFilter Pointer to the filter that allocates bandwidth. + * @param cbTransfer Number of bytes to allocate. + */ + DECLRCCALLBACKMEMBER(bool, pfnNetShaperAllocateBandwidth,(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter, size_t cbTransfer)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDRVHLPRC; +/** Current PDMDRVHLPRC version number. */ +#define PDM_DRVHLPRC_VERSION PDM_VERSION_MAKE(0xf0f9, 6, 0) + + +/** + * PDM Driver API, ring-0 context. + */ +typedef struct PDMDRVHLPR0 +{ + /** Structure version. PDM_DRVHLPR0_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR0CALLBACKMEMBER(bool, pfnAssertEMT,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR0CALLBACKMEMBER(bool, pfnAssertOther,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLR0CALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR0CALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectScheduleExitEvent,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal)); + /** @} */ + + /** + * Obtains bandwidth in a bandwidth group. + * + * @returns True if bandwidth was allocated, false if not. + * @param pDrvIns The driver instance. + * @param pFilter Pointer to the filter that allocates bandwidth. + * @param cbTransfer Number of bytes to allocate. + */ + DECLR0CALLBACKMEMBER(bool, pfnNetShaperAllocateBandwidth,(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter, size_t cbTransfer)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDRVHLPR0; +/** Current DRVHLP version number. */ +#define PDM_DRVHLPR0_VERSION PDM_VERSION_MAKE(0xf0f8, 6, 0) + + +#ifdef IN_RING3 + +/** + * PDM Driver API. + */ +typedef struct PDMDRVHLPR3 +{ + /** Structure version. PDM_DRVHLPR3_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Attaches a driver (chain) to the driver. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG or 0. + * @param ppBaseInterface Where to store the pointer to the base interface. + */ + DECLR3CALLBACKMEMBER(int, pfnAttach,(PPDMDRVINS pDrvIns, uint32_t fFlags, PPDMIBASE *ppBaseInterface)); + + /** + * Detach the driver the drivers below us. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG or 0. + */ + DECLR3CALLBACKMEMBER(int, pfnDetach,(PPDMDRVINS pDrvIns, uint32_t fFlags)); + + /** + * Detach the driver from the driver above it and destroy this + * driver and all drivers below it. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG or 0. + */ + DECLR3CALLBACKMEMBER(int, pfnDetachSelf,(PPDMDRVINS pDrvIns, uint32_t fFlags)); + + /** + * Prepare a media mount. + * + * The driver must not have anything attached to itself + * when calling this function as the purpose is to set up the configuration + * of an future attachment. + * + * @returns VBox status code + * @param pDrvIns Driver instance. + * @param pszFilename Pointer to filename. If this is NULL it assumed that the caller have + * constructed a configuration which can be attached to the bottom driver. + * @param pszCoreDriver Core driver name. NULL will cause autodetection. Ignored if pszFilanem is NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnMountPrepare,(PPDMDRVINS pDrvIns, const char *pszFilename, const char *pszCoreDriver)); + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertEMT,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertOther,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Set the VM error message + * + * @returns rc. + * @param pDrvIns Driver instance. + * @param rc VBox status code. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetErrorV,(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetRuntimeErrorV,(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(4, 0)); + + /** + * Gets the VM state. + * + * @returns VM state. + * @param pDrvIns The driver instance. + * @thread Any thread (just keep in mind that it's volatile info). + */ + DECLR3CALLBACKMEMBER(VMSTATE, pfnVMState, (PPDMDRVINS pDrvIns)); + + /** + * Checks if the VM was teleported and hasn't been fully resumed yet. + * + * @returns true / false. + * @param pDrvIns The driver instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnVMTeleportedAndNotFullyResumedYet,(PPDMDRVINS pDrvIns)); + + /** + * Gets the support driver session. + * + * This is intended for working using the semaphore API. + * + * @returns Support driver session handle. + * @param pDrvIns The driver instance. + */ + DECLR3CALLBACKMEMBER(PSUPDRVSESSION, pfnGetSupDrvSession,(PPDMDRVINS pDrvIns)); + + /** @name Exported PDM Queue Functions + * @{ */ + /** + * Create a queue. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param cbItem Size a queue item. + * @param cItems Number of items in the queue. + * @param cMilliesInterval Number of milliseconds between polling the queue. + * If 0 then the emulation thread will be notified whenever an item arrives. + * @param pfnCallback The consumer function. + * @param pszName The queue base name. The instance number will be + * appended automatically. + * @param phQueue Where to store the queue handle on success. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueueCreate,(PPDMDRVINS pDrvIns, uint32_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDRV pfnCallback, const char *pszName, PDMQUEUEHANDLE *phQueue)); + + DECLR3CALLBACKMEMBER(PPDMQUEUEITEMCORE, pfnQueueAlloc,(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue)); + DECLR3CALLBACKMEMBER(int, pfnQueueInsert,(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)); + DECLR3CALLBACKMEMBER(bool, pfnQueueFlushIfNecessary,(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue)); + /** @} */ + + /** + * Query the virtual timer frequency. + * + * @returns Frequency in Hz. + * @param pDrvIns Driver instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMGetVirtualFreq,(PPDMDRVINS pDrvIns)); + + /** + * Query the virtual time. + * + * @returns The current virtual time. + * @param pDrvIns Driver instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMGetVirtualTime,(PPDMDRVINS pDrvIns)); + + /** + * Creates a timer. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param enmClock The clock to use on this timer. + * @param pfnCallback Callback function. + * @param pvUser The user argument to the callback. + * @param fFlags Timer creation flags, see grp_tm_timer_flags. + * @param pszDesc Pointer to description string which must stay around + * until the timer is fully destroyed (i.e. a bit after TMTimerDestroy()). + * @param phTimer Where to store the timer handle on success. + * @thread EMT + * + * @todo Need to add a bunch of timer helpers for this to be useful again. + * Will do when required. + */ + DECLR3CALLBACKMEMBER(int, pfnTimerCreate,(PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer)); + + /** + * Destroys a timer. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param hTimer The timer handle to destroy. + */ + DECLR3CALLBACKMEMBER(int, pfnTimerDestroy,(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer)); + + /** + * Register a save state data unit. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * + * @param pfnLivePrep Prepare live save callback, optional. + * @param pfnLiveExec Execute live save callback, optional. + * @param pfnLiveVote Vote live save callback, optional. + * + * @param pfnSavePrep Prepare save callback, optional. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnSaveDone Done save callback, optional. + * + * @param pfnLoadPrep Prepare load callback, optional. + * @param pfnLoadExec Execute load callback, optional. + * @param pfnLoadDone Done load callback, optional. + */ + DECLR3CALLBACKMEMBER(int, pfnSSMRegister,(PPDMDRVINS pDrvIns, uint32_t uVersion, size_t cbGuess, + PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote, + PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone, + PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone)); + + /** + * Deregister a save state data unit. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param pszName Data unit name. + * @param uInstance The instance identifier of the data unit. + * This must together with the name be unique. + */ + DECLR3CALLBACKMEMBER(int, pfnSSMDeregister,(PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance)); + + /** @name Exported SSM Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnSSMPutStruct,(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStructEx,(PSSMHANDLE pSSM, const void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutBool,(PSSMHANDLE pSSM, bool fBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU8,(PSSMHANDLE pSSM, uint8_t u8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS8,(PSSMHANDLE pSSM, int8_t i8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU16,(PSSMHANDLE pSSM, uint16_t u16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS16,(PSSMHANDLE pSSM, int16_t i16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU32,(PSSMHANDLE pSSM, uint32_t u32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS32,(PSSMHANDLE pSSM, int32_t i32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU64,(PSSMHANDLE pSSM, uint64_t u64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS64,(PSSMHANDLE pSSM, int64_t i64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU128,(PSSMHANDLE pSSM, uint128_t u128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS128,(PSSMHANDLE pSSM, int128_t i128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutUInt,(PSSMHANDLE pSSM, RTUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSInt,(PSSMHANDLE pSSM, RTINT i)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUInt,(PSSMHANDLE pSSM, RTGCUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntReg,(PSSMHANDLE pSSM, RTGCUINTREG u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys32,(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys64,(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys,(PSSMHANDLE pSSM, RTGCPHYS GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPtr,(PSSMHANDLE pSSM, RTGCPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntPtr,(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutRCPtr,(PSSMHANDLE pSSM, RTRCPTR RCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutIOPort,(PSSMHANDLE pSSM, RTIOPORT IOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSel,(PSSMHANDLE pSSM, RTSEL Sel)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutMem,(PSSMHANDLE pSSM, const void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStrZ,(PSSMHANDLE pSSM, const char *psz)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStruct,(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStructEx,(PSSMHANDLE pSSM, void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBool,(PSSMHANDLE pSSM, bool *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBoolV,(PSSMHANDLE pSSM, bool volatile *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8,(PSSMHANDLE pSSM, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8V,(PSSMHANDLE pSSM, uint8_t volatile *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8,(PSSMHANDLE pSSM, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8V,(PSSMHANDLE pSSM, int8_t volatile *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16,(PSSMHANDLE pSSM, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16V,(PSSMHANDLE pSSM, uint16_t volatile *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16,(PSSMHANDLE pSSM, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16V,(PSSMHANDLE pSSM, int16_t volatile *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32,(PSSMHANDLE pSSM, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32V,(PSSMHANDLE pSSM, uint32_t volatile *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32,(PSSMHANDLE pSSM, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32V,(PSSMHANDLE pSSM, int32_t volatile *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64,(PSSMHANDLE pSSM, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64V,(PSSMHANDLE pSSM, uint64_t volatile *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64,(PSSMHANDLE pSSM, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64V,(PSSMHANDLE pSSM, int64_t volatile *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128,(PSSMHANDLE pSSM, uint128_t *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128V,(PSSMHANDLE pSSM, uint128_t volatile *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128,(PSSMHANDLE pSSM, int128_t *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128V,(PSSMHANDLE pSSM, int128_t volatile *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32,(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32V,(PSSMHANDLE pSSM, RTGCPHYS32 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64,(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64V,(PSSMHANDLE pSSM, RTGCPHYS64 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys,(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhysV,(PSSMHANDLE pSSM, RTGCPHYS volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetUInt,(PSSMHANDLE pSSM, PRTUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSInt,(PSSMHANDLE pSSM, PRTINT pi)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUInt,(PSSMHANDLE pSSM, PRTGCUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntReg,(PSSMHANDLE pSSM, PRTGCUINTREG pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPtr,(PSSMHANDLE pSSM, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntPtr,(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetRCPtr,(PSSMHANDLE pSSM, PRTRCPTR pRCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetIOPort,(PSSMHANDLE pSSM, PRTIOPORT pIOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSel,(PSSMHANDLE pSSM, PRTSEL pSel)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetMem,(PSSMHANDLE pSSM, void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZ,(PSSMHANDLE pSSM, char *psz, size_t cbMax)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZEx,(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkip,(PSSMHANDLE pSSM, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkipToEndOfUnit,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadError,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadErrorV,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgError,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgErrorV,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMHandleGetStatus,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(SSMAFTER, pfnSSMHandleGetAfter,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(bool, pfnSSMHandleIsLiveSave,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleMaxDowntime,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleHostBits,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleRevision,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleVersion,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(const char *, pfnSSMHandleHostOSAndArch,(PSSMHANDLE pSSM)); + /** @} */ + + /** @name Exported CFGM Functions. + * @{ */ + DECLR3CALLBACKMEMBER(bool, pfnCFGMExists,( PCFGMNODE pNode, const char *pszName)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryType,( PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySize,( PCFGMNODE pNode, const char *pszName, size_t *pcb)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryInteger,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryIntegerDef,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryString,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringDef,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPassword,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPasswordDef,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBytes,( PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64Def,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64,( PCFGMNODE pNode, const char *pszName, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64Def,( PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32Def,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32,( PCFGMNODE pNode, const char *pszName, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32Def,( PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16Def,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16,( PCFGMNODE pNode, const char *pszName, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16Def,( PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8Def,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8,( PCFGMNODE pNode, const char *pszName, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8Def,( PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBool,( PCFGMNODE pNode, const char *pszName, bool *pf)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBoolDef,( PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPort,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPortDef,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUInt,( PCFGMNODE pNode, const char *pszName, unsigned int *pu)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUIntDef,( PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySInt,( PCFGMNODE pNode, const char *pszName, signed int *pi)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySIntDef,( PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtr,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrDef,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrU,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrUDef,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrS,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrSDef,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAlloc,( PCFGMNODE pNode, const char *pszName, char **ppszString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAllocDef,(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetParent,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChild,(PCFGMNODE pNode, const char *pszPath)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildF,(PCFGMNODE pNode, const char *pszPathFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildFV,(PCFGMNODE pNode, const char *pszPathFormat, va_list Args) RT_IPRT_FORMAT_ATTR(3, 0)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetFirstChild,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetNextChild,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetName,(PCFGMNODE pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetNameLen,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreChildrenValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetFirstValue,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetNextValue,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetValueName,(PCFGMLEAF pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetValueNameLen,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(CFGMVALUETYPE, pfnCFGMGetValueType,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreValuesValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(int, pfnCFGMValidateConfig,(PCFGMNODE pNode, const char *pszNode, + const char *pszValidValues, const char *pszValidNodes, + const char *pszWho, uint32_t uInstance)); + /** @} */ + + /** + * Free memory allocated with pfnMMHeapAlloc() and pfnMMHeapAllocZ(). + * + * @param pDrvIns Driver instance. + * @param pv Pointer to the memory to free. + */ + DECLR3CALLBACKMEMBER(void, pfnMMHeapFree,(PPDMDRVINS pDrvIns, void *pv)); + + /** + * Register an info handler with DBGF. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param pszName Data unit name. + * @param pszDesc The description of the info and any arguments + * the handler may take. + * @param pfnHandler The handler function to be called to display the + * info. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFInfoRegister,(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler)); + + /** + * Register an info handler with DBGF, argv style. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param pszName Data unit name. + * @param pszDesc The description of the info and any arguments + * the handler may take. + * @param pfnHandler The handler function to be called to display the + * info. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFInfoRegisterArgv,(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDRV pfnHandler)); + + /** + * Deregister an info handler from DBGF. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param pszName Data unit name. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFInfoDeregister,(PPDMDRVINS pDrvIns, const char *pszName)); + + /** + * Registers a statistics sample if statistics are enabled. + * + * @param pDrvIns Driver instance. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param pszName Sample name. The name is on this form "/<component>/<sample>". + * Further nesting is possible. If this does not start + * with a '/', the default prefix will be prepended, + * otherwise it will be used as-is. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegister,(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, const char *pszName, + STAMUNIT enmUnit, const char *pszDesc)); + + /** + * Same as pfnSTAMRegister except that the name is specified in a + * RTStrPrintf like fashion. + * + * @param pDrvIns Driver instance. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + * @param pszName The sample name format string. If this does not start + * with a '/', the default prefix will be prepended, + * otherwise it will be used as-is. + * @param ... Arguments to the format string. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegisterF,(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, const char *pszDesc, + const char *pszName, ...) RT_IPRT_FORMAT_ATTR(7, 8)); + + /** + * Same as pfnSTAMRegister except that the name is specified in a + * RTStrPrintfV like fashion. + * + * @param pDrvIns Driver instance. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + * @param pszName The sample name format string. If this does not + * start with a '/', the default prefix will be prepended, + * otherwise it will be used as-is. + * @param args Arguments to the format string. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegisterV,(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, const char *pszDesc, + const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(7, 0)); + + /** + * Deregister a statistic item previously registered with pfnSTAMRegister, + * pfnSTAMRegisterF or pfnSTAMRegisterV + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param pvSample Pointer to the sample. + */ + DECLR3CALLBACKMEMBER(int, pfnSTAMDeregister,(PPDMDRVINS pDrvIns, void *pvSample)); + + /** + * Calls the HC R0 VMM entry point, in a safer but slower manner than + * SUPR3CallVMMR0. + * + * When entering using this call the R0 components can call into the host kernel + * (i.e. use the SUPR0 and RT APIs). + * + * See VMMR0Entry() for more details. + * + * @returns error code specific to uFunction. + * @param pDrvIns The driver instance. + * @param uOperation Operation to execute. + * This is limited to services. + * @param pvArg Pointer to argument structure or if cbArg is 0 just an value. + * @param cbArg The size of the argument. This is used to copy whatever the argument + * points at into a kernel buffer to avoid problems like the user page + * being invalidated while we're executing the call. + */ + DECLR3CALLBACKMEMBER(int, pfnSUPCallVMMR0Ex,(PPDMDRVINS pDrvIns, unsigned uOperation, void *pvArg, unsigned cbArg)); + + /** + * Registers a USB HUB. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param fVersions Indicates the kinds of USB devices that can be attached to this HUB. + * @param cPorts The number of ports. + * @param pUsbHubReg The hub callback structure that PDMUsb uses to interact with it. + * @param ppUsbHubHlp The helper callback structure that the hub uses to talk to PDMUsb. + * + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnUSBRegisterHub,(PPDMDRVINS pDrvIns, uint32_t fVersions, uint32_t cPorts, PCPDMUSBHUBREG pUsbHubReg, PPCPDMUSBHUBHLP ppUsbHubHlp)); + + /** + * Set up asynchronous handling of a suspend, reset or power off notification. + * + * This shall only be called when getting the notification. It must be called + * for each one. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pfnAsyncNotify The callback. + * @thread EMT(0) + */ + DECLR3CALLBACKMEMBER(int, pfnSetAsyncNotification, (PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify)); + + /** + * Notify EMT(0) that the driver has completed the asynchronous notification + * handling. + * + * This can be called at any time, spurious calls will simply be ignored. + * + * @param pDrvIns The driver instance. + * @thread Any + */ + DECLR3CALLBACKMEMBER(void, pfnAsyncNotificationCompleted, (PPDMDRVINS pDrvIns)); + + /** + * Creates a PDM thread. + * + * This differs from the RTThreadCreate() API in that PDM takes care of suspending, + * resuming, and destroying the thread as the VM state changes. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param ppThread Where to store the thread 'handle'. + * @param pvUser The user argument to the thread function. + * @param pfnThread The thread function. + * @param pfnWakeup The wakup callback. This is called on the EMT thread when + * a state change is pending. + * @param cbStack See RTThreadCreate. + * @param enmType See RTThreadCreate. + * @param pszName See RTThreadCreate. + */ + DECLR3CALLBACKMEMBER(int, pfnThreadCreate,(PPDMDRVINS pDrvIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDRV pfnThread, + PFNPDMTHREADWAKEUPDRV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)); + + /** @name Exported PDM Thread Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnThreadDestroy,(PPDMTHREAD pThread, int *pRcThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmSuspending,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmRunning,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadSleep,(PPDMTHREAD pThread, RTMSINTERVAL cMillies)); + DECLR3CALLBACKMEMBER(int, pfnThreadSuspend,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadResume,(PPDMTHREAD pThread)); + /** @} */ + + /** + * Creates an async completion template for a driver instance. + * + * The template is used when creating new completion tasks. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param ppTemplate Where to store the template pointer on success. + * @param pfnCompleted The completion callback routine. + * @param pvTemplateUser Template user argument. + * @param pszDesc Description. + */ + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionTemplateCreate,(PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, + PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser, + const char *pszDesc)); + + /** @name Exported PDM Async Completion Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionTemplateDestroy,(PPDMASYNCCOMPLETIONTEMPLATE pTemplate)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpCreateForFile,(PPPDMASYNCCOMPLETIONENDPOINT ppEndpoint, + const char *pszFilename, uint32_t fFlags, + PPDMASYNCCOMPLETIONTEMPLATE pTemplate)); + DECLR3CALLBACKMEMBER(void, pfnAsyncCompletionEpClose,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpGetSize,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t *pcbSize)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpSetSize,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cbSize)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpSetBwMgr,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, const char *pszBwMgr)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpFlush,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser, PPPDMASYNCCOMPLETIONTASK ppTask)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpRead,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbRead, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpWrite,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbWrite, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask)); + /** @} */ + + + /** + * Attaches a network filter driver to a named bandwidth group. + * + * @returns VBox status code. + * @retval VERR_ALREADY_INITIALIZED if already attached to a group. + * @param pDrvIns The driver instance. + * @param pszBwGroup Name of the bandwidth group to attach to. + * @param pFilter Pointer to the filter we attach. + */ + DECLR3CALLBACKMEMBER(int, pfnNetShaperAttach,(PPDMDRVINS pDrvIns, const char *pszBwGroup, PPDMNSFILTER pFilter)); + + /** + * Detaches a network filter driver from its current bandwidth group (if any). + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pFilter Pointer to the filter we attach. + */ + DECLR3CALLBACKMEMBER(int, pfnNetShaperDetach,(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter)); + + /** + * Obtains bandwidth in a bandwidth group. + * + * @returns True if bandwidth was allocated, false if not. + * @param pDrvIns The driver instance. + * @param pFilter Pointer to the filter that allocates bandwidth. + * @param cbTransfer Number of bytes to allocate. + */ + DECLR3CALLBACKMEMBER(bool, pfnNetShaperAllocateBandwidth,(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter, size_t cbTransfer)); + + /** + * Resolves the symbol for a raw-mode context interface. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pvInterface The interface structure. + * @param cbInterface The size of the interface structure. + * @param pszSymPrefix What to prefix the symbols in the list with before + * resolving them. This must start with 'drv' and + * contain the driver name. + * @param pszSymList List of symbols corresponding to the interface. + * There is generally a there is generally a define + * holding this list associated with the interface + * definition (INTERFACE_SYM_LIST). For more details + * see PDMR3LdrGetInterfaceSymbols. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnLdrGetRCInterfaceSymbols,(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface, + const char *pszSymPrefix, const char *pszSymList)); + + /** + * Resolves the symbol for a ring-0 context interface. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pvInterface The interface structure. + * @param cbInterface The size of the interface structure. + * @param pszSymPrefix What to prefix the symbols in the list with before + * resolving them. This must start with 'drv' and + * contain the driver name. + * @param pszSymList List of symbols corresponding to the interface. + * There is generally a there is generally a define + * holding this list associated with the interface + * definition (INTERFACE_SYM_LIST). For more details + * see PDMR3LdrGetInterfaceSymbols. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnLdrGetR0InterfaceSymbols,(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface, + const char *pszSymPrefix, const char *pszSymList)); + /** + * Initializes a PDM critical section. + * + * The PDM critical sections are derived from the IPRT critical sections, but + * works in both RC and R0 as well as R3. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pCritSect Pointer to the critical section. + * @param SRC_POS Use RT_SRC_POS. + * @param pszName The base name of the critical section. Will be + * mangeled with the instance number. For + * statistics and lock validation. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnCritSectInit,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, const char *pszName)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLR3CALLBACKMEMBER(bool, pfnCritSectYield,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR3CALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectScheduleExitEvent,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal)); + DECLR3CALLBACKMEMBER(int, pfnCritSectDelete,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + /** @} */ + + /** + * Call the ring-0 request handler routine of the driver. + * + * For this to work, the driver must be ring-0 enabled and export a request + * handler function. The name of the function must be the driver name in the + * PDMDRVREG struct prefixed with 'drvR0' and suffixed with 'ReqHandler'. + * The driver name will be capitalized. It shall take the exact same + * arguments as this function and be declared using PDMBOTHCBDECL. See + * FNPDMDRVREQHANDLERR0. + * + * @returns VBox status code. + * @retval VERR_SYMBOL_NOT_FOUND if the driver doesn't export the required + * handler function. + * @retval VERR_ACCESS_DENIED if the driver isn't ring-0 capable. + * + * @param pDrvIns The driver instance. + * @param uOperation The operation to perform. + * @param u64Arg 64-bit integer argument. + * @thread Any + */ + DECLR3CALLBACKMEMBER(int, pfnCallR0,(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg)); + + /** + * Creates a block cache for a driver driver instance. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param ppBlkCache Where to store the handle to the block cache. + * @param pfnXferComplete The I/O transfer complete callback. + * @param pfnXferEnqueue The I/O request enqueue callback. + * @param pfnXferEnqueueDiscard The discard request enqueue callback. + * @param pcszId Unique ID used to identify the user. + */ + DECLR3CALLBACKMEMBER(int, pfnBlkCacheRetain, (PPDMDRVINS pDrvIns, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEDRV pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEDRV pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV pfnXferEnqueueDiscard, + const char *pcszId)); + + /** @name Exported PDM Block Cache Functions + * @{ */ + DECLR3CALLBACKMEMBER(void, pfnBlkCacheRelease,(PPDMBLKCACHE pBlkCache)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheClear,(PPDMBLKCACHE pBlkCache)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheSuspend,(PPDMBLKCACHE pBlkCache)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheResume,(PPDMBLKCACHE pBlkCache)); + DECLR3CALLBACKMEMBER(void, pfnBlkCacheIoXferComplete,(PPDMBLKCACHE pBlkCache, PPDMBLKCACHEIOXFER hIoXfer, int rcIoXfer)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheRead,(PPDMBLKCACHE pBlkCache, uint64_t off, PCRTSGBUF pSgBuf, size_t cbRead, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheWrite,(PPDMBLKCACHE pBlkCache, uint64_t off, PCRTSGBUF pSgBuf, size_t cbRead, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheFlush,(PPDMBLKCACHE pBlkCache, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheDiscard,(PPDMBLKCACHE pBlkCache, PCRTRANGE paRanges, unsigned cRanges, void *pvUser)); + /** @} */ + + /** + * Gets the reason for the most recent VM suspend. + * + * @returns The suspend reason. VMSUSPENDREASON_INVALID is returned if no + * suspend has been made or if the pDrvIns is invalid. + * @param pDrvIns The driver instance. + */ + DECLR3CALLBACKMEMBER(VMSUSPENDREASON, pfnVMGetSuspendReason,(PPDMDRVINS pDrvIns)); + + /** + * Gets the reason for the most recent VM resume. + * + * @returns The resume reason. VMRESUMEREASON_INVALID is returned if no + * resume has been made or if the pDrvIns is invalid. + * @param pDrvIns The driver instance. + */ + DECLR3CALLBACKMEMBER(VMRESUMEREASON, pfnVMGetResumeReason,(PPDMDRVINS pDrvIns)); + + /** @name Space reserved for minor interface changes. + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnTimerSetMillies,(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)); + + /** + * Deregister zero or more samples given their name prefix. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pszPrefix The name prefix of the samples to remove. If this does + * not start with a '/', the default prefix will be + * prepended, otherwise it will be used as-is. + */ + DECLR3CALLBACKMEMBER(int, pfnSTAMDeregisterByPrefix,(PPDMDRVINS pDrvIns, const char *pszPrefix)); + + /** + * Queries a generic object from the VMM user. + * + * @returns Pointer to the object if found, NULL if not. + * @param pDrvIns The driver instance. + * @param pUuid The UUID of what's being queried. The UUIDs and + * the usage conventions are defined by the user. + */ + DECLR3CALLBACKMEMBER(void *, pfnQueryGenericUserObject,(PPDMDRVINS pDrvIns, PCRTUUID pUuid)); + + DECLR3CALLBACKMEMBER(void, pfnReserved0,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved1,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved2,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved3,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved4,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved5,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved6,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved7,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved8,(PPDMDRVINS pDrvIns)); + /** @} */ + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDRVHLPR3; +/** Current DRVHLP version number. */ +#define PDM_DRVHLPR3_VERSION PDM_VERSION_MAKE(0xf0fb, 16, 0) + + +/** + * Set the VM error message + * + * @returns rc. + * @param pDrvIns Driver instance. + * @param rc VBox status code. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + * @sa PDMDRV_SET_ERROR, PDMDrvHlpVMSetErrorV, VMSetError + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 7) PDMDrvHlpVMSetError(PPDMDRVINS pDrvIns, const int rc, RT_SRC_POS_DECL, + const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + pDrvIns->CTX_SUFF(pHlp)->pfnVMSetErrorV(pDrvIns, rc, RT_SRC_POS_ARGS, pszFormat, va); + va_end(va); + return rc; +} + +/** @def PDMDRV_SET_ERROR + * Set the VM error. See PDMDrvHlpVMSetError() for printf like message formatting. + */ +#define PDMDRV_SET_ERROR(pDrvIns, rc, pszError) \ + PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, "%s", pszError) + +/** + * @copydoc PDMDRVHLPR3::pfnVMSetErrorV + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 0) PDMDrvHlpVMSetErrorV(PPDMDRVINS pDrvIns, const int rc, RT_SRC_POS_DECL, + const char *pszFormat, va_list va) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnVMSetErrorV(pDrvIns, rc, RT_SRC_POS_ARGS, pszFormat, va); +} + + +/** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + * @sa PDMDRV_SET_RUNTIME_ERROR, PDMDrvHlpVMSetRuntimeErrorV, + * VMSetRuntimeError + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(4, 5) PDMDrvHlpVMSetRuntimeError(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, ...) +{ + va_list va; + int rc; + va_start(va, pszFormat); + rc = pDrvIns->CTX_SUFF(pHlp)->pfnVMSetRuntimeErrorV(pDrvIns, fFlags, pszErrorId, pszFormat, va); + va_end(va); + return rc; +} + +/** @def PDMDRV_SET_RUNTIME_ERROR + * Set the VM runtime error. See PDMDrvHlpVMSetRuntimeError() for printf like message formatting. + */ +#define PDMDRV_SET_RUNTIME_ERROR(pDrvIns, fFlags, pszErrorId, pszError) \ + PDMDrvHlpVMSetRuntimeError(pDrvIns, fFlags, pszErrorId, "%s", pszError) + +/** + * @copydoc PDMDRVHLPR3::pfnVMSetRuntimeErrorV + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(4, 0) PDMDrvHlpVMSetRuntimeErrorV(PPDMDRVINS pDrvIns, uint32_t fFlags, + const char *pszErrorId, const char *pszFormat, va_list va) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnVMSetRuntimeErrorV(pDrvIns, fFlags, pszErrorId, pszFormat, va); +} + +#endif /* IN_RING3 */ + +/** @def PDMDRV_ASSERT_EMT + * Assert that the current thread is the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMDRV_ASSERT_EMT(pDrvIns) pDrvIns->CTX_SUFF(pHlp)->pfnAssertEMT(pDrvIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMDRV_ASSERT_EMT(pDrvIns) do { } while (0) +#endif + +/** @def PDMDRV_ASSERT_OTHER + * Assert that the current thread is NOT the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMDRV_ASSERT_OTHER(pDrvIns) pDrvIns->CTX_SUFF(pHlp)->pfnAssertOther(pDrvIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMDRV_ASSERT_OTHER(pDrvIns) do { } while (0) +#endif + + +#ifdef IN_RING3 + +/** + * @copydoc PDMDRVHLPR3::pfnAttach + */ +DECLINLINE(int) PDMDrvHlpAttach(PPDMDRVINS pDrvIns, uint32_t fFlags, PPDMIBASE *ppBaseInterface) +{ + return pDrvIns->pHlpR3->pfnAttach(pDrvIns, fFlags, ppBaseInterface); +} + +/** + * Check that there is no driver below the us that we should attach to. + * + * @returns VERR_PDM_NO_ATTACHED_DRIVER if there is no driver. + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpNoAttach(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnAttach(pDrvIns, 0, NULL); +} + +/** + * @copydoc PDMDRVHLPR3::pfnDetach + */ +DECLINLINE(int) PDMDrvHlpDetach(PPDMDRVINS pDrvIns, uint32_t fFlags) +{ + return pDrvIns->pHlpR3->pfnDetach(pDrvIns, fFlags); +} + +/** + * @copydoc PDMDRVHLPR3::pfnDetachSelf + */ +DECLINLINE(int) PDMDrvHlpDetachSelf(PPDMDRVINS pDrvIns, uint32_t fFlags) +{ + return pDrvIns->pHlpR3->pfnDetachSelf(pDrvIns, fFlags); +} + +/** + * @copydoc PDMDRVHLPR3::pfnMountPrepare + */ +DECLINLINE(int) PDMDrvHlpMountPrepare(PPDMDRVINS pDrvIns, const char *pszFilename, const char *pszCoreDriver) +{ + return pDrvIns->pHlpR3->pfnMountPrepare(pDrvIns, pszFilename, pszCoreDriver); +} + +/** + * @copydoc PDMDRVHLPR3::pfnVMState + */ +DECLINLINE(VMSTATE) PDMDrvHlpVMState(PPDMDRVINS pDrvIns) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnVMState(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnVMTeleportedAndNotFullyResumedYet + */ +DECLINLINE(bool) PDMDrvHlpVMTeleportedAndNotFullyResumedYet(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnVMTeleportedAndNotFullyResumedYet(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnGetSupDrvSession + */ +DECLINLINE(PSUPDRVSESSION) PDMDrvHlpGetSupDrvSession(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnGetSupDrvSession(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnQueueCreate + */ +DECLINLINE(int) PDMDrvHlpQueueCreate(PPDMDRVINS pDrvIns, uint32_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDRV pfnCallback, const char *pszName, PDMQUEUEHANDLE *phQueue) +{ + return pDrvIns->pHlpR3->pfnQueueCreate(pDrvIns, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, phQueue); +} + +/** + * @copydoc PDMDRVHLPR3::pfnQueueAlloc + */ +DECLINLINE(PPDMQUEUEITEMCORE) PDMDrvHlpQueueAlloc(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnQueueAlloc(pDrvIns, hQueue); +} + +/** + * @copydoc PDMDRVHLPR3::pfnQueueInsert + */ +DECLINLINE(int) PDMDrvHlpQueueInsert(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnQueueInsert(pDrvIns, hQueue, pItem); +} + +/** + * @copydoc PDMDRVHLPR3::pfnQueueFlushIfNecessary + */ +DECLINLINE(bool) PDMDrvHlpQueueFlushIfNecessary(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnQueueFlushIfNecessary(pDrvIns, hQueue); +} + +/** + * @copydoc PDMDRVHLPR3::pfnTMGetVirtualFreq + */ +DECLINLINE(uint64_t) PDMDrvHlpTMGetVirtualFreq(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnTMGetVirtualFreq(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnTMGetVirtualTime + */ +DECLINLINE(uint64_t) PDMDrvHlpTMGetVirtualTime(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnTMGetVirtualTime(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnTimerCreate + */ +DECLINLINE(int) PDMDrvHlpTMTimerCreate(PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer) + +{ + return pDrvIns->pHlpR3->pfnTimerCreate(pDrvIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, phTimer); +} + +/** + * @copydoc PDMDRVHLPR3::pfnTimerDestroy + */ +DECLINLINE(int) PDMDrvHlpTimerDestroy(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer) + +{ + return pDrvIns->pHlpR3->pfnTimerDestroy(pDrvIns, hTimer); +} + +/** + * @copydoc PDMDRVHLPR3::pfnTimerSetMillies + */ +DECLINLINE(int) PDMDrvHlpTimerSetMillies(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext) + +{ + return pDrvIns->pHlpR3->pfnTimerSetMillies(pDrvIns, hTimer, cMilliesToNext); +} + +/** + * Register a save state data unit. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnLoadExec Execute load callback, optional. + */ +DECLINLINE(int) PDMDrvHlpSSMRegister(PPDMDRVINS pDrvIns, uint32_t uVersion, size_t cbGuess, + PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVLOADEXEC pfnLoadExec) +{ + return pDrvIns->pHlpR3->pfnSSMRegister(pDrvIns, uVersion, cbGuess, + NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/, + NULL /*pfnSavePrep*/, pfnSaveExec, NULL /*pfnSaveDone*/, + NULL /*pfnLoadPrep*/, pfnLoadExec, NULL /*pfnLoadDone*/); +} + +/** + * @copydoc PDMDRVHLPR3::pfnSSMRegister + */ +DECLINLINE(int) PDMDrvHlpSSMRegisterEx(PPDMDRVINS pDrvIns, uint32_t uVersion, size_t cbGuess, + PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote, + PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone, + PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone) +{ + return pDrvIns->pHlpR3->pfnSSMRegister(pDrvIns, uVersion, cbGuess, + pfnLivePrep, pfnLiveExec, pfnLiveVote, + pfnSavePrep, pfnSaveExec, pfnSaveDone, + pfnLoadPrep, pfnLoadExec, pfnLoadDone); +} + +/** + * Register a load done callback. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param pfnLoadDone Done load callback, optional. + */ +DECLINLINE(int) PDMDrvHlpSSMRegisterLoadDone(PPDMDRVINS pDrvIns, PFNSSMDRVLOADDONE pfnLoadDone) +{ + return pDrvIns->pHlpR3->pfnSSMRegister(pDrvIns, 0 /*uVersion*/, 0 /*cbGuess*/, + NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/, + NULL /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/, + NULL /*pfnLoadPrep*/, NULL /*pfnLoadExec*/, pfnLoadDone); +} + +/** + * @copydoc PDMDRVHLPR3::pfnMMHeapFree + */ +DECLINLINE(void) PDMDrvHlpMMHeapFree(PPDMDRVINS pDrvIns, void *pv) +{ + pDrvIns->pHlpR3->pfnMMHeapFree(pDrvIns, pv); +} + +/** + * @copydoc PDMDRVHLPR3::pfnDBGFInfoRegister + */ +DECLINLINE(int) PDMDrvHlpDBGFInfoRegister(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler) +{ + return pDrvIns->pHlpR3->pfnDBGFInfoRegister(pDrvIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDRVHLPR3::pfnDBGFInfoRegisterArgv + */ +DECLINLINE(int) PDMDrvHlpDBGFInfoRegisterArgv(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDRV pfnHandler) +{ + return pDrvIns->pHlpR3->pfnDBGFInfoRegisterArgv(pDrvIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDRVHLPR3::pfnDBGFInfoRegister + */ +DECLINLINE(int) PDMDrvHlpDBGFInfoDeregister(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler) +{ + return pDrvIns->pHlpR3->pfnDBGFInfoRegister(pDrvIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDRVHLPR3::pfnSTAMRegister + */ +DECLINLINE(void) PDMDrvHlpSTAMRegister(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, const char *pszName, STAMUNIT enmUnit, const char *pszDesc) +{ + pDrvIns->pHlpR3->pfnSTAMRegister(pDrvIns, pvSample, enmType, pszName, enmUnit, pszDesc); +} + +/** + * @copydoc PDMDRVHLPR3::pfnSTAMRegisterF + */ +DECLINLINE(void) RT_IPRT_FORMAT_ATTR(7, 8) PDMDrvHlpSTAMRegisterF(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, + STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, ...) +{ + va_list va; + va_start(va, pszName); + pDrvIns->pHlpR3->pfnSTAMRegisterV(pDrvIns, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va); + va_end(va); +} + +/** + * Convenience wrapper that registers counter which is always visible. + * + * @param pDrvIns The driver instance. + * @param pCounter Pointer to the counter variable. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/<drivername>-<instance no>/". + * @param enmUnit The unit. + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegCounterEx(PPDMDRVINS pDrvIns, PSTAMCOUNTER pCounter, const char *pszName, STAMUNIT enmUnit, const char *pszDesc) +{ + pDrvIns->pHlpR3->pfnSTAMRegisterF(pDrvIns, pCounter, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, enmUnit, pszDesc, + "/Drivers/%s-%u/%s", pDrvIns->pReg->szName, pDrvIns->iInstance, pszName); +} + +/** + * Convenience wrapper that registers counter which is always visible and has + * the STAMUNIT_COUNT unit. + * + * @param pDrvIns The driver instance. + * @param pCounter Pointer to the counter variable. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/<drivername>-<instance no>/". + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegCounter(PPDMDRVINS pDrvIns, PSTAMCOUNTER pCounter, const char *pszName, const char *pszDesc) +{ + PDMDrvHlpSTAMRegCounterEx(pDrvIns, pCounter, pszName, STAMUNIT_COUNT, pszDesc); +} + +/** + * Convenience wrapper that registers profiling sample which is always visible. + * + * @param pDrvIns The driver instance. + * @param pProfile Pointer to the profiling variable. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/<drivername>-<instance no>/". + * @param enmUnit The unit. + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegProfileEx(PPDMDRVINS pDrvIns, PSTAMPROFILE pProfile, const char *pszName, STAMUNIT enmUnit, const char *pszDesc) +{ + pDrvIns->pHlpR3->pfnSTAMRegisterF(pDrvIns, pProfile, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, enmUnit, pszDesc, + "/Drivers/%s-%u/%s", pDrvIns->pReg->szName, pDrvIns->iInstance, pszName); +} + +/** + * Convenience wrapper that registers profiling sample which is always visible + * hand counts ticks per call (STAMUNIT_TICKS_PER_CALL). + * + * @param pDrvIns The driver instance. + * @param pProfile Pointer to the profiling variable. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/<drivername>-<instance no>/". + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegProfile(PPDMDRVINS pDrvIns, PSTAMPROFILE pProfile, const char *pszName, const char *pszDesc) +{ + PDMDrvHlpSTAMRegProfileEx(pDrvIns, pProfile, pszName, STAMUNIT_TICKS_PER_CALL, pszDesc); +} + +/** + * Convenience wrapper that registers an advanced profiling sample which is + * always visible. + * + * @param pDrvIns The driver instance. + * @param pProfile Pointer to the profiling variable. + * @param enmUnit The unit. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/<drivername>-<instance no>/". + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegProfileAdvEx(PPDMDRVINS pDrvIns, PSTAMPROFILEADV pProfile, const char *pszName, STAMUNIT enmUnit, const char *pszDesc) +{ + pDrvIns->pHlpR3->pfnSTAMRegisterF(pDrvIns, pProfile, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, enmUnit, pszDesc, + "/Drivers/%s-%u/%s", pDrvIns->pReg->szName, pDrvIns->iInstance, pszName); +} + +/** + * Convenience wrapper that registers an advanced profiling sample which is + * always visible. + * + * @param pDrvIns The driver instance. + * @param pProfile Pointer to the profiling variable. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/<drivername>-<instance no>/". + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegProfileAdv(PPDMDRVINS pDrvIns, PSTAMPROFILEADV pProfile, const char *pszName, const char *pszDesc) +{ + PDMDrvHlpSTAMRegProfileAdvEx(pDrvIns, pProfile, pszName, STAMUNIT_TICKS_PER_CALL, pszDesc); +} + +/** + * @copydoc PDMDRVHLPR3::pfnSTAMDeregister + */ +DECLINLINE(int) PDMDrvHlpSTAMDeregister(PPDMDRVINS pDrvIns, void *pvSample) +{ + return pDrvIns->pHlpR3->pfnSTAMDeregister(pDrvIns, pvSample); +} + +/** + * @copydoc PDMDRVHLPR3::pfnSTAMDeregisterByPrefix + */ +DECLINLINE(int) PDMDrvHlpSTAMDeregisterByPrefix(PPDMDRVINS pDrvIns, const char *pszPrefix) +{ + return pDrvIns->pHlpR3->pfnSTAMDeregisterByPrefix(pDrvIns, pszPrefix); +} + +/** + * @copydoc PDMDRVHLPR3::pfnSUPCallVMMR0Ex + */ +DECLINLINE(int) PDMDrvHlpSUPCallVMMR0Ex(PPDMDRVINS pDrvIns, unsigned uOperation, void *pvArg, unsigned cbArg) +{ + return pDrvIns->pHlpR3->pfnSUPCallVMMR0Ex(pDrvIns, uOperation, pvArg, cbArg); +} + +/** + * @copydoc PDMDRVHLPR3::pfnUSBRegisterHub + */ +DECLINLINE(int) PDMDrvHlpUSBRegisterHub(PPDMDRVINS pDrvIns, uint32_t fVersions, uint32_t cPorts, PCPDMUSBHUBREG pUsbHubReg, PPCPDMUSBHUBHLP ppUsbHubHlp) +{ + return pDrvIns->pHlpR3->pfnUSBRegisterHub(pDrvIns, fVersions, cPorts, pUsbHubReg, ppUsbHubHlp); +} + +/** + * @copydoc PDMDRVHLPR3::pfnSetAsyncNotification + */ +DECLINLINE(int) PDMDrvHlpSetAsyncNotification(PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify) +{ + return pDrvIns->pHlpR3->pfnSetAsyncNotification(pDrvIns, pfnAsyncNotify); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncNotificationCompleted + */ +DECLINLINE(void) PDMDrvHlpAsyncNotificationCompleted(PPDMDRVINS pDrvIns) +{ + pDrvIns->pHlpR3->pfnAsyncNotificationCompleted(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnThreadCreate + */ +DECLINLINE(int) PDMDrvHlpThreadCreate(PPDMDRVINS pDrvIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDRV pfnThread, + PFNPDMTHREADWAKEUPDRV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName) +{ + return pDrvIns->pHlpR3->pfnThreadCreate(pDrvIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName); +} + +/** + * @copydoc PDMR3ThreadDestroy + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadDestroy(PPDMDRVINS pDrvIns, PPDMTHREAD pThread, int *pRcThread) +{ + return pDrvIns->pHlpR3->pfnThreadDestroy(pThread, pRcThread); +} + +/** + * @copydoc PDMR3ThreadIAmSuspending + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadIAmSuspending(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) +{ + return pDrvIns->pHlpR3->pfnThreadIAmSuspending(pThread); +} + +/** + * @copydoc PDMR3ThreadIAmRunning + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadIAmRunning(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) +{ + return pDrvIns->pHlpR3->pfnThreadIAmRunning(pThread); +} + +/** + * @copydoc PDMR3ThreadSleep + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadSleep(PPDMDRVINS pDrvIns, PPDMTHREAD pThread, RTMSINTERVAL cMillies) +{ + return pDrvIns->pHlpR3->pfnThreadSleep(pThread, cMillies); +} + +/** + * @copydoc PDMR3ThreadSuspend + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadSuspend(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) +{ + return pDrvIns->pHlpR3->pfnThreadSuspend(pThread); +} + +/** + * @copydoc PDMR3ThreadResume + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadResume(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) +{ + return pDrvIns->pHlpR3->pfnThreadResume(pThread); +} + +# ifdef VBOX_WITH_PDM_ASYNC_COMPLETION +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionTemplateCreate + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionTemplateCreate(PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, + PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser, const char *pszDesc) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionTemplateCreate(pDrvIns, ppTemplate, pfnCompleted, pvTemplateUser, pszDesc); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionTemplateDestroy + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionTemplateDestroy(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONTEMPLATE pTemplate) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionTemplateDestroy(pTemplate); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpCreateForFile + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpCreateForFile(PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONENDPOINT ppEndpoint, + const char *pszFilename, uint32_t fFlags, + PPDMASYNCCOMPLETIONTEMPLATE pTemplate) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpCreateForFile(ppEndpoint, pszFilename, fFlags, pTemplate); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpClose + */ +DECLINLINE(void) PDMDrvHlpAsyncCompletionEpClose(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint) +{ + pDrvIns->pHlpR3->pfnAsyncCompletionEpClose(pEndpoint); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpGetSize + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpGetSize(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t *pcbSize) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpGetSize(pEndpoint, pcbSize); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpSetSize + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpSetSize(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cbSize) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpSetSize(pEndpoint, cbSize); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpSetBwMgr + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpSetBwMgr(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, const char *pszBwMgr) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpSetBwMgr(pEndpoint, pszBwMgr); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpFlush + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpFlush(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpFlush(pEndpoint, pvUser, ppTask); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpRead + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpRead(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbRead, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpRead(pEndpoint, off, paSegments, cSegments, cbRead, pvUser, ppTask); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpWrite + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpWrite(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbWrite, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpWrite(pEndpoint, off, paSegments, cSegments, cbWrite, pvUser, ppTask); +} +# endif + +#endif /* IN_RING3 */ + +#ifdef VBOX_WITH_NETSHAPER +# ifdef IN_RING3 + +/** + * @copydoc PDMDRVHLPR3::pfnNetShaperAttach + */ +DECLINLINE(int) PDMDrvHlpNetShaperAttach(PPDMDRVINS pDrvIns, const char *pcszBwGroup, PPDMNSFILTER pFilter) +{ + return pDrvIns->pHlpR3->pfnNetShaperAttach(pDrvIns, pcszBwGroup, pFilter); +} + +/** + * @copydoc PDMDRVHLPR3::pfnNetShaperDetach + */ +DECLINLINE(int) PDMDrvHlpNetShaperDetach(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter) +{ + return pDrvIns->pHlpR3->pfnNetShaperDetach(pDrvIns, pFilter); +} + +# endif /* IN_RING3 */ + +/** + * @copydoc PDMDRVHLPR3::pfnNetShaperAllocateBandwidth + */ +DECLINLINE(bool) PDMDrvHlpNetShaperAllocateBandwidth(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter, size_t cbTransfer) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnNetShaperAllocateBandwidth(pDrvIns, pFilter, cbTransfer); +} + +#endif /* VBOX_WITH_NETSHAPER*/ + +#ifdef IN_RING3 +/** + * @copydoc PDMDRVHLPR3::pfnCritSectInit + */ +DECLINLINE(int) PDMDrvHlpCritSectInit(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, const char *pszName) +{ + return pDrvIns->pHlpR3->pfnCritSectInit(pDrvIns, pCritSect, RT_SRC_POS_ARGS, pszName); +} +#endif /* IN_RING3 */ + +/** + * @see PDMCritSectEnter + */ +DECLINLINE(int) PDMDrvHlpCritSectEnter(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectEnter(pDrvIns, pCritSect, rcBusy); +} + +/** + * @see PDMCritSectEnterDebug + */ +DECLINLINE(int) PDMDrvHlpCritSectEnterDebug(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectEnterDebug(pDrvIns, pCritSect, rcBusy, uId, RT_SRC_POS_ARGS); +} + +/** + * @see PDMCritSectTryEnter + */ +DECLINLINE(int) PDMDrvHlpCritSectTryEnter(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectTryEnter(pDrvIns, pCritSect); +} + +/** + * @see PDMCritSectTryEnterDebug + */ +DECLINLINE(int) PDMDrvHlpCritSectTryEnterDebug(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectTryEnterDebug(pDrvIns, pCritSect, uId, RT_SRC_POS_ARGS); +} + +/** + * @see PDMCritSectLeave + */ +DECLINLINE(int) PDMDrvHlpCritSectLeave(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectLeave(pDrvIns, pCritSect); +} + +/** + * @see PDMCritSectIsOwner + */ +DECLINLINE(bool) PDMDrvHlpCritSectIsOwner(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectIsOwner(pDrvIns, pCritSect); +} + +/** + * @see PDMCritSectIsInitialized + */ +DECLINLINE(bool) PDMDrvHlpCritSectIsInitialized(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectIsInitialized(pDrvIns, pCritSect); +} + +/** + * @see PDMCritSectHasWaiters + */ +DECLINLINE(bool) PDMDrvHlpCritSectHasWaiters(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectHasWaiters(pDrvIns, pCritSect); +} + +/** + * @see PDMCritSectGetRecursion + */ +DECLINLINE(uint32_t) PDMDrvHlpCritSectGetRecursion(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectGetRecursion(pDrvIns, pCritSect); +} + +#if defined(IN_RING3) || defined(IN_RING0) +/** + * @see PDMHCCritSectScheduleExitEvent + */ +DECLINLINE(int) PDMDrvHlpCritSectScheduleExitEvent(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectScheduleExitEvent(pDrvIns, pCritSect, hEventToSignal); +} +#endif + +/* Strict build: Remap the two enter calls to the debug versions. */ +#ifdef VBOX_STRICT +# ifdef IPRT_INCLUDED_asm_h +# define PDMDrvHlpCritSectEnter(pDrvIns, pCritSect, rcBusy) PDMDrvHlpCritSectEnterDebug((pDrvIns), (pCritSect), (rcBusy), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMDrvHlpCritSectTryEnter(pDrvIns, pCritSect) PDMDrvHlpCritSectTryEnterDebug((pDrvIns), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define PDMDrvHlpCritSectEnter(pDrvIns, pCritSect, rcBusy) PDMDrvHlpCritSectEnterDebug((pDrvIns), (pCritSect), (rcBusy), 0, RT_SRC_POS) +# define PDMDrvHlpCritSectTryEnter(pDrvIns, pCritSect) PDMDrvHlpCritSectTryEnterDebug((pDrvIns), (pCritSect), 0, RT_SRC_POS) +# endif +#endif + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @see PDMR3CritSectDelete + */ +DECLINLINE(int) PDMDrvHlpCritSectDelete(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect) +{ + return pDrvIns->pHlpR3->pfnCritSectDelete(pDrvIns, pCritSect); +} + +/** + * @copydoc PDMDRVHLPR3::pfnCallR0 + */ +DECLINLINE(int) PDMDrvHlpCallR0(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg) +{ + return pDrvIns->pHlpR3->pfnCallR0(pDrvIns, uOperation, u64Arg); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheRetain + */ +DECLINLINE(int) PDMDrvHlpBlkCacheRetain(PPDMDRVINS pDrvIns, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEDRV pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEDRV pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV pfnXferEnqueueDiscard, + const char *pcszId) +{ + return pDrvIns->pHlpR3->pfnBlkCacheRetain(pDrvIns, ppBlkCache, pfnXferComplete, pfnXferEnqueue, pfnXferEnqueueDiscard, pcszId); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheRelease + */ +DECLINLINE(void) PDMDrvHlpBlkCacheRelease(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache) +{ + pDrvIns->pHlpR3->pfnBlkCacheRelease(pBlkCache); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheClear + */ +DECLINLINE(int) PDMDrvHlpBlkCacheClear(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache) +{ + return pDrvIns->pHlpR3->pfnBlkCacheClear(pBlkCache); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheSuspend + */ +DECLINLINE(int) PDMDrvHlpBlkCacheSuspend(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache) +{ + return pDrvIns->pHlpR3->pfnBlkCacheSuspend(pBlkCache); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheResume + */ +DECLINLINE(int) PDMDrvHlpBlkCacheResume(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache) +{ + return pDrvIns->pHlpR3->pfnBlkCacheResume(pBlkCache); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheIoXferComplete + */ +DECLINLINE(void) PDMDrvHlpBlkCacheIoXferComplete(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache, + PPDMBLKCACHEIOXFER hIoXfer, int rcIoXfer) +{ + pDrvIns->pHlpR3->pfnBlkCacheIoXferComplete(pBlkCache, hIoXfer, rcIoXfer); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheRead + */ +DECLINLINE(int) PDMDrvHlpBlkCacheRead(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache, uint64_t off, + PCRTSGBUF pSgBuf, size_t cbRead, void *pvUser) +{ + return pDrvIns->pHlpR3->pfnBlkCacheRead(pBlkCache, off, pSgBuf, cbRead, pvUser); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheWrite + */ +DECLINLINE(int) PDMDrvHlpBlkCacheWrite(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache, uint64_t off, + PCRTSGBUF pSgBuf, size_t cbRead, void *pvUser) +{ + return pDrvIns->pHlpR3->pfnBlkCacheWrite(pBlkCache, off, pSgBuf, cbRead, pvUser); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheFlush + */ +DECLINLINE(int) PDMDrvHlpBlkCacheFlush(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache, void *pvUser) +{ + return pDrvIns->pHlpR3->pfnBlkCacheFlush(pBlkCache, pvUser); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheDiscard + */ +DECLINLINE(int) PDMDrvHlpBlkCacheDiscard(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache, PCRTRANGE paRanges, + unsigned cRanges, void *pvUser) +{ + return pDrvIns->pHlpR3->pfnBlkCacheDiscard(pBlkCache, paRanges, cRanges, pvUser); +} + +/** + * @copydoc PDMDRVHLPR3::pfnVMGetSuspendReason + */ +DECLINLINE(VMSUSPENDREASON) PDMDrvHlpVMGetSuspendReason(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnVMGetSuspendReason(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnVMGetResumeReason + */ +DECLINLINE(VMRESUMEREASON) PDMDrvHlpVMGetResumeReason(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnVMGetResumeReason(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnQueryGenericUserObject + */ +DECLINLINE(void *) PDMDrvHlpQueryGenericUserObject(PPDMDRVINS pDrvIns, PCRTUUID pUuid) +{ + return pDrvIns->pHlpR3->pfnQueryGenericUserObject(pDrvIns, pUuid); +} + + +/** Pointer to callbacks provided to the VBoxDriverRegister() call. */ +typedef struct PDMDRVREGCB *PPDMDRVREGCB; +/** Pointer to const callbacks provided to the VBoxDriverRegister() call. */ +typedef const struct PDMDRVREGCB *PCPDMDRVREGCB; + +/** + * Callbacks for VBoxDriverRegister(). + */ +typedef struct PDMDRVREGCB +{ + /** Interface version. + * This is set to PDM_DRVREG_CB_VERSION. */ + uint32_t u32Version; + + /** + * Registers a driver with the current VM instance. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param pReg Pointer to the driver registration record. + * This data must be permanent and readonly. + */ + DECLR3CALLBACKMEMBER(int, pfnRegister,(PCPDMDRVREGCB pCallbacks, PCPDMDRVREG pReg)); +} PDMDRVREGCB; + +/** Current version of the PDMDRVREGCB structure. */ +#define PDM_DRVREG_CB_VERSION PDM_VERSION_MAKE(0xf0fa, 1, 0) + + +/** + * The VBoxDriverRegister callback function. + * + * PDM will invoke this function after loading a driver module and letting + * the module decide which drivers to register and how to handle conflicts. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param u32Version VBox version number. + */ +typedef DECLCALLBACKTYPE(int, FNPDMVBOXDRIVERSREGISTER,(PCPDMDRVREGCB pCallbacks, uint32_t u32Version)); + +VMMR3DECL(int) PDMR3DrvStaticRegistration(PVM pVM, FNPDMVBOXDRIVERSREGISTER pfnCallback); + +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmdrv_h */ diff --git a/include/VBox/vmm/pdmifs.h b/include/VBox/vmm/pdmifs.h new file mode 100644 index 00000000..57ad02f2 --- /dev/null +++ b/include/VBox/vmm/pdmifs.h @@ -0,0 +1,2366 @@ +/** @file + * PDM - Pluggable Device Manager, Interfaces. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmifs_h +#define VBOX_INCLUDED_vmm_pdmifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/sg.h> +#include <VBox/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_interfaces The PDM Interface Definitions + * @ingroup grp_pdm + * + * For historical reasons (the PDMINTERFACE enum) a lot of interface was stuffed + * together in this group instead, dragging stuff into global space that didn't + * need to be there and making this file huge (>2500 lines). Since we're using + * UUIDs as interface identifiers (IIDs) now, no only generic PDM interface will + * be added to this file. Component specific interface should be defined in the + * header file of that component. + * + * Interfaces consists of a method table (typedef'ed struct) and an interface + * ID. The typename of the method table should have an 'I' in it, be all + * capitals and according to the rules, no underscores. The interface ID is a + * \#define constructed by appending '_IID' to the typename. The IID value is a + * UUID string on the form "a2299c0d-b709-4551-aa5a-73f59ffbed74". If you stick + * to these rules, you can make use of the PDMIBASE_QUERY_INTERFACE and + * PDMIBASE_RETURN_INTERFACE when querying interface and implementing + * PDMIBASE::pfnQueryInterface respectively. + * + * In most interface descriptions the orientation of the interface is given as + * 'down' or 'up'. This refers to a model with the device on the top and the + * drivers stacked below it. Sometimes there is mention of 'main' or 'external' + * which normally means the same, i.e. the Main or VBoxBFE API. Picture the + * orientation of 'main' as horizontal. + * + * @{ + */ + + +/** @name PDMIBASE + * @{ + */ + +/** + * PDM Base Interface. + * + * Everyone implements this. + */ +typedef struct PDMIBASE +{ + /** + * Queries an interface to the driver. + * + * @returns Pointer to interface. + * @returns NULL if the interface was not supported by the driver. + * @param pInterface Pointer to this interface structure. + * @param pszIID The interface ID, a UUID string. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(void *, pfnQueryInterface,(struct PDMIBASE *pInterface, const char *pszIID)); +} PDMIBASE; +/** PDMIBASE interface ID. */ +#define PDMIBASE_IID "a2299c0d-b709-4551-aa5a-73f59ffbed74" + +/** + * Helper macro for querying an interface from PDMIBASE. + * + * @returns Correctly typed PDMIBASE::pfnQueryInterface return value. + * + * @param pIBase Pointer to the base interface. + * @param InterfaceType The interface type name. The interface ID is + * derived from this by appending _IID. + */ +#define PDMIBASE_QUERY_INTERFACE(pIBase, InterfaceType) \ + ( (InterfaceType *)(pIBase)->pfnQueryInterface(pIBase, InterfaceType##_IID ) ) + +/** + * Helper macro for implementing PDMIBASE::pfnQueryInterface. + * + * Return @a pInterface if @a pszIID matches the @a InterfaceType. This will + * perform basic type checking. + * + * @param pszIID The ID of the interface that is being queried. + * @param InterfaceType The interface type name. The interface ID is + * derived from this by appending _IID. + * @param pInterface The interface address expression. + */ +#define PDMIBASE_RETURN_INTERFACE(pszIID, InterfaceType, pInterface) \ + do { \ + if (RTUuidCompare2Strs((pszIID), InterfaceType##_IID) == 0) \ + { \ + P##InterfaceType pReturnInterfaceTypeCheck = (pInterface); \ + return pReturnInterfaceTypeCheck; \ + } \ + } while (0) + +/** @} */ + + +/** @name PDMIBASERC + * @{ + */ + +/** + * PDM Base Interface for querying ring-mode context interfaces in + * ring-3. + * + * This is mandatory for drivers present in raw-mode context. + */ +typedef struct PDMIBASERC +{ + /** + * Queries an ring-mode context interface to the driver. + * + * @returns Pointer to interface. + * @returns NULL if the interface was not supported by the driver. + * @param pInterface Pointer to this interface structure. + * @param pszIID The interface ID, a UUID string. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(RTRCPTR, pfnQueryInterface,(struct PDMIBASERC *pInterface, const char *pszIID)); +} PDMIBASERC; +/** Pointer to a PDM Base Interface for query ring-mode context interfaces. */ +typedef PDMIBASERC *PPDMIBASERC; +/** PDMIBASERC interface ID. */ +#define PDMIBASERC_IID "f6a6c649-6cb3-493f-9737-4653f221aeca" + +/** + * Helper macro for querying an interface from PDMIBASERC. + * + * @returns PDMIBASERC::pfnQueryInterface return value. + * + * @param pIBaseRC Pointer to the base raw-mode context interface. Can + * be NULL. + * @param InterfaceType The interface type base name, no trailing RC. The + * interface ID is derived from this by appending _IID. + * + * @remarks Unlike PDMIBASE_QUERY_INTERFACE, this macro is not able to do any + * implicit type checking for you. + */ +#define PDMIBASERC_QUERY_INTERFACE(pIBaseRC, InterfaceType) \ + ( (P##InterfaceType##RC)((pIBaseRC) ? (pIBaseRC)->pfnQueryInterface(pIBaseRC, InterfaceType##_IID) : NIL_RTRCPTR) ) + +/** + * Helper macro for implementing PDMIBASERC::pfnQueryInterface. + * + * Return @a pInterface if @a pszIID matches the @a InterfaceType. This will + * perform basic type checking. + * + * @param pIns Pointer to the instance data. + * @param pszIID The ID of the interface that is being queried. + * @param InterfaceType The interface type base name, no trailing RC. The + * interface ID is derived from this by appending _IID. + * @param pInterface The interface address expression. This must resolve + * to some address within the instance data. + * @remarks Don't use with PDMIBASE. + */ +#define PDMIBASERC_RETURN_INTERFACE(pIns, pszIID, InterfaceType, pInterface) \ + do { \ + Assert((uintptr_t)pInterface - PDMINS_2_DATA(pIns, uintptr_t) < _4M); \ + if (RTUuidCompare2Strs((pszIID), InterfaceType##_IID) == 0) \ + { \ + InterfaceType##RC *pReturnInterfaceTypeCheck = (pInterface); \ + return (uintptr_t)pReturnInterfaceTypeCheck \ + - PDMINS_2_DATA(pIns, uintptr_t) \ + + PDMINS_2_DATA_RCPTR(pIns); \ + } \ + } while (0) + +/** @} */ + + +/** @name PDMIBASER0 + * @{ + */ + +/** + * PDM Base Interface for querying ring-0 interfaces in ring-3. + * + * This is mandatory for drivers present in ring-0 context. + */ +typedef struct PDMIBASER0 +{ + /** + * Queries an ring-0 interface to the driver. + * + * @returns Pointer to interface. + * @returns NULL if the interface was not supported by the driver. + * @param pInterface Pointer to this interface structure. + * @param pszIID The interface ID, a UUID string. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(RTR0PTR, pfnQueryInterface,(struct PDMIBASER0 *pInterface, const char *pszIID)); +} PDMIBASER0; +/** Pointer to a PDM Base Interface for query ring-0 context interfaces. */ +typedef PDMIBASER0 *PPDMIBASER0; +/** PDMIBASER0 interface ID. */ +#define PDMIBASER0_IID "9c9b99b8-7f53-4f59-a3c2-5bc9659c7944" + +/** + * Helper macro for querying an interface from PDMIBASER0. + * + * @returns PDMIBASER0::pfnQueryInterface return value. + * + * @param pIBaseR0 Pointer to the base ring-0 interface. Can be NULL. + * @param InterfaceType The interface type base name, no trailing R0. The + * interface ID is derived from this by appending _IID. + * + * @remarks Unlike PDMIBASE_QUERY_INTERFACE, this macro is not able to do any + * implicit type checking for you. + */ +#define PDMIBASER0_QUERY_INTERFACE(pIBaseR0, InterfaceType) \ + ( (P##InterfaceType##R0)((pIBaseR0) ? (pIBaseR0)->pfnQueryInterface(pIBaseR0, InterfaceType##_IID) : NIL_RTR0PTR) ) + +/** + * Helper macro for implementing PDMIBASER0::pfnQueryInterface. + * + * Return @a pInterface if @a pszIID matches the @a InterfaceType. This will + * perform basic type checking. + * + * @param pIns Pointer to the instance data. + * @param pszIID The ID of the interface that is being queried. + * @param InterfaceType The interface type base name, no trailing R0. The + * interface ID is derived from this by appending _IID. + * @param pInterface The interface address expression. This must resolve + * to some address within the instance data. + * @remarks Don't use with PDMIBASE. + */ +#define PDMIBASER0_RETURN_INTERFACE(pIns, pszIID, InterfaceType, pInterface) \ + do { \ + Assert((uintptr_t)pInterface - PDMINS_2_DATA(pIns, uintptr_t) < _4M); \ + if (RTUuidCompare2Strs((pszIID), InterfaceType##_IID) == 0) \ + { \ + InterfaceType##R0 *pReturnInterfaceTypeCheck = (pInterface); \ + return (uintptr_t)pReturnInterfaceTypeCheck \ + - PDMINS_2_DATA(pIns, uintptr_t) \ + + PDMINS_2_DATA_R0PTR(pIns); \ + } \ + } while (0) + +/** @} */ + + +/** + * Dummy interface. + * + * This is used to typedef other dummy interfaces. The purpose of a dummy + * interface is to validate the logical function of a driver/device and + * full a natural interface pair. + */ +typedef struct PDMIDUMMY +{ + RTHCPTR pvDummy; +} PDMIDUMMY; + + +/** Pointer to a mouse port interface. */ +typedef struct PDMIMOUSEPORT *PPDMIMOUSEPORT; +/** + * Mouse port interface (down). + * Pair with PDMIMOUSECONNECTOR. + */ +typedef struct PDMIMOUSEPORT +{ + /** + * Puts a mouse event. + * + * This is called by the source of mouse events. The event will be passed up + * until the topmost driver, which then calls the registered event handler. + * + * @returns VBox status code. Return VERR_TRY_AGAIN if you cannot process the + * event now and want it to be repeated at a later point. + * + * @param pInterface Pointer to this interface structure. + * @param dx The X delta. + * @param dy The Y delta. + * @param dz The Z delta. + * @param dw The W (horizontal scroll button) delta. + * @param fButtons The button states, see the PDMIMOUSEPORT_BUTTON_* \#defines. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEvent,(PPDMIMOUSEPORT pInterface, + int32_t dx, int32_t dy, int32_t dz, + int32_t dw, uint32_t fButtons)); + /** + * Puts an absolute mouse event. + * + * This is called by the source of mouse events. The event will be passed up + * until the topmost driver, which then calls the registered event handler. + * + * @returns VBox status code. Return VERR_TRY_AGAIN if you cannot process the + * event now and want it to be repeated at a later point. + * + * @param pInterface Pointer to this interface structure. + * @param x The X value, in the range 0 to 0xffff. + * @param y The Y value, in the range 0 to 0xffff. + * @param dz The Z delta. + * @param dw The W (horizontal scroll button) delta. + * @param fButtons The button states, see the PDMIMOUSEPORT_BUTTON_* \#defines. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEventAbs,(PPDMIMOUSEPORT pInterface, + uint32_t x, uint32_t y, + int32_t dz, int32_t dw, + uint32_t fButtons)); + /** + * Puts a multi-touch absolute (touchscreen) event. + * + * @returns VBox status code. Return VERR_TRY_AGAIN if you cannot process the + * event now and want it to be repeated at a later point. + * + * @param pInterface Pointer to this interface structure. + * @param cContacts How many touch contacts in this event. + * @param pau64Contacts Pointer to array of packed contact information. + * Each 64bit element contains: + * Bits 0..15: X coordinate in pixels (signed). + * Bits 16..31: Y coordinate in pixels (signed). + * Bits 32..39: contact identifier. + * Bit 40: "in contact" flag, which indicates that + * there is a contact with the touch surface. + * Bit 41: "in range" flag, the contact is close enough + * to the touch surface. + * All other bits are reserved for future use and must be set to 0. + * @param u32ScanTime Timestamp of this event in milliseconds. Only relative + * time between event is important. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEventTouchScreen,(PPDMIMOUSEPORT pInterface, + uint8_t cContacts, + const uint64_t *pau64Contacts, + uint32_t u32ScanTime)); + + /** + * Puts a multi-touch relative (touchpad) event. + * + * @returns VBox status code. Return VERR_TRY_AGAIN if you cannot process the + * event now and want it to be repeated at a later point. + * + * @param pInterface Pointer to this interface structure. + * @param cContacts How many touch contacts in this event. + * @param pau64Contacts Pointer to array of packed contact information. + * Each 64bit element contains: + * Bits 0..15: Normalized X coordinate (range: 0 - 0xffff). + * Bits 16..31: Normalized Y coordinate (range: 0 - 0xffff). + * Bits 32..39: contact identifier. + * Bit 40: "in contact" flag, which indicates that + * there is a contact with the touch surface. + * All other bits are reserved for future use and must be set to 0. + * @param u32ScanTime Timestamp of this event in milliseconds. Only relative + * time between event is important. + */ + + DECLR3CALLBACKMEMBER(int, pfnPutEventTouchPad,(PPDMIMOUSEPORT pInterface, + uint8_t cContacts, + const uint64_t *pau64Contacts, + uint32_t u32ScanTime)); +} PDMIMOUSEPORT; +/** PDMIMOUSEPORT interface ID. */ +#define PDMIMOUSEPORT_IID "d2bb54b7-d877-441b-9d25-d2d3329465c2" + +/** Mouse button defines for PDMIMOUSEPORT::pfnPutEvent. + * @{ */ +#define PDMIMOUSEPORT_BUTTON_LEFT RT_BIT(0) +#define PDMIMOUSEPORT_BUTTON_RIGHT RT_BIT(1) +#define PDMIMOUSEPORT_BUTTON_MIDDLE RT_BIT(2) +#define PDMIMOUSEPORT_BUTTON_X1 RT_BIT(3) +#define PDMIMOUSEPORT_BUTTON_X2 RT_BIT(4) +/** @} */ + + +/** Pointer to a mouse connector interface. */ +typedef struct PDMIMOUSECONNECTOR *PPDMIMOUSECONNECTOR; +/** + * Mouse connector interface (up). + * Pair with PDMIMOUSEPORT. + */ +typedef struct PDMIMOUSECONNECTOR +{ + /** + * Notifies the the downstream driver of changes to the reporting modes + * supported by the driver + * + * @param pInterface Pointer to this interface structure. + * @param fRelative Whether relative mode is currently supported. + * @param fAbsolute Whether absolute mode is currently supported. + * @param fMTAbsolute Whether absolute multi-touch mode is currently supported. + * @param fMTRelative Whether relative multi-touch mode is currently supported. + */ + DECLR3CALLBACKMEMBER(void, pfnReportModes,(PPDMIMOUSECONNECTOR pInterface, bool fRelative, bool fAbsolute, bool fMTAbsolute, bool fMTRelative)); + + /** + * Flushes the mouse queue if it contains pending events. + * + * @param pInterface Pointer to this interface structure. + */ + DECLR3CALLBACKMEMBER(void, pfnFlushQueue,(PPDMIMOUSECONNECTOR pInterface)); + +} PDMIMOUSECONNECTOR; +/** PDMIMOUSECONNECTOR interface ID. */ +#define PDMIMOUSECONNECTOR_IID "ce64d7bd-fa8f-41d1-a6fb-d102a2d6bffe" + + +/** Flags for PDMIKEYBOARDPORT::pfnPutEventHid. + * @{ */ +#define PDMIKBDPORT_KEY_UP RT_BIT(31) /** Key release event if set. */ +#define PDMIKBDPORT_RELEASE_KEYS RT_BIT(30) /** Force all keys to be released. */ +/** @} */ + +/** USB HID usage pages understood by PDMIKEYBOARDPORT::pfnPutEventHid. + * @{ */ +#define USB_HID_DC_PAGE 1 /** USB HID Generic Desktop Control Usage Page. */ +#define USB_HID_KB_PAGE 7 /** USB HID Keyboard Usage Page. */ +#define USB_HID_CC_PAGE 12 /** USB HID Consumer Control Usage Page. */ +/** @} */ + + +/** Pointer to a keyboard port interface. */ +typedef struct PDMIKEYBOARDPORT *PPDMIKEYBOARDPORT; +/** + * Keyboard port interface (down). + * Pair with PDMIKEYBOARDCONNECTOR. + */ +typedef struct PDMIKEYBOARDPORT +{ + /** + * Puts a scan code based keyboard event. + * + * This is called by the source of keyboard events. The event will be passed up + * until the topmost driver, which then calls the registered event handler. + * + * @returns VBox status code. Return VERR_TRY_AGAIN if you cannot process the + * event now and want it to be repeated at a later point. + * + * @param pInterface Pointer to this interface structure. + * @param u8ScanCode The scan code to queue. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEventScan,(PPDMIKEYBOARDPORT pInterface, uint8_t u8KeyCode)); + + /** + * Puts a USB HID usage ID based keyboard event. + * + * This is called by the source of keyboard events. The event will be passed up + * until the topmost driver, which then calls the registered event handler. + * + * @returns VBox status code. Return VERR_TRY_AGAIN if you cannot process the + * event now and want it to be repeated at a later point. + * + * @param pInterface Pointer to this interface structure. + * @param idUsage The HID usage code event to queue. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEventHid,(PPDMIKEYBOARDPORT pInterface, uint32_t idUsage)); + + /** + * Forcibly releases any pressed keys. + * + * This is called by the source of keyboard events in situations when a full + * release of all currently pressed keys must be forced, e.g. when activating + * a different keyboard, or when key-up events may have been lost. + * + * @returns VBox status code. + * + * @param pInterface Pointer to this interface structure. + */ + DECLR3CALLBACKMEMBER(int, pfnReleaseKeys,(PPDMIKEYBOARDPORT pInterface)); +} PDMIKEYBOARDPORT; +/** PDMIKEYBOARDPORT interface ID. */ +#define PDMIKEYBOARDPORT_IID "2a0844f0-410b-40ab-a6ed-6575f3aa3e29" + + +/** + * Keyboard LEDs. + */ +typedef enum PDMKEYBLEDS +{ + /** No leds. */ + PDMKEYBLEDS_NONE = 0x0000, + /** Num Lock */ + PDMKEYBLEDS_NUMLOCK = 0x0001, + /** Caps Lock */ + PDMKEYBLEDS_CAPSLOCK = 0x0002, + /** Scroll Lock */ + PDMKEYBLEDS_SCROLLLOCK = 0x0004 +} PDMKEYBLEDS; + +/** Pointer to keyboard connector interface. */ +typedef struct PDMIKEYBOARDCONNECTOR *PPDMIKEYBOARDCONNECTOR; +/** + * Keyboard connector interface (up). + * Pair with PDMIKEYBOARDPORT + */ +typedef struct PDMIKEYBOARDCONNECTOR +{ + /** + * Notifies the the downstream driver about an LED change initiated by the guest. + * + * @param pInterface Pointer to this interface structure. + * @param enmLeds The new led mask. + */ + DECLR3CALLBACKMEMBER(void, pfnLedStatusChange,(PPDMIKEYBOARDCONNECTOR pInterface, PDMKEYBLEDS enmLeds)); + + /** + * Notifies the the downstream driver of changes in driver state. + * + * @param pInterface Pointer to this interface structure. + * @param fActive Whether interface wishes to get "focus". + */ + DECLR3CALLBACKMEMBER(void, pfnSetActive,(PPDMIKEYBOARDCONNECTOR pInterface, bool fActive)); + + /** + * Flushes the keyboard queue if it contains pending events. + * + * @param pInterface Pointer to this interface structure. + */ + DECLR3CALLBACKMEMBER(void, pfnFlushQueue,(PPDMIKEYBOARDCONNECTOR pInterface)); + +} PDMIKEYBOARDCONNECTOR; +/** PDMIKEYBOARDCONNECTOR interface ID. */ +#define PDMIKEYBOARDCONNECTOR_IID "db3f7bd5-953e-436f-9f8e-077905a92d82" + + + +/** Pointer to a display port interface. */ +typedef struct PDMIDISPLAYPORT *PPDMIDISPLAYPORT; +/** + * Display port interface (down). + * Pair with PDMIDISPLAYCONNECTOR. + */ +typedef struct PDMIDISPLAYPORT +{ + /** + * Update the display with any changed regions. + * + * Flushes any display changes to the memory pointed to by the + * PDMIDISPLAYCONNECTOR interface and calles PDMIDISPLAYCONNECTOR::pfnUpdateRect() + * while doing so. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnUpdateDisplay,(PPDMIDISPLAYPORT pInterface)); + + /** + * Update the entire display. + * + * Flushes the entire display content to the memory pointed to by the + * PDMIDISPLAYCONNECTOR interface and calles PDMIDISPLAYCONNECTOR::pfnUpdateRect(). + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param fFailOnResize Fail is a resize is pending. + * @thread The emulation thread - bird sees no need for EMT here! + */ + DECLR3CALLBACKMEMBER(int, pfnUpdateDisplayAll,(PPDMIDISPLAYPORT pInterface, bool fFailOnResize)); + + /** + * Return the current guest resolution and color depth in bits per pixel (bpp). + * + * As the graphics card is able to provide display updates with the bpp + * requested by the host, this method can be used to query the actual + * guest color depth. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pcBits Where to store the current guest color depth. + * @param pcx Where to store the horizontal resolution. + * @param pcy Where to store the vertical resolution. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryVideoMode,(PPDMIDISPLAYPORT pInterface, uint32_t *pcBits, uint32_t *pcx, uint32_t *pcy)); + + /** + * Sets the refresh rate and restart the timer. + * The rate is defined as the minimum interval between the return of + * one PDMIDISPLAYPORT::pfnRefresh() call to the next one. + * + * The interval timer will be restarted by this call. So at VM startup + * this function must be called to start the refresh cycle. The refresh + * rate is not saved, but have to be when resuming a loaded VM state. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param cMilliesInterval Number of millis between two refreshes. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetRefreshRate,(PPDMIDISPLAYPORT pInterface, uint32_t cMilliesInterval)); + + /** + * Create a 32-bbp screenshot of the display. + * + * This will allocate and return a 32-bbp bitmap. Size of the bitmap scanline in bytes is 4*width. + * + * The allocated bitmap buffer must be freed with pfnFreeScreenshot. + * + * @param pInterface Pointer to this interface. + * @param ppbData Where to store the pointer to the allocated + * buffer. + * @param pcbData Where to store the actual size of the bitmap. + * @param pcx Where to store the width of the bitmap. + * @param pcy Where to store the height of the bitmap. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnTakeScreenshot,(PPDMIDISPLAYPORT pInterface, uint8_t **ppbData, size_t *pcbData, uint32_t *pcx, uint32_t *pcy)); + + /** + * Free screenshot buffer. + * + * This will free the memory buffer allocated by pfnTakeScreenshot. + * + * @param pInterface Pointer to this interface. + * @param pbData Pointer to the buffer returned by + * pfnTakeScreenshot. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(void, pfnFreeScreenshot,(PPDMIDISPLAYPORT pInterface, uint8_t *pbData)); + + /** + * Copy bitmap to the display. + * + * This will convert and copy a 32-bbp bitmap (with dword aligned scanline length) to + * the memory pointed to by the PDMIDISPLAYCONNECTOR interface. + * + * @param pInterface Pointer to this interface. + * @param pvData Pointer to the bitmap bits. + * @param x The upper left corner x coordinate of the destination rectangle. + * @param y The upper left corner y coordinate of the destination rectangle. + * @param cx The width of the source and destination rectangles. + * @param cy The height of the source and destination rectangles. + * @thread The emulation thread. + * @remark This is just a convenience for using the bitmap conversions of the + * graphics device. + */ + DECLR3CALLBACKMEMBER(int, pfnDisplayBlt,(PPDMIDISPLAYPORT pInterface, const void *pvData, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)); + + /** + * Render a rectangle from guest VRAM to Framebuffer. + * + * @param pInterface Pointer to this interface. + * @param x The upper left corner x coordinate of the rectangle to be updated. + * @param y The upper left corner y coordinate of the rectangle to be updated. + * @param cx The width of the rectangle to be updated. + * @param cy The height of the rectangle to be updated. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateDisplayRect,(PPDMIDISPLAYPORT pInterface, int32_t x, int32_t y, uint32_t cx, uint32_t cy)); + + /** + * Inform the VGA device whether the Display is directly using the guest VRAM and there is no need + * to render the VRAM to the framebuffer memory. + * + * @param pInterface Pointer to this interface. + * @param fRender Whether the VRAM content must be rendered to the framebuffer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnSetRenderVRAM,(PPDMIDISPLAYPORT pInterface, bool fRender)); + + /** + * Render a bitmap rectangle from source to target buffer. + * + * @param pInterface Pointer to this interface. + * @param cx The width of the rectangle to be copied. + * @param cy The height of the rectangle to be copied. + * @param pbSrc Source frame buffer 0,0. + * @param xSrc The upper left corner x coordinate of the source rectangle. + * @param ySrc The upper left corner y coordinate of the source rectangle. + * @param cxSrc The width of the source frame buffer. + * @param cySrc The height of the source frame buffer. + * @param cbSrcLine The line length of the source frame buffer. + * @param cSrcBitsPerPixel The pixel depth of the source. + * @param pbDst Destination frame buffer 0,0. + * @param xDst The upper left corner x coordinate of the destination rectangle. + * @param yDst The upper left corner y coordinate of the destination rectangle. + * @param cxDst The width of the destination frame buffer. + * @param cyDst The height of the destination frame buffer. + * @param cbDstLine The line length of the destination frame buffer. + * @param cDstBitsPerPixel The pixel depth of the destination. + * @thread The emulation thread - bird sees no need for EMT here! + */ + DECLR3CALLBACKMEMBER(int, pfnCopyRect,(PPDMIDISPLAYPORT pInterface, uint32_t cx, uint32_t cy, + const uint8_t *pbSrc, int32_t xSrc, int32_t ySrc, uint32_t cxSrc, uint32_t cySrc, uint32_t cbSrcLine, uint32_t cSrcBitsPerPixel, + uint8_t *pbDst, int32_t xDst, int32_t yDst, uint32_t cxDst, uint32_t cyDst, uint32_t cbDstLine, uint32_t cDstBitsPerPixel)); + + /** + * Inform the VGA device of viewport changes (as a result of e.g. scrolling). + * + * @param pInterface Pointer to this interface. + * @param idScreen The screen updates are for. + * @param x The upper left corner x coordinate of the new viewport rectangle + * @param y The upper left corner y coordinate of the new viewport rectangle + * @param cx The width of the new viewport rectangle + * @param cy The height of the new viewport rectangle + * @thread GUI thread? + * + * @remarks Is allowed to be NULL. + */ + DECLR3CALLBACKMEMBER(void, pfnSetViewport,(PPDMIDISPLAYPORT pInterface, + uint32_t idScreen, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)); + + /** + * Send a video mode hint to the VGA device. + * + * @param pInterface Pointer to this interface. + * @param cx The X resolution. + * @param cy The Y resolution. + * @param cBPP The bit count. + * @param iDisplay The screen number. + * @param dx X offset into the virtual framebuffer or ~0. + * @param dy Y offset into the virtual framebuffer or ~0. + * @param fEnabled Is this screen currently enabled? + * @param fNotifyGuest Should the device send the guest an IRQ? + * Set for the last hint of a series. + * @thread Schedules on the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSendModeHint, (PPDMIDISPLAYPORT pInterface, uint32_t cx, uint32_t cy, + uint32_t cBPP, uint32_t iDisplay, uint32_t dx, + uint32_t dy, uint32_t fEnabled, uint32_t fNotifyGuest)); + + /** + * Send the guest a notification about host cursor capabilities changes. + * + * @param pInterface Pointer to this interface. + * @param fSupportsRenderCursor Whether the host can draw the guest cursor + * using the host one provided the location matches. + * @param fSupportsMoveCursor Whether the host can draw the guest cursor + * itself at any position. Implies RenderCursor. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(void, pfnReportHostCursorCapabilities, (PPDMIDISPLAYPORT pInterface, bool fSupportsRenderCursor, bool fSupportsMoveCursor)); + + /** + * Tell the graphics device about the host cursor position. + * + * @param pInterface Pointer to this interface. + * @param x X offset into the cursor range. + * @param y Y offset into the cursor range. + * @param fOutOfRange The host pointer is out of all guest windows, so + * X and Y do not currently have meaningful value. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(void, pfnReportHostCursorPosition, (PPDMIDISPLAYPORT pInterface, uint32_t x, uint32_t y, bool fOutOfRange)); + + /** + * Notify the graphics device about the monitor positions since the ones we get + * from vmwgfx FIFO are not correct. + * + * In an ideal universe this method should not be here. + * + * @param pInterface Pointer to this interface. + * @param cPositions Number of monitor positions. + * @param paPositions Monitor positions (offsets/origins) array. + * @thread Any (EMT). + * @sa PDMIVMMDEVCONNECTOR::pfnUpdateMonitorPositions + */ + DECLR3CALLBACKMEMBER(void, pfnReportMonitorPositions, (PPDMIDISPLAYPORT pInterface, uint32_t cPositions, + PCRTPOINT paPositions)); + +} PDMIDISPLAYPORT; +/** PDMIDISPLAYPORT interface ID. */ +#define PDMIDISPLAYPORT_IID "471b0520-338c-11e9-bb84-6ff2c956da45" + +/** @name Flags for PDMIDISPLAYCONNECTOR::pfnVBVAReportCursorPosition. + * @{ */ +/** Is the data in the report valid? */ +#define VBVA_CURSOR_VALID_DATA RT_BIT(0) +/** Is the cursor position reported relative to a particular guest screen? */ +#define VBVA_CURSOR_SCREEN_RELATIVE RT_BIT(1) +/** @} */ + +/** Pointer to a 3D graphics notification. */ +typedef struct VBOX3DNOTIFY VBOX3DNOTIFY; +/** Pointer to a 2D graphics acceleration command. */ +typedef struct VBOXVHWACMD VBOXVHWACMD; +/** Pointer to a VBVA command header. */ +typedef struct VBVACMDHDR *PVBVACMDHDR; +/** Pointer to a const VBVA command header. */ +typedef const struct VBVACMDHDR *PCVBVACMDHDR; +/** Pointer to a VBVA screen information. */ +typedef struct VBVAINFOSCREEN *PVBVAINFOSCREEN; +/** Pointer to a const VBVA screen information. */ +typedef const struct VBVAINFOSCREEN *PCVBVAINFOSCREEN; +/** Pointer to a VBVA guest VRAM area information. */ +typedef struct VBVAINFOVIEW *PVBVAINFOVIEW; +/** Pointer to a const VBVA guest VRAM area information. */ +typedef const struct VBVAINFOVIEW *PCVBVAINFOVIEW; +typedef struct VBVAHOSTFLAGS *PVBVAHOSTFLAGS; + +/** Pointer to a display connector interface. */ +typedef struct PDMIDISPLAYCONNECTOR *PPDMIDISPLAYCONNECTOR; + +/** + * Display connector interface (up). + * Pair with PDMIDISPLAYPORT. + */ +typedef struct PDMIDISPLAYCONNECTOR +{ + /** + * Resize the display. + * This is called when the resolution changes. This usually happens on + * request from the guest os, but may also happen as the result of a reset. + * If the callback returns VINF_VGA_RESIZE_IN_PROGRESS, the caller (VGA device) + * must not access the connector and return. + * + * @returns VINF_SUCCESS if the framebuffer resize was completed, + * VINF_VGA_RESIZE_IN_PROGRESS if resize takes time and not yet finished. + * @param pInterface Pointer to this interface. + * @param cBits Color depth (bits per pixel) of the new video mode. + * @param pvVRAM Address of the guest VRAM. + * @param cbLine Size in bytes of a single scan line. + * @param cx New display width. + * @param cy New display height. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnResize,(PPDMIDISPLAYCONNECTOR pInterface, uint32_t cBits, void *pvVRAM, uint32_t cbLine, + uint32_t cx, uint32_t cy)); + + /** + * Update a rectangle of the display. + * PDMIDISPLAYPORT::pfnUpdateDisplay is the caller. + * + * @param pInterface Pointer to this interface. + * @param x The upper left corner x coordinate of the rectangle. + * @param y The upper left corner y coordinate of the rectangle. + * @param cx The width of the rectangle. + * @param cy The height of the rectangle. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateRect,(PPDMIDISPLAYCONNECTOR pInterface, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)); + + /** + * Refresh the display. + * + * The interval between these calls is set by + * PDMIDISPLAYPORT::pfnSetRefreshRate(). The driver should call + * PDMIDISPLAYPORT::pfnUpdateDisplay() if it wishes to refresh the + * display. PDMIDISPLAYPORT::pfnUpdateDisplay calls pfnUpdateRect with + * the changed rectangles. + * + * @param pInterface Pointer to this interface. + * @thread The emulation thread or timer queue thread. + */ + DECLR3CALLBACKMEMBER(void, pfnRefresh,(PPDMIDISPLAYCONNECTOR pInterface)); + + /** + * Reset the display. + * + * Notification message when the graphics card has been reset. + * + * @param pInterface Pointer to this interface. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnReset,(PPDMIDISPLAYCONNECTOR pInterface)); + + /** + * LFB video mode enter/exit. + * + * Notification message when LinearFrameBuffer video mode is enabled/disabled. + * + * @param pInterface Pointer to this interface. + * @param fEnabled false - LFB mode was disabled, + * true - an LFB mode was disabled + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnLFBModeChange,(PPDMIDISPLAYCONNECTOR pInterface, bool fEnabled)); + + /** + * Process the guest graphics adapter information. + * + * Direct notification from guest to the display connector. + * + * @param pInterface Pointer to this interface. + * @param pvVRAM Address of the guest VRAM. + * @param u32VRAMSize Size of the guest VRAM. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnProcessAdapterData,(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM, uint32_t u32VRAMSize)); + + /** + * Process the guest display information. + * + * Direct notification from guest to the display connector. + * + * @param pInterface Pointer to this interface. + * @param pvVRAM Address of the guest VRAM. + * @param uScreenId The index of the guest display to be processed. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnProcessDisplayData,(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM, unsigned uScreenId)); + + /** + * Process the guest Video HW Acceleration command. + * + * @param pInterface Pointer to this interface. + * @param enmCmd The command type (don't re-read from pCmd). + * @param fGuestCmd Set if the command origins with the guest and + * pCmd must be considered volatile. + * @param pCmd Video HW Acceleration Command to be processed. + * @retval VINF_SUCCESS - command is completed, + * @retval VINF_CALLBACK_RETURN if command will by asynchronously completed via + * complete callback. + * @retval VERR_INVALID_STATE if the command could not be processed (most + * likely because the framebuffer was disconnected) - the post should + * be retried later. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnVHWACommandProcess,(PPDMIDISPLAYCONNECTOR pInterface, int enmCmd, bool fGuestCmd, + VBOXVHWACMD RT_UNTRUSTED_VOLATILE_GUEST *pCmd)); + + /** + * The specified screen enters VBVA mode. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @param pHostFlags Undocumented! + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVBVAEnable,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, + struct VBVAHOSTFLAGS RT_UNTRUSTED_VOLATILE_GUEST *pHostFlags)); + + /** + * The specified screen leaves VBVA mode. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @thread if render thread mode is on (fRenderThreadMode that was passed to pfnVBVAEnable is TRUE) - the render thread pfnVBVAEnable was called in, + * otherwise - the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVADisable,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)); + + /** + * A sequence of pfnVBVAUpdateProcess calls begins. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @thread if render thread mode is on (fRenderThreadMode that was passed to pfnVBVAEnable is TRUE) - the render thread pfnVBVAEnable was called in, + * otherwise - the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAUpdateBegin,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)); + + /** + * Process the guest VBVA command. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @param pCmd Video HW Acceleration Command to be processed. + * @param cbCmd Undocumented! + * @thread if render thread mode is on (fRenderThreadMode that was passed to pfnVBVAEnable is TRUE) - the render thread pfnVBVAEnable was called in, + * otherwise - the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAUpdateProcess,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, + struct VBVACMDHDR const RT_UNTRUSTED_VOLATILE_GUEST *pCmd, size_t cbCmd)); + + /** + * A sequence of pfnVBVAUpdateProcess calls ends. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @param x The upper left corner x coordinate of the combined rectangle of all VBVA updates. + * @param y The upper left corner y coordinate of the rectangle. + * @param cx The width of the rectangle. + * @param cy The height of the rectangle. + * @thread if render thread mode is on (fRenderThreadMode that was passed to pfnVBVAEnable is TRUE) - the render thread pfnVBVAEnable was called in, + * otherwise - the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAUpdateEnd,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, int32_t x, int32_t y, + uint32_t cx, uint32_t cy)); + + /** + * Resize the display. + * This is called when the resolution changes. This usually happens on + * request from the guest os, but may also happen as the result of a reset. + * If the callback returns VINF_VGA_RESIZE_IN_PROGRESS, the caller (VGA device) + * must not access the connector and return. + * + * @todo Merge with pfnResize. + * + * @returns VINF_SUCCESS if the framebuffer resize was completed, + * VINF_VGA_RESIZE_IN_PROGRESS if resize takes time and not yet finished. + * @param pInterface Pointer to this interface. + * @param pView The description of VRAM block for this screen. + * @param pScreen The data of screen being resized. + * @param pvVRAM Address of the guest VRAM. + * @param fResetInputMapping Whether to reset the absolute pointing device to screen position co-ordinate + * mapping. Needed for real resizes, as the caller on the guest may not know how + * to set the mapping. Not wanted when we restore a saved state and are resetting + * the mode. + * @thread if render thread mode is on (fRenderThreadMode that was passed to pfnVBVAEnable is TRUE) - the render thread pfnVBVAEnable was called in, + * otherwise - the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVBVAResize,(PPDMIDISPLAYCONNECTOR pInterface, PCVBVAINFOVIEW pView, PCVBVAINFOSCREEN pScreen, + void *pvVRAM, bool fResetInputMapping)); + + /** + * Update the pointer shape. + * This is called when the mouse pointer shape changes. The new shape + * is passed as a caller allocated buffer that will be freed after returning + * + * @param pInterface Pointer to this interface. + * @param fVisible Visibility indicator (if false, the other parameters are undefined). + * @param fAlpha Flag whether alpha channel is being passed. + * @param xHot Pointer hot spot x coordinate. + * @param yHot Pointer hot spot y coordinate. + * @param cx Pointer width in pixels. + * @param cy Pointer height in pixels. + * @param pvShape New shape buffer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVBVAMousePointerShape,(PPDMIDISPLAYCONNECTOR pInterface, bool fVisible, bool fAlpha, + uint32_t xHot, uint32_t yHot, uint32_t cx, uint32_t cy, + const void *pvShape)); + + /** + * The guest capabilities were updated. + * + * @param pInterface Pointer to this interface. + * @param fCapabilities The new capability flag state. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAGuestCapabilityUpdate,(PPDMIDISPLAYCONNECTOR pInterface, uint32_t fCapabilities)); + + /** Read-only attributes. + * For preformance reasons some readonly attributes are kept in the interface. + * We trust the interface users to respect the readonlyness of these. + * @{ + */ + /** Pointer to the display data buffer. */ + uint8_t *pbData; + /** Size of a scanline in the data buffer. */ + uint32_t cbScanline; + /** The color depth (in bits) the graphics card is supposed to provide. */ + uint32_t cBits; + /** The display width. */ + uint32_t cx; + /** The display height. */ + uint32_t cy; + /** @} */ + + /** + * The guest display input mapping rectangle was updated. + * + * @param pInterface Pointer to this interface. + * @param xOrigin Upper left X co-ordinate relative to the first screen. + * @param yOrigin Upper left Y co-ordinate relative to the first screen. + * @param cx Rectangle width. + * @param cy Rectangle height. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAInputMappingUpdate,(PPDMIDISPLAYCONNECTOR pInterface, int32_t xOrigin, int32_t yOrigin, uint32_t cx, uint32_t cy)); + + /** + * The guest is reporting the requested location of the host pointer. + * + * @param pInterface Pointer to this interface. + * @param fFlags VBVA_CURSOR_* + * @param uScreenId The screen to which X and Y are relative if VBVA_CURSOR_SCREEN_RELATIVE is set. + * @param x Cursor X offset. + * @param y Cursor Y offset. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAReportCursorPosition,(PPDMIDISPLAYCONNECTOR pInterface, uint32_t fFlags, uint32_t uScreen, uint32_t x, uint32_t y)); + + /** + * Process the graphics device HW Acceleration command. + * + * @param pInterface Pointer to this interface. + * @param p3DNotify Acceleration Command to be processed. + * @thread The graphics device thread: FIFO for the VMSVGA device. + */ + DECLR3CALLBACKMEMBER(int, pfn3DNotifyProcess,(PPDMIDISPLAYCONNECTOR pInterface, + VBOX3DNOTIFY *p3DNotify)); +} PDMIDISPLAYCONNECTOR; +/** PDMIDISPLAYCONNECTOR interface ID. */ +#define PDMIDISPLAYCONNECTOR_IID "cdd562e4-8030-11ea-8d40-bbc8e146c565" + + +/** Pointer to a secret key interface. */ +typedef struct PDMISECKEY *PPDMISECKEY; + +/** + * Secret key interface to retrieve secret keys. + */ +typedef struct PDMISECKEY +{ + /** + * Retains a key identified by the ID. The caller will only hold a reference + * to the key and must not modify the key buffer in any way. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pszId The alias/id for the key to retrieve. + * @param ppbKey Where to store the pointer to the key buffer on success. + * @param pcbKey Where to store the size of the key in bytes on success. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyRetain, (PPDMISECKEY pInterface, const char *pszId, + const uint8_t **pbKey, size_t *pcbKey)); + + /** + * Releases one reference of the key identified by the given identifier. + * The caller must not access the key buffer after calling this operation. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pszId The alias/id for the key to release. + * + * @note: It is advised to release the key whenever it is not used anymore so the entity + * storing the key can do anything to make retrieving the key from memory more + * difficult like scrambling the memory buffer for instance. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyRelease, (PPDMISECKEY pInterface, const char *pszId)); + + /** + * Retains a password identified by the ID. The caller will only hold a reference + * to the password and must not modify the buffer in any way. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pszId The alias/id for the password to retrieve. + * @param ppszPassword Where to store the pointer to the password on success. + */ + DECLR3CALLBACKMEMBER(int, pfnPasswordRetain, (PPDMISECKEY pInterface, const char *pszId, + const char **ppszPassword)); + + /** + * Releases one reference of the password identified by the given identifier. + * The caller must not access the password after calling this operation. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pszId The alias/id for the password to release. + * + * @note: It is advised to release the password whenever it is not used anymore so the entity + * storing the password can do anything to make retrieving the password from memory more + * difficult like scrambling the memory buffer for instance. + */ + DECLR3CALLBACKMEMBER(int, pfnPasswordRelease, (PPDMISECKEY pInterface, const char *pszId)); +} PDMISECKEY; +/** PDMISECKEY interface ID. */ +#define PDMISECKEY_IID "3d698355-d995-453d-960f-31566a891df2" + +/** Pointer to a secret key helper interface. */ +typedef struct PDMISECKEYHLP *PPDMISECKEYHLP; + +/** + * Secret key helper interface for non critical functionality. + */ +typedef struct PDMISECKEYHLP +{ + /** + * Notifies the interface provider that a key couldn't be retrieved from the key store. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyMissingNotify, (PPDMISECKEYHLP pInterface)); + +} PDMISECKEYHLP; +/** PDMISECKEY interface ID. */ +#define PDMISECKEYHLP_IID "7be96168-4156-40ac-86d2-3073bf8b318e" + + +/** Pointer to a stream interface. */ +typedef struct PDMISTREAM *PPDMISTREAM; +/** + * Stream interface (up). + * Makes up the foundation for PDMICHARCONNECTOR. No pair interface. + */ +typedef struct PDMISTREAM +{ + /** + * Polls for the specified events. + * + * @returns VBox status code. + * @retval VERR_INTERRUPTED if the poll was interrupted. + * @retval VERR_TIMEOUT if the maximum waiting time was reached. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fEvts The events to poll for, see RTPOLL_EVT_XXX. + * @param pfEvts Where to return details about the events that occurred. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait for ever. + */ + DECLR3CALLBACKMEMBER(int, pfnPoll,(PPDMISTREAM pInterface, uint32_t fEvts, uint32_t *pfEvts, RTMSINTERVAL cMillies)); + + /** + * Interrupts the current poll call. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnPollInterrupt,(PPDMISTREAM pInterface)); + + /** + * Read bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the read bits. + * @param pcbRead Number of bytes to read/bytes actually read. + * @thread Any thread. + * + * @note: This is non blocking, use the poll callback to block when there is nothing to read. + */ + DECLR3CALLBACKMEMBER(int, pfnRead,(PPDMISTREAM pInterface, void *pvBuf, size_t *pcbRead)); + + /** + * Write bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the write bits. + * @param pcbWrite Number of bytes to write/bytes actually written. + * @thread Any thread. + * + * @note: This is non blocking, use the poll callback to block until there is room to write. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMISTREAM pInterface, const void *pvBuf, size_t *pcbWrite)); +} PDMISTREAM; +/** PDMISTREAM interface ID. */ +#define PDMISTREAM_IID "f9bd1ba6-c134-44cc-8259-febe14393952" + + +/** Mode of the parallel port */ +typedef enum PDMPARALLELPORTMODE +{ + /** First invalid mode. */ + PDM_PARALLEL_PORT_MODE_INVALID = 0, + /** SPP (Compatibility mode). */ + PDM_PARALLEL_PORT_MODE_SPP, + /** EPP Data mode. */ + PDM_PARALLEL_PORT_MODE_EPP_DATA, + /** EPP Address mode. */ + PDM_PARALLEL_PORT_MODE_EPP_ADDR, + /** ECP mode (not implemented yet). */ + PDM_PARALLEL_PORT_MODE_ECP, + /** 32bit hack. */ + PDM_PARALLEL_PORT_MODE_32BIT_HACK = 0x7fffffff +} PDMPARALLELPORTMODE; + +/** Pointer to a host parallel port interface. */ +typedef struct PDMIHOSTPARALLELPORT *PPDMIHOSTPARALLELPORT; +/** + * Host parallel port interface (down). + * Pair with PDMIHOSTPARALLELCONNECTOR. + */ +typedef struct PDMIHOSTPARALLELPORT +{ + /** + * Notify device/driver that an interrupt has occurred. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnNotifyInterrupt,(PPDMIHOSTPARALLELPORT pInterface)); +} PDMIHOSTPARALLELPORT; +/** PDMIHOSTPARALLELPORT interface ID. */ +#define PDMIHOSTPARALLELPORT_IID "f24b8668-e7f6-4eaa-a14c-4aa2a5f7048e" + + + +/** Pointer to a Host Parallel connector interface. */ +typedef struct PDMIHOSTPARALLELCONNECTOR *PPDMIHOSTPARALLELCONNECTOR; +/** + * Host parallel connector interface (up). + * Pair with PDMIHOSTPARALLELPORT. + */ +typedef struct PDMIHOSTPARALLELCONNECTOR +{ + /** + * Write bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the write bits. + * @param cbWrite Number of bytes to write. + * @param enmMode Mode to write the data. + * @thread Any thread. + * @todo r=klaus cbWrite only defines buffer length, method needs a way top return actually written amount of data. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMIHOSTPARALLELCONNECTOR pInterface, const void *pvBuf, + size_t cbWrite, PDMPARALLELPORTMODE enmMode)); + + /** + * Read bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the read bits. + * @param cbRead Number of bytes to read. + * @param enmMode Mode to read the data. + * @thread Any thread. + * @todo r=klaus cbRead only defines buffer length, method needs a way top return actually read amount of data. + */ + DECLR3CALLBACKMEMBER(int, pfnRead,(PPDMIHOSTPARALLELCONNECTOR pInterface, void *pvBuf, + size_t cbRead, PDMPARALLELPORTMODE enmMode)); + + /** + * Set data direction of the port (forward/reverse). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fForward Flag whether to indicate whether the port is operated in forward or reverse mode. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetPortDirection,(PPDMIHOSTPARALLELCONNECTOR pInterface, bool fForward)); + + /** + * Write control register bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fReg The new control register value. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnWriteControl,(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t fReg)); + + /** + * Read control register bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfReg Where to store the control register bits. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnReadControl,(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t *pfReg)); + + /** + * Read status register bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfReg Where to store the status register bits. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnReadStatus,(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t *pfReg)); + +} PDMIHOSTPARALLELCONNECTOR; +/** PDMIHOSTPARALLELCONNECTOR interface ID. */ +#define PDMIHOSTPARALLELCONNECTOR_IID "7c532602-7438-4fbc-9265-349d9f0415f9" + + +/** ACPI power source identifier */ +typedef enum PDMACPIPOWERSOURCE +{ + PDM_ACPI_POWER_SOURCE_UNKNOWN = 0, + PDM_ACPI_POWER_SOURCE_OUTLET, + PDM_ACPI_POWER_SOURCE_BATTERY +} PDMACPIPOWERSOURCE; +/** Pointer to ACPI battery state. */ +typedef PDMACPIPOWERSOURCE *PPDMACPIPOWERSOURCE; + +/** ACPI battey capacity */ +typedef enum PDMACPIBATCAPACITY +{ + PDM_ACPI_BAT_CAPACITY_MIN = 0, + PDM_ACPI_BAT_CAPACITY_MAX = 100, + PDM_ACPI_BAT_CAPACITY_UNKNOWN = 255 +} PDMACPIBATCAPACITY; +/** Pointer to ACPI battery capacity. */ +typedef PDMACPIBATCAPACITY *PPDMACPIBATCAPACITY; + +/** ACPI battery state. See ACPI 3.0 spec '_BST (Battery Status)' */ +typedef enum PDMACPIBATSTATE +{ + PDM_ACPI_BAT_STATE_CHARGED = 0x00, + PDM_ACPI_BAT_STATE_DISCHARGING = 0x01, + PDM_ACPI_BAT_STATE_CHARGING = 0x02, + PDM_ACPI_BAT_STATE_CRITICAL = 0x04 +} PDMACPIBATSTATE; +/** Pointer to ACPI battery state. */ +typedef PDMACPIBATSTATE *PPDMACPIBATSTATE; + +/** Pointer to an ACPI port interface. */ +typedef struct PDMIACPIPORT *PPDMIACPIPORT; +/** + * ACPI port interface (down). Used by both the ACPI driver and (grumble) main. + * Pair with PDMIACPICONNECTOR. + */ +typedef struct PDMIACPIPORT +{ + /** + * Send an ACPI power off event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnPowerButtonPress,(PPDMIACPIPORT pInterface)); + + /** + * Send an ACPI sleep button event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnSleepButtonPress,(PPDMIACPIPORT pInterface)); + + /** + * Check if the last power button event was handled by the guest. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfHandled Is set to true if the last power button event was handled, false otherwise. + */ + DECLR3CALLBACKMEMBER(int, pfnGetPowerButtonHandled,(PPDMIACPIPORT pInterface, bool *pfHandled)); + + /** + * Check if the guest entered the ACPI mode. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfEntered Is set to true if the guest entered the ACPI mode, false otherwise. + */ + DECLR3CALLBACKMEMBER(int, pfnGetGuestEnteredACPIMode,(PPDMIACPIPORT pInterface, bool *pfEntered)); + + /** + * Check if the given CPU is still locked by the guest. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param uCpu The CPU to check for. + * @param pfLocked Is set to true if the CPU is still locked by the guest, false otherwise. + */ + DECLR3CALLBACKMEMBER(int, pfnGetCpuStatus,(PPDMIACPIPORT pInterface, unsigned uCpu, bool *pfLocked)); + + /** + * Send an ACPI monitor hot-plug event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing + * the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnMonitorHotPlugEvent,(PPDMIACPIPORT pInterface)); + + /** + * Send a battery status change event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing + * the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnBatteryStatusChangeEvent,(PPDMIACPIPORT pInterface)); +} PDMIACPIPORT; +/** PDMIACPIPORT interface ID. */ +#define PDMIACPIPORT_IID "974cb8fb-7fda-408c-f9b4-7ff4e3b2a699" + + +/** Pointer to an ACPI connector interface. */ +typedef struct PDMIACPICONNECTOR *PPDMIACPICONNECTOR; +/** + * ACPI connector interface (up). + * Pair with PDMIACPIPORT. + */ +typedef struct PDMIACPICONNECTOR +{ + /** + * Get the current power source of the host system. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param penmPowerSource Pointer to the power source result variable. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryPowerSource,(PPDMIACPICONNECTOR, PPDMACPIPOWERSOURCE penmPowerSource)); + + /** + * Query the current battery status of the host system. + * + * @returns VBox status code? + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfPresent Is set to true if battery is present, false otherwise. + * @param penmRemainingCapacity Pointer to the battery remaining capacity (0 - 100 or 255 for unknown). + * @param penmBatteryState Pointer to the battery status. + * @param pu32PresentRate Pointer to the present rate (0..1000 of the total capacity). + */ + DECLR3CALLBACKMEMBER(int, pfnQueryBatteryStatus,(PPDMIACPICONNECTOR, bool *pfPresent, PPDMACPIBATCAPACITY penmRemainingCapacity, + PPDMACPIBATSTATE penmBatteryState, uint32_t *pu32PresentRate)); +} PDMIACPICONNECTOR; +/** PDMIACPICONNECTOR interface ID. */ +#define PDMIACPICONNECTOR_IID "5f14bf8d-1edf-4e3a-a1e1-cca9fd08e359" + +struct VMMDevDisplayDef; + +/** Pointer to a VMMDevice port interface. */ +typedef struct PDMIVMMDEVPORT *PPDMIVMMDEVPORT; +/** + * VMMDevice port interface (down). + * Pair with PDMIVMMDEVCONNECTOR. + */ +typedef struct PDMIVMMDEVPORT +{ + /** + * Return the current absolute mouse position in pixels + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pxAbs Pointer of result value, can be NULL + * @param pyAbs Pointer of result value, can be NULL + */ + DECLR3CALLBACKMEMBER(int, pfnQueryAbsoluteMouse,(PPDMIVMMDEVPORT pInterface, int32_t *pxAbs, int32_t *pyAbs)); + + /** + * Set the new absolute mouse position in pixels + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param xAbs New absolute X position + * @param yAbs New absolute Y position + * @param dz New mouse wheel vertical movement offset + * @param dw New mouse wheel horizontal movement offset + * @param fButtons New buttons state + */ + DECLR3CALLBACKMEMBER(int, pfnSetAbsoluteMouse,(PPDMIVMMDEVPORT pInterface, int32_t xAbs, int32_t yAbs, + int32_t dz, int32_t dw, uint32_t fButtons)); + + /** + * Return the current mouse capability flags + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfCapabilities Pointer of result value + */ + DECLR3CALLBACKMEMBER(int, pfnQueryMouseCapabilities,(PPDMIVMMDEVPORT pInterface, uint32_t *pfCapabilities)); + + /** + * Set the current mouse capability flag (host side) + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fCapsAdded Mask of capabilities to add to the flag + * @param fCapsRemoved Mask of capabilities to remove from the flag + */ + DECLR3CALLBACKMEMBER(int, pfnUpdateMouseCapabilities,(PPDMIVMMDEVPORT pInterface, uint32_t fCapsAdded, uint32_t fCapsRemoved)); + + /** + * Issue a display resolution change request. + * + * Note that there can only one request in the queue and that in case the guest does + * not process it, issuing another request will overwrite the previous. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cDisplays Number of displays. Can be either 1 or the number of VM virtual monitors. + * @param paDisplays Definitions of guest screens to be applied. See VMMDev.h + * @param fForce Whether to deliver the request to the guest even if the guest has + * the requested resolution already. + * @param fMayNotify Whether to send a hotplug notification to the guest if appropriate. + */ + DECLR3CALLBACKMEMBER(int, pfnRequestDisplayChange,(PPDMIVMMDEVPORT pInterface, uint32_t cDisplays, + struct VMMDevDisplayDef const *paDisplays, bool fForce, bool fMayNotify)); + + /** + * Pass credentials to guest. + * + * Note that there can only be one set of credentials and the guest may or may not + * query them and may do whatever it wants with them. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pszUsername User name, may be empty (UTF-8). + * @param pszPassword Password, may be empty (UTF-8). + * @param pszDomain Domain name, may be empty (UTF-8). + * @param fFlags VMMDEV_SETCREDENTIALS_*. + */ + DECLR3CALLBACKMEMBER(int, pfnSetCredentials,(PPDMIVMMDEVPORT pInterface, const char *pszUsername, + const char *pszPassword, const char *pszDomain, + uint32_t fFlags)); + + /** + * Notify the driver about a VBVA status change. + * + * @returns Nothing. Because it is informational callback. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fEnabled Current VBVA status. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAChange, (PPDMIVMMDEVPORT pInterface, bool fEnabled)); + + /** + * Issue a seamless mode change request. + * + * Note that there can only one request in the queue and that in case the guest does + * not process it, issuing another request will overwrite the previous. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fEnabled Seamless mode enabled or not + */ + DECLR3CALLBACKMEMBER(int, pfnRequestSeamlessChange,(PPDMIVMMDEVPORT pInterface, bool fEnabled)); + + /** + * Issue a memory balloon change request. + * + * Note that there can only one request in the queue and that in case the guest does + * not process it, issuing another request will overwrite the previous. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cMbBalloon Balloon size in megabytes + */ + DECLR3CALLBACKMEMBER(int, pfnSetMemoryBalloon,(PPDMIVMMDEVPORT pInterface, uint32_t cMbBalloon)); + + /** + * Issue a statistcs interval change request. + * + * Note that there can only one request in the queue and that in case the guest does + * not process it, issuing another request will overwrite the previous. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cSecsStatInterval Statistics query interval in seconds + * (0=disable). + */ + DECLR3CALLBACKMEMBER(int, pfnSetStatisticsInterval,(PPDMIVMMDEVPORT pInterface, uint32_t cSecsStatInterval)); + + /** + * Notify the guest about a VRDP status change. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fVRDPEnabled Current VRDP status. + * @param uVRDPExperienceLevel Which visual effects to be disabled in + * the guest. + */ + DECLR3CALLBACKMEMBER(int, pfnVRDPChange, (PPDMIVMMDEVPORT pInterface, bool fVRDPEnabled, uint32_t uVRDPExperienceLevel)); + + /** + * Notify the guest of CPU hot-unplug event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param idCpuCore The core id of the CPU to remove. + * @param idCpuPackage The package id of the CPU to remove. + */ + DECLR3CALLBACKMEMBER(int, pfnCpuHotUnplug, (PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)); + + /** + * Notify the guest of CPU hot-plug event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param idCpuCore The core id of the CPU to add. + * @param idCpuPackage The package id of the CPU to add. + */ + DECLR3CALLBACKMEMBER(int, pfnCpuHotPlug, (PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)); + +} PDMIVMMDEVPORT; +/** PDMIVMMDEVPORT interface ID. */ +#define PDMIVMMDEVPORT_IID "9e004f1a-875d-11e9-a673-c77c30f53623" + + +/** Pointer to a HPET legacy notification interface. */ +typedef struct PDMIHPETLEGACYNOTIFY *PPDMIHPETLEGACYNOTIFY; +/** + * HPET legacy notification interface. + */ +typedef struct PDMIHPETLEGACYNOTIFY +{ + /** + * Notify about change of HPET legacy mode. + * + * @param pInterface Pointer to the interface structure containing the + * called function pointer. + * @param fActivated If HPET legacy mode is activated (@c true) or + * deactivated (@c false). + */ + DECLR3CALLBACKMEMBER(void, pfnModeChanged,(PPDMIHPETLEGACYNOTIFY pInterface, bool fActivated)); +} PDMIHPETLEGACYNOTIFY; +/** PDMIHPETLEGACYNOTIFY interface ID. */ +#define PDMIHPETLEGACYNOTIFY_IID "c9ada595-4b65-4311-8b21-b10498997774" + + +/** @name Flags for PDMIVMMDEVPORT::pfnSetCredentials. + * @{ */ +/** The guest should perform a logon with the credentials. */ +#define VMMDEV_SETCREDENTIALS_GUESTLOGON RT_BIT(0) +/** The guest should prevent local logons. */ +#define VMMDEV_SETCREDENTIALS_NOLOCALLOGON RT_BIT(1) +/** The guest should verify the credentials. */ +#define VMMDEV_SETCREDENTIALS_JUDGE RT_BIT(15) +/** @} */ + +/** Forward declaration of the guest information structure. */ +struct VBoxGuestInfo; +/** Forward declaration of the guest information-2 structure. */ +struct VBoxGuestInfo2; +/** Forward declaration of the guest statistics structure */ +struct VBoxGuestStatistics; +/** Forward declaration of the guest status structure */ +struct VBoxGuestStatus; + +/** Forward declaration of the video accelerator command memory. */ +struct VBVAMEMORY; +/** Pointer to video accelerator command memory. */ +typedef struct VBVAMEMORY *PVBVAMEMORY; + +/** Pointer to a VMMDev connector interface. */ +typedef struct PDMIVMMDEVCONNECTOR *PPDMIVMMDEVCONNECTOR; +/** + * VMMDev connector interface (up). + * Pair with PDMIVMMDEVPORT. + */ +typedef struct PDMIVMMDEVCONNECTOR +{ + /** + * Update guest facility status. + * + * Called in response to VMMDevReq_ReportGuestStatus, reset or state restore. + * + * @param pInterface Pointer to this interface. + * @param uFacility The facility. + * @param uStatus The status. + * @param fFlags Flags assoicated with the update. Currently + * reserved and should be ignored. + * @param pTimeSpecTS Pointer to the timestamp of this report. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateGuestStatus,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t uFacility, uint16_t uStatus, + uint32_t fFlags, PCRTTIMESPEC pTimeSpecTS)); + + /** + * Updates a guest user state. + * + * Called in response to VMMDevReq_ReportGuestUserState. + * + * @param pInterface Pointer to this interface. + * @param pszUser Guest user name to update status for. + * @param pszDomain Domain the guest user is bound to. Optional. + * @param uState New guest user state to notify host about. + * @param pabDetails Pointer to optional state data. + * @param cbDetails Size (in bytes) of optional state data. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateGuestUserState,(PPDMIVMMDEVCONNECTOR pInterface, const char *pszUser, + const char *pszDomain, uint32_t uState, + const uint8_t *pabDetails, uint32_t cbDetails)); + + /** + * Reports the guest API and OS version. + * Called whenever the Additions issue a guest info report request. + * + * @param pInterface Pointer to this interface. + * @param pGuestInfo Pointer to guest information structure + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateGuestInfo,(PPDMIVMMDEVCONNECTOR pInterface, const struct VBoxGuestInfo *pGuestInfo)); + + /** + * Reports the detailed Guest Additions version. + * + * @param pInterface Pointer to this interface. + * @param uFullVersion The guest additions version as a full version. + * Use VBOX_FULL_VERSION_GET_MAJOR, + * VBOX_FULL_VERSION_GET_MINOR and + * VBOX_FULL_VERSION_GET_BUILD to access it. + * (This will not be zero, so turn down the + * paranoia level a notch.) + * @param pszName Pointer to the sanitized version name. This can + * be empty, but will not be NULL. If not empty, + * it will contain a build type tag and/or a + * publisher tag. If both, then they are separated + * by an underscore (VBOX_VERSION_STRING fashion). + * @param uRevision The SVN revision. Can be 0. + * @param fFeatures Feature mask, currently none are defined. + * + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateGuestInfo2,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t uFullVersion, + const char *pszName, uint32_t uRevision, uint32_t fFeatures)); + + /** + * Update the guest additions capabilities. + * This is called when the guest additions capabilities change. The new capabilities + * are given and the connector should update its internal state. + * + * @param pInterface Pointer to this interface. + * @param newCapabilities New capabilities. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateGuestCapabilities,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t newCapabilities)); + + /** + * Update the mouse capabilities. + * This is called when the mouse capabilities change. The new capabilities + * are given and the connector should update its internal state. + * + * @param pInterface Pointer to this interface. + * @param newCapabilities New capabilities. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateMouseCapabilities,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t newCapabilities)); + + /** + * Update the pointer shape. + * This is called when the mouse pointer shape changes. The new shape + * is passed as a caller allocated buffer that will be freed after returning + * + * @param pInterface Pointer to this interface. + * @param fVisible Visibility indicator (if false, the other parameters are undefined). + * @param fAlpha Flag whether alpha channel is being passed. + * @param xHot Pointer hot spot x coordinate. + * @param yHot Pointer hot spot y coordinate. + * @param x Pointer new x coordinate on screen. + * @param y Pointer new y coordinate on screen. + * @param cx Pointer width in pixels. + * @param cy Pointer height in pixels. + * @param cbScanline Size of one scanline in bytes. + * @param pvShape New shape buffer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdatePointerShape,(PPDMIVMMDEVCONNECTOR pInterface, bool fVisible, bool fAlpha, + uint32_t xHot, uint32_t yHot, + uint32_t cx, uint32_t cy, + void *pvShape)); + + /** + * Enable or disable video acceleration on behalf of guest. + * + * @param pInterface Pointer to this interface. + * @param fEnable Whether to enable acceleration. + * @param pVbvaMemory Video accelerator memory. + + * @return VBox rc. VINF_SUCCESS if VBVA was enabled. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVideoAccelEnable,(PPDMIVMMDEVCONNECTOR pInterface, bool fEnable, PVBVAMEMORY pVbvaMemory)); + + /** + * Force video queue processing. + * + * @param pInterface Pointer to this interface. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVideoAccelFlush,(PPDMIVMMDEVCONNECTOR pInterface)); + + /** + * Return whether the given video mode is supported/wanted by the host. + * + * @returns VBox status code + * @param pInterface Pointer to this interface. + * @param display The guest monitor, 0 for primary. + * @param cy Video mode horizontal resolution in pixels. + * @param cx Video mode vertical resolution in pixels. + * @param cBits Video mode bits per pixel. + * @param pfSupported Where to put the indicator for whether this mode is supported. (output) + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVideoModeSupported,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t display, uint32_t cx, uint32_t cy, uint32_t cBits, bool *pfSupported)); + + /** + * Queries by how many pixels the height should be reduced when calculating video modes + * + * @returns VBox status code + * @param pInterface Pointer to this interface. + * @param pcyReduction Pointer to the result value. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnGetHeightReduction,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pcyReduction)); + + /** + * Informs about a credentials judgement result from the guest. + * + * @returns VBox status code + * @param pInterface Pointer to this interface. + * @param fFlags Judgement result flags. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetCredentialsJudgementResult,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t fFlags)); + + /** + * Set the visible region of the display + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param cRect Number of rectangles in pRect + * @param pRect Rectangle array + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetVisibleRegion,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t cRect, PRTRECT pRect)); + + /** + * Update monitor positions (offsets). + * + * Passing monitor positions from the guest to host exclusively since vmwgfx + * (linux driver) fails to do so thru the FIFO. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param cPositions Number of monitor positions + * @param paPositions Positions array + * @remarks Is allowed to be NULL. + * @thread The emulation thread. + * @sa PDMIDISPLAYPORT::pfnReportMonitorPositions + */ + DECLR3CALLBACKMEMBER(int, pfnUpdateMonitorPositions,(PPDMIVMMDEVCONNECTOR pInterface, + uint32_t cPositions, PCRTPOINT paPositions)); + + /** + * Query the visible region of the display + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pcRects Where to return the number of rectangles in + * paRects. + * @param paRects Rectangle array (set to NULL to query the number + * of rectangles) + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryVisibleRegion,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pcRects, PRTRECT paRects)); + + /** + * Request the statistics interval + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pulInterval Pointer to interval in seconds + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryStatisticsInterval,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pulInterval)); + + /** + * Report new guest statistics + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pGuestStats Guest statistics + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnReportStatistics,(PPDMIVMMDEVCONNECTOR pInterface, struct VBoxGuestStatistics *pGuestStats)); + + /** + * Query the current balloon size + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pcbBalloon Balloon size + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryBalloonSize,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pcbBalloon)); + + /** + * Query the current page fusion setting + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pfPageFusionEnabled Pointer to boolean + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIsPageFusionEnabled,(PPDMIVMMDEVCONNECTOR pInterface, bool *pfPageFusionEnabled)); + +} PDMIVMMDEVCONNECTOR; +/** PDMIVMMDEVCONNECTOR interface ID. */ +#define PDMIVMMDEVCONNECTOR_IID "aff90240-a443-434e-9132-80c186ab97d4" + + +/** + * Generic status LED core. + * Note that a unit doesn't have to support all the indicators. + */ +typedef union PDMLEDCORE +{ + /** 32-bit view. */ + uint32_t volatile u32; + /** Bit view. */ + struct + { + /** Reading/Receiving indicator. */ + uint32_t fReading : 1; + /** Writing/Sending indicator. */ + uint32_t fWriting : 1; + /** Busy indicator. */ + uint32_t fBusy : 1; + /** Error indicator. */ + uint32_t fError : 1; + } s; +} PDMLEDCORE; + +/** LED bit masks for the u32 view. + * @{ */ +/** Reading/Receiving indicator. */ +#define PDMLED_READING RT_BIT(0) +/** Writing/Sending indicator. */ +#define PDMLED_WRITING RT_BIT(1) +/** Busy indicator. */ +#define PDMLED_BUSY RT_BIT(2) +/** Error indicator. */ +#define PDMLED_ERROR RT_BIT(3) +/** @} */ + + +/** + * Generic status LED. + * Note that a unit doesn't have to support all the indicators. + */ +typedef struct PDMLED +{ + /** Just a magic for sanity checking. */ + uint32_t u32Magic; + uint32_t u32Alignment; /**< structure size alignment. */ + /** The actual LED status. + * Only the device is allowed to change this. */ + PDMLEDCORE Actual; + /** The asserted LED status which is cleared by the reader. + * The device will assert the bits but never clear them. + * The driver clears them as it sees fit. */ + PDMLEDCORE Asserted; +} PDMLED; + +/** Pointer to an LED. */ +typedef PDMLED *PPDMLED; +/** Pointer to a const LED. */ +typedef const PDMLED *PCPDMLED; + +/** Magic value for PDMLED::u32Magic. */ +#define PDMLED_MAGIC UINT32_C(0x11335577) + +/** Pointer to an LED ports interface. */ +typedef struct PDMILEDPORTS *PPDMILEDPORTS; +/** + * Interface for exporting LEDs (down). + * Pair with PDMILEDCONNECTORS. + */ +typedef struct PDMILEDPORTS +{ + /** + * Gets the pointer to the status LED of a unit. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param iLUN The unit which status LED we desire. + * @param ppLed Where to store the LED pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryStatusLed,(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)); + +} PDMILEDPORTS; +/** PDMILEDPORTS interface ID. */ +#define PDMILEDPORTS_IID "435e0cec-8549-4ca0-8c0d-98e52f1dc038" + + +/** Pointer to an LED connectors interface. */ +typedef struct PDMILEDCONNECTORS *PPDMILEDCONNECTORS; +/** + * Interface for reading LEDs (up). + * Pair with PDMILEDPORTS. + */ +typedef struct PDMILEDCONNECTORS +{ + /** + * Notification about a unit which have been changed. + * + * The driver must discard any pointers to data owned by + * the unit and requery it. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param iLUN The unit number. + */ + DECLR3CALLBACKMEMBER(void, pfnUnitChanged,(PPDMILEDCONNECTORS pInterface, unsigned iLUN)); +} PDMILEDCONNECTORS; +/** PDMILEDCONNECTORS interface ID. */ +#define PDMILEDCONNECTORS_IID "8ed63568-82a7-4193-b57b-db8085ac4495" + + +/** Pointer to a Media Notification interface. */ +typedef struct PDMIMEDIANOTIFY *PPDMIMEDIANOTIFY; +/** + * Interface for exporting Medium eject information (up). No interface pair. + */ +typedef struct PDMIMEDIANOTIFY +{ + /** + * Signals that the medium was ejected. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param iLUN The unit which had the medium ejected. + */ + DECLR3CALLBACKMEMBER(int, pfnEjected,(PPDMIMEDIANOTIFY pInterface, unsigned iLUN)); + +} PDMIMEDIANOTIFY; +/** PDMIMEDIANOTIFY interface ID. */ +#define PDMIMEDIANOTIFY_IID "fc22d53e-feb1-4a9c-b9fb-0a990a6ab288" + + +/** The special status unit number */ +#define PDM_STATUS_LUN 999 + + +#ifdef VBOX_WITH_HGCM + +/** Abstract HGCM command structure. Used only to define a typed pointer. */ +struct VBOXHGCMCMD; + +/** Pointer to HGCM command structure. This pointer is unique and identifies + * the command being processed. The pointer is passed to HGCM connector methods, + * and must be passed back to HGCM port when command is completed. + */ +typedef struct VBOXHGCMCMD *PVBOXHGCMCMD; + +/** Pointer to a HGCM port interface. */ +typedef struct PDMIHGCMPORT *PPDMIHGCMPORT; +/** + * Host-Guest communication manager port interface (down). Normally implemented + * by VMMDev. + * Pair with PDMIHGCMCONNECTOR. + */ +typedef struct PDMIHGCMPORT +{ + /** + * Notify the guest on a command completion. + * + * @returns VINF_SUCCESS or VERR_CANCELLED if the guest canceled the call. + * @param pInterface Pointer to this interface. + * @param rc The return code (VBox error code). + * @param pCmd A pointer that identifies the completed command. + */ + DECLR3CALLBACKMEMBER(int, pfnCompleted,(PPDMIHGCMPORT pInterface, int32_t rc, PVBOXHGCMCMD pCmd)); + + /** + * Checks if @a pCmd was restored & resubmitted from saved state. + * + * @returns true if restored, false if not. + * @param pInterface Pointer to this interface. + * @param pCmd The command we're checking on. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsCmdRestored,(PPDMIHGCMPORT pInterface, PVBOXHGCMCMD pCmd)); + + /** + * Checks if @a pCmd was cancelled. + * + * @returns true if cancelled, false if not. + * @param pInterface Pointer to this interface. + * @param pCmd The command we're checking on. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsCmdCancelled,(PPDMIHGCMPORT pInterface, PVBOXHGCMCMD pCmd)); + + /** + * Gets the VMMDevRequestHeader::fRequestor value for @a pCmd. + * + * @returns The fRequestor value, VMMDEV_REQUESTOR_LEGACY if guest does not + * support it, VMMDEV_REQUESTOR_LOWEST if invalid parameters. + * @param pInterface Pointer to this interface. + * @param pCmd The command we're in checking on. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetRequestor,(PPDMIHGCMPORT pInterface, PVBOXHGCMCMD pCmd)); + + /** + * Gets the VMMDevState::idSession value. + * + * @returns VMMDevState::idSession. + * @param pInterface Pointer to this interface. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnGetVMMDevSessionId,(PPDMIHGCMPORT pInterface)); + +} PDMIHGCMPORT; +/** PDMIHGCMPORT interface ID. */ +# define PDMIHGCMPORT_IID "28c0a201-68cd-4752-9404-bb42a0c09eb7" + +/* forward decl to hgvmsvc.h. */ +struct VBOXHGCMSVCPARM; +/** Pointer to a HGCM service location structure. */ +typedef struct HGCMSERVICELOCATION *PHGCMSERVICELOCATION; +/** Pointer to a HGCM connector interface. */ +typedef struct PDMIHGCMCONNECTOR *PPDMIHGCMCONNECTOR; +/** + * The Host-Guest communication manager connector interface (up). Normally + * implemented by Main::VMMDevInterface. + * Pair with PDMIHGCMPORT. + */ +typedef struct PDMIHGCMCONNECTOR +{ + /** + * Locate a service and inform it about a client connection. + * + * @param pInterface Pointer to this interface. + * @param pCmd A pointer that identifies the command. + * @param pServiceLocation Pointer to the service location structure. + * @param pu32ClientID Where to store the client id for the connection. + * @return VBox status code. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnConnect,(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, PHGCMSERVICELOCATION pServiceLocation, uint32_t *pu32ClientID)); + + /** + * Disconnect from service. + * + * @param pInterface Pointer to this interface. + * @param pCmd A pointer that identifies the command. + * @param u32ClientID The client id returned by the pfnConnect call. + * @return VBox status code. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnDisconnect,(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t u32ClientID)); + + /** + * Process a guest issued command. + * + * @param pInterface Pointer to this interface. + * @param pCmd A pointer that identifies the command. + * @param u32ClientID The client id returned by the pfnConnect call. + * @param u32Function Function to be performed by the service. + * @param cParms Number of parameters in the array pointed to by paParams. + * @param paParms Pointer to an array of parameters. + * @param tsArrival The STAM_GET_TS() value when the request arrived. + * @return VBox status code. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnCall,(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t u32ClientID, uint32_t u32Function, + uint32_t cParms, struct VBOXHGCMSVCPARM *paParms, uint64_t tsArrival)); + + /** + * Notification about the guest cancelling a pending request. + * @param pInterface Pointer to this interface. + * @param pCmd A pointer that identifies the command. + * @param idclient The client id returned by the pfnConnect call. + */ + DECLR3CALLBACKMEMBER(void, pfnCancelled,(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t idClient)); + +} PDMIHGCMCONNECTOR; +/** PDMIHGCMCONNECTOR interface ID. */ +# define PDMIHGCMCONNECTOR_IID "33cb5c91-6a4a-4ad9-3fec-d1f7d413c4a5" + +#endif /* VBOX_WITH_HGCM */ + + +/** Pointer to a display VBVA callbacks interface. */ +typedef struct PDMIDISPLAYVBVACALLBACKS *PPDMIDISPLAYVBVACALLBACKS; +/** + * Display VBVA callbacks interface (up). + */ +typedef struct PDMIDISPLAYVBVACALLBACKS +{ + + /** + * Informs guest about completion of processing the given Video HW Acceleration + * command, does not wait for the guest to process the command. + * + * @returns ??? + * @param pInterface Pointer to this interface. + * @param pCmd The Video HW Acceleration Command that was + * completed. + */ + DECLR3CALLBACKMEMBER(int, pfnVHWACommandCompleteAsync,(PPDMIDISPLAYVBVACALLBACKS pInterface, + VBOXVHWACMD RT_UNTRUSTED_VOLATILE_GUEST *pCmd)); +} PDMIDISPLAYVBVACALLBACKS; +/** PDMIDISPLAYVBVACALLBACKS */ +#define PDMIDISPLAYVBVACALLBACKS_IID "37f34c9c-0491-47dc-a0b3-81697c44a416" + +/** Pointer to a PCI raw connector interface. */ +typedef struct PDMIPCIRAWCONNECTOR *PPDMIPCIRAWCONNECTOR; +/** + * PCI raw connector interface (up). + */ +typedef struct PDMIPCIRAWCONNECTOR +{ + + /** + * + */ + DECLR3CALLBACKMEMBER(int, pfnDeviceConstructComplete, (PPDMIPCIRAWCONNECTOR pInterface, const char *pcszName, + uint32_t uHostPciAddress, uint32_t uGuestPciAddress, + int rc)); + +} PDMIPCIRAWCONNECTOR; +/** PDMIPCIRAWCONNECTOR interface ID. */ +#define PDMIPCIRAWCONNECTOR_IID "14aa9c6c-8869-4782-9dfc-910071a6aebf" + + +/** Pointer to a VFS connector interface. */ +typedef struct PDMIVFSCONNECTOR *PPDMIVFSCONNECTOR; +/** + * VFS connector interface (up). + */ +typedef struct PDMIVFSCONNECTOR +{ + /** + * Queries the size of the given path. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the path is not available. + * @param pInterface Pointer to this interface. + * @param pszNamespace The namespace for the path (usually driver/device name) or NULL for default namespace. + * @param pszPath The path to query the size for. + * @param pcb Where to store the size of the path in bytes on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQuerySize, (PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath, + uint64_t *pcb)); + + /** + * Reads everything from the given path and stores the data into the supplied buffer. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the path is not available. + * @retval VERR_BUFFER_OVERFLOW if the supplied buffer is too small to read everything. + * @retval VINF_BUFFER_UNDERFLOW if the supplied buffer is too large. + * @param pInterface Pointer to this interface. + * @param pszNamespace The namespace for the path (usually driver/device name) or NULL for default namespace. + * @param pszPath The path to read everything for. + * @param pvBuf Where to store the data. + * @param cbRead How much to read. + */ + DECLR3CALLBACKMEMBER(int, pfnReadAll, (PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath, + void *pvBuf, size_t cbRead)); + + /** + * Writes the supplied data to the given path, overwriting any previously existing data. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pszNamespace The namespace for the path (usually driver/device name) or NULL for default namespace. + * @param pszPath The path to write everything to. + * @param pvBuf The data to store. + * @param cbWrite How many bytes to write. + */ + DECLR3CALLBACKMEMBER(int, pfnWriteAll, (PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath, + const void *pvBuf, size_t cbWrite)); + + /** + * Deletes the given path. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the path is not available. + * @param pszNamespace The namespace for the path (usually driver/device name) or NULL for default namespace. + * @param pszPath The path to delete. + */ + DECLR3CALLBACKMEMBER(int, pfnDelete, (PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath)); + + /** @todo Add standard open/read/write/close callbacks when the need arises. */ + +} PDMIVFSCONNECTOR; +/** PDMIVFSCONNECTOR interface ID. */ +#define PDMIVFSCONNECTOR_IID "a1fc51e0-414a-4e78-8388-8053b9dc6521" + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmifs_h */ diff --git a/include/VBox/vmm/pdmins.h b/include/VBox/vmm/pdmins.h new file mode 100644 index 00000000..9e50b723 --- /dev/null +++ b/include/VBox/vmm/pdmins.h @@ -0,0 +1,99 @@ +/** @file + * PDM - Pluggable Device Manager, Common Instance Macros. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmins_h +#define VBOX_INCLUDED_vmm_pdmins_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/** @defgroup grp_pdm_ins Common PDM Instance Macros + * @ingroup grp_pdm + * @{ + */ + +/** @def PDMBOTHCBDECL + * Macro for declaring a callback which is static in HC and exported in GC. + */ +#if defined(IN_RC) || defined(IN_RING0) +# ifdef __cplusplus +# define PDMBOTHCBDECL(type) extern "C" DECLEXPORT(type) +# else +# define PDMBOTHCBDECL(type) DECLEXPORT(type) +# endif +#else +# define PDMBOTHCBDECL(type) static DECLCALLBACK(type) +#endif + +/** @def PDMINS_2_DATA + * Gets the shared instance data for a PDM device, USB device, or driver instance. + * @note For devices using PDMDEVINS_2_DATA is highly recommended. + */ +#define PDMINS_2_DATA(pIns, type) ( (type)(pIns)->CTX_SUFF(pvInstanceData) ) + +/** @def PDMINS_2_DATA_CC + * Gets the current context instance data for a PDM device, USB device, or driver instance. + * @note For devices using PDMDEVINS_2_DATA_CC is highly recommended. + */ +#define PDMINS_2_DATA_CC(pIns, type) ( (type)(void *)&(pIns)->achInstanceData[0] ) + +/* @def PDMINS_2_DATA_RC + * Gets the raw-mode context instance data for a PDM device instance. + */ +#define PDMINS_2_DATA_RC(pIns, type) ( (type)(pIns)->CTX_SUFF(pvInstanceDataForRC) ) + + +/** @def PDMINS_2_DATA_RCPTR + * Converts a PDM Device, USB Device, or Driver instance pointer to a RC pointer to the instance data. + * @deprecated + */ +#define PDMINS_2_DATA_RCPTR(pIns) ( (pIns)->pvInstanceDataRC ) + +/** @def PDMINS_2_DATA_R3PTR + * Converts a PDM Device, USB Device, or Driver instance pointer to a HC pointer to the instance data. + * @deprecated + */ +#define PDMINS_2_DATA_R3PTR(pIns) ( (pIns)->pvInstanceDataR3 ) + +/** @def PDMINS_2_DATA_R0PTR + * Converts a PDM Device, USB Device, or Driver instance pointer to a R0 pointer to the instance data. + * @deprecated + */ +#define PDMINS_2_DATA_R0PTR(pIns) ( (pIns)->pvInstanceDataR0 ) + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmins_h */ diff --git a/include/VBox/vmm/pdmnetifs.h b/include/VBox/vmm/pdmnetifs.h new file mode 100644 index 00000000..49e93cb5 --- /dev/null +++ b/include/VBox/vmm/pdmnetifs.h @@ -0,0 +1,456 @@ +/** @file + * PDM - Pluggable Device Manager, Network Interfaces. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmnetifs_h +#define VBOX_INCLUDED_vmm_pdmnetifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_ifs_net PDM Network Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + + +/** + * PDM scatter/gather buffer. + * + * @todo Promote this to VBox/types.h, VBox/vmm/pdmcommon.h or some such place. + */ +typedef struct PDMSCATTERGATHER +{ + /** Flags. */ + size_t fFlags; + /** The number of bytes used. + * This is cleared on alloc and set by the user. */ + size_t cbUsed; + /** The number of bytes available. + * This is set on alloc and not changed by the user. */ + size_t cbAvailable; + /** Private data member for the allocator side. */ + void *pvAllocator; + /** Private data member for the user side. */ + void *pvUser; + /** The number of segments + * This is set on alloc and not changed by the user. */ + size_t cSegs; + /** Variable sized array of segments. */ + PDMDATASEG aSegs[1]; +} PDMSCATTERGATHER; +/** Pointer to a PDM scatter/gather buffer. */ +typedef PDMSCATTERGATHER *PPDMSCATTERGATHER; +/** Pointer to a PDM scatter/gather buffer pointer. */ +typedef PPDMSCATTERGATHER *PPPDMSCATTERGATHER; + + +/** @name PDMSCATTERGATHER::fFlags + * @{ */ +/** Magic value. */ +#define PDMSCATTERGATHER_FLAGS_MAGIC UINT32_C(0xb1b10000) +/** Magic mask. */ +#define PDMSCATTERGATHER_FLAGS_MAGIC_MASK UINT32_C(0xffff0000) +/** Owned by owner number 1. */ +#define PDMSCATTERGATHER_FLAGS_OWNER_1 UINT32_C(0x00000001) +/** Owned by owner number 2. */ +#define PDMSCATTERGATHER_FLAGS_OWNER_2 UINT32_C(0x00000002) +/** Owned by owner number 3. */ +#define PDMSCATTERGATHER_FLAGS_OWNER_3 UINT32_C(0x00000002) +/** Owner mask. */ +#define PDMSCATTERGATHER_FLAGS_OWNER_MASK UINT32_C(0x00000003) +/** Mask of flags available to general use. + * The parties using the SG must all agree upon how to use these of course. */ +#define PDMSCATTERGATHER_FLAGS_AVL_MASK UINT32_C(0x0000f000) +/** Flags reserved for future use, MBZ. */ +#define PDMSCATTERGATHER_FLAGS_RVD_MASK UINT32_C(0x00000ff8) +/** @} */ + + +/** + * Sets the owner of a scatter/gather buffer. + * + * @param pSgBuf . + * @param uNewOwner The new owner. + */ +DECLINLINE(void) PDMScatterGatherSetOwner(PPDMSCATTERGATHER pSgBuf, uint32_t uNewOwner) +{ + pSgBuf->fFlags = (pSgBuf->fFlags & ~PDMSCATTERGATHER_FLAGS_OWNER_MASK) | uNewOwner; +} + + + +/** Pointer to a network port interface */ +typedef struct PDMINETWORKDOWN *PPDMINETWORKDOWN; +/** + * Network port interface (down). + * Pair with PDMINETWORKUP. + */ +typedef struct PDMINETWORKDOWN +{ + /** + * Wait until there is space for receiving data. We do not care how much space is available + * because pfnReceive() will re-check and notify the guest if necessary. + * + * This function must be called before the pfnRecieve() method is called. + * + * @returns VBox status code. VINF_SUCCESS means there is at least one receive descriptor available. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cMillies Number of milliseconds to wait. 0 means return immediately. + * + * @thread Non-EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnWaitReceiveAvail,(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies)); + + /** + * Receive data from the network. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf The available data. + * @param cb Number of bytes available in the buffer. + * + * @thread Non-EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnReceive,(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)); + + /** + * Receive data with segmentation context from the network. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf The available data. + * @param cb Number of bytes available in the buffer. + * @param pGso Segmentation context. + * + * @thread Non-EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnReceiveGso,(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb, PCPDMNETWORKGSO pGso)); + + /** + * Do pending transmit work on the leaf driver's XMIT thread. + * + * When a PDMINETWORKUP::pfnBeginTransmit or PDMINETWORKUP::pfnAllocBuf call + * fails with VERR_TRY_AGAIN, the leaf drivers XMIT thread will offer to process + * the upstream device/driver when the the VERR_TRY_AGAIN condition has been + * removed. In some cases the VERR_TRY_AGAIN condition is simply being in an + * inconvenient context and the XMIT thread will start working ASAP. + * + * @param pInterface Pointer to this interface. + * @thread Non-EMT. + */ + DECLR3CALLBACKMEMBER(void, pfnXmitPending,(PPDMINETWORKDOWN pInterface)); + +} PDMINETWORKDOWN; +/** PDMINETWORKDOWN interface ID. */ +#define PDMINETWORKDOWN_IID "52b8cdbb-a087-493b-baa7-81ec3b803e06" + + +/** + * Network link state. + */ +typedef enum PDMNETWORKLINKSTATE +{ + /** Invalid state. */ + PDMNETWORKLINKSTATE_INVALID = 0, + /** The link is up. */ + PDMNETWORKLINKSTATE_UP, + /** The link is down. */ + PDMNETWORKLINKSTATE_DOWN, + /** The link is temporarily down while resuming. */ + PDMNETWORKLINKSTATE_DOWN_RESUME +} PDMNETWORKLINKSTATE; + + +/** Pointer to a network connector interface */ +typedef R3PTRTYPE(struct PDMINETWORKUP *) PPDMINETWORKUPR3; +/** Pointer to a network connector interface, ring-0 context. */ +typedef R0PTRTYPE(struct PDMINETWORKUPR0 *) PPDMINETWORKUPR0; +/** Pointer to a network connector interface, raw-mode context. */ +typedef RCPTRTYPE(struct PDMINETWORKUPRC *) PPDMINETWORKUPRC; +/** Pointer to a current context network connector interface. */ +typedef CTX_SUFF(PPDMINETWORKUP) PPDMINETWORKUP; + +/** + * Network connector interface (up). + * Pair with PDMINETWORKDOWN. + */ +typedef struct PDMINETWORKUP +{ + /** + * Begins a transmit session. + * + * The leaf driver guarantees that there are no concurrent sessions. + * + * @retval VINF_SUCCESS on success. Must always call + * PDMINETWORKUP::pfnEndXmit. + * @retval VERR_TRY_AGAIN if there is already an open transmit session or some + * important resource was unavailable (like buffer space). If it's a + * resources issue, the driver will signal its XMIT thread and have it + * work the device thru the PDMINETWORKDOWN::pfnNotifyBufAvailable + * callback method. + * + * @param pInterface Pointer to the interface structure containing the + * called function pointer. + * @param fOnWorkerThread Set if we're being called on a work thread. Clear + * if an EMT. + * + * @thread Any, but normally EMT or the XMIT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnBeginXmit,(PPDMINETWORKUP pInterface, bool fOnWorkerThread)); + + /** + * Get a send buffer for passing to pfnSendBuf. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_TRY_AGAIN if temporarily out of buffer space. After this + * happens, the driver will call PDMINETWORKDOWN::pfnNotifyBufAvailable + * when this is a buffer of the required size available. + * @retval VERR_NO_MEMORY if really out of buffer space. + * @retval VERR_NET_DOWN if we cannot send anything to the network at this + * point in time. Drop the frame with a xmit error. This is typically + * only seen when pausing the VM since the device keeps the link state, + * but there could of course be races. + * + * @param pInterface Pointer to the interface structure containing the + * called function pointer. + * @param cbMin The minimum buffer size. + * @param pGso Pointer to a GSO context (only reference while in + * this call). NULL indicates no segmentation + * offloading. PDMSCATTERGATHER::pvUser is used to + * indicate that a network SG uses GSO, usually by + * pointing to a copy of @a pGso. + * @param ppSgBuf Where to return the buffer. The buffer will be + * owned by the caller, designation owner number 1. + * + * @thread Any, but normally EMT or the XMIT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnAllocBuf,(PPDMINETWORKUP pInterface, size_t cbMin, PCPDMNETWORKGSO pGso, + PPPDMSCATTERGATHER ppSgBuf)); + + /** + * Frees an unused buffer. + * + * @retval VINF_SUCCESS on success. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pSgBuf A buffer from PDMINETWORKUP::pfnAllocBuf or + * PDMINETWORKDOWN::pfnNotifyBufAvailable. The buffer + * ownership shall be 1. + * + * @thread Any, but normally EMT or the XMIT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnFreeBuf,(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)); + + /** + * Send data to the network. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_NET_DOWN if the NIC is not connected to a network. pSgBuf will + * be freed. + * @retval VERR_NET_NO_BUFFER_SPACE if we're out of resources. pSgBuf will be + * freed. + * + * @param pInterface Pointer to the interface structure containing the + * called function pointer. + * @param pSgBuf The buffer containing the data to send. The buffer + * ownership shall be 1. The buffer will always be + * consumed, regardless of the status code. + * + * @param fOnWorkerThread Set if we're being called on a work thread. Clear + * if an EMT. + * + * @thread Any, but normally EMT or the XMIT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSendBuf,(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)); + + /** + * Ends a transmit session. + * + * Pairs with successful PDMINETWORKUP::pfnBeginXmit calls. + * + * @param pInterface Pointer to the interface structure containing the + * called function pointer. + * + * @thread Any, but normally EMT or the XMIT thread. + */ + DECLR3CALLBACKMEMBER(void, pfnEndXmit,(PPDMINETWORKUP pInterface)); + + /** + * Set promiscuous mode. + * + * This is called when the promiscuous mode is set. This means that there doesn't have + * to be a mode change when it's called. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not. + * @thread EMT ?? + */ + DECLR3CALLBACKMEMBER(void, pfnSetPromiscuousMode,(PPDMINETWORKUP pInterface, bool fPromiscuous)); + + /** + * Notification on link status changes. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmLinkState The new link state. + * @thread EMT ?? + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyLinkChanged,(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)); + + /** @todo Add a callback that informs the driver chain about MAC address changes if we ever implement that. */ + +} PDMINETWORKUP; + +/** Ring-0 edition of PDMINETWORKUP. */ +typedef struct PDMINETWORKUPR0 +{ + /** @copydoc PDMINETWORKUP::pfnBeginXmit */ + DECLR0CALLBACKMEMBER(int, pfnBeginXmit,(PPDMINETWORKUPR0 pInterface, bool fOnWorkerThread)); + /** @copydoc PDMINETWORKUP::pfnAllocBuf */ + DECLR0CALLBACKMEMBER(int, pfnAllocBuf,(PPDMINETWORKUPR0 pInterface, size_t cbMin, PCPDMNETWORKGSO pGso, + PPPDMSCATTERGATHER ppSgBuf)); + /** @copydoc PDMINETWORKUP::pfnFreeBuf */ + DECLR0CALLBACKMEMBER(int, pfnFreeBuf,(PPDMINETWORKUPR0 pInterface, PPDMSCATTERGATHER pSgBuf)); + /** @copydoc PDMINETWORKUP::pfnSendBuf */ + DECLR0CALLBACKMEMBER(int, pfnSendBuf,(PPDMINETWORKUPR0 pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)); + /** @copydoc PDMINETWORKUP::pfnEndXmit */ + DECLR0CALLBACKMEMBER(void, pfnEndXmit,(PPDMINETWORKUPR0 pInterface)); + /** @copydoc PDMINETWORKUP::pfnSetPromiscuousMode */ + DECLR0CALLBACKMEMBER(void, pfnSetPromiscuousMode,(PPDMINETWORKUPR0 pInterface, bool fPromiscuous)); +} PDMINETWORKUPR0; + +/** Raw-mode context edition of PDMINETWORKUP. */ +typedef struct PDMINETWORKUPRC +{ + /** @copydoc PDMINETWORKUP::pfnBeginXmit */ + DECLRCCALLBACKMEMBER(int, pfnBeginXmit,(PPDMINETWORKUPRC pInterface, bool fOnWorkerThread)); + /** @copydoc PDMINETWORKUP::pfnAllocBuf */ + DECLRCCALLBACKMEMBER(int, pfnAllocBuf,(PPDMINETWORKUPRC pInterface, size_t cbMin, PCPDMNETWORKGSO pGso, + PPPDMSCATTERGATHER ppSgBuf)); + /** @copydoc PDMINETWORKUP::pfnFreeBuf */ + DECLRCCALLBACKMEMBER(int, pfnFreeBuf,(PPDMINETWORKUPRC pInterface, PPDMSCATTERGATHER pSgBuf)); + /** @copydoc PDMINETWORKUP::pfnSendBuf */ + DECLRCCALLBACKMEMBER(int, pfnSendBuf,(PPDMINETWORKUPRC pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)); + /** @copydoc PDMINETWORKUP::pfnEndXmit */ + DECLRCCALLBACKMEMBER(void, pfnEndXmit,(PPDMINETWORKUPRC pInterface)); + /** @copydoc PDMINETWORKUP::pfnSetPromiscuousMode */ + DECLRCCALLBACKMEMBER(void, pfnSetPromiscuousMode,(PPDMINETWORKUPRC pInterface, bool fPromiscuous)); +} PDMINETWORKUPRC; + +/** PDMINETWORKUP interface ID. */ +#define PDMINETWORKUP_IID "67e7e7a8-2594-4649-a1e3-7cee680c6083" +/** PDMINETWORKUP interface method names. */ +#define PDMINETWORKUP_SYM_LIST "BeginXmit;AllocBuf;FreeBuf;SendBuf;EndXmit;SetPromiscuousMode" + + +/** Pointer to a network config port interface */ +typedef struct PDMINETWORKCONFIG *PPDMINETWORKCONFIG; +/** + * Network config port interface (main). + * No interface pair. + */ +typedef struct PDMINETWORKCONFIG +{ + /** + * Gets the current Media Access Control (MAC) address. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pMac Where to store the MAC address. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnGetMac,(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)); + + /** + * Gets the new link state. + * + * @returns The current link state. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(PDMNETWORKLINKSTATE, pfnGetLinkState,(PPDMINETWORKCONFIG pInterface)); + + /** + * Sets the new link state. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmState The new link state + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnSetLinkState,(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)); + +} PDMINETWORKCONFIG; +/** PDMINETWORKCONFIG interface ID. */ +#define PDMINETWORKCONFIG_IID "d6d909e8-716d-415d-b109-534e4478ff4e" + + +/** Pointer to a NAT configuration port. */ +typedef struct PDMINETWORKNATCONFIG *PPDMINETWORKNATCONFIG; +/** + * Network config port interface (main). + * No interface pair. + */ +typedef struct PDMINETWORKNATCONFIG +{ + /** + * Inform NAT about the adding/removing redirection rule + * + * @todo D O C U M E N T M E ! + * @todo s/u16/u/g + */ + DECLR3CALLBACKMEMBER(int, pfnRedirectRuleCommand ,(PPDMINETWORKNATCONFIG pInterface, bool fRemove, + bool fUdp, const char *pHostIp, uint16_t u16HostPort, + const char *pGuestIp, uint16_t u16GuestPort)); + /** + * Inform NAT about host DNS settings change. + * + * IHostNameResolutionConfigurationChangeEvent. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyDnsChanged, (PPDMINETWORKNATCONFIG pInterface)); + +} PDMINETWORKNATCONFIG; +/** PDMINETWORKNATCONFIG interface ID. */ +#define PDMINETWORKNATCONFIG_IID "dc961028-3523-4b52-a93b-e38168a4a9fa" +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmnetifs_h */ + diff --git a/include/VBox/vmm/pdmnetinline.h b/include/VBox/vmm/pdmnetinline.h new file mode 100644 index 00000000..0acd5fb9 --- /dev/null +++ b/include/VBox/vmm/pdmnetinline.h @@ -0,0 +1,724 @@ +/** @file + * PDM - Networking Helpers, Inlined Code. (DEV,++) + * + * This is all inlined because it's too tedious to create 2-3 libraries to + * contain it all (same bad excuse as for intnetinline.h). + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmnetinline_h +#define VBOX_INCLUDED_vmm_pdmnetinline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include <VBox/log.h> +#include <VBox/types.h> +#include <iprt/asm.h> +#include <iprt/assert.h> +#include <iprt/net.h> +#include <iprt/string.h> + + +/** @defgroup grp_pdm_net_inline The PDM Networking Helper APIs + * @ingroup grp_pdm + * @{ + */ + + +/** + * Checksum type. + */ +typedef enum PDMNETCSUMTYPE +{ + /** No checksum. */ + PDMNETCSUMTYPE_NONE = 0, + /** Normal TCP checksum. */ + PDMNETCSUMTYPE_COMPLETE, + /** Checksum on pseudo header (used with GSO). */ + PDMNETCSUMTYPE_PSEUDO, + /** The usual 32-bit hack. */ + PDMNETCSUMTYPE_32_BIT_HACK = 0x7fffffff +} PDMNETCSUMTYPE; + + +/** + * Validates the GSO context. + * + * @returns true if valid, false if not (not asserted or logged). + * @param pGso The GSO context. + * @param cbGsoMax The max size of the GSO context. + * @param cbFrame The max size of the GSO frame (use to validate + * the MSS). + */ +DECLINLINE(bool) PDMNetGsoIsValid(PCPDMNETWORKGSO pGso, size_t cbGsoMax, size_t cbFrame) +{ +#define CHECK_COND_RETURN_FALSE(expr) if (RT_LIKELY(expr)) { /* likely */ } else return false + PDMNETWORKGSOTYPE enmType; + + CHECK_COND_RETURN_FALSE(cbGsoMax >= sizeof(*pGso)); + + enmType = (PDMNETWORKGSOTYPE)pGso->u8Type; + CHECK_COND_RETURN_FALSE(enmType > PDMNETWORKGSOTYPE_INVALID && enmType < PDMNETWORKGSOTYPE_END); + + /* all types requires both headers. */ + CHECK_COND_RETURN_FALSE(pGso->offHdr1 >= sizeof(RTNETETHERHDR)); + CHECK_COND_RETURN_FALSE(pGso->offHdr2 > pGso->offHdr1); + CHECK_COND_RETURN_FALSE(pGso->cbHdrsTotal > pGso->offHdr2); + + /* min size of the 1st header(s). */ + switch (enmType) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: + case PDMNETWORKGSOTYPE_IPV4_UDP: + CHECK_COND_RETURN_FALSE((unsigned)pGso->offHdr2 - pGso->offHdr1 >= RTNETIPV4_MIN_LEN); + break; + case PDMNETWORKGSOTYPE_IPV6_TCP: + case PDMNETWORKGSOTYPE_IPV6_UDP: + CHECK_COND_RETURN_FALSE((unsigned)pGso->offHdr2 - pGso->offHdr1 >= RTNETIPV6_MIN_LEN); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + CHECK_COND_RETURN_FALSE((unsigned)pGso->offHdr2 - pGso->offHdr1 >= RTNETIPV4_MIN_LEN + RTNETIPV6_MIN_LEN); + break; + /* These two have been rejected above already, but we need to include them to avoid gcc warnings. */ + case PDMNETWORKGSOTYPE_INVALID: + case PDMNETWORKGSOTYPE_END: + break; + /* No default case! Want gcc warnings. */ + } + + /* min size of the 2nd header. */ + switch (enmType) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: + case PDMNETWORKGSOTYPE_IPV6_TCP: + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: + CHECK_COND_RETURN_FALSE((unsigned)pGso->cbHdrsTotal - pGso->offHdr2 >= RTNETTCP_MIN_LEN); + break; + case PDMNETWORKGSOTYPE_IPV4_UDP: + case PDMNETWORKGSOTYPE_IPV6_UDP: + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + CHECK_COND_RETURN_FALSE((unsigned)pGso->cbHdrsTotal - pGso->offHdr2 >= RTNETUDP_MIN_LEN); + break; + /* These two have been rejected above already, but we need to include them to avoid gcc warnings. */ + case PDMNETWORKGSOTYPE_INVALID: + case PDMNETWORKGSOTYPE_END: + break; + /* No default case! Want gcc warnings. */ + } + + /* There must be at more than one segment. */ + CHECK_COND_RETURN_FALSE(cbFrame > pGso->cbHdrsTotal); + CHECK_COND_RETURN_FALSE(cbFrame - pGso->cbHdrsTotal >= pGso->cbMaxSeg); + + /* Make sure the segment size is enough to fit a UDP header. */ + CHECK_COND_RETURN_FALSE(enmType != PDMNETWORKGSOTYPE_IPV4_UDP || pGso->cbMaxSeg >= RTNETUDP_MIN_LEN); + + /* Make sure the segment size is not zero. */ + CHECK_COND_RETURN_FALSE(pGso->cbMaxSeg > 0); + + return true; +#undef CHECK_COND_RETURN_FALSE +} + + +/** + * Returns the length of header for a particular segment/fragment. + * + * We cannot simply treat UDP header as a part of payload because we do not + * want to modify the payload but still need to modify the checksum field in + * UDP header. So we want to include UDP header when calculating the length + * of headers in the first segment getting it copied to a temporary buffer + * along with other headers. + * + * @returns Length of headers (including UDP header for the first fragment). + * @param pGso The GSO context. + * @param iSeg The segment index. + */ +DECLINLINE(uint8_t) pdmNetSegHdrLen(PCPDMNETWORKGSO pGso, uint32_t iSeg) +{ + return iSeg ? pGso->cbHdrsSeg : pGso->cbHdrsTotal; +} + +/** + * Returns the length of payload for a particular segment/fragment. + * + * The first segment does not contain UDP header. The size of UDP header is + * determined as the difference between the total headers size and the size + * used during segmentation. + * + * @returns Length of payload (including UDP header for the first fragment). + * @param pGso The GSO context. + * @param iSeg The segment that we're carving out (0-based). + * @param cSegs The number of segments in the GSO frame. + * @param cbFrame The size of the GSO frame. + */ +DECLINLINE(uint32_t) pdmNetSegPayloadLen(PCPDMNETWORKGSO pGso, uint32_t iSeg, uint32_t cSegs, uint32_t cbFrame) +{ + if (iSeg + 1 == cSegs) + return cbFrame - iSeg * pGso->cbMaxSeg - pdmNetSegHdrLen(pGso, iSeg); + return pGso->cbMaxSeg - (iSeg ? 0 : pGso->cbHdrsTotal - pGso->cbHdrsSeg); +} + +/** + * Calculates the number of segments a GSO frame will be segmented into. + * + * @returns Segment count. + * @param pGso The GSO context. + * @param cbFrame The GSO frame size (header proto + payload). + */ +DECLINLINE(uint32_t) PDMNetGsoCalcSegmentCount(PCPDMNETWORKGSO pGso, size_t cbFrame) +{ + size_t cbPayload; + Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame)); + cbPayload = cbFrame - pGso->cbHdrsSeg; + return (uint32_t)((cbPayload + pGso->cbMaxSeg - 1) / pGso->cbMaxSeg); +} + + +/** + * Used to find the IPv6 header when handling 4to6 tunneling. + * + * @returns Offset of the IPv6 header. + * @param pbSegHdrs The headers / frame start. + * @param offIPv4Hdr The offset of the IPv4 header. + */ +DECLINLINE(uint8_t) pgmNetGsoCalcIpv6Offset(uint8_t *pbSegHdrs, uint8_t offIPv4Hdr) +{ + PCRTNETIPV4 pIPv4Hdr = (PCRTNETIPV4)&pbSegHdrs[offIPv4Hdr]; + return offIPv4Hdr + pIPv4Hdr->ip_hl * 4; +} + + +/** + * Update an UDP header after carving out a segment + * + * @param u32PseudoSum The pseudo checksum. + * @param pbSegHdrs Pointer to the header bytes / frame start. + * @param offUdpHdr The offset into @a pbSegHdrs of the UDP header. + * @param pbPayload Pointer to the payload bytes. + * @param cbPayload The amount of payload. + * @param cbHdrs The size of all the headers. + * @param enmCsumType Whether to checksum the payload, the pseudo + * header or nothing. + * @internal + */ +DECLINLINE(void) pdmNetGsoUpdateUdpHdr(uint32_t u32PseudoSum, uint8_t *pbSegHdrs, uint8_t offUdpHdr, + uint8_t const *pbPayload, uint32_t cbPayload, uint8_t cbHdrs, + PDMNETCSUMTYPE enmCsumType) +{ + PRTNETUDP pUdpHdr = (PRTNETUDP)&pbSegHdrs[offUdpHdr]; + pUdpHdr->uh_ulen = RT_H2N_U16(cbPayload + cbHdrs - offUdpHdr); + switch (enmCsumType) + { + case PDMNETCSUMTYPE_NONE: + pUdpHdr->uh_sum = 0; + break; + case PDMNETCSUMTYPE_COMPLETE: + pUdpHdr->uh_sum = RTNetUDPChecksum(u32PseudoSum, pUdpHdr); + break; + case PDMNETCSUMTYPE_PSEUDO: + pUdpHdr->uh_sum = ~RTNetIPv4FinalizeChecksum(u32PseudoSum); + break; + default: + NOREF(pbPayload); + AssertFailed(); + break; + } +} + + +/** + * Update an UDP header after carving out an IP fragment + * + * @param u32PseudoSum The pseudo checksum. + * @param pbSegHdrs Pointer to the header bytes copy + * @param pbFrame Pointer to the frame start. + * @param offUdpHdr The offset into @a pbSegHdrs of the UDP header. + * + * @internal + */ +DECLINLINE(void) pdmNetGsoUpdateUdpHdrUfo(uint32_t u32PseudoSum, uint8_t *pbSegHdrs, const uint8_t *pbFrame, uint8_t offUdpHdr) +{ + PCRTNETUDP pcUdpHdrOrig = (PCRTNETUDP)&pbFrame[offUdpHdr]; + PRTNETUDP pUdpHdr = (PRTNETUDP)&pbSegHdrs[offUdpHdr]; + pUdpHdr->uh_sum = RTNetUDPChecksum(u32PseudoSum, pcUdpHdrOrig); +} + + +/** + * Update a TCP header after carving out a segment. + * + * @param u32PseudoSum The pseudo checksum. + * @param pbSegHdrs Pointer to the header bytes / frame start. + * @param offTcpHdr The offset into @a pbSegHdrs of the TCP header. + * @param pbPayload Pointer to the payload bytes. + * @param cbPayload The amount of payload. + * @param offPayload The offset into the payload that we're splitting + * up. We're ASSUMING that the payload follows + * immediately after the TCP header w/ options. + * @param cbHdrs The size of all the headers. + * @param fLastSeg Set if this is the last segment. + * @param enmCsumType Whether to checksum the payload, the pseudo + * header or nothing. + * @internal + */ +DECLINLINE(void) pdmNetGsoUpdateTcpHdr(uint32_t u32PseudoSum, uint8_t *pbSegHdrs, uint8_t offTcpHdr, + uint8_t const *pbPayload, uint32_t cbPayload, uint32_t offPayload, uint8_t cbHdrs, + bool fLastSeg, PDMNETCSUMTYPE enmCsumType) +{ + PRTNETTCP pTcpHdr = (PRTNETTCP)&pbSegHdrs[offTcpHdr]; + pTcpHdr->th_seq = RT_H2N_U32(RT_N2H_U32(pTcpHdr->th_seq) + offPayload); + if (!fLastSeg) + pTcpHdr->th_flags &= ~(RTNETTCP_F_FIN | RTNETTCP_F_PSH); + switch (enmCsumType) + { + case PDMNETCSUMTYPE_NONE: + pTcpHdr->th_sum = 0; + break; + case PDMNETCSUMTYPE_COMPLETE: + pTcpHdr->th_sum = RTNetTCPChecksum(u32PseudoSum, pTcpHdr, pbPayload, cbPayload); + break; + case PDMNETCSUMTYPE_PSEUDO: + pTcpHdr->th_sum = ~RTNetIPv4FinalizeChecksum(u32PseudoSum); + break; + default: + NOREF(cbHdrs); + AssertFailed(); + break; + } +} + + +/** + * Updates a IPv6 header after carving out a segment. + * + * @returns 32-bit intermediary checksum value for the pseudo header. + * @param pbSegHdrs Pointer to the header bytes. + * @param offIpHdr The offset into @a pbSegHdrs of the IP header. + * @param cbSegPayload The amount of segmented payload. Not to be + * confused with the IP payload. + * @param cbHdrs The size of all the headers. + * @param offPktHdr Offset of the protocol packet header. For the + * pseudo header checksum calulation. + * @param bProtocol The protocol type. For the pseudo header. + * @internal + */ +DECLINLINE(uint32_t) pdmNetGsoUpdateIPv6Hdr(uint8_t *pbSegHdrs, uint8_t offIpHdr, uint32_t cbSegPayload, uint8_t cbHdrs, + uint8_t offPktHdr, uint8_t bProtocol) +{ + PRTNETIPV6 pIpHdr = (PRTNETIPV6)&pbSegHdrs[offIpHdr]; + uint16_t cbPayload = (uint16_t)(cbHdrs - (offIpHdr + sizeof(RTNETIPV6)) + cbSegPayload); + pIpHdr->ip6_plen = RT_H2N_U16(cbPayload); + return RTNetIPv6PseudoChecksumEx(pIpHdr, bProtocol, (uint16_t)(cbHdrs - offPktHdr + cbSegPayload)); +} + + +/** + * Updates a IPv4 header after carving out a segment. + * + * @returns 32-bit intermediary checksum value for the pseudo header. + * @param pbSegHdrs Pointer to the header bytes. + * @param offIpHdr The offset into @a pbSegHdrs of the IP header. + * @param cbSegPayload The amount of segmented payload. + * @param iSeg The segment index. + * @param cbHdrs The size of all the headers. + * @internal + */ +DECLINLINE(uint32_t) pdmNetGsoUpdateIPv4Hdr(uint8_t *pbSegHdrs, uint8_t offIpHdr, uint32_t cbSegPayload, + uint32_t iSeg, uint8_t cbHdrs) +{ + PRTNETIPV4 pIpHdr = (PRTNETIPV4)&pbSegHdrs[offIpHdr]; + pIpHdr->ip_len = RT_H2N_U16(cbHdrs - offIpHdr + cbSegPayload); + pIpHdr->ip_id = RT_H2N_U16(RT_N2H_U16(pIpHdr->ip_id) + iSeg); + pIpHdr->ip_sum = RTNetIPv4HdrChecksum(pIpHdr); + return RTNetIPv4PseudoChecksum(pIpHdr); +} + + +/** + * Updates a IPv4 header after carving out an IP fragment. + * + * @param pbSegHdrs Pointer to the header bytes. + * @param offIpHdr The offset into @a pbSegHdrs of the IP header. + * @param cbSegPayload The amount of segmented payload. + * @param offFragment The offset of this fragment for reassembly. + * @param cbHdrs The size of all the headers. + * @param fLastFragment True if this is the last fragment of datagram. + * @internal + */ +DECLINLINE(void) pdmNetGsoUpdateIPv4HdrUfo(uint8_t *pbSegHdrs, uint8_t offIpHdr, uint32_t cbSegPayload, + uint32_t offFragment, uint8_t cbHdrs, bool fLastFragment) +{ + PRTNETIPV4 pIpHdr = (PRTNETIPV4)&pbSegHdrs[offIpHdr]; + pIpHdr->ip_len = RT_H2N_U16(cbHdrs - offIpHdr + cbSegPayload); + pIpHdr->ip_off = RT_H2N_U16((offFragment / 8) | (fLastFragment ? 0 : RTNETIPV4_FLAGS_MF)); + pIpHdr->ip_sum = RTNetIPv4HdrChecksum(pIpHdr); +} + + +/** + * Carves out the specified segment in a destructive manner. + * + * This is for sequentially carving out segments and pushing them along for + * processing or sending. To avoid allocating a temporary buffer for + * constructing the segment in, we trash the previous frame by putting the + * header at the end of it. + * + * @returns Pointer to the segment frame that we've carved out. + * @param pGso The GSO context data. + * @param pbFrame Pointer to the GSO frame. + * @param cbFrame The size of the GSO frame. + * @param pbHdrScatch Pointer to a pGso->cbHdrs sized area where we + * can save the original header prototypes on the + * first call (@a iSeg is 0) and retrieve it on + * susequent calls. (Just use a 256 bytes + * buffer to make life easy.) + * @param iSeg The segment that we're carving out (0-based). + * @param cSegs The number of segments in the GSO frame. Use + * PDMNetGsoCalcSegmentCount to find this. + * @param pcbSegFrame Where to return the size of the returned segment + * frame. + */ +DECLINLINE(void *) PDMNetGsoCarveSegmentQD(PCPDMNETWORKGSO pGso, uint8_t *pbFrame, size_t cbFrame, uint8_t *pbHdrScatch, + uint32_t iSeg, uint32_t cSegs, uint32_t *pcbSegFrame) +{ + /* + * Figure out where the payload is and where the header starts before we + * do the protocol specific carving. + * + * UDP GSO uses IPv4 fragmentation, meaning that UDP header is present in + * the first fragment only. When computing the total frame size of the + * first fragment we need to use PDMNETWORKGSO::cbHdrsTotal instead of + * PDMNETWORKGSO::cbHdrsSeg. In case of TCP GSO both cbHdrsTotal and + * cbHdrsSeg have the same value, so it will work as well. + */ + uint8_t * const pbSegHdrs = pbFrame + pGso->cbMaxSeg * iSeg; + uint8_t * const pbSegPayload = pbSegHdrs + pGso->cbHdrsSeg; + uint32_t const cbSegPayload = pdmNetSegPayloadLen(pGso, iSeg, cSegs, (uint32_t)cbFrame); + uint32_t const cbSegFrame = cbSegPayload + (iSeg ? pGso->cbHdrsSeg : pGso->cbHdrsTotal); + + /* + * Check assumptions (doing it after declaring the variables because of C). + */ + Assert(iSeg < cSegs); + Assert(cSegs == PDMNetGsoCalcSegmentCount(pGso, cbFrame)); + Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame)); + + /* + * Copy the header and do the protocol specific massaging of it. + */ + if (iSeg != 0) + memcpy(pbSegHdrs, pbHdrScatch, pGso->cbHdrsSeg); + else + memcpy(pbHdrScatch, pbSegHdrs, pGso->cbHdrsSeg); /* There is no need to save UDP header */ + + switch ((PDMNETWORKGSOTYPE)pGso->u8Type) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrsSeg), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + pGso->cbHdrsSeg, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_UDP: + if (iSeg == 0) + { + /* uh_ulen shall not exceed cbFrame - pGso->offHdr2 (offset of UDP header) */ + PRTNETUDP pUdpHdr = (PRTNETUDP)&pbFrame[pGso->offHdr2]; + Assert(pGso->offHdr2 + RT_UOFFSET_AFTER(RTNETUDP, uh_ulen) <= cbFrame); + if ((unsigned)(pGso->offHdr2 + RT_BE2H_U16(pUdpHdr->uh_ulen)) > cbFrame) + { + size_t cbUdp = cbFrame - pGso->offHdr2; + if (cbUdp >= UINT16_MAX) + pUdpHdr->uh_ulen = UINT16_MAX; + else + pUdpHdr->uh_ulen = RT_H2BE_U16((uint16_t)cbUdp); + } + /* uh_ulen shall be at least the size of UDP header */ + if (RT_BE2H_U16(pUdpHdr->uh_ulen) < sizeof(RTNETUDP)) + pUdpHdr->uh_ulen = RT_H2BE_U16(sizeof(RTNETUDP)); + pdmNetGsoUpdateUdpHdrUfo(RTNetIPv4PseudoChecksum((PRTNETIPV4)&pbFrame[pGso->offHdr1]), + pbSegHdrs, pbFrame, pGso->offHdr2); + } + pdmNetGsoUpdateIPv4HdrUfo(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg * pGso->cbMaxSeg, + pdmNetSegHdrLen(pGso, iSeg), iSeg + 1 == cSegs); + break; + case PDMNETWORKGSOTYPE_IPV6_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, pGso->cbHdrsSeg, + pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + pGso->cbHdrsSeg, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV6_UDP: + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, pGso->cbHdrsSeg, + pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, pGso->cbHdrsSeg, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: + pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrsSeg); + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1), + cbSegPayload, pGso->cbHdrsSeg, pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + pGso->cbHdrsSeg, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrsSeg); + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1), + cbSegPayload, pGso->cbHdrsSeg, pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, pGso->cbHdrsSeg, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_INVALID: + case PDMNETWORKGSOTYPE_END: + /* no default! wnat gcc warnings. */ + break; + } + + *pcbSegFrame = cbSegFrame; + return pbSegHdrs; +} + + +/** + * Carves out the specified segment in a non-destructive manner. + * + * The segment headers and segment payload is kept separate here. The GSO frame + * is still expected to be one linear chunk of data, but we don't modify any of + * it. + * + * @returns The offset into the GSO frame of the payload. + * @param pGso The GSO context data. + * @param pbFrame Pointer to the GSO frame. Used for retrieving + * the header prototype and for checksumming the + * payload. The buffer is not modified. + * @param cbFrame The size of the GSO frame. + * @param iSeg The segment that we're carving out (0-based). + * @param cSegs The number of segments in the GSO frame. Use + * PDMNetGsoCalcSegmentCount to find this. + * @param pbSegHdrs Where to return the headers for the segment + * that's been carved out. The buffer must be at + * least pGso->cbHdrs in size, using a 256 byte + * buffer is a recommended simplification. + * @param pcbSegHdrs Where to return the size of the returned + * segment headers. + * @param pcbSegPayload Where to return the size of the returned + * segment payload. + */ +DECLINLINE(uint32_t) PDMNetGsoCarveSegment(PCPDMNETWORKGSO pGso, const uint8_t *pbFrame, size_t cbFrame, + uint32_t iSeg, uint32_t cSegs, uint8_t *pbSegHdrs, + uint32_t *pcbSegHdrs, uint32_t *pcbSegPayload) +{ + /* + * Figure out where the payload is and where the header starts before we + * do the protocol specific carving. + */ + uint32_t const cbSegHdrs = pdmNetSegHdrLen(pGso, iSeg); + uint8_t const * const pbSegPayload = pbFrame + cbSegHdrs + iSeg * pGso->cbMaxSeg; + uint32_t const cbSegPayload = pdmNetSegPayloadLen(pGso, iSeg, cSegs, (uint32_t)cbFrame); + + /* + * Check assumptions (doing it after declaring the variables because of C). + */ + Assert(iSeg < cSegs); + Assert(cSegs == PDMNetGsoCalcSegmentCount(pGso, cbFrame)); + Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame)); + + /* + * Copy the header and do the protocol specific massaging of it. + */ + memcpy(pbSegHdrs, pbFrame, pGso->cbHdrsTotal); /* include UDP header */ + + switch ((PDMNETWORKGSOTYPE)pGso->u8Type) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, cbSegHdrs), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + cbSegHdrs, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_UDP: + if (iSeg == 0) + { + /* uh_ulen shall not exceed cbFrame - pGso->offHdr2 (offset of UDP header) */ + PRTNETUDP pUdpHdr = (PRTNETUDP)&pbFrame[pGso->offHdr2]; + Assert(pGso->offHdr2 + RT_UOFFSET_AFTER(RTNETUDP, uh_ulen) <= cbFrame); + if ((unsigned)(pGso->offHdr2 + RT_BE2H_U16(pUdpHdr->uh_ulen)) > cbFrame) + { + size_t cbUdp = cbFrame - pGso->offHdr2; + if (cbUdp >= UINT16_MAX) + pUdpHdr->uh_ulen = UINT16_MAX; + else + pUdpHdr->uh_ulen = RT_H2BE_U16((uint16_t)cbUdp); + } + /* uh_ulen shall be at least the size of UDP header */ + if (RT_BE2H_U16(pUdpHdr->uh_ulen) < sizeof(RTNETUDP)) + pUdpHdr->uh_ulen = RT_H2BE_U16(sizeof(RTNETUDP)); + pdmNetGsoUpdateUdpHdrUfo(RTNetIPv4PseudoChecksum((PRTNETIPV4)&pbFrame[pGso->offHdr1]), + pbSegHdrs, pbFrame, pGso->offHdr2); + } + pdmNetGsoUpdateIPv4HdrUfo(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg * pGso->cbMaxSeg, + cbSegHdrs, iSeg + 1 == cSegs); + break; + case PDMNETWORKGSOTYPE_IPV6_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, cbSegHdrs, + pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + cbSegHdrs, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV6_UDP: + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, cbSegHdrs, + pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, cbSegHdrs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: + pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, cbSegHdrs); + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1), + cbSegPayload, cbSegHdrs, pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + cbSegHdrs, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, cbSegHdrs); + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1), + cbSegPayload, cbSegHdrs, pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, cbSegHdrs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_INVALID: + case PDMNETWORKGSOTYPE_END: + /* no default! wnat gcc warnings. */ + break; + } + + *pcbSegHdrs = cbSegHdrs; + *pcbSegPayload = cbSegPayload; + return cbSegHdrs + iSeg * pGso->cbMaxSeg; +} + + +/** + * Prepares the GSO frame for direct use without any segmenting. + * + * @param pGso The GSO context. + * @param pvFrame The frame to prepare. + * @param cbFrame The frame size. + * @param enmCsumType Whether to checksum the payload, the pseudo + * header or nothing. + */ +DECLINLINE(void) PDMNetGsoPrepForDirectUse(PCPDMNETWORKGSO pGso, void *pvFrame, size_t cbFrame, PDMNETCSUMTYPE enmCsumType) +{ + /* + * Figure out where the payload is and where the header starts before we + * do the protocol bits. + */ + uint8_t * const pbHdrs = (uint8_t *)pvFrame; + uint8_t * const pbPayload = pbHdrs + pGso->cbHdrsTotal; + uint32_t const cbFrame32 = (uint32_t)cbFrame; + uint32_t const cbPayload = cbFrame32 - pGso->cbHdrsTotal; + + /* + * Check assumptions (doing it after declaring the variables because of C). + */ + Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame)); + + /* + * Get down to busienss. + */ + switch ((PDMNETWORKGSOTYPE)pGso->u8Type) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv4Hdr(pbHdrs, pGso->offHdr1, cbFrame32 - pGso->cbHdrsTotal, 0, pGso->cbHdrsTotal), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, 0, pGso->cbHdrsTotal, true, enmCsumType); + break; + case PDMNETWORKGSOTYPE_IPV4_UDP: + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv4Hdr(pbHdrs, pGso->offHdr1, cbFrame32 - pGso->cbHdrsTotal, 0, pGso->cbHdrsTotal), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, pGso->cbHdrsTotal, enmCsumType); + break; + case PDMNETWORKGSOTYPE_IPV6_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbHdrs, pGso->offHdr1, cbPayload, pGso->cbHdrsTotal, + pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, 0, pGso->cbHdrsTotal, true, enmCsumType); + break; + case PDMNETWORKGSOTYPE_IPV6_UDP: + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbHdrs, pGso->offHdr1, cbPayload, pGso->cbHdrsTotal, + pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, pGso->cbHdrsTotal, enmCsumType); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: + pdmNetGsoUpdateIPv4Hdr(pbHdrs, pGso->offHdr1, cbPayload, 0, pGso->cbHdrsTotal); + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbHdrs, pgmNetGsoCalcIpv6Offset(pbHdrs, pGso->offHdr1), + cbPayload, pGso->cbHdrsTotal, pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, 0, pGso->cbHdrsTotal, true, enmCsumType); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + pdmNetGsoUpdateIPv4Hdr(pbHdrs, pGso->offHdr1, cbPayload, 0, pGso->cbHdrsTotal); + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbHdrs, pgmNetGsoCalcIpv6Offset(pbHdrs, pGso->offHdr1), + cbPayload, pGso->cbHdrsTotal, pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, pGso->cbHdrsTotal, enmCsumType); + break; + case PDMNETWORKGSOTYPE_INVALID: + case PDMNETWORKGSOTYPE_END: + /* no default! wnat gcc warnings. */ + break; + } +} + + +/** + * Gets the GSO type name string. + * + * @returns Pointer to read only name string. + * @param enmType The type. + */ +DECLINLINE(const char *) PDMNetGsoTypeName(PDMNETWORKGSOTYPE enmType) +{ + switch (enmType) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: return "TCPv4"; + case PDMNETWORKGSOTYPE_IPV6_TCP: return "TCPv6"; + case PDMNETWORKGSOTYPE_IPV4_UDP: return "UDPv4"; + case PDMNETWORKGSOTYPE_IPV6_UDP: return "UDPv6"; + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: return "4to6TCP"; + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: return "4to6UDP"; + case PDMNETWORKGSOTYPE_INVALID: return "invalid"; + case PDMNETWORKGSOTYPE_END: return "end"; + } + return "bad-gso-type"; +} + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmnetinline_h */ + diff --git a/include/VBox/vmm/pdmnetshaper.h b/include/VBox/vmm/pdmnetshaper.h new file mode 100644 index 00000000..dc6932bd --- /dev/null +++ b/include/VBox/vmm/pdmnetshaper.h @@ -0,0 +1,93 @@ +/** @file + * PDM - Pluggable Device Manager, Network Shaper. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmnetshaper_h +#define VBOX_INCLUDED_vmm_pdmnetshaper_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/pdmnetifs.h> +#include <iprt/list.h> +#include <iprt/sg.h> + + +/** @defgroup grp_pdm_net_shaper The PDM Network Shaper API + * @ingroup grp_pdm + * @{ + */ + + +#define PDM_NETSHAPER_MIN_BUCKET_SIZE UINT32_C(65536) /**< bytes */ +#define PDM_NETSHAPER_MAX_LATENCY UINT32_C(100) /**< milliseconds */ + +RT_C_DECLS_BEGIN + +/** + * A network shaper filter entry. + * + * This is used by DrvNetShaper and any similar drivers. + */ +typedef struct PDMNSFILTER +{ + /** Entry in the group's filter list. + * Both members are NULL when not associated with a group. */ + RTLISTNODER3 ListEntry; + /** The group index + 1. + * @note For safety reasons the value zero is invalid and this is 1-based + * (like pascal) rather than 0-based indexing. + * @note Volatile to prevent re-reading after validation. */ + uint32_t volatile iGroup; + /** Set when the filter fails to obtain bandwidth. + * This will then cause pIDrvNetR3 to be called before long. */ + bool fChoked; + /** Aligment padding. */ + bool afPadding[3]; + /** The driver this filter is aggregated into (ring-3). */ + R3PTRTYPE(PPDMINETWORKDOWN) pIDrvNetR3; +} PDMNSFILTER; + +VMM_INT_DECL(bool) PDMNetShaperAllocateBandwidth(PVMCC pVM, PPDMNSFILTER pFilter, size_t cbTransfer); +VMMR3_INT_DECL(int) PDMR3NsAttach(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, PPDMNSFILTER pFilter); +VMMR3_INT_DECL(int) PDMR3NsDetach(PVM pVM, PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter); +VMMR3DECL(int) PDMR3NsBwGroupSetLimit(PUVM pUVM, const char *pszName, uint64_t cbPerSecMax); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmnetshaper_h */ + diff --git a/include/VBox/vmm/pdmpci.h b/include/VBox/vmm/pdmpci.h new file mode 100644 index 00000000..61493eb8 --- /dev/null +++ b/include/VBox/vmm/pdmpci.h @@ -0,0 +1,408 @@ +/** @file + * PDM - Pluggable Device Manager, raw PCI Devices. (VMM) + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmpci_h +#define VBOX_INCLUDED_vmm_pdmpci_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/rawpci.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_pciraw The raw PCI Devices API + * @ingroup grp_pdm + * @{ + */ + +typedef struct PDMIPCIRAW *PPDMIPCIRAW; +typedef struct PDMIPCIRAW +{ + /** + * Notify virtual device that interrupt has arrived. + * For this callback to be called, interface have to be + * registered with PDMIPCIRAWUP::pfnRegisterInterruptListener. + * + * @note no level parameter, as we can only support flip-flop. + * + * @param pInterface Pointer to this interface structure. + * @param iGuestIrq Guest interrupt number, passed earlier when registering listener. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnInterruptRequest,(PPDMIPCIRAW pInterface, int32_t iGuestIrq)); +} PDMIPCIRAW; + +typedef struct PDMIPCIRAWUP *PPDMIPCIRAWUP; +typedef struct PDMIPCIRAWUP +{ + /** + * Host PCI MMIO access function. + */ + + /** + * Request driver info about PCI region on host PCI device. + * + * @returns true, if region is present, and out parameters are correct + * @param pInterface Pointer to this interface structure. + * @param iRegion Region number. + * @param pGCPhysRegion Where to store region base address (guest). + * @param pcbRegion Where to store region size. + * + * @param pfFlags If region is MMIO or IO. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnGetRegionInfo, (PPDMIPCIRAWUP pInterface, + uint32_t iRegion, + RTGCPHYS *pGCPhysRegion, + uint64_t *pcbRegion, + uint32_t *pfFlags)); + + /** + * Request driver to map part of host device's MMIO region to the VM process and maybe kernel. + * Shall only be issued within earlier obtained with pfnGetRegionInfo() + * host physical address ranges for the device BARs. Even if failed, device still may function + * using pfnMmio* and pfnPio* operations, just much slower. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param iRegion Number of the region. + * @param StartAddress Host physical address of start. + * @param cbRegion Size of the region. + * @param fFlags Flags, currently lowest significant bit set if R0 mapping requested too + * @param ppvAddressR3 Where to store mapped region address for R3 (can be 0, if cannot map into userland) + * @param ppvAddressR0 Where to store mapped region address for R0 (can be 0, if cannot map into kernel) + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnMapRegion, (PPDMIPCIRAWUP pInterface, + uint32_t iRegion, + RTHCPHYS StartAddress, + uint64_t cbRegion, + uint32_t fFlags, + PRTR3PTR ppvAddressR3, + PRTR0PTR ppvAddressR0)); + + /** + * Request driver to unmap part of host device's MMIO region to the VM process. + * Shall only be issued with pointer earlier obtained with pfnMapRegion(). + * + * @returns status code + * @param pInterface Pointer to this interface structure + * @param iRegion Number of the region. + * @param StartAddress Host physical address of start. + * @param cbRegion Size of the region. + * @param pvAddressR3 R3 address of mapped region. + * @param pvAddressR0 R0 address of mapped region. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnUnmapRegion, (PPDMIPCIRAWUP pInterface, + uint32_t iRegion, + RTHCPHYS StartAddress, + uint64_t cbRegion, + RTR3PTR pvAddressR3, + RTR0PTR pvAddressR0)); + + /** + * Request port IO write. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param uPort I/O port address. + * @param uValue Value to write. + * @param cb Access width. + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPioWrite, (PPDMIPCIRAWUP pInterface, + RTIOPORT uPort, + uint32_t uValue, + unsigned cb)); + + /** + * Request port IO read. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param uPort I/O port address. + * @param puValue Place to store read value. + * @param cb Access width. + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPioRead, (PPDMIPCIRAWUP pInterface, + RTIOPORT uPort, + uint32_t *puValue, + unsigned cb)); + + + /** + * Request MMIO write. + * + * This callback is only called if driver wants to receive MMIO via pu32Flags + * argument of pfnPciDeviceConstructStart(). + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param Address Guest physical address. + * @param pvValue Address of value to write. + * @param cb Access width. + * + * @todo Why is this @a Address documented as guest physical + * address and given a host ring-0 address type? + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioWrite, (PPDMIPCIRAWUP pInterface, + RTR0PTR Address, + void const *pvValue, + unsigned cb)); + + /** + * Request MMIO read. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param Address Guest physical address. + * @param pvValue Place to store read value. + * @param cb Access width. + * + * @todo Why is this @a Address documented as guest physical + * address and given a host ring-0 address type? + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioRead, (PPDMIPCIRAWUP pInterface, + RTR0PTR Address, + void *pvValue, + unsigned cb)); + + /** + * Host PCI config space accessors. + */ + /** + * Request driver to write value to host device's PCI config space. + * Host specific way (PIO or MCFG) is used to perform actual operation. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param offCfgSpace Offset in PCI config space. + * @param pvValue Value to write. + * @param cb Access width. + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciCfgWrite, (PPDMIPCIRAWUP pInterface, + uint32_t offCfgSpace, + void *pvValue, + unsigned cb)); + /** + * Request driver to read value from host device's PCI config space. + * Host specific way (PIO or MCFG) is used to perform actual operation. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param offCfgSpace Offset in PCI config space. + * @param pvValue Where to store read value. + * @param cb Access width. + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciCfgRead, (PPDMIPCIRAWUP pInterface, + uint32_t offCfgSpace, + void *pvValue, + unsigned cb)); + + /** + * Request to enable interrupt notifications. Please note that this is purely + * R3 interface, so it's up to implementor to perform necessary machinery + * for communications with host OS kernel driver. Typical implementation will start + * userland thread waiting on shared semaphore (such as using SUPSEMEVENT), + * notified by the kernel interrupt handler, and then will call + * upper port pfnInterruptRequest() based on data provided by the driver. + * This apporach is taken, as calling VBox code from an asyncronous R0 + * interrupt handler when VMM may not be even running doesn't look + * like a good idea. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param uGuestIrq Guest IRQ to be passed to pfnInterruptRequest(). + * + * @thread Any thread, pfnInterruptRequest() will be usually invoked on a dedicated thread. + */ + DECLR3CALLBACKMEMBER(int, pfnEnableInterruptNotifications, (PPDMIPCIRAWUP pInterface, uint8_t uGuestIrq)); + + /** + * Request to disable interrupt notifications. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnDisableInterruptNotifications, (PPDMIPCIRAWUP pInterface)); + + /** @name Notification APIs. + * @{ + */ + + /** + * Notify driver when raw PCI device construction starts. + * + * Have to be the first operation as initializes internal state and opens host + * device driver. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param uHostPciAddress Host PCI address of device attached. + * @param uGuestPciAddress Guest PCI address of device attached. + * @param pszDeviceName Human readable device name. + * @param fDeviceFlags Flags for the host device. + * @param pfFlags Flags for virtual device, from the upper driver. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciDeviceConstructStart, (PPDMIPCIRAWUP pInterface, + uint32_t uHostPciAddress, + uint32_t uGuestPciAddress, + const char *pszDeviceName, + uint32_t fDeviceFlags, + uint32_t *pfFlags)); + + /** + * Notify driver when raw PCI device construction completes, so that it may + * perform further actions depending on success or failure of this operation. + * Standard action is to raise global IHostPciDevicePlugEvent. + * + * @param pInterface Pointer to this interface structure. + * @param rc Result code of the operation. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(void, pfnPciDeviceConstructComplete, (PPDMIPCIRAWUP pInterface, int rc)); + + /** + * Notify driver on finalization of raw PCI device. + * + * @param pInterface Pointer to this interface structure. + * @param fFlags Flags. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciDeviceDestruct, (PPDMIPCIRAWUP pInterface, uint32_t fFlags)); + + /** + * Notify driver on guest power state change. + * + * @param pInterface Pointer to this interface structure. + * @param enmState New power state. + * @param pu64Param State-specific in/out parameter. For now only used during power-on to provide VM caps. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciDevicePowerStateChange, (PPDMIPCIRAWUP pInterface, + PCIRAWPOWERSTATE enmState, + uint64_t *pu64Param)); + + /** + * Notify driver about runtime error. + * + * @param pInterface Pointer to this interface structure. + * @param fFatal If error is fatal. + * @param pszErrorId Error ID. + * @param pszMessage Error message. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnReportRuntimeError, (PPDMIPCIRAWUP pInterface, + bool fFatal, + const char *pszErrorId, + const char *pszMessage)); + /** @} */ +} PDMIPCIRAWUP; + +/** + * Init R0 PCI module. + */ +PCIRAWR0DECL(int) PciRawR0Init(void); +/** + * Process request (in R0). + */ +PCIRAWR0DECL(int) PciRawR0ProcessReq(PGVM pGVM, PSUPDRVSESSION pSession, PPCIRAWSENDREQ pReq); +/** + * Terminate R0 PCI module. + */ +PCIRAWR0DECL(void) PciRawR0Term(void); + +/** + * Per-VM R0 module init. + */ +PCIRAWR0DECL(int) PciRawR0InitVM(PGVM pGVM); + +/** + * Per-VM R0 module termination routine. + */ +PCIRAWR0DECL(void) PciRawR0TermVM(PGVM pGVM); + +/** + * Flags returned by pfnPciDeviceConstructStart(), to notify device + * how it shall handle device IO traffic. + */ +typedef enum PCIRAWDEVICEFLAGS +{ + /** Intercept port IO (R3 PIO always go to the driver). */ + PCIRAWRFLAG_CAPTURE_PIO = (1 << 0), + /** Intercept MMIO. */ + PCIRAWRFLAG_CAPTURE_MMIO = (1 << 1), + /** Allow bus mastering by physical device (requires IOMMU). */ + PCIRAWRFLAG_ALLOW_BM = (1 << 2), + /** Allow R3 MMIO mapping. */ + PCIRAWRFLAG_ALLOW_R3MAP = (1 << 3), + + /** The usual 32-bit type blow up. */ + PCIRAWRFLAG_32BIT_HACK = 0x7fffffff +} PCIRAWDEVICEFLAGS; + +#define PDMIPCIRAWUP_IID "06daa17f-097b-4ebe-a626-15f467b1de12" +#define PDMIPCIRAW_IID "68c6e4c4-4223-47e0-9134-e3c297992543" + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmpci_h */ diff --git a/include/VBox/vmm/pdmpcidev.h b/include/VBox/vmm/pdmpcidev.h new file mode 100644 index 00000000..077c5525 --- /dev/null +++ b/include/VBox/vmm/pdmpcidev.h @@ -0,0 +1,803 @@ +/** @file + * PCI - The PCI Controller And Devices. (DEV) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmpcidev_h +#define VBOX_INCLUDED_vmm_pdmpcidev_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/pci.h> +#include <iprt/assert.h> + + +/** @defgroup grp_pdm_pcidev PDM PCI Device + * @ingroup grp_pdm_device + * @{ + */ + +/** + * Callback function for intercept reading from the PCI configuration space. + * + * @returns VINF_SUCCESS or PDMDevHlpDBGFStop status (maybe others later). + * @retval VINF_PDM_PCI_DO_DEFAULT to do default read (same as calling + * PDMDevHlpPCIConfigRead()). + * + * @param pDevIns Pointer to the device instance the PCI device + * belongs to. + * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance. + * @param uAddress The configuration space register address. [0..4096] + * @param cb The register size. [1,2,4] + * @param pu32Value Where to return the register value. + * + * @remarks Called with the PDM lock held. The device lock is NOT take because + * that is very likely be a lock order violation. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPCICONFIGREAD,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t *pu32Value)); +/** Pointer to a FNPCICONFIGREAD() function. */ +typedef FNPCICONFIGREAD *PFNPCICONFIGREAD; +#if !RT_CLANG_PREREQ(11, 0) /* Clang 11 (at least) has trouble with nothrow and pointers to function pointers. */ +/** Pointer to a PFNPCICONFIGREAD. */ +typedef PFNPCICONFIGREAD *PPFNPCICONFIGREAD; +#endif + +/** + * Callback function for writing to the PCI configuration space. + * + * @returns VINF_SUCCESS or PDMDevHlpDBGFStop status (maybe others later). + * @retval VINF_PDM_PCI_DO_DEFAULT to do default read (same as calling + * PDMDevHlpPCIConfigWrite()). + * + * @param pDevIns Pointer to the device instance the PCI device + * belongs to. + * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance. + * @param uAddress The configuration space register address. [0..4096] + * @param cb The register size. [1,2,4] + * @param u32Value The value that's being written. The number of bits actually used from + * this value is determined by the cb parameter. + * + * @remarks Called with the PDM lock held. The device lock is NOT take because + * that is very likely be a lock order violation. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPCICONFIGWRITE,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t u32Value)); +/** Pointer to a FNPCICONFIGWRITE() function. */ +typedef FNPCICONFIGWRITE *PFNPCICONFIGWRITE; +#if !RT_CLANG_PREREQ(11, 0) /* Clang 11 (at least) has trouble with nothrow and pointers to function pointers. */ +/** Pointer to a PFNPCICONFIGWRITE. */ +typedef PFNPCICONFIGWRITE *PPFNPCICONFIGWRITE; +#endif + +/** + * Callback function for mapping an PCI I/O region. + * + * This is called when a PCI I/O region is mapped, and for new-style devices + * also when unmapped (address set to NIL_RTGCPHYS). For new-style devices, + * this callback is optional as the PCI bus calls IOM to map and unmap the + * regions. + * + * Old style devices have to call IOM to map the region themselves, while + * unmapping is done by the PCI bus like with the new style devices. + * + * @returns VBox status code. + * @retval VINF_PCI_MAPPING_DONE if the caller already did the mapping and the + * PCI bus should not use the handle it got to do the registration + * again. (Only allowed when @a GCPhysAddress is not NIL_RTGCPHYS.) + * + * @param pDevIns Pointer to the device instance the PCI device + * belongs to. + * @param pPciDev Pointer to the PCI device. + * @param iRegion The region number. + * @param GCPhysAddress Physical address of the region. If @a enmType is + * PCI_ADDRESS_SPACE_IO, this is an I/O port, otherwise + * it's a physical address. + * + * NIL_RTGCPHYS indicates that a mapping is about to be + * unmapped and that the device deregister access + * handlers for it and update its internal state to + * reflect this. + * + * @param cb Size of the region in bytes. + * @param enmType One of the PCI_ADDRESS_SPACE_* values. + * + * @remarks Called with the PDM lock held. The device lock is NOT take because + * that is very likely be a lock order violation. + */ +typedef DECLCALLBACKTYPE(int, FNPCIIOREGIONMAP,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, + RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)); +/** Pointer to a FNPCIIOREGIONMAP() function. */ +typedef FNPCIIOREGIONMAP *PFNPCIIOREGIONMAP; + + +/** + * Sets the size and type for old saved states from within a + * PDMPCIDEV::pfnRegionLoadChangeHookR3 callback. + * + * @returns VBox status code. + * @param pPciDev Pointer to the PCI device. + * @param iRegion The region number. + * @param cbRegion The region size. + * @param enmType Combination of the PCI_ADDRESS_SPACE_* values. + */ +typedef DECLCALLBACKTYPE(int, FNPCIIOREGIONOLDSETTER,(PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cbRegion, + PCIADDRESSSPACE enmType)); +/** Pointer to a FNPCIIOREGIONOLDSETTER() function. */ +typedef FNPCIIOREGIONOLDSETTER *PFNPCIIOREGIONOLDSETTER; + +/** + * Swaps two PCI I/O regions from within a PDMPCIDEV::pfnRegionLoadChangeHookR3 + * callback. + * + * @returns VBox status code. + * @param pPciDev Pointer to the PCI device. + * @param iRegion The region number. + * @param iOtherRegion The number of the region swap with. + * @sa @bugref{9359} + */ +typedef DECLCALLBACKTYPE(int, FNPCIIOREGIONSWAP,(PPDMPCIDEV pPciDev, uint32_t iRegion, uint32_t iOtherRegion)); +/** Pointer to a FNPCIIOREGIONSWAP() function. */ +typedef FNPCIIOREGIONSWAP *PFNPCIIOREGIONSWAP; + + +/* + * Hack to include the PDMPCIDEVINT structure at the right place + * to avoid duplications of FNPCIIOREGIONMAP and such. + */ +#ifdef PDMPCIDEV_INCLUDE_PRIVATE +# include "pdmpcidevint.h" +#endif + +/** + * PDM PCI Device structure. + * + * A PCI device belongs to a PDM device. A PDM device may have zero or more PCI + * devices associated with it. The first PCI device that it registers + * automatically becomes the default PCI device and can be used implicitly + * with the device helper APIs. Subsequent PCI devices must be specified + * explicitly to the device helper APIs when used. + */ +typedef struct PDMPCIDEV +{ + /** @name Read only data. + * @{ + */ + /** Magic number (PDMPCIDEV_MAGIC). */ + uint32_t u32Magic; + /** PCI device number [11:3] and function [2:0] on the pci bus. + * @sa VBOX_PCI_DEVFN_MAKE, VBOX_PCI_DEVFN_FUN_MASK, VBOX_PCI_DEVFN_DEV_SHIFT */ + uint32_t uDevFn; + /** Size of the valid config space (we always allocate 4KB). */ + uint16_t cbConfig; + /** Size of the MSI-X state data optionally following the config space. */ + uint16_t cbMsixState; + /** Index into the PDMDEVINS::apPciDev array. */ + uint16_t idxSubDev; + uint16_t u16Padding; + /** Device name. */ + R3PTRTYPE(const char *) pszNameR3; + /** @} */ + + /** + * Callback for dealing with size changes. + * + * This is set by the PCI device when needed. It is only needed if any changes + * in the PCI resources have been made that may be incompatible with saved state + * (i.e. does not reflect configuration, but configuration defaults changed). + * + * The implementation can use PDMDevHlpMMIOExReduce to adjust the resource + * allocation down in size. There is currently no way of growing resources. + * Dropping a resource is automatic. + * + * @returns VBox status code. + * @param pDevIns Pointer to the device instance the PCI device + * belongs to. + * @param pPciDev Pointer to the PCI device. + * @param iRegion The region number or UINT32_MAX if old saved state call. + * @param cbRegion The size being loaded, RTGCPHYS_MAX if old saved state + * call, or 0 for dummy 64-bit top half region. + * @param enmType The type being loaded, -1 if old saved state call, or + * 0xff if dummy 64-bit top half region. + * @param pfnOldSetter Callback for setting size and type for call + * regarding old saved states. NULL otherwise. + * @param pfnSwapRegions Used to swaps two regions. The second one must be a + * higher number than @a iRegion. NULL if old saved + * state. + */ + DECLR3CALLBACKMEMBER(int, pfnRegionLoadChangeHookR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, + uint64_t cbRegion, PCIADDRESSSPACE enmType, + PFNPCIIOREGIONOLDSETTER pfnOldSetter, + PFNPCIIOREGIONSWAP pfnSwapRegion)); + + /** Reserved for future stuff. */ + uint64_t au64Reserved[4 + (R3_ARCH_BITS == 32 ? 1 : 0)]; + + /** Internal data. */ + union + { +#ifdef PDMPCIDEVINT_DECLARED + PDMPCIDEVINT s; +#endif + uint8_t padding[0x180]; + } Int; + + /** PCI config space. + * This is either 256 or 4096 in size. In the latter case it may be + * followed by a MSI-X state area. */ + uint8_t abConfig[4096]; + /** The MSI-X state data. Optional. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abMsixState[RT_FLEXIBLE_ARRAY]; +} PDMPCIDEV; +#ifdef PDMPCIDEVINT_DECLARED +AssertCompile(RT_SIZEOFMEMB(PDMPCIDEV, Int.s) <= RT_SIZEOFMEMB(PDMPCIDEV, Int.padding)); +#endif +/** Magic number of PDMPCIDEV::u32Magic (Margaret Eleanor Atwood). */ +#define PDMPCIDEV_MAGIC UINT32_C(0x19391118) + +/** Checks that the PCI device structure is valid and belongs to the device + * instance, but does not return. */ +#ifdef VBOX_STRICT +# define PDMPCIDEV_ASSERT_VALID(a_pDevIns, a_pPciDev) \ + do { \ + uintptr_t const offPciDevInTable = (uintptr_t)(a_pPciDev) - (uintptr_t)pDevIns->apPciDevs[0]; \ + uint32_t const cbPciDevTmp = pDevIns->cbPciDev; \ + ASMCompilerBarrier(); \ + AssertMsg( offPciDevInTable < pDevIns->cPciDevs * cbPciDevTmp \ + && cbPciDevTmp >= RT_UOFFSETOF(PDMPCIDEV, abConfig) + 256 \ + && offPciDevInTable % cbPciDevTmp == 0, \ + ("pPciDev=%p apPciDevs[0]=%p offPciDevInTable=%p cPciDevs=%#x cbPciDev=%#x\n", \ + (a_pPciDev), pDevIns->apPciDevs[0], offPciDevInTable, pDevIns->cPciDevs, cbPciDevTmp)); \ + AssertPtr((a_pPciDev)); \ + AssertMsg((a_pPciDev)->u32Magic == PDMPCIDEV_MAGIC, ("%#x\n", (a_pPciDev)->u32Magic)); \ + } while (0) +#else +# define PDMPCIDEV_ASSERT_VALID(a_pDevIns, a_pPciDev) do { } while (0) +#endif + +/** Checks that the PCI device structure is valid, belongs to the device + * instance and that it is registered, but does not return. */ +#ifdef VBOX_STRICT +# define PDMPCIDEV_ASSERT_VALID_AND_REGISTERED(a_pDevIns, a_pPciDev) \ + do { \ + PDMPCIDEV_ASSERT_VALID(a_pDevIns, a_pPciDev); \ + Assert((a_pPciDev)->Int.s.fRegistered); \ + } while (0) +#else +# define PDMPCIDEV_ASSERT_VALID_AND_REGISTERED(a_pDevIns, a_pPciDev) do { } while (0) +#endif + +/** Checks that the PCI device structure is valid and belongs to the device + * instance, returns appropriate status code if not valid. */ +#define PDMPCIDEV_ASSERT_VALID_RET(a_pDevIns, a_pPciDev) \ + do { \ + uintptr_t const offPciDevInTable = (uintptr_t)(a_pPciDev) - (uintptr_t)pDevIns->apPciDevs[0]; \ + uint32_t const cbPciDevTmp = pDevIns->cbPciDev; \ + ASMCompilerBarrier(); \ + AssertMsgReturn( offPciDevInTable < pDevIns->cPciDevs * cbPciDevTmp \ + && cbPciDevTmp >= RT_UOFFSETOF(PDMPCIDEV, abConfig) + 256 \ + && offPciDevInTable % cbPciDevTmp == 0, \ + ("pPciDev=%p apPciDevs[0]=%p offPciDevInTable=%p cPciDevs=%#x cbPciDev=%#x\n", \ + (a_pPciDev), pDevIns->apPciDevs[0], offPciDevInTable, pDevIns->cPciDevs, cbPciDevTmp), \ + VERR_PDM_NOT_PCI_DEVICE); \ + AssertMsgReturn((a_pPciDev)->u32Magic == PDMPCIDEV_MAGIC, ("%#x\n", (a_pPciDev)->u32Magic), VERR_PDM_NOT_PCI_DEVICE); \ + AssertReturn((a_pPciDev)->Int.s.fRegistered, VERR_PDM_NOT_PCI_DEVICE); \ + } while (0) + + + +/** @name PDM PCI config space accessor function. + * @{ + */ + +/** @todo handle extended space access. */ + +DECLINLINE(void) PDMPciDevSetByte(PPDMPCIDEV pPciDev, uint32_t offReg, uint8_t u8Value) +{ + Assert(offReg < sizeof(pPciDev->abConfig)); + pPciDev->abConfig[offReg] = u8Value; +} + +DECLINLINE(uint8_t) PDMPciDevGetByte(PCPDMPCIDEV pPciDev, uint32_t offReg) +{ + Assert(offReg < sizeof(pPciDev->abConfig)); + return pPciDev->abConfig[offReg]; +} + +DECLINLINE(void) PDMPciDevSetWord(PPDMPCIDEV pPciDev, uint32_t offReg, uint16_t u16Value) +{ + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint16_t)); + *(uint16_t*)&pPciDev->abConfig[offReg] = RT_H2LE_U16(u16Value); +} + +DECLINLINE(uint16_t) PDMPciDevGetWord(PCPDMPCIDEV pPciDev, uint32_t offReg) +{ + uint16_t u16Value; + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint16_t)); + u16Value = *(uint16_t*)&pPciDev->abConfig[offReg]; + return RT_H2LE_U16(u16Value); +} + +DECLINLINE(void) PDMPciDevSetDWord(PPDMPCIDEV pPciDev, uint32_t offReg, uint32_t u32Value) +{ + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint32_t)); + *(uint32_t*)&pPciDev->abConfig[offReg] = RT_H2LE_U32(u32Value); +} + +DECLINLINE(uint32_t) PDMPciDevGetDWord(PCPDMPCIDEV pPciDev, uint32_t offReg) +{ + uint32_t u32Value; + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint32_t)); + u32Value = *(uint32_t*)&pPciDev->abConfig[offReg]; + return RT_H2LE_U32(u32Value); +} + +DECLINLINE(void) PDMPciDevSetQWord(PPDMPCIDEV pPciDev, uint32_t offReg, uint64_t u64Value) +{ + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint64_t)); + *(uint64_t*)&pPciDev->abConfig[offReg] = RT_H2LE_U64(u64Value); +} + +DECLINLINE(uint64_t) PDMPciDevGetQWord(PCPDMPCIDEV pPciDev, uint32_t offReg) +{ + uint64_t u64Value; + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint64_t)); + u64Value = *(uint64_t*)&pPciDev->abConfig[offReg]; + return RT_H2LE_U64(u64Value); +} + +/** + * Sets the vendor id config register. + * @param pPciDev The PCI device. + * @param u16VendorId The vendor id. + */ +DECLINLINE(void) PDMPciDevSetVendorId(PPDMPCIDEV pPciDev, uint16_t u16VendorId) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_VENDOR_ID, u16VendorId); +} + +/** + * Gets the vendor id config register. + * @returns the vendor id. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetVendorId(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_VENDOR_ID); +} + + +/** + * Sets the device id config register. + * @param pPciDev The PCI device. + * @param u16DeviceId The device id. + */ +DECLINLINE(void) PDMPciDevSetDeviceId(PPDMPCIDEV pPciDev, uint16_t u16DeviceId) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_DEVICE_ID, u16DeviceId); +} + +/** + * Gets the device id config register. + * @returns the device id. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetDeviceId(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_DEVICE_ID); +} + +/** + * Sets the command config register. + * + * @param pPciDev The PCI device. + * @param u16Command The command register value. + */ +DECLINLINE(void) PDMPciDevSetCommand(PPDMPCIDEV pPciDev, uint16_t u16Command) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_COMMAND, u16Command); +} + + +/** + * Gets the command config register. + * @returns The command register value. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetCommand(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_COMMAND); +} + +/** + * Checks if the given PCI device is a bus master. + * @returns true if the device is a bus master, false if not. + * @param pPciDev The PCI device. + */ +DECLINLINE(bool) PDMPciDevIsBusmaster(PCPDMPCIDEV pPciDev) +{ + return (PDMPciDevGetCommand(pPciDev) & VBOX_PCI_COMMAND_MASTER) != 0; +} + +/** + * Checks if INTx interrupts disabled in the command config register. + * @returns true if disabled. + * @param pPciDev The PCI device. + */ +DECLINLINE(bool) PDMPciDevIsIntxDisabled(PCPDMPCIDEV pPciDev) +{ + return (PDMPciDevGetCommand(pPciDev) & VBOX_PCI_COMMAND_INTX_DISABLE) != 0; +} + +/** + * Gets the status config register. + * + * @returns status config register. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetStatus(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_STATUS); +} + +/** + * Sets the status config register. + * + * @param pPciDev The PCI device. + * @param u16Status The status register value. + */ +DECLINLINE(void) PDMPciDevSetStatus(PPDMPCIDEV pPciDev, uint16_t u16Status) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_STATUS, u16Status); +} + + +/** + * Sets the revision id config register. + * + * @param pPciDev The PCI device. + * @param u8RevisionId The revision id. + */ +DECLINLINE(void) PDMPciDevSetRevisionId(PPDMPCIDEV pPciDev, uint8_t u8RevisionId) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_REVISION_ID, u8RevisionId); +} + + +/** + * Sets the register level programming class config register. + * + * @param pPciDev The PCI device. + * @param u8ClassProg The new value. + */ +DECLINLINE(void) PDMPciDevSetClassProg(PPDMPCIDEV pPciDev, uint8_t u8ClassProg) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_CLASS_PROG, u8ClassProg); +} + + +/** + * Sets the sub-class (aka device class) config register. + * + * @param pPciDev The PCI device. + * @param u8SubClass The sub-class. + */ +DECLINLINE(void) PDMPciDevSetClassSub(PPDMPCIDEV pPciDev, uint8_t u8SubClass) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_CLASS_SUB, u8SubClass); +} + + +/** + * Sets the base class config register. + * + * @param pPciDev The PCI device. + * @param u8BaseClass The base class. + */ +DECLINLINE(void) PDMPciDevSetClassBase(PPDMPCIDEV pPciDev, uint8_t u8BaseClass) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_CLASS_BASE, u8BaseClass); +} + +/** + * Sets the header type config register. + * + * @param pPciDev The PCI device. + * @param u8HdrType The header type. + */ +DECLINLINE(void) PDMPciDevSetHeaderType(PPDMPCIDEV pPciDev, uint8_t u8HdrType) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_HEADER_TYPE, u8HdrType); +} + +/** + * Gets the header type config register. + * + * @param pPciDev The PCI device. + * @returns u8HdrType The header type. + */ +DECLINLINE(uint8_t) PDMPciDevGetHeaderType(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetByte(pPciDev, VBOX_PCI_HEADER_TYPE); +} + +/** + * Sets the BIST (built-in self-test) config register. + * + * @param pPciDev The PCI device. + * @param u8Bist The BIST value. + */ +DECLINLINE(void) PDMPciDevSetBIST(PPDMPCIDEV pPciDev, uint8_t u8Bist) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_BIST, u8Bist); +} + +/** + * Gets the BIST (built-in self-test) config register. + * + * @param pPciDev The PCI device. + * @returns u8Bist The BIST. + */ +DECLINLINE(uint8_t) PDMPciDevGetBIST(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetByte(pPciDev, VBOX_PCI_BIST); +} + + +/** + * Sets a base address config register. + * + * @param pPciDev The PCI device. + * @param iReg Base address register number (0..5). + * @param fIOSpace Whether it's I/O (true) or memory (false) space. + * @param fPrefetchable Whether the memory is prefetachable. Must be false if fIOSpace == true. + * @param f64Bit Whether the memory can be mapped anywhere in the 64-bit address space. Otherwise restrict to 32-bit. + * @param u32Addr The address value. + */ +DECLINLINE(void) PDMPciDevSetBaseAddress(PPDMPCIDEV pPciDev, uint8_t iReg, bool fIOSpace, bool fPrefetchable, bool f64Bit, + uint32_t u32Addr) +{ + if (fIOSpace) + { + Assert(!(u32Addr & 0x3)); Assert(!fPrefetchable); Assert(!f64Bit); + u32Addr |= RT_BIT_32(0); + } + else + { + Assert(!(u32Addr & 0xf)); + if (fPrefetchable) + u32Addr |= RT_BIT_32(3); + if (f64Bit) + u32Addr |= 0x2 << 1; + } + switch (iReg) + { + case 0: iReg = VBOX_PCI_BASE_ADDRESS_0; break; + case 1: iReg = VBOX_PCI_BASE_ADDRESS_1; break; + case 2: iReg = VBOX_PCI_BASE_ADDRESS_2; break; + case 3: iReg = VBOX_PCI_BASE_ADDRESS_3; break; + case 4: iReg = VBOX_PCI_BASE_ADDRESS_4; break; + case 5: iReg = VBOX_PCI_BASE_ADDRESS_5; break; + default: AssertFailedReturnVoid(); + } + + PDMPciDevSetDWord(pPciDev, iReg, u32Addr); +} + +/** + * Please document me. I don't seem to be getting as much as calculating + * the address of some PCI region. + */ +DECLINLINE(uint32_t) PDMPciDevGetRegionReg(uint32_t iRegion) +{ + return iRegion == VBOX_PCI_ROM_SLOT + ? VBOX_PCI_ROM_ADDRESS : (VBOX_PCI_BASE_ADDRESS_0 + iRegion * 4); +} + +/** + * Sets the sub-system vendor id config register. + * + * @param pPciDev The PCI device. + * @param u16SubSysVendorId The sub-system vendor id. + */ +DECLINLINE(void) PDMPciDevSetSubSystemVendorId(PPDMPCIDEV pPciDev, uint16_t u16SubSysVendorId) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_SUBSYSTEM_VENDOR_ID, u16SubSysVendorId); +} + +/** + * Gets the sub-system vendor id config register. + * @returns the sub-system vendor id. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetSubSystemVendorId(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_SUBSYSTEM_VENDOR_ID); +} + + +/** + * Sets the sub-system id config register. + * + * @param pPciDev The PCI device. + * @param u16SubSystemId The sub-system id. + */ +DECLINLINE(void) PDMPciDevSetSubSystemId(PPDMPCIDEV pPciDev, uint16_t u16SubSystemId) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_SUBSYSTEM_ID, u16SubSystemId); +} + +/** + * Gets the sub-system id config register. + * @returns the sub-system id. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetSubSystemId(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_SUBSYSTEM_ID); +} + +/** + * Sets offset to capability list. + * + * @param pPciDev The PCI device. + * @param u8Offset The offset to capability list. + */ +DECLINLINE(void) PDMPciDevSetCapabilityList(PPDMPCIDEV pPciDev, uint8_t u8Offset) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST, u8Offset); +} + +/** + * Returns offset to capability list. + * + * @returns offset to capability list. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint8_t) PDMPciDevGetCapabilityList(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST); +} + +/** + * Sets the interrupt line config register. + * + * @param pPciDev The PCI device. + * @param u8Line The interrupt line. + */ +DECLINLINE(void) PDMPciDevSetInterruptLine(PPDMPCIDEV pPciDev, uint8_t u8Line) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE, u8Line); +} + +/** + * Gets the interrupt line config register. + * + * @returns The interrupt line. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint8_t) PDMPciDevGetInterruptLine(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE); +} + +/** + * Sets the interrupt pin config register. + * + * @param pPciDev The PCI device. + * @param u8Pin The interrupt pin. + */ +DECLINLINE(void) PDMPciDevSetInterruptPin(PPDMPCIDEV pPciDev, uint8_t u8Pin) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN, u8Pin); +} + +/** + * Gets the interrupt pin config register. + * + * @returns The interrupt pin. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint8_t) PDMPciDevGetInterruptPin(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN); +} + +/** @} */ + +/** @name Aliases for old function names. + * @{ + */ +#if !defined(PDMPCIDEVICE_NO_DEPRECATED) || defined(DOXYGEN_RUNNING) +# define PCIDevSetByte PDMPciDevSetByte +# define PCIDevGetByte PDMPciDevGetByte +# define PCIDevSetWord PDMPciDevSetWord +# define PCIDevGetWord PDMPciDevGetWord +# define PCIDevSetDWord PDMPciDevSetDWord +# define PCIDevGetDWord PDMPciDevGetDWord +# define PCIDevSetQWord PDMPciDevSetQWord +# define PCIDevGetQWord PDMPciDevGetQWord +# define PCIDevSetVendorId PDMPciDevSetVendorId +# define PCIDevGetVendorId PDMPciDevGetVendorId +# define PCIDevSetDeviceId PDMPciDevSetDeviceId +# define PCIDevGetDeviceId PDMPciDevGetDeviceId +# define PCIDevSetCommand PDMPciDevSetCommand +# define PCIDevGetCommand PDMPciDevGetCommand +# define PCIDevIsBusmaster PDMPciDevIsBusmaster +# define PCIDevIsIntxDisabled PDMPciDevIsIntxDisabled +# define PCIDevGetStatus PDMPciDevGetStatus +# define PCIDevSetStatus PDMPciDevSetStatus +# define PCIDevSetRevisionId PDMPciDevSetRevisionId +# define PCIDevSetClassProg PDMPciDevSetClassProg +# define PCIDevSetClassSub PDMPciDevSetClassSub +# define PCIDevSetClassBase PDMPciDevSetClassBase +# define PCIDevSetHeaderType PDMPciDevSetHeaderType +# define PCIDevGetHeaderType PDMPciDevGetHeaderType +# define PCIDevSetBIST PDMPciDevSetBIST +# define PCIDevGetBIST PDMPciDevGetBIST +# define PCIDevSetBaseAddress PDMPciDevSetBaseAddress +# define PCIDevGetRegionReg PDMPciDevGetRegionReg +# define PCIDevSetSubSystemVendorId PDMPciDevSetSubSystemVendorId +# define PCIDevGetSubSystemVendorId PDMPciDevGetSubSystemVendorId +# define PCIDevSetSubSystemId PDMPciDevSetSubSystemId +# define PCIDevGetSubSystemId PDMPciDevGetSubSystemId +# define PCIDevSetCapabilityList PDMPciDevSetCapabilityList +# define PCIDevGetCapabilityList PDMPciDevGetCapabilityList +# define PCIDevSetInterruptLine PDMPciDevSetInterruptLine +# define PCIDevGetInterruptLine PDMPciDevGetInterruptLine +# define PCIDevSetInterruptPin PDMPciDevSetInterruptPin +# define PCIDevGetInterruptPin PDMPciDevGetInterruptPin +#endif +/** @} */ + + +/** @name PDMIICH9BRIDGEPDMPCIDEV_IID - Ugly 3rd party bridge/raw PCI hack. + * + * When querying this IID via IBase::pfnQueryInterface on a ICH9 bridge, you + * will get a pointer to a PDMPCIDEV rather pointer to an interface function + * table as is the custom. This was needed by some unusual 3rd-party raw and/or + * pass-through implementation which need to provide different PCI configuration + * space content for bridges (as long as we don't allow pass-through of bridges + * or custom bridge device implementations). So, HACK ALERT to all of this! + * @{ */ +#define PDMIICH9BRIDGEPDMPCIDEV_IID "785c74b1-8510-4458-9422-56750bf221db" +typedef PPDMPCIDEV PPDMIICH9BRIDGEPDMPCIDEV; +typedef PDMPCIDEV PDMIICH9BRIDGEPDMPCIDEV; +/** @} */ + + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmpcidev_h */ diff --git a/include/VBox/vmm/pdmpcidevint.h b/include/VBox/vmm/pdmpcidevint.h new file mode 100644 index 00000000..b678bf05 --- /dev/null +++ b/include/VBox/vmm/pdmpcidevint.h @@ -0,0 +1,238 @@ +/* $Id: pdmpcidevint.h $ */ +/** @file + * DevPCI - PDM PCI Internal header - Only for hiding bits of PDMPCIDEV. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmpcidevint_h +#define VBOX_INCLUDED_vmm_pdmpcidevint_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/pdmdev.h> + +/** @defgroup grp_pdm_pcidev_int The PDM PCI Device Internals + * @ingroup grp_pdm_pcidev + * + * @remarks The PDM PCI device internals are visible to both PDM and the PCI Bus + * implementation, thus it lives among the the public headers despite + * being rather private and internal. + * + * @{ + */ + + +/** + * PCI I/O region. + */ +typedef struct PCIIOREGION +{ + /** Current PCI mapping address, INVALID_PCI_ADDRESS (0xffffffff) means not mapped. */ + uint64_t addr; + /** The region size. Power of 2. */ + uint64_t size; + /** Handle or UINT64_MAX (see PDMPCIDEV_IORGN_F_HANDLE_MASK in fFlags). */ + uint64_t hHandle; + /** PDMPCIDEV_IORGN_F_XXXX. */ + uint32_t fFlags; + /** PCIADDRESSSPACE */ + uint8_t type; + uint8_t abPadding0[3]; + /** Callback called when the region is mapped or unmapped (new style devs). */ + R3PTRTYPE(PFNPCIIOREGIONMAP) pfnMap; +#if R3_ARCH_BITS == 32 + uint32_t u32Padding2; +#endif +} PCIIOREGION; +AssertCompileSize(PCIIOREGION, 5*8); +/** Pointer to a PCI I/O region. */ +typedef PCIIOREGION *PPCIIOREGION; +/** Pointer to a const PCI I/O region. */ +typedef PCIIOREGION const *PCPCIIOREGION; + +/** + * Callback function for reading from the PCI configuration space. + * + * @returns Strict VBox status code. + * @param pDevIns Pointer to the device instance of the PCI bus. + * @param iBus The bus number this device is on. + * @param iDevice The number of the device on the bus. + * @param u32Address The configuration space register address. [0..255] + * @param cb The register size. [1,2,4] + * @param pu32Value Where to return the register value. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPCIBRIDGECONFIGREAD,(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, + uint32_t u32Address, unsigned cb, uint32_t *pu32Value)); +/** Pointer to a FNPCICONFIGREAD() function. */ +typedef FNPCIBRIDGECONFIGREAD *PFNPCIBRIDGECONFIGREAD; +#if !RT_CLANG_PREREQ(11, 0) /* Clang 11 (at least) has trouble with nothrow and pointers to function pointers. */ +/** Pointer to a PFNPCICONFIGREAD. */ +typedef PFNPCIBRIDGECONFIGREAD *PPFNPCIBRIDGECONFIGREAD; +#endif + +/** + * Callback function for writing to the PCI configuration space. + * + * @returns Strict VBox status code. + * @param pDevIns Pointer to the device instance of the PCI bus. + * @param iBus The bus number this device is on. + * @param iDevice The number of the device on the bus. + * @param u32Address The configuration space register address. [0..255] + * @param cb The register size. [1,2,4] + * @param u32Value The value that's being written. The number of bits actually used from + * this value is determined by the cb parameter. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPCIBRIDGECONFIGWRITE,(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, + uint32_t u32Address, unsigned cb, uint32_t u32Value)); +/** Pointer to a FNPCICONFIGWRITE() function. */ +typedef FNPCIBRIDGECONFIGWRITE *PFNPCIBRIDGECONFIGWRITE; +#if !RT_CLANG_PREREQ(11, 0) /* Clang 11 (at least) has trouble with nothrow and pointers to function pointers. */ +/** Pointer to a PFNPCICONFIGWRITE. */ +typedef PFNPCIBRIDGECONFIGWRITE *PPFNPCIBRIDGECONFIGWRITE; +#endif + +/* Forward declaration */ +struct DEVPCIBUS; + +enum { + /** Flag whether the device is a pci-to-pci bridge. + * This is set prior to device registration. */ + PCIDEV_FLAG_PCI_TO_PCI_BRIDGE = RT_BIT_32(1), + /** Flag whether the device is a PCI Express device. + * This is set prior to device registration. */ + PCIDEV_FLAG_PCI_EXPRESS_DEVICE = RT_BIT_32(2), + /** Flag whether the device is capable of MSI. + * This one is set by MsiInit(). */ + PCIDEV_FLAG_MSI_CAPABLE = RT_BIT_32(3), + /** Flag whether the device is capable of MSI-X. + * This one is set by MsixInit(). */ + PCIDEV_FLAG_MSIX_CAPABLE = RT_BIT_32(4), + /** Flag if device represents real physical device in passthrough mode. */ + PCIDEV_FLAG_PASSTHROUGH = RT_BIT_32(5), + /** Flag whether the device is capable of MSI using 64-bit address. */ + PCIDEV_FLAG_MSI64_CAPABLE = RT_BIT_32(6) + +}; + + +/** + * PDM PCI Device - Internal data. + * + * @sa PDMPCIDEV + */ +typedef struct PDMPCIDEVINT +{ + /** @name Owned by PDM. + * @remarks The bus may use the device instance pointers. + * @{ + */ + /** Pointer to the PDM device the PCI device belongs to. (R3 ptr) */ + PPDMDEVINSR3 pDevInsR3; + /** The CFGM device configuration index (default, PciDev1..255). + * This also works as the internal sub-device ordinal with MMIOEx. + * @note Same value as idxSubDev, can therefore be removed later. */ + uint8_t idxDevCfg; + /** Set if the it can be reassigned to a different PCI device number. */ + bool fReassignableDevNo; + /** Set if the it can be reassigned to a different PCI function number. */ + bool fReassignableFunNo; + /** Alignment padding - used by ICH9 for region swapping (DevVGA hack). */ + uint8_t bPadding0; + /** Index into the PDM internal bus array (PDM::aPciBuses). */ + uint8_t idxPdmBus; + /** Set if this device has been registered. */ + bool fRegistered; + /** Index into PDMDEVINSR3::apPciDevs (same as PDMPCIDEV::idxSubDev). */ + uint16_t idxSubDev; + /** @} */ + + /** @name Owned by the PCI Bus + * @remarks PDM will not touch anything here (includes not relocating anything). + * @{ + */ + /** Pointer to the PCI bus of the device. (R3 ptr) */ + R3PTRTYPE(struct DEVPCIBUS *) pBusR3; + /** Read config callback. */ + R3PTRTYPE(PFNPCICONFIGREAD) pfnConfigRead; + /** Write config callback. */ + R3PTRTYPE(PFNPCICONFIGWRITE) pfnConfigWrite; + /** Read config callback for PCI bridges to pass requests + * to devices on another bus. */ + R3PTRTYPE(PFNPCIBRIDGECONFIGREAD) pfnBridgeConfigRead; + /** Write config callback for PCI bridges to pass requests + * to devices on another bus. */ + R3PTRTYPE(PFNPCIBRIDGECONFIGWRITE) pfnBridgeConfigWrite; + + /** Flags of this PCI device, see PCIDEV_FLAG_XXX constants. */ + uint32_t fFlags; + /** Current state of the IRQ pin of the device. */ + int32_t uIrqPinState; + + /** Offset of MSI PCI capability in config space, or 0. + * @todo fix non-standard naming. */ + uint8_t u8MsiCapOffset; + /** Size of MSI PCI capability in config space, or 0. + * @todo fix non-standard naming. */ + uint8_t u8MsiCapSize; + /** Offset of MSI-X PCI capability in config space, or 0. + * @todo fix non-standard naming. */ + uint8_t u8MsixCapOffset; + /** Size of MSI-X PCI capability in config space, or 0. + * @todo fix non-standard naming. */ + uint8_t u8MsixCapSize; + /** Size of the MSI-X region. */ + uint16_t cbMsixRegion; + /** Offset to the PBA for MSI-X. */ + uint16_t offMsixPba; + /** Add padding to align aIORegions to an 16 byte boundary. */ + uint8_t abPadding2[HC_ARCH_BITS == 32 ? 12 : 8]; + /** The MMIO handle for the MSI-X MMIO bar. */ + IOMMMIOHANDLE hMmioMsix; + + /** Pointer to bus specific data. (R3 ptr) */ + R3PTRTYPE(const void *) pvPciBusPtrR3; + /** I/O regions. */ + PCIIOREGION aIORegions[VBOX_PCI_NUM_REGIONS]; + /** @} */ +} PDMPCIDEVINT; +AssertCompileMemberAlignment(PDMPCIDEVINT, aIORegions, 8); +AssertCompileSize(PDMPCIDEVINT, HC_ARCH_BITS == 32 ? 0x98 : 0x178); + +/** Indicate that PDMPCIDEV::Int.s can be declared. */ +#define PDMPCIDEVINT_DECLARED + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmpcidevint_h */ + diff --git a/include/VBox/vmm/pdmqueue.h b/include/VBox/vmm/pdmqueue.h new file mode 100644 index 00000000..a932ec28 --- /dev/null +++ b/include/VBox/vmm/pdmqueue.h @@ -0,0 +1,169 @@ +/** @file + * PDM - Pluggable Device Manager, Queues. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmqueue_h +#define VBOX_INCLUDED_vmm_pdmqueue_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_queue The PDM Queues API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer to a PDM queue. */ +typedef struct PDMQUEUE *PPDMQUEUE; + +/** Pointer to a PDM queue item core. */ +typedef union PDMQUEUEITEMCORE *PPDMQUEUEITEMCORE; + +/** + * PDM queue item core. + */ +typedef union PDMQUEUEITEMCORE +{ + /** The next queue item on the pending list (UINT32_MAX for NIL). */ + uint32_t volatile iNext; + /** The next item about to be flushed. */ + R3PTRTYPE(PPDMQUEUEITEMCORE) pNext; + /** Make sure the core is 64-bit wide. */ + uint64_t u64View; +} PDMQUEUEITEMCORE; + + +/** + * Queue consumer callback for devices. + * + * @returns Success indicator. + * If false the item will not be removed and the flushing will stop. + * @param pDevIns The device instance. + * @param pItem The item to consume. Upon return this item will be freed. + * @remarks The device critical section will NOT be entered before calling the + * callback. No locks will be held, but for now it's safe to assume + * that only one EMT will do queue callbacks at any one time. + */ +typedef DECLCALLBACKTYPE(bool, FNPDMQUEUEDEV,(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)); +/** Pointer to a FNPDMQUEUEDEV(). */ +typedef FNPDMQUEUEDEV *PFNPDMQUEUEDEV; + +/** + * Queue consumer callback for USB devices. + * + * @returns Success indicator. + * If false the item will not be removed and the flushing will stop. + * @param pUsbIns The USB device instance. + * @param pItem The item to consume. Upon return this item will be freed. + * @remarks No locks will be held, but for now it's safe to assume that only one + * EMT will do queue callbacks at any one time. + */ +typedef DECLCALLBACKTYPE(bool, FNPDMQUEUEUSB,(PPDMUSBINS pUsbIns, PPDMQUEUEITEMCORE pItem)); +/** Pointer to a FNPDMQUEUEUSB(). */ +typedef FNPDMQUEUEUSB *PFNPDMQUEUEUSB; + +/** + * Queue consumer callback for drivers. + * + * @returns Success indicator. + * If false the item will not be removed and the flushing will stop. + * @param pDrvIns The driver instance. + * @param pItem The item to consume. Upon return this item will be freed. + * @remarks No locks will be held, but for now it's safe to assume that only one + * EMT will do queue callbacks at any one time. + */ +typedef DECLCALLBACKTYPE(bool, FNPDMQUEUEDRV,(PPDMDRVINS pDrvIns, PPDMQUEUEITEMCORE pItem)); +/** Pointer to a FNPDMQUEUEDRV(). */ +typedef FNPDMQUEUEDRV *PFNPDMQUEUEDRV; + +/** + * Queue consumer callback for internal component. + * + * @returns Success indicator. + * If false the item will not be removed and the flushing will stop. + * @param pVM The cross context VM structure. + * @param pItem The item to consume. Upon return this item will be freed. + * @remarks No locks will be held, but for now it's safe to assume that only one + * EMT will do queue callbacks at any one time. + */ +typedef DECLCALLBACKTYPE(bool, FNPDMQUEUEINT,(PVM pVM, PPDMQUEUEITEMCORE pItem)); +/** Pointer to a FNPDMQUEUEINT(). */ +typedef FNPDMQUEUEINT *PFNPDMQUEUEINT; + +/** + * Queue consumer callback for external component. + * + * @returns Success indicator. + * If false the item will not be removed and the flushing will stop. + * @param pvUser User argument. + * @param pItem The item to consume. Upon return this item will be freed. + * @remarks No locks will be held, but for now it's safe to assume that only one + * EMT will do queue callbacks at any one time. + */ +typedef DECLCALLBACKTYPE(bool, FNPDMQUEUEEXT,(void *pvUser, PPDMQUEUEITEMCORE pItem)); +/** Pointer to a FNPDMQUEUEEXT(). */ +typedef FNPDMQUEUEEXT *PFNPDMQUEUEEXT; + +#ifdef VBOX_IN_VMM +VMMR3_INT_DECL(int) PDMR3QueueCreateDevice(PVM pVM, PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems, + uint32_t cMilliesInterval, PFNPDMQUEUEDEV pfnCallback, + bool fRZEnabled, const char *pszName, PDMQUEUEHANDLE *phQueue); +VMMR3_INT_DECL(int) PDMR3QueueCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, size_t cbItem, uint32_t cItems, + uint32_t cMilliesInterval, PFNPDMQUEUEDRV pfnCallback, + const char *pszName, PDMQUEUEHANDLE *phQueue); +VMMR3_INT_DECL(int) PDMR3QueueCreateInternal(PVM pVM, size_t cbItem, uint32_t cItems, + uint32_t cMilliesInterval, PFNPDMQUEUEINT pfnCallback, + bool fRZEnabled, const char *pszName, PDMQUEUEHANDLE *phQueue); +VMMR3DECL(int) PDMR3QueueCreateExternal(PVM pVM, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEEXT pfnCallback, void *pvUser, const char *pszName, PDMQUEUEHANDLE *phQueue); +VMMR3DECL(int) PDMR3QueueDestroy(PVM pVM, PDMQUEUEHANDLE hQueue, void *pvOwner); +VMMR3_INT_DECL(int) PDMR3QueueDestroyDevice(PVM pVM, PPDMDEVINS pDevIns); +VMMR3_INT_DECL(int) PDMR3QueueDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns); +VMMR3DECL(void) PDMR3QueueFlushAll(PVM pVM); +#endif /* VBOX_IN_VMM */ + +VMMDECL(PPDMQUEUEITEMCORE) PDMQueueAlloc(PVMCC pVM, PDMQUEUEHANDLE hQueue, void *pvOwner); +VMMDECL(int) PDMQueueInsert(PVMCC pVM, PDMQUEUEHANDLE hQueue, void *pvOwner, PPDMQUEUEITEMCORE pInsert); +VMMDECL(int) PDMQueueFlushIfNecessary(PVMCC pVM, PDMQUEUEHANDLE hQueue, void *pvOwner); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmqueue_h */ + diff --git a/include/VBox/vmm/pdmserialifs.h b/include/VBox/vmm/pdmserialifs.h new file mode 100644 index 00000000..3917e0e5 --- /dev/null +++ b/include/VBox/vmm/pdmserialifs.h @@ -0,0 +1,249 @@ +/** @file + * PDM - Pluggable Device Manager, Serial port related interfaces. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmserialifs_h +#define VBOX_INCLUDED_vmm_pdmserialifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_ifs_serial PDM Serial Port Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + + +/** @name Bit mask definitions for status line type. + * @{ */ +#define PDMISERIALPORT_STS_LINE_DCD RT_BIT(0) +#define PDMISERIALPORT_STS_LINE_RI RT_BIT(1) +#define PDMISERIALPORT_STS_LINE_DSR RT_BIT(2) +#define PDMISERIALPORT_STS_LINE_CTS RT_BIT(3) +/** @} */ + +/** Pointer to a serial port interface. */ +typedef struct PDMISERIALPORT *PPDMISERIALPORT; +/** + * Serial port interface (down). + */ +typedef struct PDMISERIALPORT +{ + /** + * Notifies the upper device/driver that data is available for reading. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cbAvail The amount of data available to be written. + */ + DECLR3CALLBACKMEMBER(int, pfnDataAvailRdrNotify, (PPDMISERIALPORT pInterface, size_t cbAvail)); + + /** + * Notifies the upper device/driver that all data was sent. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnDataSentNotify, (PPDMISERIALPORT pInterface)); + + /** + * Try to read data from the device/driver above for writing. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the read data. + * @param cbRead How much to read. + * @param pcbRead Where to store the amount of data actually read on success. + */ + DECLR3CALLBACKMEMBER(int, pfnReadWr, (PPDMISERIALPORT pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)); + + /** + * Notify the device/driver when the status lines changed. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fNewStatusLines New state of the status line pins. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnNotifyStsLinesChanged, (PPDMISERIALPORT pInterface, uint32_t fNewStatusLines)); + + /** + * Notify the device/driver that a break condition occurred. + * + * @returns VBox statsus code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnNotifyBrk, (PPDMISERIALPORT pInterface)); + +} PDMISERIALPORT; +/** PDMISERIALPORT interface ID. */ +#define PDMISERIALPORT_IID "44540323-06ca-44c1-8eb2-f5a387704dbd" + + +/** + * Supported parity modes. + */ +typedef enum PDMSERIALPARITY +{ + /** Invalid parity setting. */ + PDMSERIALPARITY_INVALID = 0, + /** No parity. */ + PDMSERIALPARITY_NONE, + /** Even parity. */ + PDMSERIALPARITY_EVEN, + /** Odd parity. */ + PDMSERIALPARITY_ODD, + /** Mark parity. */ + PDMSERIALPARITY_MARK, + /** Space parity. */ + PDMSERIALPARITY_SPACE, + /** 32bit hack. */ + PDMSERIALPARITY_32BIT_HACK = 0x7fffffff +} PDMSERIALPARITY; + + +/** + * Supported number of stop bits. + */ +typedef enum PDMSERIALSTOPBITS +{ + /** Invalid stop bits setting. */ + PDMSERIALSTOPBITS_INVALID = 0, + /** One stop bit is used. */ + PDMSERIALSTOPBITS_ONE, + /** 1.5 stop bits are used. */ + PDMSERIALSTOPBITS_ONEPOINTFIVE, + /** 2 stop bits are used. */ + PDMSERIALSTOPBITS_TWO, + /** 32bit hack. */ + PDMSERIALSTOPBITS_32BIT_HACK = 0x7fffffff +} PDMSERIALSTOPBITS; + + +/** Pointer to a serial interface. */ +typedef struct PDMISERIALCONNECTOR *PPDMISERIALCONNECTOR; +/** + * Serial interface (up). + * Pairs with PDMISERIALPORT. + */ +typedef struct PDMISERIALCONNECTOR +{ + /** + * Notifies the lower layer that data is available for writing. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnDataAvailWrNotify, (PPDMISERIALCONNECTOR pInterface)); + + /** + * Try to read data from the underyling driver. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the read data. + * @param cbRead How much to read. + * @param pcbRead Where to store the amount of data actually read on success. + */ + DECLR3CALLBACKMEMBER(int, pfnReadRdr, (PPDMISERIALCONNECTOR pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)); + + /** + * Change device parameters. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param uBps Speed of the serial connection. (bits per second) + * @param enmParity Parity method. + * @param cDataBits Number of data bits. + * @param enmStopBits Number of stop bits. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnChgParams, (PPDMISERIALCONNECTOR pInterface, uint32_t uBps, + PDMSERIALPARITY enmParity, unsigned cDataBits, + PDMSERIALSTOPBITS enmStopBits)); + + /** + * Set the state of the modem lines. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fRts Set to true to make the Request to Send line active otherwise to 0. + * @param fDtr Set to true to make the Data Terminal Ready line active otherwise 0. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnChgModemLines, (PPDMISERIALCONNECTOR pInterface, bool fRts, bool fDtr)); + + /** + * Changes the TD line into the requested break condition. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fBrk Set to true to let the device send a break false to put into normal operation. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnChgBrk, (PPDMISERIALCONNECTOR pInterface, bool fBrk)); + + /** + * Queries the current state of the status lines. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfStsLines Where to store the status line states on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryStsLines, (PPDMISERIALCONNECTOR pInterface, uint32_t *pfStsLines)); + + /** + * Flushes the indicated queues. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fQueueRecv Flag whether to flush the receive queue. + * @param fQueueXmit Flag whether to flush the transmit queue. + */ + DECLR3CALLBACKMEMBER(int, pfnQueuesFlush, (PPDMISERIALCONNECTOR pInterface, bool fQueueRecv, bool fQueueXmit)); + +} PDMISERIALCONNECTOR; +/** PDMIMEDIA interface ID. */ +#define PDMISERIALCONNECTOR_IID "d024f170-c00d-11e8-b568-0800200c9a66" + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmserialifs_h */ diff --git a/include/VBox/vmm/pdmsrv.h b/include/VBox/vmm/pdmsrv.h new file mode 100644 index 00000000..e0b3f7ce --- /dev/null +++ b/include/VBox/vmm/pdmsrv.h @@ -0,0 +1,350 @@ +/** @file + * PDM - Pluggable Device Manager, VM Services. + * + * @todo This has not been implemented, consider dropping the concept. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmsrv_h +#define VBOX_INCLUDED_vmm_pdmsrv_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/pdmifs.h> +#include <VBox/vmm/ssm.h> +#include <VBox/vmm/cfgm.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_services The PDM Services API + * @ingroup grp_pdm + * @{ + */ + +/** + * Construct a service instance for a VM. + * + * @returns VBox status. + * @param pSrvIns The service instance data. + * If the registration structure is needed, pSrvIns->pReg points to it. + * @param pCfg Configuration node handle for the service. Use this to obtain the configuration + * of the driver instance. It's also found in pSrvIns->pCfg, but since it's primary + * usage is expected in this function it is passed as a parameter. + */ +typedef DECLCALLBACKTYPE(int, FNPDMSRVCONSTRUCT,(PPDMSRVINS pSrvIns, PCFGMNODE pCfg)); +/** Pointer to a FNPDMSRVCONSTRUCT() function. */ +typedef FNPDMSRVCONSTRUCT *PFNPDMSRVCONSTRUCT; + +/** + * Destruct a driver instance. + * + * Most VM resources are freed by the VM. This callback is provided so that any non-VM + * resources can be freed correctly. + * + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVDESTRUCT,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVDESTRUCT() function. */ +typedef FNPDMSRVDESTRUCT *PFNPDMSRVDESTRUCT; + +/** + * Power On notification. + * + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVPOWERON,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVPOWERON() function. */ +typedef FNPDMSRVPOWERON *PFNPDMSRVPOWERON; + +/** + * Reset notification. + * + * @returns VBox status. + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVRESET,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVRESET() function. */ +typedef FNPDMSRVRESET *PFNPDMSRVRESET; + +/** + * Suspend notification. + * + * @returns VBox status. + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVSUSPEND,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVSUSPEND() function. */ +typedef FNPDMSRVSUSPEND *PFNPDMSRVSUSPEND; + +/** + * Resume notification. + * + * @returns VBox status. + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVRESUME,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVRESUME() function. */ +typedef FNPDMSRVRESUME *PFNPDMSRVRESUME; + +/** + * Power Off notification. + * + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVPOWEROFF,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVPOWEROFF() function. */ +typedef FNPDMSRVPOWEROFF *PFNPDMSRVPOWEROFF; + +/** + * Detach notification. + * + * This is called when a driver or device is detached from the service + * + * @param pSrvIns The service instance data. + * @param pDevIns The device instance to detach. + * @param pDrvIns The driver instance to detach. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVDETACH,(PPDMSRVINS pSrvIns, PPDMDEVINS pDevIns, PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMSRVDETACH() function. */ +typedef FNPDMSRVDETACH *PFNPDMSRVDETACH; + + + +/** PDM Service Registration Structure, + * This structure is used when registering a driver from + * VBoxServicesRegister() (HC Ring-3). PDM will continue use till + * the VM is terminated. + */ +typedef struct PDMSRVREG +{ + /** Structure version. PDM_SRVREG_VERSION defines the current version. */ + uint32_t u32Version; + /** Driver name. */ + char szServiceName[32]; + /** The description of the driver. The UTF-8 string pointed to shall, like this structure, + * remain unchanged from registration till VM destruction. */ + const char *pszDescription; + + /** Flags, combination of the PDM_SRVREG_FLAGS_* \#defines. */ + RTUINT fFlags; + /** Size of the instance data. */ + RTUINT cbInstance; + + /** Construct instance - required. */ + PFNPDMSRVCONSTRUCT pfnConstruct; + /** Destruct instance - optional. */ + PFNPDMSRVDESTRUCT pfnDestruct; + /** Power on notification - optional. */ + PFNPDMSRVPOWERON pfnPowerOn; + /** Reset notification - optional. */ + PFNPDMSRVRESET pfnReset; + /** Suspend notification - optional. */ + PFNPDMSRVSUSPEND pfnSuspend; + /** Resume notification - optional. */ + PFNPDMSRVRESUME pfnResume; + /** Detach notification - optional. */ + PFNPDMSRVDETACH pfnDetach; + /** Power off notification - optional. */ + PFNPDMSRVPOWEROFF pfnPowerOff; + +} PDMSRVREG; +/** Pointer to a PDM Driver Structure. */ +typedef PDMSRVREG *PPDMSRVREG; +/** Const pointer to a PDM Driver Structure. */ +typedef PDMSRVREG const *PCPDMSRVREG; + + + +/** + * PDM Service API. + */ +typedef struct PDMSRVHLP +{ + /** Structure version. PDM_SRVHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pSrvIns Service instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertEMT,(PPDMSRVINS pSrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pSrvIns Service instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertOther,(PPDMSRVINS pSrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Creates a timer. + * + * @returns VBox status. + * @param pVM The cross context VM structure. + * @param pSrvIns Service instance. + * @param enmClock The clock to use on this timer. + * @param pfnCallback Callback function. + * @param pszDesc Pointer to description string which must stay around + * until the timer is fully destroyed (i.e. a bit after TMTimerDestroy()). + * @param ppTimer Where to store the timer on success. + */ + DECLR3CALLBACKMEMBER(int, pfnTMTimerCreate,(PPDMSRVINS pSrvIns, TMCLOCK enmClock, PFNTMTIMERDEV pfnCallback, const char *pszDesc, PPTMTIMERR3 ppTimer)); + + /** + * Query the virtual timer frequency. + * + * @returns Frequency in Hz. + * @param pSrvIns Service instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMGetVirtualFreq,(PPDMSRVINS pSrvIns)); + + /** + * Query the virtual time. + * + * @returns The current virtual time. + * @param pSrvIns Service instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMGetVirtualTime,(PPDMSRVINS pSrvIns)); + +} PDMSRVHLP; +/** Pointer PDM Service API. */ +typedef PDMSRVHLP *PPDMSRVHLP; +/** Pointer const PDM Service API. */ +typedef const PDMSRVHLP *PCPDMSRVHLP; + +/** Current SRVHLP version number. */ +#define PDM_SRVHLP_VERSION PDM_VERSION_MAKE(0xdfff, 1, 0) + + +/** + * PDM Service Instance. + */ +typedef struct PDMSRVINS +{ + /** Structure version. PDM_SRVINS_VERSION defines the current version. */ + uint32_t u32Version; + + /** Internal data. */ + union + { +#ifdef PDMSRVINSINT_DECLARED + PDMSRVINSINT s; +#endif + uint8_t padding[HC_ARCH_BITS == 32 ? 32 : 32]; + } Internal; + + /** Pointer the PDM Service API. */ + R3PTRTYPE(PCPDMSRVHLP) pHlp; + /** Pointer to driver registration structure. */ + R3PTRTYPE(PCPDMSRVREG) pReg; + /** Configuration handle. */ + R3PTRTYPE(PCFGMNODE) pCfg; + /** The base interface of the service. + * The service constructor initializes this. */ + PDMIBASE IBase; + /* padding to make achInstanceData aligned at 16 byte boundary. */ + uint32_t au32Padding[2]; + /** Pointer to driver instance data. */ + R3PTRTYPE(void *) pvInstanceData; + /** Driver instance data. The size of this area is defined + * in the PDMSRVREG::cbInstanceData field. */ + char achInstanceData[4]; +} PDMSRVINS; + +/** Current PDMSRVREG version number. */ +#define PDM_SRVINS_VERSION PDM_VERSION_MAKE(0xdffe, 1, 0) + +/** Converts a pointer to the PDMSRVINS::IBase to a pointer to PDMSRVINS. */ +#define PDMIBASE_2_PDMSRV(pInterface) ( (PPDMSRVINS)((char *)(pInterface) - RT_UOFFSETOF(PDMSRVINS, IBase)) ) + + + +/** Pointer to callbacks provided to the VBoxServiceRegister() call. */ +typedef struct PDMSRVREGCB *PPDMSRVREGCB; + +/** + * Callbacks for VBoxServiceRegister(). + */ +typedef struct PDMSRVREGCB +{ + /** Interface version. + * This is set to PDM_SRVREG_CB_VERSION. */ + uint32_t u32Version; + + /** + * Registers a service with the current VM instance. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param pSrvReg Pointer to the device registration record. + * This data must be permanent and readonly. + */ + DECLR3CALLBACKMEMBER(int, pfnRegister,(PPDMSRVREGCB pCallbacks, PCPDMSRVREG pSrvReg)); +} PDMSRVREGCB; + +/** Current version of the PDMSRVREGCB structure. */ +#define PDM_SRVREG_CB_VERSION PDM_VERSION_MAKE(0xdffd, 1, 0) + + +/** + * The VBoxServicesRegister callback function. + * + * PDM will invoke this function after loading a device module and letting + * the module decide which devices to register and how to handle conflicts. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param u32Version VBox version number. + */ +typedef DECLCALLBACKTYPE(int, FNPDMVBOXSERVICESREGISTER,(PPDMSRVREGCB pCallbacks, uint32_t u32Version)); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmsrv_h */ diff --git a/include/VBox/vmm/pdmstorageifs.h b/include/VBox/vmm/pdmstorageifs.h new file mode 100644 index 00000000..2aeeed99 --- /dev/null +++ b/include/VBox/vmm/pdmstorageifs.h @@ -0,0 +1,1059 @@ +/** @file + * PDM - Pluggable Device Manager, Storage related interfaces. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmstorageifs_h +#define VBOX_INCLUDED_vmm_pdmstorageifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/sg.h> +#include <VBox/types.h> +#include <VBox/vdmedia.h> + +RT_C_DECLS_BEGIN + +struct PDMISECKEY; +struct PDMISECKEYHLP; + + +/** @defgroup grp_pdm_ifs_storage PDM Storage Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + + +/** Pointer to a mount interface. */ +typedef struct PDMIMOUNTNOTIFY *PPDMIMOUNTNOTIFY; +/** + * Block interface (up). + * Pair with PDMIMOUNT. + */ +typedef struct PDMIMOUNTNOTIFY +{ + /** + * Called when a media is mounted. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnMountNotify,(PPDMIMOUNTNOTIFY pInterface)); + + /** + * Called when a media is unmounted + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUnmountNotify,(PPDMIMOUNTNOTIFY pInterface)); +} PDMIMOUNTNOTIFY; +/** PDMIMOUNTNOTIFY interface ID. */ +#define PDMIMOUNTNOTIFY_IID "fa143ac9-9fc6-498e-997f-945380a558f9" + + +/** Pointer to mount interface. */ +typedef struct PDMIMOUNT *PPDMIMOUNT; +/** + * Mount interface (down). + * Pair with PDMIMOUNTNOTIFY. + */ +typedef struct PDMIMOUNT +{ + /** + * Unmount the media. + * + * The driver will validate and pass it on. On the rebounce it will decide whether or not to detach it self. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread The emulation thread. + * @param fForce Force the unmount, even for locked media. + * @param fEject Eject the medium. Only relevant for host drives. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnUnmount,(PPDMIMOUNT pInterface, bool fForce, bool fEject)); + + /** + * Checks if a media is mounted. + * + * @returns true if mounted. + * @returns false if not mounted. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsMounted,(PPDMIMOUNT pInterface)); + + /** + * Locks the media, preventing any unmounting of it. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnLock,(PPDMIMOUNT pInterface)); + + /** + * Unlocks the media, canceling previous calls to pfnLock(). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnUnlock,(PPDMIMOUNT pInterface)); + + /** + * Checks if a media is locked. + * + * @returns true if locked. + * @returns false if not locked. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsLocked,(PPDMIMOUNT pInterface)); +} PDMIMOUNT; +/** PDMIMOUNT interface ID. */ +#define PDMIMOUNT_IID "34fc7a4c-623a-4806-a6bf-5be1be33c99f" + + +/** + * Callback which provides progress information. + * + * @return VBox status code. + * @param pvUser Opaque user data. + * @param uPercentage Completion percentage. + */ +typedef DECLCALLBACKTYPE(int, FNSIMPLEPROGRESS,(void *pvUser, unsigned uPercentage)); +/** Pointer to FNSIMPLEPROGRESS() */ +typedef FNSIMPLEPROGRESS *PFNSIMPLEPROGRESS; + + +/** + * Media type. + */ +typedef enum PDMMEDIATYPE +{ + /** Error (for the query function). */ + PDMMEDIATYPE_ERROR = 1, + /** 360KB 5 1/4" floppy drive. */ + PDMMEDIATYPE_FLOPPY_360, + /** 720KB 3 1/2" floppy drive. */ + PDMMEDIATYPE_FLOPPY_720, + /** 1.2MB 5 1/4" floppy drive. */ + PDMMEDIATYPE_FLOPPY_1_20, + /** 1.44MB 3 1/2" floppy drive. */ + PDMMEDIATYPE_FLOPPY_1_44, + /** 2.88MB 3 1/2" floppy drive. */ + PDMMEDIATYPE_FLOPPY_2_88, + /** Fake drive that can take up to 15.6 MB images. + * C=255, H=2, S=63. */ + PDMMEDIATYPE_FLOPPY_FAKE_15_6, + /** Fake drive that can take up to 63.5 MB images. + * C=255, H=2, S=255. */ + PDMMEDIATYPE_FLOPPY_FAKE_63_5, + /** CDROM drive. */ + PDMMEDIATYPE_CDROM, + /** DVD drive. */ + PDMMEDIATYPE_DVD, + /** Hard disk drive. */ + PDMMEDIATYPE_HARD_DISK +} PDMMEDIATYPE; + +/** Check if the given block type is a floppy. */ +#define PDMMEDIATYPE_IS_FLOPPY(a_enmType) ( (a_enmType) >= PDMMEDIATYPE_FLOPPY_360 && (a_enmType) <= PDMMEDIATYPE_FLOPPY_2_88 ) + +/** + * Raw command data transfer direction. + */ +typedef enum PDMMEDIATXDIR +{ + PDMMEDIATXDIR_NONE = 0, + PDMMEDIATXDIR_FROM_DEVICE, + PDMMEDIATXDIR_TO_DEVICE +} PDMMEDIATXDIR; + +/** + * Media geometry structure. + */ +typedef struct PDMMEDIAGEOMETRY +{ + /** Number of cylinders. */ + uint32_t cCylinders; + /** Number of heads. */ + uint32_t cHeads; + /** Number of sectors. */ + uint32_t cSectors; +} PDMMEDIAGEOMETRY; + +/** Pointer to media geometry structure. */ +typedef PDMMEDIAGEOMETRY *PPDMMEDIAGEOMETRY; +/** Pointer to constant media geometry structure. */ +typedef const PDMMEDIAGEOMETRY *PCPDMMEDIAGEOMETRY; + +/** Pointer to a media port interface. */ +typedef struct PDMIMEDIAPORT *PPDMIMEDIAPORT; +/** + * Media port interface (down). + */ +typedef struct PDMIMEDIAPORT +{ + /** + * Returns the storage controller name, instance and LUN of the attached medium. + * + * @returns VBox status. + * @param pInterface Pointer to this interface. + * @param ppcszController Where to store the name of the storage controller. + * @param piInstance Where to store the instance number of the controller. + * @param piLUN Where to store the LUN of the attached device. + */ + 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, optional. + * + * @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 "77180ab8-6485-454f-b440-efca322b7bd7" + +/** Pointer to a media interface. */ +typedef struct PDMIMEDIA *PPDMIMEDIA; +/** + * Media interface (up). + * Pairs with PDMIMEDIAPORT. + */ +typedef struct PDMIMEDIA +{ + /** + * Read bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param off Offset to start reading from. The offset must be aligned to a sector boundary. + * @param pvBuf Where to store the read bits. + * @param cbRead Number of bytes to read. Must be aligned to a sector boundary. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnRead,(PPDMIMEDIA pInterface, uint64_t off, void *pvBuf, size_t cbRead)); + + /** + * Read bits - version for DevPcBios. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param off Offset to start reading from. The offset must be aligned to a sector boundary. + * @param pvBuf Where to store the read bits. + * @param cbRead Number of bytes to read. Must be aligned to a sector boundary. + * @thread Any thread. + * + * @note: Special version of pfnRead which doesn't try to suspend the VM when the DEKs for encrypted disks + * are missing but just returns an error. + */ + DECLR3CALLBACKMEMBER(int, pfnReadPcBios,(PPDMIMEDIA pInterface, uint64_t off, void *pvBuf, size_t cbRead)); + + /** + * Write bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param off Offset to start writing at. The offset must be aligned to a sector boundary. + * @param pvBuf Where to store the write bits. + * @param cbWrite Number of bytes to write. Must be aligned to a sector boundary. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMIMEDIA pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)); + + /** + * Make sure that the bits written are actually on the storage medium. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnFlush,(PPDMIMEDIA pInterface)); + + /** + * Send a raw command to the underlying device (CDROM). + * This method is optional (i.e. the function pointer may be NULL). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pbCdb The command to process. + * @param cbCdb The length of the command in bytes. + * @param enmTxDir Direction of transfer. + * @param pvBuf Pointer tp the transfer buffer. + * @param pcbBuf Size of the transfer buffer. + * @param pabSense Status of the command (when return value is VERR_DEV_IO_ERROR). + * @param cbSense Size of the sense buffer in bytes. + * @param cTimeoutMillies Command timeout in milliseconds. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSendCmd,(PPDMIMEDIA pInterface, const uint8_t *pbCdb, size_t cbCdb, + PDMMEDIATXDIR enmTxDir, void *pvBuf, uint32_t *pcbBuf, + uint8_t *pabSense, size_t cbSense, uint32_t cTimeoutMillies)); + + /** + * Merge medium contents during a live snapshot deletion. All details + * must have been configured through CFGM or this will fail. + * This method is optional (i.e. the function pointer may be NULL). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfnProgress Function pointer for progress notification. + * @param pvUser Opaque user data for progress notification. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnMerge,(PPDMIMEDIA pInterface, PFNSIMPLEPROGRESS pfnProgress, void *pvUser)); + + /** + * Sets the secret key retrieval interface to use to get secret keys. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pIfSecKey The secret key interface to use. + * Use NULL to clear the currently set interface and clear all secret + * keys from the user. + * @param pIfSecKeyHlp The secret key helper interface to use. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetSecKeyIf,(PPDMIMEDIA pInterface, struct PDMISECKEY *pIfSecKey, + struct PDMISECKEYHLP *pIfSecKeyHlp)); + + /** + * Get the media size in bytes. + * + * @returns Media size in bytes. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnGetSize,(PPDMIMEDIA pInterface)); + + /** + * Gets the media sector size in bytes. + * + * @returns Media sector size in bytes. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetSectorSize,(PPDMIMEDIA pInterface)); + + /** + * Check if the media is readonly or not. + * + * @returns true if readonly. + * @returns false if read/write. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsReadOnly,(PPDMIMEDIA pInterface)); + + /** + * Returns whether the medium should be marked as rotational or not. + * + * @returns true if non rotating medium. + * @returns false if rotating medium. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsNonRotational,(PPDMIMEDIA pInterface)); + + /** + * Get stored media geometry (physical CHS, PCHS) - BIOS property. + * This is an optional feature of a media. + * + * @returns VBox status code. + * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry. + * @returns VERR_PDM_GEOMETRY_NOT_SET if the geometry hasn't been set using pfnBiosSetPCHSGeometry() yet. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pPCHSGeometry Pointer to PCHS geometry (cylinders/heads/sectors). + * @remark This has no influence on the read/write operations. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnBiosGetPCHSGeometry,(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)); + + /** + * Store the media geometry (physical CHS, PCHS) - BIOS property. + * This is an optional feature of a media. + * + * @returns VBox status code. + * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pPCHSGeometry Pointer to PCHS geometry (cylinders/heads/sectors). + * @remark This has no influence on the read/write operations. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnBiosSetPCHSGeometry,(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)); + + /** + * Get stored media geometry (logical CHS, LCHS) - BIOS property. + * This is an optional feature of a media. + * + * @returns VBox status code. + * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry. + * @returns VERR_PDM_GEOMETRY_NOT_SET if the geometry hasn't been set using pfnBiosSetLCHSGeometry() yet. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pLCHSGeometry Pointer to LCHS geometry (cylinders/heads/sectors). + * @remark This has no influence on the read/write operations. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnBiosGetLCHSGeometry,(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)); + + /** + * Store the media geometry (logical CHS, LCHS) - BIOS property. + * This is an optional feature of a media. + * + * @returns VBox status code. + * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pLCHSGeometry Pointer to LCHS geometry (cylinders/heads/sectors). + * @remark This has no influence on the read/write operations. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnBiosSetLCHSGeometry,(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)); + + /** + * Checks if the device should be visible to the BIOS or not. + * + * @returns true if the device is visible to the BIOS. + * @returns false if the device is not visible to the BIOS. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnBiosIsVisible,(PPDMIMEDIA pInterface)); + + /** + * Gets the media type. + * + * @returns media type. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(PDMMEDIATYPE, pfnGetType,(PPDMIMEDIA pInterface)); + + /** + * Gets the UUID of the media drive. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pUuid Where to store the UUID on success. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnGetUuid,(PPDMIMEDIA pInterface, PRTUUID pUuid)); + + /** + * Discards the given range. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param paRanges Array of ranges to discard. + * @param cRanges Number of entries in the array. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnDiscard,(PPDMIMEDIA pInterface, PCRTRANGE paRanges, unsigned cRanges)); + + /** + * Returns the number of regions for the medium. + * + * @returns Number of regions. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetRegionCount,(PPDMIMEDIA pInterface)); + + /** + * Queries the properties for the given region. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the region index is not known. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param uRegion The region index to query the properties of. + * @param pu64LbaStart Where to store the starting LBA for the region on success. + * @param pcBlocks Where to store the number of blocks for the region on success. + * @param pcbBlock Where to store the size of one block in bytes on success. + * @param penmDataForm WHere to store the data form for the region on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryRegionProperties,(PPDMIMEDIA pInterface, uint32_t uRegion, uint64_t *pu64LbaStart, + uint64_t *pcBlocks, uint64_t *pcbBlock, + PVDREGIONDATAFORM penmDataForm)); + + /** + * Queries the properties for the region covering the given LBA. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the region index is not known. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param u64LbaStart Where to store the starting LBA for the region on success. + * @param puRegion Where to store the region number on success. + * @param pcBlocks Where to store the number of blocks left in this region starting from the given LBA. + * @param pcbBlock Where to store the size of one block in bytes on success. + * @param penmDataForm WHere to store the data form for the region on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryRegionPropertiesForLba,(PPDMIMEDIA pInterface, uint64_t u64LbaStart, + uint32_t *puRegion, uint64_t *pcBlocks, + uint64_t *pcbBlock, PVDREGIONDATAFORM penmDataForm)); + +} PDMIMEDIA; +/** PDMIMEDIA interface ID. */ +#define PDMIMEDIA_IID "8ec68c48-dd20-4430-8386-f0d628a5aca6" + + +/** + * Opaque I/O request handle. + * + * The specific content depends on the driver implementing this interface. + */ +typedef struct PDMMEDIAEXIOREQINT *PDMMEDIAEXIOREQ; +/** Pointer to an I/O request handle. */ +typedef PDMMEDIAEXIOREQ *PPDMMEDIAEXIOREQ; +/** NIL I/O request handle. */ +#define NIL_PDMMEDIAEXIOREQ ((PDMMEDIAEXIOREQ)0) + +/** A I/O request ID. */ +typedef uint64_t PDMMEDIAEXIOREQID; + +/** + * I/O Request Type. + */ +typedef enum PDMMEDIAEXIOREQTYPE +{ + /** Invalid tpe. */ + PDMMEDIAEXIOREQTYPE_INVALID = 0, + /** Flush request. */ + PDMMEDIAEXIOREQTYPE_FLUSH, + /** Write request. */ + PDMMEDIAEXIOREQTYPE_WRITE, + /** Read request. */ + PDMMEDIAEXIOREQTYPE_READ, + /** Discard request. */ + PDMMEDIAEXIOREQTYPE_DISCARD, + /** SCSI command. */ + PDMMEDIAEXIOREQTYPE_SCSI +} PDMMEDIAEXIOREQTYPE; +/** Pointer to a I/O request type. */ +typedef PDMMEDIAEXIOREQTYPE *PPDMMEDIAEXIOREQTYPE; + +/** + * Data direction for raw SCSI commands. + */ +typedef enum PDMMEDIAEXIOREQSCSITXDIR +{ + /** Invalid data direction. */ + PDMMEDIAEXIOREQSCSITXDIR_INVALID = 0, + /** Direction is unknown. */ + PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN, + /** Direction is from device to host. */ + PDMMEDIAEXIOREQSCSITXDIR_FROM_DEVICE, + /** Direction is from host to device. */ + PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE, + /** No data transfer associated with this request. */ + PDMMEDIAEXIOREQSCSITXDIR_NONE, + /** 32bit hack. */ + PDMMEDIAEXIOREQSCSITXDIR_32BIT_HACK = 0x7fffffff +} PDMMEDIAEXIOREQSCSITXDIR; + +/** + * I/O request state. + */ +typedef enum PDMMEDIAEXIOREQSTATE +{ + /** Invalid state. */ + PDMMEDIAEXIOREQSTATE_INVALID = 0, + /** The request is active and being processed. */ + PDMMEDIAEXIOREQSTATE_ACTIVE, + /** The request is suspended due to an error and no processing will take place. */ + PDMMEDIAEXIOREQSTATE_SUSPENDED, + /** 32bit hack. */ + PDMMEDIAEXIOREQSTATE_32BIT_HACK = 0x7fffffff +} PDMMEDIAEXIOREQSTATE; +/** Pointer to a I/O request state. */ +typedef PDMMEDIAEXIOREQSTATE *PPDMMEDIAEXIOREQSTATE; + +/** @name Supported feature flags + * @{ */ +/** I/O requests will execute asynchronously by default. */ +#define PDMIMEDIAEX_FEATURE_F_ASYNC RT_BIT_32(0) +/** The discard request is supported. */ +#define PDMIMEDIAEX_FEATURE_F_DISCARD RT_BIT_32(1) +/** The send raw SCSI command request is supported. */ +#define PDMIMEDIAEX_FEATURE_F_RAWSCSICMD RT_BIT_32(2) +/** Mask of valid flags. */ +#define PDMIMEDIAEX_FEATURE_F_VALID (PDMIMEDIAEX_FEATURE_F_ASYNC | PDMIMEDIAEX_FEATURE_F_DISCARD | PDMIMEDIAEX_FEATURE_F_RAWSCSICMD) +/** @} */ + +/** @name I/O request specific flags + * @{ */ +/** Default behavior (async I/O).*/ +#define PDMIMEDIAEX_F_DEFAULT (0) +/** The I/O request will be executed synchronously. */ +#define PDMIMEDIAEX_F_SYNC RT_BIT_32(0) +/** Whether to suspend the VM on a recoverable error with + * an appropriate error message (disk full, etc.). + * The request will be retried by the driver implementing the interface + * when the VM resumes the next time. However before suspending the request + * the owner of the request will be notified using the PDMMEDIAEXPORT::pfnIoReqStateChanged. + * The same goes for resuming the request after the VM was resumed. + */ +#define PDMIMEDIAEX_F_SUSPEND_ON_RECOVERABLE_ERR RT_BIT_32(1) + /** Mask of valid flags. */ +#define PDMIMEDIAEX_F_VALID (PDMIMEDIAEX_F_SYNC | PDMIMEDIAEX_F_SUSPEND_ON_RECOVERABLE_ERR) +/** @} */ + +/** Pointer to an extended media notification interface. */ +typedef struct PDMIMEDIAEXPORT *PPDMIMEDIAEXPORT; + +/** + * Asynchronous version of the media interface (up). + * Pair with PDMIMEDIAEXPORT. + */ +typedef struct PDMIMEDIAEXPORT +{ + /** + * Notify completion of a I/O request. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param rcReq IPRT Status code of the completed request. + * VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqCompleteNotify, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, int rcReq)); + + /** + * Copy data from the memory buffer of the caller to the callees memory buffer for the given request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOBUF_OVERFLOW if there is not enough room to store the data. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param offDst The destination offset from the start to write the data to. + * @param pSgBuf The S/G buffer to read the data from. + * @param cbCopy How many bytes to copy. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqCopyFromBuf, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf, + size_t cbCopy)); + + /** + * Copy data to the memory buffer of the caller from the callees memory buffer for the given request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOBUF_UNDERRUN if there is not enough data to copy from the buffer. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param offSrc The offset from the start of the buffer to read the data from. + * @param pSgBuf The S/G buffer to write the data to. + * @param cbCopy How many bytes to copy. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqCopyToBuf, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf, + size_t cbCopy)); + + /** + * Queries a pointer to the memory buffer for the request from the drive/device above. + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if this is not supported for this request. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param ppvBuf Where to store the pointer to the guest buffer on success. + * @param pcbBuf Where to store the size of the buffer on success. + * + * @note This is an optional feature of the entity implementing this interface to avoid overhead + * by copying the data between buffers. If NULL it is not supported at all and the caller + * has to resort to PDMIMEDIAEXPORT::pfnIoReqCopyToBuf and PDMIMEDIAEXPORT::pfnIoReqCopyFromBuf. + * The same holds when VERR_NOT_SUPPORTED is returned. + * + * On the upside the caller of this interface might not call this method at all and just + * use the before mentioned methods to copy the data between the buffers. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQueryBuf, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, void **ppvBuf, size_t *pcbBuf)); + + /** + * Queries the specified amount of ranges to discard from the callee for the given I/O request. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param idxRangeStart The range index to start with. + * @param cRanges How man ranges can be stored in the provided array. + * @param paRanges Where to store the ranges on success. + * @param *pcRanges Where to store the number of ranges copied over on success. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQueryDiscardRanges, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, uint32_t idxRangeStart, + uint32_t cRanges, PRTRANGE paRanges, + uint32_t *pcRanges)); + + /** + * Notify the request owner about a state change for the request. + * + * @returns nothing. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param enmState The new state of the request. + */ + DECLR3CALLBACKMEMBER(void, pfnIoReqStateChanged, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)); + + /** + * Informs the device that the underlying medium was ejected. + * + * @returns nothing. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(void, pfnMediumEjected, (PPDMIMEDIAEXPORT pInterface)); + +} PDMIMEDIAEXPORT; + +/** PDMIMEDIAAEXPORT interface ID. */ +#define PDMIMEDIAEXPORT_IID "0ae2e534-6c28-41d6-9a88-7f88f2cb2ff8" + + +/** Pointer to an extended media interface. */ +typedef struct PDMIMEDIAEX *PPDMIMEDIAEX; + +/** + * Extended version of PDMIMEDIA (down). + * Pair with PDMIMEDIAEXPORT. + */ +typedef struct PDMIMEDIAEX +{ + /** + * Queries the features supported by the entity implementing this interface. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfFeatures Where to store the supported feature flags on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryFeatures, (PPDMIMEDIAEX pInterface, uint32_t *pfFeatures)); + + /** + * Notifies the driver below that the device received a suspend notification. + * + * @returns nothing. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * + * @note this is required because the PDM drivers in the storage area usually get their suspend notification + * only after the device finished suspending. For some cases it is useful for the driver to know + * as early as possible that a suspend is in progress to stop issuing deferred requests or other things. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifySuspend, (PPDMIMEDIAEX pInterface)); + + /** + * Sets the size of the allocator specific memory for a I/O request. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cbIoReqAlloc The size of the allocator specific memory in bytes. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqAllocSizeSet, (PPDMIMEDIAEX pInterface, size_t cbIoReqAlloc)); + + /** + * Allocates a new I/O request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQID_CONFLICT if the ID belongs to a still active request. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param phIoReq Where to store the handle to the new I/O request on success. + * @param ppvIoReqAlloc Where to store the pointer to the allocator specific memory on success. + * NULL if the memory size was not set or set to 0. + * @param uIoReqId A custom request ID which can be used to cancel the request. + * @param fFlags A combination of PDMIMEDIAEX_F_* flags. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqAlloc, (PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc, + PDMMEDIAEXIOREQID uIoReqId, uint32_t fFlags)); + + /** + * Frees a given I/O request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE if the given request is still active. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to free. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqFree, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)); + + /** + * Queries the residual amount of data not transfered when the request completed. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE has not completed yet. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request. + * @param pcbResidual Where to store the amount of resdiual data in bytes. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQueryResidual, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbResidual)); + + /** + * Queries the residual amount of data not transfered when the request completed. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE has not completed yet. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request. + * @param pcbXfer Where to store the amount of resdiual data in bytes. + * @thread Any thread. + * + * @note For simple read/write requests this returns the amount to read/write as given to the + * PDMIMEDIAEX::pfnIoReqRead or PDMIMEDIAEX::pfnIoReqWrite call. + * For SCSI commands this returns the transfer size as given in the provided CDB. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQueryXferSize, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbXfer)); + + /** + * Cancels all I/O active requests. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqCancelAll, (PPDMIMEDIAEX pInterface)); + + /** + * Cancels a I/O request identified by the ID. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQID_NOT_FOUND if the given ID could not be found in the active request list. + * (The request has either completed already or an invalid ID was given). + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param uIoReqId The I/O request ID + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqCancel, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQID uIoReqId)); + + /** + * Start a reading request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @retval VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS if the request was successfully submitted but is still in progress. + * Completion will be notified through PDMIMEDIAEXPORT::pfnIoReqCompleteNotify with the appropriate status code. + * @retval VINF_SUCCESS if the request completed successfully. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to associate the read with. + * @param off Offset to start reading from. Must be aligned to a sector boundary. + * @param cbRead Number of bytes to read. Must be aligned to a sector boundary. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqRead, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbRead)); + + /** + * Start a writing request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @retval VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS if the request was successfully submitted but is still in progress. + * Completion will be notified through PDMIMEDIAEXPORT::pfnIoReqCompleteNotify with the appropriate status code. + * @retval VINF_SUCCESS if the request completed successfully. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to associate the write with. + * @param off Offset to start reading from. Must be aligned to a sector boundary. + * @param cbWrite Number of bytes to write. Must be aligned to a sector boundary. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqWrite, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbWrite)); + + /** + * Flush everything to disk. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @retval VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS if the request was successfully submitted but is still in progress. + * Completion will be notified through PDMIMEDIAEXPORT::pfnIoReqCompleteNotify with the appropriate status code. + * @retval VINF_SUCCESS if the request completed successfully. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to associate the flush with. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqFlush, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)); + + /** + * Discards the given range. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @retval VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS if the request was successfully submitted but is still in progress. + * Completion will be notified through PDMIMEDIAEXPORT::pfnIoReqCompleteNotify with the appropriate status code. + * @retval VINF_SUCCESS if the request completed successfully. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to associate the discard with. + * @param cRangesMax The maximum number of ranges this request has associated, this must not be accurate + * but can actually be bigger than the amount of ranges actually available. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqDiscard, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, unsigned cRangesMax)); + + /** + * Send a raw command to the underlying device (CDROM). + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @retval VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS if the request was successfully submitted but is still in progress. + * Completion will be notified through PDMIMEDIAEXPORT::pfnIoReqCompleteNotify with the appropriate status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to associate the command with. + * @param uLun The LUN the command is for. + * @param pbCdb The SCSI CDB containing the command. + * @param cbCdb Size of the CDB in bytes. + * @param enmTxDir Direction of transfer. + * @param penmTxDirRet Where to store the transfer direction as parsed from the CDB, optional. + * @param cbBuf Size of the transfer buffer. + * @param pabSense Where to store the optional sense key. + * @param cbSense Size of the sense key buffer. + * @param pcbSenseRet Where to store the amount of sense data written, optional. + * @param pu8ScsiSts Where to store the SCSI status on success. + * @param cTimeoutMillies Command timeout in milliseconds. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqSendScsiCmd,(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, + uint32_t uLun, const uint8_t *pbCdb, size_t cbCdb, + PDMMEDIAEXIOREQSCSITXDIR enmTxDir, PDMMEDIAEXIOREQSCSITXDIR *penmTxDirRet, + size_t cbBuf, uint8_t *pabSense, size_t cbSense, size_t *pcbSenseRet, + uint8_t *pu8ScsiSts, uint32_t cTimeoutMillies)); + + /** + * Returns the number of active I/O requests. + * + * @returns Number of active I/O requests. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnIoReqGetActiveCount, (PPDMIMEDIAEX pInterface)); + + /** + * Returns the number of suspended requests. + * + * @returns Number of suspended I/O requests. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnIoReqGetSuspendedCount, (PPDMIMEDIAEX pInterface)); + + /** + * Gets the first suspended request handle. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if there is no suspended request waiting. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param phIoReq Where to store the request handle on success. + * @param ppvIoReqAlloc Where to store the pointer to the allocator specific memory on success. + * @thread Any thread. + * + * @note This should only be called when the VM is suspended to make sure the request doesn't suddenly + * changes into the active state again. The only purpose for this method for now is to make saving the state + * possible without breaking saved state versions. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQuerySuspendedStart, (PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc)); + + /** + * Gets the next suspended request handle. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if there is no suspended request waiting. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The current request handle. + * @param phIoReqNext Where to store the request handle on success. + * @param ppvIoReqAllocNext Where to store the pointer to the allocator specific memory on success. + * @thread Any thread. + * + * @note This should only be called when the VM is suspended to make sure the request doesn't suddenly + * changes into the active state again. The only purpose for this method for now is to make saving the state + * possible without breaking saved state versions. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQuerySuspendedNext, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, + PPDMMEDIAEXIOREQ phIoReqNext, void **ppvIoReqAllocNext)); + + /** + * Saves the given I/O request state in the provided saved state unit. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pSSM The SSM handle. + * @param hIoReq The request handle to save. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqSuspendedSave, (PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)); + + /** + * Load a suspended request state from the given saved state unit and link it into the suspended list. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pSSM The SSM handle to read the state from. + * @param hIoReq The request handle to load the state into. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqSuspendedLoad, (PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)); + +} PDMIMEDIAEX; +/** PDMIMEDIAEX interface ID. */ +#define PDMIMEDIAEX_IID "29c9e82b-934e-45c5-bb84-0d871c3cc9dd" + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmstorageifs_h */ diff --git a/include/VBox/vmm/pdmtask.h b/include/VBox/vmm/pdmtask.h new file mode 100644 index 00000000..d3b48e99 --- /dev/null +++ b/include/VBox/vmm/pdmtask.h @@ -0,0 +1,162 @@ +/** @file + * PDM - Pluggable Device Manager, Tasks. + */ + +/* + * Copyright (C) 2019-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmtask_h +#define VBOX_INCLUDED_vmm_pdmtask_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_task The PDM Tasks API + * @ingroup grp_pdm + * + * A task is a predefined asynchronous procedure call that can be triggered from + * any context. + * + * @{ + */ + +/** PDM task handle. */ +typedef uint64_t PDMTASKHANDLE; +/** NIL PDM task handle. */ +#define NIL_PDMTASKHANDLE UINT64_MAX + + +/** + * Task worker callback for devices. + * + * @param pDevIns The device instance. + * @param pvUser The user parameter. + * @thread Task worker thread. + * @remarks The device critical section will NOT be entered before calling the + * callback. No other locks will be held either. + */ +typedef DECLCALLBACKTYPE(void, FNPDMTASKDEV,(PPDMDEVINS pDevIns, void *pvUser)); +/** Pointer to a FNPDMTASKDEV(). */ +typedef FNPDMTASKDEV *PFNPDMTASKDEV; + +/** + * Task worker callback for drivers. + * + * @param pDrvIns The driver instance. + * @param pvUser The user parameter. + * @thread Task worker thread. + * @remarks No other locks will be held. + */ +typedef DECLCALLBACKTYPE(void, FNPDMTASKDRV,(PPDMDRVINS pDrvIns, void *pvUser)); +/** Pointer to a FNPDMTASKDRV(). */ +typedef FNPDMTASKDRV *PFNPDMTASKDRV; + +/** + * Task worker callback for USB devices. + * + * @param pUsbIns The USB device instance. + * @param pvUser The user parameter. + * @thread Task worker thread. + * @remarks No other locks will be held. + */ +typedef DECLCALLBACKTYPE(void, FNPDMTASKUSB,(PPDMUSBINS pUsbIns, void *pvUser)); +/** Pointer to a FNPDMTASKUSB(). */ +typedef FNPDMTASKUSB *PFNPDMTASKUSB; + +/** + * Task worker callback for internal components. + * + * @param pVM The cross context VM structure. + * @param pvUser The user parameter. + * @thread Task worker thread. + * @remarks No other locks will be held. + */ +typedef DECLCALLBACKTYPE(void, FNPDMTASKINT,(PVM pVM, void *pvUser)); +/** Pointer to a FNPDMTASKINT(). */ +typedef FNPDMTASKINT *PFNPDMTASKINT; + + +/** @name PDMTASK_F_XXX - Task creation flags. + * @{ */ +/** Create a ring-0 triggerable task. */ +#define PDMTASK_F_R0 RT_BIT_32(0) +/** Create a raw-mode triggerable task. */ +#define PDMTASK_F_RC RT_BIT_32(1) +/** Create a ring-0 and raw-mode triggerable task. */ +#define PDMTASK_F_RZ (PDMTASK_F_R0 | PDMTASK_F_RC) +/** Valid flags. */ +#define PDMTASK_F_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +#ifdef VBOX_IN_VMM +/** + * Task owner type. + */ +typedef enum PDMTASKTYPE +{ + /** Invalid zero value. */ + PDMTASKTYPE_INVALID = 0, + /** Device consumer. */ + PDMTASKTYPE_DEV, + /** Driver consumer. */ + PDMTASKTYPE_DRV, + /** USB device consumer. */ + PDMTASKTYPE_USB, + /** Internal consumer. */ + PDMTASKTYPE_INTERNAL, + /** End of valid values. */ + PDMTASKTYPE_END, + /** Typical 32-bit type blowup. */ + PDMTASKTYPE_32BIT_HACK = 0x7fffffff +} PDMTASKTYPE; + +VMMR3_INT_DECL(int) PDMR3TaskCreate(PVM pVM, uint32_t fFlags, const char *pszName, PDMTASKTYPE enmType, void *pvOwner, + PFNRT pfnCallback, void *pvUser, PDMTASKHANDLE *phTask); +VMMR3_INT_DECL(int) PDMR3TaskCreateInternal(PVM pVM, uint32_t fFlags, const char *pszName, + PFNPDMTASKINT pfnCallback, void *pvUser, PDMTASKHANDLE *phTask); +VMMR3_INT_DECL(int) PDMR3TaskDestroyAllByOwner(PVM pVM, PDMTASKTYPE enmType, void *pvOwner); +VMMR3_INT_DECL(int) PDMR3TaskDestroySpecific(PVM pVM, PDMTASKTYPE enmType, void *pvOwner, PDMTASKHANDLE hTask); +VMMR3_INT_DECL(int) PDMR3TaskDestroyInternal(PVM pVM, PDMTASKHANDLE hTask); + +VMM_INT_DECL(int) PDMTaskTrigger(PVMCC pVM, PDMTASKTYPE enmType, RTR3PTR pvOwner, PDMTASKHANDLE hTask); +VMM_INT_DECL(int) PDMTaskTriggerInternal(PVMCC pVM, PDMTASKHANDLE hTask); +#endif /* VBOX_IN_VMM */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmtask_h */ + diff --git a/include/VBox/vmm/pdmthread.h b/include/VBox/vmm/pdmthread.h new file mode 100644 index 00000000..1163f163 --- /dev/null +++ b/include/VBox/vmm/pdmthread.h @@ -0,0 +1,311 @@ +/** @file + * PDM - Pluggable Device Manager, Threads. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmthread_h +#define VBOX_INCLUDED_vmm_pdmthread_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/types.h> +#ifdef IN_RING3 +# include <iprt/thread.h> +#endif + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_thread The PDM Threads API + * @ingroup grp_pdm + * @{ + */ + +/** + * The thread state + */ +typedef enum PDMTHREADSTATE +{ + /** The usual invalid 0 entry. */ + PDMTHREADSTATE_INVALID = 0, + /** The thread is initializing. + * Prev state: none + * Next state: suspended, terminating (error) */ + PDMTHREADSTATE_INITIALIZING, + /** The thread has been asked to suspend. + * Prev state: running + * Next state: suspended */ + PDMTHREADSTATE_SUSPENDING, + /** The thread is supended. + * Prev state: suspending, initializing + * Next state: resuming, terminated. */ + PDMTHREADSTATE_SUSPENDED, + /** The thread is active. + * Prev state: suspended + * Next state: running, terminating. */ + PDMTHREADSTATE_RESUMING, + /** The thread is active. + * Prev state: resuming + * Next state: suspending, terminating. */ + PDMTHREADSTATE_RUNNING, + /** The thread has been asked to terminate. + * Prev state: initializing, suspended, resuming, running + * Next state: terminated. */ + PDMTHREADSTATE_TERMINATING, + /** The thread is terminating / has terminated. + * Prev state: terminating + * Next state: none */ + PDMTHREADSTATE_TERMINATED, + /** The usual 32-bit hack. */ + PDMTHREADSTATE_32BIT_HACK = 0x7fffffff +} PDMTHREADSTATE; + +/** A pointer to a PDM thread. */ +typedef R3PTRTYPE(struct PDMTHREAD *) PPDMTHREAD; +/** A pointer to a pointer to a PDM thread. */ +typedef PPDMTHREAD *PPPDMTHREAD; + +/** + * PDM thread, device variation. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMTHREADDEV,(PPDMDEVINS pDevIns, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADDEV(). */ +typedef FNPDMTHREADDEV *PFNPDMTHREADDEV; + +/** + * PDM thread, USB device variation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMTHREADUSB,(PPDMUSBINS pUsbIns, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADUSB(). */ +typedef FNPDMTHREADUSB *PFNPDMTHREADUSB; + +/** + * PDM thread, driver variation. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMTHREADDRV,(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADDRV(). */ +typedef FNPDMTHREADDRV *PFNPDMTHREADDRV; + +/** + * PDM thread, driver variation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMTHREADINT,(PVM pVM, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADINT(). */ +typedef FNPDMTHREADINT *PFNPDMTHREADINT; + +/** + * PDM thread, driver variation. + * + * @returns VBox status code. + * @param pThread The PDM thread data. + */ +typedef int FNPDMTHREADEXT(PPDMTHREAD pThread); +/** Pointer to a FNPDMTHREADEXT(). */ +typedef FNPDMTHREADEXT *PFNPDMTHREADEXT; + + + +/** + * PDM thread wakeup call, device variation. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMTHREADWAKEUPDEV,(PPDMDEVINS pDevIns, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADDEV(). */ +typedef FNPDMTHREADWAKEUPDEV *PFNPDMTHREADWAKEUPDEV; + +/** + * PDM thread wakeup call, device variation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMTHREADWAKEUPUSB,(PPDMUSBINS pUsbIns, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADUSB(). */ +typedef FNPDMTHREADWAKEUPUSB *PFNPDMTHREADWAKEUPUSB; + +/** + * PDM thread wakeup call, driver variation. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMTHREADWAKEUPDRV,(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADDRV(). */ +typedef FNPDMTHREADWAKEUPDRV *PFNPDMTHREADWAKEUPDRV; + +/** + * PDM thread wakeup call, internal variation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMTHREADWAKEUPINT,(PVM pVM, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADWAKEUPINT(). */ +typedef FNPDMTHREADWAKEUPINT *PFNPDMTHREADWAKEUPINT; + +/** + * PDM thread wakeup call, external variation. + * + * @returns VBox status code. + * @param pThread The PDM thread data. + */ +typedef int FNPDMTHREADWAKEUPEXT(PPDMTHREAD pThread); +/** Pointer to a FNPDMTHREADEXT(). */ +typedef FNPDMTHREADWAKEUPEXT *PFNPDMTHREADWAKEUPEXT; + + +/** + * PDM Thread instance data. + */ +typedef struct PDMTHREAD +{ + /** PDMTHREAD_VERSION. */ + uint32_t u32Version; + /** The thread state. */ + PDMTHREADSTATE volatile enmState; + /** The thread handle. */ + RTTHREAD Thread; + /** The user parameter. */ + R3PTRTYPE(void *) pvUser; + /** Data specific to the kind of thread. + * This should really be in PDMTHREADINT, but is placed here because of the + * function pointer typedefs. So, don't touch these, please. + */ + union + { + /** PDMTHREADTYPE_DEVICE data. */ + struct + { + /** The device instance. */ + PPDMDEVINSR3 pDevIns; + /** The thread function. */ + R3PTRTYPE(PFNPDMTHREADDEV) pfnThread; + /** Thread. */ + R3PTRTYPE(PFNPDMTHREADWAKEUPDEV) pfnWakeUp; + } Dev; + + /** PDMTHREADTYPE_USB data. */ + struct + { + /** The device instance. */ + PPDMUSBINS pUsbIns; + /** The thread function. */ + R3PTRTYPE(PFNPDMTHREADUSB) pfnThread; + /** Thread. */ + R3PTRTYPE(PFNPDMTHREADWAKEUPUSB) pfnWakeUp; + } Usb; + + /** PDMTHREADTYPE_DRIVER data. */ + struct + { + /** The driver instance. */ + R3PTRTYPE(PPDMDRVINS) pDrvIns; + /** The thread function. */ + R3PTRTYPE(PFNPDMTHREADDRV) pfnThread; + /** Thread. */ + R3PTRTYPE(PFNPDMTHREADWAKEUPDRV) pfnWakeUp; + } Drv; + + /** PDMTHREADTYPE_INTERNAL data. */ + struct + { + /** The thread function. */ + R3PTRTYPE(PFNPDMTHREADINT) pfnThread; + /** Thread. */ + R3PTRTYPE(PFNPDMTHREADWAKEUPINT) pfnWakeUp; + } Int; + + /** PDMTHREADTYPE_EXTERNAL data. */ + struct + { + /** The thread function. */ + R3PTRTYPE(PFNPDMTHREADEXT) pfnThread; + /** Thread. */ + R3PTRTYPE(PFNPDMTHREADWAKEUPEXT) pfnWakeUp; + } Ext; + } u; + + /** Internal data. */ + union + { +#ifdef PDMTHREADINT_DECLARED + PDMTHREADINT s; +#endif + uint8_t padding[64]; + } Internal; +} PDMTHREAD; + +/** PDMTHREAD::u32Version value. */ +#define PDMTHREAD_VERSION PDM_VERSION_MAKE(0xefff, 1, 0) + +#ifdef IN_RING3 +VMMR3DECL(int) PDMR3ThreadCreate(PVM pVM, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADINT pfnThread, + PFNPDMTHREADWAKEUPINT pfnWakeUp, size_t cbStack, RTTHREADTYPE enmType, const char *pszName); +VMMR3DECL(int) PDMR3ThreadCreateExternal(PVM pVM, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADEXT pfnThread, + PFNPDMTHREADWAKEUPEXT pfnWakeUp, size_t cbStack, RTTHREADTYPE enmType, const char *pszName); +VMMR3DECL(int) PDMR3ThreadDestroy(PPDMTHREAD pThread, int *pRcThread); +VMMR3DECL(int) PDMR3ThreadIAmSuspending(PPDMTHREAD pThread); +VMMR3DECL(int) PDMR3ThreadIAmRunning(PPDMTHREAD pThread); +VMMR3DECL(int) PDMR3ThreadSleep(PPDMTHREAD pThread, RTMSINTERVAL cMillies); +VMMR3DECL(int) PDMR3ThreadSuspend(PPDMTHREAD pThread); +VMMR3DECL(int) PDMR3ThreadResume(PPDMTHREAD pThread); +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmthread_h */ diff --git a/include/VBox/vmm/pdmtpmifs.h b/include/VBox/vmm/pdmtpmifs.h new file mode 100644 index 00000000..22a15839 --- /dev/null +++ b/include/VBox/vmm/pdmtpmifs.h @@ -0,0 +1,163 @@ +/** @file + * PDM - Pluggable Device Manager, TPM related interfaces. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmtpmifs_h +#define VBOX_INCLUDED_vmm_pdmtpmifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_ifs_tpm PDM TPM Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + + +/** Pointer to a TPM port interface. */ +typedef struct PDMITPMPORT *PPDMITPMPORT; +/** + * TPM port interface (down). + */ +typedef struct PDMITPMPORT +{ + /** + * @todo + */ + DECLR3CALLBACKMEMBER(int, pfnDummy, (PPDMITPMPORT pInterface)); + +} PDMITPMPORT; +/** PDMITPMPORT interface ID. */ +#define PDMITPMPORT_IID "1e57710f-f820-47ec-afa6-2713195f8f94" + + +/** + * TPM version enumeration. + */ +typedef enum TPMVERSION +{ + /** Invalid TPM version, don't use. */ + TPMVERSION_INVALID = 0, + /** TPM works according to version 1.2 of the specification. */ + TPMVERSION_1_2, + /** TPM works according to version 2.0 of the specification. */ + TPMVERSION_2_0, + /** TPM version is unknown. */ + TPMVERSION_UNKNOWN +} TPMVERSION; + + +/** Pointer to a TPM interface. */ +typedef struct PDMITPMCONNECTOR *PPDMITPMCONNECTOR; +/** + * TPM interface (up). + * Pairs with PDMITPMPORT. + */ +typedef struct PDMITPMCONNECTOR +{ + /** + * Returns the version of the TPM implemented by the driver below. + * + * @returns The TPM version. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(TPMVERSION, pfnGetVersion, (PPDMITPMCONNECTOR pInterface)); + + /** + * Returns the maximum supported locality of the driver below. + * + * @returns The maximum supported locality (0-4). + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetLocalityMax, (PPDMITPMCONNECTOR pInterface)); + + /** + * Returns the command/response buffer size of the driver below. + * + * @returns Buffer size in bytes. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetBufferSize, (PPDMITPMCONNECTOR pInterface)); + + /** + * Returns the status of the established flag. + * + * @returns Status of the established flag. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(bool, pfnGetEstablishedFlag, (PPDMITPMCONNECTOR pInterface)); + + /** + * Resets the TPM established flag. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param bLoc The locality issuing this request. + */ + DECLR3CALLBACKMEMBER(int, pfnResetEstablishedFlag, (PPDMITPMCONNECTOR pInterface, uint8_t bLoc)); + + /** + * Executes the given command. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param bLoc The locality the command is issued from. + * @param pvCmd Pointer to the command data. + * @param cbCmd Size of the command in bytes. + * @param pvResp Where to store the response data. + * @param cbResp Size of the response buffer in bytes. + */ + DECLR3CALLBACKMEMBER(int, pfnCmdExec, (PPDMITPMCONNECTOR pInterface, uint8_t bLoc, const void *pvCmd, size_t cbCmd, void *pvResp, size_t cbResp)); + + /** + * Cancels the currently executed command. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnCmdCancel, (PPDMITPMCONNECTOR pInterface)); + +} PDMITPMCONNECTOR; +/** PDMITPMCONNECTOR interface ID. */ +#define PDMITPMCONNECTOR_IID "30afefd8-c11f-4e2a-a746-424e3d99fa86" + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmtpmifs_h */ diff --git a/include/VBox/vmm/pdmusb.h b/include/VBox/vmm/pdmusb.h new file mode 100644 index 00000000..c27c33a7 --- /dev/null +++ b/include/VBox/vmm/pdmusb.h @@ -0,0 +1,1502 @@ +/** @file + * PDM - Pluggable Device Manager, USB Devices. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmusb_h +#define VBOX_INCLUDED_vmm_pdmusb_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/pdmqueue.h> +#include <VBox/vmm/pdmcritsect.h> +#include <VBox/vmm/pdmthread.h> +#include <VBox/vmm/pdmifs.h> +#include <VBox/vmm/pdmins.h> +#include <VBox/vmm/pdmcommon.h> +#include <VBox/vmm/tm.h> +#include <VBox/vmm/ssm.h> +#include <VBox/vmm/cfgm.h> +#include <VBox/vmm/dbgf.h> +#include <VBox/vmm/mm.h> +#include <VBox/vusb.h> +#include <iprt/errcore.h> +#include <iprt/stdarg.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_usbdev The USB Devices API + * @ingroup grp_pdm + * @{ + */ + + +/** + * A string entry for the USB descriptor cache. + */ +typedef struct PDMUSBDESCCACHESTRING +{ + /** The string index. */ + uint8_t idx; + /** The UTF-8 representation of the string. */ + const char *psz; +} PDMUSBDESCCACHESTRING; +/** Pointer to a const string entry. */ +typedef PDMUSBDESCCACHESTRING const *PCPDMUSBDESCCACHESTRING; + + +/** + * A language entry for the USB descriptor cache. + */ +typedef struct PDMUSBDESCCACHELANG +{ + /** The language ID for the strings in this block. */ + uint16_t idLang; + /** The number of strings in the array. */ + uint16_t cStrings; + /** Pointer to an array of associated strings. + * This must be sorted in ascending order by string index as a binary lookup + * will be performed. */ + PCPDMUSBDESCCACHESTRING paStrings; +} PDMUSBDESCCACHELANG; +/** Pointer to a const language entry. */ +typedef PDMUSBDESCCACHELANG const *PCPDMUSBDESCCACHELANG; + + +/** + * USB descriptor cache. + * + * This structure is owned by the USB device but provided to the PDM/VUSB layer + * thru the PDMUSBREG::pfnGetDescriptorCache method. PDM/VUSB will use the + * information here to map addresses to endpoints, perform SET_CONFIGURATION + * requests, and optionally perform GET_DESCRIPTOR requests (see flag). + * + * Currently, only device and configuration descriptors are cached. + */ +typedef struct PDMUSBDESCCACHE +{ + /** USB device descriptor */ + PCVUSBDESCDEVICE pDevice; + /** USB Descriptor arrays (pDev->bNumConfigurations) */ + PCVUSBDESCCONFIGEX paConfigs; + /** Language IDs and their associated strings. + * This must be sorted in ascending order by language ID as a binary lookup + * will be used. */ + PCPDMUSBDESCCACHELANG paLanguages; + /** The number of entries in the array pointed to by paLanguages. */ + uint16_t cLanguages; + /** Use the cached descriptors for GET_DESCRIPTOR requests. */ + bool fUseCachedDescriptors; + /** Use the cached string descriptors. */ + bool fUseCachedStringsDescriptors; +} PDMUSBDESCCACHE; +/** Pointer to an USB descriptor cache. */ +typedef PDMUSBDESCCACHE *PPDMUSBDESCCACHE; +/** Pointer to a const USB descriptor cache. */ +typedef const PDMUSBDESCCACHE *PCPDMUSBDESCCACHE; + + +/** PDM Device Flags. + * @{ */ +/** A high-speed capable USB 2.0 device (also required to support full-speed). */ +#define PDM_USBREG_HIGHSPEED_CAPABLE RT_BIT(0) +/** Indicates that the device implements the saved state handlers. */ +#define PDM_USBREG_SAVED_STATE_SUPPORTED RT_BIT(1) +/** A SuperSpeed USB 3.0 device. */ +#define PDM_USBREG_SUPERSPEED_CAPABLE RT_BIT(2) +/** @} */ + +/** PDM USB Device Registration Structure, + * + * This structure is used when registering a device from VBoxUsbRegister() in HC Ring-3. + * The PDM will make use of this structure until the VM is destroyed. + */ +typedef struct PDMUSBREG +{ + /** Structure version. PDM_DEVREG_VERSION defines the current version. */ + uint32_t u32Version; + /** Device name. */ + char szName[32]; + /** The description of the device. The UTF-8 string pointed to shall, like this structure, + * remain unchanged from registration till VM destruction. */ + const char *pszDescription; + + /** Flags, combination of the PDM_USBREG_FLAGS_* \#defines. */ + RTUINT fFlags; + /** Maximum number of instances (per VM). */ + RTUINT cMaxInstances; + /** Size of the instance data. */ + RTUINT cbInstance; + + + /** + * Construct an USB device instance for a VM. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * If the registration structure is needed, it will be + * accessible thru pUsbDev->pReg. + * @param iInstance Instance number. Use this to figure out which registers + * and such to use. The instance number is also found in + * pUsbDev->iInstance, but since it's likely to be + * frequently used PDM passes it as parameter. + * @param pCfg Configuration node handle for the device. Use this to + * obtain the configuration of the device instance. It is + * also found in pUsbDev->pCfg, but since it is primary + * usage will in this function it is passed as a parameter. + * @param pCfgGlobal Handle to the global device configuration. Also found + * in pUsbDev->pCfgGlobal. + * @remarks This callback is required. + */ + DECLR3CALLBACKMEMBER(int, pfnConstruct,(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)); + + /** + * Destruct an USB device instance. + * + * Most VM resources are freed by the VM. This callback is provided so that any non-VM + * resources can be freed correctly. + * + * This method will be called regardless of the pfnConstruct result to avoid + * complicated failure paths. + * + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnDestruct,(PPDMUSBINS pUsbIns)); + + + /** + * Init complete notification. + * + * This can be done to do communication with other devices and other + * initialization which requires everything to be in place. + * + * @returns VBOX status code. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + * @remarks Not called when hotplugged. + */ + DECLR3CALLBACKMEMBER(int, pfnVMInitComplete,(PPDMUSBINS pUsbIns)); + + /** + * VM Power On notification. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnVMPowerOn,(PPDMUSBINS pUsbIns)); + + /** + * VM Reset notification. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnVMReset,(PPDMUSBINS pUsbIns)); + + /** + * VM Suspend notification. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnVMSuspend,(PPDMUSBINS pUsbIns)); + + /** + * VM Resume notification. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnVMResume,(PPDMUSBINS pUsbIns)); + + /** + * VM Power Off notification. + * + * This is only called when the VMR3PowerOff call is made on a running VM. This + * means that there is no notification if the VM was suspended before being + * powered of. There will also be no callback when hot plugging devices. + * + * @param pUsbIns The USB device instance data. + */ + DECLR3CALLBACKMEMBER(void, pfnVMPowerOff,(PPDMUSBINS pUsbIns)); + + /** + * Called after the constructor when attaching a device at run time. + * + * This can be used to do tasks normally assigned to pfnInitComplete and/or pfnVMPowerOn. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnHotPlugged,(PPDMUSBINS pUsbIns)); + + /** + * Called before the destructor when a device is unplugged at run time. + * + * This can be used to do tasks normally assigned to pfnVMSuspend and/or pfnVMPowerOff. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnHotUnplugged,(PPDMUSBINS pUsbIns)); + /** + * Driver Attach command. + * + * This is called to let the USB device attach to a driver for a specified LUN + * at runtime. This is not called during VM construction, the device constructor + * have to attach to all the available drivers. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance data. + * @param iLUN The logical unit which is being detached. + * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnDriverAttach,(PPDMUSBINS pUsbIns, unsigned iLUN, uint32_t fFlags)); + + /** + * Driver Detach notification. + * + * This is called when a driver is detaching itself from a LUN of the device. + * The device should adjust it's state to reflect this. + * + * @param pUsbIns The USB device instance data. + * @param iLUN The logical unit which is being detached. + * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnDriverDetach,(PPDMUSBINS pUsbIns, unsigned iLUN, uint32_t fFlags)); + + /** + * Query the base interface of a logical unit. + * + * @returns VBOX status code. + * @param pUsbIns The USB device instance data. + * @param iLUN The logicial unit to query. + * @param ppBase Where to store the pointer to the base interface of the LUN. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryInterface,(PPDMUSBINS pUsbIns, unsigned iLUN, PPDMIBASE *ppBase)); + + /** + * Requests the USB device to reset. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param fResetOnLinux A hint to the usb proxy. + * Don't use this unless you're the linux proxy device. + * @thread Any thread. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnUsbReset,(PPDMUSBINS pUsbIns, bool fResetOnLinux)); + + /** + * Query device and configuration descriptors for the caching and servicing + * relevant GET_DESCRIPTOR requests. + * + * @returns Pointer to the descriptor cache (read-only). + * @param pUsbIns The USB device instance. + * @remarks Mandatory. + */ + DECLR3CALLBACKMEMBER(PCPDMUSBDESCCACHE, pfnUsbGetDescriptorCache,(PPDMUSBINS pUsbIns)); + + /** + * SET_CONFIGURATION request. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param bConfigurationValue The bConfigurationValue of the new configuration. + * @param pvOldCfgDesc Internal - for the device proxy. + * @param pvOldIfState Internal - for the device proxy. + * @param pvNewCfgDesc Internal - for the device proxy. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnUsbSetConfiguration,(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue, + const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)); + + /** + * SET_INTERFACE request. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param bInterfaceNumber The interface number. + * @param bAlternateSetting The alternate setting. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnUsbSetInterface,(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)); + + /** + * Clears the halted state of an endpoint. (Optional) + * + * This called when VUSB sees a CLEAR_FEATURE(ENDPOINT_HALT) on request + * on the zero pipe. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param uEndpoint The endpoint to clear. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnUsbClearHaltedEndpoint,(PPDMUSBINS pUsbIns, unsigned uEndpoint)); + + /** + * Allocates an URB. + * + * This can be used to make use of shared user/kernel mode buffers. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param cbData The size of the data buffer. + * @param cTds The number of TDs. + * @param enmType The type of URB. + * @param ppUrb Where to store the allocated URB. + * @remarks Optional. + * @remarks Not implemented yet. + */ + DECLR3CALLBACKMEMBER(int, pfnUrbNew,(PPDMUSBINS pUsbIns, size_t cbData, size_t cTds, VUSBXFERTYPE enmType, PVUSBURB *ppUrb)); + + /** + * Queues an URB for processing. + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_VUSB_DEVICE_NOT_ATTACHED if the device has been disconnected. + * @retval VERR_VUSB_FAILED_TO_QUEUE_URB as a general failure kind of thing. + * @retval TBD - document new stuff! + * + * @param pUsbIns The USB device instance. + * @param pUrb The URB to process. + * @remarks Mandatory. + */ + DECLR3CALLBACKMEMBER(int, pfnUrbQueue,(PPDMUSBINS pUsbIns, PVUSBURB pUrb)); + + /** + * Cancels an URB. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param pUrb The URB to cancel. + * @remarks Mandatory. + */ + DECLR3CALLBACKMEMBER(int, pfnUrbCancel,(PPDMUSBINS pUsbIns, PVUSBURB pUrb)); + + /** + * Reaps an URB. + * + * @returns A ripe URB, NULL if none. + * @param pUsbIns The USB device instance. + * @param cMillies How log to wait for an URB to become ripe. + * @remarks Mandatory. + */ + DECLR3CALLBACKMEMBER(PVUSBURB, pfnUrbReap,(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)); + + /** + * Wakes a thread waiting in pfnUrbReap. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + */ + DECLR3CALLBACKMEMBER(int, pfnWakeup,(PPDMUSBINS pUsbIns)); + + /** Just some init precaution. Must be set to PDM_USBREG_VERSION. */ + uint32_t u32TheEnd; +} PDMUSBREG; +/** Pointer to a PDM USB Device Structure. */ +typedef PDMUSBREG *PPDMUSBREG; +/** Const pointer to a PDM USB Device Structure. */ +typedef PDMUSBREG const *PCPDMUSBREG; + +/** Current USBREG version number. */ +#define PDM_USBREG_VERSION PDM_VERSION_MAKE(0xeeff, 2, 0) + +/** PDM USB Device Flags. + * @{ */ +/* none yet */ +/** @} */ + + +#ifdef IN_RING3 + +/** + * PDM USB Device API. + */ +typedef struct PDMUSBHLP +{ + /** Structure version. PDM_USBHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Attaches a driver (chain) to the USB device. + * + * The first call for a LUN this will serve as a registration of the LUN. The pBaseInterface and + * the pszDesc string will be registered with that LUN and kept around for PDMR3QueryUSBDeviceLun(). + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param iLun The logical unit to attach. + * @param pBaseInterface Pointer to the base interface for that LUN. (device side / down) + * @param ppBaseInterface Where to store the pointer to the base interface. (driver side / up) + * @param pszDesc Pointer to a string describing the LUN. This string must remain valid + * for the live of the device instance. + */ + DECLR3CALLBACKMEMBER(int, pfnDriverAttach,(PPDMUSBINS pUsbIns, RTUINT iLun, PPDMIBASE pBaseInterface, PPDMIBASE *ppBaseInterface, const char *pszDesc)); + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pUsbIns The USB device instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertEMT,(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pUsbIns The USB device instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertOther,(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Stops the VM and enters the debugger to look at the guest state. + * + * Use the PDMUsbDBGFStop() inline function with the RT_SRC_POS macro instead of + * invoking this function directly. + * + * @returns VBox status code which must be passed up to the VMM. + * @param pUsbIns The USB device instance. + * @param pszFile Filename of the assertion location. + * @param iLine The linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + * @param pszFormat Message. (optional) + * @param va Message parameters. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFStopV,(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0)); + + /** + * Register a info handler with DBGF, argv style. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param pszName The identifier of the info. + * @param pszDesc The description of the info and any arguments the handler may take. + * @param pfnHandler The handler function to be called to display the info. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFInfoRegisterArgv,(PPDMUSBINS pUsbIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVUSB pfnHandler)); + + /** + * Allocate memory which is associated with current VM instance + * and automatically freed on it's destruction. + * + * @returns Pointer to allocated memory. The memory is *NOT* zero-ed. + * @param pUsbIns The USB device instance. + * @param cb Number of bytes to allocate. + */ + DECLR3CALLBACKMEMBER(void *, pfnMMHeapAlloc,(PPDMUSBINS pUsbIns, size_t cb)); + + /** + * Allocate memory which is associated with current VM instance + * and automatically freed on it's destruction. The memory is ZEROed. + * + * @returns Pointer to allocated memory. The memory is *NOT* zero-ed. + * @param pUsbIns The USB device instance. + * @param cb Number of bytes to allocate. + */ + DECLR3CALLBACKMEMBER(void *, pfnMMHeapAllocZ,(PPDMUSBINS pUsbIns, size_t cb)); + + /** + * Free memory allocated with pfnMMHeapAlloc() and pfnMMHeapAllocZ(). + * + * @param pUsbIns The USB device instance. + * @param pv Pointer to the memory to free. + */ + DECLR3CALLBACKMEMBER(void, pfnMMHeapFree,(PPDMUSBINS pUsbIns, void *pv)); + + /** + * Create a queue. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param cbItem Size a queue item. + * @param cItems Number of items in the queue. + * @param cMilliesInterval Number of milliseconds between polling the queue. + * If 0 then the emulation thread will be notified whenever an item arrives. + * @param pfnCallback The consumer function. + * @param pszName The queue base name. The instance number will be + * appended automatically. + * @param ppQueue Where to store the queue handle on success. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPDMQueueCreate,(PPDMUSBINS pUsbIns, RTUINT cbItem, RTUINT cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEUSB pfnCallback, const char *pszName, PPDMQUEUE *ppQueue)); + + /** + * Register a save state data unit. + * + * @returns VBox status. + * @param pUsbIns The USB device instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * + * @param pfnLivePrep Prepare live save callback, optional. + * @param pfnLiveExec Execute live save callback, optional. + * @param pfnLiveVote Vote live save callback, optional. + * + * @param pfnSavePrep Prepare save callback, optional. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnSaveDone Done save callback, optional. + * + * @param pfnLoadPrep Prepare load callback, optional. + * @param pfnLoadExec Execute load callback, optional. + * @param pfnLoadDone Done load callback, optional. + */ + DECLR3CALLBACKMEMBER(int, pfnSSMRegister,(PPDMUSBINS pUsbIns, uint32_t uVersion, size_t cbGuess, + PFNSSMUSBLIVEPREP pfnLivePrep, PFNSSMUSBLIVEEXEC pfnLiveExec, PFNSSMUSBLIVEVOTE pfnLiveVote, + PFNSSMUSBSAVEPREP pfnSavePrep, PFNSSMUSBSAVEEXEC pfnSaveExec, PFNSSMUSBSAVEDONE pfnSaveDone, + PFNSSMUSBLOADPREP pfnLoadPrep, PFNSSMUSBLOADEXEC pfnLoadExec, PFNSSMUSBLOADDONE pfnLoadDone)); + + /** @name Exported SSM Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnSSMPutStruct,(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStructEx,(PSSMHANDLE pSSM, const void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutBool,(PSSMHANDLE pSSM, bool fBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU8,(PSSMHANDLE pSSM, uint8_t u8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS8,(PSSMHANDLE pSSM, int8_t i8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU16,(PSSMHANDLE pSSM, uint16_t u16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS16,(PSSMHANDLE pSSM, int16_t i16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU32,(PSSMHANDLE pSSM, uint32_t u32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS32,(PSSMHANDLE pSSM, int32_t i32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU64,(PSSMHANDLE pSSM, uint64_t u64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS64,(PSSMHANDLE pSSM, int64_t i64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU128,(PSSMHANDLE pSSM, uint128_t u128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS128,(PSSMHANDLE pSSM, int128_t i128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutUInt,(PSSMHANDLE pSSM, RTUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSInt,(PSSMHANDLE pSSM, RTINT i)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUInt,(PSSMHANDLE pSSM, RTGCUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntReg,(PSSMHANDLE pSSM, RTGCUINTREG u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys32,(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys64,(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys,(PSSMHANDLE pSSM, RTGCPHYS GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPtr,(PSSMHANDLE pSSM, RTGCPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntPtr,(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutRCPtr,(PSSMHANDLE pSSM, RTRCPTR RCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutIOPort,(PSSMHANDLE pSSM, RTIOPORT IOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSel,(PSSMHANDLE pSSM, RTSEL Sel)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutMem,(PSSMHANDLE pSSM, const void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStrZ,(PSSMHANDLE pSSM, const char *psz)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStruct,(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStructEx,(PSSMHANDLE pSSM, void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBool,(PSSMHANDLE pSSM, bool *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBoolV,(PSSMHANDLE pSSM, bool volatile *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8,(PSSMHANDLE pSSM, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8V,(PSSMHANDLE pSSM, uint8_t volatile *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8,(PSSMHANDLE pSSM, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8V,(PSSMHANDLE pSSM, int8_t volatile *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16,(PSSMHANDLE pSSM, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16V,(PSSMHANDLE pSSM, uint16_t volatile *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16,(PSSMHANDLE pSSM, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16V,(PSSMHANDLE pSSM, int16_t volatile *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32,(PSSMHANDLE pSSM, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32V,(PSSMHANDLE pSSM, uint32_t volatile *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32,(PSSMHANDLE pSSM, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32V,(PSSMHANDLE pSSM, int32_t volatile *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64,(PSSMHANDLE pSSM, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64V,(PSSMHANDLE pSSM, uint64_t volatile *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64,(PSSMHANDLE pSSM, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64V,(PSSMHANDLE pSSM, int64_t volatile *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128,(PSSMHANDLE pSSM, uint128_t *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128V,(PSSMHANDLE pSSM, uint128_t volatile *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128,(PSSMHANDLE pSSM, int128_t *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128V,(PSSMHANDLE pSSM, int128_t volatile *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32,(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32V,(PSSMHANDLE pSSM, RTGCPHYS32 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64,(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64V,(PSSMHANDLE pSSM, RTGCPHYS64 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys,(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhysV,(PSSMHANDLE pSSM, RTGCPHYS volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetUInt,(PSSMHANDLE pSSM, PRTUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSInt,(PSSMHANDLE pSSM, PRTINT pi)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUInt,(PSSMHANDLE pSSM, PRTGCUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntReg,(PSSMHANDLE pSSM, PRTGCUINTREG pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPtr,(PSSMHANDLE pSSM, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntPtr,(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetRCPtr,(PSSMHANDLE pSSM, PRTRCPTR pRCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetIOPort,(PSSMHANDLE pSSM, PRTIOPORT pIOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSel,(PSSMHANDLE pSSM, PRTSEL pSel)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetMem,(PSSMHANDLE pSSM, void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZ,(PSSMHANDLE pSSM, char *psz, size_t cbMax)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZEx,(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkip,(PSSMHANDLE pSSM, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkipToEndOfUnit,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadError,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadErrorV,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgError,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgErrorV,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMHandleGetStatus,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(SSMAFTER, pfnSSMHandleGetAfter,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(bool, pfnSSMHandleIsLiveSave,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleMaxDowntime,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleHostBits,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleRevision,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleVersion,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(const char *, pfnSSMHandleHostOSAndArch,(PSSMHANDLE pSSM)); + /** @} */ + + /** @name Exported CFGM Functions. + * @{ */ + DECLR3CALLBACKMEMBER(bool, pfnCFGMExists,( PCFGMNODE pNode, const char *pszName)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryType,( PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySize,( PCFGMNODE pNode, const char *pszName, size_t *pcb)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryInteger,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryIntegerDef,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryString,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringDef,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBytes,( PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64Def,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64,( PCFGMNODE pNode, const char *pszName, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64Def,( PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32Def,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32,( PCFGMNODE pNode, const char *pszName, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32Def,( PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16Def,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16,( PCFGMNODE pNode, const char *pszName, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16Def,( PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8Def,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8,( PCFGMNODE pNode, const char *pszName, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8Def,( PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBool,( PCFGMNODE pNode, const char *pszName, bool *pf)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBoolDef,( PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPort,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPortDef,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUInt,( PCFGMNODE pNode, const char *pszName, unsigned int *pu)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUIntDef,( PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySInt,( PCFGMNODE pNode, const char *pszName, signed int *pi)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySIntDef,( PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtr,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrDef,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrU,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrUDef,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrS,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrSDef,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAlloc,( PCFGMNODE pNode, const char *pszName, char **ppszString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAllocDef,(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetParent,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChild,(PCFGMNODE pNode, const char *pszPath)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildF,(PCFGMNODE pNode, const char *pszPathFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildFV,(PCFGMNODE pNode, const char *pszPathFormat, va_list Args) RT_IPRT_FORMAT_ATTR(3, 0)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetFirstChild,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetNextChild,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetName,(PCFGMNODE pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetNameLen,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreChildrenValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetFirstValue,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetNextValue,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetValueName,(PCFGMLEAF pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetValueNameLen,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(CFGMVALUETYPE, pfnCFGMGetValueType,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreValuesValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(int, pfnCFGMValidateConfig,(PCFGMNODE pNode, const char *pszNode, + const char *pszValidValues, const char *pszValidNodes, + const char *pszWho, uint32_t uInstance)); + /** @} */ + + /** + * Register a STAM sample. + * + * Use the PDMUsbHlpSTAMRegister wrapper. + * + * @returns VBox status. + * @param pUsbIns The USB device instance. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + * @param pszName The sample name format string. + * @param va Arguments to the format string. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegisterV,(PPDMUSBINS pUsbIns, void *pvSample, STAMTYPE enmType, + STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, const char *pszDesc, + const char *pszName, va_list va) RT_IPRT_FORMAT_ATTR(7, 0)); + + /** + * Creates a timer. + * + * @returns VBox status. + * @param pUsbIns The USB device instance. + * @param enmClock The clock to use on this timer. + * @param pfnCallback Callback function. + * @param pvUser User argument for the callback. + * @param fFlags Flags, see TMTIMER_FLAGS_*. + * @param pszDesc Pointer to description string which must stay around + * until the timer is fully destroyed (i.e. a bit after TMTimerDestroy()). + * @param phTimer Where to store the timer handle on success. + */ + DECLR3CALLBACKMEMBER(int, pfnTimerCreate,(PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer)); + + /** @name Timer handle method wrappers + * @{ */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromMicro,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromMilli,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromNano,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGet,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGetFreq,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGetNano,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(bool, pfnTimerIsActive,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(bool, pfnTimerIsLockOwner,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(int, pfnTimerLockClock,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + /** Takes the clock lock then enters the specified critical section. */ + DECLR3CALLBACKMEMBER(int, pfnTimerLockClock2,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnTimerSet,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t uExpire)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetFrequencyHint,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint32_t uHz)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetMicro,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetMillies,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetNano,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetRelative,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now)); + DECLR3CALLBACKMEMBER(int, pfnTimerStop,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(void, pfnTimerUnlockClock,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(void, pfnTimerUnlockClock2,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetCritSect,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnTimerSave,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnTimerLoad,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnTimerDestroy,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + /** @sa TMR3TimerSkip */ + DECLR3CALLBACKMEMBER(int, pfnTimerSkipLoad,(PSSMHANDLE pSSM, bool *pfActive)); + /** @} */ + + /** + * Set the VM error message + * + * @returns rc. + * @param pUsbIns The USB device instance. + * @param rc VBox status code. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetErrorV,(PPDMUSBINS pUsbIns, int rc, RT_SRC_POS_DECL, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetRuntimeErrorV,(PPDMUSBINS pUsbIns, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(4, 0)); + + /** + * Gets the VM state. + * + * @returns VM state. + * @param pUsbIns The USB device instance. + * @thread Any thread (just keep in mind that it's volatile info). + */ + DECLR3CALLBACKMEMBER(VMSTATE, pfnVMState, (PPDMUSBINS pUsbIns)); + + /** + * Creates a PDM thread. + * + * This differs from the RTThreadCreate() API in that PDM takes care of suspending, + * resuming, and destroying the thread as the VM state changes. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param ppThread Where to store the thread 'handle'. + * @param pvUser The user argument to the thread function. + * @param pfnThread The thread function. + * @param pfnWakeup The wakup callback. This is called on the EMT + * thread when a state change is pending. + * @param cbStack See RTThreadCreate. + * @param enmType See RTThreadCreate. + * @param pszName See RTThreadCreate. + */ + DECLR3CALLBACKMEMBER(int, pfnThreadCreate,(PPDMUSBINS pUsbIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADUSB pfnThread, + PFNPDMTHREADWAKEUPUSB pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)); + + /** @name Exported PDM Thread Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnThreadDestroy,(PPDMTHREAD pThread, int *pRcThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmSuspending,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmRunning,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadSleep,(PPDMTHREAD pThread, RTMSINTERVAL cMillies)); + DECLR3CALLBACKMEMBER(int, pfnThreadSuspend,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadResume,(PPDMTHREAD pThread)); + /** @} */ + + /** + * Set up asynchronous handling of a suspend, reset or power off notification. + * + * This shall only be called when getting the notification. It must be called + * for each one. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param pfnAsyncNotify The callback. + * @thread EMT(0) + */ + DECLR3CALLBACKMEMBER(int, pfnSetAsyncNotification, (PPDMUSBINS pUSbIns, PFNPDMUSBASYNCNOTIFY pfnAsyncNotify)); + + /** + * Notify EMT(0) that the device has completed the asynchronous notification + * handling. + * + * This can be called at any time, spurious calls will simply be ignored. + * + * @param pUsbIns The USB device instance. + * @thread Any + */ + DECLR3CALLBACKMEMBER(void, pfnAsyncNotificationCompleted, (PPDMUSBINS pUsbIns)); + + /** + * Gets the reason for the most recent VM suspend. + * + * @returns The suspend reason. VMSUSPENDREASON_INVALID is returned if no + * suspend has been made or if the pUsbIns is invalid. + * @param pUsbIns The driver instance. + */ + DECLR3CALLBACKMEMBER(VMSUSPENDREASON, pfnVMGetSuspendReason,(PPDMUSBINS pUsbIns)); + + /** + * Gets the reason for the most recent VM resume. + * + * @returns The resume reason. VMRESUMEREASON_INVALID is returned if no + * resume has been made or if the pUsbIns is invalid. + * @param pUsbIns The driver instance. + */ + DECLR3CALLBACKMEMBER(VMRESUMEREASON, pfnVMGetResumeReason,(PPDMUSBINS pUsbIns)); + + /** + * Queries a generic object from the VMM user. + * + * @returns Pointer to the object if found, NULL if not. + * @param pUsbIns The USB device instance. + * @param pUuid The UUID of what's being queried. The UUIDs and + * the usage conventions are defined by the user. + */ + DECLR3CALLBACKMEMBER(void *, pfnQueryGenericUserObject,(PPDMUSBINS pUsbIns, PCRTUUID pUuid)); + + /** @name Space reserved for minor interface changes. + * @{ */ + DECLR3CALLBACKMEMBER(void, pfnReserved0,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved1,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved2,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved3,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved4,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved5,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved6,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved7,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved8,(PPDMUSBINS pUsbIns)); + /** @} */ + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMUSBHLP; +/** Pointer PDM USB Device API. */ +typedef PDMUSBHLP *PPDMUSBHLP; +/** Pointer const PDM USB Device API. */ +typedef const PDMUSBHLP *PCPDMUSBHLP; + +/** Current USBHLP version number. */ +#define PDM_USBHLP_VERSION PDM_VERSION_MAKE(0xeefe, 7, 0) + +#endif /* IN_RING3 */ + +/** + * PDM USB Device Instance. + */ +typedef struct PDMUSBINS +{ + /** Structure version. PDM_USBINS_VERSION defines the current version. */ + uint32_t u32Version; + /** USB device instance number. */ + uint32_t iInstance; + /** The base interface of the device. + * The device constructor initializes this if it has any device level + * interfaces to export. To obtain this interface call PDMR3QueryUSBDevice(). */ + PDMIBASE IBase; +#if HC_ARCH_BITS == 32 + uint32_t u32Alignment; /**< Alignment padding. */ +#endif + + /** Internal data. */ + union + { +#ifdef PDMUSBINSINT_DECLARED + PDMUSBINSINT s; +#endif + uint8_t padding[HC_ARCH_BITS == 32 ? 96 : 128]; + } Internal; + + /** Pointer the PDM USB Device API. */ + R3PTRTYPE(PCPDMUSBHLP) pHlpR3; + /** Pointer to the USB device registration structure. */ + R3PTRTYPE(PCPDMUSBREG) pReg; + /** Configuration handle. */ + R3PTRTYPE(PCFGMNODE) pCfg; + /** The (device) global configuration handle. */ + R3PTRTYPE(PCFGMNODE) pCfgGlobal; + /** Pointer to device instance data. */ + R3PTRTYPE(void *) pvInstanceDataR3; + /** Pointer to the VUSB Device structure. + * Internal to VUSB, don't touch. + * @todo Moved this to PDMUSBINSINT. */ + R3PTRTYPE(void *) pvVUsbDev2; + /** Device name for using when logging. + * The constructor sets this and the destructor frees it. */ + R3PTRTYPE(char *) pszName; + /** Tracing indicator. */ + uint32_t fTracing; + /** The tracing ID of this device. */ + uint32_t idTracing; + /** The port/device speed. HCs and emulated devices need to know. */ + VUSBSPEED enmSpeed; + + /** Padding to make achInstanceData aligned at 32 byte boundary. */ + uint32_t au32Padding[HC_ARCH_BITS == 32 ? 2 : 3]; + + /** Device instance data. The size of this area is defined + * in the PDMUSBREG::cbInstanceData field. */ + char achInstanceData[8]; +} PDMUSBINS; + +/** Current USBINS version number. */ +#define PDM_USBINS_VERSION PDM_VERSION_MAKE(0xeefd, 3, 0) + +/** + * Checks the structure versions of the USB device instance and USB device + * helpers, returning if they are incompatible. + * + * This shall be the first statement of the constructor! + * + * @param pUsbIns The USB device instance pointer. + */ +#define PDMUSB_CHECK_VERSIONS_RETURN(pUsbIns) \ + do \ + { \ + PPDMUSBINS pUsbInsTypeCheck = (pUsbIns); NOREF(pUsbInsTypeCheck); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pUsbIns)->u32Version, PDM_USBINS_VERSION), \ + ("DevIns=%#x mine=%#x\n", (pUsbIns)->u32Version, PDM_USBINS_VERSION), \ + VERR_PDM_USBINS_VERSION_MISMATCH); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pUsbIns)->pHlpR3->u32Version, PDM_USBHLP_VERSION), \ + ("DevHlp=%#x mine=%#x\n", (pUsbIns)->pHlpR3->u32Version, PDM_USBHLP_VERSION), \ + VERR_PDM_USBHLPR3_VERSION_MISMATCH); \ + } while (0) + +/** + * Quietly checks the structure versions of the USB device instance and + * USB device helpers, returning if they are incompatible. + * + * This shall be invoked as the first statement in the destructor! + * + * @param pUsbIns The USB device instance pointer. + */ +#define PDMUSB_CHECK_VERSIONS_RETURN_VOID(pUsbIns) \ + do \ + { \ + PPDMUSBINS pUsbInsTypeCheck = (pUsbIns); NOREF(pUsbInsTypeCheck); \ + if (RT_LIKELY(PDM_VERSION_ARE_COMPATIBLE((pUsbIns)->u32Version, PDM_USBINS_VERSION) )) \ + { /* likely */ } else return; \ + if (RT_LIKELY(PDM_VERSION_ARE_COMPATIBLE((pUsbIns)->pHlpR3->u32Version, PDM_USBHLP_VERSION) )) \ + { /* likely */ } else return; \ + } while (0) + + +/** Converts a pointer to the PDMUSBINS::IBase to a pointer to PDMUSBINS. */ +#define PDMIBASE_2_PDMUSB(pInterface) ( (PPDMUSBINS)((char *)(pInterface) - RT_UOFFSETOF(PDMUSBINS, IBase)) ) + + +/** @def PDMUSB_ASSERT_EMT + * Assert that the current thread is the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMUSB_ASSERT_EMT(pUsbIns) pUsbIns->pHlpR3->pfnAssertEMT(pUsbIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMUSB_ASSERT_EMT(pUsbIns) do { } while (0) +#endif + +/** @def PDMUSB_ASSERT_OTHER + * Assert that the current thread is NOT the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMUSB_ASSERT_OTHER(pUsbIns) pUsbIns->pHlpR3->pfnAssertOther(pUsbIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMUSB_ASSERT_OTHER(pUsbIns) do { } while (0) +#endif + +/** @def PDMUSB_SET_ERROR + * Set the VM error. See PDMUsbHlpVMSetError() for printf like message + * formatting. + */ +#define PDMUSB_SET_ERROR(pUsbIns, rc, pszError) \ + PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, "%s", pszError) + +/** @def PDMUSB_SET_RUNTIME_ERROR + * Set the VM runtime error. See PDMUsbHlpVMSetRuntimeError() for printf like + * message formatting. + */ +#define PDMUSB_SET_RUNTIME_ERROR(pUsbIns, fFlags, pszErrorId, pszError) \ + PDMUsbHlpVMSetRuntimeError(pUsbIns, fFlags, pszErrorId, "%s", pszError) + + +#ifdef IN_RING3 + +/** + * @copydoc PDMUSBHLP::pfnDriverAttach + */ +DECLINLINE(int) PDMUsbHlpDriverAttach(PPDMUSBINS pUsbIns, RTUINT iLun, PPDMIBASE pBaseInterface, PPDMIBASE *ppBaseInterface, const char *pszDesc) +{ + return pUsbIns->pHlpR3->pfnDriverAttach(pUsbIns, iLun, pBaseInterface, ppBaseInterface, pszDesc); +} + +/** + * VBOX_STRICT wrapper for pHlpR3->pfnDBGFStopV. + * + * @returns VBox status code which must be passed up to the VMM. + * @param pUsbIns Device instance. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Message. (optional) + * @param ... Message parameters. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(5, 6) PDMUsbDBGFStop(PPDMUSBINS pUsbIns, RT_SRC_POS_DECL, const char *pszFormat, ...) +{ +#ifdef VBOX_STRICT + int rc; + va_list va; + va_start(va, pszFormat); + rc = pUsbIns->pHlpR3->pfnDBGFStopV(pUsbIns, RT_SRC_POS_ARGS, pszFormat, va); + va_end(va); + return rc; +#else + NOREF(pUsbIns); + NOREF(pszFile); + NOREF(iLine); + NOREF(pszFunction); + NOREF(pszFormat); + return VINF_SUCCESS; +#endif +} + +/** + * @copydoc PDMUSBHLP::pfnVMState + */ +DECLINLINE(VMSTATE) PDMUsbHlpVMState(PPDMUSBINS pUsbIns) +{ + return pUsbIns->pHlpR3->pfnVMState(pUsbIns); +} + +/** + * @copydoc PDMUSBHLP::pfnThreadCreate + */ +DECLINLINE(int) PDMUsbHlpThreadCreate(PPDMUSBINS pUsbIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADUSB pfnThread, + PFNPDMTHREADWAKEUPUSB pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName) +{ + return pUsbIns->pHlpR3->pfnThreadCreate(pUsbIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName); +} + + +/** + * @copydoc PDMUSBHLP::pfnSetAsyncNotification + */ +DECLINLINE(int) PDMUsbHlpSetAsyncNotification(PPDMUSBINS pUsbIns, PFNPDMUSBASYNCNOTIFY pfnAsyncNotify) +{ + return pUsbIns->pHlpR3->pfnSetAsyncNotification(pUsbIns, pfnAsyncNotify); +} + +/** + * @copydoc PDMUSBHLP::pfnAsyncNotificationCompleted + */ +DECLINLINE(void) PDMUsbHlpAsyncNotificationCompleted(PPDMUSBINS pUsbIns) +{ + pUsbIns->pHlpR3->pfnAsyncNotificationCompleted(pUsbIns); +} + +/** + * Set the VM error message + * + * @returns rc. + * @param pUsbIns The USB device instance. + * @param rc VBox status code. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 7) PDMUsbHlpVMSetError(PPDMUSBINS pUsbIns, int rc, RT_SRC_POS_DECL, + const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + rc = pUsbIns->pHlpR3->pfnVMSetErrorV(pUsbIns, rc, RT_SRC_POS_ARGS, pszFormat, va); + va_end(va); + return rc; +} + +/** + * @copydoc PDMUSBHLP::pfnMMHeapAlloc + */ +DECLINLINE(void *) PDMUsbHlpMMHeapAlloc(PPDMUSBINS pUsbIns, size_t cb) +{ + return pUsbIns->pHlpR3->pfnMMHeapAlloc(pUsbIns, cb); +} + +/** + * @copydoc PDMUSBHLP::pfnMMHeapAllocZ + */ +DECLINLINE(void *) PDMUsbHlpMMHeapAllocZ(PPDMUSBINS pUsbIns, size_t cb) +{ + return pUsbIns->pHlpR3->pfnMMHeapAllocZ(pUsbIns, cb); +} + +/** + * Frees memory allocated by PDMUsbHlpMMHeapAlloc or PDMUsbHlpMMHeapAllocZ. + * + * @param pUsbIns The USB device instance. + * @param pv The memory to free. NULL is fine. + */ +DECLINLINE(void) PDMUsbHlpMMHeapFree(PPDMUSBINS pUsbIns, void *pv) +{ + pUsbIns->pHlpR3->pfnMMHeapFree(pUsbIns, pv); +} + +/** + * @copydoc PDMUSBHLP::pfnDBGFInfoRegisterArgv + */ +DECLINLINE(int) PDMUsbHlpDBGFInfoRegisterArgv(PPDMUSBINS pUsbIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVUSB pfnHandler) +{ + return pUsbIns->pHlpR3->pfnDBGFInfoRegisterArgv(pUsbIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerCreate + */ +DECLINLINE(int) PDMUsbHlpTimerCreate(PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer) +{ + return pUsbIns->pHlpR3->pfnTimerCreate(pUsbIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, phTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerFromMicro + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerFromMicro(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs) +{ + return pUsbIns->pHlpR3->pfnTimerFromMicro(pUsbIns, hTimer, cMicroSecs); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerFromMilli + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerFromMilli(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs) +{ + return pUsbIns->pHlpR3->pfnTimerFromMilli(pUsbIns, hTimer, cMilliSecs); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerFromNano + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerFromNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs) +{ + return pUsbIns->pHlpR3->pfnTimerFromNano(pUsbIns, hTimer, cNanoSecs); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerGet + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerGet(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerGet(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerGetFreq + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerGetFreq(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerGetFreq(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerGetNano + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerGetNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerGetNano(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerIsActive + */ +DECLINLINE(bool) PDMUsbHlpTimerIsActive(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerIsActive(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerIsLockOwner + */ +DECLINLINE(bool) PDMUsbHlpTimerIsLockOwner(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerIsLockOwner(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerLockClock + */ +DECLINLINE(int) PDMUsbHlpTimerLockClock(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerLockClock(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerLockClock2 + */ +DECLINLINE(int) PDMUsbHlpTimerLockClock2(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect) +{ + return pUsbIns->pHlpR3->pfnTimerLockClock2(pUsbIns, hTimer, pCritSect); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSet + */ +DECLINLINE(int) PDMUsbHlpTimerSet(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t uExpire) +{ + return pUsbIns->pHlpR3->pfnTimerSet(pUsbIns, hTimer, uExpire); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetFrequencyHint + */ +DECLINLINE(int) PDMUsbHlpTimerSetFrequencyHint(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint32_t uHz) +{ + return pUsbIns->pHlpR3->pfnTimerSetFrequencyHint(pUsbIns, hTimer, uHz); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetMicro + */ +DECLINLINE(int) PDMUsbHlpTimerSetMicro(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext) +{ + return pUsbIns->pHlpR3->pfnTimerSetMicro(pUsbIns, hTimer, cMicrosToNext); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetMillies + */ +DECLINLINE(int) PDMUsbHlpTimerSetMillies(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext) +{ + return pUsbIns->pHlpR3->pfnTimerSetMillies(pUsbIns, hTimer, cMilliesToNext); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetNano + */ +DECLINLINE(int) PDMUsbHlpTimerSetNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext) +{ + return pUsbIns->pHlpR3->pfnTimerSetNano(pUsbIns, hTimer, cNanosToNext); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetRelative + */ +DECLINLINE(int) PDMUsbHlpTimerSetRelative(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now) +{ + return pUsbIns->pHlpR3->pfnTimerSetRelative(pUsbIns, hTimer, cTicksToNext, pu64Now); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerStop + */ +DECLINLINE(int) PDMUsbHlpTimerStop(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerStop(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerUnlockClock + */ +DECLINLINE(void) PDMUsbHlpTimerUnlockClock(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + pUsbIns->pHlpR3->pfnTimerUnlockClock(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerUnlockClock2 + */ +DECLINLINE(void) PDMUsbHlpTimerUnlockClock2(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect) +{ + pUsbIns->pHlpR3->pfnTimerUnlockClock2(pUsbIns, hTimer, pCritSect); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetCritSect + */ +DECLINLINE(int) PDMUsbHlpTimerSetCritSect(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect) +{ + return pUsbIns->pHlpR3->pfnTimerSetCritSect(pUsbIns, hTimer, pCritSect); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSave + */ +DECLINLINE(int) PDMUsbHlpTimerSave(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM) +{ + return pUsbIns->pHlpR3->pfnTimerSave(pUsbIns, hTimer, pSSM); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerLoad + */ +DECLINLINE(int) PDMUsbHlpTimerLoad(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM) +{ + return pUsbIns->pHlpR3->pfnTimerLoad(pUsbIns, hTimer, pSSM); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerDestroy + */ +DECLINLINE(int) PDMUsbHlpTimerDestroy(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerDestroy(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnSSMRegister + */ +DECLINLINE(int) PDMUsbHlpSSMRegister(PPDMUSBINS pUsbIns, uint32_t uVersion, size_t cbGuess, + PFNSSMUSBLIVEPREP pfnLivePrep, PFNSSMUSBLIVEEXEC pfnLiveExec, PFNSSMUSBLIVEVOTE pfnLiveVote, + PFNSSMUSBSAVEPREP pfnSavePrep, PFNSSMUSBSAVEEXEC pfnSaveExec, PFNSSMUSBSAVEDONE pfnSaveDone, + PFNSSMUSBLOADPREP pfnLoadPrep, PFNSSMUSBLOADEXEC pfnLoadExec, PFNSSMUSBLOADDONE pfnLoadDone) +{ + return pUsbIns->pHlpR3->pfnSSMRegister(pUsbIns, uVersion, cbGuess, + pfnLivePrep, pfnLiveExec, pfnLiveVote, + pfnSavePrep, pfnSaveExec, pfnSaveDone, + pfnLoadPrep, pfnLoadExec, pfnLoadDone); +} + +/** + * @copydoc PDMUSBHLP::pfnQueryGenericUserObject + */ +DECLINLINE(void *) PDMUsbHlpQueryGenericUserObject(PPDMUSBINS pUsbIns, PCRTUUID pUuid) +{ + return pUsbIns->pHlpR3->pfnQueryGenericUserObject(pUsbIns, pUuid); +} + +#endif /* IN_RING3 */ + + + +/** Pointer to callbacks provided to the VBoxUsbRegister() call. */ +typedef const struct PDMUSBREGCB *PCPDMUSBREGCB; + +/** + * Callbacks for VBoxUSBDeviceRegister(). + */ +typedef struct PDMUSBREGCB +{ + /** Interface version. + * This is set to PDM_USBREG_CB_VERSION. */ + uint32_t u32Version; + + /** + * Registers a device with the current VM instance. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param pReg Pointer to the USB device registration record. + * This data must be permanent and readonly. + */ + DECLR3CALLBACKMEMBER(int, pfnRegister,(PCPDMUSBREGCB pCallbacks, PCPDMUSBREG pReg)); +} PDMUSBREGCB; + +/** Current version of the PDMUSBREGCB structure. */ +#define PDM_USBREG_CB_VERSION PDM_VERSION_MAKE(0xeefc, 1, 0) + + +/** + * The VBoxUsbRegister callback function. + * + * PDM will invoke this function after loading a USB device module and letting + * the module decide which devices to register and how to handle conflicts. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param u32Version VBox version number. + */ +typedef DECLCALLBACKTYPE(int, FNPDMVBOXUSBREGISTER,(PCPDMUSBREGCB pCallbacks, uint32_t u32Version)); + +VMMR3DECL(int) PDMR3UsbCreateEmulatedDevice(PUVM pUVM, const char *pszDeviceName, PCFGMNODE pDeviceNode, PCRTUUID pUuid, + const char *pszCaptureFilename); +VMMR3DECL(int) PDMR3UsbCreateProxyDevice(PUVM pUVM, PCRTUUID pUuid, const char *pszBackend, const char *pszAddress, PCFGMNODE pSubTree, + VUSBSPEED enmSpeed, uint32_t fMaskedIfs, const char *pszCaptureFilename); +VMMR3DECL(int) PDMR3UsbDetachDevice(PUVM pUVM, PCRTUUID pUuid); +VMMR3DECL(bool) PDMR3UsbHasHub(PUVM pUVM); +VMMR3DECL(int) PDMR3UsbDriverAttach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, uint32_t fFlags, + PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3UsbDriverDetach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, + const char *pszDriver, unsigned iOccurrence, uint32_t fFlags); +VMMR3DECL(int) PDMR3UsbQueryLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase); +VMMR3DECL(int) PDMR3UsbQueryDriverOnLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, + const char *pszDriver, PPPDMIBASE ppBase); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmusb_h */ diff --git a/include/VBox/vmm/pdmwebcaminfs.h b/include/VBox/vmm/pdmwebcaminfs.h new file mode 100644 index 00000000..3c1fe35f --- /dev/null +++ b/include/VBox/vmm/pdmwebcaminfs.h @@ -0,0 +1,156 @@ +/* $Id: pdmwebcaminfs.h $ */ +/** @file + * webcaminfs - interfaces between dev and driver. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmwebcaminfs_h +#define VBOX_INCLUDED_vmm_pdmwebcaminfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + +struct VRDEVIDEOINDEVICEDESC; +struct VRDEVIDEOINPAYLOADHDR; +struct VRDEVIDEOINCTRLHDR; + + +/** @defgroup grp_pdm_ifs_webcam PDM Web Camera Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + +/** Pointer to the web camera driver (up) interface. */ +typedef struct PDMIWEBCAMDRV *PPDMIWEBCAMDRV; +/** + * Web camera interface driver provided by the driver to the device, + * i.e. facing upwards. + */ +typedef struct PDMIWEBCAMDRV +{ + /** + * The PDM device is ready to get webcam notifications. + * + * @param pInterface Pointer to the interface. + * @param fReady Whether the device is ready. + */ + DECLR3CALLBACKMEMBER(void, pfnReady,(PPDMIWEBCAMDRV pInterface, bool fReady)); + + /** + * Send a control request to the webcam. + * + * Async response will be returned by pfnWebcamUpControl callback. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface. + * @param pvUser The callers context. + * @param idDevice Unique id for the reported webcam assigned by the driver. + * @param pCtrl The control data. + * @param cbCtrl The size of the control data. + */ + DECLR3CALLBACKMEMBER(int, pfnControl,(PPDMIWEBCAMDRV pInterface, void *pvUser, uint64_t idDevice, + struct VRDEVIDEOINCTRLHDR const *pCtrl, uint32_t cbCtrl)); +} PDMIWEBCAMDRV; +/** Interface ID for PDMIWEBCAMDRV. */ +#define PDMIWEBCAMDRV_IID "0d29b9a1-f4cd-4719-a564-38d5634ba9f8" + + +/** Pointer to the web camera driver/device (down) interface. */ +typedef struct PDMIWEBCAMDEV *PPDMIWEBCAMDEV; +/** + * Web camera interface provided by the device(/driver) interface, + * i.e. facing downwards. + */ +typedef struct PDMIWEBCAMDEV +{ + /** + * A webcam is available. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface. + * @param idDevice Unique id for the reported webcam assigned by the driver. + * @param pDeviceDesc The device description. + * @param cbDeviceDesc The size of the device description. + * @param uVersion The remote video input protocol version. + * @param fCapabilities The remote video input protocol capabilities. + */ + DECLR3CALLBACKMEMBER(int, pfnAttached,(PPDMIWEBCAMDEV pInterface, uint64_t idDevice, + struct VRDEVIDEOINDEVICEDESC const *pDeviceDesc, uint32_t cbDeviceDesc, + uint32_t uVersion, uint32_t fCapabilities)); + + /** + * The webcam is not available anymore. + * + * @param pInterface Pointer to the interface. + * @param idDevice Unique id for the reported webcam assigned by the + * driver. + */ + DECLR3CALLBACKMEMBER(void, pfnDetached,(PPDMIWEBCAMDEV pInterface, uint64_t idDevice)); + + /** + * There is a control response or a control change for the webcam. + * + * @param pInterface Pointer to the interface. + * @param fResponse True if this is a response for a previous pfnWebcamDownControl call. + * @param pvUser The pvUser parameter of the pfnWebcamDownControl call. Undefined if fResponse == false. + * @param idDevice Unique id for the reported webcam assigned by the + * driver. + * @param pCtrl The control data (defined in VRDE). + * @param cbCtrl The size of the control data. + */ + DECLR3CALLBACKMEMBER(void, pfnControl,(PPDMIWEBCAMDEV pInterface, bool fResponse, void *pvUser, + uint64_t idDevice, struct VRDEVIDEOINCTRLHDR const *pCtrl, uint32_t cbCtrl)); + + /** + * A new frame. + * + * @param pInterface Pointer to the interface. + * @param idDevice Unique id for the reported webcam assigned by the driver. + * @param pHeader Payload header (defined in VRDE). + * @param cbHeader Size of the payload header. + * @param pvFrame Frame (image) data. + * @param cbFrame Size of the image data. + */ + DECLR3CALLBACKMEMBER(void, pfnFrame,(PPDMIWEBCAMDEV pInterface, uint64_t idDevice, + struct VRDEVIDEOINPAYLOADHDR const *pHeader, uint32_t cbHeader, + const void *pvFrame, uint32_t cbFrame)); +} PDMIWEBCAMDEV; +/** Interface ID for PDMIWEBCAMDEV. */ +#define PDMIWEBCAMDEV_IID "6ac03e3c-f56c-4a35-80af-c13ce47a9dd7" + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmwebcaminfs_h */ + diff --git a/include/VBox/vmm/pgm.h b/include/VBox/vmm/pgm.h new file mode 100644 index 00000000..133ad827 --- /dev/null +++ b/include/VBox/vmm/pgm.h @@ -0,0 +1,1129 @@ +/** @file + * PGM - Page Monitor / Monitor. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pgm_h +#define VBOX_INCLUDED_vmm_pgm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/sup.h> +#include <VBox/vmm/vmapi.h> +#include <VBox/vmm/gmm.h> /* for PGMMREGISTERSHAREDMODULEREQ */ +#include <VBox/vmm/hm_vmx.h> +#include <iprt/x86.h> +#include <VBox/param.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pgm The Page Monitor / Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * FNPGMRELOCATE callback mode. + */ +typedef enum PGMRELOCATECALL +{ + /** The callback is for checking if the suggested address is suitable. */ + PGMRELOCATECALL_SUGGEST = 1, + /** The callback is for executing the relocation. */ + PGMRELOCATECALL_RELOCATE +} PGMRELOCATECALL; + + +/** + * Callback function which will be called when PGM is trying to find + * a new location for the mapping. + * + * The callback is called in two modes, 1) the check mode and 2) the relocate mode. + * In 1) the callback should say if it objects to a suggested new location. If it + * accepts the new location, it is called again for doing it's relocation. + * + * + * @returns true if the location is ok. + * @returns false if another location should be found. + * @param pVM The cross context VM structure. + * @param GCPtrOld The old virtual address. + * @param GCPtrNew The new virtual address. + * @param enmMode Used to indicate the callback mode. + * @param pvUser User argument. + * @remark The return value is no a failure indicator, it's an acceptance + * indicator. Relocation can not fail! + */ +typedef DECLCALLBACKTYPE(bool, FNPGMRELOCATE,(PVM pVM, RTGCPTR GCPtrOld, RTGCPTR GCPtrNew, PGMRELOCATECALL enmMode, void *pvUser)); +/** Pointer to a relocation callback function. */ +typedef FNPGMRELOCATE *PFNPGMRELOCATE; + + +/** + * Memory access origin. + */ +typedef enum PGMACCESSORIGIN +{ + /** Invalid zero value. */ + PGMACCESSORIGIN_INVALID = 0, + /** IEM is access memory. */ + PGMACCESSORIGIN_IEM, + /** HM is access memory. */ + PGMACCESSORIGIN_HM, + /** Some device is access memory. */ + PGMACCESSORIGIN_DEVICE, + /** Someone debugging is access memory. */ + PGMACCESSORIGIN_DEBUGGER, + /** SELM is access memory. */ + PGMACCESSORIGIN_SELM, + /** FTM is access memory. */ + PGMACCESSORIGIN_FTM, + /** REM is access memory. */ + PGMACCESSORIGIN_REM, + /** IOM is access memory. */ + PGMACCESSORIGIN_IOM, + /** End of valid values. */ + PGMACCESSORIGIN_END, + /** Type size hack. */ + PGMACCESSORIGIN_32BIT_HACK = 0x7fffffff +} PGMACCESSORIGIN; + + +/** + * Physical page access handler kind. + */ +typedef enum PGMPHYSHANDLERKIND +{ + /** Invalid zero value. */ + PGMPHYSHANDLERKIND_INVALID = 0, + /** MMIO range. Pages are not present, all access is done in interpreter or recompiler. */ + PGMPHYSHANDLERKIND_MMIO, + /** Handler all write access to a physical page range. */ + PGMPHYSHANDLERKIND_WRITE, + /** Handler all access to a physical page range. */ + PGMPHYSHANDLERKIND_ALL, + /** End of the valid values. */ + PGMPHYSHANDLERKIND_END, + /** Type size hack. */ + PGMPHYSHANDLERKIND_32BIT_HACK = 0x7fffffff +} PGMPHYSHANDLERKIND; + +/** + * Guest Access type + */ +typedef enum PGMACCESSTYPE +{ + /** Read access. */ + PGMACCESSTYPE_READ = 1, + /** Write access. */ + PGMACCESSTYPE_WRITE +} PGMACCESSTYPE; + + +/** @def PGM_ALL_CB_DECL + * Macro for declaring a handler callback for all contexts. The handler + * callback is static in ring-3, and exported in RC and R0. + * @sa PGM_ALL_CB2_DECL. + */ +#if defined(IN_RC) || defined(IN_RING0) +# ifdef __cplusplus +# define PGM_ALL_CB_DECL(type) extern "C" DECLCALLBACK(DECLEXPORT(type)) +# else +# define PGM_ALL_CB_DECL(type) DECLCALLBACK(DECLEXPORT(type)) +# endif +#else +# define PGM_ALL_CB_DECL(type) static DECLCALLBACK(type) +#endif + +/** @def PGM_ALL_CB2_DECL + * Macro for declaring a handler callback for all contexts. The handler + * callback is hidden in ring-3, and exported in RC and R0. + * @sa PGM_ALL_CB2_DECL. + */ +#if defined(IN_RC) || defined(IN_RING0) +# ifdef __cplusplus +# define PGM_ALL_CB2_DECL(type) extern "C" DECLCALLBACK(DECLEXPORT(type)) +# else +# define PGM_ALL_CB2_DECL(type) DECLCALLBACK(DECLEXPORT(type)) +# endif +#else +# define PGM_ALL_CB2_DECL(type) DECL_HIDDEN_CALLBACK(type) +#endif + +/** @def PGM_ALL_CB2_PROTO + * Macro for declaring a handler callback for all contexts. The handler + * callback is hidden in ring-3, and exported in RC and R0. + * @param fnType The callback function type. + * @sa PGM_ALL_CB2_DECL. + */ +#if defined(IN_RC) || defined(IN_RING0) +# ifdef __cplusplus +# define PGM_ALL_CB2_PROTO(fnType) extern "C" DECLEXPORT(fnType) +# else +# define PGM_ALL_CB2_PROTO(fnType) DECLEXPORT(fnType) +# endif +#else +# define PGM_ALL_CB2_PROTO(fnType) DECLHIDDEN(fnType) +#endif + + +/** + * \#PF Handler callback for physical access handler ranges in RC and R0. + * + * @returns Strict VBox status code (appropriate for ring-0 and raw-mode). + * @param pVM The cross context VM structure. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param uErrorCode CPU Error code. + * @param pCtx Pointer to the register context for the CPU. + * @param pvFault The fault address (cr2). + * @param GCPhysFault The GC physical address corresponding to pvFault. + * @param uUser User argument (not a pointer). + * @thread EMT(pVCpu) + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPGMRZPHYSPFHANDLER,(PVMCC pVM, PVMCPUCC pVCpu, RTGCUINT uErrorCode, PCPUMCTX pCtx, + RTGCPTR pvFault, RTGCPHYS GCPhysFault, uint64_t uUser)); +/** Pointer to PGM access callback. */ +typedef FNPGMRZPHYSPFHANDLER *PFNPGMRZPHYSPFHANDLER; + + +/** + * Access handler callback for physical access handler ranges. + * + * The handler can not raise any faults, it's mainly for monitoring write access + * to certain pages (like MMIO). + * + * @returns Strict VBox status code in ring-0 and raw-mode context, in ring-3 + * the only supported informational status code is + * VINF_PGM_HANDLER_DO_DEFAULT. + * @retval VINF_SUCCESS if the handler have carried out the operation. + * @retval VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the + * access operation. + * @retval VINF_EM_XXX in ring-0 and raw-mode context. + * + * @param pVM The cross context VM structure. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param GCPhys The physical address the guest is writing to. + * @param pvPhys The HC mapping of that address. + * @param pvBuf What the guest is reading/writing. + * @param cbBuf How much it's reading/writing. + * @param enmAccessType The access type. + * @param enmOrigin The origin of this call. + * @param uUser User argument (not a pointer). + * @thread EMT(pVCpu) + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPGMPHYSHANDLER,(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, void *pvPhys, + void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, + PGMACCESSORIGIN enmOrigin, uint64_t uUser)); +/** Pointer to PGM access callback. */ +typedef FNPGMPHYSHANDLER *PFNPGMPHYSHANDLER; + + +/** + * Paging mode. + * + * @note Part of saved state. Change with extreme care. + */ +typedef enum PGMMODE +{ + /** The usual invalid value. */ + PGMMODE_INVALID = 0, + /** Real mode. */ + PGMMODE_REAL, + /** Protected mode, no paging. */ + PGMMODE_PROTECTED, + /** 32-bit paging. */ + PGMMODE_32_BIT, + /** PAE paging. */ + PGMMODE_PAE, + /** PAE paging with NX enabled. */ + PGMMODE_PAE_NX, + /** 64-bit AMD paging (long mode). */ + PGMMODE_AMD64, + /** 64-bit AMD paging (long mode) with NX enabled. */ + PGMMODE_AMD64_NX, + /** 32-bit nested paging mode (shadow only; guest physical to host physical). */ + PGMMODE_NESTED_32BIT, + /** PAE nested paging mode (shadow only; guest physical to host physical). */ + PGMMODE_NESTED_PAE, + /** AMD64 nested paging mode (shadow only; guest physical to host physical). */ + PGMMODE_NESTED_AMD64, + /** Extended paging (Intel) mode. */ + PGMMODE_EPT, + /** Special mode used by NEM to indicate no shadow paging necessary. */ + PGMMODE_NONE, + /** The max number of modes */ + PGMMODE_MAX, + /** 32bit hackishness. */ + PGMMODE_32BIT_HACK = 0x7fffffff +} PGMMODE; + +/** + * Second level address translation (SLAT) mode. + */ +typedef enum PGMSLAT +{ + /** The usual invalid value. */ + PGMSLAT_INVALID = 0, + /** No second level translation. */ + PGMSLAT_DIRECT, + /** Intel Extended Page Tables (EPT). */ + PGMSLAT_EPT, + /** AMD-V Nested Paging 32-bit. */ + PGMSLAT_32BIT, + /** AMD-V Nested Paging PAE. */ + PGMSLAT_PAE, + /** AMD-V Nested Paging 64-bit. */ + PGMSLAT_AMD64, + /** 32bit hackishness. */ + PGMSLAT_32BIT_HACK = 0x7fffffff +} PGMSLAT; + + +/** @name PGMPTWALK::fFailed flags. + * These flags indicate the type of a page-walk failure. + * @{ + */ +typedef uint32_t PGMWALKFAIL; +/** Regular page fault (MBZ since guest Walk code don't set these explicitly). */ +#define PGM_WALKFAIL_PAGE_FAULT UINT32_C(0) +/** EPT violation - Intel. */ +#define PGM_WALKFAIL_EPT_VIOLATION RT_BIT_32(0) +/** EPT violation, convertible to \#VE exception - Intel. */ +#define PGM_WALKFAIL_EPT_VIOLATION_CONVERTIBLE RT_BIT_32(1) +/** EPT misconfiguration - Intel. */ +#define PGM_WALKFAIL_EPT_MISCONFIG RT_BIT_32(2) + +/** Mask of all EPT induced page-walk failures - Intel. */ +#define PGM_WALKFAIL_EPT ( PGM_WALKFAIL_EPT_VIOLATION \ + | PGM_WALKFAIL_EPT_VIOLATION_CONVERTIBLE \ + | PGM_WALKFAIL_EPT_MISCONFIG) +/** @} */ + + +/** @name PGMPTATTRS - PGM page-table attributes. + * + * This is VirtualBox's combined page table attributes. It combines regular page + * table and Intel EPT attributes. It's 64-bit in size so there's ample room for + * bits added in the future to EPT or regular page tables (for e.g. Protection Key). + * + * The following bits map 1:1 (shifted by PGM_PTATTRS_EPT_SHIFT) to the Intel EPT + * attributes as these are unique to EPT and fit within 64-bits despite the shift: + * - EPT_R : Read access. + * - EPT_W : Write access. + * - EPT_X_SUPER : Execute or execute for supervisor-mode linear addr access. + * - EPT_MEMTYPE : EPT memory type. + * - EPT_IGNORE_PAT: Ignore PAT memory type. + * - EPT_X_USER : Execute access for user-mode linear addresses. + * + * For regular page tables, the R bit is always 1 (same as P bit). + * For Intel EPT, the EPT_R and EPT_W bits are copied to R and W bits respectively. + * + * The following EPT attributes are mapped to the following positions because they + * exist in the regular page tables at these positions OR are exclusive to EPT and + * have been mapped to arbitrarily chosen positions: + * - EPT_A : Accessed (EPT bit 8 maps to bit 5). + * - EPT_D : Dirty (EPT bit 9 maps to bit 6). + * - EPT_SUPER_SHW_STACK : Supervisor Shadow Stack (EPT bit 60 maps to bit 24). + * - EPT_SUPPRESS_VE_XCPT: Suppress \#VE exception (EPT bit 63 maps to bit 25). + * + * Bits 12, 11:9 and 43 are deliberately kept unused (correspond to bit PS and bits + * 11:9 in the regular page-table structures and to bit 11 in the EPT structures + * respectively) as bit 12 is the page-size bit and bits 11:9 are reserved for + * use by software and we may want to use/preserve them in the future. + * + * @{ */ +typedef uint64_t PGMPTATTRS; +/** Pointer to a PGMPTATTRS type. */ +typedef PGMPTATTRS *PPGMPTATTRS; + +/** Read bit (always 1 for regular PT, copy of EPT_R for EPT). */ +#define PGM_PTATTRS_R_SHIFT 0 +#define PGM_PTATTRS_R_MASK RT_BIT_64(PGM_PTATTRS_R_SHIFT) +/** Write access bit (aka read/write bit for regular PT). */ +#define PGM_PTATTRS_W_SHIFT 1 +#define PGM_PTATTRS_W_MASK RT_BIT_64(PGM_PTATTRS_W_SHIFT) +/** User-mode access bit. */ +#define PGM_PTATTRS_US_SHIFT 2 +#define PGM_PTATTRS_US_MASK RT_BIT_64(PGM_PTATTRS_US_SHIFT) +/** Write through cache bit. */ +#define PGM_PTATTRS_PWT_SHIFT 3 +#define PGM_PTATTRS_PWT_MASK RT_BIT_64(PGM_PTATTRS_PWT_SHIFT) +/** Cache disabled bit. */ +#define PGM_PTATTRS_PCD_SHIFT 4 +#define PGM_PTATTRS_PCD_MASK RT_BIT_64(PGM_PTATTRS_PCD_SHIFT) +/** Accessed bit. */ +#define PGM_PTATTRS_A_SHIFT 5 +#define PGM_PTATTRS_A_MASK RT_BIT_64(PGM_PTATTRS_A_SHIFT) +/** Dirty bit. */ +#define PGM_PTATTRS_D_SHIFT 6 +#define PGM_PTATTRS_D_MASK RT_BIT_64(PGM_PTATTRS_D_SHIFT) +/** The PAT bit. */ +#define PGM_PTATTRS_PAT_SHIFT 7 +#define PGM_PTATTRS_PAT_MASK RT_BIT_64(PGM_PTATTRS_PAT_SHIFT) +/** The global bit. */ +#define PGM_PTATTRS_G_SHIFT 8 +#define PGM_PTATTRS_G_MASK RT_BIT_64(PGM_PTATTRS_G_SHIFT) +/** Reserved (bits 12:9) unused. */ +#define PGM_PTATTRS_RSVD_12_9_SHIFT 9 +#define PGM_PTATTRS_RSVD_12_9_MASK UINT64_C(0x0000000000001e00) +/** Read access bit - EPT only. */ +#define PGM_PTATTRS_EPT_R_SHIFT 13 +#define PGM_PTATTRS_EPT_R_MASK RT_BIT_64(PGM_PTATTRS_EPT_R_SHIFT) +/** Write access bit - EPT only. */ +#define PGM_PTATTRS_EPT_W_SHIFT 14 +#define PGM_PTATTRS_EPT_W_MASK RT_BIT_64(PGM_PTATTRS_EPT_W_SHIFT) +/** Execute or execute access for supervisor-mode linear addresses - EPT only. */ +#define PGM_PTATTRS_EPT_X_SUPER_SHIFT 15 +#define PGM_PTATTRS_EPT_X_SUPER_MASK RT_BIT_64(PGM_PTATTRS_EPT_X_SUPER_SHIFT) +/** EPT memory type - EPT only. */ +#define PGM_PTATTRS_EPT_MEMTYPE_SHIFT 16 +#define PGM_PTATTRS_EPT_MEMTYPE_MASK UINT64_C(0x0000000000070000) +/** Ignore PAT memory type - EPT only. */ +#define PGM_PTATTRS_EPT_IGNORE_PAT_SHIFT 19 +#define PGM_PTATTRS_EPT_IGNORE_PAT_MASK RT_BIT_64(PGM_PTATTRS_EPT_IGNORE_PAT_SHIFT) +/** Leaf paging entry (big or regular) - EPT only. */ +#define PGM_PTATTRS_EPT_LEAF_SHIFT 20 +#define PGM_PTATTRS_EPT_LEAF_MASK RT_BIT_64(PGM_PTATTRS_EPT_LEAF_SHIFT) +/** Accessed bit - EPT only. */ +#define PGM_PTATTRS_EPT_A_SHIFT 21 +#define PGM_PTATTRS_EPT_A_MASK RT_BIT_64(PGM_PTATTRS_EPT_A_SHIFT) +/** Dirty bit - EPT only. */ +#define PGM_PTATTRS_EPT_D_SHIFT 22 +#define PGM_PTATTRS_EPT_D_MASK RT_BIT_64(PGM_PTATTRS_EPT_D_SHIFT) +/** Execute access for user-mode linear addresses - EPT only. */ +#define PGM_PTATTRS_EPT_X_USER_SHIFT 23 +#define PGM_PTATTRS_EPT_X_USER_MASK RT_BIT_64(PGM_PTATTRS_EPT_X_USER_SHIFT) +/** Reserved (bits 29:24) - unused. */ +#define PGM_PTATTRS_RSVD_29_24_SHIFT 24 +#define PGM_PTATTRS_RSVD_29_24_MASK UINT64_C(0x000000003f000000) +/** Verify Guest Paging - EPT only. */ +#define PGM_PTATTRS_EPT_VGP_SHIFT 30 +#define PGM_PTATTRS_EPT_VGP_MASK RT_BIT_64(PGM_PTATTRS_EPT_VGP_SHIFT) +/** Paging-write - EPT only. */ +#define PGM_PTATTRS_EPT_PW_SHIFT 31 +#define PGM_PTATTRS_EPT_PW_MASK RT_BIT_64(PGM_PTATTRS_EPT_PW_SHIFT) +/** Reserved (bit 32) - unused. */ +#define PGM_PTATTRS_RSVD_32_SHIFT 32 +#define PGM_PTATTRS_RSVD_32_MASK UINT64_C(0x0000000100000000) +/** Supervisor shadow stack - EPT only. */ +#define PGM_PTATTRS_EPT_SSS_SHIFT 33 +#define PGM_PTATTRS_EPT_SSS_MASK RT_BIT_64(PGM_PTATTRS_EPT_SSS_SHIFT) +/** Sub-page write permission - EPT only. */ +#define PGM_PTATTRS_EPT_SPP_SHIFT 34 +#define PGM_PTATTRS_EPT_SPP_MASK RT_BIT_64(PGM_PTATTRS_EPT_SPP_SHIFT) +/** Reserved (bit 35) - unused. */ +#define PGM_PTATTRS_RSVD_35_SHIFT 35 +#define PGM_PTATTRS_RSVD_35_MASK UINT64_C(0x0000000800000000) +/** Suppress \#VE exception - EPT only. */ +#define PGM_PTATTRS_EPT_SVE_SHIFT 36 +#define PGM_PTATTRS_EPT_SVE_MASK RT_BIT_64(PGM_PTATTRS_EPT_SVE_SHIFT) +/** Reserved (bits 62:37) - unused. */ +#define PGM_PTATTRS_RSVD_62_37_SHIFT 37 +#define PGM_PTATTRS_RSVD_62_37_MASK UINT64_C(0x7fffffe000000000) +/** No-execute bit. */ +#define PGM_PTATTRS_NX_SHIFT 63 +#define PGM_PTATTRS_NX_MASK RT_BIT_64(PGM_PTATTRS_NX_SHIFT) + +RT_BF_ASSERT_COMPILE_CHECKS(PGM_PTATTRS_, UINT64_C(0), UINT64_MAX, + (R, W, US, PWT, PCD, A, D, PAT, G, RSVD_12_9, EPT_R, EPT_W, EPT_X_SUPER, EPT_MEMTYPE, EPT_IGNORE_PAT, + EPT_LEAF, EPT_A, EPT_D, EPT_X_USER, RSVD_29_24, EPT_VGP, EPT_PW, RSVD_32, EPT_SSS, EPT_SPP, + RSVD_35, EPT_SVE, RSVD_62_37, NX)); + +/** The bit position where the EPT specific attributes begin. */ +#define PGM_PTATTRS_EPT_SHIFT PGM_PTATTRS_EPT_R_SHIFT +/** The mask of EPT bits (bits 36:ATTR_SHIFT). In the future we might choose to + * use higher unused bits for something else, in that case adjust this mask. */ +#define PGM_PTATTRS_EPT_MASK UINT64_C(0x0000001fffffe000) + +/** The mask of all PGM page attribute bits for regular page-tables. */ +#define PGM_PTATTRS_PT_VALID_MASK ( PGM_PTATTRS_R_MASK \ + | PGM_PTATTRS_W_MASK \ + | PGM_PTATTRS_US_MASK \ + | PGM_PTATTRS_PWT_MASK \ + | PGM_PTATTRS_PCD_MASK \ + | PGM_PTATTRS_A_MASK \ + | PGM_PTATTRS_D_MASK \ + | PGM_PTATTRS_PAT_MASK \ + | PGM_PTATTRS_G_MASK \ + | PGM_PTATTRS_NX_MASK) + +/** The mask of all PGM page attribute bits for EPT. */ +#define PGM_PTATTRS_EPT_VALID_MASK ( PGM_PTATTRS_EPT_R_MASK \ + | PGM_PTATTRS_EPT_W_MASK \ + | PGM_PTATTRS_EPT_X_SUPER_MASK \ + | PGM_PTATTRS_EPT_MEMTYPE_MASK \ + | PGM_PTATTRS_EPT_IGNORE_PAT_MASK \ + | PGM_PTATTRS_EPT_LEAF_MASK \ + | PGM_PTATTRS_EPT_A_MASK \ + | PGM_PTATTRS_EPT_D_MASK \ + | PGM_PTATTRS_EPT_X_USER_MASK \ + | PGM_PTATTRS_EPT_VGP_MASK \ + | PGM_PTATTRS_EPT_PW_MASK \ + | PGM_PTATTRS_EPT_SSS_MASK \ + | PGM_PTATTRS_EPT_SPP_MASK \ + | PGM_PTATTRS_EPT_SVE_MASK) + +/* The mask of all PGM page attribute bits (combined). */ +#define PGM_PTATTRS_VALID_MASK (PGM_PTATTRS_PT_VALID_MASK | PGM_PTATTRS_EPT_VALID_MASK) + +/* Verify bits match the regular PT bits. */ +AssertCompile(PGM_PTATTRS_W_SHIFT == X86_PTE_BIT_RW); +AssertCompile(PGM_PTATTRS_US_SHIFT == X86_PTE_BIT_US); +AssertCompile(PGM_PTATTRS_PWT_SHIFT == X86_PTE_BIT_PWT); +AssertCompile(PGM_PTATTRS_PCD_SHIFT == X86_PTE_BIT_PCD); +AssertCompile(PGM_PTATTRS_A_SHIFT == X86_PTE_BIT_A); +AssertCompile(PGM_PTATTRS_D_SHIFT == X86_PTE_BIT_D); +AssertCompile(PGM_PTATTRS_PAT_SHIFT == X86_PTE_BIT_PAT); +AssertCompile(PGM_PTATTRS_G_SHIFT == X86_PTE_BIT_G); +AssertCompile(PGM_PTATTRS_W_MASK == X86_PTE_RW); +AssertCompile(PGM_PTATTRS_US_MASK == X86_PTE_US); +AssertCompile(PGM_PTATTRS_PWT_MASK == X86_PTE_PWT); +AssertCompile(PGM_PTATTRS_PCD_MASK == X86_PTE_PCD); +AssertCompile(PGM_PTATTRS_A_MASK == X86_PTE_A); +AssertCompile(PGM_PTATTRS_D_MASK == X86_PTE_D); +AssertCompile(PGM_PTATTRS_PAT_MASK == X86_PTE_PAT); +AssertCompile(PGM_PTATTRS_G_MASK == X86_PTE_G); +AssertCompile(PGM_PTATTRS_NX_MASK == X86_PTE_PAE_NX); + +/* Verify those EPT bits that must map 1:1 (after shifting). */ +AssertCompile(PGM_PTATTRS_EPT_R_SHIFT - PGM_PTATTRS_EPT_SHIFT == EPT_E_BIT_READ); +AssertCompile(PGM_PTATTRS_EPT_W_SHIFT - PGM_PTATTRS_EPT_SHIFT == EPT_E_BIT_WRITE); +AssertCompile(PGM_PTATTRS_EPT_X_SUPER_SHIFT - PGM_PTATTRS_EPT_SHIFT == EPT_E_BIT_EXECUTE); +AssertCompile(PGM_PTATTRS_EPT_IGNORE_PAT_SHIFT - PGM_PTATTRS_EPT_SHIFT == EPT_E_BIT_IGNORE_PAT); +AssertCompile(PGM_PTATTRS_EPT_X_USER_SHIFT - PGM_PTATTRS_EPT_SHIFT == EPT_E_BIT_USER_EXECUTE); +/** @} */ + + +/** + * Page table walk information. + * + * This provides extensive information regarding page faults (or EPT + * violations/misconfigurations) while traversing page tables. + */ +typedef struct PGMPTWALK +{ + /** The linear address that is being resolved (input). */ + RTGCPTR GCPtr; + + /** The second-level physical address (input/output). + * @remarks only valid if fIsSlat is set. */ + RTGCPHYS GCPhysNested; + + /** The physical address that is the result of the walk (output). */ + RTGCPHYS GCPhys; + + /** Set if the walk succeeded. */ + bool fSucceeded; + /** Whether this is a second-level address translation. */ + bool fIsSlat; + /** Whether the linear address (GCPtr) caused the second-level + * address translation. */ + bool fIsLinearAddrValid; + /** The level problem arrised at. + * PTE is level 1, PDE is level 2, PDPE is level 3, PML4 is level 4, CR3 is + * level 8. This is 0 on success. */ + uint8_t uLevel; + /** Set if the page isn't present. */ + bool fNotPresent; + /** Encountered a bad physical address. */ + bool fBadPhysAddr; + /** Set if there was reserved bit violations. */ + bool fRsvdError; + /** Set if it involves a big page (2/4 MB). */ + bool fBigPage; + /** Set if it involves a gigantic page (1 GB). */ + bool fGigantPage; + bool afPadding[3]; + /** Page-walk failure type, PGM_WALKFAIL_XXX. */ + PGMWALKFAIL fFailed; + + /** The effective page-table attributes, PGM_PTATTRS_XXX. */ + PGMPTATTRS fEffective; +} PGMPTWALK; +/** Pointer to page walk information. */ +typedef PGMPTWALK *PPGMPTWALK; +/** Pointer to const page walk information. */ +typedef PGMPTWALK const *PCPGMPTWALK; + + +/** Macro for checking if the guest is using paging. + * @param enmMode PGMMODE_*. + * @remark ASSUMES certain order of the PGMMODE_* values. + */ +#define PGMMODE_WITH_PAGING(enmMode) ((enmMode) >= PGMMODE_32_BIT) + +/** Macro for checking if it's one of the long mode modes. + * @param enmMode PGMMODE_*. + */ +#define PGMMODE_IS_LONG_MODE(enmMode) ((enmMode) == PGMMODE_AMD64_NX || (enmMode) == PGMMODE_AMD64) + +/** Macro for checking if it's one of the AMD64 nested modes. + * @param enmMode PGMMODE_*. + */ +#define PGMMODE_IS_NESTED(enmMode) ( (enmMode) == PGMMODE_NESTED_32BIT \ + || (enmMode) == PGMMODE_NESTED_PAE \ + || (enmMode) == PGMMODE_NESTED_AMD64) + +/** Macro for checking if it's one of the PAE modes. + * @param enmMode PGMMODE_*. + */ +#define PGMMODE_IS_PAE(enmMode) ( (enmMode) == PGMMODE_PAE \ + || (enmMode) == PGMMODE_PAE_NX) + +/** + * Is the ROM mapped (true) or is the shadow RAM mapped (false). + * + * @returns boolean. + * @param enmProt The PGMROMPROT value, must be valid. + */ +#define PGMROMPROT_IS_ROM(enmProt) \ + ( (enmProt) == PGMROMPROT_READ_ROM_WRITE_IGNORE \ + || (enmProt) == PGMROMPROT_READ_ROM_WRITE_RAM ) + + +VMMDECL(bool) PGMIsLockOwner(PVMCC pVM); + +VMMDECL(int) PGMRegisterStringFormatTypes(void); +VMMDECL(void) PGMDeregisterStringFormatTypes(void); +VMMDECL(RTHCPHYS) PGMGetHyperCR3(PVMCPU pVCpu); +VMMDECL(int) PGMTrap0eHandler(PVMCPUCC pVCpu, RTGCUINT uErr, PCPUMCTX pCtx, RTGCPTR pvFault); +VMMDECL(int) PGMPrefetchPage(PVMCPUCC pVCpu, RTGCPTR GCPtrPage); +VMMDECL(VBOXSTRICTRC) PGMInterpretInstruction(PVMCPUCC pVCpu, RTGCPTR pvFault); +VMMDECL(int) PGMShwGetPage(PVMCPUCC pVCpu, RTGCPTR GCPtr, uint64_t *pfFlags, PRTHCPHYS pHCPhys); +VMMDECL(int) PGMShwMakePageReadonly(PVMCPUCC pVCpu, RTGCPTR GCPtr, uint32_t fFlags); +VMMDECL(int) PGMShwMakePageWritable(PVMCPUCC pVCpu, RTGCPTR GCPtr, uint32_t fFlags); +VMMDECL(int) PGMShwMakePageNotPresent(PVMCPUCC pVCpu, RTGCPTR GCPtr, uint32_t fFlags); +/** @name Flags for PGMShwMakePageReadonly, PGMShwMakePageWritable and + * PGMShwMakePageNotPresent + * @{ */ +/** The call is from an access handler for dealing with the a faulting write + * operation. The virtual address is within the same page. */ +#define PGM_MK_PG_IS_WRITE_FAULT RT_BIT(0) +/** The page is an MMIO2. */ +#define PGM_MK_PG_IS_MMIO2 RT_BIT(1) +/** @}*/ +VMMDECL(int) PGMGstGetPage(PVMCPUCC pVCpu, RTGCPTR GCPtr, PPGMPTWALK pWalk); +VMMDECL(int) PGMGstModifyPage(PVMCPUCC pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask); +VMM_INT_DECL(bool) PGMGstArePaePdpesValid(PVMCPUCC pVCpu, PCX86PDPE paPaePdpes); +VMM_INT_DECL(int) PGMGstMapPaePdpes(PVMCPUCC pVCpu, PCX86PDPE paPaePdpes); +VMM_INT_DECL(int) PGMGstMapPaePdpesAtCr3(PVMCPUCC pVCpu, uint64_t cr3); + +VMMDECL(int) PGMInvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCPtrPage); +VMMDECL(int) PGMFlushTLB(PVMCPUCC pVCpu, uint64_t cr3, bool fGlobal); +VMMDECL(int) PGMSyncCR3(PVMCPUCC pVCpu, uint64_t cr0, uint64_t cr3, uint64_t cr4, bool fGlobal); +VMMDECL(int) PGMUpdateCR3(PVMCPUCC pVCpu, uint64_t cr3); +VMMDECL(int) PGMChangeMode(PVMCPUCC pVCpu, uint64_t cr0, uint64_t cr4, uint64_t efer, bool fForce); +VMM_INT_DECL(int) PGMHCChangeMode(PVMCC pVM, PVMCPUCC pVCpu, PGMMODE enmGuestMode, bool fForce); +VMMDECL(void) PGMCr0WpEnabled(PVMCPUCC pVCpu); +VMMDECL(PGMMODE) PGMGetGuestMode(PVMCPU pVCpu); +VMMDECL(PGMMODE) PGMGetShadowMode(PVMCPU pVCpu); +VMMDECL(PGMMODE) PGMGetHostMode(PVM pVM); +VMMDECL(const char *) PGMGetModeName(PGMMODE enmMode); +#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT +VMM_INT_DECL(const char *) PGMGetSlatModeName(PGMSLAT enmSlatMode); +#endif +VMM_INT_DECL(RTGCPHYS) PGMGetGuestCR3Phys(PVMCPU pVCpu); +VMM_INT_DECL(void) PGMNotifyNxeChanged(PVMCPU pVCpu, bool fNxe); +VMMDECL(bool) PGMHasDirtyPages(PVM pVM); +VMM_INT_DECL(void) PGMSetGuestEptPtr(PVMCPUCC pVCpu, uint64_t uEptPtr); + +/** PGM physical access handler type registration handle (heap offset, valid + * cross contexts without needing fixing up). Callbacks and handler type is + * associated with this and it is shared by all handler registrations. */ +typedef uint64_t PGMPHYSHANDLERTYPE; +/** Pointer to a PGM physical handler type registration handle. */ +typedef PGMPHYSHANDLERTYPE *PPGMPHYSHANDLERTYPE; +/** NIL value for PGM physical access handler type handle. */ +#define NIL_PGMPHYSHANDLERTYPE UINT64_MAX +VMMDECL(int) PGMHandlerPhysicalRegister(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, PGMPHYSHANDLERTYPE hType, + uint64_t uUser, R3PTRTYPE(const char *) pszDesc); +VMMDECL(int) PGMHandlerPhysicalModify(PVMCC pVM, RTGCPHYS GCPhysCurrent, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast); +VMMDECL(int) PGMHandlerPhysicalDeregister(PVMCC pVM, RTGCPHYS GCPhys); +VMMDECL(int) PGMHandlerPhysicalChangeUserArg(PVMCC pVM, RTGCPHYS GCPhys, uint64_t uUser); +VMMDECL(int) PGMHandlerPhysicalSplit(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysSplit); +VMMDECL(int) PGMHandlerPhysicalJoin(PVMCC pVM, RTGCPHYS GCPhys1, RTGCPHYS GCPhys2); +VMMDECL(int) PGMHandlerPhysicalPageTempOff(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage); +VMMDECL(int) PGMHandlerPhysicalPageAliasMmio2(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage, + PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS offMMio2PageRemap); +VMMDECL(int) PGMHandlerPhysicalPageAliasHC(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage, RTHCPHYS HCPhysPageRemap); +VMMDECL(int) PGMHandlerPhysicalReset(PVMCC pVM, RTGCPHYS GCPhys); +VMMDECL(bool) PGMHandlerPhysicalIsRegistered(PVMCC pVM, RTGCPHYS GCPhys); + +/** @name PGMPHYSHANDLER_F_XXX - flags for PGMR3HandlerPhysicalTypeRegister and PGMR0HandlerPhysicalTypeRegister + * @{ */ +/** Whether to hold the PGM lock while calling the handler or not. + * Mainly an optimization for PGM callers. */ +#define PGMPHYSHANDLER_F_KEEP_PGM_LOCK RT_BIT_32(0) +/** The uUser value is a ring-0 device instance index that needs translating + * into a PDMDEVINS pointer before calling the handler. This is a hack to make + * it possible to use access handlers in devices. */ +#define PGMPHYSHANDLER_F_R0_DEVINS_IDX RT_BIT_32(1) +/** Don't apply the access handler to VT-x and AMD-V. Only works with full pages. + * This is a trick for the VT-x APIC access page in nested VT-x setups. */ +#define PGMPHYSHANDLER_F_NOT_IN_HM RT_BIT_32(2) +/** Mask of valid bits. */ +#define PGMPHYSHANDLER_F_VALID_MASK UINT32_C(7) +/** @} */ + + +/** + * Page type. + * + * @remarks This enum has to fit in a 3-bit field (see PGMPAGE::u3Type). + * @remarks This is used in the saved state, so changes to it requires bumping + * the saved state version. + * @todo So, convert to \#defines! + */ +typedef enum PGMPAGETYPE +{ + /** The usual invalid zero entry. */ + PGMPAGETYPE_INVALID = 0, + /** RAM page. (RWX) */ + PGMPAGETYPE_RAM, + /** MMIO2 page. (RWX) */ + PGMPAGETYPE_MMIO2, + /** MMIO2 page aliased over an MMIO page. (RWX) + * See PGMHandlerPhysicalPageAlias(). */ + PGMPAGETYPE_MMIO2_ALIAS_MMIO, + /** Special page aliased over an MMIO page. (RWX) + * See PGMHandlerPhysicalPageAliasHC(), but this is generally only used for + * VT-x's APIC access page at the moment. Treated as MMIO by everyone except + * the shadow paging code. */ + PGMPAGETYPE_SPECIAL_ALIAS_MMIO, + /** Shadowed ROM. (RWX) */ + PGMPAGETYPE_ROM_SHADOW, + /** ROM page. (R-X) */ + PGMPAGETYPE_ROM, + /** MMIO page. (---) */ + PGMPAGETYPE_MMIO, + /** End of valid entries. */ + PGMPAGETYPE_END +} PGMPAGETYPE; +AssertCompile(PGMPAGETYPE_END == 8); + +/** @name PGM page type predicates. + * @{ */ +#define PGMPAGETYPE_IS_READABLE(a_enmType) ( (a_enmType) <= PGMPAGETYPE_ROM ) +#define PGMPAGETYPE_IS_WRITEABLE(a_enmType) ( (a_enmType) <= PGMPAGETYPE_ROM_SHADOW ) +#define PGMPAGETYPE_IS_RWX(a_enmType) ( (a_enmType) <= PGMPAGETYPE_ROM_SHADOW ) +#define PGMPAGETYPE_IS_ROX(a_enmType) ( (a_enmType) == PGMPAGETYPE_ROM ) +#define PGMPAGETYPE_IS_NP(a_enmType) ( (a_enmType) == PGMPAGETYPE_MMIO ) +/** @} */ + + +VMM_INT_DECL(PGMPAGETYPE) PGMPhysGetPageType(PVMCC pVM, RTGCPHYS GCPhys); + +VMM_INT_DECL(int) PGMPhysGCPhys2HCPhys(PVMCC pVM, RTGCPHYS GCPhys, PRTHCPHYS pHCPhys); +VMM_INT_DECL(int) PGMPhysGCPtr2HCPhys(PVMCPUCC pVCpu, RTGCPTR GCPtr, PRTHCPHYS pHCPhys); +VMM_INT_DECL(int) PGMPhysGCPhys2CCPtr(PVMCC pVM, RTGCPHYS GCPhys, void **ppv, PPGMPAGEMAPLOCK pLock); +VMM_INT_DECL(int) PGMPhysGCPhys2CCPtrReadOnly(PVMCC pVM, RTGCPHYS GCPhys, void const **ppv, PPGMPAGEMAPLOCK pLock); +VMM_INT_DECL(int) PGMPhysGCPtr2CCPtr(PVMCPU pVCpu, RTGCPTR GCPtr, void **ppv, PPGMPAGEMAPLOCK pLock); +VMM_INT_DECL(int) PGMPhysGCPtr2CCPtrReadOnly(PVMCPUCC pVCpu, RTGCPTR GCPtr, void const **ppv, PPGMPAGEMAPLOCK pLock); + +VMMDECL(bool) PGMPhysIsA20Enabled(PVMCPU pVCpu); +VMMDECL(bool) PGMPhysIsGCPhysValid(PVMCC pVM, RTGCPHYS GCPhys); +VMMDECL(bool) PGMPhysIsGCPhysNormal(PVMCC pVM, RTGCPHYS GCPhys); +VMMDECL(int) PGMPhysGCPtr2GCPhys(PVMCPUCC pVCpu, RTGCPTR GCPtr, PRTGCPHYS pGCPhys); +VMMDECL(void) PGMPhysReleasePageMappingLock(PVMCC pVM, PPGMPAGEMAPLOCK pLock); +VMMDECL(void) PGMPhysBulkReleasePageMappingLocks(PVMCC pVM, uint32_t cPages, PPGMPAGEMAPLOCK paLock); + +/** @def PGM_PHYS_RW_IS_SUCCESS + * Check whether a PGMPhysRead, PGMPhysWrite, PGMPhysReadGCPtr or + * PGMPhysWriteGCPtr call completed the given task. + * + * @returns true if completed, false if not. + * @param a_rcStrict The status code. + * @sa IOM_SUCCESS + */ +#ifdef IN_RING3 +# define PGM_PHYS_RW_IS_SUCCESS(a_rcStrict) \ + ( (a_rcStrict) == VINF_SUCCESS \ + || (a_rcStrict) == VINF_EM_DBG_STOP \ + || (a_rcStrict) == VINF_EM_DBG_EVENT \ + || (a_rcStrict) == VINF_EM_DBG_BREAKPOINT \ + ) +#elif defined(IN_RING0) +# define PGM_PHYS_RW_IS_SUCCESS(a_rcStrict) \ + ( (a_rcStrict) == VINF_SUCCESS \ + || (a_rcStrict) == VINF_IOM_R3_MMIO_COMMIT_WRITE \ + || (a_rcStrict) == VINF_EM_OFF \ + || (a_rcStrict) == VINF_EM_SUSPEND \ + || (a_rcStrict) == VINF_EM_RESET \ + || (a_rcStrict) == VINF_EM_HALT \ + || (a_rcStrict) == VINF_EM_DBG_STOP \ + || (a_rcStrict) == VINF_EM_DBG_EVENT \ + || (a_rcStrict) == VINF_EM_DBG_BREAKPOINT \ + ) +#elif defined(IN_RC) +# define PGM_PHYS_RW_IS_SUCCESS(a_rcStrict) \ + ( (a_rcStrict) == VINF_SUCCESS \ + || (a_rcStrict) == VINF_IOM_R3_MMIO_COMMIT_WRITE \ + || (a_rcStrict) == VINF_EM_OFF \ + || (a_rcStrict) == VINF_EM_SUSPEND \ + || (a_rcStrict) == VINF_EM_RESET \ + || (a_rcStrict) == VINF_EM_HALT \ + || (a_rcStrict) == VINF_SELM_SYNC_GDT \ + || (a_rcStrict) == VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT \ + || (a_rcStrict) == VINF_EM_DBG_STOP \ + || (a_rcStrict) == VINF_EM_DBG_EVENT \ + || (a_rcStrict) == VINF_EM_DBG_BREAKPOINT \ + ) +#endif +/** @def PGM_PHYS_RW_DO_UPDATE_STRICT_RC + * Updates the return code with a new result. + * + * Both status codes must be successes according to PGM_PHYS_RW_IS_SUCCESS. + * + * @param a_rcStrict The current return code, to be updated. + * @param a_rcStrict2 The new return code to merge in. + */ +#ifdef IN_RING3 +# define PGM_PHYS_RW_DO_UPDATE_STRICT_RC(a_rcStrict, a_rcStrict2) \ + do { \ + Assert(rcStrict == VINF_SUCCESS); \ + Assert(rcStrict2 == VINF_SUCCESS); \ + } while (0) +#elif defined(IN_RING0) +# define PGM_PHYS_RW_DO_UPDATE_STRICT_RC(a_rcStrict, a_rcStrict2) \ + do { \ + Assert(PGM_PHYS_RW_IS_SUCCESS(rcStrict)); \ + Assert(PGM_PHYS_RW_IS_SUCCESS(rcStrict2)); \ + AssertCompile(VINF_IOM_R3_MMIO_COMMIT_WRITE > VINF_EM_LAST); \ + if ((a_rcStrict2) == VINF_SUCCESS || (a_rcStrict) == (a_rcStrict2)) \ + { /* likely */ } \ + else if ( (a_rcStrict) == VINF_SUCCESS \ + || (a_rcStrict) > (a_rcStrict2)) \ + (a_rcStrict) = (a_rcStrict2); \ + } while (0) +#elif defined(IN_RC) +# define PGM_PHYS_RW_DO_UPDATE_STRICT_RC(a_rcStrict, a_rcStrict2) \ + do { \ + Assert(PGM_PHYS_RW_IS_SUCCESS(rcStrict)); \ + Assert(PGM_PHYS_RW_IS_SUCCESS(rcStrict2)); \ + AssertCompile(VINF_SELM_SYNC_GDT > VINF_EM_LAST); \ + AssertCompile(VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT > VINF_EM_LAST); \ + AssertCompile(VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT < VINF_SELM_SYNC_GDT); \ + AssertCompile(VINF_IOM_R3_MMIO_COMMIT_WRITE > VINF_EM_LAST); \ + AssertCompile(VINF_IOM_R3_MMIO_COMMIT_WRITE > VINF_SELM_SYNC_GDT); \ + AssertCompile(VINF_IOM_R3_MMIO_COMMIT_WRITE > VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT); \ + if ((a_rcStrict2) == VINF_SUCCESS || (a_rcStrict) == (a_rcStrict2)) \ + { /* likely */ } \ + else if ((a_rcStrict) == VINF_SUCCESS) \ + (a_rcStrict) = (a_rcStrict2); \ + else if ( ( (a_rcStrict) > (a_rcStrict2) \ + && ( (a_rcStrict2) <= VINF_EM_RESET \ + || (a_rcStrict) != VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT) ) \ + || ( (a_rcStrict2) == VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT \ + && (a_rcStrict) > VINF_EM_RESET) ) \ + (a_rcStrict) = (a_rcStrict2); \ + } while (0) +#endif + +VMMDECL(VBOXSTRICTRC) PGMPhysRead(PVMCC pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, PGMACCESSORIGIN enmOrigin); +VMMDECL(VBOXSTRICTRC) PGMPhysWrite(PVMCC pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, PGMACCESSORIGIN enmOrigin); +VMMDECL(VBOXSTRICTRC) PGMPhysReadGCPtr(PVMCPUCC pVCpu, void *pvDst, RTGCPTR GCPtrSrc, size_t cb, PGMACCESSORIGIN enmOrigin); +VMMDECL(VBOXSTRICTRC) PGMPhysWriteGCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb, PGMACCESSORIGIN enmOrigin); + +VMMDECL(int) PGMPhysSimpleReadGCPhys(PVMCC pVM, void *pvDst, RTGCPHYS GCPhysSrc, size_t cb); +VMMDECL(int) PGMPhysSimpleWriteGCPhys(PVMCC pVM, RTGCPHYS GCPhysDst, const void *pvSrc, size_t cb); +VMMDECL(int) PGMPhysSimpleReadGCPtr(PVMCPUCC pVCpu, void *pvDst, RTGCPTR GCPtrSrc, size_t cb); +VMMDECL(int) PGMPhysSimpleWriteGCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb); +VMMDECL(int) PGMPhysSimpleDirtyWriteGCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb); + +VMM_INT_DECL(int) PGMPhysIemGCPhys2Ptr(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, bool fWritable, bool fByPassHandlers, void **ppv, PPGMPAGEMAPLOCK pLock); +VMM_INT_DECL(int) PGMPhysIemQueryAccess(PVMCC pVM, RTGCPHYS GCPhys, bool fWritable, bool fByPassHandlers); +VMM_INT_DECL(int) PGMPhysIemGCPhys2PtrNoLock(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, uint64_t const volatile *puTlbPhysRev, +#if defined(IN_RC) + R3PTRTYPE(uint8_t *) *ppb, +#else + R3R0PTRTYPE(uint8_t *) *ppb, +#endif + uint64_t *pfTlb); +/** @name Flags returned by PGMPhysIemGCPhys2PtrNoLock + * @{ */ +#define PGMIEMGCPHYS2PTR_F_NO_WRITE RT_BIT_32(3) /**< Not writable (IEMTLBE_F_PG_NO_WRITE). */ +#define PGMIEMGCPHYS2PTR_F_NO_READ RT_BIT_32(4) /**< Not readable (IEMTLBE_F_PG_NO_READ). */ +#define PGMIEMGCPHYS2PTR_F_NO_MAPPINGR3 RT_BIT_32(7) /**< No ring-3 mapping (IEMTLBE_F_NO_MAPPINGR3). */ +#define PGMIEMGCPHYS2PTR_F_UNASSIGNED RT_BIT_32(8) /**< Unassgined memory (IEMTLBE_F_PG_UNASSIGNED). */ +/** @} */ + +/** Information returned by PGMPhysNemQueryPageInfo. */ +typedef struct PGMPHYSNEMPAGEINFO +{ + /** The host physical address of the page, NIL_HCPHYS if invalid page. */ + RTHCPHYS HCPhys; + /** The NEM access mode for the page, NEM_PAGE_PROT_XXX */ + uint32_t fNemProt : 8; + /** The NEM state associated with the PAGE. */ + uint32_t u2NemState : 2; + /** The NEM state associated with the PAGE before pgmPhysPageMakeWritable was called. */ + uint32_t u2OldNemState : 2; + /** Set if the page has handler. */ + uint32_t fHasHandlers : 1; + /** Set if is the zero page backing it. */ + uint32_t fZeroPage : 1; + /** Set if the page has handler. */ + PGMPAGETYPE enmType; +} PGMPHYSNEMPAGEINFO; +/** Pointer to page information for NEM. */ +typedef PGMPHYSNEMPAGEINFO *PPGMPHYSNEMPAGEINFO; +/** + * Callback for checking that the page is in sync while under the PGM lock. + * + * NEM passes this callback to PGMPhysNemQueryPageInfo to check that the page is + * in-sync between PGM and the native hypervisor API in an atomic fashion. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pVCpu The cross context per virtual CPU structure. Optional, + * see PGMPhysNemQueryPageInfo. + * @param GCPhys The guest physical address (not A20 masked). + * @param pInfo The page info structure. This function updates the + * u2NemState memory and the caller will update the PGMPAGE + * copy accordingly. + * @param pvUser Callback user argument. + */ +typedef DECLCALLBACKTYPE(int, FNPGMPHYSNEMCHECKPAGE,(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, PPGMPHYSNEMPAGEINFO pInfo, void *pvUser)); +/** Pointer to a FNPGMPHYSNEMCHECKPAGE function. */ +typedef FNPGMPHYSNEMCHECKPAGE *PFNPGMPHYSNEMCHECKPAGE; + +VMM_INT_DECL(int) PGMPhysNemPageInfoChecker(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, bool fMakeWritable, + PPGMPHYSNEMPAGEINFO pInfo, PFNPGMPHYSNEMCHECKPAGE pfnChecker, void *pvUser); + +/** + * Callback for use with PGMPhysNemEnumPagesByState. + * @returns VBox status code. + * Failure status will stop enumeration immediately and return. + * @param pVM The cross context VM structure. + * @param pVCpu The cross context per virtual CPU structure. Optional, + * see PGMPhysNemEnumPagesByState. + * @param GCPhys The guest physical address (not A20 masked). + * @param pu2NemState Pointer to variable with the NEM state. This can be + * update. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(int, FNPGMPHYSNEMENUMCALLBACK,(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, + uint8_t *pu2NemState, void *pvUser)); +/** Pointer to a FNPGMPHYSNEMENUMCALLBACK function. */ +typedef FNPGMPHYSNEMENUMCALLBACK *PFNPGMPHYSNEMENUMCALLBACK; +VMM_INT_DECL(int) PGMPhysNemEnumPagesByState(PVMCC pVM, PVMCPUCC VCpu, uint8_t uMinState, + PFNPGMPHYSNEMENUMCALLBACK pfnCallback, void *pvUser); + + +#ifdef VBOX_STRICT +VMMDECL(unsigned) PGMAssertHandlerAndFlagsInSync(PVMCC pVM); +VMMDECL(unsigned) PGMAssertNoMappingConflicts(PVM pVM); +VMMDECL(unsigned) PGMAssertCR3(PVMCC pVM, PVMCPUCC pVCpu, uint64_t cr3, uint64_t cr4); +#endif /* VBOX_STRICT */ + +VMMDECL(int) PGMSetLargePageUsage(PVMCC pVM, bool fUseLargePages); + +/** + * Query large page usage state + * + * @returns 0 - disabled, 1 - enabled + * @param pVM The cross context VM structure. + */ +#define PGMIsUsingLargePages(pVM) ((pVM)->pgm.s.fUseLargePages) + + +#ifdef IN_RING0 +/** @defgroup grp_pgm_r0 The PGM Host Context Ring-0 API + * @{ + */ +VMMR0_INT_DECL(int) PGMR0InitPerVMData(PGVM pGVM, RTR0MEMOBJ hMemObj); +VMMR0_INT_DECL(int) PGMR0InitVM(PGVM pGVM); +VMMR0_INT_DECL(void) PGMR0DoneInitVM(PGVM pGVM); +VMMR0_INT_DECL(void) PGMR0CleanupVM(PGVM pGVM); +VMMR0_INT_DECL(int) PGMR0PhysAllocateHandyPages(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) PGMR0PhysFlushHandyPages(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) PGMR0PhysAllocateLargePage(PGVM pGVM, VMCPUID idCpu, RTGCPHYS GCPhys); +VMMR0_INT_DECL(int) PGMR0PhysMMIO2MapKernel(PGVM pGVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, + size_t offSub, size_t cbSub, void **ppvMapping); +VMMR0_INT_DECL(int) PGMR0PhysSetupIoMmu(PGVM pGVM); +VMMR0_INT_DECL(int) PGMR0PhysHandlerInitReqHandler(PGVM pGVM, uint32_t cEntries); +VMMR0_INT_DECL(int) PGMR0HandlerPhysicalTypeSetUpContext(PGVM pGVM, PGMPHYSHANDLERKIND enmKind, uint32_t fFlags, + PFNPGMPHYSHANDLER pfnHandler, PFNPGMRZPHYSPFHANDLER pfnPfHandler, + const char *pszDesc, PGMPHYSHANDLERTYPE hType); + +VMMR0DECL(int) PGMR0SharedModuleCheck(PVMCC pVM, PGVM pGVM, VMCPUID idCpu, PGMMSHAREDMODULE pModule, + PCRTGCPTR64 paRegionsGCPtrs); +VMMR0DECL(int) PGMR0Trap0eHandlerNestedPaging(PGVM pGVM, PGVMCPU pGVCpu, PGMMODE enmShwPagingMode, RTGCUINT uErr, + PCPUMCTX pCtx, RTGCPHYS pvFault); +VMMR0DECL(VBOXSTRICTRC) PGMR0Trap0eHandlerNPMisconfig(PGVM pGVM, PGVMCPU pGVCpu, PGMMODE enmShwPagingMode, + PCPUMCTX pCtx, RTGCPHYS GCPhysFault, uint32_t uErr); +VMMR0_INT_DECL(int) PGMR0PoolGrow(PGVM pGVM, VMCPUID idCpu); + +# ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT +VMMR0DECL(VBOXSTRICTRC) PGMR0NestedTrap0eHandlerNestedPaging(PGVMCPU pGVCpu, PGMMODE enmShwPagingMode, RTGCUINT uErr, + PCPUMCTX pCtx, RTGCPHYS GCPhysNestedFault, + bool fIsLinearAddrValid, RTGCPTR GCPtrNestedFault, PPGMPTWALK pWalk); +# endif +/** @} */ +#endif /* IN_RING0 */ + + + +#ifdef IN_RING3 +/** @defgroup grp_pgm_r3 The PGM Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(void) PGMR3EnableNemMode(PVM pVM); +VMMR3_INT_DECL(bool) PGMR3IsNemModeEnabled(PVM pVM); +VMMR3DECL(int) PGMR3Init(PVM pVM); +VMMR3DECL(int) PGMR3InitFinalize(PVM pVM); +VMMR3_INT_DECL(int) PGMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3DECL(void) PGMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3DECL(void) PGMR3ResetCpu(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(void) PGMR3Reset(PVM pVM); +VMMR3_INT_DECL(void) PGMR3ResetNoMorePhysWritesFlag(PVM pVM); +VMMR3_INT_DECL(void) PGMR3MemSetup(PVM pVM, bool fReset); +VMMR3DECL(int) PGMR3Term(PVM pVM); + +VMMR3DECL(int) PGMR3PhysRegisterRam(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, const char *pszDesc); +VMMR3DECL(int) PGMR3PhysChangeMemBalloon(PVM pVM, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage); +VMMR3DECL(int) PGMR3PhysWriteProtectRAM(PVM pVM); +VMMR3DECL(uint32_t) PGMR3PhysGetRamRangeCount(PVM pVM); +VMMR3DECL(int) PGMR3PhysGetRange(PVM pVM, uint32_t iRange, PRTGCPHYS pGCPhysStart, PRTGCPHYS pGCPhysLast, + const char **ppszDesc, bool *pfIsMmio); +VMMR3DECL(int) PGMR3QueryMemoryStats(PUVM pUVM, uint64_t *pcbTotalMem, uint64_t *pcbPrivateMem, uint64_t *pcbSharedMem, uint64_t *pcbZeroMem); +VMMR3DECL(int) PGMR3QueryGlobalMemoryStats(PUVM pUVM, uint64_t *pcbAllocMem, uint64_t *pcbFreeMem, uint64_t *pcbBallonedMem, uint64_t *pcbSharedMem); + +VMMR3DECL(int) PGMR3PhysMMIORegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, PGMPHYSHANDLERTYPE hType, + uint64_t uUser, const char *pszDesc); +VMMR3DECL(int) PGMR3PhysMMIODeregister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb); + +/** @name PGMPHYS_MMIO2_FLAGS_XXX - MMIO2 registration flags. + * @see PGMR3PhysMmio2Register, PDMDevHlpMmio2Create + * @{ */ +/** Track dirty pages. + * @see PGMR3PhysMmio2QueryAndResetDirtyBitmap(), PGMR3PhysMmio2ControlDirtyPageTracking(). */ +#define PGMPHYS_MMIO2_FLAGS_TRACK_DIRTY_PAGES RT_BIT_32(0) +/** Valid flags. */ +#define PGMPHYS_MMIO2_FLAGS_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +VMMR3_INT_DECL(int) PGMR3PhysMmio2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS cb, + uint32_t fFlags, const char *pszDesc, void **ppv, PGMMMIO2HANDLE *phRegion); +VMMR3_INT_DECL(int) PGMR3PhysMmio2Deregister(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2); +VMMR3_INT_DECL(int) PGMR3PhysMmio2Map(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS GCPhys); +VMMR3_INT_DECL(int) PGMR3PhysMmio2Unmap(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS GCPhys); +VMMR3_INT_DECL(int) PGMR3PhysMmio2Reduce(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS cbRegion); +VMMR3_INT_DECL(int) PGMR3PhysMmio2ValidateHandle(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2); +VMMR3_INT_DECL(RTGCPHYS) PGMR3PhysMmio2GetMappingAddress(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2); +VMMR3_INT_DECL(int) PGMR3PhysMmio2ChangeRegionNo(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, uint32_t iNewRegion); +VMMR3_INT_DECL(int) PGMR3PhysMmio2QueryAndResetDirtyBitmap(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, + void *pvBitmap, size_t cbBitmap); +VMMR3_INT_DECL(int) PGMR3PhysMmio2ControlDirtyPageTracking(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, bool fEnabled); + +/** @name PGMPHYS_ROM_FLAGS_XXX - ROM registration flags. + * @see PGMR3PhysRegisterRom, PDMDevHlpROMRegister + * @{ */ +/** Inidicates that ROM shadowing should be enabled. */ +#define PGMPHYS_ROM_FLAGS_SHADOWED UINT8_C(0x01) +/** Indicates that what pvBinary points to won't go away + * and can be used for strictness checks. */ +#define PGMPHYS_ROM_FLAGS_PERMANENT_BINARY UINT8_C(0x02) +/** Indicates that the ROM is allowed to be missing from saved state. + * @note This is a hack for EFI, see @bugref{6940} */ +#define PGMPHYS_ROM_FLAGS_MAYBE_MISSING_FROM_STATE UINT8_C(0x04) +/** Valid flags. */ +#define PGMPHYS_ROM_FLAGS_VALID_MASK UINT8_C(0x07) +/** @} */ + +VMMR3DECL(int) PGMR3PhysRomRegister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS cb, + const void *pvBinary, uint32_t cbBinary, uint8_t fFlags, const char *pszDesc); +VMMR3DECL(int) PGMR3PhysRomProtect(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, PGMROMPROT enmProt); +VMMDECL(void) PGMR3PhysSetA20(PVMCPU pVCpu, bool fEnable); + +VMMR3_INT_DECL(int) PGMR3HandlerPhysicalTypeRegister(PVM pVM, PGMPHYSHANDLERKIND enmKind, uint32_t fFlags, + PFNPGMPHYSHANDLER pfnHandlerR3, const char *pszDesc, + PPGMPHYSHANDLERTYPE phType); + +VMMR3_INT_DECL(int) PGMR3PoolGrow(PVM pVM, PVMCPU pVCpu); + +VMMR3DECL(int) PGMR3PhysTlbGCPhys2Ptr(PVM pVM, RTGCPHYS GCPhys, bool fWritable, void **ppv); +VMMR3DECL(uint8_t) PGMR3PhysReadU8(PVM pVM, RTGCPHYS GCPhys, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(uint16_t) PGMR3PhysReadU16(PVM pVM, RTGCPHYS GCPhys, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(uint32_t) PGMR3PhysReadU32(PVM pVM, RTGCPHYS GCPhys, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(uint64_t) PGMR3PhysReadU64(PVM pVM, RTGCPHYS GCPhys, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(void) PGMR3PhysWriteU8(PVM pVM, RTGCPHYS GCPhys, uint8_t Value, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(void) PGMR3PhysWriteU16(PVM pVM, RTGCPHYS GCPhys, uint16_t Value, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(void) PGMR3PhysWriteU32(PVM pVM, RTGCPHYS GCPhys, uint32_t Value, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(void) PGMR3PhysWriteU64(PVM pVM, RTGCPHYS GCPhys, uint64_t Value, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(int) PGMR3PhysReadExternal(PVM pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(int) PGMR3PhysWriteExternal(PVM pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(int) PGMR3PhysGCPhys2CCPtrExternal(PVM pVM, RTGCPHYS GCPhys, void **ppv, PPGMPAGEMAPLOCK pLock); +VMMR3DECL(int) PGMR3PhysGCPhys2CCPtrReadOnlyExternal(PVM pVM, RTGCPHYS GCPhys, void const **ppv, PPGMPAGEMAPLOCK pLock); +VMMR3DECL(int) PGMR3PhysBulkGCPhys2CCPtrExternal(PVM pVM, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + void **papvPages, PPGMPAGEMAPLOCK paLocks); +VMMR3DECL(int) PGMR3PhysBulkGCPhys2CCPtrReadOnlyExternal(PVM pVM, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + void const **papvPages, PPGMPAGEMAPLOCK paLocks); +VMMR3DECL(void) PGMR3PhysChunkInvalidateTLB(PVM pVM); +VMMR3DECL(int) PGMR3PhysAllocateHandyPages(PVM pVM); + +VMMR3DECL(int) PGMR3CheckIntegrity(PVM pVM); + +VMMR3DECL(int) PGMR3DbgR3Ptr2GCPhys(PUVM pUVM, RTR3PTR R3Ptr, PRTGCPHYS pGCPhys); +VMMR3DECL(int) PGMR3DbgR3Ptr2HCPhys(PUVM pUVM, RTR3PTR R3Ptr, PRTHCPHYS pHCPhys); +VMMR3DECL(int) PGMR3DbgHCPhys2GCPhys(PUVM pUVM, RTHCPHYS HCPhys, PRTGCPHYS pGCPhys); +VMMR3_INT_DECL(int) PGMR3DbgReadGCPhys(PVM pVM, void *pvDst, RTGCPHYS GCPhysSrc, size_t cb, uint32_t fFlags, size_t *pcbRead); +VMMR3_INT_DECL(int) PGMR3DbgWriteGCPhys(PVM pVM, RTGCPHYS GCPhysDst, const void *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten); +VMMR3_INT_DECL(int) PGMR3DbgReadGCPtr(PVM pVM, void *pvDst, RTGCPTR GCPtrSrc, size_t cb, uint32_t fFlags, size_t *pcbRead); +VMMR3_INT_DECL(int) PGMR3DbgWriteGCPtr(PVM pVM, RTGCPTR GCPtrDst, void const *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten); +VMMR3_INT_DECL(int) PGMR3DbgScanPhysical(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cbRange, RTGCPHYS GCPhysAlign, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCPHYS pGCPhysHit); +VMMR3_INT_DECL(int) PGMR3DbgScanVirtual(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, RTGCPTR cbRange, RTGCPTR GCPtrAlign, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCUINTPTR pGCPhysHit); +VMMR3_INT_DECL(int) PGMR3DumpHierarchyShw(PVM pVM, uint64_t cr3, uint32_t fFlags, uint64_t u64FirstAddr, uint64_t u64LastAddr, uint32_t cMaxDepth, PCDBGFINFOHLP pHlp); +VMMR3_INT_DECL(int) PGMR3DumpHierarchyGst(PVM pVM, uint64_t cr3, uint32_t fFlags, RTGCPTR FirstAddr, RTGCPTR LastAddr, uint32_t cMaxDepth, PCDBGFINFOHLP pHlp); + + +/** @name Page sharing + * @{ */ +VMMR3DECL(int) PGMR3SharedModuleRegister(PVM pVM, VBOXOSFAMILY enmGuestOS, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule, + uint32_t cRegions, VMMDEVSHAREDREGIONDESC const *paRegions); +VMMR3DECL(int) PGMR3SharedModuleUnregister(PVM pVM, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule); +VMMR3DECL(int) PGMR3SharedModuleCheckAll(PVM pVM); +VMMR3DECL(int) PGMR3SharedModuleGetPageState(PVM pVM, RTGCPTR GCPtrPage, bool *pfShared, uint64_t *pfPageFlags); +/** @} */ + +/** @} */ +#endif /* IN_RING3 */ + +RT_C_DECLS_END + +/** @} */ +#endif /* !VBOX_INCLUDED_vmm_pgm_h */ + diff --git a/include/VBox/vmm/selm.h b/include/VBox/vmm/selm.h new file mode 100644 index 00000000..1b68e3f5 --- /dev/null +++ b/include/VBox/vmm/selm.h @@ -0,0 +1,114 @@ +/** @file + * SELM - The Selector Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_selm_h +#define VBOX_INCLUDED_vmm_selm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/x86.h> +#include <VBox/dis.h> +#include <VBox/vmm/dbgfsel.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_selm The Selector Monitor(/Manager) API + * @ingroup grp_vmm + * @{ + */ + +VMMDECL(int) SELMGetTSSInfo(PVM pVM, PVMCPU pVCpu, PRTGCUINTPTR pGCPtrTss, PRTGCUINTPTR pcbTss, bool *pfCanHaveIOBitmap); +VMMDECL(RTGCPTR) SELMToFlat(PVMCPUCC pVCpu, unsigned idxSeg, PCPUMCTX pCtx, RTGCPTR Addr); +VMMDECL(RTGCPTR) SELMToFlatBySel(PVM pVM, RTSEL Sel, RTGCPTR Addr); + +/** Flags for SELMToFlatEx(). + * @{ */ +/** Don't check the RPL,DPL or CPL. */ +#define SELMTOFLAT_FLAGS_NO_PL RT_BIT(8) +/** Flags contains CPL information. */ +#define SELMTOFLAT_FLAGS_HAVE_CPL RT_BIT(9) +/** CPL is 3. */ +#define SELMTOFLAT_FLAGS_CPL3 3 +/** CPL is 2. */ +#define SELMTOFLAT_FLAGS_CPL2 2 +/** CPL is 1. */ +#define SELMTOFLAT_FLAGS_CPL1 1 +/** CPL is 0. */ +#define SELMTOFLAT_FLAGS_CPL0 0 +/** Get the CPL from the flags. */ +#define SELMTOFLAT_FLAGS_CPL(fFlags) ((fFlags) & X86_SEL_RPL) +#define SELMTOFLAT_FLAGS_HYPER RT_BIT(10) +/** @} */ + +VMMDECL(int) SELMToFlatEx(PVMCPU pVCpu, unsigned idxSeg, PCPUMCTX pCtx, RTGCPTR Addr, uint32_t fFlags, PRTGCPTR ppvGC); +VMMDECL(int) SELMValidateAndConvertCSAddr(PVMCPU pVCpu, uint32_t fEFlags, RTSEL SelCPL, RTSEL SelCS, + PCPUMSELREG pSRegCS, RTGCPTR Addr, PRTGCPTR ppvFlat); +#ifdef VBOX_WITH_RAW_MODE +VMM_INT_DECL(void) SELMLoadHiddenSelectorReg(PVMCPU pVCpu, PCCPUMCTX pCtx, PCPUMSELREG pSReg); +#endif + + +#ifdef IN_RING3 +/** @defgroup grp_selm_r3 The SELM ring-3 Context API + * @{ + */ +VMMR3DECL(int) SELMR3Init(PVM pVM); +VMMR3DECL(void) SELMR3Relocate(PVM pVM); +VMMR3DECL(int) SELMR3Term(PVM pVM); +VMMR3DECL(void) SELMR3Reset(PVM pVM); +VMMR3DECL(int) SELMR3GetSelectorInfo(PVMCPU pVCpu, RTSEL Sel, PDBGFSELINFO pSelInfo); +VMMR3DECL(void) SELMR3DumpDescriptor(X86DESC Desc, RTSEL Sel, const char *pszMsg); +VMMR3DECL(void) SELMR3DumpGuestGDT(PVM pVM); +VMMR3DECL(void) SELMR3DumpGuestLDT(PVM pVM); + +/** @def SELMR3_DEBUG_CHECK + * Invokes SELMR3DebugCheck in stricts builds. */ +# ifdef VBOX_STRICT +# define SELMR3_DEBUG_CHECK(pVM) SELMR3DebugCheck(pVM) +# else +# define SELMR3_DEBUG_CHECK(pVM) do { } while (0) +# endif +/** @} */ +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_selm_h */ + diff --git a/include/VBox/vmm/ssm.h b/include/VBox/vmm/ssm.h new file mode 100644 index 00000000..591b5d7e --- /dev/null +++ b/include/VBox/vmm/ssm.h @@ -0,0 +1,1354 @@ +/** @file + * SSM - The Save State Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_ssm_h +#define VBOX_INCLUDED_vmm_ssm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/tm.h> +#include <VBox/vmm/vmapi.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_ssm The Saved State Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * Determine the major version of the SSM version. If the major SSM version of two snapshots is + * different, the snapshots are incompatible. + */ +#define SSM_VERSION_MAJOR(ver) ((ver) & 0xffff0000) + +/** + * Determine the minor version of the SSM version. If the major SSM version of two snapshots is + * the same, the code must handle incompatibilies between minor version changes (e.g. use dummy + * values for non-existent fields). + */ +#define SSM_VERSION_MINOR(ver) ((ver) & 0x0000ffff) + +/** + * Determine if the major version changed between two SSM versions. + */ +#define SSM_VERSION_MAJOR_CHANGED(ver1,ver2) (SSM_VERSION_MAJOR(ver1) != SSM_VERSION_MAJOR(ver2)) + +/** The special value for the final pass. */ +#define SSM_PASS_FINAL UINT32_MAX + + +#ifdef IN_RING3 +/** @defgroup grp_ssm_r3 The SSM Host Context Ring-3 API + * @{ + */ + + +/** + * What to do after the save/load operation. + */ +typedef enum SSMAFTER +{ + /** Invalid. */ + SSMAFTER_INVALID = 0, + /** Will resume the loaded state. */ + SSMAFTER_RESUME, + /** Will destroy the VM after saving. */ + SSMAFTER_DESTROY, + /** Will continue execution after saving the VM. */ + SSMAFTER_CONTINUE, + /** Will teleport the VM. + * The source VM will be destroyed (then one saving), the destination VM + * will continue execution. */ + SSMAFTER_TELEPORT, + /** Will debug the saved state. + * This is used to drop some of the stricter consitentcy checks so it'll + * load fine in the debugger or animator. */ + SSMAFTER_DEBUG_IT, + /** The file was opened using SSMR3Open() and we have no idea what the plan is. */ + SSMAFTER_OPENED +} SSMAFTER; + + +/** Pointer to a structure field description. */ +typedef struct SSMFIELD *PSSMFIELD; +/** Pointer to a const structure field description. */ +typedef const struct SSMFIELD *PCSSMFIELD; + +/** + * SSMFIELD Get/Put callback function. + * + * This is call for getting and putting the field it is associated with. It's + * up to the callback to work the saved state correctly. + * + * @returns VBox status code. + * + * @param pSSM The saved state handle. + * @param pField The field that is being processed. + * @param pvStruct Pointer to the structure. + * @param fFlags SSMSTRUCT_FLAGS_XXX. + * @param fGetOrPut True if getting, false if putting. + * @param pvUser The user argument specified to SSMR3GetStructEx or + * SSMR3PutStructEx. + */ +typedef DECLCALLBACKTYPE(int, FNSSMFIELDGETPUT,(PSSMHANDLE pSSM, const struct SSMFIELD *pField, void *pvStruct, + uint32_t fFlags, bool fGetOrPut, void *pvUser)); +/** Pointer to a SSMFIELD Get/Put callback. */ +typedef FNSSMFIELDGETPUT *PFNSSMFIELDGETPUT; + +/** + * SSM field transformers. + * + * These are stored in the SSMFIELD::pfnGetPutOrTransformer and must therefore + * have values outside the valid pointer range. + */ +typedef enum SSMFIELDTRANS +{ + /** Invalid. */ + SSMFIELDTRANS_INVALID = 0, + /** No transformation. */ + SSMFIELDTRANS_NO_TRANSFORMATION, + /** Guest context (GC) physical address. */ + SSMFIELDTRANS_GCPHYS, + /** Guest context (GC) virtual address. */ + SSMFIELDTRANS_GCPTR, + /** Raw-mode context (RC) virtual address. */ + SSMFIELDTRANS_RCPTR, + /** Array of raw-mode context (RC) virtual addresses. */ + SSMFIELDTRANS_RCPTR_ARRAY, + /** Host context (HC) virtual address used as a NULL indicator. See + * SSMFIELD_ENTRY_HCPTR_NI. */ + SSMFIELDTRANS_HCPTR_NI, + /** Array of SSMFIELDTRANS_HCPTR_NI. */ + SSMFIELDTRANS_HCPTR_NI_ARRAY, + /** Host context (HC) virtual address used to hold a unsigned 32-bit value. */ + SSMFIELDTRANS_HCPTR_HACK_U32, + /** Load a 32-bit unsigned filed from the state and zero extend it into a 64-bit + * structure member. */ + SSMFIELDTRANS_U32_ZX_U64, + + /** Ignorable field. See SSMFIELD_ENTRY_IGNORE. */ + SSMFIELDTRANS_IGNORE, + /** Ignorable guest context (GC) physical address. */ + SSMFIELDTRANS_IGN_GCPHYS, + /** Ignorable guest context (GC) virtual address. */ + SSMFIELDTRANS_IGN_GCPTR, + /** Ignorable raw-mode context (RC) virtual address. */ + SSMFIELDTRANS_IGN_RCPTR, + /** Ignorable host context (HC) virtual address. */ + SSMFIELDTRANS_IGN_HCPTR, + + /** Old field. + * Save as zeros and skip on restore (nowhere to restore it any longer). */ + SSMFIELDTRANS_OLD, + /** Old guest context (GC) physical address. */ + SSMFIELDTRANS_OLD_GCPHYS, + /** Old guest context (GC) virtual address. */ + SSMFIELDTRANS_OLD_GCPTR, + /** Old raw-mode context (RC) virtual address. */ + SSMFIELDTRANS_OLD_RCPTR, + /** Old host context (HC) virtual address. */ + SSMFIELDTRANS_OLD_HCPTR, + /** Old host context specific padding. + * The lower word is the size of 32-bit hosts, the upper for 64-bit hosts. */ + SSMFIELDTRANS_OLD_PAD_HC, + /** Old padding specific to the 32-bit Microsoft C Compiler. */ + SSMFIELDTRANS_OLD_PAD_MSC32, + + /** Padding that differs between 32-bit and 64-bit hosts. + * The first byte of SSMFIELD::cb contains the size for 32-bit hosts. + * The second byte of SSMFIELD::cb contains the size for 64-bit hosts. + * The upper word of SSMFIELD::cb contains the actual field size. + */ + SSMFIELDTRANS_PAD_HC, + /** Padding for 32-bit hosts only. + * SSMFIELD::cb has the same format as for SSMFIELDTRANS_PAD_HC. */ + SSMFIELDTRANS_PAD_HC32, + /** Padding for 64-bit hosts only. + * SSMFIELD::cb has the same format as for SSMFIELDTRANS_PAD_HC. */ + SSMFIELDTRANS_PAD_HC64, + /** Automatic compiler padding that may differ between 32-bit and + * 64-bit hosts. SSMFIELD::cb has the same format as for + * SSMFIELDTRANS_PAD_HC. */ + SSMFIELDTRANS_PAD_HC_AUTO, + /** Automatic compiler padding specific to the 32-bit Microsoft C + * compiler. + * SSMFIELD::cb has the same format as for SSMFIELDTRANS_PAD_HC. */ + SSMFIELDTRANS_PAD_MSC32_AUTO +} SSMFIELDTRANS; + +/** Tests if it's a padding field with the special SSMFIELD::cb format. + * @returns true / false. + * @param pfn The SSMFIELD::pfnGetPutOrTransformer value. + */ +#define SSMFIELDTRANS_IS_PADDING(pfn) \ + ( (uintptr_t)(pfn) >= SSMFIELDTRANS_PAD_HC && (uintptr_t)(pfn) <= SSMFIELDTRANS_PAD_MSC32_AUTO ) + +/** Tests if it's an entry for an old field. + * + * @returns true / false. + * @param pfn The SSMFIELD::pfnGetPutOrTransformer value. + */ +#define SSMFIELDTRANS_IS_OLD(pfn) \ + ( (uintptr_t)(pfn) >= SSMFIELDTRANS_OLD && (uintptr_t)(pfn) <= SSMFIELDTRANS_OLD_PAD_MSC32 ) + +/** + * A structure field description. + */ +typedef struct SSMFIELD +{ + /** Getter and putter callback or transformer index. */ + PFNSSMFIELDGETPUT pfnGetPutOrTransformer; + /** Field offset into the structure. */ + uint32_t off; + /** The size of the field. */ + uint32_t cb; + /** This field was first saved by this unit version number. */ + uint32_t uFirstVer; + /** Field name. */ + const char *pszName; +} SSMFIELD; + +/** Emit a SSMFIELD array entry. + * @internal */ +#define SSMFIELD_ENTRY_INT(Name, off, cb, enmTransformer, uFirstVer) \ + { (PFNSSMFIELDGETPUT)(uintptr_t)(enmTransformer), (uint32_t)(off), (uint32_t)(cb), (uFirstVer), Name } +/** Emit a SSMFIELD array entry. + * @internal */ +#define SSMFIELD_ENTRY_TF_INT(Type, Field, enmTransformer, uFirstVer) \ + SSMFIELD_ENTRY_INT(#Type "::" #Field, RT_UOFFSETOF(Type, Field), RT_SIZEOFMEMB(Type, Field), enmTransformer, uFirstVer) +/** Emit a SSMFIELD array entry for an old field. + * @internal */ +#define SSMFIELD_ENTRY_OLD_INT(Field, cb, enmTransformer) \ + SSMFIELD_ENTRY_INT("old::" #Field, UINT32_MAX / 2, (cb), enmTransformer, 0) +/** Emit a SSMFIELD array entry for an alignment padding. + * @internal */ +#define SSMFIELD_ENTRY_PAD_INT(Type, Field, cb32, cb64, enmTransformer) \ + SSMFIELD_ENTRY_INT(#Type "::" #Field, RT_UOFFSETOF(Type, Field), \ + (RT_SIZEOFMEMB(Type, Field) << 16) | (cb32) | ((cb64) << 8), enmTransformer, 0) +/** Emit a SSMFIELD array entry for an alignment padding. + * @internal */ +#define SSMFIELD_ENTRY_PAD_OTHER_INT(Type, Field, cb32, cb64, enmTransformer) \ + SSMFIELD_ENTRY_INT(#Type "::" #Field, UINT32_MAX / 2, 0 | (cb32) | ((cb64) << 8), enmTransformer, 0) + +/** Emit a SSMFIELD array entry. */ +#define SSMFIELD_ENTRY(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_NO_TRANSFORMATION, 0) +/** Emit a SSMFIELD array entry with first version. */ +#define SSMFIELD_ENTRY_VER(Type, Field, uFirstVer) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_NO_TRANSFORMATION, uFirstVer) +/** Emit a SSMFIELD array entry for a custom made field. This is intended + * for working around bitfields in old structures. */ +#define SSMFIELD_ENTRY_CUSTOM(Field, off, cb) SSMFIELD_ENTRY_INT("custom::" #Field, off, cb, \ + SSMFIELDTRANS_NO_TRANSFORMATION, 0) +/** Emit a SSMFIELD array entry for a RTGCPHYS type. */ +#define SSMFIELD_ENTRY_GCPHYS(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_GCPHYS, 0) +/** Emit a SSMFIELD array entry for a RTGCPTR type. */ +#define SSMFIELD_ENTRY_GCPTR(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_GCPTR, 0) +/** Emit a SSMFIELD array entry for a raw-mode context pointer. */ +#define SSMFIELD_ENTRY_RCPTR(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_RCPTR, 0) +/** Emit a SSMFIELD array entry for a raw-mode context pointer. */ +#define SSMFIELD_ENTRY_RCPTR_ARRAY(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_RCPTR_ARRAY, 0) +/** Emit a SSMFIELD array entry for a ring-0 or ring-3 pointer type that is only + * of interest as a NULL indicator. + * + * This is always restored as a 0 (NULL) or 1 value. When + * SSMSTRUCT_FLAGS_DONT_IGNORE is set, the pointer will be saved in its + * entirety, when clear it will be saved as a boolean. */ +#define SSMFIELD_ENTRY_HCPTR_NI(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_HCPTR_NI, 0) +/** Same as SSMFIELD_ENTRY_HCPTR_NI, except it's an array of the buggers. */ +#define SSMFIELD_ENTRY_HCPTR_NI_ARRAY(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_HCPTR_NI_ARRAY, 0) +/** Emit a SSMFIELD array entry for a ring-0 or ring-3 pointer type that has + * been hacked such that it will never exceed 32-bit. No sign extending. */ +#define SSMFIELD_ENTRY_HCPTR_HACK_U32(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_HCPTR_HACK_U32, 0) +/** Emit a SSMFIELD array entry for loading a 32-bit field into a 64-bit + * structure member, zero extending the value. */ +#define SSMFIELD_ENTRY_U32_ZX_U64(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_U32_ZX_U64, 0) + +/** Emit a SSMFIELD array entry for a field that can be ignored. + * It is stored as zeros if SSMSTRUCT_FLAGS_DONT_IGNORE is specified to + * SSMR3PutStructEx. The member is never touched upon restore. */ +#define SSMFIELD_ENTRY_IGNORE(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_IGNORE, 0) +/** Emit a SSMFIELD array entry for an ignorable RTGCPHYS type. */ +#define SSMFIELD_ENTRY_IGN_GCPHYS(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_IGN_GCPHYS, 0) +/** Emit a SSMFIELD array entry for an ignorable RTGCPHYS type. */ +#define SSMFIELD_ENTRY_IGN_GCPTR(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_IGN_GCPTR, 0) +/** Emit a SSMFIELD array entry for an ignorable raw-mode context pointer. */ +#define SSMFIELD_ENTRY_IGN_RCPTR(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_IGN_RCPTR, 0) +/** Emit a SSMFIELD array entry for an ignorable ring-3 or/and ring-0 pointer. */ +#define SSMFIELD_ENTRY_IGN_HCPTR(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_IGN_HCPTR, 0) + +/** Emit a SSMFIELD array entry for an old field that should be ignored now. + * It is stored as zeros and skipped on load. */ +#define SSMFIELD_ENTRY_OLD(Field, cb) SSMFIELD_ENTRY_OLD_INT(Field, cb, SSMFIELDTRANS_OLD) +/** Same as SSMFIELD_ENTRY_IGN_GCPHYS, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_GCPHYS(Field) SSMFIELD_ENTRY_OLD_INT(Field, sizeof(RTGCPHYS), SSMFIELDTRANS_OLD_GCPHYS) +/** Same as SSMFIELD_ENTRY_IGN_GCPTR, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_GCPTR(Field) SSMFIELD_ENTRY_OLD_INT(Field, sizeof(RTGCPTR), SSMFIELDTRANS_OLD_GCPTR) +/** Same as SSMFIELD_ENTRY_IGN_RCPTR, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_RCPTR(Field) SSMFIELD_ENTRY_OLD_INT(Field, sizeof(RTRCPTR), SSMFIELDTRANS_OLD_RCPTR) +/** Same as SSMFIELD_ENTRY_IGN_HCPTR, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_HCPTR(Field) SSMFIELD_ENTRY_OLD_INT(Field, sizeof(RTHCPTR), SSMFIELDTRANS_OLD_HCPTR) +/** Same as SSMFIELD_ENTRY_PAD_HC, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_PAD_HC(Field, cb32, cb64) \ + SSMFIELD_ENTRY_OLD_INT(Field, RT_MAKE_U32((cb32), (cb64)), SSMFIELDTRANS_OLD_PAD_HC) +/** Same as SSMFIELD_ENTRY_PAD_HC64, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_PAD_HC64(Field, cb) SSMFIELD_ENTRY_OLD_PAD_HC(Field, 0, cb) +/** Same as SSMFIELD_ENTRY_PAD_HC32, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_PAD_HC32(Field, cb) SSMFIELD_ENTRY_OLD_PAD_HC(Field, cb, 0) +/** Same as SSMFIELD_ENTRY_PAD_HC, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_PAD_MSC32(Field, cb) SSMFIELD_ENTRY_OLD_INT(Field, cb, SSMFIELDTRANS_OLD_PAD_MSC32) + +/** Emit a SSMFIELD array entry for a padding that differs in size between + * 64-bit and 32-bit hosts. */ +#define SSMFIELD_ENTRY_PAD_HC(Type, Field, cb32, cb64) SSMFIELD_ENTRY_PAD_INT( Type, Field, cb32, cb64, SSMFIELDTRANS_PAD_HC) +/** Emit a SSMFIELD array entry for a padding that is exclusive to 64-bit hosts. */ +#if HC_ARCH_BITS == 64 +# define SSMFIELD_ENTRY_PAD_HC64(Type, Field, cb) SSMFIELD_ENTRY_PAD_INT( Type, Field, 0, cb, SSMFIELDTRANS_PAD_HC64) +#else +# define SSMFIELD_ENTRY_PAD_HC64(Type, Field, cb) SSMFIELD_ENTRY_PAD_OTHER_INT(Type, Field, 0, cb, SSMFIELDTRANS_PAD_HC64) +#endif +/** Emit a SSMFIELD array entry for a 32-bit padding for on 64-bits hosts. */ +#if HC_ARCH_BITS == 32 +# define SSMFIELD_ENTRY_PAD_HC32(Type, Field, cb) SSMFIELD_ENTRY_PAD_INT( Type, Field, cb, 0, SSMFIELDTRANS_PAD_HC32) +#else +# define SSMFIELD_ENTRY_PAD_HC32(Type, Field, cb) SSMFIELD_ENTRY_PAD_OTHER_INT(Type, Field, cb, 0, SSMFIELDTRANS_PAD_HC32) +#endif +/** Emit a SSMFIELD array entry for an automatic compiler padding that may + * differ in size between 64-bit and 32-bit hosts. */ +#if HC_ARCH_BITS == 64 +# define SSMFIELD_ENTRY_PAD_HC_AUTO(cb32, cb64) \ + { \ + (PFNSSMFIELDGETPUT)(uintptr_t)(SSMFIELDTRANS_PAD_HC_AUTO), \ + UINT32_MAX / 2, (cb64 << 16) | (cb32) | ((cb64) << 8), 0, "<compiler-padding>" \ + } +#else +# define SSMFIELD_ENTRY_PAD_HC_AUTO(cb32, cb64) \ + { \ + (PFNSSMFIELDGETPUT)(uintptr_t)(SSMFIELDTRANS_PAD_HC_AUTO), \ + UINT32_MAX / 2, (cb32 << 16) | (cb32) | ((cb64) << 8), 0, "<compiler-padding>" \ + } +#endif +/** Emit a SSMFIELD array entry for an automatic compiler padding that is unique + * to the 32-bit microsoft compiler. This is usually used together with + * SSMFIELD_ENTRY_PAD_HC*. */ +#if HC_ARCH_BITS == 32 && defined(_MSC_VER) +# define SSMFIELD_ENTRY_PAD_MSC32_AUTO(cb) \ + { \ + (PFNSSMFIELDGETPUT)(uintptr_t)(SSMFIELDTRANS_PAD_MSC32_AUTO), \ + UINT32_MAX / 2, ((cb) << 16) | (cb), 0, "<msc32-padding>" \ + } +#else +# define SSMFIELD_ENTRY_PAD_MSC32_AUTO(cb) \ + { \ + (PFNSSMFIELDGETPUT)(uintptr_t)(SSMFIELDTRANS_PAD_MSC32_AUTO), \ + UINT32_MAX / 2, (cb), 0, "<msc32-padding>" \ + } +#endif + +/** Emit a SSMFIELD array entry for a field with a custom callback. */ +#define SSMFIELD_ENTRY_CALLBACK(Type, Field, pfnGetPut) \ + { (pfnGetPut), RT_UOFFSETOF(Type, Field), RT_SIZEOFMEMB(Type, Field), 0, #Type "::" #Field } +/** Emit the terminating entry of a SSMFIELD array. */ +#define SSMFIELD_ENTRY_TERM() \ + { (PFNSSMFIELDGETPUT)(uintptr_t)SSMFIELDTRANS_INVALID, UINT32_MAX, UINT32_MAX, UINT32_MAX, NULL } + + +/** @name SSMR3GetStructEx and SSMR3PutStructEx flags. + * @{ */ +/** The field descriptors must exactly cover the entire struct, A to Z. */ +#define SSMSTRUCT_FLAGS_FULL_STRUCT RT_BIT_32(0) +/** No start and end markers, just the raw bits. */ +#define SSMSTRUCT_FLAGS_NO_MARKERS RT_BIT_32(1) +/** Do not ignore any ignorable fields. */ +#define SSMSTRUCT_FLAGS_DONT_IGNORE RT_BIT_32(2) +/** Saved using SSMR3PutMem, don't be too strict. */ +#define SSMSTRUCT_FLAGS_SAVED_AS_MEM RT_BIT_32(3) +/** No introductory structure marker. Use when splitting up structures. */ +#define SSMSTRUCT_FLAGS_NO_LEAD_MARKER RT_BIT_32(4) +/** No trailing structure marker. Use when splitting up structures. */ +#define SSMSTRUCT_FLAGS_NO_TAIL_MARKER RT_BIT_32(5) + +/** Band-aid for old SSMR3PutMem/SSMR3GetMem of structurs with host pointers. + * @remarks This type is normally only used up to the first changes to the + * structures take place in order to make sure the conversion from + * SSMR3PutMem to field descriptors went smoothly. Replace with + * SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED when changing the structure. */ +#define SSMSTRUCT_FLAGS_MEM_BAND_AID ( SSMSTRUCT_FLAGS_DONT_IGNORE | SSMSTRUCT_FLAGS_FULL_STRUCT \ + | SSMSTRUCT_FLAGS_NO_MARKERS | SSMSTRUCT_FLAGS_SAVED_AS_MEM) +/** Band-aid for old SSMR3PutMem/SSMR3GetMem of structurs with host + * pointers, with relaxed checks. */ +#define SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED ( SSMSTRUCT_FLAGS_DONT_IGNORE \ + | SSMSTRUCT_FLAGS_NO_MARKERS | SSMSTRUCT_FLAGS_SAVED_AS_MEM) +/** Mask of the valid bits. */ +#define SSMSTRUCT_FLAGS_VALID_MASK UINT32_C(0x0000003f) +/** @} */ + + +/** The PDM Device callback variants. + * @{ + */ + +/** + * Prepare state live save operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @remarks The caller enters the device critical section prior to the call. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVLIVEPREP,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDEVLIVEPREP() function. */ +typedef FNSSMDEVLIVEPREP *PFNSSMDEVLIVEPREP; + +/** + * Execute state live save operation. + * + * This will be called repeatedly until all units vote that the live phase has + * been concluded. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @param uPass The pass. + * @remarks The caller enters the device critical section prior to the call. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVLIVEEXEC,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)); +/** Pointer to a FNSSMDEVLIVEEXEC() function. */ +typedef FNSSMDEVLIVEEXEC *PFNSSMDEVLIVEEXEC; + +/** + * Vote on whether the live part of the saving has been concluded. + * + * The vote stops once a unit has vetoed the decision, so don't rely upon this + * being called every time. + * + * @returns VBox status code. + * @retval VINF_SUCCESS if done. + * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. + * @retval VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN if the live saving of the unit is + * done and there is not need calling it again before the final pass. + * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. + * + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @remarks The caller enters the device critical section prior to the call. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVLIVEVOTE,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)); +/** Pointer to a FNSSMDEVLIVEVOTE() function. */ +typedef FNSSMDEVLIVEVOTE *PFNSSMDEVLIVEVOTE; + +/** + * Prepare state save operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVSAVEPREP,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDEVSAVEPREP() function. */ +typedef FNSSMDEVSAVEPREP *PFNSSMDEVSAVEPREP; + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVSAVEEXEC,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDEVSAVEEXEC() function. */ +typedef FNSSMDEVSAVEEXEC *PFNSSMDEVSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVSAVEDONE,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDEVSAVEDONE() function. */ +typedef FNSSMDEVSAVEDONE *PFNSSMDEVSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVLOADPREP,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDEVLOADPREP() function. */ +typedef FNSSMDEVLOADPREP *PFNSSMDEVLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @param uVersion Data layout version. + * @param uPass The pass. This is always SSM_PASS_FINAL for units + * that doesn't specify a pfnSaveLive callback. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVLOADEXEC,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)); +/** Pointer to a FNSSMDEVLOADEXEC() function. */ +typedef FNSSMDEVLOADEXEC *PFNSSMDEVLOADEXEC; + +/** + * Done state load operation. + * + * @returns VBox load code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVLOADDONE,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDEVLOADDONE() function. */ +typedef FNSSMDEVLOADDONE *PFNSSMDEVLOADDONE; + +/** @} */ + + +/** The PDM USB device callback variants. + * @{ + */ + +/** + * Prepare state live save operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBLIVEPREP,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMUSBLIVEPREP() function. */ +typedef FNSSMUSBLIVEPREP *PFNSSMUSBLIVEPREP; + +/** + * Execute state live save operation. + * + * This will be called repeatedly until all units vote that the live phase has + * been concluded. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + * @param uPass The pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBLIVEEXEC,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uPass)); +/** Pointer to a FNSSMUSBLIVEEXEC() function. */ +typedef FNSSMUSBLIVEEXEC *PFNSSMUSBLIVEEXEC; + +/** + * Vote on whether the live part of the saving has been concluded. + * + * The vote stops once a unit has vetoed the decision, so don't rely upon this + * being called every time. + * + * @returns VBox status code. + * @retval VINF_SUCCESS if done. + * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. + * @retval VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN if the live saving of the unit is + * done and there is not need calling it again before the final pass. + * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. + * + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBLIVEVOTE,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uPass)); +/** Pointer to a FNSSMUSBLIVEVOTE() function. */ +typedef FNSSMUSBLIVEVOTE *PFNSSMUSBLIVEVOTE; + +/** + * Prepare state save operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBSAVEPREP,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMUSBSAVEPREP() function. */ +typedef FNSSMUSBSAVEPREP *PFNSSMUSBSAVEPREP; + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBSAVEEXEC,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMUSBSAVEEXEC() function. */ +typedef FNSSMUSBSAVEEXEC *PFNSSMUSBSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBSAVEDONE,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMUSBSAVEDONE() function. */ +typedef FNSSMUSBSAVEDONE *PFNSSMUSBSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBLOADPREP,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMUSBLOADPREP() function. */ +typedef FNSSMUSBLOADPREP *PFNSSMUSBLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + * @param uVersion Data layout version. + * @param uPass The pass. This is always SSM_PASS_FINAL for units + * that doesn't specify a pfnSaveLive callback. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBLOADEXEC,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)); +/** Pointer to a FNSSMUSBLOADEXEC() function. */ +typedef FNSSMUSBLOADEXEC *PFNSSMUSBLOADEXEC; + +/** + * Done state load operation. + * + * @returns VBox load code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBLOADDONE,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMUSBLOADDONE() function. */ +typedef FNSSMUSBLOADDONE *PFNSSMUSBLOADDONE; + +/** @} */ + + +/** The PDM Driver callback variants. + * @{ + */ + +/** + * Prepare state live save operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the + * data unit. + * @param pSSM SSM operation handle. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVLIVEPREP,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDRVLIVEPREP() function. */ +typedef FNSSMDRVLIVEPREP *PFNSSMDRVLIVEPREP; + +/** + * Execute state live save operation. + * + * This will be called repeatedly until all units vote that the live phase has + * been concluded. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the + * data unit. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVLIVEEXEC,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM, uint32_t uPass)); +/** Pointer to a FNSSMDRVLIVEEXEC() function. */ +typedef FNSSMDRVLIVEEXEC *PFNSSMDRVLIVEEXEC; + +/** + * Vote on whether the live part of the saving has been concluded. + * + * The vote stops once a unit has vetoed the decision, so don't rely upon this + * being called every time. + * + * @returns VBox status code. + * @retval VINF_SUCCESS if done. + * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. + * @retval VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN if the live saving of the unit is + * done and there is not need calling it again before the final pass. + * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. + * + * @param pDrvIns Driver instance of the driver which registered the + * data unit. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVLIVEVOTE,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM, uint32_t uPass)); +/** Pointer to a FNSSMDRVLIVEVOTE() function. */ +typedef FNSSMDRVLIVEVOTE *PFNSSMDRVLIVEVOTE; + + +/** + * Prepare state save operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVSAVEPREP,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDRVSAVEPREP() function. */ +typedef FNSSMDRVSAVEPREP *PFNSSMDRVSAVEPREP; + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVSAVEEXEC,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDRVSAVEEXEC() function. */ +typedef FNSSMDRVSAVEEXEC *PFNSSMDRVSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVSAVEDONE,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDRVSAVEDONE() function. */ +typedef FNSSMDRVSAVEDONE *PFNSSMDRVSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVLOADPREP,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDRVLOADPREP() function. */ +typedef FNSSMDRVLOADPREP *PFNSSMDRVLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + * @param uVersion Data layout version. + * @param uPass The pass. This is always SSM_PASS_FINAL for units + * that doesn't specify a pfnSaveLive callback. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVLOADEXEC,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)); +/** Pointer to a FNSSMDRVLOADEXEC() function. */ +typedef FNSSMDRVLOADEXEC *PFNSSMDRVLOADEXEC; + +/** + * Done state load operation. + * + * @returns VBox load code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVLOADDONE,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDRVLOADDONE() function. */ +typedef FNSSMDRVLOADDONE *PFNSSMDRVLOADDONE; + +/** @} */ + + +/** The internal callback variants. + * @{ + */ + + +/** + * Prepare state live save operation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTLIVEPREP,(PVM pVM, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMINTLIVEPREP() function. */ +typedef FNSSMINTLIVEPREP *PFNSSMINTLIVEPREP; + +/** + * Execute state live save operation. + * + * This will be called repeatedly until all units vote that the live phase has + * been concluded. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTLIVEEXEC,(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)); +/** Pointer to a FNSSMINTLIVEEXEC() function. */ +typedef FNSSMINTLIVEEXEC *PFNSSMINTLIVEEXEC; + +/** + * Vote on whether the live part of the saving has been concluded. + * + * The vote stops once a unit has vetoed the decision, so don't rely upon this + * being called every time. + * + * @returns VBox status code. + * @retval VINF_SUCCESS if done. + * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. + * @retval VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN if the live saving of the unit is + * done and there is not need calling it again before the final pass. + * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. + * + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTLIVEVOTE,(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)); +/** Pointer to a FNSSMINTLIVEVOTE() function. */ +typedef FNSSMINTLIVEVOTE *PFNSSMINTLIVEVOTE; + +/** + * Prepare state save operation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTSAVEPREP,(PVM pVM, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMINTSAVEPREP() function. */ +typedef FNSSMINTSAVEPREP *PFNSSMINTSAVEPREP; + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTSAVEEXEC,(PVM pVM, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMINTSAVEEXEC() function. */ +typedef FNSSMINTSAVEEXEC *PFNSSMINTSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTSAVEDONE,(PVM pVM, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMINTSAVEDONE() function. */ +typedef FNSSMINTSAVEDONE *PFNSSMINTSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTLOADPREP,(PVM pVM, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMINTLOADPREP() function. */ +typedef FNSSMINTLOADPREP *PFNSSMINTLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + * @param uVersion Data layout version. + * @param uPass The pass. This is always SSM_PASS_FINAL for units + * that doesn't specify a pfnSaveLive callback. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTLOADEXEC,(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)); +/** Pointer to a FNSSMINTLOADEXEC() function. */ +typedef FNSSMINTLOADEXEC *PFNSSMINTLOADEXEC; + +/** + * Done state load operation. + * + * @returns VBox load code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTLOADDONE,(PVM pVM, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMINTLOADDONE() function. */ +typedef FNSSMINTLOADDONE *PFNSSMINTLOADDONE; + +/** @} */ + + +/** The External callback variants. + * @{ + */ + +/** + * Prepare state live save operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLIVEPREP,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNSSMEXTLIVEPREP() function. */ +typedef FNSSMEXTLIVEPREP *PFNSSMEXTLIVEPREP; + +/** + * Execute state live save operation. + * + * This will be called repeatedly until all units vote that the live phase has + * been concluded. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLIVEEXEC,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser, uint32_t uPass)); +/** Pointer to a FNSSMEXTLIVEEXEC() function. */ +typedef FNSSMEXTLIVEEXEC *PFNSSMEXTLIVEEXEC; + +/** + * Vote on whether the live part of the saving has been concluded. + * + * The vote stops once a unit has vetoed the decision, so don't rely upon this + * being called every time. + * + * @returns VBox status code. + * @retval VINF_SUCCESS if done. + * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. + * @retval VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN if the live saving of the unit is + * done and there is not need calling it again before the final pass. + * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. + * + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLIVEVOTE,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser, uint32_t uPass)); +/** Pointer to a FNSSMEXTLIVEVOTE() function. */ +typedef FNSSMEXTLIVEVOTE *PFNSSMEXTLIVEVOTE; + +/** + * Prepare state save operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTSAVEPREP,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNSSMEXTSAVEPREP() function. */ +typedef FNSSMEXTSAVEPREP *PFNSSMEXTSAVEPREP; + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTSAVEEXEC,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNSSMEXTSAVEEXEC() function. */ +typedef FNSSMEXTSAVEEXEC *PFNSSMEXTSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTSAVEDONE,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNSSMEXTSAVEDONE() function. */ +typedef FNSSMEXTSAVEDONE *PFNSSMEXTSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLOADPREP,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNSSMEXTLOADPREP() function. */ +typedef FNSSMEXTLOADPREP *PFNSSMEXTLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + * @param uVersion Data layout version. + * @param uPass The pass. This is always SSM_PASS_FINAL for units + * that doesn't specify a pfnSaveLive callback. + * @remark The odd return value is for legacy reasons. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLOADEXEC,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser, + uint32_t uVersion, uint32_t uPass)); +/** Pointer to a FNSSMEXTLOADEXEC() function. */ +typedef FNSSMEXTLOADEXEC *PFNSSMEXTLOADEXEC; + +/** + * Done state load operation. + * + * @returns VBox load code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLOADDONE,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNSSMEXTLOADDONE() function. */ +typedef FNSSMEXTLOADDONE *PFNSSMEXTLOADDONE; + +/** @} */ + + +/** + * SSM stream method table. + * + * This is used by external parties for teleporting over TCP or any other media. + * SSM also uses this internally for file access, thus the 2-3 file centric + * methods. + */ +typedef struct SSMSTRMOPS +{ + /** Struct magic + version (SSMSTRMOPS_VERSION). */ + uint32_t u32Version; + + /** + * Write bytes to the stream. + * + * @returns VBox status code. + * @param pvUser The user argument. + * @param offStream The stream offset we're (supposed to be) at. + * @param pvBuf Pointer to the data. + * @param cbToWrite The number of bytes to write. + */ + DECLCALLBACKMEMBER(int, pfnWrite,(void *pvUser, uint64_t offStream, const void *pvBuf, size_t cbToWrite)); + + /** + * Read bytes to the stream. + * + * @returns VBox status code. + * @param pvUser The user argument. + * @param offStream The stream offset we're (supposed to be) at. + * @param pvBuf Where to return the bytes. + * @param cbToRead The number of bytes to read. + * @param pcbRead Where to return the number of bytes actually + * read. This may differ from cbToRead when the + * end of the stream is encountered. + */ + DECLCALLBACKMEMBER(int, pfnRead,(void *pvUser, uint64_t offStream, void *pvBuf, size_t cbToRead, size_t *pcbRead)); + + /** + * Seeks in the stream. + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if the stream doesn't support this action. + * + * @param pvUser The user argument. + * @param offSeek The seek offset. + * @param uMethod RTFILE_SEEK_BEGIN, RTFILE_SEEK_END or + * RTFILE_SEEK_CURRENT. + * @param poffActual Where to store the new file position. Optional. + */ + DECLCALLBACKMEMBER(int, pfnSeek,(void *pvUser, int64_t offSeek, unsigned uMethod, uint64_t *poffActual)); + + /** + * Get the current stream position. + * + * @returns The correct stream position. + * @param pvUser The user argument. + */ + DECLCALLBACKMEMBER(uint64_t, pfnTell,(void *pvUser)); + + /** + * Get the size/length of the stream. + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if the stream doesn't support this action. + * + * @param pvUser The user argument. + * @param pcb Where to return the size/length. + */ + DECLCALLBACKMEMBER(int, pfnSize,(void *pvUser, uint64_t *pcb)); + + /** + * Check if the stream is OK or not (cancelled). + * + * @returns VBox status code. + * @param pvUser The user argument. + * + * @remarks The method is expected to do a LogRel on failure. + */ + DECLCALLBACKMEMBER(int, pfnIsOk,(void *pvUser)); + + /** + * Close the stream. + * + * @returns VBox status code. + * @param pvUser The user argument. + * @param fCancelled True if the operation was cancelled. + */ + DECLCALLBACKMEMBER(int, pfnClose,(void *pvUser, bool fCancelled)); + + /** Struct magic + version (SSMSTRMOPS_VERSION). */ + uint32_t u32EndVersion; +} SSMSTRMOPS; +/** Struct magic + version (SSMSTRMOPS_VERSION). */ +#define SSMSTRMOPS_VERSION UINT32_C(0x55aa0001) + + +VMMR3DECL(void) SSMR3Term(PVM pVM); +VMMR3_INT_DECL(int) +SSMR3RegisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, + size_t cbGuess, const char *pszBefore, + PFNSSMDEVLIVEPREP pfnLivePrep, PFNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVLIVEVOTE pfnLiveVote, + PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone, + PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone); +VMMR3_INT_DECL(int) +SSMR3RegisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, + PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote, + PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone, + PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone); +VMMR3_INT_DECL(int) +SSMR3RegisterUsb(PVM pVM, PPDMUSBINS pUsbIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, + PFNSSMUSBLIVEPREP pfnLivePrep, PFNSSMUSBLIVEEXEC pfnLiveExec, PFNSSMUSBLIVEVOTE pfnLiveVote, + PFNSSMUSBSAVEPREP pfnSavePrep, PFNSSMUSBSAVEEXEC pfnSaveExec, PFNSSMUSBSAVEDONE pfnSaveDone, + PFNSSMUSBLOADPREP pfnLoadPrep, PFNSSMUSBLOADEXEC pfnLoadExec, PFNSSMUSBLOADDONE pfnLoadDone); +VMMR3DECL(int) +SSMR3RegisterInternal(PVM pVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, + PFNSSMINTLIVEPREP pfnLivePrep, PFNSSMINTLIVEEXEC pfnLiveExec, PFNSSMINTLIVEVOTE pfnLiveVote, + PFNSSMINTSAVEPREP pfnSavePrep, PFNSSMINTSAVEEXEC pfnSaveExec, PFNSSMINTSAVEDONE pfnSaveDone, + PFNSSMINTLOADPREP pfnLoadPrep, PFNSSMINTLOADEXEC pfnLoadExec, PFNSSMINTLOADDONE pfnLoadDone); +VMMR3DECL(int) +SSMR3RegisterExternal(PUVM pUVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, + PFNSSMEXTLIVEPREP pfnLivePrep, PFNSSMEXTLIVEEXEC pfnLiveExec, PFNSSMEXTLIVEVOTE pfnLiveVote, + PFNSSMEXTSAVEPREP pfnSavePrep, PFNSSMEXTSAVEEXEC pfnSaveExec, PFNSSMEXTSAVEDONE pfnSaveDone, + PFNSSMEXTLOADPREP pfnLoadPrep, PFNSSMEXTLOADEXEC pfnLoadExec, PFNSSMEXTLOADDONE pfnLoadDone, void *pvUser); +VMMR3DECL(int) SSMR3RegisterStub(PVM pVM, const char *pszName, uint32_t uInstance); +VMMR3_INT_DECL(int) SSMR3DeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t uInstance); +VMMR3_INT_DECL(int) SSMR3DeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance); +VMMR3_INT_DECL(int) SSMR3DeregisterUsb(PVM pVM, PPDMUSBINS pUsbIns, const char *pszName, uint32_t uInstance); +VMMR3DECL(int) SSMR3DeregisterInternal(PVM pVM, const char *pszName); +VMMR3DECL(int) SSMR3DeregisterExternal(PUVM pUVM, const char *pszName); +VMMR3DECL(int) SSMR3Save(PVM pVM, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser); +VMMR3_INT_DECL(int) SSMR3LiveSave(PVM pVM, uint32_t cMsMaxDowntime, + const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOps, + SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvProgressUser, + PSSMHANDLE *ppSSM); +VMMR3_INT_DECL(int) SSMR3LiveDoStep1(PSSMHANDLE pSSM); +VMMR3_INT_DECL(int) SSMR3LiveDoStep2(PSSMHANDLE pSSM); +VMMR3_INT_DECL(int) SSMR3LiveDone(PSSMHANDLE pSSM); +VMMR3DECL(int) SSMR3Load(PVM pVM, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, + SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvProgressUser); +VMMR3DECL(int) SSMR3ValidateFile(const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOps, + bool fChecksumIt); +VMMR3DECL(int) SSMR3Open(const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOps, + unsigned fFlags, PSSMHANDLE *ppSSM); +VMMR3DECL(int) SSMR3Close(PSSMHANDLE pSSM); +VMMR3DECL(int) SSMR3Seek(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion); +VMMR3DECL(int) SSMR3HandleGetStatus(PSSMHANDLE pSSM); +VMMR3DECL(int) SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus); +VMMR3DECL(SSMAFTER) SSMR3HandleGetAfter(PSSMHANDLE pSSM); +VMMR3DECL(bool) SSMR3HandleIsLiveSave(PSSMHANDLE pSSM); +VMMR3DECL(uint32_t) SSMR3HandleMaxDowntime(PSSMHANDLE pSSM); +VMMR3DECL(uint32_t) SSMR3HandleHostBits(PSSMHANDLE pSSM); +VMMR3DECL(uint32_t) SSMR3HandleRevision(PSSMHANDLE pSSM); +VMMR3DECL(uint32_t) SSMR3HandleVersion(PSSMHANDLE pSSM); +VMMR3DECL(const char *) SSMR3HandleHostOSAndArch(PSSMHANDLE pSSM); +VMMR3_INT_DECL(int) SSMR3HandleSetGCPtrSize(PSSMHANDLE pSSM, unsigned cbGCPtr); +VMMR3DECL(void) SSMR3HandleReportLivePercent(PSSMHANDLE pSSM, unsigned uPercent); +#ifdef DEBUG +VMMR3DECL(uint64_t) SSMR3HandleTellInUnit(PSSMHANDLE pSSM); +#endif +VMMR3DECL(int) SSMR3Cancel(PUVM pUVM); + + +/** Save operations. + * @{ + */ +VMMR3DECL(int) SSMR3PutStruct(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields); +VMMR3DECL(int) SSMR3PutStructEx(PSSMHANDLE pSSM, const void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser); +VMMR3DECL(int) SSMR3PutBool(PSSMHANDLE pSSM, bool fBool); +VMMR3DECL(int) SSMR3PutU8(PSSMHANDLE pSSM, uint8_t u8); +VMMR3DECL(int) SSMR3PutS8(PSSMHANDLE pSSM, int8_t i8); +VMMR3DECL(int) SSMR3PutU16(PSSMHANDLE pSSM, uint16_t u16); +VMMR3DECL(int) SSMR3PutS16(PSSMHANDLE pSSM, int16_t i16); +VMMR3DECL(int) SSMR3PutU32(PSSMHANDLE pSSM, uint32_t u32); +VMMR3DECL(int) SSMR3PutS32(PSSMHANDLE pSSM, int32_t i32); +VMMR3DECL(int) SSMR3PutU64(PSSMHANDLE pSSM, uint64_t u64); +VMMR3DECL(int) SSMR3PutS64(PSSMHANDLE pSSM, int64_t i64); +VMMR3DECL(int) SSMR3PutU128(PSSMHANDLE pSSM, uint128_t u128); +VMMR3DECL(int) SSMR3PutS128(PSSMHANDLE pSSM, int128_t i128); +VMMR3DECL(int) SSMR3PutUInt(PSSMHANDLE pSSM, RTUINT u); +VMMR3DECL(int) SSMR3PutSInt(PSSMHANDLE pSSM, RTINT i); +VMMR3DECL(int) SSMR3PutGCUInt(PSSMHANDLE pSSM, RTGCUINT u); +VMMR3DECL(int) SSMR3PutGCUIntReg(PSSMHANDLE pSSM, RTGCUINTREG u); +VMMR3DECL(int) SSMR3PutGCPhys32(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys); +VMMR3DECL(int) SSMR3PutGCPhys64(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys); +VMMR3DECL(int) SSMR3PutGCPhys(PSSMHANDLE pSSM, RTGCPHYS GCPhys); +VMMR3DECL(int) SSMR3PutGCPtr(PSSMHANDLE pSSM, RTGCPTR GCPtr); +VMMR3DECL(int) SSMR3PutGCUIntPtr(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr); +VMMR3DECL(int) SSMR3PutRCPtr(PSSMHANDLE pSSM, RTRCPTR RCPtr); +VMMR3DECL(int) SSMR3PutIOPort(PSSMHANDLE pSSM, RTIOPORT IOPort); +VMMR3DECL(int) SSMR3PutSel(PSSMHANDLE pSSM, RTSEL Sel); +VMMR3DECL(int) SSMR3PutMem(PSSMHANDLE pSSM, const void *pv, size_t cb); +VMMR3DECL(int) SSMR3PutStrZ(PSSMHANDLE pSSM, const char *psz); +/** @} */ + + + +/** Load operations. + * @{ + */ +VMMR3DECL(int) SSMR3GetStruct(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields); +VMMR3DECL(int) SSMR3GetStructEx(PSSMHANDLE pSSM, void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser); +VMMR3DECL(int) SSMR3GetBool(PSSMHANDLE pSSM, bool *pfBool); +VMMR3DECL(int) SSMR3GetBoolV(PSSMHANDLE pSSM, bool volatile *pfBool); +VMMR3DECL(int) SSMR3GetU8(PSSMHANDLE pSSM, uint8_t *pu8); +VMMR3DECL(int) SSMR3GetU8V(PSSMHANDLE pSSM, uint8_t volatile *pu8); +VMMR3DECL(int) SSMR3GetS8(PSSMHANDLE pSSM, int8_t *pi8); +VMMR3DECL(int) SSMR3GetS8V(PSSMHANDLE pSSM, int8_t volatile *pi8); +VMMR3DECL(int) SSMR3GetU16(PSSMHANDLE pSSM, uint16_t *pu16); +VMMR3DECL(int) SSMR3GetU16V(PSSMHANDLE pSSM, uint16_t volatile *pu16); +VMMR3DECL(int) SSMR3GetS16(PSSMHANDLE pSSM, int16_t *pi16); +VMMR3DECL(int) SSMR3GetS16V(PSSMHANDLE pSSM, int16_t volatile *pi16); +VMMR3DECL(int) SSMR3GetU32(PSSMHANDLE pSSM, uint32_t *pu32); +VMMR3DECL(int) SSMR3GetU32V(PSSMHANDLE pSSM, uint32_t volatile *pu32); +VMMR3DECL(int) SSMR3GetS32(PSSMHANDLE pSSM, int32_t *pi32); +VMMR3DECL(int) SSMR3GetS32V(PSSMHANDLE pSSM, int32_t volatile *pi32); +VMMR3DECL(int) SSMR3GetU64(PSSMHANDLE pSSM, uint64_t *pu64); +VMMR3DECL(int) SSMR3GetU64V(PSSMHANDLE pSSM, uint64_t volatile *pu64); +VMMR3DECL(int) SSMR3GetS64(PSSMHANDLE pSSM, int64_t *pi64); +VMMR3DECL(int) SSMR3GetS64V(PSSMHANDLE pSSM, int64_t volatile *pi64); +VMMR3DECL(int) SSMR3GetU128(PSSMHANDLE pSSM, uint128_t *pu128); +VMMR3DECL(int) SSMR3GetU128V(PSSMHANDLE pSSM, uint128_t volatile *pu128); +VMMR3DECL(int) SSMR3GetS128(PSSMHANDLE pSSM, int128_t *pi128); +VMMR3DECL(int) SSMR3GetS128V(PSSMHANDLE pSSM, int128_t volatile *pi128); +VMMR3DECL(int) SSMR3GetGCPhys32(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhys32V(PSSMHANDLE pSSM, RTGCPHYS32 volatile *pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhys64(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhys64V(PSSMHANDLE pSSM, RTGCPHYS64 volatile *pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhys(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhysV(PSSMHANDLE pSSM, RTGCPHYS volatile *pGCPhys); +VMMR3DECL(int) SSMR3GetUInt(PSSMHANDLE pSSM, PRTUINT pu); +VMMR3DECL(int) SSMR3GetSInt(PSSMHANDLE pSSM, PRTINT pi); +VMMR3DECL(int) SSMR3GetGCUInt(PSSMHANDLE pSSM, PRTGCUINT pu); +VMMR3DECL(int) SSMR3GetGCUIntReg(PSSMHANDLE pSSM, PRTGCUINTREG pu); +VMMR3DECL(int) SSMR3GetGCPtr(PSSMHANDLE pSSM, PRTGCPTR pGCPtr); +VMMR3DECL(int) SSMR3GetGCUIntPtr(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr); +VMMR3DECL(int) SSMR3GetRCPtr(PSSMHANDLE pSSM, PRTRCPTR pRCPtr); +VMMR3DECL(int) SSMR3GetIOPort(PSSMHANDLE pSSM, PRTIOPORT pIOPort); +VMMR3DECL(int) SSMR3GetSel(PSSMHANDLE pSSM, PRTSEL pSel); +VMMR3DECL(int) SSMR3GetMem(PSSMHANDLE pSSM, void *pv, size_t cb); +VMMR3DECL(int) SSMR3GetStrZ(PSSMHANDLE pSSM, char *psz, size_t cbMax); +VMMR3DECL(int) SSMR3GetStrZEx(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr); +VMMR3DECL(int) SSMR3Skip(PSSMHANDLE pSSM, size_t cb); +VMMR3DECL(int) SSMR3SkipToEndOfUnit(PSSMHANDLE pSSM); +VMMR3DECL(int) SSMR3SetLoadError(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7); +VMMR3DECL(int) SSMR3SetLoadErrorV(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0); +VMMR3DECL(int) SSMR3SetCfgError(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6); +VMMR3DECL(int) SSMR3SetCfgErrorV(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0); + +/** Wrapper around SSMR3GetU32 for simplifying getting enum values saved as uint32_t. */ +# define SSM_GET_ENUM32_RET(a_pSSM, a_enmDst, a_EnumType) \ + do { \ + uint32_t u32GetEnumTmp = 0; \ + int rcGetEnum32Tmp = SSMR3GetU32((a_pSSM), &u32GetEnumTmp); \ + AssertRCReturn(rcGetEnum32Tmp, rcGetEnum32Tmp); \ + (a_enmDst) = (a_EnumType)u32GetEnumTmp; \ + AssertCompile(sizeof(a_EnumType) == sizeof(u32GetEnumTmp)); \ + } while (0) + +/** @} */ + +/** @} */ +#endif /* IN_RING3 */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_ssm_h */ + diff --git a/include/VBox/vmm/stam.h b/include/VBox/vmm/stam.h new file mode 100644 index 00000000..4c5764b4 --- /dev/null +++ b/include/VBox/vmm/stam.h @@ -0,0 +1,1376 @@ +/** @file + * STAM - Statistics Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_stam_h +#define VBOX_INCLUDED_vmm_stam_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/stdarg.h> +#ifdef _MSC_VER +# if RT_MSC_PREREQ(RT_MSC_VER_VS2005) +# include <iprt/sanitized/intrin.h> +# endif +#endif +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) +# include <iprt/asm-arm.h> +#endif + +RT_C_DECLS_BEGIN + +/** @defgroup grp_stam The Statistics Manager API + * @ingroup grp_vmm + * @{ + */ + +#if defined(VBOX_WITHOUT_RELEASE_STATISTICS) && defined(VBOX_WITH_STATISTICS) +# error "Both VBOX_WITHOUT_RELEASE_STATISTICS and VBOX_WITH_STATISTICS are defined! Make up your mind!" +#endif + + +/** @def STAM_GET_TS + * Gets the CPU timestamp counter. + * + * @param u64 The 64-bit variable which the timestamp shall be saved in. + */ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) +# define STAM_GET_TS(u64) do { (u64) = ASMReadTSC(); } while (0) +#elif defined(__GNUC__) +# if defined(RT_ARCH_X86) + /* This produces optimal assembler code for x86 but does not work for AMD64 ('A' means 'either rax or rdx') */ +# define STAM_GET_TS(u64) __asm__ __volatile__ ("rdtsc\n\t" : "=A" (u64)) +# elif defined(RT_ARCH_AMD64) +# define STAM_GET_TS(u64) \ + do { uint64_t low; uint64_t high; \ + __asm__ __volatile__ ("rdtsc\n\t" : "=a"(low), "=d"(high)); \ + (u64) = ((high << 32) | low); \ + } while (0) +# endif +#else +# if RT_MSC_PREREQ(RT_MSC_VER_VS2005) +# pragma intrinsic(__rdtsc) +# define STAM_GET_TS(u64) \ + do { (u64) = __rdtsc(); } while (0) +# else +# define STAM_GET_TS(u64) \ + do { \ + uint64_t u64Tmp; \ + __asm { \ + __asm rdtsc \ + __asm mov dword ptr [u64Tmp], eax \ + __asm mov dword ptr [u64Tmp + 4], edx \ + } \ + (u64) = u64Tmp; \ + } while (0) +# endif +#endif + + +/** @def STAM_REL_STATS + * Code for inclusion only when VBOX_WITH_STATISTICS is defined. + * @param code A code block enclosed in {}. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_STATS(code) do code while(0) +#else +# define STAM_REL_STATS(code) do {} while(0) +#endif +/** @def STAM_STATS + * Code for inclusion only when VBOX_WITH_STATISTICS is defined. + * @param code A code block enclosed in {}. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_STATS(code) STAM_REL_STATS(code) +#else +# define STAM_STATS(code) do {} while(0) +#endif + + +/** + * Sample type. + */ +typedef enum STAMTYPE +{ + /** Invalid entry. */ + STAMTYPE_INVALID = 0, + /** Generic counter. */ + STAMTYPE_COUNTER, + /** Profiling of an function. */ + STAMTYPE_PROFILE, + /** Profiling of an operation. */ + STAMTYPE_PROFILE_ADV, + /** Ratio of A to B, uint32_t types. Not reset. */ + STAMTYPE_RATIO_U32, + /** Ratio of A to B, uint32_t types. Reset both to 0. */ + STAMTYPE_RATIO_U32_RESET, + /** Callback. */ + STAMTYPE_CALLBACK, + /** Generic unsigned 8-bit value. Not reset. */ + STAMTYPE_U8, + /** Generic unsigned 8-bit value. Reset to 0. */ + STAMTYPE_U8_RESET, + /** Generic hexadecimal unsigned 8-bit value. Not reset. */ + STAMTYPE_X8, + /** Generic hexadecimal unsigned 8-bit value. Reset to 0. */ + STAMTYPE_X8_RESET, + /** Generic unsigned 16-bit value. Not reset. */ + STAMTYPE_U16, + /** Generic unsigned 16-bit value. Reset to 0. */ + STAMTYPE_U16_RESET, + /** Generic hexadecimal unsigned 16-bit value. Not reset. */ + STAMTYPE_X16, + /** Generic hexadecimal unsigned 16-bit value. Reset to 0. */ + STAMTYPE_X16_RESET, + /** Generic unsigned 32-bit value. Not reset. */ + STAMTYPE_U32, + /** Generic unsigned 32-bit value. Reset to 0. */ + STAMTYPE_U32_RESET, + /** Generic hexadecimal unsigned 32-bit value. Not reset. */ + STAMTYPE_X32, + /** Generic hexadecimal unsigned 32-bit value. Reset to 0. */ + STAMTYPE_X32_RESET, + /** Generic unsigned 64-bit value. Not reset. */ + STAMTYPE_U64, + /** Generic unsigned 64-bit value. Reset to 0. */ + STAMTYPE_U64_RESET, + /** Generic hexadecimal unsigned 64-bit value. Not reset. */ + STAMTYPE_X64, + /** Generic hexadecimal unsigned 64-bit value. Reset to 0. */ + STAMTYPE_X64_RESET, + /** Generic boolean value. Not reset. */ + STAMTYPE_BOOL, + /** Generic boolean value. Reset to false. */ + STAMTYPE_BOOL_RESET, + /** The end (exclusive). */ + STAMTYPE_END +} STAMTYPE; + +/** + * Sample visibility type. + */ +typedef enum STAMVISIBILITY +{ + /** Invalid entry. */ + STAMVISIBILITY_INVALID = 0, + /** Always visible. */ + STAMVISIBILITY_ALWAYS, + /** Only visible when used (/hit). */ + STAMVISIBILITY_USED, + /** Not visible in the GUI. */ + STAMVISIBILITY_NOT_GUI, + /** The end (exclusive). */ + STAMVISIBILITY_END +} STAMVISIBILITY; + +/** + * Sample unit. + */ +typedef enum STAMUNIT +{ + /** Invalid entry .*/ + STAMUNIT_INVALID = 0, + /** No unit. */ + STAMUNIT_NONE, + /** Number of calls. */ + STAMUNIT_CALLS, + /** Count of whatever. */ + STAMUNIT_COUNT, + /** Count of bytes. */ + STAMUNIT_BYTES, + /** Count of bytes per call. */ + STAMUNIT_BYTES_PER_CALL, + /** Count of bytes. */ + STAMUNIT_PAGES, + /** Error count. */ + STAMUNIT_ERRORS, + /** Number of occurences. */ + STAMUNIT_OCCURENCES, + /** Ticks. */ + STAMUNIT_TICKS, + /** Ticks per call. */ + STAMUNIT_TICKS_PER_CALL, + /** Ticks per occurence. */ + STAMUNIT_TICKS_PER_OCCURENCE, + /** Ratio of good vs. bad. */ + STAMUNIT_GOOD_BAD, + /** Megabytes. */ + STAMUNIT_MEGABYTES, + /** Kilobytes. */ + STAMUNIT_KILOBYTES, + /** Nano seconds. */ + STAMUNIT_NS, + /** Nanoseconds per call. */ + STAMUNIT_NS_PER_CALL, + /** Nanoseconds per call. */ + STAMUNIT_NS_PER_OCCURENCE, + /** Percentage. */ + STAMUNIT_PCT, + /** Hertz. */ + STAMUNIT_HZ, + /** The end (exclusive). */ + STAMUNIT_END +} STAMUNIT; + +/** @name STAM_REFRESH_GRP_XXX - STAM refresh groups + * @{ */ +#define STAM_REFRESH_GRP_NONE UINT8_MAX +#define STAM_REFRESH_GRP_GVMM 0 +#define STAM_REFRESH_GRP_GMM 1 +#define STAM_REFRESH_GRP_NEM 2 +/** @} */ + + +/** @def STAM_REL_U8_INC + * Increments a uint8_t sample by one. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U8_INC(pCounter) \ + do { ++*(pCounter); } while (0) +#else +# define STAM_REL_U8_INC(pCounter) do { } while (0) +#endif +/** @def STAM_U8_INC + * Increments a uint8_t sample by one. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U8_INC(pCounter) STAM_REL_U8_INC(pCounter) +#else +# define STAM_U8_INC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U8_DEC + * Decrements a uint8_t sample by one. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U8_DEC(pCounter) \ + do { --*(pCounter); } while (0) +#else +# define STAM_REL_U8_DEC(pCounter) do { } while (0) +#endif +/** @def STAM_U8_DEC + * Decrements a uint8_t sample by one. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U8_DEC(pCounter) STAM_REL_U8_DEC(pCounter) +#else +# define STAM_U8_DEC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U8_ADD + * Increments a uint8_t sample by a value. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + * @param Addend The value to add. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U8_ADD(pCounter, Addend) \ + do { *(pCounter) += (Addend); } while (0) +#else +# define STAM_REL_U8_ADD(pCounter, Addend) do { } while (0) +#endif +/** @def STAM_U8_ADD + * Increments a uint8_t sample by a value. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + * @param Addend The value to add. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U8_ADD(pCounter, Addend) STAM_REL_U8_ADD(pCounter, Addend +#else +# define STAM_U8_ADD(pCounter, Addend) do { } while (0) +#endif + + +/** @def STAM_REL_U16_INC + * Increments a uint16_t sample by one. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U16_INC(pCounter) \ + do { ++*(pCounter); } while (0) +#else +# define STAM_REL_U16_INC(pCounter) do { } while (0) +#endif +/** @def STAM_U16_INC + * Increments a uint16_t sample by one. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U16_INC(pCounter) STAM_REL_U16_INC(pCounter) +#else +# define STAM_U16_INC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U16_DEC + * Decrements a uint16_t sample by one. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U16_DEC(pCounter) \ + do { --*(pCounter); } while (0) +#else +# define STAM_REL_U16_DEC(pCounter) do { } while (0) +#endif +/** @def STAM_U16_DEC + * Decrements a uint16_t sample by one. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U16_DEC(pCounter) STAM_REL_U16_DEC(pCounter) +#else +# define STAM_U16_DEC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U16_ADD + * Increments a uint16_t sample by a value. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + * @param Addend The value to add. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U16_ADD(pCounter, Addend) \ + do { *(pCounter) += (Addend); } while (0) +#else +# define STAM_REL_U16_ADD(pCounter, Addend) do { } while (0) +#endif +/** @def STAM_U16_ADD + * Increments a uint16_t sample by a value. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + * @param Addend The value to add. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U16_ADD(pCounter, Addend) STAM_REL_U16_ADD(pCounter, Addend) +#else +# define STAM_U16_ADD(pCounter, Addend) do { } while (0) +#endif + + +/** @def STAM_REL_U32_INC + * Increments a uint32_t sample by one. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U32_INC(pCounter) \ + do { ++*(pCounter); } while (0) +#else +# define STAM_REL_U32_INC(pCounter) do { } while (0) +#endif +/** @def STAM_U32_INC + * Increments a uint32_t sample by one. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U32_INC(pCounter) STAM_REL_U32_INC(pCounter) +#else +# define STAM_U32_INC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U32_DEC + * Decrements a uint32_t sample by one. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U32_DEC(pCounter) \ + do { --*(pCounter); } while (0) +#else +# define STAM_REL_U32_DEC(pCounter) do { } while (0) +#endif +/** @def STAM_U32_DEC + * Decrements a uint32_t sample by one. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U32_DEC(pCounter) STAM_REL_U32_DEC(pCounter) +#else +# define STAM_U32_DEC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U32_ADD + * Increments a uint32_t sample by value. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + * @param Addend The value to add. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U32_ADD(pCounter, Addend) \ + do { *(pCounter) += (Addend); } while (0) +#else +# define STAM_REL_U32_ADD(pCounter, Addend) do { } while (0) +#endif +/** @def STAM_U32_ADD + * Increments a uint32_t sample by value. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + * @param Addend The value to add. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U32_ADD(pCounter, Addend) STAM_REL_U32_ADD(pCounter, Addend) +#else +# define STAM_U32_ADD(pCounter, Addend) do { } while (0) +#endif + + +/** @def STAM_REL_U64_INC + * Increments a uint64_t sample by one. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U64_INC(pCounter) \ + do { ++*(pCounter); } while (0) +#else +# define STAM_REL_U64_INC(pCounter) do { } while (0) +#endif +/** @def STAM_U64_INC + * Increments a uint64_t sample by one. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U64_INC(pCounter) STAM_REL_U64_INC(pCounter) +#else +# define STAM_U64_INC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U64_DEC + * Decrements a uint64_t sample by one. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U64_DEC(pCounter) \ + do { --*(pCounter); } while (0) +#else +# define STAM_REL_U64_DEC(pCounter) do { } while (0) +#endif +/** @def STAM_U64_DEC + * Decrements a uint64_t sample by one. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U64_DEC(pCounter) STAM_REL_U64_DEC(pCounter) +#else +# define STAM_U64_DEC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U64_ADD + * Increments a uint64_t sample by a value. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + * @param Addend The value to add. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U64_ADD(pCounter, Addend) \ + do { *(pCounter) += (Addend); } while (0) +#else +# define STAM_REL_U64_ADD(pCounter, Addend) do { } while (0) +#endif +/** @def STAM_U64_ADD + * Increments a uint64_t sample by a value. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + * @param Addend The value to add. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U64_ADD(pCounter, Addend) STAM_REL_U64_ADD(pCounter, Addend) +#else +# define STAM_U64_ADD(pCounter, Addend) do { } while (0) +#endif + + +/** + * Counter sample - STAMTYPE_COUNTER. + */ +typedef struct STAMCOUNTER +{ + /** The current count. */ + volatile uint64_t c; +} STAMCOUNTER; +/** Pointer to a counter. */ +typedef STAMCOUNTER *PSTAMCOUNTER; +/** Pointer to a const counter. */ +typedef const STAMCOUNTER *PCSTAMCOUNTER; + + +/** @def STAM_REL_COUNTER_INC + * Increments a counter sample by one. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_COUNTER_INC(pCounter) \ + do { (pCounter)->c++; } while (0) +#else +# define STAM_REL_COUNTER_INC(pCounter) do { } while (0) +#endif +/** @def STAM_COUNTER_INC + * Increments a counter sample by one. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_COUNTER_INC(pCounter) STAM_REL_COUNTER_INC(pCounter) +#else +# define STAM_COUNTER_INC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_COUNTER_DEC + * Decrements a counter sample by one. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_COUNTER_DEC(pCounter) \ + do { (pCounter)->c--; } while (0) +#else +# define STAM_REL_COUNTER_DEC(pCounter) do { } while (0) +#endif +/** @def STAM_COUNTER_DEC + * Decrements a counter sample by one. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_COUNTER_DEC(pCounter) STAM_REL_COUNTER_DEC(pCounter) +#else +# define STAM_COUNTER_DEC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_COUNTER_ADD + * Increments a counter sample by a value. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + * @param Addend The value to add to the counter. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_COUNTER_ADD(pCounter, Addend) \ + do { (pCounter)->c += (Addend); } while (0) +#else +# define STAM_REL_COUNTER_ADD(pCounter, Addend) do { } while (0) +#endif +/** @def STAM_COUNTER_ADD + * Increments a counter sample by a value. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + * @param Addend The value to add to the counter. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_COUNTER_ADD(pCounter, Addend) STAM_REL_COUNTER_ADD(pCounter, Addend) +#else +# define STAM_COUNTER_ADD(pCounter, Addend) do { } while (0) +#endif + + +/** @def STAM_REL_COUNTER_RESET + * Resets the statistics sample. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_COUNTER_RESET(pCounter) do { (pCounter)->c = 0; } while (0) +#else +# define STAM_REL_COUNTER_RESET(pCounter) do { } while (0) +#endif +/** @def STAM_COUNTER_RESET + * Resets the statistics sample. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_COUNTER_RESET(pCounter) STAM_REL_COUNTER_RESET(pCounter) +#else +# define STAM_COUNTER_RESET(pCounter) do { } while (0) +#endif + + + +/** + * Profiling sample - STAMTYPE_PROFILE. + */ +typedef struct STAMPROFILE +{ + /** Number of periods. */ + volatile uint64_t cPeriods; + /** Total count of ticks. */ + volatile uint64_t cTicks; + /** Maximum tick count during a sampling. */ + volatile uint64_t cTicksMax; + /** Minimum tick count during a sampling. */ + volatile uint64_t cTicksMin; +} STAMPROFILE; +/** Pointer to a profile sample. */ +typedef STAMPROFILE *PSTAMPROFILE; +/** Pointer to a const profile sample. */ +typedef const STAMPROFILE *PCSTAMPROFILE; + + +/** @def STAM_REL_PROFILE_ADD_PERIOD + * Adds a period. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param cTicksInPeriod The number of tick (or whatever) of the preiod + * being added. This is only referenced once. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) \ + do { \ + uint64_t const StamPrefix_cTicks = (cTicksInPeriod); \ + (pProfile)->cTicks += StamPrefix_cTicks; \ + (pProfile)->cPeriods++; \ + if ((pProfile)->cTicksMax < StamPrefix_cTicks) \ + (pProfile)->cTicksMax = StamPrefix_cTicks; \ + if ((pProfile)->cTicksMin > StamPrefix_cTicks) \ + (pProfile)->cTicksMin = StamPrefix_cTicks; \ + } while (0) +#else +# define STAM_REL_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) do { } while (0) +#endif +/** @def STAM_PROFILE_ADD_PERIOD + * Adds a period. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param cTicksInPeriod The number of tick (or whatever) of the preiod + * being added. This is only referenced once. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) STAM_REL_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) +#else +# define STAM_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_START + * Samples the start time of a profiling period. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + * + * @remarks Declears a stack variable that will be used by related macros. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_START(pProfile, Prefix) \ + uint64_t Prefix##_tsStart; \ + STAM_GET_TS(Prefix##_tsStart) +#else +# define STAM_REL_PROFILE_START(pProfile, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_START + * Samples the start time of a profiling period. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + * + * @remarks Declears a stack variable that will be used by related macros. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_START(pProfile, Prefix) STAM_REL_PROFILE_START(pProfile, Prefix) +#else +# define STAM_PROFILE_START(pProfile, Prefix) do { } while (0) +#endif + +/** @def STAM_REL_PROFILE_STOP + * Samples the stop time of a profiling period and updates the sample. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_STOP(pProfile, Prefix) \ + do { \ + uint64_t Prefix##_cTicks; \ + STAM_GET_TS(Prefix##_cTicks); \ + Prefix##_cTicks -= Prefix##_tsStart; \ + (pProfile)->cTicks += Prefix##_cTicks; \ + (pProfile)->cPeriods++; \ + if ((pProfile)->cTicksMax < Prefix##_cTicks) \ + (pProfile)->cTicksMax = Prefix##_cTicks; \ + if ((pProfile)->cTicksMin > Prefix##_cTicks) \ + (pProfile)->cTicksMin = Prefix##_cTicks; \ + } while (0) +#else +# define STAM_REL_PROFILE_STOP(pProfile, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_STOP + * Samples the stop time of a profiling period and updates the sample. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_STOP(pProfile, Prefix) STAM_REL_PROFILE_STOP(pProfile, Prefix) +#else +# define STAM_PROFILE_STOP(pProfile, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_STOP_EX + * Samples the stop time of a profiling period and updates both the sample + * and an attribution sample. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param pProfile2 Pointer to the STAMPROFILE structure which this + * interval should be attributed to as well. This may be NULL. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) \ + do { \ + uint64_t Prefix##_cTicks; \ + STAM_GET_TS(Prefix##_cTicks); \ + Prefix##_cTicks -= Prefix##_tsStart; \ + (pProfile)->cTicks += Prefix##_cTicks; \ + (pProfile)->cPeriods++; \ + if ((pProfile)->cTicksMax < Prefix##_cTicks) \ + (pProfile)->cTicksMax = Prefix##_cTicks; \ + if ((pProfile)->cTicksMin > Prefix##_cTicks) \ + (pProfile)->cTicksMin = Prefix##_cTicks; \ + \ + if ((pProfile2)) \ + { \ + (pProfile2)->cTicks += Prefix##_cTicks; \ + (pProfile2)->cPeriods++; \ + if ((pProfile2)->cTicksMax < Prefix##_cTicks) \ + (pProfile2)->cTicksMax = Prefix##_cTicks; \ + if ((pProfile2)->cTicksMin > Prefix##_cTicks) \ + (pProfile2)->cTicksMin = Prefix##_cTicks; \ + } \ + } while (0) +#else +# define STAM_REL_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_STOP_EX + * Samples the stop time of a profiling period and updates both the sample + * and an attribution sample. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param pProfile2 Pointer to the STAMPROFILE structure which this + * interval should be attributed to as well. This may be NULL. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) STAM_REL_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) +#else +# define STAM_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_STOP_START + * Stops one profile counter (if running) and starts another one. + * + * @param pProfile1 Pointer to the STAMPROFILE structure to stop. + * @param pProfile2 Pointer to the STAMPROFILE structure to start. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) \ + do { \ + uint64_t Prefix##_tsStop; \ + STAM_GET_TS(Prefix##_tsStop); \ + STAM_REL_PROFILE_ADD_PERIOD(pProfile1, Prefix##_tsStop - Prefix##_tsStart); \ + Prefix##_tsStart = Prefix##_tsStop; \ + } while (0) +#else +# define STAM_REL_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) \ + do { } while (0) +#endif +/** @def STAM_PROFILE_STOP_START + * Samples the stop time of a profiling period (if running) and updates the + * sample. + * + * @param pProfile1 Pointer to the STAMPROFILE structure to stop. + * @param pProfile2 Pointer to the STAMPROFILE structure to start. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) \ + STAM_REL_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) +#else +# define STAM_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) \ + do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_START_NS + * Samples the start time of a profiling period, using RTTimeNanoTS(). + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + * + * @remarks Declears a stack variable that will be used by related macros. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_START_NS(pProfile, Prefix) \ + uint64_t const Prefix##_tsStart = RTTimeNanoTS() +#else +# define STAM_REL_PROFILE_START_NS(pProfile, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_START_NS + * Samples the start time of a profiling period, using RTTimeNanoTS(). + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + * + * @remarks Declears a stack variable that will be used by related macros. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_START_NS(pProfile, Prefix) STAM_REL_PROFILE_START_NS(pProfile, Prefix) +#else +# define STAM_PROFILE_START_NS(pProfile, Prefix) do { } while (0) +#endif + +/** @def STAM_REL_PROFILE_STOP_NS + * Samples the stop time of a profiling period and updates the sample, using + * RTTimeNanoTS(). + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_STOP_NS(pProfile, Prefix) \ + STAM_REL_PROFILE_ADD_PERIOD(pProfile, RTTimeNanoTS() - Prefix##_tsStart) +#else +# define STAM_REL_PROFILE_STOP_NS(pProfile, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_STOP_NS + * Samples the stop time of a profiling period and updates the sample, using + * RTTimeNanoTS(). + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_STOP_NS(pProfile, Prefix) STAM_REL_PROFILE_STOP_NS(pProfile, Prefix) +#else +# define STAM_PROFILE_STOP_NS(pProfile, Prefix) do { } while (0) +#endif + + +/** + * Advanced profiling sample - STAMTYPE_PROFILE_ADV. + * + * Identical to a STAMPROFILE sample, but the start timestamp + * is stored after the STAMPROFILE structure so the sampling + * can start and stop in different functions. + */ +typedef struct STAMPROFILEADV +{ + /** The STAMPROFILE core. */ + STAMPROFILE Core; + /** The start timestamp. */ + volatile uint64_t tsStart; +} STAMPROFILEADV; +/** Pointer to a advanced profile sample. */ +typedef STAMPROFILEADV *PSTAMPROFILEADV; +/** Pointer to a const advanced profile sample. */ +typedef const STAMPROFILEADV *PCSTAMPROFILEADV; + + +/** @def STAM_REL_PROFILE_ADV_START + * Samples the start time of a profiling period. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_START(pProfileAdv, Prefix) \ + STAM_GET_TS((pProfileAdv)->tsStart) +#else +# define STAM_REL_PROFILE_ADV_START(pProfileAdv, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_START + * Samples the start time of a profiling period. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_START(pProfileAdv, Prefix) STAM_REL_PROFILE_ADV_START(pProfileAdv, Prefix) +#else +# define STAM_PROFILE_ADV_START(pProfileAdv, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_ADV_STOP + * Samples the stop time of a profiling period (if running) and updates the + * sample. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_STOP(pProfileAdv, Prefix) \ + do { \ + if ((pProfileAdv)->tsStart) \ + { \ + uint64_t Prefix##_cTicks; \ + STAM_GET_TS(Prefix##_cTicks); \ + Prefix##_cTicks -= (pProfileAdv)->tsStart; \ + (pProfileAdv)->tsStart = 0; \ + (pProfileAdv)->Core.cTicks += Prefix##_cTicks; \ + (pProfileAdv)->Core.cPeriods++; \ + if ((pProfileAdv)->Core.cTicksMax < Prefix##_cTicks) \ + (pProfileAdv)->Core.cTicksMax = Prefix##_cTicks; \ + if ((pProfileAdv)->Core.cTicksMin > Prefix##_cTicks) \ + (pProfileAdv)->Core.cTicksMin = Prefix##_cTicks; \ + } \ + } while (0) +#else +# define STAM_REL_PROFILE_ADV_STOP(pProfileAdv, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_STOP + * Samples the stop time of a profiling period (if running) and updates the + * sample. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_STOP(pProfileAdv, Prefix) STAM_REL_PROFILE_ADV_STOP(pProfileAdv, Prefix) +#else +# define STAM_PROFILE_ADV_STOP(pProfileAdv, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_ADV_STOP_START + * Stops one profile counter (if running) and starts another one. + * + * @param pProfileAdv1 Pointer to the STAMPROFILEADV structure to stop. + * @param pProfileAdv2 Pointer to the STAMPROFILEADV structure to start. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) \ + do { \ + uint64_t Prefix##_cTicks; \ + STAM_GET_TS(Prefix##_cTicks); \ + (pProfileAdv2)->tsStart = Prefix##_cTicks; \ + if ((pProfileAdv1)->tsStart) \ + { \ + Prefix##_cTicks -= (pProfileAdv1)->tsStart; \ + (pProfileAdv1)->tsStart = 0; \ + (pProfileAdv1)->Core.cTicks += Prefix##_cTicks; \ + (pProfileAdv1)->Core.cPeriods++; \ + if ((pProfileAdv1)->Core.cTicksMax < Prefix##_cTicks) \ + (pProfileAdv1)->Core.cTicksMax = Prefix##_cTicks; \ + if ((pProfileAdv1)->Core.cTicksMin > Prefix##_cTicks) \ + (pProfileAdv1)->Core.cTicksMin = Prefix##_cTicks; \ + } \ + } while (0) +#else +# define STAM_REL_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) \ + do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_STOP_START + * Samples the stop time of a profiling period (if running) and updates the + * sample. + * + * @param pProfileAdv1 Pointer to the STAMPROFILEADV structure to stop. + * @param pProfileAdv2 Pointer to the STAMPROFILEADV structure to start. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) \ + STAM_REL_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) +#else +# define STAM_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) \ + do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_ADV_SUSPEND + * Suspends the sampling for a while. This can be useful to exclude parts + * covered by other samples without screwing up the count, and average+min times. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. The prefix + * must match that of the resume one since it stores the + * suspend time in a stack variable. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) \ + uint64_t Prefix##_tsSuspend; \ + STAM_GET_TS(Prefix##_tsSuspend) +#else +# define STAM_REL_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_SUSPEND + * Suspends the sampling for a while. This can be useful to exclude parts + * covered by other samples without screwing up the count, and average+min times. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. The prefix + * must match that of the resume one since it stores the + * suspend time in a stack variable. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) STAM_REL_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) +#else +# define STAM_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_ADV_RESUME + * Counter to STAM_REL_PROFILE_ADV_SUSPEND. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. This must + * match the one used with the SUSPEND! + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_RESUME(pProfileAdv, Prefix) \ + do { \ + uint64_t Prefix##_tsNow; \ + STAM_GET_TS(Prefix##_tsNow); \ + (pProfileAdv)->tsStart += Prefix##_tsNow - Prefix##_tsSuspend; \ + } while (0) +#else +# define STAM_REL_PROFILE_ADV_RESUME(pProfileAdv, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_RESUME + * Counter to STAM_PROFILE_ADV_SUSPEND. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. This must + * match the one used with the SUSPEND! + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_RESUME(pProfileAdv, Prefix) STAM_REL_PROFILE_ADV_RESUME(pProfileAdv, Prefix) +#else +# define STAM_PROFILE_ADV_RESUME(pProfileAdv, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_ADV_STOP_EX + * Samples the stop time of a profiling period (if running) and updates both + * the sample and an attribution sample. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param pProfile2 Pointer to the STAMPROFILE structure which this + * interval should be attributed to as well. This may be NULL. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) \ + do { \ + if ((pProfileAdv)->tsStart) \ + { \ + uint64_t Prefix##_cTicks; \ + STAM_GET_TS(Prefix##_cTicks); \ + Prefix##_cTicks -= (pProfileAdv)->tsStart; \ + (pProfileAdv)->tsStart = 0; \ + (pProfileAdv)->Core.cTicks += Prefix##_cTicks; \ + (pProfileAdv)->Core.cPeriods++; \ + if ((pProfileAdv)->Core.cTicksMax < Prefix##_cTicks) \ + (pProfileAdv)->Core.cTicksMax = Prefix##_cTicks; \ + if ((pProfileAdv)->Core.cTicksMin > Prefix##_cTicks) \ + (pProfileAdv)->Core.cTicksMin = Prefix##_cTicks; \ + if ((pProfile2)) \ + { \ + (pProfile2)->cTicks += Prefix##_cTicks; \ + (pProfile2)->cPeriods++; \ + if ((pProfile2)->cTicksMax < Prefix##_cTicks) \ + (pProfile2)->cTicksMax = Prefix##_cTicks; \ + if ((pProfile2)->cTicksMin > Prefix##_cTicks) \ + (pProfile2)->cTicksMin = Prefix##_cTicks; \ + } \ + } \ + } while (0) +#else +# define STAM_REL_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_STOP_EX + * Samples the stop time of a profiling period (if running) and updates both + * the sample and an attribution sample. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param pProfile2 Pointer to the STAMPROFILE structure which this + * interval should be attributed to as well. This may be NULL. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) STAM_REL_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) +#else +# define STAM_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) do { } while (0) +#endif + +/** @def STAM_REL_PROFILE_ADV_IS_RUNNING + * Checks if it is running. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_IS_RUNNING(pProfileAdv) (pProfileAdv)->tsStart +#else +# define STAM_REL_PROFILE_ADV_IS_RUNNING(pProfileAdv) (false) +#endif +/** @def STAM_PROFILE_ADV_IS_RUNNING + * Checks if it is running. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_IS_RUNNING(pProfileAdv) STAM_REL_PROFILE_ADV_IS_RUNNING(pProfileAdv) +#else +# define STAM_PROFILE_ADV_IS_RUNNING(pProfileAdv) (false) +#endif + +/** @def STAM_REL_PROFILE_ADV_SET_STOPPED + * Marks the profile counter as stopped. + * + * This is for avoiding screwups in twisty code. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_SET_STOPPED(pProfileAdv) do { (pProfileAdv)->tsStart = 0; } while (0) +#else +# define STAM_REL_PROFILE_ADV_SET_STOPPED(pProfileAdv) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_SET_STOPPED + * Marks the profile counter as stopped. + * + * This is for avoiding screwups in twisty code. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_SET_STOPPED(pProfileAdv) STAM_REL_PROFILE_ADV_SET_STOPPED(pProfileAdv) +#else +# define STAM_PROFILE_ADV_SET_STOPPED(pProfileAdv) do { } while (0) +#endif + + +/** + * Ratio of A to B, uint32_t types. + * @remark Use STAM_STATS or STAM_REL_STATS for modifying A & B values. + */ +typedef struct STAMRATIOU32 +{ + /** Sample A. */ + uint32_t volatile u32A; + /** Sample B. */ + uint32_t volatile u32B; +} STAMRATIOU32; +/** Pointer to a uint32_t ratio. */ +typedef STAMRATIOU32 *PSTAMRATIOU32; +/** Pointer to const a uint32_t ratio. */ +typedef const STAMRATIOU32 *PCSTAMRATIOU32; + + + + +/** @defgroup grp_stam_r3 The STAM Host Context Ring 3 API + * @{ + */ + +VMMR3DECL(int) STAMR3InitUVM(PUVM pUVM); +VMMR3DECL(void) STAMR3TermUVM(PUVM pUVM); +VMMR3DECL(int) STAMR3RegisterU(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + const char *pszName, STAMUNIT enmUnit, const char *pszDesc); +VMMR3DECL(int) STAMR3Register(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + const char *pszName, STAMUNIT enmUnit, const char *pszDesc); + +/** @def STAM_REL_REG + * Registers a statistics sample. + * + * @param pVM The cross context VM structure. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param pszName Sample name. The name is on this form "/<component>/<sample>". + * Further nesting is possible. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ +#define STAM_REL_REG(pVM, pvSample, enmType, pszName, enmUnit, pszDesc) \ + STAM_REL_STATS({ int rcStam = STAMR3Register(pVM, pvSample, enmType, STAMVISIBILITY_ALWAYS, pszName, enmUnit, pszDesc); \ + AssertRC(rcStam); }) +/** @def STAM_REG + * Registers a statistics sample if statistics are enabled. + * + * @param pVM The cross context VM structure. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param pszName Sample name. The name is on this form "/<component>/<sample>". + * Further nesting is possible. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ +#define STAM_REG(pVM, pvSample, enmType, pszName, enmUnit, pszDesc) \ + STAM_STATS({STAM_REL_REG(pVM, pvSample, enmType, pszName, enmUnit, pszDesc);}) + +/** @def STAM_REL_REG_USED + * Registers a statistics sample which only shows when used. + * + * @param pVM The cross context VM structure. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param pszName Sample name. The name is on this form "/<component>/<sample>". + * Further nesting is possible. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ +#define STAM_REL_REG_USED(pVM, pvSample, enmType, pszName, enmUnit, pszDesc) \ + STAM_REL_STATS({ int rcStam = STAMR3Register(pVM, pvSample, enmType, STAMVISIBILITY_USED, pszName, enmUnit, pszDesc); \ + AssertRC(rcStam);}) +/** @def STAM_REG_USED + * Registers a statistics sample which only shows when used, if statistics are enabled. + * + * @param pVM The cross context VM structure. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param pszName Sample name. The name is on this form "/<component>/<sample>". + * Further nesting is possible. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ +#define STAM_REG_USED(pVM, pvSample, enmType, pszName, enmUnit, pszDesc) \ + STAM_STATS({ STAM_REL_REG_USED(pVM, pvSample, enmType, pszName, enmUnit, pszDesc); }) + +VMMR3DECL(int) STAMR3RegisterFU(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, ...) RT_IPRT_FORMAT_ATTR(7, 8); +VMMR3DECL(int) STAMR3RegisterF(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, ...) RT_IPRT_FORMAT_ATTR(7, 8); +VMMR3DECL(int) STAMR3RegisterVU(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(7, 0); +VMMR3DECL(int) STAMR3RegisterV(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(7, 0); + +/** + * Resets the sample. + * @param pVM The cross context VM structure. + * @param pvSample The sample registered using STAMR3RegisterCallback. + */ +typedef DECLCALLBACKTYPE(void, FNSTAMR3CALLBACKRESET,(PVM pVM, void *pvSample)); +/** Pointer to a STAM sample reset callback. */ +typedef FNSTAMR3CALLBACKRESET *PFNSTAMR3CALLBACKRESET; + +/** + * Prints the sample into the buffer. + * + * @param pVM The cross context VM structure. + * @param pvSample The sample registered using STAMR3RegisterCallback. + * @param pszBuf The buffer to print into. + * @param cchBuf The size of the buffer. + */ +typedef DECLCALLBACKTYPE(void, FNSTAMR3CALLBACKPRINT,(PVM pVM, void *pvSample, char *pszBuf, size_t cchBuf)); +/** Pointer to a STAM sample print callback. */ +typedef FNSTAMR3CALLBACKPRINT *PFNSTAMR3CALLBACKPRINT; + +VMMR3DECL(int) STAMR3RegisterCallback(PVM pVM, void *pvSample, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint, + const char *pszDesc, const char *pszName, ...) RT_IPRT_FORMAT_ATTR(8, 9); +VMMR3DECL(int) STAMR3RegisterCallbackV(PVM pVM, void *pvSample, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint, + const char *pszDesc, const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(8, 0); + +VMMR3DECL(int) STAMR3RegisterRefresh(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, uint8_t iRefreshGrp, const char *pszDesc, + const char *pszName, ...) RT_IPRT_FORMAT_ATTR(8, 9); +VMMR3DECL(int) STAMR3RegisterRefreshV(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, uint8_t iRefreshGrp, const char *pszDesc, + const char *pszName, va_list va) RT_IPRT_FORMAT_ATTR(8, 0); + +VMMR3DECL(int) STAMR3Deregister(PUVM pUVM, const char *pszPat); +VMMR3DECL(int) STAMR3DeregisterF(PUVM pUVM, const char *pszPatFmt, ...) RT_IPRT_FORMAT_ATTR(2, 3); +VMMR3DECL(int) STAMR3DeregisterV(PUVM pUVM, const char *pszPatFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); +VMMR3DECL(int) STAMR3DeregisterByPrefix(PUVM pUVM, const char *pszPrefix); +VMMR3DECL(int) STAMR3DeregisterByAddr(PUVM pUVM, void *pvSample); + +VMMR3DECL(int) STAMR3Reset(PUVM pUVM, const char *pszPat); +VMMR3DECL(int) STAMR3Snapshot(PUVM pUVM, const char *pszPat, char **ppszSnapshot, size_t *pcchSnapshot, bool fWithDesc); +VMMR3DECL(int) STAMR3SnapshotFree(PUVM pUVM, char *pszSnapshot); +VMMR3DECL(int) STAMR3Dump(PUVM pUVM, const char *pszPat); +VMMR3DECL(int) STAMR3DumpToReleaseLog(PUVM pUVM, const char *pszPat); +VMMR3DECL(int) STAMR3Print(PUVM pUVM, const char *pszPat); + +/** + * Callback function for STAMR3Enum(). + * + * @returns non-zero to halt the enumeration. + * + * @param pszName The name of the sample. + * @param enmType The type. + * @param pvSample Pointer to the data. enmType indicates the format of this data. + * @param enmUnit The unit. + * @param pszUnit The unit as string. This is a permanent string, + * same as returned by STAMR3GetUnit(). + * @param enmVisibility The visibility. + * @param pszDesc The description. + * @param pvUser The pvUser argument given to STAMR3Enum(). + */ +typedef DECLCALLBACKTYPE(int, FNSTAMR3ENUM,(const char *pszName, STAMTYPE enmType, void *pvSample, STAMUNIT enmUnit, + const char *pszUnit, STAMVISIBILITY enmVisibility, const char *pszDesc, void *pvUser)); +/** Pointer to a FNSTAMR3ENUM(). */ +typedef FNSTAMR3ENUM *PFNSTAMR3ENUM; + +VMMR3DECL(int) STAMR3Enum(PUVM pUVM, const char *pszPat, PFNSTAMR3ENUM pfnEnum, void *pvUser); +VMMR3DECL(const char *) STAMR3GetUnit(STAMUNIT enmUnit); +VMMR3DECL(const char *) STAMR3GetUnit1(STAMUNIT enmUnit); +VMMR3DECL(const char *) STAMR3GetUnit2(STAMUNIT enmUnit); + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_stam_h */ + diff --git a/include/VBox/vmm/stam.mac b/include/VBox/vmm/stam.mac new file mode 100644 index 00000000..b70a881a --- /dev/null +++ b/include/VBox/vmm/stam.mac @@ -0,0 +1,392 @@ +;; @file +; STAM - Statistics Manager. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_vmm_stam_mac__ +%define ___VBox_vmm_stam_mac__ + + +%ifndef VBOX_WITH_STATISTICS + %ifdef DEBUG + %define VBOX_WITH_STATISTICS + %endif +%endif + + + +;; +; Counter sample - STAMTYPE_COUNTER. +struc STAMCOUNTER + .c resd 2 +endstruc + +;; +; Increments a counter sample by one. +; @param %1 Pointer to the STAMCOUNTER structure to operate on. +%macro STAM32_COUNTER_INC 1 +%ifdef VBOX_WITH_STATISTICS + push ebx + mov ebx, %1 + inc dword [ebx + STAMCOUNTER.c] + adc dword [ebx + STAMCOUNTER.c + 1], byte 0 + pop ebx +%endif +%endmacro + +%macro STAM64_COUNTER_INC 1 +%ifdef VBOX_WITH_STATISTICS + push rbx + mov rbx, %1 + inc qword [rbx + STAMCOUNTER.c] + pop rbx +%endif +%endmacro + +%macro STAM_COUNTER_INC 1 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_COUNTER_INC %1 + %else + STAM32_COUNTER_INC %1 + %endif +%endif +%endmacro + + +;; +; Increments a counter sample by a value. +; +; @param %1 Pointer to the STAMCOUNTER structure to operate on. +; @param %2 The value to add to the counter. +%macro STAM32_COUNTER_ADD 2 +%ifdef VBOX_WITH_STATISTICS + push ebx + mov ebx, %1 + push eax + mov eax, %2 + + add [ebx + STAMCOUNTER.c], eax + adc dword [ebx + STAMCOUNTER.c], byte 0 + + pop eax + pop ebx +%endif +%endmacro + +%macro STAM64_COUNTER_ADD 2 +%ifdef VBOX_WITH_STATISTICS + push rbx + mov rbx, %1 + push rax + mov rax, %2 + + add [rbx + STAMCOUNTER.c], rax + + pop rax + pop rbx +%endif +%endmacro + +%macro STAM_COUNTER_ADD 2 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_COUNTER_ADD %1, %2 + %else + STAM32_COUNTER_ADD %1, %2 + %endif +%endif +%endmacro + + +;; +; Profiling sample - STAMTYPE_PROFILE. +struc STAMPROFILE + .cPeriods resd 2 + .cTicks resd 2 + .cTicksMax resd 2 + .cTicksMin resd 2 +endstruc + + +;; +; Samples the start time of a profiling period. +; +; @param %1 Pointer to somewhere one can store a 64-bit timestamp until STAM_PROFILE_STOPP +%macro STAM32_PROFILE_START 1 +%ifdef VBOX_WITH_STATISTICS + push ebx + mov ebx, %1 + push eax + push edx + + rdtsc + mov [ebx], eax + mov [ebx + 4], edx + + pop edx + pop eax + pop ebx +%endif +%endmacro + +%macro STAM64_PROFILE_START 1 +%ifdef VBOX_WITH_STATISTICS + push rbx + mov rbx, %1 + push rax + push rdx + + rdtsc + mov [rbx], eax + mov [rbx + 4], edx + + pop rdx + pop rax + pop rbx +%endif +%endmacro + +%macro STAM_PROFILE_START 1 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_PROFILE_START %1 + %else + STAM32_PROFILE_START %1 + %endif +%endif +%endmacro + + +;; +; Samples the stop time of a profiling period and updates the sample. +; +; @param %1 Pointer to the STAMPROFILE structure to operate on. +; @param %2 Pointer to where the 64-bit timestamp from STAM_PROFILE_START was stored. +%macro STAM32_PROFILE_STOP 2 +%ifdef VBOX_WITH_STATISTICS + push ebx + mov ebx, %1 + push eax + push edx + + ; calc cTicks + push ecx + mov ecx, %2 + rdtsc + sub eax, [ecx] + sbb edx, [ecx + 4] + pop ecx + + ; update STAMPROFILE.cTicks + add [ebx + STAMPROFILE.cTicks], eax + adc [ebx + STAMPROFILE.cTicks + 4], edx + ; update STAMPROFILE.cPeriods + inc dword [ebx + STAMPROFILE.cPeriods] + adc dword [ebx + STAMPROFILE.cPeriods + 4], byte 0 + + ; update max? + cmp edx, [ebx + STAMPROFILE.cTicksMax + 4] + jb short %%not_update_max + ja short %%update_max + cmp eax, [ebx + STAMPROFILE.cTicksMax] + jbe short %%not_update_max +%%update_max: + mov [ebx + STAMPROFILE.cTicksMax], eax + mov [ebx + STAMPROFILE.cTicksMax + 4], edx +%%not_update_max: + + ; update min? + cmp edx, [ebx + STAMPROFILE.cTicksMin + 4] + ja short %%not_update_min + jb short %%update_min + cmp eax, [ebx + STAMPROFILE.cTicksMin] + jae short %%not_update_min +%%update_min: + mov [ebx + STAMPROFILE.cTicksMin], eax + mov [ebx + STAMPROFILE.cTicksMin + 4], edx +%%not_update_min: + + pop edx + pop eax + pop ebx +%endif +%endmacro + +%macro STAM64_PROFILE_STOP 2 +%ifdef VBOX_WITH_STATISTICS + push rbx + mov rbx, %1 + push rax + push rdx + + ; calc cTicks + push rcx + mov rcx, %2 + rdtsc + sub rax, [ecx] + sbb rdx, [ecx + 4] + pop rcx + + ; update STAMPROFILE.cTicks + shl rdx, 32 + or rdx, rax + add [rbx + STAMPROFILE.cTicks], rdx + ; update STAMPROFILE.cPeriods + inc qword [rbx + STAMPROFILE.cPeriods] + + ; update max? + cmp rdx, [rbx + STAMPROFILE.cTicksMax] + jbe short %%not_update_max + mov [rbx + STAMPROFILE.cTicksMax], rdx +%%not_update_max: + + ; update min? + cmp rdx, [rbx + STAMPROFILE.cTicksMin] + jae short %%not_update_min + mov [rbx + STAMPROFILE.cTicksMin], rax +%%not_update_min: + + pop rdx + pop rax + pop rbx +%endif +%endmacro + +%macro STAM_PROFILE_STOP 2 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_PROFILE_STOP %1, %2 + %else + STAM32_PROFILE_STOP %1, %2 + %endif +%endif +%endmacro + + + +struc STAMPROFILEADV + .cPeriods resd 2 + .cTicks resd 2 + .cTicksMax resd 2 + .cTicksMin resd 2 + .tsStart resd 2 +endstruc + + +;; +; Samples the start time of a profiling period. +; +; @param %1 Pointer to the STAMPROFILEADV structure to operate on. +%macro STAM32_PROFILE_ADV_START 1 +%ifdef VBOX_WITH_STATISTICS + push ecx + mov ecx, %1 + lea ecx, [ecx + STAMPROFILEADV.tsStart] + STAM32_PROFILE_START ecx + pop ecx +%endif +%endmacro + +%macro STAM64_PROFILE_ADV_START 1 +%ifdef VBOX_WITH_STATISTICS + push rcx + mov rcx, %1 + lea rcx, [rcx + STAMPROFILEADV.tsStart] + STAM64_PROFILE_START rcx + pop rcx +%endif +%endmacro + +%macro STAM_PROFILE_ADV_START 1 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_PROFILE_ADV_START %1 + %else + STAM32_PROFILE_ADV_START %1 + %endif +%endif +%endmacro + + +;; +; Samples the stop time of a profiling period and updates the sample. +; +; @param %1 Pointer to the STAMPROFILEADV structure to operate on. + +%macro STAM32_PROFILE_ADV_STOP 1 +%ifdef VBOX_WITH_STATISTICS + push ecx + mov ecx, %1 + lea ecx, [ecx + STAMPROFILEADV.tsStart] + cmp dword [ecx], byte 0 + jnz short %%doit + cmp dword [ecx + 4], byte 0 + jz short %%dont +%%doit: + STAM32_PROFILE_STOP %1, ecx +%%dont: + mov dword [ecx], 0 + mov dword [ecx + 4], 0 + pop ecx +%endif +%endmacro + +%macro STAM64_PROFILE_ADV_STOP 1 +%ifdef VBOX_WITH_STATISTICS + push rcx + mov rcx, %1 + lea rcx, [rcx + STAMPROFILEADV.tsStart] + cmp qword [rcx], byte 0 + jz short %%dont +%%doit: + STAM64_PROFILE_STOP %1, rcx +%%dont: + mov qword [rcx], 0 + pop rcx +%endif +%endmacro + +%macro STAM_PROFILE_ADV_STOP 1 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_PROFILE_ADV_STOP %1 + %else + STAM32_PROFILE_ADV_STOP %1 + %endif +%endif +%endmacro + + + +%endif diff --git a/include/VBox/vmm/tm.h b/include/VBox/vmm/tm.h new file mode 100644 index 00000000..2bd62d3a --- /dev/null +++ b/include/VBox/vmm/tm.h @@ -0,0 +1,322 @@ +/** @file + * TM - Time Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_tm_h +#define VBOX_INCLUDED_vmm_tm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#ifdef IN_RING3 +# include <iprt/time.h> +#endif + +RT_C_DECLS_BEGIN + +/** @defgroup grp_tm The Time Manager API + * @ingroup grp_vmm + * @{ + */ + +/** Enable a timer hack which improves the timer response/resolution a bit. */ +#define VBOX_HIGH_RES_TIMERS_HACK + + +/** + * Clock type. + */ +typedef enum TMCLOCK +{ + /** Real host time. + * This clock ticks all the time, so use with care. */ + TMCLOCK_REAL = 0, + /** Virtual guest time. + * This clock only ticks when the guest is running. It's implemented + * as an offset to monotonic real time (GIP). */ + TMCLOCK_VIRTUAL, + /** Virtual guest synchronized timer time. + * This is a special clock and timer queue for synchronizing virtual timers + * and virtual time sources. This clock is trying to keep up with + * TMCLOCK_VIRTUAL, but will wait for timers to be executed. If it lags + * too far behind TMCLOCK_VIRTUAL, it will try speed up to close the + * distance. + * @remarks Do not use this unless you really *must*. */ + TMCLOCK_VIRTUAL_SYNC, + /** Virtual CPU timestamp. + * By default this is a function of TMCLOCK_VIRTUAL_SYNC and the virtual + * CPU frequency. */ + TMCLOCK_TSC, + /** Number of clocks. */ + TMCLOCK_MAX +} TMCLOCK; + + +/** @defgroup grp_tm_timer_flags Timer flags. + * @{ */ +/** Use the default critical section for the class of timers. */ +#define TMTIMER_FLAGS_DEFAULT_CRIT_SECT 0 +/** No critical section needed or a custom one is set using + * TMR3TimerSetCritSect(). */ +#define TMTIMER_FLAGS_NO_CRIT_SECT RT_BIT_32(0) +/** Used in ring-0. Must set this or TMTIMER_FLAGS_NO_RING0. */ +#define TMTIMER_FLAGS_RING0 RT_BIT_32(1) +/** Not used in ring-0 (for refactoring and doc purposes). */ +#define TMTIMER_FLAGS_NO_RING0 RT_BIT_32(31) +/** @} */ + + +VMMDECL(void) TMNotifyStartOfExecution(PVMCC pVM, PVMCPUCC pVCpu); +VMMDECL(void) TMNotifyEndOfExecution(PVMCC pVM, PVMCPUCC pVCpu, uint64_t uTsc); +VMM_INT_DECL(void) TMNotifyStartOfHalt(PVMCPUCC pVCpu); +VMM_INT_DECL(void) TMNotifyEndOfHalt(PVMCPUCC pVCpu); +#ifdef IN_RING3 +VMMR3DECL(int) TMR3NotifySuspend(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) TMR3NotifyResume(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) TMR3SetWarpDrive(PUVM pUVM, uint32_t u32Percent); +VMMR3DECL(uint32_t) TMR3GetWarpDrive(PUVM pUVM); +#endif +VMM_INT_DECL(uint32_t) TMCalcHostTimerFrequency(PVMCC pVM, PVMCPUCC pVCpu); +#ifdef IN_RING3 +VMMR3DECL(int) TMR3GetCpuLoadTimes(PVM pVM, VMCPUID idCpu, uint64_t *pcNsTotal, uint64_t *pcNsExecuting, + uint64_t *pcNsHalted, uint64_t *pcNsOther); +VMMR3DECL(int) TMR3GetCpuLoadPercents(PUVM pVUM, VMCPUID idCpu, uint64_t *pcMsInterval, uint8_t *pcPctExecuting, + uint8_t *pcPctHalted, uint8_t *pcPctOther); +#endif + + +/** @name Real Clock Methods + * @{ + */ +VMM_INT_DECL(uint64_t) TMRealGet(PVM pVM); +VMM_INT_DECL(uint64_t) TMRealGetFreq(PVM pVM); +/** @} */ + + +/** @name Virtual Clock Methods + * @{ + */ +VMM_INT_DECL(uint64_t) TMVirtualGet(PVMCC pVM); +VMM_INT_DECL(uint64_t) TMVirtualGetNoCheck(PVMCC pVM); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetLag(PVMCC pVM); +VMM_INT_DECL(uint32_t) TMVirtualSyncGetCatchUpPct(PVMCC pVM); +VMM_INT_DECL(uint64_t) TMVirtualGetFreq(PVM pVM); +VMM_INT_DECL(uint64_t) TMVirtualSyncGet(PVMCC pVM); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetNoCheck(PVMCC pVM); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetNoCheckWithTsc(PVMCC pVM, uint64_t *puTscNow); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetEx(PVMCC pVM, bool fCheckTimers); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetWithDeadlineNoCheck(PVMCC pVM, uint64_t *pcNsToDeadline, + uint64_t *puDeadlineVersion, uint64_t *puTscNow); +VMMDECL(uint64_t) TMVirtualSyncGetNsToDeadline(PVMCC pVM, uint64_t *puDeadlineVersion, uint64_t *puTscNow); +VMM_INT_DECL(bool) TMVirtualSyncIsCurrentDeadlineVersion(PVMCC pVM, uint64_t uDeadlineVersion); +VMM_INT_DECL(uint64_t) TMVirtualToNano(PVM pVM, uint64_t u64VirtualTicks); +VMM_INT_DECL(uint64_t) TMVirtualToMicro(PVM pVM, uint64_t u64VirtualTicks); +VMM_INT_DECL(uint64_t) TMVirtualToMilli(PVM pVM, uint64_t u64VirtualTicks); +VMM_INT_DECL(uint64_t) TMVirtualFromNano(PVM pVM, uint64_t u64NanoTS); +VMM_INT_DECL(uint64_t) TMVirtualFromMicro(PVM pVM, uint64_t u64MicroTS); +VMM_INT_DECL(uint64_t) TMVirtualFromMilli(PVM pVM, uint64_t u64MilliTS); +VMM_INT_DECL(bool) TMVirtualIsTicking(PVM pVM); + +VMMR3DECL(uint64_t) TMR3TimeVirtGet(PUVM pUVM); +VMMR3DECL(uint64_t) TMR3TimeVirtGetMilli(PUVM pUVM); +VMMR3DECL(uint64_t) TMR3TimeVirtGetMicro(PUVM pUVM); +VMMR3DECL(uint64_t) TMR3TimeVirtGetNano(PUVM pUVM); +/** @} */ + + +/** @name CPU Clock Methods + * @{ + */ +VMMDECL(uint64_t) TMCpuTickGet(PVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) TMCpuTickGetNoCheck(PVMCPUCC pVCpu); +VMM_INT_DECL(bool) TMCpuTickCanUseRealTSC(PVMCC pVM, PVMCPUCC pVCpu, uint64_t *poffRealTSC, bool *pfParavirtTsc); +VMM_INT_DECL(uint64_t) TMCpuTickGetDeadlineAndTscOffset(PVMCC pVM, PVMCPUCC pVCpu, uint64_t *poffRealTsc, + bool *pfOffsettedTsc, bool *pfParavirtTsc, + uint64_t *puTscNow, uint64_t *puDeadlineVersion); +VMM_INT_DECL(int) TMCpuTickSet(PVMCC pVM, PVMCPUCC pVCpu, uint64_t u64Tick); +VMM_INT_DECL(int) TMCpuTickSetLastSeen(PVMCPUCC pVCpu, uint64_t u64LastSeenTick); +VMM_INT_DECL(uint64_t) TMCpuTickGetLastSeen(PVMCPUCC pVCpu); +VMMDECL(uint64_t) TMCpuTicksPerSecond(PVMCC pVM); +VMM_INT_DECL(bool) TMCpuTickIsTicking(PVMCPUCC pVCpu); +/** @} */ + + +/** @name Timer Methods + * @{ + */ +/** + * Device timer callback function. + * + * @param pDevIns Device instance of the device which registered the timer. + * @param hTimer The timer handle. + * @param pvUser User argument specified upon timer creation. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMERDEV,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, void *pvUser)); +/** Pointer to a device timer callback function. */ +typedef FNTMTIMERDEV *PFNTMTIMERDEV; + +/** + * USB device timer callback function. + * + * @param pUsbIns The USB device instance the timer is associated + * with. + * @param hTimer The timer handle. + * @param pvUser User argument specified upon timer creation. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMERUSB,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, void *pvUser)); +/** Pointer to a timer callback for a USB device. */ +typedef FNTMTIMERUSB *PFNTMTIMERUSB; + +/** + * Driver timer callback function. + * + * @param pDrvIns Device instance of the device which registered the timer. + * @param hTimer The timer handle. + * @param pvUser User argument specified upon timer creation. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMERDRV,(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer, void *pvUser)); +/** Pointer to a driver timer callback function. */ +typedef FNTMTIMERDRV *PFNTMTIMERDRV; + +/** + * Service timer callback function. + * + * @param pSrvIns Service instance of the device which registered the timer. + * @param hTimer The timer handle. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMERSRV,(PPDMSRVINS pSrvIns, TMTIMERHANDLE hTimer)); +/** Pointer to a service timer callback function. */ +typedef FNTMTIMERSRV *PFNTMTIMERSRV; + +/** + * Internal timer callback function. + * + * @param pVM The cross context VM structure. + * @param hTimer The timer handle. + * @param pvUser User argument specified upon timer creation. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMERINT,(PVM pVM, TMTIMERHANDLE hTimer, void *pvUser)); +/** Pointer to internal timer callback function. */ +typedef FNTMTIMERINT *PFNTMTIMERINT; + +/** + * External timer callback function. + * + * @param pvUser User argument as specified when the timer was created. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMEREXT,(void *pvUser)); +/** Pointer to an external timer callback function. */ +typedef FNTMTIMEREXT *PFNTMTIMEREXT; + +VMMDECL(int) TMTimerLock(PVMCC pVM, TMTIMERHANDLE hTimer, int rcBusy); +VMMDECL(void) TMTimerUnlock(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(bool) TMTimerIsLockOwner(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(int) TMTimerSet(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t u64Expire); +VMMDECL(int) TMTimerSetRelative(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now); +VMMDECL(int) TMTimerSetFrequencyHint(PVMCC pVM, TMTIMERHANDLE hTimer, uint32_t uHz); +VMMDECL(uint64_t) TMTimerGet(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(int) TMTimerStop(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(bool) TMTimerIsActive(PVMCC pVM, TMTIMERHANDLE hTimer); + +VMMDECL(int) TMTimerSetMillies(PVMCC pVM, TMTIMERHANDLE hTimer, uint32_t cMilliesToNext); +VMMDECL(int) TMTimerSetMicro(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext); +VMMDECL(int) TMTimerSetNano(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cNanosToNext); +VMMDECL(uint64_t) TMTimerGetNano(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(uint64_t) TMTimerGetMicro(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(uint64_t) TMTimerGetMilli(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(uint64_t) TMTimerGetFreq(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(uint64_t) TMTimerGetExpire(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(uint64_t) TMTimerToNano(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cTicks); +VMMDECL(uint64_t) TMTimerToMicro(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cTicks); +VMMDECL(uint64_t) TMTimerToMilli(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cTicks); +VMMDECL(uint64_t) TMTimerFromNano(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cNanoSecs); +VMMDECL(uint64_t) TMTimerFromMicro(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cMicroSecs); +VMMDECL(uint64_t) TMTimerFromMilli(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cMilliSecs); + +VMMDECL(bool) TMTimerPollBool(PVMCC pVM, PVMCPUCC pVCpu); +VMM_INT_DECL(void) TMTimerPollVoid(PVMCC pVM, PVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) TMTimerPollGIP(PVMCC pVM, PVMCPUCC pVCpu, uint64_t *pu64Delta); +/** @} */ + + +/** @defgroup grp_tm_r3 The TM Host Context Ring-3 API + * @{ + */ +VMM_INT_DECL(int) TMR3Init(PVM pVM); +VMM_INT_DECL(int) TMR3InitFinalize(PVM pVM); +VMM_INT_DECL(void) TMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMM_INT_DECL(int) TMR3Term(PVM pVM); +VMM_INT_DECL(void) TMR3Reset(PVM pVM); +VMM_INT_DECL(int) TMR3TimerCreateDevice(PVM pVM, PPDMDEVINS pDevIns, TMCLOCK enmClock, PFNTMTIMERDEV pfnCallback, + void *pvUser, uint32_t fFlags, const char *pszName, PTMTIMERHANDLE phTimer); +VMM_INT_DECL(int) TMR3TimerCreateUsb(PVM pVM, PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, + void *pvUser, uint32_t fFlags, const char *pszName, PTMTIMERHANDLE phTimer); +VMM_INT_DECL(int) TMR3TimerCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, + void *pvUser, uint32_t fFlags, const char *pszName, PTMTIMERHANDLE phTimer); +VMMR3DECL(int) TMR3TimerCreate(PVM pVM, TMCLOCK enmClock, PFNTMTIMERINT pfnCallback, void *pvUser, uint32_t fFlags, + const char *pszName, PTMTIMERHANDLE phTimer); +VMMR3DECL(int) TMR3TimerDestroy(PVM pVM, TMTIMERHANDLE hTimer); +VMM_INT_DECL(int) TMR3TimerDestroyDevice(PVM pVM, PPDMDEVINS pDevIns); +VMM_INT_DECL(int) TMR3TimerDestroyUsb(PVM pVM, PPDMUSBINS pUsbIns); +VMM_INT_DECL(int) TMR3TimerDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns); +VMMR3DECL(int) TMR3TimerSave(PVMCC pVM, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM); +VMMR3DECL(int) TMR3TimerLoad(PVMCC pVM, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM); +VMMR3DECL(int) TMR3TimerSkip(PSSMHANDLE pSSM, bool *pfActive); +VMMR3DECL(int) TMR3TimerSetCritSect(PVMCC pVM, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect); +VMMR3DECL(void) TMR3TimerQueuesDo(PVM pVM); +VMMR3_INT_DECL(void) TMR3VirtualSyncFF(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(PRTTIMESPEC) TMR3UtcNow(PVM pVM, PRTTIMESPEC pTime); + +VMMR3_INT_DECL(int) TMR3CpuTickParavirtEnable(PVM pVM); +VMMR3_INT_DECL(int) TMR3CpuTickParavirtDisable(PVM pVM); +VMMR3_INT_DECL(bool) TMR3CpuTickIsFixedRateMonotonic(PVM pVM, bool fWithParavirtEnabled); +/** @} */ + + +/** @defgroup grp_tm_r0 The TM Host Context Ring-0 API + * @{ + */ +VMMR0_INT_DECL(void) TMR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(void) TMR0CleanupVM(PGVM pGVM); +VMMR0_INT_DECL(int) TMR0TimerQueueGrow(PGVM pGVM, uint32_t idxQueue, uint32_t cMinTimers); +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_tm_h */ + diff --git a/include/VBox/vmm/trpm.h b/include/VBox/vmm/trpm.h new file mode 100644 index 00000000..0e23dd5b --- /dev/null +++ b/include/VBox/vmm/trpm.h @@ -0,0 +1,102 @@ +/** @file + * TRPM - The Trap Monitor. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_trpm_h +#define VBOX_INCLUDED_vmm_trpm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/x86.h> + + +RT_C_DECLS_BEGIN +/** @defgroup grp_trpm The Trap Monitor API + * @ingroup grp_vmm + * @{ + */ + +/** + * TRPM event type. + */ +typedef enum +{ + TRPM_TRAP = 0, + TRPM_HARDWARE_INT = 1, + TRPM_SOFTWARE_INT = 2, + /** The usual 32-bit paranoia. */ + TRPM_32BIT_HACK = 0x7fffffff +} TRPMEVENT; +/** Pointer to a TRPM event type. */ +typedef TRPMEVENT *PTRPMEVENT; +/** Pointer to a const TRPM event type. */ +typedef TRPMEVENT const *PCTRPMEVENT; + +VMMDECL(int) TRPMQueryTrap(PVMCPU pVCpu, uint8_t *pu8TrapNo, PTRPMEVENT penmType); +VMMDECL(uint8_t) TRPMGetTrapNo(PVMCPU pVCpu); +VMMDECL(uint32_t) TRPMGetErrorCode(PVMCPU pVCpu); +VMMDECL(RTGCUINTPTR) TRPMGetFaultAddress(PVMCPU pVCpu); +VMMDECL(uint8_t) TRPMGetInstrLength(PVMCPU pVCpu); +VMMDECL(bool) TRPMIsTrapDueToIcebp(PVMCPU pVCpu); +VMMDECL(int) TRPMResetTrap(PVMCPU pVCpu); +VMMDECL(int) TRPMAssertTrap(PVMCPUCC pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType); +VMMDECL(int) TRPMAssertXcptPF(PVMCPUCC pVCpu, RTGCUINTPTR uCR2, uint32_t uErrorCode); +VMMDECL(void) TRPMSetErrorCode(PVMCPU pVCpu, uint32_t uErrorCode); +VMMDECL(void) TRPMSetFaultAddress(PVMCPU pVCpu, RTGCUINTPTR uCR2); +VMMDECL(void) TRPMSetInstrLength(PVMCPU pVCpu, uint8_t cbInstr); +VMMDECL(void) TRPMSetTrapDueToIcebp(PVMCPU pVCpu); +VMMDECL(bool) TRPMIsSoftwareInterrupt(PVMCPU pVCpu); +VMMDECL(bool) TRPMHasTrap(PVMCPU pVCpu); +VMMDECL(int) TRPMQueryTrapAll(PVMCPU pVCpu, uint8_t *pu8TrapNo, PTRPMEVENT pEnmType, uint32_t *puErrorCode, + PRTGCUINTPTR puCR2, uint8_t *pcbInstr, bool *pfIcebp); + +#ifdef IN_RING3 +/** @defgroup grp_trpm_r3 TRPM Host Context Ring 3 API + * @{ + */ +VMMR3DECL(int) TRPMR3Init(PVM pVM); +VMMR3DECL(void) TRPMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3DECL(void) TRPMR3ResetCpu(PVMCPU pVCpu); +VMMR3DECL(void) TRPMR3Reset(PVM pVM); +VMMR3DECL(int) TRPMR3Term(PVM pVM); +VMMR3DECL(int) TRPMR3InjectEvent(PVM pVM, PVMCPU pVCpu, TRPMEVENT enmEvent, bool *pfInjected); +/** @} */ +#endif + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_trpm_h */ diff --git a/include/VBox/vmm/trpm.mac b/include/VBox/vmm/trpm.mac new file mode 100644 index 00000000..6e1c1cd6 --- /dev/null +++ b/include/VBox/vmm/trpm.mac @@ -0,0 +1,57 @@ +;; @file +; TRPM - The Trap Monitor. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_vmm_trpm_mac__ +%define ___VBox_vmm_trpm_mac__ + + +;/** +; * TRPM event type +; */ +;/** Note: must match trpm.mac! */ +;typedef enum +;{ +; TRPM_TRAP = 0, +; TRPM_HARDWARE_INT = 1, +; TRPM_SOFTWARE_INT = 2, +; /** The usual 32-bit paranoia. */ +; TRPM_32BIT_HACK = 0x7fffffff +;} TRPMEVENT; + +%define TRPM_TRAP 0 +%define TRPM_HARDWARE_INT 1 +%define TRPM_SOFTWARE_INT 2 +%endif + diff --git a/include/VBox/vmm/uvm.h b/include/VBox/vmm/uvm.h new file mode 100644 index 00000000..2edc65db --- /dev/null +++ b/include/VBox/vmm/uvm.h @@ -0,0 +1,195 @@ +/** @file + * GVM - The Global VM Data. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_uvm_h +#define VBOX_INCLUDED_vmm_uvm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/assert.h> + +/** @addtogroup grp_vm + * @{ */ + + +/** + * Per virtual CPU ring-3 (user mode) data. + */ +typedef struct UVMCPU +{ + /** Pointer to the UVM structure. */ + PUVM pUVM; + /** Pointer to the VM structure. */ + PVM pVM; + /** Pointer to the VMCPU structure. */ + PVMCPU pVCpu; + /** The virtual CPU ID. */ + RTCPUID idCpu; + /** Alignment padding. */ + uint8_t abAlignment0[HC_ARCH_BITS == 32 ? 16 : 4]; + + /** The VM internal data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_VMInternal_h + struct VMINTUSERPERVMCPU s; +#endif + uint8_t padding[512]; + } vm; + + /** The DBGF data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_DBGFInternal_h + struct DBGFUSERPERVMCPU s; +#endif + uint8_t padding[64]; + } dbgf; + +} UVMCPU; +AssertCompileMemberAlignment(UVMCPU, vm, 32); + + +/** + * The ring-3 (user mode) VM structure. + * + * This structure is similar to VM and GVM except that it resides in swappable + * user memory. The main purpose is to assist bootstrapping, where it allows us + * to start EMT much earlier and gives PDMLdr somewhere to put it's VMMR0 data. + * It is also a nice place to put big things that are user mode only. + */ +typedef struct UVM +{ + /** Magic / eye-catcher (UVM_MAGIC). */ + uint32_t u32Magic; + /** The number of virtual CPUs. */ + uint32_t cCpus; + /** The ring-3 mapping of the shared VM structure. */ + PVM pVM; + /** Pointer to the next VM. + * We keep a per process list of VM for the event that a process could + * contain more than one VM. + * @todo move this into vm.s! + */ + struct UVM *pNext; + + /** Pointer to the optional method table provided by the VMM user. */ + PCVMM2USERMETHODS pVmm2UserMethods; + +#if HC_ARCH_BITS == 32 + /** Align the next member on a 32 byte boundary. */ + uint8_t abAlignment0[HC_ARCH_BITS == 32 ? 12 : 0]; +#endif + + /** The VM internal data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_VMInternal_h + struct VMINTUSERPERVM s; +#endif + uint8_t padding[512]; + } vm; + + /** The MM data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_MMInternal_h + struct MMUSERPERVM s; +#endif + uint8_t padding[32]; + } mm; + + /** The PDM data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_PDMInternal_h + struct PDMUSERPERVM s; +#endif + uint8_t padding[256]; + } pdm; + + /** The STAM data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_STAMInternal_h + struct STAMUSERPERVM s; +#endif + uint8_t padding[30208]; + } stam; + + /** The DBGF data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_DBGFInternal_h + struct DBGFUSERPERVM s; +#endif + uint8_t padding[1024]; + } dbgf; + + /** Per virtual CPU data. */ + UVMCPU aCpus[1]; +} UVM; +AssertCompileMemberAlignment(UVM, vm, 32); +AssertCompileMemberAlignment(UVM, mm, 32); +AssertCompileMemberAlignment(UVM, pdm, 32); +AssertCompileMemberAlignment(UVM, stam, 32); +AssertCompileMemberAlignment(UVM, aCpus, 32); + +/** The UVM::u32Magic value (Brad Mehldau). */ +#define UVM_MAGIC 0x19700823 + +/** @def UVM_ASSERT_VALID_EXT_RETURN + * Asserts a user mode VM handle is valid for external access. + */ +#define UVM_ASSERT_VALID_EXT_RETURN(a_pUVM, a_rc) \ + AssertMsgReturn( RT_VALID_ALIGNED_PTR(a_pUVM, PAGE_SIZE) \ + && (a_pUVM)->u32Magic == UVM_MAGIC, \ + ("a_pUVM=%p u32Magic=%#x\n", (a_pUVM), \ + RT_VALID_ALIGNED_PTR(a_pUVM, PAGE_SIZE) ? (a_pUVM)->u32Magic : 0), \ + (a_rc)) +/** @def UVM_ASSERT_VALID_EXT_RETURN + * Asserts a user mode VM handle is valid for external access. + */ +#define UVM_ASSERT_VALID_EXT_RETURN_VOID(a_pUVM) \ + AssertMsgReturnVoid( RT_VALID_ALIGNED_PTR(a_pUVM, PAGE_SIZE) \ + && (a_pUVM)->u32Magic == UVM_MAGIC, \ + ("a_pUVM=%p u32Magic=%#x\n", (a_pUVM), \ + RT_VALID_ALIGNED_PTR(a_pUVM, PAGE_SIZE) ? (a_pUVM)->u32Magic : 0)) + +/** @} */ +#endif /* !VBOX_INCLUDED_vmm_uvm_h */ + diff --git a/include/VBox/vmm/vm.h b/include/VBox/vmm/vm.h new file mode 100644 index 00000000..2ebdda94 --- /dev/null +++ b/include/VBox/vmm/vm.h @@ -0,0 +1,1519 @@ +/** @file + * VM - The Virtual Machine, data. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vm_h +#define VBOX_INCLUDED_vmm_vm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef VBOX_FOR_DTRACE_LIB +# ifndef USING_VMM_COMMON_DEFS +# error "Compile job does not include VMM_COMMON_DEFS from src/VBox/VMM/Config.kmk - make sure you really need to include this file!" +# endif +# include <iprt/param.h> +# include <VBox/param.h> +# include <VBox/types.h> +# include <VBox/vmm/cpum.h> +# include <VBox/vmm/stam.h> +# include <VBox/vmm/vmapi.h> +# include <VBox/vmm/vmm.h> +# include <VBox/sup.h> +#else +# pragma D depends_on library vbox-types.d +# pragma D depends_on library CPUMInternal.d +# define VMM_INCLUDED_SRC_include_CPUMInternal_h +#endif + + + +/** @defgroup grp_vm The Virtual Machine + * @ingroup grp_vmm + * @{ + */ + +/** + * The state of a Virtual CPU. + * + * The basic state indicated here is whether the CPU has been started or not. In + * addition, there are sub-states when started for assisting scheduling (GVMM + * mostly). + * + * The transition out of the STOPPED state is done by a vmR3PowerOn. + * The transition back to the STOPPED state is done by vmR3PowerOff. + * + * (Alternatively we could let vmR3PowerOn start CPU 0 only and let the SPIP + * handling switch on the other CPUs. Then vmR3Reset would stop all but CPU 0.) + */ +typedef enum VMCPUSTATE +{ + /** The customary invalid zero. */ + VMCPUSTATE_INVALID = 0, + + /** Virtual CPU has not yet been started. */ + VMCPUSTATE_STOPPED, + + /** CPU started. */ + VMCPUSTATE_STARTED, + /** CPU started in HM context. */ + VMCPUSTATE_STARTED_HM, + /** Executing guest code and can be poked (RC or STI bits of HM). */ + VMCPUSTATE_STARTED_EXEC, + /** Executing guest code using NEM. */ + VMCPUSTATE_STARTED_EXEC_NEM, + VMCPUSTATE_STARTED_EXEC_NEM_WAIT, + VMCPUSTATE_STARTED_EXEC_NEM_CANCELED, + /** Halted. */ + VMCPUSTATE_STARTED_HALTED, + + /** The end of valid virtual CPU states. */ + VMCPUSTATE_END, + + /** Ensure 32-bit type. */ + VMCPUSTATE_32BIT_HACK = 0x7fffffff +} VMCPUSTATE; + +/** Enables 64-bit FFs. */ +#define VMCPU_WITH_64_BIT_FFS + + +/** + * The cross context virtual CPU structure. + * + * Run 'kmk run-struct-tests' (from src/VBox/VMM if you like) after updating! + */ +typedef struct VMCPU +{ + /** @name Volatile per-cpu data. + * @{ */ + /** Per CPU forced action. + * See the VMCPU_FF_* \#defines. Updated atomically. */ +#ifdef VMCPU_WITH_64_BIT_FFS + uint64_t volatile fLocalForcedActions; +#else + uint32_t volatile fLocalForcedActions; + uint32_t fForLocalForcedActionsExpansion; +#endif + /** The CPU state. */ + VMCPUSTATE volatile enmState; + + /** Padding up to 64 bytes. */ + uint8_t abAlignment0[64 - 12]; + /** @} */ + + /** IEM part. + * @remarks This comes first as it allows the use of 8-bit immediates for the + * first 64 bytes of the structure, reducing code size a wee bit. */ +#ifdef VMM_INCLUDED_SRC_include_IEMInternal_h /* For PDB hacking. */ + union VMCPUUNIONIEMFULL +#else + union VMCPUUNIONIEMSTUB +#endif + { +#ifdef VMM_INCLUDED_SRC_include_IEMInternal_h + struct IEMCPU s; +#endif + uint8_t padding[32832]; /* multiple of 64 */ + } iem; + + /** @name Static per-cpu data. + * (Putting this after IEM, hoping that it's less frequently used than it.) + * @{ */ + /** Ring-3 Host Context VM Pointer. */ + PVMR3 pVMR3; + /** Ring-0 Host Context VM Pointer, currently used by VTG/dtrace. */ + RTR0PTR pVCpuR0ForVtg; + /** Raw-mode Context VM Pointer. */ + uint32_t pVMRC; + /** Padding for new raw-mode (long mode). */ + uint32_t pVMRCPadding; + /** Pointer to the ring-3 UVMCPU structure. */ + PUVMCPU pUVCpu; + /** The native thread handle. */ + RTNATIVETHREAD hNativeThread; + /** The native R0 thread handle. (different from the R3 handle!) */ + RTNATIVETHREAD hNativeThreadR0; + /** The IPRT thread handle (for VMMDevTesting). */ + RTTHREAD hThread; + /** The CPU ID. + * This is the index into the VM::aCpu array. */ +#ifdef IN_RING0 + VMCPUID idCpuUnsafe; +#else + VMCPUID idCpu; +#endif + + /** Align the structures below bit on a 64-byte boundary and make sure it starts + * at the same offset in both 64-bit and 32-bit builds. + * + * @remarks The alignments of the members that are larger than 48 bytes should be + * 64-byte for cache line reasons. structs containing small amounts of + * data could be lumped together at the end with a < 64 byte padding + * following it (to grow into and align the struct size). + */ + uint8_t abAlignment1[64 - 6 * (HC_ARCH_BITS == 32 ? 4 : 8) - 8 - 4]; + /** @} */ + + /** HM part. */ + union VMCPUUNIONHM + { +#ifdef VMM_INCLUDED_SRC_include_HMInternal_h + struct HMCPU s; +#endif + uint8_t padding[9984]; /* multiple of 64 */ + } hm; + + /** NEM part. */ + union VMCPUUNIONNEM + { +#ifdef VMM_INCLUDED_SRC_include_NEMInternal_h + struct NEMCPU s; +#endif + uint8_t padding[4608]; /* multiple of 64 */ + } nem; + + /** TRPM part. */ + union VMCPUUNIONTRPM + { +#ifdef VMM_INCLUDED_SRC_include_TRPMInternal_h + struct TRPMCPU s; +#endif + uint8_t padding[128]; /* multiple of 64 */ + } trpm; + + /** TM part. */ + union VMCPUUNIONTM + { +#ifdef VMM_INCLUDED_SRC_include_TMInternal_h + struct TMCPU s; +#endif + uint8_t padding[5760]; /* multiple of 64 */ + } tm; + + /** VMM part. */ + union VMCPUUNIONVMM + { +#ifdef VMM_INCLUDED_SRC_include_VMMInternal_h + struct VMMCPU s; +#endif + uint8_t padding[9536]; /* multiple of 64 */ + } vmm; + + /** PDM part. */ + union VMCPUUNIONPDM + { +#ifdef VMM_INCLUDED_SRC_include_PDMInternal_h + struct PDMCPU s; +#endif + uint8_t padding[256]; /* multiple of 64 */ + } pdm; + + /** IOM part. */ + union VMCPUUNIONIOM + { +#ifdef VMM_INCLUDED_SRC_include_IOMInternal_h + struct IOMCPU s; +#endif + uint8_t padding[512]; /* multiple of 64 */ + } iom; + + /** DBGF part. + * @todo Combine this with other tiny structures. */ + union VMCPUUNIONDBGF + { +#ifdef VMM_INCLUDED_SRC_include_DBGFInternal_h + struct DBGFCPU s; +#endif + uint8_t padding[512]; /* multiple of 64 */ + } dbgf; + + /** GIM part. */ + union VMCPUUNIONGIM + { +#ifdef VMM_INCLUDED_SRC_include_GIMInternal_h + struct GIMCPU s; +#endif + uint8_t padding[512]; /* multiple of 64 */ + } gim; + + /** APIC part. */ + union VMCPUUNIONAPIC + { +#ifdef VMM_INCLUDED_SRC_include_APICInternal_h + struct APICCPU s; +#endif + uint8_t padding[3840]; /* multiple of 64 */ + } apic; + + /* + * Some less frequently used global members that doesn't need to take up + * precious space at the head of the structure. + */ + + /** Trace groups enable flags. */ + uint32_t fTraceGroups; /* 64 / 44 */ + /** Number of collisions hashing the ring-0 EMT handle. */ + uint8_t cEmtHashCollisions; + uint8_t abAdHoc[3]; + /** Profiling samples for use by ad hoc profiling. */ + STAMPROFILEADV aStatAdHoc[8]; /* size: 40*8 = 320 */ + + /** Align the following members on page boundary. */ + uint8_t abAlignment2[696]; + + /** PGM part. */ + union VMCPUUNIONPGM + { +#ifdef VMM_INCLUDED_SRC_include_PGMInternal_h + struct PGMCPU s; +#endif + uint8_t padding[4096 + 28672]; /* multiple of 4096 */ + } pgm; + + /** CPUM part. */ + union VMCPUUNIONCPUM + { +#ifdef VMM_INCLUDED_SRC_include_CPUMInternal_h + struct CPUMCPU s; +#endif +#ifdef VMCPU_INCL_CPUM_GST_CTX + /** The guest CPUM context for direct use by execution engines. + * This is not for general consumption, but for HM, REM, IEM, and maybe a few + * others. The rest will use the function based CPUM API. */ + CPUMCTX GstCtx; +#endif + uint8_t padding[102400]; /* multiple of 4096 */ + } cpum; + + /** EM part. */ + union VMCPUUNIONEM + { +#ifdef VMM_INCLUDED_SRC_include_EMInternal_h + struct EMCPU s; +#endif + uint8_t padding[40960]; /* multiple of 4096 */ + } em; + +} VMCPU; + + +#ifndef VBOX_FOR_DTRACE_LIB +/* Make sure the structure size is aligned on a 16384 boundary for arm64 purposes. */ +AssertCompileSizeAlignment(VMCPU, 16384); + +/** @name Operations on VMCPU::enmState + * @{ */ +/** Gets the VMCPU state. */ +#define VMCPU_GET_STATE(pVCpu) ( (pVCpu)->enmState ) +/** Sets the VMCPU state. */ +#define VMCPU_SET_STATE(pVCpu, enmNewState) \ + ASMAtomicWriteU32((uint32_t volatile *)&(pVCpu)->enmState, (enmNewState)) +/** Cmpares and sets the VMCPU state. */ +#define VMCPU_CMPXCHG_STATE(pVCpu, enmNewState, enmOldState) \ + ASMAtomicCmpXchgU32((uint32_t volatile *)&(pVCpu)->enmState, (enmNewState), (enmOldState)) +/** Checks the VMCPU state. */ +#ifdef VBOX_STRICT +# define VMCPU_ASSERT_STATE(pVCpu, enmExpectedState) \ + do { \ + VMCPUSTATE enmState = VMCPU_GET_STATE(pVCpu); \ + AssertMsg(enmState == (enmExpectedState), \ + ("enmState=%d enmExpectedState=%d idCpu=%u\n", \ + enmState, enmExpectedState, (pVCpu)->idCpu)); \ + } while (0) + +# define VMCPU_ASSERT_STATE_2(pVCpu, enmExpectedState, a_enmExpectedState2) \ + do { \ + VMCPUSTATE enmState = VMCPU_GET_STATE(pVCpu); \ + AssertMsg( enmState == (enmExpectedState) \ + || enmState == (a_enmExpectedState2), \ + ("enmState=%d enmExpectedState=%d enmExpectedState2=%d idCpu=%u\n", \ + enmState, enmExpectedState, a_enmExpectedState2, (pVCpu)->idCpu)); \ + } while (0) +#else +# define VMCPU_ASSERT_STATE(pVCpu, enmExpectedState) do { } while (0) +# define VMCPU_ASSERT_STATE_2(pVCpu, enmExpectedState, a_enmExpectedState2) do { } while (0) +#endif +/** Tests if the state means that the CPU is started. */ +#define VMCPUSTATE_IS_STARTED(enmState) ( (enmState) > VMCPUSTATE_STOPPED ) +/** Tests if the state means that the CPU is stopped. */ +#define VMCPUSTATE_IS_STOPPED(enmState) ( (enmState) == VMCPUSTATE_STOPPED ) +/** @} */ + + +/** The name of the raw-mode context VMM Core module. */ +#define VMMRC_MAIN_MODULE_NAME "VMMRC.rc" +/** The name of the ring-0 context VMM Core module. */ +#define VMMR0_MAIN_MODULE_NAME "VMMR0.r0" + + +/** VM Forced Action Flags. + * + * Use the VM_FF_SET() and VM_FF_CLEAR() macros to change the force + * action mask of a VM. + * + * Available VM bits: + * 0, 1, 5, 6, 7, 13, 14, 15, 16, 17, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 + * + * + * Available VMCPU bits: + * 14, 15, 36 to 63 + * + * @todo If we run low on VMCPU, we may consider merging the SELM bits + * + * @{ + */ +/** The virtual sync clock has been stopped, go to TM until it has been + * restarted... */ +#define VM_FF_TM_VIRTUAL_SYNC RT_BIT_32(VM_FF_TM_VIRTUAL_SYNC_BIT) +#define VM_FF_TM_VIRTUAL_SYNC_BIT 2 +/** PDM Queues are pending. */ +#define VM_FF_PDM_QUEUES RT_BIT_32(VM_FF_PDM_QUEUES_BIT) +/** The bit number for VM_FF_PDM_QUEUES. */ +#define VM_FF_PDM_QUEUES_BIT 3 +/** PDM DMA transfers are pending. */ +#define VM_FF_PDM_DMA RT_BIT_32(VM_FF_PDM_DMA_BIT) +/** The bit number for VM_FF_PDM_DMA. */ +#define VM_FF_PDM_DMA_BIT 4 +/** This action forces the VM to call DBGF so DBGF can service debugger + * requests in the emulation thread. + * This action flag stays asserted till DBGF clears it.*/ +#define VM_FF_DBGF RT_BIT_32(VM_FF_DBGF_BIT) +/** The bit number for VM_FF_DBGF. */ +#define VM_FF_DBGF_BIT 8 +/** This action forces the VM to service pending requests from other + * thread or requests which must be executed in another context. */ +#define VM_FF_REQUEST RT_BIT_32(VM_FF_REQUEST_BIT) +#define VM_FF_REQUEST_BIT 9 +/** Check for VM state changes and take appropriate action. */ +#define VM_FF_CHECK_VM_STATE RT_BIT_32(VM_FF_CHECK_VM_STATE_BIT) +/** The bit number for VM_FF_CHECK_VM_STATE. */ +#define VM_FF_CHECK_VM_STATE_BIT 10 +/** Reset the VM. (postponed) */ +#define VM_FF_RESET RT_BIT_32(VM_FF_RESET_BIT) +/** The bit number for VM_FF_RESET. */ +#define VM_FF_RESET_BIT 11 +/** EMT rendezvous in VMM. */ +#define VM_FF_EMT_RENDEZVOUS RT_BIT_32(VM_FF_EMT_RENDEZVOUS_BIT) +/** The bit number for VM_FF_EMT_RENDEZVOUS. */ +#define VM_FF_EMT_RENDEZVOUS_BIT 12 + +/** PGM needs to allocate handy pages. */ +#define VM_FF_PGM_NEED_HANDY_PAGES RT_BIT_32(VM_FF_PGM_NEED_HANDY_PAGES_BIT) +#define VM_FF_PGM_NEED_HANDY_PAGES_BIT 18 +/** PGM is out of memory. + * Abandon all loops and code paths which can be resumed and get up to the EM + * loops. */ +#define VM_FF_PGM_NO_MEMORY RT_BIT_32(VM_FF_PGM_NO_MEMORY_BIT) +#define VM_FF_PGM_NO_MEMORY_BIT 19 + /** PGM is about to perform a lightweight pool flush + * Guest SMP: all EMT threads should return to ring 3 + */ +#define VM_FF_PGM_POOL_FLUSH_PENDING RT_BIT_32(VM_FF_PGM_POOL_FLUSH_PENDING_BIT) +#define VM_FF_PGM_POOL_FLUSH_PENDING_BIT 20 +/** Suspend the VM - debug only. */ +#define VM_FF_DEBUG_SUSPEND RT_BIT_32(VM_FF_DEBUG_SUSPEND_BIT) +#define VM_FF_DEBUG_SUSPEND_BIT 31 + + +/** This action forces the VM to check any pending interrupts on the APIC. */ +#define VMCPU_FF_INTERRUPT_APIC RT_BIT_64(VMCPU_FF_INTERRUPT_APIC_BIT) +#define VMCPU_FF_INTERRUPT_APIC_BIT 0 +/** This action forces the VM to check any pending interrups on the PIC. */ +#define VMCPU_FF_INTERRUPT_PIC RT_BIT_64(VMCPU_FF_INTERRUPT_PIC_BIT) +#define VMCPU_FF_INTERRUPT_PIC_BIT 1 +/** This action forces the VM to schedule and run pending timer (TM). + * @remarks Don't move - PATM compatibility. */ +#define VMCPU_FF_TIMER RT_BIT_64(VMCPU_FF_TIMER_BIT) +#define VMCPU_FF_TIMER_BIT 2 +/** This action forces the VM to check any pending NMIs. */ +#define VMCPU_FF_INTERRUPT_NMI RT_BIT_64(VMCPU_FF_INTERRUPT_NMI_BIT) +#define VMCPU_FF_INTERRUPT_NMI_BIT 3 +/** This action forces the VM to check any pending SMIs. */ +#define VMCPU_FF_INTERRUPT_SMI RT_BIT_64(VMCPU_FF_INTERRUPT_SMI_BIT) +#define VMCPU_FF_INTERRUPT_SMI_BIT 4 +/** PDM critical section unlocking is pending, process promptly upon return to R3. */ +#define VMCPU_FF_PDM_CRITSECT RT_BIT_64(VMCPU_FF_PDM_CRITSECT_BIT) +#define VMCPU_FF_PDM_CRITSECT_BIT 5 +/** Special EM internal force flag that is used by EMUnhaltAndWakeUp() to force + * the virtual CPU out of the next (/current) halted state. It is not processed + * nor cleared by emR3ForcedActions (similar to VMCPU_FF_BLOCK_NMIS), instead it + * is cleared the next time EM leaves the HALTED state. */ +#define VMCPU_FF_UNHALT RT_BIT_64(VMCPU_FF_UNHALT_BIT) +#define VMCPU_FF_UNHALT_BIT 6 +/** Pending IEM action (mask). */ +#define VMCPU_FF_IEM RT_BIT_64(VMCPU_FF_IEM_BIT) +/** Pending IEM action (bit number). */ +#define VMCPU_FF_IEM_BIT 7 +/** Pending APIC action (bit number). */ +#define VMCPU_FF_UPDATE_APIC_BIT 8 +/** This action forces the VM to update APIC's asynchronously arrived + * interrupts as pending interrupts. */ +#define VMCPU_FF_UPDATE_APIC RT_BIT_64(VMCPU_FF_UPDATE_APIC_BIT) +/** This action forces the VM to service pending requests from other + * thread or requests which must be executed in another context. */ +#define VMCPU_FF_REQUEST RT_BIT_64(VMCPU_FF_REQUEST_BIT) +#define VMCPU_FF_REQUEST_BIT 9 +/** Pending DBGF event (alternative to passing VINF_EM_DBG_EVENT around). */ +#define VMCPU_FF_DBGF RT_BIT_64(VMCPU_FF_DBGF_BIT) +/** The bit number for VMCPU_FF_DBGF. */ +#define VMCPU_FF_DBGF_BIT 10 +/** Hardware virtualized nested-guest interrupt pending. */ +#define VMCPU_FF_INTERRUPT_NESTED_GUEST RT_BIT_64(VMCPU_FF_INTERRUPT_NESTED_GUEST_BIT) +#define VMCPU_FF_INTERRUPT_NESTED_GUEST_BIT 11 +/** This action forces PGM to update changes to CR3 when the guest was in HM mode + * (when using nested paging). */ +#define VMCPU_FF_HM_UPDATE_CR3 RT_BIT_64(VMCPU_FF_HM_UPDATE_CR3_BIT) +#define VMCPU_FF_HM_UPDATE_CR3_BIT 12 +/* Bit 13 used to be VMCPU_FF_HM_UPDATE_PAE_PDPES. */ +/** This action forces the VM to resync the page tables before going + * back to execute guest code. (GLOBAL FLUSH) */ +#define VMCPU_FF_PGM_SYNC_CR3 RT_BIT_64(VMCPU_FF_PGM_SYNC_CR3_BIT) +#define VMCPU_FF_PGM_SYNC_CR3_BIT 16 +/** Same as VM_FF_PGM_SYNC_CR3 except that global pages can be skipped. + * (NON-GLOBAL FLUSH) */ +#define VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL RT_BIT_64(VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL_BIT) +#define VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL_BIT 17 +/** Check for pending TLB shootdown actions (deprecated) + * Reserved for future HM re-use if necessary / safe. + * Consumer: HM */ +#define VMCPU_FF_TLB_SHOOTDOWN_UNUSED RT_BIT_64(VMCPU_FF_TLB_SHOOTDOWN_UNUSED_BIT) +#define VMCPU_FF_TLB_SHOOTDOWN_UNUSED_BIT 18 +/** Check for pending TLB flush action. + * Consumer: HM + * @todo rename to VMCPU_FF_HM_TLB_FLUSH */ +#define VMCPU_FF_TLB_FLUSH RT_BIT_64(VMCPU_FF_TLB_FLUSH_BIT) +/** The bit number for VMCPU_FF_TLB_FLUSH. */ +#define VMCPU_FF_TLB_FLUSH_BIT 19 +/* 20 used to be VMCPU_FF_TRPM_SYNC_IDT (raw-mode only). */ +/* 21 used to be VMCPU_FF_SELM_SYNC_TSS (raw-mode only). */ +/* 22 used to be VMCPU_FF_SELM_SYNC_GDT (raw-mode only). */ +/* 23 used to be VMCPU_FF_SELM_SYNC_LDT (raw-mode only). */ +/* 24 used to be VMCPU_FF_INHIBIT_INTERRUPTS, which moved to CPUMCTX::eflags.uBoth in v7.0.4. */ +/* 25 used to be VMCPU_FF_BLOCK_NMIS, which moved to CPUMCTX::eflags.uBoth in v7.0.4. */ +/** Force return to Ring-3. */ +#define VMCPU_FF_TO_R3 RT_BIT_64(VMCPU_FF_TO_R3_BIT) +#define VMCPU_FF_TO_R3_BIT 28 +/** Force return to ring-3 to service pending I/O or MMIO write. + * This is a backup for mechanism VINF_IOM_R3_IOPORT_COMMIT_WRITE and + * VINF_IOM_R3_MMIO_COMMIT_WRITE, allowing VINF_EM_DBG_BREAKPOINT and similar + * status codes to be propagated at the same time without loss. */ +#define VMCPU_FF_IOM RT_BIT_64(VMCPU_FF_IOM_BIT) +#define VMCPU_FF_IOM_BIT 29 +/* 30 used to be VMCPU_FF_CPUM */ +/** VMX-preemption timer expired. */ +#define VMCPU_FF_VMX_PREEMPT_TIMER RT_BIT_64(VMCPU_FF_VMX_PREEMPT_TIMER_BIT) +#define VMCPU_FF_VMX_PREEMPT_TIMER_BIT 31 +/** Pending MTF (Monitor Trap Flag) event. */ +#define VMCPU_FF_VMX_MTF RT_BIT_64(VMCPU_FF_VMX_MTF_BIT) +#define VMCPU_FF_VMX_MTF_BIT 32 +/** VMX APIC-write emulation pending. + * @todo possible candidate for internal EFLAGS, or maybe just a summary bit + * (see also VMCPU_FF_VMX_INT_WINDOW). */ +#define VMCPU_FF_VMX_APIC_WRITE RT_BIT_64(VMCPU_FF_VMX_APIC_WRITE_BIT) +#define VMCPU_FF_VMX_APIC_WRITE_BIT 33 +/** VMX interrupt-window event pending. + * + * "Pending" is misleading here, it would be better to say that the event need + * to be generated at the next opportunity and that this flag causes it to be + * polled for on every instruction boundrary and such. + * + * @todo Change the IEM side of this to not poll but to track down the places + * where it can be generated and set an internal EFLAGS bit that causes it + * to be checked out when finishing the current instruction. */ +#define VMCPU_FF_VMX_INT_WINDOW RT_BIT_64(VMCPU_FF_VMX_INT_WINDOW_BIT) +#define VMCPU_FF_VMX_INT_WINDOW_BIT 34 +/** VMX NMI-window event pending. + * Same "pending" comment and todo in VMCPU_FF_VMX_INT_WINDOW. */ +#define VMCPU_FF_VMX_NMI_WINDOW RT_BIT_64(VMCPU_FF_VMX_NMI_WINDOW_BIT) +#define VMCPU_FF_VMX_NMI_WINDOW_BIT 35 + + +/** Externally VM forced actions. Used to quit the idle/wait loop. */ +#define VM_FF_EXTERNAL_SUSPENDED_MASK ( VM_FF_CHECK_VM_STATE | VM_FF_DBGF | VM_FF_REQUEST | VM_FF_EMT_RENDEZVOUS ) +/** Externally VMCPU forced actions. Used to quit the idle/wait loop. */ +#define VMCPU_FF_EXTERNAL_SUSPENDED_MASK ( VMCPU_FF_REQUEST | VMCPU_FF_DBGF ) + +/** Externally forced VM actions. Used to quit the idle/wait loop. */ +#define VM_FF_EXTERNAL_HALTED_MASK ( VM_FF_CHECK_VM_STATE | VM_FF_DBGF | VM_FF_REQUEST \ + | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA | VM_FF_EMT_RENDEZVOUS ) +/** Externally forced VMCPU actions. Used to quit the idle/wait loop. */ +#define VMCPU_FF_EXTERNAL_HALTED_MASK ( VMCPU_FF_UPDATE_APIC | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC \ + | VMCPU_FF_REQUEST | VMCPU_FF_INTERRUPT_NMI | VMCPU_FF_INTERRUPT_SMI \ + | VMCPU_FF_UNHALT | VMCPU_FF_TIMER | VMCPU_FF_DBGF \ + | VMCPU_FF_INTERRUPT_NESTED_GUEST) + +/** High priority VM pre-execution actions. */ +#define VM_FF_HIGH_PRIORITY_PRE_MASK ( VM_FF_CHECK_VM_STATE | VM_FF_DBGF | VM_FF_TM_VIRTUAL_SYNC \ + | VM_FF_DEBUG_SUSPEND | VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY \ + | VM_FF_EMT_RENDEZVOUS ) +/** High priority VMCPU pre-execution actions. */ +#define VMCPU_FF_HIGH_PRIORITY_PRE_MASK ( VMCPU_FF_TIMER | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC \ + | VMCPU_FF_UPDATE_APIC | VMCPU_FF_DBGF \ + | VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL \ + | VMCPU_FF_INTERRUPT_NESTED_GUEST | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_APIC_WRITE \ + | VMCPU_FF_VMX_PREEMPT_TIMER | VMCPU_FF_VMX_NMI_WINDOW | VMCPU_FF_VMX_INT_WINDOW ) + +/** High priority VM pre raw-mode execution mask. */ +#define VM_FF_HIGH_PRIORITY_PRE_RAW_MASK ( VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY ) +/** High priority VMCPU pre raw-mode execution mask. */ +#define VMCPU_FF_HIGH_PRIORITY_PRE_RAW_MASK ( VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL ) + +/** High priority post-execution actions. */ +#define VM_FF_HIGH_PRIORITY_POST_MASK ( VM_FF_PGM_NO_MEMORY ) +/** High priority post-execution actions. */ +#define VMCPU_FF_HIGH_PRIORITY_POST_MASK ( VMCPU_FF_PDM_CRITSECT | VMCPU_FF_HM_UPDATE_CR3 | VMCPU_FF_IEM | VMCPU_FF_IOM ) + +/** Normal priority VM post-execution actions. */ +#define VM_FF_NORMAL_PRIORITY_POST_MASK ( VM_FF_CHECK_VM_STATE | VM_FF_DBGF | VM_FF_RESET \ + | VM_FF_PGM_NO_MEMORY | VM_FF_EMT_RENDEZVOUS) +/** Normal priority VMCPU post-execution actions. */ +#define VMCPU_FF_NORMAL_PRIORITY_POST_MASK ( VMCPU_FF_DBGF ) + +/** Normal priority VM actions. */ +#define VM_FF_NORMAL_PRIORITY_MASK ( VM_FF_REQUEST | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA | VM_FF_EMT_RENDEZVOUS) +/** Normal priority VMCPU actions. */ +#define VMCPU_FF_NORMAL_PRIORITY_MASK ( VMCPU_FF_REQUEST ) + +/** Flags to clear before resuming guest execution. */ +#define VMCPU_FF_RESUME_GUEST_MASK ( VMCPU_FF_TO_R3 ) + + +/** VM flags that cause the REP[|NE|E] STRINS loops to yield immediately. */ +#define VM_FF_HIGH_PRIORITY_POST_REPSTR_MASK ( VM_FF_TM_VIRTUAL_SYNC | VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY \ + | VM_FF_EMT_RENDEZVOUS | VM_FF_PGM_POOL_FLUSH_PENDING | VM_FF_RESET) +/** VM flags that cause the REP[|NE|E] STRINS loops to yield. */ +#define VM_FF_YIELD_REPSTR_MASK ( VM_FF_HIGH_PRIORITY_POST_REPSTR_MASK \ + | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA | VM_FF_DBGF | VM_FF_DEBUG_SUSPEND ) +/** VMCPU flags that cause the REP[|NE|E] STRINS loops to yield immediately. */ +#ifdef IN_RING3 +# define VMCPU_FF_HIGH_PRIORITY_POST_REPSTR_MASK ( VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_DBGF \ + | VMCPU_FF_VMX_MTF ) +#else +# define VMCPU_FF_HIGH_PRIORITY_POST_REPSTR_MASK ( VMCPU_FF_TO_R3 | VMCPU_FF_IEM | VMCPU_FF_IOM | VMCPU_FF_PGM_SYNC_CR3 \ + | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_DBGF | VMCPU_FF_VMX_MTF ) +#endif +/** VMCPU flags that cause the REP[|NE|E] STRINS loops to yield, interrupts + * enabled. */ +#define VMCPU_FF_YIELD_REPSTR_MASK ( VMCPU_FF_HIGH_PRIORITY_POST_REPSTR_MASK \ + | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_UPDATE_APIC | VMCPU_FF_INTERRUPT_PIC \ + | VMCPU_FF_INTERRUPT_NMI | VMCPU_FF_INTERRUPT_SMI | VMCPU_FF_PDM_CRITSECT \ + | VMCPU_FF_TIMER | VMCPU_FF_REQUEST \ + | VMCPU_FF_INTERRUPT_NESTED_GUEST ) +/** VMCPU flags that cause the REP[|NE|E] STRINS loops to yield, interrupts + * disabled. */ +#define VMCPU_FF_YIELD_REPSTR_NOINT_MASK ( VMCPU_FF_YIELD_REPSTR_MASK \ + & ~( VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_UPDATE_APIC | VMCPU_FF_INTERRUPT_PIC \ + | VMCPU_FF_INTERRUPT_NESTED_GUEST) ) + +/** VM Flags that cause the HM loops to go back to ring-3. */ +#define VM_FF_HM_TO_R3_MASK ( VM_FF_TM_VIRTUAL_SYNC | VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY \ + | VM_FF_PDM_QUEUES | VM_FF_EMT_RENDEZVOUS) +/** VMCPU Flags that cause the HM loops to go back to ring-3. */ +#define VMCPU_FF_HM_TO_R3_MASK ( VMCPU_FF_TO_R3 | VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT \ + | VMCPU_FF_IEM | VMCPU_FF_IOM) + +/** High priority ring-0 VM pre HM-mode execution mask. */ +#define VM_FF_HP_R0_PRE_HM_MASK (VM_FF_HM_TO_R3_MASK | VM_FF_REQUEST | VM_FF_PGM_POOL_FLUSH_PENDING | VM_FF_PDM_DMA) +/** High priority ring-0 VMCPU pre HM-mode execution mask. */ +#define VMCPU_FF_HP_R0_PRE_HM_MASK ( VMCPU_FF_HM_TO_R3_MASK | VMCPU_FF_PGM_SYNC_CR3 \ + | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_REQUEST \ + | VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER) +/** High priority ring-0 VM pre HM-mode execution mask, single stepping. */ +#define VM_FF_HP_R0_PRE_HM_STEP_MASK (VM_FF_HP_R0_PRE_HM_MASK & ~( VM_FF_TM_VIRTUAL_SYNC | VM_FF_PDM_QUEUES \ + | VM_FF_EMT_RENDEZVOUS | VM_FF_REQUEST \ + | VM_FF_PDM_DMA) ) +/** High priority ring-0 VMCPU pre HM-mode execution mask, single stepping. */ +#define VMCPU_FF_HP_R0_PRE_HM_STEP_MASK (VMCPU_FF_HP_R0_PRE_HM_MASK & ~( VMCPU_FF_TO_R3 | VMCPU_FF_TIMER \ + | VMCPU_FF_PDM_CRITSECT | VMCPU_FF_REQUEST) ) + +/** All the VMX nested-guest flags. */ +#define VMCPU_FF_VMX_ALL_MASK ( VMCPU_FF_VMX_PREEMPT_TIMER | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_APIC_WRITE \ + | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW ) + +/** All the forced VM flags. */ +#define VM_FF_ALL_MASK (UINT32_MAX) +/** All the forced VMCPU flags. */ +#define VMCPU_FF_ALL_MASK (UINT32_MAX) + +/** All the forced VM flags except those related to raw-mode and hardware + * assisted execution. */ +#define VM_FF_ALL_REM_MASK (~(VM_FF_HIGH_PRIORITY_PRE_RAW_MASK) | VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY) +/** All the forced VMCPU flags except those related to raw-mode and hardware + * assisted execution. */ +#define VMCPU_FF_ALL_REM_MASK (~(VMCPU_FF_HIGH_PRIORITY_PRE_RAW_MASK | VMCPU_FF_PDM_CRITSECT | VMCPU_FF_TLB_FLUSH)) +/** @} */ + +/** @def VM_FF_SET + * Sets a single force action flag. + * + * @param pVM The cross context VM structure. + * @param fFlag The flag to set. + */ +#define VM_FF_SET(pVM, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_32(fFlag##_BIT)); \ + ASMAtomicOrU32(&(pVM)->fGlobalForcedActions, (fFlag)); \ + } while (0) + +/** @def VMCPU_FF_SET + * Sets a single force action flag for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlag The flag to set. + * @sa VMCPU_FF_SET_MASK + */ +#ifdef VMCPU_WITH_64_BIT_FFS +# define VMCPU_FF_SET(pVCpu, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_64(fFlag##_BIT)); \ + ASMAtomicBitSet(&(pVCpu)->fLocalForcedActions, fFlag##_BIT); \ + } while (0) +#else +# define VMCPU_FF_SET(pVCpu, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_32(fFlag##_BIT)); \ + ASMAtomicOrU32(&(pVCpu)->fLocalForcedActions, (fFlag)); \ + } while (0) +#endif + +/** @def VMCPU_FF_SET_MASK + * Sets a two or more force action flag for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlags The flags to set. + * @sa VMCPU_FF_SET + */ +#ifdef VMCPU_WITH_64_BIT_FFS +# if ARCH_BITS > 32 +# define VMCPU_FF_SET_MASK(pVCpu, fFlags) \ + do { ASMAtomicOrU64(&pVCpu->fLocalForcedActions, (fFlags)); } while (0) +# else +# define VMCPU_FF_SET_MASK(pVCpu, fFlags) do { \ + if (!((fFlags) >> 32)) ASMAtomicOrU32((uint32_t volatile *)&pVCpu->fLocalForcedActions, (uint32_t)(fFlags)); \ + else ASMAtomicOrU64(&pVCpu->fLocalForcedActions, (fFlags)); \ + } while (0) +# endif +#else +# define VMCPU_FF_SET_MASK(pVCpu, fFlags) \ + do { ASMAtomicOrU32(&pVCpu->fLocalForcedActions, (fFlags)); } while (0) +#endif + +/** @def VM_FF_CLEAR + * Clears a single force action flag. + * + * @param pVM The cross context VM structure. + * @param fFlag The flag to clear. + */ +#define VM_FF_CLEAR(pVM, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_32(fFlag##_BIT)); \ + ASMAtomicAndU32(&(pVM)->fGlobalForcedActions, ~(fFlag)); \ + } while (0) + +/** @def VMCPU_FF_CLEAR + * Clears a single force action flag for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlag The flag to clear. + */ +#ifdef VMCPU_WITH_64_BIT_FFS +# define VMCPU_FF_CLEAR(pVCpu, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_64(fFlag##_BIT)); \ + ASMAtomicBitClear(&(pVCpu)->fLocalForcedActions, fFlag##_BIT); \ + } while (0) +#else +# define VMCPU_FF_CLEAR(pVCpu, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_32(fFlag##_BIT)); \ + ASMAtomicAndU32(&(pVCpu)->fLocalForcedActions, ~(fFlag)); \ + } while (0) +#endif + +/** @def VMCPU_FF_CLEAR_MASK + * Clears two or more force action flags for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlags The flags to clear. + */ +#ifdef VMCPU_WITH_64_BIT_FFS +# if ARCH_BITS > 32 +# define VMCPU_FF_CLEAR_MASK(pVCpu, fFlags) \ + do { ASMAtomicAndU64(&(pVCpu)->fLocalForcedActions, ~(fFlags)); } while (0) +# else +# define VMCPU_FF_CLEAR_MASK(pVCpu, fFlags) do { \ + if (!((fFlags) >> 32)) ASMAtomicAndU32((uint32_t volatile *)&(pVCpu)->fLocalForcedActions, ~(uint32_t)(fFlags)); \ + else ASMAtomicAndU64(&(pVCpu)->fLocalForcedActions, ~(fFlags)); \ + } while (0) +# endif +#else +# define VMCPU_FF_CLEAR_MASK(pVCpu, fFlags) \ + do { ASMAtomicAndU32(&(pVCpu)->fLocalForcedActions, ~(fFlags)); } while (0) +#endif + +/** @def VM_FF_IS_SET + * Checks if single a force action flag is set. + * + * @param pVM The cross context VM structure. + * @param fFlag The flag to check. + * @sa VM_FF_IS_ANY_SET + */ +#if !defined(VBOX_STRICT) || !defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define VM_FF_IS_SET(pVM, fFlag) RT_BOOL((pVM)->fGlobalForcedActions & (fFlag)) +#else +# define VM_FF_IS_SET(pVM, fFlag) \ + ([](PVM a_pVM) -> bool \ + { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_32(fFlag##_BIT)); \ + return RT_BOOL(a_pVM->fGlobalForcedActions & (fFlag)); \ + }(pVM)) +#endif + +/** @def VMCPU_FF_IS_SET + * Checks if a single force action flag is set for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlag The flag to check. + * @sa VMCPU_FF_IS_ANY_SET + */ +#if !defined(VBOX_STRICT) || !defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define VMCPU_FF_IS_SET(pVCpu, fFlag) RT_BOOL((pVCpu)->fLocalForcedActions & (fFlag)) +#else +# define VMCPU_FF_IS_SET(pVCpu, fFlag) \ + ([](PCVMCPU a_pVCpu) -> bool \ + { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_64(fFlag##_BIT)); \ + return RT_BOOL(a_pVCpu->fLocalForcedActions & (fFlag)); \ + }(pVCpu)) +#endif + +/** @def VM_FF_IS_ANY_SET + * Checks if one or more force action in the specified set is pending. + * + * @param pVM The cross context VM structure. + * @param fFlags The flags to check for. + * @sa VM_FF_IS_SET + */ +#define VM_FF_IS_ANY_SET(pVM, fFlags) RT_BOOL((pVM)->fGlobalForcedActions & (fFlags)) + +/** @def VMCPU_FF_IS_ANY_SET + * Checks if two or more force action flags in the specified set is set for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlags The flags to check for. + * @sa VMCPU_FF_IS_SET + */ +#define VMCPU_FF_IS_ANY_SET(pVCpu, fFlags) RT_BOOL((pVCpu)->fLocalForcedActions & (fFlags)) + +/** @def VM_FF_TEST_AND_CLEAR + * Checks if one (!) force action in the specified set is pending and clears it atomically + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * @param pVM The cross context VM structure. + * @param fFlag Flag constant to check and clear (_BIT is appended). + */ +#define VM_FF_TEST_AND_CLEAR(pVM, fFlag) (ASMAtomicBitTestAndClear(&(pVM)->fGlobalForcedActions, fFlag##_BIT)) + +/** @def VMCPU_FF_TEST_AND_CLEAR + * Checks if one (!) force action in the specified set is pending and clears it atomically + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * @param pVCpu The cross context virtual CPU structure. + * @param fFlag Flag constant to check and clear (_BIT is appended). + */ +#define VMCPU_FF_TEST_AND_CLEAR(pVCpu, fFlag) (ASMAtomicBitTestAndClear(&(pVCpu)->fLocalForcedActions, fFlag##_BIT)) + +/** @def VM_FF_IS_PENDING_EXCEPT + * Checks if one or more force action in the specified set is pending while one + * or more other ones are not. + * + * @param pVM The cross context VM structure. + * @param fFlags The flags to check for. + * @param fExcpt The flags that should not be set. + */ +#define VM_FF_IS_PENDING_EXCEPT(pVM, fFlags, fExcpt) \ + ( ((pVM)->fGlobalForcedActions & (fFlags)) && !((pVM)->fGlobalForcedActions & (fExcpt)) ) + +/** @def VM_IS_EMT + * Checks if the current thread is the emulation thread (EMT). + * + * @remark The ring-0 variation will need attention if we expand the ring-0 + * code to let threads other than EMT mess around with the VM. + */ +#ifdef IN_RC +# define VM_IS_EMT(pVM) true +#else +# define VM_IS_EMT(pVM) (VMMGetCpu(pVM) != NULL) +#endif + +/** @def VMCPU_IS_EMT + * Checks if the current thread is the emulation thread (EMT) for the specified + * virtual CPU. + */ +#ifdef IN_RC +# define VMCPU_IS_EMT(pVCpu) true +#else +# define VMCPU_IS_EMT(pVCpu) ((pVCpu) && ((pVCpu) == VMMGetCpu((pVCpu)->CTX_SUFF(pVM)))) +#endif + +/** @def VM_ASSERT_EMT + * Asserts that the current thread IS the emulation thread (EMT). + */ +#ifdef IN_RC +# define VM_ASSERT_EMT(pVM) Assert(VM_IS_EMT(pVM)) +#elif defined(IN_RING0) +# define VM_ASSERT_EMT(pVM) Assert(VM_IS_EMT(pVM)) +#else +# define VM_ASSERT_EMT(pVM) \ + AssertMsg(VM_IS_EMT(pVM), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd\n", RTThreadNativeSelf(), VMR3GetVMCPUNativeThread(pVM))) +#endif + +/** @def VMCPU_ASSERT_EMT + * Asserts that the current thread IS the emulation thread (EMT) of the + * specified virtual CPU. + */ +#ifdef IN_RC +# define VMCPU_ASSERT_EMT(pVCpu) Assert(VMCPU_IS_EMT(pVCpu)) +#elif defined(IN_RING0) +# define VMCPU_ASSERT_EMT(pVCpu) AssertMsg(VMCPU_IS_EMT(pVCpu), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd idCpu=%u\n", \ + RTThreadNativeSelf(), (pVCpu) ? (pVCpu)->hNativeThreadR0 : 0, \ + (pVCpu) ? (pVCpu)->idCpu : 0)) +#else +# define VMCPU_ASSERT_EMT(pVCpu) AssertMsg(VMCPU_IS_EMT(pVCpu), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd idCpu=%#x\n", \ + RTThreadNativeSelf(), (pVCpu)->hNativeThread, (pVCpu)->idCpu)) +#endif + +/** @def VM_ASSERT_EMT_RETURN + * Asserts that the current thread IS the emulation thread (EMT) and returns if it isn't. + */ +#ifdef IN_RC +# define VM_ASSERT_EMT_RETURN(pVM, rc) AssertReturn(VM_IS_EMT(pVM), (rc)) +#elif defined(IN_RING0) +# define VM_ASSERT_EMT_RETURN(pVM, rc) AssertReturn(VM_IS_EMT(pVM), (rc)) +#else +# define VM_ASSERT_EMT_RETURN(pVM, rc) \ + AssertMsgReturn(VM_IS_EMT(pVM), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd\n", RTThreadNativeSelf(), VMR3GetVMCPUNativeThread(pVM)), \ + (rc)) +#endif + +/** @def VMCPU_ASSERT_EMT_RETURN + * Asserts that the current thread IS the emulation thread (EMT) and returns if it isn't. + */ +#ifdef IN_RC +# define VMCPU_ASSERT_EMT_RETURN(pVCpu, rc) AssertReturn(VMCPU_IS_EMT(pVCpu), (rc)) +#elif defined(IN_RING0) +# define VMCPU_ASSERT_EMT_RETURN(pVCpu, rc) AssertReturn(VMCPU_IS_EMT(pVCpu), (rc)) +#else +# define VMCPU_ASSERT_EMT_RETURN(pVCpu, rc) \ + AssertMsgReturn(VMCPU_IS_EMT(pVCpu), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd idCpu=%#x\n", \ + RTThreadNativeSelf(), (pVCpu)->hNativeThread, (pVCpu)->idCpu), \ + (rc)) +#endif + +/** @def VMCPU_ASSERT_EMT_OR_GURU + * Asserts that the current thread IS the emulation thread (EMT) of the + * specified virtual CPU. + */ +#if defined(IN_RC) || defined(IN_RING0) +# define VMCPU_ASSERT_EMT_OR_GURU(pVCpu) Assert( VMCPU_IS_EMT(pVCpu) \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_GURU_MEDITATION \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_GURU_MEDITATION_LS ) +#else +# define VMCPU_ASSERT_EMT_OR_GURU(pVCpu) \ + AssertMsg( VMCPU_IS_EMT(pVCpu) \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_GURU_MEDITATION \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_GURU_MEDITATION_LS, \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd idCpu=%#x\n", \ + RTThreadNativeSelf(), (pVCpu)->hNativeThread, (pVCpu)->idCpu)) +#endif + +/** @def VMCPU_ASSERT_EMT_OR_NOT_RUNNING + * Asserts that the current thread IS the emulation thread (EMT) of the + * specified virtual CPU or the VM is not running. + */ +#if defined(IN_RC) || defined(IN_RING0) +# define VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu) \ + Assert( VMCPU_IS_EMT(pVCpu) \ + || !VM_IS_RUNNING_FOR_ASSERTIONS_ONLY((pVCpu)->CTX_SUFF(pVM)) ) +#else +# define VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu) \ + AssertMsg( VMCPU_IS_EMT(pVCpu) \ + || !VM_IS_RUNNING_FOR_ASSERTIONS_ONLY((pVCpu)->CTX_SUFF(pVM)), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd idCpu=%#x\n", \ + RTThreadNativeSelf(), (pVCpu)->hNativeThread, (pVCpu)->idCpu)) +#endif + +/** @def VMSTATE_IS_RUNNING + * Checks if the given state indicates a running VM. + */ +#define VMSTATE_IS_RUNNING(a_enmVMState) \ + ( (enmVMState) == VMSTATE_RUNNING \ + || (enmVMState) == VMSTATE_RUNNING_LS ) + +/** @def VM_IS_RUNNING_FOR_ASSERTIONS_ONLY + * Checks if the VM is running. + * @note This is only for pure debug assertions. No AssertReturn or similar! + * @sa VMSTATE_IS_RUNNING + */ +#define VM_IS_RUNNING_FOR_ASSERTIONS_ONLY(pVM) \ + ( (pVM)->enmVMState == VMSTATE_RUNNING \ + || (pVM)->enmVMState == VMSTATE_RUNNING_LS ) + +/** @def VM_ASSERT_IS_NOT_RUNNING + * Asserts that the VM is not running. + */ +#if defined(IN_RC) || defined(IN_RING0) +#define VM_ASSERT_IS_NOT_RUNNING(pVM) Assert(!VM_IS_RUNNING_FOR_ASSERTIONS_ONLY(pVM)) +#else +#define VM_ASSERT_IS_NOT_RUNNING(pVM) AssertMsg(!VM_IS_RUNNING_FOR_ASSERTIONS_ONLY(pVM), \ + ("VM is running. enmVMState=%d\n", (pVM)->enmVMState)) +#endif + +/** @def VM_ASSERT_EMT0 + * Asserts that the current thread IS emulation thread \#0 (EMT0). + */ +#ifdef IN_RING3 +# define VM_ASSERT_EMT0(a_pVM) VMCPU_ASSERT_EMT((a_pVM)->apCpusR3[0]) +#else +# define VM_ASSERT_EMT0(a_pVM) VMCPU_ASSERT_EMT(&(a_pVM)->aCpus[0]) +#endif + +/** @def VM_ASSERT_EMT0_RETURN + * Asserts that the current thread IS emulation thread \#0 (EMT0) and returns if + * it isn't. + */ +#ifdef IN_RING3 +# define VM_ASSERT_EMT0_RETURN(pVM, rc) VMCPU_ASSERT_EMT_RETURN((pVM)->apCpusR3[0], (rc)) +#else +# define VM_ASSERT_EMT0_RETURN(pVM, rc) VMCPU_ASSERT_EMT_RETURN(&(pVM)->aCpus[0], (rc)) +#endif + + +/** + * Asserts that the current thread is NOT the emulation thread. + */ +#define VM_ASSERT_OTHER_THREAD(pVM) \ + AssertMsg(!VM_IS_EMT(pVM), ("Not other thread!!\n")) + + +/** @def VM_ASSERT_STATE + * Asserts a certain VM state. + */ +#define VM_ASSERT_STATE(pVM, _enmState) \ + AssertMsg((pVM)->enmVMState == (_enmState), \ + ("state %s, expected %s\n", VMGetStateName((pVM)->enmVMState), VMGetStateName(_enmState))) + +/** @def VM_ASSERT_STATE_RETURN + * Asserts a certain VM state and returns if it doesn't match. + */ +#define VM_ASSERT_STATE_RETURN(pVM, _enmState, rc) \ + AssertMsgReturn((pVM)->enmVMState == (_enmState), \ + ("state %s, expected %s\n", VMGetStateName((pVM)->enmVMState), VMGetStateName(_enmState)), \ + (rc)) + +/** @def VM_IS_VALID_EXT + * Asserts a the VM handle is valid for external access, i.e. not being destroy + * or terminated. */ +#define VM_IS_VALID_EXT(pVM) \ + ( RT_VALID_ALIGNED_PTR(pVM, PAGE_SIZE) \ + && ( (unsigned)(pVM)->enmVMState < (unsigned)VMSTATE_DESTROYING \ + || ( (unsigned)(pVM)->enmVMState == (unsigned)VMSTATE_DESTROYING \ + && VM_IS_EMT(pVM))) ) + +/** @def VM_ASSERT_VALID_EXT_RETURN + * Asserts a the VM handle is valid for external access, i.e. not being + * destroy or terminated. + */ +#define VM_ASSERT_VALID_EXT_RETURN(pVM, rc) \ + AssertMsgReturn(VM_IS_VALID_EXT(pVM), \ + ("pVM=%p state %s\n", (pVM), RT_VALID_ALIGNED_PTR(pVM, PAGE_SIZE) \ + ? VMGetStateName(pVM->enmVMState) : ""), \ + (rc)) + +/** @def VMCPU_ASSERT_VALID_EXT_RETURN + * Asserts a the VMCPU handle is valid for external access, i.e. not being + * destroy or terminated. + */ +#define VMCPU_ASSERT_VALID_EXT_RETURN(pVCpu, rc) \ + AssertMsgReturn( RT_VALID_ALIGNED_PTR(pVCpu, 64) \ + && RT_VALID_ALIGNED_PTR((pVCpu)->CTX_SUFF(pVM), PAGE_SIZE) \ + && (unsigned)(pVCpu)->CTX_SUFF(pVM)->enmVMState < (unsigned)VMSTATE_DESTROYING, \ + ("pVCpu=%p pVM=%p state %s\n", (pVCpu), RT_VALID_ALIGNED_PTR(pVCpu, 64) ? (pVCpu)->CTX_SUFF(pVM) : NULL, \ + RT_VALID_ALIGNED_PTR(pVCpu, 64) && RT_VALID_ALIGNED_PTR((pVCpu)->CTX_SUFF(pVM), PAGE_SIZE) \ + ? VMGetStateName((pVCpu)->pVMR3->enmVMState) : ""), \ + (rc)) + +#endif /* !VBOX_FOR_DTRACE_LIB */ + + +/** + * Helper that HM and NEM uses for safely modifying VM::bMainExecutionEngine. + * + * ONLY HM and NEM MAY USE THIS! + * + * @param a_pVM The cross context VM structure. + * @param a_bValue The new value. + * @internal + */ +#define VM_SET_MAIN_EXECUTION_ENGINE(a_pVM, a_bValue) \ + do { \ + *const_cast<uint8_t *>(&(a_pVM)->bMainExecutionEngine) = (a_bValue); \ + ASMCompilerBarrier(); /* just to be on the safe side */ \ + } while (0) + +/** + * Checks whether iem-executes-all-mode is used. + * + * @retval true if IEM is used. + * @retval false if not. + * + * @param a_pVM The cross context VM structure. + * @sa VM_IS_HM_OR_NEM_ENABLED, VM_IS_HM_ENABLED, VM_IS_NEM_ENABLED. + * @internal + */ +#define VM_IS_EXEC_ENGINE_IEM(a_pVM) ((a_pVM)->bMainExecutionEngine == VM_EXEC_ENGINE_IEM) + +/** + * Checks whether HM (VT-x/AMD-V) or NEM is being used by this VM. + * + * @retval true if either is used. + * @retval false if software virtualization (raw-mode) is used. + * + * @param a_pVM The cross context VM structure. + * @sa VM_IS_EXEC_ENGINE_IEM, VM_IS_HM_ENABLED, VM_IS_NEM_ENABLED. + * @internal + */ +#define VM_IS_HM_OR_NEM_ENABLED(a_pVM) ((a_pVM)->bMainExecutionEngine != VM_EXEC_ENGINE_IEM) + +/** + * Checks whether HM is being used by this VM. + * + * @retval true if HM (VT-x/AMD-v) is used. + * @retval false if not. + * + * @param a_pVM The cross context VM structure. + * @sa VM_IS_NEM_ENABLED, VM_IS_EXEC_ENGINE_IEM, VM_IS_HM_OR_NEM_ENABLED. + * @internal + */ +#define VM_IS_HM_ENABLED(a_pVM) ((a_pVM)->bMainExecutionEngine == VM_EXEC_ENGINE_HW_VIRT) + +/** + * Checks whether NEM is being used by this VM. + * + * @retval true if a native hypervisor API is used. + * @retval false if not. + * + * @param a_pVM The cross context VM structure. + * @sa VM_IS_HM_ENABLED, VM_IS_EXEC_ENGINE_IEM, VM_IS_HM_OR_NEM_ENABLED. + * @internal + */ +#define VM_IS_NEM_ENABLED(a_pVM) ((a_pVM)->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API) + + +/** + * The cross context VM structure. + * + * It contains all the VM data which have to be available in all contexts. + * Even if it contains all the data the idea is to use APIs not to modify all + * the members all around the place. Therefore we make use of unions to hide + * everything which isn't local to the current source module. This means we'll + * have to pay a little bit of attention when adding new members to structures + * in the unions and make sure to keep the padding sizes up to date. + * + * Run 'kmk run-struct-tests' (from src/VBox/VMM if you like) after updating! + */ +typedef struct VM +{ + /** The state of the VM. + * This field is read only to everyone except the VM and EM. */ + VMSTATE volatile enmVMState; + /** Forced action flags. + * See the VM_FF_* \#defines. Updated atomically. + */ + volatile uint32_t fGlobalForcedActions; + /** Pointer to the array of page descriptors for the VM structure allocation. */ + R3PTRTYPE(PSUPPAGE) paVMPagesR3; + /** Session handle. For use when calling SUPR0 APIs. */ +#ifdef IN_RING0 + PSUPDRVSESSION pSessionUnsafe; +#else + PSUPDRVSESSION pSession; +#endif + /** Pointer to the ring-3 VM structure. */ + PUVM pUVM; + /** Ring-3 Host Context VM Pointer. */ +#ifdef IN_RING0 + R3PTRTYPE(struct VM *) pVMR3Unsafe; +#else + R3PTRTYPE(struct VM *) pVMR3; +#endif + /** Ring-0 Host Context VM pointer for making ring-0 calls. */ + R0PTRTYPE(struct VM *) pVMR0ForCall; + /** Raw-mode Context VM Pointer. */ + uint32_t pVMRC; + /** Padding for new raw-mode (long mode). */ + uint32_t pVMRCPadding; + + /** The GVM VM handle. Only the GVM should modify this field. */ +#ifdef IN_RING0 + uint32_t hSelfUnsafe; +#else + uint32_t hSelf; +#endif + /** Number of virtual CPUs. */ +#ifdef IN_RING0 + uint32_t cCpusUnsafe; +#else + uint32_t cCpus; +#endif + /** CPU excution cap (1-100) */ + uint32_t uCpuExecutionCap; + + /** Size of the VM structure. */ + uint32_t cbSelf; + /** Size of the VMCPU structure. */ + uint32_t cbVCpu; + /** Structure version number (TBD). */ + uint32_t uStructVersion; + + /** @name Various items that are frequently accessed. + * @{ */ + /** The main execution engine, VM_EXEC_ENGINE_XXX. + * This is set early during vmR3InitRing3 by HM or NEM. */ + uint8_t const bMainExecutionEngine; + + /** Hardware VM support is available and enabled. + * Determined very early during init. + * This is placed here for performance reasons. + * @todo obsoleted by bMainExecutionEngine, eliminate. */ + bool fHMEnabled; + /** @} */ + + /** Alignment padding. */ + uint8_t uPadding1[6]; + + /** @name Debugging + * @{ */ + /** Ring-3 Host Context VM Pointer. */ + R3PTRTYPE(RTTRACEBUF) hTraceBufR3; + /** Ring-0 Host Context VM Pointer. */ + R0PTRTYPE(RTTRACEBUF) hTraceBufR0; + /** @} */ + + /** Max EMT hash lookup collisions (in GVMM). */ + uint8_t cMaxEmtHashCollisions; + + /** Padding - the unions must be aligned on a 64 bytes boundary. */ + uint8_t abAlignment3[HC_ARCH_BITS == 64 ? 23 : 51]; + + /** CPUM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_CPUMInternal_h + struct CPUM s; +#endif +#ifdef VBOX_INCLUDED_vmm_cpum_h + /** Read only info exposed about the host and guest CPUs. */ + struct + { + /** Padding for hidden fields. */ + uint8_t abHidden0[64 + 48]; + /** Guest CPU feature information. */ + CPUMFEATURES GuestFeatures; + } const ro; +#endif + /** @todo this is rather bloated because of static MSR range allocation. + * Probably a good idea to move it to a separate R0 allocation... */ + uint8_t padding[8832 + 128*8192 + 0x1d00]; /* multiple of 64 */ + } cpum; + + /** PGM part. + * @note 16384 aligned for zero and mmio page storage. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_PGMInternal_h + struct PGM s; +#endif + uint8_t padding[53888]; /* multiple of 64 */ + } pgm; + + /** VMM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_VMMInternal_h + struct VMM s; +#endif + uint8_t padding[1600]; /* multiple of 64 */ + } vmm; + + /** HM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_HMInternal_h + struct HM s; +#endif + uint8_t padding[5504]; /* multiple of 64 */ + } hm; + + /** TRPM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_TRPMInternal_h + struct TRPM s; +#endif + uint8_t padding[2048]; /* multiple of 64 */ + } trpm; + + /** SELM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_SELMInternal_h + struct SELM s; +#endif + uint8_t padding[768]; /* multiple of 64 */ + } selm; + + /** MM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_MMInternal_h + struct MM s; +#endif + uint8_t padding[192]; /* multiple of 64 */ + } mm; + + /** PDM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_PDMInternal_h + struct PDM s; +#endif + uint8_t padding[22400]; /* multiple of 64 */ + } pdm; + + /** IOM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_IOMInternal_h + struct IOM s; +#endif + uint8_t padding[1152]; /* multiple of 64 */ + } iom; + + /** EM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_EMInternal_h + struct EM s; +#endif + uint8_t padding[256]; /* multiple of 64 */ + } em; + + /** NEM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_NEMInternal_h + struct NEM s; +#endif + uint8_t padding[4608]; /* multiple of 64 */ + } nem; + + /** TM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_TMInternal_h + struct TM s; +#endif + uint8_t padding[10112]; /* multiple of 64 */ + } tm; + + /** DBGF part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_DBGFInternal_h + struct DBGF s; +#endif +#ifdef VBOX_INCLUDED_vmm_dbgf_h + /** Read only info exposed about interrupt breakpoints and selected events. */ + struct + { + /** Bitmap of enabled hardware interrupt breakpoints. */ + uint32_t bmHardIntBreakpoints[256 / 32]; + /** Bitmap of enabled software interrupt breakpoints. */ + uint32_t bmSoftIntBreakpoints[256 / 32]; + /** Bitmap of selected events. + * This includes non-selectable events too for simplicity, we maintain the + * state for some of these, as it may come in handy. */ + uint64_t bmSelectedEvents[(DBGFEVENT_END + 63) / 64]; + /** Enabled hardware interrupt breakpoints. */ + uint32_t cHardIntBreakpoints; + /** Enabled software interrupt breakpoints. */ + uint32_t cSoftIntBreakpoints; + /** The number of selected events. */ + uint32_t cSelectedEvents; + /** The number of enabled hardware breakpoints. */ + uint8_t cEnabledHwBreakpoints; + /** The number of enabled hardware I/O breakpoints. */ + uint8_t cEnabledHwIoBreakpoints; + uint8_t au8Alignment1[2]; /**< Alignment padding. */ + /** The number of enabled INT3 breakpoints. */ + uint32_t volatile cEnabledInt3Breakpoints; + } const ro; +#endif + uint8_t padding[2432]; /* multiple of 64 */ + } dbgf; + + /** SSM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_SSMInternal_h + struct SSM s; +#endif + uint8_t padding[128]; /* multiple of 64 */ + } ssm; + + union + { +#ifdef VMM_INCLUDED_SRC_include_GIMInternal_h + struct GIM s; +#endif + uint8_t padding[448]; /* multiple of 64 */ + } gim; + + union + { +#ifdef VMM_INCLUDED_SRC_include_APICInternal_h + struct APIC s; +#endif + uint8_t padding[128]; /* multiple of 8 */ + } apic; + + /* ---- begin small stuff ---- */ + + /** VM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_VMInternal_h + struct VMINT s; +#endif + uint8_t padding[32]; /* multiple of 8 */ + } vm; + + /** CFGM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_CFGMInternal_h + struct CFGM s; +#endif + uint8_t padding[8]; /* multiple of 8 */ + } cfgm; + + /** IEM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_IEMInternal_h + struct IEM s; +#endif + uint8_t padding[16]; /* multiple of 8 */ + } iem; + + /** Statistics for ring-0 only components. */ + struct + { + /** GMMR0 stats. */ + struct + { + /** Chunk TLB hits. */ + uint64_t cChunkTlbHits; + /** Chunk TLB misses. */ + uint64_t cChunkTlbMisses; + } gmm; + uint64_t au64Padding[6]; /* probably more comming here... */ + } R0Stats; + + union + { +#ifdef VMM_INCLUDED_SRC_include_GCMInternal_h + struct GCM s; +#endif + uint8_t padding[32]; /* multiple of 8 */ + } gcm; + + /** Padding for aligning the structure size on a page boundrary. */ + uint8_t abAlignment2[8872 - sizeof(PVMCPUR3) * VMM_MAX_CPU_COUNT]; + + /* ---- end small stuff ---- */ + + /** Array of VMCPU ring-3 pointers. */ + PVMCPUR3 apCpusR3[VMM_MAX_CPU_COUNT]; + + /* This point is aligned on a 16384 boundrary (for arm64 purposes). */ +} VM; +#ifndef VBOX_FOR_DTRACE_LIB +//AssertCompileSizeAlignment(VM, 16384); +#endif + + +#ifdef IN_RC +RT_C_DECLS_BEGIN + +/** The VM structure. + * This is imported from the VMMRCBuiltin module, i.e. it's a one of those magic + * globals which we should avoid using. + */ +extern DECLIMPORT(VM) g_VM; + +/** The VMCPU structure for virtual CPU \#0. + * This is imported from the VMMRCBuiltin module, i.e. it's a one of those magic + * globals which we should avoid using. + */ +extern DECLIMPORT(VMCPU) g_VCpu0; + +RT_C_DECLS_END +#endif + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_vm_h */ + diff --git a/include/VBox/vmm/vm.mac b/include/VBox/vmm/vm.mac new file mode 100644 index 00000000..2aa4b515 --- /dev/null +++ b/include/VBox/vmm/vm.mac @@ -0,0 +1,187 @@ +;; @file +; VM - The Virtual Machine. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_vmm_vm_mac +%define ___VBox_vmm_vm_mac + +%include "VBox/vmm/stam.mac" +%include "VBox/param.mac" + +;/** This action forces the VM to service check and pending interrups on the APIC. */ +%define VMCPU_FF_INTERRUPT_APIC (1 << 0) +;/** This action forces the VM to service check and pending interrups on the PIC. */ +%define VMCPU_FF_INTERRUPT_PIC (1 << 1) +;/** This action forces the VM to schedule and run pending timer (TM). */ +%define VMCPU_FF_TIMER (1 << 2) +;/** This action forces the VM to service pending requests from other +; * thread or requests which must be executed in another context. */ +%define VMCPU_FF_REQUEST (1 << 9) + +;; +; This is part of the VMCPU structure. +struc VMCPU + .fLocalForcedActions resd 1 + alignb 8 + .enmState resd 1 + + alignb 64 + .iem resb 32832 + + alignb 64 + .pVMR3 RTR3PTR_RES 1 + .pVCpuR0ForVtg RTR0PTR_RES 1 + .pVMRC resq 1 + .pUVCpu RTR3PTR_RES 1 + .hNativeThread RTR3PTR_RES 1 + .hNativeThreadR0 RTR0PTR_RES 1 + .hThread RTR3PTR_RES 1 + .idCpu resd 1 + + alignb 64 + .hm resb 9984 + alignb 64 + .nem resb 4608 + alignb 64 + .trpm resb 128 + alignb 64 + .tm resb 5760 + alignb 64 + .vmm resb 9536 + alignb 64 + .pdm resb 256 + alignb 64 + .iom resb 512 + alignb 64 + .dbgf resb 512 + alignb 64 + .gim resb 512 + alignb 64 + .apic resb 3840 + + alignb 64 + .fTraceGroups resd 1 + .cEmtHashCollisions resb 1 + .abAdHoc resb 3 + alignb 8 + .aStatAdHoc resb STAMPROFILEADV_size * 8 + + alignb 4096 + .pgm resb 4096+28672 + alignb 4096 + .cpum resb 102400 +%define VMCPU.cpum.GstCtx VMCPU.cpum + alignb 4096 + .em resb 40960 + alignb 16384 +endstruc + +;; +; This is part of the VM structure. +struc VM + .enmVMState resd 1 + .fGlobalForcedActions resd 1 + .paVMPagesR3 RTR3PTR_RES 1 + .pSession RTR0PTR_RES 1 + .pUVM RTR3PTR_RES 1 + .pVMR3 RTR3PTR_RES 1 + .pVMR0ForCall RTR0PTR_RES 1 + .pVMRC resq 1 +%ifdef IN_RING0 + .hSelfUnsafe resd 1 + .cCpusUnsafe resd 1 +%else + .hSelf resd 1 + .cCpus resd 1 +%endif + .uCpuExecutionCap resd 1 + .cbSelf resd 1 + .cbVCpu resd 1 + .uStructVersion resd 1 + .bMainExecutionEngine resb 1 + .fHMEnabled resb 1 + + .uPadding1 resb 6 + + .hTraceBufR3 RTR3PTR_RES 1 + .hTraceBufR0 RTR0PTR_RES 1 + + alignb 64 + .cpum resb 8832 + 128*8192 + alignb 16384 + .pgm resb 53888 + alignb 64 + .vmm resb 1600 + alignb 64 + .hm resb 5504 + alignb 64 + .trpm resb 2048 + alignb 64 + .selm resb 768 + alignb 64 + .mm resb 192 + alignb 64 + .pdm resb 22400 + alignb 64 + .iom resb 1152 + alignb 64 + .em resb 256 + alignb 64 + .nem resb 4608 + alignb 64 + .tm resb 10112 + alignb 64 + .dbgf resb 2432 + alignb 64 + .ssm resb 128 + alignb 64 + .gim resb 448 + alignb 64 + .apic resb 128 + alignb 64 + .vm resb 32 + .cfgm resb 8 + .iem resb 16 + .R0Stats resb 64 + .gcm resb 32 + + times ((($ + VMM_MAX_CPU_COUNT * RTR0PTR_CB + 16383) & ~16383) - ($ + VMM_MAX_CPU_COUNT * RTR0PTR_CB)) resb 1 + .apCpusR3 RTR3PTR_RES VMM_MAX_CPU_COUNT + alignb 16384 + +endstruc + + +%endif + diff --git a/include/VBox/vmm/vmapi.h b/include/VBox/vmm/vmapi.h new file mode 100644 index 00000000..0a1cc09b --- /dev/null +++ b/include/VBox/vmm/vmapi.h @@ -0,0 +1,485 @@ +/** @file + * VM - The Virtual Machine, API. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vmapi_h +#define VBOX_INCLUDED_vmm_vmapi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/stam.h> +#include <VBox/vmm/cfgm.h> + +#include <iprt/stdarg.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_vm_apis VM All Contexts API + * @ingroup grp_vm + * @{ */ + +/** @name VM_EXEC_ENGINE_XXX - VM::bMainExecutionEngine values. + * @sa EMR3QueryMainExecutionEngine, VM_IS_RAW_MODE_ENABLED, VM_IS_HM_ENABLED, + * VM_IS_HM_OR_NEM_ENABLED, VM_IS_NEM_ENABLED, VM_SET_MAIN_EXECUTION_ENGINE + * @{ */ +/** Has not yet been set. */ +#define VM_EXEC_ENGINE_NOT_SET UINT8_C(0) +/** The interpreter (IEM). */ +#define VM_EXEC_ENGINE_IEM UINT8_C(1) +/** Hardware assisted virtualization thru HM. */ +#define VM_EXEC_ENGINE_HW_VIRT UINT8_C(2) +/** Hardware assisted virtualization thru native API (NEM). */ +#define VM_EXEC_ENGINE_NATIVE_API UINT8_C(3) +/** @} */ + + +/** + * VM error callback function. + * + * @param pUVM The user mode VM handle. Can be NULL if an error + * occurred before successfully creating a VM. + * @param pvUser The user argument. + * @param rc VBox status code. + * @param SRC_POS The source position arguments. See RT_SRC_POS and RT_SRC_POS_ARGS. + * @param pszFormat Error message format string. + * @param args Error message arguments. + */ +typedef DECLCALLBACKTYPE(void, FNVMATERROR,(PUVM pUVM, void *pvUser, int rc, RT_SRC_POS_DECL, + const char *pszFormat, va_list args)); +/** Pointer to a VM error callback. */ +typedef FNVMATERROR *PFNVMATERROR; + +#ifdef IN_RING3 +VMMDECL(int) VMSetError(PVMCC pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7); +VMMDECL(int) VMSetErrorV(PVMCC pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(6, 7); +#endif + +/** @def VM_SET_ERROR + * Macro for setting a simple VM error message. + * Don't use '%' in the message! + * + * @returns rc. Meaning you can do: + * @code + * return VM_SET_ERROR(pVM, VERR_OF_YOUR_CHOICE, "descriptive message"); + * @endcode + * @param pVM The cross context VM structure. + * @param rc VBox status code. + * @param pszMessage Error message string. + * @thread Any + */ +#define VM_SET_ERROR(pVM, rc, pszMessage) (VMSetError(pVM, rc, RT_SRC_POS, pszMessage)) + +/** @def VM_SET_ERROR + * Macro for setting a simple VM error message. + * Don't use '%' in the message! + * + * @returns rc. Meaning you can do: + * @code + * return VM_SET_ERROR(pVM, VERR_OF_YOUR_CHOICE, "descriptive message"); + * @endcode + * @param pVM The cross context VM structure. + * @param rc VBox status code. + * @param pszMessage Error message string. + * @thread Any + */ +#define VM_SET_ERROR_U(a_pUVM, a_rc, a_pszMessage) (VMR3SetError(a_pUVM, a_rc, RT_SRC_POS, a_pszMessage)) + + +/** + * VM runtime error callback function. + * + * See VMSetRuntimeError for the detailed description of parameters. + * + * @param pUVM The user mode VM handle. + * @param pvUser The user argument. + * @param fFlags The error flags. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ +typedef DECLCALLBACKTYPE(void, FNVMATRUNTIMEERROR,(PUVM pUVM, void *pvUser, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, va_list va)) RT_IPRT_FORMAT_ATTR(5, 0); +/** Pointer to a VM runtime error callback. */ +typedef FNVMATRUNTIMEERROR *PFNVMATRUNTIMEERROR; + +#ifdef IN_RING3 +VMMDECL(int) VMSetRuntimeError(PVMCC pVM, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(4, 5); +VMMDECL(int) VMSetRuntimeErrorV(PVMCC pVM, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(4, 0); +#endif + +/** @name VMSetRuntimeError fFlags + * When no flags are given the VM will continue running and it's up to the front + * end to take action on the error condition. + * + * @{ */ +/** The error is fatal. + * The VM is not in a state where it can be saved and will enter a state + * where it can no longer execute code. The caller <b>must</b> propagate status + * codes. */ +#define VMSETRTERR_FLAGS_FATAL RT_BIT_32(0) +/** Suspend the VM after, or if possible before, raising the error on EMT. The + * caller <b>must</b> propagate status codes. */ +#define VMSETRTERR_FLAGS_SUSPEND RT_BIT_32(1) +/** Don't wait for the EMT to handle the request. + * Only valid when on a worker thread and there is a high risk of a dead + * lock. Be careful not to flood the user with errors. */ +#define VMSETRTERR_FLAGS_NO_WAIT RT_BIT_32(2) +/** @} */ + +/** + * VM state change callback function. + * + * You are not allowed to call any function which changes the VM state from a + * state callback, except VMR3Destroy(). + * + * @param pUVM The user mode VM handle. + * @param pVMM The VMM ring-3 vtable. + * @param enmState The new state. + * @param enmOldState The old state. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(void, FNVMATSTATE,(PUVM pUVM, PCVMMR3VTABLE pVMM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser)); +/** Pointer to a VM state callback. */ +typedef FNVMATSTATE *PFNVMATSTATE; + +VMMDECL(const char *) VMGetStateName(VMSTATE enmState); + +VMMDECL(uint32_t) VMGetResetCount(PVMCC pVM); +VMMDECL(uint32_t) VMGetSoftResetCount(PVMCC pVM); +VMMDECL(uint32_t) VMGetHardResetCount(PVMCC pVM); + + +/** + * Request type. + */ +typedef enum VMREQTYPE +{ + /** Invalid request. */ + VMREQTYPE_INVALID = 0, + /** VM: Internal. */ + VMREQTYPE_INTERNAL, + /** Maximum request type (exclusive). Used for validation. */ + VMREQTYPE_MAX +} VMREQTYPE; + +/** + * Request state. + */ +typedef enum VMREQSTATE +{ + /** The state is invalid. */ + VMREQSTATE_INVALID = 0, + /** The request have been allocated and is in the process of being filed. */ + VMREQSTATE_ALLOCATED, + /** The request is queued by the requester. */ + VMREQSTATE_QUEUED, + /** The request is begin processed. */ + VMREQSTATE_PROCESSING, + /** The request is completed, the requester is begin notified. */ + VMREQSTATE_COMPLETED, + /** The request packet is in the free chain. (The requester */ + VMREQSTATE_FREE +} VMREQSTATE; + +/** + * Request flags. + */ +typedef enum VMREQFLAGS +{ + /** The request returns a VBox status code. */ + VMREQFLAGS_VBOX_STATUS = 0, + /** The request is a void request and have no status code. */ + VMREQFLAGS_VOID = 1, + /** Return type mask. */ + VMREQFLAGS_RETURN_MASK = 1, + /** Caller does not wait on the packet, EMT will free it. */ + VMREQFLAGS_NO_WAIT = 2, + /** Poke the destination EMT(s) if executing guest code. Use with care. */ + VMREQFLAGS_POKE = 4, + /** Priority request that can safely be processed while doing async + * suspend and power off. */ + VMREQFLAGS_PRIORITY = 8 +} VMREQFLAGS; + + +/** + * VM Request packet. + * + * This is used to request an action in the EMT. Usually the requester is + * another thread, but EMT can also end up being the requester in which case + * it's carried out synchronously. + */ +typedef struct VMREQ +{ + /** Pointer to the next request in the chain. */ + struct VMREQ * volatile pNext; + /** Pointer to ring-3 VM structure which this request belongs to. */ + PUVM pUVM; + /** Request state. */ + volatile VMREQSTATE enmState; + /** VBox status code for the completed request. */ + volatile int32_t iStatus; + /** Requester event sem. + * The request can use this event semaphore to wait/poll for completion + * of the request. + */ + RTSEMEVENT EventSem; + /** Set if the event semaphore is clear. */ + volatile bool fEventSemClear; + /** Flags, VMR3REQ_FLAGS_*. */ + unsigned fFlags; + /** Request type. */ + VMREQTYPE enmType; + /** Request destination. */ + VMCPUID idDstCpu; + /** Request specific data. */ + union VMREQ_U + { + /** VMREQTYPE_INTERNAL. */ + struct + { + /** Pointer to the function to be called. */ + PFNRT pfn; + /** Number of arguments. */ + unsigned cArgs; + /** Array of arguments. */ + uintptr_t aArgs[64]; + } Internal; + } u; +} VMREQ; +/** Pointer to a VM request packet. */ +typedef VMREQ *PVMREQ; + + +#ifndef IN_RC +/** @defgroup grp_vmm_apis_hc VM Host Context API + * @ingroup grp_vm + * @{ */ + +/** @} */ +#endif + + +#ifdef IN_RING3 +/** @defgroup grp_vmm_apis_r3 VM Host Context Ring 3 API + * @ingroup grp_vm + * @{ */ + +/** + * Completion notification codes. + */ +typedef enum VMINITCOMPLETED +{ + /** The ring-3 init is completed. */ + VMINITCOMPLETED_RING3 = 1, + /** The ring-0 init is completed. */ + VMINITCOMPLETED_RING0, + /** The hardware accelerated virtualization init is completed. + * Used to make decisision depending on HM* bits being completely + * initialized. */ + VMINITCOMPLETED_HM +} VMINITCOMPLETED; + + +/** Reason for VM resume. */ +typedef enum VMRESUMEREASON +{ + VMRESUMEREASON_INVALID = 0, + /** User decided to do so. */ + VMRESUMEREASON_USER, + /** VM reconfiguration (like changing DVD). */ + VMRESUMEREASON_RECONFIG, + /** The host resumed. */ + VMRESUMEREASON_HOST_RESUME, + /** Restored state. */ + VMRESUMEREASON_STATE_RESTORED, + /** Snapshot / saved state. */ + VMRESUMEREASON_STATE_SAVED, + /** Teleported to a new box / instance. */ + VMRESUMEREASON_TELEPORTED, + /** Teleportation failed. */ + VMRESUMEREASON_TELEPORT_FAILED, + /** FTM temporarily suspended the VM. */ + VMRESUMEREASON_FTM_SYNC, + /** End of valid reasons. */ + VMRESUMEREASON_END, + /** Blow the type up to 32-bits. */ + VMRESUMEREASON_32BIT_HACK = 0x7fffffff +} VMRESUMEREASON; + +/** Reason for VM suspend. */ +typedef enum VMSUSPENDREASON +{ + VMSUSPENDREASON_INVALID = 0, + /** User decided to do so. */ + VMSUSPENDREASON_USER, + /** VM reconfiguration (like changing DVD). */ + VMSUSPENDREASON_RECONFIG, + /** The VM is suspending itself. */ + VMSUSPENDREASON_VM, + /** The Vm is suspending because of a runtime error. */ + VMSUSPENDREASON_RUNTIME_ERROR, + /** The host was suspended. */ + VMSUSPENDREASON_HOST_SUSPEND, + /** The host is running low on battery power. */ + VMSUSPENDREASON_HOST_BATTERY_LOW, + /** FTM is temporarily suspending the VM. */ + VMSUSPENDREASON_FTM_SYNC, + /** End of valid reasons. */ + VMSUSPENDREASON_END, + /** Blow the type up to 32-bits. */ + VMSUSPENDREASON_32BIT_HACK = 0x7fffffff +} VMSUSPENDREASON; + + +/** + * Progress callback. + * + * This will report the completion percentage of an operation. + * + * @returns VINF_SUCCESS. + * @returns Error code to cancel the operation with. + * @param pUVM The user mode VM handle. + * @param uPercent Completion percentage (0-100). + * @param pvUser User specified argument. + */ +typedef DECLCALLBACKTYPE(int, FNVMPROGRESS,(PUVM pUVM, unsigned uPercent, void *pvUser)); +/** Pointer to a FNVMPROGRESS function. */ +typedef FNVMPROGRESS *PFNVMPROGRESS; + + +VMMR3DECL(int) VMR3Create(uint32_t cCpus, PCVMM2USERMETHODS pVm2UserCbs, + PFNVMATERROR pfnVMAtError, void *pvUserVM, + PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUserCFGM, + PVM *ppVM, PUVM *ppUVM); +VMMR3DECL(int) VMR3PowerOn(PUVM pUVM); +VMMR3DECL(int) VMR3Suspend(PUVM pUVM, VMSUSPENDREASON enmReason); +VMMR3DECL(VMSUSPENDREASON) VMR3GetSuspendReason(PUVM); +VMMR3DECL(int) VMR3Resume(PUVM pUVM, VMRESUMEREASON enmReason); +VMMR3DECL(VMRESUMEREASON) VMR3GetResumeReason(PUVM); +VMMR3DECL(int) VMR3Reset(PUVM pUVM); +VMMR3_INT_DECL(VBOXSTRICTRC) VMR3ResetFF(PVM pVM); +VMMR3_INT_DECL(VBOXSTRICTRC) VMR3ResetTripleFault(PVM pVM); +VMMR3DECL(int) VMR3Save(PUVM pUVM, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, bool fContinueAfterwards, PFNVMPROGRESS pfnProgress, void *pvUser, bool *pfSuspended); +VMMR3DECL(int) VMR3Teleport(PUVM pUVM, uint32_t cMsDowntime, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, PFNVMPROGRESS pfnProgress, void *pvProgressUser, bool *pfSuspended); +VMMR3DECL(int) VMR3LoadFromFile(PUVM pUVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser); +VMMR3DECL(int) VMR3LoadFromStream(PUVM pUVM, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, + PFNVMPROGRESS pfnProgress, void *pvProgressUser, bool fTeleporting); + +VMMR3DECL(int) VMR3PowerOff(PUVM pUVM); +VMMR3DECL(int) VMR3Destroy(PUVM pUVM); +VMMR3_INT_DECL(void) VMR3Relocate(PVM pVM, RTGCINTPTR offDelta); + +VMMR3DECL(PVM) VMR3GetVM(PUVM pUVM); +VMMR3DECL(PUVM) VMR3GetUVM(PVM pVM); +VMMR3DECL(uint32_t) VMR3RetainUVM(PUVM pUVM); +VMMR3DECL(uint32_t) VMR3ReleaseUVM(PUVM pUVM); +VMMR3DECL(const char *) VMR3GetName(PUVM pUVM); +VMMR3DECL(PRTUUID) VMR3GetUuid(PUVM pUVM, PRTUUID pUuid); +VMMR3DECL(VMSTATE) VMR3GetState(PVM pVM); +VMMR3DECL(VMSTATE) VMR3GetStateU(PUVM pUVM); +VMMR3DECL(const char *) VMR3GetStateName(VMSTATE enmState); +VMMR3DECL(int) VMR3AtStateRegister(PUVM pUVM, PFNVMATSTATE pfnAtState, void *pvUser); +VMMR3DECL(int) VMR3AtStateDeregister(PUVM pUVM, PFNVMATSTATE pfnAtState, void *pvUser); +VMMR3_INT_DECL(bool) VMR3SetGuruMeditation(PVM pVM); +VMMR3_INT_DECL(bool) VMR3TeleportedAndNotFullyResumedYet(PVM pVM); +VMMR3DECL(int) VMR3AtErrorRegister(PUVM pUVM, PFNVMATERROR pfnAtError, void *pvUser); +VMMR3DECL(int) VMR3AtErrorDeregister(PUVM pUVM, PFNVMATERROR pfnAtError, void *pvUser); +VMMR3DECL(int) VMR3SetError(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7); +VMMR3DECL(int) VMR3SetErrorV(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0); +VMMR3_INT_DECL(void) VMR3SetErrorWorker(PVM pVM); +VMMR3_INT_DECL(uint32_t) VMR3GetErrorCount(PUVM pUVM); +VMMR3DECL(int) VMR3AtRuntimeErrorRegister(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser); +VMMR3DECL(int) VMR3AtRuntimeErrorDeregister(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser); +VMMR3_INT_DECL(int) VMR3SetRuntimeErrorWorker(PVM pVM); +VMMR3_INT_DECL(uint32_t) VMR3GetRuntimeErrorCount(PUVM pUVM); + +VMMR3DECL(int) VMR3ReqCallU(PUVM pUVM, VMCPUID idDstCpu, PVMREQ *ppReq, RTMSINTERVAL cMillies, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallVU(PUVM pUVM, VMCPUID idDstCpu, PVMREQ *ppReq, RTMSINTERVAL cMillies, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args); +VMMR3_INT_DECL(int) VMR3ReqCallWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallWaitU(PUVM pUVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallNoWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallNoWaitU(PUVM pUVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3_INT_DECL(int) VMR3ReqCallVoidWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallVoidWaitU(PUVM pUVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallVoidNoWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqPriorityCallWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqPriorityCallWaitU(PUVM pUVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqPriorityCallVoidWaitU(PUVM pUVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqAlloc(PUVM pUVM, PVMREQ *ppReq, VMREQTYPE enmType, VMCPUID idDstCpu); +VMMR3DECL(int) VMR3ReqFree(PVMREQ pReq); +VMMR3DECL(int) VMR3ReqQueue(PVMREQ pReq, RTMSINTERVAL cMillies); +VMMR3DECL(int) VMR3ReqWait(PVMREQ pReq, RTMSINTERVAL cMillies); +VMMR3_INT_DECL(int) VMR3ReqProcessU(PUVM pUVM, VMCPUID idDstCpu, bool fPriorityOnly); + +/** @name Flags for VMR3NotifyCpuFFU and VMR3NotifyGlobalFFU. + * @{ */ +/** Whether we've done REM or not. */ +#define VMNOTIFYFF_FLAGS_DONE_REM RT_BIT_32(0) +/** Whether we should poke the CPU if it's executing guest code. */ +#define VMNOTIFYFF_FLAGS_POKE RT_BIT_32(1) +/** @} */ +VMMR3_INT_DECL(void) VMR3NotifyGlobalFFU(PUVM pUVM, uint32_t fFlags); +VMMR3_INT_DECL(void) VMR3NotifyCpuFFU(PUVMCPU pUVMCpu, uint32_t fFlags); +VMMR3DECL(int) VMR3NotifyCpuDeviceReady(PVM pVM, VMCPUID idCpu); +VMMR3_INT_DECL(int) VMR3WaitHalted(PVM pVM, PVMCPU pVCpu, bool fIgnoreInterrupts); +VMMR3_INT_DECL(int) VMR3WaitU(PUVMCPU pUVMCpu); +VMMR3DECL(int) VMR3WaitForDeviceReady(PVM pVM, VMCPUID idCpu); +VMMR3_INT_DECL(int) VMR3AsyncPdmNotificationWaitU(PUVMCPU pUVCpu); +VMMR3_INT_DECL(void) VMR3AsyncPdmNotificationWakeupU(PUVM pUVM); +VMMR3_INT_DECL(RTCPUID) VMR3GetVMCPUId(PVM pVM); +VMMR3_INT_DECL(bool) VMR3IsLongModeAllowed(PVM pVM); +VMMR3_INT_DECL(RTTHREAD) VMR3GetThreadHandle(PUVMCPU pUVCpu); +VMMR3DECL(RTTHREAD) VMR3GetVMCPUThread(PUVM pUVM); +VMMR3DECL(RTNATIVETHREAD) VMR3GetVMCPUNativeThread(PVM pVM); +VMMR3DECL(RTNATIVETHREAD) VMR3GetVMCPUNativeThreadU(PUVM pUVM); +VMMR3DECL(int) VMR3GetCpuCoreAndPackageIdFromCpuId(PUVM pUVM, VMCPUID idCpu, uint32_t *pidCpuCore, uint32_t *pidCpuPackage); +VMMR3_INT_DECL(uint32_t) VMR3GetActiveEmts(PUVM pUVM); +VMMR3DECL(int) VMR3HotUnplugCpu(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) VMR3HotPlugCpu(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) VMR3SetCpuExecutionCap(PUVM pUVM, uint32_t uCpuExecutionCap); +VMMR3DECL(int) VMR3SetPowerOffInsteadOfReset(PUVM pUVM, bool fPowerOffInsteadOfReset); +/** @} */ +#endif /* IN_RING3 */ + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_vmapi_h */ + diff --git a/include/VBox/vmm/vmcc.h b/include/VBox/vmm/vmcc.h new file mode 100644 index 00000000..3a143fae --- /dev/null +++ b/include/VBox/vmm/vmcc.h @@ -0,0 +1,148 @@ +/** @file + * VM - The Virtual Machine, GVM/GVMCPU or VM/VMCPU depending on context. + */ + +/* + * Copyright (C) 2019-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vmcc_h +#define VBOX_INCLUDED_vmm_vmcc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include <VBox/vmm/vm.h> +#ifdef IN_RING0 +# include <VBox/vmm/gvm.h> +#else +# include <VBox/vmm/uvm.h> +#endif + +/** @typedef VMCC + * Context specific VM derived structure. + * This is plain VM in ring-3 and GVM (inherits from VM) in ring-0. */ +/** @typedef VMCPUCC + * Context specific VMCPU derived structure. + * This is plain VM in ring-3 and GVMCPU (inherits from VMCPU) in ring-0. */ +#ifdef IN_RING0 +typedef GVM VMCC; +typedef GVMCPU VMCPUCC; +#else +typedef VM VMCC; +typedef VMCPU VMCPUCC; +#endif + +/** @def VMCC_GET_CPU_0 + * Gets the context specfic pointer to virtual CPU \#0. + * @param a_pVM The context specfic VM structure. + */ +#ifdef IN_RING0 +# define VMCC_GET_CPU_0(a_pVM) (&(a_pVM)->aCpus[0]) +#else +# define VMCC_GET_CPU_0(a_pVM) ((a_pVM)->CTX_SUFF(apCpus)[0]) +#endif + +/** @def VMCC_GET_CPU + * Gets the context specfic pointer to a virtual CPU by index (ID). + * @param a_pVM The context specfic VM structure. + * @param a_idCpu The CPU number to get (caller ensures validity). + */ +#ifdef IN_RING0 +# define VMCC_GET_CPU(a_pVM, a_idCpu) (&(a_pVM)->aCpus[(a_idCpu)]) +#else +# define VMCC_GET_CPU(a_pVM, a_idCpu) ((a_pVM)->CTX_SUFF(apCpus)[(a_idCpu)]) +#endif + +/** @def VMCC_FOR_EACH_VMCPU + * For enumerating VCpus in ascending order, avoiding unnecessary apCpusR0 + * access in ring-0, caching the CPU count and not checking for CPU \#0. + * + * Defines local variables @c idCpu, @c pVCpu and @c cCpus. + * + * @param a_pVM The VM handle. + * + * @note Close loop with VMCC_FOR_EACH_VMCPU_END. + */ +#define VMCC_FOR_EACH_VMCPU(a_pVM) \ + do { \ + VMCPUID idCpu = 0; \ + VMCPUID const cCpus = (a_pVM)->cCpus; \ + PVMCPUCC pVCpu = VMCC_GET_CPU_0(a_pVM); \ + for (;;) \ + { + +/** @def VMCC_FOR_EACH_VMCPU_END + * Ends a VMCC_FOR_EACH_VMCPU loop. + * @param a_pVM The VM handle. + */ +#define VMCC_FOR_EACH_VMCPU_END(a_pVM) \ + /* advance */ \ + if (++idCpu >= cCpus) \ + break; \ + pVCpu = VMCC_GET_CPU(pVM, idCpu); \ + } \ + } while (0) + +/** + * Execute the given statement for each virtual CPU in an environment with + * @c pVCpu and @c idCpu variables. + * + * @param a_pVM The VM handle. + * @param a_Stmt The statement to execute. + */ +#define VMCC_FOR_EACH_VMCPU_STMT(a_pVM, a_Stmt) VMCC_FOR_EACH_VMCPU(pVM) { a_Stmt; } VMCC_FOR_EACH_VMCPU_END(pVM) + +/** @def VMCC_GET_VMR0_FOR_CALL(pVM) */ +#if defined(IN_RING3) +# define VMCC_GET_VMR0_FOR_CALL(a_pVM) ((a_pVM)->pVMR0ForCall) +#elif defined(IN_RING3) +# define VMCC_GET_VMR0_FOR_CALL(a_pVM) ((a_pVM)->pVMR0) +#else +# define VMCC_GET_VMR0_FOR_CALL(a_pVM) ((a_pVM)->ring3_only_macro) +#endif + + +/** + * Used to pick ring-0 or ring-3 VM component data. + * + * @code{.cpp} + * pVM->VMCC_CTX(pdm).s.pfnWorker + * @endcode + */ +#ifdef IN_RING0 +# define VMCC_CTX(a_Name) a_Name ## r0 +#else +# define VMCC_CTX(a_Name) a_Name +#endif + +#endif /* !VBOX_INCLUDED_vmm_vmcc_h */ + diff --git a/include/VBox/vmm/vmcpuset.h b/include/VBox/vmm/vmcpuset.h new file mode 100644 index 00000000..496721de --- /dev/null +++ b/include/VBox/vmm/vmcpuset.h @@ -0,0 +1,124 @@ +/** @file + * VirtualBox - VMCPUSET Operation. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vmcpuset_h +#define VBOX_INCLUDED_vmm_vmcpuset_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/asm.h> +#include <iprt/string.h> + +/** @defgroup grp_vmcpuset VMCPUSET Operations + * @ingroup grp_types_both + * @sa VMCPUSET + * @{ + */ + +/** Tests if a valid CPU ID is present in the set. */ +#define VMCPUSET_IS_PRESENT(pSet, idCpu) ASMBitTest( &(pSet)->au32Bitmap[0], (idCpu)) +/** Adds a CPU to the set. */ +#define VMCPUSET_ADD(pSet, idCpu) ASMBitSet( &(pSet)->au32Bitmap[0], (idCpu)) +/** Deletes a CPU from the set. */ +#define VMCPUSET_DEL(pSet, idCpu) ASMBitClear(&(pSet)->au32Bitmap[0], (idCpu)) +/** Adds a CPU to the set, atomically. */ +#define VMCPUSET_ATOMIC_ADD(pSet, idCpu) ASMAtomicBitSet( &(pSet)->au32Bitmap[0], (idCpu)) +/** Deletes a CPU from the set, atomically. */ +#define VMCPUSET_ATOMIC_DEL(pSet, idCpu) ASMAtomicBitClear(&(pSet)->au32Bitmap[0], (idCpu)) +/** Empties the set. */ +#define VMCPUSET_EMPTY(pSet) memset(&(pSet)->au32Bitmap[0], '\0', sizeof((pSet)->au32Bitmap)) +/** Fills the set. */ +#define VMCPUSET_FILL(pSet) memset(&(pSet)->au32Bitmap[0], 0xff, sizeof((pSet)->au32Bitmap)) +/** Checks if two sets are equal to one another. */ +#define VMCPUSET_IS_EQUAL(pSet1, pSet2) (memcmp(&(pSet1)->au32Bitmap[0], &(pSet2)->au32Bitmap[0], sizeof((pSet1)->au32Bitmap)) == 0) +/** Checks if the set is empty. */ +#define VMCPUSET_IS_EMPTY(a_pSet) ( (a_pSet)->au32Bitmap[0] == 0 \ + && (a_pSet)->au32Bitmap[1] == 0 \ + && (a_pSet)->au32Bitmap[2] == 0 \ + && (a_pSet)->au32Bitmap[3] == 0 \ + && (a_pSet)->au32Bitmap[4] == 0 \ + && (a_pSet)->au32Bitmap[5] == 0 \ + && (a_pSet)->au32Bitmap[6] == 0 \ + && (a_pSet)->au32Bitmap[7] == 0 \ + ) +/** Finds the first CPU present in the SET. + * @returns CPU index if found, NIL_VMCPUID if not. */ +#define VMCPUSET_FIND_FIRST_PRESENT(a_pSet) VMCpuSetFindFirstPresentInternal(a_pSet) + +/** Implements VMCPUSET_FIND_FIRST_PRESENT. + * + * @returns CPU index of the first CPU present in the set, NIL_VMCPUID if none + * are present. + * @param pSet The set to scan. + */ +DECLINLINE(int32_t) VMCpuSetFindFirstPresentInternal(PCVMCPUSET pSet) +{ + int i = ASMBitFirstSet(&pSet->au32Bitmap[0], RT_ELEMENTS(pSet->au32Bitmap) * 32); + return i >= 0 ? (VMCPUID)i : NIL_VMCPUID; +} + +/** Finds the first CPU present in the SET. + * @returns CPU index if found, NIL_VMCPUID if not. */ +#define VMCPUSET_FIND_LAST_PRESENT(a_pSet) VMCpuSetFindLastPresentInternal(a_pSet) + +/** Implements VMCPUSET_FIND_LAST_PRESENT. + * + * @returns CPU index of the last CPU present in the set, NIL_VMCPUID if none + * are present. + * @param pSet The set to scan. + */ +DECLINLINE(int32_t) VMCpuSetFindLastPresentInternal(PCVMCPUSET pSet) +{ + uint32_t i = RT_ELEMENTS(pSet->au32Bitmap); + while (i-- > 0) + { + uint32_t u = pSet->au32Bitmap[i]; + if (u) + { + u = ASMBitLastSetU32(u); + u--; + u |= i << 5; + return u; + } + } + return NIL_VMCPUID; +} + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_vmcpuset_h */ + diff --git a/include/VBox/vmm/vmm.h b/include/VBox/vmm/vmm.h new file mode 100644 index 00000000..85df7e4c --- /dev/null +++ b/include/VBox/vmm/vmm.h @@ -0,0 +1,639 @@ +/** @file + * VMM - The Virtual Machine Monitor. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vmm_h +#define VBOX_INCLUDED_vmm_vmm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/vmapi.h> +#include <VBox/sup.h> +#include <VBox/log.h> +#include <iprt/stdarg.h> +#include <iprt/thread.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_vmm The Virtual Machine Monitor + * @{ + */ + +/** @defgroup grp_vmm_api The Virtual Machine Monitor API + * @{ + */ + + +/** + * Ring-0 assertion notification callback. + * + * @returns VBox status code. + * @param pVCpu The cross context virtual CPU structure. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(int, FNVMMR0ASSERTIONNOTIFICATION,(PVMCPUCC pVCpu, void *pvUser)); +/** Pointer to a FNVMMR0ASSERTIONNOTIFICATION(). */ +typedef FNVMMR0ASSERTIONNOTIFICATION *PFNVMMR0ASSERTIONNOTIFICATION; + +/** + * Rendezvous callback. + * + * @returns VBox strict status code - EM scheduling. Do not return + * informational status code other than the ones used by EM for + * scheduling. + * + * @param pVM The cross context VM structure. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNVMMEMTRENDEZVOUS,(PVM pVM, PVMCPU pVCpu, void *pvUser)); +/** Pointer to a rendezvous callback function. */ +typedef FNVMMEMTRENDEZVOUS *PFNVMMEMTRENDEZVOUS; + +/** + * Method table that the VMM uses to call back the user of the VMM. + */ +typedef struct VMM2USERMETHODS +{ + /** Magic value (VMM2USERMETHODS_MAGIC). */ + uint32_t u32Magic; + /** Structure version (VMM2USERMETHODS_VERSION). */ + uint32_t u32Version; + + /** + * Save the VM state. + * + * @returns VBox status code. + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * + * @remarks This member shall be set to NULL if the operation is not + * supported. + */ + DECLR3CALLBACKMEMBER(int, pfnSaveState,(PCVMM2USERMETHODS pThis, PUVM pUVM)); + /** @todo Move pfnVMAtError and pfnCFGMConstructor here? */ + + /** + * EMT initialization notification callback. + * + * This is intended for doing per-thread initialization for EMTs (like COM + * init). + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * @param pUVCpu The user mode virtual CPU handle. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyEmtInit,(PCVMM2USERMETHODS pThis, PUVM pUVM, PUVMCPU pUVCpu)); + + /** + * EMT termination notification callback. + * + * This is intended for doing per-thread cleanups for EMTs (like COM). + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * @param pUVCpu The user mode virtual CPU handle. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyEmtTerm,(PCVMM2USERMETHODS pThis, PUVM pUVM, PUVMCPU pUVCpu)); + + /** + * PDM thread initialization notification callback. + * + * This is intended for doing per-thread initialization (like COM init). + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyPdmtInit,(PCVMM2USERMETHODS pThis, PUVM pUVM)); + + /** + * EMT termination notification callback. + * + * This is intended for doing per-thread cleanups for EMTs (like COM). + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyPdmtTerm,(PCVMM2USERMETHODS pThis, PUVM pUVM)); + + /** + * Notification callback that that a VM reset will be turned into a power off. + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyResetTurnedIntoPowerOff,(PCVMM2USERMETHODS pThis, PUVM pUVM)); + + /** + * Generic object query by UUID. + * + * @returns pointer to queried the object on success, NULL if not found. + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * @param pUuid The UUID of what's being queried. The UUIDs and the + * usage conventions are defined by the user. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void *, pfnQueryGenericObject,(PCVMM2USERMETHODS pThis, PUVM pUVM, PCRTUUID pUuid)); + + /** Magic value (VMM2USERMETHODS_MAGIC) marking the end of the structure. */ + uint32_t u32EndMagic; +} VMM2USERMETHODS; + +/** Magic value of the VMM2USERMETHODS (Franz Kafka). */ +#define VMM2USERMETHODS_MAGIC UINT32_C(0x18830703) +/** The VMM2USERMETHODS structure version. */ +#define VMM2USERMETHODS_VERSION UINT32_C(0x00030000) + + +/** + * Checks whether we've armed the ring-0 long jump machinery. + * + * @returns @c true / @c false + * @param a_pVCpu The caller's cross context virtual CPU structure. + * @thread EMT + * @sa VMMR0IsLongJumpArmed + */ +#ifdef IN_RING0 +# define VMMIsLongJumpArmed(a_pVCpu) VMMR0IsLongJumpArmed(a_pVCpu) +#else +# define VMMIsLongJumpArmed(a_pVCpu) (false) +#endif + + +VMMDECL(VMCPUID) VMMGetCpuId(PVMCC pVM); +VMMDECL(PVMCPUCC) VMMGetCpu(PVMCC pVM); +VMMDECL(PVMCPUCC) VMMGetCpu0(PVMCC pVM); +VMMDECL(PVMCPUCC) VMMGetCpuById(PVMCC pVM, VMCPUID idCpu); +VMMR3DECL(PVMCPUCC) VMMR3GetCpuByIdU(PUVM pVM, VMCPUID idCpu); +VMM_INT_DECL(uint32_t) VMMGetSvnRev(void); +VMM_INT_DECL(void) VMMTrashVolatileXMMRegs(void); + + +/** @defgroup grp_vmm_api_r0 The VMM Host Context Ring 0 API + * @{ + */ + +/** + * The VMMR0Entry() codes. + */ +typedef enum VMMR0OPERATION +{ + /** Run guest code using the available hardware acceleration technology. */ + VMMR0_DO_HM_RUN = SUP_VMMR0_DO_HM_RUN, + /** Official NOP that we use for profiling. */ + VMMR0_DO_NEM_RUN = SUP_VMMR0_DO_NEM_RUN, + /** Official NOP that we use for profiling. */ + VMMR0_DO_NOP = SUP_VMMR0_DO_NOP, + /** Official slow iocl NOP that we use for profiling. */ + VMMR0_DO_SLOW_NOP, + + /** Ask the GVMM to create a new VM. */ + VMMR0_DO_GVMM_CREATE_VM = 32, + /** Ask the GVMM to destroy the VM. */ + VMMR0_DO_GVMM_DESTROY_VM, + /** Call GVMMR0RegisterVCpu(). */ + VMMR0_DO_GVMM_REGISTER_VMCPU, + /** Call GVMMR0DeregisterVCpu(). */ + VMMR0_DO_GVMM_DEREGISTER_VMCPU, + /** Call GVMMR0RegisterWorkerThread(). */ + VMMR0_DO_GVMM_REGISTER_WORKER_THREAD, + /** Call GVMMR0DeregisterWorkerThread(). */ + VMMR0_DO_GVMM_DEREGISTER_WORKER_THREAD, + /** Call GVMMR0SchedHalt(). */ + VMMR0_DO_GVMM_SCHED_HALT, + /** Call GVMMR0SchedWakeUp(). */ + VMMR0_DO_GVMM_SCHED_WAKE_UP, + /** Call GVMMR0SchedPoke(). */ + VMMR0_DO_GVMM_SCHED_POKE, + /** Call GVMMR0SchedWakeUpAndPokeCpus(). */ + VMMR0_DO_GVMM_SCHED_WAKE_UP_AND_POKE_CPUS, + /** Call GVMMR0SchedPoll(). */ + VMMR0_DO_GVMM_SCHED_POLL, + /** Call GVMMR0QueryStatistics(). */ + VMMR0_DO_GVMM_QUERY_STATISTICS, + /** Call GVMMR0ResetStatistics(). */ + VMMR0_DO_GVMM_RESET_STATISTICS, + + /** Call VMMR0 Per VM Init. */ + VMMR0_DO_VMMR0_INIT = 64, + /** Call VMMR0 Per VM EMT Init */ + VMMR0_DO_VMMR0_INIT_EMT, + /** Call VMMR0 Per VM Termination. */ + VMMR0_DO_VMMR0_TERM, + /** Copy logger settings from userland, VMMR0UpdateLoggersReq(). */ + VMMR0_DO_VMMR0_UPDATE_LOGGERS, + /** Used by the log flusher, VMMR0LogFlusher. */ + VMMR0_DO_VMMR0_LOG_FLUSHER, + /** Used by EMTs to wait for the log flusher to finish, VMMR0LogWaitFlushed. */ + VMMR0_DO_VMMR0_LOG_WAIT_FLUSHED, + + /** Setup hardware-assisted VM session. */ + VMMR0_DO_HM_SETUP_VM = 128, + /** Attempt to enable or disable hardware-assisted mode. */ + VMMR0_DO_HM_ENABLE, + + /** Call PGMR0PhysAllocateHandyPages(). */ + VMMR0_DO_PGM_ALLOCATE_HANDY_PAGES = 192, + /** Call PGMR0PhysFlushHandyPages(). */ + VMMR0_DO_PGM_FLUSH_HANDY_PAGES, + /** Call PGMR0AllocateLargePage(). */ + VMMR0_DO_PGM_ALLOCATE_LARGE_PAGE, + /** Call PGMR0PhysSetupIommu(). */ + VMMR0_DO_PGM_PHYS_SETUP_IOMMU, + /** Call PGMR0PoolGrow(). */ + VMMR0_DO_PGM_POOL_GROW, + /** Call PGMR0PhysHandlerInitReqHandler(). */ + VMMR0_DO_PGM_PHYS_HANDLER_INIT, + + /** Call GMMR0InitialReservation(). */ + VMMR0_DO_GMM_INITIAL_RESERVATION = 256, + /** Call GMMR0UpdateReservation(). */ + VMMR0_DO_GMM_UPDATE_RESERVATION, + /** Call GMMR0AllocatePages(). */ + VMMR0_DO_GMM_ALLOCATE_PAGES, + /** Call GMMR0FreePages(). */ + VMMR0_DO_GMM_FREE_PAGES, + /** Call GMMR0FreeLargePage(). */ + VMMR0_DO_GMM_FREE_LARGE_PAGE, + /** Call GMMR0QueryHypervisorMemoryStatsReq(). */ + VMMR0_DO_GMM_QUERY_HYPERVISOR_MEM_STATS, + /** Call GMMR0QueryMemoryStatsReq(). */ + VMMR0_DO_GMM_QUERY_MEM_STATS, + /** Call GMMR0BalloonedPages(). */ + VMMR0_DO_GMM_BALLOONED_PAGES, + /** Call GMMR0MapUnmapChunk(). */ + VMMR0_DO_GMM_MAP_UNMAP_CHUNK, + /** Call GMMR0RegisterSharedModule. */ + VMMR0_DO_GMM_REGISTER_SHARED_MODULE, + /** Call GMMR0UnregisterSharedModule. */ + VMMR0_DO_GMM_UNREGISTER_SHARED_MODULE, + /** Call GMMR0ResetSharedModules. */ + VMMR0_DO_GMM_RESET_SHARED_MODULES, + /** Call GMMR0CheckSharedModules. */ + VMMR0_DO_GMM_CHECK_SHARED_MODULES, + /** Call GMMR0FindDuplicatePage. */ + VMMR0_DO_GMM_FIND_DUPLICATE_PAGE, + /** Call GMMR0QueryStatistics(). */ + VMMR0_DO_GMM_QUERY_STATISTICS, + /** Call GMMR0ResetStatistics(). */ + VMMR0_DO_GMM_RESET_STATISTICS, + + /** Call PDMR0DriverCallReqHandler. */ + VMMR0_DO_PDM_DRIVER_CALL_REQ_HANDLER = 320, + /** Call PDMR0DeviceCreateReqHandler. */ + VMMR0_DO_PDM_DEVICE_CREATE, + /** Call PDMR0DeviceGenCallReqHandler. */ + VMMR0_DO_PDM_DEVICE_GEN_CALL, + /** Old style device compat: Set ring-0 critical section. */ + VMMR0_DO_PDM_DEVICE_COMPAT_SET_CRITSECT, + /** Call PDMR0QueueCreateReqHandler. */ + VMMR0_DO_PDM_QUEUE_CREATE, + + /** Set a GVMM or GMM configuration value. */ + VMMR0_DO_GCFGM_SET_VALUE = 400, + /** Query a GVMM or GMM configuration value. */ + VMMR0_DO_GCFGM_QUERY_VALUE, + + /** The start of the R0 service operations. */ + VMMR0_DO_SRV_START = 448, + /** Call IntNetR0Open(). */ + VMMR0_DO_INTNET_OPEN, + /** Call IntNetR0IfClose(). */ + VMMR0_DO_INTNET_IF_CLOSE, + /** Call IntNetR0IfGetBufferPtrs(). */ + VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS, + /** Call IntNetR0IfSetPromiscuousMode(). */ + VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE, + /** Call IntNetR0IfSetMacAddress(). */ + VMMR0_DO_INTNET_IF_SET_MAC_ADDRESS, + /** Call IntNetR0IfSetActive(). */ + VMMR0_DO_INTNET_IF_SET_ACTIVE, + /** Call IntNetR0IfSend(). */ + VMMR0_DO_INTNET_IF_SEND, + /** Call IntNetR0IfWait(). */ + VMMR0_DO_INTNET_IF_WAIT, + /** Call IntNetR0IfAbortWait(). */ + VMMR0_DO_INTNET_IF_ABORT_WAIT, + +#if 0 + /** Forward call to the PCI driver */ + VMMR0_DO_PCIRAW_REQ = 512, +#endif + + /** The end of the R0 service operations. */ + VMMR0_DO_SRV_END, + + /** Call NEMR0InitVM() (host specific). */ + VMMR0_DO_NEM_INIT_VM = 576, + /** Call NEMR0InitVMPart2() (host specific). */ + VMMR0_DO_NEM_INIT_VM_PART_2, + /** Call NEMR0MapPages() (host specific). */ + VMMR0_DO_NEM_MAP_PAGES, + /** Call NEMR0UnmapPages() (host specific). */ + VMMR0_DO_NEM_UNMAP_PAGES, + /** Call NEMR0ExportState() (host specific). */ + VMMR0_DO_NEM_EXPORT_STATE, + /** Call NEMR0ImportState() (host specific). */ + VMMR0_DO_NEM_IMPORT_STATE, + /** Call NEMR0QueryCpuTick() (host specific). */ + VMMR0_DO_NEM_QUERY_CPU_TICK, + /** Call NEMR0ResumeCpuTickOnAll() (host specific). */ + VMMR0_DO_NEM_RESUME_CPU_TICK_ON_ALL, + /** Call NEMR0UpdateStatistics() (host specific). */ + VMMR0_DO_NEM_UPDATE_STATISTICS, + /** Call NEMR0DoExperiment() (host specific, experimental, debug only). */ + VMMR0_DO_NEM_EXPERIMENT, + + /** Grow the I/O port registration tables. */ + VMMR0_DO_IOM_GROW_IO_PORTS = 640, + /** Grow the I/O port statistics tables. */ + VMMR0_DO_IOM_GROW_IO_PORT_STATS, + /** Grow the MMIO registration tables. */ + VMMR0_DO_IOM_GROW_MMIO_REGS, + /** Grow the MMIO statistics tables. */ + VMMR0_DO_IOM_GROW_MMIO_STATS, + /** Synchronize statistics indices for I/O ports and MMIO regions. */ + VMMR0_DO_IOM_SYNC_STATS_INDICES, + + /** Call DBGFR0TraceCreateReqHandler. */ + VMMR0_DO_DBGF_TRACER_CREATE = 704, + /** Call DBGFR0TraceCallReqHandler. */ + VMMR0_DO_DBGF_TRACER_CALL_REQ_HANDLER, + /** Call DBGFR0BpInitReqHandler(). */ + VMMR0_DO_DBGF_BP_INIT, + /** Call DBGFR0BpChunkAllocReqHandler(). */ + VMMR0_DO_DBGF_BP_CHUNK_ALLOC, + /** Call DBGFR0BpL2TblChunkAllocReqHandler(). */ + VMMR0_DO_DBGF_BP_L2_TBL_CHUNK_ALLOC, + /** Call DBGFR0BpOwnerInitReqHandler(). */ + VMMR0_DO_DBGF_BP_OWNER_INIT, + /** Call DBGFR0BpPortIoInitReqHandler(). */ + VMMR0_DO_DBGF_BP_PORTIO_INIT, + + /** Grow a timer queue. */ + VMMR0_DO_TM_GROW_TIMER_QUEUE = 768, + + /** Official call we use for testing Ring-0 APIs. */ + VMMR0_DO_TESTS = 2048, + + /** The usual 32-bit type blow up. */ + VMMR0_DO_32BIT_HACK = 0x7fffffff +} VMMR0OPERATION; + + +/** + * Request buffer for VMMR0_DO_GCFGM_SET_VALUE and VMMR0_DO_GCFGM_QUERY_VALUE. + * @todo Move got GCFGM.h when it's implemented. + */ +typedef struct GCFGMVALUEREQ +{ + /** The request header.*/ + SUPVMMR0REQHDR Hdr; + /** The support driver session handle. */ + PSUPDRVSESSION pSession; + /** The value. + * This is input for the set request and output for the query. */ + uint64_t u64Value; + /** The variable name. + * This is fixed sized just to make things simple for the mock-up. */ + char szName[48]; +} GCFGMVALUEREQ; +/** Pointer to a VMMR0_DO_GCFGM_SET_VALUE and VMMR0_DO_GCFGM_QUERY_VALUE request buffer. + * @todo Move got GCFGM.h when it's implemented. + */ +typedef GCFGMVALUEREQ *PGCFGMVALUEREQ; + + +/** + * Request package for VMMR0_DO_VMMR0_UPDATE_LOGGERS. + * + * In addition the u64Arg is selects the logger and indicates whether we're only + * outputting to the parent VMM. See VMMR0UPDATELOGGER_F_XXX. + */ +typedef struct VMMR0UPDATELOGGERSREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** The current logger flags (RTLOGFLAGS). */ + uint64_t fFlags; + /** Groups, assuming same group layout as ring-3. */ + uint32_t cGroups; + /** CRC32 of the group names. */ + uint32_t uGroupCrc32; + /** Per-group settings, variable size. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint32_t afGroups[RT_FLEXIBLE_ARRAY]; +} VMMR0UPDATELOGGERSREQ; +/** Pointer to a VMMR0_DO_VMMR0_UPDATE_LOGGERS request. */ +typedef VMMR0UPDATELOGGERSREQ *PVMMR0UPDATELOGGERSREQ; + +/** @name VMMR0UPDATELOGGER_F_XXX - u64Arg definitions for VMMR0_DO_VMMR0_UPDATE_LOGGERS. + * @{ */ +/** Logger index mask. */ +#define VMMR0UPDATELOGGER_F_LOGGER_MASK UINT64_C(0x0001) +/** Only flush to the parent VMM's debug log, don't return to ring-3. */ +#define VMMR0UPDATELOGGER_F_TO_PARENT_VMM_DBG UINT64_C(0x0002) +/** Only flush to the parent VMM's debug log, don't return to ring-3. */ +#define VMMR0UPDATELOGGER_F_TO_PARENT_VMM_REL UINT64_C(0x0004) +/** Valid flag mask. */ +#define VMMR0UPDATELOGGER_F_VALID_MASK UINT64_C(0x0007) +/** @} */ + +#if defined(IN_RING0) || defined(DOXYGEN_RUNNING) + +/** + * Structure VMMR0EmtPrepareToBlock uses to pass info to + * VMMR0EmtResumeAfterBlocking. + */ +typedef struct VMMR0EMTBLOCKCTX +{ + /** Magic value (VMMR0EMTBLOCKCTX_MAGIC). */ + uint32_t uMagic; + /** Set if we were in HM context, clear if not. */ + bool fWasInHmContext; +} VMMR0EMTBLOCKCTX; +/** Pointer to a VMMR0EmtPrepareToBlock context structure. */ +typedef VMMR0EMTBLOCKCTX *PVMMR0EMTBLOCKCTX; +/** Magic value for VMMR0EMTBLOCKCTX::uMagic (Paul Desmond). */ +#define VMMR0EMTBLOCKCTX_MAGIC UINT32_C(0x19261125) +/** Magic value for VMMR0EMTBLOCKCTX::uMagic when its out of context. */ +#define VMMR0EMTBLOCKCTX_MAGIC_DEAD UINT32_C(0x19770530) + +VMMR0DECL(void) VMMR0EntryFast(PGVM pGVM, PVMCC pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation); +VMMR0DECL(int) VMMR0EntryEx(PGVM pGVM, PVMCC pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation, + PSUPVMMR0REQHDR pReq, uint64_t u64Arg, PSUPDRVSESSION); +VMMR0_INT_DECL(int) VMMR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(int) VMMR0TermVM(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(void) VMMR0CleanupVM(PGVM pGVM); +VMMR0_INT_DECL(bool) VMMR0IsLongJumpArmed(PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) VMMR0ThreadCtxHookCreateForEmt(PVMCPUCC pVCpu); +VMMR0_INT_DECL(void) VMMR0ThreadCtxHookDestroyForEmt(PVMCPUCC pVCpu); +VMMR0_INT_DECL(void) VMMR0ThreadCtxHookDisable(PVMCPUCC pVCpu); +VMMR0_INT_DECL(bool) VMMR0ThreadCtxHookIsEnabled(PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) VMMR0EmtPrepareToBlock(PVMCPUCC pVCpu, int rcBusy, const char *pszCaller, void *pvLock, + PVMMR0EMTBLOCKCTX pCtx); +VMMR0_INT_DECL(void) VMMR0EmtResumeAfterBlocking(PVMCPUCC pVCpu, PVMMR0EMTBLOCKCTX pCtx); +VMMR0_INT_DECL(int) VMMR0EmtWaitEventInner(PGVMCPU pGVCpu, uint32_t fFlags, RTSEMEVENT hEvent, RTMSINTERVAL cMsTimeout); +VMMR0_INT_DECL(int) VMMR0EmtSignalSupEvent(PGVM pGVM, PGVMCPU pGVCpu, SUPSEMEVENT hEvent); +VMMR0_INT_DECL(int) VMMR0EmtSignalSupEventByGVM(PGVM pGVM, SUPSEMEVENT hEvent); +VMMR0_INT_DECL(int) VMMR0AssertionSetNotification(PVMCPUCC pVCpu, PFNVMMR0ASSERTIONNOTIFICATION pfnCallback, RTR0PTR pvUser); +VMMR0_INT_DECL(void) VMMR0AssertionRemoveNotification(PVMCPUCC pVCpu); +VMMR0_INT_DECL(bool) VMMR0AssertionIsNotificationSet(PVMCPUCC pVCpu); + +/** @name VMMR0EMTWAIT_F_XXX - flags for VMMR0EmtWaitEventInner and friends. + * @{ */ +/** Try suppress VERR_INTERRUPTED for a little while (~10 sec). */ +#define VMMR0EMTWAIT_F_TRY_SUPPRESS_INTERRUPTED RT_BIT_32(0) +/** @} */ +#endif /* IN_RING0 */ + +VMMR0_INT_DECL(PRTLOGGER) VMMR0GetReleaseLogger(PVMCPUCC pVCpu); +/** @} */ + + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +/** @defgroup grp_vmm_api_r3 The VMM Host Context Ring 3 API + * @{ + */ +VMMR3DECL(PCVMMR3VTABLE) VMMR3GetVTable(void); +VMMR3_INT_DECL(int) VMMR3Init(PVM pVM); +VMMR3_INT_DECL(int) VMMR3InitR0(PVM pVM); +VMMR3_INT_DECL(int) VMMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3_INT_DECL(int) VMMR3Term(PVM pVM); +VMMR3_INT_DECL(void) VMMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) VMMR3UpdateLoggers(PVM pVM); +VMMR3DECL(const char *) VMMR3GetRZAssertMsg1(PVM pVM); +VMMR3DECL(const char *) VMMR3GetRZAssertMsg2(PVM pVM); +VMMR3_INT_DECL(int) VMMR3HmRunGC(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) VMMR3CallR0(PVM pVM, uint32_t uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr); +VMMR3_INT_DECL(int) VMMR3CallR0Emt(PVM pVM, PVMCPU pVCpu, VMMR0OPERATION enmOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr); +VMMR3_INT_DECL(VBOXSTRICTRC) VMMR3CallR0EmtFast(PVM pVM, PVMCPU pVCpu, VMMR0OPERATION enmOperation); +VMMR3DECL(void) VMMR3FatalDump(PVM pVM, PVMCPU pVCpu, int rcErr); +VMMR3_INT_DECL(void) VMMR3YieldSuspend(PVM pVM); +VMMR3_INT_DECL(void) VMMR3YieldStop(PVM pVM); +VMMR3_INT_DECL(void) VMMR3YieldResume(PVM pVM); +VMMR3_INT_DECL(void) VMMR3SendStartupIpi(PVM pVM, VMCPUID idCpu, uint32_t uVector); +VMMR3_INT_DECL(void) VMMR3SendInitIpi(PVM pVM, VMCPUID idCpu); +VMMR3DECL(int) VMMR3RegisterPatchMemory(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem); +VMMR3DECL(int) VMMR3DeregisterPatchMemory(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem); +VMMR3DECL(int) VMMR3EmtRendezvous(PVM pVM, uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser); +/** @defgroup grp_VMMR3EmtRendezvous_fFlags VMMR3EmtRendezvous flags + * @{ */ +/** Execution type mask. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK UINT32_C(0x00000007) +/** Invalid execution type. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_INVALID UINT32_C(0) +/** Let the EMTs execute the callback one by one (in no particular order). + * Recursion from within the callback possible. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE UINT32_C(1) +/** Let all the EMTs execute the callback at the same time. + * Cannot recurse from the callback. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE UINT32_C(2) +/** Only execute the callback on one EMT (no particular one). + * Recursion from within the callback possible. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE UINT32_C(3) +/** Let the EMTs execute the callback one by one in ascending order. + * Recursion from within the callback possible. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING UINT32_C(4) +/** Let the EMTs execute the callback one by one in descending order. + * Recursion from within the callback possible. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING UINT32_C(5) +/** Stop after the first error. + * This is not valid for any execution type where more than one EMT is active + * at a time. */ +#define VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR UINT32_C(0x00000008) +/** Use VMREQFLAGS_PRIORITY when contacting the EMTs. */ +#define VMMEMTRENDEZVOUS_FLAGS_PRIORITY UINT32_C(0x00000010) +/** The valid flags. */ +#define VMMEMTRENDEZVOUS_FLAGS_VALID_MASK UINT32_C(0x0000001f) +/** @} */ +VMMR3_INT_DECL(int) VMMR3EmtRendezvousFF(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(void) VMMR3SetMayHaltInRing0(PVMCPU pVCpu, bool fMayHaltInRing0, uint32_t cNsSpinBlockThreshold); +VMMR3_INT_DECL(int) VMMR3ReadR0Stack(PVM pVM, VMCPUID idCpu, RTHCUINTPTR R0Addr, void *pvBuf, size_t cbRead); +VMMR3_INT_DECL(void) VMMR3InitR0StackUnwindState(PUVM pUVM, VMCPUID idCpu, PRTDBGUNWINDSTATE pState); +/** @} */ +#endif /* IN_RING3 */ + + +#if defined(IN_RC) || defined(IN_RING0) || defined(DOXYGEN_RUNNING) +/** @defgroup grp_vmm_api_rz The VMM Raw-Mode and Ring-0 Context API + * @{ + */ +VMMRZDECL(void) VMMRZCallRing3Disable(PVMCPUCC pVCpu); +VMMRZDECL(void) VMMRZCallRing3Enable(PVMCPUCC pVCpu); +VMMRZDECL(bool) VMMRZCallRing3IsEnabled(PVMCPUCC pVCpu); +/** @} */ +#endif + + +/** Wrapper around AssertReleaseMsgReturn that avoid tripping up in the + * kernel when we don't have a setjmp in place. */ +#ifdef IN_RING0 +# define VMM_ASSERT_RELEASE_MSG_RETURN(a_pVM, a_Expr, a_Msg, a_rc) do { \ + if (RT_LIKELY(a_Expr)) { /* likely */ } \ + else \ + { \ + PVMCPUCC pVCpuAssert = VMMGetCpu(a_pVM); \ + if (pVCpuAssert && VMMR0IsLongJumpArmed(pVCpuAssert)) \ + AssertReleaseMsg(a_Expr, a_Msg); \ + else \ + AssertLogRelMsg(a_Expr, a_Msg); \ + return (a_rc); \ + } \ + } while (0) +#else +# define VMM_ASSERT_RELEASE_MSG_RETURN(a_pVM, a_Expr, a_Msg, a_rc) AssertReleaseMsgReturn(a_Expr, a_Msg, a_rc) +#endif + +/** @} */ + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_vmm_h */ diff --git a/include/VBox/vmm/vmmr3vtable-def.h b/include/VBox/vmm/vmmr3vtable-def.h new file mode 100644 index 00000000..b95fdb47 --- /dev/null +++ b/include/VBox/vmm/vmmr3vtable-def.h @@ -0,0 +1,711 @@ +/** @file + * VM - The Virtual Machine Monitor, VTable ring-3 API, Definition Template. + * + * This is used by the vmmr3vtable.h header and the VMMR3VTable.cpp source file + * that implements it. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/** @name VMM + * @{ */ +VTABLE_ENTRY(VMMGetSvnRev) +VTABLE_ENTRY(VMMGetCpu) + +VTABLE_RESERVED(pfnVMMR3Reserved1) +VTABLE_RESERVED(pfnVMMR3Reserved2) +VTABLE_RESERVED(pfnVMMR3Reserved3) +VTABLE_RESERVED(pfnVMMR3Reserved4) +VTABLE_RESERVED(pfnVMMR3Reserved5) +/** @} */ + +/** @name VM + * @{ + */ +VTABLE_ENTRY(VMR3Create) +VTABLE_ENTRY(VMR3PowerOn) +VTABLE_ENTRY(VMR3Suspend) +VTABLE_ENTRY(VMR3GetSuspendReason) +VTABLE_ENTRY(VMR3Resume) +VTABLE_ENTRY(VMR3GetResumeReason) +VTABLE_ENTRY(VMR3Reset) +VTABLE_ENTRY(VMR3Save) +VTABLE_ENTRY(VMR3Teleport) +VTABLE_ENTRY(VMR3LoadFromFile) +VTABLE_ENTRY(VMR3LoadFromStream) +VTABLE_ENTRY(VMR3PowerOff) +VTABLE_ENTRY(VMR3Destroy) + +VTABLE_ENTRY(VMR3GetVM) +VTABLE_ENTRY(VMR3GetUVM) +VTABLE_ENTRY(VMR3RetainUVM) +VTABLE_ENTRY(VMR3ReleaseUVM) +VTABLE_ENTRY(VMR3GetName) +VTABLE_ENTRY(VMR3GetUuid) +VTABLE_ENTRY(VMR3GetState) +VTABLE_ENTRY(VMR3GetStateU) +VTABLE_ENTRY(VMR3GetStateName) +VTABLE_ENTRY(VMR3AtStateRegister) +VTABLE_ENTRY(VMR3AtStateDeregister) +VTABLE_ENTRY(VMR3AtErrorRegister) +VTABLE_ENTRY(VMR3AtErrorDeregister) +VTABLE_ENTRY(VMR3SetError) +VTABLE_ENTRY(VMR3SetErrorV) +VTABLE_ENTRY(VMR3AtRuntimeErrorRegister) +VTABLE_ENTRY(VMR3AtRuntimeErrorDeregister) + +VTABLE_ENTRY(VMR3ReqCallU) +VTABLE_ENTRY(VMR3ReqCallVU) +VTABLE_ENTRY(VMR3ReqCallWaitU) +VTABLE_ENTRY(VMR3ReqCallNoWait) +VTABLE_ENTRY(VMR3ReqCallNoWaitU) +VTABLE_ENTRY(VMR3ReqCallVoidWaitU) +VTABLE_ENTRY(VMR3ReqCallVoidNoWait) +VTABLE_ENTRY(VMR3ReqPriorityCallWait) +VTABLE_ENTRY(VMR3ReqPriorityCallWaitU) +VTABLE_ENTRY(VMR3ReqPriorityCallVoidWaitU) +VTABLE_ENTRY(VMR3ReqAlloc) +VTABLE_ENTRY(VMR3ReqFree) +VTABLE_ENTRY(VMR3ReqQueue) +VTABLE_ENTRY(VMR3ReqWait) + +VTABLE_ENTRY(VMR3NotifyCpuDeviceReady) +VTABLE_ENTRY(VMR3WaitForDeviceReady) +VTABLE_ENTRY(VMR3GetVMCPUThread) +VTABLE_ENTRY(VMR3GetVMCPUNativeThread) +VTABLE_ENTRY(VMR3GetVMCPUNativeThreadU) +VTABLE_ENTRY(VMR3GetCpuCoreAndPackageIdFromCpuId) +VTABLE_ENTRY(VMR3HotUnplugCpu) +VTABLE_ENTRY(VMR3HotPlugCpu) +VTABLE_ENTRY(VMR3SetCpuExecutionCap) +VTABLE_ENTRY(VMR3SetPowerOffInsteadOfReset) + +VTABLE_RESERVED(pfnVMR3Reserved1) +VTABLE_RESERVED(pfnVMR3Reserved2) +VTABLE_RESERVED(pfnVMR3Reserved3) +VTABLE_RESERVED(pfnVMR3Reserved4) +VTABLE_RESERVED(pfnVMR3Reserved5) +/** @} */ + +/** @name CFGM + * @{ */ +VTABLE_ENTRY(CFGMR3Init) +VTABLE_ENTRY(CFGMR3Term) +VTABLE_ENTRY(CFGMR3ConstructDefaultTree) + +VTABLE_ENTRY(CFGMR3CreateTree) +VTABLE_ENTRY(CFGMR3DestroyTree) +VTABLE_ENTRY(CFGMR3Dump) +VTABLE_ENTRY(CFGMR3DuplicateSubTree) +VTABLE_ENTRY(CFGMR3ReplaceSubTree) +VTABLE_ENTRY(CFGMR3InsertSubTree) +VTABLE_ENTRY(CFGMR3InsertNode) +VTABLE_ENTRY(CFGMR3InsertNodeF) +VTABLE_ENTRY(CFGMR3InsertNodeFV) +VTABLE_ENTRY(CFGMR3SetRestrictedRoot) +VTABLE_ENTRY(CFGMR3RemoveNode) +VTABLE_ENTRY(CFGMR3InsertInteger) +VTABLE_ENTRY(CFGMR3InsertString) +VTABLE_ENTRY(CFGMR3InsertStringN) +VTABLE_ENTRY(CFGMR3InsertStringF) +VTABLE_ENTRY(CFGMR3InsertStringFV) +VTABLE_ENTRY(CFGMR3InsertStringW) +VTABLE_ENTRY(CFGMR3InsertBytes) +VTABLE_ENTRY(CFGMR3InsertPassword) +VTABLE_ENTRY(CFGMR3InsertPasswordN) +VTABLE_ENTRY(CFGMR3InsertValue) +VTABLE_ENTRY(CFGMR3RemoveValue) +VTABLE_ENTRY(CFGMR3CopyTree) + +VTABLE_ENTRY(CFGMR3Exists) +VTABLE_ENTRY(CFGMR3QueryType) +VTABLE_ENTRY(CFGMR3QuerySize) +VTABLE_ENTRY(CFGMR3QueryInteger) +VTABLE_ENTRY(CFGMR3QueryIntegerDef) +VTABLE_ENTRY(CFGMR3QueryString) +VTABLE_ENTRY(CFGMR3QueryStringDef) +VTABLE_ENTRY(CFGMR3QueryPassword) +VTABLE_ENTRY(CFGMR3QueryPasswordDef) +VTABLE_ENTRY(CFGMR3QueryBytes) + +VTABLE_ENTRY(CFGMR3QueryU64) +VTABLE_ENTRY(CFGMR3QueryU64Def) +VTABLE_ENTRY(CFGMR3QueryS64) +VTABLE_ENTRY(CFGMR3QueryS64Def) +VTABLE_ENTRY(CFGMR3QueryU32) +VTABLE_ENTRY(CFGMR3QueryU32Def) +VTABLE_ENTRY(CFGMR3QueryS32) +VTABLE_ENTRY(CFGMR3QueryS32Def) +VTABLE_ENTRY(CFGMR3QueryU16) +VTABLE_ENTRY(CFGMR3QueryU16Def) +VTABLE_ENTRY(CFGMR3QueryS16) +VTABLE_ENTRY(CFGMR3QueryS16Def) +VTABLE_ENTRY(CFGMR3QueryU8) +VTABLE_ENTRY(CFGMR3QueryU8Def) +VTABLE_ENTRY(CFGMR3QueryS8) +VTABLE_ENTRY(CFGMR3QueryS8Def) +VTABLE_ENTRY(CFGMR3QueryBool) +VTABLE_ENTRY(CFGMR3QueryBoolDef) +VTABLE_ENTRY(CFGMR3QueryPort) +VTABLE_ENTRY(CFGMR3QueryPortDef) +VTABLE_ENTRY(CFGMR3QueryUInt) +VTABLE_ENTRY(CFGMR3QueryUIntDef) +VTABLE_ENTRY(CFGMR3QuerySInt) +VTABLE_ENTRY(CFGMR3QuerySIntDef) +VTABLE_ENTRY(CFGMR3QueryGCPtr) +VTABLE_ENTRY(CFGMR3QueryGCPtrDef) +VTABLE_ENTRY(CFGMR3QueryGCPtrU) +VTABLE_ENTRY(CFGMR3QueryGCPtrUDef) +VTABLE_ENTRY(CFGMR3QueryGCPtrS) +VTABLE_ENTRY(CFGMR3QueryGCPtrSDef) +VTABLE_ENTRY(CFGMR3QueryStringAlloc) +VTABLE_ENTRY(CFGMR3QueryStringAllocDef) + +VTABLE_ENTRY(CFGMR3GetRoot) +VTABLE_ENTRY(CFGMR3GetRootU) +VTABLE_ENTRY(CFGMR3GetParent) +VTABLE_ENTRY(CFGMR3GetParentEx) +VTABLE_ENTRY(CFGMR3GetChild) +VTABLE_ENTRY(CFGMR3GetChildF) +VTABLE_ENTRY(CFGMR3GetChildFV) +VTABLE_ENTRY(CFGMR3GetFirstChild) +VTABLE_ENTRY(CFGMR3GetNextChild) +VTABLE_ENTRY(CFGMR3GetName) +VTABLE_ENTRY(CFGMR3GetNameLen) +VTABLE_ENTRY(CFGMR3AreChildrenValid) +VTABLE_ENTRY(CFGMR3GetFirstValue) +VTABLE_ENTRY(CFGMR3GetNextValue) +VTABLE_ENTRY(CFGMR3GetValueName) +VTABLE_ENTRY(CFGMR3GetValueNameLen) +VTABLE_ENTRY(CFGMR3GetValueType) +VTABLE_ENTRY(CFGMR3AreValuesValid) +VTABLE_ENTRY(CFGMR3ValidateConfig) + +VTABLE_RESERVED(pfnCFMGR3Reserved1) +VTABLE_RESERVED(pfnCFMGR3Reserved2) +VTABLE_RESERVED(pfnCFMGR3Reserved3) +VTABLE_RESERVED(pfnCFMGR3Reserved4) +VTABLE_RESERVED(pfnCFMGR3Reserved5) +/** @} */ + +/** @name SSM + * @{ */ +VTABLE_ENTRY(SSMR3Term) +VTABLE_ENTRY(SSMR3RegisterInternal) +VTABLE_ENTRY(SSMR3RegisterExternal) +VTABLE_ENTRY(SSMR3RegisterStub) +VTABLE_ENTRY(SSMR3DeregisterInternal) +VTABLE_ENTRY(SSMR3DeregisterExternal) +VTABLE_ENTRY(SSMR3Save) +VTABLE_ENTRY(SSMR3Load) +VTABLE_ENTRY(SSMR3ValidateFile) +VTABLE_ENTRY(SSMR3Open) +VTABLE_ENTRY(SSMR3Close) +VTABLE_ENTRY(SSMR3Seek) +VTABLE_ENTRY(SSMR3HandleGetStatus) +VTABLE_ENTRY(SSMR3HandleSetStatus) +VTABLE_ENTRY(SSMR3HandleGetAfter) +VTABLE_ENTRY(SSMR3HandleIsLiveSave) +VTABLE_ENTRY(SSMR3HandleMaxDowntime) +VTABLE_ENTRY(SSMR3HandleHostBits) +VTABLE_ENTRY(SSMR3HandleRevision) +VTABLE_ENTRY(SSMR3HandleVersion) +VTABLE_ENTRY(SSMR3HandleHostOSAndArch) +VTABLE_ENTRY(SSMR3HandleReportLivePercent) +VTABLE_ENTRY(SSMR3Cancel) + +VTABLE_ENTRY(SSMR3PutStruct) +VTABLE_ENTRY(SSMR3PutStructEx) +VTABLE_ENTRY(SSMR3PutBool) +VTABLE_ENTRY(SSMR3PutU8) +VTABLE_ENTRY(SSMR3PutS8) +VTABLE_ENTRY(SSMR3PutU16) +VTABLE_ENTRY(SSMR3PutS16) +VTABLE_ENTRY(SSMR3PutU32) +VTABLE_ENTRY(SSMR3PutS32) +VTABLE_ENTRY(SSMR3PutU64) +VTABLE_ENTRY(SSMR3PutS64) +VTABLE_ENTRY(SSMR3PutU128) +VTABLE_ENTRY(SSMR3PutS128) +VTABLE_ENTRY(SSMR3PutUInt) +VTABLE_ENTRY(SSMR3PutSInt) +VTABLE_ENTRY(SSMR3PutGCUInt) +VTABLE_ENTRY(SSMR3PutGCUIntReg) +VTABLE_ENTRY(SSMR3PutGCPhys32) +VTABLE_ENTRY(SSMR3PutGCPhys64) +VTABLE_ENTRY(SSMR3PutGCPhys) +VTABLE_ENTRY(SSMR3PutGCPtr) +VTABLE_ENTRY(SSMR3PutGCUIntPtr) +VTABLE_ENTRY(SSMR3PutRCPtr) +VTABLE_ENTRY(SSMR3PutIOPort) +VTABLE_ENTRY(SSMR3PutSel) +VTABLE_ENTRY(SSMR3PutMem) +VTABLE_ENTRY(SSMR3PutStrZ) + +VTABLE_ENTRY(SSMR3GetStruct) +VTABLE_ENTRY(SSMR3GetStructEx) +VTABLE_ENTRY(SSMR3GetBool) +VTABLE_ENTRY(SSMR3GetBoolV) +VTABLE_ENTRY(SSMR3GetU8) +VTABLE_ENTRY(SSMR3GetU8V) +VTABLE_ENTRY(SSMR3GetS8) +VTABLE_ENTRY(SSMR3GetS8V) +VTABLE_ENTRY(SSMR3GetU16) +VTABLE_ENTRY(SSMR3GetU16V) +VTABLE_ENTRY(SSMR3GetS16) +VTABLE_ENTRY(SSMR3GetS16V) +VTABLE_ENTRY(SSMR3GetU32) +VTABLE_ENTRY(SSMR3GetU32V) +VTABLE_ENTRY(SSMR3GetS32) +VTABLE_ENTRY(SSMR3GetS32V) +VTABLE_ENTRY(SSMR3GetU64) +VTABLE_ENTRY(SSMR3GetU64V) +VTABLE_ENTRY(SSMR3GetS64) +VTABLE_ENTRY(SSMR3GetS64V) +VTABLE_ENTRY(SSMR3GetU128) +VTABLE_ENTRY(SSMR3GetU128V) +VTABLE_ENTRY(SSMR3GetS128) +VTABLE_ENTRY(SSMR3GetS128V) +VTABLE_ENTRY(SSMR3GetGCPhys32) +VTABLE_ENTRY(SSMR3GetGCPhys32V) +VTABLE_ENTRY(SSMR3GetGCPhys64) +VTABLE_ENTRY(SSMR3GetGCPhys64V) +VTABLE_ENTRY(SSMR3GetGCPhys) +VTABLE_ENTRY(SSMR3GetGCPhysV) +VTABLE_ENTRY(SSMR3GetUInt) +VTABLE_ENTRY(SSMR3GetSInt) +VTABLE_ENTRY(SSMR3GetGCUInt) +VTABLE_ENTRY(SSMR3GetGCUIntReg) +VTABLE_ENTRY(SSMR3GetGCPtr) +VTABLE_ENTRY(SSMR3GetGCUIntPtr) +VTABLE_ENTRY(SSMR3GetRCPtr) +VTABLE_ENTRY(SSMR3GetIOPort) +VTABLE_ENTRY(SSMR3GetSel) +VTABLE_ENTRY(SSMR3GetMem) +VTABLE_ENTRY(SSMR3GetStrZ) +VTABLE_ENTRY(SSMR3GetStrZEx) +VTABLE_ENTRY(SSMR3Skip) +VTABLE_ENTRY(SSMR3SkipToEndOfUnit) +VTABLE_ENTRY(SSMR3SetLoadError) +VTABLE_ENTRY(SSMR3SetLoadErrorV) +VTABLE_ENTRY(SSMR3SetCfgError) +VTABLE_ENTRY(SSMR3SetCfgErrorV) + +VTABLE_RESERVED(pfnSSMR3Reserved1) +VTABLE_RESERVED(pfnSSMR3Reserved2) +VTABLE_RESERVED(pfnSSMR3Reserved3) +VTABLE_RESERVED(pfnSSMR3Reserved4) +VTABLE_RESERVED(pfnSSMR3Reserved5) +/** @} */ + +/** @name STAM + * @{ */ +VTABLE_ENTRY(STAMR3InitUVM) +VTABLE_ENTRY(STAMR3TermUVM) +VTABLE_ENTRY(STAMR3RegisterU) +VTABLE_ENTRY(STAMR3Register) +VTABLE_ENTRY(STAMR3RegisterFU) +VTABLE_ENTRY(STAMR3RegisterF) +VTABLE_ENTRY(STAMR3RegisterVU) +VTABLE_ENTRY(STAMR3RegisterV) +VTABLE_ENTRY(STAMR3RegisterCallback) +VTABLE_ENTRY(STAMR3RegisterCallbackV) +VTABLE_ENTRY(STAMR3RegisterRefresh) +VTABLE_ENTRY(STAMR3RegisterRefreshV) +VTABLE_ENTRY(STAMR3Deregister) +VTABLE_ENTRY(STAMR3DeregisterF) +VTABLE_ENTRY(STAMR3DeregisterV) +VTABLE_ENTRY(STAMR3DeregisterByPrefix) +VTABLE_ENTRY(STAMR3DeregisterByAddr) +VTABLE_ENTRY(STAMR3Reset) +VTABLE_ENTRY(STAMR3Snapshot) +VTABLE_ENTRY(STAMR3SnapshotFree) +VTABLE_ENTRY(STAMR3Dump) +VTABLE_ENTRY(STAMR3DumpToReleaseLog) +VTABLE_ENTRY(STAMR3Print) +VTABLE_ENTRY(STAMR3Enum) +VTABLE_ENTRY(STAMR3GetUnit) +VTABLE_ENTRY(STAMR3GetUnit1) +VTABLE_ENTRY(STAMR3GetUnit2) + +VTABLE_RESERVED(pfnSTAMR3Reserved1) +VTABLE_RESERVED(pfnSTAMR3Reserved2) +VTABLE_RESERVED(pfnSTAMR3Reserved3) +VTABLE_RESERVED(pfnSTAMR3Reserved4) +VTABLE_RESERVED(pfnSTAMR3Reserved5) +/** @} */ + +/** @name CPUM + * @{ */ +VTABLE_ENTRY(CPUMGetHostCpuVendor) +VTABLE_ENTRY(CPUMGetHostMicroarch) + +VTABLE_RESERVED(pfnCPUMR3Reserved1) +VTABLE_RESERVED(pfnCPUMR3Reserved2) +VTABLE_RESERVED(pfnCPUMR3Reserved3) +VTABLE_RESERVED(pfnCPUMR3Reserved4) +VTABLE_RESERVED(pfnCPUMR3Reserved5) +/** @} */ + +/** @name DBGC + * @{ */ +VTABLE_ENTRY(DBGCCreate) + +VTABLE_RESERVED(pfnDBGCR3Reserved1) +VTABLE_RESERVED(pfnDBGCR3Reserved2) +VTABLE_RESERVED(pfnDBGCR3Reserved3) +VTABLE_RESERVED(pfnDBGCR3Reserved4) +VTABLE_RESERVED(pfnDBGCR3Reserved5) +/** @} */ + +/** @name DBGF + * @{ */ +VTABLE_ENTRY(DBGFR3BpClear) +VTABLE_ENTRY(DBGFR3BpDisable) +VTABLE_ENTRY(DBGFR3BpEnable) +VTABLE_ENTRY(DBGFR3BpOwnerCreate) +VTABLE_ENTRY(DBGFR3BpOwnerDestroy) +VTABLE_ENTRY(DBGFR3BpSetInt3) +VTABLE_ENTRY(DBGFR3BpSetInt3Ex) +VTABLE_ENTRY(DBGFR3BpSetMmio) +VTABLE_ENTRY(DBGFR3BpSetMmioEx) +VTABLE_ENTRY(DBGFR3BpSetPortIo) +VTABLE_ENTRY(DBGFR3BpSetPortIoEx) +VTABLE_ENTRY(DBGFR3BpSetReg) +VTABLE_ENTRY(DBGFR3BpSetRegEx) +VTABLE_ENTRY(DBGFR3BpSetREM) +VTABLE_ENTRY(DBGFR3CoreWrite) +VTABLE_ENTRY(DBGFR3Info) +VTABLE_ENTRY(DBGFR3InfoRegisterExternal) +VTABLE_ENTRY(DBGFR3InfoDeregisterExternal) +VTABLE_ENTRY(DBGFR3InfoGenericGetOptError) +VTABLE_ENTRY(DBGFR3InjectNMI) +VTABLE_ENTRY(DBGFR3LogModifyDestinations) +VTABLE_ENTRY(DBGFR3LogModifyFlags) +VTABLE_ENTRY(DBGFR3LogModifyGroups) +VTABLE_ENTRY(DBGFR3OSDetect) +VTABLE_ENTRY(DBGFR3OSQueryNameAndVersion) +VTABLE_ENTRY(DBGFR3RegCpuQueryU8) +VTABLE_ENTRY(DBGFR3RegCpuQueryU16) +VTABLE_ENTRY(DBGFR3RegCpuQueryU32) +VTABLE_ENTRY(DBGFR3RegCpuQueryU64) +VTABLE_ENTRY(DBGFR3RegCpuQueryXdtr) +VTABLE_ENTRY(DBGFR3RegFormatValue) +VTABLE_ENTRY(DBGFR3RegNmQuery) +VTABLE_ENTRY(DBGFR3RegNmQueryAll) +VTABLE_ENTRY(DBGFR3RegNmQueryAllCount) +VTABLE_ENTRY(DBGFR3RegNmSetBatch) +VTABLE_ENTRY(DBGFR3OSDeregister) +VTABLE_ENTRY(DBGFR3OSRegister) +VTABLE_ENTRY(DBGFR3OSQueryInterface) +VTABLE_ENTRY(DBGFR3MemReadString) +VTABLE_ENTRY(DBGFR3MemRead) +VTABLE_ENTRY(DBGFR3MemScan) +VTABLE_ENTRY(DBGFR3ModInMem) +VTABLE_ENTRY(DBGFR3AddrFromFlat) +VTABLE_ENTRY(DBGFR3AsSymbolByName) +VTABLE_ENTRY(DBGFR3AsResolveAndRetain) +VTABLE_ENTRY(DBGFR3AsSetAlias) +VTABLE_ENTRY(DBGFR3AddrAdd) +VTABLE_ENTRY(DBGFR3AddrSub) +VTABLE_ENTRY(DBGFR3AsGetConfig) +VTABLE_ENTRY(DBGFR3CpuGetCount) +VTABLE_ENTRY(DBGFR3CpuGetMode) +VTABLE_ENTRY(DBGFR3CpuGetState) +VTABLE_ENTRY(DBGFR3AddrFromSelOff) +VTABLE_ENTRY(DBGFR3FlowCreate) +VTABLE_ENTRY(DBGFR3FlowRetain) +VTABLE_ENTRY(DBGFR3FlowRelease) +VTABLE_ENTRY(DBGFR3FlowQueryStartBb) +VTABLE_ENTRY(DBGFR3FlowQueryBbByAddress) +VTABLE_ENTRY(DBGFR3FlowQueryBranchTblByAddress) +VTABLE_ENTRY(DBGFR3FlowGetBbCount) +VTABLE_ENTRY(DBGFR3FlowGetBranchTblCount) +VTABLE_ENTRY(DBGFR3FlowGetCallInsnCount) +VTABLE_ENTRY(DBGFR3FlowBbRetain) +VTABLE_ENTRY(DBGFR3FlowBbRelease) +VTABLE_ENTRY(DBGFR3FlowBbGetStartAddress) +VTABLE_ENTRY(DBGFR3FlowBbGetEndAddress) +VTABLE_ENTRY(DBGFR3FlowBbGetBranchAddress) +VTABLE_ENTRY(DBGFR3FlowBbGetFollowingAddress) +VTABLE_ENTRY(DBGFR3FlowBbGetType) +VTABLE_ENTRY(DBGFR3FlowBbGetInstrCount) +VTABLE_ENTRY(DBGFR3FlowBbGetFlags) +VTABLE_ENTRY(DBGFR3FlowBbQueryBranchTbl) +VTABLE_ENTRY(DBGFR3FlowBbQueryError) +VTABLE_ENTRY(DBGFR3FlowBbQueryInstr) +VTABLE_ENTRY(DBGFR3FlowBbQuerySuccessors) +VTABLE_ENTRY(DBGFR3FlowBbGetRefBbCount) +VTABLE_ENTRY(DBGFR3FlowBbGetRefBb) +VTABLE_ENTRY(DBGFR3FlowBranchTblRetain) +VTABLE_ENTRY(DBGFR3FlowBranchTblRelease) +VTABLE_ENTRY(DBGFR3FlowBranchTblGetSlots) +VTABLE_ENTRY(DBGFR3FlowBranchTblGetStartAddress) +VTABLE_ENTRY(DBGFR3FlowBranchTblGetAddrAtSlot) +VTABLE_ENTRY(DBGFR3FlowBranchTblQueryAddresses) +VTABLE_ENTRY(DBGFR3FlowItCreate) +VTABLE_ENTRY(DBGFR3FlowItDestroy) +VTABLE_ENTRY(DBGFR3FlowItNext) +VTABLE_ENTRY(DBGFR3FlowItReset) +VTABLE_ENTRY(DBGFR3FlowBranchTblItCreate) +VTABLE_ENTRY(DBGFR3FlowBranchTblItDestroy) +VTABLE_ENTRY(DBGFR3FlowBranchTblItNext) +VTABLE_ENTRY(DBGFR3FlowBranchTblItReset) +VTABLE_ENTRY(DBGFR3FlowTraceModCreate) +VTABLE_ENTRY(DBGFR3FlowTraceModCreateFromFlowGraph) +VTABLE_ENTRY(DBGFR3FlowTraceModRetain) +VTABLE_ENTRY(DBGFR3FlowTraceModRelease) +VTABLE_ENTRY(DBGFR3FlowTraceModEnable) +VTABLE_ENTRY(DBGFR3FlowTraceModDisable) +VTABLE_ENTRY(DBGFR3FlowTraceModQueryReport) +VTABLE_ENTRY(DBGFR3FlowTraceModClear) +VTABLE_ENTRY(DBGFR3FlowTraceModAddProbe) +VTABLE_ENTRY(DBGFR3FlowTraceProbeCreate) +VTABLE_ENTRY(DBGFR3FlowTraceProbeRetain) +VTABLE_ENTRY(DBGFR3FlowTraceProbeRelease) +VTABLE_ENTRY(DBGFR3FlowTraceProbeEntriesAdd) +VTABLE_ENTRY(DBGFR3FlowTraceReportRetain) +VTABLE_ENTRY(DBGFR3FlowTraceReportRelease) +VTABLE_ENTRY(DBGFR3FlowTraceReportGetRecordCount) +VTABLE_ENTRY(DBGFR3FlowTraceReportQueryRecord) +VTABLE_ENTRY(DBGFR3FlowTraceReportQueryFiltered) +VTABLE_ENTRY(DBGFR3FlowTraceReportEnumRecords) +VTABLE_ENTRY(DBGFR3FlowTraceRecordRetain) +VTABLE_ENTRY(DBGFR3FlowTraceRecordRelease) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetSeqNo) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetTimestamp) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetAddr) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetProbe) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetValCount) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetVals) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetValsCommon) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetCpuId) +VTABLE_ENTRY(DBGFR3PlugInLoad) +VTABLE_ENTRY(DBGFR3PlugInUnload) +VTABLE_ENTRY(DBGFR3PlugInLoadAll) +VTABLE_ENTRY(DBGFR3PlugInUnloadAll) +VTABLE_ENTRY(DBGFR3SampleReportCreate) +VTABLE_ENTRY(DBGFR3SampleReportRetain) +VTABLE_ENTRY(DBGFR3SampleReportRelease) +VTABLE_ENTRY(DBGFR3SampleReportStart) +VTABLE_ENTRY(DBGFR3SampleReportStop) +VTABLE_ENTRY(DBGFR3SampleReportDumpToFile) +VTABLE_ENTRY(DBGFR3SelQueryInfo) +VTABLE_ENTRY(DBGFR3StackWalkBegin) +VTABLE_ENTRY(DBGFR3StackWalkNext) +VTABLE_ENTRY(DBGFR3StackWalkEnd) +VTABLE_ENTRY(DBGFR3TypeDeregister) +VTABLE_ENTRY(DBGFR3TypeDumpEx) +VTABLE_ENTRY(DBGFR3TypeQueryReg) +VTABLE_ENTRY(DBGFR3TypeQuerySize) +VTABLE_ENTRY(DBGFR3TypeQueryValByType) +VTABLE_ENTRY(DBGFR3TypeRegister) +VTABLE_ENTRY(DBGFR3TypeSetSize) +VTABLE_ENTRY(DBGFR3TypeValFree) +VTABLE_ENTRY(DBGFR3TypeValDumpEx) + +VTABLE_RESERVED(pfnDBGFR3Reserved1) +VTABLE_RESERVED(pfnDBGFR3Reserved2) +VTABLE_RESERVED(pfnDBGFR3Reserved3) +VTABLE_RESERVED(pfnDBGFR3Reserved4) +VTABLE_RESERVED(pfnDBGFR3Reserved5) +/** @} */ + +/** @name EM + * @{ */ +VTABLE_ENTRY(EMR3QueryExecutionPolicy) +VTABLE_ENTRY(EMR3QueryMainExecutionEngine) +VTABLE_ENTRY(EMR3SetExecutionPolicy) + +VTABLE_RESERVED(pfnEMR3Reserved1) +VTABLE_RESERVED(pfnEMR3Reserved2) +VTABLE_RESERVED(pfnEMR3Reserved3) +VTABLE_RESERVED(pfnEMR3Reserved4) +VTABLE_RESERVED(pfnEMR3Reserved5) +/** @} */ + +/** @name HM + * @{ */ +VTABLE_ENTRY(HMR3IsEnabled) +VTABLE_ENTRY(HMR3IsNestedPagingActive) +VTABLE_ENTRY(HMR3IsUXActive) +VTABLE_ENTRY(HMR3IsVpidActive) + +VTABLE_RESERVED(pfnHMR3Reserved1) +VTABLE_RESERVED(pfnHMR3Reserved2) +VTABLE_RESERVED(pfnHMR3Reserved3) +VTABLE_RESERVED(pfnHMR3Reserved4) +VTABLE_RESERVED(pfnHMR3Reserved5) +/** @} */ + +/** @name MM + * @{ */ +VTABLE_ENTRY(MMR3HeapAllocU) +VTABLE_ENTRY(MMR3HeapAllocExU) +VTABLE_ENTRY(MMR3HeapAllocZU) +VTABLE_ENTRY(MMR3HeapAllocZExU) +VTABLE_ENTRY(MMR3HeapRealloc) +VTABLE_ENTRY(MMR3HeapStrDupU) +VTABLE_ENTRY(MMR3HeapAPrintfU) +VTABLE_ENTRY(MMR3HeapAPrintfVU) +VTABLE_ENTRY(MMR3HeapFree) + +VTABLE_RESERVED(pfnMMR3Reserved1) +VTABLE_RESERVED(pfnMMR3Reserved2) +VTABLE_RESERVED(pfnMMR3Reserved3) +VTABLE_RESERVED(pfnMMR3Reserved4) +VTABLE_RESERVED(pfnMMR3Reserved5) +/** @} */ + +/** @name PDM + * @{ */ +VTABLE_ENTRY(PDMR3AsyncCompletionBwMgrSetMaxForFile) +VTABLE_ENTRY(PDMR3DeviceAttach) +VTABLE_ENTRY(PDMR3DeviceDetach) +VTABLE_ENTRY(PDMR3DriverAttach) +VTABLE_ENTRY(PDMR3DriverDetach) +VTABLE_ENTRY(PDMR3NsBwGroupSetLimit) +VTABLE_ENTRY(PDMR3QueryDeviceLun) +VTABLE_ENTRY(PDMR3QueryDriverOnLun) +VTABLE_ENTRY(PDMR3QueryLun) + +VTABLE_ENTRY(PDMCritSectEnter) +VTABLE_ENTRY(PDMCritSectEnterDebug) +VTABLE_ENTRY(PDMCritSectTryEnter) +VTABLE_ENTRY(PDMCritSectTryEnterDebug) +VTABLE_ENTRY(PDMR3CritSectEnterEx) +VTABLE_ENTRY(PDMCritSectLeave) +VTABLE_ENTRY(PDMCritSectIsOwner) +VTABLE_ENTRY(PDMCritSectIsOwnerEx) +VTABLE_ENTRY(PDMCritSectIsInitialized) +VTABLE_ENTRY(PDMCritSectHasWaiters) +VTABLE_ENTRY(PDMCritSectGetRecursion) +VTABLE_ENTRY(PDMR3CritSectYield) +VTABLE_ENTRY(PDMR3CritSectName) +VTABLE_ENTRY(PDMR3CritSectDelete) + +VTABLE_ENTRY(PDMQueueAlloc) +VTABLE_ENTRY(PDMQueueInsert) +VTABLE_RESERVED(pfnPDMR3Reserved11) + +VTABLE_ENTRY(PDMR3ThreadDestroy) +VTABLE_ENTRY(PDMR3ThreadIAmRunning) +VTABLE_ENTRY(PDMR3ThreadIAmSuspending) +VTABLE_ENTRY(PDMR3ThreadResume) +VTABLE_ENTRY(PDMR3ThreadSleep) +VTABLE_ENTRY(PDMR3ThreadSuspend) + +VTABLE_ENTRY(PDMR3UsbCreateEmulatedDevice) +VTABLE_ENTRY(PDMR3UsbCreateProxyDevice) +VTABLE_ENTRY(PDMR3UsbDetachDevice) +VTABLE_ENTRY(PDMR3UsbHasHub) +VTABLE_ENTRY(PDMR3UsbDriverAttach) +VTABLE_ENTRY(PDMR3UsbDriverDetach) +VTABLE_ENTRY(PDMR3UsbQueryLun) +VTABLE_ENTRY(PDMR3UsbQueryDriverOnLun) + +VTABLE_RESERVED(pfnPDMR3Reserved1) +VTABLE_RESERVED(pfnPDMR3Reserved2) +VTABLE_RESERVED(pfnPDMR3Reserved3) +VTABLE_RESERVED(pfnPDMR3Reserved4) +VTABLE_RESERVED(pfnPDMR3Reserved5) +VTABLE_RESERVED(pfnPDMR3Reserved6) +VTABLE_RESERVED(pfnPDMR3Reserved7) +VTABLE_RESERVED(pfnPDMR3Reserved8) +VTABLE_RESERVED(pfnPDMR3Reserved9) +VTABLE_RESERVED(pfnPDMR3Reserved10) +/** @} */ + +/** @name PGM + * @{ */ +VTABLE_ENTRY(PGMHandlerPhysicalPageTempOff) +VTABLE_ENTRY(PGMPhysReadGCPtr) +VTABLE_ENTRY(PGMPhysSimpleDirtyWriteGCPtr) +VTABLE_ENTRY(PGMPhysSimpleReadGCPtr) +VTABLE_ENTRY(PGMPhysSimpleWriteGCPhys) +VTABLE_ENTRY(PGMPhysSimpleWriteGCPtr) +VTABLE_ENTRY(PGMPhysWriteGCPtr) +VTABLE_ENTRY(PGMShwMakePageWritable) +VTABLE_ENTRY(PGMR3QueryGlobalMemoryStats) +VTABLE_ENTRY(PGMR3QueryMemoryStats) + +VTABLE_RESERVED(pfnPGMR3Reserved1) +VTABLE_RESERVED(pfnPGMR3Reserved2) +VTABLE_RESERVED(pfnPGMR3Reserved3) +VTABLE_RESERVED(pfnPGMR3Reserved4) +VTABLE_RESERVED(pfnPGMR3Reserved5) +/** @} */ + +/** @name TM + * @{ */ +VTABLE_ENTRY(TMR3GetCpuLoadPercents) +VTABLE_ENTRY(TMR3TimerSetCritSect) +VTABLE_ENTRY(TMR3TimerLoad) +VTABLE_ENTRY(TMR3TimerSave) +VTABLE_ENTRY(TMR3TimerSkip) +VTABLE_ENTRY(TMR3TimerDestroy) +VTABLE_ENTRY(TMTimerFromMicro) +VTABLE_ENTRY(TMTimerFromMilli) +VTABLE_ENTRY(TMTimerFromNano) +VTABLE_ENTRY(TMTimerGet) +VTABLE_ENTRY(TMTimerGetFreq) +VTABLE_ENTRY(TMTimerGetMicro) +VTABLE_ENTRY(TMTimerGetMilli) +VTABLE_ENTRY(TMTimerGetNano) +VTABLE_ENTRY(TMTimerIsActive) +VTABLE_ENTRY(TMTimerIsLockOwner) +VTABLE_ENTRY(TMTimerLock) +VTABLE_ENTRY(TMTimerSet) +VTABLE_ENTRY(TMTimerSetFrequencyHint) +VTABLE_ENTRY(TMTimerSetMicro) +VTABLE_ENTRY(TMTimerSetMillies) +VTABLE_ENTRY(TMTimerSetNano) +VTABLE_ENTRY(TMTimerSetRelative) +VTABLE_ENTRY(TMTimerStop) +VTABLE_ENTRY(TMTimerToMicro) +VTABLE_ENTRY(TMTimerToMilli) +VTABLE_ENTRY(TMTimerToNano) +VTABLE_ENTRY(TMTimerUnlock) +VTABLE_ENTRY(TMR3GetWarpDrive) +VTABLE_ENTRY(TMR3SetWarpDrive) +VTABLE_ENTRY(TMR3TimeVirtGet) +VTABLE_ENTRY(TMR3TimeVirtGetMicro) +VTABLE_ENTRY(TMR3TimeVirtGetMilli) +VTABLE_ENTRY(TMR3TimeVirtGetNano) + +VTABLE_RESERVED(pfnTMR3Reserved1) +VTABLE_RESERVED(pfnTMR3Reserved2) +VTABLE_RESERVED(pfnTMR3Reserved3) +VTABLE_RESERVED(pfnTMR3Reserved4) +VTABLE_RESERVED(pfnTMR3Reserved5) +/** @} */ diff --git a/include/VBox/vmm/vmmr3vtable.h b/include/VBox/vmm/vmmr3vtable.h new file mode 100644 index 00000000..96d88636 --- /dev/null +++ b/include/VBox/vmm/vmmr3vtable.h @@ -0,0 +1,140 @@ +/** @file + * VM - The Virtual Machine Monitor, VTable ring-3 API. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vmmr3vtable_h +#define VBOX_INCLUDED_vmm_vmmr3vtable_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/cfgm.h> +#include <VBox/vmm/cpum.h> +#include <VBox/vmm/dbgf.h> +#include <VBox/vmm/dbgfflowtrace.h> +#include <VBox/vmm/em.h> +#include <VBox/vmm/hm.h> +#include <VBox/vmm/pdmapi.h> +#include <VBox/vmm/pdmasynccompletion.h> +#include <VBox/vmm/pdmcritsect.h> +#include <VBox/vmm/pdmnetshaper.h> +#include <VBox/vmm/pdmqueue.h> +#include <VBox/vmm/pdmusb.h> +#include <VBox/vmm/pdmthread.h> +#include <VBox/vmm/pgm.h> +#include <VBox/vmm/ssm.h> +#include <VBox/vmm/stam.h> +#include <VBox/vmm/tm.h> +#include <VBox/vmm/vmm.h> +#include <VBox/dbg.h> + +#include <iprt/stdarg.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_vmm_vtable VMM Function Table + * @ingroup grp_vmm + * @{ */ + + +/** Magic and version for the VMM vtable. (Magic: Emmet Cohen) */ +#define VMMR3VTABLE_MAGIC_VERSION RT_MAKE_U64(0x19900525, 0x00030000) +/** Compatibility mask: These bits must match - magic and major version. */ +#define VMMR3VTABLE_MAGIC_VERSION_MASK RT_MAKE_U64(0xffffffff, 0xffff0000) + +/** Checks if @a a_uTableMagicVersion can be used by code compiled + * against @a a_CompiledMagicVersion */ +#define VMMR3VTABLE_IS_COMPATIBLE_EX(a_uTableMagicVersion, a_CompiledMagicVersion) \ + ( (a_uTableMagicVersion) >= (a_CompiledMagicVersion) /* table must be same or later version */ \ + && ((a_uTableMagicVersion) & VMMR3VTABLE_MAGIC_VERSION_MASK) == ((a_CompiledMagicVersion) & VMMR3VTABLE_MAGIC_VERSION_MASK) ) + +/** Checks if @a a_uTableMagicVersion can be used by this us. */ +#define VMMR3VTABLE_IS_COMPATIBLE(a_uTableMagicVersion) \ + VMMR3VTABLE_IS_COMPATIBLE_EX(a_uTableMagicVersion, VMMR3VTABLE_MAGIC_VERSION) + + +/** + * Function for getting the vtable of a VMM DLL/SO/DyLib. + * + * @returns the pointer to the vtable. + */ +typedef DECLCALLBACKTYPE(PCVMMR3VTABLE, FNVMMGETVTABLE,(void)); +/** Pointer to VMM vtable getter. */ +typedef FNVMMGETVTABLE *PFNVMMGETVTABLE; +/** The name of the FNVMMGETVTABLE function. */ +#define VMMR3VTABLE_GETTER_NAME "VMMR3GetVTable" + + +/** + * VTable for the ring-3 VMM API. + */ +typedef struct VMMR3VTABLE +{ + /** VMMR3VTABLE_MAGIC_VERSION. */ + uint64_t uMagicVersion; + /** Flags (TBD). */ + uint64_t fFlags; + /** The description of this VMM. */ + const char *pszDescription; + +/** @def VTABLE_ENTRY + * Define a VTable entry for the given function. */ +#if defined(DOXYGEN_RUNNING) \ + || (defined(__cplusplus) && (defined(__clang_major__) || RT_GNUC_PREREQ_EX(4, 8, /*non-gcc: */1) /* For 4.8+ we enable c++11 */)) +# define VTABLE_ENTRY(a_Api) /** @copydoc a_Api */ decltype(a_Api) *pfn ## a_Api; +#elif defined(__GNUC__) +# define VTABLE_ENTRY(a_Api) /** @copydoc a_Api */ typeof(a_Api) *pfn ## a_Api; +#else +# error "Unsupported compiler" +#endif +/** @def VTABLE_RESERVED + * Define a reserved VTable entry with the given name. */ +#define VTABLE_RESERVED(a_Name) DECLCALLBACKMEMBER(int, a_Name,(void)); + +#include "vmmr3vtable-def.h" + +#undef VTABLE_ENTRY +#undef VTABLE_RESERVED + + /** VMMR3VTABLE_MAGIC_VERSION. */ + uint64_t uMagicVersionEnd; +} VMMR3VTABLE; + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_vmmr3vtable_h */ + diff --git a/include/VBox/vrdpusb.h b/include/VBox/vrdpusb.h new file mode 100644 index 00000000..54da45a6 --- /dev/null +++ b/include/VBox/vrdpusb.h @@ -0,0 +1,135 @@ +/** @file + * VBox Remote Desktop Protocol - Remote USB backend interface. (VRDP) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vrdpusb_h +#define VBOX_INCLUDED_vrdpusb_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/types.h> + +#ifdef IN_RING0 +# error "There are no VRDP APIs available in Ring-0 Host Context!" +#endif +#ifdef IN_RC +# error "There are no VRDP APIs available Guest Context!" +#endif + + +/** @defgroup grp_vrdpusb Remote USB over VURP + * @ingroup grp_vusb + * @{ + */ + +#define REMOTE_USB_BACKEND_PREFIX_S "REMOTEUSB" +#define REMOTE_USB_BACKEND_PREFIX_LEN 9 + +/* Forward declaration. */ +struct _REMOTEUSBDEVICE; +typedef struct _REMOTEUSBDEVICE *PREMOTEUSBDEVICE; + +/* Forward declaration. */ +struct _REMOTEUSBQURB; +typedef struct _REMOTEUSBQURB *PREMOTEUSBQURB; + +/* Forward declaration. Actually a class. */ +struct _REMOTEUSBBACKEND; +typedef struct _REMOTEUSBBACKEND *PREMOTEUSBBACKEND; + +/** + * Pointer to this structure is queried from USBREMOTEIF::pfnQueryRemoteUsbBackend. + */ +typedef struct REMOTEUSBCALLBACK +{ + PREMOTEUSBBACKEND pInstance; + + DECLCALLBACKMEMBER(int, pfnOpen,(PREMOTEUSBBACKEND pInstance, const char *pszAddress, size_t cbAddress, PREMOTEUSBDEVICE *ppDevice)); + DECLCALLBACKMEMBER(void, pfnClose,(PREMOTEUSBDEVICE pDevice)); + DECLCALLBACKMEMBER(int, pfnReset,(PREMOTEUSBDEVICE pDevice)); + DECLCALLBACKMEMBER(int, pfnSetConfig,(PREMOTEUSBDEVICE pDevice, uint8_t u8Cfg)); + DECLCALLBACKMEMBER(int, pfnClaimInterface,(PREMOTEUSBDEVICE pDevice, uint8_t u8Ifnum)); + DECLCALLBACKMEMBER(int, pfnReleaseInterface,(PREMOTEUSBDEVICE pDevice, uint8_t u8Ifnum)); + DECLCALLBACKMEMBER(int, pfnInterfaceSetting,(PREMOTEUSBDEVICE pDevice, uint8_t u8Ifnum, uint8_t u8Setting)); + DECLCALLBACKMEMBER(int, pfnQueueURB,(PREMOTEUSBDEVICE pDevice, uint8_t u8Type, uint8_t u8Ep, uint8_t u8Direction, uint32_t u32Len, void *pvData, void *pvURB, PREMOTEUSBQURB *ppRemoteURB)); + DECLCALLBACKMEMBER(int, pfnReapURB,(PREMOTEUSBDEVICE pDevice, uint32_t u32Millies, void **ppvURB, uint32_t *pu32Len, uint32_t *pu32Err)); + DECLCALLBACKMEMBER(int, pfnClearHaltedEP,(PREMOTEUSBDEVICE pDevice, uint8_t u8Ep)); + DECLCALLBACKMEMBER(void, pfnCancelURB,(PREMOTEUSBDEVICE pDevice, PREMOTEUSBQURB pRemoteURB)); + DECLCALLBACKMEMBER(int, pfnWakeup,(PREMOTEUSBDEVICE pDevice)); +} REMOTEUSBCALLBACK; +/** Pointer to a remote USB callback table. */ +typedef REMOTEUSBCALLBACK *PREMOTEUSBCALLBACK; + +/** + * Remote USB interface for querying the remote USB callback table for particular client. + * Returned from the *QueryGenericUserObject when passing REMOTEUSBIF_OID as the identifier. + */ +typedef struct REMOTEUSBIF +{ + /** Opaque user data to pass as the first parameter to the callbacks. */ + void *pvUser; + + /** + * Queries the remote USB interface callback table for a given UUID/client ID pair. + * + * @returns Pointer to the remote USB callback table or NULL if the client ID and or UUID is invalid. + * @param pvUser Opaque user data from this interface. + * @param pUuid The device UUID to query the interface for. + * @param idClient The client ID to query the interface for. + */ + DECLCALLBACKMEMBER(PREMOTEUSBCALLBACK, pfnQueryRemoteUsbBackend, (void *pvUser, PCRTUUID pUuid, uint32_t idClient)); +} REMOTEUSBIF; +/** Pointer to a remote USB interface. */ +typedef REMOTEUSBIF *PREMOTEUSBIF; + +/** The UUID to identify the remote USB interface. */ +#define REMOTEUSBIF_OID "87012f58-2ad6-4f89-b7b1-92f72c7ea8cc" + + +typedef struct EMULATEDUSBIF +{ + /** Opaque user data to pass as the first parameter to the callbacks. */ + void *pvUser; + + DECLCALLBACKMEMBER(int, pfnQueryEmulatedUsbDataById, (void *pvUser, const char *pszId, void **ppvEmUsbCb, void **ppvEmUsbCbData, void **ppvObject)); +} EMULATEDUSBIF; +typedef EMULATEDUSBIF *PEMULATEDUSBIF; + +#define EMULATEDUSBIF_OID "b7b4e194-ada0-4722-8e4e-1700ed9064f3" + +/** @} */ + +#endif /* !VBOX_INCLUDED_vrdpusb_h */ diff --git a/include/VBox/vscsi.h b/include/VBox/vscsi.h new file mode 100644 index 00000000..dea697e2 --- /dev/null +++ b/include/VBox/vscsi.h @@ -0,0 +1,488 @@ +/* $Id: vscsi.h $ */ +/** @file + * VBox storage drivers - Virtual SCSI driver + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vscsi_h +#define VBOX_INCLUDED_vscsi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <VBox/vdmedia.h> +#include <iprt/sg.h> + +RT_C_DECLS_BEGIN + +#ifdef IN_RING0 +# error "There are no VBox VSCSI APIs available in Ring-0 Host Context!" +#endif + +/** @defgroup grp_drv_vscsi Virtual VSCSI Driver + * @ingroup grp_devdrv + * @{ + */ +/** @todo figure better grouping. */ + +/** A virtual SCSI device handle */ +typedef struct VSCSIDEVICEINT *VSCSIDEVICE; +/** A pointer to a virtual SCSI device handle. */ +typedef VSCSIDEVICE *PVSCSIDEVICE; +/** A virtual SCSI LUN handle. */ +typedef struct VSCSILUNINT *VSCSILUN; +/** A pointer to a virtual SCSI LUN handle. */ +typedef VSCSILUN *PVSCSILUN; +/** A virtual SCSI request handle. */ +typedef struct VSCSIREQINT *VSCSIREQ; +/** A pointer to a virtual SCSI request handle. */ +typedef VSCSIREQ *PVSCSIREQ; +/** A SCSI I/O request handle. */ +typedef struct VSCSIIOREQINT *VSCSIIOREQ; +/** A pointer to a SCSI I/O request handle. */ +typedef VSCSIIOREQ *PVSCSIIOREQ; + +/** + * Virtual SCSI I/O request transfer direction. + */ +typedef enum VSCSIIOREQTXDIR +{ + /** Invalid direction */ + VSCSIIOREQTXDIR_INVALID = 0, + /** Read */ + VSCSIIOREQTXDIR_READ, + /** Write */ + VSCSIIOREQTXDIR_WRITE, + /** Flush */ + VSCSIIOREQTXDIR_FLUSH, + /** Unmap */ + VSCSIIOREQTXDIR_UNMAP, + /** 32bit hack */ + VSCSIIOREQTXDIR_32BIT_HACK = 0x7fffffff +} VSCSIIOREQTXDIR; +/** Pointer to a SCSI LUN type */ +typedef VSCSIIOREQTXDIR *PVSCSIIOREQTXDIR; + +/** + * Virtual SCSI transfer direction as seen from the initiator. + */ +typedef enum VSCSIXFERDIR +{ + /** Invalid data direction. */ + PVSCSIXFERDIR_INVALID = 0, + /** Direction is unknown. */ + VSCSIXFERDIR_UNKNOWN, + /** Direction is from target to initiator (aka a read). */ + VSCSIXFERDIR_T2I, + /** Direction is from initiator to device (aka a write). */ + VSCSIXFERDIR_I2T, + /** No data transfer associated with this request. */ + VSCSIXFERDIR_NONE, + /** 32bit hack. */ + VSCSIXFERDIR_32BIT_HACK = 0x7fffffff +} VSCSIXFERDIR; + +/** + * LUN types we support + */ +typedef enum VSCSILUNTYPE +{ + /** Invalid type */ + VSCSILUNTYPE_INVALID = 0, + /** Hard disk (SBC) */ + VSCSILUNTYPE_SBC, + /** CD/DVD drive (MMC) */ + VSCSILUNTYPE_MMC, + /** Tape drive (SSC) */ + VSCSILUNTYPE_SSC, + /** Last value to indicate an invalid device */ + VSCSILUNTYPE_LAST, + /** 32bit hack */ + VSCSILUNTYPE_32BIT_HACK = 0x7fffffff +} VSCSILUNTYPE; +/** Pointer to a SCSI LUN type */ +typedef VSCSILUNTYPE *PVSCSILUNTYPE; + +/** The LUN can handle the UNMAP command. */ +#define VSCSI_LUN_FEATURE_UNMAP RT_BIT(0) +/** The LUN has a non rotational medium. */ +#define VSCSI_LUN_FEATURE_NON_ROTATIONAL RT_BIT(1) +/** The medium of the LUN is readonly. */ +#define VSCSI_LUN_FEATURE_READONLY RT_BIT(2) + +/** + * Virtual SCSI LUN I/O Callback table. + */ +typedef struct VSCSILUNIOCALLBACKS +{ + /** + * Sets the size of the allocator specific memory for a I/O request. + * + * @returns VBox status code. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param cbVScsiIoReqAlloc The size of the allocator specific memory in bytes. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunReqAllocSizeSet, (VSCSILUN hVScsiLun, void *pvScsiLunUser, + size_t cbVScsiIoReqAlloc)); + + /** + * Allocates a new I/O request. + * + * @returns VBox status code. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param u64Tag A tag to assign to the request handle for identification later on. + * @param phVScsiIoReq Where to store the handle to the allocated I/O request on success. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunReqAlloc, (VSCSILUN hVScsiLun, void *pvScsiLunUser, + uint64_t u64Tag, PVSCSIIOREQ phVScsiIoReq)); + + /** + * Frees a given I/O request. + * + * @returns VBox status code. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param hVScsiIoReq The VSCSI I/O request to free. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunReqFree, (VSCSILUN hVScsiLun, void *pvScsiLunUser, VSCSIIOREQ hVScsiIoReq)); + + /** + * Returns the number of regions for the medium. + * + * @returns Number of regions. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnVScsiLunMediumGetRegionCount,(VSCSILUN hVScsiLun, void *pvScsiLunUser)); + + /** + * Queries the properties for the given region. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the region index is not known. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param uRegion The region index to query the properties of. + * @param pu64LbaStart Where to store the starting LBA for the region on success. + * @param pcBlocks Where to store the number of blocks for the region on success. + * @param pcbBlock Where to store the size of one block in bytes on success. + * @param penmDataForm WHere to store the data form for the region on success. + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunMediumQueryRegionProperties,(VSCSILUN hVScsiLun, void *pvScsiLunUser, + uint32_t uRegion, uint64_t *pu64LbaStart, + uint64_t *pcBlocks, uint64_t *pcbBlock, + PVDREGIONDATAFORM penmDataForm)); + + /** + * Queries the properties for the region covering the given LBA. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the region index is not known. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param u64LbaStart Where to store the starting LBA for the region on success. + * @param puRegion Where to store the region number on success. + * @param pcBlocks Where to store the number of blocks left in this region starting from the given LBA. + * @param pcbBlock Where to store the size of one block in bytes on success. + * @param penmDataForm WHere to store the data form for the region on success. + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunMediumQueryRegionPropertiesForLba,(VSCSILUN hVScsiLun, void *pvScsiLunUser, + uint64_t u64LbaStart, uint32_t *puRegion, + uint64_t *pcBlocks, uint64_t *pcbBlock, + PVDREGIONDATAFORM penmDataForm)); + + /** + * Set the lock state of the underlying medium. + * + * @returns VBox status status code. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param fLocked New lock state (locked/unlocked). + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunMediumSetLock,(VSCSILUN hVScsiLun, void *pvScsiLunUser, bool fLocked)); + + /** + * Eject the attached medium. + * + * @returns VBox status code. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunMediumEject, (VSCSILUN hVScsiLun, void *pvScsiLunUser)); + + /** + * Enqueue a read or write request from the medium. + * + * @returns VBox status status code. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param hVScsiIoReq Virtual SCSI I/O request handle. + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunReqTransferEnqueue,(VSCSILUN hVScsiLun, void *pvScsiLunUser, VSCSIIOREQ hVScsiIoReq)); + + /** + * Returns flags of supported features. + * + * @returns VBox status status code. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param pfFeatures Where to return the queried features. + */ + 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; + +/** + * The virtual SCSI request completed callback. + */ +typedef DECLCALLBACKTYPE(void, FNVSCSIREQCOMPLETED,(VSCSIDEVICE hVScsiDevice, + void *pvVScsiDeviceUser, + void *pvVScsiReqUser, + int rcScsiCode, + bool fRedoPossible, + int rcReq, + size_t cbXfer, + VSCSIXFERDIR enmXferDir, + size_t cbSense)); +/** Pointer to a virtual SCSI request completed callback. */ +typedef FNVSCSIREQCOMPLETED *PFNVSCSIREQCOMPLETED; + +/** + * Create a new empty SCSI device instance. + * + * @returns VBox status code. + * @param phVScsiDevice Where to store the SCSI device handle. + * @param pfnVScsiReqCompleted The method call after a request completed. + * @param pvVScsiDeviceUser Opaque user data given in the completion callback. + */ +VBOXDDU_DECL(int) VSCSIDeviceCreate(PVSCSIDEVICE phVScsiDevice, + PFNVSCSIREQCOMPLETED pfnVScsiReqCompleted, + void *pvVScsiDeviceUser); + +/** + * Destroy a SCSI device instance. + * + * @returns VBox status code. + * @param hVScsiDevice The SCSI device handle to destroy. + */ +VBOXDDU_DECL(int) VSCSIDeviceDestroy(VSCSIDEVICE hVScsiDevice); + +/** + * Attach a LUN to the SCSI device. + * + * @returns VBox status code. + * @param hVScsiDevice The SCSI device handle to add the LUN to. + * @param hVScsiLun The LUN handle to add. + * @param iLun The LUN number. + */ +VBOXDDU_DECL(int) VSCSIDeviceLunAttach(VSCSIDEVICE hVScsiDevice, VSCSILUN hVScsiLun, uint32_t iLun); + +/** + * Detach a LUN from the SCSI device. + * + * @returns VBox status code. + * @param hVScsiDevice The SCSI device handle to add the LUN to. + * @param iLun The LUN number to remove. + * @param phVScsiLun Where to store the detached LUN handle. + */ +VBOXDDU_DECL(int) VSCSIDeviceLunDetach(VSCSIDEVICE hVScsiDevice, uint32_t iLun, + PVSCSILUN phVScsiLun); + +/** + * Query the SCSI LUN type. + * + * @returns VBox status code. + * @param hVScsiDevice The SCSI device handle. + * @param iLun The LUN number to get. + * @param pEnmLunType Where to store the LUN type. + */ +VBOXDDU_DECL(int) VSCSIDeviceLunQueryType(VSCSIDEVICE hVScsiDevice, uint32_t iLun, + PVSCSILUNTYPE pEnmLunType); + +/** + * Enqueue a request to the SCSI device. + * + * @returns VBox status code. + * @param hVScsiDevice The SCSI device handle. + * @param hVScsiReq The SCSI request handle to enqueue. + */ +VBOXDDU_DECL(int) VSCSIDeviceReqEnqueue(VSCSIDEVICE hVScsiDevice, VSCSIREQ hVScsiReq); + +/** + * Allocate a new request handle. + * + * @returns VBox status code. + * @param hVScsiDevice The SCSI device handle. + * @param phVScsiReq Where to SCSI request handle. + * @param iLun The LUN the request is for. + * @param pbCDB The CDB for the request. + * @param cbCDB The size of the CDB in bytes. + * @param cbSGList Number of bytes the S/G list describes. + * @param cSGListEntries Number of S/G list entries. + * @param paSGList Pointer to the S/G list. + * @param pbSense Pointer to the sense buffer. + * @param cbSense Size of the sense buffer. + * @param pvVScsiReqUser Opqaue user data returned when the request completes. + */ +VBOXDDU_DECL(int) VSCSIDeviceReqCreate(VSCSIDEVICE hVScsiDevice, PVSCSIREQ phVScsiReq, + uint32_t iLun, uint8_t *pbCDB, size_t cbCDB, + size_t cbSGList, unsigned cSGListEntries, + PCRTSGSEG paSGList, uint8_t *pbSense, + size_t cbSense, void *pvVScsiReqUser); + +/** + * Create a new LUN. + * + * @returns VBox status code. + * @param phVScsiLun Where to store the SCSI LUN handle. + * @param enmLunType The Lun type. + * @param pVScsiLunIoCallbacks Pointer to the I/O callbacks to use for his LUN. + * @param pvVScsiLunUser Opaque user argument which + * is returned in the pvScsiLunUser parameter + * when the request completion callback is called. + */ +VBOXDDU_DECL(int) VSCSILunCreate(PVSCSILUN phVScsiLun, VSCSILUNTYPE enmLunType, + PVSCSILUNIOCALLBACKS pVScsiLunIoCallbacks, + void *pvVScsiLunUser); + +/** + * Destroy virtual SCSI LUN. + * + * @returns VBox status code. + * @param hVScsiLun The virtual SCSI LUN handle to destroy. + */ +VBOXDDU_DECL(int) VSCSILunDestroy(VSCSILUN hVScsiLun); + +/** + * Notify virtual SCSI LUN of medium being mounted. + * + * @returns VBox status code. + * @param hVScsiLun The virtual SCSI LUN handle to destroy. + */ +VBOXDDU_DECL(int) VSCSILunMountNotify(VSCSILUN hVScsiLun); + +/** + * Notify virtual SCSI LUN of medium being unmounted. + * + * @returns VBox status code. + * @param hVScsiLun The virtual SCSI LUN handle to destroy. + */ +VBOXDDU_DECL(int) VSCSILunUnmountNotify(VSCSILUN hVScsiLun); + +/** + * Notify a that a I/O request completed. + * + * @returns VBox status code. + * @param hVScsiIoReq The I/O request handle that completed. + * This is given when a I/O callback for + * the LUN is called by the virtual SCSI layer. + * @param rcIoReq The status code the I/O request completed with. + * @param fRedoPossible Flag whether it is possible to redo the request. + * If true setting any sense code will be omitted + * in case of an error to not alter the device state. + */ +VBOXDDU_DECL(int) VSCSIIoReqCompleted(VSCSIIOREQ hVScsiIoReq, int rcIoReq, bool fRedoPossible); + +/** + * Query the transfer direction of the I/O request. + * + * @returns Transfer direction.of the given I/O request + * @param hVScsiIoReq The SCSI I/O request handle. + */ +VBOXDDU_DECL(VSCSIIOREQTXDIR) VSCSIIoReqTxDirGet(VSCSIIOREQ hVScsiIoReq); + +/** + * Query I/O parameters. + * + * @returns VBox status code. + * @param hVScsiIoReq The SCSI I/O request handle. + * @param puOffset Where to store the start offset. + * @param pcbTransfer Where to store the amount of bytes to transfer. + * @param pcSeg Where to store the number of segments in the S/G list. + * @param pcbSeg Where to store the number of bytes the S/G list describes. + * @param ppaSeg Where to store the pointer to the S/G list. + */ +VBOXDDU_DECL(int) VSCSIIoReqParamsGet(VSCSIIOREQ hVScsiIoReq, uint64_t *puOffset, + size_t *pcbTransfer, unsigned *pcSeg, + size_t *pcbSeg, PCRTSGSEG *ppaSeg); + +/** + * Query unmap parameters. + * + * @returns VBox status code. + * @param hVScsiIoReq The SCSI I/O request handle. + * @param ppaRanges Where to store the pointer to the range array on success. + * @param pcRanges Where to store the number of ranges on success. + */ +VBOXDDU_DECL(int) VSCSIIoReqUnmapParamsGet(VSCSIIOREQ hVScsiIoReq, PCRTRANGE *ppaRanges, + unsigned *pcRanges); + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vscsi_h */ + diff --git a/include/VBox/vusb.h b/include/VBox/vusb.h new file mode 100644 index 00000000..95ae9b0a --- /dev/null +++ b/include/VBox/vusb.h @@ -0,0 +1,1472 @@ +/** @file + * VUSB - VirtualBox USB. (DEV,VMM) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vusb_h +#define VBOX_INCLUDED_vusb_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <iprt/assert.h> + +struct PDMLED; + +RT_C_DECLS_BEGIN + +/** @defgroup grp_vusb VBox USB API + * @{ + */ + +/** @defgroup grp_vusb_std Standard Stuff + * @{ */ + +/** Frequency of USB bus (from spec). */ +#define VUSB_BUS_HZ 12000000 + + +/** @name USB Descriptor types (from spec) + * @{ */ +#define VUSB_DT_DEVICE 0x01 +#define VUSB_DT_CONFIG 0x02 +#define VUSB_DT_STRING 0x03 +#define VUSB_DT_INTERFACE 0x04 +#define VUSB_DT_ENDPOINT 0x05 +#define VUSB_DT_DEVICE_QUALIFIER 0x06 +#define VUSB_DT_OTHER_SPEED_CFG 0x07 +#define VUSB_DT_INTERFACE_POWER 0x08 +#define VUSB_DT_INTERFACE_ASSOCIATION 0x0B +#define VUSB_DT_BOS 0x0F +#define VUSB_DT_DEVICE_CAPABILITY 0x10 +#define VUSB_DT_SS_ENDPOINT_COMPANION 0x30 +/** @} */ + +/** @name USB Descriptor minimum sizes (from spec) + * @{ */ +#define VUSB_DT_DEVICE_MIN_LEN 18 +#define VUSB_DT_CONFIG_MIN_LEN 9 +#define VUSB_DT_CONFIG_STRING_MIN_LEN 2 +#define VUSB_DT_INTERFACE_MIN_LEN 9 +#define VUSB_DT_ENDPOINT_MIN_LEN 7 +#define VUSB_DT_SSEP_COMPANION_MIN_LEN 6 +/** @} */ + +/** @name USB Device Capability Type Codes (from spec) + * @{ */ +#define VUSB_DCT_WIRELESS_USB 0x01 +#define VUSB_DCT_USB_20_EXTENSION 0x02 +#define VUSB_DCT_SUPERSPEED_USB 0x03 +#define VUSB_DCT_CONTAINER_ID 0x04 +/** @} */ + + +#pragma pack(1) /* ensure byte packing of the descriptors. */ + +/** + * USB language id descriptor (from specs). + */ +typedef struct VUSBDESCLANGID +{ + uint8_t bLength; + uint8_t bDescriptorType; +} VUSBDESCLANGID; +/** Pointer to a USB language id descriptor. */ +typedef VUSBDESCLANGID *PVUSBDESCLANGID; +/** Pointer to a const USB language id descriptor. */ +typedef const VUSBDESCLANGID *PCVUSBDESCLANGID; + + +/** + * USB string descriptor (from specs). + */ +typedef struct VUSBDESCSTRING +{ + uint8_t bLength; + uint8_t bDescriptorType; +} VUSBDESCSTRING; +/** Pointer to a USB string descriptor. */ +typedef VUSBDESCSTRING *PVUSBDESCSTRING; +/** Pointer to a const USB string descriptor. */ +typedef const VUSBDESCSTRING *PCVUSBDESCSTRING; + + +/** + * USB device descriptor (from spec) + */ +typedef struct VUSBDESCDEVICE +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +} VUSBDESCDEVICE; +/** Pointer to a USB device descriptor. */ +typedef VUSBDESCDEVICE *PVUSBDESCDEVICE; +/** Pointer to a const USB device descriptor. */ +typedef const VUSBDESCDEVICE *PCVUSBDESCDEVICE; + +/** + * USB device qualifier (from spec 9.6.2) + */ +struct VUSBDEVICEQUALIFIER +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUsb; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint8_t bNumConfigurations; + uint8_t bReserved; +}; + +typedef struct VUSBDEVICEQUALIFIER VUSBDEVICEQUALIFIER; +typedef VUSBDEVICEQUALIFIER *PVUSBDEVICEQUALIFIER; + + +/** + * USB configuration descriptor (from spec). + */ +typedef struct VUSBDESCCONFIG +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; /**< recalculated by VUSB when involved in URB. */ + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t MaxPower; +} VUSBDESCCONFIG; +/** Pointer to a USB configuration descriptor. */ +typedef VUSBDESCCONFIG *PVUSBDESCCONFIG; +/** Pointer to a readonly USB configuration descriptor. */ +typedef const VUSBDESCCONFIG *PCVUSBDESCCONFIG; + + +/** + * USB interface association descriptor (from USB ECN Interface Association Descriptors) + */ +typedef struct VUSBDESCIAD +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bFirstInterface; + uint8_t bInterfaceCount; + uint8_t bFunctionClass; + uint8_t bFunctionSubClass; + uint8_t bFunctionProtocol; + uint8_t iFunction; +} VUSBDESCIAD; +/** Pointer to a USB interface association descriptor. */ +typedef VUSBDESCIAD *PVUSBDESCIAD; +/** Pointer to a readonly USB interface association descriptor. */ +typedef const VUSBDESCIAD *PCVUSBDESCIAD; + + +/** + * USB interface descriptor (from spec) + */ +typedef struct VUSBDESCINTERFACE +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} VUSBDESCINTERFACE; +/** Pointer to a USB interface descriptor. */ +typedef VUSBDESCINTERFACE *PVUSBDESCINTERFACE; +/** Pointer to a const USB interface descriptor. */ +typedef const VUSBDESCINTERFACE *PCVUSBDESCINTERFACE; + + +/** + * USB endpoint descriptor (from spec) + */ +typedef struct VUSBDESCENDPOINT +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; +} VUSBDESCENDPOINT; +/** Pointer to a USB endpoint descriptor. */ +typedef VUSBDESCENDPOINT *PVUSBDESCENDPOINT; +/** Pointer to a const USB endpoint descriptor. */ +typedef const VUSBDESCENDPOINT *PCVUSBDESCENDPOINT; + + +/** + * USB SuperSpeed endpoint companion descriptor (from USB3 spec) + */ +typedef struct VUSBDESCSSEPCOMPANION +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bMaxBurst; + uint8_t bmAttributes; + uint16_t wBytesPerInterval; +} VUSBDESCSSEPCOMPANION; +/** Pointer to a USB endpoint companion descriptor. */ +typedef VUSBDESCSSEPCOMPANION *PVUSBDESCSSEPCOMPANION; +/** Pointer to a const USB endpoint companion descriptor. */ +typedef const VUSBDESCSSEPCOMPANION *PCVUSBDESCSSEPCOMPANION; + + +/** + * USB Binary Device Object Store, aka BOS (from USB3 spec) + */ +typedef struct VUSBDESCBOS +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumDeviceCaps; +} VUSBDESCBOS; +/** Pointer to a USB BOS descriptor. */ +typedef VUSBDESCBOS *PVUSBDESCBOS; +/** Pointer to a const USB BOS descriptor. */ +typedef const VUSBDESCBOS *PCVUSBDESCBOS; + + +/** + * Generic USB Device Capability Descriptor within BOS (from USB3 spec) + */ +typedef struct VUSBDESCDEVICECAP +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t aCapSpecific[1]; +} VUSBDESCDEVICECAP; +/** Pointer to a USB device capability descriptor. */ +typedef VUSBDESCDEVICECAP *PVUSBDESCDEVICECAP; +/** Pointer to a const USB device capability descriptor. */ +typedef const VUSBDESCDEVICECAP *PCVUSBDESCDEVICECAP; + + +/** + * SuperSpeed USB Device Capability Descriptor within BOS + */ +typedef struct VUSBDESCSSDEVCAP +{ + uint8_t bLength; + uint8_t bDescriptorType; /* DEVICE CAPABILITY */ + uint8_t bDevCapabilityType; /* SUPERSPEED_USB */ + uint8_t bmAttributes; + uint16_t wSpeedsSupported; + uint8_t bFunctionalitySupport; + uint8_t bU1DevExitLat; + uint16_t wU2DevExitLat; +} VUSBDESCSSDEVCAP; +/** Pointer to an SS USB device capability descriptor. */ +typedef VUSBDESCSSDEVCAP *PVUSBDESCSSDEVCAP; +/** Pointer to a const SS USB device capability descriptor. */ +typedef const VUSBDESCSSDEVCAP *PCVUSBDESCSSDEVCAP; + + +/** + * USB 2.0 Extension Descriptor within BOS + */ +typedef struct VUSBDESCUSB2EXT +{ + uint8_t bLength; + uint8_t bDescriptorType; /* DEVICE CAPABILITY */ + uint8_t bDevCapabilityType; /* USB 2.0 EXTENSION */ + uint8_t bmAttributes; +} VUSBDESCUSB2EXT; +/** Pointer to a USB 2.0 extension capability descriptor. */ +typedef VUSBDESCUSB2EXT *PVUSBDESCUSB2EXT; +/** Pointer to a const USB 2.0 extension capability descriptor. */ +typedef const VUSBDESCUSB2EXT *PCVUSBDESCUSB2EXT; + + +#pragma pack() /* end of the byte packing. */ + + +/** + * USB configuration descriptor, the parsed variant used by VUSB. + */ +typedef struct VUSBDESCCONFIGEX +{ + /** The USB descriptor data. + * @remark The wTotalLength member is recalculated before the data is passed to the guest. */ + VUSBDESCCONFIG Core; + /** Pointer to additional descriptor bytes following what's covered by VUSBDESCCONFIG. */ + void *pvMore; + /** Pointer to additional class- or vendor-specific interface descriptors. */ + const void *pvClass; + /** Size of class- or vendor-specific descriptors. */ + uint16_t cbClass; + /** Pointer to an array of the interfaces referenced in the configuration. + * Core.bNumInterfaces in size. */ + const struct VUSBINTERFACE *paIfs; + /** Pointer to the original descriptor data read from the device. */ + const void *pvOriginal; +} VUSBDESCCONFIGEX; +/** Pointer to a parsed USB configuration descriptor. */ +typedef VUSBDESCCONFIGEX *PVUSBDESCCONFIGEX; +/** Pointer to a const parsed USB configuration descriptor. */ +typedef const VUSBDESCCONFIGEX *PCVUSBDESCCONFIGEX; + + +/** + * For tracking the alternate interface settings of a configuration. + */ +typedef struct VUSBINTERFACE +{ + /** Pointer to an array of interfaces. */ + const struct VUSBDESCINTERFACEEX *paSettings; + /** The number of entries in the array. */ + uint32_t cSettings; +} VUSBINTERFACE; +/** Pointer to a VUSBINTERFACE. */ +typedef VUSBINTERFACE *PVUSBINTERFACE; +/** Pointer to a const VUSBINTERFACE. */ +typedef const VUSBINTERFACE *PCVUSBINTERFACE; + + +/** + * USB interface descriptor, the parsed variant used by VUSB. + */ +typedef struct VUSBDESCINTERFACEEX +{ + /** The USB descriptor data. */ + VUSBDESCINTERFACE Core; + /** Pointer to additional descriptor bytes following what's covered by VUSBDESCINTERFACE. */ + const void *pvMore; + /** Pointer to additional class- or vendor-specific interface descriptors. */ + const void *pvClass; + /** Size of class- or vendor-specific descriptors. */ + uint16_t cbClass; + /** Pointer to an array of the endpoints referenced by the interface. + * Core.bNumEndpoints in size. */ + const struct VUSBDESCENDPOINTEX *paEndpoints; + /** Interface association descriptor, which prepends a group of interfaces, + * starting with this interface. */ + PCVUSBDESCIAD pIAD; + /** Size of interface association descriptor. */ + uint16_t cbIAD; +} VUSBDESCINTERFACEEX; +/** Pointer to an prased USB interface descriptor. */ +typedef VUSBDESCINTERFACEEX *PVUSBDESCINTERFACEEX; +/** Pointer to a const parsed USB interface descriptor. */ +typedef const VUSBDESCINTERFACEEX *PCVUSBDESCINTERFACEEX; + + +/** + * USB endpoint descriptor, the parsed variant used by VUSB. + */ +typedef struct VUSBDESCENDPOINTEX +{ + /** The USB descriptor data. + * @remark The wMaxPacketSize member is converted to native endian. */ + VUSBDESCENDPOINT Core; + /** Pointer to additional descriptor bytes following what's covered by VUSBDESCENDPOINT. */ + const void *pvMore; + /** Pointer to additional class- or vendor-specific endpoint descriptors. */ + const void *pvClass; + /** Size of class- or vendor-specific descriptors. */ + uint16_t cbClass; + /** Pointer to SuperSpeed endpoint companion descriptor (SS endpoints only). */ + const void *pvSsepc; + /** Size of SuperSpeed endpoint companion descriptor. + * @remark Must be non-zero for SuperSpeed endpoints. */ + uint16_t cbSsepc; +} VUSBDESCENDPOINTEX; +/** Pointer to a parsed USB endpoint descriptor. */ +typedef VUSBDESCENDPOINTEX *PVUSBDESCENDPOINTEX; +/** Pointer to a const parsed USB endpoint descriptor. */ +typedef const VUSBDESCENDPOINTEX *PCVUSBDESCENDPOINTEX; + + +/** @name USB Control message recipient codes (from spec) + * @{ */ +#define VUSB_TO_DEVICE 0x0 +#define VUSB_TO_INTERFACE 0x1 +#define VUSB_TO_ENDPOINT 0x2 +#define VUSB_TO_OTHER 0x3 +#define VUSB_RECIP_MASK 0x1f +/** @} */ + +/** @name USB control pipe setup packet structure (from spec) + * @{ */ +#define VUSB_REQ_SHIFT (5) +#define VUSB_REQ_STANDARD (0x0 << VUSB_REQ_SHIFT) +#define VUSB_REQ_CLASS (0x1 << VUSB_REQ_SHIFT) +#define VUSB_REQ_VENDOR (0x2 << VUSB_REQ_SHIFT) +#define VUSB_REQ_RESERVED (0x3 << VUSB_REQ_SHIFT) +#define VUSB_REQ_MASK (0x3 << VUSB_REQ_SHIFT) +/** @} */ + +#define VUSB_DIR_TO_DEVICE 0x00 +#define VUSB_DIR_TO_HOST 0x80 +#define VUSB_DIR_MASK 0x80 + +/** + * USB Setup request (from spec) + */ +typedef struct vusb_setup +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} VUSBSETUP; +/** Pointer to a setup request. */ +typedef VUSBSETUP *PVUSBSETUP; +/** Pointer to a const setup request. */ +typedef const VUSBSETUP *PCVUSBSETUP; + +/** @name USB Standard device requests (from spec) + * @{ */ +#define VUSB_REQ_GET_STATUS 0x00 +#define VUSB_REQ_CLEAR_FEATURE 0x01 +#define VUSB_REQ_SET_FEATURE 0x03 +#define VUSB_REQ_SET_ADDRESS 0x05 +#define VUSB_REQ_GET_DESCRIPTOR 0x06 +#define VUSB_REQ_SET_DESCRIPTOR 0x07 +#define VUSB_REQ_GET_CONFIGURATION 0x08 +#define VUSB_REQ_SET_CONFIGURATION 0x09 +#define VUSB_REQ_GET_INTERFACE 0x0a +#define VUSB_REQ_SET_INTERFACE 0x0b +#define VUSB_REQ_SYNCH_FRAME 0x0c +#define VUSB_REQ_MAX 0x0d +/** @} */ + +/** @} */ /* end of grp_vusb_std */ + + + +/** @name USB Standard version flags. + * @{ */ +/** Indicates USB 1.1 support. */ +#define VUSB_STDVER_11 RT_BIT(1) +/** Indicates USB 2.0 support. */ +#define VUSB_STDVER_20 RT_BIT(2) +/** Indicates USB 3.0 support. */ +#define VUSB_STDVER_30 RT_BIT(3) +/** @} */ + +/** + * USB port/device speeds. + */ +typedef enum VUSBSPEED +{ + /** Undetermined/unknown speed. */ + VUSB_SPEED_UNKNOWN = 0, + /** Low-speed (LS), 1.5 Mbit/s, USB 1.0. */ + VUSB_SPEED_LOW, + /** Full-speed (FS), 12 Mbit/s, USB 1.1. */ + VUSB_SPEED_FULL, + /** High-speed (HS), 480 Mbit/s, USB 2.0. */ + VUSB_SPEED_HIGH, + /** Variable speed, wireless USB 2.5. */ + VUSB_SPEED_VARIABLE, + /** SuperSpeed (SS), 5.0 Gbit/s, USB 3.0. */ + VUSB_SPEED_SUPER, + /** SuperSpeed+ (SS+), 10.0 Gbit/s, USB 3.1. */ + VUSB_SPEED_SUPERPLUS, + /** The usual 32-bit hack. */ + VUSB_SPEED_32BIT_HACK = 0x7fffffff +} VUSBSPEED; + +/** + * VUSB transfer direction. + */ +typedef enum VUSBDIRECTION +{ + /** Setup */ + VUSBDIRECTION_SETUP = 0, +#define VUSB_DIRECTION_SETUP VUSBDIRECTION_SETUP + /** In - Device to host. */ + VUSBDIRECTION_IN = 1, +#define VUSB_DIRECTION_IN VUSBDIRECTION_IN + /** Out - Host to device. */ + VUSBDIRECTION_OUT = 2, +#define VUSB_DIRECTION_OUT VUSBDIRECTION_OUT + /** Invalid direction */ + VUSBDIRECTION_INVALID = 0x7f +} VUSBDIRECTION; + +/** + * VUSB Transfer types. + */ +typedef enum VUSBXFERTYPE +{ + /** Control message. Used to represent a single control transfer. */ + VUSBXFERTYPE_CTRL = 0, + /* Isochronous transfer. */ + VUSBXFERTYPE_ISOC, + /** Bulk transfer. */ + VUSBXFERTYPE_BULK, + /** Interrupt transfer. */ + VUSBXFERTYPE_INTR, + /** Complete control message. Used to represent an entire control message. */ + VUSBXFERTYPE_MSG, + /** Invalid transfer type. */ + VUSBXFERTYPE_INVALID = 0x7f +} VUSBXFERTYPE; + +/** Number of valid USB transfer types - KEEP in sync with VUSBXFERTYPE!. */ +#define VUSBXFERTYPE_ELEMENTS (5) + +/** Pointer to a VBox USB device interface. */ +typedef struct VUSBIDEVICE *PVUSBIDEVICE; + +/** Pointer to a VUSB RootHub port interface. */ +typedef struct VUSBIROOTHUBPORT *PVUSBIROOTHUBPORT; + +/** Pointer to an USB request descriptor. */ +typedef struct VUSBURB *PVUSBURB; + + +/** + * VUSB device reset completion callback function. + * This is called by the reset thread when the reset has been completed. + * + * @param pDevice Pointer to the virtual USB device core. + * @param uPort The port of the device which completed the reset. + * @param rc The VBox status code of the reset operation. + * @param pvUser User specific argument. + * + * @thread The reset thread or EMT. + */ +typedef DECLCALLBACKTYPE(void, FNVUSBRESETDONE,(PVUSBIDEVICE pDevice, uint32_t uPort, int rc, void *pvUser)); +/** Pointer to a device reset completion callback function (FNUSBRESETDONE). */ +typedef FNVUSBRESETDONE *PFNVUSBRESETDONE; + + +/** + * The state of a VUSB Device. + * + * @remark The order of these states is vital. + */ +typedef enum VUSBDEVICESTATE +{ + VUSB_DEVICE_STATE_INVALID = 0, + VUSB_DEVICE_STATE_DETACHED, + VUSB_DEVICE_STATE_ATTACHED, + VUSB_DEVICE_STATE_POWERED, + VUSB_DEVICE_STATE_DEFAULT, + VUSB_DEVICE_STATE_ADDRESS, + VUSB_DEVICE_STATE_CONFIGURED, + VUSB_DEVICE_STATE_SUSPENDED, + /** The device is being reset. Don't mess with it. + * Next states: VUSB_DEVICE_STATE_DEFAULT, VUSB_DEVICE_STATE_DESTROYED + */ + VUSB_DEVICE_STATE_RESET, + /** The device has been destroyed. */ + VUSB_DEVICE_STATE_DESTROYED, + /** The usual 32-bit hack. */ + VUSB_DEVICE_STATE_32BIT_HACK = 0x7fffffff +} VUSBDEVICESTATE; + + +/** Maximum number of USB devices supported. */ +#define VUSB_DEVICES_MAX 128 +/** An invalid device port. */ +#define VUSB_DEVICE_PORT_INVALID UINT32_MAX + +/** + * VBox USB port bitmap. + * + * Bit 0 == Port 0, ... , Bit 127 == Port 127. + */ +typedef struct VUSBPORTBITMAP +{ + /** 128 bits */ + char ach[VUSB_DEVICES_MAX / 8]; +} VUSBPORTBITMAP; +/** Pointer to a VBox USB port bitmap. */ +typedef VUSBPORTBITMAP *PVUSBPORTBITMAP; +AssertCompile(sizeof(VUSBPORTBITMAP) * 8 >= VUSB_DEVICES_MAX); + +#ifndef RDESKTOP + +/** + * The VUSB RootHub port interface provided by the HCI (down). + * Pair with VUSBIROOTCONNECTOR + */ +typedef struct VUSBIROOTHUBPORT +{ + /** + * Get the number of available ports in the hub. + * + * @returns The number of ports available. + * @param pInterface Pointer to this structure. + * @param pAvailable Bitmap indicating the available ports. Set bit == available port. + */ + DECLR3CALLBACKMEMBER(unsigned, pfnGetAvailablePorts,(PVUSBIROOTHUBPORT pInterface, PVUSBPORTBITMAP pAvailable)); + + /** + * Gets the supported USB versions. + * + * @returns The mask of supported USB versions. + * @param pInterface Pointer to this structure. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetUSBVersions,(PVUSBIROOTHUBPORT pInterface)); + + /** + * A device is being attached to a port in the roothub. + * + * @param pInterface Pointer to this structure. + * @param uPort The port number assigned to the device. + * @param enmSpeed The speed of the device being attached. + */ + DECLR3CALLBACKMEMBER(int, pfnAttach,(PVUSBIROOTHUBPORT pInterface, uint32_t uPort, VUSBSPEED enmSpeed)); + + /** + * A device is being detached from a port in the roothub. + * + * @param pInterface Pointer to this structure. + * @param uPort The port number assigned to the device. + */ + DECLR3CALLBACKMEMBER(void, pfnDetach,(PVUSBIROOTHUBPORT pInterface, uint32_t uPort)); + + /** + * Reset the root hub. + * + * @returns VBox status code. + * @param pInterface Pointer to this structure. + * @param fResetOnLinux Whether or not to do real reset on linux. + */ + DECLR3CALLBACKMEMBER(int, pfnReset,(PVUSBIROOTHUBPORT pInterface, bool fResetOnLinux)); + + /** + * Transfer completion callback routine. + * + * VUSB will call this when a transfer have been completed + * in a one or another way. + * + * @param pInterface Pointer to this structure. + * @param pUrb Pointer to the URB in question. + */ + DECLR3CALLBACKMEMBER(void, pfnXferCompletion,(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb)); + + /** + * Handle transfer errors. + * + * VUSB calls this when a transfer attempt failed. This function will respond + * indicating whether to retry or complete the URB with failure. + * + * @returns Retry indicator. + * @param pInterface Pointer to this structure. + * @param pUrb Pointer to the URB in question. + */ + DECLR3CALLBACKMEMBER(bool, pfnXferError,(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb)); + + /** + * Processes a new frame if periodic frame processing is enabled. + * + * @returns Flag whether there was activity which influences the frame rate. + * @param pInterface Pointer to this structure. + * @param u32FrameNo The frame number. + */ + DECLR3CALLBACKMEMBER(bool, pfnStartFrame, (PVUSBIROOTHUBPORT pInterface, uint32_t u32FrameNo)); + + /** + * Informs the callee about a change in the frame rate due to too many idle cycles or + * when seeing activity after some idle time. + * + * @returns nothing. + * @param pInterface Pointer to this structure. + * @param u32FrameRate The new frame rate. + */ + DECLR3CALLBACKMEMBER(void, pfnFrameRateChanged, (PVUSBIROOTHUBPORT pInterface, uint32_t u32FrameRate)); + + /** Alignment dummy. */ + RTR3PTR Alignment; + +} VUSBIROOTHUBPORT; +/** VUSBIROOTHUBPORT interface ID. */ +# define VUSBIROOTHUBPORT_IID "2ece01c2-4dbf-4bd5-96ca-09fc14164cd4" + +/** Pointer to a VUSB RootHub connector interface. */ +typedef struct VUSBIROOTHUBCONNECTOR *PVUSBIROOTHUBCONNECTOR; +/** + * The VUSB RootHub connector interface provided by the VBox USB RootHub driver + * (up). + * Pair with VUSBIROOTHUBPORT. + */ +typedef struct VUSBIROOTHUBCONNECTOR +{ + /** + * Sets the URB parameters for the caller. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param cbHci Size of the data private to the HCI for each URB when allocated. + * @param cbHciTd Size of one transfer descriptor. The number of transfer descriptors + * is given VUSBIROOTHUBCONNECTOR::pfnNewUrb for each URB to calculate the + * final amount of memory required for the TDs. + * + * @note This must be called before starting to allocate any URB or otherwise there will be no + * data available for the HCI. + */ + DECLR3CALLBACKMEMBER(int, pfnSetUrbParams, (PVUSBIROOTHUBCONNECTOR pInterface, size_t cbHci, size_t cbHciTd)); + + /** + * Resets the roothub. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param fResetOnLinux Whether or not to do real reset on linux. + */ + DECLR3CALLBACKMEMBER(int, pfnReset, (PVUSBIROOTHUBCONNECTOR pInterface, bool fResetOnLinux)); + + /** + * Powers on the roothub. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + */ + DECLR3CALLBACKMEMBER(int, pfnPowerOn, (PVUSBIROOTHUBCONNECTOR pInterface)); + + /** + * Power off the roothub. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + */ + DECLR3CALLBACKMEMBER(int, pfnPowerOff, (PVUSBIROOTHUBCONNECTOR pInterface)); + + /** + * Allocates a new URB for a transfer. + * + * Either submit using pfnSubmitUrb or free using VUSBUrbFree(). + * + * @returns Pointer to a new URB. + * @returns NULL on failure - try again later. + * This will not fail if the device wasn't found. We'll fail it + * at submit time, since that makes the usage of this api simpler. + * @param pInterface Pointer to this struct. + * @param DstAddress The destination address of the URB. + * @param uPort Optional port of the device the URB is for, use VUSB_DEVICE_PORT_INVALID to indicate to use the destination address. + * @param enmType Type of the URB. + * @param enmDir Data transfer direction. + * @param cbData The amount of data space required. + * @param cTds The amount of TD space. + * @param pszTag Custom URB tag assigned by the caller, only for + * logged builds and optional. + * + * @note pDev should be NULL in most cases. The only useful case is for USB3 where + * it is required for the SET_ADDRESS request because USB3 uses unicast traffic. + */ + DECLR3CALLBACKMEMBER(PVUSBURB, pfnNewUrb,(PVUSBIROOTHUBCONNECTOR pInterface, uint8_t DstAddress, uint32_t uPort, + VUSBXFERTYPE enmType, VUSBDIRECTION enmDir, uint32_t cbData, uint32_t cTds, const char *pszTag)); + + /** + * Free an URB not submitted yet. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param pUrb Pointer to the URB to free returned by VUSBIROOTHUBCONNECTOR::pfnNewUrb. + */ + DECLR3CALLBACKMEMBER(int, pfnFreeUrb, (PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb)); + + /** + * Submits a URB for transfer. + * The transfer will do asynchronously if possible. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param pUrb Pointer to the URB returned by pfnNewUrb. + * The URB will be freed in case of failure. + * @param pLed Pointer to USB Status LED + */ + DECLR3CALLBACKMEMBER(int, pfnSubmitUrb,(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb, struct PDMLED *pLed)); + + /** + * Call to service asynchronous URB completions in a polling fashion. + * + * Reaped URBs will be finished by calling the completion callback, + * thus there is no return code or input or anything from this function + * except for potential state changes elsewhere. + * + * @returns VINF_SUCCESS if no URBs are pending upon return. + * @returns VERR_TIMEOUT if one or more URBs are still in flight upon returning. + * @returns Other VBox status code. + * + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to reap URBs on. + * @param cMillies Number of milliseconds to poll for completion. + */ + DECLR3CALLBACKMEMBER(void, pfnReapAsyncUrbs,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, RTMSINTERVAL cMillies)); + + /** + * Cancels and completes - with CRC failure - all URBs queued on an endpoint. + * This is done in response to guest URB cancellation. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param pUrb Pointer to a previously submitted URB. + */ + DECLR3CALLBACKMEMBER(int, pfnCancelUrbsEp,(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb)); + + /** + * Cancels and completes - with CRC failure - all in-flight async URBs. + * This is typically done before saving a state. + * + * @param pInterface Pointer to this struct. + */ + DECLR3CALLBACKMEMBER(void, pfnCancelAllUrbs,(PVUSBIROOTHUBCONNECTOR pInterface)); + + /** + * Cancels and completes - with CRC failure - all URBs queued on an endpoint. + * This is done in response to a guest endpoint/pipe abort. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device. + * @param EndPt Endpoint number. + * @param enmDir Endpoint direction. + */ + DECLR3CALLBACKMEMBER(int, pfnAbortEp,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, int EndPt, VUSBDIRECTION enmDir)); + + /** + * Attach the device to the root hub. + * The device must not be attached to any hub for this call to succeed. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to attach. + */ + DECLR3CALLBACKMEMBER(int, pfnAttachDevice,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)); + + /** + * Detach the device from the root hub. + * The device must already be attached for this call to succeed. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to detach. + */ + DECLR3CALLBACKMEMBER(int, pfnDetachDevice,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)); + + /** + * Sets periodic frame processing. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param uFrameRate The target frame rate in Hertz, 0 disables periodic frame processing. + * The real frame rate might be lower if there is no activity for a certain period or + * higher if there is a need for catching up with where the guest expects the device to be. + */ + DECLR3CALLBACKMEMBER(int, pfnSetPeriodicFrameProcessing, (PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uFrameRate)); + + /** + * Returns the current frame rate for the periodic frame processing. + * + * @returns Frame rate for periodic frame processing. + * @retval 0 if disabled. + * @param pInterface Pointer to this struct. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetPeriodicFrameRate, (PVUSBIROOTHUBCONNECTOR pInterface)); + + /** + * Updates the internally stored isochronous scheduling frame for a given + * endpoint and returns the delta between the current and previous frame. + * + * @returns Delta between currently and previously scheduled frame. + * @retval 0 if no previous frame was set. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device. + * @param EndPt Endpoint number. + * @param enmDir Endpoint direction. + * @param uNewFrameID The frame ID of a new transfer. + * @param uBits The number of significant bits in frame ID. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnUpdateIsocFrameDelta, (PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, + int EndPt, VUSBDIRECTION enmDir, uint16_t uNewFrameID, uint8_t uBits)); + + /** + * Resets the device. + * + * Since a device reset shall take at least 10ms from the guest point of view, + * it must be performed asynchronously. We create a thread which performs this + * operation and ensures it will take at least 10ms. + * + * At times - like init - a synchronous reset is required, this can be done + * by passing NULL for pfnDone. + * + * -- internal stuff, move it -- + * While the device is being reset it is in the VUSB_DEVICE_STATE_RESET state. + * On completion it will be in the VUSB_DEVICE_STATE_DEFAULT state if successful, + * or in the VUSB_DEVICE_STATE_DETACHED state if the rest failed. + * -- internal stuff, move it -- + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to reset. + * @param fResetOnLinux Set if we can permit a real reset and a potential logical + * device reconnect on linux hosts. + * @param pfnDone Pointer to the completion routine. If NULL a synchronous + * reset is performed not respecting the 10ms. + * @param pvUser User argument to the completion routine. + * @param pVM The cross context VM structure. Required if pfnDone + * is not NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnDevReset,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, bool fResetOnLinux, + PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)); + + /** + * Powers on the device. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to power on. + */ + DECLR3CALLBACKMEMBER(int, pfnDevPowerOn,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)); + + /** + * Powers off the device. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to power off. + */ + DECLR3CALLBACKMEMBER(int, pfnDevPowerOff,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)); + + /** + * Get the state of the device. + * + * @returns Device state. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to get the state for. + */ + DECLR3CALLBACKMEMBER(VUSBDEVICESTATE, pfnDevGetState,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)); + + /** + * Returns whether the device implements the saved state handlers + * and doesn't need to get detached. + * + * @returns true if the device supports saving the state, false otherwise. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to query saved state support for. + */ + DECLR3CALLBACKMEMBER(bool, pfnDevIsSavedStateSupported,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)); + + /** + * Get the speed the device is operating at. + * + * @returns Device state. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to query the speed for. + */ + DECLR3CALLBACKMEMBER(VUSBSPEED, pfnDevGetSpeed,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)); + +} VUSBIROOTHUBCONNECTOR; +AssertCompileSizeAlignment(VUSBIROOTHUBCONNECTOR, 8); +/** VUSBIROOTHUBCONNECTOR interface ID. */ +# define VUSBIROOTHUBCONNECTOR_IID "662d7822-b9c6-43b5-88b6-5d59f0106e46" + + +# ifdef IN_RING3 +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnSetUrbParams */ +DECLINLINE(int) VUSBIRhSetUrbParams(PVUSBIROOTHUBCONNECTOR pInterface, size_t cbHci, size_t cbHciTd) +{ + return pInterface->pfnSetUrbParams(pInterface, cbHci, cbHciTd); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnNewUrb */ +DECLINLINE(PVUSBURB) VUSBIRhNewUrb(PVUSBIROOTHUBCONNECTOR pInterface, uint8_t DstAddress, uint32_t uPort, + VUSBXFERTYPE enmType, VUSBDIRECTION enmDir, uint32_t cbData, uint32_t cTds, const char *pszTag) +{ + return pInterface->pfnNewUrb(pInterface, DstAddress, uPort, enmType, enmDir, cbData, cTds, pszTag); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnFreeUrb */ +DECLINLINE(int) VUSBIRhFreeUrb(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb) +{ + return pInterface->pfnFreeUrb(pInterface, pUrb); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnSubmitUrb */ +DECLINLINE(int) VUSBIRhSubmitUrb(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb, struct PDMLED *pLed) +{ + return pInterface->pfnSubmitUrb(pInterface, pUrb, pLed); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnReapAsyncUrbs */ +DECLINLINE(void) VUSBIRhReapAsyncUrbs(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, RTMSINTERVAL cMillies) +{ + pInterface->pfnReapAsyncUrbs(pInterface, uPort, cMillies); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnCancelAllUrbs */ +DECLINLINE(void) VUSBIRhCancelAllUrbs(PVUSBIROOTHUBCONNECTOR pInterface) +{ + pInterface->pfnCancelAllUrbs(pInterface); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnAttachDevice */ +DECLINLINE(int) VUSBIRhAttachDevice(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort) +{ + return pInterface->pfnAttachDevice(pInterface, uPort); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDetachDevice */ +DECLINLINE(int) VUSBIRhDetachDevice(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort) +{ + return pInterface->pfnDetachDevice(pInterface, uPort); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnSetPeriodicFrameProcessing */ +DECLINLINE(int) VUSBIRhSetPeriodicFrameProcessing(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uFrameRate) +{ + return pInterface->pfnSetPeriodicFrameProcessing(pInterface, uFrameRate); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnGetPeriodicFrameRate */ +DECLINLINE(uint32_t) VUSBIRhGetPeriodicFrameRate(PVUSBIROOTHUBCONNECTOR pInterface) +{ + return pInterface->pfnGetPeriodicFrameRate(pInterface); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevReset */ +DECLINLINE(int) VUSBIRhDevReset(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, bool fResetOnLinux, + PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM) +{ + return pInterface->pfnDevReset(pInterface, uPort, fResetOnLinux, pfnDone, pvUser, pVM); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevPowerOn */ +DECLINLINE(int) VUSBIRhDevPowerOn(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort) +{ + return pInterface->pfnDevPowerOn(pInterface, uPort); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevPowerOff */ +DECLINLINE(int) VUSBIRhDevPowerOff(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort) +{ + return pInterface->pfnDevPowerOff(pInterface, uPort); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevGetState */ +DECLINLINE(VUSBDEVICESTATE) VUSBIRhDevGetState(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort) +{ + return pInterface->pfnDevGetState(pInterface, uPort); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevGetState */ +DECLINLINE(bool) VUSBIRhDevIsSavedStateSupported(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort) +{ + return pInterface->pfnDevIsSavedStateSupported(pInterface, uPort); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevGetSpeed */ +DECLINLINE(VUSBSPEED) VUSBIRhDevGetSpeed(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort) +{ + return pInterface->pfnDevGetSpeed(pInterface, uPort); +} +# endif /* IN_RING3 */ + +#endif /* ! RDESKTOP */ + + +#ifndef RDESKTOP + +/** + * USB Device Interface (up). + * No interface pair. + */ +typedef struct VUSBIDEVICE +{ + /** + * Resets the device. + * + * Since a device reset shall take at least 10ms from the guest point of view, + * it must be performed asynchronously. We create a thread which performs this + * operation and ensures it will take at least 10ms. + * + * At times - like init - a synchronous reset is required, this can be done + * by passing NULL for pfnDone. + * + * -- internal stuff, move it -- + * While the device is being reset it is in the VUSB_DEVICE_STATE_RESET state. + * On completion it will be in the VUSB_DEVICE_STATE_DEFAULT state if successful, + * or in the VUSB_DEVICE_STATE_DETACHED state if the rest failed. + * -- internal stuff, move it -- + * + * @returns VBox status code. + * @param pInterface Pointer to this structure. + * @param fResetOnLinux Set if we can permit a real reset and a potential logical + * device reconnect on linux hosts. + * @param pfnDone Pointer to the completion routine. If NULL a synchronous + * reset is performed not respecting the 10ms. + * @param pvUser User argument to the completion routine. + * @param pVM The cross context VM structure. Required if pfnDone + * is not NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnReset,(PVUSBIDEVICE pInterface, bool fResetOnLinux, + PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)); + + /** + * Powers on the device. + * + * @returns VBox status code. + * @param pInterface Pointer to the device interface structure. + */ + DECLR3CALLBACKMEMBER(int, pfnPowerOn,(PVUSBIDEVICE pInterface)); + + /** + * Powers off the device. + * + * @returns VBox status code. + * @param pInterface Pointer to the device interface structure. + */ + DECLR3CALLBACKMEMBER(int, pfnPowerOff,(PVUSBIDEVICE pInterface)); + + /** + * Get the state of the device. + * + * @returns Device state. + * @param pInterface Pointer to the device interface structure. + */ + DECLR3CALLBACKMEMBER(VUSBDEVICESTATE, pfnGetState,(PVUSBIDEVICE pInterface)); + + /** + * Returns whether the device implements the saved state handlers + * and doesn't need to get detached. + * + * @returns true if the device supports saving the state, false otherwise. + * @param pInterface Pointer to the device interface structure. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsSavedStateSupported,(PVUSBIDEVICE pInterface)); + + /** + * Get the speed the device is operating at. + * + * @returns Device state. + * @param pInterface Pointer to the device interface structure. + */ + DECLR3CALLBACKMEMBER(VUSBSPEED, pfnGetSpeed,(PVUSBIDEVICE pInterface)); + +} VUSBIDEVICE; +/** VUSBIDEVICE interface ID. */ +# define VUSBIDEVICE_IID "af576b38-e8ca-4db7-810a-2596d8d57ca0" + + +# ifdef IN_RING3 +/** + * Resets the device. + * + * Since a device reset shall take at least 10ms from the guest point of view, + * it must be performed asynchronously. We create a thread which performs this + * operation and ensures it will take at least 10ms. + * + * At times - like init - a synchronous reset is required, this can be done + * by passing NULL for pfnDone. + * + * -- internal stuff, move it -- + * While the device is being reset it is in the VUSB_DEVICE_STATE_RESET state. + * On completion it will be in the VUSB_DEVICE_STATE_DEFAULT state if successful, + * or in the VUSB_DEVICE_STATE_DETACHED state if the rest failed. + * -- internal stuff, move it -- + * + * @returns VBox status code. + * @param pInterface Pointer to the device interface structure. + * @param fResetOnLinux Set if we can permit a real reset and a potential logical + * device reconnect on linux hosts. + * @param pfnDone Pointer to the completion routine. If NULL a + * synchronous reset is performed not respecting the + * 10ms. + * @param pvUser User argument to the completion routine. + * @param pVM The cross context VM structure. Required if pfnDone + * is not NULL. + * + * NULL is acceptable Required if callback in EMT is desired, NULL is otherwise + * acceptable. + */ +DECLINLINE(int) VUSBIDevReset(PVUSBIDEVICE pInterface, bool fResetOnLinux, PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM) +{ + return pInterface->pfnReset(pInterface, fResetOnLinux, pfnDone, pvUser, pVM); +} + +/** + * Powers on the device. + * + * @returns VBox status code. + * @param pInterface Pointer to the device interface structure. + */ +DECLINLINE(int) VUSBIDevPowerOn(PVUSBIDEVICE pInterface) +{ + return pInterface->pfnPowerOn(pInterface); +} + +/** + * Powers off the device. + * + * @returns VBox status code. + * @param pInterface Pointer to the device interface structure. + */ +DECLINLINE(int) VUSBIDevPowerOff(PVUSBIDEVICE pInterface) +{ + return pInterface->pfnPowerOff(pInterface); +} + +/** + * Get the state of the device. + * + * @returns Device state. + * @param pInterface Pointer to the device interface structure. + */ +DECLINLINE(VUSBDEVICESTATE) VUSBIDevGetState(PVUSBIDEVICE pInterface) +{ + return pInterface->pfnGetState(pInterface); +} + +/** + * @copydoc VUSBIDEVICE::pfnIsSavedStateSupported + */ +DECLINLINE(bool) VUSBIDevIsSavedStateSupported(PVUSBIDEVICE pInterface) +{ + return pInterface->pfnIsSavedStateSupported(pInterface); +} +# endif /* IN_RING3 */ + +#endif /* ! RDESKTOP */ + +/** @name URB + * @{ */ + +/** + * VUSB Transfer status codes. + */ +typedef enum VUSBSTATUS +{ + /** Transer was ok. */ + VUSBSTATUS_OK = 0, + /** Transfer stalled, endpoint halted. */ + VUSBSTATUS_STALL, + /** Device not responding. */ + VUSBSTATUS_DNR, + /** CRC error. */ + VUSBSTATUS_CRC, + /** Data underrun error. */ + VUSBSTATUS_DATA_UNDERRUN, + /** Data overrun error. */ + VUSBSTATUS_DATA_OVERRUN, + /** The isochronous buffer hasn't been touched. */ + VUSBSTATUS_NOT_ACCESSED, + /** Canceled/undone URB (VUSB internal). */ + VUSBSTATUS_UNDO, + /** Canceled URB. */ + VUSBSTATUS_CANCELED, + /** Invalid status. */ + VUSBSTATUS_INVALID = 0x7f +} VUSBSTATUS; + + +/** + * The URB states + */ +typedef enum VUSBURBSTATE +{ + /** The usual invalid state. */ + VUSBURBSTATE_INVALID = 0, + /** The URB is free, i.e. not in use. + * Next state: ALLOCATED */ + VUSBURBSTATE_FREE, + /** The URB is allocated, i.e. being prepared for submission. + * Next state: FREE, IN_FLIGHT */ + VUSBURBSTATE_ALLOCATED, + /** The URB is in flight. + * Next state: REAPED, CANCELLED */ + VUSBURBSTATE_IN_FLIGHT, + /** The URB has been reaped and is being completed. + * Next state: FREE */ + VUSBURBSTATE_REAPED, + /** The URB has been cancelled and is awaiting reaping and immediate freeing. + * Next state: FREE */ + VUSBURBSTATE_CANCELLED, + /** The end of the valid states (exclusive). */ + VUSBURBSTATE_END, + /** The usual 32-bit blow up. */ + VUSBURBSTATE_32BIT_HACK = 0x7fffffff +} VUSBURBSTATE; + + +/** + * Information about a isochronous packet. + */ +typedef struct VUSBURBISOCPKT +{ + /** The size of the packet. + * IN: The packet size. I.e. the number of bytes to the next packet or end of buffer. + * OUT: The actual size transferred. */ + uint32_t cb; + /** The offset of the packet. (Relative to VUSBURB::abData[0].) + * OUT: This can be changed by the USB device if it does some kind of buffer squeezing. */ + uint32_t off; + /** The status of the transfer. + * IN: VUSBSTATUS_INVALID + * OUT: VUSBSTATUS_INVALID if nothing was done, otherwise the correct status. */ + VUSBSTATUS enmStatus; +} VUSBURBISOCPKT; +/** Pointer to a isochronous packet. */ +typedef VUSBURBISOCPKT *PVUSBURBISOCPTK; +/** Pointer to a const isochronous packet. */ +typedef const VUSBURBISOCPKT *PCVUSBURBISOCPKT; + +/** Private controller emulation specific data for the associated USB request descriptor. */ +typedef struct VUSBURBHCIINT *PVUSBURBHCI; +/** Private controller emulation specific TD data. */ +typedef struct VUSBURBHCITDINT *PVUSBURBHCITD; +/** Private VUSB/roothub related state for the associated URB. */ +typedef struct VUSBURBVUSBINT *PVUSBURBVUSB; + +/** + * Asynchronous USB request descriptor + */ +typedef struct VUSBURB +{ + /** URB magic value. */ + uint32_t u32Magic; + /** The USR state. */ + VUSBURBSTATE enmState; + /** Flag whether the URB is about to be completed, + * either by the I/O thread or the cancellation worker. + */ + volatile bool fCompleting; + /** URB description, can be null. intended for logging. */ + char *pszDesc; + +#ifdef RDESKTOP + /** The next URB in rdesktop-vrdp's linked list */ + PVUSBURB pNext; + /** The previous URB in rdesktop-vrdp's linked list */ + PVUSBURB pPrev; + /** The vrdp handle for the URB */ + uint32_t handle; + /** Pointer used to find the usb proxy device */ + struct VUSBDEV *pDev; +#endif + + /** The VUSB stack private data. */ + PVUSBURBVUSB pVUsb; + /** Private host controller data associated with this URB. */ + PVUSBURBHCI pHci; + /** Pointer to the host controller transfer descriptor array. */ + PVUSBURBHCITD paTds; + + /** The device data. */ + struct VUSBURBDEV + { + /** Pointer to private device specific data. */ + void *pvPrivate; + /** Used by the device when linking the URB in some list of its own. */ + PVUSBURB pNext; + } Dev; + + /** The device address. + * This is set at allocation time. */ + uint8_t DstAddress; + + /** The endpoint. + * IN: Must be set before submitting the URB. + * @remark This does not have the high bit (direction) set! */ + uint8_t EndPt; + /** The transfer type. + * IN: Set at allocation time. */ + VUSBXFERTYPE enmType; + /** The transfer direction. + * IN: Set at allocation time. */ + VUSBDIRECTION enmDir; + /** Indicates whether it is OK to receive/send less data than requested. + * IN: Must be initialized before submitting the URB. */ + bool fShortNotOk; + /** The transfer status. + * OUT: This is set when reaping the URB. */ + VUSBSTATUS enmStatus; + + /** The relative starting frame for isochronous transfers. + * Zero indicates "transfer ASAP". + * This is ignored when enmType isn't VUSBXFERTYPE_ISOC. */ + uint16_t uStartFrameDelta; + /** Flag indicating whether the start frame delta is relative + * to the previous transfer (false) or now (true). + * This is ignored when enmType isn't VUSBXFERTYPE_ISOC. */ + bool fStartRelToNow; + /** The number of isochronous packets describe in aIsocPkts. + * This is ignored when enmType isn't VUSBXFERTYPE_ISOC. */ + uint8_t cIsocPkts; + /** The iso packets within abData. + * This is ignored when enmType isn't VUSBXFERTYPE_ISOC. */ + VUSBURBISOCPKT aIsocPkts[8]; + + /** The message length. + * IN: The amount of data to send / receive - set at allocation time. + * OUT: The amount of data sent / received. */ + uint32_t cbData; + /** The message data. + * IN: On host to device transfers, the data to send. + * OUT: On device to host transfers, the data to received. + * This array has actually a size of VUsb.cbDataAllocated, not 8KB! */ + uint8_t abData[8*_1K]; +} VUSBURB; + +/** The magic value of a valid VUSBURB. (Murakami Haruki) */ +#define VUSBURB_MAGIC UINT32_C(0x19490112) + +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vusb_h */ diff --git a/include/VBox/xrandr-calls.h b/include/VBox/xrandr-calls.h new file mode 100644 index 00000000..5ede4291 --- /dev/null +++ b/include/VBox/xrandr-calls.h @@ -0,0 +1,80 @@ +/** @file + * Stubs for dynamically loading libXrandr and the symbols which are needed by + * VirtualBox. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +/** The file name of the libXrandr library. */ +#define RT_RUNTIME_LOADER_LIB_NAME "libXrandr.so.2" + +/** The name of the loader function. */ +#define RT_RUNTIME_LOADER_FUNCTION RTXrandrLoadLib + +/** The following are the symbols which we need from the Xrandr library. */ +#define RT_RUNTIME_LOADER_INSERT_SYMBOLS \ + RT_PROXY_STUB(XRRQueryExtension, Bool, (Display *dpy, int *event_base_return, int *error_base_return), \ + (dpy, event_base_return, error_base_return)) \ + RT_PROXY_STUB(XRRQueryVersion, Bool, (Display *dpy, int *major_version_return, int *minor_version_return), \ + (dpy, major_version_return, minor_version_return)) \ + RT_PROXY_STUB(XRRSelectInput, void, (Display *dpy, Window window, int mask), \ + (dpy, window, mask)) \ + RT_PROXY_STUB(XRRGetMonitors, XRRMonitorInfo *, (Display *dpy, Window window, Bool get_active, int *nmonitors), \ + (dpy, window, get_active, nmonitors)) \ + RT_PROXY_STUB(XRRFreeMonitors, void, (XRRMonitorInfo *monitors), \ + (monitors)) \ + RT_PROXY_STUB(XRRGetScreenResources, XRRScreenResources *, (Display *dpy, Window window), \ + (dpy, window)) \ + RT_PROXY_STUB(XRRFreeScreenResources, void, (XRRScreenResources *resources), \ + (resources)) \ + RT_PROXY_STUB(XRRSetOutputPrimary, void, (Display *dpy, Window window, RROutput output), \ + (dpy, window, output)) + +#ifdef VBOX_XRANDR_GENERATE_HEADER +# define RT_RUNTIME_LOADER_GENERATE_HEADER +# define RT_RUNTIME_LOADER_GENERATE_DECLS +# include <iprt/runtime-loader.h> +# undef RT_RUNTIME_LOADER_GENERATE_HEADER +# undef RT_RUNTIME_LOADER_GENERATE_DECLS + +#elif defined(VBOX_XRANDR_GENERATE_BODY) +# define RT_RUNTIME_LOADER_GENERATE_BODY_STUBS +# include <iprt/runtime-loader.h> +# undef RT_RUNTIME_LOADER_GENERATE_BODY_STUBS + +#else +# error This file should only be included to generate stubs for loading the Xrandr library at runtime +#endif + +#undef RT_RUNTIME_LOADER_LIB_NAME +#undef RT_RUNTIME_LOADER_INSERT_SYMBOLS + diff --git a/include/VBox/xrandr.h b/include/VBox/xrandr.h new file mode 100644 index 00000000..79adff4a --- /dev/null +++ b/include/VBox/xrandr.h @@ -0,0 +1,125 @@ +/** @file + * Module to dynamically load libXrandr and load all symbols which are needed by + * VirtualBox. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_xrandr_h +#define VBOX_INCLUDED_xrandr_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/stdarg.h> + +#ifndef __cplusplus +# error "This header requires C++ to avoid name clashes." +#endif + +/* Define missing X11/XRandr structures, types and macros. */ + +#define Bool int +#define RRScreenChangeNotifyMask (1L << 0) +#define RRScreenChangeNotify 0 + +struct _XDisplay; +typedef struct _XDisplay Display; + +typedef unsigned long Atom; +typedef unsigned long XID; +typedef XID RROutput; +typedef XID Window; +typedef XID RROutput; +typedef XID RRCrtc; +typedef XID RRMode; +typedef unsigned long XRRModeFlags; +typedef unsigned long int Time; + +struct XRRMonitorInfo +{ + Atom name; + Bool primary; + Bool automatic; + int noutput; + int x; + int y; + int width; + int height; + int mwidth; + int mheight; + RROutput *outputs; +}; +typedef struct XRRMonitorInfo XRRMonitorInfo; + +struct XRRModeInfo +{ + RRMode id; + unsigned int width; + unsigned int height; + unsigned long dotClock; + unsigned int hSyncStart; + unsigned int hSyncEnd; + unsigned int hTotal; + unsigned int hSkew; + unsigned int vSyncStart; + unsigned int vSyncEnd; + unsigned int vTotal; + char *name; + unsigned int nameLength; + XRRModeFlags modeFlags; +}; +typedef struct XRRModeInfo XRRModeInfo; + +struct XRRScreenResources +{ + Time timestamp; + Time configTimestamp; + int ncrtc; + RRCrtc *crtcs; + int noutput; + RROutput *outputs; + int nmode; + XRRModeInfo *modes; +}; +typedef struct XRRScreenResources XRRScreenResources; + +/* Declarations of the functions that we need from libXrandr. */ +#define VBOX_XRANDR_GENERATE_HEADER + +#include <VBox/xrandr-calls.h> + +#undef VBOX_XRANDR_GENERATE_HEADER + +#endif /* !VBOX_INCLUDED_xrandr_h */ + diff --git a/include/iprt/Makefile.kup b/include/iprt/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/iprt/Makefile.kup diff --git a/include/iprt/alloc.h b/include/iprt/alloc.h new file mode 100644 index 00000000..a0d6561d --- /dev/null +++ b/include/iprt/alloc.h @@ -0,0 +1,46 @@ +/** @file + * IPRT - Memory Allocation. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_alloc_h +#define IPRT_INCLUDED_alloc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Forwarding to the canonical header. */ +#include <iprt/mem.h> + +#endif /* !IPRT_INCLUDED_alloc_h */ + diff --git a/include/iprt/alloca.h b/include/iprt/alloca.h new file mode 100644 index 00000000..1866d975 --- /dev/null +++ b/include/iprt/alloca.h @@ -0,0 +1,110 @@ +/** @file + * IPRT - alloca(). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_alloca_h +#define IPRT_INCLUDED_alloca_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#if defined(IN_RC) || defined(IN_RING0_AGNOSTIC) +# error "No alloca() in raw-mode and agnostic ring-0 context as it may have external dependencies like libgcc." +#endif + +/* + * If there are more difficult platforms out there, we'll do OS + * specific #ifdefs. But for now we'll just include the headers + * which normally contains the alloca() prototype. + * When we're in kernel territory it starts getting a bit more + * interesting of course... + */ +#if defined(IN_RING0) \ + && ( defined(RT_OS_DARWIN) \ + || defined(RT_OS_FREEBSD) \ + || defined(RT_OS_LINUX) \ + || defined(RT_OS_NETBSD) \ + || defined(RT_OS_SOLARIS)) +/* ASSUMES GNU C */ +# define alloca(cb) __builtin_alloca(cb) + +#elif defined(IPRT_NO_CRT) && defined(RT_OS_WINDOWS) +# include <iprt/types.h> + +RT_C_DECLS_BEGIN +# ifdef RT_ARCH_X86 +void * __cdecl _alloca(size_t); +# else +void *_alloca(size_t); +# endif +# define alloca _alloca +RT_C_DECLS_END + +#else +# include <stdlib.h> +# if !defined(RT_OS_DARWIN) && !defined(RT_OS_FREEBSD) && !defined(RT_OS_NETBSD) +# include <malloc.h> +# endif +# if defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) +# include <alloca.h> +# endif + +# if defined(RT_OS_SOLARIS) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) \ + && defined(_SYS_REGSET_H) && !defined(IPRT_NO_SOLARIS_UCONTEXT_CLEANUPS) +/* Solaris' sys/regset.h pollutes the namespace with register constants that + frequently conflicts with structure members and variable/parameter names. */ +# undef CS +# undef DS +# undef EAX +# undef EBP +# undef EBX +# undef ECX +# undef EDI +# undef EDX +# undef EFL +# undef EIP +# undef ERR +# undef ES +# undef ESI +# undef ESP +# undef FS +# undef GS +# undef SS +# undef TRAPNO +# undef UESP +# endif +#endif + +#endif /* !IPRT_INCLUDED_alloca_h */ + diff --git a/include/iprt/asm-amd64-x86-watcom-16.h b/include/iprt/asm-amd64-x86-watcom-16.h new file mode 100644 index 00000000..a3fd3ebd --- /dev/null +++ b/include/iprt/asm-amd64-x86-watcom-16.h @@ -0,0 +1,831 @@ +/** @file + * IPRT - AMD64 and x86 Specific Assembly Functions, 16-bit Watcom C pragma aux. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asm_amd64_x86_watcom_16_h +#define IPRT_INCLUDED_asm_amd64_x86_watcom_16_h +/* no pragma once */ + +#ifndef IPRT_INCLUDED_asm_amd64_x86_h +# error "Don't include this header directly." +#endif + +/* + * Turns out we cannot use 'ds' for segment stuff here because the compiler + * seems to insists on loading the DGROUP segment into 'ds' before calling + * stuff when using -ecc. Using 'es' instead as this seems to work fine. + * + * Note! The #undef that preceds the #pragma aux statements is for undoing + * the mangling, because the symbol in #pragma aux [symbol] statements + * doesn't get subjected to preprocessing. This is also why we include + * the watcom header at both the top and the bottom of asm-amd64-x86.h file. + */ + +#undef ASMGetIDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetIDTR = \ + ".286p" \ + "sidt fword ptr es:[bx]" \ + parm [es bx] \ + modify exact []; +#endif + +#undef ASMGetIdtrLimit +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetIdtrLimit = \ + ".286p" \ + "sub sp, 8" \ + "mov bx, sp" \ + "sidt fword ptr ss:[bx]" \ + "mov bx, ss:[bx]" \ + "add sp, 8" \ + parm [] \ + value [bx] \ + modify exact [bx]; +#endif + +#undef ASMSetIDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetIDTR = \ + ".286p" \ + "lidt fword ptr es:[bx]" \ + parm [es bx] nomemory \ + modify nomemory; +#endif + +#undef ASMGetGDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetGDTR = \ + ".286p" \ + "sgdt fword ptr es:[bx]" \ + parm [es bx] \ + modify exact []; +#endif + +#undef ASMSetGDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetGDTR = \ + ".286p" \ + "lgdt fword ptr es:[bx]" \ + parm [es bx] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMGetCS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetCS = \ + "mov ax, cs" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMGetDS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetDS = \ + "mov ax, ds" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMGetES +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetES = \ + "mov ax, es" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMGetFS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetFS = \ + ".386" \ + "mov ax, fs" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMGetGS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetGS = \ + ".386" \ + "mov ax, gs" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMGetSS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetSS = \ + "mov ax, ss" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMGetTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetTR = \ + ".286" \ + "str ax" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMGetLDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetLDTR = \ + ".286" \ + "sldt ax" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +/** @todo ASMGetSegAttr */ + +#undef ASMGetFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetFlags = \ + "pushf" \ + "pop ax" \ + parm [] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMSetFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetFlags = \ + "push ax" \ + "popf" \ + parm [ax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMChangeFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMChangeFlags = \ + "pushf" \ + "pop ax" \ + "and dx, ax" \ + "or dx, cx" \ + "push dx" \ + "popf" \ + parm [dx] [cx] nomemory \ + value [ax] \ + modify exact [dx] nomemory; +#endif + +#undef ASMAddFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMAddFlags = \ + "pushf" \ + "pop ax" \ + "or dx, ax" \ + "push dx" \ + "popf" \ + parm [dx] nomemory \ + value [ax] \ + modify exact [dx] nomemory; +#endif + +#undef ASMClearFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMClearFlags = \ + "pushf" \ + "pop ax" \ + "and dx, ax" \ + "push dx" \ + "popf" \ + parm [dx] nomemory \ + value [ax] \ + modify exact [dx] nomemory; +#endif + +/* Note! Must use the 64-bit integer return value convension. + The order of registers in the value [set] does not seem to mean anything. */ +#undef ASMReadTSC +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMReadTSC = \ + ".586" \ + "rdtsc" \ + "mov ebx, edx" \ + "mov ecx, eax" \ + "shr ecx, 16" \ + "xchg eax, edx" \ + "shr eax, 16" \ + parm [] nomemory \ + value [dx cx bx ax] \ + modify exact [ax bx cx dx] nomemory; +#endif + +/** @todo ASMReadTscWithAux if needed (rdtscp not recognized by compiler) */ + + +/* ASMCpuId: Implemented externally, too many parameters. */ +/* ASMCpuId_Idx_ECX: Implemented externally, too many parameters. */ +/* ASMCpuIdExSlow: Always implemented externally. */ +/* ASMCpuId_ECX_EDX: Implemented externally, too many parameters. */ + +#undef ASMCpuId_EAX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMCpuId_EAX = \ + ".586" \ + "xchg ax, dx" \ + "shl eax, 16" \ + "mov ax, dx" \ + "cpuid" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [ax dx] \ + value [ax dx] \ + modify exact [ax bx cx dx]; +#endif + +#undef ASMCpuId_EBX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMCpuId_EBX = \ + ".586" \ + "xchg ax, dx" \ + "shl eax, 16" \ + "mov ax, dx" \ + "cpuid" \ + "mov ax, bx" \ + "shr ebx, 16" \ + parm [ax dx] \ + value [ax bx] \ + modify exact [ax bx cx dx]; +#endif + +#undef ASMCpuId_ECX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMCpuId_ECX = \ + ".586" \ + "xchg ax, dx" \ + "shl eax, 16" \ + "mov ax, dx" \ + "cpuid" \ + "mov ax, cx" \ + "shr ecx, 16" \ + parm [ax dx] \ + value [ax cx] \ + modify exact [ax bx cx dx]; +#endif + +#undef ASMCpuId_EDX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMCpuId_EDX = \ + ".586" \ + "xchg ax, dx" \ + "shl eax, 16" \ + "mov ax, dx" \ + "cpuid" \ + "mov ax, dx" \ + "shr edx, 16" \ + parm [ax dx] \ + value [ax dx] \ + modify exact [ax bx cx dx]; +#endif + +/* ASMHasCpuId: MSC inline in main source file. */ +/* ASMGetApicId: Implemented externally, lazy bird. */ + +/* Note! Again, when returning two registers, watcom have certain fixed ordering rules (low:high): + ax:bx, ax:cx, ax:dx, ax:si, ax:di + bx:cx, bx:dx, bx:si, bx:di + dx:cx, si:cx, di:cx + si:dx, di:dx + si:di + This ordering seems to apply to parameter values too. */ +#undef ASMGetCR0 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetCR0 = \ + ".386" \ + "mov eax, cr0" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMSetCR0 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetCR0 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov cr0, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +#undef ASMGetCR2 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetCR2 = \ + ".386" \ + "mov eax, cr2" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMSetCR2 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetCR2 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov cr2, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +#undef ASMGetCR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetCR3 = \ + ".386" \ + "mov eax, cr3" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMSetCR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetCR3 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov cr3, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +#undef ASMReloadCR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMReloadCR3 = \ + ".386" \ + "mov eax, cr3" \ + "mov cr3, eax" \ + parm [] nomemory \ + modify exact [ax] nomemory; +#endif + +#undef ASMGetCR4 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetCR4 = \ + ".386" \ + "mov eax, cr4" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMSetCR4 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetCR4 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov cr4, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +/* ASMGetCR8: Don't bother for 16-bit. */ +/* ASMSetCR8: Don't bother for 16-bit. */ + +#undef ASMIntEnable +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMIntEnable = \ + "sti" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMIntDisable +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMIntDisable = \ + "cli" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMIntDisableFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMIntDisableFlags = \ + "pushf" \ + "cli" \ + "pop ax" \ + parm [] nomemory \ + value [ax] \ + modify exact [] nomemory; +#endif + +#undef ASMHalt +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMHalt = \ + "hlt" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMRdMsr +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMRdMsr = \ + ".586" \ + "shl ecx, 16" \ + "mov cx, ax" \ + "rdmsr" \ + "mov ebx, edx" \ + "mov ecx, eax" \ + "shr ecx, 16" \ + "xchg eax, edx" \ + "shr eax, 16" \ + parm [ax cx] nomemory \ + value [dx cx bx ax] \ + modify exact [ax bx cx dx] nomemory; +#endif + +/* ASMWrMsr: Implemented externally, lazy bird. */ +/* ASMRdMsrEx: Implemented externally, lazy bird. */ +/* ASMWrMsrEx: Implemented externally, lazy bird. */ + +#undef ASMRdMsr_Low +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMRdMsr_Low = \ + ".586" \ + "shl ecx, 16" \ + "mov cx, ax" \ + "rdmsr" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [ax cx] nomemory \ + value [ax dx] \ + modify exact [ax bx cx dx] nomemory; +#endif + +#undef ASMRdMsr_High +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMRdMsr_High = \ + ".586" \ + "shl ecx, 16" \ + "mov cx, ax" \ + "rdmsr" \ + "mov eax, edx" \ + "shr edx, 16" \ + parm [ax cx] nomemory \ + value [ax dx] \ + modify exact [ax bx cx dx] nomemory; +#endif + + +#undef ASMGetDR0 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetDR0 = \ + ".386" \ + "mov eax, dr0" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMGetDR1 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetDR1 = \ + ".386" \ + "mov eax, dr1" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMGetDR2 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetDR2 = \ + ".386" \ + "mov eax, dr2" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMGetDR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetDR3 = \ + ".386" \ + "mov eax, dr3" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMGetDR6 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetDR6 = \ + ".386" \ + "mov eax, dr6" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMGetAndClearDR6 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetAndClearDR6 = \ + ".386" \ + "mov edx, 0ffff0ff0h" \ + "mov eax, dr6" \ + "mov dr6, edx" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMGetDR7 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMGetDR7 = \ + ".386" \ + "mov eax, dr7" \ + "mov edx, eax" \ + "shr edx, 16" \ + parm [] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMSetDR0 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetDR0 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov dr0, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +#undef ASMSetDR1 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetDR1 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov dr1, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +#undef ASMSetDR2 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetDR2 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov dr2, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +#undef ASMSetDR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetDR3 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov dr3, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +#undef ASMSetDR6 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetDR6 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov dr6, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +#undef ASMSetDR7 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMSetDR7 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "mov dr7, edx" \ + parm [ax dx] nomemory \ + modify exact [dx] nomemory; +#endif + +/* Yeah, could've used outp here, but this keeps the main file simpler. */ +#undef ASMOutU8 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMOutU8 = \ + "out dx, al" \ + parm [dx] [al] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMInU8 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMInU8 = \ + "in al, dx" \ + parm [dx] nomemory \ + value [al] \ + modify exact [] nomemory; +#endif + +#undef ASMOutU16 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMOutU16 = \ + "out dx, ax" \ + parm [dx] [ax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMInU16 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMInU16 = \ + "in ax, dx" \ + parm [dx] nomemory \ + value [ax] \ + modify exact [] nomemory; +#endif + +#undef ASMOutU32 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMOutU32 = \ + ".386" \ + "shl ecx, 16" \ + "mov cx, ax" \ + "mov eax, ecx" \ + "out dx, eax" \ + parm [dx] [ax cx] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMInU32 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMInU32 = \ + ".386" \ + "in eax, dx" \ + "mov ecx, eax" \ + "shr ecx, 16" \ + parm [dx] nomemory \ + value [ax cx] \ + modify exact [] nomemory; +#endif + +#undef ASMOutStrU8 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMOutStrU8 = \ + ".186" \ + "mov ax, ds" \ + "mov ds, di" \ + "rep outsb" \ + "mov ds, ax" \ + parm [dx] [si di] [cx] nomemory \ + modify exact [si cx ax] nomemory; +#endif + +#undef ASMInStrU8 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMInStrU8 = \ + ".186" \ + "rep insb" \ + parm [dx] [di es] [cx] \ + modify exact [di cx]; +#endif + +#undef ASMOutStrU16 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMOutStrU16 = \ + ".186" \ + "mov ax, ds" \ + "mov ds, di" \ + "rep outsw" \ + "mov ds, ax" \ + parm [dx] [si di] [cx] nomemory \ + modify exact [si cx ax] nomemory; +#endif + +#undef ASMInStrU16 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMInStrU16 = \ + ".186" \ + "rep insw" \ + parm [dx] [di es] [cx] \ + modify exact [di cx]; +#endif + +#undef ASMOutStrU32 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMOutStrU32 = \ + ".386" \ + "mov ax, ds" \ + "mov ds, di" \ + "rep outsd" \ + "mov ds, ax" \ + parm [dx] [si di] [cx] nomemory \ + modify exact [si cx ax] nomemory; +#endif + +#undef ASMInStrU32 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMInStrU32 = \ + ".386" \ + "rep insd" \ + parm [dx] [es di] [cx] \ + modify exact [di cx]; +#endif + +#undef ASMInvalidatePage +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMInvalidatePage = \ + ".486" \ + "shl edx, 16" \ + "mov dx, ax" \ + "invlpg [edx]" \ + parm [ax dx] \ + modify exact [dx]; +#endif + +#undef ASMWriteBackAndInvalidateCaches +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMWriteBackAndInvalidateCaches = \ + ".486" \ + "wbinvd" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMInvalidateInternalCaches +#ifdef IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +#pragma aux ASMInvalidateInternalCaches = \ + ".486" \ + "invd" \ + parm [] \ + modify exact []; +#endif + +#endif /* !IPRT_INCLUDED_asm_amd64_x86_watcom_16_h */ + diff --git a/include/iprt/asm-amd64-x86-watcom-32.h b/include/iprt/asm-amd64-x86-watcom-32.h new file mode 100644 index 00000000..4486bb5b --- /dev/null +++ b/include/iprt/asm-amd64-x86-watcom-32.h @@ -0,0 +1,737 @@ +/** @file + * IPRT - AMD64 and x86 Specific Assembly Functions, 32-bit Watcom C pragma aux. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asm_amd64_x86_watcom_32_h +#define IPRT_INCLUDED_asm_amd64_x86_watcom_32_h +/* no pragma once */ + +#ifndef IPRT_INCLUDED_asm_amd64_x86_h +# error "Don't include this header directly." +#endif + +#ifndef __FLAT__ +# error "Only works with flat pointers! (-mf)" +#endif + +/* + * Note! The #undef that preceds the #pragma aux statements is for undoing + * the mangling, because the symbol in #pragma aux [symbol] statements + * doesn't get subjected to preprocessing. This is also why we include + * the watcom header at both the top and the bottom of asm-amd64-x86.h file. + */ + +#undef ASMGetIDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetIDTR = \ + "sidt fword ptr [ecx]" \ + parm [ecx] \ + modify exact []; +#endif + +#undef ASMGetIdtrLimit +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetIdtrLimit = \ + "sub esp, 8" \ + "sidt fword ptr [esp]" \ + "mov cx, [esp]" \ + "add esp, 8" \ + parm [] \ + value [cx] \ + modify exact [ecx]; +#endif + +#undef ASMSetIDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetIDTR = \ + "lidt fword ptr [ecx]" \ + parm [ecx] nomemory \ + modify nomemory; +#endif + +#undef ASMGetGDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetGDTR = \ + "sgdt fword ptr [ecx]" \ + parm [ecx] \ + modify exact []; +#endif + +#undef ASMSetGDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetGDTR = \ + "lgdt fword ptr [ecx]" \ + parm [ecx] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMGetCS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetCS = \ + "mov ax, cs" \ + parm [] nomemory \ + value [ax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetDS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetDS = \ + "mov ax, ds" \ + parm [] nomemory \ + value [ax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetES +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetES = \ + "mov ax, es" \ + parm [] nomemory \ + value [ax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetFS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetFS = \ + "mov ax, fs" \ + parm [] nomemory \ + value [ax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetGS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetGS = \ + "mov ax, gs" \ + parm [] nomemory \ + value [ax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetSS +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetSS = \ + "mov ax, ss" \ + parm [] nomemory \ + value [ax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetTR = \ + "str ax" \ + parm [] nomemory \ + value [ax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetLDTR +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetLDTR = \ + "sldt ax" \ + parm [] nomemory \ + value [ax] \ + modify exact [eax] nomemory; +#endif + +/** @todo ASMGetSegAttr */ + +#undef ASMGetFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetFlags = \ + "pushfd" \ + "pop eax" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMSetFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetFlags = \ + "push eax" \ + "popfd" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMChangeFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMChangeFlags = \ + "pushfd" \ + "pop eax" \ + "and edx, eax" \ + "or edx, ecx" \ + "push edx" \ + "popfd" \ + parm [edx] [ecx] nomemory \ + value [eax] \ + modify exact [edx] nomemory; +#endif + +#undef ASMAddFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMAddFlags = \ + "pushfd" \ + "pop eax" \ + "or edx, eax" \ + "push edx" \ + "popfd" \ + parm [edx] nomemory \ + value [eax] \ + modify exact [edx] nomemory; +#endif + +#undef ASMClearFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMClearFlags = \ + "pushfd" \ + "pop eax" \ + "and edx, eax" \ + "push edx" \ + "popfd" \ + parm [edx] nomemory \ + value [eax] \ + modify exact [edx] nomemory; +#endif + +/* Note! Must use the 64-bit integer return value convension. + The order of registers in the value [set] does not seem to mean anything. */ +#undef ASMReadTSC +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMReadTSC = \ + ".586" \ + "rdtsc" \ + parm [] nomemory \ + value [eax edx] \ + modify exact [edx eax] nomemory; +#endif + +#undef ASMReadTscWithAux +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMReadTscWithAux = \ + 0x0f 0x01 0xf9 \ + "mov [ebx], ecx" \ + parm [ebx] \ + value [eax edx] \ + modify exact [eax edx ecx]; +#endif + +/* ASMCpuId: Implemented externally, too many parameters. */ +/* ASMCpuId_Idx_ECX: Implemented externally, too many parameters. */ +/* ASMCpuIdExSlow: Always implemented externally. */ + +#undef ASMCpuId_ECX_EDX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMCpuId_ECX_EDX = \ + ".586" \ + "cpuid" \ + "mov [edi], ecx" \ + "mov [esi], edx" \ + parm [eax] [edi] [esi] \ + modify exact [eax ebx ecx edx]; +#endif + +#undef ASMCpuId_EAX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMCpuId_EAX = \ + ".586" \ + "cpuid" \ + parm [eax] \ + value [eax] \ + modify exact [eax ebx ecx edx]; +#endif + +#undef ASMCpuId_EBX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMCpuId_EBX = \ + ".586" \ + "cpuid" \ + parm [eax] \ + value [ebx] \ + modify exact [eax ebx ecx edx]; +#endif + +#undef ASMCpuId_ECX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMCpuId_ECX = \ + ".586" \ + "cpuid" \ + parm [eax] \ + value [ecx] \ + modify exact [eax ebx ecx edx]; +#endif + +#undef ASMCpuId_EDX +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMCpuId_EDX = \ + ".586" \ + "cpuid" \ + parm [eax] \ + value [edx] \ + modify exact [eax ebx ecx edx]; +#endif + +/* ASMHasCpuId: MSC inline in main source file. */ + +#undef ASMGetApicId +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetApicId = \ + ".586" \ + "xor eax, eax" \ + "cpuid" \ + "shr ebx,24" \ + parm [] \ + value [bl] \ + modify exact [eax ebx ecx edx]; +#endif + +#undef ASMGetCR0 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetCR0 = \ + "mov eax, cr0" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMSetCR0 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetCR0 = \ + "mov cr0, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMGetCR2 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetCR2 = \ + "mov eax, cr2" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMSetCR2 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetCR2 = \ + "mov cr2, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMGetCR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetCR3 = \ + "mov eax, cr3" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMSetCR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetCR3 = \ + "mov cr3, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMReloadCR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMReloadCR3 = \ + "mov eax, cr3" \ + "mov cr3, eax" \ + parm [] nomemory \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetCR4 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetCR4 = \ + "mov eax, cr4" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMSetCR4 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetCR4 = \ + "mov cr4, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +/* ASMGetCR8: Don't bother for 32-bit. */ +/* ASMSetCR8: Don't bother for 32-bit. */ + +#undef ASMIntEnable +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMIntEnable = \ + "sti" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMIntDisable +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMIntDisable = \ + "cli" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMIntDisableFlags +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMIntDisableFlags = \ + "pushfd" \ + "cli" \ + "pop eax" \ + parm [] nomemory \ + value [eax] \ + modify exact [] nomemory; +#endif + +#undef ASMHalt +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMHalt = \ + "hlt" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMRdMsr +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMRdMsr = \ + ".586" \ + "rdmsr" \ + parm [ecx] nomemory \ + value [eax edx] \ + modify exact [eax edx] nomemory; +#endif + +#undef ASMWrMsr +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMWrMsr = \ + ".586" \ + "wrmsr" \ + parm [ecx] [eax edx] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMRdMsrEx +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMRdMsrEx = \ + ".586" \ + "rdmsr" \ + parm [ecx] [edi] nomemory \ + value [eax edx] \ + modify exact [eax edx] nomemory; +#endif + +#undef ASMWrMsrEx +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMWrMsrEx = \ + ".586" \ + "wrmsr" \ + parm [ecx] [edi] [eax edx] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMRdMsr_Low +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMRdMsr_Low = \ + ".586" \ + "rdmsr" \ + parm [ecx] nomemory \ + value [eax] \ + modify exact [eax edx] nomemory; +#endif + +#undef ASMRdMsr_High +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMRdMsr_High = \ + ".586" \ + "rdmsr" \ + parm [ecx] nomemory \ + value [edx] \ + modify exact [eax edx] nomemory; +#endif + + +#undef ASMGetDR0 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetDR0 = \ + "mov eax, dr0" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetDR1 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetDR1 = \ + "mov eax, dr1" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetDR2 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetDR2 = \ + "mov eax, dr2" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetDR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetDR3 = \ + "mov eax, dr3" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetDR6 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetDR6 = \ + "mov eax, dr6" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMGetAndClearDR6 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetAndClearDR6 = \ + "mov edx, 0ffff0ff0h" \ + "mov eax, dr6" \ + "mov dr6, edx" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax edx] nomemory; +#endif + +#undef ASMGetDR7 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMGetDR7 = \ + "mov eax, dr7" \ + parm [] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMSetDR0 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetDR0 = \ + "mov dr0, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMSetDR1 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetDR1 = \ + "mov dr1, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMSetDR2 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetDR2 = \ + "mov dr2, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMSetDR3 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetDR3 = \ + "mov dr3, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMSetDR6 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetDR6 = \ + "mov dr6, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMSetDR7 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMSetDR7 = \ + "mov dr7, eax" \ + parm [eax] nomemory \ + modify exact [] nomemory; +#endif + +/* Yeah, could've used outp here, but this keeps the main file simpler. */ +#undef ASMOutU8 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMOutU8 = \ + "out dx, al" \ + parm [dx] [al] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMInU8 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMInU8 = \ + "in al, dx" \ + parm [dx] nomemory \ + value [al] \ + modify exact [] nomemory; +#endif + +#undef ASMOutU16 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMOutU16 = \ + "out dx, ax" \ + parm [dx] [ax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMInU16 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMInU16 = \ + "in ax, dx" \ + parm [dx] nomemory \ + value [ax] \ + modify exact [] nomemory; +#endif + +#undef ASMOutU32 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMOutU32 = \ + "out dx, eax" \ + parm [dx] [eax] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMInU32 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMInU32 = \ + "in eax, dx" \ + parm [dx] nomemory \ + value [eax] \ + modify exact [] nomemory; +#endif + +#undef ASMOutStrU8 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMOutStrU8 = \ + "rep outsb" \ + parm [dx] [esi] [ecx] nomemory \ + modify exact [esi ecx] nomemory; +#endif + +#undef ASMInStrU8 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMInStrU8 = \ + "rep insb" \ + parm [dx] [edi] [ecx] \ + modify exact [edi ecx]; +#endif + +#undef ASMOutStrU16 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMOutStrU16 = \ + "rep outsw" \ + parm [dx] [esi] [ecx] nomemory \ + modify exact [esi ecx] nomemory; +#endif + +#undef ASMInStrU16 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMInStrU16 = \ + "rep insw" \ + parm [dx] [edi] [ecx] \ + modify exact [edi ecx]; +#endif + +#undef ASMOutStrU32 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMOutStrU32 = \ + "rep outsd" \ + parm [dx] [esi] [ecx] nomemory \ + modify exact [esi ecx] nomemory; +#endif + +#undef ASMInStrU32 +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMInStrU32 = \ + "rep insd" \ + parm [dx] [edi] [ecx] \ + modify exact [edi ecx]; +#endif + +#undef ASMInvalidatePage +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMInvalidatePage = \ + "invlpg [eax]" \ + parm [eax] \ + modify exact []; +#endif + +#undef ASMWriteBackAndInvalidateCaches +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMWriteBackAndInvalidateCaches = \ + ".486" \ + "wbinvd" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMInvalidateInternalCaches +#ifdef IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +#pragma aux ASMInvalidateInternalCaches = \ + ".486" \ + "invd" \ + parm [] \ + modify exact []; +#endif + +#endif /* !IPRT_INCLUDED_asm_amd64_x86_watcom_32_h */ + diff --git a/include/iprt/asm-amd64-x86.h b/include/iprt/asm-amd64-x86.h new file mode 100644 index 00000000..0bfa1925 --- /dev/null +++ b/include/iprt/asm-amd64-x86.h @@ -0,0 +1,3447 @@ +/** @file + * IPRT - AMD64 and x86 Specific Assembly Functions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asm_amd64_x86_h +#define IPRT_INCLUDED_asm_amd64_x86_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assert.h> +#include <iprt/x86-helpers.h> +#if !defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86) +# error "Not on AMD64 or x86" +#endif + +#if defined(_MSC_VER) && RT_INLINE_ASM_USES_INTRIN +/* Emit the intrinsics at all optimization levels. */ +# include <iprt/sanitized/intrin.h> +# pragma intrinsic(_ReadWriteBarrier) +# pragma intrinsic(__cpuid) +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2010 /*?*/ +# pragma intrinsic(__cpuidex) +# endif +# pragma intrinsic(_enable) +# pragma intrinsic(_disable) +# pragma intrinsic(__rdtsc) +# pragma intrinsic(__readmsr) +# pragma intrinsic(__writemsr) +# pragma intrinsic(__outbyte) +# pragma intrinsic(__outbytestring) +# pragma intrinsic(__outword) +# pragma intrinsic(__outwordstring) +# pragma intrinsic(__outdword) +# pragma intrinsic(__outdwordstring) +# pragma intrinsic(__inbyte) +# pragma intrinsic(__inbytestring) +# pragma intrinsic(__inword) +# pragma intrinsic(__inwordstring) +# pragma intrinsic(__indword) +# pragma intrinsic(__indwordstring) +# pragma intrinsic(__invlpg) +# pragma intrinsic(__wbinvd) +# pragma intrinsic(__readcr0) +# pragma intrinsic(__readcr2) +# pragma intrinsic(__readcr3) +# pragma intrinsic(__readcr4) +# pragma intrinsic(__writecr0) +# pragma intrinsic(__writecr3) +# pragma intrinsic(__writecr4) +# pragma intrinsic(__readdr) +# pragma intrinsic(__writedr) +# ifdef RT_ARCH_AMD64 +# pragma intrinsic(__readcr8) +# pragma intrinsic(__writecr8) +# endif +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2005 +# pragma intrinsic(__halt) +# endif +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008 +/*# pragma intrinsic(__readeflags) - buggy intrinsics in VC++ 2010, reordering/optimizers issues +# pragma intrinsic(__writeeflags) */ +# pragma intrinsic(__rdtscp) +# endif +# if defined(RT_ARCH_AMD64) && RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2015 /*?*/ +# pragma intrinsic(_readfsbase_u64) +# pragma intrinsic(_readgsbase_u64) +# pragma intrinsic(_writefsbase_u64) +# pragma intrinsic(_writegsbase_u64) +# endif +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013 +# pragma intrinsic(__lidt) +# pragma intrinsic(__sidt) +# pragma intrinsic(_lgdt) +# pragma intrinsic(_sgdt) +# endif +#endif + + +/* + * Undefine all symbols we have Watcom C/C++ #pragma aux'es for. + */ +#if defined(__WATCOMC__) && ARCH_BITS == 16 +# include "asm-amd64-x86-watcom-16.h" +#elif defined(__WATCOMC__) && ARCH_BITS == 32 +# include "asm-amd64-x86-watcom-32.h" +#endif + + +/** @defgroup grp_rt_asm_amd64_x86 AMD64 and x86 Specific ASM Routines + * @ingroup grp_rt_asm + * @{ + */ + +/** @todo find a more proper place for these structures? */ + +#pragma pack(1) +/** IDTR */ +typedef struct RTIDTR +{ + /** Size of the IDT. */ + uint16_t cbIdt; + /** Address of the IDT. */ +#if ARCH_BITS != 64 + uint32_t pIdt; +#else + uint64_t pIdt; +#endif +} RTIDTR, RT_FAR *PRTIDTR; +#pragma pack() + +#pragma pack(1) +/** @internal */ +typedef struct RTIDTRALIGNEDINT +{ + /** Alignment padding. */ + uint16_t au16Padding[ARCH_BITS == 64 ? 3 : 1]; + /** The IDTR structure. */ + RTIDTR Idtr; +} RTIDTRALIGNEDINT; +#pragma pack() + +/** Wrapped RTIDTR for preventing misalignment exceptions. */ +typedef union RTIDTRALIGNED +{ + /** Try make sure this structure has optimal alignment. */ + uint64_t auAlignmentHack[ARCH_BITS == 64 ? 2 : 1]; + /** Aligned structure. */ + RTIDTRALIGNEDINT s; +} RTIDTRALIGNED; +AssertCompileSize(RTIDTRALIGNED, ((ARCH_BITS == 64) + 1) * 8); +/** Pointer to a an RTIDTR alignment wrapper. */ +typedef RTIDTRALIGNED RT_FAR *PRIDTRALIGNED; + + +#pragma pack(1) +/** GDTR */ +typedef struct RTGDTR +{ + /** Size of the GDT. */ + uint16_t cbGdt; + /** Address of the GDT. */ +#if ARCH_BITS != 64 + uint32_t pGdt; +#else + uint64_t pGdt; +#endif +} RTGDTR, RT_FAR *PRTGDTR; +#pragma pack() + +#pragma pack(1) +/** @internal */ +typedef struct RTGDTRALIGNEDINT +{ + /** Alignment padding. */ + uint16_t au16Padding[ARCH_BITS == 64 ? 3 : 1]; + /** The GDTR structure. */ + RTGDTR Gdtr; +} RTGDTRALIGNEDINT; +#pragma pack() + +/** Wrapped RTGDTR for preventing misalignment exceptions. */ +typedef union RTGDTRALIGNED +{ + /** Try make sure this structure has optimal alignment. */ + uint64_t auAlignmentHack[ARCH_BITS == 64 ? 2 : 1]; + /** Aligned structure. */ + RTGDTRALIGNEDINT s; +} RTGDTRALIGNED; +AssertCompileSize(RTIDTRALIGNED, ((ARCH_BITS == 64) + 1) * 8); +/** Pointer to a an RTGDTR alignment wrapper. */ +typedef RTGDTRALIGNED RT_FAR *PRGDTRALIGNED; + + +/** + * Gets the content of the IDTR CPU register. + * @param pIdtr Where to store the IDTR contents. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2013 +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMGetIDTR(PRTIDTR pIdtr); +#else +DECLINLINE(void) ASMGetIDTR(PRTIDTR pIdtr) +{ +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013 + __sidt(pIdtr); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("sidt %0" : "=m" (*pIdtr)); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pIdtr] + sidt [rax] +# else + mov eax, [pIdtr] + sidt [eax] +# endif + } +# endif +} +#endif + + +/** + * Gets the content of the IDTR.LIMIT CPU register. + * @returns IDTR limit. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2013 +RT_ASM_DECL_PRAGMA_WATCOM(uint16_t) ASMGetIdtrLimit(void); +#else +DECLINLINE(uint16_t) ASMGetIdtrLimit(void) +{ + RTIDTRALIGNED TmpIdtr; +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013 + __sidt(&TmpIdtr); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("sidt %0" : "=m" (TmpIdtr.s.Idtr)); +# else + __asm + { + sidt [TmpIdtr.s.Idtr] + } +# endif + return TmpIdtr.s.Idtr.cbIdt; +} +#endif + + +/** + * Sets the content of the IDTR CPU register. + * @param pIdtr Where to load the IDTR contents from + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2013 +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetIDTR(const RTIDTR RT_FAR *pIdtr); +#else +DECLINLINE(void) ASMSetIDTR(const RTIDTR RT_FAR *pIdtr) +{ +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013 + __lidt((void *)pIdtr); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lidt %0" : : "m" (*pIdtr)); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pIdtr] + lidt [rax] +# else + mov eax, [pIdtr] + lidt [eax] +# endif + } +# endif +} +#endif + + +/** + * Gets the content of the GDTR CPU register. + * @param pGdtr Where to store the GDTR contents. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2013 +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMGetGDTR(PRTGDTR pGdtr); +#else +DECLINLINE(void) ASMGetGDTR(PRTGDTR pGdtr) +{ +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013 + _sgdt(pGdtr); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("sgdt %0" : "=m" (*pGdtr)); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pGdtr] + sgdt [rax] +# else + mov eax, [pGdtr] + sgdt [eax] +# endif + } +# endif +} +#endif + + +/** + * Sets the content of the GDTR CPU register. + * @param pGdtr Where to load the GDTR contents from + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2013 +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetGDTR(const RTGDTR RT_FAR *pGdtr); +#else +DECLINLINE(void) ASMSetGDTR(const RTGDTR RT_FAR *pGdtr) +{ +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013 + _lgdt((void *)pGdtr); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lgdt %0" : : "m" (*pGdtr)); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pGdtr] + lgdt [rax] +# else + mov eax, [pGdtr] + lgdt [eax] +# endif + } +# endif +} +#endif + + + +/** + * Get the cs register. + * @returns cs. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetCS(void); +#else +DECLINLINE(RTSEL) ASMGetCS(void) +{ + RTSEL SelCS; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("movw %%cs, %0\n\t" : "=r" (SelCS)); +# else + __asm + { + mov ax, cs + mov [SelCS], ax + } +# endif + return SelCS; +} +#endif + + +/** + * Get the DS register. + * @returns DS. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetDS(void); +#else +DECLINLINE(RTSEL) ASMGetDS(void) +{ + RTSEL SelDS; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("movw %%ds, %0\n\t" : "=r" (SelDS)); +# else + __asm + { + mov ax, ds + mov [SelDS], ax + } +# endif + return SelDS; +} +#endif + + +/** + * Get the ES register. + * @returns ES. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetES(void); +#else +DECLINLINE(RTSEL) ASMGetES(void) +{ + RTSEL SelES; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("movw %%es, %0\n\t" : "=r" (SelES)); +# else + __asm + { + mov ax, es + mov [SelES], ax + } +# endif + return SelES; +} +#endif + + +/** + * Get the FS register. + * @returns FS. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetFS(void); +#else +DECLINLINE(RTSEL) ASMGetFS(void) +{ + RTSEL SelFS; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("movw %%fs, %0\n\t" : "=r" (SelFS)); +# else + __asm + { + mov ax, fs + mov [SelFS], ax + } +# endif + return SelFS; +} +# endif + +#ifdef RT_ARCH_AMD64 + +/** + * Get the FS base register. + * @returns FS base address. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2015 /*?*/ +DECLASM(uint64_t) ASMGetFSBase(void); +#else +DECLINLINE(uint64_t) ASMGetFSBase(void) +{ +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2015 + return (uint64_t)_readfsbase_u64(); +# elif RT_INLINE_ASM_GNU_STYLE + uint64_t uFSBase; + __asm__ __volatile__("rdfsbase %0\n\t" : "=r" (uFSBase)); + return uFSBase; +# endif +} +# endif + + +/** + * Set the FS base register. + * @param uNewBase The new base value. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2015 /*?*/ +DECLASM(void) ASMSetFSBase(uint64_t uNewBase); +#else +DECLINLINE(void) ASMSetFSBase(uint64_t uNewBase) +{ +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2015 + _writefsbase_u64(uNewBase); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("wrfsbase %0\n\t" : : "r" (uNewBase)); +# endif +} +# endif + +#endif /* RT_ARCH_AMD64 */ + +/** + * Get the GS register. + * @returns GS. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetGS(void); +#else +DECLINLINE(RTSEL) ASMGetGS(void) +{ + RTSEL SelGS; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("movw %%gs, %0\n\t" : "=r" (SelGS)); +# else + __asm + { + mov ax, gs + mov [SelGS], ax + } +# endif + return SelGS; +} +#endif + +#ifdef RT_ARCH_AMD64 + +/** + * Get the GS base register. + * @returns GS base address. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2015 /*?*/ +DECLASM(uint64_t) ASMGetGSBase(void); +#else +DECLINLINE(uint64_t) ASMGetGSBase(void) +{ +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2015 + return (uint64_t)_readgsbase_u64(); +# elif RT_INLINE_ASM_GNU_STYLE + uint64_t uGSBase; + __asm__ __volatile__("rdgsbase %0\n\t" : "=r" (uGSBase)); + return uGSBase; +# endif +} +# endif + + +/** + * Set the GS base register. + * @param uNewBase The new base value. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2015 /*?*/ +DECLASM(void) ASMSetGSBase(uint64_t uNewBase); +#else +DECLINLINE(void) ASMSetGSBase(uint64_t uNewBase) +{ +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2015 + _writegsbase_u64(uNewBase); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("wrgsbase %0\n\t" : : "r" (uNewBase)); +# endif +} +# endif + +#endif /* RT_ARCH_AMD64 */ + + +/** + * Get the SS register. + * @returns SS. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetSS(void); +#else +DECLINLINE(RTSEL) ASMGetSS(void) +{ + RTSEL SelSS; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("movw %%ss, %0\n\t" : "=r" (SelSS)); +# else + __asm + { + mov ax, ss + mov [SelSS], ax + } +# endif + return SelSS; +} +#endif + + +/** + * Get the TR register. + * @returns TR. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetTR(void); +#else +DECLINLINE(RTSEL) ASMGetTR(void) +{ + RTSEL SelTR; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("str %w0\n\t" : "=r" (SelTR)); +# else + __asm + { + str ax + mov [SelTR], ax + } +# endif + return SelTR; +} +#endif + + +/** + * Get the LDTR register. + * @returns LDTR. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetLDTR(void); +#else +DECLINLINE(RTSEL) ASMGetLDTR(void) +{ + RTSEL SelLDTR; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("sldt %w0\n\t" : "=r" (SelLDTR)); +# else + __asm + { + sldt ax + mov [SelLDTR], ax + } +# endif + return SelLDTR; +} +#endif + + +/** + * Get the access rights for the segment selector. + * + * @returns The access rights on success or UINT32_MAX on failure. + * @param uSel The selector value. + * + * @remarks Using UINT32_MAX for failure is chosen because valid access rights + * always have bits 0:7 as 0 (on both Intel & AMD). + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMGetSegAttr(uint32_t uSel); +#else +DECLINLINE(uint32_t) ASMGetSegAttr(uint32_t uSel) +{ + uint32_t uAttr; + /* LAR only accesses 16-bit of the source operand, but eax for the + destination operand is required for getting the full 32-bit access rights. */ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lar %1, %%eax\n\t" + "jz done%=\n\t" + "movl $0xffffffff, %%eax\n\t" + "done%=:\n\t" + "movl %%eax, %0\n\t" + : "=r" (uAttr) + : "r" (uSel) + : "cc", "%eax"); +# else + __asm + { + lar eax, [uSel] + jz done + mov eax, 0ffffffffh + done: + mov [uAttr], eax + } +# endif + return uAttr; +} +#endif + + +/** + * Get the [RE]FLAGS register. + * @returns [RE]FLAGS. + */ +#if RT_INLINE_ASM_EXTERNAL /*&& RT_INLINE_ASM_USES_INTRIN < 15 - buggy intrinsics in VC++ 2010, reordering/optimizers issues. */ +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTREG) ASMGetFlags(void); +#else +DECLINLINE(RTCCUINTREG) ASMGetFlags(void) +{ + RTCCUINTREG uFlags; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("pushfq\n\t" + "popq %0\n\t" + : "=r" (uFlags)); +# else + __asm__ __volatile__("pushfl\n\t" + "popl %0\n\t" + : "=r" (uFlags)); +# endif +# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008 + uFlags = __readeflags(); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + pushfq + pop [uFlags] +# else + pushfd + pop [uFlags] +# endif + } +# endif + return uFlags; +} +#endif + + +/** + * Set the [RE]FLAGS register. + * @param uFlags The new [RE]FLAGS value. + */ +#if RT_INLINE_ASM_EXTERNAL /*&& RT_INLINE_ASM_USES_INTRIN < 15 - see __readeflags() above. */ +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetFlags(RTCCUINTREG uFlags); +#else +DECLINLINE(void) ASMSetFlags(RTCCUINTREG uFlags) +{ +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("pushq %0\n\t" + "popfq\n\t" + : : "g" (uFlags)); +# else + __asm__ __volatile__("pushl %0\n\t" + "popfl\n\t" + : : "g" (uFlags)); +# endif +# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008 + __writeeflags(uFlags); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + push [uFlags] + popfq +# else + push [uFlags] + popfd +# endif + } +# endif +} +#endif + + +/** + * Modifies the [RE]FLAGS register. + * @returns Original value. + * @param fAndEfl Flags to keep (applied first). + * @param fOrEfl Flags to be set. + */ +#if RT_INLINE_ASM_EXTERNAL /*&& RT_INLINE_ASM_USES_INTRIN < 15 - buggy intrinsics in VC++ 2010, reordering/optimizers issues. */ +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTREG) ASMChangeFlags(RTCCUINTREG fAndEfl, RTCCUINTREG fOrEfl); +#else +DECLINLINE(RTCCUINTREG) ASMChangeFlags(RTCCUINTREG fAndEfl, RTCCUINTREG fOrEfl) +{ + RTCCUINTREG fOldEfl; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("pushfq\n\t" + "movq (%%rsp), %0\n\t" + "andq %0, %1\n\t" + "orq %3, %1\n\t" + "mov %1, (%%rsp)\n\t" + "popfq\n\t" + : "=&r" (fOldEfl), + "=r" (fAndEfl) + : "1" (fAndEfl), + "rn" (fOrEfl) ); +# else + __asm__ __volatile__("pushfl\n\t" + "movl (%%esp), %0\n\t" + "andl %1, (%%esp)\n\t" + "orl %2, (%%esp)\n\t" + "popfl\n\t" + : "=&r" (fOldEfl) + : "rn" (fAndEfl), + "rn" (fOrEfl) ); +# endif +# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008 + fOldEfl = __readeflags(); + __writeeflags((fOldEfl & fAndEfl) | fOrEfl); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [fAndEfl] + mov rcx, [fOrEfl] + pushfq + mov rax, [rsp] + and rdx, rax + or rdx, rcx + mov [rsp], rdx + popfq + mov [fOldEfl], rax +# else + mov edx, [fAndEfl] + mov ecx, [fOrEfl] + pushfd + mov eax, [esp] + and edx, eax + or edx, ecx + mov [esp], edx + popfd + mov [fOldEfl], eax +# endif + } +# endif + return fOldEfl; +} +#endif + + +/** + * Modifies the [RE]FLAGS register by ORing in one or more flags. + * @returns Original value. + * @param fOrEfl The flags to be set (ORed in). + */ +#if RT_INLINE_ASM_EXTERNAL /*&& RT_INLINE_ASM_USES_INTRIN < 15 - buggy intrinsics in VC++ 2010, reordering/optimizers issues. */ +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTREG) ASMAddFlags(RTCCUINTREG fOrEfl); +#else +DECLINLINE(RTCCUINTREG) ASMAddFlags(RTCCUINTREG fOrEfl) +{ + RTCCUINTREG fOldEfl; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("pushfq\n\t" + "movq (%%rsp), %0\n\t" + "orq %1, (%%rsp)\n\t" + "popfq\n\t" + : "=&r" (fOldEfl) + : "rn" (fOrEfl) ); +# else + __asm__ __volatile__("pushfl\n\t" + "movl (%%esp), %0\n\t" + "orl %1, (%%esp)\n\t" + "popfl\n\t" + : "=&r" (fOldEfl) + : "rn" (fOrEfl) ); +# endif +# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008 + fOldEfl = __readeflags(); + __writeeflags(fOldEfl | fOrEfl); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rcx, [fOrEfl] + pushfq + mov rdx, [rsp] + or [rsp], rcx + popfq + mov [fOldEfl], rax +# else + mov ecx, [fOrEfl] + pushfd + mov edx, [esp] + or [esp], ecx + popfd + mov [fOldEfl], eax +# endif + } +# endif + return fOldEfl; +} +#endif + + +/** + * Modifies the [RE]FLAGS register by AND'ing out one or more flags. + * @returns Original value. + * @param fAndEfl The flags to keep. + */ +#if RT_INLINE_ASM_EXTERNAL /*&& RT_INLINE_ASM_USES_INTRIN < 15 - buggy intrinsics in VC++ 2010, reordering/optimizers issues. */ +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTREG) ASMClearFlags(RTCCUINTREG fAndEfl); +#else +DECLINLINE(RTCCUINTREG) ASMClearFlags(RTCCUINTREG fAndEfl) +{ + RTCCUINTREG fOldEfl; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("pushfq\n\t" + "movq (%%rsp), %0\n\t" + "andq %1, (%%rsp)\n\t" + "popfq\n\t" + : "=&r" (fOldEfl) + : "rn" (fAndEfl) ); +# else + __asm__ __volatile__("pushfl\n\t" + "movl (%%esp), %0\n\t" + "andl %1, (%%esp)\n\t" + "popfl\n\t" + : "=&r" (fOldEfl) + : "rn" (fAndEfl) ); +# endif +# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008 + fOldEfl = __readeflags(); + __writeeflags(fOldEfl & fAndEfl); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [fAndEfl] + pushfq + mov rdx, [rsp] + and [rsp], rdx + popfq + mov [fOldEfl], rax +# else + mov edx, [fAndEfl] + pushfd + mov edx, [esp] + and [esp], edx + popfd + mov [fOldEfl], eax +# endif + } +# endif + return fOldEfl; +} +#endif + + +/** + * Gets the content of the CPU timestamp counter register. + * + * @returns TSC. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMReadTSC(void); +#else +DECLINLINE(uint64_t) ASMReadTSC(void) +{ + RTUINT64U u; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rdtsc\n\t" : "=a" (u.s.Lo), "=d" (u.s.Hi)); +# else +# if RT_INLINE_ASM_USES_INTRIN + u.u = __rdtsc(); +# else + __asm + { + rdtsc + mov [u.s.Lo], eax + mov [u.s.Hi], edx + } +# endif +# endif + return u.u; +} +#endif + + +/** + * Gets the content of the CPU timestamp counter register and the + * assoicated AUX value. + * + * @returns TSC. + * @param puAux Where to store the AUX value. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2008 +RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMReadTscWithAux(uint32_t RT_FAR *puAux); +#else +DECLINLINE(uint64_t) ASMReadTscWithAux(uint32_t RT_FAR *puAux) +{ + RTUINT64U u; +# if RT_INLINE_ASM_GNU_STYLE + /* rdtscp is not supported by ancient linux build VM of course :-( */ + /*__asm__ __volatile__("rdtscp\n\t" : "=a" (u.s.Lo), "=d" (u.s.Hi), "=c" (*puAux)); */ + __asm__ __volatile__(".byte 0x0f,0x01,0xf9\n\t" : "=a" (u.s.Lo), "=d" (u.s.Hi), "=c" (*puAux)); +# else +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008 + u.u = __rdtscp(puAux); +# else + __asm + { + rdtscp + mov [u.s.Lo], eax + mov [u.s.Hi], edx + mov eax, [puAux] + mov [eax], ecx + } +# endif +# endif + return u.u; +} +#endif + + +/** + * Performs the cpuid instruction returning all registers. + * + * @param uOperator CPUID operation (eax). + * @param pvEAX Where to store eax. + * @param pvEBX Where to store ebx. + * @param pvECX Where to store ecx. + * @param pvEDX Where to store edx. + * @remark We're using void pointers to ease the use of special bitfield structures and such. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +DECLASM(void) ASMCpuId(uint32_t uOperator, void RT_FAR *pvEAX, void RT_FAR *pvEBX, void RT_FAR *pvECX, void RT_FAR *pvEDX); +#else +DECLINLINE(void) ASMCpuId(uint32_t uOperator, void RT_FAR *pvEAX, void RT_FAR *pvEBX, void RT_FAR *pvECX, void RT_FAR *pvEDX) +{ +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + RTCCUINTREG uRAX, uRBX, uRCX, uRDX; + __asm__ __volatile__ ("cpuid\n\t" + : "=a" (uRAX), + "=b" (uRBX), + "=c" (uRCX), + "=d" (uRDX) + : "0" (uOperator), "2" (0)); + *(uint32_t RT_FAR *)pvEAX = (uint32_t)uRAX; + *(uint32_t RT_FAR *)pvEBX = (uint32_t)uRBX; + *(uint32_t RT_FAR *)pvECX = (uint32_t)uRCX; + *(uint32_t RT_FAR *)pvEDX = (uint32_t)uRDX; +# else + __asm__ __volatile__ ("xchgl %%ebx, %1\n\t" + "cpuid\n\t" + "xchgl %%ebx, %1\n\t" + : "=a" (*(uint32_t *)pvEAX), + "=r" (*(uint32_t *)pvEBX), + "=c" (*(uint32_t *)pvECX), + "=d" (*(uint32_t *)pvEDX) + : "0" (uOperator), "2" (0)); +# endif + +# elif RT_INLINE_ASM_USES_INTRIN + int aInfo[4]; + __cpuid(aInfo, uOperator); + *(uint32_t RT_FAR *)pvEAX = aInfo[0]; + *(uint32_t RT_FAR *)pvEBX = aInfo[1]; + *(uint32_t RT_FAR *)pvECX = aInfo[2]; + *(uint32_t RT_FAR *)pvEDX = aInfo[3]; + +# else + uint32_t uEAX; + uint32_t uEBX; + uint32_t uECX; + uint32_t uEDX; + __asm + { + push ebx + mov eax, [uOperator] + cpuid + mov [uEAX], eax + mov [uEBX], ebx + mov [uECX], ecx + mov [uEDX], edx + pop ebx + } + *(uint32_t RT_FAR *)pvEAX = uEAX; + *(uint32_t RT_FAR *)pvEBX = uEBX; + *(uint32_t RT_FAR *)pvECX = uECX; + *(uint32_t RT_FAR *)pvEDX = uEDX; +# endif +} +#endif + + +/** + * Performs the CPUID instruction with EAX and ECX input returning ALL output + * registers. + * + * @param uOperator CPUID operation (eax). + * @param uIdxECX ecx index + * @param pvEAX Where to store eax. + * @param pvEBX Where to store ebx. + * @param pvECX Where to store ecx. + * @param pvEDX Where to store edx. + * @remark We're using void pointers to ease the use of special bitfield structures and such. + */ +#if RT_INLINE_ASM_EXTERNAL || RT_INLINE_ASM_USES_INTRIN +DECLASM(void) ASMCpuId_Idx_ECX(uint32_t uOperator, uint32_t uIdxECX, void RT_FAR *pvEAX, void RT_FAR *pvEBX, void RT_FAR *pvECX, void RT_FAR *pvEDX); +#else +DECLINLINE(void) ASMCpuId_Idx_ECX(uint32_t uOperator, uint32_t uIdxECX, void RT_FAR *pvEAX, void RT_FAR *pvEBX, void RT_FAR *pvECX, void RT_FAR *pvEDX) +{ +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + RTCCUINTREG uRAX, uRBX, uRCX, uRDX; + __asm__ ("cpuid\n\t" + : "=a" (uRAX), + "=b" (uRBX), + "=c" (uRCX), + "=d" (uRDX) + : "0" (uOperator), + "2" (uIdxECX)); + *(uint32_t RT_FAR *)pvEAX = (uint32_t)uRAX; + *(uint32_t RT_FAR *)pvEBX = (uint32_t)uRBX; + *(uint32_t RT_FAR *)pvECX = (uint32_t)uRCX; + *(uint32_t RT_FAR *)pvEDX = (uint32_t)uRDX; +# else + __asm__ ("xchgl %%ebx, %1\n\t" + "cpuid\n\t" + "xchgl %%ebx, %1\n\t" + : "=a" (*(uint32_t *)pvEAX), + "=r" (*(uint32_t *)pvEBX), + "=c" (*(uint32_t *)pvECX), + "=d" (*(uint32_t *)pvEDX) + : "0" (uOperator), + "2" (uIdxECX)); +# endif + +# elif RT_INLINE_ASM_USES_INTRIN + int aInfo[4]; + __cpuidex(aInfo, uOperator, uIdxECX); + *(uint32_t RT_FAR *)pvEAX = aInfo[0]; + *(uint32_t RT_FAR *)pvEBX = aInfo[1]; + *(uint32_t RT_FAR *)pvECX = aInfo[2]; + *(uint32_t RT_FAR *)pvEDX = aInfo[3]; + +# else + uint32_t uEAX; + uint32_t uEBX; + uint32_t uECX; + uint32_t uEDX; + __asm + { + push ebx + mov eax, [uOperator] + mov ecx, [uIdxECX] + cpuid + mov [uEAX], eax + mov [uEBX], ebx + mov [uECX], ecx + mov [uEDX], edx + pop ebx + } + *(uint32_t RT_FAR *)pvEAX = uEAX; + *(uint32_t RT_FAR *)pvEBX = uEBX; + *(uint32_t RT_FAR *)pvECX = uECX; + *(uint32_t RT_FAR *)pvEDX = uEDX; +# endif +} +#endif + + +/** + * CPUID variant that initializes all 4 registers before the CPUID instruction. + * + * @returns The EAX result value. + * @param uOperator CPUID operation (eax). + * @param uInitEBX The value to assign EBX prior to the CPUID instruction. + * @param uInitECX The value to assign ECX prior to the CPUID instruction. + * @param uInitEDX The value to assign EDX prior to the CPUID instruction. + * @param pvEAX Where to store eax. Optional. + * @param pvEBX Where to store ebx. Optional. + * @param pvECX Where to store ecx. Optional. + * @param pvEDX Where to store edx. Optional. + */ +DECLASM(uint32_t) ASMCpuIdExSlow(uint32_t uOperator, uint32_t uInitEBX, uint32_t uInitECX, uint32_t uInitEDX, + void RT_FAR *pvEAX, void RT_FAR *pvEBX, void RT_FAR *pvECX, void RT_FAR *pvEDX); + + +/** + * Performs the cpuid instruction returning ecx and edx. + * + * @param uOperator CPUID operation (eax). + * @param pvECX Where to store ecx. + * @param pvEDX Where to store edx. + * @remark We're using void pointers to ease the use of special bitfield structures and such. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMCpuId_ECX_EDX(uint32_t uOperator, void RT_FAR *pvECX, void RT_FAR *pvEDX); +#else +DECLINLINE(void) ASMCpuId_ECX_EDX(uint32_t uOperator, void RT_FAR *pvECX, void RT_FAR *pvEDX) +{ + uint32_t uEBX; + ASMCpuId(uOperator, &uOperator, &uEBX, pvECX, pvEDX); +} +#endif + + +/** + * Performs the cpuid instruction returning eax. + * + * @param uOperator CPUID operation (eax). + * @returns EAX after cpuid operation. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMCpuId_EAX(uint32_t uOperator); +#else +DECLINLINE(uint32_t) ASMCpuId_EAX(uint32_t uOperator) +{ + RTCCUINTREG xAX; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ ("cpuid" + : "=a" (xAX) + : "0" (uOperator) + : "rbx", "rcx", "rdx"); +# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__) + __asm__ ("push %%ebx\n\t" + "cpuid\n\t" + "pop %%ebx\n\t" + : "=a" (xAX) + : "0" (uOperator) + : "ecx", "edx"); +# else + __asm__ ("cpuid" + : "=a" (xAX) + : "0" (uOperator) + : "edx", "ecx", "ebx"); +# endif + +# elif RT_INLINE_ASM_USES_INTRIN + int aInfo[4]; + __cpuid(aInfo, uOperator); + xAX = aInfo[0]; + +# else + __asm + { + push ebx + mov eax, [uOperator] + cpuid + mov [xAX], eax + pop ebx + } +# endif + return (uint32_t)xAX; +} +#endif + + +/** + * Performs the cpuid instruction returning ebx. + * + * @param uOperator CPUID operation (eax). + * @returns EBX after cpuid operation. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMCpuId_EBX(uint32_t uOperator); +#else +DECLINLINE(uint32_t) ASMCpuId_EBX(uint32_t uOperator) +{ + RTCCUINTREG xBX; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + RTCCUINTREG uSpill; + __asm__ ("cpuid" + : "=a" (uSpill), + "=b" (xBX) + : "0" (uOperator) + : "rdx", "rcx"); +# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__) + __asm__ ("push %%ebx\n\t" + "cpuid\n\t" + "mov %%ebx, %%edx\n\t" + "pop %%ebx\n\t" + : "=a" (uOperator), + "=d" (xBX) + : "0" (uOperator) + : "ecx"); +# else + __asm__ ("cpuid" + : "=a" (uOperator), + "=b" (xBX) + : "0" (uOperator) + : "edx", "ecx"); +# endif + +# elif RT_INLINE_ASM_USES_INTRIN + int aInfo[4]; + __cpuid(aInfo, uOperator); + xBX = aInfo[1]; + +# else + __asm + { + push ebx + mov eax, [uOperator] + cpuid + mov [xBX], ebx + pop ebx + } +# endif + return (uint32_t)xBX; +} +#endif + + +/** + * Performs the cpuid instruction returning ecx. + * + * @param uOperator CPUID operation (eax). + * @returns ECX after cpuid operation. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMCpuId_ECX(uint32_t uOperator); +#else +DECLINLINE(uint32_t) ASMCpuId_ECX(uint32_t uOperator) +{ + RTCCUINTREG xCX; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + RTCCUINTREG uSpill; + __asm__ ("cpuid" + : "=a" (uSpill), + "=c" (xCX) + : "0" (uOperator) + : "rbx", "rdx"); +# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__) + __asm__ ("push %%ebx\n\t" + "cpuid\n\t" + "pop %%ebx\n\t" + : "=a" (uOperator), + "=c" (xCX) + : "0" (uOperator) + : "edx"); +# else + __asm__ ("cpuid" + : "=a" (uOperator), + "=c" (xCX) + : "0" (uOperator) + : "ebx", "edx"); + +# endif + +# elif RT_INLINE_ASM_USES_INTRIN + int aInfo[4]; + __cpuid(aInfo, uOperator); + xCX = aInfo[2]; + +# else + __asm + { + push ebx + mov eax, [uOperator] + cpuid + mov [xCX], ecx + pop ebx + } +# endif + return (uint32_t)xCX; +} +#endif + + +/** + * Performs the cpuid instruction returning edx. + * + * @param uOperator CPUID operation (eax). + * @returns EDX after cpuid operation. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMCpuId_EDX(uint32_t uOperator); +#else +DECLINLINE(uint32_t) ASMCpuId_EDX(uint32_t uOperator) +{ + RTCCUINTREG xDX; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + RTCCUINTREG uSpill; + __asm__ ("cpuid" + : "=a" (uSpill), + "=d" (xDX) + : "0" (uOperator) + : "rbx", "rcx"); +# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__) + __asm__ ("push %%ebx\n\t" + "cpuid\n\t" + "pop %%ebx\n\t" + : "=a" (uOperator), + "=d" (xDX) + : "0" (uOperator) + : "ecx"); +# else + __asm__ ("cpuid" + : "=a" (uOperator), + "=d" (xDX) + : "0" (uOperator) + : "ebx", "ecx"); +# endif + +# elif RT_INLINE_ASM_USES_INTRIN + int aInfo[4]; + __cpuid(aInfo, uOperator); + xDX = aInfo[3]; + +# else + __asm + { + push ebx + mov eax, [uOperator] + cpuid + mov [xDX], edx + pop ebx + } +# endif + return (uint32_t)xDX; +} +#endif + + +/** + * Checks if the current CPU supports CPUID. + * + * @returns true if CPUID is supported. + */ +#ifdef __WATCOMC__ +DECLASM(bool) ASMHasCpuId(void); +#else +DECLINLINE(bool) ASMHasCpuId(void) +{ +# ifdef RT_ARCH_AMD64 + return true; /* ASSUME that all amd64 compatible CPUs have cpuid. */ +# else /* !RT_ARCH_AMD64 */ + bool fRet = false; +# if RT_INLINE_ASM_GNU_STYLE + uint32_t u1; + uint32_t u2; + __asm__ ("pushf\n\t" + "pop %1\n\t" + "mov %1, %2\n\t" + "xorl $0x200000, %1\n\t" + "push %1\n\t" + "popf\n\t" + "pushf\n\t" + "pop %1\n\t" + "cmpl %1, %2\n\t" + "setne %0\n\t" + "push %2\n\t" + "popf\n\t" + : "=m" (fRet), "=r" (u1), "=r" (u2)); +# else + __asm + { + pushfd + pop eax + mov ebx, eax + xor eax, 0200000h + push eax + popfd + pushfd + pop eax + cmp eax, ebx + setne fRet + push ebx + popfd + } +# endif + return fRet; +# endif /* !RT_ARCH_AMD64 */ +} +#endif + + +/** + * Gets the APIC ID of the current CPU. + * + * @returns the APIC ID. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint8_t) ASMGetApicId(void); +#else +DECLINLINE(uint8_t) ASMGetApicId(void) +{ + RTCCUINTREG xBX; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + RTCCUINTREG uSpill; + __asm__ __volatile__ ("cpuid" + : "=a" (uSpill), + "=b" (xBX) + : "0" (1) + : "rcx", "rdx"); +# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__) + RTCCUINTREG uSpill; + __asm__ __volatile__ ("mov %%ebx,%1\n\t" + "cpuid\n\t" + "xchgl %%ebx,%1\n\t" + : "=a" (uSpill), + "=rm" (xBX) + : "0" (1) + : "ecx", "edx"); +# else + RTCCUINTREG uSpill; + __asm__ __volatile__ ("cpuid" + : "=a" (uSpill), + "=b" (xBX) + : "0" (1) + : "ecx", "edx"); +# endif + +# elif RT_INLINE_ASM_USES_INTRIN + int aInfo[4]; + __cpuid(aInfo, 1); + xBX = aInfo[1]; + +# else + __asm + { + push ebx + mov eax, 1 + cpuid + mov [xBX], ebx + pop ebx + } +# endif + return (uint8_t)(xBX >> 24); +} +#endif + + +/** + * Gets the APIC ID of the current CPU using leaf 0xb. + * + * @returns the APIC ID. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2010 /*?*/ +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMGetApicIdExt0B(void); +#else +DECLINLINE(uint32_t) ASMGetApicIdExt0B(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG xDX; +# ifdef RT_ARCH_AMD64 + RTCCUINTREG uSpillEax, uSpillEcx; + __asm__ __volatile__ ("cpuid" + : "=a" (uSpillEax), + "=c" (uSpillEcx), + "=d" (xDX) + : "0" (0xb), + "1" (0) + : "rbx"); +# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__) + RTCCUINTREG uSpillEax, uSpillEcx, uSpillEbx; + __asm__ __volatile__ ("mov %%ebx,%2\n\t" + "cpuid\n\t" + "xchgl %%ebx,%2\n\t" + : "=a" (uSpillEax), + "=c" (uSpillEcx), + "=rm" (uSpillEbx), + "=d" (xDX) + : "0" (0xb), + "1" (0)); +# else + RTCCUINTREG uSpillEax, uSpillEcx; + __asm__ __volatile__ ("cpuid" + : "=a" (uSpillEax), + "=c" (uSpillEcx), + "=d" (xDX) + : "0" (0xb), + "1" (0) + : "ebx"); +# endif + return (uint32_t)xDX; + +# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2010 /*?*/ + + int aInfo[4]; + __cpuidex(aInfo, 0xb, 0); + return aInfo[3]; + +# else + RTCCUINTREG xDX; + __asm + { + push ebx + mov eax, 0xb + xor ecx, ecx + cpuid + mov [xDX], edx + pop ebx + } + return (uint32_t)xDX; +# endif +} +#endif + + +/** + * Gets the APIC ID of the current CPU using leaf 8000001E. + * + * @returns the APIC ID. + */ +DECLINLINE(uint32_t) ASMGetApicIdExt8000001E(void) +{ + return ASMCpuId_EAX(0x8000001e); +} + + +/** + * Tests if this is a genuine Intel CPU. + * + * @returns true/false. + * @remarks ASSUMES that cpuid is supported by the CPU. + */ +DECLINLINE(bool) ASMIsIntelCpu(void) +{ + uint32_t uEAX, uEBX, uECX, uEDX; + ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX); + return RTX86IsIntelCpu(uEBX, uECX, uEDX); +} + + +/** + * Tests if this is an authentic AMD CPU. + * + * @returns true/false. + * @remarks ASSUMES that cpuid is supported by the CPU. + */ +DECLINLINE(bool) ASMIsAmdCpu(void) +{ + uint32_t uEAX, uEBX, uECX, uEDX; + ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX); + return RTX86IsAmdCpu(uEBX, uECX, uEDX); +} + + +/** + * Tests if this is a centaur hauling VIA CPU. + * + * @returns true/false. + * @remarks ASSUMES that cpuid is supported by the CPU. + */ +DECLINLINE(bool) ASMIsViaCentaurCpu(void) +{ + uint32_t uEAX, uEBX, uECX, uEDX; + ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX); + return RTX86IsViaCentaurCpu(uEBX, uECX, uEDX); +} + + +/** + * Tests if this is a Shanghai CPU. + * + * @returns true/false. + * @remarks ASSUMES that cpuid is supported by the CPU. + */ +DECLINLINE(bool) ASMIsShanghaiCpu(void) +{ + uint32_t uEAX, uEBX, uECX, uEDX; + ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX); + return RTX86IsShanghaiCpu(uEBX, uECX, uEDX); +} + + +/** + * Tests if this is a genuine Hygon CPU. + * + * @returns true/false. + * @remarks ASSUMES that cpuid is supported by the CPU. + */ +DECLINLINE(bool) ASMIsHygonCpu(void) +{ + uint32_t uEAX, uEBX, uECX, uEDX; + ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX); + return RTX86IsHygonCpu(uEBX, uECX, uEDX); +} + + +/** + * Get cr0. + * @returns cr0. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetCR0(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetCR0(void) +{ + RTCCUINTXREG uCR0; +# if RT_INLINE_ASM_USES_INTRIN + uCR0 = __readcr0(); + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%cr0, %0\t\n" : "=r" (uCR0)); +# else + __asm__ __volatile__("movl %%cr0, %0\t\n" : "=r" (uCR0)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, cr0 + mov [uCR0], rax +# else + mov eax, cr0 + mov [uCR0], eax +# endif + } +# endif + return uCR0; +} +#endif + + +/** + * Sets the CR0 register. + * @param uCR0 The new CR0 value. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetCR0(RTCCUINTXREG uCR0); +#else +DECLINLINE(void) ASMSetCR0(RTCCUINTXREG uCR0) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writecr0(uCR0); + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%cr0\n\t" :: "r" (uCR0)); +# else + __asm__ __volatile__("movl %0, %%cr0\n\t" :: "r" (uCR0)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uCR0] + mov cr0, rax +# else + mov eax, [uCR0] + mov cr0, eax +# endif + } +# endif +} +#endif + + +/** + * Get cr2. + * @returns cr2. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetCR2(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetCR2(void) +{ + RTCCUINTXREG uCR2; +# if RT_INLINE_ASM_USES_INTRIN + uCR2 = __readcr2(); + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%cr2, %0\t\n" : "=r" (uCR2)); +# else + __asm__ __volatile__("movl %%cr2, %0\t\n" : "=r" (uCR2)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, cr2 + mov [uCR2], rax +# else + mov eax, cr2 + mov [uCR2], eax +# endif + } +# endif + return uCR2; +} +#endif + + +/** + * Sets the CR2 register. + * @param uCR2 The new CR0 value. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetCR2(RTCCUINTXREG uCR2); +#else +DECLINLINE(void) ASMSetCR2(RTCCUINTXREG uCR2) +{ +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%cr2\n\t" :: "r" (uCR2)); +# else + __asm__ __volatile__("movl %0, %%cr2\n\t" :: "r" (uCR2)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uCR2] + mov cr2, rax +# else + mov eax, [uCR2] + mov cr2, eax +# endif + } +# endif +} +#endif + + +/** + * Get cr3. + * @returns cr3. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetCR3(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetCR3(void) +{ + RTCCUINTXREG uCR3; +# if RT_INLINE_ASM_USES_INTRIN + uCR3 = __readcr3(); + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%cr3, %0\t\n" : "=r" (uCR3)); +# else + __asm__ __volatile__("movl %%cr3, %0\t\n" : "=r" (uCR3)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, cr3 + mov [uCR3], rax +# else + mov eax, cr3 + mov [uCR3], eax +# endif + } +# endif + return uCR3; +} +#endif + + +/** + * Sets the CR3 register. + * + * @param uCR3 New CR3 value. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetCR3(RTCCUINTXREG uCR3); +#else +DECLINLINE(void) ASMSetCR3(RTCCUINTXREG uCR3) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writecr3(uCR3); + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%cr3\n\t" : : "r" (uCR3)); +# else + __asm__ __volatile__("movl %0, %%cr3\n\t" : : "r" (uCR3)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uCR3] + mov cr3, rax +# else + mov eax, [uCR3] + mov cr3, eax +# endif + } +# endif +} +#endif + + +/** + * Reloads the CR3 register. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMReloadCR3(void); +#else +DECLINLINE(void) ASMReloadCR3(void) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writecr3(__readcr3()); + +# elif RT_INLINE_ASM_GNU_STYLE + RTCCUINTXREG u; +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%cr3, %0\n\t" + "movq %0, %%cr3\n\t" + : "=r" (u)); +# else + __asm__ __volatile__("movl %%cr3, %0\n\t" + "movl %0, %%cr3\n\t" + : "=r" (u)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, cr3 + mov cr3, rax +# else + mov eax, cr3 + mov cr3, eax +# endif + } +# endif +} +#endif + + +/** + * Get cr4. + * @returns cr4. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetCR4(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetCR4(void) +{ + RTCCUINTXREG uCR4; +# if RT_INLINE_ASM_USES_INTRIN + uCR4 = __readcr4(); + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%cr4, %0\t\n" : "=r" (uCR4)); +# else + __asm__ __volatile__("movl %%cr4, %0\t\n" : "=r" (uCR4)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, cr4 + mov [uCR4], rax +# else + push eax /* just in case */ + /*mov eax, cr4*/ + _emit 0x0f + _emit 0x20 + _emit 0xe0 + mov [uCR4], eax + pop eax +# endif + } +# endif + return uCR4; +} +#endif + + +/** + * Sets the CR4 register. + * + * @param uCR4 New CR4 value. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetCR4(RTCCUINTXREG uCR4); +#else +DECLINLINE(void) ASMSetCR4(RTCCUINTXREG uCR4) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writecr4(uCR4); + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%cr4\n\t" : : "r" (uCR4)); +# else + __asm__ __volatile__("movl %0, %%cr4\n\t" : : "r" (uCR4)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uCR4] + mov cr4, rax +# else + mov eax, [uCR4] + _emit 0x0F + _emit 0x22 + _emit 0xE0 /* mov cr4, eax */ +# endif + } +# endif +} +#endif + + +/** + * Get cr8. + * @returns cr8. + * @remark The lock prefix hack for access from non-64-bit modes is NOT used and 0 is returned. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +DECLASM(RTCCUINTXREG) ASMGetCR8(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetCR8(void) +{ +# ifdef RT_ARCH_AMD64 + RTCCUINTXREG uCR8; +# if RT_INLINE_ASM_USES_INTRIN + uCR8 = __readcr8(); + +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("movq %%cr8, %0\t\n" : "=r" (uCR8)); +# else + __asm + { + mov rax, cr8 + mov [uCR8], rax + } +# endif + return uCR8; +# else /* !RT_ARCH_AMD64 */ + return 0; +# endif /* !RT_ARCH_AMD64 */ +} +#endif + + +/** + * Get XCR0 (eXtended feature Control Register 0). + * @returns xcr0. + */ +DECLASM(uint64_t) ASMGetXcr0(void); + +/** + * Sets the XCR0 register. + * @param uXcr0 The new XCR0 value. + */ +DECLASM(void) ASMSetXcr0(uint64_t uXcr0); + +struct X86XSAVEAREA; +/** + * Save extended CPU state. + * @param pXStateArea Where to save the state. + * @param fComponents Which state components to save. + */ +DECLASM(void) ASMXSave(struct X86XSAVEAREA RT_FAR *pXStateArea, uint64_t fComponents); + +/** + * Loads extended CPU state. + * @param pXStateArea Where to load the state from. + * @param fComponents Which state components to load. + */ +DECLASM(void) ASMXRstor(struct X86XSAVEAREA const RT_FAR *pXStateArea, uint64_t fComponents); + + +struct X86FXSTATE; +/** + * Save FPU and SSE CPU state. + * @param pXStateArea Where to save the state. + */ +DECLASM(void) ASMFxSave(struct X86FXSTATE RT_FAR *pXStateArea); + +/** + * Load FPU and SSE CPU state. + * @param pXStateArea Where to load the state from. + */ +DECLASM(void) ASMFxRstor(struct X86FXSTATE const RT_FAR *pXStateArea); + + +/** + * Enables interrupts (EFLAGS.IF). + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMIntEnable(void); +#else +DECLINLINE(void) ASMIntEnable(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm("sti\n"); +# elif RT_INLINE_ASM_USES_INTRIN + _enable(); +# else + __asm sti +# endif +} +#endif + + +/** + * Disables interrupts (!EFLAGS.IF). + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMIntDisable(void); +#else +DECLINLINE(void) ASMIntDisable(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm("cli\n"); +# elif RT_INLINE_ASM_USES_INTRIN + _disable(); +# else + __asm cli +# endif +} +#endif + + +/** + * Disables interrupts and returns previous xFLAGS. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTREG) ASMIntDisableFlags(void); +#else +DECLINLINE(RTCCUINTREG) ASMIntDisableFlags(void) +{ + RTCCUINTREG xFlags; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("pushfq\n\t" + "cli\n\t" + "popq %0\n\t" + : "=r" (xFlags)); +# else + __asm__ __volatile__("pushfl\n\t" + "cli\n\t" + "popl %0\n\t" + : "=r" (xFlags)); +# endif +# elif RT_INLINE_ASM_USES_INTRIN && !defined(RT_ARCH_X86) + xFlags = ASMGetFlags(); + _disable(); +# else + __asm { + pushfd + cli + pop [xFlags] + } +# endif + return xFlags; +} +#endif + + +/** + * Are interrupts enabled? + * + * @returns true / false. + */ +DECLINLINE(bool) ASMIntAreEnabled(void) +{ + RTCCUINTREG uFlags = ASMGetFlags(); + return uFlags & 0x200 /* X86_EFL_IF */ ? true : false; +} + + +/** + * Halts the CPU until interrupted. + */ +#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2005 +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMHalt(void); +#else +DECLINLINE(void) ASMHalt(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("hlt\n\t"); +# elif RT_INLINE_ASM_USES_INTRIN + __halt(); +# else + __asm { + hlt + } +# endif +} +#endif + + +/** + * Reads a machine specific register. + * + * @returns Register content. + * @param uRegister Register to read. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMRdMsr(uint32_t uRegister); +#else +DECLINLINE(uint64_t) ASMRdMsr(uint32_t uRegister) +{ + RTUINT64U u; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rdmsr\n\t" + : "=a" (u.s.Lo), + "=d" (u.s.Hi) + : "c" (uRegister)); + +# elif RT_INLINE_ASM_USES_INTRIN + u.u = __readmsr(uRegister); + +# else + __asm + { + mov ecx, [uRegister] + rdmsr + mov [u.s.Lo], eax + mov [u.s.Hi], edx + } +# endif + + return u.u; +} +#endif + + +/** + * Writes a machine specific register. + * + * @returns Register content. + * @param uRegister Register to write to. + * @param u64Val Value to write. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(void) ASMWrMsr(uint32_t uRegister, uint64_t u64Val); +#else +DECLINLINE(void) ASMWrMsr(uint32_t uRegister, uint64_t u64Val) +{ + RTUINT64U u; + + u.u = u64Val; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("wrmsr\n\t" + ::"a" (u.s.Lo), + "d" (u.s.Hi), + "c" (uRegister)); + +# elif RT_INLINE_ASM_USES_INTRIN + __writemsr(uRegister, u.u); + +# else + __asm + { + mov ecx, [uRegister] + mov edx, [u.s.Hi] + mov eax, [u.s.Lo] + wrmsr + } +# endif +} +#endif + + +/** + * Reads a machine specific register, extended version (for AMD). + * + * @returns Register content. + * @param uRegister Register to read. + * @param uXDI RDI/EDI value. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM_386(uint64_t) ASMRdMsrEx(uint32_t uRegister, RTCCUINTXREG uXDI); +#else +DECLINLINE(uint64_t) ASMRdMsrEx(uint32_t uRegister, RTCCUINTXREG uXDI) +{ + RTUINT64U u; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rdmsr\n\t" + : "=a" (u.s.Lo), + "=d" (u.s.Hi) + : "c" (uRegister), + "D" (uXDI)); + +# else + __asm + { + mov ecx, [uRegister] + xchg edi, [uXDI] + rdmsr + mov [u.s.Lo], eax + mov [u.s.Hi], edx + xchg edi, [uXDI] + } +# endif + + return u.u; +} +#endif + + +/** + * Writes a machine specific register, extended version (for AMD). + * + * @returns Register content. + * @param uRegister Register to write to. + * @param uXDI RDI/EDI value. + * @param u64Val Value to write. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM_386(void) ASMWrMsrEx(uint32_t uRegister, RTCCUINTXREG uXDI, uint64_t u64Val); +#else +DECLINLINE(void) ASMWrMsrEx(uint32_t uRegister, RTCCUINTXREG uXDI, uint64_t u64Val) +{ + RTUINT64U u; + + u.u = u64Val; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("wrmsr\n\t" + ::"a" (u.s.Lo), + "d" (u.s.Hi), + "c" (uRegister), + "D" (uXDI)); + +# else + __asm + { + mov ecx, [uRegister] + xchg edi, [uXDI] + mov edx, [u.s.Hi] + mov eax, [u.s.Lo] + wrmsr + xchg edi, [uXDI] + } +# endif +} +#endif + + + +/** + * Reads low part of a machine specific register. + * + * @returns Register content. + * @param uRegister Register to read. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMRdMsr_Low(uint32_t uRegister); +#else +DECLINLINE(uint32_t) ASMRdMsr_Low(uint32_t uRegister) +{ + uint32_t u32; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rdmsr\n\t" + : "=a" (u32) + : "c" (uRegister) + : "edx"); + +# elif RT_INLINE_ASM_USES_INTRIN + u32 = (uint32_t)__readmsr(uRegister); + +#else + __asm + { + mov ecx, [uRegister] + rdmsr + mov [u32], eax + } +# endif + + return u32; +} +#endif + + +/** + * Reads high part of a machine specific register. + * + * @returns Register content. + * @param uRegister Register to read. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMRdMsr_High(uint32_t uRegister); +#else +DECLINLINE(uint32_t) ASMRdMsr_High(uint32_t uRegister) +{ + uint32_t u32; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rdmsr\n\t" + : "=d" (u32) + : "c" (uRegister) + : "eax"); + +# elif RT_INLINE_ASM_USES_INTRIN + u32 = (uint32_t)(__readmsr(uRegister) >> 32); + +# else + __asm + { + mov ecx, [uRegister] + rdmsr + mov [u32], edx + } +# endif + + return u32; +} +#endif + + +/** + * Gets dr0. + * + * @returns dr0. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR0(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetDR0(void) +{ + RTCCUINTXREG uDR0; +# if RT_INLINE_ASM_USES_INTRIN + uDR0 = __readdr(0); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%dr0, %0\n\t" : "=r" (uDR0)); +# else + __asm__ __volatile__("movl %%dr0, %0\n\t" : "=r" (uDR0)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, dr0 + mov [uDR0], rax +# else + mov eax, dr0 + mov [uDR0], eax +# endif + } +# endif + return uDR0; +} +#endif + + +/** + * Gets dr1. + * + * @returns dr1. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR1(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetDR1(void) +{ + RTCCUINTXREG uDR1; +# if RT_INLINE_ASM_USES_INTRIN + uDR1 = __readdr(1); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%dr1, %0\n\t" : "=r" (uDR1)); +# else + __asm__ __volatile__("movl %%dr1, %0\n\t" : "=r" (uDR1)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, dr1 + mov [uDR1], rax +# else + mov eax, dr1 + mov [uDR1], eax +# endif + } +# endif + return uDR1; +} +#endif + + +/** + * Gets dr2. + * + * @returns dr2. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR2(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetDR2(void) +{ + RTCCUINTXREG uDR2; +# if RT_INLINE_ASM_USES_INTRIN + uDR2 = __readdr(2); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%dr2, %0\n\t" : "=r" (uDR2)); +# else + __asm__ __volatile__("movl %%dr2, %0\n\t" : "=r" (uDR2)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, dr2 + mov [uDR2], rax +# else + mov eax, dr2 + mov [uDR2], eax +# endif + } +# endif + return uDR2; +} +#endif + + +/** + * Gets dr3. + * + * @returns dr3. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR3(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetDR3(void) +{ + RTCCUINTXREG uDR3; +# if RT_INLINE_ASM_USES_INTRIN + uDR3 = __readdr(3); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%dr3, %0\n\t" : "=r" (uDR3)); +# else + __asm__ __volatile__("movl %%dr3, %0\n\t" : "=r" (uDR3)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, dr3 + mov [uDR3], rax +# else + mov eax, dr3 + mov [uDR3], eax +# endif + } +# endif + return uDR3; +} +#endif + + +/** + * Gets dr6. + * + * @returns dr6. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR6(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetDR6(void) +{ + RTCCUINTXREG uDR6; +# if RT_INLINE_ASM_USES_INTRIN + uDR6 = __readdr(6); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%dr6, %0\n\t" : "=r" (uDR6)); +# else + __asm__ __volatile__("movl %%dr6, %0\n\t" : "=r" (uDR6)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, dr6 + mov [uDR6], rax +# else + mov eax, dr6 + mov [uDR6], eax +# endif + } +# endif + return uDR6; +} +#endif + + +/** + * Reads and clears DR6. + * + * @returns DR6. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetAndClearDR6(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetAndClearDR6(void) +{ + RTCCUINTXREG uDR6; +# if RT_INLINE_ASM_USES_INTRIN + uDR6 = __readdr(6); + __writedr(6, 0xffff0ff0U); /* 31-16 and 4-11 are 1's, 12 and 63-31 are zero. */ +# elif RT_INLINE_ASM_GNU_STYLE + RTCCUINTXREG uNewValue = 0xffff0ff0U;/* 31-16 and 4-11 are 1's, 12 and 63-31 are zero. */ +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%dr6, %0\n\t" + "movq %1, %%dr6\n\t" + : "=r" (uDR6) + : "r" (uNewValue)); +# else + __asm__ __volatile__("movl %%dr6, %0\n\t" + "movl %1, %%dr6\n\t" + : "=r" (uDR6) + : "r" (uNewValue)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, dr6 + mov [uDR6], rax + mov rcx, rax + mov ecx, 0ffff0ff0h; /* 31-16 and 4-11 are 1's, 12 and 63-31 are zero. */ + mov dr6, rcx +# else + mov eax, dr6 + mov [uDR6], eax + mov ecx, 0ffff0ff0h; /* 31-16 and 4-11 are 1's, 12 is zero. */ + mov dr6, ecx +# endif + } +# endif + return uDR6; +} +#endif + + +/** + * Gets dr7. + * + * @returns dr7. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR7(void); +#else +DECLINLINE(RTCCUINTXREG) ASMGetDR7(void) +{ + RTCCUINTXREG uDR7; +# if RT_INLINE_ASM_USES_INTRIN + uDR7 = __readdr(7); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %%dr7, %0\n\t" : "=r" (uDR7)); +# else + __asm__ __volatile__("movl %%dr7, %0\n\t" : "=r" (uDR7)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, dr7 + mov [uDR7], rax +# else + mov eax, dr7 + mov [uDR7], eax +# endif + } +# endif + return uDR7; +} +#endif + + +/** + * Sets dr0. + * + * @param uDRVal Debug register value to write + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR0(RTCCUINTXREG uDRVal); +#else +DECLINLINE(void) ASMSetDR0(RTCCUINTXREG uDRVal) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writedr(0, uDRVal); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%dr0\n\t" : : "r" (uDRVal)); +# else + __asm__ __volatile__("movl %0, %%dr0\n\t" : : "r" (uDRVal)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uDRVal] + mov dr0, rax +# else + mov eax, [uDRVal] + mov dr0, eax +# endif + } +# endif +} +#endif + + +/** + * Sets dr1. + * + * @param uDRVal Debug register value to write + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR1(RTCCUINTXREG uDRVal); +#else +DECLINLINE(void) ASMSetDR1(RTCCUINTXREG uDRVal) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writedr(1, uDRVal); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%dr1\n\t" : : "r" (uDRVal)); +# else + __asm__ __volatile__("movl %0, %%dr1\n\t" : : "r" (uDRVal)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uDRVal] + mov dr1, rax +# else + mov eax, [uDRVal] + mov dr1, eax +# endif + } +# endif +} +#endif + + +/** + * Sets dr2. + * + * @param uDRVal Debug register value to write + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR2(RTCCUINTXREG uDRVal); +#else +DECLINLINE(void) ASMSetDR2(RTCCUINTXREG uDRVal) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writedr(2, uDRVal); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%dr2\n\t" : : "r" (uDRVal)); +# else + __asm__ __volatile__("movl %0, %%dr2\n\t" : : "r" (uDRVal)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uDRVal] + mov dr2, rax +# else + mov eax, [uDRVal] + mov dr2, eax +# endif + } +# endif +} +#endif + + +/** + * Sets dr3. + * + * @param uDRVal Debug register value to write + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR3(RTCCUINTXREG uDRVal); +#else +DECLINLINE(void) ASMSetDR3(RTCCUINTXREG uDRVal) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writedr(3, uDRVal); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%dr3\n\t" : : "r" (uDRVal)); +# else + __asm__ __volatile__("movl %0, %%dr3\n\t" : : "r" (uDRVal)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uDRVal] + mov dr3, rax +# else + mov eax, [uDRVal] + mov dr3, eax +# endif + } +# endif +} +#endif + + +/** + * Sets dr6. + * + * @param uDRVal Debug register value to write + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR6(RTCCUINTXREG uDRVal); +#else +DECLINLINE(void) ASMSetDR6(RTCCUINTXREG uDRVal) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writedr(6, uDRVal); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%dr6\n\t" : : "r" (uDRVal)); +# else + __asm__ __volatile__("movl %0, %%dr6\n\t" : : "r" (uDRVal)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uDRVal] + mov dr6, rax +# else + mov eax, [uDRVal] + mov dr6, eax +# endif + } +# endif +} +#endif + + +/** + * Sets dr7. + * + * @param uDRVal Debug register value to write + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR7(RTCCUINTXREG uDRVal); +#else +DECLINLINE(void) ASMSetDR7(RTCCUINTXREG uDRVal) +{ +# if RT_INLINE_ASM_USES_INTRIN + __writedr(7, uDRVal); +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("movq %0, %%dr7\n\t" : : "r" (uDRVal)); +# else + __asm__ __volatile__("movl %0, %%dr7\n\t" : : "r" (uDRVal)); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uDRVal] + mov dr7, rax +# else + mov eax, [uDRVal] + mov dr7, eax +# endif + } +# endif +} +#endif + + +/** + * Writes a 8-bit unsigned integer to an I/O port, ordered. + * + * @param Port I/O port to write to. + * @param u8 8-bit integer to write. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutU8(RTIOPORT Port, uint8_t u8); +#else +DECLINLINE(void) ASMOutU8(RTIOPORT Port, uint8_t u8) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("outb %b1, %w0\n\t" + :: "Nd" (Port), + "a" (u8)); + +# elif RT_INLINE_ASM_USES_INTRIN + __outbyte(Port, u8); + +# else + __asm + { + mov dx, [Port] + mov al, [u8] + out dx, al + } +# endif +} +#endif + + +/** + * Reads a 8-bit unsigned integer from an I/O port, ordered. + * + * @returns 8-bit integer. + * @param Port I/O port to read from. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint8_t) ASMInU8(RTIOPORT Port); +#else +DECLINLINE(uint8_t) ASMInU8(RTIOPORT Port) +{ + uint8_t u8; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("inb %w1, %b0\n\t" + : "=a" (u8) + : "Nd" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + u8 = __inbyte(Port); + +# else + __asm + { + mov dx, [Port] + in al, dx + mov [u8], al + } +# endif + return u8; +} +#endif + + +/** + * Writes a 16-bit unsigned integer to an I/O port, ordered. + * + * @param Port I/O port to write to. + * @param u16 16-bit integer to write. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutU16(RTIOPORT Port, uint16_t u16); +#else +DECLINLINE(void) ASMOutU16(RTIOPORT Port, uint16_t u16) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("outw %w1, %w0\n\t" + :: "Nd" (Port), + "a" (u16)); + +# elif RT_INLINE_ASM_USES_INTRIN + __outword(Port, u16); + +# else + __asm + { + mov dx, [Port] + mov ax, [u16] + out dx, ax + } +# endif +} +#endif + + +/** + * Reads a 16-bit unsigned integer from an I/O port, ordered. + * + * @returns 16-bit integer. + * @param Port I/O port to read from. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint16_t) ASMInU16(RTIOPORT Port); +#else +DECLINLINE(uint16_t) ASMInU16(RTIOPORT Port) +{ + uint16_t u16; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("inw %w1, %w0\n\t" + : "=a" (u16) + : "Nd" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + u16 = __inword(Port); + +# else + __asm + { + mov dx, [Port] + in ax, dx + mov [u16], ax + } +# endif + return u16; +} +#endif + + +/** + * Writes a 32-bit unsigned integer to an I/O port, ordered. + * + * @param Port I/O port to write to. + * @param u32 32-bit integer to write. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutU32(RTIOPORT Port, uint32_t u32); +#else +DECLINLINE(void) ASMOutU32(RTIOPORT Port, uint32_t u32) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("outl %1, %w0\n\t" + :: "Nd" (Port), + "a" (u32)); + +# elif RT_INLINE_ASM_USES_INTRIN + __outdword(Port, u32); + +# else + __asm + { + mov dx, [Port] + mov eax, [u32] + out dx, eax + } +# endif +} +#endif + + +/** + * Reads a 32-bit unsigned integer from an I/O port, ordered. + * + * @returns 32-bit integer. + * @param Port I/O port to read from. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMInU32(RTIOPORT Port); +#else +DECLINLINE(uint32_t) ASMInU32(RTIOPORT Port) +{ + uint32_t u32; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("inl %w1, %0\n\t" + : "=a" (u32) + : "Nd" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + u32 = __indword(Port); + +# else + __asm + { + mov dx, [Port] + in eax, dx + mov [u32], eax + } +# endif + return u32; +} +#endif + + +/** + * Writes a string of 8-bit unsigned integer items to an I/O port, ordered. + * + * @param Port I/O port to write to. + * @param pau8 Pointer to the string buffer. + * @param c The number of items to write. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutStrU8(RTIOPORT Port, uint8_t const RT_FAR *pau8, size_t c); +#else +DECLINLINE(void) ASMOutStrU8(RTIOPORT Port, uint8_t const RT_FAR *pau8, size_t c) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rep; outsb\n\t" + : "+S" (pau8), + "+c" (c) + : "d" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + __outbytestring(Port, (unsigned char RT_FAR *)pau8, (unsigned long)c); + +# else + __asm + { + mov dx, [Port] + mov ecx, [c] + mov eax, [pau8] + xchg esi, eax + rep outsb + xchg esi, eax + } +# endif +} +#endif + + +/** + * Reads a string of 8-bit unsigned integer items from an I/O port, ordered. + * + * @param Port I/O port to read from. + * @param pau8 Pointer to the string buffer (output). + * @param c The number of items to read. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInStrU8(RTIOPORT Port, uint8_t RT_FAR *pau8, size_t c); +#else +DECLINLINE(void) ASMInStrU8(RTIOPORT Port, uint8_t RT_FAR *pau8, size_t c) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rep; insb\n\t" + : "+D" (pau8), + "+c" (c) + : "d" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + __inbytestring(Port, pau8, (unsigned long)c); + +# else + __asm + { + mov dx, [Port] + mov ecx, [c] + mov eax, [pau8] + xchg edi, eax + rep insb + xchg edi, eax + } +# endif +} +#endif + + +/** + * Writes a string of 16-bit unsigned integer items to an I/O port, ordered. + * + * @param Port I/O port to write to. + * @param pau16 Pointer to the string buffer. + * @param c The number of items to write. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutStrU16(RTIOPORT Port, uint16_t const RT_FAR *pau16, size_t c); +#else +DECLINLINE(void) ASMOutStrU16(RTIOPORT Port, uint16_t const RT_FAR *pau16, size_t c) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rep; outsw\n\t" + : "+S" (pau16), + "+c" (c) + : "d" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + __outwordstring(Port, (unsigned short RT_FAR *)pau16, (unsigned long)c); + +# else + __asm + { + mov dx, [Port] + mov ecx, [c] + mov eax, [pau16] + xchg esi, eax + rep outsw + xchg esi, eax + } +# endif +} +#endif + + +/** + * Reads a string of 16-bit unsigned integer items from an I/O port, ordered. + * + * @param Port I/O port to read from. + * @param pau16 Pointer to the string buffer (output). + * @param c The number of items to read. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInStrU16(RTIOPORT Port, uint16_t RT_FAR *pau16, size_t c); +#else +DECLINLINE(void) ASMInStrU16(RTIOPORT Port, uint16_t RT_FAR *pau16, size_t c) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rep; insw\n\t" + : "+D" (pau16), + "+c" (c) + : "d" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + __inwordstring(Port, pau16, (unsigned long)c); + +# else + __asm + { + mov dx, [Port] + mov ecx, [c] + mov eax, [pau16] + xchg edi, eax + rep insw + xchg edi, eax + } +# endif +} +#endif + + +/** + * Writes a string of 32-bit unsigned integer items to an I/O port, ordered. + * + * @param Port I/O port to write to. + * @param pau32 Pointer to the string buffer. + * @param c The number of items to write. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutStrU32(RTIOPORT Port, uint32_t const RT_FAR *pau32, size_t c); +#else +DECLINLINE(void) ASMOutStrU32(RTIOPORT Port, uint32_t const RT_FAR *pau32, size_t c) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rep; outsl\n\t" + : "+S" (pau32), + "+c" (c) + : "d" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + __outdwordstring(Port, (unsigned long RT_FAR *)pau32, (unsigned long)c); + +# else + __asm + { + mov dx, [Port] + mov ecx, [c] + mov eax, [pau32] + xchg esi, eax + rep outsd + xchg esi, eax + } +# endif +} +#endif + + +/** + * Reads a string of 32-bit unsigned integer items from an I/O port, ordered. + * + * @param Port I/O port to read from. + * @param pau32 Pointer to the string buffer (output). + * @param c The number of items to read. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInStrU32(RTIOPORT Port, uint32_t RT_FAR *pau32, size_t c); +#else +DECLINLINE(void) ASMInStrU32(RTIOPORT Port, uint32_t RT_FAR *pau32, size_t c) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rep; insl\n\t" + : "+D" (pau32), + "+c" (c) + : "d" (Port)); + +# elif RT_INLINE_ASM_USES_INTRIN + __indwordstring(Port, (unsigned long RT_FAR *)pau32, (unsigned long)c); + +# else + __asm + { + mov dx, [Port] + mov ecx, [c] + mov eax, [pau32] + xchg edi, eax + rep insd + xchg edi, eax + } +# endif +} +#endif + + +/** + * Invalidate page. + * + * @param uPtr Address of the page to invalidate. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInvalidatePage(RTCCUINTXREG uPtr); +#else +DECLINLINE(void) ASMInvalidatePage(RTCCUINTXREG uPtr) +{ +# if RT_INLINE_ASM_USES_INTRIN + __invlpg((void RT_FAR *)uPtr); + +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("invlpg %0\n\t" + : : "m" (*(uint8_t RT_FAR *)(uintptr_t)uPtr)); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [uPtr] + invlpg [rax] +# else + mov eax, [uPtr] + invlpg [eax] +# endif + } +# endif +} +#endif + + +/** + * Write back the internal caches and invalidate them. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMWriteBackAndInvalidateCaches(void); +#else +DECLINLINE(void) ASMWriteBackAndInvalidateCaches(void) +{ +# if RT_INLINE_ASM_USES_INTRIN + __wbinvd(); + +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("wbinvd"); +# else + __asm + { + wbinvd + } +# endif +} +#endif + + +/** + * Invalidate internal and (perhaps) external caches without first + * flushing dirty cache lines. Use with extreme care. + */ +#if RT_INLINE_ASM_EXTERNAL +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInvalidateInternalCaches(void); +#else +DECLINLINE(void) ASMInvalidateInternalCaches(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("invd"); +# else + __asm + { + invd + } +# endif +} +#endif + + +/** + * Memory load/store fence, waits for any pending writes and reads to complete. + * Requires the X86_CPUID_FEATURE_EDX_SSE2 CPUID bit set. + */ +DECLINLINE(void) ASMMemoryFenceSSE2(void) +{ +#if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ (".byte 0x0f,0xae,0xf0\n\t"); +#elif RT_INLINE_ASM_USES_INTRIN + _mm_mfence(); +#else + __asm + { + _emit 0x0f + _emit 0xae + _emit 0xf0 + } +#endif +} + + +/** + * Memory store fence, waits for any writes to complete. + * Requires the X86_CPUID_FEATURE_EDX_SSE CPUID bit set. + */ +DECLINLINE(void) ASMWriteFenceSSE(void) +{ +#if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ (".byte 0x0f,0xae,0xf8\n\t"); +#elif RT_INLINE_ASM_USES_INTRIN + _mm_sfence(); +#else + __asm + { + _emit 0x0f + _emit 0xae + _emit 0xf8 + } +#endif +} + + +/** + * Memory load fence, waits for any pending reads to complete. + * Requires the X86_CPUID_FEATURE_EDX_SSE2 CPUID bit set. + */ +DECLINLINE(void) ASMReadFenceSSE2(void) +{ +#if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ (".byte 0x0f,0xae,0xe8\n\t"); +#elif RT_INLINE_ASM_USES_INTRIN + _mm_lfence(); +#else + __asm + { + _emit 0x0f + _emit 0xae + _emit 0xe8 + } +#endif +} + +#if !defined(_MSC_VER) || !defined(RT_ARCH_AMD64) + +/* + * Clear the AC bit in the EFLAGS register. + * Requires the X86_CPUID_STEXT_FEATURE_EBX_SMAP CPUID bit set. + * Requires to be executed in R0. + */ +DECLINLINE(void) ASMClearAC(void) +{ +#if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ (".byte 0x0f,0x01,0xca\n\t"); +#else + __asm + { + _emit 0x0f + _emit 0x01 + _emit 0xca + } +#endif +} + + +/* + * Set the AC bit in the EFLAGS register. + * Requires the X86_CPUID_STEXT_FEATURE_EBX_SMAP CPUID bit set. + * Requires to be executed in R0. + */ +DECLINLINE(void) ASMSetAC(void) +{ +#if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ (".byte 0x0f,0x01,0xcb\n\t"); +#else + __asm + { + _emit 0x0f + _emit 0x01 + _emit 0xcb + } +#endif +} + +#endif /* !_MSC_VER || !RT_ARCH_AMD64 */ + + +/* + * Include #pragma aux definitions for Watcom C/C++. + */ +#if defined(__WATCOMC__) && ARCH_BITS == 16 +# define IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE +# undef IPRT_INCLUDED_asm_amd64_x86_watcom_16_h +# include "asm-amd64-x86-watcom-16.h" +#elif defined(__WATCOMC__) && ARCH_BITS == 32 +# define IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE +# undef IPRT_INCLUDED_asm_amd64_x86_watcom_32_h +# include "asm-amd64-x86-watcom-32.h" +#endif + + +/** @} */ +#endif /* !IPRT_INCLUDED_asm_amd64_x86_h */ + diff --git a/include/iprt/asm-arm.h b/include/iprt/asm-arm.h new file mode 100644 index 00000000..b9d287fa --- /dev/null +++ b/include/iprt/asm-arm.h @@ -0,0 +1,321 @@ +/** @file + * IPRT - ARM Specific Assembly Functions. + */ + +/* + * Copyright (C) 2015-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asm_arm_h +#define IPRT_INCLUDED_asm_arm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#if !defined(RT_ARCH_ARM64) && !defined(RT_ARCH_ARM32) +# error "Not on ARM64 or ARM32" +#endif + +/** @defgroup grp_rt_asm_arm ARM Specific ASM Routines + * @ingroup grp_rt_asm + * @{ + */ + + +#if 0 /* figure out arm64 */ + +/** + * Get the CPSR (Current Program Status) register. + * @returns CPSR. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(RTCCUINTREG) ASMGetFlags(void); +#else +DECLINLINE(RTCCUINTREG) ASMGetFlags(void) +{ + RTCCUINTREG uFlags; +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_ARM64 + __asm__ __volatile__("mrs %0, nzcv\n\t" : "=r" (uFlags)); +# else + __asm__ __volatile__("mrs %0, cpsr\n\t" : "=r" (uFlags)); +# endif +# else +# error "Unsupported compiler" +# endif + return uFlags; +} +#endif + + +/** + * Set the CPSR register. + * @param uFlags The new CPSR value. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(void) ASMSetFlags(RTCCUINTREG uFlags); +#else +DECLINLINE(void) ASMSetFlags(RTCCUINTREG uFlags) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("msr cpsr_c, %0\n\t" + : : "r" (uFlags)); +# else +# error "Unsupported compiler" +# endif +} +#endif + +#endif + + +/** + * Gets the content of the CNTVCT_EL0 (or CNTPCT) register. + * + * @returns CNTVCT_EL0 value. + * @note We call this TSC to better fit in with existing x86/amd64 based code. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(uint64_t) ASMReadTSC(void); +#else +DECLINLINE(uint64_t) ASMReadTSC(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + uint64_t u64; +# ifdef RT_ARCH_ARM64 + __asm__ __volatile__("isb\n\t" + "mrs %0, CNTVCT_EL0\n\t" + : "=r" (u64)); +# else + uint32_t u32Spill; + uint32_t u32Comp; + __asm__ __volatile__("isb\n" + "Lagain:\n\t" + "mrrc p15, 0, %[uSpill], %H[uRet], c14\n\t" /* CNTPCT high into uRet.hi */ + "mrrc p15, 0, %[uRet], %[uSpill], c14\n\t" /* CNTPCT low into uRet.lo */ + "mrrc p15, 0, %[uSpill], %[uHiComp], c14\n\t" /* CNTPCT high into uHiComp */ + "cmp %H[uRet], %[uHiComp]\n\t" + "b.eq Lagain\n\t" /* Redo if high value changed. */ + : [uRet] "=r" (u64) + , "=r" (uHiComp) + , "=r" (uSpill)); +# endif + return u64; + +# else +# error "Unsupported compiler" +# endif +} +#endif + +#if 0 /* port to arm64, armv7 and check */ + +/** + * Enables interrupts (IRQ and FIQ). + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(void) ASMIntEnable(void); +#else +DECLINLINE(void) ASMIntEnable(void) +{ + RTCCUINTREG uFlags; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("mrs %0, cpsr\n\t" + "bic %0, %0, #0xc0\n\t" + "msr cpsr_c, %0\n\t" + : "=r" (uFlags)); +# else +# error "Unsupported compiler" +# endif +} +#endif + + +/** + * Disables interrupts (IRQ and FIQ). + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(void) ASMIntDisable(void); +#else +DECLINLINE(void) ASMIntDisable(void) +{ + RTCCUINTREG uFlags; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("mrs %0, cpsr\n\t" + "orr %0, %0, #0xc0\n\t" + "msr cpsr_c, %0\n\t" + : "=r" (uFlags)); +# else +# error "Unsupported compiler" +# endif +} +#endif + + +/** + * Disables interrupts and returns previous uFLAGS. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(RTCCUINTREG) ASMIntDisableFlags(void); +#else +DECLINLINE(RTCCUINTREG) ASMIntDisableFlags(void) +{ + RTCCUINTREG uFlags; +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG uNewFlags; + __asm__ __volatile__("mrs %0, cpsr\n\t" + "orr %1, %0, #0xc0\n\t" + "msr cpsr_c, %1\n\t" + : "=r" (uFlags) + , "=r" (uNewFlags)); +# else +# error "Unsupported compiler" +# endif + return uFlags; +} +#endif + + +/** + * Are interrupts enabled? + * + * @returns true / false. + */ +DECLINLINE(bool) ASMIntAreEnabled(void) +{ +/** @todo r=bird: reversed, but does both need to be enabled? */ + return ASMGetFlags() & 0xc0 /* IRQ and FIQ bits */ ? true : false; +} + +#endif + +/** + * Halts the CPU until interrupted. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(void) ASMHalt(void); +#else +DECLINLINE(void) ASMHalt(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ ("wfi\n\t"); /* wait for interrupt */ +# else +# error "Unsupported compiler" +# endif +} +#endif + +#if 0 +/** + * Gets the CPU ID of the current CPU. + * + * @returns the CPU ID. + * @note the name of this method is a bit misleading but serves the purpose + * and prevents #ifdef orgies in other places. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(uint8_t) ASMGetApicId(void); +#else +DECLINLINE(uint8_t) ASMGetApicId(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG uCpuId; + __asm__ ("mrc p15, 0, %0, c0, c0, 5\n\t" /* CPU ID Register, privileged */ + : "=r" (uCpuId)); + return uCpuId; +# else +# error "Unsupported compiler" +# endif +} +#endif +#endif + +#if 0 + +/** + * Invalidate page. + * + * @param pv Address of the page to invalidate. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(void) ASMInvalidatePage(void *pv); +#else +DECLINLINE(void) ASMInvalidatePage(void *pv) +{ +# if RT_INLINE_ASM_GNU_STYLE + +# else +# error "Unsupported compiler" +# endif +} +#endif + + +/** + * Write back the internal caches and invalidate them. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(void) ASMWriteBackAndInvalidateCaches(void); +#else +DECLINLINE(void) ASMWriteBackAndInvalidateCaches(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + +# else +# error "Unsupported compiler" +# endif +} +#endif + + +/** + * Invalidate internal and (perhaps) external caches without first + * flushing dirty cache lines. Use with extreme care. + */ +#if RT_INLINE_ASM_EXTERNAL +DECLASM(void) ASMInvalidateInternalCaches(void); +#else +DECLINLINE(void) ASMInvalidateInternalCaches(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + +# else +# error "Unsupported compiler" +# endif +} +#endif + +#endif + + +/** @} */ +#endif /* !IPRT_INCLUDED_asm_arm_h */ + diff --git a/include/iprt/asm-math.h b/include/iprt/asm-math.h new file mode 100644 index 00000000..d379111c --- /dev/null +++ b/include/iprt/asm-math.h @@ -0,0 +1,445 @@ +/** @file + * IPRT - Assembly Routines for Optimizing some Integers Math Operations. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asm_math_h +#define IPRT_INCLUDED_asm_math_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +#if defined(_MSC_VER) && RT_INLINE_ASM_USES_INTRIN +/* Emit the intrinsics at all optimization levels. */ +# include <iprt/sanitized/intrin.h> +# pragma intrinsic(__emul) +# pragma intrinsic(__emulu) +# ifdef RT_ARCH_AMD64 +# pragma intrinsic(_mul128) +# pragma intrinsic(_umul128) +# endif +#endif + + +/** @defgroup grp_rt_asm_math Interger Math Optimizations + * @ingroup grp_rt_asm + * @{ */ + +/** + * Multiplies two unsigned 32-bit values returning an unsigned 64-bit result. + * + * @returns u32F1 * u32F2. + */ + +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_X86) +DECLASM(uint64_t) ASMMult2xU32RetU64(uint32_t u32F1, uint32_t u32F2); +#else +DECLINLINE(uint64_t) ASMMult2xU32RetU64(uint32_t u32F1, uint32_t u32F2) +{ +# ifdef RT_ARCH_X86 + uint64_t u64; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("mull %%edx" + : "=A" (u64) + : "a" (u32F2), "d" (u32F1)); +# elif RT_INLINE_ASM_USES_INTRIN + u64 = __emulu(u32F1, u32F2); +# else + __asm + { + mov edx, [u32F1] + mov eax, [u32F2] + mul edx + mov dword ptr [u64], eax + mov dword ptr [u64 + 4], edx + } +# endif + return u64; +# else /* generic: */ + return (uint64_t)u32F1 * u32F2; +# endif +} +#endif + + +/** + * Multiplies two signed 32-bit values returning a signed 64-bit result. + * + * @returns u32F1 * u32F2. + */ +#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_X86) +DECLASM(int64_t) ASMMult2xS32RetS64(int32_t i32F1, int32_t i32F2); +#else +DECLINLINE(int64_t) ASMMult2xS32RetS64(int32_t i32F1, int32_t i32F2) +{ +# ifdef RT_ARCH_X86 + int64_t i64; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("imull %%edx" + : "=A" (i64) + : "a" (i32F2), "d" (i32F1)); +# elif RT_INLINE_ASM_USES_INTRIN + i64 = __emul(i32F1, i32F2); +# else + __asm + { + mov edx, [i32F1] + mov eax, [i32F2] + imul edx + mov dword ptr [i64], eax + mov dword ptr [i64 + 4], edx + } +# endif + return i64; +# else /* generic: */ + return (int64_t)i32F1 * i32F2; +# endif +} +#endif + + +DECLINLINE(uint64_t) ASMMult2xU64Ret2xU64(uint64_t u64F1, uint64_t u64F2, uint64_t *pu64ProdHi) +{ +#if defined(RT_ARCH_AMD64) && (RT_INLINE_ASM_GNU_STYLE || RT_INLINE_ASM_USES_INTRIN) +# if RT_INLINE_ASM_GNU_STYLE + uint64_t u64Low, u64High; + __asm__ __volatile__("mulq %%rdx" + : "=a" (u64Low), "=d" (u64High) + : "0" (u64F1), "1" (u64F2)); + *pu64ProdHi = u64High; + return u64Low; +# elif RT_INLINE_ASM_USES_INTRIN + return _umul128(u64F1, u64F2, pu64ProdHi); +# else +# error "hmm" +# endif +#else /* generic: */ + /* + * F1 * F2 = Prod + * -- -- + * ab * cd = b*d + a*d*10 + b*c*10 + a*c*100 + * + * Where a, b, c and d are 'digits', and 10 is max digit + 1. + * + * Our digits are 32-bit wide, so instead of 10 we multiply by 4G. + * Prod = F1.s.Lo*F2.s.Lo + F1.s.Hi*F2.s.Lo*4G + * + F1.s.Lo*F2.s.Hi*4G + F1.s.Hi*F2.s.Hi*4G*4G + */ + RTUINT128U Prod; + RTUINT64U Tmp1; + uint64_t u64Tmp; + RTUINT64U F1, F2; + F1.u = u64F1; + F2.u = u64F2; + + Prod.s.Lo = ASMMult2xU32RetU64(F1.s.Lo, F2.s.Lo); + + Tmp1.u = ASMMult2xU32RetU64(F1.s.Hi, F2.s.Lo); + u64Tmp = (uint64_t)Prod.DWords.dw1 + Tmp1.s.Lo; + Prod.DWords.dw1 = (uint32_t)u64Tmp; + Prod.s.Hi = Tmp1.s.Hi; + Prod.s.Hi += u64Tmp >> 32; /* carry */ + + Tmp1.u = ASMMult2xU32RetU64(F1.s.Lo, F2.s.Hi); + u64Tmp = (uint64_t)Prod.DWords.dw1 + Tmp1.s.Lo; + Prod.DWords.dw1 = (uint32_t)u64Tmp; + u64Tmp >>= 32; /* carry */ + u64Tmp += Prod.DWords.dw2; + u64Tmp += Tmp1.s.Hi; + Prod.DWords.dw2 = (uint32_t)u64Tmp; + Prod.DWords.dw3 += u64Tmp >> 32; /* carry */ + + Prod.s.Hi += ASMMult2xU32RetU64(F1.s.Hi, F2.s.Hi); + *pu64ProdHi = Prod.s.Hi; + return Prod.s.Lo; +#endif +} + + + +/** + * Divides a 64-bit unsigned by a 32-bit unsigned returning an unsigned 32-bit result. + * + * @returns u64 / u32. + */ +#if RT_INLINE_ASM_EXTERNAL && defined(RT_ARCH_X86) +DECLASM(uint32_t) ASMDivU64ByU32RetU32(uint64_t u64, uint32_t u32); +#else +DECLINLINE(uint32_t) ASMDivU64ByU32RetU32(uint64_t u64, uint32_t u32) +{ +# ifdef RT_ARCH_X86 +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG uDummy; + __asm__ __volatile__("divl %3" + : "=a" (u32), "=d"(uDummy) + : "A" (u64), "r" (u32)); +# else + __asm + { + mov eax, dword ptr [u64] + mov edx, dword ptr [u64 + 4] + mov ecx, [u32] + div ecx + mov [u32], eax + } +# endif + return u32; +# else /* generic: */ + return (uint32_t)(u64 / u32); +# endif +} +#endif + + +/** + * Divides a 64-bit signed by a 32-bit signed returning a signed 32-bit result. + * + * @returns u64 / u32. + */ +#if RT_INLINE_ASM_EXTERNAL && defined(RT_ARCH_X86) +DECLASM(int32_t) ASMDivS64ByS32RetS32(int64_t i64, int32_t i32); +#else +DECLINLINE(int32_t) ASMDivS64ByS32RetS32(int64_t i64, int32_t i32) +{ +# ifdef RT_ARCH_X86 +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG iDummy; + __asm__ __volatile__("idivl %3" + : "=a" (i32), "=d"(iDummy) + : "A" (i64), "r" (i32)); +# else + __asm + { + mov eax, dword ptr [i64] + mov edx, dword ptr [i64 + 4] + mov ecx, [i32] + idiv ecx + mov [i32], eax + } +# endif + return i32; +# else /* generic: */ + return (int32_t)(i64 / i32); +# endif +} +#endif + + +/** + * Performs 64-bit unsigned by a 32-bit unsigned division with a 32-bit unsigned result, + * returning the rest. + * + * @returns u64 % u32. + * + * @remarks It is important that the result is <= UINT32_MAX or we'll overflow and crash. + */ +#if RT_INLINE_ASM_EXTERNAL && defined(RT_ARCH_X86) +DECLASM(uint32_t) ASMModU64ByU32RetU32(uint64_t u64, uint32_t u32); +#else +DECLINLINE(uint32_t) ASMModU64ByU32RetU32(uint64_t u64, uint32_t u32) +{ +# ifdef RT_ARCH_X86 +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG uDummy; + __asm__ __volatile__("divl %3" + : "=a" (uDummy), "=d"(u32) + : "A" (u64), "r" (u32)); +# else + __asm + { + mov eax, dword ptr [u64] + mov edx, dword ptr [u64 + 4] + mov ecx, [u32] + div ecx + mov [u32], edx + } +# endif + return u32; +# else /* generic: */ + return (uint32_t)(u64 % u32); +# endif +} +#endif + + +/** + * Performs 64-bit signed by a 32-bit signed division with a 32-bit signed result, + * returning the rest. + * + * @returns u64 % u32. + * + * @remarks It is important that the result is <= UINT32_MAX or we'll overflow and crash. + */ +#if RT_INLINE_ASM_EXTERNAL && defined(RT_ARCH_X86) +DECLASM(int32_t) ASMModS64ByS32RetS32(int64_t i64, int32_t i32); +#else +DECLINLINE(int32_t) ASMModS64ByS32RetS32(int64_t i64, int32_t i32) +{ +# ifdef RT_ARCH_X86 +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG iDummy; + __asm__ __volatile__("idivl %3" + : "=a" (iDummy), "=d"(i32) + : "A" (i64), "r" (i32)); +# else + __asm + { + mov eax, dword ptr [i64] + mov edx, dword ptr [i64 + 4] + mov ecx, [i32] + idiv ecx + mov [i32], edx + } +# endif + return i32; +# else /* generic: */ + return (int32_t)(i64 % i32); +# endif +} +#endif + + +/** + * Multiple a 32-bit by a 32-bit integer and divide the result by a 32-bit integer + * using a 64 bit intermediate result. + * + * @returns (u32A * u32B) / u32C. + * @param u32A The 32-bit value (A). + * @param u32B The 32-bit value to multiple by A. + * @param u32C The 32-bit value to divide A*B by. + * + * @remarks Architecture specific. + * @remarks Make sure the result won't ever exceed 32-bit, because hardware + * exception may be raised if it does. + * @remarks On x86 this may be used to avoid dragging in 64-bit builtin + * arithmetics functions. + */ +#if RT_INLINE_ASM_EXTERNAL && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) +DECLASM(uint32_t) ASMMultU32ByU32DivByU32(uint32_t u32A, uint32_t u32B, uint32_t u32C); +#else +DECLINLINE(uint32_t) ASMMultU32ByU32DivByU32(uint32_t u32A, uint32_t u32B, uint32_t u32C) +{ +# if RT_INLINE_ASM_GNU_STYLE && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) + uint32_t u32Result, u32Spill; + __asm__ __volatile__("mull %2\n\t" + "divl %3\n\t" + : "=&a" (u32Result), + "=&d" (u32Spill) + : "r" (u32B), + "r" (u32C), + "0" (u32A)); + return u32Result; +# else + return (uint32_t)(((uint64_t)u32A * u32B) / u32C); +# endif +} +#endif + + +/** + * Multiple a 64-bit by a 32-bit integer and divide the result by a 32-bit integer + * using a 96 bit intermediate result. + * + * @returns (u64A * u32B) / u32C. + * @param u64A The 64-bit value. + * @param u32B The 32-bit value to multiple by A. + * @param u32C The 32-bit value to divide A*B by. + * + * @remarks Architecture specific. + * @remarks Make sure the result won't ever exceed 64-bit, because hardware + * exception may be raised if it does. + * @remarks On x86 this may be used to avoid dragging in 64-bit builtin + * arithmetics function. + */ +#if RT_INLINE_ASM_EXTERNAL || !defined(__GNUC__) || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +DECLASM(uint64_t) ASMMultU64ByU32DivByU32(uint64_t u64A, uint32_t u32B, uint32_t u32C); +#else +DECLINLINE(uint64_t) ASMMultU64ByU32DivByU32(uint64_t u64A, uint32_t u32B, uint32_t u32C) +{ +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + uint64_t u64Result, u64Spill; + __asm__ __volatile__("mulq %2\n\t" + "divq %3\n\t" + : "=&a" (u64Result), + "=&d" (u64Spill) + : "r" ((uint64_t)u32B), + "r" ((uint64_t)u32C), + "0" (u64A)); + return u64Result; +# else + uint32_t u32Dummy; + uint64_t u64Result; + __asm__ __volatile__("mull %%ecx \n\t" /* eax = u64Lo.lo = (u64A.lo * u32B).lo + edx = u64Lo.hi = (u64A.lo * u32B).hi */ + "xchg %%eax,%%esi \n\t" /* esi = u64Lo.lo + eax = u64A.hi */ + "xchg %%edx,%%edi \n\t" /* edi = u64Low.hi + edx = u32C */ + "xchg %%edx,%%ecx \n\t" /* ecx = u32C + edx = u32B */ + "mull %%edx \n\t" /* eax = u64Hi.lo = (u64A.hi * u32B).lo + edx = u64Hi.hi = (u64A.hi * u32B).hi */ + "addl %%edi,%%eax \n\t" /* u64Hi.lo += u64Lo.hi */ + "adcl $0,%%edx \n\t" /* u64Hi.hi += carry */ + "divl %%ecx \n\t" /* eax = u64Hi / u32C + edx = u64Hi % u32C */ + "movl %%eax,%%edi \n\t" /* edi = u64Result.hi = u64Hi / u32C */ + "movl %%esi,%%eax \n\t" /* eax = u64Lo.lo */ + "divl %%ecx \n\t" /* u64Result.lo */ + "movl %%edi,%%edx \n\t" /* u64Result.hi */ + : "=A"(u64Result), "=c"(u32Dummy), + "=S"(u32Dummy), "=D"(u32Dummy) + : "a"((uint32_t)u64A), + "S"((uint32_t)(u64A >> 32)), + "c"(u32B), + "D"(u32C)); + return u64Result; +# endif +# else + RTUINT64U u; + uint64_t u64Lo = (uint64_t)(u64A & 0xffffffff) * u32B; + uint64_t u64Hi = (uint64_t)(u64A >> 32) * u32B; + u64Hi += (u64Lo >> 32); + u.s.Hi = (uint32_t)(u64Hi / u32C); + u.s.Lo = (uint32_t)((((u64Hi % u32C) << 32) + (u64Lo & 0xffffffff)) / u32C); + return u.u; +# endif +} +#endif + +/** @} */ +#endif /* !IPRT_INCLUDED_asm_math_h */ + diff --git a/include/iprt/asm-watcom-x86-16.h b/include/iprt/asm-watcom-x86-16.h new file mode 100644 index 00000000..db8d4e69 --- /dev/null +++ b/include/iprt/asm-watcom-x86-16.h @@ -0,0 +1,983 @@ +/** @file + * IPRT - Assembly Functions, x86 16-bit Watcom C/C++ pragma aux. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asm_watcom_x86_16_h +#define IPRT_INCLUDED_asm_watcom_x86_16_h +/* no pragma once */ + +#ifndef IPRT_INCLUDED_asm_h +# error "Don't include this header directly." +#endif + +/* + * Turns out we cannot use 'ds' for segment stuff here because the compiler + * seems to insists on loading the DGROUP segment into 'ds' before calling + * stuff when using -ecc. Using 'es' instead as this seems to work fine. + * + * Note! The #undef that preceds the #pragma aux statements is for undoing + * the mangling, because the symbol in #pragma aux [symbol] statements + * doesn't get subjected to preprocessing. This is also why we include + * the watcom header at both the top and the bottom of asm.h file. + */ + +#undef ASMCompilerBarrier +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if 0 /* overkill version. */ +# pragma aux ASMCompilerBarrier = \ + "nop" \ + parm [] \ + modify exact [ax bx cx dx es ds]; +# else +# pragma aux ASMCompilerBarrier = \ + "" \ + parm [] \ + modify exact []; +# endif +#endif + +#undef ASMNopPause +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMNopPause = \ + ".686p" \ + ".xmm2" \ + "pause" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMAtomicXchgU8 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicXchgU8 = \ + "xchg es:[bx], al" \ + parm [es bx] [al] \ + value [al] \ + modify exact [al]; +#endif + +#undef ASMAtomicXchgU16 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicXchgU16 = \ + "xchg es:[bx], ax" \ + parm [es bx] [ax] \ + value [ax] \ + modify exact [ax]; +#endif + +#undef ASMAtomicXchgU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicXchgU32 = \ + ".386" \ + "shl ecx, 16" \ + "mov cx, ax" \ + "xchg es:[bx], ecx" \ + "mov eax, ecx" \ + "shr ecx, 16" \ + parm [es bx] [ax cx] \ + value [ax cx] \ + modify exact [ax cx]; +#endif + +#undef ASMAtomicXchgU64 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicXchgU64 = \ + ".586" \ + "shl eax, 16" \ + "mov ax, bx" /* eax = high dword */ \ + "shl ecx, 16" \ + "mov cx, dx" /* ecx = low dword */ \ + "mov ebx, ecx" /* ebx = low */ \ + "mov ecx, eax" /* ecx = high */ \ + "try_again:" \ + "lock cmpxchg8b es:[si]" \ + "jnz try_again" \ + "xchg eax, edx" \ + "mov ebx, eax" \ + "shr eax, 16" \ + "mov ecx, edx" \ + "shr ecx, 16" \ + parm [es si] [dx cx bx ax] \ + value [dx cx bx ax] \ + modify exact [dx cx bx ax]; +#endif + +#undef ASMAtomicCmpXchgU8 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgU8 = \ + ".486" \ + "lock cmpxchg es:[bx], cl" \ + "setz al" \ + parm [es bx] [cl] [al] \ + value [al] \ + modify exact [al]; +#endif + +#undef ASMAtomicCmpXchgU16 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgU16 = \ + ".486" \ + "lock cmpxchg es:[bx], cx" \ + "setz al" \ + parm [es bx] [cx] [ax] \ + value [al] \ + modify exact [ax]; +#endif + +#undef ASMAtomicCmpXchgU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgU32 = \ + ".486" \ + "shl ecx, 16" \ + "mov cx, dx" \ + "shl eax, 16" \ + "mov ax, di" \ + "rol eax, 16" \ + "lock cmpxchg es:[bx], ecx" \ + "setz al" \ + parm [es bx] [cx dx] [ax di] \ + value [al] \ + modify exact [ax cx]; +#endif + +/* ASMAtomicCmpXchgU64: External assembly implementation, too few registers for parameters. */ +/* ASMAtomicCmpXchgExU32: External assembly implementation, too few registers for parameters. */ +/* ASMAtomicCmpXchgExU64: External assembly implementation, too few registers for parameters. */ + +#undef ASMSerializeInstructionCpuId +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMSerializeInstructionCpuId = \ + ".586" \ + "xor eax, eax" \ + "cpuid" \ + parm [] \ + modify exact [ax bx cx dx]; +#endif + +#undef ASMSerializeInstructionIRet +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMSerializeInstructionIRet = \ + "pushf" \ + "push cs" \ + "call foo" /* 'push offset done' doesn't work */ \ + "jmp done" \ + "foo:" \ + "iret" \ + "done:" \ + parm [] \ + modify exact []; +#endif + +#undef ASMSerializeInstructionRdTscp +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMSerializeInstructionRdTscp = \ + 0x0f 0x01 0xf9 \ + parm [] \ + modify exact [ax dx cx]; +#endif + +#undef ASMAtomicReadU64 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicReadU64 = \ + ".586" \ + "xor eax, eax" \ + "xor edx, edx" \ + "xor ebx, ebx" \ + "xor ecx, ecx" \ + "lock cmpxchg8b es:[si]" \ + "xchg eax, edx" \ + "mov ebx, eax" \ + "shr eax, 16" \ + "mov ecx, edx" \ + "shr ecx, 16" \ + parm [es si] \ + value [dx cx bx ax] \ + modify exact [dx cx bx ax]; +#endif + +#undef ASMAtomicUoReadU64 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicUoReadU64 = \ + ".586" \ + "xor eax, eax" \ + "xor edx, edx" \ + "xor ebx, ebx" \ + "xor ecx, ecx" \ + "lock cmpxchg8b es:[si]" \ + "xchg eax, edx" \ + "mov ebx, eax" \ + "shr eax, 16" \ + "mov ecx, edx" \ + "shr ecx, 16" \ + parm [es si] \ + value [dx cx bx ax] \ + modify exact [dx cx bx ax]; +#endif + +#undef ASMAtomicAddU16 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicAddU16 = \ + ".486" \ + "lock xadd es:[bx], ax" \ + parm [es bx] [ax] \ + value [ax] \ + modify exact [ax]; +#endif + +#undef ASMAtomicAddU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicAddU32 = \ + ".486" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock xadd es:[bx], edx" \ + "mov ax, dx" \ + "shr edx, 16" \ + parm [es bx] [ax dx] \ + value [ax dx] \ + modify exact [ax dx]; +#endif + +#undef ASMAtomicIncU16 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicIncU16 = \ + ".486" \ + "mov ax, 1" \ + "lock xadd es:[bx], ax" \ + "inc ax" \ + parm [es bx] \ + value [ax] \ + modify exact [ax]; +#endif + +#undef ASMAtomicIncU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicIncU32 = \ + ".486" \ + "mov edx, 1" \ + "lock xadd es:[bx], edx" \ + "inc edx" \ + "mov ax, dx" \ + "shr edx, 16" \ + parm [es bx] \ + value [ax dx] \ + modify exact [ax dx]; +#endif + +/* ASMAtomicIncU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicDecU16 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicDecU16 = \ + ".486" \ + "mov ax, 0ffffh" \ + "lock xadd es:[bx], ax" \ + "dec ax" \ + parm [es bx] \ + value [ax] \ + modify exact [ax]; +#endif + +#undef ASMAtomicDecU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicDecU32 = \ + ".486" \ + "mov edx, 0ffffffffh" \ + "lock xadd es:[bx], edx" \ + "dec edx" \ + "mov ax, dx" \ + "shr edx, 16" \ + parm [es bx] \ + value [ax dx] \ + modify exact [ax dx]; +#endif + +/* ASMAtomicDecU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicOrU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicOrU32 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock or es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +#endif + +/* ASMAtomicOrU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicAndU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicAndU32 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock and es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +#endif + +/* ASMAtomicAndU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicUoOrU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicUoOrU32 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "or es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +#endif + +/* ASMAtomicUoOrU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicUoAndU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicUoAndU32 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "and es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +#endif + +/* ASMAtomicUoAndU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicUoIncU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicUoIncU32 = \ + ".486" \ + "mov edx, 1" \ + "xadd es:[bx], edx" \ + "inc edx" \ + "mov ax, dx" \ + "shr edx, 16" \ + parm [es bx] \ + value [ax dx] \ + modify exact [ax dx]; +#endif + +#undef ASMAtomicUoDecU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicUoDecU32 = \ + ".486" \ + "mov edx, 0ffffffffh" \ + "xadd es:[bx], edx" \ + "dec edx" \ + "mov ax, dx" \ + "shr edx, 16" \ + parm [es bx] \ + value [ax dx] \ + modify exact [ax dx]; +#endif + +#undef ASMMemZeroPage +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMMemZeroPage = \ + "mov cx, 2048" \ + "xor ax, ax" \ + "rep stosw" \ + parm [es di] \ + modify exact [ax cx di]; +# else +# pragma aux ASMMemZeroPage = \ + "mov ecx, 1024" \ + "xor eax, eax" \ + "rep stosd" \ + parm [es di] \ + modify exact [ax cx di]; +# endif +#endif + +#undef ASMMemZero32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMMemZero32 = \ + "xor ax, ax" \ + "shr cx, 1" \ + "shr cx, 1" \ + "rep stosw" \ + parm [es di] [cx] \ + modify exact [ax dx cx di]; +# else +# pragma aux ASMMemZero32 = \ + "and ecx, 0ffffh" /* probably not necessary, lazy bird should check... */ \ + "shr ecx, 2" \ + "xor eax, eax" \ + "rep stosd" \ + parm [es di] [cx] \ + modify exact [ax cx di]; +# endif +#endif + +#undef ASMMemFill32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMMemFill32 = \ + " shr cx, 1" \ + " shr cx, 1" \ + " jz done" \ + "again:" \ + " stosw" \ + " xchg ax, dx" \ + " stosw" \ + " xchg ax, dx" \ + " dec cx" \ + " jnz again" \ + "done:" \ + parm [es di] [cx] [ax dx]\ + modify exact [cx di]; +# else +# pragma aux ASMMemFill32 = \ + "and ecx, 0ffffh" /* probably not necessary, lazy bird should check... */ \ + "shr ecx, 2" \ + "shl eax, 16" \ + "mov ax, dx" \ + "rol eax, 16" \ + "rep stosd" \ + parm [es di] [cx] [ax dx]\ + modify exact [ax cx di]; +# endif +#endif + +#undef ASMProbeReadByte +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMProbeReadByte = \ + "mov al, es:[bx]" \ + parm [es bx] \ + value [al] \ + modify exact [al]; +#endif + +#undef ASMBitSet +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMBitSet = \ + " mov ch, cl" /* Only the three lowest bits are relevant due to 64KB segments */ \ + " mov cl, 5" \ + " shl ch, cl" \ + " add bh, ch" /* Adjust the pointer. */ \ + " mov cl, al" \ + " shr ax, 1" /* convert to byte offset */ \ + " shr ax, 1" \ + " shr ax, 1" \ + " add bx, ax" /* adjust pointer again */\ + " and cl, 7" \ + " mov al, 1" \ + " shl al, cl" /* al=bitmask */ \ + " or es:[bx], al" \ + parm [es bx] [ax cx] \ + modify exact [ax bx cx]; +# else +# pragma aux ASMBitSet = \ + "shl edx, 16" \ + "mov dx, ax" \ + "bts es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +# endif +#endif + +#undef ASMAtomicBitSet +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicBitSet = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock bts es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +#endif + +#undef ASMBitClear +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMBitClear = \ + " mov ch, cl" /* Only the three lowest bits are relevant due to 64KB segments */ \ + " mov cl, 5" \ + " shl ch, cl" \ + " add bh, ch" /* Adjust the pointer. */ \ + " mov cl, al" \ + " shr ax, 1" /* convert to byte offset */ \ + " shr ax, 1" \ + " shr ax, 1" \ + " add bx, ax" /* adjust pointer again */\ + " and cl, 7" \ + " mov al, 1" \ + " shl al, cl" \ + " not al" /* al=bitmask */ \ + " and es:[bx], al" \ + parm [es bx] [ax cx] \ + modify exact [ax bx cx]; +# else +# pragma aux ASMBitClear = \ + "shl edx, 16" \ + "mov dx, ax" \ + "btr es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +# endif +#endif + +#undef ASMAtomicBitClear +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicBitClear = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock btr es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +#endif + +#undef ASMBitToggle +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMBitToggle = \ + " mov ch, cl" /* Only the three lowest bits are relevant due to 64KB segments */ \ + " mov cl, 5" \ + " shl ch, cl" \ + " add bh, ch" /* Adjust the pointer. */ \ + " mov cl, al" \ + " shr ax, 1" /* convert to byte offset */ \ + " shr ax, 1" \ + " shr ax, 1" \ + " add bx, ax" /* adjust pointer again */\ + " and cl, 7" \ + " mov al, 1" \ + " shl al, cl" /* al=bitmask */ \ + " xor es:[bx], al" \ + parm [es bx] [ax cx] \ + modify exact [ax bx cx]; +# else +# pragma aux ASMBitToggle = \ + "shl edx, 16" \ + "mov dx, ax" \ + "btc es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +# endif +#endif + +#undef ASMAtomicBitToggle +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicBitToggle = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock btc es:[bx], edx" \ + parm [es bx] [ax dx] \ + modify exact [dx]; +#endif + +#undef ASMBitTestAndSet +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMBitTestAndSet = \ + " mov ch, cl" /* Only the three lowest bits are relevant due to 64KB segments */ \ + " mov cl, 5" \ + " shl ch, cl" \ + " add bh, ch" /* Adjust the pointer. */ \ + " mov cl, al" \ + " shr ax, 1" /* convert to byte offset */ \ + " shr ax, 1" \ + " shr ax, 1" \ + " add bx, ax" /* adjust pointer again */\ + " and cl, 7" /* cl=byte shift count */ \ + " mov ah, 1" \ + " shl ah, cl" /* ah=bitmask */ \ + " mov al, es:[bx]" \ + " or ah, al" \ + " mov es:[bx], ah" \ + " shr al, cl" \ + " and al, 1" \ + parm [es bx] [ax cx] \ + value [al] \ + modify exact [ax bx cx]; +# else +# pragma aux ASMBitTestAndSet = \ + "shl edx, 16" \ + "mov dx, ax" \ + "bts es:[bx], edx" \ + "setc al" \ + parm [es bx] [ax dx] \ + value [al] \ + modify exact [ax dx]; +# endif +#endif + +#undef ASMAtomicBitTestAndSet +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicBitTestAndSet = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock bts es:[bx], edx" \ + "setc al" \ + parm [es bx] [ax dx] \ + value [al] \ + modify exact [ax dx]; +#endif + +#undef ASMBitTestAndClear +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMBitTestAndClear = \ + " mov ch, cl" /* Only the three lowest bits are relevant due to 64KB segments */ \ + " mov cl, 5" \ + " shl ch, cl" \ + " add bh, ch" /* Adjust the pointer. */ \ + " mov cl, al" \ + " shr ax, 1" /* convert to byte offset */ \ + " shr ax, 1" \ + " shr ax, 1" \ + " add bx, ax" /* adjust pointer again */\ + " and cl, 7" /* cl=byte shift count */ \ + " mov ah, 1" \ + " shl ah, cl" \ + " not ah" /* ah=bitmask */ \ + " mov al, es:[bx]" \ + " and ah, al" \ + " mov es:[bx], ah" \ + " shr al, cl" \ + " and al, 1" \ + parm [es bx] [ax cx] \ + value [al] \ + modify exact [ax bx cx]; +# else +# pragma aux ASMBitTestAndClear = \ + "shl edx, 16" \ + "mov dx, ax" \ + "btr es:[bx], edx" \ + "setc al" \ + parm [es bx] [ax dx] \ + value [al] \ + modify exact [ax dx]; +# endif +#endif + +#undef ASMAtomicBitTestAndClear +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicBitTestAndClear = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock btr es:[bx], edx" \ + "setc al" \ + parm [es bx] [ax dx] \ + value [al] \ + modify exact [ax dx]; +#endif + +#undef ASMBitTestAndToggle +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMBitTestAndToggle = \ + " mov ch, cl" /* Only the three lowest bits are relevant due to 64KB segments */ \ + " mov cl, 5" \ + " shl ch, cl" \ + " add bh, ch" /* Adjust the pointer. */ \ + " mov cl, al" \ + " shr ax, 1" /* convert to byte offset */ \ + " shr ax, 1" \ + " shr ax, 1" \ + " add bx, ax" /* adjust pointer again */\ + " and cl, 7" /* cl=byte shift count */ \ + " mov ah, 1" \ + " shl ah, cl" /* ah=bitmask */ \ + " mov al, es:[bx]" \ + " xor ah, al" \ + " mov es:[bx], ah" \ + " shr al, cl" \ + " and al, 1" \ + parm [es bx] [ax cx] \ + value [al] \ + modify exact [ax bx cx]; +# else +# pragma aux ASMBitTestAndToggle = \ + "shl edx, 16" \ + "mov dx, ax" \ + "btc es:[bx], edx" \ + "setc al" \ + parm [es bx] [ax dx] \ + value [al] \ + modify exact [ax dx]; +# endif +#endif + +#undef ASMAtomicBitTestAndToggle +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMAtomicBitTestAndToggle = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "lock btc es:[bx], edx" \ + "setc al" \ + parm [es bx] [ax dx] \ + value [al] \ + modify exact [ax dx]; +#endif + +#undef ASMBitTest +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# pragma aux ASMBitTest = \ + " mov ch, cl" /* Only the three lowest bits are relevant due to 64KB segments */ \ + " mov cl, 5" \ + " shl ch, cl" \ + " add bh, ch" /* Adjust the pointer. */ \ + " mov cl, al" \ + " shr ax, 1" /* convert to byte offset */ \ + " shr ax, 1" \ + " shr ax, 1" \ + " add bx, ax" /* adjust pointer again */\ + " and cl, 7" \ + " mov al, es:[bx]" \ + " shr al, cl" \ + " and al, 1" \ + parm [es bx] [ax cx] \ + value [al] \ + modify exact [ax bx cx]; +# else +# pragma aux ASMBitTest = \ + "shl edx, 16" \ + "mov dx, ax" \ + "bt es:[bx], edx" \ + "setc al" \ + parm [es bx] [ax dx] nomemory \ + value [al] \ + modify exact [ax dx] nomemory; +# endif +#endif + +/* ASMBitFirstClear: External file. */ +/* ASMBitNextClear: External file. */ +/* ASMBitFirstSet: External file. */ +/* ASMBitNextSet: External file. */ + +#if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +/* ASMBitFirstSetU32: External file. */ +#else +# undef ASMBitFirstSetU32 +# ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# pragma aux ASMBitFirstSetU32 = \ + "shl edx, 16" \ + "mov dx, ax" \ + "bsf eax, edx" \ + "jz not_found" \ + "inc ax" \ + "jmp done" \ + "not_found:" \ + "xor ax, ax" \ + "done:" \ + parm [ax dx] nomemory \ + value [ax] \ + modify exact [ax dx] nomemory; +# endif +#endif + +#if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +/* ASMBitFirstSetU64: External file. */ +#else +# undef ASMBitFirstSetU64 +# ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# pragma aux ASMBitFirstSetU64 = \ + ".386" \ + "shl ecx, 16" \ + "mov cx, dx" \ + "bsf ecx, ecx" \ + "jz not_found_low" \ + "mov ax, cx" \ + "inc ax" \ + "jmp done" \ + \ + "not_found_low:" \ + "shr eax, 16" \ + "mov ax, bx" \ + "bsf eax, eax" \ + "jz not_found_high" \ + "add ax, 33" \ + "jmp done" \ + \ + "not_found_high:" \ + "xor ax, ax" \ + "done:" \ + parm [dx cx bx ax] nomemory \ + value [ax] \ + modify exact [ax cx] nomemory; +# endif +#endif + +#if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +/* ASMBitFirstSetU16: External file. */ +#else +# undef ASMBitFirstSetU16 +# ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# pragma aux ASMBitFirstSetU16 = \ + "bsf ax, ax" \ + "jz not_found" \ + "inc ax" \ + "jmp done" \ + "not_found:" \ + "xor ax, ax" \ + "done:" \ + parm [ax] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +# endif +#endif + +#if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +/* ASMBitLastSetU32: External file. */ +#else +# undef ASMBitLastSetU32 +# ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# pragma aux ASMBitLastSetU32 = \ + "shl edx, 16" \ + "mov dx, ax" \ + "bsr eax, edx" \ + "jz not_found" \ + "inc ax" \ + "jmp done" \ + "not_found:" \ + "xor ax, ax" \ + "done:" \ + parm [ax dx] nomemory \ + value [ax] \ + modify exact [ax dx] nomemory; +# endif +#endif + +#if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +/* ASMBitLastSetU64: External file. */ +#else +# undef ASMBitLastSetU64 +# ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# pragma aux ASMBitLastSetU64 = \ + ".386" \ + "shl ecx, 16" \ + "mov cx, dx" \ + "bsf ecx, ecx" \ + "jz not_found_low" \ + "mov ax, cx" \ + "inc ax" \ + "jmp done" \ + \ + "not_found_low:" \ + "shr eax, 16" \ + "mov ax, bx" \ + "bsf eax, eax" \ + "jz not_found_high" \ + "add ax, 33" \ + "jmp done" \ + \ + "not_found_high:" \ + "xor ax, ax" \ + "done:" \ + parm [dx cx bx ax] nomemory \ + value [ax] \ + modify exact [ax cx] nomemory; +# endif +#endif + +#if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +/* ASMBitLastSetU16: External file. */ +#else +# undef ASMBitLastSetU16 +# ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# pragma aux ASMBitLastSetU16 = \ + "bsr ax, ax" \ + "jz not_found" \ + "inc ax" \ + "jmp done" \ + "not_found:" \ + "xor ax, ax" \ + "done:" \ + parm [ax] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +# endif +#endif + +#undef ASMByteSwapU16 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMByteSwapU16 = \ + "xchg al, ah" \ + parm [ax] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMByteSwapU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMByteSwapU32 = \ + "xchg dh, al" \ + "xchg dl, ah" \ + parm [ax dx] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMRotateLeftU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMRotateLeftU32 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "rol edx, cl" \ + "mov eax, edx" \ + "shr edx, 16" \ + parm [ax dx] [cx] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#undef ASMRotateRightU32 +#ifdef IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +#pragma aux ASMRotateRightU32 = \ + ".386" \ + "shl edx, 16" \ + "mov dx, ax" \ + "ror edx, cl" \ + "mov eax, edx" \ + "shr edx, 16" \ + parm [ax dx] [cx] nomemory \ + value [ax dx] \ + modify exact [ax dx] nomemory; +#endif + +#endif /* !IPRT_INCLUDED_asm_watcom_x86_16_h */ diff --git a/include/iprt/asm-watcom-x86-32.h b/include/iprt/asm-watcom-x86-32.h new file mode 100644 index 00000000..e52c59b2 --- /dev/null +++ b/include/iprt/asm-watcom-x86-32.h @@ -0,0 +1,741 @@ +/** @file + * IPRT - Assembly Functions, x86 32-bit Watcom C/C++ pragma aux. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asm_watcom_x86_32_h +#define IPRT_INCLUDED_asm_watcom_x86_32_h +/* no pragma once */ + +#ifndef IPRT_INCLUDED_asm_h +# error "Don't include this header directly." +#endif + +#ifndef __FLAT__ +# error "Only works with flat pointers! (-mf)" +#endif + +/* + * Note! The #undef that preceds the #pragma aux statements is for undoing + * the mangling, because the symbol in #pragma aux [symbol] statements + * doesn't get subjected to preprocessing. This is also why we include + * the watcom header at both the top and the bottom of asm.h file. + */ + +#undef ASMCompilerBarrier +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +# if 0 /* overkill version. */ +# pragma aux ASMCompilerBarrier = \ + "nop" \ + parm [] \ + modify exact [eax ebx ecx edx es ds fs gs]; +# else +# pragma aux ASMCompilerBarrier = \ + "" \ + parm [] \ + modify exact []; +# endif +#endif + +#undef ASMNopPause +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMNopPause = \ + ".686p" \ + ".xmm2" \ + "pause" \ + parm [] nomemory \ + modify exact [] nomemory; +#endif + +#undef ASMAtomicXchgU8 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicXchgU8 = \ + "xchg [ecx], al" \ + parm [ecx] [al] \ + value [al] \ + modify exact [al]; +#endif + +#undef ASMAtomicXchgU16 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicXchgU16 = \ + "xchg [ecx], ax" \ + parm [ecx] [ax] \ + value [ax] \ + modify exact [ax]; +#endif + +#undef ASMAtomicXchgU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicXchgU32 = \ + "xchg [ecx], eax" \ + parm [ecx] [eax] \ + value [eax] \ + modify exact [eax]; +#endif + +#undef ASMAtomicXchgU64 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicXchgU64 = \ + ".586" \ + "try_again:" \ + "lock cmpxchg8b [esi]" \ + "jnz try_again" \ + parm [esi] [ebx ecx] \ + value [eax edx] \ + modify exact [edx ecx ebx eax]; +#endif + +#undef ASMAtomicCmpXchgU8 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgU8 = \ + ".486" \ + "lock cmpxchg [edx], cl" \ + "setz al" \ + parm [edx] [cl] [al] \ + value [al] \ + modify exact [al]; +#endif + +#undef ASMAtomicCmpXchgU16 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgU16 = \ + ".486" \ + "lock cmpxchg [edx], cx" \ + "setz al" \ + parm [edx] [cx] [ax] \ + value [al] \ + modify exact [ax]; +#endif + +#undef ASMAtomicCmpXchgU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgU32 = \ + ".486" \ + "lock cmpxchg [edx], ecx" \ + "setz al" \ + parm [edx] [ecx] [eax] \ + value [al] \ + modify exact [eax]; +#endif + +#undef ASMAtomicCmpXchgU64 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgU64 = \ + ".586" \ + "lock cmpxchg8b [edi]" \ + "setz al" \ + parm [edi] [ebx ecx] [eax edx] \ + value [al] \ + modify exact [eax edx]; +#endif + +#undef ASMAtomicCmpXchgExU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgExU32 = \ + ".586" \ + "lock cmpxchg [edx], ecx" \ + "mov [edi], eax" \ + "setz al" \ + parm [edx] [ecx] [eax] [edi] \ + value [al] \ + modify exact [eax]; +#endif + +#undef ASMAtomicCmpXchgExU64 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicCmpXchgExU64 = \ + ".586" \ + "lock cmpxchg8b [edi]" \ + "mov [esi], eax" \ + "mov [esi + 4], edx" \ + "setz al" \ + parm [edi] [ebx ecx] [eax edx] [esi] \ + value [al] \ + modify exact [eax edx]; +#endif + +#undef ASMSerializeInstructionCpuId +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMSerializeInstructionCpuId = \ + ".586" \ + "xor eax, eax" \ + "cpuid" \ + parm [] \ + modify exact [eax ebx ecx edx]; +#endif + +#undef ASMSerializeInstructionIRet +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMSerializeInstructionIRet = \ + "pushf" \ + "push cs" \ + "call foo" /* 'push offset done' doesn't work */ \ + "jmp done" \ + "foo:" \ + "iret" \ + "done:" \ + parm [] \ + modify exact []; +#endif + +#undef ASMSerializeInstructionRdTscp +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMSerializeInstructionRdTscp = \ + 0x0f 0x01 0xf9 \ + parm [] \ + modify exact [eax edx ecx]; +#endif + +#undef ASMAtomicReadU64 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicReadU64 = \ + ".586" \ + "xor eax, eax" \ + "mov edx, eax" \ + "mov ebx, eax" \ + "mov ecx, eax" \ + "lock cmpxchg8b [edi]" \ + parm [edi] \ + value [eax edx] \ + modify exact [eax ebx ecx edx]; +#endif + +#undef ASMAtomicUoReadU64 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicUoReadU64 = \ + ".586" \ + "xor eax, eax" \ + "mov edx, eax" \ + "mov ebx, eax" \ + "mov ecx, eax" \ + "lock cmpxchg8b [edi]" \ + parm [edi] \ + value [eax edx] \ + modify exact [eax ebx ecx edx]; +#endif + +#undef ASMAtomicAddU16 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicAddU16 = \ + ".486" \ + "lock xadd [ecx], ax" \ + parm [ecx] [ax] \ + value [ax] \ + modify exact [ax]; +#endif + +#undef ASMAtomicAddU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicAddU32 = \ + ".486" \ + "lock xadd [ecx], eax" \ + parm [ecx] [eax] \ + value [eax] \ + modify exact [eax]; +#endif + +#undef ASMAtomicIncU16 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicIncU16 = \ + ".486" \ + "mov ax, 1" \ + "lock xadd [ecx], ax" \ + "inc ax" \ + parm [ecx] \ + value [ax] \ + modify exact [ax]; +#endif + +#undef ASMAtomicIncU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicIncU32 = \ + ".486" \ + "mov eax, 1" \ + "lock xadd [ecx], eax" \ + "inc eax" \ + parm [ecx] \ + value [eax] \ + modify exact [eax]; +#endif + +/* ASMAtomicIncU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicDecU16 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicDecU16 = \ + ".486" \ + "mov ax, 0ffffh" \ + "lock xadd [ecx], ax" \ + "dec ax" \ + parm [ecx] \ + value [ax] \ + modify exact [ax]; +#endif + +#undef ASMAtomicDecU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicDecU32 = \ + ".486" \ + "mov eax, 0ffffffffh" \ + "lock xadd [ecx], eax" \ + "dec eax" \ + parm [ecx] \ + value [eax] \ + modify exact [eax]; +#endif + +/* ASMAtomicDecU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicOrU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicOrU32 = \ + "lock or [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +/* ASMAtomicOrU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicAndU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicAndU32 = \ + "lock and [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +/* ASMAtomicAndU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicUoOrU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicUoOrU32 = \ + "or [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +/* ASMAtomicUoOrU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicUoAndU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicUoAndU32 = \ + "and [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +/* ASMAtomicUoAndU64: Should be done by C inline or in external file. */ + +#undef ASMAtomicUoIncU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicUoIncU32 = \ + ".486" \ + "xadd [ecx], eax" \ + "inc eax" \ + parm [ecx] \ + value [eax] \ + modify exact [eax]; +#endif + +#undef ASMAtomicUoDecU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicUoDecU32 = \ + ".486" \ + "mov eax, 0ffffffffh" \ + "xadd [ecx], eax" \ + "dec eax" \ + parm [ecx] \ + value [eax] \ + modify exact [eax]; +#endif + +#undef ASMMemZeroPage +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMMemZeroPage = \ + "mov ecx, 1024" \ + "xor eax, eax" \ + "rep stosd" \ + parm [edi] \ + modify exact [eax ecx edi]; +#endif + +#undef ASMMemZero32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMMemZero32 = \ + "shr ecx, 2" \ + "xor eax, eax" \ + "rep stosd" \ + parm [edi] [ecx] \ + modify exact [eax ecx edi]; +#endif + +#undef ASMMemFill32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMMemFill32 = \ + "shr ecx, 2" \ + "rep stosd" \ + parm [edi] [ecx] [eax]\ + modify exact [ecx edi]; +#endif + +#undef ASMProbeReadByte +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMProbeReadByte = \ + "mov al, [ecx]" \ + parm [ecx] \ + value [al] \ + modify exact [al]; +#endif + +#undef ASMBitSet +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitSet = \ + "bts [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +#undef ASMAtomicBitSet +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicBitSet = \ + "lock bts [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +#undef ASMBitClear +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitClear = \ + "btr [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +#undef ASMAtomicBitClear +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicBitClear = \ + "lock btr [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +#undef ASMBitToggle +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitToggle = \ + "btc [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + +#undef ASMAtomicBitToggle +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicBitToggle = \ + "lock btc [ecx], eax" \ + parm [ecx] [eax] \ + modify exact []; +#endif + + +#undef ASMBitTestAndSet +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitTestAndSet = \ + "bts [ecx], eax" \ + "setc al" \ + parm [ecx] [eax] \ + value [al] \ + modify exact [eax]; +#endif + +#undef ASMAtomicBitTestAndSet +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicBitTestAndSet = \ + "lock bts [ecx], eax" \ + "setc al" \ + parm [ecx] [eax] \ + value [al] \ + modify exact [eax]; +#endif + +#undef ASMBitTestAndClear +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitTestAndClear = \ + "btr [ecx], eax" \ + "setc al" \ + parm [ecx] [eax] \ + value [al] \ + modify exact [eax]; +#endif + +#undef ASMAtomicBitTestAndClear +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicBitTestAndClear = \ + "lock btr [ecx], eax" \ + "setc al" \ + parm [ecx] [eax] \ + value [al] \ + modify exact [eax]; +#endif + +#undef ASMBitTestAndToggle +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitTestAndToggle = \ + "btc [ecx], eax" \ + "setc al" \ + parm [ecx] [eax] \ + value [al] \ + modify exact [eax]; +#endif + +#undef ASMAtomicBitTestAndToggle +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMAtomicBitTestAndToggle = \ + "lock btc [ecx], eax" \ + "setc al" \ + parm [ecx] [eax] \ + value [al] \ + modify exact [eax]; +#endif + +#undef ASMBitTest +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitTest = \ + "bt [ecx], eax" \ + "setc al" \ + parm [ecx] [eax] nomemory \ + value [al] \ + modify exact [eax] nomemory; +#endif + +#if 0 +/** @todo this is way to much inline assembly, better off in an external function. */ +#undef ASMBitFirstClear +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitFirstClear = \ + "mov edx, edi" /* save start of bitmap for later */ \ + "add ecx, 31" \ + "shr ecx, 5" /* cDWord = RT_ALIGN_32(cBits, 32) / 32; */ \ + "mov eax, 0ffffffffh" \ + "repe scasd" \ + "je done" \ + "lea edi, [edi - 4]" /* rewind edi */ \ + "xor eax, [edi]" /* load inverted bits */ \ + "sub edi, edx" /* calc byte offset */ \ + "shl edi, 3" /* convert byte to bit offset */ \ + "mov edx, eax" \ + "bsf eax, edx" \ + "add eax, edi" \ + "done:" \ + parm [edi] [ecx] \ + value [eax] \ + modify exact [eax ecx edx edi]; +#endif + +/* ASMBitNextClear: Too much work, do when needed. */ + +/** @todo this is way to much inline assembly, better off in an external function. */ +#undef ASMBitFirstSet +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitFirstSet = \ + "mov edx, edi" /* save start of bitmap for later */ \ + "add ecx, 31" \ + "shr ecx, 5" /* cDWord = RT_ALIGN_32(cBits, 32) / 32; */ \ + "mov eax, 0ffffffffh" \ + "repe scasd" \ + "je done" \ + "lea edi, [edi - 4]" /* rewind edi */ \ + "mov eax, [edi]" /* reload previous dword */ \ + "sub edi, edx" /* calc byte offset */ \ + "shl edi, 3" /* convert byte to bit offset */ \ + "mov edx, eax" \ + "bsf eax, edx" \ + "add eax, edi" \ + "done:" \ + parm [edi] [ecx] \ + value [eax] \ + modify exact [eax ecx edx edi]; +#endif + +/* ASMBitNextSet: Too much work, do when needed. */ +#else +/* ASMBitFirstClear: External file. */ +/* ASMBitNextClear: External file. */ +/* ASMBitFirstSet: External file. */ +/* ASMBitNextSet: External file. */ +#endif + +#undef ASMBitFirstSetU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitFirstSetU32 = \ + "bsf eax, eax" \ + "jz not_found" \ + "inc eax" \ + "jmp done" \ + "not_found:" \ + "xor eax, eax" \ + "done:" \ + parm [eax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMBitFirstSetU64 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitFirstSetU64 = \ + "bsf eax, eax" \ + "jz not_found_low" \ + "inc eax" \ + "jmp done" \ + \ + "not_found_low:" \ + "bsf eax, edx" \ + "jz not_found_high" \ + "add eax, 33" \ + "jmp done" \ + \ + "not_found_high:" \ + "xor eax, eax" \ + "done:" \ + parm [eax edx] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMBitFirstSetU16 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitFirstSetU16 = \ + "movzx eax, ax" \ + "bsf eax, eax" \ + "jz not_found" \ + "inc eax" \ + "jmp done" \ + "not_found:" \ + "xor eax, eax" \ + "done:" \ + parm [ax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMBitLastSetU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitLastSetU32 = \ + "bsr eax, eax" \ + "jz not_found" \ + "inc eax" \ + "jmp done" \ + "not_found:" \ + "xor eax, eax" \ + "done:" \ + parm [eax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMBitLastSetU64 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitLastSetU64 = \ + "xchg eax, edx" \ + "bsr eax, eax" \ + "jz not_found_high" \ + "add eax, 33" \ + "jmp done" \ + \ + "not_found_high:" \ + "bsr eax, edx" \ + "jz not_found" \ + "inc eax" \ + "jmp done" \ + \ + "not_found:" \ + "xor eax, eax" \ + "done:" \ + parm [eax edx] nomemory \ + value [eax] \ + modify exact [eax edx] nomemory; +#endif + +#undef ASMBitLastSetU16 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMBitLastSetU16 = \ + "movzx eax, ax" \ + "bsr eax, eax" \ + "jz not_found" \ + "inc eax" \ + "jmp done" \ + "not_found:" \ + "xor eax, eax" \ + "done:" \ + parm [ax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMByteSwapU16 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMByteSwapU16 = \ + "ror ax, 8" \ + parm [ax] nomemory \ + value [ax] \ + modify exact [ax] nomemory; +#endif + +#undef ASMByteSwapU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMByteSwapU32 = \ + "bswap eax" \ + parm [eax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMRotateLeftU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMRotateLeftU32 = \ + "rol eax, cl" \ + parm [eax] [ecx] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#undef ASMRotateRightU32 +#ifdef IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +#pragma aux ASMRotateRightU32 = \ + "ror eax, cl" \ + parm [eax] [ecx] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + +#endif /* !IPRT_INCLUDED_asm_watcom_x86_32_h */ + diff --git a/include/iprt/asm.h b/include/iprt/asm.h new file mode 100644 index 00000000..100555ed --- /dev/null +++ b/include/iprt/asm.h @@ -0,0 +1,8132 @@ +/** @file + * IPRT - Assembly Functions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asm_h +#define IPRT_INCLUDED_asm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/assert.h> +/** @def RT_INLINE_ASM_USES_INTRIN + * Defined as 1 if we're using a _MSC_VER 1400. + * Otherwise defined as 0. + */ + +/* Solaris 10 header ugliness */ +#ifdef u +# undef u +#endif + +#if defined(_MSC_VER) && RT_INLINE_ASM_USES_INTRIN +/* Emit the intrinsics at all optimization levels. */ +# include <iprt/sanitized/intrin.h> +# pragma intrinsic(_ReadWriteBarrier) +# pragma intrinsic(__cpuid) +# pragma intrinsic(__stosd) +# pragma intrinsic(__stosw) +# pragma intrinsic(__stosb) +# pragma intrinsic(_BitScanForward) +# pragma intrinsic(_BitScanReverse) +# pragma intrinsic(_bittest) +# pragma intrinsic(_bittestandset) +# pragma intrinsic(_bittestandreset) +# pragma intrinsic(_bittestandcomplement) +# pragma intrinsic(_byteswap_ushort) +# pragma intrinsic(_byteswap_ulong) +# pragma intrinsic(_interlockedbittestandset) +# pragma intrinsic(_interlockedbittestandreset) +# pragma intrinsic(_InterlockedAnd) +# pragma intrinsic(_InterlockedOr) +# pragma intrinsic(_InterlockedXor) +# pragma intrinsic(_InterlockedIncrement) +# pragma intrinsic(_InterlockedDecrement) +# pragma intrinsic(_InterlockedExchange) +# pragma intrinsic(_InterlockedExchangeAdd) +# pragma intrinsic(_InterlockedCompareExchange) +# pragma intrinsic(_InterlockedCompareExchange8) +# pragma intrinsic(_InterlockedCompareExchange16) +# pragma intrinsic(_InterlockedCompareExchange64) +# pragma intrinsic(_rotl) +# pragma intrinsic(_rotr) +# pragma intrinsic(_rotl64) +# pragma intrinsic(_rotr64) +# ifdef RT_ARCH_AMD64 +# pragma intrinsic(__stosq) +# pragma intrinsic(_byteswap_uint64) +# pragma intrinsic(_InterlockedCompareExchange128) +# pragma intrinsic(_InterlockedExchange64) +# pragma intrinsic(_InterlockedExchangeAdd64) +# pragma intrinsic(_InterlockedAnd64) +# pragma intrinsic(_InterlockedOr64) +# pragma intrinsic(_InterlockedIncrement64) +# pragma intrinsic(_InterlockedDecrement64) +# endif +#endif + +/* + * Undefine all symbols we have Watcom C/C++ #pragma aux'es for. + */ +#if defined(__WATCOMC__) && ARCH_BITS == 16 && defined(RT_ARCH_X86) +# include "asm-watcom-x86-16.h" +#elif defined(__WATCOMC__) && ARCH_BITS == 32 && defined(RT_ARCH_X86) +# include "asm-watcom-x86-32.h" +#endif + + +/** @defgroup grp_rt_asm ASM - Assembly Routines + * @ingroup grp_rt + * + * @remarks The difference between ordered and unordered atomic operations are + * that the former will complete outstanding reads and writes before + * continuing while the latter doesn't make any promises about the + * order. Ordered operations doesn't, it seems, make any 100% promise + * wrt to whether the operation will complete before any subsequent + * memory access. (please, correct if wrong.) + * + * ASMAtomicSomething operations are all ordered, while + * ASMAtomicUoSomething are unordered (note the Uo). + * + * Please note that ordered operations does not necessarily imply a + * compiler (memory) barrier. The user has to use the + * ASMCompilerBarrier() macro when that is deemed necessary. + * + * @remarks Some remarks about __volatile__: Without this keyword gcc is allowed + * to reorder or even optimize assembler instructions away. For + * instance, in the following code the second rdmsr instruction is + * optimized away because gcc treats that instruction as deterministic: + * + * @code + * static inline uint64_t rdmsr_low(int idx) + * { + * uint32_t low; + * __asm__ ("rdmsr" : "=a"(low) : "c"(idx) : "edx"); + * } + * ... + * uint32_t msr1 = rdmsr_low(1); + * foo(msr1); + * msr1 = rdmsr_low(1); + * bar(msr1); + * @endcode + * + * The input parameter of rdmsr_low is the same for both calls and + * therefore gcc will use the result of the first call as input + * parameter for bar() as well. For rdmsr this is not acceptable as + * this instruction is _not_ deterministic. This applies to reading + * machine status information in general. + * + * @{ + */ + + +/** @def RT_INLINE_ASM_GCC_4_3_X_X86 + * Used to work around some 4.3.x register allocation issues in this version of + * the compiler. So far this workaround is still required for 4.4 and 4.5 but + * definitely not for 5.x */ +#if (RT_GNUC_PREREQ(4, 3) && !RT_GNUC_PREREQ(5, 0) && defined(__i386__)) +# define RT_INLINE_ASM_GCC_4_3_X_X86 1 +#else +# define RT_INLINE_ASM_GCC_4_3_X_X86 0 +#endif + +/** @def RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC + * i686-apple-darwin9-gcc-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5493) screws up + * RTSemRWRequestWrite semsemrw-lockless-generic.cpp in release builds. PIC + * mode, x86. + * + * Some gcc 4.3.x versions may have register allocation issues with cmpxchg8b + * when in PIC mode on x86. + */ +#ifndef RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC +# if defined(DOXYGEN_RUNNING) || defined(__WATCOMC__) /* Watcom has trouble with the expression below */ +# define RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC 1 +# elif defined(_MSC_VER) /* Visual C++ has trouble too, but it'll only tell us when C4688 is enabled. */ +# define RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC 0 +# elif ( (defined(PIC) || defined(__PIC__)) \ + && defined(RT_ARCH_X86) \ + && ( RT_INLINE_ASM_GCC_4_3_X_X86 \ + || defined(RT_OS_DARWIN)) ) +# define RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC 1 +# else +# define RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC 0 +# endif +#endif + + +/** @def RT_INLINE_ASM_EXTERNAL_TMP_ARM + * Temporary version of RT_INLINE_ASM_EXTERNAL that excludes ARM. */ +#if RT_INLINE_ASM_EXTERNAL && !(defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)) +# define RT_INLINE_ASM_EXTERNAL_TMP_ARM 1 +#else +# define RT_INLINE_ASM_EXTERNAL_TMP_ARM 0 +#endif + +/* + * ARM is great fun. + */ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + +# define RTASM_ARM_NO_BARRIER +# ifdef RT_ARCH_ARM64 +# define RTASM_ARM_NO_BARRIER_IN_REG +# define RTASM_ARM_NO_BARRIER_COMMA_IN_REG +# define RTASM_ARM_DSB_SY "dsb sy\n\t" +# define RTASM_ARM_DSB_SY_IN_REG +# define RTASM_ARM_DSB_SY_COMMA_IN_REG +# define RTASM_ARM_DMB_SY "dmb sy\n\t" +# define RTASM_ARM_DMB_SY_IN_REG +# define RTASM_ARM_DMB_SY_COMMA_IN_REG +# define RTASM_ARM_DMB_ST "dmb st\n\t" +# define RTASM_ARM_DMB_ST_IN_REG +# define RTASM_ARM_DMB_ST_COMMA_IN_REG +# define RTASM_ARM_DMB_LD "dmb ld\n\t" +# define RTASM_ARM_DMB_LD_IN_REG +# define RTASM_ARM_DMB_LD_COMMA_IN_REG +# define RTASM_ARM_PICK_6432(expr64, expr32) expr64 +# define RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(name, a_pu32Mem, barrier_type, modify64, modify32, in_reg) \ + uint32_t rcSpill; \ + uint32_t u32NewRet; \ + __asm__ __volatile__(".Ltry_again_" #name "_%=:\n\t" \ + RTASM_ARM_##barrier_type /* before lable? */ \ + "ldaxr %w[uNew], %[pMem]\n\t" \ + modify64 \ + "stlxr %w[rc], %w[uNew], %[pMem]\n\t" \ + "cbnz %w[rc], .Ltry_again_" #name "_%=\n\t" \ + : [pMem] "+Q" (*a_pu32Mem) \ + , [uNew] "=&r" (u32NewRet) \ + , [rc] "=&r" (rcSpill) \ + : in_reg \ + : "cc") +# define RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(name, a_pu32Mem, barrier_type, modify64, modify32, in_reg) \ + uint32_t rcSpill; \ + uint32_t u32OldRet; \ + uint32_t u32NewSpill; \ + __asm__ __volatile__(".Ltry_again_" #name "_%=:\n\t" \ + RTASM_ARM_##barrier_type /* before lable? */ \ + "ldaxr %w[uOld], %[pMem]\n\t" \ + modify64 \ + "stlxr %w[rc], %w[uNew], %[pMem]\n\t" \ + "cbnz %w[rc], .Ltry_again_" #name "_%=\n\t" \ + : [pMem] "+Q" (*a_pu32Mem) \ + , [uOld] "=&r" (u32OldRet) \ + , [uNew] "=&r" (u32NewSpill) \ + , [rc] "=&r" (rcSpill) \ + : in_reg \ + : "cc") +# define RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_64(name, a_pu64Mem, barrier_type, modify64, modify32, in_reg) \ + uint32_t rcSpill; \ + uint64_t u64NewRet; \ + __asm__ __volatile__(".Ltry_again_" #name "_%=:\n\t" \ + RTASM_ARM_##barrier_type /* before lable? */ \ + "ldaxr %[uNew], %[pMem]\n\t" \ + modify64 \ + "stlxr %w[rc], %[uNew], %[pMem]\n\t" \ + "cbnz %w[rc], .Ltry_again_" #name "_%=\n\t" \ + : [pMem] "+Q" (*a_pu64Mem) \ + , [uNew] "=&r" (u64NewRet) \ + , [rc] "=&r" (rcSpill) \ + : in_reg \ + : "cc") +# define RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_64(name, a_pu64Mem, barrier_type, modify64, modify32, in_reg) \ + uint32_t rcSpill; \ + uint64_t u64OldRet; \ + uint64_t u64NewSpill; \ + __asm__ __volatile__(".Ltry_again_" #name "_%=:\n\t" \ + RTASM_ARM_##barrier_type /* before lable? */ \ + "ldaxr %[uOld], %[pMem]\n\t" \ + modify64 \ + "stlxr %w[rc], %[uNew], %[pMem]\n\t" \ + "cbnz %w[rc], .Ltry_again_" #name "_%=\n\t" \ + : [pMem] "+Q" (*a_pu64Mem) \ + , [uOld] "=&r" (u64OldRet) \ + , [uNew] "=&r" (u64NewSpill) \ + , [rc] "=&r" (rcSpill) \ + : in_reg \ + : "cc") + +# else /* RT_ARCH_ARM32 */ +# define RTASM_ARM_PICK_6432(expr64, expr32) expr32 +# if RT_ARCH_ARM32 >= 7 +# warning armv7 +# define RTASM_ARM_NO_BARRIER_IN_REG +# define RTASM_ARM_NO_BARRIER_COMMA_IN_REG +# define RTASM_ARM_DSB_SY "dsb sy\n\t" +# define RTASM_ARM_DSB_SY_IN_REG "X" (0xfade) +# define RTASM_ARM_DMB_SY "dmb sy\n\t" +# define RTASM_ARM_DMB_SY_IN_REG "X" (0xfade) +# define RTASM_ARM_DMB_ST "dmb st\n\t" +# define RTASM_ARM_DMB_ST_IN_REG "X" (0xfade) +# define RTASM_ARM_DMB_LD "dmb ld\n\t" +# define RTASM_ARM_DMB_LD_IN_REG "X" (0xfade) + +# elif RT_ARCH_ARM32 >= 6 +# warning armv6 +# define RTASM_ARM_DSB_SY "mcr p15, 0, %[uZero], c7, c10, 4\n\t" +# define RTASM_ARM_DSB_SY_IN_REG [uZero] "r" (0) +# define RTASM_ARM_DMB_SY "mcr p15, 0, %[uZero], c7, c10, 5\n\t" +# define RTASM_ARM_DMB_SY_IN_REG [uZero] "r" (0) +# define RTASM_ARM_DMB_ST RTASM_ARM_DMB_SY +# define RTASM_ARM_DMB_ST_IN_REG RTASM_ARM_DMB_SY_IN_REG +# define RTASM_ARM_DMB_LD RTASM_ARM_DMB_SY +# define RTASM_ARM_DMB_LD_IN_REG RTASM_ARM_DMB_SY_IN_REG +# elif RT_ARCH_ARM32 >= 4 +# warning armv5 or older +# define RTASM_ARM_DSB_SY "mcr p15, 0, %[uZero], c7, c10, 4\n\t" +# define RTASM_ARM_DSB_SY_IN_REG [uZero] "r" (0) +# define RTASM_ARM_DMB_SY RTASM_ARM_DSB_SY +# define RTASM_ARM_DMB_SY_IN_REG RTASM_ARM_DSB_SY_IN_REG +# define RTASM_ARM_DMB_ST RTASM_ARM_DSB_SY +# define RTASM_ARM_DMB_ST_IN_REG RTASM_ARM_DSB_SY_IN_REG +# define RTASM_ARM_DMB_LD RTASM_ARM_DSB_SY +# define RTASM_ARM_DMB_LD_IN_REG RTASM_ARM_DSB_SY_IN_REG +# else +# error "huh? Odd RT_ARCH_ARM32 value!" +# endif +# define RTASM_ARM_DSB_SY_COMMA_IN_REG , RTASM_ARM_DSB_SY_IN_REG +# define RTASM_ARM_DMB_SY_COMMA_IN_REG , RTASM_ARM_DMB_SY_IN_REG +# define RTASM_ARM_DMB_ST_COMMA_IN_REG , RTASM_ARM_DMB_ST_IN_REG +# define RTASM_ARM_DMB_LD_COMMA_IN_REG , RTASM_ARM_DMB_LD_IN_REG +# define RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(name, a_pu32Mem, barrier_type, modify64, modify32, in_reg) \ + uint32_t rcSpill; \ + uint32_t u32NewRet; \ + __asm__ __volatile__(".Ltry_again_" #name "_%=:\n\t" \ + RT_CONCAT(RTASM_ARM_,barrier_type) /* before lable? */ \ + "ldrex %[uNew], %[pMem]\n\t" \ + modify32 \ + "strex %[rc], %[uNew], %[pMem]\n\t" \ + "cmp %[rc], #0\n\t" \ + "bne .Ltry_again_" #name "_%=\n\t" \ + : [pMem] "+m" (*a_pu32Mem) \ + , [uNew] "=&r" (u32NewRet) \ + , [rc] "=&r" (rcSpill) \ + : RT_CONCAT3(RTASM_ARM_,barrier_type,_IN_REG) \ + , in_reg \ + : "cc") +# define RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(name, a_pu32Mem, barrier_type, modify64, modify32, in_reg) \ + uint32_t rcSpill; \ + uint32_t u32OldRet; \ + uint32_t u32NewSpill; \ + __asm__ __volatile__(".Ltry_again_" #name "_%=:\n\t" \ + RT_CONCAT(RTASM_ARM_,barrier_type) /* before lable? */ \ + "ldrex %[uOld], %[pMem]\n\t" \ + modify32 \ + "strex %[rc], %[uNew], %[pMem]\n\t" \ + "cmp %[rc], #0\n\t" \ + "bne .Ltry_again_" #name "_%=\n\t" \ + : [pMem] "+m" (*a_pu32Mem) \ + , [uOld] "=&r" (u32OldRet) \ + , [uNew] "=&r" (u32NewSpill) \ + , [rc] "=&r" (rcSpill) \ + : RT_CONCAT3(RTASM_ARM_,barrier_type,_IN_REG) \ + , in_reg \ + : "cc") +# define RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_64(name, a_pu64Mem, barrier_type, modify64, modify32, in_reg) \ + uint32_t rcSpill; \ + uint64_t u64NewRet; \ + __asm__ __volatile__(".Ltry_again_" #name "_%=:\n\t" \ + RT_CONCAT(RTASM_ARM_,barrier_type) /* before lable? */ \ + "ldrexd %[uNew], %H[uNew], %[pMem]\n\t" \ + modify32 \ + "strexd %[rc], %[uNew], %H[uNew], %[pMem]\n\t" \ + "cmp %[rc], #0\n\t" \ + "bne .Ltry_again_" #name "_%=\n\t" \ + : [pMem] "+m" (*a_pu64Mem), \ + [uNew] "=&r" (u64NewRet), \ + [rc] "=&r" (rcSpill) \ + : RT_CONCAT3(RTASM_ARM_,barrier_type,_IN_REG) \ + , in_reg \ + : "cc") +# define RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_64(name, a_pu64Mem, barrier_type, modify64, modify32, in_reg) \ + uint32_t rcSpill; \ + uint64_t u64OldRet; \ + uint64_t u64NewSpill; \ + __asm__ __volatile__(".Ltry_again_" #name "_%=:\n\t" \ + RT_CONCAT(RTASM_ARM_,barrier_type) /* before lable? */ \ + "ldrexd %[uOld], %H[uOld], %[pMem]\n\t" \ + modify32 \ + "strexd %[rc], %[uNew], %H[uNew], %[pMem]\n\t" \ + "cmp %[rc], #0\n\t" \ + "bne .Ltry_again_" #name "_%=\n\t" \ + : [pMem] "+m" (*a_pu64Mem), \ + [uOld] "=&r" (u64OldRet), \ + [uNew] "=&r" (u64NewSpill), \ + [rc] "=&r" (rcSpill) \ + : RT_CONCAT3(RTASM_ARM_,barrier_type,_IN_REG) \ + , in_reg \ + : "cc") +# endif /* RT_ARCH_ARM32 */ +#endif + + +/** @def ASMReturnAddress + * Gets the return address of the current (or calling if you like) function or method. + */ +#ifdef _MSC_VER +# ifdef __cplusplus +extern "C" +# endif +void * _ReturnAddress(void); +# pragma intrinsic(_ReturnAddress) +# define ASMReturnAddress() _ReturnAddress() +#elif defined(__GNUC__) || defined(DOXYGEN_RUNNING) +# define ASMReturnAddress() __builtin_return_address(0) +#elif defined(__WATCOMC__) +# define ASMReturnAddress() Watcom_does_not_appear_to_have_intrinsic_return_address_function() +#else +# error "Unsupported compiler." +#endif + + +/** + * Compiler memory barrier. + * + * Ensure that the compiler does not use any cached (register/tmp stack) memory + * values or any outstanding writes when returning from this function. + * + * This function must be used if non-volatile data is modified by a + * device or the VMM. Typical cases are port access, MMIO access, + * trapping instruction, etc. + */ +#if RT_INLINE_ASM_GNU_STYLE +# define ASMCompilerBarrier() do { __asm__ __volatile__("" : : : "memory"); } while (0) +#elif RT_INLINE_ASM_USES_INTRIN +# define ASMCompilerBarrier() do { _ReadWriteBarrier(); } while (0) +#elif defined(__WATCOMC__) +void ASMCompilerBarrier(void); +#else /* 2003 should have _ReadWriteBarrier() but I guess we're at 2002 level then... */ +DECLINLINE(void) ASMCompilerBarrier(void) RT_NOTHROW_DEF +{ + __asm + { + } +} +#endif + + +/** @def ASMBreakpoint + * Debugger Breakpoint. + * @deprecated Use RT_BREAKPOINT instead. + * @internal + */ +#define ASMBreakpoint() RT_BREAKPOINT() + + +/** + * Spinloop hint for platforms that have these, empty function on the other + * platforms. + * + * x86 & AMD64: The PAUSE variant of NOP for helping hyperthreaded CPUs detecting + * spin locks. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMNopPause(void) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMNopPause(void) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__(".byte 0xf3,0x90\n\t"); +# else + __asm { + _emit 0f3h + _emit 090h + } +# endif + +# elif defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) + __asm__ __volatile__("yield\n\t"); /* ARMv6K+ */ + +# else + /* dummy */ +# endif +} +#endif + + +/** + * Atomically Exchange an unsigned 8-bit value, ordered. + * + * @returns Current *pu8 value + * @param pu8 Pointer to the 8-bit variable to update. + * @param u8 The 8-bit value to assign to *pu8. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(uint8_t) ASMAtomicXchgU8(volatile uint8_t RT_FAR *pu8, uint8_t u8) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint8_t) ASMAtomicXchgU8(volatile uint8_t RT_FAR *pu8, uint8_t u8) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("xchgb %0, %1\n\t" + : "=m" (*pu8) + , "=q" (u8) /* =r - busted on g++ (GCC) 3.4.4 20050721 (Red Hat 3.4.4-2) */ + : "1" (u8) + , "m" (*pu8)); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [pu8] + mov al, [u8] + xchg [rdx], al + mov [u8], al +# else + mov edx, [pu8] + mov al, [u8] + xchg [edx], al + mov [u8], al +# endif + } +# endif + return u8; + +# elif defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) + uint32_t uOld; + uint32_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicXchgU8_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxrb %w[uOld], %[pMem]\n\t" + "stlxrb %w[rc], %w[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicXchgU8_%=\n\t" +# else + "ldrexb %[uOld], %[pMem]\n\t" /* ARMv6+ */ + "strexb %[rc], %[uNew], %[pMem]\n\t" + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicXchgU8_%=\n\t" +# endif + : [pMem] "+Q" (*pu8) + , [uOld] "=&r" (uOld) + , [rc] "=&r" (rcSpill) + : [uNew] "r" ((uint32_t)u8) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + return (uint8_t)uOld; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Exchange a signed 8-bit value, ordered. + * + * @returns Current *pu8 value + * @param pi8 Pointer to the 8-bit variable to update. + * @param i8 The 8-bit value to assign to *pi8. + */ +DECLINLINE(int8_t) ASMAtomicXchgS8(volatile int8_t RT_FAR *pi8, int8_t i8) RT_NOTHROW_DEF +{ + return (int8_t)ASMAtomicXchgU8((volatile uint8_t RT_FAR *)pi8, (uint8_t)i8); +} + + +/** + * Atomically Exchange a bool value, ordered. + * + * @returns Current *pf value + * @param pf Pointer to the 8-bit variable to update. + * @param f The 8-bit value to assign to *pi8. + */ +DECLINLINE(bool) ASMAtomicXchgBool(volatile bool RT_FAR *pf, bool f) RT_NOTHROW_DEF +{ +#ifdef _MSC_VER + return !!ASMAtomicXchgU8((volatile uint8_t RT_FAR *)pf, (uint8_t)f); +#else + return (bool)ASMAtomicXchgU8((volatile uint8_t RT_FAR *)pf, (uint8_t)f); +#endif +} + + +/** + * Atomically Exchange an unsigned 16-bit value, ordered. + * + * @returns Current *pu16 value + * @param pu16 Pointer to the 16-bit variable to update. + * @param u16 The 16-bit value to assign to *pu16. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(uint16_t) ASMAtomicXchgU16(volatile uint16_t RT_FAR *pu16, uint16_t u16) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint16_t) ASMAtomicXchgU16(volatile uint16_t RT_FAR *pu16, uint16_t u16) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("xchgw %0, %1\n\t" + : "=m" (*pu16) + , "=r" (u16) + : "1" (u16) + , "m" (*pu16)); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [pu16] + mov ax, [u16] + xchg [rdx], ax + mov [u16], ax +# else + mov edx, [pu16] + mov ax, [u16] + xchg [edx], ax + mov [u16], ax +# endif + } +# endif + return u16; + +# elif defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) + uint32_t uOld; + uint32_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicXchgU16_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxrh %w[uOld], %[pMem]\n\t" + "stlxrh %w[rc], %w[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicXchgU16_%=\n\t" +# else + "ldrexh %[uOld], %[pMem]\n\t" /* ARMv6+ */ + "strexh %[rc], %[uNew], %[pMem]\n\t" + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicXchgU16_%=\n\t" +# endif + : [pMem] "+Q" (*pu16) + , [uOld] "=&r" (uOld) + , [rc] "=&r" (rcSpill) + : [uNew] "r" ((uint32_t)u16) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + return (uint16_t)uOld; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Exchange a signed 16-bit value, ordered. + * + * @returns Current *pu16 value + * @param pi16 Pointer to the 16-bit variable to update. + * @param i16 The 16-bit value to assign to *pi16. + */ +DECLINLINE(int16_t) ASMAtomicXchgS16(volatile int16_t RT_FAR *pi16, int16_t i16) RT_NOTHROW_DEF +{ + return (int16_t)ASMAtomicXchgU16((volatile uint16_t RT_FAR *)pi16, (uint16_t)i16); +} + + +/** + * Atomically Exchange an unsigned 32-bit value, ordered. + * + * @returns Current *pu32 value + * @param pu32 Pointer to the 32-bit variable to update. + * @param u32 The 32-bit value to assign to *pu32. + * + * @remarks Does not work on 286 and earlier. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMAtomicXchgU32(volatile uint32_t RT_FAR *pu32, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMAtomicXchgU32(volatile uint32_t RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("xchgl %0, %1\n\t" + : "=m" (*pu32) /** @todo r=bird: +m rather than =m here? */ + , "=r" (u32) + : "1" (u32) + , "m" (*pu32)); + +# elif RT_INLINE_ASM_USES_INTRIN + u32 = _InterlockedExchange((long RT_FAR *)pu32, u32); + +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + mov eax, u32 + xchg [rdx], eax + mov [u32], eax +# else + mov edx, [pu32] + mov eax, u32 + xchg [edx], eax + mov [u32], eax +# endif + } +# endif + return u32; + +# elif defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) + uint32_t uOld; + uint32_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicXchgU32_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxr %w[uOld], %[pMem]\n\t" + "stlxr %w[rc], %w[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicXchgU32_%=\n\t" +# else + "ldrex %[uOld], %[pMem]\n\t" /* ARMv6+ */ + "strex %[rc], %[uNew], %[pMem]\n\t" + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicXchgU32_%=\n\t" +# endif + : [pMem] "+Q" (*pu32) + , [uOld] "=&r" (uOld) + , [rc] "=&r" (rcSpill) + : [uNew] "r" (u32) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + return uOld; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Exchange a signed 32-bit value, ordered. + * + * @returns Current *pu32 value + * @param pi32 Pointer to the 32-bit variable to update. + * @param i32 The 32-bit value to assign to *pi32. + */ +DECLINLINE(int32_t) ASMAtomicXchgS32(volatile int32_t RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + return (int32_t)ASMAtomicXchgU32((volatile uint32_t RT_FAR *)pi32, (uint32_t)i32); +} + + +/** + * Atomically Exchange an unsigned 64-bit value, ordered. + * + * @returns Current *pu64 value + * @param pu64 Pointer to the 64-bit variable to update. + * @param u64 The 64-bit value to assign to *pu64. + * + * @remarks Works on 32-bit x86 CPUs starting with Pentium. + */ +#if (RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN) \ + || RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC +RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMAtomicXchgU64(volatile uint64_t RT_FAR *pu64, uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint64_t) ASMAtomicXchgU64(volatile uint64_t RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) +# if RT_INLINE_ASM_USES_INTRIN + return _InterlockedExchange64((__int64 *)pu64, u64); + +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("xchgq %0, %1\n\t" + : "=m" (*pu64) + , "=r" (u64) + : "1" (u64) + , "m" (*pu64)); + return u64; +# else + __asm + { + mov rdx, [pu64] + mov rax, [u64] + xchg [rdx], rax + mov [u64], rax + } + return u64; +# endif + +# elif defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE +# if defined(PIC) || defined(__PIC__) + uint32_t u32EBX = (uint32_t)u64; + __asm__ __volatile__(/*"xchgl %%esi, %5\n\t"*/ + "xchgl %%ebx, %3\n\t" + "1:\n\t" + "lock; cmpxchg8b (%5)\n\t" + "jnz 1b\n\t" + "movl %3, %%ebx\n\t" + /*"xchgl %%esi, %5\n\t"*/ + : "=A" (u64) + , "=m" (*pu64) + : "0" (*pu64) + , "m" ( u32EBX ) + , "c" ( (uint32_t)(u64 >> 32) ) + , "S" (pu64) + : "cc"); +# else /* !PIC */ + __asm__ __volatile__("1:\n\t" + "lock; cmpxchg8b %1\n\t" + "jnz 1b\n\t" + : "=A" (u64) + , "=m" (*pu64) + : "0" (*pu64) + , "b" ( (uint32_t)u64 ) + , "c" ( (uint32_t)(u64 >> 32) ) + : "cc"); +# endif +# else + __asm + { + mov ebx, dword ptr [u64] + mov ecx, dword ptr [u64 + 4] + mov edi, pu64 + mov eax, dword ptr [edi] + mov edx, dword ptr [edi + 4] + retry: + lock cmpxchg8b [edi] + jnz retry + mov dword ptr [u64], eax + mov dword ptr [u64 + 4], edx + } +# endif + return u64; + +# elif defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) + uint32_t rcSpill; + uint64_t uOld; + __asm__ __volatile__(".Ltry_again_ASMAtomicXchgU64_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxr %[uOld], %[pMem]\n\t" + "stlxr %w[rc], %[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicXchgU64_%=\n\t" +# else + "ldrexd %[uOld], %H[uOld], %[pMem]\n\t" /* ARMv6+ */ + "strexd %[rc], %[uNew], %H[uNew], %[pMem]\n\t" + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicXchgU64_%=\n\t" +# endif + : [pMem] "+Q" (*pu64) + , [uOld] "=&r" (uOld) + , [rc] "=&r" (rcSpill) + : [uNew] "r" (u64) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + return uOld; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Exchange an signed 64-bit value, ordered. + * + * @returns Current *pi64 value + * @param pi64 Pointer to the 64-bit variable to update. + * @param i64 The 64-bit value to assign to *pi64. + */ +DECLINLINE(int64_t) ASMAtomicXchgS64(volatile int64_t RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + return (int64_t)ASMAtomicXchgU64((volatile uint64_t RT_FAR *)pi64, (uint64_t)i64); +} + + +/** + * Atomically Exchange a size_t value, ordered. + * + * @returns Current *ppv value + * @param puDst Pointer to the size_t variable to update. + * @param uNew The new value to assign to *puDst. + */ +DECLINLINE(size_t) ASMAtomicXchgZ(size_t volatile RT_FAR *puDst, const size_t uNew) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 16 + AssertCompile(sizeof(size_t) == 2); + return ASMAtomicXchgU16((volatile uint16_t RT_FAR *)puDst, uNew); +#elif ARCH_BITS == 32 + return ASMAtomicXchgU32((volatile uint32_t RT_FAR *)puDst, uNew); +#elif ARCH_BITS == 64 + return ASMAtomicXchgU64((volatile uint64_t RT_FAR *)puDst, uNew); +#else +# error "ARCH_BITS is bogus" +#endif +} + + +/** + * Atomically Exchange a pointer value, ordered. + * + * @returns Current *ppv value + * @param ppv Pointer to the pointer variable to update. + * @param pv The pointer value to assign to *ppv. + */ +DECLINLINE(void RT_FAR *) ASMAtomicXchgPtr(void RT_FAR * volatile RT_FAR *ppv, const void RT_FAR *pv) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 32 || ARCH_BITS == 16 + return (void RT_FAR *)ASMAtomicXchgU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppv, (uint32_t)pv); +#elif ARCH_BITS == 64 + return (void RT_FAR *)ASMAtomicXchgU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppv, (uint64_t)pv); +#else +# error "ARCH_BITS is bogus" +#endif +} + + +/** + * Convenience macro for avoiding the annoying casting with ASMAtomicXchgPtr. + * + * @returns Current *pv value + * @param ppv Pointer to the pointer variable to update. + * @param pv The pointer value to assign to *ppv. + * @param Type The type of *ppv, sans volatile. + */ +#ifdef __GNUC__ /* 8.2.0 requires -Wno-ignored-qualifiers */ +# define ASMAtomicXchgPtrT(ppv, pv, Type) \ + __extension__ \ + ({\ + __typeof__(*(ppv)) volatile * const ppvTypeChecked = (ppv); \ + Type const pvTypeChecked = (pv); \ + Type pvTypeCheckedRet = (__typeof__(*(ppv))) ASMAtomicXchgPtr((void * volatile *)ppvTypeChecked, (void *)pvTypeChecked); \ + pvTypeCheckedRet; \ + }) +#else +# define ASMAtomicXchgPtrT(ppv, pv, Type) \ + (Type)ASMAtomicXchgPtr((void RT_FAR * volatile RT_FAR *)(ppv), (void RT_FAR *)(pv)) +#endif + + +/** + * Atomically Exchange a raw-mode context pointer value, ordered. + * + * @returns Current *ppv value + * @param ppvRC Pointer to the pointer variable to update. + * @param pvRC The pointer value to assign to *ppv. + */ +DECLINLINE(RTRCPTR) ASMAtomicXchgRCPtr(RTRCPTR volatile RT_FAR *ppvRC, RTRCPTR pvRC) RT_NOTHROW_DEF +{ + return (RTRCPTR)ASMAtomicXchgU32((uint32_t volatile RT_FAR *)(void RT_FAR *)ppvRC, (uint32_t)pvRC); +} + + +/** + * Atomically Exchange a ring-0 pointer value, ordered. + * + * @returns Current *ppv value + * @param ppvR0 Pointer to the pointer variable to update. + * @param pvR0 The pointer value to assign to *ppv. + */ +DECLINLINE(RTR0PTR) ASMAtomicXchgR0Ptr(RTR0PTR volatile RT_FAR *ppvR0, RTR0PTR pvR0) RT_NOTHROW_DEF +{ +#if R0_ARCH_BITS == 32 || ARCH_BITS == 16 + return (RTR0PTR)ASMAtomicXchgU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppvR0, (uint32_t)pvR0); +#elif R0_ARCH_BITS == 64 + return (RTR0PTR)ASMAtomicXchgU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppvR0, (uint64_t)pvR0); +#else +# error "R0_ARCH_BITS is bogus" +#endif +} + + +/** + * Atomically Exchange a ring-3 pointer value, ordered. + * + * @returns Current *ppv value + * @param ppvR3 Pointer to the pointer variable to update. + * @param pvR3 The pointer value to assign to *ppv. + */ +DECLINLINE(RTR3PTR) ASMAtomicXchgR3Ptr(RTR3PTR volatile RT_FAR *ppvR3, RTR3PTR pvR3) RT_NOTHROW_DEF +{ +#if R3_ARCH_BITS == 32 || ARCH_BITS == 16 + return (RTR3PTR)ASMAtomicXchgU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppvR3, (uint32_t)pvR3); +#elif R3_ARCH_BITS == 64 + return (RTR3PTR)ASMAtomicXchgU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppvR3, (uint64_t)pvR3); +#else +# error "R3_ARCH_BITS is bogus" +#endif +} + + +/** @def ASMAtomicXchgHandle + * Atomically Exchange a typical IPRT handle value, ordered. + * + * @param ph Pointer to the value to update. + * @param hNew The new value to assigned to *pu. + * @param phRes Where to store the current *ph value. + * + * @remarks This doesn't currently work for all handles (like RTFILE). + */ +#if HC_ARCH_BITS == 32 || ARCH_BITS == 16 +# define ASMAtomicXchgHandle(ph, hNew, phRes) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \ + AssertCompile(sizeof(*(phRes)) == sizeof(uint32_t)); \ + *(uint32_t RT_FAR *)(phRes) = ASMAtomicXchgU32((uint32_t volatile RT_FAR *)(ph), (const uint32_t)(hNew)); \ + } while (0) +#elif HC_ARCH_BITS == 64 +# define ASMAtomicXchgHandle(ph, hNew, phRes) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint64_t)); \ + AssertCompile(sizeof(*(phRes)) == sizeof(uint64_t)); \ + *(uint64_t RT_FAR *)(phRes) = ASMAtomicXchgU64((uint64_t volatile RT_FAR *)(ph), (const uint64_t)(hNew)); \ + } while (0) +#else +# error HC_ARCH_BITS +#endif + + +/** + * Atomically Exchange a value which size might differ + * between platforms or compilers, ordered. + * + * @param pu Pointer to the variable to update. + * @param uNew The value to assign to *pu. + * @todo This is busted as its missing the result argument. + */ +#define ASMAtomicXchgSize(pu, uNew) \ + do { \ + switch (sizeof(*(pu))) { \ + case 1: ASMAtomicXchgU8( (volatile uint8_t RT_FAR *)(void RT_FAR *)(pu), (uint8_t)(uNew)); break; \ + case 2: ASMAtomicXchgU16((volatile uint16_t RT_FAR *)(void RT_FAR *)(pu), (uint16_t)(uNew)); break; \ + case 4: ASMAtomicXchgU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu), (uint32_t)(uNew)); break; \ + case 8: ASMAtomicXchgU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu), (uint64_t)(uNew)); break; \ + default: AssertMsgFailed(("ASMAtomicXchgSize: size %d is not supported\n", sizeof(*(pu)))); \ + } \ + } while (0) + +/** + * Atomically Exchange a value which size might differ + * between platforms or compilers, ordered. + * + * @param pu Pointer to the variable to update. + * @param uNew The value to assign to *pu. + * @param puRes Where to store the current *pu value. + */ +#define ASMAtomicXchgSizeCorrect(pu, uNew, puRes) \ + do { \ + switch (sizeof(*(pu))) { \ + case 1: *(uint8_t RT_FAR *)(puRes) = ASMAtomicXchgU8( (volatile uint8_t RT_FAR *)(void RT_FAR *)(pu), (uint8_t)(uNew)); break; \ + case 2: *(uint16_t RT_FAR *)(puRes) = ASMAtomicXchgU16((volatile uint16_t RT_FAR *)(void RT_FAR *)(pu), (uint16_t)(uNew)); break; \ + case 4: *(uint32_t RT_FAR *)(puRes) = ASMAtomicXchgU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu), (uint32_t)(uNew)); break; \ + case 8: *(uint64_t RT_FAR *)(puRes) = ASMAtomicXchgU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu), (uint64_t)(uNew)); break; \ + default: AssertMsgFailed(("ASMAtomicXchgSize: size %d is not supported\n", sizeof(*(pu)))); \ + } \ + } while (0) + + + +/** + * Atomically Compare and Exchange an unsigned 8-bit value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pu8 Pointer to the value to update. + * @param u8New The new value to assigned to *pu8. + * @param u8Old The old value to *pu8 compare with. + * + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWriteU8 + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM || !RT_INLINE_ASM_GNU_STYLE +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicCmpXchgU8(volatile uint8_t RT_FAR *pu8, const uint8_t u8New, const uint8_t u8Old) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicCmpXchgU8(volatile uint8_t RT_FAR *pu8, const uint8_t u8New, uint8_t u8Old) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) + uint8_t u8Ret; + __asm__ __volatile__("lock; cmpxchgb %3, %0\n\t" + "setz %1\n\t" + : "=m" (*pu8) + , "=qm" (u8Ret) + , "=a" (u8Old) + : "q" (u8New) + , "2" (u8Old) + , "m" (*pu8) + : "cc"); + return (bool)u8Ret; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + union { uint32_t u; bool f; } fXchg; + uint32_t u32Spill; + uint32_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicCmpXchgU8_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxrb %w[uOld], %[pMem]\n\t" + "cmp %w[uOld], %w[uCmp]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "stlxrb %w[rc], %w[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicCmpXchgU8_%=\n\t" + "mov %w[fXchg], #1\n\t" +# else + "ldrexb %[uOld], %[pMem]\n\t" + "teq %[uOld], %[uCmp]\n\t" + "strexbeq %[rc], %[uNew], %[pMem]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicCmpXchgU8_%=\n\t" + "mov %[fXchg], #1\n\t" +# endif + "1:\n\t" + : [pMem] "+Q" (*pu8) + , [uOld] "=&r" (u32Spill) + , [rc] "=&r" (rcSpill) + , [fXchg] "=&r" (fXchg.u) + : [uCmp] "r" ((uint32_t)u8Old) + , [uNew] "r" ((uint32_t)u8New) + , "[fXchg]" (0) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + return fXchg.f; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Compare and Exchange a signed 8-bit value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pi8 Pointer to the value to update. + * @param i8New The new value to assigned to *pi8. + * @param i8Old The old value to *pi8 compare with. + * + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWriteS8 + */ +DECLINLINE(bool) ASMAtomicCmpXchgS8(volatile int8_t RT_FAR *pi8, const int8_t i8New, const int8_t i8Old) RT_NOTHROW_DEF +{ + return ASMAtomicCmpXchgU8((volatile uint8_t RT_FAR *)pi8, (uint8_t)i8New, (uint8_t)i8Old); +} + + +/** + * Atomically Compare and Exchange a bool value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pf Pointer to the value to update. + * @param fNew The new value to assigned to *pf. + * @param fOld The old value to *pf compare with. + * + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWriteBool + */ +DECLINLINE(bool) ASMAtomicCmpXchgBool(volatile bool RT_FAR *pf, const bool fNew, const bool fOld) RT_NOTHROW_DEF +{ + return ASMAtomicCmpXchgU8((volatile uint8_t RT_FAR *)pf, (uint8_t)fNew, (uint8_t)fOld); +} + + +/** + * Atomically Compare and Exchange an unsigned 32-bit value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pu32 Pointer to the value to update. + * @param u32New The new value to assigned to *pu32. + * @param u32Old The old value to *pu32 compare with. + * + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWriteU32 + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicCmpXchgU32(volatile uint32_t RT_FAR *pu32, const uint32_t u32New, const uint32_t u32Old) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicCmpXchgU32(volatile uint32_t RT_FAR *pu32, const uint32_t u32New, uint32_t u32Old) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + uint8_t u8Ret; + __asm__ __volatile__("lock; cmpxchgl %3, %0\n\t" + "setz %1\n\t" + : "=m" (*pu32) + , "=qm" (u8Ret) + , "=a" (u32Old) + : "r" (u32New) + , "2" (u32Old) + , "m" (*pu32) + : "cc"); + return (bool)u8Ret; + +# elif RT_INLINE_ASM_USES_INTRIN + return (uint32_t)_InterlockedCompareExchange((long RT_FAR *)pu32, u32New, u32Old) == u32Old; + +# else + uint32_t u32Ret; + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] +# else + mov edx, [pu32] +# endif + mov eax, [u32Old] + mov ecx, [u32New] +# ifdef RT_ARCH_AMD64 + lock cmpxchg [rdx], ecx +# else + lock cmpxchg [edx], ecx +# endif + setz al + movzx eax, al + mov [u32Ret], eax + } + return !!u32Ret; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + union { uint32_t u; bool f; } fXchg; + uint32_t u32Spill; + uint32_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicCmpXchgU32_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxr %w[uOld], %[pMem]\n\t" + "cmp %w[uOld], %w[uCmp]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "stlxr %w[rc], %w[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicCmpXchgU32_%=\n\t" + "mov %w[fXchg], #1\n\t" +# else + "ldrex %[uOld], %[pMem]\n\t" + "teq %[uOld], %[uCmp]\n\t" + "strexeq %[rc], %[uNew], %[pMem]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicCmpXchgU32_%=\n\t" + "mov %[fXchg], #1\n\t" +# endif + "1:\n\t" + : [pMem] "+Q" (*pu32) + , [uOld] "=&r" (u32Spill) + , [rc] "=&r" (rcSpill) + , [fXchg] "=&r" (fXchg.u) + : [uCmp] "r" (u32Old) + , [uNew] "r" (u32New) + , "[fXchg]" (0) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + return fXchg.f; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Compare and Exchange a signed 32-bit value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pi32 Pointer to the value to update. + * @param i32New The new value to assigned to *pi32. + * @param i32Old The old value to *pi32 compare with. + * + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWriteS32 + */ +DECLINLINE(bool) ASMAtomicCmpXchgS32(volatile int32_t RT_FAR *pi32, const int32_t i32New, const int32_t i32Old) RT_NOTHROW_DEF +{ + return ASMAtomicCmpXchgU32((volatile uint32_t RT_FAR *)pi32, (uint32_t)i32New, (uint32_t)i32Old); +} + + +/** + * Atomically Compare and exchange an unsigned 64-bit value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pu64 Pointer to the 64-bit variable to update. + * @param u64New The 64-bit value to assign to *pu64. + * @param u64Old The value to compare with. + * + * @remarks x86: Requires a Pentium or later. + * @todo Rename ASMAtomicCmpWriteU64 + */ +#if (RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN) \ + || RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicCmpXchgU64(volatile uint64_t RT_FAR *pu64, const uint64_t u64New, const uint64_t u64Old) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicCmpXchgU64(volatile uint64_t RT_FAR *pu64, uint64_t u64New, uint64_t u64Old) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + return (uint64_t)_InterlockedCompareExchange64((__int64 RT_FAR *)pu64, u64New, u64Old) == u64Old; + +# elif defined(RT_ARCH_AMD64) +# if RT_INLINE_ASM_GNU_STYLE + uint8_t u8Ret; + __asm__ __volatile__("lock; cmpxchgq %3, %0\n\t" + "setz %1\n\t" + : "=m" (*pu64) + , "=qm" (u8Ret) + , "=a" (u64Old) + : "r" (u64New) + , "2" (u64Old) + , "m" (*pu64) + : "cc"); + return (bool)u8Ret; +# else + bool fRet; + __asm + { + mov rdx, [pu32] + mov rax, [u64Old] + mov rcx, [u64New] + lock cmpxchg [rdx], rcx + setz al + mov [fRet], al + } + return fRet; +# endif + +# elif defined(RT_ARCH_X86) + uint32_t u32Ret; +# if RT_INLINE_ASM_GNU_STYLE +# if defined(PIC) || defined(__PIC__) + uint32_t u32EBX = (uint32_t)u64New; + uint32_t u32Spill; + __asm__ __volatile__("xchgl %%ebx, %4\n\t" + "lock; cmpxchg8b (%6)\n\t" + "setz %%al\n\t" + "movl %4, %%ebx\n\t" + "movzbl %%al, %%eax\n\t" + : "=a" (u32Ret) + , "=d" (u32Spill) +# if RT_GNUC_PREREQ(4, 3) + , "+m" (*pu64) +# else + , "=m" (*pu64) +# endif + : "A" (u64Old) + , "m" ( u32EBX ) + , "c" ( (uint32_t)(u64New >> 32) ) + , "S" (pu64) + : "cc"); +# else /* !PIC */ + uint32_t u32Spill; + __asm__ __volatile__("lock; cmpxchg8b %2\n\t" + "setz %%al\n\t" + "movzbl %%al, %%eax\n\t" + : "=a" (u32Ret) + , "=d" (u32Spill) + , "+m" (*pu64) + : "A" (u64Old) + , "b" ( (uint32_t)u64New ) + , "c" ( (uint32_t)(u64New >> 32) ) + : "cc"); +# endif + return (bool)u32Ret; +# else + __asm + { + mov ebx, dword ptr [u64New] + mov ecx, dword ptr [u64New + 4] + mov edi, [pu64] + mov eax, dword ptr [u64Old] + mov edx, dword ptr [u64Old + 4] + lock cmpxchg8b [edi] + setz al + movzx eax, al + mov dword ptr [u32Ret], eax + } + return !!u32Ret; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + union { uint32_t u; bool f; } fXchg; + uint64_t u64Spill; + uint32_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicCmpXchgU64_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxr %[uOld], %[pMem]\n\t" + "cmp %[uOld], %[uCmp]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "stlxr %w[rc], %[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicCmpXchgU64_%=\n\t" + "mov %w[fXchg], #1\n\t" +# else + "ldrexd %[uOld], %H[uOld], %[pMem]\n\t" + "teq %[uOld], %[uCmp]\n\t" + "teqeq %H[uOld], %H[uCmp]\n\t" + "strexdeq %[rc], %[uNew], %H[uNew], %[pMem]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicCmpXchgU64_%=\n\t" + "mov %[fXchg], #1\n\t" +# endif + "1:\n\t" + : [pMem] "+Q" (*pu64) + , [uOld] "=&r" (u64Spill) + , [rc] "=&r" (rcSpill) + , [fXchg] "=&r" (fXchg.u) + : [uCmp] "r" (u64Old) + , [uNew] "r" (u64New) + , "[fXchg]" (0) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + return fXchg.f; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Compare and exchange a signed 64-bit value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pi64 Pointer to the 64-bit variable to update. + * @param i64 The 64-bit value to assign to *pu64. + * @param i64Old The value to compare with. + * + * @remarks x86: Requires a Pentium or later. + * @todo Rename ASMAtomicCmpWriteS64 + */ +DECLINLINE(bool) ASMAtomicCmpXchgS64(volatile int64_t RT_FAR *pi64, const int64_t i64, const int64_t i64Old) RT_NOTHROW_DEF +{ + return ASMAtomicCmpXchgU64((volatile uint64_t RT_FAR *)pi64, (uint64_t)i64, (uint64_t)i64Old); +} + +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_ARM64) || defined(DOXYGEN_RUNNING) + +/** @def RTASM_HAVE_CMP_WRITE_U128 + * Indicates that we've got ASMAtomicCmpWriteU128(), ASMAtomicCmpWriteU128v2() + * and ASMAtomicCmpWriteExU128() available. */ +# define RTASM_HAVE_CMP_WRITE_U128 1 + + +/** + * Atomically compare and write an unsigned 128-bit value, ordered. + * + * @returns true if write was done. + * @returns false if write wasn't done. + * + * @param pu128 Pointer to the 128-bit variable to update. + * @param u64NewHi The high 64 bits of the value to assign to *pu128. + * @param u64NewLo The low 64 bits of the value to assign to *pu128. + * @param u64OldHi The high 64-bit of the value to compare with. + * @param u64OldLo The low 64-bit of the value to compare with. + * + * @remarks AMD64: Not present in the earliest CPUs, so check CPUID. + */ +# if (RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN) +DECLASM(bool) ASMAtomicCmpWriteU128v2(volatile uint128_t *pu128, const uint64_t u64NewHi, const uint64_t u64NewLo, + const uint64_t u64OldHi, const uint64_t u64OldLo) RT_NOTHROW_PROTO; +# else +DECLINLINE(bool) ASMAtomicCmpWriteU128v2(volatile uint128_t *pu128, const uint64_t u64NewHi, const uint64_t u64NewLo, + const uint64_t u64OldHi, const uint64_t u64OldLo) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + __int64 ai64Cmp[2]; + ai64Cmp[0] = u64OldLo; + ai64Cmp[1] = u64OldHi; + return _InterlockedCompareExchange128((__int64 volatile *)pu128, u64NewHi, u64NewLo, ai64Cmp) != 0; + +# elif (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64) + return __sync_bool_compare_and_swap(pu128, ((uint128_t)u64OldHi << 64) | u64OldLo, ((uint128_t)u64NewHi << 64) | u64NewLo); + +# elif defined(RT_ARCH_AMD64) +# if RT_INLINE_ASM_GNU_STYLE + uint64_t u64Ret; + uint64_t u64Spill; + __asm__ __volatile__("lock; cmpxchg16b %2\n\t" + "setz %%al\n\t" + "movzbl %%al, %%eax\n\t" + : "=a" (u64Ret) + , "=d" (u64Spill) + , "+m" (*pu128) + : "a" (u64OldLo) + , "d" (u64OldHi) + , "b" (u64NewLo) + , "c" (u64NewHi) + : "cc"); + + return (bool)u64Ret; +# else +# error "Port me" +# endif +# else +# error "Port me" +# endif +} +# endif + + +/** + * Atomically compare and write an unsigned 128-bit value, ordered. + * + * @returns true if write was done. + * @returns false if write wasn't done. + * + * @param pu128 Pointer to the 128-bit variable to update. + * @param u128New The 128-bit value to assign to *pu128. + * @param u128Old The value to compare with. + * + * @remarks AMD64: Not present in the earliest CPUs, so check CPUID. + */ +DECLINLINE(bool) ASMAtomicCmpWriteU128(volatile uint128_t *pu128, const uint128_t u128New, const uint128_t u128Old) RT_NOTHROW_DEF +{ +# ifdef RT_COMPILER_WITH_128BIT_INT_TYPES +# if (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64) + return __sync_bool_compare_and_swap(pu128, u128Old, u128New); +# else + return ASMAtomicCmpWriteU128v2(pu128, (uint64_t)(u128New >> 64), (uint64_t)u128New, + (uint64_t)(u128Old >> 64), (uint64_t)u128Old); +# endif +# else + return ASMAtomicCmpWriteU128v2(pu128, u128New.Hi, u128New.Lo, u128Old.Hi, u128Old.Lo); +# endif +} + + +/** + * RTUINT128U wrapper for ASMAtomicCmpWriteU128. + */ +DECLINLINE(bool) ASMAtomicCmpWriteU128U(volatile RTUINT128U *pu128, const RTUINT128U u128New, + const RTUINT128U u128Old) RT_NOTHROW_DEF +{ +# if (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64) + return ASMAtomicCmpWriteU128(&pu128->u, u128New.u, u128Old.u); +# else + return ASMAtomicCmpWriteU128v2(&pu128->u, u128New.s.Hi, u128New.s.Lo, u128Old.s.Hi, u128Old.s.Lo); +# endif +} + +#endif /* RT_ARCH_AMD64 || RT_ARCH_ARM64 */ + +/** + * Atomically Compare and Exchange a pointer value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param ppv Pointer to the value to update. + * @param pvNew The new value to assigned to *ppv. + * @param pvOld The old value to *ppv compare with. + * + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWritePtrVoid + */ +DECLINLINE(bool) ASMAtomicCmpXchgPtrVoid(void RT_FAR * volatile RT_FAR *ppv, const void RT_FAR *pvNew, const void RT_FAR *pvOld) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 32 || ARCH_BITS == 16 + return ASMAtomicCmpXchgU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppv, (uint32_t)pvNew, (uint32_t)pvOld); +#elif ARCH_BITS == 64 + return ASMAtomicCmpXchgU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppv, (uint64_t)pvNew, (uint64_t)pvOld); +#else +# error "ARCH_BITS is bogus" +#endif +} + + +/** + * Atomically Compare and Exchange a pointer value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param ppv Pointer to the value to update. + * @param pvNew The new value to assigned to *ppv. + * @param pvOld The old value to *ppv compare with. + * + * @remarks This is relatively type safe on GCC platforms. + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWritePtr + */ +#ifdef __GNUC__ +# define ASMAtomicCmpXchgPtr(ppv, pvNew, pvOld) \ + __extension__ \ + ({\ + __typeof__(*(ppv)) volatile * const ppvTypeChecked = (ppv); \ + __typeof__(*(ppv)) const pvNewTypeChecked = (pvNew); \ + __typeof__(*(ppv)) const pvOldTypeChecked = (pvOld); \ + bool fMacroRet = ASMAtomicCmpXchgPtrVoid((void * volatile *)ppvTypeChecked, \ + (void *)pvNewTypeChecked, (void *)pvOldTypeChecked); \ + fMacroRet; \ + }) +#else +# define ASMAtomicCmpXchgPtr(ppv, pvNew, pvOld) \ + ASMAtomicCmpXchgPtrVoid((void RT_FAR * volatile RT_FAR *)(ppv), (void RT_FAR *)(pvNew), (void RT_FAR *)(pvOld)) +#endif + + +/** @def ASMAtomicCmpXchgHandle + * Atomically Compare and Exchange a typical IPRT handle value, ordered. + * + * @param ph Pointer to the value to update. + * @param hNew The new value to assigned to *pu. + * @param hOld The old value to *pu compare with. + * @param fRc Where to store the result. + * + * @remarks This doesn't currently work for all handles (like RTFILE). + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWriteHandle + */ +#if HC_ARCH_BITS == 32 || ARCH_BITS == 16 +# define ASMAtomicCmpXchgHandle(ph, hNew, hOld, fRc) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \ + (fRc) = ASMAtomicCmpXchgU32((uint32_t volatile RT_FAR *)(ph), (const uint32_t)(hNew), (const uint32_t)(hOld)); \ + } while (0) +#elif HC_ARCH_BITS == 64 +# define ASMAtomicCmpXchgHandle(ph, hNew, hOld, fRc) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint64_t)); \ + (fRc) = ASMAtomicCmpXchgU64((uint64_t volatile RT_FAR *)(ph), (const uint64_t)(hNew), (const uint64_t)(hOld)); \ + } while (0) +#else +# error HC_ARCH_BITS +#endif + + +/** @def ASMAtomicCmpXchgSize + * Atomically Compare and Exchange a value which size might differ + * between platforms or compilers, ordered. + * + * @param pu Pointer to the value to update. + * @param uNew The new value to assigned to *pu. + * @param uOld The old value to *pu compare with. + * @param fRc Where to store the result. + * + * @remarks x86: Requires a 486 or later. + * @todo Rename ASMAtomicCmpWriteSize + */ +#define ASMAtomicCmpXchgSize(pu, uNew, uOld, fRc) \ + do { \ + switch (sizeof(*(pu))) { \ + case 4: (fRc) = ASMAtomicCmpXchgU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu), (uint32_t)(uNew), (uint32_t)(uOld)); \ + break; \ + case 8: (fRc) = ASMAtomicCmpXchgU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu), (uint64_t)(uNew), (uint64_t)(uOld)); \ + break; \ + default: AssertMsgFailed(("ASMAtomicCmpXchgSize: size %d is not supported\n", sizeof(*(pu)))); \ + (fRc) = false; \ + break; \ + } \ + } while (0) + + +/** + * Atomically Compare and Exchange an unsigned 8-bit value, additionally passes + * back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pu8 Pointer to the value to update. + * @param u8New The new value to assigned to *pu32. + * @param u8Old The old value to *pu8 compare with. + * @param pu8Old Pointer store the old value at. + * + * @remarks x86: Requires a 486 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicCmpXchgExU8(volatile uint8_t RT_FAR *pu8, const uint8_t u8New, const uint8_t u8Old, uint8_t RT_FAR *pu8Old) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicCmpXchgExU8(volatile uint8_t RT_FAR *pu8, const uint8_t u8New, const uint8_t u8Old, uint8_t RT_FAR *pu8Old) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + uint8_t u8Ret; + __asm__ __volatile__("lock; cmpxchgb %3, %0\n\t" + "setz %1\n\t" + : "=m" (*pu8) + , "=qm" (u8Ret) + , "=a" (*pu8Old) +# if defined(RT_ARCH_X86) + : "q" (u8New) +# else + : "r" (u8New) +# endif + , "a" (u8Old) + , "m" (*pu8) + : "cc"); + return (bool)u8Ret; + +# elif RT_INLINE_ASM_USES_INTRIN + return (*pu8Old = _InterlockedCompareExchange8((char RT_FAR *)pu8, u8New, u8Old)) == u8Old; + +# else + uint8_t u8Ret; + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [pu8] +# else + mov edx, [pu8] +# endif + mov eax, [u8Old] + mov ecx, [u8New] +# ifdef RT_ARCH_AMD64 + lock cmpxchg [rdx], ecx + mov rdx, [pu8Old] + mov [rdx], eax +# else + lock cmpxchg [edx], ecx + mov edx, [pu8Old] + mov [edx], eax +# endif + setz al + movzx eax, al + mov [u8Ret], eax + } + return !!u8Ret; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + union { uint8_t u; bool f; } fXchg; + uint8_t u8ActualOld; + uint8_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicCmpXchgExU8_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxrb %w[uOld], %[pMem]\n\t" + "cmp %w[uOld], %w[uCmp]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "stlxrb %w[rc], %w[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicCmpXchgExU8_%=\n\t" + "mov %w[fXchg], #1\n\t" +# else + "ldrexb %[uOld], %[pMem]\n\t" + "teq %[uOld], %[uCmp]\n\t" + "strexbeq %[rc], %[uNew], %[pMem]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicCmpXchgExU8_%=\n\t" + "mov %[fXchg], #1\n\t" +# endif + "1:\n\t" + : [pMem] "+Q" (*pu8) + , [uOld] "=&r" (u8ActualOld) + , [rc] "=&r" (rcSpill) + , [fXchg] "=&r" (fXchg.u) + : [uCmp] "r" (u8Old) + , [uNew] "r" (u8New) + , "[fXchg]" (0) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + *pu8Old = u8ActualOld; + return fXchg.f; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Compare and Exchange a signed 8-bit value, additionally + * passes back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pi8 Pointer to the value to update. + * @param i8New The new value to assigned to *pi8. + * @param i8Old The old value to *pi8 compare with. + * @param pi8Old Pointer store the old value at. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(bool) ASMAtomicCmpXchgExS8(volatile int8_t RT_FAR *pi8, const int8_t i8New, const int8_t i8Old, int8_t RT_FAR *pi8Old) RT_NOTHROW_DEF +{ + return ASMAtomicCmpXchgExU8((volatile uint8_t RT_FAR *)pi8, (uint8_t)i8New, (uint8_t)i8Old, (uint8_t RT_FAR *)pi8Old); +} + + +/** + * Atomically Compare and Exchange an unsigned 16-bit value, additionally passes + * back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pu16 Pointer to the value to update. + * @param u16New The new value to assigned to *pu16. + * @param u16Old The old value to *pu32 compare with. + * @param pu16Old Pointer store the old value at. + * + * @remarks x86: Requires a 486 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicCmpXchgExU16(volatile uint16_t RT_FAR *pu16, const uint16_t u16New, const uint16_t u16Old, uint16_t RT_FAR *pu16Old) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicCmpXchgExU16(volatile uint16_t RT_FAR *pu16, const uint16_t u16New, const uint16_t u16Old, uint16_t RT_FAR *pu16Old) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + uint8_t u8Ret; + __asm__ __volatile__("lock; cmpxchgw %3, %0\n\t" + "setz %1\n\t" + : "=m" (*pu16) + , "=qm" (u8Ret) + , "=a" (*pu16Old) + : "r" (u16New) + , "a" (u16Old) + , "m" (*pu16) + : "cc"); + return (bool)u8Ret; + +# elif RT_INLINE_ASM_USES_INTRIN + return (*pu16Old = _InterlockedCompareExchange16((short RT_FAR *)pu16, u16New, u16Old)) == u16Old; + +# else + uint16_t u16Ret; + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [pu16] +# else + mov edx, [pu16] +# endif + mov eax, [u16Old] + mov ecx, [u16New] +# ifdef RT_ARCH_AMD64 + lock cmpxchg [rdx], ecx + mov rdx, [pu16Old] + mov [rdx], eax +# else + lock cmpxchg [edx], ecx + mov edx, [pu16Old] + mov [edx], eax +# endif + setz al + movzx eax, al + mov [u16Ret], eax + } + return !!u16Ret; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + union { uint16_t u; bool f; } fXchg; + uint16_t u16ActualOld; + uint16_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicCmpXchgExU16_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxrh %w[uOld], %[pMem]\n\t" + "cmp %w[uOld], %w[uCmp]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "stlxrh %w[rc], %w[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicCmpXchgExU16_%=\n\t" + "mov %w[fXchg], #1\n\t" +# else + "ldrexh %[uOld], %[pMem]\n\t" + "teq %[uOld], %[uCmp]\n\t" + "strexheq %[rc], %[uNew], %[pMem]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicCmpXchgExU16_%=\n\t" + "mov %[fXchg], #1\n\t" +# endif + "1:\n\t" + : [pMem] "+Q" (*pu16) + , [uOld] "=&r" (u16ActualOld) + , [rc] "=&r" (rcSpill) + , [fXchg] "=&r" (fXchg.u) + : [uCmp] "r" (u16Old) + , [uNew] "r" (u16New) + , "[fXchg]" (0) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + *pu16Old = u16ActualOld; + return fXchg.f; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Compare and Exchange a signed 16-bit value, additionally + * passes back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pi16 Pointer to the value to update. + * @param i16New The new value to assigned to *pi16. + * @param i16Old The old value to *pi16 compare with. + * @param pi16Old Pointer store the old value at. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(bool) ASMAtomicCmpXchgExS16(volatile int16_t RT_FAR *pi16, const int16_t i16New, const int16_t i16Old, int16_t RT_FAR *pi16Old) RT_NOTHROW_DEF +{ + return ASMAtomicCmpXchgExU16((volatile uint16_t RT_FAR *)pi16, (uint16_t)i16New, (uint16_t)i16Old, (uint16_t RT_FAR *)pi16Old); +} + + +/** + * Atomically Compare and Exchange an unsigned 32-bit value, additionally + * passes back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pu32 Pointer to the value to update. + * @param u32New The new value to assigned to *pu32. + * @param u32Old The old value to *pu32 compare with. + * @param pu32Old Pointer store the old value at. + * + * @remarks x86: Requires a 486 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicCmpXchgExU32(volatile uint32_t RT_FAR *pu32, const uint32_t u32New, const uint32_t u32Old, uint32_t RT_FAR *pu32Old) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicCmpXchgExU32(volatile uint32_t RT_FAR *pu32, const uint32_t u32New, const uint32_t u32Old, uint32_t RT_FAR *pu32Old) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + uint8_t u8Ret; + __asm__ __volatile__("lock; cmpxchgl %3, %0\n\t" + "setz %1\n\t" + : "=m" (*pu32) + , "=qm" (u8Ret) + , "=a" (*pu32Old) + : "r" (u32New) + , "a" (u32Old) + , "m" (*pu32) + : "cc"); + return (bool)u8Ret; + +# elif RT_INLINE_ASM_USES_INTRIN + return (*pu32Old = _InterlockedCompareExchange((long RT_FAR *)pu32, u32New, u32Old)) == u32Old; + +# else + uint32_t u32Ret; + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] +# else + mov edx, [pu32] +# endif + mov eax, [u32Old] + mov ecx, [u32New] +# ifdef RT_ARCH_AMD64 + lock cmpxchg [rdx], ecx + mov rdx, [pu32Old] + mov [rdx], eax +# else + lock cmpxchg [edx], ecx + mov edx, [pu32Old] + mov [edx], eax +# endif + setz al + movzx eax, al + mov [u32Ret], eax + } + return !!u32Ret; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + union { uint32_t u; bool f; } fXchg; + uint32_t u32ActualOld; + uint32_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicCmpXchgExU32_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxr %w[uOld], %[pMem]\n\t" + "cmp %w[uOld], %w[uCmp]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "stlxr %w[rc], %w[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicCmpXchgExU32_%=\n\t" + "mov %w[fXchg], #1\n\t" +# else + "ldrex %[uOld], %[pMem]\n\t" + "teq %[uOld], %[uCmp]\n\t" + "strexeq %[rc], %[uNew], %[pMem]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicCmpXchgExU32_%=\n\t" + "mov %[fXchg], #1\n\t" +# endif + "1:\n\t" + : [pMem] "+Q" (*pu32) + , [uOld] "=&r" (u32ActualOld) + , [rc] "=&r" (rcSpill) + , [fXchg] "=&r" (fXchg.u) + : [uCmp] "r" (u32Old) + , [uNew] "r" (u32New) + , "[fXchg]" (0) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + *pu32Old = u32ActualOld; + return fXchg.f; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Compare and Exchange a signed 32-bit value, additionally + * passes back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pi32 Pointer to the value to update. + * @param i32New The new value to assigned to *pi32. + * @param i32Old The old value to *pi32 compare with. + * @param pi32Old Pointer store the old value at. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(bool) ASMAtomicCmpXchgExS32(volatile int32_t RT_FAR *pi32, const int32_t i32New, const int32_t i32Old, int32_t RT_FAR *pi32Old) RT_NOTHROW_DEF +{ + return ASMAtomicCmpXchgExU32((volatile uint32_t RT_FAR *)pi32, (uint32_t)i32New, (uint32_t)i32Old, (uint32_t RT_FAR *)pi32Old); +} + + +/** + * Atomically Compare and exchange an unsigned 64-bit value, additionally + * passing back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pu64 Pointer to the 64-bit variable to update. + * @param u64New The 64-bit value to assign to *pu64. + * @param u64Old The value to compare with. + * @param pu64Old Pointer store the old value at. + * + * @remarks x86: Requires a Pentium or later. + */ +#if (RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN) \ + || RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicCmpXchgExU64(volatile uint64_t RT_FAR *pu64, const uint64_t u64New, const uint64_t u64Old, uint64_t RT_FAR *pu64Old) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicCmpXchgExU64(volatile uint64_t RT_FAR *pu64, const uint64_t u64New, const uint64_t u64Old, uint64_t RT_FAR *pu64Old) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + return (*pu64Old =_InterlockedCompareExchange64((__int64 RT_FAR *)pu64, u64New, u64Old)) == u64Old; + +# elif defined(RT_ARCH_AMD64) +# if RT_INLINE_ASM_GNU_STYLE + uint8_t u8Ret; + __asm__ __volatile__("lock; cmpxchgq %3, %0\n\t" + "setz %1\n\t" + : "=m" (*pu64) + , "=qm" (u8Ret) + , "=a" (*pu64Old) + : "r" (u64New) + , "a" (u64Old) + , "m" (*pu64) + : "cc"); + return (bool)u8Ret; +# else + bool fRet; + __asm + { + mov rdx, [pu32] + mov rax, [u64Old] + mov rcx, [u64New] + lock cmpxchg [rdx], rcx + mov rdx, [pu64Old] + mov [rdx], rax + setz al + mov [fRet], al + } + return fRet; +# endif + +# elif defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + uint64_t u64Ret; +# if defined(PIC) || defined(__PIC__) + /* Note #1: This code uses a memory clobber description, because the clean + solution with an output value for *pu64 makes gcc run out of + registers. This will cause suboptimal code, and anyone with a + better solution is welcome to improve this. + + Note #2: We must prevent gcc from encoding the memory access, as it + may go via the GOT if we're working on a global variable (like + in the testcase). Thus we request a register (%3) and + dereference it ourselves. */ + __asm__ __volatile__("xchgl %%ebx, %1\n\t" + "lock; cmpxchg8b (%3)\n\t" + "xchgl %%ebx, %1\n\t" + : "=A" (u64Ret) + : "DS" ((uint32_t)u64New) + , "c" ((uint32_t)(u64New >> 32)) + , "r" (pu64) /* Do not use "m" here*/ + , "0" (u64Old) + : "memory" + , "cc" ); +# else /* !PIC */ + __asm__ __volatile__("lock; cmpxchg8b %4\n\t" + : "=A" (u64Ret) + , "=m" (*pu64) + : "b" ((uint32_t)u64New) + , "c" ((uint32_t)(u64New >> 32)) + , "m" (*pu64) + , "0" (u64Old) + : "cc"); +# endif + *pu64Old = u64Ret; + return u64Ret == u64Old; +# else + uint32_t u32Ret; + __asm + { + mov ebx, dword ptr [u64New] + mov ecx, dword ptr [u64New + 4] + mov edi, [pu64] + mov eax, dword ptr [u64Old] + mov edx, dword ptr [u64Old + 4] + lock cmpxchg8b [edi] + mov ebx, [pu64Old] + mov [ebx], eax + setz al + movzx eax, al + add ebx, 4 + mov [ebx], edx + mov dword ptr [u32Ret], eax + } + return !!u32Ret; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + union { uint32_t u; bool f; } fXchg; + uint64_t u64ActualOld; + uint32_t rcSpill; + __asm__ __volatile__(".Ltry_again_ASMAtomicCmpXchgU64_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldaxr %[uOld], %[pMem]\n\t" + "cmp %[uOld], %[uCmp]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "stlxr %w[rc], %[uNew], %[pMem]\n\t" + "cbnz %w[rc], .Ltry_again_ASMAtomicCmpXchgU64_%=\n\t" + "mov %w[fXchg], #1\n\t" +# else + "ldrexd %[uOld], %H[uOld], %[pMem]\n\t" + "teq %[uOld], %[uCmp]\n\t" + "teqeq %H[uOld], %H[uCmp]\n\t" + "strexdeq %[rc], %[uNew], %H[uNew], %[pMem]\n\t" + "bne 1f\n\t" /* stop here if not equal */ + "cmp %[rc], #0\n\t" + "bne .Ltry_again_ASMAtomicCmpXchgU64_%=\n\t" + "mov %[fXchg], #1\n\t" +# endif + "1:\n\t" + : [pMem] "+Q" (*pu64) + , [uOld] "=&r" (u64ActualOld) + , [rc] "=&r" (rcSpill) + , [fXchg] "=&r" (fXchg.u) + : [uCmp] "r" (u64Old) + , [uNew] "r" (u64New) + , "[fXchg]" (0) + RTASM_ARM_DMB_SY_COMMA_IN_REG + : "cc"); + *pu64Old = u64ActualOld; + return fXchg.f; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically Compare and exchange a signed 64-bit value, additionally + * passing back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param pi64 Pointer to the 64-bit variable to update. + * @param i64 The 64-bit value to assign to *pu64. + * @param i64Old The value to compare with. + * @param pi64Old Pointer store the old value at. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(bool) ASMAtomicCmpXchgExS64(volatile int64_t RT_FAR *pi64, const int64_t i64, const int64_t i64Old, int64_t RT_FAR *pi64Old) RT_NOTHROW_DEF +{ + return ASMAtomicCmpXchgExU64((volatile uint64_t RT_FAR *)pi64, (uint64_t)i64, (uint64_t)i64Old, (uint64_t RT_FAR *)pi64Old); +} + +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_ARM64) || defined(DOXYGEN_RUNNING) + +/** @def RTASM_HAVE_CMP_XCHG_U128 + * Indicates that we've got ASMAtomicCmpSwapU128(), ASMAtomicCmpSwapU128v2() + * and ASMAtomicCmpSwapExU128() available. */ +# define RTASM_HAVE_CMP_XCHG_U128 1 + + +/** + * Atomically compare and exchange an unsigned 128-bit value, ordered. + * + * @returns true if exchange was done. + * @returns false if exchange wasn't done. + * + * @param pu128 Pointer to the 128-bit variable to update. + * @param u64NewHi The high 64 bits of the value to assign to *pu128. + * @param u64NewLo The low 64 bits of the value to assign to *pu128. + * @param u64OldHi The high 64-bit of the value to compare with. + * @param u64OldLo The low 64-bit of the value to compare with. + * @param pu128Old Where to return the old value. + * + * @remarks AMD64: Not present in the earliest CPUs, so check CPUID. + */ +# if (RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN) +DECLASM(bool) ASMAtomicCmpXchgU128v2(volatile uint128_t *pu128, const uint64_t u64NewHi, const uint64_t u64NewLo, + const uint64_t u64OldHi, const uint64_t u64OldLo, uint128_t *pu128Old) RT_NOTHROW_PROTO; +# else +DECLINLINE(bool) ASMAtomicCmpXchgU128v2(volatile uint128_t *pu128, const uint64_t u64NewHi, const uint64_t u64NewLo, + const uint64_t u64OldHi, const uint64_t u64OldLo, uint128_t *pu128Old) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + pu128Old->Hi = u64OldHi; + pu128Old->Lo = u64OldLo; + AssertCompileMemberOffset(uint128_t, Lo, 0); + return _InterlockedCompareExchange128((__int64 volatile *)pu128, u64NewHi, u64NewLo, (__int64 *)&pu128Old->Lo) != 0; + +# elif (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64) + uint128_t const uCmp = ((uint128_t)u64OldHi << 64) | u64OldLo; + uint128_t const uOld = __sync_val_compare_and_swap(pu128, uCmp, ((uint128_t)u64NewHi << 64) | u64NewLo); + *pu128Old = uOld; + return uCmp == uOld; + +# elif defined(RT_ARCH_AMD64) +# if RT_INLINE_ASM_GNU_STYLE + uint8_t bRet; + uint64_t u64RetHi, u64RetLo; + __asm__ __volatile__("lock; cmpxchg16b %3\n\t" + "setz %b0\n\t" + : "=r" (bRet) + , "=a" (u64RetLo) + , "=d" (u64RetHi) + , "+m" (*pu128) + : "a" (u64OldLo) + , "d" (u64OldHi) + , "b" (u64NewLo) + , "c" (u64NewHi) + : "cc"); + *pu128Old = ((uint128_t)u64RetHi << 64) | u64RetLo; + return (bool)bRet; +# else +# error "Port me" +# endif +# else +# error "Port me" +# endif +} +# endif + + +/** + * Atomically compare and exchange an unsigned 128-bit value, ordered. + * + * @returns true if exchange was done. + * @returns false if exchange wasn't done. + * + * @param pu128 Pointer to the 128-bit variable to update. + * @param u128New The 128-bit value to assign to *pu128. + * @param u128Old The value to compare with. + * @param pu128Old Where to return the old value. + * + * @remarks AMD64: Not present in the earliest CPUs, so check CPUID. + */ +DECLINLINE(bool) ASMAtomicCmpXchgU128(volatile uint128_t *pu128, const uint128_t u128New, + const uint128_t u128Old, uint128_t *pu128Old) RT_NOTHROW_DEF +{ +# ifdef RT_COMPILER_WITH_128BIT_INT_TYPES +# if (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64) + uint128_t const uSwapped = __sync_val_compare_and_swap(pu128, u128Old, u128New); + *pu128Old = uSwapped; + return uSwapped == u128Old; +# else + return ASMAtomicCmpXchgU128v2(pu128, (uint64_t)(u128New >> 64), (uint64_t)u128New, + (uint64_t)(u128Old >> 64), (uint64_t)u128Old, pu128Old); +# endif +# else + return ASMAtomicCmpXchgU128v2(pu128, u128New.Hi, u128New.Lo, u128Old.Hi, u128Old.Lo, pu128Old); +# endif +} + + +/** + * RTUINT128U wrapper for ASMAtomicCmpXchgU128. + */ +DECLINLINE(bool) ASMAtomicCmpXchgU128U(volatile RTUINT128U *pu128, const RTUINT128U u128New, + const RTUINT128U u128Old, PRTUINT128U pu128Old) RT_NOTHROW_DEF +{ +# if (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64) + return ASMAtomicCmpXchgU128(&pu128->u, u128New.u, u128Old.u, &pu128Old->u); +# else + return ASMAtomicCmpXchgU128v2(&pu128->u, u128New.s.Hi, u128New.s.Lo, u128Old.s.Hi, u128Old.s.Lo, &pu128Old->u); +# endif +} + +#endif /* RT_ARCH_AMD64 || RT_ARCH_ARM64 */ + + + +/** @def ASMAtomicCmpXchgExHandle + * Atomically Compare and Exchange a typical IPRT handle value, ordered. + * + * @param ph Pointer to the value to update. + * @param hNew The new value to assigned to *pu. + * @param hOld The old value to *pu compare with. + * @param fRc Where to store the result. + * @param phOldVal Pointer to where to store the old value. + * + * @remarks This doesn't currently work for all handles (like RTFILE). + */ +#if HC_ARCH_BITS == 32 || ARCH_BITS == 16 +# define ASMAtomicCmpXchgExHandle(ph, hNew, hOld, fRc, phOldVal) \ + do { \ + AssertCompile(sizeof(*ph) == sizeof(uint32_t)); \ + AssertCompile(sizeof(*phOldVal) == sizeof(uint32_t)); \ + (fRc) = ASMAtomicCmpXchgExU32((volatile uint32_t RT_FAR *)(ph), (uint32_t)(hNew), (uint32_t)(hOld), (uint32_t RT_FAR *)(phOldVal)); \ + } while (0) +#elif HC_ARCH_BITS == 64 +# define ASMAtomicCmpXchgExHandle(ph, hNew, hOld, fRc, phOldVal) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint64_t)); \ + AssertCompile(sizeof(*(phOldVal)) == sizeof(uint64_t)); \ + (fRc) = ASMAtomicCmpXchgExU64((volatile uint64_t RT_FAR *)(ph), (uint64_t)(hNew), (uint64_t)(hOld), (uint64_t RT_FAR *)(phOldVal)); \ + } while (0) +#else +# error HC_ARCH_BITS +#endif + + +/** @def ASMAtomicCmpXchgExSize + * Atomically Compare and Exchange a value which size might differ + * between platforms or compilers. Additionally passes back old value. + * + * @param pu Pointer to the value to update. + * @param uNew The new value to assigned to *pu. + * @param uOld The old value to *pu compare with. + * @param fRc Where to store the result. + * @param puOldVal Pointer to where to store the old value. + * + * @remarks x86: Requires a 486 or later. + */ +#define ASMAtomicCmpXchgExSize(pu, uNew, uOld, fRc, puOldVal) \ + do { \ + switch (sizeof(*(pu))) { \ + case 4: (fRc) = ASMAtomicCmpXchgExU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu), (uint32_t)(uNew), (uint32_t)(uOld), (uint32_t RT_FAR *)(uOldVal)); \ + break; \ + case 8: (fRc) = ASMAtomicCmpXchgExU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu), (uint64_t)(uNew), (uint64_t)(uOld), (uint64_t RT_FAR *)(uOldVal)); \ + break; \ + default: AssertMsgFailed(("ASMAtomicCmpXchgSize: size %d is not supported\n", sizeof(*(pu)))); \ + (fRc) = false; \ + (uOldVal) = 0; \ + break; \ + } \ + } while (0) + + +/** + * Atomically Compare and Exchange a pointer value, additionally + * passing back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param ppv Pointer to the value to update. + * @param pvNew The new value to assigned to *ppv. + * @param pvOld The old value to *ppv compare with. + * @param ppvOld Pointer store the old value at. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(bool) ASMAtomicCmpXchgExPtrVoid(void RT_FAR * volatile RT_FAR *ppv, const void RT_FAR *pvNew, const void RT_FAR *pvOld, + void RT_FAR * RT_FAR *ppvOld) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 32 || ARCH_BITS == 16 + return ASMAtomicCmpXchgExU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppv, (uint32_t)pvNew, (uint32_t)pvOld, (uint32_t RT_FAR *)ppvOld); +#elif ARCH_BITS == 64 + return ASMAtomicCmpXchgExU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppv, (uint64_t)pvNew, (uint64_t)pvOld, (uint64_t RT_FAR *)ppvOld); +#else +# error "ARCH_BITS is bogus" +#endif +} + + +/** + * Atomically Compare and Exchange a pointer value, additionally + * passing back old value, ordered. + * + * @returns true if xchg was done. + * @returns false if xchg wasn't done. + * + * @param ppv Pointer to the value to update. + * @param pvNew The new value to assigned to *ppv. + * @param pvOld The old value to *ppv compare with. + * @param ppvOld Pointer store the old value at. + * + * @remarks This is relatively type safe on GCC platforms. + * @remarks x86: Requires a 486 or later. + */ +#ifdef __GNUC__ +# define ASMAtomicCmpXchgExPtr(ppv, pvNew, pvOld, ppvOld) \ + __extension__ \ + ({\ + __typeof__(*(ppv)) volatile * const ppvTypeChecked = (ppv); \ + __typeof__(*(ppv)) const pvNewTypeChecked = (pvNew); \ + __typeof__(*(ppv)) const pvOldTypeChecked = (pvOld); \ + __typeof__(*(ppv)) * const ppvOldTypeChecked = (ppvOld); \ + bool fMacroRet = ASMAtomicCmpXchgExPtrVoid((void * volatile *)ppvTypeChecked, \ + (void *)pvNewTypeChecked, (void *)pvOldTypeChecked, \ + (void **)ppvOldTypeChecked); \ + fMacroRet; \ + }) +#else +# define ASMAtomicCmpXchgExPtr(ppv, pvNew, pvOld, ppvOld) \ + ASMAtomicCmpXchgExPtrVoid((void RT_FAR * volatile RT_FAR *)(ppv), (void RT_FAR *)(pvNew), (void RT_FAR *)(pvOld), (void RT_FAR * RT_FAR *)(ppvOld)) +#endif + + +/** + * Virtualization unfriendly serializing instruction, always exits. + */ +#if (RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN) || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSerializeInstructionCpuId(void) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMSerializeInstructionCpuId(void) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG xAX = 0; +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__ ("cpuid" + : "=a" (xAX) + : "0" (xAX) + : "rbx", "rcx", "rdx", "memory"); +# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__) + __asm__ __volatile__ ("push %%ebx\n\t" + "cpuid\n\t" + "pop %%ebx\n\t" + : "=a" (xAX) + : "0" (xAX) + : "ecx", "edx", "memory"); +# else + __asm__ __volatile__ ("cpuid" + : "=a" (xAX) + : "0" (xAX) + : "ebx", "ecx", "edx", "memory"); +# endif + +# elif RT_INLINE_ASM_USES_INTRIN + int aInfo[4]; + _ReadWriteBarrier(); + __cpuid(aInfo, 0); + +# else + __asm + { + push ebx + xor eax, eax + cpuid + pop ebx + } +# endif +} +#endif + +/** + * Virtualization friendly serializing instruction, though more expensive. + */ +#if RT_INLINE_ASM_EXTERNAL || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSerializeInstructionIRet(void) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMSerializeInstructionIRet(void) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__ ("movq %%rsp,%%r10\n\t" + "subq $128, %%rsp\n\t" /*redzone*/ + "mov %%ss, %%eax\n\t" + "pushq %%rax\n\t" + "pushq %%r10\n\t" + "pushfq\n\t" + "movl %%cs, %%eax\n\t" + "pushq %%rax\n\t" + "leaq 1f(%%rip), %%rax\n\t" + "pushq %%rax\n\t" + "iretq\n\t" + "1:\n\t" + ::: "rax", "r10", "memory", "cc"); +# else + __asm__ __volatile__ ("pushfl\n\t" + "pushl %%cs\n\t" + "pushl $1f\n\t" + "iretl\n\t" + "1:\n\t" + ::: "memory"); +# endif + +# else + __asm + { + pushfd + push cs + push la_ret + iretd + la_ret: + } +# endif +} +#endif + +/** + * Virtualization friendlier serializing instruction, may still cause exits. + */ +#if (RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2008) || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSerializeInstructionRdTscp(void) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMSerializeInstructionRdTscp(void) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_GNU_STYLE + /* rdtscp is not supported by ancient linux build VM of course :-( */ +# ifdef RT_ARCH_AMD64 + /*__asm__ __volatile__("rdtscp\n\t" ::: "rax", "rdx, "rcx"); */ + __asm__ __volatile__(".byte 0x0f,0x01,0xf9\n\t" ::: "rax", "rdx", "rcx", "memory"); +# else + /*__asm__ __volatile__("rdtscp\n\t" ::: "eax", "edx, "ecx"); */ + __asm__ __volatile__(".byte 0x0f,0x01,0xf9\n\t" ::: "eax", "edx", "ecx", "memory"); +# endif +# else +# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008 + uint32_t uIgnore; + _ReadWriteBarrier(); + (void)__rdtscp(&uIgnore); + (void)uIgnore; +# else + __asm + { + rdtscp + } +# endif +# endif +} +#endif + + +/** + * Serialize Instruction (both data store and instruction flush). + */ +#if (defined(RT_ARCH_X86) && ARCH_BITS == 16) || defined(IN_GUEST) +# define ASMSerializeInstruction() ASMSerializeInstructionIRet() +#elif defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) +# define ASMSerializeInstruction() ASMSerializeInstructionCpuId() +#elif defined(RT_ARCH_SPARC64) +RTDECL(void) ASMSerializeInstruction(void) RT_NOTHROW_PROTO; +#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) +DECLINLINE(void) ASMSerializeInstruction(void) RT_NOTHROW_DEF +{ + __asm__ __volatile__ (RTASM_ARM_DSB_SY :: RTASM_ARM_DSB_SY_IN_REG :); +} +#else +# error "Port me" +#endif + + +/** + * Memory fence, waits for any pending writes and reads to complete. + * @note No implicit compiler barrier (which is probably stupid). + */ +DECLINLINE(void) ASMMemoryFence(void) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_AMD64) || (defined(RT_ARCH_X86) && !defined(RT_WITH_OLD_CPU_SUPPORT)) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ (".byte 0x0f,0xae,0xf0\n\t"); +# elif RT_INLINE_ASM_USES_INTRIN + _mm_mfence(); +# else + __asm + { + _emit 0x0f + _emit 0xae + _emit 0xf0 + } +# endif +#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + __asm__ __volatile__ (RTASM_ARM_DMB_SY :: RTASM_ARM_DMB_SY_IN_REG :); +#elif ARCH_BITS == 16 + uint16_t volatile u16; + ASMAtomicXchgU16(&u16, 0); +#else + uint32_t volatile u32; + ASMAtomicXchgU32(&u32, 0); +#endif +} + + +/** + * Write fence, waits for any pending writes to complete. + * @note No implicit compiler barrier (which is probably stupid). + */ +DECLINLINE(void) ASMWriteFence(void) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_AMD64) || (defined(RT_ARCH_X86) && !defined(RT_WITH_OLD_CPU_SUPPORT)) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ (".byte 0x0f,0xae,0xf8\n\t"); +# elif RT_INLINE_ASM_USES_INTRIN + _mm_sfence(); +# else + __asm + { + _emit 0x0f + _emit 0xae + _emit 0xf8 + } +# endif +#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + __asm__ __volatile__ (RTASM_ARM_DMB_ST :: RTASM_ARM_DMB_ST_IN_REG :); +#else + ASMMemoryFence(); +#endif +} + + +/** + * Read fence, waits for any pending reads to complete. + * @note No implicit compiler barrier (which is probably stupid). + */ +DECLINLINE(void) ASMReadFence(void) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_AMD64) || (defined(RT_ARCH_X86) && !defined(RT_WITH_OLD_CPU_SUPPORT)) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ (".byte 0x0f,0xae,0xe8\n\t"); +# elif RT_INLINE_ASM_USES_INTRIN + _mm_lfence(); +# else + __asm + { + _emit 0x0f + _emit 0xae + _emit 0xe8 + } +# endif +#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + __asm__ __volatile__ (RTASM_ARM_DMB_LD :: RTASM_ARM_DMB_LD_IN_REG :); +#else + ASMMemoryFence(); +#endif +} + + +/** + * Atomically reads an unsigned 8-bit value, ordered. + * + * @returns Current *pu8 value + * @param pu8 Pointer to the 8-bit variable to read. + */ +DECLINLINE(uint8_t) ASMAtomicReadU8(volatile uint8_t RT_FAR *pu8) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t u32; + __asm__ __volatile__(".Lstart_ASMAtomicReadU8_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldxrb %w[uDst], %[pMem]\n\t" +# else + "ldrexb %[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u32) + : [pMem] "Q" (*pu8) + RTASM_ARM_DMB_SY_COMMA_IN_REG); + return (uint8_t)u32; +#else + ASMMemoryFence(); + return *pu8; /* byte reads are atomic on x86 */ +#endif +} + + +/** + * Atomically reads an unsigned 8-bit value, unordered. + * + * @returns Current *pu8 value + * @param pu8 Pointer to the 8-bit variable to read. + */ +DECLINLINE(uint8_t) ASMAtomicUoReadU8(volatile uint8_t RT_FAR *pu8) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t u32; + __asm__ __volatile__(".Lstart_ASMAtomicUoReadU8_%=:\n\t" +# if defined(RT_ARCH_ARM64) + "ldxrb %w[uDst], %[pMem]\n\t" +# else + "ldrexb %[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u32) + : [pMem] "Q" (*pu8)); + return (uint8_t)u32; +#else + return *pu8; /* byte reads are atomic on x86 */ +#endif +} + + +/** + * Atomically reads a signed 8-bit value, ordered. + * + * @returns Current *pi8 value + * @param pi8 Pointer to the 8-bit variable to read. + */ +DECLINLINE(int8_t) ASMAtomicReadS8(volatile int8_t RT_FAR *pi8) RT_NOTHROW_DEF +{ + ASMMemoryFence(); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + int32_t i32; + __asm__ __volatile__(".Lstart_ASMAtomicReadS8_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldxrb %w[iDst], %[pMem]\n\t" +# else + "ldrexb %[iDst], %[pMem]\n\t" +# endif + : [iDst] "=&r" (i32) + : [pMem] "Q" (*pi8) + RTASM_ARM_DMB_SY_COMMA_IN_REG); + return (int8_t)i32; +#else + return *pi8; /* byte reads are atomic on x86 */ +#endif +} + + +/** + * Atomically reads a signed 8-bit value, unordered. + * + * @returns Current *pi8 value + * @param pi8 Pointer to the 8-bit variable to read. + */ +DECLINLINE(int8_t) ASMAtomicUoReadS8(volatile int8_t RT_FAR *pi8) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + int32_t i32; + __asm__ __volatile__(".Lstart_ASMAtomicUoReadS8_%=:\n\t" +# if defined(RT_ARCH_ARM64) + "ldxrb %w[iDst], %[pMem]\n\t" +# else + "ldrexb %[iDst], %[pMem]\n\t" +# endif + : [iDst] "=&r" (i32) + : [pMem] "Q" (*pi8)); + return (int8_t)i32; +#else + return *pi8; /* byte reads are atomic on x86 */ +#endif +} + + +/** + * Atomically reads an unsigned 16-bit value, ordered. + * + * @returns Current *pu16 value + * @param pu16 Pointer to the 16-bit variable to read. + */ +DECLINLINE(uint16_t) ASMAtomicReadU16(volatile uint16_t RT_FAR *pu16) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pu16 & 1)); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t u32; + __asm__ __volatile__(".Lstart_ASMAtomicReadU16_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldxrh %w[uDst], %[pMem]\n\t" +# else + "ldrexh %[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u32) + : [pMem] "Q" (*pu16) + RTASM_ARM_DMB_SY_COMMA_IN_REG); + return (uint16_t)u32; +#else + ASMMemoryFence(); + return *pu16; +#endif +} + + +/** + * Atomically reads an unsigned 16-bit value, unordered. + * + * @returns Current *pu16 value + * @param pu16 Pointer to the 16-bit variable to read. + */ +DECLINLINE(uint16_t) ASMAtomicUoReadU16(volatile uint16_t RT_FAR *pu16) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pu16 & 1)); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t u32; + __asm__ __volatile__(".Lstart_ASMAtomicUoReadU16_%=:\n\t" +# if defined(RT_ARCH_ARM64) + "ldxrh %w[uDst], %[pMem]\n\t" +# else + "ldrexh %[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u32) + : [pMem] "Q" (*pu16)); + return (uint16_t)u32; +#else + return *pu16; +#endif +} + + +/** + * Atomically reads a signed 16-bit value, ordered. + * + * @returns Current *pi16 value + * @param pi16 Pointer to the 16-bit variable to read. + */ +DECLINLINE(int16_t) ASMAtomicReadS16(volatile int16_t RT_FAR *pi16) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pi16 & 1)); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + int32_t i32; + __asm__ __volatile__(".Lstart_ASMAtomicReadS16_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldxrh %w[iDst], %[pMem]\n\t" +# else + "ldrexh %[iDst], %[pMem]\n\t" +# endif + : [iDst] "=&r" (i32) + : [pMem] "Q" (*pi16) + RTASM_ARM_DMB_SY_COMMA_IN_REG); + return (int16_t)i32; +#else + ASMMemoryFence(); + return *pi16; +#endif +} + + +/** + * Atomically reads a signed 16-bit value, unordered. + * + * @returns Current *pi16 value + * @param pi16 Pointer to the 16-bit variable to read. + */ +DECLINLINE(int16_t) ASMAtomicUoReadS16(volatile int16_t RT_FAR *pi16) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pi16 & 1)); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + int32_t i32; + __asm__ __volatile__(".Lstart_ASMAtomicUoReadS16_%=:\n\t" +# if defined(RT_ARCH_ARM64) + "ldxrh %w[iDst], %[pMem]\n\t" +# else + "ldrexh %[iDst], %[pMem]\n\t" +# endif + : [iDst] "=&r" (i32) + : [pMem] "Q" (*pi16)); + return (int16_t)i32; +#else + return *pi16; +#endif +} + + +/** + * Atomically reads an unsigned 32-bit value, ordered. + * + * @returns Current *pu32 value + * @param pu32 Pointer to the 32-bit variable to read. + */ +DECLINLINE(uint32_t) ASMAtomicReadU32(volatile uint32_t RT_FAR *pu32) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pu32 & 3)); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t u32; + __asm__ __volatile__(".Lstart_ASMAtomicReadU32_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldxr %w[uDst], %[pMem]\n\t" +# else + "ldrex %[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u32) + : [pMem] "Q" (*pu32) + RTASM_ARM_DMB_SY_COMMA_IN_REG); + return u32; +#else + ASMMemoryFence(); +# if ARCH_BITS == 16 + AssertFailed(); /** @todo 16-bit */ +# endif + return *pu32; +#endif +} + + +/** + * Atomically reads an unsigned 32-bit value, unordered. + * + * @returns Current *pu32 value + * @param pu32 Pointer to the 32-bit variable to read. + */ +DECLINLINE(uint32_t) ASMAtomicUoReadU32(volatile uint32_t RT_FAR *pu32) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pu32 & 3)); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t u32; + __asm__ __volatile__(".Lstart_ASMAtomicUoReadU32_%=:\n\t" +# if defined(RT_ARCH_ARM64) + "ldxr %w[uDst], %[pMem]\n\t" +# else + "ldrex %[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u32) + : [pMem] "Q" (*pu32)); + return u32; +#else +# if ARCH_BITS == 16 + AssertFailed(); /** @todo 16-bit */ +# endif + return *pu32; +#endif +} + + +/** + * Atomically reads a signed 32-bit value, ordered. + * + * @returns Current *pi32 value + * @param pi32 Pointer to the 32-bit variable to read. + */ +DECLINLINE(int32_t) ASMAtomicReadS32(volatile int32_t RT_FAR *pi32) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pi32 & 3)); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + int32_t i32; + __asm__ __volatile__(".Lstart_ASMAtomicReadS32_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldxr %w[iDst], %[pMem]\n\t" +# else + "ldrex %[iDst], %[pMem]\n\t" +# endif + : [iDst] "=&r" (i32) + : [pMem] "Q" (*pi32) + RTASM_ARM_DMB_SY_COMMA_IN_REG); + return i32; +#else + ASMMemoryFence(); +# if ARCH_BITS == 16 + AssertFailed(); /** @todo 16-bit */ +# endif + return *pi32; +#endif +} + + +/** + * Atomically reads a signed 32-bit value, unordered. + * + * @returns Current *pi32 value + * @param pi32 Pointer to the 32-bit variable to read. + */ +DECLINLINE(int32_t) ASMAtomicUoReadS32(volatile int32_t RT_FAR *pi32) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pi32 & 3)); +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + int32_t i32; + __asm__ __volatile__(".Lstart_ASMAtomicUoReadS32_%=:\n\t" +# if defined(RT_ARCH_ARM64) + "ldxr %w[iDst], %[pMem]\n\t" +# else + "ldrex %[iDst], %[pMem]\n\t" +# endif + : [iDst] "=&r" (i32) + : [pMem] "Q" (*pi32)); + return i32; + +#else +# if ARCH_BITS == 16 + AssertFailed(); /** @todo 16-bit */ +# endif + return *pi32; +#endif +} + + +/** + * Atomically reads an unsigned 64-bit value, ordered. + * + * @returns Current *pu64 value + * @param pu64 Pointer to the 64-bit variable to read. + * The memory pointed to must be writable. + * + * @remarks This may fault if the memory is read-only! + * @remarks x86: Requires a Pentium or later. + */ +#if (RT_INLINE_ASM_EXTERNAL_TMP_ARM && !defined(RT_ARCH_AMD64)) \ + || RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC +RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMAtomicReadU64(volatile uint64_t RT_FAR *pu64) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint64_t) ASMAtomicReadU64(volatile uint64_t RT_FAR *pu64) RT_NOTHROW_DEF +{ + uint64_t u64; +# ifdef RT_ARCH_AMD64 + Assert(!((uintptr_t)pu64 & 7)); +/*# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__( "mfence\n\t" + "movq %1, %0\n\t" + : "=r" (u64) + : "m" (*pu64)); +# else + __asm + { + mfence + mov rdx, [pu64] + mov rax, [rdx] + mov [u64], rax + } +# endif*/ + ASMMemoryFence(); + u64 = *pu64; + +# elif defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE +# if defined(PIC) || defined(__PIC__) + uint32_t u32EBX = 0; + Assert(!((uintptr_t)pu64 & 7)); + __asm__ __volatile__("xchgl %%ebx, %3\n\t" + "lock; cmpxchg8b (%5)\n\t" + "movl %3, %%ebx\n\t" + : "=A" (u64) +# if RT_GNUC_PREREQ(4, 3) + , "+m" (*pu64) +# else + , "=m" (*pu64) +# endif + : "0" (0ULL) + , "m" (u32EBX) + , "c" (0) + , "S" (pu64) + : "cc"); +# else /* !PIC */ + __asm__ __volatile__("lock; cmpxchg8b %1\n\t" + : "=A" (u64) + , "+m" (*pu64) + : "0" (0ULL) + , "b" (0) + , "c" (0) + : "cc"); +# endif +# else + Assert(!((uintptr_t)pu64 & 7)); + __asm + { + xor eax, eax + xor edx, edx + mov edi, pu64 + xor ecx, ecx + xor ebx, ebx + lock cmpxchg8b [edi] + mov dword ptr [u64], eax + mov dword ptr [u64 + 4], edx + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + Assert(!((uintptr_t)pu64 & 7)); + __asm__ __volatile__(".Lstart_ASMAtomicReadU64_%=:\n\t" + RTASM_ARM_DMB_SY +# if defined(RT_ARCH_ARM64) + "ldxr %[uDst], %[pMem]\n\t" +# else + "ldrexd %[uDst], %H[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u64) + : [pMem] "Q" (*pu64) + RTASM_ARM_DMB_SY_COMMA_IN_REG); + +# else +# error "Port me" +# endif + return u64; +} +#endif + + +/** + * Atomically reads an unsigned 64-bit value, unordered. + * + * @returns Current *pu64 value + * @param pu64 Pointer to the 64-bit variable to read. + * The memory pointed to must be writable. + * + * @remarks This may fault if the memory is read-only! + * @remarks x86: Requires a Pentium or later. + */ +#if !defined(RT_ARCH_AMD64) \ + && ( (RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN) \ + || RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC) +RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMAtomicUoReadU64(volatile uint64_t RT_FAR *pu64) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint64_t) ASMAtomicUoReadU64(volatile uint64_t RT_FAR *pu64) RT_NOTHROW_DEF +{ + uint64_t u64; +# ifdef RT_ARCH_AMD64 + Assert(!((uintptr_t)pu64 & 7)); +/*# if RT_INLINE_ASM_GNU_STYLE + Assert(!((uintptr_t)pu64 & 7)); + __asm__ __volatile__("movq %1, %0\n\t" + : "=r" (u64) + : "m" (*pu64)); +# else + __asm + { + mov rdx, [pu64] + mov rax, [rdx] + mov [u64], rax + } +# endif */ + u64 = *pu64; + +# elif defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE +# if defined(PIC) || defined(__PIC__) + uint32_t u32EBX = 0; + uint32_t u32Spill; + Assert(!((uintptr_t)pu64 & 7)); + __asm__ __volatile__("xor %%eax,%%eax\n\t" + "xor %%ecx,%%ecx\n\t" + "xor %%edx,%%edx\n\t" + "xchgl %%ebx, %3\n\t" + "lock; cmpxchg8b (%4)\n\t" + "movl %3, %%ebx\n\t" + : "=A" (u64) +# if RT_GNUC_PREREQ(4, 3) + , "+m" (*pu64) +# else + , "=m" (*pu64) +# endif + , "=c" (u32Spill) + : "m" (u32EBX) + , "S" (pu64) + : "cc"); +# else /* !PIC */ + __asm__ __volatile__("lock; cmpxchg8b %1\n\t" + : "=A" (u64) + , "+m" (*pu64) + : "0" (0ULL) + , "b" (0) + , "c" (0) + : "cc"); +# endif +# else + Assert(!((uintptr_t)pu64 & 7)); + __asm + { + xor eax, eax + xor edx, edx + mov edi, pu64 + xor ecx, ecx + xor ebx, ebx + lock cmpxchg8b [edi] + mov dword ptr [u64], eax + mov dword ptr [u64 + 4], edx + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + Assert(!((uintptr_t)pu64 & 7)); + __asm__ __volatile__(".Lstart_ASMAtomicUoReadU64_%=:\n\t" +# if defined(RT_ARCH_ARM64) + "ldxr %[uDst], %[pMem]\n\t" +# else + "ldrexd %[uDst], %H[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u64) + : [pMem] "Q" (*pu64)); + +# else +# error "Port me" +# endif + return u64; +} +#endif + + +/** + * Atomically reads a signed 64-bit value, ordered. + * + * @returns Current *pi64 value + * @param pi64 Pointer to the 64-bit variable to read. + * The memory pointed to must be writable. + * + * @remarks This may fault if the memory is read-only! + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(int64_t) ASMAtomicReadS64(volatile int64_t RT_FAR *pi64) RT_NOTHROW_DEF +{ + return (int64_t)ASMAtomicReadU64((volatile uint64_t RT_FAR *)pi64); +} + + +/** + * Atomically reads a signed 64-bit value, unordered. + * + * @returns Current *pi64 value + * @param pi64 Pointer to the 64-bit variable to read. + * The memory pointed to must be writable. + * + * @remarks This will fault if the memory is read-only! + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(int64_t) ASMAtomicUoReadS64(volatile int64_t RT_FAR *pi64) RT_NOTHROW_DEF +{ + return (int64_t)ASMAtomicUoReadU64((volatile uint64_t RT_FAR *)pi64); +} + + +/** + * Atomically reads a size_t value, ordered. + * + * @returns Current *pcb value + * @param pcb Pointer to the size_t variable to read. + */ +DECLINLINE(size_t) ASMAtomicReadZ(size_t volatile RT_FAR *pcb) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 64 + return ASMAtomicReadU64((uint64_t volatile RT_FAR *)pcb); +#elif ARCH_BITS == 32 + return ASMAtomicReadU32((uint32_t volatile RT_FAR *)pcb); +#elif ARCH_BITS == 16 + AssertCompileSize(size_t, 2); + return ASMAtomicReadU16((uint16_t volatile RT_FAR *)pcb); +#else +# error "Unsupported ARCH_BITS value" +#endif +} + + +/** + * Atomically reads a size_t value, unordered. + * + * @returns Current *pcb value + * @param pcb Pointer to the size_t variable to read. + */ +DECLINLINE(size_t) ASMAtomicUoReadZ(size_t volatile RT_FAR *pcb) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 64 || ARCH_BITS == 16 + return ASMAtomicUoReadU64((uint64_t volatile RT_FAR *)pcb); +#elif ARCH_BITS == 32 + return ASMAtomicUoReadU32((uint32_t volatile RT_FAR *)pcb); +#elif ARCH_BITS == 16 + AssertCompileSize(size_t, 2); + return ASMAtomicUoReadU16((uint16_t volatile RT_FAR *)pcb); +#else +# error "Unsupported ARCH_BITS value" +#endif +} + + +/** + * Atomically reads a pointer value, ordered. + * + * @returns Current *pv value + * @param ppv Pointer to the pointer variable to read. + * + * @remarks Please use ASMAtomicReadPtrT, it provides better type safety and + * requires less typing (no casts). + */ +DECLINLINE(void RT_FAR *) ASMAtomicReadPtr(void RT_FAR * volatile RT_FAR *ppv) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 32 || ARCH_BITS == 16 + return (void RT_FAR *)ASMAtomicReadU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppv); +#elif ARCH_BITS == 64 + return (void RT_FAR *)ASMAtomicReadU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppv); +#else +# error "ARCH_BITS is bogus" +#endif +} + +/** + * Convenience macro for avoiding the annoying casting with ASMAtomicReadPtr. + * + * @returns Current *pv value + * @param ppv Pointer to the pointer variable to read. + * @param Type The type of *ppv, sans volatile. + */ +#ifdef __GNUC__ /* 8.2.0 requires -Wno-ignored-qualifiers */ +# define ASMAtomicReadPtrT(ppv, Type) \ + __extension__ \ + ({\ + __typeof__(*(ppv)) volatile *ppvTypeChecked = (ppv); \ + Type pvTypeChecked = (__typeof__(*(ppv))) ASMAtomicReadPtr((void * volatile *)ppvTypeChecked); \ + pvTypeChecked; \ + }) +#else +# define ASMAtomicReadPtrT(ppv, Type) \ + (Type)ASMAtomicReadPtr((void RT_FAR * volatile RT_FAR *)(ppv)) +#endif + + +/** + * Atomically reads a pointer value, unordered. + * + * @returns Current *pv value + * @param ppv Pointer to the pointer variable to read. + * + * @remarks Please use ASMAtomicUoReadPtrT, it provides better type safety and + * requires less typing (no casts). + */ +DECLINLINE(void RT_FAR *) ASMAtomicUoReadPtr(void RT_FAR * volatile RT_FAR *ppv) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 32 || ARCH_BITS == 16 + return (void RT_FAR *)ASMAtomicUoReadU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppv); +#elif ARCH_BITS == 64 + return (void RT_FAR *)ASMAtomicUoReadU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppv); +#else +# error "ARCH_BITS is bogus" +#endif +} + + +/** + * Convenience macro for avoiding the annoying casting with ASMAtomicUoReadPtr. + * + * @returns Current *pv value + * @param ppv Pointer to the pointer variable to read. + * @param Type The type of *ppv, sans volatile. + */ +#ifdef __GNUC__ /* 8.2.0 requires -Wno-ignored-qualifiers */ +# define ASMAtomicUoReadPtrT(ppv, Type) \ + __extension__ \ + ({\ + __typeof__(*(ppv)) volatile * const ppvTypeChecked = (ppv); \ + Type pvTypeChecked = (__typeof__(*(ppv))) ASMAtomicUoReadPtr((void * volatile *)ppvTypeChecked); \ + pvTypeChecked; \ + }) +#else +# define ASMAtomicUoReadPtrT(ppv, Type) \ + (Type)ASMAtomicUoReadPtr((void RT_FAR * volatile RT_FAR *)(ppv)) +#endif + + +/** + * Atomically reads a boolean value, ordered. + * + * @returns Current *pf value + * @param pf Pointer to the boolean variable to read. + */ +DECLINLINE(bool) ASMAtomicReadBool(volatile bool RT_FAR *pf) RT_NOTHROW_DEF +{ + ASMMemoryFence(); + return *pf; /* byte reads are atomic on x86 */ +} + + +/** + * Atomically reads a boolean value, unordered. + * + * @returns Current *pf value + * @param pf Pointer to the boolean variable to read. + */ +DECLINLINE(bool) ASMAtomicUoReadBool(volatile bool RT_FAR *pf) RT_NOTHROW_DEF +{ + return *pf; /* byte reads are atomic on x86 */ +} + + +/** + * Atomically read a typical IPRT handle value, ordered. + * + * @param ph Pointer to the handle variable to read. + * @param phRes Where to store the result. + * + * @remarks This doesn't currently work for all handles (like RTFILE). + */ +#if HC_ARCH_BITS == 32 || ARCH_BITS == 16 +# define ASMAtomicReadHandle(ph, phRes) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \ + AssertCompile(sizeof(*(phRes)) == sizeof(uint32_t)); \ + *(uint32_t RT_FAR *)(phRes) = ASMAtomicReadU32((uint32_t volatile RT_FAR *)(ph)); \ + } while (0) +#elif HC_ARCH_BITS == 64 +# define ASMAtomicReadHandle(ph, phRes) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint64_t)); \ + AssertCompile(sizeof(*(phRes)) == sizeof(uint64_t)); \ + *(uint64_t RT_FAR *)(phRes) = ASMAtomicReadU64((uint64_t volatile RT_FAR *)(ph)); \ + } while (0) +#else +# error HC_ARCH_BITS +#endif + + +/** + * Atomically read a typical IPRT handle value, unordered. + * + * @param ph Pointer to the handle variable to read. + * @param phRes Where to store the result. + * + * @remarks This doesn't currently work for all handles (like RTFILE). + */ +#if HC_ARCH_BITS == 32 || ARCH_BITS == 16 +# define ASMAtomicUoReadHandle(ph, phRes) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \ + AssertCompile(sizeof(*(phRes)) == sizeof(uint32_t)); \ + *(uint32_t RT_FAR *)(phRes) = ASMAtomicUoReadU32((uint32_t volatile RT_FAR *)(ph)); \ + } while (0) +#elif HC_ARCH_BITS == 64 +# define ASMAtomicUoReadHandle(ph, phRes) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint64_t)); \ + AssertCompile(sizeof(*(phRes)) == sizeof(uint64_t)); \ + *(uint64_t RT_FAR *)(phRes) = ASMAtomicUoReadU64((uint64_t volatile RT_FAR *)(ph)); \ + } while (0) +#else +# error HC_ARCH_BITS +#endif + + +/** + * Atomically read a value which size might differ + * between platforms or compilers, ordered. + * + * @param pu Pointer to the variable to read. + * @param puRes Where to store the result. + */ +#define ASMAtomicReadSize(pu, puRes) \ + do { \ + switch (sizeof(*(pu))) { \ + case 1: *(uint8_t RT_FAR *)(puRes) = ASMAtomicReadU8( (volatile uint8_t RT_FAR *)(void RT_FAR *)(pu)); break; \ + case 2: *(uint16_t RT_FAR *)(puRes) = ASMAtomicReadU16((volatile uint16_t RT_FAR *)(void RT_FAR *)(pu)); break; \ + case 4: *(uint32_t RT_FAR *)(puRes) = ASMAtomicReadU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu)); break; \ + case 8: *(uint64_t RT_FAR *)(puRes) = ASMAtomicReadU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu)); break; \ + default: AssertMsgFailed(("ASMAtomicReadSize: size %d is not supported\n", sizeof(*(pu)))); \ + } \ + } while (0) + + +/** + * Atomically read a value which size might differ + * between platforms or compilers, unordered. + * + * @param pu Pointer to the variable to read. + * @param puRes Where to store the result. + */ +#define ASMAtomicUoReadSize(pu, puRes) \ + do { \ + switch (sizeof(*(pu))) { \ + case 1: *(uint8_t RT_FAR *)(puRes) = ASMAtomicUoReadU8( (volatile uint8_t RT_FAR *)(void RT_FAR *)(pu)); break; \ + case 2: *(uint16_t RT_FAR *)(puRes) = ASMAtomicUoReadU16((volatile uint16_t RT_FAR *)(void RT_FAR *)(pu)); break; \ + case 4: *(uint32_t RT_FAR *)(puRes) = ASMAtomicUoReadU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu)); break; \ + case 8: *(uint64_t RT_FAR *)(puRes) = ASMAtomicUoReadU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu)); break; \ + default: AssertMsgFailed(("ASMAtomicReadSize: size %d is not supported\n", sizeof(*(pu)))); \ + } \ + } while (0) + + +/** + * Atomically writes an unsigned 8-bit value, ordered. + * + * @param pu8 Pointer to the 8-bit variable. + * @param u8 The 8-bit value to assign to *pu8. + */ +DECLINLINE(void) ASMAtomicWriteU8(volatile uint8_t RT_FAR *pu8, uint8_t u8) RT_NOTHROW_DEF +{ + /** @todo Any possible ARM32/ARM64 optimizations here? */ + ASMAtomicXchgU8(pu8, u8); +} + + +/** + * Atomically writes an unsigned 8-bit value, unordered. + * + * @param pu8 Pointer to the 8-bit variable. + * @param u8 The 8-bit value to assign to *pu8. + */ +DECLINLINE(void) ASMAtomicUoWriteU8(volatile uint8_t RT_FAR *pu8, uint8_t u8) RT_NOTHROW_DEF +{ + /** @todo Any possible ARM32/ARM64 improvements here? */ + *pu8 = u8; /* byte writes are atomic on x86 */ +} + + +/** + * Atomically writes a signed 8-bit value, ordered. + * + * @param pi8 Pointer to the 8-bit variable to read. + * @param i8 The 8-bit value to assign to *pi8. + */ +DECLINLINE(void) ASMAtomicWriteS8(volatile int8_t RT_FAR *pi8, int8_t i8) RT_NOTHROW_DEF +{ + /** @todo Any possible ARM32/ARM64 optimizations here? */ + ASMAtomicXchgS8(pi8, i8); +} + + +/** + * Atomically writes a signed 8-bit value, unordered. + * + * @param pi8 Pointer to the 8-bit variable to write. + * @param i8 The 8-bit value to assign to *pi8. + */ +DECLINLINE(void) ASMAtomicUoWriteS8(volatile int8_t RT_FAR *pi8, int8_t i8) RT_NOTHROW_DEF +{ + *pi8 = i8; /* byte writes are atomic on x86 */ +} + + +/** + * Atomically writes an unsigned 16-bit value, ordered. + * + * @param pu16 Pointer to the 16-bit variable to write. + * @param u16 The 16-bit value to assign to *pu16. + */ +DECLINLINE(void) ASMAtomicWriteU16(volatile uint16_t RT_FAR *pu16, uint16_t u16) RT_NOTHROW_DEF +{ + /** @todo Any possible ARM32/ARM64 optimizations here? */ + ASMAtomicXchgU16(pu16, u16); +} + + +/** + * Atomically writes an unsigned 16-bit value, unordered. + * + * @param pu16 Pointer to the 16-bit variable to write. + * @param u16 The 16-bit value to assign to *pu16. + */ +DECLINLINE(void) ASMAtomicUoWriteU16(volatile uint16_t RT_FAR *pu16, uint16_t u16) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pu16 & 1)); + *pu16 = u16; +} + + +/** + * Atomically writes a signed 16-bit value, ordered. + * + * @param pi16 Pointer to the 16-bit variable to write. + * @param i16 The 16-bit value to assign to *pi16. + */ +DECLINLINE(void) ASMAtomicWriteS16(volatile int16_t RT_FAR *pi16, int16_t i16) RT_NOTHROW_DEF +{ + /** @todo Any possible ARM32/ARM64 optimizations here? */ + ASMAtomicXchgS16(pi16, i16); +} + + +/** + * Atomically writes a signed 16-bit value, unordered. + * + * @param pi16 Pointer to the 16-bit variable to write. + * @param i16 The 16-bit value to assign to *pi16. + */ +DECLINLINE(void) ASMAtomicUoWriteS16(volatile int16_t RT_FAR *pi16, int16_t i16) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pi16 & 1)); + *pi16 = i16; +} + + +/** + * Atomically writes an unsigned 32-bit value, ordered. + * + * @param pu32 Pointer to the 32-bit variable to write. + * @param u32 The 32-bit value to assign to *pu32. + */ +DECLINLINE(void) ASMAtomicWriteU32(volatile uint32_t RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ + /** @todo Any possible ARM32/ARM64 optimizations here? */ + ASMAtomicXchgU32(pu32, u32); +} + + +/** + * Atomically writes an unsigned 32-bit value, unordered. + * + * @param pu32 Pointer to the 32-bit variable to write. + * @param u32 The 32-bit value to assign to *pu32. + */ +DECLINLINE(void) ASMAtomicUoWriteU32(volatile uint32_t RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pu32 & 3)); +#if ARCH_BITS >= 32 + *pu32 = u32; +#else + ASMAtomicXchgU32(pu32, u32); +#endif +} + + +/** + * Atomically writes a signed 32-bit value, ordered. + * + * @param pi32 Pointer to the 32-bit variable to write. + * @param i32 The 32-bit value to assign to *pi32. + */ +DECLINLINE(void) ASMAtomicWriteS32(volatile int32_t RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + ASMAtomicXchgS32(pi32, i32); +} + + +/** + * Atomically writes a signed 32-bit value, unordered. + * + * @param pi32 Pointer to the 32-bit variable to write. + * @param i32 The 32-bit value to assign to *pi32. + */ +DECLINLINE(void) ASMAtomicUoWriteS32(volatile int32_t RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pi32 & 3)); +#if ARCH_BITS >= 32 + *pi32 = i32; +#else + ASMAtomicXchgS32(pi32, i32); +#endif +} + + +/** + * Atomically writes an unsigned 64-bit value, ordered. + * + * @param pu64 Pointer to the 64-bit variable to write. + * @param u64 The 64-bit value to assign to *pu64. + */ +DECLINLINE(void) ASMAtomicWriteU64(volatile uint64_t RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ + /** @todo Any possible ARM32/ARM64 optimizations here? */ + ASMAtomicXchgU64(pu64, u64); +} + + +/** + * Atomically writes an unsigned 64-bit value, unordered. + * + * @param pu64 Pointer to the 64-bit variable to write. + * @param u64 The 64-bit value to assign to *pu64. + */ +DECLINLINE(void) ASMAtomicUoWriteU64(volatile uint64_t RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pu64 & 7)); +#if ARCH_BITS == 64 + *pu64 = u64; +#else + ASMAtomicXchgU64(pu64, u64); +#endif +} + + +/** + * Atomically writes a signed 64-bit value, ordered. + * + * @param pi64 Pointer to the 64-bit variable to write. + * @param i64 The 64-bit value to assign to *pi64. + */ +DECLINLINE(void) ASMAtomicWriteS64(volatile int64_t RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + /** @todo Any possible ARM32/ARM64 optimizations here? */ + ASMAtomicXchgS64(pi64, i64); +} + + +/** + * Atomically writes a signed 64-bit value, unordered. + * + * @param pi64 Pointer to the 64-bit variable to write. + * @param i64 The 64-bit value to assign to *pi64. + */ +DECLINLINE(void) ASMAtomicUoWriteS64(volatile int64_t RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + Assert(!((uintptr_t)pi64 & 7)); +#if ARCH_BITS == 64 + *pi64 = i64; +#else + ASMAtomicXchgS64(pi64, i64); +#endif +} + + +/** + * Atomically writes a size_t value, ordered. + * + * @returns nothing. + * @param pcb Pointer to the size_t variable to write. + * @param cb The value to assign to *pcb. + */ +DECLINLINE(void) ASMAtomicWriteZ(volatile size_t RT_FAR *pcb, size_t cb) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 64 + ASMAtomicWriteU64((uint64_t volatile *)pcb, cb); +#elif ARCH_BITS == 32 + ASMAtomicWriteU32((uint32_t volatile *)pcb, cb); +#elif ARCH_BITS == 16 + AssertCompileSize(size_t, 2); + ASMAtomicWriteU16((uint16_t volatile *)pcb, cb); +#else +# error "Unsupported ARCH_BITS value" +#endif +} + + +/** + * Atomically writes a size_t value, unordered. + * + * @returns nothing. + * @param pcb Pointer to the size_t variable to write. + * @param cb The value to assign to *pcb. + */ +DECLINLINE(void) ASMAtomicUoWriteZ(volatile size_t RT_FAR *pcb, size_t cb) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 64 + ASMAtomicUoWriteU64((uint64_t volatile *)pcb, cb); +#elif ARCH_BITS == 32 + ASMAtomicUoWriteU32((uint32_t volatile *)pcb, cb); +#elif ARCH_BITS == 16 + AssertCompileSize(size_t, 2); + ASMAtomicUoWriteU16((uint16_t volatile *)pcb, cb); +#else +# error "Unsupported ARCH_BITS value" +#endif +} + + +/** + * Atomically writes a boolean value, unordered. + * + * @param pf Pointer to the boolean variable to write. + * @param f The boolean value to assign to *pf. + */ +DECLINLINE(void) ASMAtomicWriteBool(volatile bool RT_FAR *pf, bool f) RT_NOTHROW_DEF +{ + ASMAtomicWriteU8((uint8_t volatile RT_FAR *)pf, f); +} + + +/** + * Atomically writes a boolean value, unordered. + * + * @param pf Pointer to the boolean variable to write. + * @param f The boolean value to assign to *pf. + */ +DECLINLINE(void) ASMAtomicUoWriteBool(volatile bool RT_FAR *pf, bool f) RT_NOTHROW_DEF +{ + *pf = f; /* byte writes are atomic on x86 */ +} + + +/** + * Atomically writes a pointer value, ordered. + * + * @param ppv Pointer to the pointer variable to write. + * @param pv The pointer value to assign to *ppv. + */ +DECLINLINE(void) ASMAtomicWritePtrVoid(void RT_FAR * volatile RT_FAR *ppv, const void *pv) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 32 || ARCH_BITS == 16 + ASMAtomicWriteU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppv, (uint32_t)pv); +#elif ARCH_BITS == 64 + ASMAtomicWriteU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppv, (uint64_t)pv); +#else +# error "ARCH_BITS is bogus" +#endif +} + + +/** + * Atomically writes a pointer value, unordered. + * + * @param ppv Pointer to the pointer variable to write. + * @param pv The pointer value to assign to *ppv. + */ +DECLINLINE(void) ASMAtomicUoWritePtrVoid(void RT_FAR * volatile RT_FAR *ppv, const void *pv) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 32 || ARCH_BITS == 16 + ASMAtomicUoWriteU32((volatile uint32_t RT_FAR *)(void RT_FAR *)ppv, (uint32_t)pv); +#elif ARCH_BITS == 64 + ASMAtomicUoWriteU64((volatile uint64_t RT_FAR *)(void RT_FAR *)ppv, (uint64_t)pv); +#else +# error "ARCH_BITS is bogus" +#endif +} + + +/** + * Atomically writes a pointer value, ordered. + * + * @param ppv Pointer to the pointer variable to write. + * @param pv The pointer value to assign to *ppv. If NULL use + * ASMAtomicWriteNullPtr or you'll land in trouble. + * + * @remarks This is relatively type safe on GCC platforms when @a pv isn't + * NULL. + */ +#ifdef __GNUC__ +# define ASMAtomicWritePtr(ppv, pv) \ + do \ + { \ + __typeof__(*(ppv)) volatile RT_FAR * const ppvTypeChecked = (ppv); \ + __typeof__(*(ppv)) const pvTypeChecked = (pv); \ + \ + AssertCompile(sizeof(*ppv) == sizeof(void RT_FAR *)); \ + AssertCompile(sizeof(pv) == sizeof(void RT_FAR *)); \ + Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \ + \ + ASMAtomicWritePtrVoid((void RT_FAR * volatile RT_FAR *)(ppvTypeChecked), (void RT_FAR *)(pvTypeChecked)); \ + } while (0) +#else +# define ASMAtomicWritePtr(ppv, pv) \ + do \ + { \ + AssertCompile(sizeof(*ppv) == sizeof(void RT_FAR *)); \ + AssertCompile(sizeof(pv) == sizeof(void RT_FAR *)); \ + Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \ + \ + ASMAtomicWritePtrVoid((void RT_FAR * volatile RT_FAR *)(ppv), (void RT_FAR *)(pv)); \ + } while (0) +#endif + + +/** + * Atomically sets a pointer to NULL, ordered. + * + * @param ppv Pointer to the pointer variable that should be set to NULL. + * + * @remarks This is relatively type safe on GCC platforms. + */ +#if RT_GNUC_PREREQ(4, 2) +# define ASMAtomicWriteNullPtr(ppv) \ + do \ + { \ + __typeof__(*(ppv)) * const ppvTypeChecked = (ppv); \ + AssertCompile(sizeof(*ppv) == sizeof(void RT_FAR *)); \ + Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \ + ASMAtomicWritePtrVoid((void RT_FAR * volatile RT_FAR *)(ppvTypeChecked), NULL); \ + } while (0) +#else +# define ASMAtomicWriteNullPtr(ppv) \ + do \ + { \ + AssertCompile(sizeof(*ppv) == sizeof(void RT_FAR *)); \ + Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \ + ASMAtomicWritePtrVoid((void RT_FAR * volatile RT_FAR *)(ppv), NULL); \ + } while (0) +#endif + + +/** + * Atomically writes a pointer value, unordered. + * + * @returns Current *pv value + * @param ppv Pointer to the pointer variable. + * @param pv The pointer value to assign to *ppv. If NULL use + * ASMAtomicUoWriteNullPtr or you'll land in trouble. + * + * @remarks This is relatively type safe on GCC platforms when @a pv isn't + * NULL. + */ +#if RT_GNUC_PREREQ(4, 2) +# define ASMAtomicUoWritePtr(ppv, pv) \ + do \ + { \ + __typeof__(*(ppv)) volatile * const ppvTypeChecked = (ppv); \ + __typeof__(*(ppv)) const pvTypeChecked = (pv); \ + \ + AssertCompile(sizeof(*ppv) == sizeof(void *)); \ + AssertCompile(sizeof(pv) == sizeof(void *)); \ + Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \ + \ + *(ppvTypeChecked) = pvTypeChecked; \ + } while (0) +#else +# define ASMAtomicUoWritePtr(ppv, pv) \ + do \ + { \ + AssertCompile(sizeof(*ppv) == sizeof(void RT_FAR *)); \ + AssertCompile(sizeof(pv) == sizeof(void RT_FAR *)); \ + Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \ + *(ppv) = pv; \ + } while (0) +#endif + + +/** + * Atomically sets a pointer to NULL, unordered. + * + * @param ppv Pointer to the pointer variable that should be set to NULL. + * + * @remarks This is relatively type safe on GCC platforms. + */ +#ifdef __GNUC__ +# define ASMAtomicUoWriteNullPtr(ppv) \ + do \ + { \ + __typeof__(*(ppv)) volatile * const ppvTypeChecked = (ppv); \ + AssertCompile(sizeof(*ppv) == sizeof(void *)); \ + Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \ + *(ppvTypeChecked) = NULL; \ + } while (0) +#else +# define ASMAtomicUoWriteNullPtr(ppv) \ + do \ + { \ + AssertCompile(sizeof(*ppv) == sizeof(void RT_FAR *)); \ + Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \ + *(ppv) = NULL; \ + } while (0) +#endif + + +/** + * Atomically write a typical IPRT handle value, ordered. + * + * @param ph Pointer to the variable to update. + * @param hNew The value to assign to *ph. + * + * @remarks This doesn't currently work for all handles (like RTFILE). + */ +#if HC_ARCH_BITS == 32 || ARCH_BITS == 16 +# define ASMAtomicWriteHandle(ph, hNew) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \ + ASMAtomicWriteU32((uint32_t volatile RT_FAR *)(ph), (const uint32_t)(hNew)); \ + } while (0) +#elif HC_ARCH_BITS == 64 +# define ASMAtomicWriteHandle(ph, hNew) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint64_t)); \ + ASMAtomicWriteU64((uint64_t volatile RT_FAR *)(ph), (const uint64_t)(hNew)); \ + } while (0) +#else +# error HC_ARCH_BITS +#endif + + +/** + * Atomically write a typical IPRT handle value, unordered. + * + * @param ph Pointer to the variable to update. + * @param hNew The value to assign to *ph. + * + * @remarks This doesn't currently work for all handles (like RTFILE). + */ +#if HC_ARCH_BITS == 32 || ARCH_BITS == 16 +# define ASMAtomicUoWriteHandle(ph, hNew) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \ + ASMAtomicUoWriteU32((uint32_t volatile RT_FAR *)(ph), (const uint32_t)hNew); \ + } while (0) +#elif HC_ARCH_BITS == 64 +# define ASMAtomicUoWriteHandle(ph, hNew) \ + do { \ + AssertCompile(sizeof(*(ph)) == sizeof(uint64_t)); \ + ASMAtomicUoWriteU64((uint64_t volatile RT_FAR *)(ph), (const uint64_t)hNew); \ + } while (0) +#else +# error HC_ARCH_BITS +#endif + + +/** + * Atomically write a value which size might differ + * between platforms or compilers, ordered. + * + * @param pu Pointer to the variable to update. + * @param uNew The value to assign to *pu. + */ +#define ASMAtomicWriteSize(pu, uNew) \ + do { \ + switch (sizeof(*(pu))) { \ + case 1: ASMAtomicWriteU8( (volatile uint8_t RT_FAR *)(void RT_FAR *)(pu), (uint8_t )(uNew)); break; \ + case 2: ASMAtomicWriteU16((volatile uint16_t RT_FAR *)(void RT_FAR *)(pu), (uint16_t)(uNew)); break; \ + case 4: ASMAtomicWriteU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu), (uint32_t)(uNew)); break; \ + case 8: ASMAtomicWriteU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu), (uint64_t)(uNew)); break; \ + default: AssertMsgFailed(("ASMAtomicWriteSize: size %d is not supported\n", sizeof(*(pu)))); \ + } \ + } while (0) + +/** + * Atomically write a value which size might differ + * between platforms or compilers, unordered. + * + * @param pu Pointer to the variable to update. + * @param uNew The value to assign to *pu. + */ +#define ASMAtomicUoWriteSize(pu, uNew) \ + do { \ + switch (sizeof(*(pu))) { \ + case 1: ASMAtomicUoWriteU8( (volatile uint8_t RT_FAR *)(void RT_FAR *)(pu), (uint8_t )(uNew)); break; \ + case 2: ASMAtomicUoWriteU16((volatile uint16_t RT_FAR *)(void RT_FAR *)(pu), (uint16_t)(uNew)); break; \ + case 4: ASMAtomicUoWriteU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu), (uint32_t)(uNew)); break; \ + case 8: ASMAtomicUoWriteU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu), (uint64_t)(uNew)); break; \ + default: AssertMsgFailed(("ASMAtomicWriteSize: size %d is not supported\n", sizeof(*(pu)))); \ + } \ + } while (0) + + + +/** + * Atomically exchanges and adds to a 16-bit value, ordered. + * + * @returns The old value. + * @param pu16 Pointer to the value. + * @param u16 Number to add. + * + * @remarks Currently not implemented, just to make 16-bit code happy. + * @remarks x86: Requires a 486 or later. + */ +RT_ASM_DECL_PRAGMA_WATCOM(uint16_t) ASMAtomicAddU16(uint16_t volatile RT_FAR *pu16, uint32_t u16) RT_NOTHROW_PROTO; + + +/** + * Atomically exchanges and adds to a 32-bit value, ordered. + * + * @returns The old value. + * @param pu32 Pointer to the value. + * @param u32 Number to add. + * + * @remarks x86: Requires a 486 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMAtomicAddU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMAtomicAddU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + u32 = _InterlockedExchangeAdd((long RT_FAR *)pu32, u32); + return u32; + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; xaddl %0, %1\n\t" + : "=r" (u32) + , "=m" (*pu32) + : "0" (u32) + , "m" (*pu32) + : "memory" + , "cc"); + return u32; +# else + __asm + { + mov eax, [u32] +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + lock xadd [rdx], eax +# else + mov edx, [pu32] + lock xadd [edx], eax +# endif + mov [u32], eax + } + return u32; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(ASMAtomicAddU32, pu32, DMB_SY, + "add %w[uNew], %w[uOld], %w[uVal]\n\t", + "add %[uNew], %[uOld], %[uVal]\n\t", + [uVal] "r" (u32)); + return u32OldRet; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically exchanges and adds to a signed 32-bit value, ordered. + * + * @returns The old value. + * @param pi32 Pointer to the value. + * @param i32 Number to add. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(int32_t) ASMAtomicAddS32(int32_t volatile RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + return (int32_t)ASMAtomicAddU32((uint32_t volatile RT_FAR *)pi32, (uint32_t)i32); +} + + +/** + * Atomically exchanges and adds to a 64-bit value, ordered. + * + * @returns The old value. + * @param pu64 Pointer to the value. + * @param u64 Number to add. + * + * @remarks x86: Requires a Pentium or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +DECLASM(uint64_t) ASMAtomicAddU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint64_t) ASMAtomicAddU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_AMD64) + u64 = _InterlockedExchangeAdd64((__int64 RT_FAR *)pu64, u64); + return u64; + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + __asm__ __volatile__("lock; xaddq %0, %1\n\t" + : "=r" (u64) + , "=m" (*pu64) + : "0" (u64) + , "m" (*pu64) + : "memory" + , "cc"); + return u64; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_64(ASMAtomicAddU64, pu64, DMB_SY, + "add %[uNew], %[uOld], %[uVal]\n\t" + , + "add %[uNew], %[uOld], %[uVal]\n\t" + "adc %H[uNew], %H[uOld], %H[uVal]\n\t", + [uVal] "r" (u64)); + return u64OldRet; + +# else + uint64_t u64Old; + for (;;) + { + uint64_t u64New; + u64Old = ASMAtomicUoReadU64(pu64); + u64New = u64Old + u64; + if (ASMAtomicCmpXchgU64(pu64, u64New, u64Old)) + break; + ASMNopPause(); + } + return u64Old; +# endif +} +#endif + + +/** + * Atomically exchanges and adds to a signed 64-bit value, ordered. + * + * @returns The old value. + * @param pi64 Pointer to the value. + * @param i64 Number to add. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(int64_t) ASMAtomicAddS64(int64_t volatile RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + return (int64_t)ASMAtomicAddU64((uint64_t volatile RT_FAR *)pi64, (uint64_t)i64); +} + + +/** + * Atomically exchanges and adds to a size_t value, ordered. + * + * @returns The old value. + * @param pcb Pointer to the size_t value. + * @param cb Number to add. + */ +DECLINLINE(size_t) ASMAtomicAddZ(size_t volatile RT_FAR *pcb, size_t cb) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 64 + AssertCompileSize(size_t, 8); + return ASMAtomicAddU64((uint64_t volatile RT_FAR *)pcb, cb); +#elif ARCH_BITS == 32 + AssertCompileSize(size_t, 4); + return ASMAtomicAddU32((uint32_t volatile RT_FAR *)pcb, cb); +#elif ARCH_BITS == 16 + AssertCompileSize(size_t, 2); + return ASMAtomicAddU16((uint16_t volatile RT_FAR *)pcb, cb); +#else +# error "Unsupported ARCH_BITS value" +#endif +} + + +/** + * Atomically exchanges and adds a value which size might differ between + * platforms or compilers, ordered. + * + * @param pu Pointer to the variable to update. + * @param uNew The value to add to *pu. + * @param puOld Where to store the old value. + */ +#define ASMAtomicAddSize(pu, uNew, puOld) \ + do { \ + switch (sizeof(*(pu))) { \ + case 4: *(uint32_t *)(puOld) = ASMAtomicAddU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu), (uint32_t)(uNew)); break; \ + case 8: *(uint64_t *)(puOld) = ASMAtomicAddU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu), (uint64_t)(uNew)); break; \ + default: AssertMsgFailed(("ASMAtomicAddSize: size %d is not supported\n", sizeof(*(pu)))); \ + } \ + } while (0) + + + +/** + * Atomically exchanges and subtracts to an unsigned 16-bit value, ordered. + * + * @returns The old value. + * @param pu16 Pointer to the value. + * @param u16 Number to subtract. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(uint16_t) ASMAtomicSubU16(uint16_t volatile RT_FAR *pu16, uint32_t u16) RT_NOTHROW_DEF +{ + return ASMAtomicAddU16(pu16, (uint16_t)-(int16_t)u16); +} + + +/** + * Atomically exchanges and subtracts to a signed 16-bit value, ordered. + * + * @returns The old value. + * @param pi16 Pointer to the value. + * @param i16 Number to subtract. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(int16_t) ASMAtomicSubS16(int16_t volatile RT_FAR *pi16, int16_t i16) RT_NOTHROW_DEF +{ + return (int16_t)ASMAtomicAddU16((uint16_t volatile RT_FAR *)pi16, (uint16_t)-i16); +} + + +/** + * Atomically exchanges and subtracts to an unsigned 32-bit value, ordered. + * + * @returns The old value. + * @param pu32 Pointer to the value. + * @param u32 Number to subtract. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(uint32_t) ASMAtomicSubU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ + return ASMAtomicAddU32(pu32, (uint32_t)-(int32_t)u32); +} + + +/** + * Atomically exchanges and subtracts to a signed 32-bit value, ordered. + * + * @returns The old value. + * @param pi32 Pointer to the value. + * @param i32 Number to subtract. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(int32_t) ASMAtomicSubS32(int32_t volatile RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + return (int32_t)ASMAtomicAddU32((uint32_t volatile RT_FAR *)pi32, (uint32_t)-i32); +} + + +/** + * Atomically exchanges and subtracts to an unsigned 64-bit value, ordered. + * + * @returns The old value. + * @param pu64 Pointer to the value. + * @param u64 Number to subtract. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(uint64_t) ASMAtomicSubU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ + return ASMAtomicAddU64(pu64, (uint64_t)-(int64_t)u64); +} + + +/** + * Atomically exchanges and subtracts to a signed 64-bit value, ordered. + * + * @returns The old value. + * @param pi64 Pointer to the value. + * @param i64 Number to subtract. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(int64_t) ASMAtomicSubS64(int64_t volatile RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + return (int64_t)ASMAtomicAddU64((uint64_t volatile RT_FAR *)pi64, (uint64_t)-i64); +} + + +/** + * Atomically exchanges and subtracts to a size_t value, ordered. + * + * @returns The old value. + * @param pcb Pointer to the size_t value. + * @param cb Number to subtract. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(size_t) ASMAtomicSubZ(size_t volatile RT_FAR *pcb, size_t cb) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 64 + return ASMAtomicSubU64((uint64_t volatile RT_FAR *)pcb, cb); +#elif ARCH_BITS == 32 + return ASMAtomicSubU32((uint32_t volatile RT_FAR *)pcb, cb); +#elif ARCH_BITS == 16 + AssertCompileSize(size_t, 2); + return ASMAtomicSubU16((uint16_t volatile RT_FAR *)pcb, cb); +#else +# error "Unsupported ARCH_BITS value" +#endif +} + + +/** + * Atomically exchanges and subtracts a value which size might differ between + * platforms or compilers, ordered. + * + * @param pu Pointer to the variable to update. + * @param uNew The value to subtract to *pu. + * @param puOld Where to store the old value. + * + * @remarks x86: Requires a 486 or later. + */ +#define ASMAtomicSubSize(pu, uNew, puOld) \ + do { \ + switch (sizeof(*(pu))) { \ + case 4: *(uint32_t RT_FAR *)(puOld) = ASMAtomicSubU32((volatile uint32_t RT_FAR *)(void RT_FAR *)(pu), (uint32_t)(uNew)); break; \ + case 8: *(uint64_t RT_FAR *)(puOld) = ASMAtomicSubU64((volatile uint64_t RT_FAR *)(void RT_FAR *)(pu), (uint64_t)(uNew)); break; \ + default: AssertMsgFailed(("ASMAtomicSubSize: size %d is not supported\n", sizeof(*(pu)))); \ + } \ + } while (0) + + + +/** + * Atomically increment a 16-bit value, ordered. + * + * @returns The new value. + * @param pu16 Pointer to the value to increment. + * @remarks Not implemented. Just to make 16-bit code happy. + * + * @remarks x86: Requires a 486 or later. + */ +RT_ASM_DECL_PRAGMA_WATCOM(uint16_t) ASMAtomicIncU16(uint16_t volatile RT_FAR *pu16) RT_NOTHROW_PROTO; + + +/** + * Atomically increment a 32-bit value, ordered. + * + * @returns The new value. + * @param pu32 Pointer to the value to increment. + * + * @remarks x86: Requires a 486 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMAtomicIncU32(uint32_t volatile RT_FAR *pu32) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMAtomicIncU32(uint32_t volatile RT_FAR *pu32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + return (uint32_t)_InterlockedIncrement((long RT_FAR *)pu32); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + uint32_t u32; + __asm__ __volatile__("lock; xaddl %0, %1\n\t" + : "=r" (u32) + , "=m" (*pu32) + : "0" (1) + , "m" (*pu32) + : "memory" + , "cc"); + return u32+1; +# else + __asm + { + mov eax, 1 +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + lock xadd [rdx], eax +# else + mov edx, [pu32] + lock xadd [edx], eax +# endif + mov u32, eax + } + return u32+1; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicIncU32, pu32, DMB_SY, + "add %w[uNew], %w[uNew], #1\n\t", + "add %[uNew], %[uNew], #1\n\t" /* arm6 / thumb2+ */, + "X" (0) /* dummy */); + return u32NewRet; + +# else + return ASMAtomicAddU32(pu32, 1) + 1; +# endif +} +#endif + + +/** + * Atomically increment a signed 32-bit value, ordered. + * + * @returns The new value. + * @param pi32 Pointer to the value to increment. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(int32_t) ASMAtomicIncS32(int32_t volatile RT_FAR *pi32) RT_NOTHROW_DEF +{ + return (int32_t)ASMAtomicIncU32((uint32_t volatile RT_FAR *)pi32); +} + + +/** + * Atomically increment a 64-bit value, ordered. + * + * @returns The new value. + * @param pu64 Pointer to the value to increment. + * + * @remarks x86: Requires a Pentium or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +DECLASM(uint64_t) ASMAtomicIncU64(uint64_t volatile RT_FAR *pu64) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint64_t) ASMAtomicIncU64(uint64_t volatile RT_FAR *pu64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_AMD64) + return (uint64_t)_InterlockedIncrement64((__int64 RT_FAR *)pu64); + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + uint64_t u64; + __asm__ __volatile__("lock; xaddq %0, %1\n\t" + : "=r" (u64) + , "=m" (*pu64) + : "0" (1) + , "m" (*pu64) + : "memory" + , "cc"); + return u64 + 1; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_64(ASMAtomicIncU64, pu64, DMB_SY, + "add %[uNew], %[uNew], #1\n\t" + , + "add %[uNew], %[uNew], #1\n\t" /* arm6 / thumb2+ */ + "adc %H[uNew], %H[uNew], %[uZeroVal]\n\t", + RTASM_ARM_PICK_6432("X" (0) /* dummy */, [uZeroVal] "r" (0)) ); + return u64NewRet; + +# else + return ASMAtomicAddU64(pu64, 1) + 1; +# endif +} +#endif + + +/** + * Atomically increment a signed 64-bit value, ordered. + * + * @returns The new value. + * @param pi64 Pointer to the value to increment. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(int64_t) ASMAtomicIncS64(int64_t volatile RT_FAR *pi64) RT_NOTHROW_DEF +{ + return (int64_t)ASMAtomicIncU64((uint64_t volatile RT_FAR *)pi64); +} + + +/** + * Atomically increment a size_t value, ordered. + * + * @returns The new value. + * @param pcb Pointer to the value to increment. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(size_t) ASMAtomicIncZ(size_t volatile RT_FAR *pcb) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 64 + return ASMAtomicIncU64((uint64_t volatile RT_FAR *)pcb); +#elif ARCH_BITS == 32 + return ASMAtomicIncU32((uint32_t volatile RT_FAR *)pcb); +#elif ARCH_BITS == 16 + return ASMAtomicIncU16((uint16_t volatile RT_FAR *)pcb); +#else +# error "Unsupported ARCH_BITS value" +#endif +} + + + +/** + * Atomically decrement an unsigned 32-bit value, ordered. + * + * @returns The new value. + * @param pu16 Pointer to the value to decrement. + * @remarks Not implemented. Just to make 16-bit code happy. + * + * @remarks x86: Requires a 486 or later. + */ +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMAtomicDecU16(uint16_t volatile RT_FAR *pu16) RT_NOTHROW_PROTO; + + +/** + * Atomically decrement an unsigned 32-bit value, ordered. + * + * @returns The new value. + * @param pu32 Pointer to the value to decrement. + * + * @remarks x86: Requires a 486 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMAtomicDecU32(uint32_t volatile RT_FAR *pu32) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMAtomicDecU32(uint32_t volatile RT_FAR *pu32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + return (uint32_t)_InterlockedDecrement((long RT_FAR *)pu32); + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) +# if RT_INLINE_ASM_GNU_STYLE + uint32_t u32; + __asm__ __volatile__("lock; xaddl %0, %1\n\t" + : "=r" (u32) + , "=m" (*pu32) + : "0" (-1) + , "m" (*pu32) + : "memory" + , "cc"); + return u32-1; +# else + uint32_t u32; + __asm + { + mov eax, -1 +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + lock xadd [rdx], eax +# else + mov edx, [pu32] + lock xadd [edx], eax +# endif + mov u32, eax + } + return u32-1; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicDecU32, pu32, DMB_SY, + "sub %w[uNew], %w[uNew], #1\n\t", + "sub %[uNew], %[uNew], #1\n\t" /* arm6 / thumb2+ */, + "X" (0) /* dummy */); + return u32NewRet; + +# else + return ASMAtomicSubU32(pu32, 1) - (uint32_t)1; +# endif +} +#endif + + +/** + * Atomically decrement a signed 32-bit value, ordered. + * + * @returns The new value. + * @param pi32 Pointer to the value to decrement. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(int32_t) ASMAtomicDecS32(int32_t volatile RT_FAR *pi32) RT_NOTHROW_DEF +{ + return (int32_t)ASMAtomicDecU32((uint32_t volatile RT_FAR *)pi32); +} + + +/** + * Atomically decrement an unsigned 64-bit value, ordered. + * + * @returns The new value. + * @param pu64 Pointer to the value to decrement. + * + * @remarks x86: Requires a Pentium or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMAtomicDecU64(uint64_t volatile RT_FAR *pu64) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint64_t) ASMAtomicDecU64(uint64_t volatile RT_FAR *pu64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_AMD64) + return (uint64_t)_InterlockedDecrement64((__int64 volatile RT_FAR *)pu64); + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + uint64_t u64; + __asm__ __volatile__("lock; xaddq %q0, %1\n\t" + : "=r" (u64) + , "=m" (*pu64) + : "0" (~(uint64_t)0) + , "m" (*pu64) + : "memory" + , "cc"); + return u64-1; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_64(ASMAtomicDecU64, pu64, DMB_SY, + "sub %[uNew], %[uNew], #1\n\t" + , + "sub %[uNew], %[uNew], #1\n\t" /* arm6 / thumb2+ */ + "sbc %H[uNew], %H[uNew], %[uZeroVal]\n\t", + RTASM_ARM_PICK_6432("X" (0) /* dummy */, [uZeroVal] "r" (0)) ); + return u64NewRet; + +# else + return ASMAtomicAddU64(pu64, UINT64_MAX) - 1; +# endif +} +#endif + + +/** + * Atomically decrement a signed 64-bit value, ordered. + * + * @returns The new value. + * @param pi64 Pointer to the value to decrement. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(int64_t) ASMAtomicDecS64(int64_t volatile RT_FAR *pi64) RT_NOTHROW_DEF +{ + return (int64_t)ASMAtomicDecU64((uint64_t volatile RT_FAR *)pi64); +} + + +/** + * Atomically decrement a size_t value, ordered. + * + * @returns The new value. + * @param pcb Pointer to the value to decrement. + * + * @remarks x86: Requires a 486 or later. + */ +DECLINLINE(size_t) ASMAtomicDecZ(size_t volatile RT_FAR *pcb) RT_NOTHROW_DEF +{ +#if ARCH_BITS == 64 + return ASMAtomicDecU64((uint64_t volatile RT_FAR *)pcb); +#elif ARCH_BITS == 32 + return ASMAtomicDecU32((uint32_t volatile RT_FAR *)pcb); +#elif ARCH_BITS == 16 + return ASMAtomicDecU16((uint16_t volatile RT_FAR *)pcb); +#else +# error "Unsupported ARCH_BITS value" +#endif +} + + +/** + * Atomically Or an unsigned 32-bit value, ordered. + * + * @param pu32 Pointer to the pointer variable to OR u32 with. + * @param u32 The value to OR *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicOrU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicOrU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + _InterlockedOr((long volatile RT_FAR *)pu32, (long)u32); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; orl %1, %0\n\t" + : "=m" (*pu32) + : "ir" (u32) + , "m" (*pu32) + : "cc"); +# else + __asm + { + mov eax, [u32] +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + lock or [rdx], eax +# else + mov edx, [pu32] + lock or [edx], eax +# endif + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + /* For more on Orr see https://en.wikipedia.org/wiki/Orr_(Catch-22) ;-) */ + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicOr32, pu32, DMB_SY, + "orr %w[uNew], %w[uNew], %w[uVal]\n\t", + "orr %[uNew], %[uNew], %[uVal]\n\t", + [uVal] "r" (u32)); + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically OR an unsigned 32-bit value, ordered, extended version (for bitmap + * fallback). + * + * @returns Old value. + * @param pu32 Pointer to the variable to OR @a u32 with. + * @param u32 The value to OR @a *pu32 with. + */ +DECLINLINE(uint32_t) ASMAtomicOrExU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(ASMAtomicOrEx32, pu32, DMB_SY, + "orr %w[uNew], %w[uOld], %w[uVal]\n\t", + "orr %[uNew], %[uOld], %[uVal]\n\t", + [uVal] "r" (u32)); + return u32OldRet; + +#else + uint32_t u32RetOld = ASMAtomicUoReadU32(pu32); + uint32_t u32New; + do + u32New = u32RetOld | u32; + while (!ASMAtomicCmpXchgExU32(pu32, u32New, u32RetOld, &u32RetOld)); + return u32RetOld; +#endif +} + + +/** + * Atomically Or a signed 32-bit value, ordered. + * + * @param pi32 Pointer to the pointer variable to OR u32 with. + * @param i32 The value to OR *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +DECLINLINE(void) ASMAtomicOrS32(int32_t volatile RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + ASMAtomicOrU32((uint32_t volatile RT_FAR *)pi32, (uint32_t)i32); +} + + +/** + * Atomically Or an unsigned 64-bit value, ordered. + * + * @param pu64 Pointer to the pointer variable to OR u64 with. + * @param u64 The value to OR *pu64 with. + * + * @remarks x86: Requires a Pentium or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +DECLASM(void) ASMAtomicOrU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicOrU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_AMD64) + _InterlockedOr64((__int64 volatile RT_FAR *)pu64, (__int64)u64); + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + __asm__ __volatile__("lock; orq %1, %q0\n\t" + : "=m" (*pu64) + : "r" (u64) + , "m" (*pu64) + : "cc"); + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_64(ASMAtomicOrU64, pu64, DMB_SY, + "orr %[uNew], %[uNew], %[uVal]\n\t" + , + "orr %[uNew], %[uNew], %[uVal]\n\t" + "orr %H[uNew], %H[uNew], %H[uVal]\n\t", + [uVal] "r" (u64)); + +# else + for (;;) + { + uint64_t u64Old = ASMAtomicUoReadU64(pu64); + uint64_t u64New = u64Old | u64; + if (ASMAtomicCmpXchgU64(pu64, u64New, u64Old)) + break; + ASMNopPause(); + } +# endif +} +#endif + + +/** + * Atomically Or a signed 64-bit value, ordered. + * + * @param pi64 Pointer to the pointer variable to OR u64 with. + * @param i64 The value to OR *pu64 with. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(void) ASMAtomicOrS64(int64_t volatile RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + ASMAtomicOrU64((uint64_t volatile RT_FAR *)pi64, (uint64_t)i64); +} + + +/** + * Atomically And an unsigned 32-bit value, ordered. + * + * @param pu32 Pointer to the pointer variable to AND u32 with. + * @param u32 The value to AND *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicAndU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicAndU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + _InterlockedAnd((long volatile RT_FAR *)pu32, u32); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; andl %1, %0\n\t" + : "=m" (*pu32) + : "ir" (u32) + , "m" (*pu32) + : "cc"); +# else + __asm + { + mov eax, [u32] +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + lock and [rdx], eax +# else + mov edx, [pu32] + lock and [edx], eax +# endif + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicAnd32, pu32, DMB_SY, + "and %w[uNew], %w[uNew], %w[uVal]\n\t", + "and %[uNew], %[uNew], %[uVal]\n\t", + [uVal] "r" (u32)); + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically AND an unsigned 32-bit value, ordered, extended version. + * + * @returns Old value. + * @param pu32 Pointer to the variable to AND @a u32 with. + * @param u32 The value to AND @a *pu32 with. + */ +DECLINLINE(uint32_t) ASMAtomicAndExU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(ASMAtomicAndEx32, pu32, DMB_SY, + "and %w[uNew], %w[uOld], %w[uVal]\n\t", + "and %[uNew], %[uOld], %[uVal]\n\t", + [uVal] "r" (u32)); + return u32OldRet; + +#else + uint32_t u32RetOld = ASMAtomicUoReadU32(pu32); + uint32_t u32New; + do + u32New = u32RetOld & u32; + while (!ASMAtomicCmpXchgExU32(pu32, u32New, u32RetOld, &u32RetOld)); + return u32RetOld; +#endif +} + + +/** + * Atomically And a signed 32-bit value, ordered. + * + * @param pi32 Pointer to the pointer variable to AND i32 with. + * @param i32 The value to AND *pi32 with. + * + * @remarks x86: Requires a 386 or later. + */ +DECLINLINE(void) ASMAtomicAndS32(int32_t volatile RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + ASMAtomicAndU32((uint32_t volatile RT_FAR *)pi32, (uint32_t)i32); +} + + +/** + * Atomically And an unsigned 64-bit value, ordered. + * + * @param pu64 Pointer to the pointer variable to AND u64 with. + * @param u64 The value to AND *pu64 with. + * + * @remarks x86: Requires a Pentium or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +DECLASM(void) ASMAtomicAndU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicAndU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_AMD64) + _InterlockedAnd64((__int64 volatile RT_FAR *)pu64, u64); + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + __asm__ __volatile__("lock; andq %1, %0\n\t" + : "=m" (*pu64) + : "r" (u64) + , "m" (*pu64) + : "cc"); + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_64(ASMAtomicAndU64, pu64, DMB_SY, + "and %[uNew], %[uNew], %[uVal]\n\t" + , + "and %[uNew], %[uNew], %[uVal]\n\t" + "and %H[uNew], %H[uNew], %H[uVal]\n\t", + [uVal] "r" (u64)); + +# else + for (;;) + { + uint64_t u64Old = ASMAtomicUoReadU64(pu64); + uint64_t u64New = u64Old & u64; + if (ASMAtomicCmpXchgU64(pu64, u64New, u64Old)) + break; + ASMNopPause(); + } +# endif +} +#endif + + +/** + * Atomically And a signed 64-bit value, ordered. + * + * @param pi64 Pointer to the pointer variable to AND i64 with. + * @param i64 The value to AND *pi64 with. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(void) ASMAtomicAndS64(int64_t volatile RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + ASMAtomicAndU64((uint64_t volatile RT_FAR *)pi64, (uint64_t)i64); +} + + +/** + * Atomically XOR an unsigned 32-bit value and a memory location, ordered. + * + * @param pu32 Pointer to the variable to XOR @a u32 with. + * @param u32 The value to XOR @a *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicXorU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicXorU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + _InterlockedXor((long volatile RT_FAR *)pu32, u32); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; xorl %1, %0\n\t" + : "=m" (*pu32) + : "ir" (u32) + , "m" (*pu32) + : "cc"); +# else + __asm + { + mov eax, [u32] +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + lock xor [rdx], eax +# else + mov edx, [pu32] + lock xor [edx], eax +# endif + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicXor32, pu32, DMB_SY, + "eor %w[uNew], %w[uNew], %w[uVal]\n\t", + "eor %[uNew], %[uNew], %[uVal]\n\t", + [uVal] "r" (u32)); + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically XOR an unsigned 32-bit value and a memory location, ordered, + * extended version (for bitmaps). + * + * @returns Old value. + * @param pu32 Pointer to the variable to XOR @a u32 with. + * @param u32 The value to XOR @a *pu32 with. + */ +DECLINLINE(uint32_t) ASMAtomicXorExU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(ASMAtomicXorEx32, pu32, DMB_SY, + "eor %w[uNew], %w[uOld], %w[uVal]\n\t", + "eor %[uNew], %[uOld], %[uVal]\n\t", + [uVal] "r" (u32)); + return u32OldRet; + +#else + uint32_t u32RetOld = ASMAtomicUoReadU32(pu32); + uint32_t u32New; + do + u32New = u32RetOld ^ u32; + while (!ASMAtomicCmpXchgExU32(pu32, u32New, u32RetOld, &u32RetOld)); + return u32RetOld; +#endif +} + + +/** + * Atomically XOR a signed 32-bit value, ordered. + * + * @param pi32 Pointer to the variable to XOR i32 with. + * @param i32 The value to XOR *pi32 with. + * + * @remarks x86: Requires a 386 or later. + */ +DECLINLINE(void) ASMAtomicXorS32(int32_t volatile RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + ASMAtomicXorU32((uint32_t volatile RT_FAR *)pi32, (uint32_t)i32); +} + + +/** + * Atomically OR an unsigned 32-bit value, unordered but interrupt safe. + * + * @param pu32 Pointer to the pointer variable to OR u32 with. + * @param u32 The value to OR *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicUoOrU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicUoOrU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("orl %1, %0\n\t" + : "=m" (*pu32) + : "ir" (u32) + , "m" (*pu32) + : "cc"); +# else + __asm + { + mov eax, [u32] +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + or [rdx], eax +# else + mov edx, [pu32] + or [edx], eax +# endif + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicUoOrU32, pu32, NO_BARRIER, + "orr %w[uNew], %w[uNew], %w[uVal]\n\t", + "orr %[uNew], %[uNew], %[uVal]\n\t", + [uVal] "r" (u32)); + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically OR an unsigned 32-bit value, unordered but interrupt safe, + * extended version (for bitmap fallback). + * + * @returns Old value. + * @param pu32 Pointer to the variable to OR @a u32 with. + * @param u32 The value to OR @a *pu32 with. + */ +DECLINLINE(uint32_t) ASMAtomicUoOrExU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(ASMAtomicUoOrExU32, pu32, NO_BARRIER, + "orr %w[uNew], %w[uOld], %w[uVal]\n\t", + "orr %[uNew], %[uOld], %[uVal]\n\t", + [uVal] "r" (u32)); + return u32OldRet; + +#else + return ASMAtomicOrExU32(pu32, u32); /* (we have no unordered cmpxchg primitive atm.) */ +#endif +} + + +/** + * Atomically OR a signed 32-bit value, unordered. + * + * @param pi32 Pointer to the pointer variable to OR u32 with. + * @param i32 The value to OR *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +DECLINLINE(void) ASMAtomicUoOrS32(int32_t volatile RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + ASMAtomicUoOrU32((uint32_t volatile RT_FAR *)pi32, (uint32_t)i32); +} + + +/** + * Atomically OR an unsigned 64-bit value, unordered. + * + * @param pu64 Pointer to the pointer variable to OR u64 with. + * @param u64 The value to OR *pu64 with. + * + * @remarks x86: Requires a Pentium or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +DECLASM(void) ASMAtomicUoOrU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicUoOrU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + __asm__ __volatile__("orq %1, %q0\n\t" + : "=m" (*pu64) + : "r" (u64) + , "m" (*pu64) + : "cc"); + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_64(ASMAtomicUoOrU64, pu64, NO_BARRIER, + "orr %[uNew], %[uNew], %[uVal]\n\t" + , + "orr %[uNew], %[uNew], %[uVal]\n\t" + "orr %H[uNew], %H[uNew], %H[uVal]\n\t", + [uVal] "r" (u64)); + +# else + for (;;) + { + uint64_t u64Old = ASMAtomicUoReadU64(pu64); + uint64_t u64New = u64Old | u64; + if (ASMAtomicCmpXchgU64(pu64, u64New, u64Old)) + break; + ASMNopPause(); + } +# endif +} +#endif + + +/** + * Atomically Or a signed 64-bit value, unordered. + * + * @param pi64 Pointer to the pointer variable to OR u64 with. + * @param i64 The value to OR *pu64 with. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(void) ASMAtomicUoOrS64(int64_t volatile RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + ASMAtomicUoOrU64((uint64_t volatile RT_FAR *)pi64, (uint64_t)i64); +} + + +/** + * Atomically And an unsigned 32-bit value, unordered. + * + * @param pu32 Pointer to the pointer variable to AND u32 with. + * @param u32 The value to AND *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicUoAndU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicUoAndU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("andl %1, %0\n\t" + : "=m" (*pu32) + : "ir" (u32) + , "m" (*pu32) + : "cc"); +# else + __asm + { + mov eax, [u32] +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + and [rdx], eax +# else + mov edx, [pu32] + and [edx], eax +# endif + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicUoAnd32, pu32, NO_BARRIER, + "and %w[uNew], %w[uNew], %w[uVal]\n\t", + "and %[uNew], %[uNew], %[uVal]\n\t", + [uVal] "r" (u32)); + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically AND an unsigned 32-bit value, unordered, extended version (for + * bitmap fallback). + * + * @returns Old value. + * @param pu32 Pointer to the pointer to AND @a u32 with. + * @param u32 The value to AND @a *pu32 with. + */ +DECLINLINE(uint32_t) ASMAtomicUoAndExU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(ASMAtomicUoAndEx32, pu32, NO_BARRIER, + "and %w[uNew], %w[uOld], %w[uVal]\n\t", + "and %[uNew], %[uOld], %[uVal]\n\t", + [uVal] "r" (u32)); + return u32OldRet; + +#else + return ASMAtomicAndExU32(pu32, u32); /* (we have no unordered cmpxchg primitive atm.) */ +#endif +} + + +/** + * Atomically And a signed 32-bit value, unordered. + * + * @param pi32 Pointer to the pointer variable to AND i32 with. + * @param i32 The value to AND *pi32 with. + * + * @remarks x86: Requires a 386 or later. + */ +DECLINLINE(void) ASMAtomicUoAndS32(int32_t volatile RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + ASMAtomicUoAndU32((uint32_t volatile RT_FAR *)pi32, (uint32_t)i32); +} + + +/** + * Atomically And an unsigned 64-bit value, unordered. + * + * @param pu64 Pointer to the pointer variable to AND u64 with. + * @param u64 The value to AND *pu64 with. + * + * @remarks x86: Requires a Pentium or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +DECLASM(void) ASMAtomicUoAndU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicUoAndU64(uint64_t volatile RT_FAR *pu64, uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + __asm__ __volatile__("andq %1, %0\n\t" + : "=m" (*pu64) + : "r" (u64) + , "m" (*pu64) + : "cc"); + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_64(ASMAtomicUoAndU64, pu64, NO_BARRIER, + "and %[uNew], %[uNew], %[uVal]\n\t" + , + "and %[uNew], %[uNew], %[uVal]\n\t" + "and %H[uNew], %H[uNew], %H[uVal]\n\t", + [uVal] "r" (u64)); + +# else + for (;;) + { + uint64_t u64Old = ASMAtomicUoReadU64(pu64); + uint64_t u64New = u64Old & u64; + if (ASMAtomicCmpXchgU64(pu64, u64New, u64Old)) + break; + ASMNopPause(); + } +# endif +} +#endif + + +/** + * Atomically And a signed 64-bit value, unordered. + * + * @param pi64 Pointer to the pointer variable to AND i64 with. + * @param i64 The value to AND *pi64 with. + * + * @remarks x86: Requires a Pentium or later. + */ +DECLINLINE(void) ASMAtomicUoAndS64(int64_t volatile RT_FAR *pi64, int64_t i64) RT_NOTHROW_DEF +{ + ASMAtomicUoAndU64((uint64_t volatile RT_FAR *)pi64, (uint64_t)i64); +} + + +/** + * Atomically XOR an unsigned 32-bit value, unordered but interrupt safe. + * + * @param pu32 Pointer to the variable to XOR @a u32 with. + * @param u32 The value to OR @a *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicUoXorU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicUoXorU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("xorl %1, %0\n\t" + : "=m" (*pu32) + : "ir" (u32) + , "m" (*pu32) + : "cc"); +# else + __asm + { + mov eax, [u32] +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + xor [rdx], eax +# else + mov edx, [pu32] + xor [edx], eax +# endif + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicUoXorU32, pu32, NO_BARRIER, + "eor %w[uNew], %w[uNew], %w[uVal]\n\t", + "eor %[uNew], %[uNew], %[uVal]\n\t", + [uVal] "r" (u32)); + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically XOR an unsigned 32-bit value, unordered but interrupt safe, + * extended version (for bitmap fallback). + * + * @returns Old value. + * @param pu32 Pointer to the variable to XOR @a u32 with. + * @param u32 The value to OR @a *pu32 with. + */ +DECLINLINE(uint32_t) ASMAtomicUoXorExU32(uint32_t volatile RT_FAR *pu32, uint32_t u32) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_OLD_32(ASMAtomicUoXorExU32, pu32, NO_BARRIER, + "eor %w[uNew], %w[uOld], %w[uVal]\n\t", + "eor %[uNew], %[uOld], %[uVal]\n\t", + [uVal] "r" (u32)); + return u32OldRet; + +#else + return ASMAtomicXorExU32(pu32, u32); /* (we have no unordered cmpxchg primitive atm.) */ +#endif +} + + +/** + * Atomically XOR a signed 32-bit value, unordered. + * + * @param pi32 Pointer to the variable to XOR @a u32 with. + * @param i32 The value to XOR @a *pu32 with. + * + * @remarks x86: Requires a 386 or later. + */ +DECLINLINE(void) ASMAtomicUoXorS32(int32_t volatile RT_FAR *pi32, int32_t i32) RT_NOTHROW_DEF +{ + ASMAtomicUoXorU32((uint32_t volatile RT_FAR *)pi32, (uint32_t)i32); +} + + +/** + * Atomically increment an unsigned 32-bit value, unordered. + * + * @returns the new value. + * @param pu32 Pointer to the variable to increment. + * + * @remarks x86: Requires a 486 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMAtomicUoIncU32(uint32_t volatile RT_FAR *pu32) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMAtomicUoIncU32(uint32_t volatile RT_FAR *pu32) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) + uint32_t u32; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("xaddl %0, %1\n\t" + : "=r" (u32) + , "=m" (*pu32) + : "0" (1) + , "m" (*pu32) + : "memory" /** @todo why 'memory'? */ + , "cc"); + return u32 + 1; +# else + __asm + { + mov eax, 1 +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + xadd [rdx], eax +# else + mov edx, [pu32] + xadd [edx], eax +# endif + mov u32, eax + } + return u32 + 1; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicUoIncU32, pu32, NO_BARRIER, + "add %w[uNew], %w[uNew], #1\n\t", + "add %[uNew], %[uNew], #1\n\t" /* arm6 / thumb2+ */, + "X" (0) /* dummy */); + return u32NewRet; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Atomically decrement an unsigned 32-bit value, unordered. + * + * @returns the new value. + * @param pu32 Pointer to the variable to decrement. + * + * @remarks x86: Requires a 486 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMAtomicUoDecU32(uint32_t volatile RT_FAR *pu32) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMAtomicUoDecU32(uint32_t volatile RT_FAR *pu32) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) + uint32_t u32; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; xaddl %0, %1\n\t" + : "=r" (u32) + , "=m" (*pu32) + : "0" (-1) + , "m" (*pu32) + : "memory" + , "cc"); + return u32 - 1; +# else + __asm + { + mov eax, -1 +# ifdef RT_ARCH_AMD64 + mov rdx, [pu32] + xadd [rdx], eax +# else + mov edx, [pu32] + xadd [edx], eax +# endif + mov u32, eax + } + return u32 - 1; +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + RTASM_ARM_LOAD_MODIFY_STORE_RET_NEW_32(ASMAtomicUoDecU32, pu32, NO_BARRIER, + "sub %w[uNew], %w[uNew], #1\n\t", + "sub %[uNew], %[uNew], #1\n\t" /* arm6 / thumb2+ */, + "X" (0) /* dummy */); + return u32NewRet; + +# else +# error "Port me" +# endif +} +#endif + + +/** @def RT_ASM_PAGE_SIZE + * We try avoid dragging in iprt/param.h here. + * @internal + */ +#if defined(RT_ARCH_SPARC64) +# define RT_ASM_PAGE_SIZE 0x2000 +# if defined(PAGE_SIZE) && !defined(NT_INCLUDED) +# if PAGE_SIZE != 0x2000 +# error "PAGE_SIZE is not 0x2000!" +# endif +# endif +#elif defined(RT_ARCH_ARM64) +# define RT_ASM_PAGE_SIZE 0x4000 +# if defined(PAGE_SIZE) && !defined(NT_INCLUDED) && !defined(_MACH_ARM_VM_PARAM_H_) +# if PAGE_SIZE != 0x4000 +# error "PAGE_SIZE is not 0x4000!" +# endif +# endif +#else +# define RT_ASM_PAGE_SIZE 0x1000 +# if defined(PAGE_SIZE) && !defined(NT_INCLUDED) +# if PAGE_SIZE != 0x1000 +# error "PAGE_SIZE is not 0x1000!" +# endif +# endif +#endif + +/** + * Zeros a 4K memory page. + * + * @param pv Pointer to the memory block. This must be page aligned. + */ +#if (RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN) || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMMemZeroPage(volatile void RT_FAR *pv) RT_NOTHROW_PROTO; +# else +DECLINLINE(void) ASMMemZeroPage(volatile void RT_FAR *pv) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN +# ifdef RT_ARCH_AMD64 + __stosq((unsigned __int64 *)pv, 0, RT_ASM_PAGE_SIZE / 8); +# else + __stosd((unsigned long *)pv, 0, RT_ASM_PAGE_SIZE / 4); +# endif + +# elif RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG uDummy; +# ifdef RT_ARCH_AMD64 + __asm__ __volatile__("rep stosq" + : "=D" (pv), + "=c" (uDummy) + : "0" (pv), + "c" (RT_ASM_PAGE_SIZE >> 3), + "a" (0) + : "memory"); +# else + __asm__ __volatile__("rep stosl" + : "=D" (pv), + "=c" (uDummy) + : "0" (pv), + "c" (RT_ASM_PAGE_SIZE >> 2), + "a" (0) + : "memory"); +# endif +# else + __asm + { +# ifdef RT_ARCH_AMD64 + xor rax, rax + mov ecx, 0200h + mov rdi, [pv] + rep stosq +# else + xor eax, eax + mov ecx, 0400h + mov edi, [pv] + rep stosd +# endif + } +# endif +} +# endif + + +/** + * Zeros a memory block with a 32-bit aligned size. + * + * @param pv Pointer to the memory block. + * @param cb Number of bytes in the block. This MUST be aligned on 32-bit! + */ +#if (RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN) || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMMemZero32(volatile void RT_FAR *pv, size_t cb) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMMemZero32(volatile void RT_FAR *pv, size_t cb) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN +# ifdef RT_ARCH_AMD64 + if (!(cb & 7)) + __stosq((unsigned __int64 RT_FAR *)pv, 0, cb / 8); + else +# endif + __stosd((unsigned long RT_FAR *)pv, 0, cb / 4); + +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rep stosl" + : "=D" (pv), + "=c" (cb) + : "0" (pv), + "1" (cb >> 2), + "a" (0) + : "memory"); +# else + __asm + { + xor eax, eax +# ifdef RT_ARCH_AMD64 + mov rcx, [cb] + shr rcx, 2 + mov rdi, [pv] +# else + mov ecx, [cb] + shr ecx, 2 + mov edi, [pv] +# endif + rep stosd + } +# endif +} +#endif + + +/** + * Fills a memory block with a 32-bit aligned size. + * + * @param pv Pointer to the memory block. + * @param cb Number of bytes in the block. This MUST be aligned on 32-bit! + * @param u32 The value to fill with. + */ +#if (RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN) || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMMemFill32(volatile void RT_FAR *pv, size_t cb, uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMMemFill32(volatile void RT_FAR *pv, size_t cb, uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN +# ifdef RT_ARCH_AMD64 + if (!(cb & 7)) + __stosq((unsigned __int64 RT_FAR *)pv, RT_MAKE_U64(u32, u32), cb / 8); + else +# endif + __stosd((unsigned long RT_FAR *)pv, u32, cb / 4); + +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("rep stosl" + : "=D" (pv), + "=c" (cb) + : "0" (pv), + "1" (cb >> 2), + "a" (u32) + : "memory"); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rcx, [cb] + shr rcx, 2 + mov rdi, [pv] +# else + mov ecx, [cb] + shr ecx, 2 + mov edi, [pv] +# endif + mov eax, [u32] + rep stosd + } +# endif +} +#endif + + +/** + * Checks if a memory block is all zeros. + * + * @returns Pointer to the first non-zero byte. + * @returns NULL if all zero. + * + * @param pv Pointer to the memory block. + * @param cb Number of bytes in the block. + */ +#if !defined(RDESKTOP) && (!defined(RT_OS_LINUX) || !defined(__KERNEL__)) +DECLASM(void RT_FAR *) ASMMemFirstNonZero(void const RT_FAR *pv, size_t cb) RT_NOTHROW_PROTO; +#else +DECLINLINE(void RT_FAR *) ASMMemFirstNonZero(void const RT_FAR *pv, size_t cb) RT_NOTHROW_DEF +{ +/** @todo replace with ASMMemFirstNonZero-generic.cpp in kernel modules. */ + uint8_t const *pb = (uint8_t const RT_FAR *)pv; + for (; cb; cb--, pb++) + if (RT_LIKELY(*pb == 0)) + { /* likely */ } + else + return (void RT_FAR *)pb; + return NULL; +} +#endif + + +/** + * Checks if a memory block is all zeros. + * + * @returns true if zero, false if not. + * + * @param pv Pointer to the memory block. + * @param cb Number of bytes in the block. + * + * @sa ASMMemFirstNonZero + */ +DECLINLINE(bool) ASMMemIsZero(void const RT_FAR *pv, size_t cb) RT_NOTHROW_DEF +{ + return ASMMemFirstNonZero(pv, cb) == NULL; +} + + +/** + * Checks if a memory page is all zeros. + * + * @returns true / false. + * + * @param pvPage Pointer to the page. Must be aligned on 16 byte + * boundary + */ +DECLINLINE(bool) ASMMemIsZeroPage(void const RT_FAR *pvPage) RT_NOTHROW_DEF +{ +# if 0 /*RT_INLINE_ASM_GNU_STYLE - this is actually slower... */ + union { RTCCUINTREG r; bool f; } uAX; + RTCCUINTREG xCX, xDI; + Assert(!((uintptr_t)pvPage & 15)); + __asm__ __volatile__("repe; " +# ifdef RT_ARCH_AMD64 + "scasq\n\t" +# else + "scasl\n\t" +# endif + "setnc %%al\n\t" + : "=&c" (xCX) + , "=&D" (xDI) + , "=&a" (uAX.r) + : "mr" (pvPage) +# ifdef RT_ARCH_AMD64 + , "0" (RT_ASM_PAGE_SIZE/8) +# else + , "0" (RT_ASM_PAGE_SIZE/4) +# endif + , "1" (pvPage) + , "2" (0) + : "cc"); + return uAX.f; +# else + uintptr_t const RT_FAR *puPtr = (uintptr_t const RT_FAR *)pvPage; + size_t cLeft = RT_ASM_PAGE_SIZE / sizeof(uintptr_t) / 8; + Assert(!((uintptr_t)pvPage & 15)); + for (;;) + { + if (puPtr[0]) return false; + if (puPtr[4]) return false; + + if (puPtr[2]) return false; + if (puPtr[6]) return false; + + if (puPtr[1]) return false; + if (puPtr[5]) return false; + + if (puPtr[3]) return false; + if (puPtr[7]) return false; + + if (!--cLeft) + return true; + puPtr += 8; + } +# endif +} + + +/** + * Checks if a memory block is filled with the specified byte, returning the + * first mismatch. + * + * This is sort of an inverted memchr. + * + * @returns Pointer to the byte which doesn't equal u8. + * @returns NULL if all equal to u8. + * + * @param pv Pointer to the memory block. + * @param cb Number of bytes in the block. + * @param u8 The value it's supposed to be filled with. + * + * @remarks No alignment requirements. + */ +#if (!defined(RT_OS_LINUX) || !defined(__KERNEL__)) \ + && (!defined(RT_OS_FREEBSD) || !defined(_KERNEL)) +DECLASM(void *) ASMMemFirstMismatchingU8(void const RT_FAR *pv, size_t cb, uint8_t u8) RT_NOTHROW_PROTO; +#else +DECLINLINE(void *) ASMMemFirstMismatchingU8(void const RT_FAR *pv, size_t cb, uint8_t u8) RT_NOTHROW_DEF +{ +/** @todo replace with ASMMemFirstMismatchingU8-generic.cpp in kernel modules. */ + uint8_t const *pb = (uint8_t const RT_FAR *)pv; + for (; cb; cb--, pb++) + if (RT_LIKELY(*pb == u8)) + { /* likely */ } + else + return (void *)pb; + return NULL; +} +#endif + + +/** + * Checks if a memory block is filled with the specified byte. + * + * @returns true if all matching, false if not. + * + * @param pv Pointer to the memory block. + * @param cb Number of bytes in the block. + * @param u8 The value it's supposed to be filled with. + * + * @remarks No alignment requirements. + */ +DECLINLINE(bool) ASMMemIsAllU8(void const RT_FAR *pv, size_t cb, uint8_t u8) RT_NOTHROW_DEF +{ + return ASMMemFirstMismatchingU8(pv, cb, u8) == NULL; +} + + +/** + * Checks if a memory block is filled with the specified 32-bit value. + * + * This is a sort of inverted memchr. + * + * @returns Pointer to the first value which doesn't equal u32. + * @returns NULL if all equal to u32. + * + * @param pv Pointer to the memory block. + * @param cb Number of bytes in the block. This MUST be aligned on 32-bit! + * @param u32 The value it's supposed to be filled with. + */ +DECLINLINE(uint32_t RT_FAR *) ASMMemFirstMismatchingU32(void const RT_FAR *pv, size_t cb, uint32_t u32) RT_NOTHROW_DEF +{ +/** @todo rewrite this in inline assembly? */ + uint32_t const RT_FAR *pu32 = (uint32_t const RT_FAR *)pv; + for (; cb; cb -= 4, pu32++) + if (RT_LIKELY(*pu32 == u32)) + { /* likely */ } + else + return (uint32_t RT_FAR *)pu32; + return NULL; +} + + +/** + * Probes a byte pointer for read access. + * + * While the function will not fault if the byte is not read accessible, + * the idea is to do this in a safe place like before acquiring locks + * and such like. + * + * Also, this functions guarantees that an eager compiler is not going + * to optimize the probing away. + * + * @param pvByte Pointer to the byte. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(uint8_t) ASMProbeReadByte(const void RT_FAR *pvByte) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint8_t) ASMProbeReadByte(const void RT_FAR *pvByte) RT_NOTHROW_DEF +{ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) + uint8_t u8; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("movb %1, %0\n\t" + : "=q" (u8) + : "m" (*(const uint8_t *)pvByte)); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pvByte] + mov al, [rax] +# else + mov eax, [pvByte] + mov al, [eax] +# endif + mov [u8], al + } +# endif + return u8; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t u32; + __asm__ __volatile__(".Lstart_ASMProbeReadByte_%=:\n\t" +# if defined(RT_ARCH_ARM64) + "ldxrb %w[uDst], %[pMem]\n\t" +# else + "ldrexb %[uDst], %[pMem]\n\t" +# endif + : [uDst] "=&r" (u32) + : [pMem] "Q" (*(uint8_t const *)pvByte)); + return (uint8_t)u32; + +# else +# error "Port me" +# endif +} +#endif + +/** + * Probes a buffer for read access page by page. + * + * While the function will fault if the buffer is not fully read + * accessible, the idea is to do this in a safe place like before + * acquiring locks and such like. + * + * Also, this functions guarantees that an eager compiler is not going + * to optimize the probing away. + * + * @param pvBuf Pointer to the buffer. + * @param cbBuf The size of the buffer in bytes. Must be >= 1. + */ +DECLINLINE(void) ASMProbeReadBuffer(const void RT_FAR *pvBuf, size_t cbBuf) RT_NOTHROW_DEF +{ + /** @todo verify that the compiler actually doesn't optimize this away. (intel & gcc) */ + /* the first byte */ + const uint8_t RT_FAR *pu8 = (const uint8_t RT_FAR *)pvBuf; + ASMProbeReadByte(pu8); + + /* the pages in between pages. */ + while (cbBuf > RT_ASM_PAGE_SIZE) + { + ASMProbeReadByte(pu8); + cbBuf -= RT_ASM_PAGE_SIZE; + pu8 += RT_ASM_PAGE_SIZE; + } + + /* the last byte */ + ASMProbeReadByte(pu8 + cbBuf - 1); +} + + +/** + * Reverse the byte order of the given 16-bit integer. + * + * @returns Revert + * @param u16 16-bit integer value. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint16_t) ASMByteSwapU16(uint16_t u16) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint16_t) ASMByteSwapU16(uint16_t u16) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + return _byteswap_ushort(u16); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ ("rorw $8, %0" : "=r" (u16) : "0" (u16) : "cc"); +# else + _asm + { + mov ax, [u16] + ror ax, 8 + mov [u16], ax + } +# endif + return u16; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t u32Ret; + __asm__ __volatile__( +# if defined(RT_ARCH_ARM64) + "rev16 %w[uRet], %w[uVal]\n\t" +# else + "rev16 %[uRet], %[uVal]\n\t" +# endif + : [uRet] "=r" (u32Ret) + : [uVal] "r" (u16)); + return (uint16_t)u32Ret; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Reverse the byte order of the given 32-bit integer. + * + * @returns Revert + * @param u32 32-bit integer value. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMByteSwapU32(uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMByteSwapU32(uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + return _byteswap_ulong(u32); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ ("bswapl %0" : "=r" (u32) : "0" (u32)); +# else + _asm + { + mov eax, [u32] + bswap eax + mov [u32], eax + } +# endif + return u32; + +# elif defined(RT_ARCH_ARM64) + uint64_t u64Ret; + __asm__ __volatile__("rev32 %[uRet], %[uVal]\n\t" + : [uRet] "=r" (u64Ret) + : [uVal] "r" ((uint64_t)u32)); + return (uint32_t)u64Ret; + +# elif defined(RT_ARCH_ARM32) + __asm__ __volatile__("rev %[uRet], %[uVal]\n\t" + : [uRet] "=r" (u32) + : [uVal] "[uRet]" (u32)); + return u32; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Reverse the byte order of the given 64-bit integer. + * + * @returns Revert + * @param u64 64-bit integer value. + */ +DECLINLINE(uint64_t) ASMByteSwapU64(uint64_t u64) RT_NOTHROW_DEF +{ +#if defined(RT_ARCH_AMD64) && RT_INLINE_ASM_USES_INTRIN + return _byteswap_uint64(u64); + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + __asm__ ("bswapq %0" : "=r" (u64) : "0" (u64)); + return u64; + +# elif defined(RT_ARCH_ARM64) + __asm__ __volatile__("rev %[uRet], %[uVal]\n\t" + : [uRet] "=r" (u64) + : [uVal] "[uRet]" (u64)); + return u64; + +#else + return (uint64_t)ASMByteSwapU32((uint32_t)u64) << 32 + | (uint64_t)ASMByteSwapU32((uint32_t)(u64 >> 32)); +#endif +} + + + +/** @defgroup grp_inline_bits Bit Operations + * @{ + */ + + +/** + * Sets a bit in a bitmap. + * + * @param pvBitmap Pointer to the bitmap (little endian). This should be + * 32-bit aligned. + * @param iBit The bit to set. + * + * @remarks The 32-bit aligning of pvBitmap is not a strict requirement. + * However, doing so will yield better performance as well as avoiding + * traps accessing the last bits in the bitmap. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMBitSet(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMBitSet(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + _bittestandset((long RT_FAR *)pvBitmap, iBit); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("btsl %1, %0" + : "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + mov edx, [iBit] + bts [rax], edx +# else + mov eax, [pvBitmap] + mov edx, [iBit] + bts [eax], edx +# endif + } +# endif + +# else + int32_t offBitmap = iBit / 32; + AssertStmt(!((uintptr_t)pvBitmap & 3), offBitmap += (uintptr_t)pvBitmap & 3; iBit += ((uintptr_t)pvBitmap & 3) * 8); + ASMAtomicUoOrU32(&((uint32_t volatile *)pvBitmap)[offBitmap], RT_H2LE_U32(RT_BIT_32(iBit & 31))); +# endif +} +#endif + + +/** + * Atomically sets a bit in a bitmap, ordered. + * + * @param pvBitmap Pointer to the bitmap (little endian). Must be 32-bit + * aligned, otherwise the memory access isn't atomic! + * @param iBit The bit to set. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicBitSet(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicBitSet(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + AssertMsg(!((uintptr_t)pvBitmap & 3), ("address %p not 32-bit aligned", pvBitmap)); +# if RT_INLINE_ASM_USES_INTRIN + _interlockedbittestandset((long RT_FAR *)pvBitmap, iBit); +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; btsl %1, %0" + : "=m" (*(volatile long *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + mov edx, [iBit] + lock bts [rax], edx +# else + mov eax, [pvBitmap] + mov edx, [iBit] + lock bts [eax], edx +# endif + } +# endif + +# else + ASMAtomicOrU32(&((uint32_t volatile *)pvBitmap)[iBit / 32], RT_H2LE_U32(RT_BIT_32(iBit & 31))); +# endif +} +#endif + + +/** + * Clears a bit in a bitmap. + * + * @param pvBitmap Pointer to the bitmap (little endian). + * @param iBit The bit to clear. + * + * @remarks The 32-bit aligning of pvBitmap is not a strict requirement. + * However, doing so will yield better performance as well as avoiding + * traps accessing the last bits in the bitmap. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMBitClear(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMBitClear(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + _bittestandreset((long RT_FAR *)pvBitmap, iBit); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("btrl %1, %0" + : "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + mov edx, [iBit] + btr [rax], edx +# else + mov eax, [pvBitmap] + mov edx, [iBit] + btr [eax], edx +# endif + } +# endif + +# else + int32_t offBitmap = iBit / 32; + AssertStmt(!((uintptr_t)pvBitmap & 3), offBitmap += (uintptr_t)pvBitmap & 3; iBit += ((uintptr_t)pvBitmap & 3) * 8); + ASMAtomicUoAndU32(&((uint32_t volatile *)pvBitmap)[offBitmap], RT_H2LE_U32(~RT_BIT_32(iBit & 31))); +# endif +} +#endif + + +/** + * Atomically clears a bit in a bitmap, ordered. + * + * @param pvBitmap Pointer to the bitmap (little endian). Must be 32-bit + * aligned, otherwise the memory access isn't atomic! + * @param iBit The bit to toggle set. + * + * @remarks No memory barrier, take care on smp. + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicBitClear(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicBitClear(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + AssertMsg(!((uintptr_t)pvBitmap & 3), ("address %p not 32-bit aligned", pvBitmap)); +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; btrl %1, %0" + : "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + mov edx, [iBit] + lock btr [rax], edx +# else + mov eax, [pvBitmap] + mov edx, [iBit] + lock btr [eax], edx +# endif + } +# endif +# else + ASMAtomicAndU32(&((uint32_t volatile *)pvBitmap)[iBit / 32], RT_H2LE_U32(~RT_BIT_32(iBit & 31))); +# endif +} +#endif + + +/** + * Toggles a bit in a bitmap. + * + * @param pvBitmap Pointer to the bitmap (little endian). + * @param iBit The bit to toggle. + * + * @remarks The 32-bit aligning of pvBitmap is not a strict requirement. + * However, doing so will yield better performance as well as avoiding + * traps accessing the last bits in the bitmap. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMBitToggle(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMBitToggle(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + _bittestandcomplement((long RT_FAR *)pvBitmap, iBit); +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("btcl %1, %0" + : "=m" (*(volatile long *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + mov edx, [iBit] + btc [rax], edx +# else + mov eax, [pvBitmap] + mov edx, [iBit] + btc [eax], edx +# endif + } +# endif +# else + int32_t offBitmap = iBit / 32; + AssertStmt(!((uintptr_t)pvBitmap & 3), offBitmap += (uintptr_t)pvBitmap & 3; iBit += ((uintptr_t)pvBitmap & 3) * 8); + ASMAtomicUoXorU32(&((uint32_t volatile *)pvBitmap)[offBitmap], RT_H2LE_U32(RT_BIT_32(iBit & 31))); +# endif +} +#endif + + +/** + * Atomically toggles a bit in a bitmap, ordered. + * + * @param pvBitmap Pointer to the bitmap (little endian). Must be 32-bit + * aligned, otherwise the memory access isn't atomic! + * @param iBit The bit to test and set. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(void) ASMAtomicBitToggle(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(void) ASMAtomicBitToggle(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + AssertMsg(!((uintptr_t)pvBitmap & 3), ("address %p not 32-bit aligned", pvBitmap)); +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; btcl %1, %0" + : "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + mov edx, [iBit] + lock btc [rax], edx +# else + mov eax, [pvBitmap] + mov edx, [iBit] + lock btc [eax], edx +# endif + } +# endif +# else + ASMAtomicXorU32(&((uint32_t volatile *)pvBitmap)[iBit / 32], RT_H2LE_U32(RT_BIT_32(iBit & 31))); +# endif +} +#endif + + +/** + * Tests and sets a bit in a bitmap. + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * + * @param pvBitmap Pointer to the bitmap (little endian). + * @param iBit The bit to test and set. + * + * @remarks The 32-bit aligning of pvBitmap is not a strict requirement. + * However, doing so will yield better performance as well as avoiding + * traps accessing the last bits in the bitmap. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMBitTestAndSet(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMBitTestAndSet(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + union { bool f; uint32_t u32; uint8_t u8; } rc; +# if RT_INLINE_ASM_USES_INTRIN + rc.u8 = _bittestandset((long RT_FAR *)pvBitmap, iBit); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("btsl %2, %1\n\t" + "setc %b0\n\t" + "andl $1, %0\n\t" + : "=q" (rc.u32) + , "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { + mov edx, [iBit] +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + bts [rax], edx +# else + mov eax, [pvBitmap] + bts [eax], edx +# endif + setc al + and eax, 1 + mov [rc.u32], eax + } +# endif + +# else + int32_t offBitmap = iBit / 32; + AssertStmt(!((uintptr_t)pvBitmap & 3), offBitmap += (uintptr_t)pvBitmap & 3; iBit += ((uintptr_t)pvBitmap & 3) * 8); + rc.u32 = RT_LE2H_U32(ASMAtomicUoOrExU32(&((uint32_t volatile *)pvBitmap)[offBitmap], RT_H2LE_U32(RT_BIT_32(iBit & 31)))) + >> (iBit & 31); + rc.u32 &= 1; +# endif + return rc.f; +} +#endif + + +/** + * Atomically tests and sets a bit in a bitmap, ordered. + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * + * @param pvBitmap Pointer to the bitmap (little endian). Must be 32-bit + * aligned, otherwise the memory access isn't atomic! + * @param iBit The bit to set. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicBitTestAndSet(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicBitTestAndSet(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + union { bool f; uint32_t u32; uint8_t u8; } rc; + AssertMsg(!((uintptr_t)pvBitmap & 3), ("address %p not 32-bit aligned", pvBitmap)); +# if RT_INLINE_ASM_USES_INTRIN + rc.u8 = _interlockedbittestandset((long RT_FAR *)pvBitmap, iBit); +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; btsl %2, %1\n\t" + "setc %b0\n\t" + "andl $1, %0\n\t" + : "=q" (rc.u32) + , "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { + mov edx, [iBit] +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + lock bts [rax], edx +# else + mov eax, [pvBitmap] + lock bts [eax], edx +# endif + setc al + and eax, 1 + mov [rc.u32], eax + } +# endif + +# else + rc.u32 = RT_LE2H_U32(ASMAtomicOrExU32(&((uint32_t volatile *)pvBitmap)[iBit / 32], RT_H2LE_U32(RT_BIT_32(iBit & 31)))) + >> (iBit & 31); + rc.u32 &= 1; +# endif + return rc.f; +} +#endif + + +/** + * Tests and clears a bit in a bitmap. + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * + * @param pvBitmap Pointer to the bitmap (little endian). + * @param iBit The bit to test and clear. + * + * @remarks The 32-bit aligning of pvBitmap is not a strict requirement. + * However, doing so will yield better performance as well as avoiding + * traps accessing the last bits in the bitmap. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMBitTestAndClear(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMBitTestAndClear(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + union { bool f; uint32_t u32; uint8_t u8; } rc; +# if RT_INLINE_ASM_USES_INTRIN + rc.u8 = _bittestandreset((long RT_FAR *)pvBitmap, iBit); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("btrl %2, %1\n\t" + "setc %b0\n\t" + "andl $1, %0\n\t" + : "=q" (rc.u32) + , "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { + mov edx, [iBit] +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + btr [rax], edx +# else + mov eax, [pvBitmap] + btr [eax], edx +# endif + setc al + and eax, 1 + mov [rc.u32], eax + } +# endif + +# else + int32_t offBitmap = iBit / 32; + AssertStmt(!((uintptr_t)pvBitmap & 3), offBitmap += (uintptr_t)pvBitmap & 3; iBit += ((uintptr_t)pvBitmap & 3) * 8); + rc.u32 = RT_LE2H_U32(ASMAtomicUoAndExU32(&((uint32_t volatile *)pvBitmap)[offBitmap], RT_H2LE_U32(~RT_BIT_32(iBit & 31)))) + >> (iBit & 31); + rc.u32 &= 1; +# endif + return rc.f; +} +#endif + + +/** + * Atomically tests and clears a bit in a bitmap, ordered. + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * + * @param pvBitmap Pointer to the bitmap (little endian). Must be 32-bit + * aligned, otherwise the memory access isn't atomic! + * @param iBit The bit to test and clear. + * + * @remarks No memory barrier, take care on smp. + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicBitTestAndClear(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicBitTestAndClear(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + union { bool f; uint32_t u32; uint8_t u8; } rc; + AssertMsg(!((uintptr_t)pvBitmap & 3), ("address %p not 32-bit aligned", pvBitmap)); +# if RT_INLINE_ASM_USES_INTRIN + rc.u8 = _interlockedbittestandreset((long RT_FAR *)pvBitmap, iBit); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; btrl %2, %1\n\t" + "setc %b0\n\t" + "andl $1, %0\n\t" + : "=q" (rc.u32) + , "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { + mov edx, [iBit] +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + lock btr [rax], edx +# else + mov eax, [pvBitmap] + lock btr [eax], edx +# endif + setc al + and eax, 1 + mov [rc.u32], eax + } +# endif + +# else + rc.u32 = RT_LE2H_U32(ASMAtomicAndExU32(&((uint32_t volatile *)pvBitmap)[iBit / 32], RT_H2LE_U32(~RT_BIT_32(iBit & 31)))) + >> (iBit & 31); + rc.u32 &= 1; +# endif + return rc.f; +} +#endif + + +/** + * Tests and toggles a bit in a bitmap. + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * + * @param pvBitmap Pointer to the bitmap (little endian). + * @param iBit The bit to test and toggle. + * + * @remarks The 32-bit aligning of pvBitmap is not a strict requirement. + * However, doing so will yield better performance as well as avoiding + * traps accessing the last bits in the bitmap. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMBitTestAndToggle(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMBitTestAndToggle(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + union { bool f; uint32_t u32; uint8_t u8; } rc; +# if RT_INLINE_ASM_USES_INTRIN + rc.u8 = _bittestandcomplement((long RT_FAR *)pvBitmap, iBit); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("btcl %2, %1\n\t" + "setc %b0\n\t" + "andl $1, %0\n\t" + : "=q" (rc.u32) + , "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { + mov edx, [iBit] +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + btc [rax], edx +# else + mov eax, [pvBitmap] + btc [eax], edx +# endif + setc al + and eax, 1 + mov [rc.u32], eax + } +# endif + +# else + int32_t offBitmap = iBit / 32; + AssertStmt(!((uintptr_t)pvBitmap & 3), offBitmap += (uintptr_t)pvBitmap & 3; iBit += ((uintptr_t)pvBitmap & 3) * 8); + rc.u32 = RT_LE2H_U32(ASMAtomicUoXorExU32(&((uint32_t volatile *)pvBitmap)[offBitmap], RT_H2LE_U32(RT_BIT_32(iBit & 31)))) + >> (iBit & 31); + rc.u32 &= 1; +# endif + return rc.f; +} +#endif + + +/** + * Atomically tests and toggles a bit in a bitmap, ordered. + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * + * @param pvBitmap Pointer to the bitmap (little endian). Must be 32-bit + * aligned, otherwise the memory access isn't atomic! + * @param iBit The bit to test and toggle. + * + * @remarks x86: Requires a 386 or later. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMAtomicBitTestAndToggle(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMAtomicBitTestAndToggle(volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + union { bool f; uint32_t u32; uint8_t u8; } rc; + AssertMsg(!((uintptr_t)pvBitmap & 3), ("address %p not 32-bit aligned", pvBitmap)); +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("lock; btcl %2, %1\n\t" + "setc %b0\n\t" + "andl $1, %0\n\t" + : "=q" (rc.u32) + , "=m" (*(volatile long RT_FAR *)pvBitmap) + : "Ir" (iBit) + , "m" (*(volatile long RT_FAR *)pvBitmap) + : "memory" + , "cc"); +# else + __asm + { + mov edx, [iBit] +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + lock btc [rax], edx +# else + mov eax, [pvBitmap] + lock btc [eax], edx +# endif + setc al + and eax, 1 + mov [rc.u32], eax + } +# endif + +# else + rc.u32 = RT_H2LE_U32(ASMAtomicXorExU32(&((uint32_t volatile *)pvBitmap)[iBit / 32], RT_LE2H_U32(RT_BIT_32(iBit & 31)))) + >> (iBit & 31); + rc.u32 &= 1; +# endif + return rc.f; +} +#endif + + +/** + * Tests if a bit in a bitmap is set. + * + * @returns true if the bit is set. + * @returns false if the bit is clear. + * + * @param pvBitmap Pointer to the bitmap (little endian). + * @param iBit The bit to test. + * + * @remarks The 32-bit aligning of pvBitmap is not a strict requirement. + * However, doing so will yield better performance as well as avoiding + * traps accessing the last bits in the bitmap. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM(bool) ASMBitTest(const volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_PROTO; +#else +DECLINLINE(bool) ASMBitTest(const volatile void RT_FAR *pvBitmap, int32_t iBit) RT_NOTHROW_DEF +{ + union { bool f; uint32_t u32; uint8_t u8; } rc; +# if RT_INLINE_ASM_USES_INTRIN + rc.u32 = _bittest((long *)pvBitmap, iBit); + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + + __asm__ __volatile__("btl %2, %1\n\t" + "setc %b0\n\t" + "andl $1, %0\n\t" + : "=q" (rc.u32) + : "m" (*(const volatile long RT_FAR *)pvBitmap) + , "Ir" (iBit) + : "memory" + , "cc"); +# else + __asm + { + mov edx, [iBit] +# ifdef RT_ARCH_AMD64 + mov rax, [pvBitmap] + bt [rax], edx +# else + mov eax, [pvBitmap] + bt [eax], edx +# endif + setc al + and eax, 1 + mov [rc.u32], eax + } +# endif + +# else + int32_t offBitmap = iBit / 32; + AssertStmt(!((uintptr_t)pvBitmap & 3), offBitmap += (uintptr_t)pvBitmap & 3; iBit += ((uintptr_t)pvBitmap & 3) * 8); + rc.u32 = RT_LE2H_U32(ASMAtomicUoReadU32(&((uint32_t volatile *)pvBitmap)[offBitmap])) >> (iBit & 31); + rc.u32 &= 1; +# endif + return rc.f; +} +#endif + + +/** + * Clears a bit range within a bitmap. + * + * @param pvBitmap Pointer to the bitmap (little endian). + * @param iBitStart The First bit to clear. + * @param iBitEnd The first bit not to clear. + */ +DECLINLINE(void) ASMBitClearRange(volatile void RT_FAR *pvBitmap, size_t iBitStart, size_t iBitEnd) RT_NOTHROW_DEF +{ + if (iBitStart < iBitEnd) + { + uint32_t volatile RT_FAR *pu32 = (volatile uint32_t RT_FAR *)pvBitmap + (iBitStart >> 5); + size_t iStart = iBitStart & ~(size_t)31; + size_t iEnd = iBitEnd & ~(size_t)31; + if (iStart == iEnd) + *pu32 &= RT_H2LE_U32(((UINT32_C(1) << (iBitStart & 31)) - 1) | ~((UINT32_C(1) << (iBitEnd & 31)) - 1)); + else + { + /* bits in first dword. */ + if (iBitStart & 31) + { + *pu32 &= RT_H2LE_U32((UINT32_C(1) << (iBitStart & 31)) - 1); + pu32++; + iBitStart = iStart + 32; + } + + /* whole dwords. */ + if (iBitStart != iEnd) + ASMMemZero32(pu32, (iEnd - iBitStart) >> 3); + + /* bits in last dword. */ + if (iBitEnd & 31) + { + pu32 = (volatile uint32_t RT_FAR *)pvBitmap + (iBitEnd >> 5); + *pu32 &= RT_H2LE_U32(~((UINT32_C(1) << (iBitEnd & 31)) - 1)); + } + } + } +} + + +/** + * Sets a bit range within a bitmap. + * + * @param pvBitmap Pointer to the bitmap (little endian). + * @param iBitStart The First bit to set. + * @param iBitEnd The first bit not to set. + */ +DECLINLINE(void) ASMBitSetRange(volatile void RT_FAR *pvBitmap, size_t iBitStart, size_t iBitEnd) RT_NOTHROW_DEF +{ + if (iBitStart < iBitEnd) + { + uint32_t volatile RT_FAR *pu32 = (volatile uint32_t RT_FAR *)pvBitmap + (iBitStart >> 5); + size_t iStart = iBitStart & ~(size_t)31; + size_t iEnd = iBitEnd & ~(size_t)31; + if (iStart == iEnd) + *pu32 |= RT_H2LE_U32(((UINT32_C(1) << (iBitEnd - iBitStart)) - 1) << (iBitStart & 31)); + else + { + /* bits in first dword. */ + if (iBitStart & 31) + { + *pu32 |= RT_H2LE_U32(~((UINT32_C(1) << (iBitStart & 31)) - 1)); + pu32++; + iBitStart = iStart + 32; + } + + /* whole dword. */ + if (iBitStart != iEnd) + ASMMemFill32(pu32, (iEnd - iBitStart) >> 3, ~UINT32_C(0)); + + /* bits in last dword. */ + if (iBitEnd & 31) + { + pu32 = (volatile uint32_t RT_FAR *)pvBitmap + (iBitEnd >> 5); + *pu32 |= RT_H2LE_U32((UINT32_C(1) << (iBitEnd & 31)) - 1); + } + } + } +} + + +/** + * Finds the first clear bit in a bitmap. + * + * @returns Index of the first zero bit. + * @returns -1 if no clear bit was found. + * @param pvBitmap Pointer to the bitmap (little endian). + * @param cBits The number of bits in the bitmap. Multiple of 32. + */ +#if RT_INLINE_ASM_EXTERNAL || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +DECLASM(int32_t) ASMBitFirstClear(const volatile void RT_FAR *pvBitmap, uint32_t cBits) RT_NOTHROW_PROTO; +#else +DECLINLINE(int32_t) ASMBitFirstClear(const volatile void RT_FAR *pvBitmap, uint32_t cBits) RT_NOTHROW_DEF +{ + if (cBits) + { + int32_t iBit; +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG uEAX, uECX, uEDI; + cBits = RT_ALIGN_32(cBits, 32); + __asm__ __volatile__("repe; scasl\n\t" + "je 1f\n\t" +# ifdef RT_ARCH_AMD64 + "lea -4(%%rdi), %%rdi\n\t" + "xorl (%%rdi), %%eax\n\t" + "subq %5, %%rdi\n\t" +# else + "lea -4(%%edi), %%edi\n\t" + "xorl (%%edi), %%eax\n\t" + "subl %5, %%edi\n\t" +# endif + "shll $3, %%edi\n\t" + "bsfl %%eax, %%edx\n\t" + "addl %%edi, %%edx\n\t" + "1:\t\n" + : "=d" (iBit) + , "=&c" (uECX) + , "=&D" (uEDI) + , "=&a" (uEAX) + : "0" (0xffffffff) + , "mr" (pvBitmap) + , "1" (cBits >> 5) + , "2" (pvBitmap) + , "3" (0xffffffff) + : "cc"); +# else + cBits = RT_ALIGN_32(cBits, 32); + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdi, [pvBitmap] + mov rbx, rdi +# else + mov edi, [pvBitmap] + mov ebx, edi +# endif + mov edx, 0ffffffffh + mov eax, edx + mov ecx, [cBits] + shr ecx, 5 + repe scasd + je done + +# ifdef RT_ARCH_AMD64 + lea rdi, [rdi - 4] + xor eax, [rdi] + sub rdi, rbx +# else + lea edi, [edi - 4] + xor eax, [edi] + sub edi, ebx +# endif + shl edi, 3 + bsf edx, eax + add edx, edi + done: + mov [iBit], edx + } +# endif + return iBit; + } + return -1; +} +#endif + + +/** + * Finds the next clear bit in a bitmap. + * + * @returns Index of the first zero bit. + * @returns -1 if no clear bit was found. + * @param pvBitmap Pointer to the bitmap (little endian). + * @param cBits The number of bits in the bitmap. Multiple of 32. + * @param iBitPrev The bit returned from the last search. + * The search will start at iBitPrev + 1. + */ +#if RT_INLINE_ASM_EXTERNAL || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +DECLASM(int) ASMBitNextClear(const volatile void RT_FAR *pvBitmap, uint32_t cBits, uint32_t iBitPrev) RT_NOTHROW_PROTO; +#else +DECLINLINE(int) ASMBitNextClear(const volatile void RT_FAR *pvBitmap, uint32_t cBits, uint32_t iBitPrev) RT_NOTHROW_DEF +{ + const volatile uint32_t RT_FAR *pau32Bitmap = (const volatile uint32_t RT_FAR *)pvBitmap; + int iBit = ++iBitPrev & 31; + if (iBit) + { + /* + * Inspect the 32-bit word containing the unaligned bit. + */ + uint32_t u32 = ~pau32Bitmap[iBitPrev / 32] >> iBit; + +# if RT_INLINE_ASM_USES_INTRIN + unsigned long ulBit = 0; + if (_BitScanForward(&ulBit, u32)) + return ulBit + iBitPrev; +# else +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("bsf %1, %0\n\t" + "jnz 1f\n\t" + "movl $-1, %0\n\t" /** @todo use conditional move for 64-bit? */ + "1:\n\t" + : "=r" (iBit) + : "r" (u32) + : "cc"); +# else + __asm + { + mov edx, [u32] + bsf eax, edx + jnz done + mov eax, 0ffffffffh + done: + mov [iBit], eax + } +# endif + if (iBit >= 0) + return iBit + (int)iBitPrev; +# endif + + /* + * Skip ahead and see if there is anything left to search. + */ + iBitPrev |= 31; + iBitPrev++; + if (cBits <= (uint32_t)iBitPrev) + return -1; + } + + /* + * 32-bit aligned search, let ASMBitFirstClear do the dirty work. + */ + iBit = ASMBitFirstClear(&pau32Bitmap[iBitPrev / 32], cBits - iBitPrev); + if (iBit >= 0) + iBit += iBitPrev; + return iBit; +} +#endif + + +/** + * Finds the first set bit in a bitmap. + * + * @returns Index of the first set bit. + * @returns -1 if no clear bit was found. + * @param pvBitmap Pointer to the bitmap (little endian). + * @param cBits The number of bits in the bitmap. Multiple of 32. + */ +#if RT_INLINE_ASM_EXTERNAL || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +DECLASM(int32_t) ASMBitFirstSet(const volatile void RT_FAR *pvBitmap, uint32_t cBits) RT_NOTHROW_PROTO; +#else +DECLINLINE(int32_t) ASMBitFirstSet(const volatile void RT_FAR *pvBitmap, uint32_t cBits) RT_NOTHROW_DEF +{ + if (cBits) + { + int32_t iBit; +# if RT_INLINE_ASM_GNU_STYLE + RTCCUINTREG uEAX, uECX, uEDI; + cBits = RT_ALIGN_32(cBits, 32); + __asm__ __volatile__("repe; scasl\n\t" + "je 1f\n\t" +# ifdef RT_ARCH_AMD64 + "lea -4(%%rdi), %%rdi\n\t" + "movl (%%rdi), %%eax\n\t" + "subq %5, %%rdi\n\t" +# else + "lea -4(%%edi), %%edi\n\t" + "movl (%%edi), %%eax\n\t" + "subl %5, %%edi\n\t" +# endif + "shll $3, %%edi\n\t" + "bsfl %%eax, %%edx\n\t" + "addl %%edi, %%edx\n\t" + "1:\t\n" + : "=d" (iBit) + , "=&c" (uECX) + , "=&D" (uEDI) + , "=&a" (uEAX) + : "0" (0xffffffff) + , "mr" (pvBitmap) + , "1" (cBits >> 5) + , "2" (pvBitmap) + , "3" (0) + : "cc"); +# else + cBits = RT_ALIGN_32(cBits, 32); + __asm + { +# ifdef RT_ARCH_AMD64 + mov rdi, [pvBitmap] + mov rbx, rdi +# else + mov edi, [pvBitmap] + mov ebx, edi +# endif + mov edx, 0ffffffffh + xor eax, eax + mov ecx, [cBits] + shr ecx, 5 + repe scasd + je done +# ifdef RT_ARCH_AMD64 + lea rdi, [rdi - 4] + mov eax, [rdi] + sub rdi, rbx +# else + lea edi, [edi - 4] + mov eax, [edi] + sub edi, ebx +# endif + shl edi, 3 + bsf edx, eax + add edx, edi + done: + mov [iBit], edx + } +# endif + return iBit; + } + return -1; +} +#endif + + +/** + * Finds the next set bit in a bitmap. + * + * @returns Index of the next set bit. + * @returns -1 if no set bit was found. + * @param pvBitmap Pointer to the bitmap (little endian). + * @param cBits The number of bits in the bitmap. Multiple of 32. + * @param iBitPrev The bit returned from the last search. + * The search will start at iBitPrev + 1. + */ +#if RT_INLINE_ASM_EXTERNAL || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)) +DECLASM(int) ASMBitNextSet(const volatile void RT_FAR *pvBitmap, uint32_t cBits, uint32_t iBitPrev) RT_NOTHROW_PROTO; +#else +DECLINLINE(int) ASMBitNextSet(const volatile void RT_FAR *pvBitmap, uint32_t cBits, uint32_t iBitPrev) RT_NOTHROW_DEF +{ + const volatile uint32_t RT_FAR *pau32Bitmap = (const volatile uint32_t RT_FAR *)pvBitmap; + int iBit = ++iBitPrev & 31; + if (iBit) + { + /* + * Inspect the 32-bit word containing the unaligned bit. + */ + uint32_t u32 = pau32Bitmap[iBitPrev / 32] >> iBit; + +# if RT_INLINE_ASM_USES_INTRIN + unsigned long ulBit = 0; + if (_BitScanForward(&ulBit, u32)) + return ulBit + iBitPrev; +# else +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("bsf %1, %0\n\t" + "jnz 1f\n\t" /** @todo use conditional move for 64-bit? */ + "movl $-1, %0\n\t" + "1:\n\t" + : "=r" (iBit) + : "r" (u32) + : "cc"); +# else + __asm + { + mov edx, [u32] + bsf eax, edx + jnz done + mov eax, 0ffffffffh + done: + mov [iBit], eax + } +# endif + if (iBit >= 0) + return iBit + (int)iBitPrev; +# endif + + /* + * Skip ahead and see if there is anything left to search. + */ + iBitPrev |= 31; + iBitPrev++; + if (cBits <= (uint32_t)iBitPrev) + return -1; + } + + /* + * 32-bit aligned search, let ASMBitFirstClear do the dirty work. + */ + iBit = ASMBitFirstSet(&pau32Bitmap[iBitPrev / 32], cBits - iBitPrev); + if (iBit >= 0) + iBit += iBitPrev; + return iBit; +} +#endif + + +/** + * Finds the first bit which is set in the given 32-bit integer. + * Bits are numbered from 1 (least significant) to 32. + * + * @returns index [1..32] of the first set bit. + * @returns 0 if all bits are cleared. + * @param u32 Integer to search for set bits. + * @remarks Similar to ffs() in BSD. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMBitFirstSetU32(uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMBitFirstSetU32(uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + unsigned long iBit; + if (_BitScanForward(&iBit, u32)) + iBit++; + else + iBit = 0; + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + uint32_t iBit; + __asm__ __volatile__("bsf %1, %0\n\t" + "jnz 1f\n\t" + "xorl %0, %0\n\t" + "jmp 2f\n" + "1:\n\t" + "incl %0\n" + "2:\n\t" + : "=r" (iBit) + : "rm" (u32) + : "cc"); +# else + uint32_t iBit; + _asm + { + bsf eax, [u32] + jnz found + xor eax, eax + jmp done + found: + inc eax + done: + mov [iBit], eax + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + /* + * Using the "count leading zeros (clz)" instruction here because there + * is no dedicated instruction to get the first set bit. + * Need to reverse the bits in the value with "rbit" first because + * "clz" starts counting from the most significant bit. + */ + uint32_t iBit; + __asm__ __volatile__( +# if defined(RT_ARCH_ARM64) + "rbit %w[uVal], %w[uVal]\n\t" + "clz %w[iBit], %w[uVal]\n\t" +# else + "rbit %[uVal], %[uVal]\n\t" + "clz %[iBit], %[uVal]\n\t" +# endif + : [uVal] "=r" (u32) + , [iBit] "=r" (iBit) + : "[uVal]" (u32)); + if (iBit != 32) + iBit++; + else + iBit = 0; /* No bit set. */ + +# else +# error "Port me" +# endif + return iBit; +} +#endif + + +/** + * Finds the first bit which is set in the given 32-bit integer. + * Bits are numbered from 1 (least significant) to 32. + * + * @returns index [1..32] of the first set bit. + * @returns 0 if all bits are cleared. + * @param i32 Integer to search for set bits. + * @remark Similar to ffs() in BSD. + */ +DECLINLINE(unsigned) ASMBitFirstSetS32(int32_t i32) RT_NOTHROW_DEF +{ + return ASMBitFirstSetU32((uint32_t)i32); +} + + +/** + * Finds the first bit which is set in the given 64-bit integer. + * + * Bits are numbered from 1 (least significant) to 64. + * + * @returns index [1..64] of the first set bit. + * @returns 0 if all bits are cleared. + * @param u64 Integer to search for set bits. + * @remarks Similar to ffs() in BSD. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMBitFirstSetU64(uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMBitFirstSetU64(uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + unsigned long iBit; +# if ARCH_BITS == 64 + if (_BitScanForward64(&iBit, u64)) + iBit++; + else + iBit = 0; +# else + if (_BitScanForward(&iBit, (uint32_t)u64)) + iBit++; + else if (_BitScanForward(&iBit, (uint32_t)(u64 >> 32))) + iBit += 33; + else + iBit = 0; +# endif + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + uint64_t iBit; + __asm__ __volatile__("bsfq %1, %0\n\t" + "jnz 1f\n\t" + "xorl %k0, %k0\n\t" + "jmp 2f\n" + "1:\n\t" + "incl %k0\n" + "2:\n\t" + : "=r" (iBit) + : "rm" (u64) + : "cc"); + +# elif defined(RT_ARCH_ARM64) + uint64_t iBit; + __asm__ __volatile__("rbit %[uVal], %[uVal]\n\t" + "clz %[iBit], %[uVal]\n\t" + : [uVal] "=r" (u64) + , [iBit] "=r" (iBit) + : "[uVal]" (u64)); + if (iBit != 64) + iBit++; + else + iBit = 0; /* No bit set. */ + +# else + unsigned iBit = ASMBitFirstSetU32((uint32_t)u64); + if (!iBit) + { + iBit = ASMBitFirstSetU32((uint32_t)(u64 >> 32)); + if (iBit) + iBit += 32; + } +# endif + return (unsigned)iBit; +} +#endif + + +/** + * Finds the first bit which is set in the given 16-bit integer. + * + * Bits are numbered from 1 (least significant) to 16. + * + * @returns index [1..16] of the first set bit. + * @returns 0 if all bits are cleared. + * @param u16 Integer to search for set bits. + * @remarks For 16-bit bs3kit code. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMBitFirstSetU16(uint16_t u16) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMBitFirstSetU16(uint16_t u16) RT_NOTHROW_DEF +{ + return ASMBitFirstSetU32((uint32_t)u16); +} +#endif + + +/** + * Finds the last bit which is set in the given 32-bit integer. + * Bits are numbered from 1 (least significant) to 32. + * + * @returns index [1..32] of the last set bit. + * @returns 0 if all bits are cleared. + * @param u32 Integer to search for set bits. + * @remark Similar to fls() in BSD. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMBitLastSetU32(uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMBitLastSetU32(uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + unsigned long iBit; + if (_BitScanReverse(&iBit, u32)) + iBit++; + else + iBit = 0; + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if RT_INLINE_ASM_GNU_STYLE + uint32_t iBit; + __asm__ __volatile__("bsrl %1, %0\n\t" + "jnz 1f\n\t" + "xorl %0, %0\n\t" + "jmp 2f\n" + "1:\n\t" + "incl %0\n" + "2:\n\t" + : "=r" (iBit) + : "rm" (u32) + : "cc"); +# else + uint32_t iBit; + _asm + { + bsr eax, [u32] + jnz found + xor eax, eax + jmp done + found: + inc eax + done: + mov [iBit], eax + } +# endif + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t iBit; + __asm__ __volatile__( +# if defined(RT_ARCH_ARM64) + "clz %w[iBit], %w[uVal]\n\t" +# else + "clz %[iBit], %[uVal]\n\t" +# endif + : [iBit] "=r" (iBit) + : [uVal] "r" (u32)); + iBit = 32 - iBit; + +# else +# error "Port me" +# endif + return iBit; +} +#endif + + +/** + * Finds the last bit which is set in the given 32-bit integer. + * Bits are numbered from 1 (least significant) to 32. + * + * @returns index [1..32] of the last set bit. + * @returns 0 if all bits are cleared. + * @param i32 Integer to search for set bits. + * @remark Similar to fls() in BSD. + */ +DECLINLINE(unsigned) ASMBitLastSetS32(int32_t i32) RT_NOTHROW_DEF +{ + return ASMBitLastSetU32((uint32_t)i32); +} + + +/** + * Finds the last bit which is set in the given 64-bit integer. + * + * Bits are numbered from 1 (least significant) to 64. + * + * @returns index [1..64] of the last set bit. + * @returns 0 if all bits are cleared. + * @param u64 Integer to search for set bits. + * @remark Similar to fls() in BSD. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMBitLastSetU64(uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMBitLastSetU64(uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + unsigned long iBit; +# if ARCH_BITS == 64 + if (_BitScanReverse64(&iBit, u64)) + iBit++; + else + iBit = 0; +# else + if (_BitScanReverse(&iBit, (uint32_t)(u64 >> 32))) + iBit += 33; + else if (_BitScanReverse(&iBit, (uint32_t)u64)) + iBit++; + else + iBit = 0; +# endif + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + uint64_t iBit; + __asm__ __volatile__("bsrq %1, %0\n\t" + "jnz 1f\n\t" + "xorl %k0, %k0\n\t" + "jmp 2f\n" + "1:\n\t" + "incl %k0\n" + "2:\n\t" + : "=r" (iBit) + : "rm" (u64) + : "cc"); + +# elif defined(RT_ARCH_ARM64) + uint64_t iBit; + __asm__ __volatile__("clz %[iBit], %[uVal]\n\t" + : [iBit] "=r" (iBit) + : [uVal] "r" (u64)); + iBit = 64 - iBit; + +# else + unsigned iBit = ASMBitLastSetU32((uint32_t)(u64 >> 32)); + if (iBit) + iBit += 32; + else + iBit = ASMBitLastSetU32((uint32_t)u64); +# endif + return (unsigned)iBit; +} +#endif + + +/** + * Finds the last bit which is set in the given 16-bit integer. + * + * Bits are numbered from 1 (least significant) to 16. + * + * @returns index [1..16] of the last set bit. + * @returns 0 if all bits are cleared. + * @param u16 Integer to search for set bits. + * @remarks For 16-bit bs3kit code. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMBitLastSetU16(uint16_t u16) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMBitLastSetU16(uint16_t u16) RT_NOTHROW_DEF +{ + return ASMBitLastSetU32((uint32_t)u16); +} +#endif + + +/** + * Count the number of leading zero bits in the given 32-bit integer. + * + * The counting starts with the most significate bit. + * + * @returns Number of most significant zero bits. + * @returns 32 if all bits are cleared. + * @param u32 Integer to consider. + * @remarks Similar to __builtin_clz() in gcc, except defined zero input result. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMCountLeadingZerosU32(uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMCountLeadingZerosU32(uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + unsigned long iBit; + if (!_BitScanReverse(&iBit, u32)) + return 32; + return 31 - (unsigned)iBit; + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) + uint32_t iBit; +# if RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) && 0 /* significantly slower on 10980xe; 929 vs 237 ps/call */ + __asm__ __volatile__("bsrl %1, %0\n\t" + "cmovzl %2, %0\n\t" + : "=&r" (iBit) + : "rm" (u32) + , "rm" ((int32_t)-1) + : "cc"); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("bsr %1, %0\n\t" + "jnz 1f\n\t" + "mov $-1, %0\n\t" + "1:\n\t" + : "=r" (iBit) + : "rm" (u32) + : "cc"); +# else + _asm + { + bsr eax, [u32] + jnz found + mov eax, -1 + found: + mov [iBit], eax + } +# endif + return 31 - iBit; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + uint32_t iBit; + __asm__ __volatile__( +# if defined(RT_ARCH_ARM64) + "clz %w[iBit], %w[uVal]\n\t" +# else + "clz %[iBit], %[uVal]\n\t" +# endif + : [uVal] "=r" (u32) + , [iBit] "=r" (iBit) + : "[uVal]" (u32)); + return iBit; + +# elif defined(__GNUC__) + AssertCompile(sizeof(u32) == sizeof(unsigned int)); + return u32 ? __builtin_clz(u32) : 32; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Count the number of leading zero bits in the given 64-bit integer. + * + * The counting starts with the most significate bit. + * + * @returns Number of most significant zero bits. + * @returns 64 if all bits are cleared. + * @param u64 Integer to consider. + * @remarks Similar to __builtin_clzl() in gcc, except defined zero input + * result. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMCountLeadingZerosU64(uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMCountLeadingZerosU64(uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + unsigned long iBit; +# if ARCH_BITS == 64 + if (_BitScanReverse64(&iBit, u64)) + return 63 - (unsigned)iBit; +# else + if (_BitScanReverse(&iBit, (uint32_t)(u64 >> 32))) + return 31 - (unsigned)iBit; + if (_BitScanReverse(&iBit, (uint32_t)u64)) + return 63 - (unsigned)iBit; +# endif + return 64; + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + uint64_t iBit; +# if 0 /* 10980xe benchmark: 932 ps/call - the slower variant */ + __asm__ __volatile__("bsrq %1, %0\n\t" + "cmovzq %2, %0\n\t" + : "=&r" (iBit) + : "rm" (u64) + , "rm" ((int64_t)-1) + : "cc"); +# else /* 10980xe benchmark: 262 ps/call */ + __asm__ __volatile__("bsrq %1, %0\n\t" + "jnz 1f\n\t" + "mov $-1, %0\n\t" + "1:\n\t" + : "=&r" (iBit) + : "rm" (u64) + : "cc"); +# endif + return 63 - (unsigned)iBit; + +# elif defined(RT_ARCH_ARM64) + uint64_t iBit; + __asm__ __volatile__("clz %[iBit], %[uVal]\n\t" + : [uVal] "=r" (u64) + , [iBit] "=r" (iBit) + : "[uVal]" (u64)); + return (unsigned)iBit; + +# elif defined(__GNUC__) && ARCH_BITS == 64 + AssertCompile(sizeof(u64) == sizeof(unsigned long)); + return u64 ? __builtin_clzl(u64) : 64; + +# else + unsigned iBit = ASMCountLeadingZerosU32((uint32_t)(u64 >> 32)); + if (iBit == 32) + iBit = ASMCountLeadingZerosU32((uint32_t)u64) + 32; + return iBit; +# endif +} +#endif + + +/** + * Count the number of leading zero bits in the given 16-bit integer. + * + * The counting starts with the most significate bit. + * + * @returns Number of most significant zero bits. + * @returns 16 if all bits are cleared. + * @param u16 Integer to consider. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMCountLeadingZerosU16(uint16_t u16) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMCountLeadingZerosU16(uint16_t u16) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_GNU_STYLE && (defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)) && 0 /* slower (10980xe: 987 vs 292 ps/call) */ + uint16_t iBit; + __asm__ __volatile__("bsrw %1, %0\n\t" + "jnz 1f\n\t" + "mov $-1, %0\n\t" + "1:\n\t" + : "=r" (iBit) + : "rm" (u16) + : "cc"); + return 15 - (int16_t)iBit; +# else + return ASMCountLeadingZerosU32((uint32_t)u16) - 16; +# endif +} +#endif + + +/** + * Count the number of trailing zero bits in the given 32-bit integer. + * + * The counting starts with the least significate bit, i.e. the zero bit. + * + * @returns Number of lest significant zero bits. + * @returns 32 if all bits are cleared. + * @param u32 Integer to consider. + * @remarks Similar to __builtin_ctz() in gcc, except defined zero input result. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMCountTrailingZerosU32(uint32_t u32) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMCountTrailingZerosU32(uint32_t u32) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + unsigned long iBit; + if (!_BitScanForward(&iBit, u32)) + return 32; + return (unsigned)iBit; + +# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) + uint32_t iBit; +# if RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) && 0 /* significantly slower on 10980xe; 932 vs 240 ps/call */ + __asm__ __volatile__("bsfl %1, %0\n\t" + "cmovzl %2, %0\n\t" + : "=&r" (iBit) + : "rm" (u32) + , "rm" ((int32_t)32) + : "cc"); +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__("bsfl %1, %0\n\t" + "jnz 1f\n\t" + "mov $32, %0\n\t" + "1:\n\t" + : "=r" (iBit) + : "rm" (u32) + : "cc"); +# else + _asm + { + bsf eax, [u32] + jnz found + mov eax, 32 + found: + mov [iBit], eax + } +# endif + return iBit; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + /* Invert the bits and use clz. */ + uint32_t iBit; + __asm__ __volatile__( +# if defined(RT_ARCH_ARM64) + "rbit %w[uVal], %w[uVal]\n\t" + "clz %w[iBit], %w[uVal]\n\t" +# else + "rbit %[uVal], %[uVal]\n\t" + "clz %[iBit], %[uVal]\n\t" +# endif + : [uVal] "=r" (u32) + , [iBit] "=r" (iBit) + : "[uVal]" (u32)); + return iBit; + +# elif defined(__GNUC__) + AssertCompile(sizeof(u32) == sizeof(unsigned int)); + return u32 ? __builtin_ctz(u32) : 32; + +# else +# error "Port me" +# endif +} +#endif + + +/** + * Count the number of trailing zero bits in the given 64-bit integer. + * + * The counting starts with the least significate bit. + * + * @returns Number of least significant zero bits. + * @returns 64 if all bits are cleared. + * @param u64 Integer to consider. + * @remarks Similar to __builtin_ctzl() in gcc, except defined zero input + * result. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMCountTrailingZerosU64(uint64_t u64) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMCountTrailingZerosU64(uint64_t u64) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + unsigned long iBit; +# if ARCH_BITS == 64 + if (_BitScanForward64(&iBit, u64)) + return (unsigned)iBit; +# else + if (_BitScanForward(&iBit, (uint32_t)u64)) + return (unsigned)iBit; + if (_BitScanForward(&iBit, (uint32_t)(u64 >> 32))) + return (unsigned)iBit + 32; +# endif + return 64; + +# elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + uint64_t iBit; +# if 0 /* 10980xe benchmark: 932 ps/call - the slower variant */ + __asm__ __volatile__("bsfq %1, %0\n\t" + "cmovzq %2, %0\n\t" + : "=&r" (iBit) + : "rm" (u64) + , "rm" ((int64_t)64) + : "cc"); +# else /* 10980xe benchmark: 262 ps/call */ + __asm__ __volatile__("bsfq %1, %0\n\t" + "jnz 1f\n\t" + "mov $64, %0\n\t" + "1:\n\t" + : "=&r" (iBit) + : "rm" (u64) + : "cc"); +# endif + return (unsigned)iBit; + +# elif defined(RT_ARCH_ARM64) + /* Invert the bits and use clz. */ + uint64_t iBit; + __asm__ __volatile__("rbit %[uVal], %[uVal]\n\t" + "clz %[iBit], %[uVal]\n\t" + : [uVal] "=r" (u64) + , [iBit] "=r" (iBit) + : "[uVal]" (u64)); + return (unsigned)iBit; + +# elif defined(__GNUC__) && ARCH_BITS == 64 + AssertCompile(sizeof(u64) == sizeof(unsigned long)); + return u64 ? __builtin_ctzl(u64) : 64; + +# else + unsigned iBit = ASMCountTrailingZerosU32((uint32_t)u64); + if (iBit == 32) + iBit = ASMCountTrailingZerosU32((uint32_t)(u64 >> 32)) + 32; + return iBit; +# endif +} +#endif + + +/** + * Count the number of trailing zero bits in the given 16-bit integer. + * + * The counting starts with the most significate bit. + * + * @returns Number of most significant zero bits. + * @returns 16 if all bits are cleared. + * @param u16 Integer to consider. + */ +#if RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN +RT_ASM_DECL_PRAGMA_WATCOM_386(unsigned) ASMCountTrailingZerosU16(uint16_t u16) RT_NOTHROW_PROTO; +#else +DECLINLINE(unsigned) ASMCountTrailingZerosU16(uint16_t u16) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_GNU_STYLE && (defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)) && 0 /* slower (10980xe: 992 vs 349 ps/call) */ + uint16_t iBit; + __asm__ __volatile__("bsfw %1, %0\n\t" + "jnz 1f\n\t" + "mov $16, %0\n\t" + "1:\n\t" + : "=r" (iBit) + : "rm" (u16) + : "cc"); + return iBit; +# else + return ASMCountTrailingZerosU32((uint32_t)u16 | UINT32_C(0x10000)); +#endif +} +#endif + + +/** + * Rotate 32-bit unsigned value to the left by @a cShift. + * + * @returns Rotated value. + * @param u32 The value to rotate. + * @param cShift How many bits to rotate by. + */ +#ifdef __WATCOMC__ +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMRotateLeftU32(uint32_t u32, unsigned cShift) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMRotateLeftU32(uint32_t u32, uint32_t cShift) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + return _rotl(u32, cShift); + +# elif RT_INLINE_ASM_GNU_STYLE && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) + __asm__ __volatile__("roll %b1, %0" : "=g" (u32) : "Ic" (cShift), "0" (u32) : "cc"); + return u32; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + __asm__ __volatile__( +# if defined(RT_ARCH_ARM64) + "ror %w[uRet], %w[uVal], %w[cShift]\n\t" +# else + "ror %[uRet], %[uVal], %[cShift]\n\t" +# endif + : [uRet] "=r" (u32) + : [uVal] "[uRet]" (u32) + , [cShift] "r" (32 - (cShift & 31))); /** @todo there is an immediate form here */ + return u32; + +# else + cShift &= 31; + return (u32 << cShift) | (u32 >> (32 - cShift)); +# endif +} +#endif + + +/** + * Rotate 32-bit unsigned value to the right by @a cShift. + * + * @returns Rotated value. + * @param u32 The value to rotate. + * @param cShift How many bits to rotate by. + */ +#ifdef __WATCOMC__ +RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMRotateRightU32(uint32_t u32, unsigned cShift) RT_NOTHROW_PROTO; +#else +DECLINLINE(uint32_t) ASMRotateRightU32(uint32_t u32, uint32_t cShift) RT_NOTHROW_DEF +{ +# if RT_INLINE_ASM_USES_INTRIN + return _rotr(u32, cShift); + +# elif RT_INLINE_ASM_GNU_STYLE && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) + __asm__ __volatile__("rorl %b1, %0" : "=g" (u32) : "Ic" (cShift), "0" (u32) : "cc"); + return u32; + +# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) + __asm__ __volatile__( +# if defined(RT_ARCH_ARM64) + "ror %w[uRet], %w[uVal], %w[cShift]\n\t" +# else + "ror %[uRet], %[uVal], %[cShift]\n\t" +# endif + : [uRet] "=r" (u32) + : [uVal] "[uRet]" (u32) + , [cShift] "r" (cShift & 31)); /** @todo there is an immediate form here */ + return u32; + +# else + cShift &= 31; + return (u32 >> cShift) | (u32 << (32 - cShift)); +# endif +} +#endif + + +/** + * Rotate 64-bit unsigned value to the left by @a cShift. + * + * @returns Rotated value. + * @param u64 The value to rotate. + * @param cShift How many bits to rotate by. + */ +DECLINLINE(uint64_t) ASMRotateLeftU64(uint64_t u64, uint32_t cShift) RT_NOTHROW_DEF +{ +#if RT_INLINE_ASM_USES_INTRIN + return _rotl64(u64, cShift); + +#elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + __asm__ __volatile__("rolq %b1, %0" : "=g" (u64) : "Jc" (cShift), "0" (u64) : "cc"); + return u64; + +#elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_X86) + uint32_t uSpill; + __asm__ __volatile__("testb $0x20, %%cl\n\t" /* if (cShift >= 0x20) { swap(u64.hi, u64lo); cShift -= 0x20; } */ + "jz 1f\n\t" + "xchgl %%eax, %%edx\n\t" + "1:\n\t" + "andb $0x1f, %%cl\n\t" /* if (cShift & 0x1f) { */ + "jz 2f\n\t" + "movl %%edx, %2\n\t" /* save the hi value in %3. */ + "shldl %%cl,%%eax,%%edx\n\t" /* shift the hi value left, feeding MSBits from the low value. */ + "shldl %%cl,%2,%%eax\n\t" /* shift the lo value left, feeding MSBits from the saved hi value. */ + "2:\n\t" /* } */ + : "=A" (u64) + , "=c" (cShift) + , "=r" (uSpill) + : "0" (u64) + , "1" (cShift) + : "cc"); + return u64; + +# elif defined(RT_ARCH_ARM64) + __asm__ __volatile__("ror %[uRet], %[uVal], %[cShift]\n\t" + : [uRet] "=r" (u64) + : [uVal] "[uRet]" (u64) + , [cShift] "r" ((uint64_t)(64 - (cShift & 63)))); /** @todo there is an immediate form here */ + return u64; + +#else + cShift &= 63; + return (u64 << cShift) | (u64 >> (64 - cShift)); +#endif +} + + +/** + * Rotate 64-bit unsigned value to the right by @a cShift. + * + * @returns Rotated value. + * @param u64 The value to rotate. + * @param cShift How many bits to rotate by. + */ +DECLINLINE(uint64_t) ASMRotateRightU64(uint64_t u64, uint32_t cShift) RT_NOTHROW_DEF +{ +#if RT_INLINE_ASM_USES_INTRIN + return _rotr64(u64, cShift); + +#elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64) + __asm__ __volatile__("rorq %b1, %0" : "=g" (u64) : "Jc" (cShift), "0" (u64) : "cc"); + return u64; + +#elif RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_X86) + uint32_t uSpill; + __asm__ __volatile__("testb $0x20, %%cl\n\t" /* if (cShift >= 0x20) { swap(u64.hi, u64lo); cShift -= 0x20; } */ + "jz 1f\n\t" + "xchgl %%eax, %%edx\n\t" + "1:\n\t" + "andb $0x1f, %%cl\n\t" /* if (cShift & 0x1f) { */ + "jz 2f\n\t" + "movl %%edx, %2\n\t" /* save the hi value in %3. */ + "shrdl %%cl,%%eax,%%edx\n\t" /* shift the hi value right, feeding LSBits from the low value. */ + "shrdl %%cl,%2,%%eax\n\t" /* shift the lo value right, feeding LSBits from the saved hi value. */ + "2:\n\t" /* } */ + : "=A" (u64) + , "=c" (cShift) + , "=r" (uSpill) + : "0" (u64) + , "1" (cShift) + : "cc"); + return u64; + +# elif defined(RT_ARCH_ARM64) + __asm__ __volatile__("ror %[uRet], %[uVal], %[cShift]\n\t" + : [uRet] "=r" (u64) + : [uVal] "[uRet]" (u64) + , [cShift] "r" ((uint64_t)(cShift & 63))); /** @todo there is an immediate form here */ + return u64; + +#else + cShift &= 63; + return (u64 >> cShift) | (u64 << (64 - cShift)); +#endif +} + +/** @} */ + + +/** @} */ + +/* + * Include #pragma aux definitions for Watcom C/C++. + */ +#if defined(__WATCOMC__) && ARCH_BITS == 16 && defined(RT_ARCH_X86) +# define IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS +# undef IPRT_INCLUDED_asm_watcom_x86_16_h +# include "asm-watcom-x86-16.h" +#elif defined(__WATCOMC__) && ARCH_BITS == 32 && defined(RT_ARCH_X86) +# define IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS +# undef IPRT_INCLUDED_asm_watcom_x86_32_h +# include "asm-watcom-x86-32.h" +#endif + +#endif /* !IPRT_INCLUDED_asm_h */ + diff --git a/include/iprt/asmdefs.mac b/include/iprt/asmdefs.mac new file mode 100644 index 00000000..d798a0c0 --- /dev/null +++ b/include/iprt/asmdefs.mac @@ -0,0 +1,1379 @@ +;; @file +; IPRT - Global YASM/NASM macros +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +; Special hack for bs3kit. +%ifdef RT_ASMDEFS_INC_FIRST_FILE + %include "asmdefs-first.mac" +%endif + +%ifndef ___iprt_asmdefs_mac +%define ___iprt_asmdefs_mac + + +;; @defgroup grp_rt_cdefs_size Size Constants +; (Of course, these are binary computer terms, not SI.) +; @{ +;; 1 K (Kilo) (1 024). +%define _1K 000000400h +;; 4 K (Kilo) (4 096). +%define _4K 000001000h +;; 8 K (Kilo) (8 192). +%define _8K 000002000h +;; 16 K (Kilo) (16 384). +%define _16K 000004000h +;; 32 K (Kilo) (32 768). +%define _32K 000008000h +;; 64 K (Kilo) (65 536). +%define _64K 000010000h +;; 128 K (Kilo) (131 072). +%define _128K 000020000h +;; 256 K (Kilo) (262 144). +%define _256K 000040000h +;; 512 K (Kilo) (524 288). +%define _512K 000080000h +;; 1 M (Mega) (1 048 576). +%define _1M 000100000h +;; 2 M (Mega) (2 097 152). +%define _2M 000200000h +;; 4 M (Mega) (4 194 304). +%define _4M 000400000h +;; 1 G (Giga) (1 073 741 824). +%define _1G 040000000h +;; 2 G (Giga) (2 147 483 648). +%define _2G 00000000080000000h +;; 4 G (Giga) (4 294 967 296). +%define _4G 00000000100000000h +;; 1 T (Tera) (1 099 511 627 776). +%define _1T 00000010000000000h +;; 1 P (Peta) (1 125 899 906 842 624). +%define _1P 00004000000000000h +;; 1 E (Exa) (1 152 921 504 606 846 976). +%define _1E 01000000000000000h +;; 2 E (Exa) (2 305 843 009 213 693 952). +%define _2E 02000000000000000h +;; @} + + +;; +; Define RT_STRICT for debug builds like iprt/cdefs.h does. +%ifndef RT_STRICT + %ifdef DEBUG + %define RT_STRICT + %endif +%endif +%ifdef RT_NO_STRICT + %undef RT_STRICT +%endif + +;; +; Make the mask for the given bit. +%define RT_BIT(bit) (1 << bit) + +;; +; Make the mask for the given bit. +%define RT_BIT_32(bit) (1 << bit) +;; +; Make the mask for the given bit. +%define RT_BIT_64(bit) (1 << bit) + +;; +; Makes a 32-bit unsigned (not type safe, but whatever) out of four byte values. +%define RT_MAKE_U32_FROM_U8(b0, b1, b2, b3) ( (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 ) + +;; Preprocessor concatenation macro. +%define RT_CONCAT(a_1,a_2) a_1 %+ a_2 + +;; Preprocessor concatenation macro, three arguments. +%define RT_CONCAT3(a_1,a_2,a_3) a_1 %+ a_2 %+ a_3 + +;; Preprocessor concatenation macro, four arguments. +%define RT_CONCAT4(a_1,a_2,a_3,a_4) a_1 %+ a_2 %+ a_3 %+ a_4 + +;; +; Trick for using RT_CONCAT and the like on %define names. +; @param 1 The name (expression. +; @param 2 The value. +%macro RT_DEFINE_EX 2 + %error 1=%1 2=%2 + %define %1 %2 +%endmacro + +;; +; Trick for using RT_CONCAT and the like on %xdefine names. +; @param 1 The name (expression. +; @param 2 The value. +%macro RT_XDEFINE_EX 2 + %xdefine %1 %2 +%endmacro + +;; +; Trick for using RT_CONCAT and the like on %undef names. +; @param 1 The name (expression. +%macro RT_UNDEF_EX 1 + %error 1=%1 + %undef %1 +%endmacro + +;; +; Empty define +%define RT_NOTHING + +;; Define ASM_FORMAT_PE64 if applicable. +%ifdef ASM_FORMAT_PE + %ifdef RT_ARCH_AMD64 + %define ASM_FORMAT_PE64 1 + %endif +%endif + +;; +; SEH64 macros. +%ifdef RT_ASM_WITH_SEH64 + %ifndef ASM_FORMAT_PE64 + %undef RT_ASM_WITH_SEH64 + %endif +%endif + +%ifdef RT_ASM_WITH_SEH64_ALT + %ifdef ASM_FORMAT_PE64 + ;; @name Register numbers. Used with RT_CONCAT to convert macro inputs to numbers. + ;; @{ + %define SEH64_PE_GREG_rax 0 + %define SEH64_PE_GREG_xAX 0 + %define SEH64_PE_GREG_rcx 1 + %define SEH64_PE_GREG_xCX 1 + %define SEH64_PE_GREG_rdx 2 + %define SEH64_PE_GREG_xDX 2 + %define SEH64_PE_GREG_rbx 3 + %define SEH64_PE_GREG_xBX 3 + %define SEH64_PE_GREG_rsp 4 + %define SEH64_PE_GREG_xSP 4 + %define SEH64_PE_GREG_rbp 5 + %define SEH64_PE_GREG_xBP 5 + %define SEH64_PE_GREG_rsi 6 + %define SEH64_PE_GREG_xSI 6 + %define SEH64_PE_GREG_rdi 7 + %define SEH64_PE_GREG_xDI 7 + %define SEH64_PE_GREG_r8 8 + %define SEH64_PE_GREG_r9 9 + %define SEH64_PE_GREG_r10 10 + %define SEH64_PE_GREG_r11 11 + %define SEH64_PE_GREG_r12 12 + %define SEH64_PE_GREG_r13 13 + %define SEH64_PE_GREG_r14 14 + %define SEH64_PE_GREG_r15 15 + ;; @} + + ;; @name PE unwind operations. + ;; @{ + %define SEH64_PE_PUSH_NONVOL 0 + %define SEH64_PE_ALLOC_LARGE 1 + %define SEH64_PE_ALLOC_SMALL 2 + %define SEH64_PE_SET_FPREG 3 + %define SEH64_PE_SAVE_NONVOL 4 + %define SEH64_PE_SAVE_NONVOL_FAR 5 + %define SEH64_PE_SAVE_XMM128 8 + %define SEH64_PE_SAVE_XMM128_FAR 9 + ;; @} + + ;; + ; Starts the unwind info for the manual SEH64 info generation. + ; @param 1 Function name. + %macro SEH64_ALT_START_UNWIND_INFO 1 + %assign seh64_idxOps 0 + %assign seh64_FrameReg SEH64_PE_GREG_rsp + %assign seh64_offFrame 0 + %define asm_seh64_proc %1 + %undef seh64_slot_bytes + %endmacro + + ;; We keep the unwind bytes in the seh64_slot_bytes (x)define, in reverse order as per spec. + %macro SEH64_APPEND_SLOT_PAIR 2 + %ifdef seh64_slot_bytes + %xdefine seh64_slot_bytes %1, %2, seh64_slot_bytes + %else + %xdefine seh64_slot_bytes %1, %2 + %endif + %endmacro + + ;; For multi-slot unwind info. + %macro SEH64_APPEND_SLOT_BYTES 2+ + %rep %0 + %rotate -1 + %ifdef seh64_slot_bytes + %xdefine seh64_slot_bytes %1, seh64_slot_bytes + %else + %xdefine seh64_slot_bytes %1 + %endif + %endrep + %endmacro + + %else + %undef RT_ASM_WITH_SEH64_ALT + %endif +%endif + +;; +; Records a xBP push. +%macro SEH64_PUSH_xBP 0 + %ifdef RT_ASM_WITH_SEH64 + [pushreg rbp] + + %elifdef RT_ASM_WITH_SEH64_ALT +RT_CONCAT(.seh64_op_label_,seh64_idxOps): + %ifdef ASM_FORMAT_PE64 + SEH64_APPEND_SLOT_PAIR RT_CONCAT(.seh64_op_label_,seh64_idxOps) - .start_of_prologue, \ + SEH64_PE_PUSH_NONVOL | (SEH64_PE_GREG_rbp << 4) + %endif + %assign seh64_idxOps seh64_idxOps + 1 + %endif +%endmacro + +;; +; Records a general register push. +; @param 1 Register name. +%macro SEH64_PUSH_GREG 1 + %ifdef RT_ASM_WITH_SEH64 + [pushreg %1] + + %elifdef RT_ASM_WITH_SEH64_ALT +RT_CONCAT(.seh64_op_label_,seh64_idxOps): + %ifdef ASM_FORMAT_PE64 + SEH64_APPEND_SLOT_PAIR RT_CONCAT(.seh64_op_label_,seh64_idxOps) - .start_of_prologue, \ + SEH64_PE_PUSH_NONVOL | (RT_CONCAT(SEH64_PE_GREG_,%1) << 4) + %endif + %assign seh64_idxOps seh64_idxOps + 1 + %endif +%endmacro + +;; +; Sets xBP as frame pointer that's pointing to a stack position %1 relative to xBP. +%macro SEH64_SET_FRAME_xBP 1 + %ifdef RT_ASM_WITH_SEH64 + [setframe rbp, %1] + + %elifdef RT_ASM_WITH_SEH64_ALT +RT_CONCAT(.seh64_op_label_,seh64_idxOps): + %ifdef ASM_FORMAT_PE64 + SEH64_APPEND_SLOT_PAIR RT_CONCAT(.seh64_op_label_,seh64_idxOps) - .start_of_prologue, \ + SEH64_PE_SET_FPREG | 0 ; vs2019 seems to put the offset in the info field + %assign seh64_FrameReg SEH64_PE_GREG_rbp + %assign seh64_offFrame %1 + %endif + %assign seh64_idxOps seh64_idxOps + 1 + %endif +%endmacro + +;; +; Records an ADD xSP, %1. +%macro SEH64_ALLOCATE_STACK 1 + %ifdef RT_ASM_WITH_SEH64 + [allocstack %1] + + %elifdef RT_ASM_WITH_SEH64_ALT +RT_CONCAT(.seh64_op_label_,seh64_idxOps): + %ifdef ASM_FORMAT_PE64 + %if (%1) & 7 + %error "SEH64_ALLOCATE_STACK must be a multiple of 8" + %endif + %if (%1) < 8 + %error "SEH64_ALLOCATE_STACK must have an argument that's 8 or higher." + %elif (%1) <= 128 + SEH64_APPEND_SLOT_PAIR RT_CONCAT(.seh64_op_label_,seh64_idxOps) - .start_of_prologue, \ + SEH64_PE_ALLOC_SMALL | ((((%1) / 8) - 1) << 4) + %elif (%1) < 512 + SEH64_APPEND_SLOT_BYTES RT_CONCAT(.seh64_op_label_,seh64_idxOps) - .start_of_prologue, \ + SEH64_PE_ALLOC_LARGE | 0, \ + ((%1) / 8) & 0xff, ((%1) / 8) >> 8 + %else + SEH64_APPEND_SLOT_BYTES RT_CONCAT(.seh64_op_label_,seh64_idxOps) - .start_of_prologue, \ + SEH64_PE_ALLOC_LARGE | 1, \ + (%1) & 0xff, ((%1) >> 8) & 0xff, ((%1) >> 16) & 0xff, ((%1) >> 24) & 0xff + %endif + %endif + %assign seh64_idxOps seh64_idxOps + 1 + %endif +%endmacro + +%macro SEH64_INFO_HELPER 1 +%if defined(%1) + dw %1 +%endif +%endmacro + +;; +; Ends the prologue. +%macro SEH64_END_PROLOGUE 0 +.end_of_prologue: + %ifdef RT_ASM_WITH_SEH64 + [endprolog] + + %elifdef RT_ASM_WITH_SEH64_ALT + %ifdef ASM_FORMAT_PE + ; Emit the unwind info now. + %ifndef ASM_DEFINED_XDATA_SECTION + %define ASM_DEFINED_XDATA_SECTION + section .xdata rdata align=4 + %else + section .xdata + align 4, db 0 + %endif +.unwind_info: + db 1 ; version 1 (3 bit), no flags (5 bits) + db .end_of_prologue - .start_of_prologue + + db (.unwind_info_array_end - .unwind_info_array) / 2 + db seh64_FrameReg | (seh64_offFrame & 0xf0) ; framereg and offset/16. +.unwind_info_array: + %ifdef seh64_slot_bytes + db seh64_slot_bytes + %undef seh64_slot_bytes + %endif +.unwind_info_array_end: + + ; Reset the segment + BEGINCODE + %endif + %endif +%endmacro + + +;; +; Align code, pad with INT3. +%define ALIGNCODE(alignment) align alignment, db 0cch + +;; +; Align data, pad with ZEROs. +%define ALIGNDATA(alignment) align alignment, db 0 + +;; +; Align BSS, pad with ZEROs. +%define ALIGNBSS(alignment) align alignment, resb 1 + +;; +; NAME_OVERLOAD can be defined by a .asm module to modify all the +; names created using the name macros in this files. +; This is handy when you've got some kind of template code. +%ifndef NAME_OVERLOAD + %ifdef RT_MANGLER_PREFIX + %define NAME_OVERLOAD(name) RT_MANGLER_PREFIX %+ name + %else + %define NAME_OVERLOAD(name) name + %endif +%endif + +;; +; Mangles the given name so it can be referenced using DECLASM() in the +; C/C++ world. +%ifndef ASM_FORMAT_BIN + %ifdef RT_ARCH_X86 + %ifdef RT_OS_OS2 + %define NAME(name) _ %+ NAME_OVERLOAD(name) + %endif + %ifdef RT_OS_WINDOWS + %define NAME(name) _ %+ NAME_OVERLOAD(name) + %endif + %endif + %ifdef RT_OS_DARWIN + %define NAME(name) _ %+ NAME_OVERLOAD(name) + %endif +%endif +%ifndef NAME + %define NAME(name) NAME_OVERLOAD(name) +%endif + +;; +; Mangles the given C name so it will _import_ the right symbol. +%ifdef ASM_FORMAT_PE + %define IMPNAME(name) __imp_ %+ NAME(name) +%else + %define IMPNAME(name) NAME(name) +%endif + +;; +; Gets the pointer to an imported object. +%ifdef ASM_FORMAT_PE + %ifdef RT_ARCH_AMD64 + %define IMP(name) qword [IMPNAME(name) wrt rip] + %else + %define IMP(name) dword [IMPNAME(name)] + %endif +%else + %define IMP(name) IMPNAME(name) +%endif + +;; +; Gets the pointer to an imported object. +%ifdef ASM_FORMAT_PE + %ifdef RT_ARCH_AMD64 + %define IMP_SEG(SegOverride, name) qword [SegOverride:IMPNAME(name) wrt rip] + %else + %define IMP_SEG(SegOverride, name) dword [SegOverride:IMPNAME(name)] + %endif +%else + %define IMP_SEG(SegOverride, name) IMPNAME(name) +%endif + +;; +; Declares an imported object for use with IMP2. +; @note May change the current section! +%macro EXTERN_IMP2 1 + extern IMPNAME(%1) + BEGINDATA + %ifdef ASM_FORMAT_MACHO + g_Imp2_ %+ %1: RTCCPTR_DEF IMPNAME(%1) + %endif +%endmacro + +;; +; Gets the pointer to an imported object, version 2. +%ifdef ASM_FORMAT_PE + %ifdef RT_ARCH_AMD64 + %define IMP2(name) qword [IMPNAME(name) wrt rip] + %else + %define IMP2(name) dword [IMPNAME(name)] + %endif +%elifdef ASM_FORMAT_ELF + %ifdef PIC + %ifdef RT_ARCH_AMD64 + %define IMP2(name) qword [rel IMPNAME(name) wrt ..got] + %else + %define IMP2(name) IMPNAME(name) wrt ..plt + %endif + %endif +%elifdef ASM_FORMAT_MACHO + %define IMP2(name) RTCCPTR_PRE [g_Imp2_ %+ name xWrtRIP] +%endif +%ifndef IMP2 + %define IMP2(name) IMPNAME(name) +%endif + + +;; +; Define a label as given, with a '$' prepended to permit using instruction +; names like fdiv as labels. +%macro SAFE_LABEL 1 +$%1: +%endmacro + +;; +; Global marker which is DECLASM() compatible. +%macro GLOBALNAME 1 +%ifndef ASM_FORMAT_BIN +global NAME(%1) +%endif +SAFE_LABEL NAME(%1) +%endmacro + +;; +; Global exported marker which is DECLASM() compatible. +%macro EXPORTEDNAME 1 + %ifdef ASM_FORMAT_PE + export %1=NAME(%1) + %endif + %ifdef __NASM__ + %ifdef ASM_FORMAT_OMF + export NAME(%1) NAME(%1) + %endif +%endif +GLOBALNAME %1 +%endmacro + +;; +; Same as GLOBALNAME_EX, but without the name mangling. +; +; @param %1 The symbol name - subjected to NAME(). +; @param %2 ELF and PE attributes: 'function', 'object', 'data', 'notype'. +; PE ignores all but 'function' (yasm only). Other formats ignores +; this completely. +; @param %3 Symbol visibility: 'hidden', 'protected', 'internal', and +; RT_NOTHING (for 'default' visibility). +; These are ELF attributes, but 'hidden' is translated to +; 'private_extern' for the Macho-O format. +; Ignored by other formats. +; +%macro GLOBALNAME_RAW 3 +%ifdef ASM_FORMAT_ELF +global %1:%2 %3 + +%elifdef ASM_FORMAT_PE + %ifidn %2,function + %ifdef __YASM__ ; nasm does not support any attributes, it errors out. So, nasm is no good with control flow guard atm. +global %1:function + %else +global %1 + %endif + %else +global %1 + %endif + +%elifdef ASM_FORMAT_MACHO + %ifidn %3,hidden +global %1:private_extern + %else +global %1 + %endif + +%elifndef ASM_FORMAT_BIN +global %1 + +%endif + +%1: +%endmacro + +;; +; Global marker which is DECLASM() compatible. +; +; @param %1 The symbol name - subjected to NAME(). +; @param %2 ELF and PE attributes: 'function', 'object', 'data', 'notype'. +; PE ignores all but 'function' (yasm only). Other formats ignores +; this completely. +; @param %3 Symbol visibility: 'hidden', 'protected', 'internal', and +; RT_NOTHING (for 'default' visibility). +; These are ELF attributes, but 'hidden' is translated to +; 'private_extern' for the Macho-O format. +; Ignored by other formats. +; +%macro GLOBALNAME_EX 3 +GLOBALNAME_RAW NAME(%1), %2, %3 +%endmacro + + +;; +; Global exported marker, raw version w/o automatic name mangling. +; +; @param %1 The internal symbol name. +; @param %2 The external symbol name. +; @param %3 ELF and PE attributes: 'function', 'object', 'data', 'notype'. +; PE ignores all but 'function' (yasm only). Other formats ignores +; this completely. +; +%macro EXPORTEDNAME_RAW 3 + %ifdef ASM_FORMAT_PE + export %2=%1 + %endif + %ifdef __NASM__ + %ifdef ASM_FORMAT_OMF + export %1 %2 + %endif +%endif +GLOBALNAME_RAW %1, %3, RT_NOTHING +%endmacro + +;; +; Global exported marker which is DECLASM() compatible. +; +; @param %1 The symbol name - subjected to NAME(). +; @param %2 ELF and PE attributes: 'function', 'object', 'data', 'notype'. +; PE ignores all but 'function' (yasm only). Other formats ignores +; this completely. +; +%macro EXPORTEDNAME_EX 2 +EXPORTEDNAME_RAW NAME(%1), %1, %2 +%endmacro + + +;; +; Begins a procedure, raw version w/o automatic name mangling. +%macro BEGINPROC_RAW 1 + %ifdef RT_ASM_WITH_SEH64_ALT + SEH64_ALT_START_UNWIND_INFO %1 + %endif + %ifdef RT_ASM_WITH_SEH64 +global %1:function +proc_frame %1 + %else +GLOBALNAME_RAW %1, function, hidden + %endif +.start_of_prologue: +%endmacro + +;; +; Begins a C callable (DECLASM) procedure. +%macro BEGINPROC 1 +BEGINPROC_RAW NAME(%1) +%endmacro + + +;; +; Begins a exported procedure, raw version w/o automatic name mangling. +; @param 1 Internal name. +; @param 2 Exported name. +%macro BEGINPROC_EXPORTED_RAW 2 + %ifdef RT_ASM_WITH_SEH64_ALT + SEH64_ALT_START_UNWIND_INFO %1 + %endif + %ifdef RT_ASM_WITH_SEH64 + %ifdef ASM_FORMAT_PE +export %2=%1 + %endif +global %1:function +proc_frame %1 + %else +EXPORTEDNAME_RAW %1, %2, function + %endif +.start_of_prologue: +%endmacro + +;; +; Begins a C callable (DECLASM) exported procedure. +%macro BEGINPROC_EXPORTED 1 +BEGINPROC_EXPORTED_RAW NAME(%1), %1 +%endmacro + + +;; +; Ends a procedure, raw version w/o automatic name mangling. +%macro ENDPROC_RAW 1 + %ifdef RT_ASM_WITH_SEH64 +endproc_frame + %endif +GLOBALNAME_RAW %1 %+ _EndProc, , hidden ; no function here, this isn't a valid code flow target. +%ifdef ASM_FORMAT_ELF + %ifndef __NASM__ ; nasm does this in the global directive. +size %1 %1 %+ _EndProc - %1 +size %1 %+ _EndProc 4 ; make it non-zero to shut up warnigns from Linux's objtool. + %endif +%endif + db 0xCC, 0xCC, 0xCC, 0xCC + + %ifdef RT_ASM_WITH_SEH64_ALT + %ifdef ASM_FORMAT_PE + ; Emit the RUNTIME_FUNCTION entry. The linker is picky here, no label. + %ifndef ASM_DEFINED_PDATA_SECTION + %define ASM_DEFINED_PDATA_SECTION + section .pdata rdata align=4 + %else + section .pdata + %endif + dd %1 wrt ..imagebase + dd %1 %+ _EndProc wrt ..imagebase + dd %1 %+ .unwind_info wrt ..imagebase + + ; Restore code section. + BEGINCODE + %endif + %endif +%endmacro + +;; +; Ends a C callable procedure. +%macro ENDPROC 1 +ENDPROC_RAW NAME(%1) +%endmacro + + +; +; Do OMF and Mach-O/Yasm segment definitions +; +; Both format requires this to get the segment order right, in the Mach-O/Yasm case +; it's only to make sure the .bss section ends up last (it's not declared here). +; +%ifdef ASM_FORMAT_OMF + %ifndef RT_NOINC_SEGMENTS + + ; 16-bit segments first (OMF / OS/2 specific). + %ifdef RT_INCL_16BIT_SEGMENTS + segment DATA16 public CLASS=FAR_DATA align=16 use16 + segment DATA16_INIT public CLASS=FAR_DATA align=16 use16 + group DGROUP16 DATA16 DATA16_INIT + + ;; + ; Begins 16-bit data + %macro BEGINDATA16 0 + segment DATA16 + %endmacro + + ;; + ; Begins 16-bit init data + %macro BEGINDATA16INIT 0 + segment DATA16_INIT + %endmacro + + segment CODE16 public CLASS=FAR_CODE align=16 use16 + segment CODE16_INIT public CLASS=FAR_CODE align=16 use16 + group CGROUP16 CODE16 CODE16_INIT + + ;; + ; Begins 16-bit code + %macro BEGINCODE16 0 + segment CODE16 + %endmacro + + ;; + ; Begins 16-bit init code + %macro BEGINCODE16INIT 0 + segment CODE16_INIT + %endmacro + + %endif + + ; 32-bit segments. + segment TEXT32 public CLASS=CODE align=16 use32 flat + segment DATA32 public CLASS=DATA align=16 use32 flat + segment BSS32 public CLASS=BSS align=16 use32 flat + + ; Make the TEXT32 segment default. + segment TEXT32 + %endif ; RT_NOINC_SEGMENTS +%endif + +%ifdef ASM_FORMAT_MACHO + %ifdef __YASM__ + section .text + section .data + %endif +%endif + + +;; +; Begins code +%ifdef ASM_FORMAT_OMF + %macro BEGINCODE 0 + segment TEXT32 + %endmacro +%else +%macro BEGINCODE 0 + section .text +%endmacro +%endif + +;; +; Begins constant (read-only) data +; +; @remarks This is mapped to the CODE section/segment when there isn't +; any dedicated const section/segment. (There is code that +; assumes this, so don't try change it.) +%ifdef ASM_FORMAT_OMF + %macro BEGINCONST 0 + segment TEXT32 + %endmacro +%else + %macro BEGINCONST 0 + %ifdef ASM_FORMAT_MACHO ;; @todo check the other guys too. + section .rodata + %else + section .text + %endif + %endmacro +%endif + +;; +; Begins initialized data +%ifdef ASM_FORMAT_OMF + %macro BEGINDATA 0 + segment DATA32 + %endmacro +%else +%macro BEGINDATA 0 + section .data +%endmacro +%endif + +;; +; Begins uninitialized data +%ifdef ASM_FORMAT_OMF + %macro BEGINBSS 0 + segment BSS32 + %endmacro +%else +%macro BEGINBSS 0 + section .bss +%endmacro +%endif + + + +;; @def ARCH_BITS +; Defines the bit count of the current context. +%ifndef ARCH_BITS + %ifdef RT_ARCH_AMD64 + %define ARCH_BITS 64 + %else + %define ARCH_BITS 32 + %endif +%endif + +;; @def HC_ARCH_BITS +; Defines the host architechture bit count. +%ifndef HC_ARCH_BITS + %ifndef IN_RC + %define HC_ARCH_BITS ARCH_BITS + %else + %define HC_ARCH_BITS 32 + %endif +%endif + +;; @def R3_ARCH_BITS +; Defines the host ring-3 architechture bit count. +%ifndef R3_ARCH_BITS + %ifdef IN_RING3 + %define R3_ARCH_BITS ARCH_BITS + %else + %define R3_ARCH_BITS HC_ARCH_BITS + %endif +%endif + +;; @def R0_ARCH_BITS +; Defines the host ring-0 architechture bit count. +%ifndef R0_ARCH_BITS + %ifdef IN_RING0 + %define R0_ARCH_BITS ARCH_BITS + %else + %define R0_ARCH_BITS HC_ARCH_BITS + %endif +%endif + +;; @def GC_ARCH_BITS +; Defines the guest architechture bit count. +%ifndef GC_ARCH_BITS + %ifdef IN_RC + %define GC_ARCH_BITS ARCH_BITS + %else + %define GC_ARCH_BITS 32 + %endif +%endif + + + +;; @def RTHCPTR_DEF +; The pesudo-instruction used to declare an initialized pointer variable in the host context. +%if HC_ARCH_BITS == 64 + %define RTHCPTR_DEF dq +%else + %define RTHCPTR_DEF dd +%endif + +;; @def RTHCPTR_RES +; The pesudo-instruction used to declare (=reserve space for) an uninitialized pointer +; variable of the host context. +%if HC_ARCH_BITS == 64 + %define RTHCPTR_RES resq +%else + %define RTHCPTR_RES resd +%endif + +;; @def RTHCPTR_PRE +; The memory operand prefix used for a pointer in the host context. +%if HC_ARCH_BITS == 64 + %define RTHCPTR_PRE qword +%else + %define RTHCPTR_PRE dword +%endif + +;; @def RTHCPTR_CB +; The size in bytes of a pointer in the host context. +%if HC_ARCH_BITS == 64 + %define RTHCPTR_CB 8 +%else + %define RTHCPTR_CB 4 +%endif + + + +;; @def RTR0PTR_DEF +; The pesudo-instruction used to declare an initialized pointer variable in the ring-0 host context. +%if R0_ARCH_BITS == 64 + %define RTR0PTR_DEF dq +%else + %define RTR0PTR_DEF dd +%endif + +;; @def RTR0PTR_RES +; The pesudo-instruction used to declare (=reserve space for) an uninitialized pointer +; variable of the ring-0 host context. +%if R0_ARCH_BITS == 64 + %define RTR0PTR_RES resq +%else + %define RTR0PTR_RES resd +%endif + +;; @def RTR0PTR_PRE +; The memory operand prefix used for a pointer in the ring-0 host context. +%if R0_ARCH_BITS == 64 + %define RTR0PTR_PRE qword +%else + %define RTR0PTR_PRE dword +%endif + +;; @def RTR0PTR_CB +; The size in bytes of a pointer in the ring-0 host context. +%if R0_ARCH_BITS == 64 + %define RTR0PTR_CB 8 +%else + %define RTR0PTR_CB 4 +%endif + + + +;; @def RTR3PTR_DEF +; The pesudo-instruction used to declare an initialized pointer variable in the ring-3 host context. +%if R3_ARCH_BITS == 64 + %define RTR3PTR_DEF dq +%else + %define RTR3PTR_DEF dd +%endif + +;; @def RTR3PTR_RES +; The pesudo-instruction used to declare (=reserve space for) an uninitialized pointer +; variable of the ring-3 host context. +%if R3_ARCH_BITS == 64 + %define RTR3PTR_RES resq +%else + %define RTR3PTR_RES resd +%endif + +;; @def RTR3PTR_PRE +; The memory operand prefix used for a pointer in the ring-3 host context. +%if R3_ARCH_BITS == 64 + %define RTR3PTR_PRE qword +%else + %define RTR3PTR_PRE dword +%endif + +;; @def RTR3PTR_CB +; The size in bytes of a pointer in the ring-3 host context. +%if R3_ARCH_BITS == 64 + %define RTR3PTR_CB 8 +%else + %define RTR3PTR_CB 4 +%endif + + + +;; @def RTGCPTR_DEF +; The pesudo-instruction used to declare an initialized pointer variable in the guest context. +%if GC_ARCH_BITS == 64 + %define RTGCPTR_DEF dq +%else + %define RTGCPTR_DEF dd +%endif + +;; @def RTGCPTR_RES +; The pesudo-instruction used to declare (=reserve space for) an uninitialized pointer +; variable of the guest context. +%if GC_ARCH_BITS == 64 + %define RTGCPTR_RES resq +%else + %define RTGCPTR_RES resd +%endif + +%define RTGCPTR32_RES resd +%define RTGCPTR64_RES resq + +;; @def RTGCPTR_PRE +; The memory operand prefix used for a pointer in the guest context. +%if GC_ARCH_BITS == 64 + %define RTGCPTR_PRE qword +%else + %define RTGCPTR_PRE dword +%endif + +;; @def RTGCPTR_CB +; The size in bytes of a pointer in the guest context. +%if GC_ARCH_BITS == 64 + %define RTGCPTR_CB 8 +%else + %define RTGCPTR_CB 4 +%endif + + +;; @def RTRCPTR_DEF +; The pesudo-instruction used to declare an initialized pointer variable in the raw mode context. +%define RTRCPTR_DEF dd + +;; @def RTRCPTR_RES +; The pesudo-instruction used to declare (=reserve space for) an uninitialized pointer +; variable of the raw mode context. +%define RTRCPTR_RES resd + +;; @def RTRCPTR_PRE +; The memory operand prefix used for a pointer in the raw mode context. +%define RTRCPTR_PRE dword + +;; @def RTRCPTR_CB +; The size in bytes of a pointer in the raw mode context. +%define RTRCPTR_CB 4 + + +;; @def RT_CCPTR_DEF +; The pesudo-instruction used to declare an initialized pointer variable in the current context. + +;; @def RT_CCPTR_RES +; The pesudo-instruction used to declare (=reserve space for) an uninitialized pointer +; variable of the current context. + +;; @def RT_CCPTR_PRE +; The memory operand prefix used for a pointer in the current context. + +;; @def RT_CCPTR_CB +; The size in bytes of a pointer in the current context. + +%ifdef IN_RC + %define RTCCPTR_DEF RTRCPTR_DEF + %define RTCCPTR_RES RTRCPTR_RES + %define RTCCPTR_PRE RTRCPTR_PRE + %define RTCCPTR_CB RTRCPTR_CB +%else + %ifdef IN_RING0 + %define RTCCPTR_DEF RTR0PTR_DEF + %define RTCCPTR_RES RTR0PTR_RES + %define RTCCPTR_PRE RTR0PTR_PRE + %define RTCCPTR_CB RTR0PTR_CB + %else + %define RTCCPTR_DEF RTR3PTR_DEF + %define RTCCPTR_RES RTR3PTR_RES + %define RTCCPTR_PRE RTR3PTR_PRE + %define RTCCPTR_CB RTR3PTR_CB + %endif +%endif + + + +;; @def RTHCPHYS_DEF +; The pesudo-instruction used to declare an initialized host physical address. +%define RTHCPHYS_DEF dq + +;; @def RTHCPTR_RES +; The pesudo-instruction used to declare (=reserve space for) an uninitialized +; host physical address variable +%define RTHCPHYS_RES resq + +;; @def RTHCPTR_PRE +; The memory operand prefix used for a host physical address. +%define RTHCPHYS_PRE qword + +;; @def RTHCPHYS_CB +; The size in bytes of a host physical address. +%define RTHCPHYS_CB 8 + + + +;; @def RTGCPHYS_DEF +; The pesudo-instruction used to declare an initialized guest physical address. +%define RTGCPHYS_DEF dq + +;; @def RTGCPHYS_RES +; The pesudo-instruction used to declare (=reserve space for) an uninitialized +; guest physical address variable +%define RTGCPHYS_RES resq + +;; @def RTGCPTR_PRE +; The memory operand prefix used for a guest physical address. +%define RTGCPHYS_PRE qword + +;; @def RTGCPHYS_CB +; The size in bytes of a guest physical address. +%define RTGCPHYS_CB 8 + + + +;; +; The size of the long double C/C++ type. +; On 32-bit Darwin this is 16 bytes, on L4, Linux, OS/2 and Windows +; it's 12 bytes. +; @todo figure out what 64-bit Windows does (I don't recall right now). +%ifdef RT_ARCH_X86 + %ifdef RT_OS_DARWIN + %define RTLRD_CB 16 + %else + %define RTLRD_CB 12 + %endif +%else + %define RTLRD_CB 16 +%endif + +;; @name Floating point constants along the lines of the iprt/types.h types. +; @note YASM does support special the __Infinity__ and __NaN__ nasm tokens. +; @{ +%define RTFLOAT32U_QNAN_PLUS 0x7fc00000 +%define RTFLOAT32U_QNAN_MINUS 0xffc00000 +%define RTFLOAT32U_INF_PLUS 0x7f800000 +%define RTFLOAT32U_INF_MINUS 0xff800000 + +%define RTFLOAT64U_QNAN_PLUS 0x7ff8000000000000 +%define RTFLOAT64U_QNAN_MINUS 0xfff8000000000000 +%define RTFLOAT64U_INF_PLUS 0x7ff0000000000000 +%define RTFLOAT64U_INF_MINUS 0xfff0000000000000 +; @} + + + +;; @def ASM_CALL64_GCC +; Indicates that we're using the GCC 64-bit calling convention. +; @see @ref sec_vboxrem_amd64_compare (in VBoxREMWrapper.cpp) for an ABI description. + +;; @def ASM_CALL64_MSC +; Indicates that we're using the Microsoft 64-bit calling convention (fastcall on steroids). +; @see @ref sec_vboxrem_amd64_compare (in VBoxREMWrapper.cpp) for an ABI description. + +; Note: On X86 we're using cdecl unconditionally. There is not yet any common +; calling convention on AMD64, that's why we need to support two different ones.) + +%ifdef RT_ARCH_AMD64 + %ifndef ASM_CALL64_GCC + %ifndef ASM_CALL64_MSC + ; define it based on the object format. + %ifdef ASM_FORMAT_PE + %define ASM_CALL64_MSC + %else + %define ASM_CALL64_GCC + %endif + %endif + %else + ; sanity check. + %ifdef ASM_CALL64_MSC + %error "Only one of the ASM_CALL64_* defines should be defined!" + %endif + %endif +%else + ;later; %ifdef ASM_CALL64_GCC + ;later; %error "ASM_CALL64_GCC is defined without RT_ARCH_AMD64!" ASM_CALL64_GCC + ;later; %endif + ;later; %ifdef ASM_CALL64_MSC + ;later; %error "ASM_CALL64_MSC is defined without RT_ARCH_AMD64!" ASM_CALL64_MSC + ;later; %endif +%endif + + +;; @def RT_BEGINPROC +; Starts an IPRT procedure that should be exported unless IN_RT_STATIC is defined. +; +; @param 1 The function name. Will apply NAME macro to it. +%macro RT_BEGINPROC 1 + %ifdef IN_RT_STATIC +BEGINPROC %1 + %else +BEGINPROC_EXPORTED %1 + %endif +%endmacro ; RT_BEGINPROC + + +;; @def RT_NOCRT +; Symbol name wrapper for the No-CRT bits. +; +; In order to coexist in the same process as other CRTs, we need to +; decorate the symbols such that they don't conflict the ones in the +; other CRTs. The result of such conflicts / duplicate symbols can +; confuse the dynamic loader on unix like systems. +; +; @remark Always feed the name to this macro first and then pass the result +; on to the next *NAME* macro. +; +%ifndef RT_WITHOUT_NOCRT_WRAPPERS + %define RT_NOCRT(name) nocrt_ %+ name +%else + %define RT_NOCRT(name) name +%endif + +;; @def RT_NOCRT_BEGINPROC +; Starts a NOCRT procedure, taking care of name wrapping and aliasing. +; +; Weak aliases for regular crt (%1) names to the nocrt_ prefixed ones will be +; added when RT_WITH_NOCRT_ALIASES is defined and the output is ELF. If +; RT_WITH_GENALIAS_NOCRT_ALIASES is undefined, strong aliases will be added for +; for non-ELF targets, otherwise it's assumed the genalias build tool will do +; the weak aliasing for us. +; +%macro RT_NOCRT_BEGINPROC 1 + %ifdef RT_WITH_NOCRT_ALIASES +BEGINPROC_EXPORTED RT_NOCRT(%1) + %ifdef ASM_FORMAT_ELF + ; ELF + %ifdef RT_WITH_NOCRT_UNDERSCORE_ALIASES +global NAME(_ %+ %1):function +weak NAME(_ %+ %1) +SAFE_LABEL NAME(_ %+ %1) + %endif +global NAME(%1):function +weak NAME(%1) +SAFE_LABEL NAME(%1) + + %elifndef RT_WITH_GENALIAS_NOCRT_ALIASES + ; non-ELF when not using genalias. + %ifdef RT_WITH_NOCRT_UNDERSCORE_ALIASES +GLOBALNAME _%1 + %endif +GLOBALNAME %1 + %endif + %else ; !RT_WITH_NOCRT_ALIASES +BEGINPROC_EXPORTED RT_NOCRT(%1) + %endif ; !RT_WITH_NOCRT_ALIASES +%endmacro ; RT_NOCRT_BEGINPROC + + + +;; @def xCB +; The stack unit size / The register unit size. + +;; @def xSP +; The stack pointer register (RSP or ESP). + +;; @def xBP +; The base pointer register (RBP or ESP). + +;; @def xAX +; RAX or EAX depending on context. + +;; @def xBX +; RBX or EBX depending on context. + +;; @def xCX +; RCX or ECX depending on context. + +;; @def xDX +; RDX or EDX depending on context. + +;; @def xDI +; RDI or EDI depending on context. + +;; @def xSI +; RSI or ESI depending on context. + +;; @def xWrtRIP +; 'wrt rip' for AMD64 targets, nothing for x86 ones. + +%ifdef RT_ARCH_AMD64 + %define xCB 8 + %define xSP rsp + %define xBP rbp + %define xAX rax + %define xBX rbx + %define xCX rcx + %define xDX rdx + %define xDI rdi + %define xSI rsi + %define xWrtRIP wrt rip +%else + %define xCB 4 + %define xSP esp + %define xBP ebp + %define xAX eax + %define xBX ebx + %define xCX ecx + %define xDX edx + %define xDI edi + %define xSI esi + %define xWrtRIP +%endif + + +; +; NASM sets __PASS__ to 0 in preprocess-only mode, and to 3 when only generating dependencies. +; YASM has no such setting which is why we must rely on kBuild to tell us what we're doing. +; For simplicity, we'll set the kBuild macro when using NASM. +; +%ifndef KBUILD_GENERATING_MAKEFILE_DEPENDENCIES + %ifdef __NASM__ + %if __PASS__ == 0 || __PASS__ == 3 + %define KBUILD_GENERATING_MAKEFILE_DEPENDENCIES + %endif + %endif +%endif + + +; +; Some simple compile time assertions. +; +; Note! Requires new kBuild to work with YASM (see above). +; + +;; +; Structure size assertion macro. +%define AssertCompileSize(a_Type, a_Size) AssertCompileSizeML a_Type, a_Size +%macro AssertCompileSizeML 2 + %ifndef KBUILD_GENERATING_MAKEFILE_DEPENDENCIES + %assign AssertVar_cbActual %1 %+ _size + %assign AssertVar_cbExpected %2 + %if AssertVar_cbActual != AssertVar_cbExpected + %error %1 is AssertVar_cbActual bytes instead of AssertVar_cbExpected + %endif + %endif +%endmacro + +;; +; Structure size alignment assertion macro. + +%define AssertCompileSizeAlignment(a_Type, a_Align) AssertCompileSizeAlignmentML a_Type, a_Align +%macro AssertCompileSizeAlignmentML 2 + %ifndef KBUILD_GENERATING_MAKEFILE_DEPENDENCIES + %assign AssertVar_cbActual %1 %+ _size + %assign AssertVar_cbAlignment %2 + %if (AssertVar_cbActual & (AssertVar_cbAlignment - 1)) != 0 + %error %1 is AssertVar_cbActual bytes, expected size with AssertVar_cbAlignment bytes alignment. + %endif + %endif +%endmacro + +;; +; Structure member offset assertion macro. +%define AssertCompileMemberOffset(a_Type, a_Member, a_off) AssertCompileMemberOffsetML a_Type, a_Member, a_off +%macro AssertCompileMemberOffsetML 3 + %ifndef KBUILD_GENERATING_MAKEFILE_DEPENDENCIES + %assign AssertVar_offActual %1 %+ . %+ %2 + %assign AssertVar_offExpected %3 + %if AssertVar_offActual != AssertVar_offExpected + %error %1 %+ . %+ %2 is at AssertVar_offActual instead of AssertVar_offExpected + %endif + %endif +%endmacro + +;; +; Structure member alignment assertion macro. +%define AssertCompileMemberAlignment(a_Type, a_Member, a_cbAlign) AssertCompileMemberAlignmentML a_Type, a_Member, a_cbAlign +%macro AssertCompileMemberAlignmentML 3 + %ifndef KBUILD_GENERATING_MAKEFILE_DEPENDENCIES + %assign AssertVar_offActual %1 %+ . %+ %2 + %assign AssertVar_cbAlign %3 + %if AssertVar_offActual & (AssertVar_cbAlign - 1) + %error %1 %+ . %+ %2 is at AssertVar_offActual, expected AssertVar_cbAlign alignment + %endif + %endif +%endmacro + +;; +; Generic compile time expression assertion. +%define AssertCompile(a_Expr) AssertCompileML { a_Expr } +%macro AssertCompileML 1 + %ifndef KBUILD_GENERATING_MAKEFILE_DEPENDENCIES + %if (%1) != 1 + %assign AssertVar_uResult %1 + %error %1 => AssertVar_uResult + %endif + %endif +%endmacro + +%endif + diff --git a/include/iprt/asn1-generator-asn1-decoder.h b/include/iprt/asn1-generator-asn1-decoder.h new file mode 100644 index 00000000..bf0d762c --- /dev/null +++ b/include/iprt/asn1-generator-asn1-decoder.h @@ -0,0 +1,40 @@ +/** @file + * IPRT - ASN.1 Code Generator, the ASN1 Decoder Passes. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#include <iprt/string.h> + +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_DECODE +#include <iprt/asn1-generator-pass.h> + diff --git a/include/iprt/asn1-generator-core.h b/include/iprt/asn1-generator-core.h new file mode 100644 index 00000000..50dbb700 --- /dev/null +++ b/include/iprt/asn1-generator-core.h @@ -0,0 +1,50 @@ +/** @file + * IPRT - ASN.1 Code Generator, the ASN.1 Core Code (VTable, Compare, ..). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#include <iprt/assert.h> +#include <iprt/err.h> +#include <iprt/string.h> + +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_XTAG +#include <iprt/asn1-generator-pass.h> +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_VTABLE +#include <iprt/asn1-generator-pass.h> +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_DELETE +#include <iprt/asn1-generator-pass.h> +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_ENUM +#include <iprt/asn1-generator-pass.h> +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_COMPARE +#include <iprt/asn1-generator-pass.h> + diff --git a/include/iprt/asn1-generator-init.h b/include/iprt/asn1-generator-init.h new file mode 100644 index 00000000..74665a8a --- /dev/null +++ b/include/iprt/asn1-generator-init.h @@ -0,0 +1,48 @@ +/** @file + * IPRT - ASN.1 Code Generator, the ASN1 Init, Clone and Modifier Passes. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#include <iprt/string.h> + +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_INIT +#include <iprt/asn1-generator-pass.h> +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_CLONE +#include <iprt/asn1-generator-pass.h> +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_SETTERS_1 +#include <iprt/asn1-generator-pass.h> +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_SETTERS_2 +#include <iprt/asn1-generator-pass.h> +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_ARRAY +#include <iprt/asn1-generator-pass.h> + diff --git a/include/iprt/asn1-generator-internal-header.h b/include/iprt/asn1-generator-internal-header.h new file mode 100644 index 00000000..9ec72f52 --- /dev/null +++ b/include/iprt/asn1-generator-internal-header.h @@ -0,0 +1,39 @@ +/** @file + * IPRT - ASN.1 Code Generator, the Internal Header File. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_INTERNAL_HEADER +#include <iprt/asn1-generator-pass.h> + diff --git a/include/iprt/asn1-generator-pass.h b/include/iprt/asn1-generator-pass.h new file mode 100644 index 00000000..86cfd3ef --- /dev/null +++ b/include/iprt/asn1-generator-pass.h @@ -0,0 +1,1757 @@ +/** @file + * IPRT - ASN.1 Code Generator, One Pass. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef ___iprt_asn1_generator_pass_h /* (special, only part of the file) */ +#define ___iprt_asn1_generator_pass_h + +#include <iprt/formats/asn1.h> +#include <iprt/err.h> + + +/** @def RTASN1TMPL_MEMBER_OPT_ANY + * Used for optional entries without any specific type at the end of a + * structure. + * + * For example PolicyQualifierInfo's qualifier member which is defined as: + * ANY DEFINED BY policyQualifierId + * + * Defaults to RTASN1TMPL_MEMBER_EX. + */ + +/** @def RTASN1TMPL_MEMBER_OPT_ITAG_EX + * Optional member with implict tag, extended version. + * + * This is what all the other RTASN1TMPL_MEMBER_OPT_ITAG* macros defere to. + */ +/** @def RTASN1TMPL_MEMBER_OPT_ITAG_CP + * Optional member of a typical primitive type with an implicit context tag. + * + * Examples of this can be found in AuthorityKeyIdentifier where the first and + * last member are primitive types (normally anyways).: + * keyIdentifier [1] OCTET STRING OPTIONAL, + * authorityCertSerialNumber [3] INTEGER OPTIONAL + */ +/** @def RTASN1TMPL_MEMBER_OPT_ITAG_UC + * Optional member of a constructed type from the universal tag class. + */ +/** @def RTASN1TMPL_MEMBER_OPT_ITAG_UP + * Optional member of a primitive type from the universal tag class. + */ + + +/** @name Expansion Passes (RTASN1TMPL_PASS values) + * @{ */ +#define RTASN1TMPL_PASS_INTERNAL_HEADER 1 + +#define RTASN1TMPL_PASS_XTAG 2 +#define RTASN1TMPL_PASS_VTABLE 3 +#define RTASN1TMPL_PASS_ENUM 4 +#define RTASN1TMPL_PASS_DELETE 5 +#define RTASN1TMPL_PASS_COMPARE 6 + +#define RTASN1TMPL_PASS_CHECK_SANITY 8 + +#define RTASN1TMPL_PASS_INIT 16 +#define RTASN1TMPL_PASS_CLONE 17 +#define RTASN1TMPL_PASS_SETTERS_1 18 +#define RTASN1TMPL_PASS_SETTERS_2 19 +#define RTASN1TMPL_PASS_ARRAY 20 + +#define RTASN1TMPL_PASS_DECODE 24 +/** @} */ + +/** @name ITAG clues + * @{ */ +#define RTASN1TMPL_ITAG_F_CC 1 /**< context, constructed. */ +#define RTASN1TMPL_ITAG_F_CP 2 /**< context, probably primary. (w/ numeric value) */ +#define RTASN1TMPL_ITAG_F_UP 3 /**< universal, probably primary. (w/ ASN1_TAG_XXX value) */ +#define RTASN1TMPL_ITAG_F_UC 4 /**< universal, constructed. (w/ ASN1_TAG_XXX value) */ +/** @} */ +/** Expands the ITAG clues into tag flag and tag class. */ +#define RTASN1TMPL_ITAG_F_EXPAND(a_fClue) \ + ( a_fClue == RTASN1TMPL_ITAG_F_CC ? (ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_CONSTRUCTED ) \ + : a_fClue == RTASN1TMPL_ITAG_F_CP ? (ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_PRIMITIVE) \ + : a_fClue == RTASN1TMPL_ITAG_F_UP ? (ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_PRIMITIVE) \ + : a_fClue == RTASN1TMPL_ITAG_F_UC ? (ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_CONSTRUCTED) \ + : 0 ) + +#define RTASN1TMPL_SEMICOLON_DUMMY() typedef unsigned RTASN1TMPLSEMICOLONDUMMY + +#endif /* !___iprt_asn1_generator_pass_h */ + + +#if RTASN1TMPL_PASS == RTASN1TMPL_PASS_INTERNAL_HEADER +/* + * + * Internal header file. + * + */ +# define RTASN1TMPL_BEGIN_COMMON() extern DECL_HIDDEN_DATA(RTASN1COREVTABLE const) RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable) + +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + extern "C" DECL_HIDDEN_DATA(RTASN1COREVTABLE const) RT_CONCAT5(g_,RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Vtable) + +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() + + +# define RTASN1TMPL_BEGIN_PCHOICE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + extern "C" DECL_HIDDEN_DATA(RTASN1COREVTABLE const) RT_CONCAT5(g_,RTASN1TMPL_INT_NAME,_PCHOICE_XTAG_,a_Name,_Vtable) + +# define RTASN1TMPL_END_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() + + +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_BEGIN_COMMON() + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_XTAG +/* + * + * Generate a vtable and associated methods for explicitly tagged items (XTAG). + * + * These turned out to be a little problematic during encoding since there are + * two tags, the first encapsulating the second, thus the enumeration has to be + * nested or we cannot calculate the size of the first tag. + * + * + */ +# define RTASN1TMPL_BEGIN_COMMON() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + /* This is the method we need to make it work. */ \ + static DECLCALLBACK(int) RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Enum)(PRTASN1CORE pThisCore, \ + PFNRTASN1ENUMCALLBACK pfnCallback, \ + uint32_t uDepth, void *pvUser) \ + { \ + RTASN1TMPL_TYPE *pThis = RT_FROM_MEMBER(pThisCore, RTASN1TMPL_TYPE, a_TnNm.a_CtxTagN); \ + if (RTASN1CORE_IS_PRESENT(&pThis->a_TnNm.a_CtxTagN.Asn1Core)) \ + return pfnCallback(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_TnNm.a_Name), #a_TnNm "." #a_Name, uDepth + 1, pvUser); \ + return VINF_SUCCESS; \ + } \ + /* The reminder of the methods shouldn't normally be needed, just stub them. */ \ + static DECLCALLBACK(void) RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Delete)(PRTASN1CORE pThisCore) \ + { AssertFailed(); RT_NOREF_PV(pThisCore); } \ + static DECLCALLBACK(int) RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Clone)(PRTASN1CORE pThisCore, PCRTASN1CORE pSrcCore, \ + PCRTASN1ALLOCATORVTABLE pAllocator) \ + { AssertFailed(); RT_NOREF_PV(pThisCore); RT_NOREF_PV(pSrcCore); RT_NOREF_PV(pAllocator); return VERR_INTERNAL_ERROR_2; } \ + static DECLCALLBACK(int) RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Compare)(PCRTASN1CORE pLeftCore, \ + PCRTASN1CORE pRightCore) \ + { AssertFailed(); RT_NOREF_PV(pLeftCore); RT_NOREF_PV(pRightCore); return VERR_INTERNAL_ERROR_2; } \ + static DECLCALLBACK(int) RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_CheckSanity)(PCRTASN1CORE pThisCore, uint32_t fFlags, \ + PRTERRINFO pErrInfo, const char *pszErrorTag) \ + { AssertFailed(); RT_NOREF_PV(pThisCore); RT_NOREF_PV(fFlags); RT_NOREF_PV(pErrInfo); RT_NOREF_PV(pszErrorTag); \ + return VERR_INTERNAL_ERROR_2; } \ + DECL_HIDDEN_CONST(RTASN1COREVTABLE const) RT_CONCAT5(g_,RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Vtable) = \ + { \ + /* When the Asn1Core is at the start of the structure, we can reuse the _Delete and _Enum APIs here. */ \ + /* .pszName = */ RT_XSTR(RTASN1TMPL_INT_NAME) "_XTAG_" RT_XSTR(a_Name), \ + /* .cb = */ RT_SIZEOFMEMB(RTASN1TMPL_TYPE, a_TnNm), \ + /* .uDefaultTag = */ a_uTag, \ + /* .fDefaultClass = */ ASN1_TAGCLASS_CONTEXT, \ + /* .uReserved = */ 0, \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Delete), \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Enum), \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Clone), \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Compare), \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_CheckSanity), \ + /*.pfnEncodePrep */ NULL, \ + /*.pfnEncodeWrite */ NULL \ + } + + +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_BEGIN_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + /* This is the method we need to make it work. */ \ + static DECLCALLBACK(int) RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_Enum)(PRTASN1CORE pThisCore, \ + PFNRTASN1ENUMCALLBACK pfnCallback, \ + uint32_t uDepth, void *pvUser) \ + { \ + if (RTASN1CORE_IS_PRESENT(pThisCore)) \ + { \ + /** @todo optimize this one day, possibly change the PCHOICE+XTAG representation. */ \ + RTASN1TMPL_TYPE Tmp; \ + *(PRTASN1CORE *)&Tmp.a_PtrTnNm = pThisCore; \ + Assert(&Tmp.a_PtrTnNm->a_CtxTagN.Asn1Core == pThisCore); \ + return pfnCallback(RT_CONCAT(a_Api,_GetAsn1Core)(&Tmp.a_PtrTnNm->a_Name), "T" #a_uTag "." #a_Name, uDepth + 1, pvUser); \ + } \ + return VINF_SUCCESS; \ + } \ + /* The reminder of the methods shouldn't normally be needed, just stub them. */ \ + static DECLCALLBACK(void) RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_Delete)(PRTASN1CORE pThisCore) \ + { AssertFailed(); RT_NOREF_PV(pThisCore); } \ + static DECLCALLBACK(int) RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_Clone)(PRTASN1CORE pThisCore, PCRTASN1CORE pSrcCore, \ + PCRTASN1ALLOCATORVTABLE pAllocator) \ + { AssertFailed(); RT_NOREF_PV(pThisCore); RT_NOREF_PV(pSrcCore); RT_NOREF_PV(pAllocator); return VERR_INTERNAL_ERROR_3; } \ + static DECLCALLBACK(int) RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_Compare)(PCRTASN1CORE pLeftCore, \ + PCRTASN1CORE pRightCore) \ + { AssertFailed(); RT_NOREF_PV(pLeftCore); RT_NOREF_PV(pRightCore); return VERR_INTERNAL_ERROR_3; } \ + static DECLCALLBACK(int) RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_CheckSanity)(PCRTASN1CORE pThisCore, uint32_t fFlags, \ + PRTERRINFO pErrInfo, const char *pszErrorTag) \ + { AssertFailed(); RT_NOREF_PV(pThisCore); RT_NOREF_PV(fFlags); RT_NOREF_PV(pErrInfo); RT_NOREF_PV(pszErrorTag); \ + return VERR_INTERNAL_ERROR_3; } \ + DECL_HIDDEN_CONST(RTASN1COREVTABLE const) RT_CONCAT5(g_,RTASN1TMPL_INT_NAME,_PCHOICE_XTAG_,a_Name,_Vtable) = \ + { \ + /* When the Asn1Core is at the start of the structure, we can reuse the _Delete and _Enum APIs here. */ \ + /* .pszName = */ RT_XSTR(RTASN1TMPL_INT_NAME) "_PCHOICE_XTAG_" RT_XSTR(a_Name), \ + /* .cb = */ sizeof(*((RTASN1TMPL_TYPE *)(void *)0)->a_PtrTnNm), \ + /* .uDefaultTag = */ a_uTag, \ + /* .fDefaultClass = */ ASN1_TAGCLASS_CONTEXT, \ + /* .uReserved = */ 0, \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_Delete), \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_Enum), \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_Clone), \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_Compare), \ + RT_CONCAT4(RTASN1TMPL_INT_NAME,_PC_XTAG_,a_Name,_CheckSanity), \ + /*.pfnEncodePrep */ NULL, \ + /*.pfnEncodeWrite */ NULL \ + } + + + +# define RTASN1TMPL_END_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SEMICOLON_DUMMY() + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_VTABLE +/* + * + * Internal header file. + * + */ +# ifndef RTASN1TMPL_VTABLE_FN_ENCODE_PREP +# define RTASN1TMPL_VTABLE_FN_ENCODE_PREP NULL +# endif +# ifndef RTASN1TMPL_VTABLE_FN_ENCODE_WRITE +# define RTASN1TMPL_VTABLE_FN_ENCODE_WRITE NULL +# endif +# define RTASN1TMPL_BEGIN_COMMON(a_uDefaultTag, a_fDefaultClass) \ + DECL_HIDDEN_CONST(RTASN1COREVTABLE const) RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable) = \ + { \ + /* When the Asn1Core is at the start of the structure, we can reuse the _Delete and _Enum APIs here. */ \ + /* .pszName = */ RT_XSTR(RTASN1TMPL_EXT_NAME), \ + /* .cb = */ sizeof(RTASN1TMPL_TYPE), \ + /* .uDefaultTag = */ a_uDefaultTag, \ + /* .fDefaultClass = */ a_fDefaultClass, \ + /* .uReserved = */ 0, \ + (PFNRTASN1COREVTDTOR)RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete), \ + (PFNRTASN1COREVTENUM)RT_CONCAT(RTASN1TMPL_EXT_NAME,_Enum), \ + (PFNRTASN1COREVTCLONE)RT_CONCAT(RTASN1TMPL_EXT_NAME,_Clone), \ + (PFNRTASN1COREVTCOMPARE)RT_CONCAT(RTASN1TMPL_EXT_NAME,_Compare), \ + (PFNRTASN1COREVTCHECKSANITY)RT_CONCAT(RTASN1TMPL_EXT_NAME,_CheckSanity), \ + RTASN1TMPL_VTABLE_FN_ENCODE_PREP, \ + RTASN1TMPL_VTABLE_FN_ENCODE_WRITE \ + } + +# define RTASN1TMPL_BEGIN_SEQCORE() \ + AssertCompileMemberOffset(RTASN1TMPL_TYPE, SeqCore, 0); \ + RTASN1TMPL_BEGIN_COMMON(ASN1_TAG_SEQUENCE, ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_CONSTRUCTED) +# define RTASN1TMPL_BEGIN_SETCORE() \ + AssertCompileMemberOffset(RTASN1TMPL_TYPE, SetCore, 0); \ + RTASN1TMPL_BEGIN_COMMON(ASN1_TAG_SET, ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_CONSTRUCTED) +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_BEGIN_PCHOICE() \ + AssertCompileMemberOffset(RTASN1TMPL_TYPE, Dummy, 0); \ + RTASN1TMPL_BEGIN_COMMON(UINT8_MAX, UINT8_MAX) +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) \ + AssertCompileMemberOffset(RTASN1TMPL_TYPE, SeqCore, 0); \ + RTASN1TMPL_BEGIN_COMMON(ASN1_TAG_SEQUENCE, ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_CONSTRUCTED) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) \ + AssertCompileMemberOffset(RTASN1TMPL_TYPE, SetCore, 0); \ + RTASN1TMPL_BEGIN_COMMON(ASN1_TAG_SET, ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_CONSTRUCTED) + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_INIT +/* + * + * Initialization to standard / default values. + * + */ +# define RTASN1TMPL_BEGIN_COMMON() \ +RTASN1TMPL_DECL(int) RT_CONCAT(RTASN1TMPL_EXT_NAME,_Init)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, PCRTASN1ALLOCATORVTABLE pAllocator) \ +{ \ + RT_NOREF_PV(pAllocator); \ + RT_ZERO(*pThis) +# define RTASN1TMPL_END_COMMON() \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_BEGIN_SEQCORE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + int rc = RTAsn1SequenceCore_Init(&pThis->SeqCore, &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable)) +# define RTASN1TMPL_BEGIN_SETCORE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + int rc = RTAsn1SetCore_Init(&pThis->SetCore, &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable)) +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) \ + if (RT_SUCCESS(rc)) \ + rc = RT_CONCAT(a_Api,_Init)(&pThis->a_Name, pAllocator) + +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator); \ + pThis->a_enmMembNm = RT_CONCAT(a_enmType,_NOT_PRESENT) +# define RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, a_IfStmt) \ + do { } while (0) +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) do { } while (0) + +# define RTASN1TMPL_MEMBER_DEF_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, a_fClue, a_DefVal, a_Constraints) \ + if (RT_SUCCESS(rc)) \ + { \ + rc = RT_CONCAT(a_Api,_InitDefault)(&pThis->a_Name, a_DefVal, pAllocator); \ + if (RT_SUCCESS(rc)) \ + rc = RTAsn1Core_SetTagAndFlags(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_Name), \ + a_uTag, RTASN1TMPL_ITAG_F_EXPAND(a_fClue)); \ + } +# define RTASN1TMPL_MEMBER_OPT_EX(a_Name, a_Type, a_Api, a_Constraints) do { } while (0) /* All optional members are left as not-present. */ +# define RTASN1TMPL_END_SEQCORE() \ + if (RT_FAILURE(rc)) \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_END_SEQCORE() + +/* No choice, just an empty, non-present structure. */ +# define RTASN1TMPL_BEGIN_PCHOICE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator); \ + int rc = VINF_SUCCESS +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + do { } while (0) +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + do { } while (0) +# define RTASN1TMPL_END_PCHOICE() RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, a_OfApi, a_OfMember) \ + RTASN1TMPL_BEGIN_COMMON(); \ + RTAsn1MemInitArrayAllocation(&pThis->Allocation, pAllocator, sizeof(a_ItemType)); \ + int rc = RT_CONCAT(a_OfApi,_Init)(&pThis->a_OfMember, &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable)); \ + if (RT_FAILURE(rc)) \ + RT_ZERO(*pThis); \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, RTAsn1SeqOfCore, SeqCore) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, RTAsn1SetOfCore, SetCore) + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_DECODE +/* + * + * Decode ASN.1. + * + */ +# define RTASN1TMPL_BEGIN_COMMON() \ +RTASN1TMPL_DECL(int) RT_CONCAT(RTASN1TMPL_EXT_NAME,_DecodeAsn1)(PRTASN1CURSOR pCursor, uint32_t fFlags, \ + RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, const char *pszErrorTag) \ +{ \ + RT_ZERO(*pThis); + +# define RTASN1TMPL_END_COMMON() \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + + +# define RTASN1TMPL_BEGIN_SEQCORE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + RTASN1CURSOR ThisCursor; \ + int rc = RTAsn1CursorGetSequenceCursor(pCursor, fFlags, &pThis->SeqCore, &ThisCursor, pszErrorTag); \ + if (RT_FAILURE(rc)) \ + return rc; \ + pCursor = &ThisCursor; \ + pThis->SeqCore.Asn1Core.pOps = &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable) +# define RTASN1TMPL_BEGIN_SETCORE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + RTASN1CURSOR ThisCursor; \ + int rc = RTAsn1CursorGetSetCursor(pCursor, fFlags, &pThis->SetCore, &ThisCursor, pszErrorTag); \ + if (RT_FAILURE(rc)) \ + return rc; \ + pCursor = &ThisCursor; \ + pThis->SetCore.Asn1Core.pOps = &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable) + +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) \ + if (RT_SUCCESS(rc)) \ + rc = RT_CONCAT(a_Api,_DecodeAsn1)(pCursor, 0, &pThis->a_Name, #a_Name) + +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + if (RT_SUCCESS(rc)) \ + { \ + int rc2; /* not initialized! */ \ + RTAsn1CursorInitAllocation(pCursor, &pThis->a_Allocation); \ + pThis->a_enmMembNm = RT_CONCAT(a_enmType, _INVALID); \ + if (false) do { /*nothing*/ } while (0) +# define RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, a_IfStmt) \ + else a_IfStmt \ + do { \ + rc2 = RTAsn1MemAllocZ(&pThis->a_Allocation, (void **)&pThis->a_UnionNm.a_PtrName, \ + sizeof(*pThis->a_UnionNm.a_PtrName)); \ + if (RT_SUCCESS(rc2)) \ + { \ + pThis->a_enmMembNm = a_enmValue; \ + rc2 = RT_CONCAT(a_Api,_DecodeAsn1)(pCursor, 0, pThis->a_UnionNm.a_PtrName, #a_UnionNm "." #a_PtrName); \ + } \ + } while (0) +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + rc = rc2; /* Should trigger warning if a _DEFAULT is missing. */ \ + } + +# define RTASN1TMPL_MEMBER_OPT_EX(a_Name, a_Type, a_Api, a_Constraints) \ + Error_Missing_Specific_Macro_In_Decode_Pass() + +# define RTASN1TMPL_MEMBER_DEF_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, a_fClue, a_DefVal, a_Constraints) \ + if (RT_SUCCESS(rc)) \ + { \ + if (RTAsn1CursorIsNextEx(pCursor, a_uTag, RTASN1TMPL_ITAG_F_EXPAND(a_fClue))) \ + rc = RT_CONCAT(a_Api,_DecodeAsn1)(pCursor, 0, &pThis->a_Name, #a_Name); \ + else \ + rc = RT_CONCAT(a_Api,_InitDefault)(&pThis->a_Name, a_DefVal, pCursor->pPrimary->pAllocator); \ + if (RT_SUCCESS(rc)) \ + rc = RTAsn1Core_SetTagAndFlags(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_Name), \ + a_uTag, RTASN1TMPL_ITAG_F_EXPAND(a_fClue)); \ + } do {} while (0) + +# define RTASN1TMPL_MEMBER_OPT_UTF8_STRING_EX(a_Name, a_Constraints) \ + if (RT_SUCCESS(rc) && RTAsn1CursorIsNextEx(pCursor, ASN1_TAG_UTF8_STRING, ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_PRIMITIVE)) \ + rc = RTAsn1CursorGetUtf8String(pCursor, 0, &pThis->a_Name, #a_Name) + +# define RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, a_fClue, a_Constraints) \ + if (RT_SUCCESS(rc) && RTAsn1CursorIsNextEx(pCursor, a_uTag, RTASN1TMPL_ITAG_F_EXPAND(a_fClue)) /** @todo || CER */) \ + rc = RT_CONCAT(a_Api,_DecodeAsn1)(pCursor, RTASN1CURSOR_GET_F_IMPLICIT, &pThis->a_Name, #a_Name) + +# define RTASN1TMPL_MEMBER_OPT_ITAG_BITSTRING(a_Name, a_cMaxBits, a_uTag) \ + if (RT_SUCCESS(rc) && RTAsn1CursorIsNextEx(pCursor, a_uTag, ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_CONSTRUCTED)) \ + rc = RTAsn1CursorGetBitStringEx(pCursor, RTASN1CURSOR_GET_F_IMPLICIT, a_cMaxBits, &pThis->a_Name, #a_Name) + +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + if (RT_SUCCESS(rc) && RTAsn1CursorIsNextEx(pCursor, a_uTag, ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_CONSTRUCTED)) \ + { \ + RTASN1CURSOR CtxCursor; \ + rc = RT_CONCAT3(RTAsn1CursorGetContextTag,a_uTag,Cursor)(pCursor, 0, \ + &RT_CONCAT5(g_,RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Vtable), \ + &pThis->a_TnNm.a_CtxTagN, &CtxCursor, #a_TnNm); \ + if (RT_SUCCESS(rc)) \ + { \ + rc = RT_CONCAT(a_Api,_DecodeAsn1)(&CtxCursor, 0, &pThis->a_TnNm.a_Name, #a_Name); \ + if (RT_SUCCESS(rc)) \ + rc = RTAsn1CursorCheckEnd(&CtxCursor); \ + } \ + } do { } while (0) + +# define RTASN1TMPL_MEMBER_OPT_ANY(a_Name, a_Type, a_Api) \ + if (RT_SUCCESS(rc) && pCursor->cbLeft > 0) \ + RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, RT_NOTHING) + +# define RTASN1TMPL_END_SEQCORE() \ + if (RT_SUCCESS(rc)) \ + rc = RTAsn1CursorCheckSeqEnd(&ThisCursor, &pThis->SeqCore); \ + if (RT_SUCCESS(rc)) \ + return VINF_SUCCESS; \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_END_SETCORE() \ + if (RT_SUCCESS(rc)) \ + rc = RTAsn1CursorCheckSetEnd(&ThisCursor, &pThis->SetCore); \ + if (RT_SUCCESS(rc)) \ + return VINF_SUCCESS; \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); \ + RTASN1TMPL_END_COMMON() + +# define RTASN1TMPL_BEGIN_PCHOICE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + RT_NOREF_PV(fFlags); \ + RTAsn1Dummy_InitEx(&pThis->Dummy); \ + pThis->Dummy.Asn1Core.pOps = &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable); \ + RTAsn1CursorInitAllocation(pCursor, &pThis->Allocation); \ + RTASN1CORE Asn1Peek; \ + int rc = RTAsn1CursorPeek(pCursor, &Asn1Peek); \ + if (RT_SUCCESS(rc)) \ + { \ + if (false) do {} while (0) +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + else if ( Asn1Peek.uTag == (a_uTag) \ + && (Asn1Peek.fClass == RTASN1TMPL_ITAG_F_EXPAND(a_fClue) /** @todo || CER */ ) ) \ + do { \ + pThis->enmChoice = a_enmChoice; \ + rc = RTAsn1MemAllocZ(&pThis->Allocation, (void **)&pThis->a_PtrName, sizeof(*pThis->a_PtrName)); \ + if (RT_SUCCESS(rc)) \ + rc = RT_CONCAT(a_Api,_DecodeAsn1)(pCursor, RTASN1CURSOR_GET_F_IMPLICIT, pThis->a_PtrName, #a_PtrName); \ + } while (0) +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + else if (Asn1Peek.uTag == (a_uTag) && Asn1Peek.fClass == (ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_CONSTRUCTED)) \ + do { \ + pThis->enmChoice = a_enmChoice; \ + rc = RTAsn1MemAllocZ(&pThis->Allocation, (void **)&pThis->a_PtrTnNm, sizeof(*pThis->a_PtrTnNm)); \ + if (RT_SUCCESS(rc)) \ + { \ + RTASN1CURSOR CtxCursor; \ + rc = RT_CONCAT3(RTAsn1CursorGetContextTag,a_uTag,Cursor)(pCursor, 0, \ + &RT_CONCAT5(g_,RTASN1TMPL_INT_NAME,_PCHOICE_XTAG_,a_Name,_Vtable), \ + &pThis->a_PtrTnNm->a_CtxTagN, &CtxCursor, "T" #a_uTag); \ + if (RT_SUCCESS(rc)) \ + rc = RT_CONCAT(a_Api,_DecodeAsn1)(&CtxCursor, RTASN1CURSOR_GET_F_IMPLICIT, \ + &pThis->a_PtrTnNm->a_Name, #a_Name); \ + if (RT_SUCCESS(rc)) \ + rc = RTAsn1CursorCheckEnd(&CtxCursor); \ + } \ + } while (0) +#define RTASN1TMPL_END_PCHOICE() \ + else \ + rc = RTAsn1CursorSetInfo(pCursor, VERR_GENERAL_FAILURE, "%s: Unknown choice: tag=%#x fClass=%#x", \ + pszErrorTag, Asn1Peek.uTag, Asn1Peek.fClass); \ + if (RT_SUCCESS(rc)) \ + return VINF_SUCCESS; \ + } \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); \ + RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, a_OfApi, a_OfMember, a_fnGetCursor) \ + RTASN1TMPL_BEGIN_COMMON(); \ + RTASN1CURSOR ThisCursor; \ + int rc = a_fnGetCursor(pCursor, fFlags, &pThis->a_OfMember, &ThisCursor, pszErrorTag); \ + if (RT_SUCCESS(rc)) \ + { \ + pCursor = &ThisCursor; \ + pThis->a_OfMember.Asn1Core.pOps = &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable); \ + RTAsn1CursorInitArrayAllocation(pCursor, &pThis->Allocation, sizeof(a_ItemType)); \ + \ + uint32_t i = 0; \ + while ( pCursor->cbLeft > 0 \ + && RT_SUCCESS(rc)) \ + { \ + rc = RTAsn1MemResizeArray(&pThis->Allocation, (void ***)&pThis->papItems, i, i + 1); \ + if (RT_SUCCESS(rc)) \ + { \ + rc = RT_CONCAT(a_ItemApi,_DecodeAsn1)(pCursor, 0, pThis->papItems[i], "papItems[#]"); \ + if (RT_SUCCESS(rc)) \ + { \ + i++; \ + pThis->cItems = i; \ + continue; \ + } \ + } \ + break; \ + } \ + if (RT_SUCCESS(rc)) \ + { \ + rc = RTAsn1CursorCheckEnd(pCursor); \ + if (RT_SUCCESS(rc)) \ + return VINF_SUCCESS; \ + } \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); \ + } \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) \ + RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, RTAsn1SeqOfCore, SeqCore, RTAsn1CursorGetSequenceCursor) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) \ + RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, RTAsn1SetOfCore, SetCore, RTAsn1CursorGetSetCursor) + + +# define RTASN1TMPL_EXEC_DECODE(a_Expr) if (RT_SUCCESS(rc)) { a_Expr; } + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_ENUM +/* + * + * Enumeration. + * + */ +# define RTASN1TMPL_BEGIN_COMMON() \ +RTASN1TMPL_DECL(int) RT_CONCAT(RTASN1TMPL_EXT_NAME,_Enum)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, \ + PFNRTASN1ENUMCALLBACK pfnCallback, \ + uint32_t uDepth, void *pvUser) \ +{ \ + if (!RT_CONCAT(RTASN1TMPL_EXT_NAME,_IsPresent)(pThis)) \ + return VINF_SUCCESS; \ + uDepth++; \ + int rc = VINF_SUCCESS + +# define RTASN1TMPL_END_COMMON() \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) \ + if (rc == VINF_SUCCESS) \ + rc = pfnCallback(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_Name), #a_Name, uDepth, pvUser) +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + if (rc == VINF_SUCCESS) \ + switch (pThis->a_enmMembNm) \ + { \ + default: rc = VERR_INTERNAL_ERROR_3; break +# define RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, a_IfStmt) \ + case a_enmValue: \ + rc = pfnCallback(RT_CONCAT(a_Api,_GetAsn1Core)(pThis->a_UnionNm.a_PtrName), #a_UnionNm "." #a_PtrName, \ + uDepth, pvUser); \ + break +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + case RT_CONCAT(a_enmType,_NOT_PRESENT): break; \ + } +# define RTASN1TMPL_MEMBER_OPT_EX(a_Name, a_Type, a_Api, a_Constraints) \ + if (rc == VINF_SUCCESS && RT_CONCAT(a_Api,_IsPresent)(&pThis->a_Name)) \ + rc = pfnCallback(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_Name), #a_Name, uDepth, pvUser) +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + if (rc == VINF_SUCCESS && RTASN1CORE_IS_PRESENT(&pThis->a_TnNm.a_CtxTagN.Asn1Core)) \ + { \ + rc = pfnCallback(&pThis->a_TnNm.a_CtxTagN.Asn1Core, #a_Name, uDepth, pvUser); \ + } do {} while (0) +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_BEGIN_PCHOICE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + switch (pThis->enmChoice) \ + { \ + default: rc = VERR_INTERNAL_ERROR_3; break +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + case a_enmChoice: rc = pfnCallback(RT_CONCAT(a_Api,_GetAsn1Core)(pThis->a_PtrName), #a_PtrName, uDepth, pvUser); break +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + case a_enmChoice: rc = pfnCallback(&pThis->a_PtrTnNm->a_CtxTagN.Asn1Core, "T" #a_uTag "." #a_CtxTagN, uDepth, pvUser); break +#define RTASN1TMPL_END_PCHOICE() \ + } \ + RTASN1TMPL_END_COMMON() + +# define RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) \ + RTASN1TMPL_BEGIN_COMMON(); \ + for (uint32_t i = 0; i < pThis->cItems && rc == VINF_SUCCESS; i++) \ + rc = pfnCallback(RT_CONCAT(a_ItemApi,_GetAsn1Core)(pThis->papItems[i]), "papItems[#]", uDepth, pvUser); \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_CLONE +/* + * + * Clone another instance of the type. + * + */ +# define RTASN1TMPL_BEGIN_COMMON() \ +RTASN1TMPL_DECL(int) RT_CONCAT(RTASN1TMPL_EXT_NAME,_Clone)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, \ + RT_CONCAT(PC,RTASN1TMPL_TYPE) pSrc, \ + PCRTASN1ALLOCATORVTABLE pAllocator) \ +{ \ + RT_ZERO(*pThis); \ + if (!RT_CONCAT(RTASN1TMPL_EXT_NAME,_IsPresent)(pSrc)) \ + return VINF_SUCCESS; \ + +# define RTASN1TMPL_END_COMMON() \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_BEGIN_SEQCORE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + int rc = RTAsn1SequenceCore_Clone(&pThis->SeqCore, &RT_CONCAT3(g_, RTASN1TMPL_INT_NAME, _Vtable), &pSrc->SeqCore) +# define RTASN1TMPL_BEGIN_SETCORE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + int rc = RTAsn1SetCore_Clone(&pThis->SetCore, &RT_CONCAT3(g_, RTASN1TMPL_INT_NAME, _Vtable), &pSrc->SetCore) + +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) \ + if (RT_SUCCESS(rc)) \ + rc = RT_CONCAT(a_Api,_Clone)(&pThis->a_Name, &pSrc->a_Name, pAllocator); \ + +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + if (RT_SUCCESS(rc)) \ + { \ + RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator); \ + pThis->a_enmMembNm = pSrc->a_enmMembNm; \ + switch (pSrc->a_enmMembNm) \ + { \ + default: rc = VERR_INTERNAL_ERROR_3; break +# define RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, a_IfStmt) \ + case a_enmValue: \ + rc = RTAsn1MemAllocZ(&pThis->a_Allocation, (void **)&pThis->a_UnionNm.a_PtrName, \ + sizeof(*pThis->a_UnionNm.a_PtrName)); \ + if (RT_SUCCESS(rc)) \ + rc = RT_CONCAT(a_Api,_Clone)(pThis->a_UnionNm.a_PtrName, pSrc->a_UnionNm.a_PtrName, pAllocator); \ + break +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + case RT_CONCAT(a_enmType,_NOT_PRESENT): break; \ + } \ + } + +/* Optional members and members with defaults are the same as a normal member when cloning. */ +# define RTASN1TMPL_MEMBER_OPT_UTF8_STRING_EX(a_Name, a_Constraints) \ + RTASN1TMPL_MEMBER_OPT_EX(a_Name, RTASN1STRING, RTAsn1Utf8String, a_Constraints RT_NOTHING) +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + if (RTASN1CORE_IS_PRESENT(&pSrc->a_TnNm.a_CtxTagN.Asn1Core) && RT_SUCCESS(rc)) \ + { \ + rc = RT_CONCAT3(RTAsn1ContextTag,a_uTag,_Clone)(&pThis->a_TnNm.a_CtxTagN, &pSrc->a_TnNm.a_CtxTagN); \ + if (RT_SUCCESS(rc)) \ + rc = RT_CONCAT(a_Api,_Clone)(&pThis->a_TnNm.a_Name, &pSrc->a_TnNm.a_Name, pAllocator); \ + } do { } while (0) + +# define RTASN1TMPL_END_SEQCORE() \ + if (RT_FAILURE(rc)) \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_END_SEQCORE() + + +# define RTASN1TMPL_BEGIN_PCHOICE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + RTAsn1Dummy_InitEx(&pThis->Dummy); \ + pThis->Dummy.Asn1Core.pOps = &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable); \ + RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator); \ + int rc; \ + pThis->enmChoice = pSrc->enmChoice; \ + switch (pSrc->enmChoice) \ + { \ + default: rc = VERR_INTERNAL_ERROR_3; break +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + case a_enmChoice: \ + rc = RTAsn1MemAllocZ(&pThis->Allocation, (void **)&pThis->a_PtrName, sizeof(*pThis->a_PtrName)); \ + if (RT_SUCCESS(rc)) \ + rc = RT_CONCAT(a_Api,_Clone)(pThis->a_PtrName, pSrc->a_PtrName, pAllocator); \ + break +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + case a_enmChoice: /* A bit of presence paranoia here, but better safe than sorry... */ \ + rc = RTAsn1MemAllocZ(&pThis->Allocation, (void **)&pThis->a_PtrTnNm, sizeof(*pThis->a_PtrTnNm)); \ + if (RT_SUCCESS(rc) && RTASN1CORE_IS_PRESENT(&pSrc->a_PtrTnNm->a_CtxTagN.Asn1Core)) \ + { \ + RT_CONCAT3(RTAsn1ContextTag,a_uTag,_Clone)(&pThis->a_PtrTnNm->a_CtxTagN, &pSrc->a_PtrTnNm->a_CtxTagN); \ + rc = RT_CONCAT(a_Api,_Clone)(&pThis->a_PtrTnNm->a_Name, &pSrc->a_PtrTnNm->a_Name, pAllocator); \ + } \ + break +#define RTASN1TMPL_END_PCHOICE() \ + } \ + if (RT_FAILURE(rc)) \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); \ + RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, a_OfApi, a_OfMember) \ + RTASN1TMPL_BEGIN_COMMON(); \ + int rc = RT_CONCAT(a_OfApi,_Clone)(&pThis->a_OfMember, &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable), &pSrc->a_OfMember); \ + if (RT_SUCCESS(rc)) \ + { \ + RTAsn1MemInitArrayAllocation(&pThis->Allocation, pAllocator, sizeof(a_ItemType)); \ + uint32_t const cItems = pSrc->cItems; \ + if (cItems > 0) \ + { \ + rc = RTAsn1MemResizeArray(&pThis->Allocation, (void ***)&pThis->papItems, 0, cItems); \ + if (RT_SUCCESS(rc)) \ + { \ + uint32_t i = 0; \ + while (i < cItems) \ + { \ + rc = RT_CONCAT(a_ItemApi,_Clone)(pThis->papItems[i], pSrc->papItems[i], pAllocator); \ + if (RT_SUCCESS(rc)) \ + pThis->cItems = ++i; \ + else \ + { \ + pThis->cItems = i; \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); \ + return rc; \ + } \ + } \ + } \ + else \ + RT_ZERO(*pThis); \ + } \ + } \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, RTAsn1SeqOfCore, SeqCore) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi, RTAsn1SetOfCore, SetCore) + +# define RTASN1TMPL_EXEC_CLONE(a_Expr) if (RT_SUCCESS(rc)) { a_Expr; } + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_SETTERS_1 +/* + * + * Member setter helpers. + * + */ +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() +#if 1 /** @todo later */ +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) RTASN1TMPL_SEMICOLON_DUMMY() +#else +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) \ + RTDECL(int) RT_CONCAT3(RTASN1TMPL_EXT_NAME,_Set,a_Name)(RTASN1TMPL_TYPE *pThis, a_Type const *pValue, \ + PCRTASN1ALLOCATORVTABLE pAllocator) \ + { \ + if (RT_CONCAT(a_Api,_IsPresent)(&pThis->a_Name)) \ + RT_CONCAT(a_Api,_Delete)(&pThis->a_Name); \ + return RT_CONCAT(a_Api,_Clone)(&pThis->a_Name, pValue, pAllocator, true /* fResetImplicit */); \ + } RTASN1TMPL_SEMICOLON_DUMMY() +#endif + +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() + + +# define RTASN1TMPL_BEGIN_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() + + +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SEMICOLON_DUMMY() + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_SETTERS_2 +/* + * + * Member setters. + * + */ +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_MEMBER_DYN(a_UnionNm, a_PtrName, a_Name, a_Type, a_Api, a_Allocation, a_ObjIdMembNm, a_enmMembNm, a_enmValue, a_szObjId) \ +RTASN1TMPL_DECL(int) RT_CONCAT3(RTASN1TMPL_EXT_NAME,_Set,a_Name)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, \ + RT_CONCAT(PC,a_Type) pToClone,\ + PCRTASN1ALLOCATORVTABLE pAllocator) \ +{ \ + AssertPtr(pThis); AssertPtrNull(pToClone); Assert(!pToClone || RT_CONCAT(a_Api,_IsPresent)(pToClone)); \ + AssertReturn(pThis->a_UnionNm.a_PtrName == NULL, VERR_INVALID_STATE); /* for now */ \ + /* Set the type */ \ + if (RTAsn1ObjId_IsPresent(&pThis->a_ObjIdMembNm)) \ + RTAsn1ObjId_Delete(&pThis->a_ObjIdMembNm); \ + int rc = RTAsn1ObjId_InitFromString(&pThis->a_ObjIdMembNm, a_szObjId, pAllocator); \ + if (RT_SUCCESS(rc)) \ + { \ + pThis->a_enmMembNm = a_enmValue; \ + \ + /* Allocate memory for the structure we're targeting. */ \ + rc = RTAsn1MemAllocZ(&pThis->a_Allocation, (void **)&pThis->a_UnionNm.a_PtrName, sizeof(*pThis->a_UnionNm.a_PtrName)); \ + if (RT_SUCCESS(rc)) \ + { \ + if (pToClone) /* If nothing to clone, just initialize the structure. */ \ + rc = RT_CONCAT(a_Api,_Clone)(pThis->a_UnionNm.a_PtrName, pToClone, pAllocator); \ + else \ + rc = RT_CONCAT(a_Api,_Init)(pThis->a_UnionNm.a_PtrName, pAllocator); \ + } \ + } \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + + + +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, a_fClue, a_Constraints) \ +RTASN1TMPL_DECL(int) RT_CONCAT3(RTASN1TMPL_EXT_NAME,_Set,a_Name)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, \ + RT_CONCAT(PC,a_Type) pToClone,\ + PCRTASN1ALLOCATORVTABLE pAllocator) \ +{ \ + AssertPtr(pThis); AssertPtrNull(pToClone); Assert(!pToClone || RT_CONCAT(a_Api,_IsPresent)(pToClone)); \ + if (RT_CONCAT(a_Api,_IsPresent)(&pThis->a_Name)) \ + RT_CONCAT(a_Api,_Delete)(&pThis->a_Name); \ + \ + int rc; \ + if (pToClone) \ + rc = RT_CONCAT(a_Api,_Clone)(&pThis->a_Name, pToClone, pAllocator); \ + else \ + rc = RT_CONCAT(a_Api,_Init)(&pThis->a_Name, pAllocator); \ + if (RT_SUCCESS(rc)) \ + { \ + RTAsn1Core_ResetImplict(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_Name)); /* probably not needed */ \ + rc = RTAsn1Core_SetTagAndFlags(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_Name), \ + a_uTag, RTASN1TMPL_ITAG_F_EXPAND(a_fClue)); \ + } \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ +RTASN1TMPL_DECL(int) RT_CONCAT3(RTASN1TMPL_EXT_NAME,_Set,a_Name)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, \ + RT_CONCAT(PC,a_Type) pToClone,\ + PCRTASN1ALLOCATORVTABLE pAllocator) \ +{ \ + AssertPtr(pThis); AssertPtrNull(pToClone); Assert(!pToClone || RT_CONCAT(a_Api,_IsPresent)(pToClone)); \ + if (RTASN1CORE_IS_PRESENT(&pThis->a_TnNm.a_CtxTagN.Asn1Core)) \ + RT_CONCAT(a_Api,_Delete)(&pThis->a_TnNm.a_Name); \ + \ + int rc = RT_CONCAT3(RTAsn1ContextTag,a_uTag,_Init)(&pThis->a_TnNm.a_CtxTagN, \ + &RT_CONCAT5(g_,RTASN1TMPL_INT_NAME,_XTAG_,a_Name,_Vtable), \ + pAllocator); \ + if (RT_SUCCESS(rc)) \ + { \ + if (pToClone) \ + rc = RT_CONCAT(a_Api,_Clone)(&pThis->a_TnNm.a_Name, pToClone, pAllocator); \ + else \ + rc = RT_CONCAT(a_Api,_Init)(&pThis->a_TnNm.a_Name, pAllocator); \ + if (RT_SUCCESS(rc) && pToClone) \ + RTAsn1Core_ResetImplict(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_TnNm.a_Name)); \ + } \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_BEGIN_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ +RTASN1TMPL_DECL(int) RT_CONCAT3(RTASN1TMPL_EXT_NAME,_Set,a_Name)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, \ + RT_CONCAT(PC,a_Type) pToClone,\ + PCRTASN1ALLOCATORVTABLE pAllocator) \ +{ \ + AssertPtrNull(pToClone); AssertPtr(pThis); \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); /* See _Init. */ \ + RTAsn1Dummy_InitEx(&pThis->Dummy); \ + pThis->Dummy.Asn1Core.pOps = &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable); \ + RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator); \ + pThis->enmChoice = a_enmChoice; \ + int rc = RTAsn1MemAllocZ(&pThis->Allocation, (void **)&pThis->a_PtrName, sizeof(*pThis->a_PtrName)); \ + if (RT_SUCCESS(rc)) \ + { \ + if (pToClone) \ + rc = RT_CONCAT(a_Api,_Clone)(pThis->a_PtrName, pToClone, pAllocator); \ + else \ + rc = RT_CONCAT(a_Api,_Init)(pThis->a_PtrName, pAllocator); \ + if (RT_SUCCESS(rc)) \ + { \ + if (pToClone) \ + RTAsn1Core_ResetImplict(RT_CONCAT(a_Api,_GetAsn1Core)(pThis->a_PtrName)); \ + rc = RTAsn1Core_SetTagAndFlags(RT_CONCAT(a_Api,_GetAsn1Core)(pThis->a_PtrName), \ + a_uTag, RTASN1TMPL_ITAG_F_EXPAND(a_fClue)); \ + } \ + } \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ +RTASN1TMPL_DECL(int) RT_CONCAT3(RTASN1TMPL_EXT_NAME,_Set,a_Name)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, \ + RT_CONCAT(PC,a_Type) pToClone,\ + PCRTASN1ALLOCATORVTABLE pAllocator) \ +{ \ + AssertPtr(pThis); AssertPtrNull(pToClone); Assert(!pToClone || RT_CONCAT(a_Api,_IsPresent)(pToClone)); \ + RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(pThis); /* See _Init. */ \ + RTAsn1Dummy_InitEx(&pThis->Dummy); \ + pThis->Dummy.Asn1Core.pOps = &RT_CONCAT3(g_,RTASN1TMPL_INT_NAME,_Vtable); \ + RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator); \ + pThis->enmChoice = a_enmChoice; \ + int rc = RTAsn1MemAllocZ(&pThis->Allocation, (void **)&pThis->a_PtrTnNm, sizeof(*pThis->a_PtrTnNm)); \ + if (RT_SUCCESS(rc)) \ + { \ + rc = RT_CONCAT3(RTAsn1ContextTag,a_uTag,_Init)(&pThis->a_PtrTnNm->a_CtxTagN, \ + &RT_CONCAT5(g_,RTASN1TMPL_INT_NAME,_PCHOICE_XTAG_,a_Name,_Vtable), \ + pAllocator); \ + if (RT_SUCCESS(rc)) \ + { \ + if (pToClone) \ + rc = RT_CONCAT(a_Api,_Clone)(&pThis->a_PtrTnNm->a_Name, pToClone, pAllocator); \ + else \ + rc = RT_CONCAT(a_Api,_Init)(&pThis->a_PtrTnNm->a_Name, pAllocator); \ + if (RT_SUCCESS(rc) && pToClone) \ + RTAsn1Core_ResetImplict(RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_PtrTnNm->a_Name)); \ + } \ + } \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_END_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() + + +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SEMICOLON_DUMMY() + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_ARRAY +/* + * + * Array operations. + * + */ +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_BEGIN_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + RTASN1TMPL_SEMICOLON_DUMMY() +# define RTASN1TMPL_END_PCHOICE() RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) \ + RTASN1TMPL_DECL(int) RT_CONCAT(RTASN1TMPL_EXT_NAME,_Erase)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, uint32_t iPosition) \ + { \ + /* Check and adjust iPosition. */ \ + uint32_t const cItems = pThis->cItems; \ + if (iPosition < cItems) \ + { /* likely */ } \ + else \ + { \ + AssertReturn(iPosition == UINT32_MAX, VERR_OUT_OF_RANGE); \ + AssertReturn(cItems > 0, VERR_OUT_OF_RANGE); \ + iPosition = cItems - 1; \ + } \ + \ + /* Delete the entry instance. */ \ + RT_CONCAT(P, a_ItemType) pErased = pThis->papItems[iPosition]; \ + if (RT_CONCAT(a_ItemApi,_IsPresent)(pErased)) \ + RT_CONCAT(a_ItemApi,_Delete)(pErased); \ + \ + /* If not the final entry, shift the other entries up and place the erased on at the end. */ \ + if (iPosition < cItems - 1) \ + { \ + memmove(&pThis->papItems[iPosition], &pThis->papItems[iPosition + 1], (cItems - iPosition - 1) * sizeof(void *)); \ + pThis->papItems[cItems - 1] = pErased; \ + } \ + /* Commit the new array size. */ \ + pThis->cItems = cItems - 1; \ + \ + /* Call the allocator to resize the array (ignore return). */ \ + RTAsn1MemResizeArray(&pThis->Allocation, (void ***)&pThis->papItems, cItems - 1, cItems); \ + return VINF_SUCCESS; \ + } \ + \ + RTASN1TMPL_DECL(int) RT_CONCAT(RTASN1TMPL_EXT_NAME,_InsertEx)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis, uint32_t iPosition, \ + RT_CONCAT(PC, a_ItemType) pToClone, \ + PCRTASN1ALLOCATORVTABLE pAllocator, uint32_t *piActualPos) \ + { \ + /* Check and adjust iPosition. */ \ + uint32_t const cItems = pThis->cItems; \ + if (iPosition <= cItems) \ + { /* likely */ } \ + else \ + { \ + AssertReturn(iPosition == UINT32_MAX, VERR_OUT_OF_RANGE); \ + iPosition = cItems; \ + } \ + \ + /* Ensure we've got space in the array. */ \ + int rc = RTAsn1MemResizeArray(&pThis->Allocation, (void ***)&pThis->papItems, cItems, cItems + 1); \ + if (RT_SUCCESS(rc)) \ + { \ + /* Initialize the new entry (which is currently at the end of the array) either with defaults or as a clone. */ \ + RT_CONCAT(P,a_ItemType) pInserted = pThis->papItems[cItems]; \ + if (RT_CONCAT(a_ItemApi,_IsPresent)(pToClone)) \ + rc = RT_CONCAT(a_ItemApi,_Clone)(pInserted, pToClone, pAllocator); \ + else \ + rc = RT_CONCAT(a_ItemApi,_Init)(pInserted, pAllocator); \ + if (RT_SUCCESS(rc)) \ + { \ + pThis->cItems = cItems + 1; \ + \ + /* If not inserting at the end of the array, shift existing items out of the way and insert the new as req. */ \ + if (iPosition != cItems) \ + { \ + memmove(&pThis->papItems[iPosition + 1], &pThis->papItems[iPosition], (cItems - iPosition) * sizeof(void *)); \ + pThis->papItems[iPosition] = pInserted; \ + } \ + \ + /* Done! */ \ + if (piActualPos) \ + *piActualPos = iPosition; \ + return VINF_SUCCESS; \ + } \ + RTAsn1MemResizeArray(&pThis->Allocation, (void ***)&pThis->papItems, cItems + 1, cItems); \ + } \ + return rc; \ + } RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_COMPARE +/* + * + * Compare two instances of the type. + * + */ +# define RTASN1TMPL_BEGIN_COMMON() \ +RTASN1TMPL_DECL(int) RT_CONCAT(RTASN1TMPL_EXT_NAME,_Compare)(RT_CONCAT(PC,RTASN1TMPL_TYPE) pLeft, \ + RT_CONCAT(PC,RTASN1TMPL_TYPE) pRight) \ +{ \ + if (!RT_CONCAT(RTASN1TMPL_EXT_NAME,_IsPresent)(pLeft)) \ + return 0 - (int)RT_CONCAT(RTASN1TMPL_EXT_NAME,_IsPresent)(pRight); \ + if (!RT_CONCAT(RTASN1TMPL_EXT_NAME,_IsPresent)(pRight)) \ + return -1; \ + int iDiff = 0 + +# define RTASN1TMPL_END_COMMON() \ + return iDiff; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) \ + if (!iDiff) \ + iDiff = RT_CONCAT(a_Api,_Compare)(&pLeft->a_Name, &pRight->a_Name) +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + if (!iDiff && pLeft->a_enmMembNm != pRight->a_enmMembNm) \ + iDiff = pLeft->a_enmMembNm < pRight->a_enmMembNm ? -1 : 1; \ + else if (!iDiff) \ + switch (pLeft->a_enmMembNm) \ + { \ + default: break +# define RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, a_IfStmt) \ + case a_enmValue: iDiff = RT_CONCAT(a_Api,_Compare)(pLeft->a_UnionNm.a_PtrName, pRight->a_UnionNm.a_PtrName); break +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + case RT_CONCAT(a_enmType,_NOT_PRESENT): break; \ + } +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + if (!iDiff) \ + { \ + if (RTASN1CORE_IS_PRESENT(&pLeft->a_TnNm.a_CtxTagN.Asn1Core)) \ + { \ + if (RTASN1CORE_IS_PRESENT(&pRight->a_TnNm.a_CtxTagN.Asn1Core)) \ + iDiff = RT_CONCAT(a_Api,_Compare)(&pLeft->a_TnNm.a_Name, &pRight->a_TnNm.a_Name); \ + else \ + iDiff = -1; \ + } \ + else \ + iDiff = 0 - (int)RTASN1CORE_IS_PRESENT(&pRight->a_TnNm.a_CtxTagN.Asn1Core); \ + } do { } while (0) +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_END_COMMON() + +# define RTASN1TMPL_BEGIN_PCHOICE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + if (pLeft->enmChoice != pRight->enmChoice) \ + return pLeft->enmChoice < pRight->enmChoice ? -1 : 1; \ + switch (pLeft->enmChoice) \ + { \ + default: break +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + case a_enmChoice: iDiff = RT_CONCAT(a_Api,_Compare)(pLeft->a_PtrName, pRight->a_PtrName); break +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + case a_enmChoice: iDiff = RT_CONCAT(a_Api,_Compare)(&pLeft->a_PtrTnNm->a_Name, &pRight->a_PtrTnNm->a_Name); break +#define RTASN1TMPL_END_PCHOICE() \ + } \ + RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) \ + RTASN1TMPL_BEGIN_COMMON(); \ + uint32_t cItems = pLeft->cItems; \ + if (cItems == pRight->cItems) \ + for (uint32_t i = 0; iDiff == 0 && i < cItems; i++) \ + iDiff = RT_CONCAT(a_ItemApi,_Compare)(pLeft->papItems[i], pRight->papItems[i]); \ + else \ + iDiff = cItems < pRight->cItems ? -1 : 1; \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) + + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_CHECK_SANITY +/* + * + * Checks the sanity of the type. + * + */ +# ifndef RTASN1TMPL_SANITY_CHECK_EXPR +# define RTASN1TMPL_SANITY_CHECK_EXPR() VINF_SUCCESS +# endif +# define RTASN1TMPL_BEGIN_COMMON() \ +RTASN1TMPL_DECL(int) RT_CONCAT(RTASN1TMPL_EXT_NAME,_CheckSanity)(RT_CONCAT(PC,RTASN1TMPL_TYPE) pThis, uint32_t fFlags, \ + PRTERRINFO pErrInfo, const char *pszErrorTag) \ +{ \ + if (RT_LIKELY(RT_CONCAT(RTASN1TMPL_EXT_NAME,_IsPresent)(pThis))) \ + { /* likely */ } \ + else \ + return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "%s: Missing (%s).", pszErrorTag, RT_XSTR(RTASN1TMPL_TYPE)); \ + int rc = VINF_SUCCESS + +# define RTASN1TMPL_END_COMMON() \ + if (RT_SUCCESS(rc)) \ + rc = (RTASN1TMPL_SANITY_CHECK_EXPR()); \ + return rc; \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) \ + if (RT_SUCCESS(rc)) \ + { \ + if (RT_LIKELY(RT_CONCAT(a_Api,_IsPresent)(&pThis->a_Name))) \ + { \ + rc = RT_CONCAT(a_Api,_CheckSanity)(&pThis->a_Name, fFlags & RTASN1_CHECK_SANITY_F_COMMON_MASK, \ + pErrInfo, RT_XSTR(RTASN1TMPL_TYPE) "::" #a_Name); \ + { a_Constraints } \ + } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "%s: Missing member %s (%s).", \ + pszErrorTag, #a_Name, RT_XSTR(RTASN1TMPL_TYPE)); \ + } do {} while (0) +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + if (RT_SUCCESS(rc)) \ + switch (pThis->a_enmMembNm) \ + { \ + default: \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, \ + "%s: Invalid " #a_enmMembNm " value: %d", pszErrorTag, pThis->a_enmMembNm); \ + break +# define RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, a_IfStmt) \ + case a_enmValue: \ + rc = RT_CONCAT(a_Api,_CheckSanity)(pThis->a_UnionNm.a_PtrName, fFlags & RTASN1_CHECK_SANITY_F_COMMON_MASK, \ + pErrInfo, RT_XSTR(RTASN1TMPL_TYPE) "::" #a_UnionNm "." #a_PtrName); \ + break +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + case RT_CONCAT(a_enmType,_NOT_PRESENT): \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, \ + "%s: Invalid " #a_enmMembNm " value: " #a_enmType "_NOT_PRESENT", pszErrorTag); \ + break; \ + } +# define RTASN1TMPL_MEMBER_OPT_EX(a_Name, a_Type, a_Api, a_Constraints) \ + if (RT_SUCCESS(rc) && RT_CONCAT(a_Api,_IsPresent)(&pThis->a_Name)) \ + { \ + rc = RT_CONCAT(a_Api,_CheckSanity)(&pThis->a_Name, fFlags & RTASN1_CHECK_SANITY_F_COMMON_MASK, \ + pErrInfo, RT_XSTR(RTASN1TMPL_TYPE) "::" #a_Name); \ + { a_Constraints } \ + } +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + if (RT_SUCCESS(rc)) \ + { \ + bool const fOuterPresent = RTASN1CORE_IS_PRESENT(&pThis->a_TnNm.a_CtxTagN.Asn1Core); \ + bool const fInnerPresent = RT_CONCAT(a_Api,_IsPresent)(&pThis->a_TnNm.a_Name); \ + if (fOuterPresent && fInnerPresent) \ + { \ + rc = RT_CONCAT(a_Api,_CheckSanity)(&pThis->a_TnNm.a_Name, fFlags & RTASN1_CHECK_SANITY_F_COMMON_MASK, \ + pErrInfo, RT_XSTR(RTASN1TMPL_TYPE) "::" #a_Name); \ + { a_Constraints } \ + } \ + else if (RT_LIKELY(RTASN1CORE_IS_PRESENT(&pThis->a_TnNm.a_CtxTagN.Asn1Core) == fInnerPresent)) \ + { /* likely */ } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, \ + "%s::" #a_TnNm "." #a_Name ": Explict tag precense mixup; " #a_CtxTagN "=%d " #a_Name "=%d.", \ + pszErrorTag, fOuterPresent, fInnerPresent); \ + } do { } while (0) +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_BEGIN_PCHOICE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + switch (pThis->enmChoice) \ + { \ + default: \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, \ + "%s: Invalid enmChoice value: %d", pszErrorTag, pThis->enmChoice); \ + break +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + case a_enmChoice: \ + if (pThis->a_PtrName && RT_CONCAT(a_Api,_IsPresent)(pThis->a_PtrName)) \ + { \ + PCRTASN1CORE pCore = RT_CONCAT(a_Api,_GetAsn1Core)(pThis->a_PtrName); \ + if (pCore->uTag == a_uTag && pCore->fClass == RTASN1TMPL_ITAG_F_EXPAND(a_fClue)) \ + { \ + rc = RT_CONCAT(a_Api,_CheckSanity)(pThis->a_PtrName, fFlags & RTASN1_CHECK_SANITY_F_COMMON_MASK, \ + pErrInfo, RT_XSTR(RTASN1TMPL_TYPE) "::" #a_Name); \ + { a_Constraints } \ + } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, \ + "%s::" #a_Name ": Tag/class mismatch: expected %#x/%#x, actual %#x/%x.", \ + pszErrorTag, a_uTag, RTASN1TMPL_ITAG_F_EXPAND(a_fClue), pCore->uTag, pCore->fClass); \ + } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "%s::" #a_Name ": Not present.", pszErrorTag); \ + break +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + case a_enmChoice: \ + if ( pThis->a_PtrTnNm \ + && RTASN1CORE_IS_PRESENT(&(pThis->a_PtrTnNm->a_CtxTagN.Asn1Core)) \ + && RT_CONCAT(a_Api,_IsPresent)(&pThis->a_PtrTnNm->a_Name) ) \ + { \ + rc = RT_CONCAT(a_Api,_CheckSanity)(&pThis->a_PtrTnNm->a_Name, fFlags & RTASN1_CHECK_SANITY_F_COMMON_MASK, \ + pErrInfo, RT_XSTR(RTASN1TMPL_TYPE) "::" #a_Name); \ + { a_Constraints } \ + } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "%s::" #a_Name ": Not present.", pszErrorTag); \ + break +#define RTASN1TMPL_END_PCHOICE() \ + } \ + RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) \ + RTASN1TMPL_BEGIN_COMMON(); \ + for (uint32_t i = 0; RT_SUCCESS(rc) && i < pThis->cItems; i++) \ + rc = RT_CONCAT(a_ItemApi,_CheckSanity)(pThis->papItems[i], fFlags & RTASN1_CHECK_SANITY_F_COMMON_MASK, \ + pErrInfo, RT_XSTR(RTASN1TMPL_TYPE) "::papItems[#]"); \ + if (RT_SUCCESS(rc)) { RTASN1TMPL_SET_SEQ_EXEC_CHECK_SANITY(); } \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) + +/* The constraints. */ +# define RTASN1TMPL_MEMBER_CONSTR_MIN_MAX(a_Name, a_Type, a_Api, cbMin, cbMax, a_MoreConstraints) \ + if (RT_SUCCESS(rc) && ((cbMin) != 0 || (cbMax) != UINT32_MAX)) \ + { \ + PCRTASN1CORE pCore = RT_CONCAT(a_Api,_GetAsn1Core)(&pThis->a_Name); \ + if (RT_LIKELY(pCore->cb >= (cbMin) && pCore->cb <= (cbMax))) \ + { /* likely */ } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, \ + "%s::" #a_Name ": Content size is out of range: %#x not in {%#x..%#x}", \ + pszErrorTag, pCore->cb, cbMin, cbMax); \ + } \ + { a_MoreConstraints } + +# define RTASN1TMPL_MEMBER_CONSTR_BITSTRING_MIN_MAX(a_Name, cMinBits, cMaxBits, a_MoreConstraints) \ + if (RT_SUCCESS(rc) && ((cMinBits) != 0 || (cMaxBits) != UINT32_MAX)) \ + { \ + if (RT_LIKELY( ((cMinBits) == 0 ? true : pThis->a_Name.cBits + 1U >= (cMinBits) + 1U /* warning avoiding */) \ + && ((cMaxBits) == UINT32_MAX ? true : pThis->a_Name.cBits + 1U <= (cMaxBits) + 1U /* ditto */) ) ) \ + { /* likely */ } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, \ + "%s::" #a_Name ": Bit size is out of range: %#x not in {%#x..%#x}", \ + pszErrorTag, pThis->a_Name.cBits, cMinBits, cMaxBits); \ + } \ + { a_MoreConstraints } + +# define RTASN1TMPL_MEMBER_CONSTR_U64_MIN_MAX(a_Name, uMin, uMax, a_MoreConstraints) \ + if (RT_SUCCESS(rc)) \ + { \ + if (RT_LIKELY( RTAsn1Integer_UnsignedCompareWithU64(&pThis->a_Name, uMin) >= 0 \ + && RTAsn1Integer_UnsignedCompareWithU64(&pThis->a_Name, uMax) <= 0) ) \ + { /* likely */ } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, \ + "%s::" #a_Name ": Out of range: %#x not in {%#llx..%#llx}", \ + pszErrorTag, pThis->a_Name.Asn1Core.cb > 8 ? UINT64_MAX : pThis->a_Name.uValue.u, \ + (uint64_t)(uMin), (uint64_t)(uMax)); \ + } \ + { a_MoreConstraints } + +# define RTASN1TMPL_MEMBER_CONSTR_PRESENT(a_Name, a_Api, a_MoreConstraints) \ + if (RT_SUCCESS(rc)) \ + { \ + if (RT_LIKELY(RT_CONCAT(a_Api,_IsPresent)(&pThis->a_Name))) \ + { /* likely */ } \ + else \ + rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "%s::" #a_Name ": Missing.", pszErrorTag); \ + } \ + { a_MoreConstraints } + + + +# define RTASN1TMPL_EXEC_CHECK_SANITY(a_Expr) if (RT_SUCCESS(rc)) { a_Expr; } + + +#elif RTASN1TMPL_PASS == RTASN1TMPL_PASS_DELETE +/* + * + * Delete wrappers. + * + */ +# define RTASN1TMPL_BEGIN_COMMON() \ +RTASN1TMPL_DECL(void) RT_CONCAT(RTASN1TMPL_EXT_NAME,_Delete)(RT_CONCAT(P,RTASN1TMPL_TYPE) pThis) \ +{ \ + if (RT_CONCAT(RTASN1TMPL_EXT_NAME,_IsPresent)(pThis)) \ + { do { } while (0) + +# define RTASN1TMPL_END_COMMON() \ + } \ + RT_ZERO(*pThis); \ +} RTASN1TMPL_SEMICOLON_DUMMY() + +# define RTASN1TMPL_BEGIN_SEQCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_BEGIN_SETCORE() RTASN1TMPL_BEGIN_COMMON() +# define RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints) RT_CONCAT(a_Api,_Delete)(&pThis->a_Name) +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + switch (pThis->a_enmMembNm) \ + { \ + default: break +# define RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, a_IfStmt) \ + case a_enmValue: \ + if (pThis->a_UnionNm.a_PtrName) \ + { \ + RT_CONCAT(a_Api,_Delete)(pThis->a_UnionNm.a_PtrName); \ + RTAsn1MemFree(&pThis->Allocation, pThis->a_UnionNm.a_PtrName); \ + pThis->a_UnionNm.a_PtrName = NULL; \ + } \ + break +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) \ + } +# define RTASN1TMPL_END_SEQCORE() RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_END_SETCORE() RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_BEGIN_PCHOICE() \ + RTASN1TMPL_BEGIN_COMMON(); \ + switch (pThis->enmChoice) \ + { \ + default: break +# define RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, a_fClue, a_Constraints) \ + case a_enmChoice: \ + if (pThis->a_PtrName) \ + { \ + RT_CONCAT(a_Api,_Delete)(pThis->a_PtrName); \ + RTAsn1MemFree(&pThis->Allocation, pThis->a_PtrName); \ + pThis->a_PtrName = NULL; \ + } \ + break +# define RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_Constraints) \ + case a_enmChoice: \ + if (pThis->a_PtrTnNm) \ + { \ + RT_CONCAT(a_Api,_Delete)(&pThis->a_PtrTnNm->a_Name); \ + RTAsn1MemFree(&pThis->Allocation, pThis->a_PtrTnNm); \ + pThis->a_PtrTnNm = NULL; \ + } \ + break +# define RTASN1TMPL_END_PCHOICE() \ + } \ + RTASN1TMPL_END_COMMON() + + +# define RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) \ + RTASN1TMPL_BEGIN_COMMON(); \ + uint32_t i = pThis->cItems; \ + while (i-- > 0) \ + RT_CONCAT(a_ItemApi,_Delete)(pThis->papItems[i]); \ + RTAsn1MemFreeArray(&pThis->Allocation, (void **)pThis->papItems); \ + pThis->papItems = NULL; \ + pThis->cItems = 0; \ + RTASN1TMPL_END_COMMON() +# define RTASN1TMPL_SEQ_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) +# define RTASN1TMPL_SET_OF(a_ItemType, a_ItemApi) RTASN1TMPL_SET_SEQ_OF_COMMON(a_ItemType, a_ItemApi) + + +#else +# error "Invalid/missing RTASN1TMPL_PASS value." +#endif + + + +/* + * Default aliases for simplified versions of macros if no specialization + * was required above. + */ +/* Non-optional members. */ +#ifndef RTASN1TMPL_MEMBER +# define RTASN1TMPL_MEMBER(a_Name, a_Type, a_Api) \ + RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, RT_NOTHING) +#endif + +#ifndef RTASN1TMPL_MEMBER_UTF8_STRING_MIN_MAX +# define RTASN1TMPL_MEMBER_UTF8_STRING_MIN_MAX(a_Name) \ + RTASN1TMPL_MEMBER(a_Name, RTASN1STRING, RTAsn1String) +#endif +#ifndef RTASN1TMPL_MEMBER_UTF8_STRING +# define RTASN1TMPL_MEMBER_UTF8_STRING(a_Name) \ + RTASN1TMPL_MEMBER_UTF8_STRING_MIN_MAX(a_Name, 0, UINT32_MAX) +#endif + +#ifndef RTASN1TMPL_MEMBER_STRING_MIN_MAX +# define RTASN1TMPL_MEMBER_STRING_MIN_MAX(a_Name, a_cbMin, a_cbMax) \ + RTASN1TMPL_MEMBER(a_Name, RTASN1STRING, RTAsn1String) +#endif +#ifndef RTASN1TMPL_MEMBER_STRING +# define RTASN1TMPL_MEMBER_STRING(a_Name) \ + RTASN1TMPL_MEMBER_STRING_MIN_MAX(a_Name, 0, UINT32_MAX) +#endif +#ifndef RTASN1TMPL_MEMBER_XTAG_EX +# define RTASN1TMPL_MEMBER_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + RTASN1TMPL_MEMBER_EX(a_TnNm.a_Name, a_Type, a_Api, a_Constraints RT_NOTHING) +#endif + +/* Any/dynamic members. */ +#ifndef RTASN1TMPL_MEMBER_DYN_BEGIN +# define RTASN1TMPL_MEMBER_DYN_BEGIN(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) do { } while (0) +#endif +#ifndef RTASN1TMPL_MEMBER_DYN_END +# define RTASN1TMPL_MEMBER_DYN_END(a_ObjIdMembNm, a_enmType, a_enmMembNm, a_Allocation) do { } while (0) +#endif +#ifndef RTASN1TMPL_MEMBER_DYN_COMMON +# define RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, a_IfStmt) \ + RTASN1TMPL_MEMBER(a_UnionNm.a_PtrName, a_Type, a_Api) +#endif +#ifndef RTASN1TMPL_MEMBER_DYN +# define RTASN1TMPL_MEMBER_DYN(a_UnionNm, a_PtrName, a_Name, a_Type, a_Api, a_Allocation, a_ObjIdMembNm, a_enmMembNm, a_enmValue, a_szObjId) \ + RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, if (RTAsn1ObjId_CompareWithString(&pThis->a_ObjIdMembNm, a_szObjId) == 0)) +#endif +#ifndef RTASN1TMPL_MEMBER_DYN_DEFAULT +# define RTASN1TMPL_MEMBER_DYN_DEFAULT(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_ObjIdMembNm, a_enmMembNm, a_enmValue) \ + RTASN1TMPL_MEMBER_DYN_COMMON(a_UnionNm, a_PtrName, a_Type, a_Api, a_Allocation, a_enmMembNm, a_enmValue, RT_NOTHING) +#endif + +/* Optional members. */ +#ifndef RTASN1TMPL_MEMBER_OPT_EX +# define RTASN1TMPL_MEMBER_OPT_EX(a_Name, a_Type, a_Api, a_Constraints) \ + RTASN1TMPL_MEMBER_EX(a_Name, a_Type, a_Api, a_Constraints RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT +# define RTASN1TMPL_MEMBER_OPT(a_Name, a_Type, a_Api) \ + RTASN1TMPL_MEMBER_OPT_EX(a_Name, a_Type, a_Api, RT_NOTHING) +#endif + +#ifndef RTASN1TMPL_MEMBER_OPT_XTAG_EX +# define RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, a_Constraints) \ + RTASN1TMPL_MEMBER_OPT_EX(a_TnNm.a_Name, a_Type, a_Api, a_Constraints RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT_XTAG +# define RTASN1TMPL_MEMBER_OPT_XTAG(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag) \ + RTASN1TMPL_MEMBER_OPT_XTAG_EX(a_TnNm, a_CtxTagN, a_Name, a_Type, a_Api, a_uTag, RT_NOTHING) +#endif + +#ifndef RTASN1TMPL_MEMBER_OPT_ITAG_EX +# define RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, a_fClue, a_Constraints) \ + RTASN1TMPL_MEMBER_OPT_EX(a_Name, a_Type, a_Api, a_Constraints RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT_ITAG_UP +# define RTASN1TMPL_MEMBER_OPT_ITAG_UP(a_Name, a_Type, a_Api, a_uTag) \ + RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, RTASN1TMPL_ITAG_F_UP, RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT_ITAG_UC +# define RTASN1TMPL_MEMBER_OPT_ITAG_UC(a_Name, a_Type, a_Api, a_uTag) \ + RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, RTASN1TMPL_ITAG_F_UC, RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT_ITAG_CP +# define RTASN1TMPL_MEMBER_OPT_ITAG_CP(a_Name, a_Type, a_Api, a_uTag) \ + RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, RTASN1TMPL_ITAG_F_CP, RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT_ITAG +# define RTASN1TMPL_MEMBER_OPT_ITAG(a_Name, a_Type, a_Api, a_uTag) \ + RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, RTASN1TMPL_ITAG_F_CC, RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT_ANY +# define RTASN1TMPL_MEMBER_OPT_ANY(a_Name, a_Type, a_Api) \ + RTASN1TMPL_MEMBER_OPT_EX(a_Name, a_Type, a_Api, RT_NOTHING) +#endif + +#ifndef RTASN1TMPL_MEMBER_DEF_ITAG_EX +# define RTASN1TMPL_MEMBER_DEF_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, a_fClue, a_DefVal, a_Constraints) \ + RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, a_fClue, a_Constraints RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_DEF_ITAG_UP +# define RTASN1TMPL_MEMBER_DEF_ITAG_UP(a_Name, a_Type, a_Api, a_uTag, a_DefVal) \ + RTASN1TMPL_MEMBER_DEF_ITAG_EX(a_Name, a_Type, a_Api, a_uTag, RTASN1TMPL_ITAG_F_UP, a_DefVal, RT_NOTHING) +#endif + +#ifndef RTASN1TMPL_MEMBER_OPT_ITAG_BITSTRING +# define RTASN1TMPL_MEMBER_OPT_ITAG_BITSTRING(a_Name, a_cMaxBits, a_uTag) \ + RTASN1TMPL_MEMBER_OPT_ITAG_EX(a_Name, RTASN1BITSTRING, RTAsn1BitString, a_uTag, RTASN1TMPL_ITAG_F_CP, \ + RTASN1TMPL_MEMBER_CONSTR_BITSTRING_MIN_MAX(a_Name, 0, a_cMaxBits, RT_NOTHING)) +#endif + +#ifndef RTASN1TMPL_MEMBER_OPT_UTF8_STRING_EX +# define RTASN1TMPL_MEMBER_OPT_UTF8_STRING_EX(a_Name, a_Constraints) \ + RTASN1TMPL_MEMBER_OPT_EX(a_Name, RTASN1STRING, RTAsn1String, a_Constraints RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT_UTF8_STRING +# define RTASN1TMPL_MEMBER_OPT_UTF8_STRING(a_Name) \ + RTASN1TMPL_MEMBER_OPT_UTF8_STRING_EX(a_Name, RT_NOTHING) +#endif + +#ifndef RTASN1TMPL_MEMBER_OPT_STRING_EX +# define RTASN1TMPL_MEMBER_OPT_STRING_EX(a_Name, a_Constraints) \ + RTASN1TMPL_MEMBER_OPT_EX(a_Name, RTASN1STRING, RTAsn1String, a_Constraints RT_NOTHING) +#endif +#ifndef RTASN1TMPL_MEMBER_OPT_STRING +# define RTASN1TMPL_MEMBER_OPT_STRING(a_Name) \ + RTASN1TMPL_MEMBER_OPT_STRING_EX(a_Name, RT_NOTHING) +#endif + +/* Pointer choices. */ +#ifndef RTASN1TMPL_PCHOICE_ITAG_UP +# define RTASN1TMPL_PCHOICE_ITAG_UP(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api) \ + RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, RTASN1TMPL_ITAG_F_UP, RT_NOTHING) +#endif +#ifndef RTASN1TMPL_PCHOICE_ITAG_UC +# define RTASN1TMPL_PCHOICE_ITAG_UC(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api) \ + RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, RTASN1TMPL_ITAG_F_UC, RT_NOTHING) +#endif +#ifndef RTASN1TMPL_PCHOICE_ITAG_CP +# define RTASN1TMPL_PCHOICE_ITAG_CP(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api) \ + RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, RTASN1TMPL_ITAG_F_CP, RT_NOTHING) +#endif +#ifndef RTASN1TMPL_PCHOICE_ITAG +# define RTASN1TMPL_PCHOICE_ITAG(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api) \ + RTASN1TMPL_PCHOICE_ITAG_EX(a_uTag, a_enmChoice, a_PtrName, a_Name, a_Type, a_Api, RTASN1TMPL_ITAG_F_CC, RT_NOTHING) +#endif + +#ifndef RTASN1TMPL_PCHOICE_XTAG +# define RTASN1TMPL_PCHOICE_XTAG(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api) \ + RTASN1TMPL_PCHOICE_XTAG_EX(a_uTag, a_enmChoice, a_PtrTnNm, a_CtxTagN, a_Name, a_Type, a_Api, RT_NOTHING) +#endif + + +/* + * Constraints are only used in the sanity check pass, so provide subs for the + * others passes. + */ +#ifndef RTASN1TMPL_MEMBER_CONSTR_MIN_MAX +# define RTASN1TMPL_MEMBER_CONSTR_MIN_MAX(a_Name, a_Type, a_Api, cbMin, cbMax, a_MoreConstraints) +#endif +#ifndef RTASN1TMPL_MEMBER_CONSTR_BITSTRING_MIN_MAX +# define RTASN1TMPL_MEMBER_CONSTR_BITSTRING_MIN_MAX(a_Name, cMinBits, cMaxBits, a_MoreConstraints) +#endif +#ifndef RTASN1TMPL_MEMBER_CONSTR_U64_MIN_MAX +# define RTASN1TMPL_MEMBER_CONSTR_U64_MIN_MAX(a_Name, uMin, uMax, a_MoreConstraints) +#endif +#ifndef RTASN1TMPL_MEMBER_CONSTR_PRESENT +# define RTASN1TMPL_MEMBER_CONSTR_PRESENT(a_Name, a_Api, a_MoreConstraints) +#endif + + +/* + * Stub exec hacks. + */ +#ifndef RTASN1TMPL_EXEC_DECODE +# define RTASN1TMPL_EXEC_DECODE(a_Expr) /* no semi colon allowed after this */ +#endif +#ifndef RTASN1TMPL_EXEC_CLONE +# define RTASN1TMPL_EXEC_CLONE(a_Expr) /* no semi colon allowed after this */ +#endif +#ifndef RTASN1TMPL_EXEC_CHECK_SANITY +# define RTASN1TMPL_EXEC_CHECK_SANITY(a_Expr) /* no semi colon allowed after this */ +#endif + +#define RTASN1TMPL_SET_SEQ_EXEC_CHECK_SANITY() do { } while (0) + + +/* + * Generate the requested code. + */ +#ifndef RTASN1TMPL_TEMPLATE_FILE +# error "No template file (RTASN1TMPL_TEMPLATE_FILE) is specified." +#endif +#include RTASN1TMPL_TEMPLATE_FILE + + + +/* + * Undo all the macros. + */ +#undef RTASN1TMPL_DECL +#undef RTASN1TMPL_TYPE +#undef RTASN1TMPL_EXT_NAME +#undef RTASN1TMPL_INT_NAME + +#undef RTASN1TMPL_PASS + +#undef RTASN1TMPL_BEGIN_COMMON +#undef RTASN1TMPL_END_COMMON +#undef RTASN1TMPL_BEGIN_SEQCORE +#undef RTASN1TMPL_BEGIN_SETCORE +#undef RTASN1TMPL_MEMBER +#undef RTASN1TMPL_MEMBER_EX +#undef RTASN1TMPL_MEMBER_DYN_BEGIN +#undef RTASN1TMPL_MEMBER_DYN +#undef RTASN1TMPL_MEMBER_DYN_DEFAULT +#undef RTASN1TMPL_MEMBER_DYN_COMMON +#undef RTASN1TMPL_MEMBER_DYN_END +#undef RTASN1TMPL_MEMBER_OPT +#undef RTASN1TMPL_MEMBER_OPT_EX +#undef RTASN1TMPL_MEMBER_OPT_ITAG +#undef RTASN1TMPL_MEMBER_OPT_ITAG_EX +#undef RTASN1TMPL_MEMBER_OPT_ITAG_CP +#undef RTASN1TMPL_MEMBER_OPT_ITAG_UC +#undef RTASN1TMPL_MEMBER_OPT_ITAG_UP +#undef RTASN1TMPL_MEMBER_OPT_ITAG_BITSTRING +#undef RTASN1TMPL_MEMBER_OPT_UTF8_STRING +#undef RTASN1TMPL_MEMBER_OPT_UTF8_STRING_EX +#undef RTASN1TMPL_MEMBER_OPT_XTAG +#undef RTASN1TMPL_MEMBER_OPT_XTAG_EX +#undef RTASN1TMPL_MEMBER_OPT_ANY +#undef RTASN1TMPL_MEMBER_DEF_ITAG_UP +#undef RTASN1TMPL_MEMBER_DEF_ITAG_EX +#undef RTASN1TMPL_END_SEQCORE +#undef RTASN1TMPL_END_SETCORE + +#undef RTASN1TMPL_BEGIN_PCHOICE +#undef RTASN1TMPL_PCHOICE_ITAG +#undef RTASN1TMPL_PCHOICE_ITAG_UP +#undef RTASN1TMPL_PCHOICE_ITAG_CP +#undef RTASN1TMPL_PCHOICE_ITAG_EX +#undef RTASN1TMPL_PCHOICE_XTAG +#undef RTASN1TMPL_PCHOICE_XTAG_EX +#undef RTASN1TMPL_END_PCHOICE + +#undef RTASN1TMPL_SET_SEQ_OF_COMMON +#undef RTASN1TMPL_SEQ_OF +#undef RTASN1TMPL_SET_OF + +#undef RTASN1TMPL_VTABLE_FN_ENCODE_PREP +#undef RTASN1TMPL_VTABLE_FN_ENCODE_WRITE + +#undef RTASN1TMPL_MEMBER_CONSTR_MIN_MAX +#undef RTASN1TMPL_MEMBER_CONSTR_BITSTRING_MIN_MAX +#undef RTASN1TMPL_MEMBER_CONSTR_U64_MIN_MAX +#undef RTASN1TMPL_MEMBER_CONSTR_PRESENT + +#undef RTASN1TMPL_SANITY_CHECK_EXPR + +#undef RTASN1TMPL_EXEC_DECODE +#undef RTASN1TMPL_EXEC_CLONE +#undef RTASN1TMPL_EXEC_CHECK_SANITY + +#undef RTASN1TMPL_SET_SEQ_EXEC_CHECK_SANITY + diff --git a/include/iprt/asn1-generator-sanity.h b/include/iprt/asn1-generator-sanity.h new file mode 100644 index 00000000..93ad5036 --- /dev/null +++ b/include/iprt/asn1-generator-sanity.h @@ -0,0 +1,38 @@ +/** @file + * IPRT - ASN.1 Code Generator, the Sanity Checking. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#define RTASN1TMPL_PASS RTASN1TMPL_PASS_CHECK_SANITY +#include <iprt/asn1-generator-pass.h> + diff --git a/include/iprt/asn1.h b/include/iprt/asn1.h new file mode 100644 index 00000000..19f200a6 --- /dev/null +++ b/include/iprt/asn1.h @@ -0,0 +1,2368 @@ +/** @file + * IPRT - Abstract Syntax Notation One (ASN.1). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_asn1_h +#define IPRT_INCLUDED_asn1_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/time.h> +#include <iprt/stdarg.h> +#include <iprt/errcore.h> +#include <iprt/formats/asn1.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_asn1 RTAsn1 - Abstract Syntax Notation One + * @ingroup grp_rt + * @{ + */ + + +/** Pointer to ASN.1 allocation information. */ +typedef struct RTASN1ALLOCATION *PRTASN1ALLOCATION; +/** Pointer to ASN.1 array allocation information. */ +typedef struct RTASN1ARRAYALLOCATION *PRTASN1ARRAYALLOCATION; +/** Pointer to a ASN.1 byte decoder cursor. */ +typedef struct RTASN1CURSOR *PRTASN1CURSOR; + + +/** + * Sketch of a custom ASN.1 allocator virtual method table. + * + * Any information required by the allocator should be associated with this + * structure, i.e. use this as a kind of parent class. This saves storage in + * RTASN1ALLOCATORINFO and possibly reduces the number of parameters by one. + */ +typedef struct RTASN1ALLOCATORVTABLE +{ + /** + * Free a chunk of memory allocated by this allocator. + * + * @returns IPRT status code. + * @param pThis Pointer to the vtable structure. + * @param pAllocation Pointer to the allocation info structure. + * @param pv Pointer to the memory that shall be freed. Not NULL. + */ + DECLCALLBACKMEMBER(void, pfnFree,(struct RTASN1ALLOCATORVTABLE const *pThis, PRTASN1ALLOCATION pAllocation, + void *pv)); + /** + * Allocates a chunk of memory, all initialized to zero. + * + * @returns IPRT status code. + * @param pThis Pointer to the vtable structure. + * @param pAllocation Pointer to the allocation info structure. + * @param ppv Where to store the pointer on success. + * @param cb The minimum number of bytes to allocate. The actual + * number of bytes allocated shall be stored in + * pInfo->cbAllocated on success. + */ + DECLCALLBACKMEMBER(int, pfnAlloc,(struct RTASN1ALLOCATORVTABLE const *pThis, PRTASN1ALLOCATION pAllocation, + void **ppv, size_t cb)); + /** + * Reallocates a memory allocation. + * + * New memory does not need to be initialized, the caller takes care of that. + * + * This will not need to deal with free (@a cbNew == 0) or the initial + * allocation (@a pvOld == NULL), those calls will be directed to pfnFree and + * pfnAlloc respectively. + * + * @returns IPRT status code. + * @param pThis Pointer to the vtable structure. + * @param pAllocation Pointer to the allocation info structure. + * @param pvOld Pointer to the current allocation. Shall remain + * valid on failure, but may be invalid on success. + * @param ppvNew Where to store the pointer on success. Shall not be + * touched, except on successful returns. + * @param cbNew The new minimum allocation size. The actual number + * of bytes allocated shall be stored in + * pInfo->cbAllocated on success. + */ + DECLCALLBACKMEMBER(int, pfnRealloc,(struct RTASN1ALLOCATORVTABLE const *pThis, PRTASN1ALLOCATION pAllocation, + void *pvOld, void **ppvNew, size_t cbNew)); + + /** + * Frees an array allocation (the array an all instances in it). + * + * @returns IPRT status code. + * @param pThis Pointer to the vtable structure. + * @param pAllocation Pointer to the allocation info structure. + * @param papvArray Pointer to the pointer array to be freed. Not NULL. + */ + DECLCALLBACKMEMBER(void, pfnFreeArray,(struct RTASN1ALLOCATORVTABLE const *pThis, PRTASN1ARRAYALLOCATION pAllocation, + void **papvArray)); + /** + * Grows the array to at least @a cMinEntries. + * + * The entries are initalized with ZEROs. + * + * @returns IPRT status code. + * @param pThis Pointer to the vtable structure. + * @param pAllocation Pointer to the allocation info structure. + * @param ppapvArray Pointer to the pointer to the array to be grown (or + * allocated). + * @param cMinEntries The minimum number of entries (array size and + * instantiated entries) that must be available + * on successful return. + */ + DECLCALLBACKMEMBER(int, pfnGrowArray,(struct RTASN1ALLOCATORVTABLE const *pThis, PRTASN1ARRAYALLOCATION pAllocation, + void ***ppapvArray, uint32_t cMinEntries)); + /** + * Shrinks the array (depends on allocator policy). + * + * If memory isn't freed, the implementation must fill the entries being + * shredded with ZEROs so the growth optimizations in RTAsn1MemResizeArray + * returns ZEROed entries. + * + * @returns IPRT status code. + * @param pThis Pointer to the vtable structure. + * @param pAllocation Pointer to the allocation info structure. + * @param ppapvArray Pointer to the pointer to the array to shrunk. + * @param cNew The new entry count. + * @param cCurrent The new entry count. + */ + DECLCALLBACKMEMBER(void, pfnShrinkArray,(struct RTASN1ALLOCATORVTABLE const *pThis, PRTASN1ARRAYALLOCATION pAllocation, + void ***ppapvArray, uint32_t cNew, uint32_t cCurrent)); +} RTASN1ALLOCATORVTABLE; +/** Pointer to an ASN.1 allocator vtable. */ +typedef RTASN1ALLOCATORVTABLE *PRTASN1ALLOCATORVTABLE; +/** Pointer to a const ASN.1 allocator vtable. */ +typedef RTASN1ALLOCATORVTABLE const *PCRTASN1ALLOCATORVTABLE; + +/** The default ASN.1 allocator. */ +extern RTDATADECL(RTASN1ALLOCATORVTABLE const) g_RTAsn1DefaultAllocator; + +/** The Electric Fence ASN.1 allocator. */ +extern RTDATADECL(RTASN1ALLOCATORVTABLE const) g_RTAsn1EFenceAllocator; + +/** The safer ASN.1 allocator for sensitive data. */ +extern RTDATADECL(RTASN1ALLOCATORVTABLE const) g_RTAsn1SaferAllocator; + + +/** + * Allocation information. + */ +typedef struct RTASN1ALLOCATION +{ + /** The number of bytes currently allocated. */ + uint32_t cbAllocated; + /** Number of realloc calls. */ + uint16_t cReallocs; + /** Reserved / padding. */ + uint16_t uReserved0; + /** Allocator vtable, NULL for the default allocator. */ + PCRTASN1ALLOCATORVTABLE pAllocator; +} RTASN1ALLOCATION; + + +/** + * Pointer array allocation information. + * + * Used by SET OF and SEQUENCE OF structures (typically automatically + * generated). + */ +typedef struct RTASN1ARRAYALLOCATION +{ + /** The size of the array entry. */ + uint32_t cbEntry; + /** The size of the pointer array allocation. */ + uint32_t cPointersAllocated; + /** Number of entry instances allocated. This can be greater than the + * official array size. */ + uint32_t cEntriesAllocated; + /** Number of array resizing calls (for increasing growth rate). + * Maintained by RTAsn1MemResizeArray(). */ + uint16_t cResizeCalls; + /** Reserved / padding. */ + uint16_t uReserved0; + /** Allocator vtable, NULL for the default allocator. */ + PCRTASN1ALLOCATORVTABLE pAllocator; +} RTASN1ARRAYALLOCATION; + + +/** + * Allocate a block of zero initialized memory. + * + * @returns IPRT status code. + * @param pAllocation The allocation record (initialized by + * RTAsn1CursorInitAllocation or similar). + * @param ppvMem Where to return the pointer to the block. + * @param cbMem The minimum number of bytes to allocate. + */ +RTDECL(int) RTAsn1MemAllocZ(PRTASN1ALLOCATION pAllocation, void **ppvMem, size_t cbMem); + +/** + * Allocates a block of memory initialized to the content of @a pvSrc. + * + * @returns IPRT status code. + * @param pAllocation The allocation record (initialized by + * RTAsn1CursorInitAllocation or similar). + * @param ppvMem Where to return the pointer to the block. + * @param pvSrc The source memory. + * @param cbMem The minimum number of bytes to allocate. + */ +RTDECL(int) RTAsn1MemDup(PRTASN1ALLOCATION pAllocation, void **ppvMem, void const *pvSrc, size_t cbMem); + +/** + * Free a memory block. + * + * @param pAllocation The allocation record (initialized by + * RTAsn1CursorInitAllocation or similar). + * @param pv The memory block to free. NULL will be ignored. + */ +RTDECL(void) RTAsn1MemFree(PRTASN1ALLOCATION pAllocation, void *pv); + +/** + * Initalize an allocation. + * + * @returns pAllocation + * @param pAllocation The allocation record (initialized by + * RTAsn1CursorInitAllocation or similar). + * @param pAllocator The allocator + */ +RTDECL(PRTASN1ALLOCATION) RTAsn1MemInitAllocation(PRTASN1ALLOCATION pAllocation, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Initalize an array allocation. + * + * @returns pAllocation + * @param pAllocation The allocation record (initialized by + * RTAsn1CursorInitAllocation or similar). + * @param pAllocator The allocator + * @param cbEntry The entry size. + */ +RTDECL(PRTASN1ARRAYALLOCATION) RTAsn1MemInitArrayAllocation(PRTASN1ARRAYALLOCATION pAllocation, + PCRTASN1ALLOCATORVTABLE pAllocator, size_t cbEntry); + +/** + * Resize an array with zero initialized memory. + * + * @returns IPRT status code. + * @param pAllocation The allocation record (initialized by + * RTAsn1CursorInitAllocation or similar). + * @param ppapvArray Pointer to the variable pointing to the array. This is + * both input and output. Remains valid on failure. + * @param cCurrent The current entry count. (Relevant for zero + * initialization of the new entries.) + * @param cNew The new entry count. + */ +RTDECL(int) RTAsn1MemResizeArray(PRTASN1ARRAYALLOCATION pAllocation, void ***ppapvArray, uint32_t cCurrent, uint32_t cNew); + +/** + * Frees an array and all its entries. + * + * @param pAllocation The array allocation record (initialized by + * RTAsn1CursorInitArrayAllocation or similar). + * @param papvArray The array to free. NULL is ignored. + */ +RTDECL(void) RTAsn1MemFreeArray(PRTASN1ARRAYALLOCATION pAllocation, void **papvArray); + + +/** Pointer to a core ASN.1 encoding info structure. */ +typedef struct RTASN1CORE *PRTASN1CORE; +/** Pointer to a const core ASN.1 encoding info structure. */ +typedef struct RTASN1CORE const *PCRTASN1CORE; + +RTDECL(int) RTAsn1ContentAllocZ(struct RTASN1CORE *pAsn1Core, size_t cb, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTAsn1ContentDup(struct RTASN1CORE *pAsn1Core, void const *pvSrc, size_t cbSrc, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTAsn1ContentReallocZ(struct RTASN1CORE *pAsn1Core, size_t cb, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(void) RTAsn1ContentFree(struct RTASN1CORE *pAsn1Core); + + + +/** + * ASN.1 object enumeration callback. + * + * @returns IPRT status code. VINF_SUCCESS continues the enumberation, all + * others quit it and is returned to the caller's caller. + * @param pAsn1Core The ASN.1 object we're called back about. + * @param pszName The member name. Array member names ends with + * '[#]'. + * @param uDepth The current depth. + * @param pvUser Callback user parameter. + */ +typedef DECLCALLBACKTYPE(int, FNRTASN1ENUMCALLBACK,(struct RTASN1CORE *pAsn1Core, const char *pszName, uint32_t uDepth, + void *pvUser)); +/** Pointer to an ASN.1 object enumeration callback. */ +typedef FNRTASN1ENUMCALLBACK *PFNRTASN1ENUMCALLBACK; + +/** + * ASN.1 object encoding writer callback. + * + * @returns IPRT status code. + * @param pvBuf Pointer to the bytes to output. + * @param cbToWrite The number of bytes to write. + * @param pvUser Callback user parameter. + * @param pErrInfo Where to store extended error info. Optional. + */ +typedef DECLCALLBACKTYPE(int, FNRTASN1ENCODEWRITER,(const void *pvBuf, size_t cbToWrite, void *pvUser, PRTERRINFO pErrInfo)); +/** Pointer to an ASN.1 encoding writer callback. */ +typedef FNRTASN1ENCODEWRITER *PFNRTASN1ENCODEWRITER; + +/** @name ASN.1 Vtable Method Types + * @{ */ + +/** + * Destructor. + * + * RTAsn1Destroy will first destroy all children by recursive calls to pfnEnum, + * afterwards it will call this method to release any memory or other resources + * associated with this object. The memory backing the object structure shall + * not be freed by this method. + * + * @param pThisCore Pointer to the ASN.1 core to destroy. + */ +typedef DECLCALLBACKTYPE(void, FNRTASN1COREVTDTOR,(PRTASN1CORE pThisCore)); +/** Pointer to a FNRTASN1COREVTDTOR method. */ +typedef FNRTASN1COREVTDTOR *PFNRTASN1COREVTDTOR; + +/** + * Enumerate members (not necessary for primitive objects). + * + * @returns IPRT status code, any non VINF_SUCCESS value stems from pfnCallback. + * @param pThisCore Pointer to the ASN.1 core to enumerate members of. + * @param pfnCallback The callback. + * @param uDepth The depth of this object. Children are at +1. + * @param pvUser Callback user argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTASN1COREVTENUM,(PRTASN1CORE pThisCore, PFNRTASN1ENUMCALLBACK pfnCallback, + uint32_t uDepth, void *pvUser)); +/** Pointer to a FNRTASN1COREVTENUM method. */ +typedef FNRTASN1COREVTENUM *PFNRTASN1COREVTENUM; + +/** + * Clone method. + * + * @param pThisCore Pointer to the ASN.1 core to initialize as a clone + * of pSrcClone. (The caller is responsible for making + * sure there is sufficent space and such.) + * @param pSrcCore The object to clone. + * @param pAllocator The allocator to use. + */ +typedef DECLCALLBACKTYPE(int, FNRTASN1COREVTCLONE,(PRTASN1CORE pThisCore, PCRTASN1CORE pSrcCore, + PCRTASN1ALLOCATORVTABLE pAllocator)); +/** Pointer to a FNRTASN1COREVTCLONE method. */ +typedef FNRTASN1COREVTCLONE *PFNRTASN1COREVTCLONE; + +/** + * Compare method. + * + * The caller makes sure both cores are present and have the same Vtable. + * + * @returns 0 if equal, -1 if @a pLeft is smaller, 1 if @a pLeft is larger. + * @param pLeftCore Pointer to the ASN.1 core of the left side object. + * @param pRightCore Pointer to the ASN.1 core of the right side object. + */ +typedef DECLCALLBACKTYPE(int, FNRTASN1COREVTCOMPARE,(PCRTASN1CORE pLeftCore, PCRTASN1CORE pRightCore)); +/** Pointer to a FNRTASN1COREVTCOMPARE method. */ +typedef FNRTASN1COREVTCOMPARE *PFNRTASN1COREVTCOMPARE; + +/** + * Check sanity method. + * + * @returns IPRT status code. + * @param pThisCore Pointer to the ASN.1 core of the object to check out. + * @param fFlags See RTASN1_CHECK_SANITY_F_XXX. + * @param pErrInfo Where to return additional error details. Optional. + * @param pszErrorTag Tag for the additional error details. + */ +typedef DECLCALLBACKTYPE(int, FNRTASN1COREVTCHECKSANITY,(PCRTASN1CORE pThisCore, uint32_t fFlags, + PRTERRINFO pErrInfo, const char *pszErrorTag)); +/** Pointer to a FNRTASN1COREVTCHECKSANITY method. */ +typedef FNRTASN1COREVTCHECKSANITY *PFNRTASN1COREVTCHECKSANITY; + +/** + * Optional encoding preparations. + * + * On successful return, the pThisCore->cb value shall be valid and up to date. + * Will be called for any present object, including ones with default values and + * similar. + * + * @returns IPRT status code + * @param pThisCore Pointer to the ASN.1 core to enumerate members of. + * @param fFlags Encoding flags, RTASN1ENCODE_F_XXX. + * @param pErrInfo Where to return extra error information. Optional. + */ +typedef DECLCALLBACKTYPE(int, FNRTASN1COREVTENCODEPREP,(PRTASN1CORE pThisCore, uint32_t fFlags, PRTERRINFO pErrInfo)); +/** Pointer to a FNRTASN1COREVTENCODEWRITE method. */ +typedef FNRTASN1COREVTENCODEPREP *PFNRTASN1COREVTENCODEPREP; + +/** + * Optional encoder writer. + * + * This writes the header as well as all the content. Will be called for any + * present object, including ones with default values and similar. + * + * @returns IPRT status code. + * @param pThisCore Pointer to the ASN.1 core to enumerate members of. + * @param fFlags Encoding flags, RTASN1ENCODE_F_XXX. + * @param pfnWriter The output writer function. + * @param pvUser The user context for the writer function. + * @param pErrInfo Where to return extra error information. Optional. + */ +typedef DECLCALLBACKTYPE(int, FNRTASN1COREVTENCODEWRITE,(PRTASN1CORE pThisCore, uint32_t fFlags, PFNRTASN1ENCODEWRITER pfnWriter, + void *pvUser, PRTERRINFO pErrInfo)); +/** Pointer to a FNRTASN1COREVTENCODEWRITE method. */ +typedef FNRTASN1COREVTENCODEWRITE *PFNRTASN1COREVTENCODEWRITE; +/** @} */ + +/** Mask of common flags. These will be propagated during sanity checking. + * Bits not in this mask are type specfic. */ +#define RTASN1_CHECK_SANITY_F_COMMON_MASK UINT32_C(0xffff0000) + +/** + * ASN.1 core vtable. + */ +typedef struct RTASN1COREVTABLE +{ + /** The name. */ + const char *pszName; + /** Size of the structure. */ + uint32_t cbStruct; + /** The default tag, UINT8_MAX if not applicable. */ + uint8_t uDefaultTag; + /** The default class and flags. */ + uint8_t fDefaultClass; + /** Reserved for later / alignment. */ + uint16_t uReserved; + /** @copydoc FNRTASN1COREVTDTOR */ + PFNRTASN1COREVTDTOR pfnDtor; + /** @copydoc FNRTASN1COREVTENUM */ + PFNRTASN1COREVTENUM pfnEnum; + /** @copydoc FNRTASN1COREVTCLONE */ + PFNRTASN1COREVTCLONE pfnClone; + /** @copydoc FNRTASN1COREVTCOMPARE */ + PFNRTASN1COREVTCOMPARE pfnCompare; + /** @copydoc FNRTASN1COREVTCHECKSANITY */ + PFNRTASN1COREVTCHECKSANITY pfnCheckSanity; + /** @copydoc FNRTASN1COREVTENCODEPREP */ + PFNRTASN1COREVTENCODEPREP pfnEncodePrep; + /** @copydoc FNRTASN1COREVTENUM */ + PFNRTASN1COREVTENCODEWRITE pfnEncodeWrite; +} RTASN1COREVTABLE; +/** Pointer to an ASN.1 allocator vtable. */ +typedef struct RTASN1COREVTABLE *PRTASN1COREVTABLE; +/** Pointer to a const ASN.1 allocator vtable. */ +typedef RTASN1COREVTABLE const *PCRTASN1COREVTABLE; + + +/** @name Helper macros for prototyping standard functions for an ASN.1 type. + * @{ */ + +#define RTASN1TYPE_STANDARD_PROTOTYPES_NO_GET_CORE(a_TypeNm, a_DeclMacro, a_ImplExtNm) \ + a_DeclMacro(int) RT_CONCAT(a_ImplExtNm,_Init)(RT_CONCAT(P,a_TypeNm) pThis, PCRTASN1ALLOCATORVTABLE pAllocator); \ + a_DeclMacro(int) RT_CONCAT(a_ImplExtNm,_Clone)(RT_CONCAT(P,a_TypeNm) pThis, RT_CONCAT(PC,a_TypeNm) pSrc, \ + PCRTASN1ALLOCATORVTABLE pAllocator); \ + a_DeclMacro(void) RT_CONCAT(a_ImplExtNm,_Delete)(RT_CONCAT(P,a_TypeNm) pThis); \ + a_DeclMacro(int) RT_CONCAT(a_ImplExtNm,_Enum)(RT_CONCAT(P,a_TypeNm) pThis, PFNRTASN1ENUMCALLBACK pfnCallback, \ + uint32_t uDepth, void *pvUser); \ + a_DeclMacro(int) RT_CONCAT(a_ImplExtNm,_Compare)(RT_CONCAT(PC,a_TypeNm) pLeft, RT_CONCAT(PC,a_TypeNm) pRight); \ + a_DeclMacro(int) RT_CONCAT(a_ImplExtNm,_DecodeAsn1)(PRTASN1CURSOR pCursor, uint32_t fFlags, RT_CONCAT(P,a_TypeNm) pThis,\ + const char *pszErrorTag); \ + a_DeclMacro(int) RT_CONCAT(a_ImplExtNm,_CheckSanity)(RT_CONCAT(PC,a_TypeNm) pThis, uint32_t fFlags, \ + PRTERRINFO pErrInfo, const char *pszErrorTag) + + +#define RTASN1TYPE_STANDARD_PROTOTYPES(a_TypeNm, a_DeclMacro, a_ImplExtNm, a_Asn1CoreNm) \ + DECL_FORCE_INLINE(PRTASN1CORE) RT_CONCAT(a_ImplExtNm,_GetAsn1Core)(RT_CONCAT(PC,a_TypeNm) pThis) \ + { return (PRTASN1CORE)&pThis->a_Asn1CoreNm; } \ + DECLINLINE(bool) RT_CONCAT(a_ImplExtNm,_IsPresent)(RT_CONCAT(PC,a_TypeNm) pThis) \ + { return pThis && RTASN1CORE_IS_PRESENT(&pThis->a_Asn1CoreNm); } \ + RTASN1TYPE_STANDARD_PROTOTYPES_NO_GET_CORE(a_TypeNm, a_DeclMacro, a_ImplExtNm) + + +/** Aliases two ASN.1 types, no method aliases. */ +#define RTASN1TYPE_ALIAS_TYPE_ONLY(a_TypeNm, a_AliasType) \ + typedef a_AliasType a_TypeNm; \ + typedef a_TypeNm *RT_CONCAT(P,a_TypeNm); \ + typedef a_TypeNm const *RT_CONCAT(PC,a_TypeNm) + +/** Aliases two ASN.1 types and methods. */ +#define RTASN1TYPE_ALIAS(a_TypeNm, a_AliasType, a_ImplExtNm, a_AliasExtNm) \ + typedef a_AliasType a_TypeNm; \ + typedef a_TypeNm *RT_CONCAT(P,a_TypeNm); \ + \ + DECLINLINE(PRTASN1CORE) RT_CONCAT(a_ImplExtNm,_GetAsn1Core)(a_TypeNm const *pThis) \ + { return RT_CONCAT(a_AliasExtNm,_GetAsn1Core)(pThis); } \ + DECLINLINE(bool) RT_CONCAT(a_ImplExtNm,_IsPresent)(a_TypeNm const *pThis) \ + { return RT_CONCAT(a_AliasExtNm,_IsPresent)(pThis); } \ + \ + DECLINLINE(int) RT_CONCAT(a_ImplExtNm,_Init)(RT_CONCAT(P,a_TypeNm) pThis, PCRTASN1ALLOCATORVTABLE pAllocator) \ + { return RT_CONCAT(a_AliasExtNm,_Init)(pThis, pAllocator); } \ + DECLINLINE(int) RT_CONCAT(a_ImplExtNm,_Clone)(RT_CONCAT(P,a_TypeNm) pThis, a_TypeNm const *pSrc, \ + PCRTASN1ALLOCATORVTABLE pAllocator) \ + { return RT_CONCAT(a_AliasExtNm,_Clone)(pThis, pSrc, pAllocator); } \ + DECLINLINE(void) RT_CONCAT(a_ImplExtNm,_Delete)(RT_CONCAT(P,a_TypeNm) pThis) \ + { RT_CONCAT(a_AliasExtNm,_Delete)(pThis); } \ + DECLINLINE(int) RT_CONCAT(a_ImplExtNm,_Enum)(a_TypeNm *pThis, PFNRTASN1ENUMCALLBACK pfnCallback, \ + uint32_t uDepth, void *pvUser) \ + { return RT_CONCAT(a_AliasExtNm,_Enum)(pThis, pfnCallback, uDepth, pvUser); } \ + DECLINLINE(int) RT_CONCAT(a_ImplExtNm,_Compare)(a_TypeNm const *pLeft, a_TypeNm const *pRight) \ + { return RT_CONCAT(a_AliasExtNm,_Compare)(pLeft, pRight); } \ + DECLINLINE(int) RT_CONCAT(a_ImplExtNm,_DecodeAsn1)(PRTASN1CURSOR pCursor, uint32_t fFlags, RT_CONCAT(P,a_TypeNm) pThis,\ + const char *pszErrorTag) \ + { return RT_CONCAT(a_AliasExtNm,_DecodeAsn1)(pCursor, fFlags, pThis, pszErrorTag); } \ + DECLINLINE(int) RT_CONCAT(a_ImplExtNm,_CheckSanity)(a_TypeNm const *pThis, uint32_t fFlags, \ + PRTERRINFO pErrInfo, const char *pszErrorTag) \ + { return RT_CONCAT(a_AliasExtNm,_CheckSanity)(pThis, fFlags, pErrInfo, pszErrorTag); } \ + \ + typedef a_TypeNm const *RT_CONCAT(PC,a_TypeNm) + +/** @} */ + + +/** + * Core ASN.1 structure for storing encoding details and data location. + * + * This is used as a 'parent' for all other decoded ASN.1 based structures. + */ +typedef struct RTASN1CORE +{ + /** The tag. + * @remarks 32-bit should be enough for everyone... We don't currently + * implement decoding tags larger than 30 anyway. :-) */ + uint32_t uTag; + /** Tag class and flags (ASN1_TAGCLASS_XXX and ASN1_TAGFLAG_XXX). */ + uint8_t fClass; + /** The real tag value for IMPLICT tag overrides. */ + uint8_t uRealTag; + /** The real class value for IMPLICT tag overrides. */ + uint8_t fRealClass; + /** The size of the tag and length ASN.1 header. */ + uint8_t cbHdr; + /** Length. */ + uint32_t cb; + /** IPRT flags (RTASN1CORE_F_XXX). */ + uint32_t fFlags; + /** Pointer to the data. + * After decoding this generally points to the encoded data content. When + * preparting something for encoding or otherwise constructing things in memory, + * this generally points heap memory or read-only constants. + * @sa RTAsn1ContentAllocZ, RTAsn1ContentReallocZ, RTAsn1ContentDup, + * RTAsn1ContentFree. */ + RTCPTRUNION uData; + /** Pointer to the virtual method table for this object. Optional. */ + PCRTASN1COREVTABLE pOps; +} RTASN1CORE; +/** The Vtable for a RTASN1CORE structure when not in some way use used as a + * parent type/class. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1Core_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES_NO_GET_CORE(RTASN1CORE, RTDECL, RTAsn1Core); + +/** @name RTASN1CORE_F_XXX - Flags for RTASN1CORE::fFlags + * @{ */ +/** Present/valid. */ +#define RTASN1CORE_F_PRESENT RT_BIT_32(0) +/** Not present in stream, using default value. */ +#define RTASN1CORE_F_DEFAULT RT_BIT_32(1) +/** The tag was overriden by an implict context tag or some such thing, + * RTASN1CORE::uImplicitTag hold the universal tag value if one exists. */ +#define RTASN1CORE_F_TAG_IMPLICIT RT_BIT_32(2) +/** Primitive tag with the corresponding RTASN1XXX struct. */ +#define RTASN1CORE_F_PRIMITE_TAG_STRUCT RT_BIT_32(3) +/** Dummy node typically used with choices, has children, not encoded, must be + * ignored. */ +#define RTASN1CORE_F_DUMMY RT_BIT_32(4) +/** Allocated content (pointed to by uData). + * The content should is still be considered 104% read-only by anyone other + * than then type methods (pOps and associates). */ +#define RTASN1CORE_F_ALLOCATED_CONTENT RT_BIT_32(5) +/** Decoded content (pointed to by uData). + * Mutually exclusive with RTASN1CORE_F_ALLOCATED_CONTENT. If neither is + * set, uData might be NULL or point to some shared static memory for + * frequently used values. */ +#define RTASN1CORE_F_DECODED_CONTENT RT_BIT_32(6) +/** Indefinite length, still pending. */ +#define RTASN1CORE_F_INDEFINITE_LENGTH RT_BIT_32(7) +/** @} */ + + +/** Checks whether an ASN.1 core object present in some way (default data, + * decoded data, ...). */ +#define RTASN1CORE_IS_PRESENT(a_pAsn1Core) ( RT_BOOL((a_pAsn1Core)->fFlags) ) + +/** Checks whether an ASN.1 core object is a dummy object (and is present). */ +#define RTASN1CORE_IS_DUMMY(a_pAsn1Core) ( RT_BOOL((a_pAsn1Core)->fFlags & RTASN1CORE_F_DUMMY) ) + +/** + * Calculates pointer to the raw ASN.1 record. + * + * ASSUMES that it's decoded content and that cbHdr and uData are both valid. + * + * @returns Byte pointer to the first tag byte. + * @param a_pAsn1Core The ASN.1 core. + */ +#define RTASN1CORE_GET_RAW_ASN1_PTR(a_pAsn1Core) ( (a_pAsn1Core)->uData.pu8 - (a_pAsn1Core)->cbHdr ) + +/** + * Calculates the length of the raw ASN.1 record to go with the + * RTASN1CORE_GET_RAW_ASN1_PTR() result. + * + * ASSUMES that it's decoded content and that cbHdr and uData are both valid. + * + * @returns Size in bytes (uint32_t). + * @param a_pAsn1Core The ASN.1 core. + */ +#define RTASN1CORE_GET_RAW_ASN1_SIZE(a_pAsn1Core) ( (a_pAsn1Core)->cbHdr + (a_pAsn1Core)->cb ) + +/** + * Retrievs the tag or implicit tag depending on the RTASN1CORE_F_TAG_IMPLICIT + * flag. + * + * @returns The ASN.1 tag of the object. + * @param a_pAsn1Core The ASN.1 core. + */ +#define RTASN1CORE_GET_TAG(a_pAsn1Core) ( !((a_pAsn1Core)->fFlags & RTASN1CORE_F_TAG_IMPLICIT) ? (a_pAsn1Core)->uTag : (a_pAsn1Core)->uRealTag ) + + +DECL_FORCE_INLINE(PRTASN1CORE) RTAsn1Core_GetAsn1Core(PCRTASN1CORE pThis) +{ + return (PRTASN1CORE)pThis; +} + + +DECL_FORCE_INLINE(bool) RTAsn1Core_IsPresent(PCRTASN1CORE pThis) +{ + return pThis && RTASN1CORE_IS_PRESENT(pThis); +} + + +RTDECL(int) RTAsn1Core_InitEx(PRTASN1CORE pAsn1Core, uint32_t uTag, uint8_t fClass, PCRTASN1COREVTABLE pOps, uint32_t fFlags); +/** + * Initialize the ASN.1 core object representation to a default value. + * + * @returns VINF_SUCCESS + * @param pAsn1Core The ASN.1 core. + * @param uTag The tag number. + * @param fClass The tag class and flags. + */ +RTDECL(int) RTAsn1Core_InitDefault(PRTASN1CORE pAsn1Core, uint32_t uTag, uint8_t fClass); +RTDECL(int) RTAsn1Core_CloneContent(PRTASN1CORE pThis, PCRTASN1CORE pSrc, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTAsn1Core_CloneNoContent(PRTASN1CORE pThis, PCRTASN1CORE pSrc); +RTDECL(int) RTAsn1Core_SetTagAndFlags(PRTASN1CORE pAsn1Core, uint32_t uTag, uint8_t fClass); +RTDECL(int) RTAsn1Core_ChangeTag(PRTASN1CORE pAsn1Core, uint32_t uTag); +RTDECL(void) RTAsn1Core_ResetImplict(PRTASN1CORE pThis); +RTDECL(int) RTAsn1Core_CompareEx(PCRTASN1CORE pLeft, PCRTASN1CORE pRight, bool fIgnoreTagAndClass); + + +/** + * Dummy ASN.1 object for use in choices and similar non-sequence structures. + * + * This allows hooking up destructors, enumerators and such, as well as not + * needing custom code for sequence-of / set-of collections. + */ +typedef struct RTASN1DUMMY +{ + /** Core ASN.1. */ + RTASN1CORE Asn1Core; +} RTASN1DUMMY; +/** Pointer to a dummy record. */ +typedef RTASN1DUMMY *PRTASN1DUMMY; + + +/** + * Initalizes a dummy ASN.1 object. + * + * @returns VINF_SUCCESS. + * @param pThis The dummy object. + */ +RTDECL(int) RTAsn1Dummy_InitEx(PRTASN1DUMMY pThis); + +/** + * Standard compliant initalizer. + * + * @returns VINF_SUCCESS. + * @param pThis The dummy object. + * @param pAllocator Ignored. + */ +DECLINLINE(int) RTAsn1Dummy_Init(PRTASN1DUMMY pThis, PCRTASN1ALLOCATORVTABLE pAllocator) +{ + NOREF(pAllocator); + return RTAsn1Dummy_InitEx(pThis); +} + + +/** + * ASN.1 sequence core (IPRT representation). + */ +typedef struct RTASN1SEQUENCECORE +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; +} RTASN1SEQUENCECORE; +/** Pointer to an ASN.1 sequence core (IPRT representation). */ +typedef RTASN1SEQUENCECORE *PRTASN1SEQUENCECORE; +/** Pointer to a const ASN.1 sequence core (IPRT representation). */ +typedef RTASN1SEQUENCECORE const *PCRTASN1SEQUENCECORE; + +RTDECL(int) RTAsn1SequenceCore_Init(PRTASN1SEQUENCECORE pSeqCore, PCRTASN1COREVTABLE pVtable); +RTDECL(int) RTAsn1SequenceCore_Clone(PRTASN1SEQUENCECORE pSeqCore, PCRTASN1COREVTABLE pVtable, PCRTASN1SEQUENCECORE pSrc); + +/** + * ASN.1 sequence-of core (IPRT representation). + */ +#if 0 +typedef struct RTASN1SEQOFCORE +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; +} RTASN1SEQUENCECORE; +/** Pointer to an ASN.1 sequence-of core (IPRT representation). */ +typedef RTASN1SEQUENCECORE *PRTASN1SEQUENCECORE; +/** Pointer to a const ASN.1 sequence-of core (IPRT representation). */ +typedef RTASN1SEQUENCECORE const *PCRTASN1SEQUENCECORE; +#else +# define RTASN1SEQOFCORE RTASN1SEQUENCECORE +# define PRTASN1SEQOFCORE PRTASN1SEQUENCECORE +# define PCRTASN1SEQOFCORE PCRTASN1SEQUENCECORE +#endif +RTDECL(int) RTAsn1SeqOfCore_Init(PRTASN1SEQOFCORE pThis, PCRTASN1COREVTABLE pVtable); +RTDECL(int) RTAsn1SeqOfCore_Clone(PRTASN1SEQOFCORE pThis, PCRTASN1COREVTABLE pVtable, PCRTASN1SEQOFCORE pSrc); + + +/** Defines the typedefs and prototypes for a generic sequence-of/set-of type. */ +#define RTASN1_IMPL_GEN_SEQ_OR_SET_OF_TYPEDEFS_AND_PROTOS(a_CoreType, a_CoreMember, \ + a_ThisType, a_ItemType, a_DeclMacro, a_ImplExtNm) \ + typedef struct a_ThisType \ + { \ + /** Sequence/set core. */ \ + a_CoreType a_CoreMember; \ + /** The array allocation tracker. */ \ + RTASN1ARRAYALLOCATION Allocation; \ + /** Items in the array. */ \ + uint32_t cItems; \ + /** Array. */ \ + RT_CONCAT(P,a_ItemType) *papItems; \ + } a_ThisType; \ + typedef a_ThisType *RT_CONCAT(P,a_ThisType); \ + typedef a_ThisType const *RT_CONCAT(PC,a_ThisType); \ + a_DeclMacro(int) RT_CONCAT(a_ImplExtNm,_Erase)(RT_CONCAT(P,a_ThisType) pThis, uint32_t iPosition); \ + a_DeclMacro(int) RT_CONCAT(a_ImplExtNm,_InsertEx)(RT_CONCAT(P,a_ThisType) pThis, uint32_t iPosition, \ + RT_CONCAT(PC,a_ItemType) pToClone, \ + PCRTASN1ALLOCATORVTABLE pAllocator, uint32_t *piActualPos); \ + /** Appends entry with default content, returns index or negative error code. */ \ + DECLINLINE(int32_t) RT_CONCAT(a_ImplExtNm,_Append)(RT_CONCAT(P,a_ThisType) pThis) \ + { \ + uint32_t uPos = pThis->cItems; \ + int rc = RT_CONCAT(a_ImplExtNm,_InsertEx)(pThis, uPos, NULL /*pToClone*/, pThis->Allocation.pAllocator, &uPos); \ + if (RT_SUCCESS(rc)) \ + return (int32_t)uPos; \ + return rc; \ + } \ + RTASN1TYPE_STANDARD_PROTOTYPES(a_ThisType, a_DeclMacro, a_ImplExtNm, a_CoreMember.Asn1Core) + +/** Defines the typedefs and prototypes for a generic sequence-of type. */ +#define RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(a_SeqOfType, a_ItemType, a_DeclMacro, a_ImplExtNm) \ + RTASN1_IMPL_GEN_SEQ_OR_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQUENCECORE, SeqCore, a_SeqOfType, a_ItemType, a_DeclMacro, a_ImplExtNm) + + +/** + * ASN.1 set core (IPRT representation). + */ +typedef struct RTASN1SETCORE +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; +} RTASN1SETCORE; +/** Pointer to an ASN.1 set core (IPRT representation). */ +typedef RTASN1SETCORE *PRTASN1SETCORE; +/** Pointer to a const ASN.1 set core (IPRT representation). */ +typedef RTASN1SETCORE const *PCRTASN1SETCORE; + +RTDECL(int) RTAsn1SetCore_Init(PRTASN1SETCORE pThis, PCRTASN1COREVTABLE pVtable); +RTDECL(int) RTAsn1SetCore_Clone(PRTASN1SETCORE pThis, PCRTASN1COREVTABLE pVtable, PCRTASN1SETCORE pSrc); + +/** + * ASN.1 set-of core (IPRT representation). + */ +#if 0 +typedef struct RTASN1SETOFCORE +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; +} RTASN1SETUENCECORE; +/** Pointer to an ASN.1 set-of core (IPRT representation). */ +typedef RTASN1SETUENCECORE *PRTASN1SETUENCECORE; +/** Pointer to a const ASN.1 set-of core (IPRT representation). */ +typedef RTASN1SETUENCECORE const *PCRTASN1SETUENCECORE; +#else +# define RTASN1SETOFCORE RTASN1SETCORE +# define PRTASN1SETOFCORE PRTASN1SETCORE +# define PCRTASN1SETOFCORE PCRTASN1SETCORE +#endif +RTDECL(int) RTAsn1SetOfCore_Init(PRTASN1SETOFCORE pThis, PCRTASN1COREVTABLE pVtable); +RTDECL(int) RTAsn1SetOfCore_Clone(PRTASN1SETOFCORE pThis, PCRTASN1COREVTABLE pVtable, PCRTASN1SETOFCORE pSrc); + + +/** Defines the typedefs and prototypes for a generic set-of type. */ +#define RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(a_SetOfType, a_ItemType, a_DeclMacro, a_ImplExtNm) \ + RTASN1_IMPL_GEN_SEQ_OR_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETCORE, SetCore, a_SetOfType, a_ItemType, a_DeclMacro, a_ImplExtNm) + + +/* + * Declare sets and sequences of the core structure. + */ +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQOFCORES, RTASN1CORE, RTDECL, RTAsn1SeqOfCores); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFCORES, RTASN1CORE, RTDECL, RTAsn1SetOfCores); + + +/** + * ASN.1 null (IPRT representation). + */ +typedef struct RTASN1NULL +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; +} RTASN1NULL; +/** Pointer to an ASN.1 null (IPRT representation). */ +typedef RTASN1NULL *PRTASN1NULL; +/** Pointer to a const ASN.1 null (IPRT representation). */ +typedef RTASN1NULL const *PCRTASN1NULL; +/** The Vtable for a RTASN1NULL structure. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1Null_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1NULL, RTDECL, RTAsn1Null, Asn1Core); + + +/** + * ASN.1 integer (IPRT representation). + */ +typedef struct RTASN1INTEGER +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; + /** The unsigned C representation of the 64 least significant bits. + * @note A ASN.1 integer doesn't define signed/unsigned and can have any + * length you like. Thus, the user needs to check the size and + * preferably use the access APIs for signed numbers. */ + RTUINT64U uValue; +} RTASN1INTEGER; +/** Pointer to an ASN.1 integer (IPRT representation). */ +typedef RTASN1INTEGER *PRTASN1INTEGER; +/** Pointer to a const ASN.1 integer (IPRT representation). */ +typedef RTASN1INTEGER const *PCRTASN1INTEGER; +/** The Vtable for a RTASN1INTEGER structure. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1Integer_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1INTEGER, RTDECL, RTAsn1Integer, Asn1Core); + +/** + * Initializes an interger object to a default value. + * @returns VINF_SUCCESS. + * @param pInteger The integer object representation. + * @param uValue The default value (unsigned 64-bit). + * @param pAllocator The allocator (pro forma). + */ +RTDECL(int) RTAsn1Integer_InitDefault(PRTASN1INTEGER pInteger, uint64_t uValue, PCRTASN1ALLOCATORVTABLE pAllocator); + +RTDECL(int) RTAsn1Integer_InitU64(PRTASN1INTEGER pThis, uint64_t uValue, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Get the most significat bit that's set (1). + * + * @returns 0-base bit number, -1 if all clear. + * @param pInteger The integer to check. + */ +RTDECL(int32_t) RTAsn1Integer_UnsignedLastBit(PCRTASN1INTEGER pInteger); + +/** + * Compares two ASN.1 unsigned integers. + * + * @returns 0 if equal, -1 if @a pLeft is smaller, 1 if @a pLeft is larger. + * @param pLeft The first ASN.1 integer. + * @param pRight The second ASN.1 integer. + */ +RTDECL(int) RTAsn1Integer_UnsignedCompare(PCRTASN1INTEGER pLeft, PCRTASN1INTEGER pRight); + +/** + * Compares an ASN.1 unsigned integer with a uint64_t. + * + * @returns 0 if equal, -1 if @a pInteger is smaller, 1 if @a pInteger is + * larger. + * @param pInteger The ASN.1 integer to treat as unsigned. + * @param u64Const The uint64_t constant to compare with. + */ +RTDECL(int) RTAsn1Integer_UnsignedCompareWithU64(PCRTASN1INTEGER pInteger, uint64_t u64Const); + +/** + * Compares an ASN.1 unsigned integer with a uint32_t. + * + * @returns 0 if equal, -1 if @a pInteger is smaller, 1 if @a pInteger is + * larger. + * @param pInteger The ASN.1 integer to treat as unsigned. + * @param u32Const The uint32_t constant to compare with. + * @remarks We don't bother with U16 and U8 variants, just use this instead. + */ +RTDECL(int) RTAsn1Integer_UnsignedCompareWithU32(PCRTASN1INTEGER pInteger, uint32_t u32Const); + + +/** + * Initializes a big integer number from an ASN.1 integer. + * + * @returns IPRT status code. + * @param pInteger The ASN.1 integer. + * @param pBigNum The big integer number structure to initialize. + * @param fBigNumInit Subset of RTBIGNUMINIT_F_XXX that concerns + * senitivity, signedness and endianness. + */ +RTDECL(int) RTAsn1Integer_ToBigNum(PCRTASN1INTEGER pInteger, PRTBIGNUM pBigNum, uint32_t fBigNumInit); +RTDECL(int) RTAsn1Integer_FromBigNum(PRTASN1INTEGER pThis, PCRTBIGNUM pBigNum, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Converts the integer to a string. + * + * This will produce a hex represenation of the number. If it fits in 64-bit, a + * C style hex number will be produced. If larger than 64-bit, it will be + * printed as a space separated string of hex bytes. + * + * @returns IPRT status code. + * @param pThis The ASN.1 integer. + * @param pszBuf The output buffer. + * @param cbBuf The buffer size. + * @param fFlags Flags reserved for future exploits. MBZ. + * @param pcbActual Where to return the amount of buffer space used + * (i.e. including terminator). Optional. + * + * @remarks Currently assume unsigned number. + */ +RTDECL(int) RTAsn1Integer_ToString(PCRTASN1INTEGER pThis, char *pszBuf, size_t cbBuf, uint32_t fFlags, size_t *pcbActual); + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQOFINTEGERS, RTASN1INTEGER, RTDECL, RTAsn1SeqOfIntegers); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFINTEGERS, RTASN1INTEGER, RTDECL, RTAsn1SetOfIntegers); + + + +/** + * ASN.1 boolean (IPRT representation). + */ +typedef struct RTASN1BOOLEAN +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; + /** The boolean value. */ + bool fValue; +} RTASN1BOOLEAN; +/** Pointer to the IPRT representation of an ASN.1 boolean. */ +typedef RTASN1BOOLEAN *PRTASN1BOOLEAN; +/** Pointer to the const IPRT representation of an ASN.1 boolean. */ +typedef RTASN1BOOLEAN const *PCRTASN1BOOLEAN; +/** The Vtable for a RTASN1BOOLEAN structure. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1Boolean_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1BOOLEAN, RTDECL, RTAsn1Boolean, Asn1Core); + +/** + * Initializes a boolean object to a default value. + * @returns VINF_SUCCESS + * @param pBoolean The boolean object representation. + * @param fValue The default value. + * @param pAllocator The allocator (pro forma). + */ +RTDECL(int) RTAsn1Boolean_InitDefault(PRTASN1BOOLEAN pBoolean, bool fValue, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTAsn1Boolean_Set(PRTASN1BOOLEAN pThis, bool fValue); + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQOFBOOLEANS, RTASN1BOOLEAN, RTDECL, RTAsn1SeqOfBooleans); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFBOOLEANS, RTASN1BOOLEAN, RTDECL, RTAsn1SetOfBooleans); + + + +/** + * ASN.1 UTC and Generalized Time (IPRT representation). + * + * The two time types only differs in the precision the render (UTC time being + * the one for which you go "WTF were they thinking?!!" for in 2014). + */ +typedef struct RTASN1TIME +{ + /** The core structure, either ASN1_TAG_UTC_TIME or + * ASN1_TAG_GENERALIZED_TIME. */ + RTASN1CORE Asn1Core; + /** The exploded time. */ + RTTIME Time; +} RTASN1TIME; +/** Pointer to an IPRT representation of ASN.1 UTC/Generalized time. */ +typedef RTASN1TIME *PRTASN1TIME; +/** Pointer to a const IPRT representation of ASN.1 UTC/Generalized time. */ +typedef RTASN1TIME const *PCRTASN1TIME; +/** The Vtable for a RTASN1TIME structure. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1Time_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1TIME, RTDECL, RTAsn1Time, Asn1Core); + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1TIME, RTDECL, RTAsn1UtcTime, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1TIME, RTDECL, RTAsn1GeneralizedTime, Asn1Core); + +/** + * Compares two ASN.1 time values. + * + * @returns 0 if equal, -1 if @a pLeft is smaller, 1 if @a pLeft is larger. + * @param pLeft The first ASN.1 time object. + * @param pTsRight The second time to compare. + */ +RTDECL(int) RTAsn1Time_CompareWithTimeSpec(PCRTASN1TIME pLeft, PCRTTIMESPEC pTsRight); + +/** + * Extended init function that lets you select the kind of time object (UTC or + * generalized). + */ +RTDECL(int) RTAsn1Time_InitEx(PRTASN1TIME pThis, uint32_t uTag, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Combines RTAsn1Time_InitEx() and RTAsn1Time_SetTime(). + */ +RTDECL(int) RTAsn1Time_InitWithTime(PRTASN1TIME pThis, uint32_t uTag, PCRTASN1ALLOCATORVTABLE pAllocator, PCRTTIME pTime); + +/** + * Sets the ASN.1 time value to @a pTime. + * + * @returns IPRT status code. + * @param pThis The ASN.1 time object to modify. + * @param pAllocator The allocator to use. + * @param pTime The time to set. + */ +RTDECL(int) RTAsn1Time_SetTime(PRTASN1TIME pThis, PCRTASN1ALLOCATORVTABLE pAllocator, PCRTTIME pTime); + +/** + * Sets the ASN.1 time value to @a pTimeSpec. + * + * @returns IPRT status code. + * @param pThis The ASN.1 time object to modify. + * @param pAllocator The allocator to use. + * @param pTimeSpec The time to set. + */ +RTDECL(int) RTAsn1Time_SetTimeSpec(PRTASN1TIME pThis, PCRTASN1ALLOCATORVTABLE pAllocator, PCRTTIMESPEC pTimeSpec); + +/** @name Predicate macros for determing the exact type of RTASN1TIME. + * @{ */ +/** True if UTC time. */ +#define RTASN1TIME_IS_UTC_TIME(a_pAsn1Time) ((a_pAsn1Time)->Asn1Core.uTag == ASN1_TAG_UTC_TIME) +/** True if generalized time. */ +#define RTASN1TIME_IS_GENERALIZED_TIME(a_pAsn1Time) ((a_pAsn1Time)->Asn1Core.uTag == ASN1_TAG_GENERALIZED_TIME) +/** @} */ + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQOFTIMES, RTASN1TIME, RTDECL, RTAsn1SeqOfTimes); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFTIMES, RTASN1TIME, RTDECL, RTAsn1SetOfTimes); + + + +/** + * ASN.1 object identifier (IPRT representation). + */ +typedef struct RTASN1OBJID +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; + /** Coverning the paComponents memory allocation if there isn't enough room in + * szObjId for both the dottet string and the component values. */ + RTASN1ALLOCATION Allocation; + /** Pointer to an array with the component values. + * This may point within szObjId if there is enough space for both there. */ + uint32_t const *pauComponents; + /** The number of components in the object identifier. + * This ASSUMES that nobody will be ever needing more than 255 components. */ + uint8_t cComponents; + /** The dotted string representation of the object identifier. + * If there is sufficient space after the string, we will place the array that + * paComponents points to here and/or the raw content bytes (Asn1Core.uData). + * + * An analysis of dumpasn1.cfg, hl7.org and our own _OID defines indicates + * that we need space for at least 10 components and 30-something chars. We've + * allocated 87 bytes, which we ASSUME should be enough for everyone. */ + char szObjId[87]; +} RTASN1OBJID; +/** Pointer to an ASN.1 object identifier representation. */ +typedef RTASN1OBJID *PRTASN1OBJID; +/** Pointer to a const ASN.1 object identifier representation. */ +typedef RTASN1OBJID const *PCRTASN1OBJID; +/** The Vtable for a RTASN1OBJID structure. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1ObjId_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1OBJID, RTDECL, RTAsn1ObjId, Asn1Core); + +RTDECL(int) RTAsn1ObjId_InitFromString(PRTASN1OBJID pThis, const char *pszObjId, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTAsn1ObjId_SetFromString(PRTASN1OBJID pThis, const char *pszObjId, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Compares an ASN.1 object identifier with a dotted object identifier string. + * + * @returns 0 if equal, -1 if @a pLeft is smaller, 1 if @a pLeft is larger. + * @param pThis The ASN.1 object identifier. + * @param pszRight The dotted object identifier string. + */ +RTDECL(int) RTAsn1ObjId_CompareWithString(PCRTASN1OBJID pThis, const char *pszRight); + +/** + * Checks if an ASN.1 object identifier starts with the given dotted object + * identifier string. + * + * The matching is only successful if the given string matches matches the last + * component completely. + * + * @returns true / false. + * @param pThis The ASN.1 object identifier. + * @param pszStartsWith The dotted object identifier string. + */ +RTDECL(bool) RTAsn1ObjId_StartsWith(PCRTASN1OBJID pThis, const char *pszStartsWith); + +RTDECL(uint8_t) RTAsn1ObjIdCountComponents(PCRTASN1OBJID pThis); +RTDECL(uint32_t) RTAsn1ObjIdGetComponentsAsUInt32(PCRTASN1OBJID pThis, uint8_t iComponent); +RTDECL(uint32_t) RTAsn1ObjIdGetLastComponentsAsUInt32(PCRTASN1OBJID pThis); + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQOFOBJIDS, RTASN1OBJID, RTDECL, RTAsn1SeqOfObjIds); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFOBJIDS, RTASN1OBJID, RTDECL, RTAsn1SetOfObjIds); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFOBJIDSEQS, RTASN1SEQOFOBJIDS, RTDECL, RTAsn1SetOfObjIdSeqs); + + +/** + * ASN.1 bit string (IPRT representation). + */ +typedef struct RTASN1BITSTRING +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; + /** The number of bits. */ + uint32_t cBits; + /** The max number of bits (given at decoding / construction). */ + uint32_t cMaxBits; + /** Pointer to the bits. */ + RTCPTRUNION uBits; + /** Pointer to user structure encapsulated in this string, if dynamically + * allocated the EncapsulatedAllocation member can be used to track it and + * trigger automatic cleanup on object destruction. If EncapsulatedAllocation + * is zero, any object pointed to will only be deleted. */ + PRTASN1CORE pEncapsulated; + /** Allocation tracking structure for pEncapsulated. */ + RTASN1ALLOCATION EncapsulatedAllocation; +} RTASN1BITSTRING; +/** Pointer to the IPRT representation of an ASN.1 bit string. */ +typedef RTASN1BITSTRING *PRTASN1BITSTRING; +/** Pointer to the const IPRT representation of an ASN.1 bit string. */ +typedef RTASN1BITSTRING const *PCRTASN1BITSTRING; +/** The Vtable for a RTASN1BITSTRING structure. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1BitString_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1BITSTRING, RTDECL, RTAsn1BitString, Asn1Core); + +/** + * Calculates pointer to the first bit. + * + * @returns Byte pointer to the first bit. + * @param a_pBitString The ASN.1 bit string. + */ +#define RTASN1BITSTRING_GET_BIT0_PTR(a_pBitString) ( &(a_pBitString)->Asn1Core.uData.pu8[1] ) + +/** + * Calculates the size in bytes. + * + * @returns Rounded up size in bytes. + * @param a_pBitString The ASN.1 bit string. + */ +#define RTASN1BITSTRING_GET_BYTE_SIZE(a_pBitString) ( ((a_pBitString)->cBits + 7U) >> 3 ) + +RTDECL(int) RTAsn1BitString_InitWithData(PRTASN1BITSTRING pThis, void const *pvSrc, uint32_t cSrcBits, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTAsn1BitString_DecodeAsn1Ex(PRTASN1CURSOR pCursor, uint32_t fFlags, uint32_t cMaxBits, PRTASN1BITSTRING pThis, + const char *pszErrorTag); +RTDECL(uint64_t) RTAsn1BitString_GetAsUInt64(PCRTASN1BITSTRING pThis); +RTDECL(int) RTAsn1BitString_RefreshContent(PRTASN1BITSTRING pThis, uint32_t fFlags, + PCRTASN1ALLOCATORVTABLE pAllocator, PRTERRINFO pErrInfo); +RTDECL(bool) RTAsn1BitString_AreContentBitsValid(PCRTASN1BITSTRING pThis, uint32_t fFlags); + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQOFBITSTRINGS, RTASN1BITSTRING, RTDECL, RTAsn1SeqOfBitStrings); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFBITSTRINGS, RTASN1BITSTRING, RTDECL, RTAsn1SetOfBitStrings); + + +/** + * ASN.1 octet string (IPRT representation). + */ +typedef struct RTASN1OCTETSTRING +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; + /** Pointer to user structure encapsulated in this string. + * + * If dynamically allocated the EncapsulatedAllocation member can be used to + * track it and trigger automatic cleanup on object destruction. If + * EncapsulatedAllocation is zero, any object pointed to will only be + * deleted. */ + PRTASN1CORE pEncapsulated; + /** Allocation tracking structure for pEncapsulated. */ + RTASN1ALLOCATION EncapsulatedAllocation; +} RTASN1OCTETSTRING; +/** Pointer to the IPRT representation of an ASN.1 octet string. */ +typedef RTASN1OCTETSTRING *PRTASN1OCTETSTRING; +/** Pointer to the const IPRT representation of an ASN.1 octet string. */ +typedef RTASN1OCTETSTRING const *PCRTASN1OCTETSTRING; +/** The Vtable for a RTASN1OCTETSTRING structure. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1OctetString_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1OCTETSTRING, RTDECL, RTAsn1OctetString, Asn1Core); + +RTDECL(int) RTAsn1OctetString_AllocContent(PRTASN1OCTETSTRING pThis, void const *pvSrc, size_t cb, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTAsn1OctetString_SetContent(PRTASN1OCTETSTRING pThis, void const *pvSrc, size_t cbSrc, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(bool) RTAsn1OctetString_AreContentBytesValid(PCRTASN1OCTETSTRING pThis, uint32_t fFlags); +RTDECL(int) RTAsn1OctetString_RefreshContent(PRTASN1OCTETSTRING pThis, uint32_t fFlags, + PCRTASN1ALLOCATORVTABLE pAllocator, PRTERRINFO pErrInfo); + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQOFOCTETSTRINGS, RTASN1OCTETSTRING, RTDECL, RTAsn1SeqOfOctetStrings); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFOCTETSTRINGS, RTASN1OCTETSTRING, RTDECL, RTAsn1SetOfOctetStrings); + + +/** + * ASN.1 string (IPRT representation). + * All char string types except 'character string (29)'. + */ +typedef struct RTASN1STRING +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; + /** Allocation tracking for pszUtf8. */ + RTASN1ALLOCATION Allocation; + /** If conversion to UTF-8 was requested, we cache that here. */ + char const *pszUtf8; + /** The length (chars, not code points) of the above UTF-8 string if + * present. */ + uint32_t cchUtf8; +} RTASN1STRING; +/** Pointer to the IPRT representation of an ASN.1 string. */ +typedef RTASN1STRING *PRTASN1STRING; +/** Pointer to the const IPRT representation of an ASN.1 string. */ +typedef RTASN1STRING const *PCRTASN1STRING; +/** The Vtable for a RTASN1STRING structure. */ +extern RTDATADECL(RTASN1COREVTABLE const) g_RTAsn1String_Vtable; + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1String, Asn1Core); + +/** @name String type predicate macros. + * @{ */ +#define RTASN1STRING_IS_NUMERIC(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_NUMERIC_STRING ) +#define RTASN1STRING_IS_PRINTABLE(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_PRINTABLE_STRING ) +#define RTASN1STRING_IS_T61(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_T61_STRING ) +#define RTASN1STRING_IS_VIDEOTEX(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_VIDEOTEX_STRING ) +#define RTASN1STRING_IS_VISIBLE(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_VISIBLE_STRING ) +#define RTASN1STRING_IS_IA5(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_IA5_STRING ) +#define RTASN1STRING_IS_GRAPHIC(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_GRAPHIC_STRING ) +#define RTASN1STRING_IS_GENERAL(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_GENERAL_STRING ) +/** UTF-8. */ +#define RTASN1STRING_IS_UTF8(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_UTF8_STRING ) +/** UCS-2. */ +#define RTASN1STRING_IS_BMP(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_BMP_STRING ) +/** UCS-4. */ +#define RTASN1STRING_IS_UNIVERSAL(a_pAsn1String) ( RTASN1CORE_GET_TAG(&(a_pAsn1String)->Asn1Core) == ASN1_TAG_UNIVERSAL_STRING ) +/** @} */ + +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1NumericString, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1PrintableString, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1T61String, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1VideoTexString, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1VisibleString, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1Ia5String, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1GraphicString, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1GeneralString, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1Utf8String, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1BmpString, Asn1Core); +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1STRING, RTDECL, RTAsn1UniversalString, Asn1Core); + +RTDECL(int) RTAsn1String_InitWithValue(PRTASN1STRING pThis, const char *pszUtf8Value, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTAsn1String_InitEx(PRTASN1STRING pThis, uint32_t uTag, void const *pvValue, size_t cbValue, + PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Compares two strings values, extended version. + * + * @returns 0 if equal, -1 if @a pLeft is smaller, 1 if @a pLeft is larger. + * @param pLeft The first string. + * @param pRight The second string. + * @param fTypeToo Set if the string types must match, false if + * not. + */ +RTDECL(int) RTAsn1String_CompareEx(PCRTASN1STRING pLeft, PCRTASN1STRING pRight, bool fTypeToo); +RTDECL(int) RTAsn1String_CompareValues(PCRTASN1STRING pLeft, PCRTASN1STRING pRight); + +/** + * Compares a ASN.1 string object with an UTF-8 string. + * + * @returns 0 if equal, -1 if @a pThis is smaller, 1 if @a pThis is larger. + * @param pThis The ASN.1 string object. + * @param pszString The UTF-8 string. + * @param cchString The length of @a pszString, or RTSTR_MAX. + */ +RTDECL(int) RTAsn1String_CompareWithString(PCRTASN1STRING pThis, const char *pszString, size_t cchString); + +/** + * Queries the UTF-8 length of an ASN.1 string object. + * + * This differs from RTAsn1String_QueryUtf8 in that it won't need to allocate + * memory for the converted string, but just calculates the length. + * + * @returns IPRT status code. + * @param pThis The ASN.1 string object. + * @param pcch Where to return the string length. + */ +RTDECL(int) RTAsn1String_QueryUtf8Len(PCRTASN1STRING pThis, size_t *pcch); + +/** + * Queries the UTF-8 string for an ASN.1 string object. + * + * This may fail as it may require memory to be allocated for storing the + * string. + * + * @returns IPRT status code. + * @param pString The ASN.1 string object. This is a const + * parameter for making life easier on the caller, + * however be aware that the object may be modified + * by this call! + * @param ppsz Where to return the pointer to the UTF-8 string. + * Optional. + * @param pcch Where to return the length (in 8-bit chars) to + * of the UTF-8 string. Optional. + */ +RTDECL(int) RTAsn1String_QueryUtf8(PCRTASN1STRING pString, const char **ppsz, size_t *pcch); +RTDECL(int) RTAsn1String_RecodeAsUtf8(PRTASN1STRING pThis, PCRTASN1ALLOCATORVTABLE pAllocator); + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTASN1SEQOFSTRINGS, RTASN1STRING, RTDECL, RTAsn1SeqOfStrings); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTASN1SETOFSTRINGS, RTASN1STRING, RTDECL, RTAsn1SetOfStrings); + + + +/** + * ASN.1 generic context specific tag (IPRT representation). + * + * Normally used to tag something that's optional, version specific or such. + * + * For the purpose of documenting the format with typedefs as well as possibly + * making it a little more type safe, there's a set of typedefs for the most + * commonly used tag values defined. These typedefs have are identical to + * RTASN1CONTEXTTAG, except from the C++ type system point of view. + */ +typedef struct RTASN1CONTEXTTAG +{ + /** Core ASN.1 encoding details. */ + RTASN1CORE Asn1Core; +} RTASN1CONTEXTTAG; +/** Pointer to an ASN.1 context tag (IPRT thing). */ +typedef RTASN1CONTEXTTAG *PRTASN1CONTEXTTAG; +/** Pointer to a const ASN.1 context tag (IPRT thing). */ +typedef RTASN1CONTEXTTAG const *PCRTASN1CONTEXTTAG; + +RTDECL(int) RTAsn1ContextTagN_Init(PRTASN1CONTEXTTAG pThis, uint32_t uTag, PCRTASN1COREVTABLE pVtable); +RTDECL(int) RTAsn1ContextTagN_Clone(PRTASN1CONTEXTTAG pThis, PCRTASN1CONTEXTTAG pSrc, uint32_t uTag); + + +/** @internal */ +#define RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(a_uTag) \ + typedef struct RT_CONCAT(RTASN1CONTEXTTAG,a_uTag) { RTASN1CORE Asn1Core; } RT_CONCAT(RTASN1CONTEXTTAG,a_uTag); \ + typedef RT_CONCAT(RTASN1CONTEXTTAG,a_uTag) *RT_CONCAT(PRTASN1CONTEXTTAG,a_uTag); \ + DECLINLINE(int) RT_CONCAT3(RTAsn1ContextTag,a_uTag,_Init)(RT_CONCAT(PRTASN1CONTEXTTAG,a_uTag) pThis, \ + PCRTASN1COREVTABLE pVtable, PCRTASN1ALLOCATORVTABLE pAllocator) \ + { \ + NOREF(pAllocator); \ + return RTAsn1ContextTagN_Init((PRTASN1CONTEXTTAG)pThis, a_uTag, pVtable); \ + } \ + DECLINLINE(int) RT_CONCAT3(RTAsn1ContextTag,a_uTag,_Clone)(RT_CONCAT(PRTASN1CONTEXTTAG,a_uTag) pThis, \ + RT_CONCAT(RTASN1CONTEXTTAG,a_uTag) const *pSrc) \ + { return RTAsn1ContextTagN_Clone((PRTASN1CONTEXTTAG)pThis, (PCRTASN1CONTEXTTAG)pSrc, a_uTag); } \ + typedef RT_CONCAT(RTASN1CONTEXTTAG,a_uTag) const *RT_CONCAT(PCRTASN1CONTEXTTAG,a_uTag) +RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(0); +RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(1); +RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(2); +RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(3); +RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(4); +RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(5); +RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(6); +RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE(7); +#undef RTASN1CONTEXTTAG_DO_TYPEDEF_AND_INLINE + +/** Helper for comparing optional context tags. + * This will return if both are not present or if their precense differs. + * @internal */ +#define RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, a_uTag) \ + do { \ + /* type checks */ \ + RT_CONCAT(PCRTASN1CONTEXTTAG,a_uTag) const pMyLeftInternal = (a_pLeft); \ + RT_CONCAT(PCRTASN1CONTEXTTAG,a_uTag) const pMyRightInternal = (a_pRight); \ + (a_iDiff) = (int)RTASN1CORE_IS_PRESENT(&pMyLeftInternal->Asn1Core) \ + - (int)RTASN1CORE_IS_PRESENT(&pMyRightInternal->Asn1Core); \ + if ((a_iDiff) || !RTASN1CORE_IS_PRESENT(&pMyLeftInternal->Asn1Core)) return iDiff; \ + } while (0) + +/** @name Helpers for comparing optional context tags. + * This will return if both are not present or if their precense differs. + * @{ */ +#define RTASN1CONTEXTTAG0_COMPARE_PRESENT_RETURN(a_iDiff, a_pLeft, a_pRight) RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, 0) +#define RTASN1CONTEXTTAG1_COMPARE_PRESENT_RETURN(a_iDiff, a_pLeft, a_pRight) RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, 1) +#define RTASN1CONTEXTTAG2_COMPARE_PRESENT_RETURN(a_iDiff, a_pLeft, a_pRight) RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, 2) +#define RTASN1CONTEXTTAG3_COMPARE_PRESENT_RETURN(a_iDiff, a_pLeft, a_pRight) RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, 3) +#define RTASN1CONTEXTTAG4_COMPARE_PRESENT_RETURN(a_iDiff, a_pLeft, a_pRight) RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, 4) +#define RTASN1CONTEXTTAG5_COMPARE_PRESENT_RETURN(a_iDiff, a_pLeft, a_pRight) RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, 5) +#define RTASN1CONTEXTTAG6_COMPARE_PRESENT_RETURN(a_iDiff, a_pLeft, a_pRight) RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, 6) +#define RTASN1CONTEXTTAG7_COMPARE_PRESENT_RETURN(a_iDiff, a_pLeft, a_pRight) RTASN1CONTEXTTAG_COMPARE_PRESENT_RETURN_INTERNAL(a_iDiff, a_pLeft, a_pRight, 7) +/** @} */ + + +/** + * Type information for dynamically bits (see RTASN1DYNTYPE). + */ +typedef enum RTASN1TYPE +{ + /** Not present. */ + RTASN1TYPE_NOT_PRESENT = 0, + /** Generic ASN.1 for unknown tag/class. */ + RTASN1TYPE_CORE, + /** ASN.1 NULL. */ + RTASN1TYPE_NULL, + /** ASN.1 integer. */ + RTASN1TYPE_INTEGER, + /** ASN.1 boolean. */ + RTASN1TYPE_BOOLEAN, + /** ASN.1 character string. */ + RTASN1TYPE_STRING, + /** ASN.1 octet string. */ + RTASN1TYPE_OCTET_STRING, + /** ASN.1 bite string. */ + RTASN1TYPE_BIT_STRING, + /** ASN.1 UTC or Generalize time. */ + RTASN1TYPE_TIME, +#if 0 + /** ASN.1 sequence core. */ + RTASN1TYPE_SEQUENCE_CORE, + /** ASN.1 set core. */ + RTASN1TYPE_SET_CORE, +#endif + /** ASN.1 object identifier. */ + RTASN1TYPE_OBJID, + /** End of valid types. */ + RTASN1TYPE_END, + /** Type size hack. */ + RTASN1TYPE_32BIT_HACK = 0x7fffffff +} RTASN1TYPE; + + +/** + * ASN.1 dynamic type record. + */ +typedef struct RTASN1DYNTYPE +{ + /** Alternative interpretation provided by a user. + * Before destroying this object, the user must explicitly free this and set + * it to NULL, otherwise there will be memory leaks. */ + PRTASN1CORE pUser; + /** The type of data we've got here. */ + RTASN1TYPE enmType; + /** Union with data of the type dictated by enmType. */ + union + { + /** RTASN1TYPE_CORE. */ + RTASN1CORE Core; + /** RTASN1TYPE_NULL. */ + RTASN1NULL Asn1Null; + /** RTASN1TYPE_INTEGER. */ + RTASN1INTEGER Integer; + /** RTASN1TYPE_BOOLEAN. */ + RTASN1BOOLEAN Boolean; + /** RTASN1TYPE_STRING. */ + RTASN1STRING String; + /** RTASN1TYPE_OCTET_STRING. */ + RTASN1OCTETSTRING OctetString; + /** RTASN1TYPE_BIT_STRING. */ + RTASN1BITSTRING BitString; + /** RTASN1TYPE_TIME. */ + RTASN1TIME Time; +#if 0 + /** RTASN1TYPE_SEQUENCE_CORE. */ + RTASN1SEQUENCECORE SeqCore; + /** RTASN1TYPE_SET_CORE. */ + RTASN1SETCORE SetCore; +#endif + /** RTASN1TYPE_OBJID. */ + RTASN1OBJID ObjId; + } u; +} RTASN1DYNTYPE; +/** Pointer to an ASN.1 dynamic type record. */ +typedef RTASN1DYNTYPE *PRTASN1DYNTYPE; +/** Pointer to a const ASN.1 dynamic type record. */ +typedef RTASN1DYNTYPE const *PCRTASN1DYNTYPE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTASN1DYNTYPE, RTDECL, RTAsn1DynType, u.Core); +RTDECL(int) RTAsn1DynType_SetToNull(PRTASN1DYNTYPE pThis); + + +/** @name Virtual Method Table Based API + * @{ */ +/** + * Calls the destructor of the ASN.1 object. + * + * @param pThisCore The IPRT representation of an ASN.1 object. + */ +RTDECL(void) RTAsn1VtDelete(PRTASN1CORE pThisCore); + +/** + * Deep enumeration of all descendants. + * + * @returns IPRT status code, any non VINF_SUCCESS value stems from pfnCallback. + * @param pThisCore Pointer to the ASN.1 core to enumerate members of. + * @param pfnCallback The callback. + * @param uDepth The depth of this object. Children are at +1. + * @param pvUser Callback user argument. + * @param fDepthFirst When set, recurse into child objects before calling + * pfnCallback on then. When clear, the child object + * is first + */ +RTDECL(int) RTAsn1VtDeepEnum(PRTASN1CORE pThisCore, bool fDepthFirst, uint32_t uDepth, + PFNRTASN1ENUMCALLBACK pfnCallback, void *pvUser); + +/** + * Clones @a pSrcCore onto @a pThisCore. + * + * The caller must be sure that @a pSrcCore and @a pThisCore are of the same + * types. + * + * @returns IPRT status code. + * @param pThisCore Pointer to the ASN.1 core to clone onto. This shall + * be uninitialized. + * @param pSrcCore Pointer to the ASN.1 core to clone. + * @param pAllocator The allocator to use. + */ +RTDECL(int) RTAsn1VtClone(PRTASN1CORE pThisCore, PRTASN1CORE pSrcCore, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Compares two objects. + * + * @returns 0 if equal, -1 if @a pLeft is smaller, 1 if @a pLeft is larger. + * @param pLeftCore Pointer to the ASN.1 core of the left side object. + * @param pRightCore Pointer to the ASN.1 core of the right side object. + */ +RTDECL(int) RTAsn1VtCompare(PCRTASN1CORE pLeftCore, PCRTASN1CORE pRightCore); + +/** + * Check sanity. + * + * A primary criteria is that the object is present and initialized. + * + * @returns IPRT status code. + * @param pThisCore Pointer to the ASN.1 core of the object to check out. + * @param fFlags See RTASN1_CHECK_SANITY_F_XXX. + * @param pErrInfo Where to return additional error details. Optional. + * @param pszErrorTag Tag for the additional error details. + */ +RTDECL(int) RTAsn1VtCheckSanity(PCRTASN1CORE pThisCore, uint32_t fFlags, + PRTERRINFO pErrInfo, const char *pszErrorTag); +/** @} */ + + +/** @defgroup rp_asn1_encode RTAsn1Encode - ASN.1 Encoding + * @{ */ + +/** @name RTASN1ENCODE_F_XXX + * @{ */ +/** Use distinguished encoding rules (DER) to encode the object. */ +#define RTASN1ENCODE_F_DER UINT32_C(0x00000001) +/** Use base encoding rules (BER) to encode the object. + * This is currently the same as DER for practical reasons. */ +#define RTASN1ENCODE_F_BER RTASN1ENCODE_F_DER +/** Mask of valid encoding rules. */ +#define RTASN1ENCODE_F_RULE_MASK UINT32_C(0x00000007) +/** @} */ + + +/** + * Recalculates cbHdr of and ASN.1 object. + * + * @returns IPRT status code. + * @retval VINF_ASN1_NOT_ENCODED if the header size is zero (default value, + * whatever). + * @param pAsn1Core The object in question. + * @param fFlags Valid combination of the RTASN1ENCODE_F_XXX + * flags. Must include the encoding type. + * @param pErrInfo Extended error info. Optional. + */ +RTDECL(int) RTAsn1EncodeRecalcHdrSize(PRTASN1CORE pAsn1Core, uint32_t fFlags, PRTERRINFO pErrInfo); + +/** + * Prepares the ASN.1 structure for encoding. + * + * The preparations is mainly calculating accurate object size, but may also + * involve operations like recoding internal UTF-8 strings to the actual ASN.1 + * format and other things that may require memory to allocated/reallocated. + * + * @returns IPRT status code + * @param pRoot The root of the ASN.1 object tree to encode. + * @param fFlags Valid combination of the RTASN1ENCODE_F_XXX + * flags. Must include the encoding type. + * @param pcbEncoded Where to return the encoded size. Optional. + * @param pErrInfo Where to store extended error information. + * Optional. + */ +RTDECL(int) RTAsn1EncodePrepare(PRTASN1CORE pRoot, uint32_t fFlags, uint32_t *pcbEncoded, PRTERRINFO pErrInfo); + +/** + * Encodes and writes the header of an ASN.1 object. + * + * @returns IPRT status code. + * @retval VINF_ASN1_NOT_ENCODED if nothing was written (default value, + * whatever). + * @param pAsn1Core The object in question. + * @param fFlags Valid combination of the RTASN1ENCODE_F_XXX + * flags. Must include the encoding type. + * @param pfnWriter The output writer callback. + * @param pvUser The user argument to pass to @a pfnWriter. + * @param pErrInfo Where to store extended error information. + * Optional. + */ +RTDECL(int) RTAsn1EncodeWriteHeader(PCRTASN1CORE pAsn1Core, uint32_t fFlags, FNRTASN1ENCODEWRITER pfnWriter, void *pvUser, + PRTERRINFO pErrInfo); + +/** + * Encodes and writes an ASN.1 object. + * + * @returns IPRT status code + * @param pRoot The root of the ASN.1 object tree to encode. + * @param fFlags Valid combination of the RTASN1ENCODE_F_XXX + * flags. Must include the encoding type. + * @param pfnWriter The output writer callback. + * @param pvUser The user argument to pass to @a pfnWriter. + * @param pErrInfo Where to store extended error information. + * Optional. + */ +RTDECL(int) RTAsn1EncodeWrite(PCRTASN1CORE pRoot, uint32_t fFlags, FNRTASN1ENCODEWRITER pfnWriter, void *pvUser, + PRTERRINFO pErrInfo); + +/** + * Encodes and writes an ASN.1 object into a caller allocated memory buffer. + * + * @returns IPRT status code + * @param pRoot The root of the ASN.1 object tree to encode. + * @param fFlags Valid combination of the RTASN1ENCODE_F_XXX + * flags. Must include the encoding type. + * @param pvBuf The output buffer. + * @param cbBuf The buffer size. This should have the size + * returned by RTAsn1EncodePrepare(). + * @param pErrInfo Where to store extended error information. + * Optional. + */ +RTDECL(int) RTAsn1EncodeToBuffer(PCRTASN1CORE pRoot, uint32_t fFlags, void *pvBuf, size_t cbBuf, PRTERRINFO pErrInfo); + +/** + * Helper for when DER encoded ASN.1 is needed for something. + * + * Handy when interfacing with OpenSSL and the many d2i_Xxxxx OpenSSL functions, + * but also handy when structures needs to be digested or similar during signing + * or verification. + * + * We sometimes can use the data we've decoded directly, but often we have + * encode it into a temporary heap buffer. + * + * @returns IPRT status code, details in @a pErrInfo if present. + * @param pRoot The ASN.1 root of the structure to be passed to OpenSSL. + * @param ppbRaw Where to return the pointer to raw encoded data. + * @param pcbRaw Where to return the size of the raw encoded data. + * @param ppvFree Where to return what to pass to RTMemTmpFree, i.e. NULL + * if we use the previously decoded data directly and + * non-NULL if we had to allocate heap and encode it. + * @param pErrInfo Where to return details about encoding issues. Optional. + */ +RTDECL(int) RTAsn1EncodeQueryRawBits(PRTASN1CORE pRoot, const uint8_t **ppbRaw, uint32_t *pcbRaw, + void **ppvFree, PRTERRINFO pErrInfo); + +/** @} */ + + + +/** @defgroup rp_asn1_cursor RTAsn1Cursor - BER, DER, and CER cursor + * @{ */ + +/** + * ASN.1 decoder byte cursor. + */ +typedef struct RTASN1CURSOR +{ + /** Pointer to the current (next) byte. */ + uint8_t const *pbCur; + /** Number of bytes left to decode. */ + uint32_t cbLeft; + /** RTASN1CURSOR_FLAGS_XXX. */ + uint8_t fFlags; + /** The cursor depth. */ + uint8_t cDepth; + /** Two bytes reserved for future tricks. */ + uint8_t abReserved[2]; + /** Pointer to the primary cursor. */ + struct RTASN1CURSORPRIMARY *pPrimary; + /** Pointer to the parent cursor. */ + struct RTASN1CURSOR *pUp; + /** The error tag for this cursor level. */ + const char *pszErrorTag; +} RTASN1CURSOR; + +/** @name RTASN1CURSOR_FLAGS_XXX - Cursor flags. + * @{ */ +/** Enforce DER rules. */ +#define RTASN1CURSOR_FLAGS_DER RT_BIT(1) +/** Enforce CER rules. */ +#define RTASN1CURSOR_FLAGS_CER RT_BIT(2) +/** Pending indefinite length encoding. */ +#define RTASN1CURSOR_FLAGS_INDEFINITE_LENGTH RT_BIT(3) +/** @} */ + + +typedef struct RTASN1CURSORPRIMARY +{ + /** The normal cursor bits. */ + RTASN1CURSOR Cursor; + /** For error reporting. */ + PRTERRINFO pErrInfo; + /** The allocator virtual method table. */ + PCRTASN1ALLOCATORVTABLE pAllocator; + /** Pointer to the first byte. Useful for calculating offsets. */ + uint8_t const *pbFirst; +} RTASN1CURSORPRIMARY; +typedef RTASN1CURSORPRIMARY *PRTASN1CURSORPRIMARY; + + +/** + * Initializes a primary cursor. + * + * The primary cursor is special in that it stores information shared with the + * sub-cursors created by methods like RTAsn1CursorGetContextTagNCursor and + * RTAsn1CursorGetSequenceCursor. Even if just sharing a few items at present, + * it still important to save every possible byte since stack space is scarce in + * some of the execution environments. + * + * @returns Pointer to pCursor->Cursor. + * @param pPrimaryCursor The primary cursor structure to initialize. + * @param pvFirst The first byte to decode. + * @param cb The number of bytes to decode. + * @param pErrInfo Where to store error information. + * @param pAllocator The allocator to use. + * @param fFlags RTASN1CURSOR_FLAGS_XXX. + * @param pszErrorTag The primary error tag. + */ +RTDECL(PRTASN1CURSOR) RTAsn1CursorInitPrimary(PRTASN1CURSORPRIMARY pPrimaryCursor, void const *pvFirst, uint32_t cb, + PRTERRINFO pErrInfo, PCRTASN1ALLOCATORVTABLE pAllocator, uint32_t fFlags, + const char *pszErrorTag); + +RTDECL(int) RTAsn1CursorInitSub(PRTASN1CURSOR pParent, uint32_t cb, PRTASN1CURSOR pChild, const char *pszErrorTag); + +/** + * Initialize a sub-cursor for traversing the content of an ASN.1 object. + * + * @returns IPRT status code. + * @param pParent The parent cursor. + * @param pAsn1Core The ASN.1 object which content we should + * traverse with the sub-cursor. + * @param pChild The sub-cursor to initialize. + * @param pszErrorTag The error tag of the sub-cursor. + */ +RTDECL(int) RTAsn1CursorInitSubFromCore(PRTASN1CURSOR pParent, PRTASN1CORE pAsn1Core, + PRTASN1CURSOR pChild, const char *pszErrorTag); + +/** + * Initalizes the an allocation structure prior to making an allocation. + * + * To try unify and optimize memory managment for decoding and in-memory + * construction of ASN.1 objects, each allocation has an allocation structure + * associated with it. This stores the allocator and keep statistics for + * optimizing resizable allocations. + * + * @returns Pointer to the allocator info (for call in alloc parameter). + * @param pCursor The cursor. + * @param pAllocation The allocation structure to initialize. + */ +RTDECL(PRTASN1ALLOCATION) RTAsn1CursorInitAllocation(PRTASN1CURSOR pCursor, PRTASN1ALLOCATION pAllocation); + +/** + * Initalizes the an array allocation structure prior to making an allocation. + * + * This is a special case of RTAsn1CursorInitAllocation. We store a little bit + * more detail here in order to optimize growing and shrinking of arrays. + * + * @returns Pointer to the allocator info (for call in alloc parameter). + * @param pCursor The cursor. + * @param pAllocation The allocation structure to initialize. + * @param cbEntry The array entry size. + */ +RTDECL(PRTASN1ARRAYALLOCATION) RTAsn1CursorInitArrayAllocation(PRTASN1CURSOR pCursor, PRTASN1ARRAYALLOCATION pAllocation, + size_t cbEntry); + +/** + * Wrapper around RTErrInfoSetV. + * + * @returns @a rc + * @param pCursor The cursor. + * @param rc The return code to return. + * @param pszMsg Message format string. + * @param ... Format arguments. + */ +RTDECL(int) RTAsn1CursorSetInfo(PRTASN1CURSOR pCursor, int rc, const char *pszMsg, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Wrapper around RTErrInfoSetV. + * + * @returns @a rc + * @param pCursor The cursor. + * @param rc The return code to return. + * @param pszMsg Message format string. + * @param va Format arguments. + */ +RTDECL(int) RTAsn1CursorSetInfoV(PRTASN1CURSOR pCursor, int rc, const char *pszMsg, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Checks that we've reached the end of the data for the cursor. + * + * This differs from RTAsn1CursorCheckEnd in that it does not consider the end + * an error and therefore leaves the error buffer alone. + * + * @returns True if end, otherwise false. + * @param pCursor The cursor we're decoding from. + */ +RTDECL(bool) RTAsn1CursorIsEnd(PRTASN1CURSOR pCursor); + +/** + * Checks that we've reached the end of the data for the cursor. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + */ +RTDECL(int) RTAsn1CursorCheckEnd(PRTASN1CURSOR pCursor); + +/** + * Specialization of RTAsn1CursorCheckEnd for handling indefinite length sequences. + * + * Makes sure we've reached the end of the data for the cursor, and in case of a + * an indefinite length sequence it may adjust sequence length and the parent + * cursor. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param pSeqCore The sequence core record. + * @sa RTAsn1CursorCheckSetEnd, RTAsn1CursorCheckOctStrEnd, + * RTAsn1CursorCheckEnd + */ +RTDECL(int) RTAsn1CursorCheckSeqEnd(PRTASN1CURSOR pCursor, PRTASN1SEQUENCECORE pSeqCore); + +/** + * Specialization of RTAsn1CursorCheckEnd for handling indefinite length sets. + * + * Makes sure we've reached the end of the data for the cursor, and in case of a + * an indefinite length sets it may adjust set length and the parent cursor. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param pSetCore The set core record. + * @sa RTAsn1CursorCheckSeqEnd, RTAsn1CursorCheckOctStrEnd, + * RTAsn1CursorCheckEnd + */ +RTDECL(int) RTAsn1CursorCheckSetEnd(PRTASN1CURSOR pCursor, PRTASN1SETCORE pSetCore); + +/** + * Specialization of RTAsn1CursorCheckEnd for handling indefinite length + * constructed octet strings. + * + * This function must used when parsing the content of an octet string, like + * for example the Content of a PKCS\#7 ContentInfo structure. It makes sure + * we've reached the end of the data for the cursor, and in case of a an + * indefinite length sets it may adjust set length and the parent cursor. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param pOctetString The octet string. + * @sa RTAsn1CursorCheckSeqEnd, RTAsn1CursorCheckSetEnd, + * RTAsn1CursorCheckEnd + */ +RTDECL(int) RTAsn1CursorCheckOctStrEnd(PRTASN1CURSOR pCursor, PRTASN1OCTETSTRING pOctetString); + + +/** + * Skips a given number of bytes. + * + * @returns @a pCursor + * @param pCursor The cursor. + * @param cb The number of bytes to skip. + * @internal + */ +DECLINLINE(PRTASN1CURSOR) RTAsn1CursorSkip(PRTASN1CURSOR pCursor, uint32_t cb) +{ + if (cb <= pCursor->cbLeft) + { + pCursor->cbLeft -= cb; + pCursor->pbCur += cb; + } + else + { + pCursor->pbCur += pCursor->cbLeft; + pCursor->cbLeft = 0; + } + + return pCursor; +} + +/** + * Low-level function for reading an ASN.1 header. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param pAsn1Core The output object core. + * @param pszErrorTag Error tag. + * @internal + */ +RTDECL(int) RTAsn1CursorReadHdr(PRTASN1CURSOR pCursor, PRTASN1CORE pAsn1Core, const char *pszErrorTag); + +/** + * Common helper for simple tag matching. + * + * @returns IPRT status code. + * @param pCursor The cursor (for error reporting). + * @param pAsn1Core The ASN.1 core structure. + * @param uTag The expected tag. + * @param fClass The expected class. + * @param fString Set if it's a string type that shall follow + * special CER and DER rules wrt to constructed and + * primitive encoding. + * @param fFlags The RTASN1CURSOR_GET_F_XXX flags. + * @param pszErrorTag The error tag. + * @param pszWhat The type/whatever name. + */ +RTDECL(int) RTAsn1CursorMatchTagClassFlagsEx(PRTASN1CURSOR pCursor, PRTASN1CORE pAsn1Core, uint32_t uTag, uint32_t fClass, + bool fString, uint32_t fFlags, const char *pszErrorTag, const char *pszWhat); + +/** + * Common helper for simple tag matching. + * + * @returns IPRT status code. + * @param pCursor The cursor (for error reporting). + * @param pAsn1Core The ASN.1 core structure. + * @param uTag The expected tag. + * @param fClass The expected class. + * @param fFlags The RTASN1CURSOR_GET_F_XXX flags. + * @param pszErrorTag The error tag. + * @param pszWhat The type/whatever name. + * @internal + */ +DECLINLINE(int) RTAsn1CursorMatchTagClassFlags(PRTASN1CURSOR pCursor, PRTASN1CORE pAsn1Core, uint32_t uTag, uint32_t fClass, + uint32_t fFlags, const char *pszErrorTag, const char *pszWhat) +{ + if (pAsn1Core->uTag == uTag && pAsn1Core->fClass == fClass) + return VINF_SUCCESS; + return RTAsn1CursorMatchTagClassFlagsEx(pCursor, pAsn1Core, uTag, fClass, false /*fString*/, fFlags, pszErrorTag, pszWhat); +} + + +/** + * Common helper for simple tag matching for strings. + * + * Check string encoding considerations. + * + * @returns IPRT status code. + * @param pCursor The cursor (for error reporting). + * @param pAsn1Core The ASN.1 core structure. + * @param uTag The expected tag. + * @param fClass The expected class. + * @param fFlags The RTASN1CURSOR_GET_F_XXX flags. + * @param pszErrorTag The error tag. + * @param pszWhat The type/whatever name. + * @internal + */ +DECLINLINE(int) RTAsn1CursorMatchTagClassFlagsString(PRTASN1CURSOR pCursor, PRTASN1CORE pAsn1Core, uint32_t uTag, uint32_t fClass, + uint32_t fFlags, const char *pszErrorTag, const char *pszWhat) +{ + if (pAsn1Core->uTag == uTag && pAsn1Core->fClass == fClass) + return VINF_SUCCESS; + return RTAsn1CursorMatchTagClassFlagsEx(pCursor, pAsn1Core, uTag, fClass, true /*fString*/, fFlags, pszErrorTag, pszWhat); +} + + + +/** @name RTASN1CURSOR_GET_F_XXX - Common flags for all the getters. + * @{ */ +/** Used for decoding objects with implicit tags assigned to them. This only + * works when calling getters with a unambigious types. */ +#define RTASN1CURSOR_GET_F_IMPLICIT RT_BIT_32(0) +/** @} */ + +/** + * Read ANY object. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pAsn1Core The output object core. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetCore(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1CORE pAsn1Core, const char *pszErrorTag); + +/** + * Read a NULL object. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pNull The output NULL object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetNull(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1NULL pNull, const char *pszErrorTag); + +/** + * Read an INTEGER object. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pInteger The output integer object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetInteger(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1INTEGER pInteger, const char *pszErrorTag); + +/** + * Read an BOOLEAN object. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pBoolean The output boolean object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetBoolean(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1BOOLEAN pBoolean, const char *pszErrorTag); + +/** + * Retrives an object identifier (aka ObjId or OID) item from the ASN.1 stream. + * + * @returns IPRT status code. + * @param pCursor The cursor. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pObjId The output ODI object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetObjId(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1OBJID pObjId, const char *pszErrorTag); + +/** + * Retrives and verifies an object identifier. + * + * @returns IPRT status code. + * @param pCursor The cursor. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pObjId Where to return the parsed object ID, optional. + * @param pszExpectedObjId The expected object identifier (dotted). + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetAndCheckObjId(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1OBJID pObjId, + const char *pszExpectedObjId, const char *pszErrorTag); + +/** + * Read an UTC TIME or GENERALIZED TIME object. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pTime The output time object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetTime(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1TIME pTime, const char *pszErrorTag); + +/** + * Read an BIT STRING object (skips past the content). + * + * @returns IPRT status ocde. + * @param pCursor The cursor. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pBitString The output bit string object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetBitString(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1BITSTRING pBitString, + const char *pszErrorTag); + +/** + * Read an BIT STRING object (skips past the content), extended version with + * cMaxBits. + * + * @returns IPRT status ocde. + * @param pCursor The cursor. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param cMaxBits The max length of the bit string in bits. Pass + * UINT32_MAX if variable size. + * @param pBitString The output bit string object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetBitStringEx(PRTASN1CURSOR pCursor, uint32_t fFlags, uint32_t cMaxBits, PRTASN1BITSTRING pBitString, + const char *pszErrorTag); + +/** + * Read an OCTET STRING object (skips past the content). + * + * @returns IPRT status ocde. + * @param pCursor The cursor. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pOctetString The output octet string object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetOctetString(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1OCTETSTRING pOctetString, + const char *pszErrorTag); + +/** + * Read any kind of string object, except 'character string (29)'. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pString The output boolean object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetString(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1STRING pString, const char *pszErrorTag); + +/** + * Read a IA5 STRING object. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pString The output boolean object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetIa5String(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1STRING pString, const char *pszErrorTag); + +/** + * Read a UTF8 STRING object. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pString The output boolean object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetUtf8String(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1STRING pString, const char *pszErrorTag); + +/** + * Read a BMP STRING (UCS-2) object. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pString The output boolean object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetBmpString(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1STRING pString, const char *pszErrorTag); + +/** + * Read a SEQUENCE object and create a cursor for its content. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pSeqCore The output sequence core object. + * @param pSeqCursor The output cursor for the sequence content. + * @param pszErrorTag Error tag, this will be associated with the + * returned cursor. + */ +RTDECL(int) RTAsn1CursorGetSequenceCursor(PRTASN1CURSOR pCursor, uint32_t fFlags, + PRTASN1SEQUENCECORE pSeqCore, PRTASN1CURSOR pSeqCursor, const char *pszErrorTag); + +/** + * Read a SET object and create a cursor for its content. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pSetCore The output set core object. + * @param pSetCursor The output cursor for the set content. + * @param pszErrorTag Error tag, this will be associated with the + * returned cursor. + */ +RTDECL(int) RTAsn1CursorGetSetCursor(PRTASN1CURSOR pCursor, uint32_t fFlags, + PRTASN1SETCORE pSetCore, PRTASN1CURSOR pSetCursor, const char *pszErrorTag); + +/** + * Read a given constructed context tag and create a cursor for its content. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param uExpectedTag The expected tag. + * @param pVtable The vtable for the context tag node (see + * RTASN1TMPL_PASS_XTAG). + * @param pCtxTag The output context tag object. + * @param pCtxTagCursor The output cursor for the context tag content. + * @param pszErrorTag Error tag, this will be associated with the + * returned cursor. + * + * @remarks There are specialized version of this function for each of the + * numbered context tag structures, like for RTASN1CONTEXTTAG0 there is + * RTAsn1CursorGetContextTag0Cursor. + */ +RTDECL(int) RTAsn1CursorGetContextTagNCursor(PRTASN1CURSOR pCursor, uint32_t fFlags, uint32_t uExpectedTag, + PCRTASN1COREVTABLE pVtable, PRTASN1CONTEXTTAG pCtxTag, PRTASN1CURSOR pCtxTagCursor, + const char *pszErrorTag); + +/** + * Read a dynamic ASN.1 type. + * + * @returns IPRT status code. + * @param pCursor The cursor we're decoding from. + * @param fFlags RTASN1CURSOR_GET_F_XXX. + * @param pDynType The output context tag object. + * @param pszErrorTag Error tag. + */ +RTDECL(int) RTAsn1CursorGetDynType(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1DYNTYPE pDynType, const char *pszErrorTag); + +/** + * Peeks at the next ASN.1 object. + * + * @returns IPRT status code. + * @param pCursor The cursore we're decoding from. + * @param pAsn1Core Where to store the output of the peek. + */ +RTDECL(int) RTAsn1CursorPeek(PRTASN1CURSOR pCursor, PRTASN1CORE pAsn1Core); + +/** + * Checks if the next ASN.1 object matches the given tag and class/flags. + * + * @returns @c true on match, @c false on mismatch. + * @param pCursor The cursore we're decoding from. + * @param uTag The tag number to match against. + * @param fClass The tag class and flags to match against. + */ +RTDECL(bool) RTAsn1CursorIsNextEx(PRTASN1CURSOR pCursor, uint32_t uTag, uint8_t fClass); + + + +/** @internal */ +#define RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(a_uTag) \ + DECLINLINE(int) RT_CONCAT3(RTAsn1CursorGetContextTag,a_uTag,Cursor)(PRTASN1CURSOR pCursor, uint32_t fFlags, \ + PCRTASN1COREVTABLE pVtable, \ + RT_CONCAT(PRTASN1CONTEXTTAG,a_uTag) pCtxTag, \ + PRTASN1CURSOR pCtxTagCursor, const char *pszErrorTag) \ + { /* Constructed is automatically implied if you need a cursor to it. */ \ + return RTAsn1CursorGetContextTagNCursor(pCursor, fFlags, a_uTag, pVtable, (PRTASN1CONTEXTTAG)pCtxTag, pCtxTagCursor, pszErrorTag); \ + } \ + DECLINLINE(int) RT_CONCAT3(RTAsn1ContextTag,a_uTag,InitDefault)(RT_CONCAT(PRTASN1CONTEXTTAG,a_uTag) pCtxTag) \ + { /* Constructed is automatically implied if you need to init it with a default value. */ \ + return RTAsn1Core_InitDefault(&pCtxTag->Asn1Core, a_uTag, ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_CONSTRUCTED); \ + } \ + DECLINLINE(int) RT_CONCAT3(RTAsn1CursorIsConstructedContextTag,a_uTag,Next)(PRTASN1CURSOR pCursor) \ + { \ + return RTAsn1CursorIsNextEx(pCursor, a_uTag, ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_CONSTRUCTED); \ + } \ + DECLINLINE(int) RT_CONCAT3(RTAsn1CursorIsPrimitiveContextTag,a_uTag,Next)(PRTASN1CURSOR pCursor) \ + { \ + return RTAsn1CursorIsNextEx(pCursor, a_uTag, ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_PRIMITIVE); \ + } \ + DECLINLINE(int) RT_CONCAT3(RTAsn1CursorIsAnyContextTag,a_uTag,Next)(PRTASN1CURSOR pCursor) \ + { \ + return RTAsn1CursorIsNextEx(pCursor, a_uTag, ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_CONSTRUCTED) \ + || RTAsn1CursorIsNextEx(pCursor, a_uTag, ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_PRIMITIVE);\ + } \ + +RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(0) +RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(1) +RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(2) +RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(3) +RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(4) +RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(5) +RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(6) +RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES(7) +#undef RTASN1CONTEXTTAG_IMPL_CURSOR_INLINES + + +/** + * Checks if the next object is a boolean. + * + * @returns true / false + * @param pCursor The cursor we're decoding from. + * @remarks May produce error info output on mismatch. + */ +DECLINLINE(bool) RTAsn1CursorIsBooleanNext(PRTASN1CURSOR pCursor) +{ + return RTAsn1CursorIsNextEx(pCursor, ASN1_TAG_BOOLEAN, ASN1_TAGFLAG_PRIMITIVE | ASN1_TAGCLASS_UNIVERSAL); +} + + +/** + * Checks if the next object is a set. + * + * @returns true / false + * @param pCursor The cursor we're decoding from. + * @remarks May produce error info output on mismatch. + */ +DECLINLINE(bool) RTAsn1CursorIsSetNext(PRTASN1CURSOR pCursor) +{ + return RTAsn1CursorIsNextEx(pCursor, ASN1_TAG_SET, ASN1_TAGFLAG_CONSTRUCTED | ASN1_TAGCLASS_UNIVERSAL); +} + + +/** @} */ + + +/** @name ASN.1 Utility APIs + * @{ */ + +/** + * Dumps an IPRT representation of a ASN.1 object tree. + * + * @returns IPRT status code. + * @param pAsn1Core The ASN.1 object which members should be dumped. + * @param fFlags RTASN1DUMP_F_XXX. + * @param uLevel The indentation level to start at. + * @param pfnPrintfV The output function. + * @param pvUser Argument to the output function. + */ +RTDECL(int) RTAsn1Dump(PCRTASN1CORE pAsn1Core, uint32_t fFlags, uint32_t uLevel, PFNRTDUMPPRINTFV pfnPrintfV, void *pvUser); + +/** + * Queries the name for an object identifier. + * + * This API is very simple due to how we store the data. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_FOUND if not found. + * @retval VERR_BUFFER_OVERFLOW if more buffer space is required. + * + * @param pObjId The object ID to name. + * @param pszDst Where to store the name if found. + * @param cbDst The size of the destination buffer. + */ +RTDECL(int) RTAsn1QueryObjIdName(PCRTASN1OBJID pObjId, char *pszDst, size_t cbDst); + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_asn1_h */ + diff --git a/include/iprt/assert.h b/include/iprt/assert.h new file mode 100644 index 00000000..6d0087ee --- /dev/null +++ b/include/iprt/assert.h @@ -0,0 +1,2893 @@ +/** @file + * IPRT - Assertions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_assert_h +#define IPRT_INCLUDED_assert_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/stdarg.h> +#include <iprt/assertcompile.h> + +/** @defgroup grp_rt_assert Assert - Assertions + * @ingroup grp_rt + * + * Assertions are generally used to check preconditions and other + * assumptions. Sometimes it is also used to catch odd errors or errors + * that one would like to inspect in the debugger. They should not be + * used for errors that happen frequently. + * + * IPRT provides a host of assertion macros, so many that it can be a bit + * overwhelming at first. Don't despair, there is a system (surprise). + * + * First there are four families of assertions: + * - Assert - The normal strict build only assertions. + * - AssertLogRel - Calls LogRel() in non-strict builds, otherwise like Assert. + * - AssertRelease - Triggers in all builds. + * - AssertFatal - Triggers in all builds and cannot be continued. + * + * Then there are variations wrt to argument list and behavior on failure: + * - Msg - Custom RTStrPrintf-like message with the assertion message. + * - Return - Return the specific rc on failure. + * - ReturnVoid - Return (void) on failure. + * - Break - Break (out of switch/loop) on failure. + * - Stmt - Execute the specified statement(s) on failure. + * - RC - Assert RT_SUCCESS. + * - RCSuccess - Assert VINF_SUCCESS. + * + * @remarks As you might have noticed, the macros don't follow the + * coding guidelines wrt to macros supposedly being all uppercase + * and underscored. For various reasons they don't, and nobody + * has complained yet. Wonder why... :-) + * + * @remarks Each project has its own specific guidelines on how to use + * assertions, so the above is just trying to give you the general idea + * from the IPRT point of view. + * + * @{ + */ + +RT_C_DECLS_BEGIN + +#if !defined(IPRT_WITHOUT_ASSERT_STACK) \ + && defined(IN_RING3) \ + && !defined(IN_RT_STATIC) /* try keep static binaries small */ \ + && (defined(RT_ARCH_AMD64) /*|| defined(RT_ARCH_X86)*/) +/** @def IPRT_WITH_ASSERT_STACK + * Indicates that we collect a callstack stack on assertion. */ +# define IPRT_WITH_ASSERT_STACK +#endif + +/** + * The 1st part of an assert message. + * + * @param pszExpr Expression. Can be NULL. + * @param uLine Location line number. + * @param pszFile Location file name. + * @param pszFunction Location function name. + */ +RTDECL(void) RTAssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction); +/** + * Weak version of RTAssertMsg1 that can be overridden locally in a module to + * modify, redirect or otherwise mess with the assertion output. + * + * @copydoc RTAssertMsg1 + */ +RTDECL(void) RTAssertMsg1Weak(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction); + +/** + * The 2nd (optional) part of an assert message. + * + * @param pszFormat Printf like format string. + * @param ... Arguments to that string. + */ +RTDECL(void) RTAssertMsg2(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); +/** + * Weak version of RTAssertMsg2 that forwards to RTAssertMsg2WeakV. + * + * There is not need to override this, check out RTAssertMsg2WeakV instead! + * + * @copydoc RTAssertMsg2 + */ +RTDECL(void) RTAssertMsg2Weak(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * The 2nd (optional) part of an assert message. + * + * @param pszFormat Printf like format string. + * @param va Arguments to that string. + */ +RTDECL(void) RTAssertMsg2V(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); +/** + * Weak version of RTAssertMsg2V that can be overridden locally in a module to + * modify, redirect or otherwise mess with the assertion output. + * + * @copydoc RTAssertMsg2V + */ +RTDECL(void) RTAssertMsg2WeakV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Additional information which should be appended to the 2nd part of an + * assertion message. + * + * @param pszFormat Printf like format string. + * @param ... Arguments to that string. + */ +RTDECL(void) RTAssertMsg2Add(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); +/** + * Weak version of RTAssertMsg2Add that forwards to RTAssertMsg2AddWeakV. + * + * There is not need to override this, check out RTAssertMsg2AddWeakV instead! + * + * @copydoc RTAssertMsg2Add + */ +RTDECL(void) RTAssertMsg2AddWeak(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Additional information which should be appended to the 2nd part of an + * assertion message. + * + * @param pszFormat Printf like format string. + * @param va Arguments to that string. + */ +RTDECL(void) RTAssertMsg2AddV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); +/** + * Weak version of RTAssertMsg2AddV that can be overridden locally in a module + * to modify, redirect or otherwise mess with the assertion output. + * + * @copydoc RTAssertMsg2AddV + */ +RTDECL(void) RTAssertMsg2AddWeakV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +#ifdef IN_RING0 +/** + * Panics the system as the result of a fail assertion. + */ +RTR0DECL(void) RTR0AssertPanicSystem(void); +#endif /* IN_RING0 */ + +/** + * Overridable function that decides whether assertions executes the panic + * (breakpoint) or not. + * + * The generic implementation will return true. + * + * @returns true if the breakpoint should be hit, false if it should be ignored. + * + * @remark The RTDECL() makes this a bit difficult to override on Windows. So, + * you'll have to use RTASSERT_HAVE_SHOULD_PANIC or + * RTASSERT_HAVE_SHOULD_PANIC_PRIVATE there to control the kind of + * prototype. + */ +#if !defined(RTASSERT_HAVE_SHOULD_PANIC) && !defined(RTASSERT_HAVE_SHOULD_PANIC_PRIVATE) +RTDECL(bool) RTAssertShouldPanic(void); +#elif defined(RTASSERT_HAVE_SHOULD_PANIC_PRIVATE) +bool RTAssertShouldPanic(void); +#else +DECLEXPORT(bool) RTCALL RTAssertShouldPanic(void); +#endif + +/** + * Controls whether the assertions should be quiet or noisy (default). + * + * @returns The old setting. + * @param fQuiet The new setting. + */ +RTDECL(bool) RTAssertSetQuiet(bool fQuiet); + +/** + * Are assertions quiet or noisy? + * + * @returns True if they are quiet, false if noisy. + */ +RTDECL(bool) RTAssertAreQuiet(void); + +/** + * Makes the assertions panic (default) or not. + * + * @returns The old setting. + * @param fPanic The new setting. + */ +RTDECL(bool) RTAssertSetMayPanic(bool fPanic); + +/** + * Can assertion panic. + * + * @returns True if they can, false if not. + */ +RTDECL(bool) RTAssertMayPanic(void); + + +/** @name Globals for crash analysis + * @remarks This is the full potential set, it + * @{ + */ +/** The last assertion message, 1st part. */ +extern RTDATADECL(char) g_szRTAssertMsg1[1024]; +/** The last assertion message, 2nd part. */ +extern RTDATADECL(char) g_szRTAssertMsg2[4096]; +#ifdef IPRT_WITH_ASSERT_STACK +/** The last assertion message, stack part. */ +extern RTDATADECL(char) g_szRTAssertStack[4096]; +#endif +/** The last assertion message, expression. */ +extern RTDATADECL(const char * volatile) g_pszRTAssertExpr; +/** The last assertion message, file name. */ +extern RTDATADECL(const char * volatile) g_pszRTAssertFile; +/** The last assertion message, line number. */ +extern RTDATADECL(uint32_t volatile) g_u32RTAssertLine; +/** The last assertion message, function name. */ +extern RTDATADECL(const char * volatile) g_pszRTAssertFunction; +/** @} */ + +RT_C_DECLS_END + +/** @def RTAssertDebugBreak() + * Debugger breakpoint instruction. + * + * @remarks This macro does not depend on RT_STRICT. + */ +#define RTAssertDebugBreak() do { RT_BREAKPOINT(); } while (0) + + + +/** @name Assertions + * + * These assertions will only trigger when RT_STRICT is defined. When it is + * undefined they will all be no-ops and generate no code. + * + * @{ + */ + + +/** @def RTASSERT_QUIET + * This can be defined to shut up the messages for a file where this would be + * problematic because the message printing code path passes thru it. + * @internal */ +#ifdef DOXYGEN_RUNNING +# define RTASSERT_QUIET +#endif +#if defined(RTASSERT_QUIET) && !defined(DOXYGEN_RUNNING) +# define RTAssertMsg1Weak(pszExpr, uLine, pszfile, pszFunction) \ + do { } while (0) +# ifdef RT_COMPILER_SUPPORTS_VA_ARGS +# define RTAssertMsg2Weak(...) do { } while (0) +# else +# define RTAssertMsg2Weak if (1) {} else RTAssertMsg2Weak +# endif +#endif + +/** @def RTAssertDoPanic + * Raises an assertion panic appropriate to the current context. + * @remarks This macro does not depend on RT_STRICT. + */ +#if defined(IN_RING0) \ + && (defined(RT_OS_DARWIN) || defined(RT_OS_HAIKU) || defined(RT_OS_SOLARIS)) +# define RTAssertDoPanic() RTR0AssertPanicSystem() +#else +# define RTAssertDoPanic() RTAssertDebugBreak() +#endif + +/** @def AssertBreakpoint() + * Assertion Breakpoint. + * @deprecated Use RTAssertPanic or RTAssertDebugBreak instead. + */ +#ifdef RT_STRICT +# define AssertBreakpoint() RTAssertDebugBreak() +#else +# define AssertBreakpoint() do { } while (0) +#endif + +/** @def RTAssertPanic() + * If RT_STRICT is defined this macro will invoke RTAssertDoPanic if + * RTAssertShouldPanic returns true. If RT_STRICT isn't defined it won't do any + * thing. + */ +#if defined(RT_STRICT) && !defined(RTASSERT_DONT_PANIC) +# define RTAssertPanic() do { if (RTAssertShouldPanic()) RTAssertDoPanic(); } while (0) +#else +# define RTAssertPanic() do { } while (0) +#endif + +/** @def Assert + * Assert that an expression is true. If false, hit breakpoint. + * @param expr Expression which should be true. + */ +#ifdef RT_STRICT +# define Assert(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + } \ + } while (0) +#else +# define Assert(expr) do { } while (0) +#endif + + +/** @def AssertStmt + * Assert that an expression is true. If false, hit breakpoint and execute the + * statement. + * @param expr Expression which should be true. + * @param stmt Statement to execute on failure. + */ +#ifdef RT_STRICT +# define AssertStmt(expr, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + } \ + } while (0) +#else +# define AssertStmt(expr, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + stmt; \ + } \ + } while (0) +#endif + + +/** @def AssertReturn + * Assert that an expression is true and returns if it isn't. + * In RT_STRICT mode it will hit a breakpoint before returning. + * + * @param expr Expression which should be true. + * @param rc What is to be presented to return. + */ +#ifdef RT_STRICT +# define AssertReturn(expr, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + return (rc); \ + } \ + } while (0) +#else +# define AssertReturn(expr, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + return (rc); \ + } while (0) +#endif + +/** @def AssertReturnStmt + * Assert that an expression is true, if it isn't execute the given statement + * and return rc. + * + * In RT_STRICT mode it will hit a breakpoint before executing the statement and + * returning. + * + * @param expr Expression which should be true. + * @param stmt Statement to execute before returning on failure. + * @param rc What is to be presented to return. + */ +#ifdef RT_STRICT +# define AssertReturnStmt(expr, stmt, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + return (rc); \ + } \ + } while (0) +#else +# define AssertReturnStmt(expr, stmt, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + stmt; \ + return (rc); \ + } \ + } while (0) +#endif + +/** @def AssertReturnVoid + * Assert that an expression is true and returns if it isn't. + * In RT_STRICT mode it will hit a breakpoint before returning. + * + * @param expr Expression which should be true. + */ +#ifdef RT_STRICT +# define AssertReturnVoid(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + return; \ + } \ + } while (0) +#else +# define AssertReturnVoid(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + return; \ + } while (0) +#endif + +/** @def AssertReturnVoidStmt + * Assert that an expression is true, if it isn't execute the given statement + * and return. + * + * In RT_STRICT mode it will hit a breakpoint before returning. + * + * @param expr Expression which should be true. + * @param stmt Statement to execute before returning on failure. + */ +#ifdef RT_STRICT +# define AssertReturnVoidStmt(expr, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + return; \ + } \ + } while (0) +#else +# define AssertReturnVoidStmt(expr, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + stmt; \ + return; \ + } \ + } while (0) +#endif + + +/** @def AssertBreak + * Assert that an expression is true and breaks if it isn't. + * In RT_STRICT mode it will hit a breakpoint before breaking. + * + * @param expr Expression which should be true. + */ +#ifdef RT_STRICT +# define AssertBreak(expr) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + break; \ + } else \ + break +#else +# define AssertBreak(expr) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + break +#endif + +/** @def AssertContinue + * Assert that an expression is true and continue if it isn't. + * In RT_STRICT mode it will hit a breakpoint before continuing. + * + * @param expr Expression which should be true. + */ +#ifdef RT_STRICT +# define AssertContinue(expr) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + continue; \ + } else do {} while (0) +#else +# define AssertContinue(expr) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + continue +#endif + +/** @def AssertBreakStmt + * Assert that an expression is true and breaks if it isn't. + * In RT_STRICT mode it will hit a breakpoint before doing break. + * + * @param expr Expression which should be true. + * @param stmt Statement to execute before break in case of a failed assertion. + */ +#ifdef RT_STRICT +# define AssertBreakStmt(expr, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + break; \ + } else do {} while (0) +#else +# define AssertBreakStmt(expr, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + stmt; \ + break; \ + } else do {} while (0) +#endif + + +/** @def AssertMsg + * Assert that an expression is true. If it's not print message and hit breakpoint. + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#ifdef RT_STRICT +# define AssertMsg(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + } \ + } while (0) +#else +# define AssertMsg(expr, a) do { } while (0) +#endif + +/** @def AssertMsgStmt + * Assert that an expression is true. If it's not print message and hit + * breakpoint and execute the statement. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute in case of a failed assertion. + * + * @remarks The expression and statement will be evaluated in all build types. + */ +#ifdef RT_STRICT +# define AssertMsgStmt(expr, a, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + stmt; \ + } \ + } while (0) +#else +# define AssertMsgStmt(expr, a, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + stmt; \ + } \ + } while (0) +#endif + +/** @def AssertMsgReturn + * Assert that an expression is true and returns if it isn't. + * In RT_STRICT mode it will hit a breakpoint before returning. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param rc What is to be presented to return. + */ +#ifdef RT_STRICT +# define AssertMsgReturn(expr, a, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + return (rc); \ + } \ + } while (0) +#else +# define AssertMsgReturn(expr, a, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + return (rc); \ + } while (0) +#endif + +/** @def AssertMsgReturnStmt + * Assert that an expression is true, if it isn't execute the statement and + * return. + * + * In RT_STRICT mode it will hit a breakpoint before returning. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rc What is to be presented to return. + */ +#ifdef RT_STRICT +# define AssertMsgReturnStmt(expr, a, stmt, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + stmt; \ + return (rc); \ + } \ + } while (0) +#else +# define AssertMsgReturnStmt(expr, a, stmt, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + stmt; \ + return (rc); \ + } \ + } while (0) +#endif + +/** @def AssertMsgReturnVoid + * Assert that an expression is true and returns if it isn't. + * In RT_STRICT mode it will hit a breakpoint before returning. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#ifdef RT_STRICT +# define AssertMsgReturnVoid(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + return; \ + } \ + } while (0) +#else +# define AssertMsgReturnVoid(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + return; \ + } while (0) +#endif + +/** @def AssertMsgReturnVoidStmt + * Assert that an expression is true, if it isn't execute the statement and + * return. + * + * In RT_STRICT mode it will hit a breakpoint before returning. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before return in case of a failed assertion. + */ +#ifdef RT_STRICT +# define AssertMsgReturnVoidStmt(expr, a, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + stmt; \ + return; \ + } \ + } while (0) +#else +# define AssertMsgReturnVoidStmt(expr, a, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + stmt; \ + return; \ + } \ + } while (0) +#endif + + +/** @def AssertMsgBreak + * Assert that an expression is true and breaks if it isn't. + * In RT_STRICT mode it will hit a breakpoint before returning. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#ifdef RT_STRICT +# define AssertMsgBreak(expr, a) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + break; \ + } else \ + break +#else +# define AssertMsgBreak(expr, a) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + break +#endif + +/** @def AssertMsgBreakStmt + * Assert that an expression is true and breaks if it isn't. + * In RT_STRICT mode it will hit a breakpoint before doing break. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + */ +#ifdef RT_STRICT +# define AssertMsgBreakStmt(expr, a, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + stmt; \ + break; \ + } else \ + break +#else +# define AssertMsgBreakStmt(expr, a, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + stmt; \ + break; \ + } else \ + break +#endif + +/** @def AssertFailed + * An assertion failed, hit breakpoint. + */ +#ifdef RT_STRICT +# define AssertFailed() \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + } while (0) +#else +# define AssertFailed() do { } while (0) +#endif + +/** @def AssertFailedStmt + * An assertion failed, hit breakpoint and execute statement. + */ +#ifdef RT_STRICT +# define AssertFailedStmt(stmt) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + } while (0) +#else +# define AssertFailedStmt(stmt) do { stmt; } while (0) +#endif + +/** @def AssertFailedReturn + * An assertion failed, hit breakpoint (RT_STRICT mode only) and return. + * + * @param rc The rc to return. + */ +#ifdef RT_STRICT +# define AssertFailedReturn(rc) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + return (rc); \ + } while (0) +#else +# define AssertFailedReturn(rc) \ + do { \ + return (rc); \ + } while (0) +#endif + +/** @def AssertFailedReturnStmt + * An assertion failed, hit breakpoint (RT_STRICT mode only), execute a + * statement and return a value. + * + * @param stmt The statement to execute before returning. + * @param rc The value to return. + */ +#ifdef RT_STRICT +# define AssertFailedReturnStmt(stmt, rc) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + return (rc); \ + } while (0) +#else +# define AssertFailedReturnStmt(stmt, rc) \ + do { \ + stmt; \ + return (rc); \ + } while (0) +#endif + +/** @def AssertFailedReturnVoid + * An assertion failed, hit breakpoint (RT_STRICT mode only) and return. + */ +#ifdef RT_STRICT +# define AssertFailedReturnVoid() \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + return; \ + } while (0) +#else +# define AssertFailedReturnVoid() \ + do { \ + return; \ + } while (0) +#endif + +/** @def AssertFailedReturnVoidStmt + * An assertion failed, hit breakpoint (RT_STRICT mode only), execute a + * statement and return. + * + * @param stmt The statement to execute before returning. + */ +#ifdef RT_STRICT +# define AssertFailedReturnVoidStmt(stmt) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + return; \ + } while (0) +#else +# define AssertFailedReturnVoidStmt(stmt) \ + do { \ + stmt; \ + return; \ + } while (0) +#endif + + +/** @def AssertFailedBreak + * An assertion failed, hit breakpoint (RT_STRICT mode only) and break. + */ +#ifdef RT_STRICT +# define AssertFailedBreak() \ + if (1) { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + break; \ + } else \ + break +#else +# define AssertFailedBreak() \ + if (1) \ + break; \ + else \ + break +#endif + +/** @def AssertFailedBreakStmt + * An assertion failed, hit breakpoint (RT_STRICT mode only), execute + * the given statement and break. + * + * @param stmt Statement to execute before break. + */ +#ifdef RT_STRICT +# define AssertFailedBreakStmt(stmt) \ + if (1) { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + break; \ + } else \ + break +#else +# define AssertFailedBreakStmt(stmt) \ + if (1) { \ + stmt; \ + break; \ + } else \ + break +#endif + + +/** @def AssertMsgFailed + * An assertion failed print a message and a hit breakpoint. + * + * @param a printf argument list (in parenthesis). + */ +#ifdef RT_STRICT +# define AssertMsgFailed(a) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + } while (0) +#else +# define AssertMsgFailed(a) do { } while (0) +#endif + +/** @def AssertMsgFailedReturn + * An assertion failed, hit breakpoint with message (RT_STRICT mode only) and return. + * + * @param a printf argument list (in parenthesis). + * @param rc What is to be presented to return. + */ +#ifdef RT_STRICT +# define AssertMsgFailedReturn(a, rc) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + return (rc); \ + } while (0) +#else +# define AssertMsgFailedReturn(a, rc) \ + do { \ + return (rc); \ + } while (0) +#endif + +/** @def AssertMsgFailedReturnVoid + * An assertion failed, hit breakpoint with message (RT_STRICT mode only) and return. + * + * @param a printf argument list (in parenthesis). + */ +#ifdef RT_STRICT +# define AssertMsgFailedReturnVoid(a) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + return; \ + } while (0) +#else +# define AssertMsgFailedReturnVoid(a) \ + do { \ + return; \ + } while (0) +#endif + + +/** @def AssertMsgFailedBreak + * An assertion failed, hit breakpoint with message (RT_STRICT mode only) and break. + * + * @param a printf argument list (in parenthesis). + */ +#ifdef RT_STRICT +# define AssertMsgFailedBreak(a) \ + if (1) { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + break; \ + } else \ + break +#else +# define AssertMsgFailedBreak(a) \ + if (1) \ + break; \ + else \ + break +#endif + +/** @def AssertMsgFailedBreakStmt + * An assertion failed, hit breakpoint (RT_STRICT mode only), execute + * the given statement and break. + * + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before break. + */ +#ifdef RT_STRICT +# define AssertMsgFailedBreakStmt(a, stmt) \ + if (1) { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertPanic(); \ + stmt; \ + break; \ + } else \ + break +#else +# define AssertMsgFailedBreakStmt(a, stmt) \ + if (1) { \ + stmt; \ + break; \ + } else \ + break +#endif + +/** @} */ + + + +/** @name Release Log Assertions + * + * These assertions will work like normal strict assertion when RT_STRICT is + * defined and LogRel statements when RT_STRICT is undefined. Typically used for + * things which shouldn't go wrong, but when it does you'd like to know one way + * or the other. + * + * @{ + */ + +/** @def RTAssertLogRelMsg1 + * RTAssertMsg1Weak (strict builds) / LogRel wrapper (non-strict). + */ +#ifdef RT_STRICT +# define RTAssertLogRelMsg1(pszExpr, iLine, pszFile, pszFunction) \ + RTAssertMsg1Weak(pszExpr, iLine, pszFile, pszFunction) +#else +# define RTAssertLogRelMsg1(pszExpr, iLine, pszFile, pszFunction) \ + LogRel(("AssertLogRel %s(%d) %s: %s\n",\ + (pszFile), (iLine), (pszFunction), (pszExpr) )) +#endif + +/** @def RTAssertLogRelMsg2 + * RTAssertMsg2Weak (strict builds) / LogRel wrapper (non-strict). + */ +#ifdef RT_STRICT +# define RTAssertLogRelMsg2(a) RTAssertMsg2Weak a +#else +# define RTAssertLogRelMsg2(a) LogRel(a) +#endif + +/** @def AssertLogRel + * Assert that an expression is true. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + */ +#define AssertLogRel(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + } \ + } while (0) + +/** @def AssertLogRelReturn + * Assert that an expression is true, return \a rc if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param rc What is to be presented to return. + */ +#define AssertLogRelReturn(expr, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + return (rc); \ + } \ + } while (0) + +/** @def AssertLogRelReturnVoid + * Assert that an expression is true, return void if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + */ +#define AssertLogRelReturnVoid(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + return; \ + } \ + } while (0) + +/** @def AssertLogRelBreak + * Assert that an expression is true, break if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + */ +#define AssertLogRelBreak(expr) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + break; \ + } \ + else \ + break + +/** @def AssertLogRelBreakStmt + * Assert that an expression is true, execute \a stmt and break if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param stmt Statement to execute before break in case of a failed assertion. + */ +#define AssertLogRelBreakStmt(expr, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + break; \ + } else \ + break + +/** @def AssertLogRelStmt + * Assert that an expression is true, return \a rc if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param stmt Statement to execute in case of a failed assertion. + */ +#define AssertLogRelStmt(expr, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + } \ + } while (0) + +/** @def AssertLogRelMsg + * Assert that an expression is true. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#define AssertLogRelMsg(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else\ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + } \ + } while (0) + +/** @def AssertLogRelMsgStmt + * Assert that an expression is true, execute \a stmt and break if it isn't + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute in case of a failed assertion. + */ +#define AssertLogRelMsgStmt(expr, a, stmt) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else\ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + stmt; \ + } \ + } while (0) + +/** @def AssertLogRelMsgReturn + * Assert that an expression is true, return \a rc if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param rc What is to be presented to return. + */ +#define AssertLogRelMsgReturn(expr, a, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else\ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + return (rc); \ + } \ + } while (0) + +/** @def AssertLogRelMsgReturnStmt + * Assert that an expression is true, execute @a stmt and return @a rcRet if it + * isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + */ +#define AssertLogRelMsgReturnStmt(expr, a, stmt, rcRet) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else\ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + stmt; \ + return (rcRet); \ + } \ + } while (0) + +/** @def AssertLogRelMsgReturnVoid + * Assert that an expression is true, return (void) if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#define AssertLogRelMsgReturnVoid(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else\ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + return; \ + } \ + } while (0) + +/** @def AssertLogRelMsgBreak + * Assert that an expression is true, break if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#define AssertLogRelMsgBreak(expr, a) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + break; \ + } \ + else \ + break + +/** @def AssertLogRelMsgBreakStmt + * Assert that an expression is true, execute \a stmt and break if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + */ +#define AssertLogRelMsgBreakStmt(expr, a, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertLogRelMsg1(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + stmt; \ + break; \ + } else \ + break + +/** @def AssertLogRelFailed + * An assertion failed. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + */ +#define AssertLogRelFailed() \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + } while (0) + +/** @def AssertLogRelFailedReturn + * An assertion failed. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param rc What is to be presented to return. + */ +#define AssertLogRelFailedReturn(rc) \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + return (rc); \ + } while (0) + +/** @def AssertLogRelFailedReturnVoid + * An assertion failed, hit a breakpoint and return. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + */ +#define AssertLogRelFailedReturnVoid() \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + return; \ + } while (0) + +/** @def AssertLogRelFailedBreak + * An assertion failed, break. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + */ +#define AssertLogRelFailedBreak() \ + if (1) \ + { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + break; \ + } else \ + break + +/** @def AssertLogRelFailedBreakStmt + * An assertion failed, execute \a stmt and break. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param stmt Statement to execute before break. + */ +#define AssertLogRelFailedBreakStmt(stmt) \ + if (1) \ + { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertPanic(); \ + stmt; \ + break; \ + } else \ + break + +/** @def AssertLogRelMsgFailed + * An assertion failed. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + */ +#define AssertLogRelMsgFailed(a) \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + } while (0) + +/** @def AssertLogRelMsgFailedStmt + * An assertion failed, execute @a stmt. + * + * Strict builds will hit a breakpoint, non-strict will only do LogRel. The + * statement will be executed in regardless of build type. + * + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute after raising/logging the assertion. + */ +#define AssertLogRelMsgFailedStmt(a, stmt) \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + stmt; \ + } while (0) + +/** @def AssertLogRelMsgFailedReturn + * An assertion failed, return \a rc. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + * @param rc What is to be presented to return. + */ +#define AssertLogRelMsgFailedReturn(a, rc) \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + return (rc); \ + } while (0) + +/** @def AssertLogRelMsgFailedReturnStmt + * An assertion failed, execute @a stmt and return @a rc. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rc What is to be presented to return. + */ +#define AssertLogRelMsgFailedReturnStmt(a, stmt, rc) \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + stmt; \ + return (rc); \ + } while (0) + +/** @def AssertLogRelMsgFailedReturnVoid + * An assertion failed, return void. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + */ +#define AssertLogRelMsgFailedReturnVoid(a) \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + return; \ + } while (0) + +/** @def AssertLogRelMsgFailedReturnVoidStmt + * An assertion failed, execute @a stmt and return void. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + */ +#define AssertLogRelMsgFailedReturnVoidStmt(a, stmt) \ + do { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + stmt; \ + return; \ + } while (0) + +/** @def AssertLogRelMsgFailedBreak + * An assertion failed, break. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + */ +#define AssertLogRelMsgFailedBreak(a) \ + if (1)\ + { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + break; \ + } else \ + break + +/** @def AssertLogRelMsgFailedBreakStmt + * An assertion failed, execute \a stmt and break. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before break. + */ +#define AssertLogRelMsgFailedBreakStmt(a, stmt) \ + if (1) \ + { \ + RTAssertLogRelMsg1((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertLogRelMsg2(a); \ + RTAssertPanic(); \ + stmt; \ + break; \ + } else \ + break + +/** @} */ + + + +/** @name Release Assertions + * + * These assertions are always enabled. + * @{ + */ + +/** @def RTAssertReleasePanic() + * Invokes RTAssertShouldPanic and RTAssertDoPanic. + * + * It might seem odd that RTAssertShouldPanic is necessary when its result isn't + * checked, but it's done since RTAssertShouldPanic is overrideable and might be + * used to bail out before taking down the system (the VMMR0 case). + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define RTAssertReleasePanic() do { RTAssertShouldPanic(); RTAssertDoPanic(); } while (0) +#else +# define RTAssertReleasePanic() do { } while (0) +#endif + + +/** @def AssertRelease + * Assert that an expression is true. If it's not hit a breakpoint. + * + * @param expr Expression which should be true. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertRelease(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + } \ + } while (0) +#else +# define AssertRelease(expr) do { } while (0) +#endif + + +/** @def AssertReleaseReturn + * Assert that an expression is true, hit a breakpoint and return if it isn't. + * + * @param expr Expression which should be true. + * @param rc What is to be presented to return. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseReturn(expr, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + return (rc); \ + } \ + } while (0) +#else +# define AssertReleaseReturn(expr, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + return (rc); \ + } while (0) +#endif + +/** @def AssertReleaseReturnVoid + * Assert that an expression is true, hit a breakpoint and return if it isn't. + * + * @param expr Expression which should be true. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseReturnVoid(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + return; \ + } \ + } while (0) +#else +# define AssertReleaseReturnVoid(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + return; \ + } while (0) +#endif + + +/** @def AssertReleaseBreak + * Assert that an expression is true, hit a breakpoint and break if it isn't. + * + * @param expr Expression which should be true. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseBreak(expr) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + break; \ + } else \ + break +#else +# define AssertReleaseBreak(expr) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + break +#endif + +/** @def AssertReleaseBreakStmt + * Assert that an expression is true, hit a breakpoint and break if it isn't. + * + * @param expr Expression which should be true. + * @param stmt Statement to execute before break in case of a failed assertion. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseBreakStmt(expr, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + stmt; \ + break; \ + } else \ + break +#else +# define AssertReleaseBreakStmt(expr, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + stmt; \ + break; \ + } else \ + break +#endif + + +/** @def AssertReleaseMsg + * Assert that an expression is true, print the message and hit a breakpoint if it isn't. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsg(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + } \ + } while (0) +#else +# define AssertReleaseMsg(expr, a) do { } while (0) +#endif + +/** @def AssertReleaseMsgReturn + * Assert that an expression is true, print the message and hit a breakpoint and return if it isn't. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param rc What is to be presented to return. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgReturn(expr, a, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + return (rc); \ + } \ + } while (0) +#else +# define AssertReleaseMsgReturn(expr, a, rc) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + return (rc); \ + } while (0) +#endif + +/** @def AssertReleaseMsgReturnVoid + * Assert that an expression is true, print the message and hit a breakpoint and return if it isn't. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgReturnVoid(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + return; \ + } \ + } while (0) +#else +# define AssertReleaseMsgReturnVoid(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + return; \ + } while (0) +#endif + + +/** @def AssertReleaseMsgBreak + * Assert that an expression is true, print the message and hit a breakpoint and break if it isn't. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgBreak(expr, a) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + break; \ + } else \ + break +#else +# define AssertReleaseMsgBreak(expr, a) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + break; \ + else \ + break +#endif + +/** @def AssertReleaseMsgBreakStmt + * Assert that an expression is true, print the message and hit a breakpoint and break if it isn't. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgBreakStmt(expr, a, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + stmt; \ + break; \ + } else \ + break +#else +# define AssertReleaseMsgBreakStmt(expr, a, stmt) \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + stmt; \ + break; \ + } else \ + break +#endif + + +/** @def AssertReleaseFailed + * An assertion failed, hit a breakpoint. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseFailed() \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + } while (0) +#else +# define AssertReleaseFailed() do { } while (0) +#endif + +/** @def AssertReleaseFailedReturn + * An assertion failed, hit a breakpoint and return. + * + * @param rc What is to be presented to return. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseFailedReturn(rc) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + return (rc); \ + } while (0) +#else +# define AssertReleaseFailedReturn(rc) \ + do { return (rc); } while (0) +#endif + +/** @def AssertReleaseFailedReturnVoid + * An assertion failed, hit a breakpoint and return. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseFailedReturnVoid() \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + return; \ + } while (0) +#else +# define AssertReleaseFailedReturnVoid() \ + do { return; } while (0) +#endif + +/** @def AssertReleaseFailedBreak + * An assertion failed, hit a breakpoint and break. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseFailedBreak() \ + if (1) { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + break; \ + } else \ + break +#else +# define AssertReleaseFailedBreak() \ + if (1) \ + break; \ + else \ + break +#endif + +/** @def AssertReleaseFailedBreakStmt + * An assertion failed, hit a breakpoint and break. + * + * @param stmt Statement to execute before break. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseFailedBreakStmt(stmt) \ + if (1) { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + stmt; \ + break; \ + } else \ + break +#else +# define AssertReleaseFailedBreakStmt(stmt) \ + if (1) { \ + stmt; \ + break; \ + } else \ + break +#endif + +/** @def AssertReleaseMsgFailed + * An assertion failed, print a message and hit a breakpoint. + * + * @param a printf argument list (in parenthesis). + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgFailed(a) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + } while (0) +#else +# define AssertReleaseMsgFailed(a) do { } while (0) +#endif + +/** @def AssertReleaseMsgFailedReturn + * An assertion failed, print a message, hit a breakpoint and return. + * + * @param a printf argument list (in parenthesis). + * @param rc What is to be presented to return. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgFailedReturn(a, rc) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + return (rc); \ + } while (0) +#else +# define AssertReleaseMsgFailedReturn(a, rc) \ + do { return (rc); } while (0) +#endif + +/** @def AssertReleaseMsgFailedReturnVoid + * An assertion failed, print a message, hit a breakpoint and return. + * + * @param a printf argument list (in parenthesis). + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgFailedReturnVoid(a) \ + do { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + return; \ + } while (0) +#else +# define AssertReleaseMsgFailedReturnVoid(a) \ + do { return; } while (0) +#endif + + +/** @def AssertReleaseMsgFailedBreak + * An assertion failed, print a message, hit a breakpoint and break. + * + * @param a printf argument list (in parenthesis). + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgFailedBreak(a) \ + if (1) { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + break; \ + } else \ + break +#else +# define AssertReleaseMsgFailedBreak(a) \ + if (1) \ + break; \ + else \ + break +#endif + +/** @def AssertReleaseMsgFailedBreakStmt + * An assertion failed, print a message, hit a breakpoint and break. + * + * @param a printf argument list (in parenthesis). + * @param stmt Statement to execute before break. + */ +#if defined(RT_STRICT) || !defined(RTASSERT_NO_RELEASE_ASSERTIONS) +# define AssertReleaseMsgFailedBreakStmt(a, stmt) \ + if (1) { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + stmt; \ + break; \ + } else \ + break +#else +# define AssertReleaseMsgFailedBreakStmt(a, stmt) \ + if (1) { \ + stmt; \ + break; \ + } else \ + break +#endif +/** @} */ + + + +/** @name Fatal Assertions + * These are similar to release assertions except that you cannot ignore them in + * any way, they will loop for ever if RTAssertDoPanic returns. + * + * @{ + */ + +/** @def AssertFatal + * Assert that an expression is true. If it's not hit a breakpoint (for ever). + * + * @param expr Expression which should be true. + */ +#define AssertFatal(expr) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + for (;;) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + } \ + } while (0) + +/** @def AssertFatalMsg + * Assert that an expression is true, print the message and hit a breakpoint (for ever) if it isn't. + * + * @param expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#define AssertFatalMsg(expr, a) \ + do { \ + if (RT_LIKELY(!!(expr))) \ + { /* likely */ } \ + else \ + for (;;) \ + { \ + RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + } \ + } while (0) + +/** @def AssertFatalFailed + * An assertion failed, hit a breakpoint (for ever). + */ +#define AssertFatalFailed() \ + do { \ + for (;;) \ + { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertReleasePanic(); \ + } \ + } while (0) + +/** @def AssertFatalMsgFailed + * An assertion failed, print a message and hit a breakpoint (for ever). + * + * @param a printf argument list (in parenthesis). + */ +#define AssertFatalMsgFailed(a) \ + do { \ + for (;;) \ + { \ + RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + RTAssertReleasePanic(); \ + } \ + } while (0) + +/** @} */ + + + +/** @name Convenience Assertions Macros + * @{ + */ + +/** @def AssertRC + * Asserts a iprt status code successful. + * + * On failure it will print info about the rc and hit a breakpoint. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRC(rc) AssertMsgRC(rc, ("%Rra\n", (rc))) + +/** @def AssertRCStmt + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and execute + * @a stmt if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCStmt(rc, stmt) AssertMsgRCStmt(rc, ("%Rra\n", (rc)), stmt) + +/** @def AssertRCReturn + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCReturn(rc, rcRet) AssertMsgRCReturn(rc, ("%Rra\n", (rc)), rcRet) + +/** @def AssertRCReturnStmt + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and returns @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCReturnStmt(rc, stmt, rcRet) AssertMsgRCReturnStmt(rc, ("%Rra\n", (rc)), stmt, rcRet) + +/** @def AssertRCReturnVoid + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCReturnVoid(rc) AssertMsgRCReturnVoid(rc, ("%Rra\n", (rc))) + +/** @def AssertRCReturnVoidStmt + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), and + * execute the given statement/return if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning on failure. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCReturnVoidStmt(rc, stmt) AssertMsgRCReturnVoidStmt(rc, ("%Rra\n", (rc)), stmt) + +/** @def AssertRCBreak + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCBreak(rc) AssertMsgRCBreak(rc, ("%Rra\n", (rc))) + +/** @def AssertRCBreakStmt + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCBreakStmt(rc, stmt) AssertMsgRCBreakStmt(rc, ("%Rra\n", (rc)), stmt) + +/** @def AssertMsgRC + * Asserts a iprt status code successful. + * + * It prints a custom message and hits a breakpoint on FAILURE. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertMsgRC(rc, msg) \ + do { AssertMsg(RT_SUCCESS_NP(rc), msg); NOREF(rc); } while (0) + +/** @def AssertMsgRCStmt + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and + * execute @a stmt if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertMsgRCStmt(rc, msg, stmt) \ + do { AssertMsgStmt(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } while (0) + +/** @def AssertMsgRCReturn + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return + * @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertMsgRCReturn(rc, msg, rcRet) \ + do { AssertMsgReturn(RT_SUCCESS_NP(rc), msg, rcRet); NOREF(rc); } while (0) + +/** @def AssertMsgRCReturnStmt + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and return @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertMsgRCReturnStmt(rc, msg, stmt, rcRet) \ + do { AssertMsgReturnStmt(RT_SUCCESS_NP(rc), msg, stmt, rcRet); NOREF(rc); } while (0) + +/** @def AssertMsgRCReturnVoid + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return + * void if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertMsgRCReturnVoid(rc, msg) \ + do { AssertMsgReturnVoid(RT_SUCCESS_NP(rc), msg); NOREF(rc); } while (0) + +/** @def AssertMsgRCReturnVoidStmt + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and return void if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertMsgRCReturnVoidStmt(rc, msg, stmt) \ + do { AssertMsgReturnVoidStmt(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } while (0) + +/** @def AssertMsgRCBreak + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break + * if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertMsgRCBreak(rc, msg) \ + if (1) { AssertMsgBreak(RT_SUCCESS(rc), msg); NOREF(rc); } else do {} while (0) + +/** @def AssertMsgRCBreakStmt + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and break if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertMsgRCBreakStmt(rc, msg, stmt) \ + if (1) { AssertMsgBreakStmt(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } else do {} while (0) + +/** @def AssertRCSuccess + * Asserts an iprt status code equals VINF_SUCCESS. + * + * On failure it will print info about the rc and hit a breakpoint. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCSuccess(rc) do { AssertMsg((rc) == VINF_SUCCESS, ("%Rra\n", (rc))); NOREF(rc); } while (0) + +/** @def AssertRCSuccessReturn + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCSuccessReturn(rc, rcRet) AssertMsgReturn((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), rcRet) + +/** @def AssertRCSuccessReturnVoid + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCSuccessReturnVoid(rc) AssertMsgReturnVoid((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def AssertRCSuccessBreak + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCSuccessBreak(rc) AssertMsgBreak((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def AssertRCSuccessBreakStmt + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define AssertRCSuccessBreakStmt(rc, stmt) AssertMsgBreakStmt((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), stmt) + + +/** @def AssertLogRelRC + * Asserts a iprt status code successful. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRC(rc) AssertLogRelMsgRC(rc, ("%Rra\n", (rc))) + +/** @def AssertLogRelRCReturn + * Asserts a iprt status code successful, returning \a rc if it isn't. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCReturn(rc, rcRet) AssertLogRelMsgRCReturn(rc, ("%Rra\n", (rc)), rcRet) + +/** @def AssertLogRelRCReturnStmt + * Asserts a iprt status code successful, executing \a stmt and returning \a rc + * if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCReturnStmt(rc, stmt, rcRet) AssertLogRelMsgRCReturnStmt(rc, ("%Rra\n", (rc)), stmt, rcRet) + +/** @def AssertLogRelRCReturnVoid + * Asserts a iprt status code successful, returning (void) if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCReturnVoid(rc) AssertLogRelMsgRCReturnVoid(rc, ("%Rra\n", (rc))) + +/** @def AssertLogRelRCBreak + * Asserts a iprt status code successful, breaking if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCBreak(rc) AssertLogRelMsgRCBreak(rc, ("%Rra\n", (rc))) + +/** @def AssertLogRelRCBreakStmt + * Asserts a iprt status code successful, execute \a statement and break if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCBreakStmt(rc, stmt) AssertLogRelMsgRCBreakStmt(rc, ("%Rra\n", (rc)), stmt) + +/** @def AssertLogRelMsgRC + * Asserts a iprt status code successful. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. + */ +#define AssertLogRelMsgRC(rc, msg) AssertLogRelMsg(RT_SUCCESS_NP(rc), msg) + +/** @def AssertLogRelMsgRCReturn + * Asserts a iprt status code successful. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelMsgRCReturn(rc, msg, rcRet) AssertLogRelMsgReturn(RT_SUCCESS_NP(rc), msg, rcRet) + +/** @def AssertLogRelMsgRCReturnStmt + * Asserts a iprt status code successful, execute \a stmt and return on + * failure. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelMsgRCReturnStmt(rc, msg, stmt, rcRet) AssertLogRelMsgReturnStmt(RT_SUCCESS_NP(rc), msg, stmt, rcRet) + +/** @def AssertLogRelMsgRCReturnVoid + * Asserts a iprt status code successful. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. + */ +#define AssertLogRelMsgRCReturnVoid(rc, msg) AssertLogRelMsgReturnVoid(RT_SUCCESS_NP(rc), msg) + +/** @def AssertLogRelMsgRCBreak + * Asserts a iprt status code successful. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. + */ +#define AssertLogRelMsgRCBreak(rc, msg) AssertLogRelMsgBreak(RT_SUCCESS(rc), msg) + +/** @def AssertLogRelMsgRCBreakStmt + * Asserts a iprt status code successful, execute \a stmt and break if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelMsgRCBreakStmt(rc, msg, stmt) AssertLogRelMsgBreakStmt(RT_SUCCESS_NP(rc), msg, stmt) + +/** @def AssertLogRelRCSuccess + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCSuccess(rc) AssertLogRelMsg((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def AssertLogRelRCSuccessReturn + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCSuccessReturn(rc, rcRet) AssertLogRelMsgReturn((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), rcRet) + +/** @def AssertLogRelRCSuccessReturnVoid + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCSuccessReturnVoid(rc) AssertLogRelMsgReturnVoid((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def AssertLogRelRCSuccessBreak + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCSuccessBreak(rc) AssertLogRelMsgBreak((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def AssertLogRelRCSuccessBreakStmt + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. + */ +#define AssertLogRelRCSuccessBreakStmt(rc, stmt) AssertLogRelMsgBreakStmt((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), stmt) + + +/** @def AssertReleaseRC + * Asserts a iprt status code successful. + * + * On failure information about the error will be printed and a breakpoint hit. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRC(rc) AssertReleaseMsgRC(rc, ("%Rra\n", (rc))) + +/** @def AssertReleaseRCReturn + * Asserts a iprt status code successful, returning if it isn't. + * + * On failure information about the error will be printed, a breakpoint hit + * and finally returning from the function if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCReturn(rc, rcRet) AssertReleaseMsgRCReturn(rc, ("%Rra\n", (rc)), rcRet) + +/** @def AssertReleaseRCReturnVoid + * Asserts a iprt status code successful, returning if it isn't. + * + * On failure information about the error will be printed, a breakpoint hit + * and finally returning from the function if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCReturnVoid(rc) AssertReleaseMsgRCReturnVoid(rc, ("%Rra\n", (rc))) + +/** @def AssertReleaseRCBreak + * Asserts a iprt status code successful, breaking if it isn't. + * + * On failure information about the error will be printed, a breakpoint hit + * and finally breaking the current statement if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCBreak(rc) AssertReleaseMsgRCBreak(rc, ("%Rra\n", (rc))) + +/** @def AssertReleaseRCBreakStmt + * Asserts a iprt status code successful, break if it isn't. + * + * On failure information about the error will be printed, a breakpoint hit + * and finally the break statement will be issued if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCBreakStmt(rc, stmt) AssertReleaseMsgRCBreakStmt(rc, ("%Rra\n", (rc)), stmt) + +/** @def AssertReleaseMsgRC + * Asserts a iprt status code successful. + * + * On failure a custom message is printed and a breakpoint is hit. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. + */ +#define AssertReleaseMsgRC(rc, msg) AssertReleaseMsg(RT_SUCCESS_NP(rc), msg) + +/** @def AssertReleaseMsgRCReturn + * Asserts a iprt status code successful. + * + * On failure a custom message is printed, a breakpoint is hit, and finally + * returning from the function if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseMsgRCReturn(rc, msg, rcRet) AssertReleaseMsgReturn(RT_SUCCESS_NP(rc), msg, rcRet) + +/** @def AssertReleaseMsgRCReturnVoid + * Asserts a iprt status code successful. + * + * On failure a custom message is printed, a breakpoint is hit, and finally + * returning from the function if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. + */ +#define AssertReleaseMsgRCReturnVoid(rc, msg) AssertReleaseMsgReturnVoid(RT_SUCCESS_NP(rc), msg) + +/** @def AssertReleaseMsgRCBreak + * Asserts a iprt status code successful. + * + * On failure a custom message is printed, a breakpoint is hit, and finally + * breaking the current status if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. + */ +#define AssertReleaseMsgRCBreak(rc, msg) AssertReleaseMsgBreak(RT_SUCCESS(rc), msg) + +/** @def AssertReleaseMsgRCBreakStmt + * Asserts a iprt status code successful. + * + * On failure a custom message is printed, a breakpoint is hit, and finally + * the break statement is issued if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseMsgRCBreakStmt(rc, msg, stmt) AssertReleaseMsgBreakStmt(RT_SUCCESS_NP(rc), msg, stmt) + +/** @def AssertReleaseRCSuccess + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * On failure information about the error will be printed and a breakpoint hit. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCSuccess(rc) AssertReleaseMsg((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def AssertReleaseRCSuccessReturn + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * On failure information about the error will be printed, a breakpoint hit + * and finally returning from the function if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCSuccessReturn(rc, rcRet) AssertReleaseMsgReturn((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), rcRet) + +/** @def AssertReleaseRCSuccessReturnVoid + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * On failure information about the error will be printed, a breakpoint hit + * and finally returning from the function if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCSuccessReturnVoid(rc) AssertReleaseMsgReturnVoid((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def AssertReleaseRCSuccessBreak + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * On failure information about the error will be printed, a breakpoint hit + * and finally breaking the current statement if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCSuccessBreak(rc) AssertReleaseMsgBreak((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def AssertReleaseRCSuccessBreakStmt + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * On failure information about the error will be printed, a breakpoint hit + * and finally the break statement will be issued if the breakpoint is somehow ignored. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. + */ +#define AssertReleaseRCSuccessBreakStmt(rc, stmt) AssertReleaseMsgBreakStmt((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), stmt) + + +/** @def AssertFatalRC + * Asserts a iprt status code successful. + * + * On failure information about the error will be printed and a breakpoint hit. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertFatalRC(rc) AssertFatalMsgRC(rc, ("%Rra\n", (rc))) + +/** @def AssertReleaseMsgRC + * Asserts a iprt status code successful. + * + * On failure a custom message is printed and a breakpoint is hit. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. + */ +#define AssertFatalMsgRC(rc, msg) AssertFatalMsg(RT_SUCCESS_NP(rc), msg) + +/** @def AssertFatalRCSuccess + * Asserts that an iprt status code equals VINF_SUCCESS. + * + * On failure information about the error will be printed and a breakpoint hit. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. + */ +#define AssertFatalRCSuccess(rc) AssertFatalMsg((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + + +/** @def AssertPtr + * Asserts that a pointer is valid. + * + * @param pv The pointer. + */ +#define AssertPtr(pv) AssertMsg(RT_VALID_PTR(pv), ("%p\n", (pv))) + +/** @def AssertPtrReturn + * Asserts that a pointer is valid. + * + * @param pv The pointer. + * @param rcRet What is to be presented to return. + */ +#define AssertPtrReturn(pv, rcRet) AssertMsgReturn(RT_VALID_PTR(pv), ("%p\n", (pv)), rcRet) + +/** @def AssertPtrReturnVoid + * Asserts that a pointer is valid. + * + * @param pv The pointer. + */ +#define AssertPtrReturnVoid(pv) AssertMsgReturnVoid(RT_VALID_PTR(pv), ("%p\n", (pv))) + +/** @def AssertPtrReturnStmt + * Asserts that a pointer is valid. + * + * @param pv The pointer. + * @param stmt Statement to execute before returninig in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + */ +#define AssertPtrReturnStmt(pv, stmt, rcRet) AssertMsgReturnStmt(RT_VALID_PTR(pv), ("%p\n", (pv)), stmt, rcRet) + +/** @def AssertPtrReturnVoidStmt + * Asserts that a pointer is valid. + * + * @param pv The pointer. + * @param stmt Statement to execute before returninig in case of a failed + * assertion. + */ +#define AssertPtrReturnVoidStmt(pv, stmt) AssertMsgReturnVoid(RT_VALID_PTR(pv), ("%p\n", (pv)), stmt) + +/** @def AssertPtrBreak + * Asserts that a pointer is valid. + * + * @param pv The pointer. + */ +#define AssertPtrBreak(pv) AssertMsgBreak(RT_VALID_PTR(pv), ("%p\n", (pv))) + +/** @def AssertPtrBreakStmt + * Asserts that a pointer is valid. + * + * @param pv The pointer. + * @param stmt Statement to execute before break in case of a failed assertion. + */ +#define AssertPtrBreakStmt(pv, stmt) AssertMsgBreakStmt(RT_VALID_PTR(pv), ("%p\n", (pv)), stmt) + +/** @def AssertPtrNull + * Asserts that a pointer is valid or NULL. + * + * @param pv The pointer. + */ +#define AssertPtrNull(pv) AssertMsg(RT_VALID_PTR(pv) || (pv) == NULL, ("%p\n", (pv))) + +/** @def AssertPtrNullReturn + * Asserts that a pointer is valid or NULL. + * + * @param pv The pointer. + * @param rcRet What is to be presented to return. + */ +#define AssertPtrNullReturn(pv, rcRet) AssertMsgReturn(RT_VALID_PTR(pv) || (pv) == NULL, ("%p\n", (pv)), rcRet) + +/** @def AssertPtrNullReturnVoid + * Asserts that a pointer is valid or NULL. + * + * @param pv The pointer. + */ +#define AssertPtrNullReturnVoid(pv) AssertMsgReturnVoid(RT_VALID_PTR(pv) || (pv) == NULL, ("%p\n", (pv))) + +/** @def AssertPtrNullBreak + * Asserts that a pointer is valid or NULL. + * + * @param pv The pointer. + */ +#define AssertPtrNullBreak(pv) AssertMsgBreak(RT_VALID_PTR(pv) || (pv) == NULL, ("%p\n", (pv))) + +/** @def AssertPtrNullBreakStmt + * Asserts that a pointer is valid or NULL. + * + * @param pv The pointer. + * @param stmt Statement to execute before break in case of a failed assertion. + */ +#define AssertPtrNullBreakStmt(pv, stmt) AssertMsgBreakStmt(RT_VALID_PTR(pv) || (pv) == NULL, ("%p\n", (pv)), stmt) + +/** @def AssertGCPhys32 + * Asserts that the high dword of a physical address is zero + * + * @param GCPhys The address (RTGCPHYS). + */ +#define AssertGCPhys32(GCPhys) AssertMsg(VALID_PHYS32(GCPhys), ("%RGp\n", (RTGCPHYS)(GCPhys))) + +/** @def AssertGCPtr32 + * Asserts that the high dword of a physical address is zero + * + * @param GCPtr The address (RTGCPTR). + */ +#if GC_ARCH_BITS == 32 +# define AssertGCPtr32(GCPtr) do { } while (0) +#else +# define AssertGCPtr32(GCPtr) AssertMsg(!((GCPtr) & UINT64_C(0xffffffff00000000)), ("%RGv\n", GCPtr)) +#endif + +/** @def AssertForEach + * Equivalent to Assert for each value of the variable from the starting + * value to the finishing one. + * + * @param var Name of the counter variable. + * @param vartype Type of the counter variable. + * @param first Lowest inclusive value of the counter variable. + * This must be free from side effects. + * @param end Highest exclusive value of the counter variable. + * This must be free from side effects. + * @param expr Expression which should be true for each value of @a var. + */ +#define AssertForEach(var, vartype, first, end, expr) \ + do { \ + vartype var; \ + Assert((first) == (first) && (end) == (end)); /* partial check for side effects */ \ + for (var = (first); var < (end); var++) \ + AssertMsg(expr, ("%s = %#RX64 (%RI64)", #var, (uint64_t)var, (int64_t)var)); \ + } while (0) + +#ifdef RT_OS_WINDOWS + +/** @def AssertNtStatus + * Asserts that the NT_SUCCESS() returns true for the given NTSTATUS value. + * + * @param a_rcNt The NTSTATUS to check. Will be evaluated twice and + * subjected to NOREF(). + * @sa AssertRC() + */ +# define AssertNtStatus(a_rcNt) \ + do { AssertMsg(NT_SUCCESS(a_rcNt), ("%#x\n", (a_rcNt))); NOREF(a_rcNt); } while (0) + +/** @def AssertNtStatusSuccess + * Asserts that the given NTSTATUS value equals STATUS_SUCCESS. + * + * @param a_rcNt The NTSTATUS to check. Will be evaluated twice and + * subjected to NOREF(). + * @sa AssertRCSuccess() + */ +# define AssertNtStatusSuccess(a_rcNt) \ + do { AssertMsg((a_rcNt) == STATUS_SUCCESS, ("%#x\n", (a_rcNt))); NOREF(a_rcNt); } while (0) + +#endif /* RT_OS_WINDOWS */ + +/** @} */ + +/** @} */ + +#endif /* !IPRT_INCLUDED_assert_h */ + diff --git a/include/iprt/assertcompile.h b/include/iprt/assertcompile.h new file mode 100644 index 00000000..dae0840d --- /dev/null +++ b/include/iprt/assertcompile.h @@ -0,0 +1,263 @@ +/** @file + * IPRT - Compile Time Assertions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_assertcompile_h +#define IPRT_INCLUDED_assertcompile_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> + +/** @defgroup grp_rt_assert_compile Compile time assertions + * @ingroup grp_rt + * + * These assertions are used to check structure sizes, member/size alignments + * and similar compile time expressions. + * + * @remarks As you might have noticed, the AssertCompile macros don't follow the + * coding guidelines wrt to macros supposedly being all uppercase and + * underscored. For various reasons they don't, and nobody has + * complained yet. + * + * @{ + */ + +/** + * RTASSERTTYPE is the type the AssertCompile() macro redefines. + * It has no other function and shouldn't be used. + * Visual C++ uses this. + */ +typedef int RTASSERTTYPE[1]; + +/** + * RTASSERTVAR is the type the AssertCompile() macro redefines. + * It has no other function and shouldn't be used. + * + * GCC and IBM VisualAge C/C++ uses this. GCC doesn't technicaly need this + * global scope one as it declares it for each use, however things get + * complicated in C++ code where most GCC and clang versions gets upset by mixed + * "C" and "C++" versions of the symbol when using inside and outside + * RT_C_DECLS_BEGIN/END. The GCC 3.3.x and 3.4.x versions we use, OTOH will + * always complain about unused RTASSERTVAR for each AssertCompileNS use in a + * function if we declare it globally, so we don't do it for those, but we do + * for 4.x+ to prevent linkage confusion. + */ +#if !defined(__cplusplus) || !defined(__GNUC__) +extern int RTASSERTVAR[1]; +#elif RT_GNUC_PREREQ(4, 0) || defined(__clang_major__) /* Not sure when they fixed the global scoping __unused__/whatever problem. */ +RT_C_DECLS_BEGIN +extern int RTASSERTVAR[1]; +RT_C_DECLS_END +#endif + +/** @def RTASSERT_HAVE_STATIC_ASSERT + * Indicates that the compiler implements static_assert(expr, msg). + */ +#ifdef _MSC_VER +# if _MSC_VER >= 1600 && defined(__cplusplus) +# define RTASSERT_HAVE_STATIC_ASSERT +# endif +#endif +#if defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define RTASSERT_HAVE_STATIC_ASSERT +#endif +#if RT_CLANG_PREREQ(6, 0) +# if __has_feature(cxx_static_assert) || __has_feature(c_static_assert) +# define RTASSERT_HAVE_STATIC_ASSERT +# endif +#endif +#ifdef DOXYGEN_RUNNING +# define RTASSERT_HAVE_STATIC_ASSERT +#endif + +/** @def AssertCompileNS + * Asserts that a compile-time expression is true. If it's not break the build. + * + * This differs from AssertCompile in that it accepts some more expressions + * than what C++0x allows - NS = Non-standard. + * + * @param expr Expression which should be true. + */ +#ifdef __GNUC__ +# define AssertCompileNS(expr) AssertCompileNS2(expr,RTASSERTVAR) +# define AssertCompileNS2(expr,a_VarName) extern int a_VarName[ 1 ] __attribute__((__unused__)), \ + a_VarName[(expr) ? 1 : 0] __attribute__((__unused__)) +#elif defined(__IBMC__) || defined(__IBMCPP__) +# define AssertCompileNS(expr) extern int RTASSERTVAR[(expr) ? 1 : 0] +#else +# define AssertCompileNS(expr) typedef int RTASSERTTYPE[(expr) ? 1 : 0] +#endif + +/** @def AssertCompile + * Asserts that a C++0x compile-time expression is true. If it's not break the + * build. + * @param expr Expression which should be true. + */ +#ifdef RTASSERT_HAVE_STATIC_ASSERT +# ifdef __cplusplus +# define AssertCompile(expr) static_assert(!!(expr), #expr) +# else +# define AssertCompile(expr) _Static_assert(!!(expr), #expr) +# endif +#else +# define AssertCompile(expr) AssertCompileNS(expr) +#endif + +/** @def RTASSERT_OFFSET_OF() + * A offsetof() macro suitable for compile time assertions. + * Both GCC v4 and VisualAge for C++ v3.08 has trouble using RT_OFFSETOF. + */ +#if defined(__GNUC__) +# if __GNUC__ >= 4 +# define RTASSERT_OFFSET_OF(a_Type, a_Member) __builtin_offsetof(a_Type, a_Member) +# else +# define RTASSERT_OFFSET_OF(a_Type, a_Member) RT_OFFSETOF(a_Type, a_Member) +# endif +#elif (defined(__IBMC__) || defined(__IBMCPP__)) && defined(RT_OS_OS2) +# define RTASSERT_OFFSET_OF(a_Type, a_Member) __offsetof(a_Type, a_Member) +#elif (defined(__WATCOMC__) && defined(__cplusplus)) +# define RTASSERT_OFFSET_OF(a_Type, a_Member) __offsetof(a_Type, a_Member) +#else +# define RTASSERT_OFFSET_OF(a_Type, a_Member) RT_OFFSETOF(a_Type, a_Member) +#endif + + +/** @def AssertCompileSize + * Asserts a size at compile. + * @param type The type. + * @param size The expected type size. + */ +#define AssertCompileSize(type, size) \ + AssertCompile(sizeof(type) == (size)) + +/** @def AssertCompileSizeAlignment + * Asserts a size alignment at compile. + * @param type The type. + * @param align The size alignment to assert. + */ +#define AssertCompileSizeAlignment(type, align) \ + AssertCompile(!(sizeof(type) & ((align) - 1))) + +/** @def AssertCompileMemberSize + * Asserts a member offset alignment at compile. + * @param type The type. + * @param member The member. + * @param size The member size to assert. + */ +#define AssertCompileMemberSize(type, member, size) \ + AssertCompile(RT_SIZEOFMEMB(type, member) == (size)) + +/** @def AssertCompileMemberSizeAlignment + * Asserts a member size alignment at compile. + * @param type The type. + * @param member The member. + * @param align The member size alignment to assert. + */ +#define AssertCompileMemberSizeAlignment(type, member, align) \ + AssertCompile(!(RT_SIZEOFMEMB(type, member) & ((align) - 1))) + +/** @def AssertCompileMemberAlignment + * Asserts a member offset alignment at compile. + * @param type The type. + * @param member The member. + * @param align The member offset alignment to assert. + */ +#define AssertCompileMemberAlignment(type, member, align) \ + AssertCompile(!(RTASSERT_OFFSET_OF(type, member) & ((align) - 1))) + +/** @def AssertCompileMemberOffset + * Asserts an offset of a structure member at compile. + * @param type The type. + * @param member The member. + * @param off The expected offset. + */ +#define AssertCompileMemberOffset(type, member, off) \ + AssertCompile(RTASSERT_OFFSET_OF(type, member) == (off)) + +/** @def AssertCompile2MemberOffsets + * Asserts that two (sub-structure) members in union have the same offset. + * @param type The type. + * @param member1 The first member. + * @param member2 The second member. + */ +#define AssertCompile2MemberOffsets(type, member1, member2) \ + AssertCompile(RTASSERT_OFFSET_OF(type, member1) == RTASSERT_OFFSET_OF(type, member2)) + +/** @def AssertCompileAdjacentMembers + * Asserts that two structure members are adjacent. + * @param type The type. + * @param member1 The first member. + * @param member2 The second member. + */ +#define AssertCompileAdjacentMembers(type, member1, member2) \ + AssertCompile(RTASSERT_OFFSET_OF(type, member1) + RT_SIZEOFMEMB(type, member1) == RTASSERT_OFFSET_OF(type, member2)) + +/** @def AssertCompileMembersAtSameOffset + * Asserts that members of two different structures are at the same offset. + * @param type1 The first type. + * @param member1 The first member. + * @param type2 The second type. + * @param member2 The second member. + */ +#define AssertCompileMembersAtSameOffset(type1, member1, type2, member2) \ + AssertCompile(RTASSERT_OFFSET_OF(type1, member1) == RTASSERT_OFFSET_OF(type2, member2)) + +/** @def AssertCompileMembersSameSize + * Asserts that members of two different structures have the same size. + * @param type1 The first type. + * @param member1 The first member. + * @param type2 The second type. + * @param member2 The second member. + */ +#define AssertCompileMembersSameSize(type1, member1, type2, member2) \ + AssertCompile(RT_SIZEOFMEMB(type1, member1) == RT_SIZEOFMEMB(type2, member2)) + +/** @def AssertCompileMembersSameSizeAndOffset + * Asserts that members of two different structures have the same size and are + * at the same offset. + * @param type1 The first type. + * @param member1 The first member. + * @param type2 The second type. + * @param member2 The second member. + */ +#define AssertCompileMembersSameSizeAndOffset(type1, member1, type2, member2) \ + AssertCompile( RTASSERT_OFFSET_OF(type1, member1) == RTASSERT_OFFSET_OF(type2, member2) \ + && RT_SIZEOFMEMB(type1, member1) == RT_SIZEOFMEMB(type2, member2)) + +/** @} */ + +#endif /* !IPRT_INCLUDED_assertcompile_h */ + diff --git a/include/iprt/avl.h b/include/iprt/avl.h new file mode 100644 index 00000000..af51d0e6 --- /dev/null +++ b/include/iprt/avl.h @@ -0,0 +1,1195 @@ +/** @file + * IPRT - AVL Trees. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_avl_h +#define IPRT_INCLUDED_avl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_avl RTAvl - AVL Trees + * @ingroup grp_rt + * @{ + */ + + +/** @name AVL tree of void pointers. + * @{ + */ + +/** + * AVL key type + */ +typedef void * AVLPVKEY; + +/** + * AVL Core node. + */ +typedef struct _AVLPVNodeCore +{ + AVLPVKEY Key; /** Key value. */ + struct _AVLPVNodeCore *pLeft; /** Pointer to left leaf node. */ + struct _AVLPVNodeCore *pRight; /** Pointer to right leaf node. */ + unsigned char uchHeight; /** Height of this tree: max(height(left), height(right)) + 1 */ +} AVLPVNODECORE, *PAVLPVNODECORE, **PPAVLPVNODECORE; + +/** A tree with void pointer keys. */ +typedef PAVLPVNODECORE AVLPVTREE; +/** Pointer to a tree with void pointer keys. */ +typedef PPAVLPVNODECORE PAVLPVTREE; + +/** Callback function for AVLPVDoWithAll(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLPVCALLBACK,(PAVLPVNODECORE, void *)); +/** Pointer to callback function for AVLPVDoWithAll(). */ +typedef AVLPVCALLBACK *PAVLPVCALLBACK; + +/* + * Functions. + */ +RTDECL(bool) RTAvlPVInsert(PAVLPVTREE ppTree, PAVLPVNODECORE pNode); +RTDECL(PAVLPVNODECORE) RTAvlPVRemove(PAVLPVTREE ppTree, AVLPVKEY Key); +RTDECL(PAVLPVNODECORE) RTAvlPVGet(PAVLPVTREE ppTree, AVLPVKEY Key); +RTDECL(PAVLPVNODECORE) RTAvlPVGetBestFit(PAVLPVTREE ppTree, AVLPVKEY Key, bool fAbove); +RTDECL(PAVLPVNODECORE) RTAvlPVRemoveBestFit(PAVLPVTREE ppTree, AVLPVKEY Key, bool fAbove); +RTDECL(int) RTAvlPVDoWithAll(PAVLPVTREE ppTree, int fFromLeft, PAVLPVCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlPVDestroy(PAVLPVTREE ppTree, PAVLPVCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of unsigned long. + * @{ + */ + +/** + * AVL key type + */ +typedef unsigned long AVLULKEY; + +/** + * AVL Core node. + */ +typedef struct _AVLULNodeCore +{ + AVLULKEY Key; /** Key value. */ + struct _AVLULNodeCore *pLeft; /** Pointer to left leaf node. */ + struct _AVLULNodeCore *pRight; /** Pointer to right leaf node. */ + unsigned char uchHeight; /** Height of this tree: max(height(left), height(right)) + 1 */ +} AVLULNODECORE, *PAVLULNODECORE, **PPAVLULNODECORE; + + +/** Callback function for AVLULDoWithAll(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLULCALLBACK,(PAVLULNODECORE, void*)); +/** Pointer to callback function for AVLULDoWithAll(). */ +typedef AVLULCALLBACK *PAVLULCALLBACK; + + +/* + * Functions. + */ +RTDECL(bool) RTAvlULInsert(PPAVLULNODECORE ppTree, PAVLULNODECORE pNode); +RTDECL(PAVLULNODECORE) RTAvlULRemove(PPAVLULNODECORE ppTree, AVLULKEY Key); +RTDECL(PAVLULNODECORE) RTAvlULGet(PPAVLULNODECORE ppTree, AVLULKEY Key); +RTDECL(PAVLULNODECORE) RTAvlULGetBestFit(PPAVLULNODECORE ppTree, AVLULKEY Key, bool fAbove); +RTDECL(PAVLULNODECORE) RTAvlULRemoveBestFit(PPAVLULNODECORE ppTree, AVLULKEY Key, bool fAbove); +RTDECL(int) RTAvlULDoWithAll(PPAVLULNODECORE ppTree, int fFromLeft, PAVLULCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlULDestroy(PPAVLULNODECORE pTree, PAVLULCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + + +/** @name AVL tree of void pointer ranges. + * @{ + */ + +/** + * AVL key type + */ +typedef void *AVLRPVKEY; + +/** + * AVL Core node. + */ +typedef struct AVLRPVNodeCore +{ + AVLRPVKEY Key; /**< First key value in the range (inclusive). */ + AVLRPVKEY KeyLast; /**< Last key value in the range (inclusive). */ + struct AVLRPVNodeCore *pLeft; /**< Pointer to left leaf node. */ + struct AVLRPVNodeCore *pRight; /**< Pointer to right leaf node. */ + unsigned char uchHeight; /**< Height of this tree: max(height(left), height(right)) + 1 */ +} AVLRPVNODECORE, *PAVLRPVNODECORE, **PPAVLRPVNODECORE; + +/** A tree with void pointer keys. */ +typedef PAVLRPVNODECORE AVLRPVTREE; +/** Pointer to a tree with void pointer keys. */ +typedef PPAVLRPVNODECORE PAVLRPVTREE; + +/** Callback function for AVLPVDoWithAll(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLRPVCALLBACK,(PAVLRPVNODECORE, void *)); +/** Pointer to callback function for AVLPVDoWithAll(). */ +typedef AVLRPVCALLBACK *PAVLRPVCALLBACK; + +/* + * Functions. + */ +RTDECL(bool) RTAvlrPVInsert(PAVLRPVTREE ppTree, PAVLRPVNODECORE pNode); +RTDECL(PAVLRPVNODECORE) RTAvlrPVRemove(PAVLRPVTREE ppTree, AVLRPVKEY Key); +RTDECL(PAVLRPVNODECORE) RTAvlrPVGet(PAVLRPVTREE ppTree, AVLRPVKEY Key); +RTDECL(PAVLRPVNODECORE) RTAvlrPVRangeGet(PAVLRPVTREE ppTree, AVLRPVKEY Key); +RTDECL(PAVLRPVNODECORE) RTAvlrPVRangeRemove(PAVLRPVTREE ppTree, AVLRPVKEY Key); +RTDECL(PAVLRPVNODECORE) RTAvlrPVGetBestFit(PAVLRPVTREE ppTree, AVLRPVKEY Key, bool fAbove); +RTDECL(PAVLRPVNODECORE) RTAvlrPVRemoveBestFit(PAVLRPVTREE ppTree, AVLRPVKEY Key, bool fAbove); +RTDECL(int) RTAvlrPVDoWithAll(PAVLRPVTREE ppTree, int fFromLeft, PAVLRPVCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlrPVDestroy(PAVLRPVTREE ppTree, PAVLRPVCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + + +/** @name AVL tree of uint32_t + * @{ + */ + +/** AVL key type. */ +typedef uint32_t AVLU32KEY; + +/** AVL Core node. */ +typedef struct _AVLU32NodeCore +{ + struct _AVLU32NodeCore *pLeft; /**< Pointer to left leaf node. */ + struct _AVLU32NodeCore *pRight; /**< Pointer to right leaf node. */ + AVLU32KEY Key; /**< Key value. */ + unsigned char uchHeight; /**< Height of this tree: max(height(left), height(right)) + 1 */ +} AVLU32NODECORE, *PAVLU32NODECORE, **PPAVLU32NODECORE; + +/** A tree with uint32_t keys. */ +typedef PAVLU32NODECORE AVLU32TREE; +/** Pointer to a tree with uint32_t keys. */ +typedef PPAVLU32NODECORE PAVLU32TREE; + +/** Callback function for AVLU32DoWithAll() & AVLU32Destroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLU32CALLBACK,(PAVLU32NODECORE, void*)); +/** Pointer to callback function for AVLU32DoWithAll() & AVLU32Destroy(). */ +typedef AVLU32CALLBACK *PAVLU32CALLBACK; + + +/* + * Functions. + */ +RTDECL(bool) RTAvlU32Insert(PAVLU32TREE pTree, PAVLU32NODECORE pNode); +RTDECL(PAVLU32NODECORE) RTAvlU32Remove(PAVLU32TREE pTree, AVLU32KEY Key); +RTDECL(PAVLU32NODECORE) RTAvlU32Get(PAVLU32TREE pTree, AVLU32KEY Key); +RTDECL(PAVLU32NODECORE) RTAvlU32GetBestFit(PAVLU32TREE pTree, AVLU32KEY Key, bool fAbove); +RTDECL(PAVLU32NODECORE) RTAvlU32RemoveBestFit(PAVLU32TREE pTree, AVLU32KEY Key, bool fAbove); +RTDECL(int) RTAvlU32DoWithAll(PAVLU32TREE pTree, int fFromLeft, PAVLU32CALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlU32Destroy(PAVLU32TREE pTree, PAVLU32CALLBACK pfnCallBack, void *pvParam); + +/** @} */ + +/** @name AVL tree of uint32_t, offset based + * @{ + */ + +/** + * AVL uint32_t type for the relative offset pointer scheme. + */ +typedef int32_t AVLOU32; + +typedef uint32_t AVLOU32KEY; + +/** + * AVL Core node. + */ +typedef struct _AVLOU32NodeCore +{ + /** Key value. */ + AVLOU32KEY Key; + /** Offset to the left leaf node, relative to this field. */ + AVLOU32 pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLOU32 pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLOU32NODECORE, *PAVLOU32NODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLOU32 AVLOU32TREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLOU32TREE *PAVLOU32TREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLOU32TREE *PPAVLOU32NODECORE; + +/** Callback function for RTAvloU32DoWithAll(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLOU32CALLBACK,(PAVLOU32NODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvloU32DoWithAll(). */ +typedef AVLOU32CALLBACK *PAVLOU32CALLBACK; + +RTDECL(bool) RTAvloU32Insert(PAVLOU32TREE pTree, PAVLOU32NODECORE pNode); +RTDECL(PAVLOU32NODECORE) RTAvloU32Remove(PAVLOU32TREE pTree, AVLOU32KEY Key); +RTDECL(PAVLOU32NODECORE) RTAvloU32Get(PAVLOU32TREE pTree, AVLOU32KEY Key); +RTDECL(int) RTAvloU32DoWithAll(PAVLOU32TREE pTree, int fFromLeft, PAVLOU32CALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLOU32NODECORE) RTAvloU32GetBestFit(PAVLOU32TREE ppTree, AVLOU32KEY Key, bool fAbove); +RTDECL(PAVLOU32NODECORE) RTAvloU32RemoveBestFit(PAVLOU32TREE ppTree, AVLOU32KEY Key, bool fAbove); +RTDECL(int) RTAvloU32Destroy(PAVLOU32TREE pTree, PAVLOU32CALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of uint32_t, list duplicates. + * @{ + */ + +/** AVL key type. */ +typedef uint32_t AVLLU32KEY; + +/** AVL Core node. */ +typedef struct _AVLLU32NodeCore +{ + AVLLU32KEY Key; /**< Key value. */ + unsigned char uchHeight; /**< Height of this tree: max(height(left), height(right)) + 1 */ + struct _AVLLU32NodeCore *pLeft; /**< Pointer to left leaf node. */ + struct _AVLLU32NodeCore *pRight; /**< Pointer to right leaf node. */ + struct _AVLLU32NodeCore *pList; /**< Pointer to next node with the same key. */ +} AVLLU32NODECORE, *PAVLLU32NODECORE, **PPAVLLU32NODECORE; + +/** Callback function for RTAvllU32DoWithAll() & RTAvllU32Destroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLLU32CALLBACK,(PAVLLU32NODECORE, void*)); +/** Pointer to callback function for RTAvllU32DoWithAll() & RTAvllU32Destroy(). */ +typedef AVLLU32CALLBACK *PAVLLU32CALLBACK; + + +/* + * Functions. + */ +RTDECL(bool) RTAvllU32Insert(PPAVLLU32NODECORE ppTree, PAVLLU32NODECORE pNode); +RTDECL(PAVLLU32NODECORE) RTAvllU32Remove(PPAVLLU32NODECORE ppTree, AVLLU32KEY Key); +RTDECL(PAVLLU32NODECORE) RTAvllU32RemoveNode(PPAVLLU32NODECORE ppTree, PAVLLU32NODECORE pNode); +RTDECL(PAVLLU32NODECORE) RTAvllU32Get(PPAVLLU32NODECORE ppTree, AVLLU32KEY Key); +RTDECL(PAVLLU32NODECORE) RTAvllU32GetBestFit(PPAVLLU32NODECORE ppTree, AVLLU32KEY Key, bool fAbove); +RTDECL(PAVLLU32NODECORE) RTAvllU32RemoveBestFit(PPAVLLU32NODECORE ppTree, AVLLU32KEY Key, bool fAbove); +RTDECL(int) RTAvllU32DoWithAll(PPAVLLU32NODECORE ppTree, int fFromLeft, PAVLLU32CALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvllU32Destroy(PPAVLLU32NODECORE pTree, PAVLLU32CALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of uint64_t + * @{ + */ + +/** AVL key type. */ +typedef uint64_t AVLU64KEY; + +/** AVL Core node. */ +typedef struct _AVLU64NodeCore +{ + struct _AVLU64NodeCore *pLeft; /**< Pointer to left leaf node. */ + struct _AVLU64NodeCore *pRight; /**< Pointer to right leaf node. */ + AVLU64KEY Key; /**< Key value. */ + unsigned char uchHeight; /**< Height of this tree: max(height(left), height(right)) + 1 */ +} AVLU64NODECORE, *PAVLU64NODECORE, **PPAVLU64NODECORE; + +/** A tree with uint64_t keys. */ +typedef PAVLU64NODECORE AVLU64TREE; +/** Pointer to a tree with uint64_t keys. */ +typedef PPAVLU64NODECORE PAVLU64TREE; + +/** Callback function for AVLU64DoWithAll() & AVLU64Destroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLU64CALLBACK,(PAVLU64NODECORE, void*)); +/** Pointer to callback function for AVLU64DoWithAll() & AVLU64Destroy(). */ +typedef AVLU64CALLBACK *PAVLU64CALLBACK; + + +/* + * Functions. + */ +RTDECL(bool) RTAvlU64Insert(PAVLU64TREE pTree, PAVLU64NODECORE pNode); +RTDECL(PAVLU64NODECORE) RTAvlU64Remove(PAVLU64TREE pTree, AVLU64KEY Key); +RTDECL(PAVLU64NODECORE) RTAvlU64Get(PAVLU64TREE pTree, AVLU64KEY Key); +RTDECL(PAVLU64NODECORE) RTAvlU64GetBestFit(PAVLU64TREE pTree, AVLU64KEY Key, bool fAbove); +RTDECL(PAVLU64NODECORE) RTAvlU64RemoveBestFit(PAVLU64TREE pTree, AVLU64KEY Key, bool fAbove); +RTDECL(int) RTAvlU64DoWithAll(PAVLU64TREE pTree, int fFromLeft, PAVLU64CALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlU64Destroy(PAVLU64TREE pTree, PAVLU64CALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of uint64_t ranges. + * @{ + */ + +/** + * AVL key type + */ +typedef uint64_t AVLRU64KEY; + +/** + * AVL Core node. + */ +typedef struct AVLRU64NodeCore +{ + AVLRU64KEY Key; /**< First key value in the range (inclusive). */ + AVLRU64KEY KeyLast; /**< Last key value in the range (inclusive). */ + struct AVLRU64NodeCore *pLeft; /**< Pointer to left leaf node. */ + struct AVLRU64NodeCore *pRight; /**< Pointer to right leaf node. */ + unsigned char uchHeight; /**< Height of this tree: max(height(left), height(right)) + 1 */ +} AVLRU64NODECORE, *PAVLRU64NODECORE, **PPAVLRU64NODECORE; + +/** A tree with uint64_t keys. */ +typedef PAVLRU64NODECORE AVLRU64TREE; +/** Pointer to a tree with uint64_t keys. */ +typedef PPAVLRU64NODECORE PAVLRU64TREE; + +/** Callback function for AVLRU64DoWithAll(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLRU64CALLBACK,(PAVLRU64NODECORE, void *)); +/** Pointer to callback function for AVLU64DoWithAll(). */ +typedef AVLRU64CALLBACK *PAVLRU64CALLBACK; + +/* + * Functions. + */ +RTDECL(bool) RTAvlrU64Insert(PAVLRU64TREE ppTree, PAVLRU64NODECORE pNode); +RTDECL(PAVLRU64NODECORE) RTAvlrU64Remove(PAVLRU64TREE ppTree, AVLRU64KEY Key); +RTDECL(PAVLRU64NODECORE) RTAvlrU64Get(PAVLRU64TREE ppTree, AVLRU64KEY Key); +RTDECL(PAVLRU64NODECORE) RTAvlrU64RangeGet(PAVLRU64TREE ppTree, AVLRU64KEY Key); +RTDECL(PAVLRU64NODECORE) RTAvlrU64RangeRemove(PAVLRU64TREE ppTree, AVLRU64KEY Key); +RTDECL(PAVLRU64NODECORE) RTAvlrU64GetBestFit(PAVLRU64TREE ppTree, AVLRU64KEY Key, bool fAbove); +RTDECL(PAVLRU64NODECORE) RTAvlrU64RemoveBestFit(PAVLRU64TREE ppTree, AVLRU64KEY Key, bool fAbove); +RTDECL(int) RTAvlrU64DoWithAll(PAVLRU64TREE ppTree, int fFromLeft, PAVLRU64CALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlrU64Destroy(PAVLRU64TREE ppTree, PAVLRU64CALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + + +/** @name AVL tree of RTGCPHYSes - using relative offsets internally. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef int32_t AVLOGCPHYS; + +/** + * AVL Core node. + */ +typedef struct _AVLOGCPhysNodeCore +{ + /** Key value. */ + RTGCPHYS Key; + /** Offset to the left leaf node, relative to this field. */ + AVLOGCPHYS pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLOGCPHYS pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; + /** Padding */ + unsigned char Padding[7]; +} AVLOGCPHYSNODECORE, *PAVLOGCPHYSNODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLOGCPHYS AVLOGCPHYSTREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLOGCPHYSTREE *PAVLOGCPHYSTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLOGCPHYSTREE *PPAVLOGCPHYSNODECORE; + +/** Callback function for RTAvloGCPhysDoWithAll() and RTAvloGCPhysDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLOGCPHYSCALLBACK,(PAVLOGCPHYSNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvloGCPhysDoWithAll() and RTAvloGCPhysDestroy(). */ +typedef AVLOGCPHYSCALLBACK *PAVLOGCPHYSCALLBACK; + +RTDECL(bool) RTAvloGCPhysInsert(PAVLOGCPHYSTREE pTree, PAVLOGCPHYSNODECORE pNode); +RTDECL(PAVLOGCPHYSNODECORE) RTAvloGCPhysRemove(PAVLOGCPHYSTREE pTree, RTGCPHYS Key); +RTDECL(PAVLOGCPHYSNODECORE) RTAvloGCPhysGet(PAVLOGCPHYSTREE pTree, RTGCPHYS Key); +RTDECL(int) RTAvloGCPhysDoWithAll(PAVLOGCPHYSTREE pTree, int fFromLeft, PAVLOGCPHYSCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLOGCPHYSNODECORE) RTAvloGCPhysGetBestFit(PAVLOGCPHYSTREE ppTree, RTGCPHYS Key, bool fAbove); +RTDECL(PAVLOGCPHYSNODECORE) RTAvloGCPhysRemoveBestFit(PAVLOGCPHYSTREE ppTree, RTGCPHYS Key, bool fAbove); +RTDECL(int) RTAvloGCPhysDestroy(PAVLOGCPHYSTREE pTree, PAVLOGCPHYSCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of RTGCPHYS ranges - using relative offsets internally. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef int32_t AVLROGCPHYS; + +/** + * AVL Core node. + */ +typedef struct _AVLROGCPhysNodeCore +{ + /** First key value in the range (inclusive). */ + RTGCPHYS Key; + /** Last key value in the range (inclusive). */ + RTGCPHYS KeyLast; + /** Offset to the left leaf node, relative to this field. */ + AVLROGCPHYS pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLROGCPHYS pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; + /** Padding */ + unsigned char Padding[7]; +} AVLROGCPHYSNODECORE, *PAVLROGCPHYSNODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLROGCPHYS AVLROGCPHYSTREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLROGCPHYSTREE *PAVLROGCPHYSTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLROGCPHYSTREE *PPAVLROGCPHYSNODECORE; + +/** Callback function for RTAvlroGCPhysDoWithAll() and RTAvlroGCPhysDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLROGCPHYSCALLBACK,(PAVLROGCPHYSNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlroGCPhysDoWithAll() and RTAvlroGCPhysDestroy(). */ +typedef AVLROGCPHYSCALLBACK *PAVLROGCPHYSCALLBACK; + +RTDECL(bool) RTAvlroGCPhysInsert(PAVLROGCPHYSTREE pTree, PAVLROGCPHYSNODECORE pNode); +RTDECL(PAVLROGCPHYSNODECORE) RTAvlroGCPhysRemove(PAVLROGCPHYSTREE pTree, RTGCPHYS Key); +RTDECL(PAVLROGCPHYSNODECORE) RTAvlroGCPhysGet(PAVLROGCPHYSTREE pTree, RTGCPHYS Key); +RTDECL(PAVLROGCPHYSNODECORE) RTAvlroGCPhysRangeGet(PAVLROGCPHYSTREE pTree, RTGCPHYS Key); +RTDECL(PAVLROGCPHYSNODECORE) RTAvlroGCPhysRangeRemove(PAVLROGCPHYSTREE pTree, RTGCPHYS Key); +RTDECL(PAVLROGCPHYSNODECORE) RTAvlroGCPhysGetBestFit(PAVLROGCPHYSTREE ppTree, RTGCPHYS Key, bool fAbove); +RTDECL(int) RTAvlroGCPhysDoWithAll(PAVLROGCPHYSTREE pTree, int fFromLeft, PAVLROGCPHYSCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlroGCPhysDestroy(PAVLROGCPHYSTREE pTree, PAVLROGCPHYSCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLROGCPHYSNODECORE) RTAvlroGCPhysGetRoot(PAVLROGCPHYSTREE pTree); +RTDECL(PAVLROGCPHYSNODECORE) RTAvlroGCPhysGetLeft(PAVLROGCPHYSNODECORE pNode); +RTDECL(PAVLROGCPHYSNODECORE) RTAvlroGCPhysGetRight(PAVLROGCPHYSNODECORE pNode); + +/** @} */ + + +/** @name AVL tree of RTGCPTRs. + * @{ + */ + +/** + * AVL Core node. + */ +typedef struct _AVLGCPtrNodeCore +{ + /** Key value. */ + RTGCPTR Key; + /** Pointer to the left node. */ + struct _AVLGCPtrNodeCore *pLeft; + /** Pointer to the right node. */ + struct _AVLGCPtrNodeCore *pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLGCPTRNODECORE, *PAVLGCPTRNODECORE, **PPAVLGCPTRNODECORE; + +/** A tree of RTGCPTR keys. */ +typedef PAVLGCPTRNODECORE AVLGCPTRTREE; +/** Pointer to a tree of RTGCPTR keys. */ +typedef PPAVLGCPTRNODECORE PAVLGCPTRTREE; + +/** Callback function for RTAvlGCPtrDoWithAll(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLGCPTRCALLBACK,(PAVLGCPTRNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlGCPtrDoWithAll(). */ +typedef AVLGCPTRCALLBACK *PAVLGCPTRCALLBACK; + +RTDECL(bool) RTAvlGCPtrInsert(PAVLGCPTRTREE pTree, PAVLGCPTRNODECORE pNode); +RTDECL(PAVLGCPTRNODECORE) RTAvlGCPtrRemove(PAVLGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLGCPTRNODECORE) RTAvlGCPtrGet(PAVLGCPTRTREE pTree, RTGCPTR Key); +RTDECL(int) RTAvlGCPtrDoWithAll(PAVLGCPTRTREE pTree, int fFromLeft, PAVLGCPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLGCPTRNODECORE) RTAvlGCPtrGetBestFit(PAVLGCPTRTREE ppTree, RTGCPTR Key, bool fAbove); +RTDECL(PAVLGCPTRNODECORE) RTAvlGCPtrRemoveBestFit(PAVLGCPTRTREE ppTree, RTGCPTR Key, bool fAbove); +RTDECL(int) RTAvlGCPtrDestroy(PAVLGCPTRTREE pTree, PAVLGCPTRCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of RTGCPTRs - using relative offsets internally. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef int32_t AVLOGCPTR; + +/** + * AVL Core node. + */ +typedef struct _AVLOGCPtrNodeCore +{ + /** Key value. */ + RTGCPTR Key; + /** Offset to the left leaf node, relative to this field. */ + AVLOGCPTR pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLOGCPTR pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; + unsigned char padding[GC_ARCH_BITS == 64 ? 7 : 3]; +} AVLOGCPTRNODECORE, *PAVLOGCPTRNODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLOGCPTR AVLOGCPTRTREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLOGCPTRTREE *PAVLOGCPTRTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLOGCPTRTREE *PPAVLOGCPTRNODECORE; + +/** Callback function for RTAvloGCPtrDoWithAll(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLOGCPTRCALLBACK,(PAVLOGCPTRNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvloGCPtrDoWithAll(). */ +typedef AVLOGCPTRCALLBACK *PAVLOGCPTRCALLBACK; + +RTDECL(bool) RTAvloGCPtrInsert(PAVLOGCPTRTREE pTree, PAVLOGCPTRNODECORE pNode); +RTDECL(PAVLOGCPTRNODECORE) RTAvloGCPtrRemove(PAVLOGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLOGCPTRNODECORE) RTAvloGCPtrGet(PAVLOGCPTRTREE pTree, RTGCPTR Key); +RTDECL(int) RTAvloGCPtrDoWithAll(PAVLOGCPTRTREE pTree, int fFromLeft, PAVLOGCPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLOGCPTRNODECORE) RTAvloGCPtrGetBestFit(PAVLOGCPTRTREE ppTree, RTGCPTR Key, bool fAbove); +RTDECL(PAVLOGCPTRNODECORE) RTAvloGCPtrRemoveBestFit(PAVLOGCPTRTREE ppTree, RTGCPTR Key, bool fAbove); +RTDECL(int) RTAvloGCPtrDestroy(PAVLOGCPTRTREE pTree, PAVLOGCPTRCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of RTGCPTR ranges. + * @{ + */ + +/** + * AVL Core node. + */ +typedef struct _AVLRGCPtrNodeCore +{ + /** First key value in the range (inclusive). */ + RTGCPTR Key; + /** Last key value in the range (inclusive). */ + RTGCPTR KeyLast; + /** Offset to the left leaf node, relative to this field. */ + struct _AVLRGCPtrNodeCore *pLeft; + /** Offset to the right leaf node, relative to this field. */ + struct _AVLRGCPtrNodeCore *pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLRGCPTRNODECORE, *PAVLRGCPTRNODECORE; + +/** A offset base tree with RTGCPTR keys. */ +typedef PAVLRGCPTRNODECORE AVLRGCPTRTREE; +/** Pointer to an offset base tree with RTGCPTR keys. */ +typedef AVLRGCPTRTREE *PAVLRGCPTRTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLRGCPTRTREE *PPAVLRGCPTRNODECORE; + +/** Callback function for RTAvlrGCPtrDoWithAll() and RTAvlrGCPtrDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLRGCPTRCALLBACK,(PAVLRGCPTRNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlrGCPtrDoWithAll() and RTAvlrGCPtrDestroy(). */ +typedef AVLRGCPTRCALLBACK *PAVLRGCPTRCALLBACK; + +RTDECL(bool) RTAvlrGCPtrInsert( PAVLRGCPTRTREE pTree, PAVLRGCPTRNODECORE pNode); +RTDECL(PAVLRGCPTRNODECORE) RTAvlrGCPtrRemove( PAVLRGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLRGCPTRNODECORE) RTAvlrGCPtrGet( PAVLRGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLRGCPTRNODECORE) RTAvlrGCPtrGetBestFit( PAVLRGCPTRTREE pTree, RTGCPTR Key, bool fAbove); +RTDECL(PAVLRGCPTRNODECORE) RTAvlrGCPtrRangeGet( PAVLRGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLRGCPTRNODECORE) RTAvlrGCPtrRangeRemove( PAVLRGCPTRTREE pTree, RTGCPTR Key); +RTDECL(int) RTAvlrGCPtrDoWithAll( PAVLRGCPTRTREE pTree, int fFromLeft, PAVLRGCPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlrGCPtrDestroy( PAVLRGCPTRTREE pTree, PAVLRGCPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLRGCPTRNODECORE) RTAvlrGCPtrGetRoot( PAVLRGCPTRTREE pTree); +RTDECL(PAVLRGCPTRNODECORE) RTAvlrGCPtrGetLeft( PAVLRGCPTRNODECORE pNode); +RTDECL(PAVLRGCPTRNODECORE) RTAvlrGCPtrGetRight( PAVLRGCPTRNODECORE pNode); + +/** @} */ + + +/** @name AVL tree of RTGCPTR ranges - using relative offsets internally. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef int32_t AVLROGCPTR; + +/** + * AVL Core node. + */ +typedef struct _AVLROGCPtrNodeCore +{ + /** First key value in the range (inclusive). */ + RTGCPTR Key; + /** Last key value in the range (inclusive). */ + RTGCPTR KeyLast; + /** Offset to the left leaf node, relative to this field. */ + AVLROGCPTR pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLROGCPTR pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; + unsigned char padding[GC_ARCH_BITS == 64 ? 7 : 7]; +} AVLROGCPTRNODECORE, *PAVLROGCPTRNODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLROGCPTR AVLROGCPTRTREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLROGCPTRTREE *PAVLROGCPTRTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLROGCPTRTREE *PPAVLROGCPTRNODECORE; + +/** Callback function for RTAvlroGCPtrDoWithAll() and RTAvlroGCPtrDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLROGCPTRCALLBACK,(PAVLROGCPTRNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlroGCPtrDoWithAll() and RTAvlroGCPtrDestroy(). */ +typedef AVLROGCPTRCALLBACK *PAVLROGCPTRCALLBACK; + +RTDECL(bool) RTAvlroGCPtrInsert(PAVLROGCPTRTREE pTree, PAVLROGCPTRNODECORE pNode); +RTDECL(PAVLROGCPTRNODECORE) RTAvlroGCPtrRemove(PAVLROGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLROGCPTRNODECORE) RTAvlroGCPtrGet(PAVLROGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLROGCPTRNODECORE) RTAvlroGCPtrGetBestFit(PAVLROGCPTRTREE ppTree, RTGCPTR Key, bool fAbove); +RTDECL(PAVLROGCPTRNODECORE) RTAvlroGCPtrRangeGet(PAVLROGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLROGCPTRNODECORE) RTAvlroGCPtrRangeRemove(PAVLROGCPTRTREE pTree, RTGCPTR Key); +RTDECL(int) RTAvlroGCPtrDoWithAll(PAVLROGCPTRTREE pTree, int fFromLeft, PAVLROGCPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlroGCPtrDestroy(PAVLROGCPTRTREE pTree, PAVLROGCPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLROGCPTRNODECORE) RTAvlroGCPtrGetRoot(PAVLROGCPTRTREE pTree); +RTDECL(PAVLROGCPTRNODECORE) RTAvlroGCPtrGetLeft(PAVLROGCPTRNODECORE pNode); +RTDECL(PAVLROGCPTRNODECORE) RTAvlroGCPtrGetRight(PAVLROGCPTRNODECORE pNode); + +/** @} */ + + +/** @name AVL tree of RTGCPTR ranges (overlapping supported) - using relative + * offsets internally. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef int32_t AVLROOGCPTR; + +/** + * AVL Core node. + */ +typedef struct _AVLROOGCPtrNodeCore +{ + /** First key value in the range (inclusive). */ + RTGCPTR Key; + /** Last key value in the range (inclusive). */ + RTGCPTR KeyLast; + /** Offset to the left leaf node, relative to this field. */ + AVLROOGCPTR pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLROOGCPTR pRight; + /** Pointer to the list of string with the same key. Don't touch. */ + AVLROOGCPTR pList; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLROOGCPTRNODECORE, *PAVLROOGCPTRNODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLROOGCPTR AVLROOGCPTRTREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLROOGCPTRTREE *PAVLROOGCPTRTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLROOGCPTRTREE *PPAVLROOGCPTRNODECORE; + +/** Callback function for RTAvlrooGCPtrDoWithAll() and RTAvlrooGCPtrDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLROOGCPTRCALLBACK,(PAVLROOGCPTRNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlrooGCPtrDoWithAll() and RTAvlrooGCPtrDestroy(). */ +typedef AVLROOGCPTRCALLBACK *PAVLROOGCPTRCALLBACK; + +RTDECL(bool) RTAvlrooGCPtrInsert(PAVLROOGCPTRTREE pTree, PAVLROOGCPTRNODECORE pNode); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrRemove(PAVLROOGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrGet(PAVLROOGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrGetBestFit(PAVLROOGCPTRTREE ppTree, RTGCPTR Key, bool fAbove); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrRangeGet(PAVLROOGCPTRTREE pTree, RTGCPTR Key); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrRangeRemove(PAVLROOGCPTRTREE pTree, RTGCPTR Key); +RTDECL(int) RTAvlrooGCPtrDoWithAll(PAVLROOGCPTRTREE pTree, int fFromLeft, PAVLROOGCPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlrooGCPtrDestroy(PAVLROOGCPTRTREE pTree, PAVLROOGCPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrGetRoot(PAVLROOGCPTRTREE pTree); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrGetLeft(PAVLROOGCPTRNODECORE pNode); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrGetRight(PAVLROOGCPTRNODECORE pNode); +RTDECL(PAVLROOGCPTRNODECORE) RTAvlrooGCPtrGetNextEqual(PAVLROOGCPTRNODECORE pNode); + +/** @} */ + + +/** @name AVL tree of RTUINTPTR. + * @{ + */ + +/** + * AVL RTUINTPTR node core. + */ +typedef struct _AVLUIntPtrNodeCore +{ + /** Key value. */ + RTUINTPTR Key; + /** Offset to the left leaf node, relative to this field. */ + struct _AVLUIntPtrNodeCore *pLeft; + /** Offset to the right leaf node, relative to this field. */ + struct _AVLUIntPtrNodeCore *pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLUINTPTRNODECORE; +/** Pointer to a RTUINTPTR AVL node core.*/ +typedef AVLUINTPTRNODECORE *PAVLUINTPTRNODECORE; + +/** A pointer based tree with RTUINTPTR keys. */ +typedef PAVLUINTPTRNODECORE AVLUINTPTRTREE; +/** Pointer to an offset base tree with RTUINTPTR keys. */ +typedef AVLUINTPTRTREE *PAVLUINTPTRTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a pointer. */ +typedef AVLUINTPTRTREE *PPAVLUINTPTRNODECORE; + +/** Callback function for RTAvlUIntPtrDoWithAll() and RTAvlUIntPtrDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLUINTPTRCALLBACK,(PAVLUINTPTRNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlUIntPtrDoWithAll() and RTAvlUIntPtrDestroy(). */ +typedef AVLUINTPTRCALLBACK *PAVLUINTPTRCALLBACK; + +RTDECL(bool) RTAvlUIntPtrInsert( PAVLUINTPTRTREE pTree, PAVLUINTPTRNODECORE pNode); +RTDECL(PAVLUINTPTRNODECORE) RTAvlUIntPtrRemove( PAVLUINTPTRTREE pTree, RTUINTPTR Key); +RTDECL(PAVLUINTPTRNODECORE) RTAvlUIntPtrGet( PAVLUINTPTRTREE pTree, RTUINTPTR Key); +RTDECL(PAVLUINTPTRNODECORE) RTAvlUIntPtrGetBestFit(PAVLUINTPTRTREE pTree, RTUINTPTR Key, bool fAbove); +RTDECL(int) RTAvlUIntPtrDoWithAll( PAVLUINTPTRTREE pTree, int fFromLeft, PAVLUINTPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlUIntPtrDestroy( PAVLUINTPTRTREE pTree, PAVLUINTPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLUINTPTRNODECORE) RTAvlUIntPtrGetRoot( PAVLUINTPTRTREE pTree); +RTDECL(PAVLUINTPTRNODECORE) RTAvlUIntPtrGetLeft( PAVLUINTPTRNODECORE pNode); +RTDECL(PAVLUINTPTRNODECORE) RTAvlUIntPtrGetRight( PAVLUINTPTRNODECORE pNode); + +/** @} */ + + +/** @name AVL tree of RTUINTPTR ranges. + * @{ + */ + +/** + * AVL RTUINTPTR range node core. + */ +typedef struct _AVLRUIntPtrNodeCore +{ + /** First key value in the range (inclusive). */ + RTUINTPTR Key; + /** Last key value in the range (inclusive). */ + RTUINTPTR KeyLast; + /** Offset to the left leaf node, relative to this field. */ + struct _AVLRUIntPtrNodeCore *pLeft; + /** Offset to the right leaf node, relative to this field. */ + struct _AVLRUIntPtrNodeCore *pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLRUINTPTRNODECORE; +/** Pointer to an AVL RTUINTPTR range node code. */ +typedef AVLRUINTPTRNODECORE *PAVLRUINTPTRNODECORE; + +/** A pointer based tree with RTUINTPTR ranges. */ +typedef PAVLRUINTPTRNODECORE AVLRUINTPTRTREE; +/** Pointer to a pointer based tree with RTUINTPTR ranges. */ +typedef AVLRUINTPTRTREE *PAVLRUINTPTRTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a pointer. */ +typedef AVLRUINTPTRTREE *PPAVLRUINTPTRNODECORE; + +/** Callback function for RTAvlrUIntPtrDoWithAll() and RTAvlrUIntPtrDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLRUINTPTRCALLBACK,(PAVLRUINTPTRNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlrUIntPtrDoWithAll() and RTAvlrUIntPtrDestroy(). */ +typedef AVLRUINTPTRCALLBACK *PAVLRUINTPTRCALLBACK; + +RTDECL(bool) RTAvlrUIntPtrInsert( PAVLRUINTPTRTREE pTree, PAVLRUINTPTRNODECORE pNode); +RTDECL(PAVLRUINTPTRNODECORE) RTAvlrUIntPtrRemove( PAVLRUINTPTRTREE pTree, RTUINTPTR Key); +RTDECL(PAVLRUINTPTRNODECORE) RTAvlrUIntPtrGet( PAVLRUINTPTRTREE pTree, RTUINTPTR Key); +RTDECL(PAVLRUINTPTRNODECORE) RTAvlrUIntPtrGetBestFit( PAVLRUINTPTRTREE pTree, RTUINTPTR Key, bool fAbove); +RTDECL(PAVLRUINTPTRNODECORE) RTAvlrUIntPtrRangeGet( PAVLRUINTPTRTREE pTree, RTUINTPTR Key); +RTDECL(PAVLRUINTPTRNODECORE) RTAvlrUIntPtrRangeRemove(PAVLRUINTPTRTREE pTree, RTUINTPTR Key); +RTDECL(int) RTAvlrUIntPtrDoWithAll( PAVLRUINTPTRTREE pTree, int fFromLeft, PAVLRUINTPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlrUIntPtrDestroy( PAVLRUINTPTRTREE pTree, PAVLRUINTPTRCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLRUINTPTRNODECORE) RTAvlrUIntPtrGetRoot( PAVLRUINTPTRTREE pTree); +RTDECL(PAVLRUINTPTRNODECORE) RTAvlrUIntPtrGetLeft( PAVLRUINTPTRNODECORE pNode); +RTDECL(PAVLRUINTPTRNODECORE) RTAvlrUIntPtrGetRight( PAVLRUINTPTRNODECORE pNode); + +/** @} */ + + +/** @name AVL tree of RTHCPHYSes - using relative offsets internally. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef int32_t AVLOHCPHYS; + +/** + * AVL Core node. + */ +typedef struct _AVLOHCPhysNodeCore +{ + /** Key value. */ + RTHCPHYS Key; + /** Offset to the left leaf node, relative to this field. */ + AVLOHCPHYS pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLOHCPHYS pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +#if HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64 + unsigned char Padding[7]; /**< Alignment padding. */ +#endif +} AVLOHCPHYSNODECORE, *PAVLOHCPHYSNODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLOHCPHYS AVLOHCPHYSTREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLOHCPHYSTREE *PAVLOHCPHYSTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLOHCPHYSTREE *PPAVLOHCPHYSNODECORE; + +/** Callback function for RTAvloHCPhysDoWithAll() and RTAvloHCPhysDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLOHCPHYSCALLBACK,(PAVLOHCPHYSNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvloHCPhysDoWithAll() and RTAvloHCPhysDestroy(). */ +typedef AVLOHCPHYSCALLBACK *PAVLOHCPHYSCALLBACK; + +RTDECL(bool) RTAvloHCPhysInsert(PAVLOHCPHYSTREE pTree, PAVLOHCPHYSNODECORE pNode); +RTDECL(PAVLOHCPHYSNODECORE) RTAvloHCPhysRemove(PAVLOHCPHYSTREE pTree, RTHCPHYS Key); +RTDECL(PAVLOHCPHYSNODECORE) RTAvloHCPhysGet(PAVLOHCPHYSTREE pTree, RTHCPHYS Key); +RTDECL(int) RTAvloHCPhysDoWithAll(PAVLOHCPHYSTREE pTree, int fFromLeft, PAVLOHCPHYSCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLOHCPHYSNODECORE) RTAvloHCPhysGetBestFit(PAVLOHCPHYSTREE ppTree, RTHCPHYS Key, bool fAbove); +RTDECL(PAVLOHCPHYSNODECORE) RTAvloHCPhysRemoveBestFit(PAVLOHCPHYSTREE ppTree, RTHCPHYS Key, bool fAbove); +RTDECL(int) RTAvloHCPhysDestroy(PAVLOHCPHYSTREE pTree, PAVLOHCPHYSCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + + +/** @name AVL tree of RTIOPORTs - using relative offsets internally. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef int32_t AVLOIOPORTPTR; + +/** + * AVL Core node. + */ +typedef struct _AVLOIOPortNodeCore +{ + /** Offset to the left leaf node, relative to this field. */ + AVLOIOPORTPTR pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLOIOPORTPTR pRight; + /** Key value. */ + RTIOPORT Key; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLOIOPORTNODECORE, *PAVLOIOPORTNODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLOIOPORTPTR AVLOIOPORTTREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLOIOPORTTREE *PAVLOIOPORTTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLOIOPORTTREE *PPAVLOIOPORTNODECORE; + +/** Callback function for RTAvloIOPortDoWithAll() and RTAvloIOPortDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLOIOPORTCALLBACK,(PAVLOIOPORTNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvloIOPortDoWithAll() and RTAvloIOPortDestroy(). */ +typedef AVLOIOPORTCALLBACK *PAVLOIOPORTCALLBACK; + +RTDECL(bool) RTAvloIOPortInsert(PAVLOIOPORTTREE pTree, PAVLOIOPORTNODECORE pNode); +RTDECL(PAVLOIOPORTNODECORE) RTAvloIOPortRemove(PAVLOIOPORTTREE pTree, RTIOPORT Key); +RTDECL(PAVLOIOPORTNODECORE) RTAvloIOPortGet(PAVLOIOPORTTREE pTree, RTIOPORT Key); +RTDECL(int) RTAvloIOPortDoWithAll(PAVLOIOPORTTREE pTree, int fFromLeft, PAVLOIOPORTCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLOIOPORTNODECORE) RTAvloIOPortGetBestFit(PAVLOIOPORTTREE ppTree, RTIOPORT Key, bool fAbove); +RTDECL(PAVLOIOPORTNODECORE) RTAvloIOPortRemoveBestFit(PAVLOIOPORTTREE ppTree, RTIOPORT Key, bool fAbove); +RTDECL(int) RTAvloIOPortDestroy(PAVLOIOPORTTREE pTree, PAVLOIOPORTCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of RTIOPORT ranges - using relative offsets internally. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef int32_t AVLROIOPORTPTR; + +/** + * AVL Core node. + */ +typedef struct _AVLROIOPortNodeCore +{ + /** First key value in the range (inclusive). */ + RTIOPORT Key; + /** Last key value in the range (inclusive). */ + RTIOPORT KeyLast; + /** Offset to the left leaf node, relative to this field. */ + AVLROIOPORTPTR pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLROIOPORTPTR pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLROIOPORTNODECORE, *PAVLROIOPORTNODECORE; + +/** A offset base tree with uint32_t keys. */ +typedef AVLROIOPORTPTR AVLROIOPORTTREE; +/** Pointer to an offset base tree with uint32_t keys. */ +typedef AVLROIOPORTTREE *PAVLROIOPORTTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLROIOPORTTREE *PPAVLROIOPORTNODECORE; + +/** Callback function for RTAvlroIOPortDoWithAll() and RTAvlroIOPortDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLROIOPORTCALLBACK,(PAVLROIOPORTNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlroIOPortDoWithAll() and RTAvlroIOPortDestroy(). */ +typedef AVLROIOPORTCALLBACK *PAVLROIOPORTCALLBACK; + +RTDECL(bool) RTAvlroIOPortInsert(PAVLROIOPORTTREE pTree, PAVLROIOPORTNODECORE pNode); +RTDECL(PAVLROIOPORTNODECORE) RTAvlroIOPortRemove(PAVLROIOPORTTREE pTree, RTIOPORT Key); +RTDECL(PAVLROIOPORTNODECORE) RTAvlroIOPortGet(PAVLROIOPORTTREE pTree, RTIOPORT Key); +RTDECL(PAVLROIOPORTNODECORE) RTAvlroIOPortRangeGet(PAVLROIOPORTTREE pTree, RTIOPORT Key); +RTDECL(PAVLROIOPORTNODECORE) RTAvlroIOPortRangeRemove(PAVLROIOPORTTREE pTree, RTIOPORT Key); +RTDECL(int) RTAvlroIOPortDoWithAll(PAVLROIOPORTTREE pTree, int fFromLeft, PAVLROIOPORTCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlroIOPortDestroy(PAVLROIOPORTTREE pTree, PAVLROIOPORTCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of RTHCPHYSes. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef struct _AVLHCPhysNodeCore *AVLHCPHYSPTR; + +/** + * AVL Core node. + */ +typedef struct _AVLHCPhysNodeCore +{ + /** Offset to the left leaf node, relative to this field. */ + AVLHCPHYSPTR pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLHCPHYSPTR pRight; + /** Key value. */ + RTHCPHYS Key; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLHCPHYSNODECORE, *PAVLHCPHYSNODECORE; + +/** A offset base tree with RTHCPHYS keys. */ +typedef AVLHCPHYSPTR AVLHCPHYSTREE; +/** Pointer to an offset base tree with RTHCPHYS keys. */ +typedef AVLHCPHYSTREE *PAVLHCPHYSTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLHCPHYSTREE *PPAVLHCPHYSNODECORE; + +/** Callback function for RTAvlHCPhysDoWithAll() and RTAvlHCPhysDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLHCPHYSCALLBACK,(PAVLHCPHYSNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlHCPhysDoWithAll() and RTAvlHCPhysDestroy(). */ +typedef AVLHCPHYSCALLBACK *PAVLHCPHYSCALLBACK; + +RTDECL(bool) RTAvlHCPhysInsert(PAVLHCPHYSTREE pTree, PAVLHCPHYSNODECORE pNode); +RTDECL(PAVLHCPHYSNODECORE) RTAvlHCPhysRemove(PAVLHCPHYSTREE pTree, RTHCPHYS Key); +RTDECL(PAVLHCPHYSNODECORE) RTAvlHCPhysGet(PAVLHCPHYSTREE pTree, RTHCPHYS Key); +RTDECL(int) RTAvlHCPhysDoWithAll(PAVLHCPHYSTREE pTree, int fFromLeft, PAVLHCPHYSCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLHCPHYSNODECORE) RTAvlHCPhysGetBestFit(PAVLHCPHYSTREE ppTree, RTHCPHYS Key, bool fAbove); +RTDECL(PAVLHCPHYSNODECORE) RTAvlHCPhysRemoveBestFit(PAVLHCPHYSTREE ppTree, RTHCPHYS Key, bool fAbove); +RTDECL(int) RTAvlHCPhysDestroy(PAVLHCPHYSTREE pTree, PAVLHCPHYSCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + +/** @name AVL tree of RTGCPHYSes. + * @{ + */ + +/** + * AVL 'pointer' type for the relative offset pointer scheme. + */ +typedef struct _AVLGCPhysNodeCore *AVLGCPHYSPTR; + +/** + * AVL Core node. + */ +typedef struct _AVLGCPhysNodeCore +{ + /** Offset to the left leaf node, relative to this field. */ + AVLGCPHYSPTR pLeft; + /** Offset to the right leaf node, relative to this field. */ + AVLGCPHYSPTR pRight; + /** Key value. */ + RTGCPHYS Key; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLGCPHYSNODECORE, *PAVLGCPHYSNODECORE; + +/** A offset base tree with RTGCPHYS keys. */ +typedef AVLGCPHYSPTR AVLGCPHYSTREE; +/** Pointer to an offset base tree with RTGCPHYS keys. */ +typedef AVLGCPHYSTREE *PAVLGCPHYSTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLGCPHYSTREE *PPAVLGCPHYSNODECORE; + +/** Callback function for RTAvlGCPhysDoWithAll() and RTAvlGCPhysDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLGCPHYSCALLBACK,(PAVLGCPHYSNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlGCPhysDoWithAll() and RTAvlGCPhysDestroy(). */ +typedef AVLGCPHYSCALLBACK *PAVLGCPHYSCALLBACK; + +RTDECL(bool) RTAvlGCPhysInsert(PAVLGCPHYSTREE pTree, PAVLGCPHYSNODECORE pNode); +RTDECL(PAVLGCPHYSNODECORE) RTAvlGCPhysRemove(PAVLGCPHYSTREE pTree, RTGCPHYS Key); +RTDECL(PAVLGCPHYSNODECORE) RTAvlGCPhysGet(PAVLGCPHYSTREE pTree, RTGCPHYS Key); +RTDECL(int) RTAvlGCPhysDoWithAll(PAVLGCPHYSTREE pTree, int fFromLeft, PAVLGCPHYSCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLGCPHYSNODECORE) RTAvlGCPhysGetBestFit(PAVLGCPHYSTREE ppTree, RTGCPHYS Key, bool fAbove); +RTDECL(PAVLGCPHYSNODECORE) RTAvlGCPhysRemoveBestFit(PAVLGCPHYSTREE ppTree, RTGCPHYS Key, bool fAbove); +RTDECL(int) RTAvlGCPhysDestroy(PAVLGCPHYSTREE pTree, PAVLGCPHYSCALLBACK pfnCallBack, void *pvParam); + +/** @} */ + + +/** @name AVL tree of RTFOFF ranges. + * @{ + */ + +/** + * AVL Core node. + */ +typedef struct _AVLRFOFFNodeCore +{ + /** First key value in the range (inclusive). */ + RTFOFF Key; + /** Last key value in the range (inclusive). */ + RTFOFF KeyLast; + /** Offset to the left leaf node, relative to this field. */ + struct _AVLRFOFFNodeCore *pLeft; + /** Offset to the right leaf node, relative to this field. */ + struct _AVLRFOFFNodeCore *pRight; + /** Height of this tree: max(height(left), height(right)) + 1 */ + unsigned char uchHeight; +} AVLRFOFFNODECORE, *PAVLRFOFFNODECORE; + +/** A pointer based tree with RTFOFF ranges. */ +typedef PAVLRFOFFNODECORE AVLRFOFFTREE; +/** Pointer to a pointer based tree with RTFOFF ranges. */ +typedef AVLRFOFFTREE *PAVLRFOFFTREE; + +/** Pointer to an internal tree pointer. + * In this case it's a pointer to a relative offset. */ +typedef AVLRFOFFTREE *PPAVLRFOFFNODECORE; + +/** Callback function for RTAvlrGCPtrDoWithAll() and RTAvlrGCPtrDestroy(). + * @returns IPRT status codes. */ +typedef DECLCALLBACKTYPE(int, AVLRFOFFCALLBACK,(PAVLRFOFFNODECORE pNode, void *pvUser)); +/** Pointer to callback function for RTAvlrGCPtrDoWithAll() and RTAvlrGCPtrDestroy(). */ +typedef AVLRFOFFCALLBACK *PAVLRFOFFCALLBACK; + +RTDECL(bool) RTAvlrFileOffsetInsert( PAVLRFOFFTREE pTree, PAVLRFOFFNODECORE pNode); +RTDECL(PAVLRFOFFNODECORE) RTAvlrFileOffsetRemove( PAVLRFOFFTREE pTree, RTFOFF Key); +RTDECL(PAVLRFOFFNODECORE) RTAvlrFileOffsetGet( PAVLRFOFFTREE pTree, RTFOFF Key); +RTDECL(PAVLRFOFFNODECORE) RTAvlrFileOffsetGetBestFit( PAVLRFOFFTREE pTree, RTFOFF Key, bool fAbove); +RTDECL(PAVLRFOFFNODECORE) RTAvlrFileOffsetRangeGet( PAVLRFOFFTREE pTree, RTFOFF Key); +RTDECL(PAVLRFOFFNODECORE) RTAvlrFileOffsetRangeRemove( PAVLRFOFFTREE pTree, RTFOFF Key); +RTDECL(int) RTAvlrFileOffsetDoWithAll( PAVLRFOFFTREE pTree, int fFromLeft, PAVLRFOFFCALLBACK pfnCallBack, void *pvParam); +RTDECL(int) RTAvlrFileOffsetDestroy( PAVLRFOFFTREE pTree, PAVLRFOFFCALLBACK pfnCallBack, void *pvParam); +RTDECL(PAVLRFOFFNODECORE) RTAvlrFileOffsetGetRoot( PAVLRFOFFTREE pTree); +RTDECL(PAVLRFOFFNODECORE) RTAvlrFileOffsetGetLeft( PAVLRFOFFNODECORE pNode); +RTDECL(PAVLRFOFFNODECORE) RTAvlrFileOffsetGetRight( PAVLRFOFFNODECORE pNode); + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_avl_h */ + diff --git a/include/iprt/base64.h b/include/iprt/base64.h new file mode 100644 index 00000000..441f6e5e --- /dev/null +++ b/include/iprt/base64.h @@ -0,0 +1,353 @@ +/** @file + * IPRT - Base64, MIME content transfer encoding. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_base64_h +#define IPRT_INCLUDED_base64_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_base64 RTBase64 - Base64, MIME content transfer encoding. + * @ingroup grp_rt + * @{ + */ + +/** @def RTBASE64_EOL_SIZE + * The size of the end-of-line marker. */ +#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) +# define RTBASE64_EOL_SIZE (sizeof("\r\n") - 1) +#else +# define RTBASE64_EOL_SIZE (sizeof("\n") - 1) +#endif + + +/** @name Flags for RTBase64EncodeEx() and RTBase64EncodedLengthEx(). + * @{ */ +/** Insert line breaks into encoded string. + * The size of the end-of-line marker is that that of the host platform. + */ +#define RTBASE64_FLAGS_EOL_NATIVE UINT32_C(0) /**< Use native newlines. */ +#define RTBASE64_FLAGS_NO_LINE_BREAKS UINT32_C(1) /**< No newlines. */ +#define RTBASE64_FLAGS_EOL_LF UINT32_C(2) /**< Use UNIX-style newlines. */ +#define RTBASE64_FLAGS_EOL_CRLF UINT32_C(3) /**< Use DOS-style newlines. */ +#define RTBASE64_FLAGS_EOL_STYLE_MASK UINT32_C(3) /**< End-of-line style mask. */ +/** @} */ + + +/** + * Calculates the decoded data size for a Base64 encoded string. + * + * @returns The length in bytes. -1 if the encoding is bad. + * + * @param pszString The Base64 encoded string. + * @param ppszEnd If not NULL, this will point to the first char + * following the Base64 encoded text block. If + * NULL the entire string is assumed to be Base64. + */ +RTDECL(ssize_t) RTBase64DecodedSize(const char *pszString, char **ppszEnd); + +/** + * Calculates the decoded data size for a Base64 encoded UTF-16 string. + * + * @returns The length in bytes. -1 if the encoding is bad. + * + * @param pwszString The Base64 encoded UTF-16 string. + * @param ppwszEnd If not NULL, this will point to the first char + * following the Base64 encoded text block. If + * NULL the entire string is assumed to be Base64. + */ +RTDECL(ssize_t) RTBase64DecodedUtf16Size(PCRTUTF16 pwszString, PRTUTF16 *ppwszEnd); + +/** + * Calculates the decoded data size for a Base64 encoded string. + * + * @returns The length in bytes. -1 if the encoding is bad. + * + * @param pszString The Base64 encoded string. + * @param cchStringMax The max length to decode, use RTSTR_MAX if the + * length of @a pszString is not known and it is + * really zero terminated. + * @param ppszEnd If not NULL, this will point to the first char + * following the Base64 encoded text block. If + * NULL the entire string is assumed to be Base64. + */ +RTDECL(ssize_t) RTBase64DecodedSizeEx(const char *pszString, size_t cchStringMax, char **ppszEnd); + +/** + * Calculates the decoded data size for a Base64 encoded UTF-16 string. + * + * @returns The length in bytes. -1 if the encoding is bad. + * + * @param pwszString The Base64 encoded UTF-16 string. + * @param cwcStringMax The max length to decode in RTUTF16 units, use + * RTSTR_MAX if the length of @a pwszString is not + * known and it is really zero terminated. + * @param ppwszEnd If not NULL, this will point to the first char + * following the Base64 encoded text block. If + * NULL the entire string is assumed to be Base64. + */ +RTDECL(ssize_t) RTBase64DecodedUtf16SizeEx(PCRTUTF16 pwszString, size_t cwcStringMax, PRTUTF16 *ppwszEnd); + +/** + * Decodes a Base64 encoded string into the buffer supplied by the caller. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. pcbActual will not + * be set, nor will ppszEnd. + * @retval VERR_INVALID_BASE64_ENCODING if the encoding is wrong. + * + * @param pszString The Base64 string. Whether the entire string or + * just the start of the string is in Base64 depends + * on whether ppszEnd is specified or not. + * @param pvData Where to store the decoded data. + * @param cbData The size of the output buffer that pvData points to. + * @param pcbActual Where to store the actual number of bytes returned. + * Optional. + * @param ppszEnd Indicates that the string may contain other stuff + * after the Base64 encoded data when not NULL. Will + * be set to point to the first char that's not part of + * the encoding. If NULL the entire string must be part + * of the Base64 encoded data. + */ +RTDECL(int) RTBase64Decode(const char *pszString, void *pvData, size_t cbData, size_t *pcbActual, char **ppszEnd); + +/** + * Decodes a Base64 encoded UTF-16 string into the buffer supplied by the + * caller. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. pcbActual will not + * be set, nor will ppszEnd. + * @retval VERR_INVALID_BASE64_ENCODING if the encoding is wrong. + * + * @param pwszString The Base64 UTF-16 string. Whether the entire string + * or just the start of the string is in Base64 depends + * on whether ppwszEnd is specified or not. + * @param pvData Where to store the decoded data. + * @param cbData The size of the output buffer that pvData points to. + * @param pcbActual Where to store the actual number of bytes returned. + * Optional. + * @param ppwszEnd Indicates that the string may contain other stuff + * after the Base64 encoded data when not NULL. Will + * be set to point to the first char that's not part of + * the encoding. If NULL the entire string must be part + * of the Base64 encoded data. + */ +RTDECL(int) RTBase64DecodeUtf16(PCRTUTF16 pwszString, void *pvData, size_t cbData, size_t *pcbActual, PRTUTF16 *ppwszEnd); + +/** + * Decodes a Base64 encoded string into the buffer supplied by the caller. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. pcbActual will not + * be set, nor will ppszEnd. + * @retval VERR_INVALID_BASE64_ENCODING if the encoding is wrong. + * + * @param pszString The Base64 string. Whether the entire string or + * just the start of the string is in Base64 depends + * on whether ppszEnd is specified or not. + * @param cchStringMax The max length to decode, use RTSTR_MAX if the + * length of @a pszString is not known and it is + * really zero terminated. + * @param pvData Where to store the decoded data. + * @param cbData The size of the output buffer that pvData points to. + * @param pcbActual Where to store the actual number of bytes returned. + * Optional. + * @param ppszEnd Indicates that the string may contain other stuff + * after the Base64 encoded data when not NULL. Will + * be set to point to the first char that's not part of + * the encoding. If NULL the entire string must be part + * of the Base64 encoded data. + */ +RTDECL(int) RTBase64DecodeEx(const char *pszString, size_t cchStringMax, void *pvData, size_t cbData, + size_t *pcbActual, char **ppszEnd); + +/** + * Decodes a Base64 encoded UTF-16 string into the buffer supplied by the + * caller. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. pcbActual will not + * be set, nor will ppszEnd. + * @retval VERR_INVALID_BASE64_ENCODING if the encoding is wrong. + * + * @param pwszString The Base64 UTF-16 string. Whether the entire string + * or just the start of the string is in Base64 depends + * on whether ppszEnd is specified or not. + * @param cwcStringMax The max length to decode in RTUTF16 units, use + * RTSTR_MAX if the length of @a pwszString is not + * known and it is really zero terminated. + * @param pvData Where to store the decoded data. + * @param cbData The size of the output buffer that pvData points to. + * @param pcbActual Where to store the actual number of bytes returned. + * Optional. + * @param ppwszEnd Indicates that the string may contain other stuff + * after the Base64 encoded data when not NULL. Will + * be set to point to the first char that's not part of + * the encoding. If NULL the entire string must be part + * of the Base64 encoded data. + */ +RTDECL(int) RTBase64DecodeUtf16Ex(PCRTUTF16 pwszString, size_t cwcStringMax, void *pvData, size_t cbData, + size_t *pcbActual, PRTUTF16 *ppwszEnd); + + +/** + * Calculates the length of the Base64 encoding of a given number of bytes of + * data produced by RTBase64Encode(). + * + * @returns The Base64 string length, excluding the terminator. + * @param cbData The number of bytes to encode. + */ +RTDECL(size_t) RTBase64EncodedLength(size_t cbData); + +/** + * Calculates the UTF-16 length of the Base64 encoding of a given number of + * bytes of data produced by RTBase64EncodeUtf16(). + * + * @returns The Base64 UTF-16 string length (in RTUTF16 units), excluding the + * terminator. + * @param cbData The number of bytes to encode. + */ +RTDECL(size_t) RTBase64EncodedUtf16Length(size_t cbData); + +/** + * Calculates the length of the Base64 encoding of a given number of bytes of + * data produced by RTBase64EncodeEx() with the same @a fFlags. + * + * @returns The Base64 string length, excluding the terminator. + * @param cbData The number of bytes to encode. + * @param fFlags Flags, any combination of the RTBASE64_FLAGS \#defines. + */ +RTDECL(size_t) RTBase64EncodedLengthEx(size_t cbData, uint32_t fFlags); + +/** + * Calculates the UTF-16 length of the Base64 encoding of a given number of + * bytes of data produced by RTBase64EncodeUtf16Ex() with the same @a fFlags. + * + * @returns The Base64 UTF-16 string length (in RTUTF16 units), excluding the + * terminator. + * @param cbData The number of bytes to encode. + * @param fFlags Flags, any combination of the RTBASE64_FLAGS \#defines. + */ +RTDECL(size_t) RTBase64EncodedUtf16LengthEx(size_t cbData, uint32_t fFlags); + +/** + * Encodes the specifed data into a Base64 string, the caller supplies the + * output buffer. + * + * This is equivalent to calling RTBase64EncodeEx() with no flags. + * + * @returns IRPT status code. + * @retval VERR_BUFFER_OVERFLOW if the output buffer is too small. The buffer + * may contain an invalid Base64 string. + * + * @param pvData The data to encode. + * @param cbData The number of bytes to encode. + * @param pszBuf Where to put the Base64 string. + * @param cbBuf The size of the output buffer, including the terminator. + * @param pcchActual The actual number of characters returned. + */ +RTDECL(int) RTBase64Encode(const void *pvData, size_t cbData, char *pszBuf, size_t cbBuf, size_t *pcchActual); + +/** + * Encodes the specifed data into a Base64 UTF-16 string, the caller supplies + * the output buffer. + * + * This is equivalent to calling RTBase64EncodeUtf16Ex() with no flags. + * + * @returns IRPT status code. + * @retval VERR_BUFFER_OVERFLOW if the output buffer is too small. The buffer + * may contain an invalid Base64 string. + * + * @param pvData The data to encode. + * @param cbData The number of bytes to encode. + * @param pwszBuf Where to put the Base64 UTF-16 string. + * @param cwcBuf The size of the output buffer in RTUTF16 units, + * including the terminator. + * @param pcwcActual The actual number of characters returned (excluding the + * terminator). Optional. + */ +RTDECL(int) RTBase64EncodeUtf16(const void *pvData, size_t cbData, PRTUTF16 pwszBuf, size_t cwcBuf, size_t *pcwcActual); + +/** + * Encodes the specifed data into a Base64 string, the caller supplies the + * output buffer. + * + * @returns IRPT status code. + * @retval VERR_BUFFER_OVERFLOW if the output buffer is too small. The buffer + * may contain an invalid Base64 string. + * + * @param pvData The data to encode. + * @param cbData The number of bytes to encode. + * @param fFlags Flags, any combination of the RTBASE64_FLAGS \#defines. + * @param pszBuf Where to put the Base64 string. + * @param cbBuf The size of the output buffer, including the terminator. + * @param pcchActual The actual number of characters returned (excluding the + * terminator). Optional. + */ +RTDECL(int) RTBase64EncodeEx(const void *pvData, size_t cbData, uint32_t fFlags, + char *pszBuf, size_t cbBuf, size_t *pcchActual); + +/** + * Encodes the specifed data into a Base64 UTF-16 string, the caller supplies + * the output buffer. + * + * @returns IRPT status code. + * @retval VERR_BUFFER_OVERFLOW if the output buffer is too small. The buffer + * may contain an invalid Base64 string. + * + * @param pvData The data to encode. + * @param cbData The number of bytes to encode. + * @param fFlags Flags, any combination of the RTBASE64_FLAGS \#defines. + * @param pwszBuf Where to put the Base64 UTF-16 string. + * @param cwcBuf The size of the output buffer in RTUTF16 units, + * including the terminator. + * @param pcwcActual The actual number of characters returned (excluding the + * terminator). Optional. + */ +RTDECL(int) RTBase64EncodeUtf16Ex(const void *pvData, size_t cbData, uint32_t fFlags, + PRTUTF16 pwszBuf, size_t cwcBuf, size_t *pcwcActual); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_base64_h */ + diff --git a/include/iprt/bignum.h b/include/iprt/bignum.h new file mode 100644 index 00000000..ff1b8c48 --- /dev/null +++ b/include/iprt/bignum.h @@ -0,0 +1,197 @@ +/** @file + * IPRT - Big Integer Numbers. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_bignum_h +#define IPRT_INCLUDED_bignum_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rtbignum RTBigNum - Big Integer Numbers + * @ingroup grp_rt + * @{ + */ + +/** The big integer number element type. */ +#if ARCH_BITS == 64 +typedef uint64_t RTBIGNUMELEMENT; +#else +typedef uint32_t RTBIGNUMELEMENT; +#endif +/** Pointer to a big integer number element. */ +typedef RTBIGNUMELEMENT *PRTBIGNUMELEMENT; +/** Pointer to a const big integer number element. */ +typedef RTBIGNUMELEMENT const *PCRTBIGNUMELEMENT; + +/** The size (in bytes) of one array element. */ +#if ARCH_BITS == 64 +# define RTBIGNUM_ELEMENT_SIZE 8 +#else +# define RTBIGNUM_ELEMENT_SIZE 4 +#endif +/** The number of bits in one array element. */ +#define RTBIGNUM_ELEMENT_BITS (RTBIGNUM_ELEMENT_SIZE * 8) +/** Returns the bitmask corrsponding to given bit number. */ +#if ARCH_BITS == 64 +# define RTBIGNUM_ELEMENT_BIT(iBit) RT_BIT_64(iBit) +#else +# define RTBIGNUM_ELEMENT_BIT(iBit) RT_BIT_32(iBit) +#endif +/** The maximum value one element can hold. */ +#if ARCH_BITS == 64 +# define RTBIGNUM_ELEMENT_MAX UINT64_MAX +#else +# define RTBIGNUM_ELEMENT_MAX UINT32_MAX +#endif +/** Mask including all the element bits set to 1. */ +#define RTBIGNUM_ELEMENT_MASK RTBIGNUM_ELEMENT_MAX + + +/** + * IPRT big integer number. + */ +typedef struct RTBIGNUM +{ + /** Elements array where the magnitue of the value is stored. */ + RTBIGNUMELEMENT *pauElements; + /** The current number of elements we're using in the pauElements array. */ + uint32_t cUsed; + /** The current allocation size of pauElements. */ + uint32_t cAllocated; + /** Reserved for future use. */ + uint32_t uReserved; + + /** Set if it's a negative number, clear if positive or zero. */ + uint32_t fNegative : 1; + + /** Whether to use a the data is sensitive (RTBIGNUMINIT_F_SENSITIVE). */ + uint32_t fSensitive : 1; + /** The number is currently scrambled */ + uint32_t fCurScrambled : 1; + + /** Bits reserved for future use. */ + uint32_t fReserved : 30; +} RTBIGNUM; + + +RTDECL(int) RTBigNumInit(PRTBIGNUM pBigNum, uint32_t fFlags, void const *pvRaw, size_t cbRaw); +RTDECL(int) RTBigNumInitZero(PRTBIGNUM pBigNum, uint32_t fFlags); + +/** @name RTBIGNUMINIT_F_XXX - RTBigNumInit flags. + * @{ */ +/** The number is sensitive so use a safer allocator, scramble it when not + * in use, and apply RTMemWipeThoroughly before freeing. The RTMemSafer API + * takes care of these things. + * @note When using this flag, concurrent access is not possible! */ +#define RTBIGNUMINIT_F_SENSITIVE RT_BIT(0) +/** Big endian number. */ +#define RTBIGNUMINIT_F_ENDIAN_BIG RT_BIT(1) +/** Little endian number. */ +#define RTBIGNUMINIT_F_ENDIAN_LITTLE RT_BIT(2) +/** The raw number is unsigned. */ +#define RTBIGNUMINIT_F_UNSIGNED RT_BIT(3) +/** The raw number is signed. */ +#define RTBIGNUMINIT_F_SIGNED RT_BIT(4) +/** @} */ + +RTDECL(int) RTBigNumClone(PRTBIGNUM pBigNum, PCRTBIGNUM pSrc); + +RTDECL(int) RTBigNumDestroy(PRTBIGNUM pBigNum); + + +/** + * The minimum number of bits require store the two's complement representation + * of the number. + * + * @returns Width in number of bits. + * @param pBigNum The big number. + */ +RTDECL(uint32_t) RTBigNumBitWidth(PCRTBIGNUM pBigNum); +RTDECL(uint32_t) RTBigNumByteWidth(PCRTBIGNUM pBigNum); + + +/** + * Converts the big number to a sign-extended big endian byte sequence. + * + * @returns IPRT status code + * @retval VERR_BUFFER_OVERFLOW if the specified buffer is too small. + * @param pBigNum The big number. + * @param pvBuf The output buffer (size is at least cbWanted). + * @param cbWanted The number of bytes wanted. + */ +RTDECL(int) RTBigNumToBytesBigEndian(PCRTBIGNUM pBigNum, void *pvBuf, size_t cbWanted); + +/** + * Compares two numbers. + * + * @retval -1 if pLeft < pRight. + * @retval 0 if pLeft == pRight. + * @retval 1 if pLeft > pRight. + * + * @param pLeft The left side number. + * @param pRight The right side number. + */ +RTDECL(int) RTBigNumCompare(PRTBIGNUM pLeft, PRTBIGNUM pRight); +RTDECL(int) RTBigNumCompareWithU64(PRTBIGNUM pLeft, uint64_t uRight); +RTDECL(int) RTBigNumCompareWithS64(PRTBIGNUM pLeft, int64_t iRight); + +RTDECL(int) RTBigNumAssign(PRTBIGNUM pDst, PCRTBIGNUM pSrc); +RTDECL(int) RTBigNumNegate(PRTBIGNUM pResult, PCRTBIGNUM pBigNum); +RTDECL(int) RTBigNumNegateThis(PRTBIGNUM pThis); + +RTDECL(int) RTBigNumAdd(PRTBIGNUM pResult, PCRTBIGNUM pAugend, PCRTBIGNUM pAddend); +RTDECL(int) RTBigNumSubtract(PRTBIGNUM pResult, PCRTBIGNUM pMinuend, PCRTBIGNUM pSubtrahend); +RTDECL(int) RTBigNumMultiply(PRTBIGNUM pResult, PCRTBIGNUM pMultiplicand, PCRTBIGNUM pMultiplier); +RTDECL(int) RTBigNumDivide(PRTBIGNUM pQuotient, PRTBIGNUM pRemainder, PCRTBIGNUM pDividend, PCRTBIGNUM pDivisor); +RTDECL(int) RTBigNumDivideKnuth(PRTBIGNUM pQuotient, PRTBIGNUM pRemainder, PCRTBIGNUM pDividend, PCRTBIGNUM pDivisor); +RTDECL(int) RTBigNumDivideLong(PRTBIGNUM pQuotient, PRTBIGNUM pRemainder, PCRTBIGNUM pDividend, PCRTBIGNUM pDivisor); +RTDECL(int) RTBigNumModulo(PRTBIGNUM pRemainder, PCRTBIGNUM pDividend, PCRTBIGNUM pDivisor); +RTDECL(int) RTBigNumExponentiate(PRTBIGNUM pResult, PCRTBIGNUM pBase, PCRTBIGNUM pExponent); +RTDECL(int) RTBigNumShiftLeft(PRTBIGNUM pResult, PCRTBIGNUM pValue, uint32_t cBits); +RTDECL(int) RTBigNumShiftRight(PRTBIGNUM pResult, PCRTBIGNUM pValue, uint32_t cBits); + +RTDECL(int) RTBigNumModExp(PRTBIGNUM pResult, PRTBIGNUM pBase, PRTBIGNUM pExponent, PRTBIGNUM pModulus); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_bignum_h */ + diff --git a/include/iprt/bldprog-strtab-template.cpp.h b/include/iprt/bldprog-strtab-template.cpp.h new file mode 100644 index 00000000..c4d63f4d --- /dev/null +++ b/include/iprt/bldprog-strtab-template.cpp.h @@ -0,0 +1,1335 @@ +/* $Id: bldprog-strtab-template.cpp.h $ */ +/** @file + * IPRT - Build Program - String Table Generator. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/* + * (Avoid include sanity checks as this is ring-3 only, C++ code.) + */ +#if defined(__cplusplus) && defined(IN_RING3) + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +/** @def BLDPROG_STRTAB_MAX_STRLEN + * The max length of strings in the table. */ +#if !defined(BLDPROG_STRTAB_MAX_STRLEN) || defined(DOXYGEN_RUNNING) +# define BLDPROG_STRTAB_MAX_STRLEN 256 +#endif + +/** @def BLDPROG_STRTAB_WITH_COMPRESSION + * Enables very simple string compression. + */ +#if defined(DOXYGEN_RUNNING) +# define BLDPROG_STRTAB_WITH_COMPRESSION +#endif + +/** @def BLDPROG_STRTAB_WITH_CAMEL_WORDS + * Modifies the string compression to look for camel case words. + */ +#if defined(DOXYGEN_RUNNING) +# define BLDPROG_STRTAB_WITH_CAMEL_WORDS +#endif + +/** @def BLDPROG_STRTAB_PURE_ASCII + * String compression assumes pure 7-bit ASCII and will fail on UTF-8 when this + * is defined. Otherwise, the compression code will require IPRT to link. + */ +#if defined(DOXYGEN_RUNNING) +# define BLDPROG_STRTAB_PURE_ASCII +#endif + + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <iprt/stdarg.h> +#include <iprt/ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION +# include <map> +# include <iprt/sanitized/string> + +# define BLDPROG_STRTAB_WITH_WORD_SEP_ALTERNATIVE +typedef struct BLDPROGWORDFREQSTATS +{ + uint32_t cWithoutSep; /**< Number of occurances without a separator. */ +# ifdef BLDPROG_STRTAB_WITH_WORD_SEP_ALTERNATIVE + uint32_t cWithSep; /**< Number of occurance with a separator. */ + char chSep; /**< The separator. First come basis. */ +# endif +} BLDPROGWORDFREQSTATS; + +typedef std::map<std::string, BLDPROGWORDFREQSTATS> BLDPROGWORDFREQMAP; + +#endif + +#include "../../src/VBox/Runtime/include/internal/strhash.h" /** @todo make this one public */ + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** + * Build table string. + */ +typedef struct BLDPROGSTRING +{ + /** The string. + * @note This may be modified or replaced (allocated from heap) when + * compressing the string table. */ + char *pszString; + /** The string hash value. */ + uint32_t uHash; + /** The strint table offset. */ + uint32_t offStrTab; + /** The string length. */ + size_t cchString; + /** Pointer to the next string reference (same string table entry). */ + struct BLDPROGSTRING *pNextRef; + /** Pointer to the next string with the same hash value (collision). */ + struct BLDPROGSTRING *pNextCollision; + +} BLDPROGSTRING; +/** Pointer to a string table string. */ +typedef BLDPROGSTRING *PBLDPROGSTRING; + + +/** String table data. */ +typedef struct BLDPROGSTRTAB +{ + /** The size of g_papStrHash. */ + size_t cStrHash; + /** String hash table. */ + PBLDPROGSTRING *papStrHash; + /** Duplicate strings found by AddString. */ + size_t cDuplicateStrings; + /** Total length of the unique strings (no terminators). */ + size_t cchUniqueStrings; + /** Number of unique strings after AddString. */ + size_t cUniqueStrings; + /** Number of collisions. */ + size_t cCollisions; + + /** Number of entries in apSortedStrings. */ + size_t cSortedStrings; + /** The sorted string table. */ + PBLDPROGSTRING *papSortedStrings; + +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + /** The 256 words we've picked to be indexed by reference. */ + BLDPROGSTRING aCompDict[256]; + /** The frequency of the 256 dictionary entries. */ + size_t auCompDictFreq[256]; + /** Incoming strings pending compression. */ + PBLDPROGSTRING *papPendingStrings; + /** Current number of entries in papStrPending. */ + size_t cPendingStrings; + /** The allocated size of papPendingStrings. */ + size_t cMaxPendingStrings; + /** Work frequency map. + * @todo rewrite in plain C. */ + BLDPROGWORDFREQMAP Frequencies; + /** Map of characters used by input strings. */ + uint64_t bmUsedChars[256/64]; +#endif + + /** The string table. */ + char *pachStrTab; + /** The actual string table size. */ + size_t cchStrTab; +} BLDPROGSTRTAB; +typedef BLDPROGSTRTAB *PBLDPROGSTRTAB; + +#if RT_CLANG_PREREQ(4, 0) || RT_GNUC_PREREQ(4, 6) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + + +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + +/** + * Same as ASMBitTest. + * + * We cannot safely use ASMBitTest here because it must be inline, as this code + * is used to build RuntimeBldProg. */ +DECLINLINE(bool) BldProgBitIsSet(uint64_t const *pbmBitmap, size_t iBit) +{ + return RT_BOOL(pbmBitmap[iBit / 64] & RT_BIT_64(iBit % 64)); +} + + +/** + * Same as ASMBitSet. + * + * We cannot safely use ASMBitSet here because it must be inline, as this code + * is used to build RuntimeBldProg. + */ +DECLINLINE(void) BldProgBitSet(uint64_t *pbmBitmap, size_t iBit) +{ + pbmBitmap[iBit / 64] |= RT_BIT_64(iBit % 64); +} + +#endif + + +/** + * Initializes the strint table compiler. + * + * @returns success indicator (out of memory if false). + * @param pThis The strint table compiler instance. + * @param cMaxStrings The max number of strings we'll be adding. + */ +static bool BldProgStrTab_Init(PBLDPROGSTRTAB pThis, size_t cMaxStrings) +{ + pThis->cStrHash = 0; + pThis->papStrHash = NULL; + pThis->cDuplicateStrings = 0; + pThis->cchUniqueStrings = 0; + pThis->cUniqueStrings = 0; + pThis->cCollisions = 0; + pThis->cSortedStrings = 0; + pThis->papSortedStrings = NULL; + pThis->pachStrTab = NULL; + pThis->cchStrTab = 0; +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + memset(pThis->aCompDict, 0, sizeof(pThis->aCompDict)); + pThis->papPendingStrings = NULL; + pThis->cPendingStrings = 0; + pThis->cMaxPendingStrings = cMaxStrings; + memset(pThis->bmUsedChars, 0, sizeof(pThis->bmUsedChars)); + BldProgBitSet(pThis->bmUsedChars, 0); /* Some parts of the code still thinks zero is a terminator, so don't use it for now. */ +# ifndef BLDPROG_STRTAB_PURE_ASCII + BldProgBitSet(pThis->bmUsedChars, 0xff); /* Reserve escape byte for codepoints above 127. */ +# endif +#endif + + /* + * Allocate a hash table double the size of all strings (to avoid too + * many collisions). Add all strings to it, finding duplicates in the + * process. + */ +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + cMaxStrings += RT_ELEMENTS(pThis->aCompDict); +#endif + cMaxStrings *= 2; + pThis->papStrHash = (PBLDPROGSTRING *)calloc(sizeof(pThis->papStrHash[0]), cMaxStrings); + if (pThis->papStrHash) + { + pThis->cStrHash = cMaxStrings; +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + pThis->papPendingStrings = (PBLDPROGSTRING *)calloc(sizeof(pThis->papPendingStrings[0]), pThis->cMaxPendingStrings); + if (pThis->papPendingStrings) +#endif + return true; + +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + free(pThis->papStrHash); + pThis->papStrHash = NULL; +#endif + } + return false; +} + + +#if 0 /* unused */ +static void BldProgStrTab_Delete(PBLDPROGSTRTAB pThis) +{ + free(pThis->papStrHash); + free(pThis->papSortedStrings); + free(pThis->pachStrTab); +# ifdef BLDPROG_STRTAB_WITH_COMPRESSION + free(pThis->papPendingStrings); +# endif + memset(pThis, 0, sizeof(*pThis)); +} +#endif + +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + +DECLINLINE(size_t) bldProgStrTab_compressorFindNextWord(const char *pszSrc, char ch, const char **ppszSrc) +{ + /* + * Skip leading word separators. + */ +# ifdef BLDPROG_STRTAB_WITH_CAMEL_WORDS + while ( ch == ' ' + || ch == '-' + || ch == '+' + || ch == '_') +# else + while (ch == ' ') +# endif + ch = *++pszSrc; + if (ch) + { + /* + * Find end of word. + */ + size_t cchWord = 1; +# ifdef BLDPROG_STRTAB_WITH_CAMEL_WORDS + char chPrev = ch; + while ( (ch = pszSrc[cchWord]) != ' ' + && ch != '\0' + && ch != '-' + && ch != '+' + && ch != '_' + && ( ch == chPrev + || !RT_C_IS_UPPER(ch) + || RT_C_IS_UPPER(chPrev)) ) + { + chPrev = ch; + cchWord++; + } +# else + while ((ch = pszSrc[cchWord]) != ' ' && ch != '\0') + cchWord++; +# endif + *ppszSrc = pszSrc; + return cchWord; + } + + *ppszSrc = pszSrc; + return 0; +} + + +/** + * Analyzes a string. + * + * @param pThis The strint table compiler instance. + * @param pStr The string to analyze. + */ +static void bldProgStrTab_compressorAnalyzeString(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pStr) +{ + /* + * Mark all the string characters as used. + */ + const char *psz = pStr->pszString; + char ch; + while ((ch = *psz++) != '\0') + BldProgBitSet(pThis->bmUsedChars, (uint8_t)ch); + + /* + * For now we just consider words. + */ + psz = pStr->pszString; + while ((ch = *psz) != '\0') + { + size_t cchWord = bldProgStrTab_compressorFindNextWord(psz, ch, &psz); + if (cchWord > 1) + { + std::string strWord(psz, cchWord); + BLDPROGWORDFREQMAP::iterator it = pThis->Frequencies.find(strWord); + if (it != pThis->Frequencies.end()) + { +# ifdef BLDPROG_STRTAB_WITH_WORD_SEP_ALTERNATIVE + char const chSep = psz[cchWord]; + if (chSep != '\0' && (it->second.chSep == chSep || it->second.chSep == '\0')) + { + it->second.chSep = chSep; + it->second.cWithSep++; + } + else +# endif + it->second.cWithoutSep++; + } + else + { +# ifdef BLDPROG_STRTAB_WITH_WORD_SEP_ALTERNATIVE + char const chSep = psz[cchWord]; + if (chSep != '\0') + { + BLDPROGWORDFREQSTATS const NewWord = { 0, 0, chSep }; + pThis->Frequencies[strWord] = NewWord; + } + else + { + static BLDPROGWORDFREQSTATS const s_NewWord = { 0, 0, 0 }; + pThis->Frequencies[strWord] = s_NewWord; + } +# else + pThis->Frequencies[strWord].cWithoutSep = 0; +# endif + } + +# if 0 /** @todo need better accounting for overlapping alternatives before this can be enabled. */ + /* Two words - immediate yields calc may lie when this enabled and we may pick the wrong words. */ + if (ch == ' ') + { + ch = psz[++cchWord]; + if (ch != ' ' && ch != '\0') + { + size_t const cchSaved = cchWord; + + do + cchWord++; + while ((ch = psz[cchWord]) != ' ' && ch != '\0'); + + strWord = std::string(psz, cchWord); + BLDPROGWORDFREQMAP::iterator it = pThis->Frequencies.find(strWord); + if (it != pThis->Frequencies.end()) + it->second += cchWord - 1; + else + pThis->Frequencies[strWord] = 0; + + cchWord = cchSaved; + } + } +# endif + } + else if (!cchWord) + break; + + /* Advance. */ + psz += cchWord; + } + pStr->cchString = psz - pStr->pszString; + if (pStr->cchString > BLDPROG_STRTAB_MAX_STRLEN) + { + fprintf(stderr, "error: String to long (%u)\n", (unsigned)pStr->cchString); + abort(); + } +} + +#endif /* BLDPROG_STRTAB_WITH_COMPRESSION */ + +/** + * Adds a string to the hash table. + * @param pThis The strint table compiler instance. + * @param pStr The string. + */ +static void bldProgStrTab_AddStringToHashTab(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pStr) +{ + pStr->pNextRef = NULL; + pStr->pNextCollision = NULL; + pStr->offStrTab = 0; + pStr->uHash = sdbm(pStr->pszString, &pStr->cchString); + if (pStr->cchString > BLDPROG_STRTAB_MAX_STRLEN) + { + fprintf(stderr, "error: String to long (%u)\n", (unsigned)pStr->cchString); + exit(RTEXITCODE_FAILURE); + } + + size_t idxHash = pStr->uHash % pThis->cStrHash; + PBLDPROGSTRING pCur = pThis->papStrHash[idxHash]; + if (!pCur) + pThis->papStrHash[idxHash] = pStr; + else + { + /* Look for matching string. */ + do + { + if ( pCur->uHash == pStr->uHash + && pCur->cchString == pStr->cchString + && memcmp(pCur->pszString, pStr->pszString, pStr->cchString) == 0) + { + pStr->pNextRef = pCur->pNextRef; + pCur->pNextRef = pStr; + pThis->cDuplicateStrings++; + return; + } + pCur = pCur->pNextCollision; + } while (pCur != NULL); + + /* No matching string, insert. */ + pThis->cCollisions++; + pStr->pNextCollision = pThis->papStrHash[idxHash]; + pThis->papStrHash[idxHash] = pStr; + } + + pThis->cUniqueStrings++; + pThis->cchUniqueStrings += pStr->cchString; +} + + +/** + * Adds a string to the string table. + * + * @param pThis The strint table compiler instance. + * @param pStr The string. + */ +static void BldProgStrTab_AddString(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pStr) +{ +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + bldProgStrTab_compressorAnalyzeString(pThis, pStr); + if (pThis->cPendingStrings < pThis->cMaxPendingStrings) + pThis->papPendingStrings[pThis->cPendingStrings++] = pStr; + else + abort(); +#else + bldProgStrTab_AddStringToHashTab(pThis, pStr); +#endif +} + + +/** + * Adds a string to the string table. + * + * @param pThis The strint table compiler instance. + * @param pStr The string entry (uninitialized). + * @param psz The string, will be duplicated if compression is enabled. + */ +DECLINLINE(void) BldProgStrTab_AddStringDup(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pStr, const char *psz) +{ +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + pStr->pszString = strdup(psz); + if (!pStr->pszString) + abort(); +#else + pStr->pszString = (char *)psz; +#endif + BldProgStrTab_AddString(pThis, pStr); +} + +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + +/** + * Copies @a cchSrc chars from @a pchSrc to @a pszDst, escaping special + * sequences. + * + * @returns New @a pszDst position, NULL if invalid source encoding. + * @param pszDst The destination buffer. + * @param pszSrc The source buffer. + * @param cchSrc How much to copy. + */ +static char *bldProgStrTab_compressorCopyAndEscape(char *pszDst, const char *pszSrc, size_t cchSrc) +{ + while (cchSrc-- > 0) + { + char ch = *pszSrc; + if (!((unsigned char)ch & 0x80)) + { + *pszDst++ = ch; + pszSrc++; + } + else + { +# ifdef BLDPROG_STRTAB_PURE_ASCII + fprintf(stderr, "error: unexpected char value %#x\n", ch); + return NULL; +# else + RTUNICP uc; + int rc = RTStrGetCpEx(&pszSrc, &uc); + if (RT_SUCCESS(rc)) + { + *pszDst++ = (unsigned char)0xff; /* escape single code point. */ + pszDst = RTStrPutCp(pszDst, uc); + } + else + { + fprintf(stderr, "Error: RTStrGetCpEx failed with rc=%d\n", rc); + return NULL; + } +# endif + } + } + return pszDst; +} + + +/** + * Replaces the dictionary words and escapes non-ascii chars in a string. + * + * @param pThis The strint table compiler instance. + * @param pString The string to fixup. + */ +static bool bldProgStrTab_compressorFixupString(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pStr) +{ + char szNew[BLDPROG_STRTAB_MAX_STRLEN * 2]; + char *pszDst = szNew; + const char *pszSrc = pStr->pszString; + const char *pszSrcEnd = pszSrc + pStr->cchString; + + char ch; + while ((ch = *pszSrc) != '\0') + { + const char * const pszSrcUncompressed = pszSrc; + size_t cchWord = bldProgStrTab_compressorFindNextWord(pszSrc, ch, &pszSrc); + size_t cchSrcUncompressed = pszSrc - pszSrcUncompressed; + if (cchSrcUncompressed > 0) + { + pszDst = bldProgStrTab_compressorCopyAndEscape(pszDst, pszSrcUncompressed, cchSrcUncompressed); + if (!pszDst) + return false; + } + if (!cchWord) + break; + + /* Check for g_aWord matches. */ + if (cchWord > 1) + { + size_t cchMax = pszSrcEnd - pszSrc; + for (unsigned i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++) + { + size_t cchLen = pThis->aCompDict[i].cchString; + if ( cchLen >= cchWord + && cchLen <= cchMax + && memcmp(pThis->aCompDict[i].pszString, pszSrc, cchLen) == 0) + { + *pszDst++ = (unsigned char)i; + pszSrc += cchLen; + cchWord = 0; + break; + } + } + } + + if (cchWord > 0) + { + /* Copy the current word. */ + pszDst = bldProgStrTab_compressorCopyAndEscape(pszDst, pszSrc, cchWord); + if (!pszDst) + return false; + pszSrc += cchWord; + } + } + + /* Just terminate it now. */ + *pszDst = '\0'; + + /* + * Update the string. + */ + size_t cchNew = pszDst - &szNew[0]; + if (cchNew > pStr->cchString) + { + pStr->pszString = (char *)malloc(cchNew + 1); + if (!pStr->pszString) + { + fprintf(stderr, "Out of memory!\n"); + return false; + } + } + memcpy(pStr->pszString, szNew, cchNew + 1); + pStr->cchString = cchNew; + + return true; +} + + +/** + * Entry in SortedDictionary. + * + * Uses variable length string member, so not class and allocated via malloc. + */ +struct SortedDictionaryEntry +{ + size_t m_cchGain; + size_t m_cchString; + RT_FLEXIBLE_ARRAY_EXTENSION + char m_szString[RT_FLEXIBLE_ARRAY]; + + /** Allocates and initializes a new entry. */ + static SortedDictionaryEntry *allocate(const char *a_pch, size_t a_cch, size_t a_cchGain, char a_chSep) + { + size_t cbString = a_cch + !!a_chSep + 1; + SortedDictionaryEntry *pNew = (SortedDictionaryEntry *)malloc(RT_UOFFSETOF(SortedDictionaryEntry, m_szString) + cbString); + if (pNew) + { + pNew->m_cchGain = a_cchGain; + memcpy(pNew->m_szString, a_pch, a_cch); + if (a_chSep) + pNew->m_szString[a_cch++] = a_chSep; + pNew->m_szString[a_cch] = '\0'; + pNew->m_cchString = a_cch; + } + return pNew; + } + + + /** Compares this dictionary entry with an incoming one. + * @retval -1 if this entry is of less worth than the new one. + * @retval 0 if this entry is of equal worth to the new one. + * @retval +1 if this entry is of more worth than the new one. + */ + int compare(size_t a_cchGain, size_t a_cchString) + { + /* Higher gain is preferred of course: */ + if (m_cchGain < a_cchGain) + return -1; + if (m_cchGain > a_cchGain) + return 1; + + /* Gain is the same. Prefer the shorter string, as it will result in a shorter string table: */ + if (m_cchString > a_cchString) + return -1; + if (m_cchString < a_cchString) + return 1; + return 0; + } +}; + + +/** + * Insertion sort dictionary that keeps the 256 best words. + * + * Used by bldProgStrTab_compressorDoStringCompression to pick the dictionary + * words. + */ +class SortedDictionary +{ +public: + size_t m_cEntries; + SortedDictionaryEntry *m_apEntries[256]; + + SortedDictionary() + : m_cEntries(0) + { + for (size_t i = 0; i < RT_ELEMENTS(m_apEntries); i++) + m_apEntries[i] = NULL; + } + + ~SortedDictionary() + { + while (m_cEntries > 0) + { + free(m_apEntries[--m_cEntries]); + m_apEntries[m_cEntries] = NULL; + } + } + + + /** + * Inserts a new entry, if it's worth it. + * @returns true on succes, false if out of memory. + */ + bool insert(const char *a_pchString, size_t a_cchStringBase, size_t a_cchGain, char a_chSep = 0) + { + size_t const cchString = a_cchStringBase + (a_chSep + 1); + + /* + * Drop the insert if the symbol table is full and the insert is less worth the last entry: + */ + if ( m_cEntries >= RT_ELEMENTS(m_apEntries) + && m_apEntries[RT_ELEMENTS(m_apEntries) - 1]->compare(a_cchGain, cchString) >= 0) + return true; + + /* + * Create a new entry to insert. + */ + SortedDictionaryEntry *pNewEntry = SortedDictionaryEntry::allocate(a_pchString, a_cchStringBase, a_cchGain, a_chSep); + if (!pNewEntry) + return false; + + /* + * Find the insert point. + */ + if (m_cEntries == 0) + { + m_apEntries[0] = pNewEntry; + m_cEntries = 1; + } + else + { + /* If table is full, drop the last entry before we start (already made + sure the incoming entry is preferable to the one were dropping): */ + if (m_cEntries >= RT_ELEMENTS(m_apEntries)) + { + free(m_apEntries[RT_ELEMENTS(m_apEntries) - 1]); + m_apEntries[RT_ELEMENTS(m_apEntries) - 1] = NULL; + m_cEntries = RT_ELEMENTS(m_apEntries) - 1; + } + + /* Find where to insert the new entry: */ + /** @todo use binary search. */ + size_t i = m_cEntries; + while (i > 0 && m_apEntries[i - 1]->compare(a_cchGain, cchString) < 0) + i--; + + /* Shift entries to make room and insert the new entry. */ + if (i < m_cEntries) + memmove(&m_apEntries[i + 1], &m_apEntries[i], (m_cEntries - i) * sizeof(m_apEntries[0])); + m_apEntries[i] = pNewEntry; + m_cEntries++; + } + return true; + } +}; + + +/** + * Compresses the vendor and product strings. + * + * This is very very simple (a lot less work than the string table for + * instance). + */ +static bool bldProgStrTab_compressorDoStringCompression(PBLDPROGSTRTAB pThis, bool fVerbose) +{ + /* + * Sort the frequency analyzis result and pick the top entries for any + * available dictionary slots. + */ + SortedDictionary SortedDict; + for (BLDPROGWORDFREQMAP::iterator it = pThis->Frequencies.begin(); it != pThis->Frequencies.end(); ++it) + { + bool fInsert; + size_t const cchString = it->first.length(); +# ifndef BLDPROG_STRTAB_WITH_WORD_SEP_ALTERNATIVE + size_t const cchGainWithout = it->second.cWithoutSep * cchString; +# else + size_t const cchGainWithout = (it->second.cWithoutSep + it->second.cWithSep) * cchString; + size_t const cchGainWith = it->second.cWithSep * (cchString + 1); + if (cchGainWith > cchGainWithout) + fInsert = SortedDict.insert(it->first.c_str(), cchString, cchGainWith, it->second.chSep); + else +# endif + fInsert = SortedDict.insert(it->first.c_str(), cchString, cchGainWithout); + if (!fInsert) + return false; + } + + size_t cb = 0; + size_t cWords = 0; + size_t iDict = 0; + for (size_t i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++) + { + char szTmp[2] = { (char)i, '\0' }; + const char *psz = szTmp; + if ( BldProgBitIsSet(pThis->bmUsedChars, i) + || iDict >= SortedDict.m_cEntries) + { + /* character entry */ + pThis->auCompDictFreq[i] = 0; + pThis->aCompDict[i].cchString = 1; + } + else + { + /* word entry */ + cb += SortedDict.m_apEntries[iDict]->m_cchGain; + pThis->auCompDictFreq[i] = SortedDict.m_apEntries[iDict]->m_cchGain; + pThis->aCompDict[i].cchString = SortedDict.m_apEntries[iDict]->m_cchString; + psz = SortedDict.m_apEntries[iDict]->m_szString; + cWords++; + iDict++; + } + pThis->aCompDict[i].pszString = (char *)malloc(pThis->aCompDict[i].cchString + 1); + if (pThis->aCompDict[i].pszString) + memcpy(pThis->aCompDict[i].pszString, psz, pThis->aCompDict[i].cchString + 1); + else + return false; + } + + if (fVerbose) + printf("debug: Estimated string compression saving: %u bytes\n" + "debug: %u words, %u characters\n" + , (unsigned)cb, (unsigned)cWords, (unsigned)(RT_ELEMENTS(pThis->aCompDict) - cWords)); + + /* + * Rework the strings. + */ + size_t cchOld = 0; + size_t cchOldMax = 0; + size_t cchOldMin = BLDPROG_STRTAB_MAX_STRLEN; + size_t cchNew = 0; + size_t cchNewMax = 0; + size_t cchNewMin = BLDPROG_STRTAB_MAX_STRLEN; + size_t i = pThis->cPendingStrings; + while (i-- > 0) + { + PBLDPROGSTRING pCurStr = pThis->papPendingStrings[i]; + cchOld += pCurStr->cchString; + if (pCurStr->cchString > cchOldMax) + cchOldMax = pCurStr->cchString; + if (pCurStr->cchString < cchOldMin) + cchOldMin = pCurStr->cchString; + + if (!bldProgStrTab_compressorFixupString(pThis, pCurStr)) + return false; + + cchNew += pCurStr->cchString; + if (pCurStr->cchString > cchNewMax) + cchNewMax = pCurStr->cchString; + if (pCurStr->cchString < cchNewMin) + cchNewMin = pCurStr->cchString; + + bldProgStrTab_AddStringToHashTab(pThis, pCurStr); + } + + /* + * Do debug stats. + */ + if (fVerbose) + { + for (i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++) + cchNew += pThis->aCompDict[i].cchString + 1; + + printf("debug: Strings: original: %u bytes; compressed: %u bytes;", (unsigned)cchOld, (unsigned)cchNew); + if (cchNew < cchOld) + printf(" saving %u bytes (%u%%)\n", (unsigned)(cchOld - cchNew), (unsigned)((cchOld - cchNew) * 100 / cchOld)); + else + printf(" wasting %u bytes!\n", (unsigned)(cchOld - cchNew)); + printf("debug: Original string lengths: average %u; min %u; max %u\n", + (unsigned)(cchOld / pThis->cPendingStrings), (unsigned)cchOldMin, (unsigned)cchOldMax); + printf("debug: Compressed string lengths: average %u; min %u; max %u\n", + (unsigned)(cchNew / pThis->cPendingStrings), (unsigned)cchNewMin, (unsigned)cchNewMax); + } + + return true; +} + +#endif /* BLDPROG_STRTAB_WITH_COMPRESSION */ + +/** + * Inserts a string into g_apUniqueStrings. + * @param pThis The strint table compiler instance. + * @param pStr The string. + */ +static void bldProgStrTab_InsertUniqueString(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pStr) +{ + size_t iIdx; + size_t iEnd = pThis->cSortedStrings; + if (iEnd) + { + size_t iStart = 0; + for (;;) + { + iIdx = iStart + (iEnd - iStart) / 2; + if (pThis->papSortedStrings[iIdx]->cchString < pStr->cchString) + { + if (iIdx <= iStart) + break; + iEnd = iIdx; + } + else if (pThis->papSortedStrings[iIdx]->cchString > pStr->cchString) + { + if (++iIdx >= iEnd) + break; + iStart = iIdx; + } + else + break; + } + + if (iIdx != pThis->cSortedStrings) + memmove(&pThis->papSortedStrings[iIdx + 1], &pThis->papSortedStrings[iIdx], + (pThis->cSortedStrings - iIdx) * sizeof(pThis->papSortedStrings[iIdx])); + } + else + iIdx = 0; + + pThis->papSortedStrings[iIdx] = pStr; + pThis->cSortedStrings++; +} + + +/** + * Compiles the string table after the string has been added. + * + * This will save space by dropping string terminators, eliminating duplicates + * and try find strings that are sub-strings of others. + * + * Will initialize the StrRef of all StrTabString instances. + * + * @returns success indicator (error flagged). + * @param pThis The strint table compiler instance. + */ +static bool BldProgStrTab_CompileIt(PBLDPROGSTRTAB pThis, bool fVerbose) +{ +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + /* + * Do the compression and add all the compressed strings to the table. + */ + if (!bldProgStrTab_compressorDoStringCompression(pThis, fVerbose)) + return false; + + /* + * Add the dictionary strings. + */ + for (unsigned i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++) + if (pThis->aCompDict[i].cchString > 1) + bldProgStrTab_AddStringToHashTab(pThis, &pThis->aCompDict[i]); +# ifdef RT_STRICT + else if (pThis->aCompDict[i].cchString != 1) + abort(); +# endif +#endif + if (fVerbose) + printf("debug: %u unique strings (%u bytes), %u duplicates, %u collisions\n", + (unsigned)pThis->cUniqueStrings, (unsigned)pThis->cchUniqueStrings, + (unsigned)pThis->cDuplicateStrings, (unsigned)pThis->cCollisions); + + /* + * Create papSortedStrings from the hash table. The table is sorted by + * string length, with the longer strings first, so that we increase our + * chances of locating duplicate substrings. + */ + pThis->papSortedStrings = (PBLDPROGSTRING *)malloc(sizeof(pThis->papSortedStrings[0]) * pThis->cUniqueStrings); + if (!pThis->papSortedStrings) + return false; + pThis->cSortedStrings = 0; + size_t idxHash = pThis->cStrHash; + while (idxHash-- > 0) + { + PBLDPROGSTRING pCur = pThis->papStrHash[idxHash]; + if (pCur) + { + do + { + bldProgStrTab_InsertUniqueString(pThis, pCur); + pCur = pCur->pNextCollision; + } while (pCur); + } + } + + /* + * Create the actual string table. + */ + pThis->pachStrTab = (char *)malloc(pThis->cchUniqueStrings + 1); + if (!pThis->pachStrTab) + return false; + pThis->cchStrTab = 0; + for (size_t i = 0; i < pThis->cSortedStrings; i++) + { + PBLDPROGSTRING pCur = pThis->papSortedStrings[i]; + const char * const pszCur = pCur->pszString; + size_t const cchCur = pCur->cchString; + size_t offStrTab = pThis->cchStrTab; + + /* + * See if the string is a substring already found in the string table. + * Excluding the zero terminator increases the chances for this. + */ + size_t cchLeft = pThis->cchStrTab >= cchCur ? pThis->cchStrTab - cchCur : 0; + const char *pchLeft = pThis->pachStrTab; + char const chFirst = *pszCur; + while (cchLeft > 0) + { + const char *pchCandidate = (const char *)memchr(pchLeft, chFirst, cchLeft); + if (!pchCandidate) + break; + if (memcmp(pchCandidate, pszCur, cchCur) == 0) + { + offStrTab = pchCandidate - pThis->pachStrTab; + break; + } + + cchLeft -= pchCandidate + 1 - pchLeft; + pchLeft = pchCandidate + 1; + } + + if (offStrTab == pThis->cchStrTab) + { + /* + * See if the start of the string overlaps the end of the string table. + */ + if (pThis->cchStrTab && cchCur > 1) + { + cchLeft = RT_MIN(pThis->cchStrTab, cchCur - 1); + pchLeft = &pThis->pachStrTab[pThis->cchStrTab - cchLeft]; + while (cchLeft > 0) + { + const char *pchCandidate = (const char *)memchr(pchLeft, chFirst, cchLeft); + if (!pchCandidate) + break; + cchLeft -= pchCandidate - pchLeft; + pchLeft = pchCandidate; + if (memcmp(pchLeft, pszCur, cchLeft) == 0) + { + size_t cchToCopy = cchCur - cchLeft; + memcpy(&pThis->pachStrTab[offStrTab], &pszCur[cchLeft], cchToCopy); + pThis->cchStrTab += cchToCopy; + offStrTab = pchCandidate - pThis->pachStrTab; + break; + } + cchLeft--; + pchLeft++; + } + } + + /* + * If we didn't have any luck above, just append the string. + */ + if (offStrTab == pThis->cchStrTab) + { + memcpy(&pThis->pachStrTab[offStrTab], pszCur, cchCur); + pThis->cchStrTab += cchCur; + } + } + + /* + * Set the string table offset for all the references to this string. + */ + do + { + pCur->offStrTab = (uint32_t)offStrTab; + pCur = pCur->pNextRef; + } while (pCur != NULL); + } + + if (fVerbose) + printf("debug: String table: %u bytes\n", (unsigned)pThis->cchStrTab); + return true; +} + + +#ifdef RT_STRICT +/** + * Sanity checks a string table string. + * @param pThis The strint table compiler instance. + * @param pStr The string to check. + */ +static void BldProgStrTab_CheckStrTabString(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pStr) +{ + if (pStr->cchString != strlen(pStr->pszString)) + abort(); + if (pStr->offStrTab >= pThis->cchStrTab) + abort(); + if (pStr->offStrTab + pStr->cchString > pThis->cchStrTab) + abort(); + if (memcmp(pStr->pszString, &pThis->pachStrTab[pStr->offStrTab], pStr->cchString) != 0) + abort(); +} +#endif + + +/** + * Output the string table string in C string litteral fashion. + * + * @param pThis The strint table instance. + * @param pString The string to print. + * @param pOut The output stream. + */ +static void BldProgStrTab_PrintCStringLitteral(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pString, FILE *pOut) +{ + const unsigned char *psz = (const unsigned char *)pString->pszString; + unsigned char uch; + while ((uch = *psz++) != '\0') + { +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + if (pThis->aCompDict[uch].cchString == 1) +#else + if (!(uch & 0x80)) +#endif + { + if (uch != '\'' && uch != '\\') + fputc((char)uch, pOut); + else + { + fputc('\\', pOut); + fputc((char)uch, pOut); + } + } +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION +# ifndef BLDPROG_STRTAB_PURE_ASCII + else if (uch == 0xff) + { + RTUNICP uc = RTStrGetCp((const char *)psz); + psz += RTStrCpSize(uc); + fprintf(pOut, "\\u%04x", uc); + } +# else + else + fputs(pThis->aCompDict[uch].pszString, pOut); +# endif +#else + else + fprintf(pOut, "\\x%02x", (unsigned)uch); + NOREF(pThis); +#endif + } +} + + +/** + * Writes the string table code to the output stream. + * + * @param pThis The strint table compiler instance. + * @param pOut The output stream. + * @param pszScope The scoping ("static " or empty string), + * including trailing space. + * @param pszPrefix The variable prefix. Typically "g_" for C programs, + * whereas C++ classes normally use "class::s_g". + * @param pszBaseName The base name for the variables. The user + * accessible variable will end up as just the + * prefix and basename concatenated. + */ +static void BldProgStrTab_WriteStringTable(PBLDPROGSTRTAB pThis, FILE *pOut, + const char *pszScope, const char *pszPrefix, const char *pszBaseName) +{ +#ifdef RT_STRICT + /* + * Do some quick sanity checks while we're here. + */ +# ifdef BLDPROG_STRTAB_WITH_COMPRESSION + for (unsigned i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++) + { + if (BldProgBitIsSet(pThis->bmUsedChars, i) + ? pThis->aCompDict[i].cchString != 1 : pThis->aCompDict[i].cchString < 1) + abort(); + if (pThis->aCompDict[i].cchString > 1) + BldProgStrTab_CheckStrTabString(pThis, &pThis->aCompDict[i]); + } +# endif +#endif + + /* + * Create a table for speeding up the character categorization. + */ + uint8_t abCharCat[256]; + memset(abCharCat, 0, sizeof(abCharCat)); + abCharCat[(unsigned char)'\\'] = 1; + abCharCat[(unsigned char)'\''] = 1; + for (unsigned i = 0; i < 0x20; i++) + abCharCat[i] = 2; + for (unsigned i = 0x7f; i < 0x100; i++) + abCharCat[i] = 2; +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + for (unsigned i = 0; i < 0x100; i++) + if (!BldProgBitIsSet(pThis->bmUsedChars, i)) /* Encode table references using '\xYY'. */ + abCharCat[i] = 2; +#endif + + /* + * We follow the sorted string table, one string per line. + */ + fprintf(pOut, + "#include <iprt/bldprog-strtab.h>\n" + "\n" + "static const char g_achStrTab%s[] =\n" + "{\n", + pszBaseName); + + uint32_t off = 0; + for (uint32_t i = 0; i < pThis->cSortedStrings; i++) + { + PBLDPROGSTRING pCur = pThis->papSortedStrings[i]; + uint32_t offEnd = pCur->offStrTab + (uint32_t)pCur->cchString; + if (offEnd > off) + { + /* Comment with an uncompressed and more readable version of the string. */ + if (off == pCur->offStrTab) + fprintf(pOut, "/* 0x%05x = \"", off); + else + fprintf(pOut, "/* 0X%05x = \"", off); + BldProgStrTab_PrintCStringLitteral(pThis, pCur, pOut); + fputs("\" */\n", pOut); + + /* Must use char by char here or we may trigger the max string + length limit in the compiler, */ + fputs(" ", pOut); + for (; off < offEnd; off++) + { + unsigned char uch = pThis->pachStrTab[off]; + fputc('\'', pOut); + if (abCharCat[uch] == 0) + fputc(uch, pOut); + else if (abCharCat[uch] != 1) + fprintf(pOut, "\\x%02x", (unsigned)uch); + else + { + fputc('\\', pOut); + fputc(uch, pOut); + } + fputc('\'', pOut); + fputc(',', pOut); + } + fputc('\n', pOut); + } + } + + fprintf(pOut, + "};\n" + "AssertCompile(sizeof(g_achStrTab%s) == %#x);\n\n", + pszBaseName, (unsigned)pThis->cchStrTab); + +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + /* + * Write the compression dictionary. + */ + fprintf(pOut, + "static const RTBLDPROGSTRREF g_aCompDict%s[%u] = \n" + "{\n", + pszBaseName, (unsigned)RT_ELEMENTS(pThis->aCompDict)); + for (unsigned i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++) + if (pThis->aCompDict[i].cchString > 1) + fprintf(pOut, " /*[%3u]=*/ { %#08x, %#04x }, // %6lu - %s\n", i, + pThis->aCompDict[i].offStrTab, (unsigned)pThis->aCompDict[i].cchString, + (unsigned long)pThis->auCompDictFreq[i], pThis->aCompDict[i].pszString); +# ifndef BLDPROG_STRTAB_PURE_ASCII + else if (i == 0xff) + fprintf(pOut, " /*[%3u]=*/ { 0x000000, 0x00 }, // UTF-8 escape\n", i); +# endif + else if (i == 0) + fprintf(pOut, " /*[%3u]=*/ { 0x000000, 0x00 }, // unused, because zero terminator\n", i); + else if (i < 0x20) + fprintf(pOut, " /*[%3u]=*/ { 0x000000, 0x00 }, // %02x\n", i, i); + else + fprintf(pOut, " /*[%3u]=*/ { 0x000000, 0x00 }, // '%c'\n", i, (char)i); + fprintf(pOut, "};\n\n"); +#endif + + + /* + * Write the string table data structure. + */ + fprintf(pOut, + "%sconst RTBLDPROGSTRTAB %s%s = \n" + "{\n" + " /*.pchStrTab = */ &g_achStrTab%s[0],\n" + " /*.cchStrTab = */ sizeof(g_achStrTab%s),\n" + , + pszScope, pszPrefix, pszBaseName, pszBaseName, pszBaseName); +#ifdef BLDPROG_STRTAB_WITH_COMPRESSION + fprintf(pOut, + " /*.cCompDict = */ %u,\n" + " /*.paCompDict = */ &g_aCompDict%s[0]\n" + "};\n" +# ifndef BLDPROG_STRTAB_PURE_ASCII /* 255 or 256 entries is how the decoder knows */ + , (unsigned)RT_ELEMENTS(pThis->aCompDict) - 1, +# else + , (unsigned)RT_ELEMENTS(pThis->aCompDict), +# endif + pszBaseName); +#else + fprintf(pOut, + " /*.cCompDict = */ 0,\n" + " /*.paCompDict = */ NULL\n" + "};\n"); +#endif +} + +#if RT_CLANG_PREREQ(4, 0) || RT_GNUC_PREREQ(4, 6) +# pragma GCC diagnostic pop +#endif + +#endif /* __cplusplus && IN_RING3 */ + diff --git a/include/iprt/bldprog-strtab.h b/include/iprt/bldprog-strtab.h new file mode 100644 index 00000000..9a40d24a --- /dev/null +++ b/include/iprt/bldprog-strtab.h @@ -0,0 +1,259 @@ +/** @file + * IPRT - Build Program - String Table Generator, Accessors. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_bldprog_strtab_h +#define IPRT_INCLUDED_bldprog_strtab_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assert.h> +#include <iprt/err.h> +#include <iprt/string.h> + + +/** + * The default build program string table reference. + */ +typedef struct RTBLDPROGSTRREF +{ + /** Offset of the string in the string table. */ + uint32_t off : 22; + /** The length of the string. */ + uint32_t cch : 10; +} RTBLDPROGSTRREF; +AssertCompileSize(RTBLDPROGSTRREF, sizeof(uint32_t)); +/** Pointer to a build program string table reference. */ +typedef RTBLDPROGSTRREF const *PCRTBLDPROGSTRREF; + + +typedef struct RTBLDPROGSTRTAB +{ + const char *pchStrTab; + uint32_t cchStrTab; + uint32_t cCompDict; + PCRTBLDPROGSTRREF paCompDict; +} RTBLDPROGSTRTAB; +typedef const RTBLDPROGSTRTAB *PCRTBLDPROGSTRTAB; + + +/** + * Tries to ensure the buffer is terminated when failing. + */ +DECLINLINE(ssize_t) RTBldProgStrTabQueryStringFail(int rc, char *pszDstStart, char *pszDst, size_t cbDst) +{ + if (cbDst) + *pszDst = '\0'; + else if (pszDstStart != pszDst) + pszDst[-1] = '\0'; + return rc; +} + + +/** + * Retrieves the decompressed string. + * + * @returns The string size on success, IPRT status code on failure. + * @param pStrTab The string table. + * @param offString The offset of the string. + * @param cchString The length of the string. + * @param pszDst The return buffer. + * @param cbDst The size of the return buffer. + */ +DECLINLINE(ssize_t) RTBldProgStrTabQueryString(PCRTBLDPROGSTRTAB pStrTab, uint32_t offString, size_t cchString, + char *pszDst, size_t cbDst) +{ + AssertReturn(offString < pStrTab->cchStrTab, VERR_OUT_OF_RANGE); + AssertReturn(offString + cchString <= pStrTab->cchStrTab, VERR_OUT_OF_RANGE); + + if (pStrTab->cCompDict) + { + Assert(pStrTab->cCompDict == 256 || pStrTab->cCompDict == 255); + + /* + * Is compressed, decompress it. + */ + char * const pchDstStart = pszDst; + const char *pchSrc = &pStrTab->pchStrTab[offString]; + while (cchString-- > 0) + { + unsigned char uch = *(unsigned char *)pchSrc++; + if (uch != 0xff || pStrTab->cCompDict > 0xff) + { + /* + * Look it up in the dictionary, either a single 7-bit character or a word. + * Either way, no UTF-8 unescaping necessary. + */ + PCRTBLDPROGSTRREF pWord = &pStrTab->paCompDict[uch]; + size_t const cchWord = pWord->cch; + if (cchWord <= 1) + { + Assert(uch != 0); + Assert(uch <= 127); + AssertReturn(cbDst > 1, RTBldProgStrTabQueryStringFail(VERR_BUFFER_OVERFLOW, pchDstStart, pszDst, cbDst)); + cbDst -= 1; + *pszDst++ = (char)uch; + } + else + { + Assert(cchWord > 1); + AssertReturn((size_t)pWord->off + cchWord <= pStrTab->cchStrTab, + RTBldProgStrTabQueryStringFail(VERR_INVALID_PARAMETER, pchDstStart, pszDst, cbDst)); + AssertReturn(cbDst > cchWord, + RTBldProgStrTabQueryStringFail(VERR_BUFFER_OVERFLOW, pchDstStart, pszDst, cbDst)); + memcpy(pszDst, &pStrTab->pchStrTab[pWord->off], cchWord); + pszDst += cchWord; + cbDst -= cchWord; + } + } + else + { + /* + * UTF-8 encoded unicode codepoint. + */ + size_t cchCp; + RTUNICP uc = ' '; + int rc = RTStrGetCpNEx(&pchSrc, &cchString, &uc); + AssertStmt(RT_SUCCESS(rc), (uc = '?', pchSrc++, cchString--)); + + cchCp = RTStrCpSize(uc); + AssertReturn(cbDst > cchCp, + RTBldProgStrTabQueryStringFail(VERR_BUFFER_OVERFLOW, pchDstStart, pszDst, cbDst)); + + RTStrPutCp(pszDst, uc); + pszDst += cchCp; + cbDst -= cchCp; + } + } + AssertReturn(cbDst > 0, RTBldProgStrTabQueryStringFail(VERR_BUFFER_OVERFLOW, pchDstStart, pszDst, cbDst)); + *pszDst = '\0'; + return pszDst - pchDstStart; + } + + /* + * Not compressed. + */ + if (cbDst > cchString) + { + memcpy(pszDst, &pStrTab->pchStrTab[offString], cchString); + pszDst[cchString] = '\0'; + return (ssize_t)cchString; + } + if (cbDst > 0) + { + memcpy(pszDst, &pStrTab->pchStrTab[offString], cbDst - 1); + pszDst[cbDst - 1] = '\0'; + } + return VERR_BUFFER_OVERFLOW; +} + + +/** + * Outputs the decompressed string. + * + * @returns The sum of the pfnOutput return values. + * @param pStrTab The string table. + * @param offString The offset of the string. + * @param cchString The length of the string. + * @param pfnOutput The output function. + * @param pvArgOutput The argument to pass to the output function. + * + */ +DECLINLINE(size_t) RTBldProgStrTabQueryOutput(PCRTBLDPROGSTRTAB pStrTab, uint32_t offString, size_t cchString, + PFNRTSTROUTPUT pfnOutput, void *pvArgOutput) +{ + AssertReturn(offString < pStrTab->cchStrTab, 0); + AssertReturn(offString + cchString <= pStrTab->cchStrTab, 0); + + if (pStrTab->cCompDict) + { + Assert(pStrTab->cCompDict == 256 || pStrTab->cCompDict == 255); + + /* + * Could be compressed, decompress it. + */ + size_t cchRet = 0; + const char *pchSrc = &pStrTab->pchStrTab[offString]; + while (cchString-- > 0) + { + unsigned char uch = *(unsigned char *)pchSrc++; + if (uch != 0xff || pStrTab->cCompDict > 0xff) + { + /* + * Look it up in the dictionary, either a single 7-bit character or a word. + * Either way, no UTF-8 unescaping necessary. + */ + PCRTBLDPROGSTRREF pWord = &pStrTab->paCompDict[uch]; + size_t const cchWord = pWord->cch; + if (cchWord <= 1) + { + Assert(uch != 0); + Assert(uch <= 127); + cchRet += pfnOutput(pvArgOutput, (const char *)&uch, 1); + } + else + { + Assert(cchWord > 1); + AssertReturn((size_t)pWord->off + cchWord <= pStrTab->cchStrTab, cchRet); + + cchRet += pfnOutput(pvArgOutput, &pStrTab->pchStrTab[pWord->off], cchWord); + } + } + else + { + /* + * UTF-8 encoded unicode codepoint. + */ + const char * const pchUtf8Seq = pchSrc; + RTUNICP uc = ' '; + int rc = RTStrGetCpNEx(&pchSrc, &cchString, &uc); + if (RT_SUCCESS(rc)) + cchRet += pfnOutput(pvArgOutput, pchUtf8Seq, (size_t)(pchSrc - pchUtf8Seq)); + else + cchRet += pfnOutput(pvArgOutput, "?", 1); + } + } + return cchRet; + } + + /* + * Not compressed. + */ + return pfnOutput(pvArgOutput, &pStrTab->pchStrTab[offString], cchString); +} + + +#endif /* !IPRT_INCLUDED_bldprog_strtab_h */ + diff --git a/include/iprt/buildconfig.h b/include/iprt/buildconfig.h new file mode 100644 index 00000000..b5292d0c --- /dev/null +++ b/include/iprt/buildconfig.h @@ -0,0 +1,138 @@ +/** @file + * IPRT - Build Configuration Information + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_buildconfig_h +#define IPRT_INCLUDED_buildconfig_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_buildconfig RTBldCfg - Build Configuration Information + * @ingroup grp_rt + * @{ + */ + +/** + * Gets the source code management revision of the IPRT build. + * @returns Source code management revision number. + */ +RTDECL(uint32_t) RTBldCfgRevision(void); + +/** + * Gets the source code management revision of the IPRT build. + * @returns Read only string containing the revision number. + */ +RTDECL(const char *) RTBldCfgRevisionStr(void); + +/** + * Gets the product version string. + * + * This will be a string on the form "x.y.z[_string]". + * + * @returns Read only version string. + * + * @remarks This is a build time configuration thing that the product using IPRT + * will set. It is therefore not any IPRT version, but rather the + * version of that product. + */ +RTDECL(const char *) RTBldCfgVersion(void); + +/** + * Gets the major product version number. + * @returns Major product version number. + * @remarks See RTBldCfgVersion. + */ +RTDECL(uint32_t) RTBldCfgVersionMajor(void); + +/** + * Gets the minor product version number. + * @returns Minor product version number. + * @remarks See RTBldCfgVersion. + */ +RTDECL(uint32_t) RTBldCfgVersionMinor(void); + +/** + * Gets the product build number. + * @returns Product build number. + * @remarks See RTBldCfgVersion. + */ +RTDECL(uint32_t) RTBldCfgVersionBuild(void); + +/** + * Gets the build target name. + * + * @returns Read only build target string. + */ +RTDECL(const char *) RTBldCfgTarget(void); + +/** + * Gets the build target architecture name. + * + * @returns Read only build target architecture string. + */ +RTDECL(const char *) RTBldCfgTargetArch(void); + +/** + * Gets the build target-dot-architecture name. + * + * @returns Read only build target-dot-architecture string. + */ +RTDECL(const char *) RTBldCfgTargetDotArch(void); + +/** + * Gets the build type name. + * + * @returns Read only build type string. + */ +RTDECL(const char *) RTBldCfgType(void); + +/** + * Gets the name of the compiler used for building IPRT. + * + * @returns Read only compiler name. + */ +RTDECL(const char *) RTBldCfgCompiler(void); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_buildconfig_h */ + diff --git a/include/iprt/cdefs.h b/include/iprt/cdefs.h new file mode 100644 index 00000000..8fe26f69 --- /dev/null +++ b/include/iprt/cdefs.h @@ -0,0 +1,4901 @@ +/** @file + * IPRT - Common C and C++ definitions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cdefs_h +#define IPRT_INCLUDED_cdefs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/** @defgroup grp_rt_cdefs IPRT Common Definitions and Macros + * @{ + */ + +/** @def RT_C_DECLS_BEGIN + * Used to start a block of function declarations which are shared + * between C and C++ program. + */ + +/** @def RT_C_DECLS_END + * Used to end a block of function declarations which are shared + * between C and C++ program. + */ + +#if defined(__cplusplus) +# define RT_C_DECLS_BEGIN extern "C" { +# define RT_C_DECLS_END } +#else +# define RT_C_DECLS_BEGIN +# define RT_C_DECLS_END +#endif + + +/* + * Shut up DOXYGEN warnings and guide it properly thru the code. + */ +#ifdef DOXYGEN_RUNNING +# define __AMD64__ +# define __X86__ +# define RT_ARCH_AMD64 +# define RT_ARCH_X86 +# define RT_ARCH_SPARC +# define RT_ARCH_SPARC64 +# define RT_ARCH_ARM32 +# define RT_ARCH_ARM64 +# define IN_RING0 +# define IN_RING3 +# define IN_RC +# define IN_RT_RC +# define IN_RT_R0 +# define IN_RT_R3 +# define IN_RT_STATIC +# define RT_STRICT +# define RT_NO_STRICT +# define RT_LOCK_STRICT +# define RT_LOCK_NO_STRICT +# define RT_LOCK_STRICT_ORDER +# define RT_LOCK_NO_STRICT_ORDER +# define RT_BREAKPOINT +# define RT_NO_DEPRECATED_MACROS +# define RT_EXCEPTIONS_ENABLED +# define RT_BIG_ENDIAN +# define RT_LITTLE_ENDIAN +# define RT_COMPILER_GROKS_64BIT_BITFIELDS +# define RT_COMPILER_WITH_80BIT_LONG_DOUBLE +# define RT_COMPILER_WITH_128BIT_LONG_DOUBLE +# define RT_COMPILER_WITH_128BIT_INT_TYPES +# define RT_NO_VISIBILITY_HIDDEN +# define RT_GCC_SUPPORTS_VISIBILITY_HIDDEN +# define RT_COMPILER_SUPPORTS_VA_ARGS +# define RT_COMPILER_SUPPORTS_LAMBDA +#endif /* DOXYGEN_RUNNING */ + +/** @def RT_ARCH_X86 + * Indicates that we're compiling for the X86 architecture. + */ + +/** @def RT_ARCH_AMD64 + * Indicates that we're compiling for the AMD64 architecture. + */ + +/** @def RT_ARCH_SPARC + * Indicates that we're compiling for the SPARC V8 architecture (32-bit). + */ + +/** @def RT_ARCH_SPARC64 + * Indicates that we're compiling for the SPARC V9 architecture (64-bit). + */ + +/** @def RT_ARCH_ARM32 + * Indicates that we're compiling for the 32-bit ARM architecture, the value + * is the version (i.e. 6 for ARMv6). + */ + +/** @def RT_ARCH_ARM64 + * Indicates that we're compiling for the 64-bit ARM architecture. + */ + +#if !defined(RT_ARCH_X86) \ + && !defined(RT_ARCH_AMD64) \ + && !defined(RT_ARCH_SPARC) \ + && !defined(RT_ARCH_SPARC64) \ + && !defined(RT_ARCH_ARM32) \ + && !defined(RT_ARCH_ARM64) +# if defined(__amd64__) || defined(__x86_64__) || defined(_M_X64) || defined(__AMD64__) +# define RT_ARCH_AMD64 +# elif defined(__i386__) || defined(_M_IX86) || defined(__X86__) +# define RT_ARCH_X86 +# elif defined(__sparcv9) +# define RT_ARCH_SPARC64 +# elif defined(__sparc__) +# define RT_ARCH_SPARC +# elif defined(__arm64__) || defined(__aarch64__) +# define RT_ARCH_ARM64 __ARM_ARCH +# elif defined(__arm__) +# define RT_ARCH_ARM32 __ARM_ARCH +# elif defined(__arm32__) +# define RT_ARCH_ARM32 __ARM_ARCH +# else /* PORTME: append test for new archs. */ +# error "Check what predefined macros your compiler uses to indicate architecture." +# endif +/* PORTME: append new archs checks. */ +#elif defined(RT_ARCH_X86) && defined(RT_ARCH_AMD64) +# error "Both RT_ARCH_X86 and RT_ARCH_AMD64 cannot be defined at the same time!" +#elif defined(RT_ARCH_X86) && defined(RT_ARCH_SPARC) +# error "Both RT_ARCH_X86 and RT_ARCH_SPARC cannot be defined at the same time!" +#elif defined(RT_ARCH_X86) && defined(RT_ARCH_SPARC64) +# error "Both RT_ARCH_X86 and RT_ARCH_SPARC64 cannot be defined at the same time!" +#elif defined(RT_ARCH_AMD64) && defined(RT_ARCH_SPARC) +# error "Both RT_ARCH_AMD64 and RT_ARCH_SPARC cannot be defined at the same time!" +#elif defined(RT_ARCH_AMD64) && defined(RT_ARCH_SPARC64) +# error "Both RT_ARCH_AMD64 and RT_ARCH_SPARC64 cannot be defined at the same time!" +#elif defined(RT_ARCH_SPARC) && defined(RT_ARCH_SPARC64) +# error "Both RT_ARCH_SPARC and RT_ARCH_SPARC64 cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM32) && defined(RT_ARCH_AMD64) +# error "Both RT_ARCH_ARM32 and RT_ARCH_AMD64 cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM32) && defined(RT_ARCH_X86) +# error "Both RT_ARCH_ARM32 and RT_ARCH_X86 cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM32) && defined(RT_ARCH_SPARC64) +# error "Both RT_ARCH_ARM32 and RT_ARCH_SPARC64 cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM32) && defined(RT_ARCH_SPARC) +# error "Both RT_ARCH_ARM32 and RT_ARCH_SPARC cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM64) && defined(RT_ARCH_AMD64) +# error "Both RT_ARCH_ARM64 and RT_ARCH_AMD64 cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM64) && defined(RT_ARCH_X86) +# error "Both RT_ARCH_ARM64 and RT_ARCH_X86 cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM64) && defined(RT_ARCH_SPARC64) +# error "Both RT_ARCH_ARM64 and RT_ARCH_SPARC64 cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM64) && defined(RT_ARCH_SPARC) +# error "Both RT_ARCH_ARM64 and RT_ARCH_SPARC cannot be defined at the same time!" +#elif defined(RT_ARCH_ARM64) && defined(RT_ARCH_ARM32) +# error "Both RT_ARCH_ARM64 and RT_ARCH_ARM32 cannot be defined at the same time!" +#endif +#ifdef RT_ARCH_ARM +# error "RT_ARCH_ARM is now RT_ARCH_ARM32!" +#endif + +/* Final check (PORTME). */ +#if (defined(RT_ARCH_X86) != 0) \ + + (defined(RT_ARCH_AMD64) != 0) \ + + (defined(RT_ARCH_SPARC) != 0) \ + + (defined(RT_ARCH_SPARC64) != 0) \ + + (defined(RT_ARCH_ARM32) != 0) \ + + (defined(RT_ARCH_ARM64) != 0) \ + != 1 +# error "Exactly one RT_ARCH_XXX macro shall be defined" +#endif + +/** @def RT_CPLUSPLUS_PREREQ + * Require a minimum __cplusplus value, simplifying dealing with non-C++ code. + * + * @param a_Min The minimum version, e.g. 201100. + */ +#ifdef __cplusplus +# define RT_CPLUSPLUS_PREREQ(a_Min) (__cplusplus >= (a_Min)) +#else +# define RT_CPLUSPLUS_PREREQ(a_Min) (0) +#endif + +/** @def RT_GNUC_PREREQ + * Shorter than fiddling with __GNUC__ and __GNUC_MINOR__. + * + * @param a_MinMajor Minimum major version + * @param a_MinMinor The minor version number part. + */ +#define RT_GNUC_PREREQ(a_MinMajor, a_MinMinor) RT_GNUC_PREREQ_EX(a_MinMajor, a_MinMinor, 0) +/** @def RT_GNUC_PREREQ_EX + * Simplified way of checking __GNUC__ and __GNUC_MINOR__ regardless of actual + * compiler used, returns @a a_OtherRet for other compilers. + * + * @param a_MinMajor Minimum major version + * @param a_MinMinor The minor version number part. + * @param a_OtherRet What to return for non-GCC compilers. + */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +# define RT_GNUC_PREREQ_EX(a_MinMajor, a_MinMinor, a_OtherRet) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((a_MinMajor) << 16) + (a_MinMinor)) +#else +# define RT_GNUC_PREREQ_EX(a_MinMajor, a_MinMinor, a_OtherRet) (a_OtherRet) +#endif + +/** @def RT_MSC_PREREQ + * Convenient way of checking _MSC_VER regardless of actual compiler used + * (returns false if not MSC). + * + * @param a_MinVer Preferably a RT_MSC_VER_XXX value. + */ +#define RT_MSC_PREREQ(a_MinVer) RT_MSC_PREREQ_EX(a_MinVer, 0) +/** @def RT_MSC_PREREQ_EX + * Convenient way of checking _MSC_VER regardless of actual compiler used, + * returns @a a_OtherRet for other compilers. + * + * @param a_MinVer Preferably a RT_MSC_VER_XXX value. + * @param a_OtherRet What to return for non-MSC compilers. + */ +#if defined(_MSC_VER) +# define RT_MSC_PREREQ_EX(a_MinVer, a_OtherRet) ( (_MSC_VER) >= (a_MinVer) ) +#else +# define RT_MSC_PREREQ_EX(a_MinVer, a_OtherRet) (a_OtherRet) +#endif +/** @name RT_MSC_VER_XXX - _MSC_VER values to use with RT_MSC_PREREQ. + * @remarks The VCxxx values are derived from the CRT DLLs shipping with the + * compilers. + * @{ */ +#define RT_MSC_VER_VC50 (1100) /**< Visual C++ 5.0. */ +#define RT_MSC_VER_VC60 (1200) /**< Visual C++ 6.0. */ +#define RT_MSC_VER_VC70 (1300) /**< Visual C++ 7.0. */ +#define RT_MSC_VER_VC70 (1300) /**< Visual C++ 7.0. */ +#define RT_MSC_VER_VS2003 (1310) /**< Visual Studio 2003, aka Visual C++ 7.1. */ +#define RT_MSC_VER_VC71 RT_MSC_VER_VS2003 /**< Visual C++ 7.1, aka Visual Studio 2003. */ +#define RT_MSC_VER_VS2005 (1400) /**< Visual Studio 2005. */ +#define RT_MSC_VER_VC80 RT_MSC_VER_VS2005 /**< Visual C++ 8.0, aka Visual Studio 2008. */ +#define RT_MSC_VER_VS2008 (1500) /**< Visual Studio 2008. */ +#define RT_MSC_VER_VC90 RT_MSC_VER_VS2008 /**< Visual C++ 9.0, aka Visual Studio 2008. */ +#define RT_MSC_VER_VS2010 (1600) /**< Visual Studio 2010. */ +#define RT_MSC_VER_VC100 RT_MSC_VER_VS2010 /**< Visual C++ 10.0, aka Visual Studio 2010. */ +#define RT_MSC_VER_VS2012 (1700) /**< Visual Studio 2012. */ +#define RT_MSC_VER_VC110 RT_MSC_VER_VS2012 /**< Visual C++ 11.0, aka Visual Studio 2012. */ +#define RT_MSC_VER_VS2013 (1800) /**< Visual Studio 2013. */ +#define RT_MSC_VER_VC120 RT_MSC_VER_VS2013 /**< Visual C++ 12.0, aka Visual Studio 2013. */ +#define RT_MSC_VER_VS2015 (1900) /**< Visual Studio 2015. */ +#define RT_MSC_VER_VC140 RT_MSC_VER_VS2015 /**< Visual C++ 14.0, aka Visual Studio 2015. */ +#define RT_MSC_VER_VS2017 (1910) /**< Visual Studio 2017. */ +#define RT_MSC_VER_VC141 RT_MSC_VER_VS2017 /**< Visual C++ 14.1, aka Visual Studio 2017. */ +#define RT_MSC_VER_VS2019 (1920) /**< Visual Studio 2019. */ +#define RT_MSC_VER_VC142 RT_MSC_VER_VS2019 /**< Visual C++ 14.2, aka Visual Studio 2019. */ +#define RT_MSC_VER_VS2019_U6 (1926) /**< Visual Studio 2019, update 6. */ +#define RT_MSC_VER_VC142_U6 RT_MSC_VER_VS2019_U6 /**< Visual C++ 14.2 update 6. */ +#define RT_MSC_VER_VS2019_U8 (1928) /**< Visual Studio 2019, update 8. */ +#define RT_MSC_VER_VC142_U8 RT_MSC_VER_VS2019_U8 /**< Visual C++ 14.2 update 8. */ +#define RT_MSC_VER_VS2019_U11 (1929) /**< Visual Studio 2019, update 11. */ +#define RT_MSC_VER_VC142_U11 RT_MSC_VER_VS2019_U11 /**< Visual C++ 14.2 update 11. */ +/** @} */ + +/** @def RT_CLANG_PREREQ + * Shorter than fiddling with __clang_major__ and __clang_minor__. + * + * @param a_MinMajor Minimum major version + * @param a_MinMinor The minor version number part. + */ +#define RT_CLANG_PREREQ(a_MinMajor, a_MinMinor) RT_CLANG_PREREQ_EX(a_MinMajor, a_MinMinor, 0) +/** @def RT_CLANG_PREREQ_EX + * Simplified way of checking __clang_major__ and __clang_minor__ regardless of + * actual compiler used, returns @a a_OtherRet for other compilers. + * + * @param a_MinMajor Minimum major version + * @param a_MinMinor The minor version number part. + * @param a_OtherRet What to return for non-GCC compilers. + */ +#if defined(__clang_major__) && defined(__clang_minor__) +# define RT_CLANG_PREREQ_EX(a_MinMajor, a_MinMinor, a_OtherRet) \ + ((__clang_major__ << 16) + __clang_minor__ >= ((a_MinMajor) << 16) + (a_MinMinor)) +#else +# define RT_CLANG_PREREQ_EX(a_MinMajor, a_MinMinor, a_OtherRet) (a_OtherRet) +#endif +/** @def RT_CLANG_HAS_FEATURE + * Wrapper around clang's __has_feature(). + * + * @param a_Feature The feature to check for. + */ +#if defined(__clang_major__) && defined(__clang_minor__) && defined(__has_feature) +# define RT_CLANG_HAS_FEATURE(a_Feature) (__has_feature(a_Feature)) +#else +# define RT_CLANG_HAS_FEATURE(a_Feature) (0) +#endif + + +#if !defined(__X86__) && !defined(__AMD64__) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) +# if defined(RT_ARCH_AMD64) +/** Indicates that we're compiling for the AMD64 architecture. + * @deprecated + */ +# define __AMD64__ +# elif defined(RT_ARCH_X86) +/** Indicates that we're compiling for the X86 architecture. + * @deprecated + */ +# define __X86__ +# else +# error "Check what predefined macros your compiler uses to indicate architecture." +# endif +#elif defined(__X86__) && defined(__AMD64__) +# error "Both __X86__ and __AMD64__ cannot be defined at the same time!" +#elif defined(__X86__) && !defined(RT_ARCH_X86) +# error "__X86__ without RT_ARCH_X86!" +#elif defined(__AMD64__) && !defined(RT_ARCH_AMD64) +# error "__AMD64__ without RT_ARCH_AMD64!" +#endif + +/** @def RT_BIG_ENDIAN + * Defined if the architecture is big endian. */ +/** @def RT_LITTLE_ENDIAN + * Defined if the architecture is little endian. */ +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) || defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) +# define RT_LITTLE_ENDIAN +#elif defined(RT_ARCH_SPARC) || defined(RT_ARCH_SPARC64) +# define RT_BIG_ENDIAN +#else +# error "PORTME: architecture endianess" +#endif +#if defined(RT_BIG_ENDIAN) && defined(RT_LITTLE_ENDIAN) +# error "Both RT_BIG_ENDIAN and RT_LITTLE_ENDIAN are defined" +#endif + + +/** @def IN_RING0 + * Used to indicate that we're compiling code which is running + * in Ring-0 Host Context. + */ + +/** @def IN_RING3 + * Used to indicate that we're compiling code which is running + * in Ring-3 Host Context. + */ + +/** @def IN_RC + * Used to indicate that we're compiling code which is running + * in the Raw-mode Context (implies R0). + */ +#if !defined(IN_RING3) && !defined(IN_RING0) && !defined(IN_RC) +# error "You must define which context the compiled code should run in; IN_RING3, IN_RING0 or IN_RC" +#endif +#if (defined(IN_RING3) && (defined(IN_RING0) || defined(IN_RC)) ) \ + || (defined(IN_RING0) && (defined(IN_RING3) || defined(IN_RC)) ) \ + || (defined(IN_RC) && (defined(IN_RING3) || defined(IN_RING0)) ) +# error "Only one of the IN_RING3, IN_RING0, IN_RC defines should be defined." +#endif + + +/** @def ARCH_BITS + * Defines the bit count of the current context. + */ +#if !defined(ARCH_BITS) || defined(DOXYGEN_RUNNING) +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_SPARC64) || defined(RT_ARCH_ARM64) || defined(DOXYGEN_RUNNING) +# define ARCH_BITS 64 +# elif !defined(__I86__) || !defined(__WATCOMC__) +# define ARCH_BITS 32 +# else +# define ARCH_BITS 16 +# endif +#endif + +/* ARCH_BITS validation (PORTME). */ +#if ARCH_BITS == 64 + #if defined(RT_ARCH_X86) || defined(RT_ARCH_SPARC) || defined(RT_ARCH_ARM32) + # error "ARCH_BITS=64 but non-64-bit RT_ARCH_XXX defined." + #endif + #if !defined(RT_ARCH_AMD64) && !defined(RT_ARCH_SPARC64) && !defined(RT_ARCH_ARM64) + # error "ARCH_BITS=64 but no 64-bit RT_ARCH_XXX defined." + #endif + +#elif ARCH_BITS == 32 + #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_SPARC64) || defined(RT_ARCH_ARM64) + # error "ARCH_BITS=32 but non-32-bit RT_ARCH_XXX defined." + #endif + #if !defined(RT_ARCH_X86) && !defined(RT_ARCH_SPARC) && !defined(RT_ARCH_ARM32) + # error "ARCH_BITS=32 but no 32-bit RT_ARCH_XXX defined." + #endif + +#elif ARCH_BITS == 16 + #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_SPARC) || defined(RT_ARCH_SPARC64) || defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) + # error "ARCH_BITS=16 but non-16-bit RT_ARCH_XX defined." + #endif + #if !defined(RT_ARCH_X86) + # error "ARCH_BITS=16 but RT_ARCH_X86 isn't defined." + #endif + +#else +# error "Unsupported ARCH_BITS value!" +#endif + +/** @def HC_ARCH_BITS + * Defines the host architecture bit count. + */ +#if !defined(HC_ARCH_BITS) || defined(DOXYGEN_RUNNING) +# if !defined(IN_RC) || defined(DOXYGEN_RUNNING) +# define HC_ARCH_BITS ARCH_BITS +# else +# define HC_ARCH_BITS 32 +# endif +#endif + +/** @def GC_ARCH_BITS + * Defines the guest architecture bit count. + */ +#if !defined(GC_ARCH_BITS) || defined(DOXYGEN_RUNNING) +# if defined(VBOX_WITH_64_BITS_GUESTS) || defined(DOXYGEN_RUNNING) +# define GC_ARCH_BITS 64 +# else +# define GC_ARCH_BITS 32 +# endif +#endif + +/** @def R3_ARCH_BITS + * Defines the host ring-3 architecture bit count. + */ +#if !defined(R3_ARCH_BITS) || defined(DOXYGEN_RUNNING) +# ifdef IN_RING3 +# define R3_ARCH_BITS ARCH_BITS +# else +# define R3_ARCH_BITS HC_ARCH_BITS +# endif +#endif + +/** @def R0_ARCH_BITS + * Defines the host ring-0 architecture bit count. + */ +#if !defined(R0_ARCH_BITS) || defined(DOXYGEN_RUNNING) +# ifdef IN_RING0 +# define R0_ARCH_BITS ARCH_BITS +# else +# define R0_ARCH_BITS HC_ARCH_BITS +# endif +#endif + + + +/** @name RT_OPSYS_XXX - Operative System Identifiers. + * These are the value that the RT_OPSYS \#define can take. @{ + */ +/** Unknown OS. */ +#define RT_OPSYS_UNKNOWN 0 +/** OS Agnostic. */ +#define RT_OPSYS_AGNOSTIC 1 +/** Darwin - aka Mac OS X. */ +#define RT_OPSYS_DARWIN 2 +/** DragonFly BSD. */ +#define RT_OPSYS_DRAGONFLY 3 +/** DOS. */ +#define RT_OPSYS_DOS 4 +/** FreeBSD. */ +#define RT_OPSYS_FREEBSD 5 +/** Haiku. */ +#define RT_OPSYS_HAIKU 6 +/** Linux. */ +#define RT_OPSYS_LINUX 7 +/** L4. */ +#define RT_OPSYS_L4 8 +/** Minix. */ +#define RT_OPSYS_MINIX 9 +/** NetBSD. */ +#define RT_OPSYS_NETBSD 11 +/** Netware. */ +#define RT_OPSYS_NETWARE 12 +/** NT (native). */ +#define RT_OPSYS_NT 13 +/** OpenBSD. */ +#define RT_OPSYS_OPENBSD 14 +/** OS/2. */ +#define RT_OPSYS_OS2 15 +/** Plan 9. */ +#define RT_OPSYS_PLAN9 16 +/** QNX. */ +#define RT_OPSYS_QNX 17 +/** Solaris. */ +#define RT_OPSYS_SOLARIS 18 +/** UEFI. */ +#define RT_OPSYS_UEFI 19 +/** Windows. */ +#define RT_OPSYS_WINDOWS 20 +/** The max RT_OPSYS_XXX value (exclusive). */ +#define RT_OPSYS_MAX 21 +/** @} */ + +/** @def RT_OPSYS + * Indicates which OS we're targeting. It's a \#define with is + * assigned one of the RT_OPSYS_XXX defines above. + * + * So to test if we're on FreeBSD do the following: + * @code + * #if RT_OPSYS == RT_OPSYS_FREEBSD + * some_funky_freebsd_specific_stuff(); + * #endif + * @endcode + */ + +/* + * Set RT_OPSYS_XXX according to RT_OS_XXX. + * + * Search: #define RT_OPSYS_([A-Z0-9]+) .* + * Replace: # elif defined(RT_OS_\1)\n# define RT_OPSYS RT_OPSYS_\1 + */ +#ifndef RT_OPSYS +# if defined(RT_OS_UNKNOWN) || defined(DOXYGEN_RUNNING) +# define RT_OPSYS RT_OPSYS_UNKNOWN +# elif defined(RT_OS_AGNOSTIC) +# define RT_OPSYS RT_OPSYS_AGNOSTIC +# elif defined(RT_OS_DARWIN) +# define RT_OPSYS RT_OPSYS_DARWIN +# elif defined(RT_OS_DRAGONFLY) +# define RT_OPSYS RT_OPSYS_DRAGONFLY +# elif defined(RT_OS_DOS) +# define RT_OPSYS RT_OPSYS_DOS +# elif defined(RT_OS_FREEBSD) +# define RT_OPSYS RT_OPSYS_FREEBSD +# elif defined(RT_OS_HAIKU) +# define RT_OPSYS RT_OPSYS_HAIKU +# elif defined(RT_OS_LINUX) +# define RT_OPSYS RT_OPSYS_LINUX +# elif defined(RT_OS_L4) +# define RT_OPSYS RT_OPSYS_L4 +# elif defined(RT_OS_MINIX) +# define RT_OPSYS RT_OPSYS_MINIX +# elif defined(RT_OS_NETBSD) +# define RT_OPSYS RT_OPSYS_NETBSD +# elif defined(RT_OS_NETWARE) +# define RT_OPSYS RT_OPSYS_NETWARE +# elif defined(RT_OS_NT) +# define RT_OPSYS RT_OPSYS_NT +# elif defined(RT_OS_OPENBSD) +# define RT_OPSYS RT_OPSYS_OPENBSD +# elif defined(RT_OS_OS2) +# define RT_OPSYS RT_OPSYS_OS2 +# elif defined(RT_OS_PLAN9) +# define RT_OPSYS RT_OPSYS_PLAN9 +# elif defined(RT_OS_QNX) +# define RT_OPSYS RT_OPSYS_QNX +# elif defined(RT_OS_SOLARIS) +# define RT_OPSYS RT_OPSYS_SOLARIS +# elif defined(RT_OS_UEFI) +# define RT_OPSYS RT_OPSYS_UEFI +# elif defined(RT_OS_WINDOWS) +# define RT_OPSYS RT_OPSYS_WINDOWS +# endif +#endif + +/* + * Guess RT_OPSYS based on compiler predefined macros. + */ +#ifndef RT_OPSYS +# if defined(__APPLE__) +# define RT_OPSYS RT_OPSYS_DARWIN +# elif defined(__DragonFly__) +# define RT_OPSYS RT_OPSYS_DRAGONFLY +# elif defined(__FreeBSD__) /*??*/ +# define RT_OPSYS RT_OPSYS_FREEBSD +# elif defined(__gnu_linux__) +# define RT_OPSYS RT_OPSYS_LINUX +# elif defined(__NetBSD__) /*??*/ +# define RT_OPSYS RT_OPSYS_NETBSD +# elif defined(__OpenBSD__) /*??*/ +# define RT_OPSYS RT_OPSYS_OPENBSD +# elif defined(__OS2__) +# define RT_OPSYS RT_OPSYS_OS2 +# elif defined(__sun__) || defined(__SunOS__) || defined(__sun) || defined(__SunOS) +# define RT_OPSYS RT_OPSYS_SOLARIS +# elif defined(_WIN32) || defined(_WIN64) +# define RT_OPSYS RT_OPSYS_WINDOWS +# elif defined(MSDOS) || defined(_MSDOS) || defined(DOS16RM) /* OW+MSC || MSC || DMC */ +# define RT_OPSYS RT_OPSYS_DOS +# else +# error "Port Me" +# endif +#endif + +#if RT_OPSYS < RT_OPSYS_UNKNOWN || RT_OPSYS >= RT_OPSYS_MAX +# error "Invalid RT_OPSYS value." +#endif + +/* + * Do some consistency checks. + * + * Search: #define RT_OPSYS_([A-Z0-9]+) .* + * Replace: #if defined(RT_OS_\1) && RT_OPSYS != RT_OPSYS_\1\n# error RT_OPSYS vs RT_OS_\1\n#endif + */ +#if defined(RT_OS_UNKNOWN) && RT_OPSYS != RT_OPSYS_UNKNOWN +# error RT_OPSYS vs RT_OS_UNKNOWN +#endif +#if defined(RT_OS_AGNOSTIC) && RT_OPSYS != RT_OPSYS_AGNOSTIC +# error RT_OPSYS vs RT_OS_AGNOSTIC +#endif +#if defined(RT_OS_DARWIN) && RT_OPSYS != RT_OPSYS_DARWIN +# error RT_OPSYS vs RT_OS_DARWIN +#endif +#if defined(RT_OS_DRAGONFLY) && RT_OPSYS != RT_OPSYS_DRAGONFLY +# error RT_OPSYS vs RT_OS_DRAGONFLY +#endif +#if defined(RT_OS_DOS) && RT_OPSYS != RT_OPSYS_DOS +# error RT_OPSYS vs RT_OS_DOS +#endif +#if defined(RT_OS_FREEBSD) && RT_OPSYS != RT_OPSYS_FREEBSD +# error RT_OPSYS vs RT_OS_FREEBSD +#endif +#if defined(RT_OS_HAIKU) && RT_OPSYS != RT_OPSYS_HAIKU +# error RT_OPSYS vs RT_OS_HAIKU +#endif +#if defined(RT_OS_LINUX) && RT_OPSYS != RT_OPSYS_LINUX +# error RT_OPSYS vs RT_OS_LINUX +#endif +#if defined(RT_OS_L4) && RT_OPSYS != RT_OPSYS_L4 +# error RT_OPSYS vs RT_OS_L4 +#endif +#if defined(RT_OS_MINIX) && RT_OPSYS != RT_OPSYS_MINIX +# error RT_OPSYS vs RT_OS_MINIX +#endif +#if defined(RT_OS_NETBSD) && RT_OPSYS != RT_OPSYS_NETBSD +# error RT_OPSYS vs RT_OS_NETBSD +#endif +#if defined(RT_OS_NETWARE) && RT_OPSYS != RT_OPSYS_NETWARE +# error RT_OPSYS vs RT_OS_NETWARE +#endif +#if defined(RT_OS_NT) && RT_OPSYS != RT_OPSYS_NT +# error RT_OPSYS vs RT_OS_NT +#endif +#if defined(RT_OS_OPENBSD) && RT_OPSYS != RT_OPSYS_OPENBSD +# error RT_OPSYS vs RT_OS_OPENBSD +#endif +#if defined(RT_OS_OS2) && RT_OPSYS != RT_OPSYS_OS2 +# error RT_OPSYS vs RT_OS_OS2 +#endif +#if defined(RT_OS_PLAN9) && RT_OPSYS != RT_OPSYS_PLAN9 +# error RT_OPSYS vs RT_OS_PLAN9 +#endif +#if defined(RT_OS_QNX) && RT_OPSYS != RT_OPSYS_QNX +# error RT_OPSYS vs RT_OS_QNX +#endif +#if defined(RT_OS_SOLARIS) && RT_OPSYS != RT_OPSYS_SOLARIS +# error RT_OPSYS vs RT_OS_SOLARIS +#endif +#if defined(RT_OS_UEFI) && RT_OPSYS != RT_OPSYS_UEFI +# error RT_OPSYS vs RT_OS_UEFI +#endif +#if defined(RT_OS_WINDOWS) && RT_OPSYS != RT_OPSYS_WINDOWS +# error RT_OPSYS vs RT_OS_WINDOWS +#endif + +/* + * Make sure the RT_OS_XXX macro is defined. + * + * Search: #define RT_OPSYS_([A-Z0-9]+) .* + * Replace: #elif RT_OPSYS == RT_OPSYS_\1\n# ifndef RT_OS_\1\n# define RT_OS_\1\n# endif + */ +#if RT_OPSYS == RT_OPSYS_UNKNOWN +# ifndef RT_OS_UNKNOWN +# define RT_OS_UNKNOWN +# endif +#elif RT_OPSYS == RT_OPSYS_AGNOSTIC +# ifndef RT_OS_AGNOSTIC +# define RT_OS_AGNOSTIC +# endif +#elif RT_OPSYS == RT_OPSYS_DARWIN +# ifndef RT_OS_DARWIN +# define RT_OS_DARWIN +# endif +#elif RT_OPSYS == RT_OPSYS_DRAGONFLY +# ifndef RT_OS_DRAGONFLY +# define RT_OS_DRAGONFLY +# endif +#elif RT_OPSYS == RT_OPSYS_DOS +# ifndef RT_OS_DOS +# define RT_OS_DOS +# endif +#elif RT_OPSYS == RT_OPSYS_FREEBSD +# ifndef RT_OS_FREEBSD +# define RT_OS_FREEBSD +# endif +#elif RT_OPSYS == RT_OPSYS_HAIKU +# ifndef RT_OS_HAIKU +# define RT_OS_HAIKU +# endif +#elif RT_OPSYS == RT_OPSYS_LINUX +# ifndef RT_OS_LINUX +# define RT_OS_LINUX +# endif +#elif RT_OPSYS == RT_OPSYS_L4 +# ifndef RT_OS_L4 +# define RT_OS_L4 +# endif +#elif RT_OPSYS == RT_OPSYS_MINIX +# ifndef RT_OS_MINIX +# define RT_OS_MINIX +# endif +#elif RT_OPSYS == RT_OPSYS_NETBSD +# ifndef RT_OS_NETBSD +# define RT_OS_NETBSD +# endif +#elif RT_OPSYS == RT_OPSYS_NETWARE +# ifndef RT_OS_NETWARE +# define RT_OS_NETWARE +# endif +#elif RT_OPSYS == RT_OPSYS_NT +# ifndef RT_OS_NT +# define RT_OS_NT +# endif +#elif RT_OPSYS == RT_OPSYS_OPENBSD +# ifndef RT_OS_OPENBSD +# define RT_OS_OPENBSD +# endif +#elif RT_OPSYS == RT_OPSYS_OS2 +# ifndef RT_OS_OS2 +# define RT_OS_OS2 +# endif +#elif RT_OPSYS == RT_OPSYS_PLAN9 +# ifndef RT_OS_PLAN9 +# define RT_OS_PLAN9 +# endif +#elif RT_OPSYS == RT_OPSYS_QNX +# ifndef RT_OS_QNX +# define RT_OS_QNX +# endif +#elif RT_OPSYS == RT_OPSYS_SOLARIS +# ifndef RT_OS_SOLARIS +# define RT_OS_SOLARIS +# endif +#elif RT_OPSYS == RT_OPSYS_UEFI +# ifndef RT_OS_UEFI +# define RT_OS_UEFI +# endif +#elif RT_OPSYS == RT_OPSYS_WINDOWS +# ifndef RT_OS_WINDOWS +# define RT_OS_WINDOWS +# endif +#else +# error "Bad RT_OPSYS value." +#endif + + +/** + * Checks whether the given OpSys uses DOS-style paths or not. + * + * By DOS-style paths we include drive lettering and UNC paths. + * + * @returns true / false + * @param a_OpSys The RT_OPSYS_XXX value to check, will be reference + * multiple times. + */ +#define RT_OPSYS_USES_DOS_PATHS(a_OpSys) \ + ( (a_OpSys) == RT_OPSYS_WINDOWS \ + || (a_OpSys) == RT_OPSYS_OS2 \ + || (a_OpSys) == RT_OPSYS_DOS ) + + + +/** @def CTXTYPE + * Declare a type differently in GC, R3 and R0. + * + * @param a_GCType The GC type. + * @param a_R3Type The R3 type. + * @param a_R0Type The R0 type. + * @remark For pointers used only in one context use RCPTRTYPE(), R3R0PTRTYPE(), R3PTRTYPE() or R0PTRTYPE(). + */ +#if defined(IN_RC) && !defined(DOXYGEN_RUNNING) +# define CTXTYPE(a_GCType, a_R3Type, a_R0Type) a_GCType +#elif defined(IN_RING3) || defined(DOXYGEN_RUNNING) +# define CTXTYPE(a_GCType, a_R3Type, a_R0Type) a_R3Type +#else +# define CTXTYPE(a_GCType, a_R3Type, a_R0Type) a_R0Type +#endif + +/** @def CTX_EXPR + * Expression selector for avoiding \#ifdef's. + * + * @param a_R3Expr The R3 expression. + * @param a_R0Expr The R0 expression. + * @param a_RCExpr The RC expression. + */ +#if defined(IN_RC) && !defined(DOXYGEN_RUNNING) +# define CTX_EXPR(a_R3Expr, a_R0Expr, a_RCExpr) a_RCExpr +#elif defined(IN_RING0) && !defined(DOXYGEN_RUNNING) +# define CTX_EXPR(a_R3Expr, a_R0Expr, a_RCExpr) a_R0Expr +#else +# define CTX_EXPR(a_R3Expr, a_R0Expr, a_RCExpr) a_R3Expr +#endif + +/** @def RCPTRTYPE + * Declare a pointer which is used in the raw mode context but appears in structure(s) used by + * both HC and RC. The main purpose is to make sure structures have the same + * size when built for different architectures. + * + * @param a_RCType The RC type. + */ +#define RCPTRTYPE(a_RCType) CTXTYPE(a_RCType, RTRCPTR, RTRCPTR) + +/** @def RGPTRTYPE + * This will become RCPTRTYPE once we've converted all uses of RCPTRTYPE to this. + * + * @param a_RCType The RC type. + */ +#define RGPTRTYPE(a_RCType) CTXTYPE(a_RCType, RTGCPTR, RTGCPTR) + +/** @def R3R0PTRTYPE + * Declare a pointer which is used in HC, is explicitly valid in ring 3 and 0, + * but appears in structure(s) used by both HC and GC. The main purpose is to + * make sure structures have the same size when built for different architectures. + * + * @param a_R3R0Type The R3R0 type. + * @remarks This used to be called HCPTRTYPE. + */ +#define R3R0PTRTYPE(a_R3R0Type) CTXTYPE(RTHCPTR, a_R3R0Type, a_R3R0Type) + +/** @def R3PTRTYPE + * Declare a pointer which is used in R3 but appears in structure(s) used by + * both HC and GC. The main purpose is to make sure structures have the same + * size when built for different architectures. + * + * @param a_R3Type The R3 type. + */ +#define R3PTRTYPE(a_R3Type) CTXTYPE(RTHCUINTPTR, a_R3Type, RTHCUINTPTR) + +/** @def R0PTRTYPE + * Declare a pointer which is used in R0 but appears in structure(s) used by + * both HC and GC. The main purpose is to make sure structures have the same + * size when built for different architectures. + * + * @param a_R0Type The R0 type. + */ +#define R0PTRTYPE(a_R0Type) CTXTYPE(RTHCUINTPTR, RTHCUINTPTR, a_R0Type) + +/** @def CTXSUFF + * Adds the suffix of the current context to the passed in + * identifier name. The suffix is HC or GC. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_Var Identifier name. + * @deprecated Use CTX_SUFF. Do NOT use this for new code. + */ +/** @def OTHERCTXSUFF + * Adds the suffix of the other context to the passed in + * identifier name. The suffix is HC or GC. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_Var Identifier name. + * @deprecated Use CTX_SUFF. Do NOT use this for new code. + */ +#if defined(IN_RC) && !defined(DOXYGEN_RUNNING) +# define CTXSUFF(a_Var) a_Var##GC +# define OTHERCTXSUFF(a_Var) a_Var##HC +#else +# define CTXSUFF(a_Var) a_Var##HC +# define OTHERCTXSUFF(a_Var) a_Var##GC +#endif + +/** @def CTXALLSUFF + * Adds the suffix of the current context to the passed in + * identifier name. The suffix is R3, R0 or GC. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_Var Identifier name. + * @deprecated Use CTX_SUFF. Do NOT use this for new code. + */ +#if defined(IN_RC) && !defined(DOXYGEN_RUNNING) +# define CTXALLSUFF(a_Var) a_Var##GC +#elif defined(IN_RING0) && !defined(DOXYGEN_RUNNING) +# define CTXALLSUFF(a_Var) a_Var##R0 +#else +# define CTXALLSUFF(a_Var) a_Var##R3 +#endif + +/** @def CTX_SUFF + * Adds the suffix of the current context to the passed in + * identifier name. The suffix is R3, R0 or RC. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_Var Identifier name. + * + * @remark This will replace CTXALLSUFF and CTXSUFF before long. + */ +#if defined(IN_RC) && !defined(DOXYGEN_RUNNING) +# define CTX_SUFF(a_Var) a_Var##RC +#elif defined(IN_RING0) && !defined(DOXYGEN_RUNNING) +# define CTX_SUFF(a_Var) a_Var##R0 +#else +# define CTX_SUFF(a_Var) a_Var##R3 +#endif + +/** @def CTX_SUFF_Z + * Adds the suffix of the current context to the passed in + * identifier name, combining RC and R0 into RZ. + * The suffix thus is R3 or RZ. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_Var Identifier name. + * + * @remark This will replace CTXALLSUFF and CTXSUFF before long. + */ +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +# define CTX_SUFF_Z(a_Var) a_Var##R3 +#else +# define CTX_SUFF_Z(a_Var) a_Var##RZ +#endif + + +/** @def CTXMID + * Adds the current context as a middle name of an identifier name + * The middle name is HC or GC. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_First First name. + * @param a_Last Surname. + */ +/** @def OTHERCTXMID + * Adds the other context as a middle name of an identifier name + * The middle name is HC or GC. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_First First name. + * @param a_Last Surname. + * @deprecated use CTX_MID or CTX_MID_Z + */ +#if defined(IN_RC) && !defined(DOXYGEN_RUNNING) +# define CTXMID(a_First, a_Last) a_First##GC##a_Last +# define OTHERCTXMID(a_First, a_Last) a_First##HC##a_Last +#else +# define CTXMID(a_First, a_Last) a_First##HC##a_Last +# define OTHERCTXMID(a_First, a_Last) a_First##GC##a_Last +#endif + +/** @def CTXALLMID + * Adds the current context as a middle name of an identifier name. + * The middle name is R3, R0 or GC. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_First First name. + * @param a_Last Surname. + * @deprecated use CTX_MID or CTX_MID_Z + */ +#if defined(IN_RC) && !defined(DOXYGEN_RUNNING) +# define CTXALLMID(a_First, a_Last) a_First##GC##a_Last +#elif defined(IN_RING0) && !defined(DOXYGEN_RUNNING) +# define CTXALLMID(a_First, a_Last) a_First##R0##a_Last +#else +# define CTXALLMID(a_First, a_Last) a_First##R3##a_Last +#endif + +/** @def CTX_MID + * Adds the current context as a middle name of an identifier name. + * The middle name is R3, R0 or RC. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_First First name. + * @param a_Last Surname. + */ +#if defined(IN_RC) && !defined(DOXYGEN_RUNNING) +# define CTX_MID(a_First, a_Last) a_First##RC##a_Last +#elif defined(IN_RING0) && !defined(DOXYGEN_RUNNING) +# define CTX_MID(a_First, a_Last) a_First##R0##a_Last +#else +# define CTX_MID(a_First, a_Last) a_First##R3##a_Last +#endif + +/** @def CTX_MID_Z + * Adds the current context as a middle name of an identifier name, combining RC + * and R0 into RZ. + * The middle name thus is either R3 or RZ. + * + * This is macro should only be used in shared code to avoid a forest of ifdefs. + * @param a_First First name. + * @param a_Last Surname. + */ +#ifdef IN_RING3 +# define CTX_MID_Z(a_First, a_Last) a_First##R3##a_Last +#else +# define CTX_MID_Z(a_First, a_Last) a_First##RZ##a_Last +#endif + + +/** @def R3STRING + * A macro which in GC and R0 will return a dummy string while in R3 it will return + * the parameter. + * + * This is typically used to wrap description strings in structures shared + * between R3, R0 and/or GC. The intention is to avoid the \#ifdef IN_RING3 mess. + * + * @param a_pR3String The R3 string. Only referenced in R3. + * @see R0STRING and GCSTRING + */ +#ifdef IN_RING3 +# define R3STRING(a_pR3String) (a_pR3String) +#else +# define R3STRING(a_pR3String) ("<R3_STRING>") +#endif + +/** @def R0STRING + * A macro which in GC and R3 will return a dummy string while in R0 it will return + * the parameter. + * + * This is typically used to wrap description strings in structures shared + * between R3, R0 and/or GC. The intention is to avoid the \#ifdef IN_RING0 mess. + * + * @param a_pR0String The R0 string. Only referenced in R0. + * @see R3STRING and GCSTRING + */ +#ifdef IN_RING0 +# define R0STRING(a_pR0String) (a_pR0String) +#else +# define R0STRING(a_pR0String) ("<R0_STRING>") +#endif + +/** @def RCSTRING + * A macro which in R3 and R0 will return a dummy string while in RC it will return + * the parameter. + * + * This is typically used to wrap description strings in structures shared + * between R3, R0 and/or RC. The intention is to avoid the \#ifdef IN_RC mess. + * + * @param a_pRCString The RC string. Only referenced in RC. + * @see R3STRING, R0STRING + */ +#ifdef IN_RC +# define RCSTRING(a_pRCString) (a_pRCString) +#else +# define RCSTRING(a_pRCString) ("<RC_STRING>") +#endif + + +/** @def RT_NOTHING + * A macro that expands to nothing. + * This is primarily intended as a dummy argument for macros to avoid the + * undefined behavior passing empty arguments to an macro (ISO C90 and C++98, + * gcc v4.4 warns about it). + */ +#define RT_NOTHING + +/** @def RT_GCC_EXTENSION + * Macro for shutting up GCC warnings about using language extensions. */ +#ifdef __GNUC__ +# define RT_GCC_EXTENSION __extension__ +#else +# define RT_GCC_EXTENSION +#endif + +/** @def RT_GCC_NO_WARN_DEPRECATED_BEGIN + * Used to start a block of code where GCC and Clang should not warn about + * deprecated declarations. */ +/** @def RT_GCC_NO_WARN_DEPRECATED_END + * Used to end a block of code where GCC and Clang should not warn about + * deprecated declarations. */ +#if RT_CLANG_PREREQ(4, 0) +# define RT_GCC_NO_WARN_DEPRECATED_BEGIN \ + _Pragma("clang diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define RT_GCC_NO_WARN_DEPRECATED_END \ + _Pragma("clang diagnostic pop") + +#elif RT_GNUC_PREREQ(4, 6) +# define RT_GCC_NO_WARN_DEPRECATED_BEGIN \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define RT_GCC_NO_WARN_DEPRECATED_END \ + _Pragma("GCC diagnostic pop") +#else +# define RT_GCC_NO_WARN_DEPRECATED_BEGIN +# define RT_GCC_NO_WARN_DEPRECATED_END +#endif + +/** @def RT_GCC_NO_WARN_CONVERSION_BEGIN + * Used to start a block of code where GCC should not warn about implicit + * conversions that may alter a value. */ +#if RT_GNUC_PREREQ(4, 6) +# define RT_GCC_NO_WARN_CONVERSION_BEGIN \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wconversion\"") +/** @def RT_GCC_NO_WARN_CONVERSION_END + * Used to end a block of code where GCC should not warn about implicit + * conversions that may alter a value. */ +# define RT_GCC_NO_WARN_CONVERSION_END \ + _Pragma("GCC diagnostic pop") +#else +# define RT_GCC_NO_WARN_CONVERSION_BEGIN +# define RT_GCC_NO_WARN_CONVERSION_END +#endif + +/** @def RT_COMPILER_GROKS_64BIT_BITFIELDS + * Macro that is defined if the compiler understands 64-bit bitfields. */ +#if !defined(RT_OS_OS2) || (!defined(__IBMC__) && !defined(__IBMCPP__)) +# if !defined(__WATCOMC__) /* watcom compiler doesn't grok it either. */ +# define RT_COMPILER_GROKS_64BIT_BITFIELDS +# endif +#endif + +/** @def RT_COMPILER_LONG_DOUBLE_BITS + * Number of relevant bits in the long double type: 64, 80 or 128 */ +/** @def RT_COMPILER_WITH_64BIT_LONG_DOUBLE + * Macro that is defined if the compiler implements long double as the + * IEEE precision floating. */ +/** @def RT_COMPILER_WITH_80BIT_LONG_DOUBLE + * Macro that is defined if the compiler implements long double as the + * IEEE extended precision floating. */ +/** @def RT_COMPILER_WITH_128BIT_LONG_DOUBLE +* Macro that is defined if the compiler implements long double as the +* IEEE quadruple precision floating (128-bit). +* @note Currently not able to detect this, so must be explicitly defined. */ +#if defined(__LDBL_MANT_DIG__) /* GCC & clang have this defined and should be more reliable. */ +# if __LDBL_MANT_DIG__ == 53 +# define RT_COMPILER_LONG_DOUBLE_BITS 64 +# define RT_COMPILER_WITH_64BIT_LONG_DOUBLE +# undef RT_COMPILER_WITH_80BIT_LONG_DOUBLE +# undef RT_COMPILER_WITH_128BIT_LONG_DOUBLE +# elif __LDBL_MANT_DIG__ == 64 +# define RT_COMPILER_LONG_DOUBLE_BITS 80 +# undef RT_COMPILER_WITH_64BIT_LONG_DOUBLE +# define RT_COMPILER_WITH_80BIT_LONG_DOUBLE +# undef RT_COMPILER_WITH_128BIT_LONG_DOUBLE +# elif __LDBL_MANT_DIG__ == 113 +# define RT_COMPILER_LONG_DOUBLE_BITS 128 +# undef RT_COMPILER_WITH_64BIT_LONG_DOUBLE +# undef RT_COMPILER_WITH_80BIT_LONG_DOUBLE +# define RT_COMPILER_WITH_128BIT_LONG_DOUBLE +# else +# error "Port me!" +# endif +#elif defined(RT_OS_WINDOWS) || defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) /* the M1 arm64 at least */ +# define RT_COMPILER_LONG_DOUBLE_BITS 64 +# define RT_COMPILER_WITH_64BIT_LONG_DOUBLE +# undef RT_COMPILER_WITH_80BIT_LONG_DOUBLE +# undef RT_COMPILER_WITH_128BIT_LONG_DOUBLE +#elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# define RT_COMPILER_LONG_DOUBLE_BITS 80 +# undef RT_COMPILER_WITH_64BIT_LONG_DOUBLE +# define RT_COMPILER_WITH_80BIT_LONG_DOUBLE +# undef RT_COMPILER_WITH_128BIT_LONG_DOUBLE +#elif defined(RT_ARCH_SPARC) || defined(RT_ARCH_SPARC64) +# define RT_COMPILER_LONG_DOUBLE_BITS 128 +# undef RT_COMPILER_WITH_64BIT_LONG_DOUBLE +# undef RT_COMPILER_WITH_80BIT_LONG_DOUBLE +# define RT_COMPILER_WITH_128BIT_LONG_DOUBLE +#else +# error "Port me!" +#endif + +/** @def RT_COMPILER_WITH_128BIT_INT_TYPES + * Defined when uint128_t and int128_t are native integer types. If + * undefined, they are structure with Hi & Lo members. */ +#if defined(__SIZEOF_INT128__) || (defined(__GNUC__) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_ARM64))) +# define RT_COMPILER_WITH_128BIT_INT_TYPES +#endif + +/** @def RT_EXCEPTIONS_ENABLED + * Defined when C++ exceptions are enabled. + */ +#if !defined(RT_EXCEPTIONS_ENABLED) \ + && defined(__cplusplus) \ + && ( (defined(_MSC_VER) && defined(_CPPUNWIND)) \ + || (defined(__GNUC__) && defined(__EXCEPTIONS))) +# define RT_EXCEPTIONS_ENABLED +#endif + +/** @def DECL_NOTHROW + * How to declare a function which does not throw C++ exceptions. + * + * @param a_Type The return type. + * + * @note This macro can be combined with other macros, for example + * @code + * RTR3DECL(DECL_NOTHROW(void)) foo(void); + * @endcode + * + * @note GCC is currently restricted to 4.2+ given the ominous comments on + * RT_NOTHROW_PROTO. + */ +#ifdef __cplusplus +# if RT_MSC_PREREQ(RT_MSC_VER_VS2015) /*?*/ +# define DECL_NOTHROW(a_Type) __declspec(nothrow) a_Type +# elif RT_CLANG_PREREQ(6,0) || RT_GNUC_PREREQ(4,2) +# define DECL_NOTHROW(a_Type) __attribute__((__nothrow__)) a_Type +# else +# define DECL_NOTHROW(a_Type) a_Type +# endif +#else +# define DECL_NOTHROW(a_Type) a_Type +#endif + +/** @def RT_NOTHROW_PROTO + * Function does not throw any C++ exceptions, prototype edition. + * + * How to express that a function doesn't throw C++ exceptions and the compiler + * can thus save itself the bother of trying to catch any of them and generate + * unwind info. Put this between the closing parenthesis and the semicolon in + * function prototypes (and implementation if C++). + * + * @note This translates to 'noexcept' when compiling in newer C++ mode. + * + * @remarks The use of the nothrow attribute with GCC is because old compilers + * (4.1.1, 32-bit) leaking the nothrow into global space or something + * when used with RTDECL or similar. Using this forces us to have two + * macros, as the nothrow attribute is not for the function definition. + */ +/** @def RT_NOTHROW_DEF + * Function does not throw any C++ exceptions, definition edition. + * + * The counter part to RT_NOTHROW_PROTO that is added to the function + * definition. + */ +#ifdef RT_EXCEPTIONS_ENABLED +# if RT_MSC_PREREQ_EX(RT_MSC_VER_VS2015, 0) \ + || RT_CLANG_HAS_FEATURE(cxx_noexcept) \ + || (RT_GNUC_PREREQ(7, 0) && __cplusplus >= 201100) +# define RT_NOTHROW_PROTO noexcept +# define RT_NOTHROW_DEF noexcept +# elif defined(__GNUC__) +# if RT_GNUC_PREREQ(3, 3) +# define RT_NOTHROW_PROTO __attribute__((__nothrow__)) +# else +# define RT_NOTHROW_PROTO +# endif +# define RT_NOTHROW_DEF /* Would need a DECL_NO_THROW like __declspec(nothrow), which we wont do at this point. */ +# else +# define RT_NOTHROW_PROTO throw() +# define RT_NOTHROW_DEF throw() +# endif +#else +# define RT_NOTHROW_PROTO +# define RT_NOTHROW_DEF +#endif +/** @def RT_NOTHROW_PROTO + * @deprecated Use RT_NOTHROW_PROTO. */ +#define RT_NO_THROW_PROTO RT_NOTHROW_PROTO +/** @def RT_NOTHROW_DEF + * @deprecated Use RT_NOTHROW_DEF. */ +#define RT_NO_THROW_DEF RT_NOTHROW_DEF + +/** @def RT_THROW + * How to express that a method or function throws a type of exceptions. Some + * compilers does not want this kind of information and will warning about it. + * + * @param a_Type The type exception. + * + * @remarks If the actual throwing is done from the header, enclose it by + * \#ifdef RT_EXCEPTIONS_ENABLED ... \#else ... \#endif so the header + * compiles cleanly without exceptions enabled. + * + * Do NOT use this for the actual throwing of exceptions! + */ +#ifdef RT_EXCEPTIONS_ENABLED +# if (__cplusplus + 0) >= 201700 +# define RT_THROW(a_Type) noexcept(false) +# elif RT_MSC_PREREQ_EX(RT_MSC_VER_VC71, 0) +# define RT_THROW(a_Type) +# elif RT_GNUC_PREREQ(7, 0) +# define RT_THROW(a_Type) +# else +# define RT_THROW(a_Type) throw(a_Type) +# endif +#else +# define RT_THROW(a_Type) +#endif + + +/** @def RT_OVERRIDE + * Wrapper for the C++11 override keyword. + * + * @remarks Recognized by g++ starting 4.7, however causes pedantic warnings + * when used without officially enabling the C++11 features. + */ +#ifdef __cplusplus +# if RT_MSC_PREREQ_EX(RT_MSC_VER_VS2012, 0) +# define RT_OVERRIDE override +# elif RT_GNUC_PREREQ(4, 7) +# if __cplusplus >= 201100 +# define RT_OVERRIDE override +# else +# define RT_OVERRIDE +# endif +# else +# define RT_OVERRIDE +# endif +#else +# define RT_OVERRIDE +#endif + +/** @def RT_NOEXCEPT + * Wrapper for the C++11 noexcept keyword (only true form). + * @note use RT_NOTHROW instead. + */ +/** @def RT_NOEXCEPT_EX + * Wrapper for the C++11 noexcept keyword with expression. + * @param a_Expr The expression. + */ +#ifdef __cplusplus +# if (RT_MSC_PREREQ_EX(RT_MSC_VER_VS2015, 0) && defined(RT_EXCEPTIONS_ENABLED)) \ + || RT_CLANG_HAS_FEATURE(cxx_noexcept) \ + || (RT_GNUC_PREREQ(7, 0) && __cplusplus >= 201100) +# define RT_NOEXCEPT noexcept +# define RT_NOEXCEPT_EX(a_Expr) noexcept(a_Expr) +# else +# define RT_NOEXCEPT +# define RT_NOEXCEPT_EX(a_Expr) +# endif +#else +# define RT_NOEXCEPT +# define RT_NOEXCEPT_EX(a_Expr) +#endif + +/** @def RT_ALIGNAS_VAR + * Wrapper for the C++ alignas keyword when used on variables. + * + * This must be put before the storage class and type. + * + * @param a_cbAlign The alignment. Must be power of two. + * @note If C++11 is not enabled/detectable, alternatives will be used where + * available. */ +/** @def RT_ALIGNAS_TYPE + * Wrapper for the C++ alignas keyword when used on types. + * + * When using struct, this must follow the struct keyword. + * + * @param a_cbAlign The alignment. Must be power of two. + * @note If C++11 is not enabled/detectable, alternatives will be used where + * available. */ +/** @def RT_ALIGNAS_MEMB + * Wrapper for the C++ alignas keyword when used on structure members. + * + * This must be put before the variable type. + * + * @param a_cbAlign The alignment. Must be power of two. + * @note If C++11 is not enabled/detectable, alternatives will be used where + * available. */ +#ifdef __cplusplus +# if __cplusplus >= 201100 || defined(DOXYGEN_RUNNING) +# define RT_ALIGNAS_VAR(a_cbAlign) alignas(a_cbAlign) +# define RT_ALIGNAS_TYPE(a_cbAlign) alignas(a_cbAlign) +# define RT_ALIGNAS_MEMB(a_cbAlign) alignas(a_cbAlign) +# endif +#endif +#ifndef RT_ALIGNAS_VAR +# ifdef _MSC_VER +# define RT_ALIGNAS_VAR(a_cbAlign) __declspec(align(a_cbAlign)) +# define RT_ALIGNAS_TYPE(a_cbAlign) __declspec(align(a_cbAlign)) +# define RT_ALIGNAS_MEMB(a_cbAlign) __declspec(align(a_cbAlign)) +# elif defined(__GNUC__) +# define RT_ALIGNAS_VAR(a_cbAlign) __attribute__((__aligned__(a_cbAlign))) +# define RT_ALIGNAS_TYPE(a_cbAlign) __attribute__((__aligned__(a_cbAlign))) +# define RT_ALIGNAS_MEMB(a_cbAlign) __attribute__((__aligned__(a_cbAlign))) +# else +# define RT_ALIGNAS_VAR(a_cbAlign) +# define RT_ALIGNAS_TYPE(a_cbAlign) +# define RT_ALIGNAS_MEMB(a_cbAlign) +# endif +#endif + +/** @def RT_CACHELINE_SIZE + * The typical cache line size for the target architecture. + * @see RT_ALIGNAS_VAR, RT_ALIGNAS_TYPE, RT_ALIGNAS_MEMB + */ +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) \ + || defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) \ + || defined(RT_ARCH_SPARC32) || defined(RT_ARCH_SPARC64) \ + || defined(DOXYGEN_RUNNING) +# define RT_CACHELINE_SIZE 64 +#else +# define RT_CACHELINE_SIZE 128 /* better overdo it */ +#endif + +/** @def RT_FALL_THROUGH + * Tell the compiler that we're falling through to the next case in a switch. + * @sa RT_FALL_THRU */ +#if RT_CLANG_PREREQ(4, 0) && RT_CPLUSPLUS_PREREQ(201100) +# define RT_FALL_THROUGH() [[clang::fallthrough]] +#elif RT_CLANG_PREREQ(12, 0) || RT_GNUC_PREREQ(7, 0) +# define RT_FALL_THROUGH() __attribute__((__fallthrough__)) +#else +# define RT_FALL_THROUGH() (void)0 +#endif +/** @def RT_FALL_THRU + * Tell the compiler that we're falling thru to the next case in a switch. + * @sa RT_FALL_THROUGH */ +#define RT_FALL_THRU() RT_FALL_THROUGH() + + +/** @def RT_IPRT_FORMAT_ATTR + * Identifies a function taking an IPRT format string. + * @param a_iFmt The index (1-based) of the format string argument. + * @param a_iArgs The index (1-based) of the first format argument, use 0 for + * va_list. + */ +#if defined(__GNUC__) && defined(WITH_IPRT_FORMAT_ATTRIBUTE) +# define RT_IPRT_FORMAT_ATTR(a_iFmt, a_iArgs) __attribute__((__iprt_format__(a_iFmt, a_iArgs))) +#else +# define RT_IPRT_FORMAT_ATTR(a_iFmt, a_iArgs) +#endif + +/** @def RT_IPRT_FORMAT_ATTR_MAYBE_NULL + * Identifies a function taking an IPRT format string, NULL is allowed. + * @param a_iFmt The index (1-based) of the format string argument. + * @param a_iArgs The index (1-based) of the first format argument, use 0 for + * va_list. + */ +#if defined(__GNUC__) && defined(WITH_IPRT_FORMAT_ATTRIBUTE) +# define RT_IPRT_FORMAT_ATTR_MAYBE_NULL(a_iFmt, a_iArgs) __attribute__((__iprt_format_maybe_null__(a_iFmt, a_iArgs))) +#else +# define RT_IPRT_FORMAT_ATTR_MAYBE_NULL(a_iFmt, a_iArgs) +#endif + + +/** @def RT_GCC_SUPPORTS_VISIBILITY_HIDDEN + * Indicates that the "hidden" visibility attribute can be used (GCC) */ +#if defined(__GNUC__) +# if __GNUC__ >= 4 && !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS) +# define RT_GCC_SUPPORTS_VISIBILITY_HIDDEN +# endif +#endif + +/** @def RT_COMPILER_SUPPORTS_VA_ARGS + * If the defined, the compiler supports the variadic macro feature (..., __VA_ARGS__). */ +#if defined(_MSC_VER) +# if _MSC_VER >= 1600 /* Visual C++ v10.0 / 2010 */ +# define RT_COMPILER_SUPPORTS_VA_ARGS +# endif +#elif defined(__GNUC__) +# if __GNUC__ >= 3 /* not entirely sure when this was added */ +# define RT_COMPILER_SUPPORTS_VA_ARGS +# endif +#elif defined(__WATCOMC__) +# define RT_COMPILER_SUPPORTS_VA_ARGS +#endif + +/** @def RT_CB_LOG_CAST + * Helper for logging function pointers to function may throw stuff. + * + * Not needed for function pointer types declared using our DECLCALLBACK + * macros, only external types. */ +#if defined(_MSC_VER) && defined(RT_EXCEPTIONS_ENABLED) +# define RT_CB_LOG_CAST(a_pfnCallback) ((uintptr_t)(a_pfnCallback) + 1 - 1) +#else +# define RT_CB_LOG_CAST(a_pfnCallback) (a_pfnCallback) +#endif + + + +/** @def RTCALL + * The standard calling convention for the Runtime interfaces. + * + * @remarks The regparm(0) in the X86/GNUC variant deals with -mregparm=x use in + * the linux kernel and potentially elsewhere (3rd party). + */ +#if defined(_MSC_VER) || defined(__WATCOMC__) +# define RTCALL __cdecl +#elif defined(RT_OS_OS2) +# define RTCALL __cdecl +#elif defined(__GNUC__) && defined(RT_ARCH_X86) +# define RTCALL __attribute__((__cdecl__,__regparm__(0))) +#else +# define RTCALL +#endif + +/** @def DECLEXPORT + * How to declare an exported function. + * @param a_RetType The return type of the function declaration. + */ +#if defined(_MSC_VER) || defined(RT_OS_OS2) +# define DECLEXPORT(a_RetType) __declspec(dllexport) a_RetType +#elif defined(RT_USE_VISIBILITY_DEFAULT) +# define DECLEXPORT(a_RetType) __attribute__((visibility("default"))) a_RetType +#else +# define DECLEXPORT(a_RetType) a_RetType +#endif + +/** @def DECL_EXPORT_NOTHROW + * How to declare an exported function that does not throw C++ exceptions. + * @param a_RetType The return type of the function declaration. + */ +#define DECL_EXPORT_NOTHROW(a_RetType) DECL_NOTHROW(DECLEXPORT(a_RetType)) + +/** @def DECLIMPORT + * How to declare an imported function. + * @param a_RetType The return type of the function declaration. + */ +#if defined(_MSC_VER) || (defined(RT_OS_OS2) && !defined(__IBMC__) && !defined(__IBMCPP__)) +# define DECLIMPORT(a_RetType) __declspec(dllimport) a_RetType +#else +# define DECLIMPORT(a_RetType) a_RetType +#endif + +/** @def DECL_IMPORT_NOTHROW + * How to declare an imported function that does not throw C++ exceptions. + * @param a_RetType The return type of the function declaration. + */ +#define DECL_IMPORT_NOTHROW(a_RetType) DECL_NOTHROW(DECLIMPORT(a_RetType)) + +/** @def DECL_HIDDEN_ONLY + * How to declare a non-exported function or variable. + * @param a_Type The return type of the function or the data type of the variable. + * @sa DECL_HIDDEN, DECL_HIDDEN_DATA, DECL_HIDDEN_CONST + * @internal Considered more or less internal. + */ +#if !defined(RT_GCC_SUPPORTS_VISIBILITY_HIDDEN) || defined(RT_NO_VISIBILITY_HIDDEN) +# define DECL_HIDDEN_ONLY(a_Type) a_Type +#else +# define DECL_HIDDEN_ONLY(a_Type) __attribute__((visibility("hidden"))) a_Type +#endif + +/** @def DECLHIDDEN + * How to declare a non-exported function or variable. + * @param a_Type The return type of the function or the data type of the variable. + * @sa DECL_HIDDEN_THROW, DECL_HIDDEN_DATA, DECL_HIDDEN_CONST + * @todo split up into data and non-data. + */ +#define DECLHIDDEN(a_Type) DECL_NOTHROW(DECL_HIDDEN_ONLY(a_Type)) + +/** @def DECL_HIDDEN_NOTHROW + * How to declare a non-exported function that does not throw C++ exceptions. + * @param a_RetType The return type of the function. + * @note Same as DECLHIDDEN but provided to go along with DECL_IMPORT_NOTHROW + * and DECL_EXPORT_NOTHROW. + */ +#define DECL_HIDDEN_NOTHROW(a_RetType) DECL_NOTHROW(DECL_HIDDEN_ONLY(a_RetType)) + +/** @def DECL_HIDDEN_THROW + * How to declare a non-exported function that may throw C++ exceptions. + * @param a_RetType The return type of the function. + */ +#define DECL_HIDDEN_THROW(a_RetType) DECL_HIDDEN_ONLY(a_Type) + +/** @def DECL_HIDDEN_DATA + * How to declare a non-exported variable. + * @param a_Type The data type of the variable. + * @sa DECL_HIDDEN_CONST + */ +#if !defined(RT_GCC_SUPPORTS_VISIBILITY_HIDDEN) || defined(RT_NO_VISIBILITY_HIDDEN) +# define DECL_HIDDEN_DATA(a_Type) a_Type +#else +# define DECL_HIDDEN_DATA(a_Type) __attribute__((visibility("hidden"))) a_Type +#endif + +/** @def DECL_HIDDEN_CONST + * Workaround for g++ warnings when applying the hidden attribute to a const + * definition. Use DECL_HIDDEN_DATA for the declaration. + * @param a_Type The data type of the variable. + * @sa DECL_HIDDEN_DATA + */ +#if defined(__cplusplus) && defined(__GNUC__) +# define DECL_HIDDEN_CONST(a_Type) a_Type +#else +# define DECL_HIDDEN_CONST(a_Type) DECL_HIDDEN_DATA(a_Type) +#endif + +/** @def DECL_INVALID + * How to declare a function not available for linking in the current context. + * The purpose is to create compile or like time errors when used. This isn't + * possible on all platforms. + * @param a_RetType The return type of the function. + */ +#if defined(_MSC_VER) +# define DECL_INVALID(a_RetType) __declspec(dllimport) a_RetType __stdcall +#elif defined(__GNUC__) && defined(__cplusplus) +# define DECL_INVALID(a_RetType) extern "C++" a_RetType +#else +# define DECL_INVALID(a_RetType) a_RetType +#endif + +/** @def DECLASM + * How to declare an internal assembly function. + * @param a_RetType The return type of the function declaration. + * @note DECL_NOTHROW is implied. + */ +#ifdef __cplusplus +# define DECLASM(a_RetType) extern "C" DECL_NOTHROW(a_RetType RTCALL) +#else +# define DECLASM(a_RetType) DECL_NOTHROW(a_RetType RTCALL) +#endif + +/** @def RT_ASM_DECL_PRAGMA_WATCOM + * How to declare a assembly method prototype with watcom \#pragma aux definition. */ +/** @def RT_ASM_DECL_PRAGMA_WATCOM_386 + * Same as RT_ASM_DECL_PRAGMA_WATCOM, but there is no 16-bit version when + * 8086, 80186 or 80286 is selected as the target CPU. */ +#if defined(__WATCOMC__) && ARCH_BITS == 16 && defined(RT_ARCH_X86) +# define RT_ASM_DECL_PRAGMA_WATCOM(a_RetType) a_RetType +# if defined(__SW_0) || defined(__SW_1) || defined(__SW_2) +# define RT_ASM_DECL_PRAGMA_WATCOM_386(a_RetType) DECLASM(a_RetType) +# else +# define RT_ASM_DECL_PRAGMA_WATCOM_386(a_RetType) a_RetType +# endif +#elif defined(__WATCOMC__) && ARCH_BITS == 32 && defined(RT_ARCH_X86) +# define RT_ASM_DECL_PRAGMA_WATCOM(a_RetType) a_RetType +# define RT_ASM_DECL_PRAGMA_WATCOM_386(a_RetType) a_RetType +#else +# define RT_ASM_DECL_PRAGMA_WATCOM(a_RetType) DECLASM(a_RetType) +# define RT_ASM_DECL_PRAGMA_WATCOM_386(a_RetType) DECLASM(a_RetType) +#endif + +/** @def DECL_NO_RETURN + * How to declare a function which does not return. + * @note This macro can be combined with other macros, for example + * @code + * RTR3DECL(DECL_NO_RETURN(void)) foo(void); + * @endcode + */ +#ifdef _MSC_VER +# define DECL_NO_RETURN(a_RetType) __declspec(noreturn) a_RetType +#elif defined(__GNUC__) +# define DECL_NO_RETURN(a_RetType) __attribute__((noreturn)) a_RetType +#else +# define DECL_NO_RETURN(a_RetType) a_RetType +#endif + +/** @def DECL_RETURNS_TWICE + * How to declare a function which may return more than once. + * @note This macro can be combined with other macros, for example + * @code + * RTR3DECL(DECL_RETURNS_TWICE(void)) MySetJmp(void); + * @endcode + */ +#if RT_GNUC_PREREQ(4, 1) +# define DECL_RETURNS_TWICE(a_RetType) __attribute__((returns_twice)) a_RetType +#else +# define DECL_RETURNS_TWICE(a_RetType) a_RetType +#endif + +/** @def DECL_CHECK_RETURN + * Require a return value to be checked. + * @note This macro can be combined with other macros, for example + * @code + * RTR3DECL(DECL_CHECK_RETURN(int)) MayReturnInfoStatus(void); + * @endcode + */ +#if RT_GNUC_PREREQ(3, 4) +# define DECL_CHECK_RETURN(a_RetType) __attribute__((warn_unused_result)) a_RetType +#elif defined(_MSC_VER) +# define DECL_CHECK_RETURN(a_RetType) __declspec("SAL_checkReturn") a_RetType +#else +# define DECL_CHECK_RETURN(a_RetType) a_RetType +#endif + +/** @def DECL_CHECK_RETURN_NOT_R3 + * Variation of DECL_CHECK_RETURN that only applies the required to non-ring-3 + * code. + */ +#ifndef IN_RING3 +# define DECL_CHECK_RETURN_NOT_R3(a_RetType) DECL_CHECK_RETURN(a_RetType) +#else +# define DECL_CHECK_RETURN_NOT_R3(a_RetType) a_RetType +#endif + +/** @def DECLWEAK + * How to declare a variable which is not necessarily resolved at + * runtime. + * @note This macro can be combined with other macros, for example + * @code + * RTR3DECL(DECLWEAK(int)) foo; + * @endcode + */ +#if defined(__GNUC__) +# define DECLWEAK(a_Type) a_Type __attribute__((weak)) +#else +# define DECLWEAK(a_Type) a_Type +#endif + +/** @def DECLCALLBACK + * How to declare an call back function. + * @param a_RetType The return type of the function declaration. + * @note DECL_NOTHROW is implied. + * @note Use DECLCALLBACKTYPE for typedefs. + */ +#define DECLCALLBACK(a_RetType) DECL_NOTHROW(a_RetType RT_FAR_CODE RTCALL) + +/** @def DECL_HIDDEN_CALLBACK + * How to declare an call back function with hidden visibility. + * @param a_RetType The return type of the function declaration. + * @note DECL_NOTHROW is implied. + * @note Use DECLCALLBACKTYPE for typedefs. + */ +#define DECL_HIDDEN_CALLBACK(a_RetType) DECL_HIDDEN_ONLY(DECLCALLBACK(a_RetType)) + +/** @def DECLCALLBACKTYPE_EX + * How to declare an call back function type. + * @param a_RetType The return type of the function declaration. + * @param a_CallConv Calling convention. + * @param a_Name The name of the typedef + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#if RT_CLANG_PREREQ(6,0) && !defined(RT_RELAXED_CALLBACKS_TYPES) +# define DECLCALLBACKTYPE_EX(a_RetType, a_CallConv, a_Name, a_Args) __attribute__((__nothrow__)) a_RetType a_CallConv a_Name a_Args +#elif RT_MSC_PREREQ(RT_MSC_VER_VS2015) /*?*/ && defined(__cplusplus) && defined(_MSC_EXTENSIONS) && !defined(RT_RELAXED_CALLBACKS_TYPES) +# define DECLCALLBACKTYPE_EX(a_RetType, a_CallConv, a_Name, a_Args) a_RetType a_CallConv a_Name a_Args throw() +#else +# define DECLCALLBACKTYPE_EX(a_RetType, a_CallConv, a_Name, a_Args) a_RetType a_CallConv a_Name a_Args +#endif +/** @def DECLCALLBACKTYPE + * How to declare an call back function type. + * @param a_RetType The return type of the function declaration. + * @param a_Name The name of the typedef + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#define DECLCALLBACKTYPE(a_RetType, a_Name, a_Args) DECLCALLBACKTYPE_EX(a_RetType, RT_FAR_CODE RTCALL, a_Name, a_Args) + +/** @def DECLCALLBACKPTR_EX + * How to declare an call back function pointer. + * @param a_RetType The return type of the function declaration. + * @param a_CallConv Calling convention. + * @param a_Name The name of the variable member. + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#if defined(__IBMC__) || defined(__IBMCPP__) +# define DECLCALLBACKPTR_EX(a_RetType, a_CallConv, a_Name, a_Args) a_RetType (* a_CallConv a_Name) a_Args +#elif RT_CLANG_PREREQ(6,0) && !defined(RT_RELAXED_CALLBACKS_TYPES) +# define DECLCALLBACKPTR_EX(a_RetType, a_CallConv, a_Name, a_Args) __attribute__((__nothrow__)) a_RetType (a_CallConv * a_Name) a_Args +#elif RT_MSC_PREREQ(RT_MSC_VER_VS2015) /*?*/ && defined(__cplusplus) && defined(_MSC_EXTENSIONS) && !defined(RT_RELAXED_CALLBACKS_TYPES) +# define DECLCALLBACKPTR_EX(a_RetType, a_CallConv, a_Name, a_Args) a_RetType (a_CallConv * a_Name) a_Args throw() +#else +# define DECLCALLBACKPTR_EX(a_RetType, a_CallConv, a_Name, a_Args) a_RetType (a_CallConv * a_Name) a_Args +#endif +/** @def DECLCALLBACKPTR + * How to declare an call back function pointer. + * @param a_RetType The return type of the function declaration. + * @param a_Name The name of the variable member. + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#define DECLCALLBACKPTR(a_RetType, a_Name, a_Args) DECLCALLBACKPTR_EX(a_RetType, RT_FAR_CODE RTCALL, a_Name, a_Args) + +/** @def DECLCALLBACKMEMBER_EX + * How to declare an call back function pointer member. + * @param a_RetType The return type of the function declaration. + * @param a_CallConv Calling convention. + * @param a_Name The name of the struct/union/class member. + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#if defined(__IBMC__) || defined(__IBMCPP__) +# define DECLCALLBACKMEMBER_EX(a_RetType, a_CallConv, a_Name, a_Args) a_RetType (* a_CallConv a_Name) a_Args +#elif RT_CLANG_PREREQ(6,0) && !defined(RT_RELAXED_CALLBACKS_TYPES) +# define DECLCALLBACKMEMBER_EX(a_RetType, a_CallConv, a_Name, a_Args) __attribute__((__nothrow__)) a_RetType (a_CallConv *a_Name) a_Args +#elif RT_MSC_PREREQ(RT_MSC_VER_VS2015) /*?*/ && defined(__cplusplus) && defined(_MSC_EXTENSIONS) && !defined(RT_RELAXED_CALLBACKS_TYPES) +# define DECLCALLBACKMEMBER_EX(a_RetType, a_CallConv, a_Name, a_Args) a_RetType (a_CallConv *a_Name) a_Args throw() +#else +# define DECLCALLBACKMEMBER_EX(a_RetType, a_CallConv, a_Name, a_Args) a_RetType (a_CallConv *a_Name) a_Args +#endif +/** @def DECLCALLBACKMEMBER + * How to declare an call back function pointer member. + * @param a_RetType The return type of the function declaration. + * @param a_Name The name of the struct/union/class member. + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#define DECLCALLBACKMEMBER(a_RetType, a_Name, a_Args) DECLCALLBACKMEMBER_EX(a_RetType, RT_FAR_CODE RTCALL, a_Name, a_Args) + +/** @def DECLR3CALLBACKMEMBER + * How to declare an call back function pointer member - R3 Ptr. + * @param a_RetType The return type of the function declaration. + * @param a_Name The name of the struct/union/class member. + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +# define DECLR3CALLBACKMEMBER(a_RetType, a_Name, a_Args) DECLCALLBACKMEMBER(a_RetType, a_Name, a_Args) +#else +# define DECLR3CALLBACKMEMBER(a_RetType, a_Name, a_Args) RTR3PTR a_Name +#endif + +/** @def DECLRCCALLBACKMEMBER + * How to declare an call back function pointer member - RC Ptr. + * @param a_RetType The return type of the function declaration. + * @param a_Name The name of the struct/union/class member. + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#if defined(IN_RC) || defined(DOXYGEN_RUNNING) +# define DECLRCCALLBACKMEMBER(a_RetType, a_Name, a_Args) DECLCALLBACKMEMBER(a_RetType, a_Name, a_Args) +#else +# define DECLRCCALLBACKMEMBER(a_RetType, a_Name, a_Args) RTRCPTR a_Name +#endif +#if defined(IN_RC) || defined(DOXYGEN_RUNNING) +# define DECLRGCALLBACKMEMBER(a_RetType, a_Name, a_Args) DECLCALLBACKMEMBER(a_RetType, a_Name, a_Args) +#else +# define DECLRGCALLBACKMEMBER(a_RetType, a_Name, a_Args) RTRGPTR a_Name +#endif + +/** @def DECLR0CALLBACKMEMBER + * How to declare an call back function pointer member - R0 Ptr. + * @param a_RetType The return type of the function declaration. + * @param a_Name The name of the struct/union/class member. + * @param a_Args The argument list enclosed in parentheses. + * @note DECL_NOTHROW is implied, but not supported by all compilers yet. + */ +#if defined(IN_RING0) || defined(DOXYGEN_RUNNING) +# define DECLR0CALLBACKMEMBER(a_RetType, a_Name, a_Args) DECLCALLBACKMEMBER(a_RetType, a_Name, a_Args) +#else +# define DECLR0CALLBACKMEMBER(a_RetType, a_Name, a_Args) RTR0PTR a_Name +#endif + +/** @def DECLINLINE + * How to declare a function as inline that does not throw any C++ exceptions. + * @param a_RetType The return type of the function declaration. + * @remarks Don't use this macro on C++ methods. + * @sa DECL_INLINE_THROW + */ +#if defined(__GNUC__) && !defined(DOXYGEN_RUNNING) +# define DECLINLINE(a_RetType) DECL_NOTHROW(static __inline__ a_RetType) +#elif defined(__cplusplus) || defined(DOXYGEN_RUNNING) +# define DECLINLINE(a_RetType) DECL_NOTHROW(static inline a_RetType) +#elif defined(_MSC_VER) +# define DECLINLINE(a_RetType) DECL_NOTHROW(static _inline a_RetType) +#elif defined(__IBMC__) +# define DECLINLINE(a_RetType) DECL_NOTHROW(_Inline a_RetType) +#else +# define DECLINLINE(a_RetType) DECL_NOTHROW(inline a_RetType) +#endif + +/** @def DECL_INLINE_THROW + * How to declare a function as inline that throws C++ exceptions. + * @param a_RetType The return type of the function declaration. + * @remarks Don't use this macro on C++ methods. + */ +#if defined(__GNUC__) && !defined(DOXYGEN_RUNNING) +# define DECL_INLINE_THROW(a_RetType) static __inline__ a_RetType +#elif defined(__cplusplus) || defined(DOXYGEN_RUNNING) +# define DECL_INLINE_THROW(a_RetType) static inline a_RetType +#elif defined(_MSC_VER) +# define DECL_INLINE_THROW(a_RetType) static _inline a_RetType +#elif defined(__IBMC__) +# define DECL_INLINE_THROW(a_RetType) _Inline a_RetType +#else +# define DECL_INLINE_THROW(a_RetType) inline a_RetType +#endif + +/** @def DECL_FORCE_INLINE + * How to declare a function that does not throw any C++ exceptions as inline + * and try convince the compiler to always inline it regardless of optimization + * switches. + * @param a_RetType The return type of the function declaration. + * @remarks Use sparsely and with care. Don't use this macro on C++ methods. + * @sa DECL_FORCE_INLINE_THROW + */ +#ifdef __GNUC__ +# define DECL_FORCE_INLINE(a_RetType) __attribute__((__always_inline__)) DECLINLINE(a_RetType) +#elif defined(_MSC_VER) +# define DECL_FORCE_INLINE(a_RetType) DECL_NOTHROW(__forceinline a_RetType) +#else +# define DECL_FORCE_INLINE(a_RetType) DECLINLINE(a_RetType) +#endif + +/** @def DECL_FORCE_INLINE_THROW + * How to declare a function throwing C++ exceptions as inline and try convince + * the compiler to always inline it regardless of optimization switches. + * @param a_RetType The return type of the function declaration. + * @remarks Use sparsely and with care. Don't use this macro on C++ methods. + */ +#ifdef __GNUC__ +# define DECL_FORCE_INLINE_THROW(a_RetType) __attribute__((__always_inline__)) DECL_INLINE_THROW(a_RetType) +#elif defined(_MSC_VER) +# define DECL_FORCE_INLINE_THROW(a_RetType) __forceinline a_RetType +#else +# define DECL_FORCE_INLINE_THROW(a_RetType) DECL_INLINE_THROW(a_RetType) +#endif + + +/** @def DECL_NO_INLINE + * How to declare a function telling the compiler not to inline it. + * @param scope The function scope, static or RT_NOTHING. + * @param a_RetType The return type of the function declaration. + * @remarks Don't use this macro on C++ methods. + */ +#ifdef __GNUC__ +# define DECL_NO_INLINE(scope, a_RetType) __attribute__((__noinline__)) scope a_RetType +#elif defined(_MSC_VER) +# define DECL_NO_INLINE(scope, a_RetType) __declspec(noinline) scope a_RetType +#else +# define DECL_NO_INLINE(scope,a_RetType) scope a_RetType +#endif + + +/** @def IN_RT_STATIC + * Used to indicate whether we're linking against a static IPRT + * or not. + * + * The IPRT symbols will be declared as hidden (if supported). Note that this + * define has no effect without also setting one of the IN_RT_R0, IN_RT_R3 or + * IN_RT_RC indicators. + */ + +/** @def IN_RT_R0 + * Used to indicate whether we're inside the same link module as the host + * context ring-0 Runtime Library. + */ +/** @def RTR0DECL(a_RetType) + * Runtime Library host context ring-0 export or import declaration. + * @param a_RetType The return a_RetType of the function declaration. + * @remarks This is only used inside IPRT. Other APIs need to define their own + * XXXX_DECL macros for dealing with import/export/static visibility. + * @note DECL_NOTHROW is implied. + */ +#ifdef IN_RT_R0 +# ifdef IN_RT_STATIC +# define RTR0DECL(a_RetType) DECL_HIDDEN_NOTHROW(a_RetType) RTCALL +# else +# define RTR0DECL(a_RetType) DECL_EXPORT_NOTHROW(a_RetType) RTCALL +# endif +#else +# define RTR0DECL(a_RetType) DECL_IMPORT_NOTHROW(a_RetType) RTCALL +#endif + +/** @def IN_RT_R3 + * Used to indicate whether we're inside the same link module as the host + * context ring-3 Runtime Library. + */ +/** @def RTR3DECL(a_RetType) + * Runtime Library host context ring-3 export or import declaration. + * @param a_RetType The return type of the function declaration. + * @remarks This is only used inside IPRT. Other APIs need to define their own + * XXXX_DECL macros for dealing with import/export/static visibility. + * @note DECL_NOTHROW is implied. + */ +#ifdef IN_RT_R3 +# ifdef IN_RT_STATIC +# define RTR3DECL(a_RetType) DECL_HIDDEN_NOTHROW(a_RetType) RTCALL +# else +# define RTR3DECL(a_RetType) DECL_EXPORT_NOTHROW(a_RetType) RTCALL +# endif +#else +# define RTR3DECL(a_RetType) DECL_IMPORT_NOTHROW(a_RetType) RTCALL +#endif + +/** @def IN_RT_RC + * Used to indicate whether we're inside the same link module as the raw-mode + * context (RC) runtime library. + */ +/** @def RTRCDECL(a_RetType) + * Runtime Library raw-mode context export or import declaration. + * @param a_RetType The return type of the function declaration. + * @remarks This is only used inside IPRT. Other APIs need to define their own + * XXXX_DECL macros for dealing with import/export/static visibility. + * @note DECL_NOTHROW is implied. + */ +#ifdef IN_RT_RC +# ifdef IN_RT_STATIC +# define RTRCDECL(a_RetType) DECL_HIDDEN_NOTHROW(a_RetType) RTCALL +# else +# define RTRCDECL(a_RetType) DECL_EXPORT_NOTHROW(a_RetType) RTCALL +# endif +#else +# define RTRCDECL(a_RetType) DECL_IMPORT_NOTHROW(a_RetType) RTCALL +#endif + +/** @def RTDECL(a_RetType) + * Runtime Library export or import declaration. + * Functions declared using this macro exists in all contexts. + * @param a_RetType The return type of the function declaration. + * @remarks This is only used inside IPRT. Other APIs need to define their own + * XXXX_DECL macros for dealing with import/export/static visibility. + * @note DECL_NOTHROW is implied. + */ +#if defined(IN_RT_R3) || defined(IN_RT_RC) || defined(IN_RT_R0) +# ifdef IN_RT_STATIC +# define RTDECL(a_RetType) DECL_HIDDEN_NOTHROW(a_RetType) RTCALL +# else +# define RTDECL(a_RetType) DECL_EXPORT_NOTHROW(a_RetType) RTCALL +# endif +#else +# define RTDECL(a_RetType) DECL_IMPORT_NOTHROW(a_RetType) RTCALL +#endif + +/** @def RTDATADECL(a_Type) + * Runtime Library export or import declaration. + * Data declared using this macro exists in all contexts. + * @param a_Type The data type. + * @remarks This is only used inside IPRT. Other APIs need to define their own + * XXXX_DECL macros for dealing with import/export/static visibility. + */ +/** @def RT_DECL_DATA_CONST(a_Type) + * Definition of a const variable. See DECL_HIDDEN_CONST. + * @param a_Type The const data type. + * @remarks This is only used inside IPRT. Other APIs need to define their own + * XXXX_DECL macros for dealing with import/export/static visibility. + */ +#if defined(IN_RT_R3) || defined(IN_RT_RC) || defined(IN_RT_R0) +# ifdef IN_RT_STATIC +# define RTDATADECL(a_Type) DECL_HIDDEN_DATA(a_Type) +# define RT_DECL_DATA_CONST(a_Type) DECL_HIDDEN_CONST(a_Type) +# else +# define RTDATADECL(a_Type) DECLEXPORT(a_Type) +# if defined(__cplusplus) && defined(__GNUC__) +# define RT_DECL_DATA_CONST(a_Type) a_Type +# else +# define RT_DECL_DATA_CONST(a_Type) DECLEXPORT(a_Type) +# endif +# endif +#else +# define RTDATADECL(a_Type) DECLIMPORT(a_Type) +# define RT_DECL_DATA_CONST(a_Type) DECLIMPORT(a_Type) +#endif + +/** @def RT_DECL_CLASS + * Declares an class living in the runtime. + * @remarks This is only used inside IPRT. Other APIs need to define their own + * XXXX_DECL macros for dealing with import/export/static visibility. + */ +#if defined(IN_RT_R3) || defined(IN_RT_RC) || defined(IN_RT_R0) +# ifdef IN_RT_STATIC +# define RT_DECL_CLASS +# else +# define RT_DECL_CLASS DECLEXPORT_CLASS +# endif +#else +# define RT_DECL_CLASS DECLIMPORT_CLASS +#endif + + +/** @def RT_NOCRT + * Symbol name wrapper for the No-CRT bits. + * + * In order to coexist in the same process as other CRTs, we need to + * decorate the symbols such that they don't conflict the ones in the + * other CRTs. The result of such conflicts / duplicate symbols can + * confuse the dynamic loader on Unix like systems. + * + * Define RT_WITHOUT_NOCRT_WRAPPERS to drop the wrapping. + * Define RT_WITHOUT_NOCRT_WRAPPER_ALIASES to drop the aliases to the + * wrapped names. + */ +/** @def RT_NOCRT_STR + * Same as RT_NOCRT only it'll return a double quoted string of the result. + */ +#if !defined(RT_WITHOUT_NOCRT_WRAPPERS) || defined(RT_FORCE_NOCRT_WRAPPERS) +# define RT_NOCRT(name) nocrt_ ## name +# define RT_NOCRT_STR(name) "nocrt_" # name +#else +# define RT_NOCRT(name) name +# define RT_NOCRT_STR(name) #name +#endif + + +/** @name Untrusted data classifications. + * @{ */ +/** @def RT_UNTRUSTED_USER + * For marking non-volatile (race free) data from user mode as untrusted. + * This is just for visible documentation. */ +#define RT_UNTRUSTED_USER +/** @def RT_UNTRUSTED_VOLATILE_USER + * For marking volatile data shared with user mode as untrusted. + * This is more than just documentation as it specifies the 'volatile' keyword, + * because the guest could modify the data at any time. */ +#define RT_UNTRUSTED_VOLATILE_USER volatile + +/** @def RT_UNTRUSTED_GUEST + * For marking non-volatile (race free) data from the guest as untrusted. + * This is just for visible documentation. */ +#define RT_UNTRUSTED_GUEST +/** @def RT_UNTRUSTED_VOLATILE_GUEST + * For marking volatile data shared with the guest as untrusted. + * This is more than just documentation as it specifies the 'volatile' keyword, + * because the guest could modify the data at any time. */ +#define RT_UNTRUSTED_VOLATILE_GUEST volatile + +/** @def RT_UNTRUSTED_HOST + * For marking non-volatile (race free) data from the host as untrusted. + * This is just for visible documentation. */ +#define RT_UNTRUSTED_HOST +/** @def RT_UNTRUSTED_VOLATILE_HOST + * For marking volatile data shared with the host as untrusted. + * This is more than just documentation as it specifies the 'volatile' keyword, + * because the host could modify the data at any time. */ +#define RT_UNTRUSTED_VOLATILE_HOST volatile + +/** @def RT_UNTRUSTED_HSTGST + * For marking non-volatile (race free) data from the host/gust as untrusted. + * This is just for visible documentation. */ +#define RT_UNTRUSTED_HSTGST +/** @def RT_UNTRUSTED_VOLATILE_HSTGST + * For marking volatile data shared with the host/guest as untrusted. + * This is more than just documentation as it specifies the 'volatile' keyword, + * because the host could modify the data at any time. */ +#define RT_UNTRUSTED_VOLATILE_HSTGST volatile +/** @} */ + +/** @name Fences for use when handling untrusted data. + * @{ */ +/** For use after copying untruated volatile data to a non-volatile location. + * This translates to a compiler memory barrier and will help ensure that the + * compiler uses the non-volatile copy of the data. */ +#define RT_UNTRUSTED_NONVOLATILE_COPY_FENCE() ASMCompilerBarrier() +/** For use after finished validating guest input. + * What this translates to is architecture dependent. On intel it will + * translate to a CPU load+store fence as well as a compiler memory barrier. */ +#if defined(RT_ARCH_AMD64) || (defined(RT_ARCH_X86) && !defined(RT_WITH_OLD_CPU_SUPPORT)) +# define RT_UNTRUSTED_VALIDATED_FENCE() do { ASMCompilerBarrier(); ASMReadFence(); } while (0) +#elif defined(RT_ARCH_X86) +# define RT_UNTRUSTED_VALIDATED_FENCE() do { ASMCompilerBarrier(); ASMMemoryFence(); } while (0) +#else +# define RT_UNTRUSTED_VALIDATED_FENCE() do { ASMCompilerBarrier(); } while (0) +#endif +/** @} */ + + +/** @def RT_LIKELY + * Give the compiler a hint that an expression is very likely to hold true. + * + * Some compilers support explicit branch prediction so that the CPU backend + * can hint the processor and also so that code blocks can be reordered such + * that the predicted path sees a more linear flow, thus improving cache + * behaviour, etc. + * + * IPRT provides the macros RT_LIKELY() and RT_UNLIKELY() as a way to utilize + * this compiler feature when present. + * + * A few notes about the usage: + * + * - Generally, order your code use RT_LIKELY() instead of RT_UNLIKELY(). + * + * - Generally, use RT_UNLIKELY() with error condition checks (unless you + * have some _strong_ reason to do otherwise, in which case document it), + * and/or RT_LIKELY() with success condition checks, assuming you want + * to optimize for the success path. + * + * - Other than that, if you don't know the likelihood of a test succeeding + * from empirical or other 'hard' evidence, don't make predictions unless + * you happen to be a Dirk Gently character. + * + * - These macros are meant to be used in places that get executed a lot. It + * is wasteful to make predictions in code that is executed rarely (e.g. + * at subsystem initialization time) as the basic block reordering that this + * affects can often generate larger code. + * + * - Note that RT_SUCCESS() and RT_FAILURE() already makes use of RT_LIKELY() + * and RT_UNLIKELY(). Should you wish for prediction free status checks, + * use the RT_SUCCESS_NP() and RT_FAILURE_NP() macros instead. + * + * + * @returns the boolean result of the expression. + * @param expr The expression that's very likely to be true. + * @see RT_UNLIKELY + */ +/** @def RT_UNLIKELY + * Give the compiler a hint that an expression is highly unlikely to hold true. + * + * See the usage instructions give in the RT_LIKELY() docs. + * + * @returns the boolean result of the expression. + * @param expr The expression that's very unlikely to be true. + * @see RT_LIKELY + * + * @deprecated Please use RT_LIKELY() instead wherever possible! That gives us + * a better chance of the windows compilers to generate favorable code + * too. The belief is that the compiler will by default assume the + * if-case is more likely than the else-case. + */ +#if defined(__GNUC__) +# if __GNUC__ >= 3 && !defined(FORTIFY_RUNNING) +# define RT_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define RT_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +# else +# define RT_LIKELY(expr) (expr) +# define RT_UNLIKELY(expr) (expr) +# endif +#else +# define RT_LIKELY(expr) (expr) +# define RT_UNLIKELY(expr) (expr) +#endif + +/** @def RT_EXPAND_2 + * Helper for RT_EXPAND. */ +#define RT_EXPAND_2(a_Expr) a_Expr +/** @def RT_EXPAND + * Returns the expanded expression. + * @param a_Expr The expression to expand. */ +#define RT_EXPAND(a_Expr) RT_EXPAND_2(a_Expr) + +/** @def RT_STR + * Returns the argument as a string constant. + * @param str Argument to stringify. */ +#define RT_STR(str) #str +/** @def RT_XSTR + * Returns the expanded argument as a string. + * @param str Argument to expand and stringify. */ +#define RT_XSTR(str) RT_STR(str) + +/** @def RT_LSTR_2 + * Helper for RT_WSTR that gets the expanded @a str. + * @param str String litteral to prefix with 'L'. */ +#define RT_LSTR_2(str) L##str +/** @def RT_LSTR + * Returns the expanded argument with a L string prefix. + * + * Intended for converting ASCII string \#defines into wide char string + * litterals on Windows. + * + * @param str String litteral to . */ +#define RT_LSTR(str) RT_LSTR_2(str) + +/** @def RT_UNPACK_CALL + * Unpacks the an argument list inside an extra set of parenthesis and turns it + * into a call to @a a_Fn. + * + * @param a_Fn Function/macro to call. + * @param a_Args Parameter list in parenthesis. + */ +#define RT_UNPACK_CALL(a_Fn, a_Args) a_Fn a_Args + +#if defined(RT_COMPILER_SUPPORTS_VA_ARGS) || defined(DOXYGEN_RUNNING) + +/** @def RT_UNPACK_ARGS + * Returns the arguments without parenthesis. + * + * @param ... Parameter list in parenthesis. + * @remarks Requires RT_COMPILER_SUPPORTS_VA_ARGS. + */ +# define RT_UNPACK_ARGS(...) __VA_ARGS__ + +/** @def RT_COUNT_VA_ARGS_HLP + * Helper for RT_COUNT_VA_ARGS that picks out the argument count from + * RT_COUNT_VA_ARGS_REV_SEQ. */ +# define RT_COUNT_VA_ARGS_HLP( \ + c69, c68, c67, c66, c65, c64, c63, c62, c61, c60, \ + c59, c58, c57, c56, c55, c54, c53, c52, c51, c50, \ + c49, c48, c47, c46, c45, c44, c43, c42, c41, c40, \ + c39, c38, c37, c36, c35, c34, c33, c32, c31, c30, \ + c29, c28, c27, c26, c25, c24, c23, c22, c21, c20, \ + c19, c18, c17, c16, c15, c14, c13, c12, c11, c10, \ + c9, c8, c7, c6, c5, c4, c3, c2, c1, cArgs, ...) cArgs +/** Argument count sequence. */ +# define RT_COUNT_VA_ARGS_REV_SEQ \ + 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, \ + 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \ + 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \ + 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \ + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \ + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \ + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 +/** This is for zero arguments. At least Visual C++ requires it. */ +# define RT_COUNT_VA_ARGS_PREFIX_RT_NOTHING RT_COUNT_VA_ARGS_REV_SEQ +/** + * Counts the number of arguments given to the variadic macro. + * + * Max is 69. + * + * @returns Number of arguments in the ellipsis + * @param ... Arguments to count. + * @remarks Requires RT_COMPILER_SUPPORTS_VA_ARGS. + */ +# define RT_COUNT_VA_ARGS(...) \ + RT_UNPACK_CALL(RT_COUNT_VA_ARGS_HLP, (RT_COUNT_VA_ARGS_PREFIX_ ## __VA_ARGS__ ## RT_NOTHING, \ + RT_COUNT_VA_ARGS_REV_SEQ)) + +#endif /* RT_COMPILER_SUPPORTS_VA_ARGS */ + + +/** @def RT_CONCAT + * Concatenate the expanded arguments without any extra spaces in between. + * + * @param a The first part. + * @param b The second part. + */ +#define RT_CONCAT(a,b) RT_CONCAT_HLP(a,b) +/** RT_CONCAT helper, don't use. */ +#define RT_CONCAT_HLP(a,b) a##b + +/** @def RT_CONCAT3 + * Concatenate the expanded arguments without any extra spaces in between. + * + * @param a The 1st part. + * @param b The 2nd part. + * @param c The 3rd part. + */ +#define RT_CONCAT3(a,b,c) RT_CONCAT3_HLP(a,b,c) +/** RT_CONCAT3 helper, don't use. */ +#define RT_CONCAT3_HLP(a,b,c) a##b##c + +/** @def RT_CONCAT4 + * Concatenate the expanded arguments without any extra spaces in between. + * + * @param a The 1st part. + * @param b The 2nd part. + * @param c The 3rd part. + * @param d The 4th part. + */ +#define RT_CONCAT4(a,b,c,d) RT_CONCAT4_HLP(a,b,c,d) +/** RT_CONCAT4 helper, don't use. */ +#define RT_CONCAT4_HLP(a,b,c,d) a##b##c##d + +/** @def RT_CONCAT5 + * Concatenate the expanded arguments without any extra spaces in between. + * + * @param a The 1st part. + * @param b The 2nd part. + * @param c The 3rd part. + * @param d The 4th part. + * @param e The 5th part. + */ +#define RT_CONCAT5(a,b,c,d,e) RT_CONCAT5_HLP(a,b,c,d,e) +/** RT_CONCAT5 helper, don't use. */ +#define RT_CONCAT5_HLP(a,b,c,d,e) a##b##c##d##e + +/** @def RT_CONCAT6 + * Concatenate the expanded arguments without any extra spaces in between. + * + * @param a The 1st part. + * @param b The 2nd part. + * @param c The 3rd part. + * @param d The 4th part. + * @param e The 5th part. + * @param f The 6th part. + */ +#define RT_CONCAT6(a,b,c,d,e,f) RT_CONCAT6_HLP(a,b,c,d,e,f) +/** RT_CONCAT6 helper, don't use. */ +#define RT_CONCAT6_HLP(a,b,c,d,e,f) a##b##c##d##e##f + +/** @def RT_CONCAT7 + * Concatenate the expanded arguments without any extra spaces in between. + * + * @param a The 1st part. + * @param b The 2nd part. + * @param c The 3rd part. + * @param d The 4th part. + * @param e The 5th part. + * @param f The 6th part. + * @param g The 7th part. + */ +#define RT_CONCAT7(a,b,c,d,e,f,g) RT_CONCAT7_HLP(a,b,c,d,e,f,g) +/** RT_CONCAT7 helper, don't use. */ +#define RT_CONCAT7_HLP(a,b,c,d,e,f,g) a##b##c##d##e##f##g + +/** @def RT_CONCAT8 + * Concatenate the expanded arguments without any extra spaces in between. + * + * @param a The 1st part. + * @param b The 2nd part. + * @param c The 3rd part. + * @param d The 4th part. + * @param e The 5th part. + * @param f The 6th part. + * @param g The 7th part. + * @param h The 8th part. + */ +#define RT_CONCAT8(a,b,c,d,e,f,g,h) RT_CONCAT8_HLP(a,b,c,d,e,f,g,h) +/** RT_CONCAT8 helper, don't use. */ +#define RT_CONCAT8_HLP(a,b,c,d,e,f,g,h) a##b##c##d##e##f##g##h + +/** @def RT_CONCAT9 + * Concatenate the expanded arguments without any extra spaces in between. + * + * @param a The 1st part. + * @param b The 2nd part. + * @param c The 3rd part. + * @param d The 4th part. + * @param e The 5th part. + * @param f The 6th part. + * @param g The 7th part. + * @param h The 8th part. + * @param i The 9th part. + */ +#define RT_CONCAT9(a,b,c,d,e,f,g,h,i) RT_CONCAT9_HLP(a,b,c,d,e,f,g,h,i) +/** RT_CONCAT9 helper, don't use. */ +#define RT_CONCAT9_HLP(a,b,c,d,e,f,g,h,i) a##b##c##d##e##f##g##h##i + +/** + * String constant tuple - string constant, strlen(string constant). + * + * @param a_szConst String constant. + * @sa RTSTRTUPLE + */ +#define RT_STR_TUPLE(a_szConst) a_szConst, (sizeof(a_szConst) - 1) + + +/** + * Macro for using in switch statements that turns constants into strings. + * + * @param a_Const The constant (not string). + */ +#define RT_CASE_RET_STR(a_Const) case a_Const: return #a_Const + + +/** @def RT_BIT + * Convert a bit number into an integer bitmask (unsigned). + * @param bit The bit number. + */ +#define RT_BIT(bit) ( 1U << (bit) ) + +/** @def RT_BIT_32 + * Convert a bit number into a 32-bit bitmask (unsigned). + * @param bit The bit number. + */ +#define RT_BIT_32(bit) ( UINT32_C(1) << (bit) ) + +/** @def RT_BIT_64 + * Convert a bit number into a 64-bit bitmask (unsigned). + * @param bit The bit number. + */ +#define RT_BIT_64(bit) ( UINT64_C(1) << (bit) ) + +/** @def RT_BIT_Z + * Convert a bit number into a size_t bitmask (for avoid MSC warnings). + * @param a_iBit The bit number. + */ +#define RT_BIT_Z(a_iBit) ( (size_t)(1) << (a_iBit) ) + + +/** @def RT_BF_GET + * Gets the value of a bit field in an integer value. + * + * This requires a couple of macros to be defined for the field: + * - \<a_FieldNm\>_SHIFT: The shift count to get to the field. + * - \<a_FieldNm\>_MASK: The field mask. + * + * @returns The bit field value. + * @param a_uValue The integer value containing the field. + * @param a_FieldNm The field name prefix for getting at the _SHIFT and + * _MASK macros. + * @sa #RT_BF_CLEAR, #RT_BF_SET, #RT_BF_MAKE, #RT_BF_ZMASK + */ +#define RT_BF_GET(a_uValue, a_FieldNm) ( ((a_uValue) >> RT_CONCAT(a_FieldNm,_SHIFT)) & RT_BF_ZMASK(a_FieldNm) ) + +/** @def RT_BF_SET + * Sets the given bit field in the integer value. + * + * This requires a couple of macros to be defined for the field: + * - \<a_FieldNm\>_SHIFT: The shift count to get to the field. + * - \<a_FieldNm\>_MASK: The field mask. Must have the same type as the + * integer value!! + * + * @returns Integer value with bit field set to @a a_uFieldValue. + * @param a_uValue The integer value containing the field. + * @param a_FieldNm The field name prefix for getting at the _SHIFT and + * _MASK macros. + * @param a_uFieldValue The new field value. + * @sa #RT_BF_GET, #RT_BF_CLEAR, #RT_BF_MAKE, #RT_BF_ZMASK + */ +#define RT_BF_SET(a_uValue, a_FieldNm, a_uFieldValue) ( RT_BF_CLEAR(a_uValue, a_FieldNm) | RT_BF_MAKE(a_FieldNm, a_uFieldValue) ) + +/** @def RT_BF_CLEAR + * Clears the given bit field in the integer value. + * + * This requires a couple of macros to be defined for the field: + * - \<a_FieldNm\>_SHIFT: The shift count to get to the field. + * - \<a_FieldNm\>_MASK: The field mask. Must have the same type as the + * integer value!! + * + * @returns Integer value with bit field set to zero. + * @param a_uValue The integer value containing the field. + * @param a_FieldNm The field name prefix for getting at the _SHIFT and + * _MASK macros. + * @sa #RT_BF_GET, #RT_BF_SET, #RT_BF_MAKE, #RT_BF_ZMASK + */ +#define RT_BF_CLEAR(a_uValue, a_FieldNm) ( (a_uValue) & ~RT_CONCAT(a_FieldNm,_MASK) ) + +/** @def RT_BF_MAKE + * Shifts and masks a bit field value into position in the integer value. + * + * This requires a couple of macros to be defined for the field: + * - \<a_FieldNm\>_SHIFT: The shift count to get to the field. + * - \<a_FieldNm\>_MASK: The field mask. + * + * @param a_FieldNm The field name prefix for getting at the _SHIFT and + * _MASK macros. + * @param a_uFieldValue The field value that should be masked and shifted + * into position. + * @sa #RT_BF_GET, #RT_BF_SET, #RT_BF_CLEAR, #RT_BF_ZMASK + */ +#define RT_BF_MAKE(a_FieldNm, a_uFieldValue) ( ((a_uFieldValue) & RT_BF_ZMASK(a_FieldNm) ) << RT_CONCAT(a_FieldNm,_SHIFT) ) + +/** @def RT_BF_ZMASK + * Helper for getting the field mask shifted to bit position zero. + * + * @param a_FieldNm The field name prefix for getting at the _SHIFT and + * _MASK macros. + * @sa #RT_BF_GET, #RT_BF_SET, #RT_BF_CLEAR, #RT_BF_MAKE + */ +#define RT_BF_ZMASK(a_FieldNm) ( RT_CONCAT(a_FieldNm,_MASK) >> RT_CONCAT(a_FieldNm,_SHIFT) ) + +/** Bit field compile time check helper + * @internal */ +#define RT_BF_CHECK_DO_XOR_MASK(a_uLeft, a_RightPrefix, a_FieldNm) ((a_uLeft) ^ RT_CONCAT3(a_RightPrefix, a_FieldNm, _MASK)) +/** Bit field compile time check helper + * @internal */ +#define RT_BF_CHECK_DO_OR_MASK(a_uLeft, a_RightPrefix, a_FieldNm) ((a_uLeft) | RT_CONCAT3(a_RightPrefix, a_FieldNm, _MASK)) +/** Bit field compile time check helper + * @internal */ +#define RT_BF_CHECK_DO_1ST_MASK_BIT(a_uLeft, a_RightPrefix, a_FieldNm) \ + ((a_uLeft) && ( (RT_CONCAT3(a_RightPrefix, a_FieldNm, _MASK) >> RT_CONCAT3(a_RightPrefix, a_FieldNm, _SHIFT)) & 1U ) ) +/** Used to check that a bit field mask does not start too early. + * @internal */ +#define RT_BF_CHECK_DO_MASK_START(a_uLeft, a_RightPrefix, a_FieldNm) \ + ( (a_uLeft) \ + && ( RT_CONCAT3(a_RightPrefix, a_FieldNm, _SHIFT) == 0 \ + || ( ( ( ((RT_CONCAT3(a_RightPrefix, a_FieldNm, _MASK) >> RT_CONCAT3(a_RightPrefix, a_FieldNm, _SHIFT)) & 1U) \ + << RT_CONCAT3(a_RightPrefix, a_FieldNm, _SHIFT)) /* => single bit mask, correct type */ \ + - 1U) /* => mask of all bits below the field */ \ + & RT_CONCAT3(a_RightPrefix, a_FieldNm, _MASK)) == 0 ) ) +/** @name Bit field compile time check recursion workers. + * @internal + * @{ */ +#define RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix, f1) \ + a_DoThis(a_uLeft, a_RightPrefix, f1) +#define RT_BF_CHECK_DO_2(a_DoThis, a_uLeft, a_RightPrefix, f1, f2) \ + RT_BF_CHECK_DO_1(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2) +#define RT_BF_CHECK_DO_3(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3) \ + RT_BF_CHECK_DO_2(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3) +#define RT_BF_CHECK_DO_4(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4) \ + RT_BF_CHECK_DO_3(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4) +#define RT_BF_CHECK_DO_5(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5) \ + RT_BF_CHECK_DO_4(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5) +#define RT_BF_CHECK_DO_6(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6) \ + RT_BF_CHECK_DO_5(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6) +#define RT_BF_CHECK_DO_7(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7) \ + RT_BF_CHECK_DO_6(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7) +#define RT_BF_CHECK_DO_8(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8) \ + RT_BF_CHECK_DO_7(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8) +#define RT_BF_CHECK_DO_9(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9) \ + RT_BF_CHECK_DO_8(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9) +#define RT_BF_CHECK_DO_10(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10) \ + RT_BF_CHECK_DO_9(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10) +#define RT_BF_CHECK_DO_11(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11) \ + RT_BF_CHECK_DO_10(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11) +#define RT_BF_CHECK_DO_12(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12) \ + RT_BF_CHECK_DO_11(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12) +#define RT_BF_CHECK_DO_13(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13) \ + RT_BF_CHECK_DO_12(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13) +#define RT_BF_CHECK_DO_14(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14) \ + RT_BF_CHECK_DO_13(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14) +#define RT_BF_CHECK_DO_15(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15) \ + RT_BF_CHECK_DO_14(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15) +#define RT_BF_CHECK_DO_16(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16) \ + RT_BF_CHECK_DO_15(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16) +#define RT_BF_CHECK_DO_17(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17) \ + RT_BF_CHECK_DO_16(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17) +#define RT_BF_CHECK_DO_18(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18) \ + RT_BF_CHECK_DO_17(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18) +#define RT_BF_CHECK_DO_19(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19) \ + RT_BF_CHECK_DO_18(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19) +#define RT_BF_CHECK_DO_20(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20) \ + RT_BF_CHECK_DO_19(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20) +#define RT_BF_CHECK_DO_21(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21) \ + RT_BF_CHECK_DO_20(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21) +#define RT_BF_CHECK_DO_22(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22) \ + RT_BF_CHECK_DO_21(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22) +#define RT_BF_CHECK_DO_23(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23) \ + RT_BF_CHECK_DO_22(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23) +#define RT_BF_CHECK_DO_24(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24) \ + RT_BF_CHECK_DO_23(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24) +#define RT_BF_CHECK_DO_25(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25) \ + RT_BF_CHECK_DO_24(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25) +#define RT_BF_CHECK_DO_26(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26) \ + RT_BF_CHECK_DO_25(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26) +#define RT_BF_CHECK_DO_27(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27) \ + RT_BF_CHECK_DO_26(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27) +#define RT_BF_CHECK_DO_28(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28) \ + RT_BF_CHECK_DO_27(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28) +#define RT_BF_CHECK_DO_29(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29) \ + RT_BF_CHECK_DO_28(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29) +#define RT_BF_CHECK_DO_30(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30) \ + RT_BF_CHECK_DO_29(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30) +#define RT_BF_CHECK_DO_31(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31) \ + RT_BF_CHECK_DO_30(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31) +#define RT_BF_CHECK_DO_32(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32) \ + RT_BF_CHECK_DO_31(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32) +#define RT_BF_CHECK_DO_33(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33) \ + RT_BF_CHECK_DO_32(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33) +#define RT_BF_CHECK_DO_34(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34) \ + RT_BF_CHECK_DO_33(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34) +#define RT_BF_CHECK_DO_35(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35) \ + RT_BF_CHECK_DO_34(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35) +#define RT_BF_CHECK_DO_36(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36) \ + RT_BF_CHECK_DO_35(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36) +#define RT_BF_CHECK_DO_37(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37) \ + RT_BF_CHECK_DO_36(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37) +#define RT_BF_CHECK_DO_38(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38) \ + RT_BF_CHECK_DO_37(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38) +#define RT_BF_CHECK_DO_39(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39) \ + RT_BF_CHECK_DO_38(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39) +#define RT_BF_CHECK_DO_40(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40) \ + RT_BF_CHECK_DO_39(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40) +#define RT_BF_CHECK_DO_41(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41) \ + RT_BF_CHECK_DO_40(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41) +#define RT_BF_CHECK_DO_42(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42) \ + RT_BF_CHECK_DO_41(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42) +#define RT_BF_CHECK_DO_43(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43) \ + RT_BF_CHECK_DO_42(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43) +#define RT_BF_CHECK_DO_44(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44) \ + RT_BF_CHECK_DO_43(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44) +#define RT_BF_CHECK_DO_45(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45) \ + RT_BF_CHECK_DO_44(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45) +#define RT_BF_CHECK_DO_46(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46) \ + RT_BF_CHECK_DO_45(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46) +#define RT_BF_CHECK_DO_47(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47) \ + RT_BF_CHECK_DO_46(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47) +#define RT_BF_CHECK_DO_48(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48) \ + RT_BF_CHECK_DO_47(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48) +#define RT_BF_CHECK_DO_49(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49) \ + RT_BF_CHECK_DO_48(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49) +#define RT_BF_CHECK_DO_50(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50) \ + RT_BF_CHECK_DO_49(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50) +#define RT_BF_CHECK_DO_51(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51) \ + RT_BF_CHECK_DO_40(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51) +#define RT_BF_CHECK_DO_52(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52) \ + RT_BF_CHECK_DO_51(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52) +#define RT_BF_CHECK_DO_53(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53) \ + RT_BF_CHECK_DO_52(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53) +#define RT_BF_CHECK_DO_54(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54) \ + RT_BF_CHECK_DO_53(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54) +#define RT_BF_CHECK_DO_55(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55) \ + RT_BF_CHECK_DO_54(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55) +#define RT_BF_CHECK_DO_56(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56) \ + RT_BF_CHECK_DO_55(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56) +#define RT_BF_CHECK_DO_57(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57) \ + RT_BF_CHECK_DO_56(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57) +#define RT_BF_CHECK_DO_58(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58) \ + RT_BF_CHECK_DO_57(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58) +#define RT_BF_CHECK_DO_59(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59) \ + RT_BF_CHECK_DO_58(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59) +#define RT_BF_CHECK_DO_60(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60) \ + RT_BF_CHECK_DO_59(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60) +#define RT_BF_CHECK_DO_61(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60, f61) \ + RT_BF_CHECK_DO_60(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60, f61) +#define RT_BF_CHECK_DO_62(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60, f61, f62) \ + RT_BF_CHECK_DO_61(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60, f61, f62) +#define RT_BF_CHECK_DO_63(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60, f61, f62, f63) \ + RT_BF_CHECK_DO_62(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60, f61, f62, f63) +#define RT_BF_CHECK_DO_64(a_DoThis, a_uLeft, a_RightPrefix, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60, f61, f62, f63, f64) \ + RT_BF_CHECK_DO_63(a_DoThis, RT_BF_CHECK_DO_1(a_DoThis, a_uLeft, a_RightPrefix,f1), a_RightPrefix, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60, f61, f62, f63, f64) +/** @} */ + +/** @def RT_BF_ASSERT_COMPILE_CHECKS + * Emits a series of AssertCompile statements checking that the bit-field + * declarations doesn't overlap, has holes, and generally makes some sense. + * + * This requires variadic macros because its too much to type otherwise. + */ +#if defined(RT_COMPILER_SUPPORTS_VA_ARGS) || defined(DOXYGEN_RUNNING) +# define RT_BF_ASSERT_COMPILE_CHECKS(a_Prefix, a_uZero, a_uCovered, a_Fields) \ + AssertCompile(RT_BF_CHECK_DO_N(RT_BF_CHECK_DO_OR_MASK, a_uZero, a_Prefix, RT_UNPACK_ARGS a_Fields ) == a_uCovered); \ + AssertCompile(RT_BF_CHECK_DO_N(RT_BF_CHECK_DO_XOR_MASK, a_uCovered, a_Prefix, RT_UNPACK_ARGS a_Fields ) == 0); \ + AssertCompile(RT_BF_CHECK_DO_N(RT_BF_CHECK_DO_1ST_MASK_BIT, true, a_Prefix, RT_UNPACK_ARGS a_Fields ) == true); \ + AssertCompile(RT_BF_CHECK_DO_N(RT_BF_CHECK_DO_MASK_START, true, a_Prefix, RT_UNPACK_ARGS a_Fields ) == true) +/** Bit field compile time check helper + * @internal */ +# define RT_BF_CHECK_DO_N(a_DoThis, a_uLeft, a_RightPrefix, ...) \ + RT_UNPACK_CALL(RT_CONCAT(RT_BF_CHECK_DO_, RT_EXPAND(RT_COUNT_VA_ARGS(__VA_ARGS__))), (a_DoThis, a_uLeft, a_RightPrefix, __VA_ARGS__)) +#else +# define RT_BF_ASSERT_COMPILE_CHECKS(a_Prefix, a_uZero, a_uCovered, a_Fields) AssertCompile(true) +#endif + + +/** @def RT_ALIGN + * Align macro. + * @param u Value to align. + * @param uAlignment The alignment. Power of two! + * + * @remark Be extremely careful when using this macro with type which sizeof != sizeof int. + * When possible use any of the other RT_ALIGN_* macros. And when that's not + * possible, make 101% sure that uAlignment is specified with a right sized type. + * + * Specifying an unsigned 32-bit alignment constant with a 64-bit value will give + * you a 32-bit return value! + * + * In short: Don't use this macro. Use RT_ALIGN_T() instead. + */ +#define RT_ALIGN(u, uAlignment) ( ((u) + ((uAlignment) - 1)) & ~((uAlignment) - 1) ) + +/** @def RT_ALIGN_T + * Align macro. + * @param u Value to align. + * @param uAlignment The alignment. Power of two! + * @param type Integer type to use while aligning. + * @remark This macro is the preferred alignment macro, it doesn't have any of the pitfalls RT_ALIGN has. + */ +#define RT_ALIGN_T(u, uAlignment, type) ( ((type)(u) + ((uAlignment) - 1)) & ~(type)((uAlignment) - 1) ) + +/** @def RT_ALIGN_32 + * Align macro for a 32-bit value. + * @param u32 Value to align. + * @param uAlignment The alignment. Power of two! + */ +#define RT_ALIGN_32(u32, uAlignment) RT_ALIGN_T(u32, uAlignment, uint32_t) + +/** @def RT_ALIGN_64 + * Align macro for a 64-bit value. + * @param u64 Value to align. + * @param uAlignment The alignment. Power of two! + */ +#define RT_ALIGN_64(u64, uAlignment) RT_ALIGN_T(u64, uAlignment, uint64_t) + +/** @def RT_ALIGN_Z + * Align macro for size_t. + * @param cb Value to align. + * @param uAlignment The alignment. Power of two! + */ +#define RT_ALIGN_Z(cb, uAlignment) RT_ALIGN_T(cb, uAlignment, size_t) + +/** @def RT_ALIGN_P + * Align macro for pointers. + * @param pv Value to align. + * @param uAlignment The alignment. Power of two! + */ +#define RT_ALIGN_P(pv, uAlignment) RT_ALIGN_PT(pv, uAlignment, void *) + +/** @def RT_ALIGN_PT + * Align macro for pointers with type cast. + * @param u Value to align. + * @param uAlignment The alignment. Power of two! + * @param CastType The type to cast the result to. + */ +#define RT_ALIGN_PT(u, uAlignment, CastType) ( (CastType)RT_ALIGN_T(u, uAlignment, uintptr_t) ) + +/** @def RT_ALIGN_R3PT + * Align macro for ring-3 pointers with type cast. + * @param u Value to align. + * @param uAlignment The alignment. Power of two! + * @param CastType The type to cast the result to. + */ +#define RT_ALIGN_R3PT(u, uAlignment, CastType) ( (CastType)RT_ALIGN_T(u, uAlignment, RTR3UINTPTR) ) + +/** @def RT_ALIGN_R0PT + * Align macro for ring-0 pointers with type cast. + * @param u Value to align. + * @param uAlignment The alignment. Power of two! + * @param CastType The type to cast the result to. + */ +#define RT_ALIGN_R0PT(u, uAlignment, CastType) ( (CastType)RT_ALIGN_T(u, uAlignment, RTR0UINTPTR) ) + +/** @def RT_ALIGN_GCPT + * Align macro for GC pointers with type cast. + * @param u Value to align. + * @param uAlignment The alignment. Power of two! + * @param CastType The type to cast the result to. + */ +#define RT_ALIGN_GCPT(u, uAlignment, CastType) ( (CastType)RT_ALIGN_T(u, uAlignment, RTGCUINTPTR) ) + + +/** @def RT_OFFSETOF + * Our own special offsetof() variant, returns a signed result. + * + * @returns offset into the structure of the specified member. signed. + * @param type Structure type. + * @param member Member. + * + * @remarks Only use this for static offset calculations. Please + * use RT_UOFFSETOF_DYN for dynamic ones (i.e. involves + * non-constant array indexing). + * + */ +#if RT_GNUC_PREREQ(4, 0) +# define RT_OFFSETOF(type, member) ( (int)__builtin_offsetof(type, member) ) +#else +# define RT_OFFSETOF(type, member) ( (int)(intptr_t)&( ((type *)(void *)0)->member) ) +#endif + +/** @def RT_UOFFSETOF + * Our own offsetof() variant, returns an unsigned result. + * + * @returns offset into the structure of the specified member. unsigned. + * @param type Structure type. + * @param member Member. + * + * @remarks Only use this for static offset calculations. Please + * use RT_UOFFSETOF_DYN for dynamic ones (i.e. involves + * non-constant array indexing). + */ +#if RT_GNUC_PREREQ(4, 0) +# define RT_UOFFSETOF(type, member) ( (uintptr_t)__builtin_offsetof(type, member) ) +#else +# define RT_UOFFSETOF(type, member) ( (uintptr_t)&( ((type *)(void *)0)->member) ) +#endif + +/** @def RT_OFFSETOF_ADD + * RT_OFFSETOF with an addend. + * + * @returns offset into the structure of the specified member. signed. + * @param type Structure type. + * @param member Member. + * @param addend The addend to add to the offset. + * + * @remarks Only use this for static offset calculations. + */ +#define RT_OFFSETOF_ADD(type, member, addend) ( (int)RT_UOFFSETOF_ADD(type, member, addend) ) + +/** @def RT_UOFFSETOF_ADD + * RT_UOFFSETOF with an addend. + * + * @returns offset into the structure of the specified member. signed. + * @param type Structure type. + * @param member Member. + * @param addend The addend to add to the offset. + * + * @remarks Only use this for static offset calculations. + */ +#if RT_GNUC_PREREQ(4, 0) +# define RT_UOFFSETOF_ADD(type, member, addend) ( (uintptr_t)(__builtin_offsetof(type, member) + (addend))) +#else +# define RT_UOFFSETOF_ADD(type, member, addend) ( (uintptr_t)&( ((type *)(void *)(uintptr_t)(addend))->member) ) +#endif + +/** @def RT_UOFFSETOF_DYN + * Dynamic (runtime) structure offset calculations, involving + * indexing of array members via variable. + * + * @returns offset into the structure of the specified member. signed. + * @param type Structure type. + * @param memberarray Member. + */ +#if defined(__cplusplus) && RT_GNUC_PREREQ(4, 4) +# define RT_UOFFSETOF_DYN(type, memberarray) ( (uintptr_t)&( ((type *)(void *)0x1000)->memberarray) - 0x1000 ) +#else +# define RT_UOFFSETOF_DYN(type, memberarray) ( (uintptr_t)&( ((type *)(void *)0)->memberarray) ) +#endif + + +/** @def RT_SIZEOFMEMB + * Get the size of a structure member. + * + * @returns size of the structure member. + * @param type Structure type. + * @param member Member. + */ +#define RT_SIZEOFMEMB(type, member) ( sizeof(((type *)(void *)0)->member) ) + +/** @def RT_UOFFSET_AFTER + * Returns the offset of the first byte following a structure/union member. + * + * @return byte offset into the struct. + * @param a_Type Structure type. + * @param a_Member The member name. + */ +#define RT_UOFFSET_AFTER(a_Type, a_Member) ( RT_UOFFSETOF(a_Type, a_Member) + RT_SIZEOFMEMB(a_Type, a_Member) ) + +/** @def RT_FROM_MEMBER + * Convert a pointer to a structure member into a pointer to the structure. + * + * @returns pointer to the structure. + * @param pMem Pointer to the member. + * @param Type Structure type. + * @param Member Member name. + */ +#define RT_FROM_MEMBER(pMem, Type, Member) ( (Type *) ((uint8_t *)(void *)(pMem) - RT_UOFFSETOF(Type, Member)) ) + +/** @def RT_FROM_CPP_MEMBER + * Same as RT_FROM_MEMBER except it avoids the annoying g++ warnings about + * invalid access to non-static data member of NULL object. + * + * @returns pointer to the structure. + * @param pMem Pointer to the member. + * @param Type Structure type. + * @param Member Member name. + * + * @remarks Using the __builtin_offsetof does not shut up the compiler. + */ +#if defined(__GNUC__) && defined(__cplusplus) +# define RT_FROM_CPP_MEMBER(pMem, Type, Member) \ + ( (Type *) ((uintptr_t)(pMem) - (uintptr_t)&((Type *)0x1000)->Member + 0x1000U) ) +#else +# define RT_FROM_CPP_MEMBER(pMem, Type, Member) RT_FROM_MEMBER(pMem, Type, Member) +#endif + +/** @def RT_FROM_MEMBER_DYN + * Convert a pointer to a structure member into a pointer to the structure. + * + * @returns pointer to the structure. + * @param pMem Pointer to the member. + * @param Type Structure type. + * @param Member Member name dynamic size (some array is index by + * non-constant value). + */ +#define RT_FROM_MEMBER_DYN(pMem, Type, Member) ( (Type *) ((uint8_t *)(void *)(pMem) - RT_UOFFSETOF_DYN(Type, Member)) ) + +/** @def RT_ELEMENTS + * Calculates the number of elements in a statically sized array. + * @returns Element count. + * @param aArray Array in question. + */ +#define RT_ELEMENTS(aArray) ( sizeof(aArray) / sizeof((aArray)[0]) ) + +/** @def RT_SAFE_SUBSCRIPT + * Safe array subscript using modulo and size_t cast. + * @param a_Array The array. + * @param a_idx The array index, cast to size_t to ensure unsigned. + */ +#define RT_SAFE_SUBSCRIPT(a_Array, a_idx) (a_Array)[(size_t)(a_idx) % RT_ELEMENTS(a_Array)] + +/** @def RT_SAFE_SUBSCRIPT32 + * Safe array subscript using modulo and uint32_t cast. + * @param a_Array The array. + * @param a_idx The array index, cast to size_t to ensure unsigned. + * @note Only consider using this if array size is not power of two. + */ +#define RT_SAFE_SUBSCRIPT32(a_Array, a_idx) (a_Array)[(uint32_t)(a_idx) % RT_ELEMENTS(a_Array)] + +/** @def RT_SAFE_SUBSCRIPT16 + * Safe array subscript using modulo and uint16_t cast. + * @param a_Array The array. + * @param a_idx The array index, cast to size_t to ensure unsigned. + * @note Only consider using this if array size is not power of two. + */ +#define RT_SAFE_SUBSCRIPT16(a_Array, a_idx) (a_Array)[(uint16_t)(a_idx) % RT_ELEMENTS(a_Array)] + +/** @def RT_SAFE_SUBSCRIPT8 + * Safe array subscript using modulo and uint8_t cast. + * @param a_Array The array. + * @param a_idx The array index, cast to size_t to ensure unsigned. + * @note Only consider using this if array size is not power of two. + */ +#define RT_SAFE_SUBSCRIPT8(a_Array, a_idx) (a_Array)[(uint8_t)(a_idx) % RT_ELEMENTS(a_Array)] + +/** @def RT_SAFE_SUBSCRIPT_NC + * Safe array subscript using modulo but no cast. + * @param a_Array The array. + * @param a_idx The array index - assumes unsigned type. + * @note Only consider using this if array size is not power of two. + */ +#define RT_SAFE_SUBSCRIPT_NC(a_Array, a_idx) (a_Array)[(a_idx) % RT_ELEMENTS(a_Array)] + +/** @def RT_FLEXIBLE_ARRAY + * What to up inside the square brackets when declaring a structure member + * with a flexible size. + * + * @note RT_FLEXIBLE_ARRAY_EXTENSION must always preceed the type, unless + * it's C-only code. + * + * @note Use RT_UOFFSETOF() to calculate the structure size. + * + * @note Never do a sizeof() on the structure or member! + * + * @note The member must be the last one. + * + * @note GCC does not permit using this in a union. So, for unions you must + * use RT_FLEXIBLE_ARRAY_IN_UNION instead. + * + * @note GCC does not permit using this in nested structures, where as MSC + * does. So, use RT_FLEXIBLE_ARRAY_NESTED for that. + * + * @sa RT_FLEXIBLE_ARRAY_NESTED, RT_FLEXIBLE_ARRAY_IN_UNION + */ +#if RT_MSC_PREREQ(RT_MSC_VER_VS2005) /** @todo Probably much much earlier. */ \ + || (defined(__cplusplus) && RT_GNUC_PREREQ(6, 1)) /* not tested 7.x, but hope it works with __extension__ too. */ \ + || defined(__WATCOMC__) /* openwatcom 1.9 supports it, we don't care about older atm. */ \ + || RT_CLANG_PREREQ_EX(3, 4, 0) /* Only tested clang v3.4, support is probably older. */ +# define RT_FLEXIBLE_ARRAY +# if defined(__cplusplus) && defined(_MSC_VER) +# pragma warning(disable:4200) /* -wd4200 does not work with VS2010 */ +# pragma warning(disable:4815) /* -wd4815 does not work with VS2019 */ +# endif +#elif defined(__STDC_VERSION__) +# if __STDC_VERSION__ >= 1999901L +# define RT_FLEXIBLE_ARRAY +# else +# define RT_FLEXIBLE_ARRAY 1 +# endif +#else +# define RT_FLEXIBLE_ARRAY 1 +#endif + +/** @def RT_FLEXIBLE_ARRAY_EXTENSION + * A trick to make GNU C++ quietly accept flexible arrays in C++ code when + * pedantic warnings are enabled. Put this on the line before the flexible + * array. */ +#if (RT_GNUC_PREREQ(7, 0) && defined(__cplusplus)) || defined(DOXGYEN_RUNNING) +# define RT_FLEXIBLE_ARRAY_EXTENSION RT_GCC_EXTENSION +#else +# define RT_FLEXIBLE_ARRAY_EXTENSION +#endif + +/** @def RT_FLEXIBLE_ARRAY_NESTED + * Variant of RT_FLEXIBLE_ARRAY for use in structures that are nested. + * + * GCC only allow the use of flexible array member in the top structure, whereas + * MSC is less strict and let you do struct { struct { char szName[]; } s; }; + * + * @note See notes for RT_FLEXIBLE_ARRAY. + * + * @note GCC does not permit using this in a union. So, for unions you must + * use RT_FLEXIBLE_ARRAY_IN_NESTED_UNION instead. + * + * @sa RT_FLEXIBLE_ARRAY, RT_FLEXIBLE_ARRAY_IN_NESTED_UNION + */ +#ifdef _MSC_VER +# define RT_FLEXIBLE_ARRAY_NESTED RT_FLEXIBLE_ARRAY +#else +# define RT_FLEXIBLE_ARRAY_NESTED 1 +#endif + +/** @def RT_FLEXIBLE_ARRAY_IN_UNION + * The union version of RT_FLEXIBLE_ARRAY. + * + * @remarks GCC does not support flexible array members in unions, 6.1.x + * actively checks for this. Visual C++ 2010 seems happy with it. + * + * @note See notes for RT_FLEXIBLE_ARRAY. + * + * @sa RT_FLEXIBLE_ARRAY, RT_FLEXIBLE_ARRAY_IN_NESTED_UNION + */ +#ifdef _MSC_VER +# define RT_FLEXIBLE_ARRAY_IN_UNION RT_FLEXIBLE_ARRAY +#else +# define RT_FLEXIBLE_ARRAY_IN_UNION 1 +#endif + +/** @def RT_FLEXIBLE_ARRAY_IN_NESTED_UNION + * The union version of RT_FLEXIBLE_ARRAY_NESTED. + * + * @note See notes for RT_FLEXIBLE_ARRAY. + * + * @sa RT_FLEXIBLE_ARRAY, RT_FLEXIBLE_ARRAY_IN_NESTED_UNION + */ +#ifdef _MSC_VER +# define RT_FLEXIBLE_ARRAY_IN_NESTED_UNION RT_FLEXIBLE_ARRAY_NESTED +#else +# define RT_FLEXIBLE_ARRAY_IN_NESTED_UNION 1 +#endif + +/** @def RT_UNION_NM + * For compilers (like DTrace) that does not grok nameless unions, we have a + * little hack to make them palatable. + */ +/** @def RT_STRUCT_NM + * For compilers (like DTrace) that does not grok nameless structs (it is + * non-standard C++), we have a little hack to make them palatable. + */ +#ifdef IPRT_WITHOUT_NAMED_UNIONS_AND_STRUCTS +# define RT_UNION_NM(a_Nm) a_Nm +# define RT_STRUCT_NM(a_Nm) a_Nm +#else +# define RT_UNION_NM(a_Nm) +# define RT_STRUCT_NM(a_Nm) +#endif + +/** + * Checks if the value is a power of two. + * + * @returns true if power of two, false if not. + * @param uVal The value to test. + * @remarks 0 is a power of two. + * @see VERR_NOT_POWER_OF_TWO + */ +#define RT_IS_POWER_OF_TWO(uVal) ( ((uVal) & ((uVal) - 1)) == 0) + +#ifdef RT_OS_OS2 +/* Undefine RT_MAX since there is an unfortunate clash with the max + resource type define in os2.h. */ +# undef RT_MAX +#endif + +/** @def RT_MAX + * Finds the maximum value. + * @returns The higher of the two. + * @param Value1 Value 1 + * @param Value2 Value 2 + */ +#define RT_MAX(Value1, Value2) ( (Value1) >= (Value2) ? (Value1) : (Value2) ) + +/** @def RT_MIN + * Finds the minimum value. + * @returns The lower of the two. + * @param Value1 Value 1 + * @param Value2 Value 2 + */ +#define RT_MIN(Value1, Value2) ( (Value1) <= (Value2) ? (Value1) : (Value2) ) + +/** @def RT_CLAMP + * Clamps the value to minimum and maximum values. + * @returns The clamped value. + * @param Value The value to check. + * @param Min Minimum value. + * @param Max Maximum value. + */ +#define RT_CLAMP(Value, Min, Max) ( (Value) > (Max) ? (Max) : (Value) < (Min) ? (Min) : (Value) ) + +/** @def RT_ABS + * Get the absolute (non-negative) value. + * @returns The absolute value of Value. + * @param Value The value. + */ +#define RT_ABS(Value) ( (Value) >= 0 ? (Value) : -(Value) ) + +/** @def RT_BOOL + * Turn non-zero/zero into true/false + * @returns The resulting boolean value. + * @param Value The value. + */ +#define RT_BOOL(Value) ( !!(Value) ) + +/** @def RT_LO_U8 + * Gets the low uint8_t of a uint16_t or something equivalent. */ +#ifdef __GNUC__ +# define RT_LO_U8(a) __extension__ ({ AssertCompile(sizeof((a)) == sizeof(uint16_t)); (uint8_t)(a); }) +#elif defined(_MSC_VER) /* shut up cast truncates constant value warnings */ +# define RT_LO_U8(a) ( (uint8_t)(UINT8_MAX & (a)) ) +#else +# define RT_LO_U8(a) ( (uint8_t)(a) ) +#endif +/** @def RT_HI_U8 + * Gets the high uint8_t of a uint16_t or something equivalent. */ +#ifdef __GNUC__ +# define RT_HI_U8(a) __extension__ ({ AssertCompile(sizeof((a)) == sizeof(uint16_t)); (uint8_t)((a) >> 8); }) +#else +# define RT_HI_U8(a) ( (uint8_t)((a) >> 8) ) +#endif + +/** @def RT_LO_U16 + * Gets the low uint16_t of a uint32_t or something equivalent. */ +#ifdef __GNUC__ +# define RT_LO_U16(a) __extension__ ({ AssertCompile(sizeof((a)) == sizeof(uint32_t)); (uint16_t)(a); }) +#elif defined(_MSC_VER) /* shut up cast truncates constant value warnings */ +# define RT_LO_U16(a) ( (uint16_t)(UINT16_MAX & (a)) ) +#else +# define RT_LO_U16(a) ( (uint16_t)(a) ) +#endif +/** @def RT_HI_U16 + * Gets the high uint16_t of a uint32_t or something equivalent. */ +#ifdef __GNUC__ +# define RT_HI_U16(a) __extension__ ({ AssertCompile(sizeof((a)) == sizeof(uint32_t)); (uint16_t)((a) >> 16); }) +#else +# define RT_HI_U16(a) ( (uint16_t)((a) >> 16) ) +#endif + +/** @def RT_LO_U32 + * Gets the low uint32_t of a uint64_t or something equivalent. */ +#ifdef __GNUC__ +# define RT_LO_U32(a) __extension__ ({ AssertCompile(sizeof((a)) == sizeof(uint64_t)); (uint32_t)(a); }) +#elif defined(_MSC_VER) /* shut up cast truncates constant value warnings */ +# define RT_LO_U32(a) ( (uint32_t)(UINT32_MAX & (a)) ) +#else +# define RT_LO_U32(a) ( (uint32_t)(a) ) +#endif +/** @def RT_HI_U32 + * Gets the high uint32_t of a uint64_t or something equivalent. */ +#ifdef __GNUC__ +# define RT_HI_U32(a) __extension__ ({ AssertCompile(sizeof((a)) == sizeof(uint64_t)); (uint32_t)((a) >> 32); }) +#else +# define RT_HI_U32(a) ( (uint32_t)((a) >> 32) ) +#endif + +/** @def RT_BYTE1 + * Gets the first byte of something. */ +#define RT_BYTE1(a) ( (uint8_t)((a) & 0xff) ) +/** @def RT_BYTE2 + * Gets the second byte of something. */ +#define RT_BYTE2(a) ( (uint8_t)(((a) >> 8) & 0xff) ) +/** @def RT_BYTE3 + * Gets the second byte of something. */ +#define RT_BYTE3(a) ( (uint8_t)(((a) >> 16) & 0xff) ) +/** @def RT_BYTE4 + * Gets the fourth byte of something. */ +#define RT_BYTE4(a) ( (uint8_t)(((a) >> 24) & 0xff) ) +/** @def RT_BYTE5 + * Gets the fifth byte of something. */ +#define RT_BYTE5(a) ( (uint8_t)(((a) >> 32) & 0xff) ) +/** @def RT_BYTE6 + * Gets the sixth byte of something. */ +#define RT_BYTE6(a) ( (uint8_t)(((a) >> 40) & 0xff) ) +/** @def RT_BYTE7 + * Gets the seventh byte of something. */ +#define RT_BYTE7(a) ( (uint8_t)(((a) >> 48) & 0xff) ) +/** @def RT_BYTE8 + * Gets the eight byte of something. */ +#define RT_BYTE8(a) ( (uint8_t)(((a) >> 56) & 0xff) ) + + +/** @def RT_LODWORD + * Gets the low dword (=uint32_t) of something. + * @deprecated Use RT_LO_U32. */ +#define RT_LODWORD(a) ( (uint32_t)(a) ) +/** @def RT_HIDWORD + * Gets the high dword (=uint32_t) of a 64-bit of something. + * @deprecated Use RT_HI_U32. */ +#define RT_HIDWORD(a) ( (uint32_t)((a) >> 32) ) + +/** @def RT_LOWORD + * Gets the low word (=uint16_t) of something. + * @deprecated Use RT_LO_U16. */ +#define RT_LOWORD(a) ( (a) & 0xffff ) +/** @def RT_HIWORD + * Gets the high word (=uint16_t) of a 32-bit something. + * @deprecated Use RT_HI_U16. */ +#define RT_HIWORD(a) ( (a) >> 16 ) + +/** @def RT_LOBYTE + * Gets the low byte of something. + * @deprecated Use RT_LO_U8. */ +#define RT_LOBYTE(a) ( (a) & 0xff ) +/** @def RT_HIBYTE + * Gets the high byte of a 16-bit something. + * @deprecated Use RT_HI_U8. */ +#define RT_HIBYTE(a) ( (a) >> 8 ) + + +/** @def RT_MAKE_U64 + * Constructs a uint64_t value from two uint32_t values. + */ +#define RT_MAKE_U64(Lo, Hi) ( (uint64_t)((uint32_t)(Hi)) << 32 | (uint32_t)(Lo) ) + +/** @def RT_MAKE_U64_FROM_U16 + * Constructs a uint64_t value from four uint16_t values. + */ +#define RT_MAKE_U64_FROM_U16(w0, w1, w2, w3) \ + ((uint64_t)( (uint64_t)((uint16_t)(w3)) << 48 \ + | (uint64_t)((uint16_t)(w2)) << 32 \ + | (uint32_t)((uint16_t)(w1)) << 16 \ + | (uint16_t)(w0) )) + +/** @def RT_MAKE_U64_FROM_U8 + * Constructs a uint64_t value from eight uint8_t values. + */ +#define RT_MAKE_U64_FROM_U8(b0, b1, b2, b3, b4, b5, b6, b7) \ + ((uint64_t)( (uint64_t)((uint8_t)(b7)) << 56 \ + | (uint64_t)((uint8_t)(b6)) << 48 \ + | (uint64_t)((uint8_t)(b5)) << 40 \ + | (uint64_t)((uint8_t)(b4)) << 32 \ + | (uint64_t)((uint8_t)(b3)) << 24 \ + | (uint64_t)((uint8_t)(b2)) << 16 \ + | (uint64_t)((uint8_t)(b1)) << 8 \ + | (uint64_t) (uint8_t)(b0) )) + +/** @def RT_MAKE_U32 + * Constructs a uint32_t value from two uint16_t values. + */ +#define RT_MAKE_U32(Lo, Hi) \ + ((uint32_t)( (uint32_t)((uint16_t)(Hi)) << 16 \ + | (uint16_t)(Lo) )) + +/** @def RT_MAKE_U32_FROM_U8 + * Constructs a uint32_t value from four uint8_t values. + */ +#define RT_MAKE_U32_FROM_U8(b0, b1, b2, b3) \ + ((uint32_t)( (uint32_t)((uint8_t)(b3)) << 24 \ + | (uint32_t)((uint8_t)(b2)) << 16 \ + | (uint32_t)((uint8_t)(b1)) << 8 \ + | (uint8_t)(b0) )) + +/** @def RT_MAKE_U16 + * Constructs a uint16_t value from two uint8_t values. + */ +#define RT_MAKE_U16(Lo, Hi) \ + ((uint16_t)( (uint16_t)((uint8_t)(Hi)) << 8 \ + | (uint8_t)(Lo) )) + + +/** @def RT_BSWAP_U64 + * Reverses the byte order of an uint64_t value. */ +#if defined(__GNUC__) +# define RT_BSWAP_U64(u64) (__builtin_constant_p((u64)) ? RT_BSWAP_U64_C(u64) : ASMByteSwapU64(u64)) +#else +# define RT_BSWAP_U64(u64) ASMByteSwapU64(u64) +#endif + +/** @def RT_BSWAP_U32 + * Reverses the byte order of an uint32_t value. */ +#if defined(__GNUC__) +# define RT_BSWAP_U32(u32) (__builtin_constant_p((u32)) ? RT_BSWAP_U32_C(u32) : ASMByteSwapU32(u32)) +#else +# define RT_BSWAP_U32(u32) ASMByteSwapU32(u32) +#endif + +/** @def RT_BSWAP_U16 + * Reverses the byte order of an uint16_t value. */ +#if defined(__GNUC__) +# define RT_BSWAP_U16(u16) (__builtin_constant_p((u16)) ? RT_BSWAP_U16_C(u16) : ASMByteSwapU16(u16)) +#else +# define RT_BSWAP_U16(u16) ASMByteSwapU16(u16) +#endif + +/** @def RT_BSWAP_S64 + * Reverses the byte order of an int64_t value. */ +#define RT_BSWAP_S64(i64) ((int64_t)RT_BSWAP_U64((uint64_t)i64)) + +/** @def RT_BSWAP_S32 + * Reverses the byte order of an int32_t value. */ +#define RT_BSWAP_S32(i32) ((int32_t)RT_BSWAP_U32((uint32_t)i32)) + +/** @def RT_BSWAP_S16 + * Reverses the byte order of an int16_t value. */ +#define RT_BSWAP_S16(i16) ((int16_t)RT_BSWAP_U16((uint16_t)i16)) + + +/** @def RT_BSWAP_U64_C + * Reverses the byte order of an uint64_t constant. */ +#define RT_BSWAP_U64_C(u64) RT_MAKE_U64(RT_BSWAP_U32_C((u64) >> 32), RT_BSWAP_U32_C((u64) & 0xffffffff)) + +/** @def RT_BSWAP_U32_C + * Reverses the byte order of an uint32_t constant. */ +#define RT_BSWAP_U32_C(u32) RT_MAKE_U32_FROM_U8(RT_BYTE4(u32), RT_BYTE3(u32), RT_BYTE2(u32), RT_BYTE1(u32)) + +/** @def RT_BSWAP_U16_C + * Reverses the byte order of an uint16_t constant. */ +#define RT_BSWAP_U16_C(u16) RT_MAKE_U16(RT_HIBYTE(u16), RT_LOBYTE(u16)) + +/** @def RT_BSWAP_S64_C + * Reverses the byte order of an int64_t constant. */ +#define RT_BSWAP_S64_C(i64) ((int64_t)RT_MAKE_U64(RT_BSWAP_U32_C((uint64_t)(i64) >> 32), RT_BSWAP_U32_C((uint32_t)(i64)))) + +/** @def RT_BSWAP_S32_C + * Reverses the byte order of an int32_t constant. */ +#define RT_BSWAP_S32_C(i32) ((int32_t)RT_MAKE_U32_FROM_U8(RT_BYTE4(i32), RT_BYTE3(i32), RT_BYTE2(i32), RT_BYTE1(i))) + +/** @def RT_BSWAP_S16_C + * Reverses the byte order of an uint16_t constant. */ +#define RT_BSWAP_S16_C(i16) ((int16_t)RT_MAKE_U16(RT_HIBYTE(i16), RT_LOBYTE(i16))) + + + +/** @name Host to/from little endian. + * @note Typically requires iprt/asm.h to be included. + * @{ */ + +/** @def RT_H2LE_U64 + * Converts an uint64_t value from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_U64(u64) RT_BSWAP_U64(u64) +#else +# define RT_H2LE_U64(u64) (u64) +#endif + +/** @def RT_H2LE_U64_C + * Converts an uint64_t constant from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_U64_C(u64) RT_BSWAP_U64_C(u64) +#else +# define RT_H2LE_U64_C(u64) (u64) +#endif + +/** @def RT_H2LE_U32 + * Converts an uint32_t value from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_U32(u32) RT_BSWAP_U32(u32) +#else +# define RT_H2LE_U32(u32) (u32) +#endif + +/** @def RT_H2LE_U32_C + * Converts an uint32_t constant from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_U32_C(u32) RT_BSWAP_U32_C(u32) +#else +# define RT_H2LE_U32_C(u32) (u32) +#endif + +/** @def RT_H2LE_U16 + * Converts an uint16_t value from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_U16(u16) RT_BSWAP_U16(u16) +#else +# define RT_H2LE_U16(u16) (u16) +#endif + +/** @def RT_H2LE_U16_C + * Converts an uint16_t constant from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_U16_C(u16) RT_BSWAP_U16_C(u16) +#else +# define RT_H2LE_U16_C(u16) (u16) +#endif + + +/** @def RT_LE2H_U64 + * Converts an uint64_t value from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_U64(u64) RT_BSWAP_U64(u64) +#else +# define RT_LE2H_U64(u64) (u64) +#endif + +/** @def RT_LE2H_U64_C + * Converts an uint64_t constant from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_U64_C(u64) RT_BSWAP_U64_C(u64) +#else +# define RT_LE2H_U64_C(u64) (u64) +#endif + +/** @def RT_LE2H_U32 + * Converts an uint32_t value from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_U32(u32) RT_BSWAP_U32(u32) +#else +# define RT_LE2H_U32(u32) (u32) +#endif + +/** @def RT_LE2H_U32_C + * Converts an uint32_t constant from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_U32_C(u32) RT_BSWAP_U32_C(u32) +#else +# define RT_LE2H_U32_C(u32) (u32) +#endif + +/** @def RT_LE2H_U16 + * Converts an uint16_t value from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_U16(u16) RT_BSWAP_U16(u16) +#else +# define RT_LE2H_U16(u16) (u16) +#endif + +/** @def RT_LE2H_U16_C + * Converts an uint16_t constant from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_U16_C(u16) RT_BSWAP_U16_C(u16) +#else +# define RT_LE2H_U16_C(u16) (u16) +#endif + +/** @def RT_H2LE_S64 + * Converts an int64_t value from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_S64(i64) RT_BSWAP_S64(i64) +#else +# define RT_H2LE_S64(i64) (i64) +#endif + +/** @def RT_H2LE_S64_C + * Converts an int64_t constant from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_S64_C(i64) RT_BSWAP_S64_C(i64) +#else +# define RT_H2LE_S64_C(i64) (i64) +#endif + +/** @def RT_H2LE_S32 + * Converts an int32_t value from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_S32(i32) RT_BSWAP_S32(i32) +#else +# define RT_H2LE_S32(i32) (i32) +#endif + +/** @def RT_H2LE_S32_C + * Converts an int32_t constant from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_S32_C(i32) RT_BSWAP_S32_C(i32) +#else +# define RT_H2LE_S32_C(i32) (i32) +#endif + +/** @def RT_H2LE_S16 + * Converts an int16_t value from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_S16(i16) RT_BSWAP_S16(i16) +#else +# define RT_H2LE_S16(i16) (i16) +#endif + +/** @def RT_H2LE_S16_C + * Converts an int16_t constant from host to little endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2LE_S16_C(i16) RT_BSWAP_S16_C(i16) +#else +# define RT_H2LE_S16_C(i16) (i16) +#endif + +/** @def RT_LE2H_S64 + * Converts an int64_t value from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_S64(i64) RT_BSWAP_S64(i64) +#else +# define RT_LE2H_S64(i64) (i64) +#endif + +/** @def RT_LE2H_S64_C + * Converts an int64_t constant from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_S64_C(i64) RT_BSWAP_S64_C(i64) +#else +# define RT_LE2H_S64_C(i64) (i64) +#endif + +/** @def RT_LE2H_S32 + * Converts an int32_t value from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_S32(i32) RT_BSWAP_S32(i32) +#else +# define RT_LE2H_S32(i32) (i32) +#endif + +/** @def RT_LE2H_S32_C + * Converts an int32_t constant from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_S32_C(i32) RT_BSWAP_S32_C(i32) +#else +# define RT_LE2H_S32_C(i32) (i32) +#endif + +/** @def RT_LE2H_S16 + * Converts an int16_t value from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_S16(i16) RT_BSWAP_S16(i16) +#else +# define RT_LE2H_S16(i16) (i16) +#endif + +/** @def RT_LE2H_S16_C + * Converts an int16_t constant from little endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_LE2H_S16_C(i16) RT_BSWAP_S16_C(i16) +#else +# define RT_LE2H_S16_C(i16) (i16) +#endif + +/** @} */ + +/** @name Host to/from big endian. + * @note Typically requires iprt/asm.h to be included. + * @{ */ + +/** @def RT_H2BE_U64 + * Converts an uint64_t value from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_U64(u64) (u64) +#else +# define RT_H2BE_U64(u64) RT_BSWAP_U64(u64) +#endif + +/** @def RT_H2BE_U64_C + * Converts an uint64_t constant from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_U64_C(u64) (u64) +#else +# define RT_H2BE_U64_C(u64) RT_BSWAP_U64_C(u64) +#endif + +/** @def RT_H2BE_U32 + * Converts an uint32_t value from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_U32(u32) (u32) +#else +# define RT_H2BE_U32(u32) RT_BSWAP_U32(u32) +#endif + +/** @def RT_H2BE_U32_C + * Converts an uint32_t constant from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_U32_C(u32) (u32) +#else +# define RT_H2BE_U32_C(u32) RT_BSWAP_U32_C(u32) +#endif + +/** @def RT_H2BE_U16 + * Converts an uint16_t value from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_U16(u16) (u16) +#else +# define RT_H2BE_U16(u16) RT_BSWAP_U16(u16) +#endif + +/** @def RT_H2BE_U16_C + * Converts an uint16_t constant from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_U16_C(u16) (u16) +#else +# define RT_H2BE_U16_C(u16) RT_BSWAP_U16_C(u16) +#endif + +/** @def RT_BE2H_U64 + * Converts an uint64_t value from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_U64(u64) (u64) +#else +# define RT_BE2H_U64(u64) RT_BSWAP_U64(u64) +#endif + +/** @def RT_BE2H_U64 + * Converts an uint64_t constant from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_U64_C(u64) (u64) +#else +# define RT_BE2H_U64_C(u64) RT_BSWAP_U64_C(u64) +#endif + +/** @def RT_BE2H_U32 + * Converts an uint32_t value from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_U32(u32) (u32) +#else +# define RT_BE2H_U32(u32) RT_BSWAP_U32(u32) +#endif + +/** @def RT_BE2H_U32_C + * Converts an uint32_t value from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_U32_C(u32) (u32) +#else +# define RT_BE2H_U32_C(u32) RT_BSWAP_U32_C(u32) +#endif + +/** @def RT_BE2H_U16 + * Converts an uint16_t value from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_U16(u16) (u16) +#else +# define RT_BE2H_U16(u16) RT_BSWAP_U16(u16) +#endif + +/** @def RT_BE2H_U16_C + * Converts an uint16_t constant from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_U16_C(u16) (u16) +#else +# define RT_BE2H_U16_C(u16) RT_BSWAP_U16_C(u16) +#endif + +/** @def RT_H2BE_S64 + * Converts an int64_t value from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_S64(i64) (i64) +#else +# define RT_H2BE_S64(i64) RT_BSWAP_S64(i64) +#endif + +/** @def RT_H2BE_S64_C + * Converts an int64_t constant from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_S64_C(i64) (i64) +#else +# define RT_H2BE_S64_C(i64) RT_BSWAP_S64_C(i64) +#endif + +/** @def RT_H2BE_S32 + * Converts an int32_t value from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_S32(i32) (i32) +#else +# define RT_H2BE_S32(i32) RT_BSWAP_S32(i32) +#endif + +/** @def RT_H2BE_S32_C + * Converts an int32_t constant from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_S32_C(i32) (i32) +#else +# define RT_H2BE_S32_C(i32) RT_BSWAP_S32_C(i32) +#endif + +/** @def RT_H2BE_S16 + * Converts an int16_t value from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_S16(i16) (i16) +#else +# define RT_H2BE_S16(i16) RT_BSWAP_S16(i16) +#endif + +/** @def RT_H2BE_S16_C + * Converts an int16_t constant from host to big endian byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_H2BE_S16_C(i16) (i16) +#else +# define RT_H2BE_S16_C(i16) RT_BSWAP_S16_C(i16) +#endif + +/** @def RT_BE2H_S64 + * Converts an int64_t value from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_S64(i64) (i64) +#else +# define RT_BE2H_S64(i64) RT_BSWAP_S64(i64) +#endif + +/** @def RT_BE2H_S64 + * Converts an int64_t constant from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_S64_C(i64) (i64) +#else +# define RT_BE2H_S64_C(i64) RT_BSWAP_S64_C(i64) +#endif + +/** @def RT_BE2H_S32 + * Converts an int32_t value from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_S32(i32) (i32) +#else +# define RT_BE2H_S32(i32) RT_BSWAP_S32(i32) +#endif + +/** @def RT_BE2H_S32_C + * Converts an int32_t value from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_S32_C(i32) (i32) +#else +# define RT_BE2H_S32_C(i32) RT_BSWAP_S32_C(i32) +#endif + +/** @def RT_BE2H_S16 + * Converts an int16_t value from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_S16(i16) (i16) +#else +# define RT_BE2H_S16(i16) RT_BSWAP_S16(i16) +#endif + +/** @def RT_BE2H_S16_C + * Converts an int16_t constant from big endian to host byte order. */ +#ifdef RT_BIG_ENDIAN +# define RT_BE2H_S16_C(i16) (i16) +#else +# define RT_BE2H_S16_C(i16) RT_BSWAP_S16_C(i16) +#endif +/** @} */ + +/** @name Host to/from network byte order. + * @note Typically requires iprt/asm.h to be included. + * @{ */ + +/** @def RT_H2N_U64 + * Converts an uint64_t value from host to network byte order. */ +#define RT_H2N_U64(u64) RT_H2BE_U64(u64) + +/** @def RT_H2N_U64_C + * Converts an uint64_t constant from host to network byte order. */ +#define RT_H2N_U64_C(u64) RT_H2BE_U64_C(u64) + +/** @def RT_H2N_U32 + * Converts an uint32_t value from host to network byte order. */ +#define RT_H2N_U32(u32) RT_H2BE_U32(u32) + +/** @def RT_H2N_U32_C + * Converts an uint32_t constant from host to network byte order. */ +#define RT_H2N_U32_C(u32) RT_H2BE_U32_C(u32) + +/** @def RT_H2N_U16 + * Converts an uint16_t value from host to network byte order. */ +#define RT_H2N_U16(u16) RT_H2BE_U16(u16) + +/** @def RT_H2N_U16_C + * Converts an uint16_t constant from host to network byte order. */ +#define RT_H2N_U16_C(u16) RT_H2BE_U16_C(u16) + +/** @def RT_N2H_U64 + * Converts an uint64_t value from network to host byte order. */ +#define RT_N2H_U64(u64) RT_BE2H_U64(u64) + +/** @def RT_N2H_U64_C + * Converts an uint64_t constant from network to host byte order. */ +#define RT_N2H_U64_C(u64) RT_BE2H_U64_C(u64) + +/** @def RT_N2H_U32 + * Converts an uint32_t value from network to host byte order. */ +#define RT_N2H_U32(u32) RT_BE2H_U32(u32) + +/** @def RT_N2H_U32_C + * Converts an uint32_t constant from network to host byte order. */ +#define RT_N2H_U32_C(u32) RT_BE2H_U32_C(u32) + +/** @def RT_N2H_U16 + * Converts an uint16_t value from network to host byte order. */ +#define RT_N2H_U16(u16) RT_BE2H_U16(u16) + +/** @def RT_N2H_U16_C + * Converts an uint16_t value from network to host byte order. */ +#define RT_N2H_U16_C(u16) RT_BE2H_U16_C(u16) + +/** @def RT_H2N_S64 + * Converts an int64_t value from host to network byte order. */ +#define RT_H2N_S64(i64) RT_H2BE_S64(i64) + +/** @def RT_H2N_S64_C + * Converts an int64_t constant from host to network byte order. */ +#define RT_H2N_S64_C(i64) RT_H2BE_S64_C(i64) + +/** @def RT_H2N_S32 + * Converts an int32_t value from host to network byte order. */ +#define RT_H2N_S32(i32) RT_H2BE_S32(i32) + +/** @def RT_H2N_S32_C + * Converts an int32_t constant from host to network byte order. */ +#define RT_H2N_S32_C(i32) RT_H2BE_S32_C(i32) + +/** @def RT_H2N_S16 + * Converts an int16_t value from host to network byte order. */ +#define RT_H2N_S16(i16) RT_H2BE_S16(i16) + +/** @def RT_H2N_S16_C + * Converts an int16_t constant from host to network byte order. */ +#define RT_H2N_S16_C(i16) RT_H2BE_S16_C(i16) + +/** @def RT_N2H_S64 + * Converts an int64_t value from network to host byte order. */ +#define RT_N2H_S64(i64) RT_BE2H_S64(i64) + +/** @def RT_N2H_S64_C + * Converts an int64_t constant from network to host byte order. */ +#define RT_N2H_S64_C(i64) RT_BE2H_S64_C(i64) + +/** @def RT_N2H_S32 + * Converts an int32_t value from network to host byte order. */ +#define RT_N2H_S32(i32) RT_BE2H_S32(i32) + +/** @def RT_N2H_S32_C + * Converts an int32_t constant from network to host byte order. */ +#define RT_N2H_S32_C(i32) RT_BE2H_S32_C(i32) + +/** @def RT_N2H_S16 + * Converts an int16_t value from network to host byte order. */ +#define RT_N2H_S16(i16) RT_BE2H_S16(i16) + +/** @def RT_N2H_S16_C + * Converts an int16_t value from network to host byte order. */ +#define RT_N2H_S16_C(i16) RT_BE2H_S16_C(i16) + +/** @} */ + + +/* + * The BSD sys/param.h + machine/param.h file is a major source of + * namespace pollution. Kill off some of the worse ones unless we're + * compiling kernel code. + */ +#if defined(RT_OS_DARWIN) \ + && !defined(KERNEL) \ + && !defined(RT_NO_BSD_PARAM_H_UNDEFING) \ + && ( defined(_SYS_PARAM_H_) || defined(_I386_PARAM_H_) ) +/* sys/param.h: */ +# undef PSWP +# undef PVM +# undef PINOD +# undef PRIBO +# undef PVFS +# undef PZERO +# undef PSOCK +# undef PWAIT +# undef PLOCK +# undef PPAUSE +# undef PUSER +# undef PRIMASK +# undef MINBUCKET +# undef MAXALLOCSAVE +# undef FSHIFT +# undef FSCALE + +/* i386/machine.h: */ +# undef ALIGN +# undef ALIGNBYTES +# undef DELAY +# undef STATUS_WORD +# undef USERMODE +# undef BASEPRI +# undef MSIZE +# undef CLSIZE +# undef CLSIZELOG2 +#endif + +/** @def NIL_OFFSET + * NIL offset. + * Whenever we use offsets instead of pointers to save space and relocation effort + * NIL_OFFSET shall be used as the equivalent to NULL. + */ +#define NIL_OFFSET (~0U) + + +/** @def NOREF + * Keeps the compiler from bitching about an unused parameter, local variable, + * or other stuff, will never use _Pragma are is thus more flexible. + */ +#define NOREF(var) (void)(var) + +/** @def RT_NOREF_PV + * Keeps the compiler from bitching about an unused parameter or local variable. + * This one cannot be used with structure members and such, like for instance + * AssertRC may end up doing due to its generic nature. + */ +#if defined(__cplusplus) && RT_CLANG_PREREQ(6, 0) +# define RT_NOREF_PV(var) _Pragma(RT_STR(unused(var))) +#else +# define RT_NOREF_PV(var) (void)(var) +#endif + +/** @def RT_NOREF1 + * RT_NOREF_PV shorthand taking on parameter. */ +#define RT_NOREF1(var1) RT_NOREF_PV(var1) +/** @def RT_NOREF2 + * RT_NOREF_PV shorthand taking two parameters. */ +#define RT_NOREF2(var1, var2) RT_NOREF_PV(var1); RT_NOREF1(var2) +/** @def RT_NOREF3 + * RT_NOREF_PV shorthand taking three parameters. */ +#define RT_NOREF3(var1, var2, var3) RT_NOREF_PV(var1); RT_NOREF2(var2, var3) +/** @def RT_NOREF4 + * RT_NOREF_PV shorthand taking four parameters. */ +#define RT_NOREF4(var1, var2, var3, var4) RT_NOREF_PV(var1); RT_NOREF3(var2, var3, var4) +/** @def RT_NOREF5 + * RT_NOREF_PV shorthand taking five parameters. */ +#define RT_NOREF5(var1, var2, var3, var4, var5) RT_NOREF_PV(var1); RT_NOREF4(var2, var3, var4, var5) +/** @def RT_NOREF6 + * RT_NOREF_PV shorthand taking six parameters. */ +#define RT_NOREF6(var1, var2, var3, var4, var5, var6) RT_NOREF_PV(var1); RT_NOREF5(var2, var3, var4, var5, var6) +/** @def RT_NOREF7 + * RT_NOREF_PV shorthand taking seven parameters. */ +#define RT_NOREF7(var1, var2, var3, var4, var5, var6, var7) \ + RT_NOREF_PV(var1); RT_NOREF6(var2, var3, var4, var5, var6, var7) +/** @def RT_NOREF8 + * RT_NOREF_PV shorthand taking eight parameters. */ +#define RT_NOREF8(var1, var2, var3, var4, var5, var6, var7, var8) \ + RT_NOREF_PV(var1); RT_NOREF7(var2, var3, var4, var5, var6, var7, var8) +/** @def RT_NOREF9 + * RT_NOREF_PV shorthand taking nine parameters. */ +#define RT_NOREF9(var1, var2, var3, var4, var5, var6, var7, var8, var9) \ + RT_NOREF_PV(var1); RT_NOREF8(var2, var3, var4, var5, var6, var7, var8, var9) +/** @def RT_NOREF10 + * RT_NOREF_PV shorthand taking ten parameters. */ +#define RT_NOREF10(var1, var2, var3, var4, var5, var6, var7, var8, var9, var10) \ + RT_NOREF_PV(var1); RT_NOREF_PV(var2); RT_NOREF_PV(var3); RT_NOREF_PV(var4); RT_NOREF_PV(var5); RT_NOREF_PV(var6); \ + RT_NOREF_PV(var7); RT_NOREF_PV(var8); RT_NOREF_PV(var9); RT_NOREF_PV(var10) +/** @def RT_NOREF11 + * RT_NOREF_PV shorthand taking eleven parameters. */ +#define RT_NOREF11(var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11) \ + RT_NOREF_PV(var1); RT_NOREF10(var2, var3, var4, var5, var6, var7, var8, var9, var10, var11) +/** @def RT_NOREF12 + * RT_NOREF_PV shorthand taking twelve parameters. */ +#define RT_NOREF12(var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12) \ + RT_NOREF_PV(var1); RT_NOREF11(var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12) +/** @def RT_NOREF13 + * RT_NOREF_PV shorthand taking thirteen parameters. */ +#define RT_NOREF13(var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13) \ + RT_NOREF_PV(var1); RT_NOREF12(var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13) +/** @def RT_NOREF14 + * RT_NOREF_PV shorthand taking fourteen parameters. */ +#define RT_NOREF14(var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14) \ + RT_NOREF_PV(var1); RT_NOREF13(var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14) +/** @def RT_NOREF15 + * RT_NOREF_PV shorthand taking fifteen parameters. */ +#define RT_NOREF15(var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14, var15) \ + RT_NOREF_PV(var1); RT_NOREF14(var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14, var15) +/** @def RT_NOREF16 + * RT_NOREF_PV shorthand taking fifteen parameters. */ +#define RT_NOREF16(var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14, var15, var16) \ + RT_NOREF_PV(var1); RT_NOREF15(var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14, var15, var16) +/** @def RT_NOREF17 + * RT_NOREF_PV shorthand taking seventeen parameters. */ +#define RT_NOREF17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) \ + RT_NOREF_PV(v1); RT_NOREF16(v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +/** @def RT_NOREF18 + * RT_NOREF_PV shorthand taking eighteen parameters. */ +#define RT_NOREF18(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) \ + RT_NOREF_PV(v1); RT_NOREF17(v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +/** @def RT_NOREF19 + * RT_NOREF_PV shorthand taking nineteen parameters. */ +#define RT_NOREF19(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) \ + RT_NOREF_PV(v1); RT_NOREF18(v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +/** @def RT_NOREF20 + * RT_NOREF_PV shorthand taking twenty parameters. */ +#define RT_NOREF20(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) \ + RT_NOREF_PV(v1); RT_NOREF19(v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +/** @def RT_NOREF21 + * RT_NOREF_PV shorthand taking twentyone parameters. */ +#define RT_NOREF21(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) \ + RT_NOREF_PV(v1); RT_NOREF20(v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +/** @def RT_NOREF22 + * RT_NOREF_PV shorthand taking twentytwo parameters. */ +#define RT_NOREF22(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) \ + RT_NOREF_PV(v1); RT_NOREF21(v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) + +/** @def RT_NOREF + * RT_NOREF_PV variant using the variadic macro feature of C99. + * @remarks Only use this in sources */ +#ifdef RT_COMPILER_SUPPORTS_VA_ARGS +# define RT_NOREF(...) \ + RT_UNPACK_CALL(RT_CONCAT(RT_NOREF, RT_EXPAND(RT_COUNT_VA_ARGS(__VA_ARGS__))),(__VA_ARGS__)) +#endif + + +/** @def RT_BREAKPOINT + * Emit a debug breakpoint instruction. + * + * @remarks In the x86/amd64 gnu world we add a nop instruction after the int3 + * to force gdb to remain at the int3 source line. + * @remarks The L4 kernel will try make sense of the breakpoint, thus the jmp on + * x86/amd64. + */ +#ifdef __GNUC__ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# if !defined(__L4ENV__) +# define RT_BREAKPOINT() __asm__ __volatile__("int $3\n\tnop\n\t") +# else +# define RT_BREAKPOINT() __asm__ __volatile__("int3; jmp 1f; 1:\n\t") +# endif +# elif defined(RT_ARCH_SPARC64) +# define RT_BREAKPOINT() __asm__ __volatile__("illtrap 0\n\t") /** @todo Sparc64: this is just a wild guess. */ +# elif defined(RT_ARCH_SPARC) +# define RT_BREAKPOINT() __asm__ __volatile__("unimp 0\n\t") /** @todo Sparc: this is just a wild guess (same as Sparc64, just different name). */ +# elif defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) +# define RT_BREAKPOINT() __asm__ __volatile__("brk #0x1\n\t") +# endif +#endif +#ifdef _MSC_VER +# define RT_BREAKPOINT() __debugbreak() +#endif +#if defined(__IBMC__) || defined(__IBMCPP__) +# define RT_BREAKPOINT() __interrupt(3) +#endif +#if defined(__WATCOMC__) +# define RT_BREAKPOINT() _asm { int 3 } +#endif +#ifndef RT_BREAKPOINT +# error "This compiler/arch is not supported!" +#endif + + +/** @defgroup grp_rt_cdefs_size Size Constants + * (Of course, these are binary computer terms, not SI.) + * @{ + */ +/** 1 K (Kilo) (1 024). */ +#define _1K 0x00000400 +/** 2 K (Kilo) (2 048). */ +#define _2K 0x00000800 +/** 4 K (Kilo) (4 096). */ +#define _4K 0x00001000 +/** 8 K (Kilo) (8 192). */ +#define _8K 0x00002000 +/** 16 K (Kilo) (16 384). */ +#define _16K 0x00004000 +/** 32 K (Kilo) (32 768). */ +#define _32K 0x00008000 +/** 64 K (Kilo) (65 536). */ +#if ARCH_BITS != 16 +# define _64K 0x00010000 +#else +# define _64K UINT32_C(0x00010000) +#endif +/** 128 K (Kilo) (131 072). */ +#if ARCH_BITS != 16 +# define _128K 0x00020000 +#else +# define _128K UINT32_C(0x00020000) +#endif +/** 256 K (Kilo) (262 144). */ +#if ARCH_BITS != 16 +# define _256K 0x00040000 +#else +# define _256K UINT32_C(0x00040000) +#endif +/** 512 K (Kilo) (524 288). */ +#if ARCH_BITS != 16 +# define _512K 0x00080000 +#else +# define _512K UINT32_C(0x00080000) +#endif +/** 1 M (Mega) (1 048 576). */ +#if ARCH_BITS != 16 +# define _1M 0x00100000 +#else +# define _1M UINT32_C(0x00100000) +#endif +/** 2 M (Mega) (2 097 152). */ +#if ARCH_BITS != 16 +# define _2M 0x00200000 +#else +# define _2M UINT32_C(0x00200000) +#endif +/** 4 M (Mega) (4 194 304). */ +#if ARCH_BITS != 16 +# define _4M 0x00400000 +#else +# define _4M UINT32_C(0x00400000) +#endif +/** 8 M (Mega) (8 388 608). */ +#define _8M UINT32_C(0x00800000) +/** 16 M (Mega) (16 777 216). */ +#define _16M UINT32_C(0x01000000) +/** 32 M (Mega) (33 554 432). */ +#define _32M UINT32_C(0x02000000) +/** 64 M (Mega) (67 108 864). */ +#define _64M UINT32_C(0x04000000) +/** 128 M (Mega) (134 217 728). */ +#define _128M UINT32_C(0x08000000) +/** 256 M (Mega) (268 435 456). */ +#define _256M UINT32_C(0x10000000) +/** 512 M (Mega) (536 870 912). */ +#define _512M UINT32_C(0x20000000) +/** 1 G (Giga) (1 073 741 824). (32-bit) */ +#if ARCH_BITS != 16 +# define _1G 0x40000000 +#else +# define _1G UINT32_C(0x40000000) +#endif +/** 1 G (Giga) (1 073 741 824). (64-bit) */ +#if ARCH_BITS != 16 +# define _1G64 0x40000000LL +#else +# define _1G64 UINT64_C(0x40000000) +#endif +/** 2 G (Giga) (2 147 483 648). (32-bit) */ +#define _2G32 UINT32_C(0x80000000) +/** 2 G (Giga) (2 147 483 648). (64-bit) */ +#if ARCH_BITS != 16 +# define _2G 0x0000000080000000LL +#else +# define _2G UINT64_C(0x0000000080000000) +#endif +/** 4 G (Giga) (4 294 967 296). */ +#if ARCH_BITS != 16 +# define _4G 0x0000000100000000LL +#else +# define _4G UINT64_C(0x0000000100000000) +#endif +/** 1 T (Tera) (1 099 511 627 776). */ +#if ARCH_BITS != 16 +# define _1T 0x0000010000000000LL +#else +# define _1T UINT64_C(0x0000010000000000) +#endif +/** 1 P (Peta) (1 125 899 906 842 624). */ +#if ARCH_BITS != 16 +# define _1P 0x0004000000000000LL +#else +# define _1P UINT64_C(0x0004000000000000) +#endif +/** 1 E (Exa) (1 152 921 504 606 846 976). */ +#if ARCH_BITS != 16 +# define _1E 0x1000000000000000LL +#else +# define _1E UINT64_C(0x1000000000000000) +#endif +/** 2 E (Exa) (2 305 843 009 213 693 952). */ +#if ARCH_BITS != 16 +# define _2E 0x2000000000000000ULL +#else +# define _2E UINT64_C(0x2000000000000000) +#endif +/** @} */ + +/** @defgroup grp_rt_cdefs_decimal_grouping Decimal Constant Grouping Macros + * @{ */ +#define RT_D1(g1) g1 +#define RT_D2(g1, g2) g1#g2 +#define RT_D3(g1, g2, g3) g1#g2#g3 +#define RT_D4(g1, g2, g3, g4) g1#g2#g3#g4 +#define RT_D5(g1, g2, g3, g4, g5) g1#g2#g3#g4#g5 +#define RT_D6(g1, g2, g3, g4, g5, g6) g1#g2#g3#g4#g5#g6 +#define RT_D7(g1, g2, g3, g4, g5, g6, g7) g1#g2#g3#g4#g5#g6#g7 + +#define RT_D1_U(g1) UINT32_C(g1) +#define RT_D2_U(g1, g2) UINT32_C(g1#g2) +#define RT_D3_U(g1, g2, g3) UINT32_C(g1#g2#g3) +#define RT_D4_U(g1, g2, g3, g4) UINT64_C(g1#g2#g3#g4) +#define RT_D5_U(g1, g2, g3, g4, g5) UINT64_C(g1#g2#g3#g4#g5) +#define RT_D6_U(g1, g2, g3, g4, g5, g6) UINT64_C(g1#g2#g3#g4#g5#g6) +#define RT_D7_U(g1, g2, g3, g4, g5, g6, g7) UINT64_C(g1#g2#g3#g4#g5#g6#g7) + +#define RT_D1_S(g1) INT32_C(g1) +#define RT_D2_S(g1, g2) INT32_C(g1#g2) +#define RT_D3_S(g1, g2, g3) INT32_C(g1#g2#g3) +#define RT_D4_S(g1, g2, g3, g4) INT64_C(g1#g2#g3#g4) +#define RT_D5_S(g1, g2, g3, g4, g5) INT64_C(g1#g2#g3#g4#g5) +#define RT_D6_S(g1, g2, g3, g4, g5, g6) INT64_C(g1#g2#g3#g4#g5#g6) +#define RT_D7_S(g1, g2, g3, g4, g5, g6, g7) INT64_C(g1#g2#g3#g4#g5#g6#g7) + +#define RT_D1_U32(g1) UINT32_C(g1) +#define RT_D2_U32(g1, g2) UINT32_C(g1#g2) +#define RT_D3_U32(g1, g2, g3) UINT32_C(g1#g2#g3) +#define RT_D4_U32(g1, g2, g3, g4) UINT32_C(g1#g2#g3#g4) + +#define RT_D1_S32(g1) INT32_C(g1) +#define RT_D2_S32(g1, g2) INT32_C(g1#g2) +#define RT_D3_S32(g1, g2, g3) INT32_C(g1#g2#g3) +#define RT_D4_S32(g1, g2, g3, g4) INT32_C(g1#g2#g3#g4) + +#define RT_D1_U64(g1) UINT64_C(g1) +#define RT_D2_U64(g1, g2) UINT64_C(g1#g2) +#define RT_D3_U64(g1, g2, g3) UINT64_C(g1#g2#g3) +#define RT_D4_U64(g1, g2, g3, g4) UINT64_C(g1#g2#g3#g4) +#define RT_D5_U64(g1, g2, g3, g4, g5) UINT64_C(g1#g2#g3#g4#g5) +#define RT_D6_U64(g1, g2, g3, g4, g5, g6) UINT64_C(g1#g2#g3#g4#g5#g6) +#define RT_D7_U64(g1, g2, g3, g4, g5, g6, g7) UINT64_C(g1#g2#g3#g4#g5#g6#g7) + +#define RT_D1_S64(g1) INT64_C(g1) +#define RT_D2_S64(g1, g2) INT64_C(g1#g2) +#define RT_D3_S64(g1, g2, g3) INT64_C(g1#g2#g3) +#define RT_D4_S64(g1, g2, g3, g4) INT64_C(g1#g2#g3#g4) +#define RT_D5_S64(g1, g2, g3, g4, g5) INT64_C(g1#g2#g3#g4#g5) +#define RT_D6_S64(g1, g2, g3, g4, g5, g6) INT64_C(g1#g2#g3#g4#g5#g6) +#define RT_D7_S64(g1, g2, g3, g4, g5, g6, g7) INT64_C(g1#g2#g3#g4#g5#g6#g7) +/** @} */ + + +/** @defgroup grp_rt_cdefs_time Time Constants + * @{ + */ +/** 1 week expressed in nanoseconds (64-bit). */ +#define RT_NS_1WEEK UINT64_C(604800000000000) +/** 1 day expressed in nanoseconds (64-bit). */ +#define RT_NS_1DAY UINT64_C(86400000000000) +/** 1 hour expressed in nanoseconds (64-bit). */ +#define RT_NS_1HOUR UINT64_C(3600000000000) +/** 30 minutes expressed in nanoseconds (64-bit). */ +#define RT_NS_30MIN UINT64_C(1800000000000) +/** 5 minutes expressed in nanoseconds (64-bit). */ +#define RT_NS_5MIN UINT64_C(300000000000) +/** 1 minute expressed in nanoseconds (64-bit). */ +#define RT_NS_1MIN UINT64_C(60000000000) +/** 45 seconds expressed in nanoseconds (64-bit). */ +#define RT_NS_45SEC UINT64_C(45000000000) +/** 30 seconds expressed in nanoseconds (64-bit). */ +#define RT_NS_30SEC UINT64_C(30000000000) +/** 20 seconds expressed in nanoseconds (64-bit). */ +#define RT_NS_20SEC UINT64_C(20000000000) +/** 15 seconds expressed in nanoseconds (64-bit). */ +#define RT_NS_15SEC UINT64_C(15000000000) +/** 10 seconds expressed in nanoseconds (64-bit). */ +#define RT_NS_10SEC UINT64_C(10000000000) +/** 1 second expressed in nanoseconds. */ +#define RT_NS_1SEC UINT32_C(1000000000) +/** 100 millsecond expressed in nanoseconds. */ +#define RT_NS_100MS UINT32_C(100000000) +/** 10 millsecond expressed in nanoseconds. */ +#define RT_NS_10MS UINT32_C(10000000) +/** 8 millsecond expressed in nanoseconds. */ +#define RT_NS_8MS UINT32_C(8000000) +/** 2 millsecond expressed in nanoseconds. */ +#define RT_NS_2MS UINT32_C(2000000) +/** 1 millsecond expressed in nanoseconds. */ +#define RT_NS_1MS UINT32_C(1000000) +/** 100 microseconds expressed in nanoseconds. */ +#define RT_NS_100US UINT32_C(100000) +/** 10 microseconds expressed in nanoseconds. */ +#define RT_NS_10US UINT32_C(10000) +/** 1 microsecond expressed in nanoseconds. */ +#define RT_NS_1US UINT32_C(1000) + +/** 1 second expressed in nanoseconds - 64-bit type. */ +#define RT_NS_1SEC_64 UINT64_C(1000000000) +/** 100 millsecond expressed in nanoseconds - 64-bit type. */ +#define RT_NS_100MS_64 UINT64_C(100000000) +/** 10 millsecond expressed in nanoseconds - 64-bit type. */ +#define RT_NS_10MS_64 UINT64_C(10000000) +/** 1 millsecond expressed in nanoseconds - 64-bit type. */ +#define RT_NS_1MS_64 UINT64_C(1000000) +/** 100 microseconds expressed in nanoseconds - 64-bit type. */ +#define RT_NS_100US_64 UINT64_C(100000) +/** 10 microseconds expressed in nanoseconds - 64-bit type. */ +#define RT_NS_10US_64 UINT64_C(10000) +/** 1 microsecond expressed in nanoseconds - 64-bit type. */ +#define RT_NS_1US_64 UINT64_C(1000) + +/** 1 week expressed in microseconds (64-bit). */ +#define RT_US_1WEEK UINT64_C(604800000000) +/** 1 day expressed in microseconds (64-bit). */ +#define RT_US_1DAY UINT64_C(86400000000) +/** 1 hour expressed in microseconds. */ +#define RT_US_1HOUR UINT32_C(3600000000) +/** 30 minutes expressed in microseconds. */ +#define RT_US_30MIN UINT32_C(1800000000) +/** 5 minutes expressed in microseconds. */ +#define RT_US_5MIN UINT32_C(300000000) +/** 1 minute expressed in microseconds. */ +#define RT_US_1MIN UINT32_C(60000000) +/** 45 seconds expressed in microseconds. */ +#define RT_US_45SEC UINT32_C(45000000) +/** 30 seconds expressed in microseconds. */ +#define RT_US_30SEC UINT32_C(30000000) +/** 20 seconds expressed in microseconds. */ +#define RT_US_20SEC UINT32_C(20000000) +/** 15 seconds expressed in microseconds. */ +#define RT_US_15SEC UINT32_C(15000000) +/** 10 seconds expressed in microseconds. */ +#define RT_US_10SEC UINT32_C(10000000) +/** 5 seconds expressed in microseconds. */ +#define RT_US_5SEC UINT32_C(5000000) +/** 1 second expressed in microseconds. */ +#define RT_US_1SEC UINT32_C(1000000) +/** 100 millsecond expressed in microseconds. */ +#define RT_US_100MS UINT32_C(100000) +/** 10 millsecond expressed in microseconds. */ +#define RT_US_10MS UINT32_C(10000) +/** 1 millsecond expressed in microseconds. */ +#define RT_US_1MS UINT32_C(1000) + +/** 1 hour expressed in microseconds - 64-bit type. */ +#define RT_US_1HOUR_64 UINT64_C(3600000000) +/** 30 minutes expressed in microseconds - 64-bit type. */ +#define RT_US_30MIN_64 UINT64_C(1800000000) +/** 5 minutes expressed in microseconds - 64-bit type. */ +#define RT_US_5MIN_64 UINT64_C(300000000) +/** 1 minute expressed in microseconds - 64-bit type. */ +#define RT_US_1MIN_64 UINT64_C(60000000) +/** 45 seconds expressed in microseconds - 64-bit type. */ +#define RT_US_45SEC_64 UINT64_C(45000000) +/** 30 seconds expressed in microseconds - 64-bit type. */ +#define RT_US_30SEC_64 UINT64_C(30000000) +/** 20 seconds expressed in microseconds - 64-bit type. */ +#define RT_US_20SEC_64 UINT64_C(20000000) +/** 15 seconds expressed in microseconds - 64-bit type. */ +#define RT_US_15SEC_64 UINT64_C(15000000) +/** 10 seconds expressed in microseconds - 64-bit type. */ +#define RT_US_10SEC_64 UINT64_C(10000000) +/** 5 seconds expressed in microseconds - 64-bit type. */ +#define RT_US_5SEC_64 UINT64_C(5000000) +/** 1 second expressed in microseconds - 64-bit type. */ +#define RT_US_1SEC_64 UINT64_C(1000000) +/** 100 millsecond expressed in microseconds - 64-bit type. */ +#define RT_US_100MS_64 UINT64_C(100000) +/** 10 millsecond expressed in microseconds - 64-bit type. */ +#define RT_US_10MS_64 UINT64_C(10000) +/** 1 millsecond expressed in microseconds - 64-bit type. */ +#define RT_US_1MS_64 UINT64_C(1000) + +/** 1 week expressed in milliseconds. */ +#define RT_MS_1WEEK UINT32_C(604800000) +/** 1 day expressed in milliseconds. */ +#define RT_MS_1DAY UINT32_C(86400000) +/** 1 hour expressed in milliseconds. */ +#define RT_MS_1HOUR UINT32_C(3600000) +/** 30 minutes expressed in milliseconds. */ +#define RT_MS_30MIN UINT32_C(1800000) +/** 5 minutes expressed in milliseconds. */ +#define RT_MS_5MIN UINT32_C(300000) +/** 1 minute expressed in milliseconds. */ +#define RT_MS_1MIN UINT32_C(60000) +/** 45 seconds expressed in milliseconds. */ +#define RT_MS_45SEC UINT32_C(45000) +/** 30 seconds expressed in milliseconds. */ +#define RT_MS_30SEC UINT32_C(30000) +/** 20 seconds expressed in milliseconds. */ +#define RT_MS_20SEC UINT32_C(20000) +/** 15 seconds expressed in milliseconds. */ +#define RT_MS_15SEC UINT32_C(15000) +/** 10 seconds expressed in milliseconds. */ +#define RT_MS_10SEC UINT32_C(10000) +/** 5 seconds expressed in milliseconds. */ +#define RT_MS_5SEC UINT32_C(5000) +/** 1 second expressed in milliseconds. */ +#define RT_MS_1SEC UINT32_C(1000) + +/** 1 week expressed in milliseconds - 64-bit type. */ +#define RT_MS_1WEEK_64 UINT64_C(604800000) +/** 1 day expressed in milliseconds - 64-bit type. */ +#define RT_MS_1DAY_64 UINT64_C(86400000) +/** 1 hour expressed in milliseconds - 64-bit type. */ +#define RT_MS_1HOUR_64 UINT64_C(3600000) +/** 30 minutes expressed in milliseconds - 64-bit type. */ +#define RT_MS_30MIN_64 UINT64_C(1800000) +/** 5 minutes expressed in milliseconds - 64-bit type. */ +#define RT_MS_5MIN_64 UINT64_C(300000) +/** 1 minute expressed in milliseconds - 64-bit type. */ +#define RT_MS_1MIN_64 UINT64_C(60000) +/** 45 seconds expressed in milliseconds - 64-bit type. */ +#define RT_MS_45SEC_64 UINT64_C(45000) +/** 30 seconds expressed in milliseconds - 64-bit type. */ +#define RT_MS_30SEC_64 UINT64_C(30000) +/** 20 seconds expressed in milliseconds - 64-bit type. */ +#define RT_MS_20SEC_64 UINT64_C(20000) +/** 15 seconds expressed in milliseconds - 64-bit type. */ +#define RT_MS_15SEC_64 UINT64_C(15000) +/** 10 seconds expressed in milliseconds - 64-bit type. */ +#define RT_MS_10SEC_64 UINT64_C(10000) +/** 5 seconds expressed in milliseconds - 64-bit type. */ +#define RT_MS_5SEC_64 UINT64_C(5000) +/** 1 second expressed in milliseconds - 64-bit type. */ +#define RT_MS_1SEC_64 UINT64_C(1000) + +/** The number of seconds per week. */ +#define RT_SEC_1WEEK UINT32_C(604800) +/** The number of seconds per day. */ +#define RT_SEC_1DAY UINT32_C(86400) +/** The number of seconds per hour. */ +#define RT_SEC_1HOUR UINT32_C(3600) + +/** The number of seconds per week - 64-bit type. */ +#define RT_SEC_1WEEK_64 UINT64_C(604800) +/** The number of seconds per day - 64-bit type. */ +#define RT_SEC_1DAY_64 UINT64_C(86400) +/** The number of seconds per hour - 64-bit type. */ +#define RT_SEC_1HOUR_64 UINT64_C(3600) +/** @} */ + + +/** @defgroup grp_rt_cdefs_dbgtype Debug Info Types + * @{ */ +/** Other format. */ +#define RT_DBGTYPE_OTHER RT_BIT_32(0) +/** Stabs. */ +#define RT_DBGTYPE_STABS RT_BIT_32(1) +/** Debug With Arbitrary Record Format (DWARF). */ +#define RT_DBGTYPE_DWARF RT_BIT_32(2) +/** Microsoft Codeview debug info. */ +#define RT_DBGTYPE_CODEVIEW RT_BIT_32(3) +/** Watcom debug info. */ +#define RT_DBGTYPE_WATCOM RT_BIT_32(4) +/** IBM High Level Language debug info. */ +#define RT_DBGTYPE_HLL RT_BIT_32(5) +/** Old OS/2 and Windows symbol file. */ +#define RT_DBGTYPE_SYM RT_BIT_32(6) +/** Map file. */ +#define RT_DBGTYPE_MAP RT_BIT_32(7) +/** @} */ + + +/** @defgroup grp_rt_cdefs_exetype Executable Image Types + * @{ */ +/** Some other format. */ +#define RT_EXETYPE_OTHER RT_BIT_32(0) +/** Portable Executable. */ +#define RT_EXETYPE_PE RT_BIT_32(1) +/** Linear eXecutable. */ +#define RT_EXETYPE_LX RT_BIT_32(2) +/** Linear Executable. */ +#define RT_EXETYPE_LE RT_BIT_32(3) +/** New Executable. */ +#define RT_EXETYPE_NE RT_BIT_32(4) +/** DOS Executable (Mark Zbikowski). */ +#define RT_EXETYPE_MZ RT_BIT_32(5) +/** COM Executable. */ +#define RT_EXETYPE_COM RT_BIT_32(6) +/** a.out Executable. */ +#define RT_EXETYPE_AOUT RT_BIT_32(7) +/** Executable and Linkable Format. */ +#define RT_EXETYPE_ELF RT_BIT_32(8) +/** Mach-O Executable (including FAT ones). */ +#define RT_EXETYPE_MACHO RT_BIT_32(9) +/** TE from UEFI. */ +#define RT_EXETYPE_TE RT_BIT_32(9) +/** @} */ + + +/** @def RT_VALID_PTR + * Pointer validation macro. + * @param ptr The pointer. + */ +#if defined(RT_ARCH_AMD64) +# ifdef IN_RING3 +# if defined(RT_OS_DARWIN) /* first 4GB is reserved for legacy kernel. */ +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) >= _4G \ + && !((uintptr_t)(ptr) & 0xffff800000000000ULL) ) +# elif defined(RT_OS_SOLARIS) /* The kernel only used the top 2TB, but keep it simple. */ +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x1000U >= 0x2000U \ + && ( ((uintptr_t)(ptr) & 0xffff800000000000ULL) == 0xffff800000000000ULL \ + || ((uintptr_t)(ptr) & 0xffff800000000000ULL) == 0) ) +# elif defined(RT_OS_LINUX) /* May use 5-level paging (see Documentation/x86/x86_64/mm.rst). */ +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) >= 0x1000U /* one invalid page at the bottom */ \ + && !((uintptr_t)(ptr) & 0xff00000000000000ULL) ) +# else +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) >= 0x1000U \ + && !((uintptr_t)(ptr) & 0xffff800000000000ULL) ) +# endif +# else /* !IN_RING3 */ +# if defined(RT_OS_LINUX) /* May use 5-level paging (see Documentation/x86/x86_64/mm.rst). */ +# if 1 /* User address are no longer considered valid in kernel mode (SMAP, etc). */ +# define RT_VALID_PTR(ptr) ((uintptr_t)(ptr) - 0xff00000000000000ULL < 0x00ffffffffe00000ULL) /* 2MB invalid space at the top */ +# else +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x200000 >= 0x201000U /* one invalid page at the bottom and 2MB at the top */ \ + && ( ((uintptr_t)(ptr) & 0xff00000000000000ULL) == 0xff00000000000000ULL \ + || ((uintptr_t)(ptr) & 0xff00000000000000ULL) == 0) ) +# endif +# else +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x1000U >= 0x2000U \ + && ( ((uintptr_t)(ptr) & 0xffff800000000000ULL) == 0xffff800000000000ULL \ + || ((uintptr_t)(ptr) & 0xffff800000000000ULL) == 0) ) +# endif +# endif /* !IN_RING3 */ + +#elif defined(RT_ARCH_X86) +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x1000U >= 0x2000U ) + +#elif defined(RT_ARCH_SPARC64) +# ifdef IN_RING3 +# if defined(RT_OS_SOLARIS) +/** Sparc64 user mode: According to Figure 9.4 in solaris internals */ +/** @todo # define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x80004000U >= 0x80004000U + 0x100000000ULL ) - figure this. */ +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x80000000U >= 0x80000000U + 0x100000000ULL ) +# else +# error "Port me" +# endif +# else /* !IN_RING3 */ +# if defined(RT_OS_SOLARIS) +/** @todo Sparc64 kernel mode: This is according to Figure 11.1 in solaris + * internals. Verify in sources. */ +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) >= 0x01000000U ) +# else +# error "Port me" +# endif +# endif /* !IN_RING3 */ + +#elif defined(RT_ARCH_SPARC) +# ifdef IN_RING3 +# ifdef RT_OS_SOLARIS +/** Sparc user mode: According to + * http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/uts/sun4/os/startup.c#510 */ +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x400000U >= 0x400000U + 0x2000U ) + +# else +# error "Port me" +# endif +# else /* !IN_RING3 */ +# ifdef RT_OS_SOLARIS +/** @todo Sparc kernel mode: Check the sources! */ +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x1000U >= 0x2000U ) +# else +# error "Port me" +# endif +# endif /* !IN_RING3 */ + +#elif defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) +/* ASSUMES that at least the last and first 4K are out of bounds. */ +# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x1000U >= 0x2000U ) + +#else +# error "Architecture identifier missing / not implemented." +#endif + +/** @def RT_VALID_ALIGNED_PTR + * Pointer validation macro that also checks the alignment. + * @param ptr The pointer. + * @param align The alignment, must be a power of two. + */ +#define RT_VALID_ALIGNED_PTR(ptr, align) \ + ( !((uintptr_t)(ptr) & (uintptr_t)((align) - 1)) \ + && RT_VALID_PTR(ptr) ) + + +/** @def VALID_PHYS32 + * 32 bits physical address validation macro. + * @param Phys The RTGCPHYS address. + */ +#define VALID_PHYS32(Phys) ( (uint64_t)(Phys) < (uint64_t)_4G ) + +/** @def N_ + * The \#define N_ is used to mark a string for translation. This is usable in + * any part of the code, as it is only used by the tools that create message + * catalogs. This macro is a no-op as far as the compiler and code generation + * is concerned. + * + * If you want to both mark a string for translation and translate it, use _(). + */ +#define N_(s) (s) + +/** @def _ + * The \#define _ is used to mark a string for translation and to translate it + * in one step. + * + * If you want to only mark a string for translation, use N_(). + */ +#define _(s) gettext(s) + + +#if (!defined(__GNUC__) && !defined(__PRETTY_FUNCTION__)) || defined(DOXYGEN_RUNNING) +# if defined(_MSC_VER) || defined(DOXYGEN_RUNNING) +/** With GNU C we'd like to use the builtin __PRETTY_FUNCTION__, so define that + * for the other compilers. */ +# define __PRETTY_FUNCTION__ __FUNCSIG__ +# else +# define __PRETTY_FUNCTION__ __FUNCTION__ +# endif +#endif + + +/** @def RT_STRICT + * The \#define RT_STRICT controls whether or not assertions and other runtime + * checks should be compiled in or not. This is defined when DEBUG is defined. + * If RT_NO_STRICT is defined, it will unconditionally be undefined. + * + * If you want assertions which are not subject to compile time options use + * the AssertRelease*() flavors. + */ +#if !defined(RT_STRICT) && defined(DEBUG) +# define RT_STRICT +#endif +#ifdef RT_NO_STRICT +# undef RT_STRICT +#endif + +/** @todo remove this: */ +#if !defined(RT_LOCK_STRICT) && !defined(DEBUG_bird) +# define RT_LOCK_NO_STRICT +#endif +#if !defined(RT_LOCK_STRICT_ORDER) && !defined(DEBUG_bird) +# define RT_LOCK_NO_STRICT_ORDER +#endif + +/** @def RT_LOCK_STRICT + * The \#define RT_LOCK_STRICT controls whether deadlock detection and related + * checks are done in the lock and semaphore code. It is by default enabled in + * RT_STRICT builds, but this behavior can be overridden by defining + * RT_LOCK_NO_STRICT. */ +#if !defined(RT_LOCK_STRICT) && !defined(RT_LOCK_NO_STRICT) && defined(RT_STRICT) +# define RT_LOCK_STRICT +#endif +/** @def RT_LOCK_NO_STRICT + * The \#define RT_LOCK_NO_STRICT disables RT_LOCK_STRICT. */ +#if defined(RT_LOCK_NO_STRICT) && defined(RT_LOCK_STRICT) +# undef RT_LOCK_STRICT +#endif + +/** @def RT_LOCK_STRICT_ORDER + * The \#define RT_LOCK_STRICT_ORDER controls whether locking order is checked + * by the lock and semaphore code. It is by default enabled in RT_STRICT + * builds, but this behavior can be overridden by defining + * RT_LOCK_NO_STRICT_ORDER. */ +#if !defined(RT_LOCK_STRICT_ORDER) && !defined(RT_LOCK_NO_STRICT_ORDER) && defined(RT_STRICT) +# define RT_LOCK_STRICT_ORDER +#endif +/** @def RT_LOCK_NO_STRICT_ORDER + * The \#define RT_LOCK_NO_STRICT_ORDER disables RT_LOCK_STRICT_ORDER. */ +#if defined(RT_LOCK_NO_STRICT_ORDER) && defined(RT_LOCK_STRICT_ORDER) +# undef RT_LOCK_STRICT_ORDER +#endif + + +/** Source position. */ +#define RT_SRC_POS __FILE__, __LINE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__ + +/** Source position declaration. */ +#define RT_SRC_POS_DECL const char *pszFile, unsigned iLine, const char *pszFunction + +/** Source position arguments. */ +#define RT_SRC_POS_ARGS pszFile, iLine, pszFunction + +/** Applies NOREF() to the source position arguments. */ +#define RT_SRC_POS_NOREF() do { NOREF(pszFile); NOREF(iLine); NOREF(pszFunction); } while (0) + + +/** @def RT_INLINE_ASM_EXTERNAL + * Defined as 1 if the compiler does not support inline assembly. + * The ASM* functions will then be implemented in external .asm files. + */ +#if (defined(_MSC_VER) && defined(RT_ARCH_AMD64)) \ + || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86) && !defined(RT_ARCH_ARM64) && !defined(RT_ARCH_ARM32)) \ + || defined(__WATCOMC__) +# define RT_INLINE_ASM_EXTERNAL 1 +#else +# define RT_INLINE_ASM_EXTERNAL 0 +#endif + +/** @def RT_INLINE_ASM_GNU_STYLE + * Defined as 1 if the compiler understands GNU style inline assembly. + */ +#if defined(_MSC_VER) || defined(__WATCOMC__) +# define RT_INLINE_ASM_GNU_STYLE 0 +#else +# define RT_INLINE_ASM_GNU_STYLE 1 +#endif + +/** @def RT_INLINE_ASM_USES_INTRIN + * Defined as one of the RT_MSC_VER_XXX MSC version values if the compiler have + * and uses intrin.h. Otherwise it is 0. */ +#ifdef _MSC_VER +# if _MSC_VER >= RT_MSC_VER_VS2019 /* Visual C++ v14.2 */ +# define RT_INLINE_ASM_USES_INTRIN RT_MSC_VER_VS2019 +# elif _MSC_VER >= RT_MSC_VER_VS2017 /* Visual C++ v14.1 */ +# define RT_INLINE_ASM_USES_INTRIN RT_MSC_VER_VS2017 +# elif _MSC_VER >= RT_MSC_VER_VS2015 /* Visual C++ v14.0 */ +# define RT_INLINE_ASM_USES_INTRIN RT_MSC_VER_VS2015 +# elif _MSC_VER >= RT_MSC_VER_VS2013 /* Visual C++ v12.0 */ +# define RT_INLINE_ASM_USES_INTRIN RT_MSC_VER_VS2013 +# elif _MSC_VER >= RT_MSC_VER_VS2012 /* Visual C++ v11.0 */ +# define RT_INLINE_ASM_USES_INTRIN RT_MSC_VER_VS2012 +# elif _MSC_VER >= RT_MSC_VER_VS2010 /* Visual C++ v10.0 */ +# define RT_INLINE_ASM_USES_INTRIN RT_MSC_VER_VS2010 +# elif _MSC_VER >= RT_MSC_VER_VS2008 /* Visual C++ v9.0 */ +# define RT_INLINE_ASM_USES_INTRIN RT_MSC_VER_VS2008 +# elif _MSC_VER >= RT_MSC_VER_VS2005 /* Visual C++ v8.0 */ +# define RT_INLINE_ASM_USES_INTRIN RT_MSC_VER_VS2005 +# endif +#endif +#ifndef RT_INLINE_ASM_USES_INTRIN +# define RT_INLINE_ASM_USES_INTRIN 0 +#endif + +#define RT_MSC_VER_VS2012 (1700) /**< Visual Studio 2012. */ +#define RT_MSC_VER_VC110 RT_MSC_VER_VS2012 /**< Visual C++ 11.0, aka Visual Studio 2012. */ +#define RT_MSC_VER_VS2013 (1800) /**< Visual Studio 2013. */ +#define RT_MSC_VER_VC120 RT_MSC_VER_VS2013 /**< Visual C++ 12.0, aka Visual Studio 2013. */ +#define RT_MSC_VER_VS2015 (1900) /**< Visual Studio 2015. */ +#define RT_MSC_VER_VC140 RT_MSC_VER_VS2015 /**< Visual C++ 14.0, aka Visual Studio 2015. */ +#define RT_MSC_VER_VS2017 (1910) /**< Visual Studio 2017. */ +#define RT_MSC_VER_VC141 RT_MSC_VER_VS2017 /**< Visual C++ 14.1, aka Visual Studio 2017. */ +#define RT_MSC_VER_VS2019 (1920) /**< Visual Studio 2017. */ +#define RT_MSC_VER_VC142 RT_MSC_VER_VS2019 /**< Visual C++ 14.2, aka Visual Studio 2019. */ + +/** @def RT_COMPILER_SUPPORTS_LAMBDA + * If the defined, the compiler supports lambda expressions. These expressions + * are useful for embedding assertions and type checks into macros. */ +#if defined(_MSC_VER) && defined(__cplusplus) +# if _MSC_VER >= 1600 /* Visual C++ v10.0 / 2010 */ +# define RT_COMPILER_SUPPORTS_LAMBDA +# endif +#elif defined(__GNUC__) && defined(__cplusplus) +/* 4.5 or later, I think, if in ++11 mode... */ +#endif + +/** @def RT_DATA_IS_FAR + * Set to 1 if we're in 16-bit mode and use far pointers. + */ +#if ARCH_BITS == 16 && defined(__WATCOMC__) \ + && (defined(__COMPACT__) || defined(__LARGE__)) +# define RT_DATA_IS_FAR 1 +#else +# define RT_DATA_IS_FAR 0 +#endif + +/** @def RT_FAR + * For indicating far pointers in 16-bit code. + * Does nothing in 32-bit and 64-bit code. */ +/** @def RT_NEAR + * For indicating near pointers in 16-bit code. + * Does nothing in 32-bit and 64-bit code. */ +/** @def RT_FAR_CODE + * For indicating far 16-bit functions. + * Does nothing in 32-bit and 64-bit code. */ +/** @def RT_NEAR_CODE + * For indicating near 16-bit functions. + * Does nothing in 32-bit and 64-bit code. */ +/** @def RT_FAR_DATA + * For indicating far 16-bit external data, i.e. in a segment other than DATA16. + * Does nothing in 32-bit and 64-bit code. */ +#if ARCH_BITS == 16 +# define RT_FAR __far +# define RT_NEAR __near +# define RT_FAR_CODE __far +# define RT_NEAR_CODE __near +# define RT_FAR_DATA __far +#else +# define RT_FAR +# define RT_NEAR +# define RT_FAR_CODE +# define RT_NEAR_CODE +# define RT_FAR_DATA +#endif + + +/** @} */ + + +/** @defgroup grp_rt_cdefs_cpp Special Macros for C++ + * @ingroup grp_rt_cdefs + * @{ + */ + +#ifdef __cplusplus + +/** @def DECLEXPORT_CLASS + * How to declare an exported class. Place this macro after the 'class' + * keyword in the declaration of every class you want to export. + * + * @note It is necessary to use this macro even for inner classes declared + * inside the already exported classes. This is a GCC specific requirement, + * but it seems not to harm other compilers. + */ +#if defined(_MSC_VER) || defined(RT_OS_OS2) +# define DECLEXPORT_CLASS __declspec(dllexport) +#elif defined(RT_USE_VISIBILITY_DEFAULT) +# define DECLEXPORT_CLASS __attribute__((visibility("default"))) +#else +# define DECLEXPORT_CLASS +#endif + +/** @def DECLIMPORT_CLASS + * How to declare an imported class Place this macro after the 'class' + * keyword in the declaration of every class you want to export. + * + * @note It is necessary to use this macro even for inner classes declared + * inside the already exported classes. This is a GCC specific requirement, + * but it seems not to harm other compilers. + */ +#if defined(_MSC_VER) || (defined(RT_OS_OS2) && !defined(__IBMC__) && !defined(__IBMCPP__)) +# define DECLIMPORT_CLASS __declspec(dllimport) +#elif defined(RT_USE_VISIBILITY_DEFAULT) +# define DECLIMPORT_CLASS __attribute__((visibility("default"))) +#else +# define DECLIMPORT_CLASS +#endif + +/** @def WORKAROUND_MSVC7_ERROR_C2593_FOR_BOOL_OP + * Macro to work around error C2593 of the not-so-smart MSVC 7.x ambiguity + * resolver. The following snippet clearly demonstrates the code causing this + * error: + * @code + * class A + * { + * public: + * operator bool() const { return false; } + * operator int*() const { return NULL; } + * }; + * int main() + * { + * A a; + * if (!a); + * if (a && 0); + * return 0; + * } + * @endcode + * The code itself seems pretty valid to me and GCC thinks the same. + * + * This macro fixes the compiler error by explicitly overloading implicit + * global operators !, && and || that take the given class instance as one of + * their arguments. + * + * The best is to use this macro right after the class declaration. + * + * @note The macro expands to nothing for compilers other than MSVC. + * + * @param Cls Class to apply the workaround to + */ +#if defined(_MSC_VER) +# define WORKAROUND_MSVC7_ERROR_C2593_FOR_BOOL_OP(Cls) \ + inline bool operator! (const Cls &that) { return !bool (that); } \ + inline bool operator&& (const Cls &that, bool b) { return bool (that) && b; } \ + inline bool operator|| (const Cls &that, bool b) { return bool (that) || b; } \ + inline bool operator&& (bool b, const Cls &that) { return b && bool (that); } \ + inline bool operator|| (bool b, const Cls &that) { return b || bool (that); } +#else +# define WORKAROUND_MSVC7_ERROR_C2593_FOR_BOOL_OP(Cls) +#endif + +/** @def WORKAROUND_MSVC7_ERROR_C2593_FOR_BOOL_OP_TPL + * Version of WORKAROUND_MSVC7_ERROR_C2593_FOR_BOOL_OP for template classes. + * + * @param Tpl Name of the template class to apply the workaround to + * @param ArgsDecl arguments of the template, as declared in |<>| after the + * |template| keyword, including |<>| + * @param Args arguments of the template, as specified in |<>| after the + * template class name when using the, including |<>| + * + * Example: + * @code + * // template class declaration + * template <class C> + * class Foo { ... }; + * // applied workaround + * WORKAROUND_MSVC7_ERROR_C2593_FOR_BOOL_OP_TPL (Foo, <class C>, <C>) + * @endcode + */ +#if defined(_MSC_VER) +# define WORKAROUND_MSVC7_ERROR_C2593_FOR_BOOL_OP_TPL(Tpl, ArgsDecl, Args) \ + template ArgsDecl \ + inline bool operator! (const Tpl Args &that) { return !bool (that); } \ + template ArgsDecl \ + inline bool operator&& (const Tpl Args &that, bool b) { return bool (that) && b; } \ + template ArgsDecl \ + inline bool operator|| (const Tpl Args &that, bool b) { return bool (that) || b; } \ + template ArgsDecl \ + inline bool operator&& (bool b, const Tpl Args &that) { return b && bool (that); } \ + template ArgsDecl \ + inline bool operator|| (bool b, const Tpl Args &that) { return b || bool (that); } +#else +# define WORKAROUND_MSVC7_ERROR_C2593_FOR_BOOL_OP_TPL(Tpl, ArgsDecl, Args) +#endif + + +/** @def DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP + * Declares the copy constructor and the assignment operation as inlined no-ops + * (non-existent functions) for the given class. Use this macro inside the + * private section if you want to effectively disable these operations for your + * class. + * + * @param Cls class name to declare for + */ +#define DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(Cls) \ + inline Cls(const Cls &); \ + inline Cls &operator= (const Cls &) + + +/** @def DECLARE_CLS_NEW_DELETE_NOOP + * Declares the new and delete operations as no-ops (non-existent functions) + * for the given class. Use this macro inside the private section if you want + * to effectively limit creating class instances on the stack only. + * + * @note The destructor of the given class must not be virtual, otherwise a + * compile time error will occur. Note that this is not a drawback: having + * the virtual destructor for a stack-based class is absolutely useless + * (the real class of the stack-based instance is always known to the compiler + * at compile time, so it will always call the correct destructor). + * + * @param Cls class name to declare for + */ +#define DECLARE_CLS_NEW_DELETE_NOOP(Cls) \ + inline static void *operator new (size_t); \ + inline static void operator delete (void *) + +#endif /* __cplusplus */ + +/** @} */ + +#endif /* !IPRT_INCLUDED_cdefs_h */ + diff --git a/include/iprt/cdrom.h b/include/iprt/cdrom.h new file mode 100644 index 00000000..78dfecba --- /dev/null +++ b/include/iprt/cdrom.h @@ -0,0 +1,195 @@ +/** @file + * IPRT CD/DVD/BD-ROM Drive API. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cdrom_h +#define IPRT_INCLUDED_cdrom_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_cdrom IPRT CD/DVD/BD-ROM Drive API + * @ingroup grp_rt + * + * The user of the API is currently resposible for serializing calls to it. + * + * @{ + */ + +/** CD-ROM drive handle. */ +typedef struct RTCDROMINT *RTCDROM; +/** Pointer to a CD-ROM handle. */ +typedef RTCDROM *PRTCDROM; +/** NIL CD-ROM handle value. */ +#define NIL_RTCDROM ((RTCDROM)0) + + +/** @name CD-ROM open flags. + * @{ */ +#define RTCDROM_O_READ RT_BIT(0) +#define RTCDROM_O_WRITE RT_BIT(1) +#define RTCDROM_O_CONTROL RT_BIT(2) +#define RTCDROM_O_QUERY RT_BIT(3) +#define RTCDROM_O_ALL_ACCESS (RTCDROM_O_READ | RTCDROM_O_WRITE | RTCDROM_O_CONTROL | RTCDROM_O_QUERY) +/** @} */ + +/** + * Opens the CD-ROM drive (by name). + * + * @returns IPRT status code. + * @param pszName The CD-ROM name (path). + * @param fFlags Open flags, see RTCDROM_O_XXX. + * @param phCdrom Where to return the CDROM handle. + */ +RTDECL(int) RTCdromOpen(const char *pszName, uint32_t fFlags, PRTCDROM phCdrom); + +/** + * Retains a reference to the CD-ROM handle. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * @param hCdrom The CD-ROM handle to retain. + */ +RTDECL(uint32_t) RTCdromRetain(RTCDROM hCdrom); + +/** + * Releases a reference to the CD-ROM handle. + * + * When the reference count reaches zero, the CD-ROM handle is destroy. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * @param hCdrom The CD-ROM handle to retain. + */ +RTDECL(uint32_t) RTCdromRelease(RTCDROM hCdrom); + +/** + * Query the primary mount point of the CD-ROM. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. The buffer will be + * set to an empty string if possible. + * + * @param hCdrom The CD-ROM handle. + * @param pszMountPoint Where to return the mount point. + * @param cbMountPoint The size of the mount point buffer. + */ +RTDECL(int) RTCdromQueryMountPoint(RTCDROM hCdrom, char *pszMountPoint, size_t cbMountPoint); + +/** + * Unmounts all file-system mounts related to the CD-ROM. + * + * @returns IPRT status code. + * @param hCdrom The CD-ROM handle. + */ +RTDECL(int) RTCdromUnmount(RTCDROM hCdrom); + +/** + * Ejects the CD-ROM from the drive. + * + * @returns IPRT status code. + * @param hCdrom The CD-ROM handle. + * @param fForce If set, unmount and unlock will be performed. + */ +RTDECL(int) RTCdromEject(RTCDROM hCdrom, bool fForce); + +/** + * Locks the CD-ROM so it cannot be ejected by the user or system. + * + * @returns IPRT status code. + * @param hCdrom The CD-ROM handle. + */ +RTDECL(int) RTCdromLock(RTCDROM hCdrom); + +/** + * Unlocks the CD-ROM so it can be ejected by the user or system. + * + * @returns IPRT status code. + * @param hCdrom The CD-ROM handle. + */ +RTDECL(int) RTCdromUnlock(RTCDROM hCdrom); + + +/** @name Ordinal / Enumeration + * @{ */ +/** + * Get the current number of CD-ROMs. + * + * This is handy for using RTCdromOpenByOrdinal() or RTCdromOrdinalToName() to + * perform some kind of enumeration of all drives. + * + * @returns Number of CD-ROM drivers in the system. + */ +RTDECL(unsigned) RTCdromCount(void); + +/** + * Translates an CD-ROM drive ordinal number to a path suitable for RTCdromOpen. + * + * @returns IRPT status code. + * @retval VINF_SUCCESS on success, with the name in the buffer. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. The buffer will be + * set to an empty string if possible, in order to prevent trouble. + * @retval VERR_OUT_OF_RANGE if the ordinal number is higher than the current + * number of CD-ROM drives. + * + * @param iCdrom The CD-ROM drive ordinal. Starts at 0. + * @param pszName Where to return the name (path). + * @param cbName Size of the output buffer. + * + * @remarks The ordinals are volatile. They may change as drives are attached + * or detected from the host. + */ +RTDECL(int) RTCdromOrdinalToName(unsigned iCdrom, char *pszName, size_t cbName); + +/** + * Combination of RTCdromOrdinalToName() and RTCdromOpen(). + * + * @returns IPRT status code. + * @param iCdrom The CD-ROM number. + * @param fFlags Open flags, see RTCDROM_O_XXX. + * @param phCdrom Where to return the CDROM handle . + * @remarks See remarks on RTCdromOrdinalToName(). + */ +RTDECL(int) RTCdromOpenByOrdinal(unsigned iCdrom, uint32_t fFlags, PRTCDROM phCdrom); + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_cdrom_h */ + diff --git a/include/iprt/cidr.h b/include/iprt/cidr.h new file mode 100644 index 00000000..ed9d558d --- /dev/null +++ b/include/iprt/cidr.h @@ -0,0 +1,76 @@ +/** @file + * IPRT - TCP/IP. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cidr_h +#define IPRT_INCLUDED_cidr_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/net.h> + +/** @defgroup grp_rt_cidr RTCidr - Classless Inter-Domain Routing notation + * @ingroup grp_rt + * @{ + */ +RT_C_DECLS_BEGIN + +/** + * Parse a string which contains an IP address in CIDR (Classless + * Inter-Domain Routing) notation. + * + * @warning The network address and the network mask are returned in + * @b host(!) byte order. This is different from all the other + * RTNetStrTo* functions. + * + * @deprecated This function is superseded by RTNetStrToIPv4Cidr() + * that provides a better API consistent with other functions + * from that family. It returns the prefix length, if you need a + * netmask, you can obtain it with RTNetPrefixToMaskIPv4(). + * + * @return iprt status code. + * + * @param pszAddress The IP address in CIDR specificaion. + * @param pNetwork The determined IP address / network in host byte order. + * @param pNetmask The determined netmask in host byte order. + */ +RTDECL(int) RTCidrStrToIPv4(const char *pszAddress, PRTNETADDRIPV4 pNetwork, PRTNETADDRIPV4 pNetmask); + +RT_C_DECLS_END +/** @} */ + +#endif /* !IPRT_INCLUDED_cidr_h */ diff --git a/include/iprt/circbuf.h b/include/iprt/circbuf.h new file mode 100644 index 00000000..bb107189 --- /dev/null +++ b/include/iprt/circbuf.h @@ -0,0 +1,165 @@ +/** @file + * IPRT - Lock Free Circular Buffer + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_circbuf_h +#define IPRT_INCLUDED_circbuf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/** @defgroup grp_rt_circbuf RTCircBuf - Lock Free Circular Buffer + * @ingroup grp_rt + * + * Implementation of a lock free circular buffer which could be used in a multi + * threaded environment. Note that only the acquire, release and getter + * functions are threading aware. So don't use reset if the circular buffer is + * still in use. + * + * @{ + */ + +RT_C_DECLS_BEGIN + +/** Pointer to a circular buffer (abstract). */ +typedef struct RTCIRCBUF *PRTCIRCBUF; + +/** + * Create a circular buffer. + * + * @returns IPRT status code. + * + * @param ppBuf Where to store the buffer. + * @param cbSize The size of the new buffer. + */ +RTDECL(int) RTCircBufCreate(PRTCIRCBUF *ppBuf, size_t cbSize); + +/** + * Destroy the circular buffer. + * + * @param pBuf The buffer to destroy. NULL is ignored. + */ +RTDECL(void) RTCircBufDestroy(PRTCIRCBUF pBuf); + +/** + * Reset all position information in the circular buffer. + * + * @note This function is not multi threading aware. + * + * @param pBuf The buffer to reset. + */ +RTDECL(void) RTCircBufReset(PRTCIRCBUF pBuf); + +/** + * Returns the current free space of the buffer. + * + * @param pBuf The buffer to query. + */ +RTDECL(size_t) RTCircBufFree(PRTCIRCBUF pBuf); + +/** + * Returns the current used space of the buffer. + * + * @param pBuf The buffer to query. + */ +RTDECL(size_t) RTCircBufUsed(PRTCIRCBUF pBuf); + +/** + * Returns the size of the buffer. + * + * @param pBuf The buffer to query. + */ +RTDECL(size_t) RTCircBufSize(PRTCIRCBUF pBuf); + +RTDECL(bool) RTCircBufIsReading(PRTCIRCBUF pBuf); +RTDECL(bool) RTCircBufIsWriting(PRTCIRCBUF pBuf); + +/** + * Returns the current read offset (in bytes) within the buffer. + * + * @param pBuf The buffer to query. + */ +RTDECL(size_t) RTCircBufOffsetRead(PRTCIRCBUF pBuf); + +/** + * Returns the current write offset (in bytes) within the buffer. + * + * @param pBuf The buffer to query. + */ +RTDECL(size_t) RTCircBufOffsetWrite(PRTCIRCBUF pBuf); + +/** + * Acquire a block of the circular buffer for reading. + * + * @param pBuf The buffer to acquire from. + * @param cbReqSize The requested size of the block. + * @param ppvStart The resulting memory pointer. + * @param pcbSize The resulting size of the memory pointer. + */ +RTDECL(void) RTCircBufAcquireReadBlock(PRTCIRCBUF pBuf, size_t cbReqSize, void **ppvStart, size_t *pcbSize); + +/** + * Release a block which was acquired by RTCircBufAcquireReadBlock. + * + * @param pBuf The buffer to acquire from. + * @param cbSize The size of the block. + */ +RTDECL(void) RTCircBufReleaseReadBlock(PRTCIRCBUF pBuf, size_t cbSize); + +/** + * Acquire a block of the circular buffer for writing. + * + * @param pBuf The buffer to acquire from. + * @param cbReqSize The requested size of the block. + * @param ppvStart The resulting memory pointer. + * @param pcbSize The resulting size of the memory pointer. + */ +RTDECL(void) RTCircBufAcquireWriteBlock(PRTCIRCBUF pBuf, size_t cbReqSize, void **ppvStart, size_t *pcbSize); + +/** + * Release a block which was acquired by RTCircBufAcquireWriteBlock. + * + * @param pBuf The buffer to acquire from. + * @param cbSize The size of the block. + */ +RTDECL(void) RTCircBufReleaseWriteBlock(PRTCIRCBUF pBuf, size_t cbSize); + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_circbuf_h */ + diff --git a/include/iprt/condvar.h b/include/iprt/condvar.h new file mode 100644 index 00000000..8501cb5b --- /dev/null +++ b/include/iprt/condvar.h @@ -0,0 +1,297 @@ +/** @file + * IPRT - Condition Variable. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_condvar_h +#define IPRT_INCLUDED_condvar_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3) +# include <iprt/lockvalidator.h> +#endif + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_condvar RTCondVar - Condition Variable + * + * Condition variables combines mutex semaphore or critical sections with event + * semaphores. See @ref grp_rt_sems_mutex, @ref grp_rt_critsect, + * @ref grp_rt_sems_event and @ref grp_rt_sems_event_multi. + * + * @ingroup grp_rt + * @{ + */ + + +/** + * Create a condition variable. + * + * @returns iprt status code. + * @param phCondVar Where to store the handle to the newly created + * condition variable. + */ +RTDECL(int) RTCondVarCreate(PRTCONDVAR phCondVar); + +/** + * Create a condition variable. + * + * @returns iprt status code. + * @param phCondVar Where to store the handle to the newly created + * condition variable. + * @param fFlags Flags, any combination of the + * RTCONDVAR_FLAGS_XXX \#defines. + * @param hClass The class (no reference consumed). Since we + * don't do order checks on condition variables, + * the use of the class is limited to controlling + * the timeout threshold for deadlock detection. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTCondVarCreateEx(PRTCONDVAR phCondVar, uint32_t fFlags, RTLOCKVALCLASS hClass, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(4, 5); + +/** @name RTCondVarCreateEx flags + * @{ */ +/** Disables lock validation. */ +#define RTCONDVAR_FLAGS_NO_LOCK_VAL UINT32_C(0x00000001) +/** @} */ + +/** + * Destroy a condition variable. + * + * @returns iprt status code. + * @param hCondVar Handle of the condition variable. NIL_RTCONDVAR + * is quietly ignored (VINF_SUCCESS). + */ +RTDECL(int) RTCondVarDestroy(RTCONDVAR hCondVar); + +/** + * Signal the condition variable, waking up exactly one thread. + * + * It is recommended that the caller holds the associated lock, but this is not + * strictly speaking necessary. + * + * If no threads are waiting on the condition variable, the call will have no + * effect on the variable. + * + * @returns iprt status code. + * @param hCondVar The condition variable to signal. + */ +RTDECL(int) RTCondVarSignal(RTCONDVAR hCondVar); + +/** + * Signal the condition variable, waking up all blocked threads. + * + * It is recommended that the caller holds the associated lock, but this is not + * strictly speaking necessary. + * + * If no threads are waiting on the condition variable, the call will have no + * effect on the variable. + * + * @returns iprt status code. + * @param hCondVar The condition variable to broadcast. + */ +RTDECL(int) RTCondVarBroadcast(RTCONDVAR hCondVar); + +/** + * Wait for the condition variable to be signaled, resume on interruption. + * + * This function will resume if the wait is interrupted by an async system event + * (like a unix signal) or similar. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param hCondVar The condition variable to wait on. + * @param hMtx The mutex to leave during the wait and which + * will be re-enter before returning. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait forever. + */ +RTDECL(int) RTCondVarMutexWait(RTCONDVAR hCondVar, RTSEMMUTEX hMtx, RTMSINTERVAL cMillies); + +/** + * Wait for the condition variable to be signaled, return on interruption. + * + * This function will not resume the wait if interrupted. + * + * @returns iprt status code. + * @param hCondVar The condition variable to wait on. + * @param hMtx The mutex to leave during the wait and which + * will be re-enter before returning. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait forever. + */ +RTDECL(int) RTCondVarMutexWaitNoResume(RTCONDVAR hCondVar, RTSEMMUTEX hMtx, RTMSINTERVAL cMillies); + +/** + * Wait for the condition variable to be signaled, resume on interruption. + * + * This function will resume if the wait is interrupted by an async system event + * (like a unix signal) or similar. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param hCondVar The condition variable to wait on. + * @param hRWSem The read/write semaphore to write-leave during + * the wait and which will be re-enter in write + * mode before returning. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait forever. + */ +RTDECL(int) RTCondVarRWWriteWait(RTCONDVAR hCondVar, RTSEMRW hRWSem, RTMSINTERVAL cMillies); + +/** + * Wait for the condition variable to be signaled, return on interruption. + * + * This function will not resume the wait if interrupted. + * + * @returns iprt status code. + * @param hCondVar The condition variable to wait on. + * @param hRWSem The read/write semaphore to write-leave during + * the wait and which will be re-enter in write + * mode before returning. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait forever. + */ +RTDECL(int) RTCondVarRWWriteWaitNoResume(RTCONDVAR hCondVar, RTSEMRW hRWSem, RTMSINTERVAL cMillies); + +/** + * Wait for the condition variable to be signaled, resume on interruption. + * + * This function will resume if the wait is interrupted by an async system event + * (like a unix signal) or similar. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param hCondVar The condition variable to wait on. + * @param hRWSem The read/write semaphore to read-leave during + * the wait and which will be re-enter in read mode + * before returning. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait forever. + */ +RTDECL(int) RTCondVarRWReadWait(RTCONDVAR hCondVar, RTSEMRW hRWSem, RTMSINTERVAL cMillies); + +/** + * Wait for the condition variable to be signaled, return on interruption. + * + * This function will not resume the wait if interrupted. + * + * @returns iprt status code. + * @param hCondVar The condition variable to wait on. + * @param hRWSem The read/write semaphore to read-leave during + * the wait and which will be re-enter in read mode + * before returning. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait forever. + */ +RTDECL(int) RTCondVarRWReadWaitNoResume(RTCONDVAR hCondVar, RTSEMRW hRWSem, RTMSINTERVAL cMillies); + +/** + * Wait for the condition variable to be signaled, resume on interruption. + * + * This function will resume if the wait is interrupted by an async system event + * (like a unix signal) or similar. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param hCondVar The condition variable to wait on. + * @param pCritSect The critical section to leave during the wait + * and which will be re-enter before returning. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait forever. + */ +RTDECL(int) RTCondVarCritSectWait(RTCONDVAR hCondVar, PRTCRITSECT pCritSect, RTMSINTERVAL cMillies); + +/** + * Wait for the condition variable to be signaled, return on interruption. + * + * This function will not resume the wait if interrupted. + * + * @returns iprt status code. + * @param hCondVar The condition variable to wait on. + * @param pCritSect The critical section to leave during the wait + * and which will be re-enter before returning. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait forever. + */ +RTDECL(int) RTCondVarCritSectWaitNoResume(RTCONDVAR hCondVar, PRTCRITSECT pCritSect, RTMSINTERVAL cMillies); + +/** + * Sets the signaller thread to one specific thread. + * + * This is only used for validating usage and deadlock detection. When used + * after calls to RTCondVarAddSignaller, the specified thread will be the only + * signalling thread. + * + * @param hCondVar The condition variable. + * @param hThread The thread that will signal it. Pass + * NIL_RTTHREAD to indicate that there is no + * special signalling thread. + */ +RTDECL(void) RTCondVarSetSignaller(RTCONDVAR hCondVar, RTTHREAD hThread); + +/** + * To add more signalling threads. + * + * First call RTCondVarSetSignaller then add further threads with this. + * + * @param hCondVar The condition variable. + * @param hThread The thread that will signal it. NIL_RTTHREAD is + * not accepted. + */ +RTDECL(void) RTCondVarAddSignaller(RTCONDVAR hCondVar, RTTHREAD hThread); + +/** + * To remove a signalling thread. + * + * Reverts work done by RTCondVarAddSignaller and RTCondVarSetSignaller. + * + * @param hCondVar The condition variable. + * @param hThread A previously added thread. + */ +RTDECL(void) RTCondVarRemoveSignaller(RTCONDVAR hCondVar, RTTHREAD hThread); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_condvar_h */ + diff --git a/include/iprt/coredumper.h b/include/iprt/coredumper.h new file mode 100644 index 00000000..7d1f07c8 --- /dev/null +++ b/include/iprt/coredumper.h @@ -0,0 +1,105 @@ +/** @file + * IPRT - Core Dumper. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_coredumper_h +#define IPRT_INCLUDED_coredumper_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_coredumper RTCoreDumper - Core Dumper. + * @ingroup grp_rt + * @{ + */ + +/** @name RTCoreDumperSetup flags + * @{ */ +/** Override system core dumper. Registers handlers for + * SIGSEGV/SIGTRAP/SIGBUS. */ +#define RTCOREDUMPER_FLAGS_REPLACE_SYSTEM_DUMP RT_BIT(0) +/** Allow taking live process dumps (without killing process). Registers handler + * for SIGUSR2. */ +#define RTCOREDUMPER_FLAGS_LIVE_CORE RT_BIT(1) +/** @} */ + +/** + * Take a core dump of the current process without terminating it. + * + * @returns IPRT status code. + * @param pszOutputFile Name of the core file. If NULL use the + * default naming scheme. + * @param fLiveCore When true, the process is not killed after + * taking a core. Otherwise it will be killed. This + * works in conjuction with the flags set during + * RTCoreDumperSetup(). + */ +RTDECL(int) RTCoreDumperTakeDump(const char *pszOutputFile, bool fLiveCore); + +/** + * Sets up and enables the core dumper. + * + * Installs signal / unhandled exception handlers for catching fatal errors + * that should result in a core dump. If you wish to install your own handlers + * you should do that after calling this function and make sure you pass on + * events you don't handle. + * + * This can be called multiple times to change the settings without needing to + * call RTCoreDumperDisable in between. + * + * @param pszOutputDir The directory to store the cores in. If NULL + * the current directory will be used. + * @param fFlags Setup flags, 0 in NOT a valid flag, it must be + * one or more of RTCOREDUMPER_FLAGS_*. + */ +RTDECL(int) RTCoreDumperSetup(const char *pszOutputDir, uint32_t fFlags); + +/** + * Disables the core dumper, i.e. undoes what RTCoreDumperSetup did. + * + * @returns IPRT status code. + */ +RTDECL(int) RTCoreDumperDisable(void); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_coredumper_h */ + diff --git a/include/iprt/cpp/Makefile.kup b/include/iprt/cpp/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/iprt/cpp/Makefile.kup diff --git a/include/iprt/cpp/autores.h b/include/iprt/cpp/autores.h new file mode 100644 index 00000000..a620de7a --- /dev/null +++ b/include/iprt/cpp/autores.h @@ -0,0 +1,216 @@ +/** @file + * IPRT - C++ Resource Management. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_autores_h +#define IPRT_INCLUDED_cpp_autores_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assert.h> +#include <iprt/cpp/utils.h> + + + +/** @defgroup grp_rt_cpp_autores C++ Resource Management + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * A callable class template which returns the correct value against which an + * IPRT type must be compared to see if it is invalid. + * + * @warning This template *must* be specialised for the types it is to work with. + */ +template <class T> +inline T RTAutoResNil(void) +{ + AssertFatalMsgFailed(("Unspecialized template!\n")); + return (T)0; +} + +/** Specialisation of RTAutoResNil for RTFILE */ +template <> +inline RTFILE RTAutoResNil(void) +{ + return NIL_RTFILE; +} + +/** + * A function template which calls the correct destructor for an IPRT type. + * + * @warning This template *must* be specialised for the types it is to work with. + */ +template <class T> +inline void RTAutoResDestruct(T a_h) +{ + AssertFatalMsgFailed(("Unspecialized template!\n")); + NOREF(a_h); +} + +/** + * An auto pointer-type class for resources which take a C-style destructor + * (RTMemFree() or equivalent). + * + * The idea of this class is to manage resources which the current code is + * responsible for freeing. By wrapping the resource in an RTCAutoRes, you + * ensure that the resource will be freed when you leave the scope in which + * the RTCAutoRes is defined, unless you explicitly release the resource. + * + * A typical use case is when a function is allocating a number of resources. + * If any single allocation fails then all other resources must be freed. If + * all allocations succeed, then the resources should be returned to the + * caller. By placing all allocated resources in RTCAutoRes containers, you + * ensure that they will be freed on failure, and only have to take care of + * releasing them when you return them. + * + * @param T The type of the resource. + * @param Destruct The function to be used to free the resource. + * This parameter must be supplied if there is no + * specialisation of RTAutoDestruct available for @a T. + * @param NilRes The function returning the NIL value for T. Required. + * This parameter must be supplied if there is no + * specialisation of RTAutoResNil available for @a T. + * + * @note The class can not be initialised directly using assignment, due + * to the lack of a copy constructor. This is intentional. + */ +template <class T, void Destruct(T) = RTAutoResDestruct<T>, T NilRes(void) = RTAutoResNil<T> > +class RTCAutoRes + : public RTCNonCopyable +{ +protected: + /** The resource handle. */ + T m_hRes; + +public: + /** + * Constructor + * + * @param a_hRes The handle to resource to manage. Defaults to NIL. + */ + RTCAutoRes(T a_hRes = NilRes()) + : m_hRes(a_hRes) + { + } + + /** + * Destructor. + * + * This destroys any resource currently managed by the object. + */ + ~RTCAutoRes() + { + if (m_hRes != NilRes()) + Destruct(m_hRes); + } + + /** + * Assignment from a value. + * + * This destroys any resource currently managed by the object + * before taking on the new one. + * + * @param a_hRes The handle to the new resource. + */ + RTCAutoRes &operator=(T a_hRes) + { + if (m_hRes != NilRes()) + Destruct(m_hRes); + m_hRes = a_hRes; + return *this; + } + + /** + * Checks if the resource handle is NIL or not. + */ + bool operator!() + { + return m_hRes == NilRes(); + } + + /** + * Give up ownership the current resource, handing it to the caller. + * + * @returns The current resource handle. + * + * @note Nothing happens to the resource when the object goes out of scope. + */ + T release(void) + { + T Tmp = m_hRes; + m_hRes = NilRes(); + return Tmp; + } + + /** + * Deletes the current resources. + * + * @param a_hRes Handle to a new resource to manage. Defaults to NIL. + */ + void reset(T a_hRes = NilRes()) + { + if (a_hRes != m_hRes) + { + if (m_hRes != NilRes()) + Destruct(m_hRes); + m_hRes = a_hRes; + } + } + + /** + * Get the raw resource handle. + * + * Typically used passing the handle to some IPRT function while + * the object remains in scope. + * + * @returns The raw resource handle. + */ + T get(void) + { + return m_hRes; + } +}; + +/** @} */ + + +/* include after template definition */ +#include <iprt/mem.h> + +#endif /* !IPRT_INCLUDED_cpp_autores_h */ + diff --git a/include/iprt/cpp/exception.h b/include/iprt/cpp/exception.h new file mode 100644 index 00000000..0c9f09b7 --- /dev/null +++ b/include/iprt/cpp/exception.h @@ -0,0 +1,118 @@ +/** @file + * IPRT - C++ Base Exceptions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_exception_h +#define IPRT_INCLUDED_cpp_exception_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cpp/ministring.h> +#include <exception> + +#if RT_MSC_PREREQ(RT_MSC_VER_VC140) +# pragma warning(push) +# pragma warning(disable:4275) /* non dll-interface class 'std::exception' used as base for dll-interface class 'RTCError' */ +#endif + + +/** @defgroup grp_rt_cpp_exceptions C++ Exceptions + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * Base exception class for IPRT, derived from std::exception. + * The XML exceptions are based on this. + */ +class RT_DECL_CLASS RTCError + : public std::exception +{ +public: + + RTCError(const char *pszMessage) + : m_strMsg(pszMessage) + { + } + + RTCError(const RTCString &a_rstrMessage) + : m_strMsg(a_rstrMessage) + { + } + + RTCError(const RTCError &a_rSrc) + : std::exception(a_rSrc), + m_strMsg(a_rSrc.what()) + { + } + + virtual ~RTCError() throw() + { + } + + void operator=(const RTCError &a_rSrc) + { + m_strMsg = a_rSrc.what(); + } + + void setWhat(const char *a_pszMessage) + { + m_strMsg = a_pszMessage; + } + + virtual const char *what() const throw() + { + return m_strMsg.c_str(); + } + +private: + /** + * Hidden default constructor making sure that the extended one above is + * always used. + */ + RTCError(); + +protected: + /** The exception message. */ + RTCString m_strMsg; +}; + +/** @} */ + +#if RT_MSC_PREREQ(RT_MSC_VER_VC140) +# pragma warning(pop) +#endif +#endif /* !IPRT_INCLUDED_cpp_exception_h */ + diff --git a/include/iprt/cpp/hardavlrange.h b/include/iprt/cpp/hardavlrange.h new file mode 100644 index 00000000..7020968e --- /dev/null +++ b/include/iprt/cpp/hardavlrange.h @@ -0,0 +1,1284 @@ +/** @file + * IPRT - Hardened AVL tree, unique key ranges. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_hardavlrange_h +#define IPRT_INCLUDED_cpp_hardavlrange_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cpp/hardavlslaballocator.h> + +/** @defgroup grp_rt_cpp_hardavl Hardened AVL Trees + * @{ + */ + +/** + * Check that the tree heights make sense for the current node. + * + * This is a RT_STRICT test as it's expensive and we should have sufficient + * other checks to ensure safe AVL tree operation. + * + * @note the a_cStackEntries parameter is a hack to avoid running into gcc's + * "the address of 'AVLStack' will never be NULL" errors. + */ +#ifdef RT_STRICT +# define RTHARDAVL_STRICT_CHECK_HEIGHTS(a_pNode, a_pAvlStack, a_cStackEntries) do { \ + NodeType * const pLeftNodeX = a_pAllocator->ptrFromInt(readIdx(&(a_pNode)->idxLeft)); \ + AssertReturnStmt(a_pAllocator->isPtrRetOkay(pLeftNodeX), m_cErrors++, a_pAllocator->ptrErrToStatus((a_pNode))); \ + NodeType * const pRightNodeX = a_pAllocator->ptrFromInt(readIdx(&(a_pNode)->idxRight)); \ + AssertReturnStmt(a_pAllocator->isPtrRetOkay(pRightNodeX), m_cErrors++, a_pAllocator->ptrErrToStatus((a_pNode))); \ + uint8_t const cLeftHeightX = pLeftNodeX ? pLeftNodeX->cHeight : 0; \ + uint8_t const cRightHeightX = pRightNodeX ? pRightNodeX->cHeight : 0; \ + if (RT_LIKELY((a_pNode)->cHeight == RT_MAX(cLeftHeightX, cRightHeightX) + 1)) { /*likely*/ } \ + else \ + { \ + RTAssertMsg2("line %u: %u l=%u r=%u\n", __LINE__, (a_pNode)->cHeight, cLeftHeightX, cRightHeightX); \ + if ((a_cStackEntries)) dumpStack(a_pAllocator, (a_pAvlStack)); \ + AssertMsgReturnStmt((a_pNode)->cHeight == RT_MAX(cLeftHeightX, cRightHeightX) + 1, \ + ("%u l=%u r=%u\n", (a_pNode)->cHeight, cLeftHeightX, cRightHeightX), \ + m_cErrors++, VERR_HARDAVL_BAD_HEIGHT); \ + } \ + AssertMsgReturnStmt(RT_ABS(cLeftHeightX - cRightHeightX) <= 1, ("l=%u r=%u\n", cLeftHeightX, cRightHeightX), \ + m_cErrors++, VERR_HARDAVL_UNBALANCED); \ + Assert(!pLeftNodeX || pLeftNodeX->Key < (a_pNode)->Key); \ + Assert(!pRightNodeX || pRightNodeX->Key > (a_pNode)->Key); \ + } while (0) +#else +# define RTHARDAVL_STRICT_CHECK_HEIGHTS(a_pNode, a_pAvlStack, a_cStackEntries) do { } while (0) +#endif + + +/** + * Hardened AVL tree for nodes with key ranges. + * + * This is very crude and therefore expects the NodeType to feature: + * - Key and KeyLast members of KeyType. + * - idxLeft and idxRight members with type uint32_t. + * - cHeight members of type uint8_t. + * + * The code is very C-ish because of it's sources and initial use (ring-0 + * without C++ exceptions enabled). + */ +template<typename NodeType, typename KeyType> +struct RTCHardAvlRangeTree +{ + /** The root index. */ + uint32_t m_idxRoot; + /** The error count. */ + uint32_t m_cErrors; + /** @name Statistics + * @{ */ + uint64_t m_cInserts; + uint64_t m_cRemovals; + uint64_t m_cRebalancingOperations; + /** @} */ + + /** The max stack depth. */ + enum { kMaxStack = 28 }; + /** The max height value we allow. */ + enum { kMaxHeight = kMaxStack + 1 }; + + /** A stack used internally to avoid recursive calls. + * This is used with operations invoking i_rebalance(). */ + typedef struct HardAvlStack + { + /** Number of entries on the stack. */ + unsigned cEntries; + /** The stack. */ + uint32_t *apidxEntries[kMaxStack]; + } HardAvlStack; + + /** @name Key comparisons + * @{ */ + static inline int areKeyRangesIntersecting(KeyType a_Key1First, KeyType a_Key2First, + KeyType a_Key1Last, KeyType a_Key2Last) RT_NOEXCEPT + { + return a_Key1First <= a_Key2Last && a_Key1Last >= a_Key2First; + } + + static inline int isKeyInRange(KeyType a_Key, KeyType a_KeyFirst, KeyType a_KeyLast) RT_NOEXCEPT + { + return a_Key <= a_KeyLast && a_Key >= a_KeyFirst; + } + + static inline int isKeyGreater(KeyType a_Key1, KeyType a_Key2) RT_NOEXCEPT + { + return a_Key1 > a_Key2; + } + /** @} */ + + /** + * Read an index value trying to prevent the compiler from re-reading it. + */ + DECL_FORCE_INLINE(uint32_t) readIdx(uint32_t volatile *pidx) RT_NOEXCEPT + { + uint32_t idx = *pidx; + ASMCompilerBarrier(); + return idx; + } + + RTCHardAvlRangeTree() RT_NOEXCEPT + : m_idxRoot(0) + , m_cErrors(0) + { } + + RTCHardAvlRangeTree(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator) RT_NOEXCEPT + { + initWithAllocator(a_pAllocator); + } + + void initWithAllocator(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator) RT_NOEXCEPT + { + m_idxRoot = a_pAllocator->kNilIndex; + m_cErrors = 0; + } + + /** + * Inserts a node into the AVL-tree. + * + * @returns IPRT status code. + * @retval VERR_ALREADY_EXISTS if a node with overlapping key range exists. + * + * @param a_pAllocator Pointer to the allocator. + * @param a_pNode Pointer to the node which is to be added. + * + * @code + * Find the location of the node (using binary tree algorithm.): + * LOOP until KAVL_NULL leaf pointer + * BEGIN + * Add node pointer pointer to the AVL-stack. + * IF new-node-key < node key THEN + * left + * ELSE + * right + * END + * Fill in leaf node and insert it. + * Rebalance the tree. + * @endcode + */ + int insert(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator, NodeType *a_pNode) RT_NOEXCEPT + { + KeyType const Key = a_pNode->Key; + KeyType const KeyLast = a_pNode->KeyLast; + AssertMsgReturn(Key <= KeyLast, ("Key=%#RX64 KeyLast=%#RX64\n", (uint64_t)Key, (uint64_t)KeyLast), + VERR_HARDAVL_INSERT_INVALID_KEY_RANGE); + + uint32_t *pidxCurNode = &m_idxRoot; + HardAvlStack AVLStack; + AVLStack.cEntries = 0; + for (;;) + { + NodeType *pCurNode = a_pAllocator->ptrFromInt(readIdx(pidxCurNode)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pCurNode), ("*pidxCurNode=%#x pCurNode=%p\n", *pidxCurNode, pCurNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pCurNode)); + if (!pCurNode) + break; + + unsigned const cEntries = AVLStack.cEntries; + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(AVLStack.apidxEntries), + ("%p[%#x/%p] %p[%#x] %p[%#x] %p[%#x] %p[%#x] %p[%#x]\n", pidxCurNode, *pidxCurNode, pCurNode, + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 1], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 1], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 2], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 2], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 3], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 3], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 4], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 4], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 5], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 5]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + AVLStack.apidxEntries[cEntries] = pidxCurNode; + AVLStack.cEntries = cEntries + 1; + + RTHARDAVL_STRICT_CHECK_HEIGHTS(pCurNode, &AVLStack, AVLStack.cEntries); + + /* Range check: */ + if (areKeyRangesIntersecting(pCurNode->Key, Key, pCurNode->KeyLast, KeyLast)) + return VERR_ALREADY_EXISTS; + + /* Descend: */ + if (isKeyGreater(pCurNode->Key, Key)) + pidxCurNode = &pCurNode->idxLeft; + else + pidxCurNode = &pCurNode->idxRight; + } + + a_pNode->idxLeft = a_pAllocator->kNilIndex; + a_pNode->idxRight = a_pAllocator->kNilIndex; + a_pNode->cHeight = 1; + + uint32_t const idxNode = a_pAllocator->ptrToInt(a_pNode); + AssertMsgReturn(a_pAllocator->isIdxRetOkay(idxNode), ("pNode=%p idxNode=%#x\n", a_pNode, idxNode), + a_pAllocator->idxErrToStatus(idxNode)); + *pidxCurNode = idxNode; + + m_cInserts++; + return i_rebalance(a_pAllocator, &AVLStack); + } + + /** + * Removes a node from the AVL-tree by a key value. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if not found. + * @param a_pAllocator Pointer to the allocator. + * @param a_Key A key value in the range of the node to be removed. + * @param a_ppRemoved Where to return the pointer to the removed node. + * + * @code + * Find the node which is to be removed: + * LOOP until not found + * BEGIN + * Add node pointer pointer to the AVL-stack. + * IF the keys matches THEN break! + * IF remove key < node key THEN + * left + * ELSE + * right + * END + * IF found THEN + * BEGIN + * IF left node not empty THEN + * BEGIN + * Find the right most node in the left tree while adding the pointer to the pointer to it's parent to the stack: + * Start at left node. + * LOOP until right node is empty + * BEGIN + * Add to stack. + * go right. + * END + * Link out the found node. + * Replace the node which is to be removed with the found node. + * Correct the stack entry for the pointer to the left tree. + * END + * ELSE + * BEGIN + * Move up right node. + * Remove last stack entry. + * END + * Balance tree using stack. + * END + * return pointer to the removed node (if found). + * @endcode + */ + int remove(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator, KeyType a_Key, NodeType **a_ppRemoved) RT_NOEXCEPT + { + *a_ppRemoved = NULL; + + /* + * Walk the tree till we locate the node that is to be deleted. + */ + uint32_t *pidxDeleteNode = &m_idxRoot; + NodeType *pDeleteNode; + HardAvlStack AVLStack; + AVLStack.cEntries = 0; + for (;;) + { + pDeleteNode = a_pAllocator->ptrFromInt(readIdx(pidxDeleteNode)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pDeleteNode), + ("*pidxCurNode=%#x pDeleteNode=%p\n", *pidxDeleteNode, pDeleteNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pDeleteNode)); + if (pDeleteNode) + { /*likely*/ } + else + return VERR_NOT_FOUND; + + unsigned const cEntries = AVLStack.cEntries; + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(AVLStack.apidxEntries), + ("%p[%#x/%p] %p[%#x] %p[%#x] %p[%#x] %p[%#x] %p[%#x]\n", + pidxDeleteNode, *pidxDeleteNode, pDeleteNode, + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 1], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 1], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 2], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 2], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 3], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 3], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 4], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 4], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 5], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 5]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + AVLStack.apidxEntries[cEntries] = pidxDeleteNode; + AVLStack.cEntries = cEntries + 1; + + RTHARDAVL_STRICT_CHECK_HEIGHTS(pDeleteNode, &AVLStack, AVLStack.cEntries); + + /* Range check: */ + if (isKeyInRange(a_Key, pDeleteNode->Key, pDeleteNode->KeyLast)) + break; + + /* Descend: */ + if (isKeyGreater(pDeleteNode->Key, a_Key)) + pidxDeleteNode = &pDeleteNode->idxLeft; + else + pidxDeleteNode = &pDeleteNode->idxRight; + } + + /* + * Do the deletion. + */ + uint32_t const idxDeleteLeftNode = readIdx(&pDeleteNode->idxLeft); + if (idxDeleteLeftNode != a_pAllocator->kNilIndex) + { + /* + * Replace the deleted node with the rightmost node in the left subtree. + */ + NodeType * const pDeleteLeftNode = a_pAllocator->ptrFromInt(idxDeleteLeftNode); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pDeleteLeftNode), + ("idxDeleteLeftNode=%#x pDeleteLeftNode=%p\n", idxDeleteLeftNode, pDeleteLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pDeleteLeftNode)); + + uint32_t const idxDeleteRightNode = readIdx(&pDeleteNode->idxRight); + AssertReturnStmt(a_pAllocator->isIntValid(idxDeleteRightNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); + + const unsigned iStackEntry = AVLStack.cEntries; + + uint32_t *pidxLeftBiggest = &pDeleteNode->idxLeft; + uint32_t idxLeftBiggestNode = idxDeleteLeftNode; + NodeType *pLeftBiggestNode = pDeleteLeftNode; + RTHARDAVL_STRICT_CHECK_HEIGHTS(pLeftBiggestNode, &AVLStack, AVLStack.cEntries); + + uint32_t idxRightTmp; + while ((idxRightTmp = readIdx(&pLeftBiggestNode->idxRight)) != a_pAllocator->kNilIndex) + { + unsigned const cEntries = AVLStack.cEntries; + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(AVLStack.apidxEntries), + ("%p[%#x/%p] %p[%#x] %p[%#x] %p[%#x] %p[%#x] %p[%#x]\n", + pidxLeftBiggest, *pidxLeftBiggest, pLeftBiggestNode, + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 1], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 1], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 2], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 2], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 3], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 3], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 4], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 4], + AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 5], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 5]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + AVLStack.apidxEntries[cEntries] = pidxLeftBiggest; + AVLStack.cEntries = cEntries + 1; + + pidxLeftBiggest = &pLeftBiggestNode->idxRight; + idxLeftBiggestNode = idxRightTmp; + pLeftBiggestNode = a_pAllocator->ptrFromInt(idxRightTmp); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftBiggestNode), + ("idxLeftBiggestNode=%#x pLeftBiggestNode=%p\n", idxLeftBiggestNode, pLeftBiggestNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftBiggestNode)); + RTHARDAVL_STRICT_CHECK_HEIGHTS(pLeftBiggestNode, &AVLStack, AVLStack.cEntries); + } + + uint32_t const idxLeftBiggestLeftNode = readIdx(&pLeftBiggestNode->idxLeft); + AssertReturnStmt(a_pAllocator->isIntValid(idxLeftBiggestLeftNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); + + /* link out pLeftBiggestNode */ + *pidxLeftBiggest = idxLeftBiggestLeftNode; + + /* link it in place of the deleted node. */ + if (idxDeleteLeftNode != idxLeftBiggestNode) + pLeftBiggestNode->idxLeft = idxDeleteLeftNode; + pLeftBiggestNode->idxRight = idxDeleteRightNode; + pLeftBiggestNode->cHeight = AVLStack.cEntries > iStackEntry ? pDeleteNode->cHeight : 0; + + *pidxDeleteNode = idxLeftBiggestNode; + + if (AVLStack.cEntries > iStackEntry) + AVLStack.apidxEntries[iStackEntry] = &pLeftBiggestNode->idxLeft; + } + else + { + /* No left node, just pull up the right one. */ + uint32_t const idxDeleteRightNode = readIdx(&pDeleteNode->idxRight); + AssertReturnStmt(a_pAllocator->isIntValid(idxDeleteRightNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); + *pidxDeleteNode = idxDeleteRightNode; + AVLStack.cEntries--; + } + *a_ppRemoved = pDeleteNode; + + m_cRemovals++; + return i_rebalance(a_pAllocator, &AVLStack); + } + + /** + * Looks up a node from the tree. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if not found. + * + * @param a_pAllocator Pointer to the allocator. + * @param a_Key A key value in the range of the desired node. + * @param a_ppFound Where to return the pointer to the node. + */ + int lookup(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator, KeyType a_Key, NodeType **a_ppFound) RT_NOEXCEPT + { + *a_ppFound = NULL; + + NodeType *pNode = a_pAllocator->ptrFromInt(readIdx(&m_idxRoot)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("m_idxRoot=%#x pNode=%p\n", m_idxRoot, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); +#ifdef RT_STRICT + HardAvlStack AVLStack; + AVLStack.apidxEntries[0] = &m_idxRoot; + AVLStack.cEntries = 1; +#endif + unsigned cDepth = 0; + while (pNode) + { + RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, &AVLStack, AVLStack.cEntries); + AssertReturn(cDepth <= kMaxHeight, VERR_HARDAVL_LOOKUP_TOO_DEEP); + cDepth++; + + if (isKeyInRange(a_Key, pNode->Key, pNode->KeyLast)) + { + *a_ppFound = pNode; + return VINF_SUCCESS; + } + if (isKeyGreater(pNode->Key, a_Key)) + { +#ifdef RT_STRICT + AVLStack.apidxEntries[AVLStack.cEntries++] = &pNode->idxLeft; +#endif + uint32_t const idxLeft = readIdx(&pNode->idxLeft); + pNode = a_pAllocator->ptrFromInt(idxLeft); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("idxLeft=%#x pNode=%p\n", idxLeft, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); + } + else + { +#ifdef RT_STRICT + AVLStack.apidxEntries[AVLStack.cEntries++] = &pNode->idxRight; +#endif + uint32_t const idxRight = readIdx(&pNode->idxRight); + pNode = a_pAllocator->ptrFromInt(idxRight); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("idxRight=%#x pNode=%p\n", idxRight, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); + } + } + + return VERR_NOT_FOUND; + } + + /** + * Looks up node matching @a a_Key or if no exact match the closest smaller than it. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if not found. + * + * @param a_pAllocator Pointer to the allocator. + * @param a_Key A key value in the range of the desired node. + * @param a_ppFound Where to return the pointer to the node. + */ + int lookupMatchingOrBelow(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator, KeyType a_Key, + NodeType **a_ppFound) RT_NOEXCEPT + { + *a_ppFound = NULL; + + NodeType *pNode = a_pAllocator->ptrFromInt(readIdx(&m_idxRoot)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("m_idxRoot=%#x pNode=%p\n", m_idxRoot, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); +#ifdef RT_STRICT + HardAvlStack AVLStack; + AVLStack.apidxEntries[0] = &m_idxRoot; + AVLStack.cEntries = 1; +#endif + unsigned cDepth = 0; + NodeType *pNodeLast = NULL; + while (pNode) + { + RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, &AVLStack, AVLStack.cEntries); + AssertReturn(cDepth <= kMaxHeight, VERR_HARDAVL_LOOKUP_TOO_DEEP); + cDepth++; + + if (isKeyInRange(a_Key, pNode->Key, pNode->KeyLast)) + { + *a_ppFound = pNode; + return VINF_SUCCESS; + } + if (isKeyGreater(pNode->Key, a_Key)) + { +#ifdef RT_STRICT + AVLStack.apidxEntries[AVLStack.cEntries++] = &pNode->idxLeft; +#endif + uint32_t const idxLeft = readIdx(&pNode->idxLeft); + NodeType *pLeftNode = a_pAllocator->ptrFromInt(idxLeft); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftNode), ("idxLeft=%#x pLeftNode=%p\n", idxLeft, pLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftNode)); + if (pLeftNode) + pNode = pLeftNode; + else if (!pNodeLast) + break; + else + { + *a_ppFound = pNodeLast; + return VINF_SUCCESS; + } + } + else + { +#ifdef RT_STRICT + AVLStack.apidxEntries[AVLStack.cEntries++] = &pNode->idxRight; +#endif + uint32_t const idxRight = readIdx(&pNode->idxRight); + NodeType *pRightNode = a_pAllocator->ptrFromInt(idxRight); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pRightNode), ("idxRight=%#x pRightNode=%p\n", idxRight, pRightNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pRightNode)); + if (pRightNode) + { + pNodeLast = pNode; + pNode = pRightNode; + } + else + { + *a_ppFound = pNode; + return VINF_SUCCESS; + } + } + } + + return VERR_NOT_FOUND; + } + + /** + * Looks up node matching @a a_Key or if no exact match the closest larger than it. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if not found. + * + * @param a_pAllocator Pointer to the allocator. + * @param a_Key A key value in the range of the desired node. + * @param a_ppFound Where to return the pointer to the node. + */ + int lookupMatchingOrAbove(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator, KeyType a_Key, + NodeType **a_ppFound) RT_NOEXCEPT + { + *a_ppFound = NULL; + + NodeType *pNode = a_pAllocator->ptrFromInt(readIdx(&m_idxRoot)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("m_idxRoot=%#x pNode=%p\n", m_idxRoot, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); +#ifdef RT_STRICT + HardAvlStack AVLStack; + AVLStack.apidxEntries[0] = &m_idxRoot; + AVLStack.cEntries = 1; +#endif + unsigned cDepth = 0; + NodeType *pNodeLast = NULL; + while (pNode) + { + RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, &AVLStack, AVLStack.cEntries); + AssertReturn(cDepth <= kMaxHeight, VERR_HARDAVL_LOOKUP_TOO_DEEP); + cDepth++; + + if (isKeyInRange(a_Key, pNode->Key, pNode->KeyLast)) + { + *a_ppFound = pNode; + return VINF_SUCCESS; + } + if (isKeyGreater(pNode->Key, a_Key)) + { +#ifdef RT_STRICT + AVLStack.apidxEntries[AVLStack.cEntries++] = &pNode->idxLeft; +#endif + uint32_t const idxLeft = readIdx(&pNode->idxLeft); + NodeType *pLeftNode = a_pAllocator->ptrFromInt(idxLeft); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftNode), ("idxLeft=%#x pLeftNode=%p\n", idxLeft, pLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftNode)); + if (pLeftNode) + { + pNodeLast = pNode; + pNode = pLeftNode; + } + else + { + *a_ppFound = pNode; + return VINF_SUCCESS; + } + } + else + { +#ifdef RT_STRICT + AVLStack.apidxEntries[AVLStack.cEntries++] = &pNode->idxRight; +#endif + uint32_t const idxRight = readIdx(&pNode->idxRight); + NodeType *pRightNode = a_pAllocator->ptrFromInt(idxRight); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pRightNode), ("idxRight=%#x pRightNode=%p\n", idxRight, pRightNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pRightNode)); + if (pRightNode) + pNode = pRightNode; + else if (!pNodeLast) + break; + else + { + *a_ppFound = pNodeLast; + return VINF_SUCCESS; + } + } + } + + return VERR_NOT_FOUND; + } + + /** + * A callback for doWithAllFromLeft and doWithAllFromRight. + * + * @returns IPRT status code. Any non-zero status causes immediate return from + * the enumeration function. + * @param pNode The current node. + * @param pvUser The user argument. + */ + typedef DECLCALLBACKTYPE(int, FNCALLBACK,(NodeType *pNode, void *pvUser)); + /** Pointer to a callback for doWithAllFromLeft and doWithAllFromRight. */ + typedef FNCALLBACK *PFNCALLBACK; + + /** + * Iterates thru all nodes in the tree from left (smaller) to right. + * + * @returns IPRT status code. + * + * @param a_pAllocator Pointer to the allocator. + * @param a_pfnCallBack Pointer to callback function. + * @param a_pvUser Callback user argument. + * + * @note This is very similar code to doWithAllFromRight() and destroy(). + */ + int doWithAllFromLeft(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator, + PFNCALLBACK a_pfnCallBack, void *a_pvUser) RT_NOEXCEPT + { + NodeType *pNode = a_pAllocator->ptrFromInt(readIdx(&m_idxRoot)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("m_idxRoot=%#x pNode=%p\n", m_idxRoot, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); + if (!pNode) + return VINF_SUCCESS; + + /* + * We simulate recursive calling here. For safety reasons, we do not + * pop before going down the right tree like the original code did. + */ + uint32_t cNodesLeft = a_pAllocator->m_cNodes; + NodeType *apEntries[kMaxStack]; + uint8_t abState[kMaxStack]; + unsigned cEntries = 1; + abState[0] = 0; + apEntries[0] = pNode; + while (cEntries > 0) + { + pNode = apEntries[cEntries - 1]; + switch (abState[cEntries - 1]) + { + /* Go left. */ + case 0: + { + abState[cEntries - 1] = 1; + + NodeType * const pLeftNode = a_pAllocator->ptrFromInt(readIdx(&pNode->idxLeft)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftNode), + ("idxLeft=%#x pLeftNode=%p\n", pNode->idxLeft, pLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftNode)); + if (pLeftNode) + { +#if RT_GNUC_PREREQ_EX(4,7,1) && defined(RTASSERT_HAVE_STATIC_ASSERT) /* 32-bit 4.4.7 has trouble, dunno when it started working */ + AssertCompile(kMaxStack > 6); /* exactly. Seems having static_assert is required. */ +#endif + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(apEntries), + ("%p[%#x] %p %p %p %p %p %p\n", pLeftNode, pNode->idxLeft, apEntries[kMaxStack - 1], + apEntries[kMaxStack - 2], apEntries[kMaxStack - 3], apEntries[kMaxStack - 4], + apEntries[kMaxStack - 5], apEntries[kMaxStack - 6]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + apEntries[cEntries] = pLeftNode; + abState[cEntries] = 0; + cEntries++; + + AssertReturn(cNodesLeft > 0, VERR_HARDAVL_TRAVERSED_TOO_MANY_NODES); + cNodesLeft--; + break; + } + RT_FALL_THROUGH(); + } + + /* center then right. */ + case 1: + { + abState[cEntries - 1] = 2; + + RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, NULL, 0); + + int rc = a_pfnCallBack(pNode, a_pvUser); + if (rc != VINF_SUCCESS) + return rc; + + NodeType * const pRightNode = a_pAllocator->ptrFromInt(readIdx(&pNode->idxRight)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pRightNode), + ("idxRight=%#x pRightNode=%p\n", pNode->idxRight, pRightNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pRightNode)); + if (pRightNode) + { +#if RT_GNUC_PREREQ_EX(4,7,1) && defined(RTASSERT_HAVE_STATIC_ASSERT) /* 32-bit 4.4.7 has trouble, dunno when it started working */ + AssertCompile(kMaxStack > 6); /* exactly. Seems having static_assert is required. */ +#endif + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(apEntries), + ("%p[%#x] %p %p %p %p %p %p\n", pRightNode, pNode->idxRight, apEntries[kMaxStack - 1], + apEntries[kMaxStack - 2], apEntries[kMaxStack - 3], apEntries[kMaxStack - 4], + apEntries[kMaxStack - 5], apEntries[kMaxStack - 6]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + apEntries[cEntries] = pRightNode; + abState[cEntries] = 0; + cEntries++; + + AssertReturn(cNodesLeft > 0, VERR_HARDAVL_TRAVERSED_TOO_MANY_NODES); + cNodesLeft--; + break; + } + RT_FALL_THROUGH(); + } + + default: + /* pop it. */ + cEntries -= 1; + break; + } + } + return VINF_SUCCESS; + } + + /** + * Iterates thru all nodes in the tree from right (larger) to left (smaller). + * + * @returns IPRT status code. + * + * @param a_pAllocator Pointer to the allocator. + * @param a_pfnCallBack Pointer to callback function. + * @param a_pvUser Callback user argument. + * + * @note This is very similar code to doWithAllFromLeft() and destroy(). + */ + int doWithAllFromRight(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator, + PFNCALLBACK a_pfnCallBack, void *a_pvUser) RT_NOEXCEPT + { + NodeType *pNode = a_pAllocator->ptrFromInt(readIdx(&m_idxRoot)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("m_idxRoot=%#x pNode=%p\n", m_idxRoot, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); + if (!pNode) + return VINF_SUCCESS; + + /* + * We simulate recursive calling here. For safety reasons, we do not + * pop before going down the right tree like the original code did. + */ + uint32_t cNodesLeft = a_pAllocator->m_cNodes; + NodeType *apEntries[kMaxStack]; + uint8_t abState[kMaxStack]; + unsigned cEntries = 1; + abState[0] = 0; + apEntries[0] = pNode; + while (cEntries > 0) + { + pNode = apEntries[cEntries - 1]; + switch (abState[cEntries - 1]) + { + /* Go right. */ + case 0: + { + abState[cEntries - 1] = 1; + + NodeType * const pRightNode = a_pAllocator->ptrFromInt(readIdx(&pNode->idxRight)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pRightNode), + ("idxRight=%#x pRightNode=%p\n", pNode->idxRight, pRightNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pRightNode)); + if (pRightNode) + { +#if RT_GNUC_PREREQ_EX(4,7,1) && defined(RTASSERT_HAVE_STATIC_ASSERT) /* 32-bit 4.4.7 has trouble, dunno when it started working */ + AssertCompile(kMaxStack > 6); /* exactly. Seems having static_assert is required. */ +#endif + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(apEntries), + ("%p[%#x] %p %p %p %p %p %p\n", pRightNode, pNode->idxRight, apEntries[kMaxStack - 1], + apEntries[kMaxStack - 2], apEntries[kMaxStack - 3], apEntries[kMaxStack - 4], + apEntries[kMaxStack - 5], apEntries[kMaxStack - 6]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + apEntries[cEntries] = pRightNode; + abState[cEntries] = 0; + cEntries++; + + AssertReturn(cNodesLeft > 0, VERR_HARDAVL_TRAVERSED_TOO_MANY_NODES); + cNodesLeft--; + break; + } + RT_FALL_THROUGH(); + } + + /* center then left. */ + case 1: + { + abState[cEntries - 1] = 2; + + RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, NULL, 0); + + int rc = a_pfnCallBack(pNode, a_pvUser); + if (rc != VINF_SUCCESS) + return rc; + + NodeType * const pLeftNode = a_pAllocator->ptrFromInt(readIdx(&pNode->idxLeft)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftNode), + ("idxLeft=%#x pLeftNode=%p\n", pNode->idxLeft, pLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftNode)); + if (pLeftNode) + { +#if RT_GNUC_PREREQ_EX(4,7,1) && defined(RTASSERT_HAVE_STATIC_ASSERT) /* 32-bit 4.4.7 has trouble, dunno when it started working */ + AssertCompile(kMaxStack > 6); /* exactly. Seems having static_assert is required. */ +#endif + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(apEntries), + ("%p[%#x] %p %p %p %p %p %p\n", pLeftNode, pNode->idxLeft, apEntries[kMaxStack - 1], + apEntries[kMaxStack - 2], apEntries[kMaxStack - 3], apEntries[kMaxStack - 4], + apEntries[kMaxStack - 5], apEntries[kMaxStack - 6]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + apEntries[cEntries] = pLeftNode; + abState[cEntries] = 0; + cEntries++; + + AssertReturn(cNodesLeft > 0, VERR_HARDAVL_TRAVERSED_TOO_MANY_NODES); + cNodesLeft--; + break; + } + RT_FALL_THROUGH(); + } + + default: + /* pop it. */ + cEntries -= 1; + break; + } + } + return VINF_SUCCESS; + } + + /** + * A callback for destroy to do additional cleanups before the node is freed. + * + * @param pNode The current node. + * @param pvUser The user argument. + */ + typedef DECLCALLBACKTYPE(void, FNDESTROYCALLBACK,(NodeType *pNode, void *pvUser)); + /** Pointer to a callback for destroy. */ + typedef FNDESTROYCALLBACK *PFNDESTROYCALLBACK; + + /** + * Destroys the tree, starting with the root node. + * + * This will invoke the freeNode() method on the allocate for every node after + * first doing the callback to let the caller free additional resources + * referenced by the node. + * + * @returns IPRT status code. + * + * @param a_pAllocator Pointer to the allocator. + * @param a_pfnCallBack Pointer to callback function. Optional. + * @param a_pvUser Callback user argument. + * + * @note This is mostly the same code as the doWithAllFromLeft(). + */ + int destroy(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator, + PFNDESTROYCALLBACK a_pfnCallBack = NULL, void *a_pvUser = NULL) RT_NOEXCEPT + { + NodeType *pNode = a_pAllocator->ptrFromInt(readIdx(&m_idxRoot)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("m_idxRoot=%#x pNode=%p\n", m_idxRoot, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); + if (!pNode) + return VINF_SUCCESS; + + /* + * We simulate recursive calling here. For safety reasons, we do not + * pop before going down the right tree like the original code did. + */ + uint32_t cNodesLeft = a_pAllocator->m_cNodes; + NodeType *apEntries[kMaxStack]; + uint8_t abState[kMaxStack]; + unsigned cEntries = 1; + abState[0] = 0; + apEntries[0] = pNode; + while (cEntries > 0) + { + pNode = apEntries[cEntries - 1]; + switch (abState[cEntries - 1]) + { + /* Go left. */ + case 0: + { + abState[cEntries - 1] = 1; + + NodeType * const pLeftNode = a_pAllocator->ptrFromInt(readIdx(&pNode->idxLeft)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftNode), + ("idxLeft=%#x pLeftNode=%p\n", pNode->idxLeft, pLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftNode)); + if (pLeftNode) + { +#if RT_GNUC_PREREQ_EX(4,7,1) && defined(RTASSERT_HAVE_STATIC_ASSERT) /* 32-bit 4.4.7 has trouble, dunno when it started working */ + AssertCompile(kMaxStack > 6); /* exactly. Seems having static_assert is required. */ +#endif + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(apEntries), + ("%p[%#x] %p %p %p %p %p %p\n", pLeftNode, pNode->idxLeft, apEntries[kMaxStack - 1], + apEntries[kMaxStack - 2], apEntries[kMaxStack - 3], apEntries[kMaxStack - 4], + apEntries[kMaxStack - 5], apEntries[kMaxStack - 6]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + apEntries[cEntries] = pLeftNode; + abState[cEntries] = 0; + cEntries++; + + AssertReturn(cNodesLeft > 0, VERR_HARDAVL_TRAVERSED_TOO_MANY_NODES); + cNodesLeft--; + break; + } + RT_FALL_THROUGH(); + } + + /* right. */ + case 1: + { + abState[cEntries - 1] = 2; + + NodeType * const pRightNode = a_pAllocator->ptrFromInt(readIdx(&pNode->idxRight)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pRightNode), + ("idxRight=%#x pRightNode=%p\n", pNode->idxRight, pRightNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pRightNode)); + if (pRightNode) + { +#if RT_GNUC_PREREQ_EX(4,7,1) && defined(RTASSERT_HAVE_STATIC_ASSERT) /* 32-bit 4.4.7 has trouble, dunno when it started working */ + AssertCompile(kMaxStack > 6); /* exactly. Seems having static_assert is required. */ +#endif + AssertMsgReturnStmt(cEntries < RT_ELEMENTS(apEntries), + ("%p[%#x] %p %p %p %p %p %p\n", pRightNode, pNode->idxRight, apEntries[kMaxStack - 1], + apEntries[kMaxStack - 2], apEntries[kMaxStack - 3], apEntries[kMaxStack - 4], + apEntries[kMaxStack - 5], apEntries[kMaxStack - 6]), + m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); + apEntries[cEntries] = pRightNode; + abState[cEntries] = 0; + cEntries++; + + AssertReturn(cNodesLeft > 0, VERR_HARDAVL_TRAVERSED_TOO_MANY_NODES); + cNodesLeft--; + break; + } + RT_FALL_THROUGH(); + } + + default: + { + /* pop it and destroy it. */ + if (a_pfnCallBack) + a_pfnCallBack(pNode, a_pvUser); + + int rc = a_pAllocator->freeNode(pNode); + AssertRCReturnStmt(rc, m_cErrors++, rc); + + cEntries -= 1; + break; + } + } + } + + Assert(m_idxRoot == a_pAllocator->kNilIndex); + return VINF_SUCCESS; + } + + + /** + * Gets the tree height value (reads cHeigh from the root node). + * + * @retval UINT8_MAX if bogus tree. + */ + uint8_t getHeight(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator) RT_NOEXCEPT + { + NodeType *pNode = a_pAllocator->ptrFromInt(readIdx(&m_idxRoot)); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("m_idxRoot=%#x pNode=%p\n", m_idxRoot, pNode), + m_cErrors++, UINT8_MAX); + if (pNode) + return pNode->cHeight; + return 0; + } + +#ifdef RT_STRICT + + static void dumpStack(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator, HardAvlStack const *pStack) RT_NOEXCEPT + { + uint32_t const * const *paidx = pStack->apidxEntries; + RTAssertMsg2("stack: %u:\n", pStack->cEntries); + for (unsigned i = 0; i < pStack->cEntries; i++) + { + uint32_t idx = *paidx[i]; + uint32_t idxNext = i + 1 < pStack->cEntries ? *paidx[i + 1] : UINT32_MAX; + NodeType const *pNode = a_pAllocator->ptrFromInt(idx); + RTAssertMsg2(" #%02u: %p[%#06x] pNode=%p h=%02d l=%#06x%c r=%#06x%c\n", i, paidx[i], idx, pNode, pNode->cHeight, + pNode->idxLeft, pNode->idxLeft == idxNext ? '*' : ' ', + pNode->idxRight, pNode->idxRight == idxNext ? '*' : ' '); + } + } + + static void printTree(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator, uint32_t a_idxRoot, + unsigned a_uLevel = 0, unsigned a_uMaxLevel = 8, const char *a_pszDir = "") RT_NOEXCEPT + { + if (a_idxRoot == a_pAllocator->kNilIndex) + RTAssertMsg2("%*snil\n", a_uLevel * 6, a_pszDir); + else if (a_uLevel < a_uMaxLevel) + { + NodeType *pNode = a_pAllocator->ptrFromInt(a_idxRoot); + printTree(a_pAllocator, readIdx(&pNode->idxRight), a_uLevel + 1, a_uMaxLevel, "/ "); + RTAssertMsg2("%*s%#x/%u\n", a_uLevel * 6, a_pszDir, a_idxRoot, pNode->cHeight); + printTree(a_pAllocator, readIdx(&pNode->idxLeft), a_uLevel + 1, a_uMaxLevel, "\\ "); + } + else + RTAssertMsg2("%*stoo deep\n", a_uLevel * 6, a_pszDir); + } + +#endif + +private: + /** + * Rewinds a stack of pointers to pointers to nodes, rebalancing the tree. + * + * @returns IPRT status code. + * + * @param a_pAllocator Pointer to the allocator. + * @param a_pStack Pointer to stack to rewind. + * @param a_fLog Log is done (DEBUG builds only). + * + * @code + * LOOP thru all stack entries + * BEGIN + * Get pointer to pointer to node (and pointer to node) from the stack. + * IF 2 higher left subtree than in right subtree THEN + * BEGIN + * IF higher (or equal) left-sub-subtree than right-sub-subtree THEN + * * n+2|n+3 + * / \ / \ + * n+2 n ==> n+1 n+1|n+2 + * / \ / \ + * n+1 n|n+1 n|n+1 n + * + * Or with keys: + * + * 4 2 + * / \ / \ + * 2 5 ==> 1 4 + * / \ / \ + * 1 3 3 5 + * + * ELSE + * * n+2 + * / \ / \ + * n+2 n n+1 n+1 + * / \ ==> / \ / \ + * n n+1 n L R n + * / \ + * L R + * + * Or with keys: + * 6 4 + * / \ / \ + * 2 7 ==> 2 6 + * / \ / \ / \ + * 1 4 1 3 5 7 + * / \ + * 3 5 + * END + * ELSE IF 2 higher in right subtree than in left subtree THEN + * BEGIN + * Same as above but left <==> right. (invert the picture) + * ELSE + * IF correct height THEN break + * ELSE correct height. + * END + * @endcode + * @internal + */ + int i_rebalance(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator, HardAvlStack *a_pStack, bool a_fLog = false) RT_NOEXCEPT + { + RT_NOREF(a_fLog); + + while (a_pStack->cEntries > 0) + { + /* pop */ + uint32_t * const pidxNode = a_pStack->apidxEntries[--a_pStack->cEntries]; + uint32_t const idxNode = readIdx(pidxNode); + NodeType * const pNode = a_pAllocator->ptrFromInt(idxNode); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), + ("pidxNode=%p[%#x] pNode=%p\n", pidxNode, *pidxNode, pNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); + + /* Read node properties: */ + uint32_t const idxLeftNode = readIdx(&pNode->idxLeft); + NodeType * const pLeftNode = a_pAllocator->ptrFromInt(idxLeftNode); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftNode), + ("idxLeftNode=%#x pLeftNode=%p\n", idxLeftNode, pLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftNode)); + + uint32_t const idxRightNode = readIdx(&pNode->idxRight); + NodeType * const pRightNode = a_pAllocator->ptrFromInt(idxRightNode); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pRightNode), + ("idxRight=%#x pRightNode=%p\n", idxRightNode, pRightNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pRightNode)); + + uint8_t const cLeftHeight = pLeftNode ? pLeftNode->cHeight : 0; + AssertReturnStmt(cLeftHeight <= kMaxHeight, m_cErrors++, VERR_HARDAVL_BAD_LEFT_HEIGHT); + + uint8_t const cRightHeight = pRightNode ? pRightNode->cHeight : 0; + AssertReturnStmt(cRightHeight <= kMaxHeight, m_cErrors++, VERR_HARDAVL_BAD_RIGHT_HEIGHT); + + /* Decide what needs doing: */ + if (cRightHeight + 1 < cLeftHeight) + { + Assert(cRightHeight + 2 == cLeftHeight); + AssertReturnStmt(pLeftNode, m_cErrors++, VERR_HARDAVL_UNEXPECTED_NULL_LEFT); + + uint32_t const idxLeftLeftNode = readIdx(&pLeftNode->idxLeft); + NodeType * const pLeftLeftNode = a_pAllocator->ptrFromInt(idxLeftLeftNode); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftLeftNode), + ("idxLeftLeftNode=%#x pLeftLeftNode=%p\n", idxLeftLeftNode, pLeftLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftLeftNode)); + + uint32_t const idxLeftRightNode = readIdx(&pLeftNode->idxRight); + NodeType * const pLeftRightNode = a_pAllocator->ptrFromInt(idxLeftRightNode); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftRightNode), + ("idxLeftRightNode=%#x pLeftRightNode=%p\n", idxLeftRightNode, pLeftRightNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftRightNode)); + + uint8_t const cLeftRightHeight = pLeftRightNode ? pLeftRightNode->cHeight : 0; + if ((pLeftLeftNode ? pLeftLeftNode->cHeight : 0) >= cLeftRightHeight) + { + AssertReturnStmt(cLeftRightHeight + 2 <= kMaxHeight, m_cErrors++, VERR_HARDAVL_BAD_NEW_HEIGHT); + pNode->idxLeft = idxLeftRightNode; + pNode->cHeight = (uint8_t)(cLeftRightHeight + 1); + pLeftNode->cHeight = (uint8_t)(cLeftRightHeight + 2); + pLeftNode->idxRight = idxNode; + *pidxNode = idxLeftNode; +#ifdef DEBUG + if (a_fLog) RTAssertMsg2("rebalance: %#2u: op #1\n", a_pStack->cEntries); +#endif + } + else + { + AssertReturnStmt(cLeftRightHeight <= kMaxHeight, m_cErrors++, VERR_HARDAVL_BAD_RIGHT_HEIGHT); + AssertReturnStmt(pLeftRightNode, m_cErrors++, VERR_HARDAVL_UNEXPECTED_NULL_RIGHT); + + uint32_t const idxLeftRightLeftNode = readIdx(&pLeftRightNode->idxLeft); + AssertReturnStmt(a_pAllocator->isIntValid(idxLeftRightLeftNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); + uint32_t const idxLeftRightRightNode = readIdx(&pLeftRightNode->idxRight); + AssertReturnStmt(a_pAllocator->isIntValid(idxLeftRightRightNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); + pLeftNode->idxRight = idxLeftRightLeftNode; + pNode->idxLeft = idxLeftRightRightNode; + + pLeftRightNode->idxLeft = idxLeftNode; + pLeftRightNode->idxRight = idxNode; + pLeftNode->cHeight = cLeftRightHeight; + pNode->cHeight = cLeftRightHeight; + pLeftRightNode->cHeight = cLeftHeight; + *pidxNode = idxLeftRightNode; +#ifdef DEBUG + if (a_fLog) RTAssertMsg2("rebalance: %#2u: op #2\n", a_pStack->cEntries); +#endif + } + m_cRebalancingOperations++; + } + else if (cLeftHeight + 1 < cRightHeight) + { + Assert(cLeftHeight + 2 == cRightHeight); + AssertReturnStmt(pRightNode, m_cErrors++, VERR_HARDAVL_UNEXPECTED_NULL_RIGHT); + + uint32_t const idxRightLeftNode = readIdx(&pRightNode->idxLeft); + NodeType * const pRightLeftNode = a_pAllocator->ptrFromInt(idxRightLeftNode); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pRightLeftNode), + ("idxRightLeftNode=%#x pRightLeftNode=%p\n", idxRightLeftNode, pRightLeftNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pRightLeftNode)); + + uint32_t const idxRightRightNode = readIdx(&pRightNode->idxRight); + NodeType * const pRightRightNode = a_pAllocator->ptrFromInt(idxRightRightNode); + AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pRightRightNode), + ("idxRightRightNode=%#x pRightRightNode=%p\n", idxRightRightNode, pRightRightNode), + m_cErrors++, a_pAllocator->ptrErrToStatus(pRightRightNode)); + + uint8_t const cRightLeftHeight = pRightLeftNode ? pRightLeftNode->cHeight : 0; + if ((pRightRightNode ? pRightRightNode->cHeight : 0) >= cRightLeftHeight) + { + AssertReturnStmt(cRightLeftHeight + 2 <= kMaxHeight, m_cErrors++, VERR_HARDAVL_BAD_NEW_HEIGHT); + + pNode->idxRight = idxRightLeftNode; + pRightNode->idxLeft = idxNode; + pNode->cHeight = (uint8_t)(cRightLeftHeight + 1); + pRightNode->cHeight = (uint8_t)(cRightLeftHeight + 2); + *pidxNode = idxRightNode; +#ifdef DEBUG + if (a_fLog) RTAssertMsg2("rebalance: %#2u: op #3 h=%d, *pidxNode=%#x\n", a_pStack->cEntries, pRightNode->cHeight, *pidxNode); +#endif + RTHARDAVL_STRICT_CHECK_HEIGHTS(pRightNode, NULL, 0); + RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, NULL, 0); + } + else + { + AssertReturnStmt(cRightLeftHeight <= kMaxHeight, m_cErrors++, VERR_HARDAVL_BAD_LEFT_HEIGHT); + AssertReturnStmt(pRightLeftNode, m_cErrors++, VERR_HARDAVL_UNEXPECTED_NULL_LEFT); + + uint32_t const idxRightLeftRightNode = readIdx(&pRightLeftNode->idxRight); + AssertReturnStmt(a_pAllocator->isIntValid(idxRightLeftRightNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); + uint32_t const idxRightLeftLeftNode = readIdx(&pRightLeftNode->idxLeft); + AssertReturnStmt(a_pAllocator->isIntValid(idxRightLeftLeftNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); + pRightNode->idxLeft = idxRightLeftRightNode; + pNode->idxRight = idxRightLeftLeftNode; + + pRightLeftNode->idxRight = idxRightNode; + pRightLeftNode->idxLeft = idxNode; + pRightNode->cHeight = cRightLeftHeight; + pNode->cHeight = cRightLeftHeight; + pRightLeftNode->cHeight = cRightHeight; + *pidxNode = idxRightLeftNode; +#ifdef DEBUG + if (a_fLog) RTAssertMsg2("rebalance: %#2u: op #4 h=%d, *pidxNode=%#x\n", a_pStack->cEntries, pRightLeftNode->cHeight, *pidxNode); +#endif + } + m_cRebalancingOperations++; + } + else + { + uint8_t const cHeight = (uint8_t)(RT_MAX(cLeftHeight, cRightHeight) + 1); + AssertReturnStmt(cHeight <= kMaxHeight, m_cErrors++, VERR_HARDAVL_BAD_NEW_HEIGHT); + if (cHeight == pNode->cHeight) + { +#ifdef DEBUG + if (a_fLog) RTAssertMsg2("rebalance: %#2u: op #5, h=%d - done\n", a_pStack->cEntries, cHeight); +#endif + RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, NULL, 0); + if (pLeftNode) + RTHARDAVL_STRICT_CHECK_HEIGHTS(pLeftNode, NULL, 0); + if (pRightNode) + RTHARDAVL_STRICT_CHECK_HEIGHTS(pRightNode, NULL, 0); + break; + } +#ifdef DEBUG + if (a_fLog) RTAssertMsg2("rebalance: %#2u: op #5, h=%d - \n", a_pStack->cEntries, cHeight); +#endif + pNode->cHeight = cHeight; + } + } + return VINF_SUCCESS; + } +}; + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_hardavlrange_h */ + diff --git a/include/iprt/cpp/hardavlslaballocator.h b/include/iprt/cpp/hardavlslaballocator.h new file mode 100644 index 00000000..515782b5 --- /dev/null +++ b/include/iprt/cpp/hardavlslaballocator.h @@ -0,0 +1,218 @@ +/** @file + * IPRT - Hardened AVL tree slab allocator. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_hardavlslaballocator_h +#define IPRT_INCLUDED_cpp_hardavlslaballocator_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/asm.h> +#include <iprt/assert.h> +#include <iprt/err.h> +#include <iprt/string.h> + +/** @addtogroup grp_rt_cpp_hardavl + * @{ + */ + + +/** + * Slab allocator for the hardened AVL tree. + */ +template<typename NodeType> +struct RTCHardAvlTreeSlabAllocator +{ + /** Pointer to an array of nodes. */ + NodeType *m_paNodes; + /** Node allocation bitmap: 1 = free, 0 = allocated. */ + uint64_t *m_pbmAlloc; + /** Max number of nodes in m_paNodes and valid bits in m_pbmAlloc. */ + uint32_t m_cNodes; + /** Pointer error counter. */ + uint32_t m_cErrors; + /** Allocation hint. */ + uint32_t m_idxAllocHint; + uint32_t m_uPadding; + + enum + { + kNilIndex = 0, + kErr_IndexOutOfBound = -1, + kErr_PointerOutOfBound = -2, + kErr_MisalignedPointer = -3, + kErr_NodeIsFree = -4, + kErr_Last = kErr_NodeIsFree + }; + + RTCHardAvlTreeSlabAllocator() RT_NOEXCEPT + : m_paNodes(NULL) + , m_pbmAlloc(NULL) + , m_cNodes(0) + , m_cErrors(0) + , m_idxAllocHint(0) + , m_uPadding(0) + {} + + inline void initSlabAllocator(uint32_t a_cNodes, NodeType *a_paNodes, uint64_t *a_pbmAlloc) RT_NOEXCEPT + { + m_cNodes = a_cNodes; + m_paNodes = a_paNodes; + m_pbmAlloc = a_pbmAlloc; + + /* Initialize the allocation bit. */ + RT_BZERO(a_pbmAlloc, (a_cNodes + 63) / 64 * 8); + ASMBitSetRange(a_pbmAlloc, 0, a_cNodes); + } + + inline NodeType *ptrFromInt(uint32_t a_idxNode1) RT_NOEXCEPT + { + if (a_idxNode1 == (uint32_t)kNilIndex) + return NULL; + AssertMsgReturnStmt(a_idxNode1 <= m_cNodes, ("a_idxNode1=%#x m_cNodes=%#x\n", a_idxNode1, m_cNodes), + m_cErrors++, (NodeType *)(intptr_t)kErr_IndexOutOfBound); + AssertMsgReturnStmt(ASMBitTest(m_pbmAlloc, a_idxNode1 - 1) == false, ("a_idxNode1=%#x\n", a_idxNode1), + m_cErrors++, (NodeType *)(intptr_t)kErr_NodeIsFree); + return &m_paNodes[a_idxNode1 - 1]; + } + + static inline bool isPtrRetOkay(NodeType *a_pNode) RT_NOEXCEPT + { + return (uintptr_t)a_pNode < (uintptr_t)kErr_Last; + } + + static inline int ptrErrToStatus(NodeType *a_pNode) RT_NOEXCEPT + { + return (int)(intptr_t)a_pNode - (VERR_HARDAVL_INDEX_OUT_OF_BOUNDS - kErr_IndexOutOfBound); + } + + inline uint32_t ptrToInt(NodeType *a_pNode) RT_NOEXCEPT + { + if (a_pNode == NULL) + return 0; + uintptr_t const offNode = (uintptr_t)a_pNode - (uintptr_t)m_paNodes; + uintptr_t const idxNode0 = offNode / sizeof(m_paNodes[0]); + AssertMsgReturnStmt((offNode % sizeof(m_paNodes[0])) == 0, + ("pNode=%p / offNode=%#zx vs m_paNodes=%p L %#x, each %#x bytes\n", + a_pNode, offNode, m_paNodes, m_cNodes, sizeof(m_paNodes[0])), + m_cErrors++, (uint32_t)kErr_MisalignedPointer); + AssertMsgReturnStmt(idxNode0 < m_cNodes, + ("pNode=%p vs m_paNodes=%p L %#x\n", a_pNode, m_paNodes, m_cNodes), + m_cErrors++, (uint32_t)kErr_PointerOutOfBound); + AssertMsgReturnStmt(ASMBitTest(m_pbmAlloc, idxNode0) == false, ("a_pNode=%p idxNode0=%#x\n", a_pNode, idxNode0), + m_cErrors++, (uint32_t)kErr_NodeIsFree); + return idxNode0 + 1; + } + + static inline bool isIdxRetOkay(uint32_t a_idxNode) RT_NOEXCEPT + { + return a_idxNode < (uint32_t)kErr_Last; + } + + static inline int idxErrToStatus(uint32_t a_idxNode) RT_NOEXCEPT + { + return (int)a_idxNode - (VERR_HARDAVL_INDEX_OUT_OF_BOUNDS - kErr_IndexOutOfBound); + } + + inline bool isIntValid(uint32_t a_idxNode1) RT_NOEXCEPT + { + return a_idxNode1 <= m_cNodes; + } + + inline int freeNode(NodeType *a_pNode) RT_NOEXCEPT + { + uint32_t idxNode1 = ptrToInt(a_pNode); + if (idxNode1 == (uint32_t)kNilIndex) + return 0; + if (idxNode1 < (uint32_t)kErr_Last) + { + AssertMsgReturnStmt(ASMAtomicBitTestAndSet(m_pbmAlloc, idxNode1 - 1) == false, + ("a_pNode=%p idxNode1=%#x\n", a_pNode, idxNode1), + m_cErrors++, kErr_NodeIsFree); + return 0; + } + return (int)idxNode1; + } + + inline NodeType *allocateNode(void) RT_NOEXCEPT + { + /* + * Use the hint first, then scan the whole bitmap. + * Note! We don't expect concurrent allocation calls, so no need to repeat. + */ + uint32_t const idxHint = m_idxAllocHint; + uint32_t idxNode0; + if ( idxHint >= m_cNodes + || (int32_t)(idxNode0 = (uint32_t)ASMBitNextSet(m_pbmAlloc, m_cNodes, idxHint)) < 0) + idxNode0 = (uint32_t)ASMBitFirstSet(m_pbmAlloc, m_cNodes); + if ((int32_t)idxNode0 >= 0) + { + if (ASMAtomicBitTestAndClear(m_pbmAlloc, idxNode0) == true) + { + m_idxAllocHint = idxNode0; + return &m_paNodes[idxNode0]; + } + AssertMsgFailed(("idxNode0=%#x\n", idxNode0)); + m_cErrors++; + } + return NULL; + } +}; + + +/** + * Placeholder structure for ring-3 slab allocator. + */ +typedef struct RTCHardAvlTreeSlabAllocatorR3_T +{ + /** Pointer to an array of nodes. */ + RTR3PTR m_paNodes; + /** Node allocation bitmap: 1 = free, 0 = allocated. */ + RTR3PTR m_pbmAlloc; + /** Max number of nodes in m_paNodes and valid bits in m_pbmAlloc. */ + uint32_t m_cNodes; + /** Pointer error counter. */ + uint32_t m_cErrors; + /** Allocation hint. */ + uint32_t m_idxAllocHint; + uint32_t m_uPadding; +} RTCHardAvlTreeSlabAllocatorR3_T; +AssertCompileSize(RTCHardAvlTreeSlabAllocatorR3_T, + sizeof(RTCHardAvlTreeSlabAllocator<RTUINT128U>) - (sizeof(void *) - sizeof(RTR3PTR)) * 2); + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_hardavlslaballocator_h */ + diff --git a/include/iprt/cpp/list.h b/include/iprt/cpp/list.h new file mode 100644 index 00000000..864c3329 --- /dev/null +++ b/include/iprt/cpp/list.h @@ -0,0 +1,1143 @@ +/** @file + * IPRT - Generic List Class. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_list_h +#define IPRT_INCLUDED_cpp_list_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cpp/meta.h> +#include <iprt/mem.h> +#include <iprt/string.h> /* for memcpy */ +#include <iprt/assert.h> + +#include <new> /* For std::bad_alloc */ + +/** @defgroup grp_rt_cpp_list C++ List support + * @ingroup grp_rt_cpp + * + * @brief Generic C++ list class support. + * + * This list classes manage any amount of data in a fast and easy to use way. + * They have no dependencies on STL, only on generic memory management methods + * of IRPT. This allows list handling in situations where the use of STL + * container classes is forbidden. + * + * Not all of the functionality of STL container classes is implemented. There + * are no iterators or any other high level access/modifier methods (e.g. + * std::algorithms). + * + * The implementation is array based which allows fast access to the items. + * Appending items is usually also fast, cause the internal array is + * preallocated. To minimize the memory overhead, native types (that is + * everything smaller then the size of void*) are directly saved in the array. + * If bigger types are used (e.g. RTCString) the internal array is an array of + * pointers to the objects. + * + * The size of the internal array will usually not shrink, but grow + * automatically. Only certain methods, like RTCList::clear or the "=" operator + * will reset any previously allocated memory. You can call + * RTCList::setCapacity for manual adjustment. If the size of an new list will + * be known, calling the constructor with the necessary capacity will speed up + * the insertion of the new items. + * + * For the full public interface these list classes offer see RTCListBase. + * + * There are some requirements for the types used which follow: + * -# They need a default and a copy constructor. + * -# Some methods (e.g. RTCList::contains) need an equal operator. + * -# If the type is some complex class (that is, having a constructor which + * allocates members on the heap) it has to be greater than sizeof(void*) to + * be used correctly. If this is not the case you can manually overwrite the + * list behavior. Just add T* as a second parameter to the list template if + * your class is called T. Another possibility is to specialize the list for + * your target class. See below for more information. + * + * The native types like int, bool, ptr, ..., are meeting this criteria, so + * they are save to use. + * + * Please note that the return type of some of the getter methods are slightly + * different depending on the list type. Native types return the item by value, + * items with a size greater than sizeof(void*) by reference. As native types + * saved directly in the internal array, returning a reference to them (and + * saving them in a reference as well) would make them invalid (or pointing to + * a wrong item) when the list is changed in the meanwhile. Returning a + * reference for bigger types isn't problematic and makes sure we get out the + * best speed of the list. The one exception to this rule is the index + * operator[]. This operator always return a reference to make it possible to + * use it as a lvalue. Its your responsibility to make sure the list isn't + * changed when using the value as reference returned by this operator. + * + * The list class is reentrant. For a thread-safe variant see RTCMTList. + * + * Implementation details: + * It is possible to specialize any type. This might be necessary to get the + * best speed out of the list. Examples are the 64-bit types, which use the + * native (no pointers) implementation even on a 32-bit host. Consult the + * source code for more details. + * + * Current specialized implementations: + * - int64_t: RTCList<int64_t> + * - uint64_t: RTCList<uint64_t> + * + * @{ + */ + +/** + * The guard definition. + */ +template <bool G> +class RTCListGuard; + +/** + * The default guard which does nothing. + */ +template <> +class RTCListGuard<false> +{ +public: + inline void enterRead() const {} + inline void leaveRead() const {} + inline void enterWrite() {} + inline void leaveWrite() {} + + /* Define our own new and delete. */ +#ifdef RT_NEED_NEW_AND_DELETE + RTMEM_IMPLEMENT_NEW_AND_DELETE(); +#else + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +#endif +}; + +/** + * General helper template for managing native values in RTCListBase. + */ +template <typename T1, typename T2> +class RTCListHelper +{ +public: + static inline void set(T2 *p, size_t i, const T1 &v) { p[i] = v; } + static inline T1 & at(T2 *p, size_t i) { return p[i]; } + static inline const T1 &atConst(T2 const *p, size_t i) { return p[i]; } + static inline size_t find(T2 *p, const T1 &v, size_t cElements) + { + size_t i = cElements; + while (i-- > 0) + if (p[i] == v) + return i; + return cElements; + } + static inline void copyTo(T2 *p, T2 *const p1 , size_t iTo, size_t cSize) + { + if (cSize > 0) + memcpy(&p[iTo], &p1[0], sizeof(T1) * cSize); + } + static inline void erase(T2 * /* p */, size_t /* i */) { /* Nothing to do here. */ } + static inline void eraseRange(T2 * /* p */, size_t /* cFrom */, size_t /* cSize */) { /* Nothing to do here. */ } +}; + +/** + * Specialized helper template for managing pointer values in RTCListBase. + */ +template <typename T1> +class RTCListHelper<T1, T1*> +{ +public: + static inline void set(T1 **p, size_t i, const T1 &v) { p[i] = new T1(v); } + static inline T1 & at(T1 **p, size_t i) { return *p[i]; } + static inline const T1 &atConst(T1 * const *p, size_t i) { return *p[i]; } + static inline size_t find(T1 **p, const T1 &v, size_t cElements) + { + size_t i = cElements; + while (i-- > 0) + if (*p[i] == v) + return i; + return cElements; + } + static inline void copyTo(T1 **p, T1 **const p1 , size_t iTo, size_t cSize) + { + for (size_t i = 0; i < cSize; ++i) + p[iTo + i] = new T1(*p1[i]); + } + static inline void erase(T1 **p, size_t i) { delete p[i]; } + static inline void eraseRange(T1 **p, size_t iFrom, size_t cItems) + { + while (cItems-- > 0) + delete p[iFrom++]; + } +}; + +/** + * This is the base class for all other list classes. It implements the + * necessary list functionality in a type independent way and offers the public + * list interface to the user. + */ +template <class T, typename ITYPE, bool MT> +class RTCListBase +{ + /** @name Traits. + * + * Defines the return type of most of the getter methods. If the internal + * used type is a pointer, we return a reference. If not we return by + * value. + * + * @{ + */ + typedef typename RTCIfPtr<ITYPE, T&, T>::result GET_RTYPE; + typedef typename RTCIfPtr<ITYPE, const T&, T>::result GET_CRTYPE; + /** @} */ + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCListBase(size_t cCapacity = kDefaultCapacity) + : m_pArray(0) + , m_cElements(0) + , m_cCapacity(0) + { + if (cCapacity > 0) + growArray(cCapacity); + } + + /** + * Creates a copy of another list. + * + * The other list will be fully copied and the capacity will be the same as + * the size of the other list. + * + * @param other The list to copy. + * @throws std::bad_alloc + */ + RTCListBase(const RTCListBase<T, ITYPE, MT>& other) + : m_pArray(0) + , m_cElements(0) + , m_cCapacity(0) + { + other.m_guard.enterRead(); + + size_t const cElementsOther = other.m_cElements; + resizeArrayNoErase(cElementsOther); + RTCListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, cElementsOther); + m_cElements = cElementsOther; + + other.m_guard.leaveRead(); + } + + /** + * Destructor. + */ + ~RTCListBase() + { + RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements); + if (m_pArray) + { + RTMemFree(m_pArray); + m_pArray = NULL; + } + m_cElements = m_cCapacity = 0; + } + + /** + * Sets a new capacity within the list. + * + * If the new capacity is bigger than the old size, it will be simply + * preallocated more space for the new items. If the new capacity is + * smaller than the previous size, items at the end of the list will be + * deleted. + * + * @param cCapacity The new capacity within the list. + * @throws std::bad_alloc + */ + void setCapacity(size_t cCapacity) + { + m_guard.enterWrite(); + resizeArray(cCapacity); + m_guard.leaveWrite(); + } + + /** + * Return the current capacity of the list. + * + * @return The actual capacity. + */ + size_t capacity() const + { + m_guard.enterRead(); + size_t cRet = m_cCapacity; + m_guard.leaveRead(); + return cRet; + } + + /** + * Check if an list contains any items. + * + * @return True if there is more than zero items, false otherwise. + */ + bool isEmpty() const + { + m_guard.enterRead(); + bool fEmpty = m_cElements == 0; + m_guard.leaveRead(); + return fEmpty; + } + + /** + * Return the current count of elements within the list. + * + * @return The current element count. + */ + size_t size() const + { + m_guard.enterRead(); + size_t cRet = m_cElements; + m_guard.leaveRead(); + return cRet; + } + + /** + * Inserts an item to the list at position @a i. + * + * @param i The position of the new item. The must be within or at the + * exact end of the list. Indexes specified beyond the end of + * the list will be changed to an append() operation and strict + * builds will raise an assert. + * @param val The new item. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase<T, ITYPE, MT> &insert(size_t i, const T &val) + { + m_guard.enterWrite(); + + AssertMsgStmt(i <= m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements); + + if (m_cElements == m_cCapacity) + growArray(m_cCapacity + kDefaultCapacity); + + memmove(&m_pArray[i + 1], &m_pArray[i], (m_cElements - i) * sizeof(ITYPE)); + RTCListHelper<T, ITYPE>::set(m_pArray, i, val); + ++m_cElements; + + m_guard.leaveWrite(); + return *this; + } + + /** + * Inserts a list to the list at position @a i. + * + * @param i The position of the new item. The must be within or at the + * exact end of the list. Indexes specified beyond the end of + * the list will be changed to an append() operation and strict + * builds will raise an assert. + * @param other The other list. This MUST not be the same as the destination + * list, will assert and return without doing anything if this + * happens. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase<T, ITYPE, MT> &insert(size_t i, const RTCListBase<T, ITYPE, MT> &other) + { + AssertReturn(this != &other, *this); + + other.m_guard.enterRead(); + m_guard.enterWrite(); + + AssertMsgStmt(i <= m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements); + + size_t cElementsOther = other.m_cElements; + if (RT_LIKELY(cElementsOther > 0)) + { + if (m_cCapacity - m_cElements < cElementsOther) + growArray(m_cCapacity + (cElementsOther - (m_cCapacity - m_cElements))); + if (i < m_cElements) + memmove(&m_pArray[i + cElementsOther], &m_pArray[i], (m_cElements - i) * sizeof(ITYPE)); + + RTCListHelper<T, ITYPE>::copyTo(&m_pArray[i], other.m_pArray, 0, cElementsOther); + m_cElements += cElementsOther; + } + + m_guard.leaveWrite(); + other.m_guard.leaveRead(); + return *this; + } + + /** + * Prepend an item to the list. + * + * @param val The new item. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase<T, ITYPE, MT> &prepend(const T &val) + { + return insert(0, val); + } + + /** + * Prepend a list of type T to the list. + * + * @param other The list to prepend. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase<T, ITYPE, MT> &prepend(const RTCListBase<T, ITYPE, MT> &other) + { + return insert(0, other); + } + + /** + * Append a default item to the list. + * + * @return a mutable reference to the item + * @throws std::bad_alloc + */ + GET_RTYPE append() + { + m_guard.enterWrite(); + if (m_cElements == m_cCapacity) + growArray(m_cCapacity + kDefaultCapacity); + RTCListHelper<T, ITYPE>::set(m_pArray, m_cElements, T()); + GET_RTYPE rRet = RTCListHelper<T, ITYPE>::at(m_pArray, m_cElements); + ++m_cElements; + m_guard.leaveWrite(); + + return rRet; + } + + /** + * Append an item to the list. + * + * @param val The new item. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase<T, ITYPE, MT> &append(const T &val) + { + m_guard.enterWrite(); + if (m_cElements == m_cCapacity) + growArray(m_cCapacity + kDefaultCapacity); + RTCListHelper<T, ITYPE>::set(m_pArray, m_cElements, val); + ++m_cElements; + m_guard.leaveWrite(); + + return *this; + } + + /** + * Append a list of type T to the list. + * + * @param other The list to append. Must not be the same as the destination + * list, will assert and return without doing anything. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase<T, ITYPE, MT> &append(const RTCListBase<T, ITYPE, MT> &other) + { + AssertReturn(this != &other, *this); + + other.m_guard.enterRead(); + m_guard.enterWrite(); + + insert(m_cElements, other); + + m_guard.leaveWrite(); + other.m_guard.leaveRead(); + return *this; + } + + /** + * Copy the items of the other list into this list. + * + * All previous items of this list are deleted. + * + * @param other The list to copy. + * @return a reference to this list. + */ + RTCListBase<T, ITYPE, MT> &operator=(const RTCListBase<T, ITYPE, MT>& other) + { + /* Prevent self assignment */ + if (RT_LIKELY(this != &other)) + { + other.m_guard.enterRead(); + m_guard.enterWrite(); + + /* Delete all items. */ + RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements); + + /* Need we to realloc memory. */ + if (other.m_cElements != m_cCapacity) + resizeArrayNoErase(other.m_cElements); + m_cElements = other.m_cElements; + + /* Copy new items. */ + RTCListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, other.m_cElements); + + m_guard.leaveWrite(); + other.m_guard.leaveRead(); + } + return *this; + } + + /** + * Compares if this list's items match the other list. + * + * @returns \c true if both lists contain the same items, \c false if not. + * @param other The list to compare this list with. + */ + bool operator==(const RTCListBase<T, ITYPE, MT>& other) + { + /* Prevent self comparrison */ + if (RT_LIKELY(this == &other)) + return true; + + other.m_guard.enterRead(); + m_guard.enterRead(); + + bool fEqual = true; + if (other.m_cElements == m_cElements) + { + for (size_t i = 0; i < m_cElements; i++) + { + if (RTCListHelper<T, ITYPE>::at(m_pArray, i) != RTCListHelper<T, ITYPE>::at(other.m_pArray, i)) + { + fEqual = false; + break; + } + } + } + else + fEqual = false; + + m_guard.leaveRead(); + other.m_guard.leaveRead(); + + return fEqual; + } + + /** + * Compares if this list's items do not match the other list. + * + * @returns \c true if the lists do not match, \c false if otherwise. + * @param other The list to compare this list with. + */ + bool operator!=(const RTCListBase<T, ITYPE, MT>& other) + { + return !(*this == other); + } + + /** + * Replace an item in the list. + * + * @param i The position of the item to replace. If this is out of range, + * the request will be ignored, strict builds will assert. + * @param val The new value. + * @return a reference to this list. + */ + RTCListBase<T, ITYPE, MT> &replace(size_t i, const T &val) + { + m_guard.enterWrite(); + + if (i < m_cElements) + { + RTCListHelper<T, ITYPE>::erase(m_pArray, i); + RTCListHelper<T, ITYPE>::set(m_pArray, i, val); + } + else + AssertMsgFailed(("i=%zu m_cElements=%zu\n", i, m_cElements)); + + m_guard.leaveWrite(); + return *this; + } + + /** + * Applies a filter of type T to this list. + * + * @param other The list which contains the elements to filter out from this list. + * @return a reference to this list. + */ + RTCListBase<T, ITYPE, MT> &filter(const RTCListBase<T, ITYPE, MT> &other) + { + AssertReturn(this != &other, *this); + + other.m_guard.enterRead(); + m_guard.enterWrite(); + + for (size_t i = 0; i < m_cElements; i++) + { + for (size_t f = 0; f < other.m_cElements; f++) + { + if (RTCListHelper<T, ITYPE>::at(m_pArray, i) == RTCListHelper<T, ITYPE>::at(other.m_pArray, f)) + removeAtLocked(i); + } + } + + m_guard.leaveWrite(); + other.m_guard.leaveRead(); + return *this; + } + + /** + * Return the first item as constant object. + * + * @return A reference or pointer to the first item. + * + * @note No boundary checks are done. Make sure there is at least one + * element. + */ + GET_CRTYPE first() const + { + m_guard.enterRead(); + Assert(m_cElements > 0); + GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, 0); + m_guard.leaveRead(); + return res; + } + + /** + * Return the first item. + * + * @return A reference or pointer to the first item. + * + * @note No boundary checks are done. Make sure there is at least one + * element. + */ + GET_RTYPE first() + { + m_guard.enterRead(); + Assert(m_cElements > 0); + GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, 0); + m_guard.leaveRead(); + return res; + } + + /** + * Return the last item as constant object. + * + * @return A reference or pointer to the last item. + * + * @note No boundary checks are done. Make sure there is at least one + * element. + */ + GET_CRTYPE last() const + { + m_guard.enterRead(); + Assert(m_cElements > 0); + GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, m_cElements - 1); + m_guard.leaveRead(); + return res; + } + + /** + * Return the last item. + * + * @return A reference or pointer to the last item. + * + * @note No boundary checks are done. Make sure there is at least one + * element. + */ + GET_RTYPE last() + { + m_guard.enterRead(); + Assert(m_cElements > 0); + GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, m_cElements - 1); + m_guard.leaveRead(); + return res; + } + + /** + * Return the item at position @a i as constant object. + * + * @param i The position of the item to return. This better not be out of + * bounds, however should it be the last element of the array + * will be return and strict builds will raise an assertion. + * Should the array be empty, a crash is very likely. + * @return The item at position @a i. + */ + GET_CRTYPE at(size_t i) const + { + m_guard.enterRead(); + AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1); + GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, i); + m_guard.leaveRead(); + return res; + } + + /** + * Return the item at position @a i. + * + * @param i The position of the item to return. This better not be out of + * bounds, however should it be the last element of the array + * will be return and strict builds will raise an assertion. + * Should the array be empty, a crash is very likely. + * @return The item at position @a i. + */ + GET_RTYPE at(size_t i) + { + m_guard.enterRead(); + AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1); + GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, i); + m_guard.leaveRead(); + return res; + } + + /** + * Return the item at position @a i as mutable reference. + * + * @param i The position of the item to return. This better not be out of + * bounds, however should it be the last element of the array + * will be return and strict builds will raise an assertion. + * Should the array be empty, a crash is very likely. + * @return The item at position @a i. + */ + T &operator[](size_t i) + { + m_guard.enterRead(); + AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1); + T &res = RTCListHelper<T, ITYPE>::at(m_pArray, i); + m_guard.leaveRead(); + return res; + } + + /** + * Return the item at position @a i as immutable reference. + * + * @param i The position of the item to return. This better not be out of + * bounds, however should it be the last element of the array + * will be return and strict builds will raise an assertion. + * Should the array be empty, a crash is very likely. + * @return The item at position @a i. + */ + const T &operator[](size_t i) const + { + m_guard.enterRead(); + AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1); + const T &rRet = RTCListHelper<T, ITYPE>::atConst(m_pArray, i); + m_guard.leaveRead(); + return rRet; + } + + /** + * Return a copy of the item at position @a i or default value if out of range. + * + * @param i The position of the item to return. + * @return Copy of the item at position @a i or default value. + */ + T value(size_t i) const + { + m_guard.enterRead(); + if (RT_LIKELY(i < m_cElements)) + { + T res = RTCListHelper<T, ITYPE>::at(m_pArray, i); + m_guard.leaveRead(); + return res; + } + m_guard.leaveRead(); + return T(); + } + + /** + * Return a copy of the item at position @a i, or @a defaultVal if out of range. + * + * @param i The position of the item to return. + * @param defaultVal The value to return in case @a i is invalid. + * @return Copy of the item at position @a i or @a defaultVal. + */ + T value(size_t i, const T &defaultVal) const + { + m_guard.enterRead(); + if (RT_LIKELY(i < m_cElements)) + { + T res = RTCListHelper<T, ITYPE>::at(m_pArray, i); + m_guard.leaveRead(); + return res; + } + m_guard.leaveRead(); + return defaultVal; + } + + /** + * Check if @a val is contained in the array. + * + * @param val The value to check for. + * @return true if it is found, false otherwise. + */ + bool contains(const T &val) const + { + m_guard.enterRead(); + bool fRc = RTCListHelper<T, ITYPE>::find(m_pArray, val, m_cElements) < m_cElements; + m_guard.leaveRead(); + return fRc; + } + + /** + * Remove the first item. + * + * @note You should make sure the list isn't empty. Strict builds will assert. + * The other builds will quietly ignore the request. + */ + void removeFirst() + { + removeAt(0); + } + + /** + * Remove the last item. + * + * @note You should make sure the list isn't empty. Strict builds will assert. + * The other builds will quietly ignore the request. + */ + void removeLast() + { + m_guard.enterWrite(); + removeAtLocked(m_cElements - 1); + m_guard.leaveWrite(); + } + + /** + * Remove the item at position @a i. + * + * @param i The position of the item to remove. Out of bounds values will + * be ignored and an assertion will be raised in strict builds. + */ + void removeAt(size_t i) + { + m_guard.enterWrite(); + removeAtLocked(i); + m_guard.leaveWrite(); + } + + /** + * Remove a range of items from the list. + * + * @param iStart The start position of the items to remove. + * @param iEnd The end position of the items to remove (excluded). + */ + void removeRange(size_t iStart, size_t iEnd) + { + AssertReturnVoid(iStart <= iEnd); + m_guard.enterWrite(); + + AssertMsgStmt(iEnd <= m_cElements, ("iEnd=%zu m_cElements=%zu\n", iEnd, m_cElements), iEnd = m_cElements); + AssertMsgStmt(iStart < m_cElements, ("iStart=%zu m_cElements=%zu\n", iStart, m_cElements), iStart = m_cElements); + size_t const cElements = iEnd - iStart; + if (cElements > 0) + { + Assert(iStart < m_cElements); + RTCListHelper<T, ITYPE>::eraseRange(m_pArray, iStart, cElements); + if (m_cElements > iEnd) + memmove(&m_pArray[iStart], &m_pArray[iEnd], (m_cElements - iEnd) * sizeof(ITYPE)); + m_cElements -= cElements; + } + + m_guard.leaveWrite(); + } + + /** + * Delete all items in the list. + */ + void clear() + { + m_guard.enterWrite(); + + /* Values cleanup */ + RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements); + if (m_cElements != kDefaultCapacity) + resizeArrayNoErase(kDefaultCapacity); + m_cElements = 0; + + m_guard.leaveWrite(); + } + + /** + * Return the raw array. + * + * For native types this is a pointer to continuous memory of the items. For + * pointer types this is a continuous memory of pointers to the items. + * + * @warning If you change anything in the underlaying list, this memory + * will very likely become invalid. So take care when using this + * method and better try to avoid using it. + * + * @returns the raw memory. + */ + ITYPE *raw() const + { + m_guard.enterRead(); + ITYPE *pRet = m_pArray; + m_guard.leaveRead(); + return pRet; + } + + RTCListBase<T, ITYPE, MT> &operator<<(const T &val) + { + return append(val); + } + + /* Define our own new and delete. */ +#ifdef RT_NEED_NEW_AND_DELETE + RTMEM_IMPLEMENT_NEW_AND_DELETE(); +#else + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +#endif + + /** + * The default capacity of the list. This is also used as grow factor. + */ + static const size_t kDefaultCapacity; + +protected: + + /** + * Generic resizes the array, surplus elements are erased. + * + * @param cElementsNew The new array size. + * @throws std::bad_alloc. + */ + void resizeArray(size_t cElementsNew) + { + /* Same size? */ + if (cElementsNew == m_cCapacity) + return; + + /* If we get smaller we have to delete some of the objects at the end + of the list. */ + if ( cElementsNew < m_cElements + && m_pArray) + RTCListHelper<T, ITYPE>::eraseRange(m_pArray, cElementsNew, m_cElements - cElementsNew); + + resizeArrayNoErase(cElementsNew); + } + + /** + * Resizes the array without doing the erase() thing on surplus elements. + * + * @param cElementsNew The new array size. + * @throws std::bad_alloc. + */ + void resizeArrayNoErase(size_t cElementsNew) + { + /* Same size? */ + if (cElementsNew == m_cCapacity) + return; + + /* Resize the array. */ + if (cElementsNew > 0) + { + void *pvNew = RTMemRealloc(m_pArray, sizeof(ITYPE) * cElementsNew); + if (!pvNew) + { +#ifdef RT_EXCEPTIONS_ENABLED + throw std::bad_alloc(); +#endif + return; + } + m_pArray = static_cast<ITYPE*>(pvNew); + } + /* If we get zero we delete the array it self. */ + else if (m_pArray) + { + RTMemFree(m_pArray); + m_pArray = NULL; + } + + m_cCapacity = cElementsNew; + if (m_cElements > cElementsNew) + m_cElements = cElementsNew; + } + + /** + * Special realloc method which require that the array will grow. + * + * @param cElementsNew The new array size. + * @throws std::bad_alloc. + * @note No boundary checks are done! + */ + void growArray(size_t cElementsNew) + { + Assert(cElementsNew > m_cCapacity); + void *pvNew = RTMemRealloc(m_pArray, sizeof(ITYPE) * cElementsNew); + if (pvNew) + { + m_cCapacity = cElementsNew; + m_pArray = static_cast<ITYPE*>(pvNew); + } + else + { +#ifdef RT_EXCEPTIONS_ENABLED + throw std::bad_alloc(); +#endif + } + } + + /** + * Remove the item at position @a i. + * + * @param i The position of the item to remove. Out of bounds values will + * be ignored and an assertion will be raised in strict builds. + * @remarks + */ + void removeAtLocked(size_t i) + { + AssertMsgReturnVoid(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements)); + + RTCListHelper<T, ITYPE>::erase(m_pArray, i); + if (i < m_cElements - 1) + memmove(&m_pArray[i], &m_pArray[i + 1], (m_cElements - i - 1) * sizeof(ITYPE)); + --m_cElements; + } + + + /** The internal list array. */ + ITYPE *m_pArray; + /** The current count of items in use. */ + size_t m_cElements; + /** The current capacity of the internal array. */ + size_t m_cCapacity; + /** The guard used to serialize the access to the items. */ + RTCListGuard<MT> m_guard; +}; + +template <class T, typename ITYPE, bool MT> +const size_t RTCListBase<T, ITYPE, MT>::kDefaultCapacity = 10; + +/** + * Template class which automatically determines the type of list to use. + * + * @see RTCListBase + */ +template <class T, typename ITYPE = typename RTCIf<(sizeof(T) > sizeof(void*)), T*, T>::result> +class RTCList : public RTCListBase<T, ITYPE, false> +{ + /* Traits */ + typedef RTCListBase<T, ITYPE, false> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + RTCList(const BASE &other) + : BASE(other) {} + + /* Define our own new and delete. */ +#ifdef RT_NEED_NEW_AND_DELETE + RTMEM_IMPLEMENT_NEW_AND_DELETE(); +#else + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +#endif +}; + +/** + * Specialized class for using the native type list for unsigned 64-bit + * values even on a 32-bit host. + * + * @see RTCListBase + */ +template <> +class RTCList<uint64_t>: public RTCListBase<uint64_t, uint64_t, false> +{ + /* Traits */ + typedef RTCListBase<uint64_t, uint64_t, false> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ +#ifdef RT_NEED_NEW_AND_DELETE + RTMEM_IMPLEMENT_NEW_AND_DELETE(); +#else + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +#endif +}; + +/** + * Specialized class for using the native type list for signed 64-bit + * values even on a 32-bit host. + * + * @see RTCListBase + */ +template <> +class RTCList<int64_t>: public RTCListBase<int64_t, int64_t, false> +{ + /* Traits */ + typedef RTCListBase<int64_t, int64_t, false> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ +#ifdef RT_NEED_NEW_AND_DELETE + RTMEM_IMPLEMENT_NEW_AND_DELETE(); +#else + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +#endif +}; + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_list_h */ + diff --git a/include/iprt/cpp/lock.h b/include/iprt/cpp/lock.h new file mode 100644 index 00000000..3a0c4bcd --- /dev/null +++ b/include/iprt/cpp/lock.h @@ -0,0 +1,179 @@ +/** @file + * IPRT - Classes for Scope-based Locking. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_lock_h +#define IPRT_INCLUDED_cpp_lock_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/critsect.h> +#ifdef RT_LOCK_STRICT +# include <iprt/lockvalidator.h> +#endif + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_cpp_lock C++ Scope-based Locking + * @ingroup grp_rt_cpp + * @{ + */ + +class RTCLock; + +/** + * The mutex lock. + * + * This is used as an object data member if the intention is to lock + * a single object. This can also be used statically, initialized in + * a global variable, for class wide purposes. + * + * This is best used together with RTCLock. + */ +class RTCLockMtx +{ +friend class RTCLock; + +private: + RTCRITSECT mMtx; + +public: + RTCLockMtx() + { +#ifdef RT_LOCK_STRICT_ORDER + RTCritSectInitEx(&mMtx, 0 /*fFlags*/, + RTLockValidatorClassCreateUnique(RT_SRC_POS, NULL), + RTLOCKVAL_SUB_CLASS_NONE, NULL); +#else + RTCritSectInit(&mMtx); +#endif + } + + /** Use to when creating locks that belongs in the same "class". */ + RTCLockMtx(RT_SRC_POS_DECL, uint32_t uSubClass = RTLOCKVAL_SUB_CLASS_NONE) + { +#ifdef RT_LOCK_STRICT_ORDER + RTCritSectInitEx(&mMtx, 0 /*fFlags*/, + RTLockValidatorClassForSrcPos(RT_SRC_POS_ARGS, NULL), + uSubClass, NULL); +#else + NOREF(uSubClass); + RTCritSectInit(&mMtx); + RT_SRC_POS_NOREF(); +#endif + } + + ~RTCLockMtx() + { + RTCritSectDelete(&mMtx); + } + + /* lock() and unlock() are private so that only friend RTCLock can access + them. */ +private: + inline void lock() + { + RTCritSectEnter(&mMtx); + } + + inline void unlock() + { + RTCritSectLeave(&mMtx); + } +}; + + +/** + * The stack object for automatic locking and unlocking. + * + * This is a helper class for automatic locks, to simplify requesting a + * RTCLockMtx and to not forget releasing it. To request a RTCLockMtx, simply + * create an instance of RTCLock on the stack and pass the mutex to it: + * + * @code + extern RTCLockMtx gMtx; // wherever this is + ... + if (...) + { + RTCLock lock(gMtx); + ... // do stuff + // when lock goes out of scope, destructor releases the mutex + } + @endcode + * + * You can also explicitly release the mutex by calling RTCLock::release(). + * This might be helpful if the lock doesn't go out of scope early enough + * for your mutex to be released. + */ +class RTCLock +{ +private: + /** Reference to the lock we're holding. */ + RTCLockMtx &m_rMtx; + /** Whether we're currently holding the lock of if it was already + * explictily released by the release() method. */ + bool m_fLocked; + +public: + RTCLock(RTCLockMtx &a_rMtx) + : m_rMtx(a_rMtx) + { + m_rMtx.lock(); + m_fLocked = true; + } + + ~RTCLock() + { + if (m_fLocked) + m_rMtx.unlock(); + } + + inline void release() + { + if (m_fLocked) + { + m_rMtx.unlock(); + m_fLocked = false; + } + } +}; + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_cpp_lock_h */ + diff --git a/include/iprt/cpp/meta.h b/include/iprt/cpp/meta.h new file mode 100644 index 00000000..e6b9796e --- /dev/null +++ b/include/iprt/cpp/meta.h @@ -0,0 +1,125 @@ +/** @file + * IPRT - C++ Meta programming. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_meta_h +#define IPRT_INCLUDED_cpp_meta_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/** @defgroup grp_rt_cpp_meta C++ Meta programming utilities + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * Check for a condition on compile time and dependent of the result TrueResult + * or FalseResult will be defined. + * + * @param Condition Condition to check. + * @param TrueResult Result when condition is true. + * @param FalseResult Result when condition is false + */ +template <bool Condition, typename TrueResult, typename FalseResult> +struct RTCIf; + +/** + * Check for a condition on compile time and dependent of the result TrueResult + * or FalseResult will be defined. + * + * True specialization of RTCIf. + * + * @param TrueResult Result when condition is true. + * @param FalseResult Result when condition is false + */ +template <typename TrueResult, typename FalseResult> +struct RTCIf<true, TrueResult, FalseResult> +{ + typedef TrueResult result; +}; + +/** + * Check for a condition on compile time and dependent of the result TrueResult + * or FalseResult will be defined. + * + * False specialization of RTCIf. + * + * @param TrueResult Result when condition is true. + * @param FalseResult Result when condition is false + */ +template <typename TrueResult, typename FalseResult> +struct RTCIf<false, TrueResult, FalseResult> +{ + typedef FalseResult result; +}; + +/** + * Check if @a T is a pointer or not at compile time and dependent of the + * result TrueResult or FalseResult will be defined. + * + * False version of RTCIfPtr. + * + * @param Condition Condition to check. + * @param TrueResult Result when condition is true. + * @param FalseResult Result when condition is false + */ +template <class T, typename TrueResult, typename FalseResult> +struct RTCIfPtr +{ + typedef FalseResult result; +}; + +/** + * Check if @a T is a pointer or not at compile time and dependent of the + * result TrueResult or FalseResult will be defined. + * + * True specialization of RTCIfPtr. + * + * @param Condition Condition to check. + * @param TrueResult Result when condition is true. + * @param FalseResult Result when condition is false + */ +template <class T, typename TrueResult, typename FalseResult> +struct RTCIfPtr<T*, TrueResult, FalseResult> +{ + typedef TrueResult result; +}; + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_meta_h */ + diff --git a/include/iprt/cpp/ministring.h b/include/iprt/cpp/ministring.h new file mode 100644 index 00000000..80ad7cb5 --- /dev/null +++ b/include/iprt/cpp/ministring.h @@ -0,0 +1,1638 @@ +/** @file + * IPRT - C++ string class. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_ministring_h +#define IPRT_INCLUDED_cpp_ministring_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/mem.h> +#include <iprt/string.h> +#include <iprt/stdarg.h> +#include <iprt/cpp/list.h> + +#include <new> + + +/** @defgroup grp_rt_cpp_string C++ String support + * @ingroup grp_rt_cpp + * @{ + */ + +/** @brief C++ string class. + * + * This is a C++ string class that does not depend on anything else except IPRT + * memory management functions. Semantics are like in std::string, except it + * can do a lot less. + * + * Note that RTCString does not differentiate between NULL strings + * and empty strings. In other words, RTCString("") and RTCString(NULL) + * behave the same. In both cases, RTCString allocates no memory, reports + * a zero length and zero allocated bytes for both, and returns an empty + * C-style string from c_str(). + * + * @note RTCString ASSUMES that all strings it deals with are valid UTF-8. + * The caller is responsible for not breaking this assumption. + */ +#ifdef VBOX + /** @remarks Much of the code in here used to be in com::Utf8Str so that + * com::Utf8Str can now derive from RTCString and only contain code + * that is COM-specific, such as com::Bstr conversions. Compared to + * the old Utf8Str though, RTCString always knows the length of its + * member string and the size of the buffer so it can use memcpy() + * instead of strdup(). + */ +#endif +class RT_DECL_CLASS RTCString +{ +public: +#if defined(RT_NEED_NEW_AND_DELETE) && ( !defined(RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF) \ + || defined(RTMEM_NO_WRAP_SOME_NEW_AND_DELETE_TO_EF)) + RTMEM_IMPLEMENT_NEW_AND_DELETE(); +#else + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +#endif + + /** + * Creates an empty string that has no memory allocated. + */ + RTCString() + : m_psz(NULL), + m_cch(0), + m_cbAllocated(0) + { + } + + /** + * Creates a copy of another RTCString. + * + * This allocates s.length() + 1 bytes for the new instance, unless s is empty. + * + * @param a_rSrc The source string. + * + * @throws std::bad_alloc + */ + RTCString(const RTCString &a_rSrc) + { + copyFromN(a_rSrc.m_psz, a_rSrc.m_cch); + } + + /** + * Creates a copy of a C-style string. + * + * This allocates strlen(pcsz) + 1 bytes for the new instance, unless s is empty. + * + * @param pcsz The source string. + * + * @throws std::bad_alloc + */ + RTCString(const char *pcsz) + { + copyFromN(pcsz, pcsz ? strlen(pcsz) : 0); + } + + /** + * Create a partial copy of another RTCString. + * + * @param a_rSrc The source string. + * @param a_offSrc The byte offset into the source string. + * @param a_cchSrc The max number of chars (encoded UTF-8 bytes) + * to copy from the source string. + */ + RTCString(const RTCString &a_rSrc, size_t a_offSrc, size_t a_cchSrc = npos) + { + if (a_offSrc < a_rSrc.m_cch) + copyFromN(&a_rSrc.m_psz[a_offSrc], RT_MIN(a_cchSrc, a_rSrc.m_cch - a_offSrc)); + else + { + m_psz = NULL; + m_cch = 0; + m_cbAllocated = 0; + } + } + + /** + * Create a partial copy of a C-style string. + * + * @param a_pszSrc The source string (UTF-8). + * @param a_cchSrc The max number of chars (encoded UTF-8 bytes) + * to copy from the source string. This must not + * be '0' as the compiler could easily mistake + * that for the va_list constructor. + */ + RTCString(const char *a_pszSrc, size_t a_cchSrc) + { + size_t cchMax = a_pszSrc ? RTStrNLen(a_pszSrc, a_cchSrc) : 0; + copyFromN(a_pszSrc, RT_MIN(a_cchSrc, cchMax)); + } + + /** + * Create a string containing @a a_cTimes repetitions of the character @a + * a_ch. + * + * @param a_cTimes The number of times the character is repeated. + * @param a_ch The character to fill the string with. + */ + RTCString(size_t a_cTimes, char a_ch) + : m_psz(NULL), + m_cch(0), + m_cbAllocated(0) + { + Assert((unsigned)a_ch < 0x80); + if (a_cTimes) + { + reserve(a_cTimes + 1); + memset(m_psz, a_ch, a_cTimes); + m_psz[a_cTimes] = '\0'; + m_cch = a_cTimes; + } + } + + /** + * Create a new string given the format string and its arguments. + * + * @param a_pszFormat Pointer to the format string (UTF-8), + * @see pg_rt_str_format. + * @param a_va Argument vector containing the arguments + * specified by the format string. + * @sa printfV + * @remarks Not part of std::string. + */ + RTCString(const char *a_pszFormat, va_list a_va) RT_IPRT_FORMAT_ATTR(1, 0) + : m_psz(NULL), + m_cch(0), + m_cbAllocated(0) + { + printfV(a_pszFormat, a_va); + } + + /** + * Destructor. + */ + virtual ~RTCString() + { + cleanup(); + } + + /** + * String length in bytes. + * + * Returns the length of the member string in bytes, which is equal to strlen(c_str()). + * In other words, this does not count unicode codepoints; use utf8length() for that. + * The byte length is always cached so calling this is cheap and requires no + * strlen() invocation. + * + * @returns m_cbLength. + */ + size_t length() const + { + return m_cch; + } + + /** + * String length in unicode codepoints. + * + * As opposed to length(), which returns the length in bytes, this counts + * the number of unicode codepoints. This is *not* cached so calling this + * is expensive. + * + * @returns Number of codepoints in the member string. + */ + size_t uniLength() const + { + return m_psz ? RTStrUniLen(m_psz) : 0; + } + + /** + * The allocated buffer size (in bytes). + * + * Returns the number of bytes allocated in the internal string buffer, which is + * at least length() + 1 if length() > 0; for an empty string, this returns 0. + * + * @returns m_cbAllocated. + */ + size_t capacity() const + { + return m_cbAllocated; + } + + /** + * Make sure at that least cb of buffer space is reserved. + * + * Requests that the contained memory buffer have at least cb bytes allocated. + * This may expand or shrink the string's storage, but will never truncate the + * contained string. In other words, cb will be ignored if it's smaller than + * length() + 1. + * + * @param cb New minimum size (in bytes) of member memory buffer. + * + * @throws std::bad_alloc On allocation error. The object is left unchanged. + */ + void reserve(size_t cb) + { + if ( ( cb != m_cbAllocated + && cb > m_cch + 1) + || ( m_psz == NULL + && cb > 0)) + { + int rc = RTStrRealloc(&m_psz, cb); + if (RT_SUCCESS(rc)) + m_cbAllocated = cb; +#ifdef RT_EXCEPTIONS_ENABLED + else + throw std::bad_alloc(); +#endif + } + } + + /** + * A C like version of the reserve method, i.e. return code instead of throw. + * + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + * @param cb New minimum size (in bytes) of member memory buffer. + */ + int reserveNoThrow(size_t cb) RT_NOEXCEPT + { + if ( ( cb != m_cbAllocated + && cb > m_cch + 1) + || ( m_psz == NULL + && cb > 0)) + { + int rc = RTStrRealloc(&m_psz, cb); + if (RT_SUCCESS(rc)) + m_cbAllocated = cb; + else + return rc; + } + return VINF_SUCCESS; + } + + /** + * Deallocates all memory. + */ + inline void setNull() + { + cleanup(); + } + + /** + * Assigns a copy of pcsz to @a this. + * + * @param pcsz The source string. + * + * @throws std::bad_alloc On allocation failure. The object is left describing + * a NULL string. + * + * @returns Reference to the object. + */ + RTCString &operator=(const char *pcsz) + { + if (m_psz != pcsz) + { + cleanup(); + copyFromN(pcsz, pcsz ? strlen(pcsz) : 0); + } + return *this; + } + + /** + * Assigns a copy of s to @a this. + * + * @param s The source string. + * + * @throws std::bad_alloc On allocation failure. The object is left describing + * a NULL string. + * + * @returns Reference to the object. + */ + RTCString &operator=(const RTCString &s) + { + if (this != &s) + { + cleanup(); + copyFromN(s.m_psz, s.m_cch); + } + return *this; + } + + /** + * Assigns a copy of another RTCString. + * + * @param a_rSrc Reference to the source string. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + */ + RTCString &assign(const RTCString &a_rSrc); + + /** + * Assigns a copy of another RTCString. + * + * @param a_rSrc Reference to the source string. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int assignNoThrow(const RTCString &a_rSrc) RT_NOEXCEPT; + + /** + * Assigns a copy of a C-style string. + * + * @param a_pszSrc Pointer to the C-style source string. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @remarks ASSUMES valid + */ + RTCString &assign(const char *a_pszSrc); + + /** + * Assigns a copy of a C-style string. + * + * @param a_pszSrc Pointer to the C-style source string. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + * @remarks ASSUMES valid + */ + int assignNoThrow(const char *a_pszSrc) RT_NOEXCEPT; + + /** + * Assigns a partial copy of another RTCString. + * + * @param a_rSrc The source string. + * @param a_offSrc The byte offset into the source string. + * @param a_cchSrc The max number of chars (encoded UTF-8 bytes) + * to copy from the source string. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + */ + RTCString &assign(const RTCString &a_rSrc, size_t a_offSrc, size_t a_cchSrc = npos); + + /** + * Assigns a partial copy of another RTCString. + * + * @param a_rSrc The source string. + * @param a_offSrc The byte offset into the source string. + * @param a_cchSrc The max number of chars (encoded UTF-8 bytes) + * to copy from the source string. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int assignNoThrow(const RTCString &a_rSrc, size_t a_offSrc, size_t a_cchSrc = npos) RT_NOEXCEPT; + + /** + * Assigns a partial copy of a C-style string. + * + * @param a_pszSrc The source string (UTF-8). + * @param a_cchSrc The max number of chars (encoded UTF-8 bytes) + * to copy from the source string. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + */ + RTCString &assign(const char *a_pszSrc, size_t a_cchSrc); + + /** + * Assigns a partial copy of a C-style string. + * + * @param a_pszSrc The source string (UTF-8). + * @param a_cchSrc The max number of chars (encoded UTF-8 bytes) + * to copy from the source string. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int assignNoThrow(const char *a_pszSrc, size_t a_cchSrc) RT_NOEXCEPT; + + /** + * Assigs a string containing @a a_cTimes repetitions of the character @a a_ch. + * + * @param a_cTimes The number of times the character is repeated. + * @param a_ch The character to fill the string with. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + */ + RTCString &assign(size_t a_cTimes, char a_ch); + + /** + * Assigs a string containing @a a_cTimes repetitions of the character @a a_ch. + * + * @param a_cTimes The number of times the character is repeated. + * @param a_ch The character to fill the string with. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int assignNoThrow(size_t a_cTimes, char a_ch) RT_NOEXCEPT; + + /** + * Assigns the output of the string format operation (RTStrPrintf). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + * + * @throws std::bad_alloc On allocation error. Object state is undefined. + * + * @returns Reference to the object. + */ + RTCString &printf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + + /** + * Assigns the output of the string format operation (RTStrPrintf). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + * + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int printfNoThrow(const char *pszFormat, ...) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 2); + + /** + * Assigns the output of the string format operation (RTStrPrintfV). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param va Argument vector containing the arguments + * specified by the format string. + * + * @throws std::bad_alloc On allocation error. Object state is undefined. + * + * @returns Reference to the object. + */ + RTCString &printfV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + + /** + * Assigns the output of the string format operation (RTStrPrintfV). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param va Argument vector containing the arguments + * specified by the format string. + * + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int printfVNoThrow(const char *pszFormat, va_list va) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 0); + + /** + * Appends the string @a that to @a rThat. + * + * @param rThat The string to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + RTCString &append(const RTCString &rThat); + + /** + * Appends the string @a that to @a rThat. + * + * @param rThat The string to append. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int appendNoThrow(const RTCString &rThat) RT_NOEXCEPT; + + /** + * Appends the string @a pszSrc to @a this. + * + * @param pszSrc The C-style string to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + RTCString &append(const char *pszSrc); + + /** + * Appends the string @a pszSrc to @a this. + * + * @param pszSrc The C-style string to append. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int appendNoThrow(const char *pszSrc) RT_NOEXCEPT; + + /** + * Appends the a substring from @a rThat to @a this. + * + * @param rThat The string to append a substring from. + * @param offStart The start of the substring to append (byte offset, + * not codepoint). + * @param cchMax The maximum number of bytes to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + RTCString &append(const RTCString &rThat, size_t offStart, size_t cchMax = RTSTR_MAX); + + /** + * Appends the a substring from @a rThat to @a this. + * + * @param rThat The string to append a substring from. + * @param offStart The start of the substring to append (byte offset, + * not codepoint). + * @param cchMax The maximum number of bytes to append. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int appendNoThrow(const RTCString &rThat, size_t offStart, size_t cchMax = RTSTR_MAX) RT_NOEXCEPT; + + /** + * Appends the first @a cchMax chars from string @a pszThat to @a this. + * + * @param pszThat The C-style string to append. + * @param cchMax The maximum number of bytes to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + RTCString &append(const char *pszThat, size_t cchMax); + + /** + * Appends the first @a cchMax chars from string @a pszThat to @a this. + * + * @param pszThat The C-style string to append. + * @param cchMax The maximum number of bytes to append. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int appendNoThrow(const char *pszThat, size_t cchMax) RT_NOEXCEPT; + + /** + * Appends the given character to @a this. + * + * @param ch The character to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + RTCString &append(char ch); + + /** + * Appends the given character to @a this. + * + * @param ch The character to append. + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int appendNoThrow(char ch) RT_NOEXCEPT; + + /** + * Appends the given unicode code point to @a this. + * + * @param uc The unicode code point to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + RTCString &appendCodePoint(RTUNICP uc); + + /** + * Appends the given unicode code point to @a this. + * + * @param uc The unicode code point to append. + * @returns VINF_SUCCESS, VERR_INVALID_UTF8_ENCODING or VERR_NO_STRING_MEMORY. + */ + int appendCodePointNoThrow(RTUNICP uc) RT_NOEXCEPT; + + /** + * Appends the output of the string format operation (RTStrPrintf). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + * + * @throws std::bad_alloc On allocation error. Object state is undefined. + * + * @returns Reference to the object. + */ + RTCString &appendPrintf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + + /** + * Appends the output of the string format operation (RTStrPrintf). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + * + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int appendPrintfNoThrow(const char *pszFormat, ...) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 2); + + /** + * Appends the output of the string format operation (RTStrPrintfV). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param va Argument vector containing the arguments + * specified by the format string. + * + * @throws std::bad_alloc On allocation error. Object state is undefined. + * + * @returns Reference to the object. + */ + RTCString &appendPrintfV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + + /** + * Appends the output of the string format operation (RTStrPrintfV). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param va Argument vector containing the arguments + * specified by the format string. + * + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + */ + int appendPrintfVNoThrow(const char *pszFormat, va_list va) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 0); + + /** + * Shortcut to append(), RTCString variant. + * + * @param rThat The string to append. + * @returns Reference to the object. + */ + RTCString &operator+=(const RTCString &rThat) + { + return append(rThat); + } + + /** + * Shortcut to append(), const char* variant. + * + * @param pszThat The C-style string to append. + * @returns Reference to the object. + */ + RTCString &operator+=(const char *pszThat) + { + return append(pszThat); + } + + /** + * Shortcut to append(), char variant. + * + * @param ch The character to append. + * + * @returns Reference to the object. + */ + RTCString &operator+=(char ch) + { + return append(ch); + } + + /** + * Converts the member string to upper case. + * + * @returns Reference to the object. + */ + RTCString &toUpper() RT_NOEXCEPT + { + if (length()) + { + /* Folding an UTF-8 string may result in a shorter encoding (see + testcase), so recalculate the length afterwards. */ + ::RTStrToUpper(m_psz); + size_t cchNew = strlen(m_psz); + Assert(cchNew <= m_cch); + m_cch = cchNew; + } + return *this; + } + + /** + * Converts the member string to lower case. + * + * @returns Reference to the object. + */ + RTCString &toLower() RT_NOEXCEPT + { + if (length()) + { + /* Folding an UTF-8 string may result in a shorter encoding (see + testcase), so recalculate the length afterwards. */ + ::RTStrToLower(m_psz); + size_t cchNew = strlen(m_psz); + Assert(cchNew <= m_cch); + m_cch = cchNew; + } + return *this; + } + + /** + * Erases a sequence from the string. + * + * @returns Reference to the object. + * @param offStart Where in @a this string to start erasing. + * @param cchLength How much following @a offStart to erase. + */ + RTCString &erase(size_t offStart = 0, size_t cchLength = npos) RT_NOEXCEPT; + + /** + * Replaces a span of @a this string with a replacement string. + * + * @returns Reference to the object. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param rStrReplacement The replacement string. + * + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * + * @note Non-standard behaviour if offStart is beyond the end of the string. + * No change will occure and strict builds hits a debug assertion. + */ + RTCString &replace(size_t offStart, size_t cchLength, const RTCString &rStrReplacement); + + /** + * Replaces a span of @a this string with a replacement string. + * + * @returns VINF_SUCCESS, VERR_OUT_OF_RANGE or VERR_NO_STRING_MEMORY. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param rStrReplacement The replacement string. + */ + int replaceNoThrow(size_t offStart, size_t cchLength, const RTCString &rStrReplacement) RT_NOEXCEPT; + + /** + * Replaces a span of @a this string with a replacement substring. + * + * @returns Reference to the object. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param rStrReplacement The string from which a substring is taken. + * @param offReplacement The offset into @a rStrReplacement where the + * replacement substring starts. + * @param cchReplacement The maximum length of the replacement substring. + * + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * + * @note Non-standard behaviour if offStart or offReplacement is beyond the + * end of the repective strings. No change is made in the former case, + * while we consider it an empty string in the latter. In both + * situation a debug assertion is raised in strict builds. + */ + RTCString &replace(size_t offStart, size_t cchLength, const RTCString &rStrReplacement, + size_t offReplacement, size_t cchReplacement); + + /** + * Replaces a span of @a this string with a replacement substring. + * + * @returns VINF_SUCCESS, VERR_OUT_OF_RANGE or VERR_NO_STRING_MEMORY. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param rStrReplacement The string from which a substring is taken. + * @param offReplacement The offset into @a rStrReplacement where the + * replacement substring starts. + * @param cchReplacement The maximum length of the replacement substring. + */ + int replaceNoThrow(size_t offStart, size_t cchLength, const RTCString &rStrReplacement, + size_t offReplacement, size_t cchReplacement) RT_NOEXCEPT; + + /** + * Replaces a span of @a this string with the replacement string. + * + * @returns Reference to the object. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param pszReplacement The replacement string. + * + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * + * @note Non-standard behaviour if offStart is beyond the end of the string. + * No change will occure and strict builds hits a debug assertion. + */ + RTCString &replace(size_t offStart, size_t cchLength, const char *pszReplacement); + + /** + * Replaces a span of @a this string with the replacement string. + * + * @returns VINF_SUCCESS, VERR_OUT_OF_RANGE or VERR_NO_STRING_MEMORY. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param pszReplacement The replacement string. + */ + int replaceNoThrow(size_t offStart, size_t cchLength, const char *pszReplacement) RT_NOEXCEPT; + + /** + * Replaces a span of @a this string with the replacement string. + * + * @returns Reference to the object. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param pszReplacement The replacement string. + * @param cchReplacement How much of @a pszReplacement to use at most. If a + * zero terminator is found before reaching this value, + * we'll stop there. + * + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * + * @note Non-standard behaviour if offStart is beyond the end of the string. + * No change will occure and strict builds hits a debug assertion. + */ + RTCString &replace(size_t offStart, size_t cchLength, const char *pszReplacement, size_t cchReplacement); + + /** + * Replaces a span of @a this string with the replacement string. + * + * @returns VINF_SUCCESS, VERR_OUT_OF_RANGE or VERR_NO_STRING_MEMORY. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param pszReplacement The replacement string. + * @param cchReplacement How much of @a pszReplacement to use at most. If a + * zero terminator is found before reaching this value, + * we'll stop there. + */ + int replaceNoThrow(size_t offStart, size_t cchLength, const char *pszReplacement, size_t cchReplacement) RT_NOEXCEPT; + + /** + * Truncates the string to a max length of @a cchMax. + * + * If the string is shorter than @a cchMax characters, no change is made. + * + * If the @a cchMax is not at the start of a UTF-8 sequence, it will be adjusted + * down to the start of the UTF-8 sequence. Thus, after a truncation, the + * length() may be smaller than @a cchMax. + * + */ + RTCString &truncate(size_t cchMax) RT_NOEXCEPT; + + /** + * Index operator. + * + * Returns the byte at the given index, or a null byte if the index is not + * smaller than length(). This does _not_ count codepoints but simply points + * into the member C-style string. + * + * @param i The index into the string buffer. + * @returns char at the index or null. + */ + inline char operator[](size_t i) const RT_NOEXCEPT + { + if (i < length()) + return m_psz[i]; + return '\0'; + } + + /** + * Returns the contained string as a const C-style string pointer. + * + * This never returns NULL; if the string is empty, this returns a pointer to + * static null byte. + * + * @returns const pointer to C-style string. + */ + inline const char *c_str() const RT_NOEXCEPT + { + return (m_psz) ? m_psz : ""; + } + + /** + * Returns a non-const raw pointer that allows to modify the string directly. + * As opposed to c_str() and raw(), this DOES return NULL for an empty string + * because we cannot return a non-const pointer to a static "" global. + * + * @warning + * -# Be sure not to modify data beyond the allocated memory! Call + * capacity() to find out how large that buffer is. + * -# After any operation that modifies the length of the string, + * you _must_ call RTCString::jolt(), or subsequent copy operations + * may go nowhere. Better not use mutableRaw() at all. + */ + char *mutableRaw() RT_NOEXCEPT + { + return m_psz; + } + + /** + * Clean up after using mutableRaw. + * + * Intended to be called after something has messed with the internal string + * buffer (e.g. after using mutableRaw() or Utf8Str::asOutParam()). Resets the + * internal lengths correctly. Otherwise subsequent copy operations may go + * nowhere. + */ + void jolt() RT_NOEXCEPT + { + if (m_psz) + { + m_cch = strlen(m_psz); + m_cbAllocated = m_cch + 1; /* (Required for the Utf8Str::asOutParam case) */ + } + else + { + m_cch = 0; + m_cbAllocated = 0; + } + } + + /** + * Returns @c true if the member string has no length. + * + * This is @c true for instances created from both NULL and "" input + * strings. + * + * This states nothing about how much memory might be allocated. + * + * @returns @c true if empty, @c false if not. + */ + bool isEmpty() const RT_NOEXCEPT + { + return length() == 0; + } + + /** + * Returns @c false if the member string has no length. + * + * This is @c false for instances created from both NULL and "" input + * strings. + * + * This states nothing about how much memory might be allocated. + * + * @returns @c false if empty, @c true if not. + */ + bool isNotEmpty() const RT_NOEXCEPT + { + return length() != 0; + } + + /** Case sensitivity selector. */ + enum CaseSensitivity + { + CaseSensitive, + CaseInsensitive + }; + + /** + * Compares the member string to a C-string. + * + * @param pcszThat The string to compare with. + * @param cs Whether comparison should be case-sensitive. + * @returns 0 if equal, negative if this is smaller than @a pcsz, positive + * if larger. + */ + int compare(const char *pcszThat, CaseSensitivity cs = CaseSensitive) const RT_NOEXCEPT + { + /* This klugde is for m_cch=0 and m_psz=NULL. pcsz=NULL and psz="" + are treated the same way so that str.compare(str2.c_str()) works. */ + if (length() == 0) + return pcszThat == NULL || *pcszThat == '\0' ? 0 : -1; + + if (cs == CaseSensitive) + return ::RTStrCmp(m_psz, pcszThat); + return ::RTStrICmp(m_psz, pcszThat); + } + + /** + * Compares the member string to another RTCString. + * + * @param rThat The string to compare with. + * @param cs Whether comparison should be case-sensitive. + * @returns 0 if equal, negative if this is smaller than @a pcsz, positive + * if larger. + */ + int compare(const RTCString &rThat, CaseSensitivity cs = CaseSensitive) const RT_NOEXCEPT + { + if (cs == CaseSensitive) + return ::RTStrCmp(m_psz, rThat.m_psz); + return ::RTStrICmp(m_psz, rThat.m_psz); + } + + /** + * Compares the two strings. + * + * @returns true if equal, false if not. + * @param rThat The string to compare with. + */ + bool equals(const RTCString &rThat) const RT_NOEXCEPT + { + return rThat.length() == length() + && ( length() == 0 + || memcmp(rThat.m_psz, m_psz, length()) == 0); + } + + /** + * Compares the two strings. + * + * @returns true if equal, false if not. + * @param pszThat The string to compare with. + */ + bool equals(const char *pszThat) const RT_NOEXCEPT + { + /* This klugde is for m_cch=0 and m_psz=NULL. pcsz=NULL and psz="" + are treated the same way so that str.equals(str2.c_str()) works. */ + if (length() == 0) + return pszThat == NULL || *pszThat == '\0'; + return RTStrCmp(pszThat, m_psz) == 0; + } + + /** + * Compares the two strings ignoring differences in case. + * + * @returns true if equal, false if not. + * @param that The string to compare with. + */ + bool equalsIgnoreCase(const RTCString &that) const RT_NOEXCEPT + { + /* Unfolded upper and lower case characters may require different + amount of encoding space, so the length optimization doesn't work. */ + return RTStrICmp(that.m_psz, m_psz) == 0; + } + + /** + * Compares the two strings ignoring differences in case. + * + * @returns true if equal, false if not. + * @param pszThat The string to compare with. + */ + bool equalsIgnoreCase(const char *pszThat) const RT_NOEXCEPT + { + /* This klugde is for m_cch=0 and m_psz=NULL. pcsz=NULL and psz="" + are treated the same way so that str.equalsIgnoreCase(str2.c_str()) works. */ + if (length() == 0) + return pszThat == NULL || *pszThat == '\0'; + return RTStrICmp(pszThat, m_psz) == 0; + } + + /** @name Comparison operators. + * @{ */ + bool operator==(const RTCString &that) const { return equals(that); } + bool operator!=(const RTCString &that) const { return !equals(that); } + bool operator<( const RTCString &that) const { return compare(that) < 0; } + bool operator>( const RTCString &that) const { return compare(that) > 0; } + + bool operator==(const char *pszThat) const { return equals(pszThat); } + bool operator!=(const char *pszThat) const { return !equals(pszThat); } + bool operator<( const char *pszThat) const { return compare(pszThat) < 0; } + bool operator>( const char *pszThat) const { return compare(pszThat) > 0; } + /** @} */ + + /** Max string offset value. + * + * When returned by a method, this indicates failure. When taken as input, + * typically a default, it means all the way to the string terminator. + */ + static const size_t npos; + + /** + * Find the given substring. + * + * Looks for @a pszNeedle in @a this starting at @a offStart and returns its + * position as a byte (not codepoint) offset, counting from the beginning of + * @a this as 0. + * + * @param pszNeedle The substring to find. + * @param offStart The (byte) offset into the string buffer to start + * searching. + * + * @returns 0 based position of pszNeedle. npos if not found. + */ + size_t find(const char *pszNeedle, size_t offStart = 0) const RT_NOEXCEPT; + size_t find_first_of(const char *pszNeedle, size_t offStart = 0) const RT_NOEXCEPT + { return find(pszNeedle, offStart); } + + /** + * Find the given substring. + * + * Looks for @a pStrNeedle in @a this starting at @a offStart and returns its + * position as a byte (not codepoint) offset, counting from the beginning of + * @a this as 0. + * + * @param pStrNeedle The substring to find. + * @param offStart The (byte) offset into the string buffer to start + * searching. + * + * @returns 0 based position of pStrNeedle. npos if not found or pStrNeedle is + * NULL or an empty string. + */ + size_t find(const RTCString *pStrNeedle, size_t offStart = 0) const RT_NOEXCEPT; + + /** + * Find the given substring. + * + * Looks for @a rStrNeedle in @a this starting at @a offStart and returns its + * position as a byte (not codepoint) offset, counting from the beginning of + * @a this as 0. + * + * @param rStrNeedle The substring to find. + * @param offStart The (byte) offset into the string buffer to start + * searching. + * + * @returns 0 based position of pStrNeedle. npos if not found or pStrNeedle is + * NULL or an empty string. + */ + size_t find(const RTCString &rStrNeedle, size_t offStart = 0) const RT_NOEXCEPT; + size_t find_first_of(const RTCString &rStrNeedle, size_t offStart = 0) const RT_NOEXCEPT + { return find(rStrNeedle, offStart); } + + /** + * Find the given character (byte). + * + * @returns 0 based position of chNeedle. npos if not found or pStrNeedle is + * NULL or an empty string. + * @param chNeedle The character (byte) to find. + * @param offStart The (byte) offset into the string buffer to start + * searching. Default is start of the string. + * + * @note This searches for a C character value, not a codepoint. Use the + * string version to locate codepoints above U+7F. + */ + size_t find(char chNeedle, size_t offStart = 0) const RT_NOEXCEPT; + size_t find_first_of(char chNeedle, size_t offStart = 0) const RT_NOEXCEPT + { return find(chNeedle, offStart); } + + /** + * Replaces all occurences of cFind with cReplace in the member string. + * In order not to produce invalid UTF-8, the characters must be ASCII + * values less than 128; this is not verified. + * + * @param chFind Character to replace. Must be ASCII < 128. + * @param chReplace Character to replace cFind with. Must be ASCII < 128. + */ + void findReplace(char chFind, char chReplace) RT_NOEXCEPT; + + /** + * Count the occurences of the specified character in the string. + * + * @param ch What to search for. Must be ASCII < 128. + * @remarks QString::count + */ + size_t count(char ch) const RT_NOEXCEPT; + + /** + * Count the occurences of the specified sub-string in the string. + * + * @param psz What to search for. + * @param cs Case sensitivity selector. + * @remarks QString::count + */ + size_t count(const char *psz, CaseSensitivity cs = CaseSensitive) const RT_NOEXCEPT; + + /** + * Count the occurences of the specified sub-string in the string. + * + * @param pStr What to search for. + * @param cs Case sensitivity selector. + * @remarks QString::count + */ + size_t count(const RTCString *pStr, CaseSensitivity cs = CaseSensitive) const RT_NOEXCEPT; + + /** + * Strips leading and trailing spaces. + * + * @returns this + */ + RTCString &strip() RT_NOEXCEPT; + + /** + * Strips leading spaces. + * + * @returns this + */ + RTCString &stripLeft() RT_NOEXCEPT; + + /** + * Strips trailing spaces. + * + * @returns this + */ + RTCString &stripRight() RT_NOEXCEPT; + + /** + * Returns a substring of @a this as a new Utf8Str. + * + * Works exactly like its equivalent in std::string. With the default + * parameters "0" and "npos", this always copies the entire string. The + * "pos" and "n" arguments represent bytes; it is the caller's responsibility + * to ensure that the offsets do not copy invalid UTF-8 sequences. When + * used in conjunction with find() and length(), this will work. + * + * @param pos Index of first byte offset to copy from @a this, + * counting from 0. + * @param n Number of bytes to copy, starting with the one at "pos". + * The copying will stop if the null terminator is encountered before + * n bytes have been copied. + */ + RTCString substr(size_t pos = 0, size_t n = npos) const + { + return RTCString(*this, pos, n); + } + + /** + * Returns a substring of @a this as a new Utf8Str. As opposed to substr(), this + * variant takes codepoint offsets instead of byte offsets. + * + * @param pos Index of first unicode codepoint to copy from + * @a this, counting from 0. + * @param n Number of unicode codepoints to copy, starting with + * the one at "pos". The copying will stop if the null + * terminator is encountered before n codepoints have + * been copied. + */ + RTCString substrCP(size_t pos = 0, size_t n = npos) const; + + /** + * Returns true if @a this ends with @a that. + * + * @param that Suffix to test for. + * @param cs Case sensitivity selector. + * @returns true if match, false if mismatch. + */ + bool endsWith(const RTCString &that, CaseSensitivity cs = CaseSensitive) const RT_NOEXCEPT; + + /** + * Returns true if @a this begins with @a that. + * @param that Prefix to test for. + * @param cs Case sensitivity selector. + * @returns true if match, false if mismatch. + */ + bool startsWith(const RTCString &that, CaseSensitivity cs = CaseSensitive) const RT_NOEXCEPT; + + /** + * Checks if the string starts with the given word, ignoring leading blanks. + * + * @param pszWord The word to test for. + * @param enmCase Case sensitivity selector. + * @returns true if match, false if mismatch. + */ + bool startsWithWord(const char *pszWord, CaseSensitivity enmCase = CaseSensitive) const RT_NOEXCEPT; + + /** + * Checks if the string starts with the given word, ignoring leading blanks. + * + * @param rThat Prefix to test for. + * @param enmCase Case sensitivity selector. + * @returns true if match, false if mismatch. + */ + bool startsWithWord(const RTCString &rThat, CaseSensitivity enmCase = CaseSensitive) const RT_NOEXCEPT; + + /** + * Returns true if @a this contains @a that (strstr). + * + * @param that Substring to look for. + * @param cs Case sensitivity selector. + * @returns true if found, false if not found. + */ + bool contains(const RTCString &that, CaseSensitivity cs = CaseSensitive) const RT_NOEXCEPT; + + /** + * Returns true if @a this contains @a pszNeedle (strstr). + * + * @param pszNeedle Substring to look for. + * @param cs Case sensitivity selector. + * @returns true if found, false if not found. + */ + bool contains(const char *pszNeedle, CaseSensitivity cs = CaseSensitive) const RT_NOEXCEPT; + + /** + * Attempts to convert the member string into a 32-bit integer. + * + * @returns 32-bit unsigned number on success. + * @returns 0 on failure. + */ + int32_t toInt32() const RT_NOEXCEPT + { + return RTStrToInt32(c_str()); + } + + /** + * Attempts to convert the member string into an unsigned 32-bit integer. + * + * @returns 32-bit unsigned number on success. + * @returns 0 on failure. + */ + uint32_t toUInt32() const RT_NOEXCEPT + { + return RTStrToUInt32(c_str()); + } + + /** + * Attempts to convert the member string into an 64-bit integer. + * + * @returns 64-bit unsigned number on success. + * @returns 0 on failure. + */ + int64_t toInt64() const RT_NOEXCEPT + { + return RTStrToInt64(c_str()); + } + + /** + * Attempts to convert the member string into an unsigned 64-bit integer. + * + * @returns 64-bit unsigned number on success. + * @returns 0 on failure. + */ + uint64_t toUInt64() const RT_NOEXCEPT + { + return RTStrToUInt64(c_str()); + } + + /** + * Attempts to convert the member string into an unsigned 64-bit integer. + * + * @param i Where to return the value on success. + * @returns IPRT error code, see RTStrToInt64. + */ + int toInt(uint64_t &i) const RT_NOEXCEPT; + + /** + * Attempts to convert the member string into an unsigned 32-bit integer. + * + * @param i Where to return the value on success. + * @returns IPRT error code, see RTStrToInt32. + */ + int toInt(uint32_t &i) const RT_NOEXCEPT; + + /** Splitting behavior regarding empty sections in the string. */ + enum SplitMode + { + KeepEmptyParts, /**< Empty parts are added as empty strings to the result list. */ + RemoveEmptyParts /**< Empty parts are skipped. */ + }; + + /** + * Splits a string separated by strSep into its parts. + * + * @param a_rstrSep The separator to search for. + * @param a_enmMode How should empty parts be handled. + * @returns separated strings as string list. + * @throws std::bad_alloc On allocation error. + */ + RTCList<RTCString, RTCString *> split(const RTCString &a_rstrSep, + SplitMode a_enmMode = RemoveEmptyParts) const; + + /** + * Joins a list of strings together using the provided separator and + * an optional prefix for each item in the list. + * + * @param a_rList The list to join. + * @param a_rstrPrefix The prefix used for appending to each item. + * @param a_rstrSep The separator used for joining. + * @returns joined string. + * @throws std::bad_alloc On allocation error. + */ + static RTCString joinEx(const RTCList<RTCString, RTCString *> &a_rList, + const RTCString &a_rstrPrefix /* = "" */, + const RTCString &a_rstrSep /* = "" */); + + /** + * Joins a list of strings together using the provided separator. + * + * @param a_rList The list to join. + * @param a_rstrSep The separator used for joining. + * @returns joined string. + * @throws std::bad_alloc On allocation error. + */ + static RTCString join(const RTCList<RTCString, RTCString *> &a_rList, + const RTCString &a_rstrSep = ""); + + /** + * Swaps two strings in a fast way. + * + * Exception safe. + * + * @param a_rThat The string to swap with. + */ + inline void swap(RTCString &a_rThat) RT_NOEXCEPT + { + char *pszTmp = m_psz; + size_t cchTmp = m_cch; + size_t cbAllocatedTmp = m_cbAllocated; + + m_psz = a_rThat.m_psz; + m_cch = a_rThat.m_cch; + m_cbAllocated = a_rThat.m_cbAllocated; + + a_rThat.m_psz = pszTmp; + a_rThat.m_cch = cchTmp; + a_rThat.m_cbAllocated = cbAllocatedTmp; + } + +protected: + + /** + * Hide operator bool() to force people to use isEmpty() explicitly. + */ + operator bool() const; + + /** + * Destructor implementation, also used to clean up in operator=() before + * assigning a new string. + */ + void cleanup() RT_NOEXCEPT + { + if (m_psz) + { + RTStrFree(m_psz); + m_psz = NULL; + m_cch = 0; + m_cbAllocated = 0; + } + } + + /** + * Protected internal helper to copy a string. + * + * This ignores the previous object state, so either call this from a + * constructor or call cleanup() first. copyFromN() unconditionally sets + * the members to a copy of the given other strings and makes no + * assumptions about previous contents. Can therefore be used both in copy + * constructors, when member variables have no defined value, and in + * assignments after having called cleanup(). + * + * @param pcszSrc The source string. + * @param cchSrc The number of chars (bytes) to copy from the + * source strings. RTSTR_MAX is NOT accepted. + * + * @throws std::bad_alloc On allocation failure. The object is left + * describing a NULL string. + */ + void copyFromN(const char *pcszSrc, size_t cchSrc) + { + if (cchSrc) + { + m_psz = RTStrAlloc(cchSrc + 1); + if (RT_LIKELY(m_psz)) + { + m_cch = cchSrc; + m_cbAllocated = cchSrc + 1; + memcpy(m_psz, pcszSrc, cchSrc); + m_psz[cchSrc] = '\0'; + } + else + { + m_cch = 0; + m_cbAllocated = 0; +#ifdef RT_EXCEPTIONS_ENABLED + throw std::bad_alloc(); +#endif + } + } + else + { + m_cch = 0; + m_cbAllocated = 0; + m_psz = NULL; + } + } + + /** + * Appends exactly @a cchSrc chars from @a pszSrc to @a this. + * + * This is an internal worker for the append() methods. + * + * @returns Reference to the object. + * @param pszSrc The source string. + * @param cchSrc The source string length (exact). + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * + */ + RTCString &appendWorker(const char *pszSrc, size_t cchSrc); + + /** + * Appends exactly @a cchSrc chars from @a pszSrc to @a this. + * + * This is an internal worker for the appendNoThrow() methods. + * + * @returns VINF_SUCCESS or VERR_NO_STRING_MEMORY. + * @param pszSrc The source string. + * @param cchSrc The source string length (exact). + */ + int appendWorkerNoThrow(const char *pszSrc, size_t cchSrc) RT_NOEXCEPT; + + /** + * Replaces exatly @a cchLength chars at @a offStart with @a cchSrc from @a + * pszSrc. + * + * @returns Reference to the object. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param pszSrc The replacement string. + * @param cchSrc The exactly length of the replacement string. + * + * @throws std::bad_alloc On allocation error. The object is left unchanged. + */ + RTCString &replaceWorker(size_t offStart, size_t cchLength, const char *pszSrc, size_t cchSrc); + + /** + * Replaces exatly @a cchLength chars at @a offStart with @a cchSrc from @a + * pszSrc. + * + * @returns VINF_SUCCESS, VERR_OUT_OF_RANGE or VERR_NO_STRING_MEMORY. + * @param offStart Where in @a this string to start replacing. + * @param cchLength How much following @a offStart to replace. npos is + * accepted. + * @param pszSrc The replacement string. + * @param cchSrc The exactly length of the replacement string. + */ + int replaceWorkerNoThrow(size_t offStart, size_t cchLength, const char *pszSrc, size_t cchSrc) RT_NOEXCEPT; + + static DECLCALLBACK(size_t) printfOutputCallback(void *pvArg, const char *pachChars, size_t cbChars); + static DECLCALLBACK(size_t) printfOutputCallbackNoThrow(void *pvArg, const char *pachChars, size_t cbChars) RT_NOEXCEPT; + + char *m_psz; /**< The string buffer. */ + size_t m_cch; /**< strlen(m_psz) - i.e. no terminator included. */ + size_t m_cbAllocated; /**< Size of buffer that m_psz points to; at least m_cbLength + 1. */ +}; + +/** @} */ + + +/** @addtogroup grp_rt_cpp_string + * @{ + */ + +/** + * Concatenate two strings. + * + * @param a_rstr1 String one. + * @param a_rstr2 String two. + * @returns the concatenate string. + * + * @relates RTCString + */ +RTDECL(const RTCString) operator+(const RTCString &a_rstr1, const RTCString &a_rstr2); + +/** + * Concatenate two strings. + * + * @param a_rstr1 String one. + * @param a_psz2 String two. + * @returns the concatenate string. + * + * @relates RTCString + */ +RTDECL(const RTCString) operator+(const RTCString &a_rstr1, const char *a_psz2); + +/** + * Concatenate two strings. + * + * @param a_psz1 String one. + * @param a_rstr2 String two. + * @returns the concatenate string. + * + * @relates RTCString + */ +RTDECL(const RTCString) operator+(const char *a_psz1, const RTCString &a_rstr2); + +/** + * Class with RTCString::printf as constructor for your convenience. + * + * Constructing a RTCString string object from a format string and a variable + * number of arguments can easily be confused with the other RTCString + * constructors, thus this child class. + * + * The usage of this class is like the following: + * @code + RTCStringFmt strName("program name = %s", argv[0]); + @endcode + */ +class RTCStringFmt : public RTCString +{ +public: + + /** + * Constructs a new string given the format string and the list of the + * arguments for the format string. + * + * @param a_pszFormat Pointer to the format string (UTF-8), + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + */ + explicit RTCStringFmt(const char *a_pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2) + { + va_list va; + va_start(va, a_pszFormat); + printfV(a_pszFormat, va); + va_end(va); + } + + RTMEMEF_NEW_AND_DELETE_OPERATORS(); + +protected: + RTCStringFmt() {} +}; + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_ministring_h */ + diff --git a/include/iprt/cpp/mtlist.h b/include/iprt/cpp/mtlist.h new file mode 100644 index 00000000..915fcbad --- /dev/null +++ b/include/iprt/cpp/mtlist.h @@ -0,0 +1,185 @@ +/** @file + * IPRT - Generic thread-safe list Class. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_mtlist_h +#define IPRT_INCLUDED_cpp_mtlist_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cpp/list.h> +#include <iprt/semaphore.h> + +/** @addtogroup grp_rt_cpp_list + * @{ + */ + +/** + * A guard class for thread-safe read/write access. + */ +template <> +class RTCListGuard<true> +{ +public: + RTCListGuard() : m_hRWSem(NIL_RTSEMRW) + { +#if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3) + RTLOCKVALCLASS hClass; + int rc = RTLockValidatorClassCreate(&hClass, true /*fAutodidact*/, RT_SRC_POS, "RTCListGuard"); + AssertStmt(RT_SUCCESS(rc), hClass = NIL_RTLOCKVALCLASS); + rc = RTSemRWCreateEx(&m_hRWSem, 0 /*fFlags*/, hClass, RTLOCKVAL_SUB_CLASS_NONE, NULL /*pszNameFmt*/); + AssertRC(rc); +#else + int rc = RTSemRWCreateEx(&m_hRWSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, 0, NULL); + AssertRC(rc); +#endif + } + + ~RTCListGuard() + { + RTSemRWDestroy(m_hRWSem); + m_hRWSem = NIL_RTSEMRW; + } + + inline void enterRead() const { int rc = RTSemRWRequestRead(m_hRWSem, RT_INDEFINITE_WAIT); AssertRC(rc); } + inline void leaveRead() const { int rc = RTSemRWReleaseRead(m_hRWSem); AssertRC(rc); } + inline void enterWrite() { int rc = RTSemRWRequestWrite(m_hRWSem, RT_INDEFINITE_WAIT); AssertRC(rc); } + inline void leaveWrite() { int rc = RTSemRWReleaseWrite(m_hRWSem); AssertRC(rc); } + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); + +private: + mutable RTSEMRW m_hRWSem; +}; + +/** + * @brief Generic thread-safe list class. + * + * RTCMTList is a thread-safe implementation of the list class. It uses a + * read/write semaphore to serialize the access to the items. Several readers + * can simultaneous access different or the same item. If one thread is writing + * to an item, the other accessors are blocked until the write has finished. + * + * Although the access is guarded, the user has to make sure the list content + * is consistent when iterating over the list or doing any other kind of access + * which makes assumptions about the list content. For a finer control of access + * restrictions, use your own locking mechanism and the standard list + * implementation. + * + * @see RTCListBase + */ +template <class T, typename ITYPE = typename RTCIf<(sizeof(T) > sizeof(void*)), T*, T>::result> +class RTCMTList : public RTCListBase<T, ITYPE, true> +{ + /* Traits */ + typedef RTCListBase<T, ITYPE, true> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCMTList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * Specialized thread-safe list class for using the native type list for + * unsigned 64-bit values even on a 32-bit host. + * + * @see RTCListBase + */ +template <> +class RTCMTList<uint64_t>: public RTCListBase<uint64_t, uint64_t, true> +{ + /* Traits */ + typedef RTCListBase<uint64_t, uint64_t, true> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCMTList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * Specialized thread-safe list class for using the native type list for + * signed 64-bit values even on a 32-bit host. + * + * @see RTCListBase + */ +template <> +class RTCMTList<int64_t>: public RTCListBase<int64_t, int64_t, true> +{ + /* Traits */ + typedef RTCListBase<int64_t, int64_t, true> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCMTList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_mtlist_h */ + diff --git a/include/iprt/cpp/path.h b/include/iprt/cpp/path.h new file mode 100644 index 00000000..1a3c7f99 --- /dev/null +++ b/include/iprt/cpp/path.h @@ -0,0 +1,249 @@ +/** @file + * IPRT - C++ path utilities. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_path_h +#define IPRT_INCLUDED_cpp_path_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assert.h> +#include <iprt/errcore.h> +#include <iprt/path.h> +#include <iprt/cpp/ministring.h> + + +/** @defgroup grp_rt_cpp_path C++ Path Utilities + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * RTPathAbs() wrapper for working directly on a RTCString instance. + * + * @returns IPRT status code. + * @param rStrAbs Reference to the destination string. + * @param pszRelative The relative source string. + */ +DECLINLINE(int) RTPathAbsCxx(RTCString &rStrAbs, const char *pszRelative) +{ + Assert(rStrAbs.c_str() != pszRelative); + int rc = rStrAbs.reserveNoThrow(RTPATH_MAX); + if (RT_SUCCESS(rc)) + { + unsigned cTries = 8; + for (;;) + { + char *pszDst = rStrAbs.mutableRaw(); + size_t cbCap = rStrAbs.capacity(); + rc = RTPathAbsEx(NULL, pszRelative, RTPATH_STR_F_STYLE_HOST, pszDst, &cbCap); + if (RT_SUCCESS(rc)) + break; + *pszDst = '\0'; + if (rc != VERR_BUFFER_OVERFLOW) + break; + if (--cTries == 0) + break; + rc = rStrAbs.reserveNoThrow(RT_MIN(RT_ALIGN_Z(cbCap, 64), RTPATH_MAX)); + if (RT_FAILURE(rc)) + break; + } + rStrAbs.jolt(); + } + return rc; +} + + +/** + * RTPathAbs() wrapper for working directly on a RTCString instance. + * + * @returns IPRT status code. + * @param rStrAbs Reference to the destination string. + * @param rStrRelative Reference to the relative source string. + */ +DECLINLINE(int) RTPathAbsCxx(RTCString &rStrAbs, RTCString const &rStrRelative) +{ + return RTPathAbsCxx(rStrAbs, rStrRelative.c_str()); +} + + + +/** + * RTPathAbsEx() wrapper for working directly on a RTCString instance. + * + * @returns IPRT status code. + * @param rStrAbs Reference to the destination string. + * @param pszBase The base path, optional. + * @param pszRelative The relative source string. + * @param fFlags RTPATH_STR_F_STYLE_XXX and RTPATHABS_F_XXX flags. + */ +DECLINLINE(int) RTPathAbsExCxx(RTCString &rStrAbs, const char *pszBase, const char *pszRelative, uint32_t fFlags = RTPATH_STR_F_STYLE_HOST) +{ + Assert(rStrAbs.c_str() != pszRelative); + int rc = rStrAbs.reserveNoThrow(RTPATH_MAX); + if (RT_SUCCESS(rc)) + { + unsigned cTries = 8; + for (;;) + { + char *pszDst = rStrAbs.mutableRaw(); + size_t cbCap = rStrAbs.capacity(); + rc = RTPathAbsEx(pszBase, pszRelative, fFlags, pszDst, &cbCap); + if (RT_SUCCESS(rc)) + break; + *pszDst = '\0'; + if (rc != VERR_BUFFER_OVERFLOW) + break; + if (--cTries == 0) + break; + rc = rStrAbs.reserveNoThrow(RT_MIN(RT_ALIGN_Z(cbCap, 64), RTPATH_MAX)); + if (RT_FAILURE(rc)) + break; + } + rStrAbs.jolt(); + } + return rc; +} + + +DECLINLINE(int) RTPathAbsExCxx(RTCString &rStrAbs, RTCString const &rStrBase, RTCString const &rStrRelative, uint32_t fFlags = RTPATH_STR_F_STYLE_HOST) +{ + return RTPathAbsExCxx(rStrAbs, rStrBase.c_str(), rStrRelative.c_str(), fFlags); +} + + +DECLINLINE(int) RTPathAbsExCxx(RTCString &rStrAbs, const char *pszBase, RTCString const &rStrRelative, uint32_t fFlags = RTPATH_STR_F_STYLE_HOST) +{ + return RTPathAbsExCxx(rStrAbs, pszBase, rStrRelative.c_str(), fFlags); +} + + +DECLINLINE(int) RTPathAbsExCxx(RTCString &rStrAbs, RTCString const &rStrBase, const char *pszRelative, uint32_t fFlags = RTPATH_STR_F_STYLE_HOST) +{ + return RTPathAbsExCxx(rStrAbs, rStrBase.c_str(), pszRelative, fFlags); +} + + + +/** + * RTPathAppPrivateNoArch() wrapper for working directly on a RTCString instance. + * + * @returns IPRT status code. + * @param rStrDst Reference to the destination string. + */ +DECLINLINE(int) RTPathAppPrivateNoArchCxx(RTCString &rStrDst) +{ + int rc = rStrDst.reserveNoThrow(RTPATH_MAX); + if (RT_SUCCESS(rc)) + { + char *pszDst = rStrDst.mutableRaw(); + rc = RTPathAppPrivateNoArch(pszDst, rStrDst.capacity()); + if (RT_FAILURE(rc)) + *pszDst = '\0'; + rStrDst.jolt(); + } + return rc; + +} + + +/** + * RTPathAppend() wrapper for working directly on a RTCString instance. + * + * @returns IPRT status code. + * @param rStrDst Reference to the destination string. + * @param pszAppend One or more components to append to the path already + * present in @a rStrDst. + */ +DECLINLINE(int) RTPathAppendCxx(RTCString &rStrDst, const char *pszAppend) +{ + Assert(rStrDst.c_str() != pszAppend); + size_t cbEstimate = rStrDst.length() + 1 + strlen(pszAppend) + 1; + int rc; + if (rStrDst.capacity() >= cbEstimate) + rc = VINF_SUCCESS; + else + rc = rStrDst.reserveNoThrow(RT_ALIGN_Z(cbEstimate, 8)); + if (RT_SUCCESS(rc)) + { + rc = RTPathAppend(rStrDst.mutableRaw(), rStrDst.capacity(), pszAppend); + if (rc == VERR_BUFFER_OVERFLOW) + { + rc = rStrDst.reserveNoThrow(RTPATH_MAX); + if (RT_SUCCESS(rc)) + rc = RTPathAppend(rStrDst.mutableRaw(), rStrDst.capacity(), pszAppend); + } + rStrDst.jolt(); + } + return rc; +} + + +/** + * RTPathAppend() wrapper for working directly on a RTCString instance. + * + * @returns IPRT status code. + * @param rStrDst Reference to the destination string. + * @param rStrAppend One or more components to append to the path already + * present in @a rStrDst. + */ +DECLINLINE(int) RTPathAppendCxx(RTCString &rStrDst, RTCString const &rStrAppend) +{ + Assert(&rStrDst != &rStrAppend); + size_t cbEstimate = rStrDst.length() + 1 + rStrAppend.length() + 1; + int rc; + if (rStrDst.capacity() >= cbEstimate) + rc = VINF_SUCCESS; + else + rc = rStrDst.reserveNoThrow(RT_ALIGN_Z(cbEstimate, 8)); + if (RT_SUCCESS(rc)) + { + rc = RTPathAppend(rStrDst.mutableRaw(), rStrDst.capacity(), rStrAppend.c_str()); + if (rc == VERR_BUFFER_OVERFLOW) + { + rc = rStrDst.reserveNoThrow(RTPATH_MAX); + if (RT_SUCCESS(rc)) + rc = RTPathAppend(rStrDst.mutableRaw(), rStrDst.capacity(), rStrAppend.c_str()); + } + rStrDst.jolt(); + } + return rc; +} + + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_path_h */ + diff --git a/include/iprt/cpp/restanyobject.h b/include/iprt/cpp/restanyobject.h new file mode 100644 index 00000000..a83a769b --- /dev/null +++ b/include/iprt/cpp/restanyobject.h @@ -0,0 +1,139 @@ +/** @file + * IPRT - C++ Representational State Transfer (REST) Any Object Class. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_restanyobject_h +#define IPRT_INCLUDED_cpp_restanyobject_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cpp/restbase.h> +#include <iprt/cpp/restarray.h> +#include <iprt/cpp/reststringmap.h> + + +/** @defgroup grp_rt_cpp_restanyobj C++ Representational State Transfer (REST) Any Object Class. + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * Wrapper object that can represent any kind of basic REST object. + * + * This class is the result of a couple of design choices made in our REST + * data model. If could have been avoided if we used pointers all over + * the place and didn't rely entirely on the object specific implementations + * of deserializeFromJson and fromString to do the deserializing or everything. + * + * The assumption, though, was that most of the data we're dealing with has a + * known structure and maps to fixed types. So, the data model was optimized + * for that rather than flexiblity here. + */ +class RT_DECL_CLASS RTCRestAnyObject : public RTCRestObjectBase +{ +public: + /** Default constructor. */ + RTCRestAnyObject() RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestAnyObject(); + + /** Copy constructor. */ + RTCRestAnyObject(RTCRestAnyObject const &a_rThat); + /** Copy assignment operator. */ + RTCRestAnyObject &operator=(RTCRestAnyObject const &a_rThat); + + /** Safe copy assignment method. */ + int assignCopy(RTCRestAnyObject const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method, boolean variant. */ + int assignCopy(RTCRestBool const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method, int64_t variant. */ + int assignCopy(RTCRestInt64 const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method, int32_t variant. */ + int assignCopy(RTCRestInt32 const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method, int16_t variant. */ + int assignCopy(RTCRestInt16 const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method, double variant. */ + int assignCopy(RTCRestDouble const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method, string variant. */ + int assignCopy(RTCRestString const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method, array variant. */ + int assignCopy(RTCRestArray<RTCRestAnyObject> const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method, string map variant. */ + int assignCopy(RTCRestStringMap<RTCRestAnyObject> const &a_rThat) RT_NOEXCEPT; + + /** Safe value assignment method, boolean variant. */ + int assignValue(bool a_fValue) RT_NOEXCEPT; + /** Safe value assignment method, int64_t variant. */ + int assignValue(int64_t a_iValue) RT_NOEXCEPT; + /** Safe value assignment method, int32_t variant. */ + int assignValue(int32_t a_iValue) RT_NOEXCEPT; + /** Safe value assignment method, int16_t variant. */ + int assignValue(int16_t a_iValue) RT_NOEXCEPT; + /** Safe value assignment method, double variant. */ + int assignValue(double a_iValue) RT_NOEXCEPT; + /** Safe value assignment method, string variant. */ + int assignValue(RTCString const &a_rValue) RT_NOEXCEPT; + /** Safe value assignment method, C-string variant. */ + int assignValue(const char *a_pszValue) RT_NOEXCEPT; + + /** Make a clone of this object. */ + inline RTCRestAnyObject *clone() const RT_NOEXCEPT { return (RTCRestAnyObject *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int setNull(void) RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** Deserialization w/ instantiation. */ + static FNDESERIALIZEINSTANCEFROMJSON deserializeInstanceFromJson; + +protected: + /** The data. */ + RTCRestObjectBase *m_pData; +}; + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_restanyobject_h */ + diff --git a/include/iprt/cpp/restarray.h b/include/iprt/cpp/restarray.h new file mode 100644 index 00000000..56509c4e --- /dev/null +++ b/include/iprt/cpp/restarray.h @@ -0,0 +1,463 @@ +/** @file + * IPRT - C++ Representational State Transfer (REST) Array Template Class. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_restarray_h +#define IPRT_INCLUDED_cpp_restarray_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cpp/restbase.h> + + +/** @defgroup grp_rt_cpp_restarray C++ Representational State Transfer (REST) Array Template Class. + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * Abstract base class for the RTCRestArray template. + */ +class RT_DECL_CLASS RTCRestArrayBase : public RTCRestObjectBase +{ +public: + /** Default destructor. */ + RTCRestArrayBase() RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestArrayBase(); + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** + * Clear the content of the map. + */ + void clear() RT_NOEXCEPT; + + /** + * Check if an list contains any items. + * + * @return True if there is more than zero items, false otherwise. + */ + inline bool isEmpty() const RT_NOEXCEPT + { + return m_cElements == 0; + } + + /** + * Gets the number of entries in the map. + */ + inline size_t size() const RT_NOEXCEPT + { + return m_cElements; + } + + /** + * Returns the base object pointer at a given index. + * + * @returns The base object at @a a_idx, NULL if out of range. + * @param a_idx The array index. + */ + inline RTCRestObjectBase *atBase(size_t a_idx) RT_NOEXCEPT + { + if (a_idx < m_cElements) + return m_papElements[a_idx]; + return NULL; + } + + /** + * Returns the const base object pointer at a given index. + * + * @returns The base object at @a a_idx, NULL if out of range. + * @param a_idx The array index. + */ + inline RTCRestObjectBase const *atBase(size_t a_idx) const RT_NOEXCEPT + { + if (a_idx < m_cElements) + return m_papElements[a_idx]; + return NULL; + } + + /** + * Removes the element at @a a_idx. + * @returns true if @a a_idx is valid, false if out of range. + * @param a_idx The index of the element to remove. + * The value ~(size_t)0 is an alias for the final element. + */ + bool removeAt(size_t a_idx) RT_NOEXCEPT; + + /** + * Makes sure the array can hold at the given number of entries. + * + * @returns VINF_SUCCESS or VERR_NO_MEMORY. + * @param a_cEnsureCapacity The number of elements to ensure capacity to hold. + */ + int ensureCapacity(size_t a_cEnsureCapacity) RT_NOEXCEPT; + + +protected: + /** The array. */ + RTCRestObjectBase **m_papElements; + /** Number of elements in the array. */ + size_t m_cElements; + /** The number of elements m_papElements can hold. + * The difference between m_cCapacity and m_cElements are all NULLs. */ + size_t m_cCapacity; + + /** + * Helper for creating a clone. + * + * @returns Pointer to new array on success, NULL if out of memory. + */ + virtual RTCRestArrayBase *createClone(void) const RT_NOEXCEPT = 0; + + /** + * Wrapper around the value constructor. + * + * @returns Pointer to new value object on success, NULL if out of memory. + */ + virtual RTCRestObjectBase *createValue(void) RT_NOEXCEPT = 0; + + /** + * For accessing the static deserializeInstanceFromJson() method of the value. + */ + virtual int deserializeValueInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT = 0; + + /** + * Worker for the copy assignment method and copyArrayWorkerMayThrow(). + * + * This will use createEntryCopy to do the copying. + * + * @returns VINF_SUCCESS on success, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_rThat The array to copy. Caller makes 100% sure the it has + * the same type as the destination. + */ + int copyArrayWorkerNoThrow(RTCRestArrayBase const &a_rThat) RT_NOEXCEPT; + + /** + * Wrapper around copyArrayWorkerNoThrow for the copy constructor and the + * assignment operator. + */ + void copyArrayWorkerMayThrow(RTCRestArrayBase const &a_rThat); + + /** + * Worker for performing inserts. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_idx Where to insert it. The value ~(size_t)0 is an alias for m_cElements. + * @param a_pValue The value to insert. Ownership is transferred to the map on success. + * @param a_fReplace Whether to replace existing entry rather than insert. + */ + int insertWorker(size_t a_idx, RTCRestObjectBase *a_pValue, bool a_fReplace) RT_NOEXCEPT; + + /** + * Worker for performing inserts. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_idx Where to insert it. The value ~(size_t)0 is an alias for m_cElements. + * @param a_rValue The value to copy into the map. + * @param a_fReplace Whether to replace existing key-value pair with matching key. + */ + int insertCopyWorker(size_t a_idx, RTCRestObjectBase const &a_rValue, bool a_fReplace) RT_NOEXCEPT; + +private: + /** Copy constructor on this class should never be used. */ + RTCRestArrayBase(RTCRestArrayBase const &a_rThat); + /** Copy assignment operator on this class should never be used. */ + RTCRestArrayBase &operator=(RTCRestArrayBase const &a_rThat); +}; + + + +/** + * Limited array class. + */ +template<class ElementType> class RTCRestArray : public RTCRestArrayBase +{ +public: + /** Default constructor - empty array. */ + RTCRestArray() RT_NOEXCEPT + : RTCRestArrayBase() + { + } + + /** Destructor. */ + ~RTCRestArray() + { + } + + /** Copy constructor. */ + RTCRestArray(RTCRestArray const &a_rThat) + : RTCRestArrayBase() + { + copyArrayWorkerMayThrow(a_rThat); + } + + /** Copy assignment operator. */ + inline RTCRestArray &operator=(RTCRestArray const &a_rThat) + { + copyArrayWorkerMayThrow(a_rThat); + return *this; + } + + /** Safe copy assignment method. */ + inline int assignCopy(RTCRestArray const &a_rThat) RT_NOEXCEPT + { + return copyArrayWorkerNoThrow(a_rThat); + } + + /** Make a clone of this object. */ + inline RTCRestArray *clone() const RT_NOEXCEPT + { + return (RTCRestArray *)baseClone(); + } + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT + { + return new (std::nothrow) RTCRestArray<ElementType>(); + } + + /** Factory method for elements. */ + static DECLCALLBACK(RTCRestObjectBase *) createElementInstance(void) RT_NOEXCEPT + { + return new (std::nothrow) ElementType(); + } + + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT + { + *a_ppInstance = new (std::nothrow) RTCRestArray<ElementType>(); + if (*a_ppInstance) + return (*a_ppInstance)->deserializeFromJson(a_rCursor); + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_NO_MEMORY, "Out of memory"); + } + + + /** + * Insert the given object at the specified index. + * + * @returns VINF_SUCCESS on success. + * VERR_INVALID_POINTER, VERR_NO_MEMORY, VERR_NO_STR_MEMORY or VERR_OUT_OF_RANGE on failure. + * @param a_idx The insertion index. ~(size_t)0 is an alias for the end. + * @param a_pThat The object to insert. The array takes ownership of the object on success. + */ + inline int insert(size_t a_idx, ElementType *a_pThat) RT_NOEXCEPT + { + return insertWorker(a_idx, a_pThat, false /*a_fReplace*/); + } + + /** + * Insert a copy of the object at the specified index. + * + * @returns VINF_SUCCESS on success. + * VERR_NO_MEMORY, VERR_NO_STR_MEMORY or VERR_OUT_OF_RANGE on failure. + * @param a_idx The insertion index. ~(size_t)0 is an alias for the end. + * @param a_rThat The object to insert a copy of. + */ + inline int insertCopy(size_t a_idx, ElementType const &a_rThat) RT_NOEXCEPT + { + return insertCopyWorker(a_idx, a_rThat, false /*a_fReplace*/); + } + + /** + * Appends the given object to the array. + * + * @returns VINF_SUCCESS on success. + * VERR_INVALID_POINTER, VERR_NO_MEMORY, VERR_NO_STR_MEMORY or VERR_OUT_OF_RANGE on failure. + * @param a_pThat The object to insert. The array takes ownership of the object on success. + */ + inline int append(ElementType *a_pThat) RT_NOEXCEPT + { + return insertWorker(~(size_t)0, a_pThat, false /*a_fReplace*/); + } + + /** + * Appends a copy of the object at the specified index. + * + * @returns VINF_SUCCESS on success. + * VERR_NO_MEMORY, VERR_NO_STR_MEMORY or VERR_OUT_OF_RANGE on failure. + * @param a_rThat The object to insert a copy of. + */ + inline int appendCopy(ElementType const &a_rThat) RT_NOEXCEPT + { + return insertCopyWorker(~(size_t)0, a_rThat, false /*a_fReplace*/); + } + + /** + * Prepends the given object to the array. + * + * @returns VINF_SUCCESS on success. + * VERR_INVALID_POINTER, VERR_NO_MEMORY, VERR_NO_STR_MEMORY or VERR_OUT_OF_RANGE on failure. + * @param a_pThat The object to insert. The array takes ownership of the object on success. + */ + inline int prepend(ElementType *a_pThat) RT_NOEXCEPT + { + return insertWorker(0, a_pThat, false /*a_fReplace*/); + } + + /** + * Prepends a copy of the object at the specified index. + * + * @returns VINF_SUCCESS on success. + * VERR_NO_MEMORY, VERR_NO_STR_MEMORY or VERR_OUT_OF_RANGE on failure. + * @param a_rThat The object to insert a copy of. + */ + inline int prependCopy(ElementType const &a_rThat) RT_NOEXCEPT + { + return insertCopyWorker(0, a_rThat, false /*a_fReplace*/); + } + + /** + * Insert the given object at the specified index. + * + * @returns VINF_SUCCESS on success. + * VERR_INVALID_POINTER, VERR_NO_MEMORY, VERR_NO_STR_MEMORY or VERR_OUT_OF_RANGE on failure. + * @param a_idx The index of the existing object to replace. + * @param a_pThat The replacement object. The array takes ownership of the object on success. + */ + inline int replace(size_t a_idx, ElementType *a_pThat) RT_NOEXCEPT + { + return insertWorker(a_idx, a_pThat, true /*a_fReplace*/); + } + + /** + * Insert a copy of the object at the specified index. + * + * @returns VINF_SUCCESS on success. + * VERR_NO_MEMORY, VERR_NO_STR_MEMORY or VERR_OUT_OF_RANGE on failure. + * @param a_idx The index of the existing object to replace. + * @param a_rThat The object to insert a copy of. + */ + inline int replaceCopy(size_t a_idx, ElementType const &a_rThat) RT_NOEXCEPT + { + return insertCopyWorker(a_idx, a_rThat, true /*a_fReplace*/); + } + + /** + * Returns the object at a given index. + * + * @returns The object at @a a_idx, NULL if out of range. + * @param a_idx The array index. + */ + inline ElementType *at(size_t a_idx) RT_NOEXCEPT + { + if (a_idx < m_cElements) + return (ElementType *)m_papElements[a_idx]; + return NULL; + } + + /** + * Returns the object at a given index, const variant. + * + * @returns The object at @a a_idx, NULL if out of range. + * @param a_idx The array index. + */ + inline ElementType const *at(size_t a_idx) const RT_NOEXCEPT + { + if (a_idx < m_cElements) + return (ElementType const *)m_papElements[a_idx]; + return NULL; + } + + /** + * Returns the first object in the array. + * @returns The first object, NULL if empty. + */ + inline ElementType *first() RT_NOEXCEPT + { + return at(0); + } + + /** + * Returns the first object in the array, const variant. + * @returns The first object, NULL if empty. + */ + inline ElementType const *first() const RT_NOEXCEPT + { + return at(0); + } + + /** + * Returns the last object in the array. + * @returns The last object, NULL if empty. + */ + inline ElementType *last() RT_NOEXCEPT + { + return at(m_cElements - 1); + } + + /** + * Returns the last object in the array, const variant. + * @returns The last object, NULL if empty. + */ + inline ElementType const *last() const RT_NOEXCEPT + { + return at(m_cElements - 1); + } + + +protected: + virtual RTCRestArrayBase *createClone(void) const RT_NOEXCEPT RT_OVERRIDE + { + return new (std::nothrow) RTCRestArray(); + } + + virtual RTCRestObjectBase *createValue(void) RT_NOEXCEPT RT_OVERRIDE + { + return new (std::nothrow) ElementType(); + } + + virtual int deserializeValueInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT RT_OVERRIDE + { + return ElementType::deserializeInstanceFromJson(a_rCursor, a_ppInstance); + } +}; + + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_restarray_h */ + diff --git a/include/iprt/cpp/restbase.h b/include/iprt/cpp/restbase.h new file mode 100644 index 00000000..912610df --- /dev/null +++ b/include/iprt/cpp/restbase.h @@ -0,0 +1,1106 @@ +/** @file + * IPRT - C++ Representational State Transfer (REST) Base Classes. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_restbase_h +#define IPRT_INCLUDED_cpp_restbase_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/errcore.h> /* VERR_NO_MEMORY */ +#include <iprt/json.h> +#include <iprt/stdarg.h> +#include <iprt/time.h> +#include <iprt/cpp/ministring.h> + + +/** @defgroup grp_rt_cpp_restbase C++ Representational State Transfer (REST) Base Classes. + * @ingroup grp_rt_cpp + * @{ + */ + +/* forward decl: */ +class RTCRestOutputBase; +class RTCRestJsonPrimaryCursor; + +/** + * JSON cursor structure. + * + * This reduces the number of parameters passed around when deserializing JSON + * input and also helps constructing full object name for logging and error reporting. + */ +struct RT_DECL_CLASS RTCRestJsonCursor +{ + /** Handle to the value being parsed. */ + RTJSONVAL m_hValue; + /** Name of the value. */ + const char *m_pszName; + /** Pointer to the parent, NULL if primary. */ + struct RTCRestJsonCursor const *m_pParent; + /** Pointer to the primary cursor structure. */ + RTCRestJsonPrimaryCursor *m_pPrimary; + + RTCRestJsonCursor(struct RTCRestJsonCursor const &a_rParent) RT_NOEXCEPT + : m_hValue(NIL_RTJSONVAL), m_pszName(NULL), m_pParent(&a_rParent), m_pPrimary(a_rParent.m_pPrimary) + { } + + RTCRestJsonCursor(RTJSONVAL hValue, const char *pszName, struct RTCRestJsonCursor *pParent) RT_NOEXCEPT + : m_hValue(hValue), m_pszName(pszName), m_pParent(pParent), m_pPrimary(pParent->m_pPrimary) + { } + + RTCRestJsonCursor(RTJSONVAL hValue, const char *pszName) RT_NOEXCEPT + : m_hValue(hValue), m_pszName(pszName), m_pParent(NULL), m_pPrimary(NULL) + { } + + ~RTCRestJsonCursor() + { + if (m_hValue != NIL_RTJSONVAL) + { + RTJsonValueRelease(m_hValue); + m_hValue = NIL_RTJSONVAL; + } + } +}; + + +/** + * The primary JSON cursor class. + */ +class RT_DECL_CLASS RTCRestJsonPrimaryCursor +{ +public: + /** The cursor for the first level. */ + RTCRestJsonCursor m_Cursor; + /** Error info keeper. */ + PRTERRINFO m_pErrInfo; + + /** Creates a primary json cursor with optiona error info. */ + RTCRestJsonPrimaryCursor(RTJSONVAL hValue, const char *pszName, PRTERRINFO pErrInfo = NULL) RT_NOEXCEPT + : m_Cursor(hValue, pszName) + , m_pErrInfo(pErrInfo) + { + m_Cursor.m_pPrimary = this; + } + + virtual ~RTCRestJsonPrimaryCursor() + { } + + /** + * Add an error message. + * + * @returns a_rc + * @param a_rCursor The cursor reporting the error. + * @param a_rc The status code. + * @param a_pszFormat Format string. + * @param ... Format string arguments. + */ + virtual int addError(RTCRestJsonCursor const &a_rCursor, int a_rc, const char *a_pszFormat, ...) RT_NOEXCEPT; + + /** + * Reports that the current field is not known. + * + * @returns Status to propagate. + * @param a_rCursor The cursor for the field. + */ + virtual int unknownField(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT; + + /** + * Copies the full path into pszDst. + * + * @returns pszDst + * @param a_rCursor The cursor to start walking at. + * @param a_pszDst Where to put the path. + * @param a_cbDst Size of the destination buffer. + */ + virtual char *getPath(RTCRestJsonCursor const &a_rCursor, char *a_pszDst, size_t a_cbDst) const RT_NOEXCEPT; +}; + + +/** + * Abstract base class for REST primitive types and data objects (via + * RTCRestDataObject). + * + * The only information this keeps is the null indicator. + */ +class RT_DECL_CLASS RTCRestObjectBase +{ +public: + RTCRestObjectBase() RT_NOEXCEPT; + RTCRestObjectBase(RTCRestObjectBase const &a_rThat) RT_NOEXCEPT; + virtual ~RTCRestObjectBase(); + + /** Copy assignment operator. */ + RTCRestObjectBase &operator=(RTCRestObjectBase const &a_rThat) RT_NOEXCEPT; + + /** + * Create a copy of this object. + * + * @returns Pointer to copy. + */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT = 0; + + /** + * Tests if the object is @a null. + * @returns true if null, false if not. + */ + inline bool isNull(void) const RT_NOEXCEPT { return m_fNullIndicator; }; + + /** + * Sets the object to @a null and fills it with defaults. + * @returns IPRT status code (from resetToDefault). + */ + virtual int setNull(void) RT_NOEXCEPT; + + /** + * Sets the object to not-null state (i.e. undoes setNull()). + * @remarks Only really important for strings. + */ + virtual void setNotNull(void) RT_NOEXCEPT; + + /** + * Resets the object to all default values. + * @returns IPRT status code. + */ + virtual int resetToDefault() RT_NOEXCEPT = 0; + + /** + * Serialize the object as JSON. + * + * @returns a_rDst + * @param a_rDst The destination for the serialization. + */ + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT = 0; + + /** + * Deserialize object from the given JSON iterator. + * + * @returns IPRT status code. + * @param a_rCursor The JSON cursor. + */ + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT = 0; + + /** + * Polymorphic JSON deserialization helper that instantiate the matching class using + * the discriminator field. + * + * @returns IPRT status code. + * @param a_rCursor The JSON cursor. + * @param a_ppInstance Where to return the deserialized instance. + * May return an object on failure. + */ + typedef DECLCALLBACKTYPE(int, FNDESERIALIZEINSTANCEFROMJSON,(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance)); + /** Pointer to a FNDESERIALIZEINSTANCEFROMJSON function. */ + typedef FNDESERIALIZEINSTANCEFROMJSON *PFNDESERIALIZEINSTANCEFROMJSON; + + /** + * Flags for toString(). + * + * The kCollectionFormat_xxx bunch controls multiple values in arrays + * are formatted. They are ignored by everyone else. + * + * @note When adding collection format types, make sure to also + * update RTCRestArrayBase::toString(). + * @note Bit 24 is reserved (for kHdrField_MapCollection). + */ + enum + { + kCollectionFormat_Unspecified = 0, /**< Not specified. */ + kCollectionFormat_csv, /**< Comma-separated list. */ + kCollectionFormat_ssv, /**< Space-separated list. */ + kCollectionFormat_tsv, /**< Tab-separated list. */ + kCollectionFormat_pipes, /**< Pipe-separated list. */ + kCollectionFormat_multi, /**< Special collection type that must be handled by caller of toString. */ + kCollectionFormat_Mask = 7, /**< Collection type mask. */ + + kToString_Append = 8 /**< Append to the string/object (rather than assigning). */ + }; + + /** + * String conversion. + * + * The default implementation of is a wrapper around serializeAsJson(). + * + * @returns IPRT status code. + * @param a_pDst Pointer to the destionation string. + * @param a_fFlags kCollectionFormat_xxx. + */ + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const RT_NOEXCEPT; + + /** + * String convertsion, naive variant. + * + * @returns String represenation. + */ + RTCString toString() const; + + /** + * Convert from (header) string value. + * + * The default implementation of is a wrapper around deserializeFromJson(). + * + * @returns IPRT status code. + * @param a_rValue The string value string to parse. + * @param a_pszName Field name or similar. + * @param a_pErrInfo Where to return additional error info. Optional. + * @param a_fFlags kCollectionFormat_xxx. + */ + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT; + + /** Type classification */ + typedef enum kTypeClass + { + kTypeClass_Invalid = 0, + kTypeClass_Bool, /**< Primitive: bool. */ + kTypeClass_Int64, /**< Primitive: int64_t. */ + kTypeClass_Int32, /**< Primitive: int32_t. */ + kTypeClass_Int16, /**< Primitive: int16_t. */ + kTypeClass_Double, /**< Primitive: double. */ + kTypeClass_String, /**< Primitive: string. */ + kTypeClass_Date, /**< Date. */ + kTypeClass_Uuid, /**< UUID. */ + kTypeClass_Binary, /**< Binary blob. */ + kTypeClass_DataObject, /**< Data object child (RTCRestDataObject). */ + kTypeClass_AnyObject, /**< Any kind of object (RTCRestAnyObject). */ + kTypeClass_Array, /**< Array (containing any kind of object). */ + kTypeClass_StringMap, /**< String map (containing any kind of object). */ + kTypeClass_StringEnum /**< String enum. */ + } kTypeClass; + + /** + * Returns the object type class. + */ + virtual kTypeClass typeClass(void) const RT_NOEXCEPT = 0; + + /** + * Returns the object type name. + */ + virtual const char *typeName(void) const RT_NOEXCEPT = 0; + +protected: + /** Null indicator. + * @remarks The null values could be mapped onto C/C++ NULL pointer values, + * with the consequence that all data members in objects and such would + * have had to been allocated individually, even simple @a bool members. + * Given that we're overly paranoid about heap allocations (std::bad_alloc), + * it's more fitting to use a null indicator for us. + */ + bool m_fNullIndicator; +}; + + +/** + * Class wrapping 'bool'. + */ +class RT_DECL_CLASS RTCRestBool : public RTCRestObjectBase +{ +public: + /** Default constructor. */ + RTCRestBool() RT_NOEXCEPT; + /** Copy constructor. */ + RTCRestBool(RTCRestBool const &a_rThat) RT_NOEXCEPT; + /** From value constructor. */ + RTCRestBool(bool fValue) RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestBool(); + /** Copy assignment operator. */ + RTCRestBool &operator=(RTCRestBool const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + int assignCopy(RTCRestBool const &a_rThat) RT_NOEXCEPT; + /** Assign value and clear null indicator. */ + void assignValue(bool a_fValue) RT_NOEXCEPT; + /** Make a clone of this object. */ + inline RTCRestBool *clone() const RT_NOEXCEPT { return (RTCRestBool *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = 0) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT; + +public: + /** The value. */ + bool m_fValue; +}; + + +/** + * Class wrapping 'int64_t'. + */ +class RT_DECL_CLASS RTCRestInt64 : public RTCRestObjectBase +{ +public: + /** Default constructor. */ + RTCRestInt64() RT_NOEXCEPT; + /** Copy constructor. */ + RTCRestInt64(RTCRestInt64 const &a_rThat) RT_NOEXCEPT; + /** From value constructor. */ + RTCRestInt64(int64_t a_iValue) RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestInt64(); + /** Copy assignment operator. */ + RTCRestInt64 &operator=(RTCRestInt64 const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + int assignCopy(RTCRestInt64 const &a_rThat) RT_NOEXCEPT; + /** Assign value and clear null indicator. */ + void assignValue(int64_t a_iValue) RT_NOEXCEPT; + /** Make a clone of this object. */ + inline RTCRestInt64 *clone() const RT_NOEXCEPT { return (RTCRestInt64 *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = 0) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT; + +public: + /** The value. */ + int64_t m_iValue; +}; + + +/** + * Class wrapping 'int32_t'. + */ +class RT_DECL_CLASS RTCRestInt32 : public RTCRestObjectBase +{ +public: + /** Default constructor. */ + RTCRestInt32() RT_NOEXCEPT; + /** Copy constructor. */ + RTCRestInt32(RTCRestInt32 const &a_rThat) RT_NOEXCEPT; + /** From value constructor. */ + RTCRestInt32(int32_t iValue) RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestInt32() RT_NOEXCEPT; + /** Copy assignment operator. */ + RTCRestInt32 &operator=(RTCRestInt32 const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + int assignCopy(RTCRestInt32 const &a_rThat) RT_NOEXCEPT; + /** Assign value and clear null indicator. */ + void assignValue(int32_t a_iValue) RT_NOEXCEPT; + /** Make a clone of this object. */ + inline RTCRestInt32 *clone() const { return (RTCRestInt32 *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = 0) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT; + +public: + /** The value. */ + int32_t m_iValue; +}; + + +/** + * Class wrapping 'int16_t'. + */ +class RT_DECL_CLASS RTCRestInt16 : public RTCRestObjectBase +{ +public: + /** Default constructor. */ + RTCRestInt16() RT_NOEXCEPT; + /** Copy constructor. */ + RTCRestInt16(RTCRestInt16 const &a_rThat) RT_NOEXCEPT; + /** From value constructor. */ + RTCRestInt16(int16_t iValue) RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestInt16(); + /** Copy assignment operator. */ + RTCRestInt16 &operator=(RTCRestInt16 const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + int assignCopy(RTCRestInt16 const &a_rThat) RT_NOEXCEPT; + /** Assign value and clear null indicator. */ + void assignValue(int16_t a_iValue) RT_NOEXCEPT; + /** Make a clone of this object. */ + inline RTCRestInt16 *clone() const RT_NOEXCEPT { return (RTCRestInt16 *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = 0) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT; + +public: + /** The value. */ + int16_t m_iValue; +}; + + +/** + * Class wrapping 'double'. + */ +class RT_DECL_CLASS RTCRestDouble : public RTCRestObjectBase +{ +public: + /** Default constructor. */ + RTCRestDouble() RT_NOEXCEPT; + /** Copy constructor. */ + RTCRestDouble(RTCRestDouble const &a_rThat) RT_NOEXCEPT; + /** From value constructor. */ + RTCRestDouble(double rdValue) RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestDouble(); + /** Copy assignment operator. */ + RTCRestDouble &operator=(RTCRestDouble const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + int assignCopy(RTCRestDouble const &a_rThat) RT_NOEXCEPT; + /** Assign value and clear null indicator. */ + void assignValue(double a_rdValue) RT_NOEXCEPT; + /** Make a clone of this object. */ + inline RTCRestDouble *clone() const RT_NOEXCEPT { return (RTCRestDouble *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = 0) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT; + +public: + /** The value. */ + double m_rdValue; +}; + + +/** + * Class wrapping 'RTCString'. + */ +class RT_DECL_CLASS RTCRestString : public RTCRestObjectBase, public RTCString +{ +public: + /** Default constructor. */ + RTCRestString() RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestString(); + + /** Copy constructor. */ + RTCRestString(RTCRestString const &a_rThat); + /** From value constructor. */ + RTCRestString(RTCString const &a_rThat); + /** From value constructor. */ + RTCRestString(const char *a_pszSrc); + /** Safe copy assignment method. */ + int assignCopy(RTCRestString const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + int assignCopy(RTCString const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + int assignCopy(const char *a_pszThat) RT_NOEXCEPT; + /** Make a clone of this object. */ + inline RTCRestString *clone() const RT_NOEXCEPT { return (RTCRestString *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int setNull(void) RT_NOEXCEPT RT_OVERRIDE; /* (ambigious, so overrider it to make sure.) */ + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT; + + /** @name RTCString assignment methods we need to replace to manage the null indicator + * @{ */ + int assignNoThrow(const RTCString &a_rSrc) RT_NOEXCEPT; + int assignNoThrow(const char *a_pszSrc) RT_NOEXCEPT; + int assignNoThrow(const RTCString &a_rSrc, size_t a_offSrc, size_t a_cchSrc = npos) RT_NOEXCEPT; + int assignNoThrow(const char *a_pszSrc, size_t a_cchSrc) RT_NOEXCEPT; + int assignNoThrow(size_t a_cTimes, char a_ch) RT_NOEXCEPT; + int printfNoThrow(const char *pszFormat, ...) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 2); + int printfVNoThrow(const char *pszFormat, va_list va) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 0); + RTCRestString &operator=(const char *a_pcsz); + RTCRestString &operator=(const RTCString &a_rThat); + RTCRestString &operator=(const RTCRestString &a_rThat); + RTCRestString &assign(const RTCString &a_rSrc); + RTCRestString &assign(const char *a_pszSrc); + RTCRestString &assign(const RTCString &a_rSrc, size_t a_offSrc, size_t a_cchSrc = npos); + RTCRestString &assign(const char *a_pszSrc, size_t a_cchSrc); + RTCRestString &assign(size_t a_cTimes, char a_ch); + RTCRestString &printf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + RTCRestString &printfV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + /** @} */ +}; + + +/** + * Date class. + * + * There are numerous ways of formatting a timestamp and the specifications + * we're currently working with doesn't have a way of telling it seems. + * Thus, decoding need to have fail safes built in so the user can give hints. + * The formatting likewise needs to be told which format to use by the user. + * + * Two side-effects of the format stuff is that the default constructor creates + * an object that is null, and resetToDefault will do the same bug leave the + * format as a hint. + */ +class RT_DECL_CLASS RTCRestDate : public RTCRestObjectBase +{ +public: + /** Default constructor. + * @note The result is a null-object. */ + RTCRestDate() RT_NOEXCEPT; + /** Copy constructor. */ + RTCRestDate(RTCRestDate const &a_rThat); + /** Destructor. */ + virtual ~RTCRestDate(); + /** Copy assignment operator. */ + RTCRestDate &operator=(RTCRestDate const &a_rThat); + /** Safe copy assignment method. */ + int assignCopy(RTCRestDate const &a_rThat) RT_NOEXCEPT; + /** Make a clone of this object. */ + inline RTCRestDate *clone() const RT_NOEXCEPT{ return (RTCRestDate *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = 0) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT; + + /** Date formats. */ + typedef enum + { + kFormat_Invalid = 0, + kFormat_Rfc2822, /**< Format it according to RFC-2822. */ + kFormat_Rfc7131, /**< Format it according to RFC-7131 (HTTP). */ + kFormat_Rfc3339, /**< Format it according to RFC-3339 (ISO-8601) (no fraction). */ + kFormat_Rfc3339_Fraction_2, /**< Format it according to RFC-3339 (ISO-8601) with two digit fraction (hundreths). */ + kFormat_Rfc3339_Fraction_3, /**< Format it according to RFC-3339 (ISO-8601) with three digit fraction (milliseconds). */ + kFormat_Rfc3339_Fraction_6, /**< Format it according to RFC-3339 (ISO-8601) with six digit fraction (microseconds). */ + kFormat_Rfc3339_Fraction_9, /**< Format it according to RFC-3339 (ISO-8601) with nine digit fraction (nanoseconds). */ + kFormat_End + } kFormat; + + /** + * Assigns the value, formats it as a string and clears the null indicator. + * + * @returns VINF_SUCCESS, VERR_NO_STR_MEMORY or VERR_INVALID_PARAMETER. + * @param a_pTimeSpec The time spec to set. + * @param a_enmFormat The date format to use when formatting it. + */ + int assignValue(PCRTTIMESPEC a_pTimeSpec, kFormat a_enmFormat) RT_NOEXCEPT; + int assignValueRfc2822(PCRTTIMESPEC a_pTimeSpec) RT_NOEXCEPT; /**< Convenience method for email/whatnot. */ + int assignValueRfc7131(PCRTTIMESPEC a_pTimeSpec) RT_NOEXCEPT; /**< Convenience method for HTTP date. */ + int assignValueRfc3339(PCRTTIMESPEC a_pTimeSpec) RT_NOEXCEPT; /**< Convenience method for ISO-8601 timstamp. */ + + /** + * Assigns the current UTC time and clears the null indicator . + * + * @returns VINF_SUCCESS, VERR_NO_STR_MEMORY or VERR_INVALID_PARAMETER. + * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY. + * @param a_enmFormat The date format to use when formatting it. + */ + int assignNow(kFormat a_enmFormat) RT_NOEXCEPT; + int assignNowRfc2822() RT_NOEXCEPT; /**< Convenience method for email/whatnot. */ + int assignNowRfc7131() RT_NOEXCEPT; /**< Convenience method for HTTP date. */ + int assignNowRfc3339() RT_NOEXCEPT; /**< Convenience method for ISO-8601 timstamp. */ + + /** + * Sets the format to help deal with decoding issues. + * + * This can also be used to change the date format for an okay timespec. + * @returns IPRT status code. + * @param a_enmFormat The date format to try/set. + */ + int setFormat(kFormat a_enmFormat) RT_NOEXCEPT; + + /** Check if the value is okay (m_TimeSpec & m_Exploded). */ + inline bool isOkay() const RT_NOEXCEPT { return m_fTimeSpecOkay; } + /** Get the timespec value. */ + inline RTTIMESPEC const &getTimeSpec() const RT_NOEXCEPT { return m_TimeSpec; } + /** Get the exploded time. */ + inline RTTIME const &getExploded() const RT_NOEXCEPT { return m_Exploded; } + /** Gets the format. */ + inline kFormat getFormat() const RT_NOEXCEPT { return m_enmFormat; } + /** Get the formatted/raw string value. */ + inline RTCString const &getString() const RT_NOEXCEPT { return m_strFormatted; } + + /** Get nanoseconds since unix epoch. */ + inline int64_t getEpochNano() const RT_NOEXCEPT { return RTTimeSpecGetNano(&m_TimeSpec); } + /** Get seconds since unix epoch. */ + inline int64_t getEpochSeconds() const RT_NOEXCEPT { return RTTimeSpecGetSeconds(&m_TimeSpec); } + /** Checks if UTC time. */ + inline bool isUtc() const RT_NOEXCEPT { return (m_Exploded.fFlags & RTTIME_FLAGS_TYPE_MASK) != RTTIME_FLAGS_TYPE_LOCAL; } + /** Checks if local time. */ + inline bool isLocal() const RT_NOEXCEPT { return (m_Exploded.fFlags & RTTIME_FLAGS_TYPE_MASK) == RTTIME_FLAGS_TYPE_LOCAL; } + +protected: + /** The value. */ + RTTIMESPEC m_TimeSpec; + /** The exploded time value. */ + RTTIME m_Exploded; + /** Set if m_TimeSpec is okay, consult m_strFormatted if not. */ + bool m_fTimeSpecOkay; + /** The format / format hint. */ + kFormat m_enmFormat; + /** The formatted date string. + * This will be the raw input string for a deserialized value, where as for + * a value set by the user it will be the formatted value. */ + RTCString m_strFormatted; + + /** + * Explodes and formats the m_TimeSpec value. + * + * Sets m_Exploded, m_strFormatted, m_fTimeSpecOkay, and m_enmFormat, clears m_fNullIndicator. + * + * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY. + * @param a_enmFormat The format to use. + */ + int explodeAndFormat(kFormat a_enmFormat) RT_NOEXCEPT; + + /** + * Formats the m_Exploded value. + * + * Sets m_strFormatted, m_fTimeSpecOkay, and m_enmFormat, clears m_fNullIndicator. + * + * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY. + * @param a_enmFormat The format to use. + */ + int format(kFormat a_enmFormat) RT_NOEXCEPT; + + /** + * Internal worker that attempts to decode m_strFormatted. + * + * Sets m_fTimeSpecOkay. + * + * @returns IPRT status code. + * @param enmFormat Specific format to try, kFormat_Invalid (default) to try guess it. + */ + int decodeFormattedString(kFormat enmFormat = kFormat_Invalid) RT_NOEXCEPT; +}; + + +/** We should provide a proper UUID class eventually. Currently it is not used. */ +typedef RTCRestString RTCRestUuid; + + +/** + * String enum base class. + */ +class RT_DECL_CLASS RTCRestStringEnumBase : public RTCRestObjectBase +{ +public: + /** Enum map entry. */ + typedef struct ENUMMAPENTRY + { + const char *pszName; + uint32_t cchName; + int32_t iValue; + } ENUMMAPENTRY; + + /** Default constructor. */ + RTCRestStringEnumBase() RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestStringEnumBase(); + + /** Copy constructor. */ + RTCRestStringEnumBase(RTCRestStringEnumBase const &a_rThat); + /** Copy assignment operator. */ + RTCRestStringEnumBase &operator=(RTCRestStringEnumBase const &a_rThat); + + /** Safe copy assignment method. */ + int assignCopy(RTCRestStringEnumBase const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + inline int assignCopy(RTCString const &a_rThat) RT_NOEXCEPT { return setByString(a_rThat); } + /** Safe copy assignment method. */ + inline int assignCopy(const char *a_pszThat) RT_NOEXCEPT { return setByString(a_pszThat); } + + /* Overridden methods: */ + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** + * Sets the value given a C-string value. + * + * @retval VINF_SUCCESS on success. + * @retval VWRN_NOT_FOUND if not mappable to enum value. + * @retval VERR_NO_STR_MEMORY if not mappable and we're out of memory. + * @param a_pszValue The string value. + * @param a_cchValue The string value length. Optional. + */ + int setByString(const char *a_pszValue, size_t a_cchValue = RTSTR_MAX) RT_NOEXCEPT; + + /** + * Sets the value given a string value. + * + * @retval VINF_SUCCESS on success. + * @retval VWRN_NOT_FOUND if not mappable to enum value. + * @retval VERR_NO_STR_MEMORY if not mappable and we're out of memory. + * @param a_rValue The string value. + */ + int setByString(RTCString const &a_rValue) RT_NOEXCEPT; + + /** + * Gets the string value. + */ + const char *getString() const RT_NOEXCEPT; + + /** Maps the given string value to an enum. */ + int stringToEnum(const char *a_pszValue, size_t a_cchValue = RTSTR_MAX) RT_NOEXCEPT; + /** Maps the given string value to an enum. */ + int stringToEnum(RTCString const &a_rStrValue) RT_NOEXCEPT; + /** Maps the given string value to an enum. */ + const char *enumToString(int a_iEnumValue, size_t *a_pcchString) RT_NOEXCEPT; + + +protected: + /** The enum value. */ + int m_iEnumValue; + /** The string value if not a match. */ + RTCString m_strValue; + + /** + * Worker for setting the object to the given enum value. + * + * @retval true on success. + * @retval false if a_iEnumValue can't be translated. + * @param a_iEnumValue The enum value to set. + */ + bool setWorker(int a_iEnumValue) RT_NOEXCEPT; + + /** Helper for implementing RTCRestObjectBase::clone(). */ + RTCRestObjectBase *cloneWorker(RTCRestStringEnumBase *a_pDst) const RT_NOEXCEPT; + + /** + * Gets the mapping table. + * + * @returns Pointer to the translation table. + * @param pcEntries Where to return the translation table size. + */ + virtual ENUMMAPENTRY const *getMappingTable(size_t *pcEntries) const RT_NOEXCEPT = 0; +}; + + +/** + * String enum template class. + * + * Takes the enum type as argument. + */ +template <typename EnumType> +class RTCRestStringEnum : public RTCRestStringEnumBase +{ +public: + typedef EnumType Type; /**< The enum type. */ + + /** Default constructor */ + RTCRestStringEnum() RT_NOEXCEPT : RTCRestStringEnumBase() { } + /** Constructor with initial enum value. */ + RTCRestStringEnum(Type a_enmValue) RT_NOEXCEPT : RTCRestStringEnumBase() { set(a_enmValue); } + /** Constructor with string default. */ + RTCRestStringEnum(const char *a_pszDefault) : RTCRestStringEnumBase() { setByString(a_pszDefault); } + /** Copy constructor */ + RTCRestStringEnum(RTCRestStringEnum const &a_rThat) : RTCRestStringEnumBase(a_rThat) { } + /** Make a clone of this object. */ + inline RTCRestStringEnum *clone() const RT_NOEXCEPT { return (RTCRestStringEnum *)baseClone(); } + + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE + { + return cloneWorker(new (std::nothrow) RTCRestStringEnum()); + } + + /** Copy assignment operator. */ + RTCRestStringEnum &operator=(RTCRestStringEnum const &a_rThat) RT_NOEXCEPT + { + RTCRestStringEnumBase::operator=(a_rThat); + return *this; + } + + /** + * Gets the enum value. + * @returns enum value. + * @retval kXxxxInvalid means there was no mapping for the string, or that + * no value has been assigned yet. + */ + Type get() const RT_NOEXCEPT { return (Type)m_iEnumValue; } + + /** + * Sets the object value to @a a_enmType + * + * @returns true if a_enmType is valid, false if not. + * @param a_enmType The new value. + */ + bool set(Type a_enmType) RT_NOEXCEPT { return setWorker((int)a_enmType); } + + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE { return "RTCRestStringEnum<EnumType>"; } + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT + { + return new (std::nothrow) RTCRestStringEnum(); + } + + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT + { + *a_ppInstance = new (std::nothrow) RTCRestStringEnum(); + if (*a_ppInstance) + return (*a_ppInstance)->deserializeFromJson(a_rCursor); + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_NO_MEMORY, "Out of memory"); + } + +protected: + /** Enum mapping table. */ + static const ENUMMAPENTRY s_aMappingTable[]; + /** Enum mapping table size. */ + static const size_t s_cMappingTable; + + virtual ENUMMAPENTRY const *getMappingTable(size_t *pcEntries) const RT_NOEXCEPT RT_OVERRIDE + { + *pcEntries = s_cMappingTable; + return s_aMappingTable; + } +}; + + +/** + * Class for handling binary blobs (strings). + * + * There are specializations of this class for body parameters and responses, + * see RTCRestBinaryParameter and RTCRestBinaryResponse. + */ +class RT_DECL_CLASS RTCRestBinary : public RTCRestObjectBase +{ +public: + /** Default constructor. */ + RTCRestBinary() RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestBinary(); + + /** Safe copy assignment method. */ + virtual int assignCopy(RTCRestBinary const &a_rThat) RT_NOEXCEPT; + /** Safe buffer copy method. */ + virtual int assignCopy(void const *a_pvData, size_t a_cbData) RT_NOEXCEPT; + + /** Use the specified data buffer directly. */ + virtual int assignReadOnly(void const *a_pvData, size_t a_cbData) RT_NOEXCEPT; + /** Use the specified data buffer directly. */ + virtual int assignWriteable(void *a_pvBuf, size_t a_cbBuf) RT_NOEXCEPT; + /** Frees the data held by the object and resets it default state. */ + virtual void freeData() RT_NOEXCEPT; + + /** Returns a pointer to the data blob. */ + inline const uint8_t *getPtr() const RT_NOEXCEPT { return m_pbData; } + /** Gets the size of the data. */ + inline size_t getSize() const RT_NOEXCEPT { return m_cbData; } + + /** Make a clone of this object. */ + inline RTCRestBinary *clone() const RT_NOEXCEPT { return (RTCRestBinary *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int setNull(void) RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault(void) RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const RT_NOEXCEPT RT_OVERRIDE; + virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT; + +protected: + /** Pointer to data blob. */ + uint8_t *m_pbData; + /** Amount of valid data in the blob. */ + size_t m_cbData; + /** Number of bytes allocated for the m_pbData buffer. */ + size_t m_cbAllocated; + /** Set if the data is freeable, only ever clear if user data. */ + bool m_fFreeable; + /** Set if the data blob is readonly user provided data. */ + bool m_fReadOnly; + +private: + /* No copy constructor or copy assignment: */ + RTCRestBinary(RTCRestBinary const &a_rThat); + RTCRestBinary &operator=(RTCRestBinary const &a_rThat); +}; + + +/** + * Abstract base class for REST data model classes. + */ +class RT_DECL_CLASS RTCRestDataObject : public RTCRestObjectBase +{ +public: + RTCRestDataObject() RT_NOEXCEPT; + RTCRestDataObject(RTCRestDataObject const &a_rThat) RT_NOEXCEPT; + virtual ~RTCRestDataObject(); + + /* Overridden methods:*/ + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** + * Serialize the object members as JSON. + * + * @returns a_rDst + * @param a_rDst The destination for the serialization. + */ + virtual RTCRestOutputBase &serializeMembersAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT; + + /** + * Deserialize object from the given JSON iterator. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if field is unknown. Top level caller will do + * invoke unknownField() on it. + * + * @param a_rCursor The JSON cursor with the current member. + * @param a_cchName The length of a_rCursor.m_pszName. + */ + virtual int deserializeMemberFromJson(RTCRestJsonCursor const &a_rCursor, size_t a_cchName) RT_NOEXCEPT; + +protected: + /** The is-set bits for all the fields. */ + uint64_t m_fIsSet; + + /** Copy assignment operator. */ + RTCRestDataObject &operator=(RTCRestDataObject const &a_rThat) RT_NOEXCEPT; + + /** Safe copy assignment method. */ + virtual int assignCopy(RTCRestDataObject const &a_rThat) RT_NOEXCEPT; +}; + + +/** + * Abstract base class for polymorphic REST data model classes. + */ +class RT_DECL_CLASS RTCRestPolyDataObject : public RTCRestDataObject +{ +public: + RTCRestPolyDataObject() RT_NOEXCEPT; + RTCRestPolyDataObject(RTCRestPolyDataObject const &a_rThat) RT_NOEXCEPT; + virtual ~RTCRestPolyDataObject(); + + /* Overridden methods:*/ + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + + /** Checks if the instance is of a child class (@c true) or of the parent (@c false). */ + virtual bool isChild() const RT_NOEXCEPT; + +protected: + + /** Copy assignment operator. */ + RTCRestPolyDataObject &operator=(RTCRestPolyDataObject const &a_rThat) RT_NOEXCEPT; +}; + + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_restbase_h */ + diff --git a/include/iprt/cpp/restclient.h b/include/iprt/cpp/restclient.h new file mode 100644 index 00000000..b62a89ea --- /dev/null +++ b/include/iprt/cpp/restclient.h @@ -0,0 +1,826 @@ +/** @file + * IPRT - C++ Representational State Transfer (REST) Client Classes. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_restclient_h +#define IPRT_INCLUDED_cpp_restclient_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/http.h> +#include <iprt/cpp/restbase.h> +#include <iprt/cpp/reststringmap.h> + + +/** @defgroup grp_rt_cpp_restclient C++ Representational State Transfer (REST) Client Classes. + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * Specialization of RTCRestBinary for use with body parameters in a client. + * + * This enables registering data callbacks for provinding data to upload. + */ +class RT_DECL_CLASS RTCRestBinaryParameter : public RTCRestBinary +{ +public: + /** Default constructor. */ + RTCRestBinaryParameter() RT_NOEXCEPT; + + /** Safe copy assignment method. */ + virtual int assignCopy(RTCRestBinaryParameter const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. + * @note Resets callbacks and ASSUMES that @a a_cbData is the content length. */ + virtual int assignCopy(RTCRestBinary const &a_rThat) RT_NOEXCEPT RT_OVERRIDE; + /** Safe copy assignment method. + * @note Resets callbacks and ASSUMES that @a a_cbData is the content length. */ + virtual int assignCopy(void const *a_pvData, size_t a_cbData) RT_NOEXCEPT RT_OVERRIDE; + + /** + * Use the specified data buffer directly. + * @note Resets callbacks and ASSUMES that @a a_cbData is the content length. */ + virtual int assignReadOnly(void const *a_pvData, size_t a_cbData) RT_NOEXCEPT RT_OVERRIDE; + /** + * Use the specified data buffer directly. + * @note This will assert and work like assignReadOnly. */ + virtual int assignWriteable(void *a_pvBuf, size_t a_cbBuf) RT_NOEXCEPT RT_OVERRIDE; + + /** Make a clone of this object. */ + inline RTCRestBinaryParameter *clone() const RT_NOEXCEPT { return (RTCRestBinaryParameter *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + + /** + * Retrieves the callback data. + */ + inline void *getCallbackData() const RT_NOEXCEPT { return m_pvCallbackData; } + + /** + * Sets the content-type for an upload. + * + * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY. + * @param a_pszContentType The content type to set. + * If NULL, no content type is set. + */ + int setContentType(const char *a_pszContentType) RT_NOEXCEPT; + + /** + * Gets the content type that was set. + */ + inline RTCString const &getContentType() const RT_NOEXCEPT { return m_strContentType; } + + /** + * Gets the content-length value (UINT64_MAX if not available). + */ + inline uint64_t getContentLength() const RT_NOEXCEPT { return m_cbContentLength; } + + /** + * Callback for producing bytes to upload. + * + * @returns IPRT status code. + * @param a_pThis The related string object. + * @param a_pvDst Where to put the bytes. + * @param a_cbDst Max number of bytes to produce. + * @param a_offContent The byte offset corresponding to the start of @a a_pvDst. + * @param a_pcbActual Where to return the number of bytes actually produced. + * + * @remarks Use getCallbackData to get the user data. + * + * @note The @a a_offContent parameter does not imply random access or anthing + * like that, it is just a convenience provided by the caller. The value + * is the sum of the previously returned @a *pcbActual values. + */ + typedef DECLCALLBACKTYPE(int, FNPRODUCER,(RTCRestBinaryParameter *a_pThis, void *a_pvDst, size_t a_cbDst, + uint64_t a_offContent, size_t *a_pcbActual)) /*RT_NOEXCEPT*/; + /** Pointer to a byte producer callback. */ + typedef FNPRODUCER *PFNPRODUCER; + + /** + * Sets the producer callback. + * + * @param a_pfnProducer The callback function for producing data. + * @param a_pvCallbackData Data the can be retrieved from the callback + * using getCallbackData(). + * @param a_cbContentLength The amount of data that will be uploaded and + * to be set as the value of the content-length + * header field. Pass UINT64_MAX if not known. + * + * @note This will drop any buffer previously registered using setUploadData(). + */ + void setProducerCallback(PFNPRODUCER a_pfnProducer, void *a_pvCallbackData = NULL, uint64_t a_cbContentLength = UINT64_MAX) RT_NOEXCEPT; + + /** + * Preprares transmission via the @a a_hHttp client instance. + * + * @returns IPRT status code. + * @param a_hHttp The HTTP client instance. + * @internal + */ + virtual int xmitPrepare(RTHTTP a_hHttp) const RT_NOEXCEPT; + + /** + * For completing and/or undoing setup from xmitPrepare. + * + * @param a_hHttp The HTTP client instance. + * @internal + */ + virtual void xmitComplete(RTHTTP a_hHttp) const RT_NOEXCEPT; + +protected: + /** Number of bytes corresponding to content-length. + * UINT64_MAX if not known. Used both for unploads and downloads. */ + uint64_t m_cbContentLength; + /** The content type if set (upload only). */ + RTCString m_strContentType; + /** Pointer to user-registered producer callback function (upload only). */ + PFNPRODUCER m_pfnProducer; + /** User argument for both callbacks (both). */ + void *m_pvCallbackData; + + /** @copydoc FNRTHTTPUPLOADCALLBACK */ + static DECLCALLBACK(int) xmitHttpCallback(RTHTTP hHttp, void *pvBuf, size_t cbBuf, uint64_t offContent, + size_t *pcbActual, void *pvUser) RT_NOEXCEPT; + +private: + /* No copy constructor or copy assignment: */ + RTCRestBinaryParameter(RTCRestBinaryParameter const &a_rThat); + RTCRestBinaryParameter &operator=(RTCRestBinaryParameter const &a_rThat); +}; + + +/** + * Specialization of RTCRestBinary for use with responses in a client. + * + * This enables registering data callbacks for consuming downloaded data. + */ +class RT_DECL_CLASS RTCRestBinaryResponse : public RTCRestBinary +{ +public: + /** Default constructor. */ + RTCRestBinaryResponse() RT_NOEXCEPT; + + /** Safe copy assignment method. */ + virtual int assignCopy(RTCRestBinaryResponse const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + virtual int assignCopy(RTCRestBinary const &a_rThat) RT_NOEXCEPT RT_OVERRIDE; + /** Safe copy assignment method. + * @note This will assert and fail as it makes no sense for a download. */ + virtual int assignCopy(void const *a_pvData, size_t a_cbData) RT_NOEXCEPT RT_OVERRIDE; + + /** + * Use the specified data buffer directly. + * @note This will assert and fail as it makes no sense for a download. + */ + virtual int assignReadOnly(void const *a_pvData, size_t a_cbData) RT_NOEXCEPT RT_OVERRIDE; + /** + * Use the specified data buffer directly. + * @note This will drop any previously registered producer callback and user data. + */ + virtual int assignWriteable(void *a_pvBuf, size_t a_cbBuf) RT_NOEXCEPT RT_OVERRIDE; + + /** Make a clone of this object. */ + inline RTCRestBinaryResponse *clone() const RT_NOEXCEPT { return (RTCRestBinaryResponse *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + + /** + * Retrieves the callback data. + */ + inline void *getCallbackData() const RT_NOEXCEPT { return m_pvCallbackData; } + + /** + * Sets the max size to download to memory. + * + * This also indicates the intention to download to a memory buffer, so it + * will drop any previously registered consumer callback and its user data. + * + * @param a_cbMaxDownload Maximum number of bytes to download to memory. + * If 0, a default is selected (currently 32MiB for + * 32-bit hosts and 128MiB for 64-bit). + */ + void setMaxDownloadSize(size_t a_cbMaxDownload) RT_NOEXCEPT; + + /** + * Gets the content-length value (UINT64_MAX if not available). + */ + inline uint64_t getContentLength() const RT_NOEXCEPT { return m_cbContentLength; } + + /** + * Callback for consuming downloaded bytes. + * + * @returns IPRT status code. + * @param a_pThis The related string object. + * @param a_pvSrc Buffer containing the bytes. + * @param a_cbSrc The number of bytes in the buffer. + * @param a_uHttpStatus The HTTP status code. + * @param a_offContent The byte offset corresponding to the start of @a a_pvSrc. + * @param a_cbContent The content length field value, UINT64_MAX if not available. + * + * @remarks Use getCallbackData to get the user data. + * + * @note The @a a_offContent parameter does not imply random access or anthing + * like that, it is just a convenience provided by the caller. The value + * is the sum of the previous @a a_cbSrc values. + */ + typedef DECLCALLBACKTYPE(int, FNCONSUMER,(RTCRestBinaryResponse *a_pThis, const void *a_pvSrc, size_t a_cbSrc, + uint32_t a_uHttpStatus, uint64_t a_offContent, uint64_t a_cbContent)) /*RT_NOEXCEPT*/; + /** Pointer to a byte consumer callback. */ + typedef FNCONSUMER *PFNCONSUMER; + + /** + * Sets the consumer callback. + * + * @param a_pfnConsumer The callback function for consuming downloaded data. + * NULL if data should be stored in m_pbData (the default). + * @param a_pvCallbackData Data the can be retrieved from the callback + * using getCallbackData(). + */ + void setConsumerCallback(PFNCONSUMER a_pfnConsumer, void *a_pvCallbackData = NULL) RT_NOEXCEPT; + + /** + * Preprares for receiving via the @a a_hHttp client instance. + * + * @returns IPRT status code. + * @param a_hHttp The HTTP client instance. + * @param a_fCallbackFlags The HTTP callback flags (status code spec). + * @internal + */ + virtual int receivePrepare(RTHTTP a_hHttp, uint32_t a_fCallbackFlags) RT_NOEXCEPT; + + /** + * For completing and/or undoing setup from receivePrepare. + * + * @param a_hHttp The HTTP client instance. + * @internal + */ + virtual void receiveComplete(RTHTTP a_hHttp) RT_NOEXCEPT; + +protected: + /** Number of bytes corresponding to content-length. + * UINT64_MAX if not known. Used both for unploads and downloads. */ + uint64_t m_cbContentLength; + /** Number of bytes downloaded thus far. */ + uint64_t m_cbDownloaded; + /** Pointer to user-registered consumer callback function (download only). */ + PFNCONSUMER m_pfnConsumer; + /** User argument for both callbacks (both). */ + void *m_pvCallbackData; + /** Maximum data to download to memory (download only). */ + size_t m_cbMaxDownload; + + /** @copydoc FNRTHTTPDOWNLOADCALLBACK */ + static DECLCALLBACK(int) receiveHttpCallback(RTHTTP hHttp, void const *pvBuf, size_t cbBuf, uint32_t uHttpStatus, + uint64_t offContent, uint64_t cbContent, void *pvUser) RT_NOEXCEPT; + +private: + /* No copy constructor or copy assignment: */ + RTCRestBinaryResponse(RTCRestBinaryResponse const &a_rThat); + RTCRestBinaryResponse &operator=(RTCRestBinaryResponse const &a_rThat); +}; + + +/** + * Base class for REST client requests. + * + * This encapsulates parameters and helps transform them into a HTTP request. + * + * Parameters can be transfered in a number of places: + * - Path part of the URL. + * - Query part of the URL. + * - HTTP header fields. + * - FORM body. + * - JSON body. + * - XML body. + * - ... + * + * They can be require or optional. The latter may have default values. In + * swagger 3 they can also be nullable, which means the null-indicator cannot + * be used for tracking optional parameters. + */ +class RT_DECL_CLASS RTCRestClientRequestBase +{ +public: + RTCRestClientRequestBase() RT_NOEXCEPT; + virtual ~RTCRestClientRequestBase(); + RTCRestClientRequestBase(RTCRestClientRequestBase const &a_rThat) RT_NOEXCEPT; + RTCRestClientRequestBase &operator=(RTCRestClientRequestBase const &a_rThat) RT_NOEXCEPT; + + /** + * Reset all members to default values. + * @returns IPRT status code. + */ + virtual int resetToDefault() RT_NOEXCEPT = 0; + + /** + * Getter for the operation name. Provided by the generated + * subclasses so that base class code may use it for more + * informative logs. + */ + virtual const char *getOperationName() const RT_NOEXCEPT = 0; + + /** + * Prepares the HTTP handle for transmitting this request. + * + * @returns IPRT status code. + * @param a_pStrPath Where to set path parameters. Will be appended to the base path. + * @param a_pStrQuery Where to set query parameters. + * @param a_hHttp Where to set header parameters and such. + * @param a_pStrBody Where to set body parameters. + */ + virtual int xmitPrepare(RTCString *a_pStrPath, RTCString *a_pStrQuery, RTHTTP a_hHttp, RTCString *a_pStrBody) const RT_NOEXCEPT = 0; + + /** + * Always called after the request has been transmitted. + * + * @param a_rcStatus Negative numbers are IPRT errors, positive are HTTP status codes. + * @param a_hHttp The HTTP handle the request was performed on. + */ + virtual void xmitComplete(int a_rcStatus, RTHTTP a_hHttp) const RT_NOEXCEPT = 0; + + /** + * Checks if there are were any assignment errors. + */ + inline bool hasAssignmentErrors() const RT_NOEXCEPT { return m_fErrorSet != 0; } + +protected: + /** Set of fields that have been explicitly assigned a value. */ + uint64_t m_fIsSet; + /** Set of fields where value assigning failed. */ + uint64_t m_fErrorSet; + + /** Path parameter descriptor. */ + typedef struct + { + const char *pszName; /**< The name string to replace (including {}). */ + size_t cchName; /**< Length of pszName. */ + uint32_t fFlags; /**< The toString flags. */ + uint8_t iBitNo; /**< The parameter bit number. */ + } PATHPARAMDESC; + + /** Path parameter state. */ + typedef struct + { + RTCRestObjectBase const *pObj; /**< Pointer to the parameter object. */ + size_t offName; /**< Maintained by worker. */ + } PATHPARAMSTATE; + + /** + * Do path parameters. + * + * @returns IPRT status code + * @param a_pStrPath The destination path. + * @param a_pszPathTemplate The path template string. + * @param a_cchPathTemplate The length of the path template string. + * @param a_paPathParams The path parameter descriptors (static). + * @param a_paPathParamStates The path parameter objects and states. + * @param a_cPathParams Number of path parameters. + */ + int doPathParameters(RTCString *a_pStrPath, const char *a_pszPathTemplate, size_t a_cchPathTemplate, + PATHPARAMDESC const *a_paPathParams, PATHPARAMSTATE *a_paPathParamStates, size_t a_cPathParams) const RT_NOEXCEPT; + + /** Query parameter descriptor. */ + typedef struct + { + const char *pszName; /**< The parameter name. */ + uint32_t fFlags; /**< The toString flags. */ + bool fRequired; /**< Required or not. */ + uint8_t iBitNo; /**< The parameter bit number. */ + } QUERYPARAMDESC; + + /** + * Do query parameters. + * + * @returns IPRT status code + * @param a_pStrQuery The destination string. + * @param a_paQueryParams The query parameter descriptors. + * @param a_papQueryParamObjs The query parameter objects, parallel to @a a_paQueryParams. + * @param a_cQueryParams Number of query parameters. + */ + int doQueryParameters(RTCString *a_pStrQuery, QUERYPARAMDESC const *a_paQueryParams, + RTCRestObjectBase const **a_papQueryParamObjs, size_t a_cQueryParams) const RT_NOEXCEPT; + + /** Header parameter descriptor. */ + typedef struct + { + const char *pszName; /**< The parameter name. */ + uint32_t fFlags; /**< The toString flags. */ + bool fRequired; /**< Required or not. */ + uint8_t iBitNo; /**< The parameter bit number. */ + bool fMapCollection; /**< Collect headers starting with pszName into a map. */ + } HEADERPARAMDESC; + + /** + * Do header parameters. + * + * @returns IPRT status code + * @param a_hHttp Where to set header parameters. + * @param a_paHeaderParams The header parameter descriptors. + * @param a_papHeaderParamObjs The header parameter objects, parallel to @a a_paHeaderParams. + * @param a_cHeaderParams Number of header parameters. + */ + int doHeaderParameters(RTHTTP a_hHttp, HEADERPARAMDESC const *a_paHeaderParams, + RTCRestObjectBase const **a_papHeaderParamObjs, size_t a_cHeaderParams) const RT_NOEXCEPT; +}; + + +/** + * Base class for REST client responses. + */ +class RT_DECL_CLASS RTCRestClientResponseBase +{ +public: + /** Default constructor. */ + RTCRestClientResponseBase() RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestClientResponseBase(); + /** Copy constructor. */ + RTCRestClientResponseBase(RTCRestClientResponseBase const &a_rThat); + /** Copy assignment operator. */ + RTCRestClientResponseBase &operator=(RTCRestClientResponseBase const &a_rThat); + + /** + * Resets the object state. + */ + virtual void reset(void) RT_NOEXCEPT; + + /** + * Getter for the operation name. Provided by the generated + * subclasses so that base class code may use it for more + * informative logs. + */ + virtual const char *getOperationName() const RT_NOEXCEPT = 0; + + /** + * Prepares the HTTP handle for receiving the response. + * + * This may install callbacks and such like. + * + * When overridden, the parent class must always be called. + * + * @returns IPRT status code. + * @param a_hHttp The HTTP handle to prepare for receiving. + */ + virtual int receivePrepare(RTHTTP a_hHttp) RT_NOEXCEPT; + + /** + * Called when the HTTP request has been completely received. + * + * @param a_rcStatus Negative numbers are IPRT errors, positive are HTTP status codes. + * @param a_hHttp The HTTP handle the request was performed on. + * This can be NIL_RTHTTP should something fail early, in + * which case it is possible receivePrepare() wasn't called. + * + * @note Called before consumeBody() but after consumeHeader(). + */ + virtual void receiveComplete(int a_rcStatus, RTHTTP a_hHttp) RT_NOEXCEPT; + + /** + * Callback that consumes HTTP body data from the server. + * + * @param a_pchData Body data. + * @param a_cbData Amount of body data. + * + * @note Called after consumeHeader(). + */ + virtual void consumeBody(const char *a_pchData, size_t a_cbData) RT_NOEXCEPT; + + /** + * Called after status, headers and body all have been presented. + * + * @returns IPRT status code. + */ + virtual void receiveFinal() RT_NOEXCEPT; + + /** + * Getter for m_rcStatus. + * @returns Negative numbers are IPRT errors, positive are HTTP status codes. + */ + inline int getStatus() const RT_NOEXCEPT { return m_rcStatus; } + + /** + * Getter for m_rcHttp. + * @returns HTTP status code or VERR_NOT_AVAILABLE. + */ + inline int getHttpStatus() const RT_NOEXCEPT { return m_rcHttp; } + + /** + * Getter for m_pErrInfo. + */ + inline PCRTERRINFO getErrInfo(void) const RT_NOEXCEPT { return m_pErrInfo; } + + /** + * Getter for m_strContentType. + */ + inline RTCString const &getContentType(void) const RT_NOEXCEPT { return m_strContentType; } + + +protected: + /** Negative numbers are IPRT errors, positive are HTTP status codes. */ + int m_rcStatus; + /** The HTTP status code, VERR_NOT_AVAILABLE if not set. */ + int m_rcHttp; + /** Error information. */ + PRTERRINFO m_pErrInfo; + /** The value of the Content-Type header field. */ + RTCString m_strContentType; + + PRTERRINFO getErrInfoInternal(void) RT_NOEXCEPT; + void deleteErrInfo(void) RT_NOEXCEPT; + void copyErrInfo(PCRTERRINFO pErrInfo) RT_NOEXCEPT; + + /** + * Reports an error (or warning if a_rc non-negative). + * + * @returns a_rc + * @param a_rc The status code to report and return. The first + * error status is assigned to m_rcStatus, subsequent + * ones as well as informational statuses are not + * recorded by m_rcStatus. + * @param a_pszFormat The message format string. + * @param ... Message arguments. + */ + int addError(int a_rc, const char *a_pszFormat, ...) RT_NOEXCEPT; + + /** + * Deserializes a header field value. + * + * @returns IPRT status code. + * @param a_pObj The object to deserialize into. + * @param a_pchValue Pointer to the value (not zero terminated). + * Not necessarily valid UTF-8! + * @param a_cchValue The value length. + * @param a_fFlags Flags to pass to fromString(). + * @param a_pszErrorTag The error tag (field name). + */ + int deserializeHeader(RTCRestObjectBase *a_pObj, const char *a_pchValue, size_t a_cchValue, + uint32_t a_fFlags, const char *a_pszErrorTag) RT_NOEXCEPT; + + /** + * Deserializes a header field value. + * + * @returns IPRT status code. + * @param a_pMap The string map object to deserialize into. + * @param a_pchField Pointer to the map field name. (Caller dropped the prefix.) + * Not necessarily valid UTF-8! + * @param a_cchField Length of field name. + * @param a_pchValue Pointer to the value (not zero terminated). + * Not necessarily valid UTF-8! + * @param a_cchValue The value length. + * @param a_fFlags Flags to pass to fromString(). + * @param a_pszErrorTag The error tag (field name). + */ + int deserializeHeaderIntoMap(RTCRestStringMapBase *a_pMap, const char *a_pchField, size_t a_cchField, + const char *a_pchValue, size_t a_cchValue, uint32_t a_fFlags, const char *a_pszErrorTag) RT_NOEXCEPT; + + /** + * Helper that does the deserializing of the response body + * via deserializeBodyFromJsonCursor(). + * + * @param a_pchData The body blob. + * @param a_cbData The size of the body blob. + * @param a_pszBodyName The name of the body parameter. + */ + void deserializeBody(const char *a_pchData, size_t a_cbData, const char *a_pszBodyName) RT_NOEXCEPT; + + /** + * Called by deserializeBody to do the actual body deserialization. + * + * @param a_rCursor The JSON cursor. + */ + virtual void deserializeBodyFromJsonCursor(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT; + + /** + * Primary json cursor for parsing bodies. + */ + class PrimaryJsonCursorForBody : public RTCRestJsonPrimaryCursor + { + public: + RTCRestClientResponseBase *m_pThat; /**< Pointer to response object. */ + PrimaryJsonCursorForBody(RTJSONVAL hValue, const char *pszName, RTCRestClientResponseBase *a_pThat) RT_NOEXCEPT; + virtual int addError(RTCRestJsonCursor const &a_rCursor, int a_rc, const char *a_pszFormat, ...) RT_NOEXCEPT RT_OVERRIDE; + virtual int unknownField(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + }; + + + /** + * Consumes a header. + * + * Child classes can override this to pick up their header fields, but must + * always call the parent class. + * + * @returns IPRT status code. + * @param a_uMatchWord Match word constructed by RTHTTP_MAKE_HDR_MATCH_WORD + * @param a_pchField The field name (not zero terminated). + * Not necessarily valid UTF-8! + * @param a_cchField The length of the field. + * @param a_pchValue The field value (not zero terminated). + * @param a_cchValue The length of the value. + */ + virtual int consumeHeader(uint32_t a_uMatchWord, const char *a_pchField, size_t a_cchField, + const char *a_pchValue, size_t a_cchValue) RT_NOEXCEPT; + +private: + /** Callback for use with RTHttpSetHeaderCallback. */ + static DECLCALLBACK(int) receiveHttpHeaderCallback(RTHTTP hHttp, uint32_t uMatchWord, const char *pchField, size_t cchField, + const char *pchValue, size_t cchValue, void *pvUser) RT_NOEXCEPT; +}; + + +/** + * Base class for REST client responses. + */ +class RT_DECL_CLASS RTCRestClientApiBase +{ +public: + RTCRestClientApiBase() RT_NOEXCEPT; + virtual ~RTCRestClientApiBase(); + + /** @name Host and Base path (URL) handling. + * @{ */ + /** + * Gets the server URL. + */ + const char *getServerUrl(void) const RT_NOEXCEPT; + + /** + * Sets the whole server URL. + * @returns IPRT status code. + * @param a_pszUrl The new server URL. NULL/empty to reset to default. + */ + int setServerUrl(const char *a_pszUrl) RT_NOEXCEPT; + + /** + * Sets the scheme part of the the server URL. + * @returns IPRT status code. + * @param a_pszScheme The new scheme. Does not accept NULL or empty string. + */ + int setServerScheme(const char *a_pszScheme) RT_NOEXCEPT; + + /** + * Sets the authority (hostname + port) part of the the server URL. + * @returns IPRT status code. + * @param a_pszAuthority The new authority. Does not accept NULL or empty string. + */ + int setServerAuthority(const char *a_pszAuthority) RT_NOEXCEPT; + + /** + * Sets the base path part of the the server URL. + * @returns IPRT status code. + * @param a_pszBasePath The new base path. Does not accept NULL or empty string. + */ + int setServerBasePath(const char *a_pszBasePath) RT_NOEXCEPT; + + /** + * Gets the default server URL as specified in the specs. + * @returns Server URL. + */ + virtual const char *getDefaultServerUrl() const RT_NOEXCEPT = 0; + + /** + * Gets the default server base path as specified in the specs. + * @returns Host string (start of URL). + */ + virtual const char *getDefaultServerBasePath() const RT_NOEXCEPT = 0; + /** @} */ + + /** + * Sets the CA file to use for HTTPS. + */ + int setCAFile(const char *pcszCAFile) RT_NOEXCEPT; + /** @overload */ + int setCAFile(const RTCString &strCAFile) RT_NOEXCEPT; + + /** Flags to doCall. */ + enum + { + kDoCall_OciReqSignExcludeBody = 1, /**< Exclude the body when doing OCI request signing. */ + kDoCall_RequireBody = 2 /**< The body is required. */ + }; + +protected: + /** Handle to the HTTP connection object. */ + RTHTTP m_hHttp; + /** The server URL to use. If empty use the default. */ + RTCString m_strServerUrl; + /** The CA file to use. If empty use the default. */ + RTCString m_strCAFile; + + /* Make non-copyable (RTCNonCopyable causes warnings): */ + RTCRestClientApiBase(RTCRestClientApiBase const &); + RTCRestClientApiBase *operator=(RTCRestClientApiBase const &); + + /** + * Re-initializes the HTTP instance. + * + * @returns IPRT status code. + */ + virtual int reinitHttpInstance() RT_NOEXCEPT; + + /** + * Hook that's called when doCall has fully assembled the request. + * + * Can be used for request signing and similar final steps. + * + * @returns IPRT status code. + * @param a_hHttp The HTTP client instance. + * @param a_rStrFullUrl The full URL. + * @param a_enmHttpMethod The HTTP request method. + * @param a_rStrXmitBody The body text. + * @param a_fFlags kDoCall_XXX. + */ + virtual int xmitReady(RTHTTP a_hHttp, RTCString const &a_rStrFullUrl, RTHTTPMETHOD a_enmHttpMethod, + RTCString const &a_rStrXmitBody, uint32_t a_fFlags) RT_NOEXCEPT; + + /** + * Implements stuff for making an API call. + * + * @returns a_pResponse->getStatus() + * @param a_rRequest Reference to the request object. + * @param a_enmHttpMethod The HTTP request method. + * @param a_pResponse Pointer to the response object. + * @param a_pszMethod The method name, for logging purposes. + * @param a_fFlags kDoCall_XXX. + */ + virtual int doCall(RTCRestClientRequestBase const &a_rRequest, RTHTTPMETHOD a_enmHttpMethod, + RTCRestClientResponseBase *a_pResponse, const char *a_pszMethod, uint32_t a_fFlags) RT_NOEXCEPT; + + /** + * Implements OCI style request signing. + * + * @returns IPRT status code. + * @param a_hHttp The HTTP client instance. + * @param a_rStrFullUrl The full URL. + * @param a_enmHttpMethod The HTTP request method. + * @param a_rStrXmitBody The body text. + * @param a_fFlags kDoCall_XXX. + * @param a_hKey The key to use for signing. + * @param a_rStrKeyId The key ID. + * + * @remarks The signing scheme is covered by a series of drafts RFC, the latest being: + * https://tools.ietf.org/html/draft-cavage-http-signatures-10 + */ + int ociSignRequest(RTHTTP a_hHttp, RTCString const &a_rStrFullUrl, RTHTTPMETHOD a_enmHttpMethod, + RTCString const &a_rStrXmitBody, uint32_t a_fFlags, RTCRKEY a_hKey, RTCString const &a_rStrKeyId) RT_NOEXCEPT; + + /** + * Worker for the server URL modifiers. + * + * @returns IPRT status code. + * @param a_pszServerUrl The current server URL (for comparing). + * @param a_offDst The offset of the component in the current server URL. + * @param a_cchDst The current component length. + * @param a_pszSrc The new URL component value. + * @param a_cchSrc The length of the new component. + */ + int setServerUrlPart(const char *a_pszServerUrl, size_t a_offDst, size_t a_cchDst, const char *a_pszSrc, size_t a_cchSrc) RT_NOEXCEPT; +}; + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_restclient_h */ + diff --git a/include/iprt/cpp/restoutput.h b/include/iprt/cpp/restoutput.h new file mode 100644 index 00000000..2f2c57d5 --- /dev/null +++ b/include/iprt/cpp/restoutput.h @@ -0,0 +1,280 @@ +/** @file + * IPRT - C++ Representational State Transfer (REST) Output Classes. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_restoutput_h +#define IPRT_INCLUDED_cpp_restoutput_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/stdarg.h> +#include <iprt/cpp/ministring.h> + + +/** @defgroup grp_rt_cpp_restoutput C++ Representational State Transfer (REST) Output Classes. + * @ingroup grp_rt_cpp + * @{ + */ + + +/** + * Abstract base class for serializing data objects. + */ +class RT_DECL_CLASS RTCRestOutputBase +{ +public: + RTCRestOutputBase() RT_NOEXCEPT; + virtual ~RTCRestOutputBase(); + + /** + * Raw output function. + * + * @returns Number of bytes outputted. + * @param a_pchString The string to output (not necessarily terminated). + * @param a_cchToWrite The length of the string + */ + virtual size_t output(const char *a_pchString, size_t a_cchToWrite) RT_NOEXCEPT = 0; + + /** + * RTStrPrintf like function (see @ref pg_rt_str_format). + * + * @returns Number of bytes outputted. + * @param pszFormat The format string. + * @param ... Argument specfied in @a pszFormat. + */ + inline size_t printf(const char *pszFormat, ...) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(2, 3) + { + va_list va; + va_start(va, pszFormat); + size_t cchWritten = this->vprintf(pszFormat, va); + va_end(va); + return cchWritten; + } + + /** + * RTStrPrintfV like function (see @ref pg_rt_str_format). + * + * @returns Number of bytes outputted. + * @param pszFormat The format string. + * @param va Argument specfied in @a pszFormat. + */ + size_t vprintf(const char *pszFormat, va_list va) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(2, 0); + + /** + * Begins an array. + * @returns Previous output state. Pass to endArray() when done. + */ + virtual uint32_t beginArray() RT_NOEXCEPT; + + /** + * Ends an array. + * @param a_uOldState Previous output state (returned by beginArray()). + */ + virtual void endArray(uint32_t a_uOldState) RT_NOEXCEPT; + + /** + * Begins an object. + * @returns Previous output state. Pass to endObject() when done. + */ + virtual uint32_t beginObject() RT_NOEXCEPT; + + /** + * Ends an array. + * @param a_uOldState Previous output state (returned by beginObject()). + */ + virtual void endObject(uint32_t a_uOldState) RT_NOEXCEPT; + + /** + * Outputs a value separator. + * This is called before a value, not after. + */ + virtual void valueSeparator() RT_NOEXCEPT; + + /** + * Outputs a value separator, name and name separator. + */ + virtual void valueSeparatorAndName(const char *a_pszName, size_t a_cchName) RT_NOEXCEPT; + + /** Outputs a null-value. */ + void nullValue() RT_NOEXCEPT; + +protected: + /** The current indentation level (bits 15:0) and separator state (bit 31). */ + uint32_t m_uState; + + /** @callback_method_impl{FNRTSTROUTPUT} */ + static DECLCALLBACK(size_t) printfOutputCallback(void *pvArg, const char *pachChars, size_t cbChars) RT_NOEXCEPT; +}; + + +/** + * Abstract base class for pretty output. + */ +class RT_DECL_CLASS RTCRestOutputPrettyBase : public RTCRestOutputBase +{ +public: + RTCRestOutputPrettyBase() RT_NOEXCEPT; + virtual ~RTCRestOutputPrettyBase(); + + /** + * Begins an array. + * @returns Previous output state. Pass to endArray() when done. + */ + virtual uint32_t beginArray() RT_NOEXCEPT RT_OVERRIDE; + + /** + * Ends an array. + * @param a_uOldState Previous output state (returned by beginArray()). + */ + virtual void endArray(uint32_t a_uOldState) RT_NOEXCEPT RT_OVERRIDE; + + /** + * Begins an object. + * @returns Previous output state. Pass to endObject() when done. + */ + virtual uint32_t beginObject() RT_NOEXCEPT RT_OVERRIDE; + + /** + * Ends an array. + * @param a_uOldState Previous output state (returned by beginObject()). + */ + virtual void endObject(uint32_t a_uOldState) RT_NOEXCEPT RT_OVERRIDE; + + /** + * Outputs a value separator. + * This is called before a value, not after. + */ + virtual void valueSeparator() RT_NOEXCEPT RT_OVERRIDE; + + /** + * Outputs a value separator, name and name separator. + */ + virtual void valueSeparatorAndName(const char *a_pszName, size_t a_cchName) RT_NOEXCEPT RT_OVERRIDE; + +protected: + /** Helper for outputting the correct amount of indentation. */ + void outputIndentation() RT_NOEXCEPT; +}; + + +/** + * Serialize to a string object. + */ +class RT_DECL_CLASS RTCRestOutputToString : public RTCRestOutputBase +{ +public: + /** + * Creates an instance that appends to @a a_pDst. + * @param a_pDst Pointer to the destination string object. + * NULL is not accepted and will assert. + * @param a_fAppend Whether to append to the current string value, or + * nuke the string content before starting the output. + */ + RTCRestOutputToString(RTCString *a_pDst, bool a_fAppend = false) RT_NOEXCEPT; + virtual ~RTCRestOutputToString(); + + virtual size_t output(const char *a_pchString, size_t a_cchToWrite) RT_NOEXCEPT RT_OVERRIDE; + + /** + * Finalizes the output and releases the string object to the caller. + * + * @returns The released string object. NULL if we ran out of memory or if + * called already. + * + * @remark This sets m_pDst to NULL and the object cannot be use for any + * more output afterwards. + */ + virtual RTCString *finalize() RT_NOEXCEPT; + +protected: + /** Pointer to the destination string. NULL after finalize(). */ + RTCString *m_pDst; + /** Set if we ran out of memory and should ignore subsequent calls. */ + bool m_fOutOfMemory; + + /* Make non-copyable (RTCNonCopyable causes warnings): */ + RTCRestOutputToString(RTCRestOutputToString const &); + RTCRestOutputToString *operator=(RTCRestOutputToString const &); +}; + + +/** + * Serialize pretty JSON to a string object. + */ +class RT_DECL_CLASS RTCRestOutputPrettyToString : public RTCRestOutputPrettyBase +{ +public: + /** + * Creates an instance that appends to @a a_pDst. + * @param a_pDst Pointer to the destination string object. + * NULL is not accepted and will assert. + * @param a_fAppend Whether to append to the current string value, or + * nuke the string content before starting the output. + */ + RTCRestOutputPrettyToString(RTCString *a_pDst, bool a_fAppend = false) RT_NOEXCEPT; + virtual ~RTCRestOutputPrettyToString(); + + virtual size_t output(const char *a_pchString, size_t a_cchToWrite) RT_NOEXCEPT RT_OVERRIDE; + + /** + * Finalizes the output and releases the string object to the caller. + * + * @returns The released string object. NULL if we ran out of memory or if + * called already. + * + * @remark This sets m_pDst to NULL and the object cannot be use for any + * more output afterwards. + */ + virtual RTCString *finalize() RT_NOEXCEPT; + +protected: + /** Pointer to the destination string. NULL after finalize(). */ + RTCString *m_pDst; + /** Set if we ran out of memory and should ignore subsequent calls. */ + bool m_fOutOfMemory; + + /* Make non-copyable (RTCNonCopyable causes warnings): */ + RTCRestOutputPrettyToString(RTCRestOutputToString const &); + RTCRestOutputPrettyToString *operator=(RTCRestOutputToString const &); +}; + + + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_restoutput_h */ + diff --git a/include/iprt/cpp/reststringmap.h b/include/iprt/cpp/reststringmap.h new file mode 100644 index 00000000..cff201bb --- /dev/null +++ b/include/iprt/cpp/reststringmap.h @@ -0,0 +1,499 @@ +/** @file + * IPRT - C++ Representational State Transfer (REST) String Map Template. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_reststringmap_h +#define IPRT_INCLUDED_cpp_reststringmap_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/list.h> +#include <iprt/string.h> +#include <iprt/cpp/restbase.h> + + +/** @defgroup grp_rt_cpp_reststingmap C++ Representational State Transfer (REST) String Map Template + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * Abstract base class for the RTCRestStringMap template. + */ +class RT_DECL_CLASS RTCRestStringMapBase : public RTCRestObjectBase +{ +public: + /** Default destructor. */ + RTCRestStringMapBase() RT_NOEXCEPT; + /** Copy constructor. */ + RTCRestStringMapBase(RTCRestStringMapBase const &a_rThat); + /** Destructor. */ + virtual ~RTCRestStringMapBase(); + /** Copy assignment operator. */ + RTCRestStringMapBase &operator=(RTCRestStringMapBase const &a_rThat); + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE; + virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + // later? + //virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const RT_NOEXCEPT RT_OVERRIDE; + //virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL, + // uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE; + virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** + * Clear the content of the map. + */ + void clear() RT_NOEXCEPT; + + /** + * Checks if the map is empty. + */ + inline bool isEmpty() const RT_NOEXCEPT { return m_cEntries == 0; } + + /** + * Gets the number of entries in the map. + */ + size_t size() const RT_NOEXCEPT; + + /** + * Checks if the map contains the given key. + * @returns true if key found, false if not. + * @param a_pszKey The key to check fo. + */ + bool containsKey(const char *a_pszKey) const RT_NOEXCEPT; + + /** + * Checks if the map contains the given key. + * @returns true if key found, false if not. + * @param a_rStrKey The key to check fo. + */ + bool containsKey(RTCString const &a_rStrKey) const RT_NOEXCEPT; + + /** + * Remove any key-value pair with the given key. + * @returns true if anything was removed, false if not found. + * @param a_pszKey The key to remove. + */ + bool remove(const char *a_pszKey) RT_NOEXCEPT; + + /** + * Remove any key-value pair with the given key. + * @returns true if anything was removed, false if not found. + * @param a_rStrKey The key to remove. + */ + bool remove(RTCString const &a_rStrKey) RT_NOEXCEPT; + + /** + * Creates a new value and inserts it under the given key, returning the new value. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_ppValue Where to return the pointer to the value. + * @param a_pszKey The key to put it under. + * @param a_cchKey The length of the key. Default is the entire string. + * @param a_fReplace Whether to replace or fail on key collision. + */ + int putNewValue(RTCRestObjectBase **a_ppValue, const char *a_pszKey, size_t a_cchKey = RTSTR_MAX, bool a_fReplace = false) RT_NOEXCEPT; + + /** + * Creates a new value and inserts it under the given key, returning the new value. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_ppValue Where to return the pointer to the value. + * @param a_rStrKey The key to put it under. + * @param a_fReplace Whether to replace or fail on key collision. + */ + int putNewValue(RTCRestObjectBase **a_ppValue, RTCString const &a_rStrKey, bool a_fReplace = false) RT_NOEXCEPT; + +protected: + /** Map entry. */ + typedef struct MapEntry + { + /** String space core. */ + RTSTRSPACECORE Core; + /** List node for enumeration. */ + RTLISTNODE ListEntry; + /** The key. + * @remarks Core.pszString points to the value of this object. So, consider it const. */ + RTCString strKey; + /** The value. */ + RTCRestObjectBase *pValue; + } MapEntry; + /** The map tree. */ + RTSTRSPACE m_Map; + /** The enumeration list head (MapEntry). */ + RTLISTANCHOR m_ListHead; + /** Number of map entries. */ + size_t m_cEntries; + +public: + /** @name Map Iteration + * @{ */ + /** Const iterator. */ + class ConstIterator + { + private: + MapEntry *m_pCur; + ConstIterator() RT_NOEXCEPT; + protected: + ConstIterator(MapEntry *a_pEntry) RT_NOEXCEPT : m_pCur(a_pEntry) { } + public: + ConstIterator(ConstIterator const &a_rThat) RT_NOEXCEPT : m_pCur(a_rThat.m_pCur) { } + + /** Gets the key string. */ + inline RTCString const &getKey() RT_NOEXCEPT { return m_pCur->strKey; } + /** Gets poitner to the value object. */ + inline RTCRestObjectBase const *getValue() RT_NOEXCEPT { return m_pCur->pValue; } + + /** Advance to the next map entry. */ + inline ConstIterator &operator++() RT_NOEXCEPT + { + m_pCur = RTListNodeGetNextCpp(&m_pCur->ListEntry, MapEntry, ListEntry); + return *this; + } + + /** Advance to the previous map entry. */ + inline ConstIterator &operator--() RT_NOEXCEPT + { + m_pCur = RTListNodeGetPrevCpp(&m_pCur->ListEntry, MapEntry, ListEntry); + return *this; + } + + /** Compare equal. */ + inline bool operator==(ConstIterator const &a_rThat) RT_NOEXCEPT { return m_pCur == a_rThat.m_pCur; } + /** Compare not equal. */ + inline bool operator!=(ConstIterator const &a_rThat) RT_NOEXCEPT { return m_pCur != a_rThat.m_pCur; } + + /* Map class must be friend so it can use the MapEntry constructor. */ + friend class RTCRestStringMapBase; + }; + + /** Returns iterator for the first map entry (unless it's empty and it's also the end). */ + inline ConstIterator begin() const RT_NOEXCEPT + { + if (!RTListIsEmpty(&m_ListHead)) + return ConstIterator(RTListNodeGetNextCpp(&m_ListHead, MapEntry, ListEntry)); + return end(); + } + /** Returns iterator for the last map entry (unless it's empty and it's also the end). */ + inline ConstIterator last() const RT_NOEXCEPT + { + if (!RTListIsEmpty(&m_ListHead)) + return ConstIterator(RTListNodeGetPrevCpp(&m_ListHead, MapEntry, ListEntry)); + return end(); + } + /** Returns the end iterator. This does not ever refer to an actual map entry. */ + inline ConstIterator end() const RT_NOEXCEPT + { + return ConstIterator(RT_FROM_CPP_MEMBER(&m_ListHead, MapEntry, ListEntry)); + } + /** @} */ + + +protected: + /** + * Helper for creating a clone. + * + * @returns Pointer to new map object on success, NULL if out of memory. + */ + virtual RTCRestStringMapBase *createClone(void) const RT_NOEXCEPT = 0; + + /** + * Wrapper around the value constructor. + * + * @returns Pointer to new value object on success, NULL if out of memory. + */ + virtual RTCRestObjectBase *createValue(void) RT_NOEXCEPT = 0; + + /** + * For accessing the static deserializeInstanceFromJson() method of the value. + */ + virtual int deserializeValueInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT = 0; + + /** + * Worker for the copy assignment method and copyMapWorkerMayThrow. + * + * This will use createEntryCopy to do the copying. + * + * @returns VINF_SUCCESS on success, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_rThat The map to copy. Caller makes 100% sure the it has + * the same type as the destination. + */ + int copyMapWorkerNoThrow(RTCRestStringMapBase const &a_rThat) RT_NOEXCEPT; + + /** + * Wrapper around copyMapWorkerNoThrow() that throws allocation errors, making + * it suitable for copy constructors and assignment operators. + */ + void copyMapWorkerMayThrow(RTCRestStringMapBase const &a_rThat); + + /** + * Worker for performing inserts. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_pszKey The key. + * @param a_pValue The value to insert. Ownership is transferred to the map on success. + * @param a_fReplace Whether to replace existing key-value pair with matching key. + * @param a_cchKey The key length, the whole string by default. + */ + int putWorker(const char *a_pszKey, RTCRestObjectBase *a_pValue, bool a_fReplace, size_t a_cchKey = RTSTR_MAX) RT_NOEXCEPT; + + /** + * Worker for performing inserts. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_pszKey The key. + * @param a_rValue The value to copy into the map. + * @param a_fReplace Whether to replace existing key-value pair with matching key. + * @param a_cchKey The key length, the whole string by default. + */ + int putCopyWorker(const char *a_pszKey, RTCRestObjectBase const &a_rValue, bool a_fReplace, size_t a_cchKey = RTSTR_MAX) RT_NOEXCEPT; + + /** + * Worker for getting the value corresponding to the given key. + * + * @returns Pointer to the value object if found, NULL if key not in the map. + * @param a_pszKey The key which value to look up. + */ + RTCRestObjectBase *getWorker(const char *a_pszKey) RT_NOEXCEPT; + + /** + * Worker for getting the value corresponding to the given key, const variant. + * + * @returns Pointer to the value object if found, NULL if key not in the map. + * @param a_pszKey The key which value to look up. + */ + RTCRestObjectBase const *getWorker(const char *a_pszKey) const RT_NOEXCEPT; + +private: + static DECLCALLBACK(int) stringSpaceDestructorCallback(PRTSTRSPACECORE pStr, void *pvUser) RT_NOEXCEPT; +}; + + +/** + * Limited map class. + */ +template<class ValueType> class RTCRestStringMap : public RTCRestStringMapBase +{ +public: + /** Default constructor, creates emtpy map. */ + RTCRestStringMap() RT_NOEXCEPT + : RTCRestStringMapBase() + {} + + /** Copy constructor. */ + RTCRestStringMap(RTCRestStringMap const &a_rThat) + : RTCRestStringMapBase() + { + copyMapWorkerMayThrow(a_rThat); + } + + /** Destructor. */ + virtual ~RTCRestStringMap() + { + /* nothing to do here. */ + } + + /** Copy assignment operator. */ + RTCRestStringMap &operator=(RTCRestStringMap const &a_rThat) + { + copyMapWorkerMayThrow(a_rThat); + return *this; + } + + /** Safe copy assignment method. */ + int assignCopy(RTCRestStringMap const &a_rThat) RT_NOEXCEPT + { + return copyMapWorkerNoThrow(a_rThat); + } + + /** Make a clone of this object. */ + inline RTCRestStringMap *clone() const RT_NOEXCEPT + { + return (RTCRestStringMap *)baseClone(); + } + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT + { + return new (std::nothrow) RTCRestStringMap<ValueType>(); + } + + /** Factory method for values. */ + static DECLCALLBACK(RTCRestObjectBase *) createValueInstance(void) RT_NOEXCEPT + { + return new (std::nothrow) ValueType(); + } + + /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */ + static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT + { + *a_ppInstance = new (std::nothrow) RTCRestStringMap<ValueType>(); + if (*a_ppInstance) + return (*a_ppInstance)->deserializeFromJson(a_rCursor); + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_NO_MEMORY, "Out of memory"); + } + + /** + * Inserts the given object into the map. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_pszKey The key. + * @param a_pValue The value to insert. Ownership is transferred to the map on success. + * @param a_fReplace Whether to replace existing key-value pair with matching key. + */ + inline int put(const char *a_pszKey, ValueType *a_pValue, bool a_fReplace = false) RT_NOEXCEPT + { + return putWorker(a_pszKey, a_pValue, a_fReplace); + } + + /** + * Inserts the given object into the map. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_rStrKey The key. + * @param a_pValue The value to insert. Ownership is transferred to the map on success. + * @param a_fReplace Whether to replace existing key-value pair with matching key. + */ + inline int put(RTCString const &a_rStrKey, ValueType *a_pValue, bool a_fReplace = false) RT_NOEXCEPT + { + return putWorker(a_rStrKey.c_str(), a_pValue, a_fReplace, a_rStrKey.length()); + } + + /** + * Inserts a copy of the given object into the map. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_pszKey The key. + * @param a_rValue The value to insert a copy of. + * @param a_fReplace Whether to replace existing key-value pair with matching key. + */ + inline int putCopy(const char *a_pszKey, const ValueType &a_rValue, bool a_fReplace = false) RT_NOEXCEPT + { + return putCopyWorker(a_pszKey, a_rValue, a_fReplace); + } + + /** + * Inserts a copy of the given object into the map. + * + * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success. + * VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure. + * @param a_rStrKey The key. + * @param a_rValue The value to insert a copy of. + * @param a_fReplace Whether to replace existing key-value pair with matching key. + */ + inline int putCopy(RTCString const &a_rStrKey, const ValueType &a_rValue, bool a_fReplace = false) RT_NOEXCEPT + { + return putCopyWorker(a_rStrKey.c_str(), a_rValue, a_fReplace, a_rStrKey.length()); + } + + /** + * Gets the value corresponding to the given key. + * + * @returns Pointer to the value object if found, NULL if key not in the map. + * @param a_pszKey The key which value to look up. + */ + inline ValueType *get(const char *a_pszKey) RT_NOEXCEPT + { + return (ValueType *)getWorker(a_pszKey); + } + + /** + * Gets the value corresponding to the given key. + * + * @returns Pointer to the value object if found, NULL if key not in the map. + * @param a_rStrKey The key which value to look up. + */ + inline ValueType *get(RTCString const &a_rStrKey) RT_NOEXCEPT + { + return (ValueType *)getWorker(a_rStrKey.c_str()); + } + + /** + * Gets the const value corresponding to the given key. + * + * @returns Pointer to the value object if found, NULL if key not in the map. + * @param a_pszKey The key which value to look up. + */ + inline ValueType const *get(const char *a_pszKey) const RT_NOEXCEPT + { + return (ValueType const *)getWorker(a_pszKey); + } + + /** + * Gets the const value corresponding to the given key. + * + * @returns Pointer to the value object if found, NULL if key not in the map. + * @param a_rStrKey The key which value to look up. + */ + inline ValueType const *get(RTCString const &a_rStrKey) const RT_NOEXCEPT + { + return (ValueType const *)getWorker(a_rStrKey.c_str()); + } + + /** @todo enumerator*/ + +protected: + virtual RTCRestStringMapBase *createClone(void) const RT_NOEXCEPT RT_OVERRIDE + { + return new (std::nothrow) RTCRestStringMap(); + } + + virtual RTCRestObjectBase *createValue(void) RT_NOEXCEPT RT_OVERRIDE + { + return new (std::nothrow) ValueType(); + } + + virtual int deserializeValueInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT RT_OVERRIDE + { + return ValueType::deserializeInstanceFromJson(a_rCursor, a_ppInstance); + } +}; + + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_reststringmap_h */ + diff --git a/include/iprt/cpp/utils.h b/include/iprt/cpp/utils.h new file mode 100644 index 00000000..f5b36fa8 --- /dev/null +++ b/include/iprt/cpp/utils.h @@ -0,0 +1,149 @@ +/** @file + * IPRT - C++ Utilities (useful templates, defines and such). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_utils_h +#define IPRT_INCLUDED_cpp_utils_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/** @defgroup grp_rt_cpp IPRT C++ APIs */ + +/** @defgroup grp_rt_cpp_util C++ Utilities + * @ingroup grp_rt_cpp + * @{ + */ + +#define DPTR(CLASS) CLASS##Private *d = static_cast<CLASS##Private *>(d_ptr) +#define QPTR(CLASS) CLASS *q = static_cast<CLASS *>(q_ptr) + +/** + * A simple class used to prevent copying and assignment. + * + * Inherit from this class in order to prevent automatic generation + * of the copy constructor and assignment operator in your class. + */ +class RTCNonCopyable +{ +protected: + RTCNonCopyable() {} + ~RTCNonCopyable() {} +private: + RTCNonCopyable(RTCNonCopyable const &); + RTCNonCopyable &operator=(RTCNonCopyable const &); +}; + + +/** + * Shortcut to |const_cast<C &>()| that automatically derives the correct + * type (class) for the const_cast template's argument from its own argument. + * + * Can be used to temporarily cancel the |const| modifier on the left-hand side + * of assignment expressions, like this: + * @code + * const Class That; + * ... + * unconst(That) = SomeValue; + * @endcode + * + * @todo What to do about the prefix here? + */ +template <class C> +inline C &unconst(const C &that) +{ + return const_cast<C &>(that); +} + + +/** + * Shortcut to |const_cast<C *>()| that automatically derives the correct + * type (class) for the const_cast template's argument from its own argument. + * + * Can be used to temporarily cancel the |const| modifier on the left-hand side + * of assignment expressions, like this: + * @code + * const Class *pThat; + * ... + * unconst(pThat) = SomeValue; + * @endcode + * + * @todo What to do about the prefix here? + */ +template <class C> +inline C *unconst(const C *that) +{ + return const_cast<C *>(that); +} + + +/** + * Macro for generating a non-const getter version from a const getter. + * + * @param a_RetType The getter return type. + * @param a_Class The class name. + * @param a_Getter The getter name. + * @param a_ArgDecls The argument declaration for the getter method. + * @param a_ArgList The argument list for the call. + */ +#define RT_CPP_GETTER_UNCONST(a_RetType, a_Class, a_Getter, a_ArgDecls, a_ArgList) \ + a_RetType a_Getter a_ArgDecls \ + { \ + return static_cast< a_Class const *>(this)-> a_Getter a_ArgList; \ + } + + +/** + * Macro for generating a non-const getter version from a const getter, + * unconsting the return value as well. + * + * @param a_RetType The getter return type. + * @param a_Class The class name. + * @param a_Getter The getter name. + * @param a_ArgDecls The argument declaration for the getter method. + * @param a_ArgList The argument list for the call. + */ +#define RT_CPP_GETTER_UNCONST_RET(a_RetType, a_Class, a_Getter, a_ArgDecls, a_ArgList) \ + a_RetType a_Getter a_ArgDecls \ + { \ + return const_cast<a_RetType>(static_cast< a_Class const *>(this)-> a_Getter a_ArgList); \ + } + + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_utils_h */ + diff --git a/include/iprt/cpp/xml.h b/include/iprt/cpp/xml.h new file mode 100644 index 00000000..9459f9d3 --- /dev/null +++ b/include/iprt/cpp/xml.h @@ -0,0 +1,1247 @@ +/** @file + * IPRT - XML Helper APIs. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpp_xml_h +#define IPRT_INCLUDED_cpp_xml_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef IN_RING3 +# error "There are no XML APIs available in Ring-0 Context!" +#endif +#ifdef IPRT_NO_CRT +# error "Not available in no-CRT mode because it depends on exceptions, std::list, std::map and stdio.h." +#endif + +#include <iprt/list.h> +#include <iprt/cpp/exception.h> +#include <iprt/cpp/utils.h> + +#include <list> +#include <memory> + + +/** @defgroup grp_rt_cpp_xml C++ XML support + * @ingroup grp_rt_cpp + * @{ + */ + +/* Forwards */ +typedef struct _xmlParserInput xmlParserInput; +typedef xmlParserInput *xmlParserInputPtr; +typedef struct _xmlParserCtxt xmlParserCtxt; +typedef xmlParserCtxt *xmlParserCtxtPtr; +typedef struct _xmlError xmlError; +typedef xmlError *xmlErrorPtr; + +typedef struct _xmlAttr xmlAttr; +typedef struct _xmlNode xmlNode; + +#define RT_XML_CONTENT_SMALL _8K +#define RT_XML_CONTENT_LARGE _128K +#define RT_XML_ATTR_TINY 64 +#define RT_XML_ATTR_SMALL _1K +#define RT_XML_ATTR_MEDIUM _8K +#define RT_XML_ATTR_LARGE _64K + +/** @} */ + +namespace xml +{ + +/** + * @addtogroup grp_rt_cpp_xml + * @{ + */ + +// Exceptions +////////////////////////////////////////////////////////////////////////////// + +class RT_DECL_CLASS LogicError : public RTCError +{ +public: + + LogicError(const char *aMsg = NULL) + : RTCError(aMsg) + {} + + LogicError(RT_SRC_POS_DECL); +}; + +class RT_DECL_CLASS RuntimeError : public RTCError +{ +public: + + RuntimeError(const char *aMsg = NULL) + : RTCError(aMsg) + {} +}; + +class RT_DECL_CLASS XmlError : public RuntimeError +{ +public: + XmlError(xmlErrorPtr aErr); + + static char* Format(xmlErrorPtr aErr); +}; + +// Logical errors +////////////////////////////////////////////////////////////////////////////// + +class RT_DECL_CLASS ENotImplemented : public LogicError +{ +public: + ENotImplemented(const char *aMsg = NULL) : LogicError(aMsg) {} + ENotImplemented(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {} +}; + +class RT_DECL_CLASS EInvalidArg : public LogicError +{ +public: + EInvalidArg(const char *aMsg = NULL) : LogicError(aMsg) {} + EInvalidArg(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {} +}; + +class RT_DECL_CLASS EDocumentNotEmpty : public LogicError +{ +public: + EDocumentNotEmpty(const char *aMsg = NULL) : LogicError(aMsg) {} + EDocumentNotEmpty(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {} +}; + +class RT_DECL_CLASS ENodeIsNotElement : public LogicError +{ +public: + ENodeIsNotElement(const char *aMsg = NULL) : LogicError(aMsg) {} + ENodeIsNotElement(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {} +}; + +// Runtime errors +////////////////////////////////////////////////////////////////////////////// + +class RT_DECL_CLASS EIPRTFailure : public RuntimeError +{ +public: + + EIPRTFailure(int aRC, const char *pszContextFmt, ...); + + int rc() const + { + return mRC; + } + +private: + int mRC; +}; + +/** + * The Stream class is a base class for I/O streams. + */ +class RT_DECL_CLASS Stream +{ +public: + + virtual ~Stream() {} + + virtual const char *uri() const = 0; + + /** + * Returns the current read/write position in the stream. The returned + * position is a zero-based byte offset from the beginning of the file. + * + * Throws ENotImplemented if this operation is not implemented for the + * given stream. + */ + virtual uint64_t pos() const = 0; + + /** + * Sets the current read/write position in the stream. + * + * @param aPos Zero-based byte offset from the beginning of the stream. + * + * Throws ENotImplemented if this operation is not implemented for the + * given stream. + */ + virtual void setPos (uint64_t aPos) = 0; +}; + +/** + * The Input class represents an input stream. + * + * This input stream is used to read the settings tree from. + * This is an abstract class that must be subclassed in order to fill it with + * useful functionality. + */ +class RT_DECL_CLASS Input : virtual public Stream +{ +public: + + /** + * Reads from the stream to the supplied buffer. + * + * @param aBuf Buffer to store read data to. + * @param aLen Buffer length. + * + * @return Number of bytes read. + */ + virtual int read (char *aBuf, int aLen) = 0; +}; + +/** + * + */ +class RT_DECL_CLASS Output : virtual public Stream +{ +public: + + /** + * Writes to the stream from the supplied buffer. + * + * @param aBuf Buffer to write data from. + * @param aLen Buffer length. + * + * @return Number of bytes written. + */ + virtual int write (const char *aBuf, int aLen) = 0; + + /** + * Truncates the stream from the current position and upto the end. + * The new file size will become exactly #pos() bytes. + * + * Throws ENotImplemented if this operation is not implemented for the + * given stream. + */ + virtual void truncate() = 0; +}; + + +////////////////////////////////////////////////////////////////////////////// + +/** + * The File class is a stream implementation that reads from and writes to + * regular files. + * + * The File class uses IPRT File API for file operations. Note that IPRT File + * API is not thread-safe. This means that if you pass the same RTFILE handle to + * different File instances that may be simultaneously used on different + * threads, you should care about serialization; otherwise you will get garbage + * when reading from or writing to such File instances. + */ +class RT_DECL_CLASS File : public Input, public Output +{ +public: + + /** + * Possible file access modes. + */ + enum Mode { Mode_Read, Mode_WriteCreate, Mode_Overwrite, Mode_ReadWrite }; + + /** + * Opens a file with the given name in the given mode. If @a aMode is Read + * or ReadWrite, the file must exist. If @a aMode is Write, the file must + * not exist. Otherwise, an EIPRTFailure exception will be thrown. + * + * @param aMode File mode. + * @param aFileName File name. + * @param aFlushIt Whether to flush a writable file before closing it. + */ + File(Mode aMode, const char *aFileName, bool aFlushIt = false); + + /** + * Uses the given file handle to perform file operations. This file + * handle must be already open in necessary mode (read, or write, or mixed). + * + * The read/write position of the given handle will be reset to the + * beginning of the file on success. + * + * Note that the given file handle will not be automatically closed upon + * this object destruction. + * + * @note It you pass the same RTFILE handle to more than one File instance, + * please make sure you have provided serialization in case if these + * instasnces are to be simultaneously used by different threads. + * Otherwise you may get garbage when reading or writing. + * + * @param aHandle Open file handle. + * @param aFileName File name (for reference). + * @param aFlushIt Whether to flush a writable file before closing it. + */ + File(RTFILE aHandle, const char *aFileName = NULL, bool aFlushIt = false); + + /** + * Destroys the File object. If the object was created from a file name + * the corresponding file will be automatically closed. If the object was + * created from a file handle, it will remain open. + */ + virtual ~File(); + + const char *uri() const; + + uint64_t pos() const; + void setPos(uint64_t aPos); + + /** + * See Input::read(). If this method is called in wrong file mode, + * LogicError will be thrown. + */ + int read(char *aBuf, int aLen); + + /** + * See Output::write(). If this method is called in wrong file mode, + * LogicError will be thrown. + */ + int write(const char *aBuf, int aLen); + + /** + * See Output::truncate(). If this method is called in wrong file mode, + * LogicError will be thrown. + */ + void truncate(); + +private: + + /* Obscure class data */ + struct Data; + Data *m; + + /* auto_ptr data doesn't have proper copy semantics */ + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(File); +}; + +/** + * The MemoryBuf class represents a stream implementation that reads from the + * memory buffer. + */ +class RT_DECL_CLASS MemoryBuf : public Input +{ +public: + + MemoryBuf (const char *aBuf, size_t aLen, const char *aURI = NULL); + + virtual ~MemoryBuf(); + + const char *uri() const; + + int read(char *aBuf, int aLen); + uint64_t pos() const; + void setPos(uint64_t aPos); + +private: + /* Obscure class data */ + struct Data; + Data *m; + + /* auto_ptr data doesn't have proper copy semantics */ + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(MemoryBuf); +}; + + +/* + * GlobalLock + * + * + */ + + +typedef DECLCALLBACKTYPE_EX(xmlParserInput *, RT_NOTHING, FNEXTERNALENTITYLOADER,(const char *aURI, const char *aID, + xmlParserCtxt *aCtxt)); +typedef FNEXTERNALENTITYLOADER *PFNEXTERNALENTITYLOADER; /**< xmlExternalEntityLoader w/ noexcept. */ + +class RT_DECL_CLASS GlobalLock +{ +public: + GlobalLock(); + ~GlobalLock(); + + void setExternalEntityLoader(PFNEXTERNALENTITYLOADER pFunc); + + static xmlParserInput* callDefaultLoader(const char *aURI, + const char *aID, + xmlParserCtxt *aCtxt); + +private: + /* Obscure class data. */ + struct Data; + struct Data *m; +}; + +class ElementNode; +typedef std::list<const ElementNode*> ElementNodesList; + +class AttributeNode; + +class ContentNode; + +/** + * Node base class. + * + * Cannot be used directly, but ElementNode, ContentNode and AttributeNode + * derive from this. This does implement useful public methods though. + * + * + */ +class RT_DECL_CLASS Node +{ +public: + virtual ~Node(); + + const char *getName() const; + const char *getPrefix() const; + const char *getNamespaceURI() const; + bool nameEqualsNS(const char *pcszNamespace, const char *pcsz) const; + bool nameEquals(const char *pcsz) const + { + return nameEqualsNS(NULL, pcsz); + } + bool nameEqualsN(const char *pcsz, size_t cchMax, const char *pcszNamespace = NULL) const; + + const char *getValue() const; + const char *getValueN(size_t cchValueLimit) const; + bool copyValue(int32_t &i) const; + bool copyValue(uint32_t &i) const; + bool copyValue(int64_t &i) const; + bool copyValue(uint64_t &i) const; + + /** @name Introspection. + * @{ */ + /** Is this an ElementNode instance. + * @returns true / false */ + bool isElement() const + { + return m_Type == IsElement; + } + + /** Is this an ContentNode instance. + * @returns true / false */ + bool isContent() const + { + return m_Type == IsContent; + } + + /** Is this an AttributeNode instance. + * @returns true / false */ + bool isAttribute() const + { + return m_Type == IsAttribute; + } + + int getLineNumber() const; + /** @} */ + + /** @name General tree enumeration. + * + * Use the introspection methods isElement() and isContent() before doing static + * casting. Parents are always or ElementNode type, but siblings and children + * can be of both ContentNode and ElementNode types. + * + * @remarks Attribute node are in the attributes list, while both content and + * element nodes are in the list of children. See ElementNode. + * + * @remarks Careful mixing tree walking with node removal! + * @{ + */ + /** Get the parent node + * @returns Pointer to the parent node, or NULL if root. */ + const Node *getParent() const + { + return m_pParent; + } + + /** Get the previous sibling. + * @returns Pointer to the previous sibling node, NULL if first child. + */ + const Node *getPrevSibiling() const + { + if (!m_pParentListAnchor) + return NULL; + return RTListGetPrevCpp(m_pParentListAnchor, this, const Node, m_listEntry); + } + + /** Get the next sibling. + * @returns Pointer to the next sibling node, NULL if last child. */ + const Node *getNextSibiling() const + { + if (!m_pParentListAnchor) + return NULL; + return RTListGetNextCpp(m_pParentListAnchor, this, const Node, m_listEntry); + } + /** @} */ + +protected: + /** Node types. */ + typedef enum { IsElement, IsAttribute, IsContent } EnumType; + + /** The type of node this is an instance of. */ + EnumType m_Type; + /** The parent node (always an element), NULL if root. */ + Node *m_pParent; + + xmlNode *m_pLibNode; ///< != NULL if this is an element or content node + xmlAttr *m_pLibAttr; ///< != NULL if this is an attribute node + const char *m_pcszNamespacePrefix; ///< not always set + const char *m_pcszNamespaceHref; ///< full http:// spec + const char *m_pcszName; ///< element or attribute name, points either into pLibNode or pLibAttr; + ///< NULL if this is a content node + + /** Child list entry of this node. (List head m_pParent->m_children or + * m_pParent->m_attribute depending on the type.) */ + RTLISTNODE m_listEntry; + /** Pointer to the parent list anchor. + * This allows us to use m_listEntry both for children and attributes. */ + PRTLISTANCHOR m_pParentListAnchor; + + // hide the default constructor so people use only our factory methods + Node(EnumType type, + Node *pParent, + PRTLISTANCHOR pListAnchor, + xmlNode *pLibNode, + xmlAttr *pLibAttr); + Node(const Node &x); // no copying + + friend class AttributeNode; + friend class ElementNode; /* C list hack. */ +}; + +/** + * Node subclass that represents an attribute of an element. + * + * For attributes, Node::getName() returns the attribute name, and Node::getValue() + * returns the attribute value, if any. + * + * Since the Node constructor is private, one can create new attribute nodes + * only through the following factory methods: + * + * -- ElementNode::setAttribute() + */ +class RT_DECL_CLASS AttributeNode : public Node +{ +public: + +protected: + // hide the default constructor so people use only our factory methods + AttributeNode(const ElementNode *pElmRoot, + Node *pParent, + PRTLISTANCHOR pListAnchor, + xmlAttr *pLibAttr); + AttributeNode(const AttributeNode &x); // no copying + + friend class Node; + friend class ElementNode; +}; + +/** + * Node subclass that represents an element. + * + * For elements, Node::getName() returns the element name, and Node::getValue() + * returns the text contents, if any. + * + * Since the Node constructor is private, one can create element nodes + * only through the following factory methods: + * + * -- Document::createRootElement() + * -- ElementNode::createChild() + */ +class RT_DECL_CLASS ElementNode : public Node +{ +public: + int getChildElements(ElementNodesList &children, const char *pcszMatch = NULL) const; + + const ElementNode *findChildElementNS(const char *pcszNamespace, const char *pcszMatch) const; + const ElementNode *findChildElement(const char *pcszMatch) const + { + return findChildElementNS(NULL, pcszMatch); + } + const ElementNode *findChildElementFromId(const char *pcszId) const; + + /** Finds the first decendant matching the name at the end of @a pcszPath and + * optionally namespace. + * + * @returns Pointer to the child string value, NULL if not found or no value. + * @param pcszPath Path to the child element. Slashes can be used to + * make a simple path to any decendant. + * @param pcszNamespace The namespace to match, NULL (default) match any + * namespace. When using a path, this matches all + * elements along the way. + * @see findChildElement, findChildElementP + */ + const ElementNode *findChildElementP(const char *pcszPath, const char *pcszNamespace = NULL) const; + + /** Finds the first child with matching the give name and optionally namspace, + * returning its value. + * + * @returns Pointer to the child string value, NULL if not found or no value. + * @param pcszPath Path to the child element. Slashes can be used to + * make a simple path to any decendant. + * @param pcszNamespace The namespace to match, NULL (default) match any + * namespace. When using a path, this matches all + * elements along the way. + * @see findChildElement, findChildElementP + */ + const char *findChildElementValueP(const char *pcszPath, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getValue(); + return NULL; + } + + /** Finds the first child with matching the give name and optionally namspace, + * returning its value. Checks the length against the limit. + * + * @returns Pointer to the child string value, NULL if not found or no value. + * @param pcszPath Path to the child element. Slashes can be used to + * make a simple path to any decendant. + * @param cchValueLimit If the length of the returned value exceeds this + * limit a EIPRTFailure exception will be thrown. + * @param pcszNamespace The namespace to match, NULL (default) match any + * namespace. When using a path, this matches all + * elements along the way. + * @see findChildElement, findChildElementP + */ + const char *findChildElementValuePN(const char *pcszPath, size_t cchValueLimit, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getValueN(cchValueLimit); + return NULL; + } + + /** Combines findChildElementNS and findAttributeValue. + * + * @returns Pointer to attribute string value, NULL if either the element or + * the attribute was not found. + * @param pcszChild The child element name. + * @param pcszAttribute The attribute name. + * @param pcszChildNamespace The namespace to match @a pcszChild with, NULL + * (default) match any namespace. + * @param pcszAttributeNamespace The namespace prefix to apply to the + * attribute, NULL (default) match any namespace. + * @see findChildElementNS and findAttributeValue + * @note The findChildElementAttributeValueP() method would do the same thing + * given the same inputs, but it would be slightly slower, thus the + * separate method. + */ + const char *findChildElementAttributeValue(const char *pcszChild, const char *pcszAttribute, + const char *pcszChildNamespace = NULL, + const char *pcszAttributeNamespace = NULL) const + { + const ElementNode *pElem = findChildElementNS(pcszChildNamespace, pcszChild); + if (pElem) + return pElem->findAttributeValue(pcszAttribute, pcszAttributeNamespace); + return NULL; + } + + /** Combines findChildElementP and findAttributeValue. + * + * @returns Pointer to attribute string value, NULL if either the element or + * the attribute was not found. + * @param pcszPath Path to the child element. Slashes can be used + * to make a simple path to any decendant. + * @param pcszAttribute The attribute name. + * @param pcszPathNamespace The namespace to match @a pcszPath with, NULL + * (default) match any namespace. When using a + * path, this matches all elements along the way. + * @param pcszAttributeNamespace The namespace prefix to apply to the + * attribute, NULL (default) match any namespace. + * @see findChildElementP and findAttributeValue + */ + const char *findChildElementAttributeValueP(const char *pcszPath, const char *pcszAttribute, + const char *pcszPathNamespace = NULL, + const char *pcszAttributeNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszPathNamespace); + if (pElem) + return pElem->findAttributeValue(pcszAttribute, pcszAttributeNamespace); + return NULL; + } + + /** Combines findChildElementP and findAttributeValueN. + * + * @returns Pointer to attribute string value, NULL if either the element or + * the attribute was not found. + * @param pcszPath The attribute name. Slashes can be used to make a + * simple path to any decendant. + * @param pcszAttribute The attribute name. + * @param cchValueLimit If the length of the returned value exceeds this + * limit a EIPRTFailure exception will be thrown. + * @param pcszPathNamespace The namespace to match @a pcszPath with, NULL + * (default) match any namespace. When using a + * path, this matches all elements along the way. + * @param pcszAttributeNamespace The namespace prefix to apply to the + * attribute, NULL (default) match any namespace. + * @see findChildElementP and findAttributeValue + */ + const char *findChildElementAttributeValuePN(const char *pcszPath, const char *pcszAttribute, + size_t cchValueLimit, + const char *pcszPathNamespace = NULL, + const char *pcszAttributeNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszPathNamespace); + if (pElem) + return pElem->findAttributeValueN(pcszAttribute, cchValueLimit, pcszAttributeNamespace); + return NULL; + } + + + /** @name Tree enumeration. + * @{ */ + + /** Get the next tree element in a full tree enumeration. + * + * By starting with the root node, this can be used to enumerate the entire tree + * (or sub-tree if @a pElmRoot is used). + * + * @returns Pointer to the next element in the tree, NULL if we're done. + * @param pElmRoot The root of the tree we're enumerating. NULL if + * it's the entire tree. + */ + ElementNode const *getNextTreeElement(ElementNode const *pElmRoot = NULL) const; + RT_CPP_GETTER_UNCONST_RET(ElementNode *, ElementNode, getNextTreeElement, (const ElementNode *pElmRoot = NULL), (pElmRoot)) + + /** Get the first child node. + * @returns Pointer to the first child node, NULL if no children. */ + const Node *getFirstChild() const + { + return RTListGetFirstCpp(&m_children, const Node, m_listEntry); + } + RT_CPP_GETTER_UNCONST_RET(Node *, ElementNode, getFirstChild,(),()) + + /** Get the last child node. + * @returns Pointer to the last child node, NULL if no children. */ + const Node *getLastChild() const + { + return RTListGetLastCpp(&m_children, const Node, m_listEntry); + } + + /** Get the first child node. + * @returns Pointer to the first child node, NULL if no children. */ + const ElementNode *getFirstChildElement() const; + + /** Get the last child node. + * @returns Pointer to the last child node, NULL if no children. */ + const ElementNode *getLastChildElement() const; + + /** Get the previous sibling element. + * @returns Pointer to the previous sibling element, NULL if first child + * element. + * @see getNextSibilingElement, getPrevSibling + */ + const ElementNode *getPrevSibilingElement() const; + + /** Get the next sibling element. + * @returns Pointer to the next sibling element, NULL if last child element. + * @see getPrevSibilingElement, getNextSibling + */ + const ElementNode *getNextSibilingElement() const; + + /** Find the previous element matching the given name and namespace (optionally). + * @returns Pointer to the previous sibling element, NULL if first child + * element. + * @param pcszName The element name to match. + * @param pcszNamespace The namespace name, default is NULL which means + * anything goes. + * @note Changed the order of the arguments. + */ + const ElementNode *findPrevSibilingElement(const char *pcszName, const char *pcszNamespace = NULL) const; + + /** Find the next element matching the given name and namespace (optionally). + * @returns Pointer to the previous sibling element, NULL if first child + * element. + * @param pcszName The element name to match. + * @param pcszNamespace The namespace name, default is NULL which means + * anything goes. + * @note Changed the order of the arguments. + */ + const ElementNode *findNextSibilingElement(const char *pcszName, const char *pcszNamespace = NULL) const; + /** @} */ + + /** @name Attribute enumeration + * @{ */ + + /** Get the first attribute node. + * @returns Pointer to the first child node, NULL if no attributes. */ + const AttributeNode *getFirstAttribute() const + { + return RTListGetFirstCpp(&m_attributes, const AttributeNode, m_listEntry); + } + + /** Get the last attribute node. + * @returns Pointer to the last child node, NULL if no attributes. */ + const AttributeNode *getLastAttribute() const + { + return RTListGetLastCpp(&m_attributes, const AttributeNode, m_listEntry); + } + + /** @} */ + + const AttributeNode *findAttribute(const char *pcszMatch, const char *pcszNamespace = NULL) const; + /** Find the first attribute with the given name, returning its value string. + * @returns Pointer to the attribute string value. + * @param pcszName The attribute name. + * @param pcszNamespace The namespace name, default is NULL which means + * anything goes. + * @see getAttributeValue + */ + const char *findAttributeValue(const char *pcszName, const char *pcszNamespace = NULL) const + { + const AttributeNode *pAttr = findAttribute(pcszName, pcszNamespace); + if (pAttr) + return pAttr->getValue(); + return NULL; + } + /** Find the first attribute with the given name, returning its value string. + * @returns Pointer to the attribute string value. + * @param pcszName The attribute name. + * @param cchValueLimit If the length of the returned value exceeds this + * limit a EIPRTFailure exception will be thrown. + * @param pcszNamespace The namespace name, default is NULL which means + * anything goes. + * @see getAttributeValue + */ + const char *findAttributeValueN(const char *pcszName, size_t cchValueLimit, const char *pcszNamespace = NULL) const + { + const AttributeNode *pAttr = findAttribute(pcszName, pcszNamespace); + if (pAttr) + return pAttr->getValueN(cchValueLimit); + return NULL; + } + + bool getAttributeValue(const char *pcszMatch, const char *&pcsz, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &pcsz, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, RTCString &str, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &str, pcszNamespace); } + bool getAttributeValuePath(const char *pcszMatch, RTCString &str, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &str, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, int32_t &i, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &i, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, uint32_t &i, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &i, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, int64_t &i, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &i, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, uint64_t &u, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &u, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, bool &f, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &f, pcszNamespace); } + bool getAttributeValueN(const char *pcszMatch, const char *&pcsz, size_t cchValueLimit, const char *pcszNamespace = NULL) const + { return getAttributeValueN(pcszMatch, &pcsz, cchValueLimit, pcszNamespace); } + bool getAttributeValueN(const char *pcszMatch, RTCString &str, size_t cchValueLimit, const char *pcszNamespace = NULL) const + { return getAttributeValueN(pcszMatch, &str, cchValueLimit, pcszNamespace); } + bool getAttributeValuePathN(const char *pcszMatch, RTCString &str, size_t cchValueLimit, const char *pcszNamespace = NULL) const + { return getAttributeValueN(pcszMatch, &str, cchValueLimit, pcszNamespace); } + + /** @name Variants that for clarity does not use references for output params. + * @{ */ + bool getAttributeValue(const char *pcszMatch, const char **ppcsz, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, RTCString *pStr, const char *pcszNamespace = NULL) const; + bool getAttributeValuePath(const char *pcszMatch, RTCString *pStr, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, int32_t *pi, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, uint32_t *pu, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, int64_t *piValue, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, uint64_t *pu, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, bool *pf, const char *pcszNamespace = NULL) const; + bool getAttributeValueN(const char *pcszMatch, const char **ppcsz, size_t cchValueLimit, const char *pcszNamespace = NULL) const; + bool getAttributeValueN(const char *pcszMatch, RTCString *pStr, size_t cchValueLimit, const char *pcszNamespace = NULL) const; + bool getAttributeValuePathN(const char *pcszMatch, RTCString *pStr, size_t cchValueLimit, const char *pcszNamespace = NULL) const; + /** @} */ + + /** @name Convenience methods for convering the element value. + * @{ */ + bool getElementValue(int32_t *piValue) const; + bool getElementValue(uint32_t *puValue) const; + bool getElementValue(int64_t *piValue) const; + bool getElementValue(uint64_t *puValue) const; + bool getElementValue(bool *pfValue) const; + /** @} */ + + /** @name Convenience findChildElementValueP and getElementValue. + * @{ */ + bool getChildElementValueP(const char *pcszPath, int32_t *piValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + return pElem && pElem->getElementValue(piValue); + } + bool getChildElementValueP(const char *pcszPath, uint32_t *puValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + return pElem && pElem->getElementValue(puValue); + } + bool getChildElementValueP(const char *pcszPath, int64_t *piValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + return pElem && pElem->getElementValue(piValue); + } + bool getChildElementValueP(const char *pcszPath, uint64_t *puValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + return pElem && pElem->getElementValue(puValue); + } + bool getChildElementValueP(const char *pcszPath, bool *pfValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + return pElem && pElem->getElementValue(pfValue); + } + + /** @} */ + + /** @name Convenience findChildElementValueP and getElementValue with a + * default value being return if the child element isn't present. + * + * @remarks These will return false on conversion errors. + * @{ */ + bool getChildElementValueDefP(const char *pcszPath, int32_t iDefault, int32_t *piValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getElementValue(piValue); + *piValue = iDefault; + return true; + } + bool getChildElementValueDefP(const char *pcszPath, uint32_t uDefault, uint32_t *puValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getElementValue(puValue); + *puValue = uDefault; + return true; + } + bool getChildElementValueDefP(const char *pcszPath, int64_t iDefault, int64_t *piValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getElementValue(piValue); + *piValue = iDefault; + return true; + } + bool getChildElementValueDefP(const char *pcszPath, uint64_t uDefault, uint64_t *puValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getElementValue(puValue); + *puValue = uDefault; + return true; + } + bool getChildElementValueDefP(const char *pcszPath, bool fDefault, bool *pfValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getElementValue(pfValue); + *pfValue = fDefault; + return true; + } + /** @} */ + + ElementNode *createChild(const char *pcszElementName); + + ContentNode *addContent(const char *pcszContent); + ContentNode *addContent(const RTCString &strContent) + { + return addContent(strContent.c_str()); + } + + ContentNode *setContent(const char *pcszContent); + ContentNode *setContent(const RTCString &strContent) + { + return setContent(strContent.c_str()); + } + + AttributeNode *setAttribute(const char *pcszName, const char *pcszValue); + AttributeNode *setAttribute(const char *pcszName, const RTCString &strValue) + { + return setAttribute(pcszName, strValue.c_str()); + } + AttributeNode *setAttributePath(const char *pcszName, const RTCString &strValue); + AttributeNode *setAttribute(const char *pcszName, int32_t i); + AttributeNode *setAttribute(const char *pcszName, uint32_t i); + AttributeNode *setAttribute(const char *pcszName, int64_t i); + AttributeNode *setAttribute(const char *pcszName, uint64_t i); + AttributeNode *setAttributeHex(const char *pcszName, uint32_t i); + AttributeNode *setAttribute(const char *pcszName, bool f); + + virtual ~ElementNode(); + +protected: + // hide the default constructor so people use only our factory methods + ElementNode(const ElementNode *pElmRoot, Node *pParent, PRTLISTANCHOR pListAnchor, xmlNode *pLibNode); + ElementNode(const ElementNode &x); // no copying + + /** We keep a pointer to the root element for attribute namespace handling. */ + const ElementNode *m_pElmRoot; + + /** List of child elements and content nodes. */ + RTLISTANCHOR m_children; + /** List of attributes nodes. */ + RTLISTANCHOR m_attributes; + + static void buildChildren(ElementNode *pElmRoot); + + friend class Node; + friend class Document; + friend class XmlFileParser; +}; + +/** + * Node subclass that represents content (non-element text). + * + * Since the Node constructor is private, one can create new content nodes + * only through the following factory methods: + * + * -- ElementNode::addContent() + */ +class RT_DECL_CLASS ContentNode : public Node +{ +public: + +protected: + // hide the default constructor so people use only our factory methods + ContentNode(Node *pParent, PRTLISTANCHOR pListAnchor, xmlNode *pLibNode); + ContentNode(const ContentNode &x); // no copying + + friend class Node; + friend class ElementNode; +}; + + +/** + * Handy helper class with which one can loop through all or some children + * of a particular element. See NodesLoop::forAllNodes() for details. + */ +class RT_DECL_CLASS NodesLoop +{ +public: + NodesLoop(const ElementNode &node, const char *pcszMatch = NULL); + ~NodesLoop(); + const ElementNode* forAllNodes() const; + +private: + /* Obscure class data */ + struct Data; + Data *m; +}; + +/** + * The XML document class. An instance of this needs to be created by a user + * of the XML classes and then passed to + * + * -- XmlMemParser or XmlFileParser to read an XML document; those classes then + * fill the caller's Document with ElementNode, ContentNode and AttributeNode + * instances. The typical sequence then is: + * @code + Document doc; + XmlFileParser parser; + parser.read("file.xml", doc); + Element *pElmRoot = doc.getRootElement(); + @endcode + * + * -- XmlMemWriter or XmlFileWriter to write out an XML document after it has + * been created and filled. Example: + * + * @code + Document doc; + Element *pElmRoot = doc.createRootElement(); + // add children + xml::XmlFileWriter writer(doc); + writer.write("file.xml", true); + @endcode + */ +class RT_DECL_CLASS Document +{ +public: + Document(); + ~Document(); + + Document(const Document &x); + Document& operator=(const Document &x); + + const ElementNode* getRootElement() const; + ElementNode* getRootElement(); + + ElementNode* createRootElement(const char *pcszRootElementName, + const char *pcszComment = NULL); + +private: + friend class XmlMemParser; + friend class XmlFileParser; + friend class XmlMemWriter; + friend class XmlStringWriter; + friend class XmlFileWriter; + + void refreshInternals(); + + /* Obscure class data */ + struct Data; + Data *m; +}; + +/* + * XmlParserBase + * + */ + +class RT_DECL_CLASS XmlParserBase +{ +protected: + XmlParserBase(); + ~XmlParserBase(); + + xmlParserCtxtPtr m_ctxt; +}; + +/* + * XmlMemParser + * + */ + +class RT_DECL_CLASS XmlMemParser : public XmlParserBase +{ +public: + XmlMemParser(); + ~XmlMemParser(); + + void read(const void* pvBuf, size_t cbSize, const RTCString &strFilename, Document &doc); +}; + +/* + * XmlFileParser + * + */ + +class RT_DECL_CLASS XmlFileParser : public XmlParserBase +{ +public: + XmlFileParser(); + ~XmlFileParser(); + + void read(const RTCString &strFilename, Document &doc); + +private: + /* Obscure class data */ + struct Data; + struct Data *m; + + static int ReadCallback(void *aCtxt, char *aBuf, int aLen) RT_NOTHROW_PROTO; + static int CloseCallback(void *aCtxt) RT_NOTHROW_PROTO; +}; + +/** + * XmlMemWriter + */ +class RT_DECL_CLASS XmlMemWriter +{ +public: + XmlMemWriter(); + ~XmlMemWriter(); + + void write(const Document &doc, void** ppvBuf, size_t *pcbSize); + +private: + void* m_pBuf; +}; + + +/** + * XmlStringWriter - writes the XML to an RTCString instance. + */ +class RT_DECL_CLASS XmlStringWriter +{ +public: + XmlStringWriter(); + + int write(const Document &rDoc, RTCString *pStrDst); + +private: + static int WriteCallbackForSize(void *pvUser, const char *pachBuf, int cbToWrite) RT_NOTHROW_PROTO; + static int WriteCallbackForReal(void *pvUser, const char *pachBuf, int cbToWrite) RT_NOTHROW_PROTO; + static int CloseCallback(void *pvUser) RT_NOTHROW_PROTO; + + /** Pointer to the destination string while we're in the write() call. */ + RTCString *m_pStrDst; + /** Set by WriteCallback if we cannot grow the destination string. */ + bool m_fOutOfMemory; +}; + + +/** + * XmlFileWriter + */ +class RT_DECL_CLASS XmlFileWriter +{ +public: + XmlFileWriter(Document &doc); + ~XmlFileWriter(); + + /** + * Writes the XML document to the specified file. + * + * @param pcszFilename The name of the output file. + * @param fSafe If @c true, some extra safety precautions will be + * taken when writing the file: + * -# The file is written with a '-tmp' suffix. + * -# It is flushed to disk after writing. + * -# Any original file is renamed to '-prev'. + * -# The '-tmp' file is then renamed to the + * specified name. + * -# The directory changes are flushed to disk. + * The suffixes are available via s_pszTmpSuff and + * s_pszPrevSuff. + */ + void write(const char *pcszFilename, bool fSafe); + + static int WriteCallback(void *aCtxt, const char *aBuf, int aLen) RT_NOTHROW_PROTO; + static int CloseCallback(void *aCtxt) RT_NOTHROW_PROTO; + + /** The suffix used by XmlFileWriter::write() for the temporary file. */ + static const char * const s_pszTmpSuff; + /** The suffix used by XmlFileWriter::write() for the previous (backup) file. */ + static const char * const s_pszPrevSuff; + +private: + void writeInternal(const char *pcszFilename, bool fSafe); + + /* Obscure class data */ + struct Data; + Data *m; +}; + +#if defined(_MSC_VER) +#pragma warning (default:4251) +#endif + +/** @} */ + +} // end namespace xml + +#endif /* !IPRT_INCLUDED_cpp_xml_h */ + diff --git a/include/iprt/cpuset.h b/include/iprt/cpuset.h new file mode 100644 index 00000000..c5882472 --- /dev/null +++ b/include/iprt/cpuset.h @@ -0,0 +1,353 @@ +/** @file + * IPRT - CPU Set. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_cpuset_h +#define IPRT_INCLUDED_cpuset_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/mp.h> /* RTMpCpuIdToSetIndex */ +#include <iprt/asm.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_cpuset RTCpuSet - CPU Set + * @ingroup grp_rt + * @{ + */ + + +/** + * Clear all CPUs. + * + * @returns pSet. + * @param pSet Pointer to the set. + */ +DECLINLINE(PRTCPUSET) RTCpuSetEmpty(PRTCPUSET pSet) +{ + size_t i; + for (i = 0; i < RT_ELEMENTS(pSet->bmSet); i++) + pSet->bmSet[i] = 0; + return pSet; +} + + +/** + * Set all CPUs. + * + * @returns pSet. + * @param pSet Pointer to the set. + */ +DECLINLINE(PRTCPUSET) RTCpuSetFill(PRTCPUSET pSet) +{ + size_t i; + for (i = 0; i < RT_ELEMENTS(pSet->bmSet); i++) + pSet->bmSet[i] = UINT64_MAX; + return pSet; +} + + +/** + * Copies one set to another. + * + * @param pDst Pointer to the destination set. + * @param pSrc Pointer to the source set. + */ +DECLINLINE(void) RTCpuSetCopy(PRTCPUSET pDst, PRTCPUSET pSrc) +{ + size_t i; + for (i = 0; i < RT_ELEMENTS(pDst->bmSet); i++) + pDst->bmSet[i] = pSrc->bmSet[i]; +} + + +/** + * ANDs the given CPU set with another. + * + * @returns pSet. + * @param pSet Pointer to the set. + * @param pAndMaskSet Pointer to the AND-mask set. + */ +DECLINLINE(PRTCPUSET) RTCpuSetAnd(PRTCPUSET pSet, PRTCPUSET pAndMaskSet) +{ + size_t i; + for (i = 0; i < RT_ELEMENTS(pSet->bmSet); i++) + ASMAtomicAndU64((volatile uint64_t *)&pSet->bmSet[i], pAndMaskSet->bmSet[i]); + return pSet; +} + + +/** + * Adds a CPU given by its identifier to the set. + * + * @returns 0 on success, -1 if idCpu isn't valid. + * @param pSet Pointer to the set. + * @param idCpu The identifier of the CPU to add. + * @remarks The modification is atomic. + */ +DECLINLINE(int) RTCpuSetAdd(PRTCPUSET pSet, RTCPUID idCpu) +{ + int iCpu = RTMpCpuIdToSetIndex(idCpu); + if (RT_LIKELY(iCpu >= 0)) + { + ASMAtomicBitSet(pSet, iCpu); + return 0; + } + return -1; +} + + +/** + * Adds a CPU given by its identifier to the set. + * + * @returns 0 on success, -1 if iCpu isn't valid. + * @param pSet Pointer to the set. + * @param iCpu The index of the CPU to add. + * @remarks The modification is atomic. + */ +DECLINLINE(int) RTCpuSetAddByIndex(PRTCPUSET pSet, int iCpu) +{ + if (RT_LIKELY((unsigned)iCpu < RTCPUSET_MAX_CPUS)) + { + ASMAtomicBitSet(pSet, iCpu); + return 0; + } + return -1; +} + + +/** + * Removes a CPU given by its identifier from the set. + * + * @returns 0 on success, -1 if idCpu isn't valid. + * @param pSet Pointer to the set. + * @param idCpu The identifier of the CPU to delete. + * @remarks The modification is atomic. + */ +DECLINLINE(int) RTCpuSetDel(PRTCPUSET pSet, RTCPUID idCpu) +{ + int iCpu = RTMpCpuIdToSetIndex(idCpu); + if (RT_LIKELY(iCpu >= 0)) + { + ASMAtomicBitClear(pSet, iCpu); + return 0; + } + return -1; +} + + +/** + * Removes a CPU given by its index from the set. + * + * @returns 0 on success, -1 if iCpu isn't valid. + * @param pSet Pointer to the set. + * @param iCpu The index of the CPU to delete. + * @remarks The modification is atomic. + */ +DECLINLINE(int) RTCpuSetDelByIndex(PRTCPUSET pSet, int iCpu) +{ + if (RT_LIKELY((unsigned)iCpu < RTCPUSET_MAX_CPUS)) + { + ASMAtomicBitClear(pSet, iCpu); + return 0; + } + return -1; +} + + +/** + * Checks if a CPU given by its identifier is a member of the set. + * + * @returns true / false accordingly. + * @param pSet Pointer to the set. + * @param idCpu The identifier of the CPU to look for. + * @remarks The test is atomic. + */ +DECLINLINE(bool) RTCpuSetIsMember(PCRTCPUSET pSet, RTCPUID idCpu) +{ + int iCpu = RTMpCpuIdToSetIndex(idCpu); + if (RT_LIKELY(iCpu >= 0)) + return ASMBitTest((volatile void *)pSet, iCpu); + return false; +} + + +/** + * Checks if a CPU given by its index is a member of the set. + * + * @returns true / false accordingly. + * @param pSet Pointer to the set. + * @param iCpu The index of the CPU in the set. + * @remarks The test is atomic. + */ +DECLINLINE(bool) RTCpuSetIsMemberByIndex(PCRTCPUSET pSet, int iCpu) +{ + if (RT_LIKELY((unsigned)iCpu < RTCPUSET_MAX_CPUS)) + return ASMBitTest((volatile void *)pSet, iCpu); + return false; +} + + +/** + * Checks if the two sets match or not. + * + * @returns true / false accordingly. + * @param pSet1 The first set. + * @param pSet2 The second set. + */ +DECLINLINE(bool) RTCpuSetIsEqual(PCRTCPUSET pSet1, PCRTCPUSET pSet2) +{ + size_t i; + for (i = 0; i < RT_ELEMENTS(pSet1->bmSet); i++) + if (pSet1->bmSet[i] != pSet2->bmSet[i]) + return false; + return true; +} + + +/** + * Checks if the CPU set is empty or not. + * + * @returns true / false accordingly. + * @param pSet Pointer to the set. + */ +DECLINLINE(bool) RTCpuSetIsEmpty(PRTCPUSET pSet) +{ + size_t i; + for (i = 0; i < RT_ELEMENTS(pSet->bmSet); i++) + if (pSet->bmSet[i]) + return false; + return true; +} + + +/** + * Converts the CPU set to a 64-bit mask. + * + * @returns The mask. + * @param pSet Pointer to the set. + * @remarks Use with extreme care as it may lose information! + */ +DECLINLINE(uint64_t) RTCpuSetToU64(PCRTCPUSET pSet) +{ + return pSet->bmSet[0]; +} + + +/** + * Initializes the CPU set from a 64-bit mask. + * + * @param pSet Pointer to the set. + * @param fMask The mask. + */ +DECLINLINE(PRTCPUSET) RTCpuSetFromU64(PRTCPUSET pSet, uint64_t fMask) +{ + size_t i; + + pSet->bmSet[0] = fMask; + for (i = 1; i < RT_ELEMENTS(pSet->bmSet); i++) + pSet->bmSet[i] = 0; + + return pSet; +} + + +/** + * Count the CPUs in the set. + * + * @returns CPU count. + * @param pSet Pointer to the set. + */ +DECLINLINE(int) RTCpuSetCount(PCRTCPUSET pSet) +{ + int cCpus = 0; + size_t i; + + for (i = 0; i < RT_ELEMENTS(pSet->bmSet); i++) + { + uint64_t u64 = pSet->bmSet[i]; + if (u64 != 0) + { + unsigned iCpu = 64; + while (iCpu-- > 0) + { + if (u64 & 1) + cCpus++; + u64 >>= 1; + } + } + } + return cCpus; +} + + +/** + * Get the highest set index. + * + * @returns The higest set index, -1 if all bits are clear. + * @param pSet Pointer to the set. + */ +DECLINLINE(int) RTCpuLastIndex(PCRTCPUSET pSet) +{ + size_t i = RT_ELEMENTS(pSet->bmSet); + while (i-- > 0) + { + uint64_t u64 = pSet->bmSet[i]; + if (u64) + { + /* There are more efficient ways to do this in asm.h... */ + unsigned iBit; + for (iBit = 63; iBit > 0; iBit--) + { + if (u64 & RT_BIT_64(63)) + break; + u64 <<= 1; + } + return (int)i * 64 + (int)iBit; + } + } + return 0; +} + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_cpuset_h */ + diff --git a/include/iprt/crc.h b/include/iprt/crc.h new file mode 100644 index 00000000..60706493 --- /dev/null +++ b/include/iprt/crc.h @@ -0,0 +1,250 @@ +/** @file + * IPRT - CRCs and Checksums. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crc_h +#define IPRT_INCLUDED_crc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_crc RTCrc - Checksums and CRCs. + * @ingroup grp_rt + * @{ + */ + + +/** @defgroup grp_rt_crc32 CRC-32 + * @{ */ +/** + * Calculate CRC-32 for a memory block. + * + * @returns CRC-32 for the memory block. + * @param pv Pointer to the memory block. + * @param cb Size of the memory block in bytes. + */ +RTDECL(uint32_t) RTCrc32(const void *pv, size_t cb); + +/** + * Start a multiblock CRC-32 calculation. + * + * @returns Start CRC-32. + */ +RTDECL(uint32_t) RTCrc32Start(void); + +/** + * Processes a multiblock of a CRC-32 calculation. + * + * @returns Intermediate CRC-32 value. + * @param uCRC32 Current CRC-32 intermediate value. + * @param pv The data block to process. + * @param cb The size of the data block in bytes. + */ +RTDECL(uint32_t) RTCrc32Process(uint32_t uCRC32, const void *pv, size_t cb); + +/** + * Complete a multiblock CRC-32 calculation. + * + * @returns CRC-32 value. + * @param uCRC32 Current CRC-32 intermediate value. + */ +RTDECL(uint32_t) RTCrc32Finish(uint32_t uCRC32); +/** @} */ + + +/** @defgroup grp_rt_crc64 CRC-64 Calculation + * @{ */ +/** + * Calculate CRC-64 for a memory block. + * + * @returns CRC-64 for the memory block. + * @param pv Pointer to the memory block. + * @param cb Size of the memory block in bytes. + */ +RTDECL(uint64_t) RTCrc64(const void *pv, size_t cb); + +/** + * Start a multiblock CRC-64 calculation. + * + * @returns Start CRC-64. + */ +RTDECL(uint64_t) RTCrc64Start(void); + +/** + * Processes a multiblock of a CRC-64 calculation. + * + * @returns Intermediate CRC-64 value. + * @param uCRC64 Current CRC-64 intermediate value. + * @param pv The data block to process. + * @param cb The size of the data block in bytes. + */ +RTDECL(uint64_t) RTCrc64Process(uint64_t uCRC64, const void *pv, size_t cb); + +/** + * Complete a multiblock CRC-64 calculation. + * + * @returns CRC-64 value. + * @param uCRC64 Current CRC-64 intermediate value. + */ +RTDECL(uint64_t) RTCrc64Finish(uint64_t uCRC64); +/** @} */ + + +/** @defgroup grp_rt_crc_adler32 Adler-32 + * @{ */ +/** + * Calculate Adler-32 for a memory block. + * + * @returns Adler-32 for the memory block. + * @param pv Pointer to the memory block. + * @param cb Size of the memory block in bytes. + */ +RTDECL(uint32_t) RTCrcAdler32(void const *pv, size_t cb); + +/** + * Start a multiblock Adler-32 calculation. + * + * @returns Start Adler-32. + */ +RTDECL(uint32_t) RTCrcAdler32Start(void); + +/** + * Processes a multiblock of a Adler-32 calculation. + * + * @returns Intermediate Adler-32 value. + * @param uCrc Current Adler-32 intermediate value. + * @param pv The data block to process. + * @param cb The size of the data block in bytes. + */ +RTDECL(uint32_t) RTCrcAdler32Process(uint32_t uCrc, void const *pv, size_t cb); + +/** + * Complete a multiblock Adler-32 calculation. + * + * @returns Adler-32 value. + * @param uCrc Current Adler-32 intermediate value. + */ +RTDECL(uint32_t) RTCrcAdler32Finish(uint32_t uCrc); + +/** @} */ + + +/** @defgroup grp_rt_crc32c CRC-32C + * @{ */ +/** + * Calculate CRC-32C for a memory block. + * + * @returns CRC-32C for the memory block. + * @param pv Pointer to the memory block. + * @param cb Size of the memory block in bytes. + */ +RTDECL(uint32_t) RTCrc32C(const void *pv, size_t cb); + +/** + * Start a multiblock CRC-32 calculation. + * + * @returns Start CRC-32. + */ +RTDECL(uint32_t) RTCrc32CStart(void); + +/** + * Processes a multiblock of a CRC-32C calculation. + * + * @returns Intermediate CRC-32C value. + * @param uCRC32C Current CRC-32C intermediate value. + * @param pv The data block to process. + * @param cb The size of the data block in bytes. + */ +RTDECL(uint32_t) RTCrc32CProcess(uint32_t uCRC32C, const void *pv, size_t cb); + +/** + * Complete a multiblock CRC-32 calculation. + * + * @returns CRC-32 value. + * @param uCRC32 Current CRC-32 intermediate value. + */ +RTDECL(uint32_t) RTCrc32CFinish(uint32_t uCRC32); + +/** @} */ + + +/** @defgroup grp_rt_crc16ccitt CRC-16-CCITT + * @{ */ +/** + * Calculate CRC-16-CCITT for a memory block. + * + * @returns CRC-16-CCITT for the memory block. + * @param pv Pointer to the memory block. + * @param cb Size of the memory block in bytes. + */ +RTDECL(uint16_t) RTCrc16Ccitt(const void *pv, size_t cb); + +/** + * Start a multiblock CRC-16-CCITT calculation. + * + * @returns Start CRC-16-CCITT. + */ +RTDECL(uint16_t) RTCrc16CcittStart(void); + +/** + * Processes a multiblock of a CRC-16-CCITT calculation. + * + * @returns Intermediate CRC-16-CCITT value. + * @param uCrc Current CRC-16-CCITT intermediate value. + * @param pv The data block to process. + * @param cb The size of the data block in bytes. + */ +RTDECL(uint16_t) RTCrc16CcittProcess(uint16_t uCrc, const void *pv, size_t cb); + +/** + * Complete a multiblock CRC-16-CCITT calculation. + * + * @returns CRC-16-CCITT value. + * @param uCrc Current CRC-16-CCITT intermediate value. + */ +RTDECL(uint16_t) RTCrc16CcittFinish(uint16_t uCrc); +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crc_h */ + diff --git a/include/iprt/critsect.h b/include/iprt/critsect.h new file mode 100644 index 00000000..861cb675 --- /dev/null +++ b/include/iprt/critsect.h @@ -0,0 +1,768 @@ +/** @file + * IPRT - Critical Sections. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_critsect_h +#define IPRT_INCLUDED_critsect_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/assert.h> +#if defined(IN_RING3) || defined(IN_RING0) +# include <iprt/thread.h> +#endif +#ifdef RT_LOCK_STRICT_ORDER +# include <iprt/lockvalidator.h> +#endif + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_critsect RTCritSect - Critical Sections + * + * "Critical section" synchronization primitives can be used to + * protect a section of code or data to which access must be exclusive; + * only one thread can hold access to a critical section at one time. + * + * A critical section is a fast recursive write lock; if the critical + * section is not acquired, then entering it is fast (requires no system + * call). IPRT uses the Windows terminology here; on other platform, this + * might be called a "futex" or a "fast mutex". As opposed to IPRT + * "fast mutexes" (see @ref grp_rt_sems_fast_mutex ), critical sections + * are recursive. + * + * Use RTCritSectInit to initialize a critical section; use RTCritSectEnter + * and RTCritSectLeave to acquire and release access. + * + * For an overview of all types of synchronization primitives provided + * by IPRT (event, mutex/fast mutex/read-write mutex semaphores), see + * @ref grp_rt_sems . + * + * @ingroup grp_rt + * @{ + */ + +/** + * Critical section. + */ +typedef struct RTCRITSECT +{ + /** Magic used to validate the section state. + * RTCRITSECT_MAGIC is the value of an initialized & operational section. */ + volatile uint32_t u32Magic; + /** Number of lockers. + * -1 if the section is free. */ + volatile int32_t cLockers; + /** The owner thread. */ + volatile RTNATIVETHREAD NativeThreadOwner; + /** Number of nested enter operations performed. + * Greater or equal to 1 if owned, 0 when free. + */ + volatile int32_t cNestings; + /** Section flags - the RTCRITSECT_FLAGS_* \#defines. */ + uint32_t fFlags; + /** The semaphore to block on. */ + RTSEMEVENT EventSem; + /** Lock validator record. Only used in strict builds. */ + R3R0PTRTYPE(PRTLOCKVALRECEXCL) pValidatorRec; + /** Alignment padding. */ + RTHCPTR Alignment; +} RTCRITSECT; +AssertCompileSize(RTCRITSECT, HC_ARCH_BITS == 32 ? 32 : 48); + +/** RTCRITSECT::u32Magic value. (Hiromi Uehara) */ +#define RTCRITSECT_MAGIC UINT32_C(0x19790326) + +/** @name RTCritSectInitEx flags / RTCRITSECT::fFlags + * @{ */ +/** If set, nesting(/recursion) is not allowed. */ +#define RTCRITSECT_FLAGS_NO_NESTING UINT32_C(0x00000001) +/** Disables lock validation. */ +#define RTCRITSECT_FLAGS_NO_LOCK_VAL UINT32_C(0x00000002) +/** Bootstrap hack for use with certain memory allocator locks only! */ +#define RTCRITSECT_FLAGS_BOOTSTRAP_HACK UINT32_C(0x00000004) +/** If set, the critical section becomes a dummy that doesn't serialize any + * threads. This flag can only be set at creation time. + * + * The intended use is avoiding lots of conditional code where some component + * might or might not require entering a critical section before access. */ +#define RTCRITSECT_FLAGS_NOP UINT32_C(0x00000008) +/** Indicates that this is a ring-0 critical section. */ +#define RTCRITSECT_FLAGS_RING0 UINT32_C(0x00000010) +/** @} */ + + +#if defined(IN_RING3) || defined(IN_RING0) + +/** + * Initialize a critical section. + */ +RTDECL(int) RTCritSectInit(PRTCRITSECT pCritSect); + +/** + * Initialize a critical section. + * + * @returns iprt status code. + * @param pCritSect Pointer to the critical section structure. + * @param fFlags Flags, any combination of the RTCRITSECT_FLAGS + * \#defines. + * @param hClass The class (no reference consumed). If NIL, no lock + * order validation will be performed on this lock. + * @param uSubClass The sub-class. This is used to define lock order + * within a class. RTLOCKVAL_SUB_CLASS_NONE is the + * recommended value here. + * @param pszNameFmt Name format string for the lock validator, optional + * (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTCritSectInitEx(PRTCRITSECT pCritSect, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(5, 6); + +/** + * Changes the lock validator sub-class of the critical section. + * + * It is recommended to try make sure that nobody is using this critical section + * while changing the value. + * + * @returns The old sub-class. RTLOCKVAL_SUB_CLASS_INVALID is returns if the + * lock validator isn't compiled in or either of the parameters are + * invalid. + * @param pCritSect The critical section. + * @param uSubClass The new sub-class value. + */ +RTDECL(uint32_t) RTCritSectSetSubClass(PRTCRITSECT pCritSect, uint32_t uSubClass); + +/** + * Enter a critical section. + * + * @returns VINF_SUCCESS on success. + * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * @param pCritSect The critical section. + */ +RTDECL(int) RTCritSectEnter(PRTCRITSECT pCritSect); + +/** + * Enter a critical section. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pCritSect The critical section. + * @param uId Where we're entering the section. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTCritSectEnterDebug(PRTCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Try enter a critical section. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pCritSect The critical section. + */ +RTDECL(int) RTCritSectTryEnter(PRTCRITSECT pCritSect); + +/** + * Try enter a critical section. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pCritSect The critical section. + * @param uId Where we're entering the section. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTCritSectTryEnterDebug(PRTCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +# ifdef IN_RING3 /* Crazy APIs: ring-3 only. */ + +/** + * Enter multiple critical sections. + * + * This function will enter ALL the specified critical sections before returning. + * + * @returns VINF_SUCCESS on success. + * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * @param cCritSects Number of critical sections in the array. + * @param papCritSects Array of critical section pointers. + * + * @remark Please note that this function will not necessarily come out favourable in a + * fight with other threads which are using the normal RTCritSectEnter() function. + * Therefore, avoid having to enter multiple critical sections! + */ +RTDECL(int) RTCritSectEnterMultiple(size_t cCritSects, PRTCRITSECT *papCritSects); + +/** + * Enter multiple critical sections. + * + * This function will enter ALL the specified critical sections before returning. + * + * @returns VINF_SUCCESS on success. + * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param cCritSects Number of critical sections in the array. + * @param papCritSects Array of critical section pointers. + * @param uId Where we're entering the section. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + * + * @remark See RTCritSectEnterMultiple(). + */ +RTDECL(int) RTCritSectEnterMultipleDebug(size_t cCritSects, PRTCRITSECT *papCritSects, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +# endif /* IN_RING3 */ + +/** + * Leave a critical section. + * + * @returns VINF_SUCCESS. + * @param pCritSect The critical section. + */ +RTDECL(int) RTCritSectLeave(PRTCRITSECT pCritSect); + +/** + * Leave multiple critical sections. + * + * @returns VINF_SUCCESS. + * @param cCritSects Number of critical sections in the array. + * @param papCritSects Array of critical section pointers. + */ +RTDECL(int) RTCritSectLeaveMultiple(size_t cCritSects, PRTCRITSECT *papCritSects); + +/** + * Deletes a critical section. + * + * @returns VINF_SUCCESS. + * @param pCritSect The critical section. + */ +RTDECL(int) RTCritSectDelete(PRTCRITSECT pCritSect); + +/** + * Checks the caller is the owner of the critical section. + * + * @returns true if owner. + * @returns false if not owner. + * @param pCritSect The critical section. + */ +DECLINLINE(bool) RTCritSectIsOwner(PCRTCRITSECT pCritSect) +{ + return pCritSect->NativeThreadOwner == RTThreadNativeSelf(); +} + +#endif /* IN_RING3 || IN_RING0 */ + +/** + * Checks the section is owned by anyone. + * + * @returns true if owned. + * @returns false if not owned. + * @param pCritSect The critical section. + */ +DECLINLINE(bool) RTCritSectIsOwned(PCRTCRITSECT pCritSect) +{ + return pCritSect->NativeThreadOwner != NIL_RTNATIVETHREAD; +} + +/** + * Gets the thread id of the critical section owner. + * + * @returns Thread id of the owner thread if owned. + * @returns NIL_RTNATIVETHREAD is not owned. + * @param pCritSect The critical section. + */ +DECLINLINE(RTNATIVETHREAD) RTCritSectGetOwner(PCRTCRITSECT pCritSect) +{ + return pCritSect->NativeThreadOwner; +} + +/** + * Checks if a critical section is initialized or not. + * + * @returns true if initialized. + * @returns false if not initialized. + * @param pCritSect The critical section. + */ +DECLINLINE(bool) RTCritSectIsInitialized(PCRTCRITSECT pCritSect) +{ + return pCritSect->u32Magic == RTCRITSECT_MAGIC; +} + +/** + * Gets the recursion depth. + * + * @returns The recursion depth. + * @param pCritSect The Critical section + */ +DECLINLINE(uint32_t) RTCritSectGetRecursion(PCRTCRITSECT pCritSect) +{ + return (uint32_t)pCritSect->cNestings; +} + +/** + * Gets the waiter count + * + * @returns The waiter count + * @param pCritSect The Critical section + */ +DECLINLINE(int32_t) RTCritSectGetWaiters(PCRTCRITSECT pCritSect) +{ + return pCritSect->cLockers; +} + +/* Lock strict build: Remap the three enter calls to the debug versions. */ +#if defined(RT_LOCK_STRICT) && !defined(RTCRITSECT_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) +# ifdef IPRT_INCLUDED_asm_h +# define RTCritSectEnter(pCritSect) RTCritSectEnterDebug(pCritSect, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTCritSectTryEnter(pCritSect) RTCritSectTryEnterDebug(pCritSect, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTCritSectEnterMultiple(cCritSects, pCritSect) RTCritSectEnterMultipleDebug((cCritSects), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define RTCritSectEnter(pCritSect) RTCritSectEnterDebug(pCritSect, 0, RT_SRC_POS) +# define RTCritSectTryEnter(pCritSect) RTCritSectTryEnterDebug(pCritSect, 0, RT_SRC_POS) +# define RTCritSectEnterMultiple(cCritSects, pCritSect) RTCritSectEnterMultipleDebug((cCritSects), (pCritSect), 0, RT_SRC_POS) +# endif +#endif + +/* Strict lock order: Automatically classify locks by init location. */ +#if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3) && !defined(RTCRITSECT_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) +# define RTCritSectInit(pCritSect) \ + RTCritSectInitEx((pCritSect), 0 /*fFlags*/, \ + RTLockValidatorClassForSrcPos(RT_SRC_POS, NULL), \ + RTLOCKVAL_SUB_CLASS_NONE, NULL) +#endif + +/** @} */ + + + +/** @defgroup grp_rt_critsectrw RTCritSectRw - Read/Write Critical Sections + * @ingroup grp_rt + * @{ + */ + +/** + * Union that allows us to atomically update both the state and + * exclusive owner if the hardware supports cmpxchg16b or similar. + */ +typedef union RTCRITSECTRWSTATE +{ + struct + { + /** The state variable. + * All accesses are atomic and it bits are defined like this: + * Bits 0..14 - cReads. + * Bit 15 - Unused. + * Bits 16..31 - cWrites. + * Bit 31 - fDirection; 0=Read, 1=Write. + * Bits 32..46 - cWaitingReads + * Bit 47 - Unused. + * Bits 48..62 - cWaitingWrites - doesn't make sense here, not used. + * Bit 63 - Unused. + */ + uint64_t u64State; + /** The write owner. */ + RTNATIVETHREAD hNativeWriter; + } s; + RTUINT128U u128; +} RTCRITSECTRWSTATE; + + +/** + * Read/write critical section. + */ +typedef struct RTCRITSECTRW +{ + /** Magic used to validate the section state. + * RTCRITSECTRW_MAGIC is the value of an initialized & operational section. */ + volatile uint32_t u32Magic; + + /** Indicates whether hEvtRead needs resetting. */ + bool volatile fNeedReset; + /** Explicit alignment padding. */ + bool volatile afPadding[1]; + /** Section flags - the RTCRITSECT_FLAGS_* \#defines. */ + uint16_t fFlags; + + /** The number of reads made by the current writer. */ + uint32_t volatile cWriterReads; + /** The number of recursions made by the current writer. (The initial grabbing + * of the lock counts as the first one.) */ + uint32_t volatile cWriteRecursions; + /** The core state. */ + RTCRITSECTRWSTATE volatile u; + + /** What the writer threads are blocking on. */ + RTSEMEVENT hEvtWrite; + /** What the read threads are blocking on when waiting for the writer to + * finish. */ + RTSEMEVENTMULTI hEvtRead; + + /** The validator record for the writer. */ + R3R0PTRTYPE(PRTLOCKVALRECEXCL) pValidatorWrite; + /** The validator record for the readers. */ + R3R0PTRTYPE(PRTLOCKVALRECSHRD) pValidatorRead; +} RTCRITSECTRW; +AssertCompileSize(RTCRITSECTRW, HC_ARCH_BITS == 32 ? 48 : 64); + +/** RTCRITSECTRW::u32Magic value. (Eric Allan Dolphy, Jr.) */ +#define RTCRITSECTRW_MAGIC UINT32_C(0x19280620) +/** RTCRITSECTRW::u32Magic dead value. */ +#define RTCRITSECTRW_MAGIC_DEAD UINT32_C(0x19640629) + +/** @name RTCRITSECTRW::u64State values. + * @note Using RTCSRW instead of RTCRITSECTRW to save space. + * @{ */ +#define RTCSRW_CNT_BITS 15 +#define RTCSRW_CNT_MASK UINT64_C(0x00007fff) + +#define RTCSRW_CNT_RD_SHIFT 0 +#define RTCSRW_CNT_RD_MASK (RTCSRW_CNT_MASK << RTCSRW_CNT_RD_SHIFT) +#define RTCSRW_CNT_WR_SHIFT 16 +#define RTCSRW_CNT_WR_MASK (RTCSRW_CNT_MASK << RTCSRW_CNT_WR_SHIFT) + +#define RTCSRW_DIR_SHIFT 31 +#define RTCSRW_DIR_MASK RT_BIT_64(RTCSRW_DIR_SHIFT) +#define RTCSRW_DIR_READ UINT64_C(0) +#define RTCSRW_DIR_WRITE UINT64_C(1) + +#define RTCSRW_WAIT_CNT_RD_SHIFT 32 +#define RTCSRW_WAIT_CNT_RD_MASK (RTCSRW_CNT_MASK << RTCSRW_WAIT_CNT_RD_SHIFT) +/* #define RTCSRW_WAIT_CNT_WR_SHIFT 48 */ +/* #define RTCSRW_WAIT_CNT_WR_MASK (RTCSRW_CNT_MASK << RTCSRW_WAIT_CNT_WR_SHIFT) */ +/** @} */ + +#if defined(IN_RING3) || defined(IN_RING0) + +/** + * Initialize a critical section. + */ +RTDECL(int) RTCritSectRwInit(PRTCRITSECTRW pThis); + +/** + * Initialize a critical section. + * + * @returns IPRT status code. + * @param pThis Pointer to the read/write critical section. + * @param fFlags Flags, any combination of the RTCRITSECT_FLAGS + * \#defines. + * @param hClass The class (no reference consumed). If NIL, no lock + * order validation will be performed on this lock. + * @param uSubClass The sub-class. This is used to define lock order + * within a class. RTLOCKVAL_SUB_CLASS_NONE is the + * recommended value here. + * @param pszNameFmt Name format string for the lock validator, optional + * (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTCritSectRwInitEx(PRTCRITSECTRW pThis, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(5, 6); + +/** + * Changes the lock validator sub-class of the critical section. + * + * It is recommended to try make sure that nobody is using this critical section + * while changing the value. + * + * @returns The old sub-class. RTLOCKVAL_SUB_CLASS_INVALID is returns if the + * lock validator isn't compiled in or either of the parameters are + * invalid. + * @param pThis Pointer to the read/write critical section. + * @param uSubClass The new sub-class value. + */ +RTDECL(uint32_t) RTCritSectRwSetSubClass(PRTCRITSECTRW pThis, uint32_t uSubClass); + + +/** + * Enter a critical section with shared (read) access. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(int) RTCritSectRwEnterShared(PRTCRITSECTRW pThis); + +/** + * Enter a critical section with shared (read) access. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pThis Pointer to the read/write critical section. + * @param uId Where we're entering the section. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTCritSectRwEnterSharedDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Try enter a critical section with shared (read) access. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(int) RTCritSectRwTryEnterShared(PRTCRITSECTRW pThis); + +/** + * Try enter a critical section with shared (read) access. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pThis Pointer to the read/write critical section. + * @param uId Where we're entering the section. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTCritSectRwTryEnterSharedDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Leave a critical section held with shared access. + * + * @returns IPRT status code. + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(int) RTCritSectRwLeaveShared(PRTCRITSECTRW pThis); + + +/** + * Enter a critical section with exclusive (write) access. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(int) RTCritSectRwEnterExcl(PRTCRITSECTRW pThis); + +/** + * Enter a critical section with exclusive (write) access. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pThis Pointer to the read/write critical section. + * @param uId Where we're entering the section. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTCritSectRwEnterExclDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Try enter a critical section with exclusive (write) access. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(int) RTCritSectRwTryEnterExcl(PRTCRITSECTRW pThis); + +/** + * Try enter a critical section with exclusive (write) access. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pThis Pointer to the read/write critical section. + * @param uId Where we're entering the section. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTCritSectRwTryEnterExclDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Leave a critical section held exclusively. + * + * @returns IPRT status code; VINF_SUCCESS, VERR_NOT_OWNER, VERR_SEM_DESTROYED, + * or VERR_WRONG_ORDER. + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(int) RTCritSectRwLeaveExcl(PRTCRITSECTRW pThis); + + +/** + * Deletes a critical section. + * + * @returns VINF_SUCCESS. + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(int) RTCritSectRwDelete(PRTCRITSECTRW pThis); + +/** + * Checks the caller is the exclusive (write) owner of the critical section. + * + * @retval true if owner. + * @retval false if not owner. + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(bool) RTCritSectRwIsWriteOwner(PRTCRITSECTRW pThis); + +/** + * Checks if the caller is one of the read owners of the critical section. + * + * @note !CAUTION! This API doesn't work reliably if lock validation isn't + * enabled. Meaning, the answer is not trustworhty unless + * RT_LOCK_STRICT or RTCRITSECTRW_STRICT was defined at build time. + * Also, make sure you do not use RTCRITSECTRW_FLAGS_NO_LOCK_VAL when + * creating the semaphore. And finally, if you used a locking class, + * don't disable deadlock detection by setting cMsMinDeadlock to + * RT_INDEFINITE_WAIT. + * + * In short, only use this for assertions. + * + * @returns @c true if reader, @c false if not. + * @param pThis Pointer to the read/write critical section. + * @param fWannaHear What you'd like to hear when lock validation is not + * available. (For avoiding asserting all over the + * place.) + */ +RTDECL(bool) RTCritSectRwIsReadOwner(PRTCRITSECTRW pThis, bool fWannaHear); + +/** + * Gets the write recursion count. + * + * @returns The write recursion count (0 if bad critsect). + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(uint32_t) RTCritSectRwGetWriteRecursion(PRTCRITSECTRW pThis); + +/** + * Gets the read recursion count of the current writer. + * + * @returns The read recursion count (0 if bad critsect). + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(uint32_t) RTCritSectRwGetWriterReadRecursion(PRTCRITSECTRW pThis); + +/** + * Gets the current number of reads. + * + * This includes all read recursions, so it might be higher than the number of + * read owners. It does not include reads done by the current writer. + * + * @returns The read count (0 if bad critsect). + * @param pThis Pointer to the read/write critical section. + */ +RTDECL(uint32_t) RTCritSectRwGetReadCount(PRTCRITSECTRW pThis); + +#endif /* IN_RING3 || IN_RING0 */ + +/** + * Checks if a critical section is initialized or not. + * + * @retval true if initialized. + * @retval false if not initialized. + * @param pThis Pointer to the read/write critical section. + */ +DECLINLINE(bool) RTCritSectRwIsInitialized(PCRTCRITSECTRW pThis) +{ + return pThis->u32Magic == RTCRITSECTRW_MAGIC; +} + +/* Lock strict build: Remap the three enter calls to the debug versions. */ +#if defined(RT_LOCK_STRICT) && !defined(RTCRITSECTRW_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) +# ifdef IPRT_INCLUDED_asm_h +# define RTCritSectRwEnterExcl(pThis) RTCritSectRwEnterExclDebug(pThis, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTCritSectRwTryEnterExcl(pThis) RTCritSectRwTryEnterExclDebug(pThis, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTCritSectRwEnterShared(pThis) RTCritSectRwEnterSharedDebug(pThis, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTCritSectRwTryEnterShared(pThis) RTCritSectRwTryEnterSharedDebug(pThis, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define RTCritSectRwEnterExcl(pThis) RTCritSectRwEnterExclDebug(pThis, 0, RT_SRC_POS) +# define RTCritSectRwTryEnterExcl(pThis) RTCritSectRwTryEnterExclDebug(pThis, 0, RT_SRC_POS) +# define RTCritSectRwEnterShared(pThis) RTCritSectRwEnterSharedDebug(pThis, 0, RT_SRC_POS) +# define RTCritSectRwTryEnterShared(pThis) RTCritSectRwTryEnterSharedDebug(pThis, 0, RT_SRC_POS) +# endif +#endif + +/* Strict lock order: Automatically classify locks by init location. */ +#if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3) && !defined(RTCRITSECTRW_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) +# define RTCritSectRwInit(a_pThis) \ + RTCritSectRwInitEx((a_pThis), 0 /*fFlags*/, \ + RTLockValidatorClassForSrcPos(RT_SRC_POS, NULL), \ + RTLOCKVAL_SUB_CLASS_NONE, NULL) +#endif + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_critsect_h */ + diff --git a/include/iprt/crypto/Makefile.kup b/include/iprt/crypto/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/iprt/crypto/Makefile.kup diff --git a/include/iprt/crypto/applecodesign.h b/include/iprt/crypto/applecodesign.h new file mode 100644 index 00000000..df546e06 --- /dev/null +++ b/include/iprt/crypto/applecodesign.h @@ -0,0 +1,290 @@ +/** @file + * IPRT - Apple Code Signing Structures and APIs. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_applecodesign_h +#define IPRT_INCLUDED_crypto_applecodesign_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> +#include <iprt/crypto/pkcs7.h> + +/** @defgroup grp_rt_craplcs RTCrAppleCs - Apple Code Signing + * @ingroup grp_rt_crypto + * @{ + */ + +/** Apple developer ID for iPhone application software development signing. */ +#define RTCR_APPLE_CS_DEVID_IPHONE_SW_DEV_OID "1.2.840.113635.100.6.1.2" +/** Apple developer ID for Mac application software development signing. */ +#define RTCR_APPLE_CS_DEVID_MAC_SW_DEV_OID "1.2.840.113635.100.6.1.12" +/** Apple developer ID for application signing. */ +#define RTCR_APPLE_CS_DEVID_APPLICATION_OID "1.2.840.113635.100.6.1.13" +/** Apple developer ID for installer signing. */ +#define RTCR_APPLE_CS_DEVID_INSTALLER_OID "1.2.840.113635.100.6.1.14" +/** Apple developer ID for kernel extension signing. */ +#define RTCR_APPLE_CS_DEVID_KEXT_OID "1.2.840.113635.100.6.1.18" +/** Apple certificate policy OID. */ +#define RTCR_APPLE_CS_CERTIFICATE_POLICY_OID "1.2.840.113635.100.5.1" + + +/** @name RTCRAPLCS_MAGIC_XXX - Apple code signing magic values for identifying blobs + * @note No byte order conversion required. + * @{ */ +#define RTCRAPLCS_MAGIC_BLOBWRAPPER RT_N2H_U32_C(UINT32_C(0xfade0b01)) +#define RTCRAPLCS_MAGIC_EMBEDDED_SIGNATURE_OLD RT_N2H_U32_C(UINT32_C(0xfade0b02)) +#define RTCRAPLCS_MAGIC_REQUIREMENT RT_N2H_U32_C(UINT32_C(0xfade0c00)) +#define RTCRAPLCS_MAGIC_REQUIREMENTS RT_N2H_U32_C(UINT32_C(0xfade0c01)) +#define RTCRAPLCS_MAGIC_CODEDIRECTORY RT_N2H_U32_C(UINT32_C(0xfade0c02)) +#define RTCRAPLCS_MAGIC_EMBEDDED_SIGNATURE RT_N2H_U32_C(UINT32_C(0xfade0cc0)) +#define RTCRAPLCS_MAGIC_DETACHED_SIGNATURE RT_N2H_U32_C(UINT32_C(0xfade0cc1)) +/** @} */ + +/** @name Apple code signing versions. + * @note Requires byte order conversion of the field value. That way + * greater-than and less-than comparisons works correctly. + * @{ */ +#define RTCRAPLCS_VER_2_0 UINT32_C(0x00020000) +#define RTCRAPLCS_VER_SUPPORTS_SCATTER UINT32_C(0x00020100) +#define RTCRAPLCS_VER_SUPPORTS_TEAMID UINT32_C(0x00020200) +#define RTCRAPLCS_VER_SUPPORTS_CODE_LIMIT_64 UINT32_C(0x00020300) +#define RTCRAPLCS_VER_SUPPORTS_EXEC_SEG UINT32_C(0x00020400) +/** @} */ + +/** @name RTCRAPLCS_SLOT_XXX - Apple code signing slots. + * @note No byte order conversion required. + * @{ */ +#define RTCRAPLCS_SLOT_CODEDIRECTORY RT_N2H_U32_C(UINT32_C(0x00000000)) +#define RTCRAPLCS_SLOT_INFO RT_N2H_U32_C(UINT32_C(0x00000001)) +#define RTCRAPLCS_SLOT_REQUIREMENTS RT_N2H_U32_C(UINT32_C(0x00000002)) +#define RTCRAPLCS_SLOT_RESOURCEDIR RT_N2H_U32_C(UINT32_C(0x00000003)) +#define RTCRAPLCS_SLOT_APPLICATION RT_N2H_U32_C(UINT32_C(0x00000004)) +#define RTCRAPLCS_SLOT_ENTITLEMENTS RT_N2H_U32_C(UINT32_C(0x00000005)) +#define RTCRAPLCS_SLOT_ALTERNATE_CODEDIRECTORIES RT_N2H_U32_C(UINT32_C(0x00001000)) +#define RTCRAPLCS_SLOT_ALTERNATE_CODEDIRECTORIES_END RT_N2H_U32_C(UINT32_C(0x00001005)) +#define RTCRAPLCS_SLOT_ALTERNATE_CODEDIRECTORIES_COUNT UINT32_C(0x00000005) +#define RTCRAPLCS_SLOT_ALTERNATE_CODEDIRECTORY_INC RT_N2H_U32_C(UINT32_C(0x00000001)) +/** The signature. + * This is simply a RTCRAPLCSHDR/RTCRAPLCS_MAGIC_BLOBWRAPPER followed by a DER + * encoded \#PKCS7 ContentInfo structure containing signedData. The inner + * signedData structure signs external data, so its ContentInfo member is set + * to 1.2.840.113549.1.7.1 and has no data. */ +#define RTCRAPLCS_SLOT_SIGNATURE RT_N2H_U32_C(UINT32_C(0x00010000)) +/** @} */ + +/** @name RTCRAPLCS_HASHTYPE_XXX - Apple code signing hash types + * @note Byte sized field, so no byte order concerns. + * @{ */ +#define RTCRAPLCS_HASHTYPE_SHA1 UINT8_C(1) +#define RTCRAPLCS_HASHTYPE_SHA256 UINT8_C(2) +#define RTCRAPLCS_HASHTYPE_SHA256_TRUNCATED UINT8_C(3) /**< Truncated to 20 bytes (SHA1 size). */ +#define RTCRAPLCS_HASHTYPE_SHA384 UINT8_C(4) +/** @} */ + + +/** + * Apple code signing blob header. + */ +typedef struct RTCRAPLCSHDR +{ + /** The magic value (RTCRAPLCS_MAGIC_XXX). + * (Big endian, but constant are big endian already.) */ + uint32_t uMagic; + /** The total length of the blob. Big endian. */ + uint32_t cb; +} RTCRAPLCSHDR; +AssertCompileSize(RTCRAPLCSHDR, 8); +/** Pointer to a CS blob header. */ +typedef RTCRAPLCSHDR *PRTCRAPLCSHDR; +/** Pointer to a const CS blob header. */ +typedef RTCRAPLCSHDR const *PCRTCRAPLCSHDR; + +/** + * Apple code signing super blob slot. + */ +typedef struct RTCRAPLCSBLOBSLOT +{ + /** Slot type, RTCRAPLCS_SLOT_XXX. + * (Big endian, but so are the constants too). */ + uint32_t uType; + /** Data offset. Big endian. */ + uint32_t offData; +} RTCRAPLCSBLOBSLOT; +AssertCompileSize(RTCRAPLCSBLOBSLOT, 8); +/** Pointer to a super blob slot. */ +typedef RTCRAPLCSBLOBSLOT *PRTCRAPLCSBLOBSLOT; +/** Pointer to a const super blob slot. */ +typedef RTCRAPLCSBLOBSLOT const *PCRTCRAPLCSBLOBSLOT; + +/** + * Apple code signing super blob. + */ +typedef struct RTCRAPLCSSUPERBLOB +{ + /** Header (uMagic = RTCRAPLCS_MAGIC_EMBEDDED_SIGNATURE? + * or RTCRAPLCS_MAGIC_EMBEDDED_SIGNATURE_OLD? ). */ + RTCRAPLCSHDR Hdr; + /** Number of slots. Big endian. */ + uint32_t cSlots; + /** Slots. */ + RT_FLEXIBLE_ARRAY_EXTENSION + RTCRAPLCSBLOBSLOT aSlots[RT_FLEXIBLE_ARRAY]; +} RTCRAPLCSSUPERBLOB; +AssertCompileMemberOffset(RTCRAPLCSSUPERBLOB, aSlots, 12); +/** Pointer to a CS super blob. */ +typedef RTCRAPLCSSUPERBLOB *PRTCRAPLCSSUPERBLOB; +/** Pointer to a const CS super blob. */ +typedef RTCRAPLCSSUPERBLOB const *PCRTCRAPLCSSUPERBLOB; + +/** + * Code directory (RTCRAPLCS_MAGIC_CODEDIRECTORY). + */ +typedef struct RTCRAPLCSCODEDIRECTORY +{ + /** 0x00: Header (uMagic = RTCRAPLCS_MAGIC_CODEDIRECTORY). */ + RTCRAPLCSHDR Hdr; + /** 0x08: The version number (RTCRAPLCS_VER_XXX). + * @note Big endian, host order constants. */ + uint32_t uVersion; + /** 0x0c: Flags & mode, RTCRAPLCS_???. (Big endian. ) */ + uint32_t fFlags; + /** 0x10: Offset of the hash slots. Big endian. + * Special slots found below this offset, code slots at and after. */ + uint32_t offHashSlots; + /** 0x14: Offset of the identifier string. Big endian. */ + uint32_t offIdentifier; + /** 0x18: Number of special hash slots. Hubertus Bigend style. */ + uint32_t cSpecialSlots; + /** 0x1c: Number of code hash slots. Big endian. */ + uint32_t cCodeSlots; + /** 0x20: Number of bytes of code that's covered, 32-bit wide. Big endian. */ + uint32_t cbCodeLimit32; + /** 0x24: The hash size. */ + uint8_t cbHash; + /** 0x25: The hash type (RTCRAPLCS_HASHTYPE_XXX). */ + uint8_t bHashType; + /** 0x26: Platform identifier or zero. */ + uint8_t idPlatform; + /** 0x27: The page shift value. zero if infinite page size. */ + uint8_t cPageShift; + /** 0x28: Spare field, MBZ. */ + uint32_t uUnused1; + /** 0x2c: Offset of scatter vector (optional). Big endian. + * @since RTCRAPLCS_VER_SUPPORTS_SCATTER */ + uint32_t offScatter; + /** 0x30: Offset of team identifier (optional). Big endian. + * @since RTCRAPLCS_VER_SUPPORTS_TEAMID */ + uint32_t offTeamId; + /** 0x34: Unused field, MBZ. + * @since RTCRAPLCS_VER_SUPPORTS_CODE_LIMIT_64 */ + uint32_t uUnused2; + /** 0x38: Number of bytes of code that's covered, 64-bit wide. Big endian. + * @since RTCRAPLCS_VER_SUPPORTS_CODE_LIMIT_64 */ + uint64_t cbCodeLimit64; + /** 0x40: File offset of the first segment. Big endian. + * @since RTCRAPLCS_VER_SUPPORTS_EXEC_SEG */ + uint64_t offExecSeg; + /** 0x48: The size of the first segment. Big endian. + * @since RTCRAPLCS_VER_SUPPORTS_EXEC_SEG */ + uint64_t cbExecSeg; + /** 0x50: Flags for the first segment. Big endian. + * @since RTCRAPLCS_VER_SUPPORTS_EXEC_SEG */ + uint64_t fExecSeg; +} RTCRAPLCSCODEDIRECTORY; +AssertCompileSize(RTCRAPLCSCODEDIRECTORY, 0x58); +/** Pointer to a CS code directory. */ +typedef RTCRAPLCSCODEDIRECTORY *PRTCRAPLCSCODEDIRECTORY; +/** Pointer to a const CS code directory. */ +typedef RTCRAPLCSCODEDIRECTORY const *PCRTCRAPLCSCODEDIRECTORY; + + +/** + * IPRT structure for working with an Apple code signing blob. + */ +typedef struct RTCRAPLCS +{ + uint8_t const *pbBlob; + size_t cbBlob; + size_t auReserved[4]; +} RTCRAPLCS; +/** Pointer to an IPRT CS blob descriptor. */ +typedef RTCRAPLCS *PRTCRAPLCS; + +/** + * Initialize a RTCRAPLCS descriptor and validate the blob data. + * + * @returns IPRT status code. + * @param pDesc The descirptor to initialize. + * @param pvBlob The blob bytes. + * @param cbBlob The number of bytes in the blob. + * @param fFlags Future validation flags, MBZ. + * @param pErrInfo Where to return additional error details. Optional. + */ +RTDECL(int) RTCrAppleCsInit(PRTCRAPLCS pDesc, void const *pvBlob, size_t cbBlob, uint32_t fFlags, PRTERRINFO pErrInfo); + +/** + * Callback used by RTCrAppleCsVerifyImage to digest a section of the image. + * + * @return IPRT status code. + * @param hDigest The digest to feed the bytes to. + * @param off The RVA of the bytes to digest. + * @param cb Number of bytes to digest. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTCRAPPLECSDIGESTAREA,(RTCRDIGEST hDigest, size_t off, size_t cb, void *pvUser)); +/** Pointer to a image digest callback. */ +typedef FNRTCRAPPLECSDIGESTAREA *PFNRTCRAPPLECSDIGESTAREA; + +/** + * Verifies an image against the given signature blob. + * + * @return IPRT status code. + * @param pDesc The apple code signing blob to verify against. + * @param fFlags Future verification flags, MBZ. + * @param pfnCallback Image digest callback. + * @param pvUser User argument for the callback. + * @param pErrInfo Where to return additional error details. Optional. + */ +RTDECL(int) RTCrAppleCsVerifyImage(PRTCRAPLCS pDesc, uint32_t fFlags, PFNRTCRAPPLECSDIGESTAREA pfnCallback, + void *pvUser, PRTERRINFO pErrInfo); + +RTDECL(int) RTCrAppleCsQuerySigneddData(PRTCRAPLCS pDesc, PRTCRPKCS7SIGNEDDATA pSignedData, PRTERRINFO pErrInfo); + +/** @} */ + +#endif /* !IPRT_INCLUDED_crypto_applecodesign_h */ + diff --git a/include/iprt/crypto/cipher.h b/include/iprt/crypto/cipher.h new file mode 100644 index 00000000..9fb3cd02 --- /dev/null +++ b/include/iprt/crypto/cipher.h @@ -0,0 +1,156 @@ +/** @file + * IPRT - Crypto - Symmetric Ciphers. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_cipher_h +#define IPRT_INCLUDED_crypto_cipher_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/asn1.h> + + +RT_C_DECLS_BEGIN + +struct RTCRX509SUBJECTPUBLICKEYINFO; + +/** @defgroup grp_rt_crcipher RTCrCipher - Symmetric Ciphers + * @ingroup grp_rt_crypto + * @{ + */ + +/** + * A symmetric cipher handle. + * + * @remarks In OpenSSL terms this corresponds to a EVP_CIPHER, while in Microsoft + * terms it is an algorithm handle. The latter is why a handle was + * choosen rather than constant descriptor structure pointer. */ +typedef struct RTCRCIPHERINT *RTCRCIPHER; +/** Pointer to a symmetric cipher handle. */ +typedef RTCRCIPHER *PRTCRCIPHER; +/** Nil symmetric cipher handle. */ +#define NIL_RTCRCIPHER ((RTCRCIPHER)0) +/** Symmetric cipher context */ +typedef struct RTCRCIPHERCTXINT *RTCRCIPHERCTX; +/** Pointer to a symmetric cipher context */ +typedef RTCRCIPHERCTX *PRTCRCIPHERCTX; +/** Nil symmetric cipher context */ +#define NIL_RTCRCIPHERCTX ((RTCRCIPHERCTX)0) + +/** + * Symmetric cipher types. + * + * @note Only add new types at the end, existing values must be stable. + */ +typedef enum RTCRCIPHERTYPE +{ + /** Invalid zero value. */ + RTCRCIPHERTYPE_INVALID = 0, + /** XTS-AES-128 (NIST SP 800-38E). */ + RTCRCIPHERTYPE_XTS_AES_128, + /** XTS-AES-256 (NIST SP 800-38E). */ + RTCRCIPHERTYPE_XTS_AES_256, + /** GCM-AES-128. */ + RTCRCIPHERTYPE_GCM_AES_128, + /** GCM-AES-256. */ + RTCRCIPHERTYPE_GCM_AES_256, + /* CTR-AES-128 */ + RTCRCIPHERTYPE_CTR_AES_128, + /* CTR-AES-256 */ + RTCRCIPHERTYPE_CTR_AES_256, + /** End of valid symmetric cipher types. */ + RTCRCIPHERTYPE_END, + /** Make sure the type is a 32-bit one. */ + RTCRCIPHERTYPE_32BIT_HACK = 0x7fffffff +} RTCRCIPHERTYPE; + + +RTDECL(int) RTCrCipherOpenByType(PRTCRCIPHER phCipher, RTCRCIPHERTYPE enmType, uint32_t fFlags); +RTDECL(uint32_t) RTCrCipherRetain(RTCRCIPHER hCipher); +RTDECL(uint32_t) RTCrCipherRelease(RTCRCIPHER hCipher); +RTDECL(uint32_t) RTCrCipherGetKeyLength(RTCRCIPHER hCipher); +RTDECL(uint32_t) RTCrCipherGetInitializationVectorLength(RTCRCIPHER hCipher); +RTDECL(uint32_t) RTCrCipherGetBlockSize(RTCRCIPHER hCipher); + +RTDECL(int) RTCrCipherCtxFree(RTCRCIPHERCTX phCipherCtx); + +RTDECL(int) RTCrCipherCtxEncryptInit(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvAuthData, size_t cbAuthData, + PRTCRCIPHERCTX phCipherCtx); +RTDECL(int) RTCrCipherCtxEncryptProcess(RTCRCIPHERCTX hCipherCtx, void const *pvPlainText, size_t cbPlainText, + void *pvEncrypted, size_t cbEncrypted, size_t *pcbEncrypted); +RTDECL(int) RTCrCipherCtxEncryptFinish(RTCRCIPHERCTX hCipherCtx, + void *pvEncrypted, size_t *pcbEncrypted, + void *pvTag, size_t cbTag, size_t *pcbTag); + +RTDECL(int) RTCrCipherCtxDecryptInit(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvAuthData, size_t cbAuthData, + void *pvTag, size_t cbTag, PRTCRCIPHERCTX phCipherCtx); +RTDECL(int) RTCrCipherCtxDecryptProcess(RTCRCIPHERCTX hCipherCtx, + void const *pvEncrypted, size_t cbEncrypted, + void *pvPlainText, size_t cbPlainText, size_t *pcbPlainText); +RTDECL(int) RTCrCipherCtxDecryptFinish(RTCRCIPHERCTX hCipherCtx, + void *pvPlainText, size_t *pcbPlainText); + + +RTDECL(int) RTCrCipherEncrypt(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvPlainText, size_t cbPlainText, + void *pvEncrypted, size_t cbEncrypted, size_t *pcbEncrypted); +RTDECL(int) RTCrCipherDecrypt(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvEncrypted, size_t cbEncrypted, + void *pvPlainText, size_t cbPlainText, size_t *pcbPlainText); +RTDECL(int) RTCrCipherEncryptEx(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvAuthData, size_t cbAuthData, + void const *pvPlainText, size_t cbPlainText, + void *pvEncrypted, size_t cbEncrypted, size_t *pcbEncrypted, + void *pvTag, size_t cbTag, size_t *pcbTag); +RTDECL(int) RTCrCipherDecryptEx(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvAuthData, size_t cbAuthData, + void *pvTag, size_t cbTag, + void const *pvEncrypted, size_t cbEncrypted, + void *pvPlainText, size_t cbPlainText, size_t *pcbPlainText); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_cipher_h */ + diff --git a/include/iprt/crypto/digest.h b/include/iprt/crypto/digest.h new file mode 100644 index 00000000..bdf3698a --- /dev/null +++ b/include/iprt/crypto/digest.h @@ -0,0 +1,331 @@ +/** @file + * IPRT - Crypto - Cryptographic Hash / Message Digest. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_digest_h +#define IPRT_INCLUDED_crypto_digest_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/asn1.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_crdigest RTCrDigest - Crypographic Hash / Message Digest API. + * @ingroup grp_rt + * @{ + */ + +/** + * Cryptographic hash / message digest provider descriptor. + * + * This gives the basic details and identifiers of the algorithm as well as + * function pointers to the implementation. + */ +typedef struct RTCRDIGESTDESC +{ + /** The message digest provider name. */ + const char *pszName; + /** The object ID string. */ + const char *pszObjId; + /** Pointer to a NULL terminated table of alias object IDs (optional). */ + const char * const *papszObjIdAliases; + /** The IPRT digest type. */ + RTDIGESTTYPE enmType; + /** The max size of the final hash (binary). */ + uint32_t cbHash; + /** The size of the state. */ + uint32_t cbState; + /** Flags, RTCRDIGESTDESC_F_XXX. */ + uint32_t fFlags; + + /** + * Allocates the digest data. + */ + DECLCALLBACKMEMBER(void *, pfnNew,(void)); + + /** + * Frees the digest data. + * + * @param pvState The opaque message digest state. + */ + DECLCALLBACKMEMBER(void, pfnFree,(void *pvState)); + + /** + * Updates the digest with more data. + * + * @param pvState The opaque message digest state. + * @param pvData The data to add to the digest. + * @param cbData The amount of data to add to the digest. + */ + DECLCALLBACKMEMBER(void, pfnUpdate,(void *pvState, const void *pvData, size_t cbData)); + + /** + * Finalizes the digest calculation. + * + * @param pvState The opaque message digest state. + * @param pbHash Where to store the output digest. This buffer is at + * least RTCRDIGESTDESC::cbHash bytes large. + */ + DECLCALLBACKMEMBER(void, pfnFinal,(void *pvState, uint8_t *pbHash)); + + /** + * (Re-)Initializes the digest. Optional. + * + * Optional, RT_BZERO will be used if NULL. + * + * @returns IPRT status code. + * @param pvState The opaque message digest state. + * @param pvOpaque Opaque algortihm specific parameter. + * @param fReInit Set if this is a re-init call. + */ + DECLCALLBACKMEMBER(int, pfnInit,(void *pvState, void *pvOpaque, bool fReInit)); + + /** + * Deletes the message digest state. + * + * Optional, memset will be used if NULL. + * + * @param pvState The opaque message digest state. + */ + DECLCALLBACKMEMBER(void, pfnDelete,(void *pvState)); + + /** + * Clones the message digest state. + * + * Optional, memcpy will be used if NULL. + * + * @returns IPRT status code. + * @param pvState The opaque message digest state (destination). + * @param pvSrcState The opaque message digest state to clone (source). + */ + DECLCALLBACKMEMBER(int, pfnClone,(void *pvState, void const *pvSrcState)); + + /** + * Gets the hash size. + * + * Optional, if not provided RTCRDIGESTDESC::cbHash will be returned. If + * provided though, RTCRDIGESTDESC::cbHash must be set to the largest possible + * hash size. + * + * @returns The hash size. + * @param pvState The opaque message digest state. + */ + DECLCALLBACKMEMBER(uint32_t, pfnGetHashSize,(void *pvState)); + + /** + * Gets the digest type (when enmType is RTDIGESTTYPE_UNKNOWN). + * + * @returns The hash size. + * @param pvState The opaque message digest state. + */ + DECLCALLBACKMEMBER(RTDIGESTTYPE, pfnGetDigestType,(void *pvState)); +} RTCRDIGESTDESC; +/** Pointer to const message digest details and vtable. */ +typedef RTCRDIGESTDESC const *PCRTCRDIGESTDESC; + +/** @name RTCRDIGESTDESC_F_XXX + * @{ */ +/** Digest is deprecated. */ +#define RTCRDIGESTDESC_F_DEPRECATED RT_BIT_32(0) +/** Digest is compromised. */ +#define RTCRDIGESTDESC_F_COMPROMISED RT_BIT_32(1) +/** Digest is severely compromised. */ +#define RTCRDIGESTDESC_F_SERVERELY_COMPROMISED RT_BIT_32(2) +/** @} */ + +/** + * Finds a cryptographic hash / message digest descriptor by object identifier + * string. + * + * @returns Pointer to the message digest details & vtable if found. NULL if + * not found. + * @param pszObjId The dotted object identifier string of the message + * digest algorithm. + * @param ppvOpaque Where to return an opaque implementation specfici + * sub-type indicator that can be passed to + * RTCrDigestCreate. This is optional, fewer + * algortihms are available if not specified. + */ +RTDECL(PCRTCRDIGESTDESC) RTCrDigestFindByObjIdString(const char *pszObjId, void **ppvOpaque); + +/** + * Finds a cryptographic hash / message digest descriptor by object identifier + * ASN.1 object. + * + * @returns Pointer to the message digest details & vtable if found. NULL if + * not found. + * @param pObjId The ASN.1 object ID of the message digest algorithm. + * @param ppvOpaque Where to return an opaque implementation specfici + * sub-type indicator that can be passed to + * RTCrDigestCreate. This is optional, fewer + * algortihms are available if not specified. + */ +RTDECL(PCRTCRDIGESTDESC) RTCrDigestFindByObjId(PCRTASN1OBJID pObjId, void **ppvOpaque); + +RTDECL(PCRTCRDIGESTDESC) RTCrDigestFindByType(RTDIGESTTYPE enmDigestType); +RTDECL(int) RTCrDigestCreateByObjIdString(PRTCRDIGEST phDigest, const char *pszObjId); +RTDECL(int) RTCrDigestCreateByObjId(PRTCRDIGEST phDigest, PCRTASN1OBJID pObjId); +RTDECL(int) RTCrDigestCreateByType(PRTCRDIGEST phDigest, RTDIGESTTYPE enmDigestType); + + +/** + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VINF_CR_DIGEST_DEPRECATED on success from a deprecated hash algorithm. + * @retval VINF_CR_DIGEST_COMPROMISED on success from a compromised hash algorithm. + * @retval VINF_CR_DIGEST_SEVERELY_COMPROMISED on success from a severely compromised hash algorithm. + */ +RTDECL(int) RTCrDigestCreate(PRTCRDIGEST phDigest, PCRTCRDIGESTDESC pDesc, void *pvOpaque); +/** + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VINF_CR_DIGEST_DEPRECATED on success from a deprecated hash algorithm. + * @retval VINF_CR_DIGEST_COMPROMISED on success from a compromised hash algorithm. + * @retval VINF_CR_DIGEST_SEVERELY_COMPROMISED on success from a severely compromised hash algorithm. + */ +RTDECL(int) RTCrDigestClone(PRTCRDIGEST phDigest, RTCRDIGEST hSrc); +/** + * Resets the digest to start calculating a new digest. + */ +RTDECL(int) RTCrDigestReset(RTCRDIGEST hDigest); + +/** + * Retains a references to the digest. + * + * @returns New reference count. UINT32_MAX if invalid handle. + * @param hDigest Handle to the digest. + */ +RTDECL(uint32_t) RTCrDigestRetain(RTCRDIGEST hDigest); +/** + * Releases a references to the digest. + * + * @returns New reference count. UINT32_MAX if invalid handle. + * @param hDigest Handle to the digest. NIL is ignored (returns 0). + */ +RTDECL(uint32_t) RTCrDigestRelease(RTCRDIGEST hDigest); + +/** + * Updates the digest with more message data. + * + * @returns IPRT status code. + * @param hDigest Handle to the digest. + * @param pvData Pointer to the message data. + * @param cbData The number of bytes of data @a pvData points to. + */ +RTDECL(int) RTCrDigestUpdate(RTCRDIGEST hDigest, void const *pvData, size_t cbData); + +/** + * Updates the digest with more message data from the given VFS file handle. + * + * @returns IPRT status code. + * @param hDigest Handle to the digest. + * @param hVfsFile Handle to the VFS file. + * @param fRewindFile Rewind to the start of the file if @a true, start + * consumption at the current file position if @a false. + */ +RTDECL(int) RTCrDigestUpdateFromVfsFile(RTCRDIGEST hDigest, RTVFSFILE hVfsFile, bool fRewindFile); + +/** + * Finalizes the hash calculation, copying out the resulting hash value. + * + * This can be called more than once and will always return the same result. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VINF_CR_DIGEST_DEPRECATED on success from a deprecated hash algorithm. + * @retval VINF_CR_DIGEST_COMPROMISED on success from a compromised hash algorithm. + * @retval VINF_CR_DIGEST_SEVERELY_COMPROMISED on success from a severely compromised hash algorithm. + * @retval VINF_BUFFER_UNDERFLOW if the supplied buffer is too big. + * @retval VERR_BUFFER_OVERFLOW if the supplied buffer is too small. + * @retval VERR_INVALID_STATE if there is nothing to finalize. + * + * @param hDigest The digest handle. + * @param pvHash Where to return the hash. Optional. + * @param cbHash The hash size. Optional. + */ +RTDECL(int) RTCrDigestFinal(RTCRDIGEST hDigest, void *pvHash, size_t cbHash); + +RTDECL(bool) RTCrDigestMatch(RTCRDIGEST hDigest, void const *pvHash, size_t cbHash); +RTDECL(uint8_t const *) RTCrDigestGetHash(RTCRDIGEST hDigest); +RTDECL(uint32_t) RTCrDigestGetHashSize(RTCRDIGEST hDigest); +RTDECL(uint64_t) RTCrDigestGetConsumedSize(RTCRDIGEST hDigest); +RTDECL(bool) RTCrDigestIsFinalized(RTCRDIGEST hDigest); +RTDECL(RTDIGESTTYPE) RTCrDigestGetType(RTCRDIGEST hDigest); +RTDECL(const char *) RTCrDigestGetAlgorithmOid(RTCRDIGEST hDigest); + +/** + * Gets the flags for the algorithm. + * + * @returns RTCRDIGESTDESC_F_XXX, UINT32_MAX on invalid handle. + * @param hDigest The digest handle. + */ +RTDECL(uint32_t) RTCrDigestGetFlags(RTCRDIGEST hDigest); + + +/** + * Translates an IPRT digest type value to an OID. + * + * @returns Dotted OID string on success, NULL if not translatable. + * @param enmDigestType The IPRT digest type value to convert. + */ +RTDECL(const char *) RTCrDigestTypeToAlgorithmOid(RTDIGESTTYPE enmDigestType); + +/** + * Translates an IPRT digest type value to a name/descriptive string. + * + * The purpose here is for human readable output rather than machine readable + * output, i.e. the names aren't set in stone. + * + * @returns Pointer to read-only string, NULL if unknown type. + * @param enmDigestType The IPRT digest type value to convert. + */ +RTDECL(const char *) RTCrDigestTypeToName(RTDIGESTTYPE enmDigestType); + +/** + * Translates an IPRT digest type value to a hash size. + * + * @returns Hash size (in bytes). + * @param enmDigestType The IPRT digest type value to convert. + */ +RTDECL(uint32_t) RTCrDigestTypeToHashSize(RTDIGESTTYPE enmDigestType); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_digest_h */ + diff --git a/include/iprt/crypto/key.h b/include/iprt/crypto/key.h new file mode 100644 index 00000000..a58d8ee6 --- /dev/null +++ b/include/iprt/crypto/key.h @@ -0,0 +1,126 @@ +/** @file + * IPRT - Cryptographic Keys + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_key_h +#define IPRT_INCLUDED_crypto_key_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/crypto/x509.h> +#include <iprt/crypto/taf.h> +#include <iprt/sha.h> + + +RT_C_DECLS_BEGIN + +struct RTCRPEMSECTION; +struct RTCRX509SUBJECTPUBLICKEYINFO; + +/** @defgroup grp_rt_crkey RTCrKey - Crypotgraphic Keys. + * @ingroup grp_rt_crypto + * @{ + */ + +/** + * Key types. + */ +typedef enum RTCRKEYTYPE +{ + /** Invalid zero value. */ + RTCRKEYTYPE_INVALID = 0, + /** RSA private key. */ + RTCRKEYTYPE_RSA_PRIVATE, + /** RSA public key. */ + RTCRKEYTYPE_RSA_PUBLIC, + /** End of key types. */ + RTCRKEYTYPE_END, + /** The usual type size hack. */ + RTCRKEYTYPE_32BIT_HACK = 0x7fffffff +} RTCRKEYTYPE; + + +RTDECL(int) RTCrKeyCreateFromSubjectPublicKeyInfo(PRTCRKEY phKey, struct RTCRX509SUBJECTPUBLICKEYINFO const *pSrc, + PRTERRINFO pErrInfo, const char *pszErrorTag); +RTDECL(int) RTCrKeyCreateFromPublicAlgorithmAndBits(PRTCRKEY phKey, PCRTASN1OBJID pAlgorithm, + PCRTASN1BITSTRING pPublicKey, + PRTERRINFO pErrInfo, const char *pszErrorTag); +RTDECL(int) RTCrKeyCreateFromPemSection(PRTCRKEY phKey, uint32_t fFlags, struct RTCRPEMSECTION const *pSection, + const char *pszPassword, PRTERRINFO pErrInfo, const char *pszErrorTag); +RTDECL(int) RTCrKeyCreateFromBuffer(PRTCRKEY phKey, uint32_t fFlags, void const *pvSrc, size_t cbSrc, + const char *pszPassword, PRTERRINFO pErrInfo, const char *pszErrorTag); +RTDECL(int) RTCrKeyCreateFromFile(PRTCRKEY phKey, uint32_t fFlags, const char *pszFilename, + const char *pszPassword, PRTERRINFO pErrInfo); +/** @todo add support for decrypting private keys. */ +/** @name RTCRKEYFROM_F_XXX + * @{ */ +/** Only PEM sections, no binary fallback. + * @sa RTCRPEMREADFILE_F_ONLY_PEM */ +#define RTCRKEYFROM_F_ONLY_PEM RT_BIT(1) +/** Valid flags. */ +#define RTCRKEYFROM_F_VALID_MASK UINT32_C(0x00000002) +/** @} */ + +RTDECL(int) RTCrKeyCreateNewRsa(PRTCRKEY phKey, uint32_t cBits, uint32_t uPubExp, uint32_t fFlags); + + +RTDECL(uint32_t) RTCrKeyRetain(RTCRKEY hKey); +RTDECL(uint32_t) RTCrKeyRelease(RTCRKEY hKey); +RTDECL(RTCRKEYTYPE) RTCrKeyGetType(RTCRKEY hKey); +RTDECL(bool) RTCrKeyHasPrivatePart(RTCRKEY hKey); +RTDECL(bool) RTCrKeyHasPublicPart(RTCRKEY hKey); +RTDECL(uint32_t) RTCrKeyGetBitCount(RTCRKEY hKey); +RTDECL(int) RTCrKeyQueryRsaModulus(RTCRKEY hKey, PRTBIGNUM pModulus); +RTDECL(int) RTCrKeyQueryRsaPrivateExponent(RTCRKEY hKey, PRTBIGNUM pPrivateExponent); + +/** Public key markers. */ +extern RT_DECL_DATA_CONST(RTCRPEMMARKER const) g_aRTCrKeyPublicMarkers[]; +/** Number of entries in g_aRTCrKeyPublicMarkers. */ +extern RT_DECL_DATA_CONST(uint32_t const) g_cRTCrKeyPublicMarkers; +/** Private key markers. */ +extern RT_DECL_DATA_CONST(RTCRPEMMARKER const) g_aRTCrKeyPrivateMarkers[]; +/** Number of entries in g_aRTCrKeyPrivateMarkers. */ +extern RT_DECL_DATA_CONST(uint32_t const) g_cRTCrKeyPrivateMarkers; +/** Private and public key markers. */ +extern RT_DECL_DATA_CONST(RTCRPEMMARKER const) g_aRTCrKeyAllMarkers[]; +/** Number of entries in g_aRTCrKeyAllMarkers. */ +extern RT_DECL_DATA_CONST(uint32_t const) g_cRTCrKeyAllMarkers; + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_key_h */ + diff --git a/include/iprt/crypto/misc.h b/include/iprt/crypto/misc.h new file mode 100644 index 00000000..bc4419fd --- /dev/null +++ b/include/iprt/crypto/misc.h @@ -0,0 +1,76 @@ +/** @file + * IPRT - Crypto - Miscellaneous. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_misc_h +#define IPRT_INCLUDED_crypto_misc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_crmisc RTCrMisc - Miscellaneous + * @ingroup grp_rt_crypto + * @{ + */ + +/** + * Get cryptographically strong random bytes. + * + * The buffer will always be filled with random bytes, however only + * on @c VINF_SUCCESS is it guaranteed to be strong random bytes. + * + * @retval VINF_SUCCESS + * @retval VERR_CR_RANDOM_FAILED if insufficient strong random bytes or some similar failure. + * @retval VERR_CR_RANDOM_SETUP_FAILED if setting up strong random failed + * and no strong bytes returned. + * + * @param pvDst Where to return the random bytes. + * @param cbDst How many random bytes to return. + */ +RTDECL(int) RTCrRandBytes(void *pvDst, size_t cbDst); + +RTDECL(int) RTCrPkcs5Pbkdf2Hmac(void const *pvInput, size_t cbInput, void const *pvSalt, size_t cbSalt, uint32_t cIterations, + RTDIGESTTYPE enmDigestType, size_t cbKeyLen, void *pvOutput); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_misc_h */ + diff --git a/include/iprt/crypto/pem.h b/include/iprt/crypto/pem.h new file mode 100644 index 00000000..c36bc587 --- /dev/null +++ b/include/iprt/crypto/pem.h @@ -0,0 +1,304 @@ +/** @file + * IPRT - Crypto - PEM-file Reader & Writer. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_pem_h +#define IPRT_INCLUDED_crypto_pem_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/asn1.h> /* PRTASN1CORE */ +#include <iprt/string.h> /* PFNRTSTROUTPUT */ + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_spc RTCrPem - PEM-file Reader & Writer + * @ingroup grp_rt_crypto + * @{ + */ + + +/** + * One PEM marker word (use RT_STR_TUPLE to initialize). + */ +typedef struct RTCRPEMMARKERWORD +{ + /** The word string. */ + const char *pszWord; + /** The length. */ + uint32_t cchWord; +} RTCRPEMMARKERWORD; +/** Pointer to a const marker word. */ +typedef RTCRPEMMARKERWORD const *PCRTCRPEMMARKERWORD; + + +/** + * A PEM marker. + * + * This is an array of words with lengths, optimized for avoid unnecessary + * strlen() while searching the file content. It is ASSUMED that all PEM + * section markers starts with either 'BEGIN' or 'END', followed by the words + * in the this structure. + */ +typedef struct RTCRPEMMARKER +{ + /** Pointer to an array of marker words. */ + PCRTCRPEMMARKERWORD paWords; + /** Number of works in the array papszWords points to. */ + uint32_t cWords; +} RTCRPEMMARKER; +/** Pointer to a const PEM marker. */ +typedef RTCRPEMMARKER const *PCRTCRPEMMARKER; + + +/** + * A PEM field. + */ +typedef struct RTCRPEMFIELD +{ + /** Pointer to the next field. */ + struct RTCRPEMFIELD const *pNext; + /** The field value. */ + char const *pszValue; + /** The field value length. */ + size_t cchValue; + /** The field name length. */ + size_t cchName; + /** The field name. */ + RT_FLEXIBLE_ARRAY_EXTENSION + char szName[RT_FLEXIBLE_ARRAY]; +} RTCRPEMFIELD; +/** Pointer to a PEM field. */ +typedef RTCRPEMFIELD *PRTCRPEMFIELD; +/** Pointer to a const PEM field. */ +typedef RTCRPEMFIELD const *PCRTCRPEMFIELD; + + +/** + * A PEM section. + * + * The API works on linked lists of these. + */ +typedef struct RTCRPEMSECTION +{ + /** Pointer to the next file section. */ + struct RTCRPEMSECTION const *pNext; + /** The marker for this section. NULL if binary file. */ + PCRTCRPEMMARKER pMarker; + /** Pointer to the binary data. */ + uint8_t *pbData; + /** The size of the binary data. */ + size_t cbData; + /** List of fields, NULL if none. */ + PCRTCRPEMFIELD pFieldHead; + /** Set if RTCRPEMREADFILE_F_SENSITIVE was specified. */ + bool fSensitive; +} RTCRPEMSECTION; +/** Pointer to a PEM section. */ +typedef RTCRPEMSECTION *PRTCRPEMSECTION; +/** Pointer to a const PEM section. */ +typedef RTCRPEMSECTION const *PCRTCRPEMSECTION; + + +/** + * Frees sections returned by RTCrPemReadFile and RTCrPemParseContent. + * @returns IPRT status code. + * @param pSectionHead The first section. + */ +RTDECL(int) RTCrPemFreeSections(PCRTCRPEMSECTION pSectionHead); + +/** + * Parses the given data and returns a list of binary sections. + * + * If the file isn't an ASCII file or if no markers were found, the entire file + * content is returned as one single section (with pMarker = NULL). + * + * @returns IPRT status code. + * @retval VINF_EOF if the file is empty. The @a ppSectionHead value will be + * NULL. + * @retval VWRN_NOT_FOUND no section was found and RTCRPEMREADFILE_F_ONLY_PEM + * is specified. The @a ppSectionHead value will be NULL. + * + * @param pvContent The content bytes to parse. + * @param cbContent The number of content bytes. + * @param fFlags RTCRPEMREADFILE_F_XXX. + * @param paMarkers Array of one or more section markers to look for. + * @param cMarkers Number of markers in the array. + * @param ppSectionHead Where to return the head of the section list. Call + * RTCrPemFreeSections to free. + * @param pErrInfo Where to return extend error info. Optional. + */ +RTDECL(int) RTCrPemParseContent(void const *pvContent, size_t cbContent, uint32_t fFlags, + PCRTCRPEMMARKER paMarkers, size_t cMarkers, PCRTCRPEMSECTION *ppSectionHead, PRTERRINFO pErrInfo); + +/** + * Reads the content of the given file and returns a list of binary sections + * found in the file. + * + * If the file isn't an ASCII file or if no markers were found, the entire file + * content is returned as one single section (with pMarker = NULL). + * + * @returns IPRT status code. + * @retval VINF_EOF if the file is empty. The @a ppSectionHead value will be + * NULL. + * @retval VWRN_NOT_FOUND no section was found and RTCRPEMREADFILE_F_ONLY_PEM + * is specified. The @a ppSectionHead value will be NULL. + * + * @param pszFilename The path to the file to read. + * @param fFlags RTCRPEMREADFILE_F_XXX. + * @param paMarkers Array of one or more section markers to look for. + * @param cMarkers Number of markers in the array. + * @param ppSectionHead Where to return the head of the section list. Call + * RTCrPemFreeSections to free. + * @param pErrInfo Where to return extend error info. Optional. + */ +RTDECL(int) RTCrPemReadFile(const char *pszFilename, uint32_t fFlags, PCRTCRPEMMARKER paMarkers, size_t cMarkers, + PCRTCRPEMSECTION *ppSectionHead, PRTERRINFO pErrInfo); +/** @name RTCRPEMREADFILE_F_XXX - Flags for RTCrPemReadFile and + * RTCrPemParseContent. + * @{ */ +/** Continue on encoding error. */ +#define RTCRPEMREADFILE_F_CONTINUE_ON_ENCODING_ERROR RT_BIT(0) +/** Only PEM sections, no binary fallback. */ +#define RTCRPEMREADFILE_F_ONLY_PEM RT_BIT(1) +/** Sensitive data, use the safer allocator. */ +#define RTCRPEMREADFILE_F_SENSITIVE RT_BIT(2) +/** Valid flags. */ +#define RTCRPEMREADFILE_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ + +/** + * Finds the beginning of first PEM section using the specified markers. + * + * This will not look any further than the first section. Nor will it check for + * binaries. + * + * @returns Pointer to the "-----BEGIN XXXX" sequence on success. + * NULL if not found. + * @param pvContent The content bytes to parse. + * @param cbContent The number of content bytes. + * @param paMarkers Array of one or more section markers to look for. + * @param cMarkers Number of markers in the array. + */ +RTDECL(const char *) RTCrPemFindFirstSectionInContent(void const *pvContent, size_t cbContent, + PCRTCRPEMMARKER paMarkers, size_t cMarkers); + + +/** + * PEM formatter for a binary data blob. + * + * @returns Number of output bytes (sum of @a pfnOutput return values). + * @param pfnOutput The output callback function. + * @param pvUser The user argument to the output callback. + * @param pvContent The binary blob to output. + * @param cbContent Size of the binary blob. + * @param pszMarker The PEM marker, .e.g "PRIVATE KEY", "CERTIFICATE" or + * similar. + * @sa RTCrPemWriteAsn1, RTCrPemWriteAsn1ToVfsFile, + * RTCrPemWriteAsn1ToVfsFile + */ +RTDECL(size_t) RTCrPemWriteBlob(PFNRTSTROUTPUT pfnOutput, void *pvUser, + const void *pvContent, size_t cbContent, const char *pszMarker); + +RTDECL(ssize_t) RTCrPemWriteBlobToVfsIoStrm(RTVFSIOSTREAM hVfsIos, const void *pvContent, size_t cbContent, const char *pszMarker); +RTDECL(ssize_t) RTCrPemWriteBlobToVfsFile(RTVFSFILE hVfsFile, const void *pvContent, size_t cbContent, const char *pszMarker); + +/** + * PEM formatter for a generic ASN.1 structure. + * + * This will call both RTAsn1EncodePrepare() and RTAsn1EncodeWrite() on + * @a pRoot. Uses DER encoding. + * + * @returns Number of outputted chars (sum of @a pfnOutput return values), + * negative values are error status codes from the ASN.1 encoding. + * @param pfnOutput The output callback function. + * @param pvUser The user argument to the output callback. + * @param fFlags Reserved, MBZ. + * @param pRoot The root of the ASN.1 to encode and format as PEM. + * @param pszMarker The PEM marker, .e.g "PRIVATE KEY", "CERTIFICATE" or + * similar. + * @param pErrInfo For encoding errors. Optional. + * @sa RTCrPemWriteAsn1ToVfsFile, RTCrPemWriteAsn1ToVfsFile, + * RTCrPemWriteBlob + */ +RTDECL(ssize_t) RTCrPemWriteAsn1(PFNRTSTROUTPUT pfnOutput, void *pvUser, PRTASN1CORE pRoot, + uint32_t fFlags, const char *pszMarker, PRTERRINFO pErrInfo); + +/** + * PEM formatter for a generic ASN.1 structure and output it to @a hVfsIos. + * + * This will call both RTAsn1EncodePrepare() and RTAsn1EncodeWrite() on + * @a pRoot. Uses DER encoding. + * + * @returns Number of chars written, negative values are error status codes from + * the ASN.1 encoding or from RTVfsIoStrmWrite(). + * @param hVfsIos Handle to the I/O stream to write it to. + * @param fFlags Reserved, MBZ. + * @param pRoot The root of the ASN.1 to encode and format as PEM. + * @param pszMarker The PEM marker, .e.g "PRIVATE KEY", "CERTIFICATE" or + * similar. + * @param pErrInfo For encoding errors. Optional. + * @sa RTCrPemWriteAsn1ToVfsFile, RTCrPemWriteAsn1, RTCrPemWriteBlob + */ +RTDECL(ssize_t) RTCrPemWriteAsn1ToVfsIoStrm(RTVFSIOSTREAM hVfsIos, PRTASN1CORE pRoot, + uint32_t fFlags, const char *pszMarker, PRTERRINFO pErrInfo); + +/** + * PEM formatter for a generic ASN.1 structure and output it to @a hVfsFile. + * + * This will call both RTAsn1EncodePrepare() and RTAsn1EncodeWrite() on + * @a pRoot. Uses DER encoding. + * + * @returns Number of chars written, negative values are error status codes from + * the ASN.1 encoding or from RTVfsIoStrmWrite(). + * @param hVfsFile Handle to the file to write it to. + * @param fFlags Reserved, MBZ. + * @param pRoot The root of the ASN.1 to encode and format as PEM. + * @param pszMarker The PEM marker, .e.g "PRIVATE KEY", "CERTIFICATE" or + * similar. + * @param pErrInfo For encoding errors. Optional. + * @sa RTCrPemWriteAsn1ToVfsIoStrm, RTCrPemWriteAsn1, RTCrPemWriteBlob + */ +RTDECL(ssize_t) RTCrPemWriteAsn1ToVfsFile(RTVFSFILE hVfsFile, PRTASN1CORE pRoot, + uint32_t fFlags, const char *pszMarker, PRTERRINFO pErrInfo); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_pem_h */ + diff --git a/include/iprt/crypto/pkcs7.h b/include/iprt/crypto/pkcs7.h new file mode 100644 index 00000000..2bc3f950 --- /dev/null +++ b/include/iprt/crypto/pkcs7.h @@ -0,0 +1,709 @@ +/** @file + * IPRT - PKCS \#7, Cryptographic Message Syntax Standard (aka CMS). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_pkcs7_h +#define IPRT_INCLUDED_crypto_pkcs7_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/asn1.h> +#include <iprt/crypto/x509.h> + + +RT_C_DECLS_BEGIN + +struct RTCRPKCS7CONTENTINFO; + + +/** @defgroup grp_rt_crpkcs7 RTCrPkcs7 - PKCS \#7, Cryptographic Message Syntax Standard (aka CMS). + * @ingroup grp_rt_crypto + * @{ + */ + +/** PKCS \#7 data object ID.*/ +#define RTCR_PKCS7_DATA_OID "1.2.840.113549.1.7.1" +/** PKCS \#7 signedData object ID. */ +#define RTCR_PKCS7_SIGNED_DATA_OID "1.2.840.113549.1.7.2" +/** PKCS \#7 envelopedData object ID. */ +#define RTCR_PKCS7_ENVELOPED_DATA_OID "1.2.840.113549.1.7.3" +/** PKCS \#7 signedAndEnvelopedData object ID. */ +#define RTCR_PKCS7_SIGNED_AND_ENVELOPED_DATA_OID "1.2.840.113549.1.7.4" +/** PKCS \#7 digestedData object ID. */ +#define RTCR_PKCS7_DIGESTED_DATA_OID "1.2.840.113549.1.7.5" +/** PKCS \#7 encryptedData object ID. */ +#define RTCR_PKCS7_ENCRYPTED_DATA_OID "1.2.840.113549.1.7.6" + + +/** + * PKCS \#7 IssuerAndSerialNumber (IPRT representation). + */ +typedef struct RTCRPKCS7ISSUERANDSERIALNUMBER +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The certificate name. */ + RTCRX509NAME Name; + /** The certificate serial number. */ + RTASN1INTEGER SerialNumber; +} RTCRPKCS7ISSUERANDSERIALNUMBER; +/** Pointer to the IPRT representation of a PKCS \#7 IssuerAndSerialNumber. */ +typedef RTCRPKCS7ISSUERANDSERIALNUMBER *PRTCRPKCS7ISSUERANDSERIALNUMBER; +/** Pointer to the const IPRT representation of a PKCS \#7 + * IssuerAndSerialNumber. */ +typedef RTCRPKCS7ISSUERANDSERIALNUMBER const *PCRTCRPKCS7ISSUERANDSERIALNUMBER; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7ISSUERANDSERIALNUMBER, RTDECL, RTCrPkcs7IssuerAndSerialNumber, SeqCore.Asn1Core); + + +/** Pointer to the IPRT representation of a PKCS \#7 SignerInfo. */ +typedef struct RTCRPKCS7SIGNERINFO *PRTCRPKCS7SIGNERINFO; +/** Pointer to the const IPRT representation of a PKCS \#7 SignerInfo. */ +typedef struct RTCRPKCS7SIGNERINFO const *PCRTCRPKCS7SIGNERINFO; +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRPKCS7SIGNERINFOS, RTCRPKCS7SIGNERINFO, RTDECL, RTCrPkcs7SignerInfos); + + +/** + * Attribute value type (for the union). + */ +typedef enum RTCRPKCS7ATTRIBUTETYPE +{ + /** Zero is invalid. */ + RTCRPKCS7ATTRIBUTETYPE_INVALID = 0, + /** Not present, union is NULL. */ + RTCRPKCS7ATTRIBUTETYPE_NOT_PRESENT, + /** Unknown values, pCores. */ + RTCRPKCS7ATTRIBUTETYPE_UNKNOWN, + /** Object IDs, use pObjIds. */ + RTCRPKCS7ATTRIBUTETYPE_OBJ_IDS, + /** Octet strings, use pOctetStrings. */ + RTCRPKCS7ATTRIBUTETYPE_OCTET_STRINGS, + /** Counter signatures (PKCS \#9), use pCounterSignatures. + * RTCR_PKCS9_ID_COUNTER_SIGNATURE_OID - 1.2.840.113549.1.9.6. */ + RTCRPKCS7ATTRIBUTETYPE_COUNTER_SIGNATURES, + /** Signing time (PKCS \#9), use pSigningTime. + * RTCR_PKCS9_ID_SIGNING_TIME_OID - 1.2.840.113549.1.9.5. */ + RTCRPKCS7ATTRIBUTETYPE_SIGNING_TIME, + /** Microsoft timestamp info (RFC-3161) signed data, use pContentInfo. + * RTCR_PKCS9_ID_MS_TIMESTAMP - 1.3.6.1.4.1.311.3.3.1. */ + RTCRPKCS7ATTRIBUTETYPE_MS_TIMESTAMP, + /** Microsoft nested PKCS\#7 signature (signtool /as). + * RTCR_PKCS9_ID_MS_NESTED_SIGNATURE - 1.3.6.1.4.1.311.2.4.1. */ + RTCRPKCS7ATTRIBUTETYPE_MS_NESTED_SIGNATURE, + /** Microsoft statement type, use pObjIdSeqs. + * RTCR_PKCS9_ID_MS_STATEMENT_TYPE - 1.3.6.1.4.1.311.2.1.11. */ + RTCRPKCS7ATTRIBUTETYPE_MS_STATEMENT_TYPE, + /** Apple plist with the all code directory digests, use pOctetStrings. + * RTCR_PKCS9_ID_APPLE_MULTI_CD_PLIST - 1.2.840.113635.100.9.1. */ + RTCRPKCS7ATTRIBUTETYPE_APPLE_MULTI_CD_PLIST, + /** Blow the type up to 32-bits. */ + RTCRPKCS7ATTRIBUTETYPE_32BIT_HACK = 0x7fffffff +} RTCRPKCS7ATTRIBUTETYPE; + +/** + * PKCS \#7 Attribute (IPRT representation). + */ +typedef struct RTCRPKCS7ATTRIBUTE +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The attribute type (object ID). */ + RTASN1OBJID Type; + /** The type of data found in the values union. */ + RTCRPKCS7ATTRIBUTETYPE enmType; + /** Value allocation. */ + RTASN1ALLOCATION Allocation; + /** Values. */ + union + { + /** ASN.1 cores (RTCRPKCS7ATTRIBUTETYPE_UNKNOWN). */ + PRTASN1SETOFCORES pCores; + /** ASN.1 object identifiers (RTCRPKCS7ATTRIBUTETYPE_OBJ_IDS). */ + PRTASN1SETOFOBJIDS pObjIds; + /** Sequence of ASN.1 object identifiers (RTCRPKCS7ATTRIBUTETYPE_MS_STATEMENT_TYPE). */ + PRTASN1SETOFOBJIDSEQS pObjIdSeqs; + /** ASN.1 octet strings (RTCRPKCS7ATTRIBUTETYPE_OCTET_STRINGS). */ + PRTASN1SETOFOCTETSTRINGS pOctetStrings; + /** Counter signatures RTCRPKCS7ATTRIBUTETYPE_COUNTER_SIGNATURES(). */ + PRTCRPKCS7SIGNERINFOS pCounterSignatures; + /** Signing time(s) (RTCRPKCS7ATTRIBUTETYPE_SIGNING_TIME). */ + PRTASN1SETOFTIMES pSigningTime; + /** Microsoft timestamp (RFC-3161 signed data, RTCRPKCS7ATTRIBUTETYPE_MS_TIMESTAMP), + * Microsoft nested signature (RTCRPKCS7ATTRIBUTETYPE_MS_NESTED_SIGNATURE). */ + struct RTCRPKCS7SETOFCONTENTINFOS *pContentInfos; + } uValues; +} RTCRPKCS7ATTRIBUTE; +/** Pointer to the IPRT representation of a PKCS \#7 Attribute. */ +typedef RTCRPKCS7ATTRIBUTE *PRTCRPKCS7ATTRIBUTE; +/** Pointer to the const IPRT representation of a PKCS \#7 Attribute. */ +typedef RTCRPKCS7ATTRIBUTE const *PCRTCRPKCS7ATTRIBUTE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7ATTRIBUTE, RTDECL, RTCrPkcs7Attribute, SeqCore.Asn1Core); + +RTDECL(int) RTCrPkcs7Attribute_SetAppleMultiCdPlist(PRTCRPKCS7ATTRIBUTE pThis, PCRTASN1SETOFOCTETSTRINGS pToClone, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Attribute_SetContentType(PRTCRPKCS7ATTRIBUTE pThis, PCRTASN1SETOFOBJIDS pToClone, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Attribute_SetCounterSignatures(PRTCRPKCS7ATTRIBUTE pThis, PCRTCRPKCS7SIGNERINFOS pToClone, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Attribute_SetMessageDigest(PRTCRPKCS7ATTRIBUTE pThis, PCRTASN1SETOFOCTETSTRINGS pToClone, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Attribute_SetMsStatementType(PRTCRPKCS7ATTRIBUTE pThis, PCRTASN1SETOFOBJIDSEQS pToClone, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Attribute_SetMsNestedSignature(PRTCRPKCS7ATTRIBUTE pThis, struct RTCRPKCS7SETOFCONTENTINFOS const *pToClone, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Attribute_SetMsTimestamp(PRTCRPKCS7ATTRIBUTE pThis, struct RTCRPKCS7SETOFCONTENTINFOS const *pToClone, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Attribute_SetSigningTime(PRTCRPKCS7ATTRIBUTE pThis, PCRTASN1SETOFTIMES pToClone, + PCRTASN1ALLOCATORVTABLE pAllocator); + +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRPKCS7ATTRIBUTES, RTCRPKCS7ATTRIBUTE, RTDECL, RTCrPkcs7Attributes); + +RTDECL(int) RTCrPkcs7Attributes_HashAttributes(PRTCRPKCS7ATTRIBUTES pAttributes, RTCRDIGEST hDigest, PRTERRINFO pErrInfo); + + +/** + * One PKCS \#7 SignerInfo (IPRT representation). + */ +typedef struct RTCRPKCS7SIGNERINFO +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The structure version (RTCRPKCS7SIGNERINFO_V1). */ + RTASN1INTEGER Version; + /** The issuer and serial number of the certificate used to produce the + * encrypted digest below. */ + RTCRPKCS7ISSUERANDSERIALNUMBER IssuerAndSerialNumber; + /** The digest algorithm use to digest the signed content. */ + RTCRX509ALGORITHMIDENTIFIER DigestAlgorithm; + /** Authenticated attributes, optional [0]. + * @todo Check how other producers formats this. The microsoft one does not + * have explicit tags, but combines it with the SET OF. */ + RTCRPKCS7ATTRIBUTES AuthenticatedAttributes; + /** The digest encryption algorithm use to encrypt the digest of the signed + * content. */ + RTCRX509ALGORITHMIDENTIFIER DigestEncryptionAlgorithm; + /** The encrypted digest. */ + RTASN1OCTETSTRING EncryptedDigest; + /** Unauthenticated attributes, optional [1]. + * @todo Check how other producers formats this. The microsoft one does not + * have explicit tags, but combines it with the SET OF. */ + RTCRPKCS7ATTRIBUTES UnauthenticatedAttributes; +} RTCRPKCS7SIGNERINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7SIGNERINFO, RTDECL, RTCrPkcs7SignerInfo, SeqCore.Asn1Core); + +RTDECL(int) RTCrPkcs7SignerInfo_SetAuthenticatedAttributes(PRTCRPKCS7SIGNERINFO pThis, PCRTCRPKCS7ATTRIBUTES pAttributes, + PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7SignerInfo_SetUnauthenticatedAttributes(PRTCRPKCS7SIGNERINFO pThis, PCRTCRPKCS7ATTRIBUTES pAttributes, + PCRTASN1ALLOCATORVTABLE pAllocator); + +/** RTCRPKCS7SIGNERINFO::Version value. */ +#define RTCRPKCS7SIGNERINFO_V1 1 + +/** @name PKCS \#9 Attribute IDs + * @{ */ +/** Content type (RFC-2630 11.1). + * Value: Object Identifier */ +#define RTCR_PKCS9_ID_CONTENT_TYPE_OID "1.2.840.113549.1.9.3" +/** Message digest (RFC-2630 11.2). + * Value: Octet string. */ +#define RTCR_PKCS9_ID_MESSAGE_DIGEST_OID "1.2.840.113549.1.9.4" +/** Signing time (RFC-2630 11.3). + * Value: Octet string. */ +#define RTCR_PKCS9_ID_SIGNING_TIME_OID "1.2.840.113549.1.9.5" +/** Counter signature (RFC-2630 11.4). + * Value: SignerInfo. */ +#define RTCR_PKCS9_ID_COUNTER_SIGNATURE_OID "1.2.840.113549.1.9.6" +/** Microsoft timestamp (RTF-3161) counter signature (SignedData). + * @remarks This isn't defined by PKCS \#9, but lumped in here for convenience. It's actually listed as SPC by MS. */ +#define RTCR_PKCS9_ID_MS_TIMESTAMP "1.3.6.1.4.1.311.3.3.1" +/** Microsoft nested PKCS\#7 signature. + * @remarks This isn't defined by PKCS \#9, but lumped in here for convenience. */ +#define RTCR_PKCS9_ID_MS_NESTED_SIGNATURE "1.3.6.1.4.1.311.2.4.1" +/** Microsoft statement type. + * @remarks This isn't defined by PKCS \#9, but lumped in here for convenience. It's actually listed as SPC by MS. */ +#define RTCR_PKCS9_ID_MS_STATEMENT_TYPE "1.3.6.1.4.1.311.2.1.11" +/** Microsoft opus info. + * @remarks This isn't defined by PKCS \#9, but lumped in here for convenience. It's actually listed as SPC by MS. */ +#define RTCR_PKCS9_ID_MS_SP_OPUS_INFO "1.3.6.1.4.1.311.2.1.12" +/** Apple code signing multi-code-directory plist. + * @remarks This isn't defined by PKCS \#9, but lumped in here for convenience. */ +#define RTCR_PKCS9_ID_APPLE_MULTI_CD_PLIST "1.2.840.113635.100.9.1" +/** @} */ + + +/** + * Get the (next) signing time attribute from the specfied SignerInfo or one of + * the immediate counter signatures. + * + * @returns Pointer to the signing time if found, NULL if not. + * @param pThis The SignerInfo to search. + * @param ppSignerInfo Pointer to variable keeping track of the + * enumeration, optional. + * + * If specified the input value is taken to the be + * SignerInfo of the previously returned signing + * time. The value pointed to is NULL, the + * search/enum restarts. + * + * On successful return this is set to the + * SignerInfo which we found the signing time in. + */ +RTDECL(PCRTASN1TIME) RTCrPkcs7SignerInfo_GetSigningTime(PCRTCRPKCS7SIGNERINFO pThis, PCRTCRPKCS7SIGNERINFO *ppSignerInfo); + + +/** + * Get the (first) timestamp from within a Microsoft timestamp server counter + * signature. + * + * @returns Pointer to the signing time if found, NULL if not. + * @param pThis The SignerInfo to search. + * @param ppContentInfoRet Where to return the pointer to the counter + * signature, optional. + */ +RTDECL(PCRTASN1TIME) RTCrPkcs7SignerInfo_GetMsTimestamp(PCRTCRPKCS7SIGNERINFO pThis, + struct RTCRPKCS7CONTENTINFO const **ppContentInfoRet); + + + +/** + * PKCS \#7 ContentInfo (IPRT representation). + */ +typedef struct RTCRPKCS7CONTENTINFO +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** Object ID identifying the content below. */ + RTASN1OBJID ContentType; + /** Content, optional, explicit tag 0. + * + * Hack alert! This should've been an explict context tag 0 structure with a + * type selected according to ContentType. However, it's simpler to replace the + * explicit context with an OCTET STRING with implict tag 0. Then we can tag + * along on the encapsulation logic RTASN1OCTETSTRING provides for the dynamic + * inner type. The default decoder code will detect known structures as + * outlined in the union below, and decode the octet string content as an + * anonymous RTASN1CORE if not known. + * + * If the user want to decode the octet string content differently, it can do so + * by destroying and freeing the current encapsulated pointer, replacing it with + * it's own. (Of course following the RTASN1OCTETSTRING rules.) Just remember + * to also update the value in the union. + * + * @remarks What's signed and verified is Content.pEncapsulated->uData.pv. + */ + RTASN1OCTETSTRING Content; + /** Pointer to the CMS octet string that's inside the Content, NULL if PKCS \#7. + * + * Hack alert! When transitioning from PKCS \#7 to CMS, the designers decided to + * change things and add another wrapper. This time we're talking about a real + * octet string, not like the one above which is really an explicit content tag. + * When constructing or decoding CMS content, this will be the same pointer as + * Content.pEncapsulated, while the union below will be holding the same pointer + * as pCmsContent->pEncapsulated. + */ + PRTASN1OCTETSTRING pCmsContent; + /** Same as Content.pEncapsulated, except a choice of known types. */ + union + { + /** ContentType is RTCRPKCS7SIGNEDDATA_OID. */ + struct RTCRPKCS7SIGNEDDATA *pSignedData; + /** ContentType is RTCRSPCINDIRECTDATACONTENT_OID. */ + struct RTCRSPCINDIRECTDATACONTENT *pIndirectDataContent; + /** ContentType is RTCRTSPTSTINFO_OID. */ + struct RTCRTSPTSTINFO *pTstInfo; + /** Generic / Unknown / User. */ + PRTASN1CORE pCore; + } u; +} RTCRPKCS7CONTENTINFO; +/** Pointer to the IPRT representation of a PKCS \#7 ContentInfo. */ +typedef RTCRPKCS7CONTENTINFO *PRTCRPKCS7CONTENTINFO; +/** Pointer to the const IPRT representation of a PKCS \#7 ContentInfo. */ +typedef RTCRPKCS7CONTENTINFO const *PCRTCRPKCS7CONTENTINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7CONTENTINFO, RTDECL, RTCrPkcs7ContentInfo, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRPKCS7SETOFCONTENTINFOS, RTCRPKCS7CONTENTINFO, RTDECL, RTCrPkcs7SetOfContentInfos); + +RTDECL(bool) RTCrPkcs7ContentInfo_IsSignedData(PCRTCRPKCS7CONTENTINFO pThis); + + +/** + * PKCS \#7 Certificate choice. + */ +typedef enum RTCRPKCS7CERTCHOICE +{ + RTCRPKCS7CERTCHOICE_INVALID = 0, + RTCRPKCS7CERTCHOICE_X509, + RTCRPKCS7CERTCHOICE_EXTENDED_PKCS6, + RTCRPKCS7CERTCHOICE_AC_V1, + RTCRPKCS7CERTCHOICE_AC_V2, + RTCRPKCS7CERTCHOICE_OTHER, + RTCRPKCS7CERTCHOICE_END, + RTCRPKCS7CERTCHOICE_32BIT_HACK = 0x7fffffff +} RTCRPKCS7CERTCHOICE; + + +/** + * Common representation for PKCS \#7 ExtendedCertificateOrCertificate and the + * CMS CertificateChoices types. + */ +typedef struct RTCRPKCS7CERT +{ + /** Dummy ASN.1 record, not encoded. */ + RTASN1DUMMY Dummy; + /** The value allocation. */ + RTASN1ALLOCATION Allocation; + /** The choice of value. */ + RTCRPKCS7CERTCHOICE enmChoice; + /** The value union. */ + union + { + /** Standard X.509 certificate (RTCRCMSCERTIFICATECHOICE_X509). */ + PRTCRX509CERTIFICATE pX509Cert; + /** Extended PKCS \#6 certificate (RTCRCMSCERTIFICATECHOICE_EXTENDED_PKCS6). */ + PRTASN1CORE pExtendedCert; + /** Attribute certificate version 1 (RTCRCMSCERTIFICATECHOICE_AC_V1). */ + PRTASN1CORE pAcV1; + /** Attribute certificate version 2 (RTCRCMSCERTIFICATECHOICE_AC_V2). */ + PRTASN1CORE pAcV2; + /** Other certificate (RTCRCMSCERTIFICATECHOICE_OTHER). */ + PRTASN1CORE pOtherCert; + } u; +} RTCRPKCS7CERT; +/** Pointer to the IPRT representation of PKCS \#7 or CMS certificate. */ +typedef RTCRPKCS7CERT *PRTCRPKCS7CERT; +/** Pointer to the const IPRT representation of PKCS \#7 or CMS certificate. */ +typedef RTCRPKCS7CERT const *PCRTCRPKCS7CERT; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7CERT, RTDECL, RTCrPkcs7Cert, Dummy.Asn1Core); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRPKCS7SETOFCERTS, RTCRPKCS7CERT, RTDECL, RTCrPkcs7SetOfCerts); + +RTDECL(int) RTCrPkcs7Cert_SetX509Cert(PRTCRPKCS7CERT pThis, PCRTCRX509CERTIFICATE pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Cert_SetExtendedCert(PRTCRPKCS7CERT pThis, PCRTASN1CORE pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Cert_SetAcV1(PRTCRPKCS7CERT pThis, PCRTASN1CORE pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Cert_SetAcV2(PRTCRPKCS7CERT pThis, PCRTASN1CORE pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7Cert_SetOtherCert(PRTCRPKCS7CERT pThis, PCRTASN1CORE pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); + +RTDECL(PCRTCRX509CERTIFICATE) RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber(PCRTCRPKCS7SETOFCERTS pCertificates, + PCRTCRX509NAME pIssuer, + PCRTASN1INTEGER pSerialNumber); + + +/** + * PKCS \#7 SignedData (IPRT representation). + */ +typedef struct RTCRPKCS7SIGNEDDATA +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The structure version value (1). */ + RTASN1INTEGER Version; + /** The digest algorithms that are used to signed the content (ContentInfo). */ + RTCRX509ALGORITHMIDENTIFIERS DigestAlgorithms; + /** The content that's being signed. */ + RTCRPKCS7CONTENTINFO ContentInfo; + /** Certificates, optional, implicit tag 0. (Required by Authenticode.) */ + RTCRPKCS7SETOFCERTS Certificates; + /** Certificate revocation lists, optional, implicit tag 1. + * Not used by Authenticode, so currently stubbed. */ + RTASN1CORE Crls; + /** Signer infos. */ + RTCRPKCS7SIGNERINFOS SignerInfos; +} RTCRPKCS7SIGNEDDATA; +/** Pointer to the IPRT representation of a PKCS \#7 SignedData. */ +typedef RTCRPKCS7SIGNEDDATA *PRTCRPKCS7SIGNEDDATA; +/** Pointer to the const IPRT representation of a PKCS \#7 SignedData. */ +typedef RTCRPKCS7SIGNEDDATA const *PCRTCRPKCS7SIGNEDDATA; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7SIGNEDDATA, RTDECL, RTCrPkcs7SignedData, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRPKCS7SETOFSIGNEDDATA, RTCRPKCS7SIGNEDDATA, RTDECL, RTCrPkcs7SetOfSignedData); + +/** PKCS \#7 SignedData object ID. */ +#define RTCRPKCS7SIGNEDDATA_OID RTCR_PKCS7_SIGNED_DATA_OID + +/** PKCS \#7 SignedData version number 1. */ +#define RTCRPKCS7SIGNEDDATA_V1 1 +/* No version 2 seems to exist. */ +/** CMS SignedData version number 3. + * This should only be used if there are version 1 attribute certificates + * present, or if there are version 3 SignerInfo items present, or if + * enmcCountInfo is not id-data (RFC-5652, section 5.1). */ +#define RTCRPKCS7SIGNEDDATA_V3 3 +/** CMS SignedData version number 4. + * This should only be used if there are version 2 attribute certificates + * present (RFC-5652, section 5.1). */ +#define RTCRPKCS7SIGNEDDATA_V4 4 +/** CMS SignedData version number 5. + * This should only be used if there are certificates or/and CRLs of the + * OTHER type present (RFC-5652, section 5.1). */ +#define RTCRPKCS7SIGNEDDATA_V5 5 + +RTDECL(int) RTCrPkcs7SignedData_SetCertificates(PRTCRPKCS7SIGNEDDATA pThis, PCRTCRPKCS7SETOFCERTS pCerts, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrPkcs7SignedData_SetCrls(PRTCRPKCS7SIGNEDDATA pThis, PCRTASN1CORE pCerts, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** @name RTCRPKCS7SIGNEDDATA_SANITY_F_XXX - Flags for RTPkcs7SignedDataCheckSantiy. + * @{ */ +/** Check for authenticode restrictions. */ +#define RTCRPKCS7SIGNEDDATA_SANITY_F_AUTHENTICODE RT_BIT_32(0) +/** Check that all the hash algorithms are known to IPRT. */ +#define RTCRPKCS7SIGNEDDATA_SANITY_F_ONLY_KNOWN_HASH RT_BIT_32(1) +/** Require signing certificate to be present. */ +#define RTCRPKCS7SIGNEDDATA_SANITY_F_SIGNING_CERT_PRESENT RT_BIT_32(2) +/** @} */ + +/** PKCS\#7/CMS (content info) markers. */ +extern RTDATADECL(RTCRPEMMARKER const) g_aRTCrPkcs7Markers[]; +/** Number of entries in g_aRTCrPkcs7Markers. */ +extern RTDATADECL(uint32_t const) g_cRTCrPkcs7Markers; + +/** @name Flags for RTCrPkcs7ContentInfo_ReadFromBuffer + * @{ */ +/** Only allow PEM certificates, not binary ones. + * @sa RTCRPEMREADFILE_F_ONLY_PEM */ +#define RTCRPKCS7_READ_F_PEM_ONLY RT_BIT(1) +/** @} */ + +RTDECL(int) RTCrPkcs7_ReadFromBuffer(PRTCRPKCS7CONTENTINFO pContentInfo, const void *pvBuf, size_t cbBuf, + uint32_t fFlags, PCRTASN1ALLOCATORVTABLE pAllocator, + bool *pfCmsLabeled, PRTERRINFO pErrInfo, const char *pszErrorTag); + + +/** + * PKCS \#7 DigestInfo (IPRT representation). + */ +typedef struct RTCRPKCS7DIGESTINFO +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The digest algorithm use to digest the signed content. */ + RTCRX509ALGORITHMIDENTIFIER DigestAlgorithm; + /** The digest. */ + RTASN1OCTETSTRING Digest; +} RTCRPKCS7DIGESTINFO; +/** Pointer to the IPRT representation of a PKCS \#7 DigestInfo object. */ +typedef RTCRPKCS7DIGESTINFO *PRTCRPKCS7DIGESTINFO; +/** Pointer to the const IPRT representation of a PKCS \#7 DigestInfo object. */ +typedef RTCRPKCS7DIGESTINFO const *PCRTCRPKCS7DIGESTINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7DIGESTINFO, RTDECL, RTCrPkcs7DigestInfo, SeqCore.Asn1Core); + + +/** + * Callback function for use with RTCrPkcs7VerifySignedData. + * + * @returns IPRT status code. + * @param pCert The certificate to verify. + * @param hCertPaths Unless the certificate is trusted directly, this + * is a reference to the certificate path builder + * and verifier instance that we used to establish + * at least valid trusted path to @a pCert. The + * callback can use this to enforce additional + * certificate lineage requirements, effective + * policy checks and whatnot. + * This is NIL_RTCRX509CERTPATHS if the certificate + * is directly trusted. + * @param fFlags Mix of the RTCRPKCS7VCC_F_XXX flags. + * @param pvUser The user argument. + * @param pErrInfo Optional error info buffer. + */ +typedef DECLCALLBACKTYPE(int, FNRTCRPKCS7VERIFYCERTCALLBACK,(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths, + uint32_t fFlags, void *pvUser, PRTERRINFO pErrInfo)); +/** Pointer to a FNRTCRPKCS7VERIFYCERTCALLBACK callback. */ +typedef FNRTCRPKCS7VERIFYCERTCALLBACK *PFNRTCRPKCS7VERIFYCERTCALLBACK; + +/** @name RTCRPKCS7VCC_F_XXX - Flags for FNRTCRPKCS7VERIFYCERTCALLBACK. + * @{ */ +/** Normal callback for a direct signatory of the signed data. */ +#define RTCRPKCS7VCC_F_SIGNED_DATA RT_BIT_32(0) +/** Check that the signatory can be trusted for timestamps. */ +#define RTCRPKCS7VCC_F_TIMESTAMP RT_BIT_32(1) +/** @} */ + +/** + * @callback_method_impl{FNRTCRPKCS7VERIFYCERTCALLBACK, + * Default implementation that checks for the DigitalSignature KeyUsage bit.} + */ +RTDECL(int) RTCrPkcs7VerifyCertCallbackDefault(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths, uint32_t fFlags, + void *pvUser, PRTERRINFO pErrInfo); + +/** + * @callback_method_impl{FNRTCRPKCS7VERIFYCERTCALLBACK, + * Standard code signing. Use this for Microsoft SPC.} + */ +RTDECL(int) RTCrPkcs7VerifyCertCallbackCodeSigning(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths, uint32_t fFlags, + void *pvUser, PRTERRINFO pErrInfo); + +/** + * Verifies PKCS \#7 SignedData. + * + * For compatability with alternative crypto providers, the user must work on + * the top level PKCS \#7 structure instead directly on the SignedData. + * + * @returns IPRT status code. + * @param pContentInfo PKCS \#7 content info structure. + * @param fFlags RTCRPKCS7VERIFY_SD_F_XXX. + * @param hAdditionalCerts Store containing additional certificates to + * supplement those mentioned in the signed data. + * @param hTrustedCerts Store containing trusted certificates. + * @param pValidationTime The time we're supposed to validate the + * certificates chains at. Ignored for signatures + * with valid signing time attributes. + * When RTCRPKCS7VERIFY_SD_F_UPDATE_VALIDATION_TIME + * is set, this is updated to the actual validation + * time used. + * @param pfnVerifyCert Callback for checking that a certificate used + * for signing the data is suitable. + * @param pvUser User argument for the callback. + * @param pErrInfo Optional error info buffer. + * @sa RTCrPkcs7VerifySignedDataWithExternalData + */ +RTDECL(int) RTCrPkcs7VerifySignedData(PCRTCRPKCS7CONTENTINFO pContentInfo, uint32_t fFlags, + RTCRSTORE hAdditionalCerts, RTCRSTORE hTrustedCerts, + PCRTTIMESPEC pValidationTime, PFNRTCRPKCS7VERIFYCERTCALLBACK pfnVerifyCert, void *pvUser, + PRTERRINFO pErrInfo); + + +/** + * Verifies PKCS \#7 SignedData with external data. + * + * For compatability with alternative crypto providers, the user must work on + * the top level PKCS \#7 structure instead directly on the SignedData. + * + * @returns IPRT status code. + * @param pContentInfo PKCS \#7 content info structure. + * @param fFlags RTCRPKCS7VERIFY_SD_F_XXX. + * @param hAdditionalCerts Store containing additional certificates to + * supplement those mentioned in the signed data. + * @param hTrustedCerts Store containing trusted certificates. + * @param pValidationTime The time we're supposed to validate the + * certificates chains at. Ignored for signatures + * with valid signing time attributes. + * When RTCRPKCS7VERIFY_SD_F_UPDATE_VALIDATION_TIME + * is set, this is updated to the actual validation + * time used. + * @param pfnVerifyCert Callback for checking that a certificate used + * for signing the data is suitable. + * @param pvUser User argument for the callback. + * @param pvData The signed external data. + * @param cbData The size of the signed external data. + * @param pErrInfo Optional error info buffer. + * @sa RTCrPkcs7VerifySignedData + */ +RTDECL(int) RTCrPkcs7VerifySignedDataWithExternalData(PCRTCRPKCS7CONTENTINFO pContentInfo, uint32_t fFlags, + RTCRSTORE hAdditionalCerts, RTCRSTORE hTrustedCerts, + PCRTTIMESPEC pValidationTime, + PFNRTCRPKCS7VERIFYCERTCALLBACK pfnVerifyCert, void *pvUser, + void const *pvData, size_t cbData, PRTERRINFO pErrInfo); + +/** @name RTCRPKCS7VERIFY_SD_F_XXX - Flags for RTCrPkcs7VerifySignedData and + * RTCrPkcs7VerifySignedDataWithExternalData + * @{ */ +/** Always use the signing time attribute if present, requiring it to be + * verified as valid. The default behavior is to ignore unverifiable + * signing time attributes and use the @a pValidationTime instead. */ +#define RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_SIGNING_TIME_IF_PRESENT RT_BIT_32(0) +/** Same as RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_SIGNING_TIME_IF_PRESENT for the MS + * timestamp counter signatures. */ +#define RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_MS_TIMESTAMP_IF_PRESENT RT_BIT_32(1) +/** Only use signing time attributes from counter signatures. */ +#define RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY RT_BIT_32(2) +/** Don't validate the counter signature containing the signing time, just use + * it unverified. This is useful if we don't necessarily have the root + * certificates for the timestamp server handy, but use with great care. + * @sa RTCRPKCS7VERIFY_SD_F_USE_MS_TIMESTAMP_UNVERIFIED */ +#define RTCRPKCS7VERIFY_SD_F_USE_SIGNING_TIME_UNVERIFIED RT_BIT_32(3) +/** Don't validate the MS counter signature containing the signing timestamp. + * @sa RTCRPKCS7VERIFY_SD_F_USE_SIGNING_TIME_UNVERIFIED */ +#define RTCRPKCS7VERIFY_SD_F_USE_MS_TIMESTAMP_UNVERIFIED RT_BIT_32(4) +/** Do not consider timestamps in microsoft counter signatures. */ +#define RTCRPKCS7VERIFY_SD_F_IGNORE_MS_TIMESTAMP RT_BIT_32(5) +/** The signed data requires certificates to have the timestamp extended + * usage bit present. This is used for recursivly verifying MS timestamp + * signatures. */ +#define RTCRPKCS7VERIFY_SD_F_USAGE_TIMESTAMPING RT_BIT_32(6) +/** Skip the verification of the certificate trust paths, taking all + * certificates to be trustworthy. */ +#define RTCRPKCS7VERIFY_SD_F_TRUST_ALL_CERTS RT_BIT_32(7) +/** Update @a pValidationTime with the actual validation time used. + * This requires RTCRPKCS7VERIFY_SD_F_HAS_SIGNER_INDEX to get a consistent + * result. And yeah, it unconst the parameter, which is patently ugly. */ +#define RTCRPKCS7VERIFY_SD_F_UPDATE_VALIDATION_TIME RT_BIT_32(8) +/** Check trust anchors (@sa RTCrX509CertPathsSetTrustAnchorChecks). */ +#define RTCRPKCS7VERIFY_SD_F_CHECK_TRUST_ANCHORS RT_BIT_32(9) + +/** This can be used to only verify one given signer info. + * Max index value is 15. */ +#define RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX(a_idxSignerInfo) \ + ( RTCRPKCS7VERIFY_SD_F_HAS_SIGNER_INDEX \ + | (((a_idxSignerInfo) & RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_MAX) << RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_SHIFT) ) +/** Has a valid value in RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_MASK. */ +#define RTCRPKCS7VERIFY_SD_F_HAS_SIGNER_INDEX RT_BIT_32(23) +/** Signer index shift value. */ +#define RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_SHIFT 24 +/** Signer index mask. */ +#define RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_MASK UINT32_C(0x0f000000) +/** Max signer index value (inclusive). */ +#define RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_MAX \ + (RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_MASK >> RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_SHIFT) + +/** Indicates internally that we're validating a counter signature and should + * use different rules when checking out the authenticated attributes. + * @internal */ +#define RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE RT_BIT_32(31) +/** @} */ + + +RTDECL(int) RTCrPkcs7SimpleSignSignedData(uint32_t fFlags, PCRTCRX509CERTIFICATE pSigner, RTCRKEY hPrivateKey, + void const *pvData, size_t cbData, RTDIGESTTYPE enmDigestType, + RTCRSTORE hAdditionalCerts, PCRTCRPKCS7ATTRIBUTES pAdditionalAuthenticatedAttribs, + void *pvResult, size_t *pcbResult, PRTERRINFO pErrInfo); + +/** @name RTCRPKCS7SIGN_SD_F_XXX - Flags for RTCrPkcs7SimpleSign. + * @{ */ +/** Detached data. */ +#define RTCRPKCS7SIGN_SD_F_DEATCHED RT_BIT_32(0) +/** No SMIME capabilities attribute. */ +#define RTCRPKCS7SIGN_SD_F_NO_SMIME_CAP RT_BIT_32(1) +/** Produce version 1 output (PKCS\#7), rather than version 3 (CMS). */ +#define RTCRPKCS7SIGN_SD_F_USE_V1 RT_BIT_32(2) +/** Avoid extra OCTET STRING encapsulation around the data blob. + * This is needed for Authenticode signatures. This requires that the + * content type is supplied via the additional authenticated attributes. + * @note Currently only works with RTCRPKCS7SIGN_SD_F_USE_V1. */ +#define RTCRPKCS7SIGN_SD_F_NO_DATA_ENCAP RT_BIT_32(3) +/** Valid flag mask. */ +#define RTCRPKCS7SIGN_SD_F_VALID_MASK UINT32_C(0x0000000f) +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_pkcs7_h */ + diff --git a/include/iprt/crypto/pkix.h b/include/iprt/crypto/pkix.h new file mode 100644 index 00000000..98120fbf --- /dev/null +++ b/include/iprt/crypto/pkix.h @@ -0,0 +1,582 @@ +/** @file + * IPRT - Public Key Infrastructure APIs. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_pkix_h +#define IPRT_INCLUDED_crypto_pkix_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/asn1.h> + + +RT_C_DECLS_BEGIN + +struct RTCRX509CERTIFICATE; +struct RTCRX509SUBJECTPUBLICKEYINFO; + +/** @defgroup grp_rt_crpkix RTCrPkix - Public Key Infrastructure APIs + * @ingroup grp_rt_crypto + * @{ + */ + +/** + * Verifies the signature (@a pSignatureValue) of the give data (@a pvData) + * using the specfied public key (@a pPublicKey) and algorithm. + * + * @returns IPRT status code. + * @param pAlgorithm The signature algorithm (digest w/ cipher). + * @param hPublicKey The public key. + * @param pParameters Parameter to the public key algorithm. Optional. + * @param pSignatureValue The signature value. + * @param pvData The signed data. + * @param cbData The amount of signed data. + * @param pErrInfo Where to return extended error info. Optional. + * + * @remarks Depending on the IPRT build configuration, the verficiation may be + * performed more than once using all available crypto implementations. + */ +RTDECL(int) RTCrPkixPubKeyVerifySignature(PCRTASN1OBJID pAlgorithm, RTCRKEY hPublicKey, PCRTASN1DYNTYPE pParameters, + PCRTASN1BITSTRING pSignatureValue, const void *pvData, size_t cbData, + PRTERRINFO pErrInfo); + + +/** + * Verifies the signed digest (@a pvSignedDigest) against our digest (@a + * hDigest) using the specfied public key (@a pPublicKey) and algorithm. + * + * @returns IPRT status code. + * @param pAlgorithm The signature algorithm (digest w/ cipher). + * @param hPublicKey The public key. + * @param pParameters Parameter to the public key algorithm. Optional. + * @param pvSignedDigest The signed digest. + * @param cbSignedDigest The signed digest size. + * @param hDigest The digest of the data to compare @a pvSignedDigest + * with. + * @param pErrInfo Where to return extended error info. Optional. + * + * @remarks Depending on the IPRT build configuration, the verficiation may be + * performed more than once using all available crypto implementations. + */ +RTDECL(int) RTCrPkixPubKeyVerifySignedDigest(PCRTASN1OBJID pAlgorithm, RTCRKEY hPublicKey, PCRTASN1DYNTYPE pParameters, + void const *pvSignedDigest, size_t cbSignedDigest, + RTCRDIGEST hDigest, PRTERRINFO pErrInfo); + +/** + * Wrapper around RTCrPkixPubKeyVerifySignedDigest & RTCrKeyCreateFromAlgorithmAndBits. + * + * @note The public key info must include digest type for this to work. + */ +RTDECL(int) RTCrPkixPubKeyVerifySignedDigestByCertPubKeyInfo(struct RTCRX509SUBJECTPUBLICKEYINFO const *pCertPubKeyInfo, + void const *pvSignedDigest, size_t cbSignedDigest, + RTCRDIGEST hDigest, PRTERRINFO pErrInfo); + +/** + * Checks if the hash size can be handled by the given public key. + */ +RTDECL(bool) RTCrPkixPubKeyCanHandleDigestType(struct RTCRX509SUBJECTPUBLICKEYINFO const *pPublicKeyInfo, + RTDIGESTTYPE enmDigestType, PRTERRINFO pErrInfo); + +/** + * Checks if the hash size can be handled by the given certificate's public key. + */ +RTDECL(bool) RTCrPkixCanCertHandleDigestType(struct RTCRX509CERTIFICATE const *pCertificate, + RTDIGESTTYPE enmDigestType, PRTERRINFO pErrInfo); + +/** + * Signs a digest (@a hDigest) using the specified private key (@a pPrivateKey) and algorithm. + * + * @returns IPRT status code. + * @param pAlgorithm The signature algorithm (digest w/ cipher). + * @param hPrivateKey Handle to the private key to use. + * @param pParameters Parameter to the public key algorithm. Optional. + * @param hDigest The digest of the data being signed. + * @param fFlags Flags for future extensions, MBZ. + * @param pvSignature The output signature buffer. Pass NULL to query + * the signature size. + * @param pcbSignature On input the variable pointed to holds the size of + * the buffer @a pvSignature points to. + * On return the variable pointed to is set to the size + * of the returned signature, or the required size in + * case of VERR_BUFFER_OVERFLOW. + * @param pErrInfo Where to return extended error info. Optional. + * + * @remarks Depending on the IPRT build configuration and the algorithm used, the + * signing may be performed more than once using all available crypto + * implementations. + */ +RTDECL(int) RTCrPkixPubKeySignDigest(PCRTASN1OBJID pAlgorithm, RTCRKEY hPrivateKey, PCRTASN1DYNTYPE pParameters, + RTCRDIGEST hDigest, uint32_t fFlags, + void *pvSignature, size_t *pcbSignature, PRTERRINFO pErrInfo); + +/** + * Gets the cipher OID matching the given signature algorithm. + * + * @returns Cipher OID string on success, NULL on failure. + * @param pAlgorithm The signature algorithm (digest w/ cipher). + */ +RTDECL(const char *) RTCrPkixGetCiperOidFromSignatureAlgorithm(PCRTASN1OBJID pAlgorithm); + + +/** @name PKCS-1 Object Identifiers (OIDs) + * @{ */ +#define RTCR_PKCS1_OID "1.2.840.113549.1.1" +#define RTCR_PKCS1_RSA_OID "1.2.840.113549.1.1.1" +#define RTCR_PKCS1_MD2_WITH_RSA_OID "1.2.840.113549.1.1.2" +#define RTCR_PKCS1_MD4_WITH_RSA_OID "1.2.840.113549.1.1.3" +#define RTCR_PKCS1_MD5_WITH_RSA_OID "1.2.840.113549.1.1.4" +#define RTCR_PKCS1_SHA1_WITH_RSA_OID "1.2.840.113549.1.1.5" +#define RTCR_PKCS1_RSA_OAEP_ENCRYPTION_SET_OID "1.2.840.113549.1.1.6" +#define RTCR_PKCS1_RSA_AES_OAEP_OID "1.2.840.113549.1.1.7" +#define RTCR_PKCS1_MSGF1_OID "1.2.840.113549.1.1.8" +#define RTCR_PKCS1_P_SPECIFIED_OID "1.2.840.113549.1.1.9" +#define RTCR_PKCS1_RSASSA_PSS_OID "1.2.840.113549.1.1.10" +#define RTCR_PKCS1_SHA256_WITH_RSA_OID "1.2.840.113549.1.1.11" +#define RTCR_PKCS1_SHA384_WITH_RSA_OID "1.2.840.113549.1.1.12" +#define RTCR_PKCS1_SHA512_WITH_RSA_OID "1.2.840.113549.1.1.13" +#define RTCR_PKCS1_SHA224_WITH_RSA_OID "1.2.840.113549.1.1.14" +#define RTCR_PKCS1_SHA512T224_WITH_RSA_OID "1.2.840.113549.1.1.15" +#define RTCR_PKCS1_SHA512T256_WITH_RSA_OID "1.2.840.113549.1.1.16" +/** @} */ + + +/** + * Public key signature scheme provider descriptor. + */ +typedef struct RTCRPKIXSIGNATUREDESC +{ + /** The signature scheme provider name. */ + const char *pszName; + /** The object ID string. */ + const char *pszObjId; + /** Pointer to a NULL terminated table of alias object IDs (optional). */ + const char * const *papszObjIdAliases; + /** The size of the state. */ + uint32_t cbState; + /** Reserved for future / explicit padding. */ + uint32_t uReserved; + /** Provider specific field. This generally indicates the kind of padding + * scheme to employ with the given OID. */ + uintptr_t uProviderSpecific; + + /** + * Initializes the state of the signature scheme provider. + * + * Optional, RT_BZERO will be used if NULL. + * + * @returns IPRT status code. + * @param pDesc Pointer to this structure (for uProviderSpecific). + * @param pvState The opaque provider state. + * @param pvOpaque Opaque provider specific parameter. + * @param fSigning Set if a signing operation is going to be performed, + * clear if it is a verification. This is a fixed + * setting for the lifetime of the instance due to the + * algorithm requiring different keys. + * @param hKey The key handle. Caller has retained it for the + * lifetime of the state being initialize. + * @param pParams Algorithm/key parameters, optional. Will be NULL if + * none. + */ + DECLCALLBACKMEMBER(int, pfnInit,(struct RTCRPKIXSIGNATUREDESC const *pDesc, void *pvState, void *pvOpaque, bool fSigning, + RTCRKEY hKey, PCRTASN1DYNTYPE pParams)); + + /** + * Resets the state before performing another signing or verification. + * + * Optional. It is assumed that the provider does not have any state needing to + * be re-initialized if this method is not implemented. + * + * @returns IPRT status code. + * @param pDesc Pointer to this structure (for uProviderSpecific). + * @param pvState The opaque provider state. + * @param fSigning Exactly the same value as the init call. + */ + DECLCALLBACKMEMBER(int, pfnReset,(struct RTCRPKIXSIGNATUREDESC const *pDesc, void *pvState, bool fSigning)); + + /** + * Deletes the provider state. Optional. + * + * The state will be securely wiped clean after the call, regardless of whether + * the method is implemented or not. + * + * @param pDesc Pointer to this structure (for uProviderSpecific). + * @param pvState The opaque provider state. + * @param fSigning Exactly the same value as the init call. + */ + DECLCALLBACKMEMBER(void, pfnDelete,(struct RTCRPKIXSIGNATUREDESC const *pDesc, void *pvState, bool fSigning)); + + /** + * Verifies a signed message digest (fSigning = false). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the signature checked out correctly. + * @retval VINF_CR_DIGEST_DEPRECATED if the signature checked out correctly + * but the hash algorithm is deprecated. + * @retval VINF_CR_DIGEST_COMPROMISED if the signature checked out correctly + * but the hash algorithm is compromised. + * @retval VINF_CR_DIGEST_SEVERELY_COMPROMISED if the signature checked out + * correctly but the hash algorithm is severely compromised. + * @retval VERR_PKIX_KEY wrong key or some other key issue. + * + * @param pDesc Pointer to this structure (for uProviderSpecific). + * @param pvState The opaque provider state. + * @param hKey The key handle associated with the state at init. + * @param hDigest The handle to the digest. Calls RTCrDigestFinal to + * complete and retreive the final hash value. + * @param pvSignature The signature to validate. + * @param cbSignature The size of the signature (in bytes). + */ + DECLCALLBACKMEMBER(int, pfnVerify,(struct RTCRPKIXSIGNATUREDESC const *pDesc, void *pvState, RTCRKEY hKey, + RTCRDIGEST hDigest, void const *pvSignature, size_t cbSignature)); + + /** + * Sign a message digest (fSigning = true). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VINF_CR_DIGEST_DEPRECATED on success but the hash algorithm is deprecated. + * @retval VINF_CR_DIGEST_COMPROMISED on success but the hash algorithm is compromised. + * @retval VINF_CR_DIGEST_SEVERELY_COMPROMISED on success but the hash algorithm + * is severely compromised. + * @retval VERR_PKIX_KEY wrong key or some other key issue. + * @retval VERR_BUFFER_OVERFLOW if the signature buffer is too small, the + * require buffer size will be available in @a *pcbSignature. + * + * @param pDesc Pointer to this structure (for uProviderSpecific). + * @param pvState The opaque provider state. + * @param hKey The key handle associated with the state at init. + * @param hDigest The handle to the digest. Calls RTCrDigestFinal to + * complete and retreive the final hash value. + * @param pvSignature The output signature buffer. + * @param pcbSignature On input the variable pointed to holds the size of + * the buffer @a pvSignature points to. + * On return the variable pointed to is set to the size + * of the returned signature, or the required size in + * case of VERR_BUFFER_OVERFLOW. + */ + DECLCALLBACKMEMBER(int, pfnSign,(struct RTCRPKIXSIGNATUREDESC const *pDesc, void *pvState, RTCRKEY hKey, + RTCRDIGEST hDigest, void *pvSignature, size_t *pcbSignature)); + +} RTCRPKIXSIGNATUREDESC; +/** Pointer to a public key signature scheme provider descriptor. */ +typedef RTCRPKIXSIGNATUREDESC const *PCRTCRPKIXSIGNATUREDESC; + +/** + * Locates a signature schema provider descriptor by object ID string. + * @returns Pointer to descriptor on success, NULL on if not found. + * @param pszObjId The ID of the signature to search for. + * @param ppvOpaque Where to store an opaque schema parameter. Optional. + */ +PCRTCRPKIXSIGNATUREDESC RTCrPkixSignatureFindByObjIdString(const char *pszObjId, void *ppvOpaque); + +/** + * Locates a signature schema provider descriptor by ASN.1 object ID. + * @returns Pointer to descriptor on success, NULL on if not found. + * @param pObjId The ID of the signature to search for. + * @param ppvOpaque Where to store an opaque schema parameter. Optional. + */ +PCRTCRPKIXSIGNATUREDESC RTCrPkixSignatureFindByObjId(PCRTASN1OBJID pObjId, void **ppvOpaque); + +/** + * Create a signature schema provier instance. + * + * @returns IPRT status code. + * @param phSignature Where to return the handle to the created instance. + * @param pDesc The signature schema provider descriptor. Use + * RTCrPkixSignatureFindByObjIdString() or RTCrPkixSignatureFindByObjId() + * to get this. + * @param pvOpaque The opaque schema parameter returned by the find functions. + * @param fSigning Set if the intention is to sign stuff, clear if verification only. + * @param hKey The key handle. A referenced will be retained. + * @param pParams Algorithm/key parameters, optional. + */ +RTDECL(int) RTCrPkixSignatureCreate(PRTCRPKIXSIGNATURE phSignature, PCRTCRPKIXSIGNATUREDESC pDesc, void *pvOpaque, + bool fSigning, RTCRKEY hKey, PCRTASN1DYNTYPE pParams); +/** Convenience wrapper function for RTCrPkixSignatureCreate(). */ +RTDECL(int) RTCrPkixSignatureCreateByObjIdString(PRTCRPKIXSIGNATURE phSignature, const char *pszObjId, + RTCRKEY hKey, PCRTASN1DYNTYPE pParams, bool fSigning); +/** Convenience wrapper function for RTCrPkixSignatureCreate(). */ +RTDECL(int) RTCrPkixSignatureCreateByObjId(PRTCRPKIXSIGNATURE phSignature, PCRTASN1OBJID pObjId, RTCRKEY hKey, + PCRTASN1DYNTYPE pParams, bool fSigning); + +/** + * Retains a reference to the signature schema provider instance. + * + * @returns New reference count on success, UINT32_MAX if invalid handle. + * @param hSignature The signature schema provider handle. + */ +RTDECL(uint32_t) RTCrPkixSignatureRetain(RTCRPKIXSIGNATURE hSignature); + +/** + * Releases a reference to the signature schema provider instance. + * + * @returns New reference count on success, UINT32_MAX if invalid handle. + * @param hSignature The signature schema provider handle. NIL is ignored. + */ +RTDECL(uint32_t) RTCrPkixSignatureRelease(RTCRPKIXSIGNATURE hSignature); + +/** + * Verifies a signed message digest. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the signature checked out correctly. + * @retval VINF_CR_DIGEST_DEPRECATED if the signature checked out correctly + * but the hash algorithm is deprecated. + * @retval VINF_CR_DIGEST_COMPROMISED if the signature checked out correctly + * but the hash algorithm is compromised. + * @retval VINF_CR_DIGEST_SEVERELY_COMPROMISED if the signature checked out + * correctly but the hash algorithm is severely compromised. + * @retval VERR_PKIX_KEY wrong key or some other key issue. + * + * @param hSignature The signature schema provider handle. + * @param hDigest The handle to the digest. All that must have been + * feed to it via RTCrDigestUpdate() and friends prior + * to calling this function. The function will itself + * call RTCrDigestFinal() to complete and retreive the + * final hash value. + * @param pvSignature The signature to validate. + * @param cbSignature The size of the signature (in bytes). + */ +RTDECL(int) RTCrPkixSignatureVerify(RTCRPKIXSIGNATURE hSignature, RTCRDIGEST hDigest, void const *pvSignature, size_t cbSignature); +/** Convenience wrapper function for RTCrPkixSignatureVerify(). */ +RTDECL(int) RTCrPkixSignatureVerifyBitString(RTCRPKIXSIGNATURE hSignature, RTCRDIGEST hDigest, PCRTASN1BITSTRING pSignature); +/** Convenience wrapper function for RTCrPkixSignatureVerify(). */ +RTDECL(int) RTCrPkixSignatureVerifyOctetString(RTCRPKIXSIGNATURE hSignature, RTCRDIGEST hDigest, PCRTASN1OCTETSTRING pSignature); + +/** + * Sign a message digest. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VINF_CR_DIGEST_DEPRECATED on success but the hash algorithm is deprecated. + * @retval VINF_CR_DIGEST_COMPROMISED on success but the hash algorithm is compromised. + * @retval VINF_CR_DIGEST_SEVERELY_COMPROMISED on success but the hash algorithm + * is severely compromised. + * @retval VERR_PKIX_KEY wrong key or some other key issue. + * @retval VERR_BUFFER_OVERFLOW if the signature buffer is too small, the + * require buffer size will be available in @a *pcbSignature. + * + * @param hSignature The signature schema provider handle. + * @param hDigest The handle to the digest. All that must have been + * feed to it via RTCrDigestUpdate() and friends prior + * to calling this function. The function will itself + * call RTCrDigestFinal() to complete and retreive the + * final hash value. + * @param pvSignature The output signature buffer. + * @param pcbSignature On input the variable pointed to holds the size of + * the buffer @a pvSignature points to. + * On return the variable pointed to is set to the size + * of the returned signature, or the required size in + * case of VERR_BUFFER_OVERFLOW. + */ +RTDECL(int) RTCrPkixSignatureSign(RTCRPKIXSIGNATURE hSignature, RTCRDIGEST hDigest, void *pvSignature, size_t *pcbSignature); + + +/** + * Public key encryption scheme provider descriptor. + * + * @todo This is just a sketch left over from when the signature code was + * chiseled out. + */ +typedef struct RTCRPKIXENCRYPTIONDESC +{ + /** The encryption scheme provider name. */ + const char *pszName; + /** The object ID string. */ + const char *pszObjId; + /** Pointer to a NULL terminated table of alias object IDs (optional). */ + const char * const *papszObjIdAliases; + /** The size of the state. */ + uint32_t cbState; + /** Reserved for future use / padding. */ + uint32_t uReserved; + /** Provider specific field. */ + uintptr_t uProviderSpecific; + + /** + * Initializes the state for this encryption scheme. + * + * Optional, RT_BZERO will be used if NULL. + * + * @returns IPRT status code. + * @param pDesc Pointer to this structure (so uProviderSpecific can + * be read). + * @param pvState The opaque provider state. + * @param pvOpaque Opaque provider specific parameter. + * @param fEncrypt Set if the instance will be encrypting, clear if it + * will be decrypting. This aspect of the instance is + * immutable due to the algorithm requiring different + * keys for each of the operations. + * @param pKey The key to use (whether private or public depends on + * the operation type). + * @param pParams Algorithm/key parameters, optional. Will be NULL if + * none. + */ + DECLCALLBACKMEMBER(int, pfnInit,(struct RTCRPKIXENCRYPTIONDESC const *pDesc, void *pvState, void *pvOpaque, bool fEncrypt, + PCRTASN1BITSTRING pKey, PCRTASN1DYNTYPE pParams)); + + /** + * Re-initializes the provider state. + * + * Optional. It is assumed that the provider does not have any state needing + * to be re-initialized if this method is not implemented. (Do not assume that + * a final encrypt/decrypt call has been made prior to this call.) + * + * @returns IPRT status code. + * @param pDesc Pointer to this structure (so uProviderSpecific can + * be read). + * @param pvState The opaque provider state. + * @param enmOperation Same as for the earlier pfnInit call. + */ + DECLCALLBACKMEMBER(int, pfnReset,(struct RTCRPKIXENCRYPTIONDESC const *pDesc, void *pvState, bool fEncrypt)); + + /** + * Deletes the provider state. Optional. + * + * The state will be securely wiped clean after the call, regardless of whether + * the method is implemented or not. + * + * @param pDesc Pointer to this structure (so uProviderSpecific can + * be read). + * @param pvState The opaque provider state. + * @param enmOperation Same as for the earlier pfnInit call. + */ + DECLCALLBACKMEMBER(void, pfnDelete,(struct RTCRPKIXENCRYPTIONDESC const *pDesc, void *pvState, bool fEncrypt)); + + /** + * Encrypt using the public key (fEncrypt = true). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_PKIX_KEY wrong key or some other key issue. + * @retval VERR_BUFFER_OVERFLOW if the output buffer is too small, the require + * buffer size will be available in @a *pcbCiphertext. The caller can + * should retry the call with a larger buffer. + * + * @param pDesc Pointer to this structure (so uProviderSpecific can + * be read). + * @param pvState The opaque provider state. + * @param pvPlaintext The plaintext to encrypt. + * @param cbPlaintext The number of bytes of plaintext. + * @param pvCiphertext Where to return the ciphertext (if any). + * @param cbMaxCiphertext The size of the buffer @a pvCiphertext points to. + * @param pcbCiphertext Where to return the actual number of bytes of + * ciphertext returned. + * @param fFinal Whether this is the final call. + */ + DECLCALLBACKMEMBER(int, pfnEncrypt,(struct RTCRPKIXENCRYPTIONDESC const *pDesc, void *pvState, + void const *pvPlaintext, size_t cbPlaintext, + void *pvCiphertext, size_t cbMaxCiphertext, size_t *pcbCiphertext, bool fFinal)); + + /** + * Calculate the output buffer size for the next pfnEncrypt call. + * + * @returns IPRT status code. + * @param pDesc Pointer to this structure (so uProviderSpecific can + * be read). + * @param pvState The opaque provider state. + * @param cbPlaintext The number of bytes of plaintext. + * @param pcbCiphertext Where to return the minimum buffer size. This may + * be larger than the actual number of bytes return. + * @param fFinal Whether this is the final call. + */ + DECLCALLBACKMEMBER(int, pfnEncryptLength,(struct RTCRPKIXENCRYPTIONDESC const *pDesc, void *pvState, + size_t cbPlaintext, size_t *pcbCiphertext, bool fFinal)); + + /** + * Decrypt using the private key (fEncrypt = false). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_PKIX_KEY wrong key or some other key issue. + * @retval VERR_BUFFER_OVERFLOW if the output buffer is too small, the require + * buffer size will be available in @a *pcbCiphertext. The caller can + * should retry the call with a larger buffer. + * + * @param pDesc Pointer to this structure (so uProviderSpecific can + * be read). + * @param pvState The opaque provider state. + * @param pvCiphertext The ciphertext to decrypt. + * @param cbCiphertext The number of bytes of ciphertext. + * @param pvPlaintext Where to return the plaintext (if any). + * @param cbMaxPlaintext The size of the buffer @a pvPlaintext points to. + * @param pcbPlaintext Where to return the actual number of bytes of + * plaintext returned. + * @param fFinal Whether this is the final call. + */ + DECLCALLBACKMEMBER(int, pfnDecrypt,(struct RTCRPKIXENCRYPTIONDESC const *pDesc, void *pvState, + void const *pvCiphertext, size_t cbCiphertext, + void *pvPlaintext, size_t cbMaxPlaintext, size_t *pcbPlaintext, bool fFinal)); + + /** + * Calculate the output buffer size for the next pfnDecrypt call. + * + * @returns IPRT status code. + * @param pDesc Pointer to this structure (so uProviderSpecific can + * be read). + * @param pvState The opaque provider state. + * @param cbCiphertext The number of bytes of ciphertext. + * @param pcbPlaintext Where to return the minimum buffer size. This may + * be larger than the actual number of bytes return. + * @param fFinal Whether this is the final call. + */ + DECLCALLBACKMEMBER(int, pfnDecryptLength,(struct RTCRPKIXENCRYPTIONDESC const *pDesc, void *pvState, + size_t cbCiphertext, size_t *pcbPlaintext, bool fFinal)); +} RTCRPKIXENCRYPTIONDESC; +/** Pointer to a public key encryption schema provider descriptor. */ +typedef RTCRPKIXENCRYPTIONDESC const *PCRTCRPKIXENCRYPTIONDESC; + + +PCRTCRPKIXENCRYPTIONDESC RTCrPkixEncryptionFindByObjIdString(const char *pszObjId, void *ppvOpaque); +PCRTCRPKIXENCRYPTIONDESC RTCrPkixEncryptionFindByObjId(PCRTASN1OBJID pObjId, void *ppvOpaque); +RTDECL(int) RTCrPkixEncryptionCreateByObjIdString(PRTCRPKIXENCRYPTION phEncryption, const char *pszObjId, + bool fEncrypt, RTCRKEY hKey, PCRTASN1DYNTYPE pParams); +RTDECL(int) RTCrPkixEncryptionCreateByObjId(PRTCRPKIXENCRYPTION phEncryption, PCRTASN1OBJID pObjId, bool fEncrypt, + RTCRKEY hKey, PCRTASN1DYNTYPE pParams); + + +RTDECL(int) RTCrPkixEncryptionCreate(PRTCRPKIXENCRYPTION phEncryption, PCRTCRPKIXENCRYPTIONDESC pDesc, void *pvOpaque, + bool fEncrypt, PCRTASN1BITSTRING pKey, PCRTASN1DYNTYPE pParams); +RTDECL(int) RTCrPkixEncryptionReset(RTCRPKIXENCRYPTION hEncryption); +RTDECL(uint32_t) RTCrPkixEncryptionRetain(RTCRPKIXENCRYPTION hEncryption); +RTDECL(uint32_t) RTCrPkixEncryptionRelease(RTCRPKIXENCRYPTION hEncryption); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_pkix_h */ + diff --git a/include/iprt/crypto/rc4.h b/include/iprt/crypto/rc4.h new file mode 100644 index 00000000..3576116f --- /dev/null +++ b/include/iprt/crypto/rc4.h @@ -0,0 +1,73 @@ +/** @file + * IPRT - Crypto - Alleged RC4 Cipher. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_rc4_h +#define IPRT_INCLUDED_crypto_rc4_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_cr_rc4 RTCrRc4 - Alleged RC4 Cipher. + * @ingroup grp_rt_crypto + * @{ + */ + +/** RC4 key structure. */ +typedef union RTCRRC4KEY +{ + uint64_t au64Padding[(2 + 256) / 2]; +#ifdef HEADER_RC4_H + RC4_KEY Ossl; +#endif +} RTCRRC4KEY; +/** Pointer to a RC4 key structure. */ +typedef RTCRRC4KEY *PRTCRRC4KEY; +/** Pointer to a const RC4 key structure. */ +typedef RTCRRC4KEY const *PCRTCRRC4KEY; + +RTDECL(void) RTCrRc4SetKey(PRTCRRC4KEY pKey, size_t cbData, void const *pvData); +RTDECL(void) RTCrRc4(PRTCRRC4KEY pKey, size_t cbData, void const *pvDataIn, void *pvDataOut); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_rc4_h */ + diff --git a/include/iprt/crypto/rsa.h b/include/iprt/crypto/rsa.h new file mode 100644 index 00000000..34bc4505 --- /dev/null +++ b/include/iprt/crypto/rsa.h @@ -0,0 +1,166 @@ +/** @file + * IPRT - Crypto - RSA Public Key Cryptosystem . + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_rsa_h +#define IPRT_INCLUDED_crypto_rsa_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/asn1.h> +#include <iprt/crypto/x509.h> +#include <iprt/crypto/pkcs7.h> +#include <iprt/md5.h> +#include <iprt/sha.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_cr_rsa RTCrRsa - RSA Public Key Cryptosystem + * @ingroup grp_rt_crypto + * @{ + */ + +/** + * RSA public key - ASN.1 IPRT representation. + */ +typedef struct RTCRRSAPUBLICKEY +{ + /** Sequence core for the structure. */ + RTASN1SEQUENCECORE SeqCore; + /** The modulus (n). */ + RTASN1INTEGER Modulus; + /** The public exponent (e). */ + RTASN1INTEGER PublicExponent; +} RTCRRSAPUBLICKEY; +/** Pointer to the ASN.1 IPRT representation of an RSA public key. */ +typedef RTCRRSAPUBLICKEY *PRTCRRSAPUBLICKEY; +/** Pointer to the const ASN.1 IPRT representation of an RSA public key. */ +typedef RTCRRSAPUBLICKEY const *PCRTCRRSAPUBLICKEY; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRRSAPUBLICKEY, RTDECL, RTCrRsaPublicKey, SeqCore.Asn1Core); + +RTDECL(bool) RTCrRsaPublicKey_CanHandleDigestType(PCRTCRRSAPUBLICKEY pRsaPublicKey, RTDIGESTTYPE enmDigestType, + PRTERRINFO pErrInfo); + + +/** + * RSA other prime info (ASN.1 IPRT representation). + */ +typedef struct RTCRRSAOTHERPRIMEINFO +{ + /** Sequence core for the structure. */ + RTASN1SEQUENCECORE SeqCore; + /** The prime (ri). */ + RTASN1INTEGER Prime; + /** The exponent (di). */ + RTASN1INTEGER Exponent; + /** The coefficient (ti). */ + RTASN1INTEGER Coefficient; +} RTCRRSAOTHERPRIMEINFO; +/** Pointer to the ASN.1 IPRT representation of RSA other prime info. */ +typedef RTCRRSAOTHERPRIMEINFO *PRTCRRSAOTHERPRIMEINFO; +/** Pointer to the const ASN.1 IPRT representation of RSA other prime info. */ +typedef RTCRRSAOTHERPRIMEINFO const *PCRTCRRSAOTHERPRIMEINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRRSAOTHERPRIMEINFO, RTDECL, RTCrRsaOtherPrimeInfo, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRRSAOTHERPRIMEINFOS, RTCRRSAOTHERPRIMEINFO, RTDECL, RTCrRsaOtherPrimeInfos); + +/** + * RSA private key - ASN.1 IPRT representation. + */ +typedef struct RTCRRSAPRIVATEKEY +{ + /** Sequence core for the structure. */ + RTASN1SEQUENCECORE SeqCore; + /** Key version number. */ + RTASN1INTEGER Version; + /** The modulus (n). */ + RTASN1INTEGER Modulus; + /** The public exponent (e). */ + RTASN1INTEGER PublicExponent; + /** The private exponent (d). */ + RTASN1INTEGER PrivateExponent; + /** The first prime factor (p) of the modulus (n). */ + RTASN1INTEGER Prime1; + /** The second prime factor (q) of the modulus (n). */ + RTASN1INTEGER Prime2; + /** The first exponent (d mod (p-1)). */ + RTASN1INTEGER Exponent1; + /** The second exponent (d mod (q-1)). */ + RTASN1INTEGER Exponent2; + /** The coefficient ((inverse of q) mod p). */ + RTASN1INTEGER Coefficient; + /** Optional other prime information (version must be 'multi' if present). */ + RTCRRSAOTHERPRIMEINFOS OtherPrimeInfos; +} RTCRRSAPRIVATEKEY; +/** Pointer to the ASN.1 IPRT representation of an RSA private key. */ +typedef RTCRRSAPRIVATEKEY *PRTCRRSAPRIVATEKEY; +/** Pointer to the const ASN.1 IPRT representation of an RSA private key. */ +typedef RTCRRSAPRIVATEKEY const *PCRTCRRSAPRIVATEKEY; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRRSAPRIVATEKEY, RTDECL, RTCrRsaPrivateKey, SeqCore.Asn1Core); + +/** @name RSA Private Key Versions + * @{ */ +#define RTCRRSAPRIVATEKEY_VERSION_TWO_PRIME 0 +#define RTCRRSAPRIVATEKEY_VERSION_MULTI 1 +/** @} */ + +RTDECL(bool) RTCrRsaPrivateKey_CanHandleDigestType(PCRTCRRSAPRIVATEKEY pRsaPrivateKey, RTDIGESTTYPE enmDigestType, + PRTERRINFO pErrInfo); + + +/** + * RSA DigestInfo used by the EMSA-PKCS1-v1_5 encoding method. + */ +typedef struct RTCRRSADIGESTINFO +{ + /** Sequence core for the structure. */ + RTASN1SEQUENCECORE SeqCore; + /** The digest algorithm. */ + RTCRX509ALGORITHMIDENTIFIER DigestAlgorithm; + /** The digest. */ + RTASN1OCTETSTRING Digest; +} RTCRRSADIGESTINFO; +/** Pointer to the ASN.1 IPRT representation of RSA digest info. */ +typedef RTCRRSADIGESTINFO *PRTCRRSADIGESTINFO; +/** Pointer to the const ASN.1 IPRT representation of RSA digest info. */ +typedef RTCRRSADIGESTINFO const *PCRTCRRSADIGESTINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRRSADIGESTINFO, RTDECL, RTCrRsaDigestInfo, SeqCore.Asn1Core); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_rsa_h */ + diff --git a/include/iprt/crypto/spc.h b/include/iprt/crypto/spc.h new file mode 100644 index 00000000..abe7fe36 --- /dev/null +++ b/include/iprt/crypto/spc.h @@ -0,0 +1,533 @@ +/** @file + * IPRT - Crypto - Microsoft SPC / Authenticode. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_spc_h +#define IPRT_INCLUDED_crypto_spc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/asn1.h> +#include <iprt/crypto/x509.h> +#include <iprt/crypto/pkcs7.h> +#include <iprt/md5.h> +#include <iprt/sha.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_cr_spc RTCrSpc - Microsoft Authenticode + * @ingroup grp_rt_crypto + * @{ + */ + +/** Value for RTCR_PKCS9_ID_MS_STATEMENT_TYPE. */ +#define RTCRSPC_STMT_TYPE_INDIVIDUAL_CODE_SIGNING "1.3.6.1.4.1.311.2.1.21" + +/** + * PE Image page hash table, generic union. + * + * @remarks This table isn't used by ldrPE.cpp, it walks the table in a generic + * fashion using the hash size. So, we can ditch it if we feel like it. + */ +typedef union RTCRSPCPEIMAGEPAGEHASHES +{ + /** MD5 page hashes. */ + struct + { + /** The file offset. */ + uint32_t offFile; + /** The hash. */ + uint8_t abHash[RTSHA1_HASH_SIZE]; + } aMd5[1]; + + /** SHA-1 page hashes. */ + struct + { + /** The file offset. */ + uint32_t offFile; + /** The hash. */ + uint8_t abHash[RTSHA1_HASH_SIZE]; + } aSha1[1]; + + /** SHA-256 page hashes. */ + struct + { + /** The file offset. */ + uint32_t offFile; + /** The hash. */ + uint8_t abHash[RTSHA256_HASH_SIZE]; + } aSha256[1]; + + /** SHA-512 page hashes. */ + struct + { + /** The file offset. */ + uint32_t offFile; + /** The hash. */ + uint8_t abHash[RTSHA512_HASH_SIZE]; + } aSha512[1]; + + /** Generic view of ONE hash. */ + struct + { + /** The file offset. */ + uint32_t offFile; + /** Variable length hash field. */ + uint8_t abHash[1]; + } Generic; +} RTCRSPCPEIMAGEPAGEHASHES; +/** Pointer to a PE image page hash table union. */ +typedef RTCRSPCPEIMAGEPAGEHASHES *PRTCRSPCPEIMAGEPAGEHASHES; +/** Pointer to a const PE image page hash table union. */ +typedef RTCRSPCPEIMAGEPAGEHASHES const *PCRTCRSPCPEIMAGEPAGEHASHES; + + +/** + * Serialization wrapper for raw RTCRSPCPEIMAGEPAGEHASHES data. + */ +typedef struct RTCRSPCSERIALIZEDPAGEHASHES +{ + /** The page hashes are within a set. Dunno if there could be multiple + * entries in this set, never seen it yet, so I doubt it. */ + RTASN1SETCORE SetCore; + /** Octet string containing the raw data. */ + RTASN1OCTETSTRING RawData; + + /** Pointer to the hash data within that string. + * The hash algorithm is given by the object attribute type in + * RTCRSPCSERIALIZEDOBJECTATTRIBUTE. It is generally the same as for the + * whole image hash. */ + PCRTCRSPCPEIMAGEPAGEHASHES pData; + /** Field the user can use to store the number of pages in pData. */ + uint32_t cPages; +} RTCRSPCSERIALIZEDPAGEHASHES; +/** Pointer to a serialized wrapper for page hashes. */ +typedef RTCRSPCSERIALIZEDPAGEHASHES *PRTCRSPCSERIALIZEDPAGEHASHES; +/** Pointer to a const serialized wrapper for page hashes. */ +typedef RTCRSPCSERIALIZEDPAGEHASHES const *PCRTCRSPCSERIALIZEDPAGEHASHES; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCSERIALIZEDPAGEHASHES, RTDECL, RTCrSpcSerializedPageHashes, SetCore.Asn1Core); + +RTDECL(int) RTCrSpcSerializedPageHashes_UpdateDerivedData(PRTCRSPCSERIALIZEDPAGEHASHES pThis); + + +/** + * Data type selection for RTCRSPCSERIALIZEDOBJECTATTRIBUTE. + */ +typedef enum RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE +{ + /** Invalid zero entry. */ + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_INVALID = 0, + /** Not present pro forma. */ + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_NOT_PRESENT, + /** Unknown object. */ + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_UNKNOWN, + /** SHA-1 page hashes (pPageHashes). */ + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V1, + /** SHA-256 page hashes (pPageHashes). */ + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V2, + /** End of valid values. */ + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_END, + /** Blow up the type to at least 32-bits. */ + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_32BIT_HACK +} RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE; + +/** + * One serialized object attribute (PE image data). + */ +typedef struct RTCRSPCSERIALIZEDOBJECTATTRIBUTE +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The attribute type. */ + RTASN1OBJID Type; + /** The allocation of the data type. */ + RTASN1ALLOCATION Allocation; + /** Indicates the valid value in the union. */ + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE enmType; + /** Union with data format depending on the Type. */ + union + { + /** The unknown value (RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_UNKNOWN). */ + PRTASN1CORE pCore; + /** Page hashes (RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V1 or + * RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V2). */ + PRTCRSPCSERIALIZEDPAGEHASHES pPageHashes; + } u; +} RTCRSPCSERIALIZEDOBJECTATTRIBUTE; +/** Pointer to a serialized object attribute. */ +typedef RTCRSPCSERIALIZEDOBJECTATTRIBUTE *PRTCRSPCSERIALIZEDOBJECTATTRIBUTE; +/** Pointer to a const serialized object attribute. */ +typedef RTCRSPCSERIALIZEDOBJECTATTRIBUTE const *PCRTCRSPCSERIALIZEDOBJECTATTRIBUTE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCSERIALIZEDOBJECTATTRIBUTE, RTDECL, RTCrSpcSerializedObjectAttribute, SeqCore.Asn1Core); + +RTDECL(int) RTCrSpcSerializedObjectAttribute_SetV1Hashes(PRTCRSPCSERIALIZEDOBJECTATTRIBUTE pThis, + PCRTCRSPCSERIALIZEDPAGEHASHES, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrSpcSerializedObjectAttribute_SetV2Hashes(PRTCRSPCSERIALIZEDOBJECTATTRIBUTE pThis, + PCRTCRSPCSERIALIZEDPAGEHASHES, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** @name RTCRSPCSERIALIZEDOBJECTATTRIBUTE::Type values + * @{ */ +/** Serialized object attribute type for page hashes version 1. */ +#define RTCRSPC_PE_IMAGE_HASHES_V1_OID "1.3.6.1.4.1.311.2.3.1" +/** Serialized object attribute type for page hashes version 2. */ +#define RTCRSPC_PE_IMAGE_HASHES_V2_OID "1.3.6.1.4.1.311.2.3.2" +/** @} */ + + +/* + * Set of serialized object attributes (PE image data). + */ +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRSPCSERIALIZEDOBJECTATTRIBUTES, RTCRSPCSERIALIZEDOBJECTATTRIBUTE, RTDECL, + RTCrSpcSerializedObjectAttributes); + +/** The UUID found in RTCRSPCSERIALIZEDOBJECT::Uuid for + * RTCRSPCSERIALIZEDOBJECTATTRIBUTES. */ +#define RTCRSPCSERIALIZEDOBJECT_UUID_STR "d586b5a6-a1b4-6624-ae05-a217da8e60d6" + + +/** + * Decoded encapsulated data type selection in RTCRSPCSERIALIZEDOBJECT. + */ +typedef enum RTCRSPCSERIALIZEDOBJECTTYPE +{ + /** Invalid zero value. */ + RTCRSPCSERIALIZEDOBJECTTYPE_INVALID = 0, + /** Serialized object attributes (RTCRSPCSERIALIZEDOBJECT_UUID_STR / pAttribs). */ + RTCRSPCSERIALIZEDOBJECTTYPE_ATTRIBUTES, + /** End of valid values. */ + RTCRSPCSERIALIZEDOBJECTTYPE_END, + /** MAke sure the type is at least 32-bit wide. */ + RTCRSPCSERIALIZEDOBJECTTYPE_32BIT_HACK = 0x7fffffff +} RTCRSPCSERIALIZEDOBJECTTYPE; + +/** + * A serialized object (PE image data). + */ +typedef struct RTCRSPCSERIALIZEDOBJECT +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The UUID of the data object. */ + RTASN1OCTETSTRING Uuid; + /** Serialized data object. */ + RTASN1OCTETSTRING SerializedData; + + /** Indicates the valid pointer in the union. */ + RTCRSPCSERIALIZEDOBJECTTYPE enmType; + /** Union of pointers shadowing SerializedData.pEncapsulated. */ + union + { + /** Generic core pointer. */ + PRTASN1CORE pCore; + /** Pointer to decoded data if Uuid is RTCRSPCSERIALIZEDOBJECT_UUID_STR. */ + PRTCRSPCSERIALIZEDOBJECTATTRIBUTES pData; + } u; +} RTCRSPCSERIALIZEDOBJECT; +/** Pointer to a serialized object (PE image data). */ +typedef RTCRSPCSERIALIZEDOBJECT *PRTCRSPCSERIALIZEDOBJECT; +/** Pointer to a const serialized object (PE image data). */ +typedef RTCRSPCSERIALIZEDOBJECT const *PCRTCRSPCSERIALIZEDOBJECT; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCSERIALIZEDOBJECT, RTDECL, RTCrSpcSerializedObject, SeqCore.Asn1Core); + + +/** + * RTCRSPCSTRING choices. + */ +typedef enum RTCRSPCSTRINGCHOICE +{ + /** Invalid zero value. */ + RTCRSPCSTRINGCHOICE_INVALID = 0, + /** Not present. */ + RTCRSPCSTRINGCHOICE_NOT_PRESENT, + /** UCS-2 string (pUcs2). */ + RTCRSPCSTRINGCHOICE_UCS2, + /** ASCII string (pAscii). */ + RTCRSPCSTRINGCHOICE_ASCII, + /** End of valid values. */ + RTCRSPCSTRINGCHOICE_END, + /** Blow the type up to 32-bit. */ + RTCRSPCSTRINGCHOICE_32BIT_HACK = 0x7fffffff +} RTCRSPCSTRINGCHOICE; + +/** + * Stupid microsoft choosy string type. + */ +typedef struct RTCRSPCSTRING +{ + /** Dummy core. */ + RTASN1DUMMY Dummy; + /** Allocation of what the pointer below points to. */ + RTASN1ALLOCATION Allocation; + /** Pointer choice.*/ + RTCRSPCSTRINGCHOICE enmChoice; + /** Pointer union. */ + union + { + /** Tag 0, implicit: UCS-2 (BMP) string. */ + PRTASN1STRING pUcs2; + /** Tag 1, implicit: ASCII (IA5) string. */ + PRTASN1STRING pAscii; + } u; +} RTCRSPCSTRING; +/** Pointer to a stupid microsoft string choice. */ +typedef RTCRSPCSTRING *PRTCRSPCSTRING; +/** Pointer to a const stupid microsoft string choice. */ +typedef RTCRSPCSTRING const *PCRTCRSPCSTRING; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCSTRING, RTDECL, RTCrSpcString, Dummy.Asn1Core); + +RTDECL(int) RTCrSpcString_SetUcs2(PRTCRSPCSTRING pThis, PCRTASN1STRING pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrSpcString_SetAscii(PRTCRSPCSTRING pThis, PCRTASN1STRING pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); + + +/** + * RTCRSPCSTRING choices. + */ +typedef enum RTCRSPCLINKCHOICE +{ + /** Invalid zero value. */ + RTCRSPCLINKCHOICE_INVALID = 0, + /** Not present. */ + RTCRSPCLINKCHOICE_NOT_PRESENT, + /** URL (ASCII) string (pUrl). */ + RTCRSPCLINKCHOICE_URL, + /** Serialized object (pMoniker). */ + RTCRSPCLINKCHOICE_MONIKER, + /** Filename (pT2). */ + RTCRSPCLINKCHOICE_FILE, + /** End of valid values. */ + RTCRSPCLINKCHOICE_END, + /** Blow the type up to 32-bit. */ + RTCRSPCLINKCHOICE_32BIT_HACK = 0x7fffffff +} RTCRSPCLINKCHOICE; + +/** + * PE image data link. + */ +typedef struct RTCRSPCLINK +{ + /** Dummy core. */ + RTASN1DUMMY Dummy; + /** Allocation of what the pointer below points to. */ + RTASN1ALLOCATION Allocation; + /** Pointer choice.*/ + RTCRSPCLINKCHOICE enmChoice; + /** Pointer union. */ + union + { + /** Tag 0, implicit: An URL encoded as an IA5 STRING. */ + PRTASN1STRING pUrl; + /** Tag 1, implicit: A serialized object. */ + PRTCRSPCSERIALIZEDOBJECT pMoniker; + /** Tag 2, explicit: The default, a file name. + * Documented to be set to "<<<Obsolete>>>" when used. */ + struct + { + /** Context tag 2. */ + RTASN1CONTEXTTAG2 CtxTag2; + /** The file name string. */ + RTCRSPCSTRING File; + } *pT2; + } u; +} RTCRSPCLINK; +/** Poitner to a PE image data link. */ +typedef RTCRSPCLINK *PRTCRSPCLINK; +/** Poitner to a const PE image data link. */ +typedef RTCRSPCLINK const *PCRTCRSPCLINK; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCLINK, RTDECL, RTCrSpcLink, Dummy.Asn1Core); + +RTDECL(int) RTCrSpcLink_SetUrl(PRTCRSPCLINK pThis, PCRTASN1STRING pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrSpcLink_SetMoniker(PRTCRSPCLINK pThis, PCRTCRSPCSERIALIZEDOBJECT pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrSpcLink_SetFile(PRTCRSPCLINK pThis, PCRTCRSPCSTRING pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); + + +#if 0 /** @todo Might not be the correct bit order. */ +/** + * Flag values for RTCRSPCPEIMAGEDATA::Flags and RTCRSPCPEIMAGEDATA::fFlags. + */ +typedef enum RTCRSPCPEIMAGEFLAGS +{ + RTCRSPCPEIMAGEFLAGS_INCLUDE_RESOURCES = 0, + RTCRSPCPEIMAGEFLAGS_INCLUDE_DEBUG_INFO = 1, + RTCRSPCPEIMAGEFLAGS_IMPORT_ADDRESS_TABLE = 2 +} RTCRSPCPEIMAGEFLAGS; +#endif + + +/** + * Authenticode PE Image data. + */ +typedef struct RTCRSPCPEIMAGEDATA +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** One of the RTCRSPCPEIMAGEFLAGS value, default is + * RTCRSPCPEIMAGEFLAGS_INCLUDE_RESOURCES. Obsolete with v2 page hashes? */ + RTASN1BITSTRING Flags; + /** Tag 0, explicit: Link to the data. */ + struct + { + /** Context tag 0. */ + RTASN1CONTEXTTAG0 CtxTag0; + /** Link to the data. */ + RTCRSPCLINK File; + } T0; +} RTCRSPCPEIMAGEDATA; +/** Pointer to a authenticode PE image data representation. */ +typedef RTCRSPCPEIMAGEDATA *PRTCRSPCPEIMAGEDATA; +/** Pointer to a const authenticode PE image data representation. */ +typedef RTCRSPCPEIMAGEDATA const *PCRTCRSPCPEIMAGEDATA; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCPEIMAGEDATA, RTDECL, RTCrSpcPeImageData, SeqCore.Asn1Core); + +RTDECL(int) RTCrSpcPeImageData_SetFlags(PRTCRSPCPEIMAGEDATA pThis, PCRTASN1BITSTRING pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); +RTDECL(int) RTCrSpcPeImageData_SetFile(PRTCRSPCPEIMAGEDATA pThis, PCRTCRSPCLINK pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** The object ID for SpcPeImageData. */ +#define RTCRSPCPEIMAGEDATA_OID "1.3.6.1.4.1.311.2.1.15" + + +/** + * Data type selection for RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE. + */ +typedef enum RTCRSPCAAOVTYPE +{ + /** Invalid zero entry. */ + RTCRSPCAAOVTYPE_INVALID = 0, + /** Not present (pro forma). */ + RTCRSPCAAOVTYPE_NOT_PRESENT, + /** Unknown object. */ + RTCRSPCAAOVTYPE_UNKNOWN, + /** PE image data (pPeImage). */ + RTCRSPCAAOVTYPE_PE_IMAGE_DATA, + /** End of valid values. */ + RTCRSPCAAOVTYPE_END, + /** Blow up the type to at least 32-bits. */ + RTCRSPCAAOVTYPE_32BIT_HACK +} RTCRSPCAAOVTYPE; + +/** + * Authenticode attribute type and optional value. + * + * Note! Spec says the value should be explicitly tagged, but in real life + * it isn't. So, not very optional? + */ +typedef struct RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** An object ID indicating the type of the value. */ + RTASN1OBJID Type; + /** Allocation of the optional data value. */ + RTASN1ALLOCATION Allocation; + /** The valid pointer. */ + RTCRSPCAAOVTYPE enmType; + /** The value part depends on the Type. */ + union + { + /** RTCRSPCAAOVTYPE_UNKNOWN / Generic. */ + PRTASN1CORE pCore; + /** RTCRSPCAAOVTYPE_PE_IMAGE_DATA / RTCRSPCPEIMAGEDATA_OID. */ + PRTCRSPCPEIMAGEDATA pPeImage; + } uValue; +} RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE; +/** Pointer to a authentication attribute type and optional value + * representation. */ +typedef RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE *PRTCRSPCATTRIBUTETYPEANDOPTIONALVALUE; +/** Pointer to a const authentication attribute type and optional value + * representation. */ +typedef RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE const *PCRTCRSPCATTRIBUTETYPEANDOPTIONALVALUE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE, RTDECL, RTCrSpcAttributeTypeAndOptionalValue, SeqCore.Asn1Core); + +RTDECL(int) RTCrSpcAttributeTypeAndOptionalValue_SetPeImage(PRTCRSPCATTRIBUTETYPEANDOPTIONALVALUE pThis, + PCRTCRSPCPEIMAGEDATA pToClone, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Authenticode indirect data content. + */ +typedef struct RTCRSPCINDIRECTDATACONTENT +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** Additional data. */ + RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE Data; + /** The whole image digest. */ + RTCRPKCS7DIGESTINFO DigestInfo; +} RTCRSPCINDIRECTDATACONTENT; +/** Pointer to a authenticode indirect data content representation. */ +typedef RTCRSPCINDIRECTDATACONTENT *PRTCRSPCINDIRECTDATACONTENT; +/** Pointer to a const authenticode indirect data content representation. */ +typedef RTCRSPCINDIRECTDATACONTENT const *PCRTCRSPCINDIRECTDATACONTENT; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCINDIRECTDATACONTENT, RTDECL, RTCrSpcIndirectDataContent, SeqCore.Asn1Core); + +/** The object ID for SpcIndirectDataContent. */ +#define RTCRSPCINDIRECTDATACONTENT_OID "1.3.6.1.4.1.311.2.1.4" + +/** + * Check the sanity of an Authenticode SPCIndirectDataContent object. + * + * @returns IPRT status code + * @param pIndData The Authenticode SPCIndirectDataContent to + * check. + * @param pSignedData The related signed data object. + * @param fFlags RTCRSPCINDIRECTDATACONTENT_SANITY_F_XXX. + * @param pErrInfo Optional error info. + */ +RTDECL(int) RTCrSpcIndirectDataContent_CheckSanityEx(PCRTCRSPCINDIRECTDATACONTENT pIndData, PCRTCRPKCS7SIGNEDDATA pSignedData, + uint32_t fFlags, PRTERRINFO pErrInfo); +/** @name RTCRSPCINDIRECTDATACONTENT_SANITY_F_XXX for RTCrSpcIndirectDataContent_CheckSanityEx. + * @{ */ +/** The digest hash algorithm must be known to IPRT. */ +#define RTCRSPCINDIRECTDATACONTENT_SANITY_F_ONLY_KNOWN_HASH RT_BIT_32(0) +/** PE image signing, check expectations of the spec. */ +#define RTCRSPCINDIRECTDATACONTENT_SANITY_F_PE_IMAGE RT_BIT_32(1) +/** @} */ + +/** + * Gets the first SPC serialized object attribute in a SPC PE image. + * + * @returns Pointer to the attribute with the given type, NULL if not found. + * @param pThis The Authenticode SpcIndirectDataContent. + * @param enmType The type of attribute to get. + */ +RTDECL(PCRTCRSPCSERIALIZEDOBJECTATTRIBUTE) +RTCrSpcIndirectDataContent_GetPeImageObjAttrib(PCRTCRSPCINDIRECTDATACONTENT pThis, + RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE enmType); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_spc_h */ + diff --git a/include/iprt/crypto/ssl.h b/include/iprt/crypto/ssl.h new file mode 100644 index 00000000..5c69811b --- /dev/null +++ b/include/iprt/crypto/ssl.h @@ -0,0 +1,143 @@ +/** @file + * IPRT - Secure Socket Layer (SSL) / Transport Security Layer (TLS) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_ssl_h +#define IPRT_INCLUDED_crypto_ssl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/sg.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_crssl RTCrSsl - Secure Socket Layer (SSL) / Transport Security Layer (TLS) + * @ingroup grp_rt_crypto + * @{ + */ + +/** SSL handle. */ +typedef R3PTRTYPE(struct RTCRSSLINT *) RTCRSSL; +/** Pointer to a SSL handle. */ +typedef RTCRSSL *PRTCRSSL; +/** Nil SSL handle. */ +#define NIL_RTCRSSL ((RTCRSSL)0) + +/** SSL session handle. */ +typedef R3PTRTYPE(struct RTCRSSLSESSIONINT *) RTCRSSLSESSION; +/** Pointer to a SSL session handle. */ +typedef RTCRSSLSESSION *PRTCRSSLSESSION; +/** Nil SSL session handle. */ +#define NIL_RTCRSSLSESSION ((RTCRSSLSESSION)0) + + +RTDECL(int) RTCrSslCreate(PRTCRSSL phSsl, uint32_t fFlags); + +/** + * Retains a reference to the SSL handle. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hSsl The SSL handle. + */ +RTDECL(uint32_t) RTCrSslRetain(RTCRSSL hSsl); + +/** + * Release a reference to the SSL handle. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hSsl The SSL handle. The NIL handle is quietly + * ignored and 0 is returned. + */ +RTDECL(uint32_t) RTCrSslRelease(RTCRSSL hSsl); + +#define RTCRSSL_FILE_F_PEM 0 +#define RTCRSSL_FILE_F_ASN1 RT_BIT_32(1) + +RTDECL(int) RTCrSslSetCertificateFile(RTCRSSL hSsl, const char *pszFile, uint32_t fFlags); +RTDECL(int) RTCrSslSetPrivateKeyFile(RTCRSSL hSsl, const char *pszFile, uint32_t fFlags); +RTDECL(int) RTCrSslLoadTrustedRootCerts(RTCRSSL hSsl, const char *pszFile, const char *pszDir); +RTDECL(int) RTCrSslSetNoPeerVerify(RTCRSSL hSsl); +/** @todo Min/max protocol setters. */ + + + +RTDECL(int) RTCrSslCreateSession(RTCRSSL hSsl, RTSOCKET hSocket, uint32_t fFlags, PRTCRSSLSESSION phSslSession); +RTDECL(int) RTCrSslCreateSessionForNativeSocket(RTCRSSL hSsl, RTHCINTPTR hNativeSocket, uint32_t fFlags, + PRTCRSSLSESSION phSslSession); +/** @name RTCRSSLSESSION_F_XXX - Flags for RTCrSslCreateSession and RTCrSslCreateSessionForNativeSocket. + * @{ */ +/** The socket is non-blocking. */ +#define RTCRSSLSESSION_F_NON_BLOCKING RT_BIT_32(0) +/** @} */ + +/** + * Retains a reference to the SSL session handle. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hSslSession The SSL session handle. + */ +RTDECL(uint32_t) RTCrSslSessionRetain(RTCRSSLSESSION hSslSession); + +/** + * Release a reference to the SSL handle. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hSslSession The SSL session handle. The NIL handle is quietly + * ignored and 0 is returned. + */ +RTDECL(uint32_t) RTCrSslSessionRelease(RTCRSSLSESSION hSslSession); + +RTDECL(int) RTCrSslSessionAccept(RTCRSSLSESSION hSslSession, uint32_t fFlags); +RTDECL(int) RTCrSslSessionConnect(RTCRSSLSESSION hSslSession, uint32_t fFlags); + +RTDECL(const char *) RTCrSslSessionGetVersion(RTCRSSLSESSION hSslSession); +RTDECL(int) RTCrSslSessionGetCertIssuerNameAsString(RTCRSSLSESSION hSslSession, char *pszBuf, size_t cbBuf, size_t *pcbActual); +RTDECL(bool) RTCrSslSessionPending(RTCRSSLSESSION hSslSession); +RTDECL(ssize_t) RTCrSslSessionRead(RTCRSSLSESSION hSslSession, void *pvBuf, size_t cbToRead); +RTDECL(ssize_t) RTCrSslSessionWrite(RTCRSSLSESSION hSslSession, void const *pvBuf, size_t cbToWrite); + + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_ssl_h */ + diff --git a/include/iprt/crypto/store.h b/include/iprt/crypto/store.h new file mode 100644 index 00000000..c25e21e7 --- /dev/null +++ b/include/iprt/crypto/store.h @@ -0,0 +1,410 @@ +/** @file + * IPRT - Cryptographic (Certificate) Store. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_store_h +#define IPRT_INCLUDED_crypto_store_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/crypto/x509.h> +#include <iprt/crypto/taf.h> +#include <iprt/sha.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_crstore RTCrStore - Crypotgraphic (Certificate) Store. + * @ingroup grp_rt_crypto + * @{ + */ + + +/** + * A certificate store search. + * + * Used by the store provider to keep track of the current location of a + * certificate search. + */ +typedef struct RTCRSTORECERTSEARCH +{ + /** Opaque provider specific storage. + * + * Provider restriction: The provider is only allowed to use the two first + * entries for the find-all searches, because the front-end API may want the + * last two for implementing specific searches on top of it. */ + uintptr_t auOpaque[4]; +} RTCRSTORECERTSEARCH; +/** Pointer to a certificate store search. */ +typedef RTCRSTORECERTSEARCH *PRTCRSTORECERTSEARCH; + + +/** + * Info about a wanted certificate. + * + * All the search criteria are optional, but for a safe and efficient search + * it's recommended to specify all possible ones. If none are given, the search + * function will fail. + * + * For use with RTCrStoreCertAddFromFishingExpedition and others. + */ +typedef struct RTCRCERTWANTED +{ + /** The certificate subject name, optional. + * The format is: "C=US, ST=California, L=Redwood Shores, O=Oracle Corporation" */ + const char *pszSubject; + /** The size of the DER (ASN.1) encoded certificate, optional (0). */ + uint16_t cbEncoded; + /** Set if abSha1 contains a valid SHA-1 fingerprint. */ + bool fSha1Fingerprint; + /** Set if abSha512 contains a valid SHA-512 fingerprint. */ + bool fSha512Fingerprint; + /** The SHA-1 fingerprint (of the encoded data). */ + uint8_t abSha1[RTSHA1_HASH_SIZE]; + /** The SHA-512 fingerprint (of the encoded data). */ + uint8_t abSha512[RTSHA512_HASH_SIZE]; + /** User pointer for directly associating other data with the entry. + * Subclassing the structure isn't possible because it's passed as an array. */ + void const *pvUser; +} RTCRCERTWANTED; +/** Pointer to a const certificat wanted structure. */ +typedef RTCRCERTWANTED const *PCRTCRCERTWANTED; + + +/** + * Standard store identifiers. + * + * This is a least common denominator approach to system specific certificate + * stores, could be extended to include things other than certificates later if + * we need it. + * + * Windows has lots of different stores, they'll be combined by the + * implementation, possibly leading to duplicates. The user stores on Windows + * seems to be unioned with the system (machine) stores. + * + * Linux may have different stores depending on the distro/version/installation, + * in which case we'll combine them, which will most likely lead to + * duplicates just like on windows. Haven't found any easily accessible + * per-user certificate stores on linux yet, so they'll all be empty. + * + * Mac OS X seems a lot simpler, at least from the GUI point of view. Each + * keychains as a "Certificates" folder (the "My Certificates" folder seems to + * only be a matching of "Keys" and "Certificates"). However, there are two + * system keychains that we need to combine, "System" and "System Roots". As + * with Windows and Linux, there is a possibility for duplicates here. + * + * On solaris we have currently no idea where to look for a certificate store, + * so that doesn't yet work. + * + * Because of the OS X setup, we do not provide any purpose specific + */ +typedef enum RTCRSTOREID +{ + /** Mandatory invalid zero value. */ + RTCRSTOREID_INVALID = 0, + /** Open the certificate store of the current user containing trusted + * CAs and certificates. + * @remarks This may or may not include all the certificates in the system + * store, that's host dependent. So, you better look in both. */ + RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES, + /** Open the certificate store of the system containg trusted CAs + * and certificates. */ + RTCRSTOREID_SYSTEM_TRUSTED_CAS_AND_CERTIFICATES, + /** Open the certificate store of the current user containing intermediate CAs. + * @remarks This may or may not include all the certificates in the system + * store, that's host dependent. So, you better look in both. */ + RTCRSTOREID_USER_INTERMEDIATE_CAS, + /** Open the certificate store of the system containg intermediate CAs. */ + RTCRSTOREID_SYSTEM_INTERMEDIATE_CAS, + /** End of valid values. */ + RTCRSTOREID_END, + /** Traditional enum type compression prevention hack. */ + RTCRSTOREID_32BIT_HACK = 0x7fffffff +} RTCRSTOREID; + +/** + * Creates a snapshot of a standard store. + * + * This will return an in-memory store containing all data from the given store. + * There will be no duplicates in this one. + * + * @returns IPRT status code. + * @param phStore Where to return the store handle. Use + * RTCrStoreRelease to release it. + * @param enmStoreId The store to snapshot. + * @param pErrInfo Where to return additional error/warning info. + * Optional. + */ +RTDECL(int) RTCrStoreCreateSnapshotById(PRTCRSTORE phStore, RTCRSTOREID enmStoreId, PRTERRINFO pErrInfo); + +RTDECL(int) RTCrStoreCreateSnapshotOfUserAndSystemTrustedCAsAndCerts(PRTCRSTORE phStore, PRTERRINFO pErrInfo); + +RTDECL(int) RTCrStoreCreateInMem(PRTCRSTORE phStore, uint32_t cSizeHint); +RTDECL(int) RTCrStoreCreateInMemEx(PRTCRSTORE phStore, uint32_t cSizeHint, RTCRSTORE hParentStore); + +RTDECL(uint32_t) RTCrStoreRetain(RTCRSTORE hStore); +RTDECL(uint32_t) RTCrStoreRelease(RTCRSTORE hStore); +RTDECL(PCRTCRCERTCTX) RTCrStoreCertByIssuerAndSerialNo(RTCRSTORE hStore, PCRTCRX509NAME pIssuer, PCRTASN1INTEGER pSerialNo); + +/** + * Add a certificate to the store. + * + * @returns IPRT status code. + * @retval VWRN_ALREADY_EXISTS if the certificate is already present and + * RTCRCERTCTX_F_ADD_IF_NOT_FOUND was specified. + * @retval VERR_WRITE_PROTECT if the store doesn't support adding. + * @param hStore The store to add the certificate to. + * @param fFlags RTCRCERTCTX_F_XXX. Encoding must be specified. + * RTCRCERTCTX_F_ADD_IF_NOT_FOUND is supported. + * @param pvSrc The encoded certificate bytes. + * @param cbSrc The size of the encoded certificate. + * @param pErrInfo Where to return additional error/warning info. + * Optional. + */ +RTDECL(int) RTCrStoreCertAddEncoded(RTCRSTORE hStore, uint32_t fFlags, void const *pvSrc, size_t cbSrc, PRTERRINFO pErrInfo); + +/** + * Add an X.509 packaged certificate to the store. + * + * @returns IPRT status code. + * @retval VWRN_ALREADY_EXISTS if the certificate is already present and + * RTCRCERTCTX_F_ADD_IF_NOT_FOUND was specified. + * @retval VERR_WRITE_PROTECT if the store doesn't support adding. + * @param hStore The store to add the certificate to. + * @param fFlags RTCRCERTCTX_F_XXX. Encoding must is optional, + * but must be RTCRCERTCTX_F_ENC_X509_DER if given. + * RTCRCERTCTX_F_ADD_IF_NOT_FOUND is supported. + * @param pCertificate The certificate to add. We may have to encode + * it, thus not const. + * @param pErrInfo Where to return additional error/warning info. + * Optional. + */ +RTDECL(int) RTCrStoreCertAddX509(RTCRSTORE hStore, uint32_t fFlags, PRTCRX509CERTIFICATE pCertificate, PRTERRINFO pErrInfo); + +/** + * Adds certificates from files in the specified directory. + * + * @returns IPRT status code. Even when RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR is + * used, an error is returned as an error (and not a warning). + * + * @param hStore The store to add the certificate(s) to. + * @param fFlags RTCRCERTCTX_F_ADD_IF_NOT_FOUND and/or + * RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR. + * @param pszDir The path to the directory. + * @param paSuffixes List of suffixes of files to process. + * @param cSuffixes Number of suffixes. If this is 0, all files are + * processed. + * @param pErrInfo Where to return additional error/warning info. + * Optional. + */ +RTDECL(int) RTCrStoreCertAddFromDir(RTCRSTORE hStore, uint32_t fFlags, const char *pszDir, + PCRTSTRTUPLE paSuffixes, size_t cSuffixes, PRTERRINFO pErrInfo); + +RTDECL(int) RTCrStoreCertAddWantedFromDir(RTCRSTORE hStore, uint32_t fFlags, + const char *pszDir, PCRTSTRTUPLE paSuffixes, size_t cSuffixes, + PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo); + +/** + * Adds certificates from the specified file. + * + * The supported file formats are: + * - PEM (base 64 blobs wrapped in -----BEGIN / END----). Support multiple + * certificates in one file. + * - Binary DER ASN.1 certificate. Only one per file. + * - Java key store version 2. + * + * @returns IPRT status code. Even when RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR is + * used, an error is returned as an error (and not a warning). + * + * @param hStore The store to add the certificate(s) to. + * @param fFlags RTCRCERTCTX_F_ADD_IF_NOT_FOUND and/or + * RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR. + * @param pszFilename The filename. + * @param pErrInfo Where to return additional error/warning info. + * Optional. + */ +RTDECL(int) RTCrStoreCertAddFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo); + +RTDECL(int) RTCrStoreCertAddWantedFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, + PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo); + +/** + * Adds certificates from the specified java key store file. + * + * @returns IPRT status code. Even when RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR is + * used, an error is returned as an error (and not a warning). + * + * @param hStore The store to add the certificate(s) to. + * @param fFlags RTCRCERTCTX_F_ADD_IF_NOT_FOUND and/or + * RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR. + * @param pszFilename The path to the JKS file. + * @param pErrInfo Where to return additional error/warning info. + * Optional. + */ +RTDECL(int) RTCrStoreCertAddFromJavaKeyStore(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo); + +/** + * Adds certificates from an in-memory java key store. + * + * @returns IPRT status code. Even when RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR is + * used, an error is returned as an error (and not a warning). + * + * @param hStore The store to add the certificate(s) to. + * @param fFlags RTCRCERTCTX_F_ADD_IF_NOT_FOUND and/or + * RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR. + * @param pvContent Pointer to the key store bytes. + * @param cbContent The size of the key store. + * @param pszErrorName The file name or whatever helpful indicator the + * caller want in the error messages. + * @param pErrInfo Where to return additional error/warning info. + * Optional. + */ +RTDECL(int) RTCrStoreCertAddFromJavaKeyStoreInMem(RTCRSTORE hStore, uint32_t fFlags, void const *pvContent, size_t cbContent, + const char *pszErrorName, PRTERRINFO pErrInfo); + +/** + * Adds all certificates from @a hStoreSrc into @a hStore. + * + * @returns IPRT status code. Even when RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR is + * used, an error is returned as an error (and not a warning). + * + * @param hStore The destination store. + * @param fFlags RTCRCERTCTX_F_ADD_IF_NOT_FOUND and/or + * RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR. + * @param hStoreSrc The source store. + */ +RTDECL(int) RTCrStoreCertAddFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hStoreSrc); + +RTDECL(int) RTCrStoreCertAddWantedFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hSrcStore, + PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound); + +RTDECL(int) RTCrStoreCertCheckWanted(RTCRSTORE hStore, PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound); + + +RTDECL(int) RTCrStoreCertAddWantedFromFishingExpedition(RTCRSTORE hStore, uint32_t fFlags, + PCRTCRCERTWANTED paWanted, size_t cWanted, + bool *pafFound, PRTERRINFO pErrInfo); + +/** + * Exports the certificates in the store to a PEM file + * + * @returns IPRT status code. + * @param hStore The store which certificates should be exported. + * @param fFlags Reserved for the future, MBZ. + * @param pszFilename The name of the destination PEM file. This will + * be truncated. + */ +RTDECL(int) RTCrStoreCertExportAsPem(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename); + +/** + * Counts the number of certificates in the store. + * + * @returns Certificate count on success, UINT32_MAX on failure. + * @param hStore The store which certificates should be counted. + */ +RTDECL(uint32_t) RTCrStoreCertCount(RTCRSTORE hStore); + +RTDECL(int) RTCrStoreCertFindAll(RTCRSTORE hStore, PRTCRSTORECERTSEARCH pSearch); +RTDECL(int) RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280(RTCRSTORE hStore, PCRTCRX509NAME pSubject, + PRTCRSTORECERTSEARCH pSearch); +RTDECL(PCRTCRCERTCTX) RTCrStoreCertSearchNext(RTCRSTORE hStore, PRTCRSTORECERTSEARCH pSearch); +RTDECL(int) RTCrStoreCertSearchDestroy(RTCRSTORE hStore, PRTCRSTORECERTSEARCH pSearch); + +RTDECL(int) RTCrStoreConvertToOpenSslCertStore(RTCRSTORE hStore, uint32_t fFlags, void **ppvOpenSslStore, PRTERRINFO pErrInfo); +RTDECL(int) RTCrStoreConvertToOpenSslCertStack(RTCRSTORE hStore, uint32_t fFlags, void **ppvOpenSslStack, PRTERRINFO pErrInfo); + + +/** @} */ + + +/** @defgroup grp_rt_crcertctx RTCrCertCtx - (Store) Certificate Context. + * @{ */ + + +/** + * Certificate context. + * + * This is returned by the certificate store APIs and is part of a larger + * reference counted structure. All the data is read only. + */ +typedef struct RTCRCERTCTX +{ + /** Flags, RTCRCERTCTX_F_XXX. */ + uint32_t fFlags; + /** The size of the (DER) encoded certificate. */ + uint32_t cbEncoded; + /** Pointer to the (DER) encoded certificate. */ + uint8_t const *pabEncoded; + /** Pointer to the decoded X.509 representation of the certificate. + * This can be NULL when pTaInfo is present. */ + PCRTCRX509CERTIFICATE pCert; + /** Pointer to the decoded TrustAnchorInfo for the certificate. This can be + * NULL, even for trust anchors, as long as pCert isn't. */ + PCRTCRTAFTRUSTANCHORINFO pTaInfo; + /** Reserved for future use. */ + void *paReserved[2]; +} RTCRCERTCTX; + +/** @name RTCRCERTCTX_F_XXX. + * @{ */ +/** Encoding mask. */ +#define RTCRCERTCTX_F_ENC_MASK UINT32_C(0x000000ff) +/** X.509 certificate, DER encoded. */ +#define RTCRCERTCTX_F_ENC_X509_DER UINT32_C(0x00000000) +/** RTF-5914 trust anchor info, DER encoded. */ +#define RTCRCERTCTX_F_ENC_TAF_DER UINT32_C(0x00000001) +#if 0 +/** Extended certificate, DER encoded. */ +#define RTCRCERTCTX_F_ENC_PKCS6_DER UINT32_C(0x00000002) +#endif +/** Mask containing the flags that ends up in the certificate context. */ +#define RTCRCERTCTX_F_MASK UINT32_C(0x000000ff) + +/** Add APIs: Add the certificate if not found. */ +#define RTCRCERTCTX_F_ADD_IF_NOT_FOUND UINT32_C(0x00010000) +/** Add APIs: Continue on error when possible. */ +#define RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR UINT32_C(0x00020000) +/** @} */ + + +RTDECL(uint32_t) RTCrCertCtxRetain(PCRTCRCERTCTX pCertCtx); +RTDECL(uint32_t) RTCrCertCtxRelease(PCRTCRCERTCTX pCertCtx); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_store_h */ + diff --git a/include/iprt/crypto/taf.h b/include/iprt/crypto/taf.h new file mode 100644 index 00000000..4966a7b2 --- /dev/null +++ b/include/iprt/crypto/taf.h @@ -0,0 +1,202 @@ +/** @file + * IPRT - Crypto - Trust Anchor Format (RFC-5914). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_taf_h +#define IPRT_INCLUDED_crypto_taf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/asn1.h> +#include <iprt/crypto/x509.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_crtaf RTCrTaf - Trust Anchor Format (RFC-5914) + * @ingroup grp_rt_crypto + * @{ + */ + + +/** + * RFC-5914 CertPathControls (IPRT representation). + */ +typedef struct RTCRTAFCERTPATHCONTROLS +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The trust anchor subject. For use in path construction. */ + RTCRX509NAME TaName; + /** Certificate, optional, implicit tag 0. */ + RTCRX509CERTIFICATE Certificate; + /** Certificate policies, optional, implicit tag 1. + * @remarks This is an ASN.1 SEQUENCE, not an ASN.1 SET as the name + * mistakenly might be taken to indicate. */ + RTCRX509CERTIFICATEPOLICIES PolicySet; + /** Policy flags, optional, implicit tag 2. */ + RTASN1BITSTRING PolicyFlags; + /** Name constraints, optional, implicit tag 3. */ + RTCRX509NAMECONSTRAINTS NameConstr; + /** Path length constraints, optional, implicit tag 4. */ + RTASN1INTEGER PathLenConstraint; +} RTCRTAFCERTPATHCONTROLS; +/** Pointer to the IPRT representation of a RFC-5914 CertPathControls. */ +typedef RTCRTAFCERTPATHCONTROLS *PRTCRTAFCERTPATHCONTROLS; +/** Pointer to the const IPRT representation of a RFC-5914 CertPathControls. */ +typedef RTCRTAFCERTPATHCONTROLS const *PCRTCRTAFCERTPATHCONTROLS; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRTAFCERTPATHCONTROLS, RTDECL, RTCrTafCertPathControls, SeqCore.Asn1Core); + +/** @name Bit definitions for RTCRTAFCERTPATHCONTROL::PolicyFlags + * @{ */ +#define RTCRTAFCERTPOLICYFLAGS_INHIBIT_POLICY_MAPPING 0 +#define RTCRTAFCERTPOLICYFLAGS_REQUIRE_EXPLICIT_POLICY 1 +#define RTCRTAFCERTPOLICYFLAGS_INHIBIT_ANY_POLICY 2 +/** @} */ + + +/** + * RFC-5914 TrustAnchorInfo (IPRT representation). + */ +typedef struct RTCRTAFTRUSTANCHORINFO +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The version number (defaults to v1). */ + RTASN1INTEGER Version; + /** The public key of the trust anchor. */ + RTCRX509SUBJECTPUBLICKEYINFO PubKey; + /** Key identifier. */ + RTASN1OCTETSTRING KeyIdentifier; + /** Trust anchor title, optional, size 1 to 64. */ + RTASN1STRING TaTitle; + /** Certificate path controls, optional. */ + RTCRTAFCERTPATHCONTROLS CertPath; + /** Extensions, explicit optional, context tag 1. */ + struct + { + /** Context tag 1. */ + RTASN1CONTEXTTAG1 CtxTag1; + /** The extensions. */ + RTCRX509EXTENSIONS Exts; + } T1; + /** Title language tag, implicit optional, context tag 2. + * Defaults to "en". */ + RTASN1STRING TaTitleLangTag; +} RTCRTAFTRUSTANCHORINFO; +/** Pointer to the IPRT representation of a RFC-5914 TrustAnchorInfo. */ +typedef RTCRTAFTRUSTANCHORINFO *PRTCRTAFTRUSTANCHORINFO; +/** Pointer to the const IPRT representation of a RFC-5914 TrustAnchorInfo. */ +typedef RTCRTAFTRUSTANCHORINFO const *PCRTCRTAFTRUSTANCHORINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRTAFTRUSTANCHORINFO, RTDECL, RTCrTafTrustAnchorInfo, SeqCore.Asn1Core); + +/** TrustAnchorInfo version 1. */ +#define RTCRTAFTRUSTANCHORINFO_V1 1 + + +/** Indicates what kind of value a TrustAnchorChoice structure contains. */ +typedef enum RTCRTAFTRUSTANCHORCHOICEVAL +{ + /** Invalid zero value. */ + RTCRTAFTRUSTANCHORCHOICEVAL_INVALID = 0, + /** RTCRTAFTRUSTANCHORCHOICE::u.pCertificate. */ + RTCRTAFTRUSTANCHORCHOICEVAL_CERTIFICATE, + /** RTCRTAFTRUSTANCHORCHOICE::u.pT1. */ + RTCRTAFTRUSTANCHORCHOICEVAL_TBS_CERTIFICATE, + /** RTCRTAFTRUSTANCHORCHOICE::u.pT2. */ + RTCRTAFTRUSTANCHORCHOICEVAL_TRUST_ANCHOR_INFO, + /** End of valid choices. */ + RTCRTAFTRUSTANCHORCHOICEVAL_END, + /** Make sure it's (at least) 32-bit wide. */ + RTCRTAFTRUSTANCHORCHOICEVAL_32BIT_HACK = 0x7fffffff +} RTCRTAFTRUSTANCHORCHOICEVAL; + + +/** + * RFC-5914 TrustAnchorChoice (IPRT representation). + */ +typedef struct RTCRTAFTRUSTANCHORCHOICE +{ + /** Dummy object for simplifying everything. */ + RTASN1DUMMY Dummy; + /** Allocation for the valid member (to optimize space usage). */ + RTASN1ALLOCATION Allocation; + /** Indicates which of the pointers are valid. */ + RTCRTAFTRUSTANCHORCHOICEVAL enmChoice; + /** Choice union. */ + union + { + /** Generic ASN.1 core pointer for the choice. */ + PRTASN1CORE pAsn1Core; + /** Choice 0: X509 certificate. */ + PRTCRX509CERTIFICATE pCertificate; + /** Choice 1: To-be-signed certificate part. This may differ from the + * TBSCertificate member of the original certificate. */ + struct + { + /** Explicit context tag. */ + RTASN1CONTEXTTAG1 CtxTag1; + /** Pointer to the TBS certificate structure. */ + RTCRX509TBSCERTIFICATE TbsCert; + } *pT1; + + /** Choice 2: To-be-signed certificate part. This may differ from the + * TBSCertificate member of the original certificate. */ + struct + { + /** Explicit context tag. */ + RTASN1CONTEXTTAG2 CtxTag2; + /** Pointer to the trust anchor infomration structure. */ + RTCRTAFTRUSTANCHORINFO TaInfo; + } *pT2; + } u; +} RTCRTAFTRUSTANCHORCHOICE; +/** Pointer to the IPRT representation of a RFC-5914 TrustAnchorChoice. */ +typedef RTCRTAFTRUSTANCHORCHOICE *PRTCRTAFTRUSTANCHORCHOICE; +/** Pointer to the const IPRT representation of a RFC-5914 TrustAnchorChoice. */ +typedef RTCRTAFTRUSTANCHORCHOICE const *PCRTCRTAFTRUSTANCHORCHOICE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRTAFTRUSTANCHORCHOICE, RTDECL, RTCrTafTrustAnchorChoice, Dummy.Asn1Core); + +/* + * RFC-5914 TrustAnchorList (IPRT representation). + */ +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRTAFTRUSTANCHORLIST, RTCRTAFTRUSTANCHORCHOICE, RTDECL, RTCrTafTrustAnchorList); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_taf_h */ + diff --git a/include/iprt/crypto/tsp.h b/include/iprt/crypto/tsp.h new file mode 100644 index 00000000..8b421044 --- /dev/null +++ b/include/iprt/crypto/tsp.h @@ -0,0 +1,148 @@ +/** @file + * IPRT - Crypto - Time-Stamp Protocol (RFC-3161). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_tsp_h +#define IPRT_INCLUDED_crypto_tsp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/asn1.h> +#include <iprt/crypto/x509.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_cr_tap RTCrTap - Time-Stamp Protocol (RFC-3161) + * @ingroup grp_rt_crypto + * @{ + */ + + +/** + * RFC-3161 MessageImprint (IPRT representation). + */ +typedef struct RTCRTSPMESSAGEIMPRINT +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The digest algorithm used to produce HashedMessage. */ + RTCRX509ALGORITHMIDENTIFIER HashAlgorithm; + /** The digest of the message being timestamped. */ + RTASN1OCTETSTRING HashedMessage; +} RTCRTSPMESSAGEIMPRINT; +/** Pointer to the IPRT representation of a RFC-3161 MessageImprint. */ +typedef RTCRTSPMESSAGEIMPRINT *PRTCRTSPMESSAGEIMPRINT; +/** Pointer to the const IPRT representation of a RFC-3161 MessageImprint. */ +typedef RTCRTSPMESSAGEIMPRINT const *PCRTCRTSPMESSAGEIMPRINT; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRTSPMESSAGEIMPRINT, RTDECL, RTCrTspMessageImprint, SeqCore.Asn1Core); + + +/** + * RFC-3161 Accuracy (IPRT representation). + */ +typedef struct RTCRTSPACCURACY +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The seconds accuracy. + * This will be larger than 0. If 1 inspect the Millis field. */ + RTASN1INTEGER Seconds; + /** The millisecond accuracy, optional, implicit tag 0. + * Range 1..999. If 1 inspect the Micros field. */ + RTASN1INTEGER Millis; + /** The microsecond accuracy, optional, implicit tag 1. + * Range 1..999. */ + RTASN1INTEGER Micros; +} RTCRTSPACCURACY; +/** Pointer to the IPRT representation of a RFC-3161 Accuracy. */ +typedef RTCRTSPACCURACY *PRTCRTSPACCURACY; +/** Pointer to the const IPRT representation of a RFC-3161 Accuracy. */ +typedef RTCRTSPACCURACY const *PCRTCRTSPACCURACY; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRTSPACCURACY, RTDECL, RTCrTspAccuracy, SeqCore.Asn1Core); + + +/** + * RFC-3161 TSTInfo (IPRT representation). + */ +typedef struct RTCRTSPTSTINFO +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The structure version number, current only 1 is valid. */ + RTASN1INTEGER Version; + /** Time authority policy. */ + RTASN1OBJID Policy; + /** The message imprint. */ + RTCRTSPMESSAGEIMPRINT MessageImprint; + /** Timestamp request serial number. */ + RTASN1INTEGER SerialNumber; + /** The timestamp. */ + RTASN1TIME GenTime; + /** The timestamp accuracy, optional. */ + RTCRTSPACCURACY Accuracy; + /** Ordering, whatever that means, defaults to FALSE. */ + RTASN1BOOLEAN Ordering; + /** Nonce, optional. */ + RTASN1INTEGER Nonce; + /** Timestamp authority name, explicit optional. + * (Should match a name in the certificate of the signature.) */ + struct + { + /** Context tag 0. */ + RTASN1CONTEXTTAG0 CtxTag0; + /** The TSA name. */ + RTCRX509GENERALNAME Tsa; + } T0; + /** Extensions, optional, implicit tag 1. */ + RTCRX509EXTENSION Extensions; +} RTCRTSPTSTINFO; +/** Pointer to the IPRT representation of a RFC-3161 TSTInfo. */ +typedef RTCRTSPTSTINFO *PRTCRTSPTSTINFO; +/** Pointer to the const IPRT representation of a RFC-3161 TSTInfo. */ +typedef RTCRTSPTSTINFO const *PCRTCRTSPTSTINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRTSPTSTINFO, RTDECL, RTCrTspTstInfo, SeqCore.Asn1Core); + +/** The object identifier for RTCRTSPTSTINFO. + * Found in the ContentType field of PKCS \#7's ContentInfo structure and + * the equivalent CMS field. */ +#define RTCRTSPTSTINFO_OID "1.2.840.113549.1.9.16.1.4" + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_crypto_tsp_h */ + diff --git a/include/iprt/crypto/x509.h b/include/iprt/crypto/x509.h new file mode 100644 index 00000000..41f5bcc0 --- /dev/null +++ b/include/iprt/crypto/x509.h @@ -0,0 +1,1180 @@ +/** @file + * IPRT - Crypto - X.509, Public Key and Privilege Management Infrastructure. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_crypto_x509_h +#define IPRT_INCLUDED_crypto_x509_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/asn1.h> +#include <iprt/crypto/pem.h> + + +RT_C_DECLS_BEGIN + +struct RTCRPKCS7SETOFCERTS; + + +/** @defgroup grp_rt_crypto Crypto + * @ingroup grp_rt + * @{ + */ + +/** @defgroup grp_rt_crx509 RTCrX509 - Public Key and Privilege Management Infrastructure. + * @{ + */ + +/** + * X.509 algorithm identifier (IPRT representation). + */ +typedef struct RTCRX509ALGORITHMIDENTIFIER +{ + /** The sequence making up this algorithm identifier. */ + RTASN1SEQUENCECORE SeqCore; + /** The algorithm object ID. */ + RTASN1OBJID Algorithm; + /** Optional parameters specified by the algorithm. */ + RTASN1DYNTYPE Parameters; +} RTCRX509ALGORITHMIDENTIFIER; +/** Poitner to the IPRT representation of a X.509 algorithm identifier. */ +typedef RTCRX509ALGORITHMIDENTIFIER *PRTCRX509ALGORITHMIDENTIFIER; +/** Poitner to the const IPRT representation of a X.509 algorithm identifier. */ +typedef RTCRX509ALGORITHMIDENTIFIER const *PCRTCRX509ALGORITHMIDENTIFIER; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509ALGORITHMIDENTIFIER, RTDECL, RTCrX509AlgorithmIdentifier, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRX509ALGORITHMIDENTIFIERS, RTCRX509ALGORITHMIDENTIFIER, RTDECL, RTCrX509AlgorithmIdentifiers); + +/** + * Tries to convert an X.509 digest algorithm ID into a RTDIGESTTYPE value. + * + * @returns Valid RTDIGESTTYPE on success, RTDIGESTTYPE_INVALID on failure. + * @param pThis The IPRT representation of a X.509 algorithm + * identifier object. + */ +RTDECL(RTDIGESTTYPE) RTCrX509AlgorithmIdentifier_QueryDigestType(PCRTCRX509ALGORITHMIDENTIFIER pThis); + +/** + * Tries to figure the digest size of an X.509 digest algorithm ID. + * + * @returns The digest size in bytes, UINT32_MAX if unknown digest. + * @param pThis The IPRT representation of a X.509 algorithm + * identifier object. + */ +RTDECL(uint32_t) RTCrX509AlgorithmIdentifier_QueryDigestSize(PCRTCRX509ALGORITHMIDENTIFIER pThis); + +RTDECL(int) RTCrX509AlgorithmIdentifier_CompareWithString(PCRTCRX509ALGORITHMIDENTIFIER pThis, const char *pszObjId); + +/** + * Compares a digest with an encrypted digest algorithm, checking if they + * specify the same digest. + * + * @returns 0 if same digest, -1 if the digest is unknown, 1 if the encrypted + * digest does not match. + * @param pDigest The digest algorithm. + * @param pEncryptedDigest The encrypted digest algorithm. + */ +RTDECL(int) RTCrX509AlgorithmIdentifier_CompareDigestAndEncryptedDigest(PCRTCRX509ALGORITHMIDENTIFIER pDigest, + PCRTCRX509ALGORITHMIDENTIFIER pEncryptedDigest); +/** + * Compares a digest OID with an encrypted digest algorithm OID, checking if + * they specify the same digest. + * + * @returns 0 if same digest, -1 if the digest is unknown, 1 if the encrypted + * digest does not match. + * @param pszDigestOid The digest algorithm OID. + * @param pszEncryptedDigestOid The encrypted digest algorithm OID. + */ +RTDECL(int) RTCrX509AlgorithmIdentifier_CompareDigestOidAndEncryptedDigestOid(const char *pszDigestOid, + const char *pszEncryptedDigestOid); + + +/** + * Combine the encryption algorithm with the digest algorithm. + * + * @returns OID of encrypted digest algorithm. + * @param pEncryption The encryption algorithm. Will work if this is + * the OID of an encrypted digest algorithm too, as + * long as it matches @a pDigest. + * @param pDigest The digest algorithm. Will work if this is the + * OID of an encrypted digest algorithm too, as + * long as it matches @a pEncryption. + */ +RTDECL(const char *) RTCrX509AlgorithmIdentifier_CombineEncryptionAndDigest(PCRTCRX509ALGORITHMIDENTIFIER pEncryption, + PCRTCRX509ALGORITHMIDENTIFIER pDigest); + +/** + * Combine the encryption algorithm OID with the digest algorithm OID. + * + * @returns OID of encrypted digest algorithm. + * @param pszEncryptionOid The encryption algorithm. Will work if this is + * the OID of an encrypted digest algorithm too, as + * long as it matches @a pszDigestOid. + * @param pszDigestOid The digest algorithm. Will work if this is the + * OID of an encrypted digest algorithm too, as + * long as it matches @a pszEncryptionOid. + */ +RTDECL(const char *) RTCrX509AlgorithmIdentifier_CombineEncryptionOidAndDigestOid(const char *pszEncryptionOid, + const char *pszDigestOid); + + +/** @name Typical Digest Algorithm OIDs. + * @{ */ +#define RTCRX509ALGORITHMIDENTIFIERID_MD2 "1.2.840.113549.2.2" +#define RTCRX509ALGORITHMIDENTIFIERID_MD4 "1.2.840.113549.2.4" +#define RTCRX509ALGORITHMIDENTIFIERID_MD5 "1.2.840.113549.2.5" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA1 "1.3.14.3.2.26" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA256 "2.16.840.1.101.3.4.2.1" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA384 "2.16.840.1.101.3.4.2.2" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA512 "2.16.840.1.101.3.4.2.3" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA224 "2.16.840.1.101.3.4.2.4" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA512T224 "2.16.840.1.101.3.4.2.5" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA512T256 "2.16.840.1.101.3.4.2.6" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA3_224 "2.16.840.1.101.3.4.2.7" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA3_256 "2.16.840.1.101.3.4.2.8" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA3_384 "2.16.840.1.101.3.4.2.9" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA3_512 "2.16.840.1.101.3.4.2.10" +#define RTCRX509ALGORITHMIDENTIFIERID_WHIRLPOOL "1.0.10118.3.0.55" +/** @} */ + +/** @name Encrypted Digest Algorithm OIDs. + * @remarks The PKCS variants are the default ones, alternative OID are marked + * as such. + * @{ */ +#define RTCRX509ALGORITHMIDENTIFIERID_RSA "1.2.840.113549.1.1.1" +#define RTCRX509ALGORITHMIDENTIFIERID_MD2_WITH_RSA "1.2.840.113549.1.1.2" +#define RTCRX509ALGORITHMIDENTIFIERID_MD4_WITH_RSA "1.2.840.113549.1.1.3" +#define RTCRX509ALGORITHMIDENTIFIERID_MD5_WITH_RSA "1.2.840.113549.1.1.4" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA1_WITH_RSA "1.2.840.113549.1.1.5" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA256_WITH_RSA "1.2.840.113549.1.1.11" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA384_WITH_RSA "1.2.840.113549.1.1.12" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA512_WITH_RSA "1.2.840.113549.1.1.13" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA224_WITH_RSA "1.2.840.113549.1.1.14" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA512T224_WITH_RSA "1.2.840.113549.1.1.15" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA512T256_WITH_RSA "1.2.840.113549.1.1.16" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA3_224_WITH_RSA "2.16.840.1.101.3.4.3.13" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA3_256_WITH_RSA "2.16.840.1.101.3.4.3.14" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA3_384_WITH_RSA "2.16.840.1.101.3.4.3.15" +#define RTCRX509ALGORITHMIDENTIFIERID_SHA3_512_WITH_RSA "2.16.840.1.101.3.4.3.16" +/** @} */ + + + + +/** + * One X.509 AttributeTypeAndValue (IPRT representation). + */ +typedef struct RTCRX509ATTRIBUTETYPEANDVALUE +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The attribute type (object ID). */ + RTASN1OBJID Type; + /** The attribute value (what it is is defined by Type). */ + RTASN1DYNTYPE Value; +} RTCRX509ATTRIBUTETYPEANDVALUE; +/** Pointer to a X.509 AttributeTypeAndValue (IPRT representation). */ +typedef RTCRX509ATTRIBUTETYPEANDVALUE *PRTCRX509ATTRIBUTETYPEANDVALUE; +/** Pointer to a const X.509 AttributeTypeAndValue (IPRT representation). */ +typedef RTCRX509ATTRIBUTETYPEANDVALUE const *PCRTCRX509ATTRIBUTETYPEANDVALUE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509ATTRIBUTETYPEANDVALUE, RTDECL, RTCrX509AttributeTypeAndValue, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRX509ATTRIBUTETYPEANDVALUES, RTCRX509ATTRIBUTETYPEANDVALUE, RTDECL, RTCrX509AttributeTypeAndValues); + +RTASN1TYPE_ALIAS(RTCRX509RELATIVEDISTINGUISHEDNAME, RTCRX509ATTRIBUTETYPEANDVALUES, RTCrX509RelativeDistinguishedName, RTCrX509AttributeTypeAndValues); + + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRX509NAME, RTCRX509RELATIVEDISTINGUISHEDNAME, RTDECL, RTCrX509Name); +RTDECL(int) RTCrX509Name_CheckSanity(PCRTCRX509NAME pName, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag); +RTDECL(bool) RTCrX509Name_MatchByRfc5280(PCRTCRX509NAME pLeft, PCRTCRX509NAME pRight); + +/** + * Name constraint matching (RFC-5280). + * + * @returns true on match, false on mismatch. + * @param pConstraint The constraint name. + * @param pName The name to match against the constraint. + * @sa RTCrX509GeneralName_ConstraintMatch, + * RTCrX509RelativeDistinguishedName_ConstraintMatch + */ +RTDECL(bool) RTCrX509Name_ConstraintMatch(PCRTCRX509NAME pConstraint, PCRTCRX509NAME pName); +RTDECL(int) RTCrX509Name_RecodeAsUtf8(PRTCRX509NAME pThis, PCRTASN1ALLOCATORVTABLE pAllocator); + +/** + * Matches the directory name against a comma separated list of the component + * strings (case sensitive). + * + * @returns true if match, false if mismatch. + * @param pThis The name object. + * @param pszString The string to match against. For example: + * "C=US, ST=California, L=Redwood Shores, O=Oracle Corporation" + * + * @remarks This is doing a straight compare, no extra effort is expended in + * dealing with different component order. If the component order + * differs, there won't be any match. + */ +RTDECL(bool) RTCrX509Name_MatchWithString(PCRTCRX509NAME pThis, const char *pszString); + +/** + * Formats the name as a command separated list of components with type + * prefixes. + * + * The output of this function is suitable for use with + * RTCrX509Name_MatchWithString. + * + * @returns IPRT status code. + * @param pThis The name object. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pcbActual Where to return the number of bytes required for the + * output, including the null terminator character. + * Optional. + */ +RTDECL(int) RTCrX509Name_FormatAsString(PCRTCRX509NAME pThis, char *pszBuf, size_t cbBuf, size_t *pcbActual); + + +/** + * Looks up the RDN ID and returns the short name for it, if found. + * + * @returns Short name (e.g. 'CN') or NULL. + * @param pRdnId The RDN ID to look up. + */ +RTDECL(const char *) RTCrX509Name_GetShortRdn(PCRTASN1OBJID pRdnId); + +/** + * One X.509 OtherName (IPRT representation). + */ +typedef struct RTCRX509OTHERNAME +{ + /** The sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The name type identifier. */ + RTASN1OBJID TypeId; + /** The name value (explicit tag 0). */ + RTASN1DYNTYPE Value; +} RTCRX509OTHERNAME; +/** Pointer to a X.509 OtherName (IPRT representation). */ +typedef RTCRX509OTHERNAME *PRTCRX509OTHERNAME; +/** Pointer to a const X.509 OtherName (IPRT representation). */ +typedef RTCRX509OTHERNAME const *PCRTCRX509OTHERNAME; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509OTHERNAME, RTDECL, RTCrX509OtherName, SeqCore.Asn1Core); + + +typedef enum RTCRX509GENERALNAMECHOICE +{ + RTCRX509GENERALNAMECHOICE_INVALID = 0, + RTCRX509GENERALNAMECHOICE_OTHER_NAME, + RTCRX509GENERALNAMECHOICE_RFC822_NAME, + RTCRX509GENERALNAMECHOICE_DNS_NAME, + RTCRX509GENERALNAMECHOICE_X400_ADDRESS, + RTCRX509GENERALNAMECHOICE_DIRECTORY_NAME, + RTCRX509GENERALNAMECHOICE_EDI_PARTY_NAME, + RTCRX509GENERALNAMECHOICE_URI, + RTCRX509GENERALNAMECHOICE_IP_ADDRESS, + RTCRX509GENERALNAMECHOICE_REGISTERED_ID, + RTCRX509GENERALNAMECHOICE_END, + RTCRX509GENERALNAMECHOICE_32BIT_HACK = 0x7fffffff +} RTCRX509GENERALNAMECHOICE; + +/** + * One X.509 GeneralName (IPRT representation). + * + * This is represented as a union. Use the RTCRX509GENERALNAME_IS_XXX predicate + * macros to figure out which member is valid (Asn1Core is always valid). + */ +typedef struct RTCRX509GENERALNAME +{ + /** Dummy ASN.1 record, not encoded. */ + RTASN1DUMMY Dummy; + /** The value allocation. */ + RTASN1ALLOCATION Allocation; + /** The choice of value. */ + RTCRX509GENERALNAMECHOICE enmChoice; + /** The value union. */ + union + { + /** Tag 0: Other Name. */ + PRTCRX509OTHERNAME pT0_OtherName; + /** Tag 1: RFC-822 Name. */ + PRTASN1STRING pT1_Rfc822; + /** Tag 2: DNS name. */ + PRTASN1STRING pT2_DnsName; + /** Tag 3: X.400 Address. */ + struct + { + /** Context tag 3. */ + RTASN1CONTEXTTAG3 CtxTag3; + /** Later. */ + RTASN1DYNTYPE X400Address; + } *pT3; + /** Tag 4: Directory Name. */ + struct + { + /** Context tag 4. */ + RTASN1CONTEXTTAG4 CtxTag4; + /** Directory name. */ + RTCRX509NAME DirectoryName; + } *pT4; + /** Tag 5: EDI Party Name. */ + struct + { + /** Context tag 5. */ + RTASN1CONTEXTTAG5 CtxTag5; + /** Later. */ + RTASN1DYNTYPE EdiPartyName; + } *pT5; + /** Tag 6: URI. */ + PRTASN1STRING pT6_Uri; + /** Tag 7: IP address. Either 4/8 (IPv4) or 16/32 (IPv16) octets long. */ + PRTASN1OCTETSTRING pT7_IpAddress; + /** Tag 8: Registered ID. */ + PRTASN1OBJID pT8_RegisteredId; + } u; +} RTCRX509GENERALNAME; +/** Pointer to the IPRT representation of an X.509 general name. */ +typedef RTCRX509GENERALNAME *PRTCRX509GENERALNAME; +/** Pointer to the const IPRT representation of an X.509 general name. */ +typedef RTCRX509GENERALNAME const *PCRTCRX509GENERALNAME; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509GENERALNAME, RTDECL, RTCrX509GeneralName, Dummy.Asn1Core); + +/** @name RTCRX509GENERALNAME tag predicates. + * @{ */ +#define RTCRX509GENERALNAME_IS_OTHER_NAME(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_OTHER_NAME) +#define RTCRX509GENERALNAME_IS_RFC822_NAME(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_RFC822_NAME) +#define RTCRX509GENERALNAME_IS_DNS_NAME(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_DNS_NAME) +#define RTCRX509GENERALNAME_IS_X400_ADDRESS(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_X400_ADDRESS) +#define RTCRX509GENERALNAME_IS_DIRECTORY_NAME(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_DIRECTORY_NAME) +#define RTCRX509GENERALNAME_IS_EDI_PARTY_NAME(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_EDI_PARTY_NAME) +#define RTCRX509GENERALNAME_IS_URI(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_URI) +#define RTCRX509GENERALNAME_IS_IP_ADDRESS(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_IP_ADDRESS) +#define RTCRX509GENERALNAME_IS_REGISTERED_ID(a_GenName) ((a_GenName)->enmChoice == RTCRX509GENERALNAMECHOICE_REGISTERED_ID) +/** @} */ + + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRX509GENERALNAMES, RTCRX509GENERALNAME, RTDECL, RTCrX509GeneralNames); +RTDECL(bool) RTCrX509GeneralName_ConstraintMatch(PCRTCRX509GENERALNAME pConstraint, PCRTCRX509GENERALNAME pName); + + +/** + * X.509 Validity (IPRT representation). + */ +typedef struct RTCRX509VALIDITY +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** Effective starting. */ + RTASN1TIME NotBefore; + /** Expires after. */ + RTASN1TIME NotAfter; +} RTCRX509VALIDITY; +/** Pointer to the IPRT representation of an X.509 validity sequence. */ +typedef RTCRX509VALIDITY *PRTCRX509VALIDITY; +/** Pointer ot the const IPRT representation of an X.509 validity sequence. */ +typedef RTCRX509VALIDITY const *PCRTCRX509VALIDITY; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509VALIDITY, RTDECL, RTCrX509Validity, SeqCore.Asn1Core); + +RTDECL(bool) RTCrX509Validity_IsValidAtTimeSpec(PCRTCRX509VALIDITY pThis, PCRTTIMESPEC pTimeSpec); + + +#if 0 +/** + * X.509 UniqueIdentifier (IPRT representation). + */ +typedef struct RTCRX509UNIQUEIDENTIFIER +{ + /** Representation is a bit string. */ + RTASN1BITSTRING BitString; +} RTCRX509UNIQUEIDENTIFIER; +/** Pointer to the IPRT representation of an X.509 unique identifier. */ +typedef RTCRX509UNIQUEIDENTIFIER *PRTCRX509UNIQUEIDENTIFIER; +/** Pointer to the const IPRT representation of an X.509 unique identifier. */ +typedef RTCRX509UNIQUEIDENTIFIER const *PCRTCRX509UNIQUEIDENTIFIER; +RTASN1TYPE_STANDARD_PROTOTYPES_NO_GET_CORE(RTCRX509UNIQUEIDENTIFIER, RTDECL, RTCrX509UniqueIdentifier); +#endif +RTASN1TYPE_ALIAS(RTCRX509UNIQUEIDENTIFIER, RTASN1BITSTRING, RTCrX509UniqueIdentifier, RTAsn1BitString); + + +/** + * X.509 SubjectPublicKeyInfo (IPRT representation). + */ +typedef struct RTCRX509SUBJECTPUBLICKEYINFO +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** The algorithm used with the public key. */ + RTCRX509ALGORITHMIDENTIFIER Algorithm; + /** A bit string containing the public key. + * + * For algorithms like rsaEncryption this is generally a sequence of two + * integers, where the first one has lots of bits, and the second one being a + * modulous value. These are details specific to the algorithm and not relevant + * when validating the certificate chain. */ + RTASN1BITSTRING SubjectPublicKey; +} RTCRX509SUBJECTPUBLICKEYINFO; +/** Pointer to the IPRT representation of an X.509 subject public key info + * sequence. */ +typedef RTCRX509SUBJECTPUBLICKEYINFO *PRTCRX509SUBJECTPUBLICKEYINFO; +/** Pointer to the const IPRT representation of an X.509 subject public key info + * sequence. */ +typedef RTCRX509SUBJECTPUBLICKEYINFO const *PCRTCRX509SUBJECTPUBLICKEYINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509SUBJECTPUBLICKEYINFO, RTDECL, RTCrX509SubjectPublicKeyInfo, SeqCore.Asn1Core); + + +/** + * One X.509 AuthorityKeyIdentifier (IPRT representation). + */ +typedef struct RTCRX509AUTHORITYKEYIDENTIFIER +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** Tag 0, optional, implicit: Key identifier. */ + RTASN1OCTETSTRING KeyIdentifier; + /** Tag 1, optional, implicit: Issuer name. */ + RTCRX509GENERALNAMES AuthorityCertIssuer; + /** Tag 2, optional, implicit: Serial number of issuer. */ + RTASN1INTEGER AuthorityCertSerialNumber; +} RTCRX509AUTHORITYKEYIDENTIFIER; +/** Pointer to the IPRT representation of an X.509 AuthorityKeyIdentifier + * sequence. */ +typedef RTCRX509AUTHORITYKEYIDENTIFIER *PRTCRX509AUTHORITYKEYIDENTIFIER; +/** Pointer to the const IPRT representation of an X.509 AuthorityKeyIdentifier + * sequence. */ +typedef RTCRX509AUTHORITYKEYIDENTIFIER const *PCRTCRX509AUTHORITYKEYIDENTIFIER; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509AUTHORITYKEYIDENTIFIER, RTDECL, RTCrX509AuthorityKeyIdentifier, SeqCore.Asn1Core); + + +/** + * One X.509 OldAuthorityKeyIdentifier (IPRT representation). + */ +typedef struct RTCRX509OLDAUTHORITYKEYIDENTIFIER +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** Tag 0, optional, implicit: Key identifier. */ + RTASN1OCTETSTRING KeyIdentifier; + struct + { + RTASN1CONTEXTTAG1 CtxTag1; + /** Tag 1, optional, implicit: Issuer name. */ + RTCRX509NAME AuthorityCertIssuer; + } T1; + /** Tag 2, optional, implicit: Serial number of issuer. */ + RTASN1INTEGER AuthorityCertSerialNumber; +} RTCRX509OLDAUTHORITYKEYIDENTIFIER; +/** Pointer to the IPRT representation of an X.509 AuthorityKeyIdentifier + * sequence. */ +typedef RTCRX509OLDAUTHORITYKEYIDENTIFIER *PRTCRX509OLDAUTHORITYKEYIDENTIFIER; +/** Pointer to the const IPRT representation of an X.509 AuthorityKeyIdentifier + * sequence. */ +typedef RTCRX509OLDAUTHORITYKEYIDENTIFIER const *PCRTCRX509OLDAUTHORITYKEYIDENTIFIER; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509OLDAUTHORITYKEYIDENTIFIER, RTDECL, RTCrX509OldAuthorityKeyIdentifier, SeqCore.Asn1Core); + + +/** + * One X.509 PolicyQualifierInfo (IPRT representation). + */ +typedef struct RTCRX509POLICYQUALIFIERINFO +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** The policy object ID. */ + RTASN1OBJID PolicyQualifierId; + /** Anything defined by the policy qualifier id. */ + RTASN1DYNTYPE Qualifier; +} RTCRX509POLICYQUALIFIERINFO; +/** Pointer to the IPRT representation of an X.509 PolicyQualifierInfo + * sequence. */ +typedef RTCRX509POLICYQUALIFIERINFO *PRTCRX509POLICYQUALIFIERINFO; +/** Pointer to the const IPRT representation of an X.509 PolicyQualifierInfo + * sequence. */ +typedef RTCRX509POLICYQUALIFIERINFO const *PCRTCRX509POLICYQUALIFIERINFO; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509POLICYQUALIFIERINFO, RTDECL, RTCrX509PolicyQualifierInfo, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRX509POLICYQUALIFIERINFOS, RTCRX509POLICYQUALIFIERINFO, RTDECL, RTCrX509PolicyQualifierInfos); + + +/** + * One X.509 PolicyInformation (IPRT representation). + */ +typedef struct RTCRX509POLICYINFORMATION +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** The policy object ID. */ + RTASN1OBJID PolicyIdentifier; + /** Optional sequence of policy qualifiers. */ + RTCRX509POLICYQUALIFIERINFOS PolicyQualifiers; +} RTCRX509POLICYINFORMATION; +/** Pointer to the IPRT representation of an X.509 PolicyInformation + * sequence. */ +typedef RTCRX509POLICYINFORMATION *PRTCRX509POLICYINFORMATION; +/** Pointer to the const IPRT representation of an X.509 PolicyInformation + * sequence. */ +typedef RTCRX509POLICYINFORMATION const *PCRTCRX509POLICYINFORMATION; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509POLICYINFORMATION, RTDECL, RTCrX509PolicyInformation, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRX509CERTIFICATEPOLICIES, RTCRX509POLICYINFORMATION, RTDECL, RTCrX509CertificatePolicies); + +/** Sepcial policy object ID that matches any policy. */ +#define RTCRX509_ID_CE_CP_ANY_POLICY_OID "2.5.29.32.0" + + +/** + * One X.509 PolicyMapping (IPRT representation). + */ +typedef struct RTCRX509POLICYMAPPING +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** Issuer policy ID. */ + RTASN1OBJID IssuerDomainPolicy; + /** Subject policy ID. */ + RTASN1OBJID SubjectDomainPolicy; +} RTCRX509POLICYMAPPING; +/** Pointer to the IPRT representation of a sequence of X.509 PolicyMapping. */ +typedef RTCRX509POLICYMAPPING *PRTCRX509POLICYMAPPING; +/** Pointer to the const IPRT representation of a sequence of X.509 + * PolicyMapping. */ +typedef RTCRX509POLICYMAPPING const *PCRTCRX509POLICYMAPPING; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509POLICYMAPPING, RTDECL, RTCrX509PolicyMapping, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRX509POLICYMAPPINGS, RTCRX509POLICYMAPPING, RTDECL, RTCrX509PolicyMappings); + + +/** + * X.509 BasicConstraints (IPRT representation). + */ +typedef struct RTCRX509BASICCONSTRAINTS +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** Is this ia certficiate authority? Default to false. */ + RTASN1BOOLEAN CA; + /** Path length constraint. */ + RTASN1INTEGER PathLenConstraint; +} RTCRX509BASICCONSTRAINTS; +/** Pointer to the IPRT representation of a sequence of X.509 + * BasicConstraints. */ +typedef RTCRX509BASICCONSTRAINTS *PRTCRX509BASICCONSTRAINTS; +/** Pointer to the const IPRT representation of a sequence of X.509 + * BasicConstraints. */ +typedef RTCRX509BASICCONSTRAINTS const *PCRTCRX509BASICCONSTRAINTS; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509BASICCONSTRAINTS, RTDECL, RTCrX509BasicConstraints, SeqCore.Asn1Core); + + +/** + * X.509 GeneralSubtree (IPRT representation). + */ +typedef struct RTCRX509GENERALSUBTREE +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** Base name. */ + RTCRX509GENERALNAME Base; + /** Tag 0, optional: Minimum, default 0. Fixed at 0 by RFC-5280. */ + RTASN1INTEGER Minimum; + /** Tag 1, optional: Maximum. Fixed as not-present by RFC-5280. */ + RTASN1INTEGER Maximum; +} RTCRX509GENERALSUBTREE; +/** Pointer to the IPRT representation of a sequence of X.509 GeneralSubtree. */ +typedef RTCRX509GENERALSUBTREE *PRTCRX509GENERALSUBTREE; +/** Pointer to the const IPRT representation of a sequence of X.509 + * GeneralSubtree. */ +typedef RTCRX509GENERALSUBTREE const *PCRTCRX509GENERALSUBTREE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509GENERALSUBTREE, RTDECL, RTCrX509GeneralSubtree, SeqCore.Asn1Core); + +RTDECL(bool) RTCrX509GeneralSubtree_ConstraintMatch(PCRTCRX509GENERALSUBTREE pConstraint, PCRTCRX509GENERALSUBTREE pName); + +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRX509GENERALSUBTREES, RTCRX509GENERALSUBTREE, RTDECL, RTCrX509GeneralSubtrees); + + +/** + * X.509 NameConstraints (IPRT representation). + */ +typedef struct RTCRX509NAMECONSTRAINTS +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** Tag 0, optional: Permitted subtrees. */ + struct + { + /** Context tag. */ + RTASN1CONTEXTTAG0 CtxTag0; + /** The permitted subtrees. */ + RTCRX509GENERALSUBTREES PermittedSubtrees; + } T0; + /** Tag 1, optional: Excluded subtrees. */ + struct + { + /** Context tag. */ + RTASN1CONTEXTTAG1 CtxTag1; + /** The excluded subtrees. */ + RTCRX509GENERALSUBTREES ExcludedSubtrees; + } T1; +} RTCRX509NAMECONSTRAINTS; +/** Pointer to the IPRT representation of a sequence of X.509 + * NameConstraints. */ +typedef RTCRX509NAMECONSTRAINTS *PRTCRX509NAMECONSTRAINTS; +/** Pointer to the const IPRT representation of a sequence of X.509 + * NameConstraints. */ +typedef RTCRX509NAMECONSTRAINTS const *PCRTCRX509NAMECONSTRAINTS; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509NAMECONSTRAINTS, RTDECL, RTCrX509NameConstraints, SeqCore.Asn1Core); + + +/** + * X.509 PolicyConstraints (IPRT representation). + */ +typedef struct RTCRX509POLICYCONSTRAINTS +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** Tag 0, optional: Certificates before an explicit policy is required. */ + RTASN1INTEGER RequireExplicitPolicy; + /** Tag 1, optional: Certificates before policy mapping is inhibited. */ + RTASN1INTEGER InhibitPolicyMapping; +} RTCRX509POLICYCONSTRAINTS; +/** Pointer to the IPRT representation of a sequence of X.509 + * PolicyConstraints. */ +typedef RTCRX509POLICYCONSTRAINTS *PRTCRX509POLICYCONSTRAINTS; +/** Pointer to the const IPRT representation of a sequence of X.509 + * PolicyConstraints. */ +typedef RTCRX509POLICYCONSTRAINTS const *PCRTCRX509POLICYCONSTRAINTS; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509POLICYCONSTRAINTS, RTDECL, RTCrX509PolicyConstraints, SeqCore.Asn1Core); + + +/** + * Indicates what an X.509 extension value encapsulates. + */ +typedef enum RTCRX509EXTENSIONVALUE +{ + RTCRX509EXTENSIONVALUE_INVALID = 0, + /** Unknown, no decoding available just the octet string. */ + RTCRX509EXTENSIONVALUE_UNKNOWN, + /** Unencapsulated (i.e. octet string). */ + RTCRX509EXTENSIONVALUE_NOT_ENCAPSULATED, + + /** Bit string (RTASN1BITSTRING). */ + RTCRX509EXTENSIONVALUE_BIT_STRING, + /** Octet string (RTASN1OCTETSTRING). */ + RTCRX509EXTENSIONVALUE_OCTET_STRING, + /** Integer string (RTASN1INTEGER). */ + RTCRX509EXTENSIONVALUE_INTEGER, + /** Sequence of object identifiers (RTASN1SEQOFOBJIDS). */ + RTCRX509EXTENSIONVALUE_SEQ_OF_OBJ_IDS, + + /** Authority key identifier (RTCRX509AUTHORITYKEYIDENTIFIER). */ + RTCRX509EXTENSIONVALUE_AUTHORITY_KEY_IDENTIFIER, + /** Old Authority key identifier (RTCRX509OLDAUTHORITYKEYIDENTIFIER). */ + RTCRX509EXTENSIONVALUE_OLD_AUTHORITY_KEY_IDENTIFIER, + /** Certificate policies (RTCRX509CERTIFICATEPOLICIES). */ + RTCRX509EXTENSIONVALUE_CERTIFICATE_POLICIES, + /** Sequence of policy mappings (RTCRX509POLICYMAPPINGS). */ + RTCRX509EXTENSIONVALUE_POLICY_MAPPINGS, + /** Basic constraints (RTCRX509BASICCONSTRAINTS). */ + RTCRX509EXTENSIONVALUE_BASIC_CONSTRAINTS, + /** Name constraints (RTCRX509NAMECONSTRAINTS). */ + RTCRX509EXTENSIONVALUE_NAME_CONSTRAINTS, + /** Policy constraints (RTCRX509POLICYCONSTRAINTS). */ + RTCRX509EXTENSIONVALUE_POLICY_CONSTRAINTS, + /** Sequence of general names (RTCRX509GENERALNAMES). */ + RTCRX509EXTENSIONVALUE_GENERAL_NAMES, + + /** Blow the type up to 32-bits. */ + RTCRX509EXTENSIONVALUE_32BIT_HACK = 0x7fffffff +} RTCRX509EXTENSIONVALUE; + +/** + * One X.509 Extension (IPRT representation). + */ +typedef struct RTCRX509EXTENSION +{ + /** Core sequence bits. */ + RTASN1SEQUENCECORE SeqCore; + /** Extension ID. */ + RTASN1OBJID ExtnId; + /** Whether this is critical (default @c false). */ + RTASN1BOOLEAN Critical; + /** Indicates what ExtnValue.pEncapsulated points at. */ + RTCRX509EXTENSIONVALUE enmValue; + /** The value. + * Contains extension specific data that we don't yet parse. */ + RTASN1OCTETSTRING ExtnValue; +} RTCRX509EXTENSION; +/** Pointer to the IPRT representation of one X.509 extensions. */ +typedef RTCRX509EXTENSION *PRTCRX509EXTENSION; +/** Pointer to the const IPRT representation of one X.509 extension. */ +typedef RTCRX509EXTENSION const *PCRTCRX509EXTENSION; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509EXTENSION, RTDECL, RTCrX509Extension, SeqCore.Asn1Core); +RTASN1_IMPL_GEN_SEQ_OF_TYPEDEFS_AND_PROTOS(RTCRX509EXTENSIONS, RTCRX509EXTENSION, RTDECL, RTCrX509Extensions); + +RTDECL(int) RTCrX509Extension_ExtnValue_DecodeAsn1(PRTASN1CURSOR pCursor, uint32_t fFlags, + PRTCRX509EXTENSION pThis, const char *pszErrorTag); + + +/** + * X.509 To-be-signed certificate information (IPRT representation). + */ +typedef struct RTCRX509TBSCERTIFICATE +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** Structure version. */ + struct + { + /** Context tag with value 0. */ + RTASN1CONTEXTTAG0 CtxTag0; + /** The actual value (RTCRX509TBSCERTIFICATE_V1, ...). */ + RTASN1INTEGER Version; + } T0; + /** The serial number of the certificate. */ + RTASN1INTEGER SerialNumber; + /** The signature algorithm. */ + RTCRX509ALGORITHMIDENTIFIER Signature; + /** The issuer name. */ + RTCRX509NAME Issuer; + /** The certificate validity period. */ + RTCRX509VALIDITY Validity; + /** The subject name. */ + RTCRX509NAME Subject; + /** The public key for this certificate. */ + RTCRX509SUBJECTPUBLICKEYINFO SubjectPublicKeyInfo; + /** Issuer unique identifier (optional, version >= v2). */ + struct + { + /** Context tag with value 1. */ + RTASN1CONTEXTTAG1 CtxTag1; + /** The unique identifier value. */ + RTCRX509UNIQUEIDENTIFIER IssuerUniqueId; + } T1; + /** Subject unique identifier (optional, version >= v2). */ + struct + { + /** Context tag with value 2. */ + RTASN1CONTEXTTAG2 CtxTag2; + /** The unique identifier value. */ + RTCRX509UNIQUEIDENTIFIER SubjectUniqueId; + } T2; + /** Extensions (optional, version >= v3). */ + struct + { + /** Context tag with value 3. */ + RTASN1CONTEXTTAG3 CtxTag3; + /** The unique identifier value. */ + RTCRX509EXTENSIONS Extensions; + /** Extensions summary flags (RTCRX509TBSCERTIFICATE_F_PRESENT_XXX). */ + uint32_t fFlags; + /** Key usage flags (RTCRX509CERT_KEY_USAGE_F_XXX). */ + uint32_t fKeyUsage; + /** Extended key usage flags (RTCRX509CERT_EKU_F_XXX). */ + uint64_t fExtKeyUsage; + + /** Pointer to the authority key ID extension if present. */ + PCRTCRX509AUTHORITYKEYIDENTIFIER pAuthorityKeyIdentifier; + /** Pointer to the OLD authority key ID extension if present. */ + PCRTCRX509OLDAUTHORITYKEYIDENTIFIER pOldAuthorityKeyIdentifier; + /** Pointer to the subject key ID extension if present. */ + PCRTASN1OCTETSTRING pSubjectKeyIdentifier; + /** Pointer to the alternative subject name extension if present. */ + PCRTCRX509GENERALNAMES pAltSubjectName; + /** Pointer to the alternative issuer name extension if present. */ + PCRTCRX509GENERALNAMES pAltIssuerName; + /** Pointer to the certificate policies extension if present. */ + PCRTCRX509CERTIFICATEPOLICIES pCertificatePolicies; + /** Pointer to the policy mappings extension if present. */ + PCRTCRX509POLICYMAPPINGS pPolicyMappings; + /** Pointer to the basic constraints extension if present. */ + PCRTCRX509BASICCONSTRAINTS pBasicConstraints; + /** Pointer to the name constraints extension if present. */ + PCRTCRX509NAMECONSTRAINTS pNameConstraints; + /** Pointer to the policy constraints extension if present. */ + PCRTCRX509POLICYCONSTRAINTS pPolicyConstraints; + /** Pointer to the inhibit anyPolicy extension if present. */ + PCRTASN1INTEGER pInhibitAnyPolicy; + } T3; +} RTCRX509TBSCERTIFICATE; +/** Pointer to the IPRT representation of a X.509 TBSCertificate. */ +typedef RTCRX509TBSCERTIFICATE *PRTCRX509TBSCERTIFICATE; +/** Pointer to the const IPRT representation of a X.509 TBSCertificate. */ +typedef RTCRX509TBSCERTIFICATE const *PCRTCRX509TBSCERTIFICATE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509TBSCERTIFICATE, RTDECL, RTCrX509TbsCertificate, SeqCore.Asn1Core); + +/** @name RTCRX509TBSCERTIFICATE::T0.Version values. + * @{ */ +#define RTCRX509TBSCERTIFICATE_V1 0 +#define RTCRX509TBSCERTIFICATE_V2 1 +#define RTCRX509TBSCERTIFICATE_V3 2 +/** @} */ + +/** @name RTCRX509TBSCERTIFICATE::T3.fFlags values. + * @{ */ +#define RTCRX509TBSCERTIFICATE_F_PRESENT_KEY_USAGE RT_BIT_32(0) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_EXT_KEY_USAGE RT_BIT_32(1) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_SUBJECT_KEY_IDENTIFIER RT_BIT_32(2) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_SUBJECT_ALT_NAME RT_BIT_32(3) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_ISSUER_ALT_NAME RT_BIT_32(4) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_CERTIFICATE_POLICIES RT_BIT_32(5) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_POLICY_MAPPINGS RT_BIT_32(6) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_BASIC_CONSTRAINTS RT_BIT_32(7) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_NAME_CONSTRAINTS RT_BIT_32(8) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_POLICY_CONSTRAINTS RT_BIT_32(9) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_AUTHORITY_KEY_IDENTIFIER RT_BIT_32(10) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_OLD_AUTHORITY_KEY_IDENTIFIER RT_BIT_32(11) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_ACCEPTABLE_CERT_POLICIES RT_BIT_32(12) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_INHIBIT_ANY_POLICY RT_BIT_32(13) +#define RTCRX509TBSCERTIFICATE_F_PRESENT_OTHER RT_BIT_32(22) /**< Other unknown extension present. */ +#define RTCRX509TBSCERTIFICATE_F_PRESENT_NONE RT_BIT_32(23) /**< No extensions present. */ +/** @} */ + +/** @name X.509 Key Usage flags. (RFC-5280 section 4.2.1.3.) + * @{ */ +#define RTCRX509CERT_KEY_USAGE_F_DIGITAL_SIGNATURE_BIT 0 +#define RTCRX509CERT_KEY_USAGE_F_DIGITAL_SIGNATURE RT_BIT_32(0) +#define RTCRX509CERT_KEY_USAGE_F_CONTENT_COMMITTMENT_BIT 1 +#define RTCRX509CERT_KEY_USAGE_F_CONTENT_COMMITTMENT RT_BIT_32(1) +#define RTCRX509CERT_KEY_USAGE_F_KEY_ENCIPHERMENT_BIT 2 +#define RTCRX509CERT_KEY_USAGE_F_KEY_ENCIPHERMENT RT_BIT_32(2) +#define RTCRX509CERT_KEY_USAGE_F_DATA_ENCIPHERMENT_BIT 3 +#define RTCRX509CERT_KEY_USAGE_F_DATA_ENCIPHERMENT RT_BIT_32(3) +#define RTCRX509CERT_KEY_USAGE_F_KEY_AGREEMENT_BIT 4 +#define RTCRX509CERT_KEY_USAGE_F_KEY_AGREEMENT RT_BIT_32(4) +#define RTCRX509CERT_KEY_USAGE_F_KEY_CERT_SIGN_BIT 5 +#define RTCRX509CERT_KEY_USAGE_F_KEY_CERT_SIGN RT_BIT_32(5) +#define RTCRX509CERT_KEY_USAGE_F_CRL_SIGN_BIT 6 +#define RTCRX509CERT_KEY_USAGE_F_CRL_SIGN RT_BIT_32(6) +#define RTCRX509CERT_KEY_USAGE_F_ENCIPHERMENT_ONLY_BIT 7 +#define RTCRX509CERT_KEY_USAGE_F_ENCIPHERMENT_ONLY RT_BIT_32(7) +#define RTCRX509CERT_KEY_USAGE_F_DECIPHERMENT_ONLY_BIT 8 +#define RTCRX509CERT_KEY_USAGE_F_DECIPHERMENT_ONLY RT_BIT_32(8) +/** @} */ + +/** @name X.509 Extended Key Usage flags. (RFC-5280 section 4.2.1.12, ++.) + * @remarks Needless to say, these flags doesn't cover all possible extended key + * usages, because there is a potential unlimited number of them. Only + * ones relevant to IPRT and it's users are covered. + * @{ */ +#define RTCRX509CERT_EKU_F_ANY RT_BIT_64(0) +#define RTCRX509CERT_EKU_F_SERVER_AUTH RT_BIT_64(1) +#define RTCRX509CERT_EKU_F_CLIENT_AUTH RT_BIT_64(2) +#define RTCRX509CERT_EKU_F_CODE_SIGNING RT_BIT_64(3) +#define RTCRX509CERT_EKU_F_EMAIL_PROTECTION RT_BIT_64(4) +#define RTCRX509CERT_EKU_F_IPSEC_END_SYSTEM RT_BIT_64(5) +#define RTCRX509CERT_EKU_F_IPSEC_TUNNEL RT_BIT_64(6) +#define RTCRX509CERT_EKU_F_IPSEC_USER RT_BIT_64(7) +#define RTCRX509CERT_EKU_F_TIMESTAMPING RT_BIT_64(8) +#define RTCRX509CERT_EKU_F_OCSP_SIGNING RT_BIT_64(9) +#define RTCRX509CERT_EKU_F_DVCS RT_BIT_64(10) +#define RTCRX509CERT_EKU_F_SBGP_CERT_AA_SERVICE_AUTH RT_BIT_64(11) +#define RTCRX509CERT_EKU_F_EAP_OVER_PPP RT_BIT_64(12) +#define RTCRX509CERT_EKU_F_EAP_OVER_LAN RT_BIT_64(13) +#define RTCRX509CERT_EKU_F_OTHER RT_BIT_64(16) /**< Other unknown extended key usage present. */ +#define RTCRX509CERT_EKU_F_APPLE_CODE_SIGNING RT_BIT_64(24) +#define RTCRX509CERT_EKU_F_APPLE_CODE_SIGNING_DEVELOPMENT RT_BIT_64(25) +#define RTCRX509CERT_EKU_F_APPLE_SOFTWARE_UPDATE_SIGNING RT_BIT_64(26) +#define RTCRX509CERT_EKU_F_APPLE_CODE_SIGNING_THIRD_PARTY RT_BIT_64(27) +#define RTCRX509CERT_EKU_F_APPLE_RESOURCE_SIGNING RT_BIT_64(28) +#define RTCRX509CERT_EKU_F_APPLE_SYSTEM_IDENTITY RT_BIT_64(29) +#define RTCRX509CERT_EKU_F_MS_TIMESTAMP_SIGNING RT_BIT_64(32) +#define RTCRX509CERT_EKU_F_MS_NT5_CRYPTO RT_BIT_64(33) +#define RTCRX509CERT_EKU_F_MS_OEM_WHQL_CRYPTO RT_BIT_64(34) +#define RTCRX509CERT_EKU_F_MS_EMBEDDED_NT_CRYPTO RT_BIT_64(35) +#define RTCRX509CERT_EKU_F_MS_KERNEL_MODE_CODE_SIGNING RT_BIT_64(36) +#define RTCRX509CERT_EKU_F_MS_LIFETIME_SIGNING RT_BIT_64(37) +#define RTCRX509CERT_EKU_F_MS_DRM RT_BIT_64(38) +#define RTCRX509CERT_EKU_F_MS_DRM_INDIVIDUALIZATION RT_BIT_64(39) +#define RTCRX509CERT_EKU_F_MS_WHQL_CRYPTO RT_BIT_64(40) +#define RTCRX509CERT_EKU_F_MS_ATTEST_WHQL_CRYPTO RT_BIT_64(41) +/** @} */ + +/** @name Key purpose OIDs (extKeyUsage) + * @{ */ +#define RTCRX509_ANY_EXTENDED_KEY_USAGE_OID "2.5.29.37.0" +#define RTCRX509_ID_KP_OID "1.3.6.1.5.5.7.3" +#define RTCRX509_ID_KP_SERVER_AUTH_OID "1.3.6.1.5.5.7.3.1" +#define RTCRX509_ID_KP_CLIENT_AUTH_OID "1.3.6.1.5.5.7.3.2" +#define RTCRX509_ID_KP_CODE_SIGNING_OID "1.3.6.1.5.5.7.3.3" +#define RTCRX509_ID_KP_EMAIL_PROTECTION_OID "1.3.6.1.5.5.7.3.4" +#define RTCRX509_ID_KP_IPSEC_END_SYSTEM_OID "1.3.6.1.5.5.7.3.5" +#define RTCRX509_ID_KP_IPSEC_TUNNEL_OID "1.3.6.1.5.5.7.3.6" +#define RTCRX509_ID_KP_IPSEC_USER_OID "1.3.6.1.5.5.7.3.7" +#define RTCRX509_ID_KP_TIMESTAMPING_OID "1.3.6.1.5.5.7.3.8" +#define RTCRX509_ID_KP_OCSP_SIGNING_OID "1.3.6.1.5.5.7.3.9" +#define RTCRX509_ID_KP_DVCS_OID "1.3.6.1.5.5.7.3.10" +#define RTCRX509_ID_KP_SBGP_CERT_AA_SERVICE_AUTH_OID "1.3.6.1.5.5.7.3.11" +#define RTCRX509_ID_KP_EAP_OVER_PPP_OID "1.3.6.1.5.5.7.3.13" +#define RTCRX509_ID_KP_EAP_OVER_LAN_OID "1.3.6.1.5.5.7.3.14" +/** @} */ + +/** @name Microsoft extended key usage OIDs + * @{ */ +#define RTCRX509_MS_EKU_CERT_TRUST_LIST_SIGNING_OID "1.3.6.1.4.1.311.10.3.1" +#define RTCRX509_MS_EKU_TIMESTAMP_SIGNING_OID "1.3.6.1.4.1.311.10.3.2" +#define RTCRX509_MS_EKU_SERVER_GATED_CRYPTO_OID "1.3.6.1.4.1.311.10.3.3" +#define RTCRX509_MS_EKU_SGC_SERIALIZED_OID "1.3.6.1.4.1.311.10.3.3.1" +#define RTCRX509_MS_EKU_ENCRYPTED_FILE_SYSTEM_OID "1.3.6.1.4.1.311.10.3.4" +#define RTCRX509_MS_EKU_WHQL_CRYPTO_OID "1.3.6.1.4.1.311.10.3.5" +#define RTCRX509_MS_EKU_ATTEST_WHQL_CRYPTO_OID "1.3.6.1.4.1.311.10.3.5.1" +#define RTCRX509_MS_EKU_NT5_CRYPTO_OID "1.3.6.1.4.1.311.10.3.6" +#define RTCRX509_MS_EKU_OEM_WHQL_CRYPTO_OID "1.3.6.1.4.1.311.10.3.7" +#define RTCRX509_MS_EKU_EMBEDDED_NT_CRYPTO_OID "1.3.6.1.4.1.311.10.3.8" +#define RTCRX509_MS_EKU_ROOT_LIST_SIGNER_OID "1.3.6.1.4.1.311.10.3.9" +#define RTCRX509_MS_EKU_QUALIFIED_SUBORDINATE_OID "1.3.6.1.4.1.311.10.3.10" +#define RTCRX509_MS_EKU_KEY_RECOVERY_3_OID "1.3.6.1.4.1.311.10.3.11" +#define RTCRX509_MS_EKU_DOCUMENT_SIGNING_OID "1.3.6.1.4.1.311.10.3.12" +#define RTCRX509_MS_EKU_LIFETIME_SIGNING_OID "1.3.6.1.4.1.311.10.3.13" +#define RTCRX509_MS_EKU_MOBILE_DEVICE_SOFTWARE_OID "1.3.6.1.4.1.311.10.3.14" +#define RTCRX509_MS_EKU_SMART_DISPLAY_OID "1.3.6.1.4.1.311.10.3.15" +#define RTCRX509_MS_EKU_CSP_SIGNATURE_OID "1.3.6.1.4.1.311.10.3.16" +#define RTCRX509_MS_EKU_EFS_RECOVERY_OID "1.3.6.1.4.1.311.10.3.4.1" +#define RTCRX509_MS_EKU_DRM_OID "1.3.6.1.4.1.311.10.5.1" +#define RTCRX509_MS_EKU_DRM_INDIVIDUALIZATION_OID "1.3.6.1.4.1.311.10.5.2" +#define RTCRX509_MS_EKU_LICENSES_OID "1.3.6.1.4.1.311.10.5.3" +#define RTCRX509_MS_EKU_LICENSE_SERVER_OID "1.3.6.1.4.1.311.10.5.4" +#define RTCRX509_MS_EKU_ENROLLMENT_AGENT_OID "1.3.6.1.4.1.311.20.2.1" +#define RTCRX509_MS_EKU_SMARTCARD_LOGON_OID "1.3.6.1.4.1.311.20.2.2" +#define RTCRX509_MS_EKU_CA_EXCHANGE_OID "1.3.6.1.4.1.311.21.5" +#define RTCRX509_MS_EKU_KEY_RECOVERY_21_OID "1.3.6.1.4.1.311.21.6" +#define RTCRX509_MS_EKU_SYSTEM_HEALTH_OID "1.3.6.1.4.1.311.47.1.1" +#define RTCRX509_MS_EKU_SYSTEM_HEALTH_LOOPHOLE_OID "1.3.6.1.4.1.311.47.1.3" +#define RTCRX509_MS_EKU_KERNEL_MODE_CODE_SIGNING_OID "1.3.6.1.4.1.311.61.1.1" +/** @} */ + +/** @name Apple extended key usage OIDs + * @{ */ +#define RTCRX509_APPLE_EKU_APPLE_EXTENDED_KEY_USAGE_OID "1.2.840.113635.100.4" +#define RTCRX509_APPLE_EKU_CODE_SIGNING_OID "1.2.840.113635.100.4.1" +#define RTCRX509_APPLE_EKU_CODE_SIGNING_DEVELOPMENT_OID "1.2.840.113635.100.4.1.1" +#define RTCRX509_APPLE_EKU_SOFTWARE_UPDATE_SIGNING_OID "1.2.840.113635.100.4.1.2" +#define RTCRX509_APPLE_EKU_CODE_SIGNING_THRID_PARTY_OID "1.2.840.113635.100.4.1.3" +#define RTCRX509_APPLE_EKU_RESOURCE_SIGNING_OID "1.2.840.113635.100.4.1.4" +#define RTCRX509_APPLE_EKU_ICHAT_SIGNING_OID "1.2.840.113635.100.4.2" +#define RTCRX509_APPLE_EKU_ICHAT_ENCRYPTION_OID "1.2.840.113635.100.4.3" +#define RTCRX509_APPLE_EKU_SYSTEM_IDENTITY_OID "1.2.840.113635.100.4.4" +#define RTCRX509_APPLE_EKU_CRYPTO_ENV_OID "1.2.840.113635.100.4.5" +#define RTCRX509_APPLE_EKU_CRYPTO_PRODUCTION_ENV_OID "1.2.840.113635.100.4.5.1" +#define RTCRX509_APPLE_EKU_CRYPTO_MAINTENANCE_ENV_OID "1.2.840.113635.100.4.5.2" +#define RTCRX509_APPLE_EKU_CRYPTO_TEST_ENV_OID "1.2.840.113635.100.4.5.3" +#define RTCRX509_APPLE_EKU_CRYPTO_DEVELOPMENT_ENV_OID "1.2.840.113635.100.4.5.4" +#define RTCRX509_APPLE_EKU_CRYPTO_QOS_OID "1.2.840.113635.100.4.6" +#define RTCRX509_APPLE_EKU_CRYPTO_TIER0_QOS_OID "1.2.840.113635.100.4.6.1" +#define RTCRX509_APPLE_EKU_CRYPTO_TIER1_QOS_OID "1.2.840.113635.100.4.6.2" +#define RTCRX509_APPLE_EKU_CRYPTO_TIER2_QOS_OID "1.2.840.113635.100.4.6.3" +#define RTCRX509_APPLE_EKU_CRYPTO_TIER3_QOS_OID "1.2.840.113635.100.4.6.4" +/** @} */ + +/** + * Use this to update derived values after changing the certificate + * extensions. + * + * @returns IPRT status code + * @param pThis The certificate. + * @param pErrInfo Where to return additional error information. Optional. + */ +RTDECL(int) RTCrX509TbsCertificate_ReprocessExtensions(PRTCRX509TBSCERTIFICATE pThis, PRTERRINFO pErrInfo); + + +/** + * One X.509 Certificate (IPRT representation). + */ +typedef struct RTCRX509CERTIFICATE +{ + /** Sequence core. */ + RTASN1SEQUENCECORE SeqCore; + /** The to-be-signed certificate information. */ + RTCRX509TBSCERTIFICATE TbsCertificate; + /** The signature algorithm (must match TbsCertificate.Signature). */ + RTCRX509ALGORITHMIDENTIFIER SignatureAlgorithm; + /** The signature value. */ + RTASN1BITSTRING SignatureValue; +} RTCRX509CERTIFICATE; +/** Pointer to the IPRT representation of one X.509 certificate. */ +typedef RTCRX509CERTIFICATE *PRTCRX509CERTIFICATE; +/** Pointer to the const IPRT representation of one X.509 certificate. */ +typedef RTCRX509CERTIFICATE const *PCRTCRX509CERTIFICATE; +RTASN1TYPE_STANDARD_PROTOTYPES(RTCRX509CERTIFICATE, RTDECL, RTCrX509Certificate, SeqCore.Asn1Core); + +/** + * Checks if a certificate matches a given issuer name and serial number. + * + * @returns True / false. + * @param pCertificate The X.509 certificat. + * @param pIssuer The issuer name to match against. + * @param pSerialNumber The serial number to match against. + */ +RTDECL(bool) RTCrX509Certificate_MatchIssuerAndSerialNumber(PCRTCRX509CERTIFICATE pCertificate, + PCRTCRX509NAME pIssuer, PCRTASN1INTEGER pSerialNumber); + +RTDECL(bool) RTCrX509Certificate_MatchSubjectOrAltSubjectByRfc5280(PCRTCRX509CERTIFICATE pThis, PCRTCRX509NAME pName); +RTDECL(bool) RTCrX509Certificate_IsSelfSigned(PCRTCRX509CERTIFICATE pCertificate); + +RTDECL(int) RTCrX509Certificate_VerifySignature(PCRTCRX509CERTIFICATE pThis, PCRTASN1OBJID pAlgorithm, + PCRTASN1DYNTYPE pParameters, PCRTASN1BITSTRING pPublicKey, + PRTERRINFO pErrInfo); +RTDECL(int) RTCrX509Certificate_VerifySignatureSelfSigned(PCRTCRX509CERTIFICATE pThis, PRTERRINFO pErrInfo); +RTDECL(int) RTCrX509Certificate_ReadFromFile(PRTCRX509CERTIFICATE pCertificate, const char *pszFilename, uint32_t fFlags, + PCRTASN1ALLOCATORVTABLE pAllocator, PRTERRINFO pErrInfo); +RTDECL(int) RTCrX509Certificate_ReadFromBuffer(PRTCRX509CERTIFICATE pCertificate, const void *pvBuf, size_t cbBuf, + uint32_t fFlags, PCRTASN1ALLOCATORVTABLE pAllocator, + PRTERRINFO pErrInfo, const char *pszErrorTag); +/** @name Flags for RTCrX509Certificate_ReadFromFile and + * RTCrX509Certificate_ReadFromBuffer + * @{ */ +/** Only allow PEM certificates, not binary ones. + * @sa RTCRPEMREADFILE_F_ONLY_PEM */ +#define RTCRX509CERT_READ_F_PEM_ONLY RT_BIT(1) +/** @} */ + +/** X509 Certificate markers for RTCrPemFindFirstSectionInContent et al. */ +extern RTDATADECL(RTCRPEMMARKER const) g_aRTCrX509CertificateMarkers[]; +/** Number of entries in g_aRTCrX509CertificateMarkers. */ +extern RTDATADECL(uint32_t const) g_cRTCrX509CertificateMarkers; + + +/** Wrapper around RTCrPemWriteAsn1ToVfsIoStrm(). */ +DECLINLINE(ssize_t) RTCrX509Certificate_WriteToVfsIoStrm(RTVFSIOSTREAM hVfsIos, PRTCRX509CERTIFICATE pCertificate, + PRTERRINFO pErrInfo) +{ + return RTCrPemWriteAsn1ToVfsIoStrm(hVfsIos, &pCertificate->SeqCore.Asn1Core, 0 /*fFlags*/, + g_aRTCrX509CertificateMarkers[0].paWords[0].pszWord, pErrInfo); +} + +/** Wrapper around RTCrPemWriteAsn1ToVfsFile(). */ +DECLINLINE(ssize_t) RTCrX509Certificate_WriteToVfsFile(RTVFSFILE hVfsFile, PRTCRX509CERTIFICATE pCertificate, + PRTERRINFO pErrInfo) +{ + return RTCrPemWriteAsn1ToVfsFile(hVfsFile, &pCertificate->SeqCore.Asn1Core, 0 /*fFlags*/, + g_aRTCrX509CertificateMarkers[0].paWords[0].pszWord, pErrInfo); +} + +/** @name X.509 Certificate Extensions + * @{ */ +/** Old AuthorityKeyIdentifier OID. */ +#define RTCRX509_ID_CE_OLD_AUTHORITY_KEY_IDENTIFIER_OID "2.5.29.1" +/** Old CertificatePolicies extension OID. */ +#define RTCRX509_ID_CE_OLD_CERTIFICATE_POLICIES_OID "2.5.29.3" +/** Old SubjectAltName extension OID. */ +#define RTCRX509_ID_CE_OLD_SUBJECT_ALT_NAME_OID "2.5.29.7" +/** Old IssuerAltName extension OID. */ +#define RTCRX509_ID_CE_OLD_ISSUER_ALT_NAME_OID "2.5.29.8" +/** Old BasicContraints extension OID. */ +#define RTCRX509_ID_CE_OLD_BASIC_CONSTRAINTS_OID "2.5.29.10" +/** SubjectKeyIdentifier OID. */ +#define RTCRX509_ID_CE_SUBJECT_KEY_IDENTIFIER_OID "2.5.29.14" +/** KeyUsage OID. */ +#define RTCRX509_ID_CE_KEY_USAGE_OID "2.5.29.15" +/** PrivateKeyUsagePeriod OID. */ +#define RTCRX509_ID_CE_PRIVATE_KEY_USAGE_PERIOD_OID "2.5.29.16" +/** SubjectAltName extension OID. */ +#define RTCRX509_ID_CE_SUBJECT_ALT_NAME_OID "2.5.29.17" +/** IssuerAltName extension OID. */ +#define RTCRX509_ID_CE_ISSUER_ALT_NAME_OID "2.5.29.18" +/** BasicContraints extension OID. */ +#define RTCRX509_ID_CE_BASIC_CONSTRAINTS_OID "2.5.29.19" +/** NameContraints extension OID. */ +#define RTCRX509_ID_CE_NAME_CONSTRAINTS_OID "2.5.29.30" +/** CertificatePolicies extension OID. */ +#define RTCRX509_ID_CE_CERTIFICATE_POLICIES_OID "2.5.29.32" +/** PolicyMappings extension OID. */ +#define RTCRX509_ID_CE_POLICY_MAPPINGS_OID "2.5.29.33" +/** AuthorityKeyIdentifier OID. */ +#define RTCRX509_ID_CE_AUTHORITY_KEY_IDENTIFIER_OID "2.5.29.35" +/** PolicyContraints extension OID. */ +#define RTCRX509_ID_CE_POLICY_CONSTRAINTS_OID "2.5.29.36" +/** ExtKeyUsage (extended key usage) extension OID. */ +#define RTCRX509_ID_CE_EXT_KEY_USAGE_OID "2.5.29.37" +/** ExtKeyUsage: OID for permitting any unspecified key usage. */ +#define RTCRX509_ID_CE_ANY_EXTENDED_KEY_USAGE_OID "2.5.29.37.0" +/** AuthorityAttributeIdentifier OID. */ +#define RTCRX509_ID_CE_AUTHORITY_ATTRIBUTE_IDENTIFIER_OID "2.5.29.38" +/** AcceptableCertPolicies OID. */ +#define RTCRX509_ID_CE_ACCEPTABLE_CERT_POLICIES_OID "2.5.29.52" +/** InhibitAnyPolicy OID. */ +#define RTCRX509_ID_CE_INHIBIT_ANY_POLICY_OID "2.5.29.54" +/** @} */ + + +/* + * Sequence of X.509 Certifcates (IPRT representation). + */ +RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRX509CERTIFICATES, RTCRX509CERTIFICATE, RTDECL, RTCrX509Certificates); + +/** + * Looks up a certificate by issuer name and serial number. + * + * @returns Pointer to the given certificate if found, NULL if not. + * @param pCertificates The X.509 certificate set to search. + * @param pIssuer The issuer name of the wanted certificate. + * @param pSerialNumber The serial number of the wanted certificate. + */ +RTDECL(PCRTCRX509CERTIFICATE) RTCrX509Certificates_FindByIssuerAndSerialNumber(PCRTCRX509CERTIFICATES pCertificates, + PCRTCRX509NAME pIssuer, + PCRTASN1INTEGER pSerialNumber); + + + +RTDECL(int) RTCrX509CertPathsCreate(PRTCRX509CERTPATHS phCertPaths, PCRTCRX509CERTIFICATE pTarget); +RTDECL(uint32_t) RTCrX509CertPathsRetain(RTCRX509CERTPATHS hCertPaths); +RTDECL(uint32_t) RTCrX509CertPathsRelease(RTCRX509CERTPATHS hCertPaths); +RTDECL(int) RTCrX509CertPathsSetTrustedStore(RTCRX509CERTPATHS hCertPaths, RTCRSTORE hTrustedStore); +RTDECL(int) RTCrX509CertPathsSetUntrustedStore(RTCRX509CERTPATHS hCertPaths, RTCRSTORE hUntrustedStore); +RTDECL(int) RTCrX509CertPathsSetUntrustedArray(RTCRX509CERTPATHS hCertPaths, PCRTCRX509CERTIFICATE paCerts, uint32_t cCerts); +RTDECL(int) RTCrX509CertPathsSetUntrustedSet(RTCRX509CERTPATHS hCertPaths, struct RTCRPKCS7SETOFCERTS const *pSetOfCerts); +RTDECL(int) RTCrX509CertPathsSetValidTime(RTCRX509CERTPATHS hCertPaths, PCRTTIME pTime); +RTDECL(int) RTCrX509CertPathsSetValidTimeSpec(RTCRX509CERTPATHS hCertPaths, PCRTTIMESPEC pTimeSpec); +RTDECL(int) RTCrX509CertPathsSetTrustAnchorChecks(RTCRX509CERTPATHS hCertPaths, bool fEnable); +RTDECL(int) RTCrX509CertPathsCreateEx(PRTCRX509CERTPATHS phCertPaths, PCRTCRX509CERTIFICATE pTarget, RTCRSTORE hTrustedStore, + RTCRSTORE hUntrustedStore, PCRTCRX509CERTIFICATE paUntrustedCerts, uint32_t cUntrustedCerts, + PCRTTIMESPEC pValidTime); +RTDECL(int) RTCrX509CertPathsBuild(RTCRX509CERTPATHS hCertPaths, PRTERRINFO pErrInfo); +RTDECL(int) RTCrX509CertPathsDumpOne(RTCRX509CERTPATHS hCertPaths, uint32_t iPath, uint32_t uVerbosity, + PFNRTDUMPPRINTFV pfnPrintfV, void *pvUser); +RTDECL(int) RTCrX509CertPathsDumpAll(RTCRX509CERTPATHS hCertPaths, uint32_t uVerbosity, + PFNRTDUMPPRINTFV pfnPrintfV, void *pvUser); + +RTDECL(int) RTCrX509CertPathsValidateOne(RTCRX509CERTPATHS hCertPaths, uint32_t iPath, PRTERRINFO pErrInfo); +RTDECL(int) RTCrX509CertPathsValidateAll(RTCRX509CERTPATHS hCertPaths, uint32_t *pcValidPaths, PRTERRINFO pErrInfo); + +RTDECL(uint32_t) RTCrX509CertPathsGetPathCount(RTCRX509CERTPATHS hCertPaths); +RTDECL(int) RTCrX509CertPathsQueryPathInfo(RTCRX509CERTPATHS hCertPaths, uint32_t iPath, + bool *pfTrusted, uint32_t *pcNodes, PCRTCRX509NAME *ppSubject, + PCRTCRX509SUBJECTPUBLICKEYINFO *ppPublicKeyInfo, + PCRTCRX509CERTIFICATE *ppCert, PCRTCRCERTCTX *ppCertCtx, int *prcVerify); +RTDECL(uint32_t) RTCrX509CertPathsGetPathLength(RTCRX509CERTPATHS hCertPaths, uint32_t iPath); +RTDECL(int) RTCrX509CertPathsGetPathVerifyResult(RTCRX509CERTPATHS hCertPaths, uint32_t iPath); +RTDECL(PCRTCRX509CERTIFICATE) RTCrX509CertPathsGetPathNodeCert(RTCRX509CERTPATHS hCertPaths, uint32_t iPath, uint32_t iNode); + + +RT_C_DECLS_END + +/** @} */ + +/** @} */ + +#endif /* !IPRT_INCLUDED_crypto_x509_h */ + diff --git a/include/iprt/ctype.h b/include/iprt/ctype.h new file mode 100644 index 00000000..139af524 --- /dev/null +++ b/include/iprt/ctype.h @@ -0,0 +1,251 @@ +/** @file + * IPRT - Simple character type classiciation and conversion. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_ctype_h +#define IPRT_INCLUDED_ctype_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/** @name C locale predicates and conversions. + * + * For most practical purposes, this can safely be used when parsing UTF-8 + * strings. Just keep in mind that we only deal with the first 127 chars and + * that full correctness is only archived using the non-existing RTLocIs* API. + * + * @remarks Use the marcros, not the inlined functions. + * + * @remarks ASSUMES the source code includes the basic ASCII chars. This is a + * general IPRT assumption. + * @{ */ +#define RT_C_IS_BLANK(ch) RTLocCIsBlank((ch)) +#define RT_C_IS_ALNUM(ch) RTLocCIsAlNum((ch)) +#define RT_C_IS_ALPHA(ch) RTLocCIsAlpha((ch)) +#define RT_C_IS_CNTRL(ch) RTLocCIsCntrl((ch)) +#define RT_C_IS_DIGIT(ch) RTLocCIsDigit((ch)) +#define RT_C_IS_LOWER(ch) RTLocCIsLower((ch)) +#define RT_C_IS_GRAPH(ch) RTLocCIsGraph((ch)) +#define RT_C_IS_ODIGIT(ch) RTLocCIsODigit((ch)) +#define RT_C_IS_PRINT(ch) RTLocCIsPrint((ch)) +#define RT_C_IS_PUNCT(ch) RTLocCIsPunct((ch)) +#define RT_C_IS_SPACE(ch) RTLocCIsSpace((ch)) +#define RT_C_IS_UPPER(ch) RTLocCIsUpper((ch)) +#define RT_C_IS_XDIGIT(ch) RTLocCIsXDigit((ch)) + +#define RT_C_TO_LOWER(ch) RTLocCToLower((ch)) +#define RT_C_TO_UPPER(ch) RTLocCToUpper((ch)) + +/** + * Checks for a blank character. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsBlank(int ch) +{ + return ch == 0x20 /* space */ + || ch == 0x09; /* horizontal tab */ +} + +/** + * Checks for a control character. + * + * @returns true / false. + * @param ch The character to test. + * + * @note Will return true of ch is '\0'! + */ +DECL_FORCE_INLINE(bool) RTLocCIsCntrl(int ch) +{ + return (unsigned)ch < 32U /* 0..2f */ + || ch == 0x7f; +} + +/** + * Checks for a decimal digit. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsDigit(int ch) +{ + return (unsigned)ch - 0x30 < 10U; /* 30..39 */ +} + +/** + * Checks for a lower case character. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsLower(int ch) +{ + return (unsigned)ch - 0x61U < 26U; /* 61..7a */ +} + +/** + * Checks for an octal digit. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsODigit(int ch) +{ + return (unsigned)ch - 0x30 < 8U; /* 30..37 */ +} + +/** + * Checks for a printable character (whitespace included). + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsPrint(int ch) +{ + return (unsigned)ch - 0x20U < 95U; /* 20..7e */ +} + +/** + * Checks for punctuation (?). + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsPunct(int ch) +{ + return (unsigned)ch - 0x21U < 15U /* 21..2f */ + || (unsigned)ch - 0x3aU < 7U /* 3a..40 */ + || (unsigned)ch - 0x5bU < 6U /* 5a..60 */ + || (unsigned)ch - 0x7bU < 4U /* 7b..7e */; +} + +/** + * Checks for a white-space character. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsSpace(int ch) +{ + return ch == 0x20 /* 20 (space) */ + || (unsigned)ch - 0x09U < 5U; /* 09..0d */ +} + +/** + * Checks for an upper case character. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsUpper(int ch) +{ + return (unsigned)ch - 0x41 < 26U; /* 41..5a */ +} + +/** + * Checks for a hexadecimal digit. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsXDigit(int ch) +{ + return (unsigned)ch - 0x30 < 10U /* 30..39 (0-9) */ + || (unsigned)ch - 0x41 < 6 /* 41..46 (A-F) */ + || (unsigned)ch - 0x61 < 6; /* 61..66 (a-f) */ +} + +/** + * Checks for an alphabetic character. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsAlpha(int ch) +{ + return RTLocCIsLower(ch) || RTLocCIsUpper(ch); +} + +/** + * Checks for an alphanumerical character. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsAlNum(int ch) +{ + return RTLocCIsDigit(ch) || RTLocCIsAlpha(ch); +} + +/** + * Checks for a printable character whitespace excluded. + * + * @returns true / false. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(bool) RTLocCIsGraph(int ch) +{ + return RTLocCIsPrint(ch) && !RTLocCIsBlank(ch); +} + + +/** + * Converts the character to lower case if applicable. + * + * @returns lower cased character or ch. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(int) RTLocCToLower(int ch) +{ + return RTLocCIsUpper(ch) ? (ch) + 0x20 : (ch); +} + +/** + * Converts the character to upper case if applicable. + * + * @returns upper cased character or ch. + * @param ch The character to test. + */ +DECL_FORCE_INLINE(int) RTLocCToUpper(int ch) +{ + return RTLocCIsLower(ch) ? (ch) - 0x20 : (ch); +} + + +/** @} */ + +#endif /* !IPRT_INCLUDED_ctype_h */ diff --git a/include/iprt/dbg.h b/include/iprt/dbg.h new file mode 100644 index 00000000..64a3a94b --- /dev/null +++ b/include/iprt/dbg.h @@ -0,0 +1,2034 @@ +/* $Id: dbg.h $ */ +/** @file + * IPRT - Debugging Routines. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_dbg_h +#define IPRT_INCLUDED_dbg_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/stdarg.h> +#include <iprt/ldr.h> + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_rt_dbg RTDbg - Debugging Routines + * @ingroup grp_rt + * @{ + */ + + +/** Debug segment index. */ +typedef uint32_t RTDBGSEGIDX; +/** Pointer to a debug segment index. */ +typedef RTDBGSEGIDX *PRTDBGSEGIDX; +/** Pointer to a const debug segment index. */ +typedef RTDBGSEGIDX const *PCRTDBGSEGIDX; +/** NIL debug segment index. */ +#define NIL_RTDBGSEGIDX UINT32_C(0xffffffff) +/** The last normal segment index. */ +#define RTDBGSEGIDX_LAST UINT32_C(0xffffffef) +/** Special segment index that indicates that the offset is a relative + * virtual address (RVA). I.e. an offset from the start of the module. */ +#define RTDBGSEGIDX_RVA UINT32_C(0xfffffff0) +/** Special segment index that indicates that the offset is a absolute. */ +#define RTDBGSEGIDX_ABS UINT32_C(0xfffffff1) +/** The last valid special segment index. */ +#define RTDBGSEGIDX_SPECIAL_LAST RTDBGSEGIDX_ABS +/** The last valid special segment index. */ +#define RTDBGSEGIDX_SPECIAL_FIRST (RTDBGSEGIDX_LAST + 1U) + + + +/** @name RTDBGSYMADDR_FLAGS_XXX + * Flags used when looking up a symbol by address. + * @{ */ +/** Less or equal address. (default) */ +#define RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL UINT32_C(0) +/** Greater or equal address. */ +#define RTDBGSYMADDR_FLAGS_GREATER_OR_EQUAL UINT32_C(1) +/** Don't consider absolute symbols in deferred modules. */ +#define RTDBGSYMADDR_FLAGS_SKIP_ABS_IN_DEFERRED UINT32_C(2) +/** Don't search for absolute symbols if it's expensive. */ +#define RTDBGSYMADDR_FLAGS_SKIP_ABS UINT32_C(4) +/** Mask of valid flags. */ +#define RTDBGSYMADDR_FLAGS_VALID_MASK UINT32_C(7) +/** @} */ + +/** @name RTDBGSYMBOLADD_F_XXX - Flags for RTDbgModSymbolAdd and RTDbgAsSymbolAdd. + * @{ */ +/** Replace existing symbol with same address. */ +#define RTDBGSYMBOLADD_F_REPLACE_SAME_ADDR UINT32_C(0x00000001) +/** Replace any existing symbols overlapping the symbol range. */ +#define RTDBGSYMBOLADD_F_REPLACE_ANY UINT32_C(0x00000002) +/** Adjust sizes on address conflict. This applies to the symbol being added + * as well as existing symbols. */ +#define RTDBGSYMBOLADD_F_ADJUST_SIZES_ON_CONFLICT UINT32_C(0x00000004) +/** Mask of valid flags. */ +#define RTDBGSYMBOLADD_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ + +/** Max length (including '\\0') of a segment name. */ +#define RTDBG_SEGMENT_NAME_LENGTH (128 - 8 - 8 - 8 - 4 - 4) + +/** + * Debug module segment. + */ +typedef struct RTDBGSEGMENT +{ + /** The load address. + * RTUINTPTR_MAX if not applicable. */ + RTUINTPTR Address; + /** The image relative virtual address of the segment. + * RTUINTPTR_MAX if not applicable. */ + RTUINTPTR uRva; + /** The segment size. */ + RTUINTPTR cb; + /** The segment flags. (reserved) */ + uint32_t fFlags; + /** The segment index. */ + RTDBGSEGIDX iSeg; + /** Symbol name. */ + char szName[RTDBG_SEGMENT_NAME_LENGTH]; +} RTDBGSEGMENT; +/** Pointer to a debug module segment. */ +typedef RTDBGSEGMENT *PRTDBGSEGMENT; +/** Pointer to a const debug module segment. */ +typedef RTDBGSEGMENT const *PCRTDBGSEGMENT; + + +/** + * Return type. + */ +typedef enum RTDBGRETURNTYPE +{ + /** The usual invalid 0 value. */ + RTDBGRETURNTYPE_INVALID = 0, + /** Near 16-bit return. */ + RTDBGRETURNTYPE_NEAR16, + /** Near 32-bit return. */ + RTDBGRETURNTYPE_NEAR32, + /** Near 64-bit return. */ + RTDBGRETURNTYPE_NEAR64, + /** Far 16:16 return. */ + RTDBGRETURNTYPE_FAR16, + /** Far 16:32 return. */ + RTDBGRETURNTYPE_FAR32, + /** Far 16:64 return. */ + RTDBGRETURNTYPE_FAR64, + /** 16-bit iret return (e.g. real or 286 protect mode). */ + RTDBGRETURNTYPE_IRET16, + /** 32-bit iret return. */ + RTDBGRETURNTYPE_IRET32, + /** 32-bit iret return. */ + RTDBGRETURNTYPE_IRET32_PRIV, + /** 32-bit iret return to V86 mode. */ + RTDBGRETURNTYPE_IRET32_V86, + /** @todo 64-bit iret return. */ + RTDBGRETURNTYPE_IRET64, + /** The end of the valid return types. */ + RTDBGRETURNTYPE_END, + /** The usual 32-bit blowup. */ + RTDBGRETURNTYPE_32BIT_HACK = 0x7fffffff +} RTDBGRETURNTYPE; + +/** + * Figures the size of the return state on the stack. + * + * @returns number of bytes. 0 if invalid parameter. + * @param enmRetType The type of return. + */ +DECLINLINE(unsigned) RTDbgReturnTypeSize(RTDBGRETURNTYPE enmRetType) +{ + switch (enmRetType) + { + case RTDBGRETURNTYPE_NEAR16: return 2; + case RTDBGRETURNTYPE_NEAR32: return 4; + case RTDBGRETURNTYPE_NEAR64: return 8; + case RTDBGRETURNTYPE_FAR16: return 4; + case RTDBGRETURNTYPE_FAR32: return 4; + case RTDBGRETURNTYPE_FAR64: return 8; + case RTDBGRETURNTYPE_IRET16: return 6; + case RTDBGRETURNTYPE_IRET32: return 4*3; + case RTDBGRETURNTYPE_IRET32_PRIV: return 4*5; + case RTDBGRETURNTYPE_IRET32_V86: return 4*9; + case RTDBGRETURNTYPE_IRET64: return 5*8; + + case RTDBGRETURNTYPE_INVALID: + case RTDBGRETURNTYPE_END: + case RTDBGRETURNTYPE_32BIT_HACK: + break; + } + return 0; +} + +/** + * Check if near return. + * + * @returns true if near, false if far or iret. + * @param enmRetType The type of return. + */ +DECLINLINE(bool) RTDbgReturnTypeIsNear(RTDBGRETURNTYPE enmRetType) +{ + return enmRetType == RTDBGRETURNTYPE_NEAR32 + || enmRetType == RTDBGRETURNTYPE_NEAR64 + || enmRetType == RTDBGRETURNTYPE_NEAR16; +} + + + +/** Magic value for RTDBGUNWINDSTATE::u32Magic (James Moody). */ +#define RTDBGUNWINDSTATE_MAGIC UINT32_C(0x19250326) +/** Magic value for RTDBGUNWINDSTATE::u32Magic after use. */ +#define RTDBGUNWINDSTATE_MAGIC_DEAD UINT32_C(0x20101209) + +/** + * Unwind machine state. + */ +typedef struct RTDBGUNWINDSTATE +{ + /** Structure magic (RTDBGUNWINDSTATE_MAGIC) */ + uint32_t u32Magic; + /** The state architecture. */ + RTLDRARCH enmArch; + + /** The program counter register. + * amd64/x86: RIP/EIP/IP + * sparc: PC + * arm32: PC / R15 + */ + uint64_t uPc; + + /** Return type. */ + RTDBGRETURNTYPE enmRetType; + + /** Register state (see enmArch). */ + union + { + /** RTLDRARCH_AMD64, RTLDRARCH_X86_32 and RTLDRARCH_X86_16. */ + struct + { + /** General purpose registers indexed by X86_GREG_XXX. */ + uint64_t auRegs[16]; + /** The frame address. */ + RTFAR64 FrameAddr; + /** Set if we're in real or virtual 8086 mode. */ + bool fRealOrV86; + /** The flags register. */ + uint64_t uRFlags; + /** Trap error code. */ + uint64_t uErrCd; + /** Segment registers (indexed by X86_SREG_XXX). */ + uint16_t auSegs[6]; + + /** Bitmap tracking register we've loaded and which content can possibly be trusted. */ + union + { + /** For effective clearing of the bits. */ + uint32_t fAll; + /** Detailed view. */ + struct + { + /** Bitmap indicating whether a GPR was loaded (parallel to auRegs). */ + uint16_t fRegs; + /** Bitmap indicating whether a segment register was loaded (parallel to auSegs). */ + uint8_t fSegs; + /** Set if uPc was loaded. */ + RT_GCC_EXTENSION uint8_t fPc : 1; + /** Set if FrameAddr was loaded. */ + RT_GCC_EXTENSION uint8_t fFrameAddr : 1; + /** Set if uRFlags was loaded. */ + RT_GCC_EXTENSION uint8_t fRFlags : 1; + /** Set if uErrCd was loaded. */ + RT_GCC_EXTENSION uint8_t fErrCd : 1; + } s; + } Loaded; + } x86; + + /** @todo add ARM and others as needed. */ + } u; + + /** + * Stack read callback. + * + * @returns IPRT status code. + * @param pThis Pointer to this structure. + * @param uSp The stack pointer address. + * @param cbToRead The number of bytes to read. + * @param pvDst Where to put the bytes we read. + */ + DECLCALLBACKMEMBER(int, pfnReadStack,(struct RTDBGUNWINDSTATE *pThis, RTUINTPTR uSp, size_t cbToRead, void *pvDst)); + /** User argument (useful for pfnReadStack). */ + void *pvUser; + +} RTDBGUNWINDSTATE; + +/** + * Try read a 16-bit value off the stack. + * + * @returns pfnReadStack result. + * @param pThis The unwind state. + * @param uSrcAddr The stack address. + * @param puDst The read destination. + */ +DECLINLINE(int) RTDbgUnwindLoadStackU16(PRTDBGUNWINDSTATE pThis, RTUINTPTR uSrcAddr, uint16_t *puDst) +{ + return pThis->pfnReadStack(pThis, uSrcAddr, sizeof(*puDst), puDst); +} + +/** + * Try read a 32-bit value off the stack. + * + * @returns pfnReadStack result. + * @param pThis The unwind state. + * @param uSrcAddr The stack address. + * @param puDst The read destination. + */ +DECLINLINE(int) RTDbgUnwindLoadStackU32(PRTDBGUNWINDSTATE pThis, RTUINTPTR uSrcAddr, uint32_t *puDst) +{ + return pThis->pfnReadStack(pThis, uSrcAddr, sizeof(*puDst), puDst); +} + +/** + * Try read a 64-bit value off the stack. + * + * @returns pfnReadStack result. + * @param pThis The unwind state. + * @param uSrcAddr The stack address. + * @param puDst The read destination. + */ +DECLINLINE(int) RTDbgUnwindLoadStackU64(PRTDBGUNWINDSTATE pThis, RTUINTPTR uSrcAddr, uint64_t *puDst) +{ + return pThis->pfnReadStack(pThis, uSrcAddr, sizeof(*puDst), puDst); +} + + + +/** Max length (including '\\0') of a symbol name. */ +#define RTDBG_SYMBOL_NAME_LENGTH (512 - 8 - 8 - 8 - 4 - 4 - 8) + +/** + * Debug symbol. + */ +typedef struct RTDBGSYMBOL +{ + /** Symbol value (address). + * This depends a bit who you ask. It will be the same as offSeg when you + * as RTDbgMod, but the mapping address if you ask RTDbgAs. */ + RTUINTPTR Value; + /** Symbol size. */ + RTUINTPTR cb; + /** Offset into the segment specified by iSeg. */ + RTUINTPTR offSeg; + /** Segment number. */ + RTDBGSEGIDX iSeg; + /** Symbol Flags. (reserved). */ + uint32_t fFlags; + /** Symbol ordinal. + * This is set to UINT32_MAX if the ordinals aren't supported. */ + uint32_t iOrdinal; + /** Symbol name. */ + char szName[RTDBG_SYMBOL_NAME_LENGTH]; +} RTDBGSYMBOL; +/** Pointer to debug symbol. */ +typedef RTDBGSYMBOL *PRTDBGSYMBOL; +/** Pointer to const debug symbol. */ +typedef const RTDBGSYMBOL *PCRTDBGSYMBOL; + + +/** + * Allocate a new symbol structure. + * + * @returns Pointer to a new structure on success, NULL on failure. + */ +RTDECL(PRTDBGSYMBOL) RTDbgSymbolAlloc(void); + +/** + * Duplicates a symbol structure. + * + * @returns Pointer to duplicate on success, NULL on failure. + * + * @param pSymInfo The symbol info to duplicate. + */ +RTDECL(PRTDBGSYMBOL) RTDbgSymbolDup(PCRTDBGSYMBOL pSymInfo); + +/** + * Free a symbol structure previously allocated by a RTDbg method. + * + * @param pSymInfo The symbol info to free. NULL is ignored. + */ +RTDECL(void) RTDbgSymbolFree(PRTDBGSYMBOL pSymInfo); + + +/** Max length (including '\\0') of a debug info file name. */ +#define RTDBG_FILE_NAME_LENGTH (260) + + +/** + * Debug line number information. + */ +typedef struct RTDBGLINE +{ + /** Address. + * This depends a bit who you ask. It will be the same as offSeg when you + * as RTDbgMod, but the mapping address if you ask RTDbgAs. */ + RTUINTPTR Address; + /** Offset into the segment specified by iSeg. */ + RTUINTPTR offSeg; + /** Segment number. */ + RTDBGSEGIDX iSeg; + /** Line number. */ + uint32_t uLineNo; + /** Symbol ordinal. + * This is set to UINT32_MAX if the ordinals aren't supported. */ + uint32_t iOrdinal; + /** Filename. */ + char szFilename[RTDBG_FILE_NAME_LENGTH]; +} RTDBGLINE; +/** Pointer to debug line number. */ +typedef RTDBGLINE *PRTDBGLINE; +/** Pointer to const debug line number. */ +typedef const RTDBGLINE *PCRTDBGLINE; + +/** + * Allocate a new line number structure. + * + * @returns Pointer to a new structure on success, NULL on failure. + */ +RTDECL(PRTDBGLINE) RTDbgLineAlloc(void); + +/** + * Duplicates a line number structure. + * + * @returns Pointer to duplicate on success, NULL on failure. + * + * @param pLine The line number to duplicate. + */ +RTDECL(PRTDBGLINE) RTDbgLineDup(PCRTDBGLINE pLine); + +/** + * Free a line number structure previously allocated by a RTDbg method. + * + * @param pLine The line number to free. NULL is ignored. + */ +RTDECL(void) RTDbgLineFree(PRTDBGLINE pLine); + + +/** + * Dump the stack of the current thread into @a pszStack. + * + * This could be a little slow as it reads image and debug info again for each call. + * + * @returns Length of string returned in @a pszStack. + * @param pszStack The output buffer. + * @param cbStack The size of the output buffer. + * @param fFlags Future flags, MBZ. + * + * @remarks Not present on all systems and contexts. + */ +RTDECL(size_t) RTDbgStackDumpSelf(char *pszStack, size_t cbStack, uint32_t fFlags); + + +# ifdef IN_RING3 + +/** @defgroup grp_rt_dbgcfg RTDbgCfg - Debugging Configuration + * + * The settings used when loading and processing debug info is kept in a + * RTDBGCFG instance since it's generally shared for a whole debugging session + * and anyhow would be a major pain to pass as individual parameters to each + * call. The debugging config API not only keeps the settings information but + * also provide APIs for making use of it, and in some cases, like for instance + * symbol severs, retriving and maintaining it. + * + * @todo Work in progress - APIs are still missing, adding when needed. + * + * @{ + */ + +/** Debugging configuration handle. */ +typedef struct RTDBGCFGINT *RTDBGCFG; +/** Pointer to a debugging configuration handle. */ +typedef RTDBGCFG *PRTDBGCFG; +/** NIL debug configuration handle. */ +#define NIL_RTDBGCFG ((RTDBGCFG)0) + +/** @name RTDBGCFG_FLAGS_XXX - Debugging configuration flags. + * @{ */ +/** Use deferred loading. */ +#define RTDBGCFG_FLAGS_DEFERRED RT_BIT_64(0) +/** Don't use the symbol server (http). */ +#define RTDBGCFG_FLAGS_NO_SYM_SRV RT_BIT_64(1) +/** Don't use system search paths. + * On windows this means not using _NT_ALT_SYMBOL_PATH, _NT_SYMBOL_PATH, + * _NT_SOURCE_PATH, and _NT_EXECUTABLE_PATH. + * On other systems the effect has yet to be determined. */ +#define RTDBGCFG_FLAGS_NO_SYSTEM_PATHS RT_BIT_64(2) +/** Don't search the debug and image paths recursively. */ +#define RTDBGCFG_FLAGS_NO_RECURSIV_SEARCH RT_BIT_64(3) +/** Don't search the source paths recursively. */ +#define RTDBGCFG_FLAGS_NO_RECURSIV_SRC_SEARCH RT_BIT_64(4) +/** @} */ + +/** + * Debugging configuration properties. + * + * The search paths are using the DOS convention of semicolon as separator + * character. The the special 'srv' + asterisk syntax known from the windows + * debugger search paths are also supported to some extent, as is 'cache' + + * asterisk. + */ +typedef enum RTDBGCFGPROP +{ + /** The customary invalid 0 value. */ + RTDBGCFGPROP_INVALID = 0, + /** RTDBGCFG_FLAGS_XXX. + * Env: _FLAGS + * The environment variable can be specified as a unsigned value or one or more + * mnemonics separated by spaces. */ + RTDBGCFGPROP_FLAGS, + /** List of paths to search for symbol files and images. + * Env: _PATH */ + RTDBGCFGPROP_PATH, + /** List of symbol file suffixes (semicolon separated). + * Env: _SUFFIXES */ + RTDBGCFGPROP_SUFFIXES, + /** List of paths to search for source files. + * Env: _SRC_PATH */ + RTDBGCFGPROP_SRC_PATH, + /** End of valid values. */ + RTDBGCFGPROP_END, + /** The customary 32-bit type hack. */ + RTDBGCFGPROP_32BIT_HACK = 0x7fffffff +} RTDBGCFGPROP; + +/** + * Configuration property change operation. + */ +typedef enum RTDBGCFGOP +{ + /** Customary invalid 0 value. */ + RTDBGCFGOP_INVALID = 0, + /** Replace the current value with the given one. */ + RTDBGCFGOP_SET, + /** Append the given value to the existing one. For integer values this is + * considered a bitwise OR operation. */ + RTDBGCFGOP_APPEND, + /** Prepend the given value to the existing one. For integer values this is + * considered a bitwise OR operation. */ + RTDBGCFGOP_PREPEND, + /** Removes the value from the existing one. For interger values the value is + * complemented and ANDed with the existing one, clearing all the specified + * flags/bits. */ + RTDBGCFGOP_REMOVE, + /** End of valid values. */ + RTDBGCFGOP_END, + /** Customary 32-bit type hack. */ + RTDBGCFGOP_32BIT_HACK = 0x7fffffff +} RTDBGCFGOP; + + + +/** + * Initializes a debugging configuration. + * + * @returns IPRT status code. + * @param phDbgCfg Where to return the configuration handle. + * @param pszEnvVarPrefix The environment variable prefix. If NULL, the + * environment is not consulted. + * @param fNativePaths Whether to pick up native paths from the + * environment. + * + * @sa RTDbgCfgChangeString, RTDbgCfgChangeUInt. + */ +RTDECL(int) RTDbgCfgCreate(PRTDBGCFG phDbgCfg, const char *pszEnvVarPrefix, bool fNativePaths); + +/** + * Retains a new reference to a debugging config. + * + * @returns New reference count. + * UINT32_MAX is returned if the handle is invalid (asserted). + * @param hDbgCfg The config handle. + */ +RTDECL(uint32_t) RTDbgCfgRetain(RTDBGCFG hDbgCfg); + +/** + * Releases a references to a debugging config. + * + * @returns New reference count, if 0 the config was freed. UINT32_MAX is + * returned if the handle is invalid (asserted). + * @param hDbgCfg The config handle. + */ +RTDECL(uint32_t) RTDbgCfgRelease(RTDBGCFG hDbgCfg); + +/** + * Changes a property value by string. + * + * For string values the string is used more or less as given. For integer + * values and flags, it can contains both values (ORed together) or property + * specific mnemonics (ORed / ~ANDed). + * + * @returns IPRT status code. + * @retval VERR_DBG_CFG_INVALID_VALUE + * @param hDbgCfg The debugging configuration handle. + * @param enmProp The property to change. + * @param enmOp How to change the property. + * @param pszValue The property value to apply. + */ +RTDECL(int) RTDbgCfgChangeString(RTDBGCFG hDbgCfg, RTDBGCFGPROP enmProp, RTDBGCFGOP enmOp, const char *pszValue); + +/** + * Changes a property value by unsigned integer (64-bit). + * + * This can only be applied to integer and flag properties. + * + * @returns IPRT status code. + * @retval VERR_DBG_CFG_NOT_UINT_PROP + * @param hDbgCfg The debugging configuration handle. + * @param enmProp The property to change. + * @param enmOp How to change the property. + * @param uValue The property value to apply. + */ +RTDECL(int) RTDbgCfgChangeUInt(RTDBGCFG hDbgCfg, RTDBGCFGPROP enmProp, RTDBGCFGOP enmOp, uint64_t uValue); + +/** + * Query a property value as string. + * + * Integer and flags properties are returned as a list of mnemonics if possible, + * otherwise as simple hex values. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if there isn't sufficient buffer space. Nothing + * is written. + * @param hDbgCfg The debugging configuration handle. + * @param enmProp The property to change. + * @param pszValue The output buffer. + * @param cbValue The size of the output buffer. + */ +RTDECL(int) RTDbgCfgQueryString(RTDBGCFG hDbgCfg, RTDBGCFGPROP enmProp, char *pszValue, size_t cbValue); + +/** + * Query a property value as unsigned integer (64-bit). + * + * Only integer and flags properties can be queried this way. + * + * @returns IPRT status code. + * @retval VERR_DBG_CFG_NOT_UINT_PROP + * @param hDbgCfg The debugging configuration handle. + * @param enmProp The property to change. + * @param puValue Where to return the value. + */ +RTDECL(int) RTDbgCfgQueryUInt(RTDBGCFG hDbgCfg, RTDBGCFGPROP enmProp, uint64_t *puValue); + +/** + * Log callback. + * + * @param hDbgCfg The debug config instance. + * @param iLevel The message level. + * @param pszMsg The message. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(void, FNRTDBGCFGLOG,(RTDBGCFG hDbgCfg, uint32_t iLevel, const char *pszMsg, void *pvUser)); +/** Pointer to a log callback. */ +typedef FNRTDBGCFGLOG *PFNRTDBGCFGLOG; + +/** + * Sets the log callback for the configuration. + * + * This will fail if there is already a log callback present, unless pfnCallback + * is NULL. + * + * @returns IPRT status code. + * @param hDbgCfg The debugging configuration handle. + * @param pfnCallback The callback function. NULL to unset. + * @param pvUser The user argument. + */ +RTDECL(int) RTDbgCfgSetLogCallback(RTDBGCFG hDbgCfg, PFNRTDBGCFGLOG pfnCallback, void *pvUser); + +/** + * Callback used by the RTDbgCfgOpen function to try out a file that was found. + * + * @returns On statuses other than VINF_CALLBACK_RETURN and + * VERR_CALLBACK_RETURN the search will continue till the end of the + * list. These status codes will not necessarily be propagated to the + * caller in any consistent manner. + * @retval VINF_CALLBACK_RETURN if successfully opened the file and it's time + * to return + * @retval VERR_CALLBACK_RETURN if we should stop searching immediately. + * + * @param hDbgCfg The debugging configuration handle. + * @param pszFilename The path to the file that should be tried out. + * @param pvUser1 First user parameter. + * @param pvUser2 Second user parameter. + */ +typedef DECLCALLBACKTYPE(int, FNRTDBGCFGOPEN,(RTDBGCFG hDbgCfg, const char *pszFilename, void *pvUser1, void *pvUser2)); +/** Pointer to a open-file callback used to the RTDbgCfgOpen functions. */ +typedef FNRTDBGCFGOPEN *PFNRTDBGCFGOPEN; + + +RTDECL(int) RTDbgCfgOpenEx(RTDBGCFG hDbgCfg, const char *pszFilename, const char *pszCacheSubDir, + const char *pszUuidMappingSubDir, uint32_t fFlags, + PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); +RTDECL(int) RTDbgCfgOpenPeImage(RTDBGCFG hDbgCfg, const char *pszFilename, uint32_t cbImage, uint32_t uTimestamp, + PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); +RTDECL(int) RTDbgCfgOpenPdb70(RTDBGCFG hDbgCfg, const char *pszFilename, PCRTUUID pUuid, uint32_t uAge, + PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); +RTDECL(int) RTDbgCfgOpenPdb20(RTDBGCFG hDbgCfg, const char *pszFilename, uint32_t cbImage, uint32_t uTimestamp, uint32_t uAge, + PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); +RTDECL(int) RTDbgCfgOpenDbg(RTDBGCFG hDbgCfg, const char *pszFilename, uint32_t cbImage, uint32_t uTimestamp, + PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); +RTDECL(int) RTDbgCfgOpenDwo(RTDBGCFG hDbgCfg, const char *pszFilename, uint32_t uCrc32, + PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); +RTDECL(int) RTDbgCfgOpenDwoBuildId(RTDBGCFG hDbgCfg, const char *pszFilename, const uint8_t *pbBuildId, + size_t cbBuildId, PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); +RTDECL(int) RTDbgCfgOpenDsymBundle(RTDBGCFG hDbgCfg, const char *pszFilename, PCRTUUID pUuid, + PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); +RTDECL(int) RTDbgCfgOpenMachOImage(RTDBGCFG hDbgCfg, const char *pszFilename, PCRTUUID pUuid, + PFNRTDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2); + +/** @name RTDBGCFG_O_XXX - Open flags for RTDbgCfgOpen. + * @{ */ +/** The operative system mask. The values are RT_OPSYS_XXX. */ +#define RTDBGCFG_O_OPSYS_MASK UINT32_C(0x000000ff) +/** Use debuginfod style symbol servers when encountered in the path. */ +#define RTDBGCFG_O_DEBUGINFOD RT_BIT_32(24) +/** Same as RTDBGCFG_FLAGS_NO_SYSTEM_PATHS. */ +#define RTDBGCFG_O_NO_SYSTEM_PATHS RT_BIT_32(25) +/** The files may be compressed MS styled. */ +#define RTDBGCFG_O_MAYBE_COMPRESSED_MS RT_BIT_32(26) +/** Whether to make a recursive search. */ +#define RTDBGCFG_O_RECURSIVE RT_BIT_32(27) +/** We're looking for a separate debug file. */ +#define RTDBGCFG_O_EXT_DEBUG_FILE RT_BIT_32(28) +/** We're looking for an executable image. */ +#define RTDBGCFG_O_EXECUTABLE_IMAGE RT_BIT_32(29) +/** The file search should be done in an case insensitive fashion. */ +#define RTDBGCFG_O_CASE_INSENSITIVE RT_BIT_32(30) +/** Use Windbg style symbol servers when encountered in the path. */ +#define RTDBGCFG_O_SYMSRV RT_BIT_32(31) +/** Mask of valid flags. */ +#define RTDBGCFG_O_VALID_MASK UINT32_C(0xff0000ff) +/** @} */ + + +/** @name Static symbol cache configuration + * @{ */ +/** The cache subdirectory containing the UUID mappings for .dSYM bundles. + * The UUID mappings implemented by IPRT are splitting the image/dsym UUID up + * into five 4 digit parts that maps to directories and one twelve digit part + * that maps to a symbolic link. The symlink points to the file in the + * Contents/Resources/DWARF/ directory of the .dSYM bundle for a .dSYM map, and + * to the image file (Contents/MacOS/bundlename for bundles) for image map. + * + * According to available documentation, both lldb and gdb are able to use these + * UUID maps to find debug info while debugging. See: + * http://lldb.llvm.org/symbols.html + */ +#define RTDBG_CACHE_UUID_MAP_DIR_DSYMS "dsym-uuids" +/** The cache subdirectory containing the UUID mappings for image files. */ +#define RTDBG_CACHE_UUID_MAP_DIR_IMAGES "image-uuids" +/** Suffix used for the cached .dSYM debug files. + * In .dSYM bundles only the .dSYM/Contents/Resources/DWARF/debug-file is + * copied into the cache, and in order to not clash with the stripped/rich image + * file, the cache tool slaps this suffix onto the name. */ +#define RTDBG_CACHE_DSYM_FILE_SUFFIX ".dwarf" +/** @} */ + +# endif /* IN_RING3 */ + +/** @} */ + + +/** @defgroup grp_rt_dbgas RTDbgAs - Debug Address Space + * @{ + */ + +/** + * Creates an empty address space. + * + * @returns IPRT status code. + * + * @param phDbgAs Where to store the address space handle on success. + * @param FirstAddr The first address in the address space. + * @param LastAddr The last address in the address space. + * @param pszName The name of the address space. + */ +RTDECL(int) RTDbgAsCreate(PRTDBGAS phDbgAs, RTUINTPTR FirstAddr, RTUINTPTR LastAddr, const char *pszName); + +/** + * Variant of RTDbgAsCreate that takes a name format string. + * + * @returns IPRT status code. + * + * @param phDbgAs Where to store the address space handle on success. + * @param FirstAddr The first address in the address space. + * @param LastAddr The last address in the address space. + * @param pszNameFmt The name format of the address space. + * @param va Format arguments. + */ +RTDECL(int) RTDbgAsCreateV(PRTDBGAS phDbgAs, RTUINTPTR FirstAddr, RTUINTPTR LastAddr, + const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(4, 0); + +/** + * Variant of RTDbgAsCreate that takes a name format string. + * + * @returns IPRT status code. + * + * @param phDbgAs Where to store the address space handle on success. + * @param FirstAddr The first address in the address space. + * @param LastAddr The last address in the address space. + * @param pszNameFmt The name format of the address space. + * @param ... Format arguments. + */ +RTDECL(int) RTDbgAsCreateF(PRTDBGAS phDbgAs, RTUINTPTR FirstAddr, RTUINTPTR LastAddr, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(4, 5); + +/** + * Retains a reference to the address space. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hDbgAs The address space handle. + * + * @remarks Will not take any locks. + */ +RTDECL(uint32_t) RTDbgAsRetain(RTDBGAS hDbgAs); + +/** + * Release a reference to the address space. + * + * When the reference count reaches zero, the address space is destroyed. + * That means unlinking all the modules it currently contains, potentially + * causing some or all of them to be destroyed as they are managed by + * reference counting. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hDbgAs The address space handle. The NIL handle is quietly + * ignored and 0 is returned. + * + * @remarks Will not take any locks. + */ +RTDECL(uint32_t) RTDbgAsRelease(RTDBGAS hDbgAs); + +/** + * Locks the address space for exclusive access. + * + * @returns IRPT status code + * @param hDbgAs The address space handle. + */ +RTDECL(int) RTDbgAsLockExcl(RTDBGAS hDbgAs); + +/** + * Counters the actions of one RTDbgAsUnlockExcl call. + * + * @returns IRPT status code + * @param hDbgAs The address space handle. + */ +RTDECL(int) RTDbgAsUnlockExcl(RTDBGAS hDbgAs); + +/** + * Gets the name of an address space. + * + * @returns read only address space name. + * NULL if hDbgAs is invalid. + * + * @param hDbgAs The address space handle. + * + * @remarks Will not take any locks. + */ +RTDECL(const char *) RTDbgAsName(RTDBGAS hDbgAs); + +/** + * Gets the first address in an address space. + * + * @returns The address. + * 0 if hDbgAs is invalid. + * + * @param hDbgAs The address space handle. + * + * @remarks Will not take any locks. + */ +RTDECL(RTUINTPTR) RTDbgAsFirstAddr(RTDBGAS hDbgAs); + +/** + * Gets the last address in an address space. + * + * @returns The address. + * 0 if hDbgAs is invalid. + * + * @param hDbgAs The address space handle. + * + * @remarks Will not take any locks. + */ +RTDECL(RTUINTPTR) RTDbgAsLastAddr(RTDBGAS hDbgAs); + +/** + * Gets the number of modules in the address space. + * + * This can be used together with RTDbgAsModuleByIndex + * to enumerate the modules. + * + * @returns The number of modules. + * + * @param hDbgAs The address space handle. + * + * @remarks Will not take any locks. + */ +RTDECL(uint32_t) RTDbgAsModuleCount(RTDBGAS hDbgAs); + +/** @name Flags for RTDbgAsModuleLink and RTDbgAsModuleLinkSeg + * @{ */ +/** Replace all conflicting module. + * (The conflicting modules will be removed the address space and their + * references released.) */ +#define RTDBGASLINK_FLAGS_REPLACE RT_BIT_32(0) +/** Mask containing the valid flags. */ +#define RTDBGASLINK_FLAGS_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Links a module into the address space at the give address. + * + * The size of the mapping is determined using RTDbgModImageSize(). + * + * @returns IPRT status code. + * @retval VERR_OUT_OF_RANGE if the specified address will put the module + * outside the address space. + * @retval VERR_ADDRESS_CONFLICT if the mapping clashes with existing mappings. + * + * @param hDbgAs The address space handle. + * @param hDbgMod The module handle of the module to be linked in. + * @param ImageAddr The address to link the module at. + * @param fFlags See RTDBGASLINK_FLAGS_*. + */ +RTDECL(int) RTDbgAsModuleLink(RTDBGAS hDbgAs, RTDBGMOD hDbgMod, RTUINTPTR ImageAddr, uint32_t fFlags); + +/** + * Links a segment into the address space at the give address. + * + * The size of the mapping is determined using RTDbgModSegmentSize(). + * + * @returns IPRT status code. + * @retval VERR_OUT_OF_RANGE if the specified address will put the module + * outside the address space. + * @retval VERR_ADDRESS_CONFLICT if the mapping clashes with existing mappings. + * + * @param hDbgAs The address space handle. + * @param hDbgMod The module handle. + * @param iSeg The segment number (0-based) of the segment to be + * linked in. + * @param SegAddr The address to link the segment at. + * @param fFlags See RTDBGASLINK_FLAGS_*. + */ +RTDECL(int) RTDbgAsModuleLinkSeg(RTDBGAS hDbgAs, RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR SegAddr, uint32_t fFlags); + +/** + * Unlinks all the mappings of a module from the address space. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if the module wasn't found. + * + * @param hDbgAs The address space handle. + * @param hDbgMod The module handle of the module to be unlinked. + */ +RTDECL(int) RTDbgAsModuleUnlink(RTDBGAS hDbgAs, RTDBGMOD hDbgMod); + +/** + * Unlinks the mapping at the specified address. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if no module or segment is mapped at that address. + * + * @param hDbgAs The address space handle. + * @param Addr The address within the mapping to be unlinked. + */ +RTDECL(int) RTDbgAsModuleUnlinkByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr); + +/** + * Get a the handle of a module in the address space by is index. + * + * @returns A retained handle to the specified module. The caller must release + * the returned reference. + * NIL_RTDBGMOD if invalid index or handle. + * + * @param hDbgAs The address space handle. + * @param iModule The index of the module to get. + * + * @remarks The module indexes may change after calls to RTDbgAsModuleLink, + * RTDbgAsModuleLinkSeg, RTDbgAsModuleUnlink and + * RTDbgAsModuleUnlinkByAddr. + */ +RTDECL(RTDBGMOD) RTDbgAsModuleByIndex(RTDBGAS hDbgAs, uint32_t iModule); + +/** + * Queries mapping module information by handle. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if no mapping was found at the specified address. + * + * @param hDbgAs The address space handle. + * @param Addr Address within the mapping of the module or segment. + * @param phMod Where to the return the retained module handle. + * Optional. + * @param pAddr Where to return the base address of the mapping. + * Optional. + * @param piSeg Where to return the segment index. This is set to + * NIL if the entire module is mapped as a single + * mapping. Optional. + */ +RTDECL(int) RTDbgAsModuleByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTDBGMOD phMod, PRTUINTPTR pAddr, PRTDBGSEGIDX piSeg); + +/** + * Queries mapping module information by name. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if no mapping was found at the specified address. + * @retval VERR_OUT_OF_RANGE if the name index was out of range. + * + * @param hDbgAs The address space handle. + * @param pszName The module name. + * @param iName There can be more than one module by the same name + * in an address space. This argument indicates which + * is meant. (0 based) + * @param phMod Where to the return the retained module handle. + */ +RTDECL(int) RTDbgAsModuleByName(RTDBGAS hDbgAs, const char *pszName, uint32_t iName, PRTDBGMOD phMod); + +/** + * Information about a mapping. + * + * This is used by RTDbgAsModuleGetMapByIndex. + */ +typedef struct RTDBGASMAPINFO +{ + /** The mapping address. */ + RTUINTPTR Address; + /** The segment mapped there. + * This is NIL_RTDBGSEGIDX if the entire module image is mapped here. */ + RTDBGSEGIDX iSeg; +} RTDBGASMAPINFO; +/** Pointer to info about an address space mapping. */ +typedef RTDBGASMAPINFO *PRTDBGASMAPINFO; +/** Pointer to const info about an address space mapping. */ +typedef RTDBGASMAPINFO const *PCRTDBGASMAPINFO; + +/** + * Queries mapping information for a module given by index. + * + * @returns IRPT status code. + * @retval VERR_INVALID_HANDLE if hDbgAs is invalid. + * @retval VERR_OUT_OF_RANGE if the name index was out of range. + * @retval VINF_BUFFER_OVERFLOW if the array is too small and the returned + * information is incomplete. + * + * @param hDbgAs The address space handle. + * @param iModule The index of the module to get. + * @param paMappings Where to return the mapping information. The buffer + * size is given by *pcMappings. + * @param pcMappings IN: Size of the paMappings array. OUT: The number of + * entries returned. + * @param fFlags Flags for reserved for future use. MBZ. + * + * @remarks See remarks for RTDbgAsModuleByIndex regarding the volatility of the + * iModule parameter. + */ +RTDECL(int) RTDbgAsModuleQueryMapByIndex(RTDBGAS hDbgAs, uint32_t iModule, PRTDBGASMAPINFO paMappings, uint32_t *pcMappings, uint32_t fFlags); + +/** + * Adds a symbol to a module in the address space. + * + * @returns IPRT status code. See RTDbgModSymbolAdd for more specific ones. + * @retval VERR_INVALID_HANDLE if hDbgAs is invalid. + * @retval VERR_NOT_FOUND if no module was found at the specified address. + * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding + * custom symbols. + * + * @param hDbgAs The address space handle. + * @param pszSymbol The symbol name. + * @param Addr The address of the symbol. + * @param cb The size of the symbol. + * @param fFlags Symbol flags, RTDBGSYMBOLADD_F_XXX. + * @param piOrdinal Where to return the symbol ordinal on success. If + * the interpreter doesn't do ordinals, this will be set to + * UINT32_MAX. Optional + */ +RTDECL(int) RTDbgAsSymbolAdd(RTDBGAS hDbgAs, const char *pszSymbol, RTUINTPTR Addr, RTUINTPTR cb, uint32_t fFlags, uint32_t *piOrdinal); + +/** + * Query a symbol by address. + * + * @returns IPRT status code. See RTDbgModSymbolAddr for more specific ones. + * @retval VERR_INVALID_HANDLE if hDbgAs is invalid. + * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module. + * @retval VERR_INVALID_PARAMETER if incorrect flags. + * + * @param hDbgAs The address space handle. + * @param Addr The address which closest symbol is requested. + * @param fFlags Symbol search flags, see RTDBGSYMADDR_FLAGS_XXX. + * @param poffDisp Where to return the distance between the symbol + * and address. Optional. + * @param pSymbol Where to return the symbol info. + * @param phMod Where to return the module handle. Optional. + */ +RTDECL(int) RTDbgAsSymbolByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, uint32_t fFlags, + PRTINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod); + +/** + * Query a symbol by address. + * + * @returns IPRT status code. See RTDbgModSymbolAddrA for more specific ones. + * @retval VERR_INVALID_HANDLE if hDbgAs is invalid. + * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module. + * @retval VERR_INVALID_PARAMETER if incorrect flags. + * + * @param hDbgAs The address space handle. + * @param Addr The address which closest symbol is requested. + * @param fFlags Symbol search flags, see RTDBGSYMADDR_FLAGS_XXX. + * @param poffDisp Where to return the distance between the symbol + * and address. Optional. + * @param ppSymInfo Where to return the pointer to the allocated symbol + * info. Always set. Free with RTDbgSymbolFree. + * @param phMod Where to return the module handle. Optional. + */ +RTDECL(int) RTDbgAsSymbolByAddrA(RTDBGAS hDbgAs, RTUINTPTR Addr, uint32_t fFlags, + PRTINTPTR poffDisp, PRTDBGSYMBOL *ppSymInfo, PRTDBGMOD phMod); + +/** + * Query a symbol by name. + * + * @returns IPRT status code. + * @retval VERR_SYMBOL_NOT_FOUND if not found. + * + * @param hDbgAs The address space handle. + * @param pszSymbol The symbol name. It is possible to limit the scope + * of the search by prefixing the symbol with a module + * name pattern followed by a bang (!) character. + * RTStrSimplePatternNMatch is used for the matching. + * @param pSymbol Where to return the symbol info. + * @param phMod Where to return the module handle. Optional. + */ +RTDECL(int) RTDbgAsSymbolByName(RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod); + +/** + * Query a symbol by name, allocating the returned symbol structure. + * + * @returns IPRT status code. + * @retval VERR_SYMBOL_NOT_FOUND if not found. + * + * @param hDbgAs The address space handle. + * @param pszSymbol The symbol name. See RTDbgAsSymbolByName for more. + * @param ppSymbol Where to return the pointer to the allocated + * symbol info. Always set. Free with RTDbgSymbolFree. + * @param phMod Where to return the module handle. Optional. + */ +RTDECL(int) RTDbgAsSymbolByNameA(RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL *ppSymbol, PRTDBGMOD phMod); + +/** + * Adds a line number to a module in the address space. + * + * @returns IPRT status code. See RTDbgModLineAdd for more specific ones. + * @retval VERR_INVALID_HANDLE if hDbgAs is invalid. + * @retval VERR_NOT_FOUND if no module was found at the specified address. + * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding + * custom symbols. + * + * @param hDbgAs The address space handle. + * @param pszFile The file name. + * @param uLineNo The line number. + * @param Addr The address of the symbol. + * @param piOrdinal Where to return the line number ordinal on success. + * If the interpreter doesn't do ordinals, this will be + * set to UINT32_MAX. Optional. + */ +RTDECL(int) RTDbgAsLineAdd(RTDBGAS hDbgAs, const char *pszFile, uint32_t uLineNo, RTUINTPTR Addr, uint32_t *piOrdinal); + +/** + * Query a line number by address. + * + * @returns IPRT status code. See RTDbgModLineAddrA for more specific ones. + * @retval VERR_INVALID_HANDLE if hDbgAs is invalid. + * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module. + * + * @param hDbgAs The address space handle. + * @param Addr The address which closest symbol is requested. + * @param poffDisp Where to return the distance between the line + * number and address. + * @param pLine Where to return the line number information. + * @param phMod Where to return the module handle. Optional. + */ +RTDECL(int) RTDbgAsLineByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE pLine, PRTDBGMOD phMod); + +/** + * Query a line number by address. + * + * @returns IPRT status code. See RTDbgModLineAddrA for more specific ones. + * @retval VERR_INVALID_HANDLE if hDbgAs is invalid. + * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module. + * + * @param hDbgAs The address space handle. + * @param Addr The address which closest symbol is requested. + * @param poffDisp Where to return the distance between the line + * number and address. + * @param ppLine Where to return the pointer to the allocated line + * number info. Always set. Free with RTDbgLineFree. + * @param phMod Where to return the module handle. Optional. + */ +RTDECL(int) RTDbgAsLineByAddrA(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE *ppLine, PRTDBGMOD phMod); + +/** @todo Missing some bits here. */ + +/** @} */ + + +# ifdef IN_RING3 +/** @defgroup grp_rt_dbgmod RTDbgMod - Debug Module Interpreter + * @{ + */ + +/** + * Creates a module based on the default debug info container. + * + * This can be used to manually load a module and its symbol. The primary user + * group is the debug info interpreters, which use this API to create an + * efficient debug info container behind the scenes and forward all queries to + * it once the info has been loaded. + * + * @returns IPRT status code. + * + * @param phDbgMod Where to return the module handle. + * @param pszName The name of the module (mandatory). + * @param cbSeg The size of initial segment. If zero, segments will + * have to be added manually using RTDbgModSegmentAdd. + * @param fFlags Flags reserved for future extensions, MBZ for now. + */ +RTDECL(int) RTDbgModCreate(PRTDBGMOD phDbgMod, const char *pszName, RTUINTPTR cbSeg, uint32_t fFlags); + +RTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, + RTLDRARCH enmArch, RTDBGCFG hDbgCfg); +RTDECL(int) RTDbgModCreateFromMap(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, RTUINTPTR uSubtrahend, + RTDBGCFG hDbgCfg); +RTDECL(int) RTDbgModCreateFromPeImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, + PRTLDRMOD phLdrMod, uint32_t cbImage, uint32_t uTimeDateStamp, RTDBGCFG hDbgCfg); +RTDECL(int) RTDbgModCreateFromDbg(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, uint32_t cbImage, + uint32_t uTimeDateStamp, RTDBGCFG hDbgCfg); +RTDECL(int) RTDbgModCreateFromPdb(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, uint32_t cbImage, + PCRTUUID pUuid, uint32_t Age, RTDBGCFG hDbgCfg); +RTDECL(int) RTDbgModCreateFromDwo(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, uint32_t cbImage, + uint32_t uCrc32, RTDBGCFG hDbgCfg); +RTDECL(int) RTDbgModCreateFromMachOImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, + RTLDRARCH enmArch, PRTLDRMOD phLdrModIn, uint32_t cbImage, uint32_t cSegs, + PCRTDBGSEGMENT paSegs, PCRTUUID pUuid, RTDBGCFG hDbgCfg, uint32_t fFlags); + +/** @name Flags for RTDbgModCreate and friends. + * @{ */ +/** Overrides the hDbgCfg settings and forces an image and/or symbol file + * search. RTDbgModCreate will quietly ignore this flag. */ +#define RTDBGMOD_F_NOT_DEFERRED RT_BIT_32(0) +/** Mach-O: Load the __LINKEDIT segment (@sa RTLDR_O_MACHO_LOAD_LINKEDIT). */ +#define RTDBGMOD_F_MACHO_LOAD_LINKEDIT RT_BIT_32(1) +/** Valid flag mask. */ +#define RTDBGMOD_F_VALID_MASK UINT32_C(0x00000003) +/** @} */ + + +/** + * Retains another reference to the module. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hDbgMod The module handle. + * + * @remarks Will not take any locks. + */ +RTDECL(uint32_t) RTDbgModRetain(RTDBGMOD hDbgMod); + +/** + * Release a reference to the module. + * + * When the reference count reaches zero, the module is destroyed. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hDbgMod The module handle. The NIL handle is quietly ignored + * and 0 is returned. + * + * @remarks Will not take any locks. + */ +RTDECL(uint32_t) RTDbgModRelease(RTDBGMOD hDbgMod); + +/** + * Removes all content from the debug module (container), optionally only + * leaving segments and image size intact. + * + * This is only possible on container modules, i.e. created by RTDbgModCreate(). + * + * @returns IPRT status code. + * @param hDbgMod The module handle. + * @param fLeaveSegments Whether to leave segments (and image size) as is. + */ +RTDECL(int) RTDbgModRemoveAll(RTDBGMOD hDbgMod, bool fLeaveSegments); + +/** + * Gets the module name. + * + * @returns Pointer to a read only string containing the name. + * + * @param hDbgMod The module handle. + */ +RTDECL(const char *) RTDbgModName(RTDBGMOD hDbgMod); + +/** + * Gets the name of the debug info file we're using. + * + * @returns Pointer to a read only string containing the filename, NULL if we + * don't use one. + * + * @param hDbgMod The module handle. + */ +RTDECL(const char *) RTDbgModDebugFile(RTDBGMOD hDbgMod); + +/** + * Gets the image filename (as specified by the user). + * + * @returns Pointer to a read only string containing the filename. + * + * @param hDbgMod The module handle. + */ +RTDECL(const char *) RTDbgModImageFile(RTDBGMOD hDbgMod); + +/** + * Gets the image filename actually used if it differs from RTDbgModImageFile. + * + * @returns Pointer to a read only string containing the filename, NULL if same + * as RTDBgModImageFile. + * + * @param hDbgMod The module handle. + */ +RTDECL(const char *) RTDbgModImageFileUsed(RTDBGMOD hDbgMod); + +/** + * Checks if the loading of the debug info has been postponed. + * + * @returns true if postponed, false if not or invalid handle. + * @param hDbgMod The module handle. + */ +RTDECL(bool) RTDbgModIsDeferred(RTDBGMOD hDbgMod); + +/** + * Checks if the debug info is exports only. + * + * @returns true if exports only, false if not or invalid handle. + * @param hDbgMod The module handle. + */ +RTDECL(bool) RTDbgModIsExports(RTDBGMOD hDbgMod); + +/** + * Converts an image relative address to a segment:offset address. + * + * @returns Segment index on success. + * NIL_RTDBGSEGIDX is returned if the module handle or the RVA are + * invalid. + * + * @param hDbgMod The module handle. + * @param uRva The image relative address to convert. + * @param poffSeg Where to return the segment offset. Optional. + */ +RTDECL(RTDBGSEGIDX) RTDbgModRvaToSegOff(RTDBGMOD hDbgMod, RTUINTPTR uRva, PRTUINTPTR poffSeg); + +/** + * Gets the module tag value if any. + * + * @returns The tag. 0 if hDbgMod is invalid. + * + * @param hDbgMod The module handle. + */ +RTDECL(uint64_t) RTDbgModGetTag(RTDBGMOD hDbgMod); + +/** + * Tags or untags the module. + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * + * @param hDbgMod The module handle. + * @param uTag The tag value. The convention is that 0 is no tag + * and any other value means it's tagged. It's adviced + * to use some kind of unique number like an address + * (global or string cache for instance) to avoid + * collisions with other users + */ +RTDECL(int) RTDbgModSetTag(RTDBGMOD hDbgMod, uint64_t uTag); + + +/** + * Image size when mapped if segments are mapped adjacently. + * + * For ELF, PE, and Mach-O images this is (usually) a natural query, for LX and + * NE and such it's a bit odder and the answer may not make much sense for them. + * + * @returns Image mapped size. + * RTUINTPTR_MAX is returned if the handle is invalid. + * + * @param hDbgMod The module handle. + */ +RTDECL(RTUINTPTR) RTDbgModImageSize(RTDBGMOD hDbgMod); + +/** + * Gets the image format. + * + * @returns Image format. + * @retval RTLDRFMT_INVALID if the handle is invalid or if the format isn't known. + * @param hDbgMod The debug module handle. + * @sa RTLdrGetFormat + */ +RTDECL(RTLDRFMT) RTDbgModImageGetFormat(RTDBGMOD hDbgMod); + +/** + * Gets the image architecture. + * + * @returns Image architecture. + * @retval RTLDRARCH_INVALID if the handle is invalid. + * @retval RTLDRARCH_WHATEVER if unknown. + * @param hDbgMod The debug module handle. + * @sa RTLdrGetArch + */ +RTDECL(RTLDRARCH) RTDbgModImageGetArch(RTDBGMOD hDbgMod); + +/** + * Generic method for querying image properties. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the property query isn't supported (either all + * or that specific property). The caller must handle this result. + * @retval VERR_NOT_FOUND the property was not found in the module. The caller + * must also normally deal with this. + * @retval VERR_INVALID_FUNCTION if the function value is wrong. + * @retval VERR_INVALID_PARAMETER if the fixed buffer size is wrong. Correct + * size in @a *pcbRet. + * @retval VERR_BUFFER_OVERFLOW if the function doesn't have a fixed size + * buffer and the buffer isn't big enough. Correct size in @a *pcbRet. + * @retval VERR_INVALID_HANDLE if the handle is invalid. + * + * @param hDbgMod The debug module handle. + * @param enmProp The property to query. + * @param pvBuf Pointer to the input / output buffer. In most cases + * it's only used for returning data. + * @param cbBuf The size of the buffer. + * @param pcbRet Where to return the amount of data returned. On + * buffer size errors, this is set to the correct size. + * Optional. + * @sa RTLdrQueryPropEx + */ +RTDECL(int) RTDbgModImageQueryProp(RTDBGMOD hDbgMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf, size_t *pcbRet); + + +/** + * Adds a segment to the module. Optional feature. + * + * This method is intended used for manually constructing debug info for a + * module. The main usage is from other debug info interpreters that want to + * avoid writing a debug info database and instead uses the standard container + * behind the scenes. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if this feature isn't support by the debug info + * interpreter. This is a common return code. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_DBG_ADDRESS_WRAP if uRva+cb wraps around. + * @retval VERR_DBG_SEGMENT_NAME_OUT_OF_RANGE if pszName is too short or long. + * @retval VERR_INVALID_PARAMETER if fFlags contains undefined flags. + * @retval VERR_DBG_SPECIAL_SEGMENT if *piSeg is a special segment. + * @retval VERR_DBG_INVALID_SEGMENT_INDEX if *piSeg doesn't meet expectations. + * + * @param hDbgMod The module handle. + * @param uRva The image relative address of the segment. + * @param cb The size of the segment. + * @param pszName The segment name. Does not normally need to be + * unique, although this is somewhat up to the + * debug interpreter to decide. + * @param fFlags Segment flags. Reserved for future used, MBZ. + * @param piSeg The segment index or NIL_RTDBGSEGIDX on input. + * The assigned segment index on successful return. + * Optional. + */ +RTDECL(int) RTDbgModSegmentAdd(RTDBGMOD hDbgMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName, + uint32_t fFlags, PRTDBGSEGIDX piSeg); + +/** + * Gets the number of segments in the module. + * + * This is can be used to determine the range which can be passed to + * RTDbgModSegmentByIndex and derivates. + * + * @returns The segment relative address. + * NIL_RTDBGSEGIDX if the handle is invalid. + * + * @param hDbgMod The module handle. + */ +RTDECL(RTDBGSEGIDX) RTDbgModSegmentCount(RTDBGMOD hDbgMod); + +/** + * Query information about a segment. + * + * This can be used together with RTDbgModSegmentCount to enumerate segments. + * The index starts a 0 and stops one below RTDbgModSegmentCount. + * + * @returns IPRT status code. + * @retval VERR_DBG_INVALID_SEGMENT_INDEX if iSeg is too high. + * @retval VERR_DBG_SPECIAL_SEGMENT if iSeg indicates a special segment. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * + * @param hDbgMod The module handle. + * @param iSeg The segment index. No special segments. + * @param pSegInfo Where to return the segment info. The + * RTDBGSEGMENT::Address member will be set to + * RTUINTPTR_MAX or the load address used at link time. + */ +RTDECL(int) RTDbgModSegmentByIndex(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo); + +/** + * Gets the size of a segment. + * + * This is a just a wrapper around RTDbgModSegmentByIndex. + * + * @returns The segment size. + * RTUINTPTR_MAX is returned if either the handle and segment index are + * invalid. + * + * @param hDbgMod The module handle. + * @param iSeg The segment index. RTDBGSEGIDX_ABS is not allowed. + * If RTDBGSEGIDX_RVA is used, the functions returns + * the same value as RTDbgModImageSize. + */ +RTDECL(RTUINTPTR) RTDbgModSegmentSize(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg); + +/** + * Gets the image relative address of a segment. + * + * This is a just a wrapper around RTDbgModSegmentByIndex. + * + * @returns The segment relative address. + * RTUINTPTR_MAX is returned if either the handle and segment index are + * invalid. + * + * @param hDbgMod The module handle. + * @param iSeg The segment index. No special segment indexes + * allowed (asserted). + */ +RTDECL(RTUINTPTR) RTDbgModSegmentRva(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg); + + +/** + * Adds a line number to the module. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding + * custom symbols. This is a common place occurrence. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE if the symbol name is too long or + * short. + * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and + * it's not inside any of the segments defined by the module. + * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid. + * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the + * end of the segment. + * @retval VERR_DBG_ADDRESS_WRAP if off+cb wraps around. + * @retval VERR_INVALID_PARAMETER if the symbol flags sets undefined bits. + * @retval VERR_DBG_DUPLICATE_SYMBOL + * @retval VERR_DBG_ADDRESS_CONFLICT + * + * @param hDbgMod The module handle. + * @param pszSymbol The symbol name. + * @param iSeg The segment index. + * @param off The segment offset. + * @param cb The size of the symbol. Can be zero, although this + * may depend somewhat on the debug interpreter. + * @param fFlags Symbol flags, RTDBGSYMBOLADD_F_XXX. + * @param piOrdinal Where to return the symbol ordinal on success. If + * the interpreter doesn't do ordinals, this will be set to + * UINT32_MAX. Optional. + */ +RTDECL(int) RTDbgModSymbolAdd(RTDBGMOD hDbgMod, const char *pszSymbol, RTDBGSEGIDX iSeg, RTUINTPTR off, + RTUINTPTR cb, uint32_t fFlags, uint32_t *piOrdinal); + +/** + * Gets the symbol count. + * + * This can be used together wtih RTDbgModSymbolByOrdinal or + * RTDbgModSymbolByOrdinalA to enumerate all the symbols. + * + * @returns The number of symbols in the module. + * UINT32_MAX is returned if the module handle is invalid or some other + * error occurs. + * + * @param hDbgMod The module handle. + */ +RTDECL(uint32_t) RTDbgModSymbolCount(RTDBGMOD hDbgMod); + +/** + * Queries symbol information by ordinal number. + * + * @returns IPRT status code. + * @retval VERR_SYMBOL_NOT_FOUND if there is no symbol at the given number. + * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_NOT_SUPPORTED if lookup by ordinal is not supported. + * + * @param hDbgMod The module handle. + * @param iOrdinal The symbol ordinal number. 0-based. The highest + * number is RTDbgModSymbolCount() - 1. + * @param pSymInfo Where to store the symbol information. + */ +RTDECL(int) RTDbgModSymbolByOrdinal(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo); + +/** + * Queries symbol information by ordinal number. + * + * @returns IPRT status code. + * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols. + * @retval VERR_NOT_SUPPORTED if lookup by ordinal is not supported. + * @retval VERR_SYMBOL_NOT_FOUND if there is no symbol at the given number. + * @retval VERR_NO_MEMORY if RTDbgSymbolAlloc fails. + * + * @param hDbgMod The module handle. + * @param iOrdinal The symbol ordinal number. 0-based. The highest + * number is RTDbgModSymbolCount() - 1. + * @param ppSymInfo Where to store the pointer to the returned + * symbol information. Always set. Free with + * RTDbgSymbolFree. + */ +RTDECL(int) RTDbgModSymbolByOrdinalA(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGSYMBOL *ppSymInfo); + +/** + * Queries symbol information by address. + * + * The returned symbol is what the debug info interpreter considers the symbol + * most applicable to the specified address. This usually means a symbol with an + * address equal or lower than the requested. + * + * @returns IPRT status code. + * @retval VERR_SYMBOL_NOT_FOUND if no suitable symbol was found. + * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and + * it's not inside any of the segments defined by the module. + * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid. + * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the + * end of the segment. + * @retval VERR_INVALID_PARAMETER if incorrect flags. + * + * @param hDbgMod The module handle. + * @param iSeg The segment number. + * @param off The offset into the segment. + * @param fFlags Symbol search flags, see RTDBGSYMADDR_FLAGS_XXX. + * @param poffDisp Where to store the distance between the + * specified address and the returned symbol. + * Optional. + * @param pSymInfo Where to store the symbol information. + */ +RTDECL(int) RTDbgModSymbolByAddr(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags, + PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo); + +/** + * Queries symbol information by address. + * + * The returned symbol is what the debug info interpreter considers the symbol + * most applicable to the specified address. This usually means a symbol with an + * address equal or lower than the requested. + * + * @returns IPRT status code. + * @retval VERR_SYMBOL_NOT_FOUND if no suitable symbol was found. + * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and + * it's not inside any of the segments defined by the module. + * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid. + * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the + * end of the segment. + * @retval VERR_NO_MEMORY if RTDbgSymbolAlloc fails. + * @retval VERR_INVALID_PARAMETER if incorrect flags. + * + * @param hDbgMod The module handle. + * @param iSeg The segment index. + * @param off The offset into the segment. + * @param fFlags Symbol search flags, see RTDBGSYMADDR_FLAGS_XXX. + * @param poffDisp Where to store the distance between the + * specified address and the returned symbol. Optional. + * @param ppSymInfo Where to store the pointer to the returned + * symbol information. Always set. Free with + * RTDbgSymbolFree. + */ +RTDECL(int) RTDbgModSymbolByAddrA(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags, + PRTINTPTR poffDisp, PRTDBGSYMBOL *ppSymInfo); + +/** + * Queries symbol information by symbol name. + * + * @returns IPRT status code. + * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols. + * @retval VERR_SYMBOL_NOT_FOUND if no suitable symbol was found. + * @retval VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE if the symbol name is too long or + * short. + * + * @param hDbgMod The module handle. + * @param pszSymbol The symbol name. + * @param pSymInfo Where to store the symbol information. + */ +RTDECL(int) RTDbgModSymbolByName(RTDBGMOD hDbgMod, const char *pszSymbol, PRTDBGSYMBOL pSymInfo); + +/** + * Queries symbol information by symbol name. + * + * @returns IPRT status code. + * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols. + * @retval VERR_SYMBOL_NOT_FOUND if no suitable symbol was found. + * @retval VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE if the symbol name is too long or + * short. + * @retval VERR_NO_MEMORY if RTDbgSymbolAlloc fails. + * + * @param hDbgMod The module handle. + * @param pszSymbol The symbol name. + * @param ppSymInfo Where to store the pointer to the returned + * symbol information. Always set. Free with + * RTDbgSymbolFree. + */ +RTDECL(int) RTDbgModSymbolByNameA(RTDBGMOD hDbgMod, const char *pszSymbol, PRTDBGSYMBOL *ppSymInfo); + +/** + * Adds a line number to the module. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding + * custom symbols. This should be consider a normal response. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_DBG_FILE_NAME_OUT_OF_RANGE if the file name is too longer or + * empty. + * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and + * it's not inside any of the segments defined by the module. + * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid. + * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the + * end of the segment. + * @retval VERR_INVALID_PARAMETER if the line number flags sets undefined bits. + * + * @param hDbgMod The module handle. + * @param pszFile The file name. + * @param uLineNo The line number. + * @param iSeg The segment index. + * @param off The segment offset. + * @param piOrdinal Where to return the line number ordinal on + * success. If the interpreter doesn't do ordinals, + * this will be set to UINT32_MAX. Optional. + */ +RTDECL(int) RTDbgModLineAdd(RTDBGMOD hDbgMod, const char *pszFile, uint32_t uLineNo, + RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t *piOrdinal); + +/** + * Gets the line number count. + * + * This can be used together wtih RTDbgModLineByOrdinal or RTDbgModSymbolByLineA + * to enumerate all the line number information. + * + * @returns The number of line numbers in the module. + * UINT32_MAX is returned if the module handle is invalid or some other + * error occurs. + * + * @param hDbgMod The module handle. + */ +RTDECL(uint32_t) RTDbgModLineCount(RTDBGMOD hDbgMod); + +/** + * Queries line number information by ordinal number. + * + * This can be used to enumerate the line numbers for the module. Use + * RTDbgModLineCount() to figure the end of the ordinals. + * + * @returns IPRT status code. + * @retval VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers. + * @retval VERR_DBG_LINE_NOT_FOUND if there is no line number with that + * ordinal. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + + * @param hDbgMod The module handle. + * @param iOrdinal The line number ordinal number. + * @param pLineInfo Where to store the information about the line + * number. + */ +RTDECL(int) RTDbgModLineByOrdinal(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo); + +/** + * Queries line number information by ordinal number. + * + * This can be used to enumerate the line numbers for the module. Use + * RTDbgModLineCount() to figure the end of the ordinals. + * + * @returns IPRT status code. + * @retval VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers. + * @retval VERR_DBG_LINE_NOT_FOUND if there is no line number with that + * ordinal. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_NO_MEMORY if RTDbgLineAlloc fails. + * + * @param hDbgMod The module handle. + * @param iOrdinal The line number ordinal number. + * @param ppLineInfo Where to store the pointer to the returned line + * number information. Always set. Free with + * RTDbgLineFree. + */ +RTDECL(int) RTDbgModLineByOrdinalA(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGLINE *ppLineInfo); + +/** + * Queries line number information by address. + * + * The returned line number is what the debug info interpreter considers the + * one most applicable to the specified address. This usually means a line + * number with an address equal or lower than the requested. + * + * @returns IPRT status code. + * @retval VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers. + * @retval VERR_DBG_LINE_NOT_FOUND if no suitable line number was found. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and + * it's not inside any of the segments defined by the module. + * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid. + * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the + * end of the segment. + * + * @param hDbgMod The module handle. + * @param iSeg The segment number. + * @param off The offset into the segment. + * @param poffDisp Where to store the distance between the + * specified address and the returned symbol. + * Optional. + * @param pLineInfo Where to store the line number information. + */ +RTDECL(int) RTDbgModLineByAddr(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTINTPTR poffDisp, PRTDBGLINE pLineInfo); + +/** + * Queries line number information by address. + * + * The returned line number is what the debug info interpreter considers the + * one most applicable to the specified address. This usually means a line + * number with an address equal or lower than the requested. + * + * @returns IPRT status code. + * @retval VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers. + * @retval VERR_DBG_LINE_NOT_FOUND if no suitable line number was found. + * @retval VERR_INVALID_HANDLE if hDbgMod is invalid. + * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and + * it's not inside any of the segments defined by the module. + * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid. + * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the + * end of the segment. + * @retval VERR_NO_MEMORY if RTDbgLineAlloc fails. + * + * @param hDbgMod The module handle. + * @param iSeg The segment number. + * @param off The offset into the segment. + * @param poffDisp Where to store the distance between the + * specified address and the returned symbol. + * Optional. + * @param ppLineInfo Where to store the pointer to the returned line + * number information. Always set. Free with + * RTDbgLineFree. + */ +RTDECL(int) RTDbgModLineByAddrA(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTINTPTR poffDisp, PRTDBGLINE *ppLineInfo); + +/** + * Try use unwind information to unwind one frame. + * + * @returns IPRT status code. Last informational status from stack reader callback. + * @retval VERR_DBG_NO_UNWIND_INFO if the module contains no unwind information. + * @retval VERR_DBG_UNWIND_INFO_NOT_FOUND if no unwind information was found + * for the location given by iSeg:off. + * + * @param hDbgMod The module handle. + * @param iSeg The segment number of the program counter. + * @param off The offset into @a iSeg. Together with @a iSeg + * this corresponds to the RTDBGUNWINDSTATE::uPc + * value pointed to by @a pState. + * @param pState The unwind state to work. + * + * @sa RTLdrUnwindFrame + */ +RTDECL(int) RTDbgModUnwindFrame(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTDBGUNWINDSTATE pState); + +/** @} */ +# endif /* IN_RING3 */ + + + +/** @name Kernel Debug Info API + * + * This is a specialized API for obtaining symbols and structure information + * about the running kernel. It is relatively OS specific. Its purpose and + * operation is doesn't map all that well onto RTDbgMod, so a few dedicated + * functions was created for it. + * + * @{ */ + +/** Handle to the kernel debug info. */ +typedef struct RTDBGKRNLINFOINT *RTDBGKRNLINFO; +/** Pointer to a kernel debug info handle. */ +typedef RTDBGKRNLINFO *PRTDBGKRNLINFO; +/** Nil kernel debug info handle. */ +#define NIL_RTDBGKRNLINFO ((RTDBGKRNLINFO)0) + +/** + * Opens the kernel debug info. + * + * @returns IPRT status code. Can fail for any number of reasons. + * + * @param phKrnlInfo Where to return the kernel debug info handle on + * success. + * @param fFlags Flags reserved for future use. Must be zero. + */ +RTR0DECL(int) RTR0DbgKrnlInfoOpen(PRTDBGKRNLINFO phKrnlInfo, uint32_t fFlags); + +/** + * Retains a reference to the kernel debug info handle. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * @param hKrnlInfo The kernel info handle. + */ +RTR0DECL(uint32_t) RTR0DbgKrnlInfoRetain(RTDBGKRNLINFO hKrnlInfo); + + +/** + * Releases a reference to the kernel debug info handle, destroying it when the + * counter reaches zero. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * @param hKrnlInfo The kernel info handle. NIL_RTDBGKRNLINFO is + * quietly ignored. + */ +RTR0DECL(uint32_t) RTR0DbgKrnlInfoRelease(RTDBGKRNLINFO hKrnlInfo); + +/** + * Queries the offset (in bytes) of a member of a kernel structure. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and offset at @a poffMember. + * @retval VERR_NOT_FOUND if the structure or the member was not found. + * @retval VERR_INVALID_HANDLE if hKrnlInfo is bad. + * @retval VERR_INVALID_POINTER if any of the pointers are bad. + * + * @param hKrnlInfo The kernel info handle. + * @param pszModule The name of the module to search, pass NULL to + * search the default kernel module(s). + * @param pszStructure The structure name. + * @param pszMember The member name. + * @param poffMember Where to return the offset. + */ +RTR0DECL(int) RTR0DbgKrnlInfoQueryMember(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, const char *pszStructure, + const char *pszMember, size_t *poffMember); + + +/** + * Queries the value (usually the address) of a kernel symbol. + * + * This may go looking for the symbol in other modules, in which case it will + * always check the kernel symbol table first. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and value at @a ppvSymbol. + * @retval VERR_SYMBOL_NOT_FOUND + * @retval VERR_INVALID_HANDLE if hKrnlInfo is bad. + * @retval VERR_INVALID_POINTER if any of the pointers are bad. + * + * @param hKrnlInfo The kernel info handle. + * @param pszModule The name of the module to search, pass NULL to + * search the default kernel module(s). + * @param pszSymbol The C name of the symbol. + * On Windows NT there are the following special symbols: + * - __ImageBase: The base address of the module. + * - __ImageSize: The size of the module. + * - __ImageNtHdrs: Address of the NT headers. + * @param ppvSymbol Where to return the symbol value, passing NULL is + * OK. This may be modified even on failure, in + * particular, it will be set to NULL when + * VERR_SYMBOL_NOT_FOUND is returned. + * + * @sa RTR0DbgKrnlInfoGetSymbol, RTLdrGetSymbol + */ +RTR0DECL(int) RTR0DbgKrnlInfoQuerySymbol(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, + const char *pszSymbol, void **ppvSymbol); + +/** + * Wrapper around RTR0DbgKrnlInfoQuerySymbol that returns the symbol. + * + * @return Symbol address if found, NULL if not found or some invalid parameter + * or something. + * @param hKrnlInfo The kernel info handle. + * @param pszModule The name of the module to search, pass NULL to + * search the default kernel module(s). + * @param pszSymbol The C name of the symbol. + * On Windows NT there are the following special symbols: + * - __ImageBase: The base address of the module. + * - __ImageSize: The size of the module. + * - __ImageNtHdrs: Address of the NT headers. + * @sa RTR0DbgKrnlInfoQuerySymbol, RTLdrGetSymbol + */ +RTR0DECL(void *) RTR0DbgKrnlInfoGetSymbol(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, const char *pszSymbol); + +/** + * Queries the size (in bytes) of a kernel data type. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and size at @a pcbType. + * @retval VERR_NOT_FOUND if the type was not found. + * @retval VERR_INVALID_HANDLE if hKrnlInfo is bad. + * @retval VERR_INVALID_POINTER if any of the pointers are bad. + * @retval VERR_WRONG_TYPE if the type was not a valid data type (e.g. a + * function) + * + * @param hKrnlInfo The kernel info handle. + * @param pszModule The name of the module to search, pass NULL to + * search the default kernel module(s). + * @param pszType The type name. + * @param pcbType Where to return the size of the type. + */ +RTR0DECL(int) RTR0DbgKrnlInfoQuerySize(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, + const char *pszType, size_t *pcbType); +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_dbg_h */ + diff --git a/include/iprt/dir.h b/include/iprt/dir.h new file mode 100644 index 00000000..ff47c974 --- /dev/null +++ b/include/iprt/dir.h @@ -0,0 +1,894 @@ +/** @file + * IPRT - Directory Manipulation. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_dir_h +#define IPRT_INCLUDED_dir_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/fs.h> +#include <iprt/symlink.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_dir RTDir - Directory Manipulation + * @ingroup grp_rt + * @{ + */ + +/** + * Check for the existence of a directory. + * + * All symbolic links will be attemped resolved. If that is undesirable, please + * use RTPathQueryInfo instead. + * + * @returns true if exist and is a directory. + * @returns false if not exists or isn't a directory. + * @param pszPath Path to the directory. + */ +RTDECL(bool) RTDirExists(const char *pszPath); + +/** @name RTDirCreate flags. + * @{ */ +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTDIRCREATE_FLAGS_NO_SYMLINKS RT_BIT(0) +/** Set the not-content-indexed flag (default). Windows only atm. */ +#define RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_DONT_SET RT_BIT(1) +/** Do not set the not-content-indexed flag. Windows only atm. */ +#define RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_SET UINT32_C(0) +/** Ignore errors setting the not-content-indexed flag. Windows only atm. */ +#define RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL RT_BIT(2) +/** Ignore umask when applying the mode. */ +#define RTDIRCREATE_FLAGS_IGNORE_UMASK RT_BIT(3) +/** Valid mask. */ +#define RTDIRCREATE_FLAGS_VALID_MASK UINT32_C(0x0000000f) +/** @} */ + +/** + * Creates a directory. + * + * @returns iprt status code. + * @param pszPath Path to the directory to create. + * @param fMode The mode of the new directory. + * @param fCreate Create flags, RTDIRCREATE_FLAGS_*. + */ +RTDECL(int) RTDirCreate(const char *pszPath, RTFMODE fMode, uint32_t fCreate); + +/** + * Creates a directory including all non-existing parent directories. + * + * @returns iprt status code. + * @param pszPath Path to the directory to create. + * @param fMode The mode of the new directories. + */ +RTDECL(int) RTDirCreateFullPath(const char *pszPath, RTFMODE fMode); + +/** + * Creates a directory including all non-existing parent directories. + * + * @returns iprt status code. + * @param pszPath Path to the directory to create. + * @param fMode The mode of the new directories. + * @param fFlags Create flags, RTDIRCREATE_FLAGS_*. + */ +RTDECL(int) RTDirCreateFullPathEx(const char *pszPath, RTFMODE fMode, uint32_t fFlags); + +/** + * Creates a new directory with a unique name using the given template. + * + * One or more trailing X'es in the template will be replaced by random alpha + * numeric characters until a RTDirCreate succeeds or we run out of patience. + * For instance: + * "/tmp/myprog-XXXXXX" + * + * As an alternative to trailing X'es, it + * is possible to put 3 or more X'es somewhere inside the directory name. In + * the following string only the last bunch of X'es will be modified: + * "/tmp/myprog-XXX-XXX.tmp" + * + * @returns iprt status code. + * @param pszTemplate The directory name template on input. The actual + * directory name on success. Empty string on failure. + * @param fMode The mode to create the directory with. Use 0700 + * unless you have reason not to. + */ +RTDECL(int) RTDirCreateTemp(char *pszTemplate, RTFMODE fMode); + +/** + * Secure version of @a RTDirCreateTemp with a fixed mode of 0700. + * + * This function behaves in the same way as @a RTDirCreateTemp with two + * additional points. Firstly the mode is fixed to 0700. Secondly it will + * fail if it is not possible to perform the operation securely. Possible + * reasons include that the directory could be removed by another unprivileged + * user before it is used (e.g. if is created in a non-sticky /tmp directory) + * or that the path contains symbolic links which another unprivileged user + * could manipulate; however the exact criteria will be specified on a + * platform-by-platform basis as platform support is added. + * @see RTPathIsSecure for the current list of criteria. + * @returns iprt status code. + * @returns VERR_NOT_SUPPORTED if the interface can not be supported on the + * current platform at this time. + * @returns VERR_INSECURE if the directory could not be created securely. + * @param pszTemplate The directory name template on input. The + * actual directory name on success. Empty string + * on failure. + */ +RTDECL(int) RTDirCreateTempSecure(char *pszTemplate); + +/** + * Creates a new directory with a unique name by appending a number. + * + * This API differs from RTDirCreateTemp & RTDirCreateTempSecure in that it + * first tries to create the directory without any random bits, thus the best + * case result will be prettier. It also differs in that it does not take a + * template, but is instead given a template description, and will only use + * digits for the filling. + * + * For sake of convenience and debugging , the current implementation + * starts at 0 and will increment sequentally for a while before switching to + * random numbers. + * + * On success @a pszPath contains the path created. + * + * @returns iprt status code. + * @param pszPath The path to the directory. On input the base template + * name. On successful return, the unique directory we + * created. + * @param cbSize The size of the pszPath buffer. Needs enough space for + * holding the digits and the optional separator. + * @param fMode The mode of the new directory. + * @param cchDigits How many digits should the number have (zero padded). + * @param chSep The separator used between the path and the number. Can + * be zero. (optional) + */ +RTDECL(int) RTDirCreateUniqueNumbered(char *pszPath, size_t cbSize, RTFMODE fMode, size_t cchDigits, char chSep); + +/** + * Removes a directory if empty. + * + * @returns iprt status code. + * @param pszPath Path to the directory to remove. + */ +RTDECL(int) RTDirRemove(const char *pszPath); + +/** + * Removes a directory tree recursively. + * + * @returns iprt status code. + * @param pszPath Path to the directory to remove recursively. + * @param fFlags Flags, see RTDIRRMREC_F_XXX. + * + * @remarks This will not work on a root directory. + */ +RTDECL(int) RTDirRemoveRecursive(const char *pszPath, uint32_t fFlags); + +/** @name RTDirRemoveRecursive flags. + * @{ */ +/** Delete the content of the directory and the directory itself. */ +#define RTDIRRMREC_F_CONTENT_AND_DIR UINT32_C(0) +/** Only delete the content of the directory, omit the directory it self. */ +#define RTDIRRMREC_F_CONTENT_ONLY RT_BIT_32(0) +/** Long path hack: Don't apply RTPathAbs to the path. */ +#define RTDIRRMREC_F_NO_ABS_PATH RT_BIT_32(1) +/** Mask of valid flags. */ +#define RTDIRRMREC_F_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** + * Flushes the specified directory. + * + * This API is not implemented on all systems. On some systems it may be + * unnecessary if you've already flushed the file. If you really care for your + * data and is entering dangerous territories, it doesn't hurt calling it after + * flushing and closing the file. + * + * @returns IPRT status code. + * @retval VERR_NOT_IMPLEMENTED must be expected. + * @retval VERR_NOT_SUPPORTED must be expected. + * @param pszPath Path to the directory. + */ +RTDECL(int) RTDirFlush(const char *pszPath); + +/** + * Flushes the parent directory of the specified file. + * + * This is just a wrapper around RTDirFlush. + * + * @returns IPRT status code, see RTDirFlush for details. + * @param pszChild Path to the file which parent should be flushed. + */ +RTDECL(int) RTDirFlushParent(const char *pszChild); + + + +/** + * Filter option for RTDirOpenFiltered(). + */ +typedef enum RTDIRFILTER +{ + /** The usual invalid 0 entry. */ + RTDIRFILTER_INVALID = 0, + /** No filter should be applied (and none was specified). */ + RTDIRFILTER_NONE, + /** The Windows NT filter. + * The following wildcard chars: *, ?, <, > and " + * The matching is done on the uppercased strings. */ + RTDIRFILTER_WINNT, + /** The UNIX filter. + * The following wildcard chars: *, ?, [..] + * The matching is done on exact case. */ + RTDIRFILTER_UNIX, + /** The UNIX filter, uppercased matching. + * Same as RTDIRFILTER_UNIX except that the strings are uppercased before comparing. */ + RTDIRFILTER_UNIX_UPCASED, + + /** The usual full 32-bit value. */ + RTDIRFILTER_32BIT_HACK = 0x7fffffff +} RTDIRFILTER; + + +/** + * Directory entry type. + * + * This is the RTFS_TYPE_MASK stuff shifted down 12 bits and + * identical to the BSD/LINUX ABI. See RTFS_TYPE_DIRENTRYTYPE_SHIFT. + */ +typedef enum RTDIRENTRYTYPE +{ + /** Unknown type (DT_UNKNOWN). */ + RTDIRENTRYTYPE_UNKNOWN = 0, + /** Named pipe (fifo) (DT_FIFO). */ + RTDIRENTRYTYPE_FIFO = 001, + /** Character device (DT_CHR). */ + RTDIRENTRYTYPE_DEV_CHAR = 002, + /** Directory (DT_DIR). */ + RTDIRENTRYTYPE_DIRECTORY = 004, + /** Block device (DT_BLK). */ + RTDIRENTRYTYPE_DEV_BLOCK = 006, + /** Regular file (DT_REG). */ + RTDIRENTRYTYPE_FILE = 010, + /** Symbolic link (DT_LNK). */ + RTDIRENTRYTYPE_SYMLINK = 012, + /** Socket (DT_SOCK). */ + RTDIRENTRYTYPE_SOCKET = 014, + /** Whiteout (DT_WHT). */ + RTDIRENTRYTYPE_WHITEOUT = 016 +} RTDIRENTRYTYPE; + + +/** + * Directory entry. + * + * This is inspired by the POSIX interfaces. + */ +#pragma pack(1) +typedef struct RTDIRENTRY +{ + /** The unique identifier (within the file system) of this file system object (d_ino). + * + * Together with INodeIdDevice, this field can be used as a OS wide unique id + * when both their values are not 0. This field is 0 if the information is not + * available. */ + RTINODE INodeId; + /** The entry type. (d_type) + * + * @warning RTDIRENTRYTYPE_UNKNOWN is a common return value here since not all + * file systems (or Unixes) stores the type of a directory entry and + * instead expects the user to use stat() to get it. So, when you see + * this you should use RTDirQueryUnknownType or RTDirQueryUnknownTypeEx + * to get the type, or if if you're lazy, use RTDirReadEx. + */ + RTDIRENTRYTYPE enmType; + /** The length of the filename, excluding the terminating nul character. */ + uint16_t cbName; + /** The filename. (no path) + * Using the pcbDirEntry parameter of RTDirRead makes this field variable in size. */ + char szName[260]; +} RTDIRENTRY; +#pragma pack() +/** Pointer to a directory entry. */ +typedef RTDIRENTRY *PRTDIRENTRY; +/** Pointer to a const directory entry. */ +typedef RTDIRENTRY const *PCRTDIRENTRY; + + +/** + * Directory entry with extended information. + * + * This is inspired by the PC interfaces. + */ +#pragma pack(1) +typedef struct RTDIRENTRYEX +{ + /** Full information about the object. */ + RTFSOBJINFO Info; + /** The length of the short field (number of RTUTF16 entries (not chars)). + * It is 16-bit for reasons of alignment. */ + uint16_t cwcShortName; + /** The short name for 8.3 compatibility. + * Empty string if not available. + * Since the length is a bit tricky for a UTF-8 encoded name, and since this + * is practically speaking only a windows thing, it is encoded as UCS-2. */ + RTUTF16 wszShortName[14]; + /** The length of the filename. */ + uint16_t cbName; + /** The filename. (no path) + * Using the pcbDirEntry parameter of RTDirReadEx makes this field variable in size. */ + char szName[260]; +} RTDIRENTRYEX; +#pragma pack() +/** Pointer to a directory entry. */ +typedef RTDIRENTRYEX *PRTDIRENTRYEX; +/** Pointer to a const directory entry. */ +typedef RTDIRENTRYEX const *PCRTDIRENTRYEX; + + +/** + * Opens a directory. + * + * @returns iprt status code. + * @param phDir Where to store the open directory handle. + * @param pszPath Path to the directory to open. + */ +RTDECL(int) RTDirOpen(RTDIR *phDir, const char *pszPath); + +/** @name RTDIR_F_XXX - RTDirOpenFiltered flags. + * @{ */ +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTDIR_F_NO_SYMLINKS RT_BIT_32(0) +/** Deny relative opening of anything above this directory. */ +#define RTDIR_F_DENY_ASCENT RT_BIT_32(1) +/** Don't follow symbolic links in the final component. */ +#define RTDIR_F_NO_FOLLOW RT_BIT_32(2) +/** Long path hack: Don't apply RTPathAbs to the path. */ +#define RTDIR_F_NO_ABS_PATH RT_BIT_32(3) +/** Valid flag mask. */ +#define RTDIR_F_VALID_MASK UINT32_C(0x0000000f) +/** @} */ + +/** + * Opens a directory with flags and optional filtering. + * + * @returns IPRT status code. + * @retval VERR_IS_A_SYMLINK if RTDIR_F_NO_FOLLOW is set, @a enmFilter is + * RTDIRFILTER_NONE and @a pszPath points to a symbolic link and does + * not end with a slash. Note that on Windows this does not apply to + * file symlinks, only directory symlinks, for the file variant + * VERR_NOT_A_DIRECTORY will be returned. + * + * @param phDir Where to store the open directory handle. + * @param pszPath Path to the directory to search, this must include wildcards. + * @param enmFilter The kind of filter to apply. Setting this to RTDIRFILTER_NONE makes + * this function behave like RTDirOpen. + * @param fFlags Open flags, RTDIR_F_XXX. + * + */ +RTDECL(int) RTDirOpenFiltered(RTDIR *phDir, const char *pszPath, RTDIRFILTER enmFilter, uint32_t fFlags); + +/** + * Closes a directory. + * + * @returns iprt status code. + * @param hDir Handle to open directory returned by RTDirOpen() or + * RTDirOpenFiltered(). + */ +RTDECL(int) RTDirClose(RTDIR hDir); + +/** + * Checks if the supplied directory handle is valid. + * + * @returns true if valid. + * @returns false if invalid. + * @param hDir The directory handle. + */ +RTDECL(bool) RTDirIsValid(RTDIR hDir); + +/** + * Reads the next entry in the directory. + * + * @returns VINF_SUCCESS and data in pDirEntry on success. + * @returns VERR_NO_MORE_FILES when the end of the directory has been reached. + * @returns VERR_BUFFER_OVERFLOW if the buffer is too small to contain the filename. If + * pcbDirEntry is specified it will be updated with the required buffer size. + * @returns suitable iprt status code on other errors. + * + * @param hDir Handle to the open directory. + * @param pDirEntry Where to store the information about the next + * directory entry on success. + * @param pcbDirEntry Optional parameter used for variable buffer size. + * + * On input the variable pointed to contains the size of the pDirEntry + * structure. This must be at least OFFSET(RTDIRENTRY, szName[2]) bytes. + * + * On successful output the field is updated to + * OFFSET(RTDIRENTRY, szName[pDirEntry->cbName + 1]). + * + * When the data doesn't fit in the buffer and VERR_BUFFER_OVERFLOW is + * returned, this field contains the required buffer size. + * + * The value is unchanged in all other cases. + */ +RTDECL(int) RTDirRead(RTDIR hDir, PRTDIRENTRY pDirEntry, size_t *pcbDirEntry); + +/** + * Reads the next entry in the directory returning extended information. + * + * @returns VINF_SUCCESS and data in pDirEntry on success. + * @returns VERR_NO_MORE_FILES when the end of the directory has been reached. + * @returns VERR_BUFFER_OVERFLOW if the buffer is too small to contain the filename. If + * pcbDirEntry is specified it will be updated with the required buffer size. + * @returns suitable iprt status code on other errors. + * + * @param hDir Handle to the open directory. + * @param pDirEntry Where to store the information about the next + * directory entry on success. + * @param pcbDirEntry Optional parameter used for variable buffer size. + * + * On input the variable pointed to contains the size of the pDirEntry + * structure. This must be at least OFFSET(RTDIRENTRYEX, szName[2]) bytes. + * + * On successful output the field is updated to + * OFFSET(RTDIRENTRYEX, szName[pDirEntry->cbName + 1]). + * + * When the data doesn't fit in the buffer and VERR_BUFFER_OVERFLOW is + * returned, this field contains the required buffer size. + * + * The value is unchanged in all other cases. + * @param enmAdditionalAttribs + * Which set of additional attributes to request. + * Use RTFSOBJATTRADD_NOTHING if this doesn't matter. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + */ +RTDECL(int) RTDirReadEx(RTDIR hDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags); + +/** + * Wrapper around RTDirReadEx that does the directory entry buffer handling. + * + * Call RTDirReadExAFree to free the buffers allocated by this function. + * + * @returns IPRT status code, see RTDirReadEx() for details. + * + * @param hDir Handle to the open directory. + * @param ppDirEntry Pointer to the directory entry pointer. Initialize this + * to NULL before the first call. + * @param pcbDirEntry Where the API caches the allocation size. Set this to + * zero before the first call. + * @param enmAddAttr See RTDirReadEx. + * @param fFlags See RTDirReadEx. + */ +RTDECL(int) RTDirReadExA(RTDIR hDir, PRTDIRENTRYEX *ppDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr, uint32_t fFlags); + +/** + * Frees the buffer allocated by RTDirReadExA. + * + * @param ppDirEntry Pointer to the directory entry pointer. + * @param pcbDirEntry Where the API caches the allocation size. + */ +RTDECL(void) RTDirReadExAFree(PRTDIRENTRYEX *ppDirEntry, size_t *pcbDirEntry); + +/** + * Resolves RTDIRENTRYTYPE_UNKNOWN values returned by RTDirRead. + * + * @returns IPRT status code (see RTPathQueryInfo). + * @param pszComposedName The path to the directory entry. The caller must + * compose this, it's NOT sufficient to pass + * RTDIRENTRY::szName! + * @param fFollowSymlinks Whether to follow symbolic links or not. + * @param penmType Pointer to the RTDIRENTRY::enmType member. If this + * is not RTDIRENTRYTYPE_UNKNOWN and, if + * @a fFollowSymlinks is false, not + * RTDIRENTRYTYPE_SYMLINK, the function will return + * immediately without doing anything. Otherwise it + * will use RTPathQueryInfo to try figure out the + * correct value. On failure, this will be unchanged. + */ +RTDECL(int) RTDirQueryUnknownType(const char *pszComposedName, bool fFollowSymlinks, RTDIRENTRYTYPE *penmType); + +/** + * Resolves RTDIRENTRYTYPE_UNKNOWN values returned by RTDirRead, extended + * version. + * + * @returns IPRT status code (see RTPathQueryInfo). + * @param pszComposedName The path to the directory entry. The caller must + * compose this, it's NOT sufficient to pass + * RTDIRENTRY::szName! + * @param fFollowSymlinks Whether to follow symbolic links or not. + * @param penmType Pointer to the RTDIRENTRY::enmType member or + * similar. Will NOT be checked on input. + * @param pObjInfo The object info buffer to use with RTPathQueryInfo. + */ +RTDECL(int) RTDirQueryUnknownTypeEx(const char *pszComposedName, bool fFollowSymlinks, RTDIRENTRYTYPE *penmType, PRTFSOBJINFO pObjInfo); + +/** + * Checks if the directory entry returned by RTDirRead is '.', '..' or similar. + * + * @returns true / false. + * @param pDirEntry The directory entry to check. + */ +RTDECL(bool) RTDirEntryIsStdDotLink(PRTDIRENTRY pDirEntry); + +/** + * Checks if the directory entry returned by RTDirReadEx is '.', '..' or + * similar. + * + * @returns true / false. + * @param pDirEntryEx The extended directory entry to check. + */ +RTDECL(bool) RTDirEntryExIsStdDotLink(PCRTDIRENTRYEX pDirEntryEx); + +/** + * Rewind and restart the directory reading. + * + * @returns IRPT status code. + * @param hDir The directory handle to rewind. + */ +RTDECL(int) RTDirRewind(RTDIR hDir); + +/** + * Renames a file. + * + * Identical to RTPathRename except that it will ensure that the source is a directory. + * + * @returns IPRT status code. + * @returns VERR_ALREADY_EXISTS if the destination file exists. + * + * @param pszSrc The path to the source file. + * @param pszDst The path to the destination file. + * This file will be created. + * @param fRename See RTPathRename. + */ +RTDECL(int) RTDirRename(const char *pszSrc, const char *pszDst, unsigned fRename); + + +/** + * Query information about an open directory. + * + * @returns iprt status code. + * + * @param hDir Handle to the open directory. + * @param pObjInfo Object information structure to be filled on successful return. + * @param enmAdditionalAttribs Which set of additional attributes to request. + * Use RTFSOBJATTRADD_NOTHING if this doesn't matter. + */ +RTR3DECL(int) RTDirQueryInfo(RTDIR hDir, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs); + + +/** + * Changes one or more of the timestamps associated of file system object. + * + * @returns iprt status code. + * @returns VERR_NOT_SUPPORTED is returned if the operation isn't supported by the OS. + * + * @param hDir Handle to the open directory. + * @param pAccessTime Pointer to the new access time. NULL if not to be changed. + * @param pModificationTime Pointer to the new modifcation time. NULL if not to be changed. + * @param pChangeTime Pointer to the new change time. NULL if not to be changed. + * @param pBirthTime Pointer to the new time of birth. NULL if not to be changed. + * + * @remark The file system might not implement all these time attributes, + * the API will ignore the ones which aren't supported. + * + * @remark The file system might not implement the time resolution + * employed by this interface, the time will be chopped to fit. + * + * @remark The file system may update the change time even if it's + * not specified. + * + * @remark POSIX can only set Access & Modification and will always set both. + */ +RTR3DECL(int) RTDirSetTimes(RTDIR hDir, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, + PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime); + + +/** + * Changes the mode flags of an open directory. + * + * The API requires at least one of the mode flag sets (Unix/Dos) to + * be set. The type is ignored. + * + * @returns iprt status code. + * @param hDir Handle to the open directory. + * @param fMode The new file mode, see @ref grp_rt_fs for details. + */ +RTDECL(int) RTDirSetMode(RTDIR hDir, RTFMODE fMode); + + +/** @defgroup grp_rt_dir_rel Directory relative APIs + * + * This group of APIs allows working with paths that are relative to an open + * directory, therebye eliminating some classic path related race conditions on + * systems with native support for these kinds of operations. + * + * On NT (Windows) there is native support for addressing files, directories and + * stuff _below_ the open directory. It is not possible to go upwards + * (hDir:../../grandparent), at least not with NTFS, forcing us to use the + * directory path as a fallback and opening us to potential races. + * + * On most unix-like systems here is now native support for all of this. + * + * @{ */ + +/** + * Open a file relative to @a hDir. + * + * @returns IPRT status code. + * @param hDir The directory to open relative to. + * @param pszRelFilename The relative path to the file. + * @param fOpen Open flags, i.e a combination of the RTFILE_O_XXX + * defines. The ACCESS, ACTION and DENY flags are + * mandatory! + * @param phFile Where to store the handle to the opened file. + * + * @sa RTFileOpen + */ +RTDECL(int) RTDirRelFileOpen(RTDIR hDir, const char *pszRelFilename, uint64_t fOpen, PRTFILE phFile); + + + +/** + * Opens a directory relative to @a hDir. + * + * @returns IPRT status code. + * @param hDir The directory to open relative to. + * @param pszDir The relative path to the directory to open. + * @param phDir Where to store the directory handle. + * + * @sa RTDirOpen + */ +RTDECL(int) RTDirRelDirOpen(RTDIR hDir, const char *pszDir, RTDIR *phDir); + +/** + * Opens a directory relative to @a hDir, with flags and optional filtering. + * + * @returns IPRT status code. + * @retval VERR_IS_A_SYMLINK if RTDIR_F_NO_FOLLOW is set, @a enmFilter is + * RTDIRFILTER_NONE and @a pszPath points to a symbolic link and does + * not end with a slash. Note that on Windows this does not apply to + * file symlinks, only directory symlinks, for the file variant + * VERR_NOT_A_DIRECTORY will be returned. + * + * @param hDir The directory to open relative to. + * @param pszDirAndFilter The relative path to the directory to search, this + * must include wildcards. + * @param enmFilter The kind of filter to apply. Setting this to + * RTDIRFILTER_NONE makes this function behave like + * RTDirOpen. + * @param fFlags Open flags, RTDIR_F_XXX. + * @param phDir Where to store the directory handle. + * + * @sa RTDirOpenFiltered + */ +RTDECL(int) RTDirRelDirOpenFiltered(RTDIR hDir, const char *pszDirAndFilter, RTDIRFILTER enmFilter, + uint32_t fFlags, RTDIR *phDir); + +/** + * Creates a directory relative to @a hDir. + * + * @returns IPRT status code. + * @param hDir The directory @a pszRelPath is relative to. + * @param pszRelPath The relative path to the directory to create. + * @param fMode The mode of the new directory. + * @param fCreate Create flags, RTDIRCREATE_FLAGS_XXX. + * @param phSubDir Where to return the handle of the created directory. + * Optional. + * + * @sa RTDirCreate + */ +RTDECL(int) RTDirRelDirCreate(RTDIR hDir, const char *pszRelPath, RTFMODE fMode, uint32_t fCreate, RTDIR *phSubDir); + +/** + * Removes a directory relative to @a hDir if empty. + * + * @returns IPRT status code. + * @param hDir The directory @a pszRelPath is relative to. + * @param pszRelPath The relative path to the directory to remove. + * + * @sa RTDirRemove + */ +RTDECL(int) RTDirRelDirRemove(RTDIR hDir, const char *pszRelPath); + + +/** + * Query information about a file system object relative to @a hDir. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the object exists, information returned. + * @retval VERR_PATH_NOT_FOUND if any but the last component in the specified + * path was not found or was not a directory. + * @retval VERR_FILE_NOT_FOUND if the object does not exist (but path to the + * parent directory exists). + * + * @param hDir The directory @a pszRelPath is relative to. + * @param pszRelPath The relative path to the file system object. + * @param pObjInfo Object information structure to be filled on successful + * return. + * @param enmAddAttr Which set of additional attributes to request. + * Use RTFSOBJATTRADD_NOTHING if this doesn't matter. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + * + * @sa RTPathQueryInfoEx + */ +RTDECL(int) RTDirRelPathQueryInfo(RTDIR hDir, const char *pszRelPath, PRTFSOBJINFO pObjInfo, + RTFSOBJATTRADD enmAddAttr, uint32_t fFlags); + +/** + * Changes the mode flags of a file system object relative to @a hDir. + * + * The API requires at least one of the mode flag sets (Unix/Dos) to + * be set. The type is ignored. + * + * @returns IPRT status code. + * @param hDir The directory @a pszRelPath is relative to. + * @param pszRelPath The relative path to the file system object. + * @param fMode The new file mode, see @ref grp_rt_fs for details. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + * + * @sa RTPathSetMode + */ +RTDECL(int) RTDirRelPathSetMode(RTDIR hDir, const char *pszRelPath, RTFMODE fMode, uint32_t fFlags); + +/** + * Changes one or more of the timestamps associated of file system object + * relative to @a hDir. + * + * @returns IPRT status code. + * @param hDir The directory @a pszRelPath is relative to. + * @param pszRelPath The relative path to the file system object. + * @param pAccessTime Pointer to the new access time. + * @param pModificationTime Pointer to the new modification time. + * @param pChangeTime Pointer to the new change time. NULL if not to be changed. + * @param pBirthTime Pointer to the new time of birth. NULL if not to be changed. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + * + * @remark The file system might not implement all these time attributes, + * the API will ignore the ones which aren't supported. + * + * @remark The file system might not implement the time resolution + * employed by this interface, the time will be chopped to fit. + * + * @remark The file system may update the change time even if it's + * not specified. + * + * @remark POSIX can only set Access & Modification and will always set both. + * + * @sa RTPathSetTimesEx + */ +RTDECL(int) RTDirRelPathSetTimes(RTDIR hDir, const char *pszRelPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, + PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags); + +/** + * Changes the owner and/or group of a file system object relative to @a hDir. + * + * @returns IPRT status code. + * @param hDir The directory @a pszRelPath is relative to. + * @param pszRelPath The relative path to the file system object. + * @param uid The new file owner user id. Pass NIL_RTUID to leave + * this unchanged. + * @param gid The new group id. Pass NIL_RTGID to leave this + * unchanged. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + * + * @sa RTPathSetOwnerEx + */ +RTDECL(int) RTDirRelPathSetOwner(RTDIR hDir, const char *pszRelPath, uint32_t uid, uint32_t gid, uint32_t fFlags); + +/** + * Renames a directory relative path within a filesystem. + * + * This will rename symbolic links. If RTPATHRENAME_FLAGS_REPLACE is used and + * pszDst is a symbolic link, it will be replaced and not its target. + * + * @returns IPRT status code. + * @param hDirSrc The directory the source path is relative to. + * @param pszSrc The source path, relative to @a hDirSrc. + * @param hDirDst The directory the destination path is relative to. + * @param pszDst The destination path, relative to @a hDirDst. + * @param fRename Rename flags, RTPATHRENAME_FLAGS_XXX. + * + * @sa RTPathRename + */ +RTDECL(int) RTDirRelPathRename(RTDIR hDirSrc, const char *pszSrc, RTDIR hDirDst, const char *pszDst, unsigned fRename); + +/** + * Removes the last component of the directory relative path. + * + * @returns IPRT status code. + * @param hDir The directory @a pszRelPath is relative to. + * @param pszRelPath The relative path to the file system object. + * @param fUnlink Unlink flags, RTPATHUNLINK_FLAGS_XXX. + * + * @sa RTPathUnlink + */ +RTDECL(int) RTDirRelPathUnlink(RTDIR hDir, const char *pszRelPath, uint32_t fUnlink); + + + +/** + * Creates a symbolic link (@a pszSymlink) relative to @a hDir targeting @a + * pszTarget. + * + * @returns IPRT status code. + * @param hDir The directory @a pszSymlink is relative to. + * @param pszSymlink The relative path of the symbolic link. + * @param pszTarget The path to the symbolic link target. This is + * relative to @a pszSymlink or an absolute path. + * @param enmType The symbolic link type. For Windows compatability + * it is very important to set this correctly. When + * RTSYMLINKTYPE_UNKNOWN is used, the API will try + * make a guess and may attempt query information + * about @a pszTarget in the process. + * @param fCreate Create flags, RTSYMLINKCREATE_FLAGS_XXX. + * + * @sa RTSymlinkCreate + */ +RTDECL(int) RTDirRelSymlinkCreate(RTDIR hDir, const char *pszSymlink, const char *pszTarget, + RTSYMLINKTYPE enmType, uint32_t fCreate); + +/** + * Read the symlink target relative to @a hDir. + * + * @returns IPRT status code. + * @retval VERR_NOT_SYMLINK if @a pszSymlink does not specify a symbolic link. + * @retval VERR_BUFFER_OVERFLOW if the link is larger than @a cbTarget. The + * buffer will contain what all we managed to read, fully terminated + * if @a cbTarget > 0. + * + * @param hDir The directory @a pszSymlink is relative to. + * @param pszSymlink The relative path to the symbolic link that should + * be read. + * @param pszTarget The target buffer. + * @param cbTarget The size of the target buffer. + * @param fRead Read flags, RTSYMLINKREAD_FLAGS_XXX. + * + * @sa RTSymlinkRead + */ +RTDECL(int) RTDirRelSymlinkRead(RTDIR hDir, const char *pszSymlink, char *pszTarget, size_t cbTarget, uint32_t fRead); + +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_dir_h */ + diff --git a/include/iprt/dvm.h b/include/iprt/dvm.h new file mode 100644 index 00000000..25f12526 --- /dev/null +++ b/include/iprt/dvm.h @@ -0,0 +1,639 @@ +/** @file + * IPRT Disk Volume Management API (DVM). + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_dvm_h +#define IPRT_INCLUDED_dvm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_dvm IPRT Disk Volume Management + * @{ + */ + +/** + * Volume type. + * Comparable to the FS type in MBR partition maps + * or the partition type GUIDs in GPT tables. + */ +typedef enum RTDVMVOLTYPE +{ + /** Invalid. */ + RTDVMVOLTYPE_INVALID = 0, + /** Unknown. */ + RTDVMVOLTYPE_UNKNOWN, + /** Volume hosts a NTFS filesystem. */ + RTDVMVOLTYPE_NTFS, + /** Volume hosts a FAT12 filesystem. */ + RTDVMVOLTYPE_FAT12, + /** Volume hosts a FAT16 filesystem. */ + RTDVMVOLTYPE_FAT16, + /** Volume hosts a FAT32 filesystem. */ + RTDVMVOLTYPE_FAT32, + + /** EFI system partition (c12a7328-f81f-11d2-ba4b-00a0c93ec93b). */ + RTDVMVOLTYPE_EFI_SYSTEM, + + /** Volume hosts a Mac OS X HFS or HFS+ filesystem. */ + RTDVMVOLTYPE_DARWIN_HFS, + /** Volume hosts a Mac OS X APFS filesystem. */ + RTDVMVOLTYPE_DARWIN_APFS, + + /** Volume hosts a Linux swap. */ + RTDVMVOLTYPE_LINUX_SWAP, + /** Volume hosts a Linux filesystem. */ + RTDVMVOLTYPE_LINUX_NATIVE, + /** Volume hosts a Linux LVM. */ + RTDVMVOLTYPE_LINUX_LVM, + /** Volume hosts a Linux SoftRaid. */ + RTDVMVOLTYPE_LINUX_SOFTRAID, + + /** Volume hosts a FreeBSD disklabel. */ + RTDVMVOLTYPE_FREEBSD, + /** Volume hosts a NetBSD disklabel. */ + RTDVMVOLTYPE_NETBSD, + /** Volume hosts a OpenBSD disklabel. */ + RTDVMVOLTYPE_OPENBSD, + /** Volume hosts a Solaris volume. */ + RTDVMVOLTYPE_SOLARIS, + + /** Volume hosts a Windows basic data partition . */ + RTDVMVOLTYPE_WIN_BASIC, + /** Volume hosts a Microsoft reserved partition (MSR). */ + RTDVMVOLTYPE_WIN_MSR, + /** Volume hosts a Windows logical disk manager (LDM) metadata partition. */ + RTDVMVOLTYPE_WIN_LDM_META, + /** Volume hosts a Windows logical disk manager (LDM) data partition. */ + RTDVMVOLTYPE_WIN_LDM_DATA, + /** Volume hosts a Windows recovery partition. */ + RTDVMVOLTYPE_WIN_RECOVERY, + /** Volume hosts a storage spaces partition. */ + RTDVMVOLTYPE_WIN_STORAGE_SPACES, + + /** Volume hosts an IBM general parallel file system (GPFS). */ + RTDVMVOLTYPE_IBM_GPFS, + + /** OS/2 (Arca Noae) type 1 partition. */ + RTDVMVOLTYPE_ARCA_OS2, + + /** End of the valid values. */ + RTDVMVOLTYPE_END, + /** Usual 32bit hack. */ + RTDVMVOLTYPE_32BIT_HACK = 0x7fffffff +} RTDVMVOLTYPE; + +/** @defgroup grp_dvm_flags Flags used by RTDvmCreate. + * @{ */ +/** DVM flags - Blocks are always marked as unused if the volume has + * no block status callback set. + * The default is to mark them as used. */ +#define DVM_FLAGS_NO_STATUS_CALLBACK_MARK_AS_UNUSED RT_BIT_32(0) +/** DVM flags - Space which is unused in the map will be marked as used + * when calling RTDvmMapQueryBlockStatus(). */ +#define DVM_FLAGS_UNUSED_SPACE_MARK_AS_USED RT_BIT_32(1) +/** Mask of all valid flags. */ +#define DVM_FLAGS_VALID_MASK UINT32_C(0x00000003) +/** @} */ + + +/** @defgroup grp_dvm_vol_flags Volume flags used by RTDvmVolumeGetFlags(). + * @{ */ +/** Volume flags - Volume is bootable. */ +#define DVMVOLUME_FLAGS_BOOTABLE RT_BIT_64(0) +/** Volume flags - Volume is active. */ +#define DVMVOLUME_FLAGS_ACTIVE RT_BIT_64(1) +/** Volume is contiguous on the underlying medium and RTDvmVolumeQueryRange(). */ +#define DVMVOLUME_F_CONTIGUOUS RT_BIT_64(2) +/** @} */ + +/** A handle to a volume manager. */ +typedef struct RTDVMINTERNAL *RTDVM; +/** A pointer to a volume manager handle. */ +typedef RTDVM *PRTDVM; +/** NIL volume manager handle. */ +#define NIL_RTDVM ((RTDVM)~0) + +/** A handle to a volume in a volume map. */ +typedef struct RTDVMVOLUMEINTERNAL *RTDVMVOLUME; +/** A pointer to a volume handle. */ +typedef RTDVMVOLUME *PRTDVMVOLUME; +/** NIL volume handle. */ +#define NIL_RTDVMVOLUME ((RTDVMVOLUME)~0) + +/** + * Callback for querying the block allocation status of a volume. + * + * @returns IPRT status code. + * @param pvUser Opaque user data passed when setting the callback. + * @param off Offset relative to the start of the volume. + * @param cb Range to check in bytes. + * @param pfAllocated Where to store the allocation status on success. + */ +typedef DECLCALLBACKTYPE(int, FNDVMVOLUMEQUERYBLOCKSTATUS,(void *pvUser, uint64_t off, uint64_t cb, bool *pfAllocated)); +/** Pointer to a query block allocation status callback. */ +typedef FNDVMVOLUMEQUERYBLOCKSTATUS *PFNDVMVOLUMEQUERYBLOCKSTATUS; + +/** + * Create a new volume manager. + * + * @returns IPRT status. + * @param phVolMgr Where to store the handle to the volume manager on + * success. + * @param hVfsFile The disk/container/whatever. + * @param cbSector Size of one sector in bytes. + * @param fFlags Combination of RTDVM_FLAGS_* + */ +RTDECL(int) RTDvmCreate(PRTDVM phVolMgr, RTVFSFILE hVfsFile, uint32_t cbSector, uint32_t fFlags); + +/** + * Retain a given volume manager. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param hVolMgr The volume manager to retain. + */ +RTDECL(uint32_t) RTDvmRetain(RTDVM hVolMgr); + +/** + * Releases a given volume manager. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param hVolMgr The volume manager to release. + */ +RTDECL(uint32_t) RTDvmRelease(RTDVM hVolMgr); + +/** + * Probes the underyling disk for the best volume manager format handler + * and opens it. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if no backend can handle the volume map on the disk. + * @param hVolMgr The volume manager handle. + */ +RTDECL(int) RTDvmMapOpen(RTDVM hVolMgr); + +/** + * Initializes a new volume map using the given format handler. + * + * @returns IPRT status code. + * @param hVolMgr The volume manager handle. + * @param pszFmt The format to use for the new map. + */ +RTDECL(int) RTDvmMapInitialize(RTDVM hVolMgr, const char *pszFmt); + +/** + * Gets the name of the currently used format of the disk map. + * + * @returns Name of the format. + * @param hVolMgr The volume manager handle. + */ +RTDECL(const char *) RTDvmMapGetFormatName(RTDVM hVolMgr); + +/** + * DVM format types. + */ +typedef enum RTDVMFORMATTYPE +{ + /** Invalid zero value. */ + RTDVMFORMATTYPE_INVALID = 0, + /** Master boot record. */ + RTDVMFORMATTYPE_MBR, + /** GUID partition table. */ + RTDVMFORMATTYPE_GPT, + /** BSD labels. */ + RTDVMFORMATTYPE_BSD_LABEL, + /** End of valid values. */ + RTDVMFORMATTYPE_END, + /** 32-bit type size hack. */ + RTDVMFORMATTYPE_32BIT_HACK = 0x7fffffff +} RTDVMFORMATTYPE; + +/** + * Gets the format type of the current disk map. + * + * @returns Format type. RTDVMFORMATTYPE_INVALID on invalid input. + * @param hVolMgr The volume manager handle. + */ +RTDECL(RTDVMFORMATTYPE) RTDvmMapGetFormatType(RTDVM hVolMgr); + +/** + * Gets the UUID of the disk if applicable. + * + * Disks using the MBR format may return the 32-bit disk identity in the + * u32TimeLow field and set the rest to zero. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the partition scheme doesn't do UUIDs. + * @retval VINF_NOT_SUPPORTED if non-UUID disk ID is returned. + * @param hVolMgr The volume manager handle. + * @param pUuid Where to return the UUID. + * + * @todo It's quite possible this should be turned into a map-level edition of + * RTDvmVolumeQueryProp... + */ +RTDECL(int) RTDvmMapQueryDiskUuid(RTDVM hVolMgr, PRTUUID pUuid); + +/** + * Gets the number of valid partitions in the map. + * + * @returns The number of valid volumes in the map or UINT32_MAX on failure. + * @param hVolMgr The volume manager handle. + */ +RTDECL(uint32_t) RTDvmMapGetValidVolumes(RTDVM hVolMgr); + +/** + * Gets the maximum number of partitions the map can hold. + * + * @returns The maximum number of volumes in the map or UINT32_MAX on failure. + * @param hVolMgr The volume manager handle. + */ +RTDECL(uint32_t) RTDvmMapGetMaxVolumes(RTDVM hVolMgr); + +/** + * Get the first valid volume from a map. + * + * @returns IPRT status code. + * @param hVolMgr The volume manager handle. + * @param phVol Where to store the handle to the first volume on + * success. Release with RTDvmVolumeRelease(). + */ +RTDECL(int) RTDvmMapQueryFirstVolume(RTDVM hVolMgr, PRTDVMVOLUME phVol); + +/** + * Get the first valid volume from a map. + * + * @returns IPRT status code. + * @param hVolMgr The volume manager handle. + * @param hVol Handle of the current volume. + * @param phVolNext Where to store the handle to the next volume on + * success. Release with RTDvmVolumeRelease(). + */ +RTDECL(int) RTDvmMapQueryNextVolume(RTDVM hVolMgr, RTDVMVOLUME hVol, PRTDVMVOLUME phVolNext); + +/** + * Returns whether the given block on the disk is in use. + * + * @returns IPRT status code. + * @param hVolMgr The volume manager handle. + * @param off The start offset to check for. + * @param cb The range in bytes to check. + * @param pfAllocated Where to store the in-use status on success. + * + * @remark This method will return true even if a part of the range is not in use. + */ +RTDECL(int) RTDvmMapQueryBlockStatus(RTDVM hVolMgr, uint64_t off, uint64_t cb, bool *pfAllocated); + +/** + * Partition/map table location information. + * @sa RTDvmMapQueryTableLocations + */ +typedef struct RTDVMTABLELOCATION +{ + /** The byte offset on the underlying media. */ + uint64_t off; + /** The table size in bytes. */ + uint64_t cb; + /** Number of padding bytes / free space between the actual table and + * first partition. */ + uint64_t cbPadding; +} RTDVMTABLELOCATION; +/** Pointer to partition table location info. */ +typedef RTDVMTABLELOCATION *PRTDVMTABLELOCATION; +/** Pointer to const partition table location info. */ +typedef RTDVMTABLELOCATION const *PCRTDVMTABLELOCATION; + + +/** @name RTDVMMAPQTABLOC_F_XXX - Flags for RTDvmMapQueryTableLocations + * @{ */ +/** Make sure GPT includes the protective MBR. */ +#define RTDVMMAPQTABLOC_F_INCLUDE_LEGACY RT_BIT_32(0) +/** Valid flags. */ +#define RTDVMMAPQTABLOC_F_VALID_MASK UINT32_C(1) +/** @} */ + +/** + * Query the partition table locations. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the table is too small, @a *pcActual will be + * set to the required size. + * @retval VERR_BUFFER_UNDERFLOW if the table is too big and @a pcActual is + * NULL. + * @param hVolMgr The volume manager handle. + * @param fFlags Flags, see RTDVMMAPQTABLOC_F_XXX. + * @param paLocations Where to return the info. This can be NULL if @a + * cLocations is zero and @a pcActual is given. + * @param cLocations The size of @a paLocations in items. + * @param pcActual Where to return the actual number of locations, or + * on VERR_BUFFER_OVERFLOW the necessary table size. + * Optional, when not specified the cLocations value + * must match exactly or it fails with + * VERR_BUFFER_UNDERFLOW. + */ +RTDECL(int) RTDvmMapQueryTableLocations(RTDVM hVolMgr, uint32_t fFlags, + PRTDVMTABLELOCATION paLocations, size_t cLocations, size_t *pcActual); + +/** + * Retains a valid volume handle. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param hVol The volume to retain. + */ +RTDECL(uint32_t) RTDvmVolumeRetain(RTDVMVOLUME hVol); + +/** + * Releases a valid volume handle. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param hVol The volume to release. + */ +RTDECL(uint32_t) RTDvmVolumeRelease(RTDVMVOLUME hVol); + +/** + * Sets the callback to query the block allocation status for a volume. + * This overwrites any other callback set previously. + * + * @returns nothing. + * @param hVol The volume handle. + * @param pfnQueryBlockStatus The callback to set. Can be NULL to disable + * a previous callback. + * @param pvUser Opaque user data passed in the callback. + */ +RTDECL(void) RTDvmVolumeSetQueryBlockStatusCallback(RTDVMVOLUME hVol, + PFNDVMVOLUMEQUERYBLOCKSTATUS pfnQueryBlockStatus, + void *pvUser); + +/** + * Get the size of a volume in bytes. + * + * @returns Size of the volume in bytes or 0 on failure. + * @param hVol The volume handle. + */ +RTDECL(uint64_t) RTDvmVolumeGetSize(RTDVMVOLUME hVol); + +/** + * Gets the name of the volume if supported. + * + * @returns IPRT status code. + * @param hVol The volume handle. + * @param ppszVolName Where to store the name of the volume on success. + * The string must be freed with RTStrFree(). + */ +RTDECL(int) RTDvmVolumeQueryName(RTDVMVOLUME hVol, char **ppszVolName); + +/** + * Get the volume type of the volume if supported. + * + * @returns The volume type on success, DVMVOLTYPE_INVALID if hVol is invalid. + * @param hVol The volume handle. + */ +RTDECL(RTDVMVOLTYPE) RTDvmVolumeGetType(RTDVMVOLUME hVol); + +/** + * Get the volume flags of the volume if supported. + * + * @returns The volume flags or UINT64_MAX on failure. + * @param hVol The volume handle. + */ +RTDECL(uint64_t) RTDvmVolumeGetFlags(RTDVMVOLUME hVol); + +/** + * Queries the range of the given volume on the underlying medium. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the DVMVOLUME_F_CONTIGUOUS flag is not returned by RTDvmVolumeGetFlags(). + * @param hVol The volume handle. + * @param poffStart Where to store the start offset in bytes on the underlying medium. + * @param poffLast Where to store the last offset in bytes on the underlying medium (inclusive). + */ +RTDECL(int) RTDvmVolumeQueryRange(RTDVMVOLUME hVol, uint64_t *poffStart, uint64_t *poffLast); + +/** + * Returns the partition/whatever table location of the volume. + * + * For volume format with a single table, like GPT and BSD-labels, it will + * return the location of that table. Though for GPT, the fake MBR will not be + * included. + * + * For logical (extended) MBR-style volumes, this will return the location of + * the extended partition table. For primary volumes the MBR location is + * returned. The special MBR case is why this operation is done on the volume + * rather than the volume manager. + * + * Using RTDvmVolumeGetIndex with RTDVMVOLIDX_IN_PART_TABLE should get you + * the index in the table returned by this function. + * + * @returns IPRT status code. + * @param hVol The volume handle. + * @param poffTable Where to return the byte offset on the underlying + * media of the (partition/volume/whatever) table. + * @param pcbTable Where to return the table size in bytes. (This does + * not include any alignment padding or such, just + * padding up to sector/block size.) + */ +RTDECL(int) RTDvmVolumeQueryTableLocation(RTDVMVOLUME hVol, uint64_t *poffTable, uint64_t *pcbTable); + +/** + * RTDvmVolumeGetIndex indexes. + */ +typedef enum RTDVMVOLIDX +{ + /** Invalid zero value. */ + RTDVMVOLIDX_INVALID = 0, + /** Index matching the host's volume numbering. + * This is a pseudo index, that gets translated to one of the others depending + * on which host we're running on. */ + RTDVMVOLIDX_HOST, + /** Only consider user visible ones, i.e. don't count MBR extended partition + * entries and such like. */ + RTDVMVOLIDX_USER_VISIBLE, + /** Index when all volumes, user visible, hidden, special, whatever ones are + * included. + * + * For MBR this is 1-based index where all primary entires are included whether + * in use or not. Only non-empty entries in extended tables are counted, though + * the forward link is included. */ + RTDVMVOLIDX_ALL, + /** The raw index within the partition/volume/whatever table. This have a kind + * of special meaning to MBR, where there are multiple tables. */ + RTDVMVOLIDX_IN_TABLE, + /** Follows the linux /dev/sdaX convention as closely as absolutely possible. */ + RTDVMVOLIDX_LINUX, + /** End of valid indexes. */ + RTDVMVOLIDX_END, + /** Make sure the type is 32-bit. */ + RTDVMVOLIDX_32BIT_HACK = 0x7fffffff +} RTDVMVOLIDX; + +/** + * Gets the tiven index for the specified volume. + * + * @returns The requested index, UINT32_MAX on failure. + * @param hVol The volume handle. + * @param enmIndex Which kind of index to get for the volume. + */ +RTDECL(uint32_t) RTDvmVolumeGetIndex(RTDVMVOLUME hVol, RTDVMVOLIDX enmIndex); + +/** + * Volume properties queriable via RTDvmVolumeQueryProp. + * + * @note Integer values can typically be queried in multiple sizes. This is + * handled by the frontend code. The format specific backends only + * have to handle the smallest allowed size. + */ +typedef enum RTDVMVOLPROP +{ + /** Customary invalid zero value. */ + RTDVMVOLPROP_INVALID = 0, + /** unsigned[16,32,64]: MBR first cylinder (0-based, CHS). */ + RTDVMVOLPROP_MBR_FIRST_CYLINDER, + /** unsigned[8,16,32,64]: MBR first head (0-based, CHS). */ + RTDVMVOLPROP_MBR_FIRST_HEAD, + /** unsigned[8,16,32,64]: MBR first sector (1-based, CHS). */ + RTDVMVOLPROP_MBR_FIRST_SECTOR, + /** unsigned[16,32,64]: MBR last cylinder (0-based, CHS). */ + RTDVMVOLPROP_MBR_LAST_CYLINDER, + /** unsigned[8,16,32,64]: MBR last head (0-based, CHS). */ + RTDVMVOLPROP_MBR_LAST_HEAD, + /** unsigned[8,16,32,64]: MBR last sector (1-based, CHS). */ + RTDVMVOLPROP_MBR_LAST_SECTOR, + /** unsigned[8,16,32,64]: MBR partition type. */ + RTDVMVOLPROP_MBR_TYPE, + /** RTUUID: GPT volume type. */ + RTDVMVOLPROP_GPT_TYPE, + /** RTUUID: GPT volume UUID. */ + RTDVMVOLPROP_GPT_UUID, + /** End of valid values. */ + RTDVMVOLPROP_END, + /** Make sure the type is 32-bit. */ + RTDVMVOLPROP_32BIT_HACK = 0x7fffffff +} RTDVMVOLPROP; + +/** + * Query a generic volume property. + * + * This is an extensible interface for retrieving mostly format specific + * information, or information that's not commonly used. (It's modeled after + * RTLdrQueryPropEx.) + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the property query isn't supported (either all + * or that specific property). The caller must handle this result. + * @retval VERR_NOT_FOUND is currently not returned, but intended for cases + * where it wasn't present in the tables. + * @retval VERR_INVALID_FUNCTION if the @a enmProperty value is wrong. + * @retval VERR_INVALID_PARAMETER if the fixed buffer size is wrong. Correct + * size in @a *pcbBuf. + * @retval VERR_BUFFER_OVERFLOW if the property doesn't have a fixed size + * buffer and the buffer isn't big enough. Correct size in @a *pcbBuf. + * @retval VERR_INVALID_HANDLE if the handle is invalid. + * @param hVol Handle to the volume. + * @param enmProperty The property to query. + * @param pvBuf Pointer to the input / output buffer. In most cases + * it's only used for returning data. + * @param cbBuf The size of the buffer. + * @param pcbBuf Where to return the amount of data returned. On + * buffer size errors, this is set to the correct size. + * Optional. + * @sa RTDvmVolumeGetPropU64 + */ +RTDECL(int) RTDvmVolumeQueryProp(RTDVMVOLUME hVol, RTDVMVOLPROP enmProperty, void *pvBuf, size_t cbBuf, size_t *pcbBuf); + +/** + * Wrapper around RTDvmVolumeQueryProp for simplifying getting unimportant + * integer properties. + * + * @returns The property value if supported and found, the default value if not. + * Errors other than VERR_NOT_SUPPORTED and VERR_NOT_FOUND are + * asserted. + * @param hVol Handle to the volume. + * @param enmProperty The property to query. + * @param uDefault The value to return on error. + * @sa RTDvmVolumeQueryProp + */ +RTDECL(uint64_t) RTDvmVolumeGetPropU64(RTDVMVOLUME hVol, RTDVMVOLPROP enmProperty, uint64_t uDefault); + +/** + * Reads data from the given volume. + * + * @returns IPRT status code. + * @param hVol The volume handle. + * @param off Where to start reading from - 0 is the beginning of + * the volume. + * @param pvBuf Where to store the read data. + * @param cbRead How many bytes to read. + */ +RTDECL(int) RTDvmVolumeRead(RTDVMVOLUME hVol, uint64_t off, void *pvBuf, size_t cbRead); + +/** + * Writes data to the given volume. + * + * @returns IPRT status code. + * @param hVol The volume handle. + * @param off Where to start writing to - 0 is the beginning of + * the volume. + * @param pvBuf The data to write. + * @param cbWrite How many bytes to write. + */ +RTDECL(int) RTDvmVolumeWrite(RTDVMVOLUME hVol, uint64_t off, const void *pvBuf, size_t cbWrite); + +/** + * Returns the description of a given volume type. + * + * @returns The description of the type. + * @param enmVolType The volume type. + */ +RTDECL(const char *) RTDvmVolumeTypeGetDescr(RTDVMVOLTYPE enmVolType); + +/** + * Creates an VFS file from a volume handle. + * + * @returns IPRT status code. + * @param hVol The volume handle. + * @param fOpen RTFILE_O_XXX. + * @param phVfsFileOut Where to store the VFS file handle on success. + */ +RTDECL(int) RTDvmVolumeCreateVfsFile(RTDVMVOLUME hVol, uint64_t fOpen, PRTVFSFILE phVfsFileOut); + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_dvm_h */ + diff --git a/include/iprt/efi.h b/include/iprt/efi.h new file mode 100644 index 00000000..30bb4475 --- /dev/null +++ b/include/iprt/efi.h @@ -0,0 +1,299 @@ +/** @file + * IPRT - EFI related utilities. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_efi_h +#define IPRT_INCLUDED_efi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/time.h> +#include <iprt/vfs.h> + +#include <iprt/formats/efi-common.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_efi RTEfi - EFI utilities + * @ingroup grp_rt + * @{ + */ + + +#ifdef IN_RING3 + +/** + * Converts an EFI time to a time spec (UTC). + * + * @returns pTimeSpec on success. + * @returns NULL if the pEfiTime data is invalid. + * @param pTimeSpec Where to store the converted time. + * @param pEfiTime Pointer to the EFI time struct. + */ +RTDECL(PRTTIMESPEC) RTEfiTimeToTimeSpec(PRTTIMESPEC pTimeSpec, PCEFI_TIME pEfiTime); + + +/** + * Converts a time spec (UTC) to an EFI time. + * + * @returns pEfiTime on success. + * @returns NULL if the pTimeSpec data is invalid. + * @param pEfiTime Pointer to the EFI time struct. + * @param pTimeSpec The time spec to convert. + */ +RTDECL(PEFI_TIME) RTEfiTimeFromTimeSpec(PEFI_TIME pEfiTime, PCRTTIMESPEC pTimeSpec); + + +/** + * Converts the given EFI GUID to the IPRT UUID representation. + * + * @returns pUuid. + * @param pUuid Where to store the converted GUID. + * @param pEfiGuid The EFI GUID to convert. + */ +RTDECL(PRTUUID) RTEfiGuidToUuid(PRTUUID pUuid, PCEFI_GUID pEfiGuid); + + +/** + * Converts the given EFI GUID to the IPRT UUID representation. + * + * @returns pEfiGuid. + * @param pEfiGuid Where to store the converted UUID. + * @param pUuid The UUID to convert. + */ +RTDECL(PEFI_GUID) RTEfiGuidFromUuid(PEFI_GUID pEfiGuid, PCRTUUID pUuid); + + +/** + * Compares two EFI GUID values. + * + * @returns 0 if eq, < 0 or > 0. + * @param pGuid1 First value to compare. + * @param pGuid2 Second value to compare. + */ +RTDECL(int) RTEfiGuidCompare(PCEFI_GUID pGuid1, PCEFI_GUID pGuid2); + + +/** + * Opens an EFI variable store. + * + * @returns IPRT status code. + * @param hVfsFileIn The file or device backing the store. + * @param fMntFlags RTVFSMNT_F_XXX. + * @param fVarStoreFlags Reserved, MBZ. + * @param phVfs Where to return the virtual file system handle. + * @param pErrInfo Where to return additional error information. + */ +RTDECL(int) RTEfiVarStoreOpenAsVfs(RTVFSFILE hVfsFileIn, uint32_t fMntFlags, uint32_t fVarStoreFlags, PRTVFS phVfs, PRTERRINFO pErrInfo); + + +/** @name RTEFIVARSTORE_CREATE_F_XXX - RTEfiVarStoreCreate flags + * @{ */ +/** Use default options. */ +#define RTEFIVARSTORE_CREATE_F_DEFAULT UINT32_C(0) +/** Don't create a fault tolerant write working space. + * The default is to create one reducing the size of the variable store. */ +#define RTEFIVARSTORE_CREATE_F_NO_FTW_WORKING_SPACE RT_BIT_32(0) +/** Mask containing all valid flags. */ +#define RTEFIVARSTORE_CREATE_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Creates a new EFI variable store. + * + * @returns IRPT status code. + * @param hVfsFile The store file. + * @param offStore The offset into @a hVfsFile of the file. + * Typically 0. + * @param cbStore The size of the variable store. Pass 0 if the rest of + * hVfsFile should be used. The remaining space for variables + * will be less because of some metadata overhead. + * @param fFlags See RTEFIVARSTORE_F_XXX. + * @param cbBlock The logical block size. + * @param pErrInfo Additional error information, maybe. Optional. + */ +RTDECL(int) RTEfiVarStoreCreate(RTVFSFILE hVfsFile, uint64_t offStore, uint64_t cbStore, uint32_t fFlags, uint32_t cbBlock, + PRTERRINFO pErrInfo); + + +/** + * EFI signature type. + */ +typedef enum RTEFISIGTYPE +{ + /** Invalid type, do not use. */ + RTEFISIGTYPE_INVALID = 0, + /** First valid signature type. */ + RTEFISIGTYPE_FIRST_VALID, + /** Signature contains a SHA256 hash. */ + RTEFISIGTYPE_SHA256 = RTEFISIGTYPE_FIRST_VALID, + /** Signature contains a RSA2048 key (only the modulus in big endian form, + * the exponent is always 65537/0x10001). */ + RTEFISIGTYPE_RSA2048, + /** Signature contains a RSA2048 signature of a SHA256 hash. */ + RTEFISIGTYPE_RSA2048_SHA256, + /** Signature contains a SHA1 hash. */ + RTEFISIGTYPE_SHA1, + /** Signature contains a RSA2048 signature of a SHA1 hash. */ + RTEFISIGTYPE_RSA2048_SHA1, + /** Signature contains a DER encoded X.509 certificate. */ + RTEFISIGTYPE_X509, + /** First invalid type (do not use). */ + RTEFISIGTYPE_FIRST_INVALID, + /** 32bit blowup hack.*/ + RTEFISIGTYPE_32BIT_HACK = 0x7fffffff +} RTEFISIGTYPE; + + +/** + * EFI signature database enumeration callback. + * + * @returns IPRT status code, any status code other than VINF_SUCCESS will abort the enumeration. + * @param hEfiSigDb Handle to the EFI signature database this callback is called on. + * @param enmSigType The signature type. + * @param pUuidOwner Signature owner UUID. + * @param pvSig The signature data (dependent on the type). + * @param cbSig Size of the signature in bytes. + * @param pvUser Opaque user data passed in RTEfiSigDbEnum(). + */ +typedef DECLCALLBACKTYPE(int, FNRTEFISIGDBENUMSIG,(RTEFISIGDB hEfiSigDb, RTEFISIGTYPE enmSigType, PCRTUUID pUuidOwner, + const void *pvSig, size_t cbSig, void *pvUser)); +/** Pointer to a EFI signature database enumeration callback. */ +typedef FNRTEFISIGDBENUMSIG *PFNRTEFISIGDBENUMSIG; + + +/** + * Creates an empty EFI signature database. + * + * @returns IPRT status code. + * @param phEfiSigDb Where to store the handle to the empty EFI signature database on success. + */ +RTDECL(int) RTEfiSigDbCreate(PRTEFISIGDB phEfiSigDb); + + +/** + * Destroys the given EFI signature database handle. + * + * @returns IPRT status code. + * @param hEfiSigDb The EFI signature database handle to destroy. + */ +RTDECL(int) RTEfiSigDbDestroy(RTEFISIGDB hEfiSigDb); + + +/** + * Adds the signatures from an existing signature database contained in the given file. + * + * @returns IPRT status code. + * @param hEfiSigDb The EFI signature database handle. + * @param hVfsFileIn The file handle containing the existing signature database. + */ +RTDECL(int) RTEfiSigDbAddFromExistingDb(RTEFISIGDB hEfiSigDb, RTVFSFILE hVfsFileIn); + + +/** + * Adds a new signature to the given signature database from the given file. + * + * @returns IPRT status code. + * @param hEfiSigDb The EFI signature database handle. + * @param enmSigType Type of the signature. + * @param pUuidOwner The UUID of the signature owner. + * @param hVfsFileIn File handle containing the signature data. + */ +RTDECL(int) RTEfiSigDbAddSignatureFromFile(RTEFISIGDB hEfiSigDb, RTEFISIGTYPE enmSigType, PCRTUUID pUuidOwner, RTVFSFILE hVfsFileIn); + + +/** + * Adds a new signature to the given signature database from the given buffer. + * + * @returns IPRT status code. + * @param hEfiSigDb The EFI signature database handle. + * @param enmSigType Type of the signature. + * @param pUuidOwner The UUID of the signature owner. + * @param pvBuf Pointer to the signature data. + * @param cbBuf Size of the signature data in bytes. + */ +RTDECL(int) RTEfiSigDbAddSignatureFromBuf(RTEFISIGDB hEfiSigDb, RTEFISIGTYPE enmSigType, PCRTUUID pUuidOwner, + const void *pvBuf, size_t cbBuf); + + +/** + * Writes the given EFI signature database to the given file. + * + * @returns IPRT status code. + * @param hEfiSigDb The EFI signature database handle. + * @param hVfsFileOut The file handle to write the signature database to. + */ +RTDECL(int) RTEfiSigDbWriteToFile(RTEFISIGDB hEfiSigDb, RTVFSFILE hVfsFileOut); + + +/** + * Enumerate all signatures in the given EFI signature database. + * + * @returns IPRT status code. + * @param hEfiSigDb The EFI signature database handle. + * @param pfnEnumSig The callback to call for each signature. + * @param pvUser Opaque user data to pass to the callback. + */ +RTDECL(int) RTEfiSigDbEnum(RTEFISIGDB hEfiSigDb, PFNRTEFISIGDBENUMSIG pfnEnumSig, void *pvUser); + + +/** + * Returns a human readable string of the given signature type. + * + * @returns Human readable string. + * @param enmSigType The signature type. + */ +RTDECL(const char *) RTEfiSigDbTypeStringify(RTEFISIGTYPE enmSigType); + + +/** + * Returns a pointer to the EFI GUID identifying the given signature type. + * + * @returns Pointer to the EFI GUID. + * @param enmSigType The signature type. + */ +RTDECL(PCEFI_GUID) RTEfiSigDbTypeGetGuid(RTEFISIGTYPE enmSigType); + +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_efi_h */ + diff --git a/include/iprt/env.h b/include/iprt/env.h new file mode 100644 index 00000000..3b3d13b2 --- /dev/null +++ b/include/iprt/env.h @@ -0,0 +1,473 @@ +/** @file + * IPRT - Process Environment Strings. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_env_h +#define IPRT_INCLUDED_env_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_env RTEnv - Process Environment Strings + * @ingroup grp_rt + * @{ + */ + +#ifdef IN_RING3 + +/** Special handle that indicates the default process environment. */ +#define RTENV_DEFAULT ((RTENV)~(uintptr_t)0) + +/** + * Creates an empty environment block. + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param pEnv Where to store the handle of the new environment block. + */ +RTDECL(int) RTEnvCreate(PRTENV pEnv); + +/** + * Creates an empty environment block. + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param phEnv Where to store the handle of the new environment block. + * @param fFlags Zero or more RTENV_CREATE_F_XXX flags. + */ +RTDECL(int) RTEnvCreateEx(PRTENV phEnv, uint32_t fFlags); + +/** @name RTENV_CREATE_F_XXX - Flags for RTEnvCreateEx() and RTEnvCreateChangeRecordEx() + * @{ */ +/** Allow equal ('=') as the first character of a variable name. + * This is useful for compatibility with Windows' handling of CWD on drives, as + * these are stored on the form "=D:=D:\tmp\asdf". It is only really useful + * for creating environment blocks for processes and such, since the CRT doesn't + * allow us to apply it directly to the process enviornment. */ +#define RTENV_CREATE_F_ALLOW_EQUAL_FIRST_IN_VAR RT_BIT_32(0) +/** Valid flags. */ +#define RTENV_CREATE_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Creates an environment block and fill it with variables from the given + * environment array. + * + * @returns IPRT status code. + * @retval VWRN_ENV_NOT_FULLY_TRANSLATED may be returned when passing + * RTENV_DEFAULT and one or more of the environment variables have + * codeset incompatibilities. The problematic variables will be + * ignored and not included in the clone, thus the clone will have + * fewer variables. + * @retval VERR_NO_MEMORY + * @retval VERR_NO_STR_MEMORY + * @retval VERR_INVALID_HANDLE + * + * @param pEnv Where to store the handle of the new environment block. + * @param EnvToClone The environment to clone. + */ +RTDECL(int) RTEnvClone(PRTENV pEnv, RTENV EnvToClone); + +/** + * Creates an environment block from an UTF-16 environment raw block. + * + * This is the reverse of RTEnvQueryUtf16Block. + * + * @returns IPRT status code. + * @retval VERR_NO_MEMORY + * @retval VERR_NO_STR_MEMORY + * + * @param phEnv Where to store the handle of the new environment block. + * @param pwszzBlock List of zero terminated string end with a zero length + * string (or two zero terminators if you prefer). The + * strings are on the RTPutEnv format (VAR=VALUE), except + * they are all expected to include an equal sign. + * @param fFlags Flags served for the future. + */ +RTDECL(int) RTEnvCloneUtf16Block(PRTENV phEnv, PCRTUTF16 pwszzBlock, uint32_t fFlags); + +/** + * Destroys an environment block. + * + * @returns IPRT status code. + * + * @param Env Environment block handle. + * Both RTENV_DEFAULT and NIL_RTENV are silently ignored. + */ +RTDECL(int) RTEnvDestroy(RTENV Env); + +/** + * Resets the environment block to contain zero variables. + * + * @returns IPRT status code. + * + * @param hEnv Environment block handle. RTENV_DEFAULT is not supported. + */ +RTDECL(int) RTEnvReset(RTENV hEnv); + +/** + * Get the execve/spawnve/main envp. + * + * All returned strings are in the current process' codepage. + * This array is only valid until the next RTEnv call. + * + * @returns Pointer to the raw array of environment variables. + * @returns NULL if Env is NULL or invalid. + * + * @param Env Environment block handle. + * + * @note This is NOT available on Windows. It is also not a stable export + * and will hopefully be replaced before long (see todo). + * + * @todo This needs to change to return a copy of the env vars like + * RTEnvQueryUtf16Block does! + */ +RTDECL(char const * const *) RTEnvGetExecEnvP(RTENV Env); + +/** + * Get a sorted, UTF-16 environment block for CreateProcess. + * + * @returns IPRT status code. + * + * @param hEnv Environment block handle. + * @param ppwszzBlock Where to return the environment block. This must be + * freed by calling RTEnvFreeUtf16Block. + */ +RTDECL(int) RTEnvQueryUtf16Block(RTENV hEnv, PRTUTF16 *ppwszzBlock); + +/** + * Frees an environment block returned by RTEnvGetUtf16Block(). + * + * @param pwszzBlock What RTEnvGetUtf16Block returned. NULL is ignored. + */ +RTDECL(void) RTEnvFreeUtf16Block(PRTUTF16 pwszzBlock); + +/** + * Get a sorted, UTF-8 environment block. + * + * The environment block is a sequence of putenv formatted ("NAME=VALUE" or + * "NAME") zero terminated strings ending with an empty string (i.e. last string + * has two zeros). + * + * @returns IPRT status code. + * + * @param hEnv Environment block handle. + * @param fSorted Whether to sort it, this will affect @a hEnv. + * @param ppszzBlock Where to return the environment block. This must be + * freed by calling RTEnvFreeUtf8Block. + * @param pcbBlock Where to return the size of the block. Optional. + */ +RTDECL(int) RTEnvQueryUtf8Block(RTENV hEnv, bool fSorted, char **ppszzBlock, size_t *pcbBlock); + +/** + * Frees an environment block returned by RTEnvGetUtf8Block(). + * + * @param pszzBlock What RTEnvGetUtf8Block returned. NULL is ignored. + */ +RTDECL(void) RTEnvFreeUtf8Block(char *pszzBlock); + +/** + * Checks if an environment variable exists in the default environment block. + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param pszVar The environment variable name. + * @remark WARNING! The current implementation does not perform the appropriate + * codeset conversion. We'll figure this out when it becomes necessary. + */ +RTDECL(bool) RTEnvExist(const char *pszVar); +RTDECL(bool) RTEnvExistsBad(const char *pszVar); +RTDECL(bool) RTEnvExistsUtf8(const char *pszVar); + +/** + * Checks if an environment variable exists in a specific environment block. + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param Env The environment handle. + * @param pszVar The environment variable name. + */ +RTDECL(bool) RTEnvExistEx(RTENV Env, const char *pszVar); + +/** + * Gets an environment variable from the default environment block. (getenv). + * + * The caller is responsible for ensuring that nobody changes the environment + * while it's using the returned string pointer! + * + * @returns Pointer to read only string on success, NULL if the variable wasn't found. + * + * @param pszVar The environment variable name. + * + * @remark WARNING! The current implementation does not perform the appropriate + * codeset conversion. We'll figure this out when it becomes necessary. + */ +RTDECL(const char *) RTEnvGet(const char *pszVar); +RTDECL(const char *) RTEnvGetBad(const char *pszVar); +RTDECL(int) RTEnvGetUtf8(const char *pszVar, char *pszValue, size_t cbValue, size_t *pcchActual); + +/** + * Gets an environment variable in a specific environment block. + * + * @returns IPRT status code. + * @retval VERR_ENV_VAR_NOT_FOUND if the variable was not found. + * @retval VERR_ENV_VAR_UNSET if @a hEnv is an environment change record and + * the variable has been recorded as unset. + * + * @param hEnv The environment handle. + * @param pszVar The environment variable name. + * @param pszValue Where to put the buffer. + * @param cbValue The size of the value buffer. + * @param pcchActual Returns the actual value string length. Optional. + */ +RTDECL(int) RTEnvGetEx(RTENV hEnv, const char *pszVar, char *pszValue, size_t cbValue, size_t *pcchActual); + +/** + * Puts an variable=value string into the environment (putenv). + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param pszVarEqualValue The variable '=' value string. If the value and '=' is + * omitted, the variable is removed from the environment. + * + * @remark Don't assume the value is copied. + * @remark WARNING! The current implementation does not perform the appropriate + * codeset conversion. We'll figure this out when it becomes necessary. + */ +RTDECL(int) RTEnvPut(const char *pszVarEqualValue); +RTDECL(int) RTEnvPutBad(const char *pszVarEqualValue); +RTDECL(int) RTEnvPutUtf8(const char *pszVarEqualValue); + +/** + * Puts a copy of the passed in 'variable=value' string into the environment block. + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param Env Handle of the environment block. + * @param pszVarEqualValue The variable '=' value string. If the value and '=' is + * omitted, the variable is removed from the environment. + */ +RTDECL(int) RTEnvPutEx(RTENV Env, const char *pszVarEqualValue); + +/** + * Sets an environment variable (setenv(,,1)). + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param pszVar The environment variable name. + * @param pszValue The environment variable value. + * + * @remark WARNING! The current implementation does not perform the appropriate + * codeset conversion. We'll figure this out when it becomes necessary. + */ +RTDECL(int) RTEnvSet(const char *pszVar, const char *pszValue); +RTDECL(int) RTEnvSetBad(const char *pszVar, const char *pszValue); +RTDECL(int) RTEnvSetUtf8(const char *pszVar, const char *pszValue); + +/** + * Sets an environment variable (setenv(,,1)). + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param Env The environment handle. + * @param pszVar The environment variable name. + * @param pszValue The environment variable value. + */ +RTDECL(int) RTEnvSetEx(RTENV Env, const char *pszVar, const char *pszValue); + +/** + * Removes an environment variable from the default environment block. + * + * @returns IPRT status code. + * @returns VINF_ENV_VAR_NOT_FOUND if the variable was not found. + * + * @param pszVar The environment variable name. + * + * @remark WARNING! The current implementation does not perform the appropriate + * codeset conversion. We'll figure this out when it becomes necessary. + */ +RTDECL(int) RTEnvUnset(const char *pszVar); +RTDECL(int) RTEnvUnsetBad(const char *pszVar); +RTDECL(int) RTEnvUnsetUtf8(const char *pszVar); + +/** + * Removes an environment variable from the specified environment block. + * + * @returns IPRT status code. + * @returns VINF_ENV_VAR_NOT_FOUND if the variable was not found. + * + * @param Env The environment handle. + * @param pszVar The environment variable name. + */ +RTDECL(int) RTEnvUnsetEx(RTENV Env, const char *pszVar); + + +/** + * Returns the value of a environment variable from the default + * environment block in a heap buffer. + * + * @returns Pointer to a string containing the value, free it using RTStrFree. + * NULL if the variable was not found or we're out of memory. + * + * @param pszVar The environment variable name (UTF-8). + */ +RTDECL(char *) RTEnvDup(const char *pszVar); + +/** + * Duplicates the value of a environment variable if it exists. + * + * @returns Pointer to a string containing the value, free it using RTStrFree. + * NULL if the variable was not found or we're out of memory. + * + * @param Env The environment handle. + * @param pszVar The environment variable name. + */ +RTDECL(char *) RTEnvDupEx(RTENV Env, const char *pszVar); + +/** + * Counts the variables in the environment. + * + * @returns Number of variables in the environment. UINT32_MAX on error. + * @param hEnv The environment handle. + * RTENV_DEFAULT is currently not accepted. + */ +RTDECL(uint32_t) RTEnvCountEx(RTENV hEnv); + +/** + * Queries an environment variable by it's index. + * + * This can be used together with RTEnvCount to enumerate the environment block. + * + * @returns IPRT status code. + * @retval VERR_ENV_VAR_NOT_FOUND if the index is out of bounds, output buffers + * untouched. + * @retval VERR_BUFFER_OVERFLOW if one of the buffers are too small. We'll + * fill it with as much we can in RTStrCopy fashion. + * @retval VINF_ENV_VAR_UNSET if @a hEnv is an environment change record and + * the variable at @a iVar is recorded as being unset. + * + * @param hEnv The environment handle. + * RTENV_DEFAULT is currently not accepted. + * @param iVar The variable index. + * @param pszVar Variable name buffer. + * @param cbVar The size of the variable name buffer. + * @param pszValue Value buffer. + * @param cbValue The size of the value buffer. + */ +RTDECL(int) RTEnvGetByIndexEx(RTENV hEnv, uint32_t iVar, char *pszVar, size_t cbVar, char *pszValue, size_t cbValue); + +/** + * Leaner and meaner version of RTEnvGetByIndexEx. + * + * This can be used together with RTEnvCount to enumerate the environment block. + * + * Use with caution as the returned pointer may change by the next call using + * the environment handle. Please only use this API in cases where there is no + * chance of races. + * + * @returns Pointer to the internal environment variable=value string on + * success. If @a hEnv is an environment change recordthe string may + * also be on the "variable" form, representing an unset operation. Do + * NOT change this string, it is read only! + * + * If the index is out of range on the environment handle is invalid, + * NULL is returned. + * + * @param hEnv The environment handle. + * RTENV_DEFAULT is currently not accepted. + * @param iVar The variable index. + */ +RTDECL(const char *) RTEnvGetByIndexRawEx(RTENV hEnv, uint32_t iVar); + + +/** + * Creates an empty environment change record. + * + * This is a special environment for use with RTEnvApplyChanges and similar + * purposes. The + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param phEnv Where to store the handle of the new environment block. + */ +RTDECL(int) RTEnvCreateChangeRecord(PRTENV phEnv); + +/** + * Extended version of RTEnvCreateChangeRecord that takes flags. + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * + * @param phEnv Where to store the handle of the new environment block. + * @param fFlags Zero or more RTENV_CREATE_F_XXX flags. + */ +RTDECL(int) RTEnvCreateChangeRecordEx(PRTENV phEnv, uint32_t fFlags); + +/** + * Checks if @a hEnv is an environment change record. + * + * @returns true if it is, false if it's not or if the handle is invalid. + * @param hEnv The environment handle. + * @sa RTEnvCreateChangeRecord. + */ +RTDECL(bool) RTEnvIsChangeRecord(RTENV hEnv); + +/** + * Applies changes from one environment onto another. + * + * If @a hEnvChanges is a normal environment, its content is just added to @a + * hEnvDst, where variables in the destination can only be overwritten. However + * if @a hEnvChanges is a change record environment, variables in the + * destination can also be removed. + * + * @returns IPRT status code. Typical error is VERR_NO_MEMORY. + * @param hEnvDst The destination environment. + * @param hEnvChanges Handle to the environment containig the changes to + * apply. As said, especially useful if it's a environment + * change record. RTENV_DEFAULT is not supported here. + */ +RTDECL(int) RTEnvApplyChanges(RTENV hEnvDst, RTENV hEnvChanges); + +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_env_h */ + diff --git a/include/iprt/err.h b/include/iprt/err.h new file mode 100644 index 00000000..cfa1d115 --- /dev/null +++ b/include/iprt/err.h @@ -0,0 +1,2823 @@ +/** @file + * IPRT - Status Codes. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_err_h +#define IPRT_INCLUDED_err_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/errcore.h> + + +/** @defgroup grp_rt_err RTErr - Status Codes + * @ingroup grp_rt + * + * The IPRT status codes are in two ranges: {0..999} and {22000..32766}. The + * IPRT users are free to use the range {1000..21999}. See RTERR_RANGE1_FIRST, + * RTERR_RANGE1_LAST, RTERR_RANGE2_FIRST, RTERR_RANGE2_LAST, RTERR_USER_FIRST + * and RTERR_USER_LAST. + * + * @{ + */ + +/** @name Status Code Ranges + * @{ */ +/** The first status code in the primary IPRT range. */ +#define RTERR_RANGE1_FIRST 0 +/** The last status code in the primary IPRT range. */ +#define RTERR_RANGE1_LAST 999 + +/** The first status code in the secondary IPRT range. */ +#define RTERR_RANGE2_FIRST 22000 +/** The last status code in the secondary IPRT range. */ +#define RTERR_RANGE2_LAST 32766 + +/** The first status code in the user range. */ +#define RTERR_USER_FIRST 1000 +/** The last status code in the user range. */ +#define RTERR_USER_LAST 21999 +/** @} */ + + +/* SED-START */ + +/** Success. */ +#define VINF_SUCCESS 0 + +/** @name Misc. Status Codes + * @{ + */ +/** General failure - DON'T USE THIS!!! */ +#define VERR_GENERAL_FAILURE (-1) +/** Invalid parameter. */ +#define VERR_INVALID_PARAMETER (-2) +/** Invalid parameter. */ +#define VWRN_INVALID_PARAMETER 2 +/** Invalid magic or cookie. */ +#define VERR_INVALID_MAGIC (-3) +/** Invalid magic or cookie. */ +#define VWRN_INVALID_MAGIC 3 +/** Invalid loader handle. */ +#define VERR_INVALID_HANDLE (-4) +/** Invalid loader handle. */ +#define VWRN_INVALID_HANDLE 4 +/** Failed to lock the address range. */ +#define VERR_LOCK_FAILED (-5) +/** Invalid memory pointer. */ +#define VERR_INVALID_POINTER (-6) +/** Failed to patch the IDT. */ +#define VERR_IDT_FAILED (-7) +/** Memory allocation failed. */ +#define VERR_NO_MEMORY (-8) +/** Already loaded. */ +#define VERR_ALREADY_LOADED (-9) +/** Permission denied. */ +#define VERR_PERMISSION_DENIED (-10) +/** Permission denied. */ +#define VINF_PERMISSION_DENIED 10 +/** Version mismatch. */ +#define VERR_VERSION_MISMATCH (-11) +/** The request function is not implemented. */ +#define VERR_NOT_IMPLEMENTED (-12) +/** The request function is not implemented. */ +#define VINF_NOT_IMPLEMENTED 12 +/** Invalid flags was given. */ +#define VERR_INVALID_FLAGS (-13) + +/** Not equal. */ +#define VERR_NOT_EQUAL (-18) +/** The specified path does not point at a symbolic link. */ +#define VERR_NOT_SYMLINK (-19) +/** Failed to allocate temporary memory. */ +#define VERR_NO_TMP_MEMORY (-20) +/** Invalid file mode mask (RTFMODE). */ +#define VERR_INVALID_FMODE (-21) +/** Incorrect call order. */ +#define VERR_WRONG_ORDER (-22) +/** There is no TLS (thread local storage) available for storing the current thread. */ +#define VERR_NO_TLS_FOR_SELF (-23) +/** Failed to set the TLS (thread local storage) entry which points to our thread structure. */ +#define VERR_FAILED_TO_SET_SELF_TLS (-24) +/** Not able to allocate contiguous memory. */ +#define VERR_NO_CONT_MEMORY (-26) +/** No memory available for page table or page directory. */ +#define VERR_NO_PAGE_MEMORY (-27) +/** Already initialized. */ +#define VINF_ALREADY_INITIALIZED 28 +/** Already initialized. */ +#define VERR_ALREADY_INITIALIZED (-28) +/** The specified thread is dead. */ +#define VERR_THREAD_IS_DEAD (-29) +/** The specified thread is not waitable. */ +#define VERR_THREAD_NOT_WAITABLE (-30) +/** Pagetable not present. */ +#define VERR_PAGE_TABLE_NOT_PRESENT (-31) +/** Invalid context. + * Typically an API was used by the wrong thread. */ +#define VERR_INVALID_CONTEXT (-32) +/** The per process timer is busy. */ +#define VERR_TIMER_BUSY (-33) +/** Address conflict. */ +#define VERR_ADDRESS_CONFLICT (-34) +/** Unresolved (unknown) host platform error. */ +#define VERR_UNRESOLVED_ERROR (-35) +/** Invalid function. */ +#define VERR_INVALID_FUNCTION (-36) +/** Not supported. */ +#define VERR_NOT_SUPPORTED (-37) +/** Not supported. */ +#define VINF_NOT_SUPPORTED 37 +/** Access denied. */ +#define VERR_ACCESS_DENIED (-38) +/** Call interrupted. */ +#define VERR_INTERRUPTED (-39) +/** Call interrupted. */ +#define VINF_INTERRUPTED 39 +/** Timeout. */ +#define VERR_TIMEOUT (-40) +/** Timeout. */ +#define VINF_TIMEOUT 40 +/** Buffer too small to save result. */ +#define VERR_BUFFER_OVERFLOW (-41) +/** Buffer too small to save result. */ +#define VINF_BUFFER_OVERFLOW 41 +/** Data size overflow. */ +#define VERR_TOO_MUCH_DATA (-42) +/** Max threads number reached. */ +#define VERR_MAX_THRDS_REACHED (-43) +/** Max process number reached. */ +#define VERR_MAX_PROCS_REACHED (-44) +/** The recipient process has refused the signal. */ +#define VERR_SIGNAL_REFUSED (-45) +/** A signal is already pending. */ +#define VERR_SIGNAL_PENDING (-46) +/** The signal being posted is not correct. */ +#define VERR_SIGNAL_INVALID (-47) +/** The state changed. + * This is a generic error message and needs a context to make sense. */ +#define VERR_STATE_CHANGED (-48) +/** Warning, the state changed. + * This is a generic error message and needs a context to make sense. */ +#define VWRN_STATE_CHANGED 48 +/** Error while parsing UUID string */ +#define VERR_INVALID_UUID_FORMAT (-49) +/** The specified process was not found. */ +#define VERR_PROCESS_NOT_FOUND (-50) +/** The process specified to a non-block wait had not exited. */ +#define VERR_PROCESS_RUNNING (-51) +/** Retry the operation. */ +#define VERR_TRY_AGAIN (-52) +/** Retry the operation. */ +#define VINF_TRY_AGAIN 52 +/** Generic parse error. */ +#define VERR_PARSE_ERROR (-53) +/** Value out of range. */ +#define VERR_OUT_OF_RANGE (-54) +/** A numeric conversion encountered a value which was too big for the target. */ +#define VERR_NUMBER_TOO_BIG (-55) +/** A numeric conversion encountered a value which was too big for the target. */ +#define VWRN_NUMBER_TOO_BIG 55 +/** The number begin converted (string) contained no digits. */ +#define VERR_NO_DIGITS (-56) +/** The number begin converted (string) contained no digits. */ +#define VWRN_NO_DIGITS 56 +/** Encountered a '-' during conversion to an unsigned value. */ +#define VERR_NEGATIVE_UNSIGNED (-57) +/** Encountered a '-' during conversion to an unsigned value. */ +#define VWRN_NEGATIVE_UNSIGNED 57 +/** Error while characters translation (unicode and so). */ +#define VERR_NO_TRANSLATION (-58) +/** Error while characters translation (unicode and so). */ +#define VWRN_NO_TRANSLATION 58 +/** Encountered unicode code point which is reserved for use as endian indicator (0xffff or 0xfffe). */ +#define VERR_CODE_POINT_ENDIAN_INDICATOR (-59) +/** Encountered unicode code point in the surrogate range (0xd800 to 0xdfff). */ +#define VERR_CODE_POINT_SURROGATE (-60) +/** A string claiming to be UTF-8 is incorrectly encoded. */ +#define VERR_INVALID_UTF8_ENCODING (-61) +/** A string claiming to be in UTF-16 is incorrectly encoded. */ +#define VERR_INVALID_UTF16_ENCODING (-62) +/** Encountered a unicode code point which cannot be represented as UTF-16. */ +#define VERR_CANT_RECODE_AS_UTF16 (-63) +/** Got an out of memory condition trying to allocate a string. */ +#define VERR_NO_STR_MEMORY (-64) +/** Got an out of memory condition trying to allocate a UTF-16 (/UCS-2) string. */ +#define VERR_NO_UTF16_MEMORY (-65) +/** Get an out of memory condition trying to allocate a code point array. */ +#define VERR_NO_CODE_POINT_MEMORY (-66) +/** Can't free the memory because it's used in mapping. */ +#define VERR_MEMORY_BUSY (-67) +/** The timer can't be started because it's already active. */ +#define VERR_TIMER_ACTIVE (-68) +/** The timer can't be stopped because it's already suspended. */ +#define VERR_TIMER_SUSPENDED (-69) +/** The operation was cancelled by the user (copy) or another thread (local ipc). */ +#define VERR_CANCELLED (-70) +/** Failed to initialize a memory object. + * Exactly what this means is OS specific. */ +#define VERR_MEMOBJ_INIT_FAILED (-71) +/** Out of memory condition when allocating memory with low physical backing. */ +#define VERR_NO_LOW_MEMORY (-72) +/** Out of memory condition when allocating physical memory (without mapping). */ +#define VERR_NO_PHYS_MEMORY (-73) +/** The address (virtual or physical) is too big. */ +#define VERR_ADDRESS_TOO_BIG (-74) +/** Failed to map a memory object. */ +#define VERR_MAP_FAILED (-75) +/** Trailing characters. */ +#define VERR_TRAILING_CHARS (-76) +/** Trailing characters. */ +#define VWRN_TRAILING_CHARS 76 +/** Trailing spaces. */ +#define VERR_TRAILING_SPACES (-77) +/** Trailing spaces. */ +#define VWRN_TRAILING_SPACES 77 +/** Generic not found error. */ +#define VERR_NOT_FOUND (-78) +/** Generic not found warning. */ +#define VWRN_NOT_FOUND 78 +/** Generic invalid state error. */ +#define VERR_INVALID_STATE (-79) +/** Generic invalid state warning. */ +#define VWRN_INVALID_STATE 79 +/** Generic out of resources error. */ +#define VERR_OUT_OF_RESOURCES (-80) +/** Generic out of resources warning. */ +#define VWRN_OUT_OF_RESOURCES 80 +/** No more handles available, too many open handles. */ +#define VERR_NO_MORE_HANDLES (-81) +/** Preemption is disabled. + * The requested operation can only be performed when preemption is enabled. */ +#define VERR_PREEMPT_DISABLED (-82) +/** End of string. */ +#define VERR_END_OF_STRING (-83) +/** End of string. */ +#define VINF_END_OF_STRING 83 +/** A page count is out of range. */ +#define VERR_PAGE_COUNT_OUT_OF_RANGE (-84) +/** Generic object destroyed status. */ +#define VERR_OBJECT_DESTROYED (-85) +/** Generic object was destroyed by the call status. */ +#define VINF_OBJECT_DESTROYED 85 +/** Generic dangling objects status. */ +#define VERR_DANGLING_OBJECTS (-86) +/** Generic dangling objects status. */ +#define VWRN_DANGLING_OBJECTS 86 +/** Invalid Base64 encoding. */ +#define VERR_INVALID_BASE64_ENCODING (-87) +/** Return instigated by a callback or similar. */ +#define VERR_CALLBACK_RETURN (-88) +/** Return instigated by a callback or similar. */ +#define VINF_CALLBACK_RETURN 88 +/** Authentication failure. */ +#define VERR_AUTHENTICATION_FAILURE (-89) +/** Not a power of two. */ +#define VERR_NOT_POWER_OF_TWO (-90) +/** Status code, typically given as a parameter, that isn't supposed to be used. */ +#define VERR_IGNORED (-91) +/** Concurrent access to the object is not allowed. */ +#define VERR_CONCURRENT_ACCESS (-92) +/** The caller does not have a reference to the object. + * This status is used when two threads is caught sharing the same object + * reference. */ +#define VERR_CALLER_NO_REFERENCE (-93) +/** Generic no change error. */ +#define VERR_NO_CHANGE (-95) +/** Generic no change info. */ +#define VINF_NO_CHANGE 95 +/** Out of memory condition when allocating executable memory. */ +#define VERR_NO_EXEC_MEMORY (-96) +/** The alignment is not supported. */ +#define VERR_UNSUPPORTED_ALIGNMENT (-97) +/** The alignment is not really supported, however we got lucky with this + * allocation. */ +#define VINF_UNSUPPORTED_ALIGNMENT 97 +/** Duplicate something. */ +#define VERR_DUPLICATE (-98) +/** Something is missing. */ +#define VERR_MISSING (-99) +/** An unexpected (/unknown) exception was caught. */ +#define VERR_UNEXPECTED_EXCEPTION (-22400) +/** Buffer underflow. */ +#define VERR_BUFFER_UNDERFLOW (-22401) +/** Buffer underflow. */ +#define VINF_BUFFER_UNDERFLOW 22401 +/** Uneven input. */ +#define VERR_UNEVEN_INPUT (-22402) +/** Something is not available or not working properly. */ +#define VERR_NOT_AVAILABLE (-22403) +/** The RTPROC_FLAGS_DETACHED flag isn't supported. */ +#define VERR_PROC_DETACH_NOT_SUPPORTED (-22404) +/** An account is restricted in a certain way. */ +#define VERR_ACCOUNT_RESTRICTED (-22405) +/** An account is restricted in a certain way. */ +#define VINF_ACCOUNT_RESTRICTED 22405 +/** Not able satisfy all the requirements of the request. */ +#define VERR_UNABLE_TO_SATISFY_REQUIREMENTS (-22406) +/** Not able satisfy all the requirements of the request. */ +#define VWRN_UNABLE_TO_SATISFY_REQUIREMENTS 22406 +/** The requested allocation is too big. */ +#define VERR_ALLOCATION_TOO_BIG (-22407) +/** Mismatch. */ +#define VERR_MISMATCH (-22408) +/** Wrong type. */ +#define VERR_WRONG_TYPE (-22409) +/** Wrong type. */ +#define VWRN_WRONG_TYPE (22409) +/** This indicates that the process does not have sufficient privileges to + * perform the operation. */ +#define VERR_PRIVILEGE_NOT_HELD (-22410) +/** Process does not have the trusted code base (TCB) privilege needed for user + * authentication or/and process creation as a given user. TCB is also called + * 'Act as part of the operating system'. */ +#define VERR_PROC_TCB_PRIV_NOT_HELD (-22411) +/** Process does not have the assign primary token (APT) privilege needed + * for creating process as a given user. APT is also called 'Replace a process + * level token'. */ +#define VERR_PROC_APT_PRIV_NOT_HELD (-22412) +/** Process does not have the increase quota (IQ) privilege needed for + * creating a process as a given user. IQ is also called 'Increase quotas'. */ +#define VERR_PROC_IQ_PRIV_NOT_HELD (-22413) +/** The system has too many CPUs. */ +#define VERR_MP_TOO_MANY_CPUS (-22414) +/** Wrong parameter count. */ +#define VERR_WRONG_PARAMETER_COUNT (-22415) +/** Wrong parameter type. */ +#define VERR_WRONG_PARAMETER_TYPE (-22416) +/** Invalid client ID. */ +#define VERR_INVALID_CLIENT_ID (-22417) +/** Invalid session ID. */ +#define VERR_INVALID_SESSION_ID (-22418) +/** Requires process elevation (UAC). */ +#define VERR_PROC_ELEVATION_REQUIRED (-22419) +/** Incompatible configuration requested. */ +#define VERR_INCOMPATIBLE_CONFIG (-22420) +/** String is not terminated within the buffer bounds. */ +#define VERR_NO_STRING_TERMINATOR (-22421) +/** Empty string. */ +#define VERR_EMPTY_STRING (-22422) +/** Too many references to an object. */ +#define VERR_TOO_MANY_REFERENCES (-22423) +/** Returned by RTThreadQueryTerminationStatus to indicate that the thread is + * (or should be) terminating. */ +#define VINF_THREAD_IS_TERMINATING (22424) +/** The thread is terminating. */ +#define VERR_THREAD_IS_TERMINATING (-22424) +/** Unable to translate one or more of the arguments to the codeset the child + * process is expected to use. */ +#define VERR_PROC_NO_ARG_TRANSLATION (-22425) +/** Floating pointer underflow. */ +#define VERR_FLOAT_UNDERFLOW (-22426) +/** Floating pointer underflow. */ +#define VWRN_FLOAT_UNDERFLOW (22426) +/** Floating pointer overflow. */ +#define VERR_FLOAT_OVERFLOW (-22427) +/** Floating pointer overflow. */ +#define VWRN_FLOAT_OVERFLOW (22427) +/** @} */ + + +/** @name Common File/Disk/Pipe/etc Status Codes + * @{ + */ +/** Unresolved (unknown) file i/o error. */ +#define VERR_FILE_IO_ERROR (-100) +/** File/Device open failed. */ +#define VERR_OPEN_FAILED (-101) +/** File not found. */ +#define VERR_FILE_NOT_FOUND (-102) +/** Path not found. */ +#define VERR_PATH_NOT_FOUND (-103) +/** Invalid (malformed) file/path name. */ +#define VERR_INVALID_NAME (-104) +/** The object in question already exists. */ +#define VERR_ALREADY_EXISTS (-105) +/** The object in question already exists. */ +#define VWRN_ALREADY_EXISTS 105 +/** Too many open files. */ +#define VERR_TOO_MANY_OPEN_FILES (-106) +/** Seek error. */ +#define VERR_SEEK (-107) +/** Seek below file start. */ +#define VERR_NEGATIVE_SEEK (-108) +/** Trying to seek on device. */ +#define VERR_SEEK_ON_DEVICE (-109) +/** Reached the end of the file. */ +#define VERR_EOF (-110) +/** Reached the end of the file. */ +#define VINF_EOF 110 +/** Generic file read error. */ +#define VERR_READ_ERROR (-111) +/** Generic file write error. */ +#define VERR_WRITE_ERROR (-112) +/** Write protect error. */ +#define VERR_WRITE_PROTECT (-113) +/** Sharing violation, file is being used by another process. */ +#define VERR_SHARING_VIOLATION (-114) +/** Unable to lock a region of a file. */ +#define VERR_FILE_LOCK_FAILED (-115) +/** File access error, another process has locked a portion of the file. */ +#define VERR_FILE_LOCK_VIOLATION (-116) +/** File or directory can't be created. */ +#define VERR_CANT_CREATE (-117) +/** Directory can't be deleted. */ +#define VERR_CANT_DELETE_DIRECTORY (-118) +/** Can't move file to another disk. */ +#define VERR_NOT_SAME_DEVICE (-119) +/** The filename or extension is too long. */ +#define VERR_FILENAME_TOO_LONG (-120) +/** Media not present in drive. */ +#define VERR_MEDIA_NOT_PRESENT (-121) +/** The type of media was not recognized. Not formatted? */ +#define VERR_MEDIA_NOT_RECOGNIZED (-122) +/** Can't unlock - region was not locked. */ +#define VERR_FILE_NOT_LOCKED (-123) +/** Unrecoverable error: lock was lost. */ +#define VERR_FILE_LOCK_LOST (-124) +/** Can't delete directory with files. */ +#define VERR_DIR_NOT_EMPTY (-125) +/** A directory operation was attempted on a non-directory object. */ +#define VERR_NOT_A_DIRECTORY (-126) +/** A non-directory operation was attempted on a directory object. */ +#define VERR_IS_A_DIRECTORY (-127) +/** Tried to grow a file beyond the limit imposed by the process or the filesystem. */ +#define VERR_FILE_TOO_BIG (-128) +/** No pending request the aio context has to wait for completion. */ +#define VERR_FILE_AIO_NO_REQUEST (-129) +/** The request could not be canceled or prepared for another transfer + * because it is still in progress. */ +#define VERR_FILE_AIO_IN_PROGRESS (-130) +/** The request could not be canceled because it already completed. */ +#define VERR_FILE_AIO_COMPLETED (-131) +/** The I/O context couldn't be destroyed because there are still pending requests. */ +#define VERR_FILE_AIO_BUSY (-132) +/** The requests couldn't be submitted because that would exceed the capacity of the context. */ +#define VERR_FILE_AIO_LIMIT_EXCEEDED (-133) +/** The request was canceled. */ +#define VERR_FILE_AIO_CANCELED (-134) +/** The request wasn't submitted so it can't be canceled. */ +#define VERR_FILE_AIO_NOT_SUBMITTED (-135) +/** A request was not prepared and thus could not be submitted. */ +#define VERR_FILE_AIO_NOT_PREPARED (-136) +/** Not all requests could be submitted due to resource shortage. */ +#define VERR_FILE_AIO_INSUFFICIENT_RESSOURCES (-137) +/** Device or resource is busy. */ +#define VERR_RESOURCE_BUSY (-138) +/** A file operation was attempted on a non-file object. */ +#define VERR_NOT_A_FILE (-139) +/** A non-file operation was attempted on a file object. */ +#define VERR_IS_A_FILE (-140) +/** Unexpected filesystem object type. */ +#define VERR_UNEXPECTED_FS_OBJ_TYPE (-141) +/** A path does not start with a root specification. */ +#define VERR_PATH_DOES_NOT_START_WITH_ROOT (-142) +/** A path is relative, expected an absolute path. */ +#define VERR_PATH_IS_RELATIVE (-143) +/** A path is not relative (start with root), expected an relative path. */ +#define VERR_PATH_IS_NOT_RELATIVE (-144) +/** Zero length path. */ +#define VERR_PATH_ZERO_LENGTH (-145) +/** There are not enough events available on the host to create the I/O context. + * This exact meaning is host platform dependent. */ +#define VERR_FILE_AIO_INSUFFICIENT_EVENTS (-146) +/** The native file handle got stale while it was open. Can occur with + * files on network shares when the server is unresponsive. */ +#define VERR_STALE_FILE_HANDLE (-147) +/** @} */ + + +/** @name Generic Filesystem I/O Status Codes + * @{ + */ +/** Unresolved (unknown) disk i/o error. */ +#define VERR_DISK_IO_ERROR (-150) +/** Invalid drive number. */ +#define VERR_INVALID_DRIVE (-151) +/** Disk is full. */ +#define VERR_DISK_FULL (-152) +/** Disk was changed. */ +#define VERR_DISK_CHANGE (-153) +/** Drive is locked. */ +#define VERR_DRIVE_LOCKED (-154) +/** The specified disk or diskette cannot be accessed. */ +#define VERR_DISK_INVALID_FORMAT (-155) +/** Too many symbolic links. */ +#define VERR_TOO_MANY_SYMLINKS (-156) +/** The OS does not support setting the time stamps on a symbolic link. */ +#define VERR_NS_SYMLINK_SET_TIME (-157) +/** The OS does not support changing the owner of a symbolic link. */ +#define VERR_NS_SYMLINK_CHANGE_OWNER (-158) +/** Symbolic link not allowed. */ +#define VERR_SYMLINK_NOT_ALLOWED (-159) +/** Is a symbolic link. */ +#define VERR_IS_A_SYMLINK (-160) +/** Is a FIFO. */ +#define VERR_IS_A_FIFO (-161) +/** Is a socket. */ +#define VERR_IS_A_SOCKET (-162) +/** Is a block device. */ +#define VERR_IS_A_BLOCK_DEVICE (-163) +/** Is a character device. */ +#define VERR_IS_A_CHAR_DEVICE (-164) +/** No media in drive. */ +#define VERR_DRIVE_IS_EMPTY (-165) +/** @} */ + + +/** @name Generic Directory Enumeration Status Codes + * @{ + */ +/** Unresolved (unknown) search error. */ +#define VERR_SEARCH_ERROR (-200) +/** No more files found. */ +#define VERR_NO_MORE_FILES (-201) +/** No more search handles available. */ +#define VERR_NO_MORE_SEARCH_HANDLES (-202) +/** RTDirReadEx() failed to retrieve the extra data which was requested. */ +#define VWRN_NO_DIRENT_INFO 203 +/** @} */ + + +/** @name Internal Processing Errors + * @{ + */ +/** Internal error - this should never happen. */ +#define VERR_INTERNAL_ERROR (-225) +/** Internal error no. 2. */ +#define VERR_INTERNAL_ERROR_2 (-226) +/** Internal error no. 3. */ +#define VERR_INTERNAL_ERROR_3 (-227) +/** Internal error no. 4. */ +#define VERR_INTERNAL_ERROR_4 (-228) +/** Internal error no. 5. */ +#define VERR_INTERNAL_ERROR_5 (-229) +/** Internal error: Unexpected status code. */ +#define VERR_IPE_UNEXPECTED_STATUS (-230) +/** Internal error: Unexpected status code. */ +#define VERR_IPE_UNEXPECTED_INFO_STATUS (-231) +/** Internal error: Unexpected status code. */ +#define VERR_IPE_UNEXPECTED_ERROR_STATUS (-232) +/** Internal error: Uninitialized status code. + * @remarks This is used by value elsewhere. */ +#define VERR_IPE_UNINITIALIZED_STATUS (-233) +/** Internal error: Supposedly unreachable default case in a switch. */ +#define VERR_IPE_NOT_REACHED_DEFAULT_CASE (-234) +/** @} */ + + +/** @name Generic Device I/O Status Codes + * @{ + */ +/** Unresolved (unknown) device i/o error. */ +#define VERR_DEV_IO_ERROR (-250) +/** Device i/o: Bad unit. */ +#define VERR_IO_BAD_UNIT (-251) +/** Device i/o: Not ready. */ +#define VERR_IO_NOT_READY (-252) +/** Device i/o: Bad command. */ +#define VERR_IO_BAD_COMMAND (-253) +/** Device i/o: CRC error. */ +#define VERR_IO_CRC (-254) +/** Device i/o: Bad length. */ +#define VERR_IO_BAD_LENGTH (-255) +/** Device i/o: Sector not found. */ +#define VERR_IO_SECTOR_NOT_FOUND (-256) +/** Device i/o: General failure. */ +#define VERR_IO_GEN_FAILURE (-257) +/** @} */ + + +/** @name Generic Pipe I/O Status Codes + * @{ + */ +/** Unresolved (unknown) pipe i/o error. */ +#define VERR_PIPE_IO_ERROR (-300) +/** Broken pipe. */ +#define VERR_BROKEN_PIPE (-301) +/** Bad pipe. */ +#define VERR_BAD_PIPE (-302) +/** Pipe is busy. */ +#define VERR_PIPE_BUSY (-303) +/** No data in pipe. */ +#define VERR_NO_DATA (-304) +/** Pipe is not connected. */ +#define VERR_PIPE_NOT_CONNECTED (-305) +/** More data available in pipe. */ +#define VERR_MORE_DATA (-306) +/** Expected read pipe, got a write pipe instead. */ +#define VERR_PIPE_NOT_READ (-307) +/** Expected write pipe, got a read pipe instead. */ +#define VERR_PIPE_NOT_WRITE (-308) +/** @} */ + + +/** @name Generic Semaphores Status Codes + * @{ + */ +/** Unresolved (unknown) semaphore error. */ +#define VERR_SEM_ERROR (-350) +/** Too many semaphores. */ +#define VERR_TOO_MANY_SEMAPHORES (-351) +/** Exclusive semaphore is owned by another process. */ +#define VERR_EXCL_SEM_ALREADY_OWNED (-352) +/** The semaphore is set and cannot be closed. */ +#define VERR_SEM_IS_SET (-353) +/** The semaphore cannot be set again. */ +#define VERR_TOO_MANY_SEM_REQUESTS (-354) +/** Attempt to release mutex not owned by caller. */ +#define VERR_NOT_OWNER (-355) +/** The semaphore has been opened too many times. */ +#define VERR_TOO_MANY_OPENS (-356) +/** The maximum posts for the event semaphore has been reached. */ +#define VERR_TOO_MANY_POSTS (-357) +/** The event semaphore has already been posted. */ +#define VERR_ALREADY_POSTED (-358) +/** The event semaphore has already been posted. */ +#define VINF_ALREADY_POSTED (358) +/** The event semaphore has already been reset. */ +#define VERR_ALREADY_RESET (-359) +/** The semaphore is in use. */ +#define VERR_SEM_BUSY (-360) +/** The previous ownership of this semaphore has ended. */ +#define VERR_SEM_OWNER_DIED (-361) +/** Failed to open semaphore by name - not found. */ +#define VERR_SEM_NOT_FOUND (-362) +/** Semaphore destroyed while waiting. */ +#define VERR_SEM_DESTROYED (-363) +/** Nested ownership requests are not permitted for this semaphore type. */ +#define VERR_SEM_NESTED (-364) +/** The release call only release a semaphore nesting, i.e. the caller is still + * holding the semaphore. */ +#define VINF_SEM_NESTED (364) +/** Deadlock detected. */ +#define VERR_DEADLOCK (-365) +/** Ping-Pong listen or speak out of turn error. */ +#define VERR_SEM_OUT_OF_TURN (-366) +/** Tried to take a semaphore in a bad context. */ +#define VERR_SEM_BAD_CONTEXT (-367) +/** Don't spin for the semaphore, but it is safe to try grab it. */ +#define VINF_SEM_BAD_CONTEXT (367) +/** Wrong locking order detected. */ +#define VERR_SEM_LV_WRONG_ORDER (-368) +/** Wrong release order detected. */ +#define VERR_SEM_LV_WRONG_RELEASE_ORDER (-369) +/** Attempt to recursively enter a non-recursive lock. */ +#define VERR_SEM_LV_NESTED (-370) +/** Invalid parameters passed to the lock validator. */ +#define VERR_SEM_LV_INVALID_PARAMETER (-371) +/** The lock validator detected a deadlock. */ +#define VERR_SEM_LV_DEADLOCK (-372) +/** The lock validator detected an existing deadlock. + * The deadlock was not caused by the current operation, but existed already. */ +#define VERR_SEM_LV_EXISTING_DEADLOCK (-373) +/** Not the lock owner according our records. */ +#define VERR_SEM_LV_NOT_OWNER (-374) +/** An illegal lock upgrade was attempted. */ +#define VERR_SEM_LV_ILLEGAL_UPGRADE (-375) +/** The thread is not a valid signaller of the event. */ +#define VERR_SEM_LV_NOT_SIGNALLER (-376) +/** Internal error in the lock validator or related components. */ +#define VERR_SEM_LV_INTERNAL_ERROR (-377) +/** @} */ + + +/** @name Generic Network I/O Status Codes + * @{ + */ +/** Unresolved (unknown) network error. */ +#define VERR_NET_IO_ERROR (-400) +/** The network is busy or is out of resources. */ +#define VERR_NET_OUT_OF_RESOURCES (-401) +/** Net host name not found. */ +#define VERR_NET_HOST_NOT_FOUND (-402) +/** Network path not found. */ +#define VERR_NET_PATH_NOT_FOUND (-403) +/** General network printing error. */ +#define VERR_NET_PRINT_ERROR (-404) +/** The machine is not on the network. */ +#define VERR_NET_NO_NETWORK (-405) +/** Name is not unique on the network. */ +#define VERR_NET_NOT_UNIQUE_NAME (-406) + +/* These are BSD networking error codes - numbers correspond, don't mess! */ +/** Operation in progress. */ +#define VERR_NET_IN_PROGRESS (-436) +/** Operation already in progress. */ +#define VERR_NET_ALREADY_IN_PROGRESS (-437) +/** Attempted socket operation with a non-socket handle. + * (This includes closed handles.) */ +#define VERR_NET_NOT_SOCKET (-438) +/** Destination address required. */ +#define VERR_NET_DEST_ADDRESS_REQUIRED (-439) +/** Message too long. */ +#define VERR_NET_MSG_SIZE (-440) +/** Protocol wrong type for socket. */ +#define VERR_NET_PROTOCOL_TYPE (-441) +/** Protocol not available. */ +#define VERR_NET_PROTOCOL_NOT_AVAILABLE (-442) +/** Protocol not supported. */ +#define VERR_NET_PROTOCOL_NOT_SUPPORTED (-443) +/** Socket type not supported. */ +#define VERR_NET_SOCKET_TYPE_NOT_SUPPORTED (-444) +/** Operation not supported. */ +#define VERR_NET_OPERATION_NOT_SUPPORTED (-445) +/** Protocol family not supported. */ +#define VERR_NET_PROTOCOL_FAMILY_NOT_SUPPORTED (-446) +/** Address family not supported by protocol family. */ +#define VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED (-447) +/** Address already in use. */ +#define VERR_NET_ADDRESS_IN_USE (-448) +/** Can't assign requested address. */ +#define VERR_NET_ADDRESS_NOT_AVAILABLE (-449) +/** Network is down. */ +#define VERR_NET_DOWN (-450) +/** Network is unreachable. */ +#define VERR_NET_UNREACHABLE (-451) +/** Network dropped connection on reset. */ +#define VERR_NET_CONNECTION_RESET (-452) +/** Software caused connection abort. */ +#define VERR_NET_CONNECTION_ABORTED (-453) +/** Connection reset by peer. */ +#define VERR_NET_CONNECTION_RESET_BY_PEER (-454) +/** No buffer space available. */ +#define VERR_NET_NO_BUFFER_SPACE (-455) +/** Socket is already connected. */ +#define VERR_NET_ALREADY_CONNECTED (-456) +/** Socket is not connected. */ +#define VERR_NET_NOT_CONNECTED (-457) +/** Can't send after socket shutdown. */ +#define VERR_NET_SHUTDOWN (-458) +/** Too many references: can't splice. */ +#define VERR_NET_TOO_MANY_REFERENCES (-459) +/** Too many references: can't splice. */ +#define VERR_NET_CONNECTION_TIMED_OUT (-460) +/** Connection refused. */ +#define VERR_NET_CONNECTION_REFUSED (-461) +/* ELOOP is not net. */ +/* ENAMETOOLONG is not net. */ +/** Host is down. */ +#define VERR_NET_HOST_DOWN (-464) +/** No route to host. */ +#define VERR_NET_HOST_UNREACHABLE (-465) +/** Protocol error. */ +#define VERR_NET_PROTOCOL_ERROR (-466) +/** Incomplete packet was submitted by guest. */ +#define VERR_NET_INCOMPLETE_TX_PACKET (-467) +/** Winsock init error. */ +#define VERR_NET_INIT_FAILED (-468) +/** Trying to use too new winsock API. */ +#define VERR_NET_NOT_UNSUPPORTED (-469) +/** @} */ + + +/** @name TCP Status Codes + * @{ + */ +/** Stop the TCP server. */ +#define VERR_TCP_SERVER_STOP (-500) +/** The server was stopped. */ +#define VINF_TCP_SERVER_STOP 500 +/** The TCP server was shut down using RTTcpServerShutdown. */ +#define VERR_TCP_SERVER_SHUTDOWN (-501) +/** The TCP server was destroyed. */ +#define VERR_TCP_SERVER_DESTROYED (-502) +/** The TCP server has no client associated with it. */ +#define VINF_TCP_SERVER_NO_CLIENT 503 +/** @} */ + + +/** @name UDP Status Codes + * @{ + */ +/** Stop the UDP server. */ +#define VERR_UDP_SERVER_STOP (-520) +/** The server was stopped. */ +#define VINF_UDP_SERVER_STOP 520 +/** The UDP server was shut down using RTUdpServerShutdown. */ +#define VERR_UDP_SERVER_SHUTDOWN (-521) +/** The UDP server was destroyed. */ +#define VERR_UDP_SERVER_DESTROYED (-522) +/** The UDP server has no client associated with it. */ +#define VINF_UDP_SERVER_NO_CLIENT 523 +/** @} */ + + +/** @name L4 Specific Status Codes + * @{ + */ +/** Invalid offset in an L4 dataspace */ +#define VERR_L4_INVALID_DS_OFFSET (-550) +/** IPC error */ +#define VERR_IPC (-551) +/** Item already used */ +#define VERR_RESOURCE_IN_USE (-552) +/** Source/destination not found */ +#define VERR_IPC_PROCESS_NOT_FOUND (-553) +/** Receive timeout */ +#define VERR_IPC_RECEIVE_TIMEOUT (-554) +/** Send timeout */ +#define VERR_IPC_SEND_TIMEOUT (-555) +/** Receive cancelled */ +#define VERR_IPC_RECEIVE_CANCELLED (-556) +/** Send cancelled */ +#define VERR_IPC_SEND_CANCELLED (-557) +/** Receive aborted */ +#define VERR_IPC_RECEIVE_ABORTED (-558) +/** Send aborted */ +#define VERR_IPC_SEND_ABORTED (-559) +/** Couldn't map pages during receive */ +#define VERR_IPC_RECEIVE_MAP_FAILED (-560) +/** Couldn't map pages during send */ +#define VERR_IPC_SEND_MAP_FAILED (-561) +/** Send pagefault timeout in receive */ +#define VERR_IPC_RECEIVE_SEND_PF_TIMEOUT (-562) +/** Send pagefault timeout in send */ +#define VERR_IPC_SEND_SEND_PF_TIMEOUT (-563) +/** (One) receive buffer was too small, or too few buffers */ +#define VINF_IPC_RECEIVE_MSG_CUT 564 +/** (One) send buffer was too small, or too few buffers */ +#define VINF_IPC_SEND_MSG_CUT 565 +/** Dataspace manager server not found */ +#define VERR_L4_DS_MANAGER_NOT_FOUND (-566) +/** @} */ + + +/** @name Loader Status Codes. + * @{ + */ +/** Invalid executable signature. */ +#define VERR_INVALID_EXE_SIGNATURE (-600) +/** The iprt loader recognized a ELF image, but doesn't support loading it. */ +#define VERR_ELF_EXE_NOT_SUPPORTED (-601) +/** The iprt loader recognized a PE image, but doesn't support loading it. */ +#define VERR_PE_EXE_NOT_SUPPORTED (-602) +/** The iprt loader recognized a LX image, but doesn't support loading it. */ +#define VERR_LX_EXE_NOT_SUPPORTED (-603) +/** The iprt loader recognized a LE image, but doesn't support loading it. */ +#define VERR_LE_EXE_NOT_SUPPORTED (-604) +/** The iprt loader recognized a NE image, but doesn't support loading it. */ +#define VERR_NE_EXE_NOT_SUPPORTED (-605) +/** The iprt loader recognized a MZ image, but doesn't support loading it. */ +#define VERR_MZ_EXE_NOT_SUPPORTED (-606) +/** The iprt loader recognized an a.out image, but doesn't support loading it. */ +#define VERR_AOUT_EXE_NOT_SUPPORTED (-607) +/** Bad executable. */ +#define VERR_BAD_EXE_FORMAT (-608) +/** Symbol (export) not found. */ +#define VERR_SYMBOL_NOT_FOUND (-609) +/** Module not found. */ +#define VERR_MODULE_NOT_FOUND (-610) +/** The loader resolved an external symbol to an address to big for the image format. */ +#define VERR_SYMBOL_VALUE_TOO_BIG (-611) +/** The image is too big. */ +#define VERR_IMAGE_TOO_BIG (-612) +/** The image base address is to high for this image type. */ +#define VERR_IMAGE_BASE_TOO_HIGH (-614) +/** Mismatching architecture. */ +#define VERR_LDR_ARCH_MISMATCH (-615) +/** Mismatch between IPRT and native loader. */ +#define VERR_LDR_MISMATCH_NATIVE (-616) +/** Failed to resolve an imported (external) symbol. */ +#define VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND (-617) +/** Generic loader failure. */ +#define VERR_LDR_GENERAL_FAILURE (-618) +/** Code signing error. */ +#define VERR_LDR_IMAGE_HASH (-619) +/** The PE loader encountered delayed imports, a feature which hasn't been implemented yet. */ +#define VERR_LDRPE_DELAY_IMPORT (-620) +/** The PE loader encountered a malformed certificate. */ +#define VERR_LDRPE_CERT_MALFORMED (-621) +/** The PE loader encountered a certificate with an unsupported type or structure revision. */ +#define VERR_LDRPE_CERT_UNSUPPORTED (-622) +/** The PE loader doesn't know how to deal with the global pointer data directory entry yet. */ +#define VERR_LDRPE_GLOBALPTR (-623) +/** The PE loader doesn't support the TLS data directory yet. */ +#define VERR_LDRPE_TLS (-624) +/** The PE loader doesn't grok the COM descriptor data directory entry. */ +#define VERR_LDRPE_COM_DESCRIPTOR (-625) +/** The PE loader encountered an unknown load config directory/header size. */ +#define VERR_LDRPE_LOAD_CONFIG_SIZE (-626) +/** The PE loader encountered a lock prefix table, a feature which hasn't been implemented yet. */ +#define VERR_LDRPE_LOCK_PREFIX_TABLE (-627) +/** The PE loader encountered some Guard CF stuff in the load config. */ +#define VERR_LDRPE_GUARD_CF_STUFF (-628) +/** The ELF loader doesn't handle foreign endianness. */ +#define VERR_LDRELF_ODD_ENDIAN (-630) +/** The ELF image is 'dynamic', the ELF loader can only deal with 'relocatable' images at present. */ +#define VERR_LDRELF_DYN (-631) +/** The ELF image is 'executable', the ELF loader can only deal with 'relocatable' images at present. */ +#define VERR_LDRELF_EXEC (-632) +/** The ELF image was created for an unsupported target machine type. */ +#define VERR_LDRELF_MACHINE (-633) +/** The ELF version is not supported. */ +#define VERR_LDRELF_VERSION (-634) +/** The ELF loader cannot handle multiple SYMTAB sections. */ +#define VERR_LDRELF_MULTIPLE_SYMTABS (-635) +/** The ELF loader encountered a relocation type which is not implemented. */ +#define VERR_LDRELF_RELOCATION_NOT_SUPPORTED (-636) +/** The ELF loader encountered a bad symbol index. */ +#define VERR_LDRELF_INVALID_SYMBOL_INDEX (-637) +/** The ELF loader encountered an invalid symbol name offset. */ +#define VERR_LDRELF_INVALID_SYMBOL_NAME_OFFSET (-638) +/** The ELF loader encountered an invalid relocation offset. */ +#define VERR_LDRELF_INVALID_RELOCATION_OFFSET (-639) +/** The ELF loader didn't find the symbol/string table for the image. */ +#define VERR_LDRELF_NO_SYMBOL_OR_NO_STRING_TABS (-640) +/** The ELF loader encountered an unterminated string table. */ +#define VERR_LDRELF_UNTERMINATED_STRING_TAB (-641) +/** Invalid link address. */ +#define VERR_LDR_INVALID_LINK_ADDRESS (-647) +/** Invalid image relative virtual address. */ +#define VERR_LDR_INVALID_RVA (-648) +/** Invalid segment:offset address. */ +#define VERR_LDR_INVALID_SEG_OFFSET (-649) +/** @}*/ + +/** @name Debug Info Reader Status Codes. + * @{ + */ +/** The module contains no line number information. */ +#define VERR_DBG_NO_LINE_NUMBERS (-650) +/** The module contains no symbol information. */ +#define VERR_DBG_NO_SYMBOLS (-651) +/** The specified segment:offset address was invalid. Typically an attempt at + * addressing outside the segment boundary. */ +#define VERR_DBG_INVALID_ADDRESS (-652) +/** Invalid segment index. */ +#define VERR_DBG_INVALID_SEGMENT_INDEX (-653) +/** Invalid segment offset. */ +#define VERR_DBG_INVALID_SEGMENT_OFFSET (-654) +/** Invalid image relative virtual address. */ +#define VERR_DBG_INVALID_RVA (-655) +/** Invalid image relative virtual address. */ +#define VERR_DBG_SPECIAL_SEGMENT (-656) +/** Address conflict within a module/segment. + * Attempted to add a segment, symbol or line number that fully or partially + * overlaps with an existing one. */ +#define VERR_DBG_ADDRESS_CONFLICT (-657) +/** Duplicate symbol within the module. + * Attempted to add a symbol which name already exists within the module. */ +#define VERR_DBG_DUPLICATE_SYMBOL (-658) +/** The segment index specified when adding a new segment is already in use. */ +#define VERR_DBG_SEGMENT_INDEX_CONFLICT (-659) +/** No line number was found for the specified address/ordinal/whatever. */ +#define VERR_DBG_LINE_NOT_FOUND (-660) +/** The length of the symbol name is out of range. + * This means it is an empty string or that it's greater or equal to + * RTDBG_SYMBOL_NAME_LENGTH. */ +#define VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE (-661) +/** The length of the file name is out of range. + * This means it is an empty string or that it's greater or equal to + * RTDBG_FILE_NAME_LENGTH. */ +#define VERR_DBG_FILE_NAME_OUT_OF_RANGE (-662) +/** The length of the segment name is out of range. + * This means it is an empty string or that it is greater or equal to + * RTDBG_SEGMENT_NAME_LENGTH. */ +#define VERR_DBG_SEGMENT_NAME_OUT_OF_RANGE (-663) +/** The specified address range wraps around. */ +#define VERR_DBG_ADDRESS_WRAP (-664) +/** The file is not a valid NM map file. */ +#define VERR_DBG_NOT_NM_MAP_FILE (-665) +/** The file is not a valid /proc/kallsyms file. */ +#define VERR_DBG_NOT_LINUX_KALLSYMS (-666) +/** No debug module interpreter matching the debug info. */ +#define VERR_DBG_NO_MATCHING_INTERPRETER (-667) +/** Bad DWARF line number header. */ +#define VERR_DWARF_BAD_LINE_NUMBER_HEADER (-668) +/** Unexpected end of DWARF unit. */ +#define VERR_DWARF_UNEXPECTED_END (-669) +/** DWARF LEB value overflows the decoder type. */ +#define VERR_DWARF_LEB_OVERFLOW (-670) +/** Bad DWARF extended line number opcode. */ +#define VERR_DWARF_BAD_LNE (-671) +/** Bad DWARF string. */ +#define VERR_DWARF_BAD_STRING (-672) +/** Bad DWARF position. */ +#define VERR_DWARF_BAD_POS (-673) +/** Bad DWARF info. */ +#define VERR_DWARF_BAD_INFO (-674) +/** Bad DWARF abbreviation data. */ +#define VERR_DWARF_BAD_ABBREV (-675) +/** A DWARF abbreviation was not found. */ +#define VERR_DWARF_ABBREV_NOT_FOUND (-676) +/** Encountered an unknown attribute form. */ +#define VERR_DWARF_UNKNOWN_FORM (-677) +/** Encountered an unexpected attribute form. */ +#define VERR_DWARF_UNEXPECTED_FORM (-678) +/** Unfinished code. */ +#define VERR_DWARF_TODO (-679) +/** Unknown location opcode. */ +#define VERR_DWARF_UNKNOWN_LOC_OPCODE (-680) +/** Expression stack overflow. */ +#define VERR_DWARF_STACK_OVERFLOW (-681) +/** Expression stack underflow. */ +#define VERR_DWARF_STACK_UNDERFLOW (-682) +/** Internal processing error in the DWARF code. */ +#define VERR_DWARF_IPE (-683) +/** Invalid configuration property value. */ +#define VERR_DBG_CFG_INVALID_VALUE (-684) +/** Not an integer property. */ +#define VERR_DBG_CFG_NOT_UINT_PROP (-685) +/** Deferred loading of information failed. */ +#define VERR_DBG_DEFERRED_LOAD_FAILED (-686) +/** Unfinished debug info reader code. */ +#define VERR_DBG_TODO (-687) +/** Found file, but it didn't match the search criteria. */ +#define VERR_DBG_FILE_MISMATCH (-688) +/** Internal processing error in the debug module reader code. */ +#define VERR_DBG_MOD_IPE (-689) +/** The symbol size was adjusted while adding it. */ +#define VINF_DBG_ADJUSTED_SYM_SIZE 690 +/** Unable to parse the CodeView debug information. */ +#define VERR_CV_BAD_FORMAT (-691) +/** Unfinished CodeView debug information feature. */ +#define VERR_CV_TODO (-692) +/** Internal processing error the CodeView debug information reader. */ +#define VERR_CV_IPE (-693) +/** No unwind information was found. */ +#define VERR_DBG_NO_UNWIND_INFO (-694) +/** No unwind information for the specified location. */ +#define VERR_DBG_UNWIND_INFO_NOT_FOUND (-695) +/** Malformed unwind information. */ +#define VERR_DBG_MALFORMED_UNWIND_INFO (-696) +/** @} */ + +/** @name Request Packet Status Codes. + * @{ + */ +/** Invalid RT request type. + * For the RTReqAlloc() case, the caller just specified an illegal enmType. For + * all the other occurrences it means indicates corruption, broken logic, or stupid + * interface user. */ +#define VERR_RT_REQUEST_INVALID_TYPE (-700) +/** Invalid RT request state. + * The state of the request packet was not the expected and accepted one(s). Either + * the interface user screwed up, or we've got corruption/broken logic. */ +#define VERR_RT_REQUEST_STATE (-701) +/** Invalid RT request packet. + * One or more of the RT controlled packet members didn't contain the correct + * values. Some thing's broken. */ +#define VERR_RT_REQUEST_INVALID_PACKAGE (-702) +/** The status field has not been updated yet as the request is still + * pending completion. Someone queried the iStatus field before the request + * has been fully processed. */ +#define VERR_RT_REQUEST_STATUS_STILL_PENDING (-703) +/** The request has been freed, don't read the status now. + * Someone is reading the iStatus field of a freed request packet. */ +#define VERR_RT_REQUEST_STATUS_FREED (-704) +/** @} */ + +/** @name Environment Status Code + * @{ + */ +/** The specified environment variable was not found. (RTEnvGetEx) */ +#define VERR_ENV_VAR_NOT_FOUND (-750) +/** The specified environment variable was not found. (RTEnvUnsetEx) */ +#define VINF_ENV_VAR_NOT_FOUND (750) +/** Unable to translate all the variables in the default environment due to + * codeset issues (LANG / LC_ALL / LC_CTYPE). */ +#define VWRN_ENV_NOT_FULLY_TRANSLATED (751) +/** Invalid environment variable name. */ +#define VERR_ENV_INVALID_VAR_NAME (-752) +/** The environment variable is an unset record. */ +#define VINF_ENV_VAR_UNSET (753) +/** The environment variable has been recorded as being unset. */ +#define VERR_ENV_VAR_UNSET (-753) +/** @} */ + +/** @name Multiprocessor Status Codes. + * @{ + */ +/** The specified cpu is offline. */ +#define VERR_CPU_OFFLINE (-800) +/** The specified cpu was not found. */ +#define VERR_CPU_NOT_FOUND (-801) +/** Not all of the requested CPUs showed up in the PFNRTMPWORKER. */ +#define VERR_NOT_ALL_CPUS_SHOWED (-802) +/** Internal processing error in the RTMp code.*/ +#define VERR_CPU_IPE_1 (-803) +/** @} */ + +/** @name RTGetOpt status codes + * @{ */ +/** RTGetOpt: Command line option not recognized. */ +#define VERR_GETOPT_UNKNOWN_OPTION (-825) +/** RTGetOpt: Command line option needs argument. */ +#define VERR_GETOPT_REQUIRED_ARGUMENT_MISSING (-826) +/** RTGetOpt: Command line option has argument with bad format. */ +#define VERR_GETOPT_INVALID_ARGUMENT_FORMAT (-827) +/** RTGetOpt: Not an option. */ +#define VINF_GETOPT_NOT_OPTION 828 +/** RTGetOpt: Command line option needs an index. */ +#define VERR_GETOPT_INDEX_MISSING (-829) +/** @} */ + +/** @name RTCache status codes + * @{ */ +/** RTCache: cache is full. */ +#define VERR_CACHE_FULL (-850) +/** RTCache: cache is empty. */ +#define VERR_CACHE_EMPTY (-851) +/** @} */ + +/** @name RTMemCache status codes + * @{ */ +/** Reached the max cache size. */ +#define VERR_MEM_CACHE_MAX_SIZE (-855) +/** @} */ + +/** @name RTS3 status codes + * @{ */ +/** Access denied error. */ +#define VERR_S3_ACCESS_DENIED (-875) +/** The bucket/key wasn't found. */ +#define VERR_S3_NOT_FOUND (-876) +/** Bucket already exists. */ +#define VERR_S3_BUCKET_ALREADY_EXISTS (-877) +/** Can't delete bucket with keys. */ +#define VERR_S3_BUCKET_NOT_EMPTY (-878) +/** The current operation was canceled. */ +#define VERR_S3_CANCELED (-879) +/** @} */ + +/** @name HTTP status codes + * @{ */ +/** HTTP Internal Server Error. */ +#define VERR_HTTP_STATUS_SERVER_ERROR (-884) +/** HTTP initialization failed. */ +#define VERR_HTTP_INIT_FAILED (-885) +/** The server has not found anything matching the URI given. */ +#define VERR_HTTP_NOT_FOUND (-886) +/** The request is for something forbidden. Authorization will not help. */ +#define VERR_HTTP_ACCESS_DENIED (-887) +/** The server did not understand the request due to bad syntax. */ +#define VERR_HTTP_BAD_REQUEST (-888) +/** Couldn't connect to the server (proxy?). */ +#define VERR_HTTP_COULDNT_CONNECT (-889) +/** SSL connection error. */ +#define VERR_HTTP_SSL_CONNECT_ERROR (-890) +/** CAcert is missing or has the wrong format. */ +#define VERR_HTTP_CACERT_WRONG_FORMAT (-891) +/** Certificate cannot be authenticated with the given CA certificates. */ +#define VERR_HTTP_CACERT_CANNOT_AUTHENTICATE (-892) +/** The current HTTP request was forcefully aborted */ +#define VERR_HTTP_ABORTED (-893) +/** Request was redirected. */ +#define VERR_HTTP_REDIRECTED (-894) +/** Proxy couldn't be resolved. */ +#define VERR_HTTP_PROXY_NOT_FOUND (-895) +/** The remote host couldn't be resolved. */ +#define VERR_HTTP_HOST_NOT_FOUND (-896) +/** Unexpected cURL error configure the proxy. */ +#define VERR_HTTP_CURL_PROXY_CONFIG (-897) +/** Generic CURL error. */ +#define VERR_HTTP_CURL_ERROR (-899) +/** @} */ + +/** @name RTManifest status codes + * @{ */ +/** A digest type used in the manifest file isn't supported. */ +#define VERR_MANIFEST_UNSUPPORTED_DIGEST_TYPE (-900) +/** An entry in the manifest file couldn't be interpreted correctly. */ +#define VERR_MANIFEST_WRONG_FILE_FORMAT (-901) +/** A digest doesn't match the corresponding file. */ +#define VERR_MANIFEST_DIGEST_MISMATCH (-902) +/** The file list doesn't match to the content of the manifest file. */ +#define VERR_MANIFEST_FILE_MISMATCH (-903) +/** The specified attribute (name) was not found in the manifest. */ +#define VERR_MANIFEST_ATTR_NOT_FOUND (-904) +/** The attribute type did not match. */ +#define VERR_MANIFEST_ATTR_TYPE_MISMATCH (-905) +/** No attribute of the specified types was found. */ +#define VERR_MANIFEST_ATTR_TYPE_NOT_FOUND (-906) +/** @} */ + +/** @name RTTar status codes + * @{ */ +/** The checksum of a tar header record doesn't match. */ +#define VERR_TAR_CHKSUM_MISMATCH (-925) +/** The tar end of file record was read. */ +#define VERR_TAR_END_OF_FILE (-926) +/** The tar file ended unexpectedly. */ +#define VERR_TAR_UNEXPECTED_EOS (-927) +/** The tar termination records was encountered without reaching the end of + * the input stream. */ +#define VERR_TAR_EOS_MORE_INPUT (-928) +/** A number tar header field was malformed. */ +#define VERR_TAR_BAD_NUM_FIELD (-929) +/** A numeric tar header field was not terminated correctly. */ +#define VERR_TAR_BAD_NUM_FIELD_TERM (-930) +/** A number tar header field was encoded using base-256 which this + * tar implementation currently does not support. */ +#define VERR_TAR_BASE_256_NOT_SUPPORTED (-931) +/** A number tar header field yielded a value too large for the internal + * variable of the tar interpreter. */ +#define VERR_TAR_NUM_VALUE_TOO_LARGE (-932) +/** The combined minor and major device number type is too small to hold the + * value stored in the tar header. */ +#define VERR_TAR_DEV_VALUE_TOO_LARGE (-933) +/** The mode field in a tar header is bad. */ +#define VERR_TAR_BAD_MODE_FIELD (-934) +/** The mode field should not include the type. */ +#define VERR_TAR_MODE_WITH_TYPE (-935) +/** The size field should be zero for links and symlinks. */ +#define VERR_TAR_SIZE_NOT_ZERO (-936) +/** Encountered an unknown type flag. */ +#define VERR_TAR_UNKNOWN_TYPE_FLAG (-937) +/** The tar header is all zeros. */ +#define VERR_TAR_ZERO_HEADER (-938) +/** Not a uniform standard tape v0.0 archive header. */ +#define VERR_TAR_NOT_USTAR_V00 (-939) +/** The name is empty. */ +#define VERR_TAR_EMPTY_NAME (-940) +/** A non-directory entry has a name ending with a slash. */ +#define VERR_TAR_NON_DIR_ENDS_WITH_SLASH (-941) +/** Encountered an unsupported portable archive exchange (pax) header. */ +#define VERR_TAR_UNSUPPORTED_PAX_TYPE (-942) +/** Encountered an unsupported Solaris Tar extension. */ +#define VERR_TAR_UNSUPPORTED_SOLARIS_HDR_TYPE (-943) +/** Encountered an unsupported GNU Tar extension. */ +#define VERR_TAR_UNSUPPORTED_GNU_HDR_TYPE (-944) +/** Malformed checksum field in the tar header. */ +#define VERR_TAR_BAD_CHKSUM_FIELD (-945) +/** Malformed checksum field in the tar header. */ +#define VERR_TAR_MALFORMED_GNU_LONGXXXX (-946) +/** Too long name or link string. */ +#define VERR_TAR_NAME_TOO_LONG (-947) +/** A directory entry in the archive. */ +#define VINF_TAR_DIR_PATH (948) +/** @} */ + +/** @name RTPoll status codes + * @{ */ +/** The handle is not pollable. */ +#define VERR_POLL_HANDLE_NOT_POLLABLE (-950) +/** The handle ID is already present in the poll set. */ +#define VERR_POLL_HANDLE_ID_EXISTS (-951) +/** The handle ID was not found in the set. */ +#define VERR_POLL_HANDLE_ID_NOT_FOUND (-952) +/** The poll set is full. */ +#define VERR_POLL_SET_IS_FULL (-953) +/** @} */ + +/** @name Pkzip status codes + * @{ */ +/** No end of central directory record found. */ +#define VERR_PKZIP_NO_EOCB (-960) +/** Too long name string. */ +#define VERR_PKZIP_NAME_TOO_LONG (-961) +/** Local file header corrupt. */ +#define VERR_PKZIP_BAD_LF_HEADER (-962) +/** Central directory file header corrupt. */ +#define VERR_PKZIP_BAD_CDF_HEADER (-963) +/** Encountered an unknown type flag. */ +#define VERR_PKZIP_UNKNOWN_TYPE_FLAG (-964) +/** Found a ZIP64 Extra Information Field in a ZIP32 file. */ +#define VERR_PKZIP_ZIP64EX_IN_ZIP32 (-965) +/** @} */ + +/** @name RTZip status codes + * @{ */ +/** Generic zip error. */ +#define VERR_ZIP_ERROR (-22000) +/** The compressed data was corrupted. */ +#define VERR_ZIP_CORRUPTED (-22001) +/** Ran out of memory while compressing or uncompressing. */ +#define VERR_ZIP_NO_MEMORY (-22002) +/** The compression format version is unsupported. */ +#define VERR_ZIP_UNSUPPORTED_VERSION (-22003) +/** The compression method is unsupported. */ +#define VERR_ZIP_UNSUPPORTED_METHOD (-22004) +/** The compressed data started with a bad header. */ +#define VERR_ZIP_BAD_HEADER (-22005) +/** @} */ + +/** @name RTVfs status codes + * @{ */ +/** The VFS chain specification does not have a valid prefix. */ +#define VERR_VFS_CHAIN_NO_PREFIX (-22100) +/** The VFS chain specification is empty. */ +#define VERR_VFS_CHAIN_EMPTY (-22101) +/** Expected an element. */ +#define VERR_VFS_CHAIN_EXPECTED_ELEMENT (-22102) +/** The VFS object type is not known. */ +#define VERR_VFS_CHAIN_UNKNOWN_TYPE (-22103) +/** Expected a left parentheses. */ +#define VERR_VFS_CHAIN_EXPECTED_LEFT_PARENTHESES (-22104) +/** Expected a right parentheses. */ +#define VERR_VFS_CHAIN_EXPECTED_RIGHT_PARENTHESES (-22105) +/** Expected a provider name. */ +#define VERR_VFS_CHAIN_EXPECTED_PROVIDER_NAME (-22106) +/** Expected an element separator (| or :). */ +#define VERR_VFS_CHAIN_EXPECTED_SEPARATOR (-22107) +/** Leading element separator not permitted. */ +#define VERR_VFS_CHAIN_LEADING_SEPARATOR (-22108) +/** Trailing element separator not permitted. */ +#define VERR_VFS_CHAIN_TRAILING_SEPARATOR (-22109) +/** The provider is only allowed as the first element. */ +#define VERR_VFS_CHAIN_MUST_BE_FIRST_ELEMENT (-22110) +/** The provider cannot be the first element. */ +#define VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT (-22111) +/** VFS object cast failed. */ +#define VERR_VFS_CHAIN_CAST_FAILED (-22112) +/** Internal error in the VFS chain code. */ +#define VERR_VFS_CHAIN_IPE (-22113) +/** VFS chain element provider not found. */ +#define VERR_VFS_CHAIN_PROVIDER_NOT_FOUND (-22114) +/** VFS chain does not terminate with the desired object type. */ +#define VERR_VFS_CHAIN_FINAL_TYPE_MISMATCH (-22115) +/** VFS chain element takes no arguments. */ +#define VERR_VFS_CHAIN_NO_ARGS (-22116) +/** VFS chain element takes exactly one argument. */ +#define VERR_VFS_CHAIN_ONE_ARG (-22117) +/** VFS chain element expected at most one argument. */ +#define VERR_VFS_CHAIN_AT_MOST_ONE_ARG (-22118) +/** VFS chain element expected at least one argument. */ +#define VERR_VFS_CHAIN_AT_LEAST_ONE_ARG (-22119) +/** VFS chain element takes exactly two arguments. */ +#define VERR_VFS_CHAIN_TWO_ARGS (-22120) +/** VFS chain element expected at least two arguments. */ +#define VERR_VFS_CHAIN_AT_LEAST_TWO_ARGS (-22121) +/** VFS chain element expected at most two arguments. */ +#define VERR_VFS_CHAIN_AT_MOST_TWO_ARGS (-22122) +/** VFS chain element takes exactly three arguments. */ +#define VERR_VFS_CHAIN_THREE_ARGS (-22123) +/** VFS chain element expected at least three arguments. */ +#define VERR_VFS_CHAIN_AT_LEAST_THREE_ARGS (-22124) +/** VFS chain element expected at most three arguments. */ +#define VERR_VFS_CHAIN_AT_MOST_THREE_ARGS (-22125) +/** VFS chain element takes exactly four arguments. */ +#define VERR_VFS_CHAIN_FOUR_ARGS (-22126) +/** VFS chain element expected at least four arguments. */ +#define VERR_VFS_CHAIN_AT_LEAST_FOUR_ARGS (-22127) +/** VFS chain element expected at most four arguments. */ +#define VERR_VFS_CHAIN_AT_MOST_FOUR_ARGS (-22128) +/** VFS chain element takes exactly five arguments. */ +#define VERR_VFS_CHAIN_FIVE_ARGS (-22129) +/** VFS chain element expected at least five arguments. */ +#define VERR_VFS_CHAIN_AT_LEAST_FIVE_ARGS (-22130) +/** VFS chain element expected at most five arguments. */ +#define VERR_VFS_CHAIN_AT_MOST_FIVE_ARGS (-22131) +/** VFS chain element takes exactly six arguments. */ +#define VERR_VFS_CHAIN_SIX_ARGS (-22132) +/** VFS chain element expected at least six arguments. */ +#define VERR_VFS_CHAIN_AT_LEAST_SIX_ARGS (-22133) +/** VFS chain element expected at most six arguments. */ +#define VERR_VFS_CHAIN_AT_MOST_SIX_ARGS (-22134) +/** VFS chain element expected at most six arguments. */ +#define VERR_VFS_CHAIN_TOO_FEW_ARGS (-22135) +/** VFS chain element expected at most six arguments. */ +#define VERR_VFS_CHAIN_TOO_MANY_ARGS (-22136) +/** VFS chain element expected non-empty argument. */ +#define VERR_VFS_CHAIN_EMPTY_ARG (-22137) +/** Invalid argument to VFS chain element. */ +#define VERR_VFS_CHAIN_INVALID_ARGUMENT (-22138) +/** VFS chain element only provides file and I/O stream (ios) objects. */ +#define VERR_VFS_CHAIN_ONLY_FILE_OR_IOS (-22139) +/** VFS chain element only provides I/O stream (ios) objects. */ +#define VERR_VFS_CHAIN_ONLY_IOS (-22140) +/** VFS chain element only provides directory (dir) objects. */ +#define VERR_VFS_CHAIN_ONLY_DIR (-22141) +/** VFS chain element only provides file system stream (fss) objects. */ +#define VERR_VFS_CHAIN_ONLY_FSS (-22142) +/** VFS chain element only provides file system (vfs) objects. */ +#define VERR_VFS_CHAIN_ONLY_VFS (-22143) +/** VFS chain element only provides file, I/O stream (ios), or + * directory (dir) objects. */ +#define VERR_VFS_CHAIN_ONLY_FILE_OR_IOS_OR_DIR (-22144) +/** VFS chain element only provides file, I/O stream (ios), or + * directory (dir) objects. */ +#define VERR_VFS_CHAIN_ONLY_DIR_OR_VFS (-22145) +/** VFS chain element takes a file object as input. */ +#define VERR_VFS_CHAIN_TAKES_FILE (-22146) +/** VFS chain element takes a file or I/O stream (ios) object as input. */ +#define VERR_VFS_CHAIN_TAKES_FILE_OR_IOS (-22147) +/** VFS chain element takes a directory (dir) object as input. */ +#define VERR_VFS_CHAIN_TAKES_DIR (-22148) +/** VFS chain element takes a file system stream (fss) object as input. */ +#define VERR_VFS_CHAIN_TAKES_FSS (-22149) +/** VFS chain element takes a file system (vfs) object as input. */ +#define VERR_VFS_CHAIN_TAKES_VFS (-22150) +/** VFS chain element takes a directory (dir) or file system (vfs) + * object as input. */ +#define VERR_VFS_CHAIN_TAKES_DIR_OR_VFS (-22151) +/** VFS chain element takes a directory (dir), file system stream (fss), + * or file system (vfs) object as input. */ +#define VERR_VFS_CHAIN_TAKES_DIR_OR_FSS_OR_VFS (-22152) +/** VFS chain element only provides a read-only I/O stream, while the chain + * requires write access. */ +#define VERR_VFS_CHAIN_READ_ONLY_IOS (-22153) +/** VFS chain element only provides a read-only I/O stream, while the chain + * read access. */ +#define VERR_VFS_CHAIN_WRITE_ONLY_IOS (-22154) +/** VFS chain only has a single element and it is just a path, need to be + * treated as a normal file system request. */ +#define VERR_VFS_CHAIN_PATH_ONLY (-22155) +/** VFS chain element preceding the final path needs to be a directory, file + * system or file system stream. */ +#define VERR_VFS_CHAIN_TYPE_MISMATCH_PATH_ONLY (-22156) +/** VFS chain doesn't end with a path only element. */ +#define VERR_VFS_CHAIN_NOT_PATH_ONLY (-22157) +/** The path only element at the end of the VFS chain is too short to make out + * the parent directory. */ +#define VERR_VFS_CHAIN_TOO_SHORT_FOR_PARENT (-22158) +/** @} */ + +/** @name RTDvm status codes + * @{ */ +/** The volume map doesn't contain any valid volume. */ +#define VERR_DVM_MAP_EMPTY (-22200) +/** There is no volume behind the current one. */ +#define VERR_DVM_MAP_NO_VOLUME (-22201) +/** @} */ + +/** @name Logger status codes + * @{ */ +/** The internal logger revision did not match. */ +#define VERR_LOG_REVISION_MISMATCH (-22300) +/** Logging is disabled or logger instance could not be created. */ +#define VINF_LOG_DISABLED (22301) +/** No logger instance. */ +#define VINF_LOG_NO_LOGGER (22302) +/** @} */ + +/* see above, 22400..22499 is used for misc codes! */ + +/** @name Logger status codes + * @{ */ +/** Power off is not supported by the hardware or the OS. */ +#define VERR_SYS_CANNOT_POWER_OFF (-22500) +/** The halt action was requested, but the OS may actually power + * off the machine. */ +#define VINF_SYS_MAY_POWER_OFF (22501) +/** Shutdown failed. */ +#define VERR_SYS_SHUTDOWN_FAILED (-22502) +/** Unsupported firmware property. */ +#define VERR_SYS_UNSUPPORTED_FIRMWARE_PROPERTY (-22503) +/** @} */ + +/** @name Filesystem status codes + * @{ */ +/** Filesystem can't be opened because it is corrupt. */ +#define VERR_FILESYSTEM_CORRUPT (-22600) +/** @} */ + +/** @name RTZipXar status codes. + * @{ */ +/** Wrong magic value. */ +#define VERR_XAR_WRONG_MAGIC (-22700) +/** Bad header size. */ +#define VERR_XAR_BAD_HDR_SIZE (-22701) +/** Unsupported version. */ +#define VERR_XAR_UNSUPPORTED_VERSION (-22702) +/** Unsupported hashing function. */ +#define VERR_XAR_UNSUPPORTED_HASH_FUNCTION (-22703) +/** The table of content (TOC) is too small and therefore can't be valid. */ +#define VERR_XAR_TOC_TOO_SMALL (-22704) +/** The table of content (TOC) is too big. */ +#define VERR_XAR_TOC_TOO_BIG (-22705) +/** The compressed table of content is too big. */ +#define VERR_XAR_TOC_TOO_BIG_COMPRESSED (-22706) +/** The uncompressed table of content size in the header didn't match what + * ZLib returned. */ +#define VERR_XAR_TOC_UNCOMP_SIZE_MISMATCH (-22707) +/** The table of content string length didn't match the size specified in the + * header. */ +#define VERR_XAR_TOC_STRLEN_MISMATCH (-22708) +/** The table of content isn't valid UTF-8. */ +#define VERR_XAR_TOC_UTF8_ENCODING (-22709) +/** XML error while parsing the table of content. */ +#define VERR_XAR_TOC_XML_PARSE_ERROR (-22710) +/** The table of content XML document does not have a toc element. */ +#define VERR_XML_TOC_ELEMENT_MISSING (-22711) +/** The table of content XML element (toc) has siblings, we expected it to be + * an only child or the root element (xar). */ +#define VERR_XML_TOC_ELEMENT_HAS_SIBLINGS (-22712) +/** The XAR table of content digest doesn't match. */ +#define VERR_XAR_TOC_DIGEST_MISMATCH (-22713) +/** Bad or missing XAR checksum element. */ +#define VERR_XAR_BAD_CHECKSUM_ELEMENT (-22714) +/** The hash function in the header doesn't match the one in the table of + * content. */ +#define VERR_XAR_HASH_FUNCTION_MISMATCH (-22715) +/** Bad digest length encountered in the table of content. */ +#define VERR_XAR_BAD_DIGEST_LENGTH (-22716) +/** The order of elements in the XAR file does not lend it self to expansion + * from via an I/O stream. */ +#define VERR_XAR_NOT_STREAMBLE_ELEMENT_ORDER (-22717) +/** Missing offset element in table of content sub-element. */ +#define VERR_XAR_MISSING_OFFSET_ELEMENT (-22718) +/** Bad offset element in table of content sub-element. */ +#define VERR_XAR_BAD_OFFSET_ELEMENT (-22719) +/** Missing size element in table of content sub-element. */ +#define VERR_XAR_MISSING_SIZE_ELEMENT (-22720) +/** Bad size element in table of content sub-element. */ +#define VERR_XAR_BAD_SIZE_ELEMENT (-22721) +/** Missing length element in table of content sub-element. */ +#define VERR_XAR_MISSING_LENGTH_ELEMENT (-22722) +/** Bad length element in table of content sub-element. */ +#define VERR_XAR_BAD_LENGTH_ELEMENT (-22723) +/** Bad file element in XAR table of content. */ +#define VERR_XAR_BAD_FILE_ELEMENT (-22724) +/** Missing data element for XAR file. */ +#define VERR_XAR_MISSING_DATA_ELEMENT (-22725) +/** Unknown XAR file type value. */ +#define VERR_XAR_UNKNOWN_FILE_TYPE (-22726) +/** Missing encoding element for XAR data stream. */ +#define VERR_XAR_NO_ENCODING (-22727) +/** Bad timestamp for XAR file. */ +#define VERR_XAR_BAD_FILE_TIMESTAMP (-22728) +/** Bad file mode for XAR file. */ +#define VERR_XAR_BAD_FILE_MODE (-22729) +/** Bad file user id for XAR file. */ +#define VERR_XAR_BAD_FILE_UID (-22730) +/** Bad file group id for XAR file. */ +#define VERR_XAR_BAD_FILE_GID (-22731) +/** Bad file inode device number for XAR file. */ +#define VERR_XAR_BAD_FILE_DEVICE_NO (-22732) +/** Bad file inode number for XAR file. */ +#define VERR_XAR_BAD_FILE_INODE (-22733) +/** Invalid name for XAR file. */ +#define VERR_XAR_INVALID_FILE_NAME (-22734) +/** The message digest of the extracted data does not match the one supplied. */ +#define VERR_XAR_EXTRACTED_HASH_MISMATCH (-22735) +/** The extracted data has exceeded the expected size. */ +#define VERR_XAR_EXTRACTED_SIZE_EXCEEDED (-22736) +/** The message digest of the archived data does not match the one supplied. */ +#define VERR_XAR_ARCHIVED_HASH_MISMATCH (-22737) +/** The decompressor completed without using all the input data. */ +#define VERR_XAR_UNUSED_ARCHIVED_DATA (-22738) +/** Expected the archived and extracted XAR data sizes to be the same for + * uncompressed data. */ +#define VERR_XAR_ARCHIVED_AND_EXTRACTED_SIZES_MISMATCH (-22739) +/** @} */ + +/** @name RTX509 status codes + * @{ */ +/** Error reading a certificate in PEM format from BIO. */ +#define VERR_X509_READING_CERT_FROM_BIO (-23100) +/** Error extracting a public key from the certificate. */ +#define VERR_X509_EXTRACT_PUBKEY_FROM_CERT (-23101) +/** Error extracting RSA from the public key. */ +#define VERR_X509_EXTRACT_RSA_FROM_PUBLIC_KEY (-23102) +/** Signature verification failed. */ +#define VERR_X509_RSA_VERIFICATION_FUILURE (-23103) +/** Basic constraints were not found. */ +#define VERR_X509_NO_BASIC_CONSTARAINTS (-23104) +/** Error getting extensions from the certificate. */ +#define VERR_X509_GETTING_EXTENSION_FROM_CERT (-23105) +/** Error getting a data from the extension. */ +#define VERR_X509_GETTING_DATA_FROM_EXTENSION (-23106) +/** Error formatting an extension. */ +#define VERR_X509_PRINT_EXTENSION_TO_BIO (-23107) +/** X509 certificate verification error. */ +#define VERR_X509_CERTIFICATE_VERIFICATION_FAILURE (-23108) +/** X509 certificate isn't self signed. */ +#define VERR_X509_NOT_SELFSIGNED_CERTIFICATE (-23109) +/** Warning X509 certificate isn't self signed. */ +#define VINF_X509_NOT_SELFSIGNED_CERTIFICATE 23109 +/** @} */ + +/** @name RTAsn1 status codes + * @{ */ +/** Temporary place holder. */ +#define VERR_ASN1_ERROR (-22800) +/** Encountered an ASN.1 string type that is not supported. */ +#define VERR_ASN1_STRING_TYPE_NOT_IMPLEMENTED (-22801) +/** Invalid ASN.1 UTF-8 STRING encoding. */ +#define VERR_ASN1_INVALID_UTF8_STRING_ENCODING (-22802) +/** Invalid ASN.1 NUMERIC STRING encoding. */ +#define VERR_ASN1_INVALID_NUMERIC_STRING_ENCODING (-22803) +/** Invalid ASN.1 PRINTABLE STRING encoding. */ +#define VERR_ASN1_INVALID_PRINTABLE_STRING_ENCODING (-22804) +/** Invalid ASN.1 T61/TELETEX STRING encoding. */ +#define VERR_ASN1_INVALID_T61_STRING_ENCODING (-22805) +/** Invalid ASN.1 VIDEOTEX STRING encoding. */ +#define VERR_ASN1_INVALID_VIDEOTEX_STRING_ENCODING (-22806) +/** Invalid ASN.1 IA5 STRING encoding. */ +#define VERR_ASN1_INVALID_IA5_STRING_ENCODING (-22807) +/** Invalid ASN.1 GRAPHIC STRING encoding. */ +#define VERR_ASN1_INVALID_GRAPHIC_STRING_ENCODING (-22808) +/** Invalid ASN.1 ISO-646/VISIBLE STRING encoding. */ +#define VERR_ASN1_INVALID_VISIBLE_STRING_ENCODING (-22809) +/** Invalid ASN.1 GENERAL STRING encoding. */ +#define VERR_ASN1_INVALID_GENERAL_STRING_ENCODING (-22810) +/** Invalid ASN.1 UNIVERSAL STRING encoding. */ +#define VERR_ASN1_INVALID_UNIVERSAL_STRING_ENCODING (-22811) +/** Invalid ASN.1 BMP STRING encoding. */ +#define VERR_ASN1_INVALID_BMP_STRING_ENCODING (-22812) +/** Invalid ASN.1 OBJECT IDENTIFIER encoding. */ +#define VERR_ASN1_INVALID_OBJID_ENCODING (-22813) +/** A component value of an ASN.1 OBJECT IDENTIFIER is too big for our + * internal representation (32-bits). */ +#define VERR_ASN1_OBJID_COMPONENT_TOO_BIG (-22814) +/** Too many components in an ASN.1 OBJECT IDENTIFIER for our internal + * representation. */ +#define VERR_ASN1_OBJID_TOO_MANY_COMPONENTS (-22815) +/** The dotted-string representation of an ASN.1 OBJECT IDENTIFIER would be too + * long for our internal representation. */ +#define VERR_ASN1_OBJID_TOO_LONG_STRING_FORM (-22816) +/** Invalid dotted string. */ +#define VERR_ASN1_OBJID_INVALID_DOTTED_STRING (-22817) +/** Constructed string type not implemented. */ +#define VERR_ASN1_CONSTRUCTED_STRING_NOT_IMPL (-22818) +/** Expected a different string tag. */ +#define VERR_ASN1_STRING_TAG_MISMATCH (-22819) +/** Expected a different time tag. */ +#define VERR_ASN1_TIME_TAG_MISMATCH (-22820) +/** More unconsumed data available. */ +#define VINF_ASN1_MORE_DATA (22821) +/** RTAsnEncodeWriteHeader return code indicating that nothing was written + * and the content should be skipped as well. */ +#define VINF_ASN1_NOT_ENCODED (22822) +/** Unknown escape sequence encountered in TeletexString. */ +#define VERR_ASN1_TELETEX_UNKNOWN_ESC_SEQ (-22823) +/** Unsupported escape sequence encountered in TeletexString. */ +#define VERR_ASN1_TELETEX_UNSUPPORTED_ESC_SEQ (-22824) +/** Unsupported character set. */ +#define VERR_ASN1_TELETEX_UNSUPPORTED_CHARSET (-22825) +/** ASN.1 object has no virtual method table. */ +#define VERR_ASN1_NO_VTABLE (-22826) +/** ASN.1 object has no pfnCheckSanity method. */ +#define VERR_ASN1_NO_CHECK_SANITY_METHOD (-22827) +/** ASN.1 object is not present */ +#define VERR_ASN1_NOT_PRESENT (-22828) +/** There are unconsumed bytes after decoding an ASN.1 object. */ +#define VERR_ASN1_CURSOR_NOT_AT_END (-22829) +/** Long ASN.1 tag form is not implemented. */ +#define VERR_ASN1_CURSOR_LONG_TAG (-22830) +/** Bad ASN.1 object length encoding. */ +#define VERR_ASN1_CURSOR_BAD_LENGTH_ENCODING (-22831) +/** Indefinite length form is against the rules. */ +#define VERR_ASN1_CURSOR_ILLEGAL_INDEFINITE_LENGTH (-22832) +/** Malformed indefinite length encoding. */ +#define VERR_ASN1_CURSOR_BAD_INDEFINITE_LENGTH (-22833) +/** ASN.1 object length goes beyond the end of the byte stream being decoded. */ +#define VERR_ASN1_CURSOR_BAD_LENGTH (-22834) +/** Not more data in ASN.1 byte stream. */ +#define VERR_ASN1_CURSOR_NO_MORE_DATA (-22835) +/** Too little data in ASN.1 byte stream. */ +#define VERR_ASN1_CURSOR_TOO_LITTLE_DATA_LEFT (-22836) +/** Constructed string is not according to the encoding rules. */ +#define VERR_ASN1_CURSOR_ILLEGAL_CONSTRUCTED_STRING (-22837) +/** Unexpected ASN.1 tag encountered while decoding. */ +#define VERR_ASN1_CURSOR_TAG_MISMATCH (-22838) +/** Unexpected ASN.1 tag class/flag encountered while decoding. */ +#define VERR_ASN1_CURSOR_TAG_FLAG_CLASS_MISMATCH (-22839) +/** ASN.1 bit string object is out of bounds. */ +#define VERR_ASN1_BITSTRING_OUT_OF_BOUNDS (-22840) +/** Bad ASN.1 time object. */ +#define VERR_ASN1_TIME_BAD_NORMALIZE_INPUT (-22841) +/** Failed to normalize ASN.1 time object. */ +#define VERR_ASN1_TIME_NORMALIZE_ERROR (-22842) +/** Normalization of ASN.1 time object didn't work out. */ +#define VERR_ASN1_TIME_NORMALIZE_MISMATCH (-22843) +/** Invalid ASN.1 UTC TIME encoding. */ +#define VERR_ASN1_INVALID_UTC_TIME_ENCODING (-22844) +/** Invalid ASN.1 GENERALIZED TIME encoding. */ +#define VERR_ASN1_INVALID_GENERALIZED_TIME_ENCODING (-22845) +/** Invalid ASN.1 BOOLEAN encoding. */ +#define VERR_ASN1_INVALID_BOOLEAN_ENCODING (-22846) +/** Invalid ASN.1 NULL encoding. */ +#define VERR_ASN1_INVALID_NULL_ENCODING (-22847) +/** Invalid ASN.1 BIT STRING encoding. */ +#define VERR_ASN1_INVALID_BITSTRING_ENCODING (-22848) +/** Unimplemented ASN.1 tag reached the RTAsn1DynType code. */ +#define VERR_ASN1_DYNTYPE_TAG_NOT_IMPL (-22849) +/** ASN.1 tag and flags/class mismatch in RTAsn1DynType code. */ +#define VERR_ASN1_DYNTYPE_BAD_TAG (-22850) +/** Unexpected ASN.1 fake/dummy object. */ +#define VERR_ASN1_DUMMY_OBJECT (-22851) +/** ASN.1 object is too long. */ +#define VERR_ASN1_TOO_LONG (-22852) +/** Expected primitive ASN.1 object. */ +#define VERR_ASN1_EXPECTED_PRIMITIVE (-22853) +/** Expected valid data pointer for ASN.1 object. */ +#define VERR_ASN1_INVALID_DATA_POINTER (-22854) +/** The ASN.1 encoding is too deeply nested for the decoder. */ +#define VERR_ASN1_TOO_DEEPLY_NESTED (-22855) +/** Generic unexpected object ID error. */ +#define VERR_ASN1_UNEXPECTED_OBJ_ID (-22856) +/** Invalid ASN.1 INTEGER encoding. */ +#define VERR_ASN1_INVALID_INTEGER_ENCODING (-22857) + +/** ANS.1 internal error 1. */ +#define VERR_ASN1_INTERNAL_ERROR_1 (-22895) +/** ANS.1 internal error 2. */ +#define VERR_ASN1_INTERNAL_ERROR_2 (-22896) +/** ANS.1 internal error 3. */ +#define VERR_ASN1_INTERNAL_ERROR_3 (-22897) +/** ANS.1 internal error 4. */ +#define VERR_ASN1_INTERNAL_ERROR_4 (-22898) +/** ANS.1 internal error 5. */ +#define VERR_ASN1_INTERNAL_ERROR_5 (-22899) +/** @} */ + +/** @name More RTLdr status codes. + * @{ */ +/** Image Verification Failure: No Authenticode Signature. */ +#define VERR_LDRVI_NOT_SIGNED (-22900) +/** Image Verification Warning: No Authenticode Signature, but on whitelist. */ +#define VINF_LDRVI_NOT_SIGNED (22900) +/** Image Verification Failure: Error reading image headers. */ +#define VERR_LDRVI_READ_ERROR_HDR (-22901) +/** Image Verification Failure: Error reading section headers. */ +#define VERR_LDRVI_READ_ERROR_SHDRS (-22902) +/** Image Verification Failure: Error reading authenticode signature data. */ +#define VERR_LDRVI_READ_ERROR_SIGNATURE (-22903) +/** Image Verification Failure: Error reading file for hashing. */ +#define VERR_LDRVI_READ_ERROR_HASH (-22904) +/** Image Verification Failure: Error determining the file length. */ +#define VERR_LDRVI_FILE_LENGTH_ERROR (-22905) +/** Image Verification Failure: Error allocating memory for state data. */ +#define VERR_LDRVI_NO_MEMORY_STATE (-22906) +/** Image Verification Failure: Error allocating memory for authenticode + * signature data. */ +#define VERR_LDRVI_NO_MEMORY_SIGNATURE (-22907) +/** Image Verification Failure: Error allocating memory for section headers. */ +#define VERR_LDRVI_NO_MEMORY_SHDRS (-22908) +/** Image Verification Failure: Authenticode parsing output. */ +#define VERR_LDRVI_NO_MEMORY_PARSE_OUTPUT (-22909) +/** Image Verification Failure: Invalid security directory entry. */ +#define VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY (-22910) +/** Image Verification Failure: */ +#define VERR_LDRVI_BAD_CERT_HDR_LENGTH (-22911) +/** Image Verification Failure: */ +#define VERR_LDRVI_BAD_CERT_HDR_REVISION (-22912) +/** Image Verification Failure: */ +#define VERR_LDRVI_BAD_CERT_HDR_TYPE (-22913) +/** Image Verification Failure: More than one certificate table entry. */ +#define VERR_LDRVI_BAD_CERT_MULTIPLE (-22914) + +/** Image Verification Failure: */ +#define VERR_LDRVI_BAD_MZ_OFFSET (-22915) +/** Image Verification Failure: Invalid section count. */ +#define VERR_LDRVI_INVALID_SECTION_COUNT (-22916) +/** Image Verification Failure: Raw data offsets and sizes are out of range. */ +#define VERR_LDRVI_SECTION_RAW_DATA_VALUES (-22917) +/** Optional header magic and target machine does not match. */ +#define VERR_LDRVI_MACHINE_OPT_HDR_MAGIC_MISMATCH (-22918) +/** Unsupported image target architecture. */ +#define VERR_LDRVI_UNSUPPORTED_ARCH (-22919) + +/** Image Verification Failure: Internal error in signature parser. */ +#define VERR_LDRVI_PARSE_IPE (-22921) +/** Generic BER parse error. Will be refined later. */ +#define VERR_LDRVI_PARSE_BER_ERROR (-22922) + +/** Expected the signed data content to be the object ID of + * SpcIndirectDataContent, found something else instead. */ +#define VERR_LDRVI_EXPECTED_INDIRECT_DATA_CONTENT_OID (-22923) +/** Page hash table size overflow. */ +#define VERR_LDRVI_PAGE_HASH_TAB_SIZE_OVERFLOW (-22924) +/** Page hash table is too long (covers signature data, i.e. itself). */ +#define VERR_LDRVI_PAGE_HASH_TAB_TOO_LONG (-22925) +/** The page hash table is not strictly ordered by offset. */ +#define VERR_LDRVI_PAGE_HASH_TAB_NOT_STRICTLY_SORTED (-22926) +/** The page hash table hashes data outside the defined and implicit sections. */ +#define VERR_PAGE_HASH_TAB_HASHES_NON_SECTION_DATA (-22927) +/** Page hash mismatch. */ +#define VERR_LDRVI_PAGE_HASH_MISMATCH (-22928) +/** Image hash mismatch. */ +#define VERR_LDRVI_IMAGE_HASH_MISMATCH (-22929) +/** Malformed code signing structure. */ +#define VERR_LDRVI_BAD_CERT_FORMAT (-22930) + +/** Cannot resolve symbol because it's a forwarder. */ +#define VERR_LDR_FORWARDER (-22950) +/** The symbol is not a forwarder. */ +#define VERR_LDR_NOT_FORWARDER (-22951) +/** Malformed forwarder entry. */ +#define VERR_LDR_BAD_FORWARDER (-22952) +/** Too long forwarder chain or there is a loop. */ +#define VERR_LDR_FORWARDER_CHAIN_TOO_LONG (-22953) +/** Support for forwarders has not been implemented. */ +#define VERR_LDR_FORWARDERS_NOT_SUPPORTED (-22954) +/** Only native endian Mach-O files are supported. */ +#define VERR_LDRMACHO_OTHER_ENDIAN_NOT_SUPPORTED (-22955) +/** The Mach-O header is bad or contains new and unsupported features. */ +#define VERR_LDRMACHO_BAD_HEADER (-22956) +/** The file type isn't supported. */ +#define VERR_LDRMACHO_UNSUPPORTED_FILE_TYPE (-22957) +/** The machine (cputype / cpusubtype combination) isn't supported. */ +#define VERR_LDRMACHO_UNSUPPORTED_MACHINE (-22958) +/** Bad load command(s). */ +#define VERR_LDRMACHO_BAD_LOAD_COMMAND (-22959) +/** Encountered an unknown load command.*/ +#define VERR_LDRMACHO_UNKNOWN_LOAD_COMMAND (-22960) +/** Encountered a load command that's not implemented.*/ +#define VERR_LDRMACHO_UNSUPPORTED_LOAD_COMMAND (-22961) +/** Bad section. */ +#define VERR_LDRMACHO_BAD_SECTION (-22962) +/** Encountered a section type that's not implemented.*/ +#define VERR_LDRMACHO_UNSUPPORTED_SECTION (-22963) +/** Encountered a init function section. */ +#define VERR_LDRMACHO_UNSUPPORTED_INIT_SECTION (-22964) +/** Encountered a term function section. */ +#define VERR_LDRMACHO_UNSUPPORTED_TERM_SECTION (-22965) +/** Encountered a section type that's not known to the loader. (probably invalid) */ +#define VERR_LDRMACHO_UNKNOWN_SECTION (-22966) +/** The sections aren't ordered by segment as expected by the loader. */ +#define VERR_LDRMACHO_BAD_SECTION_ORDER (-22967) +/** The image is 32-bit and contains 64-bit load commands or vise versa. */ +#define VERR_LDRMACHO_BIT_MIX (-22968) +/** Bad MH_OBJECT file. */ +#define VERR_LDRMACHO_BAD_OBJECT_FILE (-22969) +/** Bad symbol table entry. */ +#define VERR_LDRMACHO_BAD_SYMBOL (-22970) +/** Unsupported fixup type. */ +#define VERR_LDRMACHO_UNSUPPORTED_FIXUP_TYPE (-22971) +/** Both debug and non-debug sections in segment. */ +#define VERR_LDRMACHO_MIXED_DEBUG_SECTION_FLAGS (-22972) +/** The segment bits are non-contiguous in the file. */ +#define VERR_LDRMACHO_NON_CONT_SEG_BITS (-22973) +/** Hit a todo in the mach-o loader. */ +#define VERR_LDRMACHO_TODO (-22974) +/** Bad symbol table size in Mach-O image. */ +#define VERR_LDRMACHO_BAD_SYMTAB_SIZE (-22975) +/** Duplicate segment name. */ +#define VERR_LDR_DUPLICATE_SEGMENT_NAME (-22976) +/** No image UUID. */ +#define VERR_LDR_NO_IMAGE_UUID (-22977) +/** Bad image relocation. */ +#define VERR_LDR_BAD_FIXUP (-22978) +/** Address overflow. */ +#define VERR_LDR_ADDRESS_OVERFLOW (-22979) +/** validation of LX header failed. */ +#define VERR_LDRLX_BAD_HEADER (-22980) +/** validation of the loader section (in the LX header) failed. */ +#define VERR_LDRLX_BAD_LOADER_SECTION (-22981) +/** validation of the fixup section (in the LX header) failed. */ +#define VERR_LDRLX_BAD_FIXUP_SECTION (-22982) +/** validation of the LX object table failed. */ +#define VERR_LDRLX_BAD_OBJECT_TABLE (-22983) +/** A bad page map entry was encountered. */ +#define VERR_LDRLX_BAD_PAGE_MAP (-22984) +/** Bad iterdata (EXEPACK) data. */ +#define VERR_LDRLX_BAD_ITERDATA (-22985) +/** Bad iterdata2 (EXEPACK2) data. */ +#define VERR_LDRLX_BAD_ITERDATA2 (-22986) +/** Bad bundle data. */ +#define VERR_LDRLX_BAD_BUNDLE (-22987) +/** No soname. */ +#define VERR_LDRLX_NO_SONAME (-22988) +/** Bad soname. */ +#define VERR_LDRLX_BAD_SONAME (-22989) +/** Bad forwarder entry. */ +#define VERR_LDRLX_BAD_FORWARDER (-22990) +/** internal fixup chain isn't implemented yet. */ +#define VERR_LDRLX_NRICHAIN_NOT_SUPPORTED (-22991) +/** Import module ordinal is out of bounds. */ +#define VERR_LDRLX_IMPORT_ORDINAL_OUT_OF_BOUNDS (-22992) +/** @} */ + +/** @name RTCrX509 status codes. + * @{ */ +/** Generic X.509 error. */ +#define VERR_CR_X509_GENERIC_ERROR (-23000) +/** Internal error in the X.509 code. */ +#define VERR_CR_X509_INTERNAL_ERROR (-23001) +/** Internal error in the X.509 certificate path building and verification + * code. */ +#define VERR_CR_X509_CERTPATHS_INTERNAL_ERROR (-23002) +/** Path not verified yet. */ +#define VERR_CR_X509_NOT_VERIFIED (-23003) +/** The certificate path has no trust anchor. */ +#define VERR_CR_X509_NO_TRUST_ANCHOR (-23004) +/** Unknown X.509 certificate signature algorithm. */ +#define VERR_CR_X509_UNKNOWN_CERT_SIGN_ALGO (-23005) +/** Certificate signature algorithm mismatch. */ +#define VERR_CR_X509_CERT_SIGN_ALGO_MISMATCH (-23006) +/** The signature algorithm in the to-be-signed certificate part does not match + * the one associated with the signature. */ +#define VERR_CR_X509_CERT_TBS_SIGN_ALGO_MISMATCH (-23007) +/** Certificate extensions requires certificate version 3 or later. */ +#define VERR_CR_X509_TBSCERT_EXTS_REQ_V3 (-23008) +/** Unique issuer and subject IDs require version certificate 2. */ +#define VERR_CR_X509_TBSCERT_UNIQUE_IDS_REQ_V2 (-23009) +/** Certificate serial number length is out of bounds. */ +#define VERR_CR_X509_TBSCERT_SERIAL_NUMBER_OUT_OF_BOUNDS (-23010) +/** Unsupported X.509 certificate version. */ +#define VERR_CR_X509_TBSCERT_UNSUPPORTED_VERSION (-23011) +/** Public key is too small. */ +#define VERR_CR_X509_PUBLIC_KEY_TOO_SMALL (-23012) +/** Invalid string tag for a X.509 name object. */ +#define VERR_CR_X509_INVALID_NAME_STRING_TAG (-23013) +/** Empty string in X.509 name object. */ +#define VERR_CR_X509_NAME_EMPTY_STRING (-23014) +/** Non-string object inside X.509 name object. */ +#define VERR_CR_X509_NAME_NOT_STRING (-23015) +/** Empty set inside X.509 name. */ +#define VERR_CR_X509_NAME_EMPTY_SET (-23016) +/** Empty sub-string set inside X.509 name. */ +#define VERR_CR_X509_NAME_EMPTY_SUB_SET (-23017) +/** The NotBefore and NotAfter values of an X.509 Validity object seems to + * have been swapped around. */ +#define VERR_CR_X509_VALIDITY_SWAPPED (-23018) +/** Duplicate certificate extension. */ +#define VERR_CR_X509_TBSCERT_DUPLICATE_EXTENSION (-23019) +/** Missing relative distinguished name map entry. */ +#define VERR_CR_X509_NAME_MISSING_RDN_MAP_ENTRY (-23020) +/** Certificate path validator: No trusted certificate paths. */ +#define VERR_CR_X509_CPV_NO_TRUSTED_PATHS (-23021) +/** Certificate path validator: No valid certificate policy. */ +#define VERR_CR_X509_CPV_NO_VALID_POLICY (-23022) +/** Certificate path validator: Unknown critical certificate extension. */ +#define VERR_CR_X509_CPV_UNKNOWN_CRITICAL_EXTENSION (-23023) +/** Certificate path validator: Intermediate certificate is missing the + * KeyCertSign usage flag. */ +#define VERR_CR_X509_CPV_MISSING_KEY_CERT_SIGN (-23024) +/** Certificate path validator: Hit the max certificate path length before + * reaching trust anchor. */ +#define VERR_CR_X509_CPV_MAX_PATH_LENGTH (-23025) +/** Certificate path validator: Intermediate certificate is not marked as a + * certificate authority (CA). */ +#define VERR_CR_X509_CPV_NOT_CA_CERT (-23026) +/** Certificate path validator: Intermediate certificate is not a version 3 + * certificate. */ +#define VERR_CR_X509_CPV_NOT_V3_CERT (-23027) +/** Certificate path validator: Invalid policy mapping (to/from anyPolicy). */ +#define VERR_CR_X509_CPV_INVALID_POLICY_MAPPING (-23028) +/** Certificate path validator: Name constraints permits no names. */ +#define VERR_CR_X509_CPV_NO_PERMITTED_NAMES (-23029) +/** Certificate path validator: Name constraints does not permits the + * certificate name. */ +#define VERR_CR_X509_CPV_NAME_NOT_PERMITTED (-23030) +/** Certificate path validator: Name constraints does not permits the + * alternative certificate name. */ +#define VERR_CR_X509_CPV_ALT_NAME_NOT_PERMITTED (-23031) +/** Certificate path validator: Intermediate certificate subject does not + * match child issuer property. */ +#define VERR_CR_X509_CPV_ISSUER_MISMATCH (-23032) +/** Certificate path validator: The certificate is not valid at the + * specified time. */ +#define VERR_CR_X509_CPV_NOT_VALID_AT_TIME (-23033) +/** Certificate path validator: Unexpected choice found in general subtree + * object (name constraints). */ +#define VERR_CR_X509_CPV_UNEXP_GENERAL_SUBTREE_CHOICE (-23034) +/** Certificate path validator: Unexpected minimum value found in general + * subtree object (name constraints). */ +#define VERR_CR_X509_CPV_UNEXP_GENERAL_SUBTREE_MIN (-23035) +/** Certificate path validator: Unexpected maximum value found in + * general subtree object (name constraints). */ +#define VERR_CR_X509_CPV_UNEXP_GENERAL_SUBTREE_MAX (-23036) +/** Certificate path builder: Encountered bad certificate context. */ +#define VERR_CR_X509_CPB_BAD_CERT_CTX (-23037) +/** OpenSSL d2i_X509 failed. */ +#define VERR_CR_X509_OSSL_D2I_FAILED (-23090) +/** @} */ + +/** @name RTCrPkcs7 status codes. + * @{ */ +/** Generic PKCS \#7 error. */ +#define VERR_CR_PKCS7_GENERIC_ERROR (-23300) +/** Signed data verification failed because there are zero signer infos. */ +#define VERR_CR_PKCS7_NO_SIGNER_INFOS (-23301) +/** Signed data certificate not found. */ +#define VERR_CR_PKCS7_SIGNED_DATA_CERT_NOT_FOUND (-23302) +/** Signed data verification failed due to key usage issues. */ +#define VERR_CR_PKCS7_KEY_USAGE_MISMATCH (-23303) +/** Signed data verification failed because of missing (or duplicate) + * authenticated content-type attribute. */ +#define VERR_CR_PKCS7_MISSING_CONTENT_TYPE_ATTRIB (-23304) +/** Signed data verification failed because of the authenticated content-type + * attribute did not match. */ +#define VERR_CR_PKCS7_CONTENT_TYPE_ATTRIB_MISMATCH (-23305) +/** Signed data verification failed because of a malformed authenticated + * content-type attribute. */ +#define VERR_CR_PKCS7_BAD_CONTENT_TYPE_ATTRIB (-23306) +/** Signed data verification failed because of missing (or duplicate) + * authenticated message-digest attribute. */ +#define VERR_CR_PKCS7_MISSING_MESSAGE_DIGEST_ATTRIB (-23307) +/** Signed data verification failed because the authenticated message-digest + * attribute did not match. */ +#define VERR_CR_PKCS7_MESSAGE_DIGEST_ATTRIB_MISMATCH (-23308) +/** Signed data verification failed because of a malformed authenticated + * message-digest attribute. */ +#define VERR_CR_PKCS7_BAD_MESSAGE_DIGEST_ATTRIB (-23309) +/** Signature verification failed. */ +#define VERR_CR_PKCS7_SIGNATURE_VERIFICATION_FAILED (-23310) +/** Internal PKCS \#7 error. */ +#define VERR_CR_PKCS7_INTERNAL_ERROR (-22311) +/** OpenSSL d2i_PKCS7 failed. */ +#define VERR_CR_PKCS7_OSSL_D2I_FAILED (-22312) +/** OpenSSL PKCS \#7 verification failed. */ +#define VERR_CR_PKCS7_OSSL_VERIFY_FAILED (-22313) +/** Digest algorithm parameters are not supported by the PKCS \#7 code. */ +#define VERR_CR_PKCS7_DIGEST_PARAMS_NOT_IMPL (-22314) +/** The digest algorithm of a signer info entry was not found in the list of + * digest algorithms in the signed data. */ +#define VERR_CR_PKCS7_DIGEST_ALGO_NOT_FOUND_IN_LIST (-22315) +/** The PKCS \#7 content is not signed data. */ +#define VERR_CR_PKCS7_NOT_SIGNED_DATA (-22316) +/** No digest algorithms listed in PKCS \#7 signed data. */ +#define VERR_CR_PKCS7_NO_DIGEST_ALGORITHMS (-22317) +/** Too many digest algorithms used by PKCS \#7 signed data. This is an + * internal limitation of the code that aims at saving kernel stack space. */ +#define VERR_CR_PKCS7_TOO_MANY_DIGEST_ALGORITHMS (-22318) +/** Error creating digest algorithm calculator. */ +#define VERR_CR_PKCS7_DIGEST_CREATE_ERROR (-22319) +/** Error while calculating a digest for a PKCS \#7 verification operation. */ +#define VERR_CR_PKCS7_DIGEST_CALC_ERROR (-22320) +/** Unsupported PKCS \#7 signed data version. */ +#define VERR_CR_PKCS7_SIGNED_DATA_VERSION (-22350) +/** PKCS \#7 signed data has no digest algorithms listed. */ +#define VERR_CR_PKCS7_SIGNED_DATA_NO_DIGEST_ALGOS (-22351) +/** Unknown digest algorithm used by PKCS \#7 object. */ +#define VERR_CR_PKCS7_UNKNOWN_DIGEST_ALGORITHM (-22352) +/** Expected PKCS \#7 object to ship at least one certificate. */ +#define VERR_CR_PKCS7_NO_CERTIFICATES (-22353) +/** Expected PKCS \#7 object to not contain any CRLs. */ +#define VERR_CR_PKCS7_EXPECTED_NO_CRLS (-22354) +/** Expected PKCS \#7 object to contain exactly on signer info entry. */ +#define VERR_CR_PKCS7_EXPECTED_ONE_SIGNER_INFO (-22355) +/** Unsupported PKCS \#7 signer info version. */ +#define VERR_CR_PKCS7_SIGNER_INFO_VERSION (-22356) +/** PKCS \#7 singer info contains no issuer serial number. */ +#define VERR_CR_PKCS7_SIGNER_INFO_NO_ISSUER_SERIAL_NO (-22357) +/** Expected PKCS \#7 object to ship the signer certificate(s). */ +#define VERR_CR_PKCS7_SIGNER_CERT_NOT_SHIPPED (-22358) +/** The encrypted digest algorithm does not match the one in the certificate. */ +#define VERR_CR_PKCS7_SIGNER_INFO_DIGEST_ENCRYPT_MISMATCH (-22359) +/** The PKCS \#7 content is not data. */ +#define VERR_CR_PKCS7_NOT_DATA (-22360) +/** @} */ + +/** @name RTCrSpc status codes. + * @{ */ +/** Generic SPC error. */ +#define VERR_CR_SPC_GENERIC_ERROR (-23400) +/** SPC requires there to be exactly one SignerInfo entry. */ +#define VERR_CR_SPC_NOT_EXACTLY_ONE_SIGNER_INFOS (-23401) +/** There shall be exactly one digest algorithm to go with the single + * SingerInfo entry required by SPC. */ +#define VERR_CR_SPC_NOT_EXACTLY_ONE_DIGEST_ALGO (-23402) +/** The digest algorithm in the SignerInfo does not match the one in the + * indirect data. */ +#define VERR_CR_SPC_SIGNED_IND_DATA_DIGEST_ALGO_MISMATCH (-23403) +/** The digest algorithm in the indirect data was not found in the list of + * digest algorithms in the signed data structure. */ +#define VERR_CR_SPC_IND_DATA_DIGEST_ALGO_NOT_IN_DIGEST_ALGOS (-23404) +/** The digest algorithm is not known to us. */ +#define VERR_CR_SPC_UNKNOWN_DIGEST_ALGO (-23405) +/** The indirect data digest size does not match the digest algorithm. */ +#define VERR_CR_SPC_IND_DATA_DIGEST_SIZE_MISMATCH (-23406) +/** Expected PE image data inside indirect data object. */ +#define VERR_CR_SPC_EXPECTED_PE_IMAGE_DATA (-23407) +/** Internal SPC error: The PE image data is missing. */ +#define VERR_CR_SPC_PEIMAGE_DATA_NOT_PRESENT (-23408) +/** Bad SPC object moniker UUID field. */ +#define VERR_CR_SPC_BAD_MONIKER_UUID (-23409) +/** Unknown SPC object moniker UUID. */ +#define VERR_CR_SPC_UNKNOWN_MONIKER_UUID (-23410) +/** Internal SPC error: Bad object moniker choice value. */ +#define VERR_CR_SPC_BAD_MONIKER_CHOICE (-23411) +/** Internal SPC error: Bad object moniker data pointer. */ +#define VERR_CR_SPC_MONIKER_BAD_DATA (-23412) +/** Multiple PE image page hash tables. */ +#define VERR_CR_SPC_PEIMAGE_MULTIPLE_HASH_TABS (-23413) +/** Unknown SPC PE image attribute. */ +#define VERR_CR_SPC_PEIMAGE_UNKNOWN_ATTRIBUTE (-23414) +/** URL not expected in SPC PE image data. */ +#define VERR_CR_SPC_PEIMAGE_URL_UNEXPECTED (-23415) +/** PE image data without any valid content was not expected. */ +#define VERR_CR_SPC_PEIMAGE_NO_CONTENT (-23416) +/** @} */ + +/** @name RTCrPkix status codes. + * @{ */ +/** Generic PKCS \#7 error. */ +#define VERR_CR_PKIX_GENERIC_ERROR (-23500) +/** Parameters was presented to a signature schema that does not take any. */ +#define VERR_CR_PKIX_SIGNATURE_TAKES_NO_PARAMETERS (-23501) +/** Unknown hash digest type. */ +#define VERR_CR_PKIX_UNKNOWN_DIGEST_TYPE (-23502) +/** Internal error. */ +#define VERR_CR_PKIX_INTERNAL_ERROR (-23503) +/** The hash is too long for the key used when signing/verifying. */ +#define VERR_CR_PKIX_HASH_TOO_LONG_FOR_KEY (-23504) +/** The signature is too long for the scratch buffer. */ +#define VERR_CR_PKIX_SIGNATURE_TOO_LONG (-23505) +/** The signature is greater than or equal to the key. */ +#define VERR_CR_PKIX_SIGNATURE_GE_KEY (-23506) +/** The signature is negative. */ +#define VERR_CR_PKIX_SIGNATURE_NEGATIVE (-23507) +/** Invalid signature length. */ +#define VERR_CR_PKIX_INVALID_SIGNATURE_LENGTH (-23508) +/** PKIX signature no does not match up to the current data. */ +#define VERR_CR_PKIX_SIGNATURE_MISMATCH (-23509) +/** PKIX cipher algorithm parameters are not implemented. */ +#define VERR_CR_PKIX_CIPHER_ALGO_PARAMS_NOT_IMPL (-23510) +/** Cipher algorithm is not known to us. */ +#define VERR_CR_PKIX_CIPHER_ALGO_NOT_KNOWN (-23511) +/** PKIX cipher algorithm is not known to OpenSSL. */ +#define VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN (-23512) +/** PKIX cipher algorithm is not known to OpenSSL EVP API. */ +#define VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN_EVP (-23513) +/** OpenSSL failed to init PKIX cipher algorithm context. */ +#define VERR_CR_PKIX_OSSL_CIPHER_ALOG_INIT_FAILED (-23514) +/** Final OpenSSL PKIX verification failed. */ +#define VERR_CR_PKIX_OSSL_VERIFY_FINAL_FAILED (-23515) +/** OpenSSL failed to decode the public key. */ +#define VERR_CR_PKIX_OSSL_D2I_PUBLIC_KEY_FAILED (-23516) +/** The EVP_PKEY_type API in OpenSSL failed. */ +#define VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR (-23517) +/** OpenSSL failed to decode the public key. */ +#define VERR_CR_PKIX_OSSL_D2I_PRIVATE_KEY_FAILED (-23518) +/** The EVP_PKEY_CTX_set_rsa_padding API in OpenSSL failed. */ +#define VERR_CR_PKIX_OSSL_EVP_PKEY_RSA_PAD_ERROR (-23519) +/** Final OpenSSL PKIX signing failed. */ +#define VERR_CR_PKIX_OSSL_SIGN_FINAL_FAILED (-23520) +/** OpenSSL and IPRT disagree on the signature size. */ +#define VERR_CR_PKIX_OSSL_VS_IPRT_SIGNATURE_SIZE (-23521) +/** OpenSSL and IPRT disagree on the signature. */ +#define VERR_CR_PKIX_OSSL_VS_IPRT_SIGNATURE (-23522) +/** Expected RSA private key. */ +#define VERR_CR_PKIX_NOT_RSA_PRIVATE_KEY (-23523) +/** Expected RSA public key. */ +#define VERR_CR_PKIX_NOT_RSA_PUBLIC_KEY (-23524) +/** @} */ + +/** @name RTCrStore status codes. + * @{ */ +/** Generic store error. */ +#define VERR_CR_STORE_GENERIC_ERROR (-23700) +/** @} */ + +/** @name RTCrKey status codes. + * @{ */ +/** Could not recognize the key type. */ +#define VERR_CR_KEY_UNKNOWN_TYPE (-23800) +/** Unsupported key format. */ +#define VERR_CR_KEY_FORMAT_NOT_SUPPORTED (-23801) +/** Key encrypted but no password was given. */ +#define VERR_CR_KEY_ENCRYPTED (-23802) +/** The key was marked as encrypted by no DEK-Info field with the encryption + * algortihms was found. */ +#define VERR_CR_KEY_NO_DEK_INFO (-23803) +/** The algorithms part of the DEK-Info field is too long. */ +#define VERR_CR_KEY_DEK_INFO_TOO_LONG (-23804) +/** Key decryption is not supported. */ +#define VERR_CR_KEY_DECRYPTION_NOT_SUPPORTED (-23805) +/** Unsupported key encryption cipher. */ +#define VERR_CR_KEY_UNSUPPORTED_CIPHER (-23806) +/** Found unexpected cipher parameters for encrypted key. */ +#define VERR_CR_KEY_UNEXPECTED_CIPHER_PARAMS (-23807) +/** Missing ciper parameters for encrypted key. */ +#define VERR_CR_KEY_MISSING_CIPHER_PARAMS (-23808) +/** To short initialization vector for encrypted key ciper. */ +#define VERR_CR_KEY_TOO_SHORT_CIPHER_IV (-23809) +/** Malformed initialization vector for encrypted key ciper. */ +#define VERR_CR_KEY_MALFORMED_CIPHER_IV (-23810) +/** Error encoding the password for key decryption. */ +#define VERR_CR_KEY_PASSWORD_ENCODING (-23811) +/** EVP_DecryptInit_ex failed. */ +#define VERR_CR_KEY_OSSL_DECRYPT_INIT_ERROR (-23812) +/** Key decryption failed, perhaps due to an incorrect password. */ +#define VERR_CR_KEY_DECRYPTION_FAILED (-23813) +/** The key was decrypted. */ +#define VINF_CR_KEY_WAS_DECRYPTED (23814) +/** Failed to generate RSA key. */ +#define VERR_CR_KEY_GEN_FAILED_RSA (-23815) +/** @} */ + +/** @name RTCrRsa status codes. + * @{ */ +/** Generic RSA error. */ +#define VERR_CR_RSA_GENERIC_ERROR (-23900) +/** @} */ + +/** @name RTBigNum status codes. + * @{ */ +/** Sensitive input requires the result(s) to be initialized as sensitive. */ +#define VERR_BIGNUM_SENSITIVE_INPUT (-24000) +/** Attempt to divide by zero. */ +#define VERR_BIGNUM_DIV_BY_ZERO (-24001) +/** Negative exponent makes no sense to integer math. */ +#define VERR_BIGNUM_NEGATIVE_EXPONENT (-24002) +/** @} */ + +/** @name RTCrDigest status codes. + * @{ */ +/** OpenSSL failed to initialize the digest algorithm context. */ +#define VERR_CR_DIGEST_OSSL_DIGEST_INIT_ERROR (-24200) +/** OpenSSL failed to clone the digest algorithm context. */ +#define VERR_CR_DIGEST_OSSL_DIGEST_CTX_COPY_ERROR (-24201) +/** Deprecated digest. */ +#define VINF_CR_DIGEST_DEPRECATED (24202) +/** Deprecated digest. */ +#define VERR_CR_DIGEST_DEPRECATED (-24202) +/** Compromised digest. */ +#define VINF_CR_DIGEST_COMPROMISED (24203) +/** Compromised digest. */ +#define VERR_CR_DIGEST_COMPROMISED (-24203) +/** Severely compromised digest. */ +#define VINF_CR_DIGEST_SEVERELY_COMPROMISED (24204) +/** Severely compromised digest. */ +#define VERR_CR_DIGEST_SEVERELY_COMPROMISED (-24204) +/** Specified digest not supported in this context. */ +#define VERR_CR_DIGEST_NOT_SUPPORTED (-24205) +/** @} */ + +/** @name RTCr misc status codes. + * @{ */ +/** Failed to derivate key from password. */ +#define VERR_CR_PASSWORD_2_KEY_DERIVIATION_FAILED (-24396) +/** Failed getting cryptographically strong random bytes. */ +#define VERR_CR_RANDOM_SETUP_FAILED (-24397) +/** Failed getting cryptographically strong random bytes. */ +#define VERR_CR_RANDOM_FAILED (-24398) +/** Malformed or failed to parse PEM formatted data. */ +#define VERR_CR_MALFORMED_PEM_HEADER (-24399) +/** @} */ + +/** @name RTPath status codes. + * @{ */ +/** Unknown glob variable. */ +#define VERR_PATH_MATCH_UNKNOWN_VARIABLE (-24400) +/** The specified glob variable must be first in the pattern. */ +#define VERR_PATH_MATCH_VARIABLE_MUST_BE_FIRST (-24401) +/** Hit unimplemented glob pattern matching feature. */ +#define VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED (-24402) +/** Unknown character class in glob pattern. */ +#define VERR_PATH_GLOB_UNKNOWN_CHAR_CLASS (-24403) +/** @} */ + +/** @name RTUri status codes. + * @{ */ +/** The URI is empty */ +#define VERR_URI_EMPTY (-24600) +/** The URI is too short to be a valid URI. */ +#define VERR_URI_TOO_SHORT (-24601) +/** Invalid scheme. */ +#define VERR_URI_INVALID_SCHEME (-24602) +/** Invalid port number. */ +#define VERR_URI_INVALID_PORT_NUMBER (-24603) +/** Invalid escape sequence. */ +#define VERR_URI_INVALID_ESCAPE_SEQ (-24604) +/** Escape URI char decodes as zero (the C string terminator). */ +#define VERR_URI_ESCAPED_ZERO (-24605) +/** Escaped URI characters does not decode to valid UTF-8. */ +#define VERR_URI_ESCAPED_CHARS_NOT_VALID_UTF8 (-24606) +/** Escaped URI character is not a valid UTF-8 lead byte. */ +#define VERR_URI_INVALID_ESCAPED_UTF8_LEAD_BYTE (-24607) +/** Escaped URI character sequence with invalid UTF-8 continutation byte. */ +#define VERR_URI_INVALID_ESCAPED_UTF8_CONTINUATION_BYTE (-24608) +/** Missing UTF-8 continutation in escaped URI character sequence. */ +#define VERR_URI_MISSING_UTF8_CONTINUATION_BYTE (-24609) +/** Expected URI using the 'file:' scheme. */ +#define VERR_URI_NOT_FILE_SCHEME (-24610) +/** @} */ + +/** @name RTJson status codes. + * @{ */ +/** The called method does not work with the value type of the given JSON value. */ +#define VERR_JSON_VALUE_INVALID_TYPE (-24700) +/** The iterator reached the end. */ +#define VERR_JSON_ITERATOR_END (-24701) +/** The JSON document is malformed. */ +#define VERR_JSON_MALFORMED (-24702) +/** Object or array is empty. */ +#define VERR_JSON_IS_EMPTY (-24703) +/** Invalid UTF-16 escape sequence. */ +#define VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE (-24704) +/** Missing UTF-16 surrogate pair. */ +#define VERR_JSON_MISSING_SURROGATE_PAIR (-24705) +/** Bad UTF-16 surrogate pair sequence. */ +#define VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE (-24706) +/** Invalid codepoint. */ +#define VERR_JSON_INVALID_CODEPOINT (-24707) +/** @} */ + +/** @name RTVfs status codes. + * @{ */ +/** Unknown file system format. */ +#define VERR_VFS_UNKNOWN_FORMAT (-24800) +/** Found bogus values in the file system. */ +#define VERR_VFS_BOGUS_FORMAT (-24801) +/** Found bogus offset in the file system. */ +#define VERR_VFS_BOGUS_OFFSET (-24802) +/** Unsupported file system format. */ +#define VERR_VFS_UNSUPPORTED_FORMAT (-24803) +/** Unsupported create type in an RTVfsObjOpen or RTVfsDirOpenObj call. */ +#define VERR_VFS_UNSUPPORTED_CREATE_TYPE (-24804) +/** @} */ + +/** @name RTFsIsoMaker status codes. + * @{ */ +/** No validation entry in the boot catalog. */ +#define VERR_ISOMK_BOOT_CAT_NO_VALIDATION_ENTRY (-25000) +/** No default entry in the boot catalog. */ +#define VERR_ISOMK_BOOT_CAT_NO_DEFAULT_ENTRY (-25001) +/** Expected section header. */ +#define VERR_ISOMK_BOOT_CAT_EXPECTED_SECTION_HEADER (-25002) +/** Entry in a boot catalog section is empty. */ +#define VERR_ISOMK_BOOT_CAT_EMPTY_ENTRY (-25003) +/** Entry in a boot catalog section is another section. */ +#define VERR_ISOMK_BOOT_CAT_INVALID_SECTION_SIZE (-25004) +/** Unsectioned boot catalog entry. */ +#define VERR_ISOMK_BOOT_CAT_ERRATIC_ENTRY (-25005) +/** The file is too big for the current ISO level (4GB+ sized files + * requires ISO level 3). */ +#define VERR_ISOMK_FILE_TOO_BIG_REQ_ISO_LEVEL_3 (-25006) +/** Cannot add symbolic link to namespace which isn't configured to support it. */ +#define VERR_ISOMK_SYMLINK_REQ_ROCK_RIDGE (-25007) +/** Cannot add symbolic link to one of the selected namespaces. */ +#define VINF_ISOMK_SYMLINK_REQ_ROCK_RIDGE (25007) +/** Cannot add symbolic link because no namespace is configured to support it. */ +#define VERR_ISOMK_SYMLINK_SUPPORT_DISABLED (-25008) +/** No space for rock ridge 'CE' entry in directory record. */ +#define VERR_ISOMK_RR_NO_SPACE_FOR_CE (-25009) +/** Internal ISO maker error: Rock ridge read problem. */ +#define VERR_ISOMK_IPE_RR_READ (-25010) +/** Internal ISO maker error: Buggy namespace table. */ +#define VERR_ISOMK_IPE_TABLE (-25011) +/** Internal ISO maker error: Namespace problem \#1. */ +#define VERR_ISOMK_IPE_NAMESPACE_1 (-25012) +/** Internal ISO maker error: Namespace problem \#2. */ +#define VERR_ISOMK_IPE_NAMESPACE_2 (-25013) +/** Internal ISO maker error: Namespace problem \#3. */ +#define VERR_ISOMK_IPE_NAMESPACE_3 (-25014) +/** Internal ISO maker error: Namespace problem \#4. */ +#define VERR_ISOMK_IPE_NAMESPACE_4 (-25015) +/** Internal ISO maker error: Namespace problem \#5. */ +#define VERR_ISOMK_IPE_NAMESPACE_5 (-25016) +/** Internal ISO maker error: Namespace problem \#6. */ +#define VERR_ISOMK_IPE_NAMESPACE_6 (-25017) +/** Internal ISO maker error: Empty path. */ +#define VERR_ISOMK_IPE_EMPTY_PATH (-25018) +/** Internal ISO maker error: Unexpected empty component. */ +#define VERR_ISOMK_IPE_EMPTY_COMPONENT (-25019) +/** Internal ISO maker error: Expected path to start with root slash. */ +#define VERR_ISOMK_IPE_ROOT_SLASH (-25020) +/** Internal ISO maker error: Descriptor miscounting. */ +#define VERR_ISOMK_IPE_DESC_COUNT (-25021) +/** Internal ISO maker error: Buffer size. */ +#define VERR_ISOMK_IPE_BUFFER_SIZE (-25022) +/** Internal ISO maker error: Boot catalog file handle problem. */ +#define VERR_ISOMK_IPE_BOOT_CAT_FILE (-25023) +/** Internal ISO maker error: Inconsistency produing trans.tbl file. */ +#define VERR_ISOMK_IPE_PRODUCE_TRANS_TBL (-25024) +/** Internal ISO maker error: Read file data probem \#1. */ +#define VERR_ISOMK_IPE_READ_FILE_DATA_1 (-25025) +/** Internal ISO maker error: Read file data probem \#2. */ +#define VERR_ISOMK_IPE_READ_FILE_DATA_2 (-25026) +/** Internal ISO maker error: Read file data probem \#3. */ +#define VERR_ISOMK_IPE_READ_FILE_DATA_3 (-25027) +/** Internal ISO maker error: Finalization problem \#1. */ +#define VERR_ISOMK_IPE_FINALIZE_1 (-25028) +/** The spill file grew larger than 4GB. */ +#define VERR_ISOMK_RR_SPILL_FILE_FULL (-25029) + +/** Requested to import an unknown ISO format. */ +#define VERR_ISOMK_IMPORT_UNKNOWN_FORMAT (-25100) +/** Too many volume descriptors in the import ISO. */ +#define VERR_ISOMK_IMPORT_TOO_MANY_VOL_DESCS (-25101) +/** Import ISO contains a bad volume descriptor header. */ +#define VERR_ISOMK_IMPORT_INVALID_VOL_DESC_HDR (-25102) +/** Import ISO contains more than one primary volume descriptor. */ +#define VERR_ISOMK_IMPORT_MULTIPLE_PRIMARY_VOL_DESCS (-25103) +/** Import ISO contains more than one el torito descriptor. */ +#define VERR_ISOMK_IMPORT_MULTIPLE_EL_TORITO_DESCS (-25104) +/** Import ISO contains more than one joliet volume descriptor. */ +#define VERR_ISOMK_IMPORT_MULTIPLE_JOLIET_VOL_DESCS (-25105) +/** Import ISO starts with supplementary volume descriptor before any + * primary ones. */ +#define VERR_ISOMK_IMPORT_SUPPLEMENTARY_BEFORE_PRIMARY (-25106) +/** Import ISO contains an unsupported primary volume descriptor version. */ +#define VERR_IOSMK_IMPORT_PRIMARY_VOL_DESC_VER (-25107) +/** Import ISO contains a bad primary volume descriptor. */ +#define VERR_ISOMK_IMPORT_BAD_PRIMARY_VOL_DESC (-25108) +/** Import ISO contains an unsupported supplementary volume descriptor + * version. */ +#define VERR_IOSMK_IMPORT_SUP_VOL_DESC_VER (-25109) +/** Import ISO contains a bad supplementary volume descriptor. */ +#define VERR_ISOMK_IMPORT_BAD_SUP_VOL_DESC (-25110) +/** Import ISO uses a logical block size other than 2KB. */ +#define VERR_ISOMK_IMPORT_LOGICAL_BLOCK_SIZE_NOT_2KB (-25111) +/** Import ISO contains more than volume. */ +#define VERR_ISOMK_IMPORT_MORE_THAN_ONE_VOLUME_IN_SET (-25112) +/** Import ISO uses invalid volume sequence number. */ +#define VERR_ISOMK_IMPORT_INVALID_VOLUMNE_SEQ_NO (-25113) +/** Import ISO has different volume space sizes of primary and supplementary + * volume descriptors. */ +#define VERR_ISOMK_IMPORT_VOLUME_SPACE_SIZE_MISMATCH (-25114) +/** Import ISO has different volume set sizes of primary and supplementary + * volume descriptors. */ +#define VERR_ISOMK_IMPORT_VOLUME_IN_SET_MISMATCH (-25115) +/** Import ISO contains a bad root directory record. */ +#define VERR_ISOMK_IMPORT_BAD_ROOT_DIR_REC (-25116) +/** Import ISO contains a zero sized root directory. */ +#define VERR_ISOMK_IMPORT_ZERO_SIZED_ROOT_DIR (-25117) +/** Import ISO contains a root directory with a mismatching volume sequence + * number. */ +#define VERR_ISOMK_IMPORT_ROOT_VOLUME_SEQ_NO (-25118) +/** Import ISO contains a root directory with an out of bounds data extent. */ +#define VERR_ISOMK_IMPORT_ROOT_DIR_EXTENT_OUT_OF_BOUNDS (-25119) +/** Import ISO contains a root directory with a bad record length. */ +#define VERR_ISOMK_IMPORT_BAD_ROOT_DIR_REC_LENGTH (-25120) +/** Import ISO contains a root directory without the directory flag set. */ +#define VERR_ISOMK_IMPORT_ROOT_DIR_WITHOUT_DIR_FLAG (-25121) +/** Import ISO contains a root directory with multiple extents. */ +#define VERR_ISOMK_IMPORT_ROOT_DIR_IS_MULTI_EXTENT (-25122) +/** Import ISO contains a too deep directory subtree. */ +#define VERR_ISOMK_IMPORT_TOO_DEEP_DIR_TREE (-25123) +/** Import ISO contains a bad directory record. */ +#define VERR_ISOMK_IMPORT_BAD_DIR_REC (-25124) +/** Import ISO contains a directory record with a mismatching volume sequence + * number. */ +#define VERR_ISOMK_IMPORT_DIR_REC_VOLUME_SEQ_NO (-25125) +/** Import ISO contains a directory with an extent that is out of bounds. */ +#define VERR_ISOMK_IMPORT_DIR_REC_EXTENT_OUT_OF_BOUNDS (-25126) +/** Import ISO contains a directory with a bad record length. */ +#define VERR_ISOMK_IMPORT_BAD_DIR_REC_LENGTH (-25127) +/** Import ISO contains a '.' or '..' directory record with a bad name + * length. */ +#define VERR_ISOMK_IMPORT_DOT_DIR_REC_BAD_NAME_LENGTH (-25128) +/** Import ISO contains a '.' or '..' directory record with a bad name. */ +#define VERR_ISOMK_IMPORT_DOT_DIR_REC_BAD_NAME (-25129) +/** Import ISO contains a directory with a more than one extent, that's + * currently not supported. */ +#define VERR_ISOMK_IMPORT_DIR_WITH_MORE_EXTENTS (-25130) +/** Import ISO contains a multi-extent directory record that differs + * significantly from first record. */ +#define VERR_ISOMK_IMPORT_MISMATCHING_MULTI_EXTENT_REC (-25131) +/** Import ISO contains a non-final multi-extent directory record with a + * size that isn't block aligned. */ +#define VERR_ISOMK_IMPORT_MISALIGNED_MULTI_EXTENT (-25132) +/** Import ISO contains a non-contigiuous multi-extent data, this is + * currently not supported. */ +#define VERR_ISOMK_IMPORT_NON_CONTIGUOUS_MULTI_EXTENT (-25133) + +/** The boot catalog block in the import ISO is out of bounds. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_BAD_OUT_OF_BOUNDS (-25140) +/** The boot catalog block in the import ISO has an incorrect validation + * header ID. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_BAD_VALIDATION_HEADER_ID (-25141) +/** The boot catalog validation entry in the import ISO has incorrect keys. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_BAD_VALIDATION_KEYS (-25142) +/** The boot catalog validation entry in the import ISO has an incorrect checksum. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_BAD_VALIDATION_CHECKSUM (-25143) +/** A boot catalog entry in the import ISO has an unknown type. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_UNKNOWN_HEADER_ID (-25144) +/** A boot catalog entry in the import ISO has an invalid boot media type. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_INVALID_BOOT_MEDIA_TYPE (-25145) +/** The default boot catalog entry in the import ISO has invalid flags set. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_DEF_ENTRY_INVALID_FLAGS (-25146) +/** A boot catalog entry in the import ISO has reserved flag set. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_RESERVED_FLAG (-25147) +/** A boot catalog entry in the import ISO is using the unused field. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_USES_UNUSED_FIELD (-25148) +/** A boot catalog entry in the import ISO points to a block after the end of + * the image input file. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_IMAGE_OUT_OF_BOUNDS (-25149) +/** A boot catalog entry in the import ISO has an image with an + * indeterminate size. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_UNKNOWN_IMAGE_SIZE (-25150) +/** The boot catalog in the import ISO is larger than a sector or it is + * missing the final section header entry. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_MISSING_FINAL_OR_TOO_BIG (-25151) +/** The default boot catalog entry in the import ISO an invalid boot + * indicator value. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_DEF_ENTRY_INVALID_BOOT_IND (-25152) +/** A boot catalog extension entry in the import ISO was either flagged + * incorrectly in the previous entry or has an invalid header ID. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_EXT_ENTRY_INVALID_ID (-25153) +/** A boot catalog extension entry in the import ISO uses undefined flags + * which will be lost. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_EXT_ENTRY_UNDEFINED_FLAGS (-25154) +/** A boot catalog extension entry in the import ISO indicates more entries when + * we reached the end of the boot catalog sector. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_EXT_ENTRY_END_OF_SECTOR (-25155) +/** A boot catalog entry in the import ISO sets the continuation flag when using + * NONE as the selection criteria type. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_CONTINUATION_WITH_NONE (-25156) +/** A boot catalog entry in the import ISO sets the continuation flag when + * we reached the ned of the boot catalog secotr. */ +#define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_CONTINUATION_EOS (-25157) +/** @} */ + + +/** @name RTFsIsoVol status codes + * @{ */ +/** Descriptor tag is all zeros. */ +#define VERR_ISOFS_TAG_IS_ALL_ZEROS (-25300) +/** Unsupported descriptor tag version. */ +#define VERR_ISOFS_UNSUPPORTED_TAG_VERSION (-25301) +/** Bad descriptor tag checksum. */ +#define VERR_ISOFS_BAD_TAG_CHECKSUM (-25302) +/** Descriptor tag sector number mismatch. */ +#define VERR_ISOFS_TAG_SECTOR_MISMATCH (-25303) +/** Descriptor CRC mismatch. */ +#define VERR_ISOFS_DESC_CRC_MISMATCH (-25304) +/** Insufficient data to check descriptor CRC. */ +#define VERR_ISOFS_INSUFFICIENT_DATA_FOR_DESC_CRC (-25305) +/** Unexpected/unknown/bad descriptor in volume descriptor sequence. */ +#define VERR_ISOFS_UNEXPECTED_VDS_DESC (-25306) +/** Too many primary volume descriptors. */ +#define VERR_ISOFS_TOO_MANY_PVDS (-25307) +/** Too many logical volume descriptors. */ +#define VERR_ISOFS_TOO_MANY_LVDS (-25308) +/** Too many partition descriptors. */ +#define VERR_ISOFS_TOO_MANY_PDS (-25309) +/** The logical volume descriptor has a too big partition map. */ +#define VERR_ISOFS_TOO_BIT_PARTMAP_IN_LVD (-25310) +/** No primary volume descriptors found. */ +#define VERR_ISOFS_NO_PVD (-25311) +/** No logical volume descriptors found. */ +#define VERR_ISOFS_NO_LVD (-25312) +/** No partition descriptors found. */ +#define VERR_ISOFS_NO_PD (-25313) +/** Multiple primary volume descriptors found, we can only deal with one. */ +#define VERR_ISOFS_MULTIPLE_PVDS (-25314) +/** Multiple logical volume descriptors found, we can only deal with one. */ +#define VERR_ISOFS_MULTIPLE_LVDS (-25315) +/** Too many partition maps in the logical volume descriptor. */ +#define VERR_ISOFS_TOO_MANY_PART_MAPS (-25316) +/** Malformed partition map table in the logical volume descriptor. */ +#define VERR_ISOFS_MALFORMED_PART_MAP_TABLE (-25317) +/** Unable to find partition descriptor for a partition map table entry. */ +#define VERR_ISOFS_PARTITION_NOT_FOUND (-25318) +/** Partition mapping table is shorted than described. */ +#define VERR_ISOFS_INCOMPLETE_PART_MAP_TABLE (-25319) +/** Unknown partition map entry type. */ +#define VERR_ISOFS_UNKNOWN_PART_MAP_ENTRY_TYPE (-25320) +/** Unkonwn paritition ID found in the partition map table. */ +#define VERR_ISOFS_UNKNOWN_PART_MAP_TYPE_ID (-25321) +/** Support for virtual partitions as not yet been implemented. */ +#define VERR_ISOFS_VPM_NOT_SUPPORTED (-25322) +/** Support for sparable partitions as not yet been implemented. */ +#define VERR_ISOFS_SPM_NOT_SUPPORTED (-25323) +/** Support for metadata partitions as not yet been implemented. */ +#define VERR_ISOFS_MPM_NOT_SUPPORTED (-25324) +/** Invalid or unsupported logical block size. */ +#define VERR_ISOFS_UNSUPPORTED_LOGICAL_BLOCK_SIZE (-25325) +/** Unsupported domain ID in logical volume descriptor. */ +#define VERR_ISOFS_BAD_LVD_DOMAIN_ID (-25326) +/** Malformed or invalid file set descriptor location. */ +#define VERR_ISOFS_BAD_LVD_FILE_SET_DESC_LOCATION (-25327) +/** Non-standard descriptor character set in the logical volume descriptor. */ +#define VERR_ISOFS_BAD_LVD_DESC_CHAR_SET (-25329) +/** Invalid partition index in a location. */ +#define VERR_ISOFS_INVALID_PARTITION_INDEX (-25330) +/** Unsupported file system charset. */ +#define VERR_ISOFS_FSD_UNSUPPORTED_CHAR_SET (-25331) +/** File set descriptor has an zero length or invalid root dir extent. */ +#define VERR_ISOFS_FSD_ZERO_ROOT_DIR (-25332) +/** File set descriptor has a next extent member. */ +#define VERR_ISOFS_FSD_NEXT_EXTENT (-25333) +/** The ICB for is too big. */ +#define VERR_ISOFS_ICB_TOO_BIG (-25334) +/** The ICB for is too small. */ +#define VERR_ISOFS_ICB_TOO_SMALL (-25335) +/** No direct ICB entries found. */ +#define VERR_ISOFS_NO_DIRECT_ICB_ENTRIES (-25336) +/** Too many ICB indirections, possibly a loop. */ +#define VERR_ISOFS_TOO_MANY_ICB_INDIRECTIONS (-25337) +/** Too deep ICB recursion. */ +#define VERR_ISOFS_TOO_DEEP_ICB_RECURSION (-25338) +/** ICB is too small to contain anything useful. */ +#define VERR_ISOFS_ICB_ENTRY_TOO_SMALL (-25339) +/** Unsupported tag encountered in ICB. */ +#define VERR_ISOFS_UNSUPPORTED_ICB (-25340) +/** Bad file entry (ICB). */ +#define VERR_ISOFS_BAD_FILE_ENTRY (-25341) +/** Unknown allocation descriptor type. */ +#define VERR_ISO_FS_UNKNOWN_AD_TYPE (-25342) +/** Malformed extended allocation descriptor. */ +#define VERR_ISOFS_BAD_EXTAD (-25343) +/** Wrong file type. */ +#define VERR_ISOFS_WRONG_FILE_TYPE (-25344) +/** Unknow file type. */ +#define VERR_ISOFS_UNKNOWN_FILE_TYPE (-25345) + +/** Not implemented for UDF. */ +#define VERR_ISOFS_UDF_NOT_IMPLEMENTED (-25390) +/** Internal processing error \#1. */ +#define VERR_ISOFS_IPE_1 (-25391) +/** Internal processing error \#2. */ +#define VERR_ISOFS_IPE_2 (-25392) +/** Internal processing error \#3. */ +#define VERR_ISOFS_IPE_3 (-25393) +/** Internal processing error \#4. */ +#define VERR_ISOFS_IPE_4 (-25394) +/** Internal processing error \#5. */ +#define VERR_ISOFS_IPE_5 (-25395) +/** @} */ + + +/** @name RTSerialPort status codes + * @{ */ +/** A break was detected until all requested data could be received. */ +#define VERR_SERIALPORT_BREAK_DETECTED (-25500) +/** The chosen baudrate is invalid or not supported by the given serial port. */ +#define VERR_SERIALPORT_INVALID_BAUDRATE (-25501) +/** @} */ + + +/** @name RTCRest status codes + * @{ */ +/** Do not know how to handle the content type in the server response. */ +#define VERR_REST_RESPONSE_CONTENT_TYPE_NOT_SUPPORTED (-25700) +/** Invalid UTF-8 encoding in the response. */ +#define VERR_REST_RESPONSE_INVALID_UTF8_ENCODING (-25701) +/** Server response contains embedded zero character(s). */ +#define VERR_REST_RESPONSE_EMBEDDED_ZERO_CHAR (-25702) +/** Server response contains unexpected repetitive header field. */ +#define VERR_REST_RESPONSE_REPEAT_HEADER_FIELD (-25703) +/** Unable to decode date value. */ +#define VWRN_REST_UNABLE_TO_DECODE_DATE (25704) +/** Unable to decode date value. */ +#define VERR_REST_UNABLE_TO_DECODE_DATE (-25704) +/** Wrong JSON type for bool value. */ +#define VERR_REST_WRONG_JSON_TYPE_FOR_BOOL (-25705) +/** Wrong JSON type for integer value. */ +#define VERR_REST_WRONG_JSON_TYPE_FOR_INTEGER (-25706) +/** Wrong JSON type for double value. */ +#define VERR_REST_WRONG_JSON_TYPE_FOR_DOUBLE (-25707) +/** Wrong JSON type for string value. */ +#define VERR_REST_WRONG_JSON_TYPE_FOR_STRING (-25708) +/** Wrong JSON type for date value. */ +#define VERR_REST_WRONG_JSON_TYPE_FOR_DATE (-25709) +/** Unable to parse string as bool. */ +#define VERR_REST_UNABLE_TO_PARSE_STRING_AS_BOOL (-25710) +/** A path parameter was not set. */ +#define VERR_REST_PATH_PARAMETER_NOT_SET (-25711) +/** A required query parameter was not set. */ +#define VERR_REST_REQUIRED_QUERY_PARAMETER_NOT_SET (-25712) +/** A required header parmaeter was not set. */ +#define VERR_REST_REQUIRED_HEADER_PARAMETER_NOT_SET (-25713) + +/** Internal error \#1. */ +#define VERR_REST_INTERNAL_ERROR_1 (-25791) +/** Internal error \#2. */ +#define VERR_REST_INTERNAL_ERROR_2 (-25792) +/** Internal error \#3. */ +#define VERR_REST_INTERNAL_ERROR_3 (-25793) +/** Internal error \#4. */ +#define VERR_REST_INTERNAL_ERROR_4 (-25794) +/** Internal error \#5. */ +#define VERR_REST_INTERNAL_ERROR_5 (-25795) +/** Internal error \#6. */ +#define VERR_REST_INTERNAL_ERROR_6 (-25796) +/** Internal error \#7. */ +#define VERR_REST_INTERNAL_ERROR_7 (-25797) +/** Internal error \#8. */ +#define VERR_REST_INTERNAL_ERROR_8 (-25798) +/** Internal error \#9. */ +#define VERR_REST_INTERNAL_ERROR_9 (-25799) +/** @} */ + + +/** @name RTCrCipher status codes + * @{ */ +/** Unsupported cipher. */ +#define VERR_CR_CIPHER_NOT_SUPPORTED (-25800) +/** EVP_EncryptInit failed. */ +#define VERR_CR_CIPHER_OSSL_ENCRYPT_INIT_FAILED (-25801) +/** EVP_EncryptUpdate failed. */ +#define VERR_CR_CIPHER_OSSL_ENCRYPT_UPDATE_FAILED (-25802) +/** EVP_EncryptFinal failed. */ +#define VERR_CR_CIPHER_OSSL_ENCRYPT_FINAL_FAILED (-25803) +/** EVP_DecryptInit failed. */ +#define VERR_CR_CIPHER_OSSL_DECRYPT_INIT_FAILED (-25804) +/** EVP_DecryptUpdate failed. */ +#define VERR_CR_CIPHER_OSSL_DECRYPT_UPDATE_FAILED (-25805) +/** EVP_DecryptFinal failed. */ +#define VERR_CR_CIPHER_OSSL_DECRYPT_FINAL_FAILED (-25806) +/** Invalid key length. */ +#define VERR_CR_CIPHER_INVALID_KEY_LENGTH (-25807) +/** Invalid initialization vector length. */ +#define VERR_CR_CIPHER_INVALID_INITIALIZATION_VECTOR_LENGTH (-25808) +/** Invalid tag length. */ +#define VERR_CR_CIPHER_INVALID_TAG_LENGTH (-25809) +/** EVP_CIPHER_CTX_ctrl EVP_CTRL_AEAD_GET_TAG failed. */ +#define VERR_CR_CIPHER_OSSL_GET_TAG_FAILED (-25810) +/** EVP_CIPHER_CTX_ctrl EVP_CTRL_AEAD_SET_TAG failed. */ +#define VERR_CR_CIPHER_OSSL_SET_TAG_FAILED (-25811) +/** @} */ + + +/** @name RTShMem status codes + * @{ */ +/** Maximum number of mappings reached. */ +#define VERR_SHMEM_MAXIMUM_MAPPINGS_REACHED (-26000) +/** @} */ + + +/** @name RTIoQueue status codes + * @{ */ +/** The handle was not registered for use with the I/O queue. */ +#define VERR_IOQUEUE_HANDLE_NOT_REGISTERED (-26200) +/** The I/O queue is full and can't accept more requests. */ +#define VERR_IOQUEUE_FULL (-26201) +/** The I/O queue doesn't contain any prepared requests to commit or wait for completion. */ +#define VERR_IOQUEUE_EMPTY (-26202) +/** The I/O queue has requests pending which need complete first. */ +#define VERR_IOQUEUE_BUSY (-26203) +/** @} */ + + +/** @name FTP status codes + * @{ */ +/** FTP Internal Server Error. */ +#define VERR_FTP_STATUS_SERVER_ERROR (-26400) +/** FTP initialization failed. */ +#define VERR_FTP_INIT_FAILED (-26401) +/** Data connection not found. */ +#define VERR_FTP_DATA_CONN_INIT_FAILED (-26402) +/** Data connection not found. */ +#define VERR_FTP_DATA_CONN_NOT_FOUND (-26403) +/** Data connection limit has been reached. */ +#define VERR_FTP_DATA_CONN_LIMIT_REACHED (-26404) +/** Client not found. */ +#define VERR_FTP_CLIENT_NOT_FOUND (-26405) +/** Client limit has been reached. */ +#define VERR_FTP_CLIENT_LIMIT_REACHED (-26406) +/** @} */ + + +/** @name Trace Log status codes. + * @{ */ +/** The trace log is malformed. */ +#define VERR_TRACELOG_READER_MALFORMED_LOG (-26600) +/** The trace log version is not supported. */ +#define VERR_TRACELOG_READER_LOG_UNSUPPORTED (-26601) +/** The trace log reader iterator reached the end of the event list. */ +#define VERR_TRACELOG_READER_ITERATOR_END (-26602) +/** @} */ + + +/** @name Hardened AVL tree status codes. + * @{ */ +/** Node index is out of bounds. */ +#define VERR_HARDAVL_INDEX_OUT_OF_BOUNDS (-26801) +/** Node pointer is not within the memory allocated for nodes. */ +#define VERR_HARDAVL_POINTER_OUT_OF_BOUNDS (-26802) +/** Node pointer does not point to the start of a node. */ +#define VERR_HARDAVL_MISALIGNED_POINTER (-26803) +/** Bogus reference to freed node. */ +#define VERR_HARDAVL_NODE_IS_FREE (-26804) +/** Stack overflow during AVL tree operation. */ +#define VERR_HARDAVL_STACK_OVERFLOW (-26810) +/** Attempted to insert mode with invalid key range. */ +#define VERR_HARDAVL_INSERT_INVALID_KEY_RANGE (-26811) +/** Bad left tree height. */ +#define VERR_HARDAVL_BAD_LEFT_HEIGHT (-26812) +/** Bad left right height. */ +#define VERR_HARDAVL_BAD_RIGHT_HEIGHT (-26813) +/** Bad new tree height. */ +#define VERR_HARDAVL_BAD_NEW_HEIGHT (-26814) +/** Unexpected NULL pointer to left subtree. */ +#define VERR_HARDAVL_UNEXPECTED_NULL_LEFT (-26815) +/** Unexpected NULL pointer to right subtree. */ +#define VERR_HARDAVL_UNEXPECTED_NULL_RIGHT (-26816) +/** Tree traversal encountered more nodes than available in the allocator. */ +#define VERR_HARDAVL_TRAVERSED_TOO_MANY_NODES (-26817) +/** Too deep walk during lookup. */ +#define VERR_HARDAVL_LOOKUP_TOO_DEEP (-26818) +/** Bad tree height. */ +#define VERR_HARDAVL_BAD_HEIGHT (-26819) +/** Unbalanced tree. */ +#define VERR_HARDAVL_UNBALANCED (-26820) +/** @} */ + +/* SED-END */ + +/** @} */ + +#endif /* !IPRT_INCLUDED_err_h */ + diff --git a/include/iprt/err.mac b/include/iprt/err.mac new file mode 100644 index 00000000..5bc57b9b --- /dev/null +++ b/include/iprt/err.mac @@ -0,0 +1,1201 @@ +;; @file +; IPRT - Status Codes. +; +; Automatically generated by err.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%define VINF_SUCCESS 0 +%define VERR_GENERAL_FAILURE (-1) +%define VERR_INVALID_PARAMETER (-2) +%define VWRN_INVALID_PARAMETER 2 +%define VERR_INVALID_MAGIC (-3) +%define VWRN_INVALID_MAGIC 3 +%define VERR_INVALID_HANDLE (-4) +%define VWRN_INVALID_HANDLE 4 +%define VERR_LOCK_FAILED (-5) +%define VERR_INVALID_POINTER (-6) +%define VERR_IDT_FAILED (-7) +%define VERR_NO_MEMORY (-8) +%define VERR_ALREADY_LOADED (-9) +%define VERR_PERMISSION_DENIED (-10) +%define VINF_PERMISSION_DENIED 10 +%define VERR_VERSION_MISMATCH (-11) +%define VERR_NOT_IMPLEMENTED (-12) +%define VINF_NOT_IMPLEMENTED 12 +%define VERR_INVALID_FLAGS (-13) +%define VERR_NOT_EQUAL (-18) +%define VERR_NOT_SYMLINK (-19) +%define VERR_NO_TMP_MEMORY (-20) +%define VERR_INVALID_FMODE (-21) +%define VERR_WRONG_ORDER (-22) +%define VERR_NO_TLS_FOR_SELF (-23) +%define VERR_FAILED_TO_SET_SELF_TLS (-24) +%define VERR_NO_CONT_MEMORY (-26) +%define VERR_NO_PAGE_MEMORY (-27) +%define VINF_ALREADY_INITIALIZED 28 +%define VERR_ALREADY_INITIALIZED (-28) +%define VERR_THREAD_IS_DEAD (-29) +%define VERR_THREAD_NOT_WAITABLE (-30) +%define VERR_PAGE_TABLE_NOT_PRESENT (-31) +%define VERR_INVALID_CONTEXT (-32) +%define VERR_TIMER_BUSY (-33) +%define VERR_ADDRESS_CONFLICT (-34) +%define VERR_UNRESOLVED_ERROR (-35) +%define VERR_INVALID_FUNCTION (-36) +%define VERR_NOT_SUPPORTED (-37) +%define VINF_NOT_SUPPORTED 37 +%define VERR_ACCESS_DENIED (-38) +%define VERR_INTERRUPTED (-39) +%define VINF_INTERRUPTED 39 +%define VERR_TIMEOUT (-40) +%define VINF_TIMEOUT 40 +%define VERR_BUFFER_OVERFLOW (-41) +%define VINF_BUFFER_OVERFLOW 41 +%define VERR_TOO_MUCH_DATA (-42) +%define VERR_MAX_THRDS_REACHED (-43) +%define VERR_MAX_PROCS_REACHED (-44) +%define VERR_SIGNAL_REFUSED (-45) +%define VERR_SIGNAL_PENDING (-46) +%define VERR_SIGNAL_INVALID (-47) +%define VERR_STATE_CHANGED (-48) +%define VWRN_STATE_CHANGED 48 +%define VERR_INVALID_UUID_FORMAT (-49) +%define VERR_PROCESS_NOT_FOUND (-50) +%define VERR_PROCESS_RUNNING (-51) +%define VERR_TRY_AGAIN (-52) +%define VINF_TRY_AGAIN 52 +%define VERR_PARSE_ERROR (-53) +%define VERR_OUT_OF_RANGE (-54) +%define VERR_NUMBER_TOO_BIG (-55) +%define VWRN_NUMBER_TOO_BIG 55 +%define VERR_NO_DIGITS (-56) +%define VWRN_NO_DIGITS 56 +%define VERR_NEGATIVE_UNSIGNED (-57) +%define VWRN_NEGATIVE_UNSIGNED 57 +%define VERR_NO_TRANSLATION (-58) +%define VWRN_NO_TRANSLATION 58 +%define VERR_CODE_POINT_ENDIAN_INDICATOR (-59) +%define VERR_CODE_POINT_SURROGATE (-60) +%define VERR_INVALID_UTF8_ENCODING (-61) +%define VERR_INVALID_UTF16_ENCODING (-62) +%define VERR_CANT_RECODE_AS_UTF16 (-63) +%define VERR_NO_STR_MEMORY (-64) +%define VERR_NO_UTF16_MEMORY (-65) +%define VERR_NO_CODE_POINT_MEMORY (-66) +%define VERR_MEMORY_BUSY (-67) +%define VERR_TIMER_ACTIVE (-68) +%define VERR_TIMER_SUSPENDED (-69) +%define VERR_CANCELLED (-70) +%define VERR_MEMOBJ_INIT_FAILED (-71) +%define VERR_NO_LOW_MEMORY (-72) +%define VERR_NO_PHYS_MEMORY (-73) +%define VERR_ADDRESS_TOO_BIG (-74) +%define VERR_MAP_FAILED (-75) +%define VERR_TRAILING_CHARS (-76) +%define VWRN_TRAILING_CHARS 76 +%define VERR_TRAILING_SPACES (-77) +%define VWRN_TRAILING_SPACES 77 +%define VERR_NOT_FOUND (-78) +%define VWRN_NOT_FOUND 78 +%define VERR_INVALID_STATE (-79) +%define VWRN_INVALID_STATE 79 +%define VERR_OUT_OF_RESOURCES (-80) +%define VWRN_OUT_OF_RESOURCES 80 +%define VERR_NO_MORE_HANDLES (-81) +%define VERR_PREEMPT_DISABLED (-82) +%define VERR_END_OF_STRING (-83) +%define VINF_END_OF_STRING 83 +%define VERR_PAGE_COUNT_OUT_OF_RANGE (-84) +%define VERR_OBJECT_DESTROYED (-85) +%define VINF_OBJECT_DESTROYED 85 +%define VERR_DANGLING_OBJECTS (-86) +%define VWRN_DANGLING_OBJECTS 86 +%define VERR_INVALID_BASE64_ENCODING (-87) +%define VERR_CALLBACK_RETURN (-88) +%define VINF_CALLBACK_RETURN 88 +%define VERR_AUTHENTICATION_FAILURE (-89) +%define VERR_NOT_POWER_OF_TWO (-90) +%define VERR_IGNORED (-91) +%define VERR_CONCURRENT_ACCESS (-92) +%define VERR_CALLER_NO_REFERENCE (-93) +%define VERR_NO_CHANGE (-95) +%define VINF_NO_CHANGE 95 +%define VERR_NO_EXEC_MEMORY (-96) +%define VERR_UNSUPPORTED_ALIGNMENT (-97) +%define VINF_UNSUPPORTED_ALIGNMENT 97 +%define VERR_DUPLICATE (-98) +%define VERR_MISSING (-99) +%define VERR_UNEXPECTED_EXCEPTION (-22400) +%define VERR_BUFFER_UNDERFLOW (-22401) +%define VINF_BUFFER_UNDERFLOW 22401 +%define VERR_UNEVEN_INPUT (-22402) +%define VERR_NOT_AVAILABLE (-22403) +%define VERR_PROC_DETACH_NOT_SUPPORTED (-22404) +%define VERR_ACCOUNT_RESTRICTED (-22405) +%define VINF_ACCOUNT_RESTRICTED 22405 +%define VERR_UNABLE_TO_SATISFY_REQUIREMENTS (-22406) +%define VWRN_UNABLE_TO_SATISFY_REQUIREMENTS 22406 +%define VERR_ALLOCATION_TOO_BIG (-22407) +%define VERR_MISMATCH (-22408) +%define VERR_WRONG_TYPE (-22409) +%define VWRN_WRONG_TYPE (22409) +%define VERR_PRIVILEGE_NOT_HELD (-22410) +%define VERR_PROC_TCB_PRIV_NOT_HELD (-22411) +%define VERR_PROC_APT_PRIV_NOT_HELD (-22412) +%define VERR_PROC_IQ_PRIV_NOT_HELD (-22413) +%define VERR_MP_TOO_MANY_CPUS (-22414) +%define VERR_WRONG_PARAMETER_COUNT (-22415) +%define VERR_WRONG_PARAMETER_TYPE (-22416) +%define VERR_INVALID_CLIENT_ID (-22417) +%define VERR_INVALID_SESSION_ID (-22418) +%define VERR_PROC_ELEVATION_REQUIRED (-22419) +%define VERR_INCOMPATIBLE_CONFIG (-22420) +%define VERR_NO_STRING_TERMINATOR (-22421) +%define VERR_EMPTY_STRING (-22422) +%define VERR_TOO_MANY_REFERENCES (-22423) +%define VINF_THREAD_IS_TERMINATING (22424) +%define VERR_THREAD_IS_TERMINATING (-22424) +%define VERR_PROC_NO_ARG_TRANSLATION (-22425) +%define VERR_FLOAT_UNDERFLOW (-22426) +%define VWRN_FLOAT_UNDERFLOW (22426) +%define VERR_FLOAT_OVERFLOW (-22427) +%define VWRN_FLOAT_OVERFLOW (22427) +%define VERR_FILE_IO_ERROR (-100) +%define VERR_OPEN_FAILED (-101) +%define VERR_FILE_NOT_FOUND (-102) +%define VERR_PATH_NOT_FOUND (-103) +%define VERR_INVALID_NAME (-104) +%define VERR_ALREADY_EXISTS (-105) +%define VWRN_ALREADY_EXISTS 105 +%define VERR_TOO_MANY_OPEN_FILES (-106) +%define VERR_SEEK (-107) +%define VERR_NEGATIVE_SEEK (-108) +%define VERR_SEEK_ON_DEVICE (-109) +%define VERR_EOF (-110) +%define VINF_EOF 110 +%define VERR_READ_ERROR (-111) +%define VERR_WRITE_ERROR (-112) +%define VERR_WRITE_PROTECT (-113) +%define VERR_SHARING_VIOLATION (-114) +%define VERR_FILE_LOCK_FAILED (-115) +%define VERR_FILE_LOCK_VIOLATION (-116) +%define VERR_CANT_CREATE (-117) +%define VERR_CANT_DELETE_DIRECTORY (-118) +%define VERR_NOT_SAME_DEVICE (-119) +%define VERR_FILENAME_TOO_LONG (-120) +%define VERR_MEDIA_NOT_PRESENT (-121) +%define VERR_MEDIA_NOT_RECOGNIZED (-122) +%define VERR_FILE_NOT_LOCKED (-123) +%define VERR_FILE_LOCK_LOST (-124) +%define VERR_DIR_NOT_EMPTY (-125) +%define VERR_NOT_A_DIRECTORY (-126) +%define VERR_IS_A_DIRECTORY (-127) +%define VERR_FILE_TOO_BIG (-128) +%define VERR_FILE_AIO_NO_REQUEST (-129) +%define VERR_FILE_AIO_IN_PROGRESS (-130) +%define VERR_FILE_AIO_COMPLETED (-131) +%define VERR_FILE_AIO_BUSY (-132) +%define VERR_FILE_AIO_LIMIT_EXCEEDED (-133) +%define VERR_FILE_AIO_CANCELED (-134) +%define VERR_FILE_AIO_NOT_SUBMITTED (-135) +%define VERR_FILE_AIO_NOT_PREPARED (-136) +%define VERR_FILE_AIO_INSUFFICIENT_RESSOURCES (-137) +%define VERR_RESOURCE_BUSY (-138) +%define VERR_NOT_A_FILE (-139) +%define VERR_IS_A_FILE (-140) +%define VERR_UNEXPECTED_FS_OBJ_TYPE (-141) +%define VERR_PATH_DOES_NOT_START_WITH_ROOT (-142) +%define VERR_PATH_IS_RELATIVE (-143) +%define VERR_PATH_IS_NOT_RELATIVE (-144) +%define VERR_PATH_ZERO_LENGTH (-145) +%define VERR_FILE_AIO_INSUFFICIENT_EVENTS (-146) +%define VERR_STALE_FILE_HANDLE (-147) +%define VERR_DISK_IO_ERROR (-150) +%define VERR_INVALID_DRIVE (-151) +%define VERR_DISK_FULL (-152) +%define VERR_DISK_CHANGE (-153) +%define VERR_DRIVE_LOCKED (-154) +%define VERR_DISK_INVALID_FORMAT (-155) +%define VERR_TOO_MANY_SYMLINKS (-156) +%define VERR_NS_SYMLINK_SET_TIME (-157) +%define VERR_NS_SYMLINK_CHANGE_OWNER (-158) +%define VERR_SYMLINK_NOT_ALLOWED (-159) +%define VERR_IS_A_SYMLINK (-160) +%define VERR_IS_A_FIFO (-161) +%define VERR_IS_A_SOCKET (-162) +%define VERR_IS_A_BLOCK_DEVICE (-163) +%define VERR_IS_A_CHAR_DEVICE (-164) +%define VERR_DRIVE_IS_EMPTY (-165) +%define VERR_SEARCH_ERROR (-200) +%define VERR_NO_MORE_FILES (-201) +%define VERR_NO_MORE_SEARCH_HANDLES (-202) +%define VWRN_NO_DIRENT_INFO 203 +%define VERR_INTERNAL_ERROR (-225) +%define VERR_INTERNAL_ERROR_2 (-226) +%define VERR_INTERNAL_ERROR_3 (-227) +%define VERR_INTERNAL_ERROR_4 (-228) +%define VERR_INTERNAL_ERROR_5 (-229) +%define VERR_IPE_UNEXPECTED_STATUS (-230) +%define VERR_IPE_UNEXPECTED_INFO_STATUS (-231) +%define VERR_IPE_UNEXPECTED_ERROR_STATUS (-232) +%define VERR_IPE_UNINITIALIZED_STATUS (-233) +%define VERR_IPE_NOT_REACHED_DEFAULT_CASE (-234) +%define VERR_DEV_IO_ERROR (-250) +%define VERR_IO_BAD_UNIT (-251) +%define VERR_IO_NOT_READY (-252) +%define VERR_IO_BAD_COMMAND (-253) +%define VERR_IO_CRC (-254) +%define VERR_IO_BAD_LENGTH (-255) +%define VERR_IO_SECTOR_NOT_FOUND (-256) +%define VERR_IO_GEN_FAILURE (-257) +%define VERR_PIPE_IO_ERROR (-300) +%define VERR_BROKEN_PIPE (-301) +%define VERR_BAD_PIPE (-302) +%define VERR_PIPE_BUSY (-303) +%define VERR_NO_DATA (-304) +%define VERR_PIPE_NOT_CONNECTED (-305) +%define VERR_MORE_DATA (-306) +%define VERR_PIPE_NOT_READ (-307) +%define VERR_PIPE_NOT_WRITE (-308) +%define VERR_SEM_ERROR (-350) +%define VERR_TOO_MANY_SEMAPHORES (-351) +%define VERR_EXCL_SEM_ALREADY_OWNED (-352) +%define VERR_SEM_IS_SET (-353) +%define VERR_TOO_MANY_SEM_REQUESTS (-354) +%define VERR_NOT_OWNER (-355) +%define VERR_TOO_MANY_OPENS (-356) +%define VERR_TOO_MANY_POSTS (-357) +%define VERR_ALREADY_POSTED (-358) +%define VINF_ALREADY_POSTED (358) +%define VERR_ALREADY_RESET (-359) +%define VERR_SEM_BUSY (-360) +%define VERR_SEM_OWNER_DIED (-361) +%define VERR_SEM_NOT_FOUND (-362) +%define VERR_SEM_DESTROYED (-363) +%define VERR_SEM_NESTED (-364) +%define VINF_SEM_NESTED (364) +%define VERR_DEADLOCK (-365) +%define VERR_SEM_OUT_OF_TURN (-366) +%define VERR_SEM_BAD_CONTEXT (-367) +%define VINF_SEM_BAD_CONTEXT (367) +%define VERR_SEM_LV_WRONG_ORDER (-368) +%define VERR_SEM_LV_WRONG_RELEASE_ORDER (-369) +%define VERR_SEM_LV_NESTED (-370) +%define VERR_SEM_LV_INVALID_PARAMETER (-371) +%define VERR_SEM_LV_DEADLOCK (-372) +%define VERR_SEM_LV_EXISTING_DEADLOCK (-373) +%define VERR_SEM_LV_NOT_OWNER (-374) +%define VERR_SEM_LV_ILLEGAL_UPGRADE (-375) +%define VERR_SEM_LV_NOT_SIGNALLER (-376) +%define VERR_SEM_LV_INTERNAL_ERROR (-377) +%define VERR_NET_IO_ERROR (-400) +%define VERR_NET_OUT_OF_RESOURCES (-401) +%define VERR_NET_HOST_NOT_FOUND (-402) +%define VERR_NET_PATH_NOT_FOUND (-403) +%define VERR_NET_PRINT_ERROR (-404) +%define VERR_NET_NO_NETWORK (-405) +%define VERR_NET_NOT_UNIQUE_NAME (-406) +%define VERR_NET_IN_PROGRESS (-436) +%define VERR_NET_ALREADY_IN_PROGRESS (-437) +%define VERR_NET_NOT_SOCKET (-438) +%define VERR_NET_DEST_ADDRESS_REQUIRED (-439) +%define VERR_NET_MSG_SIZE (-440) +%define VERR_NET_PROTOCOL_TYPE (-441) +%define VERR_NET_PROTOCOL_NOT_AVAILABLE (-442) +%define VERR_NET_PROTOCOL_NOT_SUPPORTED (-443) +%define VERR_NET_SOCKET_TYPE_NOT_SUPPORTED (-444) +%define VERR_NET_OPERATION_NOT_SUPPORTED (-445) +%define VERR_NET_PROTOCOL_FAMILY_NOT_SUPPORTED (-446) +%define VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED (-447) +%define VERR_NET_ADDRESS_IN_USE (-448) +%define VERR_NET_ADDRESS_NOT_AVAILABLE (-449) +%define VERR_NET_DOWN (-450) +%define VERR_NET_UNREACHABLE (-451) +%define VERR_NET_CONNECTION_RESET (-452) +%define VERR_NET_CONNECTION_ABORTED (-453) +%define VERR_NET_CONNECTION_RESET_BY_PEER (-454) +%define VERR_NET_NO_BUFFER_SPACE (-455) +%define VERR_NET_ALREADY_CONNECTED (-456) +%define VERR_NET_NOT_CONNECTED (-457) +%define VERR_NET_SHUTDOWN (-458) +%define VERR_NET_TOO_MANY_REFERENCES (-459) +%define VERR_NET_CONNECTION_TIMED_OUT (-460) +%define VERR_NET_CONNECTION_REFUSED (-461) +%define VERR_NET_HOST_DOWN (-464) +%define VERR_NET_HOST_UNREACHABLE (-465) +%define VERR_NET_PROTOCOL_ERROR (-466) +%define VERR_NET_INCOMPLETE_TX_PACKET (-467) +%define VERR_NET_INIT_FAILED (-468) +%define VERR_NET_NOT_UNSUPPORTED (-469) +%define VERR_TCP_SERVER_STOP (-500) +%define VINF_TCP_SERVER_STOP 500 +%define VERR_TCP_SERVER_SHUTDOWN (-501) +%define VERR_TCP_SERVER_DESTROYED (-502) +%define VINF_TCP_SERVER_NO_CLIENT 503 +%define VERR_UDP_SERVER_STOP (-520) +%define VINF_UDP_SERVER_STOP 520 +%define VERR_UDP_SERVER_SHUTDOWN (-521) +%define VERR_UDP_SERVER_DESTROYED (-522) +%define VINF_UDP_SERVER_NO_CLIENT 523 +%define VERR_L4_INVALID_DS_OFFSET (-550) +%define VERR_IPC (-551) +%define VERR_RESOURCE_IN_USE (-552) +%define VERR_IPC_PROCESS_NOT_FOUND (-553) +%define VERR_IPC_RECEIVE_TIMEOUT (-554) +%define VERR_IPC_SEND_TIMEOUT (-555) +%define VERR_IPC_RECEIVE_CANCELLED (-556) +%define VERR_IPC_SEND_CANCELLED (-557) +%define VERR_IPC_RECEIVE_ABORTED (-558) +%define VERR_IPC_SEND_ABORTED (-559) +%define VERR_IPC_RECEIVE_MAP_FAILED (-560) +%define VERR_IPC_SEND_MAP_FAILED (-561) +%define VERR_IPC_RECEIVE_SEND_PF_TIMEOUT (-562) +%define VERR_IPC_SEND_SEND_PF_TIMEOUT (-563) +%define VINF_IPC_RECEIVE_MSG_CUT 564 +%define VINF_IPC_SEND_MSG_CUT 565 +%define VERR_L4_DS_MANAGER_NOT_FOUND (-566) +%define VERR_INVALID_EXE_SIGNATURE (-600) +%define VERR_ELF_EXE_NOT_SUPPORTED (-601) +%define VERR_PE_EXE_NOT_SUPPORTED (-602) +%define VERR_LX_EXE_NOT_SUPPORTED (-603) +%define VERR_LE_EXE_NOT_SUPPORTED (-604) +%define VERR_NE_EXE_NOT_SUPPORTED (-605) +%define VERR_MZ_EXE_NOT_SUPPORTED (-606) +%define VERR_AOUT_EXE_NOT_SUPPORTED (-607) +%define VERR_BAD_EXE_FORMAT (-608) +%define VERR_SYMBOL_NOT_FOUND (-609) +%define VERR_MODULE_NOT_FOUND (-610) +%define VERR_SYMBOL_VALUE_TOO_BIG (-611) +%define VERR_IMAGE_TOO_BIG (-612) +%define VERR_IMAGE_BASE_TOO_HIGH (-614) +%define VERR_LDR_ARCH_MISMATCH (-615) +%define VERR_LDR_MISMATCH_NATIVE (-616) +%define VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND (-617) +%define VERR_LDR_GENERAL_FAILURE (-618) +%define VERR_LDR_IMAGE_HASH (-619) +%define VERR_LDRPE_DELAY_IMPORT (-620) +%define VERR_LDRPE_CERT_MALFORMED (-621) +%define VERR_LDRPE_CERT_UNSUPPORTED (-622) +%define VERR_LDRPE_GLOBALPTR (-623) +%define VERR_LDRPE_TLS (-624) +%define VERR_LDRPE_COM_DESCRIPTOR (-625) +%define VERR_LDRPE_LOAD_CONFIG_SIZE (-626) +%define VERR_LDRPE_LOCK_PREFIX_TABLE (-627) +%define VERR_LDRPE_GUARD_CF_STUFF (-628) +%define VERR_LDRELF_ODD_ENDIAN (-630) +%define VERR_LDRELF_DYN (-631) +%define VERR_LDRELF_EXEC (-632) +%define VERR_LDRELF_MACHINE (-633) +%define VERR_LDRELF_VERSION (-634) +%define VERR_LDRELF_MULTIPLE_SYMTABS (-635) +%define VERR_LDRELF_RELOCATION_NOT_SUPPORTED (-636) +%define VERR_LDRELF_INVALID_SYMBOL_INDEX (-637) +%define VERR_LDRELF_INVALID_SYMBOL_NAME_OFFSET (-638) +%define VERR_LDRELF_INVALID_RELOCATION_OFFSET (-639) +%define VERR_LDRELF_NO_SYMBOL_OR_NO_STRING_TABS (-640) +%define VERR_LDRELF_UNTERMINATED_STRING_TAB (-641) +%define VERR_LDR_INVALID_LINK_ADDRESS (-647) +%define VERR_LDR_INVALID_RVA (-648) +%define VERR_LDR_INVALID_SEG_OFFSET (-649) +%define VERR_DBG_NO_LINE_NUMBERS (-650) +%define VERR_DBG_NO_SYMBOLS (-651) +%define VERR_DBG_INVALID_ADDRESS (-652) +%define VERR_DBG_INVALID_SEGMENT_INDEX (-653) +%define VERR_DBG_INVALID_SEGMENT_OFFSET (-654) +%define VERR_DBG_INVALID_RVA (-655) +%define VERR_DBG_SPECIAL_SEGMENT (-656) +%define VERR_DBG_ADDRESS_CONFLICT (-657) +%define VERR_DBG_DUPLICATE_SYMBOL (-658) +%define VERR_DBG_SEGMENT_INDEX_CONFLICT (-659) +%define VERR_DBG_LINE_NOT_FOUND (-660) +%define VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE (-661) +%define VERR_DBG_FILE_NAME_OUT_OF_RANGE (-662) +%define VERR_DBG_SEGMENT_NAME_OUT_OF_RANGE (-663) +%define VERR_DBG_ADDRESS_WRAP (-664) +%define VERR_DBG_NOT_NM_MAP_FILE (-665) +%define VERR_DBG_NOT_LINUX_KALLSYMS (-666) +%define VERR_DBG_NO_MATCHING_INTERPRETER (-667) +%define VERR_DWARF_BAD_LINE_NUMBER_HEADER (-668) +%define VERR_DWARF_UNEXPECTED_END (-669) +%define VERR_DWARF_LEB_OVERFLOW (-670) +%define VERR_DWARF_BAD_LNE (-671) +%define VERR_DWARF_BAD_STRING (-672) +%define VERR_DWARF_BAD_POS (-673) +%define VERR_DWARF_BAD_INFO (-674) +%define VERR_DWARF_BAD_ABBREV (-675) +%define VERR_DWARF_ABBREV_NOT_FOUND (-676) +%define VERR_DWARF_UNKNOWN_FORM (-677) +%define VERR_DWARF_UNEXPECTED_FORM (-678) +%define VERR_DWARF_TODO (-679) +%define VERR_DWARF_UNKNOWN_LOC_OPCODE (-680) +%define VERR_DWARF_STACK_OVERFLOW (-681) +%define VERR_DWARF_STACK_UNDERFLOW (-682) +%define VERR_DWARF_IPE (-683) +%define VERR_DBG_CFG_INVALID_VALUE (-684) +%define VERR_DBG_CFG_NOT_UINT_PROP (-685) +%define VERR_DBG_DEFERRED_LOAD_FAILED (-686) +%define VERR_DBG_TODO (-687) +%define VERR_DBG_FILE_MISMATCH (-688) +%define VERR_DBG_MOD_IPE (-689) +%define VINF_DBG_ADJUSTED_SYM_SIZE 690 +%define VERR_CV_BAD_FORMAT (-691) +%define VERR_CV_TODO (-692) +%define VERR_CV_IPE (-693) +%define VERR_DBG_NO_UNWIND_INFO (-694) +%define VERR_DBG_UNWIND_INFO_NOT_FOUND (-695) +%define VERR_DBG_MALFORMED_UNWIND_INFO (-696) +%define VERR_RT_REQUEST_INVALID_TYPE (-700) +%define VERR_RT_REQUEST_STATE (-701) +%define VERR_RT_REQUEST_INVALID_PACKAGE (-702) +%define VERR_RT_REQUEST_STATUS_STILL_PENDING (-703) +%define VERR_RT_REQUEST_STATUS_FREED (-704) +%define VERR_ENV_VAR_NOT_FOUND (-750) +%define VINF_ENV_VAR_NOT_FOUND (750) +%define VWRN_ENV_NOT_FULLY_TRANSLATED (751) +%define VERR_ENV_INVALID_VAR_NAME (-752) +%define VINF_ENV_VAR_UNSET (753) +%define VERR_ENV_VAR_UNSET (-753) +%define VERR_CPU_OFFLINE (-800) +%define VERR_CPU_NOT_FOUND (-801) +%define VERR_NOT_ALL_CPUS_SHOWED (-802) +%define VERR_CPU_IPE_1 (-803) +%define VERR_GETOPT_UNKNOWN_OPTION (-825) +%define VERR_GETOPT_REQUIRED_ARGUMENT_MISSING (-826) +%define VERR_GETOPT_INVALID_ARGUMENT_FORMAT (-827) +%define VINF_GETOPT_NOT_OPTION 828 +%define VERR_GETOPT_INDEX_MISSING (-829) +%define VERR_CACHE_FULL (-850) +%define VERR_CACHE_EMPTY (-851) +%define VERR_MEM_CACHE_MAX_SIZE (-855) +%define VERR_S3_ACCESS_DENIED (-875) +%define VERR_S3_NOT_FOUND (-876) +%define VERR_S3_BUCKET_ALREADY_EXISTS (-877) +%define VERR_S3_BUCKET_NOT_EMPTY (-878) +%define VERR_S3_CANCELED (-879) +%define VERR_HTTP_STATUS_SERVER_ERROR (-884) +%define VERR_HTTP_INIT_FAILED (-885) +%define VERR_HTTP_NOT_FOUND (-886) +%define VERR_HTTP_ACCESS_DENIED (-887) +%define VERR_HTTP_BAD_REQUEST (-888) +%define VERR_HTTP_COULDNT_CONNECT (-889) +%define VERR_HTTP_SSL_CONNECT_ERROR (-890) +%define VERR_HTTP_CACERT_WRONG_FORMAT (-891) +%define VERR_HTTP_CACERT_CANNOT_AUTHENTICATE (-892) +%define VERR_HTTP_ABORTED (-893) +%define VERR_HTTP_REDIRECTED (-894) +%define VERR_HTTP_PROXY_NOT_FOUND (-895) +%define VERR_HTTP_HOST_NOT_FOUND (-896) +%define VERR_HTTP_CURL_PROXY_CONFIG (-897) +%define VERR_HTTP_CURL_ERROR (-899) +%define VERR_MANIFEST_UNSUPPORTED_DIGEST_TYPE (-900) +%define VERR_MANIFEST_WRONG_FILE_FORMAT (-901) +%define VERR_MANIFEST_DIGEST_MISMATCH (-902) +%define VERR_MANIFEST_FILE_MISMATCH (-903) +%define VERR_MANIFEST_ATTR_NOT_FOUND (-904) +%define VERR_MANIFEST_ATTR_TYPE_MISMATCH (-905) +%define VERR_MANIFEST_ATTR_TYPE_NOT_FOUND (-906) +%define VERR_TAR_CHKSUM_MISMATCH (-925) +%define VERR_TAR_END_OF_FILE (-926) +%define VERR_TAR_UNEXPECTED_EOS (-927) +%define VERR_TAR_EOS_MORE_INPUT (-928) +%define VERR_TAR_BAD_NUM_FIELD (-929) +%define VERR_TAR_BAD_NUM_FIELD_TERM (-930) +%define VERR_TAR_BASE_256_NOT_SUPPORTED (-931) +%define VERR_TAR_NUM_VALUE_TOO_LARGE (-932) +%define VERR_TAR_DEV_VALUE_TOO_LARGE (-933) +%define VERR_TAR_BAD_MODE_FIELD (-934) +%define VERR_TAR_MODE_WITH_TYPE (-935) +%define VERR_TAR_SIZE_NOT_ZERO (-936) +%define VERR_TAR_UNKNOWN_TYPE_FLAG (-937) +%define VERR_TAR_ZERO_HEADER (-938) +%define VERR_TAR_NOT_USTAR_V00 (-939) +%define VERR_TAR_EMPTY_NAME (-940) +%define VERR_TAR_NON_DIR_ENDS_WITH_SLASH (-941) +%define VERR_TAR_UNSUPPORTED_PAX_TYPE (-942) +%define VERR_TAR_UNSUPPORTED_SOLARIS_HDR_TYPE (-943) +%define VERR_TAR_UNSUPPORTED_GNU_HDR_TYPE (-944) +%define VERR_TAR_BAD_CHKSUM_FIELD (-945) +%define VERR_TAR_MALFORMED_GNU_LONGXXXX (-946) +%define VERR_TAR_NAME_TOO_LONG (-947) +%define VINF_TAR_DIR_PATH (948) +%define VERR_POLL_HANDLE_NOT_POLLABLE (-950) +%define VERR_POLL_HANDLE_ID_EXISTS (-951) +%define VERR_POLL_HANDLE_ID_NOT_FOUND (-952) +%define VERR_POLL_SET_IS_FULL (-953) +%define VERR_PKZIP_NO_EOCB (-960) +%define VERR_PKZIP_NAME_TOO_LONG (-961) +%define VERR_PKZIP_BAD_LF_HEADER (-962) +%define VERR_PKZIP_BAD_CDF_HEADER (-963) +%define VERR_PKZIP_UNKNOWN_TYPE_FLAG (-964) +%define VERR_PKZIP_ZIP64EX_IN_ZIP32 (-965) +%define VERR_ZIP_ERROR (-22000) +%define VERR_ZIP_CORRUPTED (-22001) +%define VERR_ZIP_NO_MEMORY (-22002) +%define VERR_ZIP_UNSUPPORTED_VERSION (-22003) +%define VERR_ZIP_UNSUPPORTED_METHOD (-22004) +%define VERR_ZIP_BAD_HEADER (-22005) +%define VERR_VFS_CHAIN_NO_PREFIX (-22100) +%define VERR_VFS_CHAIN_EMPTY (-22101) +%define VERR_VFS_CHAIN_EXPECTED_ELEMENT (-22102) +%define VERR_VFS_CHAIN_UNKNOWN_TYPE (-22103) +%define VERR_VFS_CHAIN_EXPECTED_LEFT_PARENTHESES (-22104) +%define VERR_VFS_CHAIN_EXPECTED_RIGHT_PARENTHESES (-22105) +%define VERR_VFS_CHAIN_EXPECTED_PROVIDER_NAME (-22106) +%define VERR_VFS_CHAIN_EXPECTED_SEPARATOR (-22107) +%define VERR_VFS_CHAIN_LEADING_SEPARATOR (-22108) +%define VERR_VFS_CHAIN_TRAILING_SEPARATOR (-22109) +%define VERR_VFS_CHAIN_MUST_BE_FIRST_ELEMENT (-22110) +%define VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT (-22111) +%define VERR_VFS_CHAIN_CAST_FAILED (-22112) +%define VERR_VFS_CHAIN_IPE (-22113) +%define VERR_VFS_CHAIN_PROVIDER_NOT_FOUND (-22114) +%define VERR_VFS_CHAIN_FINAL_TYPE_MISMATCH (-22115) +%define VERR_VFS_CHAIN_NO_ARGS (-22116) +%define VERR_VFS_CHAIN_ONE_ARG (-22117) +%define VERR_VFS_CHAIN_AT_MOST_ONE_ARG (-22118) +%define VERR_VFS_CHAIN_AT_LEAST_ONE_ARG (-22119) +%define VERR_VFS_CHAIN_TWO_ARGS (-22120) +%define VERR_VFS_CHAIN_AT_LEAST_TWO_ARGS (-22121) +%define VERR_VFS_CHAIN_AT_MOST_TWO_ARGS (-22122) +%define VERR_VFS_CHAIN_THREE_ARGS (-22123) +%define VERR_VFS_CHAIN_AT_LEAST_THREE_ARGS (-22124) +%define VERR_VFS_CHAIN_AT_MOST_THREE_ARGS (-22125) +%define VERR_VFS_CHAIN_FOUR_ARGS (-22126) +%define VERR_VFS_CHAIN_AT_LEAST_FOUR_ARGS (-22127) +%define VERR_VFS_CHAIN_AT_MOST_FOUR_ARGS (-22128) +%define VERR_VFS_CHAIN_FIVE_ARGS (-22129) +%define VERR_VFS_CHAIN_AT_LEAST_FIVE_ARGS (-22130) +%define VERR_VFS_CHAIN_AT_MOST_FIVE_ARGS (-22131) +%define VERR_VFS_CHAIN_SIX_ARGS (-22132) +%define VERR_VFS_CHAIN_AT_LEAST_SIX_ARGS (-22133) +%define VERR_VFS_CHAIN_AT_MOST_SIX_ARGS (-22134) +%define VERR_VFS_CHAIN_TOO_FEW_ARGS (-22135) +%define VERR_VFS_CHAIN_TOO_MANY_ARGS (-22136) +%define VERR_VFS_CHAIN_EMPTY_ARG (-22137) +%define VERR_VFS_CHAIN_INVALID_ARGUMENT (-22138) +%define VERR_VFS_CHAIN_ONLY_FILE_OR_IOS (-22139) +%define VERR_VFS_CHAIN_ONLY_IOS (-22140) +%define VERR_VFS_CHAIN_ONLY_DIR (-22141) +%define VERR_VFS_CHAIN_ONLY_FSS (-22142) +%define VERR_VFS_CHAIN_ONLY_VFS (-22143) +%define VERR_VFS_CHAIN_ONLY_FILE_OR_IOS_OR_DIR (-22144) +%define VERR_VFS_CHAIN_ONLY_DIR_OR_VFS (-22145) +%define VERR_VFS_CHAIN_TAKES_FILE (-22146) +%define VERR_VFS_CHAIN_TAKES_FILE_OR_IOS (-22147) +%define VERR_VFS_CHAIN_TAKES_DIR (-22148) +%define VERR_VFS_CHAIN_TAKES_FSS (-22149) +%define VERR_VFS_CHAIN_TAKES_VFS (-22150) +%define VERR_VFS_CHAIN_TAKES_DIR_OR_VFS (-22151) +%define VERR_VFS_CHAIN_TAKES_DIR_OR_FSS_OR_VFS (-22152) +%define VERR_VFS_CHAIN_READ_ONLY_IOS (-22153) +%define VERR_VFS_CHAIN_WRITE_ONLY_IOS (-22154) +%define VERR_VFS_CHAIN_PATH_ONLY (-22155) +%define VERR_VFS_CHAIN_TYPE_MISMATCH_PATH_ONLY (-22156) +%define VERR_VFS_CHAIN_NOT_PATH_ONLY (-22157) +%define VERR_VFS_CHAIN_TOO_SHORT_FOR_PARENT (-22158) +%define VERR_DVM_MAP_EMPTY (-22200) +%define VERR_DVM_MAP_NO_VOLUME (-22201) +%define VERR_LOG_REVISION_MISMATCH (-22300) +%define VINF_LOG_DISABLED (22301) +%define VINF_LOG_NO_LOGGER (22302) +%define VERR_SYS_CANNOT_POWER_OFF (-22500) +%define VINF_SYS_MAY_POWER_OFF (22501) +%define VERR_SYS_SHUTDOWN_FAILED (-22502) +%define VERR_SYS_UNSUPPORTED_FIRMWARE_PROPERTY (-22503) +%define VERR_FILESYSTEM_CORRUPT (-22600) +%define VERR_XAR_WRONG_MAGIC (-22700) +%define VERR_XAR_BAD_HDR_SIZE (-22701) +%define VERR_XAR_UNSUPPORTED_VERSION (-22702) +%define VERR_XAR_UNSUPPORTED_HASH_FUNCTION (-22703) +%define VERR_XAR_TOC_TOO_SMALL (-22704) +%define VERR_XAR_TOC_TOO_BIG (-22705) +%define VERR_XAR_TOC_TOO_BIG_COMPRESSED (-22706) +%define VERR_XAR_TOC_UNCOMP_SIZE_MISMATCH (-22707) +%define VERR_XAR_TOC_STRLEN_MISMATCH (-22708) +%define VERR_XAR_TOC_UTF8_ENCODING (-22709) +%define VERR_XAR_TOC_XML_PARSE_ERROR (-22710) +%define VERR_XML_TOC_ELEMENT_MISSING (-22711) +%define VERR_XML_TOC_ELEMENT_HAS_SIBLINGS (-22712) +%define VERR_XAR_TOC_DIGEST_MISMATCH (-22713) +%define VERR_XAR_BAD_CHECKSUM_ELEMENT (-22714) +%define VERR_XAR_HASH_FUNCTION_MISMATCH (-22715) +%define VERR_XAR_BAD_DIGEST_LENGTH (-22716) +%define VERR_XAR_NOT_STREAMBLE_ELEMENT_ORDER (-22717) +%define VERR_XAR_MISSING_OFFSET_ELEMENT (-22718) +%define VERR_XAR_BAD_OFFSET_ELEMENT (-22719) +%define VERR_XAR_MISSING_SIZE_ELEMENT (-22720) +%define VERR_XAR_BAD_SIZE_ELEMENT (-22721) +%define VERR_XAR_MISSING_LENGTH_ELEMENT (-22722) +%define VERR_XAR_BAD_LENGTH_ELEMENT (-22723) +%define VERR_XAR_BAD_FILE_ELEMENT (-22724) +%define VERR_XAR_MISSING_DATA_ELEMENT (-22725) +%define VERR_XAR_UNKNOWN_FILE_TYPE (-22726) +%define VERR_XAR_NO_ENCODING (-22727) +%define VERR_XAR_BAD_FILE_TIMESTAMP (-22728) +%define VERR_XAR_BAD_FILE_MODE (-22729) +%define VERR_XAR_BAD_FILE_UID (-22730) +%define VERR_XAR_BAD_FILE_GID (-22731) +%define VERR_XAR_BAD_FILE_DEVICE_NO (-22732) +%define VERR_XAR_BAD_FILE_INODE (-22733) +%define VERR_XAR_INVALID_FILE_NAME (-22734) +%define VERR_XAR_EXTRACTED_HASH_MISMATCH (-22735) +%define VERR_XAR_EXTRACTED_SIZE_EXCEEDED (-22736) +%define VERR_XAR_ARCHIVED_HASH_MISMATCH (-22737) +%define VERR_XAR_UNUSED_ARCHIVED_DATA (-22738) +%define VERR_XAR_ARCHIVED_AND_EXTRACTED_SIZES_MISMATCH (-22739) +%define VERR_X509_READING_CERT_FROM_BIO (-23100) +%define VERR_X509_EXTRACT_PUBKEY_FROM_CERT (-23101) +%define VERR_X509_EXTRACT_RSA_FROM_PUBLIC_KEY (-23102) +%define VERR_X509_RSA_VERIFICATION_FUILURE (-23103) +%define VERR_X509_NO_BASIC_CONSTARAINTS (-23104) +%define VERR_X509_GETTING_EXTENSION_FROM_CERT (-23105) +%define VERR_X509_GETTING_DATA_FROM_EXTENSION (-23106) +%define VERR_X509_PRINT_EXTENSION_TO_BIO (-23107) +%define VERR_X509_CERTIFICATE_VERIFICATION_FAILURE (-23108) +%define VERR_X509_NOT_SELFSIGNED_CERTIFICATE (-23109) +%define VINF_X509_NOT_SELFSIGNED_CERTIFICATE 23109 +%define VERR_ASN1_ERROR (-22800) +%define VERR_ASN1_STRING_TYPE_NOT_IMPLEMENTED (-22801) +%define VERR_ASN1_INVALID_UTF8_STRING_ENCODING (-22802) +%define VERR_ASN1_INVALID_NUMERIC_STRING_ENCODING (-22803) +%define VERR_ASN1_INVALID_PRINTABLE_STRING_ENCODING (-22804) +%define VERR_ASN1_INVALID_T61_STRING_ENCODING (-22805) +%define VERR_ASN1_INVALID_VIDEOTEX_STRING_ENCODING (-22806) +%define VERR_ASN1_INVALID_IA5_STRING_ENCODING (-22807) +%define VERR_ASN1_INVALID_GRAPHIC_STRING_ENCODING (-22808) +%define VERR_ASN1_INVALID_VISIBLE_STRING_ENCODING (-22809) +%define VERR_ASN1_INVALID_GENERAL_STRING_ENCODING (-22810) +%define VERR_ASN1_INVALID_UNIVERSAL_STRING_ENCODING (-22811) +%define VERR_ASN1_INVALID_BMP_STRING_ENCODING (-22812) +%define VERR_ASN1_INVALID_OBJID_ENCODING (-22813) +%define VERR_ASN1_OBJID_COMPONENT_TOO_BIG (-22814) +%define VERR_ASN1_OBJID_TOO_MANY_COMPONENTS (-22815) +%define VERR_ASN1_OBJID_TOO_LONG_STRING_FORM (-22816) +%define VERR_ASN1_OBJID_INVALID_DOTTED_STRING (-22817) +%define VERR_ASN1_CONSTRUCTED_STRING_NOT_IMPL (-22818) +%define VERR_ASN1_STRING_TAG_MISMATCH (-22819) +%define VERR_ASN1_TIME_TAG_MISMATCH (-22820) +%define VINF_ASN1_MORE_DATA (22821) +%define VINF_ASN1_NOT_ENCODED (22822) +%define VERR_ASN1_TELETEX_UNKNOWN_ESC_SEQ (-22823) +%define VERR_ASN1_TELETEX_UNSUPPORTED_ESC_SEQ (-22824) +%define VERR_ASN1_TELETEX_UNSUPPORTED_CHARSET (-22825) +%define VERR_ASN1_NO_VTABLE (-22826) +%define VERR_ASN1_NO_CHECK_SANITY_METHOD (-22827) +%define VERR_ASN1_NOT_PRESENT (-22828) +%define VERR_ASN1_CURSOR_NOT_AT_END (-22829) +%define VERR_ASN1_CURSOR_LONG_TAG (-22830) +%define VERR_ASN1_CURSOR_BAD_LENGTH_ENCODING (-22831) +%define VERR_ASN1_CURSOR_ILLEGAL_INDEFINITE_LENGTH (-22832) +%define VERR_ASN1_CURSOR_BAD_INDEFINITE_LENGTH (-22833) +%define VERR_ASN1_CURSOR_BAD_LENGTH (-22834) +%define VERR_ASN1_CURSOR_NO_MORE_DATA (-22835) +%define VERR_ASN1_CURSOR_TOO_LITTLE_DATA_LEFT (-22836) +%define VERR_ASN1_CURSOR_ILLEGAL_CONSTRUCTED_STRING (-22837) +%define VERR_ASN1_CURSOR_TAG_MISMATCH (-22838) +%define VERR_ASN1_CURSOR_TAG_FLAG_CLASS_MISMATCH (-22839) +%define VERR_ASN1_BITSTRING_OUT_OF_BOUNDS (-22840) +%define VERR_ASN1_TIME_BAD_NORMALIZE_INPUT (-22841) +%define VERR_ASN1_TIME_NORMALIZE_ERROR (-22842) +%define VERR_ASN1_TIME_NORMALIZE_MISMATCH (-22843) +%define VERR_ASN1_INVALID_UTC_TIME_ENCODING (-22844) +%define VERR_ASN1_INVALID_GENERALIZED_TIME_ENCODING (-22845) +%define VERR_ASN1_INVALID_BOOLEAN_ENCODING (-22846) +%define VERR_ASN1_INVALID_NULL_ENCODING (-22847) +%define VERR_ASN1_INVALID_BITSTRING_ENCODING (-22848) +%define VERR_ASN1_DYNTYPE_TAG_NOT_IMPL (-22849) +%define VERR_ASN1_DYNTYPE_BAD_TAG (-22850) +%define VERR_ASN1_DUMMY_OBJECT (-22851) +%define VERR_ASN1_TOO_LONG (-22852) +%define VERR_ASN1_EXPECTED_PRIMITIVE (-22853) +%define VERR_ASN1_INVALID_DATA_POINTER (-22854) +%define VERR_ASN1_TOO_DEEPLY_NESTED (-22855) +%define VERR_ASN1_UNEXPECTED_OBJ_ID (-22856) +%define VERR_ASN1_INVALID_INTEGER_ENCODING (-22857) +%define VERR_ASN1_INTERNAL_ERROR_1 (-22895) +%define VERR_ASN1_INTERNAL_ERROR_2 (-22896) +%define VERR_ASN1_INTERNAL_ERROR_3 (-22897) +%define VERR_ASN1_INTERNAL_ERROR_4 (-22898) +%define VERR_ASN1_INTERNAL_ERROR_5 (-22899) +%define VERR_LDRVI_NOT_SIGNED (-22900) +%define VINF_LDRVI_NOT_SIGNED (22900) +%define VERR_LDRVI_READ_ERROR_HDR (-22901) +%define VERR_LDRVI_READ_ERROR_SHDRS (-22902) +%define VERR_LDRVI_READ_ERROR_SIGNATURE (-22903) +%define VERR_LDRVI_READ_ERROR_HASH (-22904) +%define VERR_LDRVI_FILE_LENGTH_ERROR (-22905) +%define VERR_LDRVI_NO_MEMORY_STATE (-22906) +%define VERR_LDRVI_NO_MEMORY_SIGNATURE (-22907) +%define VERR_LDRVI_NO_MEMORY_SHDRS (-22908) +%define VERR_LDRVI_NO_MEMORY_PARSE_OUTPUT (-22909) +%define VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY (-22910) +%define VERR_LDRVI_BAD_CERT_HDR_LENGTH (-22911) +%define VERR_LDRVI_BAD_CERT_HDR_REVISION (-22912) +%define VERR_LDRVI_BAD_CERT_HDR_TYPE (-22913) +%define VERR_LDRVI_BAD_CERT_MULTIPLE (-22914) +%define VERR_LDRVI_BAD_MZ_OFFSET (-22915) +%define VERR_LDRVI_INVALID_SECTION_COUNT (-22916) +%define VERR_LDRVI_SECTION_RAW_DATA_VALUES (-22917) +%define VERR_LDRVI_MACHINE_OPT_HDR_MAGIC_MISMATCH (-22918) +%define VERR_LDRVI_UNSUPPORTED_ARCH (-22919) +%define VERR_LDRVI_PARSE_IPE (-22921) +%define VERR_LDRVI_PARSE_BER_ERROR (-22922) +%define VERR_LDRVI_EXPECTED_INDIRECT_DATA_CONTENT_OID (-22923) +%define VERR_LDRVI_PAGE_HASH_TAB_SIZE_OVERFLOW (-22924) +%define VERR_LDRVI_PAGE_HASH_TAB_TOO_LONG (-22925) +%define VERR_LDRVI_PAGE_HASH_TAB_NOT_STRICTLY_SORTED (-22926) +%define VERR_PAGE_HASH_TAB_HASHES_NON_SECTION_DATA (-22927) +%define VERR_LDRVI_PAGE_HASH_MISMATCH (-22928) +%define VERR_LDRVI_IMAGE_HASH_MISMATCH (-22929) +%define VERR_LDRVI_BAD_CERT_FORMAT (-22930) +%define VERR_LDR_FORWARDER (-22950) +%define VERR_LDR_NOT_FORWARDER (-22951) +%define VERR_LDR_BAD_FORWARDER (-22952) +%define VERR_LDR_FORWARDER_CHAIN_TOO_LONG (-22953) +%define VERR_LDR_FORWARDERS_NOT_SUPPORTED (-22954) +%define VERR_LDRMACHO_OTHER_ENDIAN_NOT_SUPPORTED (-22955) +%define VERR_LDRMACHO_BAD_HEADER (-22956) +%define VERR_LDRMACHO_UNSUPPORTED_FILE_TYPE (-22957) +%define VERR_LDRMACHO_UNSUPPORTED_MACHINE (-22958) +%define VERR_LDRMACHO_BAD_LOAD_COMMAND (-22959) +%define VERR_LDRMACHO_UNKNOWN_LOAD_COMMAND (-22960) +%define VERR_LDRMACHO_UNSUPPORTED_LOAD_COMMAND (-22961) +%define VERR_LDRMACHO_BAD_SECTION (-22962) +%define VERR_LDRMACHO_UNSUPPORTED_SECTION (-22963) +%define VERR_LDRMACHO_UNSUPPORTED_INIT_SECTION (-22964) +%define VERR_LDRMACHO_UNSUPPORTED_TERM_SECTION (-22965) +%define VERR_LDRMACHO_UNKNOWN_SECTION (-22966) +%define VERR_LDRMACHO_BAD_SECTION_ORDER (-22967) +%define VERR_LDRMACHO_BIT_MIX (-22968) +%define VERR_LDRMACHO_BAD_OBJECT_FILE (-22969) +%define VERR_LDRMACHO_BAD_SYMBOL (-22970) +%define VERR_LDRMACHO_UNSUPPORTED_FIXUP_TYPE (-22971) +%define VERR_LDRMACHO_MIXED_DEBUG_SECTION_FLAGS (-22972) +%define VERR_LDRMACHO_NON_CONT_SEG_BITS (-22973) +%define VERR_LDRMACHO_TODO (-22974) +%define VERR_LDRMACHO_BAD_SYMTAB_SIZE (-22975) +%define VERR_LDR_DUPLICATE_SEGMENT_NAME (-22976) +%define VERR_LDR_NO_IMAGE_UUID (-22977) +%define VERR_LDR_BAD_FIXUP (-22978) +%define VERR_LDR_ADDRESS_OVERFLOW (-22979) +%define VERR_LDRLX_BAD_HEADER (-22980) +%define VERR_LDRLX_BAD_LOADER_SECTION (-22981) +%define VERR_LDRLX_BAD_FIXUP_SECTION (-22982) +%define VERR_LDRLX_BAD_OBJECT_TABLE (-22983) +%define VERR_LDRLX_BAD_PAGE_MAP (-22984) +%define VERR_LDRLX_BAD_ITERDATA (-22985) +%define VERR_LDRLX_BAD_ITERDATA2 (-22986) +%define VERR_LDRLX_BAD_BUNDLE (-22987) +%define VERR_LDRLX_NO_SONAME (-22988) +%define VERR_LDRLX_BAD_SONAME (-22989) +%define VERR_LDRLX_BAD_FORWARDER (-22990) +%define VERR_LDRLX_NRICHAIN_NOT_SUPPORTED (-22991) +%define VERR_LDRLX_IMPORT_ORDINAL_OUT_OF_BOUNDS (-22992) +%define VERR_CR_X509_GENERIC_ERROR (-23000) +%define VERR_CR_X509_INTERNAL_ERROR (-23001) +%define VERR_CR_X509_CERTPATHS_INTERNAL_ERROR (-23002) +%define VERR_CR_X509_NOT_VERIFIED (-23003) +%define VERR_CR_X509_NO_TRUST_ANCHOR (-23004) +%define VERR_CR_X509_UNKNOWN_CERT_SIGN_ALGO (-23005) +%define VERR_CR_X509_CERT_SIGN_ALGO_MISMATCH (-23006) +%define VERR_CR_X509_CERT_TBS_SIGN_ALGO_MISMATCH (-23007) +%define VERR_CR_X509_TBSCERT_EXTS_REQ_V3 (-23008) +%define VERR_CR_X509_TBSCERT_UNIQUE_IDS_REQ_V2 (-23009) +%define VERR_CR_X509_TBSCERT_SERIAL_NUMBER_OUT_OF_BOUNDS (-23010) +%define VERR_CR_X509_TBSCERT_UNSUPPORTED_VERSION (-23011) +%define VERR_CR_X509_PUBLIC_KEY_TOO_SMALL (-23012) +%define VERR_CR_X509_INVALID_NAME_STRING_TAG (-23013) +%define VERR_CR_X509_NAME_EMPTY_STRING (-23014) +%define VERR_CR_X509_NAME_NOT_STRING (-23015) +%define VERR_CR_X509_NAME_EMPTY_SET (-23016) +%define VERR_CR_X509_NAME_EMPTY_SUB_SET (-23017) +%define VERR_CR_X509_VALIDITY_SWAPPED (-23018) +%define VERR_CR_X509_TBSCERT_DUPLICATE_EXTENSION (-23019) +%define VERR_CR_X509_NAME_MISSING_RDN_MAP_ENTRY (-23020) +%define VERR_CR_X509_CPV_NO_TRUSTED_PATHS (-23021) +%define VERR_CR_X509_CPV_NO_VALID_POLICY (-23022) +%define VERR_CR_X509_CPV_UNKNOWN_CRITICAL_EXTENSION (-23023) +%define VERR_CR_X509_CPV_MISSING_KEY_CERT_SIGN (-23024) +%define VERR_CR_X509_CPV_MAX_PATH_LENGTH (-23025) +%define VERR_CR_X509_CPV_NOT_CA_CERT (-23026) +%define VERR_CR_X509_CPV_NOT_V3_CERT (-23027) +%define VERR_CR_X509_CPV_INVALID_POLICY_MAPPING (-23028) +%define VERR_CR_X509_CPV_NO_PERMITTED_NAMES (-23029) +%define VERR_CR_X509_CPV_NAME_NOT_PERMITTED (-23030) +%define VERR_CR_X509_CPV_ALT_NAME_NOT_PERMITTED (-23031) +%define VERR_CR_X509_CPV_ISSUER_MISMATCH (-23032) +%define VERR_CR_X509_CPV_NOT_VALID_AT_TIME (-23033) +%define VERR_CR_X509_CPV_UNEXP_GENERAL_SUBTREE_CHOICE (-23034) +%define VERR_CR_X509_CPV_UNEXP_GENERAL_SUBTREE_MIN (-23035) +%define VERR_CR_X509_CPV_UNEXP_GENERAL_SUBTREE_MAX (-23036) +%define VERR_CR_X509_CPB_BAD_CERT_CTX (-23037) +%define VERR_CR_X509_OSSL_D2I_FAILED (-23090) +%define VERR_CR_PKCS7_GENERIC_ERROR (-23300) +%define VERR_CR_PKCS7_NO_SIGNER_INFOS (-23301) +%define VERR_CR_PKCS7_SIGNED_DATA_CERT_NOT_FOUND (-23302) +%define VERR_CR_PKCS7_KEY_USAGE_MISMATCH (-23303) +%define VERR_CR_PKCS7_MISSING_CONTENT_TYPE_ATTRIB (-23304) +%define VERR_CR_PKCS7_CONTENT_TYPE_ATTRIB_MISMATCH (-23305) +%define VERR_CR_PKCS7_BAD_CONTENT_TYPE_ATTRIB (-23306) +%define VERR_CR_PKCS7_MISSING_MESSAGE_DIGEST_ATTRIB (-23307) +%define VERR_CR_PKCS7_MESSAGE_DIGEST_ATTRIB_MISMATCH (-23308) +%define VERR_CR_PKCS7_BAD_MESSAGE_DIGEST_ATTRIB (-23309) +%define VERR_CR_PKCS7_SIGNATURE_VERIFICATION_FAILED (-23310) +%define VERR_CR_PKCS7_INTERNAL_ERROR (-22311) +%define VERR_CR_PKCS7_OSSL_D2I_FAILED (-22312) +%define VERR_CR_PKCS7_OSSL_VERIFY_FAILED (-22313) +%define VERR_CR_PKCS7_DIGEST_PARAMS_NOT_IMPL (-22314) +%define VERR_CR_PKCS7_DIGEST_ALGO_NOT_FOUND_IN_LIST (-22315) +%define VERR_CR_PKCS7_NOT_SIGNED_DATA (-22316) +%define VERR_CR_PKCS7_NO_DIGEST_ALGORITHMS (-22317) +%define VERR_CR_PKCS7_TOO_MANY_DIGEST_ALGORITHMS (-22318) +%define VERR_CR_PKCS7_DIGEST_CREATE_ERROR (-22319) +%define VERR_CR_PKCS7_DIGEST_CALC_ERROR (-22320) +%define VERR_CR_PKCS7_SIGNED_DATA_VERSION (-22350) +%define VERR_CR_PKCS7_SIGNED_DATA_NO_DIGEST_ALGOS (-22351) +%define VERR_CR_PKCS7_UNKNOWN_DIGEST_ALGORITHM (-22352) +%define VERR_CR_PKCS7_NO_CERTIFICATES (-22353) +%define VERR_CR_PKCS7_EXPECTED_NO_CRLS (-22354) +%define VERR_CR_PKCS7_EXPECTED_ONE_SIGNER_INFO (-22355) +%define VERR_CR_PKCS7_SIGNER_INFO_VERSION (-22356) +%define VERR_CR_PKCS7_SIGNER_INFO_NO_ISSUER_SERIAL_NO (-22357) +%define VERR_CR_PKCS7_SIGNER_CERT_NOT_SHIPPED (-22358) +%define VERR_CR_PKCS7_SIGNER_INFO_DIGEST_ENCRYPT_MISMATCH (-22359) +%define VERR_CR_PKCS7_NOT_DATA (-22360) +%define VERR_CR_SPC_GENERIC_ERROR (-23400) +%define VERR_CR_SPC_NOT_EXACTLY_ONE_SIGNER_INFOS (-23401) +%define VERR_CR_SPC_NOT_EXACTLY_ONE_DIGEST_ALGO (-23402) +%define VERR_CR_SPC_SIGNED_IND_DATA_DIGEST_ALGO_MISMATCH (-23403) +%define VERR_CR_SPC_IND_DATA_DIGEST_ALGO_NOT_IN_DIGEST_ALGOS (-23404) +%define VERR_CR_SPC_UNKNOWN_DIGEST_ALGO (-23405) +%define VERR_CR_SPC_IND_DATA_DIGEST_SIZE_MISMATCH (-23406) +%define VERR_CR_SPC_EXPECTED_PE_IMAGE_DATA (-23407) +%define VERR_CR_SPC_PEIMAGE_DATA_NOT_PRESENT (-23408) +%define VERR_CR_SPC_BAD_MONIKER_UUID (-23409) +%define VERR_CR_SPC_UNKNOWN_MONIKER_UUID (-23410) +%define VERR_CR_SPC_BAD_MONIKER_CHOICE (-23411) +%define VERR_CR_SPC_MONIKER_BAD_DATA (-23412) +%define VERR_CR_SPC_PEIMAGE_MULTIPLE_HASH_TABS (-23413) +%define VERR_CR_SPC_PEIMAGE_UNKNOWN_ATTRIBUTE (-23414) +%define VERR_CR_SPC_PEIMAGE_URL_UNEXPECTED (-23415) +%define VERR_CR_SPC_PEIMAGE_NO_CONTENT (-23416) +%define VERR_CR_PKIX_GENERIC_ERROR (-23500) +%define VERR_CR_PKIX_SIGNATURE_TAKES_NO_PARAMETERS (-23501) +%define VERR_CR_PKIX_UNKNOWN_DIGEST_TYPE (-23502) +%define VERR_CR_PKIX_INTERNAL_ERROR (-23503) +%define VERR_CR_PKIX_HASH_TOO_LONG_FOR_KEY (-23504) +%define VERR_CR_PKIX_SIGNATURE_TOO_LONG (-23505) +%define VERR_CR_PKIX_SIGNATURE_GE_KEY (-23506) +%define VERR_CR_PKIX_SIGNATURE_NEGATIVE (-23507) +%define VERR_CR_PKIX_INVALID_SIGNATURE_LENGTH (-23508) +%define VERR_CR_PKIX_SIGNATURE_MISMATCH (-23509) +%define VERR_CR_PKIX_CIPHER_ALGO_PARAMS_NOT_IMPL (-23510) +%define VERR_CR_PKIX_CIPHER_ALGO_NOT_KNOWN (-23511) +%define VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN (-23512) +%define VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN_EVP (-23513) +%define VERR_CR_PKIX_OSSL_CIPHER_ALOG_INIT_FAILED (-23514) +%define VERR_CR_PKIX_OSSL_VERIFY_FINAL_FAILED (-23515) +%define VERR_CR_PKIX_OSSL_D2I_PUBLIC_KEY_FAILED (-23516) +%define VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR (-23517) +%define VERR_CR_PKIX_OSSL_D2I_PRIVATE_KEY_FAILED (-23518) +%define VERR_CR_PKIX_OSSL_EVP_PKEY_RSA_PAD_ERROR (-23519) +%define VERR_CR_PKIX_OSSL_SIGN_FINAL_FAILED (-23520) +%define VERR_CR_PKIX_OSSL_VS_IPRT_SIGNATURE_SIZE (-23521) +%define VERR_CR_PKIX_OSSL_VS_IPRT_SIGNATURE (-23522) +%define VERR_CR_PKIX_NOT_RSA_PRIVATE_KEY (-23523) +%define VERR_CR_PKIX_NOT_RSA_PUBLIC_KEY (-23524) +%define VERR_CR_STORE_GENERIC_ERROR (-23700) +%define VERR_CR_KEY_UNKNOWN_TYPE (-23800) +%define VERR_CR_KEY_FORMAT_NOT_SUPPORTED (-23801) +%define VERR_CR_KEY_ENCRYPTED (-23802) +%define VERR_CR_KEY_NO_DEK_INFO (-23803) +%define VERR_CR_KEY_DEK_INFO_TOO_LONG (-23804) +%define VERR_CR_KEY_DECRYPTION_NOT_SUPPORTED (-23805) +%define VERR_CR_KEY_UNSUPPORTED_CIPHER (-23806) +%define VERR_CR_KEY_UNEXPECTED_CIPHER_PARAMS (-23807) +%define VERR_CR_KEY_MISSING_CIPHER_PARAMS (-23808) +%define VERR_CR_KEY_TOO_SHORT_CIPHER_IV (-23809) +%define VERR_CR_KEY_MALFORMED_CIPHER_IV (-23810) +%define VERR_CR_KEY_PASSWORD_ENCODING (-23811) +%define VERR_CR_KEY_OSSL_DECRYPT_INIT_ERROR (-23812) +%define VERR_CR_KEY_DECRYPTION_FAILED (-23813) +%define VINF_CR_KEY_WAS_DECRYPTED (23814) +%define VERR_CR_KEY_GEN_FAILED_RSA (-23815) +%define VERR_CR_RSA_GENERIC_ERROR (-23900) +%define VERR_BIGNUM_SENSITIVE_INPUT (-24000) +%define VERR_BIGNUM_DIV_BY_ZERO (-24001) +%define VERR_BIGNUM_NEGATIVE_EXPONENT (-24002) +%define VERR_CR_DIGEST_OSSL_DIGEST_INIT_ERROR (-24200) +%define VERR_CR_DIGEST_OSSL_DIGEST_CTX_COPY_ERROR (-24201) +%define VINF_CR_DIGEST_DEPRECATED (24202) +%define VERR_CR_DIGEST_DEPRECATED (-24202) +%define VINF_CR_DIGEST_COMPROMISED (24203) +%define VERR_CR_DIGEST_COMPROMISED (-24203) +%define VINF_CR_DIGEST_SEVERELY_COMPROMISED (24204) +%define VERR_CR_DIGEST_SEVERELY_COMPROMISED (-24204) +%define VERR_CR_DIGEST_NOT_SUPPORTED (-24205) +%define VERR_CR_PASSWORD_2_KEY_DERIVIATION_FAILED (-24396) +%define VERR_CR_RANDOM_SETUP_FAILED (-24397) +%define VERR_CR_RANDOM_FAILED (-24398) +%define VERR_CR_MALFORMED_PEM_HEADER (-24399) +%define VERR_PATH_MATCH_UNKNOWN_VARIABLE (-24400) +%define VERR_PATH_MATCH_VARIABLE_MUST_BE_FIRST (-24401) +%define VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED (-24402) +%define VERR_PATH_GLOB_UNKNOWN_CHAR_CLASS (-24403) +%define VERR_URI_EMPTY (-24600) +%define VERR_URI_TOO_SHORT (-24601) +%define VERR_URI_INVALID_SCHEME (-24602) +%define VERR_URI_INVALID_PORT_NUMBER (-24603) +%define VERR_URI_INVALID_ESCAPE_SEQ (-24604) +%define VERR_URI_ESCAPED_ZERO (-24605) +%define VERR_URI_ESCAPED_CHARS_NOT_VALID_UTF8 (-24606) +%define VERR_URI_INVALID_ESCAPED_UTF8_LEAD_BYTE (-24607) +%define VERR_URI_INVALID_ESCAPED_UTF8_CONTINUATION_BYTE (-24608) +%define VERR_URI_MISSING_UTF8_CONTINUATION_BYTE (-24609) +%define VERR_URI_NOT_FILE_SCHEME (-24610) +%define VERR_JSON_VALUE_INVALID_TYPE (-24700) +%define VERR_JSON_ITERATOR_END (-24701) +%define VERR_JSON_MALFORMED (-24702) +%define VERR_JSON_IS_EMPTY (-24703) +%define VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE (-24704) +%define VERR_JSON_MISSING_SURROGATE_PAIR (-24705) +%define VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE (-24706) +%define VERR_JSON_INVALID_CODEPOINT (-24707) +%define VERR_VFS_UNKNOWN_FORMAT (-24800) +%define VERR_VFS_BOGUS_FORMAT (-24801) +%define VERR_VFS_BOGUS_OFFSET (-24802) +%define VERR_VFS_UNSUPPORTED_FORMAT (-24803) +%define VERR_VFS_UNSUPPORTED_CREATE_TYPE (-24804) +%define VERR_ISOMK_BOOT_CAT_NO_VALIDATION_ENTRY (-25000) +%define VERR_ISOMK_BOOT_CAT_NO_DEFAULT_ENTRY (-25001) +%define VERR_ISOMK_BOOT_CAT_EXPECTED_SECTION_HEADER (-25002) +%define VERR_ISOMK_BOOT_CAT_EMPTY_ENTRY (-25003) +%define VERR_ISOMK_BOOT_CAT_INVALID_SECTION_SIZE (-25004) +%define VERR_ISOMK_BOOT_CAT_ERRATIC_ENTRY (-25005) +%define VERR_ISOMK_FILE_TOO_BIG_REQ_ISO_LEVEL_3 (-25006) +%define VERR_ISOMK_SYMLINK_REQ_ROCK_RIDGE (-25007) +%define VINF_ISOMK_SYMLINK_REQ_ROCK_RIDGE (25007) +%define VERR_ISOMK_SYMLINK_SUPPORT_DISABLED (-25008) +%define VERR_ISOMK_RR_NO_SPACE_FOR_CE (-25009) +%define VERR_ISOMK_IPE_RR_READ (-25010) +%define VERR_ISOMK_IPE_TABLE (-25011) +%define VERR_ISOMK_IPE_NAMESPACE_1 (-25012) +%define VERR_ISOMK_IPE_NAMESPACE_2 (-25013) +%define VERR_ISOMK_IPE_NAMESPACE_3 (-25014) +%define VERR_ISOMK_IPE_NAMESPACE_4 (-25015) +%define VERR_ISOMK_IPE_NAMESPACE_5 (-25016) +%define VERR_ISOMK_IPE_NAMESPACE_6 (-25017) +%define VERR_ISOMK_IPE_EMPTY_PATH (-25018) +%define VERR_ISOMK_IPE_EMPTY_COMPONENT (-25019) +%define VERR_ISOMK_IPE_ROOT_SLASH (-25020) +%define VERR_ISOMK_IPE_DESC_COUNT (-25021) +%define VERR_ISOMK_IPE_BUFFER_SIZE (-25022) +%define VERR_ISOMK_IPE_BOOT_CAT_FILE (-25023) +%define VERR_ISOMK_IPE_PRODUCE_TRANS_TBL (-25024) +%define VERR_ISOMK_IPE_READ_FILE_DATA_1 (-25025) +%define VERR_ISOMK_IPE_READ_FILE_DATA_2 (-25026) +%define VERR_ISOMK_IPE_READ_FILE_DATA_3 (-25027) +%define VERR_ISOMK_IPE_FINALIZE_1 (-25028) +%define VERR_ISOMK_RR_SPILL_FILE_FULL (-25029) +%define VERR_ISOMK_IMPORT_UNKNOWN_FORMAT (-25100) +%define VERR_ISOMK_IMPORT_TOO_MANY_VOL_DESCS (-25101) +%define VERR_ISOMK_IMPORT_INVALID_VOL_DESC_HDR (-25102) +%define VERR_ISOMK_IMPORT_MULTIPLE_PRIMARY_VOL_DESCS (-25103) +%define VERR_ISOMK_IMPORT_MULTIPLE_EL_TORITO_DESCS (-25104) +%define VERR_ISOMK_IMPORT_MULTIPLE_JOLIET_VOL_DESCS (-25105) +%define VERR_ISOMK_IMPORT_SUPPLEMENTARY_BEFORE_PRIMARY (-25106) +%define VERR_IOSMK_IMPORT_PRIMARY_VOL_DESC_VER (-25107) +%define VERR_ISOMK_IMPORT_BAD_PRIMARY_VOL_DESC (-25108) +%define VERR_IOSMK_IMPORT_SUP_VOL_DESC_VER (-25109) +%define VERR_ISOMK_IMPORT_BAD_SUP_VOL_DESC (-25110) +%define VERR_ISOMK_IMPORT_LOGICAL_BLOCK_SIZE_NOT_2KB (-25111) +%define VERR_ISOMK_IMPORT_MORE_THAN_ONE_VOLUME_IN_SET (-25112) +%define VERR_ISOMK_IMPORT_INVALID_VOLUMNE_SEQ_NO (-25113) +%define VERR_ISOMK_IMPORT_VOLUME_SPACE_SIZE_MISMATCH (-25114) +%define VERR_ISOMK_IMPORT_VOLUME_IN_SET_MISMATCH (-25115) +%define VERR_ISOMK_IMPORT_BAD_ROOT_DIR_REC (-25116) +%define VERR_ISOMK_IMPORT_ZERO_SIZED_ROOT_DIR (-25117) +%define VERR_ISOMK_IMPORT_ROOT_VOLUME_SEQ_NO (-25118) +%define VERR_ISOMK_IMPORT_ROOT_DIR_EXTENT_OUT_OF_BOUNDS (-25119) +%define VERR_ISOMK_IMPORT_BAD_ROOT_DIR_REC_LENGTH (-25120) +%define VERR_ISOMK_IMPORT_ROOT_DIR_WITHOUT_DIR_FLAG (-25121) +%define VERR_ISOMK_IMPORT_ROOT_DIR_IS_MULTI_EXTENT (-25122) +%define VERR_ISOMK_IMPORT_TOO_DEEP_DIR_TREE (-25123) +%define VERR_ISOMK_IMPORT_BAD_DIR_REC (-25124) +%define VERR_ISOMK_IMPORT_DIR_REC_VOLUME_SEQ_NO (-25125) +%define VERR_ISOMK_IMPORT_DIR_REC_EXTENT_OUT_OF_BOUNDS (-25126) +%define VERR_ISOMK_IMPORT_BAD_DIR_REC_LENGTH (-25127) +%define VERR_ISOMK_IMPORT_DOT_DIR_REC_BAD_NAME_LENGTH (-25128) +%define VERR_ISOMK_IMPORT_DOT_DIR_REC_BAD_NAME (-25129) +%define VERR_ISOMK_IMPORT_DIR_WITH_MORE_EXTENTS (-25130) +%define VERR_ISOMK_IMPORT_MISMATCHING_MULTI_EXTENT_REC (-25131) +%define VERR_ISOMK_IMPORT_MISALIGNED_MULTI_EXTENT (-25132) +%define VERR_ISOMK_IMPORT_NON_CONTIGUOUS_MULTI_EXTENT (-25133) +%define VERR_ISOMK_IMPORT_BOOT_CAT_BAD_OUT_OF_BOUNDS (-25140) +%define VERR_ISOMK_IMPORT_BOOT_CAT_BAD_VALIDATION_HEADER_ID (-25141) +%define VERR_ISOMK_IMPORT_BOOT_CAT_BAD_VALIDATION_KEYS (-25142) +%define VERR_ISOMK_IMPORT_BOOT_CAT_BAD_VALIDATION_CHECKSUM (-25143) +%define VERR_ISOMK_IMPORT_BOOT_CAT_UNKNOWN_HEADER_ID (-25144) +%define VERR_ISOMK_IMPORT_BOOT_CAT_INVALID_BOOT_MEDIA_TYPE (-25145) +%define VERR_ISOMK_IMPORT_BOOT_CAT_DEF_ENTRY_INVALID_FLAGS (-25146) +%define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_RESERVED_FLAG (-25147) +%define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_USES_UNUSED_FIELD (-25148) +%define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_IMAGE_OUT_OF_BOUNDS (-25149) +%define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_UNKNOWN_IMAGE_SIZE (-25150) +%define VERR_ISOMK_IMPORT_BOOT_CAT_MISSING_FINAL_OR_TOO_BIG (-25151) +%define VERR_ISOMK_IMPORT_BOOT_CAT_DEF_ENTRY_INVALID_BOOT_IND (-25152) +%define VERR_ISOMK_IMPORT_BOOT_CAT_EXT_ENTRY_INVALID_ID (-25153) +%define VERR_ISOMK_IMPORT_BOOT_CAT_EXT_ENTRY_UNDEFINED_FLAGS (-25154) +%define VERR_ISOMK_IMPORT_BOOT_CAT_EXT_ENTRY_END_OF_SECTOR (-25155) +%define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_CONTINUATION_WITH_NONE (-25156) +%define VERR_ISOMK_IMPORT_BOOT_CAT_ENTRY_CONTINUATION_EOS (-25157) +%define VERR_ISOFS_TAG_IS_ALL_ZEROS (-25300) +%define VERR_ISOFS_UNSUPPORTED_TAG_VERSION (-25301) +%define VERR_ISOFS_BAD_TAG_CHECKSUM (-25302) +%define VERR_ISOFS_TAG_SECTOR_MISMATCH (-25303) +%define VERR_ISOFS_DESC_CRC_MISMATCH (-25304) +%define VERR_ISOFS_INSUFFICIENT_DATA_FOR_DESC_CRC (-25305) +%define VERR_ISOFS_UNEXPECTED_VDS_DESC (-25306) +%define VERR_ISOFS_TOO_MANY_PVDS (-25307) +%define VERR_ISOFS_TOO_MANY_LVDS (-25308) +%define VERR_ISOFS_TOO_MANY_PDS (-25309) +%define VERR_ISOFS_TOO_BIT_PARTMAP_IN_LVD (-25310) +%define VERR_ISOFS_NO_PVD (-25311) +%define VERR_ISOFS_NO_LVD (-25312) +%define VERR_ISOFS_NO_PD (-25313) +%define VERR_ISOFS_MULTIPLE_PVDS (-25314) +%define VERR_ISOFS_MULTIPLE_LVDS (-25315) +%define VERR_ISOFS_TOO_MANY_PART_MAPS (-25316) +%define VERR_ISOFS_MALFORMED_PART_MAP_TABLE (-25317) +%define VERR_ISOFS_PARTITION_NOT_FOUND (-25318) +%define VERR_ISOFS_INCOMPLETE_PART_MAP_TABLE (-25319) +%define VERR_ISOFS_UNKNOWN_PART_MAP_ENTRY_TYPE (-25320) +%define VERR_ISOFS_UNKNOWN_PART_MAP_TYPE_ID (-25321) +%define VERR_ISOFS_VPM_NOT_SUPPORTED (-25322) +%define VERR_ISOFS_SPM_NOT_SUPPORTED (-25323) +%define VERR_ISOFS_MPM_NOT_SUPPORTED (-25324) +%define VERR_ISOFS_UNSUPPORTED_LOGICAL_BLOCK_SIZE (-25325) +%define VERR_ISOFS_BAD_LVD_DOMAIN_ID (-25326) +%define VERR_ISOFS_BAD_LVD_FILE_SET_DESC_LOCATION (-25327) +%define VERR_ISOFS_BAD_LVD_DESC_CHAR_SET (-25329) +%define VERR_ISOFS_INVALID_PARTITION_INDEX (-25330) +%define VERR_ISOFS_FSD_UNSUPPORTED_CHAR_SET (-25331) +%define VERR_ISOFS_FSD_ZERO_ROOT_DIR (-25332) +%define VERR_ISOFS_FSD_NEXT_EXTENT (-25333) +%define VERR_ISOFS_ICB_TOO_BIG (-25334) +%define VERR_ISOFS_ICB_TOO_SMALL (-25335) +%define VERR_ISOFS_NO_DIRECT_ICB_ENTRIES (-25336) +%define VERR_ISOFS_TOO_MANY_ICB_INDIRECTIONS (-25337) +%define VERR_ISOFS_TOO_DEEP_ICB_RECURSION (-25338) +%define VERR_ISOFS_ICB_ENTRY_TOO_SMALL (-25339) +%define VERR_ISOFS_UNSUPPORTED_ICB (-25340) +%define VERR_ISOFS_BAD_FILE_ENTRY (-25341) +%define VERR_ISO_FS_UNKNOWN_AD_TYPE (-25342) +%define VERR_ISOFS_BAD_EXTAD (-25343) +%define VERR_ISOFS_WRONG_FILE_TYPE (-25344) +%define VERR_ISOFS_UNKNOWN_FILE_TYPE (-25345) +%define VERR_ISOFS_UDF_NOT_IMPLEMENTED (-25390) +%define VERR_ISOFS_IPE_1 (-25391) +%define VERR_ISOFS_IPE_2 (-25392) +%define VERR_ISOFS_IPE_3 (-25393) +%define VERR_ISOFS_IPE_4 (-25394) +%define VERR_ISOFS_IPE_5 (-25395) +%define VERR_SERIALPORT_BREAK_DETECTED (-25500) +%define VERR_SERIALPORT_INVALID_BAUDRATE (-25501) +%define VERR_REST_RESPONSE_CONTENT_TYPE_NOT_SUPPORTED (-25700) +%define VERR_REST_RESPONSE_INVALID_UTF8_ENCODING (-25701) +%define VERR_REST_RESPONSE_EMBEDDED_ZERO_CHAR (-25702) +%define VERR_REST_RESPONSE_REPEAT_HEADER_FIELD (-25703) +%define VWRN_REST_UNABLE_TO_DECODE_DATE (25704) +%define VERR_REST_UNABLE_TO_DECODE_DATE (-25704) +%define VERR_REST_WRONG_JSON_TYPE_FOR_BOOL (-25705) +%define VERR_REST_WRONG_JSON_TYPE_FOR_INTEGER (-25706) +%define VERR_REST_WRONG_JSON_TYPE_FOR_DOUBLE (-25707) +%define VERR_REST_WRONG_JSON_TYPE_FOR_STRING (-25708) +%define VERR_REST_WRONG_JSON_TYPE_FOR_DATE (-25709) +%define VERR_REST_UNABLE_TO_PARSE_STRING_AS_BOOL (-25710) +%define VERR_REST_PATH_PARAMETER_NOT_SET (-25711) +%define VERR_REST_REQUIRED_QUERY_PARAMETER_NOT_SET (-25712) +%define VERR_REST_REQUIRED_HEADER_PARAMETER_NOT_SET (-25713) +%define VERR_REST_INTERNAL_ERROR_1 (-25791) +%define VERR_REST_INTERNAL_ERROR_2 (-25792) +%define VERR_REST_INTERNAL_ERROR_3 (-25793) +%define VERR_REST_INTERNAL_ERROR_4 (-25794) +%define VERR_REST_INTERNAL_ERROR_5 (-25795) +%define VERR_REST_INTERNAL_ERROR_6 (-25796) +%define VERR_REST_INTERNAL_ERROR_7 (-25797) +%define VERR_REST_INTERNAL_ERROR_8 (-25798) +%define VERR_REST_INTERNAL_ERROR_9 (-25799) +%define VERR_CR_CIPHER_NOT_SUPPORTED (-25800) +%define VERR_CR_CIPHER_OSSL_ENCRYPT_INIT_FAILED (-25801) +%define VERR_CR_CIPHER_OSSL_ENCRYPT_UPDATE_FAILED (-25802) +%define VERR_CR_CIPHER_OSSL_ENCRYPT_FINAL_FAILED (-25803) +%define VERR_CR_CIPHER_OSSL_DECRYPT_INIT_FAILED (-25804) +%define VERR_CR_CIPHER_OSSL_DECRYPT_UPDATE_FAILED (-25805) +%define VERR_CR_CIPHER_OSSL_DECRYPT_FINAL_FAILED (-25806) +%define VERR_CR_CIPHER_INVALID_KEY_LENGTH (-25807) +%define VERR_CR_CIPHER_INVALID_INITIALIZATION_VECTOR_LENGTH (-25808) +%define VERR_CR_CIPHER_INVALID_TAG_LENGTH (-25809) +%define VERR_CR_CIPHER_OSSL_GET_TAG_FAILED (-25810) +%define VERR_CR_CIPHER_OSSL_SET_TAG_FAILED (-25811) +%define VERR_SHMEM_MAXIMUM_MAPPINGS_REACHED (-26000) +%define VERR_IOQUEUE_HANDLE_NOT_REGISTERED (-26200) +%define VERR_IOQUEUE_FULL (-26201) +%define VERR_IOQUEUE_EMPTY (-26202) +%define VERR_IOQUEUE_BUSY (-26203) +%define VERR_FTP_STATUS_SERVER_ERROR (-26400) +%define VERR_FTP_INIT_FAILED (-26401) +%define VERR_FTP_DATA_CONN_INIT_FAILED (-26402) +%define VERR_FTP_DATA_CONN_NOT_FOUND (-26403) +%define VERR_FTP_DATA_CONN_LIMIT_REACHED (-26404) +%define VERR_FTP_CLIENT_NOT_FOUND (-26405) +%define VERR_FTP_CLIENT_LIMIT_REACHED (-26406) +%define VERR_TRACELOG_READER_MALFORMED_LOG (-26600) +%define VERR_TRACELOG_READER_LOG_UNSUPPORTED (-26601) +%define VERR_TRACELOG_READER_ITERATOR_END (-26602) +%define VERR_HARDAVL_INDEX_OUT_OF_BOUNDS (-26801) +%define VERR_HARDAVL_POINTER_OUT_OF_BOUNDS (-26802) +%define VERR_HARDAVL_MISALIGNED_POINTER (-26803) +%define VERR_HARDAVL_NODE_IS_FREE (-26804) +%define VERR_HARDAVL_STACK_OVERFLOW (-26810) +%define VERR_HARDAVL_INSERT_INVALID_KEY_RANGE (-26811) +%define VERR_HARDAVL_BAD_LEFT_HEIGHT (-26812) +%define VERR_HARDAVL_BAD_RIGHT_HEIGHT (-26813) +%define VERR_HARDAVL_BAD_NEW_HEIGHT (-26814) +%define VERR_HARDAVL_UNEXPECTED_NULL_LEFT (-26815) +%define VERR_HARDAVL_UNEXPECTED_NULL_RIGHT (-26816) +%define VERR_HARDAVL_TRAVERSED_TOO_MANY_NODES (-26817) +%define VERR_HARDAVL_LOOKUP_TOO_DEEP (-26818) +%define VERR_HARDAVL_BAD_HEIGHT (-26819) +%define VERR_HARDAVL_UNBALANCED (-26820) diff --git a/include/iprt/err.sed b/include/iprt/err.sed new file mode 100644 index 00000000..e094b083 --- /dev/null +++ b/include/iprt/err.sed @@ -0,0 +1,55 @@ +## @file +# IPRT - SED script for converting VBox/err.h to .mac. +# + +# +# Copyright (C) 2006-2022 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# The contents of this file may alternatively be used under the terms +# of the Common Development and Distribution License Version 1.0 +# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +# in the VirtualBox 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. +# +# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +# + +# Handle text inside the markers. +/SED-START/,/SED-END/{ + +# if (#define) goto defines +/^[[:space:]]*#[[:space:]]*define/b defines + +} + +# Everything else is deleted! +d +b end + +## +# Convert the defines +:defines +s/^[[:space:]]*#[[:space:]]*define[[:space:]]*\([[:alnum:]_]*\)[[:space:]]*\(.*\)[[:space:]]*$/%define \1 \2/ +b end + +# next expression +:end diff --git a/include/iprt/errcore.h b/include/iprt/errcore.h new file mode 100644 index 00000000..12a09c1c --- /dev/null +++ b/include/iprt/errcore.h @@ -0,0 +1,947 @@ +/** @file + * IPRT - Status Codes Core. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_errcore_h +#define IPRT_INCLUDED_errcore_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/stdarg.h> + + +/** @defgroup grp_rt_err_core Status Codes Core + * @ingroup grp_rt_err + * @{ + */ + +/** @def RTERR_STRICT_RC + * Indicates that RT_SUCCESS_NP, RT_SUCCESS, RT_FAILURE_NP and RT_FAILURE should + * make type enforcing at compile time. + * + * @remarks Only define this for C++ code. + */ +#if defined(__cplusplus) \ + && !defined(RTERR_STRICT_RC) \ + && !defined(RTERR_NO_STRICT_RC) \ + && ( defined(DOXYGEN_RUNNING) \ + || defined(DEBUG) \ + || defined(RT_STRICT) ) +# define RTERR_STRICT_RC 1 +#endif + + +/** @def RT_SUCCESS + * Check for success. We expect success in normal cases, that is the code path depending on + * this check is normally taken. To prevent any prediction use RT_SUCCESS_NP instead. + * + * @returns true if rc indicates success. + * @returns false if rc indicates failure. + * + * @param rc The iprt status code to test. + */ +#define RT_SUCCESS(rc) ( RT_LIKELY(RT_SUCCESS_NP(rc)) ) + +/** @def RT_SUCCESS_NP + * Check for success. Don't predict the result. + * + * @returns true if rc indicates success. + * @returns false if rc indicates failure. + * + * @param rc The iprt status code to test. + */ +#ifdef RTERR_STRICT_RC +# define RT_SUCCESS_NP(rc) ( RTErrStrictType(rc).success() ) +#else +# define RT_SUCCESS_NP(rc) ( (int)(rc) >= VINF_SUCCESS ) +#endif + +/** @def RT_FAILURE + * Check for failure, predicting unlikely. + * + * We don't expect in normal cases, that is the code path depending on this + * check is normally NOT taken. To prevent any prediction use RT_FAILURE_NP + * instead. + * + * @returns true if rc indicates failure. + * @returns false if rc indicates success. + * + * @param rc The iprt status code to test. + * + * @remarks Please structure your code to use the RT_SUCCESS() macro instead of + * RT_FAILURE() where possible, as that gives us a better shot at good + * code with the windows compilers. + */ +#define RT_FAILURE(rc) ( RT_UNLIKELY(!RT_SUCCESS_NP(rc)) ) + +/** @def RT_FAILURE_NP + * Check for failure, no prediction. + * + * @returns true if rc indicates failure. + * @returns false if rc indicates success. + * + * @param rc The iprt status code to test. + */ +#define RT_FAILURE_NP(rc) ( !RT_SUCCESS_NP(rc) ) + + +#ifdef __cplusplus +/** + * Strict type validation class. + * + * This is only really useful for type checking the arguments to RT_SUCCESS, + * RT_SUCCESS_NP, RT_FAILURE and RT_FAILURE_NP. The RTErrStrictType2 + * constructor is for integration with external status code strictness regimes. + */ +class RTErrStrictType +{ +protected: + int32_t m_rc; + +public: + /** + * Constructor for interaction with external status code strictness regimes. + * + * This is a special constructor for helping external return code validator + * classes interact cleanly with RT_SUCCESS, RT_SUCCESS_NP, RT_FAILURE and + * RT_FAILURE_NP while barring automatic cast to integer. + * + * @param rcObj IPRT status code object from an automatic cast. + */ + RTErrStrictType(RTErrStrictType2 const rcObj) RT_NO_THROW_DEF + : m_rc(rcObj.getValue()) + { + } + + /** + * Integer constructor used by RT_SUCCESS_NP. + * + * @param rc IPRT style status code. + */ + RTErrStrictType(int32_t rc) RT_NO_THROW_DEF + : m_rc(rc) + { + } + +#if 0 /** @todo figure where int32_t is long instead of int. */ + /** + * Integer constructor used by RT_SUCCESS_NP. + * + * @param rc IPRT style status code. + */ + RTErrStrictType(signed int rc) + : m_rc(rc) + { + } +#endif + + /** + * Test for success. + */ + bool success() const RT_NO_THROW_DEF + { + return m_rc >= 0; + } + +private: + /** @name Try ban a number of wrong types. + * @{ */ + RTErrStrictType(uint8_t rc) RT_NO_THROW_DEF : m_rc(-999) { NOREF(rc); } + RTErrStrictType(uint16_t rc) RT_NO_THROW_DEF : m_rc(-999) { NOREF(rc); } + RTErrStrictType(uint32_t rc) RT_NO_THROW_DEF : m_rc(-999) { NOREF(rc); } + RTErrStrictType(uint64_t rc) RT_NO_THROW_DEF : m_rc(-999) { NOREF(rc); } + RTErrStrictType(int8_t rc) RT_NO_THROW_DEF : m_rc(-999) { NOREF(rc); } + RTErrStrictType(int16_t rc) RT_NO_THROW_DEF : m_rc(-999) { NOREF(rc); } + RTErrStrictType(int64_t rc) RT_NO_THROW_DEF : m_rc(-999) { NOREF(rc); } + /** @todo fight long here - clashes with int32_t/int64_t on some platforms. */ + /** @} */ +}; +#endif /* __cplusplus */ + + +RT_C_DECLS_BEGIN + +/** + * Converts a Darwin HRESULT error to an iprt status code. + * + * @returns iprt status code. + * @param iNativeCode HRESULT error code. + * @remark Darwin ring-3 only. + */ +RTDECL(int) RTErrConvertFromDarwinCOM(int32_t iNativeCode); + +/** + * Converts a Darwin IOReturn error to an iprt status code. + * + * @returns iprt status code. + * @param iNativeCode IOReturn error code. + * @remark Darwin only. + */ +RTDECL(int) RTErrConvertFromDarwinIO(int iNativeCode); + +/** + * Converts a Darwin kern_return_t error to an iprt status code. + * + * @returns iprt status code. + * @param iNativeCode kern_return_t error code. + * @remark Darwin only. + */ +RTDECL(int) RTErrConvertFromDarwinKern(int iNativeCode); + +/** + * Converts a Darwin error to an iprt status code. + * + * This will consult RTErrConvertFromDarwinKern, RTErrConvertFromDarwinIO + * and RTErrConvertFromDarwinCOM in this order. The latter is ring-3 only as it + * doesn't apply elsewhere. + * + * @returns iprt status code. + * @param iNativeCode Darwin error code. + * @remarks Darwin only. + * @remarks This is recommended over RTErrConvertFromDarwinKern and RTErrConvertFromDarwinIO + * since these are really just subsets of the same error space. + */ +RTDECL(int) RTErrConvertFromDarwin(int iNativeCode); + +/** + * Converts errno to iprt status code. + * + * @returns iprt status code. + * @param iNativeCode errno code. + */ +RTDECL(int) RTErrConvertFromErrno(int iNativeCode); + +/** + * Converts a L4 errno to a iprt status code. + * + * @returns iprt status code. + * @param uNativeCode l4 errno. + * @remark L4 only. + */ +RTDECL(int) RTErrConvertFromL4Errno(unsigned uNativeCode); + +/** + * Converts NT status code to iprt status code. + * + * Needless to say, this is only available on NT and winXX targets. + * + * @returns iprt status code. + * @param lNativeCode NT status code. + * @remark Windows only. + */ +RTDECL(int) RTErrConvertFromNtStatus(long lNativeCode); + +/** + * Converts OS/2 error code to iprt status code. + * + * @returns iprt status code. + * @param uNativeCode OS/2 error code. + * @remark OS/2 only. + */ +RTDECL(int) RTErrConvertFromOS2(unsigned uNativeCode); + +/** + * Converts Win32 error code to iprt status code. + * + * @returns iprt status code. + * @param uNativeCode Win32 error code. + * @remark Windows only. + */ +RTDECL(int) RTErrConvertFromWin32(unsigned uNativeCode); + +/** + * Converts an iprt status code to a errno status code. + * + * @returns errno status code. + * @param iErr iprt status code. + */ +RTDECL(int) RTErrConvertToErrno(int iErr); + + +#ifndef DECLARED_FNRTSTROUTPUT /* duplicated in iprt/string.h & iprt/log.h */ +#define DECLARED_FNRTSTROUTPUT +/** + * Output callback. + * + * @returns number of bytes written. + * @param pvArg User argument. + * @param pachChars Pointer to an array of utf-8 characters. + * @param cbChars Number of bytes in the character array pointed to by pachChars. + */ +typedef DECLCALLBACKTYPE(size_t, FNRTSTROUTPUT,(void *pvArg, const char *pachChars, size_t cbChars)); +/** Pointer to callback function. */ +typedef FNRTSTROUTPUT *PFNRTSTROUTPUT; +#endif + +#ifdef IN_RING3 + +RTDECL(bool) RTErrIsKnown(int rc); +RTDECL(ssize_t) RTErrQueryDefine(int rc, char *pszBuf, size_t cbBuf, bool fFailIfUnknown); +RTDECL(ssize_t) RTErrQueryMsgShort(int rc, char *pszBuf, size_t cbBuf, bool fFailIfUnknown); +RTDECL(ssize_t) RTErrQueryMsgFull(int rc, char *pszBuf, size_t cbBuf, bool fFailIfUnknown); + +/** @name Error formatters used internally by RTStrFormat. + * @internal + * @{ */ +RTDECL(size_t) RTErrFormatDefine( int rc, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, char *pszTmp, size_t cbTmp); +RTDECL(size_t) RTErrFormatMsgShort(int rc, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, char *pszTmp, size_t cbTmp); +RTDECL(size_t) RTErrFormatMsgFull( int rc, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, char *pszTmp, size_t cbTmp); +RTDECL(size_t) RTErrFormatMsgAll( int rc, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, char *pszTmp, size_t cbTmp); +/** @} */ + + +# ifdef RT_OS_WINDOWS +/** + * Windows error code message. + */ +typedef struct RTWINERRMSG +{ + /** Pointer to the full message string. */ + const char *pszMsgFull; + /** Pointer to the define string. */ + const char *pszDefine; + /** Error code number. */ + long iCode; +} RTWINERRMSG; +/** Pointer to Windows error code message. */ +typedef RTWINERRMSG *PRTWINERRMSG; +/** Pointer to const Windows error code message. */ +typedef const RTWINERRMSG *PCRTWINERRMSG; + +RTDECL(bool) RTErrWinIsKnown(long rc); +RTDECL(ssize_t) RTErrWinQueryDefine(long rc, char *pszBuf, size_t cbBuf, bool fFailIfUnknown); + +/** @name Error formatters used internally by RTStrFormat. + * @internal + * @{ */ +RTDECL(size_t) RTErrWinFormatDefine(long rc, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, char *pszTmp, size_t cbTmp); +RTDECL(size_t) RTErrWinFormatMsg( long rc, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, char *pszTmp, size_t cbTmp); +RTDECL(size_t) RTErrWinFormatMsgAll(long rc, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, char *pszTmp, size_t cbTmp); +/** @} */ + +# else /* !RT_OS_WINDOWS */ + +/** + * COM/XPCOM error code message. + */ +typedef struct RTCOMERRMSG +{ + /** Pointer to the full message string. */ + const char *pszMsgFull; + /** Pointer to the define string. */ + const char *pszDefine; + /** Error code number. */ + uint32_t iCode; +} RTCOMERRMSG; +/** Pointer to a XPCOM/COM error code message. */ +typedef RTCOMERRMSG *PRTCOMERRMSG; +/** Pointer to const a XPCOM/COM error code message. */ +typedef const RTCOMERRMSG *PCRTCOMERRMSG; + +/** + * Get the message structure corresponding to a given COM/XPCOM error code. + * + * @returns Pointer to read-only message description. + * @param rc The status code. + */ +RTDECL(PCRTCOMERRMSG) RTErrCOMGet(uint32_t rc); + +# endif /* !RT_OS_WINDOWS */ + +#endif /* IN_RING3 */ + +/** @defgroup RTERRINFO_FLAGS_XXX RTERRINFO::fFlags + * @{ */ +/** Custom structure (the default). */ +#define RTERRINFO_FLAGS_T_CUSTOM UINT32_C(0) +/** Static structure (RTERRINFOSTATIC). */ +#define RTERRINFO_FLAGS_T_STATIC UINT32_C(1) +/** Allocated structure (RTErrInfoAlloc). */ +#define RTERRINFO_FLAGS_T_ALLOC UINT32_C(2) +/** Reserved type. */ +#define RTERRINFO_FLAGS_T_RESERVED UINT32_C(3) +/** Type mask. */ +#define RTERRINFO_FLAGS_T_MASK UINT32_C(3) +/** Error info is set. */ +#define RTERRINFO_FLAGS_SET RT_BIT_32(2) +/** Fixed flags (magic). */ +#define RTERRINFO_FLAGS_MAGIC UINT32_C(0xbabe0000) +/** The bit mask for the magic value. */ +#define RTERRINFO_FLAGS_MAGIC_MASK UINT32_C(0xffff0000) +/** @} */ + +/** + * Initializes an error info structure. + * + * @returns @a pErrInfo. + * @param pErrInfo The error info structure to init. + * @param pszMsg The message buffer. Must be at least one byte. + * @param cbMsg The size of the message buffer. + */ +DECLINLINE(PRTERRINFO) RTErrInfoInit(PRTERRINFO pErrInfo, char *pszMsg, size_t cbMsg) +{ + *pszMsg = '\0'; + + pErrInfo->fFlags = RTERRINFO_FLAGS_T_CUSTOM | RTERRINFO_FLAGS_MAGIC; + pErrInfo->rc = /*VINF_SUCCESS*/ 0; + pErrInfo->pszMsg = pszMsg; + pErrInfo->cbMsg = cbMsg; + pErrInfo->apvReserved[0] = NULL; + pErrInfo->apvReserved[1] = NULL; + + return pErrInfo; +} + +/** + * Initialize a static error info structure. + * + * @returns Pointer to the core error info structure. + * @param pStaticErrInfo The static error info structure to init. + */ +DECLINLINE(PRTERRINFO) RTErrInfoInitStatic(PRTERRINFOSTATIC pStaticErrInfo) +{ + RTErrInfoInit(&pStaticErrInfo->Core, pStaticErrInfo->szMsg, sizeof(pStaticErrInfo->szMsg)); + pStaticErrInfo->Core.fFlags = RTERRINFO_FLAGS_T_STATIC | RTERRINFO_FLAGS_MAGIC; + return &pStaticErrInfo->Core; +} + +/** + * Allocates a error info structure with a buffer at least the given size. + * + * @returns Pointer to an error info structure on success, NULL on failure. + * + * @param cbMsg The minimum message buffer size. Use 0 to get + * the default buffer size. + */ +RTDECL(PRTERRINFO) RTErrInfoAlloc(size_t cbMsg); + +/** + * Same as RTErrInfoAlloc, except that an IPRT status code is returned. + * + * @returns IPRT status code. + * + * @param cbMsg The minimum message buffer size. Use 0 to get + * the default buffer size. + * @param ppErrInfo Where to store the pointer to the allocated + * error info structure on success. This is + * always set to NULL. + */ +RTDECL(int) RTErrInfoAllocEx(size_t cbMsg, PRTERRINFO *ppErrInfo); + +/** + * Frees an error info structure allocated by RTErrInfoAlloc or + * RTErrInfoAllocEx. + * + * @param pErrInfo The error info structure. + */ +RTDECL(void) RTErrInfoFree(PRTERRINFO pErrInfo); + +/** + * Fills in the error info details. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param pszMsg The error message string. + */ +RTDECL(int) RTErrInfoSet(PRTERRINFO pErrInfo, int rc, const char *pszMsg); + +/** + * Fills in the error info details, with a sprintf style message. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param pszFormat The format string. + * @param ... The format arguments. + */ +RTDECL(int) RTErrInfoSetF(PRTERRINFO pErrInfo, int rc, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Fills in the error info details, with a vsprintf style message. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param pszFormat The format string. + * @param va The format arguments. + */ +RTDECL(int) RTErrInfoSetV(PRTERRINFO pErrInfo, int rc, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Adds more error info details. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param pszMsg The error message string to add. + */ +RTDECL(int) RTErrInfoAdd(PRTERRINFO pErrInfo, int rc, const char *pszMsg); + +/** + * Adds more error info details, with a sprintf style message. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param pszFormat The format string to add. + * @param ... The format arguments. + */ +RTDECL(int) RTErrInfoAddF(PRTERRINFO pErrInfo, int rc, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Adds more error info details, with a vsprintf style message. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param pszFormat The format string to add. + * @param va The format arguments. + */ +RTDECL(int) RTErrInfoAddV(PRTERRINFO pErrInfo, int rc, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** @name RTERRINFO_LOG_F_XXX + * @{ */ +/** Both debug and release log. */ +#define RTERRINFO_LOG_F_RELEASE RT_BIT_32(0) +/** @} */ + +/** + * Fills in the error info details. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param iLogGroup The logging group. + * @param fFlags RTERRINFO_LOG_F_XXX. + * @param pszMsg The error message string. + */ +RTDECL(int) RTErrInfoLogAndSet(PRTERRINFO pErrInfo, int rc, uint32_t iLogGroup, uint32_t fFlags, const char *pszMsg); + +/** + * Fills in the error info details, with a sprintf style message. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param iLogGroup The logging group. + * @param fFlags RTERRINFO_LOG_F_XXX. + * @param pszFormat The format string. + * @param ... The format arguments. + */ +RTDECL(int) RTErrInfoLogAndSetF(PRTERRINFO pErrInfo, int rc, uint32_t iLogGroup, uint32_t fFlags, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6); + +/** + * Fills in the error info details, with a vsprintf style message. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param iLogGroup The logging group. + * @param fFlags RTERRINFO_LOG_F_XXX. + * @param pszFormat The format string. + * @param va The format arguments. + */ +RTDECL(int) RTErrInfoLogAndSetV(PRTERRINFO pErrInfo, int rc, uint32_t iLogGroup, uint32_t fFlags, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0); + +/** + * Adds more error info details. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param iLogGroup The logging group. + * @param fFlags RTERRINFO_LOG_F_XXX. + * @param pszMsg The error message string to add. + */ +RTDECL(int) RTErrInfoLogAndAdd(PRTERRINFO pErrInfo, int rc, uint32_t iLogGroup, uint32_t fFlags, const char *pszMsg); + +/** + * Adds more error info details, with a sprintf style message. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param iLogGroup The logging group. + * @param fFlags RTERRINFO_LOG_F_XXX. + * @param pszFormat The format string to add. + * @param ... The format arguments. + */ +RTDECL(int) RTErrInfoLogAndAddF(PRTERRINFO pErrInfo, int rc, uint32_t iLogGroup, uint32_t fFlags, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6); + +/** + * Adds more error info details, with a vsprintf style message. + * + * @returns @a rc. + * + * @param pErrInfo The error info structure to fill in. + * @param rc The status code to return. + * @param iLogGroup The logging group. + * @param fFlags RTERRINFO_LOG_F_XXX. + * @param pszFormat The format string to add. + * @param va The format arguments. + */ +RTDECL(int) RTErrInfoLogAndAddV(PRTERRINFO pErrInfo, int rc, uint32_t iLogGroup, uint32_t fFlags, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0); + +/** @name Macros wrapping the RTErrInfoLog* functions. + * @{ */ +#ifndef LOG_DISABLED +# define RTERRINFO_LOG_SET( a_pErrInfo, a_rc, a_pszMsg) RTErrInfoLogAndSet( a_pErrInfo, a_rc, LOG_GROUP, 0, a_pszMsg) +# define RTERRINFO_LOG_SET_V(a_pErrInfo, a_rc, a_pszMsg, a_va) RTErrInfoLogAndSetV(a_pErrInfo, a_rc, LOG_GROUP, 0, a_pszMsg, a_va) +# define RTERRINFO_LOG_ADD( a_pErrInfo, a_rc, a_pszMsg) RTErrInfoLogAndAdd( a_pErrInfo, a_rc, LOG_GROUP, 0, a_pszMsg) +# define RTERRINFO_LOG_ADD_V(a_pErrInfo, a_rc, a_pszMsg, a_va) RTErrInfoLogAndAddV(a_pErrInfo, a_rc, LOG_GROUP, 0, a_pszMsg, a_va) +# ifdef RT_COMPILER_SUPPORTS_VA_ARGS +# define RTERRINFO_LOG_ADD_F(a_pErrInfo, a_rc, ...) RTErrInfoLogAndAddF(a_pErrInfo, a_rc, LOG_GROUP, 0, __VA_ARGS__) +# define RTERRINFO_LOG_SET_F(a_pErrInfo, a_rc, ...) RTErrInfoLogAndSetF(a_pErrInfo, a_rc, LOG_GROUP, 0, __VA_ARGS__) +# else +# define RTERRINFO_LOG_ADD_F RTErrInfoAddF +# define RTERRINFO_LOG_SET_F RTErrInfoSetF +# endif +#else +# define RTERRINFO_LOG_SET( a_pErrInfo, a_rc, a_pszMsg) RTErrInfoSet( a_pErrInfo, a_rc, a_pszMsg) +# define RTERRINFO_LOG_SET_V(a_pErrInfo, a_rc, a_pszMsg, a_va) RTErrInfoSetV(a_pErrInfo, a_rc, a_pszMsg, a_va) +# define RTERRINFO_LOG_ADD( a_pErrInfo, a_rc, a_pszMsg) RTErrInfoAdd( a_pErrInfo, a_rc, a_pszMsg) +# define RTERRINFO_LOG_ADD_V(a_pErrInfo, a_rc, a_pszMsg, a_va) RTErrInfoAddV(a_pErrInfo, a_rc, a_pszMsg, a_va) +# define RTERRINFO_LOG_ADD_F RTErrInfoAddF +# define RTERRINFO_LOG_SET_F RTErrInfoSetF +#endif + +#define RTERRINFO_LOG_REL_SET( a_pErrInfo, a_rc, a_pszMsg) RTErrInfoLogAndSet( a_pErrInfo, a_rc, LOG_GROUP, RTERRINFO_LOG_F_RELEASE, a_pszMsg) +#define RTERRINFO_LOG_REL_SET_V(a_pErrInfo, a_rc, a_pszMsg, a_va) RTErrInfoLogAndSetV(a_pErrInfo, a_rc, LOG_GROUP, RTERRINFO_LOG_F_RELEASE, a_pszMsg, a_va) +#define RTERRINFO_LOG_REL_ADD( a_pErrInfo, a_rc, a_pszMsg) RTErrInfoLogAndAdd( a_pErrInfo, a_rc, LOG_GROUP, RTERRINFO_LOG_F_RELEASE, a_pszMsg) +#define RTERRINFO_LOG_REL_ADD_V(a_pErrInfo, a_rc, a_pszMsg, a_va) RTErrInfoLogAndAddV(a_pErrInfo, a_rc, LOG_GROUP, RTERRINFO_LOG_F_RELEASE, a_pszMsg, a_va) +#ifdef RT_COMPILER_SUPPORTS_VA_ARGS +# define RTERRINFO_LOG_REL_ADD_F(a_pErrInfo, a_rc, ...) RTErrInfoLogAndAddF(a_pErrInfo, a_rc, LOG_GROUP, RTERRINFO_LOG_F_RELEASE, __VA_ARGS__) +# define RTERRINFO_LOG_REL_SET_F(a_pErrInfo, a_rc, ...) RTErrInfoLogAndSetF(a_pErrInfo, a_rc, LOG_GROUP, RTERRINFO_LOG_F_RELEASE, __VA_ARGS__) +#else +# define RTERRINFO_LOG_REL_ADD_F RTErrInfoAddF +# define RTERRINFO_LOG_REL_SET_F RTErrInfoSetF +#endif +/** @} */ + + +/** + * Checks if the error info is set. + * + * @returns true if set, false if not. + * @param pErrInfo The error info structure. NULL is OK. + */ +DECLINLINE(bool) RTErrInfoIsSet(PCRTERRINFO pErrInfo) +{ + if (!pErrInfo) + return false; + return (pErrInfo->fFlags & (RTERRINFO_FLAGS_MAGIC_MASK | RTERRINFO_FLAGS_SET)) + == (RTERRINFO_FLAGS_MAGIC | RTERRINFO_FLAGS_SET); +} + +/** + * Clears the error info structure. + * + * @param pErrInfo The error info structure. NULL is OK. + */ +DECLINLINE(void) RTErrInfoClear(PRTERRINFO pErrInfo) +{ + if (pErrInfo) + { + pErrInfo->fFlags &= ~RTERRINFO_FLAGS_SET; + pErrInfo->rc = /*VINF_SUCCESS*/0; + *pErrInfo->pszMsg = '\0'; + } +} + +/** + * Storage for error variables. + * + * @remarks Do NOT touch the members! They are platform specific and what's + * where may change at any time! + */ +typedef union RTERRVARS +{ + int8_t ai8Vars[32]; + int16_t ai16Vars[16]; + int32_t ai32Vars[8]; + int64_t ai64Vars[4]; +} RTERRVARS; +/** Pointer to an error variable storage union. */ +typedef RTERRVARS *PRTERRVARS; +/** Pointer to a const error variable storage union. */ +typedef RTERRVARS const *PCRTERRVARS; + +/** + * Saves the error variables. + * + * @returns @a pVars. + * @param pVars The variable storage union. + */ +RTDECL(PRTERRVARS) RTErrVarsSave(PRTERRVARS pVars); + +/** + * Restores the error variables. + * + * @param pVars The variable storage union. + */ +RTDECL(void) RTErrVarsRestore(PCRTERRVARS pVars); + +/** + * Checks if the first variable set equals the second. + * + * @returns true if they are equal, false if not. + * @param pVars1 The first variable storage union. + * @param pVars2 The second variable storage union. + */ +RTDECL(bool) RTErrVarsAreEqual(PCRTERRVARS pVars1, PCRTERRVARS pVars2); + +/** + * Checks if the (live) error variables have changed since we saved them. + * + * @returns @c true if they have changed, @c false if not. + * @param pVars The saved variables to compare the current state + * against. + */ +RTDECL(bool) RTErrVarsHaveChanged(PCRTERRVARS pVars); + +RT_C_DECLS_END + + +/* We duplicate a handful of very commonly used status codes from err.h here. + Needless to say, these needs to match the err.h definition exactly: */ + +/** Success. + * @ingroup grp_rt_err */ +#define VINF_SUCCESS 0 + +/** General failure - DON'T USE THIS!!! + * @ingroup grp_rt_err */ +#define VERR_GENERAL_FAILURE (-1) +/** Invalid parameter. + * @ingroup grp_rt_err */ +#define VERR_INVALID_PARAMETER (-2) +/** Invalid parameter. + * @ingroup grp_rt_err */ +#define VWRN_INVALID_PARAMETER 2 +/** Invalid magic or cookie. + * @ingroup grp_rt_err */ +#define VERR_INVALID_MAGIC (-3) +/** Invalid magic or cookie. + * @ingroup grp_rt_err */ +#define VWRN_INVALID_MAGIC 3 +/** Invalid loader handle. + * @ingroup grp_rt_err */ +#define VERR_INVALID_HANDLE (-4) +/** Invalid loader handle. + * @ingroup grp_rt_err */ +#define VWRN_INVALID_HANDLE 4 +/** Invalid memory pointer. */ +#define VERR_INVALID_POINTER (-6) +/** Memory allocation failed. + * @ingroup grp_rt_err */ +#define VERR_NO_MEMORY (-8) +/** Permission denied. + * @ingroup grp_rt_err */ +#define VERR_PERMISSION_DENIED (-10) +/** Permission denied. + * @ingroup grp_rt_err */ +#define VINF_PERMISSION_DENIED 10 +/** Version mismatch. + * @ingroup grp_rt_err */ +#define VERR_VERSION_MISMATCH (-11) +/** The request function is not implemented. + * @ingroup grp_rt_err */ +#define VERR_NOT_IMPLEMENTED (-12) +/** Invalid flags was given. + * @ingroup grp_rt_err */ +#define VERR_INVALID_FLAGS (-13) +/** Incorrect call order. + * @ingroup grp_rt_err */ +#define VERR_WRONG_ORDER (-22) +/** Invalid function. + * @ingroup grp_rt_err */ +#define VERR_INVALID_FUNCTION (-36) +/** Not supported. + * @ingroup grp_rt_err */ +#define VERR_NOT_SUPPORTED (-37) +/** Not supported. + * @ingroup grp_rt_err */ +#define VINF_NOT_SUPPORTED 37 +/** Access denied. + * @ingroup grp_rt_err */ +#define VERR_ACCESS_DENIED (-38) +/** Call interrupted. + * @ingroup grp_rt_err */ +#define VERR_INTERRUPTED (-39) +/** Call interrupted. + * @ingroup grp_rt_err */ +#define VINF_INTERRUPTED 39 +/** Timeout. + * @ingroup grp_rt_err */ +#define VERR_TIMEOUT (-40) +/** Timeout. + * @ingroup grp_rt_err */ +#define VINF_TIMEOUT 40 +/** Buffer too small to save result. + * @ingroup grp_rt_err */ +#define VERR_BUFFER_OVERFLOW (-41) +/** Buffer too small to save result. + * @ingroup grp_rt_err */ +#define VINF_BUFFER_OVERFLOW 41 +/** Data size overflow. + * @ingroup grp_rt_err */ +#define VERR_TOO_MUCH_DATA (-42) +/** Retry the operation. + * @ingroup grp_rt_err */ +#define VERR_TRY_AGAIN (-52) +/** Retry the operation. + * @ingroup grp_rt_err */ +#define VINF_TRY_AGAIN 52 +/** Generic parse error. + * @ingroup grp_rt_err */ +#define VERR_PARSE_ERROR (-53) +/** Value out of range. + * @ingroup grp_rt_err */ +#define VERR_OUT_OF_RANGE (-54) +/** A numeric conversion encountered a value which was too big for the target. + * @ingroup grp_rt_err */ +#define VERR_NUMBER_TOO_BIG (-55) +/** A numeric conversion encountered a value which was too big for the target. + * @ingroup grp_rt_err */ +#define VWRN_NUMBER_TOO_BIG 55 +/** The operation was cancelled by the user (copy) or another thread (local ipc). + * @ingroup grp_rt_err */ +#define VERR_CANCELLED (-70) +/** Trailing characters. + * @ingroup grp_rt_err */ +#define VERR_TRAILING_CHARS (-76) +/** Trailing characters. + * @ingroup grp_rt_err */ +#define VWRN_TRAILING_CHARS 76 +/** Trailing spaces. + * @ingroup grp_rt_err */ +#define VERR_TRAILING_SPACES (-77) +/** Trailing spaces. + * @ingroup grp_rt_err */ +#define VWRN_TRAILING_SPACES 77 +/** Generic not found error. + * @ingroup grp_rt_err */ +#define VERR_NOT_FOUND (-78) +/** Generic not found warning. + * @ingroup grp_rt_err */ +#define VWRN_NOT_FOUND 78 +/** Generic invalid state error. + * @ingroup grp_rt_err */ +#define VERR_INVALID_STATE (-79) +/** Generic invalid state warning. + * @ingroup grp_rt_err */ +#define VWRN_INVALID_STATE 79 +/** Generic out of resources error. + * @ingroup grp_rt_err */ +#define VERR_OUT_OF_RESOURCES (-80) +/** Generic out of resources warning. + * @ingroup grp_rt_err */ +#define VWRN_OUT_OF_RESOURCES 80 +/** End of string. + * @ingroup grp_rt_err */ +#define VERR_END_OF_STRING (-83) +/** Return instigated by a callback or similar. + * @ingroup grp_rt_err */ +#define VERR_CALLBACK_RETURN (-88) +/** Return instigated by a callback or similar. + * @ingroup grp_rt_err */ +#define VINF_CALLBACK_RETURN 88 +/** Duplicate something. + * @ingroup grp_rt_err */ +#define VERR_DUPLICATE (-98) +/** Something is missing. + * @ingroup grp_rt_err */ +#define VERR_MISSING (-99) +/** Buffer underflow. + * @ingroup grp_rt_err */ +#define VERR_BUFFER_UNDERFLOW (-22401) +/** Buffer underflow. + * @ingroup grp_rt_err */ +#define VINF_BUFFER_UNDERFLOW 22401 +/** Something is not available or not working properly. + * @ingroup grp_rt_err */ +#define VERR_NOT_AVAILABLE (-22403) +/** Mismatch. + * @ingroup grp_rt_err */ +#define VERR_MISMATCH (-22408) +/** Wrong type. + * @ingroup grp_rt_err */ +#define VERR_WRONG_TYPE (-22409) +/** Wrong type. + * @ingroup grp_rt_err */ +#define VWRN_WRONG_TYPE (22409) +/** Wrong parameter count. + * @ingroup grp_rt_err */ +#define VERR_WRONG_PARAMETER_COUNT (-22415) +/** Wrong parameter type. + * @ingroup grp_rt_err */ +#define VERR_WRONG_PARAMETER_TYPE (-22416) +/** Invalid client ID. + * @ingroup grp_rt_err */ +#define VERR_INVALID_CLIENT_ID (-22417) +/** Invalid session ID. + * @ingroup grp_rt_err */ +#define VERR_INVALID_SESSION_ID (-22418) +/** Incompatible configuration requested. + * @ingroup grp_rt_err */ +#define VERR_INCOMPATIBLE_CONFIG (-22420) +/** Internal error - this should never happen. + * @ingroup grp_rt_err */ +#define VERR_INTERNAL_ERROR (-225) +/** RTGetOpt: Not an option. + * @ingroup grp_rt_err */ +#define VINF_GETOPT_NOT_OPTION 828 +/** RTGetOpt: Command line option not recognized. + * @ingroup grp_rt_err */ +#define VERR_GETOPT_UNKNOWN_OPTION (-825) + +/** @} */ + +#endif /* !IPRT_INCLUDED_errcore_h */ + diff --git a/include/iprt/errno.h b/include/iprt/errno.h new file mode 100644 index 00000000..f41e677b --- /dev/null +++ b/include/iprt/errno.h @@ -0,0 +1,441 @@ +/** @file + * IPRT - errno.h wrapper. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_errno_h +#define IPRT_INCLUDED_errno_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef IPRT_NO_CRT +# if defined(RT_OS_DARWIN) && defined(KERNEL) +# include <sys/errno.h> +# elif defined(RT_OS_LINUX) && defined(__KERNEL__) +# include <linux/errno.h> +# elif defined(RT_OS_FREEBSD) && defined(_KERNEL) +# include <sys/errno.h> +# elif defined(RT_OS_NETBSD) && defined(_KERNEL) +# include <sys/errno.h> +# else +# include <errno.h> +# endif +#endif + + +/* + * Supply missing errno values according to the current RT_OS_XXX definition. + * + * Note! These supplements are for making no-CRT mode, as well as making UNIXy + * code that makes used of odd errno defines internally, work smoothly. + * + * When adding more error codes, always check the following errno.h sources: + * - RT_OS_DARWIN: http://fxr.watson.org/fxr/source/bsd/sys/errno.h?v=xnu-1699.24.8 + * - RT_OS_FREEBSD: http://fxr.watson.org/fxr/source/sys/errno.h?v=DFBSD + * - RT_OS_NETBSD: http://fxr.watson.org/fxr/source/sys/errno.h?v=NETBSD + * - RT_OS_OPENBSD: http://fxr.watson.org/fxr/source/sys/errno.h?v=OPENBSD + * - RT_OS_OS2: http://svn.netlabs.org/libc/browser/trunk/libc/include/sys/errno.h + * - RT_OS_LINUX: http://fxr.watson.org/fxr/source/include/asm-generic/errno.h?v=linux-2.6 + * - RT_OS_SOLARIS: http://fxr.watson.org/fxr/source/common/sys/errno.h?v=OPENSOLARIS + * - RT_OS_WINDOWS: tools/win.x86/vcc/v8sp1/include/errno.h + */ + +#if defined(RT_OS_DARWIN) \ + || defined(RT_OS_FREEBSD) \ + || defined(RT_OS_NETBSD) \ + || defined(RT_OS_OPENBSD) \ + || defined(RT_OS_OS2) +# define RT_ERRNO_OS_BSD +#endif +#ifdef RT_OS_SOLARIS +# define RT_ERRNO_OS_SYSV_HARDCORE /* ?? */ +#endif + +/* The relatively similar part. */ +#ifndef EPERM +# define EPERM (1) +#endif +#ifndef ENOENT +# define ENOENT (2) +#endif +#ifndef ESRCH +# define ESRCH (3) +#endif +#ifndef EINTR +# define EINTR (4) +#endif +#ifndef EIO +# define EIO (5) +#endif +#ifndef ENXIO +# define ENXIO (6) +#endif +#ifndef E2BIG +# define E2BIG (7) +#endif +#ifndef ENOEXEC +# define ENOEXEC (8) +#endif +#ifndef EBADF +# define EBADF (9) +#endif +#ifndef ECHILD +# define ECHILD (10) +#endif +#ifndef EAGAIN +# if defined(RT_ERRNO_OS_BSD) +# define EAGAIN (35) +# else +# define EAGAIN (11) +# endif +#endif +#ifndef EWOULDBLOCK +# define EWOULDBLOCK EAGAIN +#endif +#ifndef EDEADLK +# if defined(RT_ERRNO_OS_BSD) +# define EDEADLK (11) +# elif defined(RT_OS_LINUX) +# define EDEADLK (35) +# elif defined(RT_OS_WINDOWS) +# define EDEADLK (36) +# else +# define EDEADLK (45) /* solaris */ +# endif +#endif +#ifndef EDEADLOCK +# define EDEADLOCK EDEADLK +#endif +#ifndef ENOMEM +# define ENOMEM (12) +#endif +#ifndef EACCES +# define EACCES (13) +#endif +#ifndef EFAULT +# define EFAULT (14) +#endif +#ifndef ENOTBLK +# define ENOTBLK (15) +#endif +#ifndef EBUSY +# define EBUSY (16) +#endif +#ifndef EEXIST +# define EEXIST (17) +#endif +#ifndef EXDEV +# define EXDEV (18) +#endif +#ifndef ENODEV +# define ENODEV (19) +#endif +#ifndef ENOTDIR +# define ENOTDIR (20) +#endif +#ifndef EISDIR +# define EISDIR (21) +#endif +#ifndef EINVAL +# define EINVAL (22) +#endif +#ifndef ENFILE +# define ENFILE (23) +#endif +#ifndef EMFILE +# define EMFILE (24) +#endif +#ifndef ENOTTY +# define ENOTTY (25) +#endif +#ifndef ETXTBSY +# define ETXTBSY (26) +#endif +#ifndef EFBIG +# define EFBIG (27) +#endif +#ifndef ENOSPC +# define ENOSPC (28) +#endif +#ifndef ESPIPE +# define ESPIPE (29) +#endif +#ifndef EROFS +# define EROFS (30) +#endif +#ifndef EMLINK +# define EMLINK (31) +#endif +#ifndef EPIPE +# define EPIPE (32) +#endif +#ifndef EDOM +# define EDOM (33) +#endif +#ifndef ERANGE +# define ERANGE (34) +#endif + +/* 35 - also EAGAIN on BSD and EDEADLK on Linux. */ +#ifndef ENOMSG +# if defined(RT_OS_DARWIN) +# define ENOMSG (91) +# elif defined(RT_OS_FREEBSD) +# define ENOMSG (83) +# elif defined(RT_OS_LINUX) +# define ENOMSG (42) +# elif defined(RT_OS_WINDOWS) +# define ENOMSG (122) +# else +# define ENOMSG (35) +# endif +#endif + +/* 36 - Also EDEADLK on Windows. */ +#ifndef EIDRM +# if defined(RT_OS_DARWIN) +# define EIDRM (90) +# elif defined(RT_OS_FREEBSD) || defined(RT_OS_NETBSD) +# define EIDRM (82) +# elif defined(RT_OS_OPENBSD) +# define EIDRM (89) +# elif defined(RT_OS_LINUX) +# define EIDRM (43) +# elif defined(RT_OS_WINDOWS) +# define EIDRM (111) +# else +# define EIDRM (36) +# endif +#endif +#ifndef EINPROGRESS +# if defined(RT_ERRNO_OS_BSD) +# define EINPROGRESS (36) +# elif defined(RT_OS_LINUX) +# define EINPROGRESS (115) +# elif defined(RT_OS_WINDOWS) +# define EINPROGRESS (112) +# else +# define EINPROGRESS (150) /* solaris */ +# endif +#endif +#ifndef ENAMETOOLONG +# if defined(RT_ERRNO_OS_BSD) +# define ENAMETOOLONG (63) +# elif defined(RT_OS_LINUX) +# define ENAMETOOLONG (36) +# elif defined(RT_OS_WINDOWS) +# define ENAMETOOLONG (38) +# else +# define ENAMETOOLONG (78) /* solaris */ +# endif +#endif + +/* 37 */ +#ifndef ECHRNG +# if defined(RT_ERRNO_OS_SYSV_HARDCORE) +# define ECHRNG (37) +# else +# define ECHRNG (599) +# endif +#endif +#ifndef ENOLCK +# if defined(RT_ERRNO_OS_BSD) +# define ENOLCK (77) +# elif defined(RT_OS_LINUX) +# define ENOLCK (37) +# elif defined(RT_OS_WINDOWS) +# define ENOLCK (39) +# else +# define ENOLCK (46) +# endif +#endif +#ifndef EALREADY +# if defined(RT_ERRNO_OS_BSD) +# define EALREADY (37) +# elif defined(RT_OS_LINUX) +# define EALREADY (114) +# elif defined(RT_OS_WINDOWS) +# define EALREADY (103) +# else +# define EALREADY (149) +# endif +#endif + +/* 38 - Also ENAMETOOLONG on Windows. */ +#ifndef ENOSYS +# if defined(RT_ERRNO_OS_BSD) +# define ENOSYS (78) +# elif defined(RT_OS_LINUX) +# define ENOSYS (38) +# elif defined(RT_OS_WINDOWS) +# define ENOSYS (40) +# else +# define ENOSYS (89) /* solaris */ +# endif +#endif +#ifndef ENOTSOCK +# if defined(RT_ERRNO_OS_BSD) +# define ENOTSOCK (38) +# elif defined(RT_OS_LINUX) +# define ENOTSOCK (88) +# elif defined(RT_OS_WINDOWS) +# define ENOTSOCK (128) +# else +# define ENOTSOCK (95) /* solaris */ +# endif +#endif +#ifndef EL2NSYNC +# if defined(RT_OS_LINUX) +# define EL2NSYNC (45) +# elif defined(RT_ERRNO_OS_SYSV_HARDCORE) +# define EL2NSYNC (38) /* solaris */ +# endif +#endif + +/* 39 - Also ENOLCK on Windows. */ +#ifndef ENOTEMPTY +# if defined(RT_ERRNO_OS_BSD) +# define ENOTEMPTY (66) +# elif defined(RT_OS_LINUX) +# define ENOTEMPTY (39) +# elif defined(RT_OS_WINDOWS) +# define ENOTEMPTY (41) +# else +# define ENOTEMPTY (93) /* solaris */ +# endif +#endif +#ifndef EDESTADDRREQ +# if defined(RT_ERRNO_OS_BSD) +# define EDESTADDRREQ (39) +# elif defined(RT_OS_LINUX) +# define EDESTADDRREQ (89) +# elif defined(RT_OS_WINDOWS) +# define EDESTADDRREQ (109) +# else +# define EDESTADDRREQ (96) /* solaris */ +# endif +#endif +#ifndef EL3HLT +# if defined(RT_OS_LINUX) +# define EL3HLT (46) +# elif defined(RT_ERRNO_OS_SYSV_HARDCORE) +# define EL3HLT (39) /* solaris */ +# endif +#endif + +/* 40 - Also ENOSYS on Windows. */ +#ifndef ELOOP +# if defined(RT_ERRNO_OS_BSD) +# define ELOOP (62) +# elif defined(RT_OS_LINUX) +# define ELOOP (40) +# elif defined(RT_OS_WINDOWS) +# define ELOOP (114) +# else +# define ELOOP (90) /* solaris */ +# endif +#endif +#ifndef EMSGSIZE +# if defined(RT_ERRNO_OS_BSD) +# define EMSGSIZE (40) +# elif defined(RT_OS_LINUX) +# define EMSGSIZE (90) +# elif defined(RT_OS_WINDOWS) +# define EMSGSIZE (115) +# else +# define EMSGSIZE (97) /* solaris */ +# endif +#endif +#ifndef EL3RST +# if defined(RT_OS_LINUX) +# define EL3RST (47) +# elif defined(RT_ERRNO_OS_SYSV_HARDCORE) +# define EL3RST (40) /* solaris */ +# endif +#endif + +/** @todo errno constants {41..44}. */ + +/* 45 - also EDEADLK on Solaris, EL2NSYNC on Linux. */ +#ifndef ENOTSUP +# if defined(RT_ERRNO_OS_BSD) +# define ENOTSUP (45) +# elif defined(RT_OS_LINUX) +# define ENOTSUP (95) +# elif defined(RT_OS_WINDOWS) +# define ENOTSUP (129) +# else +# define ENOTSUP (48) +# endif +#endif +#ifndef EOPNOTSUPP +# if defined(RT_ERRNO_OS_BSD) +# define EOPNOTSUPP ENOTSUP +# elif defined(RT_OS_LINUX) +# define EOPNOTSUPP ENOTSUP +# elif defined(RT_OS_WINDOWS) +# define EOPNOTSUPP (130) +# else +# define EOPNOTSUPP (122) +# endif +#endif + +/** @todo errno constants {46..74}. */ + +/* 75 - note that Solaris has constant with value 75. */ +#ifndef EOVERFLOW +# if defined(RT_OS_OPENBSD) +# define EOVERFLOW (87) +# elif defined(RT_ERRNO_OS_BSD) +# define EOVERFLOW (84) +# elif defined(RT_OS_LINUX) +# define EOVERFLOW (75) +# elif defined(RT_OS_WINDOWS) +# define EOVERFLOW (132) +# else +# define EOVERFLOW (79) +# endif +#endif +#ifndef EPROGMISMATCH +# if defined(RT_ERRNO_OS_BSD) +# define EPROGMISMATCH (75) +# else +# define EPROGMISMATCH (598) +# endif +#endif + +/** @todo errno constants {76..}. */ + + +#endif /* !IPRT_INCLUDED_errno_h */ diff --git a/include/iprt/expreval.h b/include/iprt/expreval.h new file mode 100644 index 00000000..0ec98a59 --- /dev/null +++ b/include/iprt/expreval.h @@ -0,0 +1,159 @@ +/* $Id: expreval.h $ */ +/** @file + * IPRT - Expression Evaluator. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_expreval_h +#define IPRT_INCLUDED_expreval_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_expr_eval RTExprEval - Expression Evaluator + * @{ */ + +/** Handle to an expression evaluator. */ +typedef struct RTEXPREVALINT *RTEXPREVAL; +/** Pointer to an expression evaluator handle. */ +typedef RTEXPREVAL *PRTEXPREVAL; +/** NIL expression evaluator handle. */ +#define NIL_RTEXPREVAL ((RTEXPREVAL)~(uintptr_t)0) + +/** + * Variable getter (supplied by user). + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if the variable does not exist. + */ +typedef DECLCALLBACKTYPE(int, FNRTEXPREVALQUERYVARIABLE,(const char *pchName, size_t cchName, void *pvUser, char **ppszValue)); +/** Pointer to a variable getter. */ +typedef FNRTEXPREVALQUERYVARIABLE *PFNRTEXPREVALQUERYVARIABLE; + +/** @name Expression evaluator flags. + * @sa RTExprEvalCreate + * @{ */ +/** Default to hexadecimal instead of decimal numbers. */ +#define RTEXPREVAL_F_DEFAULT_BASE_16 RT_BIT_64(0) +/** Enables C-ish octal style, i.e. 0777 be read as 0x1ff (in hex). */ +#define RTEXPREVAL_F_C_OCTAL RT_BIT_64(1) +/** Enables the 'exists' operator that can be used to check if a path exists. + * @sa RTPathExists */ +#define RTEXPREVAL_F_EXISTS_OP RT_BIT_64(2) +/** Valid mask. */ +#define RTEXPREVAL_F_VALID_MASK UINT64_MAX(3) +/** @} */ + +/** + * Creates an expression evaluator. + * + * @returns IPRT status code. + * @param phEval Where to return the handle to the evaluator. + * @param fFlags RTEXPREVAL_F_XXX. + * @param pszName The evaluator name (for logging). + * @param pvUser User argument for callbacks. + * @param pfnQueryVariable Callback for querying variables. Optional. + */ +RTDECL(int) RTExprEvalCreate(PRTEXPREVAL phEval, uint64_t fFlags, const char *pszName, + void *pvUser, PFNRTEXPREVALQUERYVARIABLE pfnQueryVariable); + +/** + * Retains a reference to the evaluator. + * + * @returns New reference count, UINT32_MAX if @a hEval is not valid. + * @param hEval Handle to the evaluator. + */ +RTDECL(uint32_t) RTExprEvalRetain(RTEXPREVAL hEval); + +/** + * Releases a reference to the evaluator. + * + * @returns New reference count, UINT32_MAX if @a hEval is not valid. (The + * evaluator was destroyed when 0 is returned.) + * @param hEval Handle to the evaluator. + */ +RTDECL(uint32_t) RTExprEvalRelease(RTEXPREVAL hEval); + +/** + * Evaluates the given if expression to a boolean result. + * + * @returns IPRT status code + * @param hEval Handle to the evaluator. + * @param pch The expression string. Does not need to be zero + * terminated. + * @param cch The length of the expression. Pass RTSTR_MAX if not + * known. + * @param pfResult Where to return the result. + * @param pErrInfo Where to return additional error info. + */ +RTDECL(int) RTExprEvalToBool(RTEXPREVAL hEval, const char *pch, size_t cch, bool *pfResult, PRTERRINFO pErrInfo); + +/** + * Evaluates the given if expression to an integer (signed 64-bit) result. + * + * @returns IPRT status code + * @param hEval Handle to the evaluator. + * @param pch The expression string. Does not need to be zero + * terminated. + * @param cch The length of the expression. Pass RTSTR_MAX if not + * known. + * @param piResult Where to return the result. + * @param pErrInfo Where to return additional error info. + */ +RTDECL(int) RTExprEvalToInteger(RTEXPREVAL hEval, const char *pch, size_t cch, int64_t *piResult, PRTERRINFO pErrInfo); + +/** + * Evaluates the given if expression to a string result. + * + * @returns IPRT status code + * @param hEval Handle to the evaluator. + * @param pch The expression string. Does not need to be zero + * terminated. + * @param cch The length of the expression. Pass RTSTR_MAX if not + * known. + * @param ppszResult Where to return the result. This must be freed using + * RTStrFree. + * @param pErrInfo Where to return additional error info. + */ +RTDECL(int) RTExprEvalToString(RTEXPREVAL hEval, const char *pch, size_t cch, char **ppszResult, PRTERRINFO pErrInfo); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_expreval_h */ + diff --git a/include/iprt/file.h b/include/iprt/file.h new file mode 100644 index 00000000..6b36bfae --- /dev/null +++ b/include/iprt/file.h @@ -0,0 +1,1826 @@ +/** @file + * IPRT - File I/O. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_file_h +#define IPRT_INCLUDED_file_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/stdarg.h> +#include <iprt/fs.h> +#include <iprt/sg.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_fileio RTFile - File I/O + * @ingroup grp_rt + * @{ + */ + +/** Platform specific text line break. + * @deprecated Use text I/O streams and '\\n'. See iprt/stream.h. */ +#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) +# define RTFILE_LINEFEED "\r\n" +#else +# define RTFILE_LINEFEED "\n" +#endif + +/** Platform specific native standard input "handle". */ +#ifdef RT_OS_WINDOWS +# define RTFILE_NATIVE_STDIN ((uint32_t)-10) +#else +# define RTFILE_NATIVE_STDIN 0 +#endif + +/** Platform specific native standard out "handle". */ +#ifdef RT_OS_WINDOWS +# define RTFILE_NATIVE_STDOUT ((uint32_t)-11) +#else +# define RTFILE_NATIVE_STDOUT 1 +#endif + +/** Platform specific native standard error "handle". */ +#ifdef RT_OS_WINDOWS +# define RTFILE_NATIVE_STDERR ((uint32_t)-12) +#else +# define RTFILE_NATIVE_STDERR 2 +#endif + + +/** + * Checks if the specified file name exists and is a regular file. + * + * Symbolic links will be resolved. + * + * @returns true if it's a regular file, false if it isn't. + * @param pszPath The path to the file. + * + * @sa RTDirExists, RTPathExists, RTSymlinkExists. + */ +RTDECL(bool) RTFileExists(const char *pszPath); + +/** + * Queries the size of a file, given the path to it. + * + * Symbolic links will be resolved. + * + * @returns IPRT status code. + * @param pszPath The path to the file. + * @param pcbFile Where to return the file size (bytes). + * + * @sa RTFileQuerySize, RTPathQueryInfoEx. + */ +RTDECL(int) RTFileQuerySizeByPath(const char *pszPath, uint64_t *pcbFile); + + +/** @name Open flags + * @{ */ +/** Attribute access only. + * @remarks Only accepted on windows, requires RTFILE_O_ACCESS_ATTR_MASK + * to yield a non-zero result. Otherwise, this is invalid. */ +#define RTFILE_O_ATTR_ONLY UINT32_C(0x00000000) +/** Open the file with read access. */ +#define RTFILE_O_READ UINT32_C(0x00000001) +/** Open the file with write access. */ +#define RTFILE_O_WRITE UINT32_C(0x00000002) +/** Open the file with read & write access. */ +#define RTFILE_O_READWRITE UINT32_C(0x00000003) +/** The file access mask. + * @remarks The value 0 is invalid, except for windows special case. */ +#define RTFILE_O_ACCESS_MASK UINT32_C(0x00000003) + +/** Open file in APPEND mode, so all writes to the file handle will + * append data at the end of the file. + * @remarks It is ignored if write access is not requested, that is + * RTFILE_O_WRITE is not set. + * @note Behaviour of functions differ between hosts: See RTFileWriteAt, as + * well as ticketref:19003 (RTFileSetSize). */ +#define RTFILE_O_APPEND UINT32_C(0x00000004) + /* UINT32_C(0x00000008) is unused atm. */ + +/** Sharing mode: deny none. */ +#define RTFILE_O_DENY_NONE UINT32_C(0x00000080) +/** Sharing mode: deny read. */ +#define RTFILE_O_DENY_READ UINT32_C(0x00000010) +/** Sharing mode: deny write. */ +#define RTFILE_O_DENY_WRITE UINT32_C(0x00000020) +/** Sharing mode: deny read and write. */ +#define RTFILE_O_DENY_READWRITE UINT32_C(0x00000030) +/** Sharing mode: deny all. */ +#define RTFILE_O_DENY_ALL RTFILE_O_DENY_READWRITE +/** Sharing mode: do NOT deny delete (NT). + * @remarks This might not be implemented on all platforms, and will be + * defaulted & ignored on those. + */ +#define RTFILE_O_DENY_NOT_DELETE UINT32_C(0x00000040) +/** Sharing mode mask. */ +#define RTFILE_O_DENY_MASK UINT32_C(0x000000f0) + +/** Action: Open an existing file. */ +#define RTFILE_O_OPEN UINT32_C(0x00000700) +/** Action: Create a new file or open an existing one. */ +#define RTFILE_O_OPEN_CREATE UINT32_C(0x00000100) +/** Action: Create a new a file. */ +#define RTFILE_O_CREATE UINT32_C(0x00000200) +/** Action: Create a new file or replace an existing one. */ +#define RTFILE_O_CREATE_REPLACE UINT32_C(0x00000300) +/** Action mask. */ +#define RTFILE_O_ACTION_MASK UINT32_C(0x00000700) + +/** Turns off indexing of files on Windows hosts, *CREATE* only. + * @remarks Window only. */ +#define RTFILE_O_NOT_CONTENT_INDEXED UINT32_C(0x00000800) +/** Truncate the file. + * @remarks This will not truncate files opened for read-only. + * @remarks The truncation doesn't have to be atomically, so anyone else opening + * the file may be racing us. The caller is responsible for not causing + * this race. */ +#define RTFILE_O_TRUNCATE UINT32_C(0x00001000) +/** Make the handle inheritable on RTProcessCreate(/exec). */ +#define RTFILE_O_INHERIT UINT32_C(0x00002000) +/** Open file in non-blocking mode - non-portable. + * @remarks This flag may not be supported on all platforms, in which case it's + * considered an invalid parameter. */ +#define RTFILE_O_NON_BLOCK UINT32_C(0x00004000) +/** Write through directly to disk. Workaround to avoid iSCSI + * initiator deadlocks on Windows hosts. + * @remarks This might not be implemented on all platforms, and will be ignored + * on those. */ +#define RTFILE_O_WRITE_THROUGH UINT32_C(0x00008000) + +/** Attribute access: Attributes can be read if the file is being opened with + * read access, and can be written with write access. */ +#define RTFILE_O_ACCESS_ATTR_DEFAULT UINT32_C(0x00000000) +/** Attribute access: Attributes can be read. + * @remarks Windows only. */ +#define RTFILE_O_ACCESS_ATTR_READ UINT32_C(0x00010000) +/** Attribute access: Attributes can be written. + * @remarks Windows only. */ +#define RTFILE_O_ACCESS_ATTR_WRITE UINT32_C(0x00020000) +/** Attribute access: Attributes can be both read & written. + * @remarks Windows only. */ +#define RTFILE_O_ACCESS_ATTR_READWRITE UINT32_C(0x00030000) +/** Attribute access: The file attributes access mask. + * @remarks Windows only. */ +#define RTFILE_O_ACCESS_ATTR_MASK UINT32_C(0x00030000) + +/** Open file for async I/O + * @remarks This flag may not be needed on all platforms, and will be ignored on + * those. */ +#define RTFILE_O_ASYNC_IO UINT32_C(0x00040000) + +/** Disables caching. + * + * Useful when using very big files which might bring the host I/O scheduler to + * its knees during high I/O load. + * + * @remarks This flag might impose restrictions + * on the buffer alignment, start offset and/or transfer size. + * + * On Linux the buffer needs to be aligned to the 512 sector + * boundary. + * + * On Windows the FILE_FLAG_NO_BUFFERING is used (see + * http://msdn.microsoft.com/en-us/library/cc644950(VS.85).aspx ). + * The buffer address, the transfer size and offset needs to be aligned + * to the sector size of the volume. Furthermore FILE_APPEND_DATA is + * disabled. To write beyond the size of file use RTFileSetSize prior + * writing the data to the file. + * + * This flag does not work on Solaris if the target filesystem is ZFS. + * RTFileOpen will return an error with that configuration. When used + * with UFS the same alginment restrictions apply like Linux and + * Windows. + * + * @remarks This might not be implemented on all platforms, and will be ignored + * on those. + */ +#define RTFILE_O_NO_CACHE UINT32_C(0x00080000) + +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTFILE_O_NO_SYMLINKS UINT32_C(0x20000000) + +/** Unix file mode mask for use when creating files. */ +#define RTFILE_O_CREATE_MODE_MASK UINT32_C(0x1ff00000) +/** The number of bits to shift to get the file mode mask. + * To extract it: (fFlags & RTFILE_O_CREATE_MODE_MASK) >> RTFILE_O_CREATE_MODE_SHIFT. + */ +#define RTFILE_O_CREATE_MODE_SHIFT 20 + +/** Temporary file that should be automatically deleted when closed. + * If not supported by the OS, the open call will fail with VERR_NOT_SUPPORTED + * to prevent leaving undeleted files behind. + * @note On unix the file wont be visible and cannot be accessed by it's path. + * On Windows it will be visible but only accessible of deletion is + * shared. Not implemented on OS/2. */ +#define RTFILE_O_TEMP_AUTO_DELETE UINT32_C(0x40000000) + + /* UINT32_C(0x80000000) is unused atm. */ + +/** Mask of all valid flags. + * @remark This doesn't validate the access mode properly. + */ +#define RTFILE_O_VALID_MASK UINT32_C(0x7ffffff7) + +/** @} */ + + +/** Action taken by RTFileOpenEx. */ +typedef enum RTFILEACTION +{ + /** Invalid zero value. */ + RTFILEACTION_INVALID = 0, + /** Existing file was opened (returned by RTFILE_O_OPEN and + * RTFILE_O_OPEN_CREATE). */ + RTFILEACTION_OPENED, + /** New file was created (returned by RTFILE_O_CREATE and + * RTFILE_O_OPEN_CREATE). */ + RTFILEACTION_CREATED, + /** Existing file was replaced (returned by RTFILE_O_CREATE_REPLACE). */ + RTFILEACTION_REPLACED, + /** Existing file was truncated (returned if RTFILE_O_TRUNCATE take effect). */ + RTFILEACTION_TRUNCATED, + /** The file already exists (returned by RTFILE_O_CREATE on failure). */ + RTFILEACTION_ALREADY_EXISTS, + /** End of valid values. */ + RTFILEACTION_END, + /** Type size hack. */ + RTFILEACTION_32BIT_HACK = 0x7fffffff +} RTFILEACTION; +/** Pointer to action taken value (RTFileOpenEx). */ +typedef RTFILEACTION *PRTFILEACTION; + + +#ifdef IN_RING3 +/** + * Force the use of open flags for all files opened after the setting is + * changed. The caller is responsible for not causing races with RTFileOpen(). + * + * @returns iprt status code. + * @param fOpenForAccess Access mode to which the set/mask settings apply. + * @param fSet Open flags to be forced set. + * @param fMask Open flags to be masked out. + */ +RTR3DECL(int) RTFileSetForceFlags(unsigned fOpenForAccess, unsigned fSet, unsigned fMask); +#endif /* IN_RING3 */ + +/** + * Open a file. + * + * @returns iprt status code. + * @param pFile Where to store the handle to the opened file. + * @param pszFilename Path to the file which is to be opened. (UTF-8) + * @param fOpen Open flags, i.e a combination of the RTFILE_O_* defines. + * The ACCESS, ACTION and DENY flags are mandatory! + */ +RTDECL(int) RTFileOpen(PRTFILE pFile, const char *pszFilename, uint64_t fOpen); + +/** + * Open a file given as a format string. + * + * @returns iprt status code. + * @param pFile Where to store the handle to the opened file. + * @param fOpen Open flags, i.e a combination of the RTFILE_O_* defines. + * The ACCESS, ACTION and DENY flags are mandatory! + * @param pszFilenameFmt Format string givin the path to the file which is to + * be opened. (UTF-8) + * @param ... Arguments to the format string. + */ +RTDECL(int) RTFileOpenF(PRTFILE pFile, uint64_t fOpen, const char *pszFilenameFmt, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Open a file given as a format string. + * + * @returns iprt status code. + * @param pFile Where to store the handle to the opened file. + * @param fOpen Open flags, i.e a combination of the RTFILE_O_* defines. + * The ACCESS, ACTION and DENY flags are mandatory! + * @param pszFilenameFmt Format string givin the path to the file which is to + * be opened. (UTF-8) + * @param va Arguments to the format string. + */ +RTDECL(int) RTFileOpenV(PRTFILE pFile, uint64_t fOpen, const char *pszFilenameFmt, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Open a file, extended version. + * + * @returns iprt status code. + * @param pszFilename Path to the file which is to be opened. (UTF-8) + * @param fOpen Open flags, i.e a combination of the RTFILE_O_* defines. + * The ACCESS, ACTION and DENY flags are mandatory! + * @param phFile Where to store the handle to the opened file. + * @param penmActionTaken Where to return an indicator of which action was + * taken. This is optional and it is recommended to + * pass NULL when not strictly needed as it adds + * complexity (slower) on posix systems. + */ +RTDECL(int) RTFileOpenEx(const char *pszFilename, uint64_t fOpen, PRTFILE phFile, PRTFILEACTION penmActionTaken); + +/** + * Open the bit bucket (aka /dev/null or nul). + * + * @returns IPRT status code. + * @param phFile Where to store the handle to the opened file. + * @param fAccess The desired access only, i.e. read, write or both. + */ +RTDECL(int) RTFileOpenBitBucket(PRTFILE phFile, uint64_t fAccess); + +/** + * Duplicates a file handle. + * + * @returns IPRT status code. + * @param hFileSrc The handle to duplicate. + * @param fFlags RTFILE_O_INHERIT or zero. + * @param phFileNew Where to return the new file handle + */ +RTDECL(int) RTFileDup(RTFILE hFileSrc, uint64_t fFlags, PRTFILE phFileNew); + +/** + * Close a file opened by RTFileOpen(). + * + * @returns iprt status code. + * @param File The file handle to close. + */ +RTDECL(int) RTFileClose(RTFILE File); + +/** + * Creates an IPRT file handle from a native one. + * + * @returns IPRT status code. + * @param pFile Where to store the IPRT file handle. + * @param uNative The native handle. + */ +RTDECL(int) RTFileFromNative(PRTFILE pFile, RTHCINTPTR uNative); + +/** + * Gets the native handle for an IPRT file handle. + * + * @return The native handle. + * @param File The IPRT file handle. + */ +RTDECL(RTHCINTPTR) RTFileToNative(RTFILE File); + +/** + * Delete a file. + * + * @returns iprt status code. + * @param pszFilename Path to the file which is to be deleted. (UTF-8) + * @todo This is a RTPath api! + */ +RTDECL(int) RTFileDelete(const char *pszFilename); + +/** @name Seek flags. + * @{ */ +/** Seek from the start of the file. */ +#define RTFILE_SEEK_BEGIN 0x00 +/** Seek from the current file position. */ +#define RTFILE_SEEK_CURRENT 0x01 +/** Seek from the end of the file. */ +#define RTFILE_SEEK_END 0x02 +/** @internal */ +#define RTFILE_SEEK_FIRST RTFILE_SEEK_BEGIN +/** @internal */ +#define RTFILE_SEEK_LAST RTFILE_SEEK_END +/** @} */ + + +/** + * Changes the read & write position in a file. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param offSeek Offset to seek. + * @param uMethod Seek method, i.e. one of the RTFILE_SEEK_* defines. + * @param poffActual Where to store the new file position. + * NULL is allowed. + */ +RTDECL(int) RTFileSeek(RTFILE File, int64_t offSeek, unsigned uMethod, uint64_t *poffActual); + +/** + * Read bytes from a file. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param pvBuf Where to put the bytes we read. + * @param cbToRead How much to read. + * @param pcbRead How much we actually read . + * If NULL an error will be returned for a partial read. + */ +RTDECL(int) RTFileRead(RTFILE File, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Read bytes from a file at a given offset. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param off Where to read. + * @param pvBuf Where to put the bytes we read. + * @param cbToRead How much to read. + * @param pcbRead How much we actually read . + * If NULL an error will be returned for a partial read. + * + * @note OS/2 requires separate seek and write calls. + * + * @note Whether the file position is modified or not is host specific. + */ +RTDECL(int) RTFileReadAt(RTFILE File, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Read bytes from a file at a given offset into a S/G buffer. + * + * @returns iprt status code. + * @param hFile Handle to the file. + * @param pSgBuf Pointer to the S/G buffer to read into. + * @param cbToRead How much to read. + * @param pcbRead How much we actually read . + * If NULL an error will be returned for a partial read. + * + * @note It is not possible to guarantee atomicity on all platforms, so + * caller must take care wrt concurrent access to @a hFile. + */ +RTDECL(int) RTFileSgRead(RTFILE hFile, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Read bytes from a file at a given offset into a S/G buffer. + * + * @returns iprt status code. + * @param hFile Handle to the file. + * @param off Where to read. + * @param pSgBuf Pointer to the S/G buffer to read into. + * @param cbToRead How much to read. + * @param pcbRead How much we actually read . + * If NULL an error will be returned for a partial read. + * + * @note Whether the file position is modified or not is host specific. + * + * @note It is not possible to guarantee atomicity on all platforms, so + * caller must take care wrt concurrent access to @a hFile. + */ +RTDECL(int) RTFileSgReadAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Write bytes to a file. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param pvBuf What to write. + * @param cbToWrite How much to write. + * @param pcbWritten How much we actually wrote. + * If NULL an error will be returned for a partial write. + */ +RTDECL(int) RTFileWrite(RTFILE File, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + +/** + * Write bytes to a file at a given offset. + * + * @returns iprt status code. + * @param hFile Handle to the file. + * @param off Where to write. + * @param pvBuf What to write. + * @param cbToWrite How much to write. + * @param pcbWritten How much we actually wrote. + * If NULL an error will be returned for a partial write. + * + * @note OS/2 requires separate seek and write calls. + * + * @note Whether the file position is modified or not is host specific. + * + * @note Whether @a off is used when @a hFile was opened with RTFILE_O_APPEND + * is also host specific. Currently Linux is the the only one + * documented to ignore @a off. + */ +RTDECL(int) RTFileWriteAt(RTFILE hFile, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + +/** + * Write bytes from a S/G buffer to a file. + * + * @returns iprt status code. + * @param hFile Handle to the file. + * @param pSgBuf What to write. + * @param cbToWrite How much to write. + * @param pcbWritten How much we actually wrote. + * If NULL an error will be returned for a partial write. + * + * @note It is not possible to guarantee atomicity on all platforms, so + * caller must take care wrt concurrent access to @a hFile. + */ +RTDECL(int) RTFileSgWrite(RTFILE hFile, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten); + +/** + * Write bytes from a S/G buffer to a file at a given offset. + * + * @returns iprt status code. + * @param hFile Handle to the file. + * @param off Where to write. + * @param pSgBuf What to write. + * @param cbToWrite How much to write. + * @param pcbWritten How much we actually wrote. + * If NULL an error will be returned for a partial write. + * + * @note It is not possible to guarantee atomicity on all platforms, so + * caller must take care wrt concurrent access to @a hFile. + * + * @note Whether the file position is modified or not is host specific. + * + * @note Whether @a off is used when @a hFile was opened with RTFILE_O_APPEND + * is also host specific. Currently Linux is the the only one + * documented to ignore @a off. + */ +RTDECL(int) RTFileSgWriteAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten); + +/** + * Flushes the buffers for the specified file. + * + * @returns iprt status code. + * @retval VINF_NOT_SUPPORTED if it is a special file that does not support + * flushing. This is reported as a informational status since in most + * cases this is entirely harmless (e.g. tty) and simplifies the usage. + * @param File Handle to the file. + */ +RTDECL(int) RTFileFlush(RTFILE File); + +/** + * Set the size of the file. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param cbSize The new file size. + */ +RTDECL(int) RTFileSetSize(RTFILE File, uint64_t cbSize); + +/** + * Query the size of the file. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param pcbSize Where to store the filesize. + */ +RTDECL(int) RTFileQuerySize(RTFILE File, uint64_t *pcbSize); + +/** + * Determine the maximum file size. + * + * @returns The max size of the file. + * -1 on failure, the file position is undefined. + * @param File Handle to the file. + * @see RTFileQueryMaxSizeEx. + */ +RTDECL(RTFOFF) RTFileGetMaxSize(RTFILE File); + +/** + * Determine the maximum file size. + * + * @returns IPRT status code. + * @param File Handle to the file. + * @param pcbMax Where to store the max file size. + * @see RTFileGetMaxSize. + */ +RTDECL(int) RTFileQueryMaxSizeEx(RTFILE File, PRTFOFF pcbMax); + +/** + * Queries the sector size (/ logical block size) for a disk or similar. + * + * @returns IPRT status code. + * @retval VERR_INVALID_FUNCTION if not a disk/similar. Could also be returned + * if not really implemented. + * @param hFile Handle to the disk. This must typically be a device + * rather than a file or directory, though this may vary + * from OS to OS. + * @param pcbSector Where to store the sector size. + */ +RTDECL(int) RTFileQuerySectorSize(RTFILE hFile, uint32_t *pcbSector); + +/** + * Gets the current file position. + * + * @returns File offset. + * @returns ~0UUL on failure. + * @param File Handle to the file. + */ +RTDECL(uint64_t) RTFileTell(RTFILE File); + +/** + * Checks if the supplied handle is valid. + * + * @returns true if valid. + * @returns false if invalid. + * @param File The file handle + */ +RTDECL(bool) RTFileIsValid(RTFILE File); + +/** + * Copies a file. + * + * @returns IPRT status code + * @retval VERR_ALREADY_EXISTS if the destination file exists. + * + * @param pszSrc The path to the source file. + * @param pszDst The path to the destination file. + * This file will be created. + */ +RTDECL(int) RTFileCopy(const char *pszSrc, const char *pszDst); + +/** + * Copies a file given the handles to both files. + * + * @returns IPRT status code + * + * @param FileSrc The source file. The file position is unaltered. + * @param FileDst The destination file. + * On successful returns the file position is at the end of the file. + * On failures the file position and size is undefined. + */ +RTDECL(int) RTFileCopyByHandles(RTFILE FileSrc, RTFILE FileDst); + +/** Flags for RTFileCopyEx(). + * @{ */ +/** Do not use RTFILE_O_DENY_WRITE on the source file to allow for copying files opened for writing. */ +#define RTFILECOPY_FLAGS_NO_SRC_DENY_WRITE RT_BIT(0) +/** Do not use RTFILE_O_DENY_WRITE on the target file. */ +#define RTFILECOPY_FLAGS_NO_DST_DENY_WRITE RT_BIT(1) +/** Do not use RTFILE_O_DENY_WRITE on either of the two files. */ +#define RTFILECOPY_FLAGS_NO_DENY_WRITE ( RTFILECOPY_FLAGS_NO_SRC_DENY_WRITE | RTFILECOPY_FLAGS_NO_DST_DENY_WRITE ) +/** */ +#define RTFILECOPY_FLAGS_MASK UINT32_C(0x00000003) +/** @} */ + +/** + * Copies a file. + * + * @returns IPRT status code + * @retval VERR_ALREADY_EXISTS if the destination file exists. + * + * @param pszSrc The path to the source file. + * @param pszDst The path to the destination file. + * This file will be created. + * @param fFlags Flags (RTFILECOPY_*). + * @param pfnProgress Pointer to callback function for reporting progress. + * @param pvUser User argument to pass to pfnProgress along with the completion percentage. + */ +RTDECL(int) RTFileCopyEx(const char *pszSrc, const char *pszDst, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser); + +/** + * Copies a file given the handles to both files and + * provide progress callbacks. + * + * @returns IPRT status code. + * + * @param FileSrc The source file. The file position is unaltered. + * @param FileDst The destination file. + * On successful returns the file position is at the end of the file. + * On failures the file position and size is undefined. + * @param pfnProgress Pointer to callback function for reporting progress. + * @param pvUser User argument to pass to pfnProgress along with the completion percentage. + */ +RTDECL(int) RTFileCopyByHandlesEx(RTFILE FileSrc, RTFILE FileDst, PFNRTPROGRESS pfnProgress, void *pvUser); + +/** + * Copies a part of a file to another one. + * + * @returns IPRT status code. + * @retval VERR_EOF if @a pcbCopied is NULL and the end-of-file is reached + * before @a cbToCopy bytes have been copied. + * + * @param hFileSrc Handle to the source file. Must be readable. + * @param offSrc The source file offset. + * @param hFileDst Handle to the destination file. Must be writable and + * RTFILE_O_APPEND must be be in effect. + * @param offDst The destination file offset. + * @param cbToCopy How many bytes to copy. + * @param fFlags Reserved for the future, must be zero. + * @param pcbCopied Where to return the exact number of bytes copied. + * Optional. + * + * @note The file positions of @a hFileSrc and @a hFileDst are undefined + * upon return of this function. + * + * @sa RTFileCopyPartEx. + */ +RTDECL(int) RTFileCopyPart(RTFILE hFileSrc, RTFOFF offSrc, RTFILE hFileDst, RTFOFF offDst, uint64_t cbToCopy, + uint32_t fFlags, uint64_t *pcbCopied); + + +/** Copy buffer state for RTFileCopyPartEx. + * @note The fields are considered internal! + */ +typedef struct RTFILECOPYPARTBUFSTATE +{ + /** Magic value (RTFILECOPYPARTBUFSTATE_MAGIC). + * @internal */ + uint32_t uMagic; + /** Allocation type (internal). + * @internal */ + int32_t iAllocType; + /** Buffer pointer. + * @internal */ + uint8_t *pbBuf; + /** Buffer size. + * @internal */ + size_t cbBuf; + /** Reserved. + * @internal */ + void *papReserved[3]; +} RTFILECOPYPARTBUFSTATE; +/** Pointer to copy buffer state for RTFileCopyPartEx(). */ +typedef RTFILECOPYPARTBUFSTATE *PRTFILECOPYPARTBUFSTATE; +/** Magic value for the RTFileCopyPartEx() buffer state structure (Stephen John Fry). */ +#define RTFILECOPYPARTBUFSTATE_MAGIC UINT32_C(0x19570857) + +/** + * Prepares buffer state for one or more RTFileCopyPartEx() calls. + * + * Caller must call RTFileCopyPartCleanup() after the final RTFileCopyPartEx() + * call. + * + * @returns IPRT status code. + * @param pBufState The buffer state to prepare. + * @param cbToCopy The number of bytes we typically to copy in one + * RTFileCopyPartEx call. + */ +RTDECL(int) RTFileCopyPartPrep(PRTFILECOPYPARTBUFSTATE pBufState, uint64_t cbToCopy); + +/** + * Cleans up after RTFileCopyPartPrep() once the final RTFileCopyPartEx() + * call has been made. + * + * @param pBufState The buffer state to clean up. + */ +RTDECL(void) RTFileCopyPartCleanup(PRTFILECOPYPARTBUFSTATE pBufState); + +/** + * Copies a part of a file to another one, extended version. + * + * @returns IPRT status code. + * @retval VERR_EOF if @a pcbCopied is NULL and the end-of-file is reached + * before @a cbToCopy bytes have been copied. + * + * @param hFileSrc Handle to the source file. Must be readable. + * @param offSrc The source file offset. + * @param hFileDst Handle to the destination file. Must be writable and + * RTFILE_O_APPEND must be be in effect. + * @param offDst The destination file offset. + * @param cbToCopy How many bytes to copy. + * @param fFlags Reserved for the future, must be zero. + * @param pBufState Copy buffer state prepared by RTFileCopyPartPrep(). + * @param pcbCopied Where to return the exact number of bytes copied. + * Optional. + * + * @note The file positions of @a hFileSrc and @a hFileDst are undefined + * upon return of this function. + * + * @sa RTFileCopyPart. + */ +RTDECL(int) RTFileCopyPartEx(RTFILE hFileSrc, RTFOFF offSrc, RTFILE hFileDst, RTFOFF offDst, uint64_t cbToCopy, + uint32_t fFlags, PRTFILECOPYPARTBUFSTATE pBufState, uint64_t *pcbCopied); + +/** + * Copy file attributes from @a hFileSrc to @a hFileDst. + * + * @returns IPRT status code. + * @param hFileSrc Handle to the source file. + * @param hFileDst Handle to the destination file. + * @param fFlags Reserved, pass zero. + */ +RTDECL(int) RTFileCopyAttributes(RTFILE hFileSrc, RTFILE hFileDst, uint32_t fFlags); + +/** + * Compares two file given the paths to both files. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if equal. + * @retval VERR_NOT_EQUAL if not equal. + * + * @param pszFile1 The path to the first file. + * @param pszFile2 The path to the second file. + */ +RTDECL(int) RTFileCompare(const char *pszFile1, const char *pszFile2); + +/** + * Compares two file given the handles to both files. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if equal. + * @retval VERR_NOT_EQUAL if not equal. + * + * @param hFile1 The first file. Undefined return position. + * @param hFile2 The second file. Undefined return position. + */ +RTDECL(int) RTFileCompareByHandles(RTFILE hFile1, RTFILE hFile2); + +/** Flags for RTFileCompareEx(). + * @{ */ +/** Do not use RTFILE_O_DENY_WRITE on the first file. */ +#define RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE1 RT_BIT(0) +/** Do not use RTFILE_O_DENY_WRITE on the second file. */ +#define RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE2 RT_BIT(1) +/** Do not use RTFILE_O_DENY_WRITE on either of the two files. */ +#define RTFILECOMP_FLAGS_NO_DENY_WRITE ( RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE1 | RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE2 ) +/** */ +#define RTFILECOMP_FLAGS_MASK UINT32_C(0x00000003) +/** @} */ + +/** + * Compares two files, extended version with progress callback. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if equal. + * @retval VERR_NOT_EQUAL if not equal. + * + * @param pszFile1 The path to the source file. + * @param pszFile2 The path to the destination file. This file will be + * created. + * @param fFlags Flags, any of the RTFILECOMP_FLAGS_ \#defines. + * @param pfnProgress Pointer to callback function for reporting progress. + * @param pvUser User argument to pass to pfnProgress along with the completion percentage. + */ +RTDECL(int) RTFileCompareEx(const char *pszFile1, const char *pszFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser); + +/** + * Compares two files given their handles, extended version with progress + * callback. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if equal. + * @retval VERR_NOT_EQUAL if not equal. + * + * @param hFile1 The first file. Undefined return position. + * @param hFile2 The second file. Undefined return position. + * + * @param fFlags Flags, any of the RTFILECOMP_FLAGS_ \#defines, flags + * related to opening of the files will be ignored. + * @param pfnProgress Pointer to callback function for reporting progress. + * @param pvUser User argument to pass to pfnProgress along with the completion percentage. + */ +RTDECL(int) RTFileCompareByHandlesEx(RTFILE hFile1, RTFILE hFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser); + +/** + * Renames a file. + * + * Identical to RTPathRename except that it will ensure that the source is not a directory. + * + * @returns IPRT status code. + * @returns VERR_ALREADY_EXISTS if the destination file exists. + * + * @param pszSrc The path to the source file. + * @param pszDst The path to the destination file. + * This file will be created. + * @param fRename See RTPathRename. + */ +RTDECL(int) RTFileRename(const char *pszSrc, const char *pszDst, unsigned fRename); + + +/** @name RTFileMove flags (bit masks). + * @{ */ +/** Replace destination file if present. */ +#define RTFILEMOVE_FLAGS_REPLACE 0x1 +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTFILEMOVE_FLAGS_NO_SYMLINKS 0x2 +/** @} */ + +/** + * Converts file opening modes (used by fopen, for example) to IPRT + * compatible flags, which then can be used with RTFileOpen* APIs. + * + * @note Handling sharing modes is not supported yet, so RTFILE_O_DENY_NONE + * will always be used. + * + * @return IPRT status code. + * @param pszMode Mode string to convert. + * @param pfMode Where to store the converted mode flags on + * success. + */ +RTDECL(int) RTFileModeToFlags(const char *pszMode, uint64_t *pfMode); + +/** + * Converts file opening modes along with a separate disposition command + * to IPRT compatible flags, which then can be used with RTFileOpen* APIs. + * + * Access modes: + * - "r": Opens a file for reading. + * - "r+": Opens a file for reading and writing. + * - "w": Opens a file for writing. + * - "w+": Opens a file for writing and reading. + * + * Disposition modes: + * - "oe", "open": Opens an existing file or fail if it does not exist. + * - "oc", "open-create": Opens an existing file or create it if it does + * not exist. + * - "oa", "open-append": Opens an existing file and places the file + * pointer at the end of the file, if opened with write access. Create + * the file if it does not exist. + * - "ot", "open-truncate": Opens and truncate an existing file or fail if + * it does not exist. + * - "ce", "create": Creates a new file if it does not exist. Fail if + * exist. + * - "ca", "create-replace": Creates a new file, always. Overwrites an + * existing file. + * + * Sharing mode: + * - "nr": Deny read. + * - "nw": Deny write. + * - "nrw": Deny both read and write. + * - "d": Allow delete. + * - "", NULL: Deny none, except delete. + * + * @return IPRT status code. + * @param pszAccess Access mode string to convert. + * @param pszDisposition Disposition mode string to convert. + * @param pszSharing Sharing mode string to convert. + * @param pfMode Where to store the converted mode flags on success. + */ +RTDECL(int) RTFileModeToFlagsEx(const char *pszAccess, const char *pszDisposition, const char *pszSharing, uint64_t *pfMode); + +/** + * Moves a file. + * + * RTFileMove differs from RTFileRename in that it works across volumes. + * + * @returns IPRT status code. + * @returns VERR_ALREADY_EXISTS if the destination file exists. + * + * @param pszSrc The path to the source file. + * @param pszDst The path to the destination file. + * This file will be created. + * @param fMove A combination of the RTFILEMOVE_* flags. + */ +RTDECL(int) RTFileMove(const char *pszSrc, const char *pszDst, unsigned fMove); + + +/** + * Creates a new file with a unique name using the given template, returning a + * handle to it. + * + * One or more trailing X'es in the template will be replaced by random alpha + * numeric characters until a RTFileOpen with RTFILE_O_CREATE succeeds or we + * run out of patience. + * For instance: + * "/tmp/myprog-XXXXXX" + * + * As an alternative to trailing X'es, it is possible to put 3 or more X'es + * somewhere inside the file name. In the following string only the last + * bunch of X'es will be modified: + * "/tmp/myprog-XXX-XXX.tmp" + * + * @returns IPRT status code. + * @param phFile Where to return the file handle on success. Set to + * NIL on failure. + * @param pszTemplate The file name template on input. The actual file + * name on success. Empty string on failure. + * @param fOpen The RTFILE_O_XXX flags to open the file with. + * RTFILE_O_CREATE is mandatory. + * @see RTFileCreateTemp + */ +RTDECL(int) RTFileCreateUnique(PRTFILE phFile, char *pszTemplate, uint64_t fOpen); + +/** + * Creates a new file with a unique name using the given template. + * + * One or more trailing X'es in the template will be replaced by random alpha + * numeric characters until a RTFileOpen with RTFILE_O_CREATE succeeds or we + * run out of patience. + * For instance: + * "/tmp/myprog-XXXXXX" + * + * As an alternative to trailing X'es, it is possible to put 3 or more X'es + * somewhere inside the file name. In the following string only the last + * bunch of X'es will be modified: + * "/tmp/myprog-XXX-XXX.tmp" + * + * @returns iprt status code. + * @param pszTemplate The file name template on input. The actual file + * name on success. Empty string on failure. + * @param fMode The mode to create the file with. Use 0600 unless + * you have reason not to. + * @see RTFileCreateUnique + */ +RTDECL(int) RTFileCreateTemp(char *pszTemplate, RTFMODE fMode); + +/** + * Secure version of @a RTFileCreateTemp with a fixed mode of 0600. + * + * This function behaves in the same way as @a RTFileCreateTemp with two + * additional points. Firstly the mode is fixed to 0600. Secondly it will + * fail if it is not possible to perform the operation securely. Possible + * reasons include that the file could be removed by another unprivileged + * user before it is used (e.g. if is created in a non-sticky /tmp directory) + * or that the path contains symbolic links which another unprivileged user + * could manipulate; however the exact criteria will be specified on a + * platform-by-platform basis as platform support is added. + * @see RTPathIsSecure for the current list of criteria. + * + * @returns iprt status code. + * @returns VERR_NOT_SUPPORTED if the interface can not be supported on the + * current platform at this time. + * @returns VERR_INSECURE if the file could not be created securely. + * @param pszTemplate The file name template on input. The actual + * file name on success. Empty string on failure. + * @see RTFileCreateUnique + */ +RTDECL(int) RTFileCreateTempSecure(char *pszTemplate); + +/** + * Opens a new file with a unique name in the temp directory. + * + * Unlike the other temp file creation APIs, this does not allow you any control + * over the name. Nor do you have to figure out where the temporary directory + * is. + * + * @returns iprt status code. + * @param phFile Where to return the handle to the file. + * @param pszFilename Where to return the name (+path) of the file . + * @param cbFilename The size of the buffer @a pszFilename points to. + * @param fOpen The RTFILE_O_XXX flags to open the file with. + * + * @remarks If actual control over the filename or location is required, we'll + * create an extended edition of this API. + */ +RTDECL(int) RTFileOpenTemp(PRTFILE phFile, char *pszFilename, size_t cbFilename, uint64_t fOpen); + + +/** @page pg_rt_filelock RT File locking API description + * + * File locking general rules: + * + * Region to lock or unlock can be located beyond the end of file, this can be used for + * growing files. + * Read (or Shared) locks can be acquired held by an unlimited number of processes at the + * same time, but a Write (or Exclusive) lock can only be acquired by one process, and + * cannot coexist with a Shared lock. To acquire a Read lock, a process must wait until + * there are no processes holding any Write locks. To acquire a Write lock, a process must + * wait until there are no processes holding either kind of lock. + * By default, RTFileLock and RTFileChangeLock calls returns error immediately if the lock + * can't be acquired due to conflict with other locks, however they can be called in wait mode. + * + * Differences in implementation: + * + * Win32, OS/2: Locking is mandatory, since locks are enforced by the operating system. + * I.e. when file region is locked in Read mode, any write in it will fail; in case of Write + * lock - region can be read and writed only by lock's owner. + * + * Win32: File size change (RTFileSetSize) is not controlled by locking at all (!) in the + * operation system. Also see comments to RTFileChangeLock API call. + * + * Linux/Posix: By default locks in Unixes are advisory. This means that cooperating processes + * may use locks to coordinate access to a file between themselves, but programs are also free + * to ignore locks and access the file in any way they choose to. + * + * Additional reading: + * http://en.wikipedia.org/wiki/File_locking + * http://unixhelp.ed.ac.uk/CGI/man-cgi?fcntl+2 + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/lockfileex.asp + */ + +/** @name Lock flags (bit masks). + * @{ */ +/** Read access, can be shared with others. */ +#define RTFILE_LOCK_READ 0x00 +/** Write access, one at a time. */ +#define RTFILE_LOCK_WRITE 0x01 +/** Don't wait for other locks to be released. */ +#define RTFILE_LOCK_IMMEDIATELY 0x00 +/** Wait till conflicting locks have been released. */ +#define RTFILE_LOCK_WAIT 0x02 +/** Valid flags mask */ +#define RTFILE_LOCK_MASK 0x03 +/** @} */ + + +/** + * Locks a region of file for read (shared) or write (exclusive) access. + * + * @returns iprt status code. + * @returns VERR_FILE_LOCK_VIOLATION if lock can't be acquired. + * @param File Handle to the file. + * @param fLock Lock method and flags, see RTFILE_LOCK_* defines. + * @param offLock Offset of lock start. + * @param cbLock Length of region to lock, may overlap the end of file. + */ +RTDECL(int) RTFileLock(RTFILE File, unsigned fLock, int64_t offLock, uint64_t cbLock); + +/** + * Changes a lock type from read to write or from write to read. + * The region to type change must correspond exactly to an existing locked region. + * If change can't be done due to locking conflict and non-blocking mode is used, error is + * returned and lock keeps its state (see next warning). + * + * WARNING: win32 implementation of this call is not atomic, it transforms to a pair of + * calls RTFileUnlock and RTFileLock. Potentially the previously acquired lock can be + * lost, i.e. function is called in non-blocking mode, previous lock is freed, new lock can't + * be acquired, and old lock (previous state) can't be acquired back too. This situation + * may occurs _only_ if the other process is acquiring a _write_ lock in blocking mode or + * in race condition with the current call. + * In this very bad case special error code VERR_FILE_LOCK_LOST will be returned. + * + * @returns iprt status code. + * @returns VERR_FILE_NOT_LOCKED if region was not locked. + * @returns VERR_FILE_LOCK_VIOLATION if lock type can't be changed, lock remains its type. + * @returns VERR_FILE_LOCK_LOST if lock was lost, we haven't this lock anymore :( + * @param File Handle to the file. + * @param fLock Lock method and flags, see RTFILE_LOCK_* defines. + * @param offLock Offset of lock start. + * @param cbLock Length of region to lock, may overlap the end of file. + */ +RTDECL(int) RTFileChangeLock(RTFILE File, unsigned fLock, int64_t offLock, uint64_t cbLock); + +/** + * Unlocks previously locked region of file. + * The region to unlock must correspond exactly to an existing locked region. + * + * @returns iprt status code. + * @returns VERR_FILE_NOT_LOCKED if region was not locked. + * @param File Handle to the file. + * @param offLock Offset of lock start. + * @param cbLock Length of region to unlock, may overlap the end of file. + */ +RTDECL(int) RTFileUnlock(RTFILE File, int64_t offLock, uint64_t cbLock); + + +/** + * Query information about an open file. + * + * @returns iprt status code. + * + * @param File Handle to the file. + * @param pObjInfo Object information structure to be filled on successful return. + * @param enmAdditionalAttribs Which set of additional attributes to request. + * Use RTFSOBJATTRADD_NOTHING if this doesn't matter. + */ +RTDECL(int) RTFileQueryInfo(RTFILE File, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs); + +/** + * Changes one or more of the timestamps associated of file system object. + * + * @returns iprt status code. + * @retval VERR_NOT_SUPPORTED is returned if the operation isn't supported by + * the OS. + * + * @param File Handle to the file. + * @param pAccessTime Pointer to the new access time. NULL if not to be changed. + * @param pModificationTime Pointer to the new modifcation time. NULL if not to be changed. + * @param pChangeTime Pointer to the new change time. NULL if not to be changed. + * @param pBirthTime Pointer to the new time of birth. NULL if not to be changed. + * + * @remark The file system might not implement all these time attributes, + * the API will ignore the ones which aren't supported. + * + * @remark The file system might not implement the time resolution + * employed by this interface, the time will be chopped to fit. + * + * @remark The file system may update the change time even if it's + * not specified. + * + * @remark POSIX can only set Access & Modification and will always set both. + */ +RTDECL(int) RTFileSetTimes(RTFILE File, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, + PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime); + +/** + * Gets one or more of the timestamps associated of file system object. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param pAccessTime Where to store the access time. NULL is ok. + * @param pModificationTime Where to store the modifcation time. NULL is ok. + * @param pChangeTime Where to store the change time. NULL is ok. + * @param pBirthTime Where to store the time of birth. NULL is ok. + * + * @remark This is wrapper around RTFileQueryInfo() and exists to complement RTFileSetTimes(). + */ +RTDECL(int) RTFileGetTimes(RTFILE File, PRTTIMESPEC pAccessTime, PRTTIMESPEC pModificationTime, + PRTTIMESPEC pChangeTime, PRTTIMESPEC pBirthTime); + +/** + * Changes the mode flags of an open file. + * + * The API requires at least one of the mode flag sets (Unix/Dos) to + * be set. The type is ignored. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param fMode The new file mode, see @ref grp_rt_fs for details. + */ +RTDECL(int) RTFileSetMode(RTFILE File, RTFMODE fMode); + +/** + * Gets the mode flags of an open file. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param pfMode Where to store the file mode, see @ref grp_rt_fs for details. + * + * @remark This is wrapper around RTFileQueryInfo() + * and exists to complement RTFileSetMode(). + */ +RTDECL(int) RTFileGetMode(RTFILE File, uint32_t *pfMode); + +/** + * Changes the owner and/or group of an open file. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param uid The new file owner user id. Pass NIL_RTUID to leave + * this unchanged. + * @param gid The new group id. Pass NIL_RTGID to leave this + * unchanged. + */ +RTDECL(int) RTFileSetOwner(RTFILE File, uint32_t uid, uint32_t gid); + +/** + * Gets the owner and/or group of an open file. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param pUid Where to store the owner user id. NULL is ok. + * @param pGid Where to store the group id. NULL is ok. + * + * @remark This is wrapper around RTFileQueryInfo() and exists to complement RTFileGetOwner(). + */ +RTDECL(int) RTFileGetOwner(RTFILE File, uint32_t *pUid, uint32_t *pGid); + +/** + * Executes an IOCTL on a file descriptor. + * + * This function is currently only available in L4 and posix environments. + * Attemps at calling it from code shared with any other platforms will break things! + * + * The rational for defining this API is to simplify L4 porting of audio drivers, + * and to remove some of the assumptions on RTFILE being a file descriptor on + * platforms using the posix file implementation. + * + * @returns iprt status code. + * @param File Handle to the file. + * @param ulRequest IOCTL request to carry out. + * @param pvData IOCTL data. + * @param cbData Size of the IOCTL data. + * @param piRet Return value of the IOCTL request. + */ +RTDECL(int) RTFileIoCtl(RTFILE File, unsigned long ulRequest, void *pvData, unsigned cbData, int *piRet); + +/** + * Query the sizes of a filesystem. + * + * @returns iprt status code. + * @retval VERR_NOT_SUPPORTED is returned if the operation isn't supported by + * the OS. + * + * @param hFile The file handle. + * @param pcbTotal Where to store the total filesystem space. (Optional) + * @param pcbFree Where to store the remaining free space in the filesystem. (Optional) + * @param pcbBlock Where to store the block size. (Optional) + * @param pcbSector Where to store the sector size. (Optional) + * + * @sa RTFsQuerySizes + */ +RTDECL(int) RTFileQueryFsSizes(RTFILE hFile, PRTFOFF pcbTotal, RTFOFF *pcbFree, + uint32_t *pcbBlock, uint32_t *pcbSector); + +/** + * Reads the file into memory. + * + * The caller must free the memory using RTFileReadAllFree(). + * + * @returns IPRT status code. + * @param pszFilename The name of the file. + * @param ppvFile Where to store the pointer to the memory on successful return. + * @param pcbFile Where to store the size of the returned memory. + * + * @remarks Note that this function may be implemented using memory mapping, which means + * that the file may remain open until RTFileReadAllFree() is called. It also + * means that the return memory may reflect the state of the file when it's + * accessed instead of when this call was done. So, in short, don't use this + * API for volatile files, then rather use the extended variant with a + * yet-to-be-defined flag. + */ +RTDECL(int) RTFileReadAll(const char *pszFilename, void **ppvFile, size_t *pcbFile); + +/** + * Reads the file into memory. + * + * The caller must free the memory using RTFileReadAllFree(). + * + * @returns IPRT status code. + * @param pszFilename The name of the file. + * @param off The offset to start reading at. + * @param cbMax The maximum number of bytes to read into memory. Specify RTFOFF_MAX + * to read to the end of the file. + * @param fFlags See RTFILE_RDALL_*. + * @param ppvFile Where to store the pointer to the memory on successful return. + * @param pcbFile Where to store the size of the returned memory. + * + * @remarks See the remarks for RTFileReadAll. + */ +RTDECL(int) RTFileReadAllEx(const char *pszFilename, RTFOFF off, RTFOFF cbMax, uint32_t fFlags, void **ppvFile, size_t *pcbFile); + +/** + * Reads the file into memory. + * + * The caller must free the memory using RTFileReadAllFree(). + * + * @returns IPRT status code. + * @param File The handle to the file. + * @param ppvFile Where to store the pointer to the memory on successful return. + * @param pcbFile Where to store the size of the returned memory. + * + * @remarks See the remarks for RTFileReadAll. + */ +RTDECL(int) RTFileReadAllByHandle(RTFILE File, void **ppvFile, size_t *pcbFile); + +/** + * Reads the file into memory. + * + * The caller must free the memory using RTFileReadAllFree(). + * + * @returns IPRT status code. + * @param File The handle to the file. + * @param off The offset to start reading at. + * @param cbMax The maximum number of bytes to read into memory. Specify RTFOFF_MAX + * to read to the end of the file. + * @param fFlags See RTFILE_RDALL_*. + * @param ppvFile Where to store the pointer to the memory on successful return. + * @param pcbFile Where to store the size of the returned memory. + * + * @remarks See the remarks for RTFileReadAll. + */ +RTDECL(int) RTFileReadAllByHandleEx(RTFILE File, RTFOFF off, RTFOFF cbMax, uint32_t fFlags, void **ppvFile, size_t *pcbFile); + +/** + * Frees the memory returned by one of the RTFileReadAll(), RTFileReadAllEx(), + * RTFileReadAllByHandle() and RTFileReadAllByHandleEx() functions. + * + * @param pvFile Pointer to the memory. + * @param cbFile The size of the memory. + */ +RTDECL(void) RTFileReadAllFree(void *pvFile, size_t cbFile); + +/** @name RTFileReadAllEx and RTFileReadAllHandleEx flags + * The open flags are ignored by RTFileReadAllHandleEx. + * @{ */ +#define RTFILE_RDALL_O_DENY_NONE RTFILE_O_DENY_NONE +#define RTFILE_RDALL_O_DENY_READ RTFILE_O_DENY_READ +#define RTFILE_RDALL_O_DENY_WRITE RTFILE_O_DENY_WRITE +#define RTFILE_RDALL_O_DENY_READWRITE RTFILE_O_DENY_READWRITE +#define RTFILE_RDALL_O_DENY_ALL RTFILE_O_DENY_ALL +#define RTFILE_RDALL_O_DENY_NOT_DELETE RTFILE_O_DENY_NOT_DELETE +#define RTFILE_RDALL_O_DENY_MASK RTFILE_O_DENY_MASK +/** Fail with VERR_OUT_OF_RANGE if the file size exceeds the specified maximum + * size. The default behavior is to cap the size at cbMax. */ +#define RTFILE_RDALL_F_FAIL_ON_MAX_SIZE RT_BIT_32(30) +/** Add a trailing zero byte to facilitate reading text files. */ +#define RTFILE_RDALL_F_TRAILING_ZERO_BYTE RT_BIT_32(31) +/** Mask of valid flags. */ +#define RTFILE_RDALL_VALID_MASK (RTFILE_RDALL_O_DENY_MASK | UINT32_C(0xc0000000)) +/** @} */ + +/** + * Sets the current size of the file ensuring that all required blocks + * are allocated on the underlying medium. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if either this operation is not supported on the + * current host in an efficient manner or the given combination of + * flags is not supported. + * @param hFile The handle to the file. + * @param cbSize The new size of the file to allocate. + * @param fFlags Combination of RTFILE_ALLOC_SIZE_F_* + */ +RTDECL(int) RTFileSetAllocationSize(RTFILE hFile, uint64_t cbSize, uint32_t fFlags); + +/** @name RTFILE_ALLOC_SIZE_F_XXX - RTFileSetAllocationSize flags + * @{ */ +/** Default flags. */ +#define RTFILE_ALLOC_SIZE_F_DEFAULT 0 +/** Do not change the size of the file if the given size is bigger than the + * current file size. + * + * Useful to preallocate blocks beyond the current size for appending data in an + * efficient manner. Might not be supported on all hosts and will return + * VERR_NOT_SUPPORTED in that case. */ +#define RTFILE_ALLOC_SIZE_F_KEEP_SIZE RT_BIT(0) +/** Mask of valid flags. */ +#define RTFILE_ALLOC_SIZE_F_VALID (RTFILE_ALLOC_SIZE_F_KEEP_SIZE) +/** @} */ + + +#ifdef IN_RING3 + +/** @page pg_rt_asyncio RT File async I/O API + * + * File operations are usually blocking the calling thread until + * they completed making it impossible to let the thread do anything + * else in-between. + * The RT File async I/O API provides an easy and efficient way to + * access files asynchronously using the native facilities provided + * by each operating system. + * + * @section sec_rt_asyncio_objects Objects + * + * There are two objects used in this API. + * The first object is the request. A request contains every information + * needed two complete the file operation successfully like the start offset + * and pointer to the source or destination buffer. + * Requests are created with RTFileAioReqCreate() and destroyed with + * RTFileAioReqDestroy(). + * Because creating a request may require allocating various operating + * system dependent resources and may be quite expensive it is possible + * to use a request more than once to save CPU cycles. + * A request is constructed with either RTFileAioReqPrepareRead() + * which will set up a request to read from the given file or + * RTFileAioReqPrepareWrite() which will write to a given file. + * + * The second object is the context. A file is associated with a context + * and requests for this file may complete only on the context the file + * was associated with and not on the context given in RTFileAioCtxSubmit() + * (see below for further information). + * RTFileAioCtxWait() is used to wait for completion of requests which were + * associated with the context. While waiting for requests the thread can not + * respond to global state changes. That's why the API provides a way to let + * RTFileAioCtxWait() return immediately no matter how many requests + * have finished through RTFileAioCtxWakeup(). The return code is + * VERR_INTERRUPTED to let the thread know that he got interrupted. + * + * @section sec_rt_asyncio_request_states Request states + * + * Created: + * After a request was created with RTFileAioReqCreate() it is in the same state + * like it just completed successfully. RTFileAioReqGetRC() will return VINF_SUCCESS + * and a transfer size of 0. RTFileAioReqGetUser() will return NULL. The request can be + * destroyed RTFileAioReqDestroy(). It is also allowed to prepare a the request + * for a data transfer with the RTFileAioReqPrepare* methods. + * Calling any other method like RTFileAioCtxSubmit() will return VERR_FILE_AIO_NOT_PREPARED + * and RTFileAioReqCancel() returns VERR_FILE_AIO_NOT_SUBMITTED. + * + * Prepared: + * A request will enter this state if one of the RTFileAioReqPrepare* methods + * is called. In this state you can still destroy and retrieve the user data + * associated with the request but trying to cancel the request or getting + * the result of the operation will return VERR_FILE_AIO_NOT_SUBMITTED. + * + * Submitted: + * A prepared request can be submitted with RTFileAioCtxSubmit(). If the operation + * succeeds it is not allowed to touch the request or free any resources until + * it completed through RTFileAioCtxWait(). The only allowed method is RTFileAioReqCancel() + * which tries to cancel the request. The request will go into the completed state + * and RTFileAioReqGetRC() will return VERR_FILE_AIO_CANCELED. + * If the request completes not matter if successfully or with an error it will + * switch into the completed state. RTFileReqDestroy() fails if the given request + * is in this state. + * + * Completed: + * The request will be in this state after it completed and returned through + * RTFileAioCtxWait(). RTFileAioReqGetRC() returns the final result code + * and the number of bytes transferred. + * The request can be used for new data transfers. + * + * @section sec_rt_asyncio_threading Threading + * + * The API is a thin wrapper around the specific host OS APIs and therefore + * relies on the thread safety of the underlying API. + * The interesting functions with regards to thread safety are RTFileAioCtxSubmit() + * and RTFileAioCtxWait(). RTFileAioCtxWait() must not be called from different + * threads at the same time with the same context handle. The same applies to + * RTFileAioCtxSubmit(). However it is possible to submit new requests from a different + * thread while waiting for completed requests on another thread with RTFileAioCtxWait(). + * + * @section sec_rt_asyncio_implementations Differences in implementation + * + * Because the host APIs are quite different on every OS and every API has other limitations + * there are some things to consider to make the code as portable as possible. + * + * The first restriction at the moment is that every buffer has to be aligned to a 512 byte boundary. + * This limitation comes from the Linux io_* interface. To use the interface the file + * must be opened with O_DIRECT. This flag disables the kernel cache too which may + * degrade performance but is unfortunately the only way to make asynchronous + * I/O work till today (if O_DIRECT is omitted io_submit will revert to sychronous behavior + * and will return when the requests finished and when they are queued). + * It is mostly used by DBMS which do theire own caching. + * Furthermore there is no filesystem independent way to discover the restrictions at least + * for the 2.4 kernel series. Since 2.6 the 512 byte boundary seems to be used by all + * file systems. So Linus comment about this flag is comprehensible but Linux + * lacks an alternative at the moment. + * + * The next limitation applies only to Windows. Requests are not associated with the + * I/O context they are associated with but with the file the request is for. + * The file needs to be associated with exactly one I/O completion port and requests + * for this file will only arrive at that context after they completed and not on + * the context the request was submitted. + * To associate a file with a specific context RTFileAioCtxAssociateWithFile() is + * used. It is only implemented on Windows and does nothing on the other platforms. + * If the file needs to be associated with different context for some reason + * the file must be closed first. After it was opened again the new context + * can be associated with the other context. + * This can't be done by the API because there is no way to retrieve the flags + * the file was opened with. + */ + +/** + * Global limits for the AIO API. + */ +typedef struct RTFILEAIOLIMITS +{ + /** Global number of simultaneous outstanding requests allowed. + * RTFILEAIO_UNLIMITED_REQS means no limit. */ + uint32_t cReqsOutstandingMax; + /** The alignment data buffers need to have. + * 0 means no alignment restrictions. */ + uint32_t cbBufferAlignment; +} RTFILEAIOLIMITS; +/** A pointer to a AIO limits structure. */ +typedef RTFILEAIOLIMITS *PRTFILEAIOLIMITS; + +/** + * Returns the global limits for the AIO API. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the host does not support the async I/O API. + * + * @param pAioLimits Where to store the global limit information. + */ +RTDECL(int) RTFileAioGetLimits(PRTFILEAIOLIMITS pAioLimits); + +/** + * Creates an async I/O request handle. + * + * @returns IPRT status code. + * @param phReq Where to store the request handle. + */ +RTDECL(int) RTFileAioReqCreate(PRTFILEAIOREQ phReq); + +/** + * Destroys an async I/O request handle. + * + * @returns IPRT status code. + * @retval VERR_FILE_AIO_IN_PROGRESS if the request is still in progress. + * + * @param hReq The request handle. + */ +RTDECL(int) RTFileAioReqDestroy(RTFILEAIOREQ hReq); + +/** + * Prepares an async read request. + * + * @returns IPRT status code. + * @retval VERR_FILE_AIO_IN_PROGRESS if the request is still in progress. + * + * @param hReq The request handle. + * @param hFile The file to read from. + * @param off The offset to start reading at. + * @param pvBuf Where to store the read bits. + * @param cbRead Number of bytes to read. + * @param pvUser Opaque user data associated with this request which + * can be retrieved with RTFileAioReqGetUser(). + */ +RTDECL(int) RTFileAioReqPrepareRead(RTFILEAIOREQ hReq, RTFILE hFile, RTFOFF off, + void *pvBuf, size_t cbRead, void *pvUser); + +/** + * Prepares an async write request. + * + * @returns IPRT status code. + * @retval VERR_FILE_AIO_IN_PROGRESS if the request is still in progress. + * + * @param hReq The request handle. + * @param hFile The file to write to. + * @param off The offset to start writing at. + * @param pvBuf The bits to write. + * @param cbWrite Number of bytes to write. + * @param pvUser Opaque user data associated with this request which + * can be retrieved with RTFileAioReqGetUser(). + */ +RTDECL(int) RTFileAioReqPrepareWrite(RTFILEAIOREQ hReq, RTFILE hFile, RTFOFF off, + void const *pvBuf, size_t cbWrite, void *pvUser); + +/** + * Prepares an async flush of all cached data associated with a file handle. + * + * @returns IPRT status code. + * @retval VERR_FILE_AIO_IN_PROGRESS if the request is still in progress. + * + * @param hReq The request handle. + * @param hFile The file to flush. + * @param pvUser Opaque user data associated with this request which + * can be retrieved with RTFileAioReqGetUser(). + * + * @remarks May also flush other caches on some platforms. + */ +RTDECL(int) RTFileAioReqPrepareFlush(RTFILEAIOREQ hReq, RTFILE hFile, void *pvUser); + +/** + * Gets the opaque user data associated with the given request. + * + * @returns Opaque user data. + * @retval NULL if the request hasn't been prepared yet. + * + * @param hReq The request handle. + */ +RTDECL(void *) RTFileAioReqGetUser(RTFILEAIOREQ hReq); + +/** + * Cancels a pending request. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS If the request was canceled. + * @retval VERR_FILE_AIO_NOT_SUBMITTED If the request wasn't submitted yet. + * @retval VERR_FILE_AIO_IN_PROGRESS If the request could not be canceled because it is already processed. + * @retval VERR_FILE_AIO_COMPLETED If the request could not be canceled because it already completed. + * + * @param hReq The request to cancel. + */ +RTDECL(int) RTFileAioReqCancel(RTFILEAIOREQ hReq); + +/** + * Gets the status of a completed request. + * + * @returns The IPRT status code of the given request. + * @retval VERR_FILE_AIO_NOT_SUBMITTED if the request wasn't submitted yet. + * @retval VERR_FILE_AIO_CANCELED if the request was canceled. + * @retval VERR_FILE_AIO_IN_PROGRESS if the request isn't yet completed. + * + * @param hReq The request handle. + * @param pcbTransferred Where to store the number of bytes transferred. + * Optional since it is not relevant for all kinds of + * requests. + */ +RTDECL(int) RTFileAioReqGetRC(RTFILEAIOREQ hReq, size_t *pcbTransferred); + + + +/** + * Creates an async I/O context. + * + * @todo briefly explain what an async context is here or in the page + * above. + * + * @returns IPRT status code. + * @param phAioCtx Where to store the async I/O context handle. + * @param cAioReqsMax How many async I/O requests the context should be capable + * to handle. Pass RTFILEAIO_UNLIMITED_REQS if the + * context should support an unlimited number of + * requests. + * @param fFlags Combination of RTFILEAIOCTX_FLAGS_*. + */ +RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax, + uint32_t fFlags); + +/** Unlimited number of requests. + * Used with RTFileAioCtxCreate and RTFileAioCtxGetMaxReqCount. */ +#define RTFILEAIO_UNLIMITED_REQS UINT32_MAX + +/** When set RTFileAioCtxWait() will always wait for completing requests, + * even when there is none waiting currently, instead of returning + * VERR_FILE_AIO_NO_REQUEST. */ +#define RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS RT_BIT_32(0) +/** mask of valid flags. */ +#define RTFILEAIOCTX_FLAGS_VALID_MASK (RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS) + +/** + * Destroys an async I/O context. + * + * @returns IPRT status code. + * @param hAioCtx The async I/O context handle. + */ +RTDECL(int) RTFileAioCtxDestroy(RTFILEAIOCTX hAioCtx); + +/** + * Get the maximum number of requests one aio context can handle. + * + * @returns Maximum number of tasks the context can handle. + * RTFILEAIO_UNLIMITED_REQS if there is no limit. + * + * @param hAioCtx The async I/O context handle. + * If NIL_RTAIOCONTEXT is passed the maximum value + * which can be passed to RTFileAioCtxCreate() + * is returned. + */ +RTDECL(uint32_t) RTFileAioCtxGetMaxReqCount(RTFILEAIOCTX hAioCtx); + +/** + * Associates a file with an async I/O context. + * Requests for this file will arrive at the completion port + * associated with the file. + * + * @returns IPRT status code. + * + * @param hAioCtx The async I/O context handle. + * @param hFile The file handle. + */ +RTDECL(int) RTFileAioCtxAssociateWithFile(RTFILEAIOCTX hAioCtx, RTFILE hFile); + +/** + * Submits a set of requests to an async I/O context for processing. + * + * @returns IPRT status code. + * @returns VERR_FILE_AIO_INSUFFICIENT_RESSOURCES if the maximum number of + * simultaneous outstanding requests would be exceeded. + * + * @param hAioCtx The async I/O context handle. + * @param pahReqs Pointer to an array of request handles. + * @param cReqs The number of entries in the array. + * + * @remarks It is possible that some requests could be submitted successfully + * even if the method returns an error code. In that case RTFileAioReqGetRC() + * can be used to determine the status of a request. + * If it returns VERR_FILE_AIO_IN_PROGRESS it was submitted successfully. + * Any other error code may indicate why the request failed. + * VERR_FILE_AIO_NOT_SUBMITTED indicates that a request wasn't submitted + * probably because the previous request encountered an error. + * + * @remarks @a cReqs uses the type size_t while it really is a uint32_t, this is + * to avoid annoying warnings when using RT_ELEMENTS and similar + * macros. + */ +RTDECL(int) RTFileAioCtxSubmit(RTFILEAIOCTX hAioCtx, PRTFILEAIOREQ pahReqs, size_t cReqs); + +/** + * Waits for request completion. + * + * Only one thread at a time may call this API on a context. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER If pcReqs or/and pahReqs are invalid. + * @retval VERR_INVALID_HANDLE If hAioCtx is invalid. + * @retval VERR_OUT_OF_RANGE If cMinReqs is larger than cReqs. + * @retval VERR_INVALID_PARAMETER If cReqs is 0. + * @retval VERR_TIMEOUT If cMinReqs didn't complete before the + * timeout expired. + * @retval VERR_INTERRUPTED If the completion context was interrupted + * by RTFileAioCtxWakeup(). + * @retval VERR_FILE_AIO_NO_REQUEST If there are no pending request. + * + * @param hAioCtx The async I/O context handle to wait and get + * completed requests from. + * @param cMinReqs The minimum number of requests which have to + * complete before this function returns. + * @param cMillies The number of milliseconds to wait before returning + * VERR_TIMEOUT. Use RT_INDEFINITE_WAIT to wait + * forever. + * @param pahReqs Pointer to an array where the handles of the + * completed requests will be stored on success. + * @param cReqs The number of entries @a pahReqs can hold. + * @param pcReqs Where to store the number of returned (complete) + * requests. This will always be set. + * + * @remarks The wait will be resume if interrupted by a signal. An + * RTFileAioCtxWaitNoResume variant can be added later if it becomes + * necessary. + * + * @remarks @a cMinReqs and @a cReqs use the type size_t while they really are + * uint32_t's, this is to avoid annoying warnings when using + * RT_ELEMENTS and similar macros. + */ +RTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL cMillies, + PRTFILEAIOREQ pahReqs, size_t cReqs, uint32_t *pcReqs); + +/** + * Forces any RTFileAioCtxWait() call on another thread to return immediately. + * + * @returns IPRT status code. + * + * @param hAioCtx The handle of the async I/O context to wakeup. + */ +RTDECL(int) RTFileAioCtxWakeup(RTFILEAIOCTX hAioCtx); + +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_file_h */ + diff --git a/include/iprt/formats/Makefile.kup b/include/iprt/formats/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/iprt/formats/Makefile.kup diff --git a/include/iprt/formats/apfs.h b/include/iprt/formats/apfs.h new file mode 100644 index 00000000..f45a37df --- /dev/null +++ b/include/iprt/formats/apfs.h @@ -0,0 +1,244 @@ +/* $Id: apfs.h $ */ +/** @file + * IPRT, APFS (Apple File System) format. + */ + +/* + * Copyright (C) 2019-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_apfs_h +#define IPRT_INCLUDED_formats_apfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_rt_formats_apfs Apple File System structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + +/* + * The filesystem structures were retrieved from: + * https://developer.apple.com/support/downloads/Apple-File-System-Reference.pdf + */ + +/** Physical address of an on-disk block. */ +typedef int64_t APFSPADDR; +/** Object identifier. */ +typedef uint64_t APFSOID; +/** Transaction identifier. */ +typedef uint64_t APFSXID; + +/** Invalid object ID. */ +#define APFS_OID_INVALID UINT64_C(0) +/** Number of reserved object IDs for special structures. */ +#define APFS_OID_RSVD_CNT 1024 +/** Object ID of a super block. */ +#define APFS_OID_NX_SUPERBLOCK UINT64_C(1) + + +/** + * Range of physical addresses. + */ +typedef struct +{ + /** Start address of the range. */ + APFSPADDR PAddrStart; + /** Size of the range in blocks.*/ + uint64_t cBlocks; +} APFSPRANGE; +/** Pointer to a APFS range. */ +typedef APFSPRANGE *PAPFSPRANGE; +/** Pointer to a const APFS range. */ +typedef const APFSPRANGE *PCAPFSPRANGE; + +/** APFS UUID (compatible with our UUID definition). */ +typedef RTUUID APFSUUID; + +/** Maximum object checksum size. */ +#define APFS_OBJ_MAX_CHKSUM_SZ 8 + +/** + * APFS Object header. + */ +typedef struct APFSOBJPHYS +{ + /** The stored checksum of the object. */ + uint8_t abChkSum[APFS_OBJ_MAX_CHKSUM_SZ]; + /** Object ID. */ + APFSOID Oid; + /** Transaction ID. */ + APFSXID Xid; + /** Object type. */ + uint32_t u32Type; + /** Object sub type. */ + uint32_t u32SubType; +} APFSOBJPHYS; +/** Pointer to an APFS object header. */ +typedef APFSOBJPHYS *PAPFSOBJPHYS; +/** Pointer to a const APFS object header. */ +typedef const APFSOBJPHYS *PCAPFSOBJPHYS; + +#define APFS_OBJECT_TYPE_MASK UINT32_C(0x0000ffff) +#define APFS_OBJECT_TYPE_FLAGS_MASK UINT32_C(0xffff0000) + +/** + * APFS EFI jumpstart information. + */ +typedef struct APFSEFIJMPSTART +{ + /** Object header. */ + APFSOBJPHYS ObjHdr; + /** The magic value. */ + uint32_t u32Magic; + /** The version of the structure. */ + uint32_t u32Version; + /** EFI file length in bytes. */ + uint32_t cbEfiFile; + /** Number of extents describing the on disk blocks the file is stored in. */ + uint32_t cExtents; + /** Reserved. */ + uint64_t au64Rsvd0[16]; + /** After this comes a variable size of APFSPRANGE extent structures. */ +} APFSEFIJMPSTART; +/** Pointer to an APFS EFI jumpstart structure. */ +typedef APFSEFIJMPSTART *PAPFSEFIJMPSTART; +/** Pointer to a const APFS EFI jumpstart structure. */ +typedef const APFSEFIJMPSTART *PCAPFSEFIJMPSTART; + +/** EFI jumpstart magic ('RDSJ'). */ +#define APFS_EFIJMPSTART_MAGIC RT_MAKE_U32_FROM_U8('J', 'S', 'D', 'R') +/** EFI jumpstart version. */ +#define APFS_EFIJMPSTART_VERSION UINT32_C(1) + +/** Maximum number of filesystems supported in a single container. */ +#define APFS_NX_SUPERBLOCK_FS_MAX UINT32_C(100) +/** Maximum number of counters in the superblock. */ +#define APFS_NX_SUPERBLOCK_COUNTERS_MAX UINT32_C(32) +/** Number of entries in the ephemeral information array. */ +#define APFS_NX_SUPERBLOCK_EPH_INFO_COUNT UINT32_C(4) + +/** + * APFS super block. + */ +typedef struct +{ + /** Object header. */ + APFSOBJPHYS ObjHdr; + /** The magic value. */ + uint32_t u32Magic; + /** Block size in bytes. */ + uint32_t cbBlock; + /** Number of blocks in the volume. */ + uint64_t cBlocks; + /** Feature flags of the volume. */ + uint64_t fFeatures; + /** Readonly compatible features. */ + uint64_t fRdOnlyCompatFeatures; + /** Incompatible features. */ + uint64_t fIncompatFeatures; + /** UUID of the volume. */ + APFSUUID Uuid; + /** Next free object identifier to use for new objects. */ + APFSOID OidNext; + /** Next free transaction identifier to use for new transactions. */ + APFSOID XidNext; + /** Number of blocks used by the checkpoint descriptor area. */ + uint32_t cXpDescBlocks; + /** Number of blocks used by the checkpoint data area. */ + uint32_t cXpDataBlocks; + /** Base address of checkpoint descriptor area. */ + APFSPADDR PAddrXpDescBase; + /** Base address of checkpoint data area. */ + APFSPADDR PAddrXpDataBase; + /** Next index to use in the checkpoint descriptor area. */ + uint32_t idxXpDescNext; + /** Next index to use in the checkpoint data area. */ + uint32_t idxXpDataNext; + /** Number of blocks in the checkpoint descriptor area used by the checkpoint that this superblock belongs to. */ + uint32_t cXpDescLen; + /** Index of the first valid item in the checkpoint data area. */ + uint32_t idxXpDataFirst; + /** Number of blocks in the checkpoint data area used by the checkpoint that this superblock belongs to. */ + uint32_t cXpDataLen; + /** Ephemeral object identifer of the space manager. */ + APFSOID OidSpaceMgr; + /** Physical object identifier for the containers object map. */ + APFSOID OidOMap; + /** Ephemeral object identifer for the reaper. */ + APFSOID OidReaper; + /** Reserved for testing should be always zero on disk. */ + uint32_t u32TestType; + /** Maximum number of filesystems which can be stored in this container. */ + uint32_t cFsMax; + /** Array of filesystem object identifiers. */ + APFSOID aFsOids[APFS_NX_SUPERBLOCK_FS_MAX]; + /** Array of counters primarily used during debugging. */ + uint64_t aCounters[APFS_NX_SUPERBLOCK_COUNTERS_MAX]; + /** Range of blocks where no space will be allocated, used for shrinking a partition. */ + APFSPRANGE RangeBlocked; + /** Physical object identifier of a tree keeping track of objects needing to be moved out of the block range. */ + APFSOID OidTreeEvictMapping; + /** Container flags. */ + uint64_t fFlags; + /** Address of the EFI jumpstart structure. */ + APFSPADDR PAddrEfiJmpStart; + /** UUID of the containers Fusion set if available. */ + APFSUUID UuidFusion; + /** Address of the containers keybag. */ + APFSPADDR PAddrKeyLocker; + /** Array of fields used in the management of ephemeral data. */ + uint64_t au64EphemeralInfo[APFS_NX_SUPERBLOCK_EPH_INFO_COUNT]; + /** Reserved for testing. */ + APFSOID OidTest; + /** Physical object identifier of the Fusion middle tree. */ + APFSOID OidFusionMt; + /** Ephemeral object identifier of the Fusion write-back cache state. */ + APFSOID OidFusionWbc; + /** Blocks used for the Fusion write-back cache area. */ + APFSPRANGE RangeFusionWbc; +} APFSNXSUPERBLOCK; +/** Pointer to a APFS super block structure. */ +typedef APFSNXSUPERBLOCK *PAPFSNXSUPERBLOCK; +/** Pointer to a const APFS super block structure. */ +typedef const APFSNXSUPERBLOCK *PCAPFSNXSUPERBLOCK; + +/** Superblock magic value ('BSXN'). */ +#define APFS_NX_SUPERBLOCK_MAGIC RT_MAKE_U32_FROM_U8('N', 'X', 'S', 'B') + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_apfs_h */ + diff --git a/include/iprt/formats/asn1.h b/include/iprt/formats/asn1.h new file mode 100644 index 00000000..d1ba8f80 --- /dev/null +++ b/include/iprt/formats/asn1.h @@ -0,0 +1,107 @@ +/** @file + * IPRT - Abstract Syntax Notation One (ASN.1) Definitions. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_asn1_h +#define IPRT_INCLUDED_formats_asn1_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> + + +/** @defgroup grp_rt_formats_asn1 ASN.1 definitions + * @ingroup grp_rt_formats + * + * @{ */ + +/** @name Tag classes. + * @{ */ +#define ASN1_TAGCLASS_UNIVERSAL UINT8_C(0x00) +#define ASN1_TAGCLASS_APPLICATION UINT8_C(0x40) +#define ASN1_TAGCLASS_CONTEXT UINT8_C(0x80) +#define ASN1_TAGCLASS_PRIVATE UINT8_C(0xc0) +#define ASN1_TAGCLASS_MASK UINT8_C(0xc0) +/** @} */ + +/** Primitive encoding. */ +#define ASN1_TAGFLAG_PRIMITIVE UINT8_C(0x00) +/** Constructed encoding, as opposed to primitive. */ +#define ASN1_TAGFLAG_CONSTRUCTED UINT8_C(0x20) + +/** The tag value mask. */ +#define ASN1_TAG_MASK UINT8_C(0x1f) + +/** @name ASN.1 universal tags. + * @{ */ +#define ASN1_TAG_EOC UINT8_C(0x00) +#define ASN1_TAG_BOOLEAN UINT8_C(0x01) +#define ASN1_TAG_INTEGER UINT8_C(0x02) +#define ASN1_TAG_BIT_STRING UINT8_C(0x03) +#define ASN1_TAG_OCTET_STRING UINT8_C(0x04) +#define ASN1_TAG_NULL UINT8_C(0x05) +#define ASN1_TAG_OID UINT8_C(0x06) +#define ASN1_TAG_OBJECT_DESCRIPTOR UINT8_C(0x07) +#define ASN1_TAG_EXTERNAL UINT8_C(0x08) +#define ASN1_TAG_REAL UINT8_C(0x09) +#define ASN1_TAG_ENUMERATED UINT8_C(0x0a) +#define ASN1_TAG_EMBEDDED_PDV UINT8_C(0x0b) +#define ASN1_TAG_UTF8_STRING UINT8_C(0x0c) +#define ASN1_TAG_RELATIVE_OID UINT8_C(0x0d) +#define ASN1_TAG_RESERVED_14 UINT8_C(0x0e) +#define ASN1_TAG_RESERVED_15 UINT8_C(0x0f) +#define ASN1_TAG_SEQUENCE UINT8_C(0x10) +#define ASN1_TAG_SET UINT8_C(0x11) +#define ASN1_TAG_NUMERIC_STRING UINT8_C(0x12) +#define ASN1_TAG_PRINTABLE_STRING UINT8_C(0x13) +#define ASN1_TAG_T61_STRING UINT8_C(0x14) +#define ASN1_TAG_VIDEOTEX_STRING UINT8_C(0x15) +#define ASN1_TAG_IA5_STRING UINT8_C(0x16) +#define ASN1_TAG_UTC_TIME UINT8_C(0x17) /**< Century seems to be 1900 if YY < 50, otherwise 2000. Baka ASN.1! */ +#define ASN1_TAG_GENERALIZED_TIME UINT8_C(0x18) +#define ASN1_TAG_GRAPHIC_STRING UINT8_C(0x19) +#define ASN1_TAG_VISIBLE_STRING UINT8_C(0x1a) +#define ASN1_TAG_GENERAL_STRING UINT8_C(0x1b) +#define ASN1_TAG_UNIVERSAL_STRING UINT8_C(0x1c) +#define ASN1_TAG_CHARACTER_STRING UINT8_C(0x1d) +#define ASN1_TAG_BMP_STRING UINT8_C(0x1e) +#define ASN1_TAG_USE_LONG_FORM UINT8_C(0x1f) +/** @} */ + + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_asn1_h */ + diff --git a/include/iprt/formats/bmp.h b/include/iprt/formats/bmp.h new file mode 100644 index 00000000..1a1625df --- /dev/null +++ b/include/iprt/formats/bmp.h @@ -0,0 +1,192 @@ +/* $Id: bmp.h $ */ +/** @file + * IPRT - Microsoft Bitmap Formats (BMP). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_bmp_h +#define IPRT_INCLUDED_formats_bmp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_rt_fmt_bmp Microsoft Bitmaps Formats (BMP) + * @ingroup grp_rt_formats + * @{ + */ + +/** @name BMP header sizes (in bytes). + * @{ */ +#define BMP_HDR_SIZE_FILE 14 +#define BMP_HDR_SIZE_OS21 12 +#define BMP_HDR_SIZE_OS22 64 +#define BMP_HDR_SIZE_WIN3X 40 +/** @} */ + + +/** BMP format file header. */ +#pragma pack(1) +typedef struct BMPFILEHDR +{ + /** File type identifier ("magic"). */ + uint16_t uType; + /** Size of file in bytes. */ + uint32_t cbFileSize; + /** Reserved (should be 0). */ + uint16_t Reserved1; + /** Reserved (should be 0). */ + uint16_t Reserved2; + /** Offset (in bytes) to bitmap data. */ + uint32_t offBits; +} BMPFILEHDR; +#pragma pack() +AssertCompileSize(BMPFILEHDR, BMP_HDR_SIZE_FILE); +/** Pointer to a BMP format file header. */ +typedef BMPFILEHDR *PBMPFILEHDR; + +/** BMP file magic number for BMP / DIB. */ +#define BMP_HDR_MAGIC (RT_H2LE_U16_C(0x4d42)) + +/** OS/2 1.x BMP core header, + * also known as BITMAPCOREHEADER. */ +typedef struct BMPOS2COREHDR +{ + /** Size (in bytes) of remaining header. */ + uint32_t cbSize; + /** Width of bitmap in pixels. */ + uint16_t uWidth; + /** Height of bitmap in pixels. */ + uint16_t uHeight; + /** Number of planes. */ + uint16_t cPlanes; + /** Color bits per pixel. */ + uint16_t cBits; +} BMPOS2COREHDR; +AssertCompileSize(BMPOS2COREHDR, BMP_HDR_SIZE_OS21); +/** Pointer to a OS/2 1.x BMP core header. */ +typedef BMPOS2COREHDR *PBMPOS2COREHDR; + +/** OS/2 2.0 BMP core header, version 2, + * also known as BITMAPCOREHEADER2. */ +typedef struct BMPOS2COREHDR2 +{ + /** Size (in bytes) of remaining header. */ + uint32_t cbSize; + /** Width of bitmap in pixels. */ + uint32_t uWidth; + /** Height of bitmap in pixels. */ + uint32_t uHeight; + /** Number of planes. */ + uint16_t cPlanes; + /** Color bits per pixel. */ + uint16_t cBits; + /** Compression scheme of type BMP_COMPRESSION_TYPE. */ + uint32_t enmCompression; + /** Size of bitmap in bytes. */ + uint32_t cbSizeImage; + /** Horz. resolution in pixels/meter. */ + uint32_t uXPelsPerMeter; + /** Vert. resolution in pixels/meter. */ + uint32_t uYPelsPerMeter; + /** Number of colors in color table. */ + uint32_t cClrUsed; + /** Number of important colors. */ + uint32_t cClrImportant; + /** Resolution measurement Used. */ + uint16_t uUnits; + /** Reserved fields (always 0). */ + uint16_t Reserved; + /** Orientation of bitmap. */ + uint16_t uRecording; + /** Halftone algorithm used on image. */ + uint16_t enmHalftone; + /** Halftone algorithm data. */ + uint32_t uHalftoneParm1; + /** Halftone algorithm data. */ + uint32_t uHalftoneParm2; + /** Color table format (always 0). */ + uint32_t uColorEncoding; + /** Misc. field for application use . */ + uint32_t uIdentifier; +} BMPOS2COREHDR2; +AssertCompileSize(BMPOS2COREHDR2, BMP_HDR_SIZE_OS22); +/** Pointer to an OS/2 2.0 BMP core header version 2. */ +typedef BMPOS2COREHDR2 *PBMPOS2COREHDR2; + +/** Windows 3.x BMP information header Format. */ +typedef struct BMPWIN3XINFOHDR +{ + /** Size (in bytes) of remaining header. */ + uint32_t cbSize; + /** Width of bitmap in pixels. */ + uint32_t uWidth; + /** Height of bitmap in pixels. */ + uint32_t uHeight; + /** Number of planes. */ + uint16_t cPlanes; + /** Color bits per pixel. */ + uint16_t cBits; + /** Compression scheme of type BMP_COMPRESSION_TYPE. */ + uint32_t enmCompression; + /** Size of bitmap in bytes. */ + uint32_t cbSizeImage; + /** Horz. resolution in pixels/meter. */ + uint32_t uXPelsPerMeter; + /** Vert. resolution in pixels/meter. */ + uint32_t uYPelsPerMeter; + /** Number of colors in color table. */ + uint32_t cClrUsed; + /** Number of important colors. */ + uint32_t cClrImportant; +} BMPWIN3XINFOHDR; +AssertCompileSize(BMPWIN3XINFOHDR, BMP_HDR_SIZE_WIN3X); +/** Pointer to a Windows 3.x BMP information header. */ +typedef BMPWIN3XINFOHDR *PBMPWIN3XINFOHDR; + + + +/** @name BMP compression types. + * @{ */ +#define BMP_COMPRESSION_TYPE_NONE 0 +#define BMP_COMPRESSION_TYPE_RLE8 1 +#define BMP_COMPRESSION_TYPE_RLE4 2 +/** @} */ + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_bmp_h */ + diff --git a/include/iprt/formats/codeview.h b/include/iprt/formats/codeview.h new file mode 100644 index 00000000..f8cf66ab --- /dev/null +++ b/include/iprt/formats/codeview.h @@ -0,0 +1,870 @@ +/** @file + * IPRT - Microsoft CodeView Debug Information. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_codeview_h +#define IPRT_INCLUDED_formats_codeview_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_rt_fmt_codeview Microsoft CodeView Debug Information + * @{ + */ + + +/** + * CodeView Header. There are two of this, base header at the start of the debug + * information and a trailing header at the end. + */ +typedef struct RTCVHDR +{ + /** The magic ('NBxx'), see RTCVHDR_MAGIC_XXX. */ + uint32_t u32Magic; + /** + * Base header: Subsection directory offset relative to this header (start). + * Trailing header: Offset of the base header relative to the end of the file. + * + * Called lfoBase, lfaBase, lfoDirectory, lfoDir and probably other things in + * the various specs/docs available. */ + uint32_t off; +} RTCVHDR; +/** Pointer to a CodeView header. */ +typedef RTCVHDR *PRTCVHDR; + +/** @name CodeView magic values (RTCVHDR::u32Magic). + * @{ */ +/** CodeView from Visual C++ 5.0. Specified in the 2001 MSDN specs.chm file. */ +#define RTCVHDR_MAGIC_NB11 RT_MAKE_U32_FROM_U8('N', 'B', '1', '1') +/** External PDB reference (often referred to as PDB 2.0). */ +#define RTCVHDR_MAGIC_NB10 RT_MAKE_U32_FROM_U8('N', 'B', '1', '0') +/** CodeView v4.10, packed. Specified in the TIS document. */ +#define RTCVHDR_MAGIC_NB09 RT_MAKE_U32_FROM_U8('N', 'B', '0', '9') +/** CodeView v4.00 thru v4.05. Specified in the TIS document? */ +#define RTCVHDR_MAGIC_NB08 RT_MAKE_U32_FROM_U8('N', 'B', '0', '8') +/** Quick C for Windows 1.0 debug info. */ +#define RTCVHDR_MAGIC_NB07 RT_MAKE_U32_FROM_U8('N', 'B', '0', '7') +/** Emitted by ILINK indicating incremental link. Comparable to NB05? */ +#define RTCVHDR_MAGIC_NB06 RT_MAKE_U32_FROM_U8('N', 'B', '0', '6') +/** Emitted by LINK version 5.20 and later before packing. */ +#define RTCVHDR_MAGIC_NB05 RT_MAKE_U32_FROM_U8('N', 'B', '0', '5') +/** Emitted by IBM ILINK for HLL (similar to NB02 in many ways). */ +#define RTCVHDR_MAGIC_NB04 RT_MAKE_U32_FROM_U8('N', 'B', '0', '4') +/** Emitted by LINK version 5.10 (or similar OMF linkers), as shipped with + * Microsoft C v6.0 for example. More or less entirely 16-bit. */ +#define RTCVHDR_MAGIC_NB02 RT_MAKE_U32_FROM_U8('N', 'B', '0', '2') +/* No idea what NB03 might have been. */ +/** AIX debugger format according to "IBM OS/2 16/32-bit Object Module Format + * (OMF) and Linear eXecutable Module Format (LX)" revision 10 (LXOMF.PDF). */ +#define RTCVHDR_MAGIC_NB01 RT_MAKE_U32_FROM_U8('N', 'B', '0', '1') +/** Ancient CodeView format according to LXOMF.PDF. */ +#define RTCVHDR_MAGIC_NB00 RT_MAKE_U32_FROM_U8('N', 'B', '0', '0') +/** @} */ + + +/** @name CV directory headers. + * @{ */ + +/** + * Really old CV directory header used with NB00 and NB02. + * + * Uses 16-bit directory entires (RTCVDIRENT16). + */ +typedef struct RTCVDIRHDR16 +{ + /** The number of directory entries. */ + uint16_t cEntries; +} RTCVDIRHDR16; +/** Pointer to a old CV directory header. */ +typedef RTCVDIRHDR16 *PRTCVDIRHDR16; + +/** + * Simple 32-bit CV directory base header, used by NB04 (aka IBM HLL). + */ +typedef struct RTCVDIRHDR32 +{ + /** The number of bytes of this header structure. */ + uint16_t cbHdr; + /** The number of bytes per entry. */ + uint16_t cbEntry; + /** The number of directory entries. */ + uint32_t cEntries; +} RTCVDIRHDR32; +/** Pointer to a 32-bit CV directory header. */ +typedef RTCVDIRHDR32 *PRTCVDIRHDR32; + +/** + * Extended 32-bit CV directory header as specified in the TIS doc. + * The two extra fields seems to never have been assigned any official purpose. + */ +typedef struct RTCVDIRHDR32EX +{ + /** This starts the same way as the NB04 header. */ + RTCVDIRHDR32 Core; + /** Tentatively decleared as the offset to the next directory generated by + * the incremental linker. Haven't seen this used yet. */ + uint32_t offNextDir; + /** Flags, non defined apparently, so MBZ. */ + uint32_t fFlags; +} RTCVDIRHDR32EX; +/** Pointer to an extended 32-bit CV directory header. */ +typedef RTCVDIRHDR32EX *PRTCVDIRHDR32EX; + +/** @} */ + + +/** + * 16-bit CV directory entry used with NB00 and NB02. + */ +typedef struct RTCVDIRENT16 +{ + /** Subsection type (RTCVSST). */ + uint16_t uSubSectType; + /** Which module (1-based, 0xffff is special). */ + uint16_t iMod; + /** The lowe offset of this subsection relative to the base CV header. */ + uint16_t offLow; + /** The high part of the subsection offset. */ + uint16_t offHigh; + /** The size of the subsection. */ + uint16_t cb; +} RTCVDIRENT16; +AssertCompileSize(RTCVDIRENT16, 10); +/** Pointer to a 16-bit CV directory entry. */ +typedef RTCVDIRENT16 *PRTCVDIRENT16; + + +/** + * 32-bit CV directory entry used starting with NB04. + */ +typedef struct RTCVDIRENT32 +{ + /** Subsection type (RTCVSST). */ + uint16_t uSubSectType; + /** Which module (1-based, 0xffff is special). */ + uint16_t iMod; + /** The offset of this subsection relative to the base CV header. */ + uint32_t off; + /** The size of the subsection. */ + uint32_t cb; +} RTCVDIRENT32; +AssertCompileSize(RTCVDIRENT32, 12); +/** Pointer to a 32-bit CV directory entry. */ +typedef RTCVDIRENT32 *PRTCVDIRENT32; +/** Pointer to a const 32-bit CV directory entry. */ +typedef RTCVDIRENT32 const *PCRTCVDIRENT32; + + +/** + * CodeView subsection types. + */ +typedef enum RTCVSST +{ + /** @name NB00, NB02 and NB04 subsection types. + * The actual format of each subsection varies between NB04 and the others, + * and it may further vary in NB04 depending on the module type. + * @{ */ + kCvSst_OldModule = 0x101, + kCvSst_OldPublic, + kCvSst_OldTypes, + kCvSst_OldSymbols, + kCvSst_OldSrcLines, + kCvSst_OldLibraries, + kCvSst_OldImports, + kCvSst_OldCompacted, + kCvSst_OldSrcLnSeg = 0x109, + kCvSst_OldSrcLines3 = 0x10b, + /** @} */ + + /** @name NB09, NB11 (and possibly NB05, NB06, NB07, and NB08) subsection types. + * @{ */ + kCvSst_Module = 0x120, + kCvSst_Types, + kCvSst_Public, + kCvSst_PublicSym, + kCvSst_Symbols, + kCvSst_AlignSym, + kCvSst_SrcLnSeg, + kCvSst_SrcModule, + kCvSst_Libraries, + kCvSst_GlobalSym, + kCvSst_GlobalPub, + kCvSst_GlobalTypes, + kCvSst_MPC, + kCvSst_SegMap, + kCvSst_SegName, + kCvSst_PreComp, + kCvSst_PreCompMap, + kCvSst_OffsetMap16, + kCvSst_OffsetMap32, + kCvSst_FileIndex = 0x133, + kCvSst_StaticSym + /** @} */ +} RTCVSST; +/** Pointer to a CV subsection type value. */ +typedef RTCVSST *PRTCVSST; +/** Pointer to a const CV subsection type value. */ +typedef RTCVSST const *PCRTCVSST; + + +/** + * CV4 module segment info. + */ +typedef struct RTCVMODSEGINFO32 +{ + /** The segment number. */ + uint16_t iSeg; + /** Explicit padding. */ + uint16_t u16Padding; + /** Offset into the segment. */ + uint32_t off; + /** The size of the contribution. */ + uint32_t cb; +} RTCVMODSEGINFO32; +typedef RTCVMODSEGINFO32 *PRTCVMODSEGINFO32; +typedef RTCVMODSEGINFO32 const *PCRTCVMODSEGINFO32; + + +/** + * CV4 segment map header. + */ +typedef struct RTCVSEGMAPHDR +{ + /** Number of segments descriptors in the table. */ + uint16_t cSegs; + /** Number of logical segment descriptors. */ + uint16_t cLogSegs; +} RTCVSEGMAPHDR; +/** Pointer to a CV4 segment map header. */ +typedef RTCVSEGMAPHDR *PRTCVSEGMAPHDR; +/** Pointer to a const CV4 segment map header. */ +typedef RTCVSEGMAPHDR const *PCRTCVSEGMAPHDR; + +/** + * CV4 Segment map descriptor entry. + */ +typedef struct RTCVSEGMAPDESC +{ + /** Segment flags. */ + uint16_t fFlags; + /** The overlay number. */ + uint16_t iOverlay; + /** Group index into this segment descriptor array. 0 if not relevant. + * The group descriptors are found in the second half of the table. */ + uint16_t iGroup; + /** Complicated. */ + uint16_t iFrame; + /** Offset (byte) into the kCvSst_SegName table of the segment name, or + * 0xffff. */ + uint16_t offSegName; + /** Offset (byte) into the kCvSst_SegName table of the class name, or 0xffff. */ + uint16_t offClassName; + /** Offset into the physical segment. */ + uint32_t off; + /** Size of segment. */ + uint32_t cb; +} RTCVSEGMAPDESC; +/** Pointer to a segment map descriptor entry. */ +typedef RTCVSEGMAPDESC *PRTCVSEGMAPDESC; +/** Pointer to a const segment map descriptor entry. */ +typedef RTCVSEGMAPDESC const *PCRTCVSEGMAPDESC; + +/** @name RTCVSEGMAPDESC_F_XXX - RTCVSEGMAPDESC::fFlags values. + * @{ */ +#define RTCVSEGMAPDESC_F_READ UINT16_C(0x0001) +#define RTCVSEGMAPDESC_F_WRITE UINT16_C(0x0002) +#define RTCVSEGMAPDESC_F_EXECUTE UINT16_C(0x0004) +#define RTCVSEGMAPDESC_F_32BIT UINT16_C(0x0008) +#define RTCVSEGMAPDESC_F_SEL UINT16_C(0x0100) +#define RTCVSEGMAPDESC_F_ABS UINT16_C(0x0200) +#define RTCVSEGMAPDESC_F_GROUP UINT16_C(0x1000) +#define RTCVSEGMAPDESC_F_RESERVED UINT16_C(0xecf0) +/** @} */ + +/** + * CV4 segment map subsection. + */ +typedef struct RTCVSEGMAP +{ + /** The header. */ + RTCVSEGMAPHDR Hdr; + /** Descriptor array. */ + RTCVSEGMAPDESC aDescs[1]; +} RTCVSEGMAP; +/** Pointer to a segment map subsection. */ +typedef RTCVSEGMAP *PRTCVSEGMAP; +/** Pointer to a const segment map subsection. */ +typedef RTCVSEGMAP const *PCRTCVSEGMAP; + + +/** + * CV4 line number segment contribution start/end table entry. + * Part of RTCVSRCMODULE. + */ +typedef struct RTCVSRCRANGE +{ + /** Start segment offset. */ + uint32_t offStart; + /** End segment offset (inclusive?). */ + uint32_t offEnd; +} RTCVSRCRANGE; +/** Pointer to a line number segment contributation. */ +typedef RTCVSRCRANGE *PRTCVSRCRANGE; +/** Pointer to a const line number segment contributation. */ +typedef RTCVSRCRANGE const *PCRTCVSRCRANGE; + +/** + * CV4 header for a line number subsection, used by kCvSst_SrcModule. + * + * The aoffSrcFiles member is followed by an array of segment ranges + * (RTCVSRCRANGE), cSegs in length. This may contain zero entries if the + * information is not known or not possible to express in this manner. + * + * After the range table, a segment index (uint16_t) mapping table follows, also + * cSegs in length. + */ +typedef struct RTCVSRCMODULE +{ + /** The number of files described in this subsection. */ + uint16_t cFiles; + /** The number of code segments this module contributes to. */ + uint16_t cSegs; + /** Offsets of the RTCVSRCFILE entries in this subsection, length given by + * the above cFiles member. */ + uint32_t aoffSrcFiles[1 /*cFiles*/]; + /* RTCVSRCRANGE aSegRanges[cSegs]; */ + /* uint16_t aidxSegs[cSegs]; */ +} RTCVSRCMODULE; +/** Pointer to a source module subsection header. */ +typedef RTCVSRCMODULE *PRTCVSRCMODULE; +/** Pointer to a const source module subsection header. */ +typedef RTCVSRCMODULE const *PCRTCVSRCMODULE; + +/** + * CV4 source file, inside a kCvSst_SrcModule (see RTCVSRCMODULE::aoffSrcFiles) + * + * The aoffSrcLines member is followed by an array of segment ranges + * (RTCVSRCRANGE), cSegs in length. Just like for RTCVSRCMODULE this may + * contain zero entries. + * + * After the range table is the filename, which is preceeded by a 8-bit length + * (actually documented to be 16-bit, but seeing 8-bit here with wlink). + */ +typedef struct RTCVSRCFILE +{ + /** The number segments that this source file contributed to. */ + uint16_t cSegs; + /** Alignment padding. */ + uint16_t uPadding; + /** Offsets of the RTCVSRCLN entries for this source file, length given by + * the above cSegs member. Relative to the start of the subsection. */ + uint32_t aoffSrcLines[1 /*cSegs*/]; + /* RTCVSRCRANGE aSegRanges[cSegs]; */ + /* uint8_t/uint16_t cchName; */ + /* char achName[cchName]; */ +} RTCVSRCFILE; +/** Pointer to a source file. */ +typedef RTCVSRCFILE *PRTCVSRCFILE; +/** Pointer to a const source file. */ +typedef RTCVSRCFILE const *PCRTCVSRCFILE; + +/** + * CV4 line numbers header. + * + * The aoffLines member is followed by an array of line numbers (uint16_t). + */ +typedef struct RTCVSRCLINE +{ + /** The index of the segment these line numbers belong to. */ + uint16_t idxSeg; + /** The number of line number pairs the two following tables. */ + uint16_t cPairs; + /** Segment offsets, cPairs long. */ + uint32_t aoffLines[1 /*cPairs*/]; + /* uint16_t aiLines[cPairs]; */ +} RTCVSRCLINE; +/** Pointer to a line numbers header. */ +typedef RTCVSRCLINE *PRTCVSRCLINE; +/** Pointer to a const line numbers header. */ +typedef RTCVSRCLINE const *PCRTCVSRCLINE; + + +/** + * Global symbol table header, used by kCvSst_GlobalSym and kCvSst_GlobalPub. + */ +typedef struct RTCVGLOBALSYMTABHDR +{ + /** The symbol hash function. */ + uint16_t uSymHash; + /** The address hash function. */ + uint16_t uAddrHash; + /** The amount of symbol information following immediately after the header. */ + uint32_t cbSymbols; + /** The amount of symbol hash tables following the symbols. */ + uint32_t cbSymHash; + /** The amount of address hash tables following the symbol hash tables. */ + uint32_t cbAddrHash; +} RTCVGLOBALSYMTABHDR; +/** Pointer to a global symbol table header. */ +typedef RTCVGLOBALSYMTABHDR *PRTCVGLOBALSYMTABHDR; +/** Pointer to a const global symbol table header. */ +typedef RTCVGLOBALSYMTABHDR const *PCRTCVGLOBALSYMTABHDR; + + +typedef enum RTCVSYMTYPE +{ + /** @name Symbols that doesn't change with compilation model or target machine. + * @{ */ + kCvSymType_Compile = 0x0001, + kCvSymType_Register, + kCvSymType_Constant, + kCvSymType_UDT, + kCvSymType_SSearch, + kCvSymType_End, + kCvSymType_Skip, + kCvSymType_CVReserve, + kCvSymType_ObjName, + kCvSymType_EndArg, + kCvSymType_CobolUDT, + kCvSymType_ManyReg, + kCvSymType_Return, + kCvSymType_EntryThis, + /** @} */ + + /** @name Symbols with 16:16 addresses. + * @{ */ + kCvSymType_BpRel16 = 0x0100, + kCvSymType_LData16, + kCvSymType_GData16, + kCvSymType_Pub16, + kCvSymType_LProc16, + kCvSymType_GProc16, + kCvSymType_Thunk16, + kCvSymType_BLock16, + kCvSymType_With16, + kCvSymType_Label16, + kCvSymType_CExModel16, + kCvSymType_VftPath16, + kCvSymType_RegRel16, + /** @} */ + + /** @name Symbols with 16:32 addresses. + * @{ */ + kCvSymType_BpRel32 = 0x0200, + kCvSymType_LData32, + kCvSymType_GData32, + kCvSymType_Pub32, + kCvSymType_LProc32, + kCvSymType_GProc32, + kCvSymType_Thunk32, + kCvSymType_Block32, + kCvSymType_With32, + kCvSymType_Label32, + kCvSymType_CExModel32, + kCvSymType_VftPath32, + kCvSymType_RegRel32, + kCvSymType_LThread32, + kCvSymType_GThread32, + /** @} */ + + /** @name Symbols for MIPS. + * @{ */ + kCvSymType_LProcMips = 0x0300, + kCvSymType_GProcMips, + /** @} */ + + /** @name Symbols for Microsoft CodeView. + * @{ */ + kCvSymType_ProcRef = 0x0400, + kCvSymType_DataRef, + kCvSymType_Align, + kCvSymType_LProcRef, + /** @} */ + + /** @name Symbols with 32-bit address (I think) and 32-bit type indices. + * @{ */ + kCvSymType_V2_Register = 0x1001, + kCvSymType_V2_Constant, + kCvSymType_V2_Udt, + kCvSymType_V2_CobolUdt, + kCvSymType_V2_ManyReg, + kCvSymType_V2_BpRel, + kCvSymType_V2_LData, + kCvSymType_V2_GData, + kCvSymType_V2_Pub, + kCvSymType_V2_LProc, + kCvSymType_V2_GProc, + kCvSymType_V2_VftTable, + kCvSymType_V2_RegRel, + kCvSymType_V2_LThread, + kCvSymType_V2_GThread, + kCvSymType_V2_Unknown_1010, + kCvSymType_V2_Unknown_1011, + kCvSymType_V2_FrameInfo, + kCvSymType_V2_Compliand, + /** @} */ + + /** @name Version 3 symbol types. + * @{ */ + /** Name of the object file, preceded by a 4-byte language type (ASM=0) */ + kCvSymType_V3_Compliand = 0x1101, + kCvSymType_V3_Thunk, + kCvSymType_V3_Block, + kCvSymType_V3_Unknown_1104, + kCvSymType_V3_Label, /**< RTCVSYMV3LABEL */ + kCvSymType_V3_Register, + kCvSymType_V3_Constant, + kCvSymType_V3_Udt, + kCvSymType_V3_Unknown_1109, + kCvSymType_V3_Unknown_110a, + kCvSymType_V3_BpRel, + kCvSymType_V3_LData, /**< RTCVSYMV3TYPEDNAME */ + kCvSymType_V3_GData, /**< RTCVSYMV3TYPEDNAME */ + kCvSymType_V3_Pub, + kCvSymType_V3_LProc, + kCvSymType_V3_GProc, + kCvSymType_V3_RegRel, + kCvSymType_V3_LThread, + kCvSymType_V3_GThread, + kCvSymType_V3_Unknown_1114, + kCvSymType_V3_Unknown_1115, + kCvSymType_V3_MSTool, /**< RTCVSYMV3MSTOOL */ + + kCvSymType_V3_PubFunc1 = 0x1125, + kCvSymType_V3_PubFunc2 = 0x1127, + kCvSymType_V3_SectInfo = 0x1136, + kCvSymType_V3_SubSectInfo, + kCvSymType_V3_Entrypoint, + kCvSymType_V3_Unknown_1139, + kCvSymType_V3_SecuCookie, + kCvSymType_V3_Unknown_113b, + kCvSymType_V3_MsToolInfo, + kCvSymType_V3_MsToolEnv, + + kCvSymType_VS2013_Local, + kCvSymType_VS2013_FpOff = 0x1144, + kCvSymType_VS2013_LProc32 = 0x1146, + kCvSymType_VS2013_GProc32, + /** @} */ + + kCvSymType_EndOfValues +} RTCVSYMTYPE; +AssertCompile(kCvSymType_V3_Udt == 0x1108); +AssertCompile(kCvSymType_V3_GProc == 0x1110); +AssertCompile(kCvSymType_V3_MSTool == 0x1116); +AssertCompile(kCvSymType_VS2013_Local == 0x113E); +typedef RTCVSYMTYPE *PRTCVSYMTYPE; +typedef RTCVSYMTYPE const *PCRTCVSYMTYPE; + + +/** + * kCvSymType_V3_MSTool format. + */ +typedef struct RTCVSYMV3MSTOOL +{ + /** Language or tool ID (3 == masm). */ + uint32_t uLanguage; + /** Target CPU (0xd0 == AMD64). */ + uint32_t uTargetCpu; + /** Flags. */ + uint32_t fFlags; + /** Version. */ + uint32_t uVersion; + /** The creator name, zero terminated. + * + * It is followed by key/value pairs of zero terminated strings giving more + * details about the current directory ('cwd'), compiler executable ('cl'), + * full command line ('cmd'), source path relative to cwd ('src'), the + * full program database path ('pdb'), and possibly others. Terminated by a + * pair of empty strings, usually. */ + char szCreator[1]; +} RTCVSYMV3MSTOOL; +typedef RTCVSYMV3MSTOOL *PRTCVSYMV3MSTOOL; +typedef RTCVSYMV3MSTOOL const *PCRTCVSYMV3MSTOOL; + +/** + * kCvSymType_V3_Label format. + */ +typedef struct RTCVSYMV3LABEL +{ + /** Offset into iSection of this symbol. */ + uint32_t offSection; + /** The index of the section where the symbol lives. */ + uint16_t iSection; + /** Flags or something. */ + uint8_t fFlags; + /** Zero terminated symbol name (variable length). */ + char szName[1]; +} RTCVSYMV3LABEL; +AssertCompileSize(RTCVSYMV3LABEL, 8); +typedef RTCVSYMV3LABEL *PRTCVSYMV3LABEL; +typedef RTCVSYMV3LABEL const *PCRTCVSYMV3LABEL; + +/** + * kCvSymType_V3_LData and kCvSymType_V3_GData format. + */ +typedef struct RTCVSYMV3TYPEDNAME +{ + /** The type ID. */ + uint32_t idType; + /** Offset into iSection of this symbol. */ + uint32_t offSection; + /** The index of the section where the symbol lives. */ + uint16_t iSection; + /** Zero terminated symbol name (variable length). */ + char szName[2]; +} RTCVSYMV3TYPEDNAME; +AssertCompileSize(RTCVSYMV3TYPEDNAME, 12); +typedef RTCVSYMV3TYPEDNAME *PRTCVSYMV3TYPEDNAME; +typedef RTCVSYMV3TYPEDNAME const *PCRTCVSYMV3TYPEDNAME; + +/** + * kCvSymType_V3_LProc and kCvSymType_V3_GProc format. + */ +typedef struct RTCVSYMV3PROC +{ + /** Lexical scope linking: Parent. */ + uint32_t uParent; + /** Lexical scope linking: End. */ + uint32_t uEnd; + /** Lexical scope linking: Next. */ + uint32_t uNext; + /** The procedure length. */ + uint32_t cbProc; + /** Offset into the procedure where the stack frame has been setup and is an + * excellent position for a function breakpoint. */ + uint32_t offDebugStart; + /** Offset into the procedure where the procedure is ready to return and has a + * return value (if applicable). */ + uint32_t offDebugEnd; + /** The type ID for the procedure. */ + uint32_t idType; + /** Offset into iSection of this procedure. */ + uint32_t offSection; + /** The index of the section where the procedure lives. */ + uint16_t iSection; + /** Flags. */ + uint8_t fFlags; + /** Zero terminated procedure name (variable length). */ + char szName[1]; +} RTCVSYMV3PROC; +AssertCompileSize(RTCVSYMV3PROC, 36); +typedef RTCVSYMV3PROC *PRTCVSYMV3PROC; +typedef RTCVSYMV3PROC const *PCRTCVSYMV3PROC; + + +/** @name $$SYMBOLS signatures. + * @{ */ +/** The $$SYMBOL table signature for CV4. */ +#define RTCVSYMBOLS_SIGNATURE_CV4 UINT32_C(0x00000001) +/** The $$SYMBOL table signature for CV8 (MSVC 8/2005). + * Also seen with MSVC 2010 using -Z7, so maybe more appropriate to call it + * CV7? */ +#define RTCVSYMBOLS_SIGNATURE_CV8 UINT32_C(0x00000004) +/** @} */ + + +/** + * CV8 $$SYMBOLS block header. + */ +typedef struct RTCV8SYMBOLSBLOCK +{ + /** BLock type (RTCV8SYMBLOCK_TYPE_XXX). */ + uint32_t uType; + /** The block length, including this header? */ + uint32_t cb; +} RTCV8SYMBOLSBLOCK; +AssertCompileSize(RTCV8SYMBOLSBLOCK, 8); +typedef RTCV8SYMBOLSBLOCK *PRTCV8SYMBOLSBLOCK; +typedef RTCV8SYMBOLSBLOCK const *PCRTCV8SYMBOLSBLOCK; + +/** @name RTCV8SYMBLOCK_TYPE_XXX - CV8 (MSVC 8/2005) $$SYMBOL table types. + * @{ */ +/** Symbol information. + * Sequence of types. Each type entry starts with a 16-bit length followed + * by a 16-bit RTCVSYMTYPE value. Just like CV4/5, but with C-strings + * instead of pascal. */ +#define RTCV8SYMBLOCK_TYPE_SYMBOLS UINT32_C(0x000000f1) +/** Line numbers for a section. */ +#define RTCV8SYMBLOCK_TYPE_SECT_LINES UINT32_C(0x000000f2) +/** Source file string table. + * The strings are null terminated. Indexed by RTCV8SYMBLOCK_TYPE_SRC_INFO. */ +#define RTCV8SYMBLOCK_TYPE_SRC_STR UINT32_C(0x000000f3) +/** Source file information. */ +#define RTCV8SYMBLOCK_TYPE_SRC_INFO UINT32_C(0x000000f4) +/** @} */ + +/** + * Line number header found in a RTCV8SYMBLOCK_TYPE_SECT_LINES block. + * + * This is followed by a sequence of RTCV8LINESSRCMAP structures. + */ +typedef struct RTCV8LINESHDR +{ + /** Offset into the section. */ + uint32_t offSection; + /** The section number. */ + uint16_t iSection; + /** Padding/zero/maybe-previous-member-is-a-32-bit-value. */ + uint16_t u16Padding; + /** Number of bytes covered by this table, starting at offSection. */ + uint32_t cbSectionCovered; +} RTCV8LINESHDR; +AssertCompileSize(RTCV8LINESHDR, 12); +typedef RTCV8LINESHDR *PRTCV8LINESHDR; +typedef RTCV8LINESHDR const *PCRTCV8LINESHDR; + +/** + * CV8 (MSVC 8/2005) line number source map. + * + * This is followed by an array of RTCV8LINEPAIR. + */ +typedef struct RTCV8LINESSRCMAP +{ + /** The source file, given as an offset (byte) into the source file + * information table (RTCV8SYMBLOCK_TYPE_SRC_INFO). */ + uint32_t offSourceInfo; + /** Number of line numbers following this structure. */ + uint32_t cLines; + /** The size of this source map. */ + uint32_t cb; +} RTCV8LINESSRCMAP; +AssertCompileSize(RTCV8LINESSRCMAP, 12); +typedef RTCV8LINESSRCMAP *PRTCV8LINESSRCMAP; +typedef RTCV8LINESSRCMAP const *PCRTCV8LINESSRCMAP; + +/** + * One line number. + */ +typedef struct RTCV8LINEPAIR +{ + /** Offset into the section of this line number. */ + uint32_t offSection; + /** The line number. */ + uint32_t uLineNumber : 30; + /** Indicates that it's not possible to set breakpoint? */ + uint32_t fEndOfStatement : 1; +} RTCV8LINEPAIR; +AssertCompileSize(RTCV8LINEPAIR, 8); +typedef RTCV8LINEPAIR *PRTCV8LINEPAIR; +typedef RTCV8LINEPAIR const *PCRTCV8LINEPAIR; + +/** + * Source file information found in a RTCV8SYMBLOCK_TYPE_SRC_INFO block. + */ +typedef struct RTCV8SRCINFO +{ + /** The source file name, given as an offset into the string table + * (RTCV8SYMBLOCK_TYPE_SRC_STR). */ + uint32_t offSourceName; + /** Digest/checksum type. */ + uint16_t uDigestType; + union + { + /** RTCV8SRCINFO_DIGEST_TYPE_MD5. */ + struct + { + /** The digest. */ + uint8_t ab[16]; + /** Structur alignment padding. */ + uint8_t abPadding[2]; + } md5; + /** RTCV8SRCINFO_DIGEST_TYPE_NONE: Padding. */ + uint8_t abNone[2]; + } Digest; +} RTCV8SRCINFO; +AssertCompileSize(RTCV8SRCINFO, 24); +typedef RTCV8SRCINFO *PRTCV8SRCINFO; +typedef RTCV8SRCINFO const *PCRTCV8SRCINFO; + +/** @name RTCV8SRCINFO_DIGEST_TYPE_XXX - CV8 source digest types. + * Used by RTCV8SRCINFO::uDigestType. + * @{ */ +#define RTCV8SRCINFO_DIGEST_TYPE_NONE UINT16_C(0x0000) +#define RTCV8SRCINFO_DIGEST_TYPE_MD5 UINT16_C(0x0110) +/** @} */ + + + +/** + * PDB v2.0 in image debug info. + * The URL is constructed from the timestamp and age? + */ +typedef struct CVPDB20INFO +{ + uint32_t u32Magic; /**< CVPDB20INFO_SIGNATURE. */ + int32_t offDbgInfo; /**< Always 0. Used to be the offset to the real debug info. */ + uint32_t uTimestamp; + uint32_t uAge; + uint8_t szPdbFilename[4]; +} CVPDB20INFO; +/** Pointer to in executable image PDB v2.0 info. */ +typedef CVPDB20INFO *PCVPDB20INFO; +/** Pointer to read only in executable image PDB v2.0 info. */ +typedef CVPDB20INFO const *PCCVPDB20INFO; +/** The CVPDB20INFO magic value. */ +#define CVPDB20INFO_MAGIC RT_MAKE_U32_FROM_U8('N','B','1','0') + +/** + * PDB v7.0 in image debug info. + * The URL is constructed from the signature and the age. + */ +#pragma pack(4) +typedef struct CVPDB70INFO +{ + uint32_t u32Magic; /**< CVPDB70INFO_SIGNATURE. */ + RTUUID PdbUuid; + uint32_t uAge; + uint8_t szPdbFilename[4]; +} CVPDB70INFO; +#pragma pack() +AssertCompileMemberOffset(CVPDB70INFO, PdbUuid, 4); +AssertCompileMemberOffset(CVPDB70INFO, uAge, 4 + 16); +/** Pointer to in executable image PDB v7.0 info. */ +typedef CVPDB70INFO *PCVPDB70INFO; +/** Pointer to read only in executable image PDB v7.0 info. */ +typedef CVPDB70INFO const *PCCVPDB70INFO; +/** The CVPDB70INFO magic value. */ +#define CVPDB70INFO_MAGIC RT_MAKE_U32_FROM_U8('R','S','D','S') + + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_codeview_h */ + diff --git a/include/iprt/formats/cpio.h b/include/iprt/formats/cpio.h new file mode 100644 index 00000000..a202a0a6 --- /dev/null +++ b/include/iprt/formats/cpio.h @@ -0,0 +1,210 @@ +/** @file + * IPRT - CPIO archive format. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_cpio_h +#define IPRT_INCLUDED_formats_cpio_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_rt_formats_cpio CPIO Archive format + * @ingroup grp_rt_formats + * + * @{ */ + +/** This denotes the end of the archive (record with this filename, zero size and + * a zero mode). */ +#define CPIO_EOS_FILE_NAME "TRAILER!!!" + + +/** + * The old binary header. + */ +typedef struct CPIOHDRBIN +{ + /** 0x00: Magic identifying the old header. */ + uint16_t u16Magic; + /** 0x02: Device number. */ + uint16_t u16Dev; + /** 0x04: Inode number. */ + uint16_t u16Inode; + /** 0x06: Mode. */ + uint16_t u16Mode; + /** 0x08: User ID. */ + uint16_t u16Uid; + /** 0x0a: Group ID. */ + uint16_t u16Gid; + /** 0x0c: Number of links to this file. */ + uint16_t u16NLinks; + /** 0x0e: Associated device number for block and character device entries. */ + uint16_t u16RDev; + /** 0x10: Modification time stored as two independent 16bit integers. */ + uint16_t au16MTime[2]; + /** 0x14: Number of bytes in the path name (including zero terminator) following the header. */ + uint16_t u16NameSize; + /** 0x16: Size of the file stored as two independent 16bit integers. */ + uint16_t au16FileSize[2]; +} CPIOHDRBIN; +AssertCompileSize(CPIOHDRBIN, 13 * 2); +typedef CPIOHDRBIN *PCPIOHDRBIN; +typedef const CPIOHDRBIN *PCCPIOHDRBIN; + + +/** The magic for the binary header. */ +#define CPIO_HDR_BIN_MAGIC UINT16_C(070707) + + +/** + * Portable ASCII format header as defined by SUSv2. + */ +typedef struct CPIOHDRSUSV2 +{ + /** 0x00: Magic identifying the header. */ + char achMagic[6]; + /** 0x06: Device number. */ + char achDev[6]; + /** 0x0c: Inode number. */ + char achInode[6]; + /** 0x12: Mode. */ + char achMode[6]; + /** 0x18: User ID. */ + char achUid[6]; + /** 0x1e: Group ID. */ + char achGid[6]; + /** 0x24: Number of links to this file. */ + char achNLinks[6]; + /** 0x2a: Associated device number for block and character device entries. */ + char achRDev[6]; + /** 0x30: Modification time stored as two independent 16bit integers. */ + char achMTime[11]; + /** 0x36: Number of bytes in the path name (including zero terminator) following the header. */ + char achNameSize[6]; + /** 0x3c: Size of the file stored as two independent 16bit integers. */ + char achFileSize[11]; +} CPIOHDRSUSV2; +AssertCompileSize(CPIOHDRSUSV2, 9 * 6 + 2 * 11); +typedef CPIOHDRSUSV2 *PCPIOHDRSUSV2; +typedef const CPIOHDRSUSV2 *PCCPIOHDRSUSV2; + + +/** The magic for the SuSv2 CPIO header. */ +#define CPIO_HDR_SUSV2_MAGIC "070707" + + +/** + * New ASCII format header. + */ +typedef struct CPIOHDRNEW +{ + /** 0x00: Magic identifying the header. */ + char achMagic[6]; + /** 0x06: Inode number. */ + char achInode[8]; + /** 0x0e: Mode. */ + char achMode[8]; + /** 0x16: User ID. */ + char achUid[8]; + /** 0x1e: Group ID. */ + char achGid[8]; + /** 0x26: Number of links to this file. */ + char achNLinks[8]; + /** 0x2e: Modification time. */ + char achMTime[8]; + /** 0x36: Size of the file stored as two independent 16bit integers. */ + char achFileSize[8]; + /** 0x3e: Device major number. */ + char achDevMajor[8]; + /** 0x46: Device minor number. */ + char achDevMinor[8]; + /** 0x4e: Assigned device major number for block or character device files. */ + char achRDevMajor[8]; + /** 0x56: Assigned device minor number for block or character device files. */ + char achRDevMinor[8]; + /** 0x5e: Number of bytes in the path name (including zero terminator) following the header. */ + char achNameSize[8]; + /** 0x66: Checksum of the file data if used. */ + char achCheck[8]; +} CPIOHDRNEW; +AssertCompileSize(CPIOHDRNEW, 6 + 13 * 8); +AssertCompileMemberOffset(CPIOHDRNEW, achMagic, 0x00); +AssertCompileMemberOffset(CPIOHDRNEW, achInode, 0x06); +AssertCompileMemberOffset(CPIOHDRNEW, achMode, 0x0e); +AssertCompileMemberOffset(CPIOHDRNEW, achUid, 0x16); +AssertCompileMemberOffset(CPIOHDRNEW, achGid, 0x1e); +AssertCompileMemberOffset(CPIOHDRNEW, achNLinks, 0x26); +AssertCompileMemberOffset(CPIOHDRNEW, achMTime, 0x2e); +AssertCompileMemberOffset(CPIOHDRNEW, achFileSize, 0x36); +AssertCompileMemberOffset(CPIOHDRNEW, achDevMajor, 0x3e); +AssertCompileMemberOffset(CPIOHDRNEW, achDevMinor, 0x46); +AssertCompileMemberOffset(CPIOHDRNEW, achRDevMajor, 0x4e); +AssertCompileMemberOffset(CPIOHDRNEW, achRDevMinor, 0x56); +AssertCompileMemberOffset(CPIOHDRNEW, achNameSize, 0x5e); +AssertCompileMemberOffset(CPIOHDRNEW, achCheck, 0x66); +typedef CPIOHDRNEW *PCPIOHDRNEW; +typedef const CPIOHDRNEW *PCCPIOHDRNEW; + + +/** The magic for the new ASCII CPIO header. */ +#define CPIO_HDR_NEW_MAGIC "070701" +/** The magic for the new ASCII CPIO header + checksum. */ +#define CPIO_HDR_NEW_CHKSUM_MAGIC "070702" + + +/** + * CPIO header union. + */ +typedef union CPIOHDR +{ + /** byte view. */ + uint8_t ab[110]; + /** The ancient binary header. */ + CPIOHDRBIN AncientBin; + /** The SuSv2 ASCII header. */ + CPIOHDRSUSV2 AsciiSuSv2; + /** The new ASCII header format. */ + CPIOHDRNEW AsciiNew; +} CPIOHDR; +typedef CPIOHDR *PCPIOHDR; +typedef const CPIOHDR *PCCPIOHDR; + + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_cpio_h */ + diff --git a/include/iprt/formats/dwarf.h b/include/iprt/formats/dwarf.h new file mode 100644 index 00000000..45a58ad9 --- /dev/null +++ b/include/iprt/formats/dwarf.h @@ -0,0 +1,542 @@ +/** @file + * IPRT - DWARF constants. + * + * @note dwarf.mac is generated from this file by running 'kmk incs' in the root. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_dwarf_h +#define IPRT_INCLUDED_formats_dwarf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/** @name Standard DWARF Line Number Opcodes + * @{ */ +#define DW_LNS_extended UINT8_C(0x00) +#define DW_LNS_copy UINT8_C(0x01) +#define DW_LNS_advance_pc UINT8_C(0x02) +#define DW_LNS_advance_line UINT8_C(0x03) +#define DW_LNS_set_file UINT8_C(0x04) +#define DW_LNS_set_column UINT8_C(0x05) +#define DW_LNS_negate_stmt UINT8_C(0x06) +#define DW_LNS_set_basic_block UINT8_C(0x07) +#define DW_LNS_const_add_pc UINT8_C(0x08) +#define DW_LNS_fixed_advance_pc UINT8_C(0x09) +#define DW_LNS_set_prologue_end UINT8_C(0x0a) +#define DW_LNS_set_epilogue_begin UINT8_C(0x0b) +#define DW_LNS_set_isa UINT8_C(0x0c) +#define DW_LNS_what_question_mark UINT8_C(0x0d) +/** @} */ + + +/** @name Extended DWARF Line Number Opcodes + * @{ */ +#define DW_LNE_end_sequence UINT8_C(1) +#define DW_LNE_set_address UINT8_C(2) +#define DW_LNE_define_file UINT8_C(3) +#define DW_LNE_set_descriminator UINT8_C(4) +/** @} */ + + +/** @name DIE Tags. + * @{ */ +#define DW_TAG_array_type UINT16_C(0x0001) +#define DW_TAG_class_type UINT16_C(0x0002) +#define DW_TAG_entry_point UINT16_C(0x0003) +#define DW_TAG_enumeration_type UINT16_C(0x0004) +#define DW_TAG_formal_parameter UINT16_C(0x0005) +#define DW_TAG_imported_declaration UINT16_C(0x0008) +#define DW_TAG_label UINT16_C(0x000a) +#define DW_TAG_lexical_block UINT16_C(0x000b) +#define DW_TAG_member UINT16_C(0x000d) +#define DW_TAG_pointer_type UINT16_C(0x000f) +#define DW_TAG_reference_type UINT16_C(0x0010) +#define DW_TAG_compile_unit UINT16_C(0x0011) +#define DW_TAG_string_type UINT16_C(0x0012) +#define DW_TAG_structure_type UINT16_C(0x0013) +#define DW_TAG_subroutine_type UINT16_C(0x0015) +#define DW_TAG_typedef UINT16_C(0x0016) +#define DW_TAG_union_type UINT16_C(0x0017) +#define DW_TAG_unspecified_parameters UINT16_C(0x0018) +#define DW_TAG_variant UINT16_C(0x0019) +#define DW_TAG_common_block UINT16_C(0x001a) +#define DW_TAG_common_inclusion UINT16_C(0x001b) +#define DW_TAG_inheritance UINT16_C(0x001c) +#define DW_TAG_inlined_subroutine UINT16_C(0x001d) +#define DW_TAG_module UINT16_C(0x001e) +#define DW_TAG_ptr_to_member_type UINT16_C(0x001f) +#define DW_TAG_set_type UINT16_C(0x0020) +#define DW_TAG_subrange_type UINT16_C(0x0021) +#define DW_TAG_with_stmt UINT16_C(0x0022) +#define DW_TAG_access_declaration UINT16_C(0x0023) +#define DW_TAG_base_type UINT16_C(0x0024) +#define DW_TAG_catch_block UINT16_C(0x0025) +#define DW_TAG_const_type UINT16_C(0x0026) +#define DW_TAG_constant UINT16_C(0x0027) +#define DW_TAG_enumerator UINT16_C(0x0028) +#define DW_TAG_file_type UINT16_C(0x0029) +#define DW_TAG_friend UINT16_C(0x002a) +#define DW_TAG_namelist UINT16_C(0x002b) +#define DW_TAG_namelist_item UINT16_C(0x002c) +#define DW_TAG_packed_type UINT16_C(0x002d) +#define DW_TAG_subprogram UINT16_C(0x002e) +#define DW_TAG_template_type_parameter UINT16_C(0x002f) +#define DW_TAG_template_value_parameter UINT16_C(0x0030) +#define DW_TAG_thrown_type UINT16_C(0x0031) +#define DW_TAG_try_block UINT16_C(0x0032) +#define DW_TAG_variant_part UINT16_C(0x0033) +#define DW_TAG_variable UINT16_C(0x0034) +#define DW_TAG_volatile_type UINT16_C(0x0035) +#define DW_TAG_dwarf_procedure UINT16_C(0x0036) +#define DW_TAG_restrict_type UINT16_C(0x0037) +#define DW_TAG_interface_type UINT16_C(0x0038) +#define DW_TAG_namespace UINT16_C(0x0039) +#define DW_TAG_imported_module UINT16_C(0x003a) +#define DW_TAG_unspecified_type UINT16_C(0x003b) +#define DW_TAG_partial_unit UINT16_C(0x003c) +#define DW_TAG_imported_unit UINT16_C(0x003d) +#define DW_TAG_condition UINT16_C(0x003f) +#define DW_TAG_shared_type UINT16_C(0x0040) +#define DW_TAG_type_unit UINT16_C(0x0041) +#define DW_TAG_rvalue_reference_type UINT16_C(0x0042) +#define DW_TAG_template_alias UINT16_C(0x0043) +#define DW_TAG_lo_user UINT16_C(0x4080) +#define DW_TAG_GNU_call_site UINT16_C(0x4109) +#define DW_TAG_GNU_call_site_parameter UINT16_C(0x410a) +#define DW_TAG_WATCOM_address_class_type UINT16_C(0x4100) /**< Watcom extension. */ +#define DW_TAG_WATCOM_namespace UINT16_C(0x4101) /**< Watcom extension. */ +#define DW_TAG_hi_user UINT16_C(0xffff) +/** @} */ + + +/** @name Has children or not (follows DW_TAG_xxx in .debug_abbrev). + * @{ */ +#define DW_CHILDREN_yes 1 +#define DW_CHILDREN_no 0 +/** @} */ + + +/** @name DIE Attributes. + * @{ */ +#define DW_AT_sibling UINT16_C(0x0001) +#define DW_AT_location UINT16_C(0x0002) +#define DW_AT_name UINT16_C(0x0003) +#define DW_AT_ordering UINT16_C(0x0009) +#define DW_AT_byte_size UINT16_C(0x000b) +#define DW_AT_bit_offset UINT16_C(0x000c) +#define DW_AT_bit_size UINT16_C(0x000d) +#define DW_AT_stmt_list UINT16_C(0x0010) +#define DW_AT_low_pc UINT16_C(0x0011) +#define DW_AT_high_pc UINT16_C(0x0012) +#define DW_AT_language UINT16_C(0x0013) +#define DW_AT_discr UINT16_C(0x0015) +#define DW_AT_discr_value UINT16_C(0x0016) +#define DW_AT_visibility UINT16_C(0x0017) +#define DW_AT_import UINT16_C(0x0018) +#define DW_AT_string_length UINT16_C(0x0019) +#define DW_AT_common_reference UINT16_C(0x001a) +#define DW_AT_comp_dir UINT16_C(0x001b) +#define DW_AT_const_value UINT16_C(0x001c) +#define DW_AT_containing_type UINT16_C(0x001d) +#define DW_AT_default_value UINT16_C(0x001e) +#define DW_AT_inline UINT16_C(0x0020) +#define DW_AT_is_optional UINT16_C(0x0021) +#define DW_AT_lower_bound UINT16_C(0x0022) +#define DW_AT_producer UINT16_C(0x0025) +#define DW_AT_prototyped UINT16_C(0x0027) +#define DW_AT_return_addr UINT16_C(0x002a) +#define DW_AT_start_scope UINT16_C(0x002c) +#define DW_AT_bit_stride UINT16_C(0x002e) +#define DW_AT_upper_bound UINT16_C(0x002f) +#define DW_AT_abstract_origin UINT16_C(0x0031) +#define DW_AT_accessibility UINT16_C(0x0032) +#define DW_AT_address_class UINT16_C(0x0033) +#define DW_AT_artificial UINT16_C(0x0034) +#define DW_AT_base_types UINT16_C(0x0035) +#define DW_AT_calling_convention UINT16_C(0x0036) +#define DW_AT_count UINT16_C(0x0037) +#define DW_AT_data_member_location UINT16_C(0x0038) +#define DW_AT_decl_column UINT16_C(0x0039) +#define DW_AT_decl_file UINT16_C(0x003a) +#define DW_AT_decl_line UINT16_C(0x003b) +#define DW_AT_declaration UINT16_C(0x003c) +#define DW_AT_discr_list UINT16_C(0x003d) +#define DW_AT_encoding UINT16_C(0x003e) +#define DW_AT_external UINT16_C(0x003f) +#define DW_AT_frame_base UINT16_C(0x0040) +#define DW_AT_friend UINT16_C(0x0041) +#define DW_AT_identifier_case UINT16_C(0x0042) +#define DW_AT_macro_info UINT16_C(0x0043) +#define DW_AT_namelist_item UINT16_C(0x0044) +#define DW_AT_priority UINT16_C(0x0045) +#define DW_AT_segment UINT16_C(0x0046) +#define DW_AT_specification UINT16_C(0x0047) +#define DW_AT_static_link UINT16_C(0x0048) +#define DW_AT_type UINT16_C(0x0049) +#define DW_AT_use_location UINT16_C(0x004a) +#define DW_AT_variable_parameter UINT16_C(0x004b) +#define DW_AT_virtuality UINT16_C(0x004c) +#define DW_AT_vtable_elem_location UINT16_C(0x004d) +#define DW_AT_allocated UINT16_C(0x004e) +#define DW_AT_associated UINT16_C(0x004f) +#define DW_AT_data_location UINT16_C(0x0050) +#define DW_AT_byte_stride UINT16_C(0x0051) +#define DW_AT_entry_pc UINT16_C(0x0052) +#define DW_AT_use_UTF8 UINT16_C(0x0053) +#define DW_AT_extension UINT16_C(0x0054) +#define DW_AT_ranges UINT16_C(0x0055) +#define DW_AT_trampoline UINT16_C(0x0056) +#define DW_AT_call_column UINT16_C(0x0057) +#define DW_AT_call_file UINT16_C(0x0058) +#define DW_AT_call_line UINT16_C(0x0059) +#define DW_AT_description UINT16_C(0x005a) +#define DW_AT_binary_scale UINT16_C(0x005b) +#define DW_AT_decimal_scale UINT16_C(0x005c) +#define DW_AT_small UINT16_C(0x005d) +#define DW_AT_decimal_sign UINT16_C(0x005e) +#define DW_AT_digit_count UINT16_C(0x005f) +#define DW_AT_picture_string UINT16_C(0x0060) +#define DW_AT_mutable UINT16_C(0x0061) +#define DW_AT_threads_scaled UINT16_C(0x0062) +#define DW_AT_explicit UINT16_C(0x0063) +#define DW_AT_object_pointer UINT16_C(0x0064) +#define DW_AT_endianity UINT16_C(0x0065) +#define DW_AT_elemental UINT16_C(0x0066) +#define DW_AT_pure UINT16_C(0x0067) +#define DW_AT_recursive UINT16_C(0x0068) +#define DW_AT_signature UINT16_C(0x0069) +#define DW_AT_main_subprogram UINT16_C(0x006a) +#define DW_AT_data_bit_offset UINT16_C(0x006b) +#define DW_AT_const_expr UINT16_C(0x006c) +#define DW_AT_enum_class UINT16_C(0x006d) +#define DW_AT_linkage_name UINT16_C(0x006e) +#define DW_AT_lo_user UINT16_C(0x2000) +/** Used by GCC and others, same as DW_AT_linkage_name. See http://wiki.dwarfstd.org/index.php?title=DW_AT_linkage_name*/ +#define DW_AT_MIPS_linkage_name UINT16_C(0x2007) +#define DW_AT_WATCOM_memory_model UINT16_C(0x2082) /**< Watcom extension. */ +#define DW_AT_WATCOM_references_start UINT16_C(0x2083) /**< Watcom extension. */ +#define DW_AT_WATCOM_parm_entry UINT16_C(0x2084) /**< Watcom extension. */ +#define DW_AT_hi_user UINT16_C(0x3fff) +/** @} */ + +/** @name DIE Forms. + * @{ */ +#define DW_FORM_addr UINT16_C(0x01) +/* 0x02 was FORM_REF in DWARF v1, obsolete now. */ +#define DW_FORM_block2 UINT16_C(0x03) +#define DW_FORM_block4 UINT16_C(0x04) +#define DW_FORM_data2 UINT16_C(0x05) +#define DW_FORM_data4 UINT16_C(0x06) +#define DW_FORM_data8 UINT16_C(0x07) +#define DW_FORM_string UINT16_C(0x08) +#define DW_FORM_block UINT16_C(0x09) +#define DW_FORM_block1 UINT16_C(0x0a) +#define DW_FORM_data1 UINT16_C(0x0b) +#define DW_FORM_flag UINT16_C(0x0c) +#define DW_FORM_sdata UINT16_C(0x0d) +#define DW_FORM_strp UINT16_C(0x0e) +#define DW_FORM_udata UINT16_C(0x0f) +#define DW_FORM_ref_addr UINT16_C(0x10) +#define DW_FORM_ref1 UINT16_C(0x11) +#define DW_FORM_ref2 UINT16_C(0x12) +#define DW_FORM_ref4 UINT16_C(0x13) +#define DW_FORM_ref8 UINT16_C(0x14) +#define DW_FORM_ref_udata UINT16_C(0x15) +#define DW_FORM_indirect UINT16_C(0x16) +#define DW_FORM_sec_offset UINT16_C(0x17) +#define DW_FORM_exprloc UINT16_C(0x18) +#define DW_FORM_flag_present UINT16_C(0x19) +#define DW_FORM_ref_sig8 UINT16_C(0x20) +/** @} */ + +/** @name Address classes. + * @{ */ +#define DW_ADDR_none UINT8_C(0) +#define DW_ADDR_i386_near16 UINT8_C(1) +#define DW_ADDR_i386_far16 UINT8_C(2) +#define DW_ADDR_i386_huge16 UINT8_C(3) +#define DW_ADDR_i386_near32 UINT8_C(4) +#define DW_ADDR_i386_far32 UINT8_C(5) +/** @} */ + + +/** @name Location Expression Opcodes + * @{ */ +#define DW_OP_addr UINT8_C(0x03) /**< 1 operand, a constant address (size target specific). */ +#define DW_OP_deref UINT8_C(0x06) /**< 0 operands. */ +#define DW_OP_const1u UINT8_C(0x08) /**< 1 operand, a 1-byte constant. */ +#define DW_OP_const1s UINT8_C(0x09) /**< 1 operand, a 1-byte constant. */ +#define DW_OP_const2u UINT8_C(0x0a) /**< 1 operand, a 2-byte constant. */ +#define DW_OP_const2s UINT8_C(0x0b) /**< 1 operand, a 2-byte constant. */ +#define DW_OP_const4u UINT8_C(0x0c) /**< 1 operand, a 4-byte constant. */ +#define DW_OP_const4s UINT8_C(0x0d) /**< 1 operand, a 4-byte constant. */ +#define DW_OP_const8u UINT8_C(0x0e) /**< 1 operand, a 8-byte constant. */ +#define DW_OP_const8s UINT8_C(0x0f) /**< 1 operand, a 8-byte constant. */ +#define DW_OP_constu UINT8_C(0x10) /**< 1 operand, a ULEB128 constant. */ +#define DW_OP_consts UINT8_C(0x11) /**< 1 operand, a SLEB128 constant. */ +#define DW_OP_dup UINT8_C(0x12) /**< 0 operands. */ +#define DW_OP_drop UINT8_C(0x13) /**< 0 operands. */ +#define DW_OP_over UINT8_C(0x14) /**< 0 operands. */ +#define DW_OP_pick UINT8_C(0x15) /**< 1 operands, a 1-byte stack index. */ +#define DW_OP_swap UINT8_C(0x16) /**< 0 operands. */ +#define DW_OP_rot UINT8_C(0x17) /**< 0 operands. */ +#define DW_OP_xderef UINT8_C(0x18) /**< 0 operands. */ +#define DW_OP_abs UINT8_C(0x19) /**< 0 operands. */ +#define DW_OP_and UINT8_C(0x1a) /**< 0 operands. */ +#define DW_OP_div UINT8_C(0x1b) /**< 0 operands. */ +#define DW_OP_minus UINT8_C(0x1c) /**< 0 operands. */ +#define DW_OP_mod UINT8_C(0x1d) /**< 0 operands. */ +#define DW_OP_mul UINT8_C(0x1e) /**< 0 operands. */ +#define DW_OP_neg UINT8_C(0x1f) /**< 0 operands. */ +#define DW_OP_not UINT8_C(0x20) /**< 0 operands. */ +#define DW_OP_or UINT8_C(0x21) /**< 0 operands. */ +#define DW_OP_plus UINT8_C(0x22) /**< 0 operands. */ +#define DW_OP_plus_uconst UINT8_C(0x23) /**< 1 operands, a ULEB128 addend. */ +#define DW_OP_shl UINT8_C(0x24) /**< 0 operands. */ +#define DW_OP_shr UINT8_C(0x25) /**< 0 operands. */ +#define DW_OP_shra UINT8_C(0x26) /**< 0 operands. */ +#define DW_OP_xor UINT8_C(0x27) /**< 0 operands. */ +#define DW_OP_skip UINT8_C(0x2f) /**< 1 signed 2-byte constant. */ +#define DW_OP_bra UINT8_C(0x28) /**< 1 signed 2-byte constant. */ +#define DW_OP_eq UINT8_C(0x29) /**< 0 operands. */ +#define DW_OP_ge UINT8_C(0x2a) /**< 0 operands. */ +#define DW_OP_gt UINT8_C(0x2b) /**< 0 operands. */ +#define DW_OP_le UINT8_C(0x2c) /**< 0 operands. */ +#define DW_OP_lt UINT8_C(0x2d) /**< 0 operands. */ +#define DW_OP_ne UINT8_C(0x2e) /**< 0 operands. */ +#define DW_OP_lit0 UINT8_C(0x30) /**< 0 operands - literals 0..31 */ +#define DW_OP_lit31 UINT8_C(0x4f) /**< last litteral. */ +#define DW_OP_reg0 UINT8_C(0x50) /**< 0 operands - reg 0..31. */ +#define DW_OP_reg31 UINT8_C(0x6f) /**< last register. */ +#define DW_OP_breg0 UINT8_C(0x70) /**< 1 operand, a SLEB128 offset. */ +#define DW_OP_breg31 UINT8_C(0x8f) /**< last branch register. */ +#define DW_OP_regx UINT8_C(0x90) /**< 1 operand, a ULEB128 register. */ +#define DW_OP_fbreg UINT8_C(0x91) /**< 1 operand, a SLEB128 offset. */ +#define DW_OP_bregx UINT8_C(0x92) /**< 2 operands, a ULEB128 register followed by a SLEB128 offset. */ +#define DW_OP_piece UINT8_C(0x93) /**< 1 operand, a ULEB128 size of piece addressed. */ +#define DW_OP_deref_size UINT8_C(0x94) /**< 1 operand, a 1-byte size of data retrieved. */ +#define DW_OP_xderef_size UINT8_C(0x95) /**< 1 operand, a 1-byte size of data retrieved. */ +#define DW_OP_nop UINT8_C(0x96) /**< 0 operands. */ +#define DW_OP_lo_user UINT8_C(0xe0) /**< First user opcode */ +#define DW_OP_hi_user UINT8_C(0xff) /**< Last user opcode. */ +/** @} */ + +/** @name Exception Handler Pointer Encodings (GCC/LSB). + * @{ */ +#define DW_EH_PE_FORMAT_MASK UINT8_C(0x0f) /**< Format mask. */ +#define DW_EH_PE_APPL_MASK UINT8_C(0x70) /**< Application mask. */ +#define DW_EH_PE_indirect UINT8_C(0x80) /**< Flag: Indirect pointer. */ +#define DW_EH_PE_omit UINT8_C(0xff) /**< Special value: Omitted. */ +#define DW_EH_PE_ptr UINT8_C(0x00) /**< Format: pointer sized, unsigned. */ +#define DW_EH_PE_uleb128 UINT8_C(0x01) /**< Format: unsigned LEB128. */ +#define DW_EH_PE_udata2 UINT8_C(0x02) /**< Format: unsigned 16-bit. */ +#define DW_EH_PE_udata4 UINT8_C(0x03) /**< Format: unsigned 32-bit. */ +#define DW_EH_PE_udata8 UINT8_C(0x04) /**< Format: unsigned 64-bit. */ +#define DW_EH_PE_sleb128 UINT8_C(0x09) /**< Format: signed LEB128. */ +#define DW_EH_PE_sdata2 UINT8_C(0x0a) /**< Format: signed 16-bit. */ +#define DW_EH_PE_sdata4 UINT8_C(0x0b) /**< Format: signed 32-bit. */ +#define DW_EH_PE_sdata8 UINT8_C(0x0c) /**< Format: signed 64-bit. */ +#define DW_EH_PE_absptr UINT8_C(0x00) /**< Application: Absolute */ +#define DW_EH_PE_pcrel UINT8_C(0x10) /**< Application: PC relative, i.e. relative pointer address. */ +#define DW_EH_PE_textrel UINT8_C(0x20) /**< Application: text section relative. */ +#define DW_EH_PE_datarel UINT8_C(0x30) /**< Application: data section relative. */ +#define DW_EH_PE_funcrel UINT8_C(0x40) /**< Application: relative to start of function. */ +#define DW_EH_PE_aligned UINT8_C(0x50) /**< Application: aligned pointer. */ +/** @} */ + +/** @name Call frame instructions. + * @{ */ +/** Mask to use to identify DW_CFA_advance_loc, DW_CFA_offset and DW_CFA_restore. */ +#define DW_CFA_high_bit_mask UINT8_C(0xc0) + +#define DW_CFA_nop UINT8_C(0x00) /**< No operands. */ + +#define DW_CFA_advance_loc UINT8_C(0x40) /**< low 6 bits: delta to advance. */ +#define DW_CFA_set_loc UINT8_C(0x01) /**< op1: address. */ +#define DW_CFA_advance_loc1 UINT8_C(0x02) /**< op1: 1-byte delta. */ +#define DW_CFA_advance_loc2 UINT8_C(0x03) /**< op1: 2-byte delta. */ +#define DW_CFA_advance_loc4 UINT8_C(0x04) /**< op1: 4-byte delta. */ + +#define DW_CFA_offset UINT8_C(0x80) /**< low 6 bits: register; op1: ULEB128 offset. */ +#define DW_CFA_offset_extended UINT8_C(0x05) /**< op1: ULEB128 register; op2: ULEB128 offset. */ +#define DW_CFA_offset_extended_sf UINT8_C(0x11) /**< op1: ULEB128 register; op2: SLEB128 offset. */ +#define DW_CFA_restore UINT8_C(0xc0) /**< low 6 bits: register. */ +#define DW_CFA_restore_extended UINT8_C(0x06) /**< op1: ULEB128 register. */ +#define DW_CFA_undefined UINT8_C(0x07) /**< op1: ULEB128 register. */ +#define DW_CFA_same_value UINT8_C(0x08) /**< op1: ULEB128 register. */ +#define DW_CFA_register UINT8_C(0x09) /**< op1: ULEB128 destination register; op2: ULEB128 source register. */ +#define DW_CFA_expression UINT8_C(0x10) /**< op1: ULEB128 register; op2: BLOCK. */ + +#define DW_CFA_val_offset UINT8_C(0x14) /**< op1: ULEB128 register; op2: ULEB128. */ +#define DW_CFA_val_offset_sf UINT8_C(0x15) /**< op1: ULEB128 register; op2: SLEB128. */ +#define DW_CFA_val_expression UINT8_C(0x16) /**< op1: ULEB128 register; op2: BLOCK. */ + +#define DW_CFA_remember_state UINT8_C(0x0a) /**< No operands. */ +#define DW_CFA_restore_state UINT8_C(0x0b) /**< No operands. */ + +#define DW_CFA_def_cfa UINT8_C(0x0c) /**< op1: ULEB128 register; op2: ULEB128 offset. */ +#define DW_CFA_def_cfa_register UINT8_C(0x0d) /**< op1: ULEB128 register. */ +#define DW_CFA_def_cfa_offset UINT8_C(0x0e) /**< op1: ULEB128 offset. */ +#define DW_CFA_def_cfa_expression UINT8_C(0x0f) /**< op1: BLOCK. */ +#define DW_CFA_def_cfa_sf UINT8_C(0x12) /**< op1: ULEB128 register; op2: SLEB128 offset. */ +#define DW_CFA_def_cfa_offset_sf UINT8_C(0x13) /**< op1: SLEB128 offset. */ + +#define DW_CFA_lo_user UINT8_C(0x1c) /**< User defined operands. */ +#define DW_CFA_MIPS_advance_loc8 UINT8_C(0x1d) /**< op1: 8-byte delta? */ +#define DW_CFA_GNU_window_save UINT8_C(0x2d) /**< op1: ??; op2: ?? */ +#define DW_CFA_GNU_args_size UINT8_C(0x2e) /**< op1: ??; op2: ?? */ +#define DW_CFA_GNU_negative_offset_extended UINT8_C(0x2f) /**< op1: ??; op2: ?? */ +#define DW_CFA_hi_user UINT8_C(0x3f) /**< User defined operands. */ +/** @} */ + + +/** @name DWREG_X86_XXX - 386+ register number mappings. + * @{ */ +#define DWREG_X86_EAX 0 +#define DWREG_X86_ECX 1 +#define DWREG_X86_EDX 2 +#define DWREG_X86_EBX 3 +#define DWREG_X86_ESP 4 +#define DWREG_X86_EBP 5 +#define DWREG_X86_ESI 6 +#define DWREG_X86_EDI 7 +#define DWREG_X86_RA 8 /* return address (=EIP) */ +#define DWREG_X86_EFLAGS 9 +#define DWREG_X86_ST1 11 +#define DWREG_X86_ST2 12 +#define DWREG_X86_ST3 13 +#define DWREG_X86_ST4 14 +#define DWREG_X86_ST5 15 +#define DWREG_X86_ST6 16 +#define DWREG_X86_ST7 17 +#define DWREG_X86_XMM0 21 +#define DWREG_X86_XMM1 22 +#define DWREG_X86_XMM2 23 +#define DWREG_X86_XMM3 24 +#define DWREG_X86_XMM4 25 +#define DWREG_X86_XMM5 26 +#define DWREG_X86_XMM6 27 +#define DWREG_X86_XMM7 28 +#define DWREG_X86_MM0 29 +#define DWREG_X86_MM1 30 +#define DWREG_X86_MM2 31 +#define DWREG_X86_MM3 32 +#define DWREG_X86_MM4 33 +#define DWREG_X86_MM5 34 +#define DWREG_X86_MM6 35 +#define DWREG_X86_MM7 36 +#define DWREG_X86_MXCSR 39 +#define DWREG_X86_ES 40 +#define DWREG_X86_CS 41 +#define DWREG_X86_SS 42 +#define DWREG_X86_DS 43 +#define DWREG_X86_FS 44 +#define DWREG_X86_GS 45 +#define DWREG_X86_TR 48 +#define DWREG_X86_LDTR 49 +/** @} */ + + +/** @name DWREG_AMD64_XXX - AMD64 register number mappings. + * @note This for some braindead reason the first 8 GPR are in intel encoding + * order, unlike the DWREG_X86_XXX variant. Utter stupidity. + * @{ */ +#define DWREG_AMD64_RAX 0 +#define DWREG_AMD64_RDX 1 +#define DWREG_AMD64_RCX 2 +#define DWREG_AMD64_RBX 3 +#define DWREG_AMD64_RSI 4 +#define DWREG_AMD64_RDI 5 +#define DWREG_AMD64_RBP 6 +#define DWREG_AMD64_RSP 7 +#define DWREG_AMD64_R8 8 +#define DWREG_AMD64_R9 9 +#define DWREG_AMD64_R10 10 +#define DWREG_AMD64_R11 11 +#define DWREG_AMD64_R12 12 +#define DWREG_AMD64_R13 13 +#define DWREG_AMD64_R14 14 +#define DWREG_AMD64_R15 15 +#define DWREG_AMD64_RA 16 /* return address (=RIP) */ +#define DWREG_AMD64_XMM0 17 +#define DWREG_AMD64_XMM1 18 +#define DWREG_AMD64_XMM2 19 +#define DWREG_AMD64_XMM3 20 +#define DWREG_AMD64_XMM4 21 +#define DWREG_AMD64_XMM5 22 +#define DWREG_AMD64_XMM6 23 +#define DWREG_AMD64_XMM7 24 +#define DWREG_AMD64_XMM8 25 +#define DWREG_AMD64_XMM9 26 +#define DWREG_AMD64_XMM10 27 +#define DWREG_AMD64_XMM11 28 +#define DWREG_AMD64_XMM12 29 +#define DWREG_AMD64_XMM13 30 +#define DWREG_AMD64_XMM14 31 +#define DWREG_AMD64_XMM15 32 +#define DWREG_AMD64_ST0 33 +#define DWREG_AMD64_ST1 34 +#define DWREG_AMD64_ST2 35 +#define DWREG_AMD64_ST3 36 +#define DWREG_AMD64_ST4 37 +#define DWREG_AMD64_ST5 38 +#define DWREG_AMD64_ST6 39 +#define DWREG_AMD64_ST7 40 +#define DWREG_AMD64_MM0 41 +#define DWREG_AMD64_MM1 42 +#define DWREG_AMD64_MM2 43 +#define DWREG_AMD64_MM3 44 +#define DWREG_AMD64_MM4 45 +#define DWREG_AMD64_MM5 46 +#define DWREG_AMD64_MM6 47 +#define DWREG_AMD64_MM7 48 +#define DWREG_AMD64_RFLAGS 49 +#define DWREG_AMD64_ES 50 +#define DWREG_AMD64_CS 51 +#define DWREG_AMD64_SS 52 +#define DWREG_AMD64_DS 53 +#define DWREG_AMD64_FS 54 +#define DWREG_AMD64_GS 55 +#define DWREG_AMD64_FS_BASE 58 +#define DWREG_AMD64_GS_BASE 59 +#define DWREG_AMD64_TR 62 +#define DWREG_AMD64_LDTR 63 +#define DWREG_AMD64_MXCSR 64 +#define DWREG_AMD64_FCW 65 +#define DWREG_AMD64_FSW 66 +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_dwarf_h */ + diff --git a/include/iprt/formats/dwarf.mac b/include/iprt/formats/dwarf.mac new file mode 100644 index 00000000..a54b0965 --- /dev/null +++ b/include/iprt/formats/dwarf.mac @@ -0,0 +1,471 @@ +;; @file +; IPRT - DWARF constants. +; +; Automatically generated by various.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef IPRT_INCLUDED_formats_dwarf_h +%define IPRT_INCLUDED_formats_dwarf_h +%ifndef RT_WITHOUT_PRAGMA_ONCE +%endif +%define DW_LNS_extended 0x00 +%define DW_LNS_copy 0x01 +%define DW_LNS_advance_pc 0x02 +%define DW_LNS_advance_line 0x03 +%define DW_LNS_set_file 0x04 +%define DW_LNS_set_column 0x05 +%define DW_LNS_negate_stmt 0x06 +%define DW_LNS_set_basic_block 0x07 +%define DW_LNS_const_add_pc 0x08 +%define DW_LNS_fixed_advance_pc 0x09 +%define DW_LNS_set_prologue_end 0x0a +%define DW_LNS_set_epilogue_begin 0x0b +%define DW_LNS_set_isa 0x0c +%define DW_LNS_what_question_mark 0x0d +%define DW_LNE_end_sequence 1 +%define DW_LNE_set_address 2 +%define DW_LNE_define_file 3 +%define DW_LNE_set_descriminator 4 +%define DW_TAG_array_type 0x0001 +%define DW_TAG_class_type 0x0002 +%define DW_TAG_entry_point 0x0003 +%define DW_TAG_enumeration_type 0x0004 +%define DW_TAG_formal_parameter 0x0005 +%define DW_TAG_imported_declaration 0x0008 +%define DW_TAG_label 0x000a +%define DW_TAG_lexical_block 0x000b +%define DW_TAG_member 0x000d +%define DW_TAG_pointer_type 0x000f +%define DW_TAG_reference_type 0x0010 +%define DW_TAG_compile_unit 0x0011 +%define DW_TAG_string_type 0x0012 +%define DW_TAG_structure_type 0x0013 +%define DW_TAG_subroutine_type 0x0015 +%define DW_TAG_typedef 0x0016 +%define DW_TAG_union_type 0x0017 +%define DW_TAG_unspecified_parameters 0x0018 +%define DW_TAG_variant 0x0019 +%define DW_TAG_common_block 0x001a +%define DW_TAG_common_inclusion 0x001b +%define DW_TAG_inheritance 0x001c +%define DW_TAG_inlined_subroutine 0x001d +%define DW_TAG_module 0x001e +%define DW_TAG_ptr_to_member_type 0x001f +%define DW_TAG_set_type 0x0020 +%define DW_TAG_subrange_type 0x0021 +%define DW_TAG_with_stmt 0x0022 +%define DW_TAG_access_declaration 0x0023 +%define DW_TAG_base_type 0x0024 +%define DW_TAG_catch_block 0x0025 +%define DW_TAG_const_type 0x0026 +%define DW_TAG_constant 0x0027 +%define DW_TAG_enumerator 0x0028 +%define DW_TAG_file_type 0x0029 +%define DW_TAG_friend 0x002a +%define DW_TAG_namelist 0x002b +%define DW_TAG_namelist_item 0x002c +%define DW_TAG_packed_type 0x002d +%define DW_TAG_subprogram 0x002e +%define DW_TAG_template_type_parameter 0x002f +%define DW_TAG_template_value_parameter 0x0030 +%define DW_TAG_thrown_type 0x0031 +%define DW_TAG_try_block 0x0032 +%define DW_TAG_variant_part 0x0033 +%define DW_TAG_variable 0x0034 +%define DW_TAG_volatile_type 0x0035 +%define DW_TAG_dwarf_procedure 0x0036 +%define DW_TAG_restrict_type 0x0037 +%define DW_TAG_interface_type 0x0038 +%define DW_TAG_namespace 0x0039 +%define DW_TAG_imported_module 0x003a +%define DW_TAG_unspecified_type 0x003b +%define DW_TAG_partial_unit 0x003c +%define DW_TAG_imported_unit 0x003d +%define DW_TAG_condition 0x003f +%define DW_TAG_shared_type 0x0040 +%define DW_TAG_type_unit 0x0041 +%define DW_TAG_rvalue_reference_type 0x0042 +%define DW_TAG_template_alias 0x0043 +%define DW_TAG_lo_user 0x4080 +%define DW_TAG_GNU_call_site 0x4109 +%define DW_TAG_GNU_call_site_parameter 0x410a +%define DW_TAG_WATCOM_address_class_type 0x4100 +%define DW_TAG_WATCOM_namespace 0x4101 +%define DW_TAG_hi_user 0xffff +%define DW_CHILDREN_yes 1 +%define DW_CHILDREN_no 0 +%define DW_AT_sibling 0x0001 +%define DW_AT_location 0x0002 +%define DW_AT_name 0x0003 +%define DW_AT_ordering 0x0009 +%define DW_AT_byte_size 0x000b +%define DW_AT_bit_offset 0x000c +%define DW_AT_bit_size 0x000d +%define DW_AT_stmt_list 0x0010 +%define DW_AT_low_pc 0x0011 +%define DW_AT_high_pc 0x0012 +%define DW_AT_language 0x0013 +%define DW_AT_discr 0x0015 +%define DW_AT_discr_value 0x0016 +%define DW_AT_visibility 0x0017 +%define DW_AT_import 0x0018 +%define DW_AT_string_length 0x0019 +%define DW_AT_common_reference 0x001a +%define DW_AT_comp_dir 0x001b +%define DW_AT_const_value 0x001c +%define DW_AT_containing_type 0x001d +%define DW_AT_default_value 0x001e +%define DW_AT_inline 0x0020 +%define DW_AT_is_optional 0x0021 +%define DW_AT_lower_bound 0x0022 +%define DW_AT_producer 0x0025 +%define DW_AT_prototyped 0x0027 +%define DW_AT_return_addr 0x002a +%define DW_AT_start_scope 0x002c +%define DW_AT_bit_stride 0x002e +%define DW_AT_upper_bound 0x002f +%define DW_AT_abstract_origin 0x0031 +%define DW_AT_accessibility 0x0032 +%define DW_AT_address_class 0x0033 +%define DW_AT_artificial 0x0034 +%define DW_AT_base_types 0x0035 +%define DW_AT_calling_convention 0x0036 +%define DW_AT_count 0x0037 +%define DW_AT_data_member_location 0x0038 +%define DW_AT_decl_column 0x0039 +%define DW_AT_decl_file 0x003a +%define DW_AT_decl_line 0x003b +%define DW_AT_declaration 0x003c +%define DW_AT_discr_list 0x003d +%define DW_AT_encoding 0x003e +%define DW_AT_external 0x003f +%define DW_AT_frame_base 0x0040 +%define DW_AT_friend 0x0041 +%define DW_AT_identifier_case 0x0042 +%define DW_AT_macro_info 0x0043 +%define DW_AT_namelist_item 0x0044 +%define DW_AT_priority 0x0045 +%define DW_AT_segment 0x0046 +%define DW_AT_specification 0x0047 +%define DW_AT_static_link 0x0048 +%define DW_AT_type 0x0049 +%define DW_AT_use_location 0x004a +%define DW_AT_variable_parameter 0x004b +%define DW_AT_virtuality 0x004c +%define DW_AT_vtable_elem_location 0x004d +%define DW_AT_allocated 0x004e +%define DW_AT_associated 0x004f +%define DW_AT_data_location 0x0050 +%define DW_AT_byte_stride 0x0051 +%define DW_AT_entry_pc 0x0052 +%define DW_AT_use_UTF8 0x0053 +%define DW_AT_extension 0x0054 +%define DW_AT_ranges 0x0055 +%define DW_AT_trampoline 0x0056 +%define DW_AT_call_column 0x0057 +%define DW_AT_call_file 0x0058 +%define DW_AT_call_line 0x0059 +%define DW_AT_description 0x005a +%define DW_AT_binary_scale 0x005b +%define DW_AT_decimal_scale 0x005c +%define DW_AT_small 0x005d +%define DW_AT_decimal_sign 0x005e +%define DW_AT_digit_count 0x005f +%define DW_AT_picture_string 0x0060 +%define DW_AT_mutable 0x0061 +%define DW_AT_threads_scaled 0x0062 +%define DW_AT_explicit 0x0063 +%define DW_AT_object_pointer 0x0064 +%define DW_AT_endianity 0x0065 +%define DW_AT_elemental 0x0066 +%define DW_AT_pure 0x0067 +%define DW_AT_recursive 0x0068 +%define DW_AT_signature 0x0069 +%define DW_AT_main_subprogram 0x006a +%define DW_AT_data_bit_offset 0x006b +%define DW_AT_const_expr 0x006c +%define DW_AT_enum_class 0x006d +%define DW_AT_linkage_name 0x006e +%define DW_AT_lo_user 0x2000 +%define DW_AT_MIPS_linkage_name 0x2007 +%define DW_AT_WATCOM_memory_model 0x2082 +%define DW_AT_WATCOM_references_start 0x2083 +%define DW_AT_WATCOM_parm_entry 0x2084 +%define DW_AT_hi_user 0x3fff +%define DW_FORM_addr 0x01 +%define DW_FORM_block2 0x03 +%define DW_FORM_block4 0x04 +%define DW_FORM_data2 0x05 +%define DW_FORM_data4 0x06 +%define DW_FORM_data8 0x07 +%define DW_FORM_string 0x08 +%define DW_FORM_block 0x09 +%define DW_FORM_block1 0x0a +%define DW_FORM_data1 0x0b +%define DW_FORM_flag 0x0c +%define DW_FORM_sdata 0x0d +%define DW_FORM_strp 0x0e +%define DW_FORM_udata 0x0f +%define DW_FORM_ref_addr 0x10 +%define DW_FORM_ref1 0x11 +%define DW_FORM_ref2 0x12 +%define DW_FORM_ref4 0x13 +%define DW_FORM_ref8 0x14 +%define DW_FORM_ref_udata 0x15 +%define DW_FORM_indirect 0x16 +%define DW_FORM_sec_offset 0x17 +%define DW_FORM_exprloc 0x18 +%define DW_FORM_flag_present 0x19 +%define DW_FORM_ref_sig8 0x20 +%define DW_ADDR_none 0 +%define DW_ADDR_i386_near16 1 +%define DW_ADDR_i386_far16 2 +%define DW_ADDR_i386_huge16 3 +%define DW_ADDR_i386_near32 4 +%define DW_ADDR_i386_far32 5 +%define DW_OP_addr 0x03 +%define DW_OP_deref 0x06 +%define DW_OP_const1u 0x08 +%define DW_OP_const1s 0x09 +%define DW_OP_const2u 0x0a +%define DW_OP_const2s 0x0b +%define DW_OP_const4u 0x0c +%define DW_OP_const4s 0x0d +%define DW_OP_const8u 0x0e +%define DW_OP_const8s 0x0f +%define DW_OP_constu 0x10 +%define DW_OP_consts 0x11 +%define DW_OP_dup 0x12 +%define DW_OP_drop 0x13 +%define DW_OP_over 0x14 +%define DW_OP_pick 0x15 +%define DW_OP_swap 0x16 +%define DW_OP_rot 0x17 +%define DW_OP_xderef 0x18 +%define DW_OP_abs 0x19 +%define DW_OP_and 0x1a +%define DW_OP_div 0x1b +%define DW_OP_minus 0x1c +%define DW_OP_mod 0x1d +%define DW_OP_mul 0x1e +%define DW_OP_neg 0x1f +%define DW_OP_not 0x20 +%define DW_OP_or 0x21 +%define DW_OP_plus 0x22 +%define DW_OP_plus_uconst 0x23 +%define DW_OP_shl 0x24 +%define DW_OP_shr 0x25 +%define DW_OP_shra 0x26 +%define DW_OP_xor 0x27 +%define DW_OP_skip 0x2f +%define DW_OP_bra 0x28 +%define DW_OP_eq 0x29 +%define DW_OP_ge 0x2a +%define DW_OP_gt 0x2b +%define DW_OP_le 0x2c +%define DW_OP_lt 0x2d +%define DW_OP_ne 0x2e +%define DW_OP_lit0 0x30 +%define DW_OP_lit31 0x4f +%define DW_OP_reg0 0x50 +%define DW_OP_reg31 0x6f +%define DW_OP_breg0 0x70 +%define DW_OP_breg31 0x8f +%define DW_OP_regx 0x90 +%define DW_OP_fbreg 0x91 +%define DW_OP_bregx 0x92 +%define DW_OP_piece 0x93 +%define DW_OP_deref_size 0x94 +%define DW_OP_xderef_size 0x95 +%define DW_OP_nop 0x96 +%define DW_OP_lo_user 0xe0 +%define DW_OP_hi_user 0xff +%define DW_EH_PE_FORMAT_MASK 0x0f +%define DW_EH_PE_APPL_MASK 0x70 +%define DW_EH_PE_indirect 0x80 +%define DW_EH_PE_omit 0xff +%define DW_EH_PE_ptr 0x00 +%define DW_EH_PE_uleb128 0x01 +%define DW_EH_PE_udata2 0x02 +%define DW_EH_PE_udata4 0x03 +%define DW_EH_PE_udata8 0x04 +%define DW_EH_PE_sleb128 0x09 +%define DW_EH_PE_sdata2 0x0a +%define DW_EH_PE_sdata4 0x0b +%define DW_EH_PE_sdata8 0x0c +%define DW_EH_PE_absptr 0x00 +%define DW_EH_PE_pcrel 0x10 +%define DW_EH_PE_textrel 0x20 +%define DW_EH_PE_datarel 0x30 +%define DW_EH_PE_funcrel 0x40 +%define DW_EH_PE_aligned 0x50 +%define DW_CFA_high_bit_mask 0xc0 +%define DW_CFA_nop 0x00 +%define DW_CFA_advance_loc 0x40 +%define DW_CFA_set_loc 0x01 +%define DW_CFA_advance_loc1 0x02 +%define DW_CFA_advance_loc2 0x03 +%define DW_CFA_advance_loc4 0x04 +%define DW_CFA_offset 0x80 +%define DW_CFA_offset_extended 0x05 +%define DW_CFA_offset_extended_sf 0x11 +%define DW_CFA_restore 0xc0 +%define DW_CFA_restore_extended 0x06 +%define DW_CFA_undefined 0x07 +%define DW_CFA_same_value 0x08 +%define DW_CFA_register 0x09 +%define DW_CFA_expression 0x10 +%define DW_CFA_val_offset 0x14 +%define DW_CFA_val_offset_sf 0x15 +%define DW_CFA_val_expression 0x16 +%define DW_CFA_remember_state 0x0a +%define DW_CFA_restore_state 0x0b +%define DW_CFA_def_cfa 0x0c +%define DW_CFA_def_cfa_register 0x0d +%define DW_CFA_def_cfa_offset 0x0e +%define DW_CFA_def_cfa_expression 0x0f +%define DW_CFA_def_cfa_sf 0x12 +%define DW_CFA_def_cfa_offset_sf 0x13 +%define DW_CFA_lo_user 0x1c +%define DW_CFA_MIPS_advance_loc8 0x1d +%define DW_CFA_GNU_window_save 0x2d +%define DW_CFA_GNU_args_size 0x2e +%define DW_CFA_GNU_negative_offset_extended 0x2f +%define DW_CFA_hi_user 0x3f +%define DWREG_X86_EAX 0 +%define DWREG_X86_ECX 1 +%define DWREG_X86_EDX 2 +%define DWREG_X86_EBX 3 +%define DWREG_X86_ESP 4 +%define DWREG_X86_EBP 5 +%define DWREG_X86_ESI 6 +%define DWREG_X86_EDI 7 +%define DWREG_X86_RA 8 +%define DWREG_X86_EFLAGS 9 +%define DWREG_X86_ST1 11 +%define DWREG_X86_ST2 12 +%define DWREG_X86_ST3 13 +%define DWREG_X86_ST4 14 +%define DWREG_X86_ST5 15 +%define DWREG_X86_ST6 16 +%define DWREG_X86_ST7 17 +%define DWREG_X86_XMM0 21 +%define DWREG_X86_XMM1 22 +%define DWREG_X86_XMM2 23 +%define DWREG_X86_XMM3 24 +%define DWREG_X86_XMM4 25 +%define DWREG_X86_XMM5 26 +%define DWREG_X86_XMM6 27 +%define DWREG_X86_XMM7 28 +%define DWREG_X86_MM0 29 +%define DWREG_X86_MM1 30 +%define DWREG_X86_MM2 31 +%define DWREG_X86_MM3 32 +%define DWREG_X86_MM4 33 +%define DWREG_X86_MM5 34 +%define DWREG_X86_MM6 35 +%define DWREG_X86_MM7 36 +%define DWREG_X86_MXCSR 39 +%define DWREG_X86_ES 40 +%define DWREG_X86_CS 41 +%define DWREG_X86_SS 42 +%define DWREG_X86_DS 43 +%define DWREG_X86_FS 44 +%define DWREG_X86_GS 45 +%define DWREG_X86_TR 48 +%define DWREG_X86_LDTR 49 +%define DWREG_AMD64_RAX 0 +%define DWREG_AMD64_RDX 1 +%define DWREG_AMD64_RCX 2 +%define DWREG_AMD64_RBX 3 +%define DWREG_AMD64_RSI 4 +%define DWREG_AMD64_RDI 5 +%define DWREG_AMD64_RBP 6 +%define DWREG_AMD64_RSP 7 +%define DWREG_AMD64_R8 8 +%define DWREG_AMD64_R9 9 +%define DWREG_AMD64_R10 10 +%define DWREG_AMD64_R11 11 +%define DWREG_AMD64_R12 12 +%define DWREG_AMD64_R13 13 +%define DWREG_AMD64_R14 14 +%define DWREG_AMD64_R15 15 +%define DWREG_AMD64_RA 16 +%define DWREG_AMD64_XMM0 17 +%define DWREG_AMD64_XMM1 18 +%define DWREG_AMD64_XMM2 19 +%define DWREG_AMD64_XMM3 20 +%define DWREG_AMD64_XMM4 21 +%define DWREG_AMD64_XMM5 22 +%define DWREG_AMD64_XMM6 23 +%define DWREG_AMD64_XMM7 24 +%define DWREG_AMD64_XMM8 25 +%define DWREG_AMD64_XMM9 26 +%define DWREG_AMD64_XMM10 27 +%define DWREG_AMD64_XMM11 28 +%define DWREG_AMD64_XMM12 29 +%define DWREG_AMD64_XMM13 30 +%define DWREG_AMD64_XMM14 31 +%define DWREG_AMD64_XMM15 32 +%define DWREG_AMD64_ST0 33 +%define DWREG_AMD64_ST1 34 +%define DWREG_AMD64_ST2 35 +%define DWREG_AMD64_ST3 36 +%define DWREG_AMD64_ST4 37 +%define DWREG_AMD64_ST5 38 +%define DWREG_AMD64_ST6 39 +%define DWREG_AMD64_ST7 40 +%define DWREG_AMD64_MM0 41 +%define DWREG_AMD64_MM1 42 +%define DWREG_AMD64_MM2 43 +%define DWREG_AMD64_MM3 44 +%define DWREG_AMD64_MM4 45 +%define DWREG_AMD64_MM5 46 +%define DWREG_AMD64_MM6 47 +%define DWREG_AMD64_MM7 48 +%define DWREG_AMD64_RFLAGS 49 +%define DWREG_AMD64_ES 50 +%define DWREG_AMD64_CS 51 +%define DWREG_AMD64_SS 52 +%define DWREG_AMD64_DS 53 +%define DWREG_AMD64_FS 54 +%define DWREG_AMD64_GS 55 +%define DWREG_AMD64_FS_BASE 58 +%define DWREG_AMD64_GS_BASE 59 +%define DWREG_AMD64_TR 62 +%define DWREG_AMD64_LDTR 63 +%define DWREG_AMD64_MXCSR 64 +%define DWREG_AMD64_FCW 65 +%define DWREG_AMD64_FSW 66 +%endif diff --git a/include/iprt/formats/efi-common.h b/include/iprt/formats/efi-common.h new file mode 100644 index 00000000..eb41ac89 --- /dev/null +++ b/include/iprt/formats/efi-common.h @@ -0,0 +1,102 @@ +/* $Id: efi-common.h $ */ +/** @file + * IPRT, EFI common definitions. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_efi_common_h +#define IPRT_INCLUDED_formats_efi_common_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + +/** + * EFI GUID. + */ +typedef struct EFI_GUID +{ + uint32_t u32Data1; + uint16_t u16Data2; + uint16_t u16Data3; + uint8_t abData4[8]; +} EFI_GUID; +AssertCompileSize(EFI_GUID, 16); +/** Pointer to an EFI GUID. */ +typedef EFI_GUID *PEFI_GUID; +/** Pointer to a const EFI GUID. */ +typedef const EFI_GUID *PCEFI_GUID; + + +/** A Null GUID. */ +#define EFI_NULL_GUID { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 }} +/** Global variable GUID. */ +#define EFI_GLOBAL_VARIABLE_GUID \ + { 0x8be4df61, 0x93ca, 0x11d2, { 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c }} +/** SecureBootEnable variable GUID. */ +#define EFI_SECURE_BOOT_ENABLE_DISABLE_GUID \ + { 0xf0a30bc7, 0xaf08, 0x4556, { 0x99, 0xc4, 0x0, 0x10, 0x9, 0xc9, 0x3a, 0x44 } } + + +/** + * EFI time value. + */ +typedef struct EFI_TIME +{ + uint16_t u16Year; + uint8_t u8Month; + uint8_t u8Day; + uint8_t u8Hour; + uint8_t u8Minute; + uint8_t u8Second; + uint8_t bPad0; + uint32_t u32Nanosecond; + int16_t iTimezone; + uint8_t u8Daylight; + uint8_t bPad1; +} EFI_TIME; +AssertCompileSize(EFI_TIME, 16); +/** Pointer to an EFI time abstraction. */ +typedef EFI_TIME *PEFI_TIME; +/** Pointer to a const EFI time abstraction. */ +typedef const EFI_TIME *PCEFI_TIME; + +#define EFI_TIME_TIMEZONE_UNSPECIFIED INT16_C(0x07ff) + +#define EFI_TIME_DAYLIGHT_ADJUST RT_BIT(0) +#define EFI_TIME_DAYLIGHT_INDST RT_BIT(1) + +#endif /* !IPRT_INCLUDED_formats_efi_common_h */ + diff --git a/include/iprt/formats/efi-fat.h b/include/iprt/formats/efi-fat.h new file mode 100644 index 00000000..975fe317 --- /dev/null +++ b/include/iprt/formats/efi-fat.h @@ -0,0 +1,92 @@ +/* $Id: efi-fat.h $ */ +/** @file + * IPRT, EFI FAT Binary (used by Apple, contains multiple architectures). + */ + +/* + * Copyright (C) 2019-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_efi_fat_h +#define IPRT_INCLUDED_formats_efi_fat_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + +/* + * Definitions come from http://refit.sourceforge.net/info/fat_binary.html + */ + +/** + * The header structure. + */ +typedef struct EFI_FATHDR +{ + /** The magic identifying the header .*/ + uint32_t u32Magic; + /** Number of files (one per architecture) embedded into the file. */ + uint32_t cFilesEmbedded; +} EFI_FATHDR; +AssertCompileSize(EFI_FATHDR, 8); +typedef EFI_FATHDR *PEFI_FATHDR; + +/** The magic identifying a FAT header. */ +#define EFI_FATHDR_MAGIC UINT32_C(0x0ef1fab9) + +/** + * The direcory entry. + */ +typedef struct EFI_FATDIRENTRY +{ + /** The CPU type the referenced file is for. */ + uint32_t u32CpuType; + /** The CPU sub-type the referenced file is for. */ + uint32_t u32CpuSubType; + /** Offset in bytes where the file is located. */ + uint32_t u32OffsetStart; + /** Length of the file in bytes. */ + uint32_t cbFile; + /** Alignment used for the file. */ + uint32_t u32Alignment; +} EFI_FATDIRENTRY; +AssertCompileSize(EFI_FATDIRENTRY, 20); +typedef EFI_FATDIRENTRY *PEFI_FATDIRENTRY; + +#define EFI_FATDIRENTRY_CPU_TYPE_X86 UINT32_C(0x7) +#define EFI_FATDIRENTRY_CPU_TYPE_AMD64 UINT32_C(0x01000007) + +#define EFI_FATDIRENTRY_CPU_SUB_TYPE_GENERIC UINT32_C(0x3) + + +#endif /* !IPRT_INCLUDED_formats_efi_fat_h */ + diff --git a/include/iprt/formats/efi-fv.h b/include/iprt/formats/efi-fv.h new file mode 100644 index 00000000..aa68189d --- /dev/null +++ b/include/iprt/formats/efi-fv.h @@ -0,0 +1,131 @@ +/* $Id: efi-fv.h $ */ +/** @file + * IPRT, EFI firmware volume (FV) definitions. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_efi_fv_h +#define IPRT_INCLUDED_formats_efi_fv_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> +#include <iprt/formats/efi-common.h> + + +/* + * Definitions come from the UEFI PI Spec 1.5 Volume 3 Firmware, chapter 3 "Firmware Storage Code Definitions" + */ + +/** + * The volume header. + */ +typedef struct EFI_FIRMWARE_VOLUME_HEADER +{ + /** Reserved data for the reset vector. */ + uint8_t abZeroVec[16]; + /** The filesystem GUID. */ + EFI_GUID GuidFilesystem; + /** The firmware volume length in bytes including this header. */ + uint64_t cbFv; + /** The signature of the firmware volume header (set to _FVH). */ + uint32_t u32Signature; + /** Firmware volume attributes. */ + uint32_t fAttr; + /** Size of the header in bytes. */ + uint16_t cbFvHdr; + /** Checksum of the header. */ + uint16_t u16Chksum; + /** Offset of the extended header (0 for no extended header). */ + uint16_t offExtHdr; + /** Reserved MBZ. */ + uint8_t bRsvd; + /** Revision of the header. */ + uint8_t bRevision; +} EFI_FIRMWARE_VOLUME_HEADER; +AssertCompileSize(EFI_FIRMWARE_VOLUME_HEADER, 56); +/** Pointer to a EFI firmware volume header. */ +typedef EFI_FIRMWARE_VOLUME_HEADER *PEFI_FIRMWARE_VOLUME_HEADER; +/** Pointer to a const EFI firmware volume header. */ +typedef const EFI_FIRMWARE_VOLUME_HEADER *PCEFI_FIRMWARE_VOLUME_HEADER; + +/** The signature for a firmware volume header. */ +#define EFI_FIRMWARE_VOLUME_HEADER_SIGNATURE RT_MAKE_U32_FROM_U8('_', 'F', 'V', 'H') +/** Revision of the firmware volume header. */ +#define EFI_FIRMWARE_VOLUME_HEADER_REVISION 2 + + +/** + * Firmware block map entry. + */ +typedef struct EFI_FW_BLOCK_MAP +{ + /** Number of blocks for this entry. */ + uint32_t cBlocks; + /** Block size in bytes. */ + uint32_t cbBlock; +} EFI_FW_BLOCK_MAP; +AssertCompileSize(EFI_FW_BLOCK_MAP, 8); +/** Pointer to a firmware volume block map entry. */ +typedef EFI_FW_BLOCK_MAP *PEFI_FW_BLOCK_MAP; +/** Pointer to a const firmware volume block map entry. */ +typedef const EFI_FW_BLOCK_MAP *PCEFI_FW_BLOCK_MAP; + + +/** + * Fault tolerant working block header. + */ +typedef struct EFI_FTW_BLOCK_HEADER +{ + /** GUID identifying the FTW block header. */ + EFI_GUID GuidSignature; + /** The checksum. */ + uint32_t u32Chksum; + /** Flags marking the working block area as valid/invalid. */ + uint32_t fWorkingBlockValid; + /** Size of the write queue. */ + uint64_t cbWriteQueue; +} EFI_FTW_BLOCK_HEADER; +/** Pointer to a fault tolerant working block header. */ +typedef EFI_FTW_BLOCK_HEADER *PEFI_FTW_BLOCK_HEADER; +/** Pointer to a const fault tolerant working block header. */ +typedef const EFI_FTW_BLOCK_HEADER *PCEFI_FTW_BLOCK_HEADER; + +/** The signature for the working block header. */ +#define EFI_WORKING_BLOCK_SIGNATURE_GUID \ + { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95 }} + +#endif /* !IPRT_INCLUDED_formats_efi_fv_h */ + diff --git a/include/iprt/formats/efi-signature.h b/include/iprt/formats/efi-signature.h new file mode 100644 index 00000000..73b4e524 --- /dev/null +++ b/include/iprt/formats/efi-signature.h @@ -0,0 +1,138 @@ +/* $Id: efi-signature.h $ */ +/** @file + * IPRT, EFI signature database definitions. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_efi_signature_h +#define IPRT_INCLUDED_formats_efi_signature_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> +#include <iprt/formats/efi-common.h> + + +/* + * Definitions come from the UEFI 2.6 specification, chapter 30.4.1 + */ + +/** The GUID used for setting and retrieving variables from the variable store. */ +#define EFI_IMAGE_SECURITY_DATABASE_GUID \ + { 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f }} + + +/** + * Signature entry data. + */ +typedef struct EFI_SIGNATURE_DATA +{ + /** The GUID of the owner of the signature. */ + EFI_GUID GuidOwner; + /** The signature data follows (size varies depending on the signature type). */ +} EFI_SIGNATURE_DATA; +AssertCompileSize(EFI_SIGNATURE_DATA, 16); +/** Pointer to a signature entry. */ +typedef EFI_SIGNATURE_DATA *PEFI_SIGNATURE_DATA; +/** Pointer to a const signature entry. */ +typedef const EFI_SIGNATURE_DATA *PCEFI_SIGNATURE_DATA; + +/** Microsoft's GUID for signatures. */ +#define EFI_SIGNATURE_OWNER_GUID_MICROSOFT \ + { 0x77fa9abd, 0x0359, 0x4d32, { 0xbd, 0x60, 0x28, 0xf4, 0xe7, 0x8f, 0x78, 0x4b }} + +/** VirtualBox's GUID for signatures. */ +#define EFI_SIGNATURE_OWNER_GUID_VBOX \ + { 0x9400896a, 0x146c, 0x4f4c, { 0x96, 0x47, 0x2c, 0x73, 0x62, 0x0c, 0xa8, 0x94 }} + + +/** + * Signature list header. + */ +typedef struct EFI_SIGNATURE_LIST +{ + /** The signature type stored in this list. */ + EFI_GUID GuidSigType; + /** Size of the signature list in bytes. */ + uint32_t cbSigLst; + /** Size of the optional signature header following this header in bytes. */ + uint32_t cbSigHdr; + /** Size of each signature entry in bytes, must be at least the size of EFI_SIGNATURE_DATA. */ + uint32_t cbSig; + // uint8_t abSigHdr[]; + // EFI_SIGNATURE_DATA aSigs[]; +} EFI_SIGNATURE_LIST; +AssertCompileSize(EFI_SIGNATURE_LIST, 28); +/** Pointer to a signature list header. */ +typedef EFI_SIGNATURE_LIST *PEFI_SIGNATURE_LIST; +/** Pointer to a const signature list header. */ +typedef const EFI_SIGNATURE_LIST *PCEFI_SIGNATURE_LIST; + +/** Signature contains a SHA256 hash. */ +#define EFI_SIGNATURE_TYPE_GUID_SHA256 \ + { 0xc1c41626, 0x504c, 0x4092, { 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 }} +/** Size of a SHA256 signature entry (GUID + 32 bytes for the hash). */ +#define EFI_SIGNATURE_TYPE_SZ_SHA256 UINT32_C(48) + +/** Signature contains a RSA2048 key. */ +#define EFI_SIGNATURE_TYPE_GUID_RSA2048 \ + { 0x3c5766e8, 0x269c, 0x4e34, { 0xaa, 0x14, 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6 }} +/** Size of a RSA2048 signature entry (GUID + 256 for the key). */ +#define EFI_SIGNATURE_TYPE_SZ_RSA2048 UINT32_C(272) + +/** Signature contains a RSA2048 signature of a SHA256 hash. */ +#define EFI_SIGNATURE_TYPE_GUID_RSA2048_SHA256 \ + { 0xe2b36190, 0x879b, 0x4a3d, { 0xad, 0x8d, 0xf2, 0xe7, 0xbb, 0xa3, 0x27, 0x84 }} +/** Size of a RSA2048 signature entry (GUID + 256 for the key). */ +#define EFI_SIGNATURE_TYPE_SZ_RSA2048_SHA256 UINT32_C(272) + +/** Signature contains a SHA1 hash. */ +#define EFI_SIGNATURE_TYPE_GUID_SHA1 \ + { 0x826ca512, 0xcf10, 0x4ac9, { 0xb1, 0x87, 0xbe, 0x01, 0x49, 0x66, 0x31, 0xbd }} +/** Size of a SHA1 signature entry (GUID + 20 bytes for the hash). */ +#define EFI_SIGNATURE_TYPE_SZ_SHA1 UINT32_C(36) + +/** Signature contains a RSA2048 signature of a SHA1 hash. */ +#define EFI_SIGNATURE_TYPE_GUID_RSA2048_SHA1 \ + { 0x67f8444f, 0x8743, 0x48f1, { 0xa3, 0x28, 0x1e, 0xaa, 0xb8, 0x73, 0x60, 0x80 }} +/** Size of a RSA2048 signature entry (GUID + 256 for the key). */ +#define EFI_SIGNATURE_TYPE_SZ_RSA2048_SHA1 UINT32_C(272) + +/** Signature contains a DER encoded X.509 certificate (size varies with each certificate). */ +#define EFI_SIGNATURE_TYPE_GUID_X509 \ + { 0xa5c059a1, 0x94e4, 0x4aa7, { 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 }} + +#endif /* !IPRT_INCLUDED_formats_efi_signature_h */ + diff --git a/include/iprt/formats/efi-varstore.h b/include/iprt/formats/efi-varstore.h new file mode 100644 index 00000000..9846ef5f --- /dev/null +++ b/include/iprt/formats/efi-varstore.h @@ -0,0 +1,160 @@ +/* $Id: efi-varstore.h $ */ +/** @file + * IPRT, EFI variable store (VarStore) definitions. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_efi_varstore_h +#define IPRT_INCLUDED_formats_efi_varstore_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> +#include <iprt/formats/efi-common.h> + + +/* + * Definitions come from the EDK2 sources MdeModulePkg/Include/Guid/VariableFormat.h + */ + +/** The filesystem GUID for a variable store stored in a volume header. */ +#define EFI_VARSTORE_FILESYSTEM_GUID \ + { 0xfff12b8d, 0x7696, 0x4c8b, { 0xa9, 0x85, 0x27, 0x47, 0x07, 0x5b, 0x4f, 0x50 }} + + +/** + * The variable store header. + */ +typedef struct EFI_VARSTORE_HEADER +{ + /** The GUID identifying a variable store. */ + EFI_GUID GuidVarStore; + /** Size of the variable store including the header. */ + uint32_t cbVarStore; + /** The format state. */ + uint8_t bFmt; + /** The region health state. */ + uint8_t bState; + /** Reserved. */ + uint8_t abRsvd[6]; +} EFI_VARSTORE_HEADER; +AssertCompileSize(EFI_VARSTORE_HEADER, 28); +/** Pointer to a variable store header. */ +typedef EFI_VARSTORE_HEADER *PEFI_VARSTORE_HEADER; +/** Pointer to a const variable store header. */ +typedef const EFI_VARSTORE_HEADER *PCEFI_VARSTORE_HEADER; + +/** The GUID for a variable store using the authenticated variable header format. */ +#define EFI_VARSTORE_HEADER_GUID_AUTHENTICATED_VARIABLE \ + { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } } +/** The GUID for a variable store using the standard variable header format. */ +#define EFI_VARSTORE_HEADER_GUID_VARIABLE \ + { 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d } } + +/** The EFI_VARSTORE_HEADER::bFmt value when the store region is formatted. */ +#define EFI_VARSTORE_HEADER_FMT_FORMATTED 0x5a +/** The EFI_VARSTORE_HEADER::bState value when the store region is healthy. */ +#define EFI_VARSTORE_HEADER_STATE_HEALTHY 0xfe + + +/** + * Authenticated variable header. + */ +#pragma pack(1) +typedef struct EFI_AUTH_VAR_HEADER +{ + /** Contains EFI_AUTH_VAR_HEADER_START to identify the start of a new variable header. */ + uint16_t u16StartId; + /** Variable state. */ + uint8_t bState; + /** Reserved. */ + uint8_t bRsvd; + /** Variable attributes. */ + uint32_t fAttr; + /** Monotonic counter value increased with each change to protect against replay attacks. */ + uint64_t cMonotonic; + /** Timestamp value to protect against replay attacks. */ + EFI_TIME Timestamp; + /** Index of associated public key in database. */ + uint32_t idPubKey; + /** Size of the variable zero terminated unicode name in bytes. */ + uint32_t cbName; + /** Size of the variable data without this header. */ + uint32_t cbData; + /** Producer/Consumer GUID for this variable. */ + EFI_GUID GuidVendor; +} EFI_AUTH_VAR_HEADER; +#pragma pack() +AssertCompileSize(EFI_AUTH_VAR_HEADER, 60); +/** Pointer to a authenticated variable header. */ +typedef EFI_AUTH_VAR_HEADER *PEFI_AUTH_VAR_HEADER; +/** Pointer to a const authenticated variable header. */ +typedef const EFI_AUTH_VAR_HEADER *PCEFI_AUTH_VAR_HEADER; + +/** Value in EFI_AUTH_VAR_HEADER::u16StartId for a valid variable header. */ +#define EFI_AUTH_VAR_HEADER_START 0x55aa +/** @name Possible variable states. + * @{ */ +/** Variable is in the process of being deleted. */ +#define EFI_AUTH_VAR_HEADER_STATE_IN_DELETED_TRANSITION 0xfe +/** Variable was deleted. */ +#define EFI_AUTH_VAR_HEADER_STATE_DELETED 0xfd +/** Variable has only a valid header right now. */ +#define EFI_AUTH_VAR_HEADER_STATE_HDR_VALID_ONLY 0x7f +/** Variable header, name and data are all valid. */ +#define EFI_AUTH_VAR_HEADER_STATE_ADDED 0x3f +/** @} */ + + +/** @name Possible variable attributes. + * @{ */ +/** The variable is stored in non volatile memory. */ +#define EFI_VAR_HEADER_ATTR_NON_VOLATILE RT_BIT_32(0) +/** The variable is accessible by the EFI bootservice stage. */ +#define EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS RT_BIT_32(1) +/** The variable is accessible during runtime. */ +#define EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS RT_BIT_32(2) +/** The variable contains an hardware error record. */ +#define EFI_VAR_HEADER_ATTR_HW_ERROR_RECORD RT_BIT_32(3) +/** The variable can be modified only by an authenticated source. */ +#define EFI_AUTH_VAR_HEADER_ATTR_AUTH_WRITE_ACCESS RT_BIT_32(4) +/** The variable was written with a time based authentication. */ +#define EFI_AUTH_VAR_HEADER_ATTR_TIME_BASED_AUTH_WRITE_ACCESS RT_BIT_32(5) +/** The variable can be appended. */ +#define EFI_AUTH_VAR_HEADER_ATTR_APPEND_WRITE RT_BIT_32(6) +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_efi_varstore_h */ + diff --git a/include/iprt/formats/elf-amd64.h b/include/iprt/formats/elf-amd64.h new file mode 100644 index 00000000..c0c7f0c1 --- /dev/null +++ b/include/iprt/formats/elf-amd64.h @@ -0,0 +1,131 @@ +/*- + * Copyright (c) 1996-1997 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef IPRT_INCLUDED_formats_elf_amd64_h +#define IPRT_INCLUDED_formats_elf_amd64_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* + * ELF definitions for the AMD64 architecture. + */ + +#if 0 /* later */ +/* + * Auxiliary vector entries for passing information to the interpreter. + * + * The i386 supplement to the SVR4 ABI specification names this "auxv_t", + * but POSIX lays claim to all symbols ending with "_t". + */ +typedef struct { /* Auxiliary vector entry on initial stack */ + int a_type; /* Entry type. */ + union { + int a_val; /* Integer value. */ + } a_un; +} Elf32_Auxinfo; + + +typedef struct { /* Auxiliary vector entry on initial stack */ + long a_type; /* Entry type. */ + union { + long a_val; /* Integer value. */ + void *a_ptr; /* Address. */ + void (*a_fcn)(void); /* Function pointer (not used). */ + } a_un; +} Elf64_Auxinfo; + +__ElfType(Auxinfo); + +/* Values for a_type. */ +#define AT_NULL 0 /* Terminates the vector. */ +#define AT_IGNORE 1 /* Ignored entry. */ +#define AT_EXECFD 2 /* File descriptor of program to load. */ +#define AT_PHDR 3 /* Program header of program already loaded. */ +#define AT_PHENT 4 /* Size of each program header entry. */ +#define AT_PHNUM 5 /* Number of program header entries. */ +#define AT_PAGESZ 6 /* Page size in bytes. */ +#define AT_BASE 7 /* Interpreter's base address. */ +#define AT_FLAGS 8 /* Flags (unused for i386). */ +#define AT_ENTRY 9 /* Where interpreter should transfer control. */ + +/* + * The following non-standard values are used for passing information + * from John Polstra's testbed program to the dynamic linker. These + * are expected to go away soon. + * + * Unfortunately, these overlap the Linux non-standard values, so they + * must not be used in the same context. + */ +#define AT_BRK 10 /* Starting point for sbrk and brk. */ +#define AT_DEBUG 11 /* Debugging level. */ + +/* + * The following non-standard values are used in Linux ELF binaries. + */ +#define AT_NOTELF 10 /* Program is not ELF ?? */ +#define AT_UID 11 /* Real uid. */ +#define AT_EUID 12 /* Effective uid. */ +#define AT_GID 13 /* Real gid. */ +#define AT_EGID 14 /* Effective gid. */ + +#define AT_COUNT 15 /* Count of defined aux entry types. */ + +#endif /* later */ + +/* + * Relocation types. + */ + +#define R_X86_64_NONE 0 /* No relocation. */ +#define R_X86_64_64 1 /* Add 64 bit symbol value. */ +#define R_X86_64_PC32 2 /* PC-relative 32 bit signed sym value. */ +#define R_X86_64_GOT32 3 /* PC-relative 32 bit GOT offset. */ +#define R_X86_64_PLT32 4 /* PC-relative 32 bit PLT offset. */ +#define R_X86_64_COPY 5 /* Copy data from shared object. */ +#define R_X86_64_GLOB_DAT 6 /* Set GOT entry to data address. */ +#define R_X86_64_JMP_SLOT 7 /* Set GOT entry to code address. */ +#define R_X86_64_RELATIVE 8 /* Add load address of shared object. */ +#define R_X86_64_GOTPCREL 9 /* Add 32 bit signed pcrel offset to GOT. */ +#define R_X86_64_32 10 /* Add 32 bit zero extended symbol value */ +#define R_X86_64_32S 11 /* Add 32 bit sign extended symbol value */ +#define R_X86_64_16 12 /* Add 16 bit zero extended symbol value */ +#define R_X86_64_PC16 13 /* Add 16 bit signed extended pc relative symbol value */ +#define R_X86_64_8 14 /* Add 8 bit zero extended symbol value */ +#define R_X86_64_PC8 15 /* Add 8 bit signed extended pc relative symbol value */ +#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ +#define R_X86_64_DTPOFF64 17 /* Offset in TLS block */ +#define R_X86_64_TPOFF64 18 /* Offset in static TLS block */ +#define R_X86_64_TLSGD 19 /* PC relative offset to GD GOT entry */ +#define R_X86_64_TLSLD 20 /* PC relative offset to LD GOT entry */ +#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ +#define R_X86_64_GOTTPOFF 22 /* PC relative offset to IE GOT entry */ +#define R_X86_64_TPOFF32 23 /* Offset in static TLS block */ + +#define R_X86_64_COUNT 24 /* Count of defined relocation types. */ + +#endif /* !IPRT_INCLUDED_formats_elf_amd64_h */ + diff --git a/include/iprt/formats/elf-common.h b/include/iprt/formats/elf-common.h new file mode 100644 index 00000000..992ebaed --- /dev/null +++ b/include/iprt/formats/elf-common.h @@ -0,0 +1,348 @@ +/*- + * Copyright (c) 1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef IPRT_INCLUDED_formats_elf_common_h +#define IPRT_INCLUDED_formats_elf_common_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/stdint.h> + +/* + * ELF definitions that are independent of architecture or word size. + */ + +/* + * Note header. The ".note" section contains an array of notes. Each + * begins with this header, aligned to a word boundary. Immediately + * following the note header is n_namesz bytes of name, padded to the + * next word boundary. Then comes n_descsz bytes of descriptor, again + * padded to a word boundary. The values of n_namesz and n_descsz do + * not include the padding. + */ + +typedef struct { + uint32_t n_namesz; /* Length of name. */ + uint32_t n_descsz; /* Length of descriptor. */ + uint32_t n_type; /* Type of this note. */ +} Elf_Note; + +/* Indexes into the e_ident array. Keep synced with + http://www.sco.com/developer/gabi/ch4.eheader.html */ +#define EI_MAG0 0 /* Magic number, byte 0. */ +#define EI_MAG1 1 /* Magic number, byte 1. */ +#define EI_MAG2 2 /* Magic number, byte 2. */ +#define EI_MAG3 3 /* Magic number, byte 3. */ +#define EI_CLASS 4 /* Class of machine. */ +#define EI_DATA 5 /* Data format. */ +#define EI_VERSION 6 /* ELF format version. */ +#define EI_OSABI 7 /* Operating system / ABI identification */ +#define EI_ABIVERSION 8 /* ABI version */ +#define OLD_EI_BRAND 8 /* Start of architecture identification. */ +#define EI_PAD 9 /* Start of padding (per SVR4 ABI). */ +#define EI_NIDENT 16 /* Size of e_ident array. */ + +/* Values for the magic number bytes. */ +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" /* magic string */ +#define SELFMAG 4 /* magic string size */ + +/* Values for e_ident[EI_VERSION] and e_version. */ +#define EV_NONE 0 +#define EV_CURRENT 1 + +/* Values for e_ident[EI_CLASS]. */ +#define ELFCLASSNONE 0 /* Unknown class. */ +#define ELFCLASS32 1 /* 32-bit architecture. */ +#define ELFCLASS64 2 /* 64-bit architecture. */ + +/* Values for e_ident[EI_DATA]. */ +#define ELFDATANONE 0 /* Unknown data format. */ +#define ELFDATA2LSB 1 /* 2's complement little-endian. */ +#define ELFDATA2MSB 2 /* 2's complement big-endian. */ + +/* Values for e_ident[EI_OSABI]. */ +#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ +#define ELFOSABI_NONE ELFOSABI_SYSV /* symbol used in old spec */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_MONTEREY 7 /* Monterey */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* Values for e_type. */ +#define ET_NONE 0 /* Unknown type. */ +#define ET_REL 1 /* Relocatable. */ +#define ET_EXEC 2 /* Executable. */ +#define ET_DYN 3 /* Shared object. */ +#define ET_CORE 4 /* Core file. */ + +/* Values for e_machine. */ +#define EM_NONE 0 /* Unknown machine. */ +#define EM_M32 1 /* AT&T WE32100. */ +#define EM_SPARC 2 /* Sun SPARC. */ +#define EM_386 3 /* Intel i386. */ +#define EM_68K 4 /* Motorola 68000. */ +#define EM_88K 5 /* Motorola 88000. */ +#define EM_486 6 /* Intel i486. */ +#define EM_860 7 /* Intel i860. */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ + +/* Extensions. This list is not complete. */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ /* Depreciated */ +#define EM_PARISC 15 /* HPPA */ +#define EM_SPARC32PLUS 18 /* SPARC v8plus */ +#define EM_PPC 20 /* PowerPC 32-bit */ +#define EM_PPC64 21 /* PowerPC 64-bit */ +#define EM_ARM 40 /* ARM */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_IA_64 50 /* Intel IA-64 Processor */ +#define EM_X86_64 62 /* Advanced Micro Devices x86-64 */ +#define EM_AMD64 EM_X86_64 /* SunOS compatibility (added by Ramshankar) */ +#define EM_ALPHA 0x9026 /* Alpha (written in the absence of an ABI */ + +/* Special section indexes. */ +#define SHN_UNDEF 0 /* Undefined, missing, irrelevant. */ +#define SHN_LORESERVE 0xff00 /* First of reserved range. */ +#define SHN_LOPROC 0xff00 /* First processor-specific. */ +#define SHN_HIPROC 0xff1f /* Last processor-specific. */ +#define SHN_ABS 0xfff1 /* Absolute values. */ +#define SHN_COMMON 0xfff2 /* Common data. */ +#define SHN_HIRESERVE 0xffff /* Last of reserved range. */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends */ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relocation section - no addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_NUM 12 /* number of section types */ +#define SHT_LOOS 0x60000000 /* First of OS specific semantics */ +#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Flags for sh_flags. */ +#define SHF_WRITE 0x1 /* Section contains writable data. */ +#define SHF_ALLOC 0x2 /* Section occupies memory. */ +#define SHF_EXECINSTR 0x4 /* Section contains instructions. */ +#define SHF_TLS 0x400 /* Section contains TLS data. */ +#define SHF_MASKPROC 0xf0000000 /* Reserved for processor-specific. */ + +/* Values for p_type. */ +#define PT_NULL 0 /* Unused entry. */ +#define PT_LOAD 1 /* Loadable segment. */ +#define PT_DYNAMIC 2 /* Dynamic linking information segment. */ +#define PT_INTERP 3 /* Pathname of interpreter. */ +#define PT_NOTE 4 /* Auxiliary information. */ +#define PT_SHLIB 5 /* Reserved (not used). */ +#define PT_PHDR 6 /* Location of program header itself. */ +#define PT_TLS 7 /* Thread local storage segment */ + +#define PT_COUNT 8 /* Number of defined p_type values. */ + +#define PT_LOOS 0x60000000 /* OS-specific */ +#define PT_HIOS 0x6fffffff /* OS-specific */ +#define PT_LOPROC 0x70000000 /* First processor-specific type. */ +#define PT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +#define PT_GNU_EH_FRAME 0x6474e550 /**< GNU/Linux -> .eh_frame_hdr */ +#define PT_GNU_STACK 0x6474e551 /**< GNU/Linux -> stack prot (RWX or RW) */ +#define PT_GNU_RELRO 0x6474e552 /**< GNU/Linux -> make RO after relocations */ +#define PT_GNU_PROPERTY 0x6474e553 /**< GNU/Linux -> .note.gnu.property */ + + +/* Values for p_flags. */ +#define PF_X 0x1 /* Executable. */ +#define PF_W 0x2 /* Writable. */ +#define PF_R 0x4 /* Readable. */ + +/* Values for d_tag. */ +#define DT_NULL 0 /* Terminating entry. */ +#define DT_NEEDED 1 /* String table offset of a needed shared + library. */ +#define DT_PLTRELSZ 2 /* Total size in bytes of PLT relocations. */ +#define DT_PLTGOT 3 /* Processor-dependent address. */ +#define DT_HASH 4 /* Address of symbol hash table. */ +#define DT_STRTAB 5 /* Address of string table. */ +#define DT_SYMTAB 6 /* Address of symbol table. */ +#define DT_RELA 7 /* Address of ElfNN_Rela relocations. */ +#define DT_RELASZ 8 /* Total size of ElfNN_Rela relocations. */ +#define DT_RELAENT 9 /* Size of each ElfNN_Rela relocation entry. */ +#define DT_STRSZ 10 /* Size of string table. */ +#define DT_SYMENT 11 /* Size of each symbol table entry. */ +#define DT_INIT 12 /* Address of initialization function. */ +#define DT_FINI 13 /* Address of finalization function. */ +#define DT_SONAME 14 /* String table offset of shared object + name. */ +#define DT_RPATH 15 /* String table offset of library path. [sup] */ +#define DT_SYMBOLIC 16 /* Indicates "symbolic" linking. [sup] */ +#define DT_REL 17 /* Address of ElfNN_Rel relocations. */ +#define DT_RELSZ 18 /* Total size of ElfNN_Rel relocations. */ +#define DT_RELENT 19 /* Size of each ElfNN_Rel relocation. */ +#define DT_PLTREL 20 /* Type of relocation used for PLT. */ +#define DT_DEBUG 21 /* Reserved (not used). */ +#define DT_TEXTREL 22 /* Indicates there may be relocations in + non-writable segments. [sup] */ +#define DT_JMPREL 23 /* Address of PLT relocations. */ +#define DT_BIND_NOW 24 /* [sup] */ +#define DT_INIT_ARRAY 25 /* Address of the array of pointers to + initialization functions */ +#define DT_FINI_ARRAY 26 /* Address of the array of pointers to + termination functions */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of the array of + initialization functions. */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of the array of + terminationfunctions. */ +#define DT_RUNPATH 29 /* String table offset of a null-terminated + library search path string. */ +#define DT_FLAGS 30 /* Object specific flag values. */ +#define DT_ENCODING 32 /* Values greater than or equal to DT_ENCODING + and less than DT_LOOS follow the rules for + the interpretation of the d_un union + as follows: even == 'd_ptr', even == 'd_val' + or none */ +#define DT_PREINIT_ARRAY 32 /* Address of the array of pointers to + pre-initialization functions. */ +#define DT_PREINIT_ARRAYSZ 33 /* Size in bytes of the array of + pre-initialization functions. */ + +#define DT_COUNT 33 /* Number of defined d_tag values. */ + +#define DT_LOOS 0x6000000d /* First OS-specific */ +#define DT_HIOS 0x6fff0000 /* Last OS-specific */ +#define DT_LOPROC 0x70000000 /* First processor-specific type. */ +#define DT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +/* Values for DT_FLAGS */ +#define DF_ORIGIN 0x0001 /* Indicates that the object being loaded may + make reference to the $ORIGIN substitution + string */ +#define DF_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */ +#define DF_TEXTREL 0x0004 /* Indicates there may be relocations in + non-writable segments. */ +#define DF_BIND_NOW 0x0008 /* Indicates that the dynamic linker should + process all relocations for the object + containing this entry before transferring + control to the program. */ +#define DF_STATIC_TLS 0x0010 /* Indicates that the shared object or + executable contains code using a static + thread-local storage scheme. */ + +/* Values for n_type. Used in core files. */ +#if defined(RT_OS_FREEBSD) +# define NT_PRSTATUS 1 /* Process status. */ +# define NT_FPREGSET 2 /* Floating point registers. */ +# define NT_PRPSINFO 3 /* Process state info. */ +#elif defined(RT_OS_SOLARIS) +# define NT_PRSTATUS 1 /* prstatus_t <sys/old_procfs.h> */ +# define NT_PRFPREG 2 /* prfpregset_t <sys/old_procfs.h> */ +# define NT_PRPSINFO 3 /* prpsinfo_t <sys/old_procfs.h> */ +# define NT_PRXREG 4 /* prxregset_t <sys/procfs.h> */ +# define NT_PLATFORM 5 /* string from sysinfo(SI_PLATFORM) */ +# define NT_AUXV 6 /* auxv_t array <sys/auxv.h> */ +# define NT_LDT 9 /* ssd array <sys/sysi86.h> IA32 only */ +# define NT_PSTATUS 10 /* pstatus_t <sys/procfs.h> */ +# define NT_PSINFO 13 /* psinfo_t <sys/procfs.h> */ +# define NT_PRCRED 14 /* prcred_t <sys/procfs.h> */ +# define NT_UTSNAME 15 /* struct utsname <sys/utsname.h> */ +# define NT_LWPSTATUS 16 /* lwpstatus_t <sys/procfs.h> */ +# define NT_LWPSINFO 17 /* lwpsinfo_t <sys/procfs.h> */ +# define NT_PRPRIV 18 /* prpriv_t <sys/procfs.h> */ +# define NT_PRPRIVINFO 19 /* priv_impl_info_t <sys/priv.h> */ +# define NT_CONTENT 20 /* core_content_t <sys/corectl.h> */ +# define NT_ZONENAME 21 /* string from getzonenamebyid(3C) */ +# define PF_SUNW_FAILURE 0x00100000 /* mapping absent due to failure */ +# define PN_XNUM 0xffff /* extended program header index */ +#elif defined(RT_OS_LINUX) +# define NT_PRSTATUS 1 /* Process status. */ +# define NT_PRFPREG 2 /* Floating point registers. */ +# define NT_PRPSINFO 3 /* Process state info. */ +# define NT_TASKSTRUCT 4 /* Task info. */ +# define NT_AUXV 6 /* Process auxiliary vectors. */ +# define NT_PRXFPREG 0x46e62b7f /* from gdb5.1/include/elf/common.h */ +#endif +/* GNU Build ID in a dedicated section. */ +#define NT_GNU_BUILD_ID 3 + +/* VirtualBox specific NOTE sections (added by Ramshankar) */ +#ifdef VBOX +# define NT_VBOXCORE 0xb00 +# define NT_VBOXCPU 0xb01 +#endif + +/* Symbol Binding - ELFNN_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific symbol bindings */ + +/* Symbol type - ELFNN_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* Unspecified type. */ +#define STT_OBJECT 1 /* Data object. */ +#define STT_FUNC 2 /* Function. */ +#define STT_SECTION 3 /* Section. */ +#define STT_FILE 4 /* Source file. */ +#define STT_TLS 6 /* TLS object. */ +#define STT_NUM 7 /* Number of generic symbol types. */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific symbol types */ + +/* Special symbol table indexes. */ +#define STN_UNDEF 0 /* Undefined symbol index. */ + +#endif /* !IPRT_INCLUDED_formats_elf_common_h */ + diff --git a/include/iprt/formats/elf-i386.h b/include/iprt/formats/elf-i386.h new file mode 100644 index 00000000..4ebaafc6 --- /dev/null +++ b/include/iprt/formats/elf-i386.h @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 1996-1997 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef IPRT_INCLUDED_formats_elf_i386_h +#define IPRT_INCLUDED_formats_elf_i386_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#if 0 /* later */ + +/* + * Auxiliary vector entries for passing information to the interpreter. + * + * The i386 supplement to the SVR4 ABI specification names this "auxv_t", + * but POSIX lays claim to all symbols ending with "_t". + */ + +typedef struct { /* Auxiliary vector entry on initial stack */ + int a_type; /* Entry type. */ + union { + long a_val; /* Integer value. */ + void *a_ptr; /* Address. */ + void (*a_fcn)(void); /* Function pointer (not used). */ + } a_un; +} Elf32_Auxinfo; + +#if __ELF_WORD_SIZE == 64 +/* Fake for amd64 loader support */ +typedef struct { + int fake; +} Elf64_Auxinfo; +#endif + +/* Values for a_type. */ +#define AT_NULL 0 /* Terminates the vector. */ +#define AT_IGNORE 1 /* Ignored entry. */ +#define AT_EXECFD 2 /* File descriptor of program to load. */ +#define AT_PHDR 3 /* Program header of program already loaded. */ +#define AT_PHENT 4 /* Size of each program header entry. */ +#define AT_PHNUM 5 /* Number of program header entries. */ +#define AT_PAGESZ 6 /* Page size in bytes. */ +#define AT_BASE 7 /* Interpreter's base address. */ +#define AT_FLAGS 8 /* Flags (unused for i386). */ +#define AT_ENTRY 9 /* Where interpreter should transfer control. */ + +/* + * The following non-standard values are used for passing information + * from John Polstra's testbed program to the dynamic linker. These + * are expected to go away soon. + * + * Unfortunately, these overlap the Linux non-standard values, so they + * must not be used in the same context. + */ +#define AT_BRK 10 /* Starting point for sbrk and brk. */ +#define AT_DEBUG 11 /* Debugging level. */ + +/* + * The following non-standard values are used in Linux ELF binaries. + */ +#define AT_NOTELF 10 /* Program is not ELF ?? */ +#define AT_UID 11 /* Real uid. */ +#define AT_EUID 12 /* Effective uid. */ +#define AT_GID 13 /* Real gid. */ +#define AT_EGID 14 /* Effective gid. */ + +#define AT_COUNT 15 /* Count of defined aux entry types. */ + +#endif /* later */ + + +/* + * Relocation types. + */ + +#define R_386_NONE 0 /* No relocation. */ +#define R_386_32 1 /* Add symbol value. */ +#define R_386_PC32 2 /* Add PC-relative symbol value. */ +#define R_386_GOT32 3 /* Add PC-relative GOT offset. */ +#define R_386_PLT32 4 /* Add PC-relative PLT offset. */ +#define R_386_COPY 5 /* Copy data from shared object. */ +#define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */ +#define R_386_JMP_SLOT 7 /* Set GOT entry to code address. */ +#define R_386_RELATIVE 8 /* Add load address of shared object. */ +#define R_386_GOTOFF 9 /* Add GOT-relative symbol address. */ +#define R_386_GOTPC 10 /* Add PC-relative GOT table address. */ +#define R_386_TLS_TPOFF 14 /* Negative offset in static TLS block */ +#define R_386_TLS_IE 15 /* Absolute address of GOT for -ve static TLS */ +#define R_386_TLS_GOTIE 16 /* GOT entry for negative static TLS block */ +#define R_386_TLS_LE 17 /* Negative offset relative to static TLS */ +#define R_386_TLS_GD 18 /* 32 bit offset to GOT (index,off) pair */ +#define R_386_TLS_LDM 19 /* 32 bit offset to GOT (index,zero) pair */ +#define R_386_TLS_GD_32 24 /* 32 bit offset to GOT (index,off) pair */ +#define R_386_TLS_GD_PUSH 25 /* pushl instruction for Sun ABI GD sequence */ +#define R_386_TLS_GD_CALL 26 /* call instruction for Sun ABI GD sequence */ +#define R_386_TLS_GD_POP 27 /* popl instruction for Sun ABI GD sequence */ +#define R_386_TLS_LDM_32 28 /* 32 bit offset to GOT (index,zero) pair */ +#define R_386_TLS_LDM_PUSH 29 /* pushl instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDM_CALL 30 /* call instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDM_POP 31 /* popl instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDO_32 32 /* 32 bit offset from start of TLS block */ +#define R_386_TLS_IE_32 33 /* 32 bit offset to GOT static TLS offset entry */ +#define R_386_TLS_LE_32 34 /* 32 bit offset within static TLS block */ +#define R_386_TLS_DTPMOD32 35 /* GOT entry containing TLS index */ +#define R_386_TLS_DTPOFF32 36 /* GOT entry containing TLS offset */ +#define R_386_TLS_TPOFF32 37 /* GOT entry of -ve static TLS offset */ + +#define R_386_COUNT 38 /* Count of defined relocation types. */ + +#endif /* !IPRT_INCLUDED_formats_elf_i386_h */ + diff --git a/include/iprt/formats/elf.h b/include/iprt/formats/elf.h new file mode 100644 index 00000000..e7daab46 --- /dev/null +++ b/include/iprt/formats/elf.h @@ -0,0 +1,98 @@ +/* $Id: elf.h $ */ +/** @file + * ELF types, current architecture. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_elf_h +#define IPRT_INCLUDED_formats_elf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_ARM64) +# include "elf64.h" +typedef Elf64_Addr Elf_Addr; +typedef Elf64_Half Elf_Half; +typedef Elf64_Off Elf_Off; +typedef Elf64_Sword Elf_Sword; +typedef Elf64_Word Elf_Word; +typedef Elf64_Size Elf_Size; +typedef Elf64_Hashelt Elf_Hashelt; +typedef Elf64_Ehdr Elf_Ehdr; +typedef Elf64_Shdr Elf_Shdr; +typedef Elf64_Phdr Elf_Phdr; +typedef Elf64_Nhdr Elf_Nhdr; +typedef Elf64_Dyn Elf_Dyn; +typedef Elf64_Rel Elf_Rel; +typedef Elf64_Rela Elf_Rela; +typedef Elf64_Sym Elf_Sym; + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_R_INFO ELF64_R_INFO +#define ELF_ST_BIND ELF64_ST_BIND +#define ELF_ST_TYPE ELF64_ST_TYPE +#define ELF_ST_INFO ELF64_ST_INFO + +#elif defined(RT_ARCH_X86) +# include "elf32.h" +typedef Elf32_Addr Elf_Addr; +typedef Elf32_Half Elf_Half; +typedef Elf32_Off Elf_Off; +typedef Elf32_Sword Elf_Sword; +typedef Elf32_Word Elf_Word; +typedef Elf32_Size Elf_Size; +typedef Elf32_Hashelt Elf_Hashelt; +typedef Elf32_Ehdr Elf_Ehdr; +typedef Elf32_Shdr Elf_Shdr; +typedef Elf32_Phdr Elf_Phdr; +typedef Elf32_Nhdr Elf_Nhdr; +typedef Elf32_Dyn Elf_Dyn; +typedef Elf32_Rel Elf_Rel; +typedef Elf32_Rela Elf_Rela; +typedef Elf32_Sym Elf_Sym; + +#define ELF_R_SYM ELF32_R_SYM +#define ELF_R_TYPE ELF32_R_TYPE +#define ELF_R_INFO ELF32_R_INFO +#define ELF_ST_BIND ELF32_ST_BIND +#define ELF_ST_TYPE ELF32_ST_TYPE +#define ELF_ST_INFO ELF32_ST_INFO + +#else +# error Unknown arch! +#endif + +#endif /* !IPRT_INCLUDED_formats_elf_h */ + diff --git a/include/iprt/formats/elf32.h b/include/iprt/formats/elf32.h new file mode 100644 index 00000000..ae322bb6 --- /dev/null +++ b/include/iprt/formats/elf32.h @@ -0,0 +1,200 @@ +/* $Id: elf32.h $ */ +/** @file + * IPRT - ELF 32-bit header. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_elf32_h +#define IPRT_INCLUDED_formats_elf32_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assertcompile.h> +#include "elf-common.h" + +/* + * ELF 32 standard types. + */ +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +/* + * Ensure type size correctness in accordance to . + * Portable Format Specification (for ELF), Version 1.1, fig 1-2. . + */ +AssertCompileSize(Elf32_Addr, 4); +AssertCompileSize(Elf32_Half, 2); +AssertCompileSize(Elf32_Off, 4); +AssertCompileSize(Elf32_Sword, 4); +AssertCompileSize(Elf32_Word, 4); + +/* + * ELF 32 non-standard types for convenience. + */ +typedef Elf32_Word Elf32_Size; +typedef Elf32_Word Elf32_Hashelt; + +/* + * ELF header. + */ +typedef struct +{ + unsigned char e_ident[16]; /* ELF identification. */ + Elf32_Half e_type; /* Object file type. */ + Elf32_Half e_machine; /* Machine type. */ + Elf32_Word e_version; /* Object file version. */ + Elf32_Addr e_entry; /* Entry point address. */ + Elf32_Off e_phoff; /* Program header offset. */ + Elf32_Off e_shoff; /* Section header offset. */ + Elf32_Word e_flags; /* Processor-specific flags. */ + Elf32_Half e_ehsize; /* ELF header size. */ + Elf32_Half e_phentsize; /* Size of program header entries. */ + Elf32_Half e_phnum; /* Number of program headers. */ + Elf32_Half e_shentsize; /* Size of section header entries. */ + Elf32_Half e_shnum; /* Number of section headers. */ + Elf32_Half e_shstrndx; /* Section name string table index. */ +} Elf32_Ehdr; + +/* + * Section header. + */ +typedef struct +{ + Elf32_Word sh_name; /* Section name. */ + Elf32_Word sh_type; /* Section type. */ + Elf32_Word sh_flags; /* Section attributes. */ + Elf32_Addr sh_addr; /* Virtual address in memory. */ + Elf32_Off sh_offset; /* Offset in file. */ + Elf32_Word sh_size; /* Size of section. */ + Elf32_Word sh_link; /* Link to other section. */ + Elf32_Word sh_info; /* Miscellaneous information. */ + Elf32_Word sh_addralign; /* Address alignment boundary. */ + Elf32_Word sh_entsize; /* Size of entries, if section has table. */ +} Elf32_Shdr; + + +/* + * Program header. + */ +typedef struct +{ + Elf32_Word p_type; /* Type of segment. */ + Elf32_Off p_offset; /* Offset in file. */ + Elf32_Addr p_vaddr; /* Virtual address in memory. */ + Elf32_Addr p_paddr; /* Physical address (reserved). */ + Elf32_Word p_filesz; /* Size of segment in file. */ + Elf32_Word p_memsz; /* Size of segment in memory. */ + Elf32_Word p_flags; /* Segment attributes. */ + Elf32_Word p_align; /* Alignment of segment. */ +} Elf32_Phdr; + + +/* + * Note header. + */ +typedef struct +{ + Elf32_Word n_namesz; /* Length of note's name. */ + Elf32_Word n_descsz; /* Length of note's description. */ + Elf32_Word n_type; /* Type of note. */ +} Elf32_Nhdr; + + +/* + * Symbol table entry. + */ +typedef struct +{ + Elf32_Word st_name; /* Symbol name. */ + Elf32_Addr st_value; /* Symbol value. */ + Elf32_Word st_size; /* Size associated with symbol. */ + unsigned char st_info; /* Type and binding attributes. */ + unsigned char st_other; /* Reserved. */ + Elf32_Half st_shndx; /* Section header table index. */ +} Elf32_Sym; + + +/* + * Relocations. + */ +typedef struct +{ + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Symbol index and type of relocation. */ +} Elf32_Rel; + +typedef struct +{ + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Symbol index and type of relocation. */ + Elf32_Sword r_addend; /* Constant part of expression. */ +} Elf32_Rela; + +/* + * Dynamic section entry. + * ".dynamic" section contains an array of this. + */ +typedef struct +{ + Elf32_Sword d_tag; /* Type of entry. */ + union + { + Elf32_Word d_val; /* Integer value. */ + Elf32_Addr d_ptr; /* Virtual address value. */ + } d_un; +} Elf32_Dyn; + +/* + * Helper macros. + */ +/** The symbol's type. */ +#define ELF32_ST_TYPE(info) ((info) & 0xF) +/** The symbol's binding. */ +#define ELF32_ST_BIND(info) ((info) >> 4) +/** Make st_info. given binding and type. */ +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/** Relocation type. */ +#define ELF32_R_TYPE(info) ((unsigned char)(info)) +/** Relocation symbol index. */ +#define ELF32_R_SYM(info) ((info) >> 8) +/** Make r_info given the symbol index and type. */ +#define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type)) + + +#endif /* !IPRT_INCLUDED_formats_elf32_h */ + diff --git a/include/iprt/formats/elf64.h b/include/iprt/formats/elf64.h new file mode 100644 index 00000000..63d4b1cb --- /dev/null +++ b/include/iprt/formats/elf64.h @@ -0,0 +1,199 @@ +/* $Id: elf64.h $ */ +/** @file + * IPRT - ELF 64-bit header. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_elf64_h +#define IPRT_INCLUDED_formats_elf64_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assertcompile.h> +#include "elf-common.h" + +/* + * ELF 64 standard types. + */ +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; +typedef uint16_t Elf64_Half; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* + * Ensure type size correctness in accordance to ELF-64 Object File Format, Version 1.5 Draft 2, p2. + */ +AssertCompileSize(Elf64_Addr, 8); +AssertCompileSize(Elf64_Off, 8); +AssertCompileSize(Elf64_Half, 2); +AssertCompileSize(Elf64_Word, 4); +AssertCompileSize(Elf64_Sword, 4); +AssertCompileSize(Elf64_Xword, 8); +AssertCompileSize(Elf64_Sxword, 8); + +/* + * ELF 64 non-standard types for convenience. + */ +typedef Elf64_Xword Elf64_Size; +typedef Elf64_Word Elf64_Hashelt; + +/* + * ELF Header. + */ +typedef struct +{ + unsigned char e_ident[16]; /* ELF identification. */ + Elf64_Half e_type; /* Object file type. */ + Elf64_Half e_machine; /* Machine type. */ + Elf64_Word e_version; /* Object file version. */ + Elf64_Addr e_entry; /* Entry point address. */ + Elf64_Off e_phoff; /* Program header offset. */ + Elf64_Off e_shoff; /* Section header offset. */ + Elf64_Word e_flags; /* Processor-specific flags. */ + Elf64_Half e_ehsize; /* ELF header size. */ + Elf64_Half e_phentsize; /* Size of program header entry. */ + Elf64_Half e_phnum; /* Number of program header entries. */ + Elf64_Half e_shentsize; /* Size of section header entry. */ + Elf64_Half e_shnum; /* Number of section header entries. */ + Elf64_Half e_shstrndx; /* Section name string table index. */ +} Elf64_Ehdr; + +/* + * Section header. + */ +typedef struct +{ + Elf64_Word sh_name; /* Section name. */ + Elf64_Word sh_type; /* Section type. */ + Elf64_Xword sh_flags; /* Section attributes. */ + Elf64_Addr sh_addr; /* Virtual address in memory. */ + Elf64_Off sh_offset; /* Offset in file. */ + Elf64_Xword sh_size; /* Size of section. */ + Elf64_Word sh_link; /* Link to other section. */ + Elf64_Word sh_info; /* Miscellaneous information. */ + Elf64_Xword sh_addralign; /* Address alignment boundary. */ + Elf64_Xword sh_entsize; /* Size of entries, if section has table. */ +} Elf64_Shdr; + +/* + * Program header. + */ +typedef struct +{ + Elf64_Word p_type; /* Type of segment. */ + Elf64_Word p_flags; /* Segment attributes. */ + Elf64_Off p_offset; /* Offset in file. */ + Elf64_Addr p_vaddr; /* Virtual address in memory. */ + Elf64_Addr p_paddr; /* Physical address (reserved). */ + Elf64_Xword p_filesz; /* Size of segment in file. */ + Elf64_Xword p_memsz; /* Size of segment in memory. */ + Elf64_Xword p_align; /* Alignment of segment. */ +} Elf64_Phdr; + +/* + * Note header. + */ +typedef struct +{ + Elf64_Word n_namesz; /* Length of note's name. */ + Elf64_Word n_descsz; /* Length of note's description. */ + Elf64_Word n_type; /* Type of note. */ +} Elf64_Nhdr; + +/* + * Symbol table entry. + */ +typedef struct +{ + Elf64_Word st_name; /* Symbol name. */ + unsigned char st_info; /* Type and binding attributes. */ + unsigned char st_other; /* Reserved. */ + Elf64_Half st_shndx; /* Section header table index. */ + Elf64_Addr st_value; /* Symbol value. */ + Elf64_Xword st_size; /* Size associated with symbol. */ +} Elf64_Sym; + +/* + * Relocations. + */ +typedef struct +{ + Elf64_Addr r_offset; /* Location to be relocated. */ + Elf64_Xword r_info; /* Symbol index and type of relocation. */ +} Elf64_Rel; + +typedef struct +{ + Elf64_Addr r_offset; /* Location to be relocated. */ + Elf64_Xword r_info; /* Symbol index and type of relocation. */ + Elf64_Sxword r_addend; /* Constant part of expression. */ +} Elf64_Rela; + +/* + * Dynamic section entry. + * ".dynamic" section contains an array of this. + */ +typedef struct +{ + Elf64_Sxword d_tag; /* Type of entry. */ + union + { + Elf64_Xword d_val; /* Integer value. */ + Elf64_Addr d_ptr; /* Virtual address value. */ + } d_un; +} Elf64_Dyn; + +/* + * Helper macros. + */ +/** The symbol's type. */ +#define ELF64_ST_TYPE(info) ((info) & 0xF) +/** The symbol's binding. */ +#define ELF64_ST_BIND(info) ((info) >> 4) +/** Make st_info. given binding and type. */ +#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/** Relocation type. */ +#define ELF64_R_TYPE(info) ((unsigned char)(info)) +/** Relocation symbol index. */ +#define ELF64_R_SYM(info) ((info) >> 32) +/** Make r_info given the symbol index and type. */ +#define ELF64_R_INFO(sym, type) (((sym) << 32) + (unsigned char)(type)) + + +#endif /* !IPRT_INCLUDED_formats_elf64_h */ + diff --git a/include/iprt/formats/ext.h b/include/iprt/formats/ext.h new file mode 100644 index 00000000..e9b137a4 --- /dev/null +++ b/include/iprt/formats/ext.h @@ -0,0 +1,998 @@ +/* $Id: ext.h $ */ +/** @file + * IPRT, Ext2/3/4 format. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_ext_h +#define IPRT_INCLUDED_formats_ext_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_rt_formats_ext Extended Filesystem (EXT2/3/4) structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + +/* + * The filesystem structures were retrieved from: + * https://www.kernel.org/doc/html/latest/filesystems/ext4/index.html + */ + +/** Offset where to find the first superblock on the disk, this is constant. */ +#define EXT_SB_OFFSET 1024 + +/** @name EXT_INODE_NR_XXX - Special inode numbers. + * @{ */ +#define EXT_INODE_NR_DEF_BLOCKS 1 /**< List of defective blocks. */ +#define EXT_INODE_NR_ROOT_DIR 2 /**< Root directory. */ +#define EXT_INODE_NR_USER_QUOTA 3 /**< User quota. */ +#define EXT_INODE_NR_GROUP_QUOTA 4 /**< Group quota. */ +#define EXT_INODE_NR_BOOT_LOADER 5 /**< Boot loader. */ +#define EXT_INODE_NR_UNDEL_DIR 6 /**< Undelete directory. */ +#define EXT_INODE_NR_RESV_GRP_DESC 7 /**< Reserved group descriptors inode. */ +#define EXT_INODE_NR_JOURNAL 8 /**< Journal. */ +#define EXT_INODE_NR_EXCLUDE 9 /**< Exclude inode. */ +#define EXT_INODE_NR_REPLICA 10 /**< Replica inode. */ +/** @} */ + +/** + * Ext superblock. + * + * Everything is stored little endian on the disk. + */ +typedef struct EXTSUPERBLOCK +{ + /** 0x00: Total number of inodes in the filesystem. */ + uint32_t cInodesTotal; + /** 0x04: Total number of blocks in the filesystem (low 32bits). */ + uint32_t cBlocksTotalLow; + /** 0x08: Number of blocks reserved for the super user (low 32bits). */ + uint32_t cBlocksRsvdForSuperUserLow; + /** 0x0c: Total number of free blocks (low 32bits). */ + uint32_t cBlocksFreeLow; + /** 0x10: Total number of free inodes. */ + uint32_t cInodesFree; + /** 0x14: First data block. */ + uint32_t iBlockOfSuperblock; + /** 0x18: Block size (calculated as 2^(10 + cBitsShiftLeftBlockSize)). */ + uint32_t cLogBlockSize; + /** 0x1c: Cluster size (calculated as 2^cLogClusterSize). */ + uint32_t cLogClusterSize; + /** 0x20: Number of blocks in each block group. */ + uint32_t cBlocksPerGroup; + /** 0x24: Number of clusters in each block group. */ + uint32_t cClustersPerBlockGroup; + /** 0x28: Number of inodes for each block group. */ + uint32_t cInodesPerBlockGroup; + /** 0x2c: Last mount time in seconds since epoch. */ + uint32_t u32LastMountTime; + /** 0x30: Last written time in seconds since epoch. */ + uint32_t u32LastWrittenTime; + /** 0x34: Number of times the volume was mounted since the last check. */ + uint16_t cMountsSinceLastCheck; + /** 0x36: Number of mounts allowed before a consistency check. */ + uint16_t cMaxMountsUntilCheck; + /** 0x38: Signature to identify a ext2 volume (EXT_SIGNATURE). */ + uint16_t u16Signature; + /** 0x3a: State of the filesystem (EXT_SB_STATE_XXX) */ + uint16_t u16FilesystemState; + /** 0x3c: What to do on an error. */ + uint16_t u16ActionOnError; + /** 0x3e: Minor revision level. */ + uint16_t u16RevLvlMinor; + /** 0x40: Time of last check in seconds since epoch. */ + uint32_t u32LastCheckTime; + /** 0x44: Interval between consistency checks in seconds. */ + uint32_t u32CheckInterval; + /** 0x48: Operating system ID of the filesystem creator (EXT_SB_OS_ID_CREATOR_XXX). */ + uint32_t u32OsIdCreator; + /** 0x4c: Revision level (EXT_SB_REV_XXX). */ + uint32_t u32RevLvl; + /** 0x50: User ID that is allowed to use reserved blocks. */ + uint16_t u16UidReservedBlocks; + /** 0x52: Group ID that is allowed to use reserved blocks. */ + uint16_t u16GidReservedBlocks; + /** 0x54: First non reserved inode number. */ + uint32_t iFirstInodeNonRsvd; + /** 0x58: Size of the inode structure in bytes. */ + uint16_t cbInode; + /** 0x5a: Block group number of this super block. */ + uint16_t iBlkGrpSb; + /** 0x5c: Compatible feature set flags (EXT_SB_FEAT_COMPAT_XXX). */ + uint32_t fFeaturesCompat; + /** 0x60: Incompatible feature set (EXT_SB_FEAT_INCOMPAT_XXX). */ + uint32_t fFeaturesIncompat; + /** 0x64: Readonly-compatible feature set (EXT_SB_FEAT_COMPAT_RO_XXX). */ + uint32_t fFeaturesCompatRo; + /** 0x68: 128bit UUID for the volume. */ + uint8_t au8Uuid[16]; + /** 0x78: Volume name. */ + char achVolumeName[16]; + /** 0x88: Directory were the filesystem was mounted last. */ + char achLastMounted[64]; + /** 0xc8: Bitmap usage algorithm (used for compression). */ + uint32_t u32AlgoUsageBitmap; + /** 0xcc: Number of blocks to try to preallocate for files(?). */ + uint8_t cBlocksPrealloc; + /** 0xcd: Number of blocks to try to preallocate for directories. */ + uint8_t cBlocksPreallocDirectory; + /** 0xce: Number of reserved group descriptor entries for future filesystem expansion. */ + uint16_t cGdtEntriesRsvd; + /** 0xd0: 128bit UUID for the journal superblock. */ + uint8_t au8JournalUuid[16]; + /** 0xe0: Inode number of the journal file. */ + uint32_t iJournalInode; + /** 0xe4: Device number of journal file (if the appropriate feature flag is set). */ + uint32_t u32JournalDev; + /** 0xe8: Start of list of orpaned inodes to delete. */ + uint32_t u32LastOrphan; + /** 0xec: HTREE hash seed. */ + uint32_t au32HashSeedHtree[4]; + /** 0xfc: Default hash algorithm to use for hashes (EXT_SB_HASH_VERSION_DEF_XXX). */ + uint8_t u8HashVersionDef; + /** 0xfd: Journal backup type. */ + uint8_t u8JnlBackupType; + /** 0xfe: Group descriptor size in bytes. */ + uint16_t cbGroupDesc; + /** 0x100: Default mount options (EXT_SB_MNT_OPTS_DEF_XXX). */ + uint32_t fMntOptsDef; + /** 0x104: First metablock block group (if feature is enabled). */ + uint32_t iFirstMetaBg; + /** 0x108: Filesystem creation time in seconds since epoch. */ + uint32_t u32TimeFsCreation; + /** 0x10c: Backup copy of journals inodes block array for the first elements. */ + uint32_t au32JnlBlocks[17]; + /** 0x150: Total number of blocks in the filesystem (high 32bits). */ + uint32_t cBlocksTotalHigh; + /** 0x154: Number of blocks reserved for the super user (high 32bits). */ + uint32_t cBlocksRsvdForSuperUserHigh; + /** 0x158: Total number of free blocks (high 32bits). */ + uint32_t cBlocksFreeHigh; + /** 0x15c: All inodes have at least this number of bytes. */ + uint16_t cbInodesExtraMin; + /** 0x15e: New inodes should reserve this number of bytes. */ + uint16_t cbNewInodesRsv; + /** 0x160: Miscellaneous flags (EXT_SB_F_XXX). */ + uint32_t fFlags; + /** 0x164: RAID stride, number of logical blocks read from or written to the disk + * before moving to the next disk. */ + uint16_t cRaidStride; + /** 0x166: Number of seconds between multi-mount prevention checking. */ + uint16_t cSecMmpInterval; + /** 0x168: Block number for the multi-mount protection data. */ + uint64_t iMmpBlock; + /** 0x170: Raid stride width. */ + uint32_t cRaidStrideWidth; + /** 0x174: Size of a flexible block group (calculated as 2^cLogGroupsPerFlex). */ + uint8_t cLogGroupsPerFlex; + /** 0x175: Metadata checksum algorithm type, only 1 is valid (for CRC32c). */ + uint8_t u8ChksumType; + /** 0x176: Padding. */ + uint16_t u16Padding; + /** 0x178: Number of KiB written to the filesystem so far. */ + uint64_t cKbWritten; + /** 0x180: Inode number of active snapshot. */ + uint32_t iSnapshotInode; + /** 0x184: Sequential ID of active snapshot. */ + uint32_t iSnapshotId; + /** 0x188: Number of blocks reserved for activ snapshot's future use. */ + uint64_t cSnapshotRsvdBlocks; + /** 0x190: Inode number of the head of the on-disk snapshot list. */ + uint32_t iSnapshotListInode; + /** 0x194: Number of errors seen so far. */ + uint32_t cErrorsSeen; + /** 0x198: First time an error happened in seconds since epoch. */ + uint32_t u32TimeFirstError; + /** 0x19c: Inode involved in the first error. */ + uint32_t iInodeFirstError; + /** 0x1a0: Number of block involved of first error. */ + uint64_t iBlkFirstError; + /** 0x1a8: Name of the function where the first error happened. */ + char achFuncFirstError[32]; + /** 0x1c8: Line number where the error happened. */ + uint32_t iLineFirstError; + /** 0x1cc: Time of the most receent error in seconds since epoch. */ + uint32_t u32TimeLastError; + /** 0x1d0: Inode involved in the most recent error. */ + uint32_t iInodeLastError; + /** 0x1d4: Line number where the most recent error happened. */ + uint32_t iLineLastError; + /** 0x1d8: Number of block involved of most recent error. */ + uint64_t iBlkLastError; + /** 0x1e0: Name of the function where the most recent error happened. */ + char achFuncLastError[32]; + /** 0x200: ASCIIz string of mount options. */ + char aszMntOpts[64]; + /** 0x240: Inode number of user quota file. */ + uint32_t iInodeUsrQuota; + /** 0x244: Inode number of group quota file. */ + uint32_t iInodeGrpQuota; + /** 0x248: Overhead blocks/clusters in filesystem. */ + uint32_t cOverheadBlocks; + /** 0x24c: Block groups containing superblock backups. */ + uint32_t aiBlkGrpSbBackups[2]; + /** 0x254: Encryption algorithms in use (EXT_SB_ENCRYPT_ALGO_XXX). */ + uint8_t au8EncryptAlgo[4]; + /** 0x258: Salt for the string2key algorithm for encryption. */ + uint8_t abEncryptPwSalt[16]; + /** 0x268: Inode number of lost+found. */ + uint32_t iInodeLostFound; + /** 0x26c: Inode that tracks project quotas. */ + uint32_t iInodeProjQuota; + /** 0x270: Checksum seed used for the metadata checksum calculations. + * Should be crc32c(~0, au8Uuid). */ + uint32_t u32ChksumSeed; + /** 0x274: Upper 8bits of the u32LastWrittenTime field. */ + uint8_t u32LastWrittenTimeHigh8Bits; + /** 0x275: Upper 8bits of the u32LastMountTime field. */ + uint8_t u32LastMountTimeHigh8Bits; + /** 0x276: Upper 8bits of the u32TimeFsCreation field. */ + uint8_t u32TimeFsCreationHigh8Bits; + /** 0x277: Upper 8bits of the u32LastCheckTime field. */ + uint8_t u32LastCheckTimeHigh8Bits; + /** 0x278: Upper 8bits of the u32TimeFirstError field. */ + uint8_t u32TimeFirstErrorHigh8Bits; + /** 0x279: Upper 8bits of the u32TimeLastError field. */ + uint8_t u32TimeLastErrorHigh8Bits; + /** 0x27a: Zero padding. */ + uint8_t au8Padding[2]; + /** 0x27c: Padding to the end of the block. */ + uint32_t au32Rsvd[96]; + /** 0x3fc: Superblock checksum. */ + uint32_t u32Chksum; +} EXTSUPERBLOCK; +AssertCompileMemberOffset(EXTSUPERBLOCK, u16UidReservedBlocks, 0x50); +AssertCompileMemberOffset(EXTSUPERBLOCK, u32AlgoUsageBitmap, 0xc8); +AssertCompileMemberOffset(EXTSUPERBLOCK, iJournalInode, 0xe0); +AssertCompileMemberOffset(EXTSUPERBLOCK, u8HashVersionDef, 0xfc); +AssertCompileMemberOffset(EXTSUPERBLOCK, fMntOptsDef, 0x100); +AssertCompileMemberOffset(EXTSUPERBLOCK, iBlkLastError, 0x1d8); +AssertCompileMemberOffset(EXTSUPERBLOCK, iInodeLostFound, 0x268); +AssertCompileSize(EXTSUPERBLOCK, 1024); +/** Pointer to an ext super block. */ +typedef EXTSUPERBLOCK *PEXTSUPERBLOCK; +/** Pointer to a const ext super block. */ +typedef EXTSUPERBLOCK const *PCEXTSUPERBLOCK; + +/** Ext signature. */ +#define EXT_SB_SIGNATURE UINT16_C(0xef53) + +/** @name EXT_SB_STATE_XXX - Filesystem state + * @{ */ +/** Clean filesystem state. */ +#define EXT_SB_STATE_CLEAN UINT16_C(0x0001) +/** Error filesystem state. */ +#define EXT_SB_STATE_ERRORS UINT16_C(0x0002) +/** Orphans being recovered state. */ +#define EXT_SB_STATE_ORPHANS_RECOVERING UINT16_C(0x0004) +/** @} */ + +/** @name EXT_SB_OS_ID_CREATOR_XXX - Filesystem creator + * @{ */ +/** Linux. */ +#define EXT_SB_OS_ID_CREATOR_LINUX 0 +/** Hurd. */ +#define EXT_SB_OS_ID_CREATOR_HURD 1 +/** Masix. */ +#define EXT_SB_OS_ID_CREATOR_MASIX 2 +/** FreeBSD. */ +#define EXT_SB_OS_ID_CREATOR_FREEBSD 3 +/** Lites. */ +#define EXT_SB_OS_ID_CREATOR_LITES 4 +/** @} */ + +/** @name EXT_SB_REV_XXX - Superblock revision + * @{ */ +/** Original format (ext2). */ +#define EXT_SB_REV_ORIG 0 +/** Inodes have dynmic sizes. */ +#define EXT_SB_REV_V2_DYN_INODE_SZ 1 +/** @} */ + +/** @name EXT_SB_FEAT_COMPAT_XXX - Compatible features which can be ignored when set + * and not being supported. + * @{ */ +/** Directories can be preallocated. */ +#define EXT_SB_FEAT_COMPAT_DIR_PREALLOC RT_BIT_32(0) +/** Some sort of "imagic" inodes. */ +#define EXT_SB_FEAT_COMPAT_IMAGIC_INODES RT_BIT_32(1) +/** Filesystem has a journal. */ +#define EXT_SB_FEAT_COMPAT_HAS_JOURNAL RT_BIT_32(2) +/** Filesystem supports extended attributes. */ +#define EXT_SB_FEAT_COMPAT_EXT_ATTR RT_BIT_32(3) +/** Filesystem contains reserved group descriptor blocks for filesystem expansion. */ +#define EXT_SB_FEAT_COMPAT_RESIZE_INODE RT_BIT_32(4) +/** Filesystem contains directory indices. */ +#define EXT_SB_FEAT_COMPAT_DIR_INDEX RT_BIT_32(5) +/** Lazy block group - not used. */ +#define EXT_SB_FEAT_COMPAT_LAZY_BG RT_BIT_32(6) +/** Exclude inode - not used. */ +#define EXT_SB_FEAT_COMPAT_EXCLUDE_INODE RT_BIT_32(7) +/** Exclude bitmap - not used. */ +#define EXT_SB_FEAT_COMPAT_EXCLUDE_BITMAP RT_BIT_32(8) +/** Sparse super blocks, super block contains pointers to block groups + * containing backups of the superblock. */ +#define EXT_SB_FEAT_COMPAT_SPARSE_SUPER2 RT_BIT_32(9) +/** @} */ + +/** @name EXT_SB_FEAT_INCOMPAT_XXX - Incompatible features which cause a mounting + * error when set and not being supported. + * @{ */ +/** Filesystem contains compressed files. */ +#define EXT_SB_FEAT_INCOMPAT_COMPRESSION RT_BIT_32(0) +/** Directory entries contain a file type. */ +#define EXT_SB_FEAT_INCOMPAT_DIR_FILETYPE RT_BIT_32(1) +/** Filesystem needs recovery. */ +#define EXT_SB_FEAT_INCOMPAT_RECOVER RT_BIT_32(2) +/** The journal is recorded on a separate device. */ +#define EXT_SB_FEAT_INCOMPAT_JOURNAL_DEV RT_BIT_32(3) +/** Filesystem uses meta block groups. */ +#define EXT_SB_FEAT_INCOMPAT_META_BG RT_BIT_32(4) +/** Files in the filesystem use extents. */ +#define EXT_SB_FEAT_INCOMPAT_EXTENTS RT_BIT_32(6) +/** Filesystem uses 64bit offsets. */ +#define EXT_SB_FEAT_INCOMPAT_64BIT RT_BIT_32(7) +/** Filesystem requires multiple mount preotection. */ +#define EXT_SB_FEAT_INCOMPAT_MMP RT_BIT_32(8) +/** Filesystem uses flexible block groups. */ +#define EXT_SB_FEAT_INCOMPAT_FLEX_BG RT_BIT_32(9) +/** Inodes can be used to store large extended attribute values. */ +#define EXT_SB_FEAT_INCOMPAT_EXT_ATTR_INODE RT_BIT_32(10) +/** Data is contained in directory entries. */ +#define EXT_SB_FEAT_INCOMPAT_DIRDATA RT_BIT_32(12) +/** Metadata checksum seed is stored in the super block. */ +#define EXT_SB_FEAT_INCOMPAT_CSUM_SEED RT_BIT_32(13) +/** Directories can be larger than 2GiB or contain a 3-level HTree. */ +#define EXT_SB_FEAT_INCOMPAT_LARGE_DIR RT_BIT_32(14) +/** Data is inlined in the inode. */ +#define EXT_SB_FEAT_INCOMPAT_INLINE_DATA RT_BIT_32(15) +/** Encrypted inodes are present on the filesystem. */ +#define EXT_SB_FEAT_INCOMPAT_ENCRYPT RT_BIT_32(16) +/** @} */ + +/** @name EXT_SB_FEAT_COMPAT_RO_XXX - Backward compatible features when mounted readonly + * @{ */ +/** Sparse superblocks. */ +#define EXT_SB_FEAT_COMPAT_RO_SPARSE_SUPER RT_BIT_32(0) +/** There is at least one large file (> 2GiB). */ +#define EXT_SB_FEAT_COMPAT_RO_LARGE_FILE RT_BIT_32(1) +/** Actually not used in the Linux kernel and e2fprogs. */ +#define EXT_SB_FEAT_COMPAT_RO_BTREE_DIR RT_BIT_32(2) +/** Filesystem contains files which sizes are not represented as a multiple of 512 byte sectors + * but logical blocks instead. */ +#define EXT_SB_FEAT_COMPAT_RO_HUGE_FILE RT_BIT_32(3) +/** Group descriptors have checksums embedded */ +#define EXT_SB_FEAT_COMPAT_RO_GDT_CHSKUM RT_BIT_32(4) +/** Subdirectory limit of 32000 doesn't apply. The link count is set to 1 if beyond 64999. */ +#define EXT_SB_FEAT_COMPAT_RO_DIR_NLINK RT_BIT_32(5) +/** Inodes can contain extra data. */ +#define EXT_SB_FEAT_COMPAT_RO_EXTRA_INODE_SZ RT_BIT_32(6) +/** There is at least one snapshot on the filesystem. */ +#define EXT_SB_FEAT_COMPAT_RO_HAS_SNAPSHOTS RT_BIT_32(7) +/** Quotas are enabled for this filesystem. */ +#define EXT_SB_FEAT_COMPAT_RO_QUOTA RT_BIT_32(8) +/** The bigalloc feature is enabled, file extents are tracked in units of clusters + * instead of blocks. */ +#define EXT_SB_FEAT_COMPAT_RO_BIGALLOC RT_BIT_32(9) +/** Metadata contains checksums. */ +#define EXT_SB_FEAT_COMPAT_RO_METADATA_CHKSUM RT_BIT_32(10) +/** Filesystem supports replicas. */ +#define EXT_SB_FEAT_COMPAT_RO_REPLICA RT_BIT_32(11) +/** Filesystem is readonly. */ +#define EXT_SB_FEAT_COMPAT_RO_READONLY RT_BIT_32(12) +/** Filesystem tracks project quotas. */ +#define EXT_SB_FEAT_COMPAT_RO_PROJECT RT_BIT_32(13) +/** @} */ + +/** @name EXT_SB_HASH_VERSION_DEF_XXX - Default hash algorithm used + * @{ */ +/** Legacy. */ +#define EXT_SB_HASH_VERSION_DEF_LEGACY 0 +/** Half MD4. */ +#define EXT_SB_HASH_VERSION_DEF_HALF_MD4 1 +/** Tea. */ +#define EXT_SB_HASH_VERSION_DEF_TEA 2 +/** Unsigned legacy. */ +#define EXT_SB_HASH_VERSION_DEF_LEGACY_UNSIGNED 3 +/** Unsigned half MD4. */ +#define EXT_SB_HASH_VERSION_DEF_HALF_MD4_UNSIGNED 4 +/** Unsigned tea. */ +#define EXT_SB_HASH_VERSION_DEF_TEA_UNSIGNED 5 +/** @} */ + +/** @name EXT_SB_MNT_OPTS_DEF_XXX - Default mount options + * @{ */ +/** Print debugging information on (re)mount. */ +#define EXT_SB_MNT_OPTS_DEF_DEBUG RT_BIT_32(0) +/** Created files take the group ID ofthe containing directory. */ +#define EXT_SB_MNT_OPTS_DEF_BSDGROUPS RT_BIT_32(1) +/** Support userspace extended attributes. */ +#define EXT_SB_MNT_OPTS_DEF_XATTR_USER RT_BIT_32(2) +/** Support POSIX access control lists. */ +#define EXT_SB_MNT_OPTS_DEF_ACL RT_BIT_32(3) +/** Do not support 32bit UIDs. */ +#define EXT_SB_MNT_OPTS_DEF_UID16 RT_BIT_32(4) +/** All data and metadata are committed to the journal. */ +#define EXT_SB_MNT_OPTS_DEF_JMODE_DATA RT_BIT_32(5) +/** All data are flushed to the disk before metadata are committed to the journal. */ +#define EXT_SB_MNT_OPTS_DEF_JMODE_ORDERED RT_BIT_32(6) +/** Data ordering not preserved, data may be written after metadata has been written. */ +#define EXT_SB_MNT_OPTS_DEF_JMODE_WBACK (EXT_SB_MNT_OPTS_DEF_JMODE_DATA | EXT_SB_MNT_OPTS_DEF_JMODE_ORDERED) +/** No write flushes. */ +#define EXT_SB_MNT_OPTS_DEF_NOBARRIER RT_BIT_32(8) +/** Track metadata blocks on the filesystem not being used as data blocks. */ +#define EXT_SB_MNT_OPTS_DEF_BLOCK_VALIDITY RT_BIT_32(9) +/** Enables TRIM/DISCARD support. */ +#define EXT_SB_MNT_OPTS_DEF_DISCARD RT_BIT_32(10) +/** Disable delayed allocation. */ +#define EXT_SB_MNT_OPTS_DEF_NODELALLOC RT_BIT_32(11) +/** @} */ + +/** @name EXT_SB_F_XXX - Superblock flags + * @{ */ +/** Signed directory hash used. */ +#define EXT_SB_F_SIGNED_DIR_HASH RT_BIT_32(0) +/** Unsigned directory hash used. */ +#define EXT_SB_F_UNSIGNED_DIR_HASH RT_BIT_32(1) +/** Only used to test development code. */ +#define EXT_SB_F_DEV_CODE RT_BIT_32(3) +/** @} */ + +/** @name EXT_SB_ENCRYPT_ALGO_XXX - Group descriptor flags + * @{ */ +/** Invalid encryption algorithm. */ +#define EXT_SB_ENCRYPT_ALGO_INVALID 0 +/** 256-bit AES in XTS mode. */ +#define EXT_SB_ENCRYPT_ALGO_256BIT_AES_XTS 1 +/** 256-bit AES in GCM mode. */ +#define EXT_SB_ENCRYPT_ALGO_256BIT_AES_GCM 2 +/** 256-bit AES in CBC mode. */ +#define EXT_SB_ENCRYPT_ALGO_256BIT_AES_CBC 3 +/** @} */ + + +/** + * Block group descriptor (32byte version). + */ +typedef struct EXTBLOCKGROUPDESC32 +{ + /** 0x00: Block address of the block bitmap (low 32bits). */ + uint32_t offBlockBitmapLow; + /** 0x04: Block address of the inode bitmap (low 32bits). */ + uint32_t offInodeBitmapLow; + /** 0x08: Start block address of the inode table (low 32bits). */ + uint32_t offInodeTableLow; + /** 0x0c: Number of unallocated blocks in group (low 16bits). */ + uint16_t cBlocksFreeLow; + /** 0x0e: Number of unallocated inodes in group (low 16bits). */ + uint16_t cInodesFreeLow; + /** 0x10: Number of directories in the group (low 16bits). */ + uint16_t cDirectoriesLow; + /** 0x12: Flags (EXT_GROUP_DESC_F_XXX). */ + uint16_t fFlags; + /** 0x14: Location of snapshot exclusion bitmap (lower 32bits) */ + uint32_t offSnapshotExclBitmapLow; + /** 0x18: Block bitmap checksum (lower 16bits). */ + uint16_t u16ChksumBlockBitmapLow; + /** 0x1a: Inode bitmap checksum (lower 16bits). */ + uint16_t u16ChksumInodeBitmapLow; + /** 0x1c: Unused inode entry count in the groups inode table (lower 16bits).*/ + uint16_t cInodeTblUnusedLow; + /** 0x1e: Group descriptor checksum. */ + uint16_t u16Chksum; +} EXTBLOCKGROUPDESC32; +AssertCompileSize(EXTBLOCKGROUPDESC32, 32); +/** Pointer to an ext block group descriptor. */ +typedef EXTBLOCKGROUPDESC32 *PEXTBLOCKGROUPDESC32; +/** Pointer to a const 32 byte block group descriptor. */ +typedef const EXTBLOCKGROUPDESC32 *PCEXTBLOCKGROUPDESC32; + + +/** + * Block group descriptor (64byte version). + */ +typedef struct EXTBLOCKGROUPDESC64 +{ + /** 0x00: Embedded 32 byte descriptor. */ + EXTBLOCKGROUPDESC32 v32; + /** 0x20: Location of block bitmap (upper 32bits). */ + uint32_t offBlockBitmapHigh; + /** 0x24: Location of inode bitmap (upper 32bits). */ + uint32_t offInodeBitmapHigh; + /** 0x28: Location of inode table (upper 32bits). */ + uint32_t offInodeTableHigh; + /** 0x2c: Number of unallocated blocks (upper 16bits). */ + uint16_t cBlocksFreeHigh; + /** 0x2e: Number of unallocated inodes (upper 16bits). */ + uint16_t cInodesFreeHigh; + /** 0x30: Number of directories in the group (upper 16bits). */ + uint16_t cDirectoriesHigh; + /** 0x32: Unused inode entry count in the groups inode table (upper 16bits).*/ + uint16_t cInodeTblUnusedHigh; + /** 0x34: Location of snapshot exclusion bitmap (upper 32bits) */ + uint32_t offSnapshotExclBitmapHigh; + /** 0x38: Block bitmap checksum (upper 16bits). */ + uint16_t u16ChksumBlockBitmapHigh; + /** 0x3a: Inode bitmap checksum (upper 16bits). */ + uint16_t u16ChksumInodeBitmapHigh; + /** 0x3c: Padding to 64 bytes. */ + uint32_t u64Padding; +} EXTBLOCKGROUPDESC64; +AssertCompileSize(EXTBLOCKGROUPDESC64, 64); +/** Pointer to an ext block group descriptor. */ +typedef EXTBLOCKGROUPDESC64 *PEXTBLOCKGROUPDESC64; +/** Pointer to a const 64 byte block group descriptor. */ +typedef const EXTBLOCKGROUPDESC64 *PCEXTBLOCKGROUPDESC64; + +/** @name EXT_GROUP_DESC_F_XXX - Group descriptor flags + * @{ */ +/** Inode table and bitmaps are not initialized. */ +#define EXT_GROUP_DESC_F_INODE_UNINIT RT_BIT(0) +/** Block bitmap is not initialized. */ +#define EXT_GROUP_DESC_F_BLOCK_UNINIT RT_BIT(1) +/** Inode table is zeroed. */ +#define EXT_GROUP_DESC_F_INODE_ZEROED RT_BIT(2) +/** @} */ + + +/** + * Combiend view of the different block gorup descriptor versions. + */ +typedef union EXTBLOCKGROUPDESC +{ + /** 32 byte version. */ + EXTBLOCKGROUPDESC32 v32; + /** 64 byte version. */ + EXTBLOCKGROUPDESC64 v64; + /** Byte view. */ + uint8_t au8[64]; +} EXTBLOCKGROUPDESC; +/** Poiner to a unified block gorup descriptor view. */ +typedef EXTBLOCKGROUPDESC *PEXTBLOCKGROUPDESC; +/** Poiner to a const unified block gorup descriptor view. */ +typedef const EXTBLOCKGROUPDESC *PCEXTBLOCKGROUPDESC; + + +/** Number of block entries in the inodes block map. */ +#define EXT_INODE_BLOCK_ENTRIES 15 + +/** + * Inode table entry (standard 128 byte version). + */ +typedef struct EXTINODE +{ + /** 0x00: File mode (EXT_INODE_FILE_MODE_XXX). */ + uint16_t fMode; + /** 0x02: Owner UID (lower 16bits). */ + uint16_t uUidLow; + /** 0x04: Size in bytes (lower 32bits). */ + uint32_t cbSizeLow; + /** 0x08: Last access time in seconds since epoch. */ + uint32_t u32TimeLastAccess; + /** 0x0c: Last inode change time in seconds since epoch. */ + uint32_t u32TimeLastChange; + /** 0x10: Last data modification time in seconds since epoch. */ + uint32_t u32TimeLastModification; + /** 0x14: Deletion time in seconds since epoch. */ + uint32_t u32TimeDeletion; + /** 0x18: Group ID (lower 16bits). */ + uint16_t uGidLow; + /** 0x1a: Hard link count. */ + uint16_t cHardLinks; + /** 0x1c: Block count (lower 32bits). */ + uint32_t cBlocksLow; + /** 0x20: Inode flags. */ + uint32_t fFlags; + /** 0x24: Operating system dependent data. */ + union + { + /** Linux: Inode version. */ + uint32_t u32LnxVersion; + } Osd1; + /** 0x28: Block map or extent tree. */ + uint32_t au32Block[EXT_INODE_BLOCK_ENTRIES]; + /** 0x64: File version. */ + uint32_t u32Version; + /** 0x68: Extended attribute control block (lower 32bits). */ + uint32_t offExtAttrLow; + /** 0x6c: File/directory size (upper 32bits). */ + uint32_t cbSizeHigh; + /** 0x70: Fragment address (obsolete). */ + uint32_t u32FragmentAddrObs; + /** 0x74: Operating system dependent data 2. */ + union + { + /** Linux related data. */ + struct + { + /** 0x00: Block count (upper 16bits). */ + uint16_t cBlocksHigh; + /** 0x02: Extended attribute block location (upper 16bits). */ + uint16_t offExtAttrHigh; + /** 0x04: Owner UID (upper 16bits). */ + uint16_t uUidHigh; + /** 0x06: Group ID (upper 16bits). */ + uint16_t uGidHigh; + /** 0x08: Inode checksum (lower 16bits). */ + uint16_t u16ChksumLow; + /** 0x0a: Reserved */ + uint16_t u16Rsvd; + } Lnx; + } Osd2; +} EXTINODE; +AssertCompileSize(EXTINODE, 128); +/** Pointer to an inode. */ +typedef EXTINODE *PEXTINODE; +/** Pointer to a const inode. */ +typedef const EXTINODE *PCEXTINODE; + + +/** + * Extra inode data (coming right behind the fixed inode data). + */ +typedef struct EXTINODEEXTRA +{ + /** 0x80: Size of the extra inode data in bytes. */ + uint16_t cbInodeExtra; + /** 0x82: Inode checksum (upper 16bits.) */ + uint16_t u16ChksumHigh; + /** 0x84: Last inode change time, extra time bits for sub-second precision. */ + uint32_t u32ExtraTimeLastChange; + /** 0x88: Last data modification time, extra time bits for sub-second precision. */ + uint32_t u32ExtraTimeLastModification; + /** 0x8c: Last access time, extra time bits for sub-second precision. */ + uint32_t u32ExtraTimeLastAccess; + /** 0x90: File creation time in seconds since epoch. */ + uint32_t u32TimeCreation; + /** 0x94: File creation time, extra time bits for sub-second precision. */ + uint32_t u32ExtraTimeCreation; + /** 0x98: Version number (upper 32bits). */ + uint32_t u32VersionHigh; + /** 0x9c: Project ID. */ + uint32_t u32ProjectId; +} EXTINODEEXTRA; +/** Pointer to extra inode data. */ +typedef EXTINODEEXTRA *PEXTINODEEXTRA; +/** Pointer to a const extra inode data. */ +typedef const EXTINODEEXTRA *PCEXTINODEEXTRA; + + +/** + * Combined inode data. + */ +typedef struct EXTINODECOMB +{ + /** Core inode structure. */ + EXTINODE Core; + /** Any extra inode data which might be present. */ + EXTINODEEXTRA Extra; +} EXTINODECOMB; +/** Pointer to combined inode data. */ +typedef EXTINODECOMB *PEXTINODECOMB; +/** Pointer to a const combined inode data. */ +typedef const EXTINODECOMB *PCEXTINODECOMB; + + + +/** @name EXT_INODE_MODE_XXX - File mode + * @{ */ +/** Others can execute the file. */ +#define EXT_INODE_MODE_EXEC_OTHER RT_BIT(0) +/** Others can write to the file. */ +#define EXT_INODE_MODE_WRITE_OTHER RT_BIT(1) +/** Others can read the file. */ +#define EXT_INODE_MODE_READ_OTHER RT_BIT(2) +/** Members of the same group can execute the file. */ +#define EXT_INODE_MODE_EXEC_GROUP RT_BIT(3) +/** Members of the same group can write to the file. */ +#define EXT_INODE_MODE_WRITE_GROUP RT_BIT(4) +/** Members of the same group can read the file. */ +#define EXT_INODE_MODE_READ_GROUP RT_BIT(5) +/** Owner can execute the file. */ +#define EXT_INODE_MODE_EXEC_OWNER RT_BIT(6) +/** Owner can write to the file. */ +#define EXT_INODE_MODE_WRITE_OWNER RT_BIT(7) +/** Owner can read the file. */ +#define EXT_INODE_MODE_READ_OWNER RT_BIT(8) +/** Sticky file mode. */ +#define EXT_INODE_MODE_STICKY RT_BIT(9) +/** File is set GID. */ +#define EXT_INODE_MODE_SET_GROUP_ID RT_BIT(10) +/** File is set UID. */ +#define EXT_INODE_MODE_SET_USER_ID RT_BIT(11) +/** @} */ + +/** @name EXT_INODE_MODE_TYPE_XXX - File type + * @{ */ +/** Inode represents a FIFO. */ +#define EXT_INODE_MODE_TYPE_FIFO UINT16_C(0x1000) +/** Inode represents a character device. */ +#define EXT_INODE_MODE_TYPE_CHAR UINT16_C(0x2000) +/** Inode represents a directory. */ +#define EXT_INODE_MODE_TYPE_DIR UINT16_C(0x4000) +/** Inode represents a block device. */ +#define EXT_INODE_MODE_TYPE_BLOCK UINT16_C(0x6000) +/** Inode represents a regular file. */ +#define EXT_INODE_MODE_TYPE_REGULAR UINT16_C(0x8000) +/** Inode represents a symlink. */ +#define EXT_INODE_MODE_TYPE_SYMLINK UINT16_C(0xa000) +/** Inode represents a socket. */ +#define EXT_INODE_MODE_TYPE_SOCKET UINT16_C(0xc000) +/** Returns the inode type from the combined mode field. */ +#define EXT_INODE_MODE_TYPE_GET_TYPE(a_Mode) ((a_Mode) & 0xf000) +/** @} */ + +/** @name EXT_INODE_F_XXX - Inode flags + * @{ */ +/** Inode requires secure erase on deletion. */ +#define EXT_INODE_F_SECURE_ERASE RT_BIT_32(0) +/** Inode should be preserved for undeletion during deletion. */ +#define EXT_INODE_F_UNDELETE RT_BIT_32(1) +/** Inode contains compressed data. */ +#define EXT_INODE_F_COMPRESSED RT_BIT_32(2) +/** All writes to this inode must be synchronous. */ +#define EXT_INODE_F_SYNCHRONOUS RT_BIT_32(3) +/** Inode is immutable. */ +#define EXT_INODE_F_IMMUTABLE RT_BIT_32(4) +/** Inode is append only. */ +#define EXT_INODE_F_APPEND_ONLY RT_BIT_32(5) +/** Inode should not be dumped via dump(1). */ +#define EXT_INODE_F_NO_DUMP RT_BIT_32(6) +/** Access time is not updated. */ +#define EXT_INODE_F_NO_ACCESS_TIME RT_BIT_32(7) +/** Dirty compressed file. */ +#define EXT_INODE_F_DIRTY_COMPRESSED RT_BIT_32(8) +/** Inode has one or more compressed clusters. */ +#define EXT_INODE_F_COMPRESSED_BLOCK RT_BIT_32(9) +/** Inode should not be compressed. */ +#define EXT_INODE_F_NO_COMPRESSION RT_BIT_32(10) +/** Inode is encrypted. */ +#define EXT_INODE_F_ENCRYPTED RT_BIT_32(11) +/** Directory has hashed indexes. */ +#define EXT_INODE_F_DIR_HASHED_INDEX RT_BIT_32(12) +/** AFS magic directory. */ +#define EXT_INODE_F_IMAGIC RT_BIT_32(13) +/** Data must always be written through the journal. */ +#define EXT_INODE_F_JOURNAL_DATA RT_BIT_32(14) +/** File tail should not be merged. */ +#define EXT_INODE_F_NOTAIL RT_BIT_32(15) +/** All directory entry data should be written synchronously. */ +#define EXT_INODE_F_DIR_SYNCHRONOUS RT_BIT_32(16) +/** Top of directory hierarchy. */ +#define EXT_INODE_F_TOP_DIRECTORY RT_BIT_32(17) +/** Inode is a huge file. */ +#define EXT_INODE_F_HUGE_FILE RT_BIT_32(18) +/** Inode uses extents. */ +#define EXT_INODE_F_EXTENTS RT_BIT_32(19) +/** Inode stores a large extended attribute value in its data blocks. */ +#define EXT_INODE_F_EXT_ATTR_INODE RT_BIT_32(20) +/** File has blocks allocated past end of file. */ +#define EXT_INODE_F_ALLOC_BLOCKS_EOF RT_BIT_32(21) +/** Inode is a snapshot. */ +#define EXT_INODE_F_SNAPSHOT RT_BIT_32(22) +/** Snapshot is being deleted. */ +#define EXT_INODE_F_SNAPSHOT_DELETED RT_BIT_32(23) +/** Snapshot shrink has completed. */ +#define EXT_INODE_F_SNAPSHOT_SHRUNK RT_BIT_32(24) +/** Inode contains inline data. */ +#define EXT_INODE_F_INLINE_DATA RT_BIT_32(25) +/** Children are created with the same project ID. */ +#define EXT_INODE_F_PROJECT_ID_INHERIT RT_BIT_32(26) +/** Reserved for ext4 library. */ +#define EXT_INODE_F_RESERVED_LIBRARY RT_BIT_32(27) +/** @} */ + + +/** + * Extent tree header. + */ +typedef struct EXTEXTENTHDR +{ + /** 0x00: Magic number for identification. */ + uint16_t u16Magic; + /** 0x02: Number of valid entries following. */ + uint16_t cEntries; + /** 0x04: Maxmimum number of entries that could follow. */ + uint16_t cMax; + /** 0x06: Depth of this extent node in the tree. */ + uint16_t uDepth; + /** 0x08: Generation of the tree (not used by standard ext4). */ + uint32_t cGeneration; +} EXTEXTENTHDR; +AssertCompileSize(EXTEXTENTHDR, 12); +/** Pointer to a extent tree header. */ +typedef EXTEXTENTHDR *PEXTEXTENTHDR; +/** Pointer to a const extent tree header. */ +typedef const EXTEXTENTHDR *PCEXTEXTENTHDR; + +/** Magic number identifying an extent header. */ +#define EXT_EXTENT_HDR_MAGIC UINT16_C(0xf30a) +/** Maximum depth an extent header can have. */ +#define EXT_EXTENT_HDR_DEPTH_MAX UINT16_C(5) + + +/** + * Extent tree index node. + */ +typedef struct EXTEXTENTIDX +{ + /** 0x00: Start file block this node covers. */ + uint32_t iBlock; + /** 0x04: Block number of child extent node (lower 32bits). */ + uint32_t offChildLow; + /** 0x08: Block number of child extent node (upper 16bits). */ + uint16_t offChildHigh; + /** 0x0a: Reserved. */ + uint16_t u16Rsvd; +} EXTEXTENTIDX; +AssertCompileSize(EXTEXTENTIDX, 12); +/** Pointer to an extent tree index node. */ +typedef EXTEXTENTIDX *PEXTEXTENTIDX; +/** Pointer to a const extent tree index node. */ +typedef const EXTEXTENTIDX *PCEXTEXTENTIDX; + + +/** + * Extent tree leaf node. + */ +typedef struct EXTEXTENT +{ + /** 0x00: First file block number this extent covers. */ + uint32_t iBlock; + /** 0x04: Number of blocks covered by this extent. */ + uint16_t cBlocks; + /** 0x06: Block number this extent points to (upper 32bits). */ + uint16_t offStartHigh; + /** 0x08: Block number this extent points to (lower 32bits). */ + uint32_t offStartLow; +} EXTEXTENT; +AssertCompileSize(EXTEXTENT, 12); +/** Pointer to a leaf node. */ +typedef EXTEXTENT *PEXTEXTENT; +/** Pointer to a const leaf node. */ +typedef const EXTEXTENT *PCEXTEXTENT; + +/** Length field limit for a populated extent, fields greater than that limit indicate a sparse extent. */ +#define EXT_EXTENT_LENGTH_LIMIT UINT16_C(32768) + + +/** + * Directory entry. + */ +typedef struct EXTDIRENTRY +{ + /** 0x00: Inode number being referenced by this entry. */ + uint32_t iInodeRef; + /** 0x04: Record length of this directory entry in bytes (multiple of 4). */ + uint16_t cbRecord; + /** 0x06: Version dependent data. */ + union + { + /** Original. */ + struct + { + /** Name length in bytes (maximum 255). */ + uint16_t cbName; + } v1; + /** Version 2. */ + struct + { + /** Name length in bytes (maximum 255). */ + uint8_t cbName; + /** File type (EXT_DIRENTRY_TYPE_XXX). */ + uint8_t uType; + } v2; + } u; + /** 0x08: File name - variable in size. */ + char achName[1]; +} EXTDIRENTRY; +/** Pointer to a directory entry. */ +typedef EXTDIRENTRY *PEXTDIRENTRY; +/** Poiner to a const directory entry. */ +typedef const EXTDIRENTRY *PCEXTDIRENTRY; + + +/** + * Extended directory entry with the maximum size (263 bytes). + */ +#pragma pack(1) +typedef union EXTDIRENTRYEX +{ + /** The directory entry. */ + EXTDIRENTRY Core; + /** The byte view. */ + uint8_t au8[263]; +} EXTDIRENTRYEX; +#pragma pack() +AssertCompileSize(EXTDIRENTRYEX, 263); +/** Pointer to an extended directory entry. */ +typedef EXTDIRENTRYEX *PEXTDIRENTRYEX; +/** Pointer to a const extended directory entry. */ +typedef const EXTDIRENTRYEX *PCEXTDIRENTRYEX; + + +/** @name EXT_DIRENTRY_TYPE_XXX - file type + * @{ */ +/** Entry is of unknown file type. */ +#define EXT_DIRENTRY_TYPE_UNKNOWN 0 +/** Entry is regular file. */ +#define EXT_DIRENTRY_TYPE_REGULAR 1 +/** Entry is another directory. */ +#define EXT_DIRENTRY_TYPE_DIRECTORY 2 +/** Entry is a character device. */ +#define EXT_DIRENTRY_TYPE_CHAR 3 +/** Entry is a block device. */ +#define EXT_DIRENTRY_TYPE_BLOCK 4 +/** Entry is a FIFO. */ +#define EXT_DIRENTRY_TYPE_FIFO 5 +/** Entry is a socket. */ +#define EXT_DIRENTRY_TYPE_SOCKET 6 +/** Entry is a symlink. */ +#define EXT_DIRENTRY_TYPE_SYMLINK 7 +/** Entry is a checksum and uses EXTDIRENTRYCHKSUM. */ +#define EXT_DIRENTRY_TYPE_CHKSUM 0xde +/** @} */ + + +/** + * Tail directory entry (for checksumming). + */ +typedef struct EXTDIRENTRYCHKSUM +{ + /** 0x00: Reserved, must be 0 (overlays with EXTDIRENTRY::iNodeRef). */ + uint32_t u32Rsvd; + /** 0x04: Record length (must be 12). */ + uint16_t cbRecord; + /** 0x06: Reserved (overlays with EXTDIRENTRY::u::v1::cbName). */ + uint8_t u8Rsvd; + /** 0x07: File type (must be 0xde). */ + uint8_t uType; + /** 0x08: Checksum. */ + uint32_t u32Chksum; +} EXTDIRENTRYCHKSUM; +/** Pointer to a tail directory entry. */ +typedef EXTDIRENTRYCHKSUM *PEXTDIRENTRYCHKSUM; +/** Pointer to const tail directory entry. */ +typedef const EXTDIRENTRYCHKSUM *PCEXTDIRENTRYCHKSUM; + + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_ext_h */ + diff --git a/include/iprt/formats/fat.h b/include/iprt/formats/fat.h new file mode 100644 index 00000000..d55c0957 --- /dev/null +++ b/include/iprt/formats/fat.h @@ -0,0 +1,759 @@ +/* $Id: fat.h $ */ +/** @file + * IPRT, File Allocation Table (FAT). + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_fat_h +#define IPRT_INCLUDED_formats_fat_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_rt_formats_fat File Allocation Table (FAT) structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + + +/** @name FAT Media byte values + * @remarks This isn't as simple as it's made out to be here! + * @{ */ +#define FATBPB_MEDIA_FLOPPY_8 UINT8_C(0xe5) +#define FATBPB_MEDIA_FLOPPY_5_DOT_25 UINT8_C(0xed) +#define FATBPB_MEDIA_FLOPPY_3_DOT_5 UINT8_C(0xf0) +/* incomplete, figure out as needed... */ + +/** Checks if @a a_bMedia is a valid media byte. */ +#define FATBPB_MEDIA_IS_VALID(a_bMedia) ( (uint8_t)(a_bMedia) >= 0xf8 \ + || (uint8_t)(a_bMedia) == 0xf0 \ + || (uint8_t)(a_bMedia) == 0xf4 /* obscure - msdos 2.11 */ \ + || (uint8_t)(a_bMedia) == 0xf5 /* obscure - msdos 2.11 */ \ + || (uint8_t)(a_bMedia) == 0xed /* obscure - tandy 2000 */ \ + || (uint8_t)(a_bMedia) == 0xe5 /* obscure - tandy 2000 */ ) +/** @} */ + +/** Checks if @a a_bFatId is a valid FAT ID byte. + * @todo uncertain whether 0xf4 and 0xf5 should be allowed here too. */ +#define FAT_ID_IS_VALID(a_bFatId) ( (uint8_t)(a_bFatId) >= 0xf8 \ + || (uint8_t)(a_bFatId) == 0xf0 \ + || (uint8_t)(a_bFatId) == 0xf4 /* obscure - msdos 2.11 */ \ + || (uint8_t)(a_bFatId) == 0xf5 /* obscure - msdos 2.11 */ \ + || (uint8_t)(a_bFatId) == 0xed /* obscure, tandy 2000 */ \ + || (uint8_t)(a_bFatId) == 0xe5 /* obscure, tandy 2000 */ ) + +/** + * The DOS 2.0 BIOS parameter block (BPB). + * + * This was the first DOS version with a BPB. + */ +#pragma pack(1) +typedef struct FATBPB20 +{ + /** 0x0b / 0x00: The sector size in bytes. */ + uint16_t cbSector; + /** 0x0d / 0x02: Number of sectors per cluster. */ + uint8_t cSectorsPerCluster; + /** 0x0e / 0x03: Number of reserved sectors before the first FAT. */ + uint16_t cReservedSectors; + /** 0x10 / 0x05: Number of FATs. */ + uint8_t cFats; + /** 0x11 / 0x06: Max size of the root directory (0 for FAT32). */ + uint16_t cMaxRootDirEntries; + /** 0x13 / 0x08: Total sector count, zero if 32-bit count is used. */ + uint16_t cTotalSectors16; + /** 0x15 / 0x0a: Media ID. */ + uint8_t bMedia; + /** 0x16 / 0x0b: Number of sectors per FAT (0 for FAT32). */ + uint16_t cSectorsPerFat; +} FATBPB20; +#pragma pack() +AssertCompileSize(FATBPB20, 0xd); +/** Pointer to a DOS 2.0 BPB. */ +typedef FATBPB20 *PFATBPB20; +/** Pointer to a const DOS 2.0 BPB. */ +typedef FATBPB20 const *PCFATBPB20; + + +/** + * The DOS 3.0 BPB changes that survived. + */ +#pragma pack(1) +typedef struct FATBPB30CMN +{ + /** DOS v2.0 BPB. */ + FATBPB20 Bpb20; + /** 0x18 / 0x0d: Sectors per track. Zero means reserved and not used. */ + uint16_t cSectorsPerTrack; + /** 0x1a / 0x0f: Number of heads. Zero means reserved and not used. */ + uint16_t cTracksPerCylinder; +} FATBPB30CMN; +#pragma pack() +AssertCompileSize(FATBPB30CMN, 0x11); + +/** + * The DOS 3.0 BPB. + */ +#pragma pack(1) +typedef struct FATBPB30 +{ + /** DOS v3.0 BPB bits that survived. */ + FATBPB30CMN Core30; + /** 0x1c / 0x11: Number of hidden sectors preceeding the volume. This is zero + * on unpartitioned media. */ + uint16_t cHiddenSectors; +} FATBPB30; +#pragma pack() +AssertCompileSize(FATBPB30, 0x13); +/** Pointer to a DOS 3.0 BPB. */ +typedef FATBPB30 *PFATBPB30; +/** Pointer to a const DOS 3.0 BPB. */ +typedef FATBPB30 const *PCFATBPB30; + +/** + * The DOS 3.0 BPB, flattened structure. + */ +#pragma pack(1) +typedef struct FATBPB30FLAT +{ + /** @name New in DOS 2.0 + * @{ */ + /** 0x0b / 0x00: The sector size in bytes. */ + uint16_t cbSector; + /** 0x0d / 0x02: Number of sectors per cluster. */ + uint8_t cSectorsPerCluster; + /** 0x0e / 0x03: Number of reserved sectors before the first FAT. */ + uint16_t cReservedSectors; + /** 0x10 / 0x05: Number of FATs. */ + uint8_t cFats; + /** 0x11 / 0x06: Max size of the root directory (0 for FAT32). */ + uint16_t cMaxRootDirEntries; + /** 0x13 / 0x08: Total sector count, zero if 32-bit count is used. */ + uint16_t cTotalSectors16; + /** 0x15 / 0x0a: Media ID. */ + uint8_t bMedia; + /** 0x16 / 0x0b: Number of sectors per FAT (0 for FAT32). */ + uint16_t cSectorsPerFat; + /** @} */ + /** @name New in DOS 3.0 + * @{ */ + /** 0x18 / 0x0d: Sectors per track. Zero means reserved and not used. */ + uint16_t cSectorsPerTrack; + /** 0x1a / 0x0f: Number of heads. Zero means reserved and not used. */ + uint16_t cTracksPerCylinder; + /** 0x1c / 0x11: Number of hidden sectors preceeding the volume. This is zero + * on unpartitioned media. */ + uint16_t cHiddenSectors; + /** @} */ +} FATBPB30FLAT; +#pragma pack() +AssertCompileSize(FATBPB30FLAT, 0x13); +/** Pointer to a flattened DOS 3.0 BPB. */ +typedef FATBPB30FLAT *PFATBPB30FLAT; +/** Pointer to a const flattened DOS 3.0 BPB. */ +typedef FATBPB30FLAT const *PCFATBPB30FLAT; + + +/** + * The DOS 3.2 BPB. + */ +#pragma pack(1) +typedef struct FATBPB32 +{ + /** DOS v3.0 BPB. */ + FATBPB30 Bpb30; + /** 0x1e / 0x13: Number of sectors, including the hidden ones. This is ZERO + * in DOS 3.31+. */ + uint16_t cAnotherTotalSectors; +} FATBPB32; +#pragma pack() +AssertCompileSize(FATBPB32, 0x15); +/** Pointer to a DOS 3.2 BPB. */ +typedef FATBPB32 *PFATBPB32; +/** Pointer to const a DOS 3.2 BPB. */ +typedef FATBPB32 const *PCFATBPB32; + +/** + * The DOS 3.2 BPB, flattened structure. + */ +#pragma pack(1) +typedef struct FATBPB32FLAT +{ + /** @name New in DOS 2.0 + * @{ */ + /** 0x0b / 0x00: The sector size in bytes. */ + uint16_t cbSector; + /** 0x0d / 0x02: Number of sectors per cluster. */ + uint8_t cSectorsPerCluster; + /** 0x0e / 0x03: Number of reserved sectors before the first FAT. */ + uint16_t cReservedSectors; + /** 0x10 / 0x05: Number of FATs. */ + uint8_t cFats; + /** 0x11 / 0x06: Max size of the root directory (0 for FAT32). */ + uint16_t cMaxRootDirEntries; + /** 0x13 / 0x08: Total sector count, zero if 32-bit count is used. */ + uint16_t cTotalSectors16; + /** 0x15 / 0x0a: Media ID. */ + uint8_t bMedia; + /** 0x16 / 0x0b: Number of sectors per FAT (0 for FAT32). */ + uint16_t cSectorsPerFat; + /** @} */ + /** @name New in DOS 3.0 + * @{ */ + /** 0x18 / 0x0d: Sectors per track. Zero means reserved and not used. */ + uint16_t cSectorsPerTrack; + /** 0x1a / 0x0f: Number of heads. Zero means reserved and not used. */ + uint16_t cTracksPerCylinder; + /** 0x1c / 0x11: Number of hidden sectors preceeding the volume. This is zero + * on unpartitioned media. */ + uint16_t cHiddenSectors; + /** @} */ + /** @name New in DOS 3.2 + * @{ */ + /** 0x1e / 0x13: Number of sectors, including the hidden ones. This is ZERO + * in DOS 3.31+. */ + uint16_t cAnotherTotalSectors; + /** @} */ +} FATBPB32FLAT; +#pragma pack() +AssertCompileSize(FATBPB32FLAT, 0x15); +/** Pointer to a flattened DOS 3.2 BPB. */ +typedef FATBPB32FLAT *PFATBPB32FLAT; +/** Pointer to a const flattened DOS 3.2 BPB. */ +typedef FATBPB32FLAT const *PCFATBPB32FLAT; + + +/** + * The DOS 3.31 BPB. + */ +#pragma pack(1) +typedef struct FATBPB331 +{ + /** DOS v3.0 BPB bits that survived. */ + FATBPB30CMN Core30; + /** 0x1c / 0x11: Number of hidden sectors preceeding the volume. This is zero + * on unpartitioned media. Values higher than 65535 are complicated due to + * the field overlapping FATBPB32::cAnotherTotalSectors */ + uint32_t cHiddenSectors; + /** 0x20 / 0x15: Total logical sectors. Used if count >= 64K, otherwise + * FATBPB20::cTotalSectors16 is used. Zero if 64-bit value used with FAT32. */ + uint32_t cTotalSectors32; +} FATBPB331; +#pragma pack() +AssertCompileSize(FATBPB331, 0x19); +/** Pointer to a DOS 3.31 BPB. */ +typedef FATBPB331 *PFATBPB331; +/** Pointer to a const DOS 3.31 BPB. */ +typedef FATBPB331 const *PCFATBPB331; + +/** + * The DOS 3.31 BPB, flattened structure. + */ +#pragma pack(1) +typedef struct FATBPB331FLAT +{ + /** @name New in DOS 2.0 + * @{ */ + /** 0x0b / 0x00: The sector size in bytes. */ + uint16_t cbSector; + /** 0x0d / 0x02: Number of sectors per cluster. */ + uint8_t cSectorsPerCluster; + /** 0x0e / 0x03: Number of reserved sectors before the first FAT (0 for + * NTFS). */ + uint16_t cReservedSectors; + /** 0x10 / 0x05: Number of FATs (0 for NTFS). */ + uint8_t cFats; + /** 0x11 / 0x06: Max size of the root directory (0 for FAT32 & NTFS). */ + uint16_t cMaxRootDirEntries; + /** 0x13 / 0x08: Total sector count, zero if 32-bit count is used (and for + * NTFS). */ + uint16_t cTotalSectors16; + /** 0x15 / 0x0a: Media ID. */ + uint8_t bMedia; + /** 0x16 / 0x0b: Number of sectors per FAT (0 for FAT32 & NTFS). */ + uint16_t cSectorsPerFat; + /** @} */ + /** @name New in DOS 3.0 + * @{ */ + /** 0x18 / 0x0d: Sectors per track. Zero means reserved and not used. */ + uint16_t cSectorsPerTrack; + /** 0x1a / 0x0f: Number of heads. Zero means reserved and not used. */ + uint16_t cTracksPerCylinder; + /** @} */ + /** @name New in DOS 3.31 + * @{ */ + /** 0x1c / 0x11: Number of hidden sectors preceeding the volume. This is zero + * on unpartitioned media. Values higher than 65535 are complicated due to + * the field overlapping FATBPB32::cAnotherTotalSectors */ + uint32_t cHiddenSectors; + /** 0x20 / 0x15: Total logical sectors. Used if count >= 64K, otherwise + * FATBPB20::cTotalSectors16 is used. Zero if 64-bit value used with FAT32. + * (Zero for NTFS). */ + uint32_t cTotalSectors32; + /** @} */ +} FATBPB331FLAT; +#pragma pack() +AssertCompileSize(FATBPB331FLAT, 0x19); +/** Pointer to a flattened DOS 3.31 BPB. */ +typedef FATBPB331FLAT *PFATBPB331FLAT; +/** Pointer to a const flattened DOS 3.31 BPB. */ +typedef FATBPB331FLAT const *PCFATBPB331FLAT; + + +/** + * Extended BIOS parameter block (EBPB). + */ +#pragma pack(1) +typedef struct FATEBPB +{ + /** The BPB. */ + FATBPB331FLAT Bpb; + + /** 0x24 / 0x19: BIOS INT13 pysical drive number. */ + uint8_t bInt13Drive; + /** 0x25 / 0x1a: Reserved. NT used bit 0 for indicating dirty FS, and bit 1 + * for surface scan. */ + uint8_t bReserved; + /** 0x26 / 0x1b: Extended boot signature, FATEBPB_SIGNATURE or + * FATEBPB_SIGNATURE_OLD. */ + uint8_t bExtSignature; + /** 0x27 / 0x1c: The volume serial number. */ + uint32_t uSerialNumber; + /** 0x2b / 0x20: The volume label (space padded). + * @remarks Not available with FATEBPB_SIGNATURE_OLD */ + char achLabel[11]; + /** 0x36 / 0x2b: The file system type (space padded). + * @remarks Not available with FATEBPB_SIGNATURE_OLD */ + char achType[8]; +} FATEBPB; +#pragma pack() +AssertCompileSize(FATEBPB, 0x33); +/** Pointer to an extended BIOS parameter block. */ +typedef FATEBPB *PFATEBPB; +/** Pointer to a const extended BIOS parameter block. */ +typedef FATEBPB const *PCFATEBPB; + +/** FATEBPB::bExtSignature value. */ +#define FATEBPB_SIGNATURE UINT8_C(0x29) +/** FATEBPB::bExtSignature value used by OS/2 1.0-1.1 and PC DOS 3.4. These + * does not have the volume and file system type. */ +#define FATEBPB_SIGNATURE_OLD UINT8_C(0x28) + +/**FATEBPB::achType value for FAT12. */ +#define FATEBPB_TYPE_FAT12 "FAT12 " +/**FATEBPB::achType value for FAT16. */ +#define FATEBPB_TYPE_FAT16 "FAT16 " +/**FATEBPB::achType value for FAT12/FAT16. */ +#define FATEBPB_TYPE_FAT "FAT32 " + + +/** + * FAT32 Extended BIOS parameter block (EBPB). + */ +#pragma pack(1) +typedef struct FAT32EBPB +{ + /** The BPB. */ + FATBPB331FLAT Bpb; + + /** 0x24 / 0x19: Number of sectors per FAT. + * @note To avoid confusion with the FATEBPB signature, values which result in + * 0x00280000 or 0x00290000 when masked by 0x00ff0000 must not be used. */ + uint32_t cSectorsPerFat32; + /** 0x28 / 0x1d: Flags pertaining to FAT mirroring and other stuff. */ + uint16_t fFlags; + /** 0x2a / 0x1f: FAT32 version number (FAT32EBPB_VERSION_0_0). */ + uint16_t uVersion; + /** 0x2c / 0x21: Cluster number of the root directory. */ + uint32_t uRootDirCluster; + /** 0x30 / 0x25: Logical sector number of the information sector. */ + uint16_t uInfoSectorNo; + /** 0x32 / 0x27: Logical sector number of boot sector copy. */ + uint16_t uBootSectorCopySectorNo; + /** 0x34 / 0x29: Reserved, zero (or 0xf6) filled, preserve. */ + uint8_t abReserved[12]; + + /** 0x40 / 0x35: BIOS INT13 pysical drive number + * @remarks Same as FATEBPB::bInt13Drive. */ + uint8_t bInt13Drive; + /** 0x41 / 0x36: Reserved. + * @remarks Same as FATEBPB::bReserved. */ + uint8_t bReserved; + /** 0x42 / 0x37: Extended boot signature (FATEBPB_SIGNATURE, or + * FATEBPB_SIGNATURE_OLD in some special cases). + * @remarks Same as FATEBPB::bExtSignature. */ + uint8_t bExtSignature; + /** 0x43 / 0x38: The volume serial number. + * @remarks Same as FATEBPB::uSerialNumber. */ + uint32_t uSerialNumber; + /** 0x47 / 0x3c: The volume label (space padded). + * @remarks Not available with FATEBPB_SIGNATURE_OLD + * @remarks Same as FATEBPB::achLabel. */ + char achLabel[11]; + /** 0x52 / 0x47: The file system type (space padded), or 64-bit logical sector + * count if both other count fields are zero. In the latter case, the type is + * moved to the OEM name field (FATBOOTSECTOR::achOemName). + * + * @remarks Not available with FATEBPB_SIGNATURE_OLD + * @remarks Same as FATEBPB::achType. */ + union + { + /** Type string variant. */ + char achType[8]; + /** Total sector count if 4G or higher. */ + uint64_t cTotalSectors64; + } u; +} FAT32EBPB; +#pragma pack() +AssertCompileSize(FAT32EBPB, 0x4f); +/** Pointer to a FAT32 extended BIOS parameter block. */ +typedef FAT32EBPB *PFAT32EBPB; +/** Pointer to a const FAT32 extended BIOS parameter block. */ +typedef FAT32EBPB const *PCFAT32EBPB; + +/** FAT32 version 0.0 (FAT32EBPB::uVersion). */ +#define FAT32EBPB_VERSION_0_0 UINT16_C(0x0000) + + +/** + * NTFS extended BIOS parameter block (NTFSEBPB). + */ +#pragma pack(1) +typedef struct NTFSEBPB +{ + /** The BPB. */ + FATBPB331FLAT Bpb; + + /** 0x24 / 0x19: BIOS INT13 pysical drive number. + * @note Same location as FATEBPB::bInt13Drive. */ + uint8_t bInt13Drive; + /** 0x25 / 0x1a: Reserved / flags */ + uint8_t bReserved; + /** 0x26 / 0x1b: Extended boot signature (NTFSEBPB_SIGNATURE). + * @note Same location as FATEBPB::bExtSignature. */ + uint8_t bExtSignature; + /** 0x27 / 0x1c: Reserved */ + uint8_t bReserved2; + + /** 0x28 / 0x1d: Number of sectors. */ + uint64_t cSectors; + /** 0x30 / 0x25: Logical cluster number of the master file table (MFT). */ + uint64_t uLcnMft; + /** 0x38 / 0x2d: Logical cluster number of the MFT mirror. */ + uint64_t uLcnMftMirror; + /** 0x40 / 0x35: Logical clusters per file record segment. + * This is a shift count if negative. */ + int8_t cClustersPerMftRecord; + /** 0x41 / 0x36: Reserved. */ + uint8_t abReserved3[3]; + /** 0x44 / 0x39: The default logical clusters count per index node. + * This is a shift count if negative. */ + int8_t cClustersPerIndexNode; + /** 0x45 / 0x3a: Reserved. */ + uint8_t abReserved4[3]; + /** 0x48 / 0x3d: Volume serial number. + * @note This is larger than the the FAT serial numbers. */ + uint64_t uSerialNumber; + /** 0x50 / 0x45: Checksum. */ + uint32_t uChecksum; +} NTFSEBPB; +#pragma pack() +AssertCompileSize(NTFSEBPB, 0x49); +/** Pointer to a NTFS extended BIOS parameter block. */ +typedef NTFSEBPB *PNTFSEBPB; +/** Pointer to a const NTFS extended BIOS parameter block. */ +typedef NTFSEBPB const *PCNTFSEBPB; + +/** NTFS EBPB signature (NTFSEBPB::bExtSignature). */ +#define NTFSEBPB_SIGNATURE UINT8_C(0x80) + + +/** + * FAT boot sector layout. + */ +#pragma pack(1) +typedef struct FATBOOTSECTOR +{ + /** 0x000: DOS 2.0+ jump sequence. */ + uint8_t abJmp[3]; + /** 0x003: OEM name (who formatted this volume). */ + char achOemName[8]; + /** 0x00b: The BIOS parameter block. + * This varies a lot in size. */ + union + { + FATBPB20 Bpb20; + FATBPB30FLAT Bpb30; + FATBPB32FLAT Bpb32; + FATBPB331FLAT Bpb331; + FATEBPB Ebpb; + FAT32EBPB Fat32Ebpb; + NTFSEBPB Ntfs; + } Bpb; + /** 0x05a: Bootloader code/data/stuff. */ + uint8_t abStuff[0x1a3]; + /** 0x1fd: Old drive number location (DOS 3.2-3.31). */ + uint8_t bOldInt13Drive; + /** 0x1fe: DOS signature (FATBOOTSECTOR_SIGNATURE). */ + uint16_t uSignature; +} FATBOOTSECTOR; +#pragma pack() +AssertCompileSize(FATBOOTSECTOR, 0x200); +/** Pointer to a FAT boot sector. */ +typedef FATBOOTSECTOR *PFATBOOTSECTOR; +/** Pointer to a const FAT boot sector. */ +typedef FATBOOTSECTOR const *PCFATBOOTSECTOR; + +/** Boot sector signature (FATBOOTSECTOR::uSignature). */ +#define FATBOOTSECTOR_SIGNATURE UINT16_C(0xaa55) + + + +/** + * FAT32 info sector (follows the boot sector). + */ +typedef struct FAT32INFOSECTOR +{ + /** 0x000: Signature \#1 (FAT32INFOSECTOR_SIGNATURE_1). */ + uint32_t uSignature1; + /** Reserved, should be zero. */ + uint8_t abReserved1[0x1E0]; + /** 0x1e4: Signature \#1 (FAT32INFOSECTOR_SIGNATURE_2). */ + uint32_t uSignature2; + /** 0x1e8: Last known number of free clusters (informational). */ + uint32_t cFreeClusters; + /** 0x1ec: Last allocated cluster number (informational). This could be used as + * an allocation hint when searching for a free cluster. */ + uint32_t cLastAllocatedCluster; + /** 0x1f0: Reserved, should be zero, preserve. */ + uint8_t abReserved2[12]; + /** 0x1fc: Signature \#3 (FAT32INFOSECTOR_SIGNATURE_3). */ + uint32_t uSignature3; +} FAT32INFOSECTOR; +AssertCompileSize(FAT32INFOSECTOR, 0x200); +/** Pointer to a FAT32 info sector. */ +typedef FAT32INFOSECTOR *PFAT32INFOSECTOR; +/** Pointer to a const FAT32 info sector. */ +typedef FAT32INFOSECTOR const *PCFAT32INFOSECTOR; + +#define FAT32INFOSECTOR_SIGNATURE_1 UINT32_C(0x41615252) +#define FAT32INFOSECTOR_SIGNATURE_2 UINT32_C(0x61417272) +#define FAT32INFOSECTOR_SIGNATURE_3 UINT32_C(0xaa550000) + + +/** @name Special FAT cluster numbers and limits. + * @{ */ +#define FAT_FIRST_DATA_CLUSTER 2 /**< The first data cluster. */ + +#define FAT_MAX_FAT12_TOTAL_CLUSTERS UINT32_C(0x00000ff6) /**< Maximum number of clusters in a 12-bit FAT . */ +#define FAT_MAX_FAT16_TOTAL_CLUSTERS UINT32_C(0x0000fff6) /**< Maximum number of clusters in a 16-bit FAT . */ +#define FAT_MAX_FAT32_TOTAL_CLUSTERS UINT32_C(0x0ffffff6) /**< Maximum number of clusters in a 32-bit FAT . */ + +#define FAT_LAST_FAT12_DATA_CLUSTER UINT32_C(0x00000ff5) /**< The last possible data cluster for FAT12. */ +#define FAT_LAST_FAT16_DATA_CLUSTER UINT32_C(0x0000fff5) /**< The last possible data cluster for FAT16. */ +#define FAT_LAST_FAT32_DATA_CLUSTER UINT32_C(0x0ffffff5) /**< The last possible data cluster for FAT32. */ + +#define FAT_MAX_FAT12_DATA_CLUSTERS UINT32_C(0x00000ff4) /**< Maximum number of data clusters for FAT12. */ +#define FAT_MAX_FAT16_DATA_CLUSTERS UINT32_C(0x0000fff4) /**< Maximum number of data clusters for FAT16. */ +#define FAT_MAX_FAT32_DATA_CLUSTERS UINT32_C(0x0ffffff4) /**< Maximum number of data clusters for FAT32. */ + +#define FAT_MIN_FAT12_DATA_CLUSTERS UINT32_C(0x00000001) /**< Maximum number of data clusters for FAT12. */ +#define FAT_MIN_FAT16_DATA_CLUSTERS UINT32_C(0x00000ff5) /**< Maximum number of data clusters for FAT16. */ +#define FAT_MIN_FAT32_DATA_CLUSTERS UINT32_C(0x0000fff5) /**< Maximum number of data clusters for FAT32. */ + +#define FAT_FIRST_FAT12_EOC UINT32_C(0x00000ff8) /**< The first end-of-file-cluster number for FAT12. */ +#define FAT_FIRST_FAT16_EOC UINT32_C(0x0000fff8) /**< The first end-of-file-cluster number for FAT16. */ +#define FAT_FIRST_FAT32_EOC UINT32_C(0x0ffffff8) /**< The first end-of-file-cluster number for FAT32. */ +/** @} */ + + +/** + * FAT directory entry. + */ +typedef struct FATDIRENTRY +{ + /** 0x00: The directory entry name. + * First character serves as a flag to indicate deleted or not. */ + uint8_t achName[8+3]; + /** 0x0b: Attributes (FAT_ATTR_XXX). */ + uint8_t fAttrib; + /** 0x0c: NT case flags (FATDIRENTRY_CASE_F_XXX). */ + uint8_t fCase; + /** 0x0d: Birth milliseconds (DOS 7.0+ w/VFAT). */ + uint8_t uBirthCentiseconds; + /** 0x0e: Birth time (DOS 7.0+ w/VFAT). */ + uint16_t uBirthTime; + /** 0x10: Birth date (DOS 7.0+ w/VFAT). */ + uint16_t uBirthDate; + /** 0x12: Access date (DOS 7.0+ w/ACCDATA in Config.sys). */ + uint16_t uAccessDate; + union + { + /** 0x14: High cluster word for FAT32. */ + uint16_t idxClusterHigh; + /** 0x14: Index of extended attributes (FAT16/FAT12). */ + uint16_t idxEAs; + } u; + /** 0x16: Modify time (PC-DOS 1.1+, MS-DOS 1.20+). */ + uint16_t uModifyTime; + /** 0x18: Modify date. */ + uint16_t uModifyDate; + /** 0x1a: The data cluster index. */ + uint16_t idxCluster; + /** 0x1c: The file size. */ + uint32_t cbFile; +} FATDIRENTRY; +AssertCompileSize(FATDIRENTRY, 0x20); +AssertCompileMemberOffset(FATDIRENTRY, fAttrib, 0x0b); +AssertCompileMemberOffset(FATDIRENTRY, fCase, 0x0c); +AssertCompileMemberOffset(FATDIRENTRY, uBirthCentiseconds, 0x0d); +AssertCompileMemberOffset(FATDIRENTRY, uBirthTime, 0x0e); +AssertCompileMemberOffset(FATDIRENTRY, uBirthDate, 0x10); +AssertCompileMemberOffset(FATDIRENTRY, uAccessDate, 0x12); +AssertCompileMemberOffset(FATDIRENTRY, u, 0x14); +AssertCompileMemberOffset(FATDIRENTRY, uModifyTime, 0x16); +AssertCompileMemberOffset(FATDIRENTRY, uModifyDate, 0x18); +AssertCompileMemberOffset(FATDIRENTRY, idxCluster, 0x1a); +AssertCompileMemberOffset(FATDIRENTRY, cbFile, 0x1c); +/** Pointer to a FAT directory entry. */ +typedef FATDIRENTRY *PFATDIRENTRY; +/** Pointer to a FAT directory entry. */ +typedef FATDIRENTRY const *PCFATDIRENTRY; + + +/** @name FAT_ATTR_XXX - FATDIRENTRY::fAttrib flags. + * @{ */ +#define FAT_ATTR_READONLY UINT8_C(0x01) +#define FAT_ATTR_HIDDEN UINT8_C(0x02) +#define FAT_ATTR_SYSTEM UINT8_C(0x04) +#define FAT_ATTR_VOLUME UINT8_C(0x08) +#define FAT_ATTR_DIRECTORY UINT8_C(0x10) +#define FAT_ATTR_ARCHIVE UINT8_C(0x20) +#define FAT_ATTR_DEVICE UINT8_C(0x40) +#define FAT_ATTR_RESERVED UINT8_C(0x80) +#define FAT_ATTR_NAME_SLOT UINT8_C(0x0f) /**< Special attribute value for FATDIRNAMESLOT. */ +/** @} */ + +/** @name FATDIRENTRY_CASE_F_XXX - FATDIRENTRY::fCase flags. + * @{ */ +/** Lower cased base name (first 8 chars). */ +#define FATDIRENTRY_CASE_F_LOWER_BASE UINT8_C(0x08) +/** Lower cased filename extension (last 3 chars). */ +#define FATDIRENTRY_CASE_F_LOWER_EXT UINT8_C(0x10) +/** @} */ + +/** @name FATDIRENTRY_CH0_XXX - FATDIRENTRY::achName[0] + * @{ */ +/** Deleted entry. */ +#define FATDIRENTRY_CH0_DELETED UINT8_C(0xe5) +/** End of used directory entries (MS-DOS 1.25+, PC-DOS 2.0+). */ +#define FATDIRENTRY_CH0_END_OF_DIR UINT8_C(0x00) +/** The special dot or dot-dot dir aliases (MS-DOS 1.40+, PC-DOS 2.0+). + * @remarks 0x2e is the ascii table entry of the '.' character. */ +#define FATDIRENTRY_CH0_DOT_ALIAS UINT8_C(0x2e) +/** Escaped 0xe5 leadcharacter (DOS 3.0+). */ +#define FATDIRENTRY_CH0_ESC_E5 UINT8_C(0x05) +/** @} */ + + +/** + * FAT directory alias name slot. + * + * Each slot holds 13 UTF-16 (/ UCS-2) characters, so it takes 20 slots to cover + * a 255 character long name. + */ +#pragma pack(1) +typedef struct FATDIRNAMESLOT +{ + /** The slot sequence number. */ + uint8_t idSlot; + /** The first 5 name chars. + * @remarks misaligned */ + RTUTF16 awcName0[5]; + /** Attributes (FAT_ATTR_XXX). */ + uint8_t fAttrib; + /** Always zero. */ + uint8_t fZero; + /** Alias checksum. */ + uint8_t bChecksum; + /** The next 6 name chars. */ + RTUTF16 awcName1[6]; + /** Always zero (usually cluster entry). */ + uint16_t idxZero; + /** The next 2 name chars. */ + RTUTF16 awcName2[2]; +} FATDIRNAMESLOT; +#pragma pack() +AssertCompileSize(FATDIRNAMESLOT, 0x20); +/** Pointer to a FAT directory entry. */ +typedef FATDIRNAMESLOT *PFATDIRNAMESLOT; +/** Pointer to a FAT directory entry. */ +typedef FATDIRNAMESLOT const *PCFATDIRNAMESLOT; + +/** Slot ID flag indicating that it's the first slot. */ +#define FATDIRNAMESLOT_FIRST_SLOT_FLAG UINT8_C(0x40) +/** Highest slot ID recognized. This allows for 260 characters, however many + * implementation limits it to 255 or 250. */ +#define FATDIRNAMESLOT_HIGHEST_SLOT_ID UINT8_C(0x14) +/** Max number of slots recognized. (This is the same as the higest slot ID + * because the 0 isn't a valid ID.) */ +#define FATDIRNAMESLOT_MAX_SLOTS FATDIRNAMESLOT_HIGHEST_SLOT_ID +/** Number of UTF-16 units per slot. */ +#define FATDIRNAMESLOT_CHARS_PER_SLOT (5 + 6 + 2) + + + +/** + * FAT directory entry union. + */ +typedef union FATDIRENTRYUNION +{ + /** Regular entry view. */ + FATDIRENTRY Entry; + /** Name slot view. */ + FATDIRNAMESLOT Slot; +} FATDIRENTRYUNION; +AssertCompileSize(FATDIRENTRYUNION, 0x20); +/** Pointer to a FAT directory entry union. */ +typedef FATDIRENTRYUNION *PFATDIRENTRYUNION; +/** Pointer to a const FAT directory entry union. */ +typedef FATDIRENTRYUNION const *PCFATDIRENTRYUNION; + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_fat_h */ + diff --git a/include/iprt/formats/hfs.h b/include/iprt/formats/hfs.h new file mode 100644 index 00000000..bedcb8f1 --- /dev/null +++ b/include/iprt/formats/hfs.h @@ -0,0 +1,691 @@ +/** @file + * IPRT - Hierarchical File System (HFS). + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_hfs_h +#define IPRT_INCLUDED_formats_hfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_rt_fmt_hfs HFS - Hierarchical File System. + * @{ + */ + + +/** @name HFS signature words (HFSPlusVolumeHeader::signature) + * @{ */ +#define kHFSSigWord UINT16_C(0x4244) +#define kHFSPlusSigWord UINT16_C(0x482b) +#define kHFSXSigWord UINT16_C(0x4858) +/** @} */ + +/** @name HFS version numbers (HFSPlusVolumeHeader::version). + * @{ */ +#define kHFSPlusVersion UINT16_C(4) +#define kHFSXVersion UINT16_C(5) +/** @} */ + +/** @name HFS mount version numbers (HFSPlusVolumeHeader::lastMountedVersion). + * @{ */ +#define kHFSPlusMountVersion UINT32_C(0x31302e30) +#define kHFSJMountVersion UINT32_C(0x4846534a) +#define kFSKMountVersion UINT32_C(0x46534b21) +/** @} */ + +/** @name Hard link file creators & types. + * @{ */ +#define kHardLinkFileType UINT32_C(0x686c6e6b) +#define kHFSPlusCreator UINT32_C(0x6866732b) +/** @} */ + +/** @name Symlink file creators & types. + * @{ */ +#define kSymLinkFileType UINT32_C(0x736c6e6b) +#define kSymLinkCreator UINT32_C(0x72686170) +/** @} */ + +/** @name Name limits. + * @{ */ +#define kHFSMaxVolumeNameChars UINT8_C(0x1b) +#define kHFSMaxFileNameChars UINT8_C(0x1f) +#define kHFSPlusMaxFileNameChars UINT8_C(0xff) +#define kHFSMaxAttrNameLen UINT8_C(0x7f) +/** @} */ + +/** @name Extent descriptor record densities + * @{ */ +#define kHFSExtentDensity UINT8_C(3) +#define kHFSPlusExtentDensity UINT8_C(8) +/** @} */ + + +/** @name File IDs (various fileID members). + * @{ */ +#define kHFSRootParentID UINT32_C(0x00000001) +#define kHFSRootFolderID UINT32_C(0x00000002) +#define kHFSExtentsFileID UINT32_C(0x00000003) +#define kHFSCatalogFileID UINT32_C(0x00000004) +#define kHFSBadBlockFileID UINT32_C(0x00000005) +#define kHFSAllocationFileID UINT32_C(0x00000006) +#define kHFSStartupFileID UINT32_C(0x00000007) +#define kHFSAttributesFileID UINT32_C(0x00000008) +#define kHFSAttributeDataFileID UINT32_C(0x0000000c) +#define kHFSRepairCatalogFileID UINT32_C(0x0000000e) +#define kHFSBogusExtentFileID UINT32_C(0x0000000f) +#define kHFSFirstUserCatalogNodeID UINT32_C(0x00000010) +/** @} */ + +/** @name Catalog record types. + * @{ */ +#define kHFSFolderRecord UINT16_C(0x0100) +#define kHFSFileRecord UINT16_C(0x0200) +#define kHFSFolderThreadRecord UINT16_C(0x0300) +#define kHFSFileThreadRecord UINT16_C(0x0400) +#define kHFSPlusFolderRecord UINT16_C(0x0001) +#define kHFSPlusFileRecord UINT16_C(0x0002) +#define kHFSPlusFolderThreadRecord UINT16_C(0x0003) +#define kHFSPlusFileThreadRecord UINT16_C(0x0004) +/** @} */ + +/** @name File record bits and masks. + * @{ */ +#define kHFSFileLockedBit 0 +#define kHFSThreadExistsBit 1 +#define kHFSHasAttributesBit 2 +#define kHFSHasSecurityBit 3 +#define kHFSHasFolderCountBit 4 +#define kHFSHasLinkChainBit 5 +#define kHFSHasChildLinkBit 6 +#define kHFSHasDateAddedBit 7 + +#define kHFSFileLockedMask RT_BIT(kHFSFileLockedBit) +#define kHFSThreadExistsMask RT_BIT(kHFSThreadExistsBit) +#define kHFSHasAttributesMask RT_BIT(kHFSHasAttributesBit) +#define kHFSHasSecurityMask RT_BIT(kHFSHasSecurityBit) +#define kHFSHasFolderCountMask RT_BIT(kHFSHasFolderCountBit) +#define kHFSHasLinkChainMask RT_BIT(kHFSHasLinkChainBit) +#define kHFSHasChildLinkMask RT_BIT(kHFSHasChildLinkBit) +#define kHFSHasDateAddedMask RT_BIT(kHFSHasDateAddedBit) +/** @} */ + +/** @name Key and node lengths. + * @{ */ +#define kHFSPlusAttrKeyMaximumLength ( sizeof(HFSPlusAttrKey) - sizeof(uint16_t) ) +#define kHFSPlusAttrKeyMinimumLength ( kHFSPlusAttrKeyMaximumLength - (kHFSMaxAttrNameLen * sizeof(uint16_t)) ) +#define kHFSPlusExtentKeyMaximumLength ( sizeof(HFSPlusExtentKey) - sizeof(uint16_t), +#define kHFSExtentKeyMaximumLength ( sizeof(HFSExtentKey) - sizeof(uint8_t) ) +#define kHFSPlusCatalogKeyMaximumLength ( sizeof(HFSPlusCatalogKey) - sizeof(uint16_t) ) +#define kHFSPlusCatalogKeyMinimumLength ( kHFSPlusCatalogKeyMaximumLength - sizeof(HFSUniStr255) + sizeof(uint16_t) ) +#define kHFSCatalogKeyMaximumLength ( sizeof(HFSCatalogKey) - sizeof(uint8_t) ) +#define kHFSCatalogKeyMinimumLength ( kHFSCatalogKeyMaximumLength - kHFSMaxFileNameChars - 1 + sizeof(uint8_t) ) +#define kHFSPlusCatalogMinNodeSize UINT16_C(0x1000) +#define kHFSPlusExtentMinNodeSize UINT16_C(0x0200) +#define kHFSPlusAttrMinNodeSize UINT16_C(0x1000) +/** @} */ + +/** @name Volume Attribute bits and masks. + * @remarks HFS has only 16-bit wide field, HFS+ has 32-bit. + * @{ */ +#define kHFSVolumeHardwareLockBit 7 +#define kHFSVolumeUnmountedBit 8 +#define kHFSVolumeSparedBlocksBit 9 +#define kHFSVolumeNoCacheRequiredBit 10 +#define kHFSBootVolumeInconsistentBit 11 +#define kHFSCatalogNodeIDsReusedBit 12 +#define kHFSVolumeJournaledBit 13 +#define kHFSVolumeInconsistentBit 14 +#define kHFSVolumeSoftwareLockBit 15 +#define kHFSUnusedNodeFixBit 31 +#define kHFSContentProtectionBit 30 + +#define kHFSVolumeHardwareLockMask RT_BIT(kHFSVolumeHardwareLockBit) +#define kHFSVolumeUnmountedMask RT_BIT(kHFSVolumeUnmountedBit) +#define kHFSVolumeSparedBlocksMask RT_BIT(kHFSVolumeSparedBlocksBit) +#define kHFSVolumeNoCacheRequiredMask RT_BIT(kHFSVolumeNoCacheRequiredBit) +#define kHFSBootVolumeInconsistentMask RT_BIT(kHFSBootVolumeInconsistentBit) +#define kHFSCatalogNodeIDsReusedMask RT_BIT(kHFSCatalogNodeIDsReusedBit) +#define kHFSVolumeJournaledMask RT_BIT(kHFSVolumeJournaledBit) +#define kHFSVolumeInconsistentMask RT_BIT(kHFSVolumeInconsistentBit) +#define kHFSVolumeSoftwareLockMask RT_BIT(kHFSVolumeSoftwareLockBit) +#define kHFSUnusedNodeFixMask RT_BIT(kHFSUnusedNodeFixBit) +#define kHFSContentProtectionMask RT_BIT(kHFSContentProtectionBit) + +#define kHFSMDBAttributesMask UINT16_C(0x8380) +/** @} */ + +/** @name Misc + * @{ */ +#define kHFSUnusedNodesFixDate UINT32_C(0xc5ef2480) + +#define HFSPLUSMETADATAFOLDER "\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80HFS+ Private Data" +#define HFSPLUS_DIR_METADATA_FOLDER ".HFS+ Private Directory Data\xd" +#define HFS_INODE_PREFIX "iNode" +#define HFS_DELETE_PREFIX "temp" +#define HFS_DIRINODE_PREFIX "dir_" +#define FIRST_LINK_XATTR_NAME "com.apple.system.hfs.firstlink" +#define FIRST_LINK_XATTR_REC_SIZE ( sizeof(HFSPlusAttrData) + 10 ) + +/* {b3e20f39-f292-11d6-97a4-00306543ecac} */ +#define HFS_UUID_NAMESPACE_ID "\xB3\xE2\x0F\x39\xF2\x92\x11\xD6\x97\xA4\x00\x30\x65\x43\xEC\xAC" + +#define SET_HFS_TEXT_ENCODING(a_uHint) (UINT32_C(0x656e6300) | (uint8_t)(a_uHint)) +#define GET_HFS_TEXT_ENCODING(a_uHint) ( ((a_uHint) & UINT32_C(0xffffff00)) == UINT32_C(0x656e6300) \ + ? UINT32_C(0x000000ff)(a_uHint) : UINT32_MAX) +/** @} */ + +/** @name B-tree stuff. + * @{ */ +#define kMaxKeyLength 520 + +#define kBTLeafNode (-1) +#define kBTIndexNode 0 +#define kBTHeaderNode 1 +#define kBTMapNode 2 + +#define kBTBadCloseMask RT_BIT_32(0) +#define kBTBigKeysMask RT_BIT_32(1) +#define kBTVariableIndexKeysMask RT_BIT_32(2) + +/** @} */ + +/** @name B-tree compare types (BTHeaderRec::keyCompareType) + * @{ */ +#define kHFSCaseFolding UINT8_C(0xcf) +#define kHFSBinaryCompare UINT8_C(0xbc) +/** @} */ + +/** @name Journal stuff. + * @{ */ +#define JIB_RESERVED_SIZE ( sizeof(uint32_t) * 32 - 85 ) + +#define kJIJournalInFSMask RT_BIT_32(0) +#define kJIJournalOnOtherDeviceMask RT_BIT_32(1) +#define kJIJournalNeedInitMask RT_BIT_32(2) + +#define EXTJNL_CONTENT_TYPE_UUID "4a6f7572-6e61-11aa-aa11-00306543ecac" +/** @} */ + + + +typedef struct HFSUniStr255 +{ + uint16_t length; + RTUTF16 unicode[255]; +} HFSUniStr255; +AssertCompileSize(HFSUniStr255, 0x200); +typedef const HFSUniStr255 * ConstHFSUniStr255Param; + +#pragma pack(1) +typedef struct HFSExtentKey +{ + uint8_t keyLength; + uint8_t forkType; + uint32_t fileID; /**< Misaligned. */ + uint16_t startBLock; +} HFSExtentKey; +#pragma pack() +AssertCompileSize(HFSExtentKey, 8); + +typedef struct HFSPlusExtentKey +{ + uint16_t keyLength; + uint8_t forkType; + uint8_t pad; + uint32_t fileID; + uint32_t startBlock; +} HFSPlusExtentKey; +AssertCompileSize(HFSPlusExtentKey, 12); + +typedef struct HFSExtentDescriptor +{ + uint16_t startBlock; + uint16_t blockCount; +} HFSExtentDescriptor; +AssertCompileSize(HFSExtentDescriptor, 4); + +typedef struct HFSPlusExtentDescriptor +{ + uint32_t startBlock; + uint32_t blockCount; +} HFSPlusExtentDescriptor; +AssertCompileSize(HFSPlusExtentDescriptor, 8); + +typedef HFSExtentDescriptor HFSExtentRecord[3]; +typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[8]; + +typedef struct FndrFileInfo +{ + uint32_t fdType; + uint32_t fdCreator; + uint16_t fdFlags; + struct + { + int16_t v; + int16_t h; + } fdLocation; + uint16_t opaque; +} FndrFileInfo; +AssertCompileSize(FndrFileInfo, 16); + +typedef struct FndrDirInfo +{ + struct + { + int16_t top; + int16_t left; + int16_t bottom; + int16_t right; + } frRect; + uint16_t frFlags; + struct + { + int16_t v; + int16_t h; + } fdLocation; + uint16_t opaque; +} FndrDirInfo; +AssertCompileSize(FndrDirInfo, 16); + +typedef struct FndrOpaqueInfo +{ + int8_t opaque[16]; +} FndrOpaqueInfo; +AssertCompileSize(FndrOpaqueInfo, 16); + +typedef struct FndrExtendedFileInfo +{ + uint32_t reserved1; + uint32_t date_added; + uint16_t extended_flags; + uint16_t reserved2; + uint32_t reserved3; +} FndrExtendedFileInfo; +AssertCompileSize(FndrExtendedFileInfo, 16); + +typedef struct FndrExtendedDirInfo +{ + uint32_t point; + uint32_t date_added; + uint16_t extended_flags; + uint16_t reserved3; + uint32_t reserved4; +} FndrExtendedDirInfo; +AssertCompileSize(FndrExtendedDirInfo, 16); + +typedef struct HFSPlusForkData +{ + uint64_t logicalSize; + uint32_t clumpSize; + uint32_t totalBlocks; + HFSPlusExtentRecord extents; +} HFSPlusForkData; +AssertCompileSize(HFSPlusForkData, 80); + +typedef struct HFSPlusBSDInfo +{ + uint32_t ownerID; + uint32_t groupID; + uint8_t adminFlags; + uint8_t ownerFlags; + uint16_t fileMode; + union + { + uint32_t iNodeNum; + uint32_t linkCount; + uint32_t rawDevice; + } special; +} HFSPlusBSDInfo; +AssertCompileSize(HFSPlusBSDInfo, 16); + +#pragma pack(1) +typedef struct HFSCatalogKey +{ + uint8_t keyLength; + uint8_t reserved; + uint32_t parentID; /**< Misaligned. */ + uint8_t nodeName[kHFSMaxFileNameChars + 1]; +} HFSCatalogKey; +#pragma pack() +AssertCompileSize(HFSCatalogKey, 0x26); + +#pragma pack(1) +typedef struct HFSPlusCatalogKey +{ + uint16_t keyLength; + uint32_t parentID; /**< Misaligned. */ + HFSUniStr255 nodeName; +} HFSPlusCatalogKey; +#pragma pack() +AssertCompileSize(HFSPlusCatalogKey, 0x206); + +#pragma pack(1) +typedef struct HFSCatalogFolder +{ + int16_t recordType; + uint16_t flags; + uint16_t valence; + uint32_t folderID; /**< Misaligned. */ + uint32_t createDate; /**< Misaligned. */ + uint32_t modifyDate; /**< Misaligned. */ + uint32_t backupDate; /**< Misaligned. */ + FndrDirInfo userInfo; + FndrOpaqueInfo finderInfo; + uint32_t reserved[4]; /**< Misaligned. */ +} HFSCatalogFolder; +#pragma pack() +AssertCompileSize(HFSCatalogFolder, 70); + +typedef struct HFSPlusCatalogFolder +{ + int16_t recordType; + uint16_t flags; + uint32_t valence; + uint32_t folderID; + uint32_t createDate; + uint32_t contentModDate; + uint32_t attributeModDate; + uint32_t accessDate; + uint32_t backupDate; + HFSPlusBSDInfo bsdInfo; + FndrDirInfo userInfo; + FndrOpaqueInfo finderInfo; + uint32_t textEncoding; + uint32_t folderCount; +} HFSPlusCatalogFolder; +AssertCompileSize(HFSPlusCatalogFolder, 88); + +#pragma pack(1) +typedef struct HFSCatalogFile +{ + int16_t recordType; + uint8_t flags; + uint8_t fileType; + FndrFileInfo userInfo; + uint32_t fileID; + uint16_t dataStartBlock; + int32_t dataLogicalSize; /**< Misaligned. */ + int32_t dataPhysicalSize; /**< Misaligned. */ + uint16_t rsrcStartBlock; + int32_t rsrcLogicalSize; + int32_t rsrcPhysicalSize; + uint32_t createDate; + uint32_t modifyDate; + uint32_t backupDate; + FndrOpaqueInfo finderInfo; + uint16_t clumpSize; + HFSExtentRecord dataExtents; /**< Misaligned. */ + HFSExtentRecord rsrcExtents; /**< Misaligned. */ + uint32_t reserved; /**< Misaligned. */ +} HFSCatalogFile; +#pragma pack() +AssertCompileSize(HFSCatalogFile, 102); + +#pragma pack(1) +typedef struct HFSPlusCatalogFile +{ + int16_t recordType; + uint16_t flags; + uint32_t reserved1; + uint32_t fileID; + uint32_t createDate; + uint32_t contentModDate; + uint32_t attributeModDate; + uint32_t accessDate; + uint32_t backupDate; + HFSPlusBSDInfo bsdInfo; + FndrFileInfo userInfo; + FndrOpaqueInfo finderInfo; + uint32_t textEncoding; + uint32_t reserved2; + HFSPlusForkData dataFork; + HFSPlusForkData resourceFork; +} HFSPlusCatalogFile; +#pragma pack() +AssertCompileMemberAlignment(HFSPlusCatalogFile, dataFork, 8); +AssertCompileSize(HFSPlusCatalogFile, 248); + +#pragma pack(1) +typedef struct HFSCatalogThread +{ + int16_t recordType; + int32_t reserved[2]; + uint32_t parentID; + uint8_t nodeName[kHFSMaxFileNameChars + 1]; +} HFSCatalogThread; +#pragma pack() +AssertCompileSize(HFSCatalogThread, 46); + +typedef struct HFSPlusCatalogThread +{ + int16_t recordType; + int16_t reserved; + uint32_t parentID; + HFSUniStr255 nodeName; +} HFSPlusCatalogThread; +AssertCompileSize(HFSPlusCatalogThread, 0x208); + +typedef struct HFSPlusAttrForkData +{ + uint32_t recordType; + uint32_t reserved; + HFSPlusForkData theFork; +} HFSPlusAttrForkData; +AssertCompileSize(HFSPlusAttrForkData, 88); + +typedef struct HFSPlusAttrExtents +{ + uint32_t recordType; + uint32_t reserved; + HFSPlusExtentRecord extents; +} HFSPlusAttrExtents; +AssertCompileSize(HFSPlusAttrExtents, 72); + +#pragma pack(1) +typedef struct HFSPlusAttrData +{ + uint32_t recordType; + uint32_t reserved[2]; + uint32_t attrSize; + uint8_t attrData[2]; /**< Causes misaligned struct size. */ +} HFSPlusAttrData; +#pragma pack() +AssertCompileSize(HFSPlusAttrData, 18); + +#pragma pack(1) +typedef struct HFSPlusAttrInlineData +{ + uint32_t recordType; + uint32_t reserved; + uint32_t logicalSize; + uint8_t userData[2]; /**< Causes misaligned struct size. */ +} HFSPlusAttrInlineData; +#pragma pack() +AssertCompileSize(HFSPlusAttrInlineData, 14); + +typedef union HFSPlusAttrRecord +{ + uint32_t recordType; + HFSPlusAttrInlineData inlineData; + HFSPlusAttrData attrData; + HFSPlusAttrForkData forkData; + HFSPlusAttrExtents overflowExtents; +} HFSPlusAttrRecord; +AssertCompileSize(HFSPlusAttrRecord, 88); + +typedef struct HFSPlusAttrKey +{ + uint16_t keyLength; + uint16_t pad; + uint32_t fileID; + uint32_t startBlock; + uint16_t attrNameLen; + RTUTF16 attrName[kHFSMaxAttrNameLen]; +} HFSPlusAttrKey; +AssertCompileSize(HFSPlusAttrKey, 268); + +#pragma pack(1) +typedef struct HFSMasterDirectoryBlock +{ + uint16_t drSigWord; + uint32_t drCrDate; /**< Misaligned. */ + uint32_t drLsMod; /**< Misaligned. */ + uint16_t drAtrb; + uint16_t drNmFls; + uint16_t drVBMSt; + uint16_t drAllocPtr; + uint16_t drNmAlBlks; + uint32_t drAlBlkSiz; + uint32_t drClpSiz; + uint16_t drAlBlSt; + uint32_t drNxCNID; /**< Misaligned. */ + uint16_t drFreeBks; + uint8_t drVN[kHFSMaxVolumeNameChars + 1]; + uint32_t drVolBkUp; + uint16_t drVSeqNum; + uint32_t drWrCnt; /**< Misaligned. */ + uint32_t drXTClpSiz; /**< Misaligned. */ + uint32_t drCTClpSiz; /**< Misaligned. */ + uint16_t drNmRtDirs; + uint32_t drFilCnt; + uint32_t drDirCnt; + uint32_t drFndrInfo[8]; + uint16_t drEmbedSigWord; + HFSExtentDescriptor drEmbedExtent; + uint32_t drXTFlSize; /**< Misaligned. */ + HFSExtentRecord drXTExtRec; + uint32_t drCTFlSize; /**< Misaligned. */ + HFSExtentRecord drCTExtRec; +} HFSMasterDirectoryBlock; +#pragma pack() +AssertCompileSize(HFSMasterDirectoryBlock, 162); + +typedef struct HFSPlusVolumeHeader +{ + uint16_t signature; + uint16_t version; + uint32_t attributes; + uint32_t lastMountedVersion; + uint32_t journalInfoBlock; + uint32_t createDate; + uint32_t modifyDate; + uint32_t backupDate; + uint32_t checkedDate; + uint32_t fileCount; + uint32_t folderCount; + uint32_t blockSize; + uint32_t totalBlocks; + uint32_t freeBlocks; + uint32_t nextAllocation; + uint32_t rsrcClumpSize; + uint32_t dataClumpSize; + uint32_t nextCatalogID; + uint32_t writeCount; + uint64_t encodingsBitmap; + uint8_t finderInfo[32]; + HFSPlusForkData allocationFile; + HFSPlusForkData extentsFile; + HFSPlusForkData catalogFile; + HFSPlusForkData attributesFile; + HFSPlusForkData startupFile; +} HFSPlusVolumeHeader; +AssertCompileMemberAlignment(HFSPlusVolumeHeader, nextCatalogID, 8); +AssertCompileSize(HFSPlusVolumeHeader, 512); + +typedef union BTreeKey +{ + uint8_t length8; + uint16_t length16; + uint8_t rawData[kMaxKeyLength + 2]; +} BTreeKey; +AssertCompileSize(BTreeKey, 522); + +#pragma pack(1) +typedef struct BTNodeDescriptor +{ + uint32_t fLink; + uint32_t bLink; + int8_t kind; + uint8_t height; + uint16_t numRecords; + uint16_t reserved; /**< Causes struct size misalignment. */ +} BTNodeDescriptor; +#pragma pack() +AssertCompileSize(BTNodeDescriptor, 14); + +#pragma pack(1) +typedef struct BTHeaderRec +{ + uint16_t treeDepth; + uint32_t rootNode; /**< Misaligned. */ + uint32_t leafRecords; /**< Misaligned. */ + uint32_t firstLeafNode; /**< Misaligned. */ + uint32_t lastLeafNode; /**< Misaligned. */ + uint16_t nodeSize; + uint16_t maxKeyLength; + uint32_t totalNodes; /**< Misaligned. */ + uint32_t freeNodes; /**< Misaligned. */ + uint16_t reserved1; + uint32_t clumpSize; + uint8_t btreeType; + uint8_t keyCompareType; + uint32_t attributes; /**< Misaligned. */ + uint32_t reserved3[16]; /**< Misaligned. */ +} BTHeaderRec; +#pragma pack() +AssertCompileSize(BTHeaderRec, 106); + +#pragma pack(1) +typedef struct JournalInfoBlock +{ + uint32_t flags; + uint32_t devices_signature[8]; + uint64_t offset; /**< Misaligned (morons). */ + uint64_t size; /**< Misaligned. */ + char ext_jnl_uuid[37]; + char machine_serial_num[48]; + char reserved[JIB_RESERVED_SIZE]; +} JournalInfoBlock; +#pragma pack() +AssertCompileSize(JournalInfoBlock, 180); + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_hfs_h */ + diff --git a/include/iprt/formats/iso9660.h b/include/iprt/formats/iso9660.h new file mode 100644 index 00000000..6b3e7192 --- /dev/null +++ b/include/iprt/formats/iso9660.h @@ -0,0 +1,1516 @@ +/* $Id: iso9660.h $ */ +/** @file + * IPRT, ISO 9660 File System + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_iso9660_h +#define IPRT_INCLUDED_formats_iso9660_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_rt_formats_iso9660 ISO 9660 structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + + +/** The (default) logical sectors size of ISO 9660. */ +#define ISO9660_SECTOR_SIZE 2048 +/** The (default) sector offset mask of ISO 9660. */ +#define ISO9660_SECTOR_OFFSET_MASK 2047 +/** Maximum filename length (level 2 & 3). */ +#define ISO9660_MAX_NAME_LEN 30 + + +/** Accessor for ISO9660U16 and ISO9660U32 that retrievs the member value for + * the host endianess. */ +#ifdef RT_BIG_ENDIAN +# define ISO9660_GET_ENDIAN(a_pInt) ((a_pInt)->be) +#else +# define ISO9660_GET_ENDIAN(a_pInt) ((a_pInt)->le) +#endif + + +/** + * ISO 9660 16-bit unsigned integer type. + */ +typedef struct ISO9660U16 +{ + /** Little endian. */ + uint16_t le; + /** Big endian. */ + uint16_t be; +} ISO9660U16; +/** Pointer to an ISO 9660 16-bit unsigned integer type. */ +typedef ISO9660U16 *PISO9660U16; +/** Pointer to a const ISO 9660 16-bit unsigned integer type. */ +typedef ISO9660U16 const *PCISO9660U16; + +/** ISO 9660 big endian 16-bit unsigned integer. */ +typedef uint16_t ISO9660U16BE; + + +/** + * ISO 9660 32-bit unsigned integer type. + */ +typedef struct ISO9660U32 +{ + /** Little endian. */ + uint32_t le; + /** Big endian. */ + uint32_t be; +} ISO9660U32; +/** Pointer to an ISO 9660 32-bit unsigned integer type. */ +typedef ISO9660U32 *PISO9660U32; +/** Pointer to a const ISO 9660 32-bit unsigned integer type. */ +typedef ISO9660U32 const *PCISO9660U32; + +/** ISO 9660 little endian 32-bit unsigned integer. */ +typedef uint32_t ISO9660U32LE; +/** ISO 9660 big endian 32-bit unsigned integer. */ +typedef uint32_t ISO9660U32BE; + +/** + * ISO 9660 timestamp (date & time). + */ +typedef struct ISO9660TIMESTAMP +{ + /** 0x00: For digit year (0001-9999). */ + char achYear[4]; + /** 0x04: Month of the year (01-12). */ + char achMonth[2]; + /** 0x06: Day of month (01-31). */ + char achDay[2]; + /** 0x08: Hour of day (00-23). */ + char achHour[2]; + /** 0x0a: Minute of hour (00-59). */ + char achMinute[2]; + /** 0x0c: Second of minute (00-59). */ + char achSecond[2]; + /** 0x0e: Hundreth of second (00-99). */ + char achCentisecond[2]; + /** 0x10: The UTC (GMT) offset in 15 min units. */ + int8_t offUtc; +} ISO9660TIMESTAMP; +AssertCompileSize(ISO9660TIMESTAMP, 17); +/** Pointer to an ISO 9660 timestamp. */ +typedef ISO9660TIMESTAMP *PISO9660TIMESTAMP; +/** Pointer to a const ISO 9660 timestamp. */ +typedef ISO9660TIMESTAMP const *PCISO9660TIMESTAMP; + +/** + * ISO 9660 record timestamp (date & time). + */ +typedef struct ISO9660RECTIMESTAMP +{ + /** 0: Years since 1900. */ + uint8_t bYear; + /** 1: Month of year (1-12). */ + uint8_t bMonth; + /** 2: Day of month (1-31). */ + uint8_t bDay; + /** 3: Hour of day (0-23). */ + uint8_t bHour; + /** 4: Minute of hour (0-59). */ + uint8_t bMinute; + /** 5: Second of minute (0-59). */ + uint8_t bSecond; + /** 6: The UTC (GMT) offset in 15 min units. */ + int8_t offUtc; +} ISO9660RECTIMESTAMP; +AssertCompileSize(ISO9660RECTIMESTAMP, 7); +/** Pointer to an ISO 9660 record timestamp. */ +typedef ISO9660RECTIMESTAMP *PISO9660RECTIMESTAMP; +/** Pointer to a const ISO 9660 record timestamp. */ +typedef ISO9660RECTIMESTAMP const *PCISO9660RECTIMESTAMP; + + +/** + * ISO 9660 directory record. + */ +#pragma pack(1) +typedef struct ISO9660DIRREC +{ + /** 0x00: Length of this record in bytes. */ + uint8_t cbDirRec; + /** 0x01: Extended attribute record length in logical blocks. */ + uint8_t cExtAttrBlocks; + /** 0x02: Location of extent (logical block number). + * @note Misaligned. */ + ISO9660U32 offExtent; + /** 0x0a: Size of the data (file section). Does not include EAs. + * @note Misaligned. */ + ISO9660U32 cbData; + /** 0x12: Recording time and date. */ + ISO9660RECTIMESTAMP RecTime; + /** 0x19: File flags (ISO9660_FILE_FLAGS_XXX). */ + uint8_t fFileFlags; + /** 0x1a: File unit size for interlaved mode. */ + uint8_t bFileUnitSize; + /** 0x1b: Interlave gap size. */ + uint8_t bInterleaveGapSize; + /** 0x1c: Volume sequence number where the extent resides. */ + ISO9660U16 VolumeSeqNo; + /** 0x20: Length of file identifier field. */ + uint8_t bFileIdLength; + /** 0x21: File identifier (d-characters or d1-characters). */ + char achFileId[1]; + /* There are more fields following: + * - one byte optional padding so the following field is at an even boundrary. + * - system use field until cbDirRec is reached. + */ +} ISO9660DIRREC; +#pragma pack() +AssertCompileMemberOffset(ISO9660DIRREC, offExtent, 0x02); +AssertCompileMemberOffset(ISO9660DIRREC, cbData, 0x0a); +AssertCompileMemberOffset(ISO9660DIRREC, RecTime, 0x12); +AssertCompileMemberOffset(ISO9660DIRREC, fFileFlags, 0x19); +AssertCompileMemberOffset(ISO9660DIRREC, bFileIdLength, 0x20); +AssertCompileMemberOffset(ISO9660DIRREC, achFileId, 0x21); +/** Pointer to an ISO 9660 directory record. */ +typedef ISO9660DIRREC *PISO9660DIRREC; +/** Pointer to a const ISO 9660 directory record. */ +typedef ISO9660DIRREC const *PCISO9660DIRREC; + +/** @name ISO9660_FILE_FLAGS_XXX + * @{ */ +/** Existence - Hide the file from the user. */ +#define ISO9660_FILE_FLAGS_HIDDEN UINT8_C(0x01) +/** Directory - Indicates a directory as apposed to a regular file (0). */ +#define ISO9660_FILE_FLAGS_DIRECTORY UINT8_C(0x02) +/** Assocated File - Indicates that the file is an associated file. */ +#define ISO9660_FILE_FLAGS_ASSOCIATED_FILE UINT8_C(0x04) +/** Record - Indicates specified file content record format (see EAs). */ +#define ISO9660_FILE_FLAGS_RECORD UINT8_C(0x08) +/** Protection - Indicates owner/group or permission protection in EAs. */ +#define ISO9660_FILE_FLAGS_PROTECTION UINT8_C(0x10) +/** Reserved bit, MBZ. */ +#define ISO9660_FILE_FLAGS_RESERVED_5 UINT8_C(0x20) +/** Reserved bit, MBZ. */ +#define ISO9660_FILE_FLAGS_RESERVED_6 UINT8_C(0x40) +/** Multi-extend - Indicates that this isn't the final record for the file. + * @remarks Use for working around 4 GiB file size limitation. */ +#define ISO9660_FILE_FLAGS_MULTI_EXTENT UINT8_C(0x80) +/** @} */ + + +/** + * ISO 9660 path table record. + */ +#pragma pack(1) +typedef struct ISO9660PATHREC +{ + /** 0x00: Length of the achDirId field in bytes. */ + uint8_t cbDirId; + /** 0x01: Extended attribute record length in bytes? */ + uint8_t cbExtAttr; + /** 0x02: Location of extent (logical block number). + * @note Endianess depends on table. + * @note Misaligned. */ + uint32_t offExtent; + /** 0x06: Parent directory number. + * @note Endianess depends on table. */ + uint16_t idParentRec; + /** 0x08: Directory identifier (d-characters or d1-characters). */ + RT_FLEXIBLE_ARRAY_EXTENSION + char achDirId[RT_FLEXIBLE_ARRAY]; + /* There will be a zero padding byte following if the directory identifier length is odd. */ +} ISO9660PATHREC; +#pragma pack() +AssertCompileMemberOffset(ISO9660PATHREC, cbExtAttr, 0x01); +AssertCompileMemberOffset(ISO9660PATHREC, offExtent, 0x02); +AssertCompileMemberOffset(ISO9660PATHREC, idParentRec, 0x06); +AssertCompileMemberOffset(ISO9660PATHREC, achDirId, 0x08); +/** Pointer to an ISO 9660 path table record. */ +typedef ISO9660PATHREC *PISO9660PATHREC; +/** Pointer to a const ISO 9660 path table record. */ +typedef ISO9660PATHREC const *PCISO9660PATHREC; + + +/** + * ISO 9660 extended attribute record. + */ +typedef struct ISO9660EXATTRREC +{ + /** 0x000: The owner ID. */ + ISO9660U16 idOwner; + /** 0x004: The group ID. */ + ISO9660U16 idGroup; + /** 0x008: File permissions (ISO9660_PERM_XXX). */ + ISO9660U16BE fPermissions; + /** 0x00a: File creation timestamp. */ + ISO9660TIMESTAMP BirthTimestamp; + /** 0x01b: File modification timestamp. */ + ISO9660TIMESTAMP ModifyTimestamp; + /** 0x02c: File expiration timestamp. */ + ISO9660TIMESTAMP ExpireTimestamp; + /** 0x03d: File effective timestamp. */ + ISO9660TIMESTAMP EffectiveTimestamp; + /** 0x04e: Record format. */ + uint8_t bRecordFormat; + /** 0x04f: Record attributes. */ + uint8_t fRecordAttrib; + /** 0x050: Record length. */ + ISO9660U16 RecordLength; + /** 0x054: System identifier (a-characters or a1-characters). */ + char achSystemId[0x20]; + /** 0x074: System specific bytes. */ + uint8_t abSystemUse[64]; + /** 0x0b4: Extended attribute record version (ISO9660EXATTRREC_VERSION). */ + uint8_t bExtRecVersion; + /** 0x0b5: Length of escape sequences. */ + uint8_t cbEscapeSequences; + /** 0x0b6: Reserved for the future, MBZ. */ + uint8_t abReserved183[64]; + /** 0x0f6: Length of the application use field. */ + ISO9660U16 cbAppUse; + /** 0x0fa: Variable sized application use field. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abAppUse[RT_FLEXIBLE_ARRAY]; + /* This is followed by escape sequences with length given by cbEscapeSequnces. */ +} ISO9660EXATTRREC; +AssertCompileMemberOffset(ISO9660EXATTRREC, EffectiveTimestamp, 0x03d); +AssertCompileMemberOffset(ISO9660EXATTRREC, cbAppUse, 0x0f6); + +/** The ISO9660EXATTRREC::bExtRecVersion value. */ +#define ISO9660EXATTRREC_VERSION UINT8_C(0x01) + +/** @name ISO9660_PERM_XXX - ISO9660EXATTRREC::fPermissions + * @{ */ +/** @todo figure out this weird permission stuff... */ +/** @} */ + + +/** + * ISO 9660 volume descriptor header. + */ +typedef struct ISO9660VOLDESCHDR +{ + /** Descriptor type ISO9660VOLDESC_TYPE_XXX. */ + uint8_t bDescType; + /** Standard identifier 'CD001' */ + uint8_t achStdId[5]; + /** The descriptor version. */ + uint8_t bDescVersion; + /* (This is followed by the descriptor specific data). */ +} ISO9660VOLDESCHDR; +AssertCompileSize(ISO9660VOLDESCHDR, 7); +/** Pointer to a volume descriptor header. */ +typedef ISO9660VOLDESCHDR *PISO9660VOLDESCHDR; +/** Pointer to a const volume descriptor header. */ +typedef ISO9660VOLDESCHDR const *PCISO9660VOLDESCHDR; + +/** @name ISO9660VOLDESC_TYPE_XXX - volume descriptor types + * @{ */ +/** See ISO9660BOOTRECORD. */ +#define ISO9660VOLDESC_TYPE_BOOT_RECORD UINT8_C(0x00) +/** See ISO9660PRIMARYVOLDESC. */ +#define ISO9660VOLDESC_TYPE_PRIMARY UINT8_C(0x01) +/** See ISO9660SUPVOLDESC. */ +#define ISO9660VOLDESC_TYPE_SUPPLEMENTARY UINT8_C(0x02) +/** See ISO9660VOLPARTDESC. */ +#define ISO9660VOLDESC_TYPE_PARTITION UINT8_C(0x03) +/** Terminates the volume descriptor set. Has no data (zeros), version is 1. */ +#define ISO9660VOLDESC_TYPE_TERMINATOR UINT8_C(0xff) +/** @} */ + +/** The value of ISO9660VOLDESCHDR::achStdId */ +#define ISO9660VOLDESC_STD_ID "CD001" +#define ISO9660VOLDESC_STD_ID_0 'C' +#define ISO9660VOLDESC_STD_ID_1 'D' +#define ISO9660VOLDESC_STD_ID_2 '0' +#define ISO9660VOLDESC_STD_ID_3 '0' +#define ISO9660VOLDESC_STD_ID_4 '1' + + + +/** + * ISO 9660 boot record (volume descriptor). + */ +typedef struct ISO9660BOOTRECORD +{ + /** The volume descriptor header. + * Type is ISO9660VOLDESC_TYPE_BOOT_RECORD and version + * ISO9660BOOTRECORD_VERSION. */ + ISO9660VOLDESCHDR Hdr; + /** Boot system identifier string (a-characters). */ + char achBootSystemId[32]; + /** Boot identifier (a-characters). */ + char achBootId[32]; + /** Boot system specific content. */ + uint8_t abBootSystemSpecific[1977]; +} ISO9660BOOTRECORD; +AssertCompileSize(ISO9660BOOTRECORD, ISO9660_SECTOR_SIZE); +/** Pointer to an ISO 9660 boot record. */ +typedef ISO9660BOOTRECORD *PISO9660BOOTRECORD; +/** Pointer to a const ISO 9660 boot record. */ +typedef ISO9660BOOTRECORD const *PCISO9660BOOTRECORD; + +/** The value of ISO9660BOOTRECORD::Hdr.uDescVersion. */ +#define ISO9660BOOTRECORD_VERSION UINT8_C(1) + + +/** + * ISO 9660 boot record (volume descriptor), El Torito variant. + */ +#pragma pack(1) +typedef struct ISO9660BOOTRECORDELTORITO +{ + /** 0x000: The volume descriptor header. + * Type is ISO9660VOLDESC_TYPE_BOOT_RECORD and version + * ISO9660BOOTRECORD_VERSION. */ + ISO9660VOLDESCHDR Hdr; + /** 0x007: Boot system identifier string, + * zero padded ISO9660BOOTRECORDELTORITO_BOOT_SYSTEM_ID. */ + char achBootSystemId[32]; + /** 0x027: Boot identifier - all zeros. */ + char achBootId[32]; + /** 0x047: Boot catalog location (block offset), always (?) little endian. + * @note Misaligned. */ + uint32_t offBootCatalog; + /** 0x04b: Unused - all zeros. */ + uint8_t abBootSystemSpecific[1973]; +} ISO9660BOOTRECORDELTORITO; +#pragma pack() +AssertCompileSize(ISO9660BOOTRECORDELTORITO, ISO9660_SECTOR_SIZE); +/** Pointer to an ISO 9660 El Torito boot record. */ +typedef ISO9660BOOTRECORDELTORITO *PISO9660BOOTRECORDELTORITO; +/** Pointer to a const ISO 9660 El Torito boot record. */ +typedef ISO9660BOOTRECORDELTORITO const *PCISO9660BOOTRECORDELTORITO; + +/** The value of ISO9660BOOTRECORDELTORITO::achBootSystemId (zero padded). */ +#define ISO9660BOOTRECORDELTORITO_BOOT_SYSTEM_ID "EL TORITO SPECIFICATION" + + +/** + * ISO 9660 primary volume descriptor. + */ +typedef struct ISO9660PRIMARYVOLDESC +{ + /** 0x000: The volume descriptor header. + * Type is ISO9660VOLDESC_TYPE_PRIMARY and version + * ISO9660PRIMARYVOLDESC_VERSION. */ + ISO9660VOLDESCHDR Hdr; + /** 0x007: Explicit alignment zero padding. */ + uint8_t bPadding8; + /** 0x008: System identifier (a-characters). */ + char achSystemId[32]; + /** 0x028: Volume identifier (d-characters). */ + char achVolumeId[32]; + /** 0x048: Unused field, zero filled. */ + ISO9660U32 Unused73; + /** 0x050: Volume space size in logical blocks (cbLogicalBlock). */ + ISO9660U32 VolumeSpaceSize; + /** 0x058: Unused field(s), zero filled. */ + uint8_t abUnused89[32]; + /** 0x078: The number of volumes in the volume set. */ + ISO9660U16 cVolumesInSet; + /** 0x07c: Volume sequence number. */ + ISO9660U16 VolumeSeqNo; + /** 0x080: Logical block size in bytes. */ + ISO9660U16 cbLogicalBlock; + /** 0x084: Path table size. */ + ISO9660U32 cbPathTable; + /** 0x08c: Type L(ittle endian) path table location (block offset). */ + ISO9660U32LE offTypeLPathTable; + /** 0x090: Optional type L(ittle endian) path table location (block offset). */ + ISO9660U32LE offOptionalTypeLPathTable; + /** 0x094: Type M (big endian) path table location (block offset). */ + ISO9660U32BE offTypeMPathTable; + /** 0x098: Optional type M (big endian) path table location (block offset). */ + ISO9660U32BE offOptionalTypeMPathTable; + /** 0x09c: Directory entry for the root directory (union). */ + union + { + uint8_t ab[34]; + ISO9660DIRREC DirRec; + } RootDir; + /** 0x0be: Volume set identifier (d-characters). */ + char achVolumeSetId[128]; + /** 0x13e: Publisher identifier (a-characters). Alternatively, it may refere to + * a file in the root dir if it starts with 0x5f and restricts itself to 8 + * d-characters. */ + char achPublisherId[128]; + /** 0x1be: Data preparer identifier (a-characters). + * Same file reference alternative as previous field. */ + char achDataPreparerId[128]; + /** 0x23e: Application identifier (a-characters). + * Same file reference alternative as previous field. */ + char achApplicationId[128]; + /** 0x2be: Copyright (root) file identifier (d-characters). + * All spaces if none. */ + char achCopyrightFileId[37]; + /** 0x2e3: Abstract (root) file identifier (d-characters). + * All spaces if none. */ + char achAbstractFileId[37]; + /** 0x308: Bibliographic file identifier (d-characters). + * All spaces if none. */ + char achBibliographicFileId[37]; + /** 0x32d: Volume creation date and time. */ + ISO9660TIMESTAMP BirthTime; + /** 0x33e: Volume modification date and time. */ + ISO9660TIMESTAMP ModifyTime; + /** 0x34f: Volume (data) expiration date and time. + * If not specified, don't regard data as obsolete. */ + ISO9660TIMESTAMP ExpireTime; + /** 0x360: Volume (data) effective date and time. + * If not specified, info can be used immediately. */ + ISO9660TIMESTAMP EffectiveTime; + /** 0x371: File structure version (ISO9660_FILE_STRUCTURE_VERSION). */ + uint8_t bFileStructureVersion; + /** 0x372: Reserve for future, MBZ. */ + uint8_t bReserved883; + /** 0x373: Reserve for future. + * mkisofs & genisoimage & libisofs seems to space pad this most of the time. + * Microsoft image (2.56) zero pads it. isomd5sum uses it to store checksum + * info for the iso and space pads it. */ + uint8_t abAppUse[512]; + /** 0x573: Reserved for future standardization, MBZ. */ + uint8_t abReserved1396[653]; +} ISO9660PRIMARYVOLDESC; +AssertCompileSize(ISO9660PRIMARYVOLDESC, ISO9660_SECTOR_SIZE); +/** Pointer to a ISO 9660 primary volume descriptor. */ +typedef ISO9660PRIMARYVOLDESC *PISO9660PRIMARYVOLDESC; +/** Pointer to a const ISO 9660 primary volume descriptor. */ +typedef ISO9660PRIMARYVOLDESC const *PCISO9660PRIMARYVOLDESC; + +/** The value of ISO9660PRIMARYVOLDESC::Hdr.uDescVersion. */ +#define ISO9660PRIMARYVOLDESC_VERSION UINT8_C(1) +/** The value of ISO9660PRIMARYVOLDESC::bFileStructureVersion and + * ISO9660SUPVOLDESC::bFileStructureVersion. */ +#define ISO9660_FILE_STRUCTURE_VERSION UINT8_C(1) + + + +/** + * ISO 9660 supplementary volume descriptor. + * + * This is in the large parts identicial to the primary descriptor, except it + * have a few more fields where the primary one has reserved spaces. + */ +typedef struct ISO9660SUPVOLDESC +{ + /** 0x000: The volume descriptor header. + * Type is ISO9660VOLDESC_TYPE_SUPPLEMENTARY and version + * ISO9660SUPVOLDESC_VERSION. */ + ISO9660VOLDESCHDR Hdr; + /** 0x007: Volume flags (ISO9660SUPVOLDESC_VOL_F_XXX). + * @note This is reserved in the primary volume descriptor. */ + uint8_t fVolumeFlags; + /** 0x008: System identifier (a1-characters) of system that can act upon + * sectors 0 thru 15. + * @note Purpose differs from primary description. */ + char achSystemId[32]; + /** 0x028: Volume identifier (d1-characters). + * @note Character set differs from primary description. */ + char achVolumeId[32]; + /** 0x048: Unused field, zero filled. */ + ISO9660U32 Unused73; + /** 0x050: Volume space size in logical blocks (cbLogicalBlock). */ + ISO9660U32 VolumeSpaceSize; + /** 0x058: Escape sequences. + * Complicated stuff, see ISO 2022 and ECMA-35. + * @note This is reserved in the primary volume descriptor. */ + uint8_t abEscapeSequences[32]; + /** 0x078: The number of volumes in the volume set. */ + ISO9660U16 cVolumesInSet; + /** 0x07c: Volume sequence number. */ + ISO9660U16 VolumeSeqNo; + /** 0x080: Logical block size in bytes. */ + ISO9660U16 cbLogicalBlock; + /** 0x084: Path table size. */ + ISO9660U32 cbPathTable; + /** 0x08c: Type L(ittle endian) path table location (block offset). */ + ISO9660U32LE offTypeLPathTable; + /** 0x090: Optional type L(ittle endian) path table location (block offset). */ + ISO9660U32LE offOptionalTypeLPathTable; + /** 0x094: Type M (big endian) path table location (block offset). */ + ISO9660U32BE offTypeMPathTable; + /** 0x098: Optional type M (big endian) path table location (block offset). */ + ISO9660U32BE offOptionalTypeMPathTable; + /** 0x09c: Directory entry for the root directory (union). */ + union + { + uint8_t ab[34]; + ISO9660DIRREC DirRec; + } RootDir; + /** 0x0be: Volume set identifier (d1-characters). + * @note Character set differs from primary description. */ + char achVolumeSetId[128]; + /** 0x13e: Publisher identifier (a1-characters). Alternatively, it may refere + * to a file in the root dir if it starts with 0x5f and restricts itself to 8 + * d1-characters. + * @note Character set differs from primary description. */ + char achPublisherId[128]; + /** 0x1be: Data preparer identifier (a1-characters). + * Same file reference alternative as previous field. + * @note Character set differs from primary description. */ + char achDataPreparerId[128]; + /** 0x23e: Application identifier (a1-characters). + * Same file reference alternative as previous field. + * @note Character set differs from primary description. */ + char achApplicationId[128]; + /** 0x2be: Copyright (root) file identifier (d1-characters). + * All spaces if none. + * @note Character set differs from primary description. */ + char achCopyrightFileId[37]; + /** 0x2e3: Abstract (root) file identifier (d1-characters). + * All spaces if none. + * @note Character set differs from primary description. */ + char achAbstractFileId[37]; + /** 0x308: Bibliographic file identifier (d1-characters). + * All spaces if none. + * @note Character set differs from primary description. */ + char achBibliographicFileId[37]; + /** 0x32d: Volume creation date and time. */ + ISO9660TIMESTAMP BirthTime; + /** 0x33e: Volume modification date and time. */ + ISO9660TIMESTAMP ModifyTime; + /** 0x34f: Volume (data) expiration date and time. + * If not specified, don't regard data as obsolete. */ + ISO9660TIMESTAMP ExpireTime; + /** 0x360: Volume (data) effective date and time. + * If not specified, info can be used immediately. */ + ISO9660TIMESTAMP EffectiveTime; + /** 0x371: File structure version (ISO9660_FILE_STRUCTURE_VERSION). */ + uint8_t bFileStructureVersion; + /** 0x372: Reserve for future, MBZ. */ + uint8_t bReserved883; + /** 0x373: Reserve for future, MBZ. */ + uint8_t abAppUse[512]; + /** 0x573: Reserved for future standardization, MBZ. */ + uint8_t abReserved1396[653]; +} ISO9660SUPVOLDESC; +AssertCompileSize(ISO9660SUPVOLDESC, ISO9660_SECTOR_SIZE); +/** Pointer to a ISO 9660 supplementary volume descriptor. */ +typedef ISO9660SUPVOLDESC *PISO9660SUPVOLDESC; +/** Pointer to a const ISO 9660 supplementary volume descriptor. */ +typedef ISO9660SUPVOLDESC const *PCISO9660SUPVOLDESC; +/** The value of ISO9660SUPVOLDESC::Hdr.uDescVersion. */ +#define ISO9660SUPVOLDESC_VERSION UINT8_C(1) + +/** @name ISO9660SUPVOLDESC_VOL_F_XXX - ISO9660SUPVOLDESC::fVolumeFlags + * @{ */ +#define ISO9660SUPVOLDESC_VOL_F_ESC_ONLY_REG UINT8_C(0x00) +#define ISO9660SUPVOLDESC_VOL_F_ESC_NOT_REG UINT8_C(0x01) +/** @} */ + + + +/** + * ISO 9660 volume partition descriptor. + */ +typedef struct ISO9660VOLPARTDESC +{ + /** 0x000: The volume descriptor header. + * Type is ISO9660VOLDESC_TYPE_PARTITION and version + * ISO9660VOLPARTDESC_VERSION. */ + ISO9660VOLDESCHDR Hdr; + /** 0x007: Alignment padding. */ + uint8_t bPadding8; + /** 0x008: System identifier (a-characters). */ + char achSystemId[32]; + /** 0x028: Volume partition identifier (d-characters). */ + char achVolumePartitionId[32]; + /** 0x048: The location of the partition (logical block number). */ + ISO9660U32 offVolumePartition; + /** 0x050: The partition size in logical blocks (cbLogicalBlock). */ + ISO9660U32 VolumePartitionSize; + /** 0x058: System specific data. */ + uint8_t achSystemUse[1960]; +} ISO9660VOLPARTDESC; +AssertCompileSize(ISO9660VOLPARTDESC, ISO9660_SECTOR_SIZE); +/** Pointer to an ISO 9660 volume partition description. */ +typedef ISO9660VOLPARTDESC *PISO9660VOLPARTDESC; +/** Pointer to a const ISO 9660 volume partition description. */ +typedef ISO9660VOLPARTDESC const *PCISO9660VOLPARTDESC; +/** The value of ISO9660VOLPARTDESC::Hdr.uDescVersion. */ +#define ISO9660VOLPARTDESC_VERSION UINT8_C(1) + + + +/** @name Joliet escape sequence identifiers. + * + * These bytes appears in the supplementary volume descriptor field + * abEscapeSequences. The ISO9660SUPVOLDESC_VOL_F_ESC_NOT_REG flags will not + * be set. + * + * @{ */ +#define ISO9660_JOLIET_ESC_SEQ_0 UINT8_C(0x25) /**< First escape sequence byte.*/ +#define ISO9660_JOLIET_ESC_SEQ_1 UINT8_C(0x2f) /**< Second escape sequence byte.*/ +#define ISO9660_JOLIET_ESC_SEQ_2_LEVEL_1 UINT8_C(0x40) /**< Third escape sequence byte: level 1 */ +#define ISO9660_JOLIET_ESC_SEQ_2_LEVEL_2 UINT8_C(0x43) /**< Third escape sequence byte: level 2 */ +#define ISO9660_JOLIET_ESC_SEQ_2_LEVEL_3 UINT8_C(0x45) /**< Third escape sequence byte: level 3 */ +/** @} */ + + +/** The size of an El Torito boot catalog entry. */ +#define ISO9660_ELTORITO_ENTRY_SIZE UINT32_C(0x20) + +/** + * El Torito boot catalog: Validation entry. + * + * This is the first entry in the boot catalog. It is followed by a + * ISO9660ELTORITODEFAULTENTRY, which in turn is followed by a + * ISO9660ELTORITOSECTIONHEADER. + */ +typedef struct ISO9660ELTORITOVALIDATIONENTRY +{ + /** 0x00: The header ID (ISO9660_ELTORITO_HEADER_ID_VALIDATION_ENTRY). */ + uint8_t bHeaderId; + /** 0x01: The platform ID (ISO9660_ELTORITO_PLATFORM_ID_XXX). */ + uint8_t bPlatformId; + /** 0x02: Reserved, MBZ. */ + uint16_t u16Reserved; + /** 0x04: String ID of the developer of the CD/DVD-ROM. */ + char achId[24]; + /** 0x1c: The checksum. */ + uint16_t u16Checksum; + /** 0x1e: Key byte 1 (ISO9660_ELTORITO_KEY_BYTE_1). */ + uint8_t bKey1; + /** 0x1f: Key byte 2 (ISO9660_ELTORITO_KEY_BYTE_2). */ + uint8_t bKey2; +} ISO9660ELTORITOVALIDATIONENTRY; +AssertCompileSize(ISO9660ELTORITOVALIDATIONENTRY, ISO9660_ELTORITO_ENTRY_SIZE); +/** Pointer to an El Torito validation entry. */ +typedef ISO9660ELTORITOVALIDATIONENTRY *PISO9660ELTORITOVALIDATIONENTRY; +/** Pointer to a const El Torito validation entry. */ +typedef ISO9660ELTORITOVALIDATIONENTRY const *PCISO9660ELTORITOVALIDATIONENTRY; + +/** ISO9660ELTORITOVALIDATIONENTRY::bKey1 value. */ +#define ISO9660_ELTORITO_KEY_BYTE_1 UINT8_C(0x55) +/** ISO9660ELTORITOVALIDATIONENTRY::bKey2 value. */ +#define ISO9660_ELTORITO_KEY_BYTE_2 UINT8_C(0xaa) + + +/** @name ISO9660_ELTORITO_HEADER_ID_XXX - header IDs. + * @{ */ +/** Header ID for a ISO9660ELTORITOVALIDATIONENTRY. */ +#define ISO9660_ELTORITO_HEADER_ID_VALIDATION_ENTRY UINT8_C(0x01) +/** Header ID for a ISO9660ELTORITOSECTIONHEADER. */ +#define ISO9660_ELTORITO_HEADER_ID_SECTION_HEADER UINT8_C(0x90) +/** Header ID for the final ISO9660ELTORITOSECTIONHEADER. */ +#define ISO9660_ELTORITO_HEADER_ID_FINAL_SECTION_HEADER UINT8_C(0x91) +/** @} */ + + +/** @name ISO9660_ELTORITO_PLATFORM_ID_XXX - El Torito Platform IDs + * @{ */ +#define ISO9660_ELTORITO_PLATFORM_ID_X86 UINT8_C(0x00) /**< 80x86 */ +#define ISO9660_ELTORITO_PLATFORM_ID_PPC UINT8_C(0x01) /**< PowerPC */ +#define ISO9660_ELTORITO_PLATFORM_ID_MAC UINT8_C(0x02) /**< Mac */ +#define ISO9660_ELTORITO_PLATFORM_ID_EFI UINT8_C(0xef) /**< UEFI */ +/** @} */ + + +/** + * El Torito boot catalog: Section header entry. + * + * A non-final section header entry is followed by + * ISO9660ELTORITOSECTIONHEADER::cEntries ISO9660ELTORITOSECTIONTENTRY instances. + */ +typedef struct ISO9660ELTORITOSECTIONHEADER +{ + /** 0x00: Header ID - ISO9660_ELTORITO_HEADER_ID_SECTION_HEADER or + * ISO9660_ELTORITO_HEADER_ID_FINAL_SECTION_HEADER (if final). */ + uint8_t bHeaderId; + /** 0x01: The platform ID (ISO9660_ELTORITO_PLATFORM_ID_XXX). */ + uint8_t bPlatformId; + /** 0x02: Number of entries in this section (i.e. following this header). */ + uint16_t cEntries; + /** 0x04: String ID for the section. */ + char achSectionId[28]; +} ISO9660ELTORITOSECTIONHEADER; +AssertCompileSize(ISO9660ELTORITOSECTIONHEADER, ISO9660_ELTORITO_ENTRY_SIZE); +/** Pointer to an El Torito section header entry. */ +typedef ISO9660ELTORITOSECTIONHEADER *PISO9660ELTORITOSECTIONHEADER; +/** Pointer to a const El Torito section header entry. */ +typedef ISO9660ELTORITOSECTIONHEADER const *PCISO9660ELTORITOSECTIONHEADER; + + +/** + * El Torito boot catalog: Default (initial) entry. + * + * Followed by ISO9660ELTORITOSECTIONHEADER. + * + * Differs from ISO9660ELTORITOSECTIONENTRY in that it doesn't have a + * selection criteria and no media flags (only type). + */ +typedef struct ISO9660ELTORITODEFAULTENTRY +{ + /** 0x00: Boot indicator (ISO9660_ELTORITO_BOOT_INDICATOR_XXX). */ + uint8_t bBootIndicator; + /** 0x01: Boot media type. The first four bits are defined by + * ISO9660_ELTORITO_BOOT_MEDIA_TYPE_XXX, whereas the top four bits MBZ. */ + uint8_t bBootMediaType; + /** 0x02: Load segment - load address divided by 0x10. */ + uint16_t uLoadSeg; + /** 0x04: System type from image partition table. */ + uint8_t bSystemType; + /** 0x05: Unused, MBZ. */ + uint8_t bUnused; + /** 0x06: Number of emulated 512 byte sectors to load. */ + uint16_t cEmulatedSectorsToLoad; + /** 0x08: Image location in the ISO (block offset), always (?) little endian. */ + uint32_t offBootImage; + /** 0x0c: Reserved, MBZ */ + uint8_t abReserved[20]; +} ISO9660ELTORITODEFAULTENTRY; +AssertCompileSize(ISO9660ELTORITODEFAULTENTRY, ISO9660_ELTORITO_ENTRY_SIZE); +/** Pointer to an El Torito default (initial) entry. */ +typedef ISO9660ELTORITODEFAULTENTRY *PISO9660ELTORITODEFAULTENTRY; +/** Pointer to a const El Torito default (initial) entry. */ +typedef ISO9660ELTORITODEFAULTENTRY const *PCISO9660ELTORITODEFAULTENTRY; + + +/** + * El Torito boot catalg: Section entry. + */ +typedef struct ISO9660ELTORITOSECTIONENTRY +{ + /** 0x00: Boot indicator (ISO9660_ELTORITO_BOOT_INDICATOR_XXX). */ + uint8_t bBootIndicator; + /** 0x01: Boot media type and flags. The first four bits are defined by + * ISO9660_ELTORITO_BOOT_MEDIA_TYPE_XXX and the top four bits by + * ISO9660_ELTORITO_BOOT_MEDIA_F_XXX. */ + uint8_t bBootMediaType; + /** 0x02: Load segment - load address divided by 0x10. */ + uint16_t uLoadSeg; + /** 0x04: System type from image partition table. */ + uint8_t bSystemType; + /** 0x05: Unused, MBZ. */ + uint8_t bUnused; + /** 0x06: Number of emulated 512 byte sectors to load. */ + uint16_t cEmulatedSectorsToLoad; + /** 0x08: Image location in the ISO (block offset), always (?) little endian. */ + uint32_t offBootImage; + /** 0x0c: Selection criteria type (ISO9660_ELTORITO_SEL_CRIT_TYPE_XXX). */ + uint8_t bSelectionCriteriaType; + /** 0x0c: Selection criteria specific data. */ + uint8_t abSelectionCriteria[19]; +} ISO9660ELTORITOSECTIONENTRY; +AssertCompileSize(ISO9660ELTORITOSECTIONENTRY, ISO9660_ELTORITO_ENTRY_SIZE); +/** Pointer to an El Torito default (initial) entry. */ +typedef ISO9660ELTORITOSECTIONENTRY *PISO9660ELTORITOSECTIONENTRY; +/** Pointer to a const El Torito default (initial) entry. */ +typedef ISO9660ELTORITOSECTIONENTRY const *PCISO9660ELTORITOSECTIONENTRY; + + +/** @name ISO9660_ELTORITO_BOOT_INDICATOR_XXX - Boot indicators. + * @{ */ +#define ISO9660_ELTORITO_BOOT_INDICATOR_BOOTABLE UINT8_C(0x88) +#define ISO9660_ELTORITO_BOOT_INDICATOR_NOT_BOOTABLE UINT8_C(0x00) +/** @} */ + +/** @name ISO9660_ELTORITO_BOOT_MEDIA_TYPE_XXX - Boot media types. + * @{ */ +#define ISO9660_ELTORITO_BOOT_MEDIA_TYPE_NO_EMULATION UINT8_C(0x0) +#define ISO9660_ELTORITO_BOOT_MEDIA_TYPE_FLOPPY_1_2_MB UINT8_C(0x1) +#define ISO9660_ELTORITO_BOOT_MEDIA_TYPE_FLOPPY_1_44_MB UINT8_C(0x2) +#define ISO9660_ELTORITO_BOOT_MEDIA_TYPE_FLOPPY_2_88_MB UINT8_C(0x3) +#define ISO9660_ELTORITO_BOOT_MEDIA_TYPE_HARD_DISK UINT8_C(0x4) +#define ISO9660_ELTORITO_BOOT_MEDIA_TYPE_MASK UINT8_C(0xf) /**< The media type mask. */ +/** @} */ + +/** @name ISO9660_ELTORITO_BOOT_MEDIA_F_XXX - Boot media flags. + * These only applies to the section entry, not to the default (initial) entry. + * @{ */ +#define ISO9660_ELTORITO_BOOT_MEDIA_F_RESERVED UINT8_C(0x10) /**< Reserved bit, MBZ. */ +#define ISO9660_ELTORITO_BOOT_MEDIA_F_CONTINUATION UINT8_C(0x20) /**< Contiunation entry follows. */ +#define ISO9660_ELTORITO_BOOT_MEDIA_F_ATAPI_DRIVER UINT8_C(0x40) /**< Image contains an ATAPI driver. */ +#define ISO9660_ELTORITO_BOOT_MEDIA_F_SCSI_DRIVERS UINT8_C(0x80) /**< Image contains SCSI drivers. */ +#define ISO9660_ELTORITO_BOOT_MEDIA_F_MASK UINT8_C(0xf0) /**< The media/entry flag mask. */ +/** @} */ + +/** @name ISO9660_ELTORITO_SEL_CRIT_TYPE_XXX - Selection criteria type. + * @{ */ +#define ISO9660_ELTORITO_SEL_CRIT_TYPE_NONE UINT8_C(0x00) /**< No selection criteria */ +#define ISO9660_ELTORITO_SEL_CRIT_TYPE_LANG_AND_VERSION UINT8_C(0x01) /**< Language and version (IBM). */ +/** @} */ + + +/** + * El Torito boot catalog: Section entry extension. + * + * This is used for carrying additional selection criteria data. It follows + * a ISO9660ELTORITOSECTIONENTRY. + */ +typedef struct ISO9660ELTORITOSECTIONENTRYEXT +{ + /** 0x00: Extension indicator (ISO9660_ELTORITO_SECTION_ENTRY_EXT_ID). */ + uint8_t bExtensionId; + /** 0x01: Selection criteria extension flags (ISO9660_ELTORITO_SECTION_ENTRY_EXT_F_XXX). */ + uint8_t fFlags; + /** 0x02: Selection critiera data. */ + uint8_t abSelectionCriteria[30]; +} ISO9660ELTORITOSECTIONENTRYEXT; +AssertCompileSize(ISO9660ELTORITOSECTIONENTRYEXT, ISO9660_ELTORITO_ENTRY_SIZE); +/** Pointer to an El Torito default (initial) entry. */ +typedef ISO9660ELTORITOSECTIONENTRYEXT *PISO9660ELTORITOSECTIONENTRYEXT; +/** Pointer to a const El Torito default (initial) entry. */ +typedef ISO9660ELTORITOSECTIONENTRYEXT const *PCISO9660ELTORITOSECTIONENTRYEXT; + +/** Value of ISO9660ELTORITOSECTIONENTRYEXT::bExtensionId. */ +#define ISO9660_ELTORITO_SECTION_ENTRY_EXT_ID UINT8_C(0x44) + +/** @name ISO9660_ELTORITO_SECTION_ENTRY_EXT_F_XXX - ISO9660ELTORITOSECTIONENTRYEXT::fFlags + * @{ */ +#define ISO9660_ELTORITO_SECTION_ENTRY_EXT_F_MORE UINT8_C(0x20) /**< Further extension entries follows. */ +#define ISO9660_ELTORITO_SECTION_ENTRY_EXT_F_UNUSED_MASK UINT8_C(0xef) /**< Mask of all unused bits. */ +/** @} */ + + +/** + * Boot information table used by isolinux and GRUB2 El Torito boot files. + */ +typedef struct ISO9660SYSLINUXINFOTABLE +{ + /** 0x00/0x08: Offset of the primary volume descriptor (block offset). */ + uint32_t offPrimaryVolDesc; + /** 0x04/0x0c: Offset of the boot file (block offset). */ + uint32_t offBootFile; + /** 0x08/0x10: Size of the boot file in bytes. */ + uint32_t cbBootFile; + /** 0x0c/0x14: Boot file checksum. + * This is the sum of all the 32-bit words in the image, start at the end of + * this structure (i.e. offset 64). */ + uint32_t uChecksum; + /** 0x10/0x18: Reserved for future fun. */ + uint32_t auReserved[10]; +} ISO9660SYSLINUXINFOTABLE; +AssertCompileSize(ISO9660SYSLINUXINFOTABLE, 56); +/** Pointer to a syslinux boot information table. */ +typedef ISO9660SYSLINUXINFOTABLE *PISO9660SYSLINUXINFOTABLE; +/** Pointer to a const syslinux boot information table. */ +typedef ISO9660SYSLINUXINFOTABLE const *PCISO9660SYSLINUXINFOTABLE; + +/** The file offset of the isolinux boot info table. */ +#define ISO9660SYSLINUXINFOTABLE_OFFSET 8 + + + +/** + * System Use Sharing Protocol Protocol (SUSP) header. + */ +typedef struct ISO9660SUSPHDR +{ + /** Signature byte 1. */ + uint8_t bSig1; + /** Signature byte 2. */ + uint8_t bSig2; + /** Length of the entry (including the header). */ + uint8_t cbEntry; + /** Entry version number. */ + uint8_t bVersion; +} ISO9660SUSPHDR; +AssertCompileSize(ISO9660SUSPHDR, 4); +/** Pointer to a SUSP header. */ +typedef ISO9660SUSPHDR *PISO9660SUSPHDR; +/** Pointer to a const SUSP header. */ +typedef ISO9660SUSPHDR const *PCISO9660SUSPHDR; + + +/** + * SUSP continuation entry (CE). + */ +typedef struct ISO9660SUSPCE +{ + /** Header (ISO9660SUSPCE_SIG1, ISO9660SUSPCE_SIG2, ISO9660SUSPCE_VER). */ + ISO9660SUSPHDR Hdr; + /** The offset of the continutation data block (block offset). */ + ISO9660U32 offBlock; + /** The byte offset in the block of the contiuation data. */ + ISO9660U32 offData; + /** The size of the continuation data. */ + ISO9660U32 cbData; +} ISO9660SUSPCE; +/** Pointer to a SUSP continuation entry. */ +typedef ISO9660SUSPCE *PISO9660SUSPCE; +/** Pointer to a const SUSP continuation entry. */ +typedef ISO9660SUSPCE const *PCISO9660SUSPCE; +#define ISO9660SUSPCE_SIG1 'C' /**< SUSP continutation entry signature byte 1. */ +#define ISO9660SUSPCE_SIG2 'E' /**< SUSP continutation entry signature byte 2. */ +#define ISO9660SUSPCE_LEN 28 /**< SUSP continutation entry length. */ +#define ISO9660SUSPCE_VER 1 /**< SUSP continutation entry version number. */ +AssertCompileSize(ISO9660SUSPCE, ISO9660SUSPCE_LEN); + + +/** + * SUSP padding entry (PD). + */ +typedef struct ISO9660SUSPPD +{ + /** Header (ISO9660SUSPPD_SIG1, ISO9660SUSPPD_SIG2, ISO9660SUSPPD_VER). */ + ISO9660SUSPHDR Hdr; + /* Padding follows. */ +} ISO9660SUSPPD; +AssertCompileSize(ISO9660SUSPPD, 4); +/** Pointer to a SUSP padding entry. */ +typedef ISO9660SUSPPD *PISO9660SUSPPD; +/** Pointer to a const SUSP padding entry. */ +typedef ISO9660SUSPPD const *PCISO9660SUSPPD; +#define ISO9660SUSPPD_SIG1 'P' /**< SUSP padding entry signature byte 1. */ +#define ISO9660SUSPPD_SIG2 'D' /**< SUSP padding entry signature byte 2. */ +#define ISO9660SUSPPD_VER 1 /**< SUSP padding entry version number. */ + + +/** + * SUSP system use protocol entry (SP) + * + * This is only used in the '.' record of the root directory. + */ +typedef struct ISO9660SUSPSP +{ + /** Header (ISO9660SUSPSP_SIG1, ISO9660SUSPSP_SIG2, + * ISO9660SUSPSP_LEN, ISO9660SUSPSP_VER). */ + ISO9660SUSPHDR Hdr; + /** Check byte 1 (ISO9660SUSPSP_CHECK1). */ + uint8_t bCheck1; + /** Check byte 2 (ISO9660SUSPSP_CHECK2). */ + uint8_t bCheck2; + /** Number of bytes to skip within the system use field of each directory + * entry (except the '.' entry of the root, since that's where this is). */ + uint8_t cbSkip; +} ISO9660SUSPSP; +/** Pointer to a SUSP entry. */ +typedef ISO9660SUSPSP *PISO9660SUSPSP; +/** Pointer to a const SUSP entry. */ +typedef ISO9660SUSPSP const *PCISO9660SUSPSP; +#define ISO9660SUSPSP_SIG1 'S' /**< SUSP system use protocol entry signature byte 1. */ +#define ISO9660SUSPSP_SIG2 'P' /**< SUSP system use protocol entry signature byte 2. */ +#define ISO9660SUSPSP_VER 1 /**< SUSP system use protocol entry version number. */ +#define ISO9660SUSPSP_LEN 7 /**< SUSP system use protocol entry length (fixed). */ +#define ISO9660SUSPSP_CHECK1 UINT8_C(0xbe) /**< SUSP system use protocol entry check byte 1. */ +#define ISO9660SUSPSP_CHECK2 UINT8_C(0xef) /**< SUSP system use protocol entry check byte 2. */ +AssertCompileSize(ISO9660SUSPSP, ISO9660SUSPSP_LEN); + + +/** + * SUSP terminator entry (ST) + * + * Used to terminate system use entries. + */ +typedef struct ISO9660SUSPST +{ + /** Header (ISO9660SUSPST_SIG1, ISO9660SUSPST_SIG2, + * ISO9660SUSPST_LEN, ISO9660SUSPST_VER). */ + ISO9660SUSPHDR Hdr; +} ISO9660SUSPST; +/** Pointer to a SUSP padding entry. */ +typedef ISO9660SUSPST *PISO9660SUSPST; +/** Pointer to a const SUSP padding entry. */ +typedef ISO9660SUSPST const *PCISO9660SUSPST; +#define ISO9660SUSPST_SIG1 'S' /**< SUSP system use protocol entry signature byte 1. */ +#define ISO9660SUSPST_SIG2 'T' /**< SUSP system use protocol entry signature byte 2. */ +#define ISO9660SUSPST_VER 1 /**< SUSP system use protocol entry version number. */ +#define ISO9660SUSPST_LEN 4 /**< SUSP system use protocol entry length (fixed). */ +AssertCompileSize(ISO9660SUSPST, ISO9660SUSPST_LEN); + + +/** + * SUSP extension record entry (ER) + * + * This is only used in the '.' record of the root directory. There can be multiple of these. + */ +typedef struct ISO9660SUSPER +{ + /** Header (ISO9660SUSPER_SIG1, ISO9660SUSPER_SIG2, ISO9660SUSPER_VER). */ + ISO9660SUSPHDR Hdr; + /** The length of the identifier component. */ + uint8_t cchIdentifier; + /** The length of the description component. */ + uint8_t cchDescription; + /** The length of the source component. */ + uint8_t cchSource; + /** The extension version number. */ + uint8_t bVersion; + /** The payload: first @a cchIdentifier chars of identifier string, second + * @a cchDescription chars of description string, thrid @a cchSource chars + * of source string. Variable length. */ + char achPayload[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} ISO9660SUSPER; +/** Pointer to a SUSP padding entry. */ +typedef ISO9660SUSPER *PISO9660SUSPER; +/** Pointer to a const SUSP padding entry. */ +typedef ISO9660SUSPER const *PCISO9660SUSPER; +#define ISO9660SUSPER_SIG1 'E' /**< SUSP extension record entry signature byte 1. */ +#define ISO9660SUSPER_SIG2 'R' /**< SUSP extension record entry signature byte 2. */ +#define ISO9660SUSPER_VER 1 /**< SUSP extension record entry version number. */ +#define ISO9660SUSPER_OFF_PAYLOAD 8 /**< SUSP extension record entry payload member offset. */ +AssertCompileMemberOffset(ISO9660SUSPER, achPayload, ISO9660SUSPER_OFF_PAYLOAD); + +/** + * SUSP extension sequence entry (ES) + * + * This is only used in the '.' record of the root directory. + */ +typedef struct ISO9660SUSPES +{ + /** Header (ISO9660SUSPES_SIG1, ISO9660SUSPES_SIG2, ISO9660SUSPES_VER). */ + ISO9660SUSPHDR Hdr; + /** The ER entry sequence number of the extension comming first. */ + uint8_t iFirstExtension; +} ISO9660SUSPES; +/** Pointer to a SUSP padding entry. */ +typedef ISO9660SUSPES *PISO9660SUSPES; +/** Pointer to a const SUSP padding entry. */ +typedef ISO9660SUSPES const *PCISO9660SUSPES; +#define ISO9660SUSPES_SIG1 'E' /**< SUSP extension sequence entry signature byte 1. */ +#define ISO9660SUSPES_SIG2 'S' /**< SUSP extension sequence entry signature byte 2. */ +#define ISO9660SUSPES_VER 1 /**< SUSP extension sequence entry version number. */ +#define ISO9660SUSPES_LEN 5 /**< SUSP extension sequence entry length (fixed). */ +AssertCompileSize(ISO9660SUSPES, ISO9660SUSPES_LEN); + + +/** RRIP ER identifier string from Rock Ridge Interchange Protocol v1.10 specs. */ +#define ISO9660_RRIP_ID "RRIP_1991A" +/** RRIP ER recommended description string (from RRIP v1.10 specs). */ +#define ISO9660_RRIP_DESC "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS" +/** RRIP ER recommended source string (from RRIP v1.10 specs). */ +#define ISO9660_RRIP_SRC "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION." +/** RRIP ER version field value from the Rock Ridge Interchange Protocol v1.10 specs. */ +#define ISO9660_RRIP_VER 1 +/** The length of a RRIP v1.10 ER record. + * The record must be constructed using ISO9660_RRIP_ID, ISO9660_RRIP_DESC + * and ISO9660_RRIP_SRC. */ +#define ISO9660_RRIP_ER_LEN ((uint8_t)( ISO9660SUSPER_OFF_PAYLOAD \ + + sizeof(ISO9660_RRIP_ID) - 1 \ + + sizeof(ISO9660_RRIP_DESC) - 1 \ + + sizeof(ISO9660_RRIP_SRC) - 1 )) + +/** RRIP ER identifier string from RRIP IEEE P1282 v1.12 draft. */ +#define ISO9660_RRIP_1_12_ID "IEEE_P1282" +/** RRIP ER recommended description string (RRIP IEEE P1282 v1.12 draft). */ +#define ISO9660_RRIP_1_12_DESC "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS." +/** RRIP ER recommended source string (RRIP IEEE P1282 v1.12 draft). */ +#define ISO9660_RRIP_1_12_SRC "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION." +/** RRIP ER version field value from the Rock Ridge Interchange Protocol v1.12 specs. */ +#define ISO9660_RRIP_1_12_VER 1 +/** The length of a RRIP v1.12 ER record. + * The record must be constructed using ISO9660_RRIP_1_12_ID, + * ISO9660_RRIP_1_12_DESC and ISO9660_RRIP_1_12_SRC. */ +#define ISO9660_RRIP_1_12_ER_LEN ((uint8_t)( ISO9660SUSPER_OFF_PAYLOAD \ + + sizeof(ISO9660_RRIP_1_12_ID) - 1 \ + + sizeof(ISO9660_RRIP_1_12_DESC) - 1 \ + + sizeof(ISO9660_RRIP_1_12_SRC) - 1 )) + + +/** + * Rock ridge interchange protocol - RR. + */ +typedef struct ISO9660RRIPRR +{ + /** Header (ISO9660RRIPRR_SIG1, ISO9660RRIPRR_SIG2, + * ISO9660RRIPRR_LEN, ISO9660RRIPRR_VER). */ + ISO9660SUSPHDR Hdr; + /** Flags indicating which RRIP entries are present (). */ + uint8_t fFlags; +} ISO9660RRIPRR; +/** Pointer to a RRIP RR entry. */ +typedef ISO9660RRIPRR *PISO9660RRIPRR; +/** Pointer to a const RRIP RR entry. */ +typedef ISO9660RRIPRR const *PCISO9660RRIPRR; +#define ISO9660RRIPRR_SIG1 'R' /**< RRIP RR entry signature byte 1. */ +#define ISO9660RRIPRR_SIG2 'R' /**< RRIP RR entry signature byte 2. */ +#define ISO9660RRIPRR_VER 1 /**< RRIP RR entry version number. */ +#define ISO9660RRIPRR_LEN 5 /**< RRIP RR entry length (fixed). */ +AssertCompileSize(ISO9660RRIPRR, ISO9660RRIPRR_LEN); + +/** @name ISO9660RRIP_RR_F_XXX - Indicates which RRIP entries are present. + * @{ */ +#define ISO9660RRIP_RR_F_PX UINT8_C(0x01) +#define ISO9660RRIP_RR_F_PN UINT8_C(0x02) +#define ISO9660RRIP_RR_F_SL UINT8_C(0x04) +#define ISO9660RRIP_RR_F_NM UINT8_C(0x08) +#define ISO9660RRIP_RR_F_CL UINT8_C(0x10) +#define ISO9660RRIP_RR_F_PL UINT8_C(0x20) +#define ISO9660RRIP_RR_F_RE UINT8_C(0x40) +#define ISO9660RRIP_RR_F_TF UINT8_C(0x80) +/** @} */ + +/** + * Rock ridge interchange protocol - posix attribute entry (PX). + */ +typedef struct ISO9660RRIPPX +{ + /** Header (ISO9660RRIPPX_SIG1, ISO9660RRIPPX_SIG2, + * ISO9660RRIPPX_LEN, ISO9660RRIPPX_VER). */ + ISO9660SUSPHDR Hdr; + /** The file mode (RTFS_UNIX_XXX, RTFS_TYPE_XXX). */ + ISO9660U32 fMode; + /** Number of hardlinks. */ + ISO9660U32 cHardlinks; + /** User ID. */ + ISO9660U32 uid; + /** Group ID. */ + ISO9660U32 gid; + /** Inode number. */ + ISO9660U32 INode; +} ISO9660RRIPPX; +/** Pointer to a RRIP posix attribute entry. */ +typedef ISO9660RRIPPX *PISO9660RRIPPX; +/** Pointer to a const RRIP posix attribute entry. */ +typedef ISO9660RRIPPX const *PCISO9660RRIPPX; +#define ISO9660RRIPPX_SIG1 'P' /**< RRIP posix attribute entry signature byte 1. */ +#define ISO9660RRIPPX_SIG2 'X' /**< RRIP posix attribute entry signature byte 2. */ +#define ISO9660RRIPPX_VER 1 /**< RRIP posix attribute entry version number. */ +#define ISO9660RRIPPX_LEN 44 /**< RRIP posix attribute entry length (fixed). */ +AssertCompileSize(ISO9660RRIPPX, ISO9660RRIPPX_LEN); +#define ISO9660RRIPPX_LEN_NO_INODE 36 /**< RRIP posix attribute entry length without inode (fixed). */ + + +/** + * Rock ridge interchange protocol - timestamp entry (TF). + */ +typedef struct ISO9660RRIPTF +{ + /** Header (ISO9660RRIPTF_SIG1, ISO9660RRIPTF_SIG2, ISO9660RRIPTF_VER). */ + ISO9660SUSPHDR Hdr; + /** Flags, ISO9660RRIPTF_F_XXX. */ + uint8_t fFlags; + /** Timestamp payload bytes (variable size and format). */ + uint8_t abPayload[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} ISO9660RRIPTF; +AssertCompileMemberOffset(ISO9660RRIPTF, abPayload, 5); +/** Pointer to a RRIP timestamp entry. */ +typedef ISO9660RRIPTF *PISO9660RRIPTF; +/** Pointer to a const RRIP timestamp entry. */ +typedef ISO9660RRIPTF const *PCISO9660RRIPTF; +#define ISO9660RRIPTF_SIG1 'T' /**< RRIP child link entry signature byte 1. */ +#define ISO9660RRIPTF_SIG2 'F' /**< RRIP child link entry signature byte 2. */ +#define ISO9660RRIPTF_VER 1 /**< RRIP child link entry version number. */ + +/** @name ISO9660RRIPTF_F_XXX - Timestmap flags. + * @{ */ +#define ISO9660RRIPTF_F_BIRTH UINT8_C(0x01) /**< Birth (creation) timestamp is recorded. */ +#define ISO9660RRIPTF_F_MODIFY UINT8_C(0x02) /**< Modification timestamp is recorded. */ +#define ISO9660RRIPTF_F_ACCESS UINT8_C(0x04) /**< Accessed timestamp is recorded. */ +#define ISO9660RRIPTF_F_CHANGE UINT8_C(0x08) /**< Attribute change timestamp is recorded. */ +#define ISO9660RRIPTF_F_BACKUP UINT8_C(0x10) /**< Backup timestamp is recorded. */ +#define ISO9660RRIPTF_F_EXPIRATION UINT8_C(0x20) /**< Expiration timestamp is recorded. */ +#define ISO9660RRIPTF_F_EFFECTIVE UINT8_C(0x40) /**< Effective timestamp is recorded. */ +#define ISO9660RRIPTF_F_LONG_FORM UINT8_C(0x80) /**< If set ISO9660TIMESTAMP is used, otherwise ISO9660RECTIMESTAMP. */ +/** @} */ + +/** + * Calculates the length of a 'TF' entry given the flags. + * + * @returns Length in bytes. + * @param fFlags The flags (ISO9660RRIPTF_F_XXX). + */ +DECLINLINE(uint8_t) Iso9660RripTfCalcLength(uint8_t fFlags) +{ + unsigned cTimestamps = ((fFlags & ISO9660RRIPTF_F_BIRTH) != 0) + + ((fFlags & ISO9660RRIPTF_F_MODIFY) != 0) + + ((fFlags & ISO9660RRIPTF_F_ACCESS) != 0) + + ((fFlags & ISO9660RRIPTF_F_CHANGE) != 0) + + ((fFlags & ISO9660RRIPTF_F_BACKUP) != 0) + + ((fFlags & ISO9660RRIPTF_F_EXPIRATION) != 0) + + ((fFlags & ISO9660RRIPTF_F_EFFECTIVE) != 0); + return (uint8_t)( cTimestamps * (fFlags & ISO9660RRIPTF_F_LONG_FORM ? sizeof(ISO9660TIMESTAMP) : sizeof(ISO9660RECTIMESTAMP)) + + RT_OFFSETOF(ISO9660RRIPTF, abPayload)); +} + + +/** + * Rock ridge interchange protocol - posix device number entry (PN). + * + * Mandatory for block or character devices. + */ +typedef struct ISO9660RRIPPN +{ + /** Header (ISO9660RRIPPN_SIG1, ISO9660RRIPPN_SIG2, + * ISO9660RRIPPN_LEN, ISO9660RRIPPN_VER). */ + ISO9660SUSPHDR Hdr; + /** The major device number. */ + ISO9660U32 Major; + /** The minor device number. */ + ISO9660U32 Minor; +} ISO9660RRIPPN; +/** Pointer to a RRIP posix attribute entry. */ +typedef ISO9660RRIPPN *PISO9660RRIPPN; +/** Pointer to a const RRIP posix attribute entry. */ +typedef ISO9660RRIPPN const *PCISO9660RRIPPN; +#define ISO9660RRIPPN_SIG1 'P' /**< RRIP posix device number entry signature byte 1. */ +#define ISO9660RRIPPN_SIG2 'N' /**< RRIP posix device number entry signature byte 2. */ +#define ISO9660RRIPPN_VER 1 /**< RRIP posix device number entry version number. */ +#define ISO9660RRIPPN_LEN 20 /**< RRIP posix device number entry length (fixed). */ +AssertCompileSize(ISO9660RRIPPN, ISO9660RRIPPN_LEN); + +/** + * Rock ridge interchange protocol - symlink entry (SL). + * + * Mandatory for symbolic links. + */ +typedef struct ISO9660RRIPSL +{ + /** Header (ISO9660RRIPSL_SIG1, ISO9660RRIPSL_SIG2, ISO9660RRIPSL_VER). */ + ISO9660SUSPHDR Hdr; + /** Flags (0 or ISO9660RRIP_SL_F_CONTINUE). */ + uint8_t fFlags; + /** Variable length of components. First byte in each component is a + * combination of ISO9660RRIP_SL_C_XXX flag values. The second byte the + * length of character data following it. */ + uint8_t abComponents[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} ISO9660RRIPSL; +AssertCompileMemberOffset(ISO9660RRIPSL, abComponents, 5); +/** Pointer to a RRIP symbolic link entry. */ +typedef ISO9660RRIPSL *PISO9660RRIPSL; +/** Pointer to a const RRIP symbolic link entry. */ +typedef ISO9660RRIPSL const *PCISO9660RRIPSL; +#define ISO9660RRIPSL_SIG1 'S' /**< RRIP symbolic link entry signature byte 1. */ +#define ISO9660RRIPSL_SIG2 'L' /**< RRIP symbolic link entry signature byte 2. */ +#define ISO9660RRIPSL_VER 1 /**< RRIP symbolic link entry version number. */ +/** ISO9660RRIPSL.fFlags - When set another symlink entry follows this one. */ +#define ISO9660RRIP_SL_F_CONTINUE UINT8_C(0x01) +/** @name ISO9660RRIP_SL_C_XXX - Symlink component flags. + * @note These matches ISO9660RRIP_NM_F_XXX. + * @{ */ +/** Indicates that the component continues in the next entry. */ +#define ISO9660RRIP_SL_C_CONTINUE UINT8_C(0x01) +/** Refer to '.' (the current dir). */ +#define ISO9660RRIP_SL_C_CURRENT UINT8_C(0x02) +/** Refer to '..' (the parent dir). */ +#define ISO9660RRIP_SL_C_PARENT UINT8_C(0x04) +/** Refer to '/' (the root dir). */ +#define ISO9660RRIP_SL_C_ROOT UINT8_C(0x08) +/** Reserved / historically was mount point reference. */ +#define ISO9660RRIP_SL_C_MOUNT_POINT UINT8_C(0x10) +/** Reserved / historically was uname network node name. */ +#define ISO9660RRIP_SL_C_UNAME UINT8_C(0x20) +/** Reserved mask (considers historically bits reserved). */ +#define ISO9660RRIP_SL_C_RESERVED_MASK UINT8_C(0xf0) +/** @} */ + + +/** + * Rock ridge interchange protocol - name entry (NM). + */ +typedef struct ISO9660RRIPNM +{ + /** Header (ISO9660RRIPNM_SIG1, ISO9660RRIPNM_SIG2, ISO9660RRIPNM_VER). */ + ISO9660SUSPHDR Hdr; + /** Flags (ISO9660RRIP_NM_F_XXX). */ + uint8_t fFlags; + /** The name part (if any). */ + char achName[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} ISO9660RRIPNM; +AssertCompileMemberOffset(ISO9660RRIPNM, achName, 5); +/** Pointer to a RRIP name entry. */ +typedef ISO9660RRIPNM *PISO9660RRIPNM; +/** Pointer to a const RRIP name entry. */ +typedef ISO9660RRIPNM const *PCISO9660RRIPNM; +#define ISO9660RRIPNM_SIG1 'N' /**< RRIP name entry signature byte 1. */ +#define ISO9660RRIPNM_SIG2 'M' /**< RRIP name entry signature byte 2. */ +#define ISO9660RRIPNM_VER 1 /**< RRIP name entry version number. */ +/** @name ISO9660RRIP_NM_F_XXX - Name flags. + * @note These matches ISO9660RRIP_SL_C_XXX. + * @{ */ +/** Indicates there are more 'NM' entries. */ +#define ISO9660RRIP_NM_F_CONTINUE UINT8_C(0x01) +/** Refer to '.' (the current dir). */ +#define ISO9660RRIP_NM_F_CURRENT UINT8_C(0x02) +/** Refer to '..' (the parent dir). */ +#define ISO9660RRIP_NM_F_PARENT UINT8_C(0x04) +/** Reserved / historically was uname network node name. */ +#define ISO9660RRIP_NM_F_UNAME UINT8_C(0x20) +/** Reserved mask (considers historical bits reserved). */ +#define ISO9660RRIP_NM_F_RESERVED_MASK UINT8_C(0xf8) +/** @} */ + +/** Maximum name length in one 'NM' entry. */ +#define ISO9660RRIPNM_MAX_NAME_LEN 250 + + +/** + * Rock ridge interchange protocol - child link entry (CL). + * + * This is used for relocated directories. Relocated directries are employed + * to bypass the ISO 9660 maximum tree depth of 8. + * + * The size of the directory and everything else is found in the '.' entry in + * the specified location. Only the name (NM or dir rec) and this link record + * should be used. + */ +typedef struct ISO9660RRIPCL +{ + /** Header (ISO9660RRIPCL_SIG1, ISO9660RRIPCL_SIG2, + * ISO9660RRIPCL_LEN, ISO9660RRIPCL_VER). */ + ISO9660SUSPHDR Hdr; + /** The offset of the directory data (block offset). */ + ISO9660U32 offExtend; +} ISO9660RRIPCL; +/** Pointer to a RRIP child link entry. */ +typedef ISO9660RRIPCL *PISO9660RRIPCL; +/** Pointer to a const RRIP child link entry. */ +typedef ISO9660RRIPCL const *PCISO9660RRIPCL; +#define ISO9660RRIPCL_SIG1 'C' /**< RRIP child link entry signature byte 1. */ +#define ISO9660RRIPCL_SIG2 'L' /**< RRIP child link entry signature byte 2. */ +#define ISO9660RRIPCL_VER 1 /**< RRIP child link entry version number. */ +#define ISO9660RRIPCL_LEN 12 /**< RRIP child link entry length. */ +AssertCompileSize(ISO9660RRIPCL, ISO9660RRIPCL_LEN); + + +/** + * Rock ridge interchange protocol - parent link entry (PL). + * + * This is used in relocated directories. Relocated directries are employed + * to bypass the ISO 9660 maximum tree depth of 8. + * + * The size of the directory and everything else is found in the '.' entry in + * the specified location. Only the name (NM or dir rec) and this link record + * should be used. + */ +typedef struct ISO9660RRIPPL +{ + /** Header (ISO9660RRIPPL_SIG1, ISO9660RRIPPL_SIG2, + * ISO9660RRIPPL_LEN, ISO9660RRIPPL_VER). */ + ISO9660SUSPHDR Hdr; + /** The offset of the directory data (block offset). */ + ISO9660U32 offExtend; +} ISO9660RRIPPL; +/** Pointer to a RRIP parent link entry. */ +typedef ISO9660RRIPPL *PISO9660RRIPPL; +/** Pointer to a const RRIP parent link entry. */ +typedef ISO9660RRIPPL const *PCISO9660RRIPPL; +#define ISO9660RRIPPL_SIG1 'P' /**< RRIP parent link entry signature byte 1. */ +#define ISO9660RRIPPL_SIG2 'L' /**< RRIP parent link entry signature byte 2. */ +#define ISO9660RRIPPL_VER 1 /**< RRIP parent link entry version number. */ +#define ISO9660RRIPPL_LEN 12 /**< RRIP parent link entry length. */ +AssertCompileSize(ISO9660RRIPPL, ISO9660RRIPPL_LEN); + + +/** + * Rock ridge interchange protocol - relocated entry (RE). + * + * This is used in the directory record for a relocated directory in the + * holding place high up in the directory hierarchy. The system may choose to + * ignore/hide entries with this entry present. + */ +typedef struct ISO9660RRIPRE +{ + /** Header (ISO9660RRIPRE_SIG1, ISO9660RRIPRE_SIG2, + * ISO9660RRIPRE_LEN, ISO9660RRIPRE_VER). */ + ISO9660SUSPHDR Hdr; +} ISO9660RRIPRE; +/** Pointer to a RRIP parent link entry. */ +typedef ISO9660RRIPRE *PISO9660RRIPRE; +/** Pointer to a const RRIP parent link entry. */ +typedef ISO9660RRIPRE const *PCISO9660RRIPRE; +#define ISO9660RRIPRE_SIG1 'R' /**< RRIP relocated entry signature byte 1. */ +#define ISO9660RRIPRE_SIG2 'E' /**< RRIP relocated entry signature byte 2. */ +#define ISO9660RRIPRE_VER 1 /**< RRIP relocated entry version number. */ +#define ISO9660RRIPRE_LEN 4 /**< RRIP relocated entry length. */ +AssertCompileSize(ISO9660RRIPRE, ISO9660RRIPRE_LEN); + + +/** + * Rock ridge interchange protocol - sparse file entry (SF). + */ +#pragma pack(1) +typedef struct ISO9660RRIPSF +{ + /** Header (ISO9660RRIPSF_SIG1, ISO9660RRIPSF_SIG2, + * ISO9660RRIPSF_LEN, ISO9660RRIPSF_VER). */ + ISO9660SUSPHDR Hdr; + /** The high 32-bits of the 64-bit sparse file size. */ + ISO9660U32 cbSparseHi; + /** The low 32-bits of the 64-bit sparse file size. */ + ISO9660U32 cbSparseLo; + /** The table depth. */ + uint8_t cDepth; +} ISO9660RRIPSF; +#pragma pack() +/** Pointer to a RRIP symbolic link entry. */ +typedef ISO9660RRIPSF *PISO9660RRIPSF; +/** Pointer to a const RRIP symbolic link entry. */ +typedef ISO9660RRIPSF const *PCISO9660RRIPSF; +#define ISO9660RRIPSF_SIG1 'S' /**< RRIP spare file entry signature byte 1. */ +#define ISO9660RRIPSF_SIG2 'F' /**< RRIP spare file entry signature byte 2. */ +#define ISO9660RRIPSF_VER 1 /**< RRIP spare file entry version number. */ +#define ISO9660RRIPSF_LEN 21 /**< RRIP spare file entry length. */ +AssertCompileSize(ISO9660RRIPSF, ISO9660RRIPSF_LEN); + +/** @name ISO9660RRIP_SF_TAB_F_XXX - Sparse table format. + * @{ */ +/** The 24-bit logical block number mask. + * This is somewhat complicated, see docs. MBZ for EMPTY. */ +#define ISO9660RRIP_SF_TAB_F_BLOCK_MASK UINT32_C(0x00ffffff) +/** Reserved bits, MBZ. */ +#define ISO9660RRIP_SF_TAB_F_RESERVED RT_BIT_32() +/** References a sub-table with 256 entries (ISO9660U32). */ +#define ISO9660RRIP_SF_TAB_F_TABLE RT_BIT_32(30) +/** Zero data region. */ +#define ISO9660RRIP_SF_TAB_F_EMPTY RT_BIT_32(31) +/** @} */ + + +/** + * SUSP and RRIP union. + */ +typedef union ISO9660SUSPUNION +{ + ISO9660SUSPHDR Hdr; /**< SUSP header . */ + ISO9660SUSPCE CE; /**< SUSP continuation entry. */ + ISO9660SUSPPD PD; /**< SUSP padding entry. */ + ISO9660SUSPSP SP; /**< SUSP system use protocol entry. */ + ISO9660SUSPST ST; /**< SUSP terminator entry. */ + ISO9660SUSPER ER; /**< SUSP extension record entry. */ + ISO9660SUSPES ES; /**< SUSP extension sequence entry. */ + ISO9660RRIPRR RR; /**< RRIP optimization entry. */ + ISO9660RRIPPX PX; /**< RRIP posix attribute entry. */ + ISO9660RRIPTF TF; /**< RRIP timestamp entry. */ + ISO9660RRIPPN PN; /**< RRIP posix device number entry. */ + ISO9660RRIPSF SF; /**< RRIP sparse file entry. */ + ISO9660RRIPSL SL; /**< RRIP symbolic link entry. */ + ISO9660RRIPNM NM; /**< RRIP name entry. */ + ISO9660RRIPCL CL; /**< RRIP child link entry. */ + ISO9660RRIPPL PL; /**< RRIP parent link entry. */ + ISO9660RRIPRE RE; /**< RRIP relocated entry. */ +} ISO9660SUSPUNION; +/** Pointer to a SUSP and RRIP union. */ +typedef ISO9660SUSPUNION *PISO9660SUSPUNION; +/** Pointer to a const SUSP and RRIP union. */ +typedef ISO9660SUSPUNION *PCISO9660SUSPUNION; + + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_iso9660_h */ + diff --git a/include/iprt/formats/lx.h b/include/iprt/formats/lx.h new file mode 100644 index 00000000..b01a5ab8 --- /dev/null +++ b/include/iprt/formats/lx.h @@ -0,0 +1,510 @@ +/* $Id: lx.h $ */ +/** @file + * LX structures, types and defines. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef IPRT_INCLUDED_formats_lx_h +#define IPRT_INCLUDED_formats_lx_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_formats_lx LX executable format (OS/2) + * @ingroup grp_rt_formats + * @{ */ + +#ifndef IMAGE_OS2_SIGNATURE_LX +/** LX signature ("LX") */ +# define IMAGE_LX_SIGNATURE K_LE2H_U16('L' | ('X' << 8)) +#endif + +/** + * Linear eXecutable header. + * This structure is exactly 196 bytes long. + */ +typedef struct e32_exe +{ + uint8_t e32_magic[2]; + uint8_t e32_border; + uint8_t e32_worder; + uint32_t e32_level; + uint16_t e32_cpu; + uint16_t e32_os; + uint32_t e32_ver; + uint32_t e32_mflags; + uint32_t e32_mpages; + uint32_t e32_startobj; + uint32_t e32_eip; + uint32_t e32_stackobj; + uint32_t e32_esp; + uint32_t e32_pagesize; + uint32_t e32_pageshift; + /** The size of the fixup section. + * The fixup section consists of the fixup page table, the fixup record table, + * the import module table, and the import procedure name table. + */ + uint32_t e32_fixupsize; + uint32_t e32_fixupsum; + /** The size of the resident loader section. + * This includes the object table, the object page map table, the resource table, the resident name table, + * the entry table, the module format directives table, and the page checksum table (?). */ + uint32_t e32_ldrsize; + /** The checksum of the loader section. 0 if not calculated. */ + uint32_t e32_ldrsum; + /** The offset of the object table relative to this structure. */ + uint32_t e32_objtab; + /** Count of objects. */ + uint32_t e32_objcnt; + /** The offset of the object page map table relative to this structure. */ + uint32_t e32_objmap; + /** The offset of the object iterated pages (whatever this is used for) relative to the start of the file. */ + uint32_t e32_itermap; + /** The offset of the resource table relative to this structure. */ + uint32_t e32_rsrctab; + /** The number of entries in the resource table. */ + uint32_t e32_rsrccnt; + /** The offset of the resident name table relative to this structure. */ + uint32_t e32_restab; + /** The offset of the entry (export) table relative to this structure. */ + uint32_t e32_enttab; + /** The offset of the module format directives table relative to this structure. */ + uint32_t e32_dirtab; + /** The number of entries in the module format directives table. */ + uint32_t e32_dircnt; + /** The offset of the fixup page table relative to this structure. */ + uint32_t e32_fpagetab; + /** The offset of the fixup record table relative to this structure. */ + uint32_t e32_frectab; + /** The offset of the import module name table relative to this structure. */ + uint32_t e32_impmod; + /** The number of entries in the import module name table. */ + uint32_t e32_impmodcnt; + /** The offset of the import procedure name table relative to this structure. */ + uint32_t e32_impproc; + /** The offset of the page checksum table relative to this structure. */ + uint32_t e32_pagesum; + /** The offset of the data pages relative to the start of the file. */ + uint32_t e32_datapage; + /** The number of preload pages (ignored). */ + uint32_t e32_preload; + /** The offset of the non-resident name table relative to the start of the file. */ + uint32_t e32_nrestab; + /** The size of the non-resident name table. */ + uint32_t e32_cbnrestab; + uint32_t e32_nressum; + uint32_t e32_autodata; + uint32_t e32_debuginfo; + uint32_t e32_debuglen; + uint32_t e32_instpreload; + uint32_t e32_instdemand; + uint32_t e32_heapsize; + uint32_t e32_stacksize; + uint8_t e32_res3[20]; +} e32_exe; +AssertCompileSize(struct e32_exe, 196); + +/** e32_magic[0] */ +#define E32MAGIC1 'L' +/** e32_magic[1] */ +#define E32MAGIC2 'X' +/** MAKEWORD(e32_magic[0], e32_magic[1]) */ +#define E32MAGIC 0x584c +/** e32_border - little endian */ +#define E32LEBO 0 +/** e32_border - big endian */ +#define E32BEBO 1 +/** e32_worder - little endian */ +#define E32LEWO 0 +/** e32_worder - big endian */ +#define E32BEWO 1 +/** e32_level */ +#define E32LEVEL UINT32_C(0) +/** e32_cpu - 80286 */ +#define E32CPU286 1 +/** e32_cpu - 80386 */ +#define E32CPU386 2 +/** e32_cpu - 80486 */ +#define E32CPU486 3 +/** e32_pagesize */ +#define OBJPAGELEN UINT32_C(0x1000) + + +/** @name e32_mflags + * @{ */ +/** App Type: Fullscreen only. */ +#define E32NOPMW UINT32_C(0x00000100) +/** App Type: PM API. */ +#define E32PMAPI UINT32_C(0x00000300) +/** App Type: PM VIO compatible. */ +#define E32PMW UINT32_C(0x00000200) +/** Application type mask. */ +#define E32APPMASK UINT32_C(0x00000300) +/** Executable module. */ +#define E32MODEXE UINT32_C(0x00000000) +/** Dynamic link library (DLL / library) module. */ +#define E32MODDLL UINT32_C(0x00008000) +/** Protected memory DLL. */ +#define E32PROTDLL UINT32_C(0x00010000) +/** Physical Device Driver. */ +#define E32MODPDEV UINT32_C(0x00020000) +/** Virtual Device Driver. */ +#define E32MODVDEV UINT32_C(0x00028000) +/** Device driver */ +#define E32DEVICE E32MODPDEV +/** Dynamic link library (DLL / library) module. */ +#define E32NOTP E32MODDLL +/** Protected memory DLL. */ +#define E32MODPROTDLL (E32MODDLL | E32PROTDLL) +/** Module Type mask. */ +#define E32MODMASK UINT32_C(0x00038000) +/** Not loadable (linker error). */ +#define E32NOLOAD UINT32_C(0x00002000) +/** No internal fixups. */ +#define E32NOINTFIX UINT32_C(0x00000010) +/** No external fixups (i.e. imports). */ +#define E32NOEXTFIX UINT32_C(0x00000020) +/** System DLL, no internal fixups. */ +#define E32SYSDLL UINT32_C(0x00000008) +/** Global (set) or per instance (cleared) library initialization. */ +#define E32LIBINIT UINT32_C(0x00000004) +/** Global (set) or per instance (cleared) library termination. */ +#define E32LIBTERM UINT32_C(0x40000000) +/** Indicates when set in an executable that the process isn't SMP safe. */ +#define E32NOTMPSAFE UINT32_C(0x00080000) +/** @} */ + + +/** @defgroup grp_rt_formats_lx_relocs Relocations (aka Fixups). + * @{ */ +typedef union r32_offset +{ + uint16_t offset16; + uint32_t offset32; +} r32_offset; +AssertCompileSize(r32_offset, 4); + +/** A relocation. + * @remark this structure isn't very usable since LX relocations comes in too many size variations. + */ +#pragma pack(1) +typedef struct r32_rlc +{ + uint8_t nr_stype; + uint8_t nr_flags; + int16_t r32_soff; + uint16_t r32_objmod; + + union targetid + { + r32_offset intref; + union extfixup + { + r32_offset proc; + uint32_t ord; + } extref; + struct addfixup + { + uint16_t entry; + r32_offset addval; + } addfix; + } r32_target; + uint16_t r32_srccount; + uint16_t r32_chain; +} r32_rlc; +#pragma pack() +AssertCompileSize(r32_rlc, 16); +/** @} */ + +/** @name Some attempt at size constanstants. + * @{ + */ +#define RINTSIZE16 8 +#define RINTSIZE32 10 +#define RORDSIZE 8 +#define RNAMSIZE16 8 +#define RNAMSIZE32 10 +#define RADDSIZE16 10 +#define RADDSIZE32 12 +/** @} */ + +/** @name nr_stype (source flags) + * @{ */ +#define NRSBYT 0x00 +#define NRSSEG 0x02 +#define NRSPTR 0x03 +#define NRSOFF 0x05 +#define NRPTR48 0x06 +#define NROFF32 0x07 +#define NRSOFF32 0x08 +#define NRSTYP 0x0f +#define NRSRCMASK 0x0f +#define NRALIAS 0x10 +#define NRCHAIN 0x20 +/** @} */ + +/** @name nr_flags (target flags) + * @{ */ +#define NRRINT 0x00 +#define NRRORD 0x01 +#define NRRNAM 0x02 +#define NRRENT 0x03 +#define NRRTYP 0x03 +#define NRADD 0x04 +#define NRICHAIN 0x08 +#define NR32BITOFF 0x10 +#define NR32BITADD 0x20 +#define NR16OBJMOD 0x40 +#define NR8BITORD 0x80 +/** @} */ + +/** @} */ + + +/** @defgroup grp_rt_formats_lx_object_tab The Object Table (aka segment table) + * @{ */ + +/** The Object Table Entry. */ +typedef struct o32_obj +{ + /** The size of the object. */ + uint32_t o32_size; + /** The base address of the object. */ + uint32_t o32_base; + /** Object flags. */ + uint32_t o32_flags; + /** Page map index. */ + uint32_t o32_pagemap; + /** Page map size. (doesn't need to be o32_size >> page shift). */ + uint32_t o32_mapsize; + /** Reserved */ + uint32_t o32_reserved; +} o32_obj; +AssertCompileSize(o32_obj, 24); + +/** @name o32_flags + * @{ */ +/** Read access. */ +#define OBJREAD UINT32_C(0x00000001) +/** Write access. */ +#define OBJWRITE UINT32_C(0x00000002) +/** Execute access. */ +#define OBJEXEC UINT32_C(0x00000004) +/** Resource object. */ +#define OBJRSRC UINT32_C(0x00000008) +/** The object is discarable (i.e. don't swap, just load in pages from the executable). + * This overlaps a bit with object type. */ +#define OBJDISCARD UINT32_C(0x00000010) +/** The object is shared. */ +#define OBJSHARED UINT32_C(0x00000020) +/** The object has preload pages. */ +#define OBJPRELOAD UINT32_C(0x00000040) +/** The object has invalid pages. */ +#define OBJINVALID UINT32_C(0x00000080) +/** Non-permanent, link386 bug. */ +#define LNKNONPERM UINT32_C(0x00000600) +/** Non-permanent, correct 'value'. */ +#define OBJNONPERM UINT32_C(0x00000000) +/** Obj Type: The object is permanent and swappable. */ +#define OBJPERM UINT32_C(0x00000100) +/** Obj Type: The object is permanent and resident (i.e. not swappable). */ +#define OBJRESIDENT UINT32_C(0x00000200) +/** Obj Type: The object is resident and contigious. */ +#define OBJCONTIG UINT32_C(0x00000300) +/** Obj Type: The object is permanent and long locable. */ +#define OBJDYNAMIC UINT32_C(0x00000400) +/** Object type mask. */ +#define OBJTYPEMASK UINT32_C(0x00000700) +/** x86: The object require an 16:16 alias. */ +#define OBJALIAS16 UINT32_C(0x00001000) +/** x86: Big/Default selector setting, i.e. toggle 32-bit or 16-bit. */ +#define OBJBIGDEF UINT32_C(0x00002000) +/** x86: conforming selector setting (weird stuff). */ +#define OBJCONFORM UINT32_C(0x00004000) +/** x86: IOPL. */ +#define OBJIOPL UINT32_C(0x00008000) +/** @} */ + +/** A Object Page Map Entry. */ +typedef struct o32_map +{ + /** The file offset of the page. */ + uint32_t o32_pagedataoffset; + /** The number of bytes of raw page data. */ + uint16_t o32_pagesize; + /** Per page flags describing how the page is encoded in the file. */ + uint16_t o32_pageflags; +} o32_map; +AssertCompileSize(o32_map, 8); + +/** @name o32 o32_pageflags + * @{ + */ +/** Raw page (uncompressed) in the file. */ +#define VALID UINT16_C(0x0000) +/** RLE encoded page in file. */ +#define ITERDATA UINT16_C(0x0001) +/** Invalid page, nothing in the file. */ +#define INVALID UINT16_C(0x0002) +/** Zero page, nothing in file. */ +#define ZEROED UINT16_C(0x0003) +/** range of pages (what is this?) */ +#define RANGE UINT16_C(0x0004) +/** Compressed page in file. */ +#define ITERDATA2 UINT16_C(0x0005) +/** @} */ + + +/** Iteration Record format (RLE compressed page). */ +#pragma pack(1) +typedef struct LX_Iter +{ + /** Number of iterations. */ + uint16_t LX_nIter; + /** The number of bytes that's being iterated. */ + uint16_t LX_nBytes; + /** The bytes. */ + uint8_t LX_Iterdata; +} LX_Iter; +#pragma pack() +AssertCompileSize(LX_Iter, 5); + +/** @} */ + + +/** A Resource Table Entry */ +#pragma pack(1) +typedef struct rsrc32 +{ + /** Resource Type. */ + uint16_t type; + /** Resource ID. */ + uint16_t name; + /** Resource size in bytes. */ + uint32_t cb; + /** The index of the object containing the resource. */ + uint16_t obj; + /** Offset of the resource that within the object. */ + uint32_t offset; +} rsrc32; +#pragma pack() +AssertCompileSize(rsrc32, 14); + + +/** @defgroup grp_rt_formats_lx_entry_tab The Entry Table (aka Export Table) + * @{ */ + +/** Entry bundle. + * Header descripting up to 255 entries that follows immediatly after this structure. */ +typedef struct b32_bundle +{ + /** The number of entries. */ + uint8_t b32_cnt; + /** The type of bundle. */ + uint8_t b32_type; + /** The index of the object containing these entry points. */ + uint16_t b32_obj; +} b32_bundle; +AssertCompileSize(b32_bundle, 4); + +/** @name b32_type + * @{ */ +/** Empty bundle, filling up unused ranges of ordinals. */ +#define EMPTY 0x00 +/** 16-bit offset entry point. */ +#define ENTRY16 0x01 +/** 16-bit callgate entry point. */ +#define GATE16 0x02 +/** 32-bit offset entry point. */ +#define ENTRY32 0x03 +/** Forwarder entry point. */ +#define ENTRYFWD 0x04 +/** Typing information present indicator. */ +#define TYPEINFO 0x80 +/** @} */ + + +/** Entry point. */ +#pragma pack(1) +typedef struct e32_entry +{ + /** Entry point flags */ + uint8_t e32_flags; /* Entry point flags */ + union entrykind + { + /** ENTRY16 or ENTRY32. */ + r32_offset e32_offset; + /** GATE16 */ + struct scallgate + { + /** Offset into segment. */ + uint16_t offset; + /** The callgate selector */ + uint16_t callgate; + } e32_callgate; + /** ENTRYFWD */ + struct fwd + { + /** Module ordinal number (i.e. into the import module table). */ + uint16_t modord; + /** Procedure name or ordinal number. */ + uint32_t value; + } e32_fwd; + } e32_variant; +} e32_entry; +#pragma pack() + +/** @name e32_flags + * @{ */ +/** Exported entry (set) or private entry (clear). */ +#define E32EXPORT 0x01 +/** Uses shared data. */ +#define E32SHARED 0x02 +/** Parameter word count mask. */ +#define E32PARAMS 0xf8 +/** ENTRYFWD: Imported by ordinal (set) or by name (clear). */ +#define FWD_ORDINAL 0x01 +/** @} */ + +/** @name dunno + * @{ */ +#define FIXENT16 3 +#define FIXENT32 5 +#define GATEENT16 5 +#define FWDENT 7 +/** @} */ + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_formats_lx_h */ + diff --git a/include/iprt/formats/mach-o.h b/include/iprt/formats/mach-o.h new file mode 100644 index 00000000..75fe0ed2 --- /dev/null +++ b/include/iprt/formats/mach-o.h @@ -0,0 +1,860 @@ +/* $Id: mach-o.h $ */ +/** @file + * IPRT - Mach-O Structures and Constants. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_mach_o_h +#define IPRT_INCLUDED_formats_mach_o_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + +#ifndef CPU_ARCH_MASK + +/* cputype */ +#define CPU_ARCH_MASK INT32_C(0xff000000) +#define CPU_ARCH_ABI64 INT32_C(0x01000000) +#define CPU_ARCH_ABI64_32 INT32_C(0x02000000) /**< LP32 on 64-bit hardware */ + +#define CPU_TYPE_ANY INT32_C(-1) +#define CPU_TYPE_VAX INT32_C(1) +#define CPU_TYPE_MC680x0 INT32_C(6) +#define CPU_TYPE_X86 INT32_C(7) +#define CPU_TYPE_I386 CPU_TYPE_X86 +#define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64) +#define CPU_TYPE_MC98000 INT32_C(10) +#define CPU_TYPE_HPPA INT32_C(11) +#define CPU_TYPE_ARM INT32_C(12) +#define CPU_TYPE_ARM32 CPU_TYPE_ARM +#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) +#define CPU_TYPE_ARM64_32 (CPU_TYPE_ARM | CPU_ARCH_ABI64_32) +#define CPU_TYPE_MC88000 INT32_C(13) +#define CPU_TYPE_SPARC INT32_C(14) +#define CPU_TYPE_I860 INT32_C(15) +#define CPU_TYPE_POWERPC INT32_C(18) +#define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | CPU_ARCH_ABI64) + +/* cpusubtype */ +#define CPU_SUBTYPE_MULTIPLE INT32_C(-1) +#define CPU_SUBTYPE_LITTLE_ENDIAN INT32_C(0) +#define CPU_SUBTYPE_BIG_ENDIAN INT32_C(1) + +#define CPU_SUBTYPE_VAX_ALL INT32_C(0) +#define CPU_SUBTYPE_VAX780 INT32_C(1) +#define CPU_SUBTYPE_VAX785 INT32_C(2) +#define CPU_SUBTYPE_VAX750 INT32_C(3) +#define CPU_SUBTYPE_VAX730 INT32_C(4) +#define CPU_SUBTYPE_UVAXI INT32_C(5) +#define CPU_SUBTYPE_UVAXII INT32_C(6) +#define CPU_SUBTYPE_VAX8200 INT32_C(7) +#define CPU_SUBTYPE_VAX8500 INT32_C(8) +#define CPU_SUBTYPE_VAX8600 INT32_C(9) +#define CPU_SUBTYPE_VAX8650 INT32_C(10) +#define CPU_SUBTYPE_VAX8800 INT32_C(11) +#define CPU_SUBTYPE_UVAXIII INT32_C(12) + +#define CPU_SUBTYPE_MC680x0_ALL INT32_C(1) +#define CPU_SUBTYPE_MC68030 INT32_C(1) +#define CPU_SUBTYPE_MC68040 INT32_C(2) +#define CPU_SUBTYPE_MC68030_ONLY INT32_C(3) + +#define CPU_SUBTYPE_INTEL(fam, model) ( (int32_t )(((model) << 4) | (fam)) ) +#define CPU_SUBTYPE_INTEL_FAMILY(subtype) ( (subtype) & 0xf ) +#define CPU_SUBTYPE_INTEL_MODEL(subtype) ( (subtype) >> 4 ) +#define CPU_SUBTYPE_INTEL_FAMILY_MAX 0xf +#define CPU_SUBTYPE_INTEL_MODEL_ALL 0 + +#define CPU_SUBTYPE_I386_ALL CPU_SUBTYPE_INTEL(3, 0) +#define CPU_SUBTYPE_386 CPU_SUBTYPE_INTEL(3, 0) +#define CPU_SUBTYPE_486 CPU_SUBTYPE_INTEL(4, 0) +#define CPU_SUBTYPE_486SX CPU_SUBTYPE_INTEL(4, 8) +#define CPU_SUBTYPE_586 CPU_SUBTYPE_INTEL(5, 0) +#define CPU_SUBTYPE_PENT CPU_SUBTYPE_INTEL(5, 0) +#define CPU_SUBTYPE_PENTPRO CPU_SUBTYPE_INTEL(6, 1) +#define CPU_SUBTYPE_PENTII_M3 CPU_SUBTYPE_INTEL(6, 3) +#define CPU_SUBTYPE_PENTII_M5 CPU_SUBTYPE_INTEL(6, 5) +#define CPU_SUBTYPE_CELERON CPU_SUBTYPE_INTEL(7, 6) +#define CPU_SUBTYPE_CELERON_MOBILE CPU_SUBTYPE_INTEL(7, 7) +#define CPU_SUBTYPE_PENTIUM_3 CPU_SUBTYPE_INTEL(8, 0) +#define CPU_SUBTYPE_PENTIUM_3_M CPU_SUBTYPE_INTEL(8, 1) +#define CPU_SUBTYPE_PENTIUM_3_XEON CPU_SUBTYPE_INTEL(8, 2) +#define CPU_SUBTYPE_PENTIUM_M CPU_SUBTYPE_INTEL(9, 0) +#define CPU_SUBTYPE_PENTIUM_4 CPU_SUBTYPE_INTEL(10, 0) +#define CPU_SUBTYPE_PENTIUM_4_M CPU_SUBTYPE_INTEL(10, 1) +#define CPU_SUBTYPE_ITANIUM CPU_SUBTYPE_INTEL(11, 0) +#define CPU_SUBTYPE_ITANIUM_2 CPU_SUBTYPE_INTEL(11, 1) +#define CPU_SUBTYPE_XEON CPU_SUBTYPE_INTEL(12, 0) +#define CPU_SUBTYPE_XEON_MP CPU_SUBTYPE_INTEL(12, 1) + +#define CPU_SUBTYPE_X86_ALL INT32_C(3) +#define CPU_SUBTYPE_X86_64_ALL INT32_C(3) +#define CPU_SUBTYPE_X86_ARCH1 INT32_C(4) + +#define CPU_SUBTYPE_MIPS_ALL INT32_C(0) +#define CPU_SUBTYPE_MIPS_R2300 INT32_C(1) +#define CPU_SUBTYPE_MIPS_R2600 INT32_C(2) +#define CPU_SUBTYPE_MIPS_R2800 INT32_C(3) +#define CPU_SUBTYPE_MIPS_R2000a INT32_C(4) +#define CPU_SUBTYPE_MIPS_R2000 INT32_C(5) +#define CPU_SUBTYPE_MIPS_R3000a INT32_C(6) +#define CPU_SUBTYPE_MIPS_R3000 INT32_C(7) + +#define CPU_SUBTYPE_MC98000_ALL INT32_C(0) +#define CPU_SUBTYPE_MC98601 INT32_C(1) + +#define CPU_SUBTYPE_HPPA_ALL INT32_C(0) +#define CPU_SUBTYPE_HPPA_7100 INT32_C(0) +#define CPU_SUBTYPE_HPPA_7100LC INT32_C(1) + +#define CPU_SUBTYPE_ARM_ALL INT32_C(0) +#define CPU_SUBTYPE_ARM_V4T INT32_C(5) +#define CPU_SUBTYPE_ARM_V6 INT32_C(6) +#define CPU_SUBTYPE_ARM_V5TEJ INT32_C(7) +#define CPU_SUBTYPE_ARM_XSCALE INT32_C(8) +#define CPU_SUBTYPE_ARM_V7 INT32_C(9) +#define CPU_SUBTYPE_ARM_V7F INT32_C(10) +#define CPU_SUBTYPE_ARM_V7S INT32_C(11) +#define CPU_SUBTYPE_ARM_V7K INT32_C(12) +#define CPU_SUBTYPE_ARM_V8 INT32_C(13) +#define CPU_SUBTYPE_ARM_V6M INT32_C(14) +#define CPU_SUBTYPE_ARM_V7M INT32_C(15) +#define CPU_SUBTYPE_ARM_V7EM INT32_C(16) +#define CPU_SUBTYPE_ARM_V8M INT32_C(17) + +#define CPU_SUBTYPE_ARM64_ALL INT32_C(0) +#define CPU_SUBTYPE_ARM64_V8 INT32_C(1) +#define CPU_SUBTYPE_ARM64E INT32_C(2) +#define CPU_SUBTYPE_ARM64_PTR_AUTH_MASK UINT32_C(0x0f000000) +#define CPU_SUBTYPE_ARM64_PTR_AUTH_VERSION(a) ( ((a) & CPU_SUBTYPE_ARM64_PTR_AUTH_MASK) >> 24 ) + +#define CPU_SUBTYPE_ARM64_32_ALL INT32_C(0) +#define CPU_SUBTYPE_ARM64_32_V8 INT32_C(1) + +#define CPU_SUBTYPE_MC88000_ALL INT32_C(0) +#define CPU_SUBTYPE_MC88100 INT32_C(1) +#define CPU_SUBTYPE_MC88110 INT32_C(2) + +#define CPU_SUBTYPE_SPARC_ALL INT32_C(0) + +#define CPU_SUBTYPE_I860_ALL INT32_C(0) +#define CPU_SUBTYPE_I860_860 INT32_C(1) + +#define CPU_SUBTYPE_POWERPC_ALL INT32_C(0) +#define CPU_SUBTYPE_POWERPC_601 INT32_C(1) +#define CPU_SUBTYPE_POWERPC_602 INT32_C(2) +#define CPU_SUBTYPE_POWERPC_603 INT32_C(3) +#define CPU_SUBTYPE_POWERPC_603e INT32_C(4) +#define CPU_SUBTYPE_POWERPC_603ev INT32_C(5) +#define CPU_SUBTYPE_POWERPC_604 INT32_C(6) +#define CPU_SUBTYPE_POWERPC_604e INT32_C(7) +#define CPU_SUBTYPE_POWERPC_620 INT32_C(8) +#define CPU_SUBTYPE_POWERPC_750 INT32_C(9) +#define CPU_SUBTYPE_POWERPC_7400 INT32_C(10) +#define CPU_SUBTYPE_POWERPC_7450 INT32_C(11) +#define CPU_SUBTYPE_POWERPC_Max INT32_C(10) +#define CPU_SUBTYPE_POWERPC_SCVger INT32_C(11) +#define CPU_SUBTYPE_POWERPC_970 INT32_C(100) + +#define CPU_SUBTYPE_MASK UINT32_C(0xff000000) +#define CPU_SUBTYPE_LIB64 UINT32_C(0x80000000) + +#endif /* !CPU_ARCH_MASK */ + + +typedef struct fat_header +{ + uint32_t magic; + uint32_t nfat_arch; +} fat_header_t; + +#ifndef IMAGE_FAT_SIGNATURE +# define IMAGE_FAT_SIGNATURE UINT32_C(0xcafebabe) +#endif +#ifndef IMAGE_FAT_SIGNATURE_OE +# define IMAGE_FAT_SIGNATURE_OE UINT32_C(0xbebafeca) +#endif + +typedef struct fat_arch +{ + int32_t cputype; + int32_t cpusubtype; + uint32_t offset; + uint32_t size; + uint32_t align; +} fat_arch_t; + +typedef struct mach_header_32 +{ + uint32_t magic; + int32_t cputype; + int32_t cpusubtype; + uint32_t filetype; + uint32_t ncmds; + uint32_t sizeofcmds; + uint32_t flags; +} mach_header_32_t; + +/* magic */ +#ifndef IMAGE_MACHO32_SIGNATURE +# define IMAGE_MACHO32_SIGNATURE UINT32_C(0xfeedface) +#endif +#ifndef IMAGE_MACHO32_SIGNATURE_OE +# define IMAGE_MACHO32_SIGNATURE_OE UINT32_C(0xcefaedfe) +#endif +#define MH_MAGIC IMAGE_MACHO32_SIGNATURE +#define MH_CIGAM IMAGE_MACHO32_SIGNATURE_OE + +typedef struct mach_header_64 +{ + uint32_t magic; /**< 0x00 */ + int32_t cputype; /**< 0x04 */ + int32_t cpusubtype; /**< 0x08 */ + uint32_t filetype; /**< 0x0c */ + uint32_t ncmds; /**< 0x10 */ + uint32_t sizeofcmds; /**< 0x14 */ + uint32_t flags; /**< 0x18 */ + uint32_t reserved; /**< 0x1c */ +} mach_header_64_t; +AssertCompileSize(mach_header_64_t, 0x20); + +/* magic */ +#ifndef IMAGE_MACHO64_SIGNATURE +# define IMAGE_MACHO64_SIGNATURE UINT32_C(0xfeedfacf) +#endif +#ifndef IMAGE_MACHO64_SIGNATURE_OE +# define IMAGE_MACHO64_SIGNATURE_OE UINT32_C(0xfefaedfe) +#endif +#define MH_MAGIC_64 IMAGE_MACHO64_SIGNATURE +#define MH_CIGAM_64 IMAGE_MACHO64_SIGNATURE_OE + +/* mach_header_* filetype */ +#define MH_OBJECT UINT32_C(1) +#define MH_EXECUTE UINT32_C(2) +#define MH_FVMLIB UINT32_C(3) +#define MH_CORE UINT32_C(4) +#define MH_PRELOAD UINT32_C(5) +#define MH_DYLIB UINT32_C(6) +#define MH_DYLINKER UINT32_C(7) +#define MH_BUNDLE UINT32_C(8) +#define MH_DYLIB_STUB UINT32_C(9) +#define MH_DSYM UINT32_C(10) +#define MH_KEXT_BUNDLE UINT32_C(11) + +/* mach_header_* flags */ +#define MH_NOUNDEFS UINT32_C(0x00000001) +#define MH_INCRLINK UINT32_C(0x00000002) +#define MH_DYLDLINK UINT32_C(0x00000004) +#define MH_BINDATLOAD UINT32_C(0x00000008) +#define MH_PREBOUND UINT32_C(0x00000010) +#define MH_SPLIT_SEGS UINT32_C(0x00000020) +#define MH_LAZY_INIT UINT32_C(0x00000040) +#define MH_TWOLEVEL UINT32_C(0x00000080) +#define MH_FORCE_FLAT UINT32_C(0x00000100) +#define MH_NOMULTIDEFS UINT32_C(0x00000200) +#define MH_NOFIXPREBINDING UINT32_C(0x00000400) +#define MH_PREBINDABLE UINT32_C(0x00000800) +#define MH_ALLMODSBOUND UINT32_C(0x00001000) +#define MH_SUBSECTIONS_VIA_SYMBOLS UINT32_C(0x00002000) +#define MH_CANONICAL UINT32_C(0x00004000) +#define MH_WEAK_DEFINES UINT32_C(0x00008000) +#define MH_BINDS_TO_WEAK UINT32_C(0x00010000) +#define MH_ALLOW_STACK_EXECUTION UINT32_C(0x00020000) +#define MH_ROOT_SAFE UINT32_C(0x00040000) +#define MH_SETUID_SAFE UINT32_C(0x00080000) +#define MH_NO_REEXPORTED_DYLIBS UINT32_C(0x00100000) +#define MH_PIE UINT32_C(0x00200000) +#define MH_DEAD_STRIPPABLE_DYLIB UINT32_C(0x00400000) +#define MH_HAS_TLV_DESCRIPTORS UINT32_C(0x00800000) +#define MH_NO_HEAP_EXECUTION UINT32_C(0x01000000) +#define MH_UNKNOWN UINT32_C(0x80000000) +#define MH_VALID_FLAGS UINT32_C(0x81ffffff) + + +typedef struct load_command +{ + uint32_t cmd; + uint32_t cmdsize; +} load_command_t; + +/* load cmd */ +#define LC_REQ_DYLD UINT32_C(0x80000000) +#define LC_SEGMENT_32 UINT32_C(0x01) +#define LC_SYMTAB UINT32_C(0x02) +#define LC_SYMSEG UINT32_C(0x03) +#define LC_THREAD UINT32_C(0x04) +#define LC_UNIXTHREAD UINT32_C(0x05) +#define LC_LOADFVMLIB UINT32_C(0x06) +#define LC_IDFVMLIB UINT32_C(0x07) +#define LC_IDENT UINT32_C(0x08) +#define LC_FVMFILE UINT32_C(0x09) +#define LC_PREPAGE UINT32_C(0x0a) +#define LC_DYSYMTAB UINT32_C(0x0b) +#define LC_LOAD_DYLIB UINT32_C(0x0c) +#define LC_ID_DYLIB UINT32_C(0x0d) +#define LC_LOAD_DYLINKER UINT32_C(0x0e) +#define LC_ID_DYLINKER UINT32_C(0x0f) +#define LC_PREBOUND_DYLIB UINT32_C(0x10) +#define LC_ROUTINES UINT32_C(0x11) +#define LC_SUB_FRAMEWORK UINT32_C(0x12) +#define LC_SUB_UMBRELLA UINT32_C(0x13) +#define LC_SUB_CLIENT UINT32_C(0x14) +#define LC_SUB_LIBRARY UINT32_C(0x15) +#define LC_TWOLEVEL_HINTS UINT32_C(0x16) +#define LC_PREBIND_CKSUM UINT32_C(0x17) +#define LC_LOAD_WEAK_DYLIB (UINT32_C(0x18) | LC_REQ_DYLD) +#define LC_SEGMENT_64 UINT32_C(0x19) +#define LC_ROUTINES_64 UINT32_C(0x1a) +#define LC_UUID UINT32_C(0x1b) +#define LC_RPATH (UINT32_C(0x1c) | LC_REQ_DYLD) +#define LC_CODE_SIGNATURE UINT32_C(0x1d) +#define LC_SEGMENT_SPLIT_INFO UINT32_C(0x1e) +#define LC_REEXPORT_DYLIB (UINT32_C(0x1f) | LC_REQ_DYLD) +#define LC_LAZY_LOAD_DYLIB UINT32_C(0x20) +#define LC_ENCRYPTION_INFO UINT32_C(0x21) +#define LC_DYLD_INFO UINT32_C(0x22) +#define LC_DYLD_INFO_ONLY (UINT32_C(0x22) | LC_REQ_DYLD) +#define LC_LOAD_UPWARD_DYLIB (UINT32_C(0x23) | LC_REQ_DYLD) +#define LC_VERSION_MIN_MACOSX UINT32_C(0x24) +#define LC_VERSION_MIN_IPHONEOS UINT32_C(0x25) +#define LC_FUNCTION_STARTS UINT32_C(0x26) +#define LC_DYLD_ENVIRONMENT UINT32_C(0x27) +#define LC_MAIN (UINT32_C(0x28) | LC_REQ_DYLD) +#define LC_DATA_IN_CODE UINT32_C(0x29) +#define LC_SOURCE_VERSION UINT32_C(0x2a) /**< source_version_command */ +#define LC_DYLIB_CODE_SIGN_DRS UINT32_C(0x2b) +#define LC_ENCRYPTION_INFO_64 UINT32_C(0x2c) +#define LC_LINKER_OPTION UINT32_C(0x2d) +#define LC_LINKER_OPTIMIZATION_HINT UINT32_C(0x2e) +#define LC_VERSION_MIN_TVOS UINT32_C(0x2f) +#define LC_VERSION_MIN_WATCHOS UINT32_C(0x30) +#define LC_NOTE UINT32_C(0x31) +#define LC_BUILD_VERSION UINT32_C(0x32) + + +typedef struct lc_str +{ + uint32_t offset; +} lc_str_t; + +typedef struct segment_command_32 +{ + uint32_t cmd; + uint32_t cmdsize; + char segname[16]; + uint32_t vmaddr; + uint32_t vmsize; + uint32_t fileoff; + uint32_t filesize; + uint32_t maxprot; + uint32_t initprot; + uint32_t nsects; + uint32_t flags; +} segment_command_32_t; + +typedef struct segment_command_64 +{ + uint32_t cmd; + uint32_t cmdsize; + char segname[16]; + uint64_t vmaddr; + uint64_t vmsize; + uint64_t fileoff; + uint64_t filesize; + uint32_t maxprot; + uint32_t initprot; + uint32_t nsects; + uint32_t flags; +} segment_command_64_t; + +/* segment flags */ +#define SG_HIGHVM UINT32_C(0x00000001) +#define SG_FVMLIB UINT32_C(0x00000002) +#define SG_NORELOC UINT32_C(0x00000004) +#define SG_PROTECTED_VERSION_1 UINT32_C(0x00000008) +#define SG_READ_ONLY UINT32_C(0x00000010) /**< Make it read-only after applying fixups. @since 10.14 */ + +/* maxprot/initprot */ +#ifndef VM_PROT_NONE +# define VM_PROT_NONE UINT32_C(0x00000000) +# define VM_PROT_READ UINT32_C(0x00000001) +# define VM_PROT_WRITE UINT32_C(0x00000002) +# define VM_PROT_EXECUTE UINT32_C(0x00000004) +# define VM_PROT_ALL UINT32_C(0x00000007) +#endif + +typedef struct section_32 +{ + char sectname[16]; + char segname[16]; + uint32_t addr; + uint32_t size; + uint32_t offset; + uint32_t align; + uint32_t reloff; + uint32_t nreloc; + uint32_t flags; + /** For S_LAZY_SYMBOL_POINTERS, S_NON_LAZY_SYMBOL_POINTERS and S_SYMBOL_STUBS + * this is the index into the indirect symbol table. */ + uint32_t reserved1; + /** For S_SYMBOL_STUBS this is the entry size. */ + uint32_t reserved2; +} section_32_t; + +typedef struct section_64 +{ + char sectname[16]; + char segname[16]; + uint64_t addr; + uint64_t size; + uint32_t offset; + uint32_t align; + uint32_t reloff; + uint32_t nreloc; + uint32_t flags; + /** For S_LAZY_SYMBOL_POINTERS, S_NON_LAZY_SYMBOL_POINTERS and S_SYMBOL_STUBS + * this is the index into the indirect symbol table. */ + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; +} section_64_t; + +/* section flags */ +#define SECTION_TYPE UINT32_C(0xff) +#define S_REGULAR UINT32_C(0x00) +#define S_ZEROFILL UINT32_C(0x01) +#define S_CSTRING_LITERALS UINT32_C(0x02) +#define S_4BYTE_LITERALS UINT32_C(0x03) +#define S_8BYTE_LITERALS UINT32_C(0x04) +#define S_LITERAL_POINTERS UINT32_C(0x05) +#define S_NON_LAZY_SYMBOL_POINTERS UINT32_C(0x06) +#define S_LAZY_SYMBOL_POINTERS UINT32_C(0x07) +#define S_SYMBOL_STUBS UINT32_C(0x08) +#define S_MOD_INIT_FUNC_POINTERS UINT32_C(0x09) +#define S_MOD_TERM_FUNC_POINTERS UINT32_C(0x0a) +#define S_COALESCED UINT32_C(0x0b) +#define S_GB_ZEROFILL UINT32_C(0x0c) +#define S_INTERPOSING UINT32_C(0x0d) +#define S_16BYTE_LITERALS UINT32_C(0x0e) +#define S_DTRACE_DOF UINT32_C(0x0f) +#define S_LAZY_DYLIB_SYMBOL_POINTERS UINT32_C(0x10) +#define S_THREAD_LOCAL_REGULAR UINT32_C(0x11) +#define S_THREAD_LOCAL_ZEROFILL UINT32_C(0x12) +#define S_THREAD_LOCAL_VARIABLES UINT32_C(0x13) +#define S_THREAD_LOCAL_VARIABLE_POINTERS UINT32_C(0x14) +#define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS UINT32_C(0x15) + + + + +#define SECTION_ATTRIBUTES UINT32_C(0xffffff00) +#define SECTION_ATTRIBUTES_USR UINT32_C(0xff000000) +#define S_ATTR_PURE_INSTRUCTIONS UINT32_C(0x80000000) +#define S_ATTR_NO_TOC UINT32_C(0x40000000) +#define S_ATTR_STRIP_STATIC_SYMS UINT32_C(0x20000000) +#define S_ATTR_NO_DEAD_STRIP UINT32_C(0x10000000) +#define S_ATTR_LIVE_SUPPORT UINT32_C(0x08000000) +#define S_ATTR_SELF_MODIFYING_CODE UINT32_C(0x04000000) +#define S_ATTR_DEBUG UINT32_C(0x02000000) +#define SECTION_ATTRIBUTES_SYS UINT32_C(0x00ffff00) +#define S_ATTR_SOME_INSTRUCTIONS UINT32_C(0x00000400) +#define S_ATTR_EXT_RELOC UINT32_C(0x00000200) +#define S_ATTR_LOC_RELOC UINT32_C(0x00000100) + +/* standard section names */ +#define SEG_PAGEZERO "__PAGEZERO" +#define SEG_TEXT "__TEXT" +#define SECT_TEXT "__text" +#define SECT_FVMLIB_INIT0 "__fvmlib_init0" +#define SECT_FVMLIB_INIT1 "__fvmlib_init1" +#define SEG_DATA "__DATA" +#define SECT_DATA "__data" +#define SECT_BSS "__bss" +#define SECT_COMMON "__common" +#define SEG_OBJC "__OBJC" +#define SECT_OBJC_SYMBOLS "__symbol_table" +#define SECT_OBJC_MODULES "__module_info" +#define SECT_OBJC_STRINGS "__selector_strs" +#define SECT_OBJC_REFS "__selector_refs" +#define SEG_ICON "__ICON" +#define SECT_ICON_HEADER "__header" +#define SECT_ICON_TIFF "__tiff" +#define SEG_LINKEDIT "__LINKEDIT" +#define SEG_UNIXSTACK "__UNIXSTACK" +#define SEG_IMPORT "__IMPORT" + +typedef struct thread_command +{ + uint32_t cmd; + uint32_t cmdsize; +} thread_command_t; + +typedef struct symtab_command +{ + uint32_t cmd; + uint32_t cmdsize; + uint32_t symoff; + uint32_t nsyms; + uint32_t stroff; + uint32_t strsize; +} symtab_command_t; + +typedef struct dysymtab_command +{ + uint32_t cmd; + uint32_t cmdsize; + /** @name Symbol groupings. + * @{ */ + uint32_t ilocalsym; /**< Index into the symbol table of the first local symbol. */ + uint32_t nlocalsym; /**< Number of local symbols. */ + uint32_t iextdefsym; /**< Index into the symbol table of the first externally defined symbol. */ + uint32_t nextdefsym; /**< Number of externally defined symbols. */ + uint32_t iundefsym; /**< Index into the symbol table of the first undefined symbol. */ + uint32_t nundefsym; /**< Number of undefined symbols. */ + /** @} */ + uint32_t tocoff; /**< Table of content file offset. (usually empty) */ + uint32_t ntoc; /**< Number of entries in TOC. */ + uint32_t modtaboff; /** The module table file offset. (usually empty) */ + uint32_t nmodtab; /**< Number of entries in the module table. */ + /** @name Dynamic symbol tables. + * @{ */ + uint32_t extrefsymoff; /**< Externally referenceable symbol table file offset. @sa dylib_reference_t */ + uint32_t nextrefsym; /**< Number externally referenceable symbols. */ + uint32_t indirectsymboff; /**< Indirect symbol table (32-bit symtab indexes) for thunks and offset tables. */ + uint32_t nindirectsymb; /**< Number of indirect symbol table entries. */ + /** @} */ + /** @name Relocations. + * @{ */ + uint32_t extreloff; /**< External relocations (r_address is relative to first segment (i.e. RVA)). */ + uint32_t nextrel; /**< Number of external relocations. */ + uint32_t locreloff; /**< Local relocations (r_address is relative to first segment (i.e. RVA)). */ + uint32_t nlocrel; /**< Number of local relocations. */ + /** @} */ +} dysymtab_command_t; +AssertCompileSize(dysymtab_command_t, 80); + +/** Special indirect symbol table entry value, stripped local symbol. */ +#define INDIRECT_SYMBOL_LOCAL UINT32_C(0x80000000) +/** Special indirect symbol table entry value, stripped absolute symbol. */ +#define INDIRECT_SYMBOL_ABS UINT32_C(0x40000000) + +typedef struct dylib_reference +{ + uint32_t isym : 24; /**< Symbol table index. */ + uint32_t flags : 8; /**< REFERENCE_FLAG_XXX? */ +} dylib_reference_t; +AssertCompileSize(dylib_reference_t, 4); + + +typedef struct dylib_table_of_contents +{ + uint32_t symbol_index; /**< External symbol table entry. */ + uint32_t module_index; /**< The module table index of the module defining it. */ +} dylib_table_of_contents_t; +AssertCompileSize(dylib_table_of_contents_t, 8); + + +/** 32-bit module table entry. */ +typedef struct dylib_module +{ + uint32_t module_name; + uint32_t iextdefsym; + uint32_t nextdefsym; + uint32_t irefsym; + uint32_t nrefsym; + uint32_t ilocalsym; + uint32_t nlocalsym; + uint32_t iextrel; + uint32_t nextrel; + uint32_t iinit_iterm; + uint32_t ninit_nterm; + uint32_t objc_module_info_addr; + uint32_t objc_module_info_size; +} dylib_module_32_t; +AssertCompileSize(dylib_module_32_t, 13*4); + +/* a 64-bit module table entry */ +typedef struct dylib_module_64 +{ + uint32_t module_name; + uint32_t iextdefsym; + uint32_t nextdefsym; + uint32_t irefsym; + uint32_t nrefsym; + uint32_t ilocalsym; + uint32_t nlocalsym; + uint32_t iextrel; + uint32_t nextrel; + uint32_t iinit_iterm; + uint32_t ninit_nterm; + uint32_t objc_module_info_size; + uint64_t objc_module_info_addr; +} dylib_module_64_t; +AssertCompileSize(dylib_module_64_t, 12*4+8); + +typedef struct uuid_command +{ + uint32_t cmd; + uint32_t cmdsize; + uint8_t uuid[16]; +} uuid_command_t; +AssertCompileSize(uuid_command_t, 24); + +typedef struct linkedit_data_command +{ + uint32_t cmd; /**< LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS */ + uint32_t cmdsize; /**< Size of this structure (16). */ + uint32_t dataoff; /**< Offset into the file of the data. */ + uint32_t datasize; /**< The size of the data. */ +} linkedit_data_command_t; +AssertCompileSize(linkedit_data_command_t, 16); + +typedef struct version_min_command +{ + uint32_t cmd; /**< LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_TVOS, LC_VERSION_MIN_WATCHOS */ + uint32_t cmdsize; /**< Size of this structure (16). */ + uint32_t version; /**< 31..16=major, 15..8=minor, 7..0=patch. */ + uint32_t reserved; /**< MBZ. */ +} version_min_command_t; +AssertCompileSize(version_min_command_t, 16); + +typedef struct build_tool_version +{ + uint32_t tool; /**< TOOL_XXX */ + uint32_t version; /**< 31..16=major, 15..8=minor, 7..0=patch. */ +} build_tool_version_t; +AssertCompileSize(build_tool_version_t, 8); + +/** @name TOOL_XXX - Values for build_tool_version::tool + * @{ */ +#define TOOL_CLANG 1 +#define TOOL_SWIFT 2 +#define TOOL_LD 3 +/** @} */ + +typedef struct build_version_command +{ + uint32_t cmd; /**< LC_BUILD_VERSION */ + uint32_t cmdsize; /**< Size of this structure (at least 24). */ + uint32_t platform; /**< PLATFORM_XXX */ + uint32_t minos; /**< Minimum OS version: 31..16=major, 15..8=minor, 7..0=patch */ + uint32_t sdk; /**< SDK version: 31..16=major, 15..8=minor, 7..0=patch */ + uint32_t ntools; /**< Number of build_tool_version entries following in aTools. */ + RT_FLEXIBLE_ARRAY_EXTENSION + build_tool_version_t aTools[RT_FLEXIBLE_ARRAY]; +} build_version_command_t; +AssertCompileMemberOffset(build_version_command_t, aTools, 24); + +/** @name PLATFORM_XXX - Values for build_version_command::platform + * @{ */ +#define PLATFORM_MACOS 1 +#define PLATFORM_IOS 2 +#define PLATFORM_TVOS 3 +#define PLATFORM_WATCHOS 4 +/** @} */ + +typedef struct source_version_command +{ + uint32_t cmd; /**< LC_SOURCE_VERSION */ + uint32_t cmdsize; /**< Size of this structure (16). */ + uint64_t version; /**< A.B.C.D.E, where A is 24 bits wide and the rest 10 bits each. */ +} source_version_command_t; +AssertCompileSize(source_version_command_t, 16); + + +typedef struct macho_nlist_32 +{ + union + { + int32_t n_strx; + } n_un; + uint8_t n_type; + uint8_t n_sect; + int16_t n_desc; + uint32_t n_value; +} macho_nlist_32_t; + + +typedef struct macho_nlist_64 +{ + union + { + uint32_t n_strx; + } n_un; + uint8_t n_type; + uint8_t n_sect; + int16_t n_desc; + uint64_t n_value; +} macho_nlist_64_t; + +#define MACHO_N_EXT UINT8_C(0x01) +#define MACHO_N_PEXT UINT8_C(0x10) + +#define MACHO_N_TYPE UINT8_C(0x0e) +#define MACHO_N_UNDF UINT8_C(0x00) +#define MACHO_N_ABS UINT8_C(0x02) +#define MACHO_N_INDR UINT8_C(0x0a) +#define MACHO_N_PBUD UINT8_C(0x0c) +#define MACHO_N_SECT UINT8_C(0x0e) + +#define MACHO_N_STAB UINT8_C(0xe0) +#define MACHO_N_GSYM UINT8_C(0x20) +#define MACHO_N_FNAME UINT8_C(0x22) +#define MACHO_N_FUN UINT8_C(0x24) +#define MACHO_N_STSYM UINT8_C(0x26) +#define MACHO_N_LCSYM UINT8_C(0x28) +#define MACHO_N_BNSYM UINT8_C(0x2e) +#define MACHO_N_PC UINT8_C(0x30) +#define MACHO_N_OPT UINT8_C(0x3c) +#define MACHO_N_RSYM UINT8_C(0x40) +#define MACHO_N_SLINE UINT8_C(0x44) +#define MACHO_N_ENSYM UINT8_C(0x4e) +#define MACHO_N_SSYM UINT8_C(0x60) +#define MACHO_N_SO UINT8_C(0x64) +#define MACHO_N_OSO UINT8_C(0x66) +#define MACHO_N_LSYM UINT8_C(0x80) +#define MACHO_N_BINCL UINT8_C(0x82) +#define MACHO_N_SOL UINT8_C(0x84) +#define MACHO_N_PARAMS UINT8_C(0x86) +#define MACHO_N_VERSION UINT8_C(0x88) +#define MACHO_N_OLEVEL UINT8_C(0x8A) +#define MACHO_N_PSYM UINT8_C(0xa0) +#define MACHO_N_EINCL UINT8_C(0xa2) +#define MACHO_N_ENTRY UINT8_C(0xa4) +#define MACHO_N_LBRAC UINT8_C(0xc0) +#define MACHO_N_EXCL UINT8_C(0xc2) +#define MACHO_N_RBRAC UINT8_C(0xe0) +#define MACHO_N_BCOMM UINT8_C(0xe2) +#define MACHO_N_ECOMM UINT8_C(0xe4) +#define MACHO_N_ECOML UINT8_C(0xe8) +#define MACHO_N_LENG UINT8_C(0xfe) + +#define MACHO_NO_SECT UINT8_C(0x00) +#define MACHO_MAX_SECT UINT8_C(0xff) + +#define REFERENCE_TYPE UINT16_C(0x000f) +#define REFERENCE_FLAG_UNDEFINED_NON_LAZY 0 +#define REFERENCE_FLAG_UNDEFINED_LAZY 1 +#define REFERENCE_FLAG_DEFINED 2 +#define REFERENCE_FLAG_PRIVATE_DEFINED 3 +#define REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY 4 +#define REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY 5 +#define REFERENCED_DYNAMICALLY UINT16_C(0x0010) + +#define GET_LIBRARY_ORDINAL(a_n_desc) \ + RT_BYTE2(a_n_desc) +#define SET_LIBRARY_ORDINAL(a_n_desc, a_ordinal) \ + do { (a_n_desc) = RT_MAKE_U16(RT_BYTE1(a_n_desc), a_ordinal); } while (0) + +#define SELF_LIBRARY_ORDINAL 0x00 +#define MAX_LIBRARY_ORDINAL 0xfd +#define DYNAMIC_LOOKUP_ORDINAL 0xfe +#define EXECUTABLE_ORDINAL 0xff + +#define N_NO_DEAD_STRIP UINT16_C(0x0020) +#define N_DESC_DISCARDED UINT16_C(0x0020) +#define N_WEAK_REF UINT16_C(0x0040) +#define N_WEAK_DEF UINT16_C(0x0080) +#define N_REF_TO_WEAK UINT16_C(0x0080) +#define N_SYMBOL_RESOLVER UINT16_C(0x0100) +#define N_ALT_ENTRY UINT16_C(0x0200) + +typedef struct macho_relocation_info +{ + int32_t r_address; + uint32_t r_symbolnum : 24; + uint32_t r_pcrel : 1; + uint32_t r_length : 2; + uint32_t r_extern : 1; + uint32_t r_type : 4; +} macho_relocation_info_t; +AssertCompileSize(macho_relocation_info_t, 8); + +#define R_ABS 0 +#define R_SCATTERED UINT32_C(0x80000000) + +typedef struct scattered_relocation_info +{ +#ifdef RT_LITTLE_ENDIAN + uint32_t r_address : 24; + uint32_t r_type : 4; + uint32_t r_length : 2; + uint32_t r_pcrel : 1; + uint32_t r_scattered : 1; +#elif defined(RT_BIG_ENDIAN) + uint32_t r_scattered : 1; + uint32_t r_pcrel : 1; + uint32_t r_length : 2; + uint32_t r_type : 4; + uint32_t r_address : 24; +#else +# error "Neither K_ENDIAN isn't LITTLE or BIG!" +#endif + int32_t r_value; +} scattered_relocation_info_t; +AssertCompileSize(scattered_relocation_info_t, 8); + +typedef union +{ + macho_relocation_info_t r; + scattered_relocation_info_t s; +} macho_relocation_union_t; +AssertCompileSize(macho_relocation_union_t, 8); + +typedef enum reloc_type_generic +{ + GENERIC_RELOC_VANILLA = 0, + GENERIC_RELOC_PAIR, + GENERIC_RELOC_SECTDIFF, + GENERIC_RELOC_PB_LA_PTR, + GENERIC_RELOC_LOCAL_SECTDIFF +} reloc_type_generic_t; + +typedef enum reloc_type_x86_64 +{ + X86_64_RELOC_UNSIGNED = 0, + X86_64_RELOC_SIGNED, + X86_64_RELOC_BRANCH, + X86_64_RELOC_GOT_LOAD, + X86_64_RELOC_GOT, + X86_64_RELOC_SUBTRACTOR, + X86_64_RELOC_SIGNED_1, + X86_64_RELOC_SIGNED_2, + X86_64_RELOC_SIGNED_4 +} reloc_type_x86_64_t; + +#endif /* !IPRT_INCLUDED_formats_mach_o_h */ + diff --git a/include/iprt/formats/mz.h b/include/iprt/formats/mz.h new file mode 100644 index 00000000..4759ad40 --- /dev/null +++ b/include/iprt/formats/mz.h @@ -0,0 +1,77 @@ +/* $Id: mz.h $ */ +/** @file + * IPRT, MZ Executable Header. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_mz_h +#define IPRT_INCLUDED_formats_mz_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + +typedef struct _IMAGE_DOS_HEADER +{ + uint16_t e_magic; + uint16_t e_cblp; + uint16_t e_cp; + uint16_t e_crlc; + uint16_t e_cparhdr; + uint16_t e_minalloc; + uint16_t e_maxalloc; + uint16_t e_ss; + uint16_t e_sp; + uint16_t e_csum; + uint16_t e_ip; + uint16_t e_cs; + uint16_t e_lfarlc; + uint16_t e_ovno; + uint16_t e_res[4]; + uint16_t e_oemid; + uint16_t e_oeminfo; + uint16_t e_res2[10]; + uint32_t e_lfanew; +} IMAGE_DOS_HEADER; +AssertCompileSize(IMAGE_DOS_HEADER, 0x40); +typedef IMAGE_DOS_HEADER *PIMAGE_DOS_HEADER; + +#ifndef IMAGE_DOS_SIGNATURE +# define IMAGE_DOS_SIGNATURE ('M' | ('Z' << 8)) /* fix endianness */ +#endif + + +#endif /* !IPRT_INCLUDED_formats_mz_h */ + diff --git a/include/iprt/formats/mz.mac b/include/iprt/formats/mz.mac new file mode 100644 index 00000000..97e30cc6 --- /dev/null +++ b/include/iprt/formats/mz.mac @@ -0,0 +1,66 @@ +;; @file +; IPRT - MZ (DOS Executable Header) definitions for YASM/NASM. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___iprt_formats_mz_mac +%define ___iprt_formats_mz_mac + +struc IMAGE_DOS_HEADER + .e_magic resw 1 + .e_cblp resw 1 + .e_cp resw 1 + .e_crlc resw 1 + .e_cparhdr resw 1 + .e_minalloc resw 1 + .e_maxalloc resw 1 + .e_ss resw 1 + .e_sp resw 1 + .e_csum resw 1 + .e_ip resw 1 + .e_cs resw 1 + .e_lfarlc resw 1 + .e_ovno resw 1 + .e_res resw 4 + .e_oemid resw 1 + .e_oeminfo resw 1 + .e_res2 resw 10 + .e_lfanew resd 1 +endstruc + +%ifndef IMAGE_DOS_SIGNATURE + %define IMAGE_DOS_SIGNATURE 0x5a4d +%endif + +%endif + diff --git a/include/iprt/formats/ntfs.h b/include/iprt/formats/ntfs.h new file mode 100644 index 00000000..36c0b112 --- /dev/null +++ b/include/iprt/formats/ntfs.h @@ -0,0 +1,782 @@ +/* $Id: ntfs.h $ */ +/** @file + * IPRT, NT File System (NTFS). + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_ntfs_h +#define IPRT_INCLUDED_formats_ntfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/formats/fat.h> + + +/** @defgroup grp_rt_formats_ntfs NT File System (NTFS) structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + +/** Value of the FATBOOTSECTOR::achOemName for an NTFS file system. */ +#define NTFS_OEM_ID_MAGIC "NTFS " + + +/** @name NTFS_MFT_IDX_XXX - Predefined MFT indexes. + * @{ */ +#define NTFS_MFT_IDX_MFT 0 /**< The MFT itself. */ +#define NTFS_MFT_IDX_MFT_MIRROR 1 /**< Mirror MFT (partial?). */ +#define NTFS_MFT_IDX_LOG_FILE 2 /**< Journalling log. */ +#define NTFS_MFT_IDX_VOLUME 3 /**< Volume attributes. */ +#define NTFS_MFT_IDX_ATTRIB_DEF 4 /**< Attribute definitions. */ +#define NTFS_MFT_IDX_ROOT 5 /**< The root directory. */ +#define NTFS_MFT_IDX_BITMAP 6 /**< Allocation bitmap. */ +#define NTFS_MFT_IDX_BOOT 7 /**< The boot sector. */ +#define NTFS_MFT_IDX_BAD_CLUSTER 8 /**< Bad cluster table. */ +#define NTFS_MFT_IDX_SECURITY 9 /**< Shared security descriptors (w2k and later). */ +#define NTFS_MFT_IDX_UP_CASE 10 /**< Unicode upper case table. */ +#define NTFS_MFT_IDX_EXTEND 11 /**< Directory containing further system files. */ +#define NTFS_MFT_IDX_FIRST_USER 16 /**< The first user file. */ +/** @} */ + +/** + * NTFS MFT record reference. + */ +typedef union NTFSMFTREF +{ + /** unsigned 64-bit view. */ + uint64_t u64; + /** unsigned 32-bit view. */ + uint32_t au32[2]; + /** unsigned 16-bit view. */ + uint16_t au16[4]; + + /** Structured view. */ + struct + { + /** Index of the master file table record. */ + RT_GCC_EXTENSION uint64_t idxMft : 48; + /** MFT record reuse sequence number (for catching dangling references). */ + RT_GCC_EXTENSION uint64_t uRecReuseSeqNo : 16; + } s; +} NTFSMFTREF; +AssertCompileSize(NTFSMFTREF, 8); +/** Pointer to a NTFS MFT record reference. */ +typedef NTFSMFTREF *PNTFSMFTREF; +/** Pointer to a const NTFS MFT record reference. */ +typedef NTFSMFTREF const *PCNTFSMFTREF; + +/** @name NTFSMFTREF_GET_IDX + * Gets the MFT index number (host endian) from a MFT reference. */ +/** @name NTFSMFTREF_GET_SEQ + * Gets the MFT reuse sequence number (host endian) from a MFT reference. */ +/** @name NTFSMFTREF_SET_IDX + * Sets the MFT index number of a MFT reference. */ +/** @name NTFSMFTREF_SET_SEQ + * Sets the MFT reuse sequence number of a MFT reference. */ +/** @name NTFSMFTREF_SET + * Sets the values of a MFT reference. */ +#ifdef RT_LITTLE_ENDIAN +# define NTFSMFTREF_GET_IDX(a_pMftRef) ((a_pMftRef)->s.idxMft) +# define NTFSMFTREF_GET_SEQ(a_pMftRef) ((a_pMftRef)->s.uRecReuseSeqNo) +# define NTFSMFTREF_SET_SEQ(a_pMftRef, a_uValue) do { (a_pMftRef)->s.uRecReuseSeqNo = (a_uValue); } while (0) +# define NTFSMFTREF_SET_IDX(a_pMftRef, a_uValue) do { (a_pMftRef)->s.idxMft = (a_uValue); } while (0) +# define NTFSMFTREF_SET(a_pMftRef, a_idx, a_uSeq) \ + do { \ + (a_pMftRef)->s.idxMft = (a_idx); \ + (a_pMftRef)->s.uRecReuseSeqNo = (a_uSeq); \ + } while (0) +#else +# define NTFSMFTREF_GET_IDX(a_pMftRef) (RT_LE2H_U64((a_pMftRef)->u64) & UINT64_C(0x0000ffffffffffff)) +# define NTFSMFTREF_GET_SEQ(a_pMftRef) RT_LE2H_U16((uint16_t)(a_pMftRef)->u64) +# define NTFSMFTREF_SET_SEQ(a_pMftRef, a_uValue) do { (a_pMftRef)->au16[3] = RT_H2LE_U16(a_uValue); } while (0) +# define NTFSMFTREF_SET_IDX(a_pMftRef, a_uValue) \ + do { \ + (a_pMftRef)->au32[0] = RT_H2LE_U32((uint32_t)(a_uValue)); \ + (a_pMftRef)->au16[2] = RT_H2LE_U16((uint16_t)((a_uValue) >> 32)); \ + } while (0) +# define NTFSMFTREF_SET(a_pMftRef, a_idx, a_uSeq) \ + do { \ + (a_pMftRef)->au32[0] = RT_H2LE_U32((uint32_t)(a_idx)); \ + (a_pMftRef)->au16[2] = RT_H2LE_U16((uint16_t)((a_idx) >> 32)); \ + (a_pMftRef)->au16[3] = RT_H2LE_U16((uint16_t)(a_uSeq)); \ + } while (0) +#endif +/** Check that the reference is zero. */ +#define NTFSMFTREF_IS_ZERO(a_pMftRef) ((a_pMftRef)->u64 == 0) + + +/** + * NTFS record header. + */ +typedef struct NTFSRECHDR +{ + /** Magic number (usually ASCII). */ + uint32_t uMagic; + /** Offset of the update sequence array from the start of the record. */ + uint16_t offUpdateSeqArray; + /** Number of entries in the update sequence array. (uint16_t sized entries) */ + uint16_t cUpdateSeqEntries; +} NTFSRECHDR; +AssertCompileSize(NTFSRECHDR, 8); +/** Pointer to a NTFS record header. */ +typedef NTFSRECHDR *PNTFSRECHDR; +/** Pointer to a const NTFS record header. */ +typedef NTFSRECHDR const *PCNTFSRECHDR; + +/** The multi-sector update sequence stride. + * @see https://msdn.microsoft.com/en-us/library/bb470212%28v=vs.85%29.aspx + * @see NTFSRECHDR::offUpdateSeqArray, NTFSRECHDR::cUpdateSeqEntries + */ +#define NTFS_MULTI_SECTOR_STRIDE 512 + + +/** + * NTFS file record (in the MFT). + */ +typedef struct NTFSRECFILE +{ + /** 0x00: Header with NTFSREC_MAGIC_FILE. */ + NTFSRECHDR Hdr; + /** 0x08: Log file sequence number. */ + uint64_t uLsn; + /** 0x10: MFT record reuse sequence number (for dangling MFT references). */ + uint16_t uRecReuseSeqNo; + /** 0x12: Number of hard links. */ + uint16_t cLinks; + /** 0x14: Offset of the first attribute (relative to start of record). */ + uint16_t offFirstAttrib; + /** 0x16: Record flags (NTFSRECFILE_F_XXX). */ + uint16_t fFlags; + /** 0x18: Number of byte in use in this MFT record. */ + uint32_t cbRecUsed; + /** 0x1c: The MFT record size. */ + uint32_t cbRecSize; + /** 0x20: Reference to the base MFT record. */ + NTFSMFTREF BaseMftRec; + /** 0x28: Next attribute instance number. */ + uint16_t idNextAttrib; + /** 0x2a: Padding if NTFS 3.1+, update sequence array if older. */ + uint16_t uPaddingOrUsa; + /** 0x2c: MFT index of this record. */ + uint32_t idxMftSelf; +} NTFSRECFILE; +AssertCompileSize(NTFSRECFILE, 0x30); +/** Pointer to a NTFS file record. */ +typedef NTFSRECFILE *PNTFSRECFILE; +/** Pointer to a const NTFS file record. */ +typedef NTFSRECFILE const *PCNTFSRECFILE; + + +/** NTFS 'FILE' record magic value. */ +#define NTFSREC_MAGIC_FILE RT_H2LE_U32_C(UINT32_C(0x454c4946)) + +/** @name NTFSRECFILE_F_XXX - NTFSRECFILE::fFlags. + * @{ */ +/** MFT record is in use. */ +#define NTFSRECFILE_F_IN_USE RT_H2LE_U16_C(UINT16_C(0x0001)) +/** Directory record. */ +#define NTFSRECFILE_F_DIRECTORY RT_H2LE_U16_C(UINT16_C(0x0002)) +/** @} */ + + +/** @name NTFS_AT_XXX - Attribute types + * @{ */ +#define NTFS_AT_UNUSED RT_H2LE_U32_C(UINT32_C(0x00000000)) +/** NTFSATSTDINFO */ +#define NTFS_AT_STANDARD_INFORMATION RT_H2LE_U32_C(UINT32_C(0x00000010)) +/** NTFSATLISTENTRY */ +#define NTFS_AT_ATTRIBUTE_LIST RT_H2LE_U32_C(UINT32_C(0x00000020)) +/** NTFSATFILENAME */ +#define NTFS_AT_FILENAME RT_H2LE_U32_C(UINT32_C(0x00000030)) +#define NTFS_AT_OBJECT_ID RT_H2LE_U32_C(UINT32_C(0x00000040)) +#define NTFS_AT_SECURITY_DESCRIPTOR RT_H2LE_U32_C(UINT32_C(0x00000050)) +#define NTFS_AT_VOLUME_NAME RT_H2LE_U32_C(UINT32_C(0x00000060)) +/** NTFSATVOLUMEINFO */ +#define NTFS_AT_VOLUME_INFORMATION RT_H2LE_U32_C(UINT32_C(0x00000070)) +#define NTFS_AT_DATA RT_H2LE_U32_C(UINT32_C(0x00000080)) +/** NTFSATINDEXROOT */ +#define NTFS_AT_INDEX_ROOT RT_H2LE_U32_C(UINT32_C(0x00000090)) +#define NTFS_AT_INDEX_ALLOCATION RT_H2LE_U32_C(UINT32_C(0x000000a0)) +#define NTFS_AT_BITMAP RT_H2LE_U32_C(UINT32_C(0x000000b0)) +#define NTFS_AT_REPARSE_POINT RT_H2LE_U32_C(UINT32_C(0x000000c0)) +#define NTFS_AT_EA_INFORMATION RT_H2LE_U32_C(UINT32_C(0x000000d0)) +#define NTFS_AT_EA RT_H2LE_U32_C(UINT32_C(0x000000e0)) +#define NTFS_AT_PROPERTY_SET RT_H2LE_U32_C(UINT32_C(0x000000f0)) +#define NTFS_AT_LOGGED_UTILITY_STREAM RT_H2LE_U32_C(UINT32_C(0x00000100)) +#define NTFS_AT_FIRST_USER_DEFINED RT_H2LE_U32_C(UINT32_C(0x00001000)) +#define NTFS_AT_END RT_H2LE_U32_C(UINT32_C(0xffffffff)) +/** @} */ + +/** @name NTFS_AF_XXX - Attribute flags. + * @{ */ +#define NTFS_AF_COMPR_FMT_NONE RT_H2LE_U16_C(UINT16_C(0x0000)) +/** See RtlCompressBuffer / COMPRESSION_FORMAT_LZNT1. */ +#define NTFS_AF_COMPR_FMT_LZNT1 RT_H2LE_U16_C(UINT16_C(0x0001)) +/** See RtlCompressBuffer / COMPRESSION_FORMAT_XPRESS_HUFF. */ +#define NTFS_AF_COMPR_FMT_XPRESS RT_H2LE_U16_C(UINT16_C(0x0002)) +/** See RtlCompressBuffer / COMPRESSION_FORMAT_XPRESS_HUFF. */ +#define NTFS_AF_COMPR_FMT_XPRESS_HUFF RT_H2LE_U16_C(UINT16_C(0x0003)) +#define NTFS_AF_COMPR_FMT_MASK RT_H2LE_U16_C(UINT16_C(0x00ff)) +#define NTFS_AF_ENCRYPTED RT_H2LE_U16_C(UINT16_C(0x4000)) +#define NTFS_AF_SPARSE RT_H2LE_U16_C(UINT16_C(0x8000)) +/** @} */ + +/** + * NTFS attribute header. + * + * This has three forms: + * - Resident + * - Non-resident, no compression + * - Non-resident, compressed. + * + * Each form translates to a different header size. + */ +typedef struct NTFSATTRIBHDR +{ + /** 0x00: Attribute type (NTFS_AT_XXX). */ + uint32_t uAttrType; + /** 0x04: Length of this attribute (resident part). */ + uint32_t cbAttrib; + /** 0x08: Set (1) if non-resident attribute, 0 if resident. */ + uint8_t fNonResident; + /** 0x09: Attribute name length (can be zero). */ + uint8_t cwcName; + /** 0x0a: Offset of the name string (relative to the start of this header). */ + uint16_t offName; + /** 0x0c: NTFS_AF_XXX. */ + uint16_t fFlags; + /** 0x0e: Attribute instance number. Unique within the MFT record. */ + uint16_t idAttrib; + /** 0x10: Data depending on the fNonResident member value. */ + union + { + /** Resident attributes. */ + struct + { + /** 0x10: Attribute value length. */ + uint32_t cbValue; + /** 0x14: Offset of the value (relative to the start of this header). */ + uint16_t offValue; + /** 0x16: NTFS_RES_AF_XXX. */ + uint8_t fFlags; + /** 0x17: Reserved. */ + uint8_t bReserved; + } Res; + + /** Non-resident attributes. */ + struct + { + /** 0x10: The first virtual cluster containing data. + * + * This is mainly for internal checking when the run list doesn't fit in one + * MFT record. It can also be used to avoid recording a sparse run at the + * beginning of the data covered by this attribute record. */ + int64_t iVcnFirst; + /** 0x18: The last virtual cluster containing data (inclusive). */ + int64_t iVcnLast; + /** 0x20: Offset of the mapping pair program. This program gives us a mapping + * between VNC and LCN for the attribute value. */ + uint16_t offMappingPairs; + /** 0x22: Power of two compression unit size in clusters (cbCluster << uCompessionUnit). + * Zero means uncompressed. */ + uint8_t uCompressionUnit; + /** 0x23: Reserved */ + uint8_t abReserved[5]; + /** 0x28: Allocated size (rouneded to cluster). + * @note Only set in the first attribute record (iVcnFirst == 0). */ + int64_t cbAllocated; + /** 0x30: The exact length of the data. + * @note Only set in the first attribute record (iVcnFirst == 0). */ + int64_t cbData; + /** 0x38: The length of the initialized data. (Not necessarily + * rounded up to cluster size.) + * @note Only set in the first attribute record (iVcnFirst == 0). */ + int64_t cbInitialized; + /** 0x40: Compressed size if compressed, otherwise absent. */ + int64_t cbCompressed; + } NonRes; + } u; +} NTFSATTRIBHDR; +AssertCompileSize(NTFSATTRIBHDR, 0x48); +AssertCompileMemberOffset(NTFSATTRIBHDR, u.Res, 0x10); +AssertCompileMemberOffset(NTFSATTRIBHDR, u.Res.bReserved, 0x17); +AssertCompileMemberOffset(NTFSATTRIBHDR, u.NonRes, 0x10); +AssertCompileMemberOffset(NTFSATTRIBHDR, u.NonRes.cbCompressed, 0x40); +/** Pointer to a NTFS attribute header. */ +typedef NTFSATTRIBHDR *PNTFSATTRIBHDR; +/** Pointer to a const NTFS attribute header. */ +typedef NTFSATTRIBHDR const *PCNTFSATTRIBHDR; + +/** @name NTFSATTRIBHDR_SIZE_XXX - Attribute header sizes. + * @{ */ +/** Attribute header size for resident values. */ +#define NTFSATTRIBHDR_SIZE_RESIDENT (0x18) +/** Attribute header size for uncompressed non-resident values. */ +#define NTFSATTRIBHDR_SIZE_NONRES_UNCOMPRESSED (0x40) +/** Attribute header size for compressed non-resident values. */ +#define NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED (0x48) +/** @} */ + +/** Get the pointer to the embedded name from an attribute. + * @note ASSUMES the caller check that there is a name. */ +#define NTFSATTRIBHDR_GET_NAME(a_pAttrHdr) ( (PRTUTF16)((uintptr_t)(a_pAttrHdr) + (a_pAttrHdr)->offName) ) + +/** Get the pointer to resident value. + * @note ASSUMES the caller checks that it's resident and valid. */ +#define NTFSATTRIBHDR_GET_RES_VALUE_PTR(a_pAttrHdr) ( (uint8_t *)(a_pAttrHdr) + (a_pAttrHdr)->u.Res.offValue ) + + +/** @name NTFS_RES_AF_XXX + * @{ */ +/** Attribute is referenced in an index. */ +#define NTFS_RES_AF_INDEXED UINT8_C(0x01) +/** @} */ + +/** + * Attribute list entry (NTFS_AT_ATTRIBUTE_LIST). + * + * This is used to deal with a file having attributes in more than one MFT + * record. A prominent example is an fragment file (unnamed data attribute) + * which mapping pairs doesn't fit in a single MFT record. + * + * This attribute can be non-resident, however it's mapping pair program must + * fit in the base MFT record. + */ +typedef struct NTFSATLISTENTRY +{ + /** 0x00: Attribute type (NTFS_AT_XXX). */ + uint32_t uAttrType; + /** 0x04: Length of this entry. */ + uint16_t cbEntry; + /** 0x06: Attribute name length (zero if none). */ + uint8_t cwcName; + /** 0x07: Name offset. */ + uint8_t offName; + /** 0x08: The first VNC for this part of the attribute value. */ + int64_t iVcnFirst; + /** 0x10: The MFT record holding the actual attribute. */ + NTFSMFTREF InMftRec; + /** 0x18: Attribute instance number. Unique within the MFT record. */ + uint16_t idAttrib; + /** 0x1a: Maybe where the attribute name starts. */ + RT_FLEXIBLE_ARRAY_EXTENSION + RTUTF16 wszName[RT_FLEXIBLE_ARRAY]; +} NTFSATLISTENTRY; +AssertCompileMemberOffset(NTFSATLISTENTRY, idAttrib, 0x18); +/** Pointer to a NTFS attribute list entry. */ +typedef NTFSATLISTENTRY *PNTFSATLISTENTRY; +/** Pointer to a const NTFS attribute list entry. */ +typedef NTFSATLISTENTRY const *PCNTFSATLISTENTRY; + +/** Unaligned minimum entry size (no name). */ +#define NTFSATLISTENTRY_SIZE_MINIMAL 0x1a + + + +/** + * NTFS standard file info attribute (NTFS_AT_STANDARD_INFORMATION). + */ +typedef struct NTFSATSTDINFO +{ + /** 0x00: Creation timestamp. */ + int64_t iCreationTime; + /** 0x08: Last data modification timestamp. */ + int64_t iLastDataModTime; + /** 0x10: Last MFT record modification timestamp. */ + int64_t iLastMftModTime; + /** 0x18: Last access timestamp. */ + int64_t iLastAccessTime; + /** 0x20: File attributes. */ + uint32_t fFileAttribs; + /** 0x24: Maximum number of file versions allowed. + * @note NTFS 3.x, padding in 1.2 */ + uint32_t cMaxFileVersions; + /** 0x28: Current file version number. + * @note NTFS 3.x, padding in 1.2 */ + uint32_t uFileVersion; + /** 0x2c: Class ID (whatever that is). + * @note NTFS 3.x, padding in 1.2 */ + uint32_t idClass; + /** 0x30: Owner ID. + * Translated via $Q index in NTFS_MFT_IDX_EXTENDED/$Quota. + * @note NTFS 3.x, not present in 1.2 */ + uint32_t idOwner; + /** 0x34: Security ID. Translated via $SII index and $SDS data stream in + * NTFS_MFT_IDX_SECURITY. + * @note NTFS 3.x, not present in 1.2 */ + uint32_t idSecurity; + /** 0x38: Total quota charged for this file. + * @note NTFS 3.x, not present in 1.2 */ + uint64_t cbQuotaChared; + /** 0x40: Last update sequence number, index into $UsnJrnl. + * @note NTFS 3.x, not present in 1.2 */ + uint64_t idxUpdateSequence; +} NTFSATSTDINFO; +AssertCompileSize(NTFSATSTDINFO, 0x48); +/** Pointer to NTFS standard file info. */ +typedef NTFSATSTDINFO *PNTFSATSTDINFO; +/** Pointer to const NTFS standard file info. */ +typedef NTFSATSTDINFO const *PCNTFSATSTDINFO; + +/** The size of NTFSATSTDINFO in NTFS v1.2 and earlier. */ +#define NTFSATSTDINFO_SIZE_NTFS_V12 (0x30) + +/** @name NTFS_FA_XXX - NTFS file attributes (host endian). + * @{ */ +#define NTFS_FA_READONLY UINT32_C(0x00000001) +#define NTFS_FA_HIDDEN UINT32_C(0x00000002) +#define NTFS_FA_SYSTEM UINT32_C(0x00000004) +#define NTFS_FA_DIRECTORY UINT32_C(0x00000010) +#define NTFS_FA_ARCHIVE UINT32_C(0x00000020) +#define NTFS_FA_DEVICE UINT32_C(0x00000040) +#define NTFS_FA_NORMAL UINT32_C(0x00000080) +#define NTFS_FA_TEMPORARY UINT32_C(0x00000100) +#define NTFS_FA_SPARSE_FILE UINT32_C(0x00000200) +#define NTFS_FA_REPARSE_POINT UINT32_C(0x00000400) +#define NTFS_FA_COMPRESSED UINT32_C(0x00000800) +#define NTFS_FA_OFFLINE UINT32_C(0x00001000) +#define NTFS_FA_NOT_CONTENT_INDEXED UINT32_C(0x00002000) +#define NTFS_FA_ENCRYPTED UINT32_C(0x00004000) +#define NTFS_FA_VALID_FLAGS UINT32_C(0x00007fb7) +#define NTFS_FA_VALID_SET_FLAGS UINT32_C(0x000031a7) +#define NTFS_FA_DUP_FILE_NAME_INDEX_PRESENT UINT32_C(0x10000000) /**< This means directory apparently. */ +#define NTFS_FA_DUP_VIEW_INDEX_PRESENT UINT32_C(0x20000000) /**< ?? */ +/** @} */ + + + +/** + * NTFS filename attribute (NTFS_AT_FILENAME). + */ +typedef struct NTFSATFILENAME +{ + /** 0x00: The parent directory MFT record. */ + NTFSMFTREF ParentDirMftRec; + /** 0x08: Creation timestamp. */ + int64_t iCreationTime; + /** 0x10: Last data modification timestamp. */ + int64_t iLastDataModTime; + /** 0x18: Last MFT record modification timestamp. */ + int64_t iLastMftModTime; + /** 0x20: Last access timestamp. */ + int64_t iLastAccessTime; + /** 0x28: Allocated disk space for the unnamed data attribute. */ + int64_t cbAllocated; + /** 0x30: Actual size of unnamed data attribute. */ + int64_t cbData; + /** 0x38: File attributes (NTFS_FA_XXX). */ + uint32_t fFileAttribs; + union + { + /** 0x3c: Packed EA length. */ + uint16_t cbPackedEas; + /** 0x3c: Reparse tag, if no EAs. */ + uint32_t uReparseTag; + } u; + /** 0x40: Filename length in unicode chars. */ + uint8_t cwcFilename; + /** 0x41: Filename type (NTFS_FILENAME_T_XXX). */ + uint8_t fFilenameType; + /** 0x42: The filename. */ + RT_FLEXIBLE_ARRAY_EXTENSION + RTUTF16 wszFilename[RT_FLEXIBLE_ARRAY]; +} NTFSATFILENAME; +AssertCompileMemberOffset(NTFSATFILENAME, cbData, 0x30); +AssertCompileMemberOffset(NTFSATFILENAME, u.cbPackedEas, 0x3c); +AssertCompileMemberOffset(NTFSATFILENAME, u.uReparseTag, 0x3c); +AssertCompileMemberOffset(NTFSATFILENAME, wszFilename, 0x42); +/** Pointer to a NTFS filename attribute. */ +typedef NTFSATFILENAME *PNTFSATFILENAME; +/** Pointer to a const NTFS filename attribute. */ +typedef NTFSATFILENAME const *PCNTFSATFILENAME; + +/** @name NTFS_FILENAME_T_XXX - filename types + * @{ */ +#define NTFS_FILENAME_T_POSIX 0 +#define NTFS_FILENAME_T_WINDOWS 1 +#define NTFS_FILENAME_T_DOS 2 +#define NTFS_FILENAME_T_WINDOWS_AND_DSO 3 +/** @} */ + + +/** + * NTFS volume information (NTFS_AT_VOLUME_INFORMATION). + * + * This is found in the special NTFS_MFT_IDX_VOLUME file. + */ +typedef struct NTFSATVOLUMEINFO +{ + /** 0x00: Reserved bytes. */ + uint8_t abReserved[8]; + /** 0x08: Major NTFS version number. */ + uint8_t uMajorVersion; + /** 0x09: Minor NTFS version number. */ + uint8_t uMinorVersion; + /** 0x0a: Volume flags (NTFS_VOLUME_F_XXX) */ + uint16_t fFlags; +} NTFSATVOLUMEINFO; +AssertCompileSize(NTFSATVOLUMEINFO, 12); +/** Pointer to NTFS volume information. */ +typedef NTFSATVOLUMEINFO *PNTFSATVOLUMEINFO; +/** Pointer to const NTFS volume information. */ +typedef NTFSATVOLUMEINFO const *PCNTFSATVOLUMEINFO; + +/** @name NTFS_VOLUME_F_XXX + * @{ */ +#define NTFS_VOLUME_F_DIRTY RT_H2LE_U16_C(0x0001) /**< Volume is dirty. */ +#define NTFS_VOLUME_F_RESIZE_LOG_FILE RT_H2LE_U16_C(0x0002) /**< */ +#define NTFS_VOLUME_F_UPGRADE_ON_MOUNT RT_H2LE_U16_C(0x0004) /**< */ +#define NTFS_VOLUME_F_MOUNTED_ON_NT4 RT_H2LE_U16_C(0x0008) /**< */ +#define NTFS_VOLUME_F_DELETE_USN_UNDERWAY RT_H2LE_U16_C(0x0010) /**< */ +#define NTFS_VOLUME_F_REPAIR_OBJECT_ID RT_H2LE_U16_C(0x0020) /**< */ +#define NTFS_VOLUME_F_CHKDSK_UNDERWAY RT_H2LE_U16_C(0x4000) /**< */ +#define NTFS_VOLUME_F_MODIFIED_BY_CHKDSK RT_H2LE_U16_C(0x8000) /**< */ + +#define NTFS_VOLUME_F_KNOWN_MASK RT_H2LE_U16_C(0xc03f) +#define NTFS_VOLUME_F_MOUNT_READONLY_MASK RT_H2LE_U16_C(0xc027) +/** @} */ + + +/** The attribute name used by the index attributes on NTFS directories, + * ASCII stirng variant. */ +#define NTFS_DIR_ATTRIBUTE_NAME "$I30" + +/** + * NTFS index header. + * + * This is used by NTFSATINDEXROOT and NTFSATINDEXALLOC as a prelude to the + * sequence of entries in a node. + */ +typedef struct NTFSINDEXHDR +{ + /** 0x00: Offset of the first entry relative to this header. */ + uint32_t offFirstEntry; + /** 0x04: Current index size in bytes, including this header. */ + uint32_t cbUsed; + /** 0x08: Number of bytes allocated for the index (including this header). */ + uint32_t cbAllocated; + /** 0x0c: Flags (NTFSINDEXHDR_F_XXX). */ + uint8_t fFlags; + /** 0x0d: Reserved bytes. */ + uint8_t abReserved[3]; + /* NTFSIDXENTRYHDR sequence typically follows here */ +} NTFSINDEXHDR; +AssertCompileSize(NTFSINDEXHDR, 16); +/** Pointer to a NTFS index header. */ +typedef NTFSINDEXHDR *PNTFSINDEXHDR; +/** Pointer to a const NTFS index header. */ +typedef NTFSINDEXHDR const *PCNTFSINDEXHDR; + +/** @name NTFSINDEXHDR_F_XXX + * @{ */ +/** An internal node (as opposed to a leaf node if clear). + * This means that the entries will have trailing node references (VCN). */ +#define NTFSINDEXHDR_F_INTERNAL UINT8_C(0x01) +/** @} */ + +/** Gets the pointer to the first entry header for an index. */ +#define NTFSINDEXHDR_GET_FIRST_ENTRY(a_pIndexHdr) \ + ( (PNTFSIDXENTRYHDR)((uint8_t *)(a_pIndexHdr) + RT_LE2H_U32((a_pIndexHdr)->offFirstEntry)) ) + + +/** + * NTFS index root node (NTFS_AT_INDEX_ROOT). + * + * This is a generic index structure, but is most prominently used for + * implementating directories. The index is structured like B-tree, meaning + * each node contains multiple entries, and each entry contains data regardless + * of whether it's a leaf node or not. + * + * The index is sorted in ascending order according to the collation rules + * defined by the root node (NTFSATINDEXROOT::uCollationRules, see also (see + * NTFS_COLLATION_XXX). + * + * @note The root directory contains a '.' entry, others don't. + */ +typedef struct NTFSATINDEXROOT +{ + /** 0x00: The index type (NTFSATINDEXROOT_TYPE_XXX). */ + uint32_t uType; + /** 0x04: The sorting rules to use (NTFS_COLLATION_XXX). */ + uint32_t uCollationRules; + /** 0x08: Number of bytes in + * Index node size (in bytes). */ + uint32_t cbIndexNode; + /** 0x0c: Number of node addresses per node. + * This sounds weird right? A subnode is generally addressed as a virtual + * cluster when cbIndexNode >= cbCluster, but when clusters are large NTFS uses + * 512 bytes chunks. + * + * (You would've thought it would be simpler to just use cbIndexNode as the + * addressing unit, maybe storing the log2 here to avoid a ffs call.) */ + uint8_t cAddressesPerIndexNode; + /** 0x0d: Reserved padding or something. */ + uint8_t abReserved[3]; + /** 0x10: Index header detailing the entries that follows. */ + NTFSINDEXHDR Hdr; + /* 0x20: NTFSIDXENTRYHDR sequence typically follows here */ +} NTFSATINDEXROOT; +AssertCompileSize(NTFSATINDEXROOT, 32); +/** Pointer to a NTFS index root. */ +typedef NTFSATINDEXROOT *PNTFSATINDEXROOT; +/** Pointer to a const NTFS index root. */ +typedef NTFSATINDEXROOT const *PCNTFSATINDEXROOT; + +/** @name NTFSATINDEXROOT_TYPE_XXX + * @{ */ +/** View index. */ +#define NTFSATINDEXROOT_TYPE_VIEW RT_H2LE_U32_C(UINT32_C(0x00000000)) +/** Directory index, NTFSATFILENAME follows NTFSINDEXENTRY. */ +#define NTFSATINDEXROOT_TYPE_DIR RT_H2LE_U32_C(UINT32_C(0x00000030)) +/** @} */ + +/** @name NTFS_COLLATION_XXX - index sorting rules + * @{ */ +/** Little endian binary compare (or plain byte compare if you like). */ +#define NTFS_COLLATION_BINARY RT_H2LE_U32_C(UINT32_C(0x00000000)) +/** Same as NTFS_COLLATION_UNICODE_STRING. */ +#define NTFS_COLLATION_FILENAME RT_H2LE_U32_C(UINT32_C(0x00000001)) +/** Compare the uppercased unicode characters. */ +#define NTFS_COLLATION_UNICODE_STRING RT_H2LE_U32_C(UINT32_C(0x00000002)) + +/** Single little endian 32-bit unsigned integer value as sort key. */ +#define NTFS_COLLATION_UINT32 RT_H2LE_U32_C(UINT32_C(0x00000010)) +/** Little endian SID value as sort key. */ +#define NTFS_COLLATION_SID RT_H2LE_U32_C(UINT32_C(0x00000011)) +/** Two little endian 32-bit unsigned integer values used as sorting key. */ +#define NTFS_COLLATION_UINT32_PAIR RT_H2LE_U32_C(UINT32_C(0x00000012)) +/** Sequence of little endian 32-bit unsigned integer values used as sorting key. */ +#define NTFS_COLLATION_UINT32_SEQ RT_H2LE_U32_C(UINT32_C(0x00000013)) +/** @} */ + + +/** + * NTFS index non-root node. + */ +typedef struct NTFSATINDEXALLOC +{ + /** 0x00: Header with NTFSREC_MAGIC_INDEX_ALLOC. */ + NTFSRECHDR RecHdr; + /** 0x08: Log file sequence number. */ + uint64_t uLsn; + /** 0x10: The node address of this node (for consistency checking and + * perhaps data reconstruction). + * @see NTFSATINDEXROOT::cAddressesPerIndexNode for node addressing. */ + int64_t iSelfAddress; + /** 0x18: Index header detailing the entries that follows. */ + NTFSINDEXHDR Hdr; + /* 0x28: NTFSIDXENTRYHDR sequence typically follows here */ +} NTFSATINDEXALLOC; +AssertCompileSize(NTFSATINDEXALLOC, 40); +/** Pointer to a NTFS index non-root node. */ +typedef NTFSATINDEXALLOC *PNTFSATINDEXALLOC; +/** Pointer to a const NTFS index non-root node. */ +typedef NTFSATINDEXALLOC const *PCNTFSATINDEXALLOC; + +/** NTFS 'INDX' attribute magic value (NTFSATINDEXALLOC). + * @todo sort out the record / attribute name clash here. */ +#define NTFSREC_MAGIC_INDEX_ALLOC RT_H2LE_U32_C(UINT32_C(0x58444e49)) + + +/** + * NTFS index entry header. + * + * Each entry in a node starts with this header. It is immediately followed by + * the key data (NTFSIDXENTRYHDR::cbKey). When + * + */ +typedef struct NTFSIDXENTRYHDR +{ + union + { + /** 0x00: NTFSATINDEXROOT_TYPE_DIR: Reference to the MFT record being indexed here. + * @note This is invalid if NTFSIDXENTRYHDR_F_END is set (no key data). */ + NTFSMFTREF FileMftRec; + /** 0x00: NTFSATINDEXROOT_TYPE_VIEW: Go figure later if necessary. */ + struct + { + /** 0x00: Offset to the data relative to this header. + * @note This is invalid if NTFSIDXENTRYHDR_F_END is set (no key data). */ + uint16_t offData; + /** 0x02: Size of data at offData. + * @note This is invalid if NTFSIDXENTRYHDR_F_END is set (no key data). */ + uint16_t cbData; + /** 0x04: Reserved. */ + uint32_t uReserved; + } View; + } u; + + /** 0x08: Size of this entry, 8-byte aligned. */ + uint16_t cbEntry; + /** 0x0a: Key length (unaligned). */ + uint16_t cbKey; + /** 0x0c: Entry flags, NTFSIDXENTRYHDR_F_XXX. */ + uint16_t fFlags; + /** 0x0e: Reserved. */ + uint16_t uReserved; +} NTFSIDXENTRYHDR; +AssertCompileSize(NTFSIDXENTRYHDR, 16); +/** Pointer to a NTFS index entry header. */ +typedef NTFSIDXENTRYHDR *PNTFSIDXENTRYHDR; +/** Pointer to a const NTFS index entry header. */ +typedef NTFSIDXENTRYHDR const *PCNTFSIDXENTRYHDR; + +/** @name NTFSIDXENTRYHDR_F_XXX - NTFSIDXENTRYHDR::fFlags + * @{ */ +/** Indicates an internal node (as opposed to a leaf node). + * This indicates that there is a 64-bit integer value at the very end of the + * entry (NTFSIDXENTRYHDR::cbEntry - 8) giving the virtual cluster number of the + * subnode. The subnode and all its decendants contain keys that are lower than + * the key in this entry. + */ +#define NTFSIDXENTRYHDR_F_INTERNAL RT_H2LE_U16_C(UINT16_C(0x0001)) +/** Set if special end entry in a node. + * This does not have any key data, but can point to a subnode with + * higher keys. */ +#define NTFSIDXENTRYHDR_F_END RT_H2LE_U16_C(UINT16_C(0x0002)) +/** @} */ + +/** Gets the pointer to the next index entry header. */ +#define NTFSIDXENTRYHDR_GET_NEXT(a_pEntryHdr) \ + ( (PNTFSIDXENTRYHDR)((uintptr_t)(a_pEntryHdr) + RT_LE2H_U16((a_pEntryHdr)->cbEntry)) ) +/** Gets the subnode address from an index entry. + * @see NTFSATINDEXROOT::cAddressesPerIndexNode for node addressing. + * @note Only invoke when NTFSIDXENTRYHDR_F_INTERNAL is set! */ +#define NTFSIDXENTRYHDR_GET_SUBNODE(a_pEntryHdr) \ + ( *(int64_t *)((uintptr_t)(a_pEntryHdr) + RT_LE2H_U16((a_pEntryHdr)->cbEntry) - sizeof(int64_t)) ) + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_ntfs_h */ + diff --git a/include/iprt/formats/omf.h b/include/iprt/formats/omf.h new file mode 100644 index 00000000..b5ffb01d --- /dev/null +++ b/include/iprt/formats/omf.h @@ -0,0 +1,260 @@ +/* $Id: omf.h $ */ +/** @file + * IPRT - Relocatable Object Module Format (OMF). + * + * @remarks For a more details description, see specification from Tools + * Interface Standards (TIS), version 1.1 dated May 2015. + * Typically named found as OMF_v1.1.pdf. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_omf_h +#define IPRT_INCLUDED_formats_omf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/stdint.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_rt_formats_omf Relocatable Object Module Format (OMF) structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + +/** + * OMF record header. + */ +#pragma pack(1) +typedef struct OMFRECHDR +{ + /** The record type. */ + uint8_t bType; + /** The record length, excluding the this header. */ + uint16_t cbLen; +} OMFRECHDR; +#pragma pack() +AssertCompileSize(OMFRECHDR, 3); +/** Pointer to an OMF header. */ +typedef OMFRECHDR *POMFRECHDR; +/** Pointer to a const OMF header. */ +typedef OMFRECHDR *PCOMFRECHDR; + +/** The max OMF record length, including the header. */ +#define OMF_MAX_RECORD_LENGTH UINT16_C(1024) + +/** The max OMF record payload, including CRC byte. */ +#define OMF_MAX_RECORD_PAYLOAD UINT16_C(1021) + + +/** @name OMF Record Types (OMFRECHDR::bType). + * @{ */ +/** Record type flag indicating 32-bit record. */ +#define OMF_REC32 UINT8_C(0x01) +/** Object file header record. + * Is followed by a length prefixed string */ +#define OMF_THEADR UINT8_C(0x80) +/** Comment record. + * Is followed by a comment type byte and a commen class byte, thereafter comes + * type specific byte sequence. */ +#define OMF_COMENT UINT8_C(0x88) +/** Local name table referenced by segment and group defintions. + * Array of length prefixed strings. Multi record. */ +#define OMF_LNAMES UINT8_C(0x96) +/** 16-bit segment definition. + * Complicated, see TIS docs. */ +#define OMF_SEGDEF16 UINT8_C(0x98) +/** 32-bit segment definition. + * Complicated, see TIS docs. */ +#define OMF_SEGDEF32 UINT8_C(0x99) +/** Segment group definition. + * Starts with an LNAMES index (one or two bytes) of the group name. Followed + * by an array which entries consists of a 0xff byte and a segment + * defintion index (one or two bytes). */ +#define OMF_GRPDEF UINT8_C(0x9a) +/** External symbol defintions. + * Array where each entry is a length prefixed symbol name string followed by a + * one or two byte type number. */ +#define OMF_EXTDEF UINT8_C(0x8c) +/** 16-but public symbol definitions. + * Starts with a group index (one or two bytes) and a segment index (ditto) + * which indicates which group/segment the symbols belong to. + * Is followed by an array with entries consiting of a length prefixed symbol + * name string, a two byte segment offset, and a one or two byte type index. */ +#define OMF_PUBDEF16 UINT8_C(0x90) +/** 32-but public symbol definitions. + * Identical to #OMF_PUBDEF16 except that the symbol offset field is four + * byte. */ +#define OMF_PUBDEF32 UINT8_C(0x91) +/** 16-bit local symbol definitions. + * Same format as #OMF_PUBDEF16. */ +#define OMF_LPUBDEF16 UINT8_C(0xb6) +/** 16-bit local symbol definitions. + * Same format as #OMF_PUBDEF32. */ +#define OMF_LPUBDEF32 UINT8_C(0xb7) +/** Logical enumerated data record (a chunk of raw segment bits). + * Starts with the index of the segment it contributes to (one or two bytes) and + * is followed by the offset into the segment of the bytes (two bytes). + * After that comes the raw data bytes. */ +#define OMF_LEDATA16 UINT8_C(0xa0) +/** Logical enumerated data record (a chunk of raw segment bits). + * Identical to #OMF_LEDATA16 except that is has a the segment offset field is + * four bytes. */ +#define OMF_LEDATA32 UINT8_C(0xa1) +/** 16-bit fixup record. + * Complicated, see TIS docs. */ +#define OMF_FIXUPP16 UINT8_C(0x9c) +/** 32-bit fixup record. + * Complicated, see TIS docs. */ +#define OMF_FIXUPP32 UINT8_C(0x9d) +/** 16-bit line numbers record. */ +#define OMF_LINNUM16 UINT8_C(0x94) +/** 32-bit line numbers record. */ +#define OMF_LINNUM32 UINT8_C(0x95) +/** 16-bit object file end record. + * Duh! wrong bitfield order. + * + * Starts with a byte bitfield indicating module type: bit 0 is set if this is a + * main program module; bit 1 is set if this is a start address is available; + * bits 2 thru 6 are reserved and must be zero; bit 7 is set to indicate + * a non-absolute start address. + * + * When bit 1 is set what follow is: A FIXUPP byte, one or two byte frame datum, + * one or two byte target datum, and a 2 byte target displacement. */ +#define OMF_MODEND16 UINT8_C(0x8a) +/** 32-bit object file end record. + * Identical to #OMF_MODEND16 except that is has a 4 byte target + * displacement field. */ +#define OMF_MODEND32 UINT8_C(0x8b) +/** @} */ + +/** @name OMF COMENT Type Flags + * @{ */ +/** Comment type: Don't remove comment when object is manipulated. */ +#define OMF_CTYP_NO_PURGE UINT8_C(0x80) +/** Comment type: Don't include in object listing. */ +#define OMF_CTYP_NO_LIST UINT8_C(0x40) +/** @} */ + +/** @name OMF COMENT Classes + * @{ */ +/** Comment class: Dependency file. + * Is followed by a dword timestamp (1980 based?) and a length prefix + * filename string. */ +#define OMF_CCLS_DEP_FILE UINT8_C(0x88) +/** Comment class: Link pass separator. + * Contains a byte with the value 01 to indicate the linker can stop pass 1 + * processing now. */ +#define OMF_CCLS_LINK_PASS_SEP UINT8_C(0xa2) +/** Comment class: Borland type information. */ +#define OMF_CCLS_BORLAND_TYPES UINT8_C(0xe3) +/** Comment class: Borland symbol information. */ +#define OMF_CCLS_BORLAND_SYMBOLS UINT8_C(0xe6) +/** Comment class: Borland source file (applies to subsequent LINNUMs). */ +#define OMF_CCLS_BORLAND_SRC_FILE UINT8_C(0xe8) +/** Comment class: Borland dependency files. */ +#define OMF_CCLS_BORLAND_DEP_FILES UINT8_C(0xe9) +/** @} */ + +/** @name OMF SEGDEF Attrib. + * @{ */ +#define OMF_SEG_ATTR_ALIGN_ABS (UINT8_C(0) << 5) /**< SEGDEF attrib A: absolute - frame and offset fields present. */ +#define OMF_SEG_ATTR_ALIGN_BYTE (UINT8_C(1) << 5) /**< SEGDEF attrib A: 1-byte alignment. */ +#define OMF_SEG_ATTR_ALIGN_WORD (UINT8_C(2) << 5) /**< SEGDEF attrib A: 2-byte alignment. */ +#define OMF_SEG_ATTR_ALIGN_PARA (UINT8_C(3) << 5) /**< SEGDEF attrib A: 16-byte alignment. */ +#define OMF_SEG_ATTR_ALIGN_PAGE (UINT8_C(4) << 5) /**< SEGDEF attrib A: 4096-byte alignment (or 256-byte). */ +#define OMF_SEG_ATTR_ALIGN_DWORD (UINT8_C(5) << 5) /**< SEGDEF attrib A: 4-byte alignment. */ +#define OMF_SEG_ATTR_ALIGN_6 (UINT8_C(6) << 5) /**< SEGDEF attrib A: not supported (load-time locatable, paragraph aligned). */ +#define OMF_SEG_ATTR_ALIGN_7 (UINT8_C(7) << 5) /**< SEGDEF attrib A: undefined. */ +#define OMF_SEG_ATTR_ALIGN_MASK (UINT8_C(7) << 5) /**< SEGDEF attrib A: Mask for the alignment field. */ +#define OMF_SEG_ATTR_ALIGN_SHIFT 5 /**< SEGDEF attrib A: Shift count for the alignment field. */ + +#define OMF_SEG_ATTR_COMB_PRIVATE (UINT8_C(0) << 2) /**< SEGDEF attrib C: Private - do not combine with anyone. */ +#define OMF_SEG_ATTR_COMB_1 (UINT8_C(1) << 2) /**< SEGDEF attrib C: Reserved */ +#define OMF_SEG_ATTR_COMB_PUBLIC (UINT8_C(2) << 2) /**< SEGDEF attrib C: Public - append at offset meeting alignment. */ +#define OMF_SEG_ATTR_COMB_3 (UINT8_C(3) << 2) /**< SEGDEF attrib C: Reserved */ +#define OMF_SEG_ATTR_COMB_PUBLIC_4 (UINT8_C(4) << 2) /**< SEGDEF attrib C: Public - append at offset meeting alignment. */ +#define OMF_SEG_ATTR_COMB_STACK (UINT8_C(5) << 2) /**< SEGDEF attrib C: Stack - same as public, but forced byte alignment. */ +#define OMF_SEG_ATTR_COMB_COMMON (UINT8_C(6) << 2) /**< SEGDEF attrib C: Common - overlay using maximum size. */ +#define OMF_SEG_ATTR_COMB_PUBLIC_7 (UINT8_C(5) << 2) /**< SEGDEF attrib C: Public - append at offset meeting alignment. */ +#define OMF_SEG_ATTR_COMB_MASK (UINT8_C(7) << 2) /**< SEGDEF attrib C: Mask for the combination field. */ +#define OMF_SEG_ATTR_COMB_SHIFT 2 /**< SEGDEF attrib C: Shift count for the combination field. */ +#define OMF_SEG_ATTR_BIG UINT8_C(2) /**< SEGDEF attrib B: Big segment 64K / 4GB. */ +#define OMF_SEG_ATTR_USE32 UINT8_C(1) /**< SEGDEF attrib P: Indicates 32-bit data or code. */ +#define OMF_SEG_ATTR_USE16 UINT8_C(0) /**< SEGDEF attrib ~P: Just for spelling out !USE32. */ +/** @} */ + + +/** @name OMF FIXUPP Locations. + * @{ */ +#define OMF_FIX_LOC_8BIT_LOW_BYTE UINT8_C(0) /**< FIXUP location: low byte (offset or displacement). */ +#define OMF_FIX_LOC_16BIT_OFFSET UINT8_C(1) /**< FIXUP location: 16-bit offset. */ +#define OMF_FIX_LOC_16BIT_SEGMENT UINT8_C(2) /**< FIXUP location: 16-bit segment. */ +#define OMF_FIX_LOC_1616FAR UINT8_C(3) /**< FIXUP location: 16:16 far pointer. */ +#define OMF_FIX_LOC_8BIT_HIGH_BYTE UINT8_C(4) /**< FIXUP location: high byte (offset). Not supported by MS/IBM. */ +#define OMF_FIX_LOC_16BIT_OFFSET_LDR UINT8_C(5) /**< FIXUP location: 16-bit loader resolved offset, same a 1 for linker. PharLab conflict. */ +#define OMF_FIX_LOC_RESERVED_FAR1632 UINT8_C(6) /**< FIXUP location: PharLab 16:32 far pointers, not defined by MS/IBM. */ +#define OMF_FIX_LOC_RESERVED_7 UINT8_C(7) /**< FIXUP location: Not defined. */ +#define OMF_FIX_LOC_RESERVED_8 UINT8_C(8) /**< FIXUP location: Not defined. */ +#define OMF_FIX_LOC_32BIT_OFFSET UINT8_C(9) /**< FIXUP location: 32-bit offset. */ +#define OMF_FIX_LOC_RESERVED_10 UINT8_C(10) /**< FIXUP location: Not defined. */ +#define OMF_FIX_LOC_1632FAR UINT8_C(11) /**< FIXUP location: 16:32 far pointer. */ +#define OMF_FIX_LOC_RESERVED_12 UINT8_C(12) /**< FIXUP location: Not defined. */ +#define OMF_FIX_LOC_32BIT_OFFSET_LDR UINT8_C(13) /**< FIXUP location: 32-bit loader resolved offset, same as 9 for linker. */ +/** @} */ +/** @name OMF FIXUPP Targets + * @{ */ +#define OMF_FIX_T_SEGDEF UINT8_C(0) /**< FIXUP target: SEGDEF index. */ +#define OMF_FIX_T_GRPDEF UINT8_C(1) /**< FIXUP target: GRPDEF index. */ +#define OMF_FIX_T_EXTDEF UINT8_C(2) /**< FIXUP target: EXTDEF index. */ +#define OMF_FIX_T_FRAME_NO UINT8_C(3) /**< FIXUP target: Explicit frame number, not supported by MS/IBM. */ +#define OMF_FIX_T_SEGDEF_NO_DISP UINT8_C(4) /**< FIXUP target: SEGDEF index only, displacement take as 0. */ +#define OMF_FIX_T_GRPDEF_NO_DISP UINT8_C(5) /**< FIXUP target: GRPDEF index only, displacement take as 0. */ +#define OMF_FIX_T_EXTDEF_NO_DISP UINT8_C(6) /**< FIXUP target: EXTDEF index only, displacement take as 0. */ +/** @} */ +/** @name OMF FIXUPP Frames + * @{ */ +#define OMF_FIX_F_SEGDEF UINT8_C(0) /**< FIXUP frame: SEGDEF index. */ +#define OMF_FIX_F_GRPDEF UINT8_C(1) /**< FIXUP frame: GRPDEF index. */ +#define OMF_FIX_F_EXTDEF UINT8_C(2) /**< FIXUP frame: EXTDEF index. */ +#define OMF_FIX_F_FRAME_NO UINT8_C(3) /**< FIXUP frame: Explicit frame number, not supported by any linkers. */ +#define OMF_FIX_F_LXDATA_SEG UINT8_C(4) /**< FIXUP frame: Determined from the data being fixed up. (No index field.) */ +#define OMF_FIX_F_TARGET_SEG UINT8_C(5) /**< FIXUP frame: Determined from the target. (No index field.) */ +#define OMF_FIX_F_RESERVED_6 UINT8_C(6) /**< FIXUP frame: Reserved. */ +/** @} */ + + +/** @} */ +#endif /* !IPRT_INCLUDED_formats_omf_h */ + diff --git a/include/iprt/formats/pe.mac b/include/iprt/formats/pe.mac new file mode 100644 index 00000000..62bf83b1 --- /dev/null +++ b/include/iprt/formats/pe.mac @@ -0,0 +1,732 @@ +;; @file +; IPRT - Windows PE definitions for YASM/NASM. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___iprt_format_pe_mac +%define ___iprt_format_pe_mac + + +;******************************************************************************* +;* Header Files * +;******************************************************************************* +%include "iprt/asmdefs.mac" + + +;******************************************************************************* +;* Defined Constants And Macros * +;******************************************************************************* +%define IMAGE_NT_SIGNATURE 0x00004550 + +; file header +%define IMAGE_FILE_MACHINE_I386 0x014c +%define IMAGE_FILE_MACHINE_AMD64 0x8664 + +%define IMAGE_FILE_RELOCS_STRIPPED 0x0001 +%define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 +%define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 +%define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 +%define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 +%define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 +%define IMAGE_FILE_16BIT_MACHINE 0x0040 +%define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 +%define IMAGE_FILE_32BIT_MACHINE 0x0100 +%define IMAGE_FILE_DEBUG_STRIPPED 0x0200 +%define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 +%define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 +%define IMAGE_FILE_SYSTEM 0x1000 +%define IMAGE_FILE_DLL 0x2000 +%define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 +%define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 + + +; optional header +%define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10B +%define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20B + +%define IMAGE_SUBSYSTEM_UNKNOWN 0x0 +%define IMAGE_SUBSYSTEM_NATIVE 0x1 +%define IMAGE_SUBSYSTEM_WINDOWS_GUI 0x2 +%define IMAGE_SUBSYSTEM_WINDOWS_CUI 0x3 +%define IMAGE_SUBSYSTEM_OS2_GUI 0x4 +%define IMAGE_SUBSYSTEM_OS2_CUI 0x5 +%define IMAGE_SUBSYSTEM_POSIX_CUI 0x7 + +%define IMAGE_LIBRARY_PROCESS_INIT 0x0001 +%define IMAGE_LIBRARY_PROCESS_TERM 0x0002 +%define IMAGE_LIBRARY_THREAD_INIT 0x0004 +%define IMAGE_LIBRARY_THREAD_TERM 0x0008 +%define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 +%define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 +%define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 +%define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 +%define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 + +%define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 0x10 + +%define IMAGE_DIRECTORY_ENTRY_EXPORT 0x0 +%define IMAGE_DIRECTORY_ENTRY_IMPORT 0x1 +%define IMAGE_DIRECTORY_ENTRY_RESOURCE 0x2 +%define IMAGE_DIRECTORY_ENTRY_EXCEPTION 0x3 +%define IMAGE_DIRECTORY_ENTRY_SECURITY 0x4 +%define IMAGE_DIRECTORY_ENTRY_BASERELOC 0x5 +%define IMAGE_DIRECTORY_ENTRY_DEBUG 0x6 +%define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 0x7 +%define IMAGE_DIRECTORY_ENTRY_COPYRIGHT IMAGE_DIRECTORY_ENTRY_ARCHITECTURE +%define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 0x8 +%define IMAGE_DIRECTORY_ENTRY_TLS 0x9 +%define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 0xa +%define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 0xb +%define IMAGE_DIRECTORY_ENTRY_IAT 0xc +%define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 0xd +%define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 0xe + + +; section header +%define IMAGE_SIZEOF_SHORT_NAME 0x8 + +%define IMAGE_SCN_TYPE_REG 0x00000000 +%define IMAGE_SCN_TYPE_DSECT 0x00000001 +%define IMAGE_SCN_TYPE_NOLOAD 0x00000002 +%define IMAGE_SCN_TYPE_GROUP 0x00000004 +%define IMAGE_SCN_TYPE_NO_PAD 0x00000008 +%define IMAGE_SCN_TYPE_COPY 0x00000010 + +%define IMAGE_SCN_CNT_CODE 0x00000020 +%define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +%define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 + +%define IMAGE_SCN_LNK_OTHER 0x00000100 +%define IMAGE_SCN_LNK_INFO 0x00000200 +%define IMAGE_SCN_TYPE_OVER 0x00000400 +%define IMAGE_SCN_LNK_REMOVE 0x00000800 +%define IMAGE_SCN_LNK_COMDAT 0x00001000 +%define IMAGE_SCN_MEM_PROTECTED 0x00004000 +%define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 +%define IMAGE_SCN_GPREL 0x00008000 +%define IMAGE_SCN_MEM_FARDATA 0x00008000 +%define IMAGE_SCN_MEM_SYSHEAP 0x00010000 +%define IMAGE_SCN_MEM_PURGEABLE 0x00020000 +%define IMAGE_SCN_MEM_16BIT 0x00020000 +%define IMAGE_SCN_MEM_LOCKED 0x00040000 +%define IMAGE_SCN_MEM_PRELOAD 0x00080000 + +%define IMAGE_SCN_ALIGN_1BYTES 0x00100000 +%define IMAGE_SCN_ALIGN_2BYTES 0x00200000 +%define IMAGE_SCN_ALIGN_4BYTES 0x00300000 +%define IMAGE_SCN_ALIGN_8BYTES 0x00400000 +%define IMAGE_SCN_ALIGN_16BYTES 0x00500000 +%define IMAGE_SCN_ALIGN_32BYTES 0x00600000 +%define IMAGE_SCN_ALIGN_64BYTES 0x00700000 +%define IMAGE_SCN_ALIGN_128BYTES 0x00800000 +%define IMAGE_SCN_ALIGN_256BYTES 0x00900000 +%define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 +%define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 +%define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 +%define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 +%define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 +%define IMAGE_SCN_ALIGN_MASK 0x00F00000 +%define IMAGE_SCN_ALIGN_SHIFT 20 + +%define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 +%define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +%define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 +%define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 +%define IMAGE_SCN_MEM_SHARED 0x10000000 +%define IMAGE_SCN_MEM_EXECUTE 0x20000000 +%define IMAGE_SCN_MEM_READ 0x40000000 +%define IMAGE_SCN_MEM_WRITE 0x80000000 + + +; relocations +%define IMAGE_REL_BASED_ABSOLUTE 0x0 +%define IMAGE_REL_BASED_HIGH 0x1 +%define IMAGE_REL_BASED_LOW 0x2 +%define IMAGE_REL_BASED_HIGHLOW 0x3 +%define IMAGE_REL_BASED_HIGHADJ 0x4 +%define IMAGE_REL_BASED_MIPS_JMPADDR 0x5 +%define IMAGE_REL_BASED_MIPS_JMPADDR16 0x9 +%define IMAGE_REL_BASED_IA64_IMM64 0x9 +%define IMAGE_REL_BASED_DIR64 0xa +%define IMAGE_REL_BASED_HIGH3ADJ 0xb + + +; imports +%define IMAGE_ORDINAL_FLAG32 0x80000000 +%define IMAGE_ORDINAL_FLAG64 UINT64_MAX(0x8000000000000000) + + +; debug dir +%define IMAGE_DEBUG_TYPE_UNKNOWN UINT32_C(0x0) +%define IMAGE_DEBUG_TYPE_COFF UINT32_C(0x1) +%define IMAGE_DEBUG_TYPE_CODEVIEW UINT32_C(0x2) +%define IMAGE_DEBUG_TYPE_FPO UINT32_C(0x3) +%define IMAGE_DEBUG_TYPE_MISC UINT32_C(0x4) +%define IMAGE_DEBUG_TYPE_EXCEPTION UINT32_C(0x5) +%define IMAGE_DEBUG_TYPE_FIXUP UINT32_C(0x6) +%define IMAGE_DEBUG_TYPE_OMAP_TO_SRC UINT32_C(0x7) +%define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC UINT32_C(0x8) +%define IMAGE_DEBUG_TYPE_BORLAND UINT32_C(0x9) +%define IMAGE_DEBUG_TYPE_RESERVED10 UINT32_C(0x10) + +%define IMAGE_DEBUG_MISC_EXENAME UINT32_C(1) + +; security directory +%define WIN_CERT_REVISION_1_0 UINT16_C(0x0100) +%define WIN_CERT_REVISION_2_0 UINT16_C(0x0200) + +%define WIN_CERT_TYPE_X509 UINT16_C(1) +%define WIN_CERT_TYPE_PKCS_SIGNED_DATA UINT16_C(2) +%define WIN_CERT_TYPE_RESERVED_1 UINT16_C(3) +%define WIN_CERT_TYPE_TS_STACK_SIGNED UINT16_C(4) +%define WIN_CERT_TYPE_EFI_PKCS115 UINT16_C(0x0ef0) +%define WIN_CERT_TYPE_EFI_GUID UINT16_C(0x0ef1) + + +; For .DBG files. +%define IMAGE_SEPARATE_DEBUG_SIGNATURE UINT16_C(0x4944) + +%define IMAGE_SIZE_OF_SYMBOL 18 +%define IMAGE_SIZE_OF_SYMBOL_EX 20 + +%define IMAGE_SYM_UNDEFINED INT16_C(0) +%define IMAGE_SYM_ABSOLUTE INT16_C(-1) +%define IMAGE_SYM_DEBUG INT16_C(-2) + +%define IMAGE_SYM_CLASS_END_OF_FUNCTION UINT8_C(0xff) ; -1 +%define IMAGE_SYM_CLASS_NULL UINT8_C(0) +%define IMAGE_SYM_CLASS_AUTOMATIC UINT8_C(1) +%define IMAGE_SYM_CLASS_EXTERNAL UINT8_C(2) +%define IMAGE_SYM_CLASS_STATIC UINT8_C(3) +%define IMAGE_SYM_CLASS_REGISTER UINT8_C(4) +%define IMAGE_SYM_CLASS_EXTERNAL_DEF UINT8_C(5) +%define IMAGE_SYM_CLASS_LABEL UINT8_C(6) +%define IMAGE_SYM_CLASS_UNDEFINED_LABEL UINT8_C(7) +%define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT UINT8_C(8) +%define IMAGE_SYM_CLASS_ARGUMENT UINT8_C(9) +%define IMAGE_SYM_CLASS_STRUCT_TAG UINT8_C(10) +%define IMAGE_SYM_CLASS_MEMBER_OF_UNION UINT8_C(11) +%define IMAGE_SYM_CLASS_UNION_TAG UINT8_C(12) +%define IMAGE_SYM_CLASS_TYPE_DEFINITION UINT8_C(13) +%define IMAGE_SYM_CLASS_UNDEFINED_STATIC UINT8_C(14) +%define IMAGE_SYM_CLASS_ENUM_TAG UINT8_C(15) +%define IMAGE_SYM_CLASS_MEMBER_OF_ENUM UINT8_C(16) +%define IMAGE_SYM_CLASS_REGISTER_PARAM UINT8_C(17) +%define IMAGE_SYM_CLASS_BIT_FIELD UINT8_C(18) +%define IMAGE_SYM_CLASS_FAR_EXTERNAL UINT8_C(68) +%define IMAGE_SYM_CLASS_BLOCK UINT8_C(100) +%define IMAGE_SYM_CLASS_FUNCTION UINT8_C(101) +%define IMAGE_SYM_CLASS_END_OF_STRUCT UINT8_C(102) +%define IMAGE_SYM_CLASS_FILE UINT8_C(103) +%define IMAGE_SYM_CLASS_SECTION UINT8_C(104) +%define IMAGE_SYM_CLASS_WEAK_EXTERNAL UINT8_C(105) +%define IMAGE_SYM_CLASS_CLR_TOKEN UINT8_C(107) + + +%define IMAGE_SYM_TYPE_NULL UINT16_C(0x0000) +%define IMAGE_SYM_TYPE_VOID UINT16_C(0x0001) +%define IMAGE_SYM_TYPE_CHAR UINT16_C(0x0002) +%define IMAGE_SYM_TYPE_SHORT UINT16_C(0x0003) +%define IMAGE_SYM_TYPE_INT UINT16_C(0x0004) +%define IMAGE_SYM_TYPE_LONG UINT16_C(0x0005) +%define IMAGE_SYM_TYPE_FLOAT UINT16_C(0x0006) +%define IMAGE_SYM_TYPE_DOUBLE UINT16_C(0x0007) +%define IMAGE_SYM_TYPE_STRUCT UINT16_C(0x0008) +%define IMAGE_SYM_TYPE_UNION UINT16_C(0x0009) +%define IMAGE_SYM_TYPE_ENUM UINT16_C(0x000a) +%define IMAGE_SYM_TYPE_MOE UINT16_C(0x000b) +%define IMAGE_SYM_TYPE_BYTE UINT16_C(0x000c) +%define IMAGE_SYM_TYPE_WORD UINT16_C(0x000d) +%define IMAGE_SYM_TYPE_UINT UINT16_C(0x000e) +%define IMAGE_SYM_TYPE_DWORD UINT16_C(0x000f) +%define IMAGE_SYM_TYPE_PCODE UINT16_C(0x8000) + +%define IMAGE_SYM_DTYPE_NULL UINT16_C(0x0) +%define IMAGE_SYM_DTYPE_POINTER UINT16_C(0x1) +%define IMAGE_SYM_DTYPE_FUNCTION UINT16_C(0x2) +%define IMAGE_SYM_DTYPE_ARRAY UINT16_C(0x3) + + +%define N_BTMASK UINT16_C(0x000f) +%define N_TMASK UINT16_C(0x0030) +%define N_TMASK1 UINT16_C(0x00c0) +%define N_TMASK2 UINT16_C(0x00f0) +%define N_BTSHFT 4 +%define N_TSHIFT 2 + + +;******************************************************************************* +;* Structures and Typedefs * +;******************************************************************************* + +struc IMAGE_FILE_HEADER + .Machine resw 1 ;;< 0x00 + .NumberOfSections resw 1 ;;< 0x02 + .TimeDateStamp resd 1 ;;< 0x04 + .PointerToSymbolTable resd 1 ;;< 0x08 + .NumberOfSymbols resd 1 ;;< 0x0c + .SizeOfOptionalHeader resw 1 ;;< 0x10 + .Characteristics resw 1 ;;< 0x12 +endstruc +AssertCompileSize(IMAGE_FILE_HEADER, 0x14) + +struc IMAGE_DATA_DIRECTORY + .VirtualAddress resd 1 + .Size resd 1 +endstruc + + +struc IMAGE_OPTIONAL_HEADER32 + .Magic resw 1 ;;< 0x00 + .MajorLinkerVersion resb 1 ;;< 0x02 + .MinorLinkerVersion resb 1 ;;< 0x03 + .SizeOfCode resd 1 ;;< 0x04 + .SizeOfInitializedData resd 1 ;;< 0x08 + .SizeOfUninitializedData resd 1 ;;< 0x0c + .AddressOfEntryPoint resd 1 ;;< 0x10 + .BaseOfCode resd 1 ;;< 0x14 + .BaseOfData resd 1 ;;< 0x18 + .ImageBase resd 1 ;;< 0x1c + .SectionAlignment resd 1 ;;< 0x20 + .FileAlignment resd 1 ;;< 0x24 + .MajorOperatingSystemVersion resw 1 ;;< 0x28 + .MinorOperatingSystemVersion resw 1 ;;< 0x2a + .MajorImageVersion resw 1 ;;< 0x2c + .MinorImageVersion resw 1 ;;< 0x2e + .MajorSubsystemVersion resw 1 ;;< 0x30 + .MinorSubsystemVersion resw 1 ;;< 0x32 + .Win32VersionValue resd 1 ;;< 0x34 + .SizeOfImage resd 1 ;;< 0x38 + .SizeOfHeaders resd 1 ;;< 0x3c + .CheckSum resd 1 ;;< 0x40 + .Subsystem resw 1 ;;< 0x44 + .DllCharacteristics resw 1 ;;< 0x46 + .SizeOfStackReserve resd 1 ;;< 0x48 + .SizeOfStackCommit resd 1 ;;< 0x4c + .SizeOfHeapReserve resd 1 ;;< 0x50 + .SizeOfHeapCommit resd 1 ;;< 0x54 + .LoaderFlags resd 1 ;;< 0x58 + .NumberOfRvaAndSizes resd 1 ;;< 0x5c + .DataDirectory resb IMAGE_DATA_DIRECTORY_size * IMAGE_NUMBEROF_DIRECTORY_ENTRIES ;;< 0x60; 0x10*8 = 0x80 +endstruc +AssertCompileSize(IMAGE_OPTIONAL_HEADER32, 0xe0); + +struc IMAGE_OPTIONAL_HEADER64 + .Magic resw 1 ;;< 0x00 + .MajorLinkerVersion resb 1 ;;< 0x02 + .MinorLinkerVersion resb 1 ;;< 0x03 + .SizeOfCode resd 1 ;;< 0x04 + .SizeOfInitializedData resd 1 ;;< 0x08 + .SizeOfUninitializedData resd 1 ;;< 0x0c + .AddressOfEntryPoint resd 1 ;;< 0x10 + .BaseOfCode resd 1 ;;< 0x14 + .ImageBase resq 1 ;;< 0x18 + .SectionAlignment resd 1 ;;< 0x20 + .FileAlignment resd 1 ;;< 0x24 + .MajorOperatingSystemVersion resw 1 ;;< 0x28 + .MinorOperatingSystemVersion resw 1 ;;< 0x2a + .MajorImageVersion resw 1 ;;< 0x2c + .MinorImageVersion resw 1 ;;< 0x2e + .MajorSubsystemVersion resw 1 ;;< 0x30 + .MinorSubsystemVersion resw 1 ;;< 0x32 + .Win32VersionValue resd 1 ;;< 0x34 + .SizeOfImage resd 1 ;;< 0x38 + .SizeOfHeaders resd 1 ;;< 0x3c + .CheckSum resd 1 ;;< 0x40 + .Subsystem resw 1 ;;< 0x44 + .DllCharacteristics resw 1 ;;< 0x46 + .SizeOfStackReserve resq 1 ;;< 0x48 + .SizeOfStackCommit resq 1 ;;< 0x50 + .SizeOfHeapReserve resq 1 ;;< 0x58 + .SizeOfHeapCommit resq 1 ;;< 0x60 + .LoaderFlags resd 1 ;;< 0x68 + .NumberOfRvaAndSizes resd 1 ;;< 0x6c + .DataDirectory resb IMAGE_DATA_DIRECTORY_size * IMAGE_NUMBEROF_DIRECTORY_ENTRIES ;;< 0x70; 0x10*8 = 0x80 +endstruc ; size: 0xf0 +AssertCompileSize(IMAGE_OPTIONAL_HEADER64, 0xf0); + + +struc IMAGE_NT_HEADERS32 + .Signature resd 1 ;;< 0x00 + .FileHeader resb IMAGE_FILE_HEADER_size ; ;;< 0x04 + .OptionalHeader resb IMAGE_OPTIONAL_HEADER32_size ;;< 0x18 +endstruc ; size: 0xf8 +AssertCompileSize(IMAGE_NT_HEADERS32, 0xf8); +AssertCompileMemberOffset(IMAGE_NT_HEADERS32, FileHeader, 4); +AssertCompileMemberOffset(IMAGE_NT_HEADERS32, OptionalHeader, 24); + +struc IMAGE_NT_HEADERS64 + .Signature resd 1 ;;< 0x00 + .FileHeader resb IMAGE_FILE_HEADER_size ;;< 0x04 + .OptionalHeader resb IMAGE_OPTIONAL_HEADER64_size ;;< 0x18 +endstruc ; size: 0x108 +AssertCompileSize(IMAGE_NT_HEADERS64, 0x108); +AssertCompileMemberOffset(IMAGE_NT_HEADERS64, FileHeader, 4); +AssertCompileMemberOffset(IMAGE_NT_HEADERS64, OptionalHeader, 24); + + +struc IMAGE_SECTION_HEADER + .Name resb IMAGE_SIZEOF_SHORT_NAME + .Misc.VirtualSize resd 1 + .VirtualAddress resd 1 + .SizeOfRawData resd 1 + .PointerToRawData resd 1 + .PointerToRelocations resd 1 + .PointerToLinenumbers resd 1 + .NumberOfRelocations resw 1 + .NumberOfLinenumbers resw 1 + .Characteristics resd 1 +endstruc +%define IMAGE_SECTION_HEADER.Misc.PhysicalAddress IMAGE_SECTION_HEADER.Misc.VirtualSize + + +struc IMAGE_BASE_RELOCATION + .VirtualAddress resd 1 + .SizeOfBlock resd 1 +endstruc + + +struc IMAGE_EXPORT_DIRECTORY + .Characteristics resd 1 + .TimeDateStamp resd 1 + .MajorVersion resw 1 + .MinorVersion resw 1 + .Name resd 1 + .Base resd 1 + .NumberOfFunctions resd 1 + .NumberOfNames resd 1 + .AddressOfFunctions resd 1 + .AddressOfNames resd 1 + .AddressOfNameOrdinals resd 1 +endstruc + + +struc IMAGE_IMPORT_DESCRIPTOR + .u.Characteristics resd 1 + .TimeDateStamp resd 1 + .ForwarderChain resd 1 + .Name resd 1 + .FirstThunk resd 1 +endstruc +%define IMAGE_IMPORT_DESCRIPTOR.u.OriginalFirstThunk IMAGE_IMPORT_DESCRIPTOR.u.Characteristics + +struc IMAGE_IMPORT_BY_NAME + .Hint resw 1 + .Name resb 1 +endstruc + + +struc IMAGE_THUNK_DATA64 + .u1.ForwarderString resq 1 +endstruc +%define IMAGE_THUNK_DATA64.u1.Function IMAGE_THUNK_DATA64.u1.ForwarderString +%define IMAGE_THUNK_DATA64.u1.Ordinal IMAGE_THUNK_DATA64.u1.ForwarderString +%define IMAGE_THUNK_DATA64.u1.AddressOfData IMAGE_THUNK_DATA64.u1.ForwarderString + +struc IMAGE_THUNK_DATA32 + .u1.ForwarderString resd 1 +endstruc +%define IMAGE_THUNK_DATA32.u1.Function IMAGE_THUNK_DATA32.u1.ForwarderString +%define IMAGE_THUNK_DATA32.u1.Ordinal IMAGE_THUNK_DATA32.u1.ForwarderString +%define IMAGE_THUNK_DATA32.u1.AddressOfData IMAGE_THUNK_DATA32.u1.ForwarderString + + +struc IMAGE_LOAD_CONFIG_DIRECTORY32 + .Size resd 1 + .TimeDateStamp resd 1 + .MajorVersion resw 1 + .MinorVersion resw 1 + .GlobalFlagsClear resd 1 + .GlobalFlagsSet resd 1 + .CriticalSectionDefaultTimeout resd 1 + .DeCommitFreeBlockThreshold resd 1 + .DeCommitTotalFreeThreshold resd 1 + .LockPrefixTable resd 1 + .MaximumAllocationSize resd 1 + .VirtualMemoryThreshold resd 1 + .ProcessHeapFlags resd 1 + .ProcessAffinityMask resd 1 + .CSDVersion resw 1 + .Reserved1 resw 1 + .EditList resd 1 + .SecurityCookie resd 1 + .SEHandlerTable resd 1 + .SEHandlerCount resd 1 +endstruc + +struc IMAGE_LOAD_CONFIG_DIRECTORY64 + .Size resd 1 + .TimeDateStamp resd 1 + .MajorVersion resw 1 + .MinorVersion resw 1 + .GlobalFlagsClear resd 1 + .GlobalFlagsSet resd 1 + .CriticalSectionDefaultTimeout resd 1 + .DeCommitFreeBlockThreshold resq 1 + .DeCommitTotalFreeThreshold resq 1 + .LockPrefixTable resq 1 + .MaximumAllocationSize resq 1 + .VirtualMemoryThreshold resq 1 + .ProcessAffinityMask resq 1 + .ProcessHeapFlags resd 1 + .CSDVersion resw 1 + .Reserved1 resw 1 + .EditList resq 1 + .SecurityCookie resq 1 + .SEHandlerTable resq 1 + .SEHandlerCount resq 1 +endstruc + + +struc IMAGE_DEBUG_DIRECTORY + .Characteristics resd 1 + .TimeDateStamp resd 1 + .MajorVersion resw 1 + .MinorVersion resw 1 + .Type resd 1 + .SizeOfData resd 1 + .AddressOfRawData resd 1 + .PointerToRawData resd 1 +endstruc + +struc IMAGE_DEBUG_MISC + .DataType resd 1 + .Length resd 1 + .Unicode resb 1 + .Reserved resb 3 + .Data resb 1 +endstruc + + +struc WIN_CERTIFICATE + .dwLength resd 1 + .wRevision resw 1 + .wCertificateType resw 1 + .bCertificate resb 8 +endstruc + +;; The header of a .DBG file (NT4). +struc IMAGE_SEPARATE_DEBUG_HEADER + .Signature resw 1 ;;< 0x00 + .Flags resw 1 ;;< 0x02 + .Machine resw 1 ;;< 0x04 + .Characteristics resw 1 ;;< 0x06 + .TimeDateStamp resd 1 ;;< 0x08 + .CheckSum resd 1 ;;< 0x0c + .ImageBase resd 1 ;;< 0x10 + .SizeOfImage resd 1 ;;< 0x14 + .NumberOfSections resd 1 ;;< 0x18 + .ExportedNamesSize resd 1 ;;< 0x1c + .DebugDirectorySize resd 1 ;;< 0x20 + .SectionAlignment resd 1 ;;< 0x24 + .Reserved resd 2 ;;< 0x28 +endstruc ; size: 0x30 +AssertCompileSize(IMAGE_SEPARATE_DEBUG_HEADER, 0x30); + + +struc IMAGE_COFF_SYMBOLS_HEADER + .NumberOfSymbols resd 1 + .LvaToFirstSymbol resd 1 + .NumberOfLinenumbers resd 1 + .LvaToFirstLinenumber resd 1 + .RvaToFirstByteOfCode resd 1 + .RvaToLastByteOfCode resd 1 + .RvaToFirstByteOfData resd 1 + .RvaToLastByteOfData resd 1 +endstruc +AssertCompileSize(IMAGE_COFF_SYMBOLS_HEADER, 0x20); + + +struc IMAGE_LINENUMBER + .Type.VirtualAddress resd 1 + .Linenumber resw 1 +endstruc +AssertCompileSize(IMAGE_LINENUMBER, 6); +%define IMAGE_LINENUMBER.Type.SymbolTableIndex IMAGE_LINENUMBER.Type.VirtualAddress + + +;;#pragma pack(2) +;;struc IMAGE_SYMBOL +;;{ +;; union +;; { +;; uint8_t ShortName[8]; +;; struct +;; { +;; .Short resd 1 +;; .Long resd 1 +;; } Name; +;; uint32_t LongName[2]; +;; } N; +;; +;; .Value resd 1 +;; int16_t SectionNumber; +;; .Type resw 1 +;; .StorageClass resb 1 +;; .NumberOfAuxSymbols resb 1 +;;} IMAGE_SYMBOL; +;;#pragma pack() +;;AssertCompileSize(IMAGE_SYMBOL, IMAGE_SIZE_OF_SYMBOL); +;; +;; +;;#pragma pack(2) +;;typedef struct IMAGE_AUX_SYMBOL_TOKEN_DEF +;;{ +;; .bAuxType resb 1 +;; .bReserved resb 1 +;; .SymbolTableIndex resd 1 +;; uint8_t rgbReserved[12]; +;;} IMAGE_AUX_SYMBOL_TOKEN_DEF; +;;#pragma pack() +;;AssertCompileSize(IMAGE_AUX_SYMBOL_TOKEN_DEF, IMAGE_SIZE_OF_SYMBOL); +;; +;; +;;#pragma pack(1) +;;typedef union _IMAGE_AUX_SYMBOL +;;{ +;; struct +;; { +;; .TagIndex resd 1 +;; union +;; { +;; struct +;; { +;; .Linenumber resw 1 +;; .Size resw 1 +;; } LnSz; +;; } Misc; +;; union +;; { +;; struct +;; { +;; .PointerToLinenumber resd 1 +;; .PointerToNextFunction resd 1 +;; } Function; +;; struct +;; { +;; uint16_t Dimension[4]; +;; } Array; +;; } FcnAry; +;; .TvIndex resw 1 +;; } Sym; +;; +;; struct +;; { +;; uint8_t Name[IMAGE_SIZE_OF_SYMBOL]; +;; } File; +;; +;; struct +;; { +;; .Length resd 1 +;; .NumberOfRelocations resw 1 +;; .NumberOfLinenumbers resw 1 +;; .CheckSum resd 1 +;; .Number resw 1 +;; .Selection resb 1 +;; .bReserved resb 1 +;; .HighNumber resw 1 +;; } Section; +;; +;; IMAGE_AUX_SYMBOL_TOKEN_DEF TokenDef; +;; struct +;; { +;; .crc resd 1 +;; uint8_t rgbReserved[14]; +;; } CRC; +;;} IMAGE_AUX_SYMBOL; +;;#pragma pack() +;;AssertCompileSize(IMAGE_AUX_SYMBOL, IMAGE_SIZE_OF_SYMBOL); +;; +;; +;; +;;struc IMAGE_SYMBOL_EX +;;{ +;; union +;; { +;; uint8_t ShortName[8]; +;; struct +;; { +;; .Short resd 1 +;; .Long resd 1 +;; } Name; +;; uint32_t LongName[2]; +;; } N; +;; +;; .Value resd 1 +;; int32_t SectionNumber; /* The difference from IMAGE_SYMBOL +;; .Type resw 1 +;; .StorageClass resb 1 +;; .NumberOfAuxSymbols resb 1 +;;} IMAGE_SYMBOL_EX; +;;AssertCompileSize(IMAGE_SYMBOL_EX, IMAGE_SIZE_OF_SYMBOL_EX); +;; +;; +;;typedef union _IMAGE_AUX_SYMBOL_EX +;;{ +;; struct +;; { +;; .WeakDefaultSymIndex resd 1 +;; .WeakSearchType resd 1 +;; uint8_t rgbReserved[12]; +;; } Sym; +;; +;; struct +;; { +;; uint8_t Name[IMAGE_SIZE_OF_SYMBOL_EX]; +;; } File; +;; +;; struct +;; { +;; .Length resd 1 +;; .NumberOfRelocations resw 1 +;; .NumberOfLinenumbers resw 1 +;; .CheckSum resd 1 +;; .Number resw 1 +;; .Selection resb 1 +;; .bReserved resb 1 +;; .HighNumber resw 1 +;; uint8_t rgbReserved[2]; +;; } Section; +;; +;; IMAGE_AUX_SYMBOL_TOKEN_DEF TokenDef; +;; +;; struct +;; { +;; .crc resd 1 +;; uint8_t rgbReserved[16]; +;; } CRC; +;;} IMAGE_AUX_SYMBOL_EX; +;;AssertCompileSize(IMAGE_AUX_SYMBOL_EX, IMAGE_SIZE_OF_SYMBOL_EX); + +%endif + diff --git a/include/iprt/formats/pecoff.h b/include/iprt/formats/pecoff.h new file mode 100644 index 00000000..a705d20a --- /dev/null +++ b/include/iprt/formats/pecoff.h @@ -0,0 +1,2610 @@ +/* $Id: pecoff.h $ */ +/** @file + * IPRT - Windows NT PE & COFF Structures and Constants. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_pecoff_h +#define IPRT_INCLUDED_formats_pecoff_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_rt_formats_pecoff PE & Microsoft COFF structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + + +/** + * PE & COFF file header. + * + * This starts COFF files, while in PE files it's preceeded by the PE signature + * (see IMAGE_NT_HEADERS32, IMAGE_NT_HEADERS64). + */ +typedef struct _IMAGE_FILE_HEADER +{ + uint16_t Machine; /**< 0x00 */ + uint16_t NumberOfSections; /**< 0x02 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint32_t PointerToSymbolTable; /**< 0x08 */ + uint32_t NumberOfSymbols; /**< 0x0c */ + uint16_t SizeOfOptionalHeader; /**< 0x10 */ + uint16_t Characteristics; /**< 0x12 */ +} IMAGE_FILE_HEADER; /* size: 0x14 */ +AssertCompileSize(IMAGE_FILE_HEADER, 0x14); +typedef IMAGE_FILE_HEADER *PIMAGE_FILE_HEADER; +typedef IMAGE_FILE_HEADER const *PCIMAGE_FILE_HEADER; + + +/** @name PE & COFF machine types. + * Used by IMAGE_FILE_HEADER::Machine and IMAGE_SEPARATE_DEBUG_HEADER::Machine. + * @{ */ +/** X86 compatible CPU, 32-bit instructions. */ +#define IMAGE_FILE_MACHINE_I386 UINT16_C(0x014c) +/** AMD64 compatible CPU, 64-bit instructions. */ +#define IMAGE_FILE_MACHINE_AMD64 UINT16_C(0x8664) + +/** Unknown target CPU. */ +#define IMAGE_FILE_MACHINE_UNKNOWN UINT16_C(0x0000) +/** Basic-16 (whatever that is). */ +#define IMAGE_FILE_MACHINE_BASIC_16 UINT16_C(0x0142) +/** Basic-16 (whatever that is) w/ transfer vector(s?) (TV). */ +#define IMAGE_FILE_MACHINE_BASIC_16_TV UINT16_C(0x0143) +/** Intel iAPX 16 (8086?). */ +#define IMAGE_FILE_MACHINE_IAPX16 UINT16_C(0x0144) +/** Intel iAPX 16 (8086?) w/ transfer vector(s?) (TV). */ +#define IMAGE_FILE_MACHINE_IAPX16_TV UINT16_C(0x0145) +/** Intel iAPX 20 (80286?). */ +#define IMAGE_FILE_MACHINE_IAPX20 UINT16_C(0x0144) +/** Intel iAPX 20 (80286?) w/ transfer vector(s?) (TV). */ +#define IMAGE_FILE_MACHINE_IAPX20_TV UINT16_C(0x0145) +/** X86 compatible CPU, 8086. */ +#define IMAGE_FILE_MACHINE_I8086 UINT16_C(0x0148) +/** X86 compatible CPU, 8086 w/ transfer vector(s?) (TV). */ +#define IMAGE_FILE_MACHINE_I8086_TV UINT16_C(0x0149) +/** X86 compatible CPU, 80286 small model program. */ +#define IMAGE_FILE_MACHINE_I286_SMALL UINT16_C(0x014a) +/** Motorola 68000. */ +#define IMAGE_FILE_MACHINE_MC68 UINT16_C(0x0150) +/** Motorola 68000 w/ writable text sections. */ +#define IMAGE_FILE_MACHINE_MC68_WR UINT16_C(0x0150) +/** Motorola 68000 w/ transfer vector(s?). */ +#define IMAGE_FILE_MACHINE_MC68_TV UINT16_C(0x0151) +/** Motorola 68000 w/ demand paged text. + * @note shared with 80286 large model program. */ +#define IMAGE_FILE_MACHINE_MC68_PG UINT16_C(0x0152) +/** X86 compatible CPU, 80286 large model program. + * @note shared with MC68000 w/ demand paged text */ +#define IMAGE_FILE_MACHINE_I286_LARGE UINT16_C(0x0152) +/** IBM 370 (writable text). */ +#define IMAGE_FILE_MACHINE_U370_WR UINT16_C(0x0158) +/** Amdahl 470/580 (writable text). */ +#define IMAGE_FILE_MACHINE_AMDAHL_470_WR UINT16_C(0x0159) +/** Amdahl 470/580 (read only text). */ +#define IMAGE_FILE_MACHINE_AMDAHL_470_RO UINT16_C(0x015c) +/** IBM 370 (read only text). */ +#define IMAGE_FILE_MACHINE_U370_RO UINT16_C(0x015d) +/** MIPS R4000 CPU, little endian. */ +#define IMAGE_FILE_MACHINE_R4000 UINT16_C(0x0166) +/** MIPS CPU, little endian, Windows CE (?) v2 designation. */ +#define IMAGE_FILE_MACHINE_WCEMIPSV2 UINT16_C(0x0169) +/** VAX-11/750 and VAX-11/780 (writable text). */ +#define IMAGE_FILE_MACHINE_VAX_WR UINT16_C(0x0178) +/** VAX-11/750 and VAX-11/780 (read-only text). */ +#define IMAGE_FILE_MACHINE_VAX_RO UINT16_C(0x017d) +/** Hitachi SH3 CPU. */ +#define IMAGE_FILE_MACHINE_SH3 UINT16_C(0x01a2) +/** Hitachi SH3 DSP. */ +#define IMAGE_FILE_MACHINE_SH3DSP UINT16_C(0x01a3) +/** Hitachi SH4 CPU. */ +#define IMAGE_FILE_MACHINE_SH4 UINT16_C(0x01a6) +/** Hitachi SH5 CPU. */ +#define IMAGE_FILE_MACHINE_SH5 UINT16_C(0x01a8) +/** Little endian ARM CPU. */ +#define IMAGE_FILE_MACHINE_ARM UINT16_C(0x01c0) +/** ARM or Thumb stuff. */ +#define IMAGE_FILE_MACHINE_THUMB UINT16_C(0x01c2) +/** ARMv7 or higher CPU, Thumb mode. */ +#define IMAGE_FILE_MACHINE_ARMNT UINT16_C(0x01c4) +/** Matshushita AM33 CPU. */ +#define IMAGE_FILE_MACHINE_AM33 UINT16_C(0x01d3) +/** Power PC CPU, little endian. */ +#define IMAGE_FILE_MACHINE_POWERPC UINT16_C(0x01f0) +/** Power PC CPU with FPU, also little endian? */ +#define IMAGE_FILE_MACHINE_POWERPCFP UINT16_C(0x01f1) +/** "Itanic" CPU. */ +#define IMAGE_FILE_MACHINE_IA64 UINT16_C(0x0200) +/** MIPS CPU, compact 16-bit instructions only? */ +#define IMAGE_FILE_MACHINE_MIPS16 UINT16_C(0x0266) +/** MIPS CPU with FPU, full 32-bit instructions only? */ +#define IMAGE_FILE_MACHINE_MIPSFPU UINT16_C(0x0366) +/** MIPS CPU with FPU, compact 16-bit instructions? */ +#define IMAGE_FILE_MACHINE_MIPSFPU16 UINT16_C(0x0466) +/** EFI byte code. */ +#define IMAGE_FILE_MACHINE_EBC UINT16_C(0x0ebc) +/** Mitsubishi M32R CPU, little endian. */ +#define IMAGE_FILE_MACHINE_M32R UINT16_C(0x9041) +/** ARMv8 CPU, 64-bit mode. */ +#define IMAGE_FILE_MACHINE_ARM64 UINT16_C(0xaa64) +/** @} */ + +/** @name File header characteristics (IMAGE_FILE_HEADER::Characteristics) + * @{ */ +#define IMAGE_FILE_RELOCS_STRIPPED UINT16_C(0x0001) +#define IMAGE_FILE_EXECUTABLE_IMAGE UINT16_C(0x0002) +#define IMAGE_FILE_LINE_NUMS_STRIPPED UINT16_C(0x0004) +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED UINT16_C(0x0008) +#define IMAGE_FILE_AGGRESIVE_WS_TRIM UINT16_C(0x0010) +#define IMAGE_FILE_LARGE_ADDRESS_AWARE UINT16_C(0x0020) +#define IMAGE_FILE_16BIT_MACHINE UINT16_C(0x0040) +#define IMAGE_FILE_BYTES_REVERSED_LO UINT16_C(0x0080) +#define IMAGE_FILE_32BIT_MACHINE UINT16_C(0x0100) +#define IMAGE_FILE_DEBUG_STRIPPED UINT16_C(0x0200) +#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP UINT16_C(0x0400) +#define IMAGE_FILE_NET_RUN_FROM_SWAP UINT16_C(0x0800) +#define IMAGE_FILE_SYSTEM UINT16_C(0x1000) /**< (COFF/IAPX*: Used to indicate 80186 instructions) */ +#define IMAGE_FILE_DLL UINT16_C(0x2000) /**< (COFF/IAPX*: Used to indicate 80286 instructions) */ +#define IMAGE_FILE_UP_SYSTEM_ONLY UINT16_C(0x4000) +#define IMAGE_FILE_BYTES_REVERSED_HI UINT16_C(0x8000) +/** @} */ + + +/** + * PE data directory. + * + * This is used to locate data in the loaded image so the dynamic linker or + * others can make use of it. However, in the case of + * IMAGE_DIRECTORY_ENTRY_SECURITY it is referring to raw file offsets. + */ +typedef struct _IMAGE_DATA_DIRECTORY +{ + uint32_t VirtualAddress; + uint32_t Size; +} IMAGE_DATA_DIRECTORY; +AssertCompileSize(IMAGE_DATA_DIRECTORY, 0x8); +typedef IMAGE_DATA_DIRECTORY *PIMAGE_DATA_DIRECTORY; +typedef IMAGE_DATA_DIRECTORY const *PCIMAGE_DATA_DIRECTORY; + +/** The standard number of data directories in the optional header. + * I.e. the dimensions of IMAGE_OPTIONAL_HEADER32::DataDirectory and + * IMAGE_OPTIONAL_HEADER64::DataDirectory. + */ +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 0x10 + + +/** + * PE optional header, 32-bit version. + */ +typedef struct _IMAGE_OPTIONAL_HEADER32 +{ + uint16_t Magic; /**< 0x00 */ + uint8_t MajorLinkerVersion; /**< 0x02 */ + uint8_t MinorLinkerVersion; /**< 0x03 */ + uint32_t SizeOfCode; /**< 0x04 */ + uint32_t SizeOfInitializedData; /**< 0x08 */ + uint32_t SizeOfUninitializedData; /**< 0x0c */ + uint32_t AddressOfEntryPoint; /**< 0x10 */ + uint32_t BaseOfCode; /**< 0x14 */ + uint32_t BaseOfData; /**< 0x18 */ + uint32_t ImageBase; /**< 0x1c */ + uint32_t SectionAlignment; /**< 0x20 */ + uint32_t FileAlignment; /**< 0x24 */ + uint16_t MajorOperatingSystemVersion; /**< 0x28 */ + uint16_t MinorOperatingSystemVersion; /**< 0x2a */ + uint16_t MajorImageVersion; /**< 0x2c */ + uint16_t MinorImageVersion; /**< 0x2e */ + uint16_t MajorSubsystemVersion; /**< 0x30 */ + uint16_t MinorSubsystemVersion; /**< 0x32 */ + uint32_t Win32VersionValue; /**< 0x34 */ + uint32_t SizeOfImage; /**< 0x38 */ + uint32_t SizeOfHeaders; /**< 0x3c */ + uint32_t CheckSum; /**< 0x40 */ + uint16_t Subsystem; /**< 0x44 */ + uint16_t DllCharacteristics; /**< 0x46 */ + uint32_t SizeOfStackReserve; /**< 0x48 */ + uint32_t SizeOfStackCommit; /**< 0x4c */ + uint32_t SizeOfHeapReserve; /**< 0x50 */ + uint32_t SizeOfHeapCommit; /**< 0x54 */ + uint32_t LoaderFlags; /**< 0x58 */ + uint32_t NumberOfRvaAndSizes; /**< 0x5c */ + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; /**< 0x60; 0x10*8 = 0x80 */ +} IMAGE_OPTIONAL_HEADER32; /* size: 0xe0 */ +AssertCompileSize(IMAGE_OPTIONAL_HEADER32, 0xe0); +typedef IMAGE_OPTIONAL_HEADER32 *PIMAGE_OPTIONAL_HEADER32; +typedef IMAGE_OPTIONAL_HEADER32 const *PCIMAGE_OPTIONAL_HEADER32; + +/** + * PE optional header, 64-bit version. + */ +typedef struct _IMAGE_OPTIONAL_HEADER64 +{ + uint16_t Magic; /**< 0x00 */ + uint8_t MajorLinkerVersion; /**< 0x02 */ + uint8_t MinorLinkerVersion; /**< 0x03 */ + uint32_t SizeOfCode; /**< 0x04 */ + uint32_t SizeOfInitializedData; /**< 0x08 */ + uint32_t SizeOfUninitializedData; /**< 0x0c */ + uint32_t AddressOfEntryPoint; /**< 0x10 */ + uint32_t BaseOfCode; /**< 0x14 */ + uint64_t ImageBase; /**< 0x18 */ + uint32_t SectionAlignment; /**< 0x20 */ + uint32_t FileAlignment; /**< 0x24 */ + uint16_t MajorOperatingSystemVersion; /**< 0x28 */ + uint16_t MinorOperatingSystemVersion; /**< 0x2a */ + uint16_t MajorImageVersion; /**< 0x2c */ + uint16_t MinorImageVersion; /**< 0x2e */ + uint16_t MajorSubsystemVersion; /**< 0x30 */ + uint16_t MinorSubsystemVersion; /**< 0x32 */ + uint32_t Win32VersionValue; /**< 0x34 */ + uint32_t SizeOfImage; /**< 0x38 */ + uint32_t SizeOfHeaders; /**< 0x3c */ + uint32_t CheckSum; /**< 0x40 */ + uint16_t Subsystem; /**< 0x44 */ + uint16_t DllCharacteristics; /**< 0x46 */ + uint64_t SizeOfStackReserve; /**< 0x48 */ + uint64_t SizeOfStackCommit; /**< 0x50 */ + uint64_t SizeOfHeapReserve; /**< 0x58 */ + uint64_t SizeOfHeapCommit; /**< 0x60 */ + uint32_t LoaderFlags; /**< 0x68 */ + uint32_t NumberOfRvaAndSizes; /**< 0x6c */ + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; /**< 0x70; 0x10*8 = 0x80 */ +} IMAGE_OPTIONAL_HEADER64; /* size: 0xf0 */ +AssertCompileSize(IMAGE_OPTIONAL_HEADER64, 0xf0); +typedef IMAGE_OPTIONAL_HEADER64 *PIMAGE_OPTIONAL_HEADER64; +typedef IMAGE_OPTIONAL_HEADER64 const *PCIMAGE_OPTIONAL_HEADER64; + +/** @name Optional header magic values. + * @{ */ +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC UINT16_C(0x010b) +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC UINT16_C(0x020b) +/** @} */ + +/** @name IMAGE_SUBSYSTEM_XXX - Optional header subsystems. + * IMAGE_OPTIONAL_HEADER32::Subsystem, IMAGE_OPTIONAL_HEADER64::Subsystem + * @{ */ +#define IMAGE_SUBSYSTEM_UNKNOWN UINT16_C(0x0000) +#define IMAGE_SUBSYSTEM_NATIVE UINT16_C(0x0001) +#define IMAGE_SUBSYSTEM_WINDOWS_GUI UINT16_C(0x0002) +#define IMAGE_SUBSYSTEM_WINDOWS_CUI UINT16_C(0x0003) +#define IMAGE_SUBSYSTEM_OS2_GUI UINT16_C(0x0004) +#define IMAGE_SUBSYSTEM_OS2_CUI UINT16_C(0x0005) +#define IMAGE_SUBSYSTEM_POSIX_CUI UINT16_C(0x0007) +/** @} */ + +/** @name Optional header characteristics. + * @{ */ +#define IMAGE_LIBRARY_PROCESS_INIT UINT16_C(0x0001) +#define IMAGE_LIBRARY_PROCESS_TERM UINT16_C(0x0002) +#define IMAGE_LIBRARY_THREAD_INIT UINT16_C(0x0004) +#define IMAGE_LIBRARY_THREAD_TERM UINT16_C(0x0008) +#define IMAGE_DLLCHARACTERISTICS_RESERVED UINT16_C(0x0010) +#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA UINT16_C(0x0020) +#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE UINT16_C(0x0040) +#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY UINT16_C(0x0080) +#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT UINT16_C(0x0100) +#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION UINT16_C(0x0200) +#define IMAGE_DLLCHARACTERISTICS_NO_SEH UINT16_C(0x0400) +#define IMAGE_DLLCHARACTERISTICS_NO_BIND UINT16_C(0x0800) +#define IMAGE_DLLCHARACTERISTICS_APPCONTAINER UINT16_C(0x1000) +#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER UINT16_C(0x2000) +#define IMAGE_DLLCHARACTERISTICS_GUARD_CF UINT16_C(0x4000) +#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE UINT16_C(0x8000) +/** @} */ + + +/** @name IMAGE_DIRECTORY_ENTRY_XXX - Data directory indexes. + * Used to index IMAGE_OPTIONAL_HEADER32::DataDirectory and + * IMAGE_OPTIONAL_HEADER64::DataDirectory + * @{ */ +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0x0 +#define IMAGE_DIRECTORY_ENTRY_IMPORT 0x1 +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 0x2 +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 0x3 +#define IMAGE_DIRECTORY_ENTRY_SECURITY 0x4 +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 0x5 +#define IMAGE_DIRECTORY_ENTRY_DEBUG 0x6 +#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 0x7 +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT IMAGE_DIRECTORY_ENTRY_ARCHITECTURE +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 0x8 +#define IMAGE_DIRECTORY_ENTRY_TLS 0x9 +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 0xa +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 0xb +#define IMAGE_DIRECTORY_ENTRY_IAT 0xc +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 0xd +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 0xe +/** @} */ + + +/** + * PE (NT) headers, 32-bit version. + */ +typedef struct _IMAGE_NT_HEADERS32 +{ + uint32_t Signature; /**< 0x00 */ + IMAGE_FILE_HEADER FileHeader; /**< 0x04 */ + IMAGE_OPTIONAL_HEADER32 OptionalHeader; /**< 0x18 */ +} IMAGE_NT_HEADERS32; /* size: 0xf8 */ +AssertCompileSize(IMAGE_NT_HEADERS32, 0xf8); +AssertCompileMemberOffset(IMAGE_NT_HEADERS32, FileHeader, 4); +AssertCompileMemberOffset(IMAGE_NT_HEADERS32, OptionalHeader, 24); +typedef IMAGE_NT_HEADERS32 *PIMAGE_NT_HEADERS32; +typedef IMAGE_NT_HEADERS32 const *PCIMAGE_NT_HEADERS32; + +/** + * PE (NT) headers, 64-bit version. + */ +typedef struct _IMAGE_NT_HEADERS64 +{ + uint32_t Signature; /**< 0x00 */ + IMAGE_FILE_HEADER FileHeader; /**< 0x04 */ + IMAGE_OPTIONAL_HEADER64 OptionalHeader; /**< 0x18 */ +} IMAGE_NT_HEADERS64; /**< 0x108 */ +AssertCompileSize(IMAGE_NT_HEADERS64, 0x108); +AssertCompileMemberOffset(IMAGE_NT_HEADERS64, FileHeader, 4); +AssertCompileMemberOffset(IMAGE_NT_HEADERS64, OptionalHeader, 24); +typedef IMAGE_NT_HEADERS64 *PIMAGE_NT_HEADERS64; +typedef IMAGE_NT_HEADERS64 const *PCIMAGE_NT_HEADERS64; + +/** The PE signature. + * Used by IMAGE_NT_HEADERS32::Signature, IMAGE_NT_HEADERS64::Signature. */ +#define IMAGE_NT_SIGNATURE UINT32_C(0x00004550) + + +/** Section header short name length (IMAGE_SECTION_HEADER::Name). */ +#define IMAGE_SIZEOF_SHORT_NAME 0x8 + +/** + * PE & COFF section header. + */ +typedef struct _IMAGE_SECTION_HEADER +{ + uint8_t Name[IMAGE_SIZEOF_SHORT_NAME]; + union + { + uint32_t PhysicalAddress; + uint32_t VirtualSize; + } Misc; + uint32_t VirtualAddress; + uint32_t SizeOfRawData; + uint32_t PointerToRawData; + uint32_t PointerToRelocations; + uint32_t PointerToLinenumbers; + uint16_t NumberOfRelocations; + uint16_t NumberOfLinenumbers; + uint32_t Characteristics; +} IMAGE_SECTION_HEADER; +AssertCompileSize(IMAGE_SECTION_HEADER, 40); +typedef IMAGE_SECTION_HEADER *PIMAGE_SECTION_HEADER; +typedef IMAGE_SECTION_HEADER const *PCIMAGE_SECTION_HEADER; + +/** @name IMAGE_SCN_XXX - Section header characteristics. + * Used by IMAGE_SECTION_HEADER::Characteristics. + * @{ */ +#define IMAGE_SCN_TYPE_REG UINT32_C(0x00000000) +#define IMAGE_SCN_TYPE_DSECT UINT32_C(0x00000001) +#define IMAGE_SCN_TYPE_NOLOAD UINT32_C(0x00000002) +#define IMAGE_SCN_TYPE_GROUP UINT32_C(0x00000004) +#define IMAGE_SCN_TYPE_NO_PAD UINT32_C(0x00000008) +#define IMAGE_SCN_TYPE_COPY UINT32_C(0x00000010) + +#define IMAGE_SCN_CNT_CODE UINT32_C(0x00000020) +#define IMAGE_SCN_CNT_INITIALIZED_DATA UINT32_C(0x00000040) +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA UINT32_C(0x00000080) + +#define IMAGE_SCN_LNK_OTHER UINT32_C(0x00000100) +#define IMAGE_SCN_LNK_INFO UINT32_C(0x00000200) +#define IMAGE_SCN_TYPE_OVER UINT32_C(0x00000400) +#define IMAGE_SCN_LNK_REMOVE UINT32_C(0x00000800) +#define IMAGE_SCN_LNK_COMDAT UINT32_C(0x00001000) +#define IMAGE_SCN_MEM_PROTECTED UINT32_C(0x00004000) +#define IMAGE_SCN_NO_DEFER_SPEC_EXC UINT32_C(0x00004000) +#define IMAGE_SCN_GPREL UINT32_C(0x00008000) +#define IMAGE_SCN_MEM_FARDATA UINT32_C(0x00008000) +#define IMAGE_SCN_MEM_SYSHEAP UINT32_C(0x00010000) +#define IMAGE_SCN_MEM_PURGEABLE UINT32_C(0x00020000) +#define IMAGE_SCN_MEM_16BIT UINT32_C(0x00020000) +#define IMAGE_SCN_MEM_LOCKED UINT32_C(0x00040000) +#define IMAGE_SCN_MEM_PRELOAD UINT32_C(0x00080000) + +#define IMAGE_SCN_ALIGN_1BYTES UINT32_C(0x00100000) +#define IMAGE_SCN_ALIGN_2BYTES UINT32_C(0x00200000) +#define IMAGE_SCN_ALIGN_4BYTES UINT32_C(0x00300000) +#define IMAGE_SCN_ALIGN_8BYTES UINT32_C(0x00400000) +#define IMAGE_SCN_ALIGN_16BYTES UINT32_C(0x00500000) +#define IMAGE_SCN_ALIGN_32BYTES UINT32_C(0x00600000) +#define IMAGE_SCN_ALIGN_64BYTES UINT32_C(0x00700000) +#define IMAGE_SCN_ALIGN_128BYTES UINT32_C(0x00800000) +#define IMAGE_SCN_ALIGN_256BYTES UINT32_C(0x00900000) +#define IMAGE_SCN_ALIGN_512BYTES UINT32_C(0x00A00000) +#define IMAGE_SCN_ALIGN_1024BYTES UINT32_C(0x00B00000) +#define IMAGE_SCN_ALIGN_2048BYTES UINT32_C(0x00C00000) +#define IMAGE_SCN_ALIGN_4096BYTES UINT32_C(0x00D00000) +#define IMAGE_SCN_ALIGN_8192BYTES UINT32_C(0x00E00000) +#define IMAGE_SCN_ALIGN_MASK UINT32_C(0x00F00000) +#define IMAGE_SCN_ALIGN_SHIFT 20 + +#define IMAGE_SCN_LNK_NRELOC_OVFL UINT32_C(0x01000000) +#define IMAGE_SCN_MEM_DISCARDABLE UINT32_C(0x02000000) +#define IMAGE_SCN_MEM_NOT_CACHED UINT32_C(0x04000000) +#define IMAGE_SCN_MEM_NOT_PAGED UINT32_C(0x08000000) +#define IMAGE_SCN_MEM_SHARED UINT32_C(0x10000000) +#define IMAGE_SCN_MEM_EXECUTE UINT32_C(0x20000000) +#define IMAGE_SCN_MEM_READ UINT32_C(0x40000000) +#define IMAGE_SCN_MEM_WRITE UINT32_C(0x80000000) +/** @} */ + + +/** + * PE image base relocations block header. + * + * This found in IMAGE_DIRECTORY_ENTRY_BASERELOC. Each entry is follow + * immediately by an array of 16-bit words, where the lower 12-bits are used + * for the page offset and the upper 4-bits for the base relocation type + * (IMAGE_REL_BASE_XXX). The block should be padded with + * IMAGE_REL_BASED_ABSOLUTE entries to ensure 32-bit alignment of this header. + */ +typedef struct _IMAGE_BASE_RELOCATION +{ + /** The RVA of the page/block the following ase relocations applies to. */ + uint32_t VirtualAddress; + /** The size of this relocation block, including this header. */ + uint32_t SizeOfBlock; +} IMAGE_BASE_RELOCATION; +AssertCompileSize(IMAGE_BASE_RELOCATION, 8); +typedef IMAGE_BASE_RELOCATION *PIMAGE_BASE_RELOCATION; +typedef IMAGE_BASE_RELOCATION const *PCIMAGE_BASE_RELOCATION; + +/** @name IMAGE_REL_BASED_XXX - PE base relocations. + * Found in the IMAGE_DIRECTORY_ENTRY_BASERELOC data directory. + * @{ */ +#define IMAGE_REL_BASED_ABSOLUTE UINT16_C(0x0) +#define IMAGE_REL_BASED_HIGH UINT16_C(0x1) +#define IMAGE_REL_BASED_LOW UINT16_C(0x2) +#define IMAGE_REL_BASED_HIGHLOW UINT16_C(0x3) +#define IMAGE_REL_BASED_HIGHADJ UINT16_C(0x4) +#define IMAGE_REL_BASED_MIPS_JMPADDR UINT16_C(0x5) +#define IMAGE_REL_BASED_MIPS_JMPADDR16 UINT16_C(0x9) +#define IMAGE_REL_BASED_IA64_IMM64 UINT16_C(0x9) +#define IMAGE_REL_BASED_DIR64 UINT16_C(0xa) +#define IMAGE_REL_BASED_HIGH3ADJ UINT16_C(0xb) +/** @} */ + +/** + * PE export directory entry. + */ +typedef struct _IMAGE_EXPORT_DIRECTORY +{ + uint32_t Characteristics; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t Name; + uint32_t Base; + uint32_t NumberOfFunctions; + uint32_t NumberOfNames; + uint32_t AddressOfFunctions; + uint32_t AddressOfNames; + uint32_t AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY; +AssertCompileSize(IMAGE_EXPORT_DIRECTORY, 40); +typedef IMAGE_EXPORT_DIRECTORY *PIMAGE_EXPORT_DIRECTORY; +typedef IMAGE_EXPORT_DIRECTORY const *PCIMAGE_EXPORT_DIRECTORY; + + +/** + * PE import directory entry. + */ +typedef struct _IMAGE_IMPORT_DESCRIPTOR +{ + union + { + uint32_t Characteristics; + uint32_t OriginalFirstThunk; + } u; + uint32_t TimeDateStamp; + uint32_t ForwarderChain; + uint32_t Name; + uint32_t FirstThunk; +} IMAGE_IMPORT_DESCRIPTOR; +AssertCompileSize(IMAGE_IMPORT_DESCRIPTOR, 20); +typedef IMAGE_IMPORT_DESCRIPTOR *PIMAGE_IMPORT_DESCRIPTOR; +typedef IMAGE_IMPORT_DESCRIPTOR const *PCIMAGE_IMPORT_DESCRIPTOR; + +/** + * Something we currently don't make use of... + */ +typedef struct _IMAGE_IMPORT_BY_NAME +{ + uint16_t Hint; + uint8_t Name[1]; +} IMAGE_IMPORT_BY_NAME; +AssertCompileSize(IMAGE_IMPORT_BY_NAME, 4); +typedef IMAGE_IMPORT_BY_NAME *PIMAGE_IMPORT_BY_NAME; +typedef IMAGE_IMPORT_BY_NAME const *PCIMAGE_IMPORT_BY_NAME; + + +#if 0 +/* The image_thunk_data32/64 structures are not very helpful except for getting RSI. + keep them around till all the code has been converted. */ +typedef struct _IMAGE_THUNK_DATA64 +{ + union + { + uint64_t ForwarderString; + uint64_t Function; + uint64_t Ordinal; + uint64_t AddressOfData; + } u1; +} IMAGE_THUNK_DATA64; +typedef IMAGE_THUNK_DATA64 *PIMAGE_THUNK_DATA64; +typedef IMAGE_THUNK_DATA64 const *PCIMAGE_THUNK_DATA64; + +typedef struct _IMAGE_THUNK_DATA32 +{ + union + { + uint32_t ForwarderString; + uint32_t Function; + uint32_t Ordinal; + uint32_t AddressOfData; + } u1; +} IMAGE_THUNK_DATA32; +typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32; +typedef IMAGE_THUNK_DATA32 const *PCIMAGE_THUNK_DATA32; +#endif + +/** @name PE import directory macros. + * @{ */ +#define IMAGE_ORDINAL_FLAG32 UINT32_C(0x80000000) +#define IMAGE_ORDINAL32(ord) ((ord) & UINT32_C(0xffff)) +#define IMAGE_SNAP_BY_ORDINAL32(ord) (!!((ord) & IMAGE_ORDINAL_FLAG32)) + +#define IMAGE_ORDINAL_FLAG64 UINT64_C(0x8000000000000000) +#define IMAGE_ORDINAL64(ord) ((ord) & UINT32_C(0xffff)) +#define IMAGE_SNAP_BY_ORDINAL64(ord) (!!((ord) & IMAGE_ORDINAL_FLAG64)) +/** @} */ + +/** @name PE Resource directory + * @{ */ +typedef struct _IMAGE_RESOURCE_DIRECTORY +{ + uint32_t Characteristics; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint16_t NumberOfNamedEntries; + uint16_t NumberOfIdEntries; +} IMAGE_RESOURCE_DIRECTORY; +typedef IMAGE_RESOURCE_DIRECTORY *PIMAGE_RESOURCE_DIRECTORY; +typedef IMAGE_RESOURCE_DIRECTORY const *PCIMAGE_RESOURCE_DIRECTORY; + +typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY +{ + union + { + struct + { + uint32_t NameOffset : 31; + uint32_t NameIsString : 1; /**< IMAGE_RESOURCE_NAME_IS_STRING */ + } s; + uint32_t Name; + uint16_t Id; + } u; + union + { + struct + { + uint32_t OffsetToDirectory : 31; + uint32_t DataIsDirectory : 1; /**< IMAGE_RESOURCE_DATA_IS_DIRECTORY*/ + } s2; + uint32_t OffsetToData; + } u2; +} IMAGE_RESOURCE_DIRECTORY_ENTRY; +typedef IMAGE_RESOURCE_DIRECTORY_ENTRY *PIMAGE_RESOURCE_DIRECTORY_ENTRY; +typedef IMAGE_RESOURCE_DIRECTORY_ENTRY const *PCIMAGE_RESOURCE_DIRECTORY_ENTRY; + +#define IMAGE_RESOURCE_NAME_IS_STRING UINT32_C(0x80000000) +#define IMAGE_RESOURCE_DATA_IS_DIRECTORY UINT32_C(0x80000000) + +typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING +{ + uint16_t Length; + char NameString[1]; +} IMAGE_RESOURCE_DIRECTORY_STRING; +typedef IMAGE_RESOURCE_DIRECTORY_STRING *PIMAGE_RESOURCE_DIRECTORY_STRING; +typedef IMAGE_RESOURCE_DIRECTORY_STRING const *PCIMAGE_RESOURCE_DIRECTORY_STRING; + + +typedef struct _IMAGE_RESOURCE_DIR_STRING_U +{ + uint16_t Length; + RTUTF16 NameString[1]; +} IMAGE_RESOURCE_DIR_STRING_U; +typedef IMAGE_RESOURCE_DIR_STRING_U *PIMAGE_RESOURCE_DIR_STRING_U; +typedef IMAGE_RESOURCE_DIR_STRING_U const *PCIMAGE_RESOURCE_DIR_STRING_U; + + +typedef struct _IMAGE_RESOURCE_DATA_ENTRY +{ + uint32_t OffsetToData; + uint32_t Size; + uint32_t CodePage; + uint32_t Reserved; +} IMAGE_RESOURCE_DATA_ENTRY; +typedef IMAGE_RESOURCE_DATA_ENTRY *PIMAGE_RESOURCE_DATA_ENTRY; +typedef IMAGE_RESOURCE_DATA_ENTRY const *PCIMAGE_RESOURCE_DATA_ENTRY; + +/** @} */ + +/** @name Image exception information + * @{ */ + +/** This structure is used by AMD64 and "Itanic". + * MIPS uses a different one. ARM, SH3, SH4 and PPC on WinCE also uses a different one. */ +typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY +{ + uint32_t BeginAddress; + uint32_t EndAddress; + uint32_t UnwindInfoAddress; +} IMAGE_RUNTIME_FUNCTION_ENTRY; +AssertCompileSize(IMAGE_RUNTIME_FUNCTION_ENTRY, 12); +typedef IMAGE_RUNTIME_FUNCTION_ENTRY *PIMAGE_RUNTIME_FUNCTION_ENTRY; +typedef IMAGE_RUNTIME_FUNCTION_ENTRY const *PCIMAGE_RUNTIME_FUNCTION_ENTRY; + +/** + * An unwind code for AMD64 and ARM64. + * + * @note Also known as UNWIND_CODE or _UNWIND_CODE. + */ +typedef union IMAGE_UNWIND_CODE +{ + struct + { + /** The prolog offset where the change takes effect. + * This means the instruction following the one being described. */ + uint8_t CodeOffset; + /** Unwind opcode. + * For AMD64 see IMAGE_AMD64_UNWIND_OP_CODES. */ + RT_GCC_EXTENSION uint8_t UnwindOp : 4; + /** Opcode specific. */ + RT_GCC_EXTENSION uint8_t OpInfo : 4; + } u; + uint16_t FrameOffset; +} IMAGE_UNWIND_CODE; +AssertCompileSize(IMAGE_UNWIND_CODE, 2); + +/** + * Unwind information for AMD64 and ARM64. + * + * Pointed to by IMAGE_RUNTIME_FUNCTION_ENTRY::UnwindInfoAddress, + * + * @note Also known as UNWIND_INFO or _UNWIND_INFO. + */ +typedef struct IMAGE_UNWIND_INFO +{ + /** Version, currently 1 or 2. The latter if IMAGE_AMD64_UWOP_EPILOG is used. */ + RT_GCC_EXTENSION uint8_t Version : 3; + /** IMAGE_UNW_FLAG_XXX */ + RT_GCC_EXTENSION uint8_t Flags : 5; + /** Size of function prolog. */ + uint8_t SizeOfProlog; + /** Number of opcodes in aOpcodes. */ + uint8_t CountOfCodes; + /** Initial frame register. */ + RT_GCC_EXTENSION uint8_t FrameRegister : 4; + /** Scaled frame register offset. */ + RT_GCC_EXTENSION uint8_t FrameOffset : 4; + /** Unwind opcodes. */ + RT_FLEXIBLE_ARRAY_EXTENSION + IMAGE_UNWIND_CODE aOpcodes[RT_FLEXIBLE_ARRAY]; +} IMAGE_UNWIND_INFO; +AssertCompileMemberOffset(IMAGE_UNWIND_INFO, aOpcodes, 4); +typedef IMAGE_UNWIND_INFO *PIMAGE_UNWIND_INFO; +typedef IMAGE_UNWIND_INFO const *PCIMAGE_UNWIND_INFO; + +/** IMAGE_UNW_FLAGS_XXX - IMAGE_UNWIND_INFO::Flags. + * @{ */ +/** No handler. + * @note Also know as UNW_FLAG_NHANDLER. */ +#define IMAGE_UNW_FLAGS_NHANDLER 0 +/** Have exception handler (RVA after codes, dword aligned.) + * @note Also know as UNW_FLAG_NHANDLER. */ +#define IMAGE_UNW_FLAGS_EHANDLER 1 +/** Have unwind handler (RVA after codes, dword aligned.) + * @note Also know as UNW_FLAG_NHANDLER. */ +#define IMAGE_UNW_FLAGS_UHANDLER 2 +/** Set if not primary unwind info for a function. An + * IMAGE_RUNTIME_FUNCTION_ENTRY giving the chained unwind info follows the + * aOpcodes array at a dword aligned offset. */ +#define IMAGE_UNW_FLAGS_CHAININFO 4 +/** @} */ + +/** + * AMD64 unwind opcodes. + */ +typedef enum IMAGE_AMD64_UNWIND_OP_CODES +{ + /** Push non-volatile register (OpInfo). + * YASM: [pushreg reg] + * MASM: .PUSHREG reg */ + IMAGE_AMD64_UWOP_PUSH_NONVOL = 0, + /** Stack allocation: Size stored in scaled in the next slot if OpInfo == 0, + * otherwise stored unscaled in the next two slots. + * YASM: [allocstack size] + * MASM: .ALLOCSTACK size */ + IMAGE_AMD64_UWOP_ALLOC_LARGE, + /** Stack allocation: OpInfo = size / 8 - 1. + * YASM: [allocstack size] + * MASM: .ALLOCSTACK size */ + IMAGE_AMD64_UWOP_ALLOC_SMALL, + /** Set frame pointer register: RSP + FrameOffset * 16. + * YASM: [setframe reg, offset] + * MASM: .SETFRAME reg, offset + * @code + * LEA RBP, [RSP + 20h] + * [setframe RBP, 20h] + * @endcode */ + IMAGE_AMD64_UWOP_SET_FPREG, + /** Save non-volatile register (OpInfo) on stack (RSP/FP + next slot). + * YASM: [savereg reg, offset] + * MASM: .SAVEREG reg, offset */ + IMAGE_AMD64_UWOP_SAVE_NONVOL, + /** Save non-volatile register (OpInfo) on stack (RSP/FP + next two slots). + * YASM: [savereg reg, offset] + * MASM: .SAVEREG reg, offset */ + IMAGE_AMD64_UWOP_SAVE_NONVOL_FAR, + /** Epilog info, version 2+. + * + * The first time this opcode is used, the CodeOffset gives the size of the + * epilog and bit 0 of the OpInfo field indicates that there is only one + * epilog at the very end of the function. + * + * Subsequent uses of this opcode specifies epilog start offsets relative to + * the end of the function, using CodeOffset for the 8 lower bits and OpInfo + * for bits 8 thru 11. + * + * The compiler seems to stack allocations and register saving opcodes and + * indicates the location mirroring the first IMAGE_AMD64_UWOP_PUSH_NONVOL. */ + IMAGE_AMD64_UWOP_EPILOG, + /** Undefined. */ + IMAGE_AMD64_UWOP_RESERVED_7, + /** Save 128-bit XMM register (OpInfo) on stack (RSP/FP + next slot). + * YASM: [savexmm128 reg, offset] + * MASM: .SAVEXMM128 reg, offset */ + IMAGE_AMD64_UWOP_SAVE_XMM128, + /** Save 128-bit XMM register (OpInfo) on stack (RSP/FP + next two slots). + * YASM: [savexmm128 reg, offset] + * MASM: .SAVEXMM128 reg, offset */ + IMAGE_AMD64_UWOP_SAVE_XMM128_FAR, + /** IRET frame, OpInfo serves as error code indicator. + * YASM: [pushframe with-code] + * MASM: .pushframe with-code */ + IMAGE_AMD64_UWOP_PUSH_MACHFRAME +} IMAGE_AMD64_UNWIND_OP_CODES; +/** @} */ + + + +/** @name Image load config directories + * @{ */ + +/** @since Windows 10 (preview 9879) */ +typedef struct _IMAGE_LOAD_CONFIG_CODE_INTEGRITY +{ + uint16_t Flags; + uint16_t Catalog; + uint32_t CatalogOffset; + uint32_t Reserved; +} IMAGE_LOAD_CONFIG_CODE_INTEGRITY; +AssertCompileSize(IMAGE_LOAD_CONFIG_CODE_INTEGRITY, 12); +typedef IMAGE_LOAD_CONFIG_CODE_INTEGRITY *PIMAGE_LOAD_CONFIG_CODE_INTEGRITY; +typedef IMAGE_LOAD_CONFIG_CODE_INTEGRITY const *PCIMAGE_LOAD_CONFIG_CODE_INTEGRITY; + +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V1 +{ + uint32_t Size; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t GlobalFlagsClear; + uint32_t GlobalFlagsSet; + uint32_t CriticalSectionDefaultTimeout; + uint32_t DeCommitFreeBlockThreshold; + uint32_t DeCommitTotalFreeThreshold; + uint32_t LockPrefixTable; + uint32_t MaximumAllocationSize; + uint32_t VirtualMemoryThreshold; + uint32_t ProcessHeapFlags; + uint32_t ProcessAffinityMask; + uint16_t CSDVersion; + uint16_t DependentLoadFlags; + uint32_t EditList; + uint32_t SecurityCookie; +} IMAGE_LOAD_CONFIG_DIRECTORY32_V1; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V1, 0x40); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V1 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V1; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V1 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V1; + +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V2 +{ + uint32_t Size; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t GlobalFlagsClear; + uint32_t GlobalFlagsSet; + uint32_t CriticalSectionDefaultTimeout; + uint32_t DeCommitFreeBlockThreshold; + uint32_t DeCommitTotalFreeThreshold; + uint32_t LockPrefixTable; + uint32_t MaximumAllocationSize; + uint32_t VirtualMemoryThreshold; + uint32_t ProcessHeapFlags; + uint32_t ProcessAffinityMask; + uint16_t CSDVersion; + uint16_t DependentLoadFlags; + uint32_t EditList; + uint32_t SecurityCookie; + uint32_t SEHandlerTable; + uint32_t SEHandlerCount; +} IMAGE_LOAD_CONFIG_DIRECTORY32_V2; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V2, 0x48); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V2 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V2; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V2 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V2; + +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V3 +{ + uint32_t Size; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t GlobalFlagsClear; + uint32_t GlobalFlagsSet; + uint32_t CriticalSectionDefaultTimeout; + uint32_t DeCommitFreeBlockThreshold; + uint32_t DeCommitTotalFreeThreshold; + uint32_t LockPrefixTable; + uint32_t MaximumAllocationSize; + uint32_t VirtualMemoryThreshold; + uint32_t ProcessHeapFlags; + uint32_t ProcessAffinityMask; + uint16_t CSDVersion; + uint16_t DependentLoadFlags; + uint32_t EditList; + uint32_t SecurityCookie; + uint32_t SEHandlerTable; + uint32_t SEHandlerCount; + uint32_t GuardCFCCheckFunctionPointer; + uint32_t GuardCFDispatchFunctionPointer; + uint32_t GuardCFFunctionTable; + uint32_t GuardCFFunctionCount; + uint32_t GuardFlags; +} IMAGE_LOAD_CONFIG_DIRECTORY32_V3; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V3, 0x5c); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V3 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V3; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V3 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V3; + +/** @since Windows 10 (preview 9879) */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V4 +{ + uint32_t Size; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t GlobalFlagsClear; + uint32_t GlobalFlagsSet; + uint32_t CriticalSectionDefaultTimeout; + uint32_t DeCommitFreeBlockThreshold; + uint32_t DeCommitTotalFreeThreshold; + uint32_t LockPrefixTable; + uint32_t MaximumAllocationSize; + uint32_t VirtualMemoryThreshold; + uint32_t ProcessHeapFlags; + uint32_t ProcessAffinityMask; + uint16_t CSDVersion; + uint16_t DependentLoadFlags; + uint32_t EditList; + uint32_t SecurityCookie; + uint32_t SEHandlerTable; + uint32_t SEHandlerCount; + uint32_t GuardCFCCheckFunctionPointer; + uint32_t GuardCFDispatchFunctionPointer; + uint32_t GuardCFFunctionTable; + uint32_t GuardCFFunctionCount; + uint32_t GuardFlags; + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; +} IMAGE_LOAD_CONFIG_DIRECTORY32_V4; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V4, 0x68); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V4 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V4; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V4 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V4; + +/** @since Windows 10 build 14286 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V5 +{ + uint32_t Size; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t GlobalFlagsClear; + uint32_t GlobalFlagsSet; + uint32_t CriticalSectionDefaultTimeout; + uint32_t DeCommitFreeBlockThreshold; + uint32_t DeCommitTotalFreeThreshold; + uint32_t LockPrefixTable; + uint32_t MaximumAllocationSize; + uint32_t VirtualMemoryThreshold; + uint32_t ProcessHeapFlags; + uint32_t ProcessAffinityMask; + uint16_t CSDVersion; + uint16_t DependentLoadFlags; + uint32_t EditList; + uint32_t SecurityCookie; + uint32_t SEHandlerTable; + uint32_t SEHandlerCount; + uint32_t GuardCFCCheckFunctionPointer; + uint32_t GuardCFDispatchFunctionPointer; + uint32_t GuardCFFunctionTable; + uint32_t GuardCFFunctionCount; + uint32_t GuardFlags; + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; + uint32_t GuardAddressTakenIatEntryTable; + uint32_t GuardAddressTakenIatEntryCount; + uint32_t GuardLongJumpTargetTable; + uint32_t GuardLongJumpTargetCount; +} IMAGE_LOAD_CONFIG_DIRECTORY32_V5; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V5, 0x78); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V5 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V5; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V5 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V5; + +/** @since Windows 10 build 14383 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V6 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint32_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint32_t DeCommitTotalFreeThreshold; /**< 0x1c */ + uint32_t LockPrefixTable; /**< 0x20 */ + uint32_t MaximumAllocationSize; /**< 0x24 */ + uint32_t VirtualMemoryThreshold; /**< 0x28 */ + uint32_t ProcessHeapFlags; /**< 0x2c */ + uint32_t ProcessAffinityMask; /**< 0x30 */ + uint16_t CSDVersion; /**< 0x34 */ + uint16_t DependentLoadFlags; /**< 0x36 */ + uint32_t EditList; /**< 0x38 */ + uint32_t SecurityCookie; /**< 0x3c */ + uint32_t SEHandlerTable; /**< 0x40 */ + uint32_t SEHandlerCount; /**< 0x44 */ + uint32_t GuardCFCCheckFunctionPointer; /**< 0x48 */ + uint32_t GuardCFDispatchFunctionPointer; /**< 0x4c */ + uint32_t GuardCFFunctionTable; /**< 0x50 */ + uint32_t GuardCFFunctionCount; /**< 0x54 */ + uint32_t GuardFlags; /**< 0x58 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x5c */ + uint32_t GuardAddressTakenIatEntryTable; /**< 0x68 */ + uint32_t GuardAddressTakenIatEntryCount; /**< 0x6c */ + uint32_t GuardLongJumpTargetTable; /**< 0x70 */ + uint32_t GuardLongJumpTargetCount; /**< 0x74 */ + uint32_t DynamicValueRelocTable; /**< 0x78 */ + uint32_t HybridMetadataPointer; /**< 0x7c */ +} IMAGE_LOAD_CONFIG_DIRECTORY32_V6; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V6, 0x80); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V6 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V6; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V6 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V6; + +/** @since Windows 10 build 14901 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V7 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint32_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint32_t DeCommitTotalFreeThreshold; /**< 0x1c */ + uint32_t LockPrefixTable; /**< 0x20 */ + uint32_t MaximumAllocationSize; /**< 0x24 */ + uint32_t VirtualMemoryThreshold; /**< 0x28 */ + uint32_t ProcessHeapFlags; /**< 0x2c */ + uint32_t ProcessAffinityMask; /**< 0x30 */ + uint16_t CSDVersion; /**< 0x34 */ + uint16_t DependentLoadFlags; /**< 0x36 */ + uint32_t EditList; /**< 0x38 */ + uint32_t SecurityCookie; /**< 0x3c */ + uint32_t SEHandlerTable; /**< 0x40 */ + uint32_t SEHandlerCount; /**< 0x44 */ + uint32_t GuardCFCCheckFunctionPointer; /**< 0x48 */ + uint32_t GuardCFDispatchFunctionPointer; /**< 0x4c */ + uint32_t GuardCFFunctionTable; /**< 0x50 */ + uint32_t GuardCFFunctionCount; /**< 0x54 */ + uint32_t GuardFlags; /**< 0x58 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x5c */ + uint32_t GuardAddressTakenIatEntryTable; /**< 0x68 */ + uint32_t GuardAddressTakenIatEntryCount; /**< 0x6c */ + uint32_t GuardLongJumpTargetTable; /**< 0x70 */ + uint32_t GuardLongJumpTargetCount; /**< 0x74 */ + uint32_t DynamicValueRelocTable; /**< 0x78 */ + uint32_t CHPEMetadataPointer; /**< 0x7c Not sure when this was renamed from HybridMetadataPointer. */ + uint32_t GuardRFFailureRoutine; /**< 0x80 */ + uint32_t GuardRFFailureRoutineFunctionPointer; /**< 0x84 */ + uint32_t DynamicValueRelocTableOffset; /**< 0x88 */ + uint16_t DynamicValueRelocTableSection; /**< 0x8c */ + uint16_t Reserved2; /**< 0x8e */ +} IMAGE_LOAD_CONFIG_DIRECTORY32_V7; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V7, 0x90); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V7 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V7; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V7 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V7; + +/** @since Windows 10 build 15002 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V8 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint32_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint32_t DeCommitTotalFreeThreshold; /**< 0x1c */ + uint32_t LockPrefixTable; /**< 0x20 */ + uint32_t MaximumAllocationSize; /**< 0x24 */ + uint32_t VirtualMemoryThreshold; /**< 0x28 */ + uint32_t ProcessHeapFlags; /**< 0x2c */ + uint32_t ProcessAffinityMask; /**< 0x30 */ + uint16_t CSDVersion; /**< 0x34 */ + uint16_t DependentLoadFlags; /**< 0x36 */ + uint32_t EditList; /**< 0x38 */ + uint32_t SecurityCookie; /**< 0x3c */ + uint32_t SEHandlerTable; /**< 0x40 */ + uint32_t SEHandlerCount; /**< 0x44 */ + uint32_t GuardCFCCheckFunctionPointer; /**< 0x48 */ + uint32_t GuardCFDispatchFunctionPointer; /**< 0x4c */ + uint32_t GuardCFFunctionTable; /**< 0x50 */ + uint32_t GuardCFFunctionCount; /**< 0x54 */ + uint32_t GuardFlags; /**< 0x58 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x5c */ + uint32_t GuardAddressTakenIatEntryTable; /**< 0x68 */ + uint32_t GuardAddressTakenIatEntryCount; /**< 0x6c */ + uint32_t GuardLongJumpTargetTable; /**< 0x70 */ + uint32_t GuardLongJumpTargetCount; /**< 0x74 */ + uint32_t DynamicValueRelocTable; /**< 0x78 */ + uint32_t CHPEMetadataPointer; /**< 0x7c Not sure when this was renamed from HybridMetadataPointer. */ + uint32_t GuardRFFailureRoutine; /**< 0x80 */ + uint32_t GuardRFFailureRoutineFunctionPointer; /**< 0x84 */ + uint32_t DynamicValueRelocTableOffset; /**< 0x88 */ + uint16_t DynamicValueRelocTableSection; /**< 0x8c */ + uint16_t Reserved2; /**< 0x8e */ + uint32_t GuardRFVerifyStackPointerFunctionPointer; /**< 0x90 */ + uint32_t HotPatchTableOffset; /**< 0x94 */ +} IMAGE_LOAD_CONFIG_DIRECTORY32_V8; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V8, 0x98); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V8 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V8; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V8 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V8; + +/** @since Windows 10 build 16237 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V9 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint32_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint32_t DeCommitTotalFreeThreshold; /**< 0x1c */ + uint32_t LockPrefixTable; /**< 0x20 */ + uint32_t MaximumAllocationSize; /**< 0x24 */ + uint32_t VirtualMemoryThreshold; /**< 0x28 */ + uint32_t ProcessHeapFlags; /**< 0x2c */ + uint32_t ProcessAffinityMask; /**< 0x30 */ + uint16_t CSDVersion; /**< 0x34 */ + uint16_t DependentLoadFlags; /**< 0x36 */ + uint32_t EditList; /**< 0x38 */ + uint32_t SecurityCookie; /**< 0x3c */ + uint32_t SEHandlerTable; /**< 0x40 */ + uint32_t SEHandlerCount; /**< 0x44 */ + uint32_t GuardCFCCheckFunctionPointer; /**< 0x48 */ + uint32_t GuardCFDispatchFunctionPointer; /**< 0x4c */ + uint32_t GuardCFFunctionTable; /**< 0x50 */ + uint32_t GuardCFFunctionCount; /**< 0x54 */ + uint32_t GuardFlags; /**< 0x58 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x5c */ + uint32_t GuardAddressTakenIatEntryTable; /**< 0x68 */ + uint32_t GuardAddressTakenIatEntryCount; /**< 0x6c */ + uint32_t GuardLongJumpTargetTable; /**< 0x70 */ + uint32_t GuardLongJumpTargetCount; /**< 0x74 */ + uint32_t DynamicValueRelocTable; /**< 0x78 */ + uint32_t CHPEMetadataPointer; /**< 0x7c Not sure when this was renamed from HybridMetadataPointer. */ + uint32_t GuardRFFailureRoutine; /**< 0x80 */ + uint32_t GuardRFFailureRoutineFunctionPointer; /**< 0x84 */ + uint32_t DynamicValueRelocTableOffset; /**< 0x88 */ + uint16_t DynamicValueRelocTableSection; /**< 0x8c */ + uint16_t Reserved2; /**< 0x8e */ + uint32_t GuardRFVerifyStackPointerFunctionPointer; /**< 0x90 */ + uint32_t HotPatchTableOffset; /**< 0x94 */ + uint32_t Reserved3; /**< 0x98 */ + uint32_t EnclaveConfigurationPointer; /**< 0x9c */ +} IMAGE_LOAD_CONFIG_DIRECTORY32_V9; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V9, 0xa0); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V9 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V9; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V9 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V9; + +/** @since Windows 10 build 18362 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V10 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint32_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint32_t DeCommitTotalFreeThreshold; /**< 0x1c */ + uint32_t LockPrefixTable; /**< 0x20 */ + uint32_t MaximumAllocationSize; /**< 0x24 */ + uint32_t VirtualMemoryThreshold; /**< 0x28 */ + uint32_t ProcessHeapFlags; /**< 0x2c */ + uint32_t ProcessAffinityMask; /**< 0x30 */ + uint16_t CSDVersion; /**< 0x34 */ + uint16_t DependentLoadFlags; /**< 0x36 */ + uint32_t EditList; /**< 0x38 */ + uint32_t SecurityCookie; /**< 0x3c */ + uint32_t SEHandlerTable; /**< 0x40 */ + uint32_t SEHandlerCount; /**< 0x44 */ + uint32_t GuardCFCCheckFunctionPointer; /**< 0x48 */ + uint32_t GuardCFDispatchFunctionPointer; /**< 0x4c */ + uint32_t GuardCFFunctionTable; /**< 0x50 */ + uint32_t GuardCFFunctionCount; /**< 0x54 */ + uint32_t GuardFlags; /**< 0x58 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x5c */ + uint32_t GuardAddressTakenIatEntryTable; /**< 0x68 */ + uint32_t GuardAddressTakenIatEntryCount; /**< 0x6c */ + uint32_t GuardLongJumpTargetTable; /**< 0x70 */ + uint32_t GuardLongJumpTargetCount; /**< 0x74 */ + uint32_t DynamicValueRelocTable; /**< 0x78 */ + uint32_t CHPEMetadataPointer; /**< 0x7c Not sure when this was renamed from HybridMetadataPointer. */ + uint32_t GuardRFFailureRoutine; /**< 0x80 */ + uint32_t GuardRFFailureRoutineFunctionPointer; /**< 0x84 */ + uint32_t DynamicValueRelocTableOffset; /**< 0x88 */ + uint16_t DynamicValueRelocTableSection; /**< 0x8c */ + uint16_t Reserved2; /**< 0x8e */ + uint32_t GuardRFVerifyStackPointerFunctionPointer; /**< 0x90 */ + uint32_t HotPatchTableOffset; /**< 0x94 */ + uint32_t Reserved3; /**< 0x98 */ + uint32_t EnclaveConfigurationPointer; /**< 0x9c */ + uint32_t VolatileMetadataPointer; /**< 0xa0 */ +} IMAGE_LOAD_CONFIG_DIRECTORY32_V10; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V10, 0xa4); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V10 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V10; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V10 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V10; + +/** @since Windows 10 build 19564 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V11 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint32_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint32_t DeCommitTotalFreeThreshold; /**< 0x1c */ + uint32_t LockPrefixTable; /**< 0x20 */ + uint32_t MaximumAllocationSize; /**< 0x24 */ + uint32_t VirtualMemoryThreshold; /**< 0x28 */ + uint32_t ProcessHeapFlags; /**< 0x2c */ + uint32_t ProcessAffinityMask; /**< 0x30 */ + uint16_t CSDVersion; /**< 0x34 */ + uint16_t DependentLoadFlags; /**< 0x36 */ + uint32_t EditList; /**< 0x38 */ + uint32_t SecurityCookie; /**< 0x3c */ + uint32_t SEHandlerTable; /**< 0x40 */ + uint32_t SEHandlerCount; /**< 0x44 */ + uint32_t GuardCFCCheckFunctionPointer; /**< 0x48 */ + uint32_t GuardCFDispatchFunctionPointer; /**< 0x4c */ + uint32_t GuardCFFunctionTable; /**< 0x50 */ + uint32_t GuardCFFunctionCount; /**< 0x54 */ + uint32_t GuardFlags; /**< 0x58 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x5c */ + uint32_t GuardAddressTakenIatEntryTable; /**< 0x68 */ + uint32_t GuardAddressTakenIatEntryCount; /**< 0x6c */ + uint32_t GuardLongJumpTargetTable; /**< 0x70 */ + uint32_t GuardLongJumpTargetCount; /**< 0x74 */ + uint32_t DynamicValueRelocTable; /**< 0x78 */ + uint32_t CHPEMetadataPointer; /**< 0x7c Not sure when this was renamed from HybridMetadataPointer. */ + uint32_t GuardRFFailureRoutine; /**< 0x80 */ + uint32_t GuardRFFailureRoutineFunctionPointer; /**< 0x84 */ + uint32_t DynamicValueRelocTableOffset; /**< 0x88 */ + uint16_t DynamicValueRelocTableSection; /**< 0x8c */ + uint16_t Reserved2; /**< 0x8e */ + uint32_t GuardRFVerifyStackPointerFunctionPointer; /**< 0x90 */ + uint32_t HotPatchTableOffset; /**< 0x94 */ + uint32_t Reserved3; /**< 0x98 */ + uint32_t EnclaveConfigurationPointer; /**< 0x9c - virtual address */ + uint32_t VolatileMetadataPointer; /**< 0xa0 */ + uint32_t GuardEHContinuationTable; /**< 0xa4 - virtual address */ + uint32_t GuardEHContinuationCount; /**< 0xa8 */ +} IMAGE_LOAD_CONFIG_DIRECTORY32_V11; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V11, 0xac); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V11 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V11; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V11 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V11; + +/** @since Visual C++ 2019 / RS5_IMAGE_LOAD_CONFIG_DIRECTORY32. */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V12 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint32_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint32_t DeCommitTotalFreeThreshold; /**< 0x1c */ + uint32_t LockPrefixTable; /**< 0x20 */ + uint32_t MaximumAllocationSize; /**< 0x24 */ + uint32_t VirtualMemoryThreshold; /**< 0x28 */ + uint32_t ProcessHeapFlags; /**< 0x2c */ + uint32_t ProcessAffinityMask; /**< 0x30 */ + uint16_t CSDVersion; /**< 0x34 */ + uint16_t DependentLoadFlags; /**< 0x36 */ + uint32_t EditList; /**< 0x38 */ + uint32_t SecurityCookie; /**< 0x3c */ + uint32_t SEHandlerTable; /**< 0x40 */ + uint32_t SEHandlerCount; /**< 0x44 */ + uint32_t GuardCFCCheckFunctionPointer; /**< 0x48 */ + uint32_t GuardCFDispatchFunctionPointer; /**< 0x4c */ + uint32_t GuardCFFunctionTable; /**< 0x50 */ + uint32_t GuardCFFunctionCount; /**< 0x54 */ + uint32_t GuardFlags; /**< 0x58 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x5c */ + uint32_t GuardAddressTakenIatEntryTable; /**< 0x68 */ + uint32_t GuardAddressTakenIatEntryCount; /**< 0x6c */ + uint32_t GuardLongJumpTargetTable; /**< 0x70 */ + uint32_t GuardLongJumpTargetCount; /**< 0x74 */ + uint32_t DynamicValueRelocTable; /**< 0x78 */ + uint32_t CHPEMetadataPointer; /**< 0x7c Not sure when this was renamed from HybridMetadataPointer. */ + uint32_t GuardRFFailureRoutine; /**< 0x80 */ + uint32_t GuardRFFailureRoutineFunctionPointer; /**< 0x84 */ + uint32_t DynamicValueRelocTableOffset; /**< 0x88 */ + uint16_t DynamicValueRelocTableSection; /**< 0x8c */ + uint16_t Reserved2; /**< 0x8e */ + uint32_t GuardRFVerifyStackPointerFunctionPointer; /**< 0x90 */ + uint32_t HotPatchTableOffset; /**< 0x94 */ + uint32_t Reserved3; /**< 0x98 */ + uint32_t EnclaveConfigurationPointer; /**< 0x9c - virtual address */ + uint32_t VolatileMetadataPointer; /**< 0xa0 */ + uint32_t GuardEHContinuationTable; /**< 0xa4 - virtual address */ + uint32_t GuardEHContinuationCount; /**< 0xa8 */ + uint32_t GuardXFGCheckFunctionPointer; /**< 0xac */ + uint32_t GuardXFGDispatchFunctionPointer; /**< 0xb0 */ + uint32_t GuardXFGTableDispatchFunctionPointer; /**< 0xb4 */ +} IMAGE_LOAD_CONFIG_DIRECTORY32_V12; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V12, 0xb8); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V12 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V12; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V12 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V12; + +/** @since Visual C++ 2019 16.x (found in 16.11.9) / RS5_IMAGE_LOAD_CONFIG_DIRECTORY32. */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32_V13 +{ + uint32_t Size; /**< 0x00 - virtual address */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint32_t DeCommitFreeBlockThreshold; /**< 0x18 - virtual address */ + uint32_t DeCommitTotalFreeThreshold; /**< 0x1c - virtual address */ + uint32_t LockPrefixTable; /**< 0x20 */ + uint32_t MaximumAllocationSize; /**< 0x24 */ + uint32_t VirtualMemoryThreshold; /**< 0x28 - virtual address of pointer variable */ + uint32_t ProcessHeapFlags; /**< 0x2c - virtual address of pointer variable */ + uint32_t ProcessAffinityMask; /**< 0x30 - virtual address */ + uint16_t CSDVersion; /**< 0x34 */ + uint16_t DependentLoadFlags; /**< 0x36 */ + uint32_t EditList; /**< 0x38 */ + uint32_t SecurityCookie; /**< 0x3c - virtual address */ + uint32_t SEHandlerTable; /**< 0x40 */ + uint32_t SEHandlerCount; /**< 0x44 - virtual address */ + uint32_t GuardCFCCheckFunctionPointer; /**< 0x48 */ + uint32_t GuardCFDispatchFunctionPointer; /**< 0x4c - virtual address */ + uint32_t GuardCFFunctionTable; /**< 0x50 */ + uint32_t GuardCFFunctionCount; /**< 0x54 - virtual address */ + uint32_t GuardFlags; /**< 0x58 - virtual address of pointer variable */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x5c */ + uint32_t GuardAddressTakenIatEntryTable; /**< 0x68 - virtual address */ + uint32_t GuardAddressTakenIatEntryCount; /**< 0x6c */ + uint32_t GuardLongJumpTargetTable; /**< 0x70 - virtual address */ + uint32_t GuardLongJumpTargetCount; /**< 0x74 */ + uint32_t DynamicValueRelocTable; /**< 0x78 - virtual address */ + uint32_t CHPEMetadataPointer; /**< 0x7c Not sure when this was renamed from HybridMetadataPointer. */ + uint32_t GuardRFFailureRoutine; /**< 0x80 - virtual address */ + uint32_t GuardRFFailureRoutineFunctionPointer; /**< 0x84 - virtual address of pointer variable */ + uint32_t DynamicValueRelocTableOffset; /**< 0x88 */ + uint16_t DynamicValueRelocTableSection; /**< 0x8c */ + uint16_t Reserved2; /**< 0x8e */ + uint32_t GuardRFVerifyStackPointerFunctionPointer; /**< 0x90 - virtual address of pointer variable */ + uint32_t HotPatchTableOffset; /**< 0x94 */ + uint32_t Reserved3; /**< 0x98 */ + uint32_t EnclaveConfigurationPointer; /**< 0x9c - virtual address of pointer variable */ + uint32_t VolatileMetadataPointer; /**< 0xa0 - virtual address of pointer variable */ + uint32_t GuardEHContinuationTable; /**< 0xa4 - virtual address */ + uint32_t GuardEHContinuationCount; /**< 0xa8 */ + uint32_t GuardXFGCheckFunctionPointer; /**< 0xac - virtual address of pointer variable */ + uint32_t GuardXFGDispatchFunctionPointer; /**< 0xb0 - virtual address of pointer variable */ + uint32_t GuardXFGTableDispatchFunctionPointer; /**< 0xb4 - virtual address of pointer variable */ + uint32_t CastGuardOsDeterminedFailureMode; /**< 0xb8 - virtual address */ +} IMAGE_LOAD_CONFIG_DIRECTORY32_V13; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY32_V13, 0xbc); +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V13 *PIMAGE_LOAD_CONFIG_DIRECTORY32_V13; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V13 const *PCIMAGE_LOAD_CONFIG_DIRECTORY32_V13; + +typedef IMAGE_LOAD_CONFIG_DIRECTORY32_V13 IMAGE_LOAD_CONFIG_DIRECTORY32; +typedef PIMAGE_LOAD_CONFIG_DIRECTORY32_V13 PIMAGE_LOAD_CONFIG_DIRECTORY32; +typedef PCIMAGE_LOAD_CONFIG_DIRECTORY32_V13 PCIMAGE_LOAD_CONFIG_DIRECTORY32; + + +/* No _IMAGE_LOAD_CONFIG_DIRECTORY64_V1 exists. */ + +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V2 +{ + uint32_t Size; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t GlobalFlagsClear; + uint32_t GlobalFlagsSet; + uint32_t CriticalSectionDefaultTimeout; + uint64_t DeCommitFreeBlockThreshold; + uint64_t DeCommitTotalFreeThreshold; + uint64_t LockPrefixTable; + uint64_t MaximumAllocationSize; + uint64_t VirtualMemoryThreshold; + uint64_t ProcessAffinityMask; + uint32_t ProcessHeapFlags; + uint16_t CSDVersion; + uint16_t DependentLoadFlags; + uint64_t EditList; + uint64_t SecurityCookie; + uint64_t SEHandlerTable; + uint64_t SEHandlerCount; +} IMAGE_LOAD_CONFIG_DIRECTORY64_V2; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V2, 0x70); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V2 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V2; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V2 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V2; + +#pragma pack(4) /* Why not 8 byte alignment, baka microsofties?!? */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V3 +{ + uint32_t Size; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t GlobalFlagsClear; + uint32_t GlobalFlagsSet; + uint32_t CriticalSectionDefaultTimeout; + uint64_t DeCommitFreeBlockThreshold; + uint64_t DeCommitTotalFreeThreshold; + uint64_t LockPrefixTable; + uint64_t MaximumAllocationSize; + uint64_t VirtualMemoryThreshold; + uint64_t ProcessAffinityMask; + uint32_t ProcessHeapFlags; + uint16_t CSDVersion; + uint16_t DependentLoadFlags; + uint64_t EditList; + uint64_t SecurityCookie; + uint64_t SEHandlerTable; + uint64_t SEHandlerCount; + uint64_t GuardCFCCheckFunctionPointer; + uint64_t GuardCFDispatchFunctionPointer; + uint64_t GuardCFFunctionTable; + uint64_t GuardCFFunctionCount; + uint32_t GuardFlags; +} IMAGE_LOAD_CONFIG_DIRECTORY64_V3; +#pragma pack() +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V3, 0x94); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V3 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V3; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V3 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V3; + +/** @since Windows 10 (Preview (9879). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V4 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V4; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V4, 0xa0); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V4 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V4; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V4 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V4; + +/** @since Windows 10 build 14286 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V5 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V5; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V5, 0xc0); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V5 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V5; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V5 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V5; + +/** @since Windows 10 build 14393 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V6 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ + uint64_t DynamicValueRelocTable; /**< 0xc0 */ + uint64_t HybridMetadataPointer; /**< 0xc8 */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V6; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V6, 0xd0); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V6 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V6; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V6 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V6; + +/** @since Windows 10 build 14901 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V7 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ + uint64_t DynamicValueRelocTable; /**< 0xc0 */ + uint64_t CHPEMetadataPointer; /**< 0xc8 Not sure when this was renamed from HybridMetadataPointer. */ + uint64_t GuardRFFailureRoutine; /**< 0xd0 */ + uint64_t GuardRFFailureRoutineFunctionPointer; /**< 0xd8 */ + uint32_t DynamicValueRelocTableOffset; /**< 0xe0 */ + uint16_t DynamicValueRelocTableSection; /**< 0xe4 */ + uint16_t Reserved2; /**< 0xe6 */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V7; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V7, 0xe8); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V7 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V7; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V7 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V7; + +/** @since Windows 10 build 15002 (or maybe earlier). */ +#pragma pack(4) /* Stupid, stupid microsofties! */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V8 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ + uint64_t DynamicValueRelocTable; /**< 0xc0 */ + uint64_t CHPEMetadataPointer; /**< 0xc8 */ + uint64_t GuardRFFailureRoutine; /**< 0xd0 */ + uint64_t GuardRFFailureRoutineFunctionPointer; /**< 0xd8 */ + uint32_t DynamicValueRelocTableOffset; /**< 0xe0 */ + uint16_t DynamicValueRelocTableSection; /**< 0xe4 */ + uint16_t Reserved2; /**< 0xe6 */ + uint64_t GuardRFVerifyStackPointerFunctionPointer; /**< 0xe8 */ + uint32_t HotPatchTableOffset; /**< 0xf0 */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V8; +#pragma pack() +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V8, 0xf4); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V8 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V8; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V8 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V8; + +/** @since Windows 10 build 15002 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V9 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ + uint64_t DynamicValueRelocTable; /**< 0xc0 */ + uint64_t CHPEMetadataPointer; /**< 0xc8 */ + uint64_t GuardRFFailureRoutine; /**< 0xd0 */ + uint64_t GuardRFFailureRoutineFunctionPointer; /**< 0xd8 */ + uint32_t DynamicValueRelocTableOffset; /**< 0xe0 */ + uint16_t DynamicValueRelocTableSection; /**< 0xe4 */ + uint16_t Reserved2; /**< 0xe6 */ + uint64_t GuardRFVerifyStackPointerFunctionPointer; /**< 0xe8 */ + uint32_t HotPatchTableOffset; /**< 0xf0 */ + uint32_t Reserved3; /**< 0xf4 */ + uint64_t EnclaveConfigurationPointer; /**< 0xf8 - seen in bcrypt and bcryptprimitives pointing to the string "L". */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V9; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V9, 0x100); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V9 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V9; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V9 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V9; + +/** @since Windows 10 build 18362 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V10 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ + uint64_t DynamicValueRelocTable; /**< 0xc0 */ + uint64_t CHPEMetadataPointer; /**< 0xc8 */ + uint64_t GuardRFFailureRoutine; /**< 0xd0 */ + uint64_t GuardRFFailureRoutineFunctionPointer; /**< 0xd8 */ + uint32_t DynamicValueRelocTableOffset; /**< 0xe0 */ + uint16_t DynamicValueRelocTableSection; /**< 0xe4 */ + uint16_t Reserved2; /**< 0xe6 */ + uint64_t GuardRFVerifyStackPointerFunctionPointer; /**< 0xe8 */ + uint32_t HotPatchTableOffset; /**< 0xf0 */ + uint32_t Reserved3; /**< 0xf4 */ + uint64_t EnclaveConfigurationPointer; /**< 0xf8 - seen in bcrypt and bcryptprimitives pointing to the string "L". */ + uint64_t VolatileMetadataPointer; /**< 0x100 */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V10; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V10, 0x108); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V10 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V10; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V10 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V10; + +/** @since Windows 10 build 19534 (or maybe earlier). */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V11 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ + uint64_t DynamicValueRelocTable; /**< 0xc0 */ + uint64_t CHPEMetadataPointer; /**< 0xc8 */ + uint64_t GuardRFFailureRoutine; /**< 0xd0 */ + uint64_t GuardRFFailureRoutineFunctionPointer; /**< 0xd8 */ + uint32_t DynamicValueRelocTableOffset; /**< 0xe0 */ + uint16_t DynamicValueRelocTableSection; /**< 0xe4 */ + uint16_t Reserved2; /**< 0xe6 */ + uint64_t GuardRFVerifyStackPointerFunctionPointer; /**< 0xe8 */ + uint32_t HotPatchTableOffset; /**< 0xf0 */ + uint32_t Reserved3; /**< 0xf4 */ + uint64_t EnclaveConfigurationPointer; /**< 0xf8 - seen in bcrypt and bcryptprimitives pointing to the string "L". */ + uint64_t VolatileMetadataPointer; /**< 0x100 */ + uint64_t GuardEHContinuationTable; /**< 0x108 - virtual address */ + uint64_t GuardEHContinuationCount; /**< 0x110 */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V11; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V11, 0x118); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V11 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V11; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V11 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V11; + +/** @since Visual C++ 2019 / RS5_IMAGE_LOAD_CONFIG_DIRECTORY64. */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V12 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 */ + uint64_t SecurityCookie; /**< 0x58 */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 */ + uint64_t GuardCFFunctionTable; /**< 0x80 */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ + uint64_t DynamicValueRelocTable; /**< 0xc0 */ + uint64_t CHPEMetadataPointer; /**< 0xc8 */ + uint64_t GuardRFFailureRoutine; /**< 0xd0 */ + uint64_t GuardRFFailureRoutineFunctionPointer; /**< 0xd8 */ + uint32_t DynamicValueRelocTableOffset; /**< 0xe0 */ + uint16_t DynamicValueRelocTableSection; /**< 0xe4 */ + uint16_t Reserved2; /**< 0xe6 */ + uint64_t GuardRFVerifyStackPointerFunctionPointer; /**< 0xe8 */ + uint32_t HotPatchTableOffset; /**< 0xf0 */ + uint32_t Reserved3; /**< 0xf4 */ + uint64_t EnclaveConfigurationPointer; /**< 0xf8 - seen in bcrypt and bcryptprimitives pointing to the string "L". */ + uint64_t VolatileMetadataPointer; /**< 0x100 */ + uint64_t GuardEHContinuationTable; /**< 0x108 - virtual address */ + uint64_t GuardEHContinuationCount; /**< 0x110 */ + uint64_t GuardXFGCheckFunctionPointer; /**< 0x118 */ + uint64_t GuardXFGDispatchFunctionPointer; /**< 0x120 */ + uint64_t GuardXFGTableDispatchFunctionPointer; /**< 0x128 */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V12; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V12, 0x130); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V12 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V12; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V12 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V12; + +/** @since Visual C++ 2019 16.x (found in 16.11.9) / RS5_IMAGE_LOAD_CONFIG_DIRECTORY32. */ +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64_V13 +{ + uint32_t Size; /**< 0x00 */ + uint32_t TimeDateStamp; /**< 0x04 */ + uint16_t MajorVersion; /**< 0x08 */ + uint16_t MinorVersion; /**< 0x0a */ + uint32_t GlobalFlagsClear; /**< 0x0c */ + uint32_t GlobalFlagsSet; /**< 0x10 */ + uint32_t CriticalSectionDefaultTimeout; /**< 0x14 */ + uint64_t DeCommitFreeBlockThreshold; /**< 0x18 */ + uint64_t DeCommitTotalFreeThreshold; /**< 0x20 */ + uint64_t LockPrefixTable; /**< 0x28 - virtual address */ + uint64_t MaximumAllocationSize; /**< 0x30 */ + uint64_t VirtualMemoryThreshold; /**< 0x38 */ + uint64_t ProcessAffinityMask; /**< 0x40 */ + uint32_t ProcessHeapFlags; /**< 0x48 */ + uint16_t CSDVersion; /**< 0x4c */ + uint16_t DependentLoadFlags; /**< 0x4e */ + uint64_t EditList; /**< 0x50 - virtual address */ + uint64_t SecurityCookie; /**< 0x58 - virtual address */ + uint64_t SEHandlerTable; /**< 0x60 */ + uint64_t SEHandlerCount; /**< 0x68 */ + uint64_t GuardCFCCheckFunctionPointer; /**< 0x70 - virtual address of pointer variable */ + uint64_t GuardCFDispatchFunctionPointer; /**< 0x78 - virtual address of pointer variable */ + uint64_t GuardCFFunctionTable; /**< 0x80 - virtual address */ + uint64_t GuardCFFunctionCount; /**< 0x88 */ + uint32_t GuardFlags; /**< 0x90 */ + IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; /**< 0x94 */ + uint64_t GuardAddressTakenIatEntryTable; /**< 0xa0 - virtual address */ + uint64_t GuardAddressTakenIatEntryCount; /**< 0xa8 */ + uint64_t GuardLongJumpTargetTable; /**< 0xb0 - virtual address */ + uint64_t GuardLongJumpTargetCount; /**< 0xb8 */ + uint64_t DynamicValueRelocTable; /**< 0xc0 - virtual address */ + uint64_t CHPEMetadataPointer; /**< 0xc8 */ + uint64_t GuardRFFailureRoutine; /**< 0xd0 - virtual address */ + uint64_t GuardRFFailureRoutineFunctionPointer; /**< 0xd8 - virtual address of pointer variable */ + uint32_t DynamicValueRelocTableOffset; /**< 0xe0 */ + uint16_t DynamicValueRelocTableSection; /**< 0xe4 */ + uint16_t Reserved2; /**< 0xe6 */ + uint64_t GuardRFVerifyStackPointerFunctionPointer; /**< 0xe8 - virtual address of pointer variable */ + uint32_t HotPatchTableOffset; /**< 0xf0 */ + uint32_t Reserved3; /**< 0xf4 */ + uint64_t EnclaveConfigurationPointer; /**< 0xf8 - seen in bcrypt and bcryptprimitives pointing to the string "L". */ + uint64_t VolatileMetadataPointer; /**< 0x100 - virtual address of pointer variable */ + uint64_t GuardEHContinuationTable; /**< 0x108 - virtual address */ + uint64_t GuardEHContinuationCount; /**< 0x110 */ + uint64_t GuardXFGCheckFunctionPointer; /**< 0x118 - virtual address of pointer variable */ + uint64_t GuardXFGDispatchFunctionPointer; /**< 0x120 - virtual address of pointer variable */ + uint64_t GuardXFGTableDispatchFunctionPointer; /**< 0x128 - virtual address of pointer variable */ + uint64_t CastGuardOsDeterminedFailureMode; /**< 0x130 - virtual address */ +} IMAGE_LOAD_CONFIG_DIRECTORY64_V13; +AssertCompileSize(IMAGE_LOAD_CONFIG_DIRECTORY64_V13, 0x138); +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V13 *PIMAGE_LOAD_CONFIG_DIRECTORY64_V13; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V13 const *PCIMAGE_LOAD_CONFIG_DIRECTORY64_V13; + +typedef IMAGE_LOAD_CONFIG_DIRECTORY64_V13 IMAGE_LOAD_CONFIG_DIRECTORY64; +typedef PIMAGE_LOAD_CONFIG_DIRECTORY64_V13 PIMAGE_LOAD_CONFIG_DIRECTORY64; +typedef PCIMAGE_LOAD_CONFIG_DIRECTORY64_V13 PCIMAGE_LOAD_CONFIG_DIRECTORY64; + +/** @} */ + + +/** + * PE certificate directory. + * + * Found in IMAGE_DIRECTORY_ENTRY_SECURITY. + */ +typedef struct WIN_CERTIFICATE +{ + uint32_t dwLength; + uint16_t wRevision; + uint16_t wCertificateType; + uint8_t bCertificate[8]; +} WIN_CERTIFICATE; +AssertCompileSize(WIN_CERTIFICATE, 16); +typedef WIN_CERTIFICATE *PWIN_CERTIFICATE; +typedef WIN_CERTIFICATE const *PCWIN_CERTIFICATE; + +/** @name WIN_CERT_REVISION_XXX - Certificate data directory revision. + * Used WIN_CERTIFICATE::wRevision found in the IMAGE_DIRECTORY_ENTRY_SECURITY + * data directory. + * @{ */ +#define WIN_CERT_REVISION_1_0 UINT16_C(0x0100) +#define WIN_CERT_REVISION_2_0 UINT16_C(0x0200) +/** @} */ + +/** @name WIN_CERT_TYPE_XXX - Signature type. + * Used by WIN_CERTIFICATE::wCertificateType. + * @{ */ +#define WIN_CERT_TYPE_X509 UINT16_C(1) +#define WIN_CERT_TYPE_PKCS_SIGNED_DATA UINT16_C(2) +#define WIN_CERT_TYPE_RESERVED_1 UINT16_C(3) +#define WIN_CERT_TYPE_TS_STACK_SIGNED UINT16_C(4) +#define WIN_CERT_TYPE_EFI_PKCS115 UINT16_C(0x0ef0) +#define WIN_CERT_TYPE_EFI_GUID UINT16_C(0x0ef1) +/** @} */ + +/** The alignment of the certificate table. + * @remarks Found thru signtool experiments. + * @note There is a copy of this in RTSignTool.cpp. */ +#define WIN_CERTIFICATE_ALIGNMENT UINT32_C(8) + + +/** + * Debug directory. + * + * Found in IMAGE_DIRECTORY_ENTRY_DEBUG. + */ +typedef struct _IMAGE_DEBUG_DIRECTORY +{ + uint32_t Characteristics; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t Type; + uint32_t SizeOfData; + uint32_t AddressOfRawData; + uint32_t PointerToRawData; +} IMAGE_DEBUG_DIRECTORY; +AssertCompileSize(IMAGE_DEBUG_DIRECTORY, 28); +typedef IMAGE_DEBUG_DIRECTORY *PIMAGE_DEBUG_DIRECTORY; +typedef IMAGE_DEBUG_DIRECTORY const *PCIMAGE_DEBUG_DIRECTORY; + +/** @name IMAGE_DEBUG_TYPE_XXX - Debug format types. + * Used by IMAGE_DEBUG_DIRECTORY::Type. + * @{ */ +#define IMAGE_DEBUG_TYPE_UNKNOWN UINT32_C(0x00) +#define IMAGE_DEBUG_TYPE_COFF UINT32_C(0x01) +#define IMAGE_DEBUG_TYPE_CODEVIEW UINT32_C(0x02) +#define IMAGE_DEBUG_TYPE_FPO UINT32_C(0x03) +#define IMAGE_DEBUG_TYPE_MISC UINT32_C(0x04) +#define IMAGE_DEBUG_TYPE_EXCEPTION UINT32_C(0x05) +#define IMAGE_DEBUG_TYPE_FIXUP UINT32_C(0x06) +#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC UINT32_C(0x07) +#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC UINT32_C(0x08) +#define IMAGE_DEBUG_TYPE_BORLAND UINT32_C(0x09) +#define IMAGE_DEBUG_TYPE_RESERVED10 UINT32_C(0x0a) +#define IMAGE_DEBUG_TYPE_CLSID UINT32_C(0x0b) +#define IMAGE_DEBUG_TYPE_VC_FEATURE UINT32_C(0x0c) +#define IMAGE_DEBUG_TYPE_POGO UINT32_C(0x0d) +#define IMAGE_DEBUG_TYPE_ILTCG UINT32_C(0x0e) +#define IMAGE_DEBUG_TYPE_MPX UINT32_C(0x0f) +#define IMAGE_DEBUG_TYPE_REPRO UINT32_C(0x10) +/** @} */ + +/** @name IMAGE_DEBUG_MISC_XXX - Misc debug data type. + * Used by IMAGE_DEBUG_MISC::DataType. + * @{ */ +#define IMAGE_DEBUG_MISC_EXENAME UINT32_C(1) +/** @} */ + + +/** + * The format of IMAGE_DEBUG_TYPE_MISC debug info. + */ +typedef struct _IMAGE_DEBUG_MISC +{ + uint32_t DataType; + uint32_t Length; + uint8_t Unicode; + uint8_t Reserved[3]; + uint8_t Data[1]; +} IMAGE_DEBUG_MISC; +AssertCompileSize(IMAGE_DEBUG_MISC, 16); +typedef IMAGE_DEBUG_MISC *PIMAGE_DEBUG_MISC; +typedef IMAGE_DEBUG_MISC const *PCIMAGE_DEBUG_MISC; + + + +/** + * The header of a .DBG file (NT4). + */ +typedef struct _IMAGE_SEPARATE_DEBUG_HEADER +{ + uint16_t Signature; /**< 0x00 */ + uint16_t Flags; /**< 0x02 */ + uint16_t Machine; /**< 0x04 */ + uint16_t Characteristics; /**< 0x06 */ + uint32_t TimeDateStamp; /**< 0x08 */ + uint32_t CheckSum; /**< 0x0c */ + uint32_t ImageBase; /**< 0x10 */ + uint32_t SizeOfImage; /**< 0x14 */ + uint32_t NumberOfSections; /**< 0x18 */ + uint32_t ExportedNamesSize; /**< 0x1c */ + uint32_t DebugDirectorySize; /**< 0x20 */ + uint32_t SectionAlignment; /**< 0x24 */ + uint32_t Reserved[2]; /**< 0x28 */ +} IMAGE_SEPARATE_DEBUG_HEADER; /* size: 0x30 */ +AssertCompileSize(IMAGE_SEPARATE_DEBUG_HEADER, 0x30); +typedef IMAGE_SEPARATE_DEBUG_HEADER *PIMAGE_SEPARATE_DEBUG_HEADER; +typedef IMAGE_SEPARATE_DEBUG_HEADER const *PCIMAGE_SEPARATE_DEBUG_HEADER; + +/** The signature of a IMAGE_SEPARATE_DEBUG_HEADER. */ +#define IMAGE_SEPARATE_DEBUG_SIGNATURE UINT16_C(0x4944) + + +/** + * The format of IMAGE_DEBUG_TYPE_COFF debug info. + */ +typedef struct _IMAGE_COFF_SYMBOLS_HEADER +{ + uint32_t NumberOfSymbols; + uint32_t LvaToFirstSymbol; + uint32_t NumberOfLinenumbers; + uint32_t LvaToFirstLinenumber; + uint32_t RvaToFirstByteOfCode; + uint32_t RvaToLastByteOfCode; + uint32_t RvaToFirstByteOfData; + uint32_t RvaToLastByteOfData; +} IMAGE_COFF_SYMBOLS_HEADER; +AssertCompileSize(IMAGE_COFF_SYMBOLS_HEADER, 0x20); +typedef IMAGE_COFF_SYMBOLS_HEADER *PIMAGE_COFF_SYMBOLS_HEADER; +typedef IMAGE_COFF_SYMBOLS_HEADER const *PCIMAGE_COFF_SYMBOLS_HEADER; + + +/** + * Line number format of IMAGE_DEBUG_TYPE_COFF debug info. + * + * @remarks This has misaligned members. + */ +#pragma pack(2) +typedef struct _IMAGE_LINENUMBER +{ + union + { + uint32_t VirtualAddress; + uint32_t SymbolTableIndex; + } Type; + uint16_t Linenumber; +} IMAGE_LINENUMBER; +#pragma pack() +AssertCompileSize(IMAGE_LINENUMBER, 6); +typedef IMAGE_LINENUMBER *PIMAGE_LINENUMBER; +typedef IMAGE_LINENUMBER const *PCIMAGE_LINENUMBER; + + +/** The size of a IMAGE_SYMBOL & IMAGE_AUX_SYMBOL structure. */ +#define IMAGE_SIZE_OF_SYMBOL 18 +/** The size of a IMAGE_SYMBOL_EX & IMAGE_AUX_SYMBOL_EX structure. */ +#define IMAGE_SIZE_OF_SYMBOL_EX 20 + +/** + * COFF symbol. + */ +#pragma pack(2) +typedef struct _IMAGE_SYMBOL +{ + union + { + uint8_t ShortName[8]; + struct + { + uint32_t Short; + uint32_t Long; + } Name; + uint32_t LongName[2]; + } N; + + uint32_t Value; + int16_t SectionNumber; + uint16_t Type; + uint8_t StorageClass; + uint8_t NumberOfAuxSymbols; +} IMAGE_SYMBOL; +#pragma pack() +AssertCompileSize(IMAGE_SYMBOL, IMAGE_SIZE_OF_SYMBOL); +typedef IMAGE_SYMBOL *PIMAGE_SYMBOL; +typedef IMAGE_SYMBOL const *PCIMAGE_SYMBOL; + +/** + * COFF auxiliary symbol token defintion (whatever that is). + */ +#pragma pack(2) +typedef struct IMAGE_AUX_SYMBOL_TOKEN_DEF +{ + uint8_t bAuxType; + uint8_t bReserved; + uint32_t SymbolTableIndex; + uint8_t rgbReserved[12]; +} IMAGE_AUX_SYMBOL_TOKEN_DEF; +#pragma pack() +AssertCompileSize(IMAGE_AUX_SYMBOL_TOKEN_DEF, IMAGE_SIZE_OF_SYMBOL); +typedef IMAGE_AUX_SYMBOL_TOKEN_DEF *PIMAGE_AUX_SYMBOL_TOKEN_DEF; +typedef IMAGE_AUX_SYMBOL_TOKEN_DEF const *PCIMAGE_AUX_SYMBOL_TOKEN_DEF; + +/** + * COFF auxiliary symbol. + */ +#pragma pack(1) +typedef union _IMAGE_AUX_SYMBOL +{ + struct + { + uint32_t TagIndex; + union + { + struct + { + uint16_t Linenumber; + uint16_t Size; + } LnSz; + } Misc; + union + { + struct + { + uint32_t PointerToLinenumber; + uint32_t PointerToNextFunction; + } Function; + struct + { + uint16_t Dimension[4]; + } Array; + } FcnAry; + uint16_t TvIndex; + } Sym; + + struct + { + uint8_t Name[IMAGE_SIZE_OF_SYMBOL]; + } File; + + struct + { + uint32_t Length; + uint16_t NumberOfRelocations; + uint16_t NumberOfLinenumbers; + uint32_t CheckSum; + uint16_t Number; + uint8_t Selection; + uint8_t bReserved; + uint16_t HighNumber; + } Section; + + IMAGE_AUX_SYMBOL_TOKEN_DEF TokenDef; + struct + { + uint32_t crc; + uint8_t rgbReserved[14]; + } CRC; +} IMAGE_AUX_SYMBOL; +#pragma pack() +AssertCompileSize(IMAGE_AUX_SYMBOL, IMAGE_SIZE_OF_SYMBOL); +typedef IMAGE_AUX_SYMBOL *PIMAGE_AUX_SYMBOL; +typedef IMAGE_AUX_SYMBOL const *PCIMAGE_AUX_SYMBOL; + + +/** + * Extended COFF symbol. + */ +typedef struct _IMAGE_SYMBOL_EX +{ + union + { + uint8_t ShortName[8]; + struct + { + uint32_t Short; + uint32_t Long; + } Name; + uint32_t LongName[2]; + } N; + + uint32_t Value; + int32_t SectionNumber; /* The difference from IMAGE_SYMBOL */ + uint16_t Type; + uint8_t StorageClass; + uint8_t NumberOfAuxSymbols; +} IMAGE_SYMBOL_EX; +AssertCompileSize(IMAGE_SYMBOL_EX, IMAGE_SIZE_OF_SYMBOL_EX); +typedef IMAGE_SYMBOL_EX *PIMAGE_SYMBOL_EX; +typedef IMAGE_SYMBOL_EX const *PCIMAGE_SYMBOL_EX; + +/** + * Extended COFF auxiliary symbol. + */ +typedef union _IMAGE_AUX_SYMBOL_EX +{ + struct + { + uint32_t WeakDefaultSymIndex; + uint32_t WeakSearchType; + uint8_t rgbReserved[12]; + } Sym; + + struct + { + uint8_t Name[IMAGE_SIZE_OF_SYMBOL_EX]; + } File; + + struct + { + uint32_t Length; + uint16_t NumberOfRelocations; + uint16_t NumberOfLinenumbers; + uint32_t CheckSum; + uint16_t Number; + uint8_t Selection; + uint8_t bReserved; + uint16_t HighNumber; + uint8_t rgbReserved[2]; + } Section; + + IMAGE_AUX_SYMBOL_TOKEN_DEF TokenDef; + + struct + { + uint32_t crc; + uint8_t rgbReserved[16]; + } CRC; +} IMAGE_AUX_SYMBOL_EX; +AssertCompileSize(IMAGE_AUX_SYMBOL_EX, IMAGE_SIZE_OF_SYMBOL_EX); +typedef IMAGE_AUX_SYMBOL_EX *PIMAGE_AUX_SYMBOL_EX; +typedef IMAGE_AUX_SYMBOL_EX const *PCIMAGE_AUX_SYMBOL_EX; + +/** @name Special COFF section numbers. + * Used by IMAGE_SYMBOL::SectionNumber and IMAGE_SYMBOL_EX::SectionNumber + * @{ */ +#define IMAGE_SYM_UNDEFINED INT16_C(0) +#define IMAGE_SYM_ABSOLUTE INT16_C(-1) +#define IMAGE_SYM_DEBUG INT16_C(-2) +/** @} */ + +/** @name IMAGE_SYM_CLASS_XXX - COFF symbol storage classes. + * @{ */ +#define IMAGE_SYM_CLASS_END_OF_FUNCTION UINT8_C(0xff) /* -1 */ +#define IMAGE_SYM_CLASS_NULL UINT8_C(0) +#define IMAGE_SYM_CLASS_AUTOMATIC UINT8_C(1) +#define IMAGE_SYM_CLASS_EXTERNAL UINT8_C(2) +#define IMAGE_SYM_CLASS_STATIC UINT8_C(3) +#define IMAGE_SYM_CLASS_REGISTER UINT8_C(4) +#define IMAGE_SYM_CLASS_EXTERNAL_DEF UINT8_C(5) +#define IMAGE_SYM_CLASS_LABEL UINT8_C(6) +#define IMAGE_SYM_CLASS_UNDEFINED_LABEL UINT8_C(7) +#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT UINT8_C(8) +#define IMAGE_SYM_CLASS_ARGUMENT UINT8_C(9) +#define IMAGE_SYM_CLASS_STRUCT_TAG UINT8_C(10) +#define IMAGE_SYM_CLASS_MEMBER_OF_UNION UINT8_C(11) +#define IMAGE_SYM_CLASS_UNION_TAG UINT8_C(12) +#define IMAGE_SYM_CLASS_TYPE_DEFINITION UINT8_C(13) +#define IMAGE_SYM_CLASS_UNDEFINED_STATIC UINT8_C(14) +#define IMAGE_SYM_CLASS_ENUM_TAG UINT8_C(15) +#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM UINT8_C(16) +#define IMAGE_SYM_CLASS_REGISTER_PARAM UINT8_C(17) +#define IMAGE_SYM_CLASS_BIT_FIELD UINT8_C(18) +#define IMAGE_SYM_CLASS_FAR_EXTERNAL UINT8_C(68) +#define IMAGE_SYM_CLASS_BLOCK UINT8_C(100) +#define IMAGE_SYM_CLASS_FUNCTION UINT8_C(101) +#define IMAGE_SYM_CLASS_END_OF_STRUCT UINT8_C(102) +#define IMAGE_SYM_CLASS_FILE UINT8_C(103) +#define IMAGE_SYM_CLASS_SECTION UINT8_C(104) +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL UINT8_C(105) +#define IMAGE_SYM_CLASS_CLR_TOKEN UINT8_C(107) +/** @} */ + +/** @name IMAGE_SYM_TYPE_XXX - COFF symbol base types + * @{ */ +#define IMAGE_SYM_TYPE_NULL UINT16_C(0x0000) +#define IMAGE_SYM_TYPE_VOID UINT16_C(0x0001) +#define IMAGE_SYM_TYPE_CHAR UINT16_C(0x0002) +#define IMAGE_SYM_TYPE_SHORT UINT16_C(0x0003) +#define IMAGE_SYM_TYPE_INT UINT16_C(0x0004) +#define IMAGE_SYM_TYPE_LONG UINT16_C(0x0005) +#define IMAGE_SYM_TYPE_FLOAT UINT16_C(0x0006) +#define IMAGE_SYM_TYPE_DOUBLE UINT16_C(0x0007) +#define IMAGE_SYM_TYPE_STRUCT UINT16_C(0x0008) +#define IMAGE_SYM_TYPE_UNION UINT16_C(0x0009) +#define IMAGE_SYM_TYPE_ENUM UINT16_C(0x000a) +#define IMAGE_SYM_TYPE_MOE UINT16_C(0x000b) +#define IMAGE_SYM_TYPE_BYTE UINT16_C(0x000c) +#define IMAGE_SYM_TYPE_WORD UINT16_C(0x000d) +#define IMAGE_SYM_TYPE_UINT UINT16_C(0x000e) +#define IMAGE_SYM_TYPE_DWORD UINT16_C(0x000f) +#define IMAGE_SYM_TYPE_PCODE UINT16_C(0x8000) +/** @} */ + +/** @name IMAGE_SYM_DTYPE_XXX - COFF symbol complex types + * @{ */ +#define IMAGE_SYM_DTYPE_NULL UINT16_C(0x0) +#define IMAGE_SYM_DTYPE_POINTER UINT16_C(0x1) +#define IMAGE_SYM_DTYPE_FUNCTION UINT16_C(0x2) +#define IMAGE_SYM_DTYPE_ARRAY UINT16_C(0x3) +/** @} */ + +/** @name COFF Symbol type masks and shift counts. + * @{ */ +#define N_BTMASK UINT16_C(0x000f) +#define N_TMASK UINT16_C(0x0030) +#define N_TMASK1 UINT16_C(0x00c0) +#define N_TMASK2 UINT16_C(0x00f0) +#define N_BTSHFT 4 +#define N_TSHIFT 2 +/** @} */ + +/** @name COFF Symbol type macros. + * @{ */ +#define BTYPE(a_Type) ( (a_Type) & N_BTMASK ) +#define ISPTR(a_Type) ( ((a_Type) & N_TMASK) == (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT) ) +#define ISFCN(a_Type) ( ((a_Type) & N_TMASK) == (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT) ) +#define ISARY(a_Type) ( ((a_Type) & N_TMASK) == (IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT) ) +#define ISTAG(a_StorageClass) ( (a_StorageClass) == IMAGE_SYM_CLASS_STRUCT_TAG \ + || (a_StorageClass) == IMAGE_SYM_CLASS_UNION_TAG \ + || (a_StorageClass) == IMAGE_SYM_CLASS_ENUM_TAG ) +/** @} */ + + +/** + * COFF relocation table entry. + * + * @note The size of the structure is not a multiple of the largest member + * (uint32_t), so odd relocation table entry members will have + * misaligned uint32_t members. + */ +#pragma pack(1) +typedef struct _IMAGE_RELOCATION +{ + union + { + uint32_t VirtualAddress; + uint32_t RelocCount; + } u; + uint32_t SymbolTableIndex; + uint16_t Type; +} IMAGE_RELOCATION; +#pragma pack() +/** The size of a COFF relocation entry. */ +#define IMAGE_SIZEOF_RELOCATION 10 +AssertCompileSize(IMAGE_RELOCATION, IMAGE_SIZEOF_RELOCATION); +typedef IMAGE_RELOCATION *PIMAGE_RELOCATION; +typedef IMAGE_RELOCATION const *PCIMAGE_RELOCATION; + + +/** @name IMAGE_REL_AMD64_XXX - COFF relocations for AMD64 CPUs. + * Used by IMAGE_RELOCATION::Type. + * @{ */ +#define IMAGE_REL_AMD64_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_AMD64_ADDR64 UINT16_C(0x0001) +#define IMAGE_REL_AMD64_ADDR32 UINT16_C(0x0002) +#define IMAGE_REL_AMD64_ADDR32NB UINT16_C(0x0003) +#define IMAGE_REL_AMD64_REL32 UINT16_C(0x0004) +#define IMAGE_REL_AMD64_REL32_1 UINT16_C(0x0005) +#define IMAGE_REL_AMD64_REL32_2 UINT16_C(0x0006) +#define IMAGE_REL_AMD64_REL32_3 UINT16_C(0x0007) +#define IMAGE_REL_AMD64_REL32_4 UINT16_C(0x0008) +#define IMAGE_REL_AMD64_REL32_5 UINT16_C(0x0009) +#define IMAGE_REL_AMD64_SECTION UINT16_C(0x000a) +#define IMAGE_REL_AMD64_SECREL UINT16_C(0x000b) +#define IMAGE_REL_AMD64_SECREL7 UINT16_C(0x000c) +#define IMAGE_REL_AMD64_TOKEN UINT16_C(0x000d) +#define IMAGE_REL_AMD64_SREL32 UINT16_C(0x000e) +#define IMAGE_REL_AMD64_PAIR UINT16_C(0x000f) +#define IMAGE_REL_AMD64_SSPAN32 UINT16_C(0x0010) +/** @} */ + +/** @name ARM IMAGE_REL_ARM_XXX - COFF relocations for ARM CPUs. + * Used by IMAGE_RELOCATION::Type. + * @{ */ +#define IMAGE_REL_ARM_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_ARM_ADDR32 UINT16_C(0x0001) +#define IMAGE_REL_ARM_ADDR32NB UINT16_C(0x0002) +#define IMAGE_REL_ARM_BRANCH24 UINT16_C(0x0003) +#define IMAGE_REL_ARM_BRANCH11 UINT16_C(0x0004) +#define IMAGE_REL_ARM_TOKEN UINT16_C(0x0005) +#define IMAGE_REL_ARM_BLX24 UINT16_C(0x0008) +#define IMAGE_REL_ARM_BLX11 UINT16_C(0x0009) +#define IMAGE_REL_ARM_SECTION UINT16_C(0x000e) +#define IMAGE_REL_ARM_SECREL UINT16_C(0x000f) +#define IMAGE_REL_ARM_MOV32A UINT16_C(0x0010) +#define IMAGE_REL_ARM_MOV32T UINT16_C(0x0011) +#define IMAGE_REL_ARM_BRANCH20T UINT16_C(0x0012) +#define IMAGE_REL_ARM_BRANCH24T UINT16_C(0x0014) +#define IMAGE_REL_ARM_BLX23T UINT16_C(0x0015) +/** @} */ + +/** @name IMAGE_REL_ARM64_XXX - COFF relocations for ARMv8 CPUs (64-bit). + * Used by IMAGE_RELOCATION::Type. + * @{ */ +#define IMAGE_REL_ARM64_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_ARM64_ADDR32 UINT16_C(0x0001) +#define IMAGE_REL_ARM64_ADDR32NB UINT16_C(0x0002) +#define IMAGE_REL_ARM64_BRANCH26 UINT16_C(0x0003) +#define IMAGE_REL_ARM64_PAGEBASE_REL21 UINT16_C(0x0004) +#define IMAGE_REL_ARM64_REL21 UINT16_C(0x0005) +#define IMAGE_REL_ARM64_PAGEOFFSET_12A UINT16_C(0x0006) +#define IMAGE_REL_ARM64_PAGEOFFSET_12L UINT16_C(0x0007) +#define IMAGE_REL_ARM64_SECREL UINT16_C(0x0008) +#define IMAGE_REL_ARM64_SECREL_LOW12A UINT16_C(0x0009) +#define IMAGE_REL_ARM64_SECREL_HIGH12A UINT16_C(0x000a) +#define IMAGE_REL_ARM64_SECREL_LOW12L UINT16_C(0x000b) +#define IMAGE_REL_ARM64_TOKEN UINT16_C(0x000c) +#define IMAGE_REL_ARM64_SECTION UINT16_C(0x000d) +#define IMAGE_REL_ARM64_ADDR64 UINT16_C(0x000e) +/** @} */ + +/** @name IMAGE_REL_SH3_XXX - COFF relocation for Hitachi SuperH CPUs. + * Used by IMAGE_RELOCATION::Type. + * @{ */ +#define IMAGE_REL_SH3_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_SH3_DIRECT16 UINT16_C(0x0001) +#define IMAGE_REL_SH3_DIRECT32 UINT16_C(0x0002) +#define IMAGE_REL_SH3_DIRECT8 UINT16_C(0x0003) +#define IMAGE_REL_SH3_DIRECT8_WORD UINT16_C(0x0004) +#define IMAGE_REL_SH3_DIRECT8_LONG UINT16_C(0x0005) +#define IMAGE_REL_SH3_DIRECT4 UINT16_C(0x0006) +#define IMAGE_REL_SH3_DIRECT4_WORD UINT16_C(0x0007) +#define IMAGE_REL_SH3_DIRECT4_LONG UINT16_C(0x0008) +#define IMAGE_REL_SH3_PCREL8_WORD UINT16_C(0x0009) +#define IMAGE_REL_SH3_PCREL8_LONG UINT16_C(0x000a) +#define IMAGE_REL_SH3_PCREL12_WORD UINT16_C(0x000b) +#define IMAGE_REL_SH3_STARTOF_SECTION UINT16_C(0x000c) +#define IMAGE_REL_SH3_SIZEOF_SECTION UINT16_C(0x000d) +#define IMAGE_REL_SH3_SECTION UINT16_C(0x000e) +#define IMAGE_REL_SH3_SECREL UINT16_C(0x000f) +#define IMAGE_REL_SH3_DIRECT32_NB UINT16_C(0x0010) +#define IMAGE_REL_SH3_GPREL4_LONG UINT16_C(0x0011) +#define IMAGE_REL_SH3_TOKEN UINT16_C(0x0012) +#define IMAGE_REL_SHM_PCRELPT UINT16_C(0x0013) +#define IMAGE_REL_SHM_REFLO UINT16_C(0x0014) +#define IMAGE_REL_SHM_REFHALF UINT16_C(0x0015) +#define IMAGE_REL_SHM_RELLO UINT16_C(0x0016) +#define IMAGE_REL_SHM_RELHALF UINT16_C(0x0017) +#define IMAGE_REL_SHM_PAIR UINT16_C(0x0018) +#define IMAGE_REL_SHM_NOMODE UINT16_C(0x8000) +/** @} */ + +/** @name IMAGE_REL_PPC_XXX - COFF relocations for IBM PowerPC CPUs. + * Used by IMAGE_RELOCATION::Type. + * @{ */ +#define IMAGE_REL_PPC_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_PPC_ADDR64 UINT16_C(0x0001) +#define IMAGE_REL_PPC_ADDR32 UINT16_C(0x0002) +#define IMAGE_REL_PPC_ADDR24 UINT16_C(0x0003) +#define IMAGE_REL_PPC_ADDR16 UINT16_C(0x0004) +#define IMAGE_REL_PPC_ADDR14 UINT16_C(0x0005) +#define IMAGE_REL_PPC_REL24 UINT16_C(0x0006) +#define IMAGE_REL_PPC_REL14 UINT16_C(0x0007) +#define IMAGE_REL_PPC_ADDR32NB UINT16_C(0x000a) +#define IMAGE_REL_PPC_SECREL UINT16_C(0x000b) +#define IMAGE_REL_PPC_SECTION UINT16_C(0x000c) +#define IMAGE_REL_PPC_SECREL16 UINT16_C(0x000f) +#define IMAGE_REL_PPC_REFHI UINT16_C(0x0010) +#define IMAGE_REL_PPC_REFLO UINT16_C(0x0011) +#define IMAGE_REL_PPC_PAIR UINT16_C(0x0012) +#define IMAGE_REL_PPC_SECRELLO UINT16_C(0x0013) +#define IMAGE_REL_PPC_GPREL UINT16_C(0x0015) +#define IMAGE_REL_PPC_TOKEN UINT16_C(0x0016) +/** @} */ + +/** @name IMAGE_REL_I386_XXX - COFF relocations for x86 CPUs. + * Used by IMAGE_RELOCATION::Type. + * @{ */ +#define IMAGE_REL_I386_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_I386_DIR16 UINT16_C(0x0001) +#define IMAGE_REL_I386_REL16 UINT16_C(0x0002) +#define IMAGE_REL_I386_DIR32 UINT16_C(0x0006) +#define IMAGE_REL_I386_DIR32NB UINT16_C(0x0007) +#define IMAGE_REL_I386_SEG12 UINT16_C(0x0009) +#define IMAGE_REL_I386_SECTION UINT16_C(0x000A) +#define IMAGE_REL_I386_SECREL UINT16_C(0x000B) +#define IMAGE_REL_I386_TOKEN UINT16_C(0x000C) +#define IMAGE_REL_I386_SECREL7 UINT16_C(0x000D) +#define IMAGE_REL_I386_REL32 UINT16_C(0x0014) +/** @} */ + +/** @name IMAGE_REL_IA64_XXX - COFF relocations for "Itanic" CPUs. + * @{ */ +#define IMAGE_REL_IA64_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_IA64_IMM14 UINT16_C(0x0001) +#define IMAGE_REL_IA64_IMM22 UINT16_C(0x0002) +#define IMAGE_REL_IA64_IMM64 UINT16_C(0x0003) +#define IMAGE_REL_IA64_DIR32 UINT16_C(0x0004) +#define IMAGE_REL_IA64_DIR64 UINT16_C(0x0005) +#define IMAGE_REL_IA64_PCREL21B UINT16_C(0x0006) +#define IMAGE_REL_IA64_PCREL21M UINT16_C(0x0007) +#define IMAGE_REL_IA64_PCREL21F UINT16_C(0x0008) +#define IMAGE_REL_IA64_GPREL22 UINT16_C(0x0009) +#define IMAGE_REL_IA64_LTOFF22 UINT16_C(0x000a) +#define IMAGE_REL_IA64_SECTION UINT16_C(0x000b) +#define IMAGE_REL_IA64_SECREL22 UINT16_C(0x000c) +#define IMAGE_REL_IA64_SECREL64I UINT16_C(0x000d) +#define IMAGE_REL_IA64_SECREL32 UINT16_C(0x000e) +#define IMAGE_REL_IA64_DIR32NB UINT16_C(0x0010) +#define IMAGE_REL_IA64_SREL14 UINT16_C(0x0011) +#define IMAGE_REL_IA64_SREL22 UINT16_C(0x0012) +#define IMAGE_REL_IA64_SREL32 UINT16_C(0x0013) +#define IMAGE_REL_IA64_UREL32 UINT16_C(0x0014) +#define IMAGE_REL_IA64_PCREL60X UINT16_C(0x0015) +#define IMAGE_REL_IA64_PCREL60B UINT16_C(0x0016) +#define IMAGE_REL_IA64_PCREL60F UINT16_C(0x0017) +#define IMAGE_REL_IA64_PCREL60I UINT16_C(0x0018) +#define IMAGE_REL_IA64_PCREL60M UINT16_C(0x0019) +#define IMAGE_REL_IA64_IMMGPREL64 UINT16_C(0x001a) +#define IMAGE_REL_IA64_TOKEN UINT16_C(0x001b) +#define IMAGE_REL_IA64_GPREL32 UINT16_C(0x001c) +#define IMAGE_REL_IA64_ADDEND UINT16_C(0x001f) +/** @} */ + +/** @name IMAGE_REL_MIPS_XXX - COFF relocations for MIPS CPUs. + * Used by IMAGE_RELOCATION::Type. + * @{ */ +#define IMAGE_REL_MIPS_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_MIPS_REFHALF UINT16_C(0x0001) +#define IMAGE_REL_MIPS_REFWORD UINT16_C(0x0002) +#define IMAGE_REL_MIPS_JMPADDR UINT16_C(0x0003) +#define IMAGE_REL_MIPS_REFHI UINT16_C(0x0004) +#define IMAGE_REL_MIPS_REFLO UINT16_C(0x0005) +#define IMAGE_REL_MIPS_GPREL UINT16_C(0x0006) +#define IMAGE_REL_MIPS_LITERAL UINT16_C(0x0007) +#define IMAGE_REL_MIPS_SECTION UINT16_C(0x000a) +#define IMAGE_REL_MIPS_SECREL UINT16_C(0x000b) +#define IMAGE_REL_MIPS_SECRELLO UINT16_C(0x000c) +#define IMAGE_REL_MIPS_SECRELHI UINT16_C(0x000d) +#define IMAGE_REL_MIPS_JMPADDR16 UINT16_C(0x0010) +#define IMAGE_REL_MIPS_REFWORDNB UINT16_C(0x0022) +#define IMAGE_REL_MIPS_PAIR UINT16_C(0x0025) +/** @} */ + +/** @name IMAGE_REL_M32R_XXX - COFF relocations for Mitsubishi M32R CPUs. + * Used by IMAGE_RELOCATION::Type. + * @{ */ +#define IMAGE_REL_M32R_ABSOLUTE UINT16_C(0x0000) +#define IMAGE_REL_M32R_ADDR32 UINT16_C(0x0001) +#define IMAGE_REL_M32R_ADDR32NB UINT16_C(0x0002) +#define IMAGE_REL_M32R_ADDR24 UINT16_C(0x0003) +#define IMAGE_REL_M32R_GPREL16 UINT16_C(0x0004) +#define IMAGE_REL_M32R_PCREL24 UINT16_C(0x0005) +#define IMAGE_REL_M32R_PCREL16 UINT16_C(0x0006) +#define IMAGE_REL_M32R_PCREL8 UINT16_C(0x0007) +#define IMAGE_REL_M32R_REFHALF UINT16_C(0x0008) +#define IMAGE_REL_M32R_REFHI UINT16_C(0x0009) +#define IMAGE_REL_M32R_REFLO UINT16_C(0x000a) +#define IMAGE_REL_M32R_PAIR UINT16_C(0x000b) +#define IMAGE_REL_M32R_SECTION UINT16_C(0x000c) +#define IMAGE_REL_M32R_SECREL UINT16_C(0x000d) +#define IMAGE_REL_M32R_TOKEN UINT16_C(0x000e) +/** @} */ + + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_pecoff_h */ + diff --git a/include/iprt/formats/riff.h b/include/iprt/formats/riff.h new file mode 100644 index 00000000..91de3bec --- /dev/null +++ b/include/iprt/formats/riff.h @@ -0,0 +1,247 @@ +/* $Id: riff.h $ */ +/** @file + * IPRT - Resource Interchange File Format (RIFF), WAVE, ++. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_riff_h +#define IPRT_INCLUDED_formats_riff_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_rt_formats_riff RIFF & WAVE structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + +/** + * Resource interchange file format (RIFF) file header. + */ +typedef struct RTRIFFHDR +{ + /** The 'RIFF' magic (RTRIFFHDR_MAGIC). */ + uint32_t uMagic; + /** The file size. */ + uint32_t cbFile; + /** The file type. */ + uint32_t uFileType; +} RTRIFFHDR; +AssertCompileSize(RTRIFFHDR, 12); +/** Pointer to a RIFF file header. */ +typedef RTRIFFHDR *PRTRIFFHDR; + +/** Magic value for RTRIFFHDR::uMagic ('RIFF'). */ +#define RTRIFFHDR_MAGIC RT_BE2H_U32_C(0x52494646) + +/** @name RIFF file types (RTRIFFHDR::uFileType) + * @{ */ +/** RIFF file type: WAVE (audio) */ +#define RTRIFF_FILE_TYPE_WAVE RT_BE2H_U32_C(0x57415645) +/** RIFF file type: AVI (video) */ +#define RTRIFF_FILE_TYPE_AVI RT_BE2H_U32_C(0x41564920) +/** @} */ + +/** + * A RIFF chunk. + */ +typedef struct RTRIFFCHUNK +{ + /** The chunk magic (four character code). */ + uint32_t uMagic; + /** The size of the chunk minus this header. */ + uint32_t cbChunk; +} RTRIFFCHUNK; +AssertCompileSize(RTRIFFCHUNK, 8); +/** Pointer to a RIFF chunk. */ +typedef RTRIFFCHUNK *PRTRIFFCHUNK; + +/** + * A RIFF list. + */ +typedef struct RTRIFFLIST +{ + /** The list indicator (RTRIFFLIST_MAGIC). */ + uint32_t uMagic; + /** The size of the chunk minus this header. */ + uint32_t cbChunk; + /** The list type (four character code). */ + uint32_t uListType; +} RTRIFFLIST; +AssertCompileSize(RTRIFFLIST, 12); +/** Pointer to a RIFF list. */ +typedef RTRIFFLIST *PRTRIFFLIST; +/** Magic value for RTRIFFLIST::uMagic ('LIST'). */ +#define RTRIFFLIST_MAGIC RT_BE2H_U32_C(0x4c495354) + +/** Generic 'INFO' list type. */ +#define RTRIFFLIST_TYPE_INFO RT_BE2H_U32_C(0x494e464f) + + +/** + * Wave file format (WAVEFORMATEX w/o cbSize). + * @see RTRIFFWAVEFMTCHUNK. + */ +typedef struct RTRIFFWAVEFMT +{ + /** Audio format tag. */ + uint16_t uFormatTag; + /** Number of channels. */ + uint16_t cChannels; + /** Sample rate. */ + uint32_t uHz; + /** Byte rate (= uHz * cChannels * cBitsPerSample / 8) */ + uint32_t cbRate; + /** Frame size (aka block alignment). */ + uint16_t cbFrame; + /** Number of bits per sample. */ + uint16_t cBitsPerSample; +} RTRIFFWAVEFMT; +AssertCompileSize(RTRIFFWAVEFMT, 16); +/** Pointer to a wave file format structure. */ +typedef RTRIFFWAVEFMT *PRTRIFFWAVEFMT; + +/** + * Extensible wave file format (WAVEFORMATEXTENSIBLE). + * @see RTRIFFWAVEFMTEXTCHUNK. + */ +#pragma pack(4) /* Override the uint64_t effect from RTUUID, so we can safely put it after RTRIFFHDR in a structure. */ +typedef struct RTRIFFWAVEFMTEXT +{ + /** The coreformat structure. */ + RTRIFFWAVEFMT Core; + /** Number of bytes of extra information after the core. */ + uint16_t cbExtra; + /** Number of valid bits per sample. */ + uint16_t cValidBitsPerSample; + /** The channel mask. */ + uint32_t fChannelMask; + /** The GUID of the sub-format. */ + RTUUID SubFormat; +} RTRIFFWAVEFMTEXT; +#pragma pack() +AssertCompileSize(RTRIFFWAVEFMTEXT, 16+2+22); +/** Pointer to an extensible wave file format structure. */ +typedef RTRIFFWAVEFMTEXT *PRTRIFFWAVEFMTEXT; + +/** RTRIFFWAVEFMT::uFormatTag value for PCM (WDK: WAVE_FORMAT_PCM). */ +#define RTRIFFWAVEFMT_TAG_PCM UINT16_C(0x0001) +/** RTRIFFWAVEFMT::uFormatTag value for extensible wave files (WDK: WAVE_FORMAT_EXTENSIBLE). */ +#define RTRIFFWAVEFMT_TAG_EXTENSIBLE UINT16_C(0xfffe) + +/** Typical RTRIFFWAVEFMTEXT::cbExtra value (min). */ +#define RTRIFFWAVEFMTEXT_EXTRA_SIZE UINT16_C(22) + +/** @name Channel IDs for RTRIFFWAVEFMTEXT::fChannelMask. + * @{ */ +#define RTRIFFWAVEFMTEXT_CH_ID_FL RT_BIT_32(0) /**< Front left. */ +#define RTRIFFWAVEFMTEXT_CH_ID_FR RT_BIT_32(1) /**< Front right. */ +#define RTRIFFWAVEFMTEXT_CH_ID_FC RT_BIT_32(2) /**< Front center */ +#define RTRIFFWAVEFMTEXT_CH_ID_LFE RT_BIT_32(3) /**< Low frequency */ +#define RTRIFFWAVEFMTEXT_CH_ID_BL RT_BIT_32(4) /**< Back left. */ +#define RTRIFFWAVEFMTEXT_CH_ID_BR RT_BIT_32(5) /**< Back right. */ +#define RTRIFFWAVEFMTEXT_CH_ID_FLC RT_BIT_32(6) /**< Front left of center. */ +#define RTRIFFWAVEFMTEXT_CH_ID_FLR RT_BIT_32(7) /**< Front right of center. */ +#define RTRIFFWAVEFMTEXT_CH_ID_BC RT_BIT_32(8) /**< Back center. */ +#define RTRIFFWAVEFMTEXT_CH_ID_SL RT_BIT_32(9) /**< Side left. */ +#define RTRIFFWAVEFMTEXT_CH_ID_SR RT_BIT_32(10) /**< Side right. */ +#define RTRIFFWAVEFMTEXT_CH_ID_TC RT_BIT_32(11) /**< Top center. */ +#define RTRIFFWAVEFMTEXT_CH_ID_TFL RT_BIT_32(12) /**< Top front left. */ +#define RTRIFFWAVEFMTEXT_CH_ID_TFC RT_BIT_32(13) /**< Top front center. */ +#define RTRIFFWAVEFMTEXT_CH_ID_TFR RT_BIT_32(14) /**< Top front right. */ +#define RTRIFFWAVEFMTEXT_CH_ID_TBL RT_BIT_32(15) /**< Top back left. */ +#define RTRIFFWAVEFMTEXT_CH_ID_TBC RT_BIT_32(16) /**< Top back center. */ +#define RTRIFFWAVEFMTEXT_CH_ID_TBR RT_BIT_32(17) /**< Top back right. */ +/** @} */ + +/** RTRIFFWAVEFMTEXT::SubFormat UUID string for PCM. */ +#define RTRIFFWAVEFMTEXT_SUBTYPE_PCM "00000001-0000-0010-8000-00aa00389b71" + + +/** + * Wave file format chunk. + */ +typedef struct RTRIFFWAVEFMTCHUNK +{ + /** Chunk header with RTRIFFWAVEFMT_MAGIC as magic. */ + RTRIFFCHUNK Chunk; + /** The wave file format. */ + RTRIFFWAVEFMT Data; +} RTRIFFWAVEFMTCHUNK; +AssertCompileSize(RTRIFFWAVEFMTCHUNK, 8+16); +/** Pointer to a wave file format chunk. */ +typedef RTRIFFWAVEFMTCHUNK *PRTRIFFWAVEFMTCHUNK; +/** Magic value for RTRIFFWAVEFMTCHUNK and RTRIFFWAVEFMTEXTCHUNK ('fmt '). */ +#define RTRIFFWAVEFMT_MAGIC RT_BE2H_U32_C(0x666d7420) + +/** + * Extensible wave file format chunk. + */ +typedef struct RTRIFFWAVEFMTEXTCHUNK +{ + /** Chunk header with RTRIFFWAVEFMT_MAGIC as magic. */ + RTRIFFCHUNK Chunk; + /** The wave file format. */ + RTRIFFWAVEFMTEXT Data; +} RTRIFFWAVEFMTEXTCHUNK; +AssertCompileSize(RTRIFFWAVEFMTEXTCHUNK, 8+16+2+22); +/** Pointer to a wave file format chunk. */ +typedef RTRIFFWAVEFMTEXTCHUNK *PRTRIFFWAVEFMTEXTCHUNK; + + +/** + * Wave file data chunk. + */ +typedef struct RTRIFFWAVEDATACHUNK +{ + /** Chunk header with RTRIFFWAVEFMT_MAGIC as magic. */ + RTRIFFCHUNK Chunk; + /** Variable sized sample data. */ + uint8_t abData[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} RTRIFFWAVEDATACHUNK; + +/** Magic value for RTRIFFWAVEFMT::uMagic ('data'). */ +#define RTRIFFWAVEDATACHUNK_MAGIC RT_BE2H_U32_C(0x64617461) + + +/** Magic value padding chunks ('PAD '). */ +#define RTRIFFPADCHUNK_MAGIC RT_BE2H_U32_C(0x50414420) + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_riff_h */ + diff --git a/include/iprt/formats/tpm.h b/include/iprt/formats/tpm.h new file mode 100644 index 00000000..454a2d4f --- /dev/null +++ b/include/iprt/formats/tpm.h @@ -0,0 +1,313 @@ +/* $Id: tpm.h $ */ +/** @file + * IPRT, TPM common definitions (this is actually a protocol and not a format). + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_tpm_h +#define IPRT_INCLUDED_formats_tpm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/asm.h> +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/assertcompile.h> +#include <iprt/string.h> + + +/** + * TPM request header (everything big endian). + */ +#pragma pack(1) +typedef struct TPMREQHDR +{ + /** The tag for this request. */ + uint16_t u16Tag; + /** Size of the request in bytes. */ + uint32_t cbReq; + /** The request ordinal to execute. */ + uint32_t u32Ordinal; +} TPMREQHDR; +#pragma pack() +AssertCompileSize(TPMREQHDR, 2 + 4 + 4); +/** Pointer to a TPM request header. */ +typedef TPMREQHDR *PTPMREQHDR; +/** Pointer to a const TPM request header. */ +typedef const TPMREQHDR *PCTPMREQHDR; + + +/** @name TPM 1.2 request tags + * @{ */ +/** Command with no authentication. */ +#define TPM_TAG_RQU_COMMAND UINT16_C(0x00c1) +/** An authenticated command with one authentication handle. */ +#define TPM_TAG_RQU_AUTH1_COMMAND UINT16_C(0x00c2) +/** An authenticated command with two authentication handles. */ +#define TPM_TAG_RQU_AUTH2_COMMAND UINT16_C(0x00c3) +/** @} */ + + +/** @name TPM 2.0 request/response tags + * @{ */ +/** Command with no associated session. */ +#define TPM2_ST_NO_SESSIONS UINT16_C(0x8001) +/** Command with an associated session. */ +#define TPM2_ST_SESSIONS UINT16_C(0x8002) +/** @} */ + + +/** @name TPM 1.2 request ordinals. + * @{ */ +/** Perform a full self test. */ +#define TPM_ORD_SELFTESTFULL UINT32_C(80) +/** Continue the selftest. */ +#define TPM_ORD_CONTINUESELFTEST UINT32_C(83) +/** Return the test result. */ +#define TPM_ORD_GETTESTRESULT UINT32_C(84) +/** Get a capability. */ +#define TPM_ORD_GETCAPABILITY UINT32_C(101) +/** @} */ + + +/** @name TPM 2.0 command codes. + * @{ */ +/** Get a capability. */ +#define TPM2_CC_GET_CAPABILITY UINT32_C(378) +/** @} */ + + +/** @name Defines related to TPM_ORD_GETCAPABILITY. + * @{ */ +/** Return a TPM related property. */ +#define TPM_CAP_PROPERTY UINT32_C(5) + +/** Returns the size of the input buffer. */ +#define TPM_CAP_PROP_INPUT_BUFFER UINT32_C(0x124) + +/** + * TPM_ORD_GETCAPABILITY request. + */ +#pragma pack(1) +typedef struct TPMREQGETCAPABILITY +{ + /** Request header. */ + TPMREQHDR Hdr; + /** The capability group to query. */ + uint32_t u32Cap; + /** Length of the capability. */ + uint32_t u32Length; + /** The sub capability to query. */ + uint32_t u32SubCap; +} TPMREQGETCAPABILITY; +#pragma pack() +/** Pointer to a TPM_ORD_GETCAPABILITY request. */ +typedef TPMREQGETCAPABILITY *PTPMREQGETCAPABILITY; +/** Pointer to a const TPM_ORD_GETCAPABILITY request. */ +typedef const TPMREQGETCAPABILITY *PCTPMREQGETCAPABILITY; +/** @} */ + + +/** @name Defines related to TPM2_CC_GET_CAPABILITY. + * @{ */ +/** Return a TPM related property. */ +#define TPM2_CAP_TPM_PROPERTIES UINT32_C(6) + +/** Returns the size of the input buffer. */ +#define TPM2_PT_INPUT_BUFFER UINT32_C(0x10d) + +/** + * TPM2_CC_GET_CAPABILITY request. + */ +#pragma pack(1) +typedef struct TPM2REQGETCAPABILITY +{ + /** Request header. */ + TPMREQHDR Hdr; + /** The capability group to query. */ + uint32_t u32Cap; + /** Property to query. */ + uint32_t u32Property; + /** Number of values to return. */ + uint32_t u32Count; +} TPM2REQGETCAPABILITY; +#pragma pack() +/** Pointer to a TPM2_CC_GET_CAPABILITY request. */ +typedef TPM2REQGETCAPABILITY *PTPM2REQGETCAPABILITY; +/** Pointer to a const TPM2_CC_GET_CAPABILITY request. */ +typedef const TPM2REQGETCAPABILITY *PCTPM2REQGETCAPABILITY; +/** @} */ + + +/** + * TPM response header (everything big endian). + */ +#pragma pack(1) +typedef struct TPMRESPHDR +{ + /** The tag for this request. */ + uint16_t u16Tag; + /** Size of the response in bytes. */ + uint32_t cbResp; + /** The error code for the response. */ + uint32_t u32ErrCode; +} TPMRESPHDR; +#pragma pack() +AssertCompileSize(TPMRESPHDR, 2 + 4 + 4); +/** Pointer to a TPM response header. */ +typedef TPMRESPHDR *PTPMRESPHDR; +/** Pointer to a const TPM response header. */ +typedef const TPMRESPHDR *PCTPMRESPHDR; + + +/** @name TPM 1.2 response tags + * @{ */ +/** A response from a command with no authentication. */ +#define TPM_TAG_RSP_COMMAND UINT16_C(0x00c4) +/** An authenticated response with one authentication handle. */ +#define TPM_TAG_RSP_AUTH1_COMMAND UINT16_C(0x00c5) +/** An authenticated response with two authentication handles. */ +#define TPM_TAG_RSP_AUTH2_COMMAND UINT16_C(0x00c6) +/** @} */ + + +/** @name TPM status codes. + * @{ */ +#ifndef TPM_SUCCESS +/** Request executed successfully. */ +# define TPM_SUCCESS UINT32_C(0) +#endif +#ifndef TPM_AUTHFAIL +/** Authentication failed. */ +# define TPM_AUTHFAIL UINT32_C(1) +#endif +#ifndef TPM_BADINDEX +/** An index is malformed. */ +# define TPM_BADINDEX UINT32_C(2) +#endif +#ifndef TPM_BAD_PARAMETER +/** A request parameter is invalid. */ +# define TPM_BAD_PARAMETER UINT32_C(3) +#endif +#ifndef TPM_FAIL +/** The TPM failed to execute the request. */ +# define TPM_FAIL UINT32_C(9) +#endif +/** @todo Extend as need arises. */ +/** @} */ + + +/* Some inline helpers to account for the unaligned members of the request and response headers. */ + +/** + * Returns the request tag of the given TPM request header. + * + * @returns TPM request tag in bytes. + * @param pTpmReqHdr Pointer to the TPM request header. + */ +DECLINLINE(uint16_t) RTTpmReqGetTag(PCTPMREQHDR pTpmReqHdr) +{ + return RT_BE2H_U16(pTpmReqHdr->u16Tag); +} + + +/** + * Returns the request size of the given TPM request header. + * + * @returns TPM request size in bytes. + * @param pTpmReqHdr Pointer to the TPM request header. + */ +DECLINLINE(size_t) RTTpmReqGetSz(PCTPMREQHDR pTpmReqHdr) +{ + uint32_t cbReq; + memcpy(&cbReq, &pTpmReqHdr->cbReq, sizeof(pTpmReqHdr->cbReq)); + return RT_BE2H_U32(cbReq); +} + + +/** + * Returns the request ordinal of the given TPM request header. + * + * @returns TPM request ordinal in bytes. + * @param pTpmReqHdr Pointer to the TPM request header. + */ +DECLINLINE(uint32_t) RTTpmReqGetOrdinal(PCTPMREQHDR pTpmReqHdr) +{ + uint32_t u32Ordinal; + memcpy(&u32Ordinal, &pTpmReqHdr->u32Ordinal, sizeof(pTpmReqHdr->u32Ordinal)); + return RT_BE2H_U32(u32Ordinal); +} + + +/** + * Returns the response tag of the given TPM response header. + * + * @returns TPM request tag in bytes. + * @param pTpmRespHdr Pointer to the TPM response header. + */ +DECLINLINE(uint16_t) RTTpmRespGetTag(PCTPMRESPHDR pTpmRespHdr) +{ + return RT_BE2H_U16(pTpmRespHdr->u16Tag); +} + + +/** + * Returns the response size included in the given TPM response header. + * + * @returns TPM response size in bytes. + * @param pTpmRespHdr Pointer to the TPM response header. + */ +DECLINLINE(size_t) RTTpmRespGetSz(PCTPMRESPHDR pTpmRespHdr) +{ + uint32_t cbResp; + memcpy(&cbResp, &pTpmRespHdr->cbResp, sizeof(pTpmRespHdr->cbResp)); + return RT_BE2H_U32(cbResp); +} + + +/** + * Returns the error code of the given TPM response header. + * + * @returns TPM response error code. + * @param pTpmRespHdr Pointer to the TPM response header. + */ +DECLINLINE(uint32_t) RTTpmRespGetErrCode(PCTPMRESPHDR pTpmRespHdr) +{ + uint32_t u32ErrCode; + memcpy(&u32ErrCode, &pTpmRespHdr->u32ErrCode, sizeof(pTpmRespHdr->u32ErrCode)); + return RT_BE2H_U32(u32ErrCode); +} + +#endif /* !IPRT_INCLUDED_formats_tpm_h */ + diff --git a/include/iprt/formats/tracelog.h b/include/iprt/formats/tracelog.h new file mode 100644 index 00000000..8b20e925 --- /dev/null +++ b/include/iprt/formats/tracelog.h @@ -0,0 +1,239 @@ +/* $Id: tracelog.h $ */ +/** @file + * IPRT, Binary trace log format. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_tracelog_h +#define IPRT_INCLUDED_formats_tracelog_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assert.h> +#include <iprt/cdefs.h> +#include <iprt/types.h> + + +/** @defgroup grp_rt_formats_tracelog Binary trace log structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + +/** Size of the record magic in bytes. */ +#define TRACELOG_MAGIC_SZ 8 + +/** + * Trace log identification and options header. + */ +typedef struct TRACELOGHDR +{ + /** Identifiaction magic. */ + uint8_t szMagic[8]; + /** Endianess indicator. */ + uint32_t u32Endianess; + /** File version indicator. */ + uint32_t u32Version; + /** File flags (MBZ for now). */ + uint32_t fFlags; + /** Size of the trace log description in bytes following this header. */ + uint32_t cbStrDesc; + /** Size of a pointer item in bytes. */ + uint8_t cbTypePtr; + /** size of the size_t item in bytes. */ + uint8_t cbTypeSize; + /** Padding to an 4 byte boundary. */ + uint16_t u16Reserved0; + /** Padding to an 8 byte boundary. */ + uint32_t u32Reserved0; + /** Starting timestamp when the log was initialised. */ + uint64_t u64TsStart; + /** Padding to 64byte boundary, reserved for future use. */ + uint64_t au64Reserved[3]; +} TRACELOGHDR; +AssertCompileSize(TRACELOGHDR, 64); +/** Pointer to a trace log header. */ +typedef TRACELOGHDR *PTRACELOGHDR; +/** Pointer to a const trace log header. */ +typedef const TRACELOGHDR *PCTRACELOGHDR; + +/** Magic value for a trace log file (TRACELOG backwards). */ +#define TRACELOG_HDR_MAGIC "GOLECART" +/** Endianess indicator. */ +#define TRACELOG_HDR_ENDIANESS 0xdeadc0de +/** The default version (Higher 16bits major, low 16bits minor version). */ +#define TRACELOG_VERSION RT_MAKE_U32(1, 0) + + +/** + * Trace log event structure descriptor. + */ +typedef struct TRACELOGEVTDESC +{ + /** Event descriptor magic. */ + uint8_t szMagic[8]; + /** Event structure descriptor ID for identification in events later. */ + uint32_t u32Id; + /** Severity class of the event .*/ + uint32_t u32Severity; + /** Size of the identifier string in bytes without terminator. */ + uint32_t cbStrId; + /** Size of the description string in bytes without terminator. */ + uint32_t cbStrDesc; + /** Number of event items following. */ + uint32_t cEvtItems; + /** Padding to end the descriptor on a 32 byte boundary. */ + uint32_t au32Padding0; +} TRACELOGEVTDESC; +AssertCompileSize(TRACELOGEVTDESC, 32); +/** Pointer to a trace log event structure descriptor. */ +typedef TRACELOGEVTDESC *PTRACELOGEVTDESC; +/** Pointer to a const trace log event structure descriptor. */ +typedef const TRACELOGEVTDESC *PCTRACELOGEVTDESC; + +/** Event descriptor magic. */ +#define TRACELOG_EVTDESC_MAGIC "\0CSEDTVE" + +/** Severity: Informational event*/ +#define TRACELOG_EVTDESC_SEVERITY_INFO UINT32_C(0) +/** Severity: Warning event*/ +#define TRACELOG_EVTDESC_SEVERITY_WARNING UINT32_C(1) +/** Severity: Error event*/ +#define TRACELOG_EVTDESC_SEVERITY_ERROR UINT32_C(2) +/** Severity: Fatal event*/ +#define TRACELOG_EVTDESC_SEVERITY_FATAL UINT32_C(3) +/** Severity: Debug event*/ +#define TRACELOG_EVTDESC_SEVERITY_DEBUG UINT32_C(4) + + +/** + * Trace log event item descriptor. + */ +typedef struct TRACELOGEVTITEMDESC +{ + /** Event item descriptor magic. */ + uint8_t szMagic[8]; + /** Size of the item name string in bytes without terminator. */ + uint32_t cbStrName; + /** Size of the optional description string in bytes without terminator. */ + uint32_t cbStrDesc; + /** Item type */ + uint32_t u32Type; + /** Size of the raw data type if static throughout. */ + uint32_t cbRawData; + /** Padding to end the descriptor on a 32 byte boundary. */ + uint32_t au32Padding0[2]; +} TRACELOGEVTITEMDESC; +AssertCompileSize(TRACELOGEVTITEMDESC, 32); +/** Pointer to a trace log event item descriptor. */ +typedef TRACELOGEVTITEMDESC *PTRACELOGEVTITEMDESC; +/** Pointer to a const trace log event item descriptor. */ +typedef const TRACELOGEVTITEMDESC *PCTRACELOGEVTITEMDESC; + +/** Event item descriptor magic. */ +#define TRACELOG_EVTITEMDESC_MAGIC "CSEDMETI" +/** Boolean type. */ +#define TRACELOG_EVTITEMDESC_TYPE_BOOL UINT32_C(1) +/** Unsigned 8bit integer type. */ +#define TRACELOG_EVTITEMDESC_TYPE_UINT8 UINT32_C(2) +/** Signed 8bit integer type. */ +#define TRACELOG_EVTITEMDESC_TYPE_INT8 UINT32_C(3) +/** Unsigned 16bit integer type. */ +#define TRACELOG_EVTITEMDESC_TYPE_UINT16 UINT32_C(4) +/** Signed 16bit integer type. */ +#define TRACELOG_EVTITEMDESC_TYPE_INT16 UINT32_C(5) +/** Unsigned 32bit integer type. */ +#define TRACELOG_EVTITEMDESC_TYPE_UINT32 UINT32_C(6) +/** Signed 32bit integer type. */ +#define TRACELOG_EVTITEMDESC_TYPE_INT32 UINT32_C(7) +/** Unsigned 64bit integer type. */ +#define TRACELOG_EVTITEMDESC_TYPE_UINT64 UINT32_C(8) +/** Signed 64bit integer type. */ +#define TRACELOG_EVTITEMDESC_TYPE_INT64 UINT32_C(9) +/** 32bit floating point type. */ +#define TRACELOG_EVTITEMDESC_TYPE_FLOAT32 UINT32_C(10) +/** 64bit floating point type. */ +#define TRACELOG_EVTITEMDESC_TYPE_FLOAT64 UINT32_C(11) +/** Raw binary data type. */ +#define TRACELOG_EVTITEMDESC_TYPE_RAWDATA UINT32_C(12) +/** Pointer data type. */ +#define TRACELOG_EVTITEMDESC_TYPE_POINTER UINT32_C(13) +/** size_t data type. */ +#define TRACELOG_EVTITEMDESC_TYPE_SIZE UINT32_C(14) + +/** + * Trace log event marker. + */ +typedef struct TRACELOGEVT +{ + /** Event marker magic. */ + uint8_t szMagic[8]; + /** Trace log sequence number to identify the event uniquely. */ + uint64_t u64SeqNo; + /** Timestamp for the marker (resolution is infered from the header). */ + uint64_t u64Ts; + /** Event group ID for grouping different events together - for no grouped event. */ + uint64_t u64EvtGrpId; + /** Parent group ID this event originated from. */ + uint64_t u64EvtParentGrpId; + /** Overall number of bytes for the event data following including static and possibly variable data. */ + uint32_t cbEvtData; + /** Number of size_t sized raw data size indicators before the raw event data follows. */ + uint32_t cRawEvtDataSz; + /** Event flags. */ + uint32_t fFlags; + /** Event structure descriptor ID to use for structuring the event data. */ + uint32_t u32EvtDescId; + /** Reserved for future use. */ + uint64_t u64Reserved0; +} TRACELOGEVT; +AssertCompileSize(TRACELOGEVT, 64); +/** Pointer to a trace log event marker. */ +typedef TRACELOGEVT *PTRACELOGEVT; +/** Pointer to a const trace log event marker. */ +typedef const TRACELOGEVT *PCTRACELOGEVT; + +/** Event marker descriptor magic. */ +#define TRACELOG_EVT_MAGIC "\0RKRMTVE" +/** Flag indicating this is the start of an event group and all subsequent events + * with the same group ID belong to the same group. */ +#define TRACELOG_EVT_F_GRP_START RT_BIT_32(0) +/** Flag indicating this is the end of an event group which was started earlier. */ +#define TRACELOG_EVT_F_GRP_END RT_BIT_32(1) +/** Combination of valid flags. */ +#define TRACELOG_EVT_F_VALID (TRACELOG_EVT_F_GRP_START | TRACELOG_EVT_F_GRP_END) + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_tracelog_h */ + diff --git a/include/iprt/formats/udf.h b/include/iprt/formats/udf.h new file mode 100644 index 00000000..5081c11e --- /dev/null +++ b/include/iprt/formats/udf.h @@ -0,0 +1,2232 @@ +/* $Id: udf.h $ */ +/** @file + * IPRT, Universal Disk Format (UDF). + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_udf_h +#define IPRT_INCLUDED_formats_udf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> +#include <iprt/formats/iso9660.h> + + +/** @defgroup grp_rt_formats_udf Universal Disk Format (UDF) structures and definitions + * @ingroup grp_rt_formats + * + * References: + * - https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-167.pdf + * - http://www.osta.org/specs/pdf/udf260.pdf + * - http://wiki.osdev.org/UDF + * - https://sites.google.com/site/udfintro/ + * + * @{ + */ + +/** + * UDF d-character string (@ecma167{1,7.2.12,25}). + * + * This is mainly to mark what's d-strings and what's not. + */ +typedef char UDFDSTRING; +/** Pointer to an UDF dstring. */ +typedef UDFDSTRING *PUDFDSTRING; +/** Pointer to a const UDF dstring. */ +typedef UDFDSTRING const *PCUDFDSTRING; + +/** + * UDF extent allocation descriptor (AD) (@ecma167{3,7.1,42}). + */ +typedef struct UDFEXTENTAD +{ + /** Extent length in bytes. */ + uint32_t cb; + /** Extent offset (logical sector number). + * If @a cb is zero, this is also zero. */ + uint32_t off; +} UDFEXTENTAD; +AssertCompileSize(UDFEXTENTAD, 8); +/** Pointer to an UDF extent descriptor. */ +typedef UDFEXTENTAD *PUDFEXTENTAD; +/** Pointer to a const UDF extent descriptor. */ +typedef UDFEXTENTAD const *PCUDFEXTENTAD; + + +/** + * UDF logical block address (@ecma167{4,7.1,73}). + */ +#pragma pack(2) +typedef struct UDFLBADDR +{ + /** Logical block number, relative to the start of the given partition. */ + uint32_t off; + /** Partition reference number. */ + uint16_t uPartitionNo; +} UDFLBADDR; +#pragma pack() +AssertCompileSize(UDFLBADDR, 6); +/** Pointer to an UDF logical block address. */ +typedef UDFLBADDR *PUDFLBADDR; +/** Pointer to a const UDF logical block address. */ +typedef UDFLBADDR const *PCUDFLBADDR; + + +/** @name UDF_AD_TYPE_XXX - Allocation descriptor types. + * + * Used by UDFSHORTAD::uType, UDFLONGAD::uType and UDFEXTAD::uType. + * + * See @ecma167{4,14.14.1.1,116}. + * + * @{ */ +/** Recorded and allocated. + * Also used for zero length descriptors. */ +#define UDF_AD_TYPE_RECORDED_AND_ALLOCATED 0 +/** Allocated but not recorded. */ +#define UDF_AD_TYPE_ONLY_ALLOCATED 1 +/** Not recorded nor allocated. */ +#define UDF_AD_TYPE_FREE 2 +/** Go figure. */ +#define UDF_AD_TYPE_NEXT 3 +/** @} */ + +/** + * UDF short allocation descriptor (@ecma167{4,14.14.1,116}). + */ +typedef struct UDFSHORTAD +{ +#ifdef RT_BIG_ENDIAN + /** Extent type (UDF_AD_TYPE_XXX). */ + uint32_t uType : 2; + /** Extent length in bytes, top 2 bits . */ + uint32_t cb : 30; +#else + /** Extent length in bytes. */ + uint32_t cb : 30; + /** Extent type (UDF_AD_TYPE_XXX). */ + uint32_t uType : 2; +#endif + /** Extent offset (logical sector number). */ + uint32_t off; +} UDFSHORTAD; +AssertCompileSize(UDFSHORTAD, 8); +/** Pointer to an UDF short allocation descriptor. */ +typedef UDFSHORTAD *PUDFSHORTAD; +/** Pointer to a const UDF short allocation descriptor. */ +typedef UDFSHORTAD const *PCUDFSHORTAD; + +/** + * UDF long allocation descriptor (@ecma167{4,14.14.2,116}). + */ +#pragma pack(2) +typedef struct UDFLONGAD +{ +#ifdef RT_BIG_ENDIAN + /** Extent type (UDF_AD_TYPE_XXX). */ + uint32_t uType : 2; + /** Extent length in bytes, top 2 bits . */ + uint32_t cb : 30; +#else + /** Extent length in bytes. */ + uint32_t cb : 30; + /** Extent type (UDF_AD_TYPE_XXX). */ + uint32_t uType : 2; +#endif + /** Extent location. */ + UDFLBADDR Location; + /** Implementation use area. */ + union + { + /** Generic view. */ + uint8_t ab[6]; + /** Used in FIDs. + * See @udf260{2.3.10.1,66}, @udf260{2.3.4.3,58}. + */ + struct + { + /** Flags (UDF_AD_IMP_USE_FLAGS_XXX). */ + uint16_t fFlags; + /** Unique ID. */ + uint32_t idUnique; + } Fid; + } ImplementationUse; +} UDFLONGAD; +#pragma pack() +AssertCompileSize(UDFLONGAD, 16); +/** Pointer to an UDF long allocation descriptor. */ +typedef UDFLONGAD *PUDFLONGAD; +/** Pointer to a const UDF long allocation descriptor. */ +typedef UDFLONGAD const *PCUDFLONGAD; + +/** @name UDF_AD_IMP_USE_FLAGS_XXX - UDFLONGAD::ImplementationUse::Fid::fFlags values + * See @udf260{2.3.10.1,66}. + * @{ */ +/** Set if erased and the extend is of the type UDF_AD_TYPE_ONLY_ALLOCATED. */ +#define UDF_AD_IMP_USE_FLAGS_ERASED UINT16_C(0x0001) +/** Valid mask. */ +#define UDF_AD_IMP_USE_FLAGS_VALID_MASK UINT16_C(0x0001) +/** @} */ + +/** + * UDF extended allocation descriptor (@ecma167{4,14.14.3,117}). + */ +typedef struct UDFEXTAD +{ +#ifdef RT_BIG_ENDIAN + /** 0x00: Extent type (UDF_AD_TYPE_XXX). */ + uint32_t uType : 2; + /** 0x00: Extent length in bytes, top 2 bits . */ + uint32_t cb : 30; + /** 0x04: Reserved, MBZ. */ + uint32_t uReserved : 2; + /** 0x04: Number of bytes recorded. */ + uint32_t cbRecorded : 30; +#else + /** 0x00: Extent length in bytes. */ + uint32_t cb : 30; + /** 0x00: Extent type (UDF_AD_TYPE_XXX). */ + uint32_t uType : 2; + /** 0x04: Number of bytes recorded. */ + uint32_t cbRecorded : 30; + /** 0x04: Reserved, MBZ. */ + uint32_t uReserved : 2; +#endif + /** 0x08: Number of bytes of information (from first byte). */ + uint32_t cbInformation; + /** 0x0c: Extent location. */ + UDFLBADDR Location; + /** 0x12: Implementation use area. */ + uint8_t abImplementationUse[2]; +} UDFEXTAD; +AssertCompileSize(UDFEXTAD, 20); +/** Pointer to an UDF extended allocation descriptor. */ +typedef UDFEXTAD *PUDFEXTAD; +/** Pointer to a const UDF extended allocation descriptor. */ +typedef UDFEXTAD const *PCUDFEXTAD; + + +/** + * UDF timestamp (@ecma167{1,7.3,25}, @udf260{2.1.4,19}). + */ +typedef struct UDFTIMESTAMP +{ +#ifdef RT_BIG_ENDIAN + /** 0x00: Type (UDFTIMESTAMP_T_XXX). */ + RT_GCC_EXTENSION uint16_t fType : 4; + /** 0x00: Time zone offset in minutes. + * For EST this will be -300, whereas for CET it will be 60. */ + RT_GCC_EXTENSION int16_t offUtcInMin : 12; +#else + /** 0x00: Time zone offset in minutes. + * For EST this will be -300, whereas for CET it will be 60. */ + RT_GCC_EXTENSION int16_t offUtcInMin : 12; + /** 0x00: Type (UDFTIMESTAMP_T_XXX). */ + RT_GCC_EXTENSION uint16_t fType : 4; +#endif + /** 0x02: The year. */ + int16_t iYear; + /** 0x04: Month of year (1-12). */ + uint8_t uMonth; + /** 0x05: Day of month (1-31). */ + uint8_t uDay; + /** 0x06: Hour of day (0-23). */ + uint8_t uHour; + /** 0x07: Minute of hour (0-59). */ + uint8_t uMinute; + /** 0x08: Second of minute (0-60 if type 2, otherwise 0-59). */ + uint8_t uSecond; + /** 0x09: Number of Centiseconds (0-99). */ + uint8_t cCentiseconds; + /** 0x0a: Number of hundreds of microseconds (0-99). Unit is 100us. */ + uint8_t cHundredsOfMicroseconds; + /** 0x0b: Number of microseconds (0-99). */ + uint8_t cMicroseconds; +} UDFTIMESTAMP; +AssertCompileSize(UDFTIMESTAMP, 12); +/** Pointer to an UDF timestamp. */ +typedef UDFTIMESTAMP *PUDFTIMESTAMP; +/** Pointer to a const UDF timestamp. */ +typedef UDFTIMESTAMP const *PCUDFTIMESTAMP; + +/** @name UDFTIMESTAMP_T_XXX + * @{ */ +/** Local time. */ +#define UDFTIMESTAMP_T_LOCAL 1 +/** @} */ + +/** No time zone specified. */ +#define UDFTIMESTAMP_NO_TIME_ZONE (-2047) + + +/** + * UDF character set specficiation (@ecma167{1,7.2.1,21}, @udf260{2.1.2,18}). + */ +typedef struct UDFCHARSPEC +{ + /** The character set type (UDF_CHAR_SET_TYPE_XXX) */ + uint8_t uType; + /** Character set information. */ + uint8_t abInfo[63]; +} UDFCHARSPEC; +AssertCompileSize(UDFCHARSPEC, 64); +/** Pointer to UDF character set specification. */ +typedef UDFCHARSPEC *PUDFCHARSPEC; +/** Pointer to const UDF character set specification. */ +typedef UDFCHARSPEC const *PCUDFCHARSPEC; + +/** @name UDF_CHAR_SET_TYPE_XXX - Character set types. + * @{ */ +/** CS0: By agreement between the medium producer and consumer. + * See UDF_CHAR_SET_OSTA_COMPRESSED_UNICODE. */ +#define UDF_CHAR_SET_TYPE_BY_AGREEMENT UINT8_C(0x00) +/** CS1: ASCII (ECMA-6) with all or part of the specified graphic characters. */ +#define UDF_CHAR_SET_TYPE_ASCII UINT8_C(0x01) +/** CS5: Latin-1 (ECMA-94) with all graphical characters. */ +#define UDF_CHAR_SET_TYPE_LATIN_1 UINT8_C(0x05) +/* there are more defined here, but they are mostly useless, since UDF only uses CS0. */ + +/** The CS0 definition used by the UDF specification. */ +#define UDF_CHAR_SET_OSTA_COMPRESSED_UNICODE UDF_CHAR_SET_TYPE_BY_AGREEMENT +/** String to put in the UDFCHARSEPC::abInfo field for UDF CS0. */ +#define UDF_CHAR_SET_OSTA_COMPRESSED_UNICODE_INFO "OSTA Compressed Unicode" +/** @} */ + + +/** + * UDF entity identifier (@ecma167{1,7.4,26}, @udf260{2.1.5,20}). + */ +typedef struct UDFENTITYID +{ + /** 0x00: Flags (UDFENTITYID_FLAGS_XXX). */ + uint8_t fFlags; + /** 0x01: Identifier string (see UDF_ENTITY_ID_XXX). */ + char achIdentifier[23]; + /** 0x18: Identifier suffix. */ + union + { + /** Domain ID suffix. */ + struct + { + uint16_t uUdfRevision; + uint8_t fDomain; + uint8_t abReserved[5]; + } Domain; + + /** UDF ID suffix. */ + struct + { + uint16_t uUdfRevision; + uint8_t bOsClass; + uint8_t idOS; + uint8_t abReserved[4]; + } Udf; + + + /** Implementation ID suffix. */ + struct + { + uint8_t bOsClass; + uint8_t idOS; + uint8_t achImplUse[6]; + } Implementation; + + /** Application ID suffix / generic. */ + uint8_t abApplication[8]; + } Suffix; +} UDFENTITYID; +AssertCompileSize(UDFENTITYID, 32); +/** Pointer to UDF entity identifier. */ +typedef UDFENTITYID *PUDFENTITYID; +/** Pointer to const UDF entity identifier. */ +typedef UDFENTITYID const *PCUDFENTITYID; + +/** @name UDF_ENTITY_ID_XXX - UDF identifier strings + * + * See @udf260{2.1.5.2,21}. + * + * @{ */ +/** Implementation use volume descriptor, implementation ID field. + * UDF ID suffix. */ +#define UDF_ENTITY_ID_IUVD_IMPLEMENTATION "*UDF LV Info" + +/** Partition descriptor, partition contents field, set to indicate UDF + * (ECMA-167 3rd edition). Application ID suffix. */ +#define UDF_ENTITY_ID_PD_PARTITION_CONTENTS_UDF "+NSR03" +/** Partition descriptor, partition contents field, set to indicate ISO-9660 + * (ECMA-119). Application ID suffix. */ +#define UDF_ENTITY_ID_PD_PARTITION_CONTENTS_ISO9660 "+CD001" +/** Partition descriptor, partition contents field, set to indicate ECMA-168. + * Application ID suffix. */ +#define UDF_ENTITY_ID_PD_PARTITION_CONTENTS_CDW "+CDW02" +/** Partition descriptor, partition contents field, set to indicate FAT + * (ECMA-107). Application ID suffix. */ +#define UDF_ENTITY_ID_PD_PARTITION_CONTENTS_FAT "+FDC01" + +/** Logical volume descriptor, domain ID field. + * Domain ID suffix. */ +#define UDF_ENTITY_ID_LVD_DOMAIN "*OSTA UDF Compliant" + +/** File set descriptor, domain ID field. + * Domain ID suffix. */ +#define UDF_ENTITY_FSD_LVD_DOMAIN "*OSTA UDF Compliant" + +/** UDF implementation use extended attribute, implementation ID field, set + * to free EA space. UDF ID suffix. */ +#define UDF_ENTITY_ID_IUEA_FREE_EA_SPACE "*UDF FreeEASpace" +/** UDF implementation use extended attribute, implementation ID field, set + * to DVD copyright management information. UDF ID suffix. */ +#define UDF_ENTITY_ID_IUEA_DVD_CGMS_INFO "*UDF DVD CGMS Info" +/** UDF implementation use extended attribute, implementation ID field, set + * to OS/2 extended attribute length. UDF ID suffix. */ +#define UDF_ENTITY_ID_IUEA_OS2_EA_LENGTH "*UDF OS/2 EALength" +/** UDF implementation use extended attribute, implementation ID field, set + * to Machintosh OS volume information. UDF ID suffix. */ +#define UDF_ENTITY_ID_IUEA_MAC_VOLUME_INFO "*UDF Mac VolumeInfo" +/** UDF implementation use extended attribute, implementation ID field, set + * to Machintosh Finder Info. UDF ID suffix. */ +#define UDF_ENTITY_ID_IUEA_MAC_FINDER_INFO "*UDF Mac FinderInfo" +/** UDF implementation use extended attribute, implementation ID field, set + * to OS/400 extended directory information. UDF ID suffix. */ +#define UDF_ENTITY_ID_IUEA_OS400_DIR_INFO "*UDF OS/400 DirInfo" + +/** UDF application use extended attribute, application ID field, set + * to free application use EA space. UDF ID suffix. */ +#define UDF_ENTITY_ID_AUEA_FREE_EA_SPACE "*UDF FreeAppEASpace" + +/** Virtual partition map, partition type field. + * UDF ID suffix. */ +#define UDF_ENTITY_ID_VPM_PARTITION_TYPE "*UDF Virtual Partition" + +/** Sparable partition map, partition type field. + * UDF ID suffix. */ +#define UDF_ENTITY_ID_SPM_PARTITION_TYPE "*UDF Sparable Partition" + +/** Metadata partition map, partition type field. + * UDF ID suffix. */ +#define UDF_ENTITY_ID_MPM_PARTITION_TYPE "*UDF Metadata Partition" + +/** Sparing table, sparing identifier field. + * UDF ID suffix. */ +#define UDF_ENTITY_ID_ST_SPARING "*UDF Sparting Table" + +/** @} */ + + +/** + * UDF descriptor tag (@ecma167{3,7.2,42}, @udf260{2.2.1,26}). + */ +typedef struct UDFTAG +{ + /** Tag identifier (UDF_TAG_ID_XXX). */ + uint16_t idTag; + /** Descriptor version. */ + uint16_t uVersion; + /** Tag checksum. + * Sum of each byte in the structure with this field as zero. */ + uint8_t uChecksum; + /** Reserved, MBZ. */ + uint8_t bReserved; + /** Tag serial number. */ + uint16_t uTagSerialNo; + /** Descriptor CRC. */ + uint16_t uDescriptorCrc; + /** Descriptor CRC length. */ + uint16_t cbDescriptorCrc; + /** The tag location (logical sector number). */ + uint32_t offTag; +} UDFTAG; +AssertCompileSize(UDFTAG, 16); +/** Pointer to an UDF descriptor tag. */ +typedef UDFTAG *PUDFTAG; +/** Pointer to a const UDF descriptor tag. */ +typedef UDFTAG const *PCUDFTAG; + +/** @name UDF_TAG_ID_XXX - UDF descriptor tag IDs. + * @{ */ +#define UDF_TAG_ID_PRIMARY_VOL_DESC UINT16_C(0x0001) /**< See UDFPRIMARYVOLUMEDESC */ +#define UDF_TAG_ID_ANCHOR_VOLUME_DESC_PTR UINT16_C(0x0002) /**< See UDFANCHORVOLUMEDESCPTR */ +#define UDF_TAG_ID_VOLUME_DESC_PTR UINT16_C(0x0003) /**< See UDFVOLUMEDESCPTR */ +#define UDF_TAG_ID_IMPLEMENTATION_USE_VOLUME_DESC UINT16_C(0x0004) /**< See UDFIMPLEMENTATIONUSEVOLUMEDESC */ +#define UDF_TAG_ID_PARTITION_DESC UINT16_C(0x0005) /**< See UDFPARTITIONDESC */ +#define UDF_TAG_ID_LOGICAL_VOLUME_DESC UINT16_C(0x0006) /**< See UDFLOGICALVOLUMEDESC */ +#define UDF_TAG_ID_UNALLOCATED_SPACE_DESC UINT16_C(0x0007) /**< See UDFUNALLOCATEDSPACEDESC */ +#define UDF_TAG_ID_TERMINATING_DESC UINT16_C(0x0008) /**< See UDFTERMINATINGDESC */ +#define UDF_TAG_ID_LOGICAL_VOLUME_INTEGRITY_DESC UINT16_C(0x0009) /**< See UDFLOGICALVOLINTEGRITYDESC */ +#define UDF_TAG_ID_FILE_SET_DESC UINT16_C(0x0100) /**< See UDFFILESETDESC */ +#define UDF_TAG_ID_FILE_ID_DESC UINT16_C(0x0101) /**< See UDFFILEIDDESC */ +#define UDF_TAG_ID_ALLOCATION_EXTENT_DESC UINT16_C(0x0102) /**< See UDFALLOCATIONEXTENTDESC */ +#define UDF_TAG_ID_INDIRECT_ENTRY UINT16_C(0x0103) /**< See UDFINDIRECTENTRY */ +#define UDF_TAG_ID_TERMINAL_ENTRY UINT16_C(0x0104) /**< See UDFTERMINALENTRY */ +#define UDF_TAG_ID_FILE_ENTRY UINT16_C(0x0105) /**< See UDFFILEENTRY */ +#define UDF_TAG_ID_EXTENDED_ATTRIB_HDR_DESC UINT16_C(0x0106) /**< See UDFEXTATTRIBHDRDESC */ +#define UDF_TAG_ID_UNALLOCATED_SPACE_ENTRY UINT16_C(0x0107) /**< See UDFUNALLOCATEDSPACEENTRY */ +#define UDF_TAG_ID_SPACE_BITMAP_DESC UINT16_C(0x0108) /**< See UDFSPACEBITMAPDESC */ +#define UDF_TAG_ID_PARTITION_INTEGERITY_DESC UINT16_C(0x0109) /**< See UDFPARTITIONINTEGRITYDESC */ +#define UDF_TAG_ID_EXTENDED_FILE_ENTRY UINT16_C(0x010a) /**< See UDFEXFILEENTRY */ +/** @} */ + + +/** + * UDF primary volume descriptor (PVD) (@ecma167{3,10.1,50}, + * @udf260{2.2.2,27}). + */ +typedef struct UDFPRIMARYVOLUMEDESC +{ + /** 0x000: The descriptor tag (UDF_TAG_ID_PRIMARY_VOL_DESC). */ + UDFTAG Tag; + /** 0x010: Volume descriptor sequence number. */ + uint32_t uVolumeDescSeqNo; + /** 0x014: Primary volume descriptor number. */ + uint32_t uPrimaryVolumeDescNo; + /** 0x018: Volume identifier (dstring). */ + UDFDSTRING achVolumeID[32]; + /** 0x038: Volume sequence number. */ + uint16_t uVolumeSeqNo; + /** 0x03a: Maximum volume sequence number. */ + uint16_t uMaxVolumeSeqNo; + /** 0x03c: Interchange level. */ + uint16_t uInterchangeLevel; + /** 0x03e: Maximum interchange level. */ + uint16_t uMaxInterchangeLevel; + /** 0x040: Character set bitmask (aka list). Each bit correspond to a + * character set number. */ + uint32_t fCharacterSets; + /** 0x044: Maximum character set bitmask (aka list). */ + uint32_t fMaxCharacterSets; + /** 0x048: Volume set identifier (dstring). This starts with 16 unique + * characters, the first 8 being the hex representation of a time value. */ + UDFDSTRING achVolumeSetID[128]; + /** 0x0c8: Descriptor character set. + * For achVolumeSetID and achVolumeID. */ + UDFCHARSPEC DescCharSet; + /** 0x108: Explanatory character set. + * For VolumeAbstract and VolumeCopyrightNotice data. */ + UDFCHARSPEC ExplanatoryCharSet; + /** 0x148: Volume abstract. */ + UDFEXTENTAD VolumeAbstract; + /** 0x150: Volume copyright notice. */ + UDFEXTENTAD VolumeCopyrightNotice; + /** 0x158: Application identifier ("*Application ID"). */ + UDFENTITYID idApplication; + /** 0x178: Recording date and time. */ + UDFTIMESTAMP RecordingTimestamp; + /** 0x184: Implementation identifier ("*Developer ID"). */ + UDFENTITYID idImplementation; + /** 0x1a4: Implementation use. */ + uint8_t abImplementationUse[64]; + /** 0x1e4: Predecessor volume descriptor sequence location. */ + uint32_t offPredecessorVolDescSeq; + /** 0x1e8: Flags (UDF_PVD_FLAGS_XXX). */ + uint16_t fFlags; + /** 0x1ea: Reserved. */ + uint8_t abReserved[22]; +} UDFPRIMARYVOLUMEDESC; +AssertCompileSize(UDFPRIMARYVOLUMEDESC, 512); +/** Pointer to a UDF primary volume descriptor. */ +typedef UDFPRIMARYVOLUMEDESC *PUDFPRIMARYVOLUMEDESC; +/** Pointer to a const UDF primary volume descriptor. */ +typedef UDFPRIMARYVOLUMEDESC const *PCUDFPRIMARYVOLUMEDESC; + +/** @name UDF_PVD_FLAGS_XXX - Flags for UDFPRIMARYVOLUMEDESC::fFlags. + * @{ */ +/** Indicates that the volume set ID is common to all members of the set. */ +#define UDF_PVD_FLAGS_COMMON_VOLUME_SET_ID UINT16_C(0x0001) +/** @} */ + + +/** + * UDF anchor volume descriptor pointer (AVDP) (@ecma167{3,10.2,53}, + * @udf260{2.2.3,29}). + * + * This is stored at least two of these locations: + * - logical sector 256 + * - logical sector N - 256. + * - logical sector N. + */ +typedef struct UDFANCHORVOLUMEDESCPTR +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_ANCHOR_VOLUME_DESC_PTR). */ + UDFTAG Tag; + /** 0x10: The extent descripting the main volume descriptor sequence. */ + UDFEXTENTAD MainVolumeDescSeq; + /** 0x18: Location of the backup descriptor sequence. */ + UDFEXTENTAD ReserveVolumeDescSeq; + /** 0x20: Reserved, probably must be zeros. */ + uint8_t abReserved[0x1e0]; +} UDFANCHORVOLUMEDESCPTR; +AssertCompileSize(UDFANCHORVOLUMEDESCPTR, 512); +/** Pointer to UDF anchor volume descriptor pointer. */ +typedef UDFANCHORVOLUMEDESCPTR *PUDFANCHORVOLUMEDESCPTR; +/** Pointer to const UDF anchor volume descriptor pointer. */ +typedef UDFANCHORVOLUMEDESCPTR const *PCUDFANCHORVOLUMEDESCPTR; + + +/** + * UDF volume descriptor pointer (VDP) (@ecma167{3,10.3,53}). + */ +typedef struct UDFVOLUMEDESCPTR +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_VOLUME_DESC_PTR). */ + UDFTAG Tag; + /** 0x10: Volume descriptor sequence number. */ + uint32_t uVolumeDescSeqNo; + /** 0x14: Location of the next volume descriptor sequence. */ + UDFEXTENTAD NextVolumeDescSeq; + /** 0x1c: Reserved, probably must be zeros. */ + uint8_t abReserved[484]; +} UDFVOLUMEDESCPTR; +AssertCompileSize(UDFVOLUMEDESCPTR, 512); +/** Pointer to UDF volume descriptor pointer. */ +typedef UDFVOLUMEDESCPTR *PUDFVOLUMEDESCPTR; +/** Pointer to const UDF volume descriptor pointer. */ +typedef UDFVOLUMEDESCPTR const *PCUDFVOLUMEDESCPTR; + + +/** + * UDF implementation use volume descriptor (IUVD) (@ecma167{3,10.4,55}, + * @udf260{2.2.7,35}). + */ +typedef struct UDFIMPLEMENTATIONUSEVOLUMEDESC +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_IMPLEMENTATION_USE_VOLUME_DESC). */ + UDFTAG Tag; + /** 0x10: Volume descriptor sequence number. */ + uint32_t uVolumeDescSeqNo; + /** 0x14: The implementation identifier (UDF_ENTITY_ID_IUVD_IMPLEMENTATION). */ + UDFENTITYID idImplementation; + /** 0x34: The implementation use area. */ + union + { + /** Generic view. */ + uint8_t ab[460]; + /** Logical volume information (@udf260{2.2.7.2,35}). */ + struct + { + /** 0x034: The character set used in this sub-structure. */ + UDFCHARSPEC Charset; + /** 0x074: Logical volume identifier. */ + UDFDSTRING achVolumeID[128]; + /** 0x0f4: Info string \#1. */ + UDFDSTRING achInfo1[36]; + /** 0x118: Info string \#2. */ + UDFDSTRING achInfo2[36]; + /** 0x13c: Info string \#3. */ + UDFDSTRING achInfo3[36]; + /** 0x160: The implementation identifier ("*Developer ID"). */ + UDFENTITYID idImplementation; + /** 0x180: Additional use bytes. */ + uint8_t abUse[128]; + } Lvi; + } ImplementationUse; +} UDFIMPLEMENTATIONUSEVOLUMEDESC; +AssertCompileSize(UDFIMPLEMENTATIONUSEVOLUMEDESC, 512); +AssertCompileMemberOffset(UDFIMPLEMENTATIONUSEVOLUMEDESC, ImplementationUse.Lvi.Charset, 0x034); +AssertCompileMemberOffset(UDFIMPLEMENTATIONUSEVOLUMEDESC, ImplementationUse.Lvi.achVolumeID, 0x074); +AssertCompileMemberOffset(UDFIMPLEMENTATIONUSEVOLUMEDESC, ImplementationUse.Lvi.achInfo1, 0x0f4); +AssertCompileMemberOffset(UDFIMPLEMENTATIONUSEVOLUMEDESC, ImplementationUse.Lvi.achInfo2, 0x118); +AssertCompileMemberOffset(UDFIMPLEMENTATIONUSEVOLUMEDESC, ImplementationUse.Lvi.achInfo3, 0x13c); +AssertCompileMemberOffset(UDFIMPLEMENTATIONUSEVOLUMEDESC, ImplementationUse.Lvi.idImplementation, 0x160); +/** Pointer to an UDF implementation use volume descriptor. */ +typedef UDFIMPLEMENTATIONUSEVOLUMEDESC *PUDFIMPLEMENTATIONUSEVOLUMEDESC; +/** Pointer to a const UDF implementation use volume descriptor. */ +typedef UDFIMPLEMENTATIONUSEVOLUMEDESC const *PCUDFIMPLEMENTATIONUSEVOLUMEDESC; + + +/** + * UDF partition header descriptor (@ecma167{4,14.3,90}, @udf260{2.3.3,56}). + * + * This is found in UDFPARTITIONDESC::ContentsUse. + */ +typedef struct UDFPARTITIONHDRDESC +{ + /** 0x00: Unallocated space table location. Zero length means no table. */ + UDFSHORTAD UnallocatedSpaceTable; + /** 0x08: Unallocated space bitmap location. Zero length means no bitmap. */ + UDFSHORTAD UnallocatedSpaceBitmap; + /** 0x10: Partition integrity table location. Zero length means no table. */ + UDFSHORTAD PartitionIntegrityTable; + /** 0x18: Freed space table location. Zero length means no table. */ + UDFSHORTAD FreedSpaceTable; + /** 0x20: Freed space bitmap location. Zero length means no bitmap. */ + UDFSHORTAD FreedSpaceBitmap; + /** 0x28: Reserved, MBZ. */ + uint8_t abReserved[88]; +} UDFPARTITIONHDRDESC; +AssertCompileSize(UDFPARTITIONHDRDESC, 128); +AssertCompileMemberOffset(UDFPARTITIONHDRDESC, PartitionIntegrityTable, 0x10); +AssertCompileMemberOffset(UDFPARTITIONHDRDESC, abReserved, 0x28); +/** Pointer to an UDF partition header descriptor. */ +typedef UDFPARTITIONHDRDESC *PUDFPARTITIONHDRDESC; +/** Pointer to a const UDF partition header descriptor. */ +typedef UDFPARTITIONHDRDESC const *PCUDFPARTITIONHDRDESC; + + +/** + * UDF partition descriptor (PD) (@ecma167{3,10.5,55}, @udf260{2.2.14,51}). + */ +typedef struct UDFPARTITIONDESC +{ + /** 0x000: The descriptor tag (UDF_TAG_ID_PARTITION_DESC). */ + UDFTAG Tag; + /** 0x010: Volume descriptor sequence number. */ + uint32_t uVolumeDescSeqNo; + /** 0x014: The partition flags (UDF_PARTITION_FLAGS_XXX). */ + uint16_t fFlags; + /** 0x016: The partition number. */ + uint16_t uPartitionNo; + /** 0x018: Partition contents (UDF_ENTITY_ID_PD_PARTITION_CONTENTS_XXX). */ + UDFENTITYID PartitionContents; + /** 0x038: partition contents use (depends on the PartitionContents field). */ + union + { + /** Generic view. */ + uint8_t ab[128]; + /** UDF partition header descriptor (UDF_ENTITY_ID_PD_PARTITION_CONTENTS_UDF). */ + UDFPARTITIONHDRDESC Hdr; + } ContentsUse; + /** 0x0b8: Access type (UDF_PART_ACCESS_TYPE_XXX). */ + uint32_t uAccessType; + /** 0x0bc: Partition starting location (logical sector number). */ + uint32_t offLocation; + /** 0x0c0: Partition length in sectors. */ + uint32_t cSectors; + /** 0x0c4: Implementation identifier ("*Developer ID"). */ + UDFENTITYID idImplementation; + /** 0x0e4: Implementation use bytes. */ + union + { + /** Generic view. */ + uint8_t ab[128]; + } ImplementationUse; + /** 0x164: Reserved. */ + uint8_t abReserved[156]; +} UDFPARTITIONDESC; +AssertCompileSize(UDFPARTITIONDESC, 512); +/** Pointer to an UDF partitions descriptor. */ +typedef UDFPARTITIONDESC *PUDFPARTITIONDESC; +/** Pointer to a const UDF partitions descriptor. */ +typedef const UDFPARTITIONDESC *PCUDFPARTITIONDESC; + +/** @name UDF_PART_ACCESS_TYPE_XXX - UDF partition access types + * + * See @ecma167{3,10.5.7,57}, @udf260{2.2.14.2,51}. + * + * @{ */ +/** Access not specified by this field. */ +#define UDF_PART_ACCESS_TYPE_NOT_SPECIFIED UINT32_C(0x00000000) +/** Read only: No writes. */ +#define UDF_PART_ACCESS_TYPE_READ_ONLY UINT32_C(0x00000001) +/** Write once: Sectors can only be written once. */ +#define UDF_PART_ACCESS_TYPE_WRITE_ONCE UINT32_C(0x00000002) +/** Rewritable: Logical sectors may require preprocessing before writing. */ +#define UDF_PART_ACCESS_TYPE_REWRITABLE UINT32_C(0x00000003) +/** Overwritable: No restrictions on writing. */ +#define UDF_PART_ACCESS_TYPE_OVERWRITABLE UINT32_C(0x00000004) +/** @} */ + + +/** + * Logical volume descriptor (LVD) (@ecma167{3,10.6,58}, @udf260{2.2.4,30}). + * + * @note Variable length. + */ +typedef struct UDFLOGICALVOLUMEDESC +{ + /** 0x000: The descriptor tag (UDF_TAG_ID_LOGICAL_VOLUME_DESC). */ + UDFTAG Tag; + /** 0x010: Volume descriptor sequence number. */ + uint32_t uVolumeDescSeqNo; + /** 0x014: Character set used in the achLogicalVolumeID field. */ + UDFCHARSPEC DescCharSet; + /** 0x054: The logical volume ID (label). */ + UDFDSTRING achLogicalVolumeID[128]; + /** 0x0d4: Logical block size (in bytes). */ + uint32_t cbLogicalBlock; + /** 0x0d8: Domain identifier (UDF_ENTITY_ID_LVD_DOMAIN). */ + UDFENTITYID idDomain; + /** 0x0f8: Logical volume contents use. */ + union + { + /** Byte view. */ + uint8_t ab[16]; + /** The extent containing the file set descriptor. */ + UDFLONGAD FileSetDescriptor; + } ContentsUse; + /** 0x108: Map table length (in bytes). */ + uint32_t cbMapTable; + /** 0x10c: Number of partition maps. */ + uint32_t cPartitionMaps; + /** 0x110: Implementation identifier ("*Developer ID"). */ + UDFENTITYID idImplementation; + /** 0x130: Implementation use. */ + union + { + /** Byte view. */ + uint8_t ab[128]; + } ImplementationUse; + /** 0x1b0: Integrity sequence extent. Can be zero if cPartitionMaps is zero. */ + UDFEXTENTAD IntegritySeqExtent; + /** 0x1b8: Partition maps (length given by @a cbMapTable), data format is + * defined by UDFPARTMAPHDR, UDFPARTMAPTYPE1 and UDFPARTMAPTYPE2. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abPartitionMaps[RT_FLEXIBLE_ARRAY]; +} UDFLOGICALVOLUMEDESC; +AssertCompileMemberOffset(UDFLOGICALVOLUMEDESC, abPartitionMaps, 0x1b8); +/** Pointer to an UDF logical volume descriptor. */ +typedef UDFLOGICALVOLUMEDESC *PUDFLOGICALVOLUMEDESC; +/** Pointer to a const UDF logical volume descriptor. */ +typedef UDFLOGICALVOLUMEDESC const *PCUDFLOGICALVOLUMEDESC; + +/** + * Partition map header (UDFLOGICALVOLUMEDESC::abPartitionMaps). + */ +typedef struct UDFPARTMAPHDR +{ + /** 0x00: The partition map type. */ + uint8_t bType; + /** 0x01: The partition map length (header included). */ + uint8_t cb; +} UDFPARTMAPHDR; +AssertCompileSize(UDFPARTMAPHDR, 2); +/** Pointer to a partition map header. */ +typedef UDFPARTMAPHDR *PUDFPARTMAPHDR; +/** Pointer to a const partition map header. */ +typedef UDFPARTMAPHDR const *PCUDFPARTMAPHDR; + +/** + * Partition map type 1 (UDFLOGICALVOLUMEDESC::abPartitionMaps). + */ +typedef struct UDFPARTMAPTYPE1 +{ + /** 0x00: Header (uType=1, cb=6). */ + UDFPARTMAPHDR Hdr; + /** 0x02: Volume sequence number. */ + uint16_t uVolumeSeqNo; + /** 0x04: Partition number. */ + uint16_t uPartitionNo; +} UDFPARTMAPTYPE1; +AssertCompileSize(UDFPARTMAPTYPE1, 6); +/** Pointer to a type 1 partition map. */ +typedef UDFPARTMAPTYPE1 *PUDFPARTMAPTYPE1; +/** Pointer to a const type 1 partition map. */ +typedef UDFPARTMAPTYPE1 const *PCUDFPARTMAPTYPE1; + +/** + * Partition map type 2 (UDFLOGICALVOLUMEDESC::abPartitionMaps). + */ +typedef struct UDFPARTMAPTYPE2 +{ + /** 0x00: Header (uType=2, cb=64). */ + UDFPARTMAPHDR Hdr; + /** 0x02: Reserved \#1. */ + uint16_t uReserved1; + /** 0x04: Partition ID type (UDF_ENTITY_ID_VPM_PARTITION_TYPE, + * UDF_ENTITY_ID_SPM_PARTITION_TYPE, or UDF_ENTITY_ID_MPM_PARTITION_TYPE). */ + UDFENTITYID idPartitionType; + /** 0x24: Volume sequence number. */ + uint16_t uVolumeSeqNo; + /** 0x26: Partition number. */ + uint16_t uPartitionNo; + /** 0x28: Data specific to the partition ID type. */ + union + { + /** 0x28: Generic view. */ + uint8_t ab[24]; + + /** UDF_ENTITY_ID_VPM_PARTITION_TYPE. */ + struct + { + /** 0x28: Reserved. */ + uint8_t abReserved2[24]; + } Vpm; + + /** UDF_ENTITY_ID_SPM_PARTITION_TYPE. */ + struct + { + /** 0x28: Packet length in blocks. */ + uint16_t cBlocksPerPacket; + /** 0x2a: Number of sparing tables. */ + uint8_t cSparingTables; + /** 0x2b: Reserved padding byte. */ + uint8_t bReserved2; + /** 0x2c: The size of each sparing table. */ + uint32_t cbSparingTable; + /** 0x30: The sparing table locations (logical block). */ + uint32_t aoffSparingTables[4]; + } Spm; + + /** UDF_ENTITY_ID_MPM_PARTITION_TYPE. */ + struct + { + /** 0x28: Metadata file entry location (logical block). */ + uint32_t offMetadataFile; + /** 0x2c: Metadata mirror file entry location (logical block). */ + uint32_t offMetadataMirrorFile; + /** 0x30: Metadata bitmap file entry location (logical block). */ + uint32_t offMetadataBitmapFile; + /** 0x34: The metadata allocation unit (logical blocks) */ + uint32_t cBlocksAllocationUnit; + /** 0x38: The metadata allocation unit alignment (logical blocks). */ + uint16_t cBlocksAlignmentUnit; + /** 0x3a: Flags, UDFPARTMAPMETADATA_F_XXX. */ + uint8_t fFlags; + /** 0x3b: Reserved. */ + uint8_t abReserved2[5]; + } Mpm; + } u; +} UDFPARTMAPTYPE2; +AssertCompileSize(UDFPARTMAPTYPE2, 64); +/** Pointer to a type 2 partition map. */ +typedef UDFPARTMAPTYPE2 *PUDFPARTMAPTYPE2; +/** Pointer to a const type 2 partition map. */ +typedef UDFPARTMAPTYPE2 const *PCUDFPARTMAPTYPE2; + +/** @name UDFPARTMAPMETADATA_F_XXX + * @{ */ +/** Indicates that the metadata is mirrored too, not just the file entry. */ +#define UDFPARTMAPMETADATA_F_DATA_MIRRORED UINT8_C(1) +/** @} */ + + +/** + * UDF unallocated space descriptor (USD) (@ecma167{3,10.8,61}, @udf260{2.2.5,32}). + * + * @note Variable length. + */ +typedef struct UDFUNALLOCATEDSPACEDESC +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_UNALLOCATED_SPACE_DESC). */ + UDFTAG Tag; + /** 0x10: Volume descriptor sequence number. */ + uint32_t uVolumeDescSeqNo; + /** 0x14: Number of allocation descriptors in the array below. */ + uint32_t cAllocationDescriptors; + /** 0x18: Allocation descriptors (variable length). */ + RT_FLEXIBLE_ARRAY_EXTENSION + UDFEXTENTAD aAllocationDescriptors[RT_FLEXIBLE_ARRAY]; +} UDFUNALLOCATEDSPACEDESC; +AssertCompileMemberOffset(UDFUNALLOCATEDSPACEDESC, aAllocationDescriptors, 0x18); +/** Pointer to an UDF unallocated space descriptor. */ +typedef UDFUNALLOCATEDSPACEDESC *PUDFUNALLOCATEDSPACEDESC; +/** Pointer to a const UDF unallocated space descriptor. */ +typedef UDFUNALLOCATEDSPACEDESC const *PCUDFUNALLOCATEDSPACEDESC; + + +/** + * UDF terminating descriptor (@ecma167{3,10.9,62}, @ecma167{4,14.2,62}). + */ +typedef struct UDFTERMINATINGDESC +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_TERMINATING_DESC). */ + UDFTAG Tag; + /** 0x10: Reserved, MBZ. */ + uint8_t abReserved[496]; +} UDFTERMINATINGDESC; +/** Pointer to an UDF terminating descriptor. */ +typedef UDFTERMINATINGDESC *PUDFTERMINATINGDESC; +/** Pointer to a const UDF terminating descriptor. */ +typedef UDFTERMINATINGDESC const *PCUDFTERMINATINGDESC; + + +/** + * UDF logical volume integrity descriptor (LVID) (@ecma167{3,10.10,62}, + * @udf260{2.2.6,32}). + */ +typedef struct UDFLOGICALVOLINTEGRITYDESC +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_TERMINATING_DESC). */ + UDFTAG Tag; + /** 0x10: Recording timestamp. */ + UDFTIMESTAMP RecordingTimestamp; + /** 0x1c: Integrity type (UDF_LVID_TYPE_XXX). */ + uint32_t uIntegrityType; + /** 0x20: The next integrity extent. */ + UDFEXTENTAD NextIntegrityExtent; + /** 0x28: Number of partitions. */ + uint32_t cPartitions; + /** 0x2c: Length of implementation use. */ + uint32_t cbImplementationUse; + /** + * There are two tables each @a cPartitions in size. The first is the free + * space table. The second the size table. + * + * Following these tables there are @a cbImplementationUse bytes of space for + * the implementation to use. + */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint32_t aTables[RT_FLEXIBLE_ARRAY]; +} UDFLOGICALVOLINTEGRITYDESC; +AssertCompileMemberOffset(UDFLOGICALVOLINTEGRITYDESC, cbImplementationUse, 0x2c); +AssertCompileMemberOffset(UDFLOGICALVOLINTEGRITYDESC, aTables, 0x30); +/** Pointer to an UDF logical volume integrity descriptor. */ +typedef UDFLOGICALVOLINTEGRITYDESC *PUDFLOGICALVOLINTEGRITYDESC; +/** Pointer to a const UDF logical volume integrity descriptor. */ +typedef UDFLOGICALVOLINTEGRITYDESC const *PCUDFLOGICALVOLINTEGRITYDESC; + +/** @name UDF_LVID_TYPE_XXX - Integirty types. + * @{ */ +#define UDF_LVID_TYPE_OPEN UINT32_C(0x00000000) +#define UDF_LVID_TYPE_CLOSE UINT32_C(0x00000001) +/** @} */ + +/** + * UDF file set descriptor (FSD) (@ecma167{4,14.1,86}, @udf260{2.3.2,54}). + */ +typedef struct UDFFILESETDESC +{ + /** 0x000: The descriptor tag (UDF_TAG_ID_FILE_SET_DESC). */ + UDFTAG Tag; + /** 0x010: Recording timestamp. */ + UDFTIMESTAMP RecordingTimestamp; + /** 0x01c: Interchange level. */ + uint16_t uInterchangeLevel; + /** 0x01e: Maximum interchange level. */ + uint16_t uMaxInterchangeLevel; + /** 0x020: Character set bitmask (aka list). Each bit correspond to a + * character set number. */ + uint32_t fCharacterSets; + /** 0x024: Maximum character set bitmask (aka list). */ + uint32_t fMaxCharacterSets; + /** 0x028: File set number. */ + uint32_t uFileSetNo; + /** 0x02c: File set descriptor number. */ + uint32_t uFileSetDescNo; + /** 0x030: Logical volume identifier character set. */ + UDFCHARSPEC LogicalVolumeIDCharSet; + /** 0x070: Logical volume identifier string. */ + UDFDSTRING achLogicalVolumeID[128]; + /** 0x0e0: File set character set. */ + UDFCHARSPEC FileSetCharSet; + /** 0x130: Identifier string for this file set. */ + UDFDSTRING achFileSetID[32]; + /** 0x150: Names a root file containing copyright info. Optional. */ + UDFDSTRING achCopyrightFile[32]; + /** 0x170: Names a root file containing an abstract for the file set. Optional. */ + UDFDSTRING achAbstractFile[32]; + /** 0x190: Root directory information control block location (ICB). + * An ICB is a sequence made up of UDF_TAG_ID_FILE_ENTRY, + * UDF_TAG_ID_INDIRECT_ENTRY, and UDF_TAG_ID_TERMINAL_ENTRY descriptors. */ + UDFLONGAD RootDirIcb; + /** 0x1a0: Domain identifier (UDF_ENTITY_FSD_LVD_DOMAIN). Optional. */ + UDFENTITYID idDomain; + /** 0x1c0: Next location with file set descriptors location, 0 if none. */ + UDFLONGAD NextExtent; + /** 0x1d0: Location of the system stream directory associated with the + * file set. Optional. */ + UDFLONGAD SystemStreamDirIcb; + /** 0x1e0: Reserved, MBZ. */ + uint8_t abReserved[32]; +} UDFFILESETDESC; +AssertCompileSize(UDFFILESETDESC, 512); +/** Pointer to an UDF file set descriptor. */ +typedef UDFFILESETDESC *PUDFFILESETDESC; +/** Pointer to a const UDF file set descriptor. */ +typedef UDFFILESETDESC const *PCUDFFILESETDESC; + + +/** + * UDF file identifier descriptor (FID) (@ecma167{4,14.4,91}, @udf260{2.3.4,57}). + */ +typedef struct UDFFILEIDDESC +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_FILE_ID_DESC). */ + UDFTAG Tag; + /** 0x10: File version number (1..32767). Always set to 1. */ + uint16_t uVersion; + /** 0x12: File characteristics (UDF_FILE_FLAGS_XXX). */ + uint8_t fFlags; + /** 0x13: File identifier (name) length. */ + uint8_t cbName; + /** 0x14: Location of an information control block describing the file. + * Can be null if marked deleted. The implementation defined part of + * this contains additional flags and a unique ID. */ + UDFLONGAD Icb; + /** 0x24: Length of implementation use field (in bytes). This can be zero. + * + * It can be used to prevent the following FID from spanning a block + * boundrary, in which case it will be 32 bytes or more, and the it will + * start with an UDFENTITYID identifying who last wrote it. + * + * The latter padding fun is a requirement from write-once media. */ + uint16_t cbImplementationUse; + /** 0x26: Two variable sized fields followed by padding to make the + * actual structure size 4 byte aligned. The first field in an + * implementation use field with length given by @a cbImplementationUse. + * After that is a d-string field with the name of the file, length + * specified by @a cbName. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abImplementationUse[RT_FLEXIBLE_ARRAY]; +} UDFFILEIDDESC; +AssertCompileMemberOffset(UDFFILEIDDESC, fFlags, 0x12); +AssertCompileMemberOffset(UDFFILEIDDESC, cbName, 0x13); +AssertCompileMemberOffset(UDFFILEIDDESC, Icb, 0x14); +AssertCompileMemberOffset(UDFFILEIDDESC, abImplementationUse, 0x26); +/** Pointer to an UDF file set descriptor */ +typedef UDFFILEIDDESC *PUDFFILEIDDESC; +/** Pointer to a const UDF file set descriptor */ +typedef UDFFILEIDDESC const *PCUDFFILEIDDESC; + +/** Get the pointer to the name field. */ +#define UDFFILEIDDESC_2_NAME(a_pFid) ((uint8_t const *)(&(a_pFid)->abImplementationUse[(a_pFid)->cbImplementationUse])) +/** Calculates the total size the size of a record. */ +#define UDFFILEIDDESC_CALC_SIZE_EX(cbImplementationUse, cbName) \ + RT_ALIGN_32((uint32_t)RT_UOFFSETOF(UDFFILEIDDESC, abImplementationUse) + cbImplementationUse + cbName, 4) +/** Gets the actual size of a record. */ +#define UDFFILEIDDESC_GET_SIZE(a_pFid) UDFFILEIDDESC_CALC_SIZE_EX((a_pFid)->cbImplementationUse, (a_pFid)->cbName) + +/** @name UDF_FILE_FLAGS_XXX + * @{ */ +/** Existence - Hide the file from the user. */ +#define UDF_FILE_FLAGS_HIDDEN UINT8_C(0x01) +/** Directory - Indicates a directory as apposed to some kind of file or symlink or something (0). */ +#define UDF_FILE_FLAGS_DIRECTORY UINT8_C(0x02) +/** Deleted - Indicate that the file has been deleted. Assoicated descriptors may still be valid, though. */ +#define UDF_FILE_FLAGS_DELETED UINT8_C(0x04) +/** Parent - Indicate the ICB field refers to the parent directory (or maybe + * a file in case of streaming directory). */ +#define UDF_FILE_FLAGS_PARENT UINT8_C(0x08) +/** Metadata - Zero means user data, one means implementation specific metadata. + * Only allowed used in stream directory. */ +#define UDF_FILE_FLAGS_METADATA UINT8_C(0x10) +/** Reserved bits that should be zer. */ +#define UDF_FILE_FLAGS_RESERVED_MASK UINT8_C(0xe0) +/** @} */ + + +/** + * UDF allocation extent descriptor (@ecma167{4,14.5,93}, @udf260{2.3.11,67}). + */ +typedef struct UDFALLOCATIONEXTENTDESC +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_ALLOCATION_EXTENT_DESC). */ + UDFTAG Tag; + /** 0x10: Previous allocation extent location (logical block in current + * partition). */ + uint32_t offPrevExtent; + /** 0x14: Size of the following allocation descriptors (in bytes). */ + uint32_t cbAllocDescs; + /** 0x18: Allocation descriptors. */ + union + { + UDFSHORTAD aShortADs[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + UDFLONGAD aLongADs[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + UDFEXTAD aExtADs[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + } u; +} UDFALLOCATIONEXTENTDESC; +AssertCompileMemberOffset(UDFALLOCATIONEXTENTDESC, u, 0x18); +/** Pointer to an UDF allocation extent descriptor. */ +typedef UDFALLOCATIONEXTENTDESC *PUDFALLOCATIONEXTENTDESC; +/** Pointer to a const UDF allocation extent descriptor. */ +typedef UDFALLOCATIONEXTENTDESC const *PCUDFALLOCATIONEXTENTDESC; + +/** + * UDF information control block tag (@ecma167{4,14.6,93}, @udf260{2.3.5,60}). + */ +typedef struct UDFICBTAG +{ + /** 0x00: Number of direct entries in this ICB prior to this one. */ + uint32_t cEntiresBeforeThis; + /** 0x04: ICB hierarchy building strategy type (UDF_ICB_STRATEGY_TYPE_XXX). */ + uint16_t uStrategyType; + /** 0x06: Type specific parameters. */ + uint8_t abStrategyParams[2]; + /** 0x08: Max number of direct and indirect entries that MAY be recorded in this ICB. */ + uint16_t cMaxEntries; + /** 0x0a: Reserved, MBZ. */ + uint8_t bReserved; + /** 0x0b: File type (UDF_FILE_TYPE_XXX). */ + uint8_t bFileType; + /** 0x0c: Parent ICB location. */ + UDFLBADDR ParentIcb; + /** 0x12: Parent ICB location (UDF_ICB_FLAGS_XXX). */ + uint16_t fFlags; +} UDFICBTAG; +AssertCompileSize(UDFICBTAG, 20); +typedef UDFICBTAG *PUDFICBTAG; +typedef UDFICBTAG const *PCUDFICBTAG; + +/** @name UDF_ICB_STRATEGY_TYPE_XXX - ICB hierarchy building strategies + * + * See @ecma167{4,14.6.2,94}, @udf260{6.6,121} + * + * @{ */ +/** Strategy not specified. */ +#define UDF_ICB_STRATEGY_TYPE_NOT_SPECIFIED UINT16_C(0x0000) +/** See @ecma167{4,A.2,129}. */ +#define UDF_ICB_STRATEGY_TYPE_1 UINT16_C(0x0001) +/** See @ecma167{4,A.3,131}. */ +#define UDF_ICB_STRATEGY_TYPE_2 UINT16_C(0x0002) +/** See @ecma167{4,A.4,131}. */ +#define UDF_ICB_STRATEGY_TYPE_3 UINT16_C(0x0003) +/** See @ecma167{4,A.5,131}. */ +#define UDF_ICB_STRATEGY_TYPE_4 UINT16_C(0x0004) +/** Defined by the UDF spec, see @udf260{6.6,121}. */ +#define UDF_ICB_STRATEGY_TYPE_4096 UINT16_C(0x1000) +/** @} */ + +/** @name UDF_ICB_FLAGS_XXX - ICB flags + * + * See @ecma167{4,14.6.8,95}, @udf260{2.3.5.4,61} + * + * @{ */ +/** Using UDFSHORTAD. */ +#define UDF_ICB_FLAGS_AD_TYPE_SHORT UINT16_C(0x0000) +/** Using UDFLONGAD. */ +#define UDF_ICB_FLAGS_AD_TYPE_LONG UINT16_C(0x0001) +/** Using UDFEXTAD. */ +#define UDF_ICB_FLAGS_AD_TYPE_EXTENDED UINT16_C(0x0002) +/** File content is embedded in the allocation descriptor area. */ +#define UDF_ICB_FLAGS_AD_TYPE_EMBEDDED UINT16_C(0x0003) +/** Allocation type mask. */ +#define UDF_ICB_FLAGS_AD_TYPE_MASK UINT16_C(0x0007) +/** Set on directories that are sorted (according to @ecma167{4,8.6.1,78}). + * @note Directories are never sorted in UDF. */ +#define UDF_ICB_FLAGS_SORTED_DIRECTORY UINT16_C(0x0008) +/** Not relocatable. */ +#define UDF_ICB_FLAGS_NON_RELOCATABLE UINT16_C(0x0010) +/** Indicate that the file needs backing up (DOS attribute). */ +#define UDF_ICB_FLAGS_ARCHIVE UINT16_C(0x0020) +/** Set UID bit (UNIX). */ +#define UDF_ICB_FLAGS_SET_UID UINT16_C(0x0040) +/** Set GID bit (UNIX). */ +#define UDF_ICB_FLAGS_SET_GID UINT16_C(0x0080) +/** Set sticky bit (UNIX). */ +#define UDF_ICB_FLAGS_STICKY UINT16_C(0x0100) +/** Extents are contiguous. */ +#define UDF_ICB_FLAGS_CONTIGUOUS UINT16_C(0x0200) +/** System bit, reserved for implementation use. */ +#define UDF_ICB_FLAGS_SYSTEM UINT16_C(0x0400) +/** Data has been transformed in some way. + * @note UDF shall not set this bit. */ +#define UDF_ICB_FLAGS_TRANSFORMED UINT16_C(0x0800) +/** Directory may contain multi-versioned files. + * @note UDF shall not set this bit. */ +#define UDF_ICB_FLAGS_MULTI_VERSIONS UINT16_C(0x1000) +/** Is a stream in a stream directory. */ +#define UDF_ICB_FLAGS_STREAM UINT16_C(0x2000) +/** Reserved mask. */ +#define UDF_ICB_FLAGS_RESERVED_MASK UINT16_C(0xc000) +/** @} */ + +/** @name UDF_FILE_TYPE_XXX - File types + * + * See @ecma167{4,14.6.6,94}, @udf260{2.3.5.2,60} + * + * @{ */ +#define UDF_FILE_TYPE_NOT_SPECIFIED UINT8_C(0x00) /**< Not specified by this field. */ +#define UDF_FILE_TYPE_UNALLOCATED_SPACE_ENTRY UINT8_C(0x01) +#define UDF_FILE_TYPE_PARTITION_INTEGRITY_ENTRY UINT8_C(0x02) +#define UDF_FILE_TYPE_INDIRECT_ENTRY UINT8_C(0x03) +#define UDF_FILE_TYPE_DIRECTORY UINT8_C(0x04) +#define UDF_FILE_TYPE_REGULAR_FILE UINT8_C(0x05) +#define UDF_FILE_TYPE_BLOCK_DEVICE UINT8_C(0x06) +#define UDF_FILE_TYPE_CHARACTER_DEVICE UINT8_C(0x07) +#define UDF_FILE_TYPE_EXTENDED_ATTRIBUTES UINT8_C(0x08) +#define UDF_FILE_TYPE_FIFO UINT8_C(0x09) +#define UDF_FILE_TYPE_SOCKET UINT8_C(0x0a) +#define UDF_FILE_TYPE_TERMINAL_ENTRY UINT8_C(0x0b) +#define UDF_FILE_TYPE_SYMBOLIC_LINK UINT8_C(0x0c) +#define UDF_FILE_TYPE_STREAM_DIRECTORY UINT8_C(0x0d) +#define UDF_FILE_TYPE_VAT UINT8_C(0xf8) +#define UDF_FILE_TYPE_REAL_TIME_FILE UINT8_C(0xf9) +#define UDF_FILE_TYPE_METADATA_FILE UINT8_C(0xfa) +#define UDF_FILE_TYPE_METADATA_MIRROR_FILE UINT8_C(0xfb) +#define UDF_FILE_TYPE_METADATA_BITMAP_FILE UINT8_C(0xfc) +/** @} */ + + +/** + * UDF ICB header (derived structure). + */ +typedef struct UDFICBHDR +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_INDIRECT_ENTRY). */ + UDFTAG Tag; + /** 0x10: ICB Tag. */ + UDFICBTAG IcbTag; +} UDFICBHDR; +AssertCompileSize(UDFICBHDR, 36); +/** Pointer to an UDF ICB header. */ +typedef UDFICBHDR *PUDFICBHDR; +/** Pointer to a const UDF ICB header. */ +typedef UDFICBHDR const *PCUDFICBHDR; + + +/** + * UDF indirect entry (@ecma167{4,14.7,96}). + */ +typedef struct UDFINDIRECTENTRY +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_INDIRECT_ENTRY). */ + UDFTAG Tag; + /** 0x10: ICB Tag. */ + UDFICBTAG IcbTag; + /** 0x24: Indirect ICB location. */ + UDFLONGAD IndirectIcb; +} UDFINDIRECTENTRY; +AssertCompileSize(UDFINDIRECTENTRY, 52); +/** Pointer to an UDF indirect entry. */ +typedef UDFINDIRECTENTRY *PUDFINDIRECTENTRY; +/** Pointer to a const UDF indirect entry. */ +typedef UDFINDIRECTENTRY const *PCUDFINDIRECTENTRY; + + +/** + * UDF terminal entry (@ecma167{4,14.8,97}). + */ +typedef struct UDFTERMINALENTRY +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_TERMINAL_ENTRY). */ + UDFTAG Tag; + /** 0x10: ICB Tag (UDF_FILE_TYPE_TERMINAL_ENTRY). */ + UDFICBTAG IcbTag; +} UDFTERMINALENTRY; +AssertCompileSize(UDFTERMINALENTRY, 36); +/** Pointer to an UDF terminal entry. */ +typedef UDFTERMINALENTRY *PUDFTERMINALENTRY; +/** Pointer to a const UDF terminal entry. */ +typedef UDFTERMINALENTRY const *PCUDFTERMINALENTRY; + + +/** + * UDF file entry (FE) (@ecma167{4,14.8,97}, @udf260{2.3.6,62}). + * + * @note Total length shall not exceed one logical block. + */ +typedef struct UDFFILEENTRY +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_FILE_ENTRY). */ + UDFTAG Tag; + /** 0x10: ICB Tag. */ + UDFICBTAG IcbTag; + /** 0x24: User ID (UNIX). */ + uint32_t uid; + /** 0x28: Group ID (UNIX). */ + uint32_t gid; + /** 0x2c: Permission (UDF_PERM_XXX). */ + uint32_t fPermissions; + /** 0x30: Number hard links. */ + uint16_t cHardlinks; + /** 0x32: Record format (UDF_REC_FMT_XXX). */ + uint8_t uRecordFormat; + /** 0x33: Record format (UDF_REC_ATTR_XXX). */ + uint8_t fRecordDisplayAttribs; + /** 0x34: Record length (in bytes). + * @note Must be zero according to the UDF specification. */ + uint32_t cbRecord; + /** 0x38: Information length in bytes (file size). */ + uint64_t cbData; + /** 0x40: Number of logical blocks allocated (for file data). */ + uint64_t cLogicalBlocks; + /** 0x48: Time of last access (prior to recording the file entry). */ + UDFTIMESTAMP AccessTime; + /** 0x54: Time of last data modification. */ + UDFTIMESTAMP ModificationTime; + /** 0x60: Time of last attribute/status modification. */ + UDFTIMESTAMP ChangeTime; + /** 0x6c: Checkpoint number (defaults to 1). */ + uint32_t uCheckpoint; + /** 0x70: Extended attribute information control block location. */ + UDFLONGAD ExtAttribIcb; + /** 0x80: Implementation identifier ("*Developer ID"). */ + UDFENTITYID idImplementation; + /** 0xa0: Unique ID. */ + uint64_t INodeId; + /** 0xa8: Length of extended attributes in bytes, multiple of four. */ + uint32_t cbExtAttribs; + /** 0xac: Length of allocation descriptors in bytes, multiple of four. */ + uint32_t cbAllocDescs; + /** 0xb0: Two variable sized fields. First @a cbExtAttribs bytes of extended + * attributes, then @a cbAllocDescs bytes of allocation descriptors. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abExtAttribs[RT_FLEXIBLE_ARRAY]; +} UDFFILEENTRY; +AssertCompileMemberOffset(UDFFILEENTRY, abExtAttribs, 0xb0); +/** Pointer to an UDF file entry. */ +typedef UDFFILEENTRY *PUDFFILEENTRY; +/** Pointer to a const UDF file entry. */ +typedef UDFFILEENTRY const *PCUDFFILEENTRY; + +/** @name UDF_PERM_XXX - UDFFILEENTRY::fPermissions + * See @ecma167{4,14.9.5,99}. + * @{ */ +#define UDF_PERM_OTH_EXEC UINT32_C(0x00000001) +#define UDF_PERM_OTH_WRITE UINT32_C(0x00000002) +#define UDF_PERM_OTH_READ UINT32_C(0x00000004) +#define UDF_PERM_OTH_ATTRIB UINT32_C(0x00000008) +#define UDF_PERM_OTH_DELETE UINT32_C(0x00000010) +#define UDF_PERM_OTH_MASK UINT32_C(0x0000001f) + +#define UDF_PERM_GRP_EXEC UINT32_C(0x00000020) +#define UDF_PERM_GRP_WRITE UINT32_C(0x00000040) +#define UDF_PERM_GRP_READ UINT32_C(0x00000080) +#define UDF_PERM_GRP_ATTRIB UINT32_C(0x00000100) +#define UDF_PERM_GRP_DELETE UINT32_C(0x00000200) +#define UDF_PERM_GRP_MASK UINT32_C(0x000003e0) + +#define UDF_PERM_USR_EXEC UINT32_C(0x00000400) +#define UDF_PERM_USR_WRITE UINT32_C(0x00000800) +#define UDF_PERM_USR_READ UINT32_C(0x00001000) +#define UDF_PERM_USR_ATTRIB UINT32_C(0x00002000) +#define UDF_PERM_USR_DELETE UINT32_C(0x00004000) +#define UDF_PERM_USR_MASK UINT32_C(0x00007c00) + +#define UDF_PERM_USR_RESERVED_MASK UINT32_C(0xffff8000) +/** @} */ + +/** @name UDF_REC_FMT_XXX - Record format. + * See @ecma167{4,14.9.7,100}. + * @{ */ +/** Not record format specified. + * @note The only allowed value according to the UDF specification. */ +#define UDF_REC_FMT_NOT_SPECIFIED UINT8_C(0x00) +/** @} */ + +/** @name UDF_REC_ATTR_XXX - Record display attributes. + * See @ecma167{4,14.9.8,100}. + * @{ */ +/** Manner of record display not specified. + * @note The only allowed value according to the UDF specification. */ +#define UDF_REC_ATTR_NOT_SPECIFIED UINT8_C(0x00) +/** @} */ + + +/** + * UDF extended attribute header descriptor (@ecma167{4,14.10.1,102}, + * @udf260{3.3.4,79}). + */ +typedef struct UDFEXTATTRIBHDRDESC +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_EXTENDED_ATTRIB_HDR_DESC). */ + UDFTAG Tag; + /** 0x10: Implementation attributes location (byte offset) into the EA space. + * This typically set to UINT32_MAX if not present, though any value larger + * than the EA space will do. */ + uint32_t offImplementationAttribs; + /** 0x14: Application attributes location (byte offset) into the EA space. + * This typically set to UINT32_MAX if not present, though any value larger + * than the EA space will do. */ + uint32_t offApplicationAttribs; +} UDFEXTATTRIBHDRDESC; +AssertCompileSize(UDFEXTATTRIBHDRDESC, 24); +/** Pointer to an UDF extended attribute header descriptor. */ +typedef UDFEXTATTRIBHDRDESC *PUDFEXTATTRIBHDRDESC; +/** Pointer to a const UDF extended attribute header descriptor. */ +typedef UDFEXTATTRIBHDRDESC const *PCUDFEXTATTRIBHDRDESC; + +/** + * UDF character set info EA data (@ecma167{4,14.10.3,104}). + * + * Not needed by UDF. + */ +typedef struct UDFEADATACHARSETINFO +{ + /** 0x00/0x0c: The length of the escape sequences (in bytes). */ + uint32_t cbEscSeqs; + /** 0x04/0x10: The character set type (UDF_CHAR_SET_TYPE_XXX). */ + uint8_t bType; + /** 0x05/0x11: Escape sequences. */ + uint8_t abEscSeqs[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} UDFEADATACHARSETINFO; +/** Pointer to UDF character set info EA data. */ +typedef UDFEADATACHARSETINFO *PUDFEADATACHARSETINFO; +/** Pointer to const UDF character set info EA data. */ +typedef UDFEADATACHARSETINFO const *PCUDFEADATACHARSETINFO; +/** UDFGEA::uAttribType value for UDFEADATACHARSETINFO.*/ +#define UDFEADATACHARSETINFO_ATTRIB_TYPE UINT32_C(0x00000001) +/** UDFGEA::uAttribSubtype value for UDFEADATACHARSETINFO. */ +#define UDFEADATACHARSETINFO_ATTRIB_SUBTYPE UINT32_C(0x00000001) + +/** + * UDF alternate permissions EA data (@ecma167{4,14.10.4,105}, @udf260{3.3.4.2,80}). + * @note Not recorded according to the UDF specification. + */ +typedef struct UDFEADATAALTPERM +{ + /** 0x00/0x0c: Alternative owner ID. */ + uint16_t idOwner; + /** 0x02/0x0e: Alternative group ID. */ + uint16_t idGroup; + /** 0x04/0x10: Alternative permissions. */ + uint16_t fPermission; +} UDFEADATAALTPERM; +/** Pointer to UDF alternative permissions EA data. */ +typedef UDFEADATAALTPERM *PUDFEADATAALTPERM; +/** Pointer to const UDF alternative permissions EA data. */ +typedef UDFEADATAALTPERM const *PCUDFEADATAALTPERM; +/** UDFGEA::uAttribType value for UDFEADATAALTPERM. */ +#define UDFEADATAALTPERM_ATTRIB_TYPE UINT32_C(0x00000003) +/** UDFGEA::uAttribSubtype value for UDFEADATAALTPERM. */ +#define UDFEADATAALTPERM_ATTRIB_SUBTYPE UINT32_C(0x00000001) + +/** + * UDF file times EA data (@ecma167{4,14.10.5,108}, @udf260{3.3.4.3,80}). + * (This is a bit reminiscent of ISO9660RRIPTF.) + */ +typedef struct UDFEADATAFILETIMES +{ + /** 0x00/0x0c: Timestamp length. */ + uint32_t cbTimestamps; + /** 0x04/0x10: Indicates which timestamps are present + * (UDF_FILE_TIMES_EA_F_XXX). */ + uint32_t fFlags; + /** 0x08/0x14: Timestamps. */ + UDFTIMESTAMP aTimestamps[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} UDFEADATAFILETIMES; +/** Pointer to UDF file times EA data. */ +typedef UDFEADATAFILETIMES *PUDFEADATAFILETIMES; +/** Pointer to const UDF file times EA data. */ +typedef UDFEADATAFILETIMES const *PCUDFEADATAFILETIMES; +/** UDFGEA::uAttribType value for UDFEADATAFILETIMES. */ +#define UDFEADATAFILETIMES_ATTRIB_TYPE UINT32_C(0x00000005) +/** UDFGEA::uAttribSubtype value for UDFEADATAFILETIMES. */ +#define UDFEADATAFILETIMES_ATTRIB_SUBTYPE UINT32_C(0x00000001) + +/** @name UDF_FILE_TIMES_EA_F_XXX - File times existence flags. + * See @ecma167{4,14.10.5.6,109} + * @{ */ +#define UDF_FILE_TIMES_EA_F_BIRTH UINT8_C(0x01) /**< Birth (creation) timestamp is recorded. */ +#define UDF_FILE_TIMES_EA_F_DELETE UINT8_C(0x04) /**< Deletion timestamp is recorded. */ +#define UDF_FILE_TIMES_EA_F_EFFECTIVE UINT8_C(0x08) /**< Effective timestamp is recorded. */ +#define UDF_FILE_TIMES_EA_F_BACKUP UINT8_C(0x20) /**< Backup timestamp is recorded. */ +#define UDF_FILE_TIMES_EA_F_RESERVED_MASK UINT8_C(0xd2) +/** @} */ + +/** + * UDF information times EA data (@ecma167{4,14.10.6,109}). + */ +typedef struct UDFEADATAINFOTIMES +{ + /** 0x00/0x0c: Timestamp length. */ + uint32_t cbTimestamps; + /** 0x04/0x10: Indicates which timestamps are present + * (UDF_INFO_TIMES_EA_F_XXX). */ + uint32_t fFlags; + /** 0x08/0x14: Timestamps. */ + UDFTIMESTAMP aTimestamps[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} UDFEADATAINFOTIMES; +/** Pointer to UDF information times EA data. */ +typedef UDFEADATAINFOTIMES *PUDFEADATAINFOTIMES; +/** Pointer to const UDF information times EA data. */ +typedef UDFEADATAINFOTIMES const *PCUDFEADATAINFOTIMES; +/** UDFGEA::uAttribType value for UDFEADATAINFOTIMES. */ +#define UDFEADATAINFOTIMES_ATTRIB_TYPE UINT32_C(0x00000006) +/** UDFGEA::uAttribSubtype value for UDFEADATAINFOTIMES. */ +#define UDFEADATAINFOTIMES_ATTRIB_SUBTYPE UINT32_C(0x00000001) + +/** @name UDF_INFO_TIMES_EA_F_XXX - Information times existence flags. + * See @ecma167{4,14.10.6.6,110} + * @{ */ +#define UDF_INFO_TIMES_EA_F_BIRTH UINT8_C(0x01) /**< Birth (creation) timestamp is recorded. */ +#define UDF_INFO_TIMES_EA_F_MODIFIED UINT8_C(0x02) /**< Last (data) modified timestamp is recorded. */ +#define UDF_INFO_TIMES_EA_F_EXPIRE UINT8_C(0x04) /**< Expiration (deletion) timestamp is recorded. */ +#define UDF_INFO_TIMES_EA_F_EFFECTIVE UINT8_C(0x08) /**< Effective timestamp is recorded. */ +#define UDF_INFO_TIMES_EA_F_RESERVED_MASK UINT8_C(0xf0) +/** @} */ + +/** + * UDF device specification EA data (@ecma167{4,14.10.7,110}, @udf260{3.3.4.4,81}). + */ +typedef struct UDFEADATADEVICESPEC +{ + /** 0x00/0x0c: Length of implementation use field. */ + uint32_t cbImplementationUse; + /** 0x04/0x10: Major device number. */ + uint32_t uMajorDeviceNo; + /** 0x08/0x14: Minor device number. */ + uint32_t uMinorDeviceNo; + /** 0x0c/0x18: Implementation use field (variable length). + * UDF specficiation expects UDFENTITYID with a "*Developer ID" as first part + * here. */ + uint8_t abImplementationUse[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} UDFEADATADEVICESPEC; +/** Pointer to UDF device specification EA data. */ +typedef UDFEADATADEVICESPEC *PUDFEADATADEVICESPEC; +/** Pointer to const UDF device specification EA data. */ +typedef UDFEADATADEVICESPEC const *PCUDFEADATADEVICESPEC; +/** UDFGEA::uAttribType value for UDFEADATADEVICESPEC. */ +#define UDFEADATADEVICESPEC_ATTRIB_TYPE UINT32_C(0x0000000c) +/** UDFGEA::uAttribSubtype value for UDFEADATADEVICESPEC. */ +#define UDFEADATADEVICESPEC_ATTRIB_SUBTYPE UINT32_C(0x00000001) + +/** + * UDF free EA space payload for implementation and application use EAs + * (@udf260{3.3.4.5.1.1,82}, @udf260{3.3.4.6.1.1,88}). + * + * UDFEADATAIMPLUSE::idImplementation is UDF_ENTITY_ID_IUEA_FREE_EA_SPACE. + * UDFEADATAAPPUSE::idImplementation is UDF_ENTITY_ID_AUEA_FREE_EA_SPACE. + */ +typedef struct UDFFREEEASPACE +{ + /** 0x00/0x30: Header checksum. + * @note 16-bit checksum of UDFGEA up thru u.ImplUse.idImplementation. */ + uint16_t uChecksum; + /** 0x02/0x32: Free space. */ + uint8_t abFree[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} UDFFREEEASPACE; +/** Pointer to UDF free EA space impl/app use payload. */ +typedef UDFFREEEASPACE *PUDFFREEEASPACE; +/** Pointer to const UDF free EA space impl/app use payload. */ +typedef UDFFREEEASPACE const *PCUDFFREEEASPACE; + +/** + * UDF DVD copyright management information implementation use EA payload + * (@udf260{3.3.4.5.1.2,83}). + * + * UDFEADATAIMPLUSE::idImplementation is UDF_ENTITY_ID_IUEA_DVD_CGMS_INFO. + */ +typedef struct UDFIUEADVDCGMSINFO +{ + /** 0x00/0x30: Header checksum. + * @note 16-bit checksum of UDFGEA up thru u.ImplUse.idImplementation. */ + uint16_t uChecksum; + /** 0x02/0x32: The CGMS information (whatever that is). */ + uint8_t bInfo; + /** 0x03/0x33: Data structure type (whatever that is). */ + uint8_t bType; + /** 0x04/0x34: Production system information, probably dependend on the + * values of previous fields. */ + uint8_t abProtSysInfo[4]; +} UDFIUEADVDCGMSINFO; +/** Pointer to UDF DVD copyright management information implementation use EA payload. */ +typedef UDFIUEADVDCGMSINFO *PUDFIUEADVDCGMSINFO; +/** Pointer to const UDF DVD copyright management information implementation use EA payload. */ +typedef UDFIUEADVDCGMSINFO const *PCUDFIUEADVDCGMSINFO; + +/** + * UDF OS/2 EA length implementation use EA payload (@udf260{3.3.4.5.3.1,84}). + * + * UDFEADATAIMPLUSE::idImplementation is UDF_ENTITY_ID_IUEA_OS2_EA_LENGTH. + */ +#pragma pack(2) +typedef struct UDFIUEAOS2EALENGTH +{ + /** 0x00/0x30: Header checksum. + * @note 16-bit checksum of UDFGEA up thru u.ImplUse.idImplementation. */ + uint16_t uChecksum; + /** 0x02/0x32: The CGMS information (whatever that is). */ + uint32_t cbEAs; +} UDFIUEAOS2EALENGTH; +#pragma pack() +AssertCompileMemberOffset(UDFIUEAOS2EALENGTH, cbEAs, 2); +/** Pointer to UDF OS/2 EA length implementation use EA payload. */ +typedef UDFIUEAOS2EALENGTH *PUDFIUEAOS2EALENGTH; +/** Pointer to const UDF OS/2 EA length implementation use EA payload. */ +typedef UDFIUEAOS2EALENGTH const *PCUDFIUEAOS2EALENGTH; + +/** + * UDF Mac volume info implementation use EA payload (@udf260{3.3.4.5.4.1,84}). + * + * UDFEADATAIMPLUSE::idImplementation is UDF_ENTITY_ID_IUEA_MAC_VOLUME_INFO. + */ +#pragma pack(2) +typedef struct UDFIUEAMACVOLINFO +{ + /** 0x00/0x30: Header checksum. + * @note 16-bit checksum of UDFGEA up thru u.ImplUse.idImplementation. */ + uint16_t uChecksum; + /** 0x02/0x32: Last modification time. */ + UDFTIMESTAMP LastModificationTime; + /** 0x0e/0x3e: Last backup time. */ + UDFTIMESTAMP LastBackupTime; + /** 0x1a/0x4e: Volume finder information. */ + uint32_t au32FinderInfo[8]; +} UDFIUEAMACVOLINFO; +#pragma pack() +AssertCompileMemberOffset(UDFIUEAMACVOLINFO, au32FinderInfo, 0x1a); +/** Pointer to UDF Mac volume info implementation use EA payload. */ +typedef UDFIUEAMACVOLINFO *PUDFIUEAMACVOLINFO; +/** Pointer to const UDF Mac volume info implementation use EA payload. */ +typedef UDFIUEAMACVOLINFO const *PCUDFIUEAMACVOLINFO; + +/** + * UDF point for use in Mac EAs (@udf260{3.3.4.5.4.2,86}). + */ +typedef struct UDFMACPOINT +{ + /** X coordinate. */ + int16_t x; + /** Y coordinate. */ + int16_t y; +} UDFMACPOINT; + +/** + * UDF rectangle for using Mac EAs (@udf260{3.3.4.5.4.2,86}). + */ +typedef struct UDFMACRECT +{ + /** top Y coordinate. */ + int16_t yTop; + /** left X coordinate. */ + int16_t xLeft; + /** bottom Y coordinate. (exclusive?) */ + int16_t yBottom; + /** right X coordinate. (exclusive?) */ + int16_t xRight; +} UDFMACRECT; + +/** + * UDF finder directory info for Mac EAs (@udf260{3.3.4.5.4.2,86}). + */ +typedef struct UDFMACFDINFO +{ + UDFMACRECT FrRect; + int16_t FrFlags; + UDFMACPOINT FrLocation; + int16_t FrView; +} UDFMACFDINFO; +AssertCompileSize(UDFMACFDINFO, 16); + +/** + * UDF finder directory extended info for Mac EAs (@udf260{3.3.4.5.4.2,86}). + */ +typedef struct UDFMACFDXINFO +{ + UDFMACPOINT FrScroll; + int32_t FrOpenChain; + uint8_t FrScript; + uint8_t FrXFlags; + uint16_t FrComment; + uint32_t FrPutAway; +} UDFMACFDXINFO; +AssertCompileSize(UDFMACFDXINFO, 16); + +/** + * UDF Mac finder info implementation use EA payload (@udf260{3.3.4.5.4.1,84}), + * directory edition. + * + * UDFEADATAIMPLUSE::idImplementation is UDF_ENTITY_ID_IUEA_MAC_FINDER_INFO. + */ +typedef struct UDFIUEAMACFINDERINFODIR +{ + /** 0x00/0x30: Header checksum. + * @note 16-bit checksum of UDFGEA up thru u.ImplUse.idImplementation. */ + uint16_t uChecksum; + /** 0x02/0x32: Explicit alignment padding, MBZ. */ + uint16_t uPadding; + /** 0x04/0x34: Parent directory ID. */ + uint32_t idParentDir; + /** 0x08/0x38: Dir information. */ + UDFMACFDINFO DirInfo; + /** 0x18/0x48: Dir extended information. */ + UDFMACFDXINFO DirExInfo; +} UDFIUEAMACFINDERINFODIR; +AssertCompileMemberOffset(UDFIUEAMACFINDERINFODIR, DirInfo, 0x08); +AssertCompileMemberOffset(UDFIUEAMACFINDERINFODIR, DirExInfo, 0x18); +AssertCompileSize(UDFIUEAMACFINDERINFODIR, 0x28); +/** Pointer to UDF Mac finder info for dir implementation use EA payload. */ +typedef UDFIUEAMACFINDERINFODIR *PUDFIUEAMACFINDERINFODIR; +/** Pointer to const UDF Mac finder info for dir implementation use EA payload. */ +typedef UDFIUEAMACFINDERINFODIR const *PCUDFIUEAMACFINDERINFODIR; + +/** + * UDF finder file info for Mac EAs (@udf260{3.3.4.5.4.2,86}). + */ +typedef struct UDFMACFFINFO +{ + uint32_t FrType; + uint32_t FrCreator; + uint16_t FrFlags; + UDFMACPOINT FrLocation; + int16_t FrFldr; +} UDFMACFFINFO; +AssertCompileSize(UDFMACFFINFO, 16); + +/** + * UDF finder file extended info for Mac EAs (@udf260{3.3.4.5.4.2,86}). + */ +typedef struct UDFMACFFXINFO +{ + int16_t FrIconID; + uint8_t FdUnused[6]; + uint8_t FrScript; + uint8_t FrXFlags; + uint16_t FrComment; + uint32_t FrPutAway; +} UDFMACFFXINFO; +AssertCompileSize(UDFMACFFXINFO, 16); + +/** + * UDF Mac finder info implementation use EA payload (@udf260{3.3.4.5.4.1,84}), + * file edition. + * + * UDFEADATAIMPLUSE::idImplementation is UDF_ENTITY_ID_IUEA_MAC_FINDER_INFO. + */ +typedef struct UDFIUEAMACFINDERINFOFILE +{ + /** 0x00/0x30: Header checksum. + * @note 16-bit checksum of UDFGEA up thru u.ImplUse.idImplementation. */ + uint16_t uChecksum; + /** 0x02/0x32: Explicit alignment padding, MBZ. */ + uint16_t uPadding; + /** 0x04/0x34: Parent directory ID. */ + uint32_t idParentDir; + /** 0x08/0x38: File information. */ + UDFMACFFINFO FileInfo; + /** 0x18/0x48: File extended information. */ + UDFMACFFXINFO FileExInfo; + /** 0x28/0x58: The size of the fork data (in bytes). */ + uint32_t cbForkData; + /** 0x2c/0x5c: The size of the fork allocation (in bytes). */ + uint32_t cbForkAlloc; +} UDFIUEAMACFINDERINFOFILE; +AssertCompileMemberOffset(UDFIUEAMACFINDERINFOFILE, FileInfo, 0x08); +AssertCompileMemberOffset(UDFIUEAMACFINDERINFOFILE, FileExInfo, 0x18); +AssertCompileMemberOffset(UDFIUEAMACFINDERINFOFILE, cbForkData, 0x28); +AssertCompileSize(UDFIUEAMACFINDERINFOFILE, 0x30); +/** Pointer to UDF Mac finder info for file implementation use EA payload. */ +typedef UDFIUEAMACFINDERINFOFILE *PUDFIUEAMACFINDERINFOFILE; +/** Pointer to const UDF Mac finder info for file implementation use EA payload. */ +typedef UDFIUEAMACFINDERINFOFILE const *PCUDFIUEAMACFINDERINFOFILE; + +/** + * UDF OS/400 directory info implementation use EA payload (@udf260{3.3.4.5.6.1,87}) + * + * UDFEADATAIMPLUSE::idImplementation is UDF_ENTITY_ID_IUEA_OS400_DIR_INFO. + */ +typedef struct UDFIUEAOS400DIRINFO +{ + /** 0x00/0x30: Header checksum. + * @note 16-bit checksum of UDFGEA up thru u.ImplUse.idImplementation. */ + uint16_t uChecksum; + /** 0x02/0x32: Explicit alignment padding, MBZ. */ + uint16_t uPadding; + /** 0x04/0x34: The directory info, format documented elsewhere. */ + uint8_t abDirInfo[44]; +} UDFIUEAOS400DIRINFO; +AssertCompileSize(UDFIUEAOS400DIRINFO, 0x30); +/** Pointer to UDF Mac finder info for file implementation use EA payload. */ +typedef UDFIUEAOS400DIRINFO *PUDFIUEAOS400DIRINFO; +/** Pointer to const UDF Mac finder info for file implementation use EA payload. */ +typedef UDFIUEAOS400DIRINFO const *PCUDFIUEAOS400DIRINFO; + + +/** + * UDF implementation use EA data (@ecma167{4,14.10.8,111}, @udf260{3.3.4.5,82}). + */ +typedef struct UDFEADATAIMPLUSE +{ + /** 0x00/0x0c: Length uData in bytes. */ + uint32_t cbData; + /** 0x04/0x10: Implementation identifier (UDF_ENTITY_ID_IUEA_XXX). */ + UDFENTITYID idImplementation; + /** 0x24/0x30: Implementation use field (variable length). */ + union + { + /** Generic byte view. */ + uint8_t abData[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + /** Free EA space (UDF_ENTITY_ID_IUEA_FREE_EA_SPACE). */ + UDFFREEEASPACE FreeEaSpace; + /** DVD copyright management information (UDF_ENTITY_ID_IUEA_DVD_CGMS_INFO). */ + UDFIUEADVDCGMSINFO DvdCgmsInfo; + /** OS/2 EA length (UDF_ENTITY_ID_IUEA_OS2_EA_LENGTH). */ + UDFIUEAOS2EALENGTH Os2EaLength; + /** Mac volume info (UDF_ENTITY_ID_IUEA_MAC_VOLUME_INFO). */ + UDFIUEAMACVOLINFO MacVolInfo; + /** Mac finder info, directory edition (UDF_ENTITY_ID_IUEA_MAC_FINDER_INFO). */ + UDFIUEAMACFINDERINFODIR MacFinderInfoDir; + /** Mac finder info, file edition (UDF_ENTITY_ID_IUEA_MAC_FINDER_INFO). */ + UDFIUEAMACFINDERINFOFILE MacFinderInfoFile; + /** OS/400 directory info (UDF_ENTITY_ID_IUEA_OS400_DIR_INFO). */ + UDFIUEAOS400DIRINFO Os400DirInfo; + } u; +} UDFEADATAIMPLUSE; +/** Pointer to UDF implementation use EA data. */ +typedef UDFEADATAIMPLUSE *PUDFEADATAIMPLUSE; +/** Pointer to const UDF implementation use EA data. */ +typedef UDFEADATAIMPLUSE const *PCUDFEADATAIMPLUSE; +/** UDFGEA::uAttribType value for UDFEADATAIMPLUSE. */ +#define UDFEADATAIMPLUSE_ATTRIB_TYPE UINT32_C(0x00000800) +/** UDFGEA::uAttribSubtype value for UDFEADATAIMPLUSE. */ +#define UDFEADATAIMPLUSE_ATTRIB_SUBTYPE UINT32_C(0x00000001) + +/** + * UDF application use EA data (@ecma167{4,14.10.9,112}, @udf260{3.3.4.6,88}). + */ +typedef struct UDFEADATAAPPUSE +{ + /** 0x0c: Length uData in bytes. */ + uint32_t cbData; + /** 0x10: Application identifier (UDF_ENTITY_ID_AUEA_FREE_EA_SPACE). */ + UDFENTITYID idApplication; + /** 0x30: Application use field (variable length). */ + union + { + /** Generic byte view. */ + uint8_t ab[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + /** Free EA space (UDF_ENTITY_ID_AUEA_FREE_EA_SPACE). */ + UDFFREEEASPACE FreeEaSpace; + } uData; +} UDFEADATAAPPUSE; +/** Pointer to UDF application use EA data. */ +typedef UDFEADATAAPPUSE *PUDFEADATAAPPUSE; +/** Pointer to const UDF application use EA data. */ +typedef UDFEADATAAPPUSE const *PCUDFEADATAAPPUSE; +/** UDFGEA::uAttribType value for UDFEADATAAPPUSE. */ +#define UDFEADATAAPPUSE_ATTRIB_TYPE UINT32_C(0x00010000) +/** UDFGEA::uAttribSubtype value for UDFEADATAAPPUSE. */ +#define UDFEADATAAPPUSE_ATTRIB_SUBTYPE UINT32_C(0x00000001) + +/** + * UDF generic extended attribute (@ecma167{4,14.10.2,103}). + */ +typedef struct UDFGEA +{ + /** 0x00: Attribute type (UDFXXX_ATTRIB_TYPE). */ + uint32_t uAttribType; + /** 0x04: Attribute subtype (UDFXXX_ATTRIB_SUBTYPE). */ + uint8_t uAttribSubtype; + /** 0x05: Reserved padding bytes, MBZ. */ + uint8_t abReserved[3]; + /** 0x08: Size of the whole extended attribute. + * Multiple of four is recommended. */ + uint32_t cbAttrib; + /** 0x0c: Attribute data union. */ + union + { + /** Generic byte view (variable size). */ + uint8_t abData[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + /** Character set information (@ecma167{4,14.10.3,104}). */ + UDFEADATACHARSETINFO CharSetInfo; + /** Alternate permissions (@ecma167{4,14.10.4,105}, @udf260{3.3.4.2,80}). + * @note Not recorded according to the UDF specification. */ + UDFEADATAALTPERM AltPerm; + /** File times (@ecma167{4,14.10.5,108}, @udf260{3.3.4.3,80}). + * (This is a bit reminiscent of ISO9660RRIPTF.) */ + UDFEADATAFILETIMES FileTimes; + /** Information times (@ecma167{4,14.10.6,109}). */ + UDFEADATAINFOTIMES InfoTimes; + /** Device specification (@ecma167{4,14.10.7,110}, @udf260{3.3.4.4,81}). */ + UDFEADATADEVICESPEC DeviceSpec; + /** Implementation use (@ecma167{4,14.10.8,111}, @udf260{3.3.4.5,82}). */ + UDFEADATAIMPLUSE ImplUse; + /** Application use (@ecma167{4,14.10.9,112}, @udf260{3.3.4.6,88}). */ + UDFEADATAAPPUSE AppUse; + } u; +} UDFGEA; +AssertCompileMemberOffset(UDFGEA, u, 0x0c); +/** Pointer to a UDF extended attribute. */ +typedef UDFGEA *PUDFGEA; +/** Pointer to a const UDF extended attribute. */ +typedef UDFGEA const *PCUDFGEA; + + +/** + * UDF unallocated space entry (@ecma167{4,14.11,113}, @udf260{2.3.7,64}). + * + * @note Total length shall not exceed one logical block. + */ +typedef struct UDFUNALLOCATEDSPACEENTRY +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_UNALLOCATED_SPACE_ENTRY). */ + UDFTAG Tag; + /** 0x10: ICB Tag. */ + UDFICBTAG IcbTag; + /** 0x24: Size of the allocation desciptors in bytes. */ + uint32_t cbAllocDescs; + /** 0x28: Allocation desciptors, type given by IcbTag::fFlags. */ + union + { + UDFSHORTAD aShortADs[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + UDFLONGAD aLongADs[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + UDFEXTAD aExtADs[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + UDFEXTENTAD SingleAD; + } u; +} UDFUNALLOCATEDSPACEENTRY; +AssertCompileMemberOffset(UDFUNALLOCATEDSPACEENTRY, u, 0x28); +/** Pointer to an UDF unallocated space entry. */ +typedef UDFUNALLOCATEDSPACEENTRY *PUDFUNALLOCATEDSPACEENTRY; +/** Pointer to a const UDF unallocated space entry. */ +typedef UDFUNALLOCATEDSPACEENTRY const *PCUDFUNALLOCATEDSPACEENTRY; + + +/** + * UDF space bitmap descriptor (SBD) (@ecma167{4,14.12,114}, @udf260{2.3.8,65}). + */ +typedef struct UDFSPACEBITMAPDESC +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_SPACE_BITMAP_DESC). */ + UDFTAG Tag; + /** 0x10: Number of bits in the bitmap. */ + uint32_t cBits; + /** 0x14: The bitmap size in bytes. */ + uint32_t cbBitmap; + /** 0x18: The bitmap. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abBitmap[RT_FLEXIBLE_ARRAY]; +} UDFSPACEBITMAPDESC; +AssertCompileMemberOffset(UDFSPACEBITMAPDESC, abBitmap, 0x18); +/** Pointer to an UDF space bitmap descriptor. */ +typedef UDFSPACEBITMAPDESC *PUDFSPACEBITMAPDESC; +/** Pointer to a const UDF space bitmap descriptor. */ +typedef UDFSPACEBITMAPDESC const *PCUDFSPACEBITMAPDESC; + + +/** + * UDF partition integrity descriptor (@ecma167{4,14.3,115}, @udf260{2.3.9,65}). + * + * @note Not needed by UDF. + */ +typedef struct UDFPARTITIONINTEGRITYDESC +{ + /** 0x000: The descriptor tag (UDF_TAG_ID_PARTITION_INTEGERITY_DESC). */ + UDFTAG Tag; + /** 0x010: ICB Tag. */ + UDFICBTAG IcbTag; + /** 0x024: Recording timestamp. */ + UDFTIMESTAMP RecordingTimestamp; + /** 0x030: Interity type (UDF_PARTITION_INTEGRITY_TYPE_XXX). */ + uint8_t bType; + /** 0x031: Reserved. */ + uint8_t abReserved[175]; + /** 0x0e0: Implementation identifier. */ + UDFENTITYID idImplementation; + /** 0x100: Implementation use data. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abImplementationUse[RT_FLEXIBLE_ARRAY]; +} UDFPARTITIONINTEGRITYDESC; +AssertCompileMemberOffset(UDFPARTITIONINTEGRITYDESC, abImplementationUse, 0x100); +/** Pointer to an UDF partition integrity descriptor. */ +typedef UDFPARTITIONINTEGRITYDESC *PUDFPARTITIONINTEGRITYDESC; +/** Pointer to a const UDF partition integrity descriptor. */ +typedef UDFPARTITIONINTEGRITYDESC const *PCUDFPARTITIONINTEGRITYDESC; + + +/** + * UDF extended file entry (EFE) (@ecma167{4,14.17,120}, @udf260{3.3.5,83}). + * + * @note Total length shall not exceed one logical block. + */ +typedef struct UDFEXFILEENTRY +{ + /** 0x00: The descriptor tag (UDF_TAG_ID_EXTENDED_FILE_ENTRY). */ + UDFTAG Tag; + /** 0x10: ICB Tag. */ + UDFICBTAG IcbTag; + /** 0x24: User ID (UNIX). */ + uint32_t uid; + /** 0x28: Group ID (UNIX). */ + uint32_t gid; + /** 0x2c: Permission (UDF_PERM_XXX). */ + uint32_t fPermissions; + /** 0x30: Number hard links. */ + uint16_t cHardlinks; + /** 0x32: Record format (UDF_REC_FMT_XXX). */ + uint8_t uRecordFormat; + /** 0x33: Record format (UDF_REC_FMT_XXX). */ + uint8_t fRecordDisplayAttribs; + /** 0x34: Record length (in bytes). + * @note Must be zero according to the UDF specification. */ + uint32_t cbRecord; + /** 0x38: Information length in bytes (file size). */ + uint64_t cbData; + /** 0x40: The size of all streams. Same as cbData if no additional streams. */ + uint64_t cbObject; + /** 0x48: Number of logical blocks allocated (for file data). */ + uint64_t cLogicalBlocks; + /** 0x50: Time of last access (prior to recording the file entry). */ + UDFTIMESTAMP AccessTime; + /** 0x5c: Time of last data modification. */ + UDFTIMESTAMP ModificationTime; + /** 0x68: Birth (creation) time. */ + UDFTIMESTAMP BirthTime; + /** 0x74: Time of last attribute/status modification. */ + UDFTIMESTAMP ChangeTime; + /** 0x80: Checkpoint number (defaults to 1). */ + uint32_t uCheckpoint; + /** 0x84: Reserved, MBZ. */ + uint32_t uReserved; + /** 0x88: Extended attribute information control block location. */ + UDFLONGAD ExtAttribIcb; + /** 0x98: Stream directory information control block location. */ + UDFLONGAD StreamDirIcb; + /** 0xa8: Implementation identifier (UDF_ENTITY_ID_FE_IMPLEMENTATION). */ + UDFENTITYID idImplementation; + /** 0xc8: Unique ID. */ + uint64_t INodeId; + /** 0xd0: Length of extended attributes in bytes, multiple of four. */ + uint32_t cbExtAttribs; + /** 0xd4: Length of allocation descriptors in bytes, multiple of four. */ + uint32_t cbAllocDescs; + /** 0xd8: Two variable sized fields. First @a cbExtAttribs bytes of extended + * attributes, then @a cbAllocDescs bytes of allocation descriptors. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abExtAttribs[RT_FLEXIBLE_ARRAY]; +} UDFEXFILEENTRY; +AssertCompileMemberOffset(UDFEXFILEENTRY, abExtAttribs, 0xd8); +/** Pointer to an UDF extended file entry. */ +typedef UDFEXFILEENTRY *PUDFEXFILEENTRY; +/** Pointer to a const UDF extended file entry. */ +typedef UDFEXFILEENTRY const *PCUDFEXFILEENTRY; + + + +/** @name UDF Volume Recognition Sequence (VRS) + * + * The recognition sequence usually follows the CD001 descriptor sequence at + * sector 16 and is there to indicate that the medium (also) contains a UDF file + * system and which standards are involved. + * + * See @ecma167{2,8,31}, @ecma167{2,9,32}, @udf260{2.1.7,25}. + * + * @{ */ + +/** The type value used for all the extended UDF volume descriptors + * (ISO9660VOLDESCHDR::bDescType). */ +#define UDF_EXT_VOL_DESC_TYPE 0 +/** The version value used for all the extended UDF volume descriptors + * (ISO9660VOLDESCHDR::bDescVersion). */ +#define UDF_EXT_VOL_DESC_VERSION 1 + +/** Standard ID for UDFEXTVOLDESCBEGIN. */ +#define UDF_EXT_VOL_DESC_STD_ID_BEGIN "BEA01" +/** Standard ID for UDFEXTVOLDESCTERM. */ +#define UDF_EXT_VOL_DESC_STD_ID_TERM "TEA01" +/** Standard ID for UDFEXTVOLDESCNSR following ECMA-167 2nd edition. */ +#define UDF_EXT_VOL_DESC_STD_ID_NSR_02 "NSR02" +/** Standard ID for UDFEXTVOLDESCNSR following ECMA-167 3rd edition. */ +#define UDF_EXT_VOL_DESC_STD_ID_NSR_03 "NSR03" +/** Standard ID for UDFEXTVOLDESCBOOT. */ +#define UDF_EXT_VOL_DESC_STD_ID_BOOT "BOOT2" + + +/** + * Begin UDF extended volume descriptor area (@ecma167{2,9.2,33}). + */ +typedef struct UDFEXTVOLDESCBEGIN +{ + /** The volume descriptor header. + * The standard identifier is UDF_EXT_VOL_DESC_STD_ID_BEGIN. */ + ISO9660VOLDESCHDR Hdr; + /** Zero payload. */ + uint8_t abZero[2041]; +} UDFEXTVOLDESCBEGIN; +AssertCompileSize(UDFEXTVOLDESCBEGIN, 2048); +/** Pointer to an UDF extended volume descriptor indicating the start of the + * extended descriptor area. */ +typedef UDFEXTVOLDESCBEGIN *PUDFEXTVOLDESCBEGIN; +/** Pointer to a const UDF extended volume descriptor indicating the start of + * the extended descriptor area. */ +typedef UDFEXTVOLDESCBEGIN const *PCUDFEXTVOLDESCBEGIN; + + +/** + * Terminate UDF extended volume descriptor area (@ecma167{2,9.3,33}). + */ +typedef struct UDFEXTVOLDESCTERM +{ + /** The volume descriptor header. + * The standard identifier is UDF_EXT_VOL_DESC_STD_ID_TERM. */ + ISO9660VOLDESCHDR Hdr; + /** Zero payload. */ + uint8_t abZero[2041]; +} UDFEXTVOLDESCTERM; +AssertCompileSize(UDFEXTVOLDESCTERM, 2048); +/** Pointer to an UDF extended volume descriptor indicating the end of the + * extended descriptor area. */ +typedef UDFEXTVOLDESCTERM *PUDFEXTVOLDESCTERM; +/** Pointer to a const UDF extended volume descriptor indicating the end of + * the extended descriptor area. */ +typedef UDFEXTVOLDESCTERM const *PCUDFEXTVOLDESCTERM; + + +/** + * UDF NSR extended volume descriptor (@ecma167{3,9.1,50}). + * + * This gives the ECMA standard version. + */ +typedef struct UDFEXTVOLDESCNSR +{ + /** The volume descriptor header. + * The standard identifier is UDF_EXT_VOL_DESC_STD_ID_NSR_02, or + * UDF_EXT_VOL_DESC_STD_ID_NSR_03. */ + ISO9660VOLDESCHDR Hdr; + /** Zero payload. */ + uint8_t abZero[2041]; +} UDFEXTVOLDESCNSR; +AssertCompileSize(UDFEXTVOLDESCNSR, 2048); +/** Pointer to an extended volume descriptor giving the UDF standard version. */ +typedef UDFEXTVOLDESCNSR *PUDFEXTVOLDESCNSR; +/** Pointer to a const extended volume descriptor giving the UDF standard version. */ +typedef UDFEXTVOLDESCNSR const *PCUDFEXTVOLDESCNSR; + + +/** + * UDF boot extended volume descriptor (@ecma167{2,9.4,34}). + * + * @note Probably entirely unused. + */ +typedef struct UDFEXTVOLDESCBOOT +{ + /** 0x00: The volume descriptor header. + * The standard identifier is UDF_EXT_VOL_DESC_STD_ID_BOOT. */ + ISO9660VOLDESCHDR Hdr; + /** 0x07: Reserved/alignment, MBZ. */ + uint8_t bReserved1; + /** 0x08: The architecture type. */ + UDFENTITYID ArchType; + /** 0x28: The boot identifier. */ + UDFENTITYID idBoot; + /** 0x48: Logical sector number of load the boot loader from. */ + uint32_t offBootExtent; + /** 0x4c: Number of bytes to load. */ + uint32_t cbBootExtent; + /** 0x50: The load address (in memory). */ + uint64_t uLoadAddress; + /** 0x58: The start address (in memory). */ + uint64_t uStartAddress; + /** 0x60: The descriptor creation timestamp. */ + UDFTIMESTAMP CreationTimestamp; + /** 0x6c: Flags. */ + uint16_t fFlags; + /** 0x6e: Reserved, MBZ. */ + uint8_t abReserved2[32]; + /** 0x8e: Implementation use. */ + uint8_t abBootUse[1906]; +} UDFEXTVOLDESCBOOT; +AssertCompileSize(UDFEXTVOLDESCBOOT, 2048); +/** Pointer to a boot extended volume descriptor. */ +typedef UDFEXTVOLDESCBOOT *PUDFEXTVOLDESCBOOT; +/** Pointer to a const boot extended volume descriptor. */ +typedef UDFEXTVOLDESCBOOT const *PCUDFEXTVOLDESCBOOT; + +/** @} */ + + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_udf_h */ + diff --git a/include/iprt/formats/wim.h b/include/iprt/formats/wim.h new file mode 100644 index 00000000..b0fb7036 --- /dev/null +++ b/include/iprt/formats/wim.h @@ -0,0 +1,160 @@ +/** @file + * IPRT - Windows Imaging (WIM) format. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_wim_h +#define IPRT_INCLUDED_formats_wim_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> +#include <iprt/uuid.h> + + +/** @defgroup grp_rt_formats_win Windows Imaging (WIM) format + * @ingroup grp_rt_formats + * + * Specification: + * http://download.microsoft.com/download/f/e/f/fefdc36e-392d-4678-9e4e-771ffa2692ab/Windows%20Imaging%20File%20Format.rtf + * + * @{ */ + + +/** + * A short WIM resource entry. + * + * This is a simplified version of the specs. + */ +typedef struct RESHDRDISKSHORT +{ + /** 0x00 - The compressed size. */ + RT_GCC_EXTENSION + uint64_t cb : 56; + /** 0x07 - Flags, RESHDR_FLAGS_XXX. */ + RT_GCC_EXTENSION + uint64_t bFlags : 8; + /** 0x08 - Offset. + * @note This is signed in the specficiation... */ + uint64_t off; + /** 0x10 - The uncompressed original size. + * @note This is signed in the specficiation... */ + uint64_t cbOriginal; +} RESHDRDISKSHORT; +AssertCompileSize(RESHDRDISKSHORT, 0x18); +/** Pointer to a short WIM resource entry. */ +typedef RESHDRDISKSHORT *PRESHDRDISKSHORT; +/** Pointer to a const short WIM resource entry. */ +typedef RESHDRDISKSHORT *PCRESHDRDISKSHORT; + +/** @name RESHDR_FLAGS_XXX + * @{ */ +#define RESHDR_FLAGS_FREE UINT8_C(0x01) +#define RESHDR_FLAGS_METADATA UINT8_C(0x02) +#define RESHDR_FLAGS_COMPRESSED UINT8_C(0x04) +#define RESHDR_FLAGS_SPANNED UINT8_C(0x08) +/** @} */ + +/** + * WIM file header, version 1. + * + * The field names have been normalized to our coding style. + */ +#pragma pack(4) +typedef struct WIMHEADERV1 +{ + /** 0x00 - Magic value WIMHEADER_MAGIC. */ + char szMagic[8]; + /** 0x08 - The size of this header structure. */ + uint32_t cbHeader; + /** 0x0c - The header version structure. */ + uint32_t uVersion; + /** 0x10 - Flags. */ + uint32_t fFlags; + /** 0x14 - ??. */ + uint32_t cbCompression; + /** 0x18 - Unique identifier. */ + RTUUID WIMGuid; + /** 0x28 - Part number in spanned (split) wim set. Unsplit use part number 1. */ + uint16_t idxPartNumber; + /** 0x2a - Total number of parts in spanned set. */ + uint16_t cTotalParts; + /** 0x2c - Number of images in the archive. */ + uint32_t cImages; + /** 0x30 - Resource lookup table offset & size. */ + RESHDRDISKSHORT OffsetTable; + /** 0x48 - XML data offset & size. */ + RESHDRDISKSHORT XmlData; + /** 0x60 - Boot metadata offset & size. */ + RESHDRDISKSHORT BootMetadata; + /** 0x78 - Bootable image index, zero if no bootable image. */ + uint32_t idxBoot; + /** 0x7c - Integrity data offset & size. + * @note Misaligned! */ + RESHDRDISKSHORT Integrity; + /** 0x94 - Reserved */ + uint8_t abUnused[60]; +} WIMHEADERV1; +#pragma pack() +AssertCompileSize(WIMHEADERV1, 0xd0); +/** Pointer to a XAR header. */ +typedef WIMHEADERV1 *PWIMHEADERV1; +/** Pointer to a const XAR header. */ +typedef WIMHEADERV1 const *PCWIMHEADERV1; + +/** The WIMHEADERV1::szMagic value. */ +#define WIMHEADER_MAGIC "MSWIM\0\0" +AssertCompile(sizeof(WIMHEADER_MAGIC) == 8); + +/** @name WIMHEADER_FLAGS_XXX - WINHEADERV1::fFlags. + * @note Specfication names these FLAG_HEADER_XXX. + * @{ */ +#define WIMHEADER_FLAGS_RESERVED RT_BIT_32(0) +#define WIMHEADER_FLAGS_COMPRESSION RT_BIT_32(1) +#define WIMHEADER_FLAGS_READONLY RT_BIT_32(2) +#define WIMHEADER_FLAGS_SPANNED RT_BIT_32(3) +#define WIMHEADER_FLAGS_RESOURCE_ONLY RT_BIT_32(4) +#define WIMHEADER_FLAGS_METADATA_ONLY RT_BIT_32(5) +#define WIMHEADER_FLAGS_WRITE_IN_PROGRESS RT_BIT_32(5) +#define WIMHEADER_FLAGS_RP_FIX RT_BIT_32(6) +#define WIMHEADER_FLAGS_COMPRESS_RESERVED RT_BIT_32(16) +#define WIMHEADER_FLAGS_COMPRESS_XPRESS RT_BIT_32(17) +#define WIMHEADER_FLAGS_COMPRESS_LZX RT_BIT_32(18) +/** @} */ + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_wim_h */ + diff --git a/include/iprt/formats/xar.h b/include/iprt/formats/xar.h new file mode 100644 index 00000000..9b3b85c4 --- /dev/null +++ b/include/iprt/formats/xar.h @@ -0,0 +1,90 @@ +/** @file + * IPRT - Extensible Archiver (XAR) format. + */ + +/* + * Copyright (C) 2013-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_xar_h +#define IPRT_INCLUDED_formats_xar_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_rt_formats_xar Extensible Archive (XAR) format + * @ingroup grp_rt_formats + * + * @{ */ + +#pragma pack(4) /* Misdesigned header, not 8-byte aligned size. */ +typedef struct XARHEADER +{ + /** The magic number 'xar!' (XAR_HEADER_MAGIC). */ + uint32_t u32Magic; + /** The size of this header structure. */ + uint16_t cbHeader; + /** The header version structure. */ + uint16_t uVersion; + /** The size of the compressed table of content (TOC). */ + uint64_t cbTocCompressed; + /** The size of the table of context (TOC) when not compressed. */ + uint64_t cbTocUncompressed; + /** Which cryptographic hash function is used (XAR_HASH_XXX). */ + uint32_t uHashFunction; +} XARHEADER; +#pragma pack() +AssertCompileSize(XARHEADER, 28); +/** Pointer to a XAR header. */ +typedef XARHEADER *PXARHEADER; +/** Pointer to a const XAR header. */ +typedef XARHEADER const *PCXARHEADER; + +/** XAR magic value (on disk endian). */ +#define XAR_HEADER_MAGIC RT_H2LE_U32(RT_MAKE_U32_FROM_U8('x', 'a', 'r', '!')) +/** The current header version value (host endian). */ +#define XAR_HEADER_VERSION 1 + +/** @name XAR hashing functions. + * @{ */ +#define XAR_HASH_NONE 0 +#define XAR_HASH_SHA1 1 +#define XAR_HASH_MD5 2 +#define XAR_HASH_MAX 2 +/** @} */ + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_xar_h */ + diff --git a/include/iprt/formats/xfs.h b/include/iprt/formats/xfs.h new file mode 100644 index 00000000..a50d6b9f --- /dev/null +++ b/include/iprt/formats/xfs.h @@ -0,0 +1,721 @@ +/* $Id: xfs.h $ */ +/** @file + * IPRT, XFS format. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_formats_xfs_h +#define IPRT_INCLUDED_formats_xfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_rt_formats_xfs XFS filesystem structures and definitions + * @ingroup grp_rt_formats + * @{ + */ + +/* + * The filesystem structures were retrieved from: + * http://xfs.org/docs/xfsdocs-xml-dev/XFS_Filesystem_Structure//tmp/en-US/html/index.html and + * https://elixir.bootlin.com/linux/v4.9/source/fs/xfs/libxfs/xfs_format.h and + * https://righteousit.wordpress.com/ + */ + +/** XFS superblock offset from the beginning of the volume, this is constant. */ +#define XFS_SB_OFFSET UINT64_C(0) + +/** @name Common XFS types as defined in the spec. + * @{ */ +/** Unsigned 64 bit absolute inode number. */ +typedef uint64_t XFSINO; +/** Signed 64 bit file offset. */ +typedef int64_t XFSFOFF; +/** Signed 64 bit disk address. */ +typedef int64_t XFSDADDR; +/** Unsinged 32 bit allocation group (AG) number. */ +typedef uint32_t XFSAGNUMBER; +/** Unsigned 32 bit AG relative block number. */ +typedef uint32_t XFSAGBLOCK; +/** Unsigned 32 bit extent length in blocks. */ +typedef uint32_t XFSEXTLEN; +/** Signed 32 bit number of extents in a file. */ +typedef int32_t XFSEXTNUM; +/** Unsigned 32 bit block number for directories and extended attributes. */ +typedef uint32_t XFSDABLK; +/** Unsigned 32 bit hash of a directory file name or extended attribute name. */ +typedef uint32_t XFSDAHASH; +/** Unsigned 64 bit filesystem block number combining AG number and block offset into the AG. */ +typedef uint64_t XFSDFSBNO; +/** Unsigned 64 bit raw filesystem block number. */ +typedef uint64_t XFSDRFSBNO; +/** Unsigned 64 bit extent number in the real-time device. */ +typedef uint64_t XFSDRTBNO; +/** Unsigned 64 bit block offset int oa file. */ +typedef uint64_t XFSDFILOFF; +/** Unsigned 64 bit block count for a file. */ +typedef uint64_t XFSDFILBLKS; +/** @} */ + +/** + * XFS superblock. + */ +#pragma pack(1) +typedef struct XFSSUPERBLOCK +{ + /** 0x00: Magic number to identify the superblock. */ + uint32_t u32Magic; + /** 0x04: Size of smallest allocation unit in bytes. */ + uint32_t cbBlock; + /** 0x04: Number of blocks available for data and metadata. */ + XFSDRFSBNO cBlocks; + /** 0x0c: Number of block in the real-time device. */ + XFSDRFSBNO cBlocksRtDev; + /** 0x14: Number of extents on real-time device. */ + XFSDRTBNO cExtentsRtDev; + /** 0x1c: UUID of the filesystem. */ + uint8_t abUuid[16]; + /** 0x2c: First block of the filesystem journal. */ + XFSDFSBNO uBlockJournal; + /** 0x34: Inode number of the root directory. */ + XFSINO uInodeRoot; + /** Inode for the real-time extent bitmap. */ + XFSINO uInodeBitmapRtExt; + /** Inode for the real-time bitmap summary. */ + XFSINO uInodeBitmapSummary; + /** Extent size on the real-time device in blocks. */ + XFSAGBLOCK cRtExtent; + /** Size of an AG in blocks. */ + XFSAGBLOCK cAgBlocks; + /** Number of AGs in hte filesystem. */ + XFSAGNUMBER cAg; + /** Number of real-time bitmap blocks. */ + XFSEXTLEN cRtBitmapBlocks; + /** Number of blocks for the journal. */ + XFSEXTLEN cJournalBlocks; + /** Version number (actually flag bitmaps of features). */ + uint16_t fVersion; + /** Sector size of the underlying medium. */ + uint16_t cbSector; + /** Size of an inode in bytes. */ + uint16_t cbInode; + /** Number of inodes stored in one block. */ + uint16_t cInodesPerBlock; + /** Name of the filesystem. */ + char achFsName[12]; + /** Block size as log2 (number of bits to shift left). */ + uint8_t cBlockSzLog; + /** Sector size as log2 (number of bits to shift left). */ + uint8_t cSectorSzLog; + /** Inode size as log2 (number of bits to shift left). */ + uint8_t cInodeSzLog; + /** Number of inodes per block as log2. */ + uint8_t cInodesPerBlockLog; + /** Number of AG blocks as log2 (number of bits to shift left). */ + uint8_t cAgBlocksLog; + /** Number of extent blocks as log2. */ + uint8_t cExtentsRtDevLog; + /** Flag when the filesystem is in the process of being created. */ + uint8_t fInProgress; + /** Maximum percentage of the filesystem usable for inodes. */ + uint8_t cInodeMaxPct; + /** Global number of inodes allocated (only mainted on the first superblock). */ + uint64_t cInodesGlobal; + /** Global number of free inodes (only mainted on the first superblock). */ + uint64_t cInodesGlobalFree; + /** Global count of free data blocks on the filesystem (only mainted on the first superblock). */ + uint64_t cBlocksFree; + /** Global count of free extents on the real-time device (only mainted on the first superblock). */ + uint64_t cExtentsRtFree; + /** Inode containing the user quotas. */ + XFSINO uInodeQuotaUsr; + /** Inode containing the group/project quotas. */ + XFSINO uInodeQuotaGrp; + /** Quota flags. */ + uint16_t fQuotaFlags; + /** Misc flags. */ + uint8_t fFlagsMisc; + /** Reserved MBZ. */ + uint8_t uSharedVn; + /** Number of filesystem blocks for the inode chunk alignment. */ + XFSEXTLEN cBlocksInodeAlignment; + /** Raid stripe size in blocks. */ + uint32_t cBlocksRaidStripe; + /** Raid width in number of blocks. */ + uint32_t cBlocksRaidWidth; + /** Multiplier for determining the allocation size for directory blocks as log2. */ + uint8_t cDirBlockAllocLog; + /** Sub volume sector size as log2 if an external journal device is used. */ + uint8_t cLogDevSubVolSectorSzLog; + /** Sector size of the device an external journal is stored as log2. */ + uint16_t cLogDevSectorSzLog; + /** Log devices stripe size. */ + uint32_t cLogDevRaidStripe; + /** Additional features which may be active. */ + uint32_t fFeatures2; + /** Padding. */ + uint32_t u32Padding0; + /** From here follow data only available from version 5 and later. */ + /** Read/Write feature flags. */ + uint32_t fFeaturesRw; + /** Read-only feature flags. */ + uint32_t fFeaturesRo; + /** Read/Write incompatible feature flags. */ + uint32_t fFeaturesIncompatRw; + /** Read/Write incompatible feature flags for the journal. */ + uint32_t fFeaturesJrnlIncompatRw; + /** CRC32 checksum for the superblock. */ + uint32_t u32Chksum; + /** Sparse inode alignment. */ + uint32_t u32SparseInodeAlignment; + /** Project quota inode. */ + XFSINO uInodeProjectQuota; + /** Log sequence number of last superblock update. */ + uint64_t uJrnlSeqSbUpdate; + /** UUID used when INCOMPAT_META_UUID is used. */ + uint8_t abUuidMeta[16]; + /** Inode if INCOMPATMETA_RMAPBT is used. */ + XFSINO uInodeRm; +} XFSSUPERBLOCK; +#pragma pack() +AssertCompileSize(XFSSUPERBLOCK, 272); +/** Pointer to an XFS superblock. */ +typedef XFSSUPERBLOCK *PXFSSUPERBLOCK; +/** Pointer to a const XFS superblock. */ +typedef const XFSSUPERBLOCK *PCXFSSUPERBLOCK; + +/** XFS superblock magic. */ +#define XFS_SB_MAGIC RT_MAKE_U32_FROM_U8('B', 'S', 'F', 'X') + +/** @name XFS_SB_VERSION_F_XXX - Version/Feature flags. + * @{ */ +/** Retrieves the version part of the field. */ +#define XFS_SB_VERSION_GET(a_fVersion) ((a_fVersion) & 0xf) +/** Version number for filesystem 5.3, 6.0.1 and 6.1. */ +#define XFS_SB_VERSION_1 1 +/** Version number for filesystem 6.2 - attributes. */ +#define XFS_SB_VERSION_2 2 +/** Version number for filesystem 6.2 - new inode version. */ +#define XFS_SB_VERSION_3 3 +/** Version number for filesystem 6.2+ - new bitmask version. */ +#define XFS_SB_VERSION_4 4 +/** Introduced checksums in the metadata. */ +#define XFS_SB_VERSION_5 5 +/** Extended attributes are used for at least one inode. */ +#define XFS_SB_VERSION_F_ATTR RT_BIT_32(4) +/** At least one inode use 32-bit nlink values. */ +#define XFS_SB_VERSION_F_NLINK RT_BIT_32(5) +/** Quotas are enabled on the filesystem. */ +#define XFS_SB_VERSION_F_QUOTA RT_BIT_32(6) +/** Set if XFSSUPERBLOCK::cBlocksInodeAlignment is used. */ +#define XFS_SB_VERSION_F_ALIGN RT_BIT_32(7) +/** Set if XFSSUPERBLOCK::cBlocksRaidStripe and XFSSUPERBLOCK::cBlocksRaidWidth are used. */ +#define XFS_SB_VERSION_F_DALIGN RT_BIT_32(8) +/** Set if XFSSUPERBLOCK::uSharedVn is used. */ +#define XFS_SB_VERSION_F_SHARED RT_BIT_32(9) +/** Version 2 journaling is used. */ +#define XFS_SB_VERSION_F_LOGV2 RT_BIT_32(10) +/** Set if sector size is not 512 bytes. */ +#define XFS_SB_VERSION_F_SECTOR RT_BIT_32(11) +/** Set if unwritten extents are used (always set). */ +#define XFS_SB_VERSION_F_EXTFLG RT_BIT_32(12) +/** Version 2 directories are used (always set). */ +#define XFS_SB_VERSION_F_DIRV2 RT_BIT_32(13) +/** Set if XFSSUPERBLOCK::fFeatures2 is used. */ +#define XFS_SB_VERSION_F_FEAT2 RT_BIT_32(14) +/** @} */ + +/** @name XFS_SB_QUOTA_F_XXX - Quota flags + * @{ */ +/** User quota accounting enabled. */ +#define XFS_SB_QUOTA_F_USR_ACCT RT_BIT(0) +/** User quotas are enforced. */ +#define XFS_SB_QUOTA_F_USR_ENFD RT_BIT(1) +/** User quotas have been checked and updated on disk. */ +#define XFS_SB_QUOTA_F_USR_CHKD RT_BIT(2) +/** Project quota accounting is enabled. */ +#define XFS_SB_QUOTA_F_PROJ_ACCT RT_BIT(3) +/** Other quotas are enforced. */ +#define XFS_SB_QUOTA_F_OTH_ENFD RT_BIT(4) +/** Other quotas have been checked and updated on disk. */ +#define XFS_SB_QUOTA_F_OTH_CHKD RT_BIT(5) +/** Group quota accounting enabled. */ +#define XFS_SB_QUOTA_F_GRP_ACCT RT_BIT(6) +/** @} */ + +/** @name XFS_SB_FEATURES2_F_XXX - Additional features + * @{ */ +/** Global counters are lazy and are only updated when the filesystem is cleanly unmounted. */ +#define XFS_SB_FEATURES2_F_LAZYSBCOUNT RT_BIT_32(1) +/** Extended attributes version 2. */ +#define XFS_SB_FEATURES2_F_ATTR2 RT_BIT_32(3) +/** Parent pointers, inodes must have an extended attribute pointing to the parent inode. */ +#define XFS_SB_FEATURES2_F_PARENT RT_BIT_32(4) +/** @} */ + + +/** + * XFS AG free space block. + */ +typedef struct XFSAGF +{ + /** Magic number. */ + uint32_t u32Magic; + /** Header version number. */ + uint32_t uVersion; + /** AG number for the sector. */ + uint32_t uSeqNo; + /** Length of the AG in filesystem blocks. */ + uint32_t cLengthBlocks; + /** Block numbers for the roots of the free space B+trees. */ + uint32_t auRoots[3]; + /** Depths of the free space B+trees. */ + uint32_t acLvls[3]; + /** Index of the first free list block. */ + uint32_t idxFreeListFirst; + /** Index of the last free list block. */ + uint32_t idxFreeListLast; + /** Number of blocks in the free list. */ + uint32_t cFreeListBlocks; + /** Current number of free blocks in the AG. */ + uint32_t cFreeBlocks; + /** Longest number of contiguous free blocks in the AG. */ + uint32_t cFreeBlocksLongest; + /** Number of blocks used for the free space B+-trees. */ + uint32_t cBlocksBTrees; + /** UUID of filesystem the AG belongs to. */ + uint8_t abUuid[16]; + /** Number of blocks used for the reverse map. */ + uint32_t cBlocksRevMap; + /** Number of blocks used for the refcount B+-tree. */ + uint32_t cBlocksRefcountBTree; + /** Block number for the refcount tree root. */ + uint32_t uRootRefcount; + /** Depth of the refcount B+-tree. */ + uint32_t cLvlRefcount; + /** Reserved contiguous space for future extensions. */ + uint64_t au64Rsvd[14]; + /** Last write sequence number. */ + uint64_t uSeqNoLastWrite; + /** CRC of the AGF. */ + uint32_t uChkSum; + /** Padding to 64 bit alignment. */ + uint32_t uAlignment0; +} XFSAGF; +/** Pointer to a AG free space block. */ +typedef XFSAGF *PXFSAGF; +/** Poiner to a const AG free space block. */ +typedef const XFSAGF *PCXFSAGF; + +/** AGF magic. */ +#define XFS_AGF_MAGIC RT_MAKE_U32_FROM_U8('F', 'G', 'A', 'X') +/** The current valid AGF version. */ +#define XFS_AGF_VERSION 1 + + +/** + * XFS AG inode information. + */ +typedef struct XFSAGI +{ + /** Magic number. */ + uint32_t u32Magic; + /** Header version number. */ + uint32_t uVersion; + /** AG number for the sector. */ + uint32_t uSeqNo; + /** Length of the AG in filesystem blocks. */ + uint32_t cLengthBlocks; + /** Count of allocated inodes. */ + uint32_t cInodesAlloc; + /** Block number of the inode tree root. */ + uint32_t uRootInode; + /** Depth of the inode B+-tree. */ + uint32_t cLvlsInode; + /** Newest allocated inode. */ + uint32_t uInodeNew; + /** Last directory inode chunk. */ + uint32_t uInodeDir; + /** Hash table of unlinked but still referenced inodes. */ + uint32_t au32HashUnlinked[64]; + /** UUID of filesystem. */ + uint8_t abUuid[16]; + /** CRC of the AGI. */ + uint32_t uChkSum; + /** Padding. */ + uint32_t uAlignment0; + /** Last write sequence number. */ + uint64_t uSeqNoLastWrite; + /** Block number of the free inode tree. */ + uint32_t uRootFreeInode; + /** Depth of the free inode B+-tree. */ + uint32_t cLvlsFreeInode; +} XFSAGI; +/** Pointer to a AG inode information. */ +typedef XFSAGI *PXFSAGI; +/** Pointer to a const AG inode information. */ +typedef const XFSAGI *PCXFSAGI; + +/** AGI magic. */ +#define XFS_AGI_MAGIC RT_MAKE_U32_FROM_U8('I', 'G', 'A', 'X') +/** The current valid AGI version. */ +#define XFS_AGI_VERSION 1 + + +/** + * XFS timestamp structure. + */ +typedef struct XFSTIMESTAMP +{ + /** 0x00: The second part of the timestamp since the epoch. */ + int32_t cSecEpoch; + /** 0x04: Nanosecond part of the timestamp. */ + int32_t cNanoSec; +} XFSTIMESTAMP; +/** Pointer to a XFS timestamp. */ +typedef XFSTIMESTAMP *PXFSTIMESTAMP; +/** Poiner to a const CFS timestamp. */ +typedef const XFSTIMESTAMP *PCXFSTIMESTAMP; + + +/** + * The inode core structure. + */ +typedef struct XFSINODECORE +{ + /** 0x00: Magic value. */ + uint16_t u16Magic; + /** 0x02: File mode and access bits (XFS_INODE_MODE_XXX). */ + uint16_t fMode; + /** 0x04: Inode version. */ + int8_t iVersion; + /** 0x05: The format of the data fork. */ + int8_t enmFormat; + /** 0x06: Number of links to this inode from directories for v1 inodes. */ + uint16_t cOnLinks; + /** 0x08: Owners UID. */ + uint32_t uUid; + /** 0x0c: Owners GID. */ + uint32_t uGid; + /** 0x10: The number of links to this inode for v2 inodes. */ + uint32_t cLinks; + /** 0x14: Project ID for v2 inodes (not used for v1, low 16bits). */ + uint16_t uProjIdLow; + /** 0x16: Project ID for v2 inodes (not used for v1, high 16bits). */ + uint16_t uProjIdHigh; + /** 0x18: Padding. */ + uint8_t abPad0[6]; + /** 0x1e: Flush counter. */ + uint16_t cFlush; + /** 0x20: Last accessed timestamp. */ + XFSTIMESTAMP TsLastAccessed; + /** 0x28: Last modified timestamp. */ + XFSTIMESTAMP TsLastModified; + /** 0x30: Inode created/modified timestamp. */ + XFSTIMESTAMP TsCreatedModified; + /** 0x38: Number of bytes in the file. */ + uint64_t cbInode; + /** 0x40: Number of direct and B-Tree blocks used for the forks. */ + uint64_t cBlocks; + /** 0x48: Minimum extent size for the inode. */ + uint32_t cExtentBlocksMin; + /** 0x4c: Number of extents in the data fork. */ + uint32_t cExtentsData; + /** 0x50: Number of extents in the attribute fork. */ + uint16_t cExtentsAttr; + /** 0x52: Offset of the attribute fork from the start of the inode. */ + uint8_t offAttrFork; + /** 0x53: Attribute fork format. */ + int8_t enmFormatAttr; + /** 0x54: DMIG event mask. */ + uint32_t fEvtMaskDmig; + /** 0x58: DMIG state info. */ + uint16_t uStateDmig; + /** 0x5a: Inode flags. */ + uint16_t fFlags; + /** 0x5c: Generation number. */ + uint32_t cGeneration; + /** 0x60: AGI unlinked list pointer. */ + uint32_t offBlockUnlinkedNext; + /** The following fields are for v3 inodes only. */ + /** 0x64: The CRC of the inode. */ + uint32_t uChkSum; + /** 0x68: Number of attribute changes. */ + uint64_t cAttrChanges; + /** 0x70: Last flush sequence number. */ + uint64_t uFlushSeqNo; + /** 0x78: Additional flags. */ + uint64_t fFlags2; + /** 0x80: Basic COW extent size. */ + uint32_t cExtentCowMin; + /** 0x84: Padding for future expansion. */ + uint8_t abPad1[12]; + /** 0x90: Inode creation timestamp. */ + XFSTIMESTAMP TsCreation; + /** 0x98: The inode number. */ + uint64_t uInode; + /** 0x100: Filesystem UUID the inode belongs to. */ + uint8_t abUuid[16]; +} XFSINODECORE; +AssertCompileSizeAlignment(XFSINODECORE, 8); +/** Pointer to a inode core. */ +typedef XFSINODECORE *PXFSINODECORE; +/** Pointer to a const inode core. */ +typedef const XFSINODECORE *PCXFSINODECORE; + +/** Inode magic. */ +#define XFS_INODE_MAGIC RT_MAKE_U16_FROM_U8('N', 'I') + +/** @name XFS_INODE_MODE_XXX - File mode + * @{ */ +/** Others can execute the file. */ +#define XFS_INODE_MODE_EXEC_OTHER RT_BIT(0) +/** Others can write to the file. */ +#define XFS_INODE_MODE_WRITE_OTHER RT_BIT(1) +/** Others can read the file. */ +#define XFS_INODE_MODE_READ_OTHER RT_BIT(2) +/** Members of the same group can execute the file. */ +#define XFS_INODE_MODE_EXEC_GROUP RT_BIT(3) +/** Members of the same group can write to the file. */ +#define XFS_INODE_MODE_WRITE_GROUP RT_BIT(4) +/** Members of the same group can read the file. */ +#define XFS_INODE_MODE_READ_GROUP RT_BIT(5) +/** Owner can execute the file. */ +#define XFS_INODE_MODE_EXEC_OWNER RT_BIT(6) +/** Owner can write to the file. */ +#define XFS_INODE_MODE_WRITE_OWNER RT_BIT(7) +/** Owner can read the file. */ +#define XFS_INODE_MODE_READ_OWNER RT_BIT(8) +/** Sticky file mode. */ +#define XFS_INODE_MODE_STICKY RT_BIT(9) +/** File is set GID. */ +#define XFS_INODE_MODE_SET_GROUP_ID RT_BIT(10) +/** File is set UID. */ +#define XFS_INODE_MODE_SET_USER_ID RT_BIT(11) +/** @} */ + +/** @name XFS_INODE_MODE_TYPE_XXX - File type + * @{ */ +/** Inode represents a FIFO. */ +#define XFS_INODE_MODE_TYPE_FIFO UINT16_C(0x1000) +/** Inode represents a character device. */ +#define XFS_INODE_MODE_TYPE_CHAR UINT16_C(0x2000) +/** Inode represents a directory. */ +#define XFS_INODE_MODE_TYPE_DIR UINT16_C(0x4000) +/** Inode represents a block device. */ +#define XFS_INODE_MODE_TYPE_BLOCK UINT16_C(0x6000) +/** Inode represents a regular file. */ +#define XFS_INODE_MODE_TYPE_REGULAR UINT16_C(0x8000) +/** Inode represents a symlink. */ +#define XFS_INODE_MODE_TYPE_SYMLINK UINT16_C(0xa000) +/** Inode represents a socket. */ +#define XFS_INODE_MODE_TYPE_SOCKET UINT16_C(0xc000) +/** Returns the inode type from the combined mode field. */ +#define XFS_INODE_MODE_TYPE_GET_TYPE(a_Mode) ((a_Mode) & 0xf000) +/** @} */ + +/** @name XFS_INODE_FORMAT_XXX - Inode data fork format. + * @{ */ +/** Device node data. */ +#define XFS_INODE_FORMAT_DEV 0 +/** Inline data. */ +#define XFS_INODE_FORMAT_LOCAL 1 +/** Array of extent descriptors. */ +#define XFS_INODE_FORMAT_EXTENTS 2 +/** Data fork contains root of B-Tree. */ +#define XFS_INODE_FORMAT_BTREE 3 +/** Data fork contains UUID. */ +#define XFS_INODE_FORMAT_UUID 4 +/** @} */ + +/** @name XFS_INODE_F_XXX - Inode flags. + * @{ */ +/** File data blocks are stored in the real-time device area. */ +#define XFS_INODE_F_RTDEV RT_BIT(0) +/** File space has been pre-allocated. */ +#define XFS_INODE_F_PREALLOC RT_BIT(1) +/** Use new real-time bitmap format. */ +#define XFS_INODE_F_NEWRTBITMAP RT_BIT(2) +/** Inode is immutable. */ +#define XFS_INODE_F_IMMUTABLE RT_BIT(3) +/** Inode is append only. */ +#define XFS_INODE_F_APPEND RT_BIT(4) +/** Inode is written synchronously. */ +#define XFS_INODE_F_SYNC RT_BIT(5) +/** The last accessed timestamp is not updated. */ +#define XFS_INODE_F_NOATIME RT_BIT(6) +/** The inode is not dumpable via dump(1). */ +#define XFS_INODE_F_NODUMP RT_BIT(7) +/** Create with real-time bit set. */ +#define XFS_INODE_F_RTINHERIT RT_BIT(8) +/** Create with parents project ID. */ +#define XFS_INODE_F_PROJIDINHERIT RT_BIT(9) +/** Deny symlink creation. */ +#define XFS_INODE_F_NOSYMLINKS RT_BIT(10) +/** Inode extent size allocator hint. */ +#define XFS_INODE_F_EXTSIZEHINT RT_BIT(11) +/** Inode extent size is inherited. */ +#define XFS_INODE_F_EXTSIZEINHERIT RT_BIT(12) +/** Do not defrag/reorganize the inode. */ +#define XFS_INODE_F_NODEFRAG RT_BIT(13) +/** Use filestream allocator. */ +#define XFS_INODE_F_FILESTREAM RT_BIT(14) +/** @} */ + +/** @name XFS_INODE_F2_XXX - Inode flags number 2 (XFSINODECORE::fFlags2). + * @{ */ +/** Use DAX for the inode. */ +#define XFS_INODE_F2_DAX RT_BIT_64(0) +/** Blocks use reference counting for sharing. */ +#define XFS_INODE_F2_REFLINK RT_BIT_64(1) +/** Inode COW extent size hint is valid. */ +#define XFS_INODE_F2_COWEXTSIZEHINT RT_BIT_64(2) +/** @} */ + + +/** + * Inode B-Tree record. + */ +typedef struct XFSINODEBTREEREC +{ + /** 0x00: Starting inode number. */ + uint32_t uInodeStart; + /** 0x04: Version dependent data. */ + union + { + /** Full (old) version. */ + struct + { + /** 0x04: Number of free inodes. */ + uint32_t cInodesFree; + } Full; + /** Sparse (new) version. */ + struct + { + /** 0x04: Hole mask for sparse chunks. */ + uint16_t bmHoles; + /** 0x06: Total number of inodes. */ + uint8_t cInodes; + /** 0x07: Number of free inodes. */ + uint8_t cInodesFree; + } Sparse; + } u; + /** 0x08: Free inode mask. */ + uint64_t bmInodesFree; +} XFSINODEBTREEREC; +/** Pointer to an inode B-Tree record. */ +typedef XFSINODEBTREEREC *PXFSINODEBTREEREC; +/** Pointer to a const inode B-Tree record. */ +typedef const XFSINODEBTREEREC *PCXFSINODEBTREEREC; + + +/** + * XFS B+Tree root header. + */ +typedef struct XFSBTREEROOTHDR +{ + /** 0x00: Tree level. */ + uint16_t iLvl; + /** 0x02: Number of records. */ + uint16_t cRecs; +} XFSBTREEROOTHDR; +/** Pointer to a B+Tree root header */ +typedef XFSBTREEROOTHDR *PXFSBTREEROOTHDR; +/** Pointer to a const B+Tree root header. */ +typedef const XFSBTREEROOTHDR *PCXFSBTREEROOTHDR; + + +/** + * XFS B+Tree intermediate/leave node header. + */ +typedef struct XFSBTREENODEHDR +{ + /** 0x00: Magic identifying the node. */ + uint32_t u32Magic; + /** 0x04: Tree level. */ + uint16_t iLvl; + /** 0x06: Number of records. */ + uint16_t cRecs; + /** 0x08: Block number of the left sibling. */ + uint64_t uSibLeft; + /** 0x10: Block number of the right sibling. */ + uint64_t uSibRight; +} XFSBTREENODEHDR; +/** Pointer to a B+Tree intermediate/leave node header. */ +typedef XFSBTREENODEHDR *PXFSBTREENODEHDR; +/** Pointer to a const B+Tree intermediate/leave node header. */ +typedef const XFSBTREENODEHDR *PCXFSBTREENODEHDR; + +/** @name XFS_BTREENODEHDR_XXX - B+Tree node related defines. + * @{ */ +/** Magic for the tree node header. */ +#define XFS_BTREENODEHDR_MAGIC RT_MAKE_U32_FROM_U8('P', 'A', 'M', 'B') +/** @} */ + + +/** + * XFS Extent. + */ +typedef struct XFSEXTENT +{ + /** 0x00: Low 64 bits. */ + uint64_t u64Low; + /** 0x08: High 64 bits. */ + uint64_t u64High; +} XFSEXTENT; +/** Pointer to an XFS extent. */ +typedef XFSEXTENT *PXFSEXTENT; +/** Pointer to a const XFS extent. */ +typedef const XFSEXTENT *PCXFSEXTENT; + +/** @name XFS_EXTENT_XXX - Extent related getters. + * @{ */ +/** Returns whether the extent is allocated but unwritten (true) or a normal extent (false). */ +#define XFS_EXTENT_IS_UNWRITTEN(a_pExtent) (RT_BOOL((a_pExtent)->u64High & RT_BIT_64(63))) +/** Returns the number of blocks the extent covers. */ +#define XFS_EXTENT_GET_BLOCK_COUNT(a_pExtent) ((a_pExtent)->u64Low & UINT64_C(0x1fffff)) +/** Returns the absolute block number where the data is stored on the disk. */ +#define XFS_EXTENT_GET_DISK_BLOCK(a_pExtent) ( (((a_pExtent)->u64High & UINT64_C(0x1ff)) << 42) \ + | (((a_pExtent)->u64Low & UINT64_C(0xffffffffffe00000)) >> 21)) +/** Returns the logical inode block offset. */ +#define XFS_EXTENT_GET_LOGICAL_BLOCK(a_pExtent) (((a_pExtent)->u64High & UINT64_C(0x7ffffffffffffe00)) >> 9) +/** @} */ + +/** @} */ + +#endif /* !IPRT_INCLUDED_formats_xfs_h */ + diff --git a/include/iprt/fs.h b/include/iprt/fs.h new file mode 100644 index 00000000..03c4f370 --- /dev/null +++ b/include/iprt/fs.h @@ -0,0 +1,668 @@ +/** @file + * IPRT - Filesystem. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_fs_h +#define IPRT_INCLUDED_fs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/time.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_fs RTFs - Filesystem and Volume + * @ingroup grp_rt + * @{ + */ + + +/** @name Filesystem Object Mode Flags. + * + * There are two sets of flags: the unix mode flags and the dos attributes. + * + * APIs returning mode flags will provide both sets. + * + * When specifying mode flags to any API at least one of them must be given. If + * one set is missing the API will synthesize it from the one given if it + * requires it. + * + * Both sets match their x86 ABIs, the DOS/NT one is simply shifted up 16 bits. + * The DOS/NT range is bits 16 to 31 inclusively. The Unix range is bits 0 to 15 + * (inclusively). + * + * @remarks These constants have been comitted to a binary format and must not + * be changed in any incompatible ways. + * + * @{ + */ + +/** Set user id on execution (S_ISUID). */ +#define RTFS_UNIX_ISUID 0004000U +/** Set group id on execution (S_ISGID). */ +#define RTFS_UNIX_ISGID 0002000U +/** Sticky bit (S_ISVTX / S_ISTXT). */ +#define RTFS_UNIX_ISTXT 0001000U + +/** Owner RWX mask (S_IRWXU). */ +#define RTFS_UNIX_IRWXU 0000700U +/** Owner readable (S_IRUSR). */ +#define RTFS_UNIX_IRUSR 0000400U +/** Owner writable (S_IWUSR). */ +#define RTFS_UNIX_IWUSR 0000200U +/** Owner executable (S_IXUSR). */ +#define RTFS_UNIX_IXUSR 0000100U + +/** Group RWX mask (S_IRWXG). */ +#define RTFS_UNIX_IRWXG 0000070U +/** Group readable (S_IRGRP). */ +#define RTFS_UNIX_IRGRP 0000040U +/** Group writable (S_IWGRP). */ +#define RTFS_UNIX_IWGRP 0000020U +/** Group executable (S_IXGRP). */ +#define RTFS_UNIX_IXGRP 0000010U + +/** Other RWX mask (S_IRWXO). */ +#define RTFS_UNIX_IRWXO 0000007U +/** Other readable (S_IROTH). */ +#define RTFS_UNIX_IROTH 0000004U +/** Other writable (S_IWOTH). */ +#define RTFS_UNIX_IWOTH 0000002U +/** Other executable (S_IXOTH). */ +#define RTFS_UNIX_IXOTH 0000001U + +/** All UNIX access permission bits (0777). */ +#define RTFS_UNIX_ALL_ACCESS_PERMS 0000777U +/** All UNIX permission bits, including set id and sticky bits. */ +#define RTFS_UNIX_ALL_PERMS 0007777U + +/** Named pipe (fifo) (S_IFIFO). */ +#define RTFS_TYPE_FIFO 0010000U +/** Character device (S_IFCHR). */ +#define RTFS_TYPE_DEV_CHAR 0020000U +/** Directory (S_IFDIR). */ +#define RTFS_TYPE_DIRECTORY 0040000U +/** Block device (S_IFBLK). */ +#define RTFS_TYPE_DEV_BLOCK 0060000U +/** Regular file (S_IFREG). */ +#define RTFS_TYPE_FILE 0100000U +/** Symbolic link (S_IFLNK). */ +#define RTFS_TYPE_SYMLINK 0120000U +/** Socket (S_IFSOCK). */ +#define RTFS_TYPE_SOCKET 0140000U +/** Whiteout (S_IFWHT). */ +#define RTFS_TYPE_WHITEOUT 0160000U +/** Type mask (S_IFMT). */ +#define RTFS_TYPE_MASK 0170000U +/** The shift count to convert between RTFS_TYPE_MASK and DIRENTRYTYPE. */ +#define RTFS_TYPE_DIRENTRYTYPE_SHIFT 12 + +/** Unix attribute mask. */ +#define RTFS_UNIX_MASK 0xffffU +/** The mask of all the NT, OS/2 and DOS attributes. */ +#define RTFS_DOS_MASK (0x7fffU << RTFS_DOS_SHIFT) + +/** The shift value. */ +#define RTFS_DOS_SHIFT 16 +/** The mask of the OS/2 and DOS attributes. */ +#define RTFS_DOS_MASK_OS2 (0x003fU << RTFS_DOS_SHIFT) +/** The mask of the NT attributes. */ +#define RTFS_DOS_MASK_NT (0x7fffU << RTFS_DOS_SHIFT) + +/** Readonly object. */ +#define RTFS_DOS_READONLY (0x0001U << RTFS_DOS_SHIFT) +/** Hidden object. */ +#define RTFS_DOS_HIDDEN (0x0002U << RTFS_DOS_SHIFT) +/** System object. */ +#define RTFS_DOS_SYSTEM (0x0004U << RTFS_DOS_SHIFT) +/** Directory. */ +#define RTFS_DOS_DIRECTORY (0x0010U << RTFS_DOS_SHIFT) +/** Archived object. + * This bit is set by the filesystem after each modification of a file. */ +#define RTFS_DOS_ARCHIVED (0x0020U << RTFS_DOS_SHIFT) +/** Undocumented / Reserved, used to be the FAT volume label. */ +#define RTFS_DOS_NT_DEVICE (0x0040U << RTFS_DOS_SHIFT) +/** Normal object, no other attribute set (NT). */ +#define RTFS_DOS_NT_NORMAL (0x0080U << RTFS_DOS_SHIFT) +/** Temporary object (NT). */ +#define RTFS_DOS_NT_TEMPORARY (0x0100U << RTFS_DOS_SHIFT) +/** Sparse file (NT). */ +#define RTFS_DOS_NT_SPARSE_FILE (0x0200U << RTFS_DOS_SHIFT) +/** Reparse point (NT). */ +#define RTFS_DOS_NT_REPARSE_POINT (0x0400U << RTFS_DOS_SHIFT) +/** Compressed object (NT). + * For a directory, compression is the default for new files. */ +#define RTFS_DOS_NT_COMPRESSED (0x0800U << RTFS_DOS_SHIFT) +/** Physically offline data (NT). + * MSDN say, don't mess with this one. */ +#define RTFS_DOS_NT_OFFLINE (0x1000U << RTFS_DOS_SHIFT) +/** Not content indexed by the content indexing service (NT). */ +#define RTFS_DOS_NT_NOT_CONTENT_INDEXED (0x2000U << RTFS_DOS_SHIFT) +/** Encryped object (NT). + * For a directory, encrypted is the default for new files. */ +#define RTFS_DOS_NT_ENCRYPTED (0x4000U << RTFS_DOS_SHIFT) + +/** @} */ + + +/** @name Filesystem Object Type Predicates. + * @{ */ +/** Checks the mode flags indicate a named pipe (fifo) (S_ISFIFO). */ +#define RTFS_IS_FIFO(fMode) ( ((fMode) & RTFS_TYPE_MASK) == RTFS_TYPE_FIFO ) +/** Checks the mode flags indicate a character device (S_ISCHR). */ +#define RTFS_IS_DEV_CHAR(fMode) ( ((fMode) & RTFS_TYPE_MASK) == RTFS_TYPE_DEV_CHAR ) +/** Checks the mode flags indicate a directory (S_ISDIR). */ +#define RTFS_IS_DIRECTORY(fMode) ( ((fMode) & RTFS_TYPE_MASK) == RTFS_TYPE_DIRECTORY ) +/** Checks the mode flags indicate a block device (S_ISBLK). */ +#define RTFS_IS_DEV_BLOCK(fMode) ( ((fMode) & RTFS_TYPE_MASK) == RTFS_TYPE_DEV_BLOCK ) +/** Checks the mode flags indicate a regular file (S_ISREG). */ +#define RTFS_IS_FILE(fMode) ( ((fMode) & RTFS_TYPE_MASK) == RTFS_TYPE_FILE ) +/** Checks the mode flags indicate a symbolic link (S_ISLNK). */ +#define RTFS_IS_SYMLINK(fMode) ( ((fMode) & RTFS_TYPE_MASK) == RTFS_TYPE_SYMLINK ) +/** Checks the mode flags indicate a socket (S_ISSOCK). */ +#define RTFS_IS_SOCKET(fMode) ( ((fMode) & RTFS_TYPE_MASK) == RTFS_TYPE_SOCKET ) +/** Checks the mode flags indicate a whiteout (S_ISWHT). */ +#define RTFS_IS_WHITEOUT(fMode) ( ((fMode) & RTFS_TYPE_MASK) == RTFS_TYPE_WHITEOUT ) +/** @} */ + + +/** + * Filesystem type IDs returned by RTFsQueryType. + * + * This enum is subject to changes and must not be used as part of any ABI or + * binary format (file, network, etc). + * + * @remarks When adding new entries, please update RTFsTypeName(). Also, try + * add them to the most natural group. + */ +typedef enum RTFSTYPE +{ + /** Unknown file system. */ + RTFSTYPE_UNKNOWN = 0, + + /** Universal Disk Format. */ + RTFSTYPE_UDF, + /** ISO 9660, aka Compact Disc File System (CDFS). */ + RTFSTYPE_ISO9660, + /** Filesystem in Userspace. */ + RTFSTYPE_FUSE, + /** VirtualBox shared folders. */ + RTFSTYPE_VBOXSHF, + + /* Linux: */ + RTFSTYPE_EXT, + RTFSTYPE_EXT2, + RTFSTYPE_EXT3, + RTFSTYPE_EXT4, + RTFSTYPE_XFS, + RTFSTYPE_CIFS, + RTFSTYPE_SMBFS, + RTFSTYPE_TMPFS, + RTFSTYPE_SYSFS, + RTFSTYPE_PROC, + RTFSTYPE_OCFS2, + RTFSTYPE_BTRFS, + + /* Windows: */ + /** New Technology File System. */ + RTFSTYPE_NTFS, + /** FAT12, FAT16 and FAT32 lumped into one basket. + * The partition size limit of FAT12 and FAT16 will be the factor + * limiting the file size (except, perhaps for the 64KB cluster case on + * non-Windows hosts). */ + RTFSTYPE_FAT, + /** Extended File Allocation Table, main target are flash drives. */ + RTFSTYPE_EXFAT, + /** Resilient File System. */ + RTFSTYPE_REFS, + + /* Solaris: */ + /** Zettabyte File System. */ + RTFSTYPE_ZFS, + /** Unix File System. */ + RTFSTYPE_UFS, + /** Network File System. */ + RTFSTYPE_NFS, + + /* Mac OS X: */ + /** Hierarchical File System. */ + RTFSTYPE_HFS, + /** @todo RTFSTYPE_HFS_PLUS? */ + RTFSTYPE_APFS, + RTFSTYPE_AUTOFS, + RTFSTYPE_DEVFS, + + /* *BSD: */ + + /* OS/2: */ + /** High Performance File System. */ + RTFSTYPE_HPFS, + /** Journaled File System (v2). */ + RTFSTYPE_JFS, + + /** The end of valid Filesystem types IDs. */ + RTFSTYPE_END, + /** The usual 32-bit type blow up. */ + RTFSTYPE_32BIT_HACK = 0x7fffffff +} RTFSTYPE; +/** Pointer to a Filesystem type ID. */ +typedef RTFSTYPE *PRTFSTYPE; + + +/** + * The available additional information in a RTFSOBJATTR object. + */ +typedef enum RTFSOBJATTRADD +{ + /** No additional information is available / requested. */ + RTFSOBJATTRADD_NOTHING = 1, + /** The additional unix attributes (RTFSOBJATTR::u::Unix) are available / + * requested. */ + RTFSOBJATTRADD_UNIX, + /** The additional unix attributes (RTFSOBJATTR::u::UnixOwner) are + * available / requested. */ + RTFSOBJATTRADD_UNIX_OWNER, + /** The additional unix attributes (RTFSOBJATTR::u::UnixGroup) are + * available / requested. */ + RTFSOBJATTRADD_UNIX_GROUP, + /** The additional extended attribute size (RTFSOBJATTR::u::EASize) is available / requested. */ + RTFSOBJATTRADD_EASIZE, + /** The last valid item (inclusive). + * The valid range is RTFSOBJATTRADD_NOTHING thru RTFSOBJATTRADD_LAST. */ + RTFSOBJATTRADD_LAST = RTFSOBJATTRADD_EASIZE, + + /** The usual 32-bit hack. */ + RTFSOBJATTRADD_32BIT_SIZE_HACK = 0x7fffffff +} RTFSOBJATTRADD; + +/** The number of bytes reserved for the additional attribute union. */ +#define RTFSOBJATTRUNION_MAX_SIZE 128 + +/** + * Additional Unix Attributes (RTFSOBJATTRADD_UNIX). + */ +typedef struct RTFSOBJATTRUNIX +{ + /** The user owning the filesystem object (st_uid). + * This field is NIL_RTUID if not supported. */ + RTUID uid; + + /** The group the filesystem object is assigned (st_gid). + * This field is NIL_RTGID if not supported. */ + RTGID gid; + + /** Number of hard links to this filesystem object (st_nlink). + * This field is 1 if the filesystem doesn't support hardlinking or + * the information isn't available. + */ + uint32_t cHardlinks; + + /** The device number of the device which this filesystem object resides on (st_dev). + * This field is 0 if this information is not available. */ + RTDEV INodeIdDevice; + + /** The unique identifier (within the filesystem) of this filesystem object (st_ino). + * Together with INodeIdDevice, this field can be used as a OS wide unique id + * when both their values are not 0. + * This field is 0 if the information is not available. + * + * @remarks The special '..' dir always shows up with 0 on NTFS/Windows. */ + RTINODE INodeId; + + /** User flags (st_flags). + * This field is 0 if this information is not available. */ + uint32_t fFlags; + + /** The current generation number (st_gen). + * This field is 0 if this information is not available. */ + uint32_t GenerationId; + + /** The device number of a character or block device type object (st_rdev). + * This field is 0 if the file isn't of a character or block device type and + * when the OS doesn't subscribe to the major+minor device idenfication scheme. */ + RTDEV Device; +} RTFSOBJATTRUNIX; + + +/** + * Additional Unix Attributes (RTFSOBJATTRADD_UNIX_OWNER). + * + * @remarks This interface is mainly for TAR. + */ +typedef struct RTFSOBJATTRUNIXOWNER +{ + /** The user owning the filesystem object (st_uid). + * This field is NIL_UID if not supported. */ + RTUID uid; + /** The user name. + * Empty if not available or not supported, truncated if too long. */ + char szName[RTFSOBJATTRUNION_MAX_SIZE - sizeof(RTUID)]; +} RTFSOBJATTRUNIXOWNER; + + +/** + * Additional Unix Attributes (RTFSOBJATTRADD_UNIX_GROUP). + * + * @remarks This interface is mainly for TAR. + */ +typedef struct RTFSOBJATTRUNIXGROUP +{ + /** The user owning the filesystem object (st_uid). + * This field is NIL_GID if not supported. */ + RTGID gid; + /** The group name. + * Empty if not available or not supported, truncated if too long. */ + char szName[RTFSOBJATTRUNION_MAX_SIZE - sizeof(RTGID)]; +} RTFSOBJATTRUNIXGROUP; + + +/** + * Filesystem object attributes. + */ +typedef struct RTFSOBJATTR +{ + /** Mode flags (st_mode). RTFS_UNIX_*, RTFS_TYPE_*, and RTFS_DOS_*. */ + RTFMODE fMode; + + /** The additional attributes available. */ + RTFSOBJATTRADD enmAdditional; + + /** + * Additional attributes. + * + * Unless explicitly specified to an API, the API can provide additional + * data as it is provided by the underlying OS. + */ + union RTFSOBJATTRUNION + { + /** Additional Unix Attributes - RTFSOBJATTRADD_UNIX. */ + RTFSOBJATTRUNIX Unix; + /** Additional Unix Owner Attributes - RTFSOBJATTRADD_UNIX_OWNER. */ + RTFSOBJATTRUNIXOWNER UnixOwner; + /** Additional Unix Group Attributes - RTFSOBJATTRADD_UNIX_GROUP. */ + RTFSOBJATTRUNIXGROUP UnixGroup; + + /** + * Extended attribute size is available when RTFS_DOS_HAVE_EA_SIZE is set. + */ + struct RTFSOBJATTREASIZE + { + /** Size of EAs. */ + RTFOFF cb; + } EASize; + /** Reserved space. */ + uint8_t abReserveSpace[128]; + } u; +} RTFSOBJATTR; +/** Pointer to a filesystem object attributes structure. */ +typedef RTFSOBJATTR *PRTFSOBJATTR; +/** Pointer to a const filesystem object attributes structure. */ +typedef const RTFSOBJATTR *PCRTFSOBJATTR; + + +/** + * Filesystem object information structure. + * + * This is returned by the RTPathQueryInfo(), RTFileQueryInfo() and RTDirRead() APIs. + */ +typedef struct RTFSOBJINFO +{ + /** Logical size (st_size). + * For normal files this is the size of the file. + * For symbolic links, this is the length of the path name contained + * in the symbolic link. + * For other objects this fields needs to be specified. + */ + RTFOFF cbObject; + + /** Disk allocation size (st_blocks * DEV_BSIZE). */ + RTFOFF cbAllocated; + + /** Time of last access (st_atime). */ + RTTIMESPEC AccessTime; + + /** Time of last data modification (st_mtime). */ + RTTIMESPEC ModificationTime; + + /** Time of last status change (st_ctime). + * If not available this is set to ModificationTime. + */ + RTTIMESPEC ChangeTime; + + /** Time of file birth (st_birthtime). + * If not available this is set to ChangeTime. + */ + RTTIMESPEC BirthTime; + + /** Attributes. */ + RTFSOBJATTR Attr; + +} RTFSOBJINFO; +/** Pointer to a filesystem object information structure. */ +typedef RTFSOBJINFO *PRTFSOBJINFO; +/** Pointer to a const filesystem object information structure. */ +typedef const RTFSOBJINFO *PCRTFSOBJINFO; + + +#ifdef IN_RING3 + +/** + * Query the sizes of a filesystem. + * + * @returns iprt status code. + * @param pszFsPath Path within the mounted filesystem. + * @param pcbTotal Where to store the total filesystem space. (Optional) + * @param pcbFree Where to store the remaining free space in the filesystem. (Optional) + * @param pcbBlock Where to store the block size. (Optional) + * @param pcbSector Where to store the sector size. (Optional) + * + * @sa RTFileQueryFsSizes + */ +RTR3DECL(int) RTFsQuerySizes(const char *pszFsPath, PRTFOFF pcbTotal, RTFOFF *pcbFree, + uint32_t *pcbBlock, uint32_t *pcbSector); + +/** + * Query the mountpoint of a filesystem. + * + * @returns iprt status code. + * @returns VERR_BUFFER_OVERFLOW if cbMountpoint isn't enough. + * @param pszFsPath Path within the mounted filesystem. + * @param pszMountpoint Where to store the mountpoint path. + * @param cbMountpoint Size of the buffer pointed to by pszMountpoint. + */ +RTR3DECL(int) RTFsQueryMountpoint(const char *pszFsPath, char *pszMountpoint, size_t cbMountpoint); + +/** + * Query the label of a filesystem. + * + * @returns iprt status code. + * @returns VERR_BUFFER_OVERFLOW if cbLabel isn't enough. + * @param pszFsPath Path within the mounted filesystem. + * @param pszLabel Where to store the label. + * @param cbLabel Size of the buffer pointed to by pszLabel. + */ +RTR3DECL(int) RTFsQueryLabel(const char *pszFsPath, char *pszLabel, size_t cbLabel); + +/** + * Query the serial number of a filesystem. + * + * @returns iprt status code. + * @param pszFsPath Path within the mounted filesystem. + * @param pu32Serial Where to store the serial number. + */ +RTR3DECL(int) RTFsQuerySerial(const char *pszFsPath, uint32_t *pu32Serial); + +/** + * Query the name of the filesystem driver. + * + * @returns iprt status code. + * @returns VERR_BUFFER_OVERFLOW if cbFsDriver isn't enough. + * @param pszFsPath Path within the mounted filesystem. + * @param pszFsDriver Where to store the filesystem driver name. + * @param cbFsDriver Size of the buffer pointed to by pszFsDriver. + */ +RTR3DECL(int) RTFsQueryDriver(const char *pszFsPath, char *pszFsDriver, size_t cbFsDriver); + +/** + * Query the name of the filesystem the file is located on. + * + * @returns iprt status code. + * @param pszFsPath Path within the mounted filesystem. It must exist. + * In case this is a symlink, the file it refers to is + * evaluated. + * @param penmType Where to store the filesystem type, this is always + * set. See RTFSTYPE for the values. + */ +RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType); + +#endif /* IN_RING3 */ + +/** + * Gets the name of a filesystem type. + * + * @returns Pointer to a read-only string containing the name. + * @param enmType A valid filesystem ID. If outside the valid range, + * the returned string will be pointing to a static + * memory buffer which will be changed on subsequent + * calls to this function by any thread. + */ +RTDECL(const char *) RTFsTypeName(RTFSTYPE enmType); + +/** + * Filesystem properties. + */ +typedef struct RTFSPROPERTIES +{ + /** The maximum size of a filesystem object name. + * This does not include the '\\0'. */ + uint32_t cbMaxComponent; + + /** True if the filesystem is remote. + * False if the filesystem is local. */ + bool fRemote; + + /** True if the filesystem is case sensitive. + * False if the filesystem is case insensitive. */ + bool fCaseSensitive; + + /** True if the filesystem is mounted read only. + * False if the filesystem is mounted read write. */ + bool fReadOnly; + + /** True if the filesystem can encode unicode object names. + * False if it can't. */ + bool fSupportsUnicode; + + /** True if the filesystem is compressed. + * False if it isn't or we don't know. */ + bool fCompressed; + + /** True if the filesystem compresses of individual files. + * False if it doesn't or we don't know. */ + bool fFileCompression; + + /** @todo more? */ +} RTFSPROPERTIES; +/** Pointer to a filesystem properties structure. */ +typedef RTFSPROPERTIES *PRTFSPROPERTIES; +/** Pointer to a const filesystem properties structure. */ +typedef RTFSPROPERTIES const *PCRTFSPROPERTIES; + +#ifdef IN_RING3 + +/** + * Query the properties of a mounted filesystem. + * + * @returns iprt status code. + * @param pszFsPath Path within the mounted filesystem. + * @param pProperties Where to store the properties. + */ +RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProperties); + +/** + * Checks if the given volume is case sensitive or not. + * + * This may be misleading in some cases as we lack the necessary APIs to query + * the information on some system (or choose not to use them) and are instead + * returning the general position on case sensitive file name of the system. + * + * @returns @c true if case sensitive, @c false if not. + * @param pszFsPath Path within the mounted file system. + */ +RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath); + +/** + * Mountpoint enumerator callback. + * + * @returns iprt status code. Failure terminates the enumeration. + * @param pszMountpoint The mountpoint name. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTFSMOUNTPOINTENUM,(const char *pszMountpoint, void *pvUser)); +/** Pointer to a FNRTFSMOUNTPOINTENUM(). */ +typedef FNRTFSMOUNTPOINTENUM *PFNRTFSMOUNTPOINTENUM; + +/** + * Enumerate mount points. + * + * @returns iprt status code. + * @param pfnCallback The callback function. + * @param pvUser The user argument to the callback. + */ +RTR3DECL(int) RTFsMountpointsEnum(PFNRTFSMOUNTPOINTENUM pfnCallback, void *pvUser); + + +/** + * A /bin/ls clone. + * + * @returns Program exit code. + * + * @param cArgs The number of arguments. + * @param papszArgs The argument vector. (Note that this may be + * reordered, so the memory must be writable.) + */ +RTR3DECL(RTEXITCODE) RTFsCmdLs(unsigned cArgs, char **papszArgs); + +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_fs_h */ + diff --git a/include/iprt/fsisomaker.h b/include/iprt/fsisomaker.h new file mode 100644 index 00000000..5eb782ba --- /dev/null +++ b/include/iprt/fsisomaker.h @@ -0,0 +1,826 @@ +/** @file + * IPRT - ISO Image Maker. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_fsisomaker_h +#define IPRT_INCLUDED_fsisomaker_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/time.h> +#include <iprt/fs.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_fsisomaker RTFsIsoMaker - ISO Image Maker + * @ingroup grp_rt_fs + * @{ + */ + + +/** @name RTFSISOMAKER_NAMESPACE_XXX - Namespace selector. + * @{ + */ +#define RTFSISOMAKER_NAMESPACE_ISO_9660 RT_BIT_32(0) /**< The primary ISO-9660 namespace. */ +#define RTFSISOMAKER_NAMESPACE_JOLIET RT_BIT_32(1) /**< The joliet namespace. */ +#define RTFSISOMAKER_NAMESPACE_UDF RT_BIT_32(2) /**< The UDF namespace. */ +#define RTFSISOMAKER_NAMESPACE_HFS RT_BIT_32(3) /**< The HFS namespace */ +#define RTFSISOMAKER_NAMESPACE_ALL UINT32_C(0x0000000f) /**< All namespaces. */ +#define RTFSISOMAKER_NAMESPACE_VALID_MASK UINT32_C(0x0000000f) /**< Valid namespace bits. */ +/** @} */ + +/** Root directory configuration index. */ +#define RTFSISOMAKER_CFG_IDX_ROOT UINT32_C(0) + + +/** + * Creates an ISO maker instance. + * + * @returns IPRT status code. + * @param phIsoMaker Where to return the handle to the new ISO maker. + */ +RTDECL(int) RTFsIsoMakerCreate(PRTFSISOMAKER phIsoMaker); + +/** + * Retains a references to an ISO maker instance. + * + * @returns New reference count on success, UINT32_MAX if invalid handle. + * @param hIsoMaker The ISO maker handle. + */ +RTDECL(uint32_t) RTFsIsoMakerRetain(RTFSISOMAKER hIsoMaker); + +/** + * Releases a references to an ISO maker instance. + * + * @returns New reference count on success, UINT32_MAX if invalid handle. + * @param hIsoMaker The ISO maker handle. NIL is ignored. + */ +RTDECL(uint32_t) RTFsIsoMakerRelease(RTFSISOMAKER hIsoMaker); + +/** + * Sets the ISO-9660 level. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param uIsoLevel The level, 1-3. + */ +RTDECL(int) RTFsIsoMakerSetIso9660Level(RTFSISOMAKER hIsoMaker, uint8_t uIsoLevel); + +/** + * Gets the ISO-9660 level. + * + * @returns The level, UINT8_MAX if invalid handle. + * @param hIsoMaker The ISO maker handle. + */ +RTDECL(uint8_t) RTFsIsoMakerGetIso9660Level(RTFSISOMAKER hIsoMaker); + +/** + * Sets the joliet level. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param uJolietLevel The joliet UCS-2 level 1-3, or 0 to disable + * joliet. + */ +RTDECL(int) RTFsIsoMakerSetJolietUcs2Level(RTFSISOMAKER hIsoMaker, uint8_t uJolietLevel); + +/** + * Sets the rock ridge support level (on the primary ISO-9660 namespace). + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param uLevel 0 if disabled, 1 to just enable, 2 to enable and + * write the ER tag. + */ +RTDECL(int) RTFsIsoMakerSetRockRidgeLevel(RTFSISOMAKER hIsoMaker, uint8_t uLevel); + +/** + * Sets the rock ridge support level on the joliet namespace (experimental). + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param uLevel 0 if disabled, 1 to just enable, 2 to enable and + * write the ER tag. + */ +RTDECL(int) RTFsIsoMakerSetJolietRockRidgeLevel(RTFSISOMAKER hIsoMaker, uint8_t uLevel); + +/** + * Gets the rock ridge support level (on the primary ISO-9660 namespace). + * + * @returns 0 if disabled, 1 just enabled, 2 if enabled with ER tag, and + * UINT8_MAX if the handle is invalid. + * @param hIsoMaker The ISO maker handle. + */ +RTDECL(uint8_t) RTFsIsoMakerGetRockRidgeLevel(RTFSISOMAKER hIsoMaker); + +/** + * Gets the rock ridge support level on the joliet namespace (experimental). + * + * @returns 0 if disabled, 1 just enabled, 2 if enabled with ER tag, and + * UINT8_MAX if the handle is invalid. + * @param hIsoMaker The ISO maker handle. + */ +RTDECL(uint8_t) RTFsIsoMakerGetJolietRockRidgeLevel(RTFSISOMAKER hIsoMaker); + +/** + * Changes the file attribute (mode, owner, group) inherit style (from source). + * + * The strict style will use the exact attributes from the source, where as the + * non-strict (aka rational and default) style will use 0 for the owner and + * group IDs and normalize the mode bits along the lines of 'chmod a=rX', + * stripping set-uid/gid bitson files but preserving sticky ones on directories. + * + * When disabling strict style, the default dir and file modes will be restored + * to default values. + * + * @returns IRPT status code. + * @param hIsoMaker The ISO maker handle. + * @param fStrict Indicates strict (true) or non-strict (false) + * style. + */ +RTDECL(int) RTFsIsoMakerSetAttribInheritStyle(RTFSISOMAKER hIsoMaker, bool fStrict); + +/** + * Sets the default file mode settings. + * + * @returns IRPT status code. + * @param hIsoMaker The ISO maker handle. + * @param fMode The default file mode. + */ +RTDECL(int) RTFsIsoMakerSetDefaultFileMode(RTFSISOMAKER hIsoMaker, RTFMODE fMode); + +/** + * Sets the default dir mode settings. + * + * @returns IRPT status code. + * @param hIsoMaker The ISO maker handle. + * @param fMode The default dir mode. + */ +RTDECL(int) RTFsIsoMakerSetDefaultDirMode(RTFSISOMAKER hIsoMaker, RTFMODE fMode); + +/** + * Sets the forced file mode, if @a fForce is true also the default mode is set. + * + * @returns IRPT status code. + * @param hIsoMaker The ISO maker handle. + * @param fMode The file mode. + * @param fForce Indicate whether forced mode is active or not. + */ +RTDECL(int) RTFsIsoMakerSetForcedFileMode(RTFSISOMAKER hIsoMaker, RTFMODE fMode, bool fForce); + +/** + * Sets the forced dir mode, if @a fForce is true also the default mode is set. + * + * @returns IRPT status code. + * @param hIsoMaker The ISO maker handle. + * @param fMode The dir mode. + * @param fForce Indicate whether forced mode is active or not. + */ +RTDECL(int) RTFsIsoMakerSetForcedDirMode(RTFSISOMAKER hIsoMaker, RTFMODE fMode, bool fForce); + +/** + * Sets the content of the system area, i.e. the first 32KB of the image. + * + * This can be used to put generic boot related stuff. + * + * @note Other settings may overwrite parts of the content (yet to be + * determined which). + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param pvContent The content to put in the system area. + * @param cbContent The size of the content. + * @param off The offset into the system area. + */ +RTDECL(int) RTFsIsoMakerSetSysAreaContent(RTFSISOMAKER hIsoMaker, void const *pvContent, size_t cbContent, uint32_t off); + +/** + * String properties settable thru RTFsIsoMakerSetStringProp. + */ +typedef enum RTFSISOMAKERSTRINGPROP +{ + /** The customary invalid zero value. */ + RTFSISOMAKERSTRINGPROP_INVALID = 0, + /** The system identifier. */ + RTFSISOMAKERSTRINGPROP_SYSTEM_ID, + /** The volume identifier(label). */ + RTFSISOMAKERSTRINGPROP_VOLUME_ID, + /** The volume set identifier. */ + RTFSISOMAKERSTRINGPROP_VOLUME_SET_ID, + /** The publisher ID (root file reference if it starts with '_'). */ + RTFSISOMAKERSTRINGPROP_PUBLISHER_ID, + /** The data preparer ID (root file reference if it starts with '_'). */ + RTFSISOMAKERSTRINGPROP_DATA_PREPARER_ID, + /** The application ID (root file reference if it starts with '_'). */ + RTFSISOMAKERSTRINGPROP_APPLICATION_ID, + /** The copyright file ID. */ + RTFSISOMAKERSTRINGPROP_COPYRIGHT_FILE_ID, + /** The abstract file ID. */ + RTFSISOMAKERSTRINGPROP_ABSTRACT_FILE_ID, + /** The bibliographic file ID. */ + RTFSISOMAKERSTRINGPROP_BIBLIOGRAPHIC_FILE_ID, + /** End of valid string property values. */ + RTFSISOMAKERSTRINGPROP_END, + /** Make sure it's a 32-bit type. */ + RTFSISOMAKERSTRINGPROP_32BIT_HACK = 0x7fffffff +} RTFSISOMAKERSTRINGPROP; + +/** + * Sets a string property in one or more namespaces. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param enmStringProp The string property to set. + * @param fNamespaces The namespaces to set it in. + * @param pszValue The value to set it to. NULL is treated like an + * empty string. The value will be silently truncated + * to fit the available space. + */ +RTDECL(int) RTFsIsoMakerSetStringProp(RTFSISOMAKER hIsoMaker, RTFSISOMAKERSTRINGPROP enmStringProp, + uint32_t fNamespaces, const char *pszValue); + +/** + * Specifies image padding. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param cSectors Number of sectors to pad the image with. + */ +RTDECL(int) RTFsIsoMakerSetImagePadding(RTFSISOMAKER hIsoMaker, uint32_t cSectors); + +/** + * Gets currently populated namespaces. + * + * @returns Set of namespaces (RTFSISOMAKER_NAMESPACE_XXX), UINT32_MAX on error. + * @param hIsoMaker The ISO maker handle. + */ +RTDECL(uint32_t) RTFsIsoMakerGetPopulatedNamespaces(RTFSISOMAKER hIsoMaker); + +/** + * Resolves a path into a object ID. + * + * This will be doing the looking up using the specified object names rather + * than the version adjusted and mangled according to the namespace setup. + * + * @returns The object ID corresponding to @a pszPath, or UINT32_MAX if not + * found or invalid parameters. + * @param hIsoMaker The ISO maker instance. + * @param fNamespaces The namespace to resolve @a pszPath in. It's + * possible to specify multiple namespaces here, of + * course, but that's inefficient. + * @param pszPath The path to the object. + */ +RTDECL(uint32_t) RTFsIsoMakerGetObjIdxForPath(RTFSISOMAKER hIsoMaker, uint32_t fNamespaces, const char *pszPath); + +/** + * Queries the configuration index of the boot catalog file object. + * + * The boot catalog file is created as necessary, thus this have to be a query + * rather than a getter since object creation may fail. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param pidxObj Where to return the configuration index. + */ +RTDECL(int) RTFsIsoMakerQueryObjIdxForBootCatalog(RTFSISOMAKER hIsoMaker, uint32_t *pidxObj); + +/** + * Removes the specified object from the image. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker instance. + * @param idxObj The index of the object to remove. + */ +RTDECL(int) RTFsIsoMakerObjRemove(RTFSISOMAKER hIsoMaker, uint32_t idxObj); + +/** + * Sets the path (name) of an object in the selected namespaces. + * + * The name will be transformed as necessary. + * + * The initial implementation does not allow this function to be called more + * than once on an object. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idxObj The configuration index of to name. + * @param fNamespaces The namespaces to apply the path to + * (RTFSISOMAKER_NAMESPACE_XXX). + * @param pszPath The path. + */ +RTDECL(int) RTFsIsoMakerObjSetPath(RTFSISOMAKER hIsoMaker, uint32_t idxObj, uint32_t fNamespaces, const char *pszPath); + +/** + * Sets the name of an object in the selected namespaces, placing it under the + * given directory. + * + * The name will be transformed as necessary. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idxObj The configuration index of to name. + * @param idxParentObj The parent directory object. + * @param fNamespaces The namespaces to apply the path to + * (RTFSISOMAKER_NAMESPACE_XXX). + * @param pszName The name. + * @param fNoNormalize Don't normalize the name (imported or such). + */ +RTDECL(int) RTFsIsoMakerObjSetNameAndParent(RTFSISOMAKER hIsoMaker, uint32_t idxObj, uint32_t idxParentObj, + uint32_t fNamespaces, const char *pszName, bool fNoNormalize); + +/** + * Changes the rock ridge name for the object in the selected namespaces. + * + * The object must already be enetered into the namespaces by + * RTFsIsoMakerObjSetNameAndParent, RTFsIsoMakerObjSetPath or similar. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idxObj The configuration index of to name. + * @param fNamespaces The namespaces to apply the path to + * (RTFSISOMAKER_NAMESPACE_XXX). + * @param pszRockName The rock ridge name. Passing NULL or an empty + * string will restore the specified name. + */ +RTDECL(int) RTFsIsoMakerObjSetRockName(RTFSISOMAKER hIsoMaker, uint32_t idxObj, uint32_t fNamespaces, const char *pszRockName); + +/** + * Enables or disable syslinux boot info table patching of a file. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idxObj The configuration index. + * @param fEnable Whether to enable or disable patching. + */ +RTDECL(int) RTFsIsoMakerObjEnableBootInfoTablePatching(RTFSISOMAKER hIsoMaker, uint32_t idxObj, bool fEnable); + +/** + * Gets the data size of an object. + * + * Currently only supported on file objects. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idxObj The configuration index. + * @param pcbData Where to return the size. + */ +RTDECL(int) RTFsIsoMakerObjQueryDataSize(RTFSISOMAKER hIsoMaker, uint32_t idxObj, uint64_t *pcbData); + +/** + * Adds an unnamed directory to the image. + * + * The directory must explictly be entered into the desired namespaces. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param pObjInfo Pointer to object attributes, must be set to + * UNIX. The size and hardlink counts are ignored. + * Optional. + * @param pidxObj Where to return the configuration index of the + * directory. + * @sa RTFsIsoMakerAddDir, RTFsIsoMakerObjSetPath + */ +RTDECL(int) RTFsIsoMakerAddUnnamedDir(RTFSISOMAKER hIsoMaker, PCRTFSOBJINFO pObjInfo, uint32_t *pidxObj); + +/** + * Adds a directory to the image in all namespaces and default attributes. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param pszDir The path (UTF-8) to the directory in the ISO. + * + * @param pidxObj Where to return the configuration index of the + * directory. Optional. + * @sa RTFsIsoMakerAddUnnamedDir, RTFsIsoMakerObjSetPath + */ +RTDECL(int) RTFsIsoMakerAddDir(RTFSISOMAKER hIsoMaker, const char *pszDir, uint32_t *pidxObj); + +/** + * Adds an unnamed file to the image that's backed by a host file. + * + * The file must explictly be entered into the desired namespaces. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param pszSrcFile The source file path. VFS chain spec allowed. + * @param pidxObj Where to return the configuration index of the + * directory. + * @sa RTFsIsoMakerAddFile, RTFsIsoMakerObjSetPath + */ +RTDECL(int) RTFsIsoMakerAddUnnamedFileWithSrcPath(RTFSISOMAKER hIsoMaker, const char *pszSrcFile, uint32_t *pidxObj); + +/** + * Adds an unnamed file to the image that's backed by a VFS file. + * + * The file must explictly be entered into the desired namespaces. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param hVfsFileSrc The source file handle. + * @param pidxObj Where to return the configuration index of the + * directory. + * @sa RTFsIsoMakerAddUnnamedFileWithSrcPath, RTFsIsoMakerObjSetPath + */ +RTDECL(int) RTFsIsoMakerAddUnnamedFileWithVfsFile(RTFSISOMAKER hIsoMaker, RTVFSFILE hVfsFileSrc, uint32_t *pidxObj); + +/** + * Adds an unnamed file to the image that's backed by a portion of a common + * source file. + * + * The file must explictly be entered into the desired namespaces. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param idxCommonSrc The common source file index. + * @param offData The offset of the data in the source file. + * @param cbData The file size. + * @param pObjInfo Pointer to file info. Optional. + * @param pidxObj Where to return the configuration index of the + * directory. + * @sa RTFsIsoMakerAddUnnamedFileWithSrcPath, RTFsIsoMakerObjSetPath + */ +RTDECL(int) RTFsIsoMakerAddUnnamedFileWithCommonSrc(RTFSISOMAKER hIsoMaker, uint32_t idxCommonSrc, + uint64_t offData, uint64_t cbData, PCRTFSOBJINFO pObjInfo, uint32_t *pidxObj); + +/** + * Adds a common source file. + * + * Using RTFsIsoMakerAddUnnamedFileWithCommonSrc a sections common source file + * can be referenced to make up other files. The typical use case is when + * importing data from an existing ISO. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param hVfsFile VFS handle of the common source. (A reference + * is added, none consumed.) + * @param pidxCommonSrc Where to return the assigned common source + * index. This is used to reference the file. + * @sa RTFsIsoMakerAddUnnamedFileWithCommonSrc + */ +RTDECL(int) RTFsIsoMakerAddCommonSourceFile(RTFSISOMAKER hIsoMaker, RTVFSFILE hVfsFile, uint32_t *pidxCommonSrc); + +/** + * Adds a file that's backed by a host file to the image in all namespaces and + * with attributes taken from the source file. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param pszFile The path to the file in the image. + * @param pszSrcFile The source file path. VFS chain spec allowed. + * @param pidxObj Where to return the configuration index of the file. + * Optional + * @sa RTFsIsoMakerAddFileWithVfsFile, + * RTFsIsoMakerAddUnnamedFileWithSrcPath + */ +RTDECL(int) RTFsIsoMakerAddFileWithSrcPath(RTFSISOMAKER hIsoMaker, const char *pszFile, const char *pszSrcFile, uint32_t *pidxObj); + +/** + * Adds a file that's backed by a VFS file to the image in all namespaces and + * with attributes taken from the source file. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param pszFile The path to the file in the image. + * @param hVfsFileSrc The source file handle. + * @param pidxObj Where to return the configuration index of the file. + * Optional. + * @sa RTFsIsoMakerAddUnnamedFileWithVfsFile, + * RTFsIsoMakerAddFileWithSrcPath + */ +RTDECL(int) RTFsIsoMakerAddFileWithVfsFile(RTFSISOMAKER hIsoMaker, const char *pszFile, RTVFSFILE hVfsFileSrc, uint32_t *pidxObj); + +/** + * Adds an unnamed symbolic link to the image. + * + * The symlink must explictly be entered into the desired namespaces. Please + * note that it is not possible to enter a symbolic link into an ISO 9660 + * namespace where rock ridge extensions are disabled, since symbolic links + * depend on rock ridge. For HFS and UDF there is no such requirement. + * + * Will fail if no namespace is configured that supports symlinks. + * + * @returns IPRT status code + * @retval VERR_ISOMK_SYMLINK_SUPPORT_DISABLED if not supported. + * @param hIsoMaker The ISO maker handle. + * @param pObjInfo Pointer to object attributes, must be set to + * UNIX. The size and hardlink counts are ignored. + * Optional. + * @param pszTarget The symbolic link target (UTF-8). + * @param pidxObj Where to return the configuration index of the + * directory. + * @sa RTFsIsoMakerAddSymlink, RTFsIsoMakerObjSetPath + */ +RTDECL(int) RTFsIsoMakerAddUnnamedSymlink(RTFSISOMAKER hIsoMaker, PCRTFSOBJINFO pObjInfo, const char *pszTarget, uint32_t *pidxObj); + +/** + * Adds a directory to the image in all namespaces and default attributes. + * + * Will fail if no namespace is configured that supports symlinks. + * + * @returns IPRT status code + * @param hIsoMaker The ISO maker handle. + * @param pszSymlink The path (UTF-8) to the symlink in the ISO. + * @param pszTarget The symlink target (UTF-8). + * @param pidxObj Where to return the configuration index of the + * directory. Optional. + * @sa RTFsIsoMakerAddUnnamedSymlink, RTFsIsoMakerObjSetPath + */ +RTDECL(int) RTFsIsoMakerAddSymlink(RTFSISOMAKER hIsoMaker, const char *pszSymlink, const char *pszTarget, uint32_t *pidxObj); + +/** + * Modifies the mode mask for a given path in one or more namespaces. + * + * The mode mask is used by rock ridge, UDF and HFS. + * + * @returns IPRT status code. + * @retval VWRN_NOT_FOUND if the path wasn't found in any of the specified + * namespaces. + * + * @param hIsoMaker The ISO maker handler. + * @param pszPath The path which mode mask should be modified. + * @param fNamespaces The namespaces to set it in. + * @param fSet The mode bits to set. + * @param fUnset The mode bits to clear (applied first). + * @param fFlags Reserved, MBZ. + * @param pcHits Where to return number of paths found. Optional. + */ +RTDECL(int) RTFsIsoMakerSetPathMode(RTFSISOMAKER hIsoMaker, const char *pszPath, uint32_t fNamespaces, + RTFMODE fSet, RTFMODE fUnset, uint32_t fFlags, uint32_t *pcHits); + +/** + * Modifies the owner ID for a given path in one or more namespaces. + * + * The owner ID is used by rock ridge, UDF and HFS. + * + * @returns IPRT status code. + * @retval VWRN_NOT_FOUND if the path wasn't found in any of the specified + * namespaces. + * + * @param hIsoMaker The ISO maker handler. + * @param pszPath The path which mode mask should be modified. + * @param fNamespaces The namespaces to set it in. + * @param idOwner The new owner ID to set. + * @param pcHits Where to return number of paths found. Optional. + */ +RTDECL(int) RTFsIsoMakerSetPathOwnerId(RTFSISOMAKER hIsoMaker, const char *pszPath, uint32_t fNamespaces, + RTUID idOwner, uint32_t *pcHits); + +/** + * Modifies the group ID for a given path in one or more namespaces. + * + * The group ID is used by rock ridge, UDF and HFS. + * + * @returns IPRT status code. + * @retval VWRN_NOT_FOUND if the path wasn't found in any of the specified + * namespaces. + * + * @param hIsoMaker The ISO maker handler. + * @param pszPath The path which mode mask should be modified. + * @param fNamespaces The namespaces to set it in. + * @param idGroup The new group ID to set. + * @param pcHits Where to return number of paths found. Optional. + */ +RTDECL(int) RTFsIsoMakerSetPathGroupId(RTFSISOMAKER hIsoMaker, const char *pszPath, uint32_t fNamespaces, + RTGID idGroup, uint32_t *pcHits); + +/** + * Set the validation entry of the boot catalog (this is the first entry). + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idPlatform The platform ID + * (ISO9660_ELTORITO_PLATFORM_ID_XXX). + * @param pszString CD/DVD-ROM identifier. Optional. + */ +RTDECL(int) RTFsIsoMakerBootCatSetValidationEntry(RTFSISOMAKER hIsoMaker, uint8_t idPlatform, const char *pszString); + +/** + * Set the validation entry of the boot catalog (this is the first entry). + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idxBootCat The boot catalog entry. Zero and two are + * invalid. Must be less than 63. + * @param idxImageObj The configuration index of the boot image. + * @param bBootMediaType The media type and flag (not for entry 1) + * (ISO9660_ELTORITO_BOOT_MEDIA_TYPE_XXX, + * ISO9660_ELTORITO_BOOT_MEDIA_F_XXX). + * @param bSystemType The partitiona table system ID. + * @param fBootable Whether it's a bootable entry or if we just want + * the BIOS to setup the emulation without booting + * it. + * @param uLoadSeg The load address divided by 0x10 (i.e. the real + * mode segment number). + * @param cSectorsToLoad Number of emulated sectors to load. + * @param bSelCritType The selection criteria type, if none pass + * ISO9660_ELTORITO_SEL_CRIT_TYPE_NONE. + * @param pvSelCritData Pointer to the selection criteria data. + * @param cbSelCritData Size of the selection criteria data. + */ +RTDECL(int) RTFsIsoMakerBootCatSetSectionEntry(RTFSISOMAKER hIsoMaker, uint32_t idxBootCat, uint32_t idxImageObj, + uint8_t bBootMediaType, uint8_t bSystemType, bool fBootable, + uint16_t uLoadSeg, uint16_t cSectorsToLoad, + uint8_t bSelCritType, void const *pvSelCritData, size_t cbSelCritData); + +/** + * Set the validation entry of the boot catalog (this is the first entry). + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idxBootCat The boot catalog entry. + * @param cEntries Number of entries in the section. + * @param idPlatform The platform ID + * (ISO9660_ELTORITO_PLATFORM_ID_XXX). + * @param pszString Section identifier or something. Optional. + */ +RTDECL(int) RTFsIsoMakerBootCatSetSectionHeaderEntry(RTFSISOMAKER hIsoMaker, uint32_t idxBootCat, uint32_t cEntries, + uint8_t idPlatform, const char *pszString); + +/** + * Sets the boot catalog backing file. + * + * The content of the given file will be discarded and replaced with the boot + * catalog, the naming and file attributes (other than size) will be retained. + * + * This API exists mainly to assist when importing ISOs. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + * @param idxObj The configuration index of the file. + */ +RTDECL(int) RTFsIsoMakerBootCatSetFile(RTFSISOMAKER hIsoMaker, uint32_t idxObj); + + +/** + * ISO maker import results (RTFsIsoMakerImport). + */ +typedef struct RTFSISOMAKERIMPORTRESULTS +{ + /** Number of names added. */ + uint32_t cAddedNames; + /** Number of directories added. */ + uint32_t cAddedDirs; + /** Amount of added data blocks, files only. */ + uint64_t cbAddedDataBlocks; + /** Number of unique files added (unique in terms of data location). */ + uint32_t cAddedFiles; + /** Number of symbolic links added. */ + uint32_t cAddedSymlinks; + /** Number of imported boot catalog entries. */ + uint32_t cBootCatEntries; + /** Number of system area bytes imported (from offset zero). */ + uint32_t cbSysArea; + + /** Number of import errors. */ + uint32_t cErrors; +} RTFSISOMAKERIMPORTRESULTS; +/** Pointer to ISO maker import results. */ +typedef RTFSISOMAKERIMPORTRESULTS *PRTFSISOMAKERIMPORTRESULTS; + +/** + * Imports an existing ISO. + * + * Just like other source files, the existing image must remain present and + * unmodified till the ISO maker is done with it. + * + * @returns IRPT status code. + * @param hIsoMaker The ISO maker handle. + * @param hIsoFile VFS file handle to the existing image to import / clone. + * @param fFlags Reserved for the future, MBZ. + * @param pResults Where to return import results. + * @param pErrInfo Where to return additional error information. + * Optional. + */ +RTDECL(int) RTFsIsoMakerImport(RTFSISOMAKER hIsoMaker, RTVFSFILE hIsoFile, uint32_t fFlags, + PRTFSISOMAKERIMPORTRESULTS pResults, PRTERRINFO pErrInfo); + +/** @name RTFSISOMK_IMPORT_F_XXX - Flags for RTFsIsoMakerImport. + * @{ */ +#define RTFSISOMK_IMPORT_F_NO_PRIMARY_ISO RT_BIT_32(0) /**< Skip the primary ISO-9660 namespace (rock ridge included). */ +#define RTFSISOMK_IMPORT_F_NO_JOLIET RT_BIT_32(1) /**< Skip the joliet namespace. */ +#define RTFSISOMK_IMPORT_F_NO_ROCK_RIDGE RT_BIT_32(2) /**< Skip rock ridge (both primary and joliet). */ +#define RTFSISOMK_IMPORT_F_NO_UDF RT_BIT_32(3) /**< Skip the UDF namespace. */ +#define RTFSISOMK_IMPORT_F_NO_HFS RT_BIT_32(4) /**< Skip the HFS namespace. */ +#define RTFSISOMK_IMPORT_F_NO_BOOT RT_BIT_32(5) /**< Skip importing El Torito boot stuff. */ +#define RTFSISOMK_IMPORT_F_NO_SYS_AREA RT_BIT_32(6) /**< Skip importing the system area (first 32KB). */ + +#define RTFSISOMK_IMPORT_F_NO_SYSTEM_ID RT_BIT_32(7) /**< Don't import the system ID primary descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_VOLUME_ID RT_BIT_32(8) /**< Don't import the volume ID primary descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_VOLUME_SET_ID RT_BIT_32(9) /**< Don't import the volume set ID primary descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_PUBLISHER_ID RT_BIT_32(10) /**< Don't import the publisher ID primary descriptor field. */ +#define RTFSISOMK_IMPORT_F_DATA_PREPARER_ID RT_BIT_32(11) /**< Do import the data preparer ID primary descriptor field. */ +#define RTFSISOMK_IMPORT_F_APPLICATION_ID RT_BIT_32(12) /**< Do import the application ID primary descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_COPYRIGHT_FID RT_BIT_32(13) /**< Don't import the copyright file ID primary descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_ABSTRACT_FID RT_BIT_32(14) /**< Don't import the abstract file ID primary descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_BIBLIO_FID RT_BIT_32(15) /**< Don't import the bibliographic file ID primary descriptor field. */ + +#define RTFSISOMK_IMPORT_F_NO_J_SYSTEM_ID RT_BIT_32(16) /**< Don't import the system ID joliet descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_J_VOLUME_ID RT_BIT_32(17) /**< Don't import the volume ID joliet descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_J_VOLUME_SET_ID RT_BIT_32(18) /**< Don't import the volume set ID joliet descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_J_PUBLISHER_ID RT_BIT_32(19) /**< Don't import the publisher ID joliet descriptor field. */ +#define RTFSISOMK_IMPORT_F_J_DATA_PREPARER_ID RT_BIT_32(20) /**< Do import the data preparer ID joliet descriptor field. */ +#define RTFSISOMK_IMPORT_F_J_APPLICATION_ID RT_BIT_32(21) /**< Do import the application ID joliet descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_J_COPYRIGHT_FID RT_BIT_32(22) /**< Don't import the copyright file ID joliet descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_J_ABSTRACT_FID RT_BIT_32(23) /**< Don't import the abstract file ID joliet descriptor field. */ +#define RTFSISOMK_IMPORT_F_NO_J_BIBLIO_FID RT_BIT_32(24) /**< Don't import the bibliographic file ID joliet descriptor field. */ + +#define RTFSISOMK_IMPORT_F_VALID_MASK UINT32_C(0x01ffffff) +/** @} */ + + +/** + * Finalizes the image. + * + * @returns IPRT status code. + * @param hIsoMaker The ISO maker handle. + */ +RTDECL(int) RTFsIsoMakerFinalize(RTFSISOMAKER hIsoMaker); + +/** + * Creates a VFS file for a finalized ISO maker instanced. + * + * The file can be used to access the image. Both sequential and random access + * are supported, so that this could in theory be hooked up to a CD/DVD-ROM + * drive emulation and used as a virtual ISO image. + * + * @returns IRPT status code. + * @param hIsoMaker The ISO maker handle. + * @param phVfsFile Where to return the handle. + */ +RTDECL(int) RTFsIsoMakerCreateVfsOutputFile(RTFSISOMAKER hIsoMaker, PRTVFSFILE phVfsFile); + + + +/** + * ISO maker command (creates image file on disk). + * + * @returns IPRT status code + * @param cArgs Number of arguments. + * @param papszArgs Pointer to argument array. + */ +RTDECL(RTEXITCODE) RTFsIsoMakerCmd(unsigned cArgs, char **papszArgs); + +/** + * Extended ISO maker command. + * + * This can be used as a ISO maker command that produces a image file, or + * alternatively for setting up a virtual ISO in memory. + * + * @returns IPRT status code + * @param cArgs Number of arguments. + * @param papszArgs Pointer to argument array. + * @param hVfsCwd The current working directory to assume when processing + * relative file/dir references. Pass NIL_RTVFSDIR to use + * the current CWD of the process. + * @param pszCwd Path to @a hVfsCwdDir. Use for error reporting and + * optimizing the open file count if possible. + * @param phVfsFile Where to return the virtual ISO. Pass NULL to for + * normal operation (creates file on disk). + * @param pErrInfo Where to return extended error information in the + * virtual ISO mode. + */ +RTDECL(int) RTFsIsoMakerCmdEx(unsigned cArgs, char **papszArgs, RTVFSDIR hVfsCwd, const char *pszCwd, + PRTVFSFILE phVfsFile, PRTERRINFO pErrInfo); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_fsisomaker_h */ + diff --git a/include/iprt/fsvfs.h b/include/iprt/fsvfs.h new file mode 100644 index 00000000..0b9d8d03 --- /dev/null +++ b/include/iprt/fsvfs.h @@ -0,0 +1,204 @@ +/** @file + * IPRT - Filesystem, VFS implementations. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_fsvfs_h +#define IPRT_INCLUDED_fsvfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_fs_vfs VFS File System Implementations + * @ingroup grp_rt_fs + * @{ + */ + +/** + * Opens a FAT file system volume. + * + * @returns IPRT status code. + * @param hVfsFileIn The file or device backing the volume. + * @param fReadOnly Whether to mount it read-only. + * @param offBootSector The offset of the boot sector relative to the start + * of @a hVfsFileIn. Pass 0 for floppies. + * @param phVfs Where to return the virtual file system handle. + * @param pErrInfo Where to return additional error information. + */ +RTDECL(int) RTFsFatVolOpen(RTVFSFILE hVfsFileIn, bool fReadOnly, uint64_t offBootSector, PRTVFS phVfs, PRTERRINFO pErrInfo); + + +/** + * FAT type (format). + */ +typedef enum RTFSFATTYPE +{ + RTFSFATTYPE_INVALID = 0, + RTFSFATTYPE_FAT12, + RTFSFATTYPE_FAT16, + RTFSFATTYPE_FAT32, + RTFSFATTYPE_END +} RTFSFATTYPE; + + +/** @name RTFSFATVOL_FMT_F_XXX - RTFsFatVolFormat flags + * @{ */ +/** Perform a full format, filling unused sectors with 0xf6. */ +#define RTFSFATVOL_FMT_F_FULL UINT32_C(0) +/** Perform a quick format. + * I.e. just write the boot sector, FATs and root directory. */ +#define RTFSFATVOL_FMT_F_QUICK RT_BIT_32(0) +/** Mask containing all valid flags. */ +#define RTFSFATVOL_FMT_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Formats a FAT volume. + * + * @returns IRPT status code. + * @param hVfsFile The volume file. + * @param offVol The offset into @a hVfsFile of the file. + * Typically 0. + * @param cbVol The size of the volume. Pass 0 if the rest of + * hVfsFile should be used. + * @param fFlags See RTFSFATVOL_FMT_F_XXX. + * @param cbSector The logical sector size. Must be power of two. + * Optional, pass zero to use 512. + * @param cSectorsPerCluster Number of sectors per cluster. Power of two. + * Optional, pass zero to auto detect. + * @param enmFatType The FAT type (12, 16, 32) to use. + * Optional, pass RTFSFATTYPE_INVALID for default. + * @param cHeads The number of heads to report in the BPB. + * Optional, pass zero to auto detect. + * @param cSectorsPerTrack The number of sectors per track to put in the + * BPB. Optional, pass zero to auto detect. + * @param bMedia The media byte value and FAT ID to use. + * Optional, pass zero to auto detect. + * @param cRootDirEntries Number of root directory entries. + * Optional, pass zero to auto detect. + * @param cHiddenSectors Number of hidden sectors. Pass 0 for + * unpartitioned media. + * @param pErrInfo Additional error information, maybe. Optional. + */ +RTDECL(int) RTFsFatVolFormat(RTVFSFILE hVfsFile, uint64_t offVol, uint64_t cbVol, uint32_t fFlags, uint16_t cbSector, + uint16_t cSectorsPerCluster, RTFSFATTYPE enmFatType, uint32_t cHeads, uint32_t cSectorsPerTrack, + uint8_t bMedia, uint16_t cRootDirEntries, uint32_t cHiddenSectors, PRTERRINFO pErrInfo); + +/** + * Formats a 1.44MB floppy image. + * + * @returns IPRT status code. + * @param hVfsFile The image. Will be grown to 1.44MB if + * necessary. + * @param fQuick Whether to quick format the floppy or not. + */ +RTDECL(int) RTFsFatVolFormat144(RTVFSFILE hVfsFile, bool fQuick); + +/** + * Formats a 2.88MB floppy image. + * + * @returns IPRT status code. + * @param hVfsFile The image. Will be grown to 1.44MB if + * necessary. + * @param fQuick Whether to quick format the floppy or not. + */ +RTDECL(int) RTFsFatVolFormat288(RTVFSFILE hVfsFile, bool fQuick); + + +/** + * Opens an EXT2/3/4 file system volume. + * + * @returns IPRT status code. + * @param hVfsFileIn The file or device backing the volume. + * @param fMntFlags RTVFSMNT_F_XXX. + * @param fExtFlags Reserved, MBZ. + * @param phVfs Where to return the virtual file system handle. + * @param pErrInfo Where to return additional error information. + */ +RTDECL(int) RTFsExtVolOpen(RTVFSFILE hVfsFileIn, uint32_t fMntFlags, uint32_t fExtFlags, PRTVFS phVfs, PRTERRINFO pErrInfo); + + + +/** @name RTFSISO9660_F_XXX - ISO 9660 mount flags. + * @{ */ +/** Do not use the UDF part if present. */ +#define RTFSISO9660_F_NO_UDF RT_BIT_32(0) +/** Do not use the joliet part. */ +#define RTFSISO9660_F_NO_JOLIET RT_BIT_32(1) +/** Do not use the rock ridge extensions if present. */ +#define RTFSISO9660_F_NO_ROCK RT_BIT_32(2) +/** Valid ISO 9660 mount option mask. */ +#define RTFSISO9660_F_VALID_MASK UINT32_C(0x00000007) +/** Checks if @a a_fNoType is the only acceptable volume type. */ +#define RTFSISO9660_F_IS_ONLY_TYPE(a_fFlags, a_fNoType) \ + ( ((a_fFlags) & (RTFSISO9660_F_NO_UDF | RTFSISO9660_F_NO_JOLIET | RTFSISO9660_F_NO_ROCK)) \ + == (~(a_fNoType) & (RTFSISO9660_F_NO_UDF | RTFSISO9660_F_NO_JOLIET | RTFSISO9660_F_NO_ROCK)) ) +/** @} */ + +/** + * Opens an ISO 9660 file system volume. + * + * @returns IPRT status code. + * @param hVfsFileIn The file or device backing the volume. + * @param fFlags RTFSISO9660_F_XXX. + * @param phVfs Where to return the virtual file system handle. + * @param pErrInfo Where to return additional error information. + */ +RTDECL(int) RTFsIso9660VolOpen(RTVFSFILE hVfsFileIn, uint32_t fFlags, PRTVFS phVfs, PRTERRINFO pErrInfo); + + +/** + * Opens an NTFS file system volume. + * + * @returns IPRT status code. + * @param hVfsFileIn The file or device backing the volume. + * @param fMntFlags RTVFSMNT_F_XXX. + * @param fNtfsFlags Reserved, MBZ. + * @param phVfs Where to return the virtual file system handle. + * @param pErrInfo Where to return additional error information. + */ +RTDECL(int) RTFsNtfsVolOpen(RTVFSFILE hVfsFileIn, uint32_t fMntFlags, uint32_t fNtfsFlags, PRTVFS phVfs, PRTERRINFO pErrInfo); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_fsvfs_h */ + diff --git a/include/iprt/ftp.h b/include/iprt/ftp.h new file mode 100644 index 00000000..8771d1d2 --- /dev/null +++ b/include/iprt/ftp.h @@ -0,0 +1,390 @@ +/* $Id: ftp.h $ */ +/** @file + * Header file for FTP client / server implementations. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_ftp_h +#define IPRT_INCLUDED_ftp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/fs.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_ftp RTFtp - FTP server and client. + * @ingroup grp_rt + * @{ + */ + +/** @defgroup grp_rt_ftpserver RTFtpServer - FTP server implementation. + * @{ + */ + +/** @todo the following three definitions may move the iprt/types.h later. */ +/** FTP server handle. */ +typedef R3PTRTYPE(struct RTFTPSERVERINTERNAL *) RTFTPSERVER; +/** Pointer to a FTP server handle. */ +typedef RTFTPSERVER *PRTFTPSERVER; +/** Nil FTP client handle. */ +#define NIL_RTFTPSERVER ((RTFTPSERVER)0) + +/** Maximum length (in characters) a command can have (without parameters). */ +#define RTFTPSERVER_MAX_CMD_LEN 8 + +/** + * Enumeration for defining the current server connection mode. + */ +typedef enum RTFTPSERVER_CONNECTION_MODE +{ + /** Normal mode, nothing to transfer. */ + RTFTPSERVER_CONNECTION_MODE_NORMAL = 0, + /** Server is in passive mode (is listening). */ + RTFTPSERVER_CONNECTION_MODE_PASSIVE, + /** Server connects via port to the client. */ + RTFTPSERVER_CONNECTION_MODE_MODE_PORT, + /** The usual 32-bit hack. */ + RTFTPSERVER_CONNECTION_MODE_32BIT_HACK = 0x7fffffff +} RTFTPSERVER_CONNECTION_MODE; + +/** + * Enumeration for defining the data transfer mode. + */ +typedef enum RTFTPSERVER_TRANSFER_MODE +{ + /** Default if nothing else is set. */ + RTFTPSERVER_TRANSFER_MODE_STREAM = 0, + RTFTPSERVER_TRANSFER_MODE_BLOCK, + RTFTPSERVER_TRANSFER_MODE_COMPRESSED, + /** The usual 32-bit hack. */ + RTFTPSERVER_DATA_MODE_32BIT_HACK = 0x7fffffff +} RTFTPSERVER_DATA_MODE; + +/** + * Enumeration for defining the data type. + */ +typedef enum RTFTPSERVER_DATA_TYPE +{ + /** Default if nothing else is set. */ + RTFTPSERVER_DATA_TYPE_ASCII = 0, + RTFTPSERVER_DATA_TYPE_EBCDIC, + RTFTPSERVER_DATA_TYPE_IMAGE, + RTFTPSERVER_DATA_TYPE_LOCAL, + /** The usual 32-bit hack. */ + RTFTPSERVER_DATA_TYPE_32BIT_HACK = 0x7fffffff +} RTFTPSERVER_DATA_TYPE; + +/** + * Enumeration for defining the struct type. + */ +typedef enum RTFTPSERVER_STRUCT_TYPE +{ + /** Default if nothing else is set. */ + RTFTPSERVER_STRUCT_TYPE_FILE = 0, + RTFTPSERVER_STRUCT_TYPE_RECORD, + RTFTPSERVER_STRUCT_TYPE_PAGE, + /** The usual 32-bit hack. */ + RTFTPSERVER_STRUCT_TYPE_32BIT_HACK = 0x7fffffff +} RTFTPSERVER_STRUCT_TYPE; + +/** + * Enumeration for FTP server reply codes. + * + ** @todo Might needs more codes, not complete yet. + */ +typedef enum RTFTPSERVER_REPLY +{ + /** Invalid reply type, do not use. */ + RTFTPSERVER_REPLY_INVALID = 0, + /** Data connection already open. */ + RTFTPSERVER_REPLY_DATACONN_ALREADY_OPEN = 125, + /** Command okay. */ + RTFTPSERVER_REPLY_FILE_STS_OK_OPENING_DATA_CONN = 150, + /** Command okay. */ + RTFTPSERVER_REPLY_OKAY = 200, + /** Command not implemented, superfluous at this site. */ + RTFTPSERVER_REPLY_ERROR_CMD_NOT_IMPL_SUPERFLUOUS = 202, + /** System status report. */ + RTFTPSERVER_REPLY_SYSTEM_STATUS = 211, + /** Service ready for new user. */ + RTFTPSERVER_REPLY_READY_FOR_NEW_USER = 220, + /** Service is closing control connection. */ + RTFTPSERVER_REPLY_CLOSING_CTRL_CONN = 221, + /** Closing data connection. */ + RTFTPSERVER_REPLY_CLOSING_DATA_CONN = 226, + /** Requested file action okay, completed. */ + RTFTPSERVER_REPLY_FILE_ACTION_OKAY_COMPLETED = 250, + /** "PATHNAME" ok (created / exists). */ + RTFTPSERVER_REPLY_PATHNAME_OK = 257, + /** User logged in, proceed. */ + RTFTPSERVER_REPLY_LOGGED_IN_PROCEED = 230, + /** User name okay, need password. */ + RTFTPSERVER_REPLY_USERNAME_OKAY_NEED_PASSWORD = 331, + /** Service not available, closing control connection. */ + RTFTPSERVER_REPLY_SVC_NOT_AVAIL_CLOSING_CTRL_CONN = 421, + /** Can't open data connection. */ + RTFTPSERVER_REPLY_CANT_OPEN_DATA_CONN = 425, + /** Connection closed; transfer aborted. */ + RTFTPSERVER_REPLY_CONN_CLOSED_TRANSFER_ABORTED = 426, + /** Requested file action not taken. */ + RTFTPSERVER_REPLY_CONN_REQ_FILE_ACTION_NOT_TAKEN = 450, + /** Requested action aborted; local error in processing. */ + RTFTPSERVER_REPLY_ACTION_ABORTED_LOCAL_ERROR = 451, + /** Syntax error, command unrecognized. */ + RTFTPSERVER_REPLY_ERROR_CMD_NOT_RECOGNIZED = 500, + /** Syntax error in parameters or arguments. */ + RTFTPSERVER_REPLY_ERROR_INVALID_PARAMETERS = 501, + /** Command not implemented. */ + RTFTPSERVER_REPLY_ERROR_CMD_NOT_IMPL = 502, + /** Bad sequence of commands. */ + RTFTPSERVER_REPLY_ERROR_BAD_SEQUENCE = 503, + /** Command not implemented for that parameter. */ + RTFTPSERVER_REPLY_ERROR_CMD_NOT_IMPL_PARAM = 504, + /** Not logged in. */ + RTFTPSERVER_REPLY_NOT_LOGGED_IN = 530, + /** Requested action not taken. */ + RTFTPSERVER_REPLY_REQ_ACTION_NOT_TAKEN = 550, + /** The usual 32-bit hack. */ + RTFTPSERVER_REPLY_32BIT_HACK = 0x7fffffff +} RTFTPSERVER_REPLY; + +/** + * Structure for maintaining a FTP server client state. + */ +typedef struct RTFTPSERVERCLIENTSTATE +{ + /** Authenticated user (name). If NULL, no user has been logged in (yet). */ + char *pszUser; + /** Current working directory. + * *Always* relative to the server's root directory (which is only is known to the actual implemenation). */ + char *pszCWD; + /** Number of failed login attempts. */ + uint8_t cFailedLoginAttempts; + /** Timestamp (in ms) of last command issued by the client. */ + uint64_t tsLastCmdMs; + /** Current set data type. */ + RTFTPSERVER_DATA_TYPE enmDataType; + /** Current set struct type. */ + RTFTPSERVER_STRUCT_TYPE enmStructType; +} RTFTPSERVERCLIENTSTATE; +/** Pointer to a FTP server client state. */ +typedef RTFTPSERVERCLIENTSTATE *PRTFTPSERVERCLIENTSTATE; + +/** + * Structure for storing FTP server callback data. + */ +typedef struct RTFTPCALLBACKDATA +{ + /** Pointer to the client state. */ + PRTFTPSERVERCLIENTSTATE pClient; + /** Saved user pointer. */ + void *pvUser; + /** Size (in bytes) of data at user pointer. */ + size_t cbUser; +} RTFTPCALLBACKDATA; +/** Pointer to FTP server callback data. */ +typedef RTFTPCALLBACKDATA *PRTFTPCALLBACKDATA; + +/** + * Function callback table for the FTP server implementation. + * + * All callbacks are optional and therefore can be NULL. + */ +typedef struct RTFTPSERVERCALLBACKS +{ + /** + * Callback which gets invoked when a user connected. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param pcszUser User name. + */ + DECLCALLBACKMEMBER(int, pfnOnUserConnect,(PRTFTPCALLBACKDATA pData, const char *pcszUser)); + /** + * Callback which gets invoked when a user tries to authenticate with a password. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param pcszUser User name to authenticate. + * @param pcszPassword Password to authenticate with. + */ + DECLCALLBACKMEMBER(int, pfnOnUserAuthenticate,(PRTFTPCALLBACKDATA pData, const char *pcszUser, const char *pcszPassword)); + /** + * Callback which gets invoked when a user disconnected. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param pcszUser User name which disconnected. + */ + DECLCALLBACKMEMBER(int, pfnOnUserDisconnect,(PRTFTPCALLBACKDATA pData, const char *pcszUser)); + /** + * Callback which gets invoked when the client wants to start reading or writing a file. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param pcsszPath Relative path (to root directory) of file to open. + * @param fMode File mode to use (IPRT stlye). + * @param ppvHandle Opaque file handle only known to the callback implementation. + */ + DECLCALLBACKMEMBER(int, pfnOnFileOpen,(PRTFTPCALLBACKDATA pData, const char *pcszPath, uint32_t fMode, void **ppvHandle)); + /** + * Callback which gets invoked when the client wants to read from a file. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param pvHandle Opaque file handle only known to the callback implementation. + * @param pvBuf Where to store the read file data. + * @param cbToRead How much (in bytes) to read. Must at least supply the size of pvBuf. + * @param pcbRead How much (in bytes) was read. Optional. + */ + DECLCALLBACKMEMBER(int, pfnOnFileRead,(PRTFTPCALLBACKDATA pData, void *pvHandle, void *pvBuf, size_t cbToRead, size_t *pcbRead)); + /** + * Callback which gets invoked when the client is done reading from or writing to a file. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param ppvHandle Opaque file handle only known to the callback implementation. + */ + DECLCALLBACKMEMBER(int, pfnOnFileClose,(PRTFTPCALLBACKDATA pData, void *pvHandle)); + /** + * Callback which gets invoked when the client wants to retrieve the size of a specific file. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param pcszPath Relative path (to root directory) of file to retrieve size for. + * @param puSize Where to store the file size on success. + */ + DECLCALLBACKMEMBER(int, pfnOnFileGetSize,(PRTFTPCALLBACKDATA pData, const char *pcszPath, uint64_t *puSize)); + /** + * Callback which gets invoked when the client wants to retrieve information about a file. + * + * @param pData Pointer to generic callback data. + * @param pcszPath Relative path (to root directory) of file / directory to "stat". Optional. + * If NULL, the current directory will be used. + * @param pFsObjInfo Where to return the RTFSOBJINFO data on success. Optional. + * @returns VBox status code. + */ + DECLCALLBACKMEMBER(int, pfnOnFileStat,(PRTFTPCALLBACKDATA pData, const char *pcszPath, PRTFSOBJINFO pFsObjInfo)); + /** + * Callback which gets invoked when setting the current working directory. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param pcszCWD Current working directory to set. + */ + DECLCALLBACKMEMBER(int, pfnOnPathSetCurrent,(PRTFTPCALLBACKDATA pData, const char *pcszCWD)); + /** + * Callback which gets invoked when a client wants to retrieve the current working directory. + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + * @param pszPWD Where to store the current working directory. + * @param cbPWD Size of buffer in bytes. + */ + DECLCALLBACKMEMBER(int, pfnOnPathGetCurrent,(PRTFTPCALLBACKDATA pData, char *pszPWD, size_t cbPWD)); + /** + * Callback which gets invoked when the client wants to move up a directory (relative to the current working directory). + * + * @returns VBox status code. + * @param pData Pointer to generic callback data. + */ + DECLCALLBACKMEMBER(int, pfnOnPathUp,(PRTFTPCALLBACKDATA pData)); + /** + * Callback which gets invoked when the server wants to open a directory for reading. + * + * @returns VBox status code. VERR_NO_MORE_FILES if listing is complete. + * @param pData Pointer to generic callback data. + * @param pcszPath Relative path (to root directory) of file / directory to list. Optional. + * If NULL, the current directory will be listed. + * @param ppvHandle Where to return the opaque directory handle. + */ + DECLCALLBACKMEMBER(int, pfnOnDirOpen,(PRTFTPCALLBACKDATA pData, const char *pcszPath, void **ppvHandle)); + /** + * Callback which gets invoked when the server wants to close a directory handle. + * + * @returns VBox status code. VERR_NO_MORE_FILES if listing is complete. + * @param pData Pointer to generic callback data. + * @param pvHandle Directory handle to close. + */ + DECLCALLBACKMEMBER(int, pfnOnDirClose,(PRTFTPCALLBACKDATA pData, void *pvHandle)); + /** + * Callback which gets invoked when the server wants to read the next directory entry. + * + * @returns VBox status code. VERR_NO_MORE_FILES if listing is complete. + * @param pData Pointer to generic callback data. + * @param pvHandle Directory handle to use for reading. + * @param pInfo Where to store the FS object information. + * @param ppszEntry Where to return the allocated string of the entry name. + * @param ppszOwner Where to return the allocated string of the owner. + * @param ppszGroup Where to return the allocated string of the group. + * @param ppszTarget Where to return the allocated string of the target (if a link). Currently unused. + */ + DECLCALLBACKMEMBER(int, pfnOnDirRead,(PRTFTPCALLBACKDATA pData, void *pvHandle, char **ppszEntry, + PRTFSOBJINFO pInfo, char **ppszOwner, char **ppszGroup, char **ppszTarget)); +} RTFTPSERVERCALLBACKS; +/** Pointer to a FTP server callback data table. */ +typedef RTFTPSERVERCALLBACKS *PRTFTPSERVERCALLBACKS; + +/** + * Creates a FTP server instance. + * + * @returns IPRT status code. + * @param phFTPServer Where to store the FTP server handle. + * @param pcszAddress The address for creating a listening socket. + * If NULL or empty string the server is bound to all interfaces. + * @param uPort The port for creating a listening socket. + * @param pCallbacks Callback table to use. + * @param pvUser Pointer to user-specific data. Optional. + * @param cbUser Size of user-specific data. Optional. + */ +RTR3DECL(int) RTFtpServerCreate(PRTFTPSERVER phFTPServer, const char *pcszAddress, uint16_t uPort, + PRTFTPSERVERCALLBACKS pCallbacks, void *pvUser, size_t cbUser); + +/** + * Destroys a FTP server instance. + * + * @returns IPRT status code. + * @param hFTPServer Handle to the FTP server handle. + */ +RTR3DECL(int) RTFtpServerDestroy(RTFTPSERVER hFTPServer); + +/** @} */ + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_ftp_h */ + diff --git a/include/iprt/fuzz.h b/include/iprt/fuzz.h new file mode 100644 index 00000000..5ad6f397 --- /dev/null +++ b/include/iprt/fuzz.h @@ -0,0 +1,971 @@ +/** @file + * IPRT - Fuzzing framework + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_fuzz_h +#define IPRT_INCLUDED_fuzz_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/process.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_fuzz RTFuzz - Data fuzzing framework + * @ingroup grp_rt + * @sa grp_rt_test + * @{ + */ + +/** A fuzzer context handle. */ +typedef struct RTFUZZCTXINT *RTFUZZCTX; +/** Pointer to a fuzzer context handle. */ +typedef RTFUZZCTX *PRTFUZZCTX; +/** NIL fuzzer context handle. */ +#define NIL_RTFUZZCTX ((RTFUZZCTX)~(uintptr_t)0) +/** A fuzzer input handle. */ +typedef struct RTFUZZINPUTINT *RTFUZZINPUT; +/** Pointer to a fuzzer input handle. */ +typedef RTFUZZINPUT *PRTFUZZINPUT; +/** NIL fuzzer input handle. */ +#define NIL_RTFUZZINPUT ((RTFUZZINPUT)~(uintptr_t)0) + + +/** A fuzzer config handle. */ +typedef struct RTFUZZCFGINT *RTFUZZCFG; +/** Pointer to a fuzzer config handle. */ +typedef RTFUZZCFG *PRTFUZZCFG; +/** NIL fuzzer config handle. */ +#define NIL_RTFUZZCFG ((RTFUZZCFG)~(uintptr_t)0) + + +/** A fuzzer target recorder handler. */ +typedef struct RTFUZZTGTRECINT *RTFUZZTGTREC; +/** Pointer to a fuzzer target recorder handle. */ +typedef RTFUZZTGTREC *PRTFUZZTGTREC; +/** NIL fuzzer target recorder handle. */ +#define NIL_RTFUZZTGTREC ((RTFUZZTGTREC)~(uintptr_t)0) +/** A fuzzed target state handle. */ +typedef struct RTFUZZTGTSTATEINT *RTFUZZTGTSTATE; +/** Pointer to a fuzzed target state handle. */ +typedef RTFUZZTGTSTATE *PRTFUZZTGTSTATE; +/** NIL fuzzed target state handle. */ +#define NIL_RTFUZZTGTSTATE ((RTFUZZTGTSTATE)~(uintptr_t)0) + + +/** Fuzzing observer handle. */ +typedef struct RTFUZZOBSINT *RTFUZZOBS; +/** Pointer to a fuzzing observer handle. */ +typedef RTFUZZOBS *PRTFUZZOBS; +/** NIL fuzzing observer handle. */ +#define NIL_RTFUZZOBS ((RTFUZZOBS)~(uintptr_t)0) + + +/** + * Fuzzing context type. + */ +typedef enum RTFUZZCTXTYPE +{ + /** Invalid type. */ + RTFUZZCTXTYPE_INVALID = 0, + /** Original input data is a single binary large object (BLOB), from a file or similar. */ + RTFUZZCTXTYPE_BLOB, + /** Original input data is from a data stream like a network connection. */ + RTFUZZCTXTYPE_STREAM, + /** 32bit hack. */ + RTFUZZCTXTYPE_32BIT_HACK = 0x7fffffff +} RTFUZZCTXTYPE; + + +/** + * Fuzzing context statistics. + */ +typedef struct RTFUZZCTXSTATS +{ + /** Amount of memory currently allocated. */ + size_t cbMemory; + /** Number of mutations accumulated in the corpus. */ + uint64_t cMutations; +} RTFUZZCTXSTATS; +/** Pointer to fuzzing context statistics. */ +typedef RTFUZZCTXSTATS *PRTFUZZCTXSTATS; + + +/** @name RTFUZZCTX_F_XXX - Flags for RTFuzzCtxCfgSetBehavioralFlags + * @{ */ +/** Adds all generated inputs automatically to the input corpus for the owning context. */ +#define RTFUZZCTX_F_BEHAVIORAL_ADD_INPUT_AUTOMATICALLY_TO_CORPUS RT_BIT_32(0) +/** All valid behavioral modification flags. */ +#define RTFUZZCTX_F_BEHAVIORAL_VALID (RTFUZZCTX_F_BEHAVIORAL_ADD_INPUT_AUTOMATICALLY_TO_CORPUS) +/** @} */ + + +/** @name RTFUZZOBS_SANITIZER_F_XXX - Flags for RTFuzzObsSetTestBinarySanitizers(). + * @{ */ +/** ASAN is compiled and enabled (observer needs to configure to abort on error to catch memory errors). */ +#define RTFUZZOBS_SANITIZER_F_ASAN UINT32_C(0x00000001) +/** A converage sanitizer is compiled in which can be used to produce coverage reports aiding in the + * fuzzing process. */ +#define RTFUZZOBS_SANITIZER_F_SANCOV UINT32_C(0x00000002) +/** @} */ + + +/** @name RTFUZZTGT_REC_STATE_F_XXX - Flags for RTFuzzTgtRecorderCreate(). + * @{ */ +/** The output from stdout is used to compare states. */ +#define RTFUZZTGT_REC_STATE_F_STDOUT RT_BIT_32(0) +/** The output from stderr is used to compare states. */ +#define RTFUZZTGT_REC_STATE_F_STDERR RT_BIT_32(1) +/** The process status is used to compare states. */ +#define RTFUZZTGT_REC_STATE_F_PROCSTATUS RT_BIT_32(2) +/** The coverage report is used to compare states. */ +#define RTFUZZTGT_REC_STATE_F_SANCOV RT_BIT_32(3) +/** Mask of all valid flags. */ +#define RTFUZZTGT_REC_STATE_F_VALID UINT32_C(0x0000000f) +/** @} */ + + +/** @name RTFUZZCFG_IMPORT_F_XXX - Flags for RTFuzzCfgImport(). + * @{ */ +/** Default flags. */ +#define RTFUZZCFG_IMPORT_F_DEFAULT 0 +/** Adds only the inputs and doesn't set any glboal configuration flags of the fuzzing context. */ +#define RTFUZZCFG_IMPORT_F_ONLY_INPUT RT_BIT_32(0) +/** Mask of all valid flags. */ +#define RTFUZZCFG_IMPORT_F_VALID UINT32_C(0x00000001) +/** @} */ + + +/** + * Fuzzing context state export callback. + * + * @returns IPRT status code. + * @param hFuzzCtx Handle of the fuzzing context. + * @param pvBuf The data to write. + * @param cbWrite Number of bytes to write. + * @param pvUser Opaque user data passed in RTFuzzCtxStateExport(). + */ +typedef DECLCALLBACKTYPE(int, FNRTFUZZCTXEXPORT,(RTFUZZCTX hFuzzCtx, const void *pvBuf, size_t cbWrite, void *pvUser)); +/** Pointer to a fuzzing context state export callback. */ +typedef FNRTFUZZCTXEXPORT *PFNRTFUZZCTXEXPORT; + +/** + * Fuzzing context state import callback. + * + * @returns IPRT status code. + * @param hFuzzCtx Handle of the fuzzing context. + * @param pvBuf Where to store the read data. + * @param cbRead Number of bytes to read. + * @param pcbRead Where to store the amount of data written, optional. + * @param pvUser Opaque user data passed in RTFuzzCtxCreateFromState(). + */ +typedef DECLCALLBACKTYPE(int, FNRTFUZZCTXIMPORT,(RTFUZZCTX hFuzzCtx, void *pvBuf, size_t cbRead, size_t *pcbRead, void *pvUser)); +/** Pointer to a fuzzing context state export callback. */ +typedef FNRTFUZZCTXIMPORT *PFNRTFUZZCTXIMPORT; + + +/** + * Creates a new fuzzing context. + * + * @returns IPRT status code. + * @param phFuzzCtx Where to store the handle to the fuzzing context on success. + * @param enmType Fuzzing context data type. + */ +RTDECL(int) RTFuzzCtxCreate(PRTFUZZCTX phFuzzCtx, RTFUZZCTXTYPE enmType); + +/** + * Creates a new fuzzing context from the given state. + * + * @returns IPRT status code. + * @param phFuzzCtx Where to store the handle to the fuzzing context on success. + * @param pfnImport State import callback. + * @param pvUser Opaque user data to pass to the callback. + */ +RTDECL(int) RTFuzzCtxCreateFromState(PRTFUZZCTX phFuzzCtx, PFNRTFUZZCTXIMPORT pfnImport, void *pvUser); + +/** + * Creates a new fuzzing context loading the state from the given memory buffer. + * + * @returns IPRT status code. + * @param phFuzzCtx Where to store the handle to the fuzzing context on success. + * @param pvState Pointer to the memory containing the state. + * @param cbState Size of the state buffer. + */ +RTDECL(int) RTFuzzCtxCreateFromStateMem(PRTFUZZCTX phFuzzCtx, const void *pvState, size_t cbState); + +/** + * Creates a new fuzzing context loading the state from the given file. + * + * @returns IPRT status code. + * @param phFuzzCtx Where to store the handle to the fuzzing context on success. + * @param pszFilename File to load the fuzzing context from. + */ +RTDECL(int) RTFuzzCtxCreateFromStateFile(PRTFUZZCTX phFuzzCtx, const char *pszFilename); + +/** + * Retains a reference to the given fuzzing context. + * + * @returns New reference count on success. + * @param hFuzzCtx Handle of the fuzzing context. + */ +RTDECL(uint32_t) RTFuzzCtxRetain(RTFUZZCTX hFuzzCtx); + +/** + * Releases a reference from the given fuzzing context, destroying it when reaching 0. + * + * @returns New reference count on success, 0 if the fuzzing context got destroyed. + * @param hFuzzCtx Handle of the fuzzing context. + */ +RTDECL(uint32_t) RTFuzzCtxRelease(RTFUZZCTX hFuzzCtx); + +/** + * Queries statistics about the given fuzzing context. + * + * @returns IPRT status code. + * @param hFuzzCtx Handle of the fuzzing context. + * @param pStats Where to store the stats on success. + */ +RTDECL(int) RTFuzzCtxQueryStats(RTFUZZCTX hFuzzCtx, PRTFUZZCTXSTATS pStats); + +/** + * Exports the given fuzzing context state. + * + * @returns IPRT statuse code + * @param hFuzzCtx The fuzzing context to export. + * @param pfnExport Export callback. + * @param pvUser Opaque user data to pass to the callback. + */ +RTDECL(int) RTFuzzCtxStateExport(RTFUZZCTX hFuzzCtx, PFNRTFUZZCTXEXPORT pfnExport, void *pvUser); + +/** + * Exports the given fuzzing context state to memory allocating the buffer. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context to export. + * @param ppvState Where to store the pointer to the memory containing state on success. + * Free with RTMemFree(). + * @param pcbState Where to store the size of the state in bytes. + */ +RTDECL(int) RTFuzzCtxStateExportToMem(RTFUZZCTX hFuzzCtx, void **ppvState, size_t *pcbState); + +/** + * Exports the given fuzzing context state to the given file. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context to export. + * @param pszFilename The file to save the state to. + */ +RTDECL(int) RTFuzzCtxStateExportToFile(RTFUZZCTX hFuzzCtx, const char *pszFilename); + +/** + * Adds a new seed to the input corpus of the given fuzzing context. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param pvInput The pointer to the input buffer. + * @param cbInput Size of the input buffer. + */ +RTDECL(int) RTFuzzCtxCorpusInputAdd(RTFUZZCTX hFuzzCtx, const void *pvInput, size_t cbInput); + +/** + * Adds a new seed to the input corpus of the given fuzzing context - extended version. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param pvInput The pointer to the input buffer. + * @param cbInput Size of the input buffer. + * @param offMutStart Start offset at which a mutation can happen. + * @param cbMutRange Size of the range in bytes where a mutation can happen, + * use UINT64_MAX to allow mutations till the end of the input. + */ +RTDECL(int) RTFuzzCtxCorpusInputAddEx(RTFUZZCTX hFuzzCtx, const void *pvInput, size_t cbInput, + uint64_t offMutStart, uint64_t cbMutRange); + +/** + * Adds a new seed to the input corpus of the given fuzzing context from the given file. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param pszFilename The filename to load the seed from. + */ +RTDECL(int) RTFuzzCtxCorpusInputAddFromFile(RTFUZZCTX hFuzzCtx, const char *pszFilename); + +/** + * Adds a new seed to the input corpus of the given fuzzing context from the given file - extended version. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param pszFilename The filename to load the seed from. + * @param offMutStart Start offset at which a mutation can happen. + * @param cbMutRange Size of the range in bytes where a mutation can happen, + * use UINT64_MAX to allow mutations till the end of the input. + */ +RTDECL(int) RTFuzzCtxCorpusInputAddFromFileEx(RTFUZZCTX hFuzzCtx, const char *pszFilename, + uint64_t offMutStart, uint64_t cbMutRange); + +/** + * Adds a new seed to the input corpus of the given fuzzing context from the given VFS file. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param hVfsFile The VFS file handle to load the seed from. + */ +RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsFile(RTFUZZCTX hFuzzCtx, RTVFSFILE hVfsFile); + +/** + * Adds a new seed to the input corpus of the given fuzzing context from the given VFS file - extended version. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param hVfsFile The VFS file handle to load the seed from. + * @param offMutStart Start offset at which a mutation can happen. + * @param cbMutRange Size of the range in bytes where a mutation can happen, + * use UINT64_MAX to allow mutations till the end of the input. + */ +RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsFileEx(RTFUZZCTX hFuzzCtx, RTVFSFILE hVfsFile, + uint64_t offMutStart, uint64_t cbMutRange); + +/** + * Adds a new seed to the input corpus of the given fuzzing context from the given VFS I/O stream. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param hVfsIos The VFS I/O stream handle to load the seed from. + */ +RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsIoStrm(RTFUZZCTX hFuzzCtx, RTVFSIOSTREAM hVfsIos); + +/** + * Adds a new seed to the input corpus of the given fuzzing context from the given VFS I/O stream - extended version. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param hVfsIos The VFS I/O stream handle to load the seed from. + * @param offMutStart Start offset at which a mutation can happen. + * @param cbMutRange Size of the range in bytes where a mutation can happen, + * use UINT64_MAX to allow mutations till the end of the input. + */ +RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsIoStrmEx(RTFUZZCTX hFuzzCtx, RTVFSIOSTREAM hVfsIos, + uint64_t offMutStart, uint64_t cbMutRange); + +/** + * Adds new seeds to the input corpus of the given fuzzing context from the given directory. + * + * Will only process regular files, i.e. ignores directories, symbolic links, devices, fifos + * and such. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param pszDirPath The directory to load seeds from. + */ +RTDECL(int) RTFuzzCtxCorpusInputAddFromDirPath(RTFUZZCTX hFuzzCtx, const char *pszDirPath); + +/** + * Restricts the maximum input size to generate by the fuzzing context. + * + * @returns IPRT status code + * @param hFuzzCtx The fuzzing context handle. + * @param cbMax Maximum input size in bytes. + */ +RTDECL(int) RTFuzzCtxCfgSetInputSeedMaximum(RTFUZZCTX hFuzzCtx, size_t cbMax); + +/** + * Returns the maximum input size of the given fuzzing context. + * + * @returns Maximum input size generated in bytes. + * @param hFuzzCtx The fuzzing context handle. + */ +RTDECL(size_t) RTFuzzCtxCfgGetInputSeedMaximum(RTFUZZCTX hFuzzCtx); + +/** + * Sets flags controlling the behavior of the fuzzing context. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param fFlags Flags controlling the fuzzing context, RTFUZZCTX_F_XXX. + */ +RTDECL(int) RTFuzzCtxCfgSetBehavioralFlags(RTFUZZCTX hFuzzCtx, uint32_t fFlags); + +/** + * Returns the current set behavioral flags for the given fuzzing context. + * + * @returns Behavioral flags of the given fuzzing context. + * @param hFuzzCtx The fuzzing context handle. + */ +RTDECL(uint32_t) RTFuzzCfgGetBehavioralFlags(RTFUZZCTX hFuzzCtx); + +/** + * Sets the temporary directory used by the fuzzing context. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param pszPathTmp The directory for the temporary state. + */ +RTDECL(int) RTFuzzCtxCfgSetTmpDirectory(RTFUZZCTX hFuzzCtx, const char *pszPathTmp); + +/** + * Returns the current temporary directory. + * + * @returns Current temporary directory. + * @param hFuzzCtx The fuzzing context handle. + */ +RTDECL(const char *) RTFuzzCtxCfgGetTmpDirectory(RTFUZZCTX hFuzzCtx); + +/** + * Sets the range in which a particular input can get mutated. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param offStart Start offset at which a mutation can happen. + * @param cbRange Size of the range in bytes where a mutation can happen, + * use UINT64_MAX to allow mutations till the end of the input. + */ +RTDECL(int) RTFuzzCtxCfgSetMutationRange(RTFUZZCTX hFuzzCtx, uint64_t offStart, uint64_t cbRange); + +/** + * Reseeds the PRNG of the given fuzzing context. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param uSeed The new seed. + */ +RTDECL(int) RTFuzzCtxReseed(RTFUZZCTX hFuzzCtx, uint64_t uSeed); + +/** + * Generates a new input from the given fuzzing context and returns it. + * + * @returns IPRT status code. + * @param hFuzzCtx The fuzzing context handle. + * @param phFuzzInput Where to store the handle to the fuzzed input on success. + */ +RTDECL(int) RTFuzzCtxInputGenerate(RTFUZZCTX hFuzzCtx, PRTFUZZINPUT phFuzzInput); + + +/** + * Retains a reference to the given fuzzing input handle. + * + * @returns New reference count on success. + * @param hFuzzInput The fuzzing input handle. + */ +RTDECL(uint32_t) RTFuzzInputRetain(RTFUZZINPUT hFuzzInput); + +/** + * Releases a reference from the given fuzzing input handle, destroying it when reaching 0. + * + * @returns New reference count on success, 0 if the fuzzing input got destroyed. + * @param hFuzzInput The fuzzing input handle. + */ +RTDECL(uint32_t) RTFuzzInputRelease(RTFUZZINPUT hFuzzInput); + +/** + * Queries the data pointer and size of the given fuzzed input blob. + * + * @returns IPRT status code + * @param hFuzzInput The fuzzing input handle. + * @param ppv Where to store the pointer to the input data on success. + * @param pcb Where to store the size of the input data on success. + */ +RTDECL(int) RTFuzzInputQueryBlobData(RTFUZZINPUT hFuzzInput, void **ppv, size_t *pcb); + +/** + * Processes the given data stream for a streamed fuzzing context. + * + * @returns IPRT status code. + * @param hFuzzInput The fuzzing input handle. + * @param pvBuf The data buffer. + * @param cbBuf Size of the buffer. + */ +RTDECL(int) RTFuzzInputMutateStreamData(RTFUZZINPUT hFuzzInput, void *pvBuf, size_t cbBuf); + +/** + * Queries the string of the MD5 digest for the given fuzzed input. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the size of the string buffer is not sufficient. + * @param hFuzzInput The fuzzing input handle. + * @param pszDigest Where to store the digest string and a closing terminator. + * @param cchDigest Size of the string buffer in characters (including the zero terminator). + */ +RTDECL(int) RTFuzzInputQueryDigestString(RTFUZZINPUT hFuzzInput, char *pszDigest, size_t cchDigest); + +/** + * Writes the given fuzzing input to the given file. + * + * @returns IPRT status code. + * @param hFuzzInput The fuzzing input handle. + * @param pszFilename The filename to store the input to. + */ +RTDECL(int) RTFuzzInputWriteToFile(RTFUZZINPUT hFuzzInput, const char *pszFilename); + +/** + * Adds the given fuzzed input to the input corpus of the owning context. + * + * @returns IPRT status code. + * @retval VERR_ALREADY_EXISTS if the input exists already. + * @param hFuzzInput The fuzzing input handle. + */ +RTDECL(int) RTFuzzInputAddToCtxCorpus(RTFUZZINPUT hFuzzInput); + +/** + * Removes the given fuzzed input from the input corpus of the owning context. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if the input is not part of the corpus. + * @param hFuzzInput The fuzzing input handle. + */ +RTDECL(int) RTFuzzInputRemoveFromCtxCorpus(RTFUZZINPUT hFuzzInput); + + +/** + * Creates a fuzzing config from the given VFS file handle. + * + * @returns IPRT status code. + * @param phFuzzCfg Where to store the handle to the fuzzing config on success. + * @param hVfsFile The VFS file to use (retained). + * @param pErrInfo Where to store extended error info. Optional. + */ +RTDECL(int) RTFuzzCfgCreateFromVfsFile(PRTFUZZCFG phFuzzCfg, RTVFSFILE hVfsFile, PRTERRINFO pErrInfo); + +/** + * Creates a fuzzing config from the given file path. + * + * @returns IPRT status code. + * @param phFuzzCfg Where to store the handle to the fuzzing config on success. + * @param pszFilename Filename to load the config from. + * @param pErrInfo Where to store extended error info. Optional. + */ +RTDECL(int) RTFuzzCfgCreateFromFile(PRTFUZZCFG phFuzzCfg, const char *pszFilename, PRTERRINFO pErrInfo); + +/** + * Retains a reference to the given fuzzing config. + * + * @returns New reference count on success. + * @param hFuzzCfg Handle of the fuzzing config. + */ +RTDECL(uint32_t) RTFuzzCfgRetain(RTFUZZCFG hFuzzCfg); + +/** + * Releases a reference from the given fuzzing config, destroying it when reaching 0. + * + * @returns New reference count on success, 0 if the fuzzing config got destroyed. + * @param hFuzzCfg Handle of the fuzzing config. + */ +RTDECL(uint32_t) RTFuzzCfgRelease(RTFUZZCFG hFuzzCfg); + +/** + * Imports the given fuzzing config into a previously created fuzzing context. + * + * @returns IPRT status code. + * @param hFuzzCfg Handle of the fuzzing config. + * @param hFuzzCtx Handle of the fuzzing context. + * @param fFlags Flags controlling what to import exactly, combination of RTFUZZCFG_IMPORT_F_XXX. + */ +RTDECL(int) RTFuzzCfgImport(RTFUZZCFG hFuzzCfg, RTFUZZCTX hFuzzCtx, uint32_t fFlags); + +/** + * Queries the custom config for the controller of the fuzzing process. + * + * @returns IPRT status code. + * @param hFuzzCfg Handle of the fuzzing config. + * @param phVfsFile Where to store the handle of the VFS file containing the custom config. + */ +RTDECL(int) RTFuzzCfgQueryCustomCfg(RTFUZZCFG hFuzzCfg, PRTVFSFILE phVfsFile); + + +/** + * Creates a new fuzzed target recorder. + * + * @returns IPRT status code. + * @param phFuzzTgtRec Where to store the handle to the fuzzed target recorder on success. + * @param fRecFlags What to take into account when checking for equal states. + * Combination of RTFUZZTGT_REC_STATE_F_* + */ +RTDECL(int) RTFuzzTgtRecorderCreate(PRTFUZZTGTREC phFuzzTgtRec, uint32_t fRecFlags); + +/** + * Retains a reference to the given fuzzed target recorder handle. + * + * @returns New reference count on success. + * @param hFuzzTgtRec The fuzzed target recorder handle. + */ +RTDECL(uint32_t) RTFuzzTgtRecorderRetain(RTFUZZTGTREC hFuzzTgtRec); + +/** + * Releases a reference from the given fuzzed target recorder handle, destroying it when reaching 0. + * + * @returns New reference count on success, 0 if the fuzzed target recorder got destroyed. + * @param hFuzzTgtRec The fuzzed target recorder handle. + */ +RTDECL(uint32_t) RTFuzzTgtRecorderRelease(RTFUZZTGTREC hFuzzTgtRec); + +/** + * Creates a new empty fuzzed target state. + * + * @returns IPRT status code. + * @param hFuzzTgtRec The fuzzed target recorder handle. + * @param phFuzzTgtState Where to store the handle to the fuzzed target state on success. + */ +RTDECL(int) RTFuzzTgtRecorderCreateNewState(RTFUZZTGTREC hFuzzTgtRec, PRTFUZZTGTSTATE phFuzzTgtState); + +/** + * Retains a reference to the given fuzzed target state handle. + * + * @returns New reference count on success. + * @param hFuzzTgtState The fuzzed target state handle. + */ +RTDECL(uint32_t) RTFuzzTgtStateRetain(RTFUZZTGTSTATE hFuzzTgtState); + +/** + * Releases a reference from the given fuzzed target state handle, destroying it when reaching 0. + * + * @returns New reference count on success, 0 if the fuzzed target recorder got destroyed. + * @param hFuzzTgtState The fuzzed target state handle. + */ +RTDECL(uint32_t) RTFuzzTgtStateRelease(RTFUZZTGTSTATE hFuzzTgtState); + +/** + * Resets the given fuzzed target state to an empty state (keeping allocated memory). + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + * + * @note Useful when the state is not added to the recorded set to avoid allocating memory. + */ +RTDECL(int) RTFuzzTgtStateReset(RTFUZZTGTSTATE hFuzzTgtState); + +/** + * Finalizes the given fuzzed target state, making it readonly. + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + */ +RTDECL(int) RTFuzzTgtStateFinalize(RTFUZZTGTSTATE hFuzzTgtState); + +/** + * Adds the given state to the set for the owning target recorder. + * + * @returns IPRT status code. + * @retval VERR_ALREADY_EXISTS if the state is already existing in the recorder set. + * @param hFuzzTgtState The fuzzed target state handle. + * + * @note This also finalizes the target state if not already done. + */ +RTDECL(int) RTFuzzTgtStateAddToRecorder(RTFUZZTGTSTATE hFuzzTgtState); + +/** + * Appends the given stdout output to the given target state. + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + * @param pvStdOut Pointer to the stdout data buffer. + * @param cbStdOut Size of the stdout data buffer in bytes. + */ +RTDECL(int) RTFuzzTgtStateAppendStdoutFromBuf(RTFUZZTGTSTATE hFuzzTgtState, const void *pvStdOut, size_t cbStdOut); + +/** + * Appends the given stderr output to the given target state. + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + * @param pvStdErr Pointer to the stderr data buffer. + * @param cbStdErr Size of the stderr data buffer in bytes. + */ +RTDECL(int) RTFuzzTgtStateAppendStderrFromBuf(RTFUZZTGTSTATE hFuzzTgtState, const void *pvStdErr, size_t cbStdErr); + +/** + * Appends the given stdout output to the given target state, reading from the given pipe. + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + * @param hPipe The stdout pipe to read the data from. + */ +RTDECL(int) RTFuzzTgtStateAppendStdoutFromPipe(RTFUZZTGTSTATE hFuzzTgtState, RTPIPE hPipe); + +/** + * Appends the given stderr output to the given target state, reading from the given pipe. + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + * @param hPipe The stdout pipe to read the data from. + */ +RTDECL(int) RTFuzzTgtStateAppendStderrFromPipe(RTFUZZTGTSTATE hFuzzTgtState, RTPIPE hPipe); + +/** + * Adds the SanCov coverage information from the given file to the given target state. + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + * @param pszFilename Filename of the coverage report. + */ +RTDECL(int) RTFuzzTgtStateAddSanCovReportFromFile(RTFUZZTGTSTATE hFuzzTgtState, const char *pszFilename); + +/** + * Adds the given process status to the target state. + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + * @param pProcSts The process status to add. + */ +RTDECL(int) RTFuzzTgtStateAddProcSts(RTFUZZTGTSTATE hFuzzTgtState, PCRTPROCSTATUS pProcSts); + +/** + * Dumps the given target state to the given directory. + * + * @returns IPRT status code. + * @param hFuzzTgtState The fuzzed target state handle. + * @param pszDirPath The directory to dump to. + */ +RTDECL(int) RTFuzzTgtStateDumpToDir(RTFUZZTGTSTATE hFuzzTgtState, const char *pszDirPath); + + +/** + * Fuzzed binary input channel. + */ +typedef enum RTFUZZOBSINPUTCHAN +{ + /** Invalid. */ + RTFUZZOBSINPUTCHAN_INVALID = 0, + /** File input. */ + RTFUZZOBSINPUTCHAN_FILE, + /** Input over stdin. */ + RTFUZZOBSINPUTCHAN_STDIN, + /** The binary is a fuzzing aware client using the + * specified protocol over stdin/stdout. */ + RTFUZZOBSINPUTCHAN_FUZZING_AWARE_CLIENT, + /** TCP server. */ + RTFUZZOBSINPUTCHAN_TCP_SERVER, + /** TCP client. */ + RTFUZZOBSINPUTCHAN_TCP_CLIENT, + /** UDP server. */ + RTFUZZOBSINPUTCHAN_UDP_SERVER, + /** UDP client. */ + RTFUZZOBSINPUTCHAN_UDP_CLIENT, + /** 32bit hack. */ + RTFUZZOBSINPUTCHAN_32BIT_HACK = 0x7fffffff +} RTFUZZOBSINPUTCHAN; + +/** + * Fuzzing observer statistics. + */ +typedef struct RTFUZZOBSSTATS +{ + /** Number of fuzzed inputs per second. */ + uint32_t cFuzzedInputsPerSec; + /** Number of overall fuzzed inputs. */ + uint32_t cFuzzedInputs; + /** Number of observed hangs. */ + uint32_t cFuzzedInputsHang; + /** Number of observed crashes. */ + uint32_t cFuzzedInputsCrash; +} RTFUZZOBSSTATS; +/** Pointer to a fuzzing observer statistics record. */ +typedef RTFUZZOBSSTATS *PRTFUZZOBSSTATS; + +/** + * Creates a new fuzzing observer. + * + * @returns IPRT status code. + * @param phFuzzObs Where to store the fuzzing observer handle on success. + * @param enmType Fuzzing context data type. + * @param fTgtRecFlags Flags to pass to the target state recorder, see RTFuzzTgtRecorderCreate(). + */ +RTDECL(int) RTFuzzObsCreate(PRTFUZZOBS phFuzzObs, RTFUZZCTXTYPE enmType, uint32_t fTgtRecFlags); + +/** + * Destroys a previously created fuzzing observer. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + */ +RTDECL(int) RTFuzzObsDestroy(RTFUZZOBS hFuzzObs); + +/** + * Queries the internal fuzzing context of the given observer. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param phFuzzCtx Where to store the handle to the fuzzing context on success. + * + * @note The fuzzing context handle should be released with RTFuzzCtxRelease() when not used anymore. + */ +RTDECL(int) RTFuzzObsQueryCtx(RTFUZZOBS hFuzzObs, PRTFUZZCTX phFuzzCtx); + +/** + * Queries the current statistics for the given fuzzing observer. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param pStats Where to store the statistics to. + */ +RTDECL(int) RTFuzzObsQueryStats(RTFUZZOBS hFuzzObs, PRTFUZZOBSSTATS pStats); + +/** + * Sets the temp directory for the given fuzzing observer. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param pszTmp The temp directory path. + */ +RTDECL(int) RTFuzzObsSetTmpDirectory(RTFUZZOBS hFuzzObs, const char *pszTmp); + +/** + * Sets the directory to store results to. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param pszResults The path to store the results. + */ +RTDECL(int) RTFuzzObsSetResultDirectory(RTFUZZOBS hFuzzObs, const char *pszResults); + +/** + * Sets the binary to run for each fuzzed input. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param pszBinary The binary path. + * @param enmInputChan The input channel to use. + */ +RTDECL(int) RTFuzzObsSetTestBinary(RTFUZZOBS hFuzzObs, const char *pszBinary, RTFUZZOBSINPUTCHAN enmInputChan); + +/** + * Sets additional arguments to run the binary with. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param papszArgs Pointer to the array of arguments. + * @param cArgs Number of arguments. + */ +RTDECL(int) RTFuzzObsSetTestBinaryArgs(RTFUZZOBS hFuzzObs, const char * const *papszArgs, unsigned cArgs); + +/** + * Sets an environment block to run the binary in. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param hEnv The environment block to set for the test binary. + * Use RTENV_DEFAULT for the default process environment or + * NULL for an empty environment. + * + * @note Upon successful return of this function the observer has taken ownership over the + * environment block and can alter it in unexpected ways. It also destroys the environment + * block when the observer gets destroyed. So don't touch the environment block after + * calling this function. + */ +RTDECL(int) RTFuzzObsSetTestBinaryEnv(RTFUZZOBS hFuzzObs, RTENV hEnv); + +/** + * Makes the observer aware of any configured sanitizers for the test binary. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param fSanitizers Bitmask of compiled and enabled sanitiziers in the + * target binary. + */ +RTDECL(int) RTFuzzObsSetTestBinarySanitizers(RTFUZZOBS hFuzzObs, uint32_t fSanitizers); + +/** + * Sets maximum timeout until a process is considered hung and killed. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param msTimeoutMax The maximum number of milliseconds to wait until the process + * is considered hung. + */ +RTDECL(int) RTFuzzObsSetTestBinaryTimeout(RTFUZZOBS hFuzzObs, RTMSINTERVAL msTimeoutMax); + +/** + * Starts fuzzing the set binary. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + * @param cProcs Number of processes to run simulteanously, + * 0 will create as many processes as there are CPUs available. + */ +RTDECL(int) RTFuzzObsExecStart(RTFUZZOBS hFuzzObs, uint32_t cProcs); + +/** + * Stops the fuzzing process. + * + * @returns IPRT status code. + * @param hFuzzObs The fuzzing observer handle. + */ +RTDECL(int) RTFuzzObsExecStop(RTFUZZOBS hFuzzObs); + + +/** + * A fuzzing master program. + * + * @returns Program exit code. + * + * @param cArgs The number of arguments. + * @param papszArgs The argument vector. (Note that this may be + * reordered, so the memory must be writable.) + */ +RTR3DECL(RTEXITCODE) RTFuzzCmdMaster(unsigned cArgs, char **papszArgs); + + +/** + * Client input consumption callback. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS the fuzzed code accepted the input. + * @retval VERR_* the client rejected the input while parsing it. + * @param pvBuf The buffer containing the input data. + * @param cbBuf Size of the buffer in bytes. + * @param pvUser Opaque user data. + */ +typedef DECLCALLBACKTYPE(int, FNFUZZCLIENTCONSUME,(const void *pvBuf, size_t cbBuf, void *pvUser)); +/** Pointer to a client consumption callback. */ +typedef FNFUZZCLIENTCONSUME *PFNFUZZCLIENTCONSUME; + +/** + * A fuzzing client program for more efficient fuzzing. + * + * @returns Program exit code. + * + * @param cArgs The number of arguments. + * @param papszArgs The argument vector. (Note that this may be + * reordered, so the memory must be writable.) + * @param pfnConsume Input data consumption callback. + * @param pvUser Opaque user data to pass to the callback. + */ +RTR3DECL(RTEXITCODE) RTFuzzCmdFuzzingClient(unsigned cArgs, char **papszArgs, PFNFUZZCLIENTCONSUME pfnConsume, void *pvUser); +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_fuzz_h */ + diff --git a/include/iprt/getopt.h b/include/iprt/getopt.h new file mode 100644 index 00000000..57a2bbcf --- /dev/null +++ b/include/iprt/getopt.h @@ -0,0 +1,564 @@ +/** @file + * IPRT - Command Line Parsing. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_getopt_h +#define IPRT_INCLUDED_getopt_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/errcore.h> /* for VINF_GETOPT_NOT_OPTION */ + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_getopt RTGetOpt - Command Line Parsing + * @ingroup grp_rt + * @{ + */ + +/** @name Values for RTGETOPTDEF::fFlags and the fFlags parameter of + * RTGetOptFetchValue. + * + * @remarks When neither of the RTGETOPT_FLAG_HEX, RTGETOPT_FLAG_OCT and RTGETOPT_FLAG_DEC + * flags are specified with a integer value format, RTGetOpt will default to + * decimal but recognize the 0x prefix when present. RTGetOpt will not look for + * for the octal prefix (0). + * @{ */ +/** Requires no extra argument. + * (Can be assumed to be 0 for ever.) */ +#define RTGETOPT_REQ_NOTHING 0 +/** A value is required or error will be returned. */ +#define RTGETOPT_REQ_STRING 1 +/** The value must be a valid signed 8-bit integer or an error will be returned. */ +#define RTGETOPT_REQ_INT8 2 +/** The value must be a valid unsigned 8-bit integer or an error will be returned. */ +#define RTGETOPT_REQ_UINT8 3 +/** The value must be a valid signed 16-bit integer or an error will be returned. */ +#define RTGETOPT_REQ_INT16 4 +/** The value must be a valid unsigned 16-bit integer or an error will be returned. */ +#define RTGETOPT_REQ_UINT16 5 +/** The value must be a valid signed 32-bit integer or an error will be returned. */ +#define RTGETOPT_REQ_INT32 6 +/** The value must be a valid unsigned 32-bit integer or an error will be returned. */ +#define RTGETOPT_REQ_UINT32 7 +/** The value must be a valid signed 64-bit integer or an error will be returned. */ +#define RTGETOPT_REQ_INT64 8 +/** The value must be a valid unsigned 64-bit integer or an error will be returned. */ +#define RTGETOPT_REQ_UINT64 9 +/** The value must be a valid IPv4 address. + * (Not a name, but 4 values in the 0..255 range with dots separating them). */ +#define RTGETOPT_REQ_IPV4ADDR 10 +/** The value must be a valid IPv4 CIDR. + * As with RTGETOPT_REQ_IPV4ADDR, no name. + */ +#define RTGETOPT_REQ_IPV4CIDR 11 +#if 0 +/* take placers */ +/** The value must be a valid IPv6 addr + * @todo: Add types and parsing routines in (iprt/net.h) + */ +#define RTGETOPT_REQ_IPV6ADDR 12 +/** The value must be a valid IPv6 CIDR + * @todo: Add types and parsing routines in (iprt/net.h) + */ +#define RTGETOPT_REQ_IPV6CIDR 13 +#endif +/** The value must be a valid ethernet MAC address. */ +#define RTGETOPT_REQ_MACADDR 14 +/** The value must be a valid UUID. */ +#define RTGETOPT_REQ_UUID 15 +/** The value must be a string with value as "on" or "off". */ +#define RTGETOPT_REQ_BOOL_ONOFF 16 +/** Boolean option accepting a wide range of typical ways of + * expression true and false. */ +#define RTGETOPT_REQ_BOOL 17 +/** The value must two unsigned 32-bit integer values separated by a colon, + * slash, pipe or space(s). */ +#define RTGETOPT_REQ_UINT32_PAIR 18 +/** The value must two unsigned 64-bit integer values separated by a colon, + * slash, pipe or space(s). */ +#define RTGETOPT_REQ_UINT64_PAIR 19 +/** The value must at least unsigned 32-bit integer value, optionally + * followed by a second separated by a colon, slash, pipe or space(s). */ +#define RTGETOPT_REQ_UINT32_OPTIONAL_PAIR 20 +/** The value must at least unsigned 64-bit integer value, optionally + * followed by a second separated by a colon, slash, pipe or space(s). */ +#define RTGETOPT_REQ_UINT64_OPTIONAL_PAIR 21 +/** The mask of the valid required types. */ +#define RTGETOPT_REQ_MASK 31 +/** Treat the value as hexadecimal - only applicable with the RTGETOPT_REQ_*INT*. */ +#define RTGETOPT_FLAG_HEX RT_BIT(16) +/** Treat the value as octal - only applicable with the RTGETOPT_REQ_*INT*. */ +#define RTGETOPT_FLAG_OCT RT_BIT(17) +/** Treat the value as decimal - only applicable with the RTGETOPT_REQ_*INT*. */ +#define RTGETOPT_FLAG_DEC RT_BIT(18) +/** The index value is attached to the argument - only valid for long arguments. */ +#define RTGETOPT_FLAG_INDEX RT_BIT(19) +/** Used with RTGETOPT_FLAG_INDEX, setting index to zero if none given. + * (The default is to fail with VERR_GETOPT_INDEX_MISSING.) */ +#define RTGETOPT_FLAG_INDEX_DEF_0 RT_BIT(20) +/** Used with RTGETOPT_FLAG_INDEX, setting index to one if none given. + * (The default is to fail with VERR_GETOPT_INDEX_MISSING.) */ +#define RTGETOPT_FLAG_INDEX_DEF_1 RT_BIT(21) +/** For simplicity. */ +#define RTGETOPT_FLAG_INDEX_DEF_MASK (RT_BIT(20) | RT_BIT(21)) +/** For simple conversion. */ +#define RTGETOPT_FLAG_INDEX_DEF_SHIFT 20 +/** For use with RTGETOPT_FLAG_INDEX_DEF_0 or RTGETOPT_FLAG_INDEX_DEF_1 to + * imply a dash before the index when a digit is specified. + * This is for transitioning from options without index to optionally allow + * index options, i.e. "--long" defaults to either index 1 or 1 using the above + * flags, while "--long-1" explicitly gives the index ("--long-" is not valid). + * This flag matches an "-" separating the "--long" string + * (RTGETOPTDEFS::pszLong) from the index value. */ +#define RTGETOPT_FLAG_INDEX_DEF_DASH RT_BIT(22) +/** Treat the long option as case insensitive. */ +#define RTGETOPT_FLAG_ICASE RT_BIT(23) +/** Mask of valid bits - for validation. */ +#define RTGETOPT_VALID_MASK ( RTGETOPT_REQ_MASK \ + | RTGETOPT_FLAG_HEX \ + | RTGETOPT_FLAG_OCT \ + | RTGETOPT_FLAG_DEC \ + | RTGETOPT_FLAG_INDEX \ + | RTGETOPT_FLAG_INDEX_DEF_0 \ + | RTGETOPT_FLAG_INDEX_DEF_1 \ + | RTGETOPT_FLAG_INDEX_DEF_DASH \ + | RTGETOPT_FLAG_ICASE ) +/** @} */ + +/** + * An option definition. + */ +typedef struct RTGETOPTDEF +{ + /** The long option. + * This is optional */ + const char *pszLong; + /** The short option character. + * This doesn't have to be a character, it may also be a \#define or enum value if + * there isn't any short version of this option. Must be greater than 0. */ + int iShort; + /** The flags (RTGETOPT_*). */ + unsigned fFlags; +} RTGETOPTDEF; +/** Pointer to an option definition. */ +typedef RTGETOPTDEF *PRTGETOPTDEF; +/** Pointer to an const option definition. */ +typedef const RTGETOPTDEF *PCRTGETOPTDEF; + +/** + * Option argument union. + * + * What ends up here depends on argument format in the option definition. + */ +typedef union RTGETOPTUNION +{ + /** Pointer to the definition on failure or when the option doesn't take an argument. + * This can be NULL for some errors. */ + PCRTGETOPTDEF pDef; + /** A RTGETOPT_REQ_STRING option argument. */ + const char *psz; + + /** A RTGETOPT_REQ_INT8 option argument. */ + int8_t i8; + /** A RTGETOPT_REQ_UINT8 option argument . */ + uint8_t u8; + /** A RTGETOPT_REQ_INT16 option argument. */ + int16_t i16; + /** A RTGETOPT_REQ_UINT16 option argument . */ + uint16_t u16; + /** A RTGETOPT_REQ_INT16 option argument. */ + int32_t i32; + /** A RTGETOPT_REQ_UINT32 option argument . */ + uint32_t u32; + /** A RTGETOPT_REQ_INT64 option argument. */ + int64_t i64; + /** A RTGETOPT_REQ_UINT64 option argument. */ + uint64_t u64; +#ifdef IPRT_INCLUDED_net_h + /** A RTGETOPT_REQ_IPV4ADDR option argument. */ + RTNETADDRIPV4 IPv4Addr; + /** A RTGETOPT_REQ_IPV4CIDR option argument. */ + struct + { + RTNETADDRIPV4 IPv4Network; + RTNETADDRIPV4 IPv4Netmask; + } CidrIPv4; +#endif + /** A RTGETOPT_REQ_MACADDR option argument. */ + RTMAC MacAddr; + /** A RTGETOPT_REQ_UUID option argument. */ + RTUUID Uuid; + /** A boolean flag. */ + bool f; + /** A RTGETOPT_REQ_UINT32_PAIR or RTGETOPT_REQ_UINT32_OPTIONAL_PAIR option + * argument. */ + struct + { + uint32_t uFirst; + uint32_t uSecond; /**< Set to UINT32_MAX if optional and not present. */ + } PairU32; + /** A RTGETOPT_REQ_UINT64_COLON_PAIR option argument. */ + struct + { + uint64_t uFirst; + uint64_t uSecond; /**< Set to UINT64_MAX if optional and not present. */ + } PairU64; +} RTGETOPTUNION; +/** Pointer to an option argument union. */ +typedef RTGETOPTUNION *PRTGETOPTUNION; +/** Pointer to a const option argument union. */ +typedef RTGETOPTUNION const *PCRTGETOPTUNION; + + +/** + * RTGetOpt state. + */ +typedef struct RTGETOPTSTATE +{ + /** The next argument. */ + int iNext; + /** Argument array. */ + char **argv; + /** Number of items in argv. */ + int argc; + /** Option definition array. */ + PCRTGETOPTDEF paOptions; + /** Number of items in paOptions. */ + size_t cOptions; + /** The next short option. + * (For parsing ls -latrT4 kind of option lists.) */ + const char *pszNextShort; + /** The option definition which matched. NULL otherwise. */ + PCRTGETOPTDEF pDef; + /** The index of an index option, otherwise UINT32_MAX. */ + uint32_t uIndex; + /** The flags passed to RTGetOptInit. */ + uint32_t fFlags; + /** Number of non-options that we're skipping during a sorted get. The value + * INT32_MAX is used to indicate that there are no more options. This is used + * to implement '--'. */ + int32_t cNonOptions; + + /* More members may be added later for dealing with new features. */ +} RTGETOPTSTATE; +/** Pointer to RTGetOpt state. */ +typedef RTGETOPTSTATE *PRTGETOPTSTATE; + + +/** + * Initialize the RTGetOpt state. + * + * The passed in argument vector may be sorted if fFlags indicates that this is + * desired (to be implemented). + * + * @returns VINF_SUCCESS, VERR_INVALID_PARAMETER or VERR_INVALID_POINTER. + * @param pState The state. + * + * @param argc Argument count, to be copied from what comes in with + * main(). + * @param argv Argument array, to be copied from what comes in with + * main(). This may end up being modified by the + * option/argument sorting. + * @param paOptions Array of RTGETOPTDEF structures, which must specify what + * options are understood by the program. + * @param cOptions Number of array items passed in with paOptions. + * @param iFirst The argument to start with (in argv). + * @param fFlags The flags, see RTGETOPTINIT_FLAGS_XXX. + */ +RTDECL(int) RTGetOptInit(PRTGETOPTSTATE pState, int argc, char **argv, + PCRTGETOPTDEF paOptions, size_t cOptions, + int iFirst, uint32_t fFlags); + +/** @name RTGetOptInit flags. + * @{ */ +/** Sort the arguments so that options comes first, then non-options. */ +#define RTGETOPTINIT_FLAGS_OPTS_FIRST RT_BIT_32(0) +/** Prevent add the standard version and help options: + * - "--help", "-h" and "-?" returns 'h'. + * - "--version" and "-V" return 'V'. + */ +#define RTGETOPTINIT_FLAGS_NO_STD_OPTS RT_BIT_32(1) +/** @} */ + +/** + * Command line argument parser, handling both long and short options and checking + * argument formats, if desired. + * + * This is to be called in a loop until it returns 0 (meaning that all options + * were parsed) or a negative value (meaning that an error occurred). How non-option + * arguments are dealt with depends on the flags passed to RTGetOptInit. The default + * (fFlags = 0) is to return VINF_GETOPT_NOT_OPTION with pValueUnion->psz pointing to + * the argument string. + * + * For example, for a program which takes the following options: + * + * --optwithstring (or -s) and a string argument; + * --optwithint (or -i) and a 32-bit signed integer argument; + * --verbose (or -v) with no arguments, + * + * code would look something like this: + * + * @code +int main(int argc, char **argv) +{ + int rc = RTR3Init(); + if (RT_FAILURE(rc)) + return RTMsgInitFailure(rc); + + static const RTGETOPTDEF s_aOptions[] = + { + { "--optwithstring", 's', RTGETOPT_REQ_STRING }, + { "--optwithint", 'i', RTGETOPT_REQ_INT32 }, + { "--verbose", 'v', 0 }, + }; + + int ch; + RTGETOPTUNION ValueUnion; + RTGETOPTSTATE GetState; + RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0); + while ((ch = RTGetOpt(&GetState, &ValueUnion))) + { + // for options that require an argument, ValueUnion has received the value + switch (ch) + { + case 's': // --optwithstring or -s + // string argument, copy ValueUnion.psz + break; + + case 'i': // --optwithint or -i + // integer argument, copy ValueUnion.i32 + break; + + case 'v': // --verbose or -v + g_fOptVerbose = true; + break; + + case VINF_GETOPT_NOT_OPTION: + // handle non-option argument in ValueUnion.psz. + break; + + default: + return RTGetOptPrintError(ch, &ValueUnion); + } + } + + return RTEXITCODE_SUCCESS; +} + @endcode + * + * @returns 0 when done parsing. + * @returns the iShort value of the option. pState->pDef points to the option + * definition which matched. + * @returns IPRT error status on parse error. + * @returns VINF_GETOPT_NOT_OPTION when encountering a non-option argument and + * RTGETOPTINIT_FLAGS_OPTS_FIRST was not specified. pValueUnion->psz + * points to the argument string. + * @returns VERR_GETOPT_UNKNOWN_OPTION when encountering an unknown option. + * pValueUnion->psz points to the option string. + * @returns VERR_GETOPT_REQUIRED_ARGUMENT_MISSING and pValueUnion->pDef if + * a required argument (aka value) was missing for an option. + * @returns VERR_GETOPT_INVALID_ARGUMENT_FORMAT and pValueUnion->pDef if + * argument (aka value) conversion failed. + * + * @param pState The state previously initialized with RTGetOptInit. + * @param pValueUnion Union with value; in the event of an error, psz member + * points to erroneous parameter; otherwise, for options + * that require an argument, this contains the value of + * that argument, depending on the type that is required. + */ +RTDECL(int) RTGetOpt(PRTGETOPTSTATE pState, PRTGETOPTUNION pValueUnion); + +/** + * Fetch a value. + * + * Used to retrive a value argument in a manner similar to what RTGetOpt does + * (@a fFlags -> @a pValueUnion). This can be used when handling + * VINF_GETOPT_NOT_OPTION, but is equally useful for decoding options that + * takes more than one value. + * + * @returns VINF_SUCCESS on success. + * @returns IPRT error status on parse error. + * @returns VERR_INVALID_PARAMETER if the flags are wrong. + * @returns VERR_GETOPT_UNKNOWN_OPTION when pState->pDef is null. + * @returns VERR_GETOPT_REQUIRED_ARGUMENT_MISSING if there are no more + * available arguments. pValueUnion->pDef is NULL. + * @returns VERR_GETOPT_INVALID_ARGUMENT_FORMAT and pValueUnion->pDef is + * unchanged if value conversion failed. + * + * @param pState The state previously initialized with RTGetOptInit. + * @param pValueUnion Union with value; in the event of an error, psz member + * points to erroneous parameter; otherwise, for options + * that require an argument, this contains the value of + * that argument, depending on the type that is required. + * @param fFlags What to get, that is RTGETOPT_REQ_XXX. + */ +RTDECL(int) RTGetOptFetchValue(PRTGETOPTSTATE pState, PRTGETOPTUNION pValueUnion, uint32_t fFlags); + +/** + * Gets the pointer to the argv entry of the current non-option argument. + * + * This function ASSUMES the previous RTGetOpt() call returned + * VINF_GETOPT_NOT_OPTION and require RTGETOPTINIT_FLAGS_OPTS_FIRST to be + * specified to RTGetOptInit(). + * + * @returns Pointer to the argv entry of the current non-option. NULL if + * (detectable) precondition isn't fullfilled (asserted) + * @param pState The state previously initialized with RTGetOptInit. + */ +RTDECL(char **) RTGetOptNonOptionArrayPtr(PRTGETOPTSTATE pState); + +/** + * Print error messages for a RTGetOpt default case. + * + * Uses RTMsgError. + * + * @returns Suitable exit code. + * + * @param ch The RTGetOpt return value. + * @param pValueUnion The value union returned by RTGetOpt. + */ +RTDECL(RTEXITCODE) RTGetOptPrintError(int ch, PCRTGETOPTUNION pValueUnion); + +/** + * Formats error messages for a RTGetOpt default case. + * + * @returns On success, positive count of formatted character excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator char). (RTStrPrintf2 style.) + * + * @param pszBuf The buffer to format into. + * @param cbBuf The size of the buffer @a pszBuf points to. + * @param ch The RTGetOpt return value. + * @param pValueUnion The value union returned by RTGetOpt. + */ +RTDECL(ssize_t) RTGetOptFormatError(char *pszBuf, size_t cbBuf, int ch, PCRTGETOPTUNION pValueUnion); + +/** + * Parses the @a pszCmdLine string into an argv array. + * + * This is useful for converting a response file or similar to an argument + * vector that can be used with RTGetOptInit(). + * + * This function aims at following the bourne shell string quoting rules. + * + * @returns IPRT status code. + * + * @param ppapszArgv Where to return the argument vector. This must be + * freed by calling RTGetOptArgvFreeEx or + * RTGetOptArgvFree. + * @param pcArgs Where to return the argument count. + * @param pszCmdLine The string to parse. + * @param fFlags A combination of the RTGETOPTARGV_CNV_XXX flags, + * except RTGETOPTARGV_CNV_UNQUOTED is not supported. + * @param pszSeparators String containing the argument separators. If NULL, + * then space, tab, line feed (\\n) and return (\\r) + * are used. + */ +RTDECL(int) RTGetOptArgvFromString(char ***ppapszArgv, int *pcArgs, const char *pszCmdLine, uint32_t fFlags, + const char *pszSeparators); + +/** + * Frees and argument vector returned by RTGetOptStringToArgv. + * + * @param papszArgv Argument vector. NULL is fine. + */ +RTDECL(void) RTGetOptArgvFree(char **papszArgv); + +/** + * Frees and argument vector returned by RTGetOptStringToArgv, taking + * RTGETOPTARGV_CNV_MODIFY_INPUT into account. + * + * @param papszArgv Argument vector. NULL is fine. + * @param fFlags The flags passed to RTGetOptStringToArgv. + */ +RTDECL(void) RTGetOptArgvFreeEx(char **papszArgv, uint32_t fFlags); + +/** + * Turns an argv array into a command line string. + * + * This is useful for calling CreateProcess on Windows, but can also be used for + * displaying an argv array. + * + * This function aims at following the bourn shell string quoting rules. + * + * @returns IPRT status code. + * + * @param ppszCmdLine Where to return the command line string. This must + * be freed by calling RTStrFree. + * @param papszArgv The argument vector to convert. + * @param fFlags A combination of the RTGETOPTARGV_CNV_XXX flags. + */ +RTDECL(int) RTGetOptArgvToString(char **ppszCmdLine, const char * const *papszArgv, uint32_t fFlags); + +/** @name RTGetOptArgvToString, RTGetOptArgvToUtf16String and + * RTGetOptArgvFromString flags + * @{ */ +/** Quote strings according to the Microsoft CRT rules. */ +#define RTGETOPTARGV_CNV_QUOTE_MS_CRT UINT32_C(0x00000000) +/** Quote strings according to the Unix Bourne Shell. */ +#define RTGETOPTARGV_CNV_QUOTE_BOURNE_SH UINT32_C(0x00000001) +/** Don't quote any strings at all. */ +#define RTGETOPTARGV_CNV_UNQUOTED UINT32_C(0x00000002) +/** Mask for the quoting style. */ +#define RTGETOPTARGV_CNV_QUOTE_MASK UINT32_C(0x00000003) +/** Allow RTGetOptArgvFromString to modifying the command line input string. + * @note Must use RTGetOptArgvFreeEx to free. */ +#define RTGETOPTARGV_CNV_MODIFY_INPUT UINT32_C(0x00000004) +/** Valid bits. */ +#define RTGETOPTARGV_CNV_VALID_MASK UINT32_C(0x00000007) +/** @} */ + +/** + * Convenience wrapper around RTGetOpArgvToString and RTStrToUtf16. + * + * @returns IPRT status code. + * + * @param ppwszCmdLine Where to return the command line string. This must + * be freed by calling RTUtf16Free. + * @param papszArgv The argument vector to convert. + * @param fFlags A combination of the RTGETOPTARGV_CNV_XXX flags. + */ +RTDECL(int) RTGetOptArgvToUtf16String(PRTUTF16 *ppwszCmdLine, const char * const *papszArgv, uint32_t fFlags); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_getopt_h */ + diff --git a/include/iprt/handle.h b/include/iprt/handle.h new file mode 100644 index 00000000..9f4ad5bd --- /dev/null +++ b/include/iprt/handle.h @@ -0,0 +1,81 @@ +/** @file + * IPRT - Generic Handle Operations. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_handle_h +#define IPRT_INCLUDED_handle_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_handle RTHandle - Generic Handle Operations + * @ingroup grp_rt + * @{ + */ + +/** + * Closes or destroy a generic handle. + * + * @returns IPRT status code. + * @param ph Pointer to the generic handle. The structure handle + * will be set to NIL. A NULL pointer or a NIL handle + * will be quietly ignore (VINF_SUCCESS). + */ +RTDECL(int) RTHandleClose(PRTHANDLE ph); + +/** + * Gets one of the standard handles. + * + * @returns IPRT status code. + * @param enmStdHandle The standard handle. + * @param fLeaveOpen Whether closing the returned handle should leave the + * native standard handle open or not. + * Note! This currently only works with pipes and + * sockets! + * @param ph Pointer to the generic handle. This will contain + * the most appropriate IPRT handle on success. + */ +RTDECL(int) RTHandleGetStandard(RTHANDLESTD enmStdHandle, bool fLeaveOpen, PRTHANDLE ph); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_handle_h */ + diff --git a/include/iprt/handletable.h b/include/iprt/handletable.h new file mode 100644 index 00000000..98d243af --- /dev/null +++ b/include/iprt/handletable.h @@ -0,0 +1,259 @@ +/** @file + * IPRT - Handle Tables. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_handletable_h +#define IPRT_INCLUDED_handletable_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_handletable RTHandleTable - Handle Tables + * @ingroup grp_rt + * @{ + */ + +/** + * Callback for retaining an object during the lookup and free calls. + * + * This callback is executed when a handle is being looked up in one + * way or another from behind the handle table lock. This allows you + * to increase the reference (or some equivalent thing) during the + * handle lookup and thereby eliminate any race with anyone trying + * to free the handle. + * + * Note that there is no counterpart to this callback, so if you make + * use of this you'll have to release the object manually of course. + * + * Another use of this callback is to do some extra access checking. + * Use the return code to indicate whether the lookup should fail + * or not (no object is returned on faliure, naturally). + * + * @returns IPRT status code for the lookup (the caller won't see this). + * + * @param hHandleTable The handle table handle. + * @param pvObj The object which has been looked up. + * @param pvCtx The context argument if the handle table was created with the + * RTHANDLETABLE_FLAGS_CONTEXT set. Otherwise NULL. + * @param pvUser The user context argument specified when creating the table. + */ +typedef DECLCALLBACKTYPE(int, FNRTHANDLETABLERETAIN,(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, void *pvUser)); +/** Pointer to a FNHANDLETABLERETAIN. */ +typedef FNRTHANDLETABLERETAIN *PFNRTHANDLETABLERETAIN; + +/** + * Callback for deleting a left over object during RTHandleTableDestroy. + * + * @param hHandleTable The handle table handle. + * @param h The handle. + * @param pvObj The object. + * @param pvCtx The context argument if the handle table was created with the + * RTHANDLETABLE_FLAGS_CONTEXT set. Otherwise NULL. + * @param pvUser The user context argument specified when creating the table. + * + */ +typedef DECLCALLBACKTYPE(void, FNRTHANDLETABLEDELETE,(RTHANDLETABLE hHandleTable, uint32_t h, void *pvObj, void *pvCtx, void *pvUser)); +/** Pointer to a FNRTHANDLETABLEDELETE. */ +typedef FNRTHANDLETABLEDELETE *PFNRTHANDLETABLEDELETE; + + +/** @name RTHandleTableCreateEx flags + * @{ */ +/** Whether the handle table entries takes a context or not. + * + * This can be useful for associating a handle with for instance a process or + * similar in order to prevent anyone but the owner from using the handle. + * + * Setting this means you will have to use the WithCtx functions to do the + * handle management. */ +#define RTHANDLETABLE_FLAGS_CONTEXT RT_BIT_32(0) +/** Whether the handle table should take care of the serialization (IRQ unsafe). + * If not specified the caller will have to take care of that. */ +#define RTHANDLETABLE_FLAGS_LOCKED RT_BIT_32(1) +/** Like RTHANDLETABLE_FLAGS_LOCKED, except it's IRQ safe. + * A side-effect is that callbacks may be called with IRQs disabled. */ +#define RTHANDLETABLE_FLAGS_LOCKED_IRQ_SAFE RT_BIT_32(2) +/** The mask of valid flags. */ +#define RTHANDLETABLE_FLAGS_MASK UINT32_C(0x00000007) +/** @} */ + + +/** + * Creates a handle table. + * + * The handle table translates a 32-bit handle into an object pointer, + * optionally calling you back so you can retain the object without + * racing RTHandleTableFree. + * + * @returns IPRT status code and on success a handle table handle will be stored at the + * location phHandleTable points at. + * + * @param phHandleTable Where to store the handle table handle on success. + * @param fFlags Flags, see RTHANDLETABLE_FLAGS_*. + * @param uBase The handle base value. This is the value of the + * first handle to be returned. + * @param cMax The max number of handles. When exceeded the RTHandleTableAlloc + * or RTHandleTableAllocWithCtx calls will fail. Note that this + * number will be rounded up to a multiple of the sub-table size, + * or if it's too close to UINT32_MAX it will be rounded down. + * @param pfnRetain Optional retain callback that will be called from behind the + * lock (if any) during lookup. + * @param pvUser The user argument to the retain callback. + */ +RTDECL(int) RTHandleTableCreateEx(PRTHANDLETABLE phHandleTable, uint32_t fFlags, uint32_t uBase, uint32_t cMax, + PFNRTHANDLETABLERETAIN pfnRetain, void *pvUser); + +/** + * A simplified version of the RTHandleTableCreateEx API. + * + * It assumes a max of about 64K handles with 1 being the base. The table + * access will serialized (RTHANDLETABLE_FLAGS_LOCKED). + * + * @returns IPRT status code and *phHandleTable. + * + * @param phHandleTable Where to store the handle table handle on success. + */ +RTDECL(int) RTHandleTableCreate(PRTHANDLETABLE phHandleTable); + +/** + * Destroys a handle table. + * + * If any entries are still in used the pfnDelete callback will be invoked + * on each of them (if specfied) to allow to you clean things up. + * + * @returns IPRT status code + * + * @param hHandleTable The handle to the handle table. + * @param pfnDelete Function to be called back on each handle still in use. Optional. + * @param pvUser The user argument to pfnDelete. + */ +RTDECL(int) RTHandleTableDestroy(RTHANDLETABLE hHandleTable, PFNRTHANDLETABLEDELETE pfnDelete, void *pvUser); + +/** + * Allocates a handle from the handle table. + * + * @returns IPRT status code, almost any. + * @retval VINF_SUCCESS on success. + * @retval VERR_NO_MEMORY if we failed to extend the handle table. + * @retval VERR_NO_MORE_HANDLES if we're out of handles. + * + * @param hHandleTable The handle to the handle table. + * @param pvObj The object to associate with the new handle. + * This must be aligned on a 4 byte boundary. + * @param ph Where to return the handle on success. + * + * @remarks Do not call this if RTHANDLETABLE_FLAGS_CONTEXT was used during creation. + */ +RTDECL(int) RTHandleTableAlloc(RTHANDLETABLE hHandleTable, void *pvObj, uint32_t *ph); + +/** + * Looks up a handle. + * + * @returns The object pointer on success. NULL on failure. + * + * @param hHandleTable The handle to the handle table. + * @param h The handle to lookup. + * + * @remarks Do not call this if RTHANDLETABLE_FLAGS_CONTEXT was used during creation. + */ +RTDECL(void *) RTHandleTableLookup(RTHANDLETABLE hHandleTable, uint32_t h); + +/** + * Looks up and frees a handle. + * + * @returns The object pointer on success. NULL on failure. + * + * @param hHandleTable The handle to the handle table. + * @param h The handle to lookup. + * + * @remarks Do not call this if RTHANDLETABLE_FLAGS_CONTEXT was used during creation. + */ +RTDECL(void *) RTHandleTableFree(RTHANDLETABLE hHandleTable, uint32_t h); + +/** + * Allocates a handle from the handle table. + * + * @returns IPRT status code, almost any. + * @retval VINF_SUCCESS on success. + * @retval VERR_NO_MEMORY if we failed to extend the handle table. + * @retval VERR_NO_MORE_HANDLES if we're out of handles. + * + * @param hHandleTable The handle to the handle table. + * @param pvObj The object to associate with the new handle. + * This must be aligned on a 4 byte boundary. + * @param pvCtx The context to associate with the new handle. + * @param ph Where to return the handle on success. + * + * @remarks Call this if RTHANDLETABLE_FLAGS_CONTEXT was used during creation. + */ +RTDECL(int) RTHandleTableAllocWithCtx(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, uint32_t *ph); + +/** + * Looks up a handle. + * + * @returns The object pointer on success. NULL on failure. + * + * @param hHandleTable The handle to the handle table. + * @param h The handle to lookup. + * @param pvCtx The handle context, this must match what was given on allocation. + * + * @remarks Call this if RTHANDLETABLE_FLAGS_CONTEXT was used during creation. + */ +RTDECL(void *) RTHandleTableLookupWithCtx(RTHANDLETABLE hHandleTable, uint32_t h, void *pvCtx); + +/** + * Looks up and frees a handle. + * + * @returns The object pointer on success. NULL on failure. + * + * @param hHandleTable The handle to the handle table. + * @param h The handle to lookup. + * @param pvCtx The handle context, this must match what was given on allocation. + * + * @remarks Call this if RTHANDLETABLE_FLAGS_CONTEXT was used during creation. + */ +RTDECL(void *) RTHandleTableFreeWithCtx(RTHANDLETABLE hHandleTable, uint32_t h, void *pvCtx); + +/** @} */ + +RT_C_DECLS_END + + +#endif /* !IPRT_INCLUDED_handletable_h */ + diff --git a/include/iprt/heap.h b/include/iprt/heap.h new file mode 100644 index 00000000..bf2b3853 --- /dev/null +++ b/include/iprt/heap.h @@ -0,0 +1,369 @@ +/** @file + * IPRT - Heap Implementations + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_heap_h +#define IPRT_INCLUDED_heap_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_heap RTHeap - Heap Implementations + * @ingroup grp_rt + * @{ + */ + + +/** @defgroup grp_rt_heap_simple RTHeapSimple - Simple Heap + * @{ + */ + +/** + * Initializes the heap. + * + * @returns IPRT status code. + * @param pHeap Where to store the heap anchor block on success. + * @param pvMemory Pointer to the heap memory. + * @param cbMemory The size of the heap memory. + */ +RTDECL(int) RTHeapSimpleInit(PRTHEAPSIMPLE pHeap, void *pvMemory, size_t cbMemory); + +/** + * Merge two simple heaps into one. + * + * The requirement is of course that they next two each other memory wise. + * + * @returns IPRT status code. + * @param pHeap Where to store the handle to the merged heap on success. + * @param Heap1 Handle to the first heap. + * @param Heap2 Handle to the second heap. + * @remark This API isn't implemented yet. + */ +RTDECL(int) RTHeapSimpleMerge(PRTHEAPSIMPLE pHeap, RTHEAPSIMPLE Heap1, RTHEAPSIMPLE Heap2); + +/** + * Relocater the heap internal structures after copying it to a new location. + * + * This can be used when loading a saved heap. + * + * @returns IPRT status code. + * @param hHeap Heap handle that has already been adjusted by to the new + * location. That is to say, when calling + * RTHeapSimpleInit, the caller must note the offset of the + * returned heap handle into the heap memory. This offset + * must be used when calcuating the handle value for the + * new location. The offset may in some cases not be zero! + * @param offDelta The delta between the new and old location, i.e. what + * should be added to the internal pointers. + */ +RTDECL(int) RTHeapSimpleRelocate(RTHEAPSIMPLE hHeap, uintptr_t offDelta); + +/** + * Allocates memory from the specified simple heap. + * + * @returns Pointer to the allocated memory block on success. + * @returns NULL if the request cannot be satisfied. (A VERR_NO_MEMORY condition.) + * + * @param Heap The heap to allocate the memory on. + * @param cb The requested heap block size. + * @param cbAlignment The requested heap block alignment. Pass 0 for default alignment. + * Must be a power of 2. + */ +RTDECL(void *) RTHeapSimpleAlloc(RTHEAPSIMPLE Heap, size_t cb, size_t cbAlignment); + +/** + * Allocates zeroed memory from the specified simple heap. + * + * @returns Pointer to the allocated memory block on success. + * @returns NULL if the request cannot be satisfied. (A VERR_NO_MEMORY condition.) + * + * @param Heap The heap to allocate the memory on. + * @param cb The requested heap block size. + * @param cbAlignment The requested heap block alignment. Pass 0 for default alignment. + * Must be a power of 2. + */ +RTDECL(void *) RTHeapSimpleAllocZ(RTHEAPSIMPLE Heap, size_t cb, size_t cbAlignment); + +/** + * Reallocates / Allocates / Frees a heap block. + * + * @param Heap The heap. This is optional and will only be used for strict assertions. + * @param pv The heap block returned by RTHeapSimple. If NULL it behaves like RTHeapSimpleAlloc(). + * @param cbNew The new size of the heap block. If NULL it behaves like RTHeapSimpleFree(). + * @param cbAlignment The requested heap block alignment. Pass 0 for default alignment. + * Must be a power of 2. + * @remark This API isn't implemented yet. + */ +RTDECL(void *) RTHeapSimpleRealloc(RTHEAPSIMPLE Heap, void *pv, size_t cbNew, size_t cbAlignment); + +/** + * Reallocates / Allocates / Frees a heap block, zeroing any new bits. + * + * @param Heap The heap. This is optional and will only be used for strict assertions. + * @param pv The heap block returned by RTHeapSimple. If NULL it behaves like RTHeapSimpleAllocZ(). + * @param cbNew The new size of the heap block. If NULL it behaves like RTHeapSimpleFree(). + * @param cbAlignment The requested heap block alignment. Pass 0 for default alignment. + * Must be a power of 2. + * @remark This API isn't implemented yet. + */ +RTDECL(void *) RTHeapSimpleReallocZ(RTHEAPSIMPLE Heap, void *pv, size_t cbNew, size_t cbAlignment); + +/** + * Frees memory allocated from a simple heap. + * + * @param Heap The heap. This is optional and will only be used for strict assertions. + * @param pv The heap block returned by RTHeapSimple + */ +RTDECL(void) RTHeapSimpleFree(RTHEAPSIMPLE Heap, void *pv); + +/** + * Gets the size of the specified heap block. + * + * @returns The actual size of the heap block. + * @returns 0 if \a pv is NULL or it doesn't point to a valid heap block. An invalid \a pv + * can also cause traps or trigger assertions. + * @param Heap The heap. This is optional and will only be used for strict assertions. + * @param pv The heap block returned by RTHeapSimple + */ +RTDECL(size_t) RTHeapSimpleSize(RTHEAPSIMPLE Heap, void *pv); + +/** + * Gets the size of the heap. + * + * This size includes all the internal heap structures. So, even if the heap is + * empty the RTHeapSimpleGetFreeSize() will never reach the heap size returned + * by this function. + * + * @returns The heap size. + * @returns 0 if heap was safely detected as being bad. + * @param Heap The heap. + */ +RTDECL(size_t) RTHeapSimpleGetHeapSize(RTHEAPSIMPLE Heap); + +/** + * Returns the sum of all free heap blocks. + * + * This is the amount of memory you can theoretically allocate + * if you do allocations exactly matching the free blocks. + * + * @returns The size of the free blocks. + * @returns 0 if heap was safely detected as being bad. + * @param Heap The heap. + */ +RTDECL(size_t) RTHeapSimpleGetFreeSize(RTHEAPSIMPLE Heap); + +/** + * Printf like callbaclk function for RTHeapSimpleDump. + * @param pszFormat IPRT format string. + * @param ... Format arguments. + */ +typedef DECLCALLBACKTYPE(void, FNRTHEAPSIMPLEPRINTF,(const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(1, 2); +/** Pointer to a FNRTHEAPSIMPLEPRINTF function. */ +typedef FNRTHEAPSIMPLEPRINTF *PFNRTHEAPSIMPLEPRINTF; + +/** + * Dumps the hypervisor heap. + * + * @param Heap The heap handle. + * @param pfnPrintf Printf like function that groks IPRT formatting. + */ +RTDECL(void) RTHeapSimpleDump(RTHEAPSIMPLE Heap, PFNRTHEAPSIMPLEPRINTF pfnPrintf); + +/** @} */ + + + +/** @defgroup grp_rt_heap_offset RTHeapOffset - Offset Based Heap + * + * This is a variation on the simple heap that doesn't use pointers internally + * and therefore can be saved and restored without any extra effort. + * + * @{ + */ + +/** + * Initializes the heap. + * + * @returns IPRT status code. + * @param phHeap Where to store the heap anchor block on success. + * @param pvMemory Pointer to the heap memory. + * @param cbMemory The size of the heap memory. + */ +RTDECL(int) RTHeapOffsetInit(PRTHEAPOFFSET phHeap, void *pvMemory, size_t cbMemory); + +/** + * Merge two simple heaps into one. + * + * The requirement is of course that they next two each other memory wise. + * + * @returns IPRT status code. + * @param phHeap Where to store the handle to the merged heap on success. + * @param hHeap1 Handle to the first heap. + * @param hHeap2 Handle to the second heap. + * @remark This API isn't implemented yet. + */ +RTDECL(int) RTHeapOffsetMerge(PRTHEAPOFFSET phHeap, RTHEAPOFFSET hHeap1, RTHEAPOFFSET hHeap2); + +/** + * Allocates memory from the specified simple heap. + * + * @returns Pointer to the allocated memory block on success. + * @returns NULL if the request cannot be satisfied. (A VERR_NO_MEMORY condition.) + * + * @param hHeap The heap to allocate the memory on. + * @param cb The requested heap block size. + * @param cbAlignment The requested heap block alignment. Pass 0 for default alignment. + * Must be a power of 2. + */ +RTDECL(void *) RTHeapOffsetAlloc(RTHEAPOFFSET hHeap, size_t cb, size_t cbAlignment); + +/** + * Allocates zeroed memory from the specified simple heap. + * + * @returns Pointer to the allocated memory block on success. + * @returns NULL if the request cannot be satisfied. (A VERR_NO_MEMORY condition.) + * + * @param hHeap The heap to allocate the memory on. + * @param cb The requested heap block size. + * @param cbAlignment The requested heap block alignment. Pass 0 for default + * alignment. Must be a power of 2. + */ +RTDECL(void *) RTHeapOffsetAllocZ(RTHEAPOFFSET hHeap, size_t cb, size_t cbAlignment); + +/** + * Reallocates / Allocates / Frees a heap block. + * + * @param hHeap The heap handle. This is optional and will only be used + * for strict assertions. + * @param pv The heap block returned by RTHeapOffset. If NULL it + * behaves like RTHeapOffsetAlloc(). + * @param cbNew The new size of the heap block. If NULL it behaves like + * RTHeapOffsetFree(). + * @param cbAlignment The requested heap block alignment. Pass 0 for default + * alignment. Must be a power of 2. + * @remark This API isn't implemented yet. + */ +RTDECL(void *) RTHeapOffsetRealloc(RTHEAPOFFSET hHeap, void *pv, size_t cbNew, size_t cbAlignment); + +/** + * Reallocates / Allocates / Frees a heap block, zeroing any new bits. + * + * @param hHeap The heap handle. This is optional and will only be used + * for strict assertions. + * @param pv The heap block returned by RTHeapOffset. If NULL it + * behaves like RTHeapOffsetAllocZ(). + * @param cbNew The new size of the heap block. If NULL it behaves like + * RTHeapOffsetFree(). + * @param cbAlignment The requested heap block alignment. Pass 0 for default + * alignment. Must be a power of 2. + * @remark This API isn't implemented yet. + */ +RTDECL(void *) RTHeapOffsetReallocZ(RTHEAPOFFSET hHeap, void *pv, size_t cbNew, size_t cbAlignment); + +/** + * Frees memory allocated from a simple heap. + * + * @param hHeap The heap handle. This is optional and will only be used + * for strict assertions. + * @param pv The heap block returned by RTHeapOffset + */ +RTDECL(void) RTHeapOffsetFree(RTHEAPOFFSET hHeap, void *pv); + +/** + * Gets the size of the specified heap block. + * + * @returns The actual size of the heap block. + * @returns 0 if \a pv is NULL or it doesn't point to a valid heap block. An + * invalid \a pv can also cause traps or trigger assertions. + * + * @param hHeap The heap handle. This is optional and will only be used + * for strict assertions. + * @param pv The heap block returned by RTHeapOffset + */ +RTDECL(size_t) RTHeapOffsetSize(RTHEAPOFFSET hHeap, void *pv); + +/** + * Gets the size of the heap. + * + * This size includes all the internal heap structures. So, even if the heap is + * empty the RTHeapOffsetGetFreeSize() will never reach the heap size returned + * by this function. + * + * @returns The heap size. + * @returns 0 if heap was safely detected as being bad. + * @param hHeap The heap handle. + */ +RTDECL(size_t) RTHeapOffsetGetHeapSize(RTHEAPOFFSET hHeap); + +/** + * Returns the sum of all free heap blocks. + * + * This is the amount of memory you can theoretically allocate + * if you do allocations exactly matching the free blocks. + * + * @returns The size of the free blocks. + * @returns 0 if heap was safely detected as being bad. + * @param hHeap The heap handle. + */ +RTDECL(size_t) RTHeapOffsetGetFreeSize(RTHEAPOFFSET hHeap); + +/** + * Printf like callbaclk function for RTHeapOffsetDump. + * @param pszFormat IPRT format string. + * @param ... Format arguments. + */ +typedef DECLCALLBACKTYPE(void, FNRTHEAPOFFSETPRINTF,(const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(1, 2); +/** Pointer to a FNRTHEAPOFFSETPRINTF function. */ +typedef FNRTHEAPOFFSETPRINTF *PFNRTHEAPOFFSETPRINTF; + +/** + * Dumps the hypervisor heap. + * + * @param hHeap The heap handle. + * @param pfnPrintf Printf like function that groks IPRT formatting. + */ +RTDECL(void) RTHeapOffsetDump(RTHEAPOFFSET hHeap, PFNRTHEAPOFFSETPRINTF pfnPrintf); + +/** @} */ + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_heap_h */ + diff --git a/include/iprt/http-common.h b/include/iprt/http-common.h new file mode 100644 index 00000000..d9cc746f --- /dev/null +++ b/include/iprt/http-common.h @@ -0,0 +1,286 @@ +/* $Id: http-common.h $ */ +/** @file + * IPRT - Common (client / server) HTTP API. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_http_common_h +#define IPRT_INCLUDED_http_common_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/list.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** HTTP methods. */ +typedef enum RTHTTPMETHOD +{ + RTHTTPMETHOD_INVALID = 0, + RTHTTPMETHOD_GET, + RTHTTPMETHOD_PUT, + RTHTTPMETHOD_POST, + RTHTTPMETHOD_PATCH, + RTHTTPMETHOD_DELETE, + RTHTTPMETHOD_HEAD, + RTHTTPMETHOD_OPTIONS, + RTHTTPMETHOD_TRACE, +#ifdef IPRT_HTTP_WITH_WEBDAV + RTHTTPMETHOD_PROPFIND, +#endif + RTHTTPMETHOD_END, + RTHTTPMETHOD_32BIT_HACK = 0x7fffffff +} RTHTTPMETHOD; + +/** HTTP status codes. */ +typedef enum RTHTTPSTATUS +{ + RTHTTPSTATUS_INTERNAL_NOT_SET = 0, + /** + * 2xx - Success / information codes. + */ + RTHTTPSTATUS_OK = 200, + RTHTTPSTATUS_CREATED = 201, + RTHTTPSTATUS_ACCEPTED = 202, + RTHTTPSTATUS_NONAUTHORITATIVEINFORMATION = 203, + RTHTTPSTATUS_NOCONTENT = 204, + RTHTTPSTATUS_RESETCONTENT = 205, + RTHTTPSTATUS_PARTIALCONTENT = 206, + RTHTTPSTATUS_MULTISTATUS = 207, + RTHTTPSTATUS_ALREADYREPORTED = 208, + RTHTTPSTATUS_IMUSED = 226, + /** + * 4xx - Client error codes. + */ + RTHTTPSTATUS_BADREQUEST = 400, + RTHTTPSTATUS_UNAUTHORIZED = 401, + RTHTTPSTATUS_PAYMENTREQUIRED = 402, + RTHTTPSTATUS_FORBIDDEN = 403, + RTHTTPSTATUS_NOTFOUND = 404, + RTHTTPSTATUS_METHODNOTALLOWED = 405, + RTHTTPSTATUS_NOTACCEPTABLE = 406, + RTHTTPSTATUS_PROXYAUTHENTICATIONREQUIRED = 407, + RTHTTPSTATUS_REQUESTTIMEOUT = 408, + RTHTTPSTATUS_CONFLICT = 409, + RTHTTPSTATUS_GONE = 410, + RTHTTPSTATUS_LENGTHREQUIRED = 411, + RTHTTPSTATUS_PRECONDITIONFAILED = 412, + RTHTTPSTATUS_PAYLOADTOOLARGE = 413, + RTHTTPSTATUS_URITOOLONG = 414, + RTHTTPSTATUS_UNSUPPORTEDMEDIATYPE = 415, + RTHTTPSTATUS_RANGENOTSATISFIABLE = 416, + RTHTTPSTATUS_EXPECTATIONFAILED = 417, + RTHTTPSTATUS_IMATEAPOT = 418, + RTHTTPSTATUS_UNPROCESSABLEENTITY = 422, + RTHTTPSTATUS_LOCKED = 423, + RTHTTPSTATUS_FAILEDDEPENDENCY = 424, + RTHTTPSTATUS_UPGRADEREQUIRED = 426, + RTHTTPSTATUS_PRECONDITIONREQUIRED = 428, + RTHTTPSTATUS_TOOMANYREQUESTS = 429, + RTHTTPSTATUS_REQUESTHEADERFIELDSTOOLARGE = 431, + RTHTTPSTATUS_UNAVAILABLEFORLEGALREASONS = 451, + /** + * 5xx - Server error codes. + */ + RTHTTPSTATUS_INTERNALSERVERERROR = 500, + RTHTTPSTATUS_NOTIMPLEMENTED = 501, + RTHTTPSTATUS_BADGATEWAY = 502, + RTHTTPSTATUS_SERVICEUNAVAILABLE = 503, + RTHTTPSTATUS_GATEWAYTIMEOUT = 504, + RTHTTPSTATUS_HTTPVERSIONNOTSUPPORTED = 505, + RTHTTPSTATUS_VARIANTALSONEGOTIATES = 506, + RTHTTPSTATUS_INSUFFICIENTSTORAGE = 507, + RTHTTPSTATUS_LOOPDETECTED = 508, + RTHTTPSTATUS_NOTEXTENDED = 510, + RTHTTPSTATUS_NETWORKAUTHENTICATIONREQUIRED = 511, + + RTHTTPSTATUS_32BIT_HACK = 0x7fffffff +} RTHTTPSTATUS; + +/** Checks whether a HTTP status is of type "informational" or not. */ +#define RTHTTPSTATUS_IS_INFO(a_Code) (a_Code >= 100 && a_Code < 200) +/** Checks whether a HTTP status indicates success or not. */ +#define RTHTTPSTATUS_IS_OK(a_Code) (a_Code >= 200 && a_Code < 300) +/** Checks whether a HTTP status indicates a redirection or not. */ +#define RTHTTPSTATUS_IS_REDIRECT(a_Code) (a_Code >= 300 && a_Code < 400) +/** Checks whether a HTTP status indicates a client error or not. */ +#define RTHTTPSTATUS_IS_CLIENTERROR(a_Code) (a_Code >= 400 && a_Code < 500) +/** Checks whether a HTTP status indicates a server error or not. */ +#define RTHTTPSTATUS_IS_SERVERERROR(a_Code) (a_Code >= 500 && a_Code < 600) +/** Checks whether a HTTP status indicates an error or not. */ +#define RTHTTPSTATUS_IS_ERROR(a_Code) (a_Code >= 400) + +/** Specifies a HTTP MIME type. */ +typedef uint32_t RTHTTPMIMETYPE; + +#define RTHTTPMIMETYPE_TEXT_PLAIN "text/plain" +#define RTHTTPMIMETYPE_APPLICATION_OCTET_STREAM "application/octet-stream" + +/** Specifies HTTP version 1.1 as a string. */ +#define RTHTTPVER_1_1_STR "HTTP/1.1" + +/** @todo the following three definitions may move the iprt/types.h later. */ +/** HTTP header list handle. */ +typedef R3PTRTYPE(struct RTHTTPHEADERLISTINTERNAL *) RTHTTPHEADERLIST; +/** Pointer to a HTTP header list handle. */ +typedef RTHTTPHEADERLIST *PRTHTTPHEADERLIST; +/** Nil HTTP HTTP header list handle. */ +#define NIL_RTHTTPHEADERLIST ((RTHTTPHEADERLIST)0) + +/** + * HTTP header list entry. + */ +typedef struct RTHTTPHEADERENTRY +{ + /** The list node. */ + RTLISTNODE Node; + /** The field name length. */ + uint32_t cchName; + /** The value offset. */ + uint32_t offValue; + /** The full header field. */ + RT_FLEXIBLE_ARRAY_EXTENSION + RT_GCC_EXTENSION char szData[RT_FLEXIBLE_ARRAY]; +} RTHTTPHEADERENTRY; +/** Pointer to a HTTP header. */ +typedef RTHTTPHEADERENTRY *PRTHTTPHEADERENTRY; + +/** + * Structure for maintaining a HTTP body. + */ +typedef struct RTHTTPBODY +{ + /** Body to send, if any. Can be NULL. */ + void *pvBody; + /** Body allocation size (in bytes). */ + size_t cbBodyAlloc; + /** How much body data is being used (in bytes). */ + size_t cbBodyUsed; + /** Current body data read/write offset (in bytes). */ + size_t offBody; +} RTHTTPBODY; +/** Pointer to a HTTP body. */ +typedef RTHTTPBODY *PRTHTTPBODY; + +/** + * Returns the name of the HTTP method. + * @returns Read only string. + * @param enmMethod The HTTP method to name. + */ +RTR3DECL(const char *) RTHttpMethodToStr(RTHTTPMETHOD enmMethod); + +RTR3DECL(const char *) RTHttpStatusToStr(RTHTTPSTATUS enmSts); + +RTR3DECL(int) RTHttpHeaderListInit(PRTHTTPHEADERLIST hHdrList); + +RTR3DECL(void) RTHttpHeaderListDestroy(RTHTTPHEADERLIST hHdrList); + +/** + * Set custom raw headers. + * + * @returns IPRT status code. + * @param hHdrLst The HTTP header list handle. + * @param cHeaders Number of custom headers. + * @param papszHeaders Array of headers in form "foo: bar". + */ +RTR3DECL(int) RTHttpHeaderListSet(RTHTTPHEADERLIST hHdrLst, size_t cHeaders, const char * const *papszHeaders); + +/** @name RTHTTPHEADERLISTADD_F_XXX - Flags for RTHttpHeaderListAddRaw and RTHttpHeaderListAdd + * @{ */ +#define RTHTTPHEADERLISTADD_F_BACK UINT32_C(0) /**< Append the header. */ +#define RTHTTPHEADERLISTADD_F_FRONT UINT32_C(1) /**< Prepend the header. */ +/** @} */ + +/** + * Adds a raw header. + * + * @returns IPRT status code. + * @param hHdrLst The HTTP header list handle. + * @param pszHeader Header string on the form "foo: bar". + * @param fFlags RTHTTPADDHDR_F_FRONT or RTHTTPADDHDR_F_BACK. + */ +RTR3DECL(int) RTHttpHeaderListAddRaw(RTHTTPHEADERLIST hHdrLst, const char *pszHeader, uint32_t fFlags); + +/** + * Adds a header field and value. + * + * @returns IPRT status code. + * @param hHdrLst The HTTP header list handle. + * @param pszField The header field name. + * @param pszValue The header field value. + * @param cchValue The value length or RTSTR_MAX. + * @param fFlags Only RTHTTPADDHDR_F_FRONT or RTHTTPADDHDR_F_BACK, + * may be extended with encoding controlling flags if + * needed later. + */ +RTR3DECL(int) RTHttpHeaderListAdd(RTHTTPHEADERLIST hHdrLst, const char *pszField, const char *pszValue, size_t cchValue, uint32_t fFlags); + +/** + * Gets a header previously added using RTHttpSetHeaders, RTHttpAppendRawHeader + * or RTHttpAppendHeader. + * + * @returns Pointer to the header value on if found, otherwise NULL. + * @param hHdrLst The HTTP header list handle. + * @param pszField The field name (no colon). + * @param cchField The length of the field name or RTSTR_MAX. + */ +RTR3DECL(const char *) RTHttpHeaderListGet(RTHTTPHEADERLIST hHdrLst, const char *pszField, size_t cchField); + +/** + * Gets the number of headers specified by RTHttpAddHeader, RTHttpAddRawHeader or RTHttpSetHeaders. + * + * @returns Number of headers. + * @param hHdrLst The HTTP header list handle. + * @note This can be slow and is only really intended for test cases and debugging! + */ +RTR3DECL(size_t) RTHttpHeaderListGetCount(RTHTTPHEADERLIST hHdrLst); + +/** + * Gets a header by ordinal. + * + * Can be used together with RTHttpGetHeaderCount by test case and debug code to + * iterate headers specified by RTHttpAddHeader, RTHttpAddRawHeader or RTHttpSetHeaders. + * + * @returns The header string ("field: value"). + * @param hHdrLst The HTTP header list handle. + * @param iOrdinal The number of the header to get. + * @note This can be slow and is only really intended for test cases and debugging! + */ +RTR3DECL(const char *) RTHttpHeaderListGetByOrdinal(RTHTTPHEADERLIST hHdrLst, size_t iOrdinal); + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_http_common_h */ + diff --git a/include/iprt/http-server.h b/include/iprt/http-server.h new file mode 100644 index 00000000..eab06a37 --- /dev/null +++ b/include/iprt/http-server.h @@ -0,0 +1,244 @@ +/* $Id: http-server.h $ */ +/** @file + * Header file for HTTP server implementation. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_http_server_h +#define IPRT_INCLUDED_http_server_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/http-common.h> +#include <iprt/types.h> +#include <iprt/fs.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_httpserver RTHttpServer - HTTP server implementation. + * @ingroup grp_rt + * @{ + */ + +/** @todo the following three definitions may move the iprt/types.h later. */ +/** HTTP server handle. */ +typedef R3PTRTYPE(struct RTHTTPSERVERINTERNAL *) RTHTTPSERVER; +/** Pointer to a HTTP server handle. */ +typedef RTHTTPSERVER *PRTHTTPSERVER; +/** Nil HTTP client handle. */ +#define NIL_RTHTTPSERVER ((RTHTTPSERVER)0) + +/** + * Structure for maintaining a HTTP client request. + */ +typedef struct RTHTTPSERVERREQ +{ + /** Request URL. */ + char *pszUrl; + /** Request method. */ + RTHTTPMETHOD enmMethod; + /** Request header list. */ + RTHTTPHEADERLIST hHdrLst; + /** Request body data. */ + RTHTTPBODY Body; +} RTHTTPSERVERREQ; +/** Pointer to a HTTP client request. */ +typedef RTHTTPSERVERREQ *PRTHTTPSERVERREQ; + +/** + * Structure for maintaining a HTTP server response. + */ +typedef struct RTHTTPSERVERRESP +{ + /** HTTP status to send. */ + RTHTTPSTATUS enmSts; + /** List of headers to send. */ + RTHTTPHEADERLIST hHdrLst; + /** Body data to send. */ + RTHTTPBODY Body; +} RTHTTPSERVERRESP; +/** Pointer to a HTTP server response. */ +typedef RTHTTPSERVERRESP *PRTHTTPSERVERRESP; + +RTR3DECL(int) RTHttpServerResponseInitEx(PRTHTTPSERVERRESP pResp, size_t cbBody); +RTR3DECL(int) RTHttpServerResponseInit(PRTHTTPSERVERRESP pResp); +RTR3DECL(void) RTHttpServerResponseDestroy(PRTHTTPSERVERRESP pResp); + +/** + * Structure for maintaining a HTTP server client state. + * + * Note: The HTTP protocol itself is stateless, but we want to have to possibility to store + * some state stuff here nevertheless. + */ +typedef struct RTHTTPSERVERCLIENTSTATE +{ + /** If non-zero, the time (in ms) to keep a client connection alive. + * Requested via client header, but set and controlled by the server in the end. */ + RTMSINTERVAL msKeepAlive; +} RTHTTPSERVERCLIENTSTATE; +/** Pointer to a FTP server client state. */ +typedef RTHTTPSERVERCLIENTSTATE *PRTHTTPSERVERCLIENTSTATE; + +/** + * Structure for storing HTTP server callback data. + */ +typedef struct RTHTTPCALLBACKDATA +{ + /** Pointer to the client state. */ + PRTHTTPSERVERCLIENTSTATE pClient; + /** Saved user pointer. */ + void *pvUser; + /** Size (in bytes) of data at user pointer. */ + size_t cbUser; +} RTHTTPCALLBACKDATA; +/** Pointer to HTTP server callback data. */ +typedef RTHTTPCALLBACKDATA *PRTHTTPCALLBACKDATA; + +/** + * Function callback table for the HTTP server implementation. + * + * All callbacks are optional and therefore can be NULL. + */ +typedef struct RTHTTPSERVERCALLBACKS +{ + /** + * Called before a given URL will be retrieved by the GET method. + * + * Note: High level function, not being called when pfnOnGetRequest is implemented. + * + * @returns VBox status code. + * @param pData Pointer to HTTP callback data. + * @param pReq Pointer to request to handle. + * @param ppvHandle Where to return the pointer to the opaque handle used for object identification. + */ + DECLCALLBACKMEMBER(int, pfnOpen,(PRTHTTPCALLBACKDATA pData, PRTHTTPSERVERREQ pReq, void **ppvHandle)); + /** + * Called when a given URL will be retrieved by the GET method. + * + * Note: High level function, not being called when pfnOnGetRequest is implemented. + * Note2: Can be called multiple times, based on the body size to send. + * + * @returns VBox status code. + * @param pData Pointer to HTTP callback data. + * @param pvHandle Opaque handle for object identification. + * @param pvBuf Pointer to buffer where to store the read data. + * @param cbBuf Size (in bytes) of the buffer where to store the read data. + * @param pcbRead Where to return the amount (in bytes) of read data. Optional and can be NULL. + */ + DECLCALLBACKMEMBER(int, pfnRead,(PRTHTTPCALLBACKDATA pData, void *pvHandle, void *pvBuf, size_t cbBuf, size_t *pcbRead)); + /** + * Called when a given URL is done retrieving by the GET method. + * + * Note: High level function, not being called when pfnOnGetRequest is implemented. + * + * @returns VBox status code. + * @param pData Pointer to HTTP callback data. + * @param pszUrl URL to handle. + * @param pvHandle Opaque handle for object identification. + */ + DECLCALLBACKMEMBER(int, pfnClose,(PRTHTTPCALLBACKDATA pData, void *pvHandle)); + /** + * Queries information about a given URL. + * + * Will be called with GET or HEAD request. + * + * @returns VBox status code. + * @param pData Pointer to HTTP callback data. + * @param pReq Pointer to request to handle. + * @param pObjInfo Where to store the queried file information on success. + * @param ppszMIMEHint Where to return an allocated MIME type hint on success. + * Must be free'd by the caller using RTStrFree(). + */ + DECLCALLBACKMEMBER(int, pfnQueryInfo,(PRTHTTPCALLBACKDATA pData, PRTHTTPSERVERREQ pReq, PRTFSOBJINFO pObjInfo, char **ppszMIMEHint)); + /** + * Low-level handler for a GET method request. + * + * @returns VBox status code. + * @param pData Pointer to HTTP callback data. + * @param pReq Pointer to request to handle. + */ + DECLCALLBACKMEMBER(int, pfnOnGetRequest,(PRTHTTPCALLBACKDATA pData, PRTHTTPSERVERREQ pReq)); + /** + * Low-level handler for a HEAD method request. + * + * @returns VBox status code. + * @param pData Pointer to HTTP callback data. + * @param pReq Pointer to request to handle. + */ + DECLCALLBACKMEMBER(int, pfnOnHeadRequest,(PRTHTTPCALLBACKDATA pData, PRTHTTPSERVERREQ pReq)); + /** + * Called before the HTTP server will be destroyed. + * + * @returns VBox status code. + * @param pData Pointer to HTTP callback data. + */ + DECLCALLBACKMEMBER(int, pfnDestroy,(PRTHTTPCALLBACKDATA pData)); +} RTHTTPSERVERCALLBACKS; +/** Pointer to a HTTP server callback data table. */ +typedef RTHTTPSERVERCALLBACKS *PRTHTTPSERVERCALLBACKS; + +/** Maximum length (in bytes) a single client request can have. */ +#define RTHTTPSERVER_MAX_REQ_LEN _8K +/** EOL string according to the HTTP 1.1 specs. + * See https://tools.ietf.org/html/rfc2616#section-2.2 */ +#define RTHTTPSERVER_HTTP11_EOL_STR "\r\n" + +/** + * Creates a HTTP server instance. + * + * @returns IPRT status code. + * @param phHttpServer Where to store the HTTP server handle. + * @param pcszAddress The address for creating a listening socket. + * If NULL or empty string the server is bound to all interfaces. + * @param uPort The port for creating a listening socket. + * @param pCallbacks Callback table to use. + * @param pvUser Pointer to user-specific data. Optional. + * @param cbUser Size of user-specific data. Optional. + */ +RTR3DECL(int) RTHttpServerCreate(PRTHTTPSERVER phHttpServer, const char *pcszAddress, uint16_t uPort, + PRTHTTPSERVERCALLBACKS pCallbacks, void *pvUser, size_t cbUser); + +/** + * Destroys a HTTP server instance. + * + * @returns IPRT status code. + * @param hHttpServer Handle to the HTTP server handle. + */ +RTR3DECL(int) RTHttpServerDestroy(RTHTTPSERVER hHttpServer); + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_http_server_h */ + diff --git a/include/iprt/http.h b/include/iprt/http.h new file mode 100644 index 00000000..5ab966fd --- /dev/null +++ b/include/iprt/http.h @@ -0,0 +1,746 @@ +/* $Id: http.h $ */ +/** @file + * IPRT - Simple HTTP/HTTPS Client API. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_http_h +#define IPRT_INCLUDED_http_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/http-common.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_http RTHttp - Simple HTTP/HTTPS Client API + * @ingroup grp_rt + * @{ + */ + +/** @todo the following three definitions may move the iprt/types.h later. */ +/** HTTP/HTTPS client handle. */ +typedef R3PTRTYPE(struct RTHTTPINTERNAL *) RTHTTP; +/** Pointer to a HTTP/HTTPS client handle. */ +typedef RTHTTP *PRTHTTP; +/** Nil HTTP/HTTPS client handle. */ +#define NIL_RTHTTP ((RTHTTP)0) + + +/** + * Creates a HTTP client instance. + * + * @returns IPRT status code. + * @param phHttp Where to store the HTTP handle. + */ +RTR3DECL(int) RTHttpCreate(PRTHTTP phHttp); + +/** + * Resets a HTTP client instance. + * + * @returns IPRT status code. + * @param hHttp Handle to the HTTP interface. + * @param fFlags Flags, RTHTTP_RESET_F_XXX. + */ +RTR3DECL(int) RTHttpReset(RTHTTP hHttp, uint32_t fFlags); + +/** @name RTHTTP_RESET_F_XXX - Flags for RTHttpReset. + * @{ */ +/** Keep the headers. */ +#define RTHTTP_RESET_F_KEEP_HEADERS RT_BIT_32(0) +/** Mask containing the valid flags. */ +#define RTHTTP_RESET_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + + +/** + * Destroys a HTTP client instance. + * + * @returns IPRT status code. + * @param hHttp Handle to the HTTP interface. + */ +RTR3DECL(int) RTHttpDestroy(RTHTTP hHttp); + + +/** + * Retrieve the redir location for 301 responses. + * + * @param hHttp Handle to the HTTP interface. + * @param ppszRedirLocation Where to store the string. To be freed with + * RTStrFree(). + */ +RTR3DECL(int) RTHttpGetRedirLocation(RTHTTP hHttp, char **ppszRedirLocation); + +/** + * Perform a simple blocking HTTP GET request. + * + * This is a just a convenient wrapper around RTHttpGetBinary that returns a + * different type and sheds a parameter. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param pszUrl URL. + * @param ppszNotUtf8 Where to return the pointer to the HTTP response. + * The string is of course zero terminated. Use + * RTHttpFreeReponseText to free. + * + * @remarks BIG FAT WARNING! + * + * This function does not guarantee the that returned string is valid UTF-8 or + * any other kind of text encoding! + * + * The caller must determine and validate the string encoding _before_ + * passing it along to functions that expect UTF-8! + * + * Also, this function does not guarantee that the returned string + * doesn't have embedded zeros and provides the caller no way of + * finding out! If you are worried about the response from the HTTPD + * containing embedded zero's, use RTHttpGetBinary instead. + */ +RTR3DECL(int) RTHttpGetText(RTHTTP hHttp, const char *pszUrl, char **ppszNotUtf8); + +/** + * Perform a simple blocking HTTP HEAD request. + * + * This is a just a convenient wrapper around RTHttpGetBinary that returns a + * different type and sheds a parameter. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param pszUrl URL. + * @param ppszNotUtf8 Where to return the pointer to the HTTP response. + * The string is of course zero terminated. Use + * RTHttpFreeReponseText to free. + * + * @remarks BIG FAT WARNING! + * + * This function does not guarantee the that returned string is valid UTF-8 or + * any other kind of text encoding! + * + * The caller must determine and validate the string encoding _before_ + * passing it along to functions that expect UTF-8! + * + * Also, this function does not guarantee that the returned string + * doesn't have embedded zeros and provides the caller no way of + * finding out! If you are worried about the response from the HTTPD + * containing embedded zero's, use RTHttpGetHeaderBinary instead. + */ +RTR3DECL(int) RTHttpGetHeaderText(RTHTTP hHttp, const char *pszUrl, char **ppszNotUtf8); + +/** + * Frees memory returned by RTHttpGetText. + * + * @param pszNotUtf8 What RTHttpGetText returned. + */ +RTR3DECL(void) RTHttpFreeResponseText(char *pszNotUtf8); + +/** + * Perform a simple blocking HTTP GET request. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param pszUrl The URL. + * @param ppvResponse Where to store the HTTP response data. Use + * RTHttpFreeResponse to free. + * @param pcb Size of the returned buffer. + * + * @note There is a limit on how much this function allows to be downloaded, + * given that the return requires a single heap allocation and all + * that. Currently 32 MB on 32-bit hosts and 64 MB on 64-bit hosts. + * Use RTHttpGetFile or RTHttpSetDownloadCallback for larger transfers. + */ +RTR3DECL(int) RTHttpGetBinary(RTHTTP hHttp, const char *pszUrl, void **ppvResponse, size_t *pcb); + +/** + * Perform a simple blocking HTTP HEAD request. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param pszUrl The URL. + * @param ppvResponse Where to store the HTTP response data. Use + * RTHttpFreeResponse to free. + * @param pcb Size of the returned buffer. + */ +RTR3DECL(int) RTHttpGetHeaderBinary(RTHTTP hHttp, const char *pszUrl, void **ppvResponse, size_t *pcb); + +/** + * Frees memory returned by RTHttpGetBinary. + * + * @param pvResponse What RTHttpGetBinary returned. + */ +RTR3DECL(void) RTHttpFreeResponse(void *pvResponse); + +/** + * Perform a simple blocking HTTP request, writing the output to a file. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param pszUrl The URL. + * @param pszDstFile The destination file name. + */ +RTR3DECL(int) RTHttpGetFile(RTHTTP hHttp, const char *pszUrl, const char *pszDstFile); + +/** + * Performs generic blocking HTTP request, optionally returning the body and headers. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pszUrl The URL. + * @param enmMethod The HTTP method for the request. + * @param pvReqBody Pointer to the request body. NULL if none. + * @param cbReqBody Size of the request body. Zero if none. + * @param puHttpStatus Where to return the HTTP status code. Optional. + * @param ppvHeaders Where to return the headers. Optional. + * @param pcbHeaders Where to return the header size. + * @param ppvBody Where to return the body. Optional. + * @param pcbBody Where to return the body size. + */ +RTR3DECL(int) RTHttpPerform(RTHTTP hHttp, const char *pszUrl, RTHTTPMETHOD enmMethod, void const *pvReqBody, size_t cbReqBody, + uint32_t *puHttpStatus, void **ppvHeaders, size_t *pcbHeaders, void **ppvBody, size_t *pcbBody); + + +/** + * Abort a pending HTTP request. A blocking RTHttpGet() call will return with + * VERR_HTTP_ABORTED. It may take some time (current cURL implementation needs + * up to 1 second) before the request is aborted. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + */ +RTR3DECL(int) RTHttpAbort(RTHTTP hHttp); + +/** + * Tells the HTTP interface to use the system proxy configuration. + * + * @returns iprt status code. + * @param hHttp The HTTP client handle. + */ +RTR3DECL(int) RTHttpUseSystemProxySettings(RTHTTP hHttp); + +/** + * Sets up the proxy according to the specified URL. + * + * @returns IPRT status code. + * @retval VWRN_WRONG_TYPE if the type isn't known/supported and we defaulted to 'http'. + * + * @param hHttp The HTTP client handle. + * @param pszUrl The proxy URL (libproxy style): + * + * [{type}"://"][{userid}[\@{password}]:]{server}[":"{port}] + * + * Valid proxy types are: http (default), https, socks4, socks4a, + * socks5, socks5h and direct. Support for the socks and https + * ones depends on the HTTP library we use. + * + * The port number defaults to 80 for http, 443 for https and 1080 + * for the socks ones. + * + * If this starts with "direct://", then no proxy will be used. + * An empty or NULL string is equivalent to calling + * RTHttpUseSystemProxySettings(). + */ +RTR3DECL(int) RTHttpSetProxyByUrl(RTHTTP hHttp, const char *pszUrl); + +/** + * Specify proxy settings. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param pszProxyUrl URL of the proxy server. + * @param uPort port number of the proxy, use 0 for not specifying a port. + * @param pszProxyUser Username, pass NULL for no authentication. + * @param pszProxyPwd Password, pass NULL for no authentication. + * + * @todo This API does not allow specifying the type of proxy server... We're + * currently assuming it's a HTTP proxy. + * + * @deprecated Use RTHttpSetProxyByUrl. + */ +RTR3DECL(int) RTHttpSetProxy(RTHTTP hHttp, const char *pszProxyUrl, uint32_t uPort, + const char *pszProxyUser, const char *pszProxyPwd); + +/** + * Set follow redirects (3xx) + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param cMaxRedirects Max number of redirects to follow. Zero if no + * redirects should be followed but instead returned + * to caller. + */ +RTR3DECL(int) RTHttpSetFollowRedirects(RTHTTP hHttp, uint32_t cMaxRedirects); + +/** + * Gets the follow redirect setting. + * + * @returns cMaxRedirects value, 0 means not to follow. + * @param hHttp The HTTP client handle. + */ +RTR3DECL(uint32_t) RTHttpGetFollowRedirects(RTHTTP hHttp); + +/** + * Set custom raw headers. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param cHeaders Number of custom headers. + * @param papszHeaders Array of headers in form "foo: bar". + */ +RTR3DECL(int) RTHttpSetHeaders(RTHTTP hHttp, size_t cHeaders, const char * const *papszHeaders); + +/** @name RTHTTPADDHDR_F_XXX - Flags for RTHttpAddRawHeader and RTHttpAddHeader + * @{ */ +#define RTHTTPADDHDR_F_BACK UINT32_C(0) /**< Append the header. */ +#define RTHTTPADDHDR_F_FRONT UINT32_C(1) /**< Prepend the header. */ +/** @} */ + +/** + * Adds a raw header. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pszHeader Header string on the form "foo: bar". + * @param fFlags RTHTTPADDHDR_F_FRONT or RTHTTPADDHDR_F_BACK. + */ +RTR3DECL(int) RTHttpAddRawHeader(RTHTTP hHttp, const char *pszHeader, uint32_t fFlags); + +/** + * Adds a header field and value. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pszField The header field name. + * @param pszValue The header field value. + * @param cchValue The value length or RTSTR_MAX. + * @param fFlags Only RTHTTPADDHDR_F_FRONT or RTHTTPADDHDR_F_BACK, + * may be extended with encoding controlling flags if + * needed later. + */ +RTR3DECL(int) RTHttpAddHeader(RTHTTP hHttp, const char *pszField, const char *pszValue, size_t cchValue, uint32_t fFlags); + +/** + * Gets a header previously added using RTHttpSetHeaders, RTHttpAppendRawHeader + * or RTHttpAppendHeader. + * + * @returns Pointer to the header value on if found, otherwise NULL. + * @param hHttp The HTTP client handle. + * @param pszField The field name (no colon). + * @param cchField The length of the field name or RTSTR_MAX. + */ +RTR3DECL(const char *) RTHttpGetHeader(RTHTTP hHttp, const char *pszField, size_t cchField); + +/** + * Gets the number of headers specified by RTHttpAddHeader, RTHttpAddRawHeader or RTHttpSetHeaders. + * + * @returns Number of headers. + * @param hHttp The HTTP client handle. + * @note This can be slow and is only really intended for test cases and debugging! + */ +RTR3DECL(size_t) RTHttpGetHeaderCount(RTHTTP hHttp); + +/** + * Gets a header by ordinal. + * + * Can be used together with RTHttpGetHeaderCount by test case and debug code to + * iterate headers specified by RTHttpAddHeader, RTHttpAddRawHeader or RTHttpSetHeaders. + * + * @returns The header string ("field: value"). + * @param hHttp The HTTP client handle. + * @param iOrdinal The number of the header to get. + * @note This can be slow and is only really intended for test cases and debugging! + */ +RTR3DECL(const char *) RTHttpGetByOrdinal(RTHTTP hHttp, size_t iOrdinal); + +/** + * Sign all headers present according to pending "Signing HTTP Messages" RFC. + * + * Currently hardcoded RSA-SHA-256 algorithm choice. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param enmMethod The HTTP method that will be used for the request. + * @param pszUrl The target URL for the request. + * @param hKey The RSA key to use when signing. + * @param pszKeyId The key ID string corresponding to @a hKey. + * @param fFlags Reserved for future, MBZ. + * + * @note Caller is responsible for making all desired fields are present before + * making the call. + * + * @remarks Latest RFC draft at the time of writing: + * https://tools.ietf.org/html/draft-cavage-http-signatures-10 + */ +RTR3DECL(int) RTHttpSignHeaders(RTHTTP hHttp, RTHTTPMETHOD enmMethod, const char *pszUrl, + RTCRKEY hKey, const char *pszKeyId, uint32_t fFlags); + +/** + * Tells the HTTP client instance to gather system CA certificates into a + * temporary file and use it for HTTPS connections. + * + * This will be called automatically if a 'https' URL is presented and + * RTHttpSetCaFile hasn't been called yet. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pErrInfo Where to store additional error/warning information. + * Optional. + */ +RTR3DECL(int) RTHttpUseTemporaryCaFile(RTHTTP hHttp, PRTERRINFO pErrInfo); + +/** + * Set a custom certification authority file, containing root certificates. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param pszCAFile File name containing root certificates. + * + * @remarks For portable HTTPS support, use RTHttpGatherCaCertsInFile and pass + */ +RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pszCAFile); + +/** + * Gathers certificates into a cryptographic (certificate) store + * + * This is a just a combination of RTHttpGatherCaCertsInStore and + * RTCrStoreCertExportAsPem. + * + * @returns IPRT status code. + * @param hStore The certificate store to gather the certificates + * in. + * @param fFlags RTHTTPGATHERCACERT_F_XXX. + * @param pErrInfo Where to store additional error/warning information. + * Optional. + */ +RTR3DECL(int) RTHttpGatherCaCertsInStore(RTCRSTORE hStore, uint32_t fFlags, PRTERRINFO pErrInfo); + +/** + * Gathers certificates into a file that can be used with RTHttpSetCAFile. + * + * This is a just a combination of RTHttpGatherCaCertsInStore and + * RTCrStoreCertExportAsPem. + * + * @returns IPRT status code. + * @param pszCaFile The output file. + * @param fFlags RTHTTPGATHERCACERT_F_XXX. + * @param pErrInfo Where to store additional error/warning information. + * Optional. + */ +RTR3DECL(int) RTHttpGatherCaCertsInFile(const char *pszCaFile, uint32_t fFlags, PRTERRINFO pErrInfo); + +/** + * Set whether to verify the peer's SSL certificate. + * + * The default is to verify it. It can however sometimes be useful or even + * necessary to skip this. + * + * @returns iprt status code. + * + * @param hHttp The HTTP client handle. + * @param fVerify Verify the certificate if @a true. + */ +RTR3DECL(int) RTHttpSetVerifyPeer(RTHTTP hHttp, bool fVerify); + +/** + * Get the state of the peer's SSL certificate setting. + * + * @returns true if we verify the SSL certificate, false if not. + * @param hHttp The HTTP client handle. + */ +RTR3DECL(bool) RTHttpGetVerifyPeer(RTHTTP hHttp); + +/** + * Callback function to be called during RTHttpGet*(). + * + * Register it using RTHttpSetDownloadProgressCallback(). + * + * @param hHttp The HTTP client handle. + * @param pvUser The user parameter specified when registering the callback. + * @param cbDownloadTotal The content-length value, if available. + * Warning! Not entirely clear what it will be if + * unavailable, probably 0. + * @param cbDownloaded How much was downloaded thus far. + */ +typedef DECLCALLBACKTYPE(void, FNRTHTTPDOWNLDPROGRCALLBACK,(RTHTTP hHttp, void *pvUser, uint64_t cbDownloadTotal, + uint64_t cbDownloaded)); +/** Pointer to a download progress callback. */ +typedef FNRTHTTPDOWNLDPROGRCALLBACK *PFNRTHTTPDOWNLDPROGRCALLBACK; + +/** + * Set the callback function which is called during (GET) + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pfnCallback Progress function to be called. Set it to + * NULL to disable the callback. + * @param pvUser Convenience pointer for the callback function. + */ +RTR3DECL(int) RTHttpSetDownloadProgressCallback(RTHTTP hHttp, PFNRTHTTPDOWNLDPROGRCALLBACK pfnCallback, void *pvUser); + +/** + * Callback function for receiving body data. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pvBuf Pointer to buffer with body bytes. + * @param cbBuf Number of bytes in the buffer. + * @param uHttpStatus The HTTP status code. + * @param offContent The byte offset corresponding to the start of @a pvBuf. + * @param cbContent The content length field value, UINT64_MAX if not available. + * @param pvUser The user parameter. + * + * @note The @a offContent parameter does not imply random access or anthing + * like that, it is just a convenience provided by the caller. The + * value is the sum of the previous @a cbBuf values. + */ +typedef DECLCALLBACKTYPE(int, FNRTHTTPDOWNLOADCALLBACK,(RTHTTP hHttp, void const *pvBuf, size_t cbBuf, uint32_t uHttpStatus, + uint64_t offContent, uint64_t cbContent, void *pvUser)); +/** Pointer to a download data receiver callback. */ +typedef FNRTHTTPDOWNLOADCALLBACK *PFNRTHTTPDOWNLOADCALLBACK; + +/** + * Set the callback function for downloading data (HTTP GET). + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param fFlags RTHTTPDOWNLOAD_F_XXX. + * @param pfnCallback The callback function. Pass NULL to reset the callback. + * @param pvUser Convenience pointer for the callback function. + * + * @remarks There can only be one download callback, so it is not possible to + * call this method for different status codes. Only the last one + * with be honored. + * + * @note This only works reliably with RTHttpPerform at the moment. + */ +RTR3DECL(int) RTHttpSetDownloadCallback(RTHTTP hHttp, uint32_t fFlags, PFNRTHTTPDOWNLOADCALLBACK pfnCallback, void *pvUser); + +/** @name RTHTTPDOWNLOAD_F_XXX + * @{ */ +/** The lower 10 bits gives the HTTP status required by the callback. + * For all other status codes, any body data will be returned via the + * RTHttpPerform ppvBody/pcbBody return parameters. */ +#define RTHTTPDOWNLOAD_F_ONLY_STATUS_MASK UINT32_C(0x000003ff) +/** Callback requires no special HTTP status. */ +#define RTHTTPDOWNLOAD_F_ANY_STATUS UINT32_C(0x000003ff) +/** @} */ + + +/** + * Callback function for producing body data for uploading. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pvBuf Where to put the data to upload + * @param cbBuf Max number of bytes to provide. + * @param offContent The byte offset corresponding to the start of @a pvBuf. + * @param pcbActual Actual number of bytes provided. + * @param pvUser The user parameter. + * + * @note The @a offContent parameter does not imply random access or anthing + * like that, it is just a convenience provided by the caller. The + * value is the sum of the previously returned @a *pcbActual values. + */ +typedef DECLCALLBACKTYPE(int, FNRTHTTPUPLOADCALLBACK,(RTHTTP hHttp, void *pvBuf, size_t cbBuf, uint64_t offContent, + size_t *pcbActual, void *pvUser)); +/** Pointer to an upload data producer callback. */ +typedef FNRTHTTPUPLOADCALLBACK *PFNRTHTTPUPLOADCALLBACK; + +/** + * Set the callback function for providing upload data (HTTP PUT / POST). + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param cbContent The content length, UINT64_MAX if not know or specified separately. + * @param pfnCallback The callback function. Pass NULL to reset the callback. + * @param pvUser Convenience pointer for the callback function. + * + * @note This only works reliably with RTHttpPerform at the moment. + */ +RTR3DECL(int) RTHttpSetUploadCallback(RTHTTP hHttp, uint64_t cbContent, PFNRTHTTPUPLOADCALLBACK pfnCallback, void *pvUser); + + +/** + * Callback for consuming header fields. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param uMatchWord Match word constructed by RTHTTP_MAKE_HDR_MATCH_WORD + * @param pchField The field name (not zero terminated). + * Not necessarily valid UTF-8! + * @param cchField The length of the field. + * @param pchValue The field value (not zero terminated). + * Not necessarily valid UTF-8! + * @param cchValue The length of the value. + * @param pvUser The user parameter. + * + * @remarks This is called with two fictitious header fields too: + * - ':http-status-line' -- the HTTP/{version} {status-code} stuff. + * - ':end-of-headers' -- marks the end of header callbacks. + */ +typedef DECLCALLBACKTYPE(int, FNRTHTTPHEADERCALLBACK,(RTHTTP hHttp, uint32_t uMatchWord, const char *pchField, size_t cchField, + const char *pchValue, size_t cchValue, void *pvUser)); +/** Pointer to a header field consumer callback. */ +typedef FNRTHTTPHEADERCALLBACK *PFNRTHTTPHEADERCALLBACK; + +/** + * Forms a fast header match word. + * + * @returns Fast header match word. + * @param a_cchField The length of the header field name. + * @param a_chLower1 The first character in the name, lowercased. + * @param a_chLower2 The second character in the name, lowercased. + * @param a_chLower3 The third character in the name, lowercased. + */ +#define RTHTTP_MAKE_HDR_MATCH_WORD(a_cchField, a_chLower1, a_chLower2, a_chLower3) \ + RT_MAKE_U32_FROM_U8(a_cchField, a_chLower1, a_chLower2, a_chLower3) + +/** + * Set the callback function for processing header fields in the response. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pfnCallback The callback function. Pass NULL to reset the callback. + * @param pvUser Convenience pointer for the callback function. + * + * @note This only works reliably with RTHttpPerform at the moment. + */ +RTR3DECL(int) RTHttpSetHeaderCallback(RTHTTP hHttp, PFNRTHTTPHEADERCALLBACK pfnCallback, void *pvUser); + + +/** + * Supported proxy types. + */ +typedef enum RTHTTPPROXYTYPE +{ + RTHTTPPROXYTYPE_INVALID = 0, + RTHTTPPROXYTYPE_NOPROXY, + RTHTTPPROXYTYPE_HTTP, + RTHTTPPROXYTYPE_HTTPS, + RTHTTPPROXYTYPE_SOCKS4, + RTHTTPPROXYTYPE_SOCKS5, + RTHTTPPROXYTYPE_UNKNOWN, + RTHTTPPROXYTYPE_END, + RTHTTPPROXYTYPE_32BIT_HACK = 0x7fffffff +} RTHTTPPROXYTYPE; + +/** + * Proxy information returned by RTHttpQueryProxyInfoForUrl. + */ +typedef struct RTHTTPPROXYINFO +{ + /** Proxy host name. */ + char *pszProxyHost; + /** Proxy port number (UINT32_MAX if not specified). */ + uint32_t uProxyPort; + /** The proxy type (RTHTTPPROXYTYPE_HTTP, RTHTTPPROXYTYPE_SOCKS5, ++). */ + RTHTTPPROXYTYPE enmProxyType; + /** Proxy username. */ + char *pszProxyUsername; + /** Proxy password. */ + char *pszProxyPassword; +} RTHTTPPROXYINFO; +/** A pointer to proxy information structure. */ +typedef RTHTTPPROXYINFO *PRTHTTPPROXYINFO; + +/** + * Retrieve system proxy information for the specified URL. + * + * @returns IPRT status code. + * @param hHttp The HTTP client handle. + * @param pszUrl The URL that needs to be accessed via proxy. + * @param pProxyInfo Where to return the proxy information. This must be + * freed up by calling RTHttpFreeProxyInfo() when done. + */ +RTR3DECL(int) RTHttpQueryProxyInfoForUrl(RTHTTP hHttp, const char *pszUrl, PRTHTTPPROXYINFO pProxyInfo); + +/** + * Counter part to RTHttpQueryProxyInfoForUrl that releases any memory returned + * in the proxy info structure. + * + * @returns IPRT status code. + * @param pProxyInfo Pointer to proxy info returned by a successful + * RTHttpQueryProxyInfoForUrl() call. + */ +RTR3DECL(int) RTHttpFreeProxyInfo(PRTHTTPPROXYINFO pProxyInfo); + +/** @name thin wrappers for setting one or a few related curl options + * @remarks Temporary. Will not be included in the 7.0 release! + * @{ */ +typedef DECLCALLBACKTYPE_EX(size_t, RT_NOTHING, FNRTHTTPREADCALLBACKRAW,(void *pbDst, size_t cbItem, size_t cItems, void *pvUser)); +typedef FNRTHTTPREADCALLBACKRAW *PFNRTHTTPREADCALLBACKRAW; +#define RT_HTTP_READCALLBACK_ABORT 0x10000000 /* CURL_READFUNC_ABORT */ +RTR3DECL(int) RTHttpRawSetReadCallback(RTHTTP hHttp, PFNRTHTTPREADCALLBACKRAW pfnRead, void *pvUser); + +typedef DECLCALLBACKTYPE_EX(size_t, RT_NOTHING, FNRTHTTPWRITECALLBACKRAW,(char *pbSrc, size_t cbItem, size_t cItems, void *pvUser)); +typedef FNRTHTTPWRITECALLBACKRAW *PFNRTHTTPWRITECALLBACKRAW; +RTR3DECL(int) RTHttpRawSetWriteCallback(RTHTTP hHttp, PFNRTHTTPWRITECALLBACKRAW pfnWrite, void *pvUser); +RTR3DECL(int) RTHttpRawSetWriteHeaderCallback(RTHTTP hHttp, PFNRTHTTPWRITECALLBACKRAW pfnWrite, void *pvUser); + +RTR3DECL(int) RTHttpRawSetUrl(RTHTTP hHttp, const char *pszUrl); + +RTR3DECL(int) RTHttpRawSetGet(RTHTTP hHttp); +RTR3DECL(int) RTHttpRawSetHead(RTHTTP hHttp); +RTR3DECL(int) RTHttpRawSetPost(RTHTTP hHttp); +RTR3DECL(int) RTHttpRawSetPut(RTHTTP hHttp); +RTR3DECL(int) RTHttpRawSetDelete(RTHTTP hHttp); +RTR3DECL(int) RTHttpRawSetCustomRequest(RTHTTP hHttp, const char *pszVerb); + +RTR3DECL(int) RTHttpRawSetPostFields(RTHTTP hHttp, const void *pv, size_t cb); +RTR3DECL(int) RTHttpRawSetInfileSize(RTHTTP hHttp, RTFOFF cb); + +RTR3DECL(int) RTHttpRawSetVerbose(RTHTTP hHttp, bool fValue); +RTR3DECL(int) RTHttpRawSetTimeout(RTHTTP hHttp, long sec); + +RTR3DECL(int) RTHttpRawPerform(RTHTTP hHttp); + +RTR3DECL(int) RTHttpRawGetResponseCode(RTHTTP hHttp, long *plCode); +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_http_h */ + diff --git a/include/iprt/inifile.h b/include/iprt/inifile.h new file mode 100644 index 00000000..bc784bc5 --- /dev/null +++ b/include/iprt/inifile.h @@ -0,0 +1,150 @@ +/* $Id: inifile.h $ */ +/** @file + * IPRT - INI-file parser. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_inifile_h +#define IPRT_INCLUDED_inifile_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_inifile RTIniFile - INI-file parser + * @ingroup grp_rt + * @{ + */ + +/** @name RTINIFILE_F_XXX - INI-file open flags. + * @{ */ +/** Readonly. */ +#define RTINIFILE_F_READONLY RT_BIT(0) +/** Valid mask. */ +#define RTINIFILE_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + + + +/** + * Creates a INI-file instance from a VFS file handle. + * + * @returns IPRT status code + * @param phIniFile Where to return the INI-file handle. + * @param hVfsFile The VFS file handle (not consumed, additional + * reference is retained). + * @param fFlags Flags, RTINIFILE_F_XXX. + */ +RTDECL(int) RTIniFileCreateFromVfsFile(PRTINIFILE phIniFile, RTVFSFILE hVfsFile, uint32_t fFlags); + +/** + * Retains a reference to an INI-file instance. + * + * @returns New reference count, UINT32_MAX on failure. + * @param hIniFile The INI-file handle. + */ +RTDECL(uint32_t) RTIniFileRetain(RTINIFILE hIniFile); + +/** + * Releases a reference to an INI-file instance, destroying it if the count + * reaches zero. + * + * @returns New reference count, UINT32_MAX on failure. + * @param hIniFile The INI-file handle. NIL is ignored. + */ +RTDECL(uint32_t) RTIniFileRelease(RTINIFILE hIniFile); + +/** + * Queries a named value in a section. + * + * The first matching value is returned. The matching is by default case + * insensitive. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if section or key not found. + * + * @param hIniFile The INI-file handle. + * @param pszSection The section name. Pass NULL to refer to the + * unsectioned key space at the top of the file. + * @param pszKey The key name. + * @param pszValue Where to return the value. + * @param cbValue Size of the buffer @a pszValue points to. + * @param pcbActual Where to return the actual value size excluding + * terminator on success. On VERR_BUFFER_OVERFLOW this + * will be set to the buffer size needed to hold the + * value, terminator included. Optional. + */ +RTDECL(int) RTIniFileQueryValue(RTINIFILE hIniFile, const char *pszSection, const char *pszKey, + char *pszValue, size_t cbValue, size_t *pcbActual); + +/** + * Queries a key-value pair in a section by ordinal. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if the section wasn't found or if it contains no pair + * with the given ordinal value. + * + * @param hIniFile The INI-file handle. + * @param pszSection The section name. Pass NULL to refer to the + * unsectioned key space at the top of the file. + * @param idxPair The pair to fetch (counting from 0). + * + * @param pszKey Where to return the key name. + * @param cbKey Size of the buffer @a pszKey points to. + * @param pcbKeyActual Where to return the actual key size excluding + * terminator on success. On VERR_BUFFER_OVERFLOW this + * will be set to the buffer size needed to hold the + * value, terminator included. Optional. + * + * @param pszValue Where to return the value. + * @param cbValue Size of the buffer @a pszValue points to. + * @param pcbValueActual Where to return the actual value size excluding + * terminator on success. On VERR_BUFFER_OVERFLOW this + * will be set to the buffer size needed to hold the + * value, terminator included. Optional. + */ +RTDECL(int) RTIniFileQueryPair(RTINIFILE hIniFile, const char *pszSection, uint32_t idxPair, + char *pszKey, size_t cbKey, size_t *pcbKeyActual, + char *pszValue, size_t cbValue, size_t *pcbValueActual); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_inifile_h */ + diff --git a/include/iprt/initterm.h b/include/iprt/initterm.h new file mode 100644 index 00000000..8083d559 --- /dev/null +++ b/include/iprt/initterm.h @@ -0,0 +1,291 @@ +/** @file + * IPRT - Runtime Init/Term. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_initterm_h +#define IPRT_INCLUDED_initterm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt IPRT C/C++ APIs + * @{ + */ + +/** @defgroup grp_rt_initterm RTInit/RTTerm - Initialization and Termination + * + * APIs for initializing and terminating the IPRT, optionally it can also + * convert input arguments to UTF-8 (in ring-3). + * + * @sa RTOnce, RTOnceEx. + * + * @{ + */ + +#ifdef IN_RING3 + +/** @name RTR3INIT_FLAGS_XXX - RTR3Init* flags. + * @see RTR3InitExeNoArguments, RTR3InitExe, RTR3InitDll, RTR3InitEx + * @{ */ +/** Initializing IPRT from a DLL. */ +# define RTR3INIT_FLAGS_DLL RT_BIT(0) +/** The caller ensures that the argument vector is UTF-8. */ +# define RTR3INIT_FLAGS_UTF8_ARGV RT_BIT(1) +/** Indicates that this is a standalone application without any additional + * shared libraries in the application directory. Mainly windows loader mess. */ +# define RTR3INIT_FLAGS_STANDALONE_APP RT_BIT(2) +/** We are sharing a process space, so we need to behave. */ +# define RTR3INIT_FLAGS_UNOBTRUSIVE RT_BIT(3) + +/** Initialize SUPLib (must not fail). */ +# define RTR3INIT_FLAGS_SUPLIB RT_BIT(16) +/** Try initialize SUPLib and ignore failures. */ +# define RTR3INIT_FLAGS_TRY_SUPLIB RT_BIT(17) +/** Shift count for passing thru SUPR3INIT_F_XXX flags. */ +# define RTR3INIT_FLAGS_SUPLIB_SHIFT 18 +/** The mask covering the passthru SUPR3INIT_F_XXX flags. */ +# define RTR3INIT_FLAGS_SUPLIB_MASK UINT32_C(0xfffc0000) + +/** Valid flag mask. */ +# define RTR3INIT_FLAGS_VALID_MASK UINT32_C(0xffff000f) +/** @} */ + +/** @name RTR3InitEx version + * @{ */ +/** Version 1. */ +# define RTR3INIT_VER_1 UINT32_C(1) +/** Version 2 - new flags, rearranged a bit. */ +# define RTR3INIT_VER_2 UINT32_C(2) +/** The current version. */ +# define RTR3INIT_VER_CUR RTR3INIT_VER_2 +/** @} */ + +/** + * Initializes the runtime library. + * + * @returns iprt status code. + * @param fFlags Flags, see RTR3INIT_FLAGS_XXX. + */ +RTR3DECL(int) RTR3InitExeNoArguments(uint32_t fFlags); + +/** + * Initializes the runtime library. + * + * @returns iprt status code. + * @param cArgs Pointer to the argument count. + * @param ppapszArgs Pointer to the argument vector pointer. + * @param fFlags Flags, see RTR3INIT_FLAGS_XXX. + */ +RTR3DECL(int) RTR3InitExe(int cArgs, char ***ppapszArgs, uint32_t fFlags); + +/** + * Initializes the runtime library. + * + * @returns iprt status code. + * @param fFlags Flags, see RTR3INIT_FLAGS_XXX. + */ +RTR3DECL(int) RTR3InitDll(uint32_t fFlags); + +/** + * Initializes the runtime library and possibly also SUPLib too. + * + * Avoid this interface, it's not considered stable. + * + * @returns IPRT status code. + * @param iVersion The interface version. Must be 0 atm. + * @param fFlags Flags, see RTR3INIT_FLAGS_XXX. + * @param cArgs Pointer to the argument count. + * @param ppapszArgs Pointer to the argument vector pointer. NULL + * allowed if @a cArgs is 0. + * @param pszProgramPath The program path. Pass NULL if we're to figure it + * out ourselves. + */ +RTR3DECL(int) RTR3InitEx(uint32_t iVersion, uint32_t fFlags, int cArgs, char ***ppapszArgs, const char *pszProgramPath); + +/** + * Terminates the runtime library. + */ +RTR3DECL(void) RTR3Term(void); + +/** + * Is IPRT succesfully initialized? + * + * @returns true/false. + */ +RTR3DECL(bool) RTR3InitIsInitialized(void); + +/** + * Are we running in unobtrusive mode? + * @returns true/false. + */ +RTR3DECL(bool) RTR3InitIsUnobtrusive(void); + +#endif /* IN_RING3 */ + + +#ifdef IN_RING0 +/** + * Initializes the ring-0 driver runtime library. + * + * @returns iprt status code. + * @param fReserved Flags reserved for the future. + */ +RTR0DECL(int) RTR0Init(unsigned fReserved); + +/** + * Terminates the ring-0 driver runtime library. + */ +RTR0DECL(void) RTR0Term(void); + +/** + * Forcibily terminates the ring-0 driver runtime library. + * + * This should be used when statically linking the IPRT. Module using dynamic + * linking shall use RTR0Term. If you're not sure, use RTR0Term! + */ +RTR0DECL(void) RTR0TermForced(void); +#endif + +#ifdef IN_RC +/** + * Initializes the raw-mode context runtime library. + * + * @returns iprt status code. + * + * @param u64ProgramStartNanoTS The startup timestamp. + */ +RTRCDECL(int) RTRCInit(uint64_t u64ProgramStartNanoTS); + +/** + * Terminates the raw-mode context runtime library. + */ +RTRCDECL(void) RTRCTerm(void); +#endif + + +/** + * Termination reason. + */ +typedef enum RTTERMREASON +{ + /** Normal exit. iStatus contains the exit code. */ + RTTERMREASON_EXIT = 1, + /** Any abnormal exit. iStatus is 0 and has no meaning. */ + RTTERMREASON_ABEND, + /** Killed by a signal. The iStatus contains the signal number. */ + RTTERMREASON_SIGNAL, + /** The IPRT module is being unloaded. iStatus is 0 and has no meaning. */ + RTTERMREASON_UNLOAD +} RTTERMREASON; + +/** Whether lazy clean up is Okay or not. + * When the process is exiting, it is a waste of time to for instance free heap + * memory or close open files. OTOH, when the runtime is unloaded from the + * process, it is important to release absolutely all resources to prevent + * resource leaks. */ +#define RTTERMREASON_IS_LAZY_CLEANUP_OK(enmReason) ((enmReason) != RTTERMREASON_UNLOAD) + + +/** + * IPRT termination callback function. + * + * @param enmReason The cause of the termination. + * @param iStatus The meaning of this depends on enmReason. + * @param pvUser User argument passed to RTTermRegisterCallback. + */ +typedef DECLCALLBACKTYPE(void, FNRTTERMCALLBACK,(RTTERMREASON enmReason, int32_t iStatus, void *pvUser)); +/** Pointer to an IPRT termination callback function. */ +typedef FNRTTERMCALLBACK *PFNRTTERMCALLBACK; + + +/** + * Registers a termination callback. + * + * This is intended for performing clean up during IPRT termination. Frequently + * paired with lazy initialization thru RTOnce. + * + * The callbacks are called in LIFO order. + * + * @returns IPRT status code. + * + * @param pfnCallback The callback function. + * @param pvUser The user argument for the callback. + * + * @remarks May need to acquire a fast mutex or critical section, so use with + * some care in ring-0 context. + * + * @remarks Be very careful using this from code that may be unloaded before + * IPRT terminates. Unlike some atexit and on_exit implementations, + * IPRT will not automatically unregister callbacks when a module gets + * unloaded. + */ +RTDECL(int) RTTermRegisterCallback(PFNRTTERMCALLBACK pfnCallback, void *pvUser); + +/** + * Deregister a termination callback. + * + * @returns VINF_SUCCESS if found, VERR_NOT_FOUND if the callback/pvUser pair + * wasn't found. + * + * @param pfnCallback The callback function. + * @param pvUser The user argument for the callback. + */ +RTDECL(int) RTTermDeregisterCallback(PFNRTTERMCALLBACK pfnCallback, void *pvUser); + +/** + * Runs the termination callback queue. + * + * Normally called by an internal IPRT termination function, but may also be + * called by external code immediately prior to terminating IPRT if it is in a + * better position to state the termination reason and/or status. + * + * @param enmReason The reason why it's called. + * @param iStatus The associated exit status or signal number. + */ +RTDECL(void) RTTermRunCallbacks(RTTERMREASON enmReason, int32_t iStatus); + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + + +#endif /* !IPRT_INCLUDED_initterm_h */ + diff --git a/include/iprt/ioqueue.h b/include/iprt/ioqueue.h new file mode 100644 index 00000000..92f1e2f1 --- /dev/null +++ b/include/iprt/ioqueue.h @@ -0,0 +1,405 @@ +/** @file + * IPRT Generic I/O queue API. + */ + +/* + * Copyright (C) 2019-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_ioqueue_h +#define IPRT_INCLUDED_ioqueue_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/sg.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_ioqueue IPRT generic I/O queue API + * @ingroup grp_rt + * + * This API models a generic I/O queue which can be attached to different providers + * for different types of handles. + * + * @{ + */ + + +/** + * I/O queue request operations. + */ +typedef enum RTIOQUEUEOP +{ + /** The usual invalid option. */ + RTIOQUEUEOP_INVALID = 0, + /** Read request. */ + RTIOQUEUEOP_READ, + /** Write request. */ + RTIOQUEUEOP_WRITE, + /** Synchronize (i.e. flush) request. */ + RTIOQUEUEOP_SYNC, + /** Usual 32bit hack. */ + RTIOQUEUEOP_32BIT_HACK = 0x7fffffff +} RTIOQUEUEOP; +/** Pointer to a I/O queue operation code. */ +typedef RTIOQUEUEOP *PRTIOQUEUEOP; + +/** I/O queue provider (processes requests put into the I/O queue) handle. */ +typedef struct RTIOQUEUEPROVINT *RTIOQUEUEPROV; +/** I/O queue handle. */ +typedef struct RTIOQUEUEINT *RTIOQUEUE; +/** Pointer to an I/O queue handle. */ +typedef RTIOQUEUE *PRTIOQUEUE; +/** NIL I/O queue handle value. */ +#define NIL_RTIOQUEUE ((RTIOQUEUE)0) + + +/** + * I/O queue completion event. + */ +typedef struct RTIOQUEUECEVT +{ + /** The user data passed when preparing the request. */ + void *pvUser; + /** The IPRT status code for this request. */ + int rcReq; + /** Transferred data size if applicaple by the request. */ + size_t cbXfered; +} RTIOQUEUECEVT; +/** Pointer to a I/O queue completion event. */ +typedef RTIOQUEUECEVT *PRTIOQUEUECEVT; +/** Pointer to a const I/O queue completion event. */ +typedef const RTIOQUEUECEVT *PCRTIOQUEUECEVT; + + +/** + * I/O queue provider virtual method table. + */ +typedef struct RTIOQUEUEPROVVTABLE +{ + /** The structure version (RTIOQUEUEPROVVTABLE_VERSION). */ + uint32_t uVersion; + /** Provider ID. */ + const char *pszId; + /** Size of provider specific data for an I/O queue instance. */ + size_t cbIoQueueProv; + /** The handle type the provider is able to process. */ + RTHANDLETYPE enmHnd; + /** Additional flags for exposing supported features or quirks to the user. */ + uint32_t fFlags; + + /** + * Returns whether the provider is supported on the calling host system. + * + * @returns Flag whether the provider is supported. + */ + DECLCALLBACKMEMBER(bool, pfnIsSupported,(void)); + + /** + * Initializes the provider specific parts of the given I/O queue. + * + * @returns IPRT status code. + * @param hIoQueueProv The I/O queue provider instance to initialize. + * @param fFlags Flags for the queue. + * @param cSqEntries Number of entries for the submission queue. + * @param cCqEntries Number of entries for the completion queue. + */ + DECLCALLBACKMEMBER(int, pfnQueueInit,(RTIOQUEUEPROV hIoQueueProv, uint32_t fFlags, uint32_t cSqEntries, uint32_t cCqEntries)); + + /** + * Destroys the provider specific parts of the I/O queue and frees all + * associated resources. + * + * @returns nothing. + * @param hIoQueueProv The I/O queue provider instance to destroy. + */ + DECLCALLBACKMEMBER(void, pfnQueueDestroy,(RTIOQUEUEPROV hIoQueueProv)); + + /** + * Registers the given handle for use with the I/O queue instance. + * The generic code already checked for the correct handle type and that the + * handle wasn't registered already by tracking all registered handles. + * + * @returns IPRT status code. + * @param hIoQueueProv The I/O queue provider instance. + * @param pHandle The handle to register. + */ + DECLCALLBACKMEMBER(int, pfnHandleRegister,(RTIOQUEUEPROV hIoQueueProv, PCRTHANDLE pHandle)); + + /** + * Deregisters the given handle for use with the I/O queue instance. + * The generic code already checked for the correct handle type and that the + * handle was registered previously. + * + * @returns IPRT status code. + * @param hIoQueueProv The I/O queue provider instance. + * @param pHandle The handle to deregister. + */ + DECLCALLBACKMEMBER(int, pfnHandleDeregister,(RTIOQUEUEPROV hIoQueueProv, PCRTHANDLE pHandle)); + + /** + * Prepares a request for the given I/O queue. + * + * @returns IPRT status code. + * @param hIoQueueProv The I/O queue provider instance. + * @param pHandle The handle the request is for. + * @param enmOp The operation to perform. + * @param off Start offset (if applicable, not all handles support/require it and will ignore it). + * @param pvBuf Buffer to use for read/write operations (sync ignores this). + * @param cbBuf Size of the buffer in bytes. + * @param fReqFlags Additional flags for the request. + * @param pvUser Opaque user data which is passed back in the completion event. + */ + DECLCALLBACKMEMBER(int, pfnReqPrepare,(RTIOQUEUEPROV hIoQueueProv, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp, + uint64_t off, void *pvBuf, size_t cbBuf, uint32_t fReqFlags, void *pvUser)); + + /** + * Prepares a request for the given I/O queue. + * + * @returns IPRT status code. + * @param hIoQueueProv The I/O queue provider instance. + * @param pHandle The handle the request is for. + * @param enmOp The operation to perform. + * @param off Start offset (if applicable, not all handles support/require it and will ignore it). + * @param pSgBuf The S/G buufer to use for read/write operations (sync ignores this). + * @param cbSg Number of bytes to transfer from the S/G buffer. + * @param fReqFlags Additional flags for the request. + * @param pvUser Opaque user data which is passed back in the completion event. + */ + DECLCALLBACKMEMBER(int, pfnReqPrepareSg,(RTIOQUEUEPROV hIoQueueProv, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp, + uint64_t off, PCRTSGBUF pSgBuf, size_t cbSg, uint32_t fReqFlags, void *pvUser)); + + /** + * Commits all prepared requests to the consumer for processing. + * + * @returns IPRT status code. + * @param hIoQueueProv The I/O queue provider instance. + * @param pcReqsCommitted Where to store the number of requests actually committed. + */ + DECLCALLBACKMEMBER(int, pfnCommit,(RTIOQUEUEPROV hIoQueueProv, uint32_t *pcReqsCommitted)); + + /** + * Waits for completion events from the given I/O queue. + * + * @returns IPRT status code. + * @retval VERR_IOQUEUE_EMPTY if there is nothing to wait for. + * @param hIoQueueProv The I/O queue provider instance. + * @param paCEvt Pointer to the array of completion event entries to fill. + * @param cCEvt Size of the completion event entry array. + * @param cMinWait Minimum number of completion events to wait for before returning. + * @param pcCEvt Where to store the number of completion events on success. + * @param fFlags Additional flags controlling the wait behavior. + */ + DECLCALLBACKMEMBER(int, pfnEvtWait,(RTIOQUEUEPROV hIoQueueProv, PRTIOQUEUECEVT paCEvt, uint32_t cCEvt, + uint32_t cMinWait, uint32_t *pcCEvt, uint32_t fFlags)); + + /** + * Wakes up the thread waiting in RTIOQUEUEPROVVTABLE::pfnEvtWait(). + * + * @returns IPRT status code. + * @param hIoQueueProv The I/O queue provider instance. + */ + DECLCALLBACKMEMBER(int, pfnEvtWaitWakeup,(RTIOQUEUEPROV hIoQueueProv)); + + /** Marks the end of the structure (RTIOQUEUEPROVVTABLE_VERSION). */ + uintptr_t uEndMarker; +} RTIOQUEUEPROVVTABLE; +/** Pointer to an I/O queue provider vtable. */ +typedef RTIOQUEUEPROVVTABLE *PRTIOQUEUEPROVVTABLE; +/** Pointer to a const I/O queue provider vtable. */ +typedef RTIOQUEUEPROVVTABLE const *PCRTIOQUEUEPROVVTABLE; + +/** The RTIOQUEUEPROVVTABLE structure version. */ +#define RTIOQUEUEPROVVTABLE_VERSION RT_MAKE_U32_FROM_U8(0xff,0xf,1,0) + +/** @name RTIOQUEUEPROVVTABLE::fFlags + * @{ */ +/** Provider supports S/G lists. */ +#define RTIOQUEUEPROVVTABLE_F_SG RT_BIT_32(0) +/** Mask of the valid I/O stream feature flags. */ +#define RTIOQUEUEPROVVTABLE_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + + +/** + * Tries to return the best I/O queue provider for the given handle type on the called + * host system. + * + * @returns Pointer to the I/O queue provider handle table or NULL if no suitable + * provider was found for the given handle type. + * @param enmHnd The handle type to look for a provider. + */ +RTDECL(PCRTIOQUEUEPROVVTABLE) RTIoQueueProviderGetBestForHndType(RTHANDLETYPE enmHnd); + + +/** + * Returns the I/O queue provider with the given ID. + * + * @returns Pointer to the I/O queue provider handle table or NULL if no provider with + * the given ID was found. + * @param pszId The ID to look for. + */ +RTDECL(PCRTIOQUEUEPROVVTABLE) RTIoQueueProviderGetById(const char *pszId); + + +/** + * Creates a new I/O queue with the given consumer. + * + * @returns IPRT status code. + * @param phIoQueue Where to store the handle to the I/O queue on success. + * @param pProvVTable The I/O queue provider vtable which will process the requests. + * @param fFlags Flags for the queue (MBZ for now). + * @param cSqEntries Number of entries for the submission queue. + * @param cCqEntries Number of entries for the completion queue. + * + * @note The number of submission and completion queue entries serve only as a hint to the + * provider implementation. It may decide to align the number to a smaller or greater + * size. + */ +RTDECL(int) RTIoQueueCreate(PRTIOQUEUE phIoQueue, PCRTIOQUEUEPROVVTABLE pProvVTable, + uint32_t fFlags, uint32_t cSqEntries, uint32_t cCqEntries); + + +/** + * Destroys the given I/O queue. + * + * @returns IPRT status code. + * @retval VERR_IOQUEUE_BUSY if the I/O queue is still processing requests. + * @param hIoQueue The I/O queue handle to destroy. + */ +RTDECL(int) RTIoQueueDestroy(RTIOQUEUE hIoQueue); + + +/** + * Registers the given handle for use with the I/O queue. + * + * @returns IPRT status code. + * @retval VERR_ALREADY_EXISTS if the handle was already registered. + * @retval VERR_NOT_SUPPORTED if the handle type is not supported by the consumer + * for the given I/O queue. + * @param hIoQueue The I/O queue handle. + * @param pHandle The handle to register. + */ +RTDECL(int) RTIoQueueHandleRegister(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle); + + +/** + * Deregisters the given handle from the given I/O queue. + * + * @returns IPRT status code. + * @retval VERR_IOQUEUE_HANDLE_NOT_REGISTERED if the handle wasn't registered by a call to RTIoQueueHandleRegister(). + * @param hIoQueue The I/O queue handle. + * @param pHandle The handle to deregister. + */ +RTDECL(int) RTIoQueueHandleDeregister(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle); + + +/** + * Prepares a request for the given I/O queue. + * + * @returns IPRT status code. + * @retval VERR_IOQUEUE_FULL if the I/O queue can't accept the new request because the submission queue is full. + * @retval VERR_IOQUEUE_HANDLE_NOT_REGISTERED if the handle wasn't registered for use with RTIoQueueHandleRegister() yet. + * @param hIoQueue The I/O queue handle. + * @param pHandle The handle the request is for. + * @param enmOp The operation to perform. + * @param off Start offset (if applicable, not all handles support/require it and will ignore it). + * @param pvBuf Buffer to use for read/write operations (sync ignores this). + * @param cbBuf Size of the buffer in bytes. + * @param fReqFlags Additional flags for the request. + * @param pvUser Opaque user data which is passed back in the completion event. + */ +RTDECL(int) RTIoQueueRequestPrepare(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp, + uint64_t off, void *pvBuf, size_t cbBuf, uint32_t fReqFlags, + void *pvUser); + + +/** + * Prepares a request for the given I/O queue - S/G buffer variant. + * + * @returns IPRT status code. + * @retval VERR_IOQUEUE_FULL if the I/O queue can't accept the new request because the submission queue is full. + * @retval VERR_IOQUEUE_HANDLE_NOT_REGISTERED if the handle wasn't registered for use with RTIoQueueHandleRegister() yet. + * @param hIoQueue The I/O queue handle. + * @param pHandle The handle the request is for. + * @param enmOp The operation to perform. + * @param off Start offset (if applicable, not all handles support/require it and will ignore it). + * @param pSgBuf The S/G buufer to use for read/write operations (sync ignores this). + * @param cbSg Number of bytes to transfer from the S/G buffer. + * @param fReqFlags Additional flags for the request. + * @param pvUser Opaque user data which is passed back in the completion event. + */ +RTDECL(int) RTIoQueueRequestPrepareSg(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp, + uint64_t off, PCRTSGBUF pSgBuf, size_t cbSg, uint32_t fReqFlags, + void *pvUser); + + +/** + * Commits all prepared requests to the consumer for processing. + * + * @returns IPRT status code. + * @retval VERR_IOQUEUE_EMPTY if there is nothing to commit. + * @param hIoQueue The I/O queue handle. + */ +RTDECL(int) RTIoQueueCommit(RTIOQUEUE hIoQueue); + + +/** + * Waits for completion events from the given I/O queue. + * + * @returns IPRT status code. + * @retval VERR_IOQUEUE_EMPTY if there is nothing to wait for. + * @param hIoQueue The I/O queue handle. + * @param paCEvt Pointer to the array of completion event entries to fill. + * @param cCEvt Size of the completion event entry array. + * @param cMinWait Minimum number of completion events to wait for before returning. + * @param pcCEvt Where to store the number of completion events on success. + * @param fFlags Additional flags controlling the wait behavior. + */ +RTDECL(int) RTIoQueueEvtWait(RTIOQUEUE hIoQueue, PRTIOQUEUECEVT paCEvt, uint32_t cCEvt, uint32_t cMinWait, + uint32_t *pcCEvt, uint32_t fFlags); + + +/** + * Wakes up the thread waiting in RTIoQueueEvtWait(). + * + * @returns IPRT status code. + * @param hIoQueue The I/O queue handle to wake up. + */ +RTDECL(int) RTIoQueueEvtWaitWakeup(RTIOQUEUE hIoQueue); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_ioqueue_h */ + diff --git a/include/iprt/json.h b/include/iprt/json.h new file mode 100644 index 00000000..df588736 --- /dev/null +++ b/include/iprt/json.h @@ -0,0 +1,384 @@ +/** @file + * IPRT - JavaScript Object Notation (JSON) Parser. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_json_h +#define IPRT_INCLUDED_json_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_json RTJson - JavaScript Object Notation (JSON) Parser + * @ingroup grp_rt + * @{ + */ + +/** + * JSON value types. + */ +typedef enum RTJSONVALTYPE +{ + /** Invalid first value. */ + RTJSONVALTYPE_INVALID = 0, + /** Value containing an object. */ + RTJSONVALTYPE_OBJECT, + /** Value containing an array. */ + RTJSONVALTYPE_ARRAY, + /** Value containing a string. */ + RTJSONVALTYPE_STRING, + /** Value containg an integer number. */ + RTJSONVALTYPE_INTEGER, + /** Value containg an floating point number. */ + RTJSONVALTYPE_NUMBER, + /** Value containg the special null value. */ + RTJSONVALTYPE_NULL, + /** Value containing true. */ + RTJSONVALTYPE_TRUE, + /** Value containing false. */ + RTJSONVALTYPE_FALSE, + /** 32-bit hack. */ + RTJSONVALTYPE_32BIT_HACK = 0x7fffffff +} RTJSONVALTYPE; +/** Pointer to a JSON value type. */ +typedef RTJSONVALTYPE *PRTJSONVALTYPE; + +/** JSON value handle. */ +typedef struct RTJSONVALINT *RTJSONVAL; +/** Pointer to a JSON value handle. */ +typedef RTJSONVAL *PRTJSONVAL; +/** NIL JSON value handle. */ +#define NIL_RTJSONVAL ((RTJSONVAL)~(uintptr_t)0) + +/** JSON iterator handle. */ +typedef struct RTJSONITINT *RTJSONIT; +/** Pointer to a JSON iterator handle. */ +typedef RTJSONIT *PRTJSONIT; +/** NIL JSON iterator handle. */ +#define NIL_RTJSONIT ((RTJSONIT)~(uintptr_t)0) + +/** + * Parses a JSON document in the provided buffer returning the root JSON value. + * + * @returns IPRT status code. + * @retval VERR_JSON_MALFORMED if the document does not conform to the spec. + * @param phJsonVal Where to store the handle to the JSON value on success. + * @param pbBuf The byte buffer containing the JSON document. + * @param cbBuf Size of the buffer. + * @param pErrInfo Where to store extended error info. Optional. + * + * @todo r=bird: The use of uint8_t makes no sense here since the parser + * expects ASCII / UTF-8. What's more, if this is a real buffer the + * type should be 'const void *' rather than 'const uint8_t *'. + * This function should be modified to reflect that it's really for + * handling unterminated strings. + */ +RTDECL(int) RTJsonParseFromBuf(PRTJSONVAL phJsonVal, const uint8_t *pbBuf, size_t cbBuf, PRTERRINFO pErrInfo); + +/** + * Parses a JSON document from the provided string returning the root JSON value. + * + * @returns IPRT status code. + * @retval VERR_JSON_MALFORMED if the document does not conform to the spec. + * @param phJsonVal Where to store the handle to the JSON value on success. + * @param pszStr The string containing the JSON document. + * @param pErrInfo Where to store extended error info. Optional. + */ +RTDECL(int) RTJsonParseFromString(PRTJSONVAL phJsonVal, const char *pszStr, PRTERRINFO pErrInfo); + +/** + * Parses a JSON document from the file pointed to by the given filename + * returning the root JSON value. + * + * @returns IPRT status code. + * @retval VERR_JSON_MALFORMED if the document does not conform to the spec. + * @param phJsonVal Where to store the handle to the JSON value on success. + * @param pszFilename The name of the file containing the JSON document. + * @param pErrInfo Where to store extended error info. Optional. + */ +RTDECL(int) RTJsonParseFromFile(PRTJSONVAL phJsonVal, const char *pszFilename, PRTERRINFO pErrInfo); + +/** + * Parses a JSON document from the given VFS file + * returning the root JSON value. + * + * @returns IPRT status code. + * @retval VERR_JSON_MALFORMED if the document does not conform to the spec. + * @param phJsonVal Where to store the handle to the JSON value on success. + * @param hVfsFile The VFS file to parse. + * @param pErrInfo Where to store extended error info. Optional. + */ +RTDECL(int) RTJsonParseFromVfsFile(PRTJSONVAL phJsonVal, RTVFSFILE hVfsFile, PRTERRINFO pErrInfo); + +/** + * Retain a given JSON value. + * + * @returns New reference count. + * @param hJsonVal The JSON value handle. + */ +RTDECL(uint32_t) RTJsonValueRetain(RTJSONVAL hJsonVal); + +/** + * Release a given JSON value. + * + * @returns New reference count, if this drops to 0 the value is freed. + * @param hJsonVal The JSON value handle. + */ +RTDECL(uint32_t) RTJsonValueRelease(RTJSONVAL hJsonVal); + +/** + * Return the type of a given JSON value. + * + * @returns Type of the given JSON value. + * @param hJsonVal The JSON value handle. + */ +RTDECL(RTJSONVALTYPE) RTJsonValueGetType(RTJSONVAL hJsonVal); + +/** + * Translates value type to a name. + * + * @returns Readonly name string + * @param enmType The JSON value type to name. + */ +RTDECL(const char *) RTJsonValueTypeName(RTJSONVALTYPE enmType); + +/** + * Returns the string from a given JSON string value. + * + * @returns Pointer to the string of the JSON value, NULL if the value type + * doesn't indicate a string. + * @param hJsonVal The JSON value handle. + */ +RTDECL(const char *) RTJsonValueGetString(RTJSONVAL hJsonVal); + +/** + * Returns the string from a given JSON string value, extended. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not a string. + * @param hJsonVal The JSON value handle. + * @param ppszStr Where to store the pointer to the string on success. + */ +RTDECL(int) RTJsonValueQueryString(RTJSONVAL hJsonVal, const char **ppszStr); + +/** + * Returns the integer from a given JSON integer value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not a number. + * @param hJsonVal The JSON value handle. + * @param pi64Num WHere to store the number on success. + * @sa RTJsonValueQueryNumber + */ +RTDECL(int) RTJsonValueQueryInteger(RTJSONVAL hJsonVal, int64_t *pi64Num); + +/** + * Returns the floating point value from a given JSON number value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not a number. + * @param hJsonVal The JSON value handle. + * @param prdNum WHere to store the floating point number on success. + * @sa RTJsonValueQueryInteger + */ +RTDECL(int) RTJsonValueQueryNumber(RTJSONVAL hJsonVal, double *prdNum); + +/** + * Returns the value associated with a given name for the given JSON object value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an object. + * @retval VERR_NOT_FOUND if the name is not known for this JSON object. + * @param hJsonVal The JSON value handle. + * @param pszName The member name of the object. + * @param phJsonVal Where to store the handle to the JSON value on success. + */ +RTDECL(int) RTJsonValueQueryByName(RTJSONVAL hJsonVal, const char *pszName, PRTJSONVAL phJsonVal); + +/** + * Returns the number of a number value associated with a given name for the given JSON object value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an object or + * the name does not point to an integer value. + * @retval VERR_NOT_FOUND if the name is not known for this JSON object. + * @param hJsonVal The JSON value handle. + * @param pszName The member name of the object. + * @param pi64Num Where to store the number on success. + */ +RTDECL(int) RTJsonValueQueryIntegerByName(RTJSONVAL hJsonVal, const char *pszName, int64_t *pi64Num); + +/** + * Returns the number of a number value associated with a given name for the given JSON object value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an object or + * the name does not point to a number value. + * @retval VERR_NOT_FOUND if the name is not known for this JSON object. + * @param hJsonVal The JSON value handle. + * @param pszName The member name of the object. + * @param prdNum WHere to store the floating point number on success. + */ +RTDECL(int) RTJsonValueQueryNumberByName(RTJSONVAL hJsonVal, const char *pszName, double *prdNum); + +/** + * Returns the string of a string value associated with a given name for the given JSON object value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an object or + * the name does not point to a string value. + * @retval VERR_NOT_FOUND if the name is not known for this JSON object. + * @param hJsonVal The JSON value handle. + * @param pszName The member name of the object. + * @param ppszStr Where to store the pointer to the string on success. + * Must be freed with RTStrFree(). + */ +RTDECL(int) RTJsonValueQueryStringByName(RTJSONVAL hJsonVal, const char *pszName, char **ppszStr); + +/** + * Returns the boolean of a true/false value associated with a given name for the given JSON object value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an object or + * the name does not point to a true/false value. + * @retval VERR_NOT_FOUND if the name is not known for this JSON object. + * @param hJsonVal The JSON value handle. + * @param pszName The member name of the object. + * @param pfBoolean Where to store the boolean value on success. + */ +RTDECL(int) RTJsonValueQueryBooleanByName(RTJSONVAL hJsonVal, const char *pszName, bool *pfBoolean); + +/** + * Returns the size of a given JSON array value. + * + * @returns Size of the JSON array value. + * @retval 0 if the array is empty or the JSON value is not an array. + * @param hJsonVal The JSON value handle. + */ +RTDECL(unsigned) RTJsonValueGetArraySize(RTJSONVAL hJsonVal); + +/** + * Returns the size of a given JSON array value - extended version. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an array. + * @param hJsonVal The JSON value handle. + * @param pcItems Where to store the size of the JSON array value on success. + */ +RTDECL(int) RTJsonValueQueryArraySize(RTJSONVAL hJsonVal, unsigned *pcItems); + +/** + * Returns the value for the given index of a given JSON array value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an array. + * @retval VERR_OUT_OF_RANGE if @a idx is out of bounds. + * + * @param hJsonVal The JSON value handle. + * @param idx The index to get the value from. + * @param phJsonVal Where to store the handle to the JSON value on success. + */ +RTDECL(int) RTJsonValueQueryByIndex(RTJSONVAL hJsonVal, unsigned idx, PRTJSONVAL phJsonVal); + +/** + * Creates an iterator for a given JSON array or object value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an array or + * object. + * @param hJsonVal The JSON value handle. + * @param phJsonIt Where to store the JSON iterator handle on success. + * @todo Make return VERR_JSON_IS_EMPTY (or remove it). + */ +RTDECL(int) RTJsonIteratorBegin(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt); + +/** + * Creates an iterator for a given JSON array value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an array. + * @retval VERR_JSON_IS_EMPTY if no members. + * @param hJsonVal The JSON value handle. + * @param phJsonIt Where to store the JSON iterator handle on success. + */ +RTDECL(int) RTJsonIteratorBeginArray(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt); + +/** + * Creates an iterator for a given JSON object value. + * + * @returns IPRT status code. + * @retval VERR_JSON_VALUE_INVALID_TYPE if the JSON value is not an object. + * @retval VERR_JSON_IS_EMPTY if no members. + * @param hJsonVal The JSON value handle. + * @param phJsonIt Where to store the JSON iterator handle on success. + */ +RTDECL(int) RTJsonIteratorBeginObject(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt); + +/** + * Gets the value and optional name for the current iterator position. + * + * @returns IPRT status code. + * @param hJsonIt The JSON iterator handle. + * @param phJsonVal Where to store the handle to the JSON value on success. + * @param ppszName Where to store the object member name for an object. + * NULL is returned for arrays. + */ +RTDECL(int) RTJsonIteratorQueryValue(RTJSONIT hJsonIt, PRTJSONVAL phJsonVal, const char **ppszName); + +/** + * Advances to the next element in the referenced JSON value. + * + * @returns IPRT status code. + * @retval VERR_JSON_ITERATOR_END if the end for this iterator was reached. + * @param hJsonIt The JSON iterator handle. + */ +RTDECL(int) RTJsonIteratorNext(RTJSONIT hJsonIt); + +/** + * Frees a given JSON iterator. + * + * @param hJsonIt The JSON iterator to free. + */ +RTDECL(void) RTJsonIteratorFree(RTJSONIT hJsonIt); + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_json_h */ + diff --git a/include/iprt/krnlmod.h b/include/iprt/krnlmod.h new file mode 100644 index 00000000..9b1eb12c --- /dev/null +++ b/include/iprt/krnlmod.h @@ -0,0 +1,202 @@ +/** @file + * IPRT - Kernel module. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_krnlmod_h +#define IPRT_INCLUDED_krnlmod_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_kmod RTKrnlMod - Kernel module/driver userspace side API. + * @ingroup grp_rt + * @{ + */ + +/** + * Checks whether the given kernel module was loaded. + * + * @returns IPRT status code. + * @param pszName The driver name to check. + * @param pfLoaded Where to store the flag whether the module is loaded on success. + */ +RTDECL(int) RTKrnlModQueryLoaded(const char *pszName, bool *pfLoaded); + +/** + * Returns the kernel module information handle for the given loaded kernel module. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if the kernel driver is not loaded. + * @param pszName The driver name. + * @param phKrnlModInfo Where to store the handle to the kernel module information record. + */ +RTDECL(int) RTKrnlModLoadedQueryInfo(const char *pszName, PRTKRNLMODINFO phKrnlModInfo); + +/** + * Returns the number of kernel modules loaded on the host system. + * + * @returns Number of kernel modules loaded. + */ +RTDECL(uint32_t) RTKrnlModLoadedGetCount(void); + +/** + * Returns all loaded kernel modules on the host. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if there are not enough entries in the passed handle array. + * The required number of entries will be returned in pcEntries. + * @param pahKrnlModInfo Where to store the handles to the kernel module information records + * on success. + * @param cEntriesMax Maximum number of entries fitting in the given array. + * @param pcEntries Where to store the number of entries used/required. + */ +RTDECL(int) RTKrnlModLoadedQueryInfoAll(PRTKRNLMODINFO pahKrnlModInfo, uint32_t cEntriesMax, + uint32_t *pcEntries); + +/** + * Retains the given kernel module information record handle. + * + * @returns New reference count. + * @param hKrnlModInfo The kernel module information record handle. + */ +RTDECL(uint32_t) RTKrnlModInfoRetain(RTKRNLMODINFO hKrnlModInfo); + +/** + * Releases the given kernel module information record handle. + * + * @returns New reference count, on 0 the handle is destroyed. + * @param hKrnlModInfo The kernel module information record handle. + */ +RTDECL(uint32_t) RTKrnlModInfoRelease(RTKRNLMODINFO hKrnlModInfo); + +/** + * Returns the number of references held onto the kernel module by other + * drivers or userspace clients. + * + * @returns Number of references held on the kernel module. + * @param hKrnlModInfo The kernel module information record handle. + */ +RTDECL(uint32_t) RTKrnlModInfoGetRefCnt(RTKRNLMODINFO hKrnlModInfo); + +/** + * Returns the name of the kernel module. + * + * @returns Pointer to the kernel module name. + * @param hKrnlModInfo The kernel module information record handle. + */ +RTDECL(const char *) RTKrnlModInfoGetName(RTKRNLMODINFO hKrnlModInfo); + +/** + * Returns the filepath of the kernel module. + * + * @returns Pointer to the kernel module path. + * @param hKrnlModInfo The kernel module information record handle. + */ +RTDECL(const char *) RTKrnlModInfoGetFilePath(RTKRNLMODINFO hKrnlModInfo); + +/** + * Returns the size of the kernel module. + * + * @returns Size of the kernel module in bytes. + * @param hKrnlModInfo The kernel module information record handle. + */ +RTDECL(size_t) RTKrnlModInfoGetSize(RTKRNLMODINFO hKrnlModInfo); + +/** + * Returns the load address of the kernel module. + * + * @returns Load address of the kernel module. + * @param hKrnlModInfo The kernel module information record handle. + */ +RTDECL(RTR0UINTPTR) RTKrnlModInfoGetLoadAddr(RTKRNLMODINFO hKrnlModInfo); + +/** + * Query the kernel information record for a referencing kernel module of the + * given record. + * + * @returns IPRT status code. + * @param hKrnlModInfo The kernel module information record handle. + * @param idx Referencing kernel module index (< reference count + * as retrieved by RTKrnlModInfoGetRefCnt() ). + * @param phKrnlModInfoRef Where to store the handle to the referencing kernel module + * information record. + */ +RTDECL(int) RTKrnlModInfoQueryRefModInfo(RTKRNLMODINFO hKrnlModInfo, uint32_t idx, + PRTKRNLMODINFO phKrnlModInfoRef); + +/** + * Tries to load a kernel module by the given name. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if not supported by or implemented for the platform. + * @param pszName The name of the kernel module. This is highly platform + * dependent. + * + * @note On macOS for example the name is the bundle ID. + */ +RTDECL(int) RTKrnlModLoadByName(const char *pszName); + +/** + * Tries to load a kernel module by the given file path. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if not supported by or implemented for the platform. + * @param pszPath The path of the kernel module. + */ +RTDECL(int) RTKrnlModLoadByPath(const char *pszPath); + +/** + * Tries to unload a kernel module by the given name. + * + * @returns IPRT status code. + * @param pszName The name of the kernel module. This is highly platform + * dependent and should be queried with RTKrnlModInfoGetName() + * when checking whether the module was actually loaded. + * + * @note On macOS for example the name is the bundle ID. + */ +RTDECL(int) RTKrnlModUnloadByName(const char *pszName); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_krnlmod_h */ + diff --git a/include/iprt/latin1.h b/include/iprt/latin1.h new file mode 100644 index 00000000..074c1e65 --- /dev/null +++ b/include/iprt/latin1.h @@ -0,0 +1,404 @@ +/** @file + * IPRT - String Manipulation, Latin-1 (ISO-8859-1) encoding. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_latin1_h +#define IPRT_INCLUDED_latin1_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assert.h> +#include <iprt/errcore.h> /* VERR_END_OF_STRING */ + +RT_C_DECLS_BEGIN + + +/** @defgroup rt_str_latin1 Latin-1 (ISO-8859-1) String Manipulation + * @ingroup grp_rt_str + * + * Deals with Latin-1 encoded strings. + * + * @warning Make sure to name all variables dealing with Latin-1 strings + * suchthat there is no way to mistake them for normal UTF-8 strings. + * There may be severe security issues resulting from mistaking Latin-1 + * for UTF-8! + * + * @{ + */ + +/** + * Get the unicode code point at the given string position. + * + * @returns unicode code point. + * @returns RTUNICP_INVALID if the encoding is invalid. + * @param pszLatin1 The Latin-1 string. + */ +DECLINLINE(RTUNICP) RTLatin1GetCp(const char *pszLatin1) +{ + return *(const unsigned char *)pszLatin1; +} + +/** + * Get the unicode code point at the given string position. + * + * @returns iprt status code. + * @param ppszLatin1 Pointer to the string pointer. This will be updated to + * point to the char following the current code point. This + * is advanced one character forward on failure. + * @param pCp Where to store the code point. RTUNICP_INVALID is stored + * here on failure. + */ +DECLINLINE(int) RTLatin1GetCpEx(const char **ppszLatin1, PRTUNICP pCp) +{ + const unsigned char uch = **(const unsigned char **)ppszLatin1; + (*ppszLatin1)++; + *pCp = uch; + return VINF_SUCCESS; +} + +/** + * Get the unicode code point at the given string position for a string of a + * given maximum length. + * + * @returns iprt status code. + * @retval VERR_END_OF_STRING if *pcch is 0. *pCp is set to RTUNICP_INVALID. + * + * @param ppszLatin1 Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * @param pcchLatin1 Pointer to the maximum string length. This will be + * decremented by the size of the code point found. + * @param pCp Where to store the code point. + * RTUNICP_INVALID is stored here on failure. + */ +DECLINLINE(int) RTLatin1GetCpNEx(const char **ppszLatin1, size_t *pcchLatin1, PRTUNICP pCp) +{ + if (RT_LIKELY(*pcchLatin1 != 0)) + { + const unsigned char uch = **(const unsigned char **)ppszLatin1; + (*ppszLatin1)++; + (*pcchLatin1)--; + *pCp = uch; + return VINF_SUCCESS; + } + *pCp = RTUNICP_INVALID; + return VERR_END_OF_STRING; +} + +/** + * Get the Latin-1 size in characters of a given Unicode code point. + * + * The code point is expected to be a valid Unicode one, but not necessarily in + * the range supported by Latin-1. + * + * @returns the size in characters, or zero if there is no Latin-1 encoding + */ +DECLINLINE(size_t) RTLatin1CpSize(RTUNICP CodePoint) +{ + if (CodePoint < 0x100) + return 1; + return 0; +} + +/** + * Put the unicode code point at the given string position + * and return the pointer to the char following it. + * + * This function will not consider anything at or following the + * buffer area pointed to by psz. It is therefore not suitable for + * inserting code points into a string, only appending/overwriting. + * + * @returns pointer to the char following the written code point. + * @param pszLatin1 The string. + * @param CodePoint The code point to write. + * This should not be RTUNICP_INVALID or any other + * character out of the Latin-1 range. + */ +DECLINLINE(char *) RTLatin1PutCp(char *pszLatin1, RTUNICP CodePoint) +{ + AssertReturn(CodePoint < 0x100, NULL); + *pszLatin1++ = (unsigned char)CodePoint; + return pszLatin1; +} + +/** + * Skips ahead, past the current code point. + * + * @returns Pointer to the char after the current code point. + * @param pszLatin1 Pointer to the current code point. + * @remark This will not move the next valid code point, only past the current one. + */ +DECLINLINE(char *) RTLatin1NextCp(const char *pszLatin1) +{ + pszLatin1++; + return (char *)pszLatin1; +} + +/** + * Skips back to the previous code point. + * + * @returns Pointer to the char before the current code point. + * @returns pszLatin1Start on failure. + * @param pszLatin1Start Pointer to the start of the string. + * @param pszLatin1 Pointer to the current code point. + */ +DECLINLINE(char *) RTLatin1PrevCp(const char *pszLatin1Start, const char *pszLatin1) +{ + if ((uintptr_t)pszLatin1 > (uintptr_t)pszLatin1Start) + { + pszLatin1--; + return (char *)pszLatin1; + } + return (char *)pszLatin1Start; +} + +/** + * Translate a Latin1 string into a UTF-8 allocating the result buffer (default + * tag). + * + * @returns iprt status code. + * @param pszLatin1 Latin1 string to convert. + * @param ppszString Receives pointer of allocated UTF-8 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + */ +#define RTLatin1ToUtf8(pszLatin1, ppszString) RTLatin1ToUtf8Tag((pszLatin1), (ppszString), RTSTR_TAG) + +/** + * Translate a Latin-1 string into a UTF-8 allocating the result buffer. + * + * @returns iprt status code. + * @param pszLatin1 Latin-1 string to convert. + * @param ppszString Receives pointer of allocated UTF-8 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTLatin1ToUtf8Tag(const char *pszLatin1, char **ppszString, const char *pszTag); + +/** + * Translates Latin-1 to UTF-8 using buffer provided by the caller or a fittingly + * sized buffer allocated by the function (default tag). + * + * @returns iprt status code. + * @param pszLatin1 The Latin-1 string to convert. + * @param cchLatin1 The number of Latin-1 characters to translate from + * pszLatin1. The translation will stop when reaching + * cchLatin1 or the terminator ('\\0'). Use RTSTR_MAX + * to translate the entire string. + * @param ppsz If @a cch is non-zero, this must either be pointing + * to a pointer to a buffer of the specified size, or + * pointer to a NULL pointer. If *ppsz is NULL or + * @a cch is zero a buffer of at least @a cch chars + * will be allocated to hold the translated string. If + * a buffer was requested it must be freed using + * RTStrFree(). + * @param cch The buffer size in chars (the type). This includes the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTLatin1ToUtf8Ex(pszLatin1, cchLatin1, ppsz, cch, pcch) \ + RTLatin1ToUtf8ExTag((pszLatin1), (cchLatin1), (ppsz), (cch), (pcch), RTSTR_TAG) + +/** + * Translates Latin1 to UTF-8 using buffer provided by the caller or a fittingly + * sized buffer allocated by the function (custom tag). + * + * @returns iprt status code. + * @param pszLatin1 The Latin1 string to convert. + * @param cchLatin1 The number of Latin1 characters to translate from + * pwszString. The translation will stop when + * reaching cchLatin1 or the terminator ('\\0'). Use + * RTSTR_MAX to translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to + * a pointer to a buffer of the specified size, or + * pointer to a NULL pointer. If *ppsz is NULL or cch + * is zero a buffer of at least cch chars will be + * allocated to hold the translated string. If a + * buffer was requested it must be freed using + * RTStrFree(). + * @param cch The buffer size in chars (the type). This includes + * the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTLatin1ToUtf8ExTag(const char *pszLatin1, size_t cchLatin1, char **ppsz, size_t cch, size_t *pcch, + const char *pszTag); + +/** + * Calculates the length of the Latin-1 string in UTF-8 chars (bytes). + * + * The primary purpose of this function is to help allocate buffers for + * RTLatin1ToUtf8() of the correct size. For most other purposes + * RTLatin1ToUtf8Ex() should be used. + * + * @returns Number of chars (bytes). + * @returns 0 if the string was incorrectly encoded. + * @param pszLatin1 The Latin-1 string. + */ +RTDECL(size_t) RTLatin1CalcUtf8Len(const char *pszLatin1); + +/** + * Calculates the length of the Latin-1 string in UTF-8 chars (bytes). + * + * @returns iprt status code. + * @param pszLatin1 The Latin-1 string. + * @param cchLatin1 The max string length. Use RTSTR_MAX to process the + * entire string. + * @param pcch Where to store the string length (in bytes). Optional. + * This is undefined on failure. + */ +RTDECL(int) RTLatin1CalcUtf8LenEx(const char *pszLatin1, size_t cchLatin1, size_t *pcch); + +/** + * Calculates the length of the Latin-1 (ISO-8859-1) string in RTUTF16 items. + * + * @returns Number of RTUTF16 items. + * @param pszLatin1 The Latin-1 string. + */ +RTDECL(size_t) RTLatin1CalcUtf16Len(const char *pszLatin1); + +/** + * Calculates the length of the Latin-1 (ISO-8859-1) string in RTUTF16 items. + * + * @returns iprt status code. + * @param pszLatin1 The Latin-1 string. + * @param cchLatin1 The max string length. Use RTSTR_MAX to process the + * entire string. + * @param pcwc Where to store the string length. Optional. + * This is undefined on failure. + */ +RTDECL(int) RTLatin1CalcUtf16LenEx(const char *pszLatin1, size_t cchLatin1, size_t *pcwc); + +/** + * Translate a Latin-1 (ISO-8859-1) string into a UTF-16 allocating the result + * buffer (default tag). + * + * @returns iprt status code. + * @param pszLatin1 The Latin-1 string to convert. + * @param ppwszString Receives pointer to the allocated UTF-16 string. The + * returned string must be freed using RTUtf16Free(). + */ +#define RTLatin1ToUtf16(pszLatin1, ppwszString) RTLatin1ToUtf16Tag((pszLatin1), (ppwszString), RTSTR_TAG) + +/** + * Translate a Latin-1 (ISO-8859-1) string into a UTF-16 allocating the result + * buffer (custom tag). + * + * @returns iprt status code. + * @param pszLatin1 The Latin-1 string to convert. + * @param ppwszString Receives pointer to the allocated UTF-16 string. The + * returned string must be freed using RTUtf16Free(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTLatin1ToUtf16Tag(const char *pszLatin1, PRTUTF16 *ppwszString, const char *pszTag); + +/** + * Translates pszLatin1 from Latin-1 (ISO-8859-1) to UTF-16, allocating the + * result buffer if requested (default tag). + * + * @returns iprt status code. + * @param pszLatin1 The Latin-1 string to convert. + * @param cchLatin1 The maximum size in chars (the type) to convert. The + * conversion stops when it reaches cchLatin1 or the + * string terminator ('\\0'). Use RTSTR_MAX to + * translate the entire string. + * @param ppwsz If cwc is non-zero, this must either be pointing + * to pointer to a buffer of the specified size, or + * pointer to a NULL pointer. + * If *ppwsz is NULL or cwc is zero a buffer of at + * least cwc items will be allocated to hold the + * translated string. If a buffer was requested it + * must be freed using RTUtf16Free(). + * @param cwc The buffer size in RTUTF16s. This includes the + * terminator. + * @param pcwc Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTLatin1ToUtf16Ex(pszLatin1, cchLatin1, ppwsz, cwc, pcwc) \ + RTLatin1ToUtf16ExTag((pszLatin1), (cchLatin1), (ppwsz), (cwc), (pcwc), RTSTR_TAG) + +/** + * Translates pszLatin1 from Latin-1 (ISO-8859-1) to UTF-16, allocating the + * result buffer if requested. + * + * @returns iprt status code. + * @param pszLatin1 The Latin-1 string to convert. + * @param cchLatin1 The maximum size in chars (the type) to convert. The + * conversion stops when it reaches cchLatin1 or the + * string terminator ('\\0'). Use RTSTR_MAX to + * translate the entire string. + * @param ppwsz If cwc is non-zero, this must either be pointing + * to pointer to a buffer of the specified size, or + * pointer to a NULL pointer. + * If *ppwsz is NULL or cwc is zero a buffer of at + * least cwc items will be allocated to hold the + * translated string. If a buffer was requested it + * must be freed using RTUtf16Free(). + * @param cwc The buffer size in RTUTF16s. This includes the + * terminator. + * @param pcwc Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTLatin1ToUtf16ExTag(const char *pszLatin1, size_t cchLatin1, + PRTUTF16 *ppwsz, size_t cwc, size_t *pcwc, const char *pszTag); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_latin1_h */ + diff --git a/include/iprt/ldr.h b/include/iprt/ldr.h new file mode 100644 index 00000000..aa67646e --- /dev/null +++ b/include/iprt/ldr.h @@ -0,0 +1,1340 @@ +/** @file + * IPRT - Loader. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_ldr_h +#define IPRT_INCLUDED_ldr_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + + +/** @defgroup grp_ldr RTLdr - Loader + * @ingroup grp_rt + * @{ + */ + + +RT_C_DECLS_BEGIN + +/** Loader address (unsigned integer). */ +typedef RTUINTPTR RTLDRADDR; +/** Pointer to a loader address. */ +typedef RTLDRADDR *PRTLDRADDR; +/** Pointer to a const loader address. */ +typedef RTLDRADDR const *PCRTLDRADDR; +/** The max loader address value. */ +#define RTLDRADDR_MAX RTUINTPTR_MAX +/** NIL loader address value. */ +#define NIL_RTLDRADDR RTLDRADDR_MAX + + +/** + * Loader module format. + */ +typedef enum RTLDRFMT +{ + /** The usual invalid 0 format. */ + RTLDRFMT_INVALID = 0, + /** The native OS loader. */ + RTLDRFMT_NATIVE, + /** The AOUT loader. */ + RTLDRFMT_AOUT, + /** The ELF loader. */ + RTLDRFMT_ELF, + /** The LX loader. */ + RTLDRFMT_LX, + /** The Mach-O loader. */ + RTLDRFMT_MACHO, + /** The PE loader. */ + RTLDRFMT_PE, + /** The end of the valid format values (exclusive). */ + RTLDRFMT_END, + /** Hack to blow the type up to 32-bit. */ + RTLDRFMT_32BIT_HACK = 0x7fffffff +} RTLDRFMT; + + +/** + * Loader module type. + */ +typedef enum RTLDRTYPE +{ + /** The usual invalid 0 type. */ + RTLDRTYPE_INVALID = 0, + /** Object file. */ + RTLDRTYPE_OBJECT, + /** Executable module, fixed load address. */ + RTLDRTYPE_EXECUTABLE_FIXED, + /** Executable module, relocatable, non-fixed load address. */ + RTLDRTYPE_EXECUTABLE_RELOCATABLE, + /** Executable module, position independent code, non-fixed load address. */ + RTLDRTYPE_EXECUTABLE_PIC, + /** Shared library, fixed load address. + * Typically a system library. */ + RTLDRTYPE_SHARED_LIBRARY_FIXED, + /** Shared library, relocatable, non-fixed load address. */ + RTLDRTYPE_SHARED_LIBRARY_RELOCATABLE, + /** Shared library, position independent code, non-fixed load address. */ + RTLDRTYPE_SHARED_LIBRARY_PIC, + /** DLL that contains no code or data only imports and exports. (Chiefly OS/2.) */ + RTLDRTYPE_FORWARDER_DLL, + /** Core or dump. */ + RTLDRTYPE_CORE, + /** Debug module (debug info with empty code & data segments). */ + RTLDRTYPE_DEBUG_INFO, + /** The end of the valid types values (exclusive). */ + RTLDRTYPE_END, + /** Hack to blow the type up to 32-bit. */ + RTLDRTYPE_32BIT_HACK = 0x7fffffff +} RTLDRTYPE; + + +/** + * Loader endian indicator. + */ +typedef enum RTLDRENDIAN +{ + /** The usual invalid endian. */ + RTLDRENDIAN_INVALID, + /** Little endian. */ + RTLDRENDIAN_LITTLE, + /** Bit endian. */ + RTLDRENDIAN_BIG, + /** Endianness doesn't have a meaning in the context. */ + RTLDRENDIAN_NA, + /** The end of the valid endian values (exclusive). */ + RTLDRENDIAN_END, + /** Hack to blow the type up to 32-bit. */ + RTLDRENDIAN_32BIT_HACK = 0x7fffffff +} RTLDRENDIAN; + + +/** Pointer to a loader reader instance. */ +typedef struct RTLDRREADER *PRTLDRREADER; +/** + * Loader image reader instance. + * + * @remarks The reader will typically have a larger structure wrapping this one + * for storing necessary instance variables. + * + * The loader ASSUMES the caller serializes all access to the + * individual loader module handlers, thus no serialization is required + * when implementing this interface. + */ +typedef struct RTLDRREADER +{ + /** Magic value (RTLDRREADER_MAGIC). */ + uintptr_t uMagic; + + /** + * Reads bytes at a give place in the raw image. + * + * @returns iprt status code. + * @param pReader Pointer to the reader instance. + * @param pvBuf Where to store the bits. + * @param cb Number of bytes to read. + * @param off Where to start reading relative to the start of the raw image. + */ + DECLCALLBACKMEMBER(int, pfnRead,(PRTLDRREADER pReader, void *pvBuf, size_t cb, RTFOFF off)); + + /** + * Tells end position of last read. + * + * @returns position relative to start of the raw image. + * @param pReader Pointer to the reader instance. + */ + DECLCALLBACKMEMBER(RTFOFF, pfnTell,(PRTLDRREADER pReader)); + + /** + * Gets the size of the raw image bits. + * + * @returns size of raw image bits in bytes. + * @param pReader Pointer to the reader instance. + */ + DECLCALLBACKMEMBER(uint64_t, pfnSize,(PRTLDRREADER pReader)); + + /** + * Map the bits into memory. + * + * The mapping will be freed upon calling pfnDestroy() if not pfnUnmap() + * is called before that. The mapping is read only. + * + * @returns iprt status code. + * @param pReader Pointer to the reader instance. + * @param ppvBits Where to store the address of the memory mapping on success. + * The size of the mapping can be obtained by calling pfnSize(). + */ + DECLCALLBACKMEMBER(int, pfnMap,(PRTLDRREADER pReader, const void **ppvBits)); + + /** + * Unmap bits. + * + * @returns iprt status code. + * @param pReader Pointer to the reader instance. + * @param pvBits Memory pointer returned by pfnMap(). + */ + DECLCALLBACKMEMBER(int, pfnUnmap,(PRTLDRREADER pReader, const void *pvBits)); + + /** + * Gets the most appropriate log name. + * + * @returns Pointer to readonly log name. + * @param pReader Pointer to the reader instance. + */ + DECLCALLBACKMEMBER(const char *, pfnLogName,(PRTLDRREADER pReader)); + + /** + * Releases all resources associated with the reader instance. + * The instance is invalid after this call returns. + * + * @returns iprt status code. + * @param pReader Pointer to the reader instance. + */ + DECLCALLBACKMEMBER(int, pfnDestroy,(PRTLDRREADER pReader)); +} RTLDRREADER; + +/** Magic value for RTLDRREADER (Gordon Matthew Thomas Sumner / Sting). */ +#define RTLDRREADER_MAGIC UINT32_C(0x19511002) + + +/** + * Gets the default file suffix for DLL/SO/DYLIB/whatever. + * + * @returns The stuff (readonly). + */ +RTDECL(const char *) RTLdrGetSuff(void); + +/** + * Checks if a library is loadable or not. + * + * This may attempt load and unload the library. + * + * @returns true/false accordingly. + * @param pszFilename Image filename. + */ +RTDECL(bool) RTLdrIsLoadable(const char *pszFilename); + +/** + * Loads a dynamic load library (/shared object) image file using native + * OS facilities. + * + * The filename will be appended the default DLL/SO extension of + * the platform if it have been omitted. This means that it's not + * possible to load DLLs/SOs with no extension using this interface, + * but that's not a bad tradeoff. + * + * If no path is specified in the filename, the OS will usually search it's library + * path to find the image file. + * + * @returns iprt status code. + * @param pszFilename Image filename. + * @param phLdrMod Where to store the handle to the loader module. + */ +RTDECL(int) RTLdrLoad(const char *pszFilename, PRTLDRMOD phLdrMod); + +/** + * Loads a dynamic load library (/shared object) image file using native + * OS facilities. + * + * The filename will be appended the default DLL/SO extension of + * the platform if it have been omitted. This means that it's not + * possible to load DLLs/SOs with no extension using this interface, + * but that's not a bad tradeoff. + * + * If no path is specified in the filename, the OS will usually search it's library + * path to find the image file. + * + * @returns iprt status code. + * @param pszFilename Image filename. + * @param phLdrMod Where to store the handle to the loader module. + * @param fFlags See RTLDRLOAD_FLAGS_XXX. + * @param pErrInfo Where to return extended error information. Optional. + */ +RTDECL(int) RTLdrLoadEx(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo); + +/** @defgroup RTLDRLOAD_FLAGS_XXX Flags for RTLdrLoadEx, RTLdrLoadSystemEx and RTLdrGetSystemSymbolEx + * @{ */ +/** Symbols defined in this library are not made available to resolve + * references in subsequently loaded libraries (default). */ +#define RTLDRLOAD_FLAGS_LOCAL UINT32_C(0) +/** Symbols defined in this library will be made available for symbol + * resolution of subsequently loaded libraries. */ +#define RTLDRLOAD_FLAGS_GLOBAL RT_BIT_32(0) +/** Do not unload the library upon RTLdrClose. (For system libs.) */ +#define RTLDRLOAD_FLAGS_NO_UNLOAD RT_BIT_32(1) +/** Windows/NT: Search the DLL load directory for imported DLLs - W7, + * Vista, and W2K8 requires KB2533623 to be installed to support this; not + * supported on XP, W2K3 or earlier. Ignored on other platforms. */ +#define RTLDRLOAD_FLAGS_NT_SEARCH_DLL_LOAD_DIR RT_BIT_32(2) +/** Do not append default suffix. */ +#define RTLDRLOAD_FLAGS_NO_SUFFIX RT_BIT_32(3) +/** Shift for the first .so.MAJOR version number to try. + * Only applicable to RTLdrLoadSystemEx() and RTLdrGetSystemSymbolEx(). */ +#define RTLDRLOAD_FLAGS_SO_VER_BEGIN_SHIFT 12 +/** Mask for the first .so.MAJOR version number to try. + * Only applicable to RTLdrLoadSystemEx() and RTLdrGetSystemSymbolEx(). */ +#define RTLDRLOAD_FLAGS_SO_VER_BEGIN_MASK UINT32_C(0x003ff000) +/** Shift for the end .so.MAJOR version number (exclusive). + * Only applicable to RTLdrLoadSystemEx() and RTLdrGetSystemSymbolEx(). */ +#define RTLDRLOAD_FLAGS_SO_VER_END_SHIFT 22 +/** Mask for the end .so.MAJOR version number (exclusive). + * Only applicable to RTLdrLoadSystemEx() and RTLdrGetSystemSymbolEx(). */ +#define RTLDRLOAD_FLAGS_SO_VER_END_MASK UINT32_C(0xffc00000) +/** Specifies the range for the .so.MAJOR version number. + * Only applicable to RTLdrLoadSystemEx() and RTLdrGetSystemSymbolEx(). + * Ignored on systems not using .so. + * @param a_uBegin The first version to try. + * @param a_uEnd The version number to stop at (exclusive). + */ +#define RTLDRLOAD_FLAGS_SO_VER_RANGE(a_uBegin, a_uEnd) \ + ( ((a_uBegin) << RTLDRLOAD_FLAGS_SO_VER_BEGIN_SHIFT) | ((a_uEnd) << RTLDRLOAD_FLAGS_SO_VER_END_SHIFT) ) +/** The mask of valid flag bits. + * The shared object major version range is excluded. */ +#define RTLDRLOAD_FLAGS_VALID_MASK UINT32_C(0x0000000f) +/** @} */ + +/** + * Loads a dynamic load library (/shared object) image file residing in one of + * the default system library locations. + * + * Only the system library locations are searched. No suffix is required. + * + * @returns iprt status code. + * @param pszFilename Image filename. No path. + * @param fNoUnload Do not unload the library when RTLdrClose is called. + * @param phLdrMod Where to store the handle to the loaded module. + */ +RTDECL(int) RTLdrLoadSystem(const char *pszFilename, bool fNoUnload, PRTLDRMOD phLdrMod); + +/** + * Loads a dynamic load library (/shared object) image file residing in one of + * the default system library locations, extended version. + * + * Only the system library locations are searched. No suffix is required. + * + * @returns iprt status code. + * @param pszFilename Image filename. No path. + * @param fFlags RTLDRLOAD_FLAGS_XXX, including RTLDRLOAD_FLAGS_SO_VER_XXX. + * @param phLdrMod Where to store the handle to the loaded module. + */ +RTDECL(int) RTLdrLoadSystemEx(const char *pszFilename, uint32_t fFlags, PRTLDRMOD phLdrMod); + +/** + * Combines RTLdrLoadSystem and RTLdrGetSymbol, with fNoUnload set to true. + * + * @returns The symbol value, NULL on failure. (If you care for a less boolean + * status, go thru the necessary API calls yourself.) + * @param pszFilename Image filename. No path. + * @param pszSymbol Symbol name. + */ +RTDECL(void *) RTLdrGetSystemSymbol(const char *pszFilename, const char *pszSymbol); + +/** + * Combines RTLdrLoadSystemEx and RTLdrGetSymbol. + * + * @returns The symbol value, NULL on failure. (If you care for a less boolean + * status, go thru the necessary API calls yourself.) + * @param pszFilename Image filename. No path. + * @param pszSymbol Symbol name. + * @param fFlags RTLDRLOAD_FLAGS_XXX, including RTLDRLOAD_FLAGS_SO_VER_XXX. + */ +RTDECL(void *) RTLdrGetSystemSymbolEx(const char *pszFilename, const char *pszSymbol, uint32_t fFlags); + +/** + * Loads a dynamic load library (/shared object) image file residing in the + * RTPathAppPrivateArch() directory. + * + * Suffix is not required. + * + * @returns iprt status code. + * @param pszFilename Image filename. No path. + * @param phLdrMod Where to store the handle to the loaded module. + */ +RTDECL(int) RTLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod); + +/** + * Gets the native module handle for a module loaded by RTLdrLoad, RTLdrLoadEx, + * RTLdrLoadSystem, or RTLdrLoadAppPriv. + * + * @returns Native handle on success, ~(uintptr_t)0 on failure. + * @param hLdrMod The loader module handle. + */ +RTDECL(uintptr_t) RTLdrGetNativeHandle(RTLDRMOD hLdrMod); + + +/** + * Image architecuture specifier for RTLdrOpenEx. + */ +typedef enum RTLDRARCH +{ + RTLDRARCH_INVALID = 0, + /** Whatever. */ + RTLDRARCH_WHATEVER, + /** The host architecture. */ + RTLDRARCH_HOST, + /** 16-bit x86. */ + RTLDRARCH_X86_16, + /** 32-bit x86. */ + RTLDRARCH_X86_32, + /** AMD64 (64-bit x86 if you like). */ + RTLDRARCH_AMD64, + /** 32-bit ARM. */ + RTLDRARCH_ARM32, + /** 64-bit ARM. */ + RTLDRARCH_ARM64, + /** End of the valid values. */ + RTLDRARCH_END, + /** Make sure the type is a full 32-bit. */ + RTLDRARCH_32BIT_HACK = 0x7fffffff +} RTLDRARCH; +/** Pointer to a RTLDRARCH. */ +typedef RTLDRARCH *PRTLDRARCH; + +/** + * Translates a RTLDRARCH value to a string. + * + * @returns Name corresponding to @a enmArch + * @param enmArch The value to name. + */ +RTDECL(const char *) RTLdrArchName(RTLDRARCH enmArch); + +/** + * Returns the host architecture. + * + * @returns Host architecture or RTLDRARCH_WHATEVER if no match. + */ +RTDECL(RTLDRARCH) RTLdrGetHostArch(void); + + +/** @name RTLDR_O_XXX - RTLdrOpen flags. + * @{ */ +/** Open for debugging or introspection reasons. + * This will skip a few of the stricter validations when loading images. */ +#define RTLDR_O_FOR_DEBUG RT_BIT_32(0) +/** Open for signature validation. */ +#define RTLDR_O_FOR_VALIDATION RT_BIT_32(1) +/** The arch specification is just a guideline for FAT binaries. */ +#define RTLDR_O_WHATEVER_ARCH RT_BIT_32(2) +/** Ignore the architecture specification if there is no code. */ +#define RTLDR_O_IGNORE_ARCH_IF_NO_CODE RT_BIT_32(3) +/** Mach-O: Include the __LINKEDIT segment (ignored by the others). */ +#define RTLDR_O_MACHO_LOAD_LINKEDIT RT_BIT_32(4) +/** Mask of valid flags. */ +#define RTLDR_O_VALID_MASK UINT32_C(0x0000001f) +/** @} */ + +/** + * Open a binary image file. + * + * @returns iprt status code. + * @param pszFilename Image filename. + * @param fFlags Valid RTLDR_O_XXX combination. + * @param enmArch CPU architecture specifier for the image to be loaded. + * @param phLdrMod Where to store the handle to the loader module. + */ +RTDECL(int) RTLdrOpen(const char *pszFilename, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod); + +/** + * Open a binary image file, extended version. + * + * @returns iprt status code. + * @param pszFilename Image filename. + * @param fFlags Valid RTLDR_O_XXX combination. + * @param enmArch CPU architecture specifier for the image to be loaded. + * @param phLdrMod Where to store the handle to the loader module. + * @param pErrInfo Where to return extended error information. Optional. + */ +RTDECL(int) RTLdrOpenEx(const char *pszFilename, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo); + +/** + * Open a binary image file allowing VFS chains in the filename. + * + * @returns iprt status code. + * @param pszFilename Image filename, VFS chain specifiers allowed. + * @param fFlags Valid RTLDR_O_XXX combination. + * @param enmArch CPU architecture specifier for the image to be loaded. + * @param phLdrMod Where to store the handle to the loader module. + * @param poffError Where to return the offset into @a pszFilename of an VFS + * chain element causing trouble. Optional. + * @param pErrInfo Where to return extended error information. Optional. + */ +RTDECL(int) RTLdrOpenVfsChain(const char *pszFilename, uint32_t fFlags, RTLDRARCH enmArch, + PRTLDRMOD phLdrMod, uint32_t *poffError, PRTERRINFO pErrInfo); + +/** + * Open part with reader. + * + * @returns iprt status code. + * @param pReader The loader reader instance which will provide the raw + * image bits. The reader instance will be consumed on + * success. On failure, the caller has to do the cleaning + * up. + * @param fFlags Valid RTLDR_O_XXX combination. + * @param enmArch Architecture specifier. + * @param phMod Where to store the handle. + * @param pErrInfo Where to return extended error information. Optional. + */ +RTDECL(int) RTLdrOpenWithReader(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phMod, PRTERRINFO pErrInfo); + +/** + * Called to read @a cb bytes at @a off into @a pvBuf. + * + * @returns IPRT status code + * @param pvBuf The output buffer. + * @param cb The number of bytes to read. + * @param off Where to start reading. + * @param pvUser The user parameter. + */ +typedef DECLCALLBACKTYPE(int, FNRTLDRRDRMEMREAD,(void *pvBuf, size_t cb, size_t off, void *pvUser)); +/** Pointer to a RTLdrOpenInMemory reader callback. */ +typedef FNRTLDRRDRMEMREAD *PFNRTLDRRDRMEMREAD; + +/** + * Called to when the module is unloaded (or done loading) to release resources + * associated with it (@a pvUser). + * + * @returns IPRT status code + * @param pvUser The user parameter. + * @param cbImage The image size. + */ +typedef DECLCALLBACKTYPE(void, FNRTLDRRDRMEMDTOR,(void *pvUser, size_t cbImage)); +/** Pointer to a RTLdrOpenInMemory destructor callback. */ +typedef FNRTLDRRDRMEMDTOR *PFNRTLDRRDRMEMDTOR; + +/** + * Open a in-memory image or an image with a custom reader callback. + * + * @returns IPRT status code. + * @param pszName The image name. + * @param fFlags Valid RTLDR_O_XXX combination. + * @param enmArch CPU architecture specifier for the image to be loaded. + * @param cbImage The size of the image (fake file). + * @param pfnRead The read function. If NULL is passed in, a default + * reader function is provided that assumes @a pvUser + * points to the raw image bits, at least @a cbImage of + * valid memory. + * @param pfnDtor The destructor function. If NULL is passed, a default + * destructor will be provided that passes @a pvUser to + * RTMemFree. + * @param pvUser The user argument or, if any of the callbacks are NULL, + * a pointer to a memory block. + * @param phLdrMod Where to return the module handle. + * @param pErrInfo Pointer to an error info buffer, optional. + * + * @remarks With the exception of invalid @a pfnDtor and/or @a pvUser + * parameters, the pfnDtor methods (or the default one if NULL) will + * always be invoked. The destruction of pvUser is entirely in the + * hands of this method once it's called. + */ +RTDECL(int) RTLdrOpenInMemory(const char *pszName, uint32_t fFlags, RTLDRARCH enmArch, size_t cbImage, + PFNRTLDRRDRMEMREAD pfnRead, PFNRTLDRRDRMEMDTOR pfnDtor, void *pvUser, + PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo); + +/** + * Closes a loader module handle. + * + * The handle can be obtained using any of the RTLdrLoad(), RTLdrOpen() + * and RTLdrOpenInMemory() functions. + * + * @returns iprt status code. + * @param hLdrMod The loader module handle. + */ +RTDECL(int) RTLdrClose(RTLDRMOD hLdrMod); + +/** + * Gets the address of a named exported symbol. + * + * @returns iprt status code. + * @retval VERR_LDR_FORWARDER forwarder, use pfnQueryForwarderInfo. Buffer size + * hint in @a ppvValue. + * @param hLdrMod The loader module handle. + * @param pszSymbol Symbol name. + * @param ppvValue Where to store the symbol value. Note that this is restricted to the + * pointer size used on the host! + */ +RTDECL(int) RTLdrGetSymbol(RTLDRMOD hLdrMod, const char *pszSymbol, void **ppvValue); + +/** + * Gets the address of a named exported symbol. + * + * This function differs from the plain one in that it can deal with + * both GC and HC address sizes, and that it can calculate the symbol + * value relative to any given base address. + * + * @returns iprt status code. + * @retval VERR_LDR_FORWARDER forwarder, use pfnQueryForwarderInfo. Buffer size + * hint in @a pValue. + * @param hLdrMod The loader module handle. + * @param pvBits Optional pointer to the loaded image. + * Set this to NULL if no RTLdrGetBits() processed image bits are available. + * Not supported for RTLdrLoad() images. + * @param BaseAddress Image load address. + * Not supported for RTLdrLoad() images. + * @param iOrdinal Symbol ordinal number, pass UINT32_MAX if pszSymbol + * should be used instead. + * @param pszSymbol Symbol name. + * @param pValue Where to store the symbol value. + */ +RTDECL(int) RTLdrGetSymbolEx(RTLDRMOD hLdrMod, const void *pvBits, RTLDRADDR BaseAddress, + uint32_t iOrdinal, const char *pszSymbol, PRTLDRADDR pValue); + +/** + * Gets the address of a named exported function. + * + * Same as RTLdrGetSymbol, but skips the status code and pointer to return + * variable stuff. + * + * @returns Pointer to the function if found, NULL if not. + * @param hLdrMod The loader module handle. + * @param pszSymbol Function name. + */ +RTDECL(PFNRT) RTLdrGetFunction(RTLDRMOD hLdrMod, const char *pszSymbol); + +/** + * Information about an imported symbol. + */ +typedef struct RTLDRIMPORTINFO +{ + /** Symbol table entry number, UINT32_MAX if not available. */ + uint32_t iSelfOrdinal; + /** The ordinal of the imported symbol in szModule, UINT32_MAX if not used. */ + uint32_t iOrdinal; + /** The symbol name, NULL if not used. This points to the char immediately + * following szModule when returned by RTLdrQueryForwarderInfo. */ + const char *pszSymbol; + /** The name of the module being imported from. */ + char szModule[1]; +} RTLDRIMPORTINFO; +/** Pointer to information about an imported symbol. */ +typedef RTLDRIMPORTINFO *PRTLDRIMPORTINFO; +/** Pointer to const information about an imported symbol. */ +typedef RTLDRIMPORTINFO const *PCRTLDRIMPORTINFO; + +/** + * Query information about a forwarded symbol. + * + * @returns IPRT status code. + * @param hLdrMod The loader module handle. + * @param pvBits Optional pointer to the loaded image. + * Set this to NULL if no RTLdrGetBits() processed image bits are available. + * Not supported for RTLdrLoad() images. + * @param iOrdinal Symbol ordinal number, pass UINT32_MAX if pszSymbol + * should be used instead. + * @param pszSymbol Symbol name. + * @param pInfo Where to return the forwarder info. + * @param cbInfo Size of the buffer @a pInfo points to. For a size + * hint, see @a pValue when RTLdrGetSymbolEx returns + * VERR_LDR_FORWARDER. + */ +RTDECL(int) RTLdrQueryForwarderInfo(RTLDRMOD hLdrMod, const void *pvBits, uint32_t iOrdinal, const char *pszSymbol, + PRTLDRIMPORTINFO pInfo, size_t cbInfo); + + +/** + * Gets the size of the loaded image. + * + * This is not necessarily available for images that has been loaded using + * RTLdrLoad(). + * + * @returns image size (in bytes). + * @returns ~(size_t)0 on if not available. + * @param hLdrMod Handle to the loader module. + */ +RTDECL(size_t) RTLdrSize(RTLDRMOD hLdrMod); + +/** + * Resolve an external symbol during RTLdrGetBits(). + * + * @returns iprt status code. + * @param hLdrMod The loader module handle. + * @param pszModule Module name. + * @param pszSymbol Symbol name, NULL if uSymbol should be used. + * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used. + * @param pValue Where to store the symbol value (address). + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTLDRIMPORT,(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, + PRTLDRADDR pValue, void *pvUser)); +/** Pointer to a FNRTLDRIMPORT() callback function. */ +typedef FNRTLDRIMPORT *PFNRTLDRIMPORT; + +/** + * Loads the image into a buffer provided by the user and applies fixups + * for the given base address. + * + * @returns iprt status code. + * @param hLdrMod The load module handle. + * @param pvBits Where to put the bits. + * Must be as large as RTLdrSize() suggests. + * @param BaseAddress The base address. + * @param pfnGetImport Callback function for resolving imports one by one. + * @param pvUser User argument for the callback. + * @remark Not supported for RTLdrLoad() images. + */ +RTDECL(int) RTLdrGetBits(RTLDRMOD hLdrMod, void *pvBits, RTLDRADDR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser); + +/** + * Relocates bits after getting them. + * Useful for code which moves around a bit. + * + * @returns iprt status code. + * @param hLdrMod The loader module handle. + * @param pvBits Where the image bits are. + * Must have been passed to RTLdrGetBits(). + * @param NewBaseAddress The new base address. + * @param OldBaseAddress The old base address. + * @param pfnGetImport Callback function for resolving imports one by one. + * @param pvUser User argument for the callback. + * @remark Not supported for RTLdrLoad() images. + */ +RTDECL(int) RTLdrRelocate(RTLDRMOD hLdrMod, void *pvBits, RTLDRADDR NewBaseAddress, RTLDRADDR OldBaseAddress, + PFNRTLDRIMPORT pfnGetImport, void *pvUser); + +/** + * Enumeration callback function used by RTLdrEnumSymbols(). + * + * @returns iprt status code. Failure will stop the enumeration. + * @param hLdrMod The loader module handle. + * @param pszSymbol Symbol name. NULL if ordinal only. + * @param uSymbol Symbol ordinal, ~0 if not used. + * @param Value Symbol value. + * @param pvUser The user argument specified to RTLdrEnumSymbols(). + */ +typedef DECLCALLBACKTYPE(int, FNRTLDRENUMSYMS,(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTLDRADDR Value, void *pvUser)); +/** Pointer to a FNRTLDRENUMSYMS() callback function. */ +typedef FNRTLDRENUMSYMS *PFNRTLDRENUMSYMS; + +/** + * Enumerates all symbols in a module. + * + * @returns iprt status code. + * @param hLdrMod The loader module handle. + * @param fFlags Flags indicating what to return and such. + * @param pvBits Optional pointer to the loaded image. (RTLDR_ENUM_SYMBOL_FLAGS_*) + * Set this to NULL if no RTLdrGetBits() processed image bits are available. + * @param BaseAddress Image load address. + * @param pfnCallback Callback function. + * @param pvUser User argument for the callback. + * @remark Not supported for RTLdrLoad() images. + */ +RTDECL(int) RTLdrEnumSymbols(RTLDRMOD hLdrMod, unsigned fFlags, const void *pvBits, RTLDRADDR BaseAddress, PFNRTLDRENUMSYMS pfnCallback, void *pvUser); + +/** @name RTLdrEnumSymbols flags. + * @{ */ +/** Returns ALL kinds of symbols. The default is to only return public/exported symbols. */ +#define RTLDR_ENUM_SYMBOL_FLAGS_ALL RT_BIT(1) +/** Ignore forwarders rather than reporting them with RTLDR_ENUM_SYMBOL_FWD_ADDRESS as value. */ +#define RTLDR_ENUM_SYMBOL_FLAGS_NO_FWD RT_BIT(2) +/** @} */ + +/** Special symbol for forwarder symbols, since they cannot be resolved with + * the current API. */ +#if (HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64) +# define RTLDR_ENUM_SYMBOL_FWD_ADDRESS UINT64_C(0xff4242fffd4242fd) +#else +# define RTLDR_ENUM_SYMBOL_FWD_ADDRESS UINT32_C(0xff4242fd) +#endif + + +/** + * Debug info type (as far the loader can tell). + */ +typedef enum RTLDRDBGINFOTYPE +{ + /** The invalid 0 value. */ + RTLDRDBGINFOTYPE_INVALID = 0, + /** Unknown debug info format. */ + RTLDRDBGINFOTYPE_UNKNOWN, + /** Stabs. */ + RTLDRDBGINFOTYPE_STABS, + /** Debug With Arbitrary Record Format (DWARF). */ + RTLDRDBGINFOTYPE_DWARF, + /** Debug With Arbitrary Record Format (DWARF), in external file (DWO). */ + RTLDRDBGINFOTYPE_DWARF_DWO, + /** Microsoft Codeview debug info. */ + RTLDRDBGINFOTYPE_CODEVIEW, + /** Microsoft Codeview debug info, in external v2.0+ program database (PDB). */ + RTLDRDBGINFOTYPE_CODEVIEW_PDB20, + /** Microsoft Codeview debug info, in external v7.0+ program database (PDB). */ + RTLDRDBGINFOTYPE_CODEVIEW_PDB70, + /** Microsoft Codeview debug info, in external file (DBG). */ + RTLDRDBGINFOTYPE_CODEVIEW_DBG, + /** Microsoft COFF debug info. */ + RTLDRDBGINFOTYPE_COFF, + /** Watcom debug info. */ + RTLDRDBGINFOTYPE_WATCOM, + /** IBM High Level Language debug info. */ + RTLDRDBGINFOTYPE_HLL, + /** The end of the valid debug info values (exclusive). */ + RTLDRDBGINFOTYPE_END, + /** Blow the type up to 32-bits. */ + RTLDRDBGINFOTYPE_32BIT_HACK = 0x7fffffff +} RTLDRDBGINFOTYPE; + + +/** + * Debug info details for the enumeration callback. + */ +typedef struct RTLDRDBGINFO +{ + /** The kind of debug info. */ + RTLDRDBGINFOTYPE enmType; + /** The debug info ordinal number / id. */ + uint32_t iDbgInfo; + /** The file offset *if* this type has one specific location in the executable + * image file. This is -1 if there isn't any specific file location. */ + RTFOFF offFile; + /** The link address of the debug info if it's loadable. NIL_RTLDRADDR if not + * loadable*/ + RTLDRADDR LinkAddress; + /** The size of the debug information. -1 is used if this isn't applicable.*/ + RTLDRADDR cb; + /** This is set if the debug information is found in an external file. NULL + * if no external file involved. + * @note Putting it outside the union to allow lazy callback implementation. */ + const char *pszExtFile; + /** Type (enmType) specific information. */ + union + { + /** RTLDRDBGINFOTYPE_DWARF */ + struct + { + /** The section name. */ + const char *pszSection; + } Dwarf; + + /** RTLDRDBGINFOTYPE_DWARF_DWO */ + struct + { + /** The CRC32 of the external file. */ + uint32_t uCrc32; + } Dwo; + + /** RTLDRDBGINFOTYPE_CODEVIEW, RTLDRDBGINFOTYPE_COFF */ + struct + { + /** The PE image size. */ + uint32_t cbImage; + /** The timestamp. */ + uint32_t uTimestamp; + /** The major version from the entry. */ + uint32_t uMajorVer; + /** The minor version from the entry. */ + uint32_t uMinorVer; + } Cv, Coff; + + /** RTLDRDBGINFOTYPE_CODEVIEW_DBG */ + struct + { + /** The PE image size. */ + uint32_t cbImage; + /** The timestamp. */ + uint32_t uTimestamp; + } Dbg; + + /** RTLDRDBGINFOTYPE_CODEVIEW_PDB20*/ + struct + { + /** The PE image size. */ + uint32_t cbImage; + /** The timestamp. */ + uint32_t uTimestamp; + /** The PDB age. */ + uint32_t uAge; + } Pdb20; + + /** RTLDRDBGINFOTYPE_CODEVIEW_PDB70 */ + struct + { + /** The PE image size. */ + uint32_t cbImage; + /** The PDB age. */ + uint32_t uAge; + /** The UUID. */ + RTUUID Uuid; + } Pdb70; + } u; +} RTLDRDBGINFO; +/** Pointer to debug info details. */ +typedef RTLDRDBGINFO *PRTLDRDBGINFO; +/** Pointer to read only debug info details. */ +typedef RTLDRDBGINFO const *PCRTLDRDBGINFO; + + +/** + * Debug info enumerator callback. + * + * @returns VINF_SUCCESS to continue the enumeration. Any other status code + * will cause RTLdrEnumDbgInfo to immediately return with that status. + * + * @param hLdrMod The module handle. + * @param pDbgInfo Pointer to a read only structure with the details. + * @param pvUser The user parameter specified to RTLdrEnumDbgInfo. + */ +typedef DECLCALLBACKTYPE(int, FNRTLDRENUMDBG,(RTLDRMOD hLdrMod, PCRTLDRDBGINFO pDbgInfo, void *pvUser)); +/** Pointer to a debug info enumerator callback. */ +typedef FNRTLDRENUMDBG *PFNRTLDRENUMDBG; + +/** + * Enumerate the debug info contained in the executable image. + * + * @returns IPRT status code or whatever pfnCallback returns. + * + * @param hLdrMod The module handle. + * @param pvBits Optional pointer to bits returned by + * RTLdrGetBits(). This can be used by some module + * interpreters to reduce memory consumption. + * @param pfnCallback The callback function. + * @param pvUser The user argument. + */ +RTDECL(int) RTLdrEnumDbgInfo(RTLDRMOD hLdrMod, const void *pvBits, PFNRTLDRENUMDBG pfnCallback, void *pvUser); + + +/** + * Loader segment. + */ +typedef struct RTLDRSEG +{ + /** The segment name. Always set to something. */ + const char *pszName; + /** The length of the segment name. */ + uint32_t cchName; + /** The flat selector to use for the segment (i.e. data/code). + * Primarily a way for the user to specify selectors for the LX/LE and NE interpreters. */ + uint16_t SelFlat; + /** The 16-bit selector to use for the segment. + * Primarily a way for the user to specify selectors for the LX/LE and NE interpreters. */ + uint16_t Sel16bit; + /** Segment flags. */ + uint32_t fFlags; + /** The segment protection (RTMEM_PROT_XXX). */ + uint32_t fProt; + /** The size of the segment. */ + RTLDRADDR cb; + /** The required segment alignment. + * The to 0 if the segment isn't supposed to be mapped. */ + RTLDRADDR Alignment; + /** The link address. + * Set to NIL_RTLDRADDR if the segment isn't supposed to be mapped or if + * the image doesn't have link addresses. */ + RTLDRADDR LinkAddress; + /** File offset of the segment. + * Set to -1 if no file backing (like BSS). */ + RTFOFF offFile; + /** Size of the file bits of the segment. + * Set to -1 if no file backing (like BSS). */ + RTFOFF cbFile; + /** The relative virtual address when mapped. + * Set to NIL_RTLDRADDR if the segment isn't supposed to be mapped. */ + RTLDRADDR RVA; + /** The size of the segment including the alignment gap up to the next segment when mapped. + * This is set to NIL_RTLDRADDR if not implemented. */ + RTLDRADDR cbMapped; +} RTLDRSEG; +/** Pointer to a loader segment. */ +typedef RTLDRSEG *PRTLDRSEG; +/** Pointer to a read only loader segment. */ +typedef RTLDRSEG const *PCRTLDRSEG; + + +/** @name Segment flags + * @{ */ +/** The segment is 16-bit. When not set the default of the target architecture is assumed. */ +#define RTLDRSEG_FLAG_16BIT UINT32_C(1) +/** The segment requires a 16-bit selector alias. (OS/2) */ +#define RTLDRSEG_FLAG_OS2_ALIAS16 UINT32_C(2) +/** Conforming segment (x86 weirdness). (OS/2) */ +#define RTLDRSEG_FLAG_OS2_CONFORM UINT32_C(4) +/** IOPL (ring-2) segment. (OS/2) */ +#define RTLDRSEG_FLAG_OS2_IOPL UINT32_C(8) +/** @} */ + +/** + * Segment enumerator callback. + * + * @returns VINF_SUCCESS to continue the enumeration. Any other status code + * will cause RTLdrEnumSegments to immediately return with that + * status. + * + * @param hLdrMod The module handle. + * @param pSeg The segment information. + * @param pvUser The user parameter specified to RTLdrEnumSegments. + */ +typedef DECLCALLBACKTYPE(int, FNRTLDRENUMSEGS,(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)); +/** Pointer to a segment enumerator callback. */ +typedef FNRTLDRENUMSEGS *PFNRTLDRENUMSEGS; + +/** + * Enumerate the debug info contained in the executable image. + * + * @returns IPRT status code or whatever pfnCallback returns. + * + * @param hLdrMod The module handle. + * @param pfnCallback The callback function. + * @param pvUser The user argument. + */ +RTDECL(int) RTLdrEnumSegments(RTLDRMOD hLdrMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser); + +/** + * Converts a link address to a segment:offset address. + * + * @returns IPRT status code. + * + * @param hLdrMod The module handle. + * @param LinkAddress The link address to convert. + * @param piSeg Where to return the segment index. + * @param poffSeg Where to return the segment offset. + */ +RTDECL(int) RTLdrLinkAddressToSegOffset(RTLDRMOD hLdrMod, RTLDRADDR LinkAddress, uint32_t *piSeg, PRTLDRADDR poffSeg); + +/** + * Converts a link address to an image relative virtual address (RVA). + * + * @returns IPRT status code. + * + * @param hLdrMod The module handle. + * @param LinkAddress The link address to convert. + * @param pRva Where to return the RVA. + */ +RTDECL(int) RTLdrLinkAddressToRva(RTLDRMOD hLdrMod, RTLDRADDR LinkAddress, PRTLDRADDR pRva); + +/** + * Converts an image relative virtual address (RVA) to a segment:offset. + * + * @returns IPRT status code. + * + * @param hLdrMod The module handle. + * @param iSeg The segment index. + * @param offSeg The segment offset. + * @param pRva Where to return the RVA. + */ +RTDECL(int) RTLdrSegOffsetToRva(RTLDRMOD hLdrMod, uint32_t iSeg, RTLDRADDR offSeg, PRTLDRADDR pRva); + +/** + * Converts a segment:offset into an image relative virtual address (RVA). + * + * @returns IPRT status code. + * + * @param hLdrMod The module handle. + * @param Rva The link address to convert. + * @param piSeg Where to return the segment index. + * @param poffSeg Where to return the segment offset. + */ +RTDECL(int) RTLdrRvaToSegOffset(RTLDRMOD hLdrMod, RTLDRADDR Rva, uint32_t *piSeg, PRTLDRADDR poffSeg); + +/** + * Gets the image format. + * + * @returns Valid image format on success. RTLDRFMT_INVALID on invalid handle or + * other errors. + * @param hLdrMod The module handle. + */ +RTDECL(RTLDRFMT) RTLdrGetFormat(RTLDRMOD hLdrMod); + +/** + * Gets the image type. + * + * @returns Valid image type value on success. RTLDRTYPE_INVALID on + * invalid handle or other errors. + * @param hLdrMod The module handle. + */ +RTDECL(RTLDRTYPE) RTLdrGetType(RTLDRMOD hLdrMod); + +/** + * Gets the image endian-ness. + * + * @returns Valid image endian value on success. RTLDRENDIAN_INVALID on invalid + * handle or other errors. + * @param hLdrMod The module handle. + */ +RTDECL(RTLDRENDIAN) RTLdrGetEndian(RTLDRMOD hLdrMod); + +/** + * Gets the image endian-ness. + * + * @returns Valid image architecture value on success. + * RTLDRARCH_INVALID on invalid handle or other errors. + * @param hLdrMod The module handle. + */ +RTDECL(RTLDRARCH) RTLdrGetArch(RTLDRMOD hLdrMod); + +/** + * Loader properties that can be queried thru RTLdrQueryProp. + */ +typedef enum RTLDRPROP +{ + RTLDRPROP_INVALID = 0, + /** The image UUID (Mach-O). + * Returns a RTUUID in the buffer. */ + RTLDRPROP_UUID, + /** The image timestamp in seconds, genrally since unix epoc. + * Returns a 32-bit or 64-bit signed integer value in the buffer. */ + RTLDRPROP_TIMESTAMP_SECONDS, + /** Checks if the image is signed. + * Returns a bool. */ + RTLDRPROP_IS_SIGNED, + /** Retrives the PKCS \#7 SignedData blob that signs the image. + * Returns variable sized buffer containing the ASN.1 BER encoding. + * + * @remarks This generally starts with a PKCS \#7 Content structure, the + * SignedData bit is found a few levels down into this as per RFC. */ + RTLDRPROP_PKCS7_SIGNED_DATA, + /** Query the number of pages that needs hashing. + * This is for RTLDRPROP_SHA1_PAGE_HASHES and RTLDRPROP_SHA256_PAGE_HASHES + * buffer size calculations. */ + RTLDRPROP_HASHABLE_PAGES, + /** Query the SHA-1 page hashes. + * Returns an array with entries made of a 32-bit file offset and a SHA-1 + * digest. Use RTLDRPROP_HASHABLE_PAGES to calculate the buffer size. */ + RTLDRPROP_SHA1_PAGE_HASHES, + /** Query the SHA-256 page hashes. + * Returns an array with entries made of a 32-bit file offset and a SHA-256 + * digest. Use RTLDRPROP_HASHABLE_PAGES to calculate the buffer size. */ + RTLDRPROP_SHA256_PAGE_HASHES, + + /** Query whether code signature checks are enabled. */ + RTLDRPROP_SIGNATURE_CHECKS_ENFORCED, + + /** Number of import or needed modules. */ + RTLDRPROP_IMPORT_COUNT, + /** Import module by index (32-bit) stored in the buffer. */ + RTLDRPROP_IMPORT_MODULE, + /** The file offset of the main executable header. + * This is mainly for PE, NE and LX headers, but also Mach-O FAT. */ + RTLDRPROP_FILE_OFF_HEADER, + /** The internal module name. + * This is the SONAME for ELF, export table name for PE, and zero'th resident + * name table entry for LX. + * Returns zero terminated string. */ + RTLDRPROP_INTERNAL_NAME, + /** The raw unwind table if available. + * For PE this means IMAGE_DIRECTORY_ENTRY_EXCEPTION content, for AMD64 this + * is the lookup table (IMAGE_RUNTIME_FUNCTION_ENTRY). + * Not implemented any others yet. */ + RTLDRPROP_UNWIND_TABLE, + /** Read unwind info at given RVA and up to buffer size. The RVA is stored + * as uint32_t in the buffer when making the call. + * This is only implemented for PE. */ + RTLDRPROP_UNWIND_INFO, + /** The image build-id (ELF/GNU). + * Returns usually a SHA1 checksum in the buffer. */ + RTLDRPROP_BUILDID, + + /** End of valid properties. */ + RTLDRPROP_END, + /** Blow the type up to 32 bits. */ + RTLDRPROP_32BIT_HACK = 0x7fffffff +} RTLDRPROP; + +/** + * Generic method for querying image properties. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the property query isn't supported (either all + * or that specific property). The caller must handle this result. + * @retval VERR_NOT_FOUND the property was not found in the module. The caller + * must also normally deal with this. + * @retval VERR_INVALID_FUNCTION if the function value is wrong. + * @retval VERR_INVALID_PARAMETER if the buffer size is wrong. + * @retval VERR_BUFFER_OVERFLOW if the function doesn't have a fixed size + * buffer and the buffer isn't big enough. Use RTLdrQueryPropEx. + * @retval VERR_INVALID_HANDLE if the handle is invalid. + * + * @param hLdrMod The module handle. + * @param enmProp The property to query. + * @param pvBuf Pointer to the input / output buffer. In most cases + * it's only used for returning data. + * @param cbBuf The size of the buffer. + */ +RTDECL(int) RTLdrQueryProp(RTLDRMOD hLdrMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf); + +/** + * Generic method for querying image properties, extended version. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the property query isn't supported (either all + * or that specific property). The caller must handle this result. + * @retval VERR_NOT_FOUND the property was not found in the module. The caller + * must also normally deal with this. + * @retval VERR_INVALID_FUNCTION if the function value is wrong. + * @retval VERR_INVALID_PARAMETER if the fixed buffer size is wrong. Correct + * size in @a *pcbRet. + * @retval VERR_BUFFER_OVERFLOW if the function doesn't have a fixed size + * buffer and the buffer isn't big enough. Correct size in @a *pcbRet. + * @retval VERR_INVALID_HANDLE if the handle is invalid. + * + * @param hLdrMod The module handle. + * @param enmProp The property to query. + * @param pvBits Optional pointer to bits returned by + * RTLdrGetBits(). This can be utilized by some module + * interpreters to reduce memory consumption and file + * access. + * @param pvBuf Pointer to the input / output buffer. In most cases + * it's only used for returning data. + * @param cbBuf The size of the buffer. + * @param pcbRet Where to return the amount of data returned. On + * buffer size errors, this is set to the correct size. + * Optional. + */ +RTDECL(int) RTLdrQueryPropEx(RTLDRMOD hLdrMod, RTLDRPROP enmProp, void *pvBits, void *pvBuf, size_t cbBuf, size_t *pcbRet); + + +/** + * Signature type, see FNRTLDRVALIDATESIGNEDDATA. + */ +typedef enum RTLDRSIGNATURETYPE +{ + /** Invalid value. */ + RTLDRSIGNATURETYPE_INVALID = 0, + /** A RTPKCS7CONTENTINFO structure w/ RTPKCS7SIGNEDDATA inside. + * It's parsed, so the whole binary ASN.1 representation can be found by + * using RTASN1CORE_GET_RAW_ASN1_PTR() and RTASN1CORE_GET_RAW_ASN1_SIZE(). */ + RTLDRSIGNATURETYPE_PKCS7_SIGNED_DATA, + /** End of valid values. */ + RTLDRSIGNATURETYPE_END, + /** Make sure the size is 32-bit. */ + RTLDRSIGNATURETYPE_32BIT_HACK = 0x7fffffff +} RTLDRSIGNATURETYPE; + +/** + * Signature information provided by FNRTLDRVALIDATESIGNEDDATA. + */ +typedef struct RTLDRSIGNATUREINFO +{ + /** The signature number (0-based). */ + uint16_t iSignature; + /** The total number of signatures. */ + uint16_t cSignatures; + /** Sginature format type. */ + RTLDRSIGNATURETYPE enmType; + /** The signature data (formatted according to enmType). */ + void const *pvSignature; + /** The size of the buffer pvSignature points to. */ + size_t cbSignature; + /** Pointer to the signed data, if external. + * NULL if the data is internal to the signature structure. */ + void const *pvExternalData; + /** Size of the signed data, if external. + * 0 if internal to the signature structure. */ + size_t cbExternalData; +} RTLDRSIGNATUREINFO; +/** Pointer to a signature structure. */ +typedef RTLDRSIGNATUREINFO *PRTLDRSIGNATUREINFO; +/** Pointer to a const signature structure. */ +typedef RTLDRSIGNATUREINFO const *PCRTLDRSIGNATUREINFO; + +/** + * Callback used by RTLdrVerifySignature to verify the signature and associated + * certificates. + * + * This is called multiple times when the executable contains more than one + * signature (PE only at the moment). The RTLDRSIGNATUREINFO::cSignatures gives + * the total number of signatures (and thereby callbacks) and + * RTLDRSIGNATUREINFO::iSignature indicates the current one. + * + * @returns IPRT status code. A status code other than VINF_SUCCESS will + * prevent callbacks the remaining signatures (if any). + * @param hLdrMod The module handle. + * @param pInfo Signature information. + * @param pErrInfo Pointer to an error info buffer, optional. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTLDRVALIDATESIGNEDDATA,(RTLDRMOD hLdrMod, PCRTLDRSIGNATUREINFO pInfo, + PRTERRINFO pErrInfo, void *pvUser)); +/** Pointer to a signature verification callback. */ +typedef FNRTLDRVALIDATESIGNEDDATA *PFNRTLDRVALIDATESIGNEDDATA; + +/** + * Verify the image signature. + * + * This may permform additional integrity checks on the image structures that + * was not done when opening the image. + * + * @returns IPRT status code. + * @retval VERR_LDRVI_NOT_SIGNED if not signed. + * + * @param hLdrMod The module handle. + * @param pfnCallback Callback that does the signature and certificate + * verficiation. + * @param pvUser User argument for the callback. + * @param pErrInfo Pointer to an error info buffer. Optional. + */ +RTDECL(int) RTLdrVerifySignature(RTLDRMOD hLdrMod, PFNRTLDRVALIDATESIGNEDDATA pfnCallback, void *pvUser, PRTERRINFO pErrInfo); + +/** + * Calculate the image hash according the image signing rules. + * + * @returns IPRT status code. + * @param hLdrMod The module handle. + * @param enmDigest Which kind of digest. + * @param pabHash Where to store the image hash. + * @param cbHash Size of the buffer @a pabHash points at. The + * required and returned size can be derived from the + * digest type (@a enmDigest). + */ +RTDECL(int) RTLdrHashImage(RTLDRMOD hLdrMod, RTDIGESTTYPE enmDigest, uint8_t *pabHash, size_t cbHash); + +/** + * Try use unwind information to unwind one frame. + * + * @returns IPRT status code. Last informational status from stack reader callback. + * @retval VERR_DBG_NO_UNWIND_INFO if the module contains no unwind information. + * @retval VERR_DBG_UNWIND_INFO_NOT_FOUND if no unwind information was found + * for the location given by iSeg:off. + * + * @param hLdrMod The module handle. + * @param pvBits Optional pointer to bits returned by + * RTLdrGetBits(). This can be utilized by some module + * interpreters to reduce memory consumption and file + * access. + * @param iSeg The segment number of the program counter. UINT32_MAX if RVA. + * @param off The offset into @a iSeg. Together with @a iSeg + * this corresponds to the RTDBGUNWINDSTATE::uPc + * value pointed to by @a pState. + * @param pState The unwind state to work. + * + * @sa RTDbgModUnwindFrame + */ +RTDECL(int) RTLdrUnwindFrame(RTLDRMOD hLdrMod, void const *pvBits, uint32_t iSeg, RTLDRADDR off, PRTDBGUNWINDSTATE pState); + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_ldr_h */ + diff --git a/include/iprt/ldrlazy.h b/include/iprt/ldrlazy.h new file mode 100644 index 00000000..0fa788da --- /dev/null +++ b/include/iprt/ldrlazy.h @@ -0,0 +1,122 @@ +/** @file + * IPRT - Lazy share library linking (2nd try). + */ + +/* + * Copyright (C) 2013-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_ldrlazy_h +#define IPRT_INCLUDED_ldrlazy_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/ldr.h> + +/** @defgroup grp_rt_ldrlazy RTLdrLazy - Lazy shared library linking. + * @ingroup grp_rt + * + * This is a set of macros which will produce code for dynamically loading and + * resolving symbols in shared libraries (DLLs). + * + * There is an assembly language alternative to this that only requires writing + * a list of symbols in a format similar to what the microsoft linkers take as + * input when producing DLLs and import libraries. That is probably preferable + * over this code. See src/bldprog/VBoxDef2LazyLoad.cpp. + * + * @{ + */ + + +/** + * Defines a module for use in lazy resolving. + * + * @param a_Mod The module name (C name). + * @param a_pszFile The file to tell RTLdrLoad to load. + */ +#define RTLDRLAZY_MODULE(a_Mod, a_pszFile) \ + RTLDRLAZY_MODULE_EX(a_Mod, a_pszFile, RTLdrLoad) + +/** + * Defines a module for use in lazy resolving. + * + * @param a_Mod The module name (C name). + * @param a_pszFile The file to tell RTLdrLoad to load. + * @param a_pfnLoadIt Function to call for loading the DLL, replacing + * RTLdrLoad. + */ +#define RTLDRLAZY_MODULE_EX(a_Mod, a_pszFile, a_pfnLoadIt) \ + static bool rtLdrLazy_##a_Mod##_Resolve(const char *pszName, void **ppvSymbol) \ + { \ + static RTLDRMOD volatile s_hMod = NIL_RTLDRMOD; \ + static bool volatile s_fLoaded = false; \ + RTLDRMOD hMod; \ + int rc; \ + if (!s_fLoaded) \ + { \ + rc = a_pfnLoadIt(a_pszFile, &hMod); \ + s_hMod = RT_SUCCESS(rc) ? hMod : NIL_RTLDRMOD; \ + s_fLoaded = true; \ + if (RT_FAILURE(rc)) \ + return false; \ + } \ + hMod = s_hMod; \ + if (hMod == NIL_RTLDRMOD) \ + return false; \ + rc = RTLdrGetSymbol(hMod, pszName, ppvSymbol); \ + return RT_SUCCESS(rc); \ + } + + + +/** Function name mangler for preventing collision with system prototypes. */ +#define RTLDRLAZY_FUNC_NAME(a_Mod, a_Name) a_Mod##__##a_Name + +/** + * Defines a function that should be lazily resolved. + */ +#define RTLDRLAZY_FUNC(a_Mod, a_RetType, a_CallConv, a_Name, a_ParamDecl, a_ParamNames, a_ErrRet) \ + DECLINLINE(a_RetType) RTLDRLAZY_FUNC_NAME(a_Mod, a_Name) a_ParamDecl \ + { \ + static a_RetType (a_CallConv * s_pfn) a_ParamDecl; \ + if (!s_pfn) \ + { \ + if (!rtLdrLazy_##a_Mod##_Resolve(#a_Name, (void **)&s_pfn)) \ + return a_ErrRet; \ + } \ + return s_pfn a_ParamNames; \ + } + + +/** @} */ + +#endif /* !IPRT_INCLUDED_ldrlazy_h */ + diff --git a/include/iprt/linux/Makefile.kup b/include/iprt/linux/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/iprt/linux/Makefile.kup diff --git a/include/iprt/linux/symvers.h b/include/iprt/linux/symvers.h new file mode 100644 index 00000000..0a8ef1b7 --- /dev/null +++ b/include/iprt/linux/symvers.h @@ -0,0 +1,89 @@ +/** @file + * IPRT - Linux symver and compatibility definitions. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +/* 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_INCLUDED_linux_symvers_h +#define IPRT_INCLUDED_linux_symvers_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* 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@GLIBC_2.2.5"); +__asm__(".symver posix_spawn,posix_spawn@GLIBC_2.2.5"); +#else /* RT_ARCH_X86 */ +__asm__(".symver posix_spawn,posix_spawn@GLIBC_2.2"); +#endif + +/* Do not use *_chk functions */ +#undef _FORTIFY_SOURCE + +/* Do not use __isoc99_* functions */ +#undef __USE_GNU +#define __USE_GNU 1 + +/* And EL5 wants this too with __USE_GNU */ +#undef _GNU_SOURCE +#define _GNU_SOURCE 1 + +/* Tell IPRT not to use newer functions */ +#include <features.h> +#undef __GLIBC_MINOR__ +#define __GLIBC_MINOR__ 3 + +/* Do not use fcntl64 */ +#include <fcntl.h> +#ifdef fnctl +# undef fcntl +#endif +#if defined(RT_ARCH_AMD64) +__asm__(".symver fcntl64,fcntl@GLIBC_2.2.5"); +#else +__asm__(".symver fcntl64,fcntl@GLIBC_2.0"); +#endif + +/* Do not use ISO C99 scanf which has a glibc 2.7 dependency. */ +#undef __GLIBC_USE_DEPRECATED_SCANF +#define __GLIBC_USE_DEPRECATED_SCANF 1 +#endif /* !IPRT_INCLUDED_linux_symvers_h */ diff --git a/include/iprt/linux/sysfs.h b/include/iprt/linux/sysfs.h new file mode 100644 index 00000000..02c3af39 --- /dev/null +++ b/include/iprt/linux/sysfs.h @@ -0,0 +1,487 @@ +/* $Id: sysfs.h $ */ +/** @file + * IPRT - Linux sysfs access. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_linux_sysfs_h +#define IPRT_INCLUDED_linux_sysfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/stdarg.h> + +#include <sys/types.h> /* for dev_t */ + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_linux_sysfs RTLinuxSysfs - Linux sysfs + * @ingroup grp_rt + * @{ + */ + +/** + * Checks if a sysfs file (or directory, device, symlink, whatever) exists. + * + * @returns true if the sysfs object exists. + * false otherwise or if an error occurred. + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param va The format args. + */ +RTDECL(bool) RTLinuxSysFsExistsV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Checks if a sysfs object (directory, device, symlink, whatever) exists. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the sysfs object exists. + * @retval VERR_FILE_NOT_FOUND if the sysfs object does not exist. + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param va The format args. + */ +RTDECL(int) RTLinuxSysFsExistsExV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Checks if a sysfs file (or directory, device, symlink, whatever) exists. + * + * @returns true if the sysfs object exists. + * false otherwise or if an error occurred. + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param ... The format args. + */ +RTDECL(bool) RTLinuxSysFsExists(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Checks if a sysfs object (directory, device, symlink, whatever) exists. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the sysfs object exists. + * @retval VERR_FILE_NOT_FOUND if the sysfs object does not exist. + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param ... The format args. + */ +RTDECL(int) RTLinuxSysFsExistsEx(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Opens a sysfs file for reading. + * + * @returns IPRT status code. + * @param phFile Where to store the file handle on success. + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param va The format args. + * + * @note Close the file using RTFileClose(). + */ +RTDECL(int) RTLinuxSysFsOpenV(PRTFILE phFile, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Opens a sysfs file - extended version. + * + * @returns IPRT status code. + * @param phFile Where to store the file handle on success. + * @param fOpen Open flags, see RTFileOpen(). + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param va The format args. + */ +RTDECL(int) RTLinuxSysFsOpenExV(PRTFILE phFile, uint64_t fOpen, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Opens a sysfs file. + * + * @returns IPRT status code. + * @param phFile Where to store the file handle on success. + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param ... The format args. + * + * @note Close the file using RTFileClose(). + */ +RTDECL(int) RTLinuxSysFsOpen(PRTFILE phFile, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Opens a sysfs file - extended version. + * + * @returns IPRT status code. + * @param phFile Where to store the file handle on success. + * @param fOpen Open flags, see RTFileOpen(). + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param ... The format args. + */ +RTDECL(int) RTLinuxSysFsOpenEx(PRTFILE phFile, uint64_t fOpen, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Reads a string from a file opened with RTLinuxSysFsOpen or RTLinuxSysFsOpenV. + * + * Expects to read the whole file, mind, and will return VERR_BUFFER_OVERFLOW if + * that is not possible with the given buffer size. + * + * @returns IPRT status code. + * @param hFile The file descriptor returned by RTLinuxSysFsOpen or RTLinuxSysFsOpenV. + * @param pszBuf Where to store the string. + * @param cchBuf The size of the buffer. Must be at least 2 bytes. + * @param pcchRead Where to store the amount of characters read on success - optional. + */ +RTDECL(int) RTLinuxSysFsReadStr(RTFILE hFile, char *pszBuf, size_t cchBuf, size_t *pcchRead); + +/** + * Writes a string to a file opened with RTLinuxSysFsOpenEx or RTLinuxSysFsOpenExV for writing. + * + * @returns IPRT status code. + * @param hFile The file descriptor returned by RTLinuxSysFsOpenEx or RTLinuxSysFsOpenExV. + * @param pszBuf The string to write. + * @param cchBuf The length of the string to write - if 0 is given + * the string length is determined before writing it including the zero terminator. + * @param pcchWritten Where to store the amount of characters written on success - optional. + */ +RTDECL(int) RTLinuxSysFsWriteStr(RTFILE hFile, const char *pszBuf, size_t cchBuf, size_t *pcchWritten); + +/** + * Reads the remainder of a file opened with RTLinuxSysFsOpen or + * RTLinuxSysFsOpenV. + * + * @returns IPRT status code. + * @param hFile The file descriptor returned by RTLinuxSysFsOpen or RTLinuxSysFsOpenV. + * @param pvBuf Where to store the bits from the file. + * @param cbBuf The size of the buffer. + * @param pcbRead Where to return the number of bytes read. Optional. + */ +RTDECL(int) RTLinuxSysFsReadFile(RTFILE hFile, void *pvBuf, size_t cbBuf, size_t *pcbRead); + +/** + * Writes the given buffer to a file opened with RTLinuxSysFsOpenEx or + * RTLinuxSysFsOpenExV. + * + * @returns IPRT status code. + * @param hFile The file descriptor returned by RTLinuxSysFsOpenEx or RTLinuxSysFsOpenExV. + * @param pvBuf The data to write. + * @param cbBuf The size of the buffer. + * @param pcbWritten Where to return the number of bytes read. Optional. + */ +RTDECL(int) RTLinuxSysFsWriteFile(RTFILE hFile, void *pvBuf, size_t cbBuf, size_t *pcbWritten); + +/** + * Reads a number from a sysfs file. + * + * @returns IPRT status code. + * @param uBase The number base, 0 for autodetect. + * @param pi64 Where to store the 64-bit signed on success. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsReadIntFileV(unsigned uBase, int64_t *pi64, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Reads a number from a sysfs file. + * + * @returns IPRT status code. + * @param uBase The number base, 0 for autodetect. + * @param pi64 Where to store the 64-bit signed on success. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsReadIntFile(unsigned uBase, int64_t *pi64, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Writes an unsigned 8-bit number to a sysfs file. + * + * @returns IPRT status code. + * @param uBase The base format to write the number. Passing 16 here for + * example writes the number as a hexadecimal string with 0x prepended. + * @param u8 The number to write. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsWriteU8FileV(unsigned uBase, uint8_t u8, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Writes an unsigned 8-bit number to a sysfs file. + * + * @returns IPRT status code. + * @param uBase The base format to write the number. Passing 16 here for + * example writes the number as a hexadecimal string with 0x prepended. + * @param u8 The number to write. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsWriteU8File(unsigned uBase, uint8_t u8, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Writes an unsigned 16-bit number to a sysfs file. + * + * @returns IPRT status code. + * @param uBase The base format to write the number. Passing 16 here for + * example writes the number as a hexadecimal string with 0x prepended. + * @param u16 The number to write. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsWriteU16FileV(unsigned uBase, uint16_t u16, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Writes an unsigned 16-bit number to a sysfs file. + * + * @returns IPRT status code. + * @param uBase The base format to write the number. Passing 16 here for + * example writes the number as a hexadecimal string with 0x prepended. + * @param u16 The number to write. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsWriteU16File(unsigned uBase, uint16_t u16, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Writes an unsigned 32-bit number to a sysfs file. + * + * @returns IPRT status code. + * @param uBase The base format to write the number. Passing 16 here for + * example writes the number as a hexadecimal string with 0x prepended. + * @param u32 The number to write. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsWriteU32FileV(unsigned uBase, uint32_t u32, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Writes an unsigned 8-bit number to a sysfs file. + * + * @returns IPRT status code. + * @param uBase The base format to write the number. Passing 16 here for + * example writes the number as a hexadecimal string with 0x prepended. + * @param u32 The number to write. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsWriteU32File(unsigned uBase, uint32_t u32, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Writes an unsigned 64-bit number to a sysfs file. + * + * @returns IPRT status code. + * @param uBase The base format to write the number. Passing 16 here for + * example writes the number as a hexadecimal string with 0x prepended. + * @param u64 The number to write. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsWriteU64FileV(unsigned uBase, uint64_t u64, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Writes an unsigned 8-bit number to a sysfs file. + * + * @returns IPRT status code. + * @param uBase The base format to write the number. Passing 16 here for + * example writes the number as a hexadecimal string with 0x prepended. + * @param u64 The number to write. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsWriteU64File(unsigned uBase, uint32_t u64, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Reads a device number from a sysfs file. + * + * @returns IPRT status code. + * @param pDevNum Where to store the device number on success. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsReadDevNumFileV(dev_t *pDevNum, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Reads a device number from a sysfs file. + * + * @returns IPRT status code. + * @param pDevNum Where to store the device number on success. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsReadDevNumFile(dev_t *pDevNum, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Reads a string from a sysfs file. + * + * If the file contains a newline, we only return the text up until there. This + * differs from the RTLinuxSysFsReadStr() behaviour. + * + * @returns IPRT status code. + * @param pszBuf Where to store the path element. Must be at least two + * characters, but a longer buffer would be advisable. + * @param cchBuf The size of the buffer pointed to by @a pszBuf. + * @param pcchRead Where to store the amount of characters read on success - optional. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsReadStrFileV(char *pszBuf, size_t cchBuf, size_t *pcchRead, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(4, 0); + +/** + * Reads a string from a sysfs file. If the file contains a newline, we only + * return the text up until there. + * + * @returns IPRT status code. + * @param pszBuf Where to store the path element. Must be at least two + * characters, but a longer buffer would be advisable. + * @param cchBuf The size of the buffer pointed to by @a pszBuf. + * @param pcchRead Where to store the amount of characters read on success - optional. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsReadStrFile(char *pszBuf, size_t cchBuf, size_t *pcchRead, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(4, 5); + +/** + * Writes a string to a sysfs file. + * + * @returns IPRT status code. + * @param pszBuf The string to write. + * @param cchBuf The size of the buffer pointed to by @a pszBuf. + * @param pcchWritten Where to store the amount of characters written on success - optional. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsWriteStrFileV(const char *pszBuf, size_t cchBuf, size_t *pcchWritten, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(4, 0); + +/** + * Writes a string to a sysfs file. + * + * @returns IPRT status code. + * @param pszBuf The string to write. + * @param cchBuf The size of the buffer pointed to by @a pszBuf. + * @param pcchWritten Where to store the amount of characters written on success - optional. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsWriteStrFile(const char *pszBuf, size_t cchBuf, size_t *pcchWritten, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(4, 5); + +/** + * Reads the last element of the path of the file pointed to by the symbolic + * link specified. + * + * This is needed at least to get the name of the driver associated with a + * device, where pszFormat should be the "driver" link in the devices sysfs + * directory. + * + * @returns IPRT status code. + * @param pszBuf Where to store the path element. Must be at least two + * characters, but a longer buffer would be advisable. + * @param cchBuf The size of the buffer pointed to by @a pszBuf. + * @param pchBuf Where to store the length of the returned string on success - optional. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param va Format args. + */ +RTDECL(int) RTLinuxSysFsGetLinkDestV(char *pszBuf, size_t cchBuf, size_t *pchBuf, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(4, 0); + +/** + * Reads the last element of the path of the file pointed to by the symbolic + * link specified. + * + * This is needed at least to get the name of the driver associated with a + * device, where pszFormat should be the "driver" link in the devices sysfs + * directory. + * + * @returns IPRT status code. + * @param pszBuf Where to store the path element. Must be at least two + * characters, but a longer buffer would be advisable. + * @param cchBuf The size of the buffer pointed to by @a pszBuf. + * @param pchBuf Where to store the length of the returned string on success - optional. + * @param pszFormat The filename format, either absolute or relative to "/sys/". + * @param ... Format args. + */ +RTDECL(int) RTLinuxSysFsGetLinkDest(char *pszBuf, size_t cchBuf, size_t *pchBuf, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(4, 5); + +/** + * Check the path of a device node under /dev, given the device number and a + * pattern and store the path into @a pszBuf. + * + * @returns IPRT status code. + * @retval VERR_FILE_NOT_FOUND if no matching device node could be found. + * @param DevNum The device number to search for. + * @param fMode The type of device - only RTFS_TYPE_DEV_CHAR and + * RTFS_TYPE_DEV_BLOCK are valid values. + * @param pszBuf Where to store the path. + * @param cchBuf The size of the buffer. + * @param pszPattern The expected path format of the device node, either + * absolute or relative to "/dev". + * @param va Format args. + */ +RTDECL(int) RTLinuxCheckDevicePathV(dev_t DevNum, RTFMODE fMode, char *pszBuf, size_t cchBuf, + const char *pszPattern, va_list va) RT_IPRT_FORMAT_ATTR(5, 0); + +/** + * Check the path of a device node under /dev, given the device number and a + * pattern and store the path into @a pszBuf. + * + * @returns IPRT status code. + * @retval VERR_FILE_NOT_FOUND if no matching device node could be found. + * @param DevNum The device number to search for + * @param fMode The type of device - only RTFS_TYPE_DEV_CHAR and + * RTFS_TYPE_DEV_BLOCK are valid values + * @param pszBuf Where to store the path. + * @param cchBuf The size of the buffer. + * @param pszPattern The expected path format of the device node, either + * absolute or relative to "/dev". + * @param ... Format args. + */ +RTDECL(int) RTLinuxCheckDevicePath(dev_t DevNum, RTFMODE fMode, char *pszBuf, size_t cchBuf, + const char *pszPattern, ...) RT_IPRT_FORMAT_ATTR(5, 6); + +/** + * Constructs the path of a sysfs file from the format parameters passed, + * prepending "/sys/" if the path is relative. + * + * @returns IPRT status code. + * @param pszPath Where to write the path. + * @param cbPath The size of the buffer pointed to by @a pszPath. + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param va The format args. + */ +RTDECL(int) RTLinuxConstructPathV(char *pszPath, size_t cbPath, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Constructs the path of a sysfs file from the format parameters passed, + * prepending "/sys/" if the path is relative. + * + * @returns IPRT status code. + * @param pszPath Where to write the path. + * @param cbPath The size of the buffer pointed to by @a pszPath. + * @param pszFormat The name format, either absolute or relative to "/sys/". + * @param ... The format args. + */ +RTDECL(int) RTLinuxConstructPath(char *pszPath, size_t cbPath, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_linux_sysfs_h */ + diff --git a/include/iprt/linux/version.h b/include/iprt/linux/version.h new file mode 100644 index 00000000..6badeab0 --- /dev/null +++ b/include/iprt/linux/version.h @@ -0,0 +1,205 @@ +/* $Id: version.h $ */ +/** @file + * IPRT - Linux kernel version. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_linux_version_h +#define IPRT_INCLUDED_linux_version_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <linux/version.h> + +/* We need utsrelease.h in order to detect Ubuntu kernel, + * i.e. check if UTS_UBUNTU_RELEASE_ABI is defined. Support kernels + * starting from Ubuntu 14.04 Trusty which is based on upstream + * kernel 3.13.x. */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0)) +# include <generated/utsrelease.h> +# include <iprt/cdefs.h> +#endif + +/** @def RTLNX_VER_MIN + * Evaluates to true if the linux kernel version is equal or higher to the + * one specfied. */ +#define RTLNX_VER_MIN(a_Major, a_Minor, a_Patch) \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(a_Major, a_Minor, a_Patch)) + +/** @def RTLNX_VER_MAX + * Evaluates to true if the linux kernel version is less to the one specfied + * (exclusive). */ +#define RTLNX_VER_MAX(a_Major, a_Minor, a_Patch) \ + (LINUX_VERSION_CODE < KERNEL_VERSION(a_Major, a_Minor, a_Patch)) + +/** @def RTLNX_VER_RANGE + * Evaluates to true if the linux kernel version is equal or higher to the given + * minimum version and less (but not equal) to the maximum version (exclusive). */ +#define RTLNX_VER_RANGE(a_MajorMin, a_MinorMin, a_PatchMin, a_MajorMax, a_MinorMax, a_PatchMax) \ + ( LINUX_VERSION_CODE >= KERNEL_VERSION(a_MajorMin, a_MinorMin, a_PatchMin) \ + && LINUX_VERSION_CODE < KERNEL_VERSION(a_MajorMax, a_MinorMax, a_PatchMax) ) + + +/** @def RTLNX_RHEL_MIN + * Require a minium RedHat release. + * @param a_iMajor The major release number (RHEL_MAJOR). + * @param a_iMinor The minor release number (RHEL_MINOR). + * @sa RTLNX_RHEL_MAX, RTLNX_RHEL_RANGE, RTLNX_RHEL_MAJ_PREREQ + */ +#if defined(RHEL_MAJOR) && defined(RHEL_MINOR) +# define RTLNX_RHEL_MIN(a_iMajor, a_iMinor) \ + ((RHEL_MAJOR) > (a_iMajor) || ((RHEL_MAJOR) == (a_iMajor) && (RHEL_MINOR) >= (a_iMinor))) +#else +# define RTLNX_RHEL_MIN(a_iMajor, a_iMinor) (0) +#endif + +/** @def RTLNX_RHEL_MAX + * Require a maximum RedHat release, true for all RHEL versions below it. + * @param a_iMajor The major release number (RHEL_MAJOR). + * @param a_iMinor The minor release number (RHEL_MINOR). + * @sa RTLNX_RHEL_MIN, RTLNX_RHEL_RANGE, RTLNX_RHEL_MAJ_PREREQ + */ +#if defined(RHEL_MAJOR) && defined(RHEL_MINOR) +# define RTLNX_RHEL_MAX(a_iMajor, a_iMinor) \ + ((RHEL_MAJOR) < (a_iMajor) || ((RHEL_MAJOR) == (a_iMajor) && (RHEL_MINOR) < (a_iMinor))) +#else +# define RTLNX_RHEL_MAX(a_iMajor, a_iMinor) (0) +#endif + +/** @def RTLNX_RHEL_RANGE + * Check that it's a RedHat kernel in the given version range. + * The max version is exclusive, the minimum inclusive. + * @sa RTLNX_RHEL_MIN, RTLNX_RHEL_MAX, RTLNX_RHEL_MAJ_PREREQ + */ +#if defined(RHEL_MAJOR) && defined(RHEL_MINOR) +# define RTLNX_RHEL_RANGE(a_iMajorMin, a_iMinorMin, a_iMajorMax, a_iMinorMax) \ + (RTLNX_RHEL_MIN(a_iMajorMin, a_iMinorMin) && RTLNX_RHEL_MAX(a_iMajorMax, a_iMinorMax)) +#else +# define RTLNX_RHEL_RANGE(a_iMajorMin, a_iMinorMin, a_iMajorMax, a_iMinorMax) (0) +#endif + +/** @def RTLNX_RHEL_MAJ_PREREQ + * Require a minimum minor release number for the given RedHat release. + * @param a_iMajor RHEL_MAJOR must _equal_ this. + * @param a_iMinor RHEL_MINOR must be greater or equal to this. + * @sa RTLNX_RHEL_MIN, RTLNX_RHEL_MAX + */ +#if defined(RHEL_MAJOR) && defined(RHEL_MINOR) +# define RTLNX_RHEL_MAJ_PREREQ(a_iMajor, a_iMinor) ((RHEL_MAJOR) == (a_iMajor) && (RHEL_MINOR) >= (a_iMinor)) +#else +# define RTLNX_RHEL_MAJ_PREREQ(a_iMajor, a_iMinor) (0) +#endif + + +/** @def RTLNX_SUSE_MAJ_PREREQ + * Require a minimum minor release number for the given SUSE release. + * @param a_iMajor CONFIG_SUSE_VERSION must _equal_ this. + * @param a_iMinor CONFIG_SUSE_PATCHLEVEL must be greater or equal to this. + */ +#if defined(CONFIG_SUSE_VERSION) && defined(CONFIG_SUSE_PATCHLEVEL) +# define RTLNX_SUSE_MAJ_PREREQ(a_iMajor, a_iMinor) ((CONFIG_SUSE_VERSION) == (a_iMajor) && (CONFIG_SUSE_PATCHLEVEL) >= (a_iMinor)) +#else +# define RTLNX_SUSE_MAJ_PREREQ(a_iMajor, a_iMinor) (0) +#endif + + +#if defined(UTS_UBUNTU_RELEASE_ABI) || defined(DOXYGEN_RUNNING) + +/** Hack to make the UTS_UBUNTU_RELEASE_ABI palatable by the C preprocesor. + * + * While the Ubuntu kernel ABI version looks like a decimal number, some + * kernels has a leading zero (e.g. 050818) that makes the preprocessor think + * it's an octal number. To work around that, we turn it into an hexadecimal + * number by prefixing it with '0x'. */ +# define RTLNX_UBUNTU_ABI(a_iAbi) (RT_CONCAT(0x,a_iAbi)) + +/** @def RTLNX_UBUNTU_ABI_MIN + * Require Ubuntu release ABI to be equal or newer than specified version. + * + * The kernel version should exactly match the specified @a a_iMajor, @a + * a_iMinor and @a a_iPatch. The @a a_iAbi number should be equal to or greater + * than the current ABI version. + * + * @param a_iMajor The major kernel version number. + * @param a_iMinor The minor kernel version number. + * @param a_iPatch The kernel patch level. + * @param a_iAbi Ubuntu kernel ABI version number (inclusive). + */ +# define RTLNX_UBUNTU_ABI_MIN(a_iMajor, a_iMinor, a_iPatch, a_iAbi) \ + ( KERNEL_VERSION(a_iMajor, a_iMinor, a_iPatch) == LINUX_VERSION_CODE \ + && RTLNX_UBUNTU_ABI(UTS_UBUNTU_RELEASE_ABI) >= RTLNX_UBUNTU_ABI(a_iAbi)) + +/** @def RTLNX_UBUNTU_ABI_MAX + * Require Ubuntu release ABI to be older than specified version. + * + * The kernel version should exactly match the specified @a a_iMajor, @a + * a_iMinor and @a a_iPatch. The @a a_iAbi number should be less than the + * current ABI version. + * + * @param a_iMajor The major kernel version number. + * @param a_iMinor The minor kernel version number. + * @param a_iPatch The kernel patch level. + * @param a_iAbi Ubuntu kernel ABI version number (exclusive). + */ +# define RTLNX_UBUNTU_ABI_MAX(a_iMajor, a_iMinor, a_iPatch, a_iAbi) \ + ( KERNEL_VERSION(a_iMajor, a_iMinor, a_iPatch) == LINUX_VERSION_CODE \ + && RTLNX_UBUNTU_ABI(UTS_UBUNTU_RELEASE_ABI) < RTLNX_UBUNTU_ABI(a_iAbi)) + +/** @def RTLNX_UBUNTU_ABI_RANGE + * Require Ubuntu release ABI to be in specified range. + * + * The kernel version should exactly match the specified @a a_iMajor, @a + * a_iMinor and @a a_iPatch. The numbers @a a_iAbiMin and @a a_iAbiMax specify + * ABI versions range. The max ABI version is exclusive, the minimum inclusive. + * + * @param a_iMajor The major kernel version number. + * @param a_iMinor The minor kernel version number. + * @param a_iPatch The kernel patch level. + * @param a_iAbiMin The minimum Ubuntu kernel ABI version number (inclusive). + * @param a_iAbiMax The maximum Ubuntu kernel ABI version number (exclusive). + */ +# define RTLNX_UBUNTU_ABI_RANGE(a_iMajor, a_iMinor, a_iPatch, a_iAbiMin, a_iAbiMax) \ + ( RTLNX_UBUNTU_ABI_MIN(a_iMajor, a_iMinor, a_iPatch, a_iAbiMin) \ + && RTLNX_UBUNTU_ABI_MAX(a_iMajor, a_iMinor, a_iPatch, a_iAbiMax)) + +#else /* !UTS_UBUNTU_RELEASE_ABI */ + +# define RTLNX_UBUNTU_ABI_MIN(a_iMajor, a_iMinor, a_iPatch, a_iAbi) (0) +# define RTLNX_UBUNTU_ABI_MAX(a_iMajor, a_iMinor, a_iPatch, a_iAbi) (0) +# define RTLNX_UBUNTU_ABI_RANGE(a_iMajorMin, a_iMinorMin, a_iPatchMin, a_iAbiMin, a_iAbiMax) (0) + +#endif /* !UTS_UBUNTU_RELEASE_ABI */ + +#endif /* !IPRT_INCLUDED_linux_version_h */ + diff --git a/include/iprt/list-off32.h b/include/iprt/list-off32.h new file mode 100644 index 00000000..69a4efcf --- /dev/null +++ b/include/iprt/list-off32.h @@ -0,0 +1,514 @@ +/** @file + * IPRT - Generic Doubly Linked List, using 32-bit offset instead of pointers. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_list_off32_h +#define IPRT_INCLUDED_list_off32_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/** @defgroup grp_rt_list_off32 RTListOff32 - Generic Doubly Linked List based on 32-bit offset. + * @ingroup grp_rt + * + * This is the same as @ref grp_rt_list , except that instead of pointers we use + * 32-bit offsets. The list implementation is circular, with a dummy node as + * anchor. Be careful with the dummy node when walking the list. + * + * @{ + */ + +RT_C_DECLS_BEGIN + +/** + * A list node of a doubly linked list. + */ +typedef struct RTLISTOFF32NODE +{ + /** Offset to the next list node, relative to this structure. */ + int32_t offNext; + /** Offset to the previous list node, relative to this structure. */ + int32_t offPrev; +} RTLISTOFF32NODE; +/** Pointer to a list node. */ +typedef RTLISTOFF32NODE *PRTLISTOFF32NODE; +/** Pointer to a const list node. */ +typedef RTLISTOFF32NODE const *PCRTLISTOFF32NODE; +/** Pointer to a list node pointer. */ +typedef PRTLISTOFF32NODE *PPRTLISTOFF32NODE; + +/** The anchor (head/tail) of a doubly linked list. + * + * @remarks Please always use this instead of RTLISTOFF32NODE to indicate a list + * head/tail. It makes the code so much easier to read. Also, + * always mention the actual list node type(s) in the comment. + * @remarks Must be allocated in a similar manner as the nodes, so as to + * keep it within a 32-bit distance from them. + */ +typedef RTLISTOFF32NODE RTLISTOFF32ANCHOR; +/** Pointer to a doubly linked list anchor. */ +typedef RTLISTOFF32ANCHOR *PRTLISTOFF32ANCHOR; +/** Pointer to a const doubly linked list anchor. */ +typedef RTLISTOFF32ANCHOR const *PCRTLISTOFF32ANCHOR; + + +/** + * Initialize a list. + * + * @param pList Pointer to an unitialised list. + */ +DECLINLINE(void) RTListOff32Init(PRTLISTOFF32NODE pList) +{ + pList->offNext = 0; + pList->offPrev = 0; +} + +/** + * Internal macro for converting an offset to a pointer. + * @returns PRTLISTOFF32NODE + * @param a_pNode The node the offset is relative to. + * @param a_off The offset. + */ +#define RTLISTOFF32_TO_PTR(a_pNode, a_off) ((PRTLISTOFF32NODE)((intptr_t)(a_pNode) + (a_off))) + +/** + * Internal macro for getting the pointer to the next node. + * @returns PRTLISTOFF32NODE + * @param a_pNode The node the offset is relative to. + */ +#define RTLISTOFF32_NEXT_PTR(a_pNode) RTLISTOFF32_TO_PTR(a_pNode, (a_pNode)->offNext) + +/** + * Internal macro for getting the pointer to the previous node. + * @returns PRTLISTOFF32NODE + * @param a_pNode The node the offset is relative to. + */ +#define RTLISTOFF32_PREV_PTR(a_pNode) RTLISTOFF32_TO_PTR(a_pNode, (a_pNode)->offPrev) + +/** + * Internal macro for converting an a pointer to an offset. + * @returns offset + * @param a_pNode The node the offset is relative to. + * @param a_pOtherNode The pointer to convert. + */ +#define RTLISTOFF32_TO_OFF(a_pNode, a_pOtherNode) ((int32_t)((intptr_t)(a_pOtherNode) - (intptr_t)(a_pNode))) + +/** + * Internal macro for getting the pointer to the next node. + * @returns PRTLISTOFF32NODE + * @param a_pNode The node which offNext member should be set. + * @param a_pNewNext Pointer to the new next node. + */ +#define RTLISTOFF32_SET_NEXT_PTR(a_pNode, a_pNewNext) \ + do { (a_pNode)->offNext = RTLISTOFF32_TO_OFF(a_pNode, a_pNewNext); } while (0) + +/** + * Internal macro for getting the pointer to the previous node. + * @returns PRTLISTOFF32NODE + * @param a_pNode The node which offPrev member should be set. + * @param a_pNewPrev Pointer to the new previous node. + */ +#define RTLISTOFF32_SET_PREV_PTR(a_pNode, a_pNewPrev) \ + do { (a_pNode)->offPrev = RTLISTOFF32_TO_OFF(a_pNode, a_pNewPrev); } while (0) + + + +/** + * Append a node to the end of the list. + * + * @param pList The list to append the node to. + * @param pNode The node to append. + */ +DECLINLINE(void) RTListOff32Append(PRTLISTOFF32NODE pList, PRTLISTOFF32NODE pNode) +{ + PRTLISTOFF32NODE pLast = RTLISTOFF32_PREV_PTR(pList); + RTLISTOFF32_SET_NEXT_PTR(pLast, pNode); + RTLISTOFF32_SET_PREV_PTR(pNode, pLast); + RTLISTOFF32_SET_NEXT_PTR(pNode, pList); + RTLISTOFF32_SET_PREV_PTR(pList, pNode); +} + +/** + * Add a node as the first element of the list. + * + * @param pList The list to prepend the node to. + * @param pNode The node to prepend. + */ +DECLINLINE(void) RTListOff32Prepend(PRTLISTOFF32NODE pList, PRTLISTOFF32NODE pNode) +{ + PRTLISTOFF32NODE pFirst = RTLISTOFF32_NEXT_PTR(pList); + RTLISTOFF32_SET_PREV_PTR(pFirst, pNode); + RTLISTOFF32_SET_NEXT_PTR(pNode, pFirst); + RTLISTOFF32_SET_PREV_PTR(pNode, pList); + RTLISTOFF32_SET_NEXT_PTR(pList, pNode); +} + +/** + * Inserts a node after the specified one. + * + * @param pCurNode The current node. + * @param pNewNode The node to insert. + */ +DECLINLINE(void) RTListOff32NodeInsertAfter(PRTLISTOFF32NODE pCurNode, PRTLISTOFF32NODE pNewNode) +{ + RTListOff32Prepend(pCurNode, pNewNode); +} + +/** + * Inserts a node before the specified one. + * + * @param pCurNode The current node. + * @param pNewNode The node to insert. + */ +DECLINLINE(void) RTListOff32NodeInsertBefore(PRTLISTOFF32NODE pCurNode, PRTLISTOFF32NODE pNewNode) +{ + RTListOff32Append(pCurNode, pNewNode); +} + +/** + * Remove a node from a list. + * + * @param pNode The node to remove. + */ +DECLINLINE(void) RTListOff32NodeRemove(PRTLISTOFF32NODE pNode) +{ + PRTLISTOFF32NODE pPrev = RTLISTOFF32_PREV_PTR(pNode); + PRTLISTOFF32NODE pNext = RTLISTOFF32_NEXT_PTR(pNode); + + RTLISTOFF32_SET_NEXT_PTR(pPrev, pNext); + RTLISTOFF32_SET_PREV_PTR(pNext, pPrev); + + /* poison */ + pNode->offNext = INT32_MAX / 2; + pNode->offPrev = INT32_MAX / 2; +} + +/** + * Checks if a node is the last element in the list. + * + * @retval true if the node is the last element in the list. + * @retval false otherwise + * + * @param pList The list. + * @param pNode The node to check. + */ +#define RTListOff32NodeIsLast(pList, pNode) (RTLISTOFF32_NEXT_PTR(pNode) == (pList)) + +/** + * Checks if a node is the first element in the list. + * + * @retval true if the node is the first element in the list. + * @retval false otherwise. + * + * @param pList The list. + * @param pNode The node to check. + */ +#define RTListOff32NodeIsFirst(pList, pNode) (RTLISTOFF32_PREV_PTR(pNode) == (pList)) + +/** + * Checks if a type converted node is actually the dummy element (@a pList). + * + * @retval true if the node is the dummy element in the list. + * @retval false otherwise. + * + * @param pList The list. + * @param pNode The node structure to check. Typically + * something obtained from RTListOff32NodeGetNext() + * or RTListOff32NodeGetPrev(). This is NOT a + * PRTLISTOFF32NODE but something that contains a + * RTLISTOFF32NODE member! + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListOff32NodeIsDummy(pList, pNode, Type, Member) \ + ( (pNode) == RT_FROM_MEMBER((pList), Type, Member) ) +/** @copydoc RTListOff32NodeIsDummy */ +#define RTListOff32NodeIsDummyCpp(pList, pNode, Type, Member) \ + ( (pNode) == RT_FROM_CPP_MEMBER((pList), Type, Member) ) + +/** + * Checks if a list is empty. + * + * @retval true if the list is empty. + * @retval false otherwise. + * + * @param pList The list to check. + */ +#define RTListOff32IsEmpty(pList) ((pList)->offNext == 0) + +/** + * Returns the next node in the list. + * + * @returns The next node. + * + * @param pCurNode The current node. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListOff32NodeGetNext(pCurNode, Type, Member) \ + RT_FROM_MEMBER(RTLISTOFF32_NEXT_PTR(pCurNode), Type, Member) +/** @copydoc RTListOff32NodeGetNext */ +#define RTListOff32NodeGetNextCpp(pCurNode, Type, Member) \ + RT_FROM_CPP_MEMBER(RTLISTOFF32_NEXT_PTR(pCurNode), Type, Member) + +/** + * Returns the previous node in the list. + * + * @returns The previous node. + * + * @param pCurNode The current node. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListOff32NodeGetPrev(pCurNode, Type, Member) \ + RT_FROM_MEMBER(RTLISTOFF32_PREV_PTR(pCurNode), Type, Member) +/** @copydoc RTListOff32NodeGetPrev */ +#define RTListOff32NodeGetPrevCpp(pCurNode, Type, Member) \ + RT_FROM_CPP_MEMBER(RTLISTOFF32_PREV_PTR(pCurNode), Type, Member) + +/** + * Returns the first element in the list (checks for empty list). + * + * @retval Pointer to the first list element. + * @retval NULL if the list is empty. + * + * @param pList List to get the first element from. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListOff32GetFirst(pList, Type, Member) \ + ((pList)->offNext != 0 ? RTListOff32NodeGetNext(pList, Type, Member) : NULL) +/** @copydoc RTListOff32GetFirst */ +#define RTListOff32GetFirstCpp(pList, Type, Member) \ + ((pList)->offNext != 0 ? RTListOff32NodeGetNextCpp(pList, Type, Member) : NULL) + +/** + * Returns the last element in the list (checks for empty list). + * + * @retval Pointer to the last list element. + * @retval NULL if the list is empty. + * + * @param pList List to get the last element from. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListOff32GetLast(pList, Type, Member) \ + ((pList)->offPrev != 0 ? RTListOff32NodeGetPrev(pList, Type, Member) : NULL) +/** @copydoc RTListOff32GetLast */ +#define RTListOff32GetLastCpp(pList, Type, Member) \ + ((pList)->offPrev != 0 ? RTListOff32NodeGetPrevCpp(pList, Type, Member) : NULL) + +/** + * Returns the next node in the list or NULL if the end has been reached. + * + * @returns The next node or NULL. + * + * @param pList The list @a pCurNode is linked on. + * @param pCurNode The current node, of type @a Type. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListOff32GetNext(pList, pCurNode, Type, Member) \ + ( RTLISTOFF32_NEXT_PTR(&(pCurNode)->Member) != (pList) \ + ? RT_FROM_MEMBER(RTLISTOFF32_NEXT_PTR(&(pCurNode)->Member), Type, Member) : NULL ) +/** @copydoc RTListOff32GetNext */ +#define RTListOff32GetNextCpp(pList, pCurNode, Type, Member) \ + ( RTLISTOFF32_NEXT_PTR(&(pCurNode)->Member) != (pList) \ + ? RT_FROM_CPP_MEMBER(RTLISTOFF32_NEXT_PTR(&(pCurNode)->Member), Type, Member) : NULL ) + +/** + * Returns the previous node in the list or NULL if the start has been reached. + * + * @returns The previous node or NULL. + * + * @param pList The list @a pCurNode is linked on. + * @param pCurNode The current node, of type @a Type. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListOff32GetPrev(pList, pCurNode, Type, Member) \ + ( RTLISTOFF32_PREV_PTR(&(pCurNode)->Member) != (pList) \ + ? RT_FROM_MEMBER(RTLISTOFF32_PREV_PTR(&(pCurNode)->Member), Type, Member) : NULL ) +/** @copydoc RTListOff32GetPrev */ +#define RTListOff32GetPrevCpp(pList, pCurNode, Type, Member) \ + ( RTLISTOFF32_PREV_PTR(&(pCurNode)->Member) != (pList) \ + ? RT_FROM_CPP_MEMBER(RTLISTOFF32_PREV_PTR(&(pCurNode)->Member), Type, Member) : NULL ) + +/** + * Enumerate the list in head to tail order. + * + * @param pList List to enumerate. + * @param pIterator The iterator variable name. + * @param Type Structure the list node is a member of. + * @param Member The list node member name. + */ +#define RTListOff32ForEach(pList, pIterator, Type, Member) \ + for (pIterator = RTListOff32NodeGetNext(pList, Type, Member); \ + !RTListOff32NodeIsDummy(pList, pIterator, Type, Member); \ + pIterator = RT_FROM_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member) ) +/** @copydoc RTListOff32ForEach */ +#define RTListOff32ForEachCpp(pList, pIterator, Type, Member) \ + for (pIterator = RTListOff32NodeGetNextCpp(pList, Type, Member); \ + !RTListOff32NodeIsDummyCpp(pList, pIterator, Type, Member); \ + pIterator = RT_FROM_CPP_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member) ) + + +/** + * Enumerate the list in head to tail order, safe against removal of the + * current node. + * + * @param pList List to enumerate. + * @param pIterator The iterator variable name. + * @param pIterNext The name of the variable saving the pointer to + * the next element. + * @param Type Structure the list node is a member of. + * @param Member The list node member name. + */ +#define RTListOff32ForEachSafe(pList, pIterator, pIterNext, Type, Member) \ + for (pIterator = RTListOff32NodeGetNext(pList, Type, Member), \ + pIterNext = RT_FROM_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member); \ + !RTListOff32NodeIsDummy(pList, pIterator, Type, Member); \ + pIterator = pIterNext, \ + pIterNext = RT_FROM_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member) ) +/** @copydoc RTListOff32ForEachSafe */ +#define RTListOff32ForEachSafeCpp(pList, pIterator, pIterNext, Type, Member) \ + for (pIterator = RTListOff32NodeGetNextCpp(pList, Type, Member), \ + pIterNext = RT_FROM_CPP_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member); \ + !RTListOff32NodeIsDummyCpp(pList, pIterator, Type, Member); \ + pIterator = pIterNext, \ + pIterNext = RT_FROM_CPP_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member) ) + + +/** + * Enumerate the list in reverse order (tail to head). + * + * @param pList List to enumerate. + * @param pIterator The iterator variable name. + * @param Type Structure the list node is a member of. + * @param Member The list node member name. + */ +#define RTListOff32ForEachReverse(pList, pIterator, Type, Member) \ + for (pIterator = RTListOff32NodeGetPrev(pList, Type, Member); \ + !RTListOff32NodeIsDummy(pList, pIterator, Type, Member); \ + pIterator = RT_FROM_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member) ) +/** @copydoc RTListOff32ForEachReverse */ +#define RTListOff32ForEachReverseCpp(pList, pIterator, Type, Member) \ + for (pIterator = RTListOff32NodeGetPrevCpp(pList, Type, Member); \ + !RTListOff32NodeIsDummyCpp(pList, pIterator, Type, Member); \ + pIterator = RT_FROM_CPP_MEMBER(RTLISTOFF32_PREV_PTR(&(pIterator)->Member), Type, Member) ) + + +/** + * Enumerate the list in reverse order (tail to head). + * + * @param pList List to enumerate. + * @param pIterator The iterator variable name. + * @param pIterPrev The name of the variable saving the pointer to + * the previous element. + * @param Type Structure the list node is a member of. + * @param Member The list node member name. + */ +#define RTListOff32ForEachReverseSafe(pList, pIterator, pIterPrev, Type, Member) \ + for (pIterator = RTListOff32NodeGetPrev(pList, Type, Member), \ + pIterPrev = RT_FROM_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member); \ + !RTListOff32NodeIsDummy(pList, pIterator, Type, Member); \ + pIterator = pIterPrev, \ + pIterPrev = RT_FROM_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member) ) +/** @copydoc RTListOff32ForEachReverseSafe */ +#define RTListOff32ForEachReverseSafeCpp(pList, pIterator, pIterPrev, Type, Member) \ + for (pIterator = RTListOff32NodeGetPrevCpp(pList, Type, Member), \ + pIterPrev = RT_FROM_CPP_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member); \ + !RTListOff32NodeIsDummyCpp(pList, pIterator, Type, Member); \ + pIterator = pIterPrev, \ + pIterPrev = RT_FROM_CPP_MEMBER(RTLISTOFF32_NEXT_PTR(&(pIterator)->Member), Type, Member) ) + + +/** + * Move the given list to a new list header. + * + * @param pListDst The new list. + * @param pListSrc The list to move. + */ +DECLINLINE(void) RTListOff32Move(PRTLISTOFF32NODE pListDst, PRTLISTOFF32NODE pListSrc) +{ + if (!RTListOff32IsEmpty(pListSrc)) + { + PRTLISTOFF32NODE pFirst = RTLISTOFF32_NEXT_PTR(pListSrc); + PRTLISTOFF32NODE pLast = RTLISTOFF32_PREV_PTR(pListSrc); + + RTLISTOFF32_SET_NEXT_PTR(pListDst, pFirst); + RTLISTOFF32_SET_PREV_PTR(pListDst, pLast); + + /* Adjust the first and last element links */ + RTLISTOFF32_SET_NEXT_PTR(pLast, pListDst); + RTLISTOFF32_SET_PREV_PTR(pFirst, pListDst); + + /* Finally remove the elements from the source list */ + RTListOff32Init(pListSrc); + } +} + +/** + * List concatenation. + * + * @returns nothing. + * @param pListDst The destination list. + * @param pListSrc The source list to concatenate. + */ +DECLINLINE(void) RTListOff32Concatenate(PRTLISTOFF32ANCHOR pListDst, PRTLISTOFF32ANCHOR pListSrc) +{ + if (!RTListOff32IsEmpty(pListSrc)) + { + PRTLISTOFF32NODE pFirstSrc = RTLISTOFF32_NEXT_PTR(pListSrc); + PRTLISTOFF32NODE pLastSrc = RTLISTOFF32_PREV_PTR(pListSrc); + PRTLISTOFF32NODE pLastDst = RTLISTOFF32_PREV_PTR(pListDst); + + RTLISTOFF32_SET_NEXT_PTR(pLastDst, pFirstSrc); + RTLISTOFF32_SET_PREV_PTR(pFirstSrc, pLastDst); + + RTLISTOFF32_SET_NEXT_PTR(pLastSrc, pListDst); + RTLISTOFF32_SET_PREV_PTR(pListDst, pLastSrc); + + /* Finally remove the elements from the source list */ + RTListOff32Init(pListSrc); + } +} + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_list_off32_h */ + diff --git a/include/iprt/list.h b/include/iprt/list.h new file mode 100644 index 00000000..dbc1946f --- /dev/null +++ b/include/iprt/list.h @@ -0,0 +1,560 @@ +/** @file + * IPRT - Generic Doubly Linked List. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_list_h +#define IPRT_INCLUDED_list_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/** @defgroup grp_rt_list RTList - Generic Doubly Linked List + * @ingroup grp_rt + * + * The list implementation is circular without any type wise distintion between + * the list and its nodes. This can be confusing since the list head usually + * resides in a different structure than the nodes, so care must be taken when + * walking the list. + * + * @{ + */ + +RT_C_DECLS_BEGIN + +/** + * A list node of a doubly linked list. + */ +typedef struct RTLISTNODE +{ + /** Pointer to the next list node. */ + struct RTLISTNODE *pNext; + /** Pointer to the previous list node. */ + struct RTLISTNODE *pPrev; +} RTLISTNODE; +/** Pointer to a list node. */ +typedef RTLISTNODE *PRTLISTNODE; +/** Pointer to a const list node. */ +typedef RTLISTNODE const *PCRTLISTNODE; +/** Pointer to a list node pointer. */ +typedef PRTLISTNODE *PPRTLISTNODE; + +/** The anchor (head/tail) of a doubly linked list. + * + * @remarks Please use this instead of RTLISTNODE to indicate a list + * head/tail. It makes the code so much easier to read. Also, + * always mention the actual list node type(s) in the comment. */ +typedef RTLISTNODE RTLISTANCHOR; +/** Pointer to a doubly linked list anchor. */ +typedef RTLISTANCHOR *PRTLISTANCHOR; +/** Pointer to a const doubly linked list anchor. */ +typedef RTLISTANCHOR const *PCRTLISTANCHOR; + +/** Version of RTLISTNODE for holding a ring-3 only list in data which gets + * shared between multiple contexts. */ +#ifdef IN_RING3 +typedef RTLISTNODE RTLISTNODER3; +#else +typedef struct { RTR3PTR aOffLimits[2]; } RTLISTNODER3; +#endif +/** Version of RTLISTANCHOR for holding a ring-3 only list in data which gets + * shared between multiple contexts. */ +typedef RTLISTNODER3 RTLISTANCHORR3; + +/** Version of RTLISTNODE for holding a ring-0 only list in data which gets + * shared between multiple contexts. */ +#ifdef IN_RING0 +typedef RTLISTNODE RTLISTNODER0; +#else +typedef struct { RTR0PTR aOffLimits[2]; } RTLISTNODER0; +#endif +/** Version of RTLISTANCHOR for holding a ring-0 only list in data which gets + * shared between multiple contexts. */ +typedef RTLISTNODER0 RTLISTANCHORR0; + + +/** + * Initialize a list. + * + * @param pList Pointer to an unitialised list. + */ +DECLINLINE(void) RTListInit(PRTLISTNODE pList) +{ + pList->pNext = pList; + pList->pPrev = pList; +} + +/** + * Append a node to the end of the list. + * + * @param pList The list to append the node to. + * @param pNode The node to append. + */ +DECLINLINE(void) RTListAppend(PRTLISTNODE pList, PRTLISTNODE pNode) +{ + pList->pPrev->pNext = pNode; + pNode->pPrev = pList->pPrev; + pNode->pNext = pList; + pList->pPrev = pNode; +} + +/** + * Add a node as the first element of the list. + * + * @param pList The list to prepend the node to. + * @param pNode The node to prepend. + */ +DECLINLINE(void) RTListPrepend(PRTLISTNODE pList, PRTLISTNODE pNode) +{ + pList->pNext->pPrev = pNode; + pNode->pNext = pList->pNext; + pNode->pPrev = pList; + pList->pNext = pNode; +} + +/** + * Inserts a node after the specified one. + * + * @param pCurNode The current node. + * @param pNewNode The node to insert. + */ +DECLINLINE(void) RTListNodeInsertAfter(PRTLISTNODE pCurNode, PRTLISTNODE pNewNode) +{ + RTListPrepend(pCurNode, pNewNode); +} + +/** + * Inserts a node before the specified one. + * + * @param pCurNode The current node. + * @param pNewNode The node to insert. + */ +DECLINLINE(void) RTListNodeInsertBefore(PRTLISTNODE pCurNode, PRTLISTNODE pNewNode) +{ + RTListAppend(pCurNode, pNewNode); +} + +/** + * Remove a node from a list. + * + * @param pNode The node to remove. + */ +DECLINLINE(void) RTListNodeRemove(PRTLISTNODE pNode) +{ + PRTLISTNODE pPrev = pNode->pPrev; + PRTLISTNODE pNext = pNode->pNext; + + pPrev->pNext = pNext; + pNext->pPrev = pPrev; + + /* poison */ + pNode->pNext = NULL; + pNode->pPrev = NULL; +} + + +/** + * Remove a node from a list, returns value. + * + * @returns pNode + * @param pNode The node to remove. + */ +DECLINLINE(PRTLISTNODE) RTListNodeRemoveRet(PRTLISTNODE pNode) +{ + PRTLISTNODE pPrev = pNode->pPrev; + PRTLISTNODE pNext = pNode->pNext; + + pPrev->pNext = pNext; + pNext->pPrev = pPrev; + + /* poison */ + pNode->pNext = NULL; + pNode->pPrev = NULL; + + return pNode; +} + +/** + * Checks if a node is the last element in the list. + * + * @retval true if the node is the last element in the list. + * @retval false otherwise + * + * @param pList The list. + * @param pNode The node to check. + */ +#define RTListNodeIsLast(pList, pNode) ((pNode)->pNext == (pList)) + +/** + * Checks if a node is the first element in the list. + * + * @retval true if the node is the first element in the list. + * @retval false otherwise. + * + * @param pList The list. + * @param pNode The node to check. + */ +#define RTListNodeIsFirst(pList, pNode) ((pNode)->pPrev == (pList)) + +/** + * Checks if a type converted node is actually the dummy element (@a pList). + * + * @retval true if the node is the dummy element in the list. + * @retval false otherwise. + * + * @param pList The list. + * @param pNode The node structure to check. Typically + * something obtained from RTListNodeGetNext() or + * RTListNodeGetPrev(). This is NOT a PRTLISTNODE + * but something that contains a RTLISTNODE member! + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListNodeIsDummy(pList, pNode, Type, Member) \ + ( (pNode) == RT_FROM_MEMBER((pList), Type, Member) ) +/** @copydoc RTListNodeIsDummy */ +#define RTListNodeIsDummyCpp(pList, pNode, Type, Member) \ + ( (pNode) == RT_FROM_CPP_MEMBER((pList), Type, Member) ) + +/** + * Checks if a list is empty. + * + * @retval true if the list is empty. + * @retval false otherwise. + * + * @param pList The list to check. + */ +#define RTListIsEmpty(pList) ((pList)->pPrev == (pList)) + +/** + * Returns the next node in the list. + * + * @returns The next node. + * + * @param pCurNode The current node. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListNodeGetNext(pCurNode, Type, Member) \ + RT_FROM_MEMBER((pCurNode)->pNext, Type, Member) +/** @copydoc RTListNodeGetNext */ +#define RTListNodeGetNextCpp(pCurNode, Type, Member) \ + RT_FROM_CPP_MEMBER((pCurNode)->pNext, Type, Member) + +/** + * Returns the previous node in the list. + * + * @returns The previous node. + * + * @param pCurNode The current node. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListNodeGetPrev(pCurNode, Type, Member) \ + RT_FROM_MEMBER((pCurNode)->pPrev, Type, Member) +/** @copydoc RTListNodeGetPrev */ +#define RTListNodeGetPrevCpp(pCurNode, Type, Member) \ + RT_FROM_CPP_MEMBER((pCurNode)->pPrev, Type, Member) + +/** + * Returns the first element in the list (checks for empty list). + * + * @returns Pointer to the first list element, or NULL if empty list. + * + * @param pList List to get the first element from. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListGetFirst(pList, Type, Member) \ + (!RTListIsEmpty(pList) ? RTListNodeGetNext(pList, Type, Member) : NULL) +/** @copydoc RTListGetFirst */ +#define RTListGetFirstCpp(pList, Type, Member) \ + (!RTListIsEmpty(pList) ? RTListNodeGetNextCpp(pList, Type, Member) : NULL) + +/** + * Returns the last element in the list (checks for empty list). + * + * @returns Pointer to the last list element, or NULL if empty list. + * + * @param pList List to get the last element from. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListGetLast(pList, Type, Member) \ + (!RTListIsEmpty(pList) ? RTListNodeGetPrev(pList, Type, Member) : NULL) +/** @copydoc RTListGetLast */ +#define RTListGetLastCpp(pList, Type, Member) \ + (!RTListIsEmpty(pList) ? RTListNodeGetPrevCpp(pList, Type, Member) : NULL) + +/** + * Returns the next node in the list or NULL if the end has been reached. + * + * @returns The next node, or NULL if end of list. + * + * @param pList The list @a pCurNode is linked on. + * @param pCurNode The current node, of type @a Type. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListGetNext(pList, pCurNode, Type, Member) \ + ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_MEMBER((pCurNode)->Member.pNext, Type, Member) : NULL ) +/** @copydoc RTListGetNext */ +#define RTListGetNextCpp(pList, pCurNode, Type, Member) \ + ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_CPP_MEMBER((pCurNode)->Member.pNext, Type, Member) : NULL ) + +/** + * Returns the previous node in the list or NULL if the start has been reached. + * + * @returns The previous node, or NULL if end of list. + * + * @param pList The list @a pCurNode is linked on. + * @param pCurNode The current node, of type @a Type. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListGetPrev(pList, pCurNode, Type, Member) \ + ( (pCurNode)->Member.pPrev != (pList) ? RT_FROM_MEMBER((pCurNode)->Member.pPrev, Type, Member) : NULL ) +/** @copydoc RTListGetPrev */ +#define RTListGetPrevCpp(pList, pCurNode, Type, Member) \ + ( (pCurNode)->Member.pPrev != (pList) ? RT_FROM_CPP_MEMBER((pCurNode)->Member.pPrev, Type, Member) : NULL ) + + +/** + * Removes and returns the first element in the list (checks for empty list). + * + * @returns Pointer to the first list element, or NULL if empty list. + * + * @param pList List to get the first element from. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListRemoveFirst(pList, Type, Member) \ + (!RTListIsEmpty(pList) ? RT_FROM_MEMBER(RTListNodeRemoveRet((pList)->pNext), Type, Member) : NULL) +/** @copydoc RTListRemoveFirst */ +#define RTListRemoveFirstCpp(pList, Type, Member) \ + (!RTListIsEmpty(pList) ? RT_FROM_CPP_MEMBER(RTListNodeRemoveRet((pList)->pNext), Type, Member) : NULL) + +/** + * Removes and returns the last element in the list (checks for empty list). + * + * @returns Pointer to the last list element, or NULL if empty list. + * + * @param pList List to get the last element from. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListRemoveLast(pList, Type, Member) \ + (!RTListIsEmpty(pList) ? RT_FROM_MEMBER(RTListNodeRemoveRet((pList)->pPrev), Type, Member) : NULL) +/** @copydoc RTListRemoveLast */ +#define RTListRemoveLastCpp(pList, Type, Member) \ + (!RTListIsEmpty(pList) ? RT_FROM_CPP_MEMBER(RTListNodeRemoveRet((pList)->pPrev), Type, Member) : NULL) + +/** + * Removes and returns the next node in the list or NULL if the end has been + * reached. + * + * @returns The next node, or NULL if end of list. + * + * @param pList The list @a pCurNode is linked on. + * @param pCurNode The current node, of type @a Type. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListRemoveNext(pList, pCurNode, Type, Member) \ + ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_MEMBER(RTListNodeRemoveRet((pCurNode)->Member.pNext), Type, Member) : NULL ) +/** @copydoc RTListRemoveNext */ +#define RTListRemoveNextCpp(pList, pCurNode, Type, Member) \ + ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_CPP_MEMBER(RTListNodeRemoveRet((pCurNode)->Member.pNext), Type, Member) : NULL ) + +/** + * Removes and returns the previous node in the list or NULL if the start has + * been reached. + * + * @returns The previous node, or NULL if end of list. + * + * @param pList The list @a pCurNode is linked on. + * @param pCurNode The current node, of type @a Type. + * @param Type Structure the list node is a member of. + * @param Member The list node member. + */ +#define RTListRemovePrev(pList, pCurNode, Type, Member) \ + ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_MEMBER(RTListNodeRemoveRet((pCurNode)->Member.pPrev), Type, Member) : NULL ) +/** @copydoc RTListRemovePrev */ +#define RTListRemovePrevCpp(pList, pCurNode, Type, Member) \ + ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_CPP_MEMBER(RTListNodeRemoveRet((pCurNode)->Member.pPrev), Type, Member) : NULL ) + + +/** + * Enumerate the list in head to tail order. + * + * @param pList List to enumerate. + * @param pIterator The iterator variable name. + * @param Type Structure the list node is a member of. + * @param Member The list node member name. + */ +#define RTListForEach(pList, pIterator, Type, Member) \ + for (pIterator = RTListNodeGetNext(pList, Type, Member); \ + !RTListNodeIsDummy(pList, pIterator, Type, Member); \ + pIterator = RT_FROM_MEMBER((pIterator)->Member.pNext, Type, Member) ) +/** @copydoc RTListForEach */ +#define RTListForEachCpp(pList, pIterator, Type, Member) \ + for (pIterator = RTListNodeGetNextCpp(pList, Type, Member); \ + !RTListNodeIsDummyCpp(pList, pIterator, Type, Member); \ + pIterator = RT_FROM_CPP_MEMBER((pIterator)->Member.pNext, Type, Member) ) + + +/** + * Enumerate the list in head to tail order, safe against removal of the + * current node. + * + * @param pList List to enumerate. + * @param pIterator The iterator variable name. + * @param pIterNext The name of the variable saving the pointer to + * the next element. + * @param Type Structure the list node is a member of. + * @param Member The list node member name. + */ +#define RTListForEachSafe(pList, pIterator, pIterNext, Type, Member) \ + for (pIterator = RTListNodeGetNext(pList, Type, Member), \ + pIterNext = RT_FROM_MEMBER((pIterator)->Member.pNext, Type, Member); \ + !RTListNodeIsDummy(pList, pIterator, Type, Member); \ + pIterator = pIterNext, \ + pIterNext = RT_FROM_MEMBER((pIterator)->Member.pNext, Type, Member) ) +/** @copydoc RTListForEachSafe */ +#define RTListForEachSafeCpp(pList, pIterator, pIterNext, Type, Member) \ + for (pIterator = RTListNodeGetNextCpp(pList, Type, Member), \ + pIterNext = RT_FROM_CPP_MEMBER((pIterator)->Member.pNext, Type, Member); \ + !RTListNodeIsDummyCpp(pList, pIterator, Type, Member); \ + pIterator = pIterNext, \ + pIterNext = RT_FROM_CPP_MEMBER((pIterator)->Member.pNext, Type, Member) ) + + +/** + * Enumerate the list in reverse order (tail to head). + * + * @param pList List to enumerate. + * @param pIterator The iterator variable name. + * @param Type Structure the list node is a member of. + * @param Member The list node member name. + */ +#define RTListForEachReverse(pList, pIterator, Type, Member) \ + for (pIterator = RTListNodeGetPrev(pList, Type, Member); \ + !RTListNodeIsDummy(pList, pIterator, Type, Member); \ + pIterator = RT_FROM_MEMBER((pIterator)->Member.pPrev, Type, Member) ) +/** @copydoc RTListForEachReverse */ +#define RTListForEachReverseCpp(pList, pIterator, Type, Member) \ + for (pIterator = RTListNodeGetPrevCpp(pList, Type, Member); \ + !RTListNodeIsDummyCpp(pList, pIterator, Type, Member); \ + pIterator = RT_FROM_CPP_MEMBER((pIterator)->Member.pPrev, Type, Member) ) + + +/** + * Enumerate the list in reverse order (tail to head). + * + * @param pList List to enumerate. + * @param pIterator The iterator variable name. + * @param pIterPrev The name of the variable saving the pointer to + * the previous element. + * @param Type Structure the list node is a member of. + * @param Member The list node member name. + */ +#define RTListForEachReverseSafe(pList, pIterator, pIterPrev, Type, Member) \ + for (pIterator = RTListNodeGetPrev(pList, Type, Member), \ + pIterPrev = RT_FROM_MEMBER((pIterator)->Member.pPrev, Type, Member); \ + !RTListNodeIsDummy(pList, pIterator, Type, Member); \ + pIterator = pIterPrev, \ + pIterPrev = RT_FROM_MEMBER((pIterator)->Member.pPrev, Type, Member) ) +/** @copydoc RTListForEachReverseSafe */ +#define RTListForEachReverseSafeCpp(pList, pIterator, pIterPrev, Type, Member) \ + for (pIterator = RTListNodeGetPrevCpp(pList, Type, Member), \ + pIterPrev = RT_FROM_CPP_MEMBER((pIterator)->Member.pPrev, Type, Member); \ + !RTListNodeIsDummyCpp(pList, pIterator, Type, Member); \ + pIterator = pIterPrev, \ + pIterPrev = RT_FROM_CPP_MEMBER((pIterator)->Member.pPrev, Type, Member) ) + + +/** + * Move the given list to a new list header. + * + * @param pListDst The new list. + * @param pListSrc The list to move. + */ +DECLINLINE(void) RTListMove(PRTLISTNODE pListDst, PRTLISTNODE pListSrc) +{ + if (!RTListIsEmpty(pListSrc)) + { + pListDst->pNext = pListSrc->pNext; + pListDst->pPrev = pListSrc->pPrev; + + /* Adjust the first and last element links */ + pListDst->pNext->pPrev = pListDst; + pListDst->pPrev->pNext = pListDst; + + /* Finally remove the elements from the source list */ + RTListInit(pListSrc); + } + else + RTListInit(pListDst); +} + +/** + * List concatenation. + * + * @returns nothing. + * @param pListDst The destination list. + * @param pListSrc The source list to concatenate. + */ +DECLINLINE(void) RTListConcatenate(PRTLISTANCHOR pListDst, PRTLISTANCHOR pListSrc) +{ + if (!RTListIsEmpty(pListSrc)) + { + PRTLISTNODE pFirst = pListSrc->pNext; + PRTLISTNODE pLast = pListSrc->pPrev; + + pListDst->pPrev->pNext = pFirst; + pFirst->pPrev = pListDst->pPrev; + pLast->pNext = pListDst; + pListDst->pPrev = pLast; + + /* Finally remove the elements from the source list */ + RTListInit(pListSrc); + } +} + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_list_h */ diff --git a/include/iprt/locale.h b/include/iprt/locale.h new file mode 100644 index 00000000..3a83a5f5 --- /dev/null +++ b/include/iprt/locale.h @@ -0,0 +1,113 @@ +/** @file + * IPRT - Locale and Related Info. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_locale_h +#define IPRT_INCLUDED_locale_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_locale RTLocale - Locale and Related Info + * @ingroup grp_rt + * @{ + */ + +/** + * Returns the setlocale(LC_ALL,NULL) return value. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if not supported. + * @param pszName Where to return the name. + * @param cbName The size of the name buffer. + */ +RTDECL(int) RTLocaleQueryLocaleName(char *pszName, size_t cbName); + +/** + * Returns a normalized base locale name ('{ll}_{CC}' or 'C'). + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if not supported. + * @param pszName Where to return the name. + * @param cbName The size of the name buffer. + * + * @sa RTLOCALE_IS_LANGUAGE2_UNDERSCORE_COUNTRY2 + */ +RTDECL(int) RTLocaleQueryNormalizedBaseLocaleName(char *pszName, size_t cbName); + +/** + * Gets the two letter country code (ISO 3166-1 alpha-2) for the current user. + * + * This is not necessarily the country from the locale name, when possible the + * source is a different setting (host specific). + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if not supported. + * @param pszCountryCode Pointer buffer that's at least three bytes in size. + * The country code will be returned here on success. + */ +RTDECL(int) RTLocaleQueryUserCountryCode(char pszCountryCode[3]); + + +/** + * Checks whether @a a_psz seems to start with a + * language-code-underscore-country-code sequence. + * + * We perform a check for a likely ISO 639-1 language code, followed by an + * underscore, followed by a likely ISO 3166-1 alpha-2 country code. + * + * @return true if probable '{ll}_{CC}' sequence, false if surely not. + * @param a_psz The string to test the start of. + * + * @note User must include iprt/ctype.h separately. + */ +#define RTLOCALE_IS_LANGUAGE2_UNDERSCORE_COUNTRY2(a_psz) \ + ( RT_C_IS_LOWER((a_psz)[0]) \ + && RT_C_IS_LOWER((a_psz)[1]) \ + && (a_psz)[2] == '_' \ + && RT_C_IS_UPPER((a_psz)[3]) \ + && RT_C_IS_UPPER((a_psz)[4]) ) + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_locale_h */ + diff --git a/include/iprt/localipc.h b/include/iprt/localipc.h new file mode 100644 index 00000000..e5baa5ab --- /dev/null +++ b/include/iprt/localipc.h @@ -0,0 +1,354 @@ +/** @file + * IPRT - Local IPC Server & Client. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_localipc_h +#define IPRT_INCLUDED_localipc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/thread.h> + +#ifdef IN_RING0 +# error "There are no RTLocalIpc APIs available Ring-0 Host Context!" +#endif + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_localipc RTLocalIpc - Local IPC + * @ingroup grp_rt + * @{ + */ + +/** Handle to a local IPC server instance. */ +typedef struct RTLOCALIPCSERVERINT *RTLOCALIPCSERVER; +/** Pointer to a local IPC server handle. */ +typedef RTLOCALIPCSERVER *PRTLOCALIPCSERVER; +/** Local IPC server handle nil value. */ +#define NIL_RTLOCALIPCSERVER ((RTLOCALIPCSERVER)0) + +/** Handle to a local ICP session instance. */ +typedef struct RTLOCALIPCSESSIONINT *RTLOCALIPCSESSION; +/** Pointer to a local ICP session handle. */ +typedef RTLOCALIPCSESSION *PRTLOCALIPCSESSION; +/** Local ICP session handle nil value. */ +#define NIL_RTLOCALIPCSESSION ((RTLOCALIPCSESSION)0) + + + +/** + * Create a local IPC server. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success and *phServer containing the instance handle. + * + * @param phServer Where to put the server instance handle. + * @param pszName The server name. This must be unique and not include + * any special chars or slashes. It will be morphed into a + * unique platform specific identifier. + * @param fFlags Flags, see RTLOCALIPC_FLAGS_*. + */ +RTDECL(int) RTLocalIpcServerCreate(PRTLOCALIPCSERVER phServer, const char *pszName, uint32_t fFlags); + +/** @name RTLocalIpcServerCreate flags + * @{ */ +/** Native name, as apposed to a portable one. */ +#define RTLOCALIPC_FLAGS_NATIVE_NAME RT_BIT_32(0) +/** The mask of valid flags. */ +#define RTLOCALIPC_FLAGS_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Destroys a local IPC server. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if still other references or NIL. + * @retval VINF_OBJECT_DESTROYED if actually destroyed. + * + * @param hServer The server handle. The nil value is quietly ignored (VINF_SUCCESS). + */ +RTDECL(int) RTLocalIpcServerDestroy(RTLOCALIPCSERVER hServer); + +/** + * Grant the specified group access to the local IPC server socket. + * + * @returns IPRT status code. + * @param hServer The server handle. + * @param gid Group ID. + */ +RTDECL(int) RTLocalIpcServerGrantGroupAccess(RTLOCALIPCSERVER hServer, RTGID gid); + +/** + * Set access mode for IPC server socket. + * + * @returns IPRT status code. + * @param hServer The server handle. + * @param fMode Access mode. + */ +RTDECL(int) RTLocalIpcServerSetAccessMode(RTLOCALIPCSERVER hServer, RTFMODE fMode); + +/** + * Listen for clients. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success and *phClientSession containing the session handle. + * @retval VERR_CANCELLED if the listening was interrupted by RTLocalIpcServerCancel(). + * + * @param hServer The server handle. + * @param phClientSession Where to store the client session handle on success. + * + */ +RTDECL(int) RTLocalIpcServerListen(RTLOCALIPCSERVER hServer, PRTLOCALIPCSESSION phClientSession); + +/** + * Cancel the current or subsequent RTLocalIpcServerListen call. + * + * @returns IPRT status code. + * @param hServer The server handle. The nil value is quietly ignored (VINF_SUCCESS). + */ +RTDECL(int) RTLocalIpcServerCancel(RTLOCALIPCSERVER hServer); + + +/** + * Connects to a local IPC server. + * + * This is used a client process (or thread). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success and *phSession holding the session handle. + * + * @param phSession Where to store the sesson handle on success. + * @param pszName The server name (see RTLocalIpcServerCreate for details). + * @param fFlags Flags, RTLOCALIPC_C_FLAGS_XXX. + */ +RTDECL(int) RTLocalIpcSessionConnect(PRTLOCALIPCSESSION phSession, const char *pszName, uint32_t fFlags); + +/** @name RTLOCALIPC_C_FLAGS_XXX - RTLocalIpcSessionConnect flags + * @{ */ +/** Native name, as apposed to a portable one. */ +#define RTLOCALIPC_C_FLAGS_NATIVE_NAME RT_BIT_32(0) +/** The mask of valid flags. */ +#define RTLOCALIPC_C_FLAGS_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Closes the local IPC session. + * + * This can be used with sessions created by both RTLocalIpcSessionConnect + * and RTLocalIpcServerListen. It will release one cancel pending I/O and + * relase one reference (typically the implict reference from the create API). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if still other references or NIL. + * @retval VINF_OBJECT_DESTROYED if session destroyed. + * + * @param hSession The session handle. The nil value is quietly ignored (VINF_SUCCESS). + */ +RTDECL(int) RTLocalIpcSessionClose(RTLOCALIPCSESSION hSession); + +/** + * Retain a refence to the given session. + * + * @returns New reference count, UINT32_MAX if the handle is invalid. + * @param hSession The session handle. + */ +RTDECL(uint32_t) RTLocalIpcSessionRetain(RTLOCALIPCSESSION hSession); + +/** + * Releases a refence to the given session. + * + * This differs from RTLocalIpcSessionClose in that it won't cancel any pending + * I/O. So, better call RTLocalIpcSessionClose if you want to terminate the + * session. + * + * @returns New reference count, 0 if NIL handle, UINT32_MAX if the handle is + * invalid. + * @param hSession The session handle. + */ +RTDECL(uint32_t) RTLocalIpcSessionRelease(RTLOCALIPCSESSION hSession); + + +/** + * Receive data from the other end of an local IPC session. + * + * This will block if there isn't any data. + * + * @returns IPRT status code. + * @retval VERR_CANCELLED if the operation was cancelled by RTLocalIpcSessionCancel. + * + * @param hSession The session handle. + * @param pvBuf Where to store the data. + * @param cbToRead How much to read. This is exact request if + * pcbRead is NULL, otherwise it's an upper limit. + * @param pcbRead Optional argument for indicating a partial read + * and returning the number of bytes actually read. + */ +RTDECL(int) RTLocalIpcSessionRead(RTLOCALIPCSESSION hSession, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Receive pending data from the other end of an local IPC session. + * + * This will not block to wait for data. + * + * @returns IPRT status code. + * @retval VINF_TRY_AGAIN if no pending data (*pcbRead is set to 0). + * @retval VERR_CANCELLED if a previous operation was cancelled by + * RTLocalIpcSessionCancel (this operation isn't cancellable). + * + * @param hSession The session handle. + * @param pvBuf Where to store the data. + * @param cbToRead How much to read (upper limit). + * @param pcbRead Where to return exactly how much was read. + */ +RTDECL(int) RTLocalIpcSessionReadNB(RTLOCALIPCSESSION hSession, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Send data to the other end of an local IPC session. + * + * This may or may not block until the data is received by the other party, + * this is an implementation detail. If you want to make sure that the data + * has been received you should always call RTLocalIpcSessionFlush(). + * + * @returns IPRT status code. + * @retval VERR_CANCELLED if the operation was cancelled by RTLocalIpcSessionCancel. + * + * @param hSession The session handle. + * @param pvBuf The data to write. + * @param cbToWrite How much to write. + */ +RTDECL(int) RTLocalIpcSessionWrite(RTLOCALIPCSESSION hSession, const void *pvBuf, size_t cbToWrite); + +/** + * Flush any buffered data and (perhaps) wait for the other party to receive it. + * + * The waiting for the other party to receive the data is + * implementation dependent. + * + * @returns IPRT status code. + * @retval VERR_CANCELLED if the operation was cancelled by RTLocalIpcSessionCancel. + * + * @param hSession The session handle. + */ +RTDECL(int) RTLocalIpcSessionFlush(RTLOCALIPCSESSION hSession); + +/** + * Wait for data to become ready for reading or for the session to be + * disconnected. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS when there is data to read. + * @retval VERR_TIMEOUT if no data became available within the specified period (@a cMillies) + * @retval VERR_BROKEN_PIPE if the session was disconnected. + * @retval VERR_CANCELLED if the operation was cancelled by RTLocalIpcSessionCancel. + * + * @param hSession The session handle. + * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT + * to wait forever. + * + * @remark VERR_INTERRUPTED will not be returned. If this is desired at some later point + * add a RTLocalIpcSessionWaitForDataNoResume() variant like we're using elsewhere. + */ +RTDECL(int) RTLocalIpcSessionWaitForData(RTLOCALIPCSESSION hSession, uint32_t cMillies); + +/** + * Cancells a pending or subsequent operation. + * + * Not all methods are cancellable, only those which are specfied + * returning VERR_CANCELLED. The others are assumed to not be blocking + * for ever and ever. However, the cancel is sticky, so the session must + * basically be trashed (closed) after calling this method. + * + * @returns IPRT status code. + * + * @param hSession The session handle. + */ +RTDECL(int) RTLocalIpcSessionCancel(RTLOCALIPCSESSION hSession); + +/** + * Query the process ID of the other party. + * + * This is an optional feature which may not be implemented, so don't + * depend on it and check for VERR_NOT_SUPPORTED. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and *pProcess on success. + * @retval VERR_CANCELLED if the operation was cancelled by RTLocalIpcSessionCancel. + * @retval VERR_NOT_SUPPORTED and *pProcess = NIL_RTPROCESS if not supported. + * + * @param hSession The session handle. + * @param pProcess Where to store the process ID. + */ +RTDECL(int) RTLocalIpcSessionQueryProcess(RTLOCALIPCSESSION hSession, PRTPROCESS pProcess); + +/** + * Query the user ID of the other party. + * + * This is an optional feature which may not be implemented, so don't + * depend on it and check for VERR_NOT_SUPPORTED. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and *pUid on success. + * @retval VERR_CANCELLED if the operation was cancelled by RTLocalIpcSessionCancel. + * @retval VERR_NOT_SUPPORTED and *pUid = NIL_RTUID if not supported. + * + * @param hSession The session handle. + * @param pUid Where to store the user ID on success. + */ +RTDECL(int) RTLocalIpcSessionQueryUserId(RTLOCALIPCSESSION hSession, PRTUID pUid); + +/** + * Query the group ID of the other party. + * + * This is an optional feature which may not be implemented, so don't + * depend on it and check for VERR_NOT_SUPPORTED. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and *pUid on success. + * @retval VERR_CANCELLED if the operation was cancelled by RTLocalIpcSessionCancel. + * @retval VERR_NOT_SUPPORTED and *pGid = NIL_RTUID if not supported. + * + * @param hSession The session handle. + * @param pGid Where to store the group ID on success. + */ +RTDECL(int) RTLocalIpcSessionQueryGroupId(RTLOCALIPCSESSION hSession, PRTGID pGid); + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_localipc_h */ + diff --git a/include/iprt/lockvalidator.h b/include/iprt/lockvalidator.h new file mode 100644 index 00000000..829ed9f2 --- /dev/null +++ b/include/iprt/lockvalidator.h @@ -0,0 +1,1143 @@ +/** @file + * IPRT - Lock Validator. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_lockvalidator_h +#define IPRT_INCLUDED_lockvalidator_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/assert.h> +#include <iprt/thread.h> +#include <iprt/stdarg.h> + + +/** @defgroup grp_rtlockval RTLockValidator - Lock Validator + * @ingroup grp_rt + * @{ + */ + +RT_C_DECLS_BEGIN + +/** Pointer to a record union. + * @internal */ +typedef union RTLOCKVALRECUNION *PRTLOCKVALRECUNION; + +/** + * Source position. + */ +typedef struct RTLOCKVALSRCPOS +{ + /** The file where the lock was taken. */ + R3R0PTRTYPE(const char * volatile) pszFile; + /** The function where the lock was taken. */ + R3R0PTRTYPE(const char * volatile) pszFunction; + /** Some ID indicating where the lock was taken, typically an address. */ + RTHCUINTPTR volatile uId; + /** The line number in the file. */ + uint32_t volatile uLine; +#if HC_ARCH_BITS == 64 + uint32_t u32Padding; /**< Alignment padding. */ +#endif +} RTLOCKVALSRCPOS; +AssertCompileSize(RTLOCKVALSRCPOS, HC_ARCH_BITS == 32 ? 16 : 32); +/* The pointer types are defined in iprt/types.h. */ + +/** @def RTLOCKVALSRCPOS_INIT + * Initializer for a RTLOCKVALSRCPOS variable. + * + * @param pszFile The file name. Optional (NULL). + * @param uLine The line number in that file. Optional (0). + * @param pszFunction The function. Optional (NULL). + * @param uId Some location ID, normally the return address. + * Optional (NULL). + */ +#if HC_ARCH_BITS == 64 +# define RTLOCKVALSRCPOS_INIT(pszFile, uLine, pszFunction, uId) \ + { (pszFile), (pszFunction), (uId), (uLine), 0 } +#else +# define RTLOCKVALSRCPOS_INIT(pszFile, uLine, pszFunction, uId) \ + { (pszFile), (pszFunction), (uId), (uLine) } +#endif + +/** @def RTLOCKVALSRCPOS_INIT_DEBUG_API + * Initializer for a RTLOCKVALSRCPOS variable in a typicial debug API + * variant. Assumes RT_SRC_POS_DECL and RTHCUINTPTR uId as arguments. + */ +#define RTLOCKVALSRCPOS_INIT_DEBUG_API() \ + RTLOCKVALSRCPOS_INIT(pszFile, iLine, pszFunction, uId) + +/** @def RTLOCKVALSRCPOS_INIT_NORMAL_API + * Initializer for a RTLOCKVALSRCPOS variable in a normal API + * variant. Assumes iprt/asm.h is included. + */ +#define RTLOCKVALSRCPOS_INIT_NORMAL_API() \ + RTLOCKVALSRCPOS_INIT(__FILE__, __LINE__, __PRETTY_FUNCTION__, (uintptr_t)ASMReturnAddress()) + +/** @def RTLOCKVALSRCPOS_INIT_POS_NO_ID + * Initializer for a RTLOCKVALSRCPOS variable when no @c uId is present. + * Assumes iprt/asm.h is included. + */ +#define RTLOCKVALSRCPOS_INIT_POS_NO_ID() \ + RTLOCKVALSRCPOS_INIT(pszFile, iLine, pszFunction, (uintptr_t)ASMReturnAddress()) + + +/** + * Lock validator record core. + */ +typedef struct RTLOCKVALRECORE +{ + /** The magic value indicating the record type. */ + uint32_t volatile u32Magic; +} RTLOCKVALRECCORE; +/** Pointer to a lock validator record core. */ +typedef RTLOCKVALRECCORE *PRTLOCKVALRECCORE; +/** Pointer to a const lock validator record core. */ +typedef RTLOCKVALRECCORE const *PCRTLOCKVALRECCORE; + + +/** + * Record recording the exclusive ownership of a lock. + * + * This is typically part of the per-lock data structure when compiling with + * the lock validator. + */ +typedef struct RTLOCKVALRECEXCL +{ + /** Record core with RTLOCKVALRECEXCL_MAGIC as the magic value. */ + RTLOCKVALRECCORE Core; + /** Whether it's enabled or not. */ + bool fEnabled; + /** Reserved. */ + bool afReserved[3]; + /** Source position where the lock was taken. */ + RTLOCKVALSRCPOS SrcPos; + /** The current owner thread. */ + RTTHREAD volatile hThread; + /** Pointer to the lock record below us. Only accessed by the owner. */ + R3R0PTRTYPE(PRTLOCKVALRECUNION) pDown; + /** Recursion count */ + uint32_t cRecursion; + /** The lock sub-class. */ + uint32_t volatile uSubClass; + /** The lock class. */ + RTLOCKVALCLASS hClass; + /** Pointer to the lock. */ + RTHCPTR hLock; + /** Pointer to the next sibling record. + * This is used to find the read side of a read-write lock. */ + R3R0PTRTYPE(PRTLOCKVALRECUNION) pSibling; + /** The lock name. + * @remarks The bytes beyond 32 are for better size alignment and can be + * taken and used for other purposes if it becomes necessary. */ + char szName[32 + (HC_ARCH_BITS == 32 ? 12 : 8)]; +} RTLOCKVALRECEXCL; +AssertCompileSize(RTLOCKVALRECEXCL, HC_ARCH_BITS == 32 ? 0x60 : 0x80); +/* The pointer type is defined in iprt/types.h. */ + +/** + * For recording the one ownership share. + */ +typedef struct RTLOCKVALRECSHRDOWN +{ + /** Record core with RTLOCKVALRECSHRDOWN_MAGIC as the magic value. */ + RTLOCKVALRECCORE Core; + /** Recursion count */ + uint16_t cRecursion; + /** Static (true) or dynamic (false) allocated record. */ + bool fStaticAlloc; + /** Reserved. */ + bool fReserved; + /** The current owner thread. */ + RTTHREAD volatile hThread; + /** Pointer to the lock record below us. Only accessed by the owner. */ + R3R0PTRTYPE(PRTLOCKVALRECUNION) pDown; + /** Pointer back to the shared record. */ + R3R0PTRTYPE(PRTLOCKVALRECSHRD) pSharedRec; +#if HC_ARCH_BITS == 32 + /** Reserved. */ + RTHCPTR pvReserved; +#endif + /** Source position where the lock was taken. */ + RTLOCKVALSRCPOS SrcPos; +} RTLOCKVALRECSHRDOWN; +AssertCompileSize(RTLOCKVALRECSHRDOWN, HC_ARCH_BITS == 32 ? 24 + 16 : 32 + 32); +/** Pointer to a RTLOCKVALRECSHRDOWN. */ +typedef RTLOCKVALRECSHRDOWN *PRTLOCKVALRECSHRDOWN; + +/** + * Record recording the shared ownership of a lock. + * + * This is typically part of the per-lock data structure when compiling with + * the lock validator. + */ +typedef struct RTLOCKVALRECSHRD +{ + /** Record core with RTLOCKVALRECSHRD_MAGIC as the magic value. */ + RTLOCKVALRECCORE Core; + /** The lock sub-class. */ + uint32_t volatile uSubClass; + /** The lock class. */ + RTLOCKVALCLASS hClass; + /** Pointer to the lock. */ + RTHCPTR hLock; + /** Pointer to the next sibling record. + * This is used to find the write side of a read-write lock. */ + R3R0PTRTYPE(PRTLOCKVALRECUNION) pSibling; + + /** The number of entries in the table. + * Updated before inserting and after removal. */ + uint32_t volatile cEntries; + /** The index of the last entry (approximately). */ + uint32_t volatile iLastEntry; + /** The max table size. */ + uint32_t volatile cAllocated; + /** Set if the table is being reallocated, clear if not. + * This is used together with rtLockValidatorSerializeDetectionEnter to make + * sure there is exactly one thread doing the reallocation and that nobody is + * using the table at that point. */ + bool volatile fReallocating; + /** Whether it's enabled or not. */ + bool fEnabled; + /** Set if event semaphore signaller, clear if read-write semaphore. */ + bool fSignaller; + /** Alignment padding. */ + bool fPadding; + /** Pointer to a table containing pointers to records of all the owners. */ + R3R0PTRTYPE(PRTLOCKVALRECSHRDOWN volatile *) papOwners; + + /** The lock name. + * @remarks The bytes beyond 32 are for better size alignment and can be + * taken and used for other purposes if it becomes necessary. */ + char szName[32 + (HC_ARCH_BITS == 32 ? 8 : 8)]; +} RTLOCKVALRECSHRD; +AssertCompileSize(RTLOCKVALRECSHRD, HC_ARCH_BITS == 32 ? 0x50 : 0x60); + + +/** + * Makes the two records siblings. + * + * @returns VINF_SUCCESS on success, VERR_SEM_LV_INVALID_PARAMETER if either of + * the records are invalid. + * @param pRec1 Record 1. + * @param pRec2 Record 2. + */ +RTDECL(int) RTLockValidatorRecMakeSiblings(PRTLOCKVALRECCORE pRec1, PRTLOCKVALRECCORE pRec2); + +/** + * Initialize a lock validator record. + * + * Use RTLockValidatorRecExclDelete to deinitialize it. + * + * @param pRec The record. + * @param hClass The class (no reference consumed). If NIL, the + * no lock order validation will be performed on + * this lock. + * @param uSubClass The sub-class. This is used to define lock + * order inside the same class. If you don't know, + * then pass RTLOCKVAL_SUB_CLASS_NONE. + * @param hLock The lock handle. + * @param fEnabled Pass @c false to explicitly disable lock + * validation, otherwise @c true. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(void) RTLockValidatorRecExclInit(PRTLOCKVALRECEXCL pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, void *hLock, + bool fEnabled, const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(6, 7); +/** + * Initialize a lock validator record. + * + * Use RTLockValidatorRecExclDelete to deinitialize it. + * + * @param pRec The record. + * @param hClass The class (no reference consumed). If NIL, the + * no lock order validation will be performed on + * this lock. + * @param uSubClass The sub-class. This is used to define lock + * order inside the same class. If you don't know, + * then pass RTLOCKVAL_SUB_CLASS_NONE. + * @param hLock The lock handle. + * @param fEnabled Pass @c false to explicitly disable lock + * validation, otherwise @c true. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param va Format string arguments. + */ +RTDECL(void) RTLockValidatorRecExclInitV(PRTLOCKVALRECEXCL pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, void *hLock, + bool fEnabled, const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(6, 0); +/** + * Uninitialize a lock validator record previously initialized by + * RTLockRecValidatorInit. + * + * @param pRec The record. Must be valid. + */ +RTDECL(void) RTLockValidatorRecExclDelete(PRTLOCKVALRECEXCL pRec); + +/** + * Create and initialize a lock validator record. + * + * Use RTLockValidatorRecExclDestroy to deinitialize and destroy the returned + * record. + * + * @return VINF_SUCCESS or VERR_NO_MEMORY. + * @param ppRec Where to return the record pointer. + * @param hClass The class (no reference consumed). If NIL, the + * no lock order validation will be performed on + * this lock. + * @param uSubClass The sub-class. This is used to define lock + * order inside the same class. If you don't know, + * then pass RTLOCKVAL_SUB_CLASS_NONE. + * @param hLock The lock handle. + * @param fEnabled Pass @c false to explicitly disable lock + * validation, otherwise @c true. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTLockValidatorRecExclCreate(PRTLOCKVALRECEXCL *ppRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, void *hLock, + bool fEnabled, const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(6, 7); + +/** + * Create and initialize a lock validator record. + * + * Use RTLockValidatorRecExclDestroy to deinitialize and destroy the returned + * record. + * + * @return VINF_SUCCESS or VERR_NO_MEMORY. + * @param ppRec Where to return the record pointer. + * @param hClass The class (no reference consumed). If NIL, the + * no lock order validation will be performed on + * this lock. + * @param uSubClass The sub-class. This is used to define lock + * order inside the same class. If you don't know, + * then pass RTLOCKVAL_SUB_CLASS_NONE. + * @param hLock The lock handle. + * @param fEnabled Pass @c false to explicitly disable lock + * validation, otherwise @c true. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param va Format string arguments. + */ +RTDECL(int) RTLockValidatorRecExclCreateV(PRTLOCKVALRECEXCL *ppRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, void *hLock, + bool fEnabled, const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(6, 0); + +/** + * Deinitialize and destroy a record created by RTLockValidatorRecExclCreate. + * + * @param ppRec Pointer to the record pointer. Will be set to + * NULL. + */ +RTDECL(void) RTLockValidatorRecExclDestroy(PRTLOCKVALRECEXCL *ppRec); + +/** + * Sets the sub-class of the record. + * + * It is recommended to try make sure that nobody is using this class while + * changing the value. + * + * @returns The old sub-class. RTLOCKVAL_SUB_CLASS_INVALID is returns if the + * lock validator isn't compiled in or either of the parameters are + * invalid. + * @param pRec The validator record. + * @param uSubClass The new sub-class value. + */ +RTDECL(uint32_t) RTLockValidatorRecExclSetSubClass(PRTLOCKVALRECEXCL pRec, uint32_t uSubClass); + +/** + * Record the specified thread as lock owner and increment the write lock count. + * + * This function is typically called after acquiring the lock. It accounts for + * recursions so it can be used instead of RTLockValidatorRecExclRecursion. Use + * RTLockValidatorRecExclReleaseOwner to reverse the effect. + * + * @param pRec The validator record. + * @param hThreadSelf The handle of the calling thread. If not known, + * pass NIL_RTTHREAD and we'll figure it out. + * @param pSrcPos The source position of the lock operation. + * @param fFirstRecursion Set if it is the first recursion, clear if not + * sure. + */ +RTDECL(void) RTLockValidatorRecExclSetOwner(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf, + PCRTLOCKVALSRCPOS pSrcPos, bool fFirstRecursion); + +/** + * Check the exit order and release (unset) the ownership. + * + * This is called by routines implementing releasing an exclusive lock, + * typically before getting down to the final lock releasing. Can be used for + * recursive releasing instead of RTLockValidatorRecExclUnwind. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_WRONG_RELEASE_ORDER if the order is wrong. Will have + * done all necessary whining and breakpointing before returning. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record. + * @param fFinalRecursion Set if it's the final recursion, clear if not + * sure. + */ +RTDECL(int) RTLockValidatorRecExclReleaseOwner(PRTLOCKVALRECEXCL pRec, bool fFinalRecursion); + +/** + * Clear the lock ownership and decrement the write lock count. + * + * This is only for special cases where we wish to drop lock validation + * recording. See RTLockValidatorRecExclCheckAndRelease. + * + * @param pRec The validator record. + */ +RTDECL(void) RTLockValidatorRecExclReleaseOwnerUnchecked(PRTLOCKVALRECEXCL pRec); + +/** + * Checks and records a lock recursion. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_NESTED if the semaphore class forbids recursion. Gone + * thru the motions. + * @retval VERR_SEM_LV_WRONG_ORDER if the locking order is wrong. Gone thru + * the motions. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record. + * @param pSrcPos The source position of the lock operation. + */ +RTDECL(int) RTLockValidatorRecExclRecursion(PRTLOCKVALRECEXCL pRec, PCRTLOCKVALSRCPOS pSrcPos); + +/** + * Checks and records a lock unwind (releasing one recursion). + * + * This should be coupled with called to RTLockValidatorRecExclRecursion. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_WRONG_RELEASE_ORDER if the release order is wrong. Gone + * thru the motions. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record. + */ +RTDECL(int) RTLockValidatorRecExclUnwind(PRTLOCKVALRECEXCL pRec); + +/** + * Checks and records a mixed recursion. + * + * An example of a mixed recursion is a writer requesting read access to a + * SemRW. + * + * This should be coupled with called to RTLockValidatorRecExclUnwindMixed. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_NESTED if the semaphore class forbids recursion. Gone + * thru the motions. + * @retval VERR_SEM_LV_WRONG_ORDER if the locking order is wrong. Gone thru + * the motions. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record it to accounted it to. + * @param pRecMixed The validator record it came in on. + * @param pSrcPos The source position of the lock operation. + */ +RTDECL(int) RTLockValidatorRecExclRecursionMixed(PRTLOCKVALRECEXCL pRec, PRTLOCKVALRECCORE pRecMixed, PCRTLOCKVALSRCPOS pSrcPos); + +/** + * Checks and records the unwinding of a mixed recursion. + * + * This should be coupled with called to RTLockValidatorRecExclRecursionMixed. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_WRONG_RELEASE_ORDER if the release order is wrong. Gone + * thru the motions. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record it was accounted to. + * @param pRecMixed The validator record it came in on. + */ +RTDECL(int) RTLockValidatorRecExclUnwindMixed(PRTLOCKVALRECEXCL pRec, PRTLOCKVALRECCORE pRecMixed); + +/** + * Check the exclusive locking order. + * + * This is called by routines implementing exclusive lock acquisition. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_WRONG_ORDER if the order is wrong. Will have done all + * necessary whining and breakpointing before returning. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record. + * @param hThreadSelf The handle of the calling thread. If not known, + * pass NIL_RTTHREAD and we'll figure it out. + * @param pSrcPos The source position of the lock operation. + * @param cMillies The timeout, in milliseconds. + */ +RTDECL(int) RTLockValidatorRecExclCheckOrder(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf, + PCRTLOCKVALSRCPOS pSrcPos, RTMSINTERVAL cMillies); + +/** + * Do deadlock detection before blocking on exclusive access to a lock and + * change the thread state. + * + * @retval VINF_SUCCESS - thread is in the specified sleep state. + * @retval VERR_SEM_LV_DEADLOCK if blocking would deadlock. Gone thru the + * motions. + * @retval VERR_SEM_LV_NESTED if the semaphore isn't recursive and hThread is + * already the owner. Gone thru the motions. + * @retval VERR_SEM_LV_ILLEGAL_UPGRADE if it's a deadlock on the same lock. + * The caller must handle any legal upgrades without invoking this + * function (for now). + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record we're blocking on. + * @param hThreadSelf The current thread. Shall not be NIL_RTTHREAD! + * @param pSrcPos The source position of the lock operation. + * @param fRecursiveOk Whether it's ok to recurse. + * @param cMillies The timeout, in milliseconds. + * @param enmSleepState The sleep state to enter on successful return. + * @param fReallySleeping Is it really going to sleep now or not. Use + * false before calls to other IPRT synchronization + * methods. + */ +RTDECL(int) RTLockValidatorRecExclCheckBlocking(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf, + PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk, RTMSINTERVAL cMillies, + RTTHREADSTATE enmSleepState, bool fReallySleeping); + +/** + * RTLockValidatorRecExclCheckOrder and RTLockValidatorRecExclCheckBlocking + * baked into one call. + * + * @returns Any of the statuses returned by the two APIs. + * @param pRec The validator record. + * @param hThreadSelf The current thread. Shall not be NIL_RTTHREAD! + * @param pSrcPos The source position of the lock operation. + * @param fRecursiveOk Whether it's ok to recurse. + * @param cMillies The timeout, in milliseconds. + * @param enmSleepState The sleep state to enter on successful return. + * @param fReallySleeping Is it really going to sleep now or not. Use + * false before calls to other IPRT synchronization + * methods. + */ +RTDECL(int) RTLockValidatorRecExclCheckOrderAndBlocking(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf, + PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk, RTMSINTERVAL cMillies, + RTTHREADSTATE enmSleepState, bool fReallySleeping); + +/** + * Initialize a lock validator record for a shared lock. + * + * Use RTLockValidatorRecSharedDelete to deinitialize it. + * + * @param pRec The shared lock record. + * @param hClass The class (no reference consumed). If NIL, the + * no lock order validation will be performed on + * this lock. + * @param uSubClass The sub-class. This is used to define lock + * order inside the same class. If you don't know, + * then pass RTLOCKVAL_SUB_CLASS_NONE. + * @param hLock The lock handle. + * @param fSignaller Set if event semaphore signaller logic should be + * applied to this record, clear if read-write + * semaphore logic should be used. + * @param fEnabled Pass @c false to explicitly disable lock + * validation, otherwise @c true. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(void) RTLockValidatorRecSharedInit(PRTLOCKVALRECSHRD pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, + void *hLock, bool fSignaller, bool fEnabled, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(7, 8); + +/** + * Initialize a lock validator record for a shared lock. + * + * Use RTLockValidatorRecSharedDelete to deinitialize it. + * + * @param pRec The shared lock record. + * @param hClass The class (no reference consumed). If NIL, the + * no lock order validation will be performed on + * this lock. + * @param uSubClass The sub-class. This is used to define lock + * order inside the same class. If you don't know, + * then pass RTLOCKVAL_SUB_CLASS_NONE. + * @param hLock The lock handle. + * @param fSignaller Set if event semaphore signaller logic should be + * applied to this record, clear if read-write + * semaphore logic should be used. + * @param fEnabled Pass @c false to explicitly disable lock + * validation, otherwise @c true. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param va Format string arguments. + */ +RTDECL(void) RTLockValidatorRecSharedInitV(PRTLOCKVALRECSHRD pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, + void *hLock, bool fSignaller, bool fEnabled, + const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(7, 0); + +/** + * Uninitialize a lock validator record previously initialized by + * RTLockValidatorRecSharedInit. + * + * @param pRec The shared lock record. Must be valid. + */ +RTDECL(void) RTLockValidatorRecSharedDelete(PRTLOCKVALRECSHRD pRec); + +/** + * Create and initialize a lock validator record for a shared lock. + * + * Use RTLockValidatorRecSharedDestroy to deinitialize and destroy the returned + * record. + * + * @returns IPRT status code. + * @param ppRec Where to return the record pointer. + * @param hClass The class (no reference consumed). If NIL, the + * no lock order validation will be performed on + * this lock. + * @param uSubClass The sub-class. This is used to define lock + * order inside the same class. If you don't know, + * then pass RTLOCKVAL_SUB_CLASS_NONE. + * @param pvLock The lock handle or address. + * @param fSignaller Set if event semaphore signaller logic should be + * applied to this record, clear if read-write + * semaphore logic should be used. + * @param fEnabled Pass @c false to explicitly disable lock + * validation, otherwise @c true. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTLockValidatorRecSharedCreate(PRTLOCKVALRECSHRD *ppRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, + void *pvLock, bool fSignaller, bool fEnabled, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(7, 8); + +/** + * Create and initialize a lock validator record for a shared lock. + * + * Use RTLockValidatorRecSharedDestroy to deinitialize and destroy the returned + * record. + * + * @returns IPRT status code. + * @param ppRec Where to return the record pointer. + * @param hClass The class (no reference consumed). If NIL, the + * no lock order validation will be performed on + * this lock. + * @param uSubClass The sub-class. This is used to define lock + * order inside the same class. If you don't know, + * then pass RTLOCKVAL_SUB_CLASS_NONE. + * @param pvLock The lock handle or address. + * @param fSignaller Set if event semaphore signaller logic should be + * applied to this record, clear if read-write + * semaphore logic should be used. + * @param fEnabled Pass @c false to explicitly disable lock + * validation, otherwise @c true. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param va Format string arguments. + */ +RTDECL(int) RTLockValidatorRecSharedCreateV(PRTLOCKVALRECSHRD *ppRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, + void *pvLock, bool fSignaller, bool fEnabled, + const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(7, 0); + +/** + * Deinitialize and destroy a record created by RTLockValidatorRecSharedCreate. + * + * @param ppRec Pointer to the record pointer. Will be set to + * NULL. + */ +RTDECL(void) RTLockValidatorRecSharedDestroy(PRTLOCKVALRECSHRD *ppRec); + +/** + * Sets the sub-class of the record. + * + * It is recommended to try make sure that nobody is using this class while + * changing the value. + * + * @returns The old sub-class. RTLOCKVAL_SUB_CLASS_INVALID is returns if the + * lock validator isn't compiled in or either of the parameters are + * invalid. + * @param pRec The validator record. + * @param uSubClass The new sub-class value. + */ +RTDECL(uint32_t) RTLockValidatorRecSharedSetSubClass(PRTLOCKVALRECSHRD pRec, uint32_t uSubClass); + +/** + * Check the shared locking order. + * + * This is called by routines implementing shared lock acquisition. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_WRONG_ORDER if the order is wrong. Will have done all + * necessary whining and breakpointing before returning. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record. + * @param hThreadSelf The handle of the calling thread. If not known, + * pass NIL_RTTHREAD and we'll figure it out. + * @param pSrcPos The source position of the lock operation. + * @param cMillies Intended sleep time in milliseconds. + */ +RTDECL(int) RTLockValidatorRecSharedCheckOrder(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf, + PCRTLOCKVALSRCPOS pSrcPos, RTMSINTERVAL cMillies); + +/** + * Do deadlock detection before blocking on shared access to a lock and change + * the thread state. + * + * @retval VINF_SUCCESS - thread is in the specified sleep state. + * @retval VERR_SEM_LV_DEADLOCK if blocking would deadlock. Gone thru the + * motions. + * @retval VERR_SEM_LV_NESTED if the semaphore isn't recursive and hThread is + * already the owner. Gone thru the motions. + * @retval VERR_SEM_LV_ILLEGAL_UPGRADE if it's a deadlock on the same lock. + * The caller must handle any legal upgrades without invoking this + * function (for now). + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record we're blocking on. + * @param hThreadSelf The current thread. Shall not be NIL_RTTHREAD! + * @param pSrcPos The source position of the lock operation. + * @param fRecursiveOk Whether it's ok to recurse. + * @param cMillies Intended sleep time in milliseconds. + * @param enmSleepState The sleep state to enter on successful return. + * @param fReallySleeping Is it really going to sleep now or not. Use + * false before calls to other IPRT synchronization + * methods. + */ +RTDECL(int) RTLockValidatorRecSharedCheckBlocking(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf, + PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk, RTMSINTERVAL cMillies, + RTTHREADSTATE enmSleepState, bool fReallySleeping); + +/** + * RTLockValidatorRecSharedCheckOrder and RTLockValidatorRecSharedCheckBlocking + * baked into one call. + * + * @returns Any of the statuses returned by the two APIs. + * @param pRec The validator record. + * @param hThreadSelf The current thread. Shall not be NIL_RTTHREAD! + * @param pSrcPos The source position of the lock operation. + * @param fRecursiveOk Whether it's ok to recurse. + * @param cMillies Intended sleep time in milliseconds. + * @param enmSleepState The sleep state to enter on successful return. + * @param fReallySleeping Is it really going to sleep now or not. Use + * false before calls to other IPRT synchronization + * methods. + */ +RTDECL(int) RTLockValidatorRecSharedCheckOrderAndBlocking(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf, + PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk, RTMSINTERVAL cMillies, + RTTHREADSTATE enmSleepState, bool fReallySleeping); + +/** + * Removes all current owners and makes hThread the only owner. + * + * @param pRec The validator record. + * @param hThread The thread handle of the owner. NIL_RTTHREAD is + * an alias for the current thread. + * @param pSrcPos The source position of the lock operation. + */ +RTDECL(void) RTLockValidatorRecSharedResetOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThread, PCRTLOCKVALSRCPOS pSrcPos); + +/** + * Adds an owner to a shared locking record. + * + * Takes recursion into account. This function is typically called after + * acquiring the lock in shared mode. + * + * @param pRec The validator record. + * @param hThread The thread handle of the owner. NIL_RTTHREAD is + * an alias for the current thread. + * @param pSrcPos The source position of the lock operation. + */ +RTDECL(void) RTLockValidatorRecSharedAddOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThread, PCRTLOCKVALSRCPOS pSrcPos); + +/** + * Removes an owner from a shared locking record. + * + * Takes recursion into account. This function is typically called before + * releasing the lock. + * + * @param pRec The validator record. + * @param hThread The thread handle of the owner. NIL_RTTHREAD is + * an alias for the current thread. + */ +RTDECL(void) RTLockValidatorRecSharedRemoveOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThread); + +/** + * Checks if the specified thread is one of the owners. + * + * @returns true if it is, false if not. + * + * @param pRec The validator record. + * @param hThread The thread handle of the owner. NIL_RTTHREAD is + * an alias for the current thread. + */ +RTDECL(bool) RTLockValidatorRecSharedIsOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThread); + +/** + * Check the exit order and release (unset) the shared ownership. + * + * This is called by routines implementing releasing the read/write lock. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_WRONG_RELEASE_ORDER if the order is wrong. Will have + * done all necessary whining and breakpointing before returning. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record. + * @param hThreadSelf The handle of the calling thread. NIL_RTTHREAD + * is an alias for the current thread. + */ +RTDECL(int) RTLockValidatorRecSharedCheckAndRelease(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf); + +/** + * Check the signaller of an event. + * + * This is called by routines implementing releasing the event semaphore (both + * kinds). + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_LV_NOT_SIGNALLER if the thread is not in the record. Will + * have done all necessary whining and breakpointing before returning. + * @retval VERR_SEM_LV_INVALID_PARAMETER if the input is invalid. + * + * @param pRec The validator record. + * @param hThreadSelf The handle of the calling thread. NIL_RTTHREAD + * is an alias for the current thread. + */ +RTDECL(int) RTLockValidatorRecSharedCheckSignaller(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf); + +/** + * Gets the number of write locks and critical sections the specified + * thread owns. + * + * This number does not include any nested lock/critect entries. + * + * Note that it probably will return 0 for non-strict builds since + * release builds doesn't do unnecessary diagnostic counting like this. + * + * @returns Number of locks on success (0+) and VERR_INVALID_HANDLER on failure + * @param Thread The thread we're inquiring about. + * @remarks Will only work for strict builds. + */ +RTDECL(int32_t) RTLockValidatorWriteLockGetCount(RTTHREAD Thread); + +/** + * Works the THREADINT::cWriteLocks member, mostly internal. + * + * @param Thread The current thread. + */ +RTDECL(void) RTLockValidatorWriteLockInc(RTTHREAD Thread); + +/** + * Works the THREADINT::cWriteLocks member, mostly internal. + * + * @param Thread The current thread. + */ +RTDECL(void) RTLockValidatorWriteLockDec(RTTHREAD Thread); + +/** + * Gets the number of read locks the specified thread owns. + * + * Note that nesting read lock entry will be included in the + * total sum. And that it probably will return 0 for non-strict + * builds since release builds doesn't do unnecessary diagnostic + * counting like this. + * + * @returns Number of read locks on success (0+) and VERR_INVALID_HANDLER on failure + * @param Thread The thread we're inquiring about. + */ +RTDECL(int32_t) RTLockValidatorReadLockGetCount(RTTHREAD Thread); + +/** + * Works the THREADINT::cReadLocks member. + * + * @param Thread The current thread. + */ +RTDECL(void) RTLockValidatorReadLockInc(RTTHREAD Thread); + +/** + * Works the THREADINT::cReadLocks member. + * + * @param Thread The current thread. + */ +RTDECL(void) RTLockValidatorReadLockDec(RTTHREAD Thread); + +/** + * Query which lock the specified thread is waiting on. + * + * @returns The lock handle value or NULL. + * @param hThread The thread in question. + */ +RTDECL(void *) RTLockValidatorQueryBlocking(RTTHREAD hThread); + +/** + * Checks if the thread is running in the lock validator after it has entered a + * block state. + * + * @returns true if it is, false if it isn't. + * @param hThread The thread in question. + */ +RTDECL(bool) RTLockValidatorIsBlockedThreadInValidator(RTTHREAD hThread); + +/** + * Checks if the calling thread is holding a lock in the specified class. + * + * @returns true if it holds a lock in the specific class, false if it + * doesn't. + * + * @param hCurrentThread The current thread. Pass NIL_RTTHREAD if you're + * lazy. + * @param hClass The class. + */ +RTDECL(bool) RTLockValidatorHoldsLocksInClass(RTTHREAD hCurrentThread, RTLOCKVALCLASS hClass); + +/** + * Checks if the calling thread is holding a lock in the specified sub-class. + * + * @returns true if it holds a lock in the specific sub-class, false if it + * doesn't. + * + * @param hCurrentThread The current thread. Pass NIL_RTTHREAD if you're + * lazy. + * @param hClass The class. + * @param uSubClass The new sub-class value. + */ +RTDECL(bool) RTLockValidatorHoldsLocksInSubClass(RTTHREAD hCurrentThread, RTLOCKVALCLASS hClass, uint32_t uSubClass); + + + +/** + * Creates a new lock validator class, all properties specified. + * + * @returns IPRT status code + * @param phClass Where to return the class handle. + * @param pSrcPos The source position of the create call. + * @param fAutodidact Whether the class should be allowed to teach + * itself new locking order rules (true), or if the + * user will teach it all it needs to know (false). + * @param fRecursionOk Whether to allow lock recursion or not. + * @param fStrictReleaseOrder Enforce strict lock release order or not. + * @param cMsMinDeadlock Used to raise the sleep interval at which + * deadlock detection kicks in. Minimum is 1 ms, + * while RT_INDEFINITE_WAIT will disable it. + * @param cMsMinOrder Used to raise the sleep interval at which lock + * order validation kicks in. Minimum is 1 ms, + * while RT_INDEFINITE_WAIT will disable it. + * @param pszNameFmt Class name format string, optional (NULL). Max + * length is 32 bytes. + * @param ... Format string arguments. + * + * @remarks The properties can be modified after creation by the + * RTLockValidatorClassSet* methods. + */ +RTDECL(int) RTLockValidatorClassCreateEx(PRTLOCKVALCLASS phClass, PCRTLOCKVALSRCPOS pSrcPos, + bool fAutodidact, bool fRecursionOk, bool fStrictReleaseOrder, + RTMSINTERVAL cMsMinDeadlock, RTMSINTERVAL cMsMinOrder, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(8, 9); + +/** + * Creates a new lock validator class, all properties specified. + * + * @returns IPRT status code + * @param phClass Where to return the class handle. + * @param pSrcPos The source position of the create call. + * @param fAutodidact Whether the class should be allowed to teach + * itself new locking order rules (true), or if the + * user will teach it all it needs to know (false). + * @param fRecursionOk Whether to allow lock recursion or not. + * @param fStrictReleaseOrder Enforce strict lock release order or not. + * @param cMsMinDeadlock Used to raise the sleep interval at which + * deadlock detection kicks in. Minimum is 1 ms, + * while RT_INDEFINITE_WAIT will disable it. + * @param cMsMinOrder Used to raise the sleep interval at which lock + * order validation kicks in. Minimum is 1 ms, + * while RT_INDEFINITE_WAIT will disable it. + * @param pszNameFmt Class name format string, optional (NULL). Max + * length is 32 bytes. + * @param va Format string arguments. + * + * @remarks The properties can be modified after creation by the + * RTLockValidatorClassSet* methods. + */ +RTDECL(int) RTLockValidatorClassCreateExV(PRTLOCKVALCLASS phClass, PCRTLOCKVALSRCPOS pSrcPos, + bool fAutodidact, bool fRecursionOk, bool fStrictReleaseOrder, + RTMSINTERVAL cMsMinDeadlock, RTMSINTERVAL cMsMinOrder, + const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(8, 0); + +/** + * Creates a new lock validator class. + * + * @returns IPRT status code + * @param phClass Where to return the class handle. + * @param fAutodidact Whether the class should be allowed to teach + * itself new locking order rules (true), or if the + * user will teach it all it needs to know (false). + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + * @param pszNameFmt Class name format string, optional (NULL). Max + * length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTLockValidatorClassCreate(PRTLOCKVALCLASS phClass, bool fAutodidact, RT_SRC_POS_DECL, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(6, 7); + +/** + * Creates a new lock validator class with a reference that is consumed by the + * first call to RTLockValidatorClassRetain. + * + * This is tailored for use in the parameter list of a semaphore constructor. + * + * @returns Class handle with a reference that is automatically consumed by the + * first retainer. NIL_RTLOCKVALCLASS if we run into trouble. + * + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + * @param pszNameFmt Class name format string, optional (NULL). Max + * length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(RTLOCKVALCLASS) RTLockValidatorClassCreateUnique(RT_SRC_POS_DECL, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(4, 5); + +/** + * Finds a class for the specified source position. + * + * @returns A handle to the class (not retained!) or NIL_RTLOCKVALCLASS. + * @param pSrcPos The source position. + */ +RTDECL(RTLOCKVALCLASS) RTLockValidatorClassFindForSrcPos(PRTLOCKVALSRCPOS pSrcPos); + +/** + * Finds or creates a class given the source position. + * + * @returns Class handle (not retained!) or NIL_RTLOCKVALCLASS. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + * @param pszNameFmt Class name format string, optional (NULL). Max + * length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(RTLOCKVALCLASS) RTLockValidatorClassForSrcPos(RT_SRC_POS_DECL, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(4, 5); + +/** + * Retains a reference to a lock validator class. + * + * @returns New reference count; UINT32_MAX if the handle is invalid. + * @param hClass Handle to the class. + */ +RTDECL(uint32_t) RTLockValidatorClassRetain(RTLOCKVALCLASS hClass); + +/** + * Releases a reference to a lock validator class. + * + * @returns New reference count. 0 if hClass is NIL_RTLOCKVALCLASS. UINT32_MAX + * if the handle is invalid. + * @param hClass Handle to the class. + */ +RTDECL(uint32_t) RTLockValidatorClassRelease(RTLOCKVALCLASS hClass); + +/** + * Teaches the class @a hClass that locks in the class @a hPriorClass can be + * held when taking a lock of class @a hClass + * + * @returns IPRT status. + * @param hClass Handle to the pupil class. + * @param hPriorClass Handle to the class that can be held prior to + * taking a lock in the pupil class. (No reference + * is consumed.) + */ +RTDECL(int) RTLockValidatorClassAddPriorClass(RTLOCKVALCLASS hClass, RTLOCKVALCLASS hPriorClass); + +/** + * Enables or disables the strict release order enforcing. + * + * @returns IPRT status. + * @param hClass Handle to the class to change. + * @param fEnabled Enable it (true) or disable it (false). + */ +RTDECL(int) RTLockValidatorClassEnforceStrictReleaseOrder(RTLOCKVALCLASS hClass, bool fEnabled); + +/** + * Enables / disables the lock validator for new locks. + * + * @returns The old setting. + * @param fEnabled The new setting. + */ +RTDECL(bool) RTLockValidatorSetEnabled(bool fEnabled); + +/** + * Is the lock validator enabled? + * + * @returns True if enabled, false if not. + */ +RTDECL(bool) RTLockValidatorIsEnabled(void); + +/** + * Controls whether the lock validator should be quiet or noisy (default). + * + * @returns The old setting. + * @param fQuiet The new setting. + */ +RTDECL(bool) RTLockValidatorSetQuiet(bool fQuiet); + +/** + * Is the lock validator quiet or noisy? + * + * @returns True if it is quiet, false if noisy. + */ +RTDECL(bool) RTLockValidatorIsQuiet(void); + +/** + * Makes the lock validator panic (default) or not. + * + * @returns The old setting. + * @param fPanic The new setting. + */ +RTDECL(bool) RTLockValidatorSetMayPanic(bool fPanic); + +/** + * Can the lock validator cause panic. + * + * @returns True if it can, false if not. + */ +RTDECL(bool) RTLockValidatorMayPanic(void); + + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_lockvalidator_h */ + diff --git a/include/iprt/log.h b/include/iprt/log.h new file mode 100644 index 00000000..fd677b71 --- /dev/null +++ b/include/iprt/log.h @@ -0,0 +1,2869 @@ +/** @file + * IPRT - Logging. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_log_h +#define IPRT_INCLUDED_log_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/stdarg.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_log RTLog - Logging + * @ingroup grp_rt + * @{ + */ + +/** + * IPRT Logging Groups. + * (Remember to update RT_LOGGROUP_NAMES!) + * + * @remark It should be pretty obvious, but just to have + * mentioned it, the values are sorted alphabetically (using the + * english alphabet) except for _DEFAULT which is always first. + * + * If anyone might be wondering what the alphabet looks like: + * a b c d e f g h i j k l m n o p q r s t u v w x y z + */ +typedef enum RTLOGGROUP +{ + /** Default logging group. */ + RTLOGGROUP_DEFAULT, + RTLOGGROUP_CRYPTO, + RTLOGGROUP_DBG, + RTLOGGROUP_DBG_DWARF, + RTLOGGROUP_DIR, + RTLOGGROUP_FILE, + RTLOGGROUP_FS, + RTLOGGROUP_FTP, + RTLOGGROUP_HTTP, + RTLOGGROUP_IOQUEUE, + RTLOGGROUP_LDR, + RTLOGGROUP_LOCALIPC, + RTLOGGROUP_PATH, + RTLOGGROUP_PROCESS, + RTLOGGROUP_REST, + RTLOGGROUP_SYMLINK, + RTLOGGROUP_THREAD, + RTLOGGROUP_TIME, + RTLOGGROUP_TIMER, + RTLOGGROUP_VFS, + RTLOGGROUP_ZIP = 31, + RTLOGGROUP_FIRST_USER = 32 +} RTLOGGROUP; + +/** @def RT_LOGGROUP_NAMES + * IPRT Logging group names. + * + * Must correspond 100% to RTLOGGROUP! + * Don't forget commas! + * + * @remark It should be pretty obvious, but just to have + * mentioned it, the values are sorted alphabetically (using the + * english alphabet) except for _DEFAULT which is always first. + * + * If anyone might be wondering what the alphabet looks like: + * a b c d e f g h i j k l m n o p q r s t u v w x y z + * + * The RT_XX log group names are placeholders for new modules being added, + * to make sure that there always is a total of 32 log group entries. + */ +#define RT_LOGGROUP_NAMES \ + "DEFAULT", \ + "RT_CRYPTO", \ + "RT_DBG", \ + "RT_DBG_DWARF", \ + "RT_DIR", \ + "RT_FILE", \ + "RT_FS", \ + "RT_FTP", \ + "RT_HTTP", \ + "RT_IOQUEUE", \ + "RT_LDR", \ + "RT_LOCALIPC", \ + "RT_PATH", \ + "RT_PROCESS", \ + "RT_REST", \ + "RT_SYMLINK", \ + "RT_THREAD", \ + "RT_TIME", \ + "RT_TIMER", \ + "RT_VFS", \ + "RT_20", \ + "RT_21", \ + "RT_22", \ + "RT_23", \ + "RT_24", \ + "RT_25", \ + "RT_26", \ + "RT_27", \ + "RT_28", \ + "RT_29", \ + "RT_30", \ + "RT_ZIP" + + +/** @def LOG_GROUP + * Active logging group. + */ +#ifndef LOG_GROUP +# define LOG_GROUP RTLOGGROUP_DEFAULT +#endif + +/** @def LOG_FN_FMT + * You can use this to specify your desired way of printing __PRETTY_FUNCTION__ + * if you dislike the default one. + */ +#ifndef LOG_FN_FMT +# define LOG_FN_FMT "%Rfn" +#endif + +#ifdef LOG_INSTANCE +# error "LOG_INSTANCE is no longer supported." +#endif +#ifdef LOG_REL_INSTANCE +# error "LOG_REL_INSTANCE is no longer supported." +#endif + +/** Logger structure. */ +typedef struct RTLOGGER RTLOGGER; +/** Pointer to logger structure. */ +typedef RTLOGGER *PRTLOGGER; +/** Pointer to const logger structure. */ +typedef const RTLOGGER *PCRTLOGGER; + + +/** Pointer to a log buffer descriptor. */ +typedef struct RTLOGBUFFERDESC *PRTLOGBUFFERDESC; + + +/** + * Logger phase. + * + * Used for signalling the log header/footer callback what to do. + */ +typedef enum RTLOGPHASE +{ + /** Begin of the logging. */ + RTLOGPHASE_BEGIN = 0, + /** End of the logging. */ + RTLOGPHASE_END, + /** Before rotating the log file. */ + RTLOGPHASE_PREROTATE, + /** After rotating the log file. */ + RTLOGPHASE_POSTROTATE, + /** 32-bit type blow up hack. */ + RTLOGPHASE_32BIT_HACK = 0x7fffffff +} RTLOGPHASE; + + +#if 0 /* retired */ +/** + * Logger function. + * + * @param pszFormat Format string. + * @param ... Optional arguments as specified in the format string. + */ +typedef DECLCALLBACKTYPE(void, FNRTLOGGER,(const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(1, 2); +/** Pointer to logger function. */ +typedef FNRTLOGGER *PFNRTLOGGER; +#endif + +/** + * Custom buffer flushing function. + * + * @retval true if flushed and the buffer can be reused. + * @retval false for switching to the next buffer because an async flush of + * @a pBufDesc is still pending. The implementation is responsible for + * only returning when the next buffer is ready for reuse, the generic + * logger code has no facility to make sure of this. + * + * @param pLogger Pointer to the logger instance which is to be flushed. + * @param pBufDesc The descriptor of the buffer to be flushed. + */ +typedef DECLCALLBACKTYPE(bool, FNRTLOGFLUSH,(PRTLOGGER pLogger, PRTLOGBUFFERDESC pBufDesc)); +/** Pointer to flush function. */ +typedef FNRTLOGFLUSH *PFNRTLOGFLUSH; + +/** + * Header/footer message callback. + * + * @param pLogger Pointer to the logger instance. + * @param pszFormat Format string. + * @param ... Optional arguments specified in the format string. + */ +typedef DECLCALLBACKTYPE(void, FNRTLOGPHASEMSG,(PRTLOGGER pLogger, const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(2, 3); +/** Pointer to header/footer message callback function. */ +typedef FNRTLOGPHASEMSG *PFNRTLOGPHASEMSG; + +/** + * Log file header/footer callback. + * + * @param pLogger Pointer to the logger instance. + * @param enmLogPhase Indicates at what time the callback is invoked. + * @param pfnLogPhaseMsg Callback for writing the header/footer (RTLogPrintf + * and others are out of bounds). + */ +typedef DECLCALLBACKTYPE(void, FNRTLOGPHASE,(PRTLOGGER pLogger, RTLOGPHASE enmLogPhase, PFNRTLOGPHASEMSG pfnLogPhaseMsg)); +/** Pointer to log header/footer callback function. */ +typedef FNRTLOGPHASE *PFNRTLOGPHASE; + +/** + * Custom log prefix callback. + * + * + * @returns The number of chars written. + * + * @param pLogger Pointer to the logger instance. + * @param pchBuf Output buffer pointer. + * No need to terminate the output. + * @param cchBuf The size of the output buffer. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(size_t, FNRTLOGPREFIX,(PRTLOGGER pLogger, char *pchBuf, size_t cchBuf, void *pvUser)); +/** Pointer to prefix callback function. */ +typedef FNRTLOGPREFIX *PFNRTLOGPREFIX; + + +/** Pointer to a constant log output interface. */ +typedef const struct RTLOGOUTPUTIF *PCRTLOGOUTPUTIF; + +/** + * Logging output interface. + */ +typedef struct RTLOGOUTPUTIF +{ + /** + * Opens a new log file with the given name. + * + * @returns IPRT status code. + * @param pIf Pointer to this interface. + * @param pvUser Opaque user data passed when setting the callbacks. + * @param pszFilename The filename to open. + * @param fFlags Open flags, combination of RTFILE_O_XXX. + */ + DECLR3CALLBACKMEMBER(int, pfnOpen, (PCRTLOGOUTPUTIF pIf, void *pvUser, const char *pszFilename, uint32_t fFlags)); + + /** + * Closes the currently open file. + * + * @returns IPRT status code. + * @param pIf Pointer to this interface. + * @param pvUser Opaque user data passed when setting the callbacks. + */ + DECLR3CALLBACKMEMBER(int, pfnClose, (PCRTLOGOUTPUTIF pIf, void *pvUser)); + + /** + * Deletes the given file. + * + * @returns IPRT status code. + * @param pIf Pointer to this interface. + * @param pvUser Opaque user data passed when setting the callbacks. + * @param pszFilename The filename to delete. + */ + DECLR3CALLBACKMEMBER(int, pfnDelete, (PCRTLOGOUTPUTIF pIf, void *pvUser, const char *pszFilename)); + + /** + * Renames the given file. + * + * @returns IPRT status code. + * @param pIf Pointer to this interface. + * @param pvUser Opaque user data passed when setting the callbacks. + * @param pszFilenameOld The old filename to rename. + * @param pszFilenameNew The new filename. + * @param fFlags Flags for the operation, combination of RTFILEMOVE_FLAGS_XXX. + */ + DECLR3CALLBACKMEMBER(int, pfnRename, (PCRTLOGOUTPUTIF pIf, void *pvUser, const char *pszFilenameOld, + const char *pszFilenameNew, uint32_t fFlags)); + + /** + * Queries the size of the log file. + * + * @returns IPRT status code. + * @param pIf Pointer to this interface. + * @param pvUser Opaque user data passed when setting the callbacks. + * @param pcbFile Where to store the file size in bytes on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQuerySize, (PCRTLOGOUTPUTIF pIf, void *pvUser, uint64_t *pcbSize)); + + /** + * Writes data to the log file. + * + * @returns IPRT status code. + * @param pIf Pointer to this interface. + * @param pvUser Opaque user data passed when setting the callbacks. + * @param pvBuf The data to write. + * @param cbWrite Number of bytes to write. + * @param pcbWritten Where to store the actual number of bytes written on success. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite, (PCRTLOGOUTPUTIF pIf, void *pvUser, const void *pvBuf, + size_t cbWrite, size_t *pcbWritten)); + + /** + * Flushes data to the underlying storage medium. + * + * @returns IPRT status code. + * @param pIf Pointer to this interface. + * @param pvUser Opaque user data passed when setting the callbacks. + */ + DECLR3CALLBACKMEMBER(int, pfnFlush, (PCRTLOGOUTPUTIF pIf, void *pvUser)); +} RTLOGOUTPUTIF; +/** Pointer to a logging output interface. */ +typedef struct RTLOGOUTPUTIF *PRTLOGOUTPUTIF; + + +/** + * Auxiliary buffer descriptor. + * + * This is what we share we ring-3 and use for flushing ring-0 EMT loggers when + * we return to ring-3. + */ +typedef struct RTLOGBUFFERAUXDESC +{ + /** Flush indicator. + * Ring-3 sets this if it flushed the buffer, ring-0 clears it again after + * writing. */ + bool volatile fFlushedIndicator; + bool afPadding[3]; + /** Copy of RTLOGBUFFERDESC::offBuf. */ + uint32_t offBuf; +} RTLOGBUFFERAUXDESC; +/** Pointer to auxiliary buffer descriptor. */ +typedef RTLOGBUFFERAUXDESC *PRTLOGBUFFERAUXDESC; + +/** + * Log buffer desciptor. + */ +typedef struct RTLOGBUFFERDESC +{ + /** Magic value / eye catcher (RTLOGBUFFERDESC_MAGIC). */ + uint32_t u32Magic; + /** Padding. */ + uint32_t uReserved; + /** The buffer size. */ + uint32_t cbBuf; + /** The current buffer offset. */ + uint32_t offBuf; + /** Pointer to the buffer. */ + char *pchBuf; + /** Pointer to auxiliary desciptor, NULL if not used. */ + PRTLOGBUFFERAUXDESC pAux; +} RTLOGBUFFERDESC; + +/** RTLOGBUFFERDESC::u32Magic value. (Avram Noam Chomsky) */ +#define RTLOGBUFFERDESC_MAGIC UINT32_C(0x19281207) + +/** + * The public logger instance part. + * + * The logger instance is mostly abstract and kept as RTLOGGERINTERNAL within + * log.cpp. This public part is at the start of RTLOGGERINTERNAL. + */ +struct RTLOGGER +{ + /** Magic number (RTLOGGER_MAGIC). */ + uint32_t u32Magic; + /** User value \#1, initialized to zero. */ + uint32_t u32UserValue1; + /** User value \#2, initialized to zero. */ + uint64_t u64UserValue2; + /** User value \#3, initialized to zero. */ + uint64_t u64UserValue3; +#if 0 + /** Pointer to the logger function (used in non-C99 mode only). + * + * This is actually pointer to a wrapper/stub function which will push a pointer + * to the instance pointer onto the stack before jumping to the real logger + * function. A very unfortunate hack to work around the missing variadic macro + * support in older C++/C standards. (The memory is allocated using + * RTMemExecAlloc(), except for agnostic R0 code.) */ + PFNRTLOGGER pfnLogger; +#else + /** Unused. */ + uintptr_t uUsedToBeNonC99Logger; +#endif +#if ARCH_BITS == 32 + /** Explicit padding. */ + uint32_t uReserved1; +#endif +}; + +/** RTLOGGER::u32Magic value. (John Rogers Searle) */ +#define RTLOGGER_MAGIC UINT32_C(0x19320731) + +/** + * Logger flags. + */ +typedef enum RTLOGFLAGS +{ + /** The logger instance is disabled for normal output. */ + RTLOGFLAGS_DISABLED = 0x00000001, + /** The logger instance is using buffered output. */ + RTLOGFLAGS_BUFFERED = 0x00000002, + /** The logger instance expands LF to CR/LF. */ + RTLOGFLAGS_USECRLF = 0x00000010, + /** Append to the log destination where applicable. */ + RTLOGFLAGS_APPEND = 0x00000020, + /** Show relative timestamps with PREFIX_TSC and PREFIX_TS */ + RTLOGFLAGS_REL_TS = 0x00000040, + /** Show decimal timestamps with PREFIX_TSC and PREFIX_TS */ + RTLOGFLAGS_DECIMAL_TS = 0x00000080, + /** Open the file in write through mode. */ + RTLOGFLAGS_WRITE_THROUGH = 0x00000100, + /** Flush the file to disk when flushing the buffer. */ + RTLOGFLAGS_FLUSH = 0x00000200, + /** Restrict the number of log entries per group. */ + RTLOGFLAGS_RESTRICT_GROUPS = 0x00000400, + /** New lines should be prefixed with the write and read lock counts. */ + RTLOGFLAGS_PREFIX_LOCK_COUNTS = 0x00008000, + /** New lines should be prefixed with the CPU id (ApicID on intel/amd). */ + RTLOGFLAGS_PREFIX_CPUID = 0x00010000, + /** New lines should be prefixed with the native process id. */ + RTLOGFLAGS_PREFIX_PID = 0x00020000, + /** New lines should be prefixed with group flag number causing the output. */ + RTLOGFLAGS_PREFIX_FLAG_NO = 0x00040000, + /** New lines should be prefixed with group flag name causing the output. */ + RTLOGFLAGS_PREFIX_FLAG = 0x00080000, + /** New lines should be prefixed with group number. */ + RTLOGFLAGS_PREFIX_GROUP_NO = 0x00100000, + /** New lines should be prefixed with group name. */ + RTLOGFLAGS_PREFIX_GROUP = 0x00200000, + /** New lines should be prefixed with the native thread id. */ + RTLOGFLAGS_PREFIX_TID = 0x00400000, + /** New lines should be prefixed with thread name. */ + RTLOGFLAGS_PREFIX_THREAD = 0x00800000, + /** New lines should be prefixed with data from a custom callback. */ + RTLOGFLAGS_PREFIX_CUSTOM = 0x01000000, + /** New lines should be prefixed with formatted timestamp since program start. */ + RTLOGFLAGS_PREFIX_TIME_PROG = 0x04000000, + /** New lines should be prefixed with formatted timestamp (UCT). */ + RTLOGFLAGS_PREFIX_TIME = 0x08000000, + /** New lines should be prefixed with milliseconds since program start. */ + RTLOGFLAGS_PREFIX_MS_PROG = 0x10000000, + /** New lines should be prefixed with timestamp. */ + RTLOGFLAGS_PREFIX_TSC = 0x20000000, + /** New lines should be prefixed with timestamp. */ + RTLOGFLAGS_PREFIX_TS = 0x40000000, + /** The prefix mask. */ + RTLOGFLAGS_PREFIX_MASK = 0x7dff8000 +} RTLOGFLAGS; +/** Don't use locking. */ +#define RTLOG_F_NO_LOCKING RT_BIT_64(63) +/** Mask with all valid log flags (for validation). */ +#define RTLOG_F_VALID_MASK UINT64_C(0x800000007fff87f3) + +/** + * Logger per group flags. + * + * @remarks We only use the lower 16 bits here. We'll be combining it with the + * group number in a few places. + */ +typedef enum RTLOGGRPFLAGS +{ + /** Enabled. */ + RTLOGGRPFLAGS_ENABLED = 0x0001, + /** Flow logging. */ + RTLOGGRPFLAGS_FLOW = 0x0002, + /** Warnings logging. */ + RTLOGGRPFLAGS_WARN = 0x0004, + /* 0x0008 for later. */ + /** Level 1 logging. */ + RTLOGGRPFLAGS_LEVEL_1 = 0x0010, + /** Level 2 logging. */ + RTLOGGRPFLAGS_LEVEL_2 = 0x0020, + /** Level 3 logging. */ + RTLOGGRPFLAGS_LEVEL_3 = 0x0040, + /** Level 4 logging. */ + RTLOGGRPFLAGS_LEVEL_4 = 0x0080, + /** Level 5 logging. */ + RTLOGGRPFLAGS_LEVEL_5 = 0x0100, + /** Level 6 logging. */ + RTLOGGRPFLAGS_LEVEL_6 = 0x0200, + /** Level 7 logging. */ + RTLOGGRPFLAGS_LEVEL_7 = 0x0400, + /** Level 8 logging. */ + RTLOGGRPFLAGS_LEVEL_8 = 0x0800, + /** Level 9 logging. */ + RTLOGGRPFLAGS_LEVEL_9 = 0x1000, + /** Level 10 logging. */ + RTLOGGRPFLAGS_LEVEL_10 = 0x2000, + /** Level 11 logging. */ + RTLOGGRPFLAGS_LEVEL_11 = 0x4000, + /** Level 12 logging. */ + RTLOGGRPFLAGS_LEVEL_12 = 0x8000, + + /** Restrict the number of log entries. */ + RTLOGGRPFLAGS_RESTRICT = 0x40000000, + /** Blow up the type. */ + RTLOGGRPFLAGS_32BIT_HACK = 0x7fffffff +} RTLOGGRPFLAGS; + +/** + * Logger destination types and flags. + */ +typedef enum RTLOGDEST +{ + /** Log to file. */ + RTLOGDEST_FILE = 0x00000001, + /** Log to stdout. */ + RTLOGDEST_STDOUT = 0x00000002, + /** Log to stderr. */ + RTLOGDEST_STDERR = 0x00000004, + /** Log to debugger (win32 only). */ + RTLOGDEST_DEBUGGER = 0x00000008, + /** Log to com port. */ + RTLOGDEST_COM = 0x00000010, + /** Log a memory ring buffer. */ + RTLOGDEST_RINGBUF = 0x00000020, + /** The parent VMM debug log. */ + RTLOGDEST_VMM = 0x00000040, + /** The parent VMM release log. */ + RTLOGDEST_VMM_REL = 0x00000080, + /** Open files with no deny (share read, write, delete) on Windows. */ + RTLOGDEST_F_NO_DENY = 0x00010000, + /** Delay opening the log file, logging to the buffer untill + * RTLogClearFileDelayFlag is called. */ + RTLOGDEST_F_DELAY_FILE = 0x00020000, + /** Don't allow changes to the filename or mode of opening it. */ + RTLOGDEST_FIXED_FILE = 0x01000000, + /** Don't allow changing the directory. */ + RTLOGDEST_FIXED_DIR = 0x02000000, + /** Just a dummy flag to be used when no other flag applies. */ + RTLOGDEST_DUMMY = 0x20000000, + /** Log to a user defined output stream. */ + RTLOGDEST_USER = 0x40000000 +} RTLOGDEST; +/** Valid log destinations. */ +#define RTLOG_DST_VALID_MASK UINT32_C(0x630300ff) +/** Log destinations that can be changed via RTLogChangeDestinations. */ +#define RTLOG_DST_CHANGE_MASK UINT32_C(0x400000de) + + +#ifdef DOXYGEN_RUNNING +# define LOG_DISABLED +# define LOG_ENABLED +# define LOG_ENABLE_FLOW +#endif + +/** @def LOG_DISABLED + * Use this compile time define to disable all logging macros. It can + * be overridden for each of the logging macros by the LOG_ENABLE* + * compile time defines. + */ + +/** @def LOG_ENABLED + * Use this compile time define to enable logging when not in debug mode + * or LOG_DISABLED is set. + * This will enable Log() only. + */ + +/** @def LOG_ENABLE_FLOW + * Use this compile time define to enable flow logging when not in + * debug mode or LOG_DISABLED is defined. + * This will enable LogFlow() only. + */ + +/* + * Determine whether logging is enabled and forcefully normalize the indicators. + */ +#if (defined(DEBUG) || defined(LOG_ENABLED)) && !defined(LOG_DISABLED) +# undef LOG_DISABLED +# undef LOG_ENABLED +# define LOG_ENABLED +#else +# undef LOG_ENABLED +# undef LOG_DISABLED +# define LOG_DISABLED +#endif + + +/** @def LOG_USE_C99 + * Governs the use of variadic macros. + */ +#ifndef LOG_USE_C99 +# define LOG_USE_C99 +#endif + + +/** @name Macros for checking whether a log level is enabled. + * @{ */ +/** @def LogIsItEnabled + * Checks whether the specified logging group is enabled or not. + */ +#ifdef LOG_ENABLED +# define LogIsItEnabled(a_fFlags, a_iGroup) ( RTLogDefaultInstanceEx(RT_MAKE_U32(a_fFlags, a_iGroup)) != NULL ) +#else +# define LogIsItEnabled(a_fFlags, a_iGroup) (false) +#endif + +/** @def LogIsEnabled + * Checks whether level 1 logging is enabled. + */ +#define LogIsEnabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP) + +/** @def LogIs2Enabled + * Checks whether level 2 logging is enabled. + */ +#define LogIs2Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP) + +/** @def LogIs3Enabled + * Checks whether level 3 logging is enabled. + */ +#define LogIs3Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_3, LOG_GROUP) + +/** @def LogIs4Enabled + * Checks whether level 4 logging is enabled. + */ +#define LogIs4Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_4, LOG_GROUP) + +/** @def LogIs5Enabled + * Checks whether level 5 logging is enabled. + */ +#define LogIs5Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_5, LOG_GROUP) + +/** @def LogIs6Enabled + * Checks whether level 6 logging is enabled. + */ +#define LogIs6Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_6, LOG_GROUP) + +/** @def LogIs7Enabled + * Checks whether level 7 logging is enabled. + */ +#define LogIs7Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_7, LOG_GROUP) + +/** @def LogIs8Enabled + * Checks whether level 8 logging is enabled. + */ +#define LogIs8Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_8, LOG_GROUP) + +/** @def LogIs9Enabled + * Checks whether level 9 logging is enabled. + */ +#define LogIs9Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_9, LOG_GROUP) + +/** @def LogIs10Enabled + * Checks whether level 10 logging is enabled. + */ +#define LogIs10Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_10, LOG_GROUP) + +/** @def LogIs11Enabled + * Checks whether level 11 logging is enabled. + */ +#define LogIs11Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_11, LOG_GROUP) + +/** @def LogIs12Enabled + * Checks whether level 12 logging is enabled. + */ +#define LogIs12Enabled() LogIsItEnabled(RTLOGGRPFLAGS_LEVEL_12, LOG_GROUP) + +/** @def LogIsFlowEnabled + * Checks whether execution flow logging is enabled. + */ +#define LogIsFlowEnabled() LogIsItEnabled(RTLOGGRPFLAGS_FLOW, LOG_GROUP) + +/** @def LogIsWarnEnabled + * Checks whether execution flow logging is enabled. + */ +#define LogIsWarnEnabled() LogIsItEnabled(RTLOGGRPFLAGS_WARN, LOG_GROUP) +/** @} */ + + +/** @def LogIt + * Write to specific logger if group enabled. + */ +#ifdef LOG_ENABLED +# if defined(LOG_USE_C99) +# define _LogRemoveParentheseis(...) __VA_ARGS__ +# define _LogIt(a_fFlags, a_iGroup, ...) \ + do \ + { \ + PRTLOGGER LogIt_pLogger = RTLogDefaultInstanceEx(RT_MAKE_U32(a_fFlags, a_iGroup)); \ + if (RT_LIKELY(!LogIt_pLogger)) \ + { /* likely */ } \ + else \ + RTLogLoggerEx(LogIt_pLogger, a_fFlags, a_iGroup, __VA_ARGS__); \ + } while (0) +# define LogIt(a_fFlags, a_iGroup, fmtargs) _LogIt(a_fFlags, a_iGroup, _LogRemoveParentheseis fmtargs) +# define _LogItAlways(a_fFlags, a_iGroup, ...) RTLogLoggerEx(NULL, a_fFlags, UINT32_MAX, __VA_ARGS__) +# define LogItAlways(a_fFlags, a_iGroup, fmtargs) _LogItAlways(a_fFlags, a_iGroup, _LogRemoveParentheseis fmtargs) + /** @todo invent a flag or something for skipping the group check so we can pass iGroup. LogItAlways. */ +# else +# define LogIt(a_fFlags, a_iGroup, fmtargs) \ + do \ + { \ + PRTLOGGER LogIt_pLogger = RTLogDefaultInstanceEx(RT_MAKE_U32(a_fFlags, a_iGroup)); \ + if (RT_LIKELY(!LogIt_pLogger)) \ + { /* likely */ } \ + else \ + { \ + LogIt_pLogger->pfnLogger fmtargs; \ + } \ + } while (0) +# define LogItAlways(a_fFlags, a_iGroup, fmtargs) \ + do \ + { \ + PRTLOGGER LogIt_pLogger = RTLogDefaultInstanceEx(RT_MAKE_U32(0, UINT16_MAX)); \ + if (LogIt_pLogger) \ + LogIt_pLogger->pfnLogger fmtargs; \ + } while (0) +# endif +#else +# define LogIt(a_fFlags, a_iGroup, fmtargs) do { } while (0) +# define LogItAlways(a_fFlags, a_iGroup, fmtargs) do { } while (0) +# if defined(LOG_USE_C99) +# define _LogRemoveParentheseis(...) __VA_ARGS__ +# define _LogIt(a_fFlags, a_iGroup, ...) do { } while (0) +# define _LogItAlways(a_fFlags, a_iGroup, ...) do { } while (0) +# endif +#endif + + +/** @name Basic logging macros + * @{ */ +/** @def Log + * Level 1 logging that works regardless of the group settings. + */ +#define LogAlways(a) LogItAlways(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, a) + +/** @def Log + * Level 1 logging. + */ +#define Log(a) LogIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, a) + +/** @def Log2 + * Level 2 logging. + */ +#define Log2(a) LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP, a) + +/** @def Log3 + * Level 3 logging. + */ +#define Log3(a) LogIt(RTLOGGRPFLAGS_LEVEL_3, LOG_GROUP, a) + +/** @def Log4 + * Level 4 logging. + */ +#define Log4(a) LogIt(RTLOGGRPFLAGS_LEVEL_4, LOG_GROUP, a) + +/** @def Log5 + * Level 5 logging. + */ +#define Log5(a) LogIt(RTLOGGRPFLAGS_LEVEL_5, LOG_GROUP, a) + +/** @def Log6 + * Level 6 logging. + */ +#define Log6(a) LogIt(RTLOGGRPFLAGS_LEVEL_6, LOG_GROUP, a) + +/** @def Log7 + * Level 7 logging. + */ +#define Log7(a) LogIt(RTLOGGRPFLAGS_LEVEL_7, LOG_GROUP, a) + +/** @def Log8 + * Level 8 logging. + */ +#define Log8(a) LogIt(RTLOGGRPFLAGS_LEVEL_8, LOG_GROUP, a) + +/** @def Log9 + * Level 9 logging. + */ +#define Log9(a) LogIt(RTLOGGRPFLAGS_LEVEL_9, LOG_GROUP, a) + +/** @def Log10 + * Level 10 logging. + */ +#define Log10(a) LogIt(RTLOGGRPFLAGS_LEVEL_10, LOG_GROUP, a) + +/** @def Log11 + * Level 11 logging. + */ +#define Log11(a) LogIt(RTLOGGRPFLAGS_LEVEL_11, LOG_GROUP, a) + +/** @def Log12 + * Level 12 logging. + */ +#define Log12(a) LogIt(RTLOGGRPFLAGS_LEVEL_12, LOG_GROUP, a) + +/** @def LogFlow + * Logging of execution flow. + */ +#define LogFlow(a) LogIt(RTLOGGRPFLAGS_FLOW, LOG_GROUP, a) + +/** @def LogWarn + * Logging of warnings. + */ +#define LogWarn(a) LogIt(RTLOGGRPFLAGS_WARN, LOG_GROUP, a) +/** @} */ + + +/** @name Logging macros prefixing the current function name. + * @{ */ +/** @def LogFunc + * Level 1 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define LogFunc(a) _LogIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogFunc(a) do { Log((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log(a); } while (0) +#endif + +/** @def Log2Func + * Level 2 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log2Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log2Func(a) do { Log2((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log2(a); } while (0) +#endif + +/** @def Log3Func + * Level 3 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log3Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_3, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log3Func(a) do { Log3((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log3(a); } while (0) +#endif + +/** @def Log4Func + * Level 4 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log4Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_4, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log4Func(a) do { Log4((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log4(a); } while (0) +#endif + +/** @def Log5Func + * Level 5 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log5Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_5, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log5Func(a) do { Log5((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log5(a); } while (0) +#endif + +/** @def Log6Func + * Level 6 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log6Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_6, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log6Func(a) do { Log6((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log6(a); } while (0) +#endif + +/** @def Log7Func + * Level 7 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log7Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_7, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log7Func(a) do { Log7((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log7(a); } while (0) +#endif + +/** @def Log8Func + * Level 8 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log8Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_8, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log8Func(a) do { Log8((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log8(a); } while (0) +#endif + +/** @def Log9Func + * Level 9 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log9Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_9, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log9Func(a) do { Log9((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log9(a); } while (0) +#endif + +/** @def Log10Func + * Level 10 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log10Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_10, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log10Func(a) do { Log10((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log10(a); } while (0) +#endif + +/** @def Log11Func + * Level 11 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log11Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_11, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log11Func(a) do { Log11((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log11(a); } while (0) +#endif + +/** @def Log12Func + * Level 12 logging inside C/C++ functions. + * + * Prepends the given log message with the function name followed by a + * semicolon and space. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log12Func(a) _LogIt(RTLOGGRPFLAGS_LEVEL_12, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log12Func(a) do { Log12((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log12(a); } while (0) +#endif + +/** @def LogFlowFunc + * Macro to log the execution flow inside C/C++ functions. + * + * Prepends the given log message with the function name followed by + * a semicolon and space. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define LogFlowFunc(a) \ + _LogIt(RTLOGGRPFLAGS_FLOW, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogFlowFunc(a) \ + do { LogFlow((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogFlow(a); } while (0) +#endif + +/** @def LogWarnFunc + * Macro to log a warning inside C/C++ functions. + * + * Prepends the given log message with the function name followed by + * a semicolon and space. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define LogWarnFunc(a) \ + _LogIt(RTLOGGRPFLAGS_WARN, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogWarnFunc(a) \ + do { LogFlow((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogFlow(a); } while (0) +#endif +/** @} */ + + +/** @name Logging macros prefixing the this pointer value and method name. + * @{ */ + +/** @def LogThisFunc + * Level 1 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define LogThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogThisFunc(a) do { Log(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log(a); } while (0) +#endif + +/** @def Log2ThisFunc + * Level 2 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log2ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log2ThisFunc(a) do { Log2(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log2(a); } while (0) +#endif + +/** @def Log3ThisFunc + * Level 3 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log3ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_3, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log3ThisFunc(a) do { Log3(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log3(a); } while (0) +#endif + +/** @def Log4ThisFunc + * Level 4 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log4ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_4, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log4ThisFunc(a) do { Log4(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log4(a); } while (0) +#endif + +/** @def Log5ThisFunc + * Level 5 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log5ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_5, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log5ThisFunc(a) do { Log5(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log5(a); } while (0) +#endif + +/** @def Log6ThisFunc + * Level 6 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log6ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_6, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log6ThisFunc(a) do { Log6(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log6(a); } while (0) +#endif + +/** @def Log7ThisFunc + * Level 7 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log7ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_7, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log7ThisFunc(a) do { Log7(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log7(a); } while (0) +#endif + +/** @def Log8ThisFunc + * Level 8 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log8ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_8, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log8ThisFunc(a) do { Log8(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log8(a); } while (0) +#endif + +/** @def Log9ThisFunc + * Level 9 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log9ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_9, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log9ThisFunc(a) do { Log9(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log9(a); } while (0) +#endif + +/** @def Log10ThisFunc + * Level 10 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log10ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_10, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log10ThisFunc(a) do { Log10(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log10(a); } while (0) +#endif + +/** @def Log11ThisFunc + * Level 11 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log11ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_11, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log11ThisFunc(a) do { Log11(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log11(a); } while (0) +#endif + +/** @def Log12ThisFunc + * Level 12 logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log12ThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_12, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log12ThisFunc(a) do { Log12(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log12(a); } while (0) +#endif + +/** @def LogFlowThisFunc + * Flow level logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define LogFlowThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_FLOW, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogFlowThisFunc(a) do { LogFlow(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogFlow(a); } while (0) +#endif + +/** @def LogWarnThisFunc + * Warning level logging inside a C++ non-static method, with object pointer and + * method name prefixed to the given message. + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define LogWarnThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_WARN, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogWarnThisFunc(a) do { LogWarn(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogWarn(a); } while (0) +#endif +/** @} */ + + +/** @name Misc Logging Macros + * @{ */ + +/** @def Log1Warning + * The same as Log(), but prepents a <tt>"WARNING! "</tt> string to the message. + * + * @param a Custom log message in format <tt>("string\n" [, args])</tt>. + */ +#if defined(LOG_USE_C99) +# define Log1Warning(a) _LogIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, "WARNING! %M", _LogRemoveParentheseis a ) +#else +# define Log1Warning(a) do { Log(("WARNING! ")); Log(a); } while (0) +#endif + +/** @def Log1WarningFunc + * The same as LogWarning(), but prepents the log message with the function name. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log1WarningFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, LOG_FN_FMT ": WARNING! %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log1WarningFunc(a) \ + do { Log((LOG_FN_FMT ": WARNING! ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log(a); } while (0) +#endif + +/** @def Log1WarningThisFunc + * The same as LogWarningFunc() but for class functions (methods): the resulting + * log line is additionally prepended with a hex value of |this| pointer. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define Log1WarningThisFunc(a) \ + _LogIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, "{%p} " LOG_FN_FMT ": WARNING! %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define Log1WarningThisFunc(a) \ + do { Log(("{%p} " LOG_FN_FMT ": WARNING! ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); Log(a); } while (0) +#endif + + +/** Shortcut to |LogFlowFunc ("ENTER\n")|, marks the beginnig of the function. */ +#define LogFlowFuncEnter() LogFlowFunc(("ENTER\n")) + +/** Shortcut to |LogFlowFunc ("LEAVE\n")|, marks the end of the function. */ +#define LogFlowFuncLeave() LogFlowFunc(("LEAVE\n")) + +/** Shortcut to |LogFlowFunc ("LEAVE: %Rrc\n")|, marks the end of the function. */ +#define LogFlowFuncLeaveRC(rc) LogFlowFunc(("LEAVE: %Rrc\n", (rc))) + +/** Shortcut to |LogFlowThisFunc ("ENTER\n")|, marks the beginnig of the function. */ +#define LogFlowThisFuncEnter() LogFlowThisFunc(("ENTER\n")) + +/** Shortcut to |LogFlowThisFunc ("LEAVE\n")|, marks the end of the function. */ +#define LogFlowThisFuncLeave() LogFlowThisFunc(("LEAVE\n")) + + +/** @def LogObjRefCnt + * Helper macro to print the current reference count of the given COM object + * to the log file. + * + * @param pObj Pointer to the object in question (must be a pointer to an + * IUnknown subclass or simply define COM-style AddRef() and + * Release() methods) + */ +#define LogObjRefCnt(pObj) \ + do { \ + if (LogIsFlowEnabled()) \ + { \ + int cRefsForLog = (pObj)->AddRef(); \ + LogFlow((#pObj "{%p}.refCnt=%d\n", (pObj), cRefsForLog - 1)); \ + (pObj)->Release(); \ + } \ + } while (0) +/** @} */ + + + +/** @name Passing Function Call Position When Logging. + * + * This is a little bit ugly as we have to omit the comma before the + * position parameters so that we don't inccur any overhead in non-logging + * builds (!defined(LOG_ENABLED). + * + * @{ */ +/** Source position for passing to a function call. */ +#ifdef LOG_ENABLED +# define RTLOG_COMMA_SRC_POS , __FILE__, __LINE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__ +#else +# define RTLOG_COMMA_SRC_POS RT_NOTHING +#endif +/** Source position declaration. */ +#ifdef LOG_ENABLED +# define RTLOG_COMMA_SRC_POS_DECL , const char *pszFile, unsigned iLine, const char *pszFunction +#else +# define RTLOG_COMMA_SRC_POS_DECL RT_NOTHING +#endif +/** Source position arguments. */ +#ifdef LOG_ENABLED +# define RTLOG_COMMA_SRC_POS_ARGS , pszFile, iLine, pszFunction +#else +# define RTLOG_COMMA_SRC_POS_ARGS RT_NOTHING +#endif +/** Applies NOREF() to the source position arguments. */ +#ifdef LOG_ENABLED +# define RTLOG_SRC_POS_NOREF() do { NOREF(pszFile); NOREF(iLine); NOREF(pszFunction); } while (0) +#else +# define RTLOG_SRC_POS_NOREF() do { } while (0) +#endif +/** @} */ + + + +/** @defgroup grp_rt_log_rel Release Logging + * @{ + */ + +#ifdef DOXYGEN_RUNNING +# define RTLOG_REL_DISABLED +# define RTLOG_REL_ENABLED +#endif + +/** @def RTLOG_REL_DISABLED + * Use this compile time define to disable all release logging + * macros. + */ + +/** @def RTLOG_REL_ENABLED + * Use this compile time define to override RTLOG_REL_DISABLE. + */ + +/* + * Determine whether release logging is enabled and forcefully normalize the indicators. + */ +#if !defined(RTLOG_REL_DISABLED) || defined(RTLOG_REL_ENABLED) +# undef RTLOG_REL_DISABLED +# undef RTLOG_REL_ENABLED +# define RTLOG_REL_ENABLED +#else +# undef RTLOG_REL_ENABLED +# undef RTLOG_REL_DISABLED +# define RTLOG_REL_DISABLED +#endif + +/** @name Macros for checking whether a release log level is enabled. + * @{ */ +/** @def LogRelIsItEnabled + * Checks whether the specified release logging group is enabled or not. + */ +#define LogRelIsItEnabled(a_fFlags, a_iGroup) ( RTLogRelGetDefaultInstanceExWeak(RT_MAKE_U32(a_fFlags, a_iGroup)) != NULL ) + +/** @def LogRelIsEnabled + * Checks whether level 1 release logging is enabled. + */ +#define LogRelIsEnabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP) + +/** @def LogRelIs2Enabled + * Checks whether level 2 release logging is enabled. + */ +#define LogRelIs2Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP) + +/** @def LogRelIs3Enabled + * Checks whether level 3 release logging is enabled. + */ +#define LogRelIs3Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_3, LOG_GROUP) + +/** @def LogRelIs4Enabled + * Checks whether level 4 release logging is enabled. + */ +#define LogRelIs4Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_4, LOG_GROUP) + +/** @def LogRelIs5Enabled + * Checks whether level 5 release logging is enabled. + */ +#define LogRelIs5Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_5, LOG_GROUP) + +/** @def LogRelIs6Enabled + * Checks whether level 6 release logging is enabled. + */ +#define LogRelIs6Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_6, LOG_GROUP) + +/** @def LogRelIs7Enabled + * Checks whether level 7 release logging is enabled. + */ +#define LogRelIs7Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_7, LOG_GROUP) + +/** @def LogRelIs8Enabled + * Checks whether level 8 release logging is enabled. + */ +#define LogRelIs8Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_8, LOG_GROUP) + +/** @def LogRelIs2Enabled + * Checks whether level 9 release logging is enabled. + */ +#define LogRelIs9Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_9, LOG_GROUP) + +/** @def LogRelIs10Enabled + * Checks whether level 10 release logging is enabled. + */ +#define LogRelIs10Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_10, LOG_GROUP) + +/** @def LogRelIs11Enabled + * Checks whether level 10 release logging is enabled. + */ +#define LogRelIs11Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_11, LOG_GROUP) + +/** @def LogRelIs12Enabled + * Checks whether level 12 release logging is enabled. + */ +#define LogRelIs12Enabled() LogRelIsItEnabled(RTLOGGRPFLAGS_LEVEL_12, LOG_GROUP) + +/** @def LogRelIsFlowEnabled + * Checks whether execution flow release logging is enabled. + */ +#define LogRelIsFlowEnabled() LogRelIsItEnabled(RTLOGGRPFLAGS_FLOW, LOG_GROUP) + +/** @def LogRelIsWarnEnabled + * Checks whether warning level release logging is enabled. + */ +#define LogRelIsWarnEnabled() LogRelIsItEnabled(RTLOGGRPFLAGS_FLOW, LOG_GROUP) +/** @} */ + + +/** @def LogRelIt + * Write to specific logger if group enabled. + */ +/** @def LogRelItLikely + * Write to specific logger if group enabled, assuming it likely it is enabled. + */ +/** @def LogRelMaxIt + * Write to specific logger if group enabled and at less than a_cMax messages + * have hit the log. Uses a static variable to count. + */ +#ifdef RTLOG_REL_ENABLED +# if defined(LOG_USE_C99) +# define _LogRelRemoveParentheseis(...) __VA_ARGS__ +# define _LogRelIt(a_fFlags, a_iGroup, ...) \ + do \ + { \ + PRTLOGGER LogRelIt_pLogger = RTLogRelGetDefaultInstanceExWeak(RT_MAKE_U32(a_fFlags, a_iGroup)); \ + if (RT_LIKELY(!LogRelIt_pLogger)) \ + { /* likely */ } \ + else \ + RTLogLoggerExWeak(LogRelIt_pLogger, a_fFlags, a_iGroup, __VA_ARGS__); \ + _LogIt(a_fFlags, a_iGroup, __VA_ARGS__); \ + } while (0) +# define LogRelIt(a_fFlags, a_iGroup, fmtargs) \ + _LogRelIt(a_fFlags, a_iGroup, _LogRelRemoveParentheseis fmtargs) +# define _LogRelItLikely(a_fFlags, a_iGroup, ...) \ + do \ + { \ + PRTLOGGER LogRelIt_pLogger = RTLogRelGetDefaultInstanceExWeak(RT_MAKE_U32(a_fFlags, a_iGroup)); \ + if (LogRelIt_pLogger) \ + RTLogLoggerExWeak(LogRelIt_pLogger, a_fFlags, a_iGroup, __VA_ARGS__); \ + _LogIt(a_fFlags, a_iGroup, __VA_ARGS__); \ + } while (0) +# define LogRelItLikely(a_fFlags, a_iGroup, fmtargs) \ + _LogRelItLikely(a_fFlags, a_iGroup, _LogRelRemoveParentheseis fmtargs) +# define _LogRelMaxIt(a_cMax, a_fFlags, a_iGroup, ...) \ + do \ + { \ + PRTLOGGER LogRelIt_pLogger = RTLogRelGetDefaultInstanceExWeak(RT_MAKE_U32(a_fFlags, a_iGroup)); \ + if (LogRelIt_pLogger) \ + { \ + static uint32_t s_LogRelMaxIt_cLogged = 0; \ + if (s_LogRelMaxIt_cLogged < (a_cMax)) \ + { \ + s_LogRelMaxIt_cLogged++; \ + RTLogLoggerExWeak(LogRelIt_pLogger, a_fFlags, a_iGroup, __VA_ARGS__); \ + } \ + } \ + _LogIt(a_fFlags, a_iGroup, __VA_ARGS__); \ + } while (0) +# define LogRelMaxIt(a_cMax, a_fFlags, a_iGroup, fmtargs) \ + _LogRelMaxIt(a_cMax, a_fFlags, a_iGroup, _LogRelRemoveParentheseis fmtargs) +# else +# define LogRelItLikely(a_fFlags, a_iGroup, fmtargs) \ + do \ + { \ + PRTLOGGER LogRelIt_pLogger = RTLogRelGetDefaultInstanceExWeak(RT_MAKE_U32(a_fFlags, a_iGroup)); \ + if (LogRelIt_pLogger) \ + { \ + LogRelIt_pLogger->pfnLogger fmtargs; \ + } \ + LogIt(a_fFlags, a_iGroup, fmtargs); \ + } while (0) +# define LogRelIt(a_fFlags, a_iGroup, fmtargs) \ + do \ + { \ + PRTLOGGER LogRelIt_pLogger = RTLogRelGetDefaultInstanceExWeak(RT_MAKE_U32(a_fFlags, a_iGroup)); \ + if (RT_LIKELY(!LogRelIt_pLogger)) \ + { /* likely */ } \ + else \ + { \ + LogRelIt_pLogger->pfnLogger fmtargs; \ + } \ + LogIt(a_fFlags, a_iGroup, fmtargs); \ + } while (0) +# define LogRelMaxIt(a_cMax, a_fFlags, a_iGroup, fmtargs) \ + do \ + { \ + PRTLOGGER LogRelIt_pLogger = RTLogRelGetDefaultInstanceExWeak(RT_MAKE_U32(a_fFlags, a_iGroup)); \ + if (LogRelIt_pLogger) \ + { \ + static uint32_t s_LogRelMaxIt_cLogged = 0; \ + if (s_LogRelMaxIt_cLogged < (a_cMax)) \ + { \ + s_LogRelMaxIt_cLogged++; \ + LogRelIt_pLogger->pfnLogger fmtargs; \ + } \ + } \ + LogIt(a_fFlags, a_iGroup, fmtargs); \ + } while (0) +# endif +#else /* !RTLOG_REL_ENABLED */ +# define LogRelIt(a_fFlags, a_iGroup, fmtargs) do { } while (0) +# define LogRelItLikely(a_fFlags, a_iGroup, fmtargs) do { } while (0) +# define LogRelMaxIt(a_cMax, a_fFlags, a_iGroup, fmtargs) do { } while (0) +# if defined(LOG_USE_C99) +# define _LogRelRemoveParentheseis(...) __VA_ARGS__ +# define _LogRelIt(a_fFlags, a_iGroup, ...) do { } while (0) +# define _LogRelItLikely(a_fFlags, a_iGroup, ...) do { } while (0) +# define _LogRelMaxIt(a_cMax, a_fFlags, a_iGroup, ...) do { } while (0) +# endif +#endif /* !RTLOG_REL_ENABLED */ + + +/** @name Basic release logging macros + * @{ */ +/** @def LogRel + * Level 1 release logging. + */ +#define LogRel(a) LogRelItLikely(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, a) + +/** @def LogRel2 + * Level 2 release logging. + */ +#define LogRel2(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP, a) + +/** @def LogRel3 + * Level 3 release logging. + */ +#define LogRel3(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_3, LOG_GROUP, a) + +/** @def LogRel4 + * Level 4 release logging. + */ +#define LogRel4(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_4, LOG_GROUP, a) + +/** @def LogRel5 + * Level 5 release logging. + */ +#define LogRel5(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_5, LOG_GROUP, a) + +/** @def LogRel6 + * Level 6 release logging. + */ +#define LogRel6(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_6, LOG_GROUP, a) + +/** @def LogRel7 + * Level 7 release logging. + */ +#define LogRel7(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_7, LOG_GROUP, a) + +/** @def LogRel8 + * Level 8 release logging. + */ +#define LogRel8(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_8, LOG_GROUP, a) + +/** @def LogRel9 + * Level 9 release logging. + */ +#define LogRel9(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_9, LOG_GROUP, a) + +/** @def LogRel10 + * Level 10 release logging. + */ +#define LogRel10(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_10, LOG_GROUP, a) + +/** @def LogRel11 + * Level 11 release logging. + */ +#define LogRel11(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_11, LOG_GROUP, a) + +/** @def LogRel12 + * Level 12 release logging. + */ +#define LogRel12(a) LogRelIt(RTLOGGRPFLAGS_LEVEL_12, LOG_GROUP, a) + +/** @def LogRelFlow + * Logging of execution flow. + */ +#define LogRelFlow(a) LogRelIt(RTLOGGRPFLAGS_FLOW, LOG_GROUP, a) + +/** @def LogRelWarn + * Warning level release logging. + */ +#define LogRelWarn(a) LogRelIt(RTLOGGRPFLAGS_WARN, LOG_GROUP, a) +/** @} */ + + + +/** @name Basic release logging macros with local max + * @{ */ +/** @def LogRelMax + * Level 1 release logging with a max number of log entries. + */ +#define LogRelMax(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, a) + +/** @def LogRelMax2 + * Level 2 release logging with a max number of log entries. + */ +#define LogRelMax2(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP, a) + +/** @def LogRelMax3 + * Level 3 release logging with a max number of log entries. + */ +#define LogRelMax3(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_3, LOG_GROUP, a) + +/** @def LogRelMax4 + * Level 4 release logging with a max number of log entries. + */ +#define LogRelMax4(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_4, LOG_GROUP, a) + +/** @def LogRelMax5 + * Level 5 release logging with a max number of log entries. + */ +#define LogRelMax5(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_5, LOG_GROUP, a) + +/** @def LogRelMax6 + * Level 6 release logging with a max number of log entries. + */ +#define LogRelMax6(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_6, LOG_GROUP, a) + +/** @def LogRelMax7 + * Level 7 release logging with a max number of log entries. + */ +#define LogRelMax7(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_7, LOG_GROUP, a) + +/** @def LogRelMax8 + * Level 8 release logging with a max number of log entries. + */ +#define LogRelMax8(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_8, LOG_GROUP, a) + +/** @def LogRelMax9 + * Level 9 release logging with a max number of log entries. + */ +#define LogRelMax9(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_9, LOG_GROUP, a) + +/** @def LogRelMax10 + * Level 10 release logging with a max number of log entries. + */ +#define LogRelMax10(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_10, LOG_GROUP, a) + +/** @def LogRelMax11 + * Level 11 release logging with a max number of log entries. + */ +#define LogRelMax11(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_11, LOG_GROUP, a) + +/** @def LogRelMax12 + * Level 12 release logging with a max number of log entries. + */ +#define LogRelMax12(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_12, LOG_GROUP, a) + +/** @def LogRelMaxFlow + * Logging of execution flow with a max number of log entries. + */ +#define LogRelMaxFlow(a_cMax, a) LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_FLOW, LOG_GROUP, a) +/** @} */ + + +/** @name Release logging macros prefixing the current function name. + * @{ */ + +/** @def LogRelFunc + * Release logging. Prepends the given log message with the function name + * followed by a semicolon and space. + */ +#ifdef LOG_USE_C99 +# define LogRelFunc(a) \ + _LogRelItLikely(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogRelFunc(a) do { LogRel((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogRel(a); } while (0) +#endif + +/** @def LogRelFlowFunc + * Release logging. Macro to log the execution flow inside C/C++ functions. + * + * Prepends the given log message with the function name followed by + * a semicolon and space. + * + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define LogRelFlowFunc(a) _LogRelIt(RTLOGGRPFLAGS_FLOW, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogRelFlowFunc(a) do { LogRelFlow((LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogRelFlow(a); } while (0) +#endif + +/** @def LogRelMaxFunc + * Release logging. Prepends the given log message with the function name + * followed by a semicolon and space. + */ +#ifdef LOG_USE_C99 +# define LogRelMaxFunc(a_cMax, a) \ + _LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogRelMaxFunc(a_cMax, a) \ + do { LogRelMax(a_cMax, (LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogRelMax(a_cMax, a); } while (0) +#endif + +/** @def LogRelMaxFlowFunc + * Release logging. Macro to log the execution flow inside C/C++ functions. + * + * Prepends the given log message with the function name followed by + * a semicolon and space. + * + * @param a_cMax Max number of times this should hit the log. + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define LogRelMaxFlowFunc(a_cMax, a) \ + _LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_FLOW, LOG_GROUP, LOG_FN_FMT ": %M", RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogRelMaxFlowFunc(a_cMax, a) \ + do { LogRelMaxFlow(a_cMax, (LOG_FN_FMT ": ", RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogRelFlow(a_cMax, a); } while (0) +#endif + +/** @} */ + + +/** @name Release Logging macros prefixing the this pointer value and method name. + * @{ */ + +/** @def LogRelThisFunc + * The same as LogRelFunc but for class functions (methods): the resulting log + * line is additionally prepended with a hex value of |this| pointer. + */ +#ifdef LOG_USE_C99 +# define LogRelThisFunc(a) \ + _LogRelItLikely(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogRelThisFunc(a) \ + do { LogRel(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogRel(a); } while (0) +#endif + +/** @def LogRelMaxThisFunc + * The same as LogRelFunc but for class functions (methods): the resulting log + * line is additionally prepended with a hex value of |this| pointer. + * @param a_cMax Max number of times this should hit the log. + * @param a Log message in format <tt>("string\n" [, args])</tt>. + */ +#ifdef LOG_USE_C99 +# define LogRelMaxThisFunc(a_cMax, a) \ + _LogRelMaxIt(a_cMax, RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogRelMaxThisFunc(a_cMax, a) \ + do { LogRelMax(a_cMax, ("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogRelMax(a_cMax, a); } while (0) +#endif + +/** @def LogRelFlowThisFunc + * The same as LogRelFlowFunc but for class functions (methods): the resulting + * log line is additionally prepended with a hex value of |this| pointer. + */ +#ifdef LOG_USE_C99 +# define LogRelFlowThisFunc(a) \ + _LogRelIt(RTLOGGRPFLAGS_FLOW, LOG_GROUP, "{%p} " LOG_FN_FMT ": %M", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__, _LogRemoveParentheseis a ) +#else +# define LogRelFlowThisFunc(a) do { LogRelFlow(("{%p} " LOG_FN_FMT ": ", this, RT_GCC_EXTENSION __PRETTY_FUNCTION__)); LogRelFlow(a); } while (0) +#endif + + +/** Shortcut to |LogRelFlowFunc ("ENTER\n")|, marks the beginnig of the function. */ +#define LogRelFlowFuncEnter() LogRelFlowFunc(("ENTER\n")) + +/** Shortcut to |LogRelFlowFunc ("LEAVE\n")|, marks the end of the function. */ +#define LogRelFlowFuncLeave() LogRelFlowFunc(("LEAVE\n")) + +/** Shortcut to |LogRelFlowFunc ("LEAVE: %Rrc\n")|, marks the end of the function. */ +#define LogRelFlowFuncLeaveRC(rc) LogRelFlowFunc(("LEAVE: %Rrc\n", (rc))) + +/** Shortcut to |LogRelFlowThisFunc ("ENTER\n")|, marks the beginnig of the function. */ +#define LogRelFlowThisFuncEnter() LogRelFlowThisFunc(("ENTER\n")) + +/** Shortcut to |LogRelFlowThisFunc ("LEAVE\n")|, marks the end of the function. */ +#define LogRelFlowThisFuncLeave() LogRelFlowThisFunc(("LEAVE\n")) + +/** @} */ + + +/** + * Sets the default release logger instance. + * + * @returns The old default instance. + * @param pLogger The new default release logger instance. + */ +RTDECL(PRTLOGGER) RTLogRelSetDefaultInstance(PRTLOGGER pLogger); + +/** + * Gets the default release logger instance. + * + * @returns Pointer to default release logger instance if availble, otherwise NULL. + */ +RTDECL(PRTLOGGER) RTLogRelGetDefaultInstance(void); + +/** @copydoc RTLogRelGetDefaultInstance */ +typedef DECLCALLBACKTYPE(PRTLOGGER, FNLOGRELGETDEFAULTINSTANCE,(void)); +/** Pointer to RTLogRelGetDefaultInstance. */ +typedef FNLOGRELGETDEFAULTINSTANCE *PFNLOGRELGETDEFAULTINSTANCE; + +/** "Weak symbol" emulation for RTLogRelGetDefaultInstance. + * @note This is first set when RTLogRelSetDefaultInstance is called. */ +extern RTDATADECL(PFNLOGRELGETDEFAULTINSTANCE) g_pfnRTLogRelGetDefaultInstance; + +/** "Weak symbol" wrapper for RTLogRelGetDefaultInstance. */ +DECL_FORCE_INLINE(PRTLOGGER) RTLogRelGetDefaultInstanceWeak(void) +{ +#if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT)) + if (g_pfnRTLogRelGetDefaultInstance) + return g_pfnRTLogRelGetDefaultInstance(); + return NULL; +#else + return RTLogRelGetDefaultInstance(); +#endif +} + +/** + * Gets the default release logger instance. + * + * @returns Pointer to default release logger instance if availble, otherwise NULL. + * @param fFlagsAndGroup The flags in the lower 16 bits, the group number in + * the high 16 bits. + */ +RTDECL(PRTLOGGER) RTLogRelGetDefaultInstanceEx(uint32_t fFlagsAndGroup); + +/** @copydoc RTLogRelGetDefaultInstanceEx */ +typedef DECLCALLBACKTYPE(PRTLOGGER, FNLOGRELGETDEFAULTINSTANCEEX,(uint32_t fFlagsAndGroup)); +/** Pointer to RTLogRelGetDefaultInstanceEx. */ +typedef FNLOGRELGETDEFAULTINSTANCEEX *PFNLOGRELGETDEFAULTINSTANCEEX; + +/** "Weak symbol" emulation for RTLogRelGetDefaultInstanceEx. + * @note This is first set when RTLogRelSetDefaultInstance is called. */ +extern RTDATADECL(PFNLOGRELGETDEFAULTINSTANCEEX) g_pfnRTLogRelGetDefaultInstanceEx; + +/** "Weak symbol" wrapper for RTLogRelGetDefaultInstanceEx. */ +DECL_FORCE_INLINE(PRTLOGGER) RTLogRelGetDefaultInstanceExWeak(uint32_t fFlagsAndGroup) +{ +#if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT)) + if (g_pfnRTLogRelGetDefaultInstanceEx) + return g_pfnRTLogRelGetDefaultInstanceEx(fFlagsAndGroup); + return NULL; +#else + return RTLogRelGetDefaultInstanceEx(fFlagsAndGroup); +#endif +} + + +/** + * Write to a logger instance, defaulting to the release one. + * + * This function will check whether the instance, group and flags makes up a + * logging kind which is currently enabled before writing anything to the log. + * + * @param pLogger Pointer to logger instance. + * @param fFlags The logging flags. + * @param iGroup The group. + * The value ~0U is reserved for compatibility with RTLogLogger[V] and is + * only for internal usage! + * @param pszFormat Format string. + * @param ... Format arguments. + * @remark This is a worker function for LogRelIt. + */ +RTDECL(void) RTLogRelLogger(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(4, 5); + +/** + * Write to a logger instance, defaulting to the release one. + * + * This function will check whether the instance, group and flags makes up a + * logging kind which is currently enabled before writing anything to the log. + * + * @param pLogger Pointer to logger instance. If NULL the default release instance is attempted. + * @param fFlags The logging flags. + * @param iGroup The group. + * The value ~0U is reserved for compatibility with RTLogLogger[V] and is + * only for internal usage! + * @param pszFormat Format string. + * @param args Format arguments. + */ +RTDECL(void) RTLogRelLoggerV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, + const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(4, 0); + +/** + * printf like function for writing to the default release log. + * + * @param pszFormat Printf like format string. + * @param ... Optional arguments as specified in pszFormat. + * + * @remark The API doesn't support formatting of floating point numbers at the moment. + */ +RTDECL(void) RTLogRelPrintf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * vprintf like function for writing to the default release log. + * + * @param pszFormat Printf like format string. + * @param args Optional arguments as specified in pszFormat. + * + * @remark The API doesn't support formatting of floating point numbers at the moment. + */ +RTDECL(void) RTLogRelPrintfV(const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Changes the buffering setting of the default release logger. + * + * This can be used for optimizing longish logging sequences. + * + * @returns The old state. + * @param fBuffered The new state. + */ +RTDECL(bool) RTLogRelSetBuffering(bool fBuffered); + +/** @} */ + + + +/** @name COM port logging + * @{ + */ + +#ifdef DOXYGEN_RUNNING +# define LOG_TO_COM +# define LOG_NO_COM +#endif + +/** @def LOG_TO_COM + * Redirects the normal logging macros to the serial versions. + */ + +/** @def LOG_NO_COM + * Disables all LogCom* macros. + */ + +/** @def LogCom + * Generic logging to serial port. + */ +#if defined(LOG_ENABLED) && !defined(LOG_NO_COM) +# define LogCom(a) RTLogComPrintf a +#else +# define LogCom(a) do { } while (0) +#endif + +/** @def LogComFlow + * Logging to serial port of execution flow. + */ +#if defined(LOG_ENABLED) && defined(LOG_ENABLE_FLOW) && !defined(LOG_NO_COM) +# define LogComFlow(a) RTLogComPrintf a +#else +# define LogComFlow(a) do { } while (0) +#endif + +#ifdef LOG_TO_COM +# undef Log +# define Log(a) LogCom(a) +# undef LogFlow +# define LogFlow(a) LogComFlow(a) +#endif + +/** @} */ + + +/** @name Backdoor Logging + * @{ + */ + +#ifdef DOXYGEN_RUNNING +# define LOG_TO_BACKDOOR +# define LOG_NO_BACKDOOR +#endif + +/** @def LOG_TO_BACKDOOR + * Redirects the normal logging macros to the backdoor versions. + */ + +/** @def LOG_NO_BACKDOOR + * Disables all LogBackdoor* macros. + */ + +/** @def LogBackdoor + * Generic logging to the VBox backdoor via port I/O. + */ +#if defined(LOG_ENABLED) && !defined(LOG_NO_BACKDOOR) +# define LogBackdoor(a) RTLogBackdoorPrintf a +#else +# define LogBackdoor(a) do { } while (0) +#endif + +/** @def LogBackdoorFlow + * Logging of execution flow messages to the backdoor I/O port. + */ +#if defined(LOG_ENABLED) && !defined(LOG_NO_BACKDOOR) +# define LogBackdoorFlow(a) RTLogBackdoorPrintf a +#else +# define LogBackdoorFlow(a) do { } while (0) +#endif + +/** @def LogRelBackdoor + * Release logging to the VBox backdoor via port I/O. + */ +#if !defined(LOG_NO_BACKDOOR) +# define LogRelBackdoor(a) RTLogBackdoorPrintf a +#else +# define LogRelBackdoor(a) do { } while (0) +#endif + +#ifdef LOG_TO_BACKDOOR +# undef Log +# define Log(a) LogBackdoor(a) +# undef LogFlow +# define LogFlow(a) LogBackdoorFlow(a) +# undef LogRel +# define LogRel(a) LogRelBackdoor(a) +# if defined(LOG_USE_C99) +# undef _LogIt +# define _LogIt(a_fFlags, a_iGroup, ...) LogBackdoor((__VA_ARGS__)) +# endif +#endif + +/** @} */ + + + +/** + * Gets the default logger instance, creating it if necessary. + * + * @returns Pointer to default logger instance if availble, otherwise NULL. + */ +RTDECL(PRTLOGGER) RTLogDefaultInstance(void); + +/** + * Gets the logger instance if enabled, creating it if necessary. + * + * @returns Pointer to default logger instance, if group has the specified + * flags enabled. Otherwise NULL is returned. + * @param fFlagsAndGroup The flags in the lower 16 bits, the group number in + * the high 16 bits. + */ +RTDECL(PRTLOGGER) RTLogDefaultInstanceEx(uint32_t fFlagsAndGroup); + +/** + * Gets the default logger instance (does not create one). + * + * @returns Pointer to default logger instance if availble, otherwise NULL. + */ +RTDECL(PRTLOGGER) RTLogGetDefaultInstance(void); + +/** @copydoc RTLogGetDefaultInstance */ +typedef DECLCALLBACKTYPE(PRTLOGGER, FNLOGGETDEFAULTINSTANCE,(void)); +/** Pointer to RTLogGetDefaultInstance. */ +typedef FNLOGGETDEFAULTINSTANCE *PFNLOGGETDEFAULTINSTANCE; + +/** "Weak symbol" emulation for RTLogGetDefaultInstance. + * @note This is first set when RTLogSetDefaultInstance is called. */ +extern RTDATADECL(PFNLOGGETDEFAULTINSTANCE) g_pfnRTLogGetDefaultInstance; + +/** "Weak symbol" wrapper for RTLogGetDefaultInstance. */ +DECL_FORCE_INLINE(PRTLOGGER) RTLogGetDefaultInstanceWeak(void) +{ +#if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT)) + if (g_pfnRTLogGetDefaultInstance) + return g_pfnRTLogGetDefaultInstance(); + return NULL; +#else + return RTLogGetDefaultInstance(); +#endif +} + +/** + * Gets the default logger instance if enabled (does not create one). + * + * @returns Pointer to default logger instance, if group has the specified + * flags enabled. Otherwise NULL is returned. + * @param fFlagsAndGroup The flags in the lower 16 bits, the group number in + * the high 16 bits. + */ +RTDECL(PRTLOGGER) RTLogGetDefaultInstanceEx(uint32_t fFlagsAndGroup); + +/** @copydoc RTLogGetDefaultInstanceEx */ +typedef DECLCALLBACKTYPE(PRTLOGGER, FNLOGGETDEFAULTINSTANCEEX,(uint32_t fFlagsAndGroup)); +/** Pointer to RTLogGetDefaultInstanceEx. */ +typedef FNLOGGETDEFAULTINSTANCEEX *PFNLOGGETDEFAULTINSTANCEEX; + +/** "Weak symbol" emulation for RTLogGetDefaultInstanceEx. + * @note This is first set when RTLogSetDefaultInstance is called. */ +extern RTDATADECL(PFNLOGGETDEFAULTINSTANCEEX) g_pfnRTLogGetDefaultInstanceEx; + +/** "Weak symbol" wrapper for RTLogGetDefaultInstanceEx. */ +DECL_FORCE_INLINE(PRTLOGGER) RTLogGetDefaultInstanceExWeak(uint32_t fFlagsAndGroup) +{ +#if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT)) + if (g_pfnRTLogGetDefaultInstanceEx) + return g_pfnRTLogGetDefaultInstanceEx(fFlagsAndGroup); + return NULL; +#else + return RTLogGetDefaultInstanceEx(fFlagsAndGroup); +#endif +} + +/** + * Sets the default logger instance. + * + * @returns The old default instance. + * @param pLogger The new default logger instance. + */ +RTDECL(PRTLOGGER) RTLogSetDefaultInstance(PRTLOGGER pLogger); + +#ifdef IN_RING0 +/** + * Changes the default logger instance for the current thread. + * + * @returns IPRT status code. + * @param pLogger The logger instance. Pass NULL for deregistration. + * @param uKey Associated key for cleanup purposes. If pLogger is NULL, + * all instances with this key will be deregistered. So in + * order to only deregister the instance associated with the + * current thread use 0. + */ +RTR0DECL(int) RTLogSetDefaultInstanceThread(PRTLOGGER pLogger, uintptr_t uKey); +#endif /* IN_RING0 */ + +/** + * Creates the default logger instance for IPRT users. + * + * Any user of the logging features will need to implement + * this or use the generic dummy. + * + * @returns Pointer to the logger instance. + */ +RTDECL(PRTLOGGER) RTLogDefaultInit(void); + +/** + * This is the 2nd half of what RTLogGetDefaultInstanceEx() and + * RTLogRelGetDefaultInstanceEx() does. + * + * @returns If the group has the specified flags enabled @a pLogger will be + * returned returned. Otherwise NULL is returned. + * @param pLogger The logger. NULL is NULL. + * @param fFlagsAndGroup The flags in the lower 16 bits, the group number in + * the high 16 bits. + */ +RTDECL(PRTLOGGER) RTLogCheckGroupFlags(PRTLOGGER pLogger, uint32_t fFlagsAndGroup); + +/** + * Create a logger instance. + * + * @returns iprt status code. + * + * @param ppLogger Where to store the logger instance. + * @param fFlags Logger instance flags, a combination of the + * RTLOGFLAGS_* values. + * @param pszGroupSettings The initial group settings. + * @param pszEnvVarBase Base name for the environment variables for + * this instance. + * @param cGroups Number of groups in the array. + * @param papszGroups Pointer to array of groups. This must stick + * around for the life of the logger instance. + * @param fDestFlags The destination flags. RTLOGDEST_FILE is ORed + * if pszFilenameFmt specified. + * @param pszFilenameFmt Log filename format string. Standard + * RTStrFormat(). + * @param ... Format arguments. + */ +RTDECL(int) RTLogCreate(PRTLOGGER *ppLogger, uint64_t fFlags, const char *pszGroupSettings, + const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups, + uint32_t fDestFlags, const char *pszFilenameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(8, 9); + +/** + * Create a logger instance. + * + * @returns iprt status code. + * + * @param ppLogger Where to store the logger instance. + * @param pszEnvVarBase Base name for the environment variables for + * this instance (ring-3 only). + * @param fFlags Logger instance flags, a combination of the + * RTLOGFLAGS_* values. + * @param pszGroupSettings The initial group settings. + * @param cGroups Number of groups in the array. + * @param papszGroups Pointer to array of groups. This must stick + * around for the life of the logger instance. + * @param cMaxEntriesPerGroup The max number of entries per group. UINT32_MAX + * or zero for unlimited. + * @param cBufDescs Number of buffer descriptors that @a paBufDescs + * points to. Zero for defaults. + * @param paBufDescs Buffer descriptors, optional. + * @param fDestFlags The destination flags. RTLOGDEST_FILE is ORed + * if pszFilenameFmt specified. + * @param pfnPhase Callback function for starting logging and for + * ending or starting a new file for log history + * rotation. NULL is OK. + * @param cHistory Number of old log files to keep when performing + * log history rotation. 0 means no history. + * @param cbHistoryFileMax Maximum size of log file when performing + * history rotation. 0 means no size limit. + * @param cSecsHistoryTimeSlot Maximum time interval per log file when + * performing history rotation, in seconds. + * 0 means time limit. + * @param pOutputIf The optional file output interface, can be NULL which will + * make use of the default one. + * @param pvOutputIfUser The opaque user data to pass to the callbacks in the output interface. + * @param pErrInfo Where to return extended error information. + * Optional. + * @param pszFilenameFmt Log filename format string. Standard RTStrFormat(). + * @param ... Format arguments. + */ +RTDECL(int) RTLogCreateEx(PRTLOGGER *ppLogger, const char *pszEnvVarBase, uint64_t fFlags, const char *pszGroupSettings, + unsigned cGroups, const char * const *papszGroups, uint32_t cMaxEntriesPerGroup, + uint32_t cBufDescs, PRTLOGBUFFERDESC paBufDescs, uint32_t fDestFlags, + PFNRTLOGPHASE pfnPhase, uint32_t cHistory, uint64_t cbHistoryFileMax, uint32_t cSecsHistoryTimeSlot, + PCRTLOGOUTPUTIF pOutputIf, void *pvOutputIfUser, + PRTERRINFO pErrInfo, const char *pszFilenameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(18, 19); + +/** + * Create a logger instance. + * + * @returns iprt status code. + * + * @param ppLogger Where to store the logger instance. + * @param pszEnvVarBase Base name for the environment variables for + * this instance (ring-3 only). + * @param fFlags Logger instance flags, a combination of the + * RTLOGFLAGS_* values. + * @param pszGroupSettings The initial group settings. + * @param cGroups Number of groups in the array. + * @param papszGroups Pointer to array of groups. This must stick + * around for the life of the logger instance. + * @param cMaxEntriesPerGroup The max number of entries per group. UINT32_MAX + * or zero for unlimited. + * @param cBufDescs Number of buffer descriptors that @a paBufDescs + * points to. Zero for defaults. + * @param paBufDescs Buffer descriptors, optional. + * @param fDestFlags The destination flags. RTLOGDEST_FILE is ORed + * if pszFilenameFmt specified. + * @param pfnPhase Callback function for starting logging and for + * ending or starting a new file for log history + * rotation. + * @param cHistory Number of old log files to keep when performing + * log history rotation. 0 means no history. + * @param cbHistoryFileMax Maximum size of log file when performing + * history rotation. 0 means no size limit. + * @param cSecsHistoryTimeSlot Maximum time interval per log file when + * performing history rotation, in seconds. + * 0 means no time limit. + * @param pOutputIf The optional file output interface, can be NULL which will + * make use of the default one. + * @param pvOutputIfUser The opaque user data to pass to the callbacks in the output interface. + * @param pErrInfo Where to return extended error information. + * Optional. + * @param pszFilenameFmt Log filename format string. Standard + * RTStrFormat(). + * @param va Format arguments. + */ +RTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, const char *pszEnvVarBase, uint64_t fFlags, const char *pszGroupSettings, + uint32_t cGroups, const char * const *papszGroups, uint32_t cMaxEntriesPerGroup, + uint32_t cBufDescs, PRTLOGBUFFERDESC paBufDescs, uint32_t fDestFlags, + PFNRTLOGPHASE pfnPhase, uint32_t cHistory, uint64_t cbHistoryFileMax, uint32_t cSecsHistoryTimeSlot, + PCRTLOGOUTPUTIF pOutputIf, void *pvOutputIfUser, + PRTERRINFO pErrInfo, const char *pszFilenameFmt, va_list va) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(18, 0); + +/** + * Destroys a logger instance. + * + * The instance is flushed and all output destinations closed (where applicable). + * + * @returns iprt status code. + * @param pLogger The logger instance which close destroyed. NULL is fine. + */ +RTDECL(int) RTLogDestroy(PRTLOGGER pLogger); + +/** + * Sets the custom prefix callback. + * + * @returns IPRT status code. + * @param pLogger The logger instance. + * @param pfnCallback The callback. + * @param pvUser The user argument for the callback. + * */ +RTDECL(int) RTLogSetCustomPrefixCallback(PRTLOGGER pLogger, PFNRTLOGPREFIX pfnCallback, void *pvUser); + +/** + * Sets the custom flush callback. + * + * This can be handy for special loggers like the per-EMT ones in ring-0, + * but also for implementing a log viewer in the debugger GUI. + * + * @returns IPRT status code. + * @retval VWRN_ALREADY_EXISTS if it was set to a different flusher. + * @param pLogger The logger instance. + * @param pfnFlush The flush callback. + */ +RTDECL(int) RTLogSetFlushCallback(PRTLOGGER pLogger, PFNRTLOGFLUSH pfnFlush); + +/** + * Sets the thread name for a thread specific ring-0 logger. + * + * @returns IPRT status code. + * @param pLogger The logger. NULL is not allowed. + * @param pszNameFmt The format string for the thread name. + * @param ... Format arguments. + */ +RTR0DECL(int) RTLogSetR0ThreadNameF(PRTLOGGER pLogger, const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Sets the thread name for a thread specific ring-0 logger. + * + * @returns IPRT status code. + * @param pLogger The logger. NULL is not allowed. + * @param pszNameFmt The format string for the thread name. + * @param va Format arguments. + */ +RTR0DECL(int) RTLogSetR0ThreadNameV(PRTLOGGER pLogger, const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Sets the program start time for a thread specific ring-0 logger. + * + * @returns IPRT status code. + * @param pLogger The logger. NULL is not allowed. + * @param nsStart The RTTimeNanoTS() value at program start. + */ +RTR0DECL(int) RTLogSetR0ProgramStart(PRTLOGGER pLogger, uint64_t nsStart); + +/** + * Get the current log group settings as a string. + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pLogger Logger instance (NULL for default logger). + * @param pszBuf The output buffer. + * @param cchBuf The size of the output buffer. Must be greater than + * zero. + */ +RTDECL(int) RTLogQueryGroupSettings(PRTLOGGER pLogger, char *pszBuf, size_t cchBuf); + +/** + * Updates the group settings for the logger instance using the specified + * specification string. + * + * @returns iprt status code. + * Failures can safely be ignored. + * @param pLogger Logger instance (NULL for default logger). + * @param pszValue Value to parse. + */ +RTDECL(int) RTLogGroupSettings(PRTLOGGER pLogger, const char *pszValue); + +/** + * Sets the max number of entries per group. + * + * @returns Old restriction. + * + * @param pLogger The logger instance (NULL is an alias for the + * default logger). + * @param cMaxEntriesPerGroup The max number of entries per group. + * + * @remarks Lowering the limit of an active logger may quietly mute groups. + * Raising it may reactive already muted groups. + */ +RTDECL(uint32_t) RTLogSetGroupLimit(PRTLOGGER pLogger, uint32_t cMaxEntriesPerGroup); + +/** + * Gets the current flag settings for the given logger. + * + * @returns Logger flags, UINT64_MAX if no logger. + * @param pLogger Logger instance (NULL for default logger). + */ +RTDECL(uint64_t) RTLogGetFlags(PRTLOGGER pLogger); + +/** + * Modifies the flag settings for the given logger. + * + * @returns IPRT status code. Returns VINF_LOG_NO_LOGGER if no default logger + * and @a pLogger is NULL. + * @param pLogger Logger instance (NULL for default logger). + * @param fSet Mask of flags to set (OR). + * @param fClear Mask of flags to clear (NAND). This is allowed to + * include invalid flags - e.g. UINT64_MAX is okay. + */ +RTDECL(int) RTLogChangeFlags(PRTLOGGER pLogger, uint64_t fSet, uint64_t fClear); + +/** + * Updates the flags for the logger instance using the specified + * specification string. + * + * @returns iprt status code. + * Failures can safely be ignored. + * @param pLogger Logger instance (NULL for default logger). + * @param pszValue Value to parse. + */ +RTDECL(int) RTLogFlags(PRTLOGGER pLogger, const char *pszValue); + +/** + * Changes the buffering setting of the specified logger. + * + * This can be used for optimizing longish logging sequences. + * + * @returns The old state. + * @param pLogger The logger instance (NULL is an alias for the default + * logger). + * @param fBuffered The new state. + */ +RTDECL(bool) RTLogSetBuffering(PRTLOGGER pLogger, bool fBuffered); + +/** + * Get the current log flags as a string. + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pLogger Logger instance (NULL for default logger). + * @param pszBuf The output buffer. + * @param cchBuf The size of the output buffer. Must be greater than + * zero. + */ +RTDECL(int) RTLogQueryFlags(PRTLOGGER pLogger, char *pszBuf, size_t cchBuf); + +/** + * Gets the current destinations flags for the given logger. + * + * @returns Logger destination flags, UINT32_MAX if no logger. + * @param pLogger Logger instance (NULL for default logger). + */ +RTDECL(uint32_t) RTLogGetDestinations(PRTLOGGER pLogger); + +/** + * Modifies the log destinations settings for the given logger. + * + * This is only suitable for simple destination settings that doesn't take + * additional arguments, like RTLOGDEST_FILE. + * + * @returns IPRT status code. Returns VINF_LOG_NO_LOGGER if no default logger + * and @a pLogger is NULL. + * @param pLogger Logger instance (NULL for default logger). + * @param fSet Mask of destinations to set (OR). + * @param fClear Mask of destinations to clear (NAND). + */ +RTDECL(int) RTLogChangeDestinations(PRTLOGGER pLogger, uint32_t fSet, uint32_t fClear); + +/** + * Updates the logger destination using the specified string. + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pLogger Logger instance (NULL for default logger). + * @param pszValue The value to parse. + */ +RTDECL(int) RTLogDestinations(PRTLOGGER pLogger, char const *pszValue); + +/** + * Clear the file delay flag if set, opening the destination and flushing. + * + * @returns IPRT status code. + * @param pLogger Logger instance (NULL for default logger). + * @param pErrInfo Where to return extended error info. Optional. + */ +RTDECL(int) RTLogClearFileDelayFlag(PRTLOGGER pLogger, PRTERRINFO pErrInfo); + +/** + * Get the current log destinations as a string. + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pLogger Logger instance (NULL for default logger). + * @param pszBuf The output buffer. + * @param cchBuf The size of the output buffer. Must be greater than 0. + */ +RTDECL(int) RTLogQueryDestinations(PRTLOGGER pLogger, char *pszBuf, size_t cchBuf); + +/** + * Performs a bulk update of logger flags and group flags. + * + * This is for instanced used for copying settings from ring-3 to ring-0 + * loggers. + * + * @returns IPRT status code. + * @param pLogger The logger instance (NULL for default logger). + * @param fFlags The new logger flags. + * @param uGroupCrc32 The CRC32 of the group name strings. + * @param cGroups Number of groups. + * @param pafGroups Array of group flags. + * @sa RTLogQueryBulk + */ +RTDECL(int) RTLogBulkUpdate(PRTLOGGER pLogger, uint64_t fFlags, uint32_t uGroupCrc32, uint32_t cGroups, uint32_t const *pafGroups); + +/** + * Queries data for a bulk update of logger flags and group flags. + * + * This is for instanced used for copying settings from ring-3 to ring-0 + * loggers. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if pafGroups is too small, @a pcGroups will be + * set to the actual number of groups. + * @param pLogger The logger instance (NULL for default logger). + * @param pfFlags Where to return the logger flags. + * @param puGroupCrc32 Where to return the CRC32 of the group names. + * @param pcGroups Input: Size of the @a pafGroups allocation. + * Output: Actual number of groups returned. + * @param pafGroups Where to return the flags for each group. + * @sa RTLogBulkUpdate + */ +RTDECL(int) RTLogQueryBulk(PRTLOGGER pLogger, uint64_t *pfFlags, uint32_t *puGroupCrc32, uint32_t *pcGroups, uint32_t *pafGroups); + +/** + * Write/copy bulk log data from another logger. + * + * This is used for transferring stuff from the ring-0 loggers and into the + * ring-3 one. The text goes in as-is w/o any processing (i.e. prefixing or + * newline fun). + * + * @returns IRPT status code. + * @param pLogger The logger instance (NULL for default logger). + * @param pszBefore Text to log before the bulk text. Optional. + * @param pch Pointer to the block of bulk log text to write. + * @param cch Size of the block of bulk log text to write. + * @param pszAfter Text to log after the bulk text. Optional. + */ +RTDECL(int) RTLogBulkWrite(PRTLOGGER pLogger, const char *pszBefore, const char *pch, size_t cch, const char *pszAfter); + +/** + * Write/copy bulk log data from a nested VM logger. + * + * This is used for + * + * @returns IRPT status code. + * @param pLogger The logger instance (NULL for default logger). + * @param pch Pointer to the block of bulk log text to write. + * @param cch Size of the block of bulk log text to write. + * @param pszInfix String to put after the line prefixes and the + * line content. + */ +RTDECL(int) RTLogBulkNestedWrite(PRTLOGGER pLogger, const char *pch, size_t cch, const char *pszInfix); + +/** + * Flushes the specified logger. + * + * @returns IRPT status code. + * @param pLogger The logger instance to flush. + * If NULL the default instance is used. The default instance + * will not be initialized by this call. + */ +RTDECL(int) RTLogFlush(PRTLOGGER pLogger); + +/** + * Write to a logger instance. + * + * @param pLogger Pointer to logger instance. + * @param pvCallerRet Ignored. + * @param pszFormat Format string. + * @param ... Format arguments. + */ +RTDECL(void) RTLogLogger(PRTLOGGER pLogger, void *pvCallerRet, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Write to a logger instance, weak version. + * + * @param pLogger Pointer to logger instance. + * @param pvCallerRet Ignored. + * @param pszFormat Format string. + * @param ... Format arguments. + */ +#if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT)) +RTDECL(void) RTLogLoggerWeak(PRTLOGGER pLogger, void *pvCallerRet, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); +#else /* Cannot use a DECL_FORCE_INLINE because older GCC versions doesn't support inlining va_start. */ +# undef RTLogLoggerWeak /* in case of mangling */ +# define RTLogLoggerWeak RTLogLogger +#endif + +/** + * Write to a logger instance. + * + * @param pLogger Pointer to logger instance. + * @param pszFormat Format string. + * @param args Format arguments. + */ +RTDECL(void) RTLogLoggerV(PRTLOGGER pLogger, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Write to a logger instance. + * + * This function will check whether the instance, group and flags makes up a + * logging kind which is currently enabled before writing anything to the log. + * + * @param pLogger Pointer to logger instance. If NULL the default logger instance will be attempted. + * @param fFlags The logging flags. + * @param iGroup The group. + * The value ~0U is reserved for compatibility with RTLogLogger[V] and is + * only for internal usage! + * @param pszFormat Format string. + * @param ... Format arguments. + * @remark This is a worker function of LogIt. + */ +RTDECL(void) RTLogLoggerEx(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(4, 5); + +/** + * Write to a logger instance, weak version. + * + * This function will check whether the instance, group and flags makes up a + * logging kind which is currently enabled before writing anything to the log. + * + * @param pLogger Pointer to logger instance. If NULL the default logger instance will be attempted. + * @param fFlags The logging flags. + * @param iGroup The group. + * The value ~0U is reserved for compatibility with RTLogLogger[V] and is + * only for internal usage! + * @param pszFormat Format string. + * @param ... Format arguments. + * @remark This is a worker function of LogIt. + */ +#if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT)) +RTDECL(void) RTLogLoggerExWeak(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(4, 5); +#else /* Cannot use a DECL_FORCE_INLINE because older GCC versions doesn't support inlining va_start. */ +# undef RTLogLoggerExWeak /* in case of mangling */ +# define RTLogLoggerExWeak RTLogLoggerEx +#endif + +/** + * Write to a logger instance. + * + * This function will check whether the instance, group and flags makes up a + * logging kind which is currently enabled before writing anything to the log. + * + * @returns VINF_SUCCESS, VINF_LOG_NO_LOGGER, VINF_LOG_DISABLED, or IPRT error + * status. + * @param pLogger Pointer to logger instance. If NULL the default logger instance will be attempted. + * @param fFlags The logging flags. + * @param iGroup The group. + * The value ~0U is reserved for compatibility with RTLogLogger[V] and is + * only for internal usage! + * @param pszFormat Format string. + * @param args Format arguments. + */ +RTDECL(int) RTLogLoggerExV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, + const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(4, 0); + +/** @copydoc RTLogLoggerExV */ +typedef DECLCALLBACKTYPE(int, FNRTLOGLOGGEREXV,(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, + const char *pszFormat, va_list args)) RT_IPRT_FORMAT_ATTR(4, 0); +/** Pointer to RTLogLoggerExV. */ +typedef FNRTLOGLOGGEREXV *PFNRTLOGLOGGEREXV; +/** "Weak symbol" emulation for RTLogLoggerExV. + * @note This is first set when RTLogCreateEx or RTLogCreate is called. */ +extern RTDATADECL(PFNRTLOGLOGGEREXV) g_pfnRTLogLoggerExV; + +/** "Weak symbol" wrapper for RTLogLoggerExV. */ +DECL_FORCE_INLINE(int) RTLogLoggerExVWeak(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, + const char *pszFormat, va_list args) /* RT_IPRT_FORMAT_ATTR(4, 0) */ +{ +#if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT)) + if (g_pfnRTLogLoggerExV) + return g_pfnRTLogLoggerExV(pLogger, fFlags, iGroup, pszFormat, args); + return 22301; /* VINF_LOG_DISABLED, don't want err.h dependency here. */ +#else + return RTLogLoggerExV(pLogger, fFlags, iGroup, pszFormat, args); +#endif +} + +/** + * printf like function for writing to the default log. + * + * @param pszFormat Printf like format string. + * @param ... Optional arguments as specified in pszFormat. + * + * @remark The API doesn't support formatting of floating point numbers at the moment. + */ +RTDECL(void) RTLogPrintf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * vprintf like function for writing to the default log. + * + * @param pszFormat Printf like format string. + * @param va Optional arguments as specified in pszFormat. + * + * @remark The API doesn't support formatting of floating point numbers at the moment. + */ +RTDECL(void) RTLogPrintfV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Dumper vprintf-like function outputting to a logger. + * + * @param pvUser Pointer to the logger instance to use, NULL for default + * instance. + * @param pszFormat Format string. + * @param va Format arguments. + */ +RTDECL(void) RTLogDumpPrintfV(void *pvUser, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Used for logging assertions, debug and release log as appropriate. + * + * Implies flushing. + * + * @param pszFormat Format string. + * @param ... Format arguments. + */ +typedef DECLCALLBACKTYPE(void, FNRTLOGASSERTION,(const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(1, 2); +/** Pointer to an assertion logger, ellipsis variant. */ +typedef FNRTLOGASSERTION *PFNRTLOGASSERTION; + +/** + * Used for logging assertions, debug and release log as appropriate. + * + * Implies flushing. + * + * @param pszFormat Format string. + * @param va Format arguments. + */ +typedef DECLCALLBACKTYPE(void, FNRTLOGASSERTIONV,(const char *pszFormat, va_list va)) RT_IPRT_FORMAT_ATTR(1, 0); +/** Pointer to an assertion logger, va_list variant. */ +typedef FNRTLOGASSERTIONV *PFNRTLOGASSERTIONV; + +/** @copydoc FNRTLOGASSERTION */ +RTDECL(void) RTLogAssert(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); +/** @copydoc FNRTLOGASSERTIONV */ +RTDECL(void) RTLogAssertV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** "Weak symbol" emulation for RTLogAssert. */ +extern RTDATADECL(PFNRTLOGASSERTION) g_pfnRTLogAssert; +/** "Weak symbol" emulation for RTLogAssertV. */ +extern RTDATADECL(PFNRTLOGASSERTIONV) g_pfnRTLogAssertV; + + +#ifndef DECLARED_FNRTSTROUTPUT /* duplicated in iprt/string.h & iprt/errcore.h */ +#define DECLARED_FNRTSTROUTPUT +/** + * Output callback. + * + * @returns number of bytes written. + * @param pvArg User argument. + * @param pachChars Pointer to an array of utf-8 characters. + * @param cbChars Number of bytes in the character array pointed to by pachChars. + */ +typedef DECLCALLBACKTYPE(size_t, FNRTSTROUTPUT,(void *pvArg, const char *pachChars, size_t cbChars)); +/** Pointer to callback function. */ +typedef FNRTSTROUTPUT *PFNRTSTROUTPUT; +#endif + +/** + * Partial vsprintf worker implementation. + * + * @returns number of bytes formatted. + * @param pfnOutput Output worker. + * Called in two ways. Normally with a string an it's length. + * For termination, it's called with NULL for string, 0 for length. + * @param pvArg Argument to output worker. + * @param pszFormat Format string. + * @param args Argument list. + */ +RTDECL(size_t) RTLogFormatV(PFNRTSTROUTPUT pfnOutput, void *pvArg, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Write log buffer to COM port. + * + * @param pach Pointer to the buffer to write. + * @param cb Number of bytes to write. + */ +RTDECL(void) RTLogWriteCom(const char *pach, size_t cb); + +/** + * Prints a formatted string to the serial port used for logging. + * + * @returns Number of bytes written. + * @param pszFormat Format string. + * @param ... Optional arguments specified in the format string. + */ +RTDECL(size_t) RTLogComPrintf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Prints a formatted string to the serial port used for logging. + * + * @returns Number of bytes written. + * @param pszFormat Format string. + * @param args Optional arguments specified in the format string. + */ +RTDECL(size_t) RTLogComPrintfV(const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Write log buffer to a debugger (RTLOGDEST_DEBUGGER). + * + * @param pach What to write. + * @param cb How much to write. + * @remark When linking statically, this function can be replaced by defining your own. + */ +RTDECL(void) RTLogWriteDebugger(const char *pach, size_t cb); + +/** + * Write log buffer to a user defined output stream (RTLOGDEST_USER). + * + * @param pach What to write. + * @param cb How much to write. + * @remark When linking statically, this function can be replaced by defining your own. + */ +RTDECL(void) RTLogWriteUser(const char *pach, size_t cb); + +/** + * Write log buffer to a parent VMM (hypervisor). + * + * @param pach What to write. + * @param cb How much to write. + * @param fRelease Set if targeting the release log, clear if debug log. + * + * @note Currently only available on AMD64 and x86. + */ +RTDECL(void) RTLogWriteVmm(const char *pach, size_t cb, bool fRelease); + +/** + * Write log buffer to stdout (RTLOGDEST_STDOUT). + * + * @param pach What to write. + * @param cb How much to write. + * @remark When linking statically, this function can be replaced by defining your own. + */ +RTDECL(void) RTLogWriteStdOut(const char *pach, size_t cb); + +/** + * Write log buffer to stdout (RTLOGDEST_STDERR). + * + * @param pach What to write. + * @param cb How much to write. + * @remark When linking statically, this function can be replaced by defining your own. + */ +RTDECL(void) RTLogWriteStdErr(const char *pach, size_t cb); + +#ifdef VBOX + +/** + * Prints a formatted string to the backdoor port. + * + * @returns Number of bytes written. + * @param pszFormat Format string. + * @param ... Optional arguments specified in the format string. + */ +RTDECL(size_t) RTLogBackdoorPrintf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Prints a formatted string to the backdoor port. + * + * @returns Number of bytes written. + * @param pszFormat Format string. + * @param args Optional arguments specified in the format string. + */ +RTDECL(size_t) RTLogBackdoorPrintfV(const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(1, 0); + +#endif /* VBOX */ + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_log_h */ + diff --git a/include/iprt/mangling.h b/include/iprt/mangling.h new file mode 100644 index 00000000..eef92f51 --- /dev/null +++ b/include/iprt/mangling.h @@ -0,0 +1,4320 @@ +/** @file + * IPRT - Symbol Mangling. + * + * This header is used to mangle public IPRT symbol to make it possible to have + * several IPRT version loaded into one symbol space at the same time. To + * enable symbol mangling you create a header which the compiler includes for + * every compilation unit (check out the -include option of gcc). Your header + * will define RT_MANGLER(name) and then include this header to set up the + * actual mappings. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_mangling_h +#define IPRT_INCLUDED_mangling_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef RT_MANGLER +# error "RT_MANGLER is not defined." +#endif + +#ifndef DOXYGEN_RUNNING + +/** @def RT_WITH_MANGLING + * Indicates that we're mangling symbols. */ +# define RT_WITH_MANGLING + + +/* + * Stable functions (alphabetical order): + */ +/* ASM*: + grep -h DECLASM include/iprt/asm.h include/iprt/asm-amd64-x86.h \ + | kmk_sed -e 's/^DECLASM.[^)]*. *\(ASM[^(]*\)[(].*$/# define \1 :RT_MANGLER(\1)\n# define \1_EndProc :RT_MANGLER(\1_EndProc)/' \ + | sort \ + | awk -F: '{ printf("%-55s %s\n", $1, $2);' */ +# define ASMAddFlags RT_MANGLER(ASMAddFlags) +# define ASMAddFlags_EndProc RT_MANGLER(ASMAddFlags_EndProc) +# define ASMAtomicAddU16 RT_MANGLER(ASMAtomicAddU16) +# define ASMAtomicAddU16_EndProc RT_MANGLER(ASMAtomicAddU16_EndProc) +# define ASMAtomicAddU32 RT_MANGLER(ASMAtomicAddU32) +# define ASMAtomicAddU32_EndProc RT_MANGLER(ASMAtomicAddU32_EndProc) +# define ASMAtomicAddU64 RT_MANGLER(ASMAtomicAddU64) +# define ASMAtomicAddU64_EndProc RT_MANGLER(ASMAtomicAddU64_EndProc) +# define ASMAtomicAndU32 RT_MANGLER(ASMAtomicAndU32) +# define ASMAtomicAndU32_EndProc RT_MANGLER(ASMAtomicAndU32_EndProc) +# define ASMAtomicAndU64 RT_MANGLER(ASMAtomicAndU64) +# define ASMAtomicAndU64_EndProc RT_MANGLER(ASMAtomicAndU64_EndProc) +# define ASMAtomicBitClear RT_MANGLER(ASMAtomicBitClear) +# define ASMAtomicBitClear_EndProc RT_MANGLER(ASMAtomicBitClear_EndProc) +# define ASMAtomicBitSet RT_MANGLER(ASMAtomicBitSet) +# define ASMAtomicBitSet_EndProc RT_MANGLER(ASMAtomicBitSet_EndProc) +# define ASMAtomicBitTestAndClear RT_MANGLER(ASMAtomicBitTestAndClear) +# define ASMAtomicBitTestAndClear_EndProc RT_MANGLER(ASMAtomicBitTestAndClear_EndProc) +# define ASMAtomicBitTestAndSet RT_MANGLER(ASMAtomicBitTestAndSet) +# define ASMAtomicBitTestAndSet_EndProc RT_MANGLER(ASMAtomicBitTestAndSet_EndProc) +# define ASMAtomicBitTestAndToggle RT_MANGLER(ASMAtomicBitTestAndToggle) +# define ASMAtomicBitTestAndToggle_EndProc RT_MANGLER(ASMAtomicBitTestAndToggle_EndProc) +# define ASMAtomicBitToggle RT_MANGLER(ASMAtomicBitToggle) +# define ASMAtomicBitToggle_EndProc RT_MANGLER(ASMAtomicBitToggle_EndProc) +# define ASMAtomicCmpXchgExU32 RT_MANGLER(ASMAtomicCmpXchgExU32) +# define ASMAtomicCmpXchgExU32_EndProc RT_MANGLER(ASMAtomicCmpXchgExU32_EndProc) +# define ASMAtomicCmpXchgExU64 RT_MANGLER(ASMAtomicCmpXchgExU64) +# define ASMAtomicCmpXchgExU64_EndProc RT_MANGLER(ASMAtomicCmpXchgExU64_EndProc) +# define ASMAtomicCmpXchgU32 RT_MANGLER(ASMAtomicCmpXchgU32) +# define ASMAtomicCmpXchgU32_EndProc RT_MANGLER(ASMAtomicCmpXchgU32_EndProc) +# define ASMAtomicCmpXchgU64 RT_MANGLER(ASMAtomicCmpXchgU64) +# define ASMAtomicCmpXchgU64_EndProc RT_MANGLER(ASMAtomicCmpXchgU64_EndProc) +# define ASMAtomicCmpXchgU8 RT_MANGLER(ASMAtomicCmpXchgU8) +# define ASMAtomicCmpXchgU8_EndProc RT_MANGLER(ASMAtomicCmpXchgU8_EndProc) +# define ASMAtomicDecU16 RT_MANGLER(ASMAtomicDecU16) +# define ASMAtomicDecU16_EndProc RT_MANGLER(ASMAtomicDecU16_EndProc) +# define ASMAtomicDecU32 RT_MANGLER(ASMAtomicDecU32) +# define ASMAtomicDecU32_EndProc RT_MANGLER(ASMAtomicDecU32_EndProc) +# define ASMAtomicDecU64 RT_MANGLER(ASMAtomicDecU64) +# define ASMAtomicDecU64_EndProc RT_MANGLER(ASMAtomicDecU64_EndProc) +# define ASMAtomicIncU16 RT_MANGLER(ASMAtomicIncU16) +# define ASMAtomicIncU16_EndProc RT_MANGLER(ASMAtomicIncU16_EndProc) +# define ASMAtomicIncU32 RT_MANGLER(ASMAtomicIncU32) +# define ASMAtomicIncU32_EndProc RT_MANGLER(ASMAtomicIncU32_EndProc) +# define ASMAtomicIncU64 RT_MANGLER(ASMAtomicIncU64) +# define ASMAtomicIncU64_EndProc RT_MANGLER(ASMAtomicIncU64_EndProc) +# define ASMAtomicOrU32 RT_MANGLER(ASMAtomicOrU32) +# define ASMAtomicOrU32_EndProc RT_MANGLER(ASMAtomicOrU32_EndProc) +# define ASMAtomicOrU64 RT_MANGLER(ASMAtomicOrU64) +# define ASMAtomicOrU64_EndProc RT_MANGLER(ASMAtomicOrU64_EndProc) +# define ASMAtomicReadU64 RT_MANGLER(ASMAtomicReadU64) +# define ASMAtomicReadU64_EndProc RT_MANGLER(ASMAtomicReadU64_EndProc) +# define ASMAtomicUoAndU32 RT_MANGLER(ASMAtomicUoAndU32) +# define ASMAtomicUoAndU32_EndProc RT_MANGLER(ASMAtomicUoAndU32_EndProc) +# define ASMAtomicUoAndU64 RT_MANGLER(ASMAtomicUoAndU64) +# define ASMAtomicUoAndU64_EndProc RT_MANGLER(ASMAtomicUoAndU64_EndProc) +# define ASMAtomicUoDecU32 RT_MANGLER(ASMAtomicUoDecU32) +# define ASMAtomicUoDecU32_EndProc RT_MANGLER(ASMAtomicUoDecU32_EndProc) +# define ASMAtomicUoIncU32 RT_MANGLER(ASMAtomicUoIncU32) +# define ASMAtomicUoIncU32_EndProc RT_MANGLER(ASMAtomicUoIncU32_EndProc) +# define ASMAtomicUoOrU32 RT_MANGLER(ASMAtomicUoOrU32) +# define ASMAtomicUoOrU32_EndProc RT_MANGLER(ASMAtomicUoOrU32_EndProc) +# define ASMAtomicUoOrU64 RT_MANGLER(ASMAtomicUoOrU64) +# define ASMAtomicUoOrU64_EndProc RT_MANGLER(ASMAtomicUoOrU64_EndProc) +# define ASMAtomicUoReadU64 RT_MANGLER(ASMAtomicUoReadU64) +# define ASMAtomicUoReadU64_EndProc RT_MANGLER(ASMAtomicUoReadU64_EndProc) +# define ASMAtomicUoXorU32 RT_MANGLER(ASMAtomicUoXorU32) +# define ASMAtomicXchgU16 RT_MANGLER(ASMAtomicXchgU16) +# define ASMAtomicXchgU16_EndProc RT_MANGLER(ASMAtomicXchgU16_EndProc) +# define ASMAtomicXchgU32 RT_MANGLER(ASMAtomicXchgU32) +# define ASMAtomicXchgU32_EndProc RT_MANGLER(ASMAtomicXchgU32_EndProc) +# define ASMAtomicXchgU64 RT_MANGLER(ASMAtomicXchgU64) +# define ASMAtomicXchgU64_EndProc RT_MANGLER(ASMAtomicXchgU64_EndProc) +# define ASMAtomicXchgU8 RT_MANGLER(ASMAtomicXchgU8) +# define ASMAtomicXchgU8_EndProc RT_MANGLER(ASMAtomicXchgU8_EndProc) +# define ASMBitClear RT_MANGLER(ASMBitClear) +# define ASMBitClear_EndProc RT_MANGLER(ASMBitClear_EndProc) +# define ASMBitFirstClear RT_MANGLER(ASMBitFirstClear) +# define ASMBitFirstClear_EndProc RT_MANGLER(ASMBitFirstClear_EndProc) +# define ASMBitFirstSet RT_MANGLER(ASMBitFirstSet) +# define ASMBitFirstSet_EndProc RT_MANGLER(ASMBitFirstSet_EndProc) +# define ASMBitFirstSetU16 RT_MANGLER(ASMBitFirstSetU16) +# define ASMBitFirstSetU16_EndProc RT_MANGLER(ASMBitFirstSetU16_EndProc) +# define ASMBitFirstSetU32 RT_MANGLER(ASMBitFirstSetU32) +# define ASMBitFirstSetU32_EndProc RT_MANGLER(ASMBitFirstSetU32_EndProc) +# define ASMBitFirstSetU64 RT_MANGLER(ASMBitFirstSetU64) +# define ASMBitFirstSetU64_EndProc RT_MANGLER(ASMBitFirstSetU64_EndProc) +# define ASMBitLastSetU16 RT_MANGLER(ASMBitLastSetU16) +# define ASMBitLastSetU16_EndProc RT_MANGLER(ASMBitLastSetU16_EndProc) +# define ASMBitLastSetU32 RT_MANGLER(ASMBitLastSetU32) +# define ASMBitLastSetU32_EndProc RT_MANGLER(ASMBitLastSetU32_EndProc) +# define ASMBitLastSetU64 RT_MANGLER(ASMBitLastSetU64) +# define ASMBitLastSetU64_EndProc RT_MANGLER(ASMBitLastSetU64_EndProc) +# define ASMBitNextClear RT_MANGLER(ASMBitNextClear) +# define ASMBitNextClear_EndProc RT_MANGLER(ASMBitNextClear_EndProc) +# define ASMBitNextSet RT_MANGLER(ASMBitNextSet) +# define ASMBitNextSet_EndProc RT_MANGLER(ASMBitNextSet_EndProc) +# define ASMBitSet RT_MANGLER(ASMBitSet) +# define ASMBitSet_EndProc RT_MANGLER(ASMBitSet_EndProc) +# define ASMBitTest RT_MANGLER(ASMBitTest) +# define ASMBitTest_EndProc RT_MANGLER(ASMBitTest_EndProc) +# define ASMBitTestAndClear RT_MANGLER(ASMBitTestAndClear) +# define ASMBitTestAndClear_EndProc RT_MANGLER(ASMBitTestAndClear_EndProc) +# define ASMBitTestAndSet RT_MANGLER(ASMBitTestAndSet) +# define ASMBitTestAndSet_EndProc RT_MANGLER(ASMBitTestAndSet_EndProc) +# define ASMBitTestAndToggle RT_MANGLER(ASMBitTestAndToggle) +# define ASMBitTestAndToggle_EndProc RT_MANGLER(ASMBitTestAndToggle_EndProc) +# define ASMBitToggle RT_MANGLER(ASMBitToggle) +# define ASMBitToggle_EndProc RT_MANGLER(ASMBitToggle_EndProc) +# define ASMByteSwapU16 RT_MANGLER(ASMByteSwapU16) +# define ASMByteSwapU16_EndProc RT_MANGLER(ASMByteSwapU16_EndProc) +# define ASMByteSwapU32 RT_MANGLER(ASMByteSwapU32) +# define ASMByteSwapU32_EndProc RT_MANGLER(ASMByteSwapU32_EndProc) +# define ASMChangeFlags RT_MANGLER(ASMChangeFlags) +# define ASMChangeFlags_EndProc RT_MANGLER(ASMChangeFlags_EndProc) +# define ASMClearFlags RT_MANGLER(ASMClearFlags) +# define ASMClearFlags_EndProc RT_MANGLER(ASMClearFlags_EndProc) +# define ASMCpuId RT_MANGLER(ASMCpuId) +# define ASMCpuId_EAX RT_MANGLER(ASMCpuId_EAX) +# define ASMCpuId_EAX_EndProc RT_MANGLER(ASMCpuId_EAX_EndProc) +# define ASMCpuId_EBX RT_MANGLER(ASMCpuId_EBX) +# define ASMCpuId_EBX_EndProc RT_MANGLER(ASMCpuId_EBX_EndProc) +# define ASMCpuId_ECX RT_MANGLER(ASMCpuId_ECX) +# define ASMCpuId_ECX_EDX RT_MANGLER(ASMCpuId_ECX_EDX) +# define ASMCpuId_ECX_EDX_EndProc RT_MANGLER(ASMCpuId_ECX_EDX_EndProc) +# define ASMCpuId_ECX_EndProc RT_MANGLER(ASMCpuId_ECX_EndProc) +# define ASMCpuId_EDX RT_MANGLER(ASMCpuId_EDX) +# define ASMCpuId_EDX_EndProc RT_MANGLER(ASMCpuId_EDX_EndProc) +# define ASMCpuId_EndProc RT_MANGLER(ASMCpuId_EndProc) +# define ASMCpuId_Idx_ECX RT_MANGLER(ASMCpuId_Idx_ECX) +# define ASMCpuId_Idx_ECX_EndProc RT_MANGLER(ASMCpuId_Idx_ECX_EndProc) +# define ASMCpuIdExSlow RT_MANGLER(ASMCpuIdExSlow) +# define ASMCpuIdExSlow_EndProc RT_MANGLER(ASMCpuIdExSlow_EndProc) +# define ASMGetAndClearDR6 RT_MANGLER(ASMGetAndClearDR6) +# define ASMGetAndClearDR6_EndProc RT_MANGLER(ASMGetAndClearDR6_EndProc) +# define ASMGetApicId RT_MANGLER(ASMGetApicId) +# define ASMGetApicId_EndProc RT_MANGLER(ASMGetApicId_EndProc) +# define ASMGetCR0 RT_MANGLER(ASMGetCR0) +# define ASMGetCR0_EndProc RT_MANGLER(ASMGetCR0_EndProc) +# define ASMGetCR2 RT_MANGLER(ASMGetCR2) +# define ASMGetCR2_EndProc RT_MANGLER(ASMGetCR2_EndProc) +# define ASMGetCR3 RT_MANGLER(ASMGetCR3) +# define ASMGetCR3_EndProc RT_MANGLER(ASMGetCR3_EndProc) +# define ASMGetCR4 RT_MANGLER(ASMGetCR4) +# define ASMGetCR4_EndProc RT_MANGLER(ASMGetCR4_EndProc) +# define ASMGetCR8 RT_MANGLER(ASMGetCR8) +# define ASMGetCR8_EndProc RT_MANGLER(ASMGetCR8_EndProc) +# define ASMGetCS RT_MANGLER(ASMGetCS) +# define ASMGetCS_EndProc RT_MANGLER(ASMGetCS_EndProc) +# define ASMGetDR0 RT_MANGLER(ASMGetDR0) +# define ASMGetDR0_EndProc RT_MANGLER(ASMGetDR0_EndProc) +# define ASMGetDR1 RT_MANGLER(ASMGetDR1) +# define ASMGetDR1_EndProc RT_MANGLER(ASMGetDR1_EndProc) +# define ASMGetDR2 RT_MANGLER(ASMGetDR2) +# define ASMGetDR2_EndProc RT_MANGLER(ASMGetDR2_EndProc) +# define ASMGetDR3 RT_MANGLER(ASMGetDR3) +# define ASMGetDR3_EndProc RT_MANGLER(ASMGetDR3_EndProc) +# define ASMGetDR6 RT_MANGLER(ASMGetDR6) +# define ASMGetDR6_EndProc RT_MANGLER(ASMGetDR6_EndProc) +# define ASMGetDR7 RT_MANGLER(ASMGetDR7) +# define ASMGetDR7_EndProc RT_MANGLER(ASMGetDR7_EndProc) +# define ASMGetDS RT_MANGLER(ASMGetDS) +# define ASMGetDS_EndProc RT_MANGLER(ASMGetDS_EndProc) +# define ASMGetES RT_MANGLER(ASMGetES) +# define ASMGetES_EndProc RT_MANGLER(ASMGetES_EndProc) +# define ASMGetFlags RT_MANGLER(ASMGetFlags) +# define ASMGetFlags_EndProc RT_MANGLER(ASMGetFlags_EndProc) +# define ASMGetFS RT_MANGLER(ASMGetFS) +# define ASMGetFS_EndProc RT_MANGLER(ASMGetFS_EndProc) +# define ASMGetGDTR RT_MANGLER(ASMGetGDTR) +# define ASMGetGDTR_EndProc RT_MANGLER(ASMGetGDTR_EndProc) +# define ASMGetGS RT_MANGLER(ASMGetGS) +# define ASMGetGS_EndProc RT_MANGLER(ASMGetGS_EndProc) +# define ASMGetIDTR RT_MANGLER(ASMGetIDTR) +# define ASMGetIDTR_EndProc RT_MANGLER(ASMGetIDTR_EndProc) +# define ASMGetIdtrLimit RT_MANGLER(ASMGetIdtrLimit) +# define ASMGetIdtrLimit_EndProc RT_MANGLER(ASMGetIdtrLimit_EndProc) +# define ASMGetLDTR RT_MANGLER(ASMGetLDTR) +# define ASMGetLDTR_EndProc RT_MANGLER(ASMGetLDTR_EndProc) +# define ASMGetSegAttr RT_MANGLER(ASMGetSegAttr) +# define ASMGetSegAttr_EndProc RT_MANGLER(ASMGetSegAttr_EndProc) +# define ASMGetSS RT_MANGLER(ASMGetSS) +# define ASMGetSS_EndProc RT_MANGLER(ASMGetSS_EndProc) +# define ASMGetTR RT_MANGLER(ASMGetTR) +# define ASMGetTR_EndProc RT_MANGLER(ASMGetTR_EndProc) +# define ASMGetXcr0 RT_MANGLER(ASMGetXcr0) +# define ASMGetXcr0_EndProc RT_MANGLER(ASMGetXcr0_EndProc) +# define ASMHalt RT_MANGLER(ASMHalt) +# define ASMHalt_EndProc RT_MANGLER(ASMHalt_EndProc) +# define ASMInStrU16 RT_MANGLER(ASMInStrU16) +# define ASMInStrU16_EndProc RT_MANGLER(ASMInStrU16_EndProc) +# define ASMInStrU32 RT_MANGLER(ASMInStrU32) +# define ASMInStrU32_EndProc RT_MANGLER(ASMInStrU32_EndProc) +# define ASMInStrU8 RT_MANGLER(ASMInStrU8) +# define ASMInStrU8_EndProc RT_MANGLER(ASMInStrU8_EndProc) +# define ASMIntDisable RT_MANGLER(ASMIntDisable) +# define ASMIntDisable_EndProc RT_MANGLER(ASMIntDisable_EndProc) +# define ASMIntDisableFlags RT_MANGLER(ASMIntDisableFlags) +# define ASMIntDisableFlags_EndProc RT_MANGLER(ASMIntDisableFlags_EndProc) +# define ASMIntEnable RT_MANGLER(ASMIntEnable) +# define ASMIntEnable_EndProc RT_MANGLER(ASMIntEnable_EndProc) +# define ASMInU16 RT_MANGLER(ASMInU16) +# define ASMInU16_EndProc RT_MANGLER(ASMInU16_EndProc) +# define ASMInU32 RT_MANGLER(ASMInU32) +# define ASMInU32_EndProc RT_MANGLER(ASMInU32_EndProc) +# define ASMInU8 RT_MANGLER(ASMInU8) +# define ASMInU8_EndProc RT_MANGLER(ASMInU8_EndProc) +# define ASMInvalidateInternalCaches RT_MANGLER(ASMInvalidateInternalCaches) +# define ASMInvalidateInternalCaches_EndProc RT_MANGLER(ASMInvalidateInternalCaches_EndProc) +# define ASMInvalidatePage RT_MANGLER(ASMInvalidatePage) +# define ASMInvalidatePage_EndProc RT_MANGLER(ASMInvalidatePage_EndProc) +# define ASMMemFill32 RT_MANGLER(ASMMemFill32) +# define ASMMemFill32_EndProc RT_MANGLER(ASMMemFill32_EndProc) +# define ASMMemFirstNonZero RT_MANGLER(ASMMemFirstNonZero) +# define ASMMemFirstNonZero_EndProc RT_MANGLER(ASMMemFirstNonZero_EndProc) +# define ASMMemFirstMismatchingU8 RT_MANGLER(ASMMemFirstMismatchingU8) +# define ASMMemFirstMismatchingU8_EndProc RT_MANGLER(ASMMemFirstMismatchingU8_EndProc) +# define ASMMemFirstMismatchingU32 RT_MANGLER(ASMMemFirstMismatchingU32) +# define ASMMemFirstMismatchingU32_EndProc RT_MANGLER(ASMMemFirstMismatchingU32_EndProc) +# define ASMMemIsZero RT_MANGLER(ASMMemIsZero) +# define ASMMemIsZero_EndProc RT_MANGLER(ASMMemIsZero_EndProc) +# define ASMMemIsAllU8 RT_MANGLER(ASMMemIsAllU8) +# define ASMMemIsAllU8_EndProc RT_MANGLER(ASMMemIsAllU8_EndProc) +# define ASMMemZero32 RT_MANGLER(ASMMemZero32) +# define ASMMemZero32_EndProc RT_MANGLER(ASMMemZero32_EndProc) +# define ASMMemZeroPage RT_MANGLER(ASMMemZeroPage) +# define ASMMemZeroPage_EndProc RT_MANGLER(ASMMemZeroPage_EndProc) +# define ASMMultU64ByU32DivByU32 RT_MANGLER(ASMMultU64ByU32DivByU32) +# define ASMMultU64ByU32DivByU32_EndProc RT_MANGLER(ASMMultU64ByU32DivByU32_EndProc) +# define ASMNopPause RT_MANGLER(ASMNopPause) +# define ASMNopPause_EndProc RT_MANGLER(ASMNopPause_EndProc) +# define ASMOutStrU16 RT_MANGLER(ASMOutStrU16) +# define ASMOutStrU16_EndProc RT_MANGLER(ASMOutStrU16_EndProc) +# define ASMOutStrU32 RT_MANGLER(ASMOutStrU32) +# define ASMOutStrU32_EndProc RT_MANGLER(ASMOutStrU32_EndProc) +# define ASMOutStrU8 RT_MANGLER(ASMOutStrU8) +# define ASMOutStrU8_EndProc RT_MANGLER(ASMOutStrU8_EndProc) +# define ASMOutU16 RT_MANGLER(ASMOutU16) +# define ASMOutU16_EndProc RT_MANGLER(ASMOutU16_EndProc) +# define ASMOutU32 RT_MANGLER(ASMOutU32) +# define ASMOutU32_EndProc RT_MANGLER(ASMOutU32_EndProc) +# define ASMOutU8 RT_MANGLER(ASMOutU8) +# define ASMOutU8_EndProc RT_MANGLER(ASMOutU8_EndProc) +# define ASMProbeReadByte RT_MANGLER(ASMProbeReadByte) +# define ASMProbeReadByte_EndProc RT_MANGLER(ASMProbeReadByte_EndProc) +# define ASMRdMsr RT_MANGLER(ASMRdMsr) +# define ASMRdMsr_EndProc RT_MANGLER(ASMRdMsr_EndProc) +# define ASMRdMsr_High RT_MANGLER(ASMRdMsr_High) +# define ASMRdMsr_High_EndProc RT_MANGLER(ASMRdMsr_High_EndProc) +# define ASMRdMsr_Low RT_MANGLER(ASMRdMsr_Low) +# define ASMRdMsr_Low_EndProc RT_MANGLER(ASMRdMsr_Low_EndProc) +# define ASMRdMsrEx RT_MANGLER(ASMRdMsrEx) +# define ASMRdMsrEx_EndProc RT_MANGLER(ASMRdMsrEx_EndProc) +# define ASMReadTSC RT_MANGLER(ASMReadTSC) +# define ASMReadTSC_EndProc RT_MANGLER(ASMReadTSC_EndProc) +# define ASMReadTscWithAux RT_MANGLER(ASMReadTscWithAux) +# define ASMReadTscWithAux_EndProc RT_MANGLER(ASMReadTscWithAux_EndProc) +# define ASMReloadCR3 RT_MANGLER(ASMReloadCR3) +# define ASMReloadCR3_EndProc RT_MANGLER(ASMReloadCR3_EndProc) +# define ASMRotateLeftU32 RT_MANGLER(ASMRotateLeftU32) +# define ASMRotateLeftU32_EndProc RT_MANGLER(ASMRotateLeftU32_EndProc) +# define ASMRotateRightU32 RT_MANGLER(ASMRotateRightU32) +# define ASMRotateRightU32_EndProc RT_MANGLER(ASMRotateRightU32_EndProc) +# define ASMSerializeInstructionCpuId RT_MANGLER(ASMSerializeInstructionCpuId) +# define ASMSerializeInstructionCpuId_EndProc RT_MANGLER(ASMSerializeInstructionCpuId_EndProc) +# define ASMSerializeInstructionIRet RT_MANGLER(ASMSerializeInstructionIRet) +# define ASMSerializeInstructionIRet_EndProc RT_MANGLER(ASMSerializeInstructionIRet_EndProc) +# define ASMSerializeInstructionRdTscp RT_MANGLER(ASMSerializeInstructionRdTscp) +# define ASMSerializeInstructionRdTscp_EndProc RT_MANGLER(ASMSerializeInstructionRdTscp_EndProc) +# define ASMSetCR0 RT_MANGLER(ASMSetCR0) +# define ASMSetCR0_EndProc RT_MANGLER(ASMSetCR0_EndProc) +# define ASMSetCR2 RT_MANGLER(ASMSetCR2) +# define ASMSetCR2_EndProc RT_MANGLER(ASMSetCR2_EndProc) +# define ASMSetCR3 RT_MANGLER(ASMSetCR3) +# define ASMSetCR3_EndProc RT_MANGLER(ASMSetCR3_EndProc) +# define ASMSetCR4 RT_MANGLER(ASMSetCR4) +# define ASMSetCR4_EndProc RT_MANGLER(ASMSetCR4_EndProc) +# define ASMSetDR0 RT_MANGLER(ASMSetDR0) +# define ASMSetDR0_EndProc RT_MANGLER(ASMSetDR0_EndProc) +# define ASMSetDR1 RT_MANGLER(ASMSetDR1) +# define ASMSetDR1_EndProc RT_MANGLER(ASMSetDR1_EndProc) +# define ASMSetDR2 RT_MANGLER(ASMSetDR2) +# define ASMSetDR2_EndProc RT_MANGLER(ASMSetDR2_EndProc) +# define ASMSetDR3 RT_MANGLER(ASMSetDR3) +# define ASMSetDR3_EndProc RT_MANGLER(ASMSetDR3_EndProc) +# define ASMSetDR6 RT_MANGLER(ASMSetDR6) +# define ASMSetDR6_EndProc RT_MANGLER(ASMSetDR6_EndProc) +# define ASMSetDR7 RT_MANGLER(ASMSetDR7) +# define ASMSetDR7_EndProc RT_MANGLER(ASMSetDR7_EndProc) +# define ASMSetFlags RT_MANGLER(ASMSetFlags) +# define ASMSetFlags_EndProc RT_MANGLER(ASMSetFlags_EndProc) +# define ASMSetGDTR RT_MANGLER(ASMSetGDTR) +# define ASMSetGDTR_EndProc RT_MANGLER(ASMSetGDTR_EndProc) +# define ASMSetIDTR RT_MANGLER(ASMSetIDTR) +# define ASMSetIDTR_EndProc RT_MANGLER(ASMSetIDTR_EndProc) +# define ASMSetXcr0 RT_MANGLER(ASMSetXcr0) +# define ASMSetXcr0_EndProc RT_MANGLER(ASMSetXcr0_EndProc) +# define ASMWriteBackAndInvalidateCaches RT_MANGLER(ASMWriteBackAndInvalidateCaches) +# define ASMWriteBackAndInvalidateCaches_EndProc RT_MANGLER(ASMWriteBackAndInvalidateCaches_EndProc) +# define ASMWrMsr RT_MANGLER(ASMWrMsr) +# define ASMWrMsr_EndProc RT_MANGLER(ASMWrMsr_EndProc) +# define ASMWrMsrEx RT_MANGLER(ASMWrMsrEx) +# define ASMWrMsrEx_EndProc RT_MANGLER(ASMWrMsrEx_EndProc) +# define ASMXRstor RT_MANGLER(ASMXRstor) +# define ASMXRstor_EndProc RT_MANGLER(ASMXRstor_EndProc) +# define ASMXSave RT_MANGLER(ASMXSave) +# define ASMXSave_EndProc RT_MANGLER(ASMXSave_EndProc) +# define ASMFxRstor RT_MANGLER(ASMFxRstor) +# define ASMFxRstor_EndProc RT_MANGLER(ASMFxRstor_EndProc) +# define ASMFxSave RT_MANGLER(ASMFxSave) +# define ASMFxSave_EndProc RT_MANGLER(ASMFxSave_EndProc) + +# define RTAssertAreQuiet RT_MANGLER(RTAssertAreQuiet) +# define RTAssertMayPanic RT_MANGLER(RTAssertMayPanic) +# define RTAssertMsg1 RT_MANGLER(RTAssertMsg1) +# define RTAssertMsg1Weak RT_MANGLER(RTAssertMsg1Weak) +# define RTAssertMsg2 RT_MANGLER(RTAssertMsg2) +# define RTAssertMsg2Add RT_MANGLER(RTAssertMsg2Add) +# define RTAssertMsg2AddV RT_MANGLER(RTAssertMsg2AddV) +# define RTAssertMsg2AddWeak RT_MANGLER(RTAssertMsg2AddWeak) +# define RTAssertMsg2AddWeakV RT_MANGLER(RTAssertMsg2AddWeakV) +# define RTAssertMsg2V RT_MANGLER(RTAssertMsg2V) +# define RTAssertMsg2Weak RT_MANGLER(RTAssertMsg2Weak) +# define RTAssertMsg2WeakV RT_MANGLER(RTAssertMsg2WeakV) +# define RTAssertSetMayPanic RT_MANGLER(RTAssertSetMayPanic) +# define RTAssertSetQuiet RT_MANGLER(RTAssertSetQuiet) +# define RTAssertShouldPanic RT_MANGLER(RTAssertShouldPanic) +# define RTAvlGCPhysDestroy RT_MANGLER(RTAvlGCPhysDestroy) +# define RTAvlGCPhysDoWithAll RT_MANGLER(RTAvlGCPhysDoWithAll) +# define RTAvlGCPhysGet RT_MANGLER(RTAvlGCPhysGet) +# define RTAvlGCPhysGetBestFit RT_MANGLER(RTAvlGCPhysGetBestFit) +# define RTAvlGCPhysInsert RT_MANGLER(RTAvlGCPhysInsert) +# define RTAvlGCPhysRemove RT_MANGLER(RTAvlGCPhysRemove) +# define RTAvlGCPhysRemoveBestFit RT_MANGLER(RTAvlGCPhysRemoveBestFit) +# define RTAvlGCPtrDestroy RT_MANGLER(RTAvlGCPtrDestroy) +# define RTAvlGCPtrDoWithAll RT_MANGLER(RTAvlGCPtrDoWithAll) +# define RTAvlGCPtrGet RT_MANGLER(RTAvlGCPtrGet) +# define RTAvlGCPtrGetBestFit RT_MANGLER(RTAvlGCPtrGetBestFit) +# define RTAvlGCPtrInsert RT_MANGLER(RTAvlGCPtrInsert) +# define RTAvlGCPtrRemove RT_MANGLER(RTAvlGCPtrRemove) +# define RTAvlGCPtrRemoveBestFit RT_MANGLER(RTAvlGCPtrRemoveBestFit) +# define RTAvlHCPhysDestroy RT_MANGLER(RTAvlHCPhysDestroy) +# define RTAvlHCPhysDoWithAll RT_MANGLER(RTAvlHCPhysDoWithAll) +# define RTAvlHCPhysGet RT_MANGLER(RTAvlHCPhysGet) +# define RTAvlHCPhysGetBestFit RT_MANGLER(RTAvlHCPhysGetBestFit) +# define RTAvlHCPhysInsert RT_MANGLER(RTAvlHCPhysInsert) +# define RTAvlHCPhysRemove RT_MANGLER(RTAvlHCPhysRemove) +# define RTAvlHCPhysRemoveBestFit RT_MANGLER(RTAvlHCPhysRemoveBestFit) +# define RTAvllU32Destroy RT_MANGLER(RTAvllU32Destroy) +# define RTAvllU32DoWithAll RT_MANGLER(RTAvllU32DoWithAll) +# define RTAvllU32Get RT_MANGLER(RTAvllU32Get) +# define RTAvllU32GetBestFit RT_MANGLER(RTAvllU32GetBestFit) +# define RTAvllU32Insert RT_MANGLER(RTAvllU32Insert) +# define RTAvllU32Remove RT_MANGLER(RTAvllU32Remove) +# define RTAvllU32RemoveBestFit RT_MANGLER(RTAvllU32RemoveBestFit) +# define RTAvllU32RemoveNode RT_MANGLER(RTAvllU32RemoveNode) +# define RTAvloGCPhysDestroy RT_MANGLER(RTAvloGCPhysDestroy) +# define RTAvloGCPhysDoWithAll RT_MANGLER(RTAvloGCPhysDoWithAll) +# define RTAvloGCPhysGet RT_MANGLER(RTAvloGCPhysGet) +# define RTAvloGCPhysGetBestFit RT_MANGLER(RTAvloGCPhysGetBestFit) +# define RTAvloGCPhysInsert RT_MANGLER(RTAvloGCPhysInsert) +# define RTAvloGCPhysRemove RT_MANGLER(RTAvloGCPhysRemove) +# define RTAvloGCPhysRemoveBestFit RT_MANGLER(RTAvloGCPhysRemoveBestFit) +# define RTAvloGCPtrDestroy RT_MANGLER(RTAvloGCPtrDestroy) +# define RTAvloGCPtrDoWithAll RT_MANGLER(RTAvloGCPtrDoWithAll) +# define RTAvloGCPtrGet RT_MANGLER(RTAvloGCPtrGet) +# define RTAvloGCPtrGetBestFit RT_MANGLER(RTAvloGCPtrGetBestFit) +# define RTAvloGCPtrInsert RT_MANGLER(RTAvloGCPtrInsert) +# define RTAvloGCPtrRemove RT_MANGLER(RTAvloGCPtrRemove) +# define RTAvloGCPtrRemoveBestFit RT_MANGLER(RTAvloGCPtrRemoveBestFit) +# define RTAvloHCPhysDestroy RT_MANGLER(RTAvloHCPhysDestroy) +# define RTAvloHCPhysDoWithAll RT_MANGLER(RTAvloHCPhysDoWithAll) +# define RTAvloHCPhysGet RT_MANGLER(RTAvloHCPhysGet) +# define RTAvloHCPhysGetBestFit RT_MANGLER(RTAvloHCPhysGetBestFit) +# define RTAvloHCPhysInsert RT_MANGLER(RTAvloHCPhysInsert) +# define RTAvloHCPhysRemove RT_MANGLER(RTAvloHCPhysRemove) +# define RTAvloHCPhysRemoveBestFit RT_MANGLER(RTAvloHCPhysRemoveBestFit) +# define RTAvloIOPortDestroy RT_MANGLER(RTAvloIOPortDestroy) +# define RTAvloIOPortDoWithAll RT_MANGLER(RTAvloIOPortDoWithAll) +# define RTAvloIOPortGet RT_MANGLER(RTAvloIOPortGet) +# define RTAvloIOPortGetBestFit RT_MANGLER(RTAvloIOPortGetBestFit) +# define RTAvloIOPortInsert RT_MANGLER(RTAvloIOPortInsert) +# define RTAvloIOPortRemove RT_MANGLER(RTAvloIOPortRemove) +# define RTAvloIOPortRemoveBestFit RT_MANGLER(RTAvloIOPortRemoveBestFit) +# define RTAvloU32Destroy RT_MANGLER(RTAvloU32Destroy) +# define RTAvloU32DoWithAll RT_MANGLER(RTAvloU32DoWithAll) +# define RTAvloU32Get RT_MANGLER(RTAvloU32Get) +# define RTAvloU32GetBestFit RT_MANGLER(RTAvloU32GetBestFit) +# define RTAvloU32Insert RT_MANGLER(RTAvloU32Insert) +# define RTAvloU32Remove RT_MANGLER(RTAvloU32Remove) +# define RTAvloU32RemoveBestFit RT_MANGLER(RTAvloU32RemoveBestFit) +# define RTAvlPVDestroy RT_MANGLER(RTAvlPVDestroy) +# define RTAvlPVDoWithAll RT_MANGLER(RTAvlPVDoWithAll) +# define RTAvlPVGet RT_MANGLER(RTAvlPVGet) +# define RTAvlPVGetBestFit RT_MANGLER(RTAvlPVGetBestFit) +# define RTAvlPVInsert RT_MANGLER(RTAvlPVInsert) +# define RTAvlPVRemove RT_MANGLER(RTAvlPVRemove) +# define RTAvlPVRemoveBestFit RT_MANGLER(RTAvlPVRemoveBestFit) +# define RTAvlrFileOffsetDestroy RT_MANGLER(RTAvlrFileOffsetDestroy) +# define RTAvlrFileOffsetDoWithAll RT_MANGLER(RTAvlrFileOffsetDoWithAll) +# define RTAvlrFileOffsetGet RT_MANGLER(RTAvlrFileOffsetGet) +# define RTAvlrFileOffsetGetBestFit RT_MANGLER(RTAvlrFileOffsetGetBestFit) +# define RTAvlrFileOffsetGetLeft RT_MANGLER(RTAvlrFileOffsetGetLeft) +# define RTAvlrFileOffsetGetRight RT_MANGLER(RTAvlrFileOffsetGetRight) +# define RTAvlrFileOffsetGetRoot RT_MANGLER(RTAvlrFileOffsetGetRoot) +# define RTAvlrFileOffsetInsert RT_MANGLER(RTAvlrFileOffsetInsert) +# define RTAvlrFileOffsetRangeGet RT_MANGLER(RTAvlrFileOffsetRangeGet) +# define RTAvlrFileOffsetRangeRemove RT_MANGLER(RTAvlrFileOffsetRangeRemove) +# define RTAvlrFileOffsetRemove RT_MANGLER(RTAvlrFileOffsetRemove) +# define RTAvlrGCPtrDestroy RT_MANGLER(RTAvlrGCPtrDestroy) +# define RTAvlrGCPtrDoWithAll RT_MANGLER(RTAvlrGCPtrDoWithAll) +# define RTAvlrGCPtrGet RT_MANGLER(RTAvlrGCPtrGet) +# define RTAvlrGCPtrGetBestFit RT_MANGLER(RTAvlrGCPtrGetBestFit) +# define RTAvlrGCPtrGetLeft RT_MANGLER(RTAvlrGCPtrGetLeft) +# define RTAvlrGCPtrGetRight RT_MANGLER(RTAvlrGCPtrGetRight) +# define RTAvlrGCPtrGetRoot RT_MANGLER(RTAvlrGCPtrGetRoot) +# define RTAvlrGCPtrInsert RT_MANGLER(RTAvlrGCPtrInsert) +# define RTAvlrGCPtrRangeGet RT_MANGLER(RTAvlrGCPtrRangeGet) +# define RTAvlrGCPtrRangeRemove RT_MANGLER(RTAvlrGCPtrRangeRemove) +# define RTAvlrGCPtrRemove RT_MANGLER(RTAvlrGCPtrRemove) +# define RTAvlroGCPhysDestroy RT_MANGLER(RTAvlroGCPhysDestroy) +# define RTAvlroGCPhysDoWithAll RT_MANGLER(RTAvlroGCPhysDoWithAll) +# define RTAvlroGCPhysGet RT_MANGLER(RTAvlroGCPhysGet) +# define RTAvlroGCPhysGetBestFit RT_MANGLER(RTAvlroGCPhysGetBestFit) +# define RTAvlroGCPhysGetLeft RT_MANGLER(RTAvlroGCPhysGetLeft) +# define RTAvlroGCPhysGetRight RT_MANGLER(RTAvlroGCPhysGetRight) +# define RTAvlroGCPhysGetRoot RT_MANGLER(RTAvlroGCPhysGetRoot) +# define RTAvlroGCPhysInsert RT_MANGLER(RTAvlroGCPhysInsert) +# define RTAvlroGCPhysRangeGet RT_MANGLER(RTAvlroGCPhysRangeGet) +# define RTAvlroGCPhysRangeRemove RT_MANGLER(RTAvlroGCPhysRangeRemove) +# define RTAvlroGCPhysRemove RT_MANGLER(RTAvlroGCPhysRemove) +# define RTAvlroGCPtrDestroy RT_MANGLER(RTAvlroGCPtrDestroy) +# define RTAvlroGCPtrDoWithAll RT_MANGLER(RTAvlroGCPtrDoWithAll) +# define RTAvlroGCPtrGet RT_MANGLER(RTAvlroGCPtrGet) +# define RTAvlroGCPtrGetBestFit RT_MANGLER(RTAvlroGCPtrGetBestFit) +# define RTAvlroGCPtrGetLeft RT_MANGLER(RTAvlroGCPtrGetLeft) +# define RTAvlroGCPtrGetRight RT_MANGLER(RTAvlroGCPtrGetRight) +# define RTAvlroGCPtrGetRoot RT_MANGLER(RTAvlroGCPtrGetRoot) +# define RTAvlroGCPtrInsert RT_MANGLER(RTAvlroGCPtrInsert) +# define RTAvlroGCPtrRangeGet RT_MANGLER(RTAvlroGCPtrRangeGet) +# define RTAvlroGCPtrRangeRemove RT_MANGLER(RTAvlroGCPtrRangeRemove) +# define RTAvlroGCPtrRemove RT_MANGLER(RTAvlroGCPtrRemove) +# define RTAvlroIOPortDestroy RT_MANGLER(RTAvlroIOPortDestroy) +# define RTAvlroIOPortDoWithAll RT_MANGLER(RTAvlroIOPortDoWithAll) +# define RTAvlroIOPortGet RT_MANGLER(RTAvlroIOPortGet) +# define RTAvlroIOPortInsert RT_MANGLER(RTAvlroIOPortInsert) +# define RTAvlroIOPortRangeGet RT_MANGLER(RTAvlroIOPortRangeGet) +# define RTAvlroIOPortRangeRemove RT_MANGLER(RTAvlroIOPortRangeRemove) +# define RTAvlroIOPortRemove RT_MANGLER(RTAvlroIOPortRemove) +# define RTAvlrooGCPtrDestroy RT_MANGLER(RTAvlrooGCPtrDestroy) +# define RTAvlrooGCPtrDoWithAll RT_MANGLER(RTAvlrooGCPtrDoWithAll) +# define RTAvlrooGCPtrGet RT_MANGLER(RTAvlrooGCPtrGet) +# define RTAvlrooGCPtrGetBestFit RT_MANGLER(RTAvlrooGCPtrGetBestFit) +# define RTAvlrooGCPtrGetLeft RT_MANGLER(RTAvlrooGCPtrGetLeft) +# define RTAvlrooGCPtrGetNextEqual RT_MANGLER(RTAvlrooGCPtrGetNextEqual) +# define RTAvlrooGCPtrGetRight RT_MANGLER(RTAvlrooGCPtrGetRight) +# define RTAvlrooGCPtrGetRoot RT_MANGLER(RTAvlrooGCPtrGetRoot) +# define RTAvlrooGCPtrInsert RT_MANGLER(RTAvlrooGCPtrInsert) +# define RTAvlrooGCPtrRangeGet RT_MANGLER(RTAvlrooGCPtrRangeGet) +# define RTAvlrooGCPtrRangeRemove RT_MANGLER(RTAvlrooGCPtrRangeRemove) +# define RTAvlrooGCPtrRemove RT_MANGLER(RTAvlrooGCPtrRemove) +# define RTAvlrPVDestroy RT_MANGLER(RTAvlrPVDestroy) +# define RTAvlrPVDoWithAll RT_MANGLER(RTAvlrPVDoWithAll) +# define RTAvlrPVGet RT_MANGLER(RTAvlrPVGet) +# define RTAvlrPVGetBestFit RT_MANGLER(RTAvlrPVGetBestFit) +# define RTAvlrPVInsert RT_MANGLER(RTAvlrPVInsert) +# define RTAvlrPVRangeGet RT_MANGLER(RTAvlrPVRangeGet) +# define RTAvlrPVRangeRemove RT_MANGLER(RTAvlrPVRangeRemove) +# define RTAvlrPVRemove RT_MANGLER(RTAvlrPVRemove) +# define RTAvlrPVRemoveBestFit RT_MANGLER(RTAvlrPVRemoveBestFit) +# define RTAvlrU64Destroy RT_MANGLER(RTAvlrU64Destroy) +# define RTAvlrU64DoWithAll RT_MANGLER(RTAvlrU64DoWithAll) +# define RTAvlrU64Get RT_MANGLER(RTAvlrU64Get) +# define RTAvlrU64GetBestFit RT_MANGLER(RTAvlrU64GetBestFit) +# define RTAvlrU64Insert RT_MANGLER(RTAvlrU64Insert) +# define RTAvlrU64RangeGet RT_MANGLER(RTAvlrU64RangeGet) +# define RTAvlrU64RangeRemove RT_MANGLER(RTAvlrU64RangeRemove) +# define RTAvlrU64Remove RT_MANGLER(RTAvlrU64Remove) +# define RTAvlrU64RemoveBestFit RT_MANGLER(RTAvlrU64RemoveBestFit) +# define RTAvlrUIntPtrDestroy RT_MANGLER(RTAvlrUIntPtrDestroy) +# define RTAvlrUIntPtrDoWithAll RT_MANGLER(RTAvlrUIntPtrDoWithAll) +# define RTAvlrUIntPtrGet RT_MANGLER(RTAvlrUIntPtrGet) +# define RTAvlrUIntPtrGetBestFit RT_MANGLER(RTAvlrUIntPtrGetBestFit) +# define RTAvlrUIntPtrGetLeft RT_MANGLER(RTAvlrUIntPtrGetLeft) +# define RTAvlrUIntPtrGetRight RT_MANGLER(RTAvlrUIntPtrGetRight) +# define RTAvlrUIntPtrGetRoot RT_MANGLER(RTAvlrUIntPtrGetRoot) +# define RTAvlrUIntPtrInsert RT_MANGLER(RTAvlrUIntPtrInsert) +# define RTAvlrUIntPtrRangeGet RT_MANGLER(RTAvlrUIntPtrRangeGet) +# define RTAvlrUIntPtrRangeRemove RT_MANGLER(RTAvlrUIntPtrRangeRemove) +# define RTAvlrUIntPtrRemove RT_MANGLER(RTAvlrUIntPtrRemove) +# define RTAvlU32Destroy RT_MANGLER(RTAvlU32Destroy) +# define RTAvlU32DoWithAll RT_MANGLER(RTAvlU32DoWithAll) +# define RTAvlU32Get RT_MANGLER(RTAvlU32Get) +# define RTAvlU32GetBestFit RT_MANGLER(RTAvlU32GetBestFit) +# define RTAvlU32Insert RT_MANGLER(RTAvlU32Insert) +# define RTAvlU32Remove RT_MANGLER(RTAvlU32Remove) +# define RTAvlU32RemoveBestFit RT_MANGLER(RTAvlU32RemoveBestFit) +# define RTAvlU64Destroy RT_MANGLER(RTAvlU64Destroy) +# define RTAvlU64DoWithAll RT_MANGLER(RTAvlU64DoWithAll) +# define RTAvlU64Get RT_MANGLER(RTAvlU64Get) +# define RTAvlU64GetBestFit RT_MANGLER(RTAvlU64GetBestFit) +# define RTAvlU64Insert RT_MANGLER(RTAvlU64Insert) +# define RTAvlU64Remove RT_MANGLER(RTAvlU64Remove) +# define RTAvlU64RemoveBestFit RT_MANGLER(RTAvlU64RemoveBestFit) +# define RTAvlUIntPtrDestroy RT_MANGLER(RTAvlUIntPtrDestroy) +# define RTAvlUIntPtrDoWithAll RT_MANGLER(RTAvlUIntPtrDoWithAll) +# define RTAvlUIntPtrGet RT_MANGLER(RTAvlUIntPtrGet) +# define RTAvlUIntPtrGetBestFit RT_MANGLER(RTAvlUIntPtrGetBestFit) +# define RTAvlUIntPtrGetLeft RT_MANGLER(RTAvlUIntPtrGetLeft) +# define RTAvlUIntPtrGetRight RT_MANGLER(RTAvlUIntPtrGetRight) +# define RTAvlUIntPtrGetRoot RT_MANGLER(RTAvlUIntPtrGetRoot) +# define RTAvlUIntPtrInsert RT_MANGLER(RTAvlUIntPtrInsert) +# define RTAvlUIntPtrRemove RT_MANGLER(RTAvlUIntPtrRemove) +# define RTAvlULDestroy RT_MANGLER(RTAvlULDestroy) +# define RTAvlULDoWithAll RT_MANGLER(RTAvlULDoWithAll) +# define RTAvlULGet RT_MANGLER(RTAvlULGet) +# define RTAvlULGetBestFit RT_MANGLER(RTAvlULGetBestFit) +# define RTAvlULInsert RT_MANGLER(RTAvlULInsert) +# define RTAvlULRemove RT_MANGLER(RTAvlULRemove) +# define RTAvlULRemoveBestFit RT_MANGLER(RTAvlULRemoveBestFit) +# define RTBase64Decode RT_MANGLER(RTBase64Decode) +# define RTBase64DecodeEx RT_MANGLER(RTBase64DecodeEx) +# define RTBase64DecodedSize RT_MANGLER(RTBase64DecodedSize) +# define RTBase64DecodedSizeEx RT_MANGLER(RTBase64DecodedSizeEx) +# define RTBase64DecodeUtf16 RT_MANGLER(RTBase64DecodeUtf16) +# define RTBase64DecodeUtf16Ex RT_MANGLER(RTBase64DecodeUtf16Ex) +# define RTBase64DecodedUtf16Size RT_MANGLER(RTBase64DecodedUtf16Size) +# define RTBase64DecodedUtf16SizeEx RT_MANGLER(RTBase64DecodedUtf16SizeEx) +# define RTBase64Encode RT_MANGLER(RTBase64Encode) +# define RTBase64EncodeEx RT_MANGLER(RTBase64EncodeEx) +# define RTBase64EncodedLength RT_MANGLER(RTBase64EncodedLength) +# define RTBase64EncodedLengthEx RT_MANGLER(RTBase64EncodedLengthEx) +# define RTBase64EncodeUtf16 RT_MANGLER(RTBase64EncodeUtf16) +# define RTBase64EncodeUtf16Ex RT_MANGLER(RTBase64EncodeUtf16Ex) +# define RTBase64EncodedUtf16Length RT_MANGLER(RTBase64EncodedUtf16Length) +# define RTBase64EncodedUtf16LengthEx RT_MANGLER(RTBase64EncodedUtf16LengthEx) +# define RTBldCfgCompiler RT_MANGLER(RTBldCfgCompiler) +# define RTBldCfgRevision RT_MANGLER(RTBldCfgRevision) +# define RTBldCfgRevisionStr RT_MANGLER(RTBldCfgRevisionStr) +# define RTBldCfgTarget RT_MANGLER(RTBldCfgTarget) +# define RTBldCfgTargetArch RT_MANGLER(RTBldCfgTargetArch) +# define RTBldCfgTargetDotArch RT_MANGLER(RTBldCfgTargetDotArch) +# define RTBldCfgType RT_MANGLER(RTBldCfgType) +# define RTBldCfgVersion RT_MANGLER(RTBldCfgVersion) +# define RTBldCfgVersionBuild RT_MANGLER(RTBldCfgVersionBuild) +# define RTBldCfgVersionMajor RT_MANGLER(RTBldCfgVersionMajor) +# define RTBldCfgVersionMinor RT_MANGLER(RTBldCfgVersionMinor) +# define RTCdromOpen RT_MANGLER(RTCdromOpen) +# define RTCdromRetain RT_MANGLER(RTCdromRetain) +# define RTCdromRelease RT_MANGLER(RTCdromRelease) +# define RTCdromQueryMountPoint RT_MANGLER(RTCdromQueryMountPoint) +# define RTCdromUnmount RT_MANGLER(RTCdromUnmount) +# define RTCdromEject RT_MANGLER(RTCdromEject) +# define RTCdromLock RT_MANGLER(RTCdromLock) +# define RTCdromUnlock RT_MANGLER(RTCdromUnlock) +# define RTCdromCount RT_MANGLER(RTCdromCount) +# define RTCdromOrdinalToName RT_MANGLER(RTCdromOrdinalToName) +# define RTCdromOpenByOrdinal RT_MANGLER(RTCdromOpenByOrdinal) +# define RTCidrStrToIPv4 RT_MANGLER(RTCidrStrToIPv4) +# define RTCircBufAcquireReadBlock RT_MANGLER(RTCircBufAcquireReadBlock) +# define RTCircBufAcquireWriteBlock RT_MANGLER(RTCircBufAcquireWriteBlock) +# define RTCircBufCreate RT_MANGLER(RTCircBufCreate) +# define RTCircBufDestroy RT_MANGLER(RTCircBufDestroy) +# define RTCircBufFree RT_MANGLER(RTCircBufFree) +# define RTCircBufIsReading RT_MANGLER(RTCircBufIsReading) +# define RTCircBufIsWriting RT_MANGLER(RTCircBufIsWriting) +# define RTCircBufOffsetRead RT_MANGLER(RTCircBufOffsetRead) +# define RTCircBufOffsetWrite RT_MANGLER(RTCircBufOffsetWrite) +# define RTCircBufReleaseReadBlock RT_MANGLER(RTCircBufReleaseReadBlock) +# define RTCircBufReleaseWriteBlock RT_MANGLER(RTCircBufReleaseWriteBlock) +# define RTCircBufReset RT_MANGLER(RTCircBufReset) +# define RTCircBufSize RT_MANGLER(RTCircBufSize) +# define RTCircBufUsed RT_MANGLER(RTCircBufUsed) +# define RTCoreDumperDisable RT_MANGLER(RTCoreDumperDisable) /* solaris */ +# define RTCoreDumperSetup RT_MANGLER(RTCoreDumperSetup) /* solaris */ +# define RTCoreDumperTakeDump RT_MANGLER(RTCoreDumperTakeDump) /* solaris */ +# define RTCrc16Ccitt RT_MANGLER(RTCrc16Ccitt) +# define RTCrc16CcittProcess RT_MANGLER(RTCrc16CcittProcess) +# define RTCrc16CcittFinish RT_MANGLER(RTCrc16CcittFinish) +# define RTCrc16CcittStart RT_MANGLER(RTCrc16CcittStart) +# define RTCrc32 RT_MANGLER(RTCrc32) +# define RTCrc32Finish RT_MANGLER(RTCrc32Finish) +# define RTCrc32Process RT_MANGLER(RTCrc32Process) +# define RTCrc32Start RT_MANGLER(RTCrc32Start) +# define RTCrc32C RT_MANGLER(RTCrc32C) +# define RTCrc32CFinish RT_MANGLER(RTCrc32CFinish) +# define RTCrc32CProcess RT_MANGLER(RTCrc32CProcess) +# define RTCrc32CStart RT_MANGLER(RTCrc32CStart) +# define RTCrc64 RT_MANGLER(RTCrc64) +# define RTCrc64Finish RT_MANGLER(RTCrc64Finish) +# define RTCrc64Process RT_MANGLER(RTCrc64Process) +# define RTCrc64Start RT_MANGLER(RTCrc64Start) +# define RTCrcAdler32 RT_MANGLER(RTCrcAdler32) +# define RTCrcAdler32Finish RT_MANGLER(RTCrcAdler32Finish) +# define RTCrcAdler32Process RT_MANGLER(RTCrcAdler32Process) +# define RTCrcAdler32Start RT_MANGLER(RTCrcAdler32Start) +# define RTCritSectDelete RT_MANGLER(RTCritSectDelete) +# define RTCritSectEnter RT_MANGLER(RTCritSectEnter) +# define RTCritSectEnterDebug RT_MANGLER(RTCritSectEnterDebug) +# define RTCritSectEnterMultiple RT_MANGLER(RTCritSectEnterMultiple) +# define RTCritSectEnterMultipleDebug RT_MANGLER(RTCritSectEnterMultipleDebug) +# define RTCritSectInit RT_MANGLER(RTCritSectInit) +# define RTCritSectInitEx RT_MANGLER(RTCritSectInitEx) +# define RTCritSectLeave RT_MANGLER(RTCritSectLeave) +# define RTCritSectLeaveMultiple RT_MANGLER(RTCritSectLeaveMultiple) +# define RTCritSectSetSubClass RT_MANGLER(RTCritSectSetSubClass) +# define RTCritSectTryEnter RT_MANGLER(RTCritSectTryEnter) +# define RTCritSectTryEnterDebug RT_MANGLER(RTCritSectTryEnterDebug) +# define RTCritSectRwDelete RT_MANGLER(RTCritSectRwDelete) +# define RTCritSectRwEnterExcl RT_MANGLER(RTCritSectRwEnterExcl) +# define RTCritSectRwEnterExclDebug RT_MANGLER(RTCritSectRwEnterExclDebug) +# define RTCritSectRwEnterShared RT_MANGLER(RTCritSectRwEnterShared) +# define RTCritSectRwEnterSharedDebug RT_MANGLER(RTCritSectRwEnterSharedDebug) +# define RTCritSectRwGetReadCount RT_MANGLER(RTCritSectRwGetReadCount) +# define RTCritSectRwGetWriteRecursion RT_MANGLER(RTCritSectRwGetWriteRecursion) +# define RTCritSectRwGetWriterReadRecursion RT_MANGLER(RTCritSectRwGetWriterReadRecursion) +# define RTCritSectRwInit RT_MANGLER(RTCritSectRwInit) +# define RTCritSectRwInitEx RT_MANGLER(RTCritSectRwInitEx) +# define RTCritSectRwIsReadOwner RT_MANGLER(RTCritSectRwIsReadOwner) +# define RTCritSectRwIsWriteOwner RT_MANGLER(RTCritSectRwIsWriteOwner) +# define RTCritSectRwLeaveExcl RT_MANGLER(RTCritSectRwLeaveExcl) +# define RTCritSectRwLeaveShared RT_MANGLER(RTCritSectRwLeaveShared) +# define RTCritSectRwSetSubClass RT_MANGLER(RTCritSectRwSetSubClass) +# define RTCritSectRwTryEnterExcl RT_MANGLER(RTCritSectRwTryEnterExcl) +# define RTCritSectRwTryEnterExclDebug RT_MANGLER(RTCritSectRwTryEnterExclDebug) +# define RTCritSectRwTryEnterShared RT_MANGLER(RTCritSectRwTryEnterShared) +# define RTCritSectRwTryEnterSharedDebug RT_MANGLER(RTCritSectRwTryEnterSharedDebug) +# define RTDbgAsCreate RT_MANGLER(RTDbgAsCreate) +# define RTDbgAsCreateF RT_MANGLER(RTDbgAsCreateF) +# define RTDbgAsCreateV RT_MANGLER(RTDbgAsCreateV) +# define RTDbgAsFirstAddr RT_MANGLER(RTDbgAsFirstAddr) +# define RTDbgAsLastAddr RT_MANGLER(RTDbgAsLastAddr) +# define RTDbgAsLineAdd RT_MANGLER(RTDbgAsLineAdd) +# define RTDbgAsLineByAddr RT_MANGLER(RTDbgAsLineByAddr) +# define RTDbgAsLineByAddrA RT_MANGLER(RTDbgAsLineByAddrA) +# define RTDbgAsLockExcl RT_MANGLER(RTDbgAsLockExcl) +# define RTDbgAsModuleByAddr RT_MANGLER(RTDbgAsModuleByAddr) +# define RTDbgAsModuleByIndex RT_MANGLER(RTDbgAsModuleByIndex) +# define RTDbgAsModuleByName RT_MANGLER(RTDbgAsModuleByName) +# define RTDbgAsModuleCount RT_MANGLER(RTDbgAsModuleCount) +# define RTDbgAsModuleLink RT_MANGLER(RTDbgAsModuleLink) +# define RTDbgAsModuleLinkSeg RT_MANGLER(RTDbgAsModuleLinkSeg) +# define RTDbgAsModuleQueryMapByIndex RT_MANGLER(RTDbgAsModuleQueryMapByIndex) +# define RTDbgAsModuleUnlink RT_MANGLER(RTDbgAsModuleUnlink) +# define RTDbgAsModuleUnlinkByAddr RT_MANGLER(RTDbgAsModuleUnlinkByAddr) +# define RTDbgAsName RT_MANGLER(RTDbgAsName) +# define RTDbgAsRelease RT_MANGLER(RTDbgAsRelease) +# define RTDbgAsRetain RT_MANGLER(RTDbgAsRetain) +# define RTDbgAsSymbolAdd RT_MANGLER(RTDbgAsSymbolAdd) +# define RTDbgAsSymbolByAddr RT_MANGLER(RTDbgAsSymbolByAddr) +# define RTDbgAsSymbolByAddrA RT_MANGLER(RTDbgAsSymbolByAddrA) +# define RTDbgAsSymbolByName RT_MANGLER(RTDbgAsSymbolByName) +# define RTDbgAsSymbolByNameA RT_MANGLER(RTDbgAsSymbolByNameA) +# define RTDbgAsUnlockExcl RT_MANGLER(RTDbgAsUnlockExcl) +# define RTDbgCfgCreate RT_MANGLER(RTDbgCfgCreate) +# define RTDbgCfgRetain RT_MANGLER(RTDbgCfgRetain) +# define RTDbgCfgRelease RT_MANGLER(RTDbgCfgRelease) +# define RTDbgCfgChangeString RT_MANGLER(RTDbgCfgChangeString) +# define RTDbgCfgChangeUInt RT_MANGLER(RTDbgCfgChangeUInt) +# define RTDbgCfgQueryString RT_MANGLER(RTDbgCfgQueryString) +# define RTDbgCfgQueryUInt RT_MANGLER(RTDbgCfgQueryUInt) +# define RTDbgCfgOpenEx RT_MANGLER(RTDbgCfgOpenEx) +# define RTDbgCfgOpenDbg RT_MANGLER(RTDbgCfgOpenDbg) +# define RTDbgCfgOpenDsymBundle RT_MANGLER(RTDbgCfgOpenDsymBundle) +# define RTDbgCfgOpenMachOImage RT_MANGLER(RTDbgCfgOpenMachOImage) +# define RTDbgCfgOpenDwo RT_MANGLER(RTDbgCfgOpenDwo) +# define RTDbgCfgOpenDwoBuildId RT_MANGLER(RTDbgCfgOpenDwoBuildId) +# define RTDbgCfgOpenPdb70 RT_MANGLER(RTDbgCfgOpenPdb70) +# define RTDbgCfgOpenPdb20 RT_MANGLER(RTDbgCfgOpenPdb20) +# define RTDbgCfgOpenPeImage RT_MANGLER(RTDbgCfgOpenPeImage) +# define RTDbgCfgSetLogCallback RT_MANGLER(RTDbgCfgSetLogCallback) +# define RTDbgLineAlloc RT_MANGLER(RTDbgLineAlloc) +# define RTDbgLineDup RT_MANGLER(RTDbgLineDup) +# define RTDbgLineFree RT_MANGLER(RTDbgLineFree) +# define RTDbgModCreate RT_MANGLER(RTDbgModCreate) +# define RTDbgModCreateFromDbg RT_MANGLER(RTDbgModCreateFromDbg) +# define RTDbgModCreateFromDwo RT_MANGLER(RTDbgModCreateFromDwo) +# define RTDbgModCreateFromImage RT_MANGLER(RTDbgModCreateFromImage) +# define RTDbgModCreateFromMap RT_MANGLER(RTDbgModCreateFromMap) +# define RTDbgModCreateFromPdb RT_MANGLER(RTDbgModCreateFromPdb) +# define RTDbgModCreateFromPeImage RT_MANGLER(RTDbgModCreateFromPeImage) +# define RTDbgModCreateFromMachOImage RT_MANGLER(RTDbgModCreateFromMachOImage) +# define RTDbgModGetTag RT_MANGLER(RTDbgModGetTag) +# define RTDbgModImageGetArch RT_MANGLER(RTDbgModImageGetArch) +# define RTDbgModImageGetFormat RT_MANGLER(RTDbgModImageGetFormat) +# define RTDbgModImageSize RT_MANGLER(RTDbgModImageSize) +# define RTDbgModImageQueryProp RT_MANGLER(RTDbgModImageQueryProp) +# define RTDbgModIsDeferred RT_MANGLER(RTDbgModIsDeferred) +# define RTDbgModIsExports RT_MANGLER(RTDbgModIsExports) +# define RTDbgModLineAdd RT_MANGLER(RTDbgModLineAdd) +# define RTDbgModLineByAddr RT_MANGLER(RTDbgModLineByAddr) +# define RTDbgModLineByAddrA RT_MANGLER(RTDbgModLineByAddrA) +# define RTDbgModLineByOrdinal RT_MANGLER(RTDbgModLineByOrdinal) +# define RTDbgModLineByOrdinalA RT_MANGLER(RTDbgModLineByOrdinalA) +# define RTDbgModLineCount RT_MANGLER(RTDbgModLineCount) +# define RTDbgModName RT_MANGLER(RTDbgModName) +# define RTDbgModDebugFile RT_MANGLER(RTDbgModDebugFile) +# define RTDbgModImageFile RT_MANGLER(RTDbgModImageFile) +# define RTDbgModImageFileUsed RT_MANGLER(RTDbgModImageFileUsed) +# define RTDbgModRelease RT_MANGLER(RTDbgModRelease) +# define RTDbgModRemoveAll RT_MANGLER(RTDbgModRemoveAll) +# define RTDbgModRetain RT_MANGLER(RTDbgModRetain) +# define RTDbgModRvaToSegOff RT_MANGLER(RTDbgModRvaToSegOff) +# define RTDbgModSegmentAdd RT_MANGLER(RTDbgModSegmentAdd) +# define RTDbgModSegmentByIndex RT_MANGLER(RTDbgModSegmentByIndex) +# define RTDbgModSegmentCount RT_MANGLER(RTDbgModSegmentCount) +# define RTDbgModSegmentRva RT_MANGLER(RTDbgModSegmentRva) +# define RTDbgModSegmentSize RT_MANGLER(RTDbgModSegmentSize) +# define RTDbgModSetTag RT_MANGLER(RTDbgModSetTag) +# define RTDbgModSymbolAdd RT_MANGLER(RTDbgModSymbolAdd) +# define RTDbgModSymbolByAddr RT_MANGLER(RTDbgModSymbolByAddr) +# define RTDbgModSymbolByAddrA RT_MANGLER(RTDbgModSymbolByAddrA) +# define RTDbgModSymbolByName RT_MANGLER(RTDbgModSymbolByName) +# define RTDbgModSymbolByNameA RT_MANGLER(RTDbgModSymbolByNameA) +# define RTDbgModSymbolByOrdinal RT_MANGLER(RTDbgModSymbolByOrdinal) +# define RTDbgModSymbolByOrdinalA RT_MANGLER(RTDbgModSymbolByOrdinalA) +# define RTDbgModSymbolCount RT_MANGLER(RTDbgModSymbolCount) +# define RTDbgModUnwindFrame RT_MANGLER(RTDbgModUnwindFrame) +# define RTDbgStackDumpSelf RT_MANGLER(RTDbgStackDumpSelf) +# define RTDbgStackDumpSelf_EndProc RT_MANGLER(RTDbgStackDumpSelf_EndProc) +# define RTDbgSymbolAlloc RT_MANGLER(RTDbgSymbolAlloc) +# define RTDbgSymbolDup RT_MANGLER(RTDbgSymbolDup) +# define RTDbgSymbolFree RT_MANGLER(RTDbgSymbolFree) +# define RTDirClose RT_MANGLER(RTDirClose) +# define RTDirCreate RT_MANGLER(RTDirCreate) +# define RTDirCreateFullPath RT_MANGLER(RTDirCreateFullPath) +# define RTDirCreateFullPathEx RT_MANGLER(RTDirCreateFullPathEx) +# define RTDirCreateTemp RT_MANGLER(RTDirCreateTemp) +# define RTDirCreateTempSecure RT_MANGLER(RTDirCreateTempSecure) +# define RTDirCreateUniqueNumbered RT_MANGLER(RTDirCreateUniqueNumbered) +# define RTDirEntryIsStdDotLink RT_MANGLER(RTDirEntryIsStdDotLink) +# define RTDirEntryExIsStdDotLink RT_MANGLER(RTDirEntryExIsStdDotLink) +# define RTDirExists RT_MANGLER(RTDirExists) +# define RTDirFlush RT_MANGLER(RTDirFlush) +# define RTDirFlushParent RT_MANGLER(RTDirFlushParent) +# define RTDirIsValid RT_MANGLER(RTDirIsValid) +# define RTDirOpen RT_MANGLER(RTDirOpen) +# define RTDirOpenFiltered RT_MANGLER(RTDirOpenFiltered) +# define RTDirQueryInfo RT_MANGLER(RTDirQueryInfo) +# define RTDirQueryUnknownType RT_MANGLER(RTDirQueryUnknownType) +# define RTDirQueryUnknownTypeEx RT_MANGLER(RTDirQueryUnknownTypeEx) +# define RTDirRead RT_MANGLER(RTDirRead) +# define RTDirReadEx RT_MANGLER(RTDirReadEx) +# define RTDirReadExA RT_MANGLER(RTDirReadExA) +# define RTDirReadExAFree RT_MANGLER(RTDirReadExAFree) +# define RTDirRemove RT_MANGLER(RTDirRemove) +# define RTDirRemoveRecursive RT_MANGLER(RTDirRemoveRecursive) +# define RTDirRename RT_MANGLER(RTDirRename) +# define RTDirRewind RT_MANGLER(RTDirRewind) +# define RTDirSetMode RT_MANGLER(RTDirSetMode) +# define RTDirSetTimes RT_MANGLER(RTDirSetTimes) +# define RTDirRelFileOpen RT_MANGLER(RTDirRelFileOpen) +# define RTDirRelDirOpen RT_MANGLER(RTDirRelDirOpen) +# define RTDirRelDirOpenFiltered RT_MANGLER(RTDirRelDirOpenFiltered) +# define RTDirRelDirCreate RT_MANGLER(RTDirRelDirCreate) +# define RTDirRelDirRemove RT_MANGLER(RTDirRelDirRemove) +# define RTDirRelPathQueryInfo RT_MANGLER(RTDirRelPathQueryInfo) +# define RTDirRelPathSetMode RT_MANGLER(RTDirRelPathSetMode) +# define RTDirRelPathSetTimes RT_MANGLER(RTDirRelPathSetTimes) +# define RTDirRelPathSetOwner RT_MANGLER(RTDirRelPathSetOwner) +# define RTDirRelPathRename RT_MANGLER(RTDirRelPathRename) +# define RTDirRelPathUnlink RT_MANGLER(RTDirRelPathUnlink) +# define RTDirRelSymlinkCreate RT_MANGLER(RTDirRelSymlinkCreate) +# define RTDirRelSymlinkRead RT_MANGLER(RTDirRelSymlinkRead) +# define RTVfsDirOpenDir RT_MANGLER(RTVfsDirOpenDir) +# define RTVfsDirFromRTDir RT_MANGLER(RTVfsDirFromRTDir) +# define RTVfsDirOpenNormal RT_MANGLER(RTVfsDirOpenNormal) +# define RTVfsDirIsStdDir RT_MANGLER(RTVfsDirIsStdDir) +# define RTDvmCreate RT_MANGLER(RTDvmCreate) +# define RTDvmCreateFromVfsFile RT_MANGLER(RTDvmCreateFromVfsFile) +# define RTDvmRetain RT_MANGLER(RTDvmRetain) +# define RTDvmRelease RT_MANGLER(RTDvmRelease) +# define RTDvmMapOpen RT_MANGLER(RTDvmMapOpen) +# define RTDvmMapInitialize RT_MANGLER(RTDvmMapInitialize) +# define RTDvmMapGetFormatName RT_MANGLER(RTDvmMapGetFormatName) +# define RTDvmMapGetFormatType RT_MANGLER(RTDvmMapGetFormatType) +# define RTDvmMapGetValidVolumes RT_MANGLER(RTDvmMapGetValidVolumes) +# define RTDvmMapGetMaxVolumes RT_MANGLER(RTDvmMapGetMaxVolumes) +# define RTDvmMapQueryBlockStatus RT_MANGLER(RTDvmMapQueryBlockStatus) +# define RTDvmMapQueryFirstVolume RT_MANGLER(RTDvmMapQueryFirstVolume) +# define RTDvmMapQueryNextVolume RT_MANGLER(RTDvmMapQueryNextVolume) +# define RTDvmMapQueryDiskUuid RT_MANGLER(RTDvmMapQueryDiskUuid) +# define RTDvmMapQueryTableLocations RT_MANGLER(RTDvmMapQueryTableLocations) +# define RTDvmVolumeRetain RT_MANGLER(RTDvmVolumeRetain) +# define RTDvmVolumeRelease RT_MANGLER(RTDvmVolumeRelease) +# define RTDvmVolumeGetIndex RT_MANGLER(RTDvmVolumeGetIndex) +# define RTDvmVolumeGetPropU64 RT_MANGLER(RTDvmVolumeGetPropU64) +# define RTDvmVolumeGetSize RT_MANGLER(RTDvmVolumeGetSize) +# define RTDvmVolumeQueryName RT_MANGLER(RTDvmVolumeQueryName) +# define RTDvmVolumeQueryProp RT_MANGLER(RTDvmVolumeQueryProp) +# define RTDvmVolumeQueryTableLocation RT_MANGLER(RTDvmVolumeQueryTableLocation) +# define RTDvmVolumeGetType RT_MANGLER(RTDvmVolumeGetType) +# define RTDvmVolumeGetFlags RT_MANGLER(RTDvmVolumeGetFlags) +# define RTDvmVolumeQueryRange RT_MANGLER(RTDvmVolumeQueryRange) +# define RTDvmVolumeRead RT_MANGLER(RTDvmVolumeRead) +# define RTDvmVolumeWrite RT_MANGLER(RTDvmVolumeWrite) +# define RTDvmVolumeSetQueryBlockStatusCallback RT_MANGLER(RTDvmVolumeSetQueryBlockStatusCallback) +# define RTDvmVolumeTypeGetDescr RT_MANGLER(RTDvmVolumeTypeGetDescr) +# define RTDvmVolumeCreateVfsFile RT_MANGLER(RTDvmVolumeCreateVfsFile) +# define RTEfiGuidCompare RT_MANGLER(RTEfiGuidCompare) +# define RTEfiGuidFromUuid RT_MANGLER(RTEfiGuidFromUuid) +# define RTEfiGuidToUuid RT_MANGLER(RTEfiGuidToUuid) +# define RTEfiSigDbAddFromExistingDb RT_MANGLER(RTEfiSigDbAddFromExistingDb) +# define RTEfiSigDbAddSignatureFromFile RT_MANGLER(RTEfiSigDbAddSignatureFromFile) +# define RTEfiSigDbAddSignatureFromBuf RT_MANGLER(RTEfiSigDbAddSignatureFromBuf) +# define RTEfiSigDbCreate RT_MANGLER(RTEfiSigDbCreate) +# define RTEfiSigDbDestroy RT_MANGLER(RTEfiSigDbDestroy) +# define RTEfiSigDbEnum RT_MANGLER(RTEfiSigDbEnum) +# define RTEfiSigDbTypeGetGuid RT_MANGLER(RTEfiSigDbTypeGetGuid) +# define RTEfiSigDbTypeStringify RT_MANGLER(RTEfiSigDbTypeStringify) +# define RTEfiSigDbWriteToFile RT_MANGLER(RTEfiSigDbWriteToFile) +# define RTEfiTimeFromTimeSpec RT_MANGLER(RTEfiTimeFromTimeSpec) +# define RTEfiTimeToTimeSpec RT_MANGLER(RTEfiTimeToTimeSpec) +# define RTEfiVarStoreCreate RT_MANGLER(RTEfiVarStoreCreate) +# define RTEfiVarStoreOpenAsVfs RT_MANGLER(RTEfiVarStoreOpenAsVfs) +# define RTEnvApplyChanges RT_MANGLER(RTEnvApplyChanges) +# define RTEnvClone RT_MANGLER(RTEnvClone) +# define RTEnvCloneUtf16Block RT_MANGLER(RTEnvCloneUtf16Block) +# define RTEnvCountEx RT_MANGLER(RTEnvCountEx) +# define RTEnvCreate RT_MANGLER(RTEnvCreate) +# define RTEnvCreateEx RT_MANGLER(RTEnvCreateEx) +# define RTEnvCreateChangeRecord RT_MANGLER(RTEnvCreateChangeRecord) +# define RTEnvCreateChangeRecordEx RT_MANGLER(RTEnvCreateChangeRecordEx) +# define RTEnvDestroy RT_MANGLER(RTEnvDestroy) +# define RTEnvDup RT_MANGLER(RTEnvDup) +# define RTEnvDupEx RT_MANGLER(RTEnvDupEx) +# define RTEnvExist RT_MANGLER(RTEnvExist) +# define RTEnvExistsBad RT_MANGLER(RTEnvExistsBad) +# define RTEnvExistsUtf8 RT_MANGLER(RTEnvExistsUtf8) +# define RTEnvExistEx RT_MANGLER(RTEnvExistEx) +# define RTEnvFreeUtf8Block RT_MANGLER(RTEnvFreeUtf8Block) +# define RTEnvFreeUtf16Block RT_MANGLER(RTEnvFreeUtf16Block) +# define RTEnvGet RT_MANGLER(RTEnvGet) +# define RTEnvGetBad RT_MANGLER(RTEnvGetBad) +# define RTEnvGetByIndexEx RT_MANGLER(RTEnvGetByIndexEx) +# define RTEnvGetByIndexRawEx RT_MANGLER(RTEnvGetByIndexRawEx) +# define RTEnvGetUtf8 RT_MANGLER(RTEnvGetUtf8) +# define RTEnvGetEx RT_MANGLER(RTEnvGetEx) +# define RTEnvGetExecEnvP RT_MANGLER(RTEnvGetExecEnvP) +# define RTEnvIsChangeRecord RT_MANGLER(RTEnvIsChangeRecord) +# define RTEnvPut RT_MANGLER(RTEnvPut) +# define RTEnvPutBad RT_MANGLER(RTEnvPutBad) +# define RTEnvPutUtf8 RT_MANGLER(RTEnvPutUtf8) +# define RTEnvPutEx RT_MANGLER(RTEnvPutEx) +# define RTEnvQueryUtf16Block RT_MANGLER(RTEnvQueryUtf16Block) +# define RTEnvQueryUtf8Block RT_MANGLER(RTEnvQueryUtf8Block) +# define RTEnvReset RT_MANGLER(RTEnvReset) +# define RTEnvSet RT_MANGLER(RTEnvSet) +# define RTEnvSetBad RT_MANGLER(RTEnvSetBad) +# define RTEnvSetUtf8 RT_MANGLER(RTEnvSetUtf8) +# define RTEnvSetEx RT_MANGLER(RTEnvSetEx) +# define RTEnvUnset RT_MANGLER(RTEnvUnset) +# define RTEnvUnsetBad RT_MANGLER(RTEnvUnsetBad) +# define RTEnvUnsetUtf8 RT_MANGLER(RTEnvUnsetUtf8) +# define RTEnvUnsetEx RT_MANGLER(RTEnvUnsetEx) +# define RTErrCOMGet RT_MANGLER(RTErrCOMGet) +# define RTErrConvertFromErrno RT_MANGLER(RTErrConvertFromErrno) +# define RTErrConvertToErrno RT_MANGLER(RTErrConvertToErrno) +# define RTErrIsKnown RT_MANGLER(RTErrIsKnown) +# define RTErrQueryDefine RT_MANGLER(RTErrQueryDefine) +# define RTErrQueryMsgShort RT_MANGLER(RTErrQueryMsgShort) +# define RTErrQueryMsgFull RT_MANGLER(RTErrQueryMsgFull) +# define RTErrFormatDefine RT_MANGLER(RTErrFormatDefine) +# define RTErrFormatMsgShort RT_MANGLER(RTErrFormatMsgShort) +# define RTErrFormatMsgFull RT_MANGLER(RTErrFormatMsgFull) +# define RTErrFormatMsgAll RT_MANGLER(RTErrFormatMsgAll) +# define RTErrInfoAlloc RT_MANGLER(RTErrInfoAlloc) +# define RTErrInfoAllocEx RT_MANGLER(RTErrInfoAllocEx) +# define RTErrInfoFree RT_MANGLER(RTErrInfoFree) +# define RTErrInfoSet RT_MANGLER(RTErrInfoSet) +# define RTErrInfoSetF RT_MANGLER(RTErrInfoSetF) +# define RTErrInfoSetV RT_MANGLER(RTErrInfoSetV) +# define RTErrInfoLogAndSet RT_MANGLER(RTErrInfoLogAndSet) +# define RTErrInfoLogAndSetF RT_MANGLER(RTErrInfoLogAndSetF) +# define RTErrInfoLogAndSetV RT_MANGLER(RTErrInfoLogAndSetV) +# define RTErrInfoLogAndAdd RT_MANGLER(RTErrInfoLogAndAdd) +# define RTErrInfoLogAndAddF RT_MANGLER(RTErrInfoLogAndAddF) +# define RTErrInfoLogAndAddV RT_MANGLER(RTErrInfoLogAndAddV) +# define RTErrVarsAreEqual RT_MANGLER(RTErrVarsAreEqual) +# define RTErrVarsHaveChanged RT_MANGLER(RTErrVarsHaveChanged) +# define RTErrVarsRestore RT_MANGLER(RTErrVarsRestore) +# define RTErrVarsSave RT_MANGLER(RTErrVarsSave) +# define RTFileAioCtxAssociateWithFile RT_MANGLER(RTFileAioCtxAssociateWithFile) +# define RTFileAioCtxCreate RT_MANGLER(RTFileAioCtxCreate) +# define RTFileAioCtxDestroy RT_MANGLER(RTFileAioCtxDestroy) +# define RTFileAioCtxGetMaxReqCount RT_MANGLER(RTFileAioCtxGetMaxReqCount) +# define RTFileAioCtxSubmit RT_MANGLER(RTFileAioCtxSubmit) +# define RTFileAioCtxWait RT_MANGLER(RTFileAioCtxWait) +# define RTFileAioCtxWakeup RT_MANGLER(RTFileAioCtxWakeup) +# define RTFileAioGetLimits RT_MANGLER(RTFileAioGetLimits) +# define RTFileAioReqCancel RT_MANGLER(RTFileAioReqCancel) +# define RTFileAioReqCreate RT_MANGLER(RTFileAioReqCreate) +# define RTFileAioReqDestroy RT_MANGLER(RTFileAioReqDestroy) +# define RTFileAioReqGetRC RT_MANGLER(RTFileAioReqGetRC) +# define RTFileAioReqGetUser RT_MANGLER(RTFileAioReqGetUser) +# define RTFileAioReqPrepareFlush RT_MANGLER(RTFileAioReqPrepareFlush) +# define RTFileAioReqPrepareRead RT_MANGLER(RTFileAioReqPrepareRead) +# define RTFileAioReqPrepareWrite RT_MANGLER(RTFileAioReqPrepareWrite) +# define RTFileChangeLock RT_MANGLER(RTFileChangeLock) +# define RTFileClose RT_MANGLER(RTFileClose) +# define RTFileCompare RT_MANGLER(RTFileCompare) +# define RTFileCompareByHandles RT_MANGLER(RTFileCompareByHandles) +# define RTFileCompareByHandlesEx RT_MANGLER(RTFileCompareByHandlesEx) +# define RTFileCompareEx RT_MANGLER(RTFileCompareEx) +# define RTFileCopy RT_MANGLER(RTFileCopy) +# define RTFileCopyAttributes RT_MANGLER(RTFileCopyAttributes) +# define RTFileCopyByHandles RT_MANGLER(RTFileCopyByHandles) +# define RTFileCopyByHandlesEx RT_MANGLER(RTFileCopyByHandlesEx) +# define RTFileCopyEx RT_MANGLER(RTFileCopyEx) +# define RTFileCopyPart RT_MANGLER(RTFileCopyPart) +# define RTFileCopyPartCleanup RT_MANGLER(RTFileCopyPartCleanup) +# define RTFileCopyPartEx RT_MANGLER(RTFileCopyPartEx) +# define RTFileCopyPartPrep RT_MANGLER(RTFileCopyPartPrep) +# define RTFileCreateUnique RT_MANGLER(RTFileCreateUnique) +# define RTFileCreateTemp RT_MANGLER(RTFileCreateTemp) +# define RTFileCreateTempSecure RT_MANGLER(RTFileCreateTempSecure) +# define RTFileDelete RT_MANGLER(RTFileDelete) +# define RTFileDup RT_MANGLER(RTFileDup) +# define RTFileExists RT_MANGLER(RTFileExists) +# define RTFileFlush RT_MANGLER(RTFileFlush) +# define RTFileFromNative RT_MANGLER(RTFileFromNative) +# define RTFileGetMaxSize RT_MANGLER(RTFileGetMaxSize) +# define RTFileQueryMaxSizeEx RT_MANGLER(RTFileQueryMaxSizeEx) +# define RTFileQuerySizeByPath RT_MANGLER(RTFileQuerySizeByPath) +# define RTFileIoCtl RT_MANGLER(RTFileIoCtl) +# define RTFileIsValid RT_MANGLER(RTFileIsValid) +# define RTFileLock RT_MANGLER(RTFileLock) +# define RTFileModeToFlags RT_MANGLER(RTFileModeToFlags) +# define RTFileModeToFlagsEx RT_MANGLER(RTFileModeToFlagsEx) +# define RTFileMove RT_MANGLER(RTFileMove) +# define RTFileOpen RT_MANGLER(RTFileOpen) +# define RTFileOpenBitBucket RT_MANGLER(RTFileOpenBitBucket) +# define RTFileOpenEx RT_MANGLER(RTFileOpenEx) +# define RTFileOpenF RT_MANGLER(RTFileOpenF) +# define RTFileOpenV RT_MANGLER(RTFileOpenV) +# define RTFileOpenTemp RT_MANGLER(RTFileOpenTemp) +# define RTFileQueryFsSizes RT_MANGLER(RTFileQueryFsSizes) +# define RTFileQueryInfo RT_MANGLER(RTFileQueryInfo) +# define RTFileQuerySectorSize RT_MANGLER(RTFileQuerySectorSize) +# define RTFileQuerySize RT_MANGLER(RTFileQuerySize) +# define RTFileRead RT_MANGLER(RTFileRead) +# define RTFileReadAll RT_MANGLER(RTFileReadAll) +# define RTFileReadAllByHandle RT_MANGLER(RTFileReadAllByHandle) +# define RTFileReadAllByHandleEx RT_MANGLER(RTFileReadAllByHandleEx) +# define RTFileReadAllEx RT_MANGLER(RTFileReadAllEx) +# define RTFileReadAllFree RT_MANGLER(RTFileReadAllFree) +# define RTFileReadAt RT_MANGLER(RTFileReadAt) +# define RTFileRename RT_MANGLER(RTFileRename) +# define RTFileSeek RT_MANGLER(RTFileSeek) +# define RTFileSetAllocationSize RT_MANGLER(RTFileSetAllocationSize) +# define RTFileSetForceFlags RT_MANGLER(RTFileSetForceFlags) +# define RTFileSetMode RT_MANGLER(RTFileSetMode) +# define RTFileSetOwner RT_MANGLER(RTFileSetOwner) +# define RTFileSetSize RT_MANGLER(RTFileSetSize) +# define RTFileSetTimes RT_MANGLER(RTFileSetTimes) +# define RTFileSgRead RT_MANGLER(RTFileSgRead) +# define RTFileSgReadAt RT_MANGLER(RTFileSgReadAt) +# define RTFileSgWrite RT_MANGLER(RTFileSgWrite) +# define RTFileSgWriteAt RT_MANGLER(RTFileSgWriteAt) +# define RTFileTell RT_MANGLER(RTFileTell) +# define RTFileToNative RT_MANGLER(RTFileToNative) +# define RTFileUnlock RT_MANGLER(RTFileUnlock) +# define RTFileWrite RT_MANGLER(RTFileWrite) +# define RTFileWriteAt RT_MANGLER(RTFileWriteAt) +# define RTFilesystemVfsFromFile RT_MANGLER(RTFilesystemVfsFromFile) +# define RTFsIsCaseSensitive RT_MANGLER(RTFsIsCaseSensitive) +# define RTFsQueryProperties RT_MANGLER(RTFsQueryProperties) +# define RTFsQuerySerial RT_MANGLER(RTFsQuerySerial) +# define RTFsQuerySizes RT_MANGLER(RTFsQuerySizes) +# define RTFsQueryType RT_MANGLER(RTFsQueryType) +# define RTFsTypeName RT_MANGLER(RTFsTypeName) +# define RTFsExtVolOpen RT_MANGLER(RTFsExtVolOpen) +# define RTFsFatVolOpen RT_MANGLER(RTFsFatVolOpen) +# define RTFsFatVolFormat RT_MANGLER(RTFsFatVolFormat) +# define RTFsFatVolFormat144 RT_MANGLER(RTFsFatVolFormat144) +# define RTFsFatVolFormat288 RT_MANGLER(RTFsFatVolFormat288) +# define RTFsCmdLs RT_MANGLER(RTFsCmdLs) +# define RTFsIso9660VolOpen RT_MANGLER(RTFsIso9660VolOpen) +# define RTFsIsoMakerCreate RT_MANGLER(RTFsIsoMakerCreate) +# define RTFsIsoMakerRetain RT_MANGLER(RTFsIsoMakerRetain) +# define RTFsIsoMakerRelease RT_MANGLER(RTFsIsoMakerRelease) +# define RTFsIsoMakerBootCatSetFile RT_MANGLER(RTFsIsoMakerBootCatSetFile) +# define RTFsIsoMakerBootCatSetValidationEntry RT_MANGLER(RTFsIsoMakerBootCatSetValidationEntry) +# define RTFsIsoMakerBootCatSetSectionEntry RT_MANGLER(RTFsIsoMakerBootCatSetSectionEntry) +# define RTFsIsoMakerBootCatSetSectionHeaderEntry RT_MANGLER(RTFsIsoMakerBootCatSetSectionHeaderEntry) +# define RTFsIsoMakerQueryObjIdxForBootCatalog RT_MANGLER(RTFsIsoMakerQueryObjIdxForBootCatalog) +# define RTFsIsoMakerGetPopulatedNamespaces RT_MANGLER(RTFsIsoMakerGetPopulatedNamespaces) +# define RTFsIsoMakerGetIso9660Level RT_MANGLER(RTFsIsoMakerGetIso9660Level) +# define RTFsIsoMakerGetRockRidgeLevel RT_MANGLER(RTFsIsoMakerGetRockRidgeLevel) +# define RTFsIsoMakerGetJolietRockRidgeLevel RT_MANGLER(RTFsIsoMakerGetJolietRockRidgeLevel) +# define RTFsIsoMakerSetImagePadding RT_MANGLER(RTFsIsoMakerSetImagePadding) +# define RTFsIsoMakerSetIso9660Level RT_MANGLER(RTFsIsoMakerSetIso9660Level) +# define RTFsIsoMakerSetJolietUcs2Level RT_MANGLER(RTFsIsoMakerSetJolietUcs2Level) +# define RTFsIsoMakerSetRockRidgeLevel RT_MANGLER(RTFsIsoMakerSetRockRidgeLevel) +# define RTFsIsoMakerSetJolietRockRidgeLevel RT_MANGLER(RTFsIsoMakerSetJolietRockRidgeLevel) +# define RTFsIsoMakerSetAttribInheritStyle RT_MANGLER(RTFsIsoMakerSetAttribInheritStyle) +# define RTFsIsoMakerSetDefaultDirMode RT_MANGLER(RTFsIsoMakerSetDefaultDirMode) +# define RTFsIsoMakerSetDefaultFileMode RT_MANGLER(RTFsIsoMakerSetDefaultFileMode) +# define RTFsIsoMakerSetForcedDirMode RT_MANGLER(RTFsIsoMakerSetForcedDirMode) +# define RTFsIsoMakerSetForcedFileMode RT_MANGLER(RTFsIsoMakerSetForcedFileMode) +# define RTFsIsoMakerSetPathGroupId RT_MANGLER(RTFsIsoMakerSetPathGroupId) +# define RTFsIsoMakerSetPathMode RT_MANGLER(RTFsIsoMakerSetPathMode) +# define RTFsIsoMakerSetPathOwnerId RT_MANGLER(RTFsIsoMakerSetPathOwnerId) +# define RTFsIsoMakerSetSysAreaContent RT_MANGLER(RTFsIsoMakerSetSysAreaContent) +# define RTFsIsoMakerSetStringProp RT_MANGLER(RTFsIsoMakerSetStringProp) +# define RTFsIsoMakerGetObjIdxForPath RT_MANGLER(RTFsIsoMakerGetObjIdxForPath) +# define RTFsIsoMakerObjEnableBootInfoTablePatching RT_MANGLER(RTFsIsoMakerObjEnableBootInfoTablePatching) +# define RTFsIsoMakerObjQueryDataSize RT_MANGLER(RTFsIsoMakerObjQueryDataSize) +# define RTFsIsoMakerObjRemove RT_MANGLER(RTFsIsoMakerObjRemove) +# define RTFsIsoMakerObjSetPath RT_MANGLER(RTFsIsoMakerObjSetPath) +# define RTFsIsoMakerObjSetNameAndParent RT_MANGLER(RTFsIsoMakerObjSetNameAndParent) +# define RTFsIsoMakerObjSetRockName RT_MANGLER(RTFsIsoMakerObjSetRockName) +# define RTFsIsoMakerAddUnnamedDir RT_MANGLER(RTFsIsoMakerAddUnnamedDir) +# define RTFsIsoMakerAddDir RT_MANGLER(RTFsIsoMakerAddDir) +# define RTFsIsoMakerAddFileWithSrcPath RT_MANGLER(RTFsIsoMakerAddFileWithSrcPath) +# define RTFsIsoMakerAddFileWithVfsFile RT_MANGLER(RTFsIsoMakerAddFileWithVfsFile) +# define RTFsIsoMakerAddUnnamedFileWithSrcPath RT_MANGLER(RTFsIsoMakerAddUnnamedFileWithSrcPath) +# define RTFsIsoMakerAddUnnamedFileWithVfsFile RT_MANGLER(RTFsIsoMakerAddUnnamedFileWithVfsFile) +# define RTFsIsoMakerAddUnnamedFileWithCommonSrc RT_MANGLER(RTFsIsoMakerAddUnnamedFileWithCommonSrc) +# define RTFsIsoMakerAddSymlink RT_MANGLER(RTFsIsoMakerAddSymlink) +# define RTFsIsoMakerAddUnnamedSymlink RT_MANGLER(RTFsIsoMakerAddUnnamedSymlink) +# define RTFsIsoMakerAddCommonSourceFile RT_MANGLER(RTFsIsoMakerAddCommonSourceFile) +# define RTFsIsoMakerImport RT_MANGLER(RTFsIsoMakerImport) +# define RTFsIsoMakerFinalize RT_MANGLER(RTFsIsoMakerFinalize) +# define RTFsIsoMakerCreateVfsOutputFile RT_MANGLER(RTFsIsoMakerCreateVfsOutputFile) +# define RTFsIsoMakerCmd RT_MANGLER(RTFsIsoMakerCmd) +# define RTFsIsoMakerCmdEx RT_MANGLER(RTFsIsoMakerCmdEx) +# define RTFsNtfsVolOpen RT_MANGLER(RTFsNtfsVolOpen) +# define RTFtpServerCreate RT_MANGLER(RTFtpServerCreate) +# define RTFtpServerDestroy RT_MANGLER(RTFtpServerDestroy) +# define RTFuzzCmdMaster RT_MANGLER(RTFuzzCmdMaster) +# define RTFuzzCfgCreateFromFile RT_MANGLER(RTFuzzCfgCreateFromFile) +# define RTFuzzCfgCreateFromVfsFile RT_MANGLER(RTFuzzCfgCreateFromVfsFile) +# define RTFuzzCfgRetain RT_MANGLER(RTFuzzCfgRetain) +# define RTFuzzCfgRelease RT_MANGLER(RTFuzzCfgRelease) +# define RTFuzzCfgImport RT_MANGLER(RTFuzzCfgImport) +# define RTFuzzCfgQueryCustomCfg RT_MANGLER(RTFuzzCfgQueryCustomCfg) +# define RTFuzzCtxCfgGetBehavioralFlags RT_MANGLER(RTFuzzCtxCfgGetBehavioralFlags) +# define RTFuzzCtxCfgGetInputSeedMaximum RT_MANGLER(RTFuzzCtxCfgGetInputSeedMaximum) +# define RTFuzzCtxCfgGetTmpDirectory RT_MANGLER(RTFuzzCtxCfgGetTmpDirectory) +# define RTFuzzCtxCfgSetBehavioralFlags RT_MANGLER(RTFuzzCtxCfgSetBehavioralFlags) +# define RTFuzzCtxCfgSetInputSeedMaximum RT_MANGLER(RTFuzzCtxCfgSetInputSeedMaximum) +# define RTFuzzCtxCfgSetMutationRange RT_MANGLER(RTFuzzCtxCfgSetMutationRange) +# define RTFuzzCtxCfgSetTmpDirectory RT_MANGLER(RTFuzzCtxCfgSetTmpDirectory) +# define RTFuzzCtxCorpusInputAdd RT_MANGLER(RTFuzzCtxCorpusInputAdd) +# define RTFuzzCtxCorpusInputAddEx RT_MANGLER(RTFuzzCtxCorpusInputAddEx) +# define RTFuzzCtxCorpusInputAddFromDirPath RT_MANGLER(RTFuzzCtxCorpusInputAddFromDirPath) +# define RTFuzzCtxCorpusInputAddFromFile RT_MANGLER(RTFuzzCtxCorpusInputAddFromFile) +# define RTFuzzCtxCorpusInputAddFromFileEx RT_MANGLER(RTFuzzCtxCorpusInputAddFromFileEx) +# define RTFuzzCtxCorpusInputAddFromVfsFile RT_MANGLER(RTFuzzCtxCorpusInputAddFromVfsFile) +# define RTFuzzCtxCorpusInputAddFromVfsFileEx RT_MANGLER(RTFuzzCtxCorpusInputAddFromVfsFileEx) +# define RTFuzzCtxCorpusInputAddFromVfsIoStrm RT_MANGLER(RTFuzzCtxCorpusInputAddFromVfsIoStrm) +# define RTFuzzCtxCorpusInputAddFromVfsIoStrmEx RT_MANGLER(RTFuzzCtxCorpusInputAddFromVfsIoStrmEx) +# define RTFuzzCtxCreate RT_MANGLER(RTFuzzCtxCreate) +# define RTFuzzCtxCreateFromState RT_MANGLER(RTFuzzCtxCreateFromState) +# define RTFuzzCtxCreateFromStateFile RT_MANGLER(RTFuzzCtxCreateFromStateFile) +# define RTFuzzCtxCreateFromStateMem RT_MANGLER(RTFuzzCtxCreateFromStateMem) +# define RTFuzzCtxInputGenerate RT_MANGLER(RTFuzzCtxInputGenerate) +# define RTFuzzCtxQueryStats RT_MANGLER(RTFuzzCtxQueryStats) +# define RTFuzzCtxRelease RT_MANGLER(RTFuzzCtxRelease) +# define RTFuzzCtxReseed RT_MANGLER(RTFuzzCtxReseed) +# define RTFuzzCtxRetain RT_MANGLER(RTFuzzCtxRetain) +# define RTFuzzCtxStateExport RT_MANGLER(RTFuzzCtxStateExport) +# define RTFuzzCtxStateExportToFile RT_MANGLER(RTFuzzCtxStateExportToFile) +# define RTFuzzCtxStateExportToMem RT_MANGLER(RTFuzzCtxStateExportToMem) +# define RTFuzzInputAddToCtxCorpus RT_MANGLER(RTFuzzInputAddToCtxCorpus) +# define RTFuzzInputMutateStreamData RT_MANGLER(RTFuzzInputMutateStreamData) +# define RTFuzzInputQueryBlobData RT_MANGLER(RTFuzzInputQueryBlobData) +# define RTFuzzInputQueryDigestString RT_MANGLER(RTFuzzInputQueryDigestString) +# define RTFuzzInputRelease RT_MANGLER(RTFuzzInputRelease) +# define RTFuzzInputRemoveFromCtxCorpus RT_MANGLER(RTFuzzInputRemoveFromCtxCorpus) +# define RTFuzzInputRetain RT_MANGLER(RTFuzzInputRetain) +# define RTFuzzInputWriteToFile RT_MANGLER(RTFuzzInputWriteToFile) +# define RTFuzzObsCreate RT_MANGLER(RTFuzzObsCreate) +# define RTFuzzObsDestroy RT_MANGLER(RTFuzzObsDestroy) +# define RTFuzzObsExecStart RT_MANGLER(RTFuzzObsExecStart) +# define RTFuzzObsExecStop RT_MANGLER(RTFuzzObsExecStop) +# define RTFuzzObsQueryCtx RT_MANGLER(RTFuzzObsQueryCtx) +# define RTFuzzObsQueryStats RT_MANGLER(RTFuzzObsQueryStats) +# define RTFuzzObsSetResultDirectory RT_MANGLER(RTFuzzObsSetResultDirectory) +# define RTFuzzObsSetTestBinary RT_MANGLER(RTFuzzObsSetTestBinary) +# define RTFuzzObsSetTestBinaryArgs RT_MANGLER(RTFuzzObsSetTestBinaryArgs) +# define RTFuzzObsSetTestBinaryEnv RT_MANGLER(RTFuzzObsSetTestBinaryEnv) +# define RTFuzzObsSetTestBinarySanitizers RT_MANGLER(RTFuzzObsSetTestBinarySanitizers) +# define RTFuzzObsSetTestBinaryTimeout RT_MANGLER(RTFuzzObsSetTestBinaryTimeout) +# define RTFuzzObsSetTmpDirectory RT_MANGLER(RTFuzzObsSetTmpDirectory) +# define RTFuzzTgtRecorderCreate RT_MANGLER(RTFuzzTgtRecorderCreate) +# define RTFuzzTgtRecorderCreateNewState RT_MANGLER(RTFuzzTgtRecorderCreateNewState) +# define RTFuzzTgtRecorderRelease RT_MANGLER(RTFuzzTgtRecorderRelease) +# define RTFuzzTgtRecorderRetain RT_MANGLER(RTFuzzTgtRecorderRetain) +# define RTFuzzTgtStateAddProcSts RT_MANGLER(RTFuzzTgtStateAddProcSts) +# define RTFuzzTgtStateAddSanCovReportFromFile RT_MANGLER(RTFuzzTgtStateAddSanCovReportFromFile) +# define RTFuzzTgtStateAddToRecorder RT_MANGLER(RTFuzzTgtStateAddToRecorder) +# define RTFuzzTgtStateAppendStderrFromBuf RT_MANGLER(RTFuzzTgtStateAppendStderrFromBuf) +# define RTFuzzTgtStateAppendStderrFromPipe RT_MANGLER(RTFuzzTgtStateAppendStderrFromPipe) +# define RTFuzzTgtStateAppendStdoutFromBuf RT_MANGLER(RTFuzzTgtStateAppendStdoutFromBuf) +# define RTFuzzTgtStateAppendStdoutFromPipe RT_MANGLER(RTFuzzTgtStateAppendStdoutFromPipe) +# define RTFuzzTgtStateDumpToDir RT_MANGLER(RTFuzzTgtStateDumpToDir) +# define RTFuzzTgtStateFinalize RT_MANGLER(RTFuzzTgtStateFinalize) +# define RTFuzzTgtStateRelease RT_MANGLER(RTFuzzTgtStateRelease) +# define RTFuzzTgtStateReset RT_MANGLER(RTFuzzTgtStateReset) +# define RTFuzzTgtStateRetain RT_MANGLER(RTFuzzTgtStateRetain) +# define RTGetOpt RT_MANGLER(RTGetOpt) +# define RTGetOptArgvFree RT_MANGLER(RTGetOptArgvFree) +# define RTGetOptArgvFreeEx RT_MANGLER(RTGetOptArgvFreeEx) +# define RTGetOptArgvFromString RT_MANGLER(RTGetOptArgvFromString) +# define RTGetOptArgvToString RT_MANGLER(RTGetOptArgvToString) +# define RTGetOptArgvToUtf16String RT_MANGLER(RTGetOptArgvToUtf16String) +# define RTGetOptFetchValue RT_MANGLER(RTGetOptFetchValue) +# define RTGetOptInit RT_MANGLER(RTGetOptInit) +# define RTGetOptNonOptionArrayPtr RT_MANGLER(RTGetOptNonOptionArrayPtr) +# define RTGetOptFormatError RT_MANGLER(RTGetOptFormatError) +# define RTGetOptPrintError RT_MANGLER(RTGetOptPrintError) +# define RTHandleClose RT_MANGLER(RTHandleClose) +# define RTHandleGetStandard RT_MANGLER(RTHandleGetStandard) +# define RTHandleTableAlloc RT_MANGLER(RTHandleTableAlloc) +# define RTHandleTableAllocWithCtx RT_MANGLER(RTHandleTableAllocWithCtx) +# define RTHandleTableCreate RT_MANGLER(RTHandleTableCreate) +# define RTHandleTableCreateEx RT_MANGLER(RTHandleTableCreateEx) +# define RTHandleTableDestroy RT_MANGLER(RTHandleTableDestroy) +# define RTHandleTableFree RT_MANGLER(RTHandleTableFree) +# define RTHandleTableFreeWithCtx RT_MANGLER(RTHandleTableFreeWithCtx) +# define RTHandleTableLookup RT_MANGLER(RTHandleTableLookup) +# define RTHandleTableLookupWithCtx RT_MANGLER(RTHandleTableLookupWithCtx) +# define RTHeapOffsetAlloc RT_MANGLER(RTHeapOffsetAlloc) +# define RTHeapOffsetAllocZ RT_MANGLER(RTHeapOffsetAllocZ) +# define RTHeapOffsetDump RT_MANGLER(RTHeapOffsetDump) +# define RTHeapOffsetFree RT_MANGLER(RTHeapOffsetFree) +# define RTHeapOffsetGetFreeSize RT_MANGLER(RTHeapOffsetGetFreeSize) +# define RTHeapOffsetGetHeapSize RT_MANGLER(RTHeapOffsetGetHeapSize) +# define RTHeapOffsetInit RT_MANGLER(RTHeapOffsetInit) +# define RTHeapOffsetSize RT_MANGLER(RTHeapOffsetSize) +# define RTHeapSimpleAlloc RT_MANGLER(RTHeapSimpleAlloc) +# define RTHeapSimpleAllocZ RT_MANGLER(RTHeapSimpleAllocZ) +# define RTHeapSimpleDump RT_MANGLER(RTHeapSimpleDump) +# define RTHeapSimpleFree RT_MANGLER(RTHeapSimpleFree) +# define RTHeapSimpleGetFreeSize RT_MANGLER(RTHeapSimpleGetFreeSize) +# define RTHeapSimpleGetHeapSize RT_MANGLER(RTHeapSimpleGetHeapSize) +# define RTHeapSimpleInit RT_MANGLER(RTHeapSimpleInit) +# define RTHeapSimpleRelocate RT_MANGLER(RTHeapSimpleRelocate) +# define RTHeapSimpleSize RT_MANGLER(RTHeapSimpleSize) +# define RTHttpGetFile RT_MANGLER(RTHttpGetFile) +# define RTHttpGetFollowRedirects RT_MANGLER(RTHttpGetFollowRedirects) +# define RTHttpSetFollowRedirects RT_MANGLER(RTHttpSetFollowRedirects) +# define RTHttpGetVerifyPeer RT_MANGLER(RTHttpGetVerifyPeer) +# define RTHttpHeaderListInit RT_MANGLER(RTHttpHeaderListInit) +# define RTHttpHeaderListDestroy RT_MANGLER(RTHttpHeaderListDestroy) +# define RTHttpHeaderListSet RT_MANGLER(RTHttpHeaderListSet) +# define RTHttpHeaderListAddRaw RT_MANGLER(RTHttpHeaderListAddRaw) +# define RTHttpHeaderListAdd RT_MANGLER(RTHttpHeaderListAdd) +# define RTHttpHeaderListGet RT_MANGLER(RTHttpHeaderListGet) +# define RTHttpHeaderListGetCount RT_MANGLER(RTHttpHeaderListGetCount) +# define RTHttpHeaderListGetByOrdinal RT_MANGLER(RTHttpHeaderListGetByOrdinal) +# define RTHttpMethodToStr RT_MANGLER(RTHttpMethodToStr) +# define RTHttpSetVerifyPeer RT_MANGLER(RTHttpSetVerifyPeer) +# define RTHttpUseSystemProxySettings RT_MANGLER(RTHttpUseSystemProxySettings) +# define RTHttpServerCreate RT_MANGLER(RTHttpServerCreate) +# define RTHttpServerDestroy RT_MANGLER(RTHttpServerDestroy) +# define RTHttpServerResponseInitEx RT_MANGLER(RTHttpServerResponseInitEx) +# define RTHttpServerResponseInit RT_MANGLER(RTHttpServerResponseInit) +# define RTHttpServerResponseDestroy RT_MANGLER(RTHttpServerResponseDestroy) +# define RTHttpStatusToStr RT_MANGLER(RTHttpStatusToStr) +# define RTIniFileCreateFromVfsFile RT_MANGLER(RTIniFileCreateFromVfsFile) +# define RTIniFileRetain RT_MANGLER(RTIniFileRetain) +# define RTIniFileRelease RT_MANGLER(RTIniFileRelease) +# define RTIniFileQueryPair RT_MANGLER(RTIniFileQueryPair) +# define RTIniFileQueryValue RT_MANGLER(RTIniFileQueryValue) +# define RTIoQueueCommit RT_MANGLER(RTIoQueueCommit) +# define RTIoQueueCreate RT_MANGLER(RTIoQueueCreate) +# define RTIoQueueDestroy RT_MANGLER(RTIoQueueDestroy) +# define RTIoQueueEvtWait RT_MANGLER(RTIoQueueEvtWait) +# define RTIoQueueEvtWaitWakeup RT_MANGLER(RTIoQueueEvtWaitWakeup) +# define RTIoQueueHandleDeregister RT_MANGLER(RTIoQueueHandleDeregister) +# define RTIoQueueHandleRegister RT_MANGLER(RTIoQueueHandleRegister) +# define RTIoQueueProviderGetBestForHndType RT_MANGLER(RTIoQueueProviderGetBestForHndType) +# define RTIoQueueProviderGetById RT_MANGLER(RTIoQueueProviderGetById) +# define RTIoQueueRequestPrepare RT_MANGLER(RTIoQueueRequestPrepare) +# define RTIoQueueRequestPrepareSg RT_MANGLER(RTIoQueueRequestPrepareSg) +# define RTJsonIteratorBegin RT_MANGLER(RTJsonIteratorBegin) +# define RTJsonIteratorBeginArray RT_MANGLER(RTJsonIteratorBeginArray) +# define RTJsonIteratorBeginObject RT_MANGLER(RTJsonIteratorBeginObject) +# define RTJsonIteratorFree RT_MANGLER(RTJsonIteratorFree) +# define RTJsonIteratorNext RT_MANGLER(RTJsonIteratorNext) +# define RTJsonIteratorQueryValue RT_MANGLER(RTJsonIteratorQueryValue) +# define RTJsonParseFromBuf RT_MANGLER(RTJsonParseFromBuf) +# define RTJsonParseFromFile RT_MANGLER(RTJsonParseFromFile) +# define RTJsonParseFromString RT_MANGLER(RTJsonParseFromString) +# define RTJsonParseFromVfsFile RT_MANGLER(RTJsonParseFromVfsFile) +# define RTJsonValueGetArraySize RT_MANGLER(RTJsonValueGetArraySize) +# define RTJsonValueGetString RT_MANGLER(RTJsonValueGetString) +# define RTJsonValueGetType RT_MANGLER(RTJsonValueGetType) +# define RTJsonValueQueryArraySizeEx RT_MANGLER(RTJsonValueQueryArraySize) +# define RTJsonValueQueryBooleanByName RT_MANGLER(RTJsonValueQueryBooleanByName) +# define RTJsonValueQueryByIndex RT_MANGLER(RTJsonValueQueryByIndex) +# define RTJsonValueQueryByName RT_MANGLER(RTJsonValueQueryByName) +# define RTJsonValueQueryInteger RT_MANGLER(RTJsonValueQueryInteger) +# define RTJsonValueQueryIntegerByName RT_MANGLER(RTJsonValueQueryIntegerByName) +# define RTJsonValueQueryNumber RT_MANGLER(RTJsonValueQueryNumber) +# define RTJsonValueQueryNumberByName RT_MANGLER(RTJsonValueQueryNumberByName) +# define RTJsonValueQueryString RT_MANGLER(RTJsonValueQueryString) +# define RTJsonValueQueryStringByName RT_MANGLER(RTJsonValueQueryStringByName) +# define RTJsonValueRelease RT_MANGLER(RTJsonValueRelease) +# define RTJsonValueRetain RT_MANGLER(RTJsonValueRetain) +# define RTJsonValueTypeName RT_MANGLER(RTJsonValueTypeName) +# define RTKrnlModInfoGetFilePath RT_MANGLER(RTKrnlModInfoGetFilePath) +# define RTKrnlModInfoGetLoadAddr RT_MANGLER(RTKrnlModInfoGetLoadAddr) +# define RTKrnlModInfoGetName RT_MANGLER(RTKrnlModInfoGetName) +# define RTKrnlModInfoGetRefCnt RT_MANGLER(RTKrnlModInfoGetRefCnt) +# define RTKrnlModInfoGetSize RT_MANGLER(RTKrnlModInfoGetSize) +# define RTKrnlModInfoQueryRefModInfo RT_MANGLER(RTKrnlModInfoQueryRefModInfo) +# define RTKrnlModInfoRetain RT_MANGLER(RTKrnlModInfoRetain) +# define RTKrnlModInfoRelease RT_MANGLER(RTKrnlModInfoRelease) +# define RTKrnlModLoadByName RT_MANGLER(RTKrnlModLoadByName) +# define RTKrnlModLoadByPath RT_MANGLER(RTKrnlModLoadByPath) +# define RTKrnlModLoadedGetCount RT_MANGLER(RTKrnlModLoadedGetCount) +# define RTKrnlModLoadedQueryInfo RT_MANGLER(RTKrnlModLoadedQueryInfo) +# define RTKrnlModLoadedQueryInfoAll RT_MANGLER(RTKrnlModLoadedQueryInfoAll) +# define RTKrnlModQueryLoaded RT_MANGLER(RTKrnlModQueryLoaded) +# define RTKrnlModUnloadByName RT_MANGLER(RTKrnlModUnloadByName) +# define RTLatin1CalcUtf16Len RT_MANGLER(RTLatin1CalcUtf16Len) +# define RTLatin1CalcUtf16LenEx RT_MANGLER(RTLatin1CalcUtf16LenEx) +# define RTLatin1CalcUtf8Len RT_MANGLER(RTLatin1CalcUtf8Len) +# define RTLatin1CalcUtf8LenEx RT_MANGLER(RTLatin1CalcUtf8LenEx) +# define RTLatin1ToUtf16ExTag RT_MANGLER(RTLatin1ToUtf16ExTag) +# define RTLatin1ToUtf16Tag RT_MANGLER(RTLatin1ToUtf16Tag) +# define RTLatin1ToUtf8ExTag RT_MANGLER(RTLatin1ToUtf8ExTag) +# define RTLatin1ToUtf8Tag RT_MANGLER(RTLatin1ToUtf8Tag) +# define RTLdrArchName RT_MANGLER(RTLdrArchName) +# define RTLdrClose RT_MANGLER(RTLdrClose) +# define RTLdrEnumDbgInfo RT_MANGLER(RTLdrEnumDbgInfo) +# define RTLdrEnumSegments RT_MANGLER(RTLdrEnumSegments) +# define RTLdrEnumSymbols RT_MANGLER(RTLdrEnumSymbols) +# define RTLdrGetArch RT_MANGLER(RTLdrGetArch) +# define RTLdrGetBits RT_MANGLER(RTLdrGetBits) +# define RTLdrGetEndian RT_MANGLER(RTLdrGetEndian) +# define RTLdrGetFormat RT_MANGLER(RTLdrGetFormat) +# define RTLdrGetFunction RT_MANGLER(RTLdrGetFunction) +# define RTLdrGetHostArch RT_MANGLER(RTLdrGetHostArch) +# define RTLdrGetNativeHandle RT_MANGLER(RTLdrGetNativeHandle) +# define RTLdrGetSuff RT_MANGLER(RTLdrGetSuff) +# define RTLdrGetSymbol RT_MANGLER(RTLdrGetSymbol) +# define RTLdrGetSymbolEx RT_MANGLER(RTLdrGetSymbolEx) +# define RTLdrGetSystemSymbol RT_MANGLER(RTLdrGetSystemSymbol) +# define RTLdrGetSystemSymbolEx RT_MANGLER(RTLdrGetSystemSymbolEx) +# define RTLdrGetType RT_MANGLER(RTLdrGetType) +# define RTLdrIsLoadable RT_MANGLER(RTLdrIsLoadable) +# define RTLdrLinkAddressToRva RT_MANGLER(RTLdrLinkAddressToRva) +# define RTLdrLinkAddressToSegOffset RT_MANGLER(RTLdrLinkAddressToSegOffset) +# define RTLdrLoad RT_MANGLER(RTLdrLoad) +# define RTLdrLoadAppPriv RT_MANGLER(RTLdrLoadAppPriv) +# define RTLdrLoadEx RT_MANGLER(RTLdrLoadEx) +# define RTLdrLoadSystem RT_MANGLER(RTLdrLoadSystem) +# define RTLdrLoadSystemEx RT_MANGLER(RTLdrLoadSystemEx) +# define RTLdrOpen RT_MANGLER(RTLdrOpen) +# define RTLdrOpenEx RT_MANGLER(RTLdrOpenEx) +# define RTLdrOpenInMemory RT_MANGLER(RTLdrOpenInMemory) +# define RTLdrOpenVfsChain RT_MANGLER(RTLdrOpenVfsChain) +# define RTLdrRelocate RT_MANGLER(RTLdrRelocate) +# define RTLdrRvaToSegOffset RT_MANGLER(RTLdrRvaToSegOffset) +# define RTLdrQueryForwarderInfo RT_MANGLER(RTLdrQueryForwarderInfo) +# define RTLdrQueryProp RT_MANGLER(RTLdrQueryProp) +# define RTLdrSegOffsetToRva RT_MANGLER(RTLdrSegOffsetToRva) +# define RTLdrSize RT_MANGLER(RTLdrSize) +# define RTLdrUnwindFrame RT_MANGLER(RTLdrUnwindFrame) +# define RTLinuxCheckDevicePath RT_MANGLER(RTLinuxCheckDevicePath) +# define RTLinuxCheckDevicePathV RT_MANGLER(RTLinuxCheckDevicePathV) +# define RTLinuxConstructPath RT_MANGLER(RTLinuxConstructPath) +# define RTLinuxConstructPathV RT_MANGLER(RTLinuxConstructPathV) +# define RTLinuxSysFsClose RT_MANGLER(RTLinuxSysFsClose) +# define RTLinuxSysFsExists RT_MANGLER(RTLinuxSysFsExists) +# define RTLinuxSysFsExistsEx RT_MANGLER(RTLinuxSysFsExistsEx) +# define RTLinuxSysFsExistsExV RT_MANGLER(RTLinuxSysFsExistsExV) +# define RTLinuxSysFsExistsV RT_MANGLER(RTLinuxSysFsExistsV) +# define RTLinuxSysFsGetLinkDest RT_MANGLER(RTLinuxSysFsGetLinkDest) +# define RTLinuxSysFsGetLinkDestV RT_MANGLER(RTLinuxSysFsGetLinkDestV) +# define RTLinuxSysFsOpen RT_MANGLER(RTLinuxSysFsOpen) +# define RTLinuxSysFsOpenEx RT_MANGLER(RTLinuxSysFsOpenEx) +# define RTLinuxSysFsOpenExV RT_MANGLER(RTLinuxSysFsOpenExV) +# define RTLinuxSysFsOpenV RT_MANGLER(RTLinuxSysFsOpenV) +# define RTLinuxSysFsReadDevNumFile RT_MANGLER(RTLinuxSysFsReadDevNumFile) +# define RTLinuxSysFsReadDevNumFileV RT_MANGLER(RTLinuxSysFsReadDevNumFileV) +# define RTLinuxSysFsReadFile RT_MANGLER(RTLinuxSysFsReadFile) +# define RTLinuxSysFsReadIntFile RT_MANGLER(RTLinuxSysFsReadIntFile) +# define RTLinuxSysFsReadIntFileV RT_MANGLER(RTLinuxSysFsReadIntFileV) +# define RTLinuxSysFsReadStr RT_MANGLER(RTLinuxSysFsReadStr) +# define RTLinuxSysFsReadStrFile RT_MANGLER(RTLinuxSysFsReadStrFile) +# define RTLinuxSysFsReadStrFileV RT_MANGLER(RTLinuxSysFsReadStrFileV) +# define RTLinuxSysFsWriteFile RT_MANGLER(RTLinuxSysFsWriteFile) +# define RTLinuxSysFsWriteStr RT_MANGLER(RTLinuxSysFsWriteStr) +# define RTLinuxSysFsWriteStrFile RT_MANGLER(RTLinuxSysFsWriteStrFile) +# define RTLinuxSysFsWriteStrFileV RT_MANGLER(RTLinuxSysFsWriteStrFileV) +# define RTLinuxSysFsWriteU8File RT_MANGLER(RTLinuxSysFsWriteU8File) +# define RTLinuxSysFsWriteU8FileV RT_MANGLER(RTLinuxSysFsWriteU8FileV) +# define RTLinuxSysFsWriteU16File RT_MANGLER(RTLinuxSysFsWriteU16File) +# define RTLinuxSysFsWriteU16FileV RT_MANGLER(RTLinuxSysFsWriteU16FileV) +# define RTLinuxSysFsWriteU32File RT_MANGLER(RTLinuxSysFsWriteU32File) +# define RTLinuxSysFsWriteU32FileV RT_MANGLER(RTLinuxSysFsWriteU32FileV) +# define RTLinuxSysFsWriteU64File RT_MANGLER(RTLinuxSysFsWriteU64File) +# define RTLinuxSysFsWriteU64FileV RT_MANGLER(RTLinuxSysFsWriteU64FileV) +# define RTLocalIpcServerCreate RT_MANGLER(RTLocalIpcServerCreate) +# define RTLocalIpcServerDestroy RT_MANGLER(RTLocalIpcServerDestroy) +# define RTLocalIpcServerGrantGroupAccess RT_MANGLER(RTLocalIpcServerGrantGroupAccess) +# define RTLocalIpcServerSetAccessMode RT_MANGLER(RTLocalIpcServerSetAccessMode); +# define RTLocalIpcServerCancel RT_MANGLER(RTLocalIpcServerCancel) +# define RTLocalIpcServerListen RT_MANGLER(RTLocalIpcServerListen) +# define RTLocalIpcSessionConnect RT_MANGLER(RTLocalIpcSessionConnect) +# define RTLocalIpcSessionClose RT_MANGLER(RTLocalIpcSessionClose) +# define RTLocalIpcSessionCancel RT_MANGLER(RTLocalIpcSessionCancel) +# define RTLocalIpcSessionRead RT_MANGLER(RTLocalIpcSessionRead) +# define RTLocalIpcSessionReadNB RT_MANGLER(RTLocalIpcSessionReadNB) +# define RTLocalIpcSessionRetain RT_MANGLER(RTLocalIpcSessionRetain) +# define RTLocalIpcSessionRelease RT_MANGLER(RTLocalIpcSessionRelease) +# define RTLocalIpcSessionWrite RT_MANGLER(RTLocalIpcSessionWrite) +# define RTLocalIpcSessionFlush RT_MANGLER(RTLocalIpcSessionFlush) +# define RTLocalIpcSessionWaitForData RT_MANGLER(RTLocalIpcSessionWaitForData) +# define RTLocalIpcSessionQueryProcess RT_MANGLER(RTLocalIpcSessionQueryProcess) +# define RTLocalIpcSessionQueryUserId RT_MANGLER(RTLocalIpcSessionQueryUserId) +# define RTLocalIpcSessionQueryGroupId RT_MANGLER(RTLocalIpcSessionQueryGroupId) +# define RTLocaleQueryLocaleName RT_MANGLER(RTLocaleQueryLocaleName) +# define RTLocaleQueryNormalizedBaseLocaleName RT_MANGLER(RTLocaleQueryNormalizedBaseLocaleName) +# define RTLocaleQueryUserCountryCode RT_MANGLER(RTLocaleQueryUserCountryCode) +# define RTLockValidatorClassAddPriorClass RT_MANGLER(RTLockValidatorClassAddPriorClass) +# define RTLockValidatorClassCreate RT_MANGLER(RTLockValidatorClassCreate) +# define RTLockValidatorClassCreateEx RT_MANGLER(RTLockValidatorClassCreateEx) +# define RTLockValidatorClassCreateExV RT_MANGLER(RTLockValidatorClassCreateExV) +# define RTLockValidatorClassCreateUnique RT_MANGLER(RTLockValidatorClassCreateUnique) +# define RTLockValidatorClassEnforceStrictReleaseOrder RT_MANGLER(RTLockValidatorClassEnforceStrictReleaseOrder) +# define RTLockValidatorClassFindForSrcPos RT_MANGLER(RTLockValidatorClassFindForSrcPos) +# define RTLockValidatorClassForSrcPos RT_MANGLER(RTLockValidatorClassForSrcPos) +# define RTLockValidatorClassRelease RT_MANGLER(RTLockValidatorClassRelease) +# define RTLockValidatorClassRetain RT_MANGLER(RTLockValidatorClassRetain) +# define RTLockValidatorHoldsLocksInClass RT_MANGLER(RTLockValidatorHoldsLocksInClass) +# define RTLockValidatorHoldsLocksInSubClass RT_MANGLER(RTLockValidatorHoldsLocksInSubClass) +# define RTLockValidatorIsBlockedThreadInValidator RT_MANGLER(RTLockValidatorIsBlockedThreadInValidator) +# define RTLockValidatorIsEnabled RT_MANGLER(RTLockValidatorIsEnabled) +# define RTLockValidatorIsQuiet RT_MANGLER(RTLockValidatorIsQuiet) +# define RTLockValidatorMayPanic RT_MANGLER(RTLockValidatorMayPanic) +# define RTLockValidatorQueryBlocking RT_MANGLER(RTLockValidatorQueryBlocking) +# define RTLockValidatorReadLockDec RT_MANGLER(RTLockValidatorReadLockDec) +# define RTLockValidatorReadLockGetCount RT_MANGLER(RTLockValidatorReadLockGetCount) +# define RTLockValidatorReadLockInc RT_MANGLER(RTLockValidatorReadLockInc) +# define RTLockValidatorRecExclCheckBlocking RT_MANGLER(RTLockValidatorRecExclCheckBlocking) +# define RTLockValidatorRecExclCheckOrder RT_MANGLER(RTLockValidatorRecExclCheckOrder) +# define RTLockValidatorRecExclCheckOrderAndBlocking RT_MANGLER(RTLockValidatorRecExclCheckOrderAndBlocking) +# define RTLockValidatorRecExclCreate RT_MANGLER(RTLockValidatorRecExclCreate) +# define RTLockValidatorRecExclCreateV RT_MANGLER(RTLockValidatorRecExclCreateV) +# define RTLockValidatorRecExclDelete RT_MANGLER(RTLockValidatorRecExclDelete) +# define RTLockValidatorRecExclDestroy RT_MANGLER(RTLockValidatorRecExclDestroy) +# define RTLockValidatorRecExclInit RT_MANGLER(RTLockValidatorRecExclInit) +# define RTLockValidatorRecExclInitV RT_MANGLER(RTLockValidatorRecExclInitV) +# define RTLockValidatorRecExclRecursion RT_MANGLER(RTLockValidatorRecExclRecursion) +# define RTLockValidatorRecExclRecursionMixed RT_MANGLER(RTLockValidatorRecExclRecursionMixed) +# define RTLockValidatorRecExclReleaseOwner RT_MANGLER(RTLockValidatorRecExclReleaseOwner) +# define RTLockValidatorRecExclReleaseOwnerUnchecked RT_MANGLER(RTLockValidatorRecExclReleaseOwnerUnchecked) +# define RTLockValidatorRecExclSetOwner RT_MANGLER(RTLockValidatorRecExclSetOwner) +# define RTLockValidatorRecExclSetSubClass RT_MANGLER(RTLockValidatorRecExclSetSubClass) +# define RTLockValidatorRecExclUnwind RT_MANGLER(RTLockValidatorRecExclUnwind) +# define RTLockValidatorRecExclUnwindMixed RT_MANGLER(RTLockValidatorRecExclUnwindMixed) +# define RTLockValidatorRecMakeSiblings RT_MANGLER(RTLockValidatorRecMakeSiblings) +# define RTLockValidatorRecSharedAddOwner RT_MANGLER(RTLockValidatorRecSharedAddOwner) +# define RTLockValidatorRecSharedCheckAndRelease RT_MANGLER(RTLockValidatorRecSharedCheckAndRelease) +# define RTLockValidatorRecSharedCheckBlocking RT_MANGLER(RTLockValidatorRecSharedCheckBlocking) +# define RTLockValidatorRecSharedCheckOrder RT_MANGLER(RTLockValidatorRecSharedCheckOrder) +# define RTLockValidatorRecSharedCheckOrderAndBlocking RT_MANGLER(RTLockValidatorRecSharedCheckOrderAndBlocking) +# define RTLockValidatorRecSharedCheckSignaller RT_MANGLER(RTLockValidatorRecSharedCheckSignaller) +# define RTLockValidatorRecSharedCreate RT_MANGLER(RTLockValidatorRecSharedCreate) +# define RTLockValidatorRecSharedCreateV RT_MANGLER(RTLockValidatorRecSharedCreateV) +# define RTLockValidatorRecSharedDelete RT_MANGLER(RTLockValidatorRecSharedDelete) +# define RTLockValidatorRecSharedDestroy RT_MANGLER(RTLockValidatorRecSharedDestroy) +# define RTLockValidatorRecSharedInit RT_MANGLER(RTLockValidatorRecSharedInit) +# define RTLockValidatorRecSharedInitV RT_MANGLER(RTLockValidatorRecSharedInitV) +# define RTLockValidatorRecSharedIsOwner RT_MANGLER(RTLockValidatorRecSharedIsOwner) +# define RTLockValidatorRecSharedRemoveOwner RT_MANGLER(RTLockValidatorRecSharedRemoveOwner) +# define RTLockValidatorRecSharedResetOwner RT_MANGLER(RTLockValidatorRecSharedResetOwner) +# define RTLockValidatorRecSharedSetSubClass RT_MANGLER(RTLockValidatorRecSharedSetSubClass) +# define RTLockValidatorSetEnabled RT_MANGLER(RTLockValidatorSetEnabled) +# define RTLockValidatorSetMayPanic RT_MANGLER(RTLockValidatorSetMayPanic) +# define RTLockValidatorSetQuiet RT_MANGLER(RTLockValidatorSetQuiet) +# define RTLockValidatorWriteLockDec RT_MANGLER(RTLockValidatorWriteLockDec) +# define RTLockValidatorWriteLockGetCount RT_MANGLER(RTLockValidatorWriteLockGetCount) +# define RTLockValidatorWriteLockInc RT_MANGLER(RTLockValidatorWriteLockInc) +# define RTLogAssert RT_MANGLER(RTLogAssert) +# define RTLogAssertV RT_MANGLER(RTLogAssertV) +# define RTLogBackdoorPrintf RT_MANGLER(RTLogBackdoorPrintf) /* r0drv-guest */ +# define RTLogBackdoorPrintfV RT_MANGLER(RTLogBackdoorPrintfV) /* r0drv-guest */ +# define RTLogBulkUpdate RT_MANGLER(RTLogBulkUpdate) +# define RTLogBulkWrite RT_MANGLER(RTLogBulkWrite) +# define RTLogBulkNestedWrite RT_MANGLER(RTLogBulkNestedWrite) +# define RTLogChangeDestinations RT_MANGLER(RTLogChangeDestinations) +# define RTLogChangeFlags RT_MANGLER(RTLogChangeFlags) +# define RTLogCheckGroupFlags RT_MANGLER(RTLogCheckGroupFlags) +# define RTLogClearFileDelayFlag RT_MANGLER(RTLogClearFileDelayFlag) +# define RTLogCloneRC RT_MANGLER(RTLogCloneRC) +# define RTLogComPrintf RT_MANGLER(RTLogComPrintf) +# define RTLogComPrintfV RT_MANGLER(RTLogComPrintfV) +# define RTLogCreate RT_MANGLER(RTLogCreate) +# define RTLogCreateEx RT_MANGLER(RTLogCreateEx) +# define RTLogCreateExV RT_MANGLER(RTLogCreateExV) +# define RTLogDefaultInit RT_MANGLER(RTLogDefaultInit) +# define RTLogDefaultInstance RT_MANGLER(RTLogDefaultInstance) +# define RTLogDefaultInstanceEx RT_MANGLER(RTLogDefaultInstanceEx) +# define RTLogDestinations RT_MANGLER(RTLogDestinations) +# define RTLogDestroy RT_MANGLER(RTLogDestroy) +# define RTLogFlags RT_MANGLER(RTLogFlags) +# define RTLogFlush RT_MANGLER(RTLogFlush) +# define RTLogFormatV RT_MANGLER(RTLogFormatV) +# define RTLogGetDefaultInstance RT_MANGLER(RTLogGetDefaultInstance) +# define RTLogGetDefaultInstanceEx RT_MANGLER(RTLogGetDefaultInstanceEx) +# define RTLogGetDestinations RT_MANGLER(RTLogGetDestinations) +# define RTLogGetFlags RT_MANGLER(RTLogGetFlags) +# define RTLogGroupSettings RT_MANGLER(RTLogGroupSettings) +# define RTLogLogger RT_MANGLER(RTLogLogger) +# define RTLogLoggerWeak RT_MANGLER(RTLogLoggerWeak) +# define RTLogLoggerEx RT_MANGLER(RTLogLoggerEx) +# define RTLogLoggerExWeak RT_MANGLER(RTLogLoggerExWeak) +# define RTLogLoggerExV RT_MANGLER(RTLogLoggerExV) +# define RTLogLoggerV RT_MANGLER(RTLogLoggerV) +# define RTLogPrintf RT_MANGLER(RTLogPrintf) +# define RTLogPrintfV RT_MANGLER(RTLogPrintfV) +# define RTLogDumpPrintfV RT_MANGLER(RTLogDumpPrintfV) +# define RTLogQueryBulk RT_MANGLER(RTLogQueryBulk) +# define RTLogQueryDestinations RT_MANGLER(RTLogQueryDestinations) +# define RTLogQueryFlags RT_MANGLER(RTLogQueryFlags) +# define RTLogQueryGroupSettings RT_MANGLER(RTLogQueryGroupSettings) +# define RTLogRelGetDefaultInstance RT_MANGLER(RTLogRelGetDefaultInstance) +# define RTLogRelGetDefaultInstanceEx RT_MANGLER(RTLogRelGetDefaultInstanceEx) +# define RTLogRelLogger RT_MANGLER(RTLogRelLogger) +# define RTLogRelLoggerV RT_MANGLER(RTLogRelLoggerV) +# define RTLogRelPrintf RT_MANGLER(RTLogRelPrintf) +# define RTLogRelPrintfV RT_MANGLER(RTLogRelPrintfV) +# define RTLogRelSetBuffering RT_MANGLER(RTLogRelSetBuffering) +# define RTLogRelSetDefaultInstance RT_MANGLER(RTLogRelSetDefaultInstance) +# define RTLogSetBuffering RT_MANGLER(RTLogSetBuffering) +# define RTLogSetCustomPrefixCallback RT_MANGLER(RTLogSetCustomPrefixCallback) +# define RTLogSetFlushCallback RT_MANGLER(RTLogSetFlushCallback) +# define RTLogSetDefaultInstance RT_MANGLER(RTLogSetDefaultInstance) +# define RTLogSetDefaultInstanceThread RT_MANGLER(RTLogSetDefaultInstanceThread) /* r0drv */ +# define RTLogSetGroupLimit RT_MANGLER(RTLogSetGroupLimit) +# define RTLogSetR0ProgramStart RT_MANGLER(RTLogSetR0ProgramStart) /* r0drv */ +# define RTLogSetR0ThreadNameF RT_MANGLER(RTLogSetR0ThreadNameF) /* r0drv */ +# define RTLogSetR0ThreadNameV RT_MANGLER(RTLogSetR0ThreadNameV) /* r0drv */ +# define RTLogWriteCom RT_MANGLER(RTLogWriteCom) +# define RTLogWriteDebugger RT_MANGLER(RTLogWriteDebugger) +# define RTLogWriteStdErr RT_MANGLER(RTLogWriteStdErr) +# define RTLogWriteStdOut RT_MANGLER(RTLogWriteStdOut) +# define RTLogWriteUser RT_MANGLER(RTLogWriteUser) +# define RTLogWriteVmm RT_MANGLER(RTLogWriteVmm) +# define RTLogWriteVmm_EndProc RT_MANGLER(RTLogWriteVmm_EndProc) +# define RTManifestCreate RT_MANGLER(RTManifestCreate) +# define RTManifestDup RT_MANGLER(RTManifestDup) +# define RTManifestEntryAdd RT_MANGLER(RTManifestEntryAdd) +# define RTManifestEntryAddIoStream RT_MANGLER(RTManifestEntryAddIoStream) +# define RTManifestEntryAddPassthruIoStream RT_MANGLER(RTManifestEntryAddPassthruIoStream) +# define RTManifestEntryExists RT_MANGLER(RTManifestEntryExists) +# define RTManifestEntryRemove RT_MANGLER(RTManifestEntryRemove) +# define RTManifestEntryQueryAttr RT_MANGLER(RTManifestEntryQueryAttr) +# define RTManifestEntrySetAttr RT_MANGLER(RTManifestEntrySetAttr) +# define RTManifestEntryUnsetAttr RT_MANGLER(RTManifestEntryUnsetAttr) +# define RTManifestEquals RT_MANGLER(RTManifestEquals) +# define RTManifestEqualsEx RT_MANGLER(RTManifestEqualsEx) +# define RTManifestPtIosAddEntryNow RT_MANGLER(RTManifestPtIosAddEntryNow) +# define RTManifestPtIosIsInstanceOf RT_MANGLER(RTManifestPtIosIsInstanceOf) +# define RTManifestQueryAllAttrTypes RT_MANGLER(RTManifestQueryAllAttrTypes) +# define RTManifestQueryAttr RT_MANGLER(RTManifestQueryAttr) +# define RTManifestReadStandard RT_MANGLER(RTManifestReadStandard) +# define RTManifestReadStandardEx RT_MANGLER(RTManifestReadStandardEx) +# define RTManifestReadStandardFromFile RT_MANGLER(RTManifestReadStandardFromFile) +# define RTManifestRelease RT_MANGLER(RTManifestRelease) +# define RTManifestRetain RT_MANGLER(RTManifestRetain) +# define RTManifestSetAttr RT_MANGLER(RTManifestSetAttr) +# define RTManifestUnsetAttr RT_MANGLER(RTManifestUnsetAttr) +# define RTManifestVerify RT_MANGLER(RTManifestVerify) +# define RTManifestVerifyDigestType RT_MANGLER(RTManifestVerifyDigestType) +# define RTManifestVerifyFiles RT_MANGLER(RTManifestVerifyFiles) +# define RTManifestVerifyFilesBuf RT_MANGLER(RTManifestVerifyFilesBuf) +# define RTManifestWriteFiles RT_MANGLER(RTManifestWriteFiles) +# define RTManifestWriteFilesBuf RT_MANGLER(RTManifestWriteFilesBuf) +# define RTManifestWriteStandard RT_MANGLER(RTManifestWriteStandard) +# define RTManifestWriteStandardToFile RT_MANGLER(RTManifestWriteStandardToFile) +# define RTMd4 RT_MANGLER(RTMd4) +# define RTMd4Final RT_MANGLER(RTMd4Final) +# define RTMd4FromString RT_MANGLER(RTMd4FromString) +# define RTMd4Init RT_MANGLER(RTMd4Init) +# define RTMd4ToString RT_MANGLER(RTMd4ToString) +# define RTMd4Update RT_MANGLER(RTMd4Update) +# define RTMd5 RT_MANGLER(RTMd5) +# define RTMd5Final RT_MANGLER(RTMd5Final) +# define RTMd5FromString RT_MANGLER(RTMd5FromString) +# define RTMd5Init RT_MANGLER(RTMd5Init) +# define RTMd5ToString RT_MANGLER(RTMd5ToString) +# define RTMd5Update RT_MANGLER(RTMd5Update) +# define RTMemAllocExTag RT_MANGLER(RTMemAllocExTag) +# define RTMemAllocTag RT_MANGLER(RTMemAllocTag) +# define RTMemAllocVarTag RT_MANGLER(RTMemAllocVarTag) +# define RTMemAllocZTag RT_MANGLER(RTMemAllocZTag) +# define RTMemAllocZVarTag RT_MANGLER(RTMemAllocZVarTag) +# define RTMemCacheAlloc RT_MANGLER(RTMemCacheAlloc) +# define RTMemCacheAllocEx RT_MANGLER(RTMemCacheAllocEx) +# define RTMemCacheCreate RT_MANGLER(RTMemCacheCreate) +# define RTMemCacheDestroy RT_MANGLER(RTMemCacheDestroy) +# define RTMemCacheFree RT_MANGLER(RTMemCacheFree) +# define RTMemContAlloc RT_MANGLER(RTMemContAlloc) /* r0drv */ +# define RTMemContFree RT_MANGLER(RTMemContFree) /* r0drv */ +# define RTMemDump RT_MANGLER(RTMemDump) +# define RTMemDumpFreed RT_MANGLER(RTMemDumpFreed) +# define RTMemDupExTag RT_MANGLER(RTMemDupExTag) +# define RTMemDupTag RT_MANGLER(RTMemDupTag) +# define RTMemEfAlloc RT_MANGLER(RTMemEfAlloc) +# define RTMemEfAllocNP RT_MANGLER(RTMemEfAllocNP) +# define RTMemEfAllocVar RT_MANGLER(RTMemEfAllocVar) +# define RTMemEfAllocVarNP RT_MANGLER(RTMemEfAllocVarNP) +# define RTMemEfAllocZ RT_MANGLER(RTMemEfAllocZ) +# define RTMemEfAllocZNP RT_MANGLER(RTMemEfAllocZNP) +# define RTMemEfAllocZVar RT_MANGLER(RTMemEfAllocZVar) +# define RTMemEfAllocZVarNP RT_MANGLER(RTMemEfAllocZVarNP) +# define RTMemEfDup RT_MANGLER(RTMemEfDup) +# define RTMemEfDupEx RT_MANGLER(RTMemEfDupEx) +# define RTMemEfDupExNP RT_MANGLER(RTMemEfDupExNP) +# define RTMemEfDupNP RT_MANGLER(RTMemEfDupNP) +# define RTMemEfFree RT_MANGLER(RTMemEfFree) +# define RTMemEfFreeNP RT_MANGLER(RTMemEfFreeNP) +# define RTMemEfFreeZ RT_MANGLER(RTMemEfFreeZ) +# define RTMemEfFreeZNP RT_MANGLER(RTMemEfFreeZNP) +# define RTMemEfRealloc RT_MANGLER(RTMemEfRealloc) +# define RTMemEfReallocNP RT_MANGLER(RTMemEfReallocNP) +# define RTMemEfReallocZ RT_MANGLER(RTMemEfReallocZ) +# define RTMemEfReallocZNP RT_MANGLER(RTMemEfReallocZNP) +# define RTMemEfTmpAlloc RT_MANGLER(RTMemEfTmpAlloc) +# define RTMemEfTmpAllocNP RT_MANGLER(RTMemEfTmpAllocNP) +# define RTMemEfTmpAllocZ RT_MANGLER(RTMemEfTmpAllocZ) +# define RTMemEfTmpAllocZNP RT_MANGLER(RTMemEfTmpAllocZNP) +# define RTMemEfTmpFree RT_MANGLER(RTMemEfTmpFree) +# define RTMemEfTmpFreeNP RT_MANGLER(RTMemEfTmpFreeNP) +# define RTMemEfTmpFreeZ RT_MANGLER(RTMemEfTmpFreeZ) +# define RTMemEfTmpFreeZNP RT_MANGLER(RTMemEfTmpFreeZNP) +# define RTMemFree RT_MANGLER(RTMemFree) +# define RTMemFreeZ RT_MANGLER(RTMemFreeZ) +# define RTMemFreeEx RT_MANGLER(RTMemFreeEx) +# define RTMemPageAllocTag RT_MANGLER(RTMemPageAllocTag) +# define RTMemPageAllocExTag RT_MANGLER(RTMemPageAllocExTag) +# define RTMemPageAllocZTag RT_MANGLER(RTMemPageAllocZTag) +# define RTMemPageFree RT_MANGLER(RTMemPageFree) +# define RTMemPoolAlloc RT_MANGLER(RTMemPoolAlloc) +# define RTMemPoolAllocZ RT_MANGLER(RTMemPoolAllocZ) +# define RTMemPoolCreate RT_MANGLER(RTMemPoolCreate) +# define RTMemPoolDestroy RT_MANGLER(RTMemPoolDestroy) +# define RTMemPoolDup RT_MANGLER(RTMemPoolDup) +# define RTMemPoolDupEx RT_MANGLER(RTMemPoolDupEx) +# define RTMemPoolFree RT_MANGLER(RTMemPoolFree) +# define RTMemPoolRealloc RT_MANGLER(RTMemPoolRealloc) +# define RTMemPoolRefCount RT_MANGLER(RTMemPoolRefCount) +# define RTMemPoolRelease RT_MANGLER(RTMemPoolRelease) +# define RTMemPoolRetain RT_MANGLER(RTMemPoolRetain) +# define RTMemProtect RT_MANGLER(RTMemProtect) +# define RTMemReallocTag RT_MANGLER(RTMemReallocTag) +# define RTMemReallocZTag RT_MANGLER(RTMemReallocZTag) +# define RTMemTmpAllocTag RT_MANGLER(RTMemTmpAllocTag) +# define RTMemTmpAllocZTag RT_MANGLER(RTMemTmpAllocZTag) +# define RTMemTmpFree RT_MANGLER(RTMemTmpFree) +# define RTMemTmpFreeZ RT_MANGLER(RTMemTmpFreeZ) +# define RTMemTrackerDumpAllToFile RT_MANGLER(RTMemTrackerDumpAllToFile) +# define RTMemTrackerDumpAllToLog RT_MANGLER(RTMemTrackerDumpAllToLog) +# define RTMemTrackerDumpAllToLogRel RT_MANGLER(RTMemTrackerDumpAllToLogRel) +# define RTMemTrackerDumpAllToStdErr RT_MANGLER(RTMemTrackerDumpAllToStdErr) +# define RTMemTrackerDumpAllToStdOut RT_MANGLER(RTMemTrackerDumpAllToStdOut) +# define RTMemTrackerDumpStatsToFile RT_MANGLER(RTMemTrackerDumpStatsToFile) +# define RTMemTrackerDumpStatsToLog RT_MANGLER(RTMemTrackerDumpStatsToLog) +# define RTMemTrackerDumpStatsToLogRel RT_MANGLER(RTMemTrackerDumpStatsToLogRel) +# define RTMemTrackerDumpStatsToStdErr RT_MANGLER(RTMemTrackerDumpStatsToStdErr) +# define RTMemTrackerDumpStatsToStdOut RT_MANGLER(RTMemTrackerDumpStatsToStdOut) +# define RTMemTrackerHdrAlloc RT_MANGLER(RTMemTrackerHdrAlloc) +# define RTMemTrackerHdrFree RT_MANGLER(RTMemTrackerHdrFree) +# define RTMemTrackerHdrReallocDone RT_MANGLER(RTMemTrackerHdrReallocDone) +# define RTMemTrackerHdrReallocPrep RT_MANGLER(RTMemTrackerHdrReallocPrep) +# define RTMemWipeThoroughly RT_MANGLER(RTMemWipeThoroughly) +# define RTMpCpuId RT_MANGLER(RTMpCpuId) +# define RTMpCpuIdFromSetIndex RT_MANGLER(RTMpCpuIdFromSetIndex) +# define RTMpCpuIdToSetIndex RT_MANGLER(RTMpCpuIdToSetIndex) +# define RTMpCurSetIndex RT_MANGLER(RTMpCurSetIndex) +# define RTMpCurSetIndexAndId RT_MANGLER(RTMpCurSetIndexAndId) +# define RTMpGetArraySize RT_MANGLER(RTMpGetArraySize) +# define RTMpGetCount RT_MANGLER(RTMpGetCount) +# define RTMpGetCurFrequency RT_MANGLER(RTMpGetCurFrequency) +# define RTMpGetDescription RT_MANGLER(RTMpGetDescription) +# define RTMpGetCpuGroupCounts RT_MANGLER(RTMpGetCpuGroupCounts) +# define RTMpGetMaxCpuGroupCount RT_MANGLER(RTMpGetMaxCpuGroupCount) +# define RTMpGetMaxCpuId RT_MANGLER(RTMpGetMaxCpuId) +# define RTMpGetMaxFrequency RT_MANGLER(RTMpGetMaxFrequency) +# define RTMpGetOnlineCount RT_MANGLER(RTMpGetOnlineCount) +# define RTMpGetOnlineCoreCount RT_MANGLER(RTMpGetOnlineCoreCount) +# define RTMpGetOnlineSet RT_MANGLER(RTMpGetOnlineSet) +# define RTMpGetPresentCount RT_MANGLER(RTMpGetPresentCount) +# define RTMpGetPresentCoreCount RT_MANGLER(RTMpGetPresentCoreCount) +# define RTMpGetPresentSet RT_MANGLER(RTMpGetPresentSet) +# define RTMpGetSet RT_MANGLER(RTMpGetSet) +# define RTMpGetCoreCount RT_MANGLER(RTMpGetCoreCount) +# define RTMpIsCpuOnline RT_MANGLER(RTMpIsCpuOnline) +# define RTMpIsCpuPossible RT_MANGLER(RTMpIsCpuPossible) /* r0drv */ +# define RTMpIsCpuPresent RT_MANGLER(RTMpIsCpuPresent) +# define RTMpIsCpuWorkPending RT_MANGLER(RTMpIsCpuWorkPending) +# define RTMpNotificationDeregister RT_MANGLER(RTMpNotificationDeregister) /* r0drv */ +# define RTMpNotificationRegister RT_MANGLER(RTMpNotificationRegister) /* r0drv */ +# define RTMpOnAll RT_MANGLER(RTMpOnAll) /* r0drv */ +# define RTMpOnAllIsConcurrentSafe RT_MANGLER(RTMpOnAllIsConcurrentSafe) /* r0drv */ +# define RTMpOnOthers RT_MANGLER(RTMpOnOthers) /* r0drv */ +# define RTMpOnPair RT_MANGLER(RTMpOnPair) /* r0drv */ +# define RTMpOnPairIsConcurrentExecSupported RT_MANGLER(RTMpOnPairIsConcurrentExecSupported) /* r0drv */ +# define RTMpOnSpecific RT_MANGLER(RTMpOnSpecific) /* r0drv */ +# define RTMpPokeCpu RT_MANGLER(RTMpPokeCpu) /* r0drv */ +# define RTMpSetIndexFromCpuGroupMember RT_MANGLER(RTMpSetIndexFromCpuGroupMember) +# define RTMsgError RT_MANGLER(RTMsgError) +# define RTMsgErrorExit RT_MANGLER(RTMsgErrorExit) +# define RTMsgErrorExitV RT_MANGLER(RTMsgErrorExitV) +# define RTMsgErrorExitFailure RT_MANGLER(RTMsgErrorExitFailure) +# define RTMsgErrorExitFailureV RT_MANGLER(RTMsgErrorExitFailureV) +# define RTMsgErrorRc RT_MANGLER(RTMsgErrorRc) +# define RTMsgErrorRcV RT_MANGLER(RTMsgErrorRcV) +# define RTMsgErrorV RT_MANGLER(RTMsgErrorV) +# define RTMsgInfo RT_MANGLER(RTMsgInfo) +# define RTMsgInfoV RT_MANGLER(RTMsgInfoV) +# define RTMsgInitFailure RT_MANGLER(RTMsgInitFailure) +# define RTMsgSetProgName RT_MANGLER(RTMsgSetProgName) +# define RTMsgSyntax RT_MANGLER(RTMsgSyntax) +# define RTMsgSyntaxV RT_MANGLER(RTMsgSyntaxV) +# define RTMsgWarning RT_MANGLER(RTMsgWarning) +# define RTMsgWarningV RT_MANGLER(RTMsgWarningV) +# define RTMsgRefEntryPrintStringTable RT_MANGLER(RTMsgRefEntryPrintStringTable) +# define RTMsgRefEntrySynopsisEx RT_MANGLER(RTMsgRefEntrySynopsisEx) +# define RTMsgRefEntrySynopsis RT_MANGLER(RTMsgRefEntrySynopsis) +# define RTMsgRefEntryHelpEx RT_MANGLER(RTMsgRefEntryHelpEx) +# define RTMsgRefEntryHelp RT_MANGLER(RTMsgRefEntryHelp) +# define RTNetIPv4AddDataChecksum RT_MANGLER(RTNetIPv4AddDataChecksum) +# define RTNetIPv4AddTCPChecksum RT_MANGLER(RTNetIPv4AddTCPChecksum) +# define RTNetIPv4AddUDPChecksum RT_MANGLER(RTNetIPv4AddUDPChecksum) +# define RTNetIPv4FinalizeChecksum RT_MANGLER(RTNetIPv4FinalizeChecksum) +# define RTNetIPv4HdrChecksum RT_MANGLER(RTNetIPv4HdrChecksum) +# define RTNetIPv4IsDHCPValid RT_MANGLER(RTNetIPv4IsDHCPValid) +# define RTNetIPv4IsHdrValid RT_MANGLER(RTNetIPv4IsHdrValid) +# define RTNetIPv4IsTCPSizeValid RT_MANGLER(RTNetIPv4IsTCPSizeValid) +# define RTNetIPv4IsTCPValid RT_MANGLER(RTNetIPv4IsTCPValid) +# define RTNetIPv4IsUDPSizeValid RT_MANGLER(RTNetIPv4IsUDPSizeValid) +# define RTNetIPv4IsUDPValid RT_MANGLER(RTNetIPv4IsUDPValid) +# define RTNetIPv4PseudoChecksum RT_MANGLER(RTNetIPv4PseudoChecksum) +# define RTNetIPv4PseudoChecksumBits RT_MANGLER(RTNetIPv4PseudoChecksumBits) +# define RTNetIPv4TCPChecksum RT_MANGLER(RTNetIPv4TCPChecksum) +# define RTNetIPv4UDPChecksum RT_MANGLER(RTNetIPv4UDPChecksum) +# define RTNetIPv6PseudoChecksum RT_MANGLER(RTNetIPv6PseudoChecksum) +# define RTNetIPv6PseudoChecksumBits RT_MANGLER(RTNetIPv6PseudoChecksumBits) +# define RTNetIPv6PseudoChecksumEx RT_MANGLER(RTNetIPv6PseudoChecksumEx) +# define RTNetIsIPv4AddrStr RT_MANGLER(RTNetIsIPv4AddrStr) +# define RTNetIsIPv6AddrStr RT_MANGLER(RTNetIsIPv6AddrStr) +# define RTNetMaskToPrefixIPv4 RT_MANGLER(RTNetMaskToPrefixIPv4) +# define RTNetMaskToPrefixIPv6 RT_MANGLER(RTNetMaskToPrefixIPv6) +# define RTNetPrefixToMaskIPv4 RT_MANGLER(RTNetPrefixToMaskIPv4) +# define RTNetPrefixToMaskIPv6 RT_MANGLER(RTNetPrefixToMaskIPv6) +# define RTNetStrIsIPv4AddrAny RT_MANGLER(RTNetStrIsIPv4AddrAny) +# define RTNetStrIsIPv6AddrAny RT_MANGLER(RTNetStrIsIPv6AddrAny) +# define RTNetStrToIPv4Addr RT_MANGLER(RTNetStrToIPv4Addr) +# define RTNetStrToIPv4AddrEx RT_MANGLER(RTNetStrToIPv4AddrEx) +# define RTNetStrToIPv4Cidr RT_MANGLER(RTNetStrToIPv4Cidr) +# define RTNetStrToIPv6Addr RT_MANGLER(RTNetStrToIPv6Addr) +# define RTNetStrToIPv6AddrEx RT_MANGLER(RTNetStrToIPv6AddrEx) +# define RTNetStrToIPv6Cidr RT_MANGLER(RTNetStrToIPv6Cidr) +# define RTNetStrToMacAddr RT_MANGLER(RTNetStrToMacAddr) +# define RTNetTCPChecksum RT_MANGLER(RTNetTCPChecksum) +# define RTNetUDPChecksum RT_MANGLER(RTNetUDPChecksum) +# define RTOnceSlow RT_MANGLER(RTOnceSlow) +# define RTOnceReset RT_MANGLER(RTOnceReset) +# define RTPathAbs RT_MANGLER(RTPathAbs) +# define RTPathAbsDup RT_MANGLER(RTPathAbsDup) +# define RTPathAbsEx RT_MANGLER(RTPathAbsEx) +# define RTPathAbsExDup RT_MANGLER(RTPathAbsExDup) +# define RTPathAppDocs RT_MANGLER(RTPathAppDocs) +# define RTPathAppend RT_MANGLER(RTPathAppend) +# define RTPathAppendEx RT_MANGLER(RTPathAppendEx) +# define RTPathAppPrivateArch RT_MANGLER(RTPathAppPrivateArch) +# define RTPathAppPrivateArchTop RT_MANGLER(RTPathAppPrivateArchTop) +# define RTPathAppPrivateNoArch RT_MANGLER(RTPathAppPrivateNoArch) +# define RTPathCalcRelative RT_MANGLER(RTPathCalcRelative) +# define RTPathChangeToDosSlashes RT_MANGLER(RTPathChangeToDosSlashes) +# define RTPathChangeToUnixSlashes RT_MANGLER(RTPathChangeToUnixSlashes) +# define RTPathCompare RT_MANGLER(RTPathCompare) +# define RTPathCopyComponents RT_MANGLER(RTPathCopyComponents) +# define RTPathCountComponents RT_MANGLER(RTPathCountComponents) +# define RTPathEnsureTrailingSeparator RT_MANGLER(RTPathEnsureTrailingSeparator) +# define RTPathEnsureTrailingSeparatorEx RT_MANGLER(RTPathEnsureTrailingSeparatorEx) +# define RTPathExecDir RT_MANGLER(RTPathExecDir) +# define RTPathExists RT_MANGLER(RTPathExists) +# define RTPathExistsEx RT_MANGLER(RTPathExistsEx) +# define RTPathSuffix RT_MANGLER(RTPathSuffix) +# define RTPathFilename RT_MANGLER(RTPathFilename) +# define RTPathFilenameUtf16 RT_MANGLER(RTPathFilenameUtf16) +# define RTPathFilenameEx RT_MANGLER(RTPathFilenameEx) +# define RTPathFilenameExUtf16 RT_MANGLER(RTPathFilenameExUtf16) +# define RTPathFindCommon RT_MANGLER(RTPathFindCommon) +# define RTPathFindCommonEx RT_MANGLER(RTPathFindCommonEx) +# define RTPathGetCurrent RT_MANGLER(RTPathGetCurrent) +# define RTPathGetCurrentDrive RT_MANGLER(RTPathGetCurrentDrive) +# define RTPathGetCurrentOnDrive RT_MANGLER(RTPathGetCurrentOnDrive) +# define RTPathGetMode RT_MANGLER(RTPathGetMode) +# define RTPathGlob RT_MANGLER(RTPathGlob) +# define RTPathGlobFree RT_MANGLER(RTPathGlobFree) +# define RTPathHasSuffix RT_MANGLER(RTPathHasSuffix) +# define RTPathHasPath RT_MANGLER(RTPathHasPath) +# define RTPathIsSame RT_MANGLER(RTPathIsSame) +# define RTPathJoin RT_MANGLER(RTPathJoin) +# define RTPathJoinA RT_MANGLER(RTPathJoinA) +# define RTPathJoinEx RT_MANGLER(RTPathJoinEx) +# define RTPathParentLength RT_MANGLER(RTPathParentLength) +# define RTPathParentLengthEx RT_MANGLER(RTPathParentLengthEx) +# define RTPathParse RT_MANGLER(RTPathParse) +# define RTPathParsedReassemble RT_MANGLER(RTPathParsedReassemble) +# define RTPathParseSimple RT_MANGLER(RTPathParseSimple) +# define RTPathPurgeFilename RT_MANGLER(RTPathPurgeFilename) +# define RTPathQueryInfo RT_MANGLER(RTPathQueryInfo) +# define RTPathQueryInfoEx RT_MANGLER(RTPathQueryInfoEx) +# define RTPathReal RT_MANGLER(RTPathReal) +# define RTPathRealDup RT_MANGLER(RTPathRealDup) +# define RTPathRename RT_MANGLER(RTPathRename) +# define RTPathRmCmd RT_MANGLER(RTPathRmCmd) +# define RTPathSetCurrent RT_MANGLER(RTPathSetCurrent) +# define RTPathSetMode RT_MANGLER(RTPathSetMode) /* not-win */ +# define RTPathSetOwner RT_MANGLER(RTPathSetOwner) /* not-win */ +# define RTPathSetOwnerEx RT_MANGLER(RTPathSetOwnerEx) /* not-win */ +# define RTPathSetTimes RT_MANGLER(RTPathSetTimes) +# define RTPathSetTimesEx RT_MANGLER(RTPathSetTimesEx) +# define RTPathSharedLibs RT_MANGLER(RTPathSharedLibs) +# define RTPathSkipRootSpec RT_MANGLER(RTPathSkipRootSpec) +# define RTPathSplit RT_MANGLER(RTPathSplit) +# define RTPathSplitATag RT_MANGLER(RTPathSplitATag) +# define RTPathSplitFree RT_MANGLER(RTPathSplitFree) +# define RTPathSplitReassemble RT_MANGLER(RTPathSplitReassemble) +# define RTPathStartsWith RT_MANGLER(RTPathStartsWith) +# define RTPathStartsWithRoot RT_MANGLER(RTPathStartsWithRoot) +# define RTPathStripSuffix RT_MANGLER(RTPathStripSuffix) +# define RTPathStripFilename RT_MANGLER(RTPathStripFilename) +# define RTPathStripTrailingSlash RT_MANGLER(RTPathStripTrailingSlash) +# define RTPathTemp RT_MANGLER(RTPathTemp) +# define RTPathTraverseList RT_MANGLER(RTPathTraverseList) +# define RTPathUnlink RT_MANGLER(RTPathUnlink) +# define RTPathUserDocuments RT_MANGLER(RTPathUserDocuments) +# define RTPathUserHome RT_MANGLER(RTPathUserHome) +# define RTPipeClose RT_MANGLER(RTPipeClose) +# define RTPipeCloseEx RT_MANGLER(RTPipeCloseEx) +# define RTPipeCreate RT_MANGLER(RTPipeCreate) +# define RTPipeFlush RT_MANGLER(RTPipeFlush) +# define RTPipeFromNative RT_MANGLER(RTPipeFromNative) +# define RTPipeQueryInfo RT_MANGLER(RTPipeQueryInfo) +# define RTPipeQueryReadable RT_MANGLER(RTPipeQueryReadable) +# define RTPipeRead RT_MANGLER(RTPipeRead) +# define RTPipeReadBlocking RT_MANGLER(RTPipeReadBlocking) +# define RTPipeSelectOne RT_MANGLER(RTPipeSelectOne) +# define RTPipeToNative RT_MANGLER(RTPipeToNative) +# define RTPipeWrite RT_MANGLER(RTPipeWrite) +# define RTPipeWriteBlocking RT_MANGLER(RTPipeWriteBlocking) +# define RTPoll RT_MANGLER(RTPoll) +# define RTPollNoResume RT_MANGLER(RTPollNoResume) +# define RTPollSetAdd RT_MANGLER(RTPollSetAdd) +# define RTPollSetCreate RT_MANGLER(RTPollSetCreate) +# define RTPollSetDestroy RT_MANGLER(RTPollSetDestroy) +# define RTPollSetEventsChange RT_MANGLER(RTPollSetEventsChange) +# define RTPollSetGetCount RT_MANGLER(RTPollSetGetCount) +# define RTPollSetQueryHandle RT_MANGLER(RTPollSetQueryHandle) +# define RTPollSetRemove RT_MANGLER(RTPollSetRemove) +# define RTPowerNotificationDeregister RT_MANGLER(RTPowerNotificationDeregister) /* r0drv */ +# define RTPowerNotificationRegister RT_MANGLER(RTPowerNotificationRegister) /* r0drv */ +# define RTPowerSignalEvent RT_MANGLER(RTPowerSignalEvent) /* r0drv */ +# define RTPrintf RT_MANGLER(RTPrintf) +# define RTPrintfV RT_MANGLER(RTPrintfV) +# define RTProcCreate RT_MANGLER(RTProcCreate) +# define RTProcCreateEx RT_MANGLER(RTProcCreateEx) +# define RTProcDaemonize RT_MANGLER(RTProcDaemonize) +# define RTProcDaemonizeUsingFork RT_MANGLER(RTProcDaemonizeUsingFork) +# define RTProcExecutablePath RT_MANGLER(RTProcExecutablePath) +# define RTProcGetAffinityMask RT_MANGLER(RTProcGetAffinityMask) +# define RTProcGetExecutablePath RT_MANGLER(RTProcGetExecutablePath) +# define RTProcGetPriority RT_MANGLER(RTProcGetPriority) +# define RTProcIsRunningByName RT_MANGLER(RTProcIsRunningByName) +# define RTProcQueryParent RT_MANGLER(RTProcQueryParent) +# define RTProcQueryUsername RT_MANGLER(RTProcQueryUsername) +# define RTProcQueryUsernameA RT_MANGLER(RTProcQueryUsernameA) +# define RTProcSelf RT_MANGLER(RTProcSelf) +# define RTProcSetPriority RT_MANGLER(RTProcSetPriority) +# define RTProcShortName RT_MANGLER(RTProcShortName) +# define RTProcSignalName RT_MANGLER(RTProcSignalName) +# define RTProcTerminate RT_MANGLER(RTProcTerminate) +# define RTProcWait RT_MANGLER(RTProcWait) +# define RTProcWaitNoResume RT_MANGLER(RTProcWaitNoResume) +# define RTR0AssertPanicSystem RT_MANGLER(RTR0AssertPanicSystem) /* r0drv */ +# define RTR0DbgKrnlInfoOpen RT_MANGLER(RTR0DbgKrnlInfoOpen) /* r0drv */ +# define RTR0DbgKrnlInfoQueryMember RT_MANGLER(RTR0DbgKrnlInfoQueryMember) /* r0drv */ +# define RTR0DbgKrnlInfoQuerySize RT_MANGLER(RTR0DbgKrnlInfoQuerySize) /* r0drv */ +# define RTR0DbgKrnlInfoQuerySymbol RT_MANGLER(RTR0DbgKrnlInfoQuerySymbol) /* r0drv */ +# define RTR0DbgKrnlInfoGetSymbol RT_MANGLER(RTR0DbgKrnlInfoGetSymbol) /* r0drv */ +# define RTR0DbgKrnlInfoRelease RT_MANGLER(RTR0DbgKrnlInfoRelease) /* r0drv */ +# define RTR0DbgKrnlInfoRetain RT_MANGLER(RTR0DbgKrnlInfoRetain) /* r0drv */ +# define RTR0Init RT_MANGLER(RTR0Init) /* r0drv */ +# define RTR0MemAreKrnlAndUsrDifferent RT_MANGLER(RTR0MemAreKrnlAndUsrDifferent) /* r0drv */ +# define RTR0MemKernelIsValidAddr RT_MANGLER(RTR0MemKernelIsValidAddr) /* r0drv */ +# define RTR0MemObjAddress RT_MANGLER(RTR0MemObjAddress) /* r0drv */ +# define RTR0MemObjAddressR3 RT_MANGLER(RTR0MemObjAddressR3) /* r0drv */ +# define RTR0MemKernelCopyFrom RT_MANGLER(RTR0MemKernelCopyFrom) /* r0drv */ +# define RTR0MemKernelCopyTo RT_MANGLER(RTR0MemKernelCopyTo) /* r0drv */ +# define RTR0MemObjAllocContTag RT_MANGLER(RTR0MemObjAllocContTag) /* r0drv */ +# define RTR0MemObjAllocLargeTag RT_MANGLER(RTR0MemObjAllocLargeTag) /* r0drv */ +# define RTR0MemObjAllocLowTag RT_MANGLER(RTR0MemObjAllocLowTag) /* r0drv */ +# define RTR0MemObjAllocPageTag RT_MANGLER(RTR0MemObjAllocPageTag) /* r0drv */ +# define RTR0MemObjAllocPhysExTag RT_MANGLER(RTR0MemObjAllocPhysExTag) /* r0drv */ +# define RTR0MemObjAllocPhysNCTag RT_MANGLER(RTR0MemObjAllocPhysNCTag) /* r0drv */ +# define RTR0MemObjAllocPhysTag RT_MANGLER(RTR0MemObjAllocPhysTag) /* r0drv */ +# define RTR0MemObjEnterPhysTag RT_MANGLER(RTR0MemObjEnterPhysTag) /* r0drv */ +# define RTR0MemObjFree RT_MANGLER(RTR0MemObjFree) /* r0drv */ +# define RTR0MemObjGetPagePhysAddr RT_MANGLER(RTR0MemObjGetPagePhysAddr) /* r0drv */ +# define RTR0MemObjIsMapping RT_MANGLER(RTR0MemObjIsMapping) /* r0drv */ +# define RTR0MemObjLockKernelTag RT_MANGLER(RTR0MemObjLockKernelTag) /* r0drv */ +# define RTR0MemObjLockUserTag RT_MANGLER(RTR0MemObjLockUserTag) /* r0drv */ +# define RTR0MemObjMapKernelExTag RT_MANGLER(RTR0MemObjMapKernelExTag) /* r0drv */ +# define RTR0MemObjMapKernelTag RT_MANGLER(RTR0MemObjMapKernelTag) /* r0drv */ +# define RTR0MemObjMapUserTag RT_MANGLER(RTR0MemObjMapUserTag) /* r0drv */ +# define RTR0MemObjMapUserExTag RT_MANGLER(RTR0MemObjMapUserExTag) /* r0drv */ +# define RTR0MemObjProtect RT_MANGLER(RTR0MemObjProtect) /* r0drv */ +# define RTR0MemObjReserveKernelTag RT_MANGLER(RTR0MemObjReserveKernelTag) /* r0drv */ +# define RTR0MemObjReserveUserTag RT_MANGLER(RTR0MemObjReserveUserTag) /* r0drv */ +# define RTR0MemObjSize RT_MANGLER(RTR0MemObjSize) /* r0drv */ +# define RTR0MemObjWasZeroInitialized RT_MANGLER(RTR0MemObjWasZeroInitialized)/* r0drv */ +# define RTR0MemUserCopyFrom RT_MANGLER(RTR0MemUserCopyFrom) /* r0drv */ +# define RTR0MemUserCopyTo RT_MANGLER(RTR0MemUserCopyTo) /* r0drv */ +# define RTR0MemUserIsValidAddr RT_MANGLER(RTR0MemUserIsValidAddr) /* r0drv */ +# define rtR0MemObjLinuxVirtToPage RT_MANGLER(rtR0MemObjLinuxVirtToPage) /* r0drv linux-only */ +# define RTR0ProcHandleSelf RT_MANGLER(RTR0ProcHandleSelf) /* r0drv */ +# define RTR0Term RT_MANGLER(RTR0Term) /* r0drv */ +# define RTR0TermForced RT_MANGLER(RTR0TermForced) /* r0drv */ +# define RTR3InitDll RT_MANGLER(RTR3InitDll) +# define RTR3InitExe RT_MANGLER(RTR3InitExe) +# define RTR3InitExeNoArguments RT_MANGLER(RTR3InitExeNoArguments) +# define RTR3InitEx RT_MANGLER(RTR3InitEx) +# define RTR3InitIsInitialized RT_MANGLER(RTR3InitIsInitialized) +# define RTR3InitIsUnobtrusive RT_MANGLER(RTR3InitIsUnobtrusive) +# define rtR3MemAlloc RT_MANGLER(rtR3MemAlloc) +# define rtR3MemFree RT_MANGLER(rtR3MemFree) +# define rtR3MemRealloc RT_MANGLER(rtR3MemRealloc) +# define RTRCInit RT_MANGLER(RTRCInit) +# define RTRCTerm RT_MANGLER(RTRCTerm) +# define RTRandAdvBytes RT_MANGLER(RTRandAdvBytes) +# define RTRandAdvCreateParkMiller RT_MANGLER(RTRandAdvCreateParkMiller) +# define RTRandAdvCreateSystemFaster RT_MANGLER(RTRandAdvCreateSystemFaster) +# define RTRandAdvCreateSystemTruer RT_MANGLER(RTRandAdvCreateSystemTruer) +# define RTRandAdvDestroy RT_MANGLER(RTRandAdvDestroy) +# define RTRandAdvRestoreState RT_MANGLER(RTRandAdvRestoreState) +# define RTRandAdvS32 RT_MANGLER(RTRandAdvS32) +# define RTRandAdvS32Ex RT_MANGLER(RTRandAdvS32Ex) +# define RTRandAdvS64 RT_MANGLER(RTRandAdvS64) +# define RTRandAdvS64Ex RT_MANGLER(RTRandAdvS64Ex) +# define RTRandAdvSaveState RT_MANGLER(RTRandAdvSaveState) +# define RTRandAdvSeed RT_MANGLER(RTRandAdvSeed) +# define RTRandAdvU32 RT_MANGLER(RTRandAdvU32) +# define RTRandAdvU32Ex RT_MANGLER(RTRandAdvU32Ex) +# define RTRandAdvU64 RT_MANGLER(RTRandAdvU64) +# define RTRandAdvU64Ex RT_MANGLER(RTRandAdvU64Ex) +# define RTRandBytes RT_MANGLER(RTRandBytes) +# define RTRandS32 RT_MANGLER(RTRandS32) +# define RTRandS32Ex RT_MANGLER(RTRandS32Ex) +# define RTRandS64 RT_MANGLER(RTRandS64) +# define RTRandS64Ex RT_MANGLER(RTRandS64Ex) +# define RTRandU32 RT_MANGLER(RTRandU32) +# define RTRandU32Ex RT_MANGLER(RTRandU32Ex) +# define RTRandU64 RT_MANGLER(RTRandU64) +# define RTRandU64Ex RT_MANGLER(RTRandU64Ex) +# define RTReqPoolAlloc RT_MANGLER(RTReqPoolAlloc) +# define RTReqPoolCallEx RT_MANGLER(RTReqPoolCallEx) +# define RTReqPoolCallExV RT_MANGLER(RTReqPoolCallExV) +# define RTReqPoolCallWait RT_MANGLER(RTReqPoolCallWait) +# define RTReqPoolCallNoWait RT_MANGLER(RTReqPoolCallNoWait) +# define RTReqPoolCallVoidWait RT_MANGLER(RTReqPoolCallVoidWait) +# define RTReqPoolCallVoidNoWait RT_MANGLER(RTReqPoolCallVoidNoWait) +# define RTReqPoolCreate RT_MANGLER(RTReqPoolCreate) +# define RTReqPoolGetCfgVar RT_MANGLER(RTReqPoolGetCfgVar) +# define RTReqPoolGetStat RT_MANGLER(RTReqPoolGetStat) +# define RTReqPoolRetain RT_MANGLER(RTReqPoolRetain) +# define RTReqPoolRelease RT_MANGLER(RTReqPoolRelease) +# define RTReqPoolSetCfgVar RT_MANGLER(RTReqPoolSetCfgVar) +# define RTReqQueueAlloc RT_MANGLER(RTReqQueueAlloc) +# define RTReqQueueCall RT_MANGLER(RTReqQueueCall) +# define RTReqQueueCallEx RT_MANGLER(RTReqQueueCallEx) +# define RTReqQueueCallV RT_MANGLER(RTReqQueueCallV) +# define RTReqQueueCallVoid RT_MANGLER(RTReqQueueCallVoid) +# define RTReqQueueCreate RT_MANGLER(RTReqQueueCreate) +# define RTReqQueueDestroy RT_MANGLER(RTReqQueueDestroy) +# define RTReqQueueIsBusy RT_MANGLER(RTReqQueueIsBusy) +# define RTReqQueueProcess RT_MANGLER(RTReqQueueProcess) +# define RTReqCancel RT_MANGLER(RTReqCancel) +# define RTReqRelease RT_MANGLER(RTReqRelease) +# define RTReqRetain RT_MANGLER(RTReqRetain) +# define RTReqSubmit RT_MANGLER(RTReqSubmit) +# define RTReqWait RT_MANGLER(RTReqWait) +# define RTReqGetStatus RT_MANGLER(RTReqGetStatus) +# define RTS3BucketsDestroy RT_MANGLER(RTS3BucketsDestroy) +# define RTS3Create RT_MANGLER(RTS3Create) +# define RTS3CreateBucket RT_MANGLER(RTS3CreateBucket) +# define RTS3DeleteBucket RT_MANGLER(RTS3DeleteBucket) +# define RTS3DeleteKey RT_MANGLER(RTS3DeleteKey) +# define RTS3Destroy RT_MANGLER(RTS3Destroy) +# define RTS3GetBucketKeys RT_MANGLER(RTS3GetBucketKeys) +# define RTS3GetBuckets RT_MANGLER(RTS3GetBuckets) +# define RTS3GetKey RT_MANGLER(RTS3GetKey) +# define RTS3KeysDestroy RT_MANGLER(RTS3KeysDestroy) +# define RTS3PutKey RT_MANGLER(RTS3PutKey) +# define RTS3SetProgressCallback RT_MANGLER(RTS3SetProgressCallback) +# define RTSemEventAddSignaller RT_MANGLER(RTSemEventAddSignaller) +# define RTSemEventCreate RT_MANGLER(RTSemEventCreate) +# define RTSemEventCreateEx RT_MANGLER(RTSemEventCreateEx) +# define RTSemEventDestroy RT_MANGLER(RTSemEventDestroy) +# define RTSemEventGetResolution RT_MANGLER(RTSemEventGetResolution) /* r0drv */ +# define RTSemEventIsSignalSafe RT_MANGLER(RTSemEventIsSignalSafe) /* r0drv */ +# define RTSemEventMultiAddSignaller RT_MANGLER(RTSemEventMultiAddSignaller) +# define RTSemEventMultiCreate RT_MANGLER(RTSemEventMultiCreate) +# define RTSemEventMultiCreateEx RT_MANGLER(RTSemEventMultiCreateEx) +# define RTSemEventMultiDestroy RT_MANGLER(RTSemEventMultiDestroy) +# define RTSemEventMultiGetResolution RT_MANGLER(RTSemEventMultiGetResolution) /* r0drv */ +# define RTSemEventMultiIsSignalSafe RT_MANGLER(RTSemEventMultiIsSignalSafe) /* r0drv */ +# define RTSemEventMultiRemoveSignaller RT_MANGLER(RTSemEventMultiRemoveSignaller) +# define RTSemEventMultiReset RT_MANGLER(RTSemEventMultiReset) +# define RTSemEventMultiSetSignaller RT_MANGLER(RTSemEventMultiSetSignaller) +# define RTSemEventMultiSignal RT_MANGLER(RTSemEventMultiSignal) +# define RTSemEventMultiWait RT_MANGLER(RTSemEventMultiWait) +# define RTSemEventMultiWaitEx RT_MANGLER(RTSemEventMultiWaitEx) +# define RTSemEventMultiWaitEx RT_MANGLER(RTSemEventMultiWaitEx) /* r0drv */ +# define RTSemEventMultiWaitExDebug RT_MANGLER(RTSemEventMultiWaitExDebug) +# define RTSemEventMultiWaitExDebug RT_MANGLER(RTSemEventMultiWaitExDebug) /* r0drv */ +# define RTSemEventMultiWaitNoResume RT_MANGLER(RTSemEventMultiWaitNoResume) +# define RTSemEventRemoveSignaller RT_MANGLER(RTSemEventRemoveSignaller) +# define RTSemEventSetSignaller RT_MANGLER(RTSemEventSetSignaller) +# define RTSemEventSignal RT_MANGLER(RTSemEventSignal) +# define RTSemEventWait RT_MANGLER(RTSemEventWait) +# define RTSemEventWaitEx RT_MANGLER(RTSemEventWaitEx) /* r0drv */ +# define RTSemEventWaitExDebug RT_MANGLER(RTSemEventWaitExDebug) /* r0drv */ +# define RTSemEventWaitNoResume RT_MANGLER(RTSemEventWaitNoResume) +# define RTSemFastMutexCreate RT_MANGLER(RTSemFastMutexCreate) +# define RTSemFastMutexDestroy RT_MANGLER(RTSemFastMutexDestroy) +# define RTSemFastMutexRelease RT_MANGLER(RTSemFastMutexRelease) +# define RTSemFastMutexRequest RT_MANGLER(RTSemFastMutexRequest) +# define RTSemMutexCreate RT_MANGLER(RTSemMutexCreate) +# define RTSemMutexCreateEx RT_MANGLER(RTSemMutexCreateEx) +# define RTSemMutexDestroy RT_MANGLER(RTSemMutexDestroy) +# define RTSemMutexIsOwned RT_MANGLER(RTSemMutexIsOwned) +# define RTSemMutexRelease RT_MANGLER(RTSemMutexRelease) +# define RTSemMutexRequest RT_MANGLER(RTSemMutexRequest) +# define RTSemMutexRequestDebug RT_MANGLER(RTSemMutexRequestDebug) +# define RTSemMutexRequestNoResume RT_MANGLER(RTSemMutexRequestNoResume) +# define RTSemMutexRequestNoResumeDebug RT_MANGLER(RTSemMutexRequestNoResumeDebug) +# define RTSemMutexSetSubClass RT_MANGLER(RTSemMutexSetSubClass) +# define RTSemPing RT_MANGLER(RTSemPing) +# define RTSemPingPongDelete RT_MANGLER(RTSemPingPongDelete) +# define RTSemPingPongInit RT_MANGLER(RTSemPingPongInit) +# define RTSemPingWait RT_MANGLER(RTSemPingWait) +# define RTSemPong RT_MANGLER(RTSemPong) +# define RTSemPongWait RT_MANGLER(RTSemPongWait) +# define RTSemRWCreate RT_MANGLER(RTSemRWCreate) +# define RTSemRWCreateEx RT_MANGLER(RTSemRWCreateEx) +# define RTSemRWDestroy RT_MANGLER(RTSemRWDestroy) +# define RTSemRWGetReadCount RT_MANGLER(RTSemRWGetReadCount) +# define RTSemRWGetWriteRecursion RT_MANGLER(RTSemRWGetWriteRecursion) +# define RTSemRWGetWriterReadRecursion RT_MANGLER(RTSemRWGetWriterReadRecursion) +# define RTSemRWIsReadOwner RT_MANGLER(RTSemRWIsReadOwner) +# define RTSemRWIsWriteOwner RT_MANGLER(RTSemRWIsWriteOwner) +# define RTSemRWReleaseRead RT_MANGLER(RTSemRWReleaseRead) +# define RTSemRWReleaseWrite RT_MANGLER(RTSemRWReleaseWrite) +# define RTSemRWRequestRead RT_MANGLER(RTSemRWRequestRead) +# define RTSemRWRequestReadDebug RT_MANGLER(RTSemRWRequestReadDebug) +# define RTSemRWRequestReadNoResume RT_MANGLER(RTSemRWRequestReadNoResume) +# define RTSemRWRequestReadNoResumeDebug RT_MANGLER(RTSemRWRequestReadNoResumeDebug) +# define RTSemRWRequestWrite RT_MANGLER(RTSemRWRequestWrite) +# define RTSemRWRequestWriteDebug RT_MANGLER(RTSemRWRequestWriteDebug) +# define RTSemRWRequestWriteNoResume RT_MANGLER(RTSemRWRequestWriteNoResume) +# define RTSemRWRequestWriteNoResumeDebug RT_MANGLER(RTSemRWRequestWriteNoResumeDebug) +# define RTSemRWSetSubClass RT_MANGLER(RTSemRWSetSubClass) +# define RTSemSpinMutexCreate RT_MANGLER(RTSemSpinMutexCreate) +# define RTSemSpinMutexDestroy RT_MANGLER(RTSemSpinMutexDestroy) +# define RTSemSpinMutexRelease RT_MANGLER(RTSemSpinMutexRelease) +# define RTSemSpinMutexRequest RT_MANGLER(RTSemSpinMutexRequest) +# define RTSemSpinMutexTryRequest RT_MANGLER(RTSemSpinMutexTryRequest) +# define RTSemXRoadsCreate RT_MANGLER(RTSemXRoadsCreate) +# define RTSemXRoadsDestroy RT_MANGLER(RTSemXRoadsDestroy) +# define RTSemXRoadsEWEnter RT_MANGLER(RTSemXRoadsEWEnter) +# define RTSemXRoadsEWLeave RT_MANGLER(RTSemXRoadsEWLeave) +# define RTSemXRoadsNSEnter RT_MANGLER(RTSemXRoadsNSEnter) +# define RTSemXRoadsNSLeave RT_MANGLER(RTSemXRoadsNSLeave) +# define RTSerialPortOpen RT_MANGLER(RTSerialPortOpen) +# define RTSerialPortClose RT_MANGLER(RTSerialPortClose) +# define RTSerialPortToNative RT_MANGLER(RTSerialPortToNative) +# define RTSerialPortRead RT_MANGLER(RTSerialPortRead) +# define RTSerialPortReadNB RT_MANGLER(RTSerialPortReadNB) +# define RTSerialPortWrite RT_MANGLER(RTSerialPortWrite) +# define RTSerialPortWriteNB RT_MANGLER(RTSerialPortWriteNB) +# define RTSerialPortCfgQueryCurrent RT_MANGLER(RTSerialPortCfgQueryCurrent) +# define RTSerialPortCfgSet RT_MANGLER(RTSerialPortCfgSet) +# define RTSerialPortEvtPoll RT_MANGLER(RTSerialPortEvtPoll) +# define RTSerialPortEvtPollInterrupt RT_MANGLER(RTSerialPortEvtPollInterrupt) +# define RTSerialPortChgBreakCondition RT_MANGLER(RTSerialPortChgBreakCondition) +# define RTSerialPortChgStatusLines RT_MANGLER(RTSerialPortChgStatusLines) +# define RTSerialPortQueryStatusLines RT_MANGLER(RTSerialPortQueryStatusLines) +# define RTSgBufAdvance RT_MANGLER(RTSgBufAdvance) +# define RTSgBufClone RT_MANGLER(RTSgBufClone) +# define RTSgBufCmp RT_MANGLER(RTSgBufCmp) +# define RTSgBufCmpEx RT_MANGLER(RTSgBufCmpEx) +# define RTSgBufCopy RT_MANGLER(RTSgBufCopy) +# define RTSgBufCopyFromBuf RT_MANGLER(RTSgBufCopyFromBuf) +# define RTSgBufCopyFromFn RT_MANGLER(RTSgBufCopyFromFn) +# define RTSgBufCopyToBuf RT_MANGLER(RTSgBufCopyToBuf) +# define RTSgBufCopyToFn RT_MANGLER(RTSgBufCopyToFn) +# define RTSgBufInit RT_MANGLER(RTSgBufInit) +# define RTSgBufIsZero RT_MANGLER(RTSgBufIsZero) +# define RTSgBufReset RT_MANGLER(RTSgBufReset) +# define RTSgBufSegArrayCreate RT_MANGLER(RTSgBufSegArrayCreate) +# define RTSgBufSet RT_MANGLER(RTSgBufSet) +# define RTSgBufGetNextSegment RT_MANGLER(RTSgBufGetNextSegment) +# define RTSha1 RT_MANGLER(RTSha1) +# define RTSha1Check RT_MANGLER(RTSha1Check) +# define RTSha1Digest RT_MANGLER(RTSha1Digest) +# define RTSha1DigestFromFile RT_MANGLER(RTSha1DigestFromFile) +# define RTSha1Final RT_MANGLER(RTSha1Final) +# define RTSha1FromString RT_MANGLER(RTSha1FromString) +# define RTSha1Init RT_MANGLER(RTSha1Init) +# define RTSha1ToString RT_MANGLER(RTSha1ToString) +# define RTSha1Update RT_MANGLER(RTSha1Update) +# define RTSha224 RT_MANGLER(RTSha224) +# define RTSha224Check RT_MANGLER(RTSha224Check) +# define RTSha224Final RT_MANGLER(RTSha224Final) +# define RTSha224FromString RT_MANGLER(RTSha224FromString) +# define RTSha224Init RT_MANGLER(RTSha224Init) +# define RTSha224ToString RT_MANGLER(RTSha224ToString) +# define RTSha224Update RT_MANGLER(RTSha224Update) +# define RTSha224Digest RT_MANGLER(RTSha224Digest) +# define RTSha224DigestFromFile RT_MANGLER(RTSha224DigestFromFile) +# define RTSha256 RT_MANGLER(RTSha256) +# define RTSha256Check RT_MANGLER(RTSha256Check) +# define RTSha256Final RT_MANGLER(RTSha256Final) +# define RTSha256FromString RT_MANGLER(RTSha256FromString) +# define RTSha256Init RT_MANGLER(RTSha256Init) +# define RTSha256ToString RT_MANGLER(RTSha256ToString) +# define RTSha256Update RT_MANGLER(RTSha256Update) +# define RTSha256Digest RT_MANGLER(RTSha256Digest) +# define RTSha256DigestFromFile RT_MANGLER(RTSha256DigestFromFile) +# define RTSha384 RT_MANGLER(RTSha384) +# define RTSha384Check RT_MANGLER(RTSha384Check) +# define RTSha384Final RT_MANGLER(RTSha384Final) +# define RTSha384FromString RT_MANGLER(RTSha384FromString) +# define RTSha384Init RT_MANGLER(RTSha384Init) +# define RTSha384ToString RT_MANGLER(RTSha384ToString) +# define RTSha384Update RT_MANGLER(RTSha384Update) +# define RTSha512 RT_MANGLER(RTSha512) +# define RTSha512Check RT_MANGLER(RTSha512Check) +# define RTSha512Final RT_MANGLER(RTSha512Final) +# define RTSha512FromString RT_MANGLER(RTSha512FromString) +# define RTSha512Init RT_MANGLER(RTSha512Init) +# define RTSha512ToString RT_MANGLER(RTSha512ToString) +# define RTSha512Update RT_MANGLER(RTSha512Update) +# define RTSha512t224 RT_MANGLER(RTSha512t224) +# define RTSha512t224Check RT_MANGLER(RTSha512t224Check) +# define RTSha512t224Final RT_MANGLER(RTSha512t224Final) +# define RTSha512t224FromString RT_MANGLER(RTSha512t224FromString) +# define RTSha512t224Init RT_MANGLER(RTSha512t224Init) +# define RTSha512t224ToString RT_MANGLER(RTSha512t224ToString) +# define RTSha512t224Update RT_MANGLER(RTSha512t224Update) +# define RTSha512t256 RT_MANGLER(RTSha512t256) +# define RTSha512t256Check RT_MANGLER(RTSha512t256Check) +# define RTSha512t256Final RT_MANGLER(RTSha512t256Final) +# define RTSha512t256FromString RT_MANGLER(RTSha512t256FromString) +# define RTSha512t256Init RT_MANGLER(RTSha512t256Init) +# define RTSha512t256ToString RT_MANGLER(RTSha512t256ToString) +# define RTSha512t256Update RT_MANGLER(RTSha512t256Update) +# define RTSha3t224 RT_MANGLER(RTSha3t224) +# define RTSha3t224Check RT_MANGLER(RTSha3t224Check) +# define RTSha3t224Cleanup RT_MANGLER(RTSha3t224Cleanup) +# define RTSha3t224Clone RT_MANGLER(RTSha3t224Clone) +# define RTSha3t224Init RT_MANGLER(RTSha3t224Init) +# define RTSha3t224Final RT_MANGLER(RTSha3t224Final) +# define RTSha3t224FromString RT_MANGLER(RTSha3t224FromString) +# define RTSha3t224ToString RT_MANGLER(RTSha3t224ToString) +# define RTSha3t224Update RT_MANGLER(RTSha3t224Update) +# define RTSha3t256 RT_MANGLER(RTSha3t256) +# define RTSha3t256Check RT_MANGLER(RTSha3t256Check) +# define RTSha3t256Cleanup RT_MANGLER(RTSha3t256Cleanup) +# define RTSha3t256Clone RT_MANGLER(RTSha3t256Clone) +# define RTSha3t256Init RT_MANGLER(RTSha3t256Init) +# define RTSha3t256Final RT_MANGLER(RTSha3t256Final) +# define RTSha3t256FromString RT_MANGLER(RTSha3t256FromString) +# define RTSha3t256ToString RT_MANGLER(RTSha3t256ToString) +# define RTSha3t256Update RT_MANGLER(RTSha3t256Update) +# define RTSha3t384 RT_MANGLER(RTSha3t384) +# define RTSha3t384Check RT_MANGLER(RTSha3t384Check) +# define RTSha3t384Cleanup RT_MANGLER(RTSha3t384Cleanup) +# define RTSha3t384Clone RT_MANGLER(RTSha3t384Clone) +# define RTSha3t384Init RT_MANGLER(RTSha3t384Init) +# define RTSha3t384Final RT_MANGLER(RTSha3t384Final) +# define RTSha3t384FromString RT_MANGLER(RTSha3t384FromString) +# define RTSha3t384ToString RT_MANGLER(RTSha3t384ToString) +# define RTSha3t384Update RT_MANGLER(RTSha3t384Update) +# define RTSha3t512 RT_MANGLER(RTSha3t512) +# define RTSha3t512Check RT_MANGLER(RTSha3t512Check) +# define RTSha3t512Cleanup RT_MANGLER(RTSha3t512Cleanup) +# define RTSha3t512Clone RT_MANGLER(RTSha3t512Clone) +# define RTSha3t512Init RT_MANGLER(RTSha3t512Init) +# define RTSha3t512Final RT_MANGLER(RTSha3t512Final) +# define RTSha3t512FromString RT_MANGLER(RTSha3t512FromString) +# define RTSha3t512ToString RT_MANGLER(RTSha3t512ToString) +# define RTSha3t512Update RT_MANGLER(RTSha3t512Update) +# define RTShMemClose RT_MANGLER(RTShMemClose) +# define RTShMemDelete RT_MANGLER(RTShMemDelete) +# define RTShMemMapRegion RT_MANGLER(RTShMemMapRegion) +# define RTShMemOpen RT_MANGLER(RTShMemOpen) +# define RTShMemQuerySize RT_MANGLER(RTShMemQuerySize) +# define RTShMemRefCount RT_MANGLER(RTShMemRefCount) +# define RTShMemSetSize RT_MANGLER(RTShMemSetSize) +# define RTShMemUnmapRegion RT_MANGLER(RTShMemUnmapRegion) +# define RTSocketClose RT_MANGLER(RTSocketClose) +# define RTSocketFromNative RT_MANGLER(RTSocketFromNative) +# define RTSocketQueryAddressStr RT_MANGLER(RTSocketQueryAddressStr) +# define RTSocketGetLocalAddress RT_MANGLER(RTSocketGetLocalAddress) +# define RTSocketGetPeerAddress RT_MANGLER(RTSocketGetPeerAddress) +# define RTSocketParseInetAddress RT_MANGLER(RTSocketParseInetAddress) +# define RTSocketRead RT_MANGLER(RTSocketRead) +# define RTSocketReadFrom RT_MANGLER(RTSocketReadFrom) +# define RTSocketReadNB RT_MANGLER(RTSocketReadNB) +# define RTSocketRelease RT_MANGLER(RTSocketRelease) +# define RTSocketRetain RT_MANGLER(RTSocketRetain) +# define RTSocketSelectOne RT_MANGLER(RTSocketSelectOne) +# define RTSocketSelectOneEx RT_MANGLER(RTSocketSelectOneEx) +# define RTSocketSetInheritance RT_MANGLER(RTSocketSetInheritance) +# define RTSocketSgWrite RT_MANGLER(RTSocketSgWrite) +# define RTSocketSgWriteL RT_MANGLER(RTSocketSgWriteL) +# define RTSocketSgWriteLNB RT_MANGLER(RTSocketSgWriteLNB) +# define RTSocketSgWriteLV RT_MANGLER(RTSocketSgWriteLV) +# define RTSocketSgWriteLVNB RT_MANGLER(RTSocketSgWriteLVNB) +# define RTSocketSgWriteNB RT_MANGLER(RTSocketSgWriteNB) +# define RTSocketShutdown RT_MANGLER(RTSocketShutdown) +# define RTSocketToNative RT_MANGLER(RTSocketToNative) +# define RTSocketWrite RT_MANGLER(RTSocketWrite) +# define RTSocketWriteNB RT_MANGLER(RTSocketWriteNB) +# define RTSocketWriteTo RT_MANGLER(RTSocketWriteTo) +# define RTSocketWriteToNB RT_MANGLER(RTSocketWriteToNB) +# define RTSortApvIsSorted RT_MANGLER(RTSortApvIsSorted) +# define RTSortApvShell RT_MANGLER(RTSortApvShell) +# define RTSortIsSorted RT_MANGLER(RTSortIsSorted) +# define RTSortShell RT_MANGLER(RTSortShell) +# define RTSpinlockAcquire RT_MANGLER(RTSpinlockAcquire) +# define RTSpinlockAcquireNoInts RT_MANGLER(RTSpinlockAcquireNoInts) +# define RTSpinlockCreate RT_MANGLER(RTSpinlockCreate) +# define RTSpinlockDestroy RT_MANGLER(RTSpinlockDestroy) +# define RTSpinlockRelease RT_MANGLER(RTSpinlockRelease) +# define RTStrAAppendExNVTag RT_MANGLER(RTStrAAppendExNVTag) +# define RTStrAAppendNTag RT_MANGLER(RTStrAAppendNTag) +# define RTStrAAppendTag RT_MANGLER(RTStrAAppendTag) +# define RTStrAllocExTag RT_MANGLER(RTStrAllocExTag) +# define RTStrAllocTag RT_MANGLER(RTStrAllocTag) +# define RTStrAPrintf2VTag RT_MANGLER(RTStrAPrintf2VTag) +# define RTStrAPrintfVTag RT_MANGLER(RTStrAPrintfVTag) +# define RTStrATruncateTag RT_MANGLER(RTStrATruncateTag) +# define RTStrCacheCreate RT_MANGLER(RTStrCacheCreate) +# define RTStrCacheDestroy RT_MANGLER(RTStrCacheDestroy) +# define RTStrCacheEnter RT_MANGLER(RTStrCacheEnter) +# define RTStrCacheEnterLower RT_MANGLER(RTStrCacheEnterLower) +# define RTStrCacheEnterLowerN RT_MANGLER(RTStrCacheEnterLowerN) +# define RTStrCacheEnterN RT_MANGLER(RTStrCacheEnterN) +# define RTStrCacheGetStats RT_MANGLER(RTStrCacheGetStats) +# define RTStrCacheIsRealImpl RT_MANGLER(RTStrCacheIsRealImpl) +# define RTStrCacheLength RT_MANGLER(RTStrCacheLength) +# define RTStrCacheRelease RT_MANGLER(RTStrCacheRelease) +# define RTStrCacheRetain RT_MANGLER(RTStrCacheRetain) +# define RTStrCalcLatin1Len RT_MANGLER(RTStrCalcLatin1Len) +# define RTStrCalcLatin1LenEx RT_MANGLER(RTStrCalcLatin1LenEx) +# define RTStrCalcUtf16Len RT_MANGLER(RTStrCalcUtf16Len) +# define RTStrCalcUtf16LenEx RT_MANGLER(RTStrCalcUtf16LenEx) +# define RTStrCat RT_MANGLER(RTStrCat) +# define RTStrCatEx RT_MANGLER(RTStrCatEx) +# define RTStrCatP RT_MANGLER(RTStrCatP) +# define RTStrCatPEx RT_MANGLER(RTStrCatPEx) +# define RTStrCmp RT_MANGLER(RTStrCmp) +# define RTStrConvertHexBytes RT_MANGLER(RTStrConvertHexBytes) +# define RTStrConvertHexBytesEx RT_MANGLER(RTStrConvertHexBytesEx) +# define RTStrCopy RT_MANGLER(RTStrCopy) +# define RTStrCopyEx RT_MANGLER(RTStrCopyEx) +# define RTStrCopyP RT_MANGLER(RTStrCopyP) +# define RTStrCopyPEx RT_MANGLER(RTStrCopyPEx) +# define RTStrCurrentCPToUtf8Tag RT_MANGLER(RTStrCurrentCPToUtf8Tag) +# define RTStrConsoleCPToUtf8Tag RT_MANGLER(RTStrConsoleCPToUtf8Tag) +# define RTStrDupExTag RT_MANGLER(RTStrDupExTag) +# define RTStrDupNTag RT_MANGLER(RTStrDupNTag) +# define RTStrDupNExTag RT_MANGLER(RTStrDupNExTag) +# define RTStrDupTag RT_MANGLER(RTStrDupTag) +# define RTStrEnd RT_MANGLER(RTStrEnd) +# define RTStrEnd_EndProc RT_MANGLER(RTStrEnd_EndProc) +# define RTStrFormat RT_MANGLER(RTStrFormat) +# define RTStrFormatNumber RT_MANGLER(RTStrFormatNumber) +# define RTStrFormatR32 RT_MANGLER(RTStrFormatR32) +# define RTStrFormatR64 RT_MANGLER(RTStrFormatR64) +# define RTStrFormatR80 RT_MANGLER(RTStrFormatR80) +# define RTStrFormatR80u2 RT_MANGLER(RTStrFormatR80u2) +# define RTStrFormatTypeDeregister RT_MANGLER(RTStrFormatTypeDeregister) +# define RTStrFormatTypeRegister RT_MANGLER(RTStrFormatTypeRegister) +# define RTStrFormatTypeSetUser RT_MANGLER(RTStrFormatTypeSetUser) +# define RTStrFormatU128 RT_MANGLER(RTStrFormatU128) +# define RTStrFormatU256 RT_MANGLER(RTStrFormatU256) +# define RTStrFormatU512 RT_MANGLER(RTStrFormatU512) +# define RTStrFormatU16 RT_MANGLER(RTStrFormatU16) +# define RTStrFormatU32 RT_MANGLER(RTStrFormatU32) +# define RTStrFormatU64 RT_MANGLER(RTStrFormatU64) +# define RTStrFormatU8 RT_MANGLER(RTStrFormatU8) +# define RTStrFormatV RT_MANGLER(RTStrFormatV) +# define RTStrFree RT_MANGLER(RTStrFree) +# define RTStrGetCpExInternal RT_MANGLER(RTStrGetCpExInternal) +# define RTStrGetCpInternal RT_MANGLER(RTStrGetCpInternal) +# define RTStrGetCpNExInternal RT_MANGLER(RTStrGetCpNExInternal) +# define RTStrHash1 RT_MANGLER(RTStrHash1) +# define RTStrHash1ExN RT_MANGLER(RTStrHash1ExN) +# define RTStrHash1ExNV RT_MANGLER(RTStrHash1ExNV) +# define RTStrHash1N RT_MANGLER(RTStrHash1N) +# define RTStrICmp RT_MANGLER(RTStrICmp) +# define RTStrICmpAscii RT_MANGLER(RTStrICmpAscii) +# define RTStrIStartsWith RT_MANGLER(RTStrIStartsWith) +# define RTStrIStr RT_MANGLER(RTStrIStr) +# define RTStrIsCaseFoldable RT_MANGLER(RTStrIsCaseFoldable) +# define RTStrIsLowerCased RT_MANGLER(RTStrIsLowerCased) +# define RTStrIsUpperCased RT_MANGLER(RTStrIsUpperCased) +# define RTStrIsValidEncoding RT_MANGLER(RTStrIsValidEncoding) +# define RTStrMemFind16 RT_MANGLER(RTStrMemFind16) +# define RTStrMemFind16_EndProc RT_MANGLER(RTStrMemFind16_EndProc) +# define RTStrMemFind32 RT_MANGLER(RTStrMemFind32) +# define RTStrMemFind32_EndProc RT_MANGLER(RTStrMemFind32_EndProc) +# define RTStrMemFind64 RT_MANGLER(RTStrMemFind64) +# define RTStrMemFind64_EndProc RT_MANGLER(RTStrMemFind64_EndProc) +# define RTStrSplit RT_MANGLER(RTStrSplit) +# define RTStrmClearError RT_MANGLER(RTStrmClearError) +# define RTStrmClose RT_MANGLER(RTStrmClose) +# define RTStrmError RT_MANGLER(RTStrmError) +# define RTStrmFlush RT_MANGLER(RTStrmFlush) +# define RTStrmGetCh RT_MANGLER(RTStrmGetCh) +# define RTStrmGetLine RT_MANGLER(RTStrmGetLine) +# define RTStrmOpen RT_MANGLER(RTStrmOpen) +# define RTStrmOpenF RT_MANGLER(RTStrmOpenF) +# define RTStrmOpenFV RT_MANGLER(RTStrmOpenFV) +# define RTStrmOpenFileHandle RT_MANGLER(RTStrmOpenFileHandle) +# define RTStrmQueryFileHandle RT_MANGLER(RTStrmQueryFileHandle) +# define RTStrmPrintf RT_MANGLER(RTStrmPrintf) +# define RTStrmPrintfV RT_MANGLER(RTStrmPrintfV) +# define RTStrmWrappedPrintf RT_MANGLER(RTStrmWrappedPrintf) +# define RTStrmWrappedPrintfV RT_MANGLER(RTStrmWrappedPrintfV) +# define RTStrmDumpPrintfV RT_MANGLER(RTStrmDumpPrintfV) +# define RTStrmPutCh RT_MANGLER(RTStrmPutCh) +# define RTStrmPutStr RT_MANGLER(RTStrmPutStr) +# define RTStrmReadEx RT_MANGLER(RTStrmReadEx) +# define RTStrmRewind RT_MANGLER(RTStrmRewind) +# define RTStrmSetBufferingMode RT_MANGLER(RTStrmSetBufferingMode) +# define RTStrmSetMode RT_MANGLER(RTStrmSetMode) +# define RTStrmSeek RT_MANGLER(RTStrmSeek) +# define RTStrmTell RT_MANGLER(RTStrmTell) +# define RTStrmWriteEx RT_MANGLER(RTStrmWriteEx) +# define RTStrmIsTerminal RT_MANGLER(RTStrmIsTerminal) +# define RTStrmInputGetEchoChars RT_MANGLER(RTStrmInputGetEchoChars) +# define RTStrmInputSetEchoChars RT_MANGLER(RTStrmInputSetEchoChars) +# define RTStrmQueryTerminalWidth RT_MANGLER(RTStrmQueryTerminalWidth) +# define RTStrNanLongDouble RT_MANGLER(RTStrNanLongDouble) +# define RTStrNanDouble RT_MANGLER(RTStrNanDouble) +# define RTStrNanFloat RT_MANGLER(RTStrNanFloat) +# define RTStrNCmp RT_MANGLER(RTStrNCmp) +# define RTStrNICmp RT_MANGLER(RTStrNICmp) +# define RTStrNICmpAscii RT_MANGLER(RTStrNICmpAscii) +# define RTStrNLen RT_MANGLER(RTStrNLen) +# define RTStrNLenEx RT_MANGLER(RTStrNLenEx) +# define RTStrPrevCp RT_MANGLER(RTStrPrevCp) +# define RTStrPrintf RT_MANGLER(RTStrPrintf) +# define RTStrPrintfEx RT_MANGLER(RTStrPrintfEx) +# define RTStrPrintfExV RT_MANGLER(RTStrPrintfExV) +# define RTStrPrintfV RT_MANGLER(RTStrPrintfV) +# define RTStrPrintf2 RT_MANGLER(RTStrPrintf2) +# define RTStrPrintf2Ex RT_MANGLER(RTStrPrintf2Ex) +# define RTStrPrintf2ExV RT_MANGLER(RTStrPrintf2ExV) +# define RTStrPrintf2V RT_MANGLER(RTStrPrintf2V) +# define RTStrPrintHexBytes RT_MANGLER(RTStrPrintHexBytes) +# define RTStrPurgeEncoding RT_MANGLER(RTStrPurgeEncoding) +# define RTStrPurgeComplementSet RT_MANGLER(RTStrPurgeComplementSet) +# define RTStrPutCpInternal RT_MANGLER(RTStrPutCpInternal) +# define RTStrReallocTag RT_MANGLER(RTStrReallocTag) +# define RTStrSimplePatternMatch RT_MANGLER(RTStrSimplePatternMatch) +# define RTStrSimplePatternMultiMatch RT_MANGLER(RTStrSimplePatternMultiMatch) +# define RTStrSimplePatternNMatch RT_MANGLER(RTStrSimplePatternNMatch) +# define RTStrSpaceDestroy RT_MANGLER(RTStrSpaceDestroy) +# define RTStrSpaceEnumerate RT_MANGLER(RTStrSpaceEnumerate) +# define RTStrSpaceGet RT_MANGLER(RTStrSpaceGet) +# define RTStrSpaceGetN RT_MANGLER(RTStrSpaceGetN) +# define RTStrSpaceInsert RT_MANGLER(RTStrSpaceInsert) +# define RTStrSpaceRemove RT_MANGLER(RTStrSpaceRemove) +# define RTStrStartsWith RT_MANGLER(RTStrStartsWith) +# define RTStrStr RT_MANGLER(RTStrStr) +# define RTStrStrip RT_MANGLER(RTStrStrip) +# define RTStrStripL RT_MANGLER(RTStrStripL) +# define RTStrStripR RT_MANGLER(RTStrStripR) +# define RTStrToInt16 RT_MANGLER(RTStrToInt16) +# define RTStrToInt16Ex RT_MANGLER(RTStrToInt16Ex) +# define RTStrToInt16Full RT_MANGLER(RTStrToInt16Full) +# define RTStrToInt32 RT_MANGLER(RTStrToInt32) +# define RTStrToInt32Ex RT_MANGLER(RTStrToInt32Ex) +# define RTStrToInt32Full RT_MANGLER(RTStrToInt32Full) +# define RTStrToInt64 RT_MANGLER(RTStrToInt64) +# define RTStrToInt64Ex RT_MANGLER(RTStrToInt64Ex) +# define RTStrToInt64Full RT_MANGLER(RTStrToInt64Full) +# define RTStrToInt8 RT_MANGLER(RTStrToInt8) +# define RTStrToInt8Ex RT_MANGLER(RTStrToInt8Ex) +# define RTStrToInt8Full RT_MANGLER(RTStrToInt8Full) +# define RTStrToLatin1ExTag RT_MANGLER(RTStrToLatin1ExTag) +# define RTStrToLatin1Tag RT_MANGLER(RTStrToLatin1Tag) +# define RTStrToLower RT_MANGLER(RTStrToLower) +# define RTStrToUInt16 RT_MANGLER(RTStrToUInt16) +# define RTStrToUInt16Ex RT_MANGLER(RTStrToUInt16Ex) +# define RTStrToUInt16Full RT_MANGLER(RTStrToUInt16Full) +# define RTStrToUInt32 RT_MANGLER(RTStrToUInt32) +# define RTStrToUInt32Ex RT_MANGLER(RTStrToUInt32Ex) +# define RTStrToUInt32Full RT_MANGLER(RTStrToUInt32Full) +# define RTStrToUInt64 RT_MANGLER(RTStrToUInt64) +# define RTStrToUInt64Ex RT_MANGLER(RTStrToUInt64Ex) +# define RTStrToUInt64Full RT_MANGLER(RTStrToUInt64Full) +# define RTStrToUInt8 RT_MANGLER(RTStrToUInt8) +# define RTStrToUInt8Ex RT_MANGLER(RTStrToUInt8Ex) +# define RTStrToUInt8Full RT_MANGLER(RTStrToUInt8Full) +# define RTStrToFloatEx RT_MANGLER(RTStrToFloatEx) +# define RTStrToDoubleEx RT_MANGLER(RTStrToDoubleEx) +# define RTStrToLongDoubleEx RT_MANGLER(RTStrToLongDoubleEx) +# define RTStrToUni RT_MANGLER(RTStrToUni) +# define RTStrToUniEx RT_MANGLER(RTStrToUniEx) +# define RTStrToUpper RT_MANGLER(RTStrToUpper) +# define RTStrToUtf16BigExTag RT_MANGLER(RTStrToUtf16BigExTag) +# define RTStrToUtf16BigTag RT_MANGLER(RTStrToUtf16BigTag) +# define RTStrToUtf16ExTag RT_MANGLER(RTStrToUtf16ExTag) +# define RTStrToUtf16Tag RT_MANGLER(RTStrToUtf16Tag) +# define RTStrUniLen RT_MANGLER(RTStrUniLen) +# define RTStrUniLenEx RT_MANGLER(RTStrUniLenEx) +# define RTStrUtf8ToCurrentCPTag RT_MANGLER(RTStrUtf8ToCurrentCPTag) +# define RTStrUtf8ToCurrentCPExTag RT_MANGLER(RTStrUtf8ToCurrentCPExTag) +# define RTStrValidateEncoding RT_MANGLER(RTStrValidateEncoding) +# define RTStrValidateEncodingEx RT_MANGLER(RTStrValidateEncodingEx) +# define RTStrVersionCompare RT_MANGLER(RTStrVersionCompare) +# define RTSymlinkCreate RT_MANGLER(RTSymlinkCreate) +# define RTSymlinkDelete RT_MANGLER(RTSymlinkDelete) +# define RTSymlinkExists RT_MANGLER(RTSymlinkExists) +# define RTSymlinkIsDangling RT_MANGLER(RTSymlinkIsDangling) +# define RTSymlinkRead RT_MANGLER(RTSymlinkRead) +# define RTSymlinkReadA RT_MANGLER(RTSymlinkReadA) +# define RTSystemQueryFirmwareType RT_MANGLER(RTSystemQueryFirmwareType) +# define RTSystemQueryFirmwareBoolean RT_MANGLER(RTSystemQueryFirmwareBoolean) +# define RTSystemFirmwareTypeName RT_MANGLER(RTSystemFirmwareTypeName) +# define RTSystemIsInsideVM RT_MANGLER(RTSystemIsInsideVM) +# define RTSystemQueryAvailableRam RT_MANGLER(RTSystemQueryAvailableRam) +# define RTSystemQueryDmiString RT_MANGLER(RTSystemQueryDmiString) +# define RTSystemQueryOSInfo RT_MANGLER(RTSystemQueryOSInfo) +# define RTSystemQueryTotalRam RT_MANGLER(RTSystemQueryTotalRam) +# define RTSystemShutdown RT_MANGLER(RTSystemShutdown) +# define RTTarClose RT_MANGLER(RTTarClose) +# define RTTarFileClose RT_MANGLER(RTTarFileClose) +# define RTTarFileGetSize RT_MANGLER(RTTarFileGetSize) +# define RTTarFileOpen RT_MANGLER(RTTarFileOpen) +# define RTTarFileReadAt RT_MANGLER(RTTarFileReadAt) +# define RTTarFileSetSize RT_MANGLER(RTTarFileSetSize) +# define RTTarFileWriteAt RT_MANGLER(RTTarFileWriteAt) +# define RTTarOpen RT_MANGLER(RTTarOpen) +# define RTTcpClientCancelConnect RT_MANGLER(RTTcpClientCancelConnect) +# define RTTcpClientClose RT_MANGLER(RTTcpClientClose) +# define RTTcpClientCloseEx RT_MANGLER(RTTcpClientCloseEx) +# define RTTcpClientConnect RT_MANGLER(RTTcpClientConnect) +# define RTTcpClientConnectEx RT_MANGLER(RTTcpClientConnectEx) +# define RTTcpCreatePair RT_MANGLER(RTTcpCreatePair) +# define RTTcpFlush RT_MANGLER(RTTcpFlush) +# define RTTcpGetLocalAddress RT_MANGLER(RTTcpGetLocalAddress) +# define RTTcpGetPeerAddress RT_MANGLER(RTTcpGetPeerAddress) +# define RTTcpRead RT_MANGLER(RTTcpRead) +# define RTTcpReadNB RT_MANGLER(RTTcpReadNB) +# define RTTcpSelectOne RT_MANGLER(RTTcpSelectOne) +# define RTTcpSelectOneEx RT_MANGLER(RTTcpSelectOneEx) +# define RTTcpServerCreate RT_MANGLER(RTTcpServerCreate) +# define RTTcpServerCreateEx RT_MANGLER(RTTcpServerCreateEx) +# define RTTcpServerDestroy RT_MANGLER(RTTcpServerDestroy) +# define RTTcpServerDisconnectClient RT_MANGLER(RTTcpServerDisconnectClient) +# define RTTcpServerDisconnectClient2 RT_MANGLER(RTTcpServerDisconnectClient2) +# define RTTcpServerListen RT_MANGLER(RTTcpServerListen) +# define RTTcpServerListen2 RT_MANGLER(RTTcpServerListen2) +# define RTTcpServerShutdown RT_MANGLER(RTTcpServerShutdown) +# define RTTcpSetSendCoalescing RT_MANGLER(RTTcpSetSendCoalescing) +# define RTTcpSetBufferSize RT_MANGLER(RTTcpSetBufferSize) +# define RTTcpSgWrite RT_MANGLER(RTTcpSgWrite) +# define RTTcpSgWriteL RT_MANGLER(RTTcpSgWriteL) +# define RTTcpSgWriteLNB RT_MANGLER(RTTcpSgWriteLNB) +# define RTTcpSgWriteLV RT_MANGLER(RTTcpSgWriteLV) +# define RTTcpSgWriteLVNB RT_MANGLER(RTTcpSgWriteLVNB) +# define RTTcpSgWriteNB RT_MANGLER(RTTcpSgWriteNB) +# define RTTcpWrite RT_MANGLER(RTTcpWrite) +# define RTTcpWriteNB RT_MANGLER(RTTcpWriteNB) +# define RTTermDeregisterCallback RT_MANGLER(RTTermDeregisterCallback) +# define RTTermRegisterCallback RT_MANGLER(RTTermRegisterCallback) +# define RTTermRunCallbacks RT_MANGLER(RTTermRunCallbacks) +# define RTTestBanner RT_MANGLER(RTTestBanner) +# define RTTestChangeName RT_MANGLER(RTTestChangeName) +# define RTTestCreate RT_MANGLER(RTTestCreate) +# define RTTestCreateChild RT_MANGLER(RTTestCreateChild) +# define RTTestCreateEx RT_MANGLER(RTTestCreateEx) +# define RTTestDestroy RT_MANGLER(RTTestDestroy) +# define RTTestDisableAssertions RT_MANGLER(RTTestDisableAssertions) +# define RTTestErrContext RT_MANGLER(RTTestErrContext) +# define RTTestErrContextV RT_MANGLER(RTTestErrContextV) +# define RTTestErrorCount RT_MANGLER(RTTestErrorCount) +# define RTTestErrorInc RT_MANGLER(RTTestErrorInc) +# define RTTestFailed RT_MANGLER(RTTestFailed) +# define RTTestFailedV RT_MANGLER(RTTestFailedV) +# define RTTestFailureDetails RT_MANGLER(RTTestFailureDetails) +# define RTTestFailureDetailsV RT_MANGLER(RTTestFailureDetailsV) +# define RTTestGuardedAlloc RT_MANGLER(RTTestGuardedAlloc) +# define RTTestGuardedAllocHead RT_MANGLER(RTTestGuardedAllocHead) +# define RTTestGuardedAllocTail RT_MANGLER(RTTestGuardedAllocTail) +# define RTTestGuardedFree RT_MANGLER(RTTestGuardedFree) +# define RTTestIDisableAssertions RT_MANGLER(RTTestIDisableAssertions) +# define RTTestIErrContext RT_MANGLER(RTTestIErrContext) +# define RTTestIErrContextV RT_MANGLER(RTTestIErrContextV) +# define RTTestIErrorCount RT_MANGLER(RTTestIErrorCount) +# define RTTestIErrorInc RT_MANGLER(RTTestIErrorInc) +# define RTTestIFailed RT_MANGLER(RTTestIFailed) +# define RTTestIFailedRc RT_MANGLER(RTTestIFailedRc) +# define RTTestIFailedRcV RT_MANGLER(RTTestIFailedRcV) +# define RTTestIFailedV RT_MANGLER(RTTestIFailedV) +# define RTTestIFailureDetails RT_MANGLER(RTTestIFailureDetails) +# define RTTestIFailureDetailsV RT_MANGLER(RTTestIFailureDetailsV) +# define RTTestInitAndCreate RT_MANGLER(RTTestInitAndCreate) +# define RTTestInitExAndCreate RT_MANGLER(RTTestInitExAndCreate) +# define RTTestIPassed RT_MANGLER(RTTestIPassed) +# define RTTestIPassedV RT_MANGLER(RTTestIPassedV) +# define RTTestIPrintf RT_MANGLER(RTTestIPrintf) +# define RTTestIPrintfV RT_MANGLER(RTTestIPrintfV) +# define RTTestIRestoreAssertions RT_MANGLER(RTTestIRestoreAssertions) +# define RTTestISub RT_MANGLER(RTTestISub) +# define RTTestISubDone RT_MANGLER(RTTestISubDone) +# define RTTestISubF RT_MANGLER(RTTestISubF) +# define RTTestISubV RT_MANGLER(RTTestISubV) +# define RTTestIValue RT_MANGLER(RTTestIValue) +# define RTTestIValueF RT_MANGLER(RTTestIValueF) +# define RTTestIValueV RT_MANGLER(RTTestIValueV) +# define RTTestPassed RT_MANGLER(RTTestPassed) +# define RTTestPassedV RT_MANGLER(RTTestPassedV) +# define RTTestPrintf RT_MANGLER(RTTestPrintf) +# define RTTestPrintfNl RT_MANGLER(RTTestPrintfNl) +# define RTTestPrintfNlV RT_MANGLER(RTTestPrintfNlV) +# define RTTestPrintfV RT_MANGLER(RTTestPrintfV) +# define RTTestRestoreAssertions RT_MANGLER(RTTestRestoreAssertions) +# define RTTestSetDefault RT_MANGLER(RTTestSetDefault) +# define RTTestSkipAndDestroy RT_MANGLER(RTTestSkipAndDestroy) +# define RTTestSkipAndDestroyV RT_MANGLER(RTTestSkipAndDestroyV) +# define RTTestSkipped RT_MANGLER(RTTestSkipped) +# define RTTestSkippedV RT_MANGLER(RTTestSkippedV) +# define RTTestSub RT_MANGLER(RTTestSub) +# define RTTestSubDone RT_MANGLER(RTTestSubDone) +# define RTTestSubErrorCount RT_MANGLER(RTTestSubErrorCount) +# define RTTestSubF RT_MANGLER(RTTestSubF) +# define RTTestSubV RT_MANGLER(RTTestSubV) +# define RTTestSummaryAndDestroy RT_MANGLER(RTTestSummaryAndDestroy) +# define RTTestValue RT_MANGLER(RTTestValue) +# define RTTestValueF RT_MANGLER(RTTestValueF) +# define RTTestValueV RT_MANGLER(RTTestValueV) +# define RTThreadAdopt RT_MANGLER(RTThreadAdopt) +# define RTThreadBlocking RT_MANGLER(RTThreadBlocking) +# define RTThreadCreate RT_MANGLER(RTThreadCreate) +# define RTThreadCreateF RT_MANGLER(RTThreadCreateF) +# define RTThreadCreateV RT_MANGLER(RTThreadCreateV) +# define RTThreadCtxHookIsEnabled RT_MANGLER(RTThreadCtxHookIsEnabled) /* r0drv */ +# define RTThreadCtxHookCreate RT_MANGLER(RTThreadCtxHookCreate) /* r0drv */ +# define RTThreadCtxHookDestroy RT_MANGLER(RTThreadCtxHookDestroy) /* r0drv */ +# define RTThreadCtxHookDisable RT_MANGLER(RTThreadCtxHookDisable) /* r0drv */ +# define RTThreadCtxHookEnable RT_MANGLER(RTThreadCtxHookEnable) /* r0drv */ +# define RTThreadFromNative RT_MANGLER(RTThreadFromNative) +# define RTThreadGetAffinity RT_MANGLER(RTThreadGetAffinity) +# define RTThreadGetExecutionTimeMilli RT_MANGLER(RTThreadGetExecutionTimeMilli) +# define RTThreadGetName RT_MANGLER(RTThreadGetName) +# define RTThreadGetNative RT_MANGLER(RTThreadGetNative) +# define RTThreadGetNativeHandle RT_MANGLER(RTThreadGetNativeHandle) +# define RTThreadGetNativeState RT_MANGLER(RTThreadGetNativeState) +# define RTThreadGetReallySleeping RT_MANGLER(RTThreadGetReallySleeping) +# define RTThreadGetState RT_MANGLER(RTThreadGetState) +# define RTThreadGetType RT_MANGLER(RTThreadGetType) +# define RTThreadIsInInterrupt RT_MANGLER(RTThreadIsInInterrupt) /* r0drv */ +# define RTThreadIsInitialized RT_MANGLER(RTThreadIsInitialized) +# define RTThreadIsMain RT_MANGLER(RTThreadIsMain) +# define RTThreadIsSelfAlive RT_MANGLER(RTThreadIsSelfAlive) +# define RTThreadIsSelfKnown RT_MANGLER(RTThreadIsSelfKnown) +# define RTThreadNativeSelf RT_MANGLER(RTThreadNativeSelf) +# define RTThreadControlPokeSignal RT_MANGLER(RTThreadControlPokeSignal) /* not-win not-os2 */ +# define RTThreadPoke RT_MANGLER(RTThreadPoke) /* not-win not-os2 */ +# define RTThreadPreemptDisable RT_MANGLER(RTThreadPreemptDisable) /* r0drv */ +# define RTThreadPreemptIsEnabled RT_MANGLER(RTThreadPreemptIsEnabled) /* r0drv */ +# define RTThreadPreemptIsPending RT_MANGLER(RTThreadPreemptIsPending) /* r0drv */ +# define RTThreadPreemptIsPendingTrusty RT_MANGLER(RTThreadPreemptIsPendingTrusty) /* r0drv */ +# define RTThreadPreemptIsPossible RT_MANGLER(RTThreadPreemptIsPossible) /* r0drv */ +# define RTThreadPreemptRestore RT_MANGLER(RTThreadPreemptRestore) /* r0drv */ +# define RTThreadQueryTerminationStatus RT_MANGLER(RTThreadQueryTerminationStatus) /* r0drv */ +# define RTThreadSelf RT_MANGLER(RTThreadSelf) +# define RTThreadSelfAutoAdopt RT_MANGLER(RTThreadSelfAutoAdopt) +# define RTThreadSelfName RT_MANGLER(RTThreadSelfName) +# define RTThreadSetAffinity RT_MANGLER(RTThreadSetAffinity) +# define RTThreadSetAffinityToCpu RT_MANGLER(RTThreadSetAffinityToCpu) +# define RTThreadSetName RT_MANGLER(RTThreadSetName) +# define RTThreadSetType RT_MANGLER(RTThreadSetType) +# define RTThreadSleep RT_MANGLER(RTThreadSleep) +# define RTThreadSleepNoLog RT_MANGLER(RTThreadSleepNoLog) +# define RTThreadStateName RT_MANGLER(RTThreadStateName) +# define RTThreadUnblocked RT_MANGLER(RTThreadUnblocked) +# define RTThreadUserReset RT_MANGLER(RTThreadUserReset) +# define RTThreadUserSignal RT_MANGLER(RTThreadUserSignal) +# define RTThreadUserWait RT_MANGLER(RTThreadUserWait) +# define RTThreadUserWaitNoResume RT_MANGLER(RTThreadUserWaitNoResume) +# define RTThreadWait RT_MANGLER(RTThreadWait) +# define RTThreadWaitNoResume RT_MANGLER(RTThreadWaitNoResume) +# define RTThreadYield RT_MANGLER(RTThreadYield) +# define RTTimeCompare RT_MANGLER(RTTimeCompare) +# define RTTimeConvertToZulu RT_MANGLER(RTTimeConvertToZulu) +# define RTTimeDbgBad RT_MANGLER(RTTimeDbgBad) +# define RTTimeDbgExpired RT_MANGLER(RTTimeDbgExpired) +# define RTTimeDbgRaces RT_MANGLER(RTTimeDbgRaces) +# define RTTimeDbgSteps RT_MANGLER(RTTimeDbgSteps) +# define RTTimeFormatDuration RT_MANGLER(RTTimeFormatDuration) +# define RTTimeFormatDurationEx RT_MANGLER(RTTimeFormatDurationEx) +# define RTTimeExplode RT_MANGLER(RTTimeExplode) +# define RTTimeImplode RT_MANGLER(RTTimeImplode) +# define RTTimeIsLeapYear RT_MANGLER(RTTimeIsLeapYear) +# define RTTimeLocalDeltaNano RT_MANGLER(RTTimeLocalDeltaNano) +# define RTTimeLocalDeltaNanoFor RT_MANGLER(RTTimeLocalDeltaNanoFor) +# define RTTimeLocalExplode RT_MANGLER(RTTimeLocalExplode) +# define RTTimeLocalNormalize RT_MANGLER(RTTimeLocalNormalize) +# define RTTimeLocalNow RT_MANGLER(RTTimeLocalNow) +# define RTTimeMilliTS RT_MANGLER(RTTimeMilliTS) +# define RTTimeNanoTS RT_MANGLER(RTTimeNanoTS) +# define RTTimeNanoTSLegacyAsync RT_MANGLER(RTTimeNanoTSLegacyAsync) +# define RTTimeNanoTSLegacyAsync_EndProc RT_MANGLER(RTTimeNanoTSLegacyAsync_EndProc) +# define RTTimeNanoTSLegacyAsyncUseApicId RT_MANGLER(RTTimeNanoTSLegacyAsyncUseApicId) +# define RTTimeNanoTSLegacyAsyncUseApicId_EndProc RT_MANGLER(RTTimeNanoTSLegacyAsyncUseApicId_EndProc) +# define RTTimeNanoTSLegacyAsyncUseApicIdExt0B RT_MANGLER(RTTimeNanoTSLegacyAsyncUseApicIdExt0B) +# define RTTimeNanoTSLegacyAsyncUseApicIdExt0B_EndProc RT_MANGLER(RTTimeNanoTSLegacyAsyncUseApicIdExt0B_EndProc) +# define RTTimeNanoTSLegacyAsyncUseApicIdExt8000001E RT_MANGLER(RTTimeNanoTSLegacyAsyncUseApicIdExt8000001E) +# define RTTimeNanoTSLegacyAsyncUseApicIdExt8000001E_EndProc RT_MANGLER(RTTimeNanoTSLegacyAsyncUseApicIdExt8000001E_EndProc) +# define RTTimeNanoTSLegacyAsyncUseRdtscp RT_MANGLER(RTTimeNanoTSLegacyAsyncUseRdtscp) +# define RTTimeNanoTSLegacyAsyncUseRdtscp_EndProc RT_MANGLER(RTTimeNanoTSLegacyAsyncUseRdtscp_EndProc) +# define RTTimeNanoTSLegacyAsyncUseRdtscpGroupChNumCl RT_MANGLER(RTTimeNanoTSLegacyAsyncUseRdtscpGroupChNumCl) +# define RTTimeNanoTSLegacyAsyncUseRdtscpGroupChNumCl_EndProc RT_MANGLER(RTTimeNanoTSLegacyAsyncUseRdtscpGroupChNumCl_EndProc) +# define RTTimeNanoTSLegacyAsyncUseIdtrLim RT_MANGLER(RTTimeNanoTSLegacyAsyncUseIdtrLim) +# define RTTimeNanoTSLegacyAsyncUseIdtrLim_EndProc RT_MANGLER(RTTimeNanoTSLegacyAsyncUseIdtrLim_EndProc) +# define RTTimeNanoTSLegacySyncInvarNoDelta RT_MANGLER(RTTimeNanoTSLegacySyncInvarNoDelta) +# define RTTimeNanoTSLegacySyncInvarNoDelta_EndProc RT_MANGLER(RTTimeNanoTSLegacySyncInvarNoDelta_EndProc) +# define RTTimeNanoTSLegacySyncInvarWithDelta RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDelta) +# define RTTimeNanoTSLegacySyncInvarWithDelta_EndProc RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDelta_EndProc) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseApicId RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseApicId) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseApicId_EndProc RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseApicId_EndProc) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt0B RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt0B) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt0B_EndProc RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt0B_EndProc) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt8000001E RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt8000001E) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt8000001E_EndProc RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt8000001E_EndProc) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseRdtscp RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseRdtscp) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseRdtscp_EndProc RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseRdtscp_EndProc) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseIdtrLim RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseIdtrLim) +# define RTTimeNanoTSLegacySyncInvarWithDeltaUseIdtrLim_EndProc RT_MANGLER(RTTimeNanoTSLegacySyncInvarWithDeltaUseIdtrLim_EndProc) +# define RTTimeNanoTSLFenceAsync RT_MANGLER(RTTimeNanoTSLFenceAsync) +# define RTTimeNanoTSLFenceAsync_EndProc RT_MANGLER(RTTimeNanoTSLFenceAsync_EndProc) +# define RTTimeNanoTSLFenceAsyncUseApicId RT_MANGLER(RTTimeNanoTSLFenceAsyncUseApicId) +# define RTTimeNanoTSLFenceAsyncUseApicId_EndProc RT_MANGLER(RTTimeNanoTSLFenceAsyncUseApicId_EndProc) +# define RTTimeNanoTSLFenceAsyncUseApicIdExt0B RT_MANGLER(RTTimeNanoTSLFenceAsyncUseApicIdExt0B) +# define RTTimeNanoTSLFenceAsyncUseApicIdExt0B_EndProc RT_MANGLER(RTTimeNanoTSLFenceAsyncUseApicIdExt0B_EndProc) +# define RTTimeNanoTSLFenceAsyncUseApicIdExt8000001E RT_MANGLER(RTTimeNanoTSLFenceAsyncUseApicIdExt8000001E) +# define RTTimeNanoTSLFenceAsyncUseApicIdExt8000001E_EndProc RT_MANGLER(RTTimeNanoTSLFenceAsyncUseApicIdExt8000001E_EndProc) +# define RTTimeNanoTSLFenceAsyncUseRdtscp RT_MANGLER(RTTimeNanoTSLFenceAsyncUseRdtscp) +# define RTTimeNanoTSLFenceAsyncUseRdtscp_EndProc RT_MANGLER(RTTimeNanoTSLFenceAsyncUseRdtscp_EndProc) +# define RTTimeNanoTSLFenceAsyncUseRdtscpGroupChNumCl RT_MANGLER(RTTimeNanoTSLFenceAsyncUseRdtscpGroupChNumCl) +# define RTTimeNanoTSLFenceAsyncUseRdtscpGroupChNumCl_EndProc RT_MANGLER(RTTimeNanoTSLFenceAsyncUseRdtscpGroupChNumCl_EndProc) +# define RTTimeNanoTSLFenceAsyncUseIdtrLim RT_MANGLER(RTTimeNanoTSLFenceAsyncUseIdtrLim) +# define RTTimeNanoTSLFenceAsyncUseIdtrLim_EndProc RT_MANGLER(RTTimeNanoTSLFenceAsyncUseIdtrLim_EndProc) +# define RTTimeNanoTSLFenceSyncInvarNoDelta RT_MANGLER(RTTimeNanoTSLFenceSyncInvarNoDelta) +# define RTTimeNanoTSLFenceSyncInvarNoDelta_EndProc RT_MANGLER(RTTimeNanoTSLFenceSyncInvarNoDelta_EndProc) +# define RTTimeNanoTSLFenceSyncInvarWithDelta RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDelta) +# define RTTimeNanoTSLFenceSyncInvarWithDelta_EndProc RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDelta_EndProc) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicId RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicId) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicId_EndProc RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicId_EndProc) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt0B RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt0B) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt0B_EndProc RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt0B_EndProc) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt8000001E RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt8000001E) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt8000001E_EndProc RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt8000001E_EndProc) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseRdtscp RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseRdtscp) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseRdtscp_EndProc RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseRdtscp_EndProc) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseIdtrLim RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseIdtrLim) +# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseIdtrLim_EndProc RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseIdtrLim_EndProc) +# define RTTimeNanoTSWorkerName RT_MANGLER(RTTimeNanoTSWorkerName) +# define RTTimeNormalize RT_MANGLER(RTTimeNormalize) +# define RTTimeNow RT_MANGLER(RTTimeNow) +# define RTTimeProgramMicroTS RT_MANGLER(RTTimeProgramMicroTS) +# define RTTimeProgramMilliTS RT_MANGLER(RTTimeProgramMilliTS) +# define RTTimeProgramNanoTS RT_MANGLER(RTTimeProgramNanoTS) +# define RTTimeProgramSecTS RT_MANGLER(RTTimeProgramSecTS) +# define RTTimeProgramStartNanoTS RT_MANGLER(RTTimeProgramStartNanoTS) +# define RTTimerCanDoHighResolution RT_MANGLER(RTTimerCanDoHighResolution) +# define RTTimerChangeInterval RT_MANGLER(RTTimerChangeInterval) +# define RTTimerCreate RT_MANGLER(RTTimerCreate) +# define RTTimerCreateEx RT_MANGLER(RTTimerCreateEx) +# define RTTimerDestroy RT_MANGLER(RTTimerDestroy) +# define RTTimerGetSystemGranularity RT_MANGLER(RTTimerGetSystemGranularity) /* r0drv */ +# define RTTimerLRCreate RT_MANGLER(RTTimerLRCreate) +# define RTTimerLRCreateEx RT_MANGLER(RTTimerLRCreateEx) +# define RTTimerLRDestroy RT_MANGLER(RTTimerLRDestroy) +# define RTTimerLRStart RT_MANGLER(RTTimerLRStart) +# define RTTimerLRStop RT_MANGLER(RTTimerLRStop) +# define RTTimerLRChangeInterval RT_MANGLER(RTTimerLRChangeInterval) +# define RTTimerReleaseSystemGranularity RT_MANGLER(RTTimerReleaseSystemGranularity) /* r0drv */ +# define RTTimerRequestSystemGranularity RT_MANGLER(RTTimerRequestSystemGranularity) /* r0drv */ +# define RTTimerStart RT_MANGLER(RTTimerStart) +# define RTTimerStop RT_MANGLER(RTTimerStop) +# define RTTimeSet RT_MANGLER(RTTimeSet) +# define RTTimeSpecFromString RT_MANGLER(RTTimeSpecFromString) +# define RTTimeSpecToString RT_MANGLER(RTTimeSpecToString) +# define RTTimeSystemMilliTS RT_MANGLER(RTTimeSystemMilliTS) +# define RTTimeSystemNanoTS RT_MANGLER(RTTimeSystemNanoTS) +# define RTTimeFromString RT_MANGLER(RTTimeFromString) +# define RTTimeFromRfc2822 RT_MANGLER(RTTimeFromRfc2822) +# define RTTimeToString RT_MANGLER(RTTimeToString) +# define RTTimeToStringEx RT_MANGLER(RTTimeToStringEx) +# define RTTimeToRfc2822 RT_MANGLER(RTTimeToRfc2822) +# define RTTimeZoneGetInfoByUnixName RT_MANGLER(RTTimeZoneGetInfoByUnixName) +# define RTTimeZoneGetInfoByWindowsName RT_MANGLER(RTTimeZoneGetInfoByWindowsName) +# define RTTimeZoneGetInfoByWindowsIndex RT_MANGLER(RTTimeZoneGetInfoByWindowsIndex) +# define RTTimeZoneGetCurrent RT_MANGLER(RTTimeZoneGetCurrent) +# define RTTlsAlloc RT_MANGLER(RTTlsAlloc) +# define RTTlsAllocEx RT_MANGLER(RTTlsAllocEx) +# define RTTlsFree RT_MANGLER(RTTlsFree) +# define RTTlsGet RT_MANGLER(RTTlsGet) +# define RTTlsGetEx RT_MANGLER(RTTlsGetEx) +# define RTTlsSet RT_MANGLER(RTTlsSet) +# define RTTpmOpen RT_MANGLER(RTTpmOpen) +# define RTTpmClose RT_MANGLER(RTTpmClose) +# define RTTpmGetLocalityMax RT_MANGLER(RTTpmGetLocalityMax) +# define RTTpmGetVersion RT_MANGLER(RTTpmGetVersion) +# define RTTpmReqCancel RT_MANGLER(RTTpmReqCancel) +# define RTTpmReqExec RT_MANGLER(RTTpmReqExec) +# define RTTraceBufAddMsg RT_MANGLER(RTTraceBufAddMsg) +# define RTTraceBufAddMsgEx RT_MANGLER(RTTraceBufAddMsgEx) +# define RTTraceBufAddMsgF RT_MANGLER(RTTraceBufAddMsgF) +# define RTTraceBufAddMsgV RT_MANGLER(RTTraceBufAddMsgV) +# define RTTraceBufAddPos RT_MANGLER(RTTraceBufAddPos) +# define RTTraceBufAddPosMsg RT_MANGLER(RTTraceBufAddPosMsg) +# define RTTraceBufAddPosMsgEx RT_MANGLER(RTTraceBufAddPosMsgEx) +# define RTTraceBufAddPosMsgF RT_MANGLER(RTTraceBufAddPosMsgF) +# define RTTraceBufAddPosMsgV RT_MANGLER(RTTraceBufAddPosMsgV) +# define RTTraceBufCarve RT_MANGLER(RTTraceBufCarve) +# define RTTraceBufCreate RT_MANGLER(RTTraceBufCreate) +# define RTTraceBufDisable RT_MANGLER(RTTraceBufDisable) +# define RTTraceBufDumpToAssert RT_MANGLER(RTTraceBufDumpToAssert) +# define RTTraceBufDumpToLog RT_MANGLER(RTTraceBufDumpToLog) +# define RTTraceBufEnable RT_MANGLER(RTTraceBufEnable) +# define RTTraceBufEnumEntries RT_MANGLER(RTTraceBufEnumEntries) +# define RTTraceBufGetEntryCount RT_MANGLER(RTTraceBufGetEntryCount) +# define RTTraceBufGetEntrySize RT_MANGLER(RTTraceBufGetEntrySize) +# define RTTraceBufRelease RT_MANGLER(RTTraceBufRelease) +# define RTTraceBufRetain RT_MANGLER(RTTraceBufRetain) +# define RTTraceGetDefaultBuf RT_MANGLER(RTTraceGetDefaultBuf) +# define RTTraceLogRdrCreate RT_MANGLER(RTTraceLogRdrCreate) +# define RTTraceLogRdrCreateFromFile RT_MANGLER(RTTraceLogRdrCreateFromFile) +# define RTTraceLogRdrDestroy RT_MANGLER(RTTraceLogRdrDestroy) +# define RTTraceLogRdrEvtFillVals RT_MANGLER(RTTraceLogRdrEvtFillVals) +# define RTTraceLogRdrEvtGetDesc RT_MANGLER(RTTraceLogRdrEvtGetDesc) +# define RTTraceLogRdrEvtGetSeqNo RT_MANGLER(RTTraceLogRdrEvtGetSeqNo) +# define RTTraceLogRdrEvtGetTs RT_MANGLER(RTTraceLogRdrEvtGetTs) +# define RTTraceLogRdrEvtIsGrouped RT_MANGLER(RTTraceLogRdrEvtIsGrouped) +# define RTTraceLogRdrEvtMapToStruct RT_MANGLER(RTTraceLogRdrEvtMapToStruct) +# define RTTraceLogRdrEvtMapFree RT_MANGLER(RTTraceLogRdrEvtMapFree) +# define RTTraceLogRdrEvtPoll RT_MANGLER(RTTraceLogRdrEvtPoll) +# define RTTraceLogRdrEvtQueryVal RT_MANGLER(RTTraceLogRdrEvtQueryVal) +# define RTTraceLogRdrIteratorFree RT_MANGLER(RTTraceLogRdrIteratorFree) +# define RTTraceLogRdrIteratorNext RT_MANGLER(RTTraceLogRdrIteratorNext) +# define RTTraceLogRdrIteratorQueryEvent RT_MANGLER(RTTraceLogRdrIteratorQueryEvent) +# define RTTraceLogRdrQueryIterator RT_MANGLER(RTTraceLogRdrQueryIterator) +# define RTTraceLogRdrQueryLastEvt RT_MANGLER(RTTraceLogRdrQueryLastEvt) +# define RTTraceLogWrAddEvtDesc RT_MANGLER(RTTraceLogWrAddEvtDesc) +# define RTTraceLogWrCreate RT_MANGLER(RTTraceLogWrCreate) +# define RTTraceLogWrCreateFile RT_MANGLER(RTTraceLogWrCreateFile) +# define RTTraceLogWrCreateTcpClient RT_MANGLER(RTTraceLogWrCreateTcpClient) +# define RTTraceLogWrCreateTcpServer RT_MANGLER(RTTraceLogWrCreateTcpServer) +# define RTTraceLogWrDestroy RT_MANGLER(RTTraceLogWrDestroy) +# define RTTraceLogWrEvtAdd RT_MANGLER(RTTraceLogWrEvtAdd) +# define RTTraceLogWrEvtAddL RT_MANGLER(RTTraceLogWrEvtAddL) +# define RTTraceLogWrEvtAddLV RT_MANGLER(RTTraceLogWrEvtAddLV) +# define RTTraceLogWrEvtAddSg RT_MANGLER(RTTraceLogWrEvtAddSg) +# define RTTraceSetDefaultBuf RT_MANGLER(RTTraceSetDefaultBuf) +# define RTUdpCreateClientSocket RT_MANGLER(RTUdpCreateClientSocket) +# define RTUdpCreateServerSocket RT_MANGLER(RTUdpCreateServerSocket) +# define RTUdpRead RT_MANGLER(RTUdpRead) +# define RTUdpServerCreate RT_MANGLER(RTUdpServerCreate) +# define RTUdpServerCreateEx RT_MANGLER(RTUdpServerCreateEx) +# define RTUdpServerDestroy RT_MANGLER(RTUdpServerDestroy) +# define RTUdpServerListen RT_MANGLER(RTUdpServerListen) +# define RTUdpServerShutdown RT_MANGLER(RTUdpServerShutdown) +# define RTUdpWrite RT_MANGLER(RTUdpWrite) +# define RTUniFree RT_MANGLER(RTUniFree) +# define RTUriCreate RT_MANGLER(RTUriCreate) +# define RTUriFileCreate RT_MANGLER(RTUriFileCreate) +# define RTUriFileCreateEx RT_MANGLER(RTUriFileCreateEx) +# define RTUriFilePath RT_MANGLER(RTUriFilePath) +# define RTUriFilePathEx RT_MANGLER(RTUriFilePathEx) +# define RTUriParse RT_MANGLER(RTUriParse) +# define RTUriParsedAuthority RT_MANGLER(RTUriParsedAuthority) +# define RTUriParsedAuthorityHost RT_MANGLER(RTUriParsedAuthorityHost) +# define RTUriParsedAuthorityPassword RT_MANGLER(RTUriParsedAuthorityPassword) +# define RTUriParsedAuthorityPort RT_MANGLER(RTUriParsedAuthorityPort) +# define RTUriParsedAuthorityUsername RT_MANGLER(RTUriParsedAuthorityUsername) +# define RTUriParsedFragment RT_MANGLER(RTUriParsedFragment) +# define RTUriParsedPath RT_MANGLER(RTUriParsedPath) +# define RTUriParsedScheme RT_MANGLER(RTUriParsedScheme) +# define RTUriParsedQuery RT_MANGLER(RTUriParsedQuery) +# define RTUriIsSchemeMatch RT_MANGLER(RTUriIsSchemeMatch) +# define RTUtf16AllocTag RT_MANGLER(RTUtf16AllocTag) +# define RTUtf16ReallocTag RT_MANGLER(RTUtf16ReallocTag) +# define RTUtf16CalcLatin1Len RT_MANGLER(RTUtf16CalcLatin1Len) +# define RTUtf16CalcLatin1LenEx RT_MANGLER(RTUtf16CalcLatin1LenEx) +# define RTUtf16CalcUtf8Len RT_MANGLER(RTUtf16CalcUtf8Len) +# define RTUtf16CalcUtf8LenEx RT_MANGLER(RTUtf16CalcUtf8LenEx) +# define RTUtf16BigCalcUtf8Len RT_MANGLER(RTUtf16BigCalcUtf8Len) +# define RTUtf16BigCalcUtf8LenEx RT_MANGLER(RTUtf16BigCalcUtf8LenEx) +# define RTUtf16LittleCalcUtf8Len RT_MANGLER(RTUtf16LittleCalcUtf8Len) +# define RTUtf16LittleCalcUtf8LenEx RT_MANGLER(RTUtf16LittleCalcUtf8LenEx) +# define RTUtf16Cmp RT_MANGLER(RTUtf16Cmp) +# define RTUtf16CmpAscii RT_MANGLER(RTUtf16CmpAscii) +# define RTUtf16CmpUtf8 RT_MANGLER(RTUtf16CmpUtf8) +# define RTUtf16DupExTag RT_MANGLER(RTUtf16DupExTag) +# define RTUtf16DupTag RT_MANGLER(RTUtf16DupTag) +# define RTUtf16Free RT_MANGLER(RTUtf16Free) +# define RTUtf16GetCpExInternal RT_MANGLER(RTUtf16GetCpExInternal) +# define RTUtf16GetCpNExInternal RT_MANGLER(RTUtf16GetCpNExInternal) +# define RTUtf16BigGetCpExInternal RT_MANGLER(RTUtf16BigGetCpExInternal) +# define RTUtf16GetCpInternal RT_MANGLER(RTUtf16GetCpInternal) +# define RTUtf16BigGetCpInternal RT_MANGLER(RTUtf16BigGetCpInternal) +# define RTUtf16NCmp RT_MANGLER(RTUtf16NCmp) +# define RTUtf16NCmpAscii RT_MANGLER(RTUtf16NCmpAscii) +# define RTUtf16NCmpUtf8 RT_MANGLER(RTUtf16NCmpUtf8) +# define RTUtf16ICmp RT_MANGLER(RTUtf16ICmp) +# define RTUtf16BigICmp RT_MANGLER(RTUtf16BigICmp) +# define RTUtf16ICmpUtf8 RT_MANGLER(RTUtf16ICmpUtf8) +# define RTUtf16NICmp RT_MANGLER(RTUtf16NICmp) +# define RTUtf16BigNICmp RT_MANGLER(RTUtf16BigNICmp) +# define RTUtf16FindAscii RT_MANGLER(RTUtf16FindAscii) +# define RTUtf16IsValidEncoding RT_MANGLER(RTUtf16IsValidEncoding) +# define RTUtf16Len RT_MANGLER(RTUtf16Len) +# define RTUtf16LocaleICmp RT_MANGLER(RTUtf16LocaleICmp) +# define RTUtf16PutCpInternal RT_MANGLER(RTUtf16PutCpInternal) +# define RTUtf16BigPutCpInternal RT_MANGLER(RTUtf16BigPutCpInternal) +# define RTUtf16ToLatin1ExTag RT_MANGLER(RTUtf16ToLatin1ExTag) +# define RTUtf16ToLatin1Tag RT_MANGLER(RTUtf16ToLatin1Tag) +# define RTUtf16ToLower RT_MANGLER(RTUtf16ToLower) +# define RTUtf16ToUpper RT_MANGLER(RTUtf16ToUpper) +# define RTUtf16PurgeComplementSet RT_MANGLER(RTUtf16PurgeComplementSet) +# define RTUtf16ToUtf8ExTag RT_MANGLER(RTUtf16ToUtf8ExTag) +# define RTUtf16BigToUtf8ExTag RT_MANGLER(RTUtf16BigToUtf8ExTag) +# define RTUtf16LittleToUtf8ExTag RT_MANGLER(RTUtf16LittleToUtf8ExTag) +# define RTUtf16ToUtf8Tag RT_MANGLER(RTUtf16ToUtf8Tag) +# define RTUtf16BigToUtf8Tag RT_MANGLER(RTUtf16BigToUtf8Tag) +# define RTUtf16LittleToUtf8Tag RT_MANGLER(RTUtf16LittleToUtf8Tag) +# define RTUtf16ValidateEncoding RT_MANGLER(RTUtf16ValidateEncoding) +# define RTUtf16ValidateEncodingEx RT_MANGLER(RTUtf16ValidateEncodingEx) +# define RTUtf16Printf RT_MANGLER(RTUtf16Printf) +# define RTUtf16PrintfV RT_MANGLER(RTUtf16PrintfV) +# define RTUtf16PrintfEx RT_MANGLER(RTUtf16PrintfEx) +# define RTUtf16PrintfExV RT_MANGLER(RTUtf16PrintfExV) +# define RTUuidClear RT_MANGLER(RTUuidClear) +# define RTUuidCompare RT_MANGLER(RTUuidCompare) +# define RTUuidCompare2Strs RT_MANGLER(RTUuidCompare2Strs) +# define RTUuidCompareStr RT_MANGLER(RTUuidCompareStr) +# define RTUuidCreate RT_MANGLER(RTUuidCreate) +# define RTUuidFromStr RT_MANGLER(RTUuidFromStr) +# define RTUuidFromUtf16 RT_MANGLER(RTUuidFromUtf16) +# define RTUuidIsNull RT_MANGLER(RTUuidIsNull) +# define RTUuidToStr RT_MANGLER(RTUuidToStr) +# define RTUuidToUtf16 RT_MANGLER(RTUuidToUtf16) +# define RTVfsChainElementDeregisterProvider RT_MANGLER(RTVfsChainElementDeregisterProvider) +# define RTVfsChainElementRegisterProvider RT_MANGLER(RTVfsChainElementRegisterProvider) +# define RTVfsChainIsSpec RT_MANGLER(RTVfsChainIsSpec) +# define RTVfsChainMsgError RT_MANGLER(RTVfsChainMsgError) +# define RTVfsChainMsgErrorExitFailure RT_MANGLER(RTVfsChainMsgErrorExitFailure) +# define RTVfsChainOpenObj RT_MANGLER(RTVfsChainOpenObj) +# define RTVfsChainOpenDir RT_MANGLER(RTVfsChainOpenDir) +# define RTVfsChainOpenParentDir RT_MANGLER(RTVfsChainOpenParentDir) +# define RTVfsChainOpenFile RT_MANGLER(RTVfsChainOpenFile) +# define RTVfsChainOpenIoStream RT_MANGLER(RTVfsChainOpenIoStream) +# define RTVfsChainQueryFinalPath RT_MANGLER(RTVfsChainQueryFinalPath) +# define RTVfsChainQueryInfo RT_MANGLER(RTVfsChainQueryInfo) +# define RTVfsChainSpecCheckAndSetup RT_MANGLER(RTVfsChainSpecCheckAndSetup) +# define RTVfsChainSpecFree RT_MANGLER(RTVfsChainSpecFree) +# define RTVfsChainSpecParse RT_MANGLER(RTVfsChainSpecParse) +# define RTVfsChainSplitOffFinalPath RT_MANGLER(RTVfsChainSplitOffFinalPath) +# define RTVfsChainValidateOpenFileOrIoStream RT_MANGLER(RTVfsChainValidateOpenFileOrIoStream) +# define RTVfsDirRelease RT_MANGLER(RTVfsDirRelease) +# define RTVfsDirRetain RT_MANGLER(RTVfsDirRetain) +# define RTVfsDirRetainDebug RT_MANGLER(RTVfsDirRetainDebug) +# define RTVfsDirOpen RT_MANGLER(RTVfsDirOpen) +# define RTVfsDirOpenDir RT_MANGLER(RTVfsDirOpenDir) +# define RTVfsDirCreateDir RT_MANGLER(RTVfsDirCreateDir) +# define RTVfsDirOpenFile RT_MANGLER(RTVfsDirOpenFile) +# define RTVfsDirOpenFileAsIoStream RT_MANGLER(RTVfsDirOpenFileAsIoStream) +# define RTVfsDirOpenObj RT_MANGLER(RTVfsDirOpenObj) +# define RTVfsDirQueryPathInfo RT_MANGLER(RTVfsDirQueryPathInfo) +# define RTVfsDirReadEx RT_MANGLER(RTVfsDirReadEx) +# define RTVfsDirRemoveDir RT_MANGLER(RTVfsDirRemoveDir) +# define RTVfsDirRewind RT_MANGLER(RTVfsDirRewind) +# define RTVfsDirSetPathMode RT_MANGLER(RTVfsDirSetPathMode) +# define RTVfsDirToPrivate RT_MANGLER(RTVfsDirToPrivate) +# define RTVfsFileFlush RT_MANGLER(RTVfsFileFlush) +# define RTVfsFileFromBuffer RT_MANGLER(RTVfsFileFromBuffer) +# define RTVfsFileFromRTFile RT_MANGLER(RTVfsFileFromRTFile) +# define RTVfsFileGetOpenFlags RT_MANGLER(RTVfsFileGetOpenFlags) +# define RTVfsFileQuerySize RT_MANGLER(RTVfsFileQuerySize) +# define RTVfsFileGetMaxSize RT_MANGLER(RTVfsFileGetMaxSize) +# define RTVfsFileOpen RT_MANGLER(RTVfsFileOpen) +# define RTVfsFileOpenNormal RT_MANGLER(RTVfsFileOpenNormal) +# define RTVfsFilePoll RT_MANGLER(RTVfsFilePoll) +# define RTVfsFilePrintf RT_MANGLER(RTVfsFilePrintf) +# define RTVfsFilePrintfV RT_MANGLER(RTVfsFilePrintfV) +# define RTVfsFileQueryInfo RT_MANGLER(RTVfsFileQueryInfo) +# define RTVfsFileQueryMaxSize RT_MANGLER(RTVfsFileQueryMaxSize) +# define RTVfsFileRead RT_MANGLER(RTVfsFileRead) +# define RTVfsFileReadAt RT_MANGLER(RTVfsFileReadAt) +# define RTVfsFileRelease RT_MANGLER(RTVfsFileRelease) +# define RTVfsFileRetain RT_MANGLER(RTVfsFileRetain) +# define RTVfsFileRetainDebug RT_MANGLER(RTVfsFileRetainDebug) +# define RTVfsFileSeek RT_MANGLER(RTVfsFileSeek) +# define RTVfsFileSetSize RT_MANGLER(RTVfsFileSetSize) +# define RTVfsFileSgRead RT_MANGLER(RTVfsFileSgRead) +# define RTVfsFileSgWrite RT_MANGLER(RTVfsFileSgWrite) +# define RTVfsFileTell RT_MANGLER(RTVfsFileTell) +# define RTVfsFileToIoStream RT_MANGLER(RTVfsFileToIoStream) +# define RTVfsFileWrite RT_MANGLER(RTVfsFileWrite) +# define RTVfsFileWriteAt RT_MANGLER(RTVfsFileWriteAt) +# define RTVfsFsStreamToPrivate RT_MANGLER(RTVfsFsStreamToPrivate) +# define RTVfsFsStrmAdd RT_MANGLER(RTVfsFsStrmAdd) +# define RTVfsFsStrmEnd RT_MANGLER(RTVfsFsStrmEnd) +# define RTVfsFsStrmNext RT_MANGLER(RTVfsFsStrmNext) +# define RTVfsFsStrmPushFile RT_MANGLER(RTVfsFsStrmPushFile) +# define RTVfsFsStrmQueryInfo RT_MANGLER(RTVfsFsStrmQueryInfo) +# define RTVfsFsStrmRelease RT_MANGLER(RTVfsFsStrmRelease) +# define RTVfsFsStrmRetain RT_MANGLER(RTVfsFsStrmRetain) +# define RTVfsFsStrmRetainDebug RT_MANGLER(RTVfsFsStrmRetainDebug) +# define RTVfsFsStrmToDir RT_MANGLER(RTVfsFsStrmToDir) +# define RTVfsFsStrmToNormalDir RT_MANGLER(RTVfsFsStrmToNormalDir) +# define RTVfsFsStrmToDirUndo RT_MANGLER(RTVfsFsStrmToDirUndo) +# define RTVfsIoStreamToPrivate RT_MANGLER(RTVfsIoStreamToPrivate) +# define RTVfsIoStrmFlush RT_MANGLER(RTVfsIoStrmFlush) +# define RTVfsIoStrmFromBuffer RT_MANGLER(RTVfsIoStrmFromBuffer) +# define RTVfsIoStrmFromRTFile RT_MANGLER(RTVfsIoStrmFromRTFile) +# define RTVfsIoStrmFromRTPipe RT_MANGLER(RTVfsIoStrmFromRTPipe) +# define RTVfsIoStrmFromStdHandle RT_MANGLER(RTVfsIoStrmFromStdHandle) +# define RTVfsIoStrmGetOpenFlags RT_MANGLER(RTVfsIoStrmGetOpenFlags) +# define RTVfsIoStrmIsAtEnd RT_MANGLER(RTVfsIoStrmIsAtEnd) +# define RTVfsIoStrmOpenNormal RT_MANGLER(RTVfsIoStrmOpenNormal) +# define RTVfsIoStrmPoll RT_MANGLER(RTVfsIoStrmPoll) +# define RTVfsIoStrmPrintf RT_MANGLER(RTVfsIoStrmPrintf) +# define RTVfsIoStrmPrintfV RT_MANGLER(RTVfsIoStrmPrintfV) +# define RTVfsIoStrmQueryInfo RT_MANGLER(RTVfsIoStrmQueryInfo) +# define RTVfsIoStrmRead RT_MANGLER(RTVfsIoStrmRead) +# define RTVfsIoStrmReadAt RT_MANGLER(RTVfsIoStrmReadAt) +# define RTVfsIoStrmReadAll RT_MANGLER(RTVfsIoStrmReadAll) +# define RTVfsIoStrmReadAllFree RT_MANGLER(RTVfsIoStrmReadAllFree) +# define RTVfsIoStrmRelease RT_MANGLER(RTVfsIoStrmRelease) +# define RTVfsIoStrmRetain RT_MANGLER(RTVfsIoStrmRetain) +# define RTVfsIoStrmRetainDebug RT_MANGLER(RTVfsIoStrmRetainDebug) +# define RTVfsIoStrmSgRead RT_MANGLER(RTVfsIoStrmSgRead) +# define RTVfsIoStrmSgWrite RT_MANGLER(RTVfsIoStrmSgWrite) +# define RTVfsIoStrmSkip RT_MANGLER(RTVfsIoStrmSkip) +# define RTVfsIoStrmStrOutputCallback RT_MANGLER(RTVfsIoStrmStrOutputCallback) +# define RTVfsIoStrmTell RT_MANGLER(RTVfsIoStrmTell) +# define RTVfsIoStrmToFile RT_MANGLER(RTVfsIoStrmToFile) +# define RTVfsIoStrmValidateUtf8Encoding RT_MANGLER(RTVfsIoStrmValidateUtf8Encoding) +# define RTVfsIoStrmWrite RT_MANGLER(RTVfsIoStrmWrite) +# define RTVfsIoStrmWriteAt RT_MANGLER(RTVfsIoStrmWriteAt) +# define RTVfsIoStrmZeroFill RT_MANGLER(RTVfsIoStrmZeroFill) +# define RTVfsQueryLabel RT_MANGLER(RTVfsQueryLabel) +# define RTVfsQueryRangeState RT_MANGLER(RTVfsQueryRangeState) +# define RTVfsLockAcquireReadSlow RT_MANGLER(RTVfsLockAcquireReadSlow) +# define RTVfsLockAcquireWriteSlow RT_MANGLER(RTVfsLockAcquireWriteSlow) +# define RTVfsLockRelease RT_MANGLER(RTVfsLockRelease) +# define RTVfsLockReleaseReadSlow RT_MANGLER(RTVfsLockReleaseReadSlow) +# define RTVfsLockReleaseWriteSlow RT_MANGLER(RTVfsLockReleaseWriteSlow) +# define RTVfsLockRetain RT_MANGLER(RTVfsLockRetain) +# define RTVfsLockRetainDebug RT_MANGLER(RTVfsLockRetainDebug) +# define RTVfsMemFileCreate RT_MANGLER(RTVfsMemFileCreate) +# define RTVfsMemIoStrmCreate RT_MANGLER(RTVfsMemIoStrmCreate) +# define RTVfsMemorizeIoStreamAsFile RT_MANGLER(RTVfsMemorizeIoStreamAsFile) +# define RTVfsNew RT_MANGLER(RTVfsNew) +# define RTVfsNewBaseObj RT_MANGLER(RTVfsNewBaseObj) +# define RTVfsNewDir RT_MANGLER(RTVfsNewDir) +# define RTVfsNewFile RT_MANGLER(RTVfsNewFile) +# define RTVfsNewFsStream RT_MANGLER(RTVfsNewFsStream) +# define RTVfsNewIoStream RT_MANGLER(RTVfsNewIoStream) +# define RTVfsNewSymlink RT_MANGLER(RTVfsNewSymlink) +# define RTVfsObjFromDir RT_MANGLER(RTVfsObjFromDir) +# define RTVfsObjFromFile RT_MANGLER(RTVfsObjFromFile) +# define RTVfsObjFromFsStream RT_MANGLER(RTVfsObjFromFsStream) +# define RTVfsObjFromIoStream RT_MANGLER(RTVfsObjFromIoStream) +# define RTVfsObjFromSymlink RT_MANGLER(RTVfsObjFromSymlink) +# define RTVfsObjFromVfs RT_MANGLER(RTVfsObjFromVfs) +# define RTVfsObjGetType RT_MANGLER(RTVfsObjGetType) +# define RTVfsObjOpen RT_MANGLER(RTVfsObjOpen) +# define RTVfsObjQueryInfo RT_MANGLER(RTVfsObjQueryInfo) +# define RTVfsObjRelease RT_MANGLER(RTVfsObjRelease) +# define RTVfsObjRetain RT_MANGLER(RTVfsObjRetain) +# define RTVfsObjRetainDebug RT_MANGLER(RTVfsObjRetainDebug) +# define RTVfsObjSetMode RT_MANGLER(RTVfsObjSetMode) +# define RTVfsObjSetOwner RT_MANGLER(RTVfsObjSetOwner) +# define RTVfsObjSetTimes RT_MANGLER(RTVfsObjSetTimes) +# define RTVfsObjToDir RT_MANGLER(RTVfsObjToDir) +# define RTVfsObjToFile RT_MANGLER(RTVfsObjToFile) +# define RTVfsObjToFsStream RT_MANGLER(RTVfsObjToFsStream) +# define RTVfsObjToIoStream RT_MANGLER(RTVfsObjToIoStream) +# define RTVfsObjToPrivate RT_MANGLER(RTVfsObjToPrivate) +# define RTVfsObjToSymlink RT_MANGLER(RTVfsObjToSymlink) +# define RTVfsObjToVfs RT_MANGLER(RTVfsObjToVfs) +# define RTVfsParsePath RT_MANGLER(RTVfsParsePath) +# define RTVfsParsePathA RT_MANGLER(RTVfsParsePathA) +# define RTVfsParsePathAppend RT_MANGLER(RTVfsParsePathAppend) +# define RTVfsParsePathFree RT_MANGLER(RTVfsParsePathFree) +# define RTVfsRelease RT_MANGLER(RTVfsRelease) +# define RTVfsOpenRoot RT_MANGLER(RTVfsOpenRoot) +# define RTVfsQuerPathInfo RT_MANGLER(RTVfsQueryPathInfo) +# define RTVfsMountVol RT_MANGLER(RTVfsMountVol) +# define RTVfsRetain RT_MANGLER(RTVfsRetain) +# define RTVfsRetainDebug RT_MANGLER(RTVfsRetainDebug) +# define RTVfsSymlinkQueryInfo RT_MANGLER(RTVfsSymlinkQueryInfo) +# define RTVfsSymlinkRead RT_MANGLER(RTVfsSymlinkRead) +# define RTVfsSymlinkRelease RT_MANGLER(RTVfsSymlinkRelease) +# define RTVfsSymlinkRetain RT_MANGLER(RTVfsSymlinkRetain) +# define RTVfsSymlinkRetainDebug RT_MANGLER(RTVfsSymlinkRetainDebug) +# define RTVfsSymlinkSetMode RT_MANGLER(RTVfsSymlinkSetMode) +# define RTVfsSymlinkSetOwner RT_MANGLER(RTVfsSymlinkSetOwner) +# define RTVfsSymlinkSetTimes RT_MANGLER(RTVfsSymlinkSetTimes) +# define RTVfsSymlinkToPrivate RT_MANGLER(RTVfsSymlinkToPrivate) +# define RTVfsTypeName RT_MANGLER(RTVfsTypeName) +# define RTVfsUtilDummyPollOne RT_MANGLER(RTVfsUtilDummyPollOne) +# define RTVfsUtilPumpIoStreams RT_MANGLER(RTVfsUtilPumpIoStreams) +# define RTVfsCreateProgressForFile RT_MANGLER(RTVfsCreateProgressForFile) +# define RTVfsCreateProgressForIoStream RT_MANGLER(RTVfsCreateProgressForIoStream) +# define RTVfsCreateReadAheadForFile RT_MANGLER(RTVfsCreateReadAheadForFile) +# define RTVfsCreateReadAheadForIoStream RT_MANGLER(RTVfsCreateReadAheadForIoStream) +# define RTZipBlockCompress RT_MANGLER(RTZipBlockCompress) +# define RTZipBlockDecompress RT_MANGLER(RTZipBlockDecompress) +# define RTZipCompCreate RT_MANGLER(RTZipCompCreate) +# define RTZipCompDestroy RT_MANGLER(RTZipCompDestroy) +# define RTZipCompFinish RT_MANGLER(RTZipCompFinish) +# define RTZipCompress RT_MANGLER(RTZipCompress) +# define RTZipDecompCreate RT_MANGLER(RTZipDecompCreate) +# define RTZipDecompDestroy RT_MANGLER(RTZipDecompDestroy) +# define RTZipDecompress RT_MANGLER(RTZipDecompress) +# define RTZipGzipCompressIoStream RT_MANGLER(RTZipGzipCompressIoStream) +# define RTZipGzipDecompressIoStream RT_MANGLER(RTZipGzipDecompressIoStream) +# define RTZipGzipCmd RT_MANGLER(RTZipGzipCmd) +# define RTZipPkzipFsStreamFromIoStream RT_MANGLER(RTZipPkzipFsStreamFromIoStream) +# define RTZipPkzipMemDecompress RT_MANGLER(RTZipPkzipMemDecompress) +# define RTZipTarCmd RT_MANGLER(RTZipTarCmd) +# define RTZipUnzipCmd RT_MANGLER(RTZipUnzipCmd) +# define RTZipTarFsStreamFromIoStream RT_MANGLER(RTZipTarFsStreamFromIoStream) +# define RTZipTarFsStreamToIoStream RT_MANGLER(RTZipTarFsStreamToIoStream) +# define RTZipTarFsStreamSetOwner RT_MANGLER(RTZipTarFsStreamSetOwner) +# define RTZipTarFsStreamSetGroup RT_MANGLER(RTZipTarFsStreamSetGroup) +# define RTZipTarFsStreamSetPrefix RT_MANGLER(RTZipTarFsStreamSetPrefix) +# define RTZipTarFsStreamSetFileMode RT_MANGLER(RTZipTarFsStreamSetFileMode) +# define RTZipTarFsStreamSetDirMode RT_MANGLER(RTZipTarFsStreamSetDirMode) +# define RTZipTarFsStreamSetModTime RT_MANGLER(RTZipTarFsStreamSetModTime) +# define RTZipTarFsStreamTruncate RT_MANGLER(RTZipTarFsStreamTruncate) +# define RTZipXarFsStreamFromIoStream RT_MANGLER(RTZipXarFsStreamFromIoStream) +# define RTZipTarFsStreamForFile RT_MANGLER(RTZipTarFsStreamForFile) +# define RTZipCpioFsStreamFromIoStream RT_MANGLER(RTZipCpioFsStreamFromIoStream) + +/* sort/merge into the above later: */ +# define RTAsn1ContentAllocZ RT_MANGLER(RTAsn1ContentAllocZ) +# define RTAsn1ContentDup RT_MANGLER(RTAsn1ContentDup) +# define RTAsn1ContentFree RT_MANGLER(RTAsn1ContentFree) +# define RTAsn1ContentReallocZ RT_MANGLER(RTAsn1ContentReallocZ) +# define RTAsn1ContextTagN_Clone RT_MANGLER(RTAsn1ContextTagN_Clone) +# define RTAsn1ContextTagN_Init RT_MANGLER(RTAsn1ContextTagN_Init) +# define RTAsn1Dummy_InitEx RT_MANGLER(RTAsn1Dummy_InitEx) +# define RTAsn1MemAllocZ RT_MANGLER(RTAsn1MemAllocZ) +# define RTAsn1MemDup RT_MANGLER(RTAsn1MemDup) +# define RTAsn1MemFree RT_MANGLER(RTAsn1MemFree) +# define RTAsn1MemFreeArray RT_MANGLER(RTAsn1MemFreeArray) +# define RTAsn1MemResizeArray RT_MANGLER(RTAsn1MemResizeArray) +# define RTAsn1MemInitAllocation RT_MANGLER(RTAsn1MemInitAllocation) +# define RTAsn1MemInitArrayAllocation RT_MANGLER(RTAsn1MemInitArrayAllocation) +# define RTAsn1SeqOfCore_Clone RT_MANGLER(RTAsn1SeqOfCore_Clone) +# define RTAsn1SeqOfCore_Init RT_MANGLER(RTAsn1SeqOfCore_Init) +# define RTAsn1SequenceCore_Clone RT_MANGLER(RTAsn1SequenceCore_Clone) +# define RTAsn1SequenceCore_Init RT_MANGLER(RTAsn1SequenceCore_Init) +# define RTAsn1SetCore_Clone RT_MANGLER(RTAsn1SetCore_Clone) +# define RTAsn1SetCore_Init RT_MANGLER(RTAsn1SetCore_Init) +# define RTAsn1SetOfCore_Clone RT_MANGLER(RTAsn1SetOfCore_Clone) +# define RTAsn1SetOfCore_Init RT_MANGLER(RTAsn1SetOfCore_Init) +# define RTAsn1VtCheckSanity RT_MANGLER(RTAsn1VtCheckSanity) +# define RTAsn1VtClone RT_MANGLER(RTAsn1VtClone) +# define RTAsn1VtCompare RT_MANGLER(RTAsn1VtCompare) +# define RTAsn1VtDeepEnum RT_MANGLER(RTAsn1VtDeepEnum) +# define RTAsn1VtDelete RT_MANGLER(RTAsn1VtDelete) +# define RTAsn1CursorCheckEnd RT_MANGLER(RTAsn1CursorCheckEnd) +# define RTAsn1CursorCheckOctStrEnd RT_MANGLER(RTAsn1CursorCheckOctStrEnd) +# define RTAsn1CursorCheckSeqEnd RT_MANGLER(RTAsn1CursorCheckSeqEnd) +# define RTAsn1CursorCheckSetEnd RT_MANGLER(RTAsn1CursorCheckSetEnd) +# define RTAsn1CursorGetBitString RT_MANGLER(RTAsn1CursorGetBitString) +# define RTAsn1CursorGetBitStringEx RT_MANGLER(RTAsn1CursorGetBitStringEx) +# define RTAsn1CursorGetBmpString RT_MANGLER(RTAsn1CursorGetBmpString) +# define RTAsn1CursorGetBoolean RT_MANGLER(RTAsn1CursorGetBoolean) +# define RTAsn1CursorGetContextTagNCursor RT_MANGLER(RTAsn1CursorGetContextTagNCursor) +# define RTAsn1CursorGetCore RT_MANGLER(RTAsn1CursorGetCore) +# define RTAsn1CursorGetDynType RT_MANGLER(RTAsn1CursorGetDynType) +# define RTAsn1CursorGetIa5String RT_MANGLER(RTAsn1CursorGetIa5String) +# define RTAsn1CursorGetInteger RT_MANGLER(RTAsn1CursorGetInteger) +# define RTAsn1CursorGetNull RT_MANGLER(RTAsn1CursorGetNull) +# define RTAsn1CursorGetObjId RT_MANGLER(RTAsn1CursorGetObjId) +# define RTAsn1CursorGetOctetString RT_MANGLER(RTAsn1CursorGetOctetString) +# define RTAsn1CursorGetSequenceCursor RT_MANGLER(RTAsn1CursorGetSequenceCursor) +# define RTAsn1CursorGetSetCursor RT_MANGLER(RTAsn1CursorGetSetCursor) +# define RTAsn1CursorGetString RT_MANGLER(RTAsn1CursorGetString) +# define RTAsn1CursorGetTime RT_MANGLER(RTAsn1CursorGetTime) +# define RTAsn1CursorGetUtf8String RT_MANGLER(RTAsn1CursorGetUtf8String) +# define RTAsn1CursorInitAllocation RT_MANGLER(RTAsn1CursorInitAllocation) +# define RTAsn1CursorInitArrayAllocation RT_MANGLER(RTAsn1CursorInitArrayAllocation) +# define RTAsn1CursorInitPrimary RT_MANGLER(RTAsn1CursorInitPrimary) +# define RTAsn1CursorInitSub RT_MANGLER(RTAsn1CursorInitSub) +# define RTAsn1CursorInitSubFromCore RT_MANGLER(RTAsn1CursorInitSubFromCore) +# define RTAsn1CursorIsNextEx RT_MANGLER(RTAsn1CursorIsNextEx) +# define RTAsn1CursorIsEnd RT_MANGLER(RTAsn1CursorIsEnd) +# define RTAsn1CursorMatchTagClassFlagsEx RT_MANGLER(RTAsn1CursorMatchTagClassFlagsEx) +# define RTAsn1CursorPeek RT_MANGLER(RTAsn1CursorPeek) +# define RTAsn1CursorReadHdr RT_MANGLER(RTAsn1CursorReadHdr) +# define RTAsn1CursorSetInfo RT_MANGLER(RTAsn1CursorSetInfo) +# define RTAsn1CursorSetInfoV RT_MANGLER(RTAsn1CursorSetInfoV) +# define RTAsn1Dump RT_MANGLER(RTAsn1Dump) +# define RTAsn1QueryObjIdName RT_MANGLER(RTAsn1QueryObjIdName) +# define RTAsn1EncodePrepare RT_MANGLER(RTAsn1EncodePrepare) +# define RTAsn1EncodeRecalcHdrSize RT_MANGLER(RTAsn1EncodeRecalcHdrSize) +# define RTAsn1EncodeToBuffer RT_MANGLER(RTAsn1EncodeToBuffer) +# define RTAsn1EncodeQueryRawBits RT_MANGLER(RTAsn1EncodeQueryRawBits) +# define RTAsn1EncodeWrite RT_MANGLER(RTAsn1EncodeWrite) +# define RTAsn1EncodeWriteHeader RT_MANGLER(RTAsn1EncodeWriteHeader) +# define RTAsn1BitString_CheckSanity RT_MANGLER(RTAsn1BitString_CheckSanity) +# define RTAsn1BitString_Clone RT_MANGLER(RTAsn1BitString_Clone) +# define RTAsn1BitString_Compare RT_MANGLER(RTAsn1BitString_Compare) +# define RTAsn1BitString_Delete RT_MANGLER(RTAsn1BitString_Delete) +# define RTAsn1BitString_Enum RT_MANGLER(RTAsn1BitString_Enum) +# define RTAsn1BitString_GetAsUInt64 RT_MANGLER(RTAsn1BitString_GetAsUInt64) +# define RTAsn1BitString_Init RT_MANGLER(RTAsn1BitString_Init) +# define RTAsn1BitString_InitWithData RT_MANGLER(RTAsn1BitString_InitWithData) +# define RTAsn1BitString_AreContentBitsValid RT_MANGLER(RTAsn1BitString_AreContentBitsValid) +# define RTAsn1BitString_RefreshContent RT_MANGLER(RTAsn1BitString_RefreshContent) +# define RTAsn1SeqOfBitStrings_CheckSanity RT_MANGLER(RTAsn1SeqOfBitStrings_CheckSanity) +# define RTAsn1SeqOfBitStrings_Clone RT_MANGLER(RTAsn1SeqOfBitStrings_Clone) +# define RTAsn1SeqOfBitStrings_Compare RT_MANGLER(RTAsn1SeqOfBitStrings_Compare) +# define RTAsn1SeqOfBitStrings_Delete RT_MANGLER(RTAsn1SeqOfBitStrings_Delete) +# define RTAsn1SeqOfBitStrings_Enum RT_MANGLER(RTAsn1SeqOfBitStrings_Enum) +# define RTAsn1SeqOfBitStrings_Init RT_MANGLER(RTAsn1SeqOfBitStrings_Init) +# define RTAsn1SetOfBitStrings_CheckSanity RT_MANGLER(RTAsn1SetOfBitStrings_CheckSanity) +# define RTAsn1SetOfBitStrings_Clone RT_MANGLER(RTAsn1SetOfBitStrings_Clone) +# define RTAsn1SetOfBitStrings_Compare RT_MANGLER(RTAsn1SetOfBitStrings_Compare) +# define RTAsn1SetOfBitStrings_Delete RT_MANGLER(RTAsn1SetOfBitStrings_Delete) +# define RTAsn1SetOfBitStrings_Enum RT_MANGLER(RTAsn1SetOfBitStrings_Enum) +# define RTAsn1SetOfBitStrings_Init RT_MANGLER(RTAsn1SetOfBitStrings_Init) +# define RTAsn1BitString_DecodeAsn1 RT_MANGLER(RTAsn1BitString_DecodeAsn1) +# define RTAsn1BitString_DecodeAsn1Ex RT_MANGLER(RTAsn1BitString_DecodeAsn1Ex) +# define RTAsn1SeqOfBitStrings_DecodeAsn1 RT_MANGLER(RTAsn1SeqOfBitStrings_DecodeAsn1) +# define RTAsn1SetOfBitStrings_DecodeAsn1 RT_MANGLER(RTAsn1SetOfBitStrings_DecodeAsn1) +# define RTAsn1Boolean_CheckSanity RT_MANGLER(RTAsn1Boolean_CheckSanity) +# define RTAsn1Boolean_Clone RT_MANGLER(RTAsn1Boolean_Clone) +# define RTAsn1Boolean_Compare RT_MANGLER(RTAsn1Boolean_Compare) +# define RTAsn1Boolean_Delete RT_MANGLER(RTAsn1Boolean_Delete) +# define RTAsn1Boolean_Enum RT_MANGLER(RTAsn1Boolean_Enum) +# define RTAsn1Boolean_Init RT_MANGLER(RTAsn1Boolean_Init) +# define RTAsn1Boolean_InitDefault RT_MANGLER(RTAsn1Boolean_InitDefault) +# define RTAsn1Boolean_Set RT_MANGLER(RTAsn1Boolean_Set) +# define RTAsn1SeqOfBooleans_CheckSanity RT_MANGLER(RTAsn1SeqOfBooleans_CheckSanity) +# define RTAsn1SeqOfBooleans_Clone RT_MANGLER(RTAsn1SeqOfBooleans_Clone) +# define RTAsn1SeqOfBooleans_Compare RT_MANGLER(RTAsn1SeqOfBooleans_Compare) +# define RTAsn1SeqOfBooleans_Delete RT_MANGLER(RTAsn1SeqOfBooleans_Delete) +# define RTAsn1SeqOfBooleans_Enum RT_MANGLER(RTAsn1SeqOfBooleans_Enum) +# define RTAsn1SeqOfBooleans_Init RT_MANGLER(RTAsn1SeqOfBooleans_Init) +# define RTAsn1SetOfBooleans_CheckSanity RT_MANGLER(RTAsn1SetOfBooleans_CheckSanity) +# define RTAsn1SetOfBooleans_Clone RT_MANGLER(RTAsn1SetOfBooleans_Clone) +# define RTAsn1SetOfBooleans_Compare RT_MANGLER(RTAsn1SetOfBooleans_Compare) +# define RTAsn1SetOfBooleans_Delete RT_MANGLER(RTAsn1SetOfBooleans_Delete) +# define RTAsn1SetOfBooleans_Enum RT_MANGLER(RTAsn1SetOfBooleans_Enum) +# define RTAsn1SetOfBooleans_Init RT_MANGLER(RTAsn1SetOfBooleans_Init) +# define RTAsn1Boolean_DecodeAsn1 RT_MANGLER(RTAsn1Boolean_DecodeAsn1) +# define RTAsn1SeqOfBooleans_DecodeAsn1 RT_MANGLER(RTAsn1SeqOfBooleans_DecodeAsn1) +# define RTAsn1SetOfBooleans_DecodeAsn1 RT_MANGLER(RTAsn1SetOfBooleans_DecodeAsn1) +# define RTAsn1Core_ChangeTag RT_MANGLER(RTAsn1Core_ChangeTag) +# define RTAsn1Core_CheckSanity RT_MANGLER(RTAsn1Core_CheckSanity) +# define RTAsn1Core_Clone RT_MANGLER(RTAsn1Core_Clone) +# define RTAsn1Core_CloneContent RT_MANGLER(RTAsn1Core_CloneContent) +# define RTAsn1Core_CloneNoContent RT_MANGLER(RTAsn1Core_CloneNoContent) +# define RTAsn1Core_Compare RT_MANGLER(RTAsn1Core_Compare) +# define RTAsn1Core_CompareEx RT_MANGLER(RTAsn1Core_CompareEx) +# define RTAsn1Core_Delete RT_MANGLER(RTAsn1Core_Delete) +# define RTAsn1Core_Enum RT_MANGLER(RTAsn1Core_Enum) +# define RTAsn1Core_Init RT_MANGLER(RTAsn1Core_Init) +# define RTAsn1Core_InitDefault RT_MANGLER(RTAsn1Core_InitDefault) +# define RTAsn1Core_InitEx RT_MANGLER(RTAsn1Core_InitEx) +# define RTAsn1Core_ResetImplict RT_MANGLER(RTAsn1Core_ResetImplict) +# define RTAsn1Core_SetTagAndFlags RT_MANGLER(RTAsn1Core_SetTagAndFlags) +# define RTAsn1SeqOfCores_CheckSanity RT_MANGLER(RTAsn1SeqOfCores_CheckSanity) +# define RTAsn1SeqOfCores_Clone RT_MANGLER(RTAsn1SeqOfCores_Clone) +# define RTAsn1SeqOfCores_Compare RT_MANGLER(RTAsn1SeqOfCores_Compare) +# define RTAsn1SeqOfCores_Delete RT_MANGLER(RTAsn1SeqOfCores_Delete) +# define RTAsn1SeqOfCores_Enum RT_MANGLER(RTAsn1SeqOfCores_Enum) +# define RTAsn1SeqOfCores_Init RT_MANGLER(RTAsn1SeqOfCores_Init) +# define RTAsn1SetOfCores_CheckSanity RT_MANGLER(RTAsn1SetOfCores_CheckSanity) +# define RTAsn1SetOfCores_Clone RT_MANGLER(RTAsn1SetOfCores_Clone) +# define RTAsn1SetOfCores_Compare RT_MANGLER(RTAsn1SetOfCores_Compare) +# define RTAsn1SetOfCores_Delete RT_MANGLER(RTAsn1SetOfCores_Delete) +# define RTAsn1SetOfCores_Enum RT_MANGLER(RTAsn1SetOfCores_Enum) +# define RTAsn1SetOfCores_Init RT_MANGLER(RTAsn1SetOfCores_Init) +# define RTAsn1Core_DecodeAsn1 RT_MANGLER(RTAsn1Core_DecodeAsn1) +# define RTAsn1SeqOfCores_DecodeAsn1 RT_MANGLER(RTAsn1SeqOfCores_DecodeAsn1) +# define RTAsn1SetOfCores_DecodeAsn1 RT_MANGLER(RTAsn1SetOfCores_DecodeAsn1) +# define RTAsn1DynType_SetToNull RT_MANGLER(RTAsn1DynType_SetToNull) +# define RTAsn1DynType_CheckSanity RT_MANGLER(RTAsn1DynType_CheckSanity) +# define RTAsn1DynType_Clone RT_MANGLER(RTAsn1DynType_Clone) +# define RTAsn1DynType_Compare RT_MANGLER(RTAsn1DynType_Compare) +# define RTAsn1DynType_Delete RT_MANGLER(RTAsn1DynType_Delete) +# define RTAsn1DynType_Enum RT_MANGLER(RTAsn1DynType_Enum) +# define RTAsn1DynType_Init RT_MANGLER(RTAsn1DynType_Init) +# define RTAsn1DynType_DecodeAsn1 RT_MANGLER(RTAsn1DynType_DecodeAsn1) +# define RTAsn1Integer_CheckSanity RT_MANGLER(RTAsn1Integer_CheckSanity) +# define RTAsn1Integer_Clone RT_MANGLER(RTAsn1Integer_Clone) +# define RTAsn1Integer_Compare RT_MANGLER(RTAsn1Integer_Compare) +# define RTAsn1Integer_Delete RT_MANGLER(RTAsn1Integer_Delete) +# define RTAsn1Integer_Enum RT_MANGLER(RTAsn1Integer_Enum) +# define RTAsn1Integer_FromBigNum RT_MANGLER(RTAsn1Integer_FromBigNum) +# define RTAsn1Integer_Init RT_MANGLER(RTAsn1Integer_Init) +# define RTAsn1Integer_InitDefault RT_MANGLER(RTAsn1Integer_InitDefault) +# define RTAsn1Integer_InitU64 RT_MANGLER(RTAsn1Integer_InitU64) +# define RTAsn1Integer_ToBigNum RT_MANGLER(RTAsn1Integer_ToBigNum) +# define RTAsn1Integer_ToString RT_MANGLER(RTAsn1Integer_ToString) +# define RTAsn1Integer_UnsignedCompare RT_MANGLER(RTAsn1Integer_UnsignedCompare) +# define RTAsn1Integer_UnsignedCompareWithU32 RT_MANGLER(RTAsn1Integer_UnsignedCompareWithU32) +# define RTAsn1Integer_UnsignedCompareWithU64 RT_MANGLER(RTAsn1Integer_UnsignedCompareWithU64) +# define RTAsn1Integer_UnsignedLastBit RT_MANGLER(RTAsn1Integer_UnsignedLastBit) +# define RTAsn1SeqOfIntegers_CheckSanity RT_MANGLER(RTAsn1SeqOfIntegers_CheckSanity) +# define RTAsn1SeqOfIntegers_Clone RT_MANGLER(RTAsn1SeqOfIntegers_Clone) +# define RTAsn1SeqOfIntegers_Compare RT_MANGLER(RTAsn1SeqOfIntegers_Compare) +# define RTAsn1SeqOfIntegers_Delete RT_MANGLER(RTAsn1SeqOfIntegers_Delete) +# define RTAsn1SeqOfIntegers_Enum RT_MANGLER(RTAsn1SeqOfIntegers_Enum) +# define RTAsn1SeqOfIntegers_Init RT_MANGLER(RTAsn1SeqOfIntegers_Init) +# define RTAsn1SetOfIntegers_CheckSanity RT_MANGLER(RTAsn1SetOfIntegers_CheckSanity) +# define RTAsn1SetOfIntegers_Clone RT_MANGLER(RTAsn1SetOfIntegers_Clone) +# define RTAsn1SetOfIntegers_Compare RT_MANGLER(RTAsn1SetOfIntegers_Compare) +# define RTAsn1SetOfIntegers_Delete RT_MANGLER(RTAsn1SetOfIntegers_Delete) +# define RTAsn1SetOfIntegers_Enum RT_MANGLER(RTAsn1SetOfIntegers_Enum) +# define RTAsn1SetOfIntegers_Init RT_MANGLER(RTAsn1SetOfIntegers_Init) +# define RTAsn1Integer_DecodeAsn1 RT_MANGLER(RTAsn1Integer_DecodeAsn1) +# define RTAsn1SeqOfIntegers_DecodeAsn1 RT_MANGLER(RTAsn1SeqOfIntegers_DecodeAsn1) +# define RTAsn1SetOfIntegers_DecodeAsn1 RT_MANGLER(RTAsn1SetOfIntegers_DecodeAsn1) +# define RTAsn1Null_CheckSanity RT_MANGLER(RTAsn1Null_CheckSanity) +# define RTAsn1Null_Clone RT_MANGLER(RTAsn1Null_Clone) +# define RTAsn1Null_Compare RT_MANGLER(RTAsn1Null_Compare) +# define RTAsn1Null_Delete RT_MANGLER(RTAsn1Null_Delete) +# define RTAsn1Null_Enum RT_MANGLER(RTAsn1Null_Enum) +# define RTAsn1Null_Init RT_MANGLER(RTAsn1Null_Init) +# define RTAsn1Null_DecodeAsn1 RT_MANGLER(RTAsn1Null_DecodeAsn1) +# define RTAsn1ObjIdCountComponents RT_MANGLER(RTAsn1ObjIdCountComponents) +# define RTAsn1ObjIdGetComponentsAsUInt32 RT_MANGLER(RTAsn1ObjIdGetComponentsAsUInt32) +# define RTAsn1ObjIdGetLastComponentsAsUInt32 RT_MANGLER(RTAsn1ObjIdGetLastComponentsAsUInt32) +# define RTAsn1ObjId_CheckSanity RT_MANGLER(RTAsn1ObjId_CheckSanity) +# define RTAsn1ObjId_Clone RT_MANGLER(RTAsn1ObjId_Clone) +# define RTAsn1ObjId_Compare RT_MANGLER(RTAsn1ObjId_Compare) +# define RTAsn1ObjId_CompareWithString RT_MANGLER(RTAsn1ObjId_CompareWithString) +# define RTAsn1ObjId_Delete RT_MANGLER(RTAsn1ObjId_Delete) +# define RTAsn1ObjId_Enum RT_MANGLER(RTAsn1ObjId_Enum) +# define RTAsn1ObjId_Init RT_MANGLER(RTAsn1ObjId_Init) +# define RTAsn1ObjId_InitFromString RT_MANGLER(RTAsn1ObjId_InitFromString) +# define RTAsn1ObjId_SetFromString RT_MANGLER(RTAsn1ObjId_SetFromString) +# define RTAsn1ObjId_StartsWith RT_MANGLER(RTAsn1ObjId_StartsWith) +# define RTAsn1SeqOfObjIds_CheckSanity RT_MANGLER(RTAsn1SeqOfObjIds_CheckSanity) +# define RTAsn1SeqOfObjIds_Clone RT_MANGLER(RTAsn1SeqOfObjIds_Clone) +# define RTAsn1SeqOfObjIds_Compare RT_MANGLER(RTAsn1SeqOfObjIds_Compare) +# define RTAsn1SeqOfObjIds_Delete RT_MANGLER(RTAsn1SeqOfObjIds_Delete) +# define RTAsn1SeqOfObjIds_Enum RT_MANGLER(RTAsn1SeqOfObjIds_Enum) +# define RTAsn1SeqOfObjIds_Init RT_MANGLER(RTAsn1SeqOfObjIds_Init) +# define RTAsn1SetOfObjIds_CheckSanity RT_MANGLER(RTAsn1SetOfObjIds_CheckSanity) +# define RTAsn1SetOfObjIds_Clone RT_MANGLER(RTAsn1SetOfObjIds_Clone) +# define RTAsn1SetOfObjIds_Compare RT_MANGLER(RTAsn1SetOfObjIds_Compare) +# define RTAsn1SetOfObjIds_Delete RT_MANGLER(RTAsn1SetOfObjIds_Delete) +# define RTAsn1SetOfObjIds_Enum RT_MANGLER(RTAsn1SetOfObjIds_Enum) +# define RTAsn1SetOfObjIds_Init RT_MANGLER(RTAsn1SetOfObjIds_Init) +# define RTAsn1SeqOfObjIdSeqs_CheckSanity RT_MANGLER(RTAsn1SeqOfObjIdSeqs_CheckSanity) +# define RTAsn1SeqOfObjIdSeqs_Clone RT_MANGLER(RTAsn1SeqOfObjIdSeqs_Clone) +# define RTAsn1SeqOfObjIdSeqs_Compare RT_MANGLER(RTAsn1SeqOfObjIdSeqs_Compare) +# define RTAsn1SetOfObjIdSeqs_DecodeAsn1 RT_MANGLER(RTAsn1SetOfObjIdSeqs_DecodeAsn1) +# define RTAsn1SeqOfObjIdSeqs_Delete RT_MANGLER(RTAsn1SeqOfObjIdSeqs_Delete) +# define RTAsn1SeqOfObjIdSeqs_Enum RT_MANGLER(RTAsn1SeqOfObjIdSeqs_Enum) +# define RTAsn1SeqOfObjIdSeqs_Init RT_MANGLER(RTAsn1SeqOfObjIdSeqs_Init) +# define RTAsn1SetOfObjIdSeqs_CheckSanity RT_MANGLER(RTAsn1SetOfObjIdSeqs_CheckSanity) +# define RTAsn1SetOfObjIdSeqs_Clone RT_MANGLER(RTAsn1SetOfObjIdSeqs_Clone) +# define RTAsn1SetOfObjIdSeqs_Compare RT_MANGLER(RTAsn1SetOfObjIdSeqs_Compare) +# define RTAsn1SetOfObjIdSeqs_Delete RT_MANGLER(RTAsn1SetOfObjIdSeqs_Delete) +# define RTAsn1SetOfObjIdSeqs_Enum RT_MANGLER(RTAsn1SetOfObjIdSeqs_Enum) +# define RTAsn1SetOfObjIdSeqs_Init RT_MANGLER(RTAsn1SetOfObjIdSeqs_Init) +# define RTAsn1ObjId_DecodeAsn1 RT_MANGLER(RTAsn1ObjId_DecodeAsn1) +# define RTAsn1SeqOfObjIds_DecodeAsn1 RT_MANGLER(RTAsn1SeqOfObjIds_DecodeAsn1) +# define RTAsn1SetOfObjIds_DecodeAsn1 RT_MANGLER(RTAsn1SetOfObjIds_DecodeAsn1) +# define RTAsn1OctetString_AllocContent RT_MANGLER(RTAsn1OctetString_AllocContent) +# define RTAsn1OctetString_SetContent RT_MANGLER(RTAsn1OctetString_SetContent) +# define RTAsn1OctetString_CheckSanity RT_MANGLER(RTAsn1OctetString_CheckSanity) +# define RTAsn1OctetString_Clone RT_MANGLER(RTAsn1OctetString_Clone) +# define RTAsn1OctetString_Compare RT_MANGLER(RTAsn1OctetString_Compare) +# define RTAsn1OctetString_Delete RT_MANGLER(RTAsn1OctetString_Delete) +# define RTAsn1OctetString_Enum RT_MANGLER(RTAsn1OctetString_Enum) +# define RTAsn1OctetString_Init RT_MANGLER(RTAsn1OctetString_Init) +# define RTAsn1OctetString_AreContentBytesValid RT_MANGLER(RTAsn1OctetString_AreContentBytesValid) +# define RTAsn1OctetString_RefreshContent RT_MANGLER(RTAsn1OctetString_RefreshContent) +# define RTAsn1SeqOfOctetStrings_CheckSanity RT_MANGLER(RTAsn1SeqOfOctetStrings_CheckSanity) +# define RTAsn1SeqOfOctetStrings_Clone RT_MANGLER(RTAsn1SeqOfOctetStrings_Clone) +# define RTAsn1SeqOfOctetStrings_Compare RT_MANGLER(RTAsn1SeqOfOctetStrings_Compare) +# define RTAsn1SeqOfOctetStrings_Delete RT_MANGLER(RTAsn1SeqOfOctetStrings_Delete) +# define RTAsn1SeqOfOctetStrings_Enum RT_MANGLER(RTAsn1SeqOfOctetStrings_Enum) +# define RTAsn1SeqOfOctetStrings_Init RT_MANGLER(RTAsn1SeqOfOctetStrings_Init) +# define RTAsn1SetOfOctetStrings_CheckSanity RT_MANGLER(RTAsn1SetOfOctetStrings_CheckSanity) +# define RTAsn1SetOfOctetStrings_Clone RT_MANGLER(RTAsn1SetOfOctetStrings_Clone) +# define RTAsn1SetOfOctetStrings_Compare RT_MANGLER(RTAsn1SetOfOctetStrings_Compare) +# define RTAsn1SetOfOctetStrings_Delete RT_MANGLER(RTAsn1SetOfOctetStrings_Delete) +# define RTAsn1SetOfOctetStrings_Enum RT_MANGLER(RTAsn1SetOfOctetStrings_Enum) +# define RTAsn1SetOfOctetStrings_Init RT_MANGLER(RTAsn1SetOfOctetStrings_Init) +# define RTAsn1OctetString_DecodeAsn1 RT_MANGLER(RTAsn1OctetString_DecodeAsn1) +# define RTAsn1SeqOfOctetStrings_DecodeAsn1 RT_MANGLER(RTAsn1SeqOfOctetStrings_DecodeAsn1) +# define RTAsn1SetOfOctetStrings_DecodeAsn1 RT_MANGLER(RTAsn1SetOfOctetStrings_DecodeAsn1) +# define RTAsn1BmpString_CheckSanity RT_MANGLER(RTAsn1BmpString_CheckSanity) +# define RTAsn1BmpString_Clone RT_MANGLER(RTAsn1BmpString_Clone) +# define RTAsn1BmpString_Compare RT_MANGLER(RTAsn1BmpString_Compare) +# define RTAsn1BmpString_Delete RT_MANGLER(RTAsn1BmpString_Delete) +# define RTAsn1BmpString_Enum RT_MANGLER(RTAsn1BmpString_Enum) +# define RTAsn1BmpString_Init RT_MANGLER(RTAsn1BmpString_Init) +# define RTAsn1GeneralString_CheckSanity RT_MANGLER(RTAsn1GeneralString_CheckSanity) +# define RTAsn1GeneralString_Clone RT_MANGLER(RTAsn1GeneralString_Clone) +# define RTAsn1GeneralString_Compare RT_MANGLER(RTAsn1GeneralString_Compare) +# define RTAsn1GeneralString_Delete RT_MANGLER(RTAsn1GeneralString_Delete) +# define RTAsn1GeneralString_Enum RT_MANGLER(RTAsn1GeneralString_Enum) +# define RTAsn1GeneralString_Init RT_MANGLER(RTAsn1GeneralString_Init) +# define RTAsn1GraphicString_CheckSanity RT_MANGLER(RTAsn1GraphicString_CheckSanity) +# define RTAsn1GraphicString_Clone RT_MANGLER(RTAsn1GraphicString_Clone) +# define RTAsn1GraphicString_Compare RT_MANGLER(RTAsn1GraphicString_Compare) +# define RTAsn1GraphicString_Delete RT_MANGLER(RTAsn1GraphicString_Delete) +# define RTAsn1GraphicString_Enum RT_MANGLER(RTAsn1GraphicString_Enum) +# define RTAsn1GraphicString_Init RT_MANGLER(RTAsn1GraphicString_Init) +# define RTAsn1Ia5String_CheckSanity RT_MANGLER(RTAsn1Ia5String_CheckSanity) +# define RTAsn1Ia5String_Clone RT_MANGLER(RTAsn1Ia5String_Clone) +# define RTAsn1Ia5String_Compare RT_MANGLER(RTAsn1Ia5String_Compare) +# define RTAsn1Ia5String_Delete RT_MANGLER(RTAsn1Ia5String_Delete) +# define RTAsn1Ia5String_Enum RT_MANGLER(RTAsn1Ia5String_Enum) +# define RTAsn1Ia5String_Init RT_MANGLER(RTAsn1Ia5String_Init) +# define RTAsn1NumericString_CheckSanity RT_MANGLER(RTAsn1NumericString_CheckSanity) +# define RTAsn1NumericString_Clone RT_MANGLER(RTAsn1NumericString_Clone) +# define RTAsn1NumericString_Compare RT_MANGLER(RTAsn1NumericString_Compare) +# define RTAsn1NumericString_Delete RT_MANGLER(RTAsn1NumericString_Delete) +# define RTAsn1NumericString_Enum RT_MANGLER(RTAsn1NumericString_Enum) +# define RTAsn1NumericString_Init RT_MANGLER(RTAsn1NumericString_Init) +# define RTAsn1PrintableString_CheckSanity RT_MANGLER(RTAsn1PrintableString_CheckSanity) +# define RTAsn1PrintableString_Clone RT_MANGLER(RTAsn1PrintableString_Clone) +# define RTAsn1PrintableString_Compare RT_MANGLER(RTAsn1PrintableString_Compare) +# define RTAsn1PrintableString_Delete RT_MANGLER(RTAsn1PrintableString_Delete) +# define RTAsn1PrintableString_Enum RT_MANGLER(RTAsn1PrintableString_Enum) +# define RTAsn1PrintableString_Init RT_MANGLER(RTAsn1PrintableString_Init) +# define RTAsn1SeqOfStrings_CheckSanity RT_MANGLER(RTAsn1SeqOfStrings_CheckSanity) +# define RTAsn1SeqOfStrings_Clone RT_MANGLER(RTAsn1SeqOfStrings_Clone) +# define RTAsn1SeqOfStrings_Compare RT_MANGLER(RTAsn1SeqOfStrings_Compare) +# define RTAsn1SeqOfStrings_Delete RT_MANGLER(RTAsn1SeqOfStrings_Delete) +# define RTAsn1SeqOfStrings_Enum RT_MANGLER(RTAsn1SeqOfStrings_Enum) +# define RTAsn1SeqOfStrings_Init RT_MANGLER(RTAsn1SeqOfStrings_Init) +# define RTAsn1SetOfStrings_CheckSanity RT_MANGLER(RTAsn1SetOfStrings_CheckSanity) +# define RTAsn1SetOfStrings_Clone RT_MANGLER(RTAsn1SetOfStrings_Clone) +# define RTAsn1SetOfStrings_Compare RT_MANGLER(RTAsn1SetOfStrings_Compare) +# define RTAsn1SetOfStrings_Delete RT_MANGLER(RTAsn1SetOfStrings_Delete) +# define RTAsn1SetOfStrings_Enum RT_MANGLER(RTAsn1SetOfStrings_Enum) +# define RTAsn1SetOfStrings_Init RT_MANGLER(RTAsn1SetOfStrings_Init) +# define RTAsn1String_CheckSanity RT_MANGLER(RTAsn1String_CheckSanity) +# define RTAsn1String_Clone RT_MANGLER(RTAsn1String_Clone) +# define RTAsn1String_Compare RT_MANGLER(RTAsn1String_Compare) +# define RTAsn1String_CompareEx RT_MANGLER(RTAsn1String_CompareEx) +# define RTAsn1String_CompareValues RT_MANGLER(RTAsn1String_CompareValues) +# define RTAsn1String_CompareWithString RT_MANGLER(RTAsn1String_CompareWithString) +# define RTAsn1String_Delete RT_MANGLER(RTAsn1String_Delete) +# define RTAsn1String_Enum RT_MANGLER(RTAsn1String_Enum) +# define RTAsn1String_Init RT_MANGLER(RTAsn1String_Init) +# define RTAsn1String_InitEx RT_MANGLER(RTAsn1String_InitEx) +# define RTAsn1String_InitWithValue RT_MANGLER(RTAsn1String_InitWithValue) +# define RTAsn1String_QueryUtf8 RT_MANGLER(RTAsn1String_QueryUtf8) +# define RTAsn1String_QueryUtf8Len RT_MANGLER(RTAsn1String_QueryUtf8Len) +# define RTAsn1String_RecodeAsUtf8 RT_MANGLER(RTAsn1String_RecodeAsUtf8) +# define RTAsn1T61String_CheckSanity RT_MANGLER(RTAsn1T61String_CheckSanity) +# define RTAsn1T61String_Clone RT_MANGLER(RTAsn1T61String_Clone) +# define RTAsn1T61String_Compare RT_MANGLER(RTAsn1T61String_Compare) +# define RTAsn1T61String_Delete RT_MANGLER(RTAsn1T61String_Delete) +# define RTAsn1T61String_Enum RT_MANGLER(RTAsn1T61String_Enum) +# define RTAsn1T61String_Init RT_MANGLER(RTAsn1T61String_Init) +# define RTAsn1UniversalString_CheckSanity RT_MANGLER(RTAsn1UniversalString_CheckSanity) +# define RTAsn1UniversalString_Clone RT_MANGLER(RTAsn1UniversalString_Clone) +# define RTAsn1UniversalString_Compare RT_MANGLER(RTAsn1UniversalString_Compare) +# define RTAsn1UniversalString_Delete RT_MANGLER(RTAsn1UniversalString_Delete) +# define RTAsn1UniversalString_Enum RT_MANGLER(RTAsn1UniversalString_Enum) +# define RTAsn1UniversalString_Init RT_MANGLER(RTAsn1UniversalString_Init) +# define RTAsn1Utf8String_CheckSanity RT_MANGLER(RTAsn1Utf8String_CheckSanity) +# define RTAsn1Utf8String_Clone RT_MANGLER(RTAsn1Utf8String_Clone) +# define RTAsn1Utf8String_Compare RT_MANGLER(RTAsn1Utf8String_Compare) +# define RTAsn1Utf8String_Delete RT_MANGLER(RTAsn1Utf8String_Delete) +# define RTAsn1Utf8String_Enum RT_MANGLER(RTAsn1Utf8String_Enum) +# define RTAsn1Utf8String_Init RT_MANGLER(RTAsn1Utf8String_Init) +# define RTAsn1VisibleString_CheckSanity RT_MANGLER(RTAsn1VisibleString_CheckSanity) +# define RTAsn1VisibleString_Clone RT_MANGLER(RTAsn1VisibleString_Clone) +# define RTAsn1VisibleString_Compare RT_MANGLER(RTAsn1VisibleString_Compare) +# define RTAsn1VisibleString_Delete RT_MANGLER(RTAsn1VisibleString_Delete) +# define RTAsn1VisibleString_Enum RT_MANGLER(RTAsn1VisibleString_Enum) +# define RTAsn1VisibleString_Init RT_MANGLER(RTAsn1VisibleString_Init) +# define RTAsn1BmpString_DecodeAsn1 RT_MANGLER(RTAsn1BmpString_DecodeAsn1) +# define RTAsn1GeneralString_DecodeAsn1 RT_MANGLER(RTAsn1GeneralString_DecodeAsn1) +# define RTAsn1GraphicString_DecodeAsn1 RT_MANGLER(RTAsn1GraphicString_DecodeAsn1) +# define RTAsn1Ia5String_DecodeAsn1 RT_MANGLER(RTAsn1Ia5String_DecodeAsn1) +# define RTAsn1NumericString_DecodeAsn1 RT_MANGLER(RTAsn1NumericString_DecodeAsn1) +# define RTAsn1PrintableString_DecodeAsn1 RT_MANGLER(RTAsn1PrintableString_DecodeAsn1) +# define RTAsn1SeqOfStrings_DecodeAsn1 RT_MANGLER(RTAsn1SeqOfStrings_DecodeAsn1) +# define RTAsn1SetOfStrings_DecodeAsn1 RT_MANGLER(RTAsn1SetOfStrings_DecodeAsn1) +# define RTAsn1String_DecodeAsn1 RT_MANGLER(RTAsn1String_DecodeAsn1) +# define RTAsn1T61String_DecodeAsn1 RT_MANGLER(RTAsn1T61String_DecodeAsn1) +# define RTAsn1UniversalString_DecodeAsn1 RT_MANGLER(RTAsn1UniversalString_DecodeAsn1) +# define RTAsn1Utf8String_DecodeAsn1 RT_MANGLER(RTAsn1Utf8String_DecodeAsn1) +# define RTAsn1VisibleString_DecodeAsn1 RT_MANGLER(RTAsn1VisibleString_DecodeAsn1) +# define RTAsn1GeneralizedTime_CheckSanity RT_MANGLER(RTAsn1GeneralizedTime_CheckSanity) +# define RTAsn1GeneralizedTime_Clone RT_MANGLER(RTAsn1GeneralizedTime_Clone) +# define RTAsn1GeneralizedTime_Compare RT_MANGLER(RTAsn1GeneralizedTime_Compare) +# define RTAsn1GeneralizedTime_Delete RT_MANGLER(RTAsn1GeneralizedTime_Delete) +# define RTAsn1GeneralizedTime_Enum RT_MANGLER(RTAsn1GeneralizedTime_Enum) +# define RTAsn1GeneralizedTime_Init RT_MANGLER(RTAsn1GeneralizedTime_Init) +# define RTAsn1SeqOfTimes_CheckSanity RT_MANGLER(RTAsn1SeqOfTimes_CheckSanity) +# define RTAsn1SeqOfTimes_Clone RT_MANGLER(RTAsn1SeqOfTimes_Clone) +# define RTAsn1SeqOfTimes_Compare RT_MANGLER(RTAsn1SeqOfTimes_Compare) +# define RTAsn1SeqOfTimes_Delete RT_MANGLER(RTAsn1SeqOfTimes_Delete) +# define RTAsn1SeqOfTimes_Enum RT_MANGLER(RTAsn1SeqOfTimes_Enum) +# define RTAsn1SeqOfTimes_Init RT_MANGLER(RTAsn1SeqOfTimes_Init) +# define RTAsn1SetOfTimes_CheckSanity RT_MANGLER(RTAsn1SetOfTimes_CheckSanity) +# define RTAsn1SetOfTimes_Clone RT_MANGLER(RTAsn1SetOfTimes_Clone) +# define RTAsn1SetOfTimes_Compare RT_MANGLER(RTAsn1SetOfTimes_Compare) +# define RTAsn1SetOfTimes_Delete RT_MANGLER(RTAsn1SetOfTimes_Delete) +# define RTAsn1SetOfTimes_Enum RT_MANGLER(RTAsn1SetOfTimes_Enum) +# define RTAsn1SetOfTimes_Init RT_MANGLER(RTAsn1SetOfTimes_Init) +# define RTAsn1Time_CheckSanity RT_MANGLER(RTAsn1Time_CheckSanity) +# define RTAsn1Time_Clone RT_MANGLER(RTAsn1Time_Clone) +# define RTAsn1Time_Compare RT_MANGLER(RTAsn1Time_Compare) +# define RTAsn1Time_CompareWithTimeSpec RT_MANGLER(RTAsn1Time_CompareWithTimeSpec) +# define RTAsn1Time_Delete RT_MANGLER(RTAsn1Time_Delete) +# define RTAsn1Time_Enum RT_MANGLER(RTAsn1Time_Enum) +# define RTAsn1Time_Init RT_MANGLER(RTAsn1Time_Init) +# define RTAsn1Time_InitEx RT_MANGLER(RTAsn1Time_InitEx) +# define RTAsn1Time_InitWithTime RT_MANGLER(RTAsn1Time_InitWithTime) +# define RTAsn1Time_SetTime RT_MANGLER(RTAsn1Time_SetTime) +# define RTAsn1Time_SetTimeSpec RT_MANGLER(RTAsn1Time_SetTimeSpec) +# define RTAsn1UtcTime_CheckSanity RT_MANGLER(RTAsn1UtcTime_CheckSanity) +# define RTAsn1UtcTime_Clone RT_MANGLER(RTAsn1UtcTime_Clone) +# define RTAsn1UtcTime_Compare RT_MANGLER(RTAsn1UtcTime_Compare) +# define RTAsn1UtcTime_Delete RT_MANGLER(RTAsn1UtcTime_Delete) +# define RTAsn1UtcTime_Enum RT_MANGLER(RTAsn1UtcTime_Enum) +# define RTAsn1UtcTime_Init RT_MANGLER(RTAsn1UtcTime_Init) +# define RTAsn1GeneralizedTime_DecodeAsn1 RT_MANGLER(RTAsn1GeneralizedTime_DecodeAsn1) +# define RTAsn1SeqOfTimes_DecodeAsn1 RT_MANGLER(RTAsn1SeqOfTimes_DecodeAsn1) +# define RTAsn1SetOfTimes_DecodeAsn1 RT_MANGLER(RTAsn1SetOfTimes_DecodeAsn1) +# define RTAsn1Time_DecodeAsn1 RT_MANGLER(RTAsn1Time_DecodeAsn1) +# define RTAsn1UtcTime_DecodeAsn1 RT_MANGLER(RTAsn1UtcTime_DecodeAsn1) +# define RTMd2 RT_MANGLER(RTMd2) +# define RTMd2Final RT_MANGLER(RTMd2Final) +# define RTMd2Init RT_MANGLER(RTMd2Init) +# define RTMd2Update RT_MANGLER(RTMd2Update) +# define RTMd2FromString RT_MANGLER(RTMd2FromString) +# define RTMd2ToString RT_MANGLER(RTMd2ToString) +# define RTCrCipherDecrypt RT_MANGLER(RTCrCipherDecrypt) +# define RTCrCipherEncrypt RT_MANGLER(RTCrCipherEncrypt) +# define RTCrCipherGetBlockSize RT_MANGLER(RTCrCipherGetBlockSize) +# define RTCrCipherGetInitializationVectorLength RT_MANGLER(RTCrCipherGetInitializationVectorLength) +# define RTCrCipherGetKeyLength RT_MANGLER(RTCrCipherGetKeyLength) +# define RTCrCipherOpenByType RT_MANGLER(RTCrCipherOpenByType) +# define RTCrCipherRetain RT_MANGLER(RTCrCipherRetain) +# define RTCrCipherRelease RT_MANGLER(RTCrCipherRelease) +# define RTCrCipherCtxFree RT_MANGLER(RTCrCipherCtxFree) +# define RTCrCipherCtxDecryptInit RT_MANGLER(RTCrCipherCtxDecryptInit) +# define RTCrCipherCtxDecryptFinish RT_MANGLER(RTCrCipherCtxDecryptFinish) +# define RTCrCipherCtxDecryptProcess RT_MANGLER(RTCrCipherCtxDecryptProcess) +# define RTCrCipherCtxEncryptInit RT_MANLGER(RTCrCipherCtxEncryptInit) +# define RTCrCipherCtxEncryptFinish RT_MANGLER(RTCrCipherCtxEncryptFinish) +# define RTCrCipherCtxEncryptProcess RT_MANGLER(RTCrCipherCtxEncryptProcess) +# define RTCrCipherDecrypt RT_MANGLER(RTCrCipherDecrypt) +# define RTCrCipherDecryptEx RT_MANGLER(RTCrCipherDecryptEx) +# define RTCrCipherEncrypt RT_MANGLER(RTCrCipherEncrypt) +# define RTCrCipherEncryptEx RT_MANGLER(RTCrCipherEncryptEx) +# define RTCrDigestClone RT_MANGLER(RTCrDigestClone) +# define RTCrDigestCreate RT_MANGLER(RTCrDigestCreate) +# define RTCrDigestFinal RT_MANGLER(RTCrDigestFinal) +# define RTCrDigestGetConsumedSize RT_MANGLER(RTCrDigestGetConsumedSize) +# define RTCrDigestGetFlags RT_MANGLER(RTCrDigestGetFlags) +# define RTCrDigestGetHash RT_MANGLER(RTCrDigestGetHash) +# define RTCrDigestGetHashSize RT_MANGLER(RTCrDigestGetHashSize) +# define RTCrDigestGetType RT_MANGLER(RTCrDigestGetType) +# define RTCrDigestGetAlgorithmOid RT_MANGLER(RTCrDigestGetAlgorithmOid) +# define RTCrDigestIsFinalized RT_MANGLER(RTCrDigestIsFinalized) +# define RTCrDigestMatch RT_MANGLER(RTCrDigestMatch) +# define RTCrDigestRelease RT_MANGLER(RTCrDigestRelease) +# define RTCrDigestReset RT_MANGLER(RTCrDigestReset) +# define RTCrDigestRetain RT_MANGLER(RTCrDigestRetain) +# define RTCrDigestUpdate RT_MANGLER(RTCrDigestUpdate) +# define RTCrDigestUpdateFromVfsFile RT_MANGLER(RTCrDigestUpdateFromVfsFile) +# define RTCrDigestCreateByObjId RT_MANGLER(RTCrDigestCreateByObjId) +# define RTCrDigestCreateByObjIdString RT_MANGLER(RTCrDigestCreateByObjIdString) +# define RTCrDigestCreateByType RT_MANGLER(RTCrDigestCreateByType) +# define RTCrDigestFindByObjId RT_MANGLER(RTCrDigestFindByObjId) +# define RTCrDigestFindByObjIdString RT_MANGLER(RTCrDigestFindByObjIdString) +# define RTCrDigestFindByType RT_MANGLER(RTCrDigestFindByType) +# define RTCrDigestTypeToAlgorithmOid RT_MANGLER(RTCrDigestTypeToAlgorithmOid) +# define RTCrDigestTypeToName RT_MANGLER(RTCrDigestTypeToName) +# define RTCrDigestTypeToHashSize RT_MANGLER(RTCrDigestTypeToHashSize) +# define RTCrKeyCreateFromBuffer RT_MANGLER(RTCrKeyCreateFromBuffer) +# define RTCrKeyCreateFromFile RT_MANGLER(RTCrKeyCreateFromFile) +# define RTCrKeyCreateFromPemSection RT_MANGLER(RTCrKeyCreateFromPemSection) +# define RTCrKeyCreateFromPublicAlgorithmAndBits RT_MANGLER(RTCrKeyCreateFromPublicAlgorithmAndBits) +# define RTCrKeyCreateFromSubjectPublicKeyInfo RT_MANGLER(RTCrKeyCreateFromSubjectPublicKeyInfo) +# define RTCrKeyCreateNewRsa RT_MANGLER(RTCrKeyCreateNewRsa) +# define RTCrKeyGetBitCount RT_MANGLER(RTCrKeyGetBitCount) +# define RTCrKeyGetType RT_MANGLER(RTCrKeyGetType) +# define RTCrKeyHasPrivatePart RT_MANGLER(RTCrKeyHasPrivatePart) +# define RTCrKeyHasPublicPart RT_MANGLER(RTCrKeyHasPublicPart) +# define RTCrKeyRelease RT_MANGLER(RTCrKeyRelease) +# define RTCrKeyRetain RT_MANGLER(RTCrKeyRetain) +# define RTCrKeyQueryRsaModulus RT_MANGLER(RTCrKeyQueryRsaModulus) +# define RTCrKeyQueryRsaPrivateExponent RT_MANGLER(RTCrKeyQueryRsaPrivateExponent) +# define RTCrRc4 RT_MANGLER(RTCrRc4) +# define RTCrRc4SetKey RT_MANGLER(RTCrRc4SetKey) +# define RTCrRsaDigestInfo_DecodeAsn1 RT_MANGLER(RTCrRsaDigestInfo_DecodeAsn1) +# define RTCrRsaOtherPrimeInfo_DecodeAsn1 RT_MANGLER(RTCrRsaOtherPrimeInfo_DecodeAsn1) +# define RTCrRsaOtherPrimeInfos_DecodeAsn1 RT_MANGLER(RTCrRsaOtherPrimeInfos_DecodeAsn1) +# define RTCrRsaPrivateKey_DecodeAsn1 RT_MANGLER(RTCrRsaPrivateKey_DecodeAsn1) +# define RTCrRsaPublicKey_DecodeAsn1 RT_MANGLER(RTCrRsaPublicKey_DecodeAsn1) +# define RTCrRsaDigestInfo_Compare RT_MANGLER(RTCrRsaDigestInfo_Compare) +# define RTCrRsaDigestInfo_Delete RT_MANGLER(RTCrRsaDigestInfo_Delete) +# define RTCrRsaDigestInfo_Enum RT_MANGLER(RTCrRsaDigestInfo_Enum) +# define RTCrRsaOtherPrimeInfo_Compare RT_MANGLER(RTCrRsaOtherPrimeInfo_Compare) +# define RTCrRsaOtherPrimeInfo_Delete RT_MANGLER(RTCrRsaOtherPrimeInfo_Delete) +# define RTCrRsaOtherPrimeInfo_Enum RT_MANGLER(RTCrRsaOtherPrimeInfo_Enum) +# define RTCrRsaOtherPrimeInfos_Compare RT_MANGLER(RTCrRsaOtherPrimeInfos_Compare) +# define RTCrRsaOtherPrimeInfos_Delete RT_MANGLER(RTCrRsaOtherPrimeInfos_Delete) +# define RTCrRsaOtherPrimeInfos_Enum RT_MANGLER(RTCrRsaOtherPrimeInfos_Enum) +# define RTCrRsaPrivateKey_Compare RT_MANGLER(RTCrRsaPrivateKey_Compare) +# define RTCrRsaPrivateKey_Delete RT_MANGLER(RTCrRsaPrivateKey_Delete) +# define RTCrRsaPrivateKey_Enum RT_MANGLER(RTCrRsaPrivateKey_Enum) +# define RTCrRsaPublicKey_Compare RT_MANGLER(RTCrRsaPublicKey_Compare) +# define RTCrRsaPublicKey_Delete RT_MANGLER(RTCrRsaPublicKey_Delete) +# define RTCrRsaPublicKey_Enum RT_MANGLER(RTCrRsaPublicKey_Enum) +# define RTCrRsaDigestInfo_Clone RT_MANGLER(RTCrRsaDigestInfo_Clone) +# define RTCrRsaDigestInfo_Init RT_MANGLER(RTCrRsaDigestInfo_Init) +# define RTCrRsaOtherPrimeInfo_Clone RT_MANGLER(RTCrRsaOtherPrimeInfo_Clone) +# define RTCrRsaOtherPrimeInfo_Init RT_MANGLER(RTCrRsaOtherPrimeInfo_Init) +# define RTCrRsaOtherPrimeInfos_Clone RT_MANGLER(RTCrRsaOtherPrimeInfos_Clone) +# define RTCrRsaOtherPrimeInfos_Init RT_MANGLER(RTCrRsaOtherPrimeInfos_Init) +# define RTCrRsaPrivateKey_Clone RT_MANGLER(RTCrRsaPrivateKey_Clone) +# define RTCrRsaPrivateKey_Init RT_MANGLER(RTCrRsaPrivateKey_Init) +# define RTCrRsaPublicKey_Clone RT_MANGLER(RTCrRsaPublicKey_Clone) +# define RTCrRsaPublicKey_Init RT_MANGLER(RTCrRsaPublicKey_Init) +# define RTCrRsaDigestInfo_CheckSanity RT_MANGLER(RTCrRsaDigestInfo_CheckSanity) +# define RTCrRsaOtherPrimeInfo_CheckSanity RT_MANGLER(RTCrRsaOtherPrimeInfo_CheckSanity) +# define RTCrRsaOtherPrimeInfos_CheckSanity RT_MANGLER(RTCrRsaOtherPrimeInfos_CheckSanity) +# define RTCrRsaPrivateKey_CheckSanity RT_MANGLER(RTCrRsaPrivateKey_CheckSanity) +# define RTCrRsaPrivateKey_CanHandleDigestType RT_MANGLER(RTCrRsaPrivateKey_CanHandleDigestType) +# define RTCrRsaPublicKey_CheckSanity RT_MANGLER(RTCrRsaPublicKey_CheckSanity) +# define RTCrRsaPublicKey_CanHandleDigestType RT_MANGLER(RTCrRsaPublicKey_CanHandleDigestType) +# define RTCrPemFindFirstSectionInContent RT_MANGLER(RTCrPemFindFirstSectionInContent) +# define RTCrPemFreeSections RT_MANGLER(RTCrPemFreeSections) +# define RTCrPemParseContent RT_MANGLER(RTCrPemParseContent) +# define RTCrPemReadFile RT_MANGLER(RTCrPemReadFile) +# define RTCrPemWriteBlob RT_MANGLER(RTCrPemWriteBlob) +# define RTCrPemWriteBlobToVfsIoStrm RT_MANGLER(RTCrPemWriteBlobToVfsIoStrm) +# define RTCrPemWriteBlobToVfsFile RT_MANGLER(RTCrPemWriteBlobToVfsFile) +# define RTCrPemWriteAsn1 RT_MANGLER(RTCrPemWriteAsn1) +# define RTCrPemWriteAsn1ToVfsIoStrm RT_MANGLER(RTCrPemWriteAsn1ToVfsIoStrm) +# define RTCrPemWriteAsn1ToVfsFile RT_MANGLER(RTCrPemWriteAsn1ToVfsFile) +# define RTCrPkcs5Pbkdf2Hmac RT_MANGLER(RTCrPkcs5Pbkdf2Hmac) +# define RTCrPkcs7_ReadFromBuffer RT_MANGLER(RTCrPkcs7_ReadFromBuffer) +# define RTCrPkcs7Attribute_SetAppleMultiCdPlist RT_MANGLER(RTCrPkcs7Attribute_SetAppleMultiCdPlist) +# define RTCrPkcs7Attribute_SetContentType RT_MANGLER(RTCrPkcs7Attribute_SetContentType) +# define RTCrPkcs7Attribute_SetCounterSignatures RT_MANGLER(RTCrPkcs7Attribute_SetCounterSignatures) +# define RTCrPkcs7Attribute_SetMessageDigest RT_MANGLER(RTCrPkcs7Attribute_SetMessageDigest) +# define RTCrPkcs7Attribute_SetMsStatementType RT_MANGLER(RTCrPkcs7Attribute_SetMsStatementType) +# define RTCrPkcs7Attribute_SetMsNestedSignature RT_MANGLER(RTCrPkcs7Attribute_SetMsNestedSignature) +# define RTCrPkcs7Attribute_SetMsTimestamp RT_MANGLER(RTCrPkcs7Attribute_SetMsTimestamp) +# define RTCrPkcs7Attribute_SetSigningTime RT_MANGLER(RTCrPkcs7Attribute_SetSigningTime) +# define RTCrPkcs7Attributes_HashAttributes RT_MANGLER(RTCrPkcs7Attributes_HashAttributes) +# define RTCrPkcs7Attribute_DecodeAsn1 RT_MANGLER(RTCrPkcs7Attribute_DecodeAsn1) +# define RTCrPkcs7Attributes_DecodeAsn1 RT_MANGLER(RTCrPkcs7Attributes_DecodeAsn1) +# define RTCrPkcs7ContentInfo_DecodeAsn1 RT_MANGLER(RTCrPkcs7ContentInfo_DecodeAsn1) +# define RTCrPkcs7DigestInfo_DecodeAsn1 RT_MANGLER(RTCrPkcs7DigestInfo_DecodeAsn1) +# define RTCrPkcs7IssuerAndSerialNumber_DecodeAsn1 RT_MANGLER(RTCrPkcs7IssuerAndSerialNumber_DecodeAsn1) +# define RTCrPkcs7SignedData_SetCertificates RT_MANGLER(RTCrPkcs7SignedData_SetCertificates) +# define RTCrPkcs7SignedData_SetCrls RT_MANGLER(RTCrPkcs7SignedData_SetCrls) +# define RTCrPkcs7SignedData_DecodeAsn1 RT_MANGLER(RTCrPkcs7SignedData_DecodeAsn1) +# define RTCrPkcs7SignerInfo_SetAuthenticatedAttributes RT_MANGLER(RTCrPkcs7SignerInfo_SetAuthenticatedAttributes) +# define RTCrPkcs7SignerInfo_SetUnauthenticatedAttributes RT_MANGLER(RTCrPkcs7SignerInfo_SetUnauthenticatedAttributes) +# define RTCrPkcs7SignerInfo_DecodeAsn1 RT_MANGLER(RTCrPkcs7SignerInfo_DecodeAsn1) +# define RTCrPkcs7SignerInfos_DecodeAsn1 RT_MANGLER(RTCrPkcs7SignerInfos_DecodeAsn1) +# define RTCrPkcs7Attribute_Compare RT_MANGLER(RTCrPkcs7Attribute_Compare) +# define RTCrPkcs7Attribute_Delete RT_MANGLER(RTCrPkcs7Attribute_Delete) +# define RTCrPkcs7Attribute_Enum RT_MANGLER(RTCrPkcs7Attribute_Enum) +# define RTCrPkcs7Attributes_Compare RT_MANGLER(RTCrPkcs7Attributes_Compare) +# define RTCrPkcs7Attributes_Delete RT_MANGLER(RTCrPkcs7Attributes_Delete) +# define RTCrPkcs7Attributes_Enum RT_MANGLER(RTCrPkcs7Attributes_Enum) +# define RTCrPkcs7ContentInfo_Compare RT_MANGLER(RTCrPkcs7ContentInfo_Compare) +# define RTCrPkcs7ContentInfo_Delete RT_MANGLER(RTCrPkcs7ContentInfo_Delete) +# define RTCrPkcs7ContentInfo_Enum RT_MANGLER(RTCrPkcs7ContentInfo_Enum) +# define RTCrPkcs7ContentInfo_IsSignedData RT_MANGLER(RTCrPkcs7ContentInfo_IsSignedData) +# define RTCrPkcs7DigestInfo_Compare RT_MANGLER(RTCrPkcs7DigestInfo_Compare) +# define RTCrPkcs7DigestInfo_Delete RT_MANGLER(RTCrPkcs7DigestInfo_Delete) +# define RTCrPkcs7DigestInfo_Enum RT_MANGLER(RTCrPkcs7DigestInfo_Enum) +# define RTCrPkcs7IssuerAndSerialNumber_Compare RT_MANGLER(RTCrPkcs7IssuerAndSerialNumber_Compare) +# define RTCrPkcs7IssuerAndSerialNumber_Delete RT_MANGLER(RTCrPkcs7IssuerAndSerialNumber_Delete) +# define RTCrPkcs7IssuerAndSerialNumber_Enum RT_MANGLER(RTCrPkcs7IssuerAndSerialNumber_Enum) +# define RTCrPkcs7SignedData_Compare RT_MANGLER(RTCrPkcs7SignedData_Compare) +# define RTCrPkcs7SignedData_Delete RT_MANGLER(RTCrPkcs7SignedData_Delete) +# define RTCrPkcs7SignedData_Enum RT_MANGLER(RTCrPkcs7SignedData_Enum) +# define RTCrPkcs7SignerInfo_Compare RT_MANGLER(RTCrPkcs7SignerInfo_Compare) +# define RTCrPkcs7SignerInfo_Delete RT_MANGLER(RTCrPkcs7SignerInfo_Delete) +# define RTCrPkcs7SignerInfo_Enum RT_MANGLER(RTCrPkcs7SignerInfo_Enum) +# define RTCrPkcs7SignerInfo_GetSigningTime RT_MANGLER(RTCrPkcs7SignerInfo_GetSigningTime) +# define RTCrPkcs7SignerInfo_GetMsTimestamp RT_MANGLER(RTCrPkcs7SignerInfo_GetMsTimestamp) +# define RTCrPkcs7SignerInfos_Compare RT_MANGLER(RTCrPkcs7SignerInfos_Compare) +# define RTCrPkcs7SignerInfos_Delete RT_MANGLER(RTCrPkcs7SignerInfos_Delete) +# define RTCrPkcs7SignerInfos_Enum RT_MANGLER(RTCrPkcs7SignerInfos_Enum) +# define RTCrPkcs7Attribute_Clone RT_MANGLER(RTCrPkcs7Attribute_Clone) +# define RTCrPkcs7Attribute_Init RT_MANGLER(RTCrPkcs7Attribute_Init) +# define RTCrPkcs7Attributes_Clone RT_MANGLER(RTCrPkcs7Attributes_Clone) +# define RTCrPkcs7Attributes_Init RT_MANGLER(RTCrPkcs7Attributes_Init) +# define RTCrPkcs7ContentInfo_Clone RT_MANGLER(RTCrPkcs7ContentInfo_Clone) +# define RTCrPkcs7ContentInfo_Init RT_MANGLER(RTCrPkcs7ContentInfo_Init) +# define RTCrPkcs7DigestInfo_Clone RT_MANGLER(RTCrPkcs7DigestInfo_Clone) +# define RTCrPkcs7DigestInfo_Init RT_MANGLER(RTCrPkcs7DigestInfo_Init) +# define RTCrPkcs7IssuerAndSerialNumber_Clone RT_MANGLER(RTCrPkcs7IssuerAndSerialNumber_Clone) +# define RTCrPkcs7IssuerAndSerialNumber_Init RT_MANGLER(RTCrPkcs7IssuerAndSerialNumber_Init) +# define RTCrPkcs7SignedData_Clone RT_MANGLER(RTCrPkcs7SignedData_Clone) +# define RTCrPkcs7SignedData_Init RT_MANGLER(RTCrPkcs7SignedData_Init) +# define RTCrPkcs7SignerInfo_Clone RT_MANGLER(RTCrPkcs7SignerInfo_Clone) +# define RTCrPkcs7SignerInfo_Init RT_MANGLER(RTCrPkcs7SignerInfo_Init) +# define RTCrPkcs7SignerInfos_Clone RT_MANGLER(RTCrPkcs7SignerInfos_Clone) +# define RTCrPkcs7SignerInfos_Init RT_MANGLER(RTCrPkcs7SignerInfos_Init) +# define RTCrPkcs7Attribute_CheckSanity RT_MANGLER(RTCrPkcs7Attribute_CheckSanity) +# define RTCrPkcs7Attributes_CheckSanity RT_MANGLER(RTCrPkcs7Attributes_CheckSanity) +# define RTCrPkcs7ContentInfo_CheckSanity RT_MANGLER(RTCrPkcs7ContentInfo_CheckSanity) +# define RTCrPkcs7DigestInfo_CheckSanity RT_MANGLER(RTCrPkcs7DigestInfo_CheckSanity) +# define RTCrPkcs7IssuerAndSerialNumber_CheckSanity RT_MANGLER(RTCrPkcs7IssuerAndSerialNumber_CheckSanity) +# define RTCrPkcs7SignedData_CheckSanity RT_MANGLER(RTCrPkcs7SignedData_CheckSanity) +# define RTCrPkcs7SignerInfo_CheckSanity RT_MANGLER(RTCrPkcs7SignerInfo_CheckSanity) +# define RTCrPkcs7SignerInfos_CheckSanity RT_MANGLER(RTCrPkcs7SignerInfos_CheckSanity) +# define RTCrPkcs7SimpleSignSignedData RT_MANGLER(RTCrPkcs7SimpleSignSignedData) +# define RTCrPkcs7VerifyCertCallbackCodeSigning RT_MANGLER(RTCrPkcs7VerifyCertCallbackCodeSigning) +# define RTCrPkcs7VerifyCertCallbackDefault RT_MANGLER(RTCrPkcs7VerifyCertCallbackDefault) +# define RTCrPkcs7VerifySignedData RT_MANGLER(RTCrPkcs7VerifySignedData) +# define RTCrPkcs7VerifySignedDataWithExternalData RT_MANGLER(RTCrPkcs7VerifySignedDataWithExternalData) +# define RTCrPkcs7Cert_SetX509Cert RT_MANGLER(RTCrPkcs7Cert_SetX509Cert) +# define RTCrPkcs7Cert_SetExtendedCert RT_MANGLER(RTCrPkcs7Cert_SetExtendedCert) +# define RTCrPkcs7Cert_SetAcV1 RT_MANGLER(RTCrPkcs7Cert_SetAcV1) +# define RTCrPkcs7Cert_SetAcV2 RT_MANGLER(RTCrPkcs7Cert_SetAcV2) +# define RTCrPkcs7Cert_SetOtherCert RT_MANGLER(RTCrPkcs7Cert_SetOtherCert) +# define RTCrPkcs7Cert_CheckSanity RT_MANGLER(RTCrPkcs7Cert_CheckSanity) +# define RTCrPkcs7Cert_Clone RT_MANGLER(RTCrPkcs7Cert_Clone) +# define RTCrPkcs7Cert_Compare RT_MANGLER(RTCrPkcs7Cert_Compare) +# define RTCrPkcs7Cert_DecodeAsn1 RT_MANGLER(RTCrPkcs7Cert_DecodeAsn1) +# define RTCrPkcs7Cert_Delete RT_MANGLER(RTCrPkcs7Cert_Delete) +# define RTCrPkcs7Cert_Enum RT_MANGLER(RTCrPkcs7Cert_Enum) +# define RTCrPkcs7Cert_Init RT_MANGLER(RTCrPkcs7Cert_Init) +# define RTCrPkcs7SetOfCerts_CheckSanity RT_MANGLER(RTCrPkcs7SetOfCerts_CheckSanity) +# define RTCrPkcs7SetOfCerts_Clone RT_MANGLER(RTCrPkcs7SetOfCerts_Clone) +# define RTCrPkcs7SetOfCerts_Compare RT_MANGLER(RTCrPkcs7SetOfCerts_Compare) +# define RTCrPkcs7SetOfCerts_DecodeAsn1 RT_MANGLER(RTCrPkcs7SetOfCerts_DecodeAsn1) +# define RTCrPkcs7SetOfCerts_Delete RT_MANGLER(RTCrPkcs7SetOfCerts_Delete) +# define RTCrPkcs7SetOfCerts_Enum RT_MANGLER(RTCrPkcs7SetOfCerts_Enum) +# define RTCrPkcs7SetOfCerts_Init RT_MANGLER(RTCrPkcs7SetOfCerts_Init) +# define RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber RT_MANGLER(RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber) +# define RTCrPkcs7SetOfContentInfos_CheckSanity RT_MANGLER(RTCrPkcs7SetOfContentInfos_CheckSanity) +# define RTCrPkcs7SetOfContentInfos_Clone RT_MANGLER(RTCrPkcs7SetOfContentInfos_Clone) +# define RTCrPkcs7SetOfContentInfos_Compare RT_MANGLER(RTCrPkcs7SetOfContentInfos_Compare) +# define RTCrPkcs7SetOfContentInfos_DecodeAsn1 RT_MANGLER(RTCrPkcs7SetOfContentInfos_DecodeAsn1) +# define RTCrPkcs7SetOfContentInfos_Delete RT_MANGLER(RTCrPkcs7SetOfContentInfos_Delete) +# define RTCrPkcs7SetOfContentInfos_Enum RT_MANGLER(RTCrPkcs7SetOfContentInfos_Enum) +# define RTCrPkcs7SetOfContentInfos_Init RT_MANGLER(RTCrPkcs7SetOfContentInfos_Init) +# define RTCrPkcs7SetOfSignedData_CheckSanity RT_MANGLER(RTCrPkcs7SetOfSignedData_CheckSanity) +# define RTCrPkcs7SetOfSignedData_Clone RT_MANGLER(RTCrPkcs7SetOfSignedData_Clone) +# define RTCrPkcs7SetOfSignedData_Compare RT_MANGLER(RTCrPkcs7SetOfSignedData_Compare) +# define RTCrPkcs7SetOfSignedData_DecodeAsn1 RT_MANGLER(RTCrPkcs7SetOfSignedData_DecodeAsn1) +# define RTCrPkcs7SetOfSignedData_Delete RT_MANGLER(RTCrPkcs7SetOfSignedData_Delete) +# define RTCrPkcs7SetOfSignedData_Enum RT_MANGLER(RTCrPkcs7SetOfSignedData_Enum) +# define RTCrPkcs7SetOfSignedData_Init RT_MANGLER(RTCrPkcs7SetOfSignedData_Init) +# define RTCrPkixSignatureCreateByObjId RT_MANGLER(RTCrPkixSignatureCreateByObjId) +# define RTCrPkixSignatureCreateByObjIdString RT_MANGLER(RTCrPkixSignatureCreateByObjIdString) +# define RTCrPkixSignatureCreate RT_MANGLER(RTCrPkixSignatureCreate) +# define RTCrPkixSignatureFindByObjId RT_MANGLER(RTCrPkixSignatureFindByObjId) +# define RTCrPkixSignatureFindByObjIdString RT_MANGLER(RTCrPkixSignatureFindByObjIdString) +# define RTCrPkixSignatureRelease RT_MANGLER(RTCrPkixSignatureRelease) +# define RTCrPkixSignatureRetain RT_MANGLER(RTCrPkixSignatureRetain) +# define RTCrPkixSignatureSign RT_MANGLER(RTCrPkixSignatureSign) +# define RTCrPkixSignatureVerify RT_MANGLER(RTCrPkixSignatureVerify) +# define RTCrPkixSignatureVerifyBitString RT_MANGLER(RTCrPkixSignatureVerifyBitString) +# define RTCrPkixSignatureVerifyOctetString RT_MANGLER(RTCrPkixSignatureVerifyOctetString) +# define RTCrPkixGetCiperOidFromSignatureAlgorithm RT_MANGLER(RTCrPkixGetCiperOidFromSignatureAlgorithm) +# define RTCrPkixPubKeySignDigest RT_MANGLER(RTCrPkixPubKeySignDigest) +# define RTCrPkixPubKeyVerifySignature RT_MANGLER(RTCrPkixPubKeyVerifySignature) +# define RTCrPkixPubKeyVerifySignedDigest RT_MANGLER(RTCrPkixPubKeyVerifySignedDigest) +# define RTCrPkixPubKeyVerifySignedDigestByCertPubKeyInfo RT_MANGLER(RTCrPkixPubKeyVerifySignedDigestByCertPubKeyInfo) +# define RTCrPkixPubKeyCanHandleDigestType RT_MANGLER(RTCrPkixPubKeyCanHandleDigestType) +# define RTCrPkixCanCertHandleDigestType RT_MANGLER(RTCrPkixCanCertHandleDigestType) +# define RTCrRandBytes RT_MANGLER(RTCrRandBytes) +# define RTCrSpcAttributeTypeAndOptionalValue_SetPeImage RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_SetPeImage) +# define RTCrSpcAttributeTypeAndOptionalValue_DecodeAsn1 RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_DecodeAsn1) +# define RTCrSpcIndirectDataContent_DecodeAsn1 RT_MANGLER(RTCrSpcIndirectDataContent_DecodeAsn1) +# define RTCrSpcLink_DecodeAsn1 RT_MANGLER(RTCrSpcLink_DecodeAsn1) +# define RTCrSpcPeImageData_SetFile RT_MANGLER(RTCrSpcPeImageData_SetFile) +# define RTCrSpcPeImageData_SetFlags RT_MANGLER(RTCrSpcPeImageData_SetFlags) +# define RTCrSpcPeImageData_DecodeAsn1 RT_MANGLER(RTCrSpcPeImageData_DecodeAsn1) +# define RTCrSpcSerializedObjectAttribute_SetV1Hashes RT_MANGLER(RTCrSpcSerializedObjectAttribute_SetV1Hashes) +# define RTCrSpcSerializedObjectAttribute_SetV2Hashes RT_MANGLER(RTCrSpcSerializedObjectAttribute_SetV2Hashes) +# define RTCrSpcSerializedObjectAttribute_DecodeAsn1 RT_MANGLER(RTCrSpcSerializedObjectAttribute_DecodeAsn1) +# define RTCrSpcSerializedObjectAttributes_DecodeAsn1 RT_MANGLER(RTCrSpcSerializedObjectAttributes_DecodeAsn1) +# define RTCrSpcSerializedObject_DecodeAsn1 RT_MANGLER(RTCrSpcSerializedObject_DecodeAsn1) +# define RTCrSpcSerializedPageHashes_DecodeAsn1 RT_MANGLER(RTCrSpcSerializedPageHashes_DecodeAsn1) +# define RTCrSpcString_DecodeAsn1 RT_MANGLER(RTCrSpcString_DecodeAsn1) +# define RTCrSpcAttributeTypeAndOptionalValue_Compare RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_Compare) +# define RTCrSpcAttributeTypeAndOptionalValue_Delete RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_Delete) +# define RTCrSpcAttributeTypeAndOptionalValue_Enum RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_Enum) +# define RTCrSpcIndirectDataContent_Compare RT_MANGLER(RTCrSpcIndirectDataContent_Compare) +# define RTCrSpcIndirectDataContent_Delete RT_MANGLER(RTCrSpcIndirectDataContent_Delete) +# define RTCrSpcIndirectDataContent_Enum RT_MANGLER(RTCrSpcIndirectDataContent_Enum) +# define RTCrSpcIndirectDataContent_GetPeImageObjAttrib RT_MANGLER(RTCrSpcIndirectDataContent_GetPeImageObjAttrib) +# define RTCrSpcLink_SetFile RT_MANGLER(RTCrSpcLink_SetFile) +# define RTCrSpcLink_SetMoniker RT_MANGLER(RTCrSpcLink_SetMoniker) +# define RTCrSpcLink_SetUrl RT_MANGLER(RTCrSpcLink_SetUrl) +# define RTCrSpcLink_Compare RT_MANGLER(RTCrSpcLink_Compare) +# define RTCrSpcLink_Delete RT_MANGLER(RTCrSpcLink_Delete) +# define RTCrSpcLink_Enum RT_MANGLER(RTCrSpcLink_Enum) +# define RTCrSpcPeImageData_Compare RT_MANGLER(RTCrSpcPeImageData_Compare) +# define RTCrSpcPeImageData_Delete RT_MANGLER(RTCrSpcPeImageData_Delete) +# define RTCrSpcPeImageData_Enum RT_MANGLER(RTCrSpcPeImageData_Enum) +# define RTCrSpcSerializedObjectAttribute_Compare RT_MANGLER(RTCrSpcSerializedObjectAttribute_Compare) +# define RTCrSpcSerializedObjectAttribute_Delete RT_MANGLER(RTCrSpcSerializedObjectAttribute_Delete) +# define RTCrSpcSerializedObjectAttribute_Enum RT_MANGLER(RTCrSpcSerializedObjectAttribute_Enum) +# define RTCrSpcSerializedObjectAttributes_Compare RT_MANGLER(RTCrSpcSerializedObjectAttributes_Compare) +# define RTCrSpcSerializedObjectAttributes_Delete RT_MANGLER(RTCrSpcSerializedObjectAttributes_Delete) +# define RTCrSpcSerializedObjectAttributes_Enum RT_MANGLER(RTCrSpcSerializedObjectAttributes_Enum) +# define RTCrSpcSerializedObject_Compare RT_MANGLER(RTCrSpcSerializedObject_Compare) +# define RTCrSpcSerializedObject_Delete RT_MANGLER(RTCrSpcSerializedObject_Delete) +# define RTCrSpcSerializedObject_Enum RT_MANGLER(RTCrSpcSerializedObject_Enum) +# define RTCrSpcSerializedPageHashes_Compare RT_MANGLER(RTCrSpcSerializedPageHashes_Compare) +# define RTCrSpcSerializedPageHashes_Delete RT_MANGLER(RTCrSpcSerializedPageHashes_Delete) +# define RTCrSpcSerializedPageHashes_Enum RT_MANGLER(RTCrSpcSerializedPageHashes_Enum) +# define RTCrSpcSerializedPageHashes_UpdateDerivedData RT_MANGLER(RTCrSpcSerializedPageHashes_UpdateDerivedData) +# define RTCrSpcString_Compare RT_MANGLER(RTCrSpcString_Compare) +# define RTCrSpcString_Delete RT_MANGLER(RTCrSpcString_Delete) +# define RTCrSpcString_Enum RT_MANGLER(RTCrSpcString_Enum) +# define RTCrSpcAttributeTypeAndOptionalValue_Clone RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_Clone) +# define RTCrSpcAttributeTypeAndOptionalValue_Init RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_Init) +# define RTCrSpcIndirectDataContent_Clone RT_MANGLER(RTCrSpcIndirectDataContent_Clone) +# define RTCrSpcIndirectDataContent_Init RT_MANGLER(RTCrSpcIndirectDataContent_Init) +# define RTCrSpcString_SetAscii RT_MANGLER(RTCrSpcString_SetAscii) +# define RTCrSpcString_SetUcs2 RT_MANGLER(RTCrSpcString_SetUcs2) +# define RTCrSpcLink_Clone RT_MANGLER(RTCrSpcLink_Clone) +# define RTCrSpcLink_Init RT_MANGLER(RTCrSpcLink_Init) +# define RTCrSpcPeImageData_Clone RT_MANGLER(RTCrSpcPeImageData_Clone) +# define RTCrSpcPeImageData_Init RT_MANGLER(RTCrSpcPeImageData_Init) +# define RTCrSpcSerializedObjectAttribute_Clone RT_MANGLER(RTCrSpcSerializedObjectAttribute_Clone) +# define RTCrSpcSerializedObjectAttribute_Init RT_MANGLER(RTCrSpcSerializedObjectAttribute_Init) +# define RTCrSpcSerializedObjectAttributes_Clone RT_MANGLER(RTCrSpcSerializedObjectAttributes_Clone) +# define RTCrSpcSerializedObjectAttributes_Init RT_MANGLER(RTCrSpcSerializedObjectAttributes_Init) +# define RTCrSpcSerializedObject_Clone RT_MANGLER(RTCrSpcSerializedObject_Clone) +# define RTCrSpcSerializedObject_Init RT_MANGLER(RTCrSpcSerializedObject_Init) +# define RTCrSpcSerializedPageHashes_Clone RT_MANGLER(RTCrSpcSerializedPageHashes_Clone) +# define RTCrSpcSerializedPageHashes_Init RT_MANGLER(RTCrSpcSerializedPageHashes_Init) +# define RTCrSpcString_Clone RT_MANGLER(RTCrSpcString_Clone) +# define RTCrSpcString_Init RT_MANGLER(RTCrSpcString_Init) +# define RTCrSpcAttributeTypeAndOptionalValue_CheckSanity RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_CheckSanity) +# define RTCrSpcIndirectDataContent_CheckSanity RT_MANGLER(RTCrSpcIndirectDataContent_CheckSanity) +# define RTCrSpcIndirectDataContent_CheckSanityEx RT_MANGLER(RTCrSpcIndirectDataContent_CheckSanityEx) +# define RTCrSpcLink_CheckSanity RT_MANGLER(RTCrSpcLink_CheckSanity) +# define RTCrSpcPeImageData_CheckSanity RT_MANGLER(RTCrSpcPeImageData_CheckSanity) +# define RTCrSpcSerializedObjectAttribute_CheckSanity RT_MANGLER(RTCrSpcSerializedObjectAttribute_CheckSanity) +# define RTCrSpcSerializedObjectAttributes_CheckSanity RT_MANGLER(RTCrSpcSerializedObjectAttributes_CheckSanity) +# define RTCrSpcSerializedObject_CheckSanity RT_MANGLER(RTCrSpcSerializedObject_CheckSanity) +# define RTCrSpcSerializedPageHashes_CheckSanity RT_MANGLER(RTCrSpcSerializedPageHashes_CheckSanity) +# define RTCrSpcString_CheckSanity RT_MANGLER(RTCrSpcString_CheckSanity) +# define RTCrSslCreate RT_MANGLER(RTCrSslCreate) +# define RTCrSslCreateSessionForNativeSocket RT_MANGLER(RTCrSslCreateSessionForNativeSocket) +# define RTCrSslLoadTrustedRootCerts RT_MANGLER(RTCrSslLoadTrustedRootCerts) +# define RTCrSslRelease RT_MANGLER(RTCrSslRelease) +# define RTCrSslRetain RT_MANGLER(RTCrSslRetain) +# define RTCrSslSessionAccept RT_MANGLER(RTCrSslSessionAccept) +# define RTCrSslSessionConnect RT_MANGLER(RTCrSslSessionConnect) +# define RTCrSslSessionGetCertIssuerNameAsString RT_MANGLER(RTCrSslSessionGetCertIssuerNameAsString) +# define RTCrSslSessionGetVersion RT_MANGLER(RTCrSslSessionGetVersion) +# define RTCrSslSessionPending RT_MANGLER(RTCrSslSessionPending) +# define RTCrSslSessionRead RT_MANGLER(RTCrSslSessionRead) +# define RTCrSslSessionRelease RT_MANGLER(RTCrSslSessionRelease) +# define RTCrSslSessionRetain RT_MANGLER(RTCrSslSessionRetain) +# define RTCrSslSessionWrite RT_MANGLER(RTCrSslSessionWrite) +# define RTCrSslSetCertificateFile RT_MANGLER(RTCrSslSetCertificateFile) +# define RTCrSslSetNoPeerVerify RT_MANGLER(RTCrSslSetNoPeerVerify) +# define RTCrSslSetPrivateKeyFile RT_MANGLER(RTCrSslSetPrivateKeyFile) +# define RTCrX509AlgorithmIdentifier_DecodeAsn1 RT_MANGLER(RTCrX509AlgorithmIdentifier_DecodeAsn1) +# define RTCrX509AlgorithmIdentifiers_DecodeAsn1 RT_MANGLER(RTCrX509AlgorithmIdentifiers_DecodeAsn1) +# define RTCrX509AttributeTypeAndValue_DecodeAsn1 RT_MANGLER(RTCrX509AttributeTypeAndValue_DecodeAsn1) +# define RTCrX509AttributeTypeAndValues_DecodeAsn1 RT_MANGLER(RTCrX509AttributeTypeAndValues_DecodeAsn1) +# define RTCrX509AuthorityKeyIdentifier_DecodeAsn1 RT_MANGLER(RTCrX509AuthorityKeyIdentifier_DecodeAsn1) +# define RTCrX509BasicConstraints_DecodeAsn1 RT_MANGLER(RTCrX509BasicConstraints_DecodeAsn1) +# define RTCrX509CertificatePolicies_DecodeAsn1 RT_MANGLER(RTCrX509CertificatePolicies_DecodeAsn1) +# define RTCrX509Certificate_DecodeAsn1 RT_MANGLER(RTCrX509Certificate_DecodeAsn1) +# define RTCrX509Certificates_DecodeAsn1 RT_MANGLER(RTCrX509Certificates_DecodeAsn1) +# define RTCrX509Extension_DecodeAsn1 RT_MANGLER(RTCrX509Extension_DecodeAsn1) +# define RTCrX509Extension_ExtnValue_DecodeAsn1 RT_MANGLER(RTCrX509Extension_ExtnValue_DecodeAsn1) +# define RTCrX509Extensions_DecodeAsn1 RT_MANGLER(RTCrX509Extensions_DecodeAsn1) +# define RTCrX509GeneralName_DecodeAsn1 RT_MANGLER(RTCrX509GeneralName_DecodeAsn1) +# define RTCrX509GeneralNames_DecodeAsn1 RT_MANGLER(RTCrX509GeneralNames_DecodeAsn1) +# define RTCrX509GeneralSubtree_DecodeAsn1 RT_MANGLER(RTCrX509GeneralSubtree_DecodeAsn1) +# define RTCrX509GeneralSubtrees_DecodeAsn1 RT_MANGLER(RTCrX509GeneralSubtrees_DecodeAsn1) +# define RTCrX509NameConstraints_DecodeAsn1 RT_MANGLER(RTCrX509NameConstraints_DecodeAsn1) +# define RTCrX509Name_DecodeAsn1 RT_MANGLER(RTCrX509Name_DecodeAsn1) +# define RTCrX509OldAuthorityKeyIdentifier_DecodeAsn1 RT_MANGLER(RTCrX509OldAuthorityKeyIdentifier_DecodeAsn1) +# define RTCrX509OtherName_DecodeAsn1 RT_MANGLER(RTCrX509OtherName_DecodeAsn1) +# define RTCrX509PolicyConstraints_DecodeAsn1 RT_MANGLER(RTCrX509PolicyConstraints_DecodeAsn1) +# define RTCrX509PolicyInformation_DecodeAsn1 RT_MANGLER(RTCrX509PolicyInformation_DecodeAsn1) +# define RTCrX509PolicyMapping_DecodeAsn1 RT_MANGLER(RTCrX509PolicyMapping_DecodeAsn1) +# define RTCrX509PolicyMappings_DecodeAsn1 RT_MANGLER(RTCrX509PolicyMappings_DecodeAsn1) +# define RTCrX509PolicyQualifierInfo_DecodeAsn1 RT_MANGLER(RTCrX509PolicyQualifierInfo_DecodeAsn1) +# define RTCrX509PolicyQualifierInfos_DecodeAsn1 RT_MANGLER(RTCrX509PolicyQualifierInfos_DecodeAsn1) +# define RTCrX509SubjectPublicKeyInfo_DecodeAsn1 RT_MANGLER(RTCrX509SubjectPublicKeyInfo_DecodeAsn1) +# define RTCrX509TbsCertificate_DecodeAsn1 RT_MANGLER(RTCrX509TbsCertificate_DecodeAsn1) +# define RTCrX509Validity_DecodeAsn1 RT_MANGLER(RTCrX509Validity_DecodeAsn1) +# define RTCrX509CertPathsBuild RT_MANGLER(RTCrX509CertPathsBuild) +# define RTCrX509CertPathsCreate RT_MANGLER(RTCrX509CertPathsCreate) +# define RTCrX509CertPathsCreateEx RT_MANGLER(RTCrX509CertPathsCreateEx) +# define RTCrX509CertPathsDumpAll RT_MANGLER(RTCrX509CertPathsDumpAll) +# define RTCrX509CertPathsDumpOne RT_MANGLER(RTCrX509CertPathsDumpOne) +# define RTCrX509CertPathsGetPathCount RT_MANGLER(RTCrX509CertPathsGetPathCount) +# define RTCrX509CertPathsGetPathLength RT_MANGLER(RTCrX509CertPathsGetPathLength) +# define RTCrX509CertPathsGetPathNodeCert RT_MANGLER(RTCrX509CertPathsGetPathNodeCert) +# define RTCrX509CertPathsGetPathVerifyResult RT_MANGLER(RTCrX509CertPathsGetPathVerifyResult) +# define RTCrX509CertPathsQueryPathInfo RT_MANGLER(RTCrX509CertPathsQueryPathInfo) +# define RTCrX509CertPathsRelease RT_MANGLER(RTCrX509CertPathsRelease) +# define RTCrX509CertPathsRetain RT_MANGLER(RTCrX509CertPathsRetain) +# define RTCrX509CertPathsSetTrustedStore RT_MANGLER(RTCrX509CertPathsSetTrustedStore) +# define RTCrX509CertPathsSetTrustAnchorChecks RT_MANGLER(RTCrX509CertPathsSetTrustAnchorChecks) +# define RTCrX509CertPathsSetUntrustedArray RT_MANGLER(RTCrX509CertPathsSetUntrustedArray) +# define RTCrX509CertPathsSetUntrustedSet RT_MANGLER(RTCrX509CertPathsSetUntrustedSet) +# define RTCrX509CertPathsSetUntrustedStore RT_MANGLER(RTCrX509CertPathsSetUntrustedStore) +# define RTCrX509CertPathsSetValidTime RT_MANGLER(RTCrX509CertPathsSetValidTime) +# define RTCrX509CertPathsSetValidTimeSpec RT_MANGLER(RTCrX509CertPathsSetValidTimeSpec) +# define RTCrX509CertPathsValidateAll RT_MANGLER(RTCrX509CertPathsValidateAll) +# define RTCrX509CertPathsValidateOne RT_MANGLER(RTCrX509CertPathsValidateOne) +# define RTCrX509AlgorithmIdentifier_CombineEncryptionAndDigest RT_MANGLER(RTCrX509AlgorithmIdentifier_CombineEncryptionAndDigest) +# define RTCrX509AlgorithmIdentifier_CombineEncryptionOidAndDigestOid RT_MANGLER(RTCrX509AlgorithmIdentifier_CombineEncryptionOidAndDigestOid) +# define RTCrX509AlgorithmIdentifier_Compare RT_MANGLER(RTCrX509AlgorithmIdentifier_Compare) +# define RTCrX509AlgorithmIdentifier_CompareDigestAndEncryptedDigest RT_MANGLER(RTCrX509AlgorithmIdentifier_CompareDigestAndEncryptedDigest) +# define RTCrX509AlgorithmIdentifier_CompareDigestOidAndEncryptedDigestOid RT_MANGLER(RTCrX509AlgorithmIdentifier_CompareDigestOidAndEncryptedDigestOid) +# define RTCrX509AlgorithmIdentifier_CompareWithString RT_MANGLER(RTCrX509AlgorithmIdentifier_CompareWithString) +# define RTCrX509AlgorithmIdentifier_Delete RT_MANGLER(RTCrX509AlgorithmIdentifier_Delete) +# define RTCrX509AlgorithmIdentifier_Enum RT_MANGLER(RTCrX509AlgorithmIdentifier_Enum) +# define RTCrX509AlgorithmIdentifier_QueryDigestSize RT_MANGLER(RTCrX509AlgorithmIdentifier_QueryDigestSize) +# define RTCrX509AlgorithmIdentifier_QueryDigestType RT_MANGLER(RTCrX509AlgorithmIdentifier_QueryDigestType) +# define RTCrX509AlgorithmIdentifiers_Compare RT_MANGLER(RTCrX509AlgorithmIdentifiers_Compare) +# define RTCrX509AlgorithmIdentifiers_Delete RT_MANGLER(RTCrX509AlgorithmIdentifiers_Delete) +# define RTCrX509AlgorithmIdentifiers_Enum RT_MANGLER(RTCrX509AlgorithmIdentifiers_Enum) +# define RTCrX509AttributeTypeAndValue_Compare RT_MANGLER(RTCrX509AttributeTypeAndValue_Compare) +# define RTCrX509AttributeTypeAndValue_Delete RT_MANGLER(RTCrX509AttributeTypeAndValue_Delete) +# define RTCrX509AttributeTypeAndValue_Enum RT_MANGLER(RTCrX509AttributeTypeAndValue_Enum) +# define RTCrX509AttributeTypeAndValues_Compare RT_MANGLER(RTCrX509AttributeTypeAndValues_Compare) +# define RTCrX509AttributeTypeAndValues_Delete RT_MANGLER(RTCrX509AttributeTypeAndValues_Delete) +# define RTCrX509AttributeTypeAndValues_Enum RT_MANGLER(RTCrX509AttributeTypeAndValues_Enum) +# define RTCrX509AuthorityKeyIdentifier_Compare RT_MANGLER(RTCrX509AuthorityKeyIdentifier_Compare) +# define RTCrX509AuthorityKeyIdentifier_Delete RT_MANGLER(RTCrX509AuthorityKeyIdentifier_Delete) +# define RTCrX509AuthorityKeyIdentifier_Enum RT_MANGLER(RTCrX509AuthorityKeyIdentifier_Enum) +# define RTCrX509BasicConstraints_Compare RT_MANGLER(RTCrX509BasicConstraints_Compare) +# define RTCrX509BasicConstraints_Delete RT_MANGLER(RTCrX509BasicConstraints_Delete) +# define RTCrX509BasicConstraints_Enum RT_MANGLER(RTCrX509BasicConstraints_Enum) +# define RTCrX509CertificatePolicies_Compare RT_MANGLER(RTCrX509CertificatePolicies_Compare) +# define RTCrX509CertificatePolicies_Delete RT_MANGLER(RTCrX509CertificatePolicies_Delete) +# define RTCrX509CertificatePolicies_Enum RT_MANGLER(RTCrX509CertificatePolicies_Enum) +# define RTCrX509Certificate_Compare RT_MANGLER(RTCrX509Certificate_Compare) +# define RTCrX509Certificate_Delete RT_MANGLER(RTCrX509Certificate_Delete) +# define RTCrX509Certificate_Enum RT_MANGLER(RTCrX509Certificate_Enum) +# define RTCrX509Certificate_IsSelfSigned RT_MANGLER(RTCrX509Certificate_IsSelfSigned) +# define RTCrX509Certificate_MatchIssuerAndSerialNumber RT_MANGLER(RTCrX509Certificate_MatchIssuerAndSerialNumber) +# define RTCrX509Certificate_MatchSubjectOrAltSubjectByRfc5280 RT_MANGLER(RTCrX509Certificate_MatchSubjectOrAltSubjectByRfc5280) +# define RTCrX509Certificates_Compare RT_MANGLER(RTCrX509Certificates_Compare) +# define RTCrX509Certificates_Delete RT_MANGLER(RTCrX509Certificates_Delete) +# define RTCrX509Certificates_Enum RT_MANGLER(RTCrX509Certificates_Enum) +# define RTCrX509Certificates_FindByIssuerAndSerialNumber RT_MANGLER(RTCrX509Certificates_FindByIssuerAndSerialNumber) +# define RTCrX509Extension_Compare RT_MANGLER(RTCrX509Extension_Compare) +# define RTCrX509Extension_Delete RT_MANGLER(RTCrX509Extension_Delete) +# define RTCrX509Extension_Enum RT_MANGLER(RTCrX509Extension_Enum) +# define RTCrX509Extensions_Compare RT_MANGLER(RTCrX509Extensions_Compare) +# define RTCrX509Extensions_Delete RT_MANGLER(RTCrX509Extensions_Delete) +# define RTCrX509Extensions_Enum RT_MANGLER(RTCrX509Extensions_Enum) +# define RTCrX509GeneralName_Compare RT_MANGLER(RTCrX509GeneralName_Compare) +# define RTCrX509GeneralName_ConstraintMatch RT_MANGLER(RTCrX509GeneralName_ConstraintMatch) +# define RTCrX509GeneralName_Delete RT_MANGLER(RTCrX509GeneralName_Delete) +# define RTCrX509GeneralName_Enum RT_MANGLER(RTCrX509GeneralName_Enum) +# define RTCrX509GeneralNames_Compare RT_MANGLER(RTCrX509GeneralNames_Compare) +# define RTCrX509GeneralNames_Delete RT_MANGLER(RTCrX509GeneralNames_Delete) +# define RTCrX509GeneralNames_Enum RT_MANGLER(RTCrX509GeneralNames_Enum) +# define RTCrX509GeneralSubtree_Compare RT_MANGLER(RTCrX509GeneralSubtree_Compare) +# define RTCrX509GeneralSubtree_ConstraintMatch RT_MANGLER(RTCrX509GeneralSubtree_ConstraintMatch) +# define RTCrX509GeneralSubtree_Delete RT_MANGLER(RTCrX509GeneralSubtree_Delete) +# define RTCrX509GeneralSubtree_Enum RT_MANGLER(RTCrX509GeneralSubtree_Enum) +# define RTCrX509GeneralSubtrees_Compare RT_MANGLER(RTCrX509GeneralSubtrees_Compare) +# define RTCrX509GeneralSubtrees_Delete RT_MANGLER(RTCrX509GeneralSubtrees_Delete) +# define RTCrX509GeneralSubtrees_Enum RT_MANGLER(RTCrX509GeneralSubtrees_Enum) +# define RTCrX509NameConstraints_Compare RT_MANGLER(RTCrX509NameConstraints_Compare) +# define RTCrX509NameConstraints_Delete RT_MANGLER(RTCrX509NameConstraints_Delete) +# define RTCrX509NameConstraints_Enum RT_MANGLER(RTCrX509NameConstraints_Enum) +# define RTCrX509Name_Compare RT_MANGLER(RTCrX509Name_Compare) +# define RTCrX509Name_ConstraintMatch RT_MANGLER(RTCrX509Name_ConstraintMatch) +# define RTCrX509Name_Delete RT_MANGLER(RTCrX509Name_Delete) +# define RTCrX509Name_Enum RT_MANGLER(RTCrX509Name_Enum) +# define RTCrX509Name_FormatAsString RT_MANGLER(RTCrX509Name_FormatAsString) +# define RTCrX509Name_MatchByRfc5280 RT_MANGLER(RTCrX509Name_MatchByRfc5280) +# define RTCrX509Name_MatchWithString RT_MANGLER(RTCrX509Name_MatchWithString) +# define RTCrX509Name_GetShortRdn RT_MANGLER(RTCrX509Name_GetShortRdn) +# define RTCrX509OldAuthorityKeyIdentifier_Compare RT_MANGLER(RTCrX509OldAuthorityKeyIdentifier_Compare) +# define RTCrX509OldAuthorityKeyIdentifier_Delete RT_MANGLER(RTCrX509OldAuthorityKeyIdentifier_Delete) +# define RTCrX509OldAuthorityKeyIdentifier_Enum RT_MANGLER(RTCrX509OldAuthorityKeyIdentifier_Enum) +# define RTCrX509OtherName_Compare RT_MANGLER(RTCrX509OtherName_Compare) +# define RTCrX509OtherName_Delete RT_MANGLER(RTCrX509OtherName_Delete) +# define RTCrX509OtherName_Enum RT_MANGLER(RTCrX509OtherName_Enum) +# define RTCrX509PolicyConstraints_Compare RT_MANGLER(RTCrX509PolicyConstraints_Compare) +# define RTCrX509PolicyConstraints_Delete RT_MANGLER(RTCrX509PolicyConstraints_Delete) +# define RTCrX509PolicyConstraints_Enum RT_MANGLER(RTCrX509PolicyConstraints_Enum) +# define RTCrX509PolicyInformation_Compare RT_MANGLER(RTCrX509PolicyInformation_Compare) +# define RTCrX509PolicyInformation_Delete RT_MANGLER(RTCrX509PolicyInformation_Delete) +# define RTCrX509PolicyInformation_Enum RT_MANGLER(RTCrX509PolicyInformation_Enum) +# define RTCrX509PolicyMapping_Compare RT_MANGLER(RTCrX509PolicyMapping_Compare) +# define RTCrX509PolicyMapping_Delete RT_MANGLER(RTCrX509PolicyMapping_Delete) +# define RTCrX509PolicyMapping_Enum RT_MANGLER(RTCrX509PolicyMapping_Enum) +# define RTCrX509PolicyMappings_Compare RT_MANGLER(RTCrX509PolicyMappings_Compare) +# define RTCrX509PolicyMappings_Delete RT_MANGLER(RTCrX509PolicyMappings_Delete) +# define RTCrX509PolicyMappings_Enum RT_MANGLER(RTCrX509PolicyMappings_Enum) +# define RTCrX509PolicyQualifierInfo_Compare RT_MANGLER(RTCrX509PolicyQualifierInfo_Compare) +# define RTCrX509PolicyQualifierInfo_Delete RT_MANGLER(RTCrX509PolicyQualifierInfo_Delete) +# define RTCrX509PolicyQualifierInfo_Enum RT_MANGLER(RTCrX509PolicyQualifierInfo_Enum) +# define RTCrX509PolicyQualifierInfos_Compare RT_MANGLER(RTCrX509PolicyQualifierInfos_Compare) +# define RTCrX509PolicyQualifierInfos_Delete RT_MANGLER(RTCrX509PolicyQualifierInfos_Delete) +# define RTCrX509PolicyQualifierInfos_Enum RT_MANGLER(RTCrX509PolicyQualifierInfos_Enum) +# define RTCrX509SubjectPublicKeyInfo_Compare RT_MANGLER(RTCrX509SubjectPublicKeyInfo_Compare) +# define RTCrX509SubjectPublicKeyInfo_Delete RT_MANGLER(RTCrX509SubjectPublicKeyInfo_Delete) +# define RTCrX509SubjectPublicKeyInfo_Enum RT_MANGLER(RTCrX509SubjectPublicKeyInfo_Enum) +# define RTCrX509TbsCertificate_Compare RT_MANGLER(RTCrX509TbsCertificate_Compare) +# define RTCrX509TbsCertificate_Delete RT_MANGLER(RTCrX509TbsCertificate_Delete) +# define RTCrX509TbsCertificate_Enum RT_MANGLER(RTCrX509TbsCertificate_Enum) +# define RTCrX509TbsCertificate_ReprocessExtensions RT_MANGLER(RTCrX509TbsCertificate_ReprocessExtensions) +# define RTCrX509Validity_Compare RT_MANGLER(RTCrX509Validity_Compare) +# define RTCrX509Validity_Delete RT_MANGLER(RTCrX509Validity_Delete) +# define RTCrX509Validity_Enum RT_MANGLER(RTCrX509Validity_Enum) +# define RTCrX509Validity_IsValidAtTimeSpec RT_MANGLER(RTCrX509Validity_IsValidAtTimeSpec) +# define RTCrX509Certificate_ReadFromFile RT_MANGLER(RTCrX509Certificate_ReadFromFile) +# define RTCrX509Certificate_ReadFromBuffer RT_MANGLER(RTCrX509Certificate_ReadFromBuffer) +# define RTCrX509AlgorithmIdentifier_Clone RT_MANGLER(RTCrX509AlgorithmIdentifier_Clone) +# define RTCrX509AlgorithmIdentifier_Init RT_MANGLER(RTCrX509AlgorithmIdentifier_Init) +# define RTCrX509AlgorithmIdentifiers_Clone RT_MANGLER(RTCrX509AlgorithmIdentifiers_Clone) +# define RTCrX509AlgorithmIdentifiers_Init RT_MANGLER(RTCrX509AlgorithmIdentifiers_Init) +# define RTCrX509AttributeTypeAndValue_Clone RT_MANGLER(RTCrX509AttributeTypeAndValue_Clone) +# define RTCrX509AttributeTypeAndValue_Init RT_MANGLER(RTCrX509AttributeTypeAndValue_Init) +# define RTCrX509AttributeTypeAndValues_Clone RT_MANGLER(RTCrX509AttributeTypeAndValues_Clone) +# define RTCrX509AttributeTypeAndValues_Init RT_MANGLER(RTCrX509AttributeTypeAndValues_Init) +# define RTCrX509AuthorityKeyIdentifier_Clone RT_MANGLER(RTCrX509AuthorityKeyIdentifier_Clone) +# define RTCrX509AuthorityKeyIdentifier_Init RT_MANGLER(RTCrX509AuthorityKeyIdentifier_Init) +# define RTCrX509BasicConstraints_Clone RT_MANGLER(RTCrX509BasicConstraints_Clone) +# define RTCrX509BasicConstraints_Init RT_MANGLER(RTCrX509BasicConstraints_Init) +# define RTCrX509CertificatePolicies_Clone RT_MANGLER(RTCrX509CertificatePolicies_Clone) +# define RTCrX509CertificatePolicies_Init RT_MANGLER(RTCrX509CertificatePolicies_Init) +# define RTCrX509Certificate_Clone RT_MANGLER(RTCrX509Certificate_Clone) +# define RTCrX509Certificate_Init RT_MANGLER(RTCrX509Certificate_Init) +# define RTCrX509Certificates_Clone RT_MANGLER(RTCrX509Certificates_Clone) +# define RTCrX509Certificates_Init RT_MANGLER(RTCrX509Certificates_Init) +# define RTCrX509Extension_Clone RT_MANGLER(RTCrX509Extension_Clone) +# define RTCrX509Extension_Init RT_MANGLER(RTCrX509Extension_Init) +# define RTCrX509Extensions_Clone RT_MANGLER(RTCrX509Extensions_Clone) +# define RTCrX509Extensions_Init RT_MANGLER(RTCrX509Extensions_Init) +# define RTCrX509GeneralName_Clone RT_MANGLER(RTCrX509GeneralName_Clone) +# define RTCrX509GeneralName_Init RT_MANGLER(RTCrX509GeneralName_Init) +# define RTCrX509GeneralNames_Clone RT_MANGLER(RTCrX509GeneralNames_Clone) +# define RTCrX509GeneralNames_Init RT_MANGLER(RTCrX509GeneralNames_Init) +# define RTCrX509GeneralSubtree_Clone RT_MANGLER(RTCrX509GeneralSubtree_Clone) +# define RTCrX509GeneralSubtree_Init RT_MANGLER(RTCrX509GeneralSubtree_Init) +# define RTCrX509GeneralSubtrees_Clone RT_MANGLER(RTCrX509GeneralSubtrees_Clone) +# define RTCrX509GeneralSubtrees_Init RT_MANGLER(RTCrX509GeneralSubtrees_Init) +# define RTCrX509NameConstraints_Clone RT_MANGLER(RTCrX509NameConstraints_Clone) +# define RTCrX509NameConstraints_Init RT_MANGLER(RTCrX509NameConstraints_Init) +# define RTCrX509Name_Clone RT_MANGLER(RTCrX509Name_Clone) +# define RTCrX509Name_Init RT_MANGLER(RTCrX509Name_Init) +# define RTCrX509Name_RecodeAsUtf8 RT_MANGLER(RTCrX509Name_RecodeAsUtf8) +# define RTCrX509OldAuthorityKeyIdentifier_Clone RT_MANGLER(RTCrX509OldAuthorityKeyIdentifier_Clone) +# define RTCrX509OldAuthorityKeyIdentifier_Init RT_MANGLER(RTCrX509OldAuthorityKeyIdentifier_Init) +# define RTCrX509OtherName_Clone RT_MANGLER(RTCrX509OtherName_Clone) +# define RTCrX509OtherName_Init RT_MANGLER(RTCrX509OtherName_Init) +# define RTCrX509PolicyConstraints_Clone RT_MANGLER(RTCrX509PolicyConstraints_Clone) +# define RTCrX509PolicyConstraints_Init RT_MANGLER(RTCrX509PolicyConstraints_Init) +# define RTCrX509PolicyInformation_Clone RT_MANGLER(RTCrX509PolicyInformation_Clone) +# define RTCrX509PolicyInformation_Init RT_MANGLER(RTCrX509PolicyInformation_Init) +# define RTCrX509PolicyMapping_Clone RT_MANGLER(RTCrX509PolicyMapping_Clone) +# define RTCrX509PolicyMapping_Init RT_MANGLER(RTCrX509PolicyMapping_Init) +# define RTCrX509PolicyMappings_Clone RT_MANGLER(RTCrX509PolicyMappings_Clone) +# define RTCrX509PolicyMappings_Init RT_MANGLER(RTCrX509PolicyMappings_Init) +# define RTCrX509PolicyQualifierInfo_Clone RT_MANGLER(RTCrX509PolicyQualifierInfo_Clone) +# define RTCrX509PolicyQualifierInfo_Init RT_MANGLER(RTCrX509PolicyQualifierInfo_Init) +# define RTCrX509PolicyQualifierInfos_Clone RT_MANGLER(RTCrX509PolicyQualifierInfos_Clone) +# define RTCrX509PolicyQualifierInfos_Init RT_MANGLER(RTCrX509PolicyQualifierInfos_Init) +# define RTCrRsaPrivateKey_ReadFromFile RT_MANGLER(RTCrRsaPrivateKey_ReadFromFile) +# define RTCrRsaPrivateKey_ReadFromBuffer RT_MANGLER(RTCrRsaPrivateKey_ReadFromBuffer) +# define RTCrRsaPublicKey_ReadFromFile RT_MANGLER(RTCrRsaPublicKey_ReadFromFile) +# define RTCrRsaPublicKey_ReadFromBuffer RT_MANGLER(RTCrRsaPublicKey_ReadFromBuffer) +# define RTCrX509SubjectPublicKeyInfo_Clone RT_MANGLER(RTCrX509SubjectPublicKeyInfo_Clone) +# define RTCrX509SubjectPublicKeyInfo_Init RT_MANGLER(RTCrX509SubjectPublicKeyInfo_Init) +# define RTCrX509TbsCertificate_Clone RT_MANGLER(RTCrX509TbsCertificate_Clone) +# define RTCrX509TbsCertificate_Init RT_MANGLER(RTCrX509TbsCertificate_Init) +# define RTCrX509Validity_Clone RT_MANGLER(RTCrX509Validity_Clone) +# define RTCrX509Validity_Init RT_MANGLER(RTCrX509Validity_Init) +# define RTCrX509AlgorithmIdentifier_CheckSanity RT_MANGLER(RTCrX509AlgorithmIdentifier_CheckSanity) +# define RTCrX509AlgorithmIdentifiers_CheckSanity RT_MANGLER(RTCrX509AlgorithmIdentifiers_CheckSanity) +# define RTCrX509AttributeTypeAndValue_CheckSanity RT_MANGLER(RTCrX509AttributeTypeAndValue_CheckSanity) +# define RTCrX509AttributeTypeAndValues_CheckSanity RT_MANGLER(RTCrX509AttributeTypeAndValues_CheckSanity) +# define RTCrX509AuthorityKeyIdentifier_CheckSanity RT_MANGLER(RTCrX509AuthorityKeyIdentifier_CheckSanity) +# define RTCrX509BasicConstraints_CheckSanity RT_MANGLER(RTCrX509BasicConstraints_CheckSanity) +# define RTCrX509CertificatePolicies_CheckSanity RT_MANGLER(RTCrX509CertificatePolicies_CheckSanity) +# define RTCrX509Certificate_CheckSanity RT_MANGLER(RTCrX509Certificate_CheckSanity) +# define RTCrX509Certificates_CheckSanity RT_MANGLER(RTCrX509Certificates_CheckSanity) +# define RTCrX509Extension_CheckSanity RT_MANGLER(RTCrX509Extension_CheckSanity) +# define RTCrX509Extensions_CheckSanity RT_MANGLER(RTCrX509Extensions_CheckSanity) +# define RTCrX509GeneralName_CheckSanity RT_MANGLER(RTCrX509GeneralName_CheckSanity) +# define RTCrX509GeneralNames_CheckSanity RT_MANGLER(RTCrX509GeneralNames_CheckSanity) +# define RTCrX509GeneralSubtree_CheckSanity RT_MANGLER(RTCrX509GeneralSubtree_CheckSanity) +# define RTCrX509GeneralSubtrees_CheckSanity RT_MANGLER(RTCrX509GeneralSubtrees_CheckSanity) +# define RTCrX509NameConstraints_CheckSanity RT_MANGLER(RTCrX509NameConstraints_CheckSanity) +# define RTCrX509Name_CheckSanity RT_MANGLER(RTCrX509Name_CheckSanity) +# define RTCrX509OldAuthorityKeyIdentifier_CheckSanity RT_MANGLER(RTCrX509OldAuthorityKeyIdentifier_CheckSanity) +# define RTCrX509OtherName_CheckSanity RT_MANGLER(RTCrX509OtherName_CheckSanity) +# define RTCrX509PolicyConstraints_CheckSanity RT_MANGLER(RTCrX509PolicyConstraints_CheckSanity) +# define RTCrX509PolicyInformation_CheckSanity RT_MANGLER(RTCrX509PolicyInformation_CheckSanity) +# define RTCrX509PolicyMapping_CheckSanity RT_MANGLER(RTCrX509PolicyMapping_CheckSanity) +# define RTCrX509PolicyMappings_CheckSanity RT_MANGLER(RTCrX509PolicyMappings_CheckSanity) +# define RTCrX509PolicyQualifierInfo_CheckSanity RT_MANGLER(RTCrX509PolicyQualifierInfo_CheckSanity) +# define RTCrX509PolicyQualifierInfos_CheckSanity RT_MANGLER(RTCrX509PolicyQualifierInfos_CheckSanity) +# define RTCrX509SubjectPublicKeyInfo_CheckSanity RT_MANGLER(RTCrX509SubjectPublicKeyInfo_CheckSanity) +# define RTCrX509TbsCertificate_CheckSanity RT_MANGLER(RTCrX509TbsCertificate_CheckSanity) +# define RTCrX509Validity_CheckSanity RT_MANGLER(RTCrX509Validity_CheckSanity) +# define RTCrX509Certificate_VerifySignature RT_MANGLER(RTCrX509Certificate_VerifySignature) +# define RTCrX509Certificate_VerifySignatureSelfSigned RT_MANGLER(RTCrX509Certificate_VerifySignatureSelfSigned) +# define RTCrTafCertPathControls_DecodeAsn1 RT_MANGLER(RTCrTafCertPathControls_DecodeAsn1) +# define RTCrTafTrustAnchorChoice_DecodeAsn1 RT_MANGLER(RTCrTafTrustAnchorChoice_DecodeAsn1) +# define RTCrTafTrustAnchorInfo_DecodeAsn1 RT_MANGLER(RTCrTafTrustAnchorInfo_DecodeAsn1) +# define RTCrTafTrustAnchorList_DecodeAsn1 RT_MANGLER(RTCrTafTrustAnchorList_DecodeAsn1) +# define RTCrTafCertPathControls_Compare RT_MANGLER(RTCrTafCertPathControls_Compare) +# define RTCrTafCertPathControls_Delete RT_MANGLER(RTCrTafCertPathControls_Delete) +# define RTCrTafCertPathControls_Enum RT_MANGLER(RTCrTafCertPathControls_Enum) +# define RTCrTafTrustAnchorChoice_Compare RT_MANGLER(RTCrTafTrustAnchorChoice_Compare) +# define RTCrTafTrustAnchorChoice_Delete RT_MANGLER(RTCrTafTrustAnchorChoice_Delete) +# define RTCrTafTrustAnchorChoice_Enum RT_MANGLER(RTCrTafTrustAnchorChoice_Enum) +# define RTCrTafTrustAnchorInfo_Compare RT_MANGLER(RTCrTafTrustAnchorInfo_Compare) +# define RTCrTafTrustAnchorInfo_Delete RT_MANGLER(RTCrTafTrustAnchorInfo_Delete) +# define RTCrTafTrustAnchorInfo_Enum RT_MANGLER(RTCrTafTrustAnchorInfo_Enum) +# define RTCrTafTrustAnchorList_Compare RT_MANGLER(RTCrTafTrustAnchorList_Compare) +# define RTCrTafTrustAnchorList_Delete RT_MANGLER(RTCrTafTrustAnchorList_Delete) +# define RTCrTafTrustAnchorList_Enum RT_MANGLER(RTCrTafTrustAnchorList_Enum) +# define RTCrTafCertPathControls_Clone RT_MANGLER(RTCrTafCertPathControls_Clone) +# define RTCrTafCertPathControls_Init RT_MANGLER(RTCrTafCertPathControls_Init) +# define RTCrTafTrustAnchorChoice_Clone RT_MANGLER(RTCrTafTrustAnchorChoice_Clone) +# define RTCrTafTrustAnchorChoice_Init RT_MANGLER(RTCrTafTrustAnchorChoice_Init) +# define RTCrTafTrustAnchorInfo_Clone RT_MANGLER(RTCrTafTrustAnchorInfo_Clone) +# define RTCrTafTrustAnchorInfo_Init RT_MANGLER(RTCrTafTrustAnchorInfo_Init) +# define RTCrTafTrustAnchorList_Clone RT_MANGLER(RTCrTafTrustAnchorList_Clone) +# define RTCrTafTrustAnchorList_Init RT_MANGLER(RTCrTafTrustAnchorList_Init) +# define RTCrTafCertPathControls_CheckSanity RT_MANGLER(RTCrTafCertPathControls_CheckSanity) +# define RTCrTafTrustAnchorChoice_CheckSanity RT_MANGLER(RTCrTafTrustAnchorChoice_CheckSanity) +# define RTCrTafTrustAnchorInfo_CheckSanity RT_MANGLER(RTCrTafTrustAnchorInfo_CheckSanity) +# define RTCrTafTrustAnchorList_CheckSanity RT_MANGLER(RTCrTafTrustAnchorList_CheckSanity) +# define RTCrTspAccuracy_CheckSanity RT_MANGLER(RTCrTspAccuracy_CheckSanity) +# define RTCrTspAccuracy_Clone RT_MANGLER(RTCrTspAccuracy_Clone) +# define RTCrTspAccuracy_Compare RT_MANGLER(RTCrTspAccuracy_Compare) +# define RTCrTspAccuracy_DecodeAsn1 RT_MANGLER(RTCrTspAccuracy_DecodeAsn1) +# define RTCrTspAccuracy_Delete RT_MANGLER(RTCrTspAccuracy_Delete) +# define RTCrTspAccuracy_Enum RT_MANGLER(RTCrTspAccuracy_Enum) +# define RTCrTspAccuracy_Init RT_MANGLER(RTCrTspAccuracy_Init) +# define RTCrTspMessageImprint_CheckSanity RT_MANGLER(RTCrTspMessageImprint_CheckSanity) +# define RTCrTspMessageImprint_Clone RT_MANGLER(RTCrTspMessageImprint_Clone) +# define RTCrTspMessageImprint_Compare RT_MANGLER(RTCrTspMessageImprint_Compare) +# define RTCrTspMessageImprint_DecodeAsn1 RT_MANGLER(RTCrTspMessageImprint_DecodeAsn1) +# define RTCrTspMessageImprint_Delete RT_MANGLER(RTCrTspMessageImprint_Delete) +# define RTCrTspMessageImprint_Enum RT_MANGLER(RTCrTspMessageImprint_Enum) +# define RTCrTspMessageImprint_Init RT_MANGLER(RTCrTspMessageImprint_Init) +# define RTCrTspTstInfo_CheckSanity RT_MANGLER(RTCrTspTstInfo_CheckSanity) +# define RTCrTspTstInfo_Clone RT_MANGLER(RTCrTspTstInfo_Clone) +# define RTCrTspTstInfo_Compare RT_MANGLER(RTCrTspTstInfo_Compare) +# define RTCrTspTstInfo_DecodeAsn1 RT_MANGLER(RTCrTspTstInfo_DecodeAsn1) +# define RTCrTspTstInfo_Delete RT_MANGLER(RTCrTspTstInfo_Delete) +# define RTCrTspTstInfo_Enum RT_MANGLER(RTCrTspTstInfo_Enum) +# define RTCrTspTstInfo_Init RT_MANGLER(RTCrTspTstInfo_Init) +# define RTCrCertCtxRelease RT_MANGLER(RTCrCertCtxRelease) +# define RTCrCertCtxRetain RT_MANGLER(RTCrCertCtxRetain) +# define RTCrStoreCertAddEncoded RT_MANGLER(RTCrStoreCertAddEncoded) +# define RTCrStoreCertAddX509 RT_MANGLER(RTCrStoreCertAddX509) +# define RTCrStoreCertByIssuerAndSerialNo RT_MANGLER(RTCrStoreCertByIssuerAndSerialNo) +# define RTCrStoreCertCount RT_MANGLER(RTCrStoreCertCount) +# define RTCrStoreCertFindAll RT_MANGLER(RTCrStoreCertFindAll) +# define RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280 RT_MANGLER(RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280) +# define RTCrStoreCertSearchDestroy RT_MANGLER(RTCrStoreCertSearchDestroy) +# define RTCrStoreCertSearchNext RT_MANGLER(RTCrStoreCertSearchNext) +# define RTCrStoreConvertToOpenSslCertStack RT_MANGLER(RTCrStoreConvertToOpenSslCertStack) +# define RTCrStoreConvertToOpenSslCertStore RT_MANGLER(RTCrStoreConvertToOpenSslCertStore) +# define RTCrStoreRelease RT_MANGLER(RTCrStoreRelease) +# define RTCrStoreRetain RT_MANGLER(RTCrStoreRetain) +# define RTCrStoreCreateInMem RT_MANGLER(RTCrStoreCreateInMem) +# define RTCrStoreCreateInMemEx RT_MANGLER(RTCrStoreCreateInMemEx) +# define RTCrStoreCreateSnapshotById RT_MANGLER(RTCrStoreCreateSnapshotById) +# define RTCrStoreCreateSnapshotOfUserAndSystemTrustedCAsAndCerts RT_MANGLER(RTCrStoreCreateSnapshotOfUserAndSystemTrustedCAsAndCerts) +# define RTCrStoreCertAddFromDir RT_MANGLER(RTCrStoreCertAddFromDir) +# define RTCrStoreCertAddFromFile RT_MANGLER(RTCrStoreCertAddFromFile) +# define RTCrStoreCertAddFromJavaKeyStore RT_MANGLER(RTCrStoreCertAddFromJavaKeyStore) +# define RTCrStoreCertAddFromJavaKeyStoreInMem RT_MANGLER(RTCrStoreCertAddFromJavaKeyStoreInMem) +# define RTCrStoreCertAddFromStore RT_MANGLER(RTCrStoreCertAddFromStore) +# define RTCrStoreCertAddWantedFromDir RT_MANGLER(RTCrStoreCertAddWantedFromDir) +# define RTCrStoreCertAddWantedFromFile RT_MANGLER(RTCrStoreCertAddWantedFromFile) +# define RTCrStoreCertAddWantedFromStore RT_MANGLER(RTCrStoreCertAddWantedFromStore) +# define RTCrStoreCertAddWantedFromFishingExpedition RT_MANGLER(RTCrStoreCertAddWantedFromFishingExpedition) +# define RTCrStoreCertCheckWanted RT_MANGLER(RTCrStoreCertCheckWanted) +# define RTCrStoreCertExportAsPem RT_MANGLER(RTCrStoreCertExportAsPem) +# define RTErrInfoAdd RT_MANGLER(RTErrInfoAdd) +# define RTErrInfoAddF RT_MANGLER(RTErrInfoAddF) +# define RTErrInfoAddV RT_MANGLER(RTErrInfoAddV) +# define RTExprEvalCreate RT_MANGLER(RTExprEvalCreate) +# define RTExprEvalRelease RT_MANGLER(RTExprEvalRelease) +# define RTExprEvalRetain RT_MANGLER(RTExprEvalRetain) +# define RTExprEvalToBool RT_MANGLER(RTExprEvalToBool) +# define RTExprEvalToInteger RT_MANGLER(RTExprEvalToInteger) +# define RTExprEvalToString RT_MANGLER(RTExprEvalToString) +# define RTLdrHashImage RT_MANGLER(RTLdrHashImage) +# define RTLdrOpenWithReader RT_MANGLER(RTLdrOpenWithReader) +# define RTLdrQueryPropEx RT_MANGLER(RTLdrQueryPropEx) +# define RTLdrVerifySignature RT_MANGLER(RTLdrVerifySignature) +# define RTBigNumAdd RT_MANGLER(RTBigNumAdd) +# define RTBigNumAssign RT_MANGLER(RTBigNumAssign) +# define RTBigNumBitWidth RT_MANGLER(RTBigNumBitWidth) +# define RTBigNumByteWidth RT_MANGLER(RTBigNumByteWidth) +# define RTBigNumClone RT_MANGLER(RTBigNumClone) +# define RTBigNumCompare RT_MANGLER(RTBigNumCompare) +# define RTBigNumCompareWithS64 RT_MANGLER(RTBigNumCompareWithS64) +# define RTBigNumCompareWithU64 RT_MANGLER(RTBigNumCompareWithU64) +# define RTBigNumDestroy RT_MANGLER(RTBigNumDestroy) +# define RTBigNumDivide RT_MANGLER(RTBigNumDivide) +# define RTBigNumDivideKnuth RT_MANGLER(RTBigNumDivideKnuth) +# define RTBigNumDivideLong RT_MANGLER(RTBigNumDivideLong) +# define RTBigNumExponentiate RT_MANGLER(RTBigNumExponentiate) +# define RTBigNumInit RT_MANGLER(RTBigNumInit) +# define RTBigNumInitZero RT_MANGLER(RTBigNumInitZero) +# define RTBigNumModExp RT_MANGLER(RTBigNumModExp) +# define RTBigNumModulo RT_MANGLER(RTBigNumModulo) +# define RTBigNumMultiply RT_MANGLER(RTBigNumMultiply) +# define RTBigNumNegate RT_MANGLER(RTBigNumNegate) +# define RTBigNumNegateThis RT_MANGLER(RTBigNumNegateThis) +# define RTBigNumShiftLeft RT_MANGLER(RTBigNumShiftLeft) +# define RTBigNumShiftRight RT_MANGLER(RTBigNumShiftRight) +# define RTBigNumSubtract RT_MANGLER(RTBigNumSubtract) +# define RTBigNumToBytesBigEndian RT_MANGLER(RTBigNumToBytesBigEndian) +# define RTUInt128MulByU64 RT_MANGLER(RTUInt128MulByU64) +# define RTUInt128MulByU64_EndProc RT_MANGLER(RTUInt128MulByU64_EndProc) +# define RTUInt128MulByU64Ex RT_MANGLER(RTUInt128MulByU64Ex) +# define RTUInt128MulByU64Ex_EndProc RT_MANGLER(RTUInt128MulByU64Ex_EndProc) +# define RTUtf16Copy RT_MANGLER(RTUtf16Copy) +# define RTUtf16CopyAscii RT_MANGLER(RTUtf16CopyAscii) +# define RTUtf16CopyEx RT_MANGLER(RTUtf16CopyEx) +# define RTUtf16Cat RT_MANGLER(RTUtf16Cat) +# define RTUtf16CatAscii RT_MANGLER(RTUtf16CatAscii) +# define RTUtf16Chr RT_MANGLER(RTUtf16Chr) +# define RTUtf16End RT_MANGLER(RTUtf16End) +# define RTUtf16ICmpAscii RT_MANGLER(RTUtf16ICmpAscii) +# define RTUtf16NICmpAscii RT_MANGLER(RTUtf16NICmpAscii) +# define RTUtf16NLen RT_MANGLER(RTUtf16NLen) +# define RTUtf16NLenEx RT_MANGLER(RTUtf16NLenEx) +# define RTUtf16PrintHexBytes RT_MANGLER(RTUtf16PrintHexBytes) +# define RTMemSaferAllocZExTag RT_MANGLER(RTMemSaferAllocZExTag) +# define RTMemSaferAllocZTag RT_MANGLER(RTMemSaferAllocZTag) +# define RTMemSaferFree RT_MANGLER(RTMemSaferFree) +# define RTMemSaferGetSize RT_MANGLER(RTMemSaferGetSize) +# define RTMemSaferReallocZExTag RT_MANGLER(RTMemSaferReallocZExTag) +# define RTMemSaferReallocZTag RT_MANGLER(RTMemSaferReallocZTag) +# define RTMemSaferScramble RT_MANGLER(RTMemSaferScramble) +# define RTMemSaferUnscramble RT_MANGLER(RTMemSaferUnscramble) +# define RTErrConvertFromDarwin RT_MANGLER(RTErrConvertFromDarwin) +# define RTErrConvertFromDarwinCOM RT_MANGLER(RTErrConvertFromDarwinCOM) +# define RTErrConvertFromDarwinIO RT_MANGLER(RTErrConvertFromDarwinIO) +# define RTErrConvertFromDarwinKern RT_MANGLER(RTErrConvertFromDarwinKern) +# define RTErrConvertFromDarwin RT_MANGLER(RTErrConvertFromDarwin) +# define RTErrConvertFromDarwinIO RT_MANGLER(RTErrConvertFromDarwinIO) +# define RTErrConvertFromDarwinKern RT_MANGLER(RTErrConvertFromDarwinKern) + +# define RTAsn1SeqOfBitStrings_Erase RT_MANGLER(RTAsn1SeqOfBitStrings_Erase) +# define RTAsn1SeqOfBitStrings_InsertEx RT_MANGLER(RTAsn1SeqOfBitStrings_InsertEx) +# define RTAsn1SeqOfBooleans_Erase RT_MANGLER(RTAsn1SeqOfBooleans_Erase) +# define RTAsn1SeqOfBooleans_InsertEx RT_MANGLER(RTAsn1SeqOfBooleans_InsertEx) +# define RTAsn1SeqOfCores_Erase RT_MANGLER(RTAsn1SeqOfCores_Erase) +# define RTAsn1SeqOfCores_InsertEx RT_MANGLER(RTAsn1SeqOfCores_InsertEx) +# define RTAsn1SeqOfIntegers_Erase RT_MANGLER(RTAsn1SeqOfIntegers_Erase) +# define RTAsn1SeqOfIntegers_InsertEx RT_MANGLER(RTAsn1SeqOfIntegers_InsertEx) +# define RTAsn1SeqOfObjIds_Erase RT_MANGLER(RTAsn1SeqOfObjIds_Erase) +# define RTAsn1SeqOfObjIds_InsertEx RT_MANGLER(RTAsn1SeqOfObjIds_InsertEx) +# define RTAsn1SeqOfOctetStrings_Erase RT_MANGLER(RTAsn1SeqOfOctetStrings_Erase) +# define RTAsn1SeqOfOctetStrings_InsertEx RT_MANGLER(RTAsn1SeqOfOctetStrings_InsertEx) +# define RTAsn1SeqOfStrings_Erase RT_MANGLER(RTAsn1SeqOfStrings_Erase) +# define RTAsn1SeqOfStrings_InsertEx RT_MANGLER(RTAsn1SeqOfStrings_InsertEx) +# define RTAsn1SeqOfTimes_Erase RT_MANGLER(RTAsn1SeqOfTimes_Erase) +# define RTAsn1SeqOfTimes_InsertEx RT_MANGLER(RTAsn1SeqOfTimes_InsertEx) +# define RTAsn1SetOfBitStrings_Erase RT_MANGLER(RTAsn1SetOfBitStrings_Erase) +# define RTAsn1SetOfBitStrings_InsertEx RT_MANGLER(RTAsn1SetOfBitStrings_InsertEx) +# define RTAsn1SetOfBooleans_Erase RT_MANGLER(RTAsn1SetOfBooleans_Erase) +# define RTAsn1SetOfBooleans_InsertEx RT_MANGLER(RTAsn1SetOfBooleans_InsertEx) +# define RTAsn1SetOfCores_Erase RT_MANGLER(RTAsn1SetOfCores_Erase) +# define RTAsn1SetOfCores_InsertEx RT_MANGLER(RTAsn1SetOfCores_InsertEx) +# define RTAsn1SetOfIntegers_Erase RT_MANGLER(RTAsn1SetOfIntegers_Erase) +# define RTAsn1SetOfIntegers_InsertEx RT_MANGLER(RTAsn1SetOfIntegers_InsertEx) +# define RTAsn1SetOfObjIds_Erase RT_MANGLER(RTAsn1SetOfObjIds_Erase) +# define RTAsn1SetOfObjIds_InsertEx RT_MANGLER(RTAsn1SetOfObjIds_InsertEx) +# define RTAsn1SetOfObjIdSeqs_Erase RT_MANGLER(RTAsn1SetOfObjIdSeqs_Erase) +# define RTAsn1SetOfObjIdSeqs_InsertEx RT_MANGLER(RTAsn1SetOfObjIdSeqs_InsertEx) +# define RTAsn1SetOfOctetStrings_Erase RT_MANGLER(RTAsn1SetOfOctetStrings_Erase) +# define RTAsn1SetOfOctetStrings_InsertEx RT_MANGLER(RTAsn1SetOfOctetStrings_InsertEx) +# define RTAsn1SetOfStrings_Erase RT_MANGLER(RTAsn1SetOfStrings_Erase) +# define RTAsn1SetOfStrings_InsertEx RT_MANGLER(RTAsn1SetOfStrings_InsertEx) +# define RTAsn1SetOfTimes_Erase RT_MANGLER(RTAsn1SetOfTimes_Erase) +# define RTAsn1SetOfTimes_InsertEx RT_MANGLER(RTAsn1SetOfTimes_InsertEx) +# define RTCrPkcs7Attributes_Erase RT_MANGLER(RTCrPkcs7Attributes_Erase) +# define RTCrPkcs7Attributes_InsertEx RT_MANGLER(RTCrPkcs7Attributes_InsertEx) +# define RTCrPkcs7SetOfCerts_Erase RT_MANGLER(RTCrPkcs7SetOfCerts_Erase) +# define RTCrPkcs7SetOfCerts_InsertEx RT_MANGLER(RTCrPkcs7SetOfCerts_InsertEx) +# define RTCrPkcs7SetOfContentInfos_Erase RT_MANGLER(RTCrPkcs7SetOfContentInfos_Erase) +# define RTCrPkcs7SetOfContentInfos_InsertEx RT_MANGLER(RTCrPkcs7SetOfContentInfos_InsertEx) +# define RTCrPkcs7SetOfSignedData_Erase RT_MANGLER(RTCrPkcs7SetOfSignedData_Erase) +# define RTCrPkcs7SetOfSignedData_InsertEx RT_MANGLER(RTCrPkcs7SetOfSignedData_InsertEx) +# define RTCrPkcs7SignerInfos_Erase RT_MANGLER(RTCrPkcs7SignerInfos_Erase) +# define RTCrPkcs7SignerInfos_InsertEx RT_MANGLER(RTCrPkcs7SignerInfos_InsertEx) +# define RTCrRsaOtherPrimeInfos_Erase RT_MANGLER(RTCrRsaOtherPrimeInfos_Erase) +# define RTCrRsaOtherPrimeInfos_InsertEx RT_MANGLER(RTCrRsaOtherPrimeInfos_InsertEx) +# define RTCrSpcSerializedObjectAttributes_Erase RT_MANGLER(RTCrSpcSerializedObjectAttributes_Erase) +# define RTCrSpcSerializedObjectAttributes_InsertEx RT_MANGLER(RTCrSpcSerializedObjectAttributes_InsertEx) +# define RTCrTafTrustAnchorList_Erase RT_MANGLER(RTCrTafTrustAnchorList_Erase) +# define RTCrTafTrustAnchorList_InsertEx RT_MANGLER(RTCrTafTrustAnchorList_InsertEx) +# define RTCrX509AlgorithmIdentifiers_Erase RT_MANGLER(RTCrX509AlgorithmIdentifiers_Erase) +# define RTCrX509AlgorithmIdentifiers_InsertEx RT_MANGLER(RTCrX509AlgorithmIdentifiers_InsertEx) +# define RTCrX509AttributeTypeAndValues_Erase RT_MANGLER(RTCrX509AttributeTypeAndValues_Erase) +# define RTCrX509AttributeTypeAndValues_InsertEx RT_MANGLER(RTCrX509AttributeTypeAndValues_InsertEx) +# define RTCrX509CertificatePolicies_Erase RT_MANGLER(RTCrX509CertificatePolicies_Erase) +# define RTCrX509CertificatePolicies_InsertEx RT_MANGLER(RTCrX509CertificatePolicies_InsertEx) +# define RTCrX509Certificates_Erase RT_MANGLER(RTCrX509Certificates_Erase) +# define RTCrX509Certificates_InsertEx RT_MANGLER(RTCrX509Certificates_InsertEx) +# define RTCrX509Extensions_Erase RT_MANGLER(RTCrX509Extensions_Erase) +# define RTCrX509Extensions_InsertEx RT_MANGLER(RTCrX509Extensions_InsertEx) +# define RTCrX509GeneralNames_Erase RT_MANGLER(RTCrX509GeneralNames_Erase) +# define RTCrX509GeneralNames_InsertEx RT_MANGLER(RTCrX509GeneralNames_InsertEx) +# define RTCrX509GeneralSubtrees_Erase RT_MANGLER(RTCrX509GeneralSubtrees_Erase) +# define RTCrX509GeneralSubtrees_InsertEx RT_MANGLER(RTCrX509GeneralSubtrees_InsertEx) +# define RTCrX509Name_Erase RT_MANGLER(RTCrX509Name_Erase) +# define RTCrX509Name_InsertEx RT_MANGLER(RTCrX509Name_InsertEx) +# define RTCrX509PolicyMappings_Erase RT_MANGLER(RTCrX509PolicyMappings_Erase) +# define RTCrX509PolicyMappings_InsertEx RT_MANGLER(RTCrX509PolicyMappings_InsertEx) +# define RTCrX509PolicyQualifierInfos_Erase RT_MANGLER(RTCrX509PolicyQualifierInfos_Erase) +# define RTCrX509PolicyQualifierInfos_InsertEx RT_MANGLER(RTCrX509PolicyQualifierInfos_InsertEx) + + +/* + * Stable variables (alphabetical order): + */ +# define g_apfnRTZlibDeps RT_MANGLER(g_apfnRTZlibDeps) /* os2 win solaris */ +# define g_aRTUniFlagsRanges RT_MANGLER(g_aRTUniFlagsRanges) +# define g_aRTUniLowerRanges RT_MANGLER(g_aRTUniLowerRanges) +# define g_aRTUniUpperRanges RT_MANGLER(g_aRTUniUpperRanges) +# define g_fRTAlignmentChecks RT_MANGLER(g_fRTAlignmentChecks) +# define g_hKrnlDbgInfo RT_MANGLER(g_hKrnlDbgInfo) /* solaris */ +# define g_pStdErr RT_MANGLER(g_pStdErr) +# define g_pStdIn RT_MANGLER(g_pStdIn) +# define g_pStdOut RT_MANGLER(g_pStdOut) +# define g_pfnRTLogAssert RT_MANGLER(g_pfnRTLogAssert) +# define g_pfnRTLogAssertV RT_MANGLER(g_pfnRTLogAssertV) +# define g_pfnRTLogGetDefaultInstance RT_MANGLER(g_pfnRTLogGetDefaultInstance) +# define g_pfnRTLogGetDefaultInstanceEx RT_MANGLER(g_pfnRTLogGetDefaultInstanceEx) +# define g_pfnRTLogLoggerExV RT_MANGLER(g_pfnRTLogLoggerExV) +# define g_pfnRTLogRelGetDefaultInstance RT_MANGLER(g_pfnRTLogRelGetDefaultInstance) +# define g_pfnRTLogRelGetDefaultInstanceEx RT_MANGLER(g_pfnRTLogRelGetDefaultInstanceEx) +# define g_pszRTAssertExpr RT_MANGLER(g_pszRTAssertExpr) +# define g_pszRTAssertFile RT_MANGLER(g_pszRTAssertFile) +# define g_pszRTAssertFunction RT_MANGLER(g_pszRTAssertFunction) +# define g_szRTAssertMsg1 RT_MANGLER(g_szRTAssertMsg1) +# define g_szRTAssertMsg2 RT_MANGLER(g_szRTAssertMsg2) +# define g_u32RTAssertLine RT_MANGLER(g_u32RTAssertLine) + +/* sort/merge into the above later: */ +# define g_RTAsn1Time_Vtable RT_MANGLER(g_RTAsn1Time_Vtable) +# define g_RTAsn1String_Vtable RT_MANGLER(g_RTAsn1String_Vtable) +# define g_RTAsn1OctetString_Vtable RT_MANGLER(g_RTAsn1OctetString_Vtable) +# define g_RTAsn1ObjId_Vtable RT_MANGLER(g_RTAsn1ObjId_Vtable) +# define g_RTAsn1Null_Vtable RT_MANGLER(g_RTAsn1Null_Vtable) +# define g_RTAsn1Integer_Vtable RT_MANGLER(g_RTAsn1Integer_Vtable) +# define g_RTAsn1Core_Vtable RT_MANGLER(g_RTAsn1Core_Vtable) +# define g_RTAsn1Boolean_Vtable RT_MANGLER(g_RTAsn1Boolean_Vtable) +# define g_RTAsn1BitString_Vtable RT_MANGLER(g_RTAsn1BitString_Vtable) +# define g_RTAsn1DefaultAllocator RT_MANGLER(g_RTAsn1DefaultAllocator) +# define g_RTAsn1EFenceAllocator RT_MANGLER(g_RTAsn1EFenceAllocator) +# define g_RTAsn1SaferAllocator RT_MANGLER(g_RTAsn1SaferAllocator) +# define g_aRTCrPkcs7Markers RT_MANGLER(g_aRTCrPkcs7Markers) +# define g_cRTCrPkcs7Markers RT_MANGLER(g_cRTCrPkcs7Markers) +# define g_aRTCrX509CertificateMarkers RT_MANGLER(g_aRTCrX509CertificateMarkers) +# define g_cRTCrX509CertificateMarkers RT_MANGLER(g_cRTCrX509CertificateMarkers) +# define g_aRTCrKeyPublicMarkers RT_MANGLER(g_aRTCrKeyPublicMarkers) +# define g_cRTCrKeyPublicMarkers RT_MANGLER(g_cRTCrKeyPublicMarkers) +# define g_aRTCrKeyPrivateMarkers RT_MANGLER(g_aRTCrKeyPrivateMarkers) +# define g_cRTCrKeyPrivateMarkers RT_MANGLER(g_cRTCrKeyPrivateMarkers) +# define g_aRTCrKeyAllMarkers RT_MANGLER(g_aRTCrKeyAllMarkers) +# define g_cRTCrKeyAllMarkers RT_MANGLER(g_cRTCrKeyAllMarkers) +# define g_acRTThreadTypeStats RT_MANGLER(g_acRTThreadTypeStats) /* internal */ +# define g_RTIoQueueStdFileProv RT_MANGLER(g_RTIoQueueStdFileProv) /* internal */ +# define g_RTIoQueueAioFileProv RT_MANGLER(g_RTIoQueueAioFileProv) /* internal */ +# define g_RTIoQueueLnxIoURingProv RT_MANGLER(g_RTIoQueueLnxIoURingProv) /* internal */ + +#if 0 /* Disabled for now as I'm not sure the assmbler supports mangling yet. */ +# define g_abRTZeroPage RT_MANGLER(g_abRTZeroPage) +# define g_abRTZero4K RT_MANGLER(g_abRTZero4K) +# define g_abRTZero8K RT_MANGLER(g_abRTZero8K) +# define g_abRTZero16K RT_MANGLER(g_abRTZero16K) +# define g_abRTZero32K RT_MANGLER(g_abRTZero32K) +# define g_abRTZero64K RT_MANGLER(g_abRTZero64K) +#endif + + +/* + * Unstable functions (alphabetical order): + */ +/** @todo the list is incomplete! See the .def files + libraries. */ + + +/* + * Unstable variables (alphabetical order): + */ +/* none */ + +#endif /* !DOXYGEN_RUNNING */ + +#endif /* !IPRT_INCLUDED_mangling_h */ + diff --git a/include/iprt/manifest.h b/include/iprt/manifest.h new file mode 100644 index 00000000..ececd07f --- /dev/null +++ b/include/iprt/manifest.h @@ -0,0 +1,560 @@ +/** @file + * IPRT - Manifest file handling. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_manifest_h +#define IPRT_INCLUDED_manifest_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_manifest RTManifest - Manifest file creation and checking + * @ingroup grp_rt + * @{ + */ + +/** @name Manifest attribute types. + * The types can be ORed together to form a set. + * @{ */ +/** For use with other attributes. Representation unknown. */ +#define RTMANIFEST_ATTR_UNKNOWN 0 +/** The size of the content. Represented as a decimal number. */ +#define RTMANIFEST_ATTR_SIZE RT_BIT_32(0) +/** The MD5 of the content. Represented as a hex string. */ +#define RTMANIFEST_ATTR_MD5 RT_BIT_32(1) +/** The SHA-1 of the content. Represented as a hex string. */ +#define RTMANIFEST_ATTR_SHA1 RT_BIT_32(2) +/** The SHA-256 of the content. Represented as a hex string. */ +#define RTMANIFEST_ATTR_SHA256 RT_BIT_32(3) +/** The SHA-512 of the content. Represented as a hex string. */ +#define RTMANIFEST_ATTR_SHA512 RT_BIT_32(4) +/** The end of the valid values. */ +#define RTMANIFEST_ATTR_END RT_BIT_32(5) +/** Wildcard for use in queries. */ +#define RTMANIFEST_ATTR_ANY UINT32_C(0xffffffff) +/** @} */ + + +/** + * Creates an empty manifest. + * + * @returns IPRT status code. + * @param fFlags Flags, MBZ. + * @param phManifest Where to return the handle to the manifest. + */ +RTDECL(int) RTManifestCreate(uint32_t fFlags, PRTMANIFEST phManifest); + +/** + * Retains a reference to the manifest handle. + * + * @returns The new reference count, UINT32_MAX if the handle is invalid. + * @param hManifest The handle to retain. + */ +RTDECL(uint32_t) RTManifestRetain(RTMANIFEST hManifest); + +/** + * Releases a reference to the manifest handle. + * + * @returns The new reference count, 0 if free. UINT32_MAX is returned if the + * handle is invalid. + * @param hManifest The handle to release. + * NIL is quietly ignored (returns 0). + */ +RTDECL(uint32_t) RTManifestRelease(RTMANIFEST hManifest); + +/** + * Creates a duplicate of the specified manifest. + * + * @returns IPRT status code + * @param hManifestSrc The manifest to clone. + * @param phManifestDst Where to store the handle to the duplicate. + */ +RTDECL(int) RTManifestDup(RTMANIFEST hManifestSrc, PRTMANIFEST phManifestDst); + +/** + * Compares two manifests for equality. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if equal. + * @retval VERR_NOT_EQUAL if not equal. + * + * @param hManifest1 The first manifest. + * @param hManifest2 The second manifest. + * @param papszIgnoreEntries Entries to ignore. Ends with a NULL entry. + * @param papszIgnoreAttrs Attributes to ignore. Ends with a NULL entry. + * @param fFlags A combination of RTMANIFEST_EQUALS_XXX values. + * @param pszError Where to store the name of the mismatching + * entry, or as much of the name as there is room + * for. This is always set. Optional. + * @param cbError The size of the buffer pointed to by @a + * pszError. + */ +RTDECL(int) RTManifestEqualsEx(RTMANIFEST hManifest1, RTMANIFEST hManifest2, const char * const *papszIgnoreEntries, + const char * const *papszIgnoreAttrs, uint32_t fFlags, char *pszError, size_t cbError); + +/** @defgroup RTMANIFEST_EQUALS_XXX RTManifestEqualsEx flags + * @{ */ +/** Ignore missing attributes if there is one or more to compare. */ +#define RTMANIFEST_EQUALS_IGN_MISSING_ATTRS RT_BIT_32(0) +/** Ignore attributes missing in the 1st manifest. + * @todo implement this */ +#define RTMANIFEST_EQUALS_IGN_MISSING_ATTRS_1ST RT_BIT_32(1) +/** Ignore missing entries in the 2nd manifest. */ +#define RTMANIFEST_EQUALS_IGN_MISSING_ENTRIES_2ND RT_BIT_32(2) +/** Mask of valid flags. */ +#define RTMANIFEST_EQUALS_VALID_MASK UINT32_C(0x00000005) +/** @} */ + +/** + * Compares two manifests for equality. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if equal. + * @retval VERR_NOT_EQUAL if not equal. + * + * @param hManifest1 The first manifest. + * @param hManifest2 The second manifest. + */ +RTDECL(int) RTManifestEquals(RTMANIFEST hManifest1, RTMANIFEST hManifest2); + +/** + * + * @returns IPRT status code. + * @param hManifest Handle to the manifest. + * @param fEntriesOnly Whether to only gather attribute types from the + * entries (@c true), or also include the manifest + * attributes (@c false). + * @param pfTypes Where to return the attributes. + */ +RTDECL(int) RTManifestQueryAllAttrTypes(RTMANIFEST hManifest, bool fEntriesOnly, uint32_t *pfTypes); + +/** + * Sets a manifest attribute. + * + * @returns IPRT status code. + * @param hManifest The manifest handle. + * @param pszAttr The attribute name, if NULL it will be termined from @a + * fType gives it. If this already exists, its value will + * be replaced. + * @param pszValue The value string. + * @param fType The attribute type. If not know, pass + * RTMANIFEST_ATTR_UNKNOWN with a valid attribute + * name string (@a pszAttr). + */ +RTDECL(int) RTManifestSetAttr(RTMANIFEST hManifest, const char *pszAttr, const char *pszValue, uint32_t fType); + +/** + * Unsets (removes) a manifest attribute if it exists. + * + * @returns IPRT status code. + * @retval VWRN_NOT_FOUND if not found. + * + * @param hManifest The manifest handle. + * @param pszAttr The attribute name. + */ +RTDECL(int) RTManifestUnsetAttr(RTMANIFEST hManifest, const char *pszAttr); + +/** + * Query a manifest attribute. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the value buffer is too small. The @a + * pszValue buffer will not be modified. + * @retval VERR_MANIFEST_ATTR_NOT_FOUND + * @retval VERR_MANIFEST_ATTR_TYPE_NOT_FOUND + * @retval VERR_MANIFEST_ATTR_TYPE_MISMATCH + * + * @param hManifest The manifest handle. + * @param pszAttr The attribute name. If NULL, it will be + * selected by @a fType alone. + * @param fType The attribute types the entry should match. Pass + * Pass RTMANIFEST_ATTR_ANY match any. If more + * than one is given, the first matching one is + * returned. + * @param pszValue Where to return value. + * @param cbValue The size of the buffer @a pszValue points to. + * @param pfType Where to return the attribute type value. + */ +RTDECL(int) RTManifestQueryAttr(RTMANIFEST hManifest, const char *pszAttr, uint32_t fType, + char *pszValue, size_t cbValue, uint32_t *pfType); + +/** + * Sets an attribute of a manifest entry. + * + * @returns IPRT status code. + * @param hManifest The manifest handle. + * @param pszEntry The entry name. This will automatically be + * added if there was no previous call to + * RTManifestEntryAdd for this name. See + * RTManifestEntryAdd for the entry name rules. + * @param pszAttr The attribute name, if NULL it will be termined from @a + * fType gives it. If this already exists, its value will + * be replaced. + * @param pszValue The value string. + * @param fType The attribute type. If not know, pass + * RTMANIFEST_ATTR_UNKNOWN with a valid attribute + * name string (@a pszAttr). + */ +RTDECL(int) RTManifestEntrySetAttr(RTMANIFEST hManifest, const char *pszEntry, const char *pszAttr, + const char *pszValue, uint32_t fType); + +/** + * Unsets (removes) an attribute of a manifest entry if they both exist. + * + * @returns IPRT status code. + * @retval VWRN_NOT_FOUND if not found. + * + * @param hManifest The manifest handle. + * @param pszEntry The entry name. + * @param pszAttr The attribute name. + */ +RTDECL(int) RTManifestEntryUnsetAttr(RTMANIFEST hManifest, const char *pszEntry, const char *pszAttr); + +/** + * Query a manifest entry attribute. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the value buffer is too small. The @a + * pszValue buffer will not be modified. + * @retval VERR_NOT_FOUND if the entry was not found. + * @retval VERR_MANIFEST_ATTR_NOT_FOUND + * @retval VERR_MANIFEST_ATTR_TYPE_NOT_FOUND + * @retval VERR_MANIFEST_ATTR_TYPE_MISMATCH + * + * @param hManifest The manifest handle. + * @param pszEntry The entry name. + * @param pszAttr The attribute name. If NULL, it will be + * selected by @a fType alone. + * @param fType The attribute types the entry should match. Pass + * Pass RTMANIFEST_ATTR_ANY match any. If more + * than one is given, the first matching one is + * returned. + * @param pszValue Where to return value. + * @param cbValue The size of the buffer @a pszValue points to. + * @param pfType Where to return the attribute type value. + */ +RTDECL(int) RTManifestEntryQueryAttr(RTMANIFEST hManifest, const char *pszEntry, const char *pszAttr, uint32_t fType, + char *pszValue, size_t cbValue, uint32_t *pfType); + +/** + * Adds a new entry to a manifest. + * + * The entry name rules: + * - The entry name can contain any character defined by unicode, except + * control characters, ':', '(' and ')'. The exceptions are mainly there + * because of uncertainty around how various formats handles these. + * - It is considered case sensitive. + * - Forward (unix) and backward (dos) slashes are considered path + * separators and converted to forward slashes. + * + * @returns IPRT status code. + * @retval VWRN_ALREADY_EXISTS if the entry already exists. + * + * @param hManifest The manifest handle. + * @param pszEntry The entry name (UTF-8). + * + * @remarks Some manifest formats will not be able to store an entry without + * any attributes. So, this is just here in case it comes in handy + * when dealing with formats which can. + */ +RTDECL(int) RTManifestEntryAdd(RTMANIFEST hManifest, const char *pszEntry); + +/** + * Removes an entry. + * + * @returns IPRT status code. + * @param hManifest The manifest handle. + * @param pszEntry The entry name. + */ +RTDECL(int) RTManifestEntryRemove(RTMANIFEST hManifest, const char *pszEntry); + +/** + * Add an entry for an I/O stream using a passthru stream. + * + * The passthru I/O stream will hash all the data read from or written to the + * stream and automatically add an entry to the manifest with the desired + * attributes when it is released. Alternatively one can call + * RTManifestPtIosAddEntryNow() to have more control over exactly when this + * action is performed and which status it yields. + * + * @returns IPRT status code. + * @param hManifest The manifest to add the entry to. + * @param hVfsIos The I/O stream to pass thru to/from. + * @param pszEntry The entry name. + * @param fAttrs The attributes to create for this stream. + * @param fReadOrWrite Whether it's a read or write I/O stream. + * @param phVfsIosPassthru Where to return the new handle. + */ +RTDECL(int) RTManifestEntryAddPassthruIoStream(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, const char *pszEntry, + uint32_t fAttrs, bool fReadOrWrite, PRTVFSIOSTREAM phVfsIosPassthru); + +/** + * Adds the entry to the manifest right now. + * + * @returns IPRT status code. + * @param hVfsPtIos The manifest passthru I/O stream returned by + * RTManifestEntryAddPassthruIoStream(). + */ +RTDECL(int) RTManifestPtIosAddEntryNow(RTVFSIOSTREAM hVfsPtIos); + +/** + * Checks if the give I/O stream is a manifest passthru instance or not. + * + * @returns true if it's a manifest passthru I/O stream, false if not. + * @param hVfsPtIos Possible the manifest passthru I/O stream handle. + */ +RTDECL(bool) RTManifestPtIosIsInstanceOf(RTVFSIOSTREAM hVfsPtIos); + +/** + * Adds an entry for a file with the specified set of attributes. + * + * @returns IPRT status code. + * + * @param hManifest The manifest handle. + * @param hVfsIos The I/O stream handle of the entry. This will + * be processed to its end on successful return. + * (Must be positioned at the start to get + * the expected results.) + * @param pszEntry The entry name. + * @param fAttrs The attributes to create for this stream. See + * RTMANIFEST_ATTR_XXX. + */ +RTDECL(int) RTManifestEntryAddIoStream(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, const char *pszEntry, uint32_t fAttrs); + +/** + * Checks if there is a manifest entry by the given name. + * + * @returns true if there is, false if not or if the handle is invalid. + * @param hManifest The manifest handle. + * @param pszEntry The entry name. + */ +RTDECL(bool) RTManifestEntryExists(RTMANIFEST hManifest, const char *pszEntry); + +/** + * Reads in a "standard" manifest. + * + * This reads the format used by OVF, the distinfo in FreeBSD ports, and + * others. + * + * @returns IPRT status code. + * @param hManifest The handle to the manifest where to add the + * manifest that's read in. + * @param hVfsIos The I/O stream to read the manifest from. + */ +RTDECL(int) RTManifestReadStandard(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos); + +/** + * Reads in a "standard" manifest. + * + * This reads the format used by OVF, the distinfo in FreeBSD ports, and + * others. + * + * @returns IPRT status code. + * @param hManifest The handle to the manifest where to add the + * manifest that's read in. + * @param hVfsIos The I/O stream to read the manifest from. + * @param pszErr Where to return extended error info on failure. + * Optional. + * @param cbErr The size of the buffer @a pszErr points to. + */ +RTDECL(int) RTManifestReadStandardEx(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, char *pszErr, size_t cbErr); + +/** + * Reads in a "standard" manifest from the specified file. + * + * This reads the format used by OVF, the distinfo in FreeBSD ports, and + * others. + * + * @returns IPRT status code. + * @param hManifest The handle to the manifest where to add the + * manifest that's read in. + * @param pszFilename The name of the file to read in. + */ +RTDECL(int) RTManifestReadStandardFromFile(RTMANIFEST hManifest, const char *pszFilename); + +/** + * Writes a "standard" manifest. + * + * This writes the format used by OVF, the distinfo in FreeBSD ports, and + * others. + * + * @returns IPRT status code. + * @param hManifest The handle to the manifest to write. + * @param hVfsIos The I/O stream to read the manifest from. + */ +RTDECL(int) RTManifestWriteStandard(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos); + +/** + * Writes a "standard" manifest to the specified file. + * + * @returns IPRT status code. + * @param hManifest The handle to the manifest to write. + * @param pszFilename The name of the file. + */ +RTDECL(int) RTManifestWriteStandardToFile(RTMANIFEST hManifest, const char *pszFilename); + + + + + +/** + * Input structure for RTManifestVerify() which contains the filename & the + * SHA1/SHA256 digest. + */ +typedef struct RTMANIFESTTEST +{ + /** The filename. */ + const char *pszTestFile; + /** The SHA1/SHA256 digest of the file. */ + const char *pszTestDigest; +} RTMANIFESTTEST; +/** Pointer to the input structure. */ +typedef RTMANIFESTTEST* PRTMANIFESTTEST; + + +/** + * Verify the given SHA1 digests against the entries in the manifest file. + * + * Please note that not only the various digest have to match, but the + * filenames as well. If there are more or even less files listed in the + * manifest file than provided by paTests, VERR_MANIFEST_FILE_MISMATCH will be + * returned. + * + * @returns iprt status code. + * + * @param pszManifestFile Filename of the manifest file to verify. + * @param paTests Array of files & SHA1 sums. + * @param cTests Number of entries in paTests. + * @param piFailed A index to paTests in the + * VERR_MANIFEST_DIGEST_MISMATCH error case + * (optional). + * @deprecated Use the RTMANIFEST based API instead. + */ +RTR3DECL(int) RTManifestVerify(const char *pszManifestFile, PRTMANIFESTTEST paTests, size_t cTests, size_t *piFailed); + +/** + * This is analogous to function RTManifestVerify(), but calculates the SHA1 + * sums of the given files itself. + * + * @returns iprt status code. + * + * @param pszManifestFile Filename of the manifest file to verify. + * @param papszFiles Array of files to check SHA1 sums. + * @param cFiles Number of entries in papszFiles. + * @param piFailed A index to papszFiles in the + * VERR_MANIFEST_DIGEST_MISMATCH error case + * (optional). + * @param pfnProgressCallback optional callback for the progress indication + * @param pvUser user defined pointer for the callback + * @deprecated Use the RTMANIFEST based API instead. + */ +RTR3DECL(int) RTManifestVerifyFiles(const char *pszManifestFile, const char * const *papszFiles, size_t cFiles, size_t *piFailed, + PFNRTPROGRESS pfnProgressCallback, void *pvUser); + +/** + * Creates a manifest file for a set of files. The manifest file contains SHA1 + * sums of every provided file and could be used to verify the data integrity + * of them. + * + * @returns iprt status code. + * + * @param pszManifestFile Filename of the manifest file to create. + * @param enmDigestType The digest type (RTDIGESTTYPE_*) + * @param papszFiles Array of files to create SHA1 sums for. + * @param cFiles Number of entries in papszFiles. + * @param pfnProgressCallback optional callback for the progress indication + * @param pvUser user defined pointer for the callback + * @deprecated Use the RTMANIFEST based API instead. + */ +RTR3DECL(int) RTManifestWriteFiles(const char *pszManifestFile, RTDIGESTTYPE enmDigestType, + const char * const *papszFiles, size_t cFiles, + PFNRTPROGRESS pfnProgressCallback, void *pvUser); + +/** + * Queries the first digest type found in the given manifest. + * + * @returns iprt status code. + * + * @param pvBuf Pointer to memory buffer of the manifest file. + * @param cbSize Size of the memory buffer. + * @param penmDigestType Where to return the first digest type found in + * the manifest. + * @deprecated Use the RTMANIFEST based API instead. + */ +RTR3DECL(int) RTManifestVerifyDigestType(void const *pvBuf, size_t cbSize, RTDIGESTTYPE *penmDigestType); + +/** + * Verify the given SHA1 digests against the entries in the manifest file in + * memory. + * + * @returns iprt status code. + * + * @param pvBuf Pointer to memory buffer of the manifest file. + * @param cbSize Size of the memory buffer. + * @param paTests Array of file names and digests. + * @param cTests Number of entries in paTests. + * @param piFailed A index to paTests in the + * VERR_MANIFEST_DIGEST_MISMATCH error case + * (optional). + * @deprecated Use the RTMANIFEST based API instead. + */ +RTR3DECL(int) RTManifestVerifyFilesBuf(void *pvBuf, size_t cbSize, PRTMANIFESTTEST paTests, size_t cTests, size_t *piFailed); + +/** + * Creates a manifest file in memory for a set of files. The manifest file + * contains SHA1 sums of every provided file and could be used to verify the + * data integrity of them. + * + * @returns iprt status code. + * + * @param ppvBuf Pointer to resulting memory buffer. + * @param pcbSize Pointer for the size of the memory buffer. + * @param enmDigestType Which type of digest ("SHA1", "SHA256", ...) + * @param paFiles Array of file names and digests. + * @param cFiles Number of entries in paFiles. + * @deprecated Use the RTMANIFEST based API instead. + */ +RTR3DECL(int) RTManifestWriteFilesBuf(void **ppvBuf, size_t *pcbSize, RTDIGESTTYPE enmDigestType, PRTMANIFESTTEST paFiles, size_t cFiles); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_manifest_h */ + diff --git a/include/iprt/md2.h b/include/iprt/md2.h new file mode 100644 index 00000000..0b408424 --- /dev/null +++ b/include/iprt/md2.h @@ -0,0 +1,139 @@ +/** @file + * IPRT - Message-Digest Algorithm 2. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_md2_h +#define IPRT_INCLUDED_md2_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_md2 RTMd2 - Message-Digest algorithm 2 + * @ingroup grp_rt + * @{ + */ + +/** Size of a MD2 hash. */ +#define RTMD2_HASH_SIZE 16 +/** The length of a MD2 digest string. The terminator is not included. */ +#define RTMD2_DIGEST_LEN 32 + +/** + * MD2 hash algorithm context. + */ +typedef union RTMD2CONTEXT +{ + uint64_t u64BetterAlignment; + uint8_t abPadding[4 + 16 + 16*4 + 16*4]; +#ifdef RT_MD2_PRIVATE_CONTEXT + MD2_CTX Private; +#endif +#ifdef RT_MD2_PRIVATE_ALT_CONTEXT + RTMD2ALTPRIVATECTX AltPrivate; +#endif +} RTMD2CONTEXT; + +/** Pointer to MD2 hash algorithm context. */ +typedef RTMD2CONTEXT *PRTMD2CONTEXT; + + +/** + * Compute the MD2 hash of the data. + * + * @param pvBuf Pointer to data. + * @param cbBuf Length of data (in bytes). + * @param pabDigest Where to store the hash. + * (What's passed is a pointer to the caller's buffer.) + */ +RTDECL(void) RTMd2(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTMD2_HASH_SIZE]); + +/** + * Initialize MD2 context. + * + * @param pCtx Pointer to the MD2 context to initialize. + */ +RTDECL(void) RTMd2Init(PRTMD2CONTEXT pCtx); + +/** + * Feed data into the MD2 computation. + * + * @param pCtx Pointer to the MD2 context. + * @param pvBuf Pointer to data. + * @param cbBuf Length of data (in bytes). + */ +RTDECL(void) RTMd2Update(PRTMD2CONTEXT pCtx, const void *pvBuf, size_t cbBuf); + +/** + * Compute the MD2 hash of the data. + * + * @param pCtx Pointer to the MD2 context. + * @param pabDigest Where to store the hash. (What's passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTMd2Final(PRTMD2CONTEXT pCtx, uint8_t pabDigest[RTMD2_HASH_SIZE]); + +/** + * Converts a MD2 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pabDigest The binary digest returned by RTMd2Final or RTMd2. + * @param pszDigest Where to return the stringified digest. + * @param cchDigest The size of the output buffer. Should be at least + * RTMD2_STRING_LEN + 1 bytes. + */ +RTDECL(int) RTMd2ToString(uint8_t const pabDigest[RTMD2_HASH_SIZE], char *pszDigest, size_t cchDigest); + +/** + * Converts a MD2 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pszDigest The stringified digest. Leading and trailing spaces are + * ignored. + * @param pabDigest Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(int) RTMd2FromString(char const *pszDigest, uint8_t pabDigest[RTMD2_HASH_SIZE]); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_md2_h */ + diff --git a/include/iprt/md4.h b/include/iprt/md4.h new file mode 100644 index 00000000..a95d2e25 --- /dev/null +++ b/include/iprt/md4.h @@ -0,0 +1,142 @@ +/** @file + * IPRT - Message-Digest Algorithm 4. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_md4_h +#define IPRT_INCLUDED_md4_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_md4 RTMd4 - Message-Digest algorithm 4 + * @ingroup grp_rt + * + * @note This is just for backwards compatibility and completeness. + * + * @{ + */ + +/** Size of a MD4 hash. */ +#define RTMD4_HASH_SIZE 16 +/** The length of a MD4 digest string. The terminator is not included. */ +#define RTMD4_DIGEST_LEN 32 + +/** + * MD4 hash algorithm context. + */ +typedef union RTMD4CONTEXT +{ + uint64_t u64BetterAlignment; + uint8_t abPadding[22*4 + 64 + 8]; +#ifdef RT_MD4_PRIVATE_CONTEXT + MD4_CTX Private; +#endif +#ifdef RT_MD4_PRIVATE_ALT_CONTEXT + RTMD4ALTPRIVATECTX AltPrivate; +#endif +} RTMD4CONTEXT; + +/** Pointer to MD4 hash algorithm context. */ +typedef RTMD4CONTEXT *PRTMD4CONTEXT; + + +/** + * Compute the MD4 hash of the data. + * + * @param pvBuf Pointer to data. + * @param cbBuf Length of data (in bytes). + * @param pabDigest Where to store the hash. + * (What's passed is a pointer to the caller's buffer.) + */ +RTDECL(void) RTMd4(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTMD4_HASH_SIZE]); + +/** + * Initialize MD4 context. + * + * @param pCtx Pointer to the MD4 context to initialize. + */ +RTDECL(void) RTMd4Init(PRTMD4CONTEXT pCtx); + +/** + * Feed data into the MD4 computation. + * + * @param pCtx Pointer to the MD4 context. + * @param pvBuf Pointer to data. + * @param cbBuf Length of data (in bytes). + */ +RTDECL(void) RTMd4Update(PRTMD4CONTEXT pCtx, const void *pvBuf, size_t cbBuf); + +/** + * Compute the MD4 hash of the data. + * + * @param pCtx Pointer to the MD4 context. + * @param pabDigest Where to store the hash. (What's passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTMd4Final(PRTMD4CONTEXT pCtx, uint8_t pabDigest[RTMD4_HASH_SIZE]); + +/** + * Converts a MD4 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pabDigest The binary digest returned by RTMd4Final or RTMd4. + * @param pszDigest Where to return the stringified digest. + * @param cchDigest The size of the output buffer. Should be at least + * RTMD4_STRING_LEN + 1 bytes. + */ +RTDECL(int) RTMd4ToString(uint8_t const pabDigest[RTMD4_HASH_SIZE], char *pszDigest, size_t cchDigest); + +/** + * Converts a MD4 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pszDigest The stringified digest. Leading and trailing spaces are + * ignored. + * @param pabDigest Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(int) RTMd4FromString(char const *pszDigest, uint8_t pabDigest[RTMD4_HASH_SIZE]); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_md4_h */ + diff --git a/include/iprt/md5.h b/include/iprt/md5.h new file mode 100644 index 00000000..a89ab8ac --- /dev/null +++ b/include/iprt/md5.h @@ -0,0 +1,148 @@ +/** @file + * IPRT - Message-Digest algorithm 5. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_md5_h +#define IPRT_INCLUDED_md5_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/** @defgroup grp_rt_md5 RTMd5 - Message-Digest algorithm 5 + * @ingroup grp_rt + * @{ + */ + +/** Size of a MD5 hash. */ +#define RTMD5_HASH_SIZE 16 +/** @deprecated Use RTMD5_HASH_SIZE. */ +#define RTMD5HASHSIZE RTMD5_HASH_SIZE +/** The length of a MD5 digest string. The terminator is not included. */ +#define RTMD5_DIGEST_LEN 32 +/** Size of a MD5 hash. + * @deprecated Use RTMD5_DIGEST_LEN */ +#define RTMD5_STRING_LEN RTMD5_DIGEST_LEN + +/** + * MD5 hash algorithm context. + */ +typedef union RTMD5CONTEXT +{ + uint64_t u64BetterAlignment; + uint8_t abPadding[(4 + 6 + 16 + 1) * sizeof(uint32_t)]; + /** Context used by md5-alt.cpp. */ + struct + { + uint32_t in[16]; + uint32_t buf[4]; + uint32_t bits[2]; + } AltPrivate; +#ifdef RT_MD5_OPENSSL_PRIVATE_CONTEXT + /** Context used by md5-openssl.cpp. */ + MD5_CTX OsslPrivate; +#endif +} RTMD5CONTEXT; +/** Pointer to MD5 hash algorithm context. */ +typedef RTMD5CONTEXT *PRTMD5CONTEXT; + +RT_C_DECLS_BEGIN + +/** + * Compute the MD5 hash of the data. + * + * @param pvBuf Pointer to data. + * @param cbBuf Length of data (in bytes). + * @param pabDigest Where to store the hash. + * (What's passed is a pointer to the caller's buffer.) + */ +RTDECL(void) RTMd5(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTMD5HASHSIZE]); + +/** + * Initialize MD5 context. + * + * @param pCtx Pointer to the MD5 context to initialize. + */ +RTDECL(void) RTMd5Init(PRTMD5CONTEXT pCtx); + +/** + * Feed data into the MD5 computation. + * + * @param pCtx Pointer to the MD5 context. + * @param pvBuf Pointer to data. + * @param cbBuf Length of data (in bytes). + */ +RTDECL(void) RTMd5Update(PRTMD5CONTEXT pCtx, const void *pvBuf, size_t cbBuf); + +/** + * Compute the MD5 hash of the data. + * + * @param pabDigest Where to store the hash. + * (What's passed is a pointer to the caller's buffer.) + * @param pCtx Pointer to the MD5 context. + */ +RTDECL(void) RTMd5Final(uint8_t pabDigest[RTMD5HASHSIZE], PRTMD5CONTEXT pCtx); + +/** + * Converts a MD5 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pabDigest The binary digest returned by RTMd5Final or RTMd5. + * @param pszDigest Where to return the stringified digest. + * @param cchDigest The size of the output buffer. Should be at least + * RTMD5_STRING_LEN + 1 bytes. + */ +RTDECL(int) RTMd5ToString(uint8_t const pabDigest[RTMD5_HASH_SIZE], char *pszDigest, size_t cchDigest); + +/** + * Converts a MD5 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pszDigest The stringified digest. Leading and trailing spaces are + * ignored. + * @param pabDigest Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(int) RTMd5FromString(char const *pszDigest, uint8_t pabDigest[RTMD5_HASH_SIZE]); + + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_md5_h */ + diff --git a/include/iprt/mem.h b/include/iprt/mem.h new file mode 100644 index 00000000..9cfbbc20 --- /dev/null +++ b/include/iprt/mem.h @@ -0,0 +1,1239 @@ +/** @file + * IPRT - Memory Management and Manipulation. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_mem_h +#define IPRT_INCLUDED_mem_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +#ifdef IPRT_WITH_GCC_SANITIZER +# include <sanitizer/lsan_interface.h> +#endif + +#ifdef IN_RC +# error "There are no RTMem APIs available Guest Context!" +#endif + + +/** @defgroup grp_rt_mem RTMem - Memory Management and Manipulation + * @ingroup grp_rt + * @{ + */ + +RT_C_DECLS_BEGIN + +/** @def RTMEM_ALIGNMENT + * The alignment of the memory blocks returned by RTMemAlloc(), RTMemAllocZ(), + * RTMemRealloc(), RTMemTmpAlloc() and RTMemTmpAllocZ() for allocations greater + * than RTMEM_ALIGNMENT. + * + * @note This alignment is not forced if the electric fence is active! + */ +#if defined(RT_OS_OS2) +# define RTMEM_ALIGNMENT 4 +#else +# define RTMEM_ALIGNMENT 8 +#endif + +/** @def RTMEM_TAG + * The default allocation tag used by the RTMem allocation APIs. + * + * When not defined before the inclusion of iprt/mem.h or iprt/memobj.h, this + * will default to the pointer to the current file name. The memory API will + * make of use of this as pointer to a volatile but read-only string. + * The alternative tag includes the line number for a more-detailed analysis. + */ +#ifndef RTMEM_TAG +# if 0 +# define RTMEM_TAG (__FILE__ ":" RT_XSTR(__LINE__)) +# else +# define RTMEM_TAG (__FILE__) +# endif +#endif + + +/** @name Allocate temporary memory. + * @{ */ +/** + * Allocates temporary memory with default tag. + * + * Temporary memory blocks are used for not too large memory blocks which + * are believed not to stick around for too long. Using this API instead + * of RTMemAlloc() not only gives the heap manager room for optimization + * but makes the code easier to read. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure, assertion raised in strict builds. + * @param cb Size in bytes of the memory block to allocated. + */ +#define RTMemTmpAlloc(cb) RTMemTmpAllocTag((cb), RTMEM_TAG) + +/** + * Allocates temporary memory with custom tag. + * + * Temporary memory blocks are used for not too large memory blocks which + * are believed not to stick around for too long. Using this API instead + * of RTMemAlloc() not only gives the heap manager room for optimization + * but makes the code easier to read. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure, assertion raised in strict builds. + * @param cb Size in bytes of the memory block to allocated. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemTmpAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Allocates zero'd temporary memory with default tag. + * + * Same as RTMemTmpAlloc() but the memory will be zero'd. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure, assertion raised in strict builds. + * @param cb Size in bytes of the memory block to allocated. + */ +#define RTMemTmpAllocZ(cb) RTMemTmpAllocZTag((cb), RTMEM_TAG) + +/** + * Allocates zero'd temporary memory with custom tag. + * + * Same as RTMemTmpAlloc() but the memory will be zero'd. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure, assertion raised in strict builds. + * @param cb Size in bytes of the memory block to allocated. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemTmpAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Free temporary memory. + * + * @param pv Pointer to memory block. + */ +RTDECL(void) RTMemTmpFree(void *pv) RT_NO_THROW_PROTO; + +/** + * Clear and free temporary memory. + * + * This is strongly recommended when the memory being freed holds untrusted data + * to help counter heap spraying. + * + * @param pv Pointer to memory block. + * @param cb Size of the memory block. + * + * @note The memory isn't always filled with zeros, it can be set to a + * different value in some configurations. + */ +RTDECL(void) RTMemTmpFreeZ(void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** @} */ + + +/** + * Allocates memory with default tag. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure, assertion raised in strict builds. + * @param cb Size in bytes of the memory block to allocated. + */ +#define RTMemAlloc(cb) RTMemAllocTag((cb), RTMEM_TAG) + +/** + * Allocates memory with custom tag. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure, assertion raised in strict builds. + * @param cb Size in bytes of the memory block to allocated. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Allocates zero'd memory with default tag. + * + * Instead of memset(pv, 0, sizeof()) use this when you want zero'd + * memory. This keeps the code smaller and the heap can skip the memset + * in about 0.42% of calls :-). + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param cb Size in bytes of the memory block to allocated. + */ +#define RTMemAllocZ(cb) RTMemAllocZTag((cb), RTMEM_TAG) + +/** + * Allocates zero'd memory with custom tag. + * + * Instead of memset(pv, 0, sizeof()) use this when you want zero'd + * memory. This keeps the code smaller and the heap can skip the memset + * in about 0.42% of calls :-). + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param cb Size in bytes of the memory block to allocated. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Wrapper around RTMemAlloc for automatically aligning variable sized + * allocations so that the various electric fence heaps works correctly. + * + * @returns See RTMemAlloc. + * @param cbUnaligned The unaligned size. + */ +#define RTMemAllocVar(cbUnaligned) RTMemAllocVarTag((cbUnaligned), RTMEM_TAG) + +/** + * Wrapper around RTMemAllocTag for automatically aligning variable sized + * allocations so that the various electric fence heaps works correctly. + * + * @returns See RTMemAlloc. + * @param cbUnaligned The unaligned size. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemAllocVarTag(size_t cbUnaligned, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Wrapper around RTMemAllocZ for automatically aligning variable sized + * allocations so that the various electric fence heaps works correctly. + * + * @returns See RTMemAllocZ. + * @param cbUnaligned The unaligned size. + */ +#define RTMemAllocZVar(cbUnaligned) RTMemAllocZVarTag((cbUnaligned), RTMEM_TAG) + +/** + * Wrapper around RTMemAllocZTag for automatically aligning variable sized + * allocations so that the various electric fence heaps works correctly. + * + * @returns See RTMemAllocZ. + * @param cbUnaligned The unaligned size. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemAllocZVarTag(size_t cbUnaligned, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Duplicates a chunk of memory into a new heap block (default tag). + * + * @returns New heap block with the duplicate data. + * @returns NULL if we're out of memory. + * @param pvSrc The memory to duplicate. + * @param cb The amount of memory to duplicate. + */ +#define RTMemDup(pvSrc, cb) RTMemDupTag((pvSrc), (cb), RTMEM_TAG) + +/** + * Duplicates a chunk of memory into a new heap block (custom tag). + * + * @returns New heap block with the duplicate data. + * @returns NULL if we're out of memory. + * @param pvSrc The memory to duplicate. + * @param cb The amount of memory to duplicate. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemDupTag(const void *pvSrc, size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Duplicates a chunk of memory into a new heap block with some additional + * zeroed memory (default tag). + * + * @returns New heap block with the duplicate data. + * @returns NULL if we're out of memory. + * @param pvSrc The memory to duplicate. + * @param cbSrc The amount of memory to duplicate. + * @param cbExtra The amount of extra memory to allocate and zero. + */ +#define RTMemDupEx(pvSrc, cbSrc, cbExtra) RTMemDupExTag((pvSrc), (cbSrc), (cbExtra), RTMEM_TAG) + +/** + * Duplicates a chunk of memory into a new heap block with some additional + * zeroed memory (default tag). + * + * @returns New heap block with the duplicate data. + * @returns NULL if we're out of memory. + * @param pvSrc The memory to duplicate. + * @param cbSrc The amount of memory to duplicate. + * @param cbExtra The amount of extra memory to allocate and zero. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemDupExTag(const void *pvSrc, size_t cbSrc, size_t cbExtra, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Reallocates memory with default tag. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param pvOld The memory block to reallocate. + * @param cbNew The new block size (in bytes). + */ +#define RTMemRealloc(pvOld, cbNew) RTMemReallocTag((pvOld), (cbNew), RTMEM_TAG) + +/** + * Reallocates memory with custom tag. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param pvOld The memory block to reallocate. + * @param cbNew The new block size (in bytes). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemReallocTag(void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Reallocates memory with default tag, initializing any new space to zero. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param pvOld The memory block to reallocate. + * @param cbOld The old block size (in bytes). + * @param cbNew The new block size (in bytes). + */ +#define RTMemReallocZ(pvOld, cbOld, cbNew) RTMemReallocZTag((pvOld), (cbOld), (cbNew), RTMEM_TAG) + +/** + * Reallocates memory with custom tag, initializing any new space to zero. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param pvOld The memory block to reallocate. + * @param cbOld The old block size (in bytes). + * @param cbNew The new block size (in bytes). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemReallocZTag(void *pvOld, size_t cbOld, size_t cbNew, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Frees memory. + * + * @param pv Pointer to memory block. + */ +RTDECL(void) RTMemFree(void *pv) RT_NO_THROW_PROTO; + +/** + * Clears and frees memory. + * + * This is strongly recommended when the memory being freed holds untrusted data + * to help counter heap spraying. + * + * @param pv Pointer to memory block. + * @param cb The size of the allocation. + * + * @note The memory isn't always filled with zeros, it can be set to a + * different value in some configurations. + */ +RTDECL(void) RTMemFreeZ(void *pv, size_t cb) RT_NO_THROW_PROTO; + + + +/** @name RTR0MemAllocEx and RTR0MemAllocExTag flags. + * @{ */ +/** The returned memory should be zeroed. */ +#define RTMEMALLOCEX_FLAGS_ZEROED RT_BIT(0) +/** Allocate memory that can be executed. + * @note Only supported in ring-3 for now, use RTR0MemObjAllocPage w/ @a + * fExecutable = @c true for ring-0. */ +#define RTMEMALLOCEX_FLAGS_EXEC RT_BIT(1) +/** Allocation from any context. + * Will return VERR_NOT_SUPPORTED if not supported. */ +#define RTMEMALLOCEX_FLAGS_ANY_CTX_ALLOC RT_BIT(2) +/** Allocate the memory such that it can be freed from any context. + * Will return VERR_NOT_SUPPORTED if not supported. */ +#define RTMEMALLOCEX_FLAGS_ANY_CTX_FREE RT_BIT(3) +/** Allocate and free from any context. + * Will return VERR_NOT_SUPPORTED if not supported. */ +#define RTMEMALLOCEX_FLAGS_ANY_CTX (RTMEMALLOCEX_FLAGS_ANY_CTX_ALLOC | RTMEMALLOCEX_FLAGS_ANY_CTX_FREE) +/** Reachable by 16-bit address. + * Will return VERR_NOT_SUPPORTED if not supported. */ +#define RTMEMALLOCEX_FLAGS_16BIT_REACH RT_BIT(4) +/** Reachable by 32-bit address. + * Will return VERR_NOT_SUPPORTED if not supported. */ +#define RTMEMALLOCEX_FLAGS_32BIT_REACH RT_BIT(5) +/** Mask of valid flags. */ +#define RTMEMALLOCEX_FLAGS_VALID_MASK UINT32_C(0x0000003f) +/** Mask of valid flags for ring-0. */ +#define RTMEMALLOCEX_FLAGS_VALID_MASK_R0 UINT32_C(0x0000000f) +/** @} */ + +/** + * Extended heap allocation API, default tag. + * + * @returns IPRT status code. + * @retval VERR_NO_MEMORY if we're out of memory. + * @retval VERR_NO_EXEC_MEMORY if we're out of executable memory. + * @retval VERR_NOT_SUPPORTED if any of the specified flags are unsupported. + * + * @param cb The amount of memory to allocate. + * @param cbAlignment The alignment requirements. Use 0 to indicate + * default alignment. + * @param fFlags A combination of the RTMEMALLOCEX_FLAGS_XXX + * defines. + * @param ppv Where to return the memory. + */ +#define RTMemAllocEx(cb, cbAlignment, fFlags, ppv) RTMemAllocExTag((cb), (cbAlignment), (fFlags), RTMEM_TAG, (ppv)) + +/** + * Extended heap allocation API, custom tag. + * + * Depending on the implementation, using this function may add extra overhead, + * so use the simpler APIs where ever possible. + * + * @returns IPRT status code. + * @retval VERR_NO_MEMORY if we're out of memory. + * @retval VERR_NO_EXEC_MEMORY if we're out of executable memory. + * @retval VERR_NOT_SUPPORTED if any of the specified flags are unsupported. + * + * @param cb The amount of memory to allocate. + * @param cbAlignment The alignment requirements. Use 0 to indicate + * default alignment. + * @param fFlags A combination of the RTMEMALLOCEX_FLAGS_XXX + * defines. + * @param pszTag The tag. + * @param ppv Where to return the memory. + */ +RTDECL(int) RTMemAllocExTag(size_t cb, size_t cbAlignment, uint32_t fFlags, const char *pszTag, void **ppv) RT_NO_THROW_PROTO; + +/** + * For freeing memory allocated by RTMemAllocEx or RTMemAllocExTag. + * + * @param pv What to free, NULL is fine. + * @param cb The amount of allocated memory. + */ +RTDECL(void) RTMemFreeEx(void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** + * Allocate page aligned memory with default tag. + * + * @returns Pointer to the allocated memory. + * @returns NULL if we're out of memory. + * @param cb Size of the memory block. Will be rounded up to page size. + */ +#define RTMemPageAlloc(cb) RTMemPageAllocTag((cb), RTMEM_TAG) + +/** + * Allocate page aligned memory with custom tag. + * + * @returns Pointer to the allocated memory. + * @returns NULL if we're out of memory. + * @param cb Size of the memory block. Will be rounded up to page size. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemPageAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Allocate zero'd page aligned memory with default tag. + * + * @returns Pointer to the allocated memory. + * @returns NULL if we're out of memory. + * @param cb Size of the memory block. Will be rounded up to page size. + */ +#define RTMemPageAllocZ(cb) RTMemPageAllocZTag((cb), RTMEM_TAG) + +/** + * Allocate zero'd page aligned memory with custom tag. + * + * @returns Pointer to the allocated memory. + * @returns NULL if we're out of memory. + * @param cb Size of the memory block. Will be rounded up to page size. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemPageAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Allocate page aligned memory with default tag, extended version. + * + * @returns Pointer to the allocated memory. + * @returns NULL if we're out of memory. + * @param cb Size of the memory block. Will be rounded up to page size. + * @param fFlags RTMEMPAGEALLOC_F_XXX. + */ +#define RTMemPageAllocEx(cb, fFlags) RTMemPageAllocExTag((cb), (fFlags), RTMEM_TAG) + +/** + * Allocate page aligned memory with custom tag, extended version. + * + * @returns Pointer to the allocated memory. + * @returns NULL if we're out of memory. + * @param cb Size of the memory block. Will be rounded up to page size. + * @param fFlags RTMEMPAGEALLOC_F_XXX. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemPageAllocExTag(size_t cb, uint32_t fFlags, const char *pszTag) RT_NO_THROW_PROTO; + +/** @name RTMEMPAGEALLOC_F_XXX - flags for RTMemPageAllocEx() and RTMemPageAllocExTag() + * @{ */ +/** Zero the allocation. */ +#define RTMEMPAGEALLOC_F_ZERO RT_BIT_32(0) +/** Try lock the allocation (failure ignored). */ +#define RTMEMPAGEALLOC_F_ADVISE_LOCKED RT_BIT_32(1) +/** Try prevent the memory from ending up in a dump/core. */ +#define RTMEMPAGEALLOC_F_ADVISE_NO_DUMP RT_BIT_32(2) +/** Valid bit mask. */ +#define RTMEMPAGEALLOC_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ + +/** + * Free a memory block allocated with RTMemPageAlloc() or RTMemPageAllocZ(). + * + * @param pv Pointer to the block as it was returned by the allocation function. + * NULL will be ignored. + * @param cb The allocation size. Will be rounded up to page size. + * Ignored if @a pv is NULL. + */ +RTDECL(void) RTMemPageFree(void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** Page level protection flags for RTMemProtect(). + * @{ + */ +/** No access at all. */ +#define RTMEM_PROT_NONE 0 +/** Read access. */ +#define RTMEM_PROT_READ 1 +/** Write access. */ +#define RTMEM_PROT_WRITE 2 +/** Execute access. */ +#define RTMEM_PROT_EXEC 4 +/** @} */ + +/** + * Change the page level protection of a memory region. + * + * @returns iprt status code. + * @param pv Start of the region. Will be rounded down to nearest page boundary. + * @param cb Size of the region. Will be rounded up to the nearest page boundary. + * @param fProtect The new protection, a combination of the RTMEM_PROT_* defines. + */ +RTDECL(int) RTMemProtect(void *pv, size_t cb, unsigned fProtect) RT_NO_THROW_PROTO; + +/** + * Goes thru some pains to make sure the specified memory block is thoroughly + * scrambled. + * + * @param pv The start of the memory block. + * @param cb The size of the memory block. + * @param cMinPasses The minimum number of passes to make. + */ +RTDECL(void) RTMemWipeThoroughly(void *pv, size_t cb, size_t cMinPasses) RT_NO_THROW_PROTO; + + +/** @def RTMEM_WILL_LEAK + * Macro for hinting that a memory allocation @a a_pv will leak. + * + * @note This shall only be used in code that doesn't allocate the object. + * Code allocating memory knowing it will leak shall start the allocation + * tag string with 'will-leak:'. + */ +/** @def RTMEM_MAY_LEAK + * Macro for hinting that a memory allocation @a a_pv may leak. + * + * @note This shall only be used in code that doesn't allocate the object. + * Code allocating memory knowing it may leak shall start the allocation + * tag string with 'may-leak:'. + */ +#ifdef IPRT_WITH_GCC_SANITIZER +# define RTMEM_WILL_LEAK(a_pv) __lsan_ignore_object(a_pv) +# define RTMEM_MAY_LEAK(a_pv) __lsan_ignore_object(a_pv) +#else +# define RTMEM_WILL_LEAK(a_pv) do { } while (0) +# define RTMEM_MAY_LEAK(a_pv) do { } while (0) +#endif + + +/** @def RTMEM_IMPLEMENT_NEW_AND_DELETE + * Provides a new and delete implementation to a class using IPRT's RTMem + * allocator. + */ +#if !defined(RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF) || defined(RTMEM_NO_WRAP_SOME_NEW_AND_DELETE_TO_EF) +# ifdef RT_EXCEPTIONS_ENABLED +# define RTMEM_IMPLEMENT_NEW_AND_DELETE() \ + void *operator new(size_t cb) RT_THROW(std::bad_alloc) \ + { \ + void *pv = RTMemAlloc(cb); \ + if (RT_LIKELY(pv)) \ + return pv; \ + throw std::bad_alloc(); \ + } \ + void *operator new(size_t cb, const std::nothrow_t ¬hrow_constant) RT_NO_THROW_DEF \ + { \ + NOREF(nothrow_constant); \ + return RTMemAlloc(cb); \ + } \ + void *operator new(size_t cb, void *pvBuf) RT_NO_THROW_DEF \ + { \ + NOREF(cb); \ + return pvBuf; \ + } \ + void *operator new[](size_t cb) RT_THROW(std::bad_alloc) \ + { \ + void *pv = RTMemAlloc(cb); \ + if (RT_LIKELY(pv)) \ + return pv; \ + throw std::bad_alloc(); \ + } \ + void *operator new[](size_t cb, const std::nothrow_t ¬hrow_constant) RT_NO_THROW_DEF \ + { \ + NOREF(nothrow_constant); \ + return RTMemAlloc(cb); \ + } \ + \ + void operator delete(void *pv) RT_NO_THROW_DEF \ + { \ + RTMemFree(pv); \ + } \ + void operator delete(void *pv, const std::nothrow_t ¬hrow_constant) RT_NO_THROW_DEF \ + { \ + NOREF(nothrow_constant); \ + RTMemFree(pv); \ + } \ + void operator delete[](void *pv) RT_NO_THROW_DEF \ + { \ + RTMemFree(pv); \ + } \ + void operator delete[](void *pv, const std::nothrow_t ¬hrow_constant) RT_NO_THROW_DEF \ + { \ + NOREF(nothrow_constant); \ + RTMemFree(pv); \ + } \ + \ + typedef int UsingIprtNewAndDeleteOperators +# else /* !RT_EXCEPTIONS_ENABLED */ +# define RTMEM_IMPLEMENT_NEW_AND_DELETE() \ + void *operator new(size_t cb) \ + { \ + return RTMemAlloc(cb); \ + } \ + void *operator new(size_t cb, const std::nothrow_t ¬hrow_constant) \ + { \ + NOREF(nothrow_constant); \ + return RTMemAlloc(cb); \ + } \ + void *operator new(size_t cb, void *pvBuf) RT_NO_THROW_DEF \ + { \ + NOREF(cb); \ + return pvBuf; \ + } \ + void *operator new[](size_t cb) \ + { \ + return RTMemAlloc(cb); \ + } \ + void *operator new[](size_t cb, const std::nothrow_t ¬hrow_constant) \ + { \ + NOREF(nothrow_constant); \ + return RTMemAlloc(cb); \ + } \ + \ + void operator delete(void *pv) \ + { \ + RTMemFree(pv); \ + } \ + void operator delete(void *pv, const std::nothrow_t ¬hrow_constant) \ + { \ + NOREF(nothrow_constant); \ + RTMemFree(pv); \ + } \ + void operator delete[](void *pv) \ + { \ + RTMemFree(pv); \ + } \ + void operator delete[](void *pv, const std::nothrow_t ¬hrow_constant) \ + { \ + NOREF(nothrow_constant); \ + RTMemFree(pv); \ + } \ + \ + typedef int UsingIprtNewAndDeleteOperators +# endif /* !RT_EXCEPTIONS_ENABLED */ +#else /* defined(RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF) && !defined(RTMEM_NO_WRAP_SOME_NEW_AND_DELETE_TO_EF) */ +# define RTMEM_IMPLEMENT_NEW_AND_DELETE() RTMEMEF_NEW_AND_DELETE_OPERATORS() +#endif /* defined(RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF) && !defined(RTMEM_NO_WRAP_SOME_NEW_AND_DELETE_TO_EF) */ + + +#ifdef IN_RING0 + +/** + * Allocates physical contiguous memory (below 4GB). + * The allocation is page aligned and the content is undefined. + * + * @returns Pointer to the memory block. This is page aligned. + * @param pPhys Where to store the physical address. + * @param cb The allocation size in bytes. This is always + * rounded up to PAGE_SIZE. + */ +RTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb) RT_NO_THROW_PROTO; + +/** + * Frees memory allocated ysing RTMemContAlloc(). + * + * @param pv Pointer to return from RTMemContAlloc(). + * @param cb The cb parameter passed to RTMemContAlloc(). + */ +RTR0DECL(void) RTMemContFree(void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** + * Copy memory from an user mode buffer into a kernel buffer. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_ACCESS_DENIED on error. + * + * @param pvDst The kernel mode destination address. + * @param R3PtrSrc The user mode source address. + * @param cb The number of bytes to copy. + */ +RTR0DECL(int) RTR0MemUserCopyFrom(void *pvDst, RTR3PTR R3PtrSrc, size_t cb); + +/** + * Copy memory from a kernel buffer into a user mode one. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_ACCESS_DENIED on error. + * + * @param R3PtrDst The user mode destination address. + * @param pvSrc The kernel mode source address. + * @param cb The number of bytes to copy. + */ +RTR0DECL(int) RTR0MemUserCopyTo(RTR3PTR R3PtrDst, void const *pvSrc, size_t cb); + +/** + * Tests if the specified address is in the user addressable range. + * + * This function does not check whether the memory at that address is accessible + * or anything of that sort, only if the address it self is in the user mode + * range. + * + * @returns true if it's in the user addressable range. false if not. + * @param R3Ptr The user mode pointer to test. + * + * @remarks Some systems may have overlapping kernel and user address ranges. + * One prominent example of this is the x86 version of Mac OS X. Use + * RTR0MemAreKrnlAndUsrDifferent() to check. + */ +RTR0DECL(bool) RTR0MemUserIsValidAddr(RTR3PTR R3Ptr); + +/** + * Tests if the specified address is in the kernel mode range. + * + * This function does not check whether the memory at that address is accessible + * or anything of that sort, only if the address it self is in the kernel mode + * range. + * + * @returns true if it's in the kernel range. false if not. + * @param pv The alleged kernel mode pointer. + * + * @remarks Some systems may have overlapping kernel and user address ranges. + * One prominent example of this is the x86 version of Mac OS X. Use + * RTR0MemAreKrnlAndUsrDifferent() to check. + */ +RTR0DECL(bool) RTR0MemKernelIsValidAddr(void *pv); + +/** + * Are user mode and kernel mode address ranges distinctly different. + * + * This determines whether RTR0MemKernelIsValidAddr and RTR0MemUserIsValidAddr + * can be used for deciding whether some arbitrary address is a user mode or a + * kernel mode one. + * + * @returns true if they are, false if not. + */ +RTR0DECL(bool) RTR0MemAreKrnlAndUsrDifferent(void); + +/** + * Copy memory from an potentially unsafe kernel mode location and into a safe + * (kernel) buffer. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_ACCESS_DENIED on error. + * @retval VERR_NOT_SUPPORTED if not (yet) supported. + * + * @param pvDst The destination address (safe). + * @param pvSrc The source address (potentially unsafe). + * @param cb The number of bytes to copy. + */ +RTR0DECL(int) RTR0MemKernelCopyFrom(void *pvDst, void const *pvSrc, size_t cb); + +/** + * Copy from a safe (kernel) buffer and to a potentially unsafe kenrel mode + * location. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_ACCESS_DENIED on error. + * @retval VERR_NOT_SUPPORTED if not (yet) supported. + * + * @param pvDst The destination address (potentially unsafe). + * @param pvSrc The source address (safe). + * @param cb The number of bytes to copy. + */ +RTR0DECL(int) RTR0MemKernelCopyTo(void *pvDst, void const *pvSrc, size_t cb); + +#endif /* IN_RING0 */ + + +/** @name Electrical Fence Version of some APIs. + * @{ + */ + +/** + * Same as RTMemTmpAllocTag() except that it's fenced. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param cb Size in bytes of the memory block to allocate. + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. + * Use RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfTmpAlloc(size_t cb, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemTmpAllocZTag() except that it's fenced. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param cb Size in bytes of the memory block to allocate. + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfTmpAllocZ(size_t cb, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemTmpFree() except that it's for fenced memory. + * + * @param pv Pointer to memory block. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void) RTMemEfTmpFree(void *pv, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemTmpFreeZ() except that it's for fenced memory. + * + * @param pv Pointer to memory block. + * @param cb Size of the memory block. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void) RTMemEfTmpFreeZ(void *pv, size_t cb, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemAllocTag() except that it's fenced. + * + * @returns Pointer to the allocated memory. Free with RTMemEfFree(). + * @returns NULL on failure. + * @param cb Size in bytes of the memory block to allocate. + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfAlloc(size_t cb, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemAllocZTag() except that it's fenced. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param cb Size in bytes of the memory block to allocate. + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfAllocZ(size_t cb, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemAllocVarTag() except that it's fenced. + * + * @returns Pointer to the allocated memory. Free with RTMemEfFree(). + * @returns NULL on failure. + * @param cbUnaligned Size in bytes of the memory block to allocate. + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfAllocVar(size_t cbUnaligned, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemAllocZVarTag() except that it's fenced. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param cbUnaligned Size in bytes of the memory block to allocate. + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfAllocZVar(size_t cbUnaligned, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemReallocTag() except that it's fenced. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param pvOld The memory block to reallocate. + * @param cbNew The new block size (in bytes). + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfRealloc(void *pvOld, size_t cbNew, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemReallocZTag() except that it's fenced. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param pvOld The memory block to reallocate. + * @param cbOld The old block size (in bytes). + * @param cbNew The new block size (in bytes). + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfReallocZ(void *pvOld, size_t cbOld, size_t cbNew, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Free memory allocated by any of the RTMemEf* allocators. + * + * @param pv Pointer to memory block. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void) RTMemEfFree(void *pv, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Clear and free memory allocated by any of the RTMemEf* allocators. + * + * @param pv Pointer to memory block. + * @param cb Size of the allocation. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void) RTMemEfFreeZ(void *pv, size_t cb, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemDupTag() except that it's fenced. + * + * @returns New heap block with the duplicate data. + * @returns NULL if we're out of memory. + * @param pvSrc The memory to duplicate. + * @param cb The amount of memory to duplicate. + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfDup(const void *pvSrc, size_t cb, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** + * Same as RTMemEfDupExTag except that it's fenced. + * + * @returns New heap block with the duplicate data. + * @returns NULL if we're out of memory. + * @param pvSrc The memory to duplicate. + * @param cbSrc The amount of memory to duplicate. + * @param cbExtra The amount of extra memory to allocate and zero. + * @param pszTag Allocation tag used for statistics and such. + * @param SRC_POS The source position where call is being made from. Use + * RT_SRC_POS when possible. Optional. + */ +RTDECL(void *) RTMemEfDupEx(const void *pvSrc, size_t cbSrc, size_t cbExtra, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_PROTO; + +/** @def RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF + * Define RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF to enable electric fence new and + * delete operators for classes which uses the RTMEMEF_NEW_AND_DELETE_OPERATORS + * macro. + */ +/** @def RTMEMEF_NEW_AND_DELETE_OPERATORS + * Defines the electric fence new and delete operators for a class when + * RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF is define. + */ +/** @def RTR0MEMEF_NEW_AND_DELETE_OPERATORS_IOKIT + * Defines the electric fence new and delete operators for an IOKit class when + * RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF is define. + * + * This differs from RTMEMEF_NEW_AND_DELETE_OPERATORS in that the memory we + * allocate is initialized to zero. It is also assuming we don't have nothrow + * variants and exceptions, so fewer variations. + */ +#if defined(RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF) && !defined(RTMEM_NO_WRAP_SOME_NEW_AND_DELETE_TO_EF) +# if defined(RT_EXCEPTIONS_ENABLED) +# define RTMEMEF_NEW_AND_DELETE_OPERATORS() \ + void *operator new(size_t cb) RT_THROW(std::bad_alloc) \ + { \ + void *pv = RTMemEfAlloc(cb, RTMEM_TAG, RT_SRC_POS); \ + if (RT_LIKELY(pv)) \ + return pv; \ + throw std::bad_alloc(); \ + } \ + void *operator new(size_t cb, const std::nothrow_t ¬hrow_constant) RT_NO_THROW_DEF \ + { \ + NOREF(nothrow_constant); \ + return RTMemEfAlloc(cb, RTMEM_TAG, RT_SRC_POS); \ + } \ + void *operator new(size_t cb, void *pvBuf) RT_NO_THROW_DEF \ + { \ + NOREF(cb); \ + return pvBuf; \ + } \ + void *operator new[](size_t cb) RT_THROW(std::bad_alloc) \ + { \ + void *pv = RTMemEfAlloc(cb, RTMEM_TAG, RT_SRC_POS); \ + if (RT_LIKELY(pv)) \ + return pv; \ + throw std::bad_alloc(); \ + } \ + void *operator new[](size_t cb, const std::nothrow_t ¬hrow_constant) RT_NO_THROW_DEF \ + { \ + NOREF(nothrow_constant); \ + return RTMemEfAlloc(cb, RTMEM_TAG, RT_SRC_POS); \ + } \ + \ + void operator delete(void *pv) RT_NO_THROW_DEF \ + { \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + void operator delete(void *pv, const std::nothrow_t ¬hrow_constant) RT_NO_THROW_DEF \ + { \ + NOREF(nothrow_constant); \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + void operator delete[](void *pv) RT_NO_THROW_DEF \ + { \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + void operator delete[](void *pv, const std::nothrow_t ¬hrow_constant) RT_NO_THROW_DEF \ + { \ + NOREF(nothrow_constant); \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + \ + typedef int UsingElectricNewAndDeleteOperators +# else +# define RTMEMEF_NEW_AND_DELETE_OPERATORS() \ + void *operator new(size_t cb) \ + { \ + return RTMemEfAlloc(cb, RTMEM_TAG, RT_SRC_POS); \ + } \ + void *operator new(size_t cb, const std::nothrow_t ¬hrow_constant) \ + { \ + NOREF(nothrow_constant); \ + return RTMemEfAlloc(cb, RTMEM_TAG, RT_SRC_POS); \ + } \ + void *operator new(size_t cb, void *pvBuf) RT_NO_THROW_DEF \ + { \ + NOREF(cb); \ + return pvBuf; \ + } \ + void *operator new[](size_t cb) \ + { \ + return RTMemEfAlloc(cb, RTMEM_TAG, RT_SRC_POS); \ + } \ + void *operator new[](size_t cb, const std::nothrow_t ¬hrow_constant) \ + { \ + NOREF(nothrow_constant); \ + return RTMemEfAlloc(cb, RTMEM_TAG, RT_SRC_POS); \ + } \ + \ + void operator delete(void *pv) \ + { \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + void operator delete(void *pv, const std::nothrow_t ¬hrow_constant) \ + { \ + NOREF(nothrow_constant); \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + void operator delete[](void *pv) \ + { \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + void operator delete[](void *pv, const std::nothrow_t ¬hrow_constant) \ + { \ + NOREF(nothrow_constant); \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + \ + typedef int UsingElectricNewAndDeleteOperators +# endif +# define RTR0MEMEF_NEW_AND_DELETE_OPERATORS_IOKIT() \ + void *operator new(size_t cb) \ + { \ + return RTMemEfAllocZ(cb, RTMEM_TAG, RT_SRC_POS); \ + } \ + void *operator new[](size_t cb) \ + { \ + return RTMemEfAllocZ(cb, RTMEM_TAG, RT_SRC_POS); \ + } \ + \ + void operator delete(void *pv) \ + { \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + void operator delete[](void *pv) \ + { \ + RTMemEfFree(pv, RT_SRC_POS); \ + } \ + \ + typedef int UsingElectricNewAndDeleteOperators +#else +# define RTMEMEF_NEW_AND_DELETE_OPERATORS() \ + typedef int UsingDefaultNewAndDeleteOperators +# define RTR0MEMEF_NEW_AND_DELETE_OPERATORS_IOKIT() \ + typedef int UsingDefaultNewAndDeleteOperators +#endif +#ifdef DOXYGEN_RUNNING +# define RTMEM_WRAP_SOME_NEW_AND_DELETE_TO_EF +#endif + +/** @def RTMEM_WRAP_TO_EF_APIS + * Define RTMEM_WRAP_TO_EF_APIS to wrap RTMem APIs to RTMemEf APIs. + */ +#if defined(RTMEM_WRAP_TO_EF_APIS) && !defined(RTMEM_NO_WRAP_TO_EF_APIS) \ + && ( defined(IN_RING3) || ( defined(IN_RING0) && !defined(IN_RING0_AGNOSTIC) && (defined(RT_OS_DARWIN) || 0) ) ) +# define RTMemTmpAllocTag(cb, pszTag) RTMemEfTmpAlloc((cb), (pszTag), RT_SRC_POS) +# define RTMemTmpAllocZTag(cb, pszTag) RTMemEfTmpAllocZ((cb), (pszTag), RT_SRC_POS) +# define RTMemTmpFree(pv) RTMemEfTmpFree((pv), RT_SRC_POS) +# define RTMemTmpFreeZ(pv, cb) RTMemEfTmpFreeZ((pv), (cb), RT_SRC_POS) +# define RTMemAllocTag(cb, pszTag) RTMemEfAlloc((cb), (pszTag), RT_SRC_POS) +# define RTMemAllocZTag(cb, pszTag) RTMemEfAllocZ((cb), (pszTag), RT_SRC_POS) +# define RTMemAllocVarTag(cbUnaligned, pszTag) RTMemEfAllocVar((cbUnaligned), (pszTag), RT_SRC_POS) +# define RTMemAllocZVarTag(cbUnaligned, pszTag) RTMemEfAllocZVar((cbUnaligned), (pszTag), RT_SRC_POS) +# define RTMemReallocTag(pvOld, cbNew, pszTag) RTMemEfRealloc((pvOld), (cbNew), (pszTag), RT_SRC_POS) +# define RTMemReallocZTag(pvOld, cbOld, cbNew, pszTag) RTMemEfReallocZ((pvOld), (cbOld), (cbNew), (pszTag), RT_SRC_POS) +# define RTMemFree(pv) RTMemEfFree((pv), RT_SRC_POS) +# define RTMemFreeZ(pv, cb) RTMemEfFreeZ((pv), (cb), RT_SRC_POS) +# define RTMemDupTag(pvSrc, cb, pszTag) RTMemEfDup((pvSrc), (cb), (pszTag), RT_SRC_POS) +# define RTMemDupExTag(pvSrc, cbSrc, cbExtra, pszTag) RTMemEfDupEx((pvSrc), (cbSrc), (cbExtra), (pszTag), RT_SRC_POS) +#endif +#ifdef DOXYGEN_RUNNING +# define RTMEM_WRAP_TO_EF_APIS +#endif + +/** + * Fenced drop-in replacement for RTMemTmpAllocTag. + * @copydoc RTMemTmpAllocTag + */ +RTDECL(void *) RTMemEfTmpAllocNP(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemTmpAllocZTag. + * @copydoc RTMemTmpAllocZTag + */ +RTDECL(void *) RTMemEfTmpAllocZNP(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemTmpFree. + * @copydoc RTMemTmpFree + */ +RTDECL(void) RTMemEfTmpFreeNP(void *pv) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemTmpFreeZ. + * @copydoc RTMemTmpFreeZ + */ +RTDECL(void) RTMemEfTmpFreeZNP(void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemAllocTag. + * @copydoc RTMemAllocTag + */ +RTDECL(void *) RTMemEfAllocNP(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemAllocZTag. + * @copydoc RTMemAllocZTag + */ +RTDECL(void *) RTMemEfAllocZNP(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemAllocVarTag + * @copydoc RTMemAllocVarTag + */ +RTDECL(void *) RTMemEfAllocVarNP(size_t cbUnaligned, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemAllocZVarTag. + * @copydoc RTMemAllocZVarTag + */ +RTDECL(void *) RTMemEfAllocZVarNP(size_t cbUnaligned, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemReallocTag. + * @copydoc RTMemReallocTag + */ +RTDECL(void *) RTMemEfReallocNP(void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemReallocZTag. + * @copydoc RTMemReallocZTag + */ +RTDECL(void *) RTMemEfReallocZNP(void *pvOld, size_t cbOld, size_t cbNew, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemFree. + * @copydoc RTMemFree + */ +RTDECL(void) RTMemEfFreeNP(void *pv) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemFreeZ. + * @copydoc RTMemFreeZ + */ +RTDECL(void) RTMemEfFreeZNP(void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemDupExTag. + * @copydoc RTMemDupTag + */ +RTDECL(void *) RTMemEfDupNP(const void *pvSrc, size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Fenced drop-in replacement for RTMemDupExTag. + * @copydoc RTMemDupExTag + */ +RTDECL(void *) RTMemEfDupExNP(const void *pvSrc, size_t cbSrc, size_t cbExtra, const char *pszTag) RT_NO_THROW_PROTO; + +/** @} */ + +RT_C_DECLS_END + +/** @} */ + + +#endif /* !IPRT_INCLUDED_mem_h */ + diff --git a/include/iprt/memcache.h b/include/iprt/memcache.h new file mode 100644 index 00000000..365ff61e --- /dev/null +++ b/include/iprt/memcache.h @@ -0,0 +1,170 @@ +/** @file + * IPRT - Memory Object Allocation Cache. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_memcache_h +#define IPRT_INCLUDED_memcache_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_rt_memcache RTMemCache - Memory Object Allocation Cache + * @ingroup grp_rt + * + * Optimized allocation, initialization, freeing and destruction of memory + * objects of the same kind and size. Objects are constructed once, then + * allocated and freed one or more times, until finally destructed together with + * the cache (RTMemCacheDestroy). It's expected behavior, even when pfnCtor is + * NULL, that the user will be store information that should be persistent + * across RTMemCacheFree calls. + * + * The objects are zeroed prior to calling pfnCtor. For obvious reasons, the + * objects are not touched by the cache after that, so that RTMemCacheAlloc will + * return the object in the same state as when it as handed to RTMemCacheFree. + * + * @todo A callback for the reuse (at alloc time) might be of interest. + * + * @{ + */ + +/** A memory cache handle. */ +typedef R3R0PTRTYPE(struct RTMEMCACHEINT *) RTMEMCACHE; +/** Pointer to a memory cache handle. */ +typedef RTMEMCACHE *PRTMEMCACHE; +/** Nil memory cache handle. */ +#define NIL_RTMEMCACHE ((RTMEMCACHE)0) + + +/** + * Object constructor. + * + * This is called for when an element is allocated for the first time. + * + * @returns IPRT status code. + * @param hMemCache The cache handle. + * @param pvObj The memory object that should be initialized. + * @param pvUser The user argument. + * + * @remarks No serialization is performed. + */ +typedef DECLCALLBACKTYPE(int, FNMEMCACHECTOR,(RTMEMCACHE hMemCache, void *pvObj, void *pvUser)); +/** Pointer to an object constructor for the memory cache. */ +typedef FNMEMCACHECTOR *PFNMEMCACHECTOR; + +/** + * Object destructor. + * + * This is called when we're shrinking or destroying the cache. + * + * @param hMemCache The cache handle. + * @param pvObj The memory object that should be initialized. + * @param pvUser The user argument. + * + * @remarks No serialization is performed. + */ +typedef DECLCALLBACKTYPE(void, FNMEMCACHEDTOR,(RTMEMCACHE hMemCache, void *pvObj, void *pvUser)); +/** Pointer to an object destructor for the memory cache. */ +typedef FNMEMCACHEDTOR *PFNMEMCACHEDTOR; + + +/** + * Create an allocation cache for fixed size memory objects. + * + * @returns IPRT status code. + * @param phMemCache Where to return the cache handle. + * @param cbObject The size of one memory object. + * @param cbAlignment The object alignment. This must be a power of + * two. The higest alignment is 64. If set to 0, + * a sensible alignment value will be derived from + * the object size. + * @param cMaxObjects The maximum cache size. Pass UINT32_MAX if unsure. + * @param pfnCtor Object constructor callback. Optional. + * @param pfnDtor Object destructor callback. Optional. + * @param pvUser User argument for the two callbacks. + * @param fFlags Flags reserved for future use. Must be zero. + */ +RTDECL(int) RTMemCacheCreate(PRTMEMCACHE phMemCache, size_t cbObject, size_t cbAlignment, uint32_t cMaxObjects, + PFNMEMCACHECTOR pfnCtor, PFNMEMCACHEDTOR pfnDtor, void *pvUser, uint32_t fFlags); + +/** + * Destroy a cache destroying and freeing allocated memory. + * + * @returns IPRT status code. + * @param hMemCache The cache handle. NIL is quietly (VINF_SUCCESS) + * ignored. + */ +RTDECL(int) RTMemCacheDestroy(RTMEMCACHE hMemCache); + +/** + * Allocate an object. + * + * @returns Pointer to the allocated cache object. + * @param hMemCache The cache handle. + */ +RTDECL(void *) RTMemCacheAlloc(RTMEMCACHE hMemCache); + +/** + * Allocate an object and return a proper status code. + * + * @returns IPRT status code. + * @retval VERR_MEM_CACHE_MAX_SIZE if we've reached maximum size (see + * RTMemCacheCreate). + * @retval VERR_NO_MEMORY if we failed to allocate more memory for the cache. + * + * @param hMemCache The cache handle. + * @param ppvObj Where to return the object. + */ +RTDECL(int) RTMemCacheAllocEx(RTMEMCACHE hMemCache, void **ppvObj); + +/** + * Free an object previously returned by RTMemCacheAlloc or RTMemCacheAllocEx. + * + * @param hMemCache The cache handle. + * @param pvObj The object to free. NULL is fine. + */ +RTDECL(void) RTMemCacheFree(RTMEMCACHE hMemCache, void *pvObj); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_memcache_h */ + diff --git a/include/iprt/memobj.h b/include/iprt/memobj.h new file mode 100644 index 00000000..e68ea046 --- /dev/null +++ b/include/iprt/memobj.h @@ -0,0 +1,795 @@ +/** @file + * IPRT - Memory Objects (Ring-0). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_memobj_h +#define IPRT_INCLUDED_memobj_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_memobj RTMemObj - Memory Object Manipulation (Ring-0) + * @ingroup grp_rt + * @{ + */ + +/** @def RTMEM_TAG + * The default allocation tag used by the RTMem allocation APIs. + * + * When not defined before the inclusion of iprt/memobj.h or iprt/mem.h, this + * will default to the pointer to the current file name. The memory API will + * make of use of this as pointer to a volatile but read-only string. + */ +#ifndef RTMEM_TAG +# define RTMEM_TAG (__FILE__) +#endif + +#ifdef IN_RING0 + +/** + * Checks if this is mapping or not. + * + * @returns true if it's a mapping, otherwise false. + * @param MemObj The ring-0 memory object handle. + */ +RTR0DECL(bool) RTR0MemObjIsMapping(RTR0MEMOBJ MemObj); + +/** + * Gets the address of a ring-0 memory object. + * + * @returns The address of the memory object. + * @returns NULL if the handle is invalid (asserts in strict builds) or if there isn't any mapping. + * @param MemObj The ring-0 memory object handle. + */ +RTR0DECL(void *) RTR0MemObjAddress(RTR0MEMOBJ MemObj); + +/** + * Gets the ring-3 address of a ring-0 memory object. + * + * This only applies to ring-0 memory object with ring-3 mappings of some kind, i.e. + * locked user memory, reserved user address space and user mappings. This API should + * not be used on any other objects. + * + * @returns The address of the memory object. + * @returns NIL_RTR3PTR if the handle is invalid or if it's not an object with a ring-3 mapping. + * Strict builds will assert in both cases. + * @param MemObj The ring-0 memory object handle. + */ +RTR0DECL(RTR3PTR) RTR0MemObjAddressR3(RTR0MEMOBJ MemObj); + +/** + * Gets the size of a ring-0 memory object. + * + * The returned value may differ from the one specified to the API creating the + * object because of alignment adjustments. The minimal alignment currently + * employed by any API is PAGE_SIZE, so the result can safely be shifted by + * PAGE_SHIFT to calculate a page count. + * + * @returns The object size. + * @returns 0 if the handle is invalid (asserts in strict builds) or if there isn't any mapping. + * @param MemObj The ring-0 memory object handle. + */ +RTR0DECL(size_t) RTR0MemObjSize(RTR0MEMOBJ MemObj); + +/** + * Get the physical address of an page in the memory object. + * + * @returns The physical address. + * @returns NIL_RTHCPHYS if the object doesn't contain fixed physical pages. + * @returns NIL_RTHCPHYS if the iPage is out of range. + * @returns NIL_RTHCPHYS if the object handle isn't valid. + * @param MemObj The ring-0 memory object handle. + * @param iPage The page number within the object. + */ +RTR0DECL(RTHCPHYS) RTR0MemObjGetPagePhysAddr(RTR0MEMOBJ MemObj, size_t iPage); + +/** + * Checks whether the allocation was zero initialized or not. + * + * This only works on allocations. It is not meaningful for mappings, reserved + * memory and entered physical address, and will return false for these. + * + * @returns true if the allocation was initialized to zero at allocation time, + * false if not or query not meaningful to the object type. + * @param hMemObj The ring-0 memory object to be freed. + * + * @remarks It can be expected that memory allocated in the same fashion will + * have the same initialization state. So, if this returns true for + * one allocation it will return true for all other similarly made + * allocations. + */ +RTR0DECL(bool) RTR0MemObjWasZeroInitialized(RTR0MEMOBJ hMemObj); + +/** + * Frees a ring-0 memory object. + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if + * @param MemObj The ring-0 memory object to be freed. NULL is accepted. + * @param fFreeMappings Whether or not to free mappings of the object. + */ +RTR0DECL(int) RTR0MemObjFree(RTR0MEMOBJ MemObj, bool fFreeMappings); + +/** + * Allocates page aligned virtual kernel memory (default tag). + * + * The memory is taken from a non paged (= fixed physical memory backing) pool. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param fExecutable Flag indicating whether it should be permitted to + * executed code in the memory object. The user must + * use RTR0MemObjProtect after initialization the + * allocation to actually make it executable. + */ +#define RTR0MemObjAllocPage(pMemObj, cb, fExecutable) \ + RTR0MemObjAllocPageTag((pMemObj), (cb), (fExecutable), RTMEM_TAG) + +/** + * Allocates page aligned virtual kernel memory (custom tag). + * + * The memory is taken from a non paged (= fixed physical memory backing) pool. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param fExecutable Flag indicating whether it should be permitted to + * executed code in the memory object. The user must + * use RTR0MemObjProtect after initialization the + * allocation to actually make it executable. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjAllocPageTag(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable, const char *pszTag); + +/** + * Allocates large page aligned virtual kernel memory (default tag). + * + * Each large page in the allocation is backed by a contiguous chunk of physical + * memory aligned to the page size. The memory is taken from a non paged (= + * fixed physical memory backing) pool. + * + * On some hosts we only support allocating a single large page at a time, they + * will return VERR_NOT_SUPPORTED if @a cb is larger than @a cbLargePage. + * + * @returns IPRT status code. + * @retval VERR_TRY_AGAIN instead of VERR_NO_MEMORY when + * RTMEMOBJ_ALLOC_LARGE_F_FAST is set and supported. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to + * nearest large page. + * @param cbLargePage The large page size. The allowed values varies from + * architecture to architecture and the paging mode + * used by the OS. + * @param fFlags Flags, RTMEMOBJ_ALLOC_LARGE_F_XXX. + * + * @note The implicit kernel mapping of this allocation does not necessarily + * have to be aligned on a @a cbLargePage boundrary. + */ +#define RTR0MemObjAllocLarge(pMemObj, cb, cbLargePage, fFlags) \ + RTR0MemObjAllocLargeTag((pMemObj), (cb), (cbLargePage), (fFlags), RTMEM_TAG) + +/** + * Allocates large page aligned virtual kernel memory (custom tag). + * + * Each large page in the allocation is backed by a contiguous chunk of physical + * memory aligned to the page size. The memory is taken from a non paged (= + * fixed physical memory backing) pool. + * + * On some hosts we only support allocating a single large page at a time, they + * will return VERR_NOT_SUPPORTED if @a cb is larger than @a cbLargePage. + * + * @returns IPRT status code. + * @retval VERR_TRY_AGAIN instead of VERR_NO_MEMORY when + * RTMEMOBJ_ALLOC_LARGE_F_FAST is set and supported. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to + * nearest large page. + * @param cbLargePage The large page size. The allowed values varies from + * architecture to architecture and the paging mode + * used by the OS. + * @param fFlags Flags, RTMEMOBJ_ALLOC_LARGE_F_XXX. + * @param pszTag Allocation tag used for statistics and such. + * + * @note The implicit kernel mapping of this allocation does not necessarily + * have to be aligned on a @a cbLargePage boundrary. + */ +RTR0DECL(int) RTR0MemObjAllocLargeTag(PRTR0MEMOBJ pMemObj, size_t cb, size_t cbLargePage, uint32_t fFlags, const char *pszTag); + +/** @name RTMEMOBJ_ALLOC_LARGE_F_XXX + * @{ */ +/** Indicates that it is okay to fail if there aren't enough large pages handy, + * cancelling any expensive search and reshuffling of memory (when supported). + * @note This flag can't be realized on all OSes. (Those who do support it + * will return VERR_TRY_AGAIN instead of VERR_NO_MEMORY if they + * cannot satisfy the request.) */ +#define RTMEMOBJ_ALLOC_LARGE_F_FAST RT_BIT_32(0) +/** Mask with valid bits. */ +#define RTMEMOBJ_ALLOC_LARGE_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Allocates page aligned virtual kernel memory with physical backing below 4GB + * (default tag). + * + * The physical memory backing the allocation is fixed. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param fExecutable Flag indicating whether it should be permitted to + * executed code in the memory object. The user must + * use RTR0MemObjProtect after initialization the + * allocation to actually make it executable. + */ +#define RTR0MemObjAllocLow(pMemObj, cb, fExecutable) \ + RTR0MemObjAllocLowTag((pMemObj), (cb), (fExecutable), RTMEM_TAG) + +/** + * Allocates page aligned virtual kernel memory with physical backing below 4GB + * (custom tag). + * + * The physical memory backing the allocation is fixed. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param fExecutable Flag indicating whether it should be permitted to + * executed code in the memory object. The user must + * use RTR0MemObjProtect after initialization the + * allocation to actually make it executable. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjAllocLowTag(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable, const char *pszTag); + +/** + * Allocates page aligned virtual kernel memory with contiguous physical backing + * below 4GB (default tag). + * + * The physical memory backing the allocation is fixed. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param fExecutable Flag indicating whether it should be permitted to + * executed code in the memory object. The user must + * use RTR0MemObjProtect after initialization the + * allocation to actually make it executable. + */ +#define RTR0MemObjAllocCont(pMemObj, cb, fExecutable) \ + RTR0MemObjAllocContTag((pMemObj), (cb), (fExecutable), RTMEM_TAG) + +/** + * Allocates page aligned virtual kernel memory with contiguous physical backing + * below 4GB (custom tag). + * + * The physical memory backing the allocation is fixed. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param fExecutable Flag indicating whether it should be permitted to + * executed code in the memory object. The user must + * use RTR0MemObjProtect after initialization the + * allocation to actually make it executable. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjAllocContTag(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable, const char *pszTag); + +/** + * Locks a range of user virtual memory (default tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param R3Ptr User virtual address. This is rounded down to a page + * boundary. + * @param cb Number of bytes to lock. This is rounded up to + * nearest page boundary. + * @param fAccess The desired access, a combination of RTMEM_PROT_READ + * and RTMEM_PROT_WRITE. + * @param R0Process The process to lock pages in. NIL_RTR0PROCESS is an + * alias for the current one. + * + * @remarks RTR0MemGetAddressR3() and RTR0MemGetAddress() will return therounded + * down address. + * + * @remarks Linux: This API requires that the memory begin locked is in a memory + * mapping that is not required in any forked off child process. This + * is not intented as permanent restriction, feel free to help out + * lifting it. + */ +#define RTR0MemObjLockUser(pMemObj, R3Ptr, cb, fAccess, R0Process) \ + RTR0MemObjLockUserTag((pMemObj), (R3Ptr), (cb), (fAccess), (R0Process), RTMEM_TAG) + +/** + * Locks a range of user virtual memory (custom tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param R3Ptr User virtual address. This is rounded down to a page + * boundary. + * @param cb Number of bytes to lock. This is rounded up to + * nearest page boundary. + * @param fAccess The desired access, a combination of RTMEM_PROT_READ + * and RTMEM_PROT_WRITE. + * @param R0Process The process to lock pages in. NIL_RTR0PROCESS is an + * alias for the current one. + * @param pszTag Allocation tag used for statistics and such. + * + * @remarks RTR0MemGetAddressR3() and RTR0MemGetAddress() will return therounded + * down address. + * + * @remarks Linux: This API requires that the memory begin locked is in a memory + * mapping that is not required in any forked off child process. This + * is not intented as permanent restriction, feel free to help out + * lifting it. + */ +RTR0DECL(int) RTR0MemObjLockUserTag(PRTR0MEMOBJ pMemObj, RTR3PTR R3Ptr, size_t cb, uint32_t fAccess, + RTR0PROCESS R0Process, const char *pszTag); + +/** + * Locks a range of kernel virtual memory (default tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param pv Kernel virtual address. This is rounded down to a page boundary. + * @param cb Number of bytes to lock. This is rounded up to nearest page boundary. + * @param fAccess The desired access, a combination of RTMEM_PROT_READ + * and RTMEM_PROT_WRITE. + * + * @remark RTR0MemGetAddress() will return the rounded down address. + */ +#define RTR0MemObjLockKernel(pMemObj, pv, cb, fAccess) \ + RTR0MemObjLockKernelTag((pMemObj), (pv), (cb), (fAccess), RTMEM_TAG) + +/** + * Locks a range of kernel virtual memory (custom tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param pv Kernel virtual address. This is rounded down to a page boundary. + * @param cb Number of bytes to lock. This is rounded up to nearest page boundary. + * @param fAccess The desired access, a combination of RTMEM_PROT_READ + * and RTMEM_PROT_WRITE. + * @param pszTag Allocation tag used for statistics and such. + * + * @remark RTR0MemGetAddress() will return the rounded down address. + */ +RTR0DECL(int) RTR0MemObjLockKernelTag(PRTR0MEMOBJ pMemObj, void *pv, size_t cb, uint32_t fAccess, const char *pszTag); + +/** + * Allocates contiguous page aligned physical memory without (necessarily) any + * kernel mapping (default tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param PhysHighest The highest permitable address (inclusive). + * Pass NIL_RTHCPHYS if any address is acceptable. + */ +#define RTR0MemObjAllocPhys(pMemObj, cb, PhysHighest) \ + RTR0MemObjAllocPhysTag((pMemObj), (cb), (PhysHighest), RTMEM_TAG) + +/** + * Allocates contiguous page aligned physical memory without (necessarily) any + * kernel mapping (custom tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param PhysHighest The highest permitable address (inclusive). + * Pass NIL_RTHCPHYS if any address is acceptable. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjAllocPhysTag(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest, const char *pszTag); + +/** + * Allocates contiguous physical memory without (necessarily) any kernel mapping + * (default tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param PhysHighest The highest permitable address (inclusive). + * Pass NIL_RTHCPHYS if any address is acceptable. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M, _4M and _1G. + */ +#define RTR0MemObjAllocPhysEx(pMemObj, cb, PhysHighest, uAlignment) \ + RTR0MemObjAllocPhysExTag((pMemObj), (cb), (PhysHighest), (uAlignment), RTMEM_TAG) + +/** + * Allocates contiguous physical memory without (necessarily) any kernel mapping + * (custom tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param PhysHighest The highest permitable address (inclusive). + * Pass NIL_RTHCPHYS if any address is acceptable. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M, _4M and _1G. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjAllocPhysExTag(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest, size_t uAlignment, const char *pszTag); + +/** + * Allocates non-contiguous page aligned physical memory without (necessarily) + * any kernel mapping (default tag). + * + * This API is for allocating huge amounts of pages and will return + * VERR_NOT_SUPPORTED if this cannot be implemented in a satisfactory + * manner. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if it's not possible to allocated unmapped + * physical memory on this platform. The caller should expect + * this error and have a fallback strategy for it. + * + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param PhysHighest The highest permitable address (inclusive). + * Pass NIL_RTHCPHYS if any address is acceptable. + */ +#define RTR0MemObjAllocPhysNC(pMemObj, cb, PhysHighest) \ + RTR0MemObjAllocPhysNCTag((pMemObj), (cb), (PhysHighest), RTMEM_TAG) + +/** + * Allocates non-contiguous page aligned physical memory without (necessarily) + * any kernel mapping (custom tag). + * + * This API is for allocating huge amounts of pages and will return + * VERR_NOT_SUPPORTED if this cannot be implemented in a satisfactory + * manner. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if it's not possible to allocated unmapped + * physical memory on this platform. The caller should expect + * this error and have a fallback strategy for it. + * + * @param pMemObj Where to store the ring-0 memory object handle. + * @param cb Number of bytes to allocate. This is rounded up to nearest page. + * @param PhysHighest The highest permitable address (inclusive). + * Pass NIL_RTHCPHYS if any address is acceptable. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjAllocPhysNCTag(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest, const char *pszTag); + +/** Memory cache policy for RTR0MemObjEnterPhys. + * @{ + */ +/** Default caching policy -- don't care. */ +#define RTMEM_CACHE_POLICY_DONT_CARE UINT32_C(0) +/** MMIO caching policy -- uncachable. */ +#define RTMEM_CACHE_POLICY_MMIO UINT32_C(1) +/** @} */ + +/** + * Creates a page aligned, contiguous, physical memory object (default tag). + * + * No physical memory is allocated, we trust you do know what you're doing. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param Phys The physical address to start at. This is rounded down to the + * nearest page boundary. + * @param cb The size of the object in bytes. This is rounded up to nearest page boundary. + * @param uCachePolicy One of the RTMEM_CACHE_XXX modes. + */ +#define RTR0MemObjEnterPhys(pMemObj, Phys, cb, uCachePolicy) \ + RTR0MemObjEnterPhysTag((pMemObj), (Phys), (cb), (uCachePolicy), RTMEM_TAG) + +/** + * Creates a page aligned, contiguous, physical memory object (custom tag). + * + * No physical memory is allocated, we trust you do know what you're doing. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param Phys The physical address to start at. This is rounded down to the + * nearest page boundary. + * @param cb The size of the object in bytes. This is rounded up to nearest page boundary. + * @param uCachePolicy One of the RTMEM_CACHE_XXX modes. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjEnterPhysTag(PRTR0MEMOBJ pMemObj, RTHCPHYS Phys, size_t cb, uint32_t uCachePolicy, const char *pszTag); + +/** + * Reserves kernel virtual address space (default tag). + * + * If this function fails with VERR_NOT_SUPPORTED, the idea is that you + * can use RTR0MemObjEnterPhys() + RTR0MemObjMapKernel() as a fallback if + * you have a safe physical address range to make use of... + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param pvFixed Requested address. (void *)-1 means any address. This must match the alignment. + * @param cb The number of bytes to reserve. This is rounded up to nearest page. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + */ +#define RTR0MemObjReserveKernel(pMemObj, pvFixed, cb, uAlignment) \ + RTR0MemObjReserveKernelTag((pMemObj), (pvFixed), (cb), (uAlignment), RTMEM_TAG) + +/** + * Reserves kernel virtual address space (custom tag). + * + * If this function fails with VERR_NOT_SUPPORTED, the idea is that you + * can use RTR0MemObjEnterPhys() + RTR0MemObjMapKernel() as a fallback if + * you have a safe physical address range to make use of... + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param pvFixed Requested address. (void *)-1 means any address. This must match the alignment. + * @param cb The number of bytes to reserve. This is rounded up to nearest page. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjReserveKernelTag(PRTR0MEMOBJ pMemObj, void *pvFixed, size_t cb, size_t uAlignment, const char *pszTag); + +/** + * Reserves user virtual address space in the current process (default tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param R3PtrFixed Requested address. (RTR3PTR)-1 means any address. This must match the alignment. + * @param cb The number of bytes to reserve. This is rounded up to nearest PAGE_SIZE. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param R0Process The process to reserve the memory in. + * NIL_RTR0PROCESS is an alias for the current one. + */ +#define RTR0MemObjReserveUser(pMemObj, R3PtrFixed, cb, uAlignment, R0Process) \ + RTR0MemObjReserveUserTag((pMemObj), (R3PtrFixed), (cb), (uAlignment), (R0Process), RTMEM_TAG) + +/** + * Reserves user virtual address space in the current process (custom tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle. + * @param R3PtrFixed Requested address. (RTR3PTR)-1 means any address. This must match the alignment. + * @param cb The number of bytes to reserve. This is rounded up to nearest PAGE_SIZE. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param R0Process The process to reserve the memory in. + * NIL_RTR0PROCESS is an alias for the current one. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjReserveUserTag(PRTR0MEMOBJ pMemObj, RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment, + RTR0PROCESS R0Process, const char *pszTag); + +/** + * Maps a memory object into kernel virtual address space (default tag). + * + * This is the same as calling RTR0MemObjMapKernelEx with cbSub and offSub set + * to zero. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle of the mapping object. + * @param MemObjToMap The object to be map. + * @param pvFixed Requested address. (void *)-1 means any address. This must match the alignment. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE). + */ +#define RTR0MemObjMapKernel(pMemObj, MemObjToMap, pvFixed, uAlignment, fProt) \ + RTR0MemObjMapKernelTag((pMemObj), (MemObjToMap), (pvFixed), (uAlignment), (fProt), RTMEM_TAG) + +/** + * Maps a memory object into kernel virtual address space (custom tag). + * + * This is the same as calling RTR0MemObjMapKernelEx with cbSub and offSub set + * to zero. + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle of the mapping object. + * @param MemObjToMap The object to be map. + * @param pvFixed Requested address. (void *)-1 means any address. This must match the alignment. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE). + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjMapKernelTag(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, void *pvFixed, + size_t uAlignment, unsigned fProt, const char *pszTag); + +/** + * Maps a memory object into kernel virtual address space (default tag). + * + * The ability to map subsections of the object into kernel space is currently + * not implemented on all platforms. All/Most of platforms supports mapping the + * whole object into kernel space. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if it's not possible to map a subsection of a + * memory object on this platform. When you hit this, try implement it. + * + * @param pMemObj Where to store the ring-0 memory object handle of the mapping object. + * @param MemObjToMap The object to be map. + * @param pvFixed Requested address. (void *)-1 means any address. This must match the alignment. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE). + * @param offSub Where in the object to start mapping. If non-zero + * the value must be page aligned and cbSub must be + * non-zero as well. + * @param cbSub The size of the part of the object to be mapped. If + * zero the entire object is mapped. The value must be + * page aligned. + */ +#define RTR0MemObjMapKernelEx(pMemObj, MemObjToMap, pvFixed, uAlignment, fProt, offSub, cbSub) \ + RTR0MemObjMapKernelExTag((pMemObj), (MemObjToMap), (pvFixed), (uAlignment), (fProt), (offSub), (cbSub), RTMEM_TAG) + +/** + * Maps a memory object into kernel virtual address space (custom tag). + * + * The ability to map subsections of the object into kernel space is currently + * not implemented on all platforms. All/Most of platforms supports mapping the + * whole object into kernel space. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if it's not possible to map a subsection of a + * memory object on this platform. When you hit this, try implement it. + * + * @param pMemObj Where to store the ring-0 memory object handle of the mapping object. + * @param MemObjToMap The object to be map. + * @param pvFixed Requested address. (void *)-1 means any address. This must match the alignment. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE). + * @param offSub Where in the object to start mapping. If non-zero + * the value must be page aligned and cbSub must be + * non-zero as well. + * @param cbSub The size of the part of the object to be mapped. If + * zero the entire object is mapped. The value must be + * page aligned. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjMapKernelExTag(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, void *pvFixed, size_t uAlignment, + unsigned fProt, size_t offSub, size_t cbSub, const char *pszTag); + +/** + * Maps a memory object into user virtual address space in the current process + * (default tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle of the mapping object. + * @param MemObjToMap The object to be map. + * @param R3PtrFixed Requested address. (RTR3PTR)-1 means any address. This must match the alignment. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE). + * @param R0Process The process to map the memory into. NIL_RTR0PROCESS + * is an alias for the current one. + */ +#define RTR0MemObjMapUser(pMemObj, MemObjToMap, R3PtrFixed, uAlignment, fProt, R0Process) \ + RTR0MemObjMapUserTag((pMemObj), (MemObjToMap), (R3PtrFixed), (uAlignment), (fProt), (R0Process), RTMEM_TAG) + +/** + * Maps a memory object into user virtual address space in the current process + * (custom tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle of the mapping object. + * @param MemObjToMap The object to be map. + * @param R3PtrFixed Requested address. (RTR3PTR)-1 means any address. This must match the alignment. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE). + * @param R0Process The process to map the memory into. NIL_RTR0PROCESS + * is an alias for the current one. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjMapUserTag(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, RTR3PTR R3PtrFixed, + size_t uAlignment, unsigned fProt, RTR0PROCESS R0Process, const char *pszTag); + +/** + * Maps a memory object into user virtual address space in the current process + * (default tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle of the mapping object. + * @param MemObjToMap The object to be map. + * @param R3PtrFixed Requested address. (RTR3PTR)-1 means any address. This must match the alignment. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE). + * @param R0Process The process to map the memory into. NIL_RTR0PROCESS + * is an alias for the current one. + * @param offSub Where in the object to start mapping. If non-zero + * the value must be page aligned and cbSub must be + * non-zero as well. + * @param cbSub The size of the part of the object to be mapped. If + * zero the entire object is mapped. The value must be + * page aligned. + */ +#define RTR0MemObjMapUserEx(pMemObj, MemObjToMap, R3PtrFixed, uAlignment, fProt, R0Process, offSub, cbSub) \ + RTR0MemObjMapUserExTag((pMemObj), (MemObjToMap), (R3PtrFixed), (uAlignment), (fProt), (R0Process), \ + (offSub), (cbSub), RTMEM_TAG) + +/** + * Maps a memory object into user virtual address space in the current process + * (custom tag). + * + * @returns IPRT status code. + * @param pMemObj Where to store the ring-0 memory object handle of the mapping object. + * @param MemObjToMap The object to be map. + * @param R3PtrFixed Requested address. (RTR3PTR)-1 means any address. This must match the alignment. + * @param uAlignment The alignment of the reserved memory. + * Supported values are 0 (alias for PAGE_SIZE), PAGE_SIZE, _2M and _4M. + * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE). + * @param R0Process The process to map the memory into. NIL_RTR0PROCESS + * is an alias for the current one. + * @param offSub Where in the object to start mapping. If non-zero + * the value must be page aligned and cbSub must be + * non-zero as well. + * @param cbSub The size of the part of the object to be mapped. If + * zero the entire object is mapped. The value must be + * page aligned. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR0DECL(int) RTR0MemObjMapUserExTag(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, RTR3PTR R3PtrFixed, size_t uAlignment, + unsigned fProt, RTR0PROCESS R0Process, size_t offSub, size_t cbSub, const char *pszTag); + +/** + * Change the page level protection of one or more pages in a memory object. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the OS doesn't provide any way to manipulate + * page level protection. The caller must handle this status code + * gracefully. (Note that it may also occur if the implementation is + * missing, in which case just go ahead and implement it.) + * + * @param hMemObj Memory object handle. + * @param offSub Offset into the memory object. Must be page aligned. + * @param cbSub Number of bytes to change the protection of. Must be + * page aligned. + * @param fProt Combination of RTMEM_PROT_* flags. + */ +RTR0DECL(int) RTR0MemObjProtect(RTR0MEMOBJ hMemObj, size_t offSub, size_t cbSub, uint32_t fProt); + +#endif /* IN_RING0 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_memobj_h */ + diff --git a/include/iprt/mempool.h b/include/iprt/mempool.h new file mode 100644 index 00000000..2073a6dd --- /dev/null +++ b/include/iprt/mempool.h @@ -0,0 +1,178 @@ +/** @file + * IPRT - Memory Allocation Pool. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_mempool_h +#define IPRT_INCLUDED_mempool_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** + * Creates a new memory pool. + * + * @returns IPRT status code. + * + * @param phMemPool Where to return the handle to the new memory + * pool. + * @param pszName The name of the pool (for debug purposes). + */ +RTDECL(int) RTMemPoolCreate(PRTMEMPOOL phMemPool, const char *pszName); + +/** + * Destroys the specified pool, freeing all the memory it contains. + * + * @returns IPRT status code. + * + * @param hMemPool The handle to the pool. The nil handle and + * RTMEMPOOL_DEFAULT are quietly ignored (retval + * VINF_SUCCESS). + */ +RTDECL(int) RTMemPoolDestroy(RTMEMPOOL hMemPool); + +/** + * Allocates memory. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * + * @param hMemPool Handle to the pool to allocate the memory from. + * @param cb Size in bytes of the memory block to allocated. + */ +RTDECL(void *) RTMemPoolAlloc(RTMEMPOOL hMemPool, size_t cb) RT_NO_THROW_PROTO; + +/** + * Allocates zero'd memory. + * + * Instead of memset(pv, 0, sizeof()) use this when you want zero'd + * memory. This keeps the code smaller and the heap can skip the memset + * in about 0.42% of calls :-). + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * + * @param hMemPool Handle to the pool to allocate the memory from. + * @param cb Size in bytes of the memory block to allocated. + */ +RTDECL(void *) RTMemPoolAllocZ(RTMEMPOOL hMemPool, size_t cb) RT_NO_THROW_PROTO; + +/** + * Duplicates a chunk of memory into a new heap block. + * + * @returns New heap block with the duplicate data. + * @returns NULL if we're out of memory. + * + * @param hMemPool Handle to the pool to allocate the memory from. + * @param pvSrc The memory to duplicate. + * @param cb The amount of memory to duplicate. + */ +RTDECL(void *) RTMemPoolDup(RTMEMPOOL hMemPool, const void *pvSrc, size_t cb) RT_NO_THROW_PROTO; + +/** + * Duplicates a chunk of memory into a new heap block with some + * additional zeroed memory. + * + * @returns New heap block with the duplicate data. + * @returns NULL if we're out of memory. + * + * @param hMemPool Handle to the pool to allocate the memory from. + * @param pvSrc The memory to duplicate. + * @param cbSrc The amount of memory to duplicate. + * @param cbExtra The amount of extra memory to allocate and zero. + */ +RTDECL(void *) RTMemPoolDupEx(RTMEMPOOL hMemPool, const void *pvSrc, size_t cbSrc, size_t cbExtra) RT_NO_THROW_PROTO; + +/** + * Reallocates memory. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * + * @param hMemPool Handle to the pool containing the old memory. + * @param pvOld The memory block to reallocate. + * @param cbNew The new block size (in bytes). + */ +RTDECL(void *) RTMemPoolRealloc(RTMEMPOOL hMemPool, void *pvOld, size_t cbNew) RT_NO_THROW_PROTO; + +/** + * Frees memory allocated from a pool. + * + * @param hMemPool Handle to the pool containing the memory. Passing + * NIL here is fine, but it may come at a slight + * performance cost. + * @param pv Pointer to memory block. + * + * @remarks This is the same a RTMemPoolRelease but included here as a separate + * function to simplify code migration. + */ +RTDECL(void) RTMemPoolFree(RTMEMPOOL hMemPool, void *pv) RT_NO_THROW_PROTO; + +/** + * Retains a reference to a memory block in a pool. + * + * @returns New reference count, UINT32_MAX on error (asserted). + * + * @param pv Pointer to memory block. + */ +RTDECL(uint32_t) RTMemPoolRetain(void *pv) RT_NO_THROW_PROTO; + +/** + * Releases a reference to a memory block in a pool. + * + * @returns New reference count, UINT32_MAX on error (asserted). + * + * @param hMemPool Handle to the pool containing the memory. Passing + * NIL here is fine, but it may come at a slight + * performance cost. + * @param pv Pointer to memory block. + */ +RTDECL(uint32_t) RTMemPoolRelease(RTMEMPOOL hMemPool, void *pv) RT_NO_THROW_PROTO; + +/** + * Get the current reference count. + * + * @returns The reference count, UINT32_MAX on error (asserted). + * @param pv Pointer to memory block. + */ +RTDECL(uint32_t) RTMemPoolRefCount(void *pv) RT_NO_THROW_PROTO; + + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_mempool_h */ + diff --git a/include/iprt/memsafer.h b/include/iprt/memsafer.h new file mode 100644 index 00000000..cc9545bf --- /dev/null +++ b/include/iprt/memsafer.h @@ -0,0 +1,270 @@ +/** @file + * IPRT - Memory Allocate for Sensitive Data. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_memsafer_h +#define IPRT_INCLUDED_memsafer_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/mem.h> /* RTMEM_TAG */ + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_rt_memsafer RTMemSafer - Memory Allocator for Sensitive Data + * @ingroup grp_rt + * + * This API doesn't provide 100% secure storage, it only provider more secure + * and safer storage. Thus the API isn't called RTMemSafe because you cannot + * assume the data is safe against all kinds of extraction methods. + * + * The API guarantee that the memory won't be returned to the system containing + * any of the information you put there. It will be repeatedly wiped after use. + * + * The API tries to isolate your data from other information stored in the + * process/system. How well this is done depends on the implementation. The + * more complicated implementations will provide protection against heartbleed + * like bugs where pieces of the heap is copied onto the wire. + * + * The more hardened implementations of the API will also do their best to + * prevent the memory from ending up in process dumps or being readable by + * debuggers. + * + * Finally, two functions are provided for scrambling the sensitive memory while + * it's not in use. + * + * @{ + */ + +/** @name RTMEMSAFER_F_XXX + * @{ */ +/** Require the memory to not hit the page file. + * @remarks Makes not guarantees with regards to hibernation / + * suspend-to-disk. */ +#define RTMEMSAFER_F_REQUIRE_NOT_PAGABLE RT_BIT_32(0) +/** Mask of valid bits. */ +#define RTMEMSAFER_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Scrambles memory allocated by RTMemSaferAllocZEx and associates after use. + * + * Call this when the sensitive data isn't actively being used. It will at a + * minimum make sure the data is slightly scrambled, how hard it is to unbutton + * is dependent on which implementation is used and available host support. + * + * The user must synchronize calls to RTMemSaferScramble and + * RTMemSaferUnscramble, this memory allocator provides no help and keeps no + * state information around. + * + * @returns IPRT status code. + * @param pv The pointer returned by the allocation function. + * @param cb The exact size given to the allocation function. + */ +RTDECL(int) RTMemSaferScramble(void *pv, size_t cb); + +/** + * Unscrambles memory allocated by RTMemSaferAllocZEx and associates before use. + * + * This undoes the effect of RTMemSaferScramble. + * + * @returns IPRT status code. + * @param pv The pointer returned by the allocation function. + * @param cb The exact size given to the allocation function. + */ +RTDECL(int) RTMemSaferUnscramble(void *pv, size_t cb); + +/** + * Allocates memory for sensitive data. + * + * Some effort will be taken to isolate the data from other memory allocation. + * Memory is always zeroed. + * + * @returns IPRT status code. + * @param ppvNew Where to return the pointer to the memory. + * @param cb Number of bytes to allocate. + * @param fFlags Flags for controlling the allocation, see + * RTMEMSAFER_F_XXX. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTMemSaferAllocZExTag(void **ppvNew, size_t cb, uint32_t fFlags, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Allocates memory for sensitive data. + * + * Some effort will be taken to isolate the data from other memory allocation. + * Memory is always zeroed. + * + * @returns IPRT status code. + * @param a_ppvNew Where to return the pointer to the memory. + * @param a_cb Number of bytes to allocate. + * @param a_fFlags Flags for controlling the allocation, see + * RTMEMSAFER_F_XXX. + */ +#define RTMemSaferAllocZEx(a_ppvNew, a_cb, a_fFlags) RTMemSaferAllocZExTag(a_ppvNew, a_cb, a_fFlags, RTMEM_TAG) + +/** + * Allocates memory for sensitive data. + * + * Some effort will be taken to isolate the data from other memory allocation. + * Memory is always zeroed. + * + * @returns Pointer to the allocated memory. + * @param cb Number of bytes to allocate. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemSaferAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Allocates memory for sensitive data. + * + * Some effort will be taken to isolate the data from other memory allocation. + * Memory is always zeroed. + * + * @returns Pointer to the allocated memory. + * @param a_cb Number of bytes to allocate. + */ +#define RTMemSaferAllocZ(a_cb) RTMemSaferAllocZTag(a_cb, RTMEM_TAG) + + +/** + * Reallocates memory allocated by RTMemSaferAllocZEx, RTMemSaferAllocZ, + * RTMemSaferAllocZExTag, or RTMemSaferAllocZTag. + * + * When extending the allocation, the new memory will be zeroed. When shrinking + * the allocation the left over memory will be wiped clean using + * RTMemWipeThorougly. + * + * The function follows the standard realloc behavior. + * + * @returns IPRT status code. + * @param cbOld The current allocation size. + * @param pvOld The current allocation. + * @param cbNew The size of the new allocation. + * @param ppvNew Where to return the pointer to the new memory. + * @param fFlags Flags for controlling the allocation, see + * RTMEMSAFER_F_XXX. It is not permitted to drop saftely + * requirments after the initial allocation. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTMemSaferReallocZExTag(size_t cbOld, void *pvOld, size_t cbNew, void **ppvNew, uint32_t fFlags, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Reallocates memory allocated by RTMemSaferAllocZEx, RTMemSaferAllocZ, + * RTMemSaferAllocZExTag, or RTMemSaferAllocZTag. + * + * When extending the allocation, the new memory will be zeroed. When shrinking + * the allocation the left over memory will be wiped clean using + * RTMemWipeThorougly. + * + * The function follows the standard realloc behavior. + * + * @returns IPRT status code. + * @param a_cbOld The current allocation size. + * @param a_pvOld The current allocation. + * @param a_cbNew The size of the new allocation. + * @param a_ppvNew Where to return the pointer to the new memory. + * @param a_fFlags Flags for controlling the allocation. See RTMEMSAFER_ALLOC_EX_FLAGS_* defines, + * this takes only effect when allocating completely new memory, for extending or + * shrinking existing allocations the flags of the allocation take precedence. + */ +#define RTMemSaferReallocZEx(a_cbOld, a_pvOld, a_cbNew, a_ppvNew, a_fFlags) \ + RTMemSaferReallocZExTag(a_cbOld, a_pvOld, a_cbNew, a_ppvNew, a_fFlags, RTMEM_TAG) + +/** + * Reallocates memory allocated by RTMemSaferAllocZ or RTMemSaferAllocZTag. + * + * When extending the allocation, the new memory will be zeroed. When shrinking + * the allocation the left over memory will be wiped clean using + * RTMemWipeThorougly. + * + * The function follows the standard realloc behavior. + * + * @returns Pointer to the allocated memory. + * @param cbOld The current allocation size. + * @param pvOld The current allocation. + * @param cbNew The size of the new allocation. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(void *) RTMemSaferReallocZTag(size_t cbOld, void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW_PROTO; + +/** + * Reallocates memory allocated by RTMemSaferAllocZ or RTMemSaferAllocZTag. + * + * When extending the allocation, the new memory will be zeroed. When shrinking + * the allocation the left over memory will be wiped clean using + * RTMemWipeThorougly. + * + * The function follows the standard realloc behavior. + * + * @returns Pointer to the allocated memory. + * @param a_cbOld The current allocation size. + * @param a_pvOld The current allocation. + * @param a_cbNew The size of the new allocation. + */ +#define RTMemSaferReallocZ(a_cbOld, a_pvOld, a_cbNew) RTMemSaferReallocZTag(a_cbOld, a_pvOld, a_cbNew, RTMEM_TAG) + + +/** + * Frees memory allocated by RTMemSaferAllocZ* or RTMemSaferReallocZ*. + * + * Before freeing the allocated memory, it will be wiped clean using + * RTMemWipeThorougly. + * + * @returns Pointer to the allocated memory. + * @param pv The allocation. + * @param cb The allocation size. + */ +RTDECL(void) RTMemSaferFree(void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** + * Gets the amount of memory allocated at @a pv. + * + * This can be used to check if the allocation was made using an RTMemSafer API. + * + * @returns Allocation size in bytes, 0 if not a RTMemSafer allocation. + * @param pv The alleged RTMemSafer allocation. + * + * @note Not supported in all contexts and implementations of the API. + */ +RTDECL(size_t) RTMemSaferGetSize(void *pv) RT_NO_THROW_PROTO; + + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_memsafer_h */ + diff --git a/include/iprt/memtracker.h b/include/iprt/memtracker.h new file mode 100644 index 00000000..cd3eff0b --- /dev/null +++ b/include/iprt/memtracker.h @@ -0,0 +1,257 @@ +/** @file + * IPRT - Memory Tracker. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_memtracker_h +#define IPRT_INCLUDED_memtracker_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/list.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_memtracker RTMemTracker - Memory Allocation Tracker. + * @ingroup grp_rt + * @{ + */ + +/** + * The allocation/free method. + */ +typedef enum RTMEMTRACKERMETHOD +{ + RTMEMTRACKERMETHOD_INVALID = 0, + RTMEMTRACKERMETHOD_ALLOC, + RTMEMTRACKERMETHOD_ALLOCZ, + RTMEMTRACKERMETHOD_REALLOC_PREP, /**< Internal, don't use. */ + RTMEMTRACKERMETHOD_REALLOC_DONE, /**< Internal, don't use. */ + RTMEMTRACKERMETHOD_REALLOC_FAILED, /**< Internal, don't use. */ + RTMEMTRACKERMETHOD_FREE, + + RTMEMTRACKERMETHOD_NEW, + RTMEMTRACKERMETHOD_NEW_ARRAY, + RTMEMTRACKERMETHOD_DELETE, + RTMEMTRACKERMETHOD_DELETE_ARRAY, + RTMEMTRACKERMETHOD_END, + RTMEMTRACKERMETHOD_32BIT_HACK = 0x7fffffff +} RTMEMTRACKERMETHOD; + +/** Pointer to a tag structure. */ +typedef struct RTMEMTRACKERTAG *PRTMEMTRACKERTAG; + +/** Pointer to a user structure. */ +typedef struct RTMEMTRACKERUSER *PRTMEMTRACKERUSER; + +/** + * Memory Tracking Header for use with RTMemTrackerHdrAlloc, + * RTMemTrackerHdrReallocPrep, RTMemTrackerHdrReallocDone and + * RTMemTrackerHdrFree. + */ +typedef struct RTMEMTRACKERHDR +{ + /** Magic value / eye catcher (RTMEMTRACKERHDR_MAGIC). */ + size_t uMagic; + /** The allocation size, user data only. */ + size_t cbUser; + /** The list entry. */ + RTLISTNODE ListEntry; + /** Pointer to the user structure where this header is linked. */ + PRTMEMTRACKERUSER pUser; + /** Pointer to the per-tag structure. */ + PRTMEMTRACKERTAG pTag; + /** The tag string. */ + const char *pszTag; + /** The caller address. */ + void *pvCaller; + /** Pointer to the user data we're tracking. */ + void *pvUser; + /** Alignment padding. */ + size_t uReserved; +} RTMEMTRACKERHDR; +/** Pointer to a memory tracker header. */ +typedef RTMEMTRACKERHDR *PRTMEMTRACKERHDR; +/** Pointer to a const memory tracker header. */ +typedef RTMEMTRACKERHDR *PPRTMEMTRACKERHDR; + +/** Magic value for RTMEMTRACKERHDR::uMagic (Kelly Link). */ +#if ARCH_BITS == 64 +# define RTMEMTRACKERHDR_MAGIC UINT64_C(0x1907691919690719) +#else +# define RTMEMTRACKERHDR_MAGIC UINT32_C(0x19690719) +#endif +/** Magic number used when reallocated. */ +#if ARCH_BITS == 64 +# define RTMEMTRACKERHDR_MAGIC_REALLOC UINT64_C(0x0000691919690000) +#else +# define RTMEMTRACKERHDR_MAGIC_REALLOC UINT32_C(0x19690000) +#endif +/** Magic number used when freed. */ +#define RTMEMTRACKERHDR_MAGIC_FREE (~RTMEMTRACKERHDR_MAGIC) + + +/** + * Initializes the allocation header and links it to the relevant tag. + * + * @returns Pointer to the user data part. + * @param pv The header + user data block. This must be at + * least @a cb + sizeof(RTMEMTRACKERHDR). + * @param cbUser The user data size (bytes). + * @param pszTag The tag string. + * @param pvCaller The return address. + * @param enmMethod The method that the user called. + */ +RTDECL(void *) RTMemTrackerHdrAlloc(void *pv, size_t cbUser, const char *pszTag, void *pvCaller, RTMEMTRACKERMETHOD enmMethod); + +/** + * Prepares for a realloc, i.e. invalidates the header. + * + * @returns Pointer to the user data part. + * @param pvOldUser Pointer to the old user data. + * @param cbOldUser The size of the old user data, 0 if not + * known. + * @param pszTag The tag string. + * @param pvCaller The return address. + */ +RTDECL(void *) RTMemTrackerHdrReallocPrep(void *pvOldUser, size_t cbOldUser, const char *pszTag, void *pvCaller); + +/** + * Initializes the allocation header and links it to the relevant tag. + * + * @returns Pointer to the user data part. + * @param pvNew The new header + user data block. This must be + * at least @a cb + sizeof(RTMEMTRACKERHDR). If + * this is NULL, we assume the realloc() call + * failed. + * @param cbNewUser The user data size (bytes). + * @param pvOldUser Pointer to the old user data. This is only + * valid on failure of course and used to bail out + * in that case. Should not be NULL. + * @param pszTag The tag string. + * @param pvCaller The return address. + */ +RTDECL(void *) RTMemTrackerHdrReallocDone(void *pvNew, size_t cbNewUser, void *pvOldUser, const char *pszTag, void *pvCaller); + + +/** + * Do the accounting on free. + * + * @returns @a pv. + * @param pvUser Pointer to the user data. + * @param cbUser The size of the user data, 0 if not known. + * @param pszTag The tag string. + * @param pvCaller The return address. + * @param enmMethod The method that the user called. + */ +RTDECL(void *) RTMemTrackerHdrFree(void *pvUser, size_t cbUser, const char *pszTag, void *pvCaller, RTMEMTRACKERMETHOD enmMethod); + + +/** + * Dumps all the allocations and tag statistics to the log. + */ +RTDECL(void) RTMemTrackerDumpAllToLog(void); + +/** + * Dumps all the allocations and tag statistics to the release log. + */ +RTDECL(void) RTMemTrackerDumpAllToLogRel(void); + +/** + * Dumps all the allocations and tag statistics to standard out. + */ +RTDECL(void) RTMemTrackerDumpAllToStdOut(void); + +/** + * Dumps all the allocations and tag statistics to standard err. + */ +RTDECL(void) RTMemTrackerDumpAllToStdErr(void); + +/** + * Dumps all the allocations and tag statistics to the specified filename. + */ +RTDECL(void) RTMemTrackerDumpAllToFile(const char *pszFilename); + + +/** + * Dumps all the tag statistics to the log. + * + * @param fVerbose Whether to print all the stats or just the ones + * relevant to hunting leaks. + */ +RTDECL(void) RTMemTrackerDumpStatsToLog(bool fVerbose); + +/** + * Dumps all the tag statistics to the release log. + * + * @param fVerbose Whether to print all the stats or just the ones + * relevant to hunting leaks. + */ +RTDECL(void) RTMemTrackerDumpStatsToLogRel(bool fVerbose); + +/** + * Dumps all the tag statistics to standard out. + * + * @param fVerbose Whether to print all the stats or just the ones + * relevant to hunting leaks. + */ +RTDECL(void) RTMemTrackerDumpStatsToStdOut(bool fVerbose); + +/** + * Dumps all the tag statistics to standard err. + * + * @param fVerbose Whether to print all the stats or just the ones + * relevant to hunting leaks. + */ +RTDECL(void) RTMemTrackerDumpStatsToStdErr(bool fVerbose); + +/** + * Dumps all the tag statistics to the specified filename. + * + * @param fVerbose Whether to print all the stats or just the ones + * relevant to hunting leaks. + * @param pszFilename The name of the file to dump to. + */ +RTDECL(void) RTMemTrackerDumpStatsToFile(bool fVerbose, const char *pszFilename); + + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_memtracker_h */ + diff --git a/include/iprt/message.h b/include/iprt/message.h new file mode 100644 index 00000000..b5a912c7 --- /dev/null +++ b/include/iprt/message.h @@ -0,0 +1,394 @@ +/** @file + * IPRT - Message Formatting. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_message_h +#define IPRT_INCLUDED_message_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/stdarg.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_msg RTMsg - Message Formatting + * @ingroup grp_rt + * @{ + */ + +/** + * Sets the program name to use. + * + * @returns IPRT status code. + * @param pszFormat The program name format string. + * @param ... Format arguments. + */ +RTDECL(int) RTMsgSetProgName(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Print error message to standard error. + * + * The message will be prefixed with the file name part of process image name + * (i.e. no path) and "error: ". If the message doesn't end with a new line, + * one will be added. The caller should call this with an empty string if + * unsure whether the cursor is currently position at the start of a new line. + * + * @returns IPRT status code. + * @param pszFormat The message format string. + * @param ... Format arguments. + */ +RTDECL(int) RTMsgError(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Print error message to standard error. + * + * The message will be prefixed with the file name part of process image name + * (i.e. no path) and "error: ". If the message doesn't end with a new line, + * one will be added. The caller should call this with an empty string if + * unsure whether the cursor is currently position at the start of a new line. + * + * @returns IPRT status code. + * @param pszFormat The message format string. + * @param va Format arguments. + */ +RTDECL(int) RTMsgErrorV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Same as RTMsgError() except for the return value. + * + * @returns @a enmExitCode + * @param enmExitCode What to exit code to return. This is mainly for + * saving some vertical space in the source file. + * @param pszFormat The message format string. + * @param ... Format arguments. + */ +RTDECL(RTEXITCODE) RTMsgErrorExit(RTEXITCODE enmExitCode, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Same as RTMsgErrorV() except for the return value. + * + * @returns @a enmExitCode + * @param enmExitCode What to exit code to return. This is mainly for + * saving some vertical space in the source file. + * @param pszFormat The message format string. + * @param va Format arguments. + */ +RTDECL(RTEXITCODE) RTMsgErrorExitV(RTEXITCODE enmExitCode, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Same as RTMsgError() except for always returning RTEXITCODE_FAILURE. + * + * @returns RTEXITCODE_FAILURE + * @param pszFormat The message format string. + * @param ... Format arguments. + */ +RTDECL(RTEXITCODE) RTMsgErrorExitFailure(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Same as RTMsgErrorV() except for always returning RTEXITCODE_FAILURE. + * + * @returns RTEXITCODE_FAILURE + * @param pszFormat The message format string. + * @param va Format arguments. + */ +RTDECL(RTEXITCODE) RTMsgErrorExitFailureV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Same as RTMsgError() except for the return value. + * + * @returns @a rcRet + * @param rcRet What IPRT status to return. This is mainly for + * saving some vertical space in the source file. + * @param pszFormat The message format string. + * @param ... Format arguments. + */ +RTDECL(int) RTMsgErrorRc(int rcRet, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Same as RTMsgErrorV() except for the return value. + * + * @returns @a rcRet + * @param rcRet What IPRT status to return. This is mainly for + * saving some vertical space in the source file. + * @param pszFormat The message format string. + * @param va Format arguments. + */ +RTDECL(int) RTMsgErrorRcV(int rcRet, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * For reporting syntax errors. + * + * @returns RTEXITCODE_SYNTAX + * @param pszFormat The message format string. Newline not needed. + * @param ... Format arguments. + */ +RTDECL(RTEXITCODE) RTMsgSyntax(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * For reporting syntax errors. + * + * @returns RTEXITCODE_SYNTAX + * @param pszFormat The message format string. Newline not needed. + * @param va Format arguments. + */ +RTDECL(RTEXITCODE) RTMsgSyntaxV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Print an error message for a RTR3Init failure and suggest an exit code. + * + * @code + * + * int rc = RTR3Init(); + * if (RT_FAILURE(rc)) + * return RTMsgInitFailure(rc); + * + * @endcode + * + * @returns Appropriate exit code. + * @param rcRTR3Init The status code returned by RTR3Init. + */ +RTDECL(RTEXITCODE) RTMsgInitFailure(int rcRTR3Init); + +/** + * Print informational message to standard error. + * + * The message will be prefixed with the file name part of process image name + * (i.e. no path) and "warning: ". If the message doesn't end with a new line, + * one will be added. The caller should call this with an empty string if + * unsure whether the cursor is currently position at the start of a new line. + * + * @returns IPRT status code. + * @param pszFormat The message format string. + * @param ... Format arguments. + */ +RTDECL(int) RTMsgWarning(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Print informational message to standard error. + * + * The message will be prefixed with the file name part of process image name + * (i.e. no path) and "warning: ". If the message doesn't end with a new line, + * one will be added. The caller should call this with an empty string if + * unsure whether the cursor is currently position at the start of a new line. + * + * @returns IPRT status code. + * @param pszFormat The message format string. + * @param va Format arguments. + */ +RTDECL(int) RTMsgWarningV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Print informational message to standard output. + * + * The message will be prefixed with the file name part of process image name + * (i.e. no path) and "info: ". If the message doesn't end with a new line, + * one will be added. The caller should call this with an empty string if + * unsure whether the cursor is currently position at the start of a new line. + * + * @returns IPRT status code. + * @param pszFormat The message format string. + * @param ... Format arguments. + */ +RTDECL(int) RTMsgInfo(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Print informational message to standard output. + * + * The message will be prefixed with the file name part of process image name + * (i.e. no path) and "info: ". If the message doesn't end with a new line, + * one will be added. The caller should call this with an empty string if + * unsure whether the cursor is currently position at the start of a new line. + * + * @returns IPRT status code. + * @param pszFormat The message format string. + * @param va Format arguments. + */ +RTDECL(int) RTMsgInfoV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + + + +/** @defgroup grp_rt_msg_refentry Help generated from refentry/manpage. + * + * The refentry/manpage docbook source in doc/manual/en_US/man_* is processed by + * doc/manual/docbook-refentry-to-C-help.xsl and turned a set of the structures + * defined here. + * + * @{ + */ + +/** The non-breaking space character. + * @remarks We could've used U+00A0, but it is easier both to encode and to + * search and replace a single ASCII character. */ +#define RTMSGREFENTRY_NBSP '\b' + +/** @name REFENTRYSTR_SCOPE_XXX - Common string scoping and flags. + * @{ */ +/** Same scope as previous string table entry, flags are reset and can be + * ORed in. */ +#define RTMSGREFENTRYSTR_SCOPE_SAME UINT64_C(0) +/** Global scope. */ +#define RTMSGREFENTRYSTR_SCOPE_GLOBAL UINT64_C(0x0fffffffffffffff) +/** Scope mask. */ +#define RTMSGREFENTRYSTR_SCOPE_MASK UINT64_C(0x0fffffffffffffff) +/** Flags mask. */ +#define RTMSGREFENTRYSTR_FLAGS_MASK UINT64_C(0xf000000000000000) +/** Command synopsis, special hanging indent rules applies. */ +#define RTMSGREFENTRYSTR_FLAGS_SYNOPSIS RT_BIT_64(63) +/** @} */ + +/** String table entry for a refentry. */ +typedef struct RTMSGREFENTRYSTR +{ + /** The scope of the string. There are two predefined scopes, + * REFENTRYSTR_SCOPE_SAME and REFENTRYSTR_SCOPE_GLOBAL. The rest are + * reference entry specific. */ + uint64_t fScope; + /** The string. Non-breaking space is represented by the char + * REFENTRY_NBSP defines, just in case the string needs wrapping. There is + * no trailing newline, that's implicit. */ + const char *psz; +} RTMSGREFENTRYSTR; +/** Pointer to a read-only string table entry. */ +typedef const RTMSGREFENTRYSTR *PCRTMSGREFENTRYSTR; + +/** Refentry string table. */ +typedef struct RTMSGREFENTRYSTRTAB +{ + /** Number of strings. */ + uint16_t cStrings; + /** Reserved for future use. */ + uint16_t fReserved; + /** Pointer to the string table. */ + PCRTMSGREFENTRYSTR paStrings; +} RTMSGREFENTRYSTRTAB; +/** Pointer to a read-only string table. */ +typedef RTMSGREFENTRYSTRTAB const *PCRTMSGREFENTRYSTRTAB; + +/** + * Help extracted from a docbook refentry document. + */ +typedef struct RTMSGREFENTRY +{ + /** Internal reference entry identifier. */ + int64_t idInternal; + /** Usage synopsis. */ + RTMSGREFENTRYSTRTAB Synopsis; + /** Full help. */ + RTMSGREFENTRYSTRTAB Help; + /** Brief command description. */ + const char *pszBrief; +} RTMSGREFENTRY; +/** Pointer to a read-only refentry help extract structure. */ +typedef RTMSGREFENTRY const *PCRTMSGREFENTRY; + + +#ifndef IPRT_INCLUDED_stream_h +typedef struct RTSTREAM *PRTSTREAM; +#endif + + +/** + * Print the synopsis to the given stream. + * + * @returns Current number of pending blank lines. + * @param pStrm The output stream. + * @param pEntry The refentry to print the help for. + */ +RTDECL(int) RTMsgRefEntrySynopsis(PRTSTREAM pStrm, PCRTMSGREFENTRY pEntry); + + +/** + * Print the synopsis to the given stream. + * + * @returns Current number of pending blank lines. + * @param pStrm The output stream. + * @param pEntry The refentry to print the help for. + * @param fScope The scope inclusion mask. + * @param fFlags RTMSGREFENTRY_SYNOPSIS_F_XXX. + */ +RTDECL(int) RTMsgRefEntrySynopsisEx(PRTSTREAM pStrm, PCRTMSGREFENTRY pEntry, uint64_t fScope, uint32_t fFlags); +/** @name RTMSGREFENTRY_SYNOPSIS_F_XXX - Flags for RTMsgRefEntrySynopsisEx. + * @{ */ +/** Prefix the output with 'Usage:'. */ +#define RTMSGREFENTRY_SYNOPSIS_F_USAGE RT_BIT_32(0) +/** @} */ + + +/** + * Print the help text to the given stream. + * + * @returns Current number of pending blank lines. + * @param pStrm The output stream. + * @param pEntry The refentry to print the help for. + */ +RTDECL(int) RTMsgRefEntryHelp(PRTSTREAM pStrm, PCRTMSGREFENTRY pEntry); + +/** + * Print the help text to the given stream, extended version. + * + * @returns Current number of pending blank lines. + * @param pStrm The output stream. + * @param pEntry The refentry to print the help for. + * @param fScope The scope inclusion mask. + * @param fFlags Reserved, MBZ. + */ +RTDECL(int) RTMsgRefEntryHelpEx(PRTSTREAM pStrm, PCRTMSGREFENTRY pEntry, uint64_t fScope, uint32_t fFlags); + +/** + * Prints a string table. + * + * @returns Current number of pending blank lines. + * @param pStrm The output stream. + * @param pStrTab The string table. + * @param fScope The selection scope. + * @param pcPendingBlankLines In: Pending blank lines from previous string + * table. Out: Pending blank lines. + * @param pcLinesWritten Pointer to variable that should be incremented + * by the number of lines written. Optional. + */ +RTDECL(int) RTMsgRefEntryPrintStringTable(PRTSTREAM pStrm, PCRTMSGREFENTRYSTRTAB pStrTab, uint64_t fScope, + uint32_t *pcPendingBlankLines, uint32_t *pcLinesWritten); + +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_message_h */ + diff --git a/include/iprt/mp.h b/include/iprt/mp.h new file mode 100644 index 00000000..e418bceb --- /dev/null +++ b/include/iprt/mp.h @@ -0,0 +1,521 @@ +/** @file + * IPRT - Multiprocessor. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_mp_h +#define IPRT_INCLUDED_mp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_mp RTMp - Multiprocessor + * @ingroup grp_rt + * @{ + */ + +/** + * Gets the identifier of the CPU executing the call. + * + * When called from a system mode where scheduling is active, like ring-3 or + * kernel mode with interrupts enabled on some systems, no assumptions should + * be made about the current CPU when the call returns. + * + * @returns CPU Id. + */ +RTDECL(RTCPUID) RTMpCpuId(void); + +/** + * Get the CPU set index of the CPU executing the call. + * + * Same scheduling warnings as for RTMpCpuId(). + * + * @returns CPU set index. + */ +RTDECL(int) RTMpCurSetIndex(void); + +/** + * Get the CPU set index and identifier of the CPU executing the call. + * + * Same scheduling warnings as for RTMpCpuId(). + * + * @returns CPU set index. + * @param pidCpu Where to return the CPU identifier. (not optional) + */ +RTDECL(int) RTMpCurSetIndexAndId(PRTCPUID pidCpu); + +/** + * Converts a CPU identifier to a CPU set index. + * + * This may or may not validate the presence of the CPU. + * + * @returns The CPU set index on success, -1 on failure. + * @param idCpu The identifier of the CPU. + */ +RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu); + +/** + * Converts a CPU set index to a a CPU identifier. + * + * This may or may not validate the presence of the CPU, so, use + * RTMpIsCpuPossible for that. + * + * @returns The corresponding CPU identifier, NIL_RTCPUID on failure. + * @param iCpu The CPU set index. + */ +RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu); + +/** + * Translates an NT process group member to a CPU set index. + * + * @returns CPU set index, -1 if not valid. + * @param idxGroup The CPU group. + * @param idxMember The CPU group member number. + * + * @remarks Only available on Windows. + */ +RTDECL(int) RTMpSetIndexFromCpuGroupMember(uint32_t idxGroup, uint32_t idxMember); + +/** + * Gets the member numbers for a CPU group. + * + * @returns Maximum number of group members. + * @param idxGroup The CPU group. + * @param pcActive Where to return the number of active members. + * + * @remarks Only available on Windows. + */ +RTDECL(uint32_t) RTMpGetCpuGroupCounts(uint32_t idxGroup, uint32_t *pcActive); + +/** + * Get the maximum number of CPU groups. + * + * @returns Maximum number of CPU groups. + * + * @remarks Only available on Windows. + */ +RTDECL(uint32_t) RTMpGetMaxCpuGroupCount(void); + +/** + * Gets the max CPU identifier (inclusive). + * + * Intended for brute force enumerations, but use with + * care as it may be expensive. + * + * @returns The current higest CPU identifier value. + */ +RTDECL(RTCPUID) RTMpGetMaxCpuId(void); + +/** + * Gets the size of a CPU array that is indexed by CPU set index. + * + * This takes both online, offline and hot-plugged cpus into account. + * + * @returns Number of elements. + * + * @remarks Use RTMpCpuIdToSetIndex to convert a RTCPUID into an array index. + */ +RTDECL(uint32_t) RTMpGetArraySize(void); + +/** + * Checks if a CPU exists in the system or may possibly be hotplugged later. + * + * @returns true/false accordingly. + * @param idCpu The identifier of the CPU. + */ +RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu); + +/** + * Gets set of the CPUs present in the system plus any that may + * possibly be hotplugged later. + * + * @returns pSet. + * @param pSet Where to put the set. + */ +RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet); + +/** + * Get the count of CPUs present in the system plus any that may + * possibly be hotplugged later. + * + * @returns The count. + * @remarks Don't use this for CPU array sizing, use RTMpGetArraySize instead. + */ +RTDECL(RTCPUID) RTMpGetCount(void); + +/** + * Get the count of physical CPU cores present in the system plus any that may + * possibly be hotplugged later. + * + * @returns The number of cores. + */ +RTDECL(RTCPUID) RTMpGetCoreCount(void); + +/** + * Gets set of the CPUs present that are currently online. + * + * @returns pSet. + * @param pSet Where to put the set. + */ +RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet); + +/** + * Get the count of CPUs that are currently online. + * + * @return The count. + */ +RTDECL(RTCPUID) RTMpGetOnlineCount(void); + +/** + * Get the count of physical CPU cores in the system with one or more online + * threads. + * + * @returns The number of online cores. + */ +RTDECL(RTCPUID) RTMpGetOnlineCoreCount(void); + +/** + * Checks if a CPU is online or not. + * + * @returns true/false accordingly. + * @param idCpu The identifier of the CPU. + */ +RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu); + + +/** + * Gets set of the CPUs present in the system. + * + * @returns pSet. + * @param pSet Where to put the set. + */ +RTDECL(PRTCPUSET) RTMpGetPresentSet(PRTCPUSET pSet); + +/** + * Get the count of CPUs that are present in the system. + * + * @return The count. + */ +RTDECL(RTCPUID) RTMpGetPresentCount(void); + +/** + * Get the count of physical CPU cores present in the system. + * + * @returns The number of cores. + */ +RTDECL(RTCPUID) RTMpGetPresentCoreCount(void); + +/** + * Checks if a CPU is present in the system. + * + * @returns true/false accordingly. + * @param idCpu The identifier of the CPU. + */ +RTDECL(bool) RTMpIsCpuPresent(RTCPUID idCpu); + + +/** + * Get the current frequency of a CPU. + * + * The CPU must be online. + * + * @returns The frequency as MHz. 0 if the CPU is offline + * or the information is not available. + * @param idCpu The identifier of the CPU. + */ +RTDECL(uint32_t) RTMpGetCurFrequency(RTCPUID idCpu); + +/** + * Get the maximum frequency of a CPU. + * + * The CPU must be online. + * + * @returns The frequency as MHz. 0 if the CPU is offline + * or the information is not available. + * @param idCpu The identifier of the CPU. + */ +RTDECL(uint32_t) RTMpGetMaxFrequency(RTCPUID idCpu); + +/** + * Get the CPU description string. + * + * The CPU must be online. + * + * @returns IPRT status code. + * @param idCpu The identifier of the CPU. NIL_RTCPUID can be used to + * indicate the current CPU. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + */ +RTDECL(int) RTMpGetDescription(RTCPUID idCpu, char *pszBuf, size_t cbBuf); + + +#ifdef IN_RING0 + +/** + * Check if there's work (DPCs on Windows) pending on the current CPU. + * + * @return true if there's pending work on the current CPU, false otherwise. + */ +RTDECL(bool) RTMpIsCpuWorkPending(void); + + +/** + * Worker function passed to RTMpOnAll, RTMpOnOthers and RTMpOnSpecific that + * is to be called on the target cpus. + * + * @param idCpu The identifier for the CPU the function is called on. + * @param pvUser1 The 1st user argument. + * @param pvUser2 The 2nd user argument. + */ +typedef DECLCALLBACKTYPE(void, FNRTMPWORKER,(RTCPUID idCpu, void *pvUser1, void *pvUser2)); +/** Pointer to a FNRTMPWORKER. */ +typedef FNRTMPWORKER *PFNRTMPWORKER; + +/** @name RTMPON_F_XXX - RTMpOn flags. + * @{ */ +/** Caller doesn't care if pfnWorker is executed at the same time on the + * specified CPUs or not, as long as it gets executed. */ +#define RTMPON_F_WHATEVER_EXEC 0 +/** The caller insists on pfnWorker being executed more or less concurrently + * on the specified CPUs. */ +#define RTMPON_F_CONCURRENT_EXEC RT_BIT_32(1) +/** Mask of valid bits. */ +#define RTMPON_F_VALID_MASK UINT32_C(0x00000001) +/** @}*/ + +/** + * Checks if the RTMpOnAll() is safe with regards to all threads executing + * concurrently. + * + * If for instance, the RTMpOnAll() is implemented in a way where the threads + * might cause a classic deadlock, it is considered -not- concurrent safe. + * Windows currently is one such platform where it isn't safe. + * + * @returns true if RTMpOnAll() is concurrent safe, false otherwise. + */ +RTDECL(bool) RTMpOnAllIsConcurrentSafe(void); + +/** + * Executes a function on each (online) CPU in the system. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_SUPPORTED if this kind of operation isn't supported by the system. + * + * @param pfnWorker The worker function. + * @param pvUser1 The first user argument for the worker. + * @param pvUser2 The second user argument for the worker. + * + * @remarks The execution isn't in any way guaranteed to be simultaneous, + * it might even be serial (cpu by cpu). + */ +RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2); + +/** + * Executes a function on all other (online) CPUs in the system. + * + * The caller must disable preemption prior to calling this API if the outcome + * is to make any sense. But do *not* disable interrupts. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_SUPPORTED if this kind of operation isn't supported by the system. + * + * @param pfnWorker The worker function. + * @param pvUser1 The first user argument for the worker. + * @param pvUser2 The second user argument for the worker. + * + * @remarks The execution isn't in any way guaranteed to be simultaneous, + * it might even be serial (cpu by cpu). + */ +RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2); + +/** + * Executes a function on a specific CPU in the system. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_SUPPORTED if this kind of operation isn't supported by the system. + * @retval VERR_CPU_OFFLINE if the CPU is offline. + * @retval VERR_CPU_NOT_FOUND if the CPU wasn't found. + * + * @param idCpu The id of the CPU. + * @param pfnWorker The worker function. + * @param pvUser1 The first user argument for the worker. + * @param pvUser2 The second user argument for the worker. + */ +RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2); + +/** + * Executes a function on two specific CPUs in the system. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_SUPPORTED if this kind of operation isn't supported by the + * system or if the specified modifier flag isn't supported. + * @retval VERR_CPU_OFFLINE if one or more of the CPUs are offline (see + * remarks). + * @retval VERR_CPU_NOT_FOUND if on or both of the CPUs weren't found. + * @retval VERR_NOT_ALL_CPUS_SHOWED if one of the CPUs didn't show. + * + * @param idCpu1 The id of the first CPU. + * @param idCpu2 The id of the second CPU. + * @param fFlags Combination of RTMPON_F_XXX flags. + * @param pfnWorker The worker function. + * @param pvUser1 The first user argument for the worker. + * @param pvUser2 The second user argument for the worker. + * + * @remarks There is a possible race between one (or both) of the CPUs going + * offline while setting up the call. The worker function must take + * this into account. + */ +RTDECL(int) RTMpOnPair(RTCPUID idCpu1, RTCPUID idCpu2, uint32_t fFlags, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2); + +/** + * Indicates whether RTMpOnPair supports running the pfnWorker concurrently on + * both CPUs using RTMPON_F_CONCURRENT_EXEC. + * + * @returns true if supported, false if not. + */ +RTDECL(bool) RTMpOnPairIsConcurrentExecSupported(void); + + +/** + * Pokes the specified CPU. + * + * This should cause the execution on the CPU to be interrupted and forcing it + * to enter kernel context. It is optimized version of a RTMpOnSpecific call + * with a worker which returns immediately. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if this kind of operation isn't supported by the + * system. The caller must not automatically assume that this API works + * when any of the RTMpOn* APIs works. This is because not all systems + * supports unicast MP events and this API will not be implemented as a + * broadcast. + * @retval VERR_CPU_OFFLINE if the CPU is offline. + * @retval VERR_CPU_NOT_FOUND if the CPU wasn't found. + * + * @param idCpu The id of the CPU to poke. + */ +RTDECL(int) RTMpPokeCpu(RTCPUID idCpu); + + +/** + * MP event, see FNRTMPNOTIFICATION. + */ +typedef enum RTMPEVENT +{ + /** The CPU goes online. */ + RTMPEVENT_ONLINE = 1, + /** The CPU goes offline. */ + RTMPEVENT_OFFLINE +} RTMPEVENT; + +/** + * Notification callback. + * + * The context this is called in differs a bit from platform to platform, so be + * careful while in here. + * + * On Windows we're running with IRQL=PASSIVE_LEVEL (reschedulable) according to + * the KeRegisterProcessorChangeCallback documentation - unrestricted API + * access. Probably not being called on the onlined/offlined CPU... + * + * On Solaris we're holding the cpu_lock, IPL/SPL/PIL is not yet known, however + * we will most likely -not- be firing on the CPU going offline/online. + * + * On Linux it looks like we're called with preemption enabled on any CPU and + * not necessarily on the CPU going offline/online. + * + * There is no callbacks for darwin at the moment, due to lack of suitable KPI. + * + * @param idCpu The CPU this applies to. + * @param enmEvent The event. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(void, FNRTMPNOTIFICATION,(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser)); +/** Pointer to a FNRTMPNOTIFICATION(). */ +typedef FNRTMPNOTIFICATION *PFNRTMPNOTIFICATION; + +/** + * Registers a notification callback for cpu events. + * + * On platforms which doesn't do cpu offline/online events this API + * will just be a no-op that pretends to work. + * + * @todo We'll be adding a flag to this soon to indicate whether the callback should be called on all + * CPUs that are currently online while it's being registered. This is to help avoid some race + * conditions (we'll hopefully be able to implement this on linux, solaris/win is no issue). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NO_MEMORY if a registration record cannot be allocated. + * @retval VERR_ALREADY_EXISTS if the pfnCallback and pvUser already exist + * in the callback list. + * + * @param pfnCallback The callback. + * @param pvUser The user argument to the callback function. + */ +RTDECL(int) RTMpNotificationRegister(PFNRTMPNOTIFICATION pfnCallback, void *pvUser); + +/** + * This deregisters a notification callback registered via RTMpNotificationRegister(). + * + * The pfnCallback and pvUser arguments must be identical to the registration call + * of we won't find the right entry. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_FOUND if no matching entry was found. + * + * @param pfnCallback The callback. + * @param pvUser The user argument to the callback function. + */ +RTDECL(int) RTMpNotificationDeregister(PFNRTMPNOTIFICATION pfnCallback, void *pvUser); + +#endif /* IN_RING0 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_mp_h */ + diff --git a/include/iprt/net.h b/include/iprt/net.h new file mode 100644 index 00000000..647c15c3 --- /dev/null +++ b/include/iprt/net.h @@ -0,0 +1,1064 @@ +/** @file + * IPRT - Network Protocols. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_net_h +#define IPRT_INCLUDED_net_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/assert.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_net RTNet - Network Protocols + * @ingroup grp_rt + * @{ + */ + +/** + * Converts an stringified Ethernet MAC address into the RTMAC representation. + * + * @todo This should be move to some generic part of the runtime. + * + * @returns VINF_SUCCESS on success, VERR_GETOPT_INVALID_ARGUMENT_FORMAT on + * failure. + * + * @param pszAddr The address string to convert. + * @param pMacAddr Where to store the result. + */ +RTDECL(int) RTNetStrToMacAddr(const char *pszAddr, PRTMAC pMacAddr); + +/** + * IPv4 address. + */ +typedef RTUINT32U RTNETADDRIPV4; +AssertCompileSize(RTNETADDRIPV4, 4); +/** Pointer to a IPv4 address. */ +typedef RTNETADDRIPV4 *PRTNETADDRIPV4; +/** Pointer to a const IPv4 address. */ +typedef RTNETADDRIPV4 const *PCRTNETADDRIPV4; + +/** + * Tests if the given string is an IPv4 address. + * + * @returns boolean. + * @param pcszAddr String which may be an IPv4 address. + */ +RTDECL(bool) RTNetIsIPv4AddrStr(const char *pcszAddr); + +/** + * Tests if the given string is a wildcard IPv4 address. + * + * @returns boolean. + * @param pcszAddr String which may be an IPv4 address. + */ +RTDECL(bool) RTNetStrIsIPv4AddrAny(const char *pcszAddr); + +/** + * Parses dotted-decimal IPv4 address into RTNETADDRIPV4 representation. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param pcszAddr The value to convert. + * @param ppszNext Where to store the pointer to the first char + * following the address. (Optional) + * @param pAddr Where to store the result. + */ +RTDECL(int) RTNetStrToIPv4AddrEx(const char *pcszAddr, PRTNETADDRIPV4 pAddr, char **ppszNext); + +/** + * Parses dotted-decimal IPv4 address into RTNETADDRIPV4 representation. + * Leading and trailing whitespace is ignored. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param pcszAddr The value to convert. + * @param pAddr Where to store the result. + */ +RTDECL(int) RTNetStrToIPv4Addr(const char *pcszAddr, PRTNETADDRIPV4 pAddr); + +/** + * Parses dotted-decimal IPv4 CIDR notation into RTNETADDRIPV4 + * representation and prefix length. Missing prefix specification is + * treated as exact address specification (prefix length 32). Leading + * and trailing whitespace is ignored. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param pcszAddr The value to convert. + * @param pAddr Where to store the address. + * @param piPrefix Where to store the prefix length; + */ +RTDECL(int) RTNetStrToIPv4Cidr(const char *pcszAddr, PRTNETADDRIPV4 pAddr, int *piPrefix); + +/** + * Verifies that RTNETADDRIPV4 is a valid contiguous netmask and + * computes its prefix length. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param pMask The netmask to verify and convert. + * @param piPrefix Where to store the prefix length. (Optional) + */ +RTDECL(int) RTNetMaskToPrefixIPv4(PCRTNETADDRIPV4 pMask, int *piPrefix); + +/** + * Computes netmask corresponding to the prefix length. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param iPrefix The prefix to convert. + * @param pMask Where to store the netmask. + */ +RTDECL(int) RTNetPrefixToMaskIPv4(int iPrefix, PRTNETADDRIPV4 pMask); + + +/** + * IPv6 address. + */ +typedef RTUINT128U RTNETADDRIPV6; +AssertCompileSize(RTNETADDRIPV6, 16); +/** Pointer to a IPv6 address. */ +typedef RTNETADDRIPV6 *PRTNETADDRIPV6; +/** Pointer to a const IPv6 address. */ +typedef RTNETADDRIPV6 const *PCRTNETADDRIPV6; + +/** + * Tests if the given string is a valid IPv6 address. + * + * @returns @c true if it is, @c false if not. + * @param pszAddress String which may be an IPv6 address. + */ +RTDECL(bool) RTNetIsIPv6AddrStr(const char *pszAddress); + +/** + * Tests if the given string is a wildcard IPv6 address. + * + * @returns @c true if it is, @c false if not. + * @param pszAddress String which may be an IPv6 address. + */ +RTDECL(bool) RTNetStrIsIPv6AddrAny(const char *pszAddress); + +/** + * Parses IPv6 address into RTNETADDRIPV6 representation. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param pcszAddr The value to convert. + * @param ppszNext Where to store the pointer to the first char + * following the address. (Optional) + * @param pAddr Where to store the result. + */ +RTDECL(int) RTNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr, char **ppszNext); + +/** + * Parses IPv6 address into RTNETADDRIPV6 representation. + * Leading and trailing whitespace is ignored. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param pcszAddr The value to convert. + * @param ppszZone Where to store the pointer to the first char + * of the zone id. NULL is stored if there is + * no zone id. + * @param pAddr Where to store the result. + */ +RTDECL(int) RTNetStrToIPv6Addr(const char *pcszAddr, PRTNETADDRIPV6 pAddr, char **ppszZone); + +/** + * Verifies that RTNETADDRIPV6 is a valid contiguous netmask and + * computes its prefix length. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param pMask The netmask to verify and convert. + * @param piPrefix Where to store the prefix length. (Optional) + */ +RTDECL(int) RTNetMaskToPrefixIPv6(PCRTNETADDRIPV6 pMask, int *piPrefix); + +/** + * Computes netmask corresponding to the prefix length. + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param iPrefix The prefix to convert. + * @param pMask Where to store the netmask. + */ +RTDECL(int) RTNetPrefixToMaskIPv6(int iPrefix, PRTNETADDRIPV6 pMask); + +/** + * Parses IPv6 prefix notation into RTNETADDRIPV6 representation and + * prefix length. Missing prefix specification is treated as exact + * address specification (prefix length 128). Leading and trailing + * whitespace is ignored. + * + * "CIDR" in the name is a misnomer as IPv6 doesn't have network + * classes, but is parallel to the IPv4 name (and naming things is + * hard). + * + * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on + * failure. + * + * @param pcszAddr The value to convert. + * @param pAddr Where to store the address. + * @param piPrefix Where to store the prefix length; + */ +RTDECL(int) RTNetStrToIPv6Cidr(const char *pcszAddr, PRTNETADDRIPV6 pAddr, int *piPrefix); + + +/** + * IPX address. + */ +#pragma pack(1) +typedef struct RTNETADDRIPX +{ + /** The network ID. */ + uint32_t Network; + /** The node ID. (Defaults to the MAC address apparently.) */ + RTMAC Node; +} RTNETADDRIPX; +#pragma pack() +AssertCompileSize(RTNETADDRIPX, 4+6); +/** Pointer to an IPX address. */ +typedef RTNETADDRIPX *PRTNETADDRIPX; +/** Pointer to a const IPX address. */ +typedef RTNETADDRIPX const *PCRTNETADDRIPX; + +/** + * Network address union. + * + * @remarks The size of this structure may change in the future. + */ +typedef union RTNETADDRU +{ + /** 64-bit view. */ + uint64_t au64[2]; + /** 32-bit view. */ + uint32_t au32[4]; + /** 16-bit view. */ + uint16_t au16[8]; + /** 8-bit view. */ + uint8_t au8[16]; + /** IPv4 view. */ + RTNETADDRIPV4 IPv4; +#ifndef IPv6 /* Work around X11 and RDP defining IPv6 to 1. */ + /** IPv6 view. */ + RTNETADDRIPV6 IPv6; +#endif + /** IPX view. */ + RTNETADDRIPX Ipx; + /** MAC address view. */ + RTMAC Mac; +} RTNETADDRU; +AssertCompileSize(RTNETADDRU, 16); +/** Pointer to an address union. */ +typedef RTNETADDRU *PRTNETADDRU; +/** Pointer to a const address union. */ +typedef RTNETADDRU const *PCRTNETADDRU; + +/** + * Network address type. + * + * @remarks The value assignments may change in the future. + */ +typedef enum RTNETADDRTYPE +{ + /** The invalid 0 entry. */ + RTNETADDRTYPE_INVALID = 0, + /** IP version 4. */ + RTNETADDRTYPE_IPV4, + /** IP version 6. */ + RTNETADDRTYPE_IPV6, + /** IPX. */ + RTNETADDRTYPE_IPX, + /** MAC address. */ + RTNETADDRTYPE_MAC, + /** The end of the valid values. */ + RTNETADDRTYPE_END, + /** The usual 32-bit hack. */ + RTNETADDRTYPE_32_BIT_HACK = 0x7fffffff +} RTNETADDRTYPE; +/** Pointer to a network address type. */ +typedef RTNETADDRTYPE *PRTNETADDRTYPE; +/** Pointer to a const network address type. */ +typedef RTNETADDRTYPE const *PCRTNETADDRTYPE; + +/** + * Network address. + * + * @remarks The size and type values may change. + */ +typedef struct RTNETADDR +{ + /** The address union. */ + RTNETADDRU uAddr; + /** Indicates which view of @a u that is valid. */ + RTNETADDRTYPE enmType; + /** The port number for IPv4 and IPv6 addresses. This is set to + * RTNETADDR_NA_PORT if not applicable. */ + uint32_t uPort; +} RTNETADDR; +/** Pointer to a network address. */ +typedef RTNETADDR *PRTNETADDR; +/** Pointer to a const network address. */ +typedef RTNETADDR const *PCRTNETADDR; + +/** The not applicable value of RTNETADDR::uPort value use to inid. */ +#define RTNETADDR_PORT_NA UINT32_MAX + +/** + * Ethernet header. + */ +#pragma pack(1) +typedef struct RTNETETHERHDR +{ + RTMAC DstMac; + RTMAC SrcMac; + /** Ethernet frame type or frame size, depending on the kind of ethernet. + * This is big endian on the wire. */ + uint16_t EtherType; +} RTNETETHERHDR; +#pragma pack() +AssertCompileSize(RTNETETHERHDR, 14); +/** Pointer to an ethernet header. */ +typedef RTNETETHERHDR *PRTNETETHERHDR; +/** Pointer to a const ethernet header. */ +typedef RTNETETHERHDR const *PCRTNETETHERHDR; + +/** @name EtherType (RTNETETHERHDR::EtherType) + * @{ */ +#define RTNET_ETHERTYPE_IPV4 UINT16_C(0x0800) +#define RTNET_ETHERTYPE_ARP UINT16_C(0x0806) +#define RTNET_ETHERTYPE_IPV6 UINT16_C(0x86dd) +#define RTNET_ETHERTYPE_VLAN UINT16_C(0x8100) +#define RTNET_ETHERTYPE_IPX_1 UINT16_C(0x8037) +#define RTNET_ETHERTYPE_IPX_2 UINT16_C(0x8137) +#define RTNET_ETHERTYPE_IPX_3 UINT16_C(0x8138) +/** @} */ + + +/** + * IPv4 header. + * All is bigendian on the wire. + */ +#pragma pack(1) +typedef struct RTNETIPV4 +{ +#ifdef RT_BIG_ENDIAN + unsigned int ip_v : 4; + unsigned int ip_hl : 4; + unsigned int ip_tos : 8; + unsigned int ip_len : 16; +#else + /** 00:0 - Header length given as a 32-bit word count. */ + unsigned int ip_hl : 4; + /** 00:4 - Header version. */ + unsigned int ip_v : 4; + /** 01 - Type of service. */ + unsigned int ip_tos : 8; + /** 02 - Total length (header + data). */ + unsigned int ip_len : 16; +#endif + /** 04 - Packet idenficiation. */ + uint16_t ip_id; + /** 06 - Offset if fragmented. */ + uint16_t ip_off; + /** 08 - Time to live. */ + uint8_t ip_ttl; + /** 09 - Protocol. */ + uint8_t ip_p; + /** 0a - Header check sum. */ + uint16_t ip_sum; + /** 0c - Source address. */ + RTNETADDRIPV4 ip_src; + /** 10 - Destination address. */ + RTNETADDRIPV4 ip_dst; + /** 14 - Options (optional). */ + uint32_t ip_options[1]; +} RTNETIPV4; +#pragma pack() +AssertCompileSize(RTNETIPV4, 6 * 4); +/** Pointer to a IPv4 header. */ +typedef RTNETIPV4 *PRTNETIPV4; +/** Pointer to a const IPv4 header. */ +typedef RTNETIPV4 const *PCRTNETIPV4; + +/** The minimum IPv4 header length (in bytes). + * Up to and including RTNETIPV4::ip_dst. */ +#define RTNETIPV4_MIN_LEN (20) + + +/** @name IPv4 Protocol Numbers + * @{ */ +/** IPv4: ICMP */ +#define RTNETIPV4_PROT_ICMP (1) +/** IPv4: TCP */ +#define RTNETIPV4_PROT_TCP (6) +/** IPv4: UDP */ +#define RTNETIPV4_PROT_UDP (17) +/** @} */ + +/** @name Common IPv4 Port Assignments + * @{ + */ +/** Boostrap Protocol / DHCP) Server. */ +#define RTNETIPV4_PORT_BOOTPS (67) +/** Boostrap Protocol / DHCP) Client. */ +#define RTNETIPV4_PORT_BOOTPC (68) +/** @} */ + +/** @name IPv4 Flags + * @{ */ +/** IPv4: Don't fragment */ +#define RTNETIPV4_FLAGS_DF (0x4000) +/** IPv4: More fragments */ +#define RTNETIPV4_FLAGS_MF (0x2000) +/** @} */ + +RTDECL(uint16_t) RTNetIPv4HdrChecksum(PCRTNETIPV4 pIpHdr); +RTDECL(bool) RTNetIPv4IsHdrValid(PCRTNETIPV4 pIpHdr, size_t cbHdrMax, size_t cbPktMax, bool fChecksum); +RTDECL(uint32_t) RTNetIPv4PseudoChecksum(PCRTNETIPV4 pIpHdr); +RTDECL(uint32_t) RTNetIPv4PseudoChecksumBits(RTNETADDRIPV4 SrcAddr, RTNETADDRIPV4 DstAddr, uint8_t bProtocol, uint16_t cbPkt); +RTDECL(uint32_t) RTNetIPv4AddDataChecksum(void const *pvData, size_t cbData, uint32_t u32Sum, bool *pfOdd); +RTDECL(uint16_t) RTNetIPv4FinalizeChecksum(uint32_t u32Sum); + + +/** + * IPv6 header. + * All is bigendian on the wire. + */ +#pragma pack(1) +typedef struct RTNETIPV6 +{ + /** Version (4 bits), Traffic Class (8 bits) and Flow Lable (20 bits). + * @todo this is probably mislabeled - ip6_flow vs. ip6_vfc, fix later. */ + uint32_t ip6_vfc; + /** 04 - Payload length, including extension headers. */ + uint16_t ip6_plen; + /** 06 - Next header type (RTNETIPV4_PROT_XXX). */ + uint8_t ip6_nxt; + /** 07 - Hop limit. */ + uint8_t ip6_hlim; + /** xx - Source address. */ + RTNETADDRIPV6 ip6_src; + /** xx - Destination address. */ + RTNETADDRIPV6 ip6_dst; +} RTNETIPV6; +#pragma pack() +AssertCompileSize(RTNETIPV6, 8 + 16 + 16); +/** Pointer to a IPv6 header. */ +typedef RTNETIPV6 *PRTNETIPV6; +/** Pointer to a const IPv6 header. */ +typedef RTNETIPV6 const *PCRTNETIPV6; + +/** The minimum IPv6 header length (in bytes). + * Up to and including RTNETIPV6::ip6_dst. */ +#define RTNETIPV6_MIN_LEN (40) +#define RTNETIPV6_ICMPV6_ND_WITH_LLA_OPT_MIN_LEN (32) + +RTDECL(uint32_t) RTNetIPv6PseudoChecksum(PCRTNETIPV6 pIpHdr); +RTDECL(uint32_t) RTNetIPv6PseudoChecksumEx(PCRTNETIPV6 pIpHdr, uint8_t bProtocol, uint16_t cbPkt); +RTDECL(uint32_t) RTNetIPv6PseudoChecksumBits(PCRTNETADDRIPV6 pSrcAddr, PCRTNETADDRIPV6 pDstAddr, + uint8_t bProtocol, uint16_t cbPkt); + + +/** + * UDP header. + */ +#pragma pack(1) +typedef struct RTNETUDP +{ + /** The source port. */ + uint16_t uh_sport; + /** The destination port. */ + uint16_t uh_dport; + /** The length of the UDP header and associated data. */ + uint16_t uh_ulen; + /** The checksum of the pseudo header, the UDP header and the data. */ + uint16_t uh_sum; +} RTNETUDP; +#pragma pack() +AssertCompileSize(RTNETUDP, 8); +/** Pointer to an UDP header. */ +typedef RTNETUDP *PRTNETUDP; +/** Pointer to a const UDP header. */ +typedef RTNETUDP const *PCRTNETUDP; + +/** The minimum UDP packet length (in bytes). (RTNETUDP::uh_ulen) */ +#define RTNETUDP_MIN_LEN (8) + +RTDECL(uint16_t) RTNetUDPChecksum(uint32_t u32Sum, PCRTNETUDP pUdpHdr); +RTDECL(uint32_t) RTNetIPv4AddUDPChecksum(PCRTNETUDP pUdpHdr, uint32_t u32Sum); +RTDECL(uint16_t) RTNetIPv4UDPChecksum(PCRTNETIPV4 pIpHdr, PCRTNETUDP pUdpHdr, void const *pvData); +RTDECL(bool) RTNetIPv4IsUDPSizeValid(PCRTNETIPV4 pIpHdr, PCRTNETUDP pUdpHdr, size_t cbPktMax); +RTDECL(bool) RTNetIPv4IsUDPValid(PCRTNETIPV4 pIpHdr, PCRTNETUDP pUdpHdr, void const *pvData, size_t cbPktMax, bool fChecksum); + + +/** + * IPv4 BOOTP / DHCP packet. + */ +#pragma pack(1) +typedef struct RTNETBOOTP +{ + /** 00 - The packet opcode (RTNETBOOTP_OP_*). */ + uint8_t bp_op; + /** 01 - Hardware address type. Same as RTNETARPHDR::ar_htype. */ + uint8_t bp_htype; + /** 02 - Hardware address length. */ + uint8_t bp_hlen; + /** 03 - Gateway hops. */ + uint8_t bp_hops; + /** 04 - Transaction ID. */ + uint32_t bp_xid; + /** 08 - Seconds since boot started. */ + uint16_t bp_secs; + /** 0a - Unused (BOOTP) / Flags (DHCP) (RTNET_DHCP_FLAGS_*). */ + uint16_t bp_flags; + /** 0c - Client IPv4 address. */ + RTNETADDRIPV4 bp_ciaddr; + /** 10 - Your IPv4 address. */ + RTNETADDRIPV4 bp_yiaddr; + /** 14 - Server IPv4 address. */ + RTNETADDRIPV4 bp_siaddr; + /** 18 - Gateway IPv4 address. */ + RTNETADDRIPV4 bp_giaddr; + /** 1c - Client hardware address. */ + union + { + uint8_t au8[16]; + RTMAC Mac; + } bp_chaddr; + /** 2c - Server name. */ + uint8_t bp_sname[64]; + /** 6c - File name / more DHCP options. */ + uint8_t bp_file[128]; + /** ec - Vendor specific area (BOOTP) / Options (DHCP). + * @remark This is really 312 bytes in the DHCP version. */ + union + { + uint8_t au8[128]; + struct DHCP + { + /** ec - The DHCP cookie (RTNET_DHCP_COOKIE). */ + uint32_t dhcp_cookie; + /** f0 - The DHCP options. */ + uint8_t dhcp_opts[124]; + } Dhcp; + } bp_vend; + +} RTNETBOOTP; +#pragma pack() +AssertCompileSize(RTNETBOOTP, 0xec + 128); +/** Pointer to a BOOTP / DHCP packet. */ +typedef RTNETBOOTP *PRTNETBOOTP; +/** Pointer to a const BOOTP / DHCP packet. */ +typedef RTNETBOOTP const *PCRTNETBOOTP; + +/** Minimum BOOTP packet length. For quick validation, no standard thing really. */ +#define RTNETBOOTP_MIN_LEN 0xec +/** Minimum DHCP packet length. For quick validation, no standard thing really. */ +#define RTNETBOOTP_DHCP_MIN_LEN 0xf1 + +/** The normal size of the a DHCP packet (i.e. a RTNETBOOTP). + * Same as RTNET_DHCP_OPT_SIZE, just expressed differently. */ +#define RTNET_DHCP_NORMAL_SIZE (0xec + 4 + RTNET_DHCP_OPT_SIZE) +/** The normal size of RTNETBOOTP::bp_vend::Dhcp::dhcp_opts. */ +#define RTNET_DHCP_OPT_SIZE (312 - 4) + +/** @name BOOTP packet opcode values + * @{ */ +#define RTNETBOOTP_OP_REQUEST 1 +#define RTNETBOOTP_OP_REPLY 2 +/** @} */ + +/** @name DHCP flags (RTNETBOOTP::bp_flags) + * @{ */ +#define RTNET_DHCP_FLAGS_NO_BROADCAST UINT16_C(0x8000) /** @todo check test!!! */ +/** @} */ + +/** The DHCP cookie (network endian). */ +#define RTNET_DHCP_COOKIE UINT32_C(0x63825363) + +/** + * An IPv4 DHCP option header. + */ +typedef struct RTNETDHCPOPT +{ + /** 00 - The DHCP option. */ + uint8_t dhcp_opt; + /** 01 - The data length (excluding this header). */ + uint8_t dhcp_len; + /* 02 - The option data follows here, optional and of variable length. */ +} RTNETDHCPOPT; +AssertCompileSize(RTNETDHCPOPT, 2); +/** Pointer to a DHCP option header. */ +typedef RTNETDHCPOPT *PRTNETDHCPOPT; +/** Pointer to a const DHCP option header. */ +typedef RTNETDHCPOPT const *PCRTNETDHCPOPT; + +/** @name DHCP options + * @{ */ +/** 1 byte padding, this has no dhcp_len field. */ +#define RTNET_DHCP_OPT_PAD 0 + +/** The subnet mask. */ +#define RTNET_DHCP_OPT_SUBNET_MASK 1 +/** The time offset. */ +#define RTNET_DHCP_OPT_TIME_OFFSET 2 +/** The routers for the subnet. */ +#define RTNET_DHCP_OPT_ROUTERS 3 +/** Domain Name Server. */ +#define RTNET_DHCP_OPT_DNS 6 +/** Host name. */ +#define RTNET_DHCP_OPT_HOST_NAME 12 +/** Domain name. */ +#define RTNET_DHCP_OPT_DOMAIN_NAME 15 + +/** The requested address. */ +#define RTNET_DHCP_OPT_REQ_ADDR 50 +/** The lease time in seconds. */ +#define RTNET_DHCP_OPT_LEASE_TIME 51 +/** Option overload. + * Indicates that the bp_file and/or bp_sname holds contains DHCP options. */ +#define RTNET_DHCP_OPT_OPTION_OVERLOAD 52 +/** Have a 8-bit message type value as data, see RTNET_DHCP_MT_*. */ +#define RTNET_DHCP_OPT_MSG_TYPE 53 +/** Server ID. */ +#define RTNET_DHCP_OPT_SERVER_ID 54 +/** Parameter request list. */ +#define RTNET_DHCP_OPT_PARAM_REQ_LIST 55 +/** The maximum DHCP message size a client is willing to accept. */ +#define RTNET_DHCP_OPT_MAX_DHCP_MSG_SIZE 57 +/** Client ID. */ +#define RTNET_DHCP_OPT_CLIENT_ID 61 +/** TFTP server name. */ +#define RTNET_DHCP_OPT_TFTP_SERVER_NAME 66 +/** Bootfile name. */ +#define RTNET_DHCP_OPT_BOOTFILE_NAME 67 + +/** Marks the end of the DHCP options, this has no dhcp_len field. */ +#define RTNET_DHCP_OPT_END 255 +/** @} */ + +/** @name DHCP Option overload flags (option 52) + * @{ */ +#define RTNET_DHCP_OPTION_OVERLOAD_FILE 1 +#define RTNET_DHCP_OPTION_OVERLOAD_SNAME 2 +#define RTNET_DHCP_OPTION_OVERLOAD_MASK 3 +/** @} */ + +/** @name DHCP Message Types (option 53) + * @{ */ +#define RTNET_DHCP_MT_DISCOVER 1 +#define RTNET_DHCP_MT_OFFER 2 +#define RTNET_DHCP_MT_REQUEST 3 +#define RTNET_DHCP_MT_DECLINE 4 +#define RTNET_DHCP_MT_ACK 5 +#define RTNET_DHCP_MT_NAC 6 +#define RTNET_DHCP_MT_RELEASE 7 +#define RTNET_DHCP_MT_INFORM 8 +/** @} */ + +/** @name DHCP Flags + * @{ */ +#define RTNET_DHCP_FLAG_BROADCAST 0x8000 +/** @} */ + +RTDECL(bool) RTNetIPv4IsDHCPValid(PCRTNETUDP pUdpHdr, PCRTNETBOOTP pDhcp, size_t cbDhcp, uint8_t *pMsgType); + + +/** + * IPv4 DHCP packet. + * @deprecated Use RTNETBOOTP. + */ +#pragma pack(1) +typedef struct RTNETDHCP +{ + /** 00 - The packet opcode. */ + uint8_t Op; + /** Hardware address type. */ + uint8_t HType; + /** Hardware address length. */ + uint8_t HLen; + uint8_t Hops; + uint32_t XID; + uint16_t Secs; + uint16_t Flags; + /** Client IPv4 address. */ + RTNETADDRIPV4 CIAddr; + /** Your IPv4 address. */ + RTNETADDRIPV4 YIAddr; + /** Server IPv4 address. */ + RTNETADDRIPV4 SIAddr; + /** Gateway IPv4 address. */ + RTNETADDRIPV4 GIAddr; + /** Client hardware address. */ + uint8_t CHAddr[16]; + /** Server name. */ + uint8_t SName[64]; + uint8_t File[128]; + uint8_t abMagic[4]; + uint8_t DhcpOpt; + uint8_t DhcpLen; /* 1 */ + uint8_t DhcpReq; + uint8_t abOptions[57]; +} RTNETDHCP; +#pragma pack() +/** @todo AssertCompileSize(RTNETDHCP, ); */ +/** Pointer to a DHCP packet. */ +typedef RTNETDHCP *PRTNETDHCP; +/** Pointer to a const DHCP packet. */ +typedef RTNETDHCP const *PCRTNETDHCP; + + +/** + * TCP packet. + */ +#pragma pack(1) +typedef struct RTNETTCP +{ + /** 00 - The source port. */ + uint16_t th_sport; + /** 02 - The destination port. */ + uint16_t th_dport; + /** 04 - The sequence number. */ + uint32_t th_seq; + /** 08 - The acknowledgement number. */ + uint32_t th_ack; +#ifdef RT_BIG_ENDIAN + unsigned int th_win : 16; + unsigned int th_flags : 8; + unsigned int th_off : 4; + unsigned int th_x2 : 4; +#else + /** 0c:0 - Reserved. */ + unsigned int th_x2 : 4; + /** 0c:4 - The data offset given as a dword count from the start of this header. */ + unsigned int th_off : 4; + /** 0d - flags. */ + unsigned int th_flags : 8; + /** 0e - The window. */ + unsigned int th_win : 16; +#endif + /** 10 - The checksum of the pseudo header, the TCP header and the data. */ + uint16_t th_sum; + /** 12 - The urgent pointer. */ + uint16_t th_urp; + /* (options follows here and then the data (aka text).) */ +} RTNETTCP; +#pragma pack() +AssertCompileSize(RTNETTCP, 20); +/** Pointer to a TCP packet. */ +typedef RTNETTCP *PRTNETTCP; +/** Pointer to a const TCP packet. */ +typedef RTNETTCP const *PCRTNETTCP; + +/** The minimum TCP header length (in bytes). (RTNETTCP::th_off * 4) */ +#define RTNETTCP_MIN_LEN (20) + +/** @name TCP flags (RTNETTCP::th_flags) + * @{ */ +#define RTNETTCP_F_FIN 0x01 +#define RTNETTCP_F_SYN 0x02 +#define RTNETTCP_F_RST 0x04 +#define RTNETTCP_F_PSH 0x08 +#define RTNETTCP_F_ACK 0x10 +#define RTNETTCP_F_URG 0x20 +#define RTNETTCP_F_ECE 0x40 +#define RTNETTCP_F_CWR 0x80 +/** @} */ + +RTDECL(uint16_t) RTNetTCPChecksum(uint32_t u32Sum, PCRTNETTCP pTcpHdr, void const *pvData, size_t cbData); +RTDECL(uint32_t) RTNetIPv4AddTCPChecksum(PCRTNETTCP pTcpHdr, uint32_t u32Sum); +RTDECL(uint16_t) RTNetIPv4TCPChecksum(PCRTNETIPV4 pIpHdr, PCRTNETTCP pTcpHdr, void const *pvData); +RTDECL(bool) RTNetIPv4IsTCPSizeValid(PCRTNETIPV4 pIpHdr, PCRTNETTCP pTcpHdr, size_t cbHdrMax, size_t cbPktMax); +RTDECL(bool) RTNetIPv4IsTCPValid(PCRTNETIPV4 pIpHdr, PCRTNETTCP pTcpHdr, size_t cbHdrMax, void const *pvData, + size_t cbPktMax, bool fChecksum); + + +/** + * IPv4 ICMP packet header. + */ +#pragma pack(1) +typedef struct RTNETICMPV4HDR +{ + /** 00 - The ICMP message type. */ + uint8_t icmp_type; + /** 01 - Type specific code that further qualifies the message. */ + uint8_t icmp_code; + /** 02 - Checksum of the ICMP message. */ + uint16_t icmp_cksum; +} RTNETICMPV4HDR; +#pragma pack() +AssertCompileSize(RTNETICMPV4HDR, 4); +/** Pointer to an ICMP packet header. */ +typedef RTNETICMPV4HDR *PRTNETICMPV4HDR; +/** Pointer to a const ICMP packet header. */ +typedef RTNETICMPV4HDR const *PCRTNETICMPV4HDR; + +/** @name ICMP (v4) message types. + * @{ */ +#define RTNETICMPV4_TYPE_ECHO_REPLY 0 +#define RTNETICMPV4_TYPE_ECHO_REQUEST 8 +#define RTNETICMPV4_TYPE_TRACEROUTE 30 +/** @} */ + +/** + * IPv4 ICMP ECHO Reply & Request packet. + */ +#pragma pack(1) +typedef struct RTNETICMPV4ECHO +{ + /** 00 - The ICMP header. */ + RTNETICMPV4HDR Hdr; + /** 04 - The identifier to help the requestor match up the reply. + * Can be 0. Typically fixed value. */ + uint16_t icmp_id; + /** 06 - The sequence number to help the requestor match up the reply. + * Can be 0. Typically incrementing between requests. */ + uint16_t icmp_seq; + /** 08 - Variable length data that is to be returned unmodified in the reply. */ + uint8_t icmp_data[1]; +} RTNETICMPV4ECHO; +#pragma pack() +AssertCompileSize(RTNETICMPV4ECHO, 9); +/** Pointer to an ICMP ECHO packet. */ +typedef RTNETICMPV4ECHO *PRTNETICMPV4ECHO; +/** Pointer to a const ICMP ECHO packet. */ +typedef RTNETICMPV4ECHO const *PCRTNETICMPV4ECHO; + +/** + * IPv4 ICMP TRACEROUTE packet. + * This is an reply to an IP packet with the traceroute option set. + */ +#pragma pack(1) +typedef struct RTNETICMPV4TRACEROUTE +{ + /** 00 - The ICMP header. */ + RTNETICMPV4HDR Hdr; + /** 04 - Identifier copied from the traceroute option's ID number. */ + uint16_t icmp_id; + /** 06 - Unused. (Possibly an icmp_seq?) */ + uint16_t icmp_void; + /** 08 - Outbound hop count. From the IP packet causing this message. */ + uint16_t icmp_ohc; + /** 0a - Return hop count. From the IP packet causing this message. */ + uint16_t icmp_rhc; + /** 0c - Output link speed, 0 if not known. */ + uint32_t icmp_speed; + /** 10 - Output link MTU, 0 if not known. */ + uint32_t icmp_mtu; +} RTNETICMPV4TRACEROUTE; +#pragma pack() +AssertCompileSize(RTNETICMPV4TRACEROUTE, 20); +/** Pointer to an ICMP TRACEROUTE packet. */ +typedef RTNETICMPV4TRACEROUTE *PRTNETICMPV4TRACEROUTE; +/** Pointer to a const ICMP TRACEROUTE packet. */ +typedef RTNETICMPV4TRACEROUTE const *PCRTNETICMPV4TRACEROUTE; + +/** @todo add more ICMPv4 as needed. */ + +/** + * IPv4 ICMP union packet. + */ +typedef union RTNETICMPV4 +{ + RTNETICMPV4HDR Hdr; + RTNETICMPV4ECHO Echo; + RTNETICMPV4TRACEROUTE Traceroute; +} RTNETICMPV4; +/** Pointer to an ICMP union packet. */ +typedef RTNETICMPV4 *PRTNETICMPV4; +/** Pointer to a const ICMP union packet. */ +typedef RTNETICMPV4 const *PCRTNETICMPV4; + + +/** + * IPv6 ICMP packet header. + */ +#pragma pack(1) +typedef struct RTNETICMPV6HDR +{ + /** 00 - The ICMPv6 message type. */ + uint8_t icmp6_type; + /** 01 - Type specific code that further qualifies the message. */ + uint8_t icmp6_code; + /** 02 - Checksum of the ICMPv6 message. */ + uint16_t icmp6_cksum; +} RTNETICMPV6HDR; +#pragma pack() +AssertCompileSize(RTNETICMPV6HDR, 4); +/** Pointer to an ICMPv6 packet header. */ +typedef RTNETICMPV6HDR *PRTNETICMPV6HDR; +/** Pointer to a const ICMP packet header. */ +typedef RTNETICMPV6HDR const *PCRTNETICMPV6HDR; + +#define RTNETIPV6_PROT_ICMPV6 (58) + +/** @name Internet Control Message Protocol version 6 (ICMPv6) message types. + * @{ */ +#define RTNETIPV6_ICMP_TYPE_RS 133 +#define RTNETIPV6_ICMP_TYPE_RA 134 +#define RTNETIPV6_ICMP_TYPE_NS 135 +#define RTNETIPV6_ICMP_TYPE_NA 136 +#define RTNETIPV6_ICMP_TYPE_RDR 137 +/** @} */ + +/** @name Neighbor Discovery option types + * @{ */ +#define RTNETIPV6_ICMP_ND_SLLA_OPT (1) +#define RTNETIPV6_ICMP_ND_TLLA_OPT (2) +/** @} */ + +/** ICMPv6 ND Source/Target Link Layer Address option */ +#pragma pack(1) +typedef struct RTNETNDP_LLA_OPT +{ + uint8_t type; + uint8_t len; + RTMAC lla; +} RTNETNDP_LLA_OPT; +#pragma pack() + +AssertCompileSize(RTNETNDP_LLA_OPT, 1+1+6); + +typedef RTNETNDP_LLA_OPT *PRTNETNDP_LLA_OPT; +typedef RTNETNDP_LLA_OPT const *PCRTNETNDP_LLA_OPT; + +/** ICMPv6 ND Neighbor Sollicitation */ +#pragma pack(1) +typedef struct RTNETNDP +{ + /** 00 - The ICMPv6 header. */ + RTNETICMPV6HDR Hdr; + /** 04 - reserved */ + uint32_t reserved; + /** 08 - target address */ + RTNETADDRIPV6 target_address; +} RTNETNDP; +#pragma pack() +AssertCompileSize(RTNETNDP, 4+4+16); +/** Pointer to a NDP ND packet. */ +typedef RTNETNDP *PRTNETNDP; +/** Pointer to a const NDP NS packet. */ +typedef RTNETNDP const *PCRTNETNDP; + + +/** + * Ethernet ARP header. + */ +#pragma pack(1) +typedef struct RTNETARPHDR +{ + /** The hardware type. */ + uint16_t ar_htype; + /** The protocol type (ethertype). */ + uint16_t ar_ptype; + /** The hardware address length. */ + uint8_t ar_hlen; + /** The protocol address length. */ + uint8_t ar_plen; + /** The operation. */ + uint16_t ar_oper; +} RTNETARPHDR; +#pragma pack() +AssertCompileSize(RTNETARPHDR, 8); +/** Pointer to an ethernet ARP header. */ +typedef RTNETARPHDR *PRTNETARPHDR; +/** Pointer to a const ethernet ARP header. */ +typedef RTNETARPHDR const *PCRTNETARPHDR; + +/** ARP hardware type - ethernet. */ +#define RTNET_ARP_ETHER UINT16_C(1) + +/** @name ARP operations + * @{ */ +#define RTNET_ARPOP_REQUEST UINT16_C(1) /**< Request hardware address given a protocol address (ARP). */ +#define RTNET_ARPOP_REPLY UINT16_C(2) +#define RTNET_ARPOP_REVREQUEST UINT16_C(3) /**< Request protocol address given a hardware address (RARP). */ +#define RTNET_ARPOP_REVREPLY UINT16_C(4) +#define RTNET_ARPOP_INVREQUEST UINT16_C(8) /**< Inverse ARP. */ +#define RTNET_ARPOP_INVREPLY UINT16_C(9) +/** Check if an ARP operation is a request or not. */ +#define RTNET_ARPOP_IS_REQUEST(Op) ((Op) & 1) +/** Check if an ARP operation is a reply or not. */ +#define RTNET_ARPOP_IS_REPLY(Op) (!RTNET_ARPOP_IS_REQUEST(Op)) +/** @} */ + + +/** + * Ethernet IPv4 + 6-byte MAC ARP request packet. + */ +#pragma pack(1) +typedef struct RTNETARPIPV4 +{ + /** ARP header. */ + RTNETARPHDR Hdr; + /** The sender hardware address. */ + RTMAC ar_sha; + /** The sender protocol address. */ + RTNETADDRIPV4 ar_spa; + /** The target hardware address. */ + RTMAC ar_tha; + /** The target protocol address. */ + RTNETADDRIPV4 ar_tpa; +} RTNETARPIPV4; +#pragma pack() +AssertCompileSize(RTNETARPIPV4, 8+6+4+6+4); +/** Pointer to an ethernet IPv4+MAC ARP request packet. */ +typedef RTNETARPIPV4 *PRTNETARPIPV4; +/** Pointer to a const ethernet IPv4+MAC ARP request packet. */ +typedef RTNETARPIPV4 const *PCRTNETARPIPV4; + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_net_h */ + diff --git a/include/iprt/nocrt/Makefile.kup b/include/iprt/nocrt/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/iprt/nocrt/Makefile.kup diff --git a/include/iprt/nocrt/algorithm b/include/iprt/nocrt/algorithm new file mode 100644 index 00000000..bf6102f8 --- /dev/null +++ b/include/iprt/nocrt/algorithm @@ -0,0 +1,164 @@ +/** @file + * IPRT / No-CRT - Minimal C++ algorithm header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_algorithm +#define VBOX_INCLUDED_SRC_nocrt_algorithm +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4643) /* warning C4643: Forward declaring 'ios_base' in namespace std is not permitted by the C++ Standard */ +#endif + +namespace std +{ + /** + * Swap the values pointed to by the two references. + */ + template<typename a_Type> + void swap(a_Type &a_rObj1, a_Type &a_rObj2) + { + a_Type Tmp(a_rObj1); + a_rObj1 = a_rObj2; + a_rObj2 = Tmp; + } + + /** + * Swap the values pointed to by two forward iterators. + */ + template<typename a_ForwardIt1, typename a_ForwardIt2> + void iter_swap(a_ForwardIt1 a_It1, a_ForwardIt2 a_It2) + { + swap(*a_It1, *a_It2); + } + + template<typename a_RandomIt> + void sort(a_RandomIt a_ItBegin, a_RandomIt a_ItEnd) + { + /* Note! Using shell sort here because it's tiny and we've got code for it. */ + /** @todo replace with faster code. */ + + /* Anything worth sorting? */ + std::size_t const cElements = a_ItEnd - a_ItBegin; + if (cElements >= 1) + { + /* Loop on decreasing gap, ending with 1: */ + std::size_t cGap = (cElements + 1) / 2; + while (cGap > 0) + { + /* Iterate from cGap till the end: */ + for (std::size_t i = cGap; i < cElements; i++) + { + /* Find the best suitable location for the item at 'i' comparing + backwards in steps of 'cGap', swapping the item at 'i' with the + one at '-cGap*j' if it's smaller, stopping if it's larger. + + Note! Original algorithm would make a copy of the item, this version + avoids extra copies of sorted items at the cost of extra copies + when dealing with unsorted ones a small cGaps values. */ + a_RandomIt ItCur = a_ItBegin + i; + size_t j = i; + do + { + j -= cGap; + a_RandomIt ItAtGap = a_ItBegin + j; + if (*ItAtGap < *ItCur) + break; + std::iter_swap(ItAtGap, ItCur); + ItCur = ItAtGap; + } while (j >= cGap); + } + + /* This does not generate the most optimal gap sequence, but it has the + advantage of being simple and avoid floating point. */ + cGap /= 2; + } + } + } + + template<typename a_RandomIt, typename a_FnCompareType> + void sort(a_RandomIt a_ItBegin, a_RandomIt a_ItEnd, a_FnCompareType a_fnComp) + { + /* Note! Using shell sort here because it's tiny and we've got code for it. */ + /** @todo replace with faster code. */ + + /* Anything worth sorting? */ + std::size_t const cElements = a_ItEnd - a_ItBegin; + if (cElements >= 1) + { + /* Loop on decreasing gap, ending with 1: */ + std::size_t cGap = (cElements + 1) / 2; + while (cGap > 0) + { + /* Iterate from cGap till the end: */ + for (std::size_t i = cGap; i < cElements; i++) + { + /* Find the best suitable location for the item at 'i' comparing + backwards in steps of 'cGap', swapping the item at 'i' with the + one at '-cGap*j' if it's smaller, stopping if it's larger. + + Note! Original algorithm would make a copy of the item, this version + avoids extra copies of sorted items at the cost of extra copies + when dealing with unsorted ones a small cGaps values. */ + a_RandomIt ItCur = a_ItBegin + i; + size_t j = i; + do + { + j -= cGap; + a_RandomIt ItAtGap = a_ItBegin + j; + if (a_fnComp(*ItAtGap, *ItCur)) + break; + std::iter_swap(ItAtGap, ItCur); + ItCur = ItAtGap; + } while (j >= cGap); + } + + /* This does not generate the most optimal gap sequence, but it has the + advantage of being simple and avoid floating point. */ + cGap /= 2; + } + } + } + +} + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !VBOX_INCLUDED_SRC_nocrt_algorithm */ + diff --git a/include/iprt/nocrt/amd64/Makefile.kup b/include/iprt/nocrt/amd64/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/iprt/nocrt/amd64/Makefile.kup diff --git a/include/iprt/nocrt/amd64/math.h b/include/iprt/nocrt/amd64/math.h new file mode 100644 index 00000000..19bdea78 --- /dev/null +++ b/include/iprt/nocrt/amd64/math.h @@ -0,0 +1,115 @@ +/** @file + * IPRT / No-CRT - math.h, AMD inlined functions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_amd64_math_h +#define IPRT_INCLUDED_nocrt_amd64_math_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/asm.h> + + +#if RT_INLINE_ASM_GNU_STYLE && defined(__SSE__) + +DECLINLINE(long double) inline_atan2l(long double lrd1, long double lrd2) +{ + long double lrdResult; + __asm__ __volatile__("fpatan" + : "=t" (lrdResult) + : "u" (lrd1), + "0" (lrd2) + : "st(1)"); + return lrdResult; +} + +DECLINLINE(long double) inline_rintl(long double lrd) +{ + long double lrdResult; + __asm__ __volatile__("frndint" + : "=t" (lrdResult) + : "0" (lrd)); + return lrdResult; +} + +DECLINLINE(float) inline_rintf(float rf) +{ + return (float)inline_rintl(rf); +} + +DECLINLINE(double) inline_rint(double rd) +{ + return (double)inline_rintl(rd); +} + +DECLINLINE(long double) inline_sqrtl(long double lrd) +{ + long double lrdResult; + __asm__ __volatile__("fsqrt" + : "=t" (lrdResult) + : "0" (lrd)); + return lrdResult; +} + +DECLINLINE(float) inline_sqrtf(float rf) +{ + return (float)inline_sqrtl(rf); +} + +DECLINLINE(double) inline_sqrt(double rd) +{ + return (double)inline_sqrtl(rd); +} + + +# undef atan2l +# define atan2l(lrd1, lrd2) inline_atan2l(lrd1, lrd2) +# undef rint +# define rint(rd) inline_rint(rd) +# undef rintf +# define rintf(rf) inline_rintf(rf) +# undef rintl +# define rintl(lrd) inline_rintl(lrd) +# undef sqrt +# define sqrt(rd) inline_sqrt(rd) +# undef sqrtf +# define sqrtf(rf) inline_sqrtf(rf) +# undef sqrtl +# define sqrtl(lrd) inline_sqrtl(lrd) + +#endif /* RT_INLINE_ASM_GNU_STYLE */ + +#endif /* !IPRT_INCLUDED_nocrt_amd64_math_h */ + diff --git a/include/iprt/nocrt/assert.h b/include/iprt/nocrt/assert.h new file mode 100644 index 00000000..987db7df --- /dev/null +++ b/include/iprt/nocrt/assert.h @@ -0,0 +1,57 @@ +/** @file + * IPRT / No-CRT - Our own assert.h header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_assert_h +#define IPRT_INCLUDED_nocrt_assert_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assert.h> + +DECL_FORCE_INLINE(void) rtCrtAssertPanic(void) +{ + RTAssertPanic(); +} + +/* Mesa uses assert() in such a way that we must not have any 'do {} while' + wrappers in the expansion, so we partially cook our own assert here but + using the standard iprt/assert.h building blocks. */ +#define assert(a_Expr) (RT_LIKELY(!!(a_Expr)) ? (void)0 \ + : RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__), \ + rtCrtAssertPanic(), (void)0 ) + +#endif /* !IPRT_INCLUDED_nocrt_assert_h */ + diff --git a/include/iprt/nocrt/cassert b/include/iprt/nocrt/cassert new file mode 100644 index 00000000..3315a4bd --- /dev/null +++ b/include/iprt/nocrt/cassert @@ -0,0 +1,49 @@ +/** @file + * IPRT / No-CRT - Minimal C++ cassert header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_cassert +#define VBOX_INCLUDED_SRC_nocrt_cassert +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/nocrt/assert.h> + +namespace std +{ +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_cassert */ + diff --git a/include/iprt/nocrt/compiler/compiler.h b/include/iprt/nocrt/compiler/compiler.h new file mode 100644 index 00000000..c2ca1d80 --- /dev/null +++ b/include/iprt/nocrt/compiler/compiler.h @@ -0,0 +1,52 @@ +/** @file + * IPRT / No-CRT - compiler specifics. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_compiler_compiler_h +#define IPRT_INCLUDED_nocrt_compiler_compiler_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef __GNUC__ +# include <iprt/nocrt/compiler/gcc.h> +#elif defined(_MSC_VER) +# include <iprt/nocrt/compiler/msc.h> +#elif defined(__WATCOMC__) +# include <iprt/nocrt/compiler/watcom.h> +#else +# error "Unsupported compiler." +#endif + +#endif /* !IPRT_INCLUDED_nocrt_compiler_compiler_h */ diff --git a/include/iprt/nocrt/compiler/gcc.h b/include/iprt/nocrt/compiler/gcc.h new file mode 100644 index 00000000..91c1d5a8 --- /dev/null +++ b/include/iprt/nocrt/compiler/gcc.h @@ -0,0 +1,134 @@ +/** @file + * IPRT / No-CRT - GCC specifics. + * + * A quick hack for freebsd where there are no separate location + * for compiler specific headers like on linux, mingw, os2, ++. + * This file will be cleaned up later... + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_compiler_gcc_h +#define IPRT_INCLUDED_nocrt_compiler_gcc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/* stddef.h */ +#ifdef __PTRDIFF_TYPE__ +typedef __PTRDIFF_TYPE__ ptrdiff_t; +#elif ARCH_BITS == 32 +typedef int32_t ptrdiff_t; +#elif ARCH_BITS == 64 +typedef int64_t ptrdiff_t; +#else +# error "ARCH_BITS is undefined or incorrect." +#endif +#define _PTRDIFF_T_DECLARED + +#ifdef __SIZE_TYPE__ +typedef __SIZE_TYPE__ size_t; +#elif ARCH_BITS == 32 +typedef uint32_t size_t; +#elif ARCH_BITS == 64 +typedef uint64_t size_t; +#else +# error "ARCH_BITS is undefined or incorrect." +#endif +#define _SIZE_T_DECLARED + +#ifndef __cplusplus +# ifdef __WCHAR_TYPE__ +typedef __WCHAR_TYPE__ wchar_t; +# elif defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) +typedef uint16_t wchar_t; +# else +typedef int wchar_t; +# endif +# define _WCHAR_T_DECLARED +#endif + +#ifdef __WINT_TYPE__ +typedef __WINT_TYPE__ wint_t; +#else +typedef unsigned int wint_t; +#endif +#define _WINT_T_DECLARED + +#ifndef NULL +# ifdef __cplusplus +# define NULL 0 +# else +# define NULL ((void *)0) +# endif +#endif + + +#ifndef offsetof +# if defined(__cplusplus) && defined(__offsetof__) +# define offsetof(type, memb) + (__offsetof__ (reinterpret_cast<size_t>(&reinterpret_cast<const volatile char &>(static_cast<type *>(0)->memb))) ) +# else +# define offsetof(type, memb) ((size_t)&((type *)0)->memb) +# endif +#endif + + +/* sys/types.h */ +#ifdef __SSIZE_TYPE__ +typedef __SSIZE_TYPE__ ssize_t; +#elif ARCH_BITS == 32 +typedef int32_t ssize_t; +#elif ARCH_BITS == 64 +typedef int64_t ssize_t; +#else +# define ARCH_BITS 123123 +# error "ARCH_BITS is undefined or incorrect." +#endif +#define _SSIZE_T_DECLARED + + +/* stdarg.h */ +typedef __builtin_va_list va_list; +#if __GNUC__ == 3 \ + && __GNUC_MINOR__ == 2 +# define va_start(va, arg) __builtin_stdarg_start(va, arg) +#else +# define va_start(va, arg) __builtin_va_start(va, arg) +#endif +#define va_end(va) __builtin_va_end(va) +#define va_arg(va, type) __builtin_va_arg(va, type) +#define va_copy(dst, src) __builtin_va_copy(dst, src) + + +#endif /* !IPRT_INCLUDED_nocrt_compiler_gcc_h */ diff --git a/include/iprt/nocrt/compiler/msc.h b/include/iprt/nocrt/compiler/msc.h new file mode 100644 index 00000000..be81fffc --- /dev/null +++ b/include/iprt/nocrt/compiler/msc.h @@ -0,0 +1,62 @@ +/** @file + * IPRT / No-CRT - MSC specifics. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_compiler_msc_h +#define IPRT_INCLUDED_nocrt_compiler_msc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/* stddef.h */ +#if !defined(_MT) && !defined(_DLL) && _MSC_VER < 1400 +# define errno msvcrt_errno +#endif +#if _MSC_VER >= 1900 +# include <vcruntime.h> +#else +# include <../include/stddef.h> +#endif +#undef errno + +#undef ssize_t +typedef intptr_t ssize_t; + + +/* stdarg.h */ +#include <../include/stdarg.h> + +#endif /* !IPRT_INCLUDED_nocrt_compiler_msc_h */ + diff --git a/include/iprt/nocrt/compiler/watcom.h b/include/iprt/nocrt/compiler/watcom.h new file mode 100644 index 00000000..507b66dc --- /dev/null +++ b/include/iprt/nocrt/compiler/watcom.h @@ -0,0 +1,108 @@ +/** @file + * IPRT / No-CRT - Open Watcom specifics. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_compiler_watcom_h +#define IPRT_INCLUDED_nocrt_compiler_watcom_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> + +/* stddef.h for size_t and such */ +#if 0 +# include <../h/stddef.h> + +# ifndef _SSIZE_T_DEFINED_ +# define _SSIZE_T_DEFINED_ +typedef signed int ssize_t; +# endif + +#else + +# define _SIZE_T_DEFINED_ +# define __size_t +typedef unsigned size_t; +typedef size_t _w_size_t; + +# define _SSIZE_T_DEFINED_ +# define __ssize_t +typedef signed int ssize_t; + +# define _RSIZE_T_DEFINED +typedef size_t rsize_t; + +# define _PTRDIFF_T_DEFINED_ +# ifdef __HUGE__ +typedef long ptrdiff_t; +# else +typedef int ptrdiff_t; +# endif + +# ifndef _WCHAR_T_DEFINED /* predefined in C++ mode? */ +# define _WCHAR_T_DEFINED +typedef unsigned short wchar_t; +# endif + +# ifndef NULL +# ifndef __cplusplus +# define NULL ((void *)0) +# elif defined(__SMALL__) || defined(__MEDIUM__) || !defined(_M_I86) +# define NULL (0) +# else +# define NULL (0L) +# endif +# endif + +# define offsetof(a_Type, a_Member) RT_OFFSETOF(a_Type, a_Member) + +# if defined(_M_I86) && (defined(__SMALL__) || defined(__MEDIUM__)) +typedef int intptr_t; +typedef unsigned int uintptr_t; +# elif defined(_M_I86) || (!defined(__COMPACT__) && !defined(__LARGE__)) +typedef long intptr_t; +typedef unsigned long uintptr_t; +# else /* 32-bit compile using far data pointers (16:32) */ +typedef long long intptr_t; +typedef unsigned long long uintptr_t; +# endif + +#endif + +/* stdarg.h */ +#include <../h/stdarg.h> + +#endif /* !IPRT_INCLUDED_nocrt_compiler_watcom_h */ + diff --git a/include/iprt/nocrt/cstddef b/include/iprt/nocrt/cstddef new file mode 100644 index 00000000..2b3c29e9 --- /dev/null +++ b/include/iprt/nocrt/cstddef @@ -0,0 +1,52 @@ +/** @file + * IPRT / No-CRT - Dummy cstddef. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_cstddef +#define VBOX_INCLUDED_SRC_nocrt_cstddef +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/nocrt/sys/types.h> + +namespace std +{ + using size_t = ::size_t; + using ptrdiff_t = ::ptrdiff_t; +} + + +#endif /* !VBOX_INCLUDED_SRC_nocrt_cstddef */ + diff --git a/include/iprt/nocrt/cstdlib b/include/iprt/nocrt/cstdlib new file mode 100644 index 00000000..2a11d98f --- /dev/null +++ b/include/iprt/nocrt/cstdlib @@ -0,0 +1,47 @@ +/** @file + * IPRT / No-CRT - Dummy cstdlib. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_cstdlib +#define VBOX_INCLUDED_SRC_nocrt_cstdlib +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/nocrt/stdlib.h> +#include <iprt/nocrt/cstddef> + + +#endif /* !VBOX_INCLUDED_SRC_nocrt_cstdlib */ + diff --git a/include/iprt/nocrt/ctype.h b/include/iprt/nocrt/ctype.h new file mode 100644 index 00000000..466a9283 --- /dev/null +++ b/include/iprt/nocrt/ctype.h @@ -0,0 +1,61 @@ +/** @file + * IPRT / No-CRT - Our own minimal ctype.h header (needed by ntdefs.h). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_ctype_h +#define IPRT_INCLUDED_nocrt_ctype_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/ctype.h> + +#define isspace(a_ch) RT_C_IS_SPACE(a_ch) +#define isblank(a_ch) RT_C_IS_BLANK(a_ch) +#define isdigit(a_ch) RT_C_IS_DIGIT(a_ch) +#define isxdigit(a_ch) RT_C_IS_XDIGIT(a_ch) +#define isalpha(a_ch) RT_C_IS_ALPHA(a_ch) +#define isalnum(a_ch) RT_C_IS_ALNUM(a_ch) +#define iscntrl(a_ch) RT_C_IS_CNTRL(a_ch) +#define isgraph(a_ch) RT_C_IS_GRAPH(a_ch) +#define ispunct(a_ch) RT_C_IS_PUNCT(a_ch) +#define isprint(a_ch) RT_C_IS_PRINT(a_ch) +#define isupper(a_ch) RT_C_IS_UPPER(a_ch) +#define islower(a_ch) RT_C_IS_LOWER(a_ch) + +#define tolower(a_ch) RT_C_TO_LOWER(a_ch) +#define toupper(a_ch) RT_C_TO_UPPER(a_ch) + +#endif /* !IPRT_INCLUDED_nocrt_ctype_h */ + diff --git a/include/iprt/nocrt/direct.h b/include/iprt/nocrt/direct.h new file mode 100644 index 00000000..72f23a17 --- /dev/null +++ b/include/iprt/nocrt/direct.h @@ -0,0 +1,43 @@ +/** @file + * IPRT / No-CRT - Stub direct.h header (for MSC compatibility). + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_direct_h +#define IPRT_INCLUDED_nocrt_direct_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#endif /* !IPRT_INCLUDED_nocrt_direct_h */ + diff --git a/include/iprt/nocrt/errno.h b/include/iprt/nocrt/errno.h new file mode 100644 index 00000000..1217a531 --- /dev/null +++ b/include/iprt/nocrt/errno.h @@ -0,0 +1,56 @@ +/** @file + * IPRT / No-CRT - Dummy errno.h. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_errno_h +#define IPRT_INCLUDED_nocrt_errno_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY +# include <iprt/errno.h> + +RT_C_DECLS_BEGIN + +RTDECL(int *) rtNoCrtGetErrnoPtr(void); +# define errno (*rtNoCrtGetErrnoPtr()) + +RT_C_DECLS_END + +#endif /* IPRT_NO_CRT_FOR_3RD_PARTY */ + +#endif /* !IPRT_INCLUDED_nocrt_errno_h */ + diff --git a/include/iprt/nocrt/exception b/include/iprt/nocrt/exception new file mode 100644 index 00000000..6e6ee777 --- /dev/null +++ b/include/iprt/nocrt/exception @@ -0,0 +1,90 @@ +/** @file + * IPRT / No-CRT - Our own exception header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_exception +#define VBOX_INCLUDED_SRC_nocrt_exception +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +namespace std { + +/** Exception base class. */ +class exception +{ +public: + exception() RT_NOEXCEPT +#ifdef _MSC_VER + : m_pszWhat(NULL) +#endif + { } + + exception(const exception &a_rThat) RT_NOEXCEPT +#ifdef _MSC_VER + : m_pszWhat(a_rThat.m_pszWhat) +#endif + { + RT_NOREF(a_rThat); + } + +#ifdef _MSC_VER + exception(const char *a_pszWhat, int a_iIgnored = 0) RT_NOEXCEPT + : m_pszWhat(a_pszWhat) + { RT_NOREF(a_iIgnored); } +#endif + + virtual ~exception() RT_NOEXCEPT + {} + + virtual const char *what() const RT_NOEXCEPT + { +#ifdef _MSC_VER + if (m_pszWhat) + return m_pszWhat; +#endif + return "unknown exception"; + } +#ifdef _MSC_VER +protected: + const char *m_pszWhat; +#endif +}; + +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_exception */ + diff --git a/include/iprt/nocrt/fcntl.h b/include/iprt/nocrt/fcntl.h new file mode 100644 index 00000000..49cf6f4b --- /dev/null +++ b/include/iprt/nocrt/fcntl.h @@ -0,0 +1,90 @@ +/** @file + * IPRT / No-CRT - fcntl.h + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_fcntl_h +#define IPRT_INCLUDED_nocrt_fcntl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/nocrt/time.h> /* to establish the timespec and timeval types before iprt/file.h includes iprt/time.h */ +#include <iprt/file.h> + +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY + +/* Open flags:*/ +AssertCompile(RT_IS_POWER_OF_TWO(RTFILE_O_OPEN_CREATE)); +AssertCompile(RT_IS_POWER_OF_TWO(RTFILE_O_CREATE)); +# define _O_CREAT RTFILE_O_OPEN_CREATE +# define _O_EXCL RTFILE_O_CREATE /**< Will remove RTFILE_O_OPEN_CREATE when processing it. */ +# define _O_TRUNC RTFILE_O_TRUNCATE +# define _O_APPEND RTFILE_O_APPEND +# define _O_RDONLY RTFILE_O_READ +# define _O_WRONLY RTFILE_O_WRITE +# define _O_RDWR (RTFILE_O_READ | RTFILE_O_WRITE) +# define _O_CLOEXEC RTFILE_O_INHERIT /**< Invert meaning when processing it. */ +# define _O_NOINHERIT O_CLOEXEC +# define _O_LARGEFILE 0 +# define _O_BINARY 0 + +# define O_CREAT _O_CREAT +# define O_EXCL _O_EXCL +# define O_TRUNC _O_TRUNC +# define O_APPEND _O_APPEND +# define O_RDONLY _O_RDONLY +# define O_WRONLY _O_WRONLY +# define O_RDWR _O_RDWR +# define O_CLOEXEC _O_CLOEXEC +# define O_NOINHERIT _O_NOINHERIT +# define O_BINARY _O_BINARY + +RT_C_DECLS_BEGIN + +int RT_NOCRT(open)(const char *pszFilename, uint64_t fFlags, ... /*RTFMODE fMode*/); +int RT_NOCRT(_open)(const char *pszFilename, uint64_t fFlags, ... /*RTFMODE fMode*/); + +# if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define open RT_NOCRT(open) +# define _open RT_NOCRT(_open) +# endif + +RT_C_DECLS_END + +#endif /* IPRT_NO_CRT_FOR_3RD_PARTY */ + + + +#endif /* !IPRT_INCLUDED_nocrt_fcntl_h */ + diff --git a/include/iprt/nocrt/fenv.h b/include/iprt/nocrt/fenv.h new file mode 100644 index 00000000..7af59d13 --- /dev/null +++ b/include/iprt/nocrt/fenv.h @@ -0,0 +1,49 @@ +/** @file + * IPRT / No-CRT - fenv.h wrapper. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_fenv_h +#define IPRT_INCLUDED_nocrt_fenv_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) +# include <iprt/nocrt/x86/fenv-x86-amd64.h> +#else +# error "IPRT: no fenv.h available for this platform, or the platform define is missing!" +#endif + +#endif /* !IPRT_INCLUDED_nocrt_fenv_h */ diff --git a/include/iprt/nocrt/float.h b/include/iprt/nocrt/float.h new file mode 100644 index 00000000..f0e8081d --- /dev/null +++ b/include/iprt/nocrt/float.h @@ -0,0 +1,131 @@ +/** @file + * IPRT / No-CRT - Our minimal float.h. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_float_h +#define IPRT_INCLUDED_nocrt_float_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/* + * Common. + */ +#define FLT_RADIX 2 + + +/* + * float + */ +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) || defined(RT_ARCH_ARM64) + +# define FLT_MAX (3.40282347E+38F) +# define FLT_MIN (1.17549435E-38F) +# define FLT_TRUE_MIN (1.40129846E-45F) +# define FLT_MAX_EXP (128) +# define FLT_MIN_EXP (-125) +# define FLT_MAX_10_EXP (38) +# define FLT_MIN_10_EXP (-37) +# define FLT_EPSILON (1.192092896E-07F) +# define FLT_DIG (6) +# define FLT_DECIMAL_DIG (9) +# define FLT_MANT_DIG (24) +# define FLT_HAS_SUBNORM (1) + +#endif + +/* + * double + */ +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) || defined(RT_ARCH_ARM64) + +# ifdef _MSC_VER +# define DBL_MAX (1.7976931348623158E+308) +# else +# define DBL_MAX (1.7976931348623157E+308) +# endif +# define DBL_MIN (2.2250738585072014E-308) +# define DBL_TRUE_MIN (4.9406564584124654E-324) +# define DBL_MAX_EXP (1024) +# define DBL_MIN_EXP (-1021) +# define DBL_MAX_10_EXP (308) +# define DBL_MIN_10_EXP (-307) +# define DBL_EPSILON (2.2204460492503131E-16) +# define DBL_DIG (15) +# define DBL_DECIMAL_DIG (17) +# define DBL_MANT_DIG (53) +# define DBL_HAS_SUBNORM (1) + +#endif + +/* + * long double + */ +#if ((defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)) && defined(RT_OS_WINDOWS)) || defined(RT_ARCH_ARM64) /*?*/ + +# define LDBL_MAX DBL_MAX +# define LDBL_MIN DBL_MIN +# define LDBL_TRUE_MIN DBL_TRUE_MIN +# define LDBL_MAX_EXP DBL_MAX_EXP +# define LDBL_MIN_EXP DBL_MIN_EXP +# define LDBL_MAX_10_EXP DBL_MAX_10_EXP +# define LDBL_MIN_10_EXP DBL_MIN_10_EXP +# define LDBL_EPSILON DBL_EPSILON +# define LDBL_DIG DBL_DIG +# define LDBL_DECIMAL_DIG DBL_DECIMAL_DIG +# define LDBL_MANT_DIG DBL_MANT_DIG +# define LDBL_HAS_SUBNORM DBL_HAS_SUBNORM + +#elif defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) + +# define LDBL_MAX (1.1897314953572317650E+4932L) +# define LDBL_MIN (3.3621031431120935063E-4932L) +# define LDBL_TRUE_MIN (3.6451995318824746025E-4951L) +# define LDBL_MAX_EXP (-16381) +# define LDBL_MIN_EXP (16384) +# define LDBL_MAX_10_EXP (4932) +# define LDBL_MIN_10_EXP (-4931) +# define LDBL_EPSILON (1.0842021724855044340E-19L) +# define LDBL_DIG (18) +# define LDBL_DECIMAL_DIG (21) +# define LDBL_MANT_DIG (64) +# define LDBL_HAS_SUBNORM (1) + +#endif + + +#endif /* !IPRT_INCLUDED_nocrt_float_h */ + diff --git a/include/iprt/nocrt/fstream b/include/iprt/nocrt/fstream new file mode 100644 index 00000000..1abd06eb --- /dev/null +++ b/include/iprt/nocrt/fstream @@ -0,0 +1,206 @@ +/** @file + * IPRT / No-CRT - Minimal C++ fstream header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_fstream +#define VBOX_INCLUDED_SRC_nocrt_fstream +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/nocrt/ostream> +#include <iprt/stream.h> + + +namespace std +{ + template<typename a_CharType, typename a_CharTraits /*= std::char_traits<a_CharType>*/ > + class basic_filebuf : public basic_streambuf<a_CharType, a_CharTraits> + { + protected: + PRTSTREAM m_pStrm; + bool m_fStdStream; + ios_base::openmode m_fMode; + + public: + basic_filebuf(PRTSTREAM a_pStrm = NULL, bool a_fStdStream = false) + : basic_streambuf() + , m_pStrm(a_pStrm) + , m_fStdStream(a_fStdStream) + , m_fMode(ios_base::openmode(0)) + { + } + + virtual ~basic_filebuf() + { + if (m_pStrm) + { + if (m_fStdStream) + RTStrmClose(m_pStrm); + m_pStrm = NULL; + } + } + + bool is_open() const RT_NOEXCEPT + { + return m_pStrm != NULL; + } + + basic_filebuf *open(const char *a_pszFilename, ios_base::openmode a_fMode) + { + /* + * Sanitize the a_fMode first. + */ + AssertReturn(!is_open(), NULL); + AssertReturn(a_fMode & (ios_base::out | ios_base::in), NULL); /* Neither write nor read mode? */ + AssertStmt((a_fMode & (ios_base::out | ios_base::app)) != ios_base::app, a_fMode &= ~ios_base::app); + AssertReturn((a_fMode & (ios_base::out | ios_base::trunc)) != ios_base::trunc, NULL); + AssertReturn(!(a_fMode & ios_base::trunc) || !(a_fMode & ios_base::app), NULL); + + /* + * Translate a_fMode into a stream mode string and try open the file. + */ + char szMode[8]; + szMode[0] = a_fMode & ios_base::trunc ? 'w' : a_fMode & ios_base::app ? 'a' : 'r'; + size_t offMode = 1; + if ((a_fMode & (ios_base::in | ios_base::out)) == (ios_base::in | ios_base::out)) + szMode[offMode++] = '+'; + if (a_fMode & ios_base::binary) + szMode[offMode++] = 'b'; + szMode[offMode] = '\0'; + + int rc = RTStrmOpen(a_pszFilename, szMode, &m_pStrm); + if (RT_SUCCESS(rc)) + { + /** @todo if (a_fMode & ios_base::ate)? */ + + /* + * Set up the buffer? + */ + if (true) + { + return this; + } + + RTStrmClose(m_pStrm); + m_pStrm = NULL; + } + return NULL; + } + + protected: + bool flushBuffered() + { + /** @todo buffering. */ + return true; + } + + //virtual int_type overflow(int_type a_iChar) RT_OVERRIDE + //{ + // if (a_iChar != traits_type::eof()) + // { + // if (flushBuffered()) + // { + // char_type ch = traits_type::to_char_type(a_iChar); + // int rc = RTStrmWrite(m_pStrm, &ch, sizeof(ch)); + // if (RT_SUCCESS(rc)) + // return a_iChar; + // } + // } + // return traits_type::eof(); + //} + + std::streamsize xsputn(char_type const *a_pchSrc, std::streamsize a_cchSrc) //RT_OVERRIDE + { + if (flushBuffered()) + { + size_t cbWritten = 0; + int rc = RTStrmWriteEx(m_pStrm, &a_pchSrc, sizeof(a_pchSrc[0]) * a_cchSrc, &cbWritten); + if (RT_SUCCESS(rc)) + return cbWritten / sizeof(a_pchSrc[0]); + } + return 0; + } + }; + + + /** + * Basic I/O stream. + */ + template<typename a_CharType, typename a_CharTraits /*= std::char_traits<a_CharType>*/ > + class basic_ofstream : public basic_ostream<a_CharType, a_CharTraits> + { + protected: + basic_filebuf<a_CharType, a_CharTraits> m_FileBuf; + + public: + basic_ofstream() + : basic_ostream(&m_FileBuf) /** @todo m_FileBuf isn't initialized yet... */ + , m_FileBuf() + { + } + + explicit basic_ofstream(const char *a_pszFilename, ios_base::openmode a_fMode = ios_base::out) + : basic_ostream(&m_FileBuf) /** @todo m_FileBuf isn't initialized yet... */ + , m_FileBuf() + { + m_FileBuf.open(a_pszFilename, a_fMode); + } + private: + basic_ofstream(basic_ofstream const &a_rSrc); /* no copying */ + basic_ofstream &operator=(basic_ofstream const &a_rSrc); /* no copying */ + + public: + virtual ~basic_ofstream() + { + } + + public: + + bool is_open() const RT_NOEXCEPT + { + return m_FileBuf.is_open(); + } + + basic_filebuf<a_CharType, a_CharTraits> *open(const char *a_pszFilename, ios_base::openmode a_fMode) + { + return m_FileBuf.open(a_pszFilename, a_fMode); + } + + + }; +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_fstream */ + diff --git a/include/iprt/nocrt/inttypes.h b/include/iprt/nocrt/inttypes.h new file mode 100644 index 00000000..cb2265c8 --- /dev/null +++ b/include/iprt/nocrt/inttypes.h @@ -0,0 +1,75 @@ +/** @file + * IPRT / No-CRT - Our minimal inttypes.h. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_inttypes_h +#define IPRT_INCLUDED_nocrt_inttypes_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +#define PRId8 "RI8" +#define PRIi8 "RI8" +#define PRIx8 "RX8" +#define PRIu8 "RU8" +#define PRIo8 huh? anyone using this? great! + +#define PRId16 "RI16" +#define PRIi16 "RI16" +#define PRIx16 "RX16" +#define PRIu16 "RU16" +#define PRIo16 huh? anyone using this? great! + +#define PRId32 "RI32" +#define PRIi32 "RI32" +#define PRIx32 "RX32" +#define PRIu32 "RU32" +#define PRIo32 huh? anyone using this? great! + +#define PRId64 "RI64" +#define PRIi64 "RI64" +#define PRIx64 "RX64" +#define PRIu64 "RU64" +#define PRIo64 huh? anyone using this? great! + +#define PRIdMAX "RI64" +#define PRIiMAX "RI64" +#define PRIxMAX "RX64" +#define PRIuMAX "RU64" +#define PRIoMAX huh? anyone using this? great! + +#endif /* !IPRT_INCLUDED_nocrt_inttypes_h */ + diff --git a/include/iprt/nocrt/io.h b/include/iprt/nocrt/io.h new file mode 100644 index 00000000..f8d42941 --- /dev/null +++ b/include/iprt/nocrt/io.h @@ -0,0 +1,48 @@ +/** @file + * IPRT / No-CRT - io.h (DOS, OS/2, Windows compilers). + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_io_h +#define IPRT_INCLUDED_nocrt_io_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/nocrt/fcntl.h> +#include <iprt/nocrt/sys/stat.h> +#include <iprt/nocrt/unistd.h> + + +#endif /* !IPRT_INCLUDED_nocrt_io_h */ + diff --git a/include/iprt/nocrt/iomanip b/include/iprt/nocrt/iomanip new file mode 100644 index 00000000..29c651e9 --- /dev/null +++ b/include/iprt/nocrt/iomanip @@ -0,0 +1,166 @@ +/** @file + * IPRT / No-CRT - Minimal C++ iomanip header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_iomanip +#define VBOX_INCLUDED_SRC_nocrt_iomanip +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/nocrt/ios> + + +namespace std +{ + /** + * Used by all flag manipulators. + */ + struct rtNoCrtIosSetFlagsEx + { + ios_base::fmtflags m_fSet; + ios_base::fmtflags m_fMask; + }; + + template<typename a_CharType, typename a_CharTraits> + inline basic_istream<a_CharType, a_CharTraits> &operator>>(basic_istream<a_CharType, a_CharTraits> &a_rSrc, + struct rtNoCrtIosSetFlagsEx a_Change) + { + a_rSrc.setf(a_Change.m_fSet, a_Change.m_fMask); + return a_rSrc; + } + + template<typename a_CharType, typename a_CharTraits> + inline basic_ostream<a_CharType, a_CharTraits> &operator<<(basic_ostream<a_CharType, a_CharTraits> &a_rDst, + struct rtNoCrtIosSetFlagsEx a_Change) + { + a_rDst.setf(a_Change.m_fSet, a_Change.m_fMask); + return a_rDst; + } + + + /* + * Flag modification functions. + */ + + inline struct rtNoCrtIosSetFlagsEx setiosflags(ios_base::fmtflags a_fFlags) + { + struct rtNoCrtIosSetFlagsEx Ret = { a_fFlags, a_fFlags }; + return Ret; + } + + inline struct rtNoCrtIosSetFlagsEx resetiosflags(ios_base::fmtflags a_fFlags) + { + struct rtNoCrtIosSetFlagsEx Ret = { ios_base::fmtflags(0), a_fFlags }; + return Ret; + } + + inline struct rtNoCrtIosSetFlagsEx setbase(int a_iBase) + { + struct rtNoCrtIosSetFlagsEx Ret = + { + a_iBase == 10 ? ios_base::dec + : a_iBase == 16 ? ios_base::hex + : a_iBase == 8 ? ios_base::oct + : ios_base::fmtflags(0), + ios_base::basefield + }; + return Ret; + } + + /* + * Modify precision. + */ + struct rtNoCrtIosSetPrecision + { + int m_cchPrecision; + }; + + template<typename a_CharType, typename a_CharTraits> + inline basic_istream<a_CharType, a_CharTraits> &operator>>(basic_istream<a_CharType, a_CharTraits> &a_rSrc, + struct rtNoCrtIosSetPrecision a_Change) + { + a_rSrc.precision(a_Change.m_cchPrecision); + return a_rSrc; + } + + template<typename a_CharType, typename a_CharTraits> + inline basic_ostream<a_CharType, a_CharTraits> &operator<<(basic_ostream<a_CharType, a_CharTraits> &a_rDst, + struct rtNoCrtIosSetPrecision a_Change) + { + a_rDst.precision(a_Change.m_cchPrecision); + return a_rDst; + } + + inline struct rtNoCrtIosSetPrecision setprecision(int a_cchPrecision) + { + struct rtNoCrtIosSetPrecision Ret = { a_cchPrecision }; + return Ret; + } + + /* + * Modify width. + */ + struct rtNoCrtIosSetWidth + { + int m_cchWidth; + }; + + template<typename a_CharType, typename a_CharTraits> + inline basic_istream<a_CharType, a_CharTraits> &operator>>(basic_istream<a_CharType, a_CharTraits> &a_rSrc, + struct rtNoCrtIosSetWidth a_Change) + { + a_rSrc.width(a_Change.m_cchWidth); + return a_rSrc; + } + + template<typename a_CharType, typename a_CharTraits> + inline basic_ostream<a_CharType, a_CharTraits> &operator<<(basic_ostream<a_CharType, a_CharTraits> &a_rDst, + struct rtNoCrtIosSetWidth a_Change) + { + a_rDst.width(a_Change.m_cchWidth); + return a_rDst; + } + + inline struct rtNoCrtIosSetWidth setw(int a_cchWidth) + { + struct rtNoCrtIosSetWidth Ret = { a_cchWidth }; + return Ret; + } + + /** @todo setfil, get_money, set_money, get_time, set_time */ +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_iomanip */ + diff --git a/include/iprt/nocrt/ios b/include/iprt/nocrt/ios new file mode 100644 index 00000000..9e49eaa9 --- /dev/null +++ b/include/iprt/nocrt/ios @@ -0,0 +1,525 @@ +/** @file + * IPRT / No-CRT - Minimal C++ ios header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_ios +#define VBOX_INCLUDED_SRC_nocrt_ios +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/nocrt/iosfwd> +#include <iprt/nocrt/string> + +/** @todo something for cdecl.h */ +#define RTNOCRT_IOS_ENUM_BIT_OPS(a_EnumType, a_IntType) \ + inline a_EnumType operator~(a_EnumType a_fLeft) RT_NOEXCEPT \ + { return a_EnumType(~static_cast<a_IntType>(a_fLeft)); } \ + \ + inline a_EnumType operator&(a_EnumType a_fLeft, a_EnumType a_fRight) RT_NOEXCEPT \ + { return a_EnumType(static_cast<a_IntType>(a_fLeft) & static_cast<a_IntType>(a_fRight)); } \ + inline a_EnumType operator|(a_EnumType a_fLeft, a_EnumType a_fRight) RT_NOEXCEPT \ + { return a_EnumType(static_cast<a_IntType>(a_fLeft) | static_cast<a_IntType>(a_fRight)); } \ + inline a_EnumType operator^(a_EnumType a_fLeft, a_EnumType a_fRight) RT_NOEXCEPT \ + { return a_EnumType(static_cast<a_IntType>(a_fLeft) ^ static_cast<a_IntType>(a_fRight)); } \ + \ + inline const a_EnumType &operator&=(a_EnumType &a_rfLeft, a_EnumType a_fRight) RT_NOEXCEPT \ + { return a_rfLeft = a_rfLeft & a_fRight; } \ + inline const a_EnumType &operator|=(a_EnumType &a_rfLeft, a_EnumType a_fRight) RT_NOEXCEPT \ + { return a_rfLeft = a_rfLeft | a_fRight; } \ + inline const a_EnumType &operator^=(a_EnumType &a_rfLeft, a_EnumType a_fRight) RT_NOEXCEPT \ + { return a_rfLeft = a_rfLeft ^ a_fRight; } \ + +namespace std +{ + typedef ptrdiff_t streamsize; + + /** + * I/O stream format flags. + */ + class rtNoCrtIosEnums + { + public: + enum fmtflags + { + /* int: */ + dec = 0x00000001, + oct = 0x00000002, + hex = 0x00000004, + basefield = 0x00000007, + /* float: */ + scientific = 0x00000010, + fixed = 0x00000020, + floatfield = 0x00000030, + /* int and float output tweaks: */ + showbase = 0x00000100, + showpoint = 0x00000200, + showpos = 0x00000400, + /* bool: */ + boolalpha = 0x00000800, + /* adjustment: */ + left = 0x00001000, + right = 0x00002000, + internal = 0x00004000, + adjustfield = 0x00007000, + /* misc: */ + skipws = 0x00010000, + unitbuf = 0x00020000, + uppercase = 0x00040000, + }; + + enum seekdir + { + beg = 1, + end, + cur, + }; + + enum openmode + { + app = 1, + binary, + in, + out, + trunc, + ate + }; + + enum iostate + { + goodbit = 0, + badbit = 1, + failbit = 2, + eofbit = 4 + }; + }; + RTNOCRT_IOS_ENUM_BIT_OPS(rtNoCrtIosEnums::fmtflags, int) + RTNOCRT_IOS_ENUM_BIT_OPS(rtNoCrtIosEnums::seekdir, int) + RTNOCRT_IOS_ENUM_BIT_OPS(rtNoCrtIosEnums::openmode, int) + RTNOCRT_IOS_ENUM_BIT_OPS(rtNoCrtIosEnums::iostate, int) + + + /** + * I/O stream base class. + */ + class ios_base : public rtNoCrtIosEnums + { + public: + //typedef rtNoCrtIosFmtFlags fmtflags; + //typedef rtNoCrtIosSeekDir seekdir; + //typedef rtNoCrtIosOpenMode openmode; + //typedef rtNoCrtIosState iostate; + + protected: + streamsize m_cWidth; + streamsize m_cPrecision; + fmtflags m_fFlags; + iostate m_fState; + + protected: + ios_base() + : m_cWidth(0) + , m_cPrecision(0) + , m_fFlags(dec | skipws) + , m_fState(goodbit) + { + } + private: + ios_base(const ios_base &); /* not copyable */ + ios_base &operator=(const ios_base &); /* not copyable */ + + public: + virtual ~ios_base() + { + } + + streamsize width() const RT_NOEXCEPT + { + return m_cWidth; + } + + streamsize width(streamsize a_cWidth) RT_NOEXCEPT + { + streamsize cOldWidth = m_cWidth; + m_cWidth = a_cWidth; + return cOldWidth; + } + + streamsize precision() const RT_NOEXCEPT + { + return m_cPrecision; + } + + streamsize precision(streamsize a_cPrecision) RT_NOEXCEPT + { + streamsize cOldPrecision = m_cPrecision; + m_cPrecision = a_cPrecision; + return cOldPrecision; + } + + fmtflags flags() const RT_NOEXCEPT + { + return m_fFlags; + } + + fmtflags flags(fmtflags a_fNew) RT_NOEXCEPT + { + fmtflags const fOld = m_fFlags; + m_fFlags = a_fNew; + return fOld; + } + + fmtflags setf(fmtflags a_fAdd) RT_NOEXCEPT + { + fmtflags const fOld = m_fFlags; + m_fFlags = static_cast<fmtflags>(fOld | a_fAdd); + return fOld; + } + + fmtflags setf(fmtflags a_fAdd, fmtflags a_fMask) RT_NOEXCEPT + { + fmtflags const fOld = m_fFlags; + m_fFlags = static_cast<fmtflags>((fOld & ~a_fMask) | (a_fAdd & a_fMask)); + return fOld; + } + + void unsetf(fmtflags a_fClear) RT_NOEXCEPT + { + m_fFlags = static_cast<fmtflags>(m_fFlags & ~a_fClear); + } + }; + + + /** + * Stream buffer. + */ + template<typename a_CharType, typename a_CharTraits /*= std::char_traits<a_CharType>*/ > + class basic_streambuf + { + public: + typedef a_CharType char_type; + typedef a_CharTraits traits_type; + typedef typename a_CharTraits::int_type int_type; + typedef typename a_CharTraits::pos_type pos_type; + typedef typename a_CharTraits::off_type off_type; + + protected: + /** @name Put buffering + * @{ */ + char_type *m_pachPut; /**< The put buffer pointer. */ + std::size_t m_cchPut; /**< Put buffer size. */ + std::size_t m_offPutNext; /**< The current put buffer position (where to write next). */ + std::size_t m_offPutStart; /**< Where the buffered put sequence starts. */ + + void setp(char_type *a_pachNewBuf, char_type *a_pachNewBufEnd) + { + Assert((uintptr_t)a_pachNewBuf <= (uintptr_t)a_pachNewBufEnd); + m_pachPut = a_pachNewBuf; + m_cchPut = static_cast<std::size_t>(a_pachNewBufEnd - a_pachNewBuf); + m_offPutNext = 0; + m_offPutStart = 0; + } + + char_type *pbbase() const RT_NOEXCEPT + { + Assert(m_offPutNext >= m_offPutStart); Assert(m_offPutNext <= m_cchPut); Assert(m_offPutStart <= m_cchPut); + return &m_pachPut[m_offPutStart]; + } + + char_type *pptr() const RT_NOEXCEPT + { + Assert(m_offPutNext <= m_cchPut); + return &m_pachPut[m_offPutNext]; + } + + char_type *epptr() const RT_NOEXCEPT + { + return &m_pachBuf[m_cchPut]; + } + + void pbump(int a_cchAdvance) const RT_NOEXCEPT + { + Assert(m_offPutNext <= m_cchPut); + m_offPutNext += a_cchAdvance; + Assert(m_offPutNext <= m_cchPut); + } + /** @} */ + + protected: + basic_streambuf() RT_NOEXCEPT + : m_pachPut(NULL) + , m_cchPut(0) + , m_offPutNext(0) + , m_offPutStart(0) + { + } + + basic_streambuf(const basic_streambuf &a_rSrc) RT_NOEXCEPT + : m_pachPut(a_rSrc.m_pachPut) + , m_cchPut(a_rSrc.m_cchPut) + , m_offPutNext(a_rSrc.m_offPutNext) + , m_offPutStart(a_rSrc.m_offPutStart) + { + } + + public: + virtual ~basic_streambuf() + { + } + + /** @name Positioning + * @{ */ + protected: + virtual basic_streambuf *setbuf(char_type *a_pchBuf, std::streamsize a_cchBuf) + { + RT_NOREF(a_pchBuf, a_cchBuf); + return this; + } + public: + basic_streambuf *pubsetbuf(char_type *a_pchBuf, std::streamsize a_cchBuf) + { + return setbuf(a_pchBuf, a_cchBuf); + } + + protected: + virtual pos_type seekoff(off_type a_off, std::ios_base::seekdir a_enmDir, + std::ios_base::openmode a_enmTarget = ios_base::in | ios_base::out) + { + RT_NOREF(a_off, a_enmDir, a_enmTarget); + return pos_type(off_type(-1)); + } + public: + pos_type pubseekoff(off_type a_off, std::ios_base::seekdir a_enmDir, + std::ios_base::openmode a_enmTarget = ios_base::in | ios_base::out) + { + return seekoff(a_off, a_enmDir, a_enmTarget); + } + + protected: + virtual pos_type seekpos(pos_type a_pos, std::ios_base::openmode a_enmTarget = ios_base::in | ios_base::out) + { + RT_NOREF(a_pos, a_enmTarget); + return pos_type(off_type(-1)); + } + public: + pos_type pubseekpos(pos_type a_pos, std::ios_base::openmode a_enmTarget = ios_base::in | ios_base::out) + { + return seekpos(a_pos, a_enmTarget); + } + + protected: + virtual int sync() + { + return 0; + } + public: + pos_type pubsync() + { + return sync(); + } + /** @} */ + + /** @name Output + * @{ */ + protected: + virtual int_type overflow(int_type a_iChar) + { + RT_NOREF(a_iChar); + return traits_type::eof(); + } + + virtual std::streamsize xsputn(char_type const *a_pchSrc, std::streamsize a_cchSrc) + { + std::streamsize cchWritten = 0; + while (a_cchSrc > 0) + { + std::size_t cchCopied = m_cchPut - m_offPutNext; + if (cchCopied > 0) + { + cchCopied = RT_MIN(cchCopied, static_cast<std::size_t>(a_cchSrc)); + traits_type::copy(&m_pachPut[m_offPutNext], a_pchSrc, cchCopied); + m_cchPut += cchCopied; + } + else + { + if (overflow(traits_type::to_int_type(m_pachPut[m_offPutNext])) != traits_type::eof()) + cchCopied = 1; + else + break; + } + a_pchSrc += cchCopied; + a_cchSrc -= cchCopied; + } + return cchWritten; + } + + public: + int_type sputc(char_type a_ch) + { + if (m_offPutNext < m_cchPut) + { + m_pachPut[m_offPutNext++] = a_ch; + return traits_type::to_int_type(a_ch); + } + return overflow(traits_type::to_int_type(a_ch)); + } + + std::streamsize sputn(char_type const *a_pchSrc, std::streamsize a_cchSrc) + { + AssertReturn(a_cchSrc >= 0, 0); + return xsputn(a_pchSrc, a_cchSrc); + } + + /** @} */ + + /** @todo add the remaining members... */ + }; + + + /** + * Basic I/O stream. + */ + template<typename a_CharType, typename a_CharTraits /*= std::char_traits<a_CharType>*/ > + class basic_ios : public ios_base + { + public: + typedef a_CharType char_type; + typedef a_CharTraits traits_type; + typedef typename a_CharTraits::int_type int_type; + typedef typename a_CharTraits::pos_type pos_type; + typedef typename a_CharTraits::off_type off_type; + + protected: + basic_streambuf<a_CharType, a_CharTraits> *m_pBuf; + basic_ostream<a_CharType, a_CharTraits> *m_pTiedStream; + + protected: + void init(std::basic_streambuf<a_CharType, a_CharTraits> *a_pBuf) + { + m_pBuf = a_pBuf; + m_cWidth = 0; + m_cPrecision = 6; + m_fFlags = ios_base::dec | ios_base::skipws; + m_fState = ios_base::goodbit; + } + + public: + basic_ios() + : ios_base() + , m_pBuf(NULL) + , m_pTiedStream(NULL) + { + } + + basic_ios(std::basic_streambuf<a_CharType, a_CharTraits> *a_pBuf) + : ios_base() + , m_pBuf(NULL) + , m_pTiedStream(NULL) + { + init(a_pBuf); + } + private: + basic_ios(const basic_ios &a_rSrc); /* not copyable */ + basic_ios &operator=(const basic_ios &a_rSrc); /* not copyable */ + + public: + virtual ~basic_ios() + { + } + + /** @name State methods + * @{ */ + bool good() const RT_NOEXCEPT { return m_fState == ios_base::goodbit; } + bool fail() const RT_NOEXCEPT { return (m_fState & (ios_base::failbit | ios_base::badbit)) != ios_base::goodbit; } + bool bad() const RT_NOEXCEPT { return (m_fState & ios_base::badbit) == ios_base::badbit; } + bool eof() const RT_NOEXCEPT { return (m_fState & ios_base::eofbit) != ios_base::eofbit; } +#if RT_CPLUSPLUS_PREREQ(201100) + operator bool() const RT_NOEXCEPT { return good(); } +#else + operator void*() const RT_NOEXCEPT { return good() ? NULL : this; } +#endif + bool operator!() const RT_NOEXCEPT { return fail(); } + + iostate rdstate() const RT_NOEXCEPT + { + return m_fState; + } + + void clear(iostate a_fNewState = goodbit) + { + m_fState = a_fNewState; + if (!m_pBuf) + m_fState |= badbit; + /** @todo failure exception */ + } + + void setstate(iostate a_fNewState) + { + clear(m_fState | a_fNewState); + } + /** @} */ + + /** @name Misc + * @{ */ + std::basic_streambuf<a_CharType, a_CharTraits> *rdbuf() const RT_NOEXCEPT + { + return m_pBuf; + } + + std::basic_streambuf<a_CharType, a_CharTraits> *rdbuf(std::basic_streambuf<a_CharType, a_CharTraits> *a_pNewbuf) RT_NOEXCEPT + { + std::basic_streambuf<a_CharType, a_CharTraits> *pOldBuf = m_pBuf; + m_pBuf = a_pNewBuf; + return pOldBuf; + } + + std::basic_ostream<a_CharType, a_CharTraits> *tie() const + { + return m_pTiedStream; + } + + std::basic_ostream<a_CharType, a_CharTraits> tie(std::basic_ostream<a_CharType, a_CharTraits> *a_pNew) const RT_NOEXCEPT + { + std::basic_ostream<a_CharType, a_CharTraits> * const pOld = m_pTiedStream; + m_pTiedStream = a_pNew; + return pOld; + } + /** @} */ + + /** @todo implement the rest... */ + }; +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_ios */ + diff --git a/include/iprt/nocrt/iosfwd b/include/iprt/nocrt/iosfwd new file mode 100644 index 00000000..835f4a5e --- /dev/null +++ b/include/iprt/nocrt/iosfwd @@ -0,0 +1,81 @@ +/** @file + * IPRT / No-CRT - Minimal C++ iosfwd header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_iosfwd +#define VBOX_INCLUDED_SRC_nocrt_iosfwd +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/nocrt/memory> +#include <iprt/nocrt/string> + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4643) /* warning C4643: Forward declaring 'ios_base' in namespace std is not permitted by the C++ Standard */ +#endif + +namespace std +{ + using streamoff = RTFOFF; + + class ios_base; + + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > class basic_ios; + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > class basic_streambuf; + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > class basic_istream; + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > class basic_ostream; + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > class basic_iostream; + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > class basic_ifstream; + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > class basic_ofstream; + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > class basic_fstream; + + + typedef basic_ios<char> ios; + typedef basic_streambuf<char> streambuf; + typedef basic_istream<char> istream; + typedef basic_ostream<char> ostream; + typedef basic_iostream<char> iostream; + typedef basic_ifstream<char> ifstream; + typedef basic_ofstream<char> ofstream; + typedef basic_fstream<char> fstream; +} + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !VBOX_INCLUDED_SRC_nocrt_iosfwd */ + diff --git a/include/iprt/nocrt/iostream b/include/iprt/nocrt/iostream new file mode 100644 index 00000000..d4997a99 --- /dev/null +++ b/include/iprt/nocrt/iostream @@ -0,0 +1,53 @@ +/** @file + * IPRT / No-CRT - Minimal C++ iostream header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_iostream +#define VBOX_INCLUDED_SRC_nocrt_iostream +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/nocrt/iosfwd> + +namespace std +{ + extern istream cin; + extern ostream cout; + extern ostream cerr; + extern ostream clog; /**< buffered cerr */ +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_iostream */ + diff --git a/include/iprt/nocrt/limits b/include/iprt/nocrt/limits new file mode 100644 index 00000000..0d414536 --- /dev/null +++ b/include/iprt/nocrt/limits @@ -0,0 +1,494 @@ +/** @file + * IPRT / No-CRT - C++ limits header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_limits +#define VBOX_INCLUDED_SRC_nocrt_limits +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/nocrt/limits.h> +#include <iprt/nocrt/float.h> + +namespace std +{ + enum float_denorm_style + { + denorm_indeterminate = -1, + denorm_absent, + denorm_present, + }; + + enum float_round_style + { + round_indeterminate = -1, + round_toward_zero, + round_to_nearest, + round_toward_infinity, + round_toward_neg_infinity, + }; + + struct rtNoCrtLimitNumericBase + { + static const bool is_specialized = false; + static const bool is_integer = false; + static const bool is_signed = false; + static const bool is_exact = false; + static const bool is_bounded = false; + + static const bool has_infinity = false; + static const bool has_quiet_NaN = false; + static const bool has_signaling_NaN = false; + static const bool has_denorm_loss = false; + static const bool is_iec559 = false; + static const bool is_modulo = false; + static const bool traps = false; + static const bool tinyness_before = false; + + static const int digits = 0; + static const int digits10 = 0; + static const int max_digits10 = 0; + static const int radix = 0; + static const int min_exponent = 0; + static const int min_exponent10 = 0; + static const int max_exponent = 0; + static const int max_exponent10 = 0; + + static const float_denorm_style has_denorm = denorm_absent; + static const float_round_style round_style = round_toward_zero; + }; + + struct rtNoCrtLimitNumericIntBase : public rtNoCrtLimitNumericBase + { + static const bool is_specialized = true; + static const bool is_integer = true; + static const bool is_exact = true; + static const bool is_bounded = true; + static const int radix = 2; + }; + + struct rtNoCrtLimitNumericFloatBase : public rtNoCrtLimitNumericBase + { + static const bool is_specialized = true; + static const bool is_signed = true; + static const bool is_bounded = true; + static const bool has_infinity = false; + static const bool has_quiet_NaN = false; + static const bool has_signaling_NaN = false; + static const bool is_iec559 = false; + static const int radix = FLT_RADIX; + static const float_denorm_style has_denorm = denorm_present; + static const float_round_style round_style = round_to_nearest; + }; + + /* + * Generic template. + */ + template<typename a_Type> + struct numeric_limits : public rtNoCrtLimitNumericBase + { + /** @todo need a RT_CONSTEXPR_FN etc */ + static constexpr a_Type(min)() RT_NOEXCEPT { return a_Type(); } + static constexpr a_Type(max)() RT_NOEXCEPT { return a_Type(); } + static constexpr a_Type lowest() RT_NOEXCEPT { return a_Type(); } + static constexpr a_Type epsilon() RT_NOEXCEPT { return a_Type(); } + static constexpr a_Type round_error() RT_NOEXCEPT { return a_Type(); } + static constexpr a_Type infinity() RT_NOEXCEPT { return a_Type(); } + static constexpr a_Type quiet_NaN() RT_NOEXCEPT { return a_Type(); } + static constexpr a_Type signaling_NaN() RT_NOEXCEPT { return a_Type(); } + static constexpr a_Type denorm_min() RT_NOEXCEPT { return a_Type(); } + }; + + /* const and volatile trickery: */ + template<typename a_Type> struct numeric_limits<const a_Type> : public numeric_limits<a_Type> {}; + template<typename a_Type> struct numeric_limits<volatile a_Type> : public numeric_limits<a_Type> {}; + template<typename a_Type> struct numeric_limits<const volatile a_Type> : public numeric_limits<a_Type> {}; + + /* + * Integer specializations. + */ + template<> + struct numeric_limits<bool> : public rtNoCrtLimitNumericIntBase + { + static constexpr bool(min)() RT_NOEXCEPT { return false; } + static constexpr bool(max)() RT_NOEXCEPT { return true; } + static constexpr bool lowest() RT_NOEXCEPT { return false; } + static constexpr bool epsilon() RT_NOEXCEPT { return false; } + static constexpr bool round_error() RT_NOEXCEPT { return false; } + static constexpr bool infinity() RT_NOEXCEPT { return false; } + static constexpr bool quiet_NaN() RT_NOEXCEPT { return false; } + static constexpr bool signaling_NaN() RT_NOEXCEPT { return false; } + static constexpr bool denorm_min() RT_NOEXCEPT { return false; } + static const int digits = 1; + }; + + template<> + struct numeric_limits<char> : public rtNoCrtLimitNumericIntBase + { + static constexpr char(min)() RT_NOEXCEPT { return CHAR_MIN; } + static constexpr char(max)() RT_NOEXCEPT { return CHAR_MAX; } + static constexpr char lowest() RT_NOEXCEPT { return CHAR_MIN; } + static constexpr char epsilon() RT_NOEXCEPT { return 0; } + static constexpr char round_error() RT_NOEXCEPT { return 0; } + static constexpr char infinity() RT_NOEXCEPT { return 0; } + static constexpr char quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr char signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr char denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_signed = (char)(-1) < 0; + static const bool is_modulo = (char)(-1) > 0; + static const int digits = (char)(-1) < 0 ? CHAR_BIT - 1 : CHAR_BIT; + static const int digits10 = 2; + }; + + template<> + struct numeric_limits<signed char> : public rtNoCrtLimitNumericIntBase + { + static constexpr signed char(min)() RT_NOEXCEPT { return SCHAR_MIN; } + static constexpr signed char(max)() RT_NOEXCEPT { return SCHAR_MAX; } + static constexpr signed char lowest() RT_NOEXCEPT { return SCHAR_MIN; } + static constexpr signed char epsilon() RT_NOEXCEPT { return 0; } + static constexpr signed char round_error() RT_NOEXCEPT { return 0; } + static constexpr signed char infinity() RT_NOEXCEPT { return 0; } + static constexpr signed char quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr signed char signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr signed char denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_signed = true; + static const int digits = CHAR_BIT - 1; + static const int digits10 = 2; + }; + + template<> + struct numeric_limits<unsigned char> : public rtNoCrtLimitNumericIntBase + { + static constexpr unsigned char(min)() RT_NOEXCEPT { return 0; } + static constexpr unsigned char(max)() RT_NOEXCEPT { return UCHAR_MAX; } + static constexpr unsigned char lowest() RT_NOEXCEPT { return 0; } + static constexpr unsigned char epsilon() RT_NOEXCEPT { return 0; } + static constexpr unsigned char round_error() RT_NOEXCEPT { return 0; } + static constexpr unsigned char infinity() RT_NOEXCEPT { return 0; } + static constexpr unsigned char quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned char signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned char denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_modulo = true; + static const int digits = CHAR_BIT; + static const int digits10 = 2; + }; + + /** @todo wchar_t, char8_t, char16_t, char32_t */ + + template<> + struct numeric_limits<short> : public rtNoCrtLimitNumericIntBase + { + static constexpr short(min)() RT_NOEXCEPT { return SHRT_MIN; } + static constexpr short(max)() RT_NOEXCEPT { return SHRT_MAX; } + static constexpr short lowest() RT_NOEXCEPT { return SHRT_MIN; } + static constexpr short epsilon() RT_NOEXCEPT { return 0; } + static constexpr short round_error() RT_NOEXCEPT { return 0; } + static constexpr short infinity() RT_NOEXCEPT { return 0; } + static constexpr short quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr short signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr short denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_signed = true; + static const int digits = CHAR_BIT * sizeof(short) - 1; + static const int digits10 = 4; + }; + + template<> + struct numeric_limits<unsigned short> : public rtNoCrtLimitNumericIntBase + { + static constexpr unsigned short(min)() RT_NOEXCEPT { return 0; } + static constexpr unsigned short(max)() RT_NOEXCEPT { return USHRT_MAX; } + static constexpr unsigned short lowest() RT_NOEXCEPT { return 0; } + static constexpr unsigned short epsilon() RT_NOEXCEPT { return 0; } + static constexpr unsigned short round_error() RT_NOEXCEPT { return 0; } + static constexpr unsigned short infinity() RT_NOEXCEPT { return 0; } + static constexpr unsigned short quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned short signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned short denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_modulo = true; + static const int digits = CHAR_BIT * sizeof(unsigned short); + static const int digits10 = 4; + }; + +# if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) + template<> + struct numeric_limits<wchar_t> : public rtNoCrtLimitNumericIntBase + { + static constexpr wchar_t(min)() RT_NOEXCEPT { return WCHAR_MIN; } + static constexpr wchar_t(max)() RT_NOEXCEPT { return WCHAR_MAX; } + static constexpr wchar_t lowest() RT_NOEXCEPT { return WCHAR_MIN; } + static constexpr wchar_t epsilon() RT_NOEXCEPT { return 0; } + static constexpr wchar_t round_error() RT_NOEXCEPT { return 0; } + static constexpr wchar_t infinity() RT_NOEXCEPT { return 0; } + static constexpr wchar_t quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr wchar_t signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr wchar_t denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_modulo = true; + static const int digits = CHAR_BIT * sizeof(wchar_t); + static const int digits10 = sizeof(wchar_t) == 2 ? 4 : 9; /** @todo ASSUMES wchar_t is either 16 or 32 bits */ + }; +# endif + + template<> + struct numeric_limits<char16_t> : public rtNoCrtLimitNumericIntBase + { + static constexpr char16_t(min)() RT_NOEXCEPT { return 0; } + static constexpr char16_t(max)() RT_NOEXCEPT { return USHRT_MAX; } + static constexpr char16_t lowest() RT_NOEXCEPT { return 0; } + static constexpr char16_t epsilon() RT_NOEXCEPT { return 0; } + static constexpr char16_t round_error() RT_NOEXCEPT { return 0; } + static constexpr char16_t infinity() RT_NOEXCEPT { return 0; } + static constexpr char16_t quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr char16_t signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr char16_t denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_modulo = true; + static const int digits = CHAR_BIT * sizeof(char16_t); + static const int digits10 = 4; + }; + + template<> + struct numeric_limits<int> : public rtNoCrtLimitNumericIntBase + { + static constexpr int(min)() RT_NOEXCEPT { return INT_MIN; } + static constexpr int(max)() RT_NOEXCEPT { return INT_MAX; } + static constexpr int lowest() RT_NOEXCEPT { return INT_MIN; } + static constexpr int epsilon() RT_NOEXCEPT { return 0; } + static constexpr int round_error() RT_NOEXCEPT { return 0; } + static constexpr int infinity() RT_NOEXCEPT { return 0; } + static constexpr int quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr int signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr int denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_signed = true; + static const int digits = CHAR_BIT * sizeof(int) - 1; + static const int digits10 = 9; + }; + + template<> + struct numeric_limits<unsigned int> : public rtNoCrtLimitNumericIntBase + { + static constexpr unsigned int(min)() RT_NOEXCEPT { return 0; } + static constexpr unsigned int(max)() RT_NOEXCEPT { return UINT_MAX; } + static constexpr unsigned int lowest() RT_NOEXCEPT { return 0; } + static constexpr unsigned int epsilon() RT_NOEXCEPT { return 0; } + static constexpr unsigned int round_error() RT_NOEXCEPT { return 0; } + static constexpr unsigned int infinity() RT_NOEXCEPT { return 0; } + static constexpr unsigned int quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned int signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned int denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_modulo = true; + static const int digits = CHAR_BIT * sizeof(unsigned int); + static const int digits10 = 9; + }; + + template<> + struct numeric_limits<char32_t> : public rtNoCrtLimitNumericIntBase + { + static constexpr char32_t(min)() RT_NOEXCEPT { return 0; } + static constexpr char32_t(max)() RT_NOEXCEPT { return UINT_MAX; } + static constexpr char32_t lowest() RT_NOEXCEPT { return 0; } + static constexpr char32_t epsilon() RT_NOEXCEPT { return 0; } + static constexpr char32_t round_error() RT_NOEXCEPT { return 0; } + static constexpr char32_t infinity() RT_NOEXCEPT { return 0; } + static constexpr char32_t quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr char32_t signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr char32_t denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_modulo = true; + static const int digits = CHAR_BIT * sizeof(char32_t); + static const int digits10 = 9; + }; + + template<> + struct numeric_limits<long> : public rtNoCrtLimitNumericIntBase + { + static constexpr long(min)() RT_NOEXCEPT { return LONG_MIN; } + static constexpr long(max)() RT_NOEXCEPT { return LONG_MAX; } + static constexpr long lowest() RT_NOEXCEPT { return LONG_MIN; } + static constexpr long epsilon() RT_NOEXCEPT { return 0; } + static constexpr long round_error() RT_NOEXCEPT { return 0; } + static constexpr long infinity() RT_NOEXCEPT { return 0; } + static constexpr long quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr long signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr long denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_signed = true; + static const int digits = CHAR_BIT * sizeof(long) - 1; + static const int digits10 = sizeof(long) == sizeof(int) ? 9 : 18; + }; + + template<> + struct numeric_limits<unsigned long> : public rtNoCrtLimitNumericIntBase + { + static constexpr unsigned long(min)() RT_NOEXCEPT { return 0; } + static constexpr unsigned long(max)() RT_NOEXCEPT { return ULONG_MAX; } + static constexpr unsigned long lowest() RT_NOEXCEPT { return 0; } + static constexpr unsigned long epsilon() RT_NOEXCEPT { return 0; } + static constexpr unsigned long round_error() RT_NOEXCEPT { return 0; } + static constexpr unsigned long infinity() RT_NOEXCEPT { return 0; } + static constexpr unsigned long quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned long signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned long denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_modulo = true; + static const int digits = CHAR_BIT * sizeof(unsigned long); + static const int digits10 = sizeof(unsigned long) == sizeof(unsigned int) ? 9 : 19; + }; + + template<> + struct numeric_limits<long long> : public rtNoCrtLimitNumericIntBase + { + static constexpr long long(min)() RT_NOEXCEPT { return LLONG_MIN; } + static constexpr long long(max)() RT_NOEXCEPT { return LLONG_MAX; } + static constexpr long long lowest() RT_NOEXCEPT { return LLONG_MIN; } + static constexpr long long epsilon() RT_NOEXCEPT { return 0; } + static constexpr long long round_error() RT_NOEXCEPT { return 0; } + static constexpr long long infinity() RT_NOEXCEPT { return 0; } + static constexpr long long quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr long long signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr long long denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_signed = true; + static const int digits = CHAR_BIT * sizeof(long long) - 1; + static const int digits10 = 18; + }; + + template<> + struct numeric_limits<unsigned long long> : public rtNoCrtLimitNumericIntBase + { + static constexpr unsigned long long(min)() RT_NOEXCEPT { return 0; } + static constexpr unsigned long long(max)() RT_NOEXCEPT { return ULLONG_MAX; } + static constexpr unsigned long long lowest() RT_NOEXCEPT { return 0; } + static constexpr unsigned long long epsilon() RT_NOEXCEPT { return 0; } + static constexpr unsigned long long round_error() RT_NOEXCEPT { return 0; } + static constexpr unsigned long long infinity() RT_NOEXCEPT { return 0; } + static constexpr unsigned long long quiet_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned long long signaling_NaN() RT_NOEXCEPT { return 0; } + static constexpr unsigned long long denorm_min() RT_NOEXCEPT { return 0; } + + static const bool is_modulo = true; + static const int digits = CHAR_BIT * sizeof(unsigned long long); + static const int digits10 = 19; + }; + + + /* + * Floating point. + */ + template<> + struct numeric_limits<float> : public rtNoCrtLimitNumericFloatBase + { + static constexpr float(min)() RT_NOEXCEPT { return FLT_MIN; } + static constexpr float(max)() RT_NOEXCEPT { return FLT_MAX; } + static constexpr float lowest() RT_NOEXCEPT { return -(FLT_MAX); } + static constexpr float epsilon() RT_NOEXCEPT { return FLT_EPSILON; } + static constexpr float round_error() RT_NOEXCEPT { return 0.5F; } + static constexpr float infinity() RT_NOEXCEPT { return __builtin_huge_valf(); } + static constexpr float quiet_NaN() RT_NOEXCEPT { return __builtin_nanf("0"); } + static constexpr float signaling_NaN() RT_NOEXCEPT { return __builtin_nansf("1"); } + static constexpr float denorm_min() RT_NOEXCEPT { return FLT_TRUE_MIN; } + + static const int digits = FLT_MANT_DIG; + static const int digits10 = FLT_DIG; + static const int max_digits10 = FLT_DECIMAL_DIG; + static const int max_exponent = FLT_MAX_EXP; + static const int max_exponent10 = FLT_MAX_10_EXP; + static const int min_exponent = FLT_MIN_EXP; + static const int min_exponent10 = FLT_MIN_10_EXP; + }; + + template<> + struct numeric_limits<double> : public rtNoCrtLimitNumericFloatBase + { + static constexpr double(min)() RT_NOEXCEPT { return DBL_MIN; } + static constexpr double(max)() RT_NOEXCEPT { return DBL_MAX; } + static constexpr double lowest() RT_NOEXCEPT { return -(DBL_MAX); } + static constexpr double epsilon() RT_NOEXCEPT { return DBL_EPSILON; } + static constexpr double round_error() RT_NOEXCEPT { return 0.5; } + static constexpr double infinity() RT_NOEXCEPT { return __builtin_huge_val(); } + static constexpr double quiet_NaN() RT_NOEXCEPT { return __builtin_nan("0"); } + static constexpr double signaling_NaN() RT_NOEXCEPT { return __builtin_nans("1"); } + static constexpr double denorm_min() RT_NOEXCEPT { return DBL_TRUE_MIN; } + + static const int digits = DBL_MANT_DIG; + static const int digits10 = DBL_DIG; + static const int max_digits10 = DBL_DECIMAL_DIG; + static const int max_exponent = DBL_MAX_EXP; + static const int max_exponent10 = DBL_MAX_10_EXP; + static const int min_exponent = DBL_MIN_EXP; + static const int min_exponent10 = DBL_MIN_10_EXP; + }; + + template<> + struct numeric_limits<long double> : public rtNoCrtLimitNumericFloatBase + { + static constexpr long double(min)() RT_NOEXCEPT { return LDBL_MIN; } + static constexpr long double(max)() RT_NOEXCEPT { return LDBL_MAX; } + static constexpr long double lowest() RT_NOEXCEPT { return -(LDBL_MAX); } + static constexpr long double epsilon() RT_NOEXCEPT { return LDBL_EPSILON; } + static constexpr long double round_error() RT_NOEXCEPT { return 0.5L; } +#if LDBL_DIG == DBL_DIG + static constexpr long double infinity() RT_NOEXCEPT { return __builtin_huge_val(); } + static constexpr long double quiet_NaN() RT_NOEXCEPT { return __builtin_nan("0"); } + static constexpr long double signaling_NaN() RT_NOEXCEPT { return __builtin_nans("1"); } +#else + static constexpr long double infinity() RT_NOEXCEPT { return __builtin_huge_vall(); } + static constexpr long double quiet_NaN() RT_NOEXCEPT { return __builtin_nanl("0"); } + static constexpr long double signaling_NaN() RT_NOEXCEPT { return __builtin_nansl("1"); } +#endif + static constexpr long double denorm_min() RT_NOEXCEPT { return LDBL_TRUE_MIN; } + + static const int digits = LDBL_MANT_DIG; + static const int digits10 = LDBL_DIG; + static const int max_digits10 = LDBL_DECIMAL_DIG; + static const int max_exponent = LDBL_MAX_EXP; + static const int max_exponent10 = LDBL_MAX_10_EXP; + static const int min_exponent = LDBL_MIN_EXP; + static const int min_exponent10 = LDBL_MIN_10_EXP; + }; + + /** @todo more types */ +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_limits */ + diff --git a/include/iprt/nocrt/limits.h b/include/iprt/nocrt/limits.h new file mode 100644 index 00000000..7b2e060b --- /dev/null +++ b/include/iprt/nocrt/limits.h @@ -0,0 +1,109 @@ +/** @file + * IPRT / No-CRT - Our own limits header. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_limits_h +#define IPRT_INCLUDED_nocrt_limits_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +#define CHAR_BIT 8 +#define SCHAR_MAX 0x7f +#define SCHAR_MIN (-0x7f - 1) +#define UCHAR_MAX 0xff +#if 1 /* ASSUMES: signed char */ +# define CHAR_MAX SCHAR_MAX +# define CHAR_MIN SCHAR_MIN +#else +# define CHAR_MAX UCHAR_MAX +# define CHAR_MIN 0 +#endif + +#define WORD_BIT 16 +#define USHRT_MAX 0xffff +#define SHRT_MAX 0x7fff +#define SHRT_MIN (-0x7fff - 1) + +/* ASSUMES 32-bit int */ +#define UINT_MAX 0xffffffffU +#define INT_MAX 0x7fffffff +#define INT_MIN (-0x7fffffff - 1) + +#if defined(RT_ARCH_X86) || defined(RT_OS_WINDOWS) || defined(RT_ARCH_SPARC) || defined(RT_ARCH_ARM32) +# define LONG_BIT 32 +# define ULONG_MAX 0xffffffffU +# define LONG_MAX 0x7fffffff +# define LONG_MIN (-0x7fffffff - 1) +#elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_SPARC64) || defined(RT_ARCH_ARM64) +# define LONG_BIT 64 +# define ULONG_MAX UINT64_C(0xffffffffffffffff) +# define LONG_MAX INT64_C(0x7fffffffffffffff) +# define LONG_MIN (INT64_C(-0x7fffffffffffffff) - 1) +#else +# error "PORTME" +#endif + +#define LLONG_BIT 64 +#define ULLONG_MAX UINT64_C(0xffffffffffffffff) +#define LLONG_MAX INT64_C(0x7fffffffffffffff) +#define LLONG_MIN (INT64_C(-0x7fffffffffffffff) - 1) + +#undef SIZE_MAX +#undef SIZE_T_MAX +#undef SSIZE_MAX +#undef INTPTR_MAX +#undef UINTPTR_MAX +#if ARCH_BITS == 32 +# define SIZE_T_MAX 0xffffffffU +# define SSIZE_MAX 0x7fffffff +# define INTPTR_MAX 0x7fffffff +# define UINTPTR_MAX 0xffffffffU +#elif ARCH_BITS == 64 +# define SIZE_T_MAX UINT64_C(0xffffffffffffffff) +# define SSIZE_MAX INT64_C(0x7fffffffffffffff) +# define INTPTR_MAX INT64_C(0x7fffffffffffffff) +# define UINTPTR_MAX UINT64_C(0xffffffffffffffff) +#else +# error "huh?" +#endif +#define SIZE_MAX SIZE_T_MAX + +/*#define OFF_MAX __OFF_MAX +#define OFF_MIN __OFF_MIN*/ + +#endif /* !IPRT_INCLUDED_nocrt_limits_h */ + diff --git a/include/iprt/nocrt/malloc.h b/include/iprt/nocrt/malloc.h new file mode 100644 index 00000000..57c5aa4f --- /dev/null +++ b/include/iprt/nocrt/malloc.h @@ -0,0 +1,49 @@ +/** @file + * IPRT / No-CRT - Our own minimal malloc.h header (needed by xmmintrin.h). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_malloc_h +#define IPRT_INCLUDED_nocrt_malloc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Just map it onto stdlib.h and alloca.h for now. */ +#include <stdlib.h> +#ifdef IN_RING3 +# include <iprt/alloca.h> +#endif + +#endif /* !IPRT_INCLUDED_nocrt_malloc_h */ + diff --git a/include/iprt/nocrt/math.h b/include/iprt/nocrt/math.h new file mode 100644 index 00000000..4ae2c48c --- /dev/null +++ b/include/iprt/nocrt/math.h @@ -0,0 +1,859 @@ +/** @file + * IPRT / No-CRT - math.h. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + * -------------------------------------------------------------------- + * + * This code is based on: + * + * from: @(#)fdlibm.h 5.1 93/09/24 + * $FreeBSD: src/lib/msun/src/math.h,v 1.61 2005/04/16 21:12:47 das Exp $ + * FreeBSD HEAD 2005-06-xx + * + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef IPRT_INCLUDED_nocrt_math_h +#define IPRT_INCLUDED_nocrt_math_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +/*#include <machine/_limits.h>*/ + +/* from sys/cdefs.h */ +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +#define __GNUC_PREREQ__(ma, mi) \ + (__GNUC__ > (ma) || __GNUC__ == (ma) && __GNUC_MINOR__ >= (mi)) +#else +#define __GNUC_PREREQ__(ma, mi) 0 +#endif +#undef __pure2 /* darwin: avoid conflict with system headers when doing syntax checking of the headers */ +#define __pure2 + + +/* + * ANSI/POSIX + */ +extern const union __infinity_un { + RTFLOAT64U __uu; + double __ud; +} RT_NOCRT(__infinity); + +extern const union __nanf_un { + RTFLOAT32U __uu; + float __uf; +} RT_NOCRT(__nanf); + +#if __GNUC_PREREQ__(3, 3) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 800) +#define __MATH_BUILTIN_CONSTANTS +#endif + +#if __GNUC_PREREQ__(3, 0) && !defined(__INTEL_COMPILER) +#define __MATH_BUILTIN_RELOPS +#endif + +#ifndef IPRT_NOCRT_WITHOUT_CONFLICTING_CONSTANTS + +# if defined(__MATH_BUILTIN_CONSTANTS) \ + || (RT_MSC_PREREQ(RT_MSC_VER_VC140) && defined(__cplusplus)) /** @todo when was this added exactly? 2015, 2017 & 2019 has it for C++. */ +# define HUGE_VAL __builtin_huge_val() +# else +# define HUGE_VAL (RT_NOCRT(__infinity).__ud) +# endif + +/* + * XOPEN/SVID + */ +# if 1/* __BSD_VISIBLE || __XSI_VISIBLE*/ +# define M_E 2.7182818284590452354 /* e */ +# define M_LOG2E 1.4426950408889634074 /* log 2e */ +# define M_LOG10E 0.43429448190325182765 /* log 10e */ +# define M_LN2 0.69314718055994530942 /* log e2 */ +# define M_LN10 2.30258509299404568402 /* log e10 */ +# define M_PI 3.14159265358979323846 /* pi */ +# define M_PI_2 1.57079632679489661923 /* pi/2 */ +# define M_PI_4 0.78539816339744830962 /* pi/4 */ +# define M_1_PI 0.31830988618379067154 /* 1/pi */ +# define M_2_PI 0.63661977236758134308 /* 2/pi */ +# define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ +# define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +# define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ + +# define MAXFLOAT ((float)3.40282346638528860e+38) +extern int RT_NOCRT(signgam); +# endif /* __BSD_VISIBLE || __XSI_VISIBLE */ + +# if 1/* __BSD_VISIBLE*/ +# if 0 +/* Old value from 4.4BSD-Lite math.h; this is probably better. */ +# define HUGE HUGE_VAL +# else +# define HUGE MAXFLOAT +# endif +# endif /* __BSD_VISIBLE */ + +#endif /* !IPRT_NOCRT_WITHOUT_MATH_CONSTANTS */ + +/* + * Most of these functions depend on the rounding mode and have the side + * effect of raising floating-point exceptions, so they are not declared + * as __pure2. In C99, FENV_ACCESS affects the purity of these functions. + */ +RT_C_DECLS_BEGIN +/* + * ANSI/POSIX + */ +int RT_NOCRT(__fpclassifyd)(double) __pure2; +int RT_NOCRT(__fpclassifyf)(float) __pure2; +int RT_NOCRT(__fpclassifyl)(long double) __pure2; +int RT_NOCRT(__isfinitef)(float) __pure2; +int RT_NOCRT(__isfinite)(double) __pure2; +int RT_NOCRT(__isfinitel)(long double) __pure2; +int RT_NOCRT(__isinff)(float) __pure2; +int RT_NOCRT(__isinfl)(long double) __pure2; +int RT_NOCRT(__isnanl)(long double) __pure2; +int RT_NOCRT(__isnormalf)(float) __pure2; +int RT_NOCRT(__isnormal)(double) __pure2; +int RT_NOCRT(__isnormall)(long double) __pure2; +int RT_NOCRT(__signbit)(double) __pure2; +int RT_NOCRT(__signbitf)(float) __pure2; +int RT_NOCRT(__signbitl)(long double) __pure2; + +double RT_NOCRT(acos)(double); +double RT_NOCRT(asin)(double); +double RT_NOCRT(atan)(double); +double RT_NOCRT(atan2)(double, double); +double RT_NOCRT(cos)(double); +double RT_NOCRT(sin)(double); +double RT_NOCRT(tan)(double); + +double RT_NOCRT(cosh)(double); +double RT_NOCRT(sinh)(double); +double RT_NOCRT(tanh)(double); + +double RT_NOCRT(exp)(double); +double RT_NOCRT(frexp)(double, int *); /* fundamentally !__pure2 */ +double RT_NOCRT(ldexp)(double, int); +double RT_NOCRT(log)(double); +double RT_NOCRT(log10)(double); +double RT_NOCRT(modf)(double, double *); /* fundamentally !__pure2 */ + +double RT_NOCRT(pow)(double, double); +double RT_NOCRT(sqrt)(double); + +double RT_NOCRT(ceil)(double); +double RT_NOCRT(fabs)(double) __pure2; +double RT_NOCRT(floor)(double); +double RT_NOCRT(fmod)(double, double); + +/* + * These functions are not in C90. + */ +#if 1 /*__BSD_VISIBLE || __ISO_C_VISIBLE >= 1999 || __XSI_VISIBLE*/ +double RT_NOCRT(acosh)(double); +double RT_NOCRT(asinh)(double); +double RT_NOCRT(atanh)(double); +double RT_NOCRT(cbrt)(double); +double RT_NOCRT(erf)(double); +double RT_NOCRT(erfc)(double); +double RT_NOCRT(exp2)(double); +double RT_NOCRT(expm1)(double); +double RT_NOCRT(fma)(double, double, double); +double RT_NOCRT(hypot)(double, double); +int RT_NOCRT(ilogb)(double) __pure2; +int RT_NOCRT(isinf)(double) __pure2; +int RT_NOCRT(isnan)(double) __pure2; +double RT_NOCRT(lgamma)(double); +long long RT_NOCRT(llrint)(double); +long long RT_NOCRT(llround)(double); +double RT_NOCRT(log1p)(double); +double RT_NOCRT(logb)(double); +long RT_NOCRT(lrint)(double); +long RT_NOCRT(lround)(double); +double RT_NOCRT(nextafter)(double, double); +double RT_NOCRT(remainder)(double, double); +double RT_NOCRT(remquo)(double, double, int *); +double RT_NOCRT(rint)(double); +#endif /* __BSD_VISIBLE || __ISO_C_VISIBLE >= 1999 || __XSI_VISIBLE */ + +#if 1/* __BSD_VISIBLE || __XSI_VISIBLE*/ +double RT_NOCRT(j0)(double); +double RT_NOCRT(j1)(double); +double RT_NOCRT(jn)(int, double); +double RT_NOCRT(scalb)(double, double); +double RT_NOCRT(y0)(double); +double RT_NOCRT(y1)(double); +double RT_NOCRT(yn)(int, double); + +#if 1/* __XSI_VISIBLE <= 500 || __BSD_VISIBLE*/ +double RT_NOCRT(gamma)(double); +#endif +#endif /* __BSD_VISIBLE || __XSI_VISIBLE */ + +#if 1/* __BSD_VISIBLE || __ISO_C_VISIBLE >= 1999*/ +double RT_NOCRT(copysign)(double, double) __pure2; +double RT_NOCRT(fdim)(double, double); +double RT_NOCRT(fmax)(double, double) __pure2; +double RT_NOCRT(fmin)(double, double) __pure2; +double RT_NOCRT(nearbyint)(double); +double RT_NOCRT(round)(double); +double RT_NOCRT(scalbln)(double, long); +double RT_NOCRT(scalbn)(double, int); +double RT_NOCRT(tgamma)(double); +double RT_NOCRT(trunc)(double); +#endif + +/* + * BSD math library entry points + */ +#if 1/* __BSD_VISIBLE*/ +double RT_NOCRT(drem)(double, double); +int RT_NOCRT(finite)(double) __pure2; +int RT_NOCRT(isnanf)(float) __pure2; + +/* + * Reentrant version of gamma & lgamma; passes signgam back by reference + * as the second argument; user must allocate space for signgam. + */ +double RT_NOCRT(gamma_r)(double, int *); +double RT_NOCRT(lgamma_r)(double, int *); + +/* + * IEEE Test Vector + */ +double RT_NOCRT(significand)(double); +#endif /* __BSD_VISIBLE */ + +/* float versions of ANSI/POSIX functions */ +#if 1/* __ISO_C_VISIBLE >= 1999*/ +float RT_NOCRT(acosf)(float); +float RT_NOCRT(asinf)(float); +float RT_NOCRT(atanf)(float); +float RT_NOCRT(atan2f)(float, float); +float RT_NOCRT(cosf)(float); +float RT_NOCRT(sinf)(float); +float RT_NOCRT(tanf)(float); + +float RT_NOCRT(coshf)(float); +float RT_NOCRT(sinhf)(float); +float RT_NOCRT(tanhf)(float); + +float RT_NOCRT(exp2f)(float); +float RT_NOCRT(expf)(float); +float RT_NOCRT(expm1f)(float); +float RT_NOCRT(frexpf)(float, int *); /* fundamentally !__pure2 */ +int RT_NOCRT(ilogbf)(float) __pure2; +float RT_NOCRT(ldexpf)(float, int); +float RT_NOCRT(log10f)(float); +float RT_NOCRT(log1pf)(float); +float RT_NOCRT(logf)(float); +float RT_NOCRT(modff)(float, float *); /* fundamentally !__pure2 */ + +float RT_NOCRT(powf)(float, float); +float RT_NOCRT(sqrtf)(float); + +float RT_NOCRT(ceilf)(float); +float RT_NOCRT(fabsf)(float) __pure2; +float RT_NOCRT(floorf)(float); +float RT_NOCRT(fmodf)(float, float); +float RT_NOCRT(roundf)(float); + +float RT_NOCRT(erff)(float); +float RT_NOCRT(erfcf)(float); +float RT_NOCRT(hypotf)(float, float); +float RT_NOCRT(lgammaf)(float); + +float RT_NOCRT(acoshf)(float); +float RT_NOCRT(asinhf)(float); +float RT_NOCRT(atanhf)(float); +float RT_NOCRT(cbrtf)(float); +float RT_NOCRT(logbf)(float); +float RT_NOCRT(copysignf)(float, float) __pure2; +long long RT_NOCRT(llrintf)(float); +long long RT_NOCRT(llroundf)(float); +long RT_NOCRT(lrintf)(float); +long RT_NOCRT(lroundf)(float); +float RT_NOCRT(nearbyintf)(float); +float RT_NOCRT(nextafterf)(float, float); +float RT_NOCRT(remainderf)(float, float); +float RT_NOCRT(remquof)(float, float, int *); +float RT_NOCRT(rintf)(float); +float RT_NOCRT(scalblnf)(float, long); +float RT_NOCRT(scalbnf)(float, int); +float RT_NOCRT(truncf)(float); + +float RT_NOCRT(fdimf)(float, float); +float RT_NOCRT(fmaf)(float, float, float); +float RT_NOCRT(fmaxf)(float, float) __pure2; +float RT_NOCRT(fminf)(float, float) __pure2; +#endif + +/* + * float versions of BSD math library entry points + */ +#if 1/* __BSD_VISIBLE*/ +float RT_NOCRT(dremf)(float, float); +int RT_NOCRT(finitef)(float) __pure2; +float RT_NOCRT(gammaf)(float); +float RT_NOCRT(j0f)(float); +float RT_NOCRT(j1f)(float); +float RT_NOCRT(jnf)(int, float); +float RT_NOCRT(scalbf)(float, float); +float RT_NOCRT(y0f)(float); +float RT_NOCRT(y1f)(float); +float RT_NOCRT(ynf)(int, float); + +/* + * Float versions of reentrant version of gamma & lgamma; passes + * signgam back by reference as the second argument; user must + * allocate space for signgam. + */ +float RT_NOCRT(gammaf_r)(float, int *); +float RT_NOCRT(lgammaf_r)(float, int *); + +/* + * float version of IEEE Test Vector + */ +float RT_NOCRT(significandf)(float); +#endif /* __BSD_VISIBLE */ + +/* + * long double versions of ISO/POSIX math functions + */ +#if 1/* __ISO_C_VISIBLE >= 1999*/ +#if 1 /* bird: we've got these */ +long double RT_NOCRT(acoshl)(long double); +long double RT_NOCRT(acosl)(long double); +long double RT_NOCRT(asinhl)(long double); +long double RT_NOCRT(asinl)(long double); +long double RT_NOCRT(atan2l)(long double, long double); +long double RT_NOCRT(atanhl)(long double); +long double RT_NOCRT(atanl)(long double); +long double RT_NOCRT(cbrtl)(long double); +#endif +long double RT_NOCRT(ceill)(long double); +long double RT_NOCRT(copysignl)(long double, long double) __pure2; +#if 1 /* bird */ +long double RT_NOCRT(coshl)(long double); +long double RT_NOCRT(cosl)(long double); +long double RT_NOCRT(erfcl)(long double); +long double RT_NOCRT(erfl)(long double); +long double RT_NOCRT(exp2l)(long double); +long double RT_NOCRT(expl)(long double); +long double RT_NOCRT(expm1l)(long double); +#endif +long double RT_NOCRT(fabsl)(long double) __pure2; +long double RT_NOCRT(fdiml)(long double, long double); +long double RT_NOCRT(floorl)(long double); +long double RT_NOCRT(fmal)(long double, long double, long double); +long double RT_NOCRT(fmaxl)(long double, long double) __pure2; +long double RT_NOCRT(fminl)(long double, long double) __pure2; +#if 1 /* bird */ +long double RT_NOCRT(fmodl)(long double, long double); +#endif +long double RT_NOCRT(frexpl)(long double value, int *); /* fundamentally !__pure2 */ +#if 1 /* bird */ +long double RT_NOCRT(hypotl)(long double, long double); +#endif +int RT_NOCRT(ilogbl)(long double) __pure2; +long double RT_NOCRT(ldexpl)(long double, int); +#if 1 /* bird */ +long double RT_NOCRT(lgammal)(long double); +long long RT_NOCRT(llrintl)(long double); +#endif +long long RT_NOCRT(llroundl)(long double); +#if 1 /* bird */ +long double RT_NOCRT(log10l)(long double); +long double RT_NOCRT(log1pl)(long double); +long double RT_NOCRT(log2l)(long double); +long double RT_NOCRT(logbl)(long double); +long double RT_NOCRT(logl)(long double); +long RT_NOCRT(lrintl)(long double); +#endif +long RT_NOCRT(lroundl)(long double); +#if 1 /* bird */ +long double RT_NOCRT(modfl)(long double, long double *); /* fundamentally !__pure2 */ +long double RT_NOCRT(nanl)(const char *) __pure2; +long double RT_NOCRT(nearbyintl)(long double); +#endif +long double RT_NOCRT(nextafterl)(long double, long double); +double RT_NOCRT(nexttoward)(double, long double); +float RT_NOCRT(nexttowardf)(float, long double); +long double RT_NOCRT(nexttowardl)(long double, long double); +#if 1 /* bird */ +long double RT_NOCRT(powl)(long double, long double); +long double RT_NOCRT(remainderl)(long double, long double); +long double RT_NOCRT(remquol)(long double, long double, int *); +long double RT_NOCRT(rintl)(long double); +#endif +long double RT_NOCRT(roundl)(long double); +long double RT_NOCRT(scalblnl)(long double, long); +long double RT_NOCRT(scalbnl)(long double, int); +#if 1 /* bird: we 've got most of these. */ +long double RT_NOCRT(sinhl)(long double); +long double RT_NOCRT(sinl)(long double); +long double RT_NOCRT(sqrtl)(long double); +long double RT_NOCRT(tanhl)(long double); +long double RT_NOCRT(tanl)(long double); +long double RT_NOCRT(tgammal)(long double); +#endif +long double RT_NOCRT(truncl)(long double); + +/* bird: these were missing, gcc apparently inlines them. */ +double RT_NOCRT(nan)(const char *); +float RT_NOCRT(nanf)(const char *); + +#endif /* __ISO_C_VISIBLE >= 1999 */ + +#ifndef IPRT_NOCRT_WITHOUT_CONFLICTING_CONSTANTS /*def __USE_GNU*/ +/* + * In GLIBC there are long variants of the XOPEN/SVID constant + * block some pages ago. We need this to get the math tests going. + */ +# define M_El 2.7182818284590452353602874713526625L +# define M_LOG2El 1.4426950408889634073599246810018921L +# define M_LOG10El 0.4342944819032518276511289189166051L +# define M_LN2l 0.6931471805599453094172321214581766L +# define M_LN10l 2.3025850929940456840179914546843642L +# define M_PIl 3.1415926535897932384626433832795029L +# define M_PI_2l 1.5707963267948966192313216916397514L +# define M_PI_4l 0.7853981633974483096156608458198757L +# define M_1_PIl 0.3183098861837906715377675267450287L +# define M_2_PIl 0.6366197723675813430755350534900574L +# define M_2_SQRTPIl 1.1283791670955125738961589031215452L +# define M_SQRT2l 1.4142135623730950488016887242096981L +# define M_SQRT1_2l 0.7071067811865475244008443621048490L +#endif /* !IPRT_NOCRT_WITHOUT_MATH_CONSTANTS */ + +#if 1/*def __USE_GNU*/ + +void RT_NOCRT(sincos)(double, double *, double *); +void RT_NOCRT(sincosf)(float, float *, float *); +void RT_NOCRT(sincosl)(long double, long double *, long double *); +float RT_NOCRT(exp10f)(float); +double RT_NOCRT(exp10)(double); +long double RT_NOCRT(exp10l)(long double); +float RT_NOCRT(log2f)(float); +double RT_NOCRT(log2)(double); +long double RT_NOCRT(log2l)(long double); +float RT_NOCRT(tgammaf)(float); +long double RT_NOCRT(significandl)(long double); +long double RT_NOCRT(j0l)(long double); +long double RT_NOCRT(j1l)(long double); +long double RT_NOCRT(jnl)(int, long double); +long double RT_NOCRT(scalbl)(long double, long double); +long double RT_NOCRT(y0l)(long double); +long double RT_NOCRT(y1l)(long double); +long double RT_NOCRT(ynl)(int, long double); +long double RT_NOCRT(lgammal_r)(long double,int *); +long double RT_NOCRT(gammal)(long double); +#endif + + +RT_C_DECLS_END + + +/** @name fpclassify return values + * @{ */ +#define RT_NOCRT_FP_INFINITE 0x01 +#define RT_NOCRT_FP_NAN 0x02 +#define RT_NOCRT_FP_NORMAL 0x04 +#define RT_NOCRT_FP_SUBNORMAL 0x08 +#define RT_NOCRT_FP_ZERO 0x10 +/** @} */ + +/* bird 2022-08-03: moved this block down so we can prototype isnan & isinf without runnning into the macro forms. */ +#ifndef IPRT_NOCRT_WITHOUT_CONFLICTING_CONSTANTS /* __ISO_C_VISIBLE >= 1999*/ +# define FP_ILOGB0 (-__INT_MAX) +# define FP_ILOGBNAN __INT_MAX + +# ifdef __MATH_BUILTIN_CONSTANTS +# define HUGE_VALF __builtin_huge_valf() +# define HUGE_VALL __builtin_huge_vall() +# define INFINITY __builtin_inf() +# define NAN __builtin_nan("") +# elif RT_MSC_PREREQ(RT_MSC_VER_VC140) && defined(__cplusplus) +/** @todo When were these introduced exactly? 2015, 2017 & 2019 has them. + * However, they only work in C++ even if the c1.dll includes the strings. Oh, well. */ +# define HUGE_VALF __builtin_huge_valf() +# define HUGE_VALL __builtin_huge_val() +# define INFINITY __builtin_huge_val() +# define NAN __builtin_nan("0") /* same as we use in climits */ +# else +# define HUGE_VALF (float)HUGE_VAL +# define HUGE_VALL (long double)HUGE_VAL +# define INFINITY HUGE_VALF +# define NAN (__nanf.__uf) +# endif /* __MATH_BUILTIN_CONSTANTS */ + +# ifndef IPRT_NO_CRT +# define MATH_ERRNO 1 +# endif +# define MATH_ERREXCEPT 2 +# define math_errhandling MATH_ERREXCEPT + +/* XXX We need a <machine/math.h>. */ +# if defined(__ia64__) || defined(__sparc64__) +# define FP_FAST_FMA +# endif +# ifdef __ia64__ +# define FP_FAST_FMAL +# endif +# define FP_FAST_FMAF + +/* Symbolic constants to classify floating point numbers. */ +# define FP_INFINITE RT_NOCRT_FP_INFINITE +# define FP_NAN RT_NOCRT_FP_NAN +# define FP_NORMAL RT_NOCRT_FP_NORMAL +# define FP_SUBNORMAL RT_NOCRT_FP_SUBNORMAL +# define FP_ZERO RT_NOCRT_FP_ZERO +# define fpclassify(x) \ + ((sizeof (x) == sizeof (float)) ? RT_NOCRT(__fpclassifyf)(x) \ + : (sizeof (x) == sizeof (double)) ? RT_NOCRT(__fpclassifyd)(x) \ + : RT_NOCRT(__fpclassifyl)(x)) + +# define isfinite(x) \ + ((sizeof (x) == sizeof (float)) ? RT_NOCRT(__isfinitef)(x) \ + : (sizeof (x) == sizeof (double)) ? RT_NOCRT(__isfinite)(x) \ + : RT_NOCRT(__isfinitel)(x)) +# define isinf(x) \ + ((sizeof (x) == sizeof (float)) ? RT_NOCRT(__isinff)(x) \ + : (sizeof (x) == sizeof (double)) ? RT_NOCRT(isinf)(x) \ + : RT_NOCRT(__isinfl)(x)) +# define isnan(x) \ + ((sizeof (x) == sizeof (float)) ? RT_NOCRT(isnanf)(x) \ + : (sizeof (x) == sizeof (double)) ? RT_NOCRT(isnan)(x) \ + : RT_NOCRT(__isnanl)(x)) +# define isnormal(x) \ + ((sizeof (x) == sizeof (float)) ? RT_NOCRT(__isnormalf)(x) \ + : (sizeof (x) == sizeof (double)) ? RT_NOCRT(__isnormal)(x) \ + : RT_NOCRT(__isnormall)(x)) + +# ifdef __MATH_BUILTIN_RELOPS +# define isgreater(x, y) __builtin_isgreater((x), (y)) +# define isgreaterequal(x, y) __builtin_isgreaterequal((x), (y)) +# define isless(x, y) __builtin_isless((x), (y)) +# define islessequal(x, y) __builtin_islessequal((x), (y)) +# define islessgreater(x, y) __builtin_islessgreater((x), (y)) +# define isunordered(x, y) __builtin_isunordered((x), (y)) +# else +# define isgreater(x, y) (!isunordered((x), (y)) && (x) > (y)) +# define isgreaterequal(x, y) (!isunordered((x), (y)) && (x) >= (y)) +# define isless(x, y) (!isunordered((x), (y)) && (x) < (y)) +# define islessequal(x, y) (!isunordered((x), (y)) && (x) <= (y)) +# define islessgreater(x, y) (!isunordered((x), (y)) && \ + ((x) > (y) || (y) > (x))) +# define isunordered(x, y) (isnan(x) || isnan(y)) +# endif /* __MATH_BUILTIN_RELOPS */ + +# define signbit(x) \ + ((sizeof (x) == sizeof (float)) ? RT_NOCRT(__signbitf)(x) \ + : (sizeof (x) == sizeof (double)) ? RT_NOCRT(__signbit)(x) \ + : RT_NOCRT(__signbitl)(x)) + +typedef double double_t; +typedef float float_t; +#endif /* !IPRT_NOCRT_WITHOUT_MATH_CONSTANTS */ /* __ISO_C_VISIBLE >= 1999 */ + + +#if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +/* sed -e "/#/d" -e "/RT_NOCRT/!d" -e "s/^.*RT_NOCRT(\([a-z0-9_]*\)).*$/# define \1 RT_NOCRT(\1)/" */ +# define __fpclassifyf RT_NOCRT(__fpclassifyf) +# define __fpclassifyd RT_NOCRT(__fpclassifyd) +# define __fpclassifyl RT_NOCRT(__fpclassifyl) +# define __isfinitef RT_NOCRT(__isfinitef) +# define __isfinite RT_NOCRT(__isfinite) +# define __isfinitel RT_NOCRT(__isfinitel) +# define __isinff RT_NOCRT(__isinff) +# define __isinfl RT_NOCRT(__isinfl) +# define __isnanl RT_NOCRT(__isnanl) +# define __isnormalf RT_NOCRT(__isnormalf) +# define __isnormal RT_NOCRT(__isnormal) +# define __isnormall RT_NOCRT(__isnormall) +# define __signbitf RT_NOCRT(__signbitf) +# define __signbit RT_NOCRT(__signbit) +# define __signbitl RT_NOCRT(__signbitl) +# define signgam RT_NOCRT(signgam) +# define __fpclassifyd RT_NOCRT(__fpclassifyd) +# define __fpclassifyf RT_NOCRT(__fpclassifyf) +# define __fpclassifyl RT_NOCRT(__fpclassifyl) +# define __isfinitef RT_NOCRT(__isfinitef) +# define __isfinite RT_NOCRT(__isfinite) +# define __isfinitel RT_NOCRT(__isfinitel) +# define __isinff RT_NOCRT(__isinff) +# define __isinfl RT_NOCRT(__isinfl) +# define __isnanl RT_NOCRT(__isnanl) +# define __isnormalf RT_NOCRT(__isnormalf) +# define __isnormal RT_NOCRT(__isnormal) +# define __isnormall RT_NOCRT(__isnormall) +# define __signbit RT_NOCRT(__signbit) +# define __signbitf RT_NOCRT(__signbitf) +# define __signbitl RT_NOCRT(__signbitl) +# define acos RT_NOCRT(acos) +# define asin RT_NOCRT(asin) +# define atan RT_NOCRT(atan) +# define atan2 RT_NOCRT(atan2) +# define cos RT_NOCRT(cos) +# define sin RT_NOCRT(sin) +# define tan RT_NOCRT(tan) +# define cosh RT_NOCRT(cosh) +# define sinh RT_NOCRT(sinh) +# define tanh RT_NOCRT(tanh) +# define exp RT_NOCRT(exp) +# define frexp RT_NOCRT(frexp) +# define ldexp RT_NOCRT(ldexp) +# define log RT_NOCRT(log) +# define log10 RT_NOCRT(log10) +# define modf RT_NOCRT(modf) +# define pow RT_NOCRT(pow) +# define sqrt RT_NOCRT(sqrt) +# define ceil RT_NOCRT(ceil) +# define fabs RT_NOCRT(fabs) +# define floor RT_NOCRT(floor) +# define fmod RT_NOCRT(fmod) +# define acosh RT_NOCRT(acosh) +# define asinh RT_NOCRT(asinh) +# define atanh RT_NOCRT(atanh) +# define cbrt RT_NOCRT(cbrt) +# define erf RT_NOCRT(erf) +# define erfc RT_NOCRT(erfc) +# define exp2 RT_NOCRT(exp2) +# define expm1 RT_NOCRT(expm1) +# define fma RT_NOCRT(fma) +# define hypot RT_NOCRT(hypot) +# define ilogb RT_NOCRT(ilogb) +# define lgamma RT_NOCRT(lgamma) +# define llrint RT_NOCRT(llrint) +# define llround RT_NOCRT(llround) +# define log1p RT_NOCRT(log1p) +# define logb RT_NOCRT(logb) +# define lrint RT_NOCRT(lrint) +# define lround RT_NOCRT(lround) +# define nextafter RT_NOCRT(nextafter) +# define remainder RT_NOCRT(remainder) +# define remquo RT_NOCRT(remquo) +# define rint RT_NOCRT(rint) +# define j0 RT_NOCRT(j0) +# define j1 RT_NOCRT(j1) +# define jn RT_NOCRT(jn) +# define scalb RT_NOCRT(scalb) +# define y0 RT_NOCRT(y0) +# define y1 RT_NOCRT(y1) +# define yn RT_NOCRT(yn) +# define gamma RT_NOCRT(gamma) +# define copysign RT_NOCRT(copysign) +# define fdim RT_NOCRT(fdim) +# define fmax RT_NOCRT(fmax) +# define fmin RT_NOCRT(fmin) +# define nearbyint RT_NOCRT(nearbyint) +# define round RT_NOCRT(round) +# define scalbln RT_NOCRT(scalbln) +# define scalbn RT_NOCRT(scalbn) +# define tgamma RT_NOCRT(tgamma) +# define trunc RT_NOCRT(trunc) +# define drem RT_NOCRT(drem) +# define finite RT_NOCRT(finite) +/*# define isinf RT_NOCRT(isinf) - already a macro */ +/*# define isnan RT_NOCRT(isnan) - already a macro */ +# define isnanf RT_NOCRT(isnanf) +# define gamma_r RT_NOCRT(gamma_r) +# define lgamma_r RT_NOCRT(lgamma_r) +# define significand RT_NOCRT(significand) +# define acosf RT_NOCRT(acosf) +# define asinf RT_NOCRT(asinf) +# define atanf RT_NOCRT(atanf) +# define atan2f RT_NOCRT(atan2f) +# define cosf RT_NOCRT(cosf) +# define sinf RT_NOCRT(sinf) +# define tanf RT_NOCRT(tanf) +# define coshf RT_NOCRT(coshf) +# define sinhf RT_NOCRT(sinhf) +# define tanhf RT_NOCRT(tanhf) +# define exp2f RT_NOCRT(exp2f) +# define expf RT_NOCRT(expf) +# define expm1f RT_NOCRT(expm1f) +# define frexpf RT_NOCRT(frexpf) +# define ilogbf RT_NOCRT(ilogbf) +# define ldexpf RT_NOCRT(ldexpf) +# define log10f RT_NOCRT(log10f) +# define log1pf RT_NOCRT(log1pf) +# define logf RT_NOCRT(logf) +# define modff RT_NOCRT(modff) +# define powf RT_NOCRT(powf) +# define sqrtf RT_NOCRT(sqrtf) +# define ceilf RT_NOCRT(ceilf) +# define fabsf RT_NOCRT(fabsf) +# define floorf RT_NOCRT(floorf) +# define fmodf RT_NOCRT(fmodf) +# define roundf RT_NOCRT(roundf) +# define erff RT_NOCRT(erff) +# define erfcf RT_NOCRT(erfcf) +# define hypotf RT_NOCRT(hypotf) +# define lgammaf RT_NOCRT(lgammaf) +# define acoshf RT_NOCRT(acoshf) +# define asinhf RT_NOCRT(asinhf) +# define atanhf RT_NOCRT(atanhf) +# define cbrtf RT_NOCRT(cbrtf) +# define logbf RT_NOCRT(logbf) +# define copysignf RT_NOCRT(copysignf) +# define llrintf RT_NOCRT(llrintf) +# define llroundf RT_NOCRT(llroundf) +# define lrintf RT_NOCRT(lrintf) +# define lroundf RT_NOCRT(lroundf) +# define nearbyintf RT_NOCRT(nearbyintf) +# define nextafterf RT_NOCRT(nextafterf) +# define remainderf RT_NOCRT(remainderf) +# define remquof RT_NOCRT(remquof) +# define rintf RT_NOCRT(rintf) +# define scalblnf RT_NOCRT(scalblnf) +# define scalbnf RT_NOCRT(scalbnf) +# define truncf RT_NOCRT(truncf) +# define fdimf RT_NOCRT(fdimf) +# define fmaf RT_NOCRT(fmaf) +# define fmaxf RT_NOCRT(fmaxf) +# define fminf RT_NOCRT(fminf) +# define dremf RT_NOCRT(dremf) +# define finitef RT_NOCRT(finitef) +# define gammaf RT_NOCRT(gammaf) +# define j0f RT_NOCRT(j0f) +# define j1f RT_NOCRT(j1f) +# define jnf RT_NOCRT(jnf) +# define scalbf RT_NOCRT(scalbf) +# define y0f RT_NOCRT(y0f) +# define y1f RT_NOCRT(y1f) +# define ynf RT_NOCRT(ynf) +# define gammaf_r RT_NOCRT(gammaf_r) +# define lgammaf_r RT_NOCRT(lgammaf_r) +# define significandf RT_NOCRT(significandf) +# define acoshl RT_NOCRT(acoshl) +# define acosl RT_NOCRT(acosl) +# define asinhl RT_NOCRT(asinhl) +# define asinl RT_NOCRT(asinl) +# define atan2l RT_NOCRT(atan2l) +# define atanhl RT_NOCRT(atanhl) +# define atanl RT_NOCRT(atanl) +# define cbrtl RT_NOCRT(cbrtl) +# define ceill RT_NOCRT(ceill) +# define copysignl RT_NOCRT(copysignl) +# define coshl RT_NOCRT(coshl) +# define cosl RT_NOCRT(cosl) +# define erfcl RT_NOCRT(erfcl) +# define erfl RT_NOCRT(erfl) +# define exp2l RT_NOCRT(exp2l) +# define expl RT_NOCRT(expl) +# define expm1l RT_NOCRT(expm1l) +# define fabsl RT_NOCRT(fabsl) +# define fdiml RT_NOCRT(fdiml) +# define floorl RT_NOCRT(floorl) +# define fmal RT_NOCRT(fmal) +# define fmaxl RT_NOCRT(fmaxl) +# define fminl RT_NOCRT(fminl) +# define fmodl RT_NOCRT(fmodl) +# define frexpl RT_NOCRT(frexpl) +# define hypotl RT_NOCRT(hypotl) +# define ilogbl RT_NOCRT(ilogbl) +# define ldexpl RT_NOCRT(ldexpl) +# define lgammal RT_NOCRT(lgammal) +# define llrintl RT_NOCRT(llrintl) +# define llroundl RT_NOCRT(llroundl) +# define log10l RT_NOCRT(log10l) +# define log1pl RT_NOCRT(log1pl) +# define log2l RT_NOCRT(log2l) +# define logbl RT_NOCRT(logbl) +# define logl RT_NOCRT(logl) +# define lrintl RT_NOCRT(lrintl) +# define lroundl RT_NOCRT(lroundl) +# define modfl RT_NOCRT(modfl) +# define nanl RT_NOCRT(nanl) +# define nearbyintl RT_NOCRT(nearbyintl) +# define nextafterl RT_NOCRT(nextafterl) +# define nexttoward RT_NOCRT(nexttoward) +# define nexttowardf RT_NOCRT(nexttowardf) +# define nexttowardl RT_NOCRT(nexttowardl) +# define powl RT_NOCRT(powl) +# define remainderl RT_NOCRT(remainderl) +# define remquol RT_NOCRT(remquol) +# define rintl RT_NOCRT(rintl) +# define roundl RT_NOCRT(roundl) +# define scalblnl RT_NOCRT(scalblnl) +# define scalbnl RT_NOCRT(scalbnl) +# define sinhl RT_NOCRT(sinhl) +# define sinl RT_NOCRT(sinl) +# define sqrtl RT_NOCRT(sqrtl) +# define tanhl RT_NOCRT(tanhl) +# define tanl RT_NOCRT(tanl) +# define tgammal RT_NOCRT(tgammal) +# define truncl RT_NOCRT(truncl) +# define nan RT_NOCRT(nan) +# define nanf RT_NOCRT(nanf) +# define sincos RT_NOCRT(sincos) +# define sincosf RT_NOCRT(sincosf) +# define sincosl RT_NOCRT(sincosl) +# define exp10f RT_NOCRT(exp10f) +# define exp10 RT_NOCRT(exp10) +# define exp10l RT_NOCRT(exp10l) +# define log2f RT_NOCRT(log2f) +# define log2 RT_NOCRT(log2) +# define log2l RT_NOCRT(log2l) +# define tgammaf RT_NOCRT(tgammaf) +# define significandl RT_NOCRT(significandl) +# define j0l RT_NOCRT(j0l) +# define j1l RT_NOCRT(j1l) +# define jnl RT_NOCRT(jnl) +# define scalbl RT_NOCRT(scalbl) +# define y0l RT_NOCRT(y0l) +# define y1l RT_NOCRT(y1l) +# define ynl RT_NOCRT(ynl) +# define lgammal_r RT_NOCRT(lgammal_r) +# define gammal RT_NOCRT(gammal) +#endif + +/* + * Include inlined implementations. + */ +#ifdef RT_ARCH_AMD64 +# include <iprt/nocrt/amd64/math.h> +#elif defined(RT_ARCH_X86) +# include <iprt/nocrt/x86/math.h> +#endif + +#endif /* !IPRT_INCLUDED_nocrt_math_h */ + diff --git a/include/iprt/nocrt/memory b/include/iprt/nocrt/memory new file mode 100644 index 00000000..6399c414 --- /dev/null +++ b/include/iprt/nocrt/memory @@ -0,0 +1,108 @@ +/** @file + * IPRT / No-CRT - Minimal C++ std::memory. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_memory +#define VBOX_INCLUDED_SRC_nocrt_memory +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/nocrt/cstddef> +#include <iprt/nocrt/new> + +namespace std +{ + /** + * Simple allocator - not C++11 compliant. + */ + template<class a_Type> class allocator + { + public: + typedef a_Type value_type; + typedef a_Type const &const_reference; + typedef a_Type *pointer; + typedef a_Type const *const_pointer; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + public: + allocator() RT_NOEXCEPT + { } + + allocator(allocator const &a_rThat) RT_NOEXCEPT + { RT_NOREF(a_rThat); } + + ~allocator() + { } + + a_Type *allocate(size_type a_cItems, const void *a_pvHint = NULL) + { + RT_NOREF(a_pvHint); + Assert(a_cItems <= max_size()); /** @todo throw stuff */ + return static_cast<pointer>(::operator new(sizeof(value_type) * a_cItems)); + } + + void deallocate(a_Type *a_paItems, size_type a_cItems) + { + if (a_paItems && a_cItems > 0) + ::operator delete(a_paItems); + } + + size_type max_size() const + { + /* whatever */ +#if ARCH_BITS >= 64 + return _4G / sizeof(value_type); +#else + return _512M / sizeof(value_type); +#endif + } + + void construct(pointer a_pDst, const_reference a_rSrc) + { + ::new (static_cast<void *>(a_pDst)) a_Type(a_rSrc); + } + + void destroy(pointer a_pDst) + { + a_pDst->~value_type(); + } + }; + + /** @todo make_unique and unique */ +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_memory */ + diff --git a/include/iprt/nocrt/new b/include/iprt/nocrt/new new file mode 100644 index 00000000..ce8929c4 --- /dev/null +++ b/include/iprt/nocrt/new @@ -0,0 +1,118 @@ +/** @file + * IPRT / No-CRT - Our own new header. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_new +#define VBOX_INCLUDED_SRC_nocrt_new +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + + +/** MSC declares the operators as cdecl it seems. */ +#ifdef _MSC_VER +# define RT_NEW_DELETE_CDECL __cdecl +#else +# define RT_NEW_DELETE_CDECL +#endif + +/** MSC doesn't use the standard namespace. */ +#ifdef _MSC_VER +# define RT_NEW_DELETE_SIZE_T size_t +#else +# define RT_NEW_DELETE_SIZE_T std::size_t +#endif + +/** The hint that we're throwing std::bad_alloc is not apprecitated by MSC. */ +#ifdef RT_EXCEPTIONS_ENABLED +# ifdef _MSC_VER +# define RT_NEW_DELETE_THROWS_BAD_ALLOC +# define RT_NEW_DELETE_NOTHROW RT_NO_THROW_DEF +# else +# ifdef _GLIBCXX_THROW +# define RT_NEW_DELETE_THROWS_BAD_ALLOC _GLIBCXX_THROW(std::bad_alloc) +# elif defined(__cplusplus) && (__cplusplus + 0) < 201700 +# define RT_NEW_DELETE_THROWS_BAD_ALLOC throw(std::bad_alloc) +# else +# define RT_NEW_DELETE_THROWS_BAD_ALLOC noexcept(false) +# endif +# define RT_NEW_DELETE_NOTHROW throw() +# endif +#else /* !RT_EXCEPTIONS_ENABLED */ +# define RT_NEW_DELETE_THROWS_BAD_ALLOC +# define RT_NEW_DELETE_NOTHROW +#endif /* !RT_EXCEPTIONS_ENABLED */ + + +#ifdef IPRT_NO_CRT + +namespace std +{ + struct nothrow_t + { + explicit nothrow_t() + {} + }; + extern __declspec(selectany) nothrow_t const nothrow; +} + + +void *RT_NEW_DELETE_CDECL operator new(RT_NEW_DELETE_SIZE_T cb) RT_NEW_DELETE_THROWS_BAD_ALLOC; +void *RT_NEW_DELETE_CDECL operator new(RT_NEW_DELETE_SIZE_T cb, const std::nothrow_t &) RT_NEW_DELETE_NOTHROW; +void *RT_NEW_DELETE_CDECL operator new(RT_NEW_DELETE_SIZE_T cb, void *pvPlacement) RT_NEW_DELETE_NOTHROW; +void RT_NEW_DELETE_CDECL operator delete(void *pv) RT_NEW_DELETE_NOTHROW; +#ifdef __cpp_sized_deallocation +void RT_NEW_DELETE_CDECL operator delete(void *pv, RT_NEW_DELETE_SIZE_T cb) RT_NEW_DELETE_NOTHROW; +#endif +void RT_NEW_DELETE_CDECL operator delete(void *pv, const std::nothrow_t &) RT_NEW_DELETE_NOTHROW; + + +void *RT_NEW_DELETE_CDECL operator new[](RT_NEW_DELETE_SIZE_T cb) RT_NEW_DELETE_THROWS_BAD_ALLOC; +void *RT_NEW_DELETE_CDECL operator new[](RT_NEW_DELETE_SIZE_T cb, const std::nothrow_t &) RT_NEW_DELETE_NOTHROW; +void *RT_NEW_DELETE_CDECL operator new[](RT_NEW_DELETE_SIZE_T cb, void *pvPlacement) RT_NEW_DELETE_NOTHROW; +void RT_NEW_DELETE_CDECL operator delete[](void * pv) RT_NEW_DELETE_NOTHROW; +#ifdef __cpp_sized_deallocation +void RT_NEW_DELETE_CDECL operator delete[](void * pv, RT_NEW_DELETE_SIZE_T cb) RT_NEW_DELETE_NOTHROW; +#endif +void RT_NEW_DELETE_CDECL operator delete[](void *pv, const std::nothrow_t &) RT_NEW_DELETE_NOTHROW; + + +#else /* IPRT_NO_CRT */ +# include <new> +#endif /* IPRT_NO_CRT */ + +#endif /* !VBOX_INCLUDED_SRC_nocrt_new */ + diff --git a/include/iprt/nocrt/ostream b/include/iprt/nocrt/ostream new file mode 100644 index 00000000..98820e27 --- /dev/null +++ b/include/iprt/nocrt/ostream @@ -0,0 +1,280 @@ +/** @file + * IPRT / No-CRT - Minimal C++ ostream header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_ostream +#define VBOX_INCLUDED_SRC_nocrt_ostream +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Currently all in the ios header. */ +#include <iprt/nocrt/ios> + +namespace std +{ + /** + * Basic output stream. + */ + template<typename a_CharType, typename a_CharTraits /*= std::char_traits<a_CharType>*/ > + class basic_ostream : public basic_ios<a_CharType, a_CharTraits> + { + protected: + /** Sentry class that performs pre and post output work. */ + class sentry + { + private: + basic_ostream &m_rParent; + + public: + explicit sentry(basic_ostream &a_rParent) + : m_rParent(a_rParent) + { + if (a_rParent.good()) + { + basic_ostream *pTiedStream = a_rParent.tie(); + if (!pTiedStream) + { /* likely? */ } + else + { + pTiedStream->flush(); + if (!pTiedStream->good()) + a_rParent.setstate(failbit); + } + } + } + + explicit operator bool() const + { + return m_rParent.good(); + } + + ~sentry() + { + if ( (m_rParent.flags() & std::ios_base::unitbuf) + && m_rParent.good()) + m_rParent.rdbuf()->pubsync(); + } + }; + + public: + explicit basic_ostream(std::basic_streambuf<a_CharType,a_CharTraits> *a_pBuf) + : basic_ios(a_pBuf) + { } + + /** For cerr initialization. + * @internal */ + explicit basic_ostream(std::basic_streambuf<a_CharType,a_CharTraits> *a_pBuf, + std::basic_ostream<a_CharType, a_CharTraits> *a_pTiedStream, + bool a_fUnbuffered) + : basic_ios(a_pBuf) + { + m_pTiedStream = a_pTiedStream; + if (!a_fUnbuffered) + setf(std::ios_base::unitbuf); + } + + private: + basic_ostream(basic_ostream const &a_rSrc); /* not copyable */ + basic_ostream &operator=(basic_ostream const &a_rSrc); /* not copyable */ + + public: + virtual ~basic_ostream() + { + } + + public: + basic_ostream &put(char_type a_ch) + { + sentry PrePost(*this); + if (PrePost) + { + if (m_pBuf->sputc(a_ch) == traits_type::eof()) + m_fState |= badbit; + } + return *this; + } + + basic_ostream &write(const char_type *a_pchSrc, std::streamsize a_cchToWrite) + { + sentry PrePost(*this); + if (PrePost) + { + std::streamsize cchWritten = m_pBuf->sputn(a_pchSrc, a_cchToWrite); + if (cchWritten != a_cchToWrite) + m_fState |= badbit; + } + return *this; + } + + basic_ostream &flush() + { + if (m_pBuf) + m_pBuf->pubsync(); + return *this; + } + + pos_type tellp() RT_NOEXCEPT; + basic_ostream &seekp(pos_type a_off) RT_NOEXCEPT; + basic_ostream &seekp(off_type a_off, seekdir enmDir) RT_NOEXCEPT; + + /** @name Internal support methods + * @{ */ + inline basic_ostream &intWrite(const char *a_pchSrc, std::streamsize a_cchToWrite); /**< Internal method outputting char buffers. */ + + /** @returns 8, 10 or 16. */ + inline unsigned intGetIntegerBase() const RT_NOEXCEPT + { + switch (m_fFlags & basefield) + { + default: + case dec: return 10; + case hex: return 16; + case oct: return 8; + } + } + + /** @returns RTSTR_F_XXX . */ + inline unsigned intGetIntegerFlags() const RT_NOEXCEPT + { + unsigned fFlags = 0; + if (m_fFlags & uppercase) + fFlags |= RTSTR_F_CAPITAL; + if (m_fFlags & showbase) + fFlags |= RTSTR_F_SPECIAL; + if (m_fFlags & showpos) + fFlags |= RTSTR_F_PLUS; + return fFlags; + } + + basic_ostream &formatInteger(uint64_t a_uValue, uint32_t a_fFlags, unsigned a_uBase = 0) + { + a_fFlags |= intGetIntegerFlags(); + char szTmp[72]; + int cchTmp = RTStrFormatNumber(szTmp, a_uValue, !a_uBase ? intGetIntegerBase() : a_uBase, 0, 0, a_fFlags); + + /** @todo apply cchWidth and padding. */ + + return intWrite(szTmp, cchTmp); + } + + /** @} */ + }; + + /** @name Character and string output. + * @{ */ + /** @todo not sure if this really works... */ + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > + basic_ostream<a_CharType, a_CharTraits> &operator<<(basic_ostream<a_CharType, a_CharTraits> &a_rDst, char a_ch) + { + return a_rDst.put(a_ch); + } + + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > + basic_ostream<a_CharType, a_CharTraits> &operator<<(basic_ostream<a_CharType, a_CharTraits> &a_rDst, const char *a_psz) + { + return a_rDst.intWrite(a_psz, strlen(a_psz)); + } + /** @} */ + + /** @name Integer formatting. + * @{ */ + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > + basic_ostream<a_CharType, a_CharTraits> &operator<<(basic_ostream<a_CharType, a_CharTraits> &a_rDst, signed char a_iValue) + { + return a_rDst.formatInteger(a_iValue, RTSTR_F_8BIT | RTSTR_F_VALSIGNED); + } + + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > + basic_ostream<a_CharType, a_CharTraits> &operator<<(basic_ostream<a_CharType, a_CharTraits> &a_rDst, unsigned char a_uValue) + { + return a_rDst.formatInteger(a_uValue, RTSTR_F_8BIT); + } + + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > + basic_ostream<a_CharType, a_CharTraits> &operator<<(basic_ostream<a_CharType, a_CharTraits> &a_rDst, short a_iValue) + { + return a_rDst.formatInteger(a_iValue, RTSTR_F_16BIT | RTSTR_F_VALSIGNED); + } + + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > + basic_ostream<a_CharType, a_CharTraits> &operator<<(basic_ostream<a_CharType, a_CharTraits> &a_rDst, unsigned short a_uValue) + { + return a_rDst.formatInteger(a_uValue, RTSTR_F_16BIT); + } + + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > + basic_ostream<a_CharType, a_CharTraits> &operator<<(basic_ostream<a_CharType, a_CharTraits> &a_rDst, int a_iValue) + { + return a_rDst.formatInteger(a_iValue, RTSTR_F_32BIT | RTSTR_F_VALSIGNED); + } + + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > + basic_ostream<a_CharType, a_CharTraits> &operator<<(basic_ostream<a_CharType, a_CharTraits> &a_rDst, unsigned int a_uValue) + { + return a_rDst.formatInteger(a_uValue, RTSTR_F_32BIT | RTSTR_F_VALSIGNED); + } + + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > + basic_ostream<a_CharType, a_CharTraits> &operator<<(basic_ostream<a_CharType, a_CharTraits> &a_rDst, long a_iValue) + { + return a_rDst.formatInteger(a_iValue, (sizeof(a_iValue) > sizeof(int32_t) ? RTSTR_F_64BIT : RTSTR_F_32BIT)); + } + + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > + basic_ostream<a_CharType, a_CharTraits> &operator<<(basic_ostream<a_CharType, a_CharTraits> &a_rDst, unsigned long a_uValue) + { + return a_rDst.formatInteger(a_uValue, + RTSTR_F_VALSIGNED | (sizeof(a_uValue) > sizeof(uint32_t) ? RTSTR_F_64BIT : RTSTR_F_32BIT)); + } + + template<typename a_CharType, typename a_CharTraits = std::char_traits<a_CharType> > + basic_ostream<a_CharType, a_CharTraits> &operator<<(basic_ostream<a_CharType, a_CharTraits> &a_rDst, void const *a_pvValue) + { + return a_rDst.formatInteger((uintptr_t)a_pvValue, + (sizeof(a_pvValue) > sizeof(uint32_t) ? RTSTR_F_64BIT : RTSTR_F_32BIT), 16); + } + /** @} */ + + template<> + inline basic_ostream<char> &basic_ostream<char>::intWrite(const char *a_pchSrc, std::streamsize a_cchToWrite) + { + return write(a_pchSrc, a_cchToWrite); + } + + +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_ostream */ + diff --git a/include/iprt/nocrt/process.h b/include/iprt/nocrt/process.h new file mode 100644 index 00000000..f965813c --- /dev/null +++ b/include/iprt/nocrt/process.h @@ -0,0 +1,43 @@ +/** @file + * IPRT / No-CRT - Stub process.h header for MSC compatibility. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_process_h +#define IPRT_INCLUDED_nocrt_process_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#endif /* !IPRT_INCLUDED_nocrt_process_h */ + diff --git a/include/iprt/nocrt/setjmp.h b/include/iprt/nocrt/setjmp.h new file mode 100644 index 00000000..6b2e15af --- /dev/null +++ b/include/iprt/nocrt/setjmp.h @@ -0,0 +1,68 @@ +/** @file + * IPRT / No-CRT - Our own setjmp header. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_setjmp_h +#define IPRT_INCLUDED_nocrt_setjmp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +#ifdef RT_ARCH_AMD64 +# ifdef RT_OS_WINDOWS /* Also saves rsi, rdi and xmm6-xmm15. */ +typedef uint64_t RT_NOCRT(jmp_buf)[10 + (2*10)]; +# else +typedef uint64_t RT_NOCRT(jmp_buf)[8]; +# endif +#else +typedef uint32_t RT_NOCRT(jmp_buf)[6+2]; +#endif + +extern DECL_RETURNS_TWICE(int) RT_NOCRT(setjmp)(RT_NOCRT(jmp_buf)); +extern DECL_NO_RETURN(int) RT_NOCRT(longjmp)(RT_NOCRT(jmp_buf), int); + +#if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define jmp_buf RT_NOCRT(jmp_buf) +# define setjmp RT_NOCRT(setjmp) +# define longjmp RT_NOCRT(longjmp) +#endif + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_nocrt_setjmp_h */ + diff --git a/include/iprt/nocrt/signal.h b/include/iprt/nocrt/signal.h new file mode 100644 index 00000000..36ca57b5 --- /dev/null +++ b/include/iprt/nocrt/signal.h @@ -0,0 +1,43 @@ +/** @file + * IPRT / No-CRT - Stub signal.h header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_signal_h +#define IPRT_INCLUDED_nocrt_signal_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#endif /* !IPRT_INCLUDED_nocrt_signal_h */ + diff --git a/include/iprt/nocrt/stdarg.h b/include/iprt/nocrt/stdarg.h new file mode 100644 index 00000000..3a5b039d --- /dev/null +++ b/include/iprt/nocrt/stdarg.h @@ -0,0 +1,45 @@ +/** @file + * IPRT / No-CRT - stdarg.h (-> iprt/stdarg.h). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_stdarg_h +#define IPRT_INCLUDED_nocrt_stdarg_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/stdarg.h> + +#endif /* !IPRT_INCLUDED_nocrt_stdarg_h */ + diff --git a/include/iprt/nocrt/stdbool.h b/include/iprt/nocrt/stdbool.h new file mode 100644 index 00000000..d288ce2c --- /dev/null +++ b/include/iprt/nocrt/stdbool.h @@ -0,0 +1,58 @@ +/** @file + * IPRT / No-CRT - Our own minimal stdbool.h header (needed by softfloat.h). + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_stdbool_h +#define IPRT_INCLUDED_nocrt_stdbool_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* The iprt/types.h header should take care of the basics. */ +#include <iprt/types.h> + +#ifndef __cplusplus +# ifndef bool +# define bool _Bool +# endif +# ifndef true +# define true (1) +# endif +# ifndef false +# define false (0) +# endif +#endif + +#endif /* !IPRT_INCLUDED_nocrt_stdbool_h */ + diff --git a/include/iprt/nocrt/stddef.h b/include/iprt/nocrt/stddef.h new file mode 100644 index 00000000..df56a617 --- /dev/null +++ b/include/iprt/nocrt/stddef.h @@ -0,0 +1,48 @@ +/** @file + * IPRT / No-CRT - stddef.h (-> iprt/types.h). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_stddef_h +#define IPRT_INCLUDED_nocrt_stddef_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +#ifndef offsetof +# define offsetof(a_Type, a_Member) RT_OFFSETOF(a_Type, a_Member) +#endif + +#endif /* !IPRT_INCLUDED_nocrt_stddef_h */ diff --git a/include/iprt/nocrt/stdint.h b/include/iprt/nocrt/stdint.h new file mode 100644 index 00000000..2b481159 --- /dev/null +++ b/include/iprt/nocrt/stdint.h @@ -0,0 +1,46 @@ +/** @file + * IPRT / No-CRT - Our own minimal stdint.h header (needed by softfloat.h). + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_stdint_h +#define IPRT_INCLUDED_nocrt_stdint_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* The iprt/stdint.h header should take care of the basics. */ +#include <iprt/stdint.h> + +#endif /* !IPRT_INCLUDED_nocrt_stdint_h */ + diff --git a/include/iprt/nocrt/stdio.h b/include/iprt/nocrt/stdio.h new file mode 100644 index 00000000..a63b3e49 --- /dev/null +++ b/include/iprt/nocrt/stdio.h @@ -0,0 +1,226 @@ +/** @file + * IPRT / No-CRT - Mostly empty stdio.h. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_stdio_h +#define IPRT_INCLUDED_nocrt_stdio_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/stream.h> +#include <iprt/nocrt/sys/types.h> /* errno_t, off_t */ +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY +# include <iprt/nocrt/time.h> /* file.h includes fs.h which includes time.h */ +# include <iprt/file.h> /* for RTFILE_SEEK_XXX */ +# include <iprt/assertcompile.h> +#endif + +typedef RTFOFF fpos_t; + + +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY +/* + * Only for external libraries and such, but even then it would be best to + * check each printf and fprintf call as IPRT isn't 100% compatible... + */ + +/* These are also in unistd.h: */ +# undef SEEK_SET +# define SEEK_SET RTFILE_SEEK_BEGIN +# undef SEEK_CUR +# define SEEK_CUR RTFILE_SEEK_CURRENT +# undef SEEK_END +# define SEEK_END RTFILE_SEEK_END +AssertCompile(SEEK_SET == 0); AssertCompile(SEEK_CUR == 1); AssertCompile(SEEK_END == 2); /* Also in WDK header mmiscapi.h. */ + +# define RT_NOCRT_BUFSIZ 4096 +# define BUFSIZ RT_NOCRT_BUFSIZ + +RT_C_DECLS_BEGIN + +typedef struct RTSTREAM FILE; +# define stdin g_pStdIn +# define stdout g_pStdOut +# define stderr g_pStdErr + +# define printf RTPrintf +# define vprintf RTPrintfV +# define fprintf RTStrmPrintf +# define vfprintf RTStrmPrintfV +int RT_NOCRT(snprintf)(char *, size_t, const char *, ...); +int RT_NOCRT(vsnprintf)(char *, size_t, const char *, va_list); +int RT_NOCRT(scprintf)(const char *, ...); +int RT_NOCRT(vscprintf)(const char *, va_list); + +FILE *RT_NOCRT(fopen)(const char *pszFilename, const char *pszMode); +FILE *RT_NOCRT(fdopen)(int fd, const char *pszMode); +FILE *RT_NOCRT(tmpfile)(void); +errno_t RT_NOCRT(tmpfile_s)(FILE **ppFile); +int RT_NOCRT(fileno)(FILE *pFile); +int RT_NOCRT(fclose)(FILE *pFile); +int RT_NOCRT(fflush)(FILE *pFile); +int RT_NOCRT(setvbuf)(FILE *pFile, char *pchBuf, int iBufferingType, size_t cbBuf); +int RT_NOCRT(fseek)(FILE *pFile, long, int); +int RT_NOCRT(fseeko)(FILE *pFile, off_t, int); +long RT_NOCRT(ftell)(FILE *pFile); +off_t RT_NOCRT(ftello)(FILE *pFile); +size_t RT_NOCRT(fwrite)(void const *pvBuf, size_t cbItem, size_t cItems, FILE *pFile); +int RT_NOCRT(fputs)(const char *psz, FILE *pFile); +int RT_NOCRT(puts)(const char *psz); +int RT_NOCRT(fputc)(int, FILE *pFile); +int RT_NOCRT(putc)(int, FILE *pFile); +size_t RT_NOCRT(fread)(void *pvBuf, size_t cbItem, size_t cItems, FILE *pFile); +int RT_NOCRT(fgetc)(FILE *pFile); +int RT_NOCRT(getc)(FILE *pFile); +int RT_NOCRT(ferror)(FILE *pFile); +void RT_NOCRT(clearerr)(FILE *pFile); +int RT_NOCRT(remove)(const char *pszFilename); +int RT_NOCRT(sscanf)(const char *pszString, const char *pszFormat, ...); +int RT_NOCRT(vsscanf)(const char *pszString, const char *pszFormat, va_list); + +# ifndef RT_NOCRT_EOF /* also in string */ +# define RT_NOCRT_EOF (-1) +# endif +# define EOF RT_NOCRT_EOF + +/* Underscored variants: */ +# define _printf RTPrintf +# define _vprintf RTPrintfV +# define _fprintf RTStrmPrintf +# define _vfprintf RTStrmPrintfV +int RT_NOCRT(_snprintf)(char *, size_t, const char *, ...); +int RT_NOCRT(_vsnprintf)(char *, size_t, const char *, va_list); +int RT_NOCRT(_scprintf)(const char *, ...); +int RT_NOCRT(_vscprintf)(const char *, va_list); + +FILE *RT_NOCRT(_fopen)(const char *pszFilename, const char *pszMode); +FILE *RT_NOCRT(_fdopen)(int fd, const char *pszMode); +FILE *RT_NOCRT(_tmpfile)(void); +errno_t RT_NOCRT(_tmpfile_s)(FILE **ppFile); +int RT_NOCRT(_fileno)(FILE *pFile); +int RT_NOCRT(_fclose)(FILE *pFile); +int RT_NOCRT(_fflush)(FILE *pFile); +int RT_NOCRT(_setvbuf)(FILE *pFile, char *pchBuf, int iBufferingType, size_t cbBuf); +int RT_NOCRT(_fseek)(FILE *pFile, long, int); +int RT_NOCRT(_fseeko)(FILE *pFile, off_t, int); +long RT_NOCRT(_ftell)(FILE *pFile); +off_t RT_NOCRT(_ftello)(FILE *pFile); +size_t RT_NOCRT(_fwrite)(void const *pvBuf, size_t cbItem, size_t cItems, FILE *pFile); +int RT_NOCRT(_fputs)(const char *psz, FILE *pFile); +int RT_NOCRT(_fputc)(int, FILE *pFile); +size_t RT_NOCRT(_fread)(void *pvBuf, size_t cbItem, size_t cItems, FILE *pFile); +int RT_NOCRT(_fgetc)(FILE *pFile); +int RT_NOCRT(_getc)(FILE *pFile); +int RT_NOCRT(_ferror)(FILE *pFile); +void RT_NOCRT(_clearerr)(FILE *pFile); +int RT_NOCRT(_remove)(const char *pszFilename); +int RT_NOCRT(_sscanf)(const char *pszString, const char *pszFormat, ...); +int RT_NOCRT(_vsscanf)(const char *pszString, const char *pszFormat, va_list); + +# define _IONBF (1) /**< No buffering. */ +# define _IOLBF (2) /**< Line buffered. */ +# define _IOFBF (3) /**< Fully buffered. */ + +/* Aliases: */ +# if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define snprintf RT_NOCRT(snprintf) +# define vsnprintf RT_NOCRT(vsnprintf) +# define scprintf RT_NOCRT(scprintf) +# define vscprintf RT_NOCRT(vscprintf) + +# define fopen RT_NOCRT(fopen) +# define fdopen RT_NOCRT(fdopen) +# define tmpfile RT_NOCRT(tmpfile) +# define tmpfile_s RT_NOCRT(tmpfile_s) +# define fileno RT_NOCRT(fileno) +# define fclose RT_NOCRT(fclose) +# define fflush RT_NOCRT(fflush) +# define setvbuf RT_NOCRT(setvbuf) +# define fseek RT_NOCRT(fseek) +# define fseeko RT_NOCRT(fseeko) +# define ftell RT_NOCRT(ftell) +# define ftello RT_NOCRT(ftello) +# define fwrite RT_NOCRT(fwrite) +# define fputs RT_NOCRT(fputs) +# define puts RT_NOCRT(puts) +# define fputc RT_NOCRT(fputc) +# define fread RT_NOCRT(fread) +# define fgetc RT_NOCRT(fgetc) +# define getc RT_NOCRT(getc) +# define ferror RT_NOCRT(ferror) +# define clearerr RT_NOCRT(clearerr) +# define remove RT_NOCRT(remove) +# define sscanf RT_NOCRT(sscanf) +# define vsscanf RT_NOCRT(vsscanf) + + +/* Underscored variants: */ +# define _snprintf RT_NOCRT(snprintf) +# define _vsnprintf RT_NOCRT(vsnprintf) +# define _scprintf RT_NOCRT(scprintf) +# define _vscprintf RT_NOCRT(vscprintf) + +# define _fopen RT_NOCRT(fopen) +# define _fdopen RT_NOCRT(fdopen) +# define _tmpfile RT_NOCRT(tmpfile) +# define _tmpfile_s RT_NOCRT(tmpfile_s) +# define _fileno RT_NOCRT(fileno) +# define _fclose RT_NOCRT(fclose) +# define _flush RT_NOCRT(fflush) +# define _setvbuf RT_NOCRT(setvbuf) +# define _fseek RT_NOCRT(fseek) +# define _fseeko RT_NOCRT(fseeko) +# define _ftell RT_NOCRT(ftell) +# define _ftello RT_NOCRT(ftello) +# define _fwrite RT_NOCRT(fwrite) +# define _fputs RT_NOCRT(fputs) +# define _puts RT_NOCRT(puts) +# define _fputc RT_NOCRT(fputc) +# define _fread RT_NOCRT(fread) +# define _fgetc RT_NOCRT(fgetc) +# define _getc RT_NOCRT(getc) +# define _ferror RT_NOCRT(ferror) +# define _clearerr RT_NOCRT(clearerr) +# define _remove RT_NOCRT(remove) +# define _sscanf RT_NOCRT(_sscanf) +# define _vsscanf RT_NOCRT(_vsscanf) +# endif + +RT_C_DECLS_END + +#endif + +#endif /* !IPRT_INCLUDED_nocrt_stdio_h */ + diff --git a/include/iprt/nocrt/stdlib.h b/include/iprt/nocrt/stdlib.h new file mode 100644 index 00000000..49868cbe --- /dev/null +++ b/include/iprt/nocrt/stdlib.h @@ -0,0 +1,227 @@ +/** @file + * IPRT / No-CRT - Our minimal stdlib.h. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_stdlib_h +#define IPRT_INCLUDED_nocrt_stdlib_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assert.h> +#include <iprt/env.h> +#include <iprt/mem.h> +#include <iprt/nocrt/limits.h> + +RT_C_DECLS_BEGIN + +#define EXIT_SUCCESS RTEXITCODE_SUCCESS +#define EXIT_FAILURE RTEXITCODE_FAILURE + + +typedef void FNRTNOCRTATEXITCALLBACK(void) /*RT_NOEXCEPT*/; +typedef FNRTNOCRTATEXITCALLBACK *PFNRTNOCRTATEXITCALLBACK; +#if defined(_MSC_VER) && defined(RT_WITHOUT_NOCRT_WRAPPERS) /* Clashes with compiler internal prototype or smth. */ +int nocrt_atexit(PFNRTNOCRTATEXITCALLBACK) RT_NOEXCEPT; +# define atexit nocrt_atexit +#else +int RT_NOCRT(atexit)(PFNRTNOCRTATEXITCALLBACK) RT_NOEXCEPT; +#endif + +#if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define atexit RT_NOCRT(atexit) +#endif + + +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY +/* + * Only for external libraries and such. + */ + +DECLINLINE(void *) RT_NOCRT(malloc)(size_t cb) +{ + return RTMemAlloc(cb); +} + +DECLINLINE(void *) RT_NOCRT(calloc)(size_t cItems, size_t cbItem) +{ + return RTMemAllocZ(cItems * cbItem); /* caller responsible for overflow issues. */ +} + +DECLINLINE(void *) RT_NOCRT(realloc)(void *pvOld, size_t cbNew) +{ + return RTMemRealloc(pvOld, cbNew); +} + +DECLINLINE(void) RT_NOCRT(free)(void *pv) +{ + RTMemFree(pv); +} + +DECLINLINE(const char *) RT_NOCRT(getenv)(const char *pszVar) +{ + return RTEnvGet(pszVar); +} + +int RT_NOCRT(abs)(int) RT_NOEXCEPT; +long RT_NOCRT(labs)(long) RT_NOEXCEPT; +long long RT_NOCRT(llabs)(long long) RT_NOEXCEPT; +int RT_NOCRT(rand)(void) RT_NOEXCEPT; +void RT_NOCRT(srand)(unsigned) RT_NOEXCEPT; +long RT_NOCRT(strtol)(const char *psz, char **ppszNext, int iBase) RT_NOEXCEPT; +long long RT_NOCRT(strtoll)(const char *psz, char **ppszNext, int iBase) RT_NOEXCEPT; +unsigned long RT_NOCRT(strtoul)(const char *psz, char **ppszNext, int iBase) RT_NOEXCEPT; +unsigned long long RT_NOCRT(strtoull)(const char *psz, char **ppszNext, int iBase) RT_NOEXCEPT; +int RT_NOCRT(atoi)(const char *psz) RT_NOEXCEPT; +double RT_NOCRT(strtod)(const char *psz, char **ppszNext) RT_NOEXCEPT; +double RT_NOCRT(atof)(const char *psz) RT_NOEXCEPT; +void *RT_NOCRT(bsearch)(const void *pvKey, const void *pvBase, size_t cEntries, size_t cbEntry, + int (*pfnCompare)(const void *pvKey, const void *pvEntry)); +void RT_NOCRT(qsort)(void *pvBase, size_t cEntries, size_t cbEntry, + int (*pfnCompare)(const void *pv1, const void *pv2)); +void RT_NOCRT(qsort_r)(void *pvBase, size_t cEntries, size_t cbEntry, + int (*pfnCompare)(const void *pv1, const void *pv2, void *pvUser), void *pvUser); + +/* Map exit & abort onto fatal assert. */ +DECL_NO_RETURN(DECLINLINE(void)) RT_NOCRT(exit)(int iExitCode) { AssertFatalMsgFailed(("exit: iExitCode=%d\n", iExitCode)); } +DECL_NO_RETURN(DECLINLINE(void)) RT_NOCRT(abort)(void) { AssertFatalMsgFailed(("abort\n")); } + +/* + * Underscored versions: + */ +DECLINLINE(void *) RT_NOCRT(_malloc)(size_t cb) +{ + return RTMemAlloc(cb); +} + +DECLINLINE(void *) RT_NOCRT(_calloc)(size_t cItems, size_t cbItem) +{ + return RTMemAllocZ(cItems * cbItem); /* caller responsible for overflow issues. */ +} + +DECLINLINE(void *) RT_NOCRT(_realloc)(void *pvOld, size_t cbNew) +{ + return RTMemRealloc(pvOld, cbNew); +} + +DECLINLINE(void) RT_NOCRT(_free)(void *pv) +{ + RTMemFree(pv); +} + +DECLINLINE(const char *) RT_NOCRT(_getenv)(const char *pszVar) +{ + return RTEnvGet(pszVar); +} + +int RT_NOCRT(_abs)(int); +long RT_NOCRT(_labs)(long); +long long RT_NOCRT(_llabs)(long long); +int RT_NOCRT(_rand)(void); +void RT_NOCRT(_srand)(unsigned); +long RT_NOCRT(_strtol)(const char *psz, char **ppszNext, int iBase); +long long RT_NOCRT(_strtoll)(const char *psz, char **ppszNext, int iBase); +unsigned long RT_NOCRT(_strtoul)(const char *psz, char **ppszNext, int iBase); +unsigned long long RT_NOCRT(_strtoull)(const char *psz, char **ppszNext, int iBase); +int RT_NOCRT(_atoi)(const char *psz); +double RT_NOCRT(_strtod)(const char *psz, char **ppszNext); +double RT_NOCRT(_atof)(const char *psz); +void *RT_NOCRT(_bsearch)(const void *pvKey, const void *pvBase, size_t cEntries, size_t cbEntry, + int (*pfnCompare)(const void *pv1, const void *pv2)); +void RT_NOCRT(_qsort)(void *pvBase, size_t cEntries, size_t cbEntry, + int (*pfnCompare)(const void *pv1, const void *pv2)); +void RT_NOCRT(_qsort_r)(void *pvBase, size_t cEntries, size_t cbEntry, + int (*pfnCompare)(const void *pv1, const void *pv2, void *pvUser), void *pvUser); + +/* Map exit & abort onto fatal assert. */ +DECL_NO_RETURN(DECLINLINE(void)) RT_NOCRT(_exit)(int iExitCode) { AssertFatalMsgFailed(("_exit: iExitCode=%d\n", iExitCode)); } +DECL_NO_RETURN(DECLINLINE(void)) RT_NOCRT(_abort)(void) { AssertFatalMsgFailed(("_abort\n")); } + +/* Some windows CRT error control functions we totally ignore (only underscored): */ +# define _set_error_mode(a_Mode) (0) +# define _set_abort_behavior(a_fFlags, a_fMask) (0) + +/* + * No-CRT aliases. + */ +# if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define malloc RT_NOCRT(malloc) +# define calloc RT_NOCRT(calloc) +# define realloc RT_NOCRT(realloc) +# define free RT_NOCRT(free) +# define getenv RT_NOCRT(getenv) +# define bsearch RT_NOCRT(bsearch) +# define exit RT_NOCRT(exit) +# define abort RT_NOCRT(abort) +# define abs RT_NOCRT(abs) +# define labs RT_NOCRT(labs) +# define llabs RT_NOCRT(llabs) +# define rand RT_NOCRT(rand) +# define srand RT_NOCRT(srand) +# define strtol RT_NOCRT(strtol) +# define strtoll RT_NOCRT(strtoll) +# define strtoul RT_NOCRT(strtoul) +# define strtoull RT_NOCRT(strtoull) +# define atoi RT_NOCRT(atoi) +# define strtod RT_NOCRT(strtod) +# define atof RT_NOCRT(atof) + +# define _malloc RT_NOCRT(malloc) +# define _calloc RT_NOCRT(calloc) +# define _realloc RT_NOCRT(realloc) +# define _free RT_NOCRT(free) +# define _getenv RT_NOCRT(getenv) +# define _bsearch RT_NOCRT(bsearch) +# define _exit RT_NOCRT(exit) +# define _abort RT_NOCRT(abort) +# define _abs RT_NOCRT(abs) +# define _labs RT_NOCRT(labs) +# define _llabs RT_NOCRT(llabs) +# define _rand RT_NOCRT(rand) +# define _srand RT_NOCRT(srand) +# define _strtol RT_NOCRT(strtol) +# define _strtoll RT_NOCRT(strtoll) +# define _strtoul RT_NOCRT(strtoul) +# define _strtoull RT_NOCRT(strtoull) +# define _atoi RT_NOCRT(atoi) +# define _strtod RT_NOCRT(strtod) +# define _atof RT_NOCRT(atof) +# endif + +#endif /* IPRT_NO_CRT_FOR_3RD_PARTY */ + + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_nocrt_stdlib_h */ diff --git a/include/iprt/nocrt/string b/include/iprt/nocrt/string new file mode 100644 index 00000000..31897dd1 --- /dev/null +++ b/include/iprt/nocrt/string @@ -0,0 +1,322 @@ +/** @file + * IPRT / No-CRT - Minimal C++ string header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_string +#define VBOX_INCLUDED_SRC_nocrt_string +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/nocrt/string.h> +#include <iprt/nocrt/cstddef> /* for std::size_t */ +#include <iprt/cpp/ministring.h> + +#ifndef RT_NOCRT_EOF /* also in stdio.h */ +# define RT_NOCRT_EOF (-1) +#endif + +namespace std +{ + using streamoff = ::RTFOFF; + + /** + * @note This should be in iosfwd, not string. + */ + template<typename a_MbStateType> + class fpos + { + protected: + std::streamoff m_off; + a_MbStateType m_MbState; + + public: + fpos() + : m_off(0) + , m_MbState() + { } + + fpos(std::streamoff a_off) + : m_off(a_off) + , m_MbState() + { } + + a_MbStateType state() const RT_NOEXCEPT + { + return m_MbState; + } + + void state(a_MbStateType a_NewMbState) const RT_NOEXCEPT + { + m_MbState = a_NewMbState; + } + }; + using mbstate_t = ::RT_NOCRT(mbstate_t); + using streampos = fpos<std::mbstate_t>; + + /* Use RTCString as std::string, it should be a reasonable match. */ + typedef ::RTCString string; + + /** + * Character traits. + */ + template<typename a_CharType> + struct char_traits + { + /** @name Types + * @{ */ + typedef a_CharType char_type; + typedef unsigned long int_type; + typedef std::streamoff off_type; + typedef std::streampos pos_type; + typedef std::mbstate_t state_type; + /** @} */ + + static void assign(char_type &a_rchDst, const char_type &a_rchSrc) RT_NOEXCEPT + { + a_rchDst = a_rchSrc; + } + + static bool eq(const char_type &a_rchLeft, const char_type &a_rchRight) RT_NOEXCEPT + { + return a_rchLeft == a_rchRight; + } + + static bool lt(const char_type &a_rchLeft, const char_type &a_rchRight) RT_NOEXCEPT + { + return a_rchLeft < a_rchRight; + } + + static std::size_t length(const char_type *a_psz) RT_NOEXCEPT; + static int compare(const char_type *a_pchLeft, const char_type *a_pchRight, std::size_t a_cch) RT_NOEXCEPT; + static const char_type *find(const char_type *a_pchHaystack, std::size_t a_cchHaystack, const char_type &a_rchNeedle) RT_NOEXCEPT; + static char_type *assign(char_type *a_pchDst, std::size_t a_cchDst, char_type a_chFill) RT_NOEXCEPT; + static char_type *copy(char_type *a_pchDst, const char_type *a_pchSrc, std::size_t a_cch) RT_NOEXCEPT; + static char_type *move(char_type *a_pchDst, const char_type *a_pchSrc, std::size_t a_cch) RT_NOEXCEPT; + + static char_type to_char_type(const int_type &a_riChar) + { + return static_cast<char_type>(a_riChar); + } + + static int_type to_int_type(const char_type &a_rch) + { + return static_cast<int_type>(a_rch); + } + + static bool eq_int_type(const int_type &a_riLeft, const int_type &a_riRight) RT_NOEXCEPT + { + return a_riLeft == a_riRight; + } + + static int_type eof() RT_NOEXCEPT + { + return static_cast<int_type>(RT_NOCRT_EOF); + } + + static int_type not_eof(const int_type &a_riChar) RT_NOEXCEPT + { + if (!eq_int_type(a_riChar, eof())) + return a_riChar; + return to_int_type(char_type()); + } + }; + + template<typename a_CharType> + /*static*/ std::size_t char_traits<a_CharType>::length(const char_type *a_psz) RT_NOEXCEPT + { + const char_type * const pszStart = a_psz; + while (!eq(*a_pszLeft, char_type())) + a_psz++; + return static_cast<std::size_t>(a_psz - pszStart); + } + + template<typename a_CharType> + /*static*/ int char_traits<a_CharType>::compare(const char_type *a_pchLeft, const char_type *a_pchRight, + std::size_t a_cch) RT_NOEXCEPT + { + for (std::size_t off = 0; off < a_cch; off++) + if (eq(a_pchLeft[off], a_pchRight[off])) + { /* likely? */ } + else + return lt(a_pchLeft[off], a_pchRight[off]) ? -1 : 1; + return 0; + } + + template<typename a_CharType> + /*static*/ const typename char_traits<a_CharType>::char_type * + char_traits<a_CharType>::find(const char_type *a_pchHaystack, std::size_t a_cchHaystack, + const char_type &a_rchNeedle) RT_NOEXCEPT + { + while (a_cchHaystack-- > 0) + { + if (eq(*a_pchHaystack, a_rchNeedle)) + return a_pchHaystack; + a_pchHaystack++; + } + return NULL; + } + + template<typename a_CharType> + /*static*/ typename char_traits<a_CharType>::char_type * + char_traits<a_CharType>::assign(char_type *a_pchDst, std::size_t a_cchDst, char_type a_chFill) RT_NOEXCEPT + { + char_type * const pchRet = a_pchDst; + while (a_cchDst-- > 0) + *a_pchDst++ = a_chFill; + return pchRet; + } + + template<typename a_CharType> + /*static*/ typename char_traits<a_CharType>::char_type * + char_traits<a_CharType>::copy(char_type *a_pchDst, const char_type *a_pchSrc, std::size_t a_cch) RT_NOEXCEPT + { + char_type * const pchRet = a_pchDst; + while (a_cch-- > 0) + *a_pchDst++ = *a_pchSrc++; + return pchRet; + } + + template<typename a_CharType> + /*static*/ typename char_traits<a_CharType>::char_type * + char_traits<a_CharType>::move(char_type *a_pchDst, const char_type *a_pchSrc, std::size_t a_cch) RT_NOEXCEPT + { + char_type * const pchRet = a_pchDst; + char_type volatile *pchDstV = static_cast<char_type const volatile *>(a_pchDst); + char_type const volatile *pchSrcV = static_cast<char_type const volatile *>(a_pchSrc); + if ((uintptr_t)a_pchDst < (uintptr_t)a_pchSrc) + { + /* forward copy */ + while (a_cch-- > 0) + *a_pchDstV++ = *a_pchSrcV++; + } + else + { + /* reverse copy */ + a_pchSrcV += a_cch; + a_pchDstV += a_cch; + while (a_cchDst-- > 0) + *a_pchDstV-- = *a_pchSrcV--; + } + return pchRet; + } + + /* + * Character train specializations. + */ + template <> + struct char_traits<char> + { + typedef char char_type; + typedef int int_type; + typedef std::streamoff off_type; + typedef std::streampos pos_type; + typedef std::mbstate_t state_type; + + static void assign(char_type &a_rchDst, const char_type &a_rchSrc) RT_NOEXCEPT + { + a_rchDst = a_rchSrc; + } + + static bool eq(const char_type &a_rchLeft, const char_type &a_rchRight) RT_NOEXCEPT + { + return a_rchLeft == a_rchRight; + } + + static bool lt(const char_type &a_rchLeft, const char_type &a_rchRight) RT_NOEXCEPT + { + return a_rchLeft < a_rchRight; + } + + static std::size_t length(const char_type *a_psz) RT_NOEXCEPT + { + return ::RT_NOCRT(strlen)(a_psz); + } + + static int compare(const char_type *a_pchLeft, const char_type *a_pchRight, std::size_t a_cch) RT_NOEXCEPT + { + return ::RT_NOCRT(memcmp)(a_pchLeft, a_pchRight, a_cch); + } + + static const char_type *find(const char_type *a_pchHaystack, std::size_t a_cchHaystack, const char_type &a_rchNeedle) RT_NOEXCEPT + { + return static_cast<const char_type *>(::RT_NOCRT(memchr)(a_pchHaystack, a_rchNeedle, a_cchHaystack)); + } + + static char_type *assign(char_type *a_pchDst, std::size_t a_cchDst, char_type a_chFill) RT_NOEXCEPT + { + return static_cast<char_type *>(::RT_NOCRT(memset)(a_pchDst, a_chFill, a_cchDst)); + } + + static char_type *copy(char_type *a_pchDst, const char_type *a_pchSrc, std::size_t a_cch) RT_NOEXCEPT + { + return static_cast<char_type *>(::RT_NOCRT(memcpy)(a_pchDst, a_pchSrc, a_cch)); + } + + static char_type *move(char_type *a_pchDst, const char_type *a_pchSrc, std::size_t a_cch) RT_NOEXCEPT + { + return static_cast<char_type *>(::RT_NOCRT(memmove)(a_pchDst, a_pchSrc, a_cch)); + } + + static char_type to_char_type(const int_type &a_riChar) + { + return static_cast<char_type>(a_riChar); + } + + static int_type to_int_type(const char_type &a_rch) + { + return static_cast<int_type>(a_rch); + } + + static bool eq_int_type(const int_type &a_riLeft, const int_type &a_riRight) RT_NOEXCEPT + { + return a_riLeft == a_riRight; + } + + static int_type eof() RT_NOEXCEPT + { + return static_cast<int_type>(RT_NOCRT_EOF); + } + + static int_type not_eof(const int_type &a_riChar) RT_NOEXCEPT + { + if (!eq_int_type(a_riChar, eof())) + return a_riChar; + return 0; + } + }; +} + + +#endif /* !VBOX_INCLUDED_SRC_nocrt_string */ diff --git a/include/iprt/nocrt/string.h b/include/iprt/nocrt/string.h new file mode 100644 index 00000000..b83d0036 --- /dev/null +++ b/include/iprt/nocrt/string.h @@ -0,0 +1,254 @@ +/** @file + * IPRT / No-CRT - string.h. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_string_h +#define IPRT_INCLUDED_nocrt_string_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/* Dummy for now, fix when/if needed. */ +typedef struct RT_NOCRT(mbstate_t) +{ + unsigned long whatever; +} RT_NOCRT(mbstate_t); + + +RT_C_DECLS_BEGIN + +void *RT_NOCRT(memchr)(const void *pv, int ch, size_t cb); +int RT_NOCRT(memcmp)(const void *pv1, const void *pv2, size_t cb); +void *RT_NOCRT(memcpy)(void *pvDst, const void *pvSrc, size_t cb); +void *RT_NOCRT(mempcpy)(void *pvDst, const void *pvSrc, size_t cb); +void *RT_NOCRT(memrchr)(const void *pv, int ch, size_t cb); +void *RT_NOCRT(memmove)(void *pvDst, const void *pvSrc, size_t cb); +void *RT_NOCRT(memset)(void *pvDst, int ch, size_t cb); + +char *RT_NOCRT(strcat)(char *pszDst, const char *pszSrc); +char *RT_NOCRT(strncat)(char *pszDst, const char *pszSrc, size_t cch); +char *RT_NOCRT(strchr)(const char *psz, int ch); +char *RT_NOCRT(strrchr)(const char *psz, int ch); +int RT_NOCRT(strcmp)(const char *psz1, const char *psz2); +int RT_NOCRT(strncmp)(const char *psz1, const char *psz2, size_t cch); +int RT_NOCRT(stricmp)(const char *psz1, const char *psz2); +int RT_NOCRT(strnicmp)(const char *psz1, const char *psz2, size_t cch); +int RT_NOCRT(strcmpcase)(const char *psz1, const char *psz2, size_t cch); +int RT_NOCRT(strcoll)(const char *psz1, const char *psz2); +char *RT_NOCRT(strcpy)(char *pszDst, const char *pszSrc); +char *RT_NOCRT(strncpy)(char *pszDst, const char *pszSrc, size_t cch); +char *RT_NOCRT(strcat)(char *pszDst, const char *pszSrc); +char *RT_NOCRT(strncat)(char *pszDst, const char *pszSrc, size_t cch); +size_t RT_NOCRT(strlen)(const char *psz); +size_t RT_NOCRT(strnlen)(const char *psz, size_t cch); +size_t RT_NOCRT(strspn)(const char *psz, const char *pszBreakChars); +size_t RT_NOCRT(strcspn)(const char *psz, const char *pszBreakChars); +char *RT_NOCRT(strpbrk)(const char *psz, const char *pszBreakChars); +char *RT_NOCRT(strstr)(const char *psz, const char *pszSub); +char *RT_NOCRT(strtok)(char *psz, const char *pszDelim); +char *RT_NOCRT(strtok_r)(char *psz, const char *pszDelim, char **ppszSave); +#if 0 /* C++11: */ +char *RT_NOCRT(strtok_s)(char *psz, /*rsize_t*/ size_t cchMax, const char *pszDelim, char **ppszSave); +#else /* Microsoft: */ +char *RT_NOCRT(strtok_s)(char *psz, const char *pszDelim, char **ppszSave); +#endif +size_t RT_NOCRT(strxfrm)(char *pszDst, const char *pszSrc, size_t cch); + +size_t RT_NOCRT(wcslen)(const wchar_t *pwsz); +wchar_t *RT_NOCRT(wcscat)(wchar_t *pwszDst, const wchar_t *pwszSrc); +wchar_t *RT_NOCRT(wcschr)(const wchar_t *pwsz, wchar_t wc); +wchar_t *RT_NOCRT(wcscpy)(wchar_t *pwszDst, const wchar_t *pwszSrc); +int RT_NOCRT(wcsicmp)(const wchar_t *pwsz1, const wchar_t *pwsz2); +size_t RT_NOCRT(wcstombs)(char *pszDst, const wchar_t *pszSrc, size_t cbDst); + + +/* Underscored versions for MSC compatibility (mesa #defines regular to _regular + a lot, which is why we really need these prototypes). */ +void *RT_NOCRT(_memchr)(const void *pv, int ch, size_t cb); +int RT_NOCRT(_memcmp)(const void *pv1, const void *pv2, size_t cb); +void *RT_NOCRT(_memcpy)(void *pvDst, const void *pvSrc, size_t cb); +void *RT_NOCRT(_mempcpy)(void *pvDst, const void *pvSrc, size_t cb); +void *RT_NOCRT(_memrchr)(const void *pv, int ch, size_t cb); +void *RT_NOCRT(_memmove)(void *pvDst, const void *pvSrc, size_t cb); +void *RT_NOCRT(_memset)(void *pvDst, int ch, size_t cb); + +char *RT_NOCRT(_strcat)(char *pszDst, const char *pszSrc); +char *RT_NOCRT(_strncat)(char *pszDst, const char *pszSrc, size_t cch); +char *RT_NOCRT(_strchr)(const char *psz, int ch); +char *RT_NOCRT(_strrchr)(const char *psz, int ch); +int RT_NOCRT(_strcmp)(const char *psz1, const char *psz2); +int RT_NOCRT(_strncmp)(const char *psz1, const char *psz2, size_t cch); +int RT_NOCRT(_stricmp)(const char *psz1, const char *psz2); +int RT_NOCRT(_strnicmp)(const char *psz1, const char *psz2, size_t cch); +int RT_NOCRT(_strcmpcase)(const char *psz1, const char *psz2, size_t cch); +int RT_NOCRT(_strcoll)(const char *psz1, const char *psz2); +char *RT_NOCRT(_strcpy)(char *pszDst, const char *pszSrc); +char *RT_NOCRT(_strncpy)(char *pszDst, const char *pszSrc, size_t cch); +char *RT_NOCRT(_strcat)(char *pszDst, const char *pszSrc); +char *RT_NOCRT(_strncat)(char *pszDst, const char *pszSrc, size_t cch); +size_t RT_NOCRT(_strlen)(const char *psz); +size_t RT_NOCRT(_strnlen)(const char *psz, size_t cch); +size_t RT_NOCRT(_strspn)(const char *psz, const char *pszBreakChars); +size_t RT_NOCRT(_strcspn)(const char *psz, const char *pszBreakChars); +char *RT_NOCRT(_strpbrk)(const char *psz, const char *pszBreakChars); +char *RT_NOCRT(_strstr)(const char *psz, const char *pszSub); +char *RT_NOCRT(_strtok)(char *psz, const char *pszDelim); +char *RT_NOCRT(_strtok_r)(char *psz, const char *pszDelim, char **ppszSave); +#if 0 /* C++11: */ +char *RT_NOCRT(_strtok_s)(char *psz, /*rsize_t*/ size_t cchMax, const char *pszDelim, char **ppszSave); +#else /* Microsoft: */ +char *RT_NOCRT(_strtok_s)(char *psz, const char *pszDelim, char **ppszSave); +#endif +size_t RT_NOCRT(_strxfrm)(char *pszDst, const char *pszSrc, size_t cch); + +size_t RT_NOCRT(_wcslen)(const wchar_t *pwsz); +wchar_t *RT_NOCRT(_wcscat)(wchar_t *pwszDst, const wchar_t *pwszSrc); +wchar_t *RT_NOCRT(_wcschr)(const wchar_t *pwsz, wchar_t wc); +wchar_t *RT_NOCRT(_wcscpy)(wchar_t *pwszDst, const wchar_t *pwszSrc); +int RT_NOCRT(_wcsicmp)(const wchar_t *pwsz1, const wchar_t *pwsz2); +size_t RT_NOCRT(_wcstombs)(char *pszDst, const wchar_t *pszSrc, size_t cbDst); + + +#if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define memchr RT_NOCRT(memchr) +# define memcmp RT_NOCRT(memcmp) +# define memcpy RT_NOCRT(memcpy) +# define mempcpy RT_NOCRT(mempcpy) +# define memrchr RT_NOCRT(memrchr) +# define memmove RT_NOCRT(memmove) +# define memset RT_NOCRT(memset) + +# define strcat RT_NOCRT(strcat) +# define strncat RT_NOCRT(strncat) +# define strchr RT_NOCRT(strchr) +# define strrchr RT_NOCRT(strrchr) +# define strcmp RT_NOCRT(strcmp) +# define strncmp RT_NOCRT(strncmp) +# define stricmp RT_NOCRT(stricmp) +# define strnicmp RT_NOCRT(strnicmp) +# define strcmpcase RT_NOCRT(strcmpcase) +# define strcoll RT_NOCRT(strcoll) +# define strcpy RT_NOCRT(strcpy) +# define strncpy RT_NOCRT(strncpy) +# define strcat RT_NOCRT(strcat) +# define strncat RT_NOCRT(strncat) +# define strlen RT_NOCRT(strlen) +# define strnlen RT_NOCRT(strnlen) +# define strspn RT_NOCRT(strspn) +# define strcspn RT_NOCRT(strcspn) +# define strpbrk RT_NOCRT(strpbrk) +# define strstr RT_NOCRT(strstr) +# define strtok RT_NOCRT(strtok) +# define strtok_r RT_NOCRT(strtok_r) +# define strtok_s RT_NOCRT(strtok_s) +# define strxfrm RT_NOCRT(strxfrm) + +# define wcslen RT_NOCRT(wcslen) +# define wcscat RT_NOCRT(wcscat) +# define wcschr RT_NOCRT(wcschr) +# define wcscpy RT_NOCRT(wcscpy) +# define wcsicmp RT_NOCRT(wcsicmp) +# define wcstombs RT_NOCRT(wcstombs) + +/* Underscored: */ +# define _memchr RT_NOCRT(memchr) +# define _memcmp RT_NOCRT(memcmp) +# define _memcpy RT_NOCRT(memcpy) +# define _mempcpy RT_NOCRT(mempcpy) +# define _memrchr RT_NOCRT(memrchr) +# define _memmove RT_NOCRT(memmove) +# define _memset RT_NOCRT(memset) + +# define _strcat RT_NOCRT(strcat) +# define _strncat RT_NOCRT(strncat) +# define _strchr RT_NOCRT(strchr) +# define _strrchr RT_NOCRT(strrchr) +# define _strcmp RT_NOCRT(strcmp) +# define _strncmp RT_NOCRT(strncmp) +# define _stricmp RT_NOCRT(stricmp) +# define _strnicmp RT_NOCRT(strnicmp) +# define _strcmpcase RT_NOCRT(strcmpcase) +# define _strcoll RT_NOCRT(strcoll) +# define _strcpy RT_NOCRT(strcpy) +# define _strncpy RT_NOCRT(strncpy) +# define _strcat RT_NOCRT(strcat) +# define _strncat RT_NOCRT(strncat) +# define _strlen RT_NOCRT(strlen) +# define _strnlen RT_NOCRT(strnlen) +# define _strspn RT_NOCRT(strspn) +# define _strcspn RT_NOCRT(strcspn) +# define _strpbrk RT_NOCRT(strpbrk) +# define _strstr RT_NOCRT(strstr) +# define _strtok RT_NOCRT(strtok) +# define _strtok_r RT_NOCRT(strtok_r) +# define _strtok_s RT_NOCRT(strtok_s) +# define _strxfrm RT_NOCRT(strxfrm) + +# define _wcslen RT_NOCRT(wcslen) +# define _wcscat RT_NOCRT(wcscat) +# define _wcschr RT_NOCRT(wcschr) +# define _wcscpy RT_NOCRT(wcscpy) +# define _wcsicmp RT_NOCRT(wcsicmp) +# define _wcstombs RT_NOCRT(wcstombs) +#endif + + +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY +/* + * Only for external libraries and such. + */ + +const char *RT_NOCRT(strerror)(int iErrNo); +char *RT_NOCRT(strdup)(const char *pszSrc); + +/* Underscored: */ +const char *RT_NOCRT(_strerror)(int iErrNo); +char *RT_NOCRT(_strdup)(const char *pszSrc); + +# if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define strerror RT_NOCRT(strerror) +# define strdup RT_NOCRT(strdup) + +/* Underscored: */ +# define _strerror RT_NOCRT(strerror) +# define _strdup RT_NOCRT(strdup) +# endif + +#endif /* IPRT_NO_CRT_FOR_3RD_PARTY */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_nocrt_string_h */ diff --git a/include/iprt/nocrt/sys/stat.h b/include/iprt/nocrt/sys/stat.h new file mode 100644 index 00000000..0ed81c59 --- /dev/null +++ b/include/iprt/nocrt/sys/stat.h @@ -0,0 +1,138 @@ +/** @file + * IPRT / No-CRT - sys/stat.h + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_sys_stat_h +#define IPRT_INCLUDED_nocrt_sys_stat_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/nocrt/time.h> /* Establish timespec and timeval before iprt/fs.h includes iprt/time.h. */ +#include <iprt/fs.h> +#include <iprt/nocrt/sys/types.h> +#include <iprt/nocrt/limits.h> + +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY + +struct RT_NOCRT(stat) +{ + RTINODE st_ino; + RTDEV st_dev; + RTDEV st_rdev; + RTFMODE st_mode; + uint32_t st_link; + RTUID st_uid; + RTGID st_gid; + RTFOFF st_size; + RTFOFF st_blocks; + uint32_t st_blksize; /**< Not related to st_blocks! */ + time_t st_birthtime; + time_t st_ctime; + time_t st_mtime; + time_t st_atime; +}; + +# define _S_IFIFO RTFS_TYPE_FIFO +# define _S_IFCHR RTFS_TYPE_DEV_CHAR +# define _S_IFDIR RTFS_TYPE_DIRECTORY +# define _S_IFBLK RTFS_TYPE_DEV_BLOCK +# define _S_IFREG RTFS_TYPE_FILE +# define _S_IFLNK RTFS_TYPE_SYMLINK +# define _S_IFSOCK RTFS_TYPE_SOCKET +# define _S_IFWHT RTFS_TYPE_WHITEOUT +# define _S_IFMT RTFS_TYPE_MASK + +# define S_IFIFO _S_IFIFO +# define S_IFCHR _S_IFCHR +# define S_IFDIR _S_IFDIR +# define S_IFBLK _S_IFBLK +# define S_IFREG _S_IFREG +# define S_IFLNK _S_IFLNK +# define S_IFSOCK _S_IFSOCK +# define S_IFWHT _S_IFWHT +# define S_IFMT _S_IFMT + +# define S_ISFIFO(a_fMode) RTFS_IS_FIFO(a_fMode) +# define S_ISCHR(a_fMode) RTFS_IS_DEV_CHAR(a_fMode) +# define S_ISDIR(a_fMode) RTFS_IS_DIRECTORY(a_fMode) +# define S_ISBLK(a_fMode) RTFS_IS_DEV_BLOCK(a_fMode) +# define S_ISREG(a_fMode) RTFS_IS_FILE(a_fMode) +# define S_ISLNK(a_fMode) RTFS_IS_SYMLINK(a_fMode) +# define S_ISSOCK(a_fMode) RTFS_IS_SOCKET(a_fMode) +# define S_ISWHT(a_fMode) RTFS_IS_WHITEOUT(a_fMode) + + +RT_C_DECLS_BEGIN + +int RT_NOCRT(chmod)(const char *pszPath, RTFMODE fMode); +int RT_NOCRT(fchmod)(int fd, RTFMODE fMode); +int RT_NOCRT(fstat)(int fd, struct RT_NOCRT(stat) *pStat); +int RT_NOCRT(lstat)(const char *pszPath, struct RT_NOCRT(stat) *pStat); +int RT_NOCRT(stat)(const char *pszPath, struct RT_NOCRT(stat) *pStat); +RTFMODE RT_NOCRT(umask)(RTFMODE fMode); +int RT_NOCRT(mkdir)(const char *, RTFMODE fMode); + +int RT_NOCRT(_chmod)(const char *pszPath, RTFMODE fMode); +int RT_NOCRT(_fchmod)(int fd, RTFMODE fMode); +int RT_NOCRT(_fstat)(int fd, struct RT_NOCRT(stat) *pStat); +int RT_NOCRT(_lstat)(const char *pszPath, struct RT_NOCRT(stat) *pStat); +int RT_NOCRT(_stat)(const char *pszPath, struct RT_NOCRT(stat) *pStat); +RTFMODE RT_NOCRT(_umask)(RTFMODE fMode); +int RT_NOCRT(_mkdir)(const char *, RTFMODE fMode); + +# if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define chmod RT_NOCRT(chmod) +# define fchmod RT_NOCRT(fchmod) +# define fstat RT_NOCRT(fstat) +# define lstat RT_NOCRT(lstat) +# define stat RT_NOCRT(stat) +# define umask RT_NOCRT(umask) +# define mkdir RT_NOCRT(mkdir) + +# define _chmod RT_NOCRT(chmod) +# define _fchmod RT_NOCRT(fchmod) +# define _fstat RT_NOCRT(fstat) +# define _lstat RT_NOCRT(lstat) +# define _stat RT_NOCRT(stat) +# define _umask RT_NOCRT(umask) +# define _mkdir RT_NOCRT(mkdir) +# endif + +RT_C_DECLS_END + +#endif /* IPRT_NO_CRT_FOR_3RD_PARTY */ + +#endif /* !IPRT_INCLUDED_nocrt_sys_stat_h */ + diff --git a/include/iprt/nocrt/sys/types.h b/include/iprt/nocrt/sys/types.h new file mode 100644 index 00000000..3320200a --- /dev/null +++ b/include/iprt/nocrt/sys/types.h @@ -0,0 +1,66 @@ +/** @file + * IPRT / No-CRT - Our own sys/types header. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_sys_types_h +#define IPRT_INCLUDED_nocrt_sys_types_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#if defined(IPRT_INCLUDED_types_h) && !defined(IPRT_COMPLETED_types_h) +# error "Can't include nocrt/sys/types.h from iprt/types.h" +#endif + +#include <iprt/types.h> + +/* #if !defined(MSC-define) && !defined(GNU/LINUX-define) */ +#if !defined(_DEV_T_DEFINED) && !defined(__dev_t_defined) +typedef RTDEV dev_t; +#endif +#if !defined(_UCRT_RESTORE_CLANG_WARNINGS) /* MSC specific type */ +typedef int errno_t; +#endif +#if !defined(_INO_T_DEFINED) && !defined(__ino_t_defined) +typedef RTINODE ino_t; +#endif +#if !defined(_OFF_T_DEFINED) && !defined(__off_t_defined) +typedef RTFOFF off_t; +#endif +#if !defined(_PID_T_DEFINED) && !defined(__pid_t_defined) +typedef RTPROCESS pid_t; +#endif + +#endif /* !IPRT_INCLUDED_nocrt_sys_types_h */ + diff --git a/include/iprt/nocrt/time.h b/include/iprt/nocrt/time.h new file mode 100644 index 00000000..ab2a8649 --- /dev/null +++ b/include/iprt/nocrt/time.h @@ -0,0 +1,107 @@ +/** @file + * IPRT / No-CRT - Our minimal time.h. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_time_h +#define IPRT_INCLUDED_nocrt_time_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#define RTTIME_INCL_TIMESPEC +/*#define RTTIME_INCL_TIMEVAL*/ +#include <iprt/types.h> +#include <iprt/nocrt/sys/types.h> + +/* #if !defined(MSC-define) && !defined(GNU/LINUX-define) */ +#if !defined(_TIME_T_DEFINED) && !defined(__time_t_defined) +# if defined(RT_OS_WINDOWS) && defined(_USE_32BIT_TIME_T) && ARCH_BITS == 32 +typedef long time_t; +# else +typedef int64_t time_t; +# endif +# ifdef _MSC_VER +typedef int64_t __time64_t; +# endif +#endif /* !_TIME_T_DEFINED */ + +#if !defined(_INC_TIME) /* MSC/UCRT guard */ + +# if !defined(_STRUCT_TIMESPEC) && !defined(__struct_timespec_defined) && !defined(_TIMESPEC_DEFINED) && !defined(__timespec_defined) /* << linux variations, new to old. */ +struct timespec +{ + time_t tv_sec; + long tv_nsec; +}; +# endif + +#if !defined(__struct_tm_defined) +struct tm +{ + int tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year; + int tm_wday, tm_yday, tm_isdst, tm_gmtoff; + const char *tm_zone; +}; +# endif + +#endif /* !_INC_TIME */ + +RT_C_DECLS_BEGIN + +time_t RT_NOCRT(time)(time_t *); +errno_t RT_NOCRT(localtime_s)(struct tm *, const time_t *); /* The Microsoft version, not the C11 one. */ +struct tm *RT_NOCRT(localtime_r)(const time_t *, struct tm *); + +time_t RT_NOCRT(_time)(time_t *); +errno_t RT_NOCRT(_localtime_s)(struct tm *, const time_t *); +struct tm *RT_NOCRT(_localtime_r)(const time_t *, struct tm *); + +# if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define time RT_NOCRT(time) +# define localtime_s RT_NOCRT(localtime_s) +# define localtime_r RT_NOCRT(localtime_r) + +# define _time RT_NOCRT(time) +# define _localtime_s RT_NOCRT(localtime_s) +# define _localtime_r RT_NOCRT(localtime_r) +# endif + +RT_C_DECLS_END + +#ifdef IPRT_INCLUDED_time_h +# error nocrt/time.h after time.h +#endif + +#endif /* !IPRT_INCLUDED_nocrt_time_h */ + diff --git a/include/iprt/nocrt/type_traits b/include/iprt/nocrt/type_traits new file mode 100644 index 00000000..c8c35b2f --- /dev/null +++ b/include/iprt/nocrt/type_traits @@ -0,0 +1,88 @@ +/** @file + * IPRT / No-CRT - Minimal type_traits C++ header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_type_traits +#define VBOX_INCLUDED_SRC_nocrt_type_traits +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> + +namespace std +{ + /* + * std::integral_constant + */ + template<typename a_Type, a_Type a_Value> + struct integral_constant + { + static constexpr a_Type value = a_Value; + typedef a_Type value_type; + typedef integral_constant<a_Type, a_Value> type; + constexpr operator value_type() const RT_NOEXCEPT { return value; } + /** @todo operator()() for 2014+ */ + }; + template<typename a_Type, a_Type a_Value> constexpr a_Type integral_constant<a_Type, a_Value>::value; + + /* Helper: */ + template<bool a_Value> using bool_constant = integral_constant<bool, a_Value>; + + /* Specializations: */ + typedef integral_constant<bool, true> true_type; + typedef integral_constant<bool, false> false_type; + + + /* + * std::is_enum + */ + template<typename a_Type> struct is_enum + : integral_constant<bool, __is_enum(a_Type) /* compiler (clan, gcc, msc) builtin */ > + { }; + + /* + * std::underlying_type + */ + template<typename a_Type> struct underlying_type + { + using type = __underlying_type(a_Type); /* compiler (clan, gcc, msc) builtin */ + }; + + template<typename a_Type> using underlying_type_t = typename underlying_type<a_Type>::type; + +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_type_traits */ + diff --git a/include/iprt/nocrt/unistd.h b/include/iprt/nocrt/unistd.h new file mode 100644 index 00000000..270a0739 --- /dev/null +++ b/include/iprt/nocrt/unistd.h @@ -0,0 +1,125 @@ +/** @file + * IPRT / No-CRT - Minimal unistd.h header. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_unistd_h +#define IPRT_INCLUDED_nocrt_unistd_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/nocrt/sys/types.h> +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY +# include <iprt/nocrt/time.h> /* file.h includes fs.h which includes time.h */ +# include <iprt/file.h> /* for RTFILE_SEEK_XXX */ +# include <iprt/assertcompile.h> +#endif + + +#ifdef IPRT_NO_CRT_FOR_3RD_PARTY + +/* Flags for access: */ +# define F_OK 0 +# define X_OK 1 +# define W_OK 2 +# define R_OK 4 + +/* These are also in stdio.h: */ +# undef SEEK_SET +# define SEEK_SET RTFILE_SEEK_BEGIN +# undef SEEK_CUR +# define SEEK_CUR RTFILE_SEEK_CURRENT +# undef SEEK_END +# define SEEK_END RTFILE_SEEK_END +AssertCompile(SEEK_SET == 0); AssertCompile(SEEK_CUR == 1); AssertCompile(SEEK_END == 2); /* Also in WDK header mmiscapi.h. */ + +RT_C_DECLS_BEGIN + +int RT_NOCRT(access)(const char *, int) RT_NOEXCEPT; +int RT_NOCRT(dup)(int) RT_NOEXCEPT; +int RT_NOCRT(dup2)(int, int) RT_NOEXCEPT; +ssize_t RT_NOCRT(read)(int, void *, size_t) RT_NOEXCEPT; +ssize_t RT_NOCRT(write)(int, const void *, size_t) RT_NOEXCEPT; +int RT_NOCRT(close)(int) RT_NOEXCEPT; +int RT_NOCRT(isatty)(int) RT_NOEXCEPT; +char *RT_NOCRT(getcwd)(char *, size_t) RT_NOEXCEPT; +RTPROCESS RT_NOCRT(getpid)(void) RT_NOEXCEPT; +RTPROCESS RT_NOCRT(getppid)(void) RT_NOEXCEPT; +int RT_NOCRT(unlink)(const char *) RT_NOEXCEPT; + +int RT_NOCRT(_access)(const char *, int) RT_NOEXCEPT; +int RT_NOCRT(_dup)(int) RT_NOEXCEPT; +int RT_NOCRT(_dup2)(int, int) RT_NOEXCEPT; +ssize_t RT_NOCRT(_read)(int, void *, size_t) RT_NOEXCEPT; +ssize_t RT_NOCRT(_write)(int, const void *, size_t) RT_NOEXCEPT; +int RT_NOCRT(_close)(int) RT_NOEXCEPT; +int RT_NOCRT(_isatty)(int) RT_NOEXCEPT; +char *RT_NOCRT(_getcwd)(char *, size_t) RT_NOEXCEPT; +RTPROCESS RT_NOCRT(_getpid)(void) RT_NOEXCEPT; +RTPROCESS RT_NOCRT(_getppid)(void) RT_NOEXCEPT; +int RT_NOCRT(_unlink)(const char *) RT_NOEXCEPT; + +# if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define access RT_NOCRT(access) +# define dup RT_NOCRT(dup) +# define dup2 RT_NOCRT(dup2) +# define read RT_NOCRT(read) +# define write RT_NOCRT(write) +# define close RT_NOCRT(close) +# define isatty RT_NOCRT(isatty) +# define getcwd RT_NOCRT(getcwd) +# define getpid RT_NOCRT(getpid) +# define getppid RT_NOCRT(getppid) +# define unlink RT_NOCRT(unlink) + +# define _access RT_NOCRT(access) +# define _dup RT_NOCRT(dup) +# define _dup2 RT_NOCRT(dup2) +# define _read RT_NOCRT(read) +# define _write RT_NOCRT(write) +# define _close RT_NOCRT(close) +# define _isatty RT_NOCRT(isatty) +# define _getcwd RT_NOCRT(getcwd) +# define _getpid RT_NOCRT(getpid) +# define _getppid RT_NOCRT(getppid) +# define _unlink RT_NOCRT(unlink) +# endif + +RT_C_DECLS_END + +#endif /* IPRT_NO_CRT_FOR_3RD_PARTY */ + + +#endif /* !IPRT_INCLUDED_nocrt_unistd_h */ + diff --git a/include/iprt/nocrt/vector b/include/iprt/nocrt/vector new file mode 100644 index 00000000..bee4b734 --- /dev/null +++ b/include/iprt/nocrt/vector @@ -0,0 +1,398 @@ +/** @file + * IPRT / No-CRT - Minimal C++ std::vector. + */ + +/* + * Copyright (C) 2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_nocrt_vector +#define VBOX_INCLUDED_SRC_nocrt_vector +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/nocrt/memory> + +namespace std +{ + template<typename a_Type, class a_Container> + class RTCNoCrtVectorIterator + { + public: + typedef a_Type &reference; + typedef a_Type *pointer; + typedef typename a_Container::difference_type difference_type; + + protected: + a_Type *m_pItem; + + public: + RTCNoCrtVectorIterator() RT_NOEXCEPT + : m_pItem(NULL) + { } + + RTCNoCrtVectorIterator(a_Type *a_pItem) RT_NOEXCEPT + : m_pItem(a_pItem) + { } + + ~RTCNoCrtVectorIterator() + { + m_pItem = NULL; + } + + /** @name Moving the iterator. + * @{ */ + + RTCNoCrtVectorIterator &operator++() RT_NOEXCEPT + { + ++m_pItem; + return *this; + } + + RTCNoCrtVectorIterator &operator--() RT_NOEXCEPT + { + --m_pItem; + return *this; + } + + RTCNoCrtVectorIterator operator++(int) RT_NOEXCEPT + { + return RTCNoCrtVectorIterator(m_pItem++); + } + + RTCNoCrtVectorIterator operator--(int) RT_NOEXCEPT + { + return RTCNoCrtVectorIterator(m_pItem--); + } + + RTCNoCrtVectorIterator &operator+=(difference_type cItems) RT_NOEXCEPT + { + m_pItem += cItems; + return *this; + } + + RTCNoCrtVectorIterator &operator-=(difference_type cItems) RT_NOEXCEPT + { + m_pItem -= cItems; + return *this; + } + + RTCNoCrtVectorIterator operator+(difference_type cItems) const RT_NOEXCEPT + { + return RTCNoCrtVectorIterator(m_pItem + cItems); + } + + RTCNoCrtVectorIterator operator-(difference_type cItems) const RT_NOEXCEPT + { + return RTCNoCrtVectorIterator(m_pItem - cItems); + } + + /** @} */ + + /** @name Item access + * @{ */ + reference operator*() const RT_NOEXCEPT + { + return *m_pItem; + } + + pointer operator->() const RT_NOEXCEPT + { + return m_pItem; + } + + reference operator[](difference_type iItem) const RT_NOEXCEPT + { + return m_pItem[iItem]; + } + + /** @} */ + + /** Helper for const/non-const iterator comparisons: */ + inline typename a_Container::const_pointer getConst() const RT_NOEXCEPT + { + return m_pItem; + } + }; + + template<typename a_TypeLeft, typename a_TypeRight, class a_Container> + inline bool operator==(const RTCNoCrtVectorIterator<a_TypeLeft, a_Container> &a_rLeft, + const RTCNoCrtVectorIterator<a_TypeRight, a_Container> &a_rRight) RT_NOEXCEPT + { + return a_rLeft.getConst() == a_rRight.getConst(); + } + + template<typename a_TypeLeft, typename a_TypeRight, class a_Container> + inline bool operator!=(const RTCNoCrtVectorIterator<a_TypeLeft, a_Container> &a_rLeft, + const RTCNoCrtVectorIterator<a_TypeRight, a_Container> &a_rRight) RT_NOEXCEPT + { + return a_rLeft.getConst() != a_rRight.getConst(); + } + + template<typename a_TypeLeft, typename a_TypeRight, class a_Container> + inline bool operator<(const RTCNoCrtVectorIterator<a_TypeLeft, a_Container> &a_rLeft, + const RTCNoCrtVectorIterator<a_TypeRight, a_Container> &a_rRight) RT_NOEXCEPT + { + return (uintptr_t)a_rLeft.getConst() < (uintptr_t)a_rRight.getConst(); + } + + template<typename a_TypeLeft, typename a_TypeRight, class a_Container> + inline bool operator<=(const RTCNoCrtVectorIterator<a_TypeLeft, a_Container> &a_rLeft, + const RTCNoCrtVectorIterator<a_TypeRight, a_Container> &a_rRight) RT_NOEXCEPT + { + return (uintptr_t)a_rLeft.getConst() <= (uintptr_t)a_rRight.getConst(); + } + + template<typename a_TypeLeft, typename a_TypeRight, class a_Container> + inline bool operator>(const RTCNoCrtVectorIterator<a_TypeLeft, a_Container> &a_rLeft, + const RTCNoCrtVectorIterator<a_TypeRight, a_Container> &a_rRight) RT_NOEXCEPT + { + return (uintptr_t)a_rLeft.getConst() > (uintptr_t)a_rRight.getConst(); + } + + template<typename a_TypeLeft, typename a_TypeRight, class a_Container> + inline bool operator>=(const RTCNoCrtVectorIterator<a_TypeLeft, a_Container> &a_rLeft, + const RTCNoCrtVectorIterator<a_TypeRight, a_Container> &a_rRight) RT_NOEXCEPT + { + return (uintptr_t)a_rLeft.getConst() >= (uintptr_t)a_rRight.getConst(); + } + + + + template<class a_Type, class a_Allocator = std::allocator<a_Type> > + class vector + { + public: + typedef a_Type value_type; + typedef a_Type &reference; + typedef a_Type const &const_reference; + typedef a_Allocator allocator_type; + typedef typename a_Allocator::size_type size_type; + typedef typename a_Allocator::difference_type difference_type; + typedef typename a_Allocator::pointer pointer; + typedef typename a_Allocator::const_pointer const_pointer; + + typedef RTCNoCrtVectorIterator<a_Type, vector> iterator; + typedef RTCNoCrtVectorIterator<const a_Type, vector> const_iterator; + + protected: + pointer m_paItems; + size_t m_cItems; + size_t m_cAllocated; + allocator_type m_Allocator; + + public: + vector() RT_NOEXCEPT + : m_paItems(NULL) + , m_cItems(0) + , m_cAllocated(0) + { } + + vector(size_type a_cAllocate) + : m_paItems(NULL) + , m_cItems(0) + , m_cAllocated(0) + { + m_paItems = m_Allocator.allocate(a_cAllocate); + if (m_paItems) + m_cAllocated = a_cAllocate; + } + + ~vector() + { + clear(); + } + + /** @name Iterators + * @{ */ + iterator begin() RT_NOEXCEPT + { + return iterator(m_paItems); + } + + const_iterator begin() const RT_NOEXCEPT + { + return const_iterator(m_paItems); + } + + const_iterator cbegin() const RT_NOEXCEPT + { + return const_iterator(m_paItems); + } + + iterator end() RT_NOEXCEPT + { + return iterator(m_paItems + m_cItems); + } + + const_iterator end() const RT_NOEXCEPT + { + return const_iterator(m_paItems + m_cItems); + } + + const_iterator cend() const RT_NOEXCEPT + { + return const_iterator(m_paItems + m_cItems); + } + /** @} */ + + /** @name Element access + * @{ */ + reference operator[](size_type iItem) RT_NOEXCEPT + { + Assert(iItem < m_cAllocated); + return m_paItems[iItem]; + } + + const_reference operator[](size_type iItem) const RT_NOEXCEPT + { + Assert(iItem < m_cAllocated); + return m_paItems[iItem]; + } + + reference front() RT_NOEXCEPT + { + return m_paItems[0]; + } + + const_reference front() const RT_NOEXCEPT + { + return m_paItems[0]; + } + + reference back() RT_NOEXCEPT + { + return m_paItems[m_cItems - 1]; + } + + const_reference back() const RT_NOEXCEPT + { + return m_paItems[m_cItems - 1]; + } + + pointer data() RT_NOEXCEPT + { + return m_paItems; + } + + const_pointer data() const RT_NOEXCEPT + { + return m_paItems; + } + + /** @} */ + + /** @name Capacity + * @{ */ + bool empty() const RT_NOEXCEPT + { + return m_cItems == 0; + } + + size_type size() const RT_NOEXCEPT + { + return m_cItems; + } + + size_type max_size() const RT_NOEXCEPT + { + return m_Allocator.max_size(); + } + + void reserve(size_type a_cNewAllocated) + { + Assert(a_cNewAllocated <= max_size()); + + if (a_cNewAllocated > m_cAllocated) + { + vector Temp(a_cNewAllocated); + if (Temp.m_paItems) + { + /* Copy over the data: */ + size_type const cItems = m_cItems; + const_pointer paSrc = m_paItems; + pointer paDst = Temp.m_paItems; + for (size_type i = 0; i < cItems; Temp.m_cItems = ++i) + m_Allocator.construct(&paDst[i], paSrc[i]); + + /* Swap the data. */ + size_type const cOldAllocated = m_cAllocated; + Temp.m_paItems = m_paItems; + m_paItems = paDst; + m_cAllocated = Temp.m_cAllocated; + Temp.m_cAllocated = cOldAllocated; + } + } + } + + /** @} */ + + /** @name Modifiers + * @{ */ + void push_back(const_reference a_rValue) + { + if (m_cItems < m_cAllocated) + { } + else + { + Assert(m_cItems * 2 >= m_cItems); + reserve(m_cItems < 8 ? 8 : m_cItems * 2); /* This might be non-standard. */ + AssertReturnVoid(m_cItems < m_cAllocated); + } + m_paItems[m_cItems] = a_rValue; + m_cItems++; + } + + void pop_back() RT_NOEXCEPT + { + if (m_cItems > 0) + m_cItems -= 1; + } + + void clear() RT_NOEXCEPT + { + size_type i = m_cItems; + while (i-- > 0) + { + m_Allocator.destroy(&m_paItems[i]); + m_cItems = i; + } + m_Allocator.deallocate(m_paItems, m_cAllocated); + m_paItems = NULL; + m_cAllocated = 0; + } + /** @} */ + }; + +} + +#endif /* !VBOX_INCLUDED_SRC_nocrt_vector */ + diff --git a/include/iprt/nocrt/x86/Makefile.kup b/include/iprt/nocrt/x86/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/iprt/nocrt/x86/Makefile.kup diff --git a/include/iprt/nocrt/x86/fenv-x86-amd64.h b/include/iprt/nocrt/x86/fenv-x86-amd64.h new file mode 100644 index 00000000..55199ab8 --- /dev/null +++ b/include/iprt/nocrt/x86/fenv-x86-amd64.h @@ -0,0 +1,219 @@ +/** @file + * IPRT / No-CRT - x86 & AMD64 fenv.h. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_x86_fenv_x86_amd64_h +#define IPRT_INCLUDED_nocrt_x86_fenv_x86_amd64_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +typedef struct RTNOCRTFENV +{ + /** The FPU environment. */ + union + { + uint32_t au32[28/4]; +#ifdef IPRT_INCLUDED_x86_h + X86FSTENV32P Env; +#endif + } fpu; + /** The SSE control & status register. */ + uint32_t fMxCsr; +} RTNOCRTFENV; + +/** Exception flags/mask. */ +typedef uint16_t RTNOCRTFEXCEPT; + +#ifndef IPRT_NOCRT_WITHOUT_CONFLICTING_TYPES +typedef RTNOCRTFENV fenv_t; +typedef RTNOCRTFEXCEPT fexcept_t; +#endif + +/** @name Exception flags (same as X86_FCW_xM, X86_FSW_xE, X86_MXCSR_xE) + * @note The X86_FSW_SF is not covered here as it is more of a sub-type of + * invalid operand exception, and it is not part of MXCSR. + * @{ */ +#define RT_NOCRT_FE_INVALID 0x0001 +#define RT_NOCRT_FE_DENORMAL 0x0002 +#define RT_NOCRT_FE_DIVBYZERO 0x0004 +#define RT_NOCRT_FE_OVERFLOW 0x0008 +#define RT_NOCRT_FE_UNDERFLOW 0x0010 +#define RT_NOCRT_FE_INEXACT 0x0020 +#define RT_NOCRT_FE_ALL_EXCEPT 0x003f +#ifndef IPRT_NOCRT_WITHOUT_MATH_CONSTANTS +# define FE_INVALID RT_NOCRT_FE_INVALID +# define FE_DENORMAL RT_NOCRT_FE_DENORMAL +# define FE_DIVBYZERO RT_NOCRT_FE_DIVBYZERO +# define FE_OVERFLOW RT_NOCRT_FE_OVERFLOW +# define FE_UNDERFLOW RT_NOCRT_FE_UNDERFLOW +# define FE_INEXACT RT_NOCRT_FE_INEXACT +# define FE_ALL_EXCEPT RT_NOCRT_FE_ALL_EXCEPT +#endif +/** @} */ + +/** @name Rounding Modes (same X86_FCW_RC_XXX) + * @{ */ +#define RT_NOCRT_FE_TONEAREST 0x0000 +#define RT_NOCRT_FE_DOWNWARD 0x0400 +#define RT_NOCRT_FE_UPWARD 0x0800 +#define RT_NOCRT_FE_TOWARDZERO 0x0c00 +#define RT_NOCRT_FE_ROUND_MASK 0x0c00 +#ifndef IPRT_NOCRT_WITHOUT_MATH_CONSTANTS +# define FE_TONEAREST RT_NOCRT_FE_TONEAREST +# define FE_DOWNWARD RT_NOCRT_FE_DOWNWARD +# define FE_UPWARD RT_NOCRT_FE_UPWARD +# define FE_TOWARDZERO RT_NOCRT_FE_TOWARDZERO +#endif +/** @} */ + + +/** @name x87 Precision (same X86_FCW_PC_XXX) + * @{ */ +#define RT_NOCRT_PC_FLOAT 0x0000 +#define RT_NOCRT_PC_RSVD 0x0100 +#define RT_NOCRT_PC_DOUBLE 0x0200 +#define RT_NOCRT_PC_EXTENDED 0x0300 +#define RT_NOCRT_PC_MASK 0x0300 +/** @} */ + + +/** @name Special environment pointer values. + * @note Only valid with fesetenv and feupdateenv. + * @note Defined as constants in fesetenv.asm. + * @{ */ +/** The default FPU+SSE environment set, all exceptions disabled (masked). */ +#define RT_NOCRT_FE_DFL_ENV ((RTNOCRTFENV const *)(intptr_t)1) +/** The default FPU+SSE environment set, but all exceptions enabled (unmasked) + * except for RT_NOCRT_FE_DENORMAL. */ +#define RT_NOCRT_FE_NOMASK_ENV ((RTNOCRTFENV const *)(intptr_t)2) +/** The default FPU+SSE environment set, all exceptions disabled (masked), + * double precision (53 bit mantissa). */ +#define RT_NOCRT_FE_PC53_ENV ((RTNOCRTFENV const *)(intptr_t)3) +/** The default FPU+SSE environment set, all exceptions disabled (masked), + * extended double precision (64 bit mantissa). */ +#define RT_NOCRT_FE_PC64_ENV ((RTNOCRTFENV const *)(intptr_t)4) +#ifndef IPRT_NOCRT_WITHOUT_MATH_CONSTANTS +# define FE_DFL_ENV RT_NOCRT_FE_DFL_ENV +# define FE_NOMASK_ENV RT_NOCRT_FE_NOMASK_ENV +# define FE_PC53_ENV RT_NOCRT_FE_PC53_ENV +# define FE_PC64_ENV RT_NOCRT_FE_PC64_ENV +#endif +/** @} */ + +RT_C_DECLS_BEGIN + +int RT_NOCRT(fegetenv)(RTNOCRTFENV *); +int RT_NOCRT(fesetenv)(RTNOCRTFENV const *); +int RT_NOCRT(feholdexcept)(RTNOCRTFENV *); +int RT_NOCRT(feupdateenv)(RTNOCRTFENV const *); + +int RT_NOCRT(fegetround)(void); +int RT_NOCRT(fesetround)(int); + +int RT_NOCRT(fegetexcept)(void); +int RT_NOCRT(feenableexcept)(int); +int RT_NOCRT(fedisableexcept)(int); + +int RT_NOCRT(feclearexcept)(int); +int RT_NOCRT(fetestexcept)(int); +int RT_NOCRT(fegetexceptflag)(RTNOCRTFEXCEPT *, int); +int RT_NOCRT(fesetexceptflag)(RTNOCRTFEXCEPT const *, int); + +int RT_NOCRT(feraiseexcept)(int); + +/* IPRT addition: */ +int RT_NOCRT(fegetx87precision)(void); +int RT_NOCRT(fesetx87precision)(int); + +/* Underscored variants: */ +int RT_NOCRT(_fegetenv)(RTNOCRTFENV *); +int RT_NOCRT(_fesetenv)(RTNOCRTFENV const *); +int RT_NOCRT(_feholdexcept)(RTNOCRTFENV *); +int RT_NOCRT(_feupdateenv)(RTNOCRTFENV const *); + +int RT_NOCRT(_fegetround)(void); +int RT_NOCRT(_fesetround)(int); + +int RT_NOCRT(_fegetexcept)(void); +int RT_NOCRT(_feenableexcept)(int); +int RT_NOCRT(_fedisableexcept)(int); + +int RT_NOCRT(_feclearexcept)(int); +int RT_NOCRT(_fetestexcept)(int); +int RT_NOCRT(_fegetexceptflag)(RTNOCRTFEXCEPT *, int); +int RT_NOCRT(_fesetexceptflag)(RTNOCRTFEXCEPT const *, int); + +int RT_NOCRT(_feraiseexcept)(int); + +/* Aliases: */ +#if !defined(RT_WITHOUT_NOCRT_WRAPPERS) && !defined(RT_WITHOUT_NOCRT_WRAPPER_ALIASES) +# define fegetenv RT_NOCRT(fegetenv) +# define fesetenv RT_NOCRT(fesetenv) +# define feholdexcept RT_NOCRT(feholdexcept) +# define feupdateenv RT_NOCRT(feupdateenv) +# define fegetround RT_NOCRT(fegetround) +# define fesetround RT_NOCRT(fesetround) +# define fegetexcept RT_NOCRT(fegetexcept) +# define feenableexcept RT_NOCRT(feenableexcept) +# define fedisableexcept RT_NOCRT(fedisableexcept) +# define feclearexcept RT_NOCRT(feclearexcept) +# define fetestexcept RT_NOCRT(fetestexcept) +# define fegetexceptflag RT_NOCRT(fegetexceptflag) +# define fesetexceptflag RT_NOCRT(fesetexceptflag) +# define feraiseexcept RT_NOCRT(feraiseexcept) + +/* Underscored variants: */ +# define _fegetenv RT_NOCRT(fegetenv) +# define _fesetenv RT_NOCRT(fesetenv) +# define _feholdexcept RT_NOCRT(feholdexcept) +# define _feupdateenv RT_NOCRT(feupdateenv) +# define _fegetround RT_NOCRT(fegetround) +# define _fesetround RT_NOCRT(fesetround) +# define _fegetexcept RT_NOCRT(fegetexcept) +# define _feenableexcept RT_NOCRT(feenableexcept) +# define _fedisableexcept RT_NOCRT(fedisableexcept) +# define _feclearexcept RT_NOCRT(feclearexcept) +# define _fetestexcept RT_NOCRT(fetestexcept) +# define _fegetexceptflag RT_NOCRT(fegetexceptflag) +# define _fesetexceptflag RT_NOCRT(fesetexceptflag) +# define _feraiseexcept RT_NOCRT(feraiseexcept) +#endif + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_nocrt_x86_fenv_x86_amd64_h */ + diff --git a/include/iprt/nocrt/x86/math.h b/include/iprt/nocrt/x86/math.h new file mode 100644 index 00000000..1aa223a3 --- /dev/null +++ b/include/iprt/nocrt/x86/math.h @@ -0,0 +1,114 @@ +/** @file + * IPRT / No-CRT - math.h, x86 inlined functions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nocrt_x86_math_h +#define IPRT_INCLUDED_nocrt_x86_math_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/asm.h> + +#if RT_INLINE_ASM_GNU_STYLE + +DECLINLINE(long double) inline_atan2l(long double lrd1, long double lrd2) +{ + long double lrdResult; + __asm__ __volatile__("fpatan" + : "=t" (lrdResult) + : "u" (lrd1), + "0" (lrd2) + : "st(1)"); + return lrdResult; +} + +DECLINLINE(long double) inline_rintl(long double lrd) +{ + long double lrdResult; + __asm__ __volatile__("frndint" + : "=t" (lrdResult) + : "0" (lrd)); + return lrdResult; +} + +DECLINLINE(float) inline_rintf(float rf) +{ + return (float)inline_rintl(rf); +} + +DECLINLINE(double) inline_rint(double rd) +{ + return (double)inline_rintl(rd); +} + +DECLINLINE(long double) inline_sqrtl(long double lrd) +{ + long double lrdResult; + __asm__ __volatile__("fsqrt" + : "=t" (lrdResult) + : "0" (lrd)); + return lrdResult; +} + +DECLINLINE(float) inline_sqrtf(float rf) +{ + return (float)inline_sqrtl(rf); +} + +DECLINLINE(double) inline_sqrt(double rd) +{ + return (double)inline_sqrtl(rd); +} + + +# undef atan2l +# define atan2l(lrd1, lrd2) inline_atan2l(lrd1, lrd2) +# undef rint +# define rint(rd) inline_rint(rd) +# undef rintf +# define rintf(rf) inline_rintf(rf) +# undef rintl +# define rintl(lrd) inline_rintl(lrd) +# undef sqrt +# define sqrt(rd) inline_sqrt(rd) +# undef sqrtf +# define sqrtf(rf) inline_sqrtf(rf) +# undef sqrtl +# define sqrtl(lrd) inline_sqrtl(lrd) + +#endif /* RT_INLINE_ASM_GNU_STYLE */ + +#endif /* !IPRT_INCLUDED_nocrt_x86_math_h */ + diff --git a/include/iprt/nt/Makefile.kup b/include/iprt/nt/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/iprt/nt/Makefile.kup diff --git a/include/iprt/nt/dispmprt.h b/include/iprt/nt/dispmprt.h new file mode 100644 index 00000000..055648d9 --- /dev/null +++ b/include/iprt/nt/dispmprt.h @@ -0,0 +1,61 @@ +/** @file + * Safe way to include dispmprt.h (DDK). + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_dispmprt_h +#define IPRT_INCLUDED_nt_dispmprt_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* warning C4668: 'DBG' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# ifndef __cplusplus +# pragma warning(disable:4255) /* video.h(1776) : warning C4255: 'VideoPortGetCurrentIrql' : no function prototype given: converting '()' to '(void)' */ +# endif +#endif + +RT_C_DECLS_BEGIN +#include <dispmprt.h> +RT_C_DECLS_END + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_nt_dispmprt_h */ + diff --git a/include/iprt/nt/hyperv.h b/include/iprt/nt/hyperv.h new file mode 100644 index 00000000..aa461a35 --- /dev/null +++ b/include/iprt/nt/hyperv.h @@ -0,0 +1,1768 @@ +/** @file + * Hyper-V related types and definitions. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_hyperv_h +#define IPRT_INCLUDED_nt_hyperv_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#ifndef IN_IDA_PRO +# include <iprt/types.h> +# include <iprt/assertcompile.h> +#else +# define RT_FLEXIBLE_ARRAY +# define RT_FLEXIBLE_ARRAY_EXTENSION +# define AssertCompile(expr) +# define AssertCompileSize(type, size) +# define AssertCompileMemberOffset(type, member, off) +typedef unsigned char uint8_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#endif + + +/** Hyper-V partition ID. */ +typedef uint64_t HV_PARTITION_ID; +/** Invalid Hyper-V partition ID. */ +#define HV_PARTITION_ID_INVALID UINT64_C(0) +/** Hyper-V virtual processor index (== VMCPUID). */ +typedef uint32_t HV_VP_INDEX; +/** Guest physical address (== RTGCPHYS). */ +typedef uint64_t HV_GPA; +/** Guest physical page number. */ +typedef uint64_t HV_GPA_PAGE_NUMBER; +/** System(/parent) physical page number. */ +typedef uint64_t HV_SPA_PAGE_NUMBER; +/** Hyper-V unsigned 128-bit integer type. */ +typedef struct { uint64_t Low64, High64; } HV_UINT128; +/** Hyper-V port ID. */ +typedef union +{ + uint32_t AsUINT32; + struct + { + uint32_t Id : 24; + uint32_t Reserved : 8; + }; +} HV_PORT_ID; +/** Pointer to a Hyper-V port ID. */ +typedef HV_PORT_ID *PHV_PORT_ID; + + +/** + * Hypercall IDs. + */ +typedef enum +{ + HvCallReserved0000 = 0, + + HvCallSwitchVirtualAddressSpace, + HvCallFlushVirtualAddressSpace, + HvCallFlushVirtualAddressList, + HvCallGetLogicalProcessorRunTime, + /* 5, 6 & 7 are deprecated / reserved. */ + HvCallNotifyLongSpinWait = 8, + HvCallParkLogicalProcessors, /**< @since v2 */ + HvCallInvokeHypervisorDebugger, /**< @since v2 - not mentioned in TLFS v5.0b */ + HvCallSendSyntheticClusterIpi, /**< @since v? */ + HvCallModifyVtlProtectionMask, /**< @since v? */ + HvCallEnablePartitionVtl, /**< @since v? */ + HvCallDisablePartitionVtl, /**< @since v? */ + HvCallEnableVpVtl, /**< @since v? */ + HvCallDisableVpVtl, /**< @since v? */ + HvCallVtlCall, /**< @since v? */ + HvCallVtlReturn, /**< @since v? */ + HvCallFlushVirtualAddressSpaceEx, /**< @since v? */ + HvCallFlushVirtualAddressListEx, /**< @since v? */ + HvCallSendSyntheticClusterIpiEx, /**< @since v? */ + /* Reserved: 0x16..0x3f */ + + HvCallCreatePartition = 0x40, + HvCallInitializePartition, + HvCallFinalizePartition, + HvCallDeletePartition, + HvCallGetPartitionProperty, + HvCallSetPartitionProperty, + HvCallGetPartitionId, + HvCallGetNextChildPartition, + HvCallDepositMemory, /**< 0x48 - Repeat call. */ + HvCallWithdrawMemory, /**< 0x49 - Repeat call. */ + HvCallGetMemoryBalance, + HvCallMapGpaPages, /**< 0X4b - Repeat call. */ + HvCallUnmapGpaPages, /**< 0X4c - Repeat call. */ + HvCallInstallIntercept, + HvCallCreateVp, + HvCallDeleteVp, /**< 0x4f - Fast call. */ + HvCallGetVpRegisters, /**< 0x50 - Repeat call. */ + HvCallSetVpRegisters, /**< 0x51 - Repeat call. */ + HvCallTranslateVirtualAddress, + HvCallReadGpa, + HvCallWriteGpa, + HvCallAssertVirtualInterruptV1, + HvCallClearVirtualInterrupt, /**< 0x56 - Fast call. */ + HvCallCreatePortV1, + HvCallDeletePort, /**< 0x58 - Fast call. */ + HvCallConnectPortV1, + HvCallGetPortProperty, + HvCallDisconnectPort, + HvCallPostMessage, + HvCallSignalEvent, + HvCallSavePartitionState, + HvCallRestorePartitionState, + HvCallInitializeEventLogBufferGroup, + HvCallFinalizeEventLogBufferGroup, + HvCallCreateEventLogBuffer, + HvCallDeleteEventLogBuffer, + HvCallMapEventLogBuffer, + HvCallUnmapEventLogBuffer, + HvCallSetEventLogGroupSources, + HvCallReleaseEventLogBuffer, + HvCallFlushEventLogBuffer, + HvCallPostDebugData, + HvCallRetrieveDebugData, + HvCallResetDebugSession, + HvCallMapStatsPage, + HvCallUnmapStatsPage, + HvCallMapSparseGpaPages, /**< @since v2 */ + HvCallSetSystemProperty, /**< @since v2 */ + HvCallSetPortProperty, /**< @since v2 */ + /* 0x71..0x75 reserved/deprecated (was v2 test IDs). */ + HvCallAddLogicalProcessor = 0x76, + HvCallRemoveLogicalProcessor, + HvCallQueryNumaDistance, + HvCallSetLogicalProcessorProperty, + HvCallGetLogicalProcessorProperty, + HvCallGetSystemProperty, + HvCallMapDeviceInterrupt, + HvCallUnmapDeviceInterrupt, + HvCallRetargetDeviceInterrupt, + /* 0x7f is reserved. */ + HvCallMapDevicePages = 0x80, + HvCallUnmapDevicePages, + HvCallAttachDevice, + HvCallDetachDevice, + HvCallNotifyStandbyTransition, + HvCallPrepareForSleep, + HvCallPrepareForHibernate, + HvCallNotifyPartitionEvent, + HvCallGetLogicalProcessorRegisters, + HvCallSetLogicalProcessorRegisters, + HvCallQueryAssociatedLpsforMca, + HvCallNotifyRingEmpty, + HvCallInjectSyntheticMachineCheck, + HvCallScrubPartition, + HvCallCollectLivedump, + HvCallDisableHypervisor, + HvCallModifySparseGpaPages, + HvCallRegisterInterceptResult, + HvCallUnregisterInterceptResult, + /* 0x93 is reserved/undocumented. */ + HvCallAssertVirtualInterrupt = 0x94, + HvCallCreatePort, + HvCallConnectPort, + HvCallGetSpaPageList, + /* 0x98 is reserved. */ + HvCallStartVirtualProcessor = 0x99, + HvCallGetVpIndexFromApicId, + /* 0x9b..0xae are reserved/undocumented. + 0xad: New version of HvCallGetVpRegisters? Perhaps on logical CPU or smth. */ + HvCallFlushGuestPhysicalAddressSpace = 0xaf, + HvCallFlushGuestPhysicalAddressList, + /* 0xb1..0xb4 are unknown */ + HvCallCreateCpuGroup = 0xb5, + HvCallDeleteCpuGroup, + HvCallGetCpuGroupProperty, + HvCallSetCpuGroupProperty, + HvCallGetCpuGroupAffinit, + HvCallGetNextCpuGroup = 0xba, + HvCallGetNextCpuGroupPartition, + HvCallPrecommitGpaPages = 0xbe, + HvCallUncommitGpaPages, /**< Happens when VidDestroyGpaRangeCheckSecure/WHvUnmapGpaRange is called. */ + /* 0xc0 is unknown */ + HvCallVpRunloopRelated = 0xc2, /**< Fast */ + /* 0xc3..0xcb are unknown */ + HvCallQueryVtlProtectionMaskRange = 0xcc, + HvCallModifyVtlProtectionMaskRange, + /* 0xce..0xd1 are unknown */ + HvCallAcquireSparseGpaPageHostAccess = 0xd2, + HvCallReleaseSparseGpaPageHostAccess, + HvCallCheckSparseGpaPageVtlAccess, + HvCallAcquireSparseSpaPageHostAccess = 0xd7, + HvCallReleaseSparseSpaPageHostAccess, + HvCallAcceptGpaPages, /**< 0x18 byte input, zero rep, no output. */ + /* 0xda..0xe0 are unknown (not dug out yet) */ + HvCallMapVpRegisterPage = 0xe1, /**< Takes partition id + VP index (16 bytes). Returns a physical address (8 bytes). */ + HvCallUnmapVpRegisterPage, /**< Takes partition id + VP index. */ + HvCallUnknownE3, + HvCallUnknownE4, + HvCallUnknownE5, + HvCallUnknownE6, + /** Number of defined hypercalls (varies with version). */ + HvCallCount +} HV_CALL_CODE; +AssertCompile(HvCallSendSyntheticClusterIpiEx == 0x15); +AssertCompile(HvCallMapGpaPages == 0x4b); +AssertCompile(HvCallSetPortProperty == 0x70); +AssertCompile(HvCallRetargetDeviceInterrupt == 0x7e); +AssertCompile(HvCallUnregisterInterceptResult == 0x92); +AssertCompile(HvCallGetSpaPageList == 0x97); +AssertCompile(HvCallFlushGuestPhysicalAddressList == 0xb0); +AssertCompile(HvCallUncommitGpaPages == 0xbf); +AssertCompile(HvCallCount == 0xe7); + +/** Makes the first parameter to a hypercall (rcx). */ +#define HV_MAKE_CALL_INFO(a_enmCallCode, a_cReps) ( (uint64_t)(a_enmCallCode) | ((uint64_t)(a_cReps) << 32) ) +/** Makes the return value (success) for a rep hypercall. */ +#define HV_MAKE_CALL_REP_RET(a_cReps) ((uint64_t)(a_cReps) << 32) + +/** Hypercall status code. */ +typedef uint16_t HV_STATUS; + +/** @name Hyper-V Hypercall status codes + * @{ */ +#define HV_STATUS_SUCCESS (0x0000) +#define HV_STATUS_RESERVED_1 (0x0001) +#define HV_STATUS_INVALID_HYPERCALL_CODE (0x0002) +#define HV_STATUS_INVALID_HYPERCALL_INPUT (0x0003) +#define HV_STATUS_INVALID_ALIGNMENT (0x0004) +#define HV_STATUS_INVALID_PARAMETER (0x0005) +#define HV_STATUS_ACCESS_DENIED (0x0006) +#define HV_STATUS_INVALID_PARTITION_STATE (0x0007) +#define HV_STATUS_OPERATION_DENIED (0x0008) +#define HV_STATUS_UNKNOWN_PROPERTY (0x0009) +#define HV_STATUS_PROPERTY_VALUE_OUT_OF_RANGE (0x000a) +#define HV_STATUS_INSUFFICIENT_MEMORY (0x000b) +#define HV_STATUS_PARTITION_TOO_DEEP (0x000c) +#define HV_STATUS_INVALID_PARTITION_ID (0x000d) +#define HV_STATUS_INVALID_VP_INDEX (0x000e) +#define HV_STATUS_RESERVED_F (0x000f) +#define HV_STATUS_NOT_FOUND (0x0010) +#define HV_STATUS_INVALID_PORT_ID (0x0011) +#define HV_STATUS_INVALID_CONNECTION_ID (0x0012) +#define HV_STATUS_INSUFFICIENT_BUFFERS (0x0013) +#define HV_STATUS_NOT_ACKNOWLEDGED (0x0014) +#define HV_STATUS_INVALID_VP_STATE (0x0015) +#define HV_STATUS_ACKNOWLEDGED (0x0016) +#define HV_STATUS_INVALID_SAVE_RESTORE_STATE (0x0017) +#define HV_STATUS_INVALID_SYNIC_STATE (0x0018) +#define HV_STATUS_OBJECT_IN_USE (0x0019) +#define HV_STATUS_INVALID_PROXIMITY_DOMAIN_INFO (0x001a) +#define HV_STATUS_NO_DATA (0x001b) +#define HV_STATUS_INACTIVE (0x001c) +#define HV_STATUS_NO_RESOURCES (0x001d) +#define HV_STATUS_FEATURE_UNAVAILABLE (0x001e) +#define HV_STATUS_PARTIAL_PACKET (0x001f) +#define HV_STATUS_PROCESSOR_FEATURE_SSE3_NOT_SUPPORTED (0x0020) +#define HV_STATUS_PROCESSOR_FEATURE_LAHFSAHF_NOT_SUPPORTED (0x0021) +#define HV_STATUS_PROCESSOR_FEATURE_SSSE3_NOT_SUPPORTED (0x0022) +#define HV_STATUS_PROCESSOR_FEATURE_SSE4_1_NOT_SUPPORTED (0x0023) +#define HV_STATUS_PROCESSOR_FEATURE_SSE4_2_NOT_SUPPORTED (0x0024) +#define HV_STATUS_PROCESSOR_FEATURE_SSE4A_NOT_SUPPORTED (0x0025) +#define HV_STATUS_PROCESSOR_FEATURE_XOP_NOT_SUPPORTED (0x0026) +#define HV_STATUS_PROCESSOR_FEATURE_POPCNT_NOT_SUPPORTED (0x0027) +#define HV_STATUS_PROCESSOR_FEATURE_CMPXCHG16B_NOT_SUPPORTED (0x0028) +#define HV_STATUS_PROCESSOR_FEATURE_ALTMOVCR8_NOT_SUPPORTED (0x0029) +#define HV_STATUS_PROCESSOR_FEATURE_LZCNT_NOT_SUPPORTED (0x002a) +#define HV_STATUS_PROCESSOR_FEATURE_MISALIGNED_SSE_NOT_SUPPORTED (0x002b) +#define HV_STATUS_PROCESSOR_FEATURE_MMX_EXT_NOT_SUPPORTED (0x002c) +#define HV_STATUS_PROCESSOR_FEATURE_3DNOW_NOT_SUPPORTED (0x002d) +#define HV_STATUS_PROCESSOR_FEATURE_EXTENDED_3DNOW_NOT_SUPPORTED (0x002e) +#define HV_STATUS_PROCESSOR_FEATURE_PAGE_1GB_NOT_SUPPORTED (0x002f) +#define HV_STATUS_PROCESSOR_CACHE_LINE_FLUSH_SIZE_INCOMPATIBLE (0x0030) +#define HV_STATUS_PROCESSOR_FEATURE_XSAVE_NOT_SUPPORTED (0x0031) +#define HV_STATUS_PROCESSOR_FEATURE_XSAVEOPT_NOT_SUPPORTED (0x0032) +#define HV_STATUS_INSUFFICIENT_BUFFER (0x0033) +#define HV_STATUS_PROCESSOR_FEATURE_XSAVE_AVX_NOT_SUPPORTED (0x0034) +#define HV_STATUS_PROCESSOR_FEATURE_XSAVE_ FEATURE_NOT_SUPPORTED (0x0035) +#define HV_STATUS_PROCESSOR_XSAVE_SAVE_AREA_INCOMPATIBLE (0x0036) +#define HV_STATUS_INCOMPATIBLE_PROCESSOR (0x0037) +#define HV_STATUS_INSUFFICIENT_DEVICE_DOMAINS (0x0038) +#define HV_STATUS_PROCESSOR_FEATURE_AES_NOT_SUPPORTED (0x0039) +#define HV_STATUS_PROCESSOR_FEATURE_PCLMULQDQ_NOT_SUPPORTED (0x003a) +#define HV_STATUS_PROCESSOR_FEATURE_INCOMPATIBLE_XSAVE_FEATURES (0x003b) +#define HV_STATUS_CPUID_FEATURE_VALIDATION_ERROR (0x003c) +#define HV_STATUS_CPUID_XSAVE_FEATURE_VALIDATION_ERROR (0x003d) +#define HV_STATUS_PROCESSOR_STARTUP_TIMEOUT (0x003e) +#define HV_STATUS_SMX_ENABLED (0x003f) +#define HV_STATUS_PROCESSOR_FEATURE_PCID_NOT_SUPPORTED (0x0040) +#define HV_STATUS_INVALID_LP_INDEX (0x0041) +#define HV_STATUS_FEATURE_FMA4_NOT_SUPPORTED (0x0042) +#define HV_STATUS_FEATURE_F16C_NOT_SUPPORTED (0x0043) +#define HV_STATUS_PROCESSOR_FEATURE_RDRAND_NOT_SUPPORTED (0x0044) +#define HV_STATUS_PROCESSOR_FEATURE_RDWRFSGS_NOT_SUPPORTED (0x0045) +#define HV_STATUS_PROCESSOR_FEATURE_SMEP_NOT_SUPPORTED (0x0046) +#define HV_STATUS_PROCESSOR_FEATURE_ENHANCED_FAST_STRING_NOT_SUPPORTED (0x0047) +#define HV_STATUS_PROCESSOR_FEATURE_MOVBE_NOT_SUPPORTED (0x0048) +#define HV_STATUS_PROCESSOR_FEATURE_BMI1_NOT_SUPPORTED (0x0049) +#define HV_STATUS_PROCESSOR_FEATURE_BMI2_NOT_SUPPORTED (0x004a) +#define HV_STATUS_PROCESSOR_FEATURE_HLE_NOT_SUPPORTED (0x004b) +#define HV_STATUS_PROCESSOR_FEATURE_RTM_NOT_SUPPORTED (0x004c) +#define HV_STATUS_PROCESSOR_FEATURE_XSAVE_FMA_NOT_SUPPORTED (0x004d) +#define HV_STATUS_PROCESSOR_FEATURE_XSAVE_AVX2_NOT_SUPPORTED (0x004e) +#define HV_STATUS_PROCESSOR_FEATURE_NPIEP1_NOT_SUPPORTED (0x004f) +#define HV_STATUS_INVALID_REGISTER_VALUE (0x0050) +#define HV_STATUS_PROCESSOR_FEATURE_RDSEED_NOT_SUPPORTED (0x0052) +#define HV_STATUS_PROCESSOR_FEATURE_ADX_NOT_SUPPORTED (0x0053) +#define HV_STATUS_PROCESSOR_FEATURE_SMAP_NOT_SUPPORTED (0x0054) +#define HV_STATUS_NX_NOT_DETECTED (0x0055) +#define HV_STATUS_PROCESSOR_FEATURE_INTEL_PREFETCH_NOT_SUPPORTED (0x0056) +#define HV_STATUS_INVALID_DEVICE_ID (0x0057) +#define HV_STATUS_INVALID_DEVICE_STATE (0x0058) +#define HV_STATUS_PENDING_PAGE_REQUESTS (0x0059) +#define HV_STATUS_PAGE_REQUEST_INVALID (0x0060) +#define HV_STATUS_OPERATION_FAILED (0x0071) +#define HV_STATUS_NOT_ALLOWED_WITH_NESTED_VIRT_ACTIVE (0x0072) +/** @} */ + + +/** Hyper-V partition property value. */ +typedef uint64_t HV_PARTITION_PROPERTY; +/** Pointer to a partition property value. */ +typedef HV_PARTITION_PROPERTY *PHV_PARTITION_PROPERTY; +/** + * Hyper-V partition property code. + * This is documented in TLFS, except version 5.x. + */ +typedef enum +{ + HvPartitionPropertyPrivilegeFlags = 0x00010000, + HvPartitionPropertySyntheticProcessorFeaturesBanks, /**< Read by WHvApi::Capabilities::GetSyntheticProcessorFeaturesBanks (build 22000) */ + + HvPartitionPropertyCpuReserve = 0x00020001, + HvPartitionPropertyCpuCap, + HvPartitionPropertyCpuWeight, + HvPartitionPropertyUnknown20004, /**< On exo partition (build 17134), initial value zero. */ + + HvPartitionPropertyEmulatedTimerPeriod = 0x00030000, /**< @note Fails on exo partition (build 17134). */ + HvPartitionPropertyEmulatedTimerControl, /**< @note Fails on exo partition (build 17134). */ + HvPartitionPropertyPmTimerAssist, /**< @note Fails on exo partition (build 17134). */ + HvPartitionPropertyUnknown30003, /**< @note WHvSetupPartition writes this (build 22000). */ + HvPartitionPropertyUnknown30004, /**< ? */ + HvPartitionPropertyUnknown30005, /**< WHvPartitionPropertyCodeReferenceTime maps to this (build 22000) */ + + HvPartitionPropertyDebugChannelId = 0x00040000, /**< @note Hangs system on exo partition hangs (build 17134). */ + + HvPartitionPropertyVirtualTlbPageCount = 0x00050000, + HvPartitionPropertyUnknown50001, /**< On exo partition (build 17134), initial value zero. */ + HvPartitionPropertyUnknown50002, /**< On exo partition (build 17134), initial value zero. */ + HvPartitionPropertyUnknown50003, /**< On exo partition (build 17134), initial value zero. */ + HvPartitionPropertyUnknown50004, /**< On exo partition (build 17134), initial value zero. */ + HvPartitionPropertyUnknown50005, /**< On exo partition (build 17134), initial value one. */ + HvPartitionPropertyUnknown50006, /**< On exo partition (build 17134), initial value zero. + * @note build 22000/w11-ga fends this off in VID.SYS. */ + HvPartitionPropertyUnknown50007, + HvPartitionPropertyUnknown50008, + HvPartitionPropertyUnknown50009, + HvPartitionPropertyUnknown5000a, + HvPartitionPropertyUnknown5000b, + HvPartitionPropertyUnknown5000c, + HvPartitionPropertyUnknown5000d, + HvPartitionPropertyUnknown5000e, + HvPartitionPropertyUnknown5000f, + HvPartitionPropertyUnknown50010, + HvPartitionPropertyUnknown50012, + HvPartitionPropertyUnknown50013, /**< Set by WHvSetupPartition (build 22000) */ + HvPartitionPropertyUnknown50014, + HvPartitionPropertyUnknown50015, + HvPartitionPropertyUnknown50016, + HvPartitionPropertyUnknown50017, /**< Set by WHvSetupPartition (build 22000) */ + + HvPartitionPropertyProcessorVendor = 0x00060000, + HvPartitionPropertyProcessorFeatures, /**< On exo/17134/threadripper: 0x6cb26f39fbf */ + HvPartitionPropertyProcessorXsaveFeatures, + HvPartitionPropertyProcessorCLFlushSize, /**< On exo/17134/threadripper: 8 */ + HvPartitionPropertyUnknown60004, /**< On exo partition (build 17134), initial value zero. */ + HvPartitionPropertyUnknown60005, /**< On exo partition (build 17134), initial value 0x603. */ + HvPartitionPropertyUnknown60006, /**< On exo partition (build 17134), initial value 0x2c. */ + HvPartitionPropertyUnknown60007, /**< WHvSetupPartition reads this (build 22000). */ + HvPartitionPropertyUnknown60008, /**< WHvSetupPartition reads this (build 22000). */ + HvPartitionPropertyProcessorClockFrequency, /**< Read by WHvApi::Capabilities::GetProcessorClockFrequency (build 22000). */ + HvPartitionPropertyProcessorFeaturesBank0, /**< Read by WHvApi::Capabilities::GetProcessorFeaturesBanks (build 22000). */ + HvPartitionPropertyProcessorFeaturesBank1, /**< Read by WHvApi::Capabilities::GetProcessorFeaturesBanks (build 22000). */ + + HvPartitionPropertyGuestOsId = 0x00070000, /**< @since v4 */ + + HvPartitionPropertyUnknown800000 = 0x00080000 /**< On exo partition (build 17134), initial value zero. */ +} HV_PARTITION_PROPERTY_CODE; +AssertCompileSize(HV_PARTITION_PROPERTY_CODE, 4); +/** Pointer to a partition property code. */ +typedef HV_PARTITION_PROPERTY_CODE *PHV_PARTITION_PROPERTY_CODE; + + +/** Input for HvCallGetPartitionProperty. */ +typedef struct +{ + HV_PARTITION_ID PartitionId; + HV_PARTITION_PROPERTY_CODE PropertyCode; + uint32_t uPadding; +} HV_INPUT_GET_PARTITION_PROPERTY; +AssertCompileSize(HV_INPUT_GET_PARTITION_PROPERTY, 16); +/** Pointer to input for HvCallGetPartitionProperty. */ +typedef HV_INPUT_GET_PARTITION_PROPERTY *PHV_INPUT_GET_PARTITION_PROPERTY; + +/** Output for HvCallGetPartitionProperty. */ +typedef struct +{ + HV_PARTITION_PROPERTY PropertyValue; +} HV_OUTPUT_GET_PARTITION_PROPERTY; +/** Pointer to output for HvCallGetPartitionProperty. */ +typedef HV_OUTPUT_GET_PARTITION_PROPERTY *PHV_OUTPUT_GET_PARTITION_PROPERTY; + + +/** Input for HvCallSetPartitionProperty. */ +typedef struct +{ + HV_PARTITION_ID PartitionId; + HV_PARTITION_PROPERTY_CODE PropertyCode; + uint32_t uPadding; + HV_PARTITION_PROPERTY PropertyValue; +} HV_INPUT_SET_PARTITION_PROPERTY; +AssertCompileSize(HV_INPUT_SET_PARTITION_PROPERTY, 24); +/** Pointer to input for HvCallSetPartitionProperty. */ +typedef HV_INPUT_SET_PARTITION_PROPERTY *PHV_INPUT_SET_PARTITION_PROPERTY; + + +/** Hyper-V NUMA node ID. + * On systems without NUMA, i.e. a single node, it uses 0 as identifier. */ +typedef uint32_t HV_PROXIMITY_DOMAIN_ID; +/** Pointer to NUMA node ID. */ +typedef HV_PROXIMITY_DOMAIN_ID *PHV_PROXIMITY_DOMAIN_ID; + +/** Hyper-V NUMA flags. */ +typedef struct +{ + uint32_t ProximityPreferred : 1; /**< When set, allocations may come from other NUMA nodes. */ + uint32_t Reserved : 30; /**< Reserved for future (as of circa v2). */ + uint32_t ProxyimityInfoValid : 1; /**< Set if the NUMA information is valid. */ +} HV_PROXIMITY_DOMAIN_FLAGS; +/** Pointer to Hyper-V NUMA flags. */ +typedef HV_PROXIMITY_DOMAIN_FLAGS *PHV_PROXIMITY_DOMAIN_FLAGS; + +/** Hyper-V NUMA information. */ +typedef struct +{ + HV_PROXIMITY_DOMAIN_ID Id; /**< NUMA node identifier. */ + HV_PROXIMITY_DOMAIN_FLAGS Flags; /**< NUMA flags. */ +} HV_PROXIMITY_DOMAIN_INFO; +/** Pointer to Hyper-V NUMA information. */ +typedef HV_PROXIMITY_DOMAIN_INFO *PHV_PROXIMITY_DOMAIN_INFO; + +/** Input for HvCallGetMemoryBalance. */ +typedef struct +{ + HV_PARTITION_ID TargetPartitionId; + HV_PROXIMITY_DOMAIN_INFO ProximityDomainInfo; +} HV_INPUT_GET_MEMORY_BALANCE; +AssertCompileSize(HV_INPUT_GET_MEMORY_BALANCE, 16); +/** Pointer to the input for HvCallGetMemoryBalance. */ +typedef HV_INPUT_GET_MEMORY_BALANCE *PHV_INPUT_GET_MEMORY_BALANCE; + +/** Output for HvCallGetMemoryBalance. */ +typedef struct +{ + uint64_t PagesAvailable; + uint64_t PagesInUse; +} HV_OUTPUT_GET_MEMORY_BALANCE; +/** Pointer to the output for HvCallGetMemoryBalance. */ +typedef HV_OUTPUT_GET_MEMORY_BALANCE *PHV_OUTPUT_GET_MEMORY_BALANCE; + + +/** @name Flags used with HvCallMapGpaPages and HvCallMapSparseGpaPages. + * @note There seems to be a more flags defined after v2. + * @{ */ +typedef uint32_t HV_MAP_GPA_FLAGS; +#define HV_MAP_GPA_READABLE UINT32_C(0x0001) +#define HV_MAP_GPA_WRITABLE UINT32_C(0x0002) +#define HV_MAP_GPA_EXECUTABLE UINT32_C(0x0004) +/** Seems this have to be set when HV_MAP_GPA_EXECUTABLE is (17101). */ +#define HV_MAP_GPA_EXECUTABLE_AGAIN UINT32_C(0x0008) +/** Dunno what this is yet, but it requires HV_MAP_GPA_DUNNO_1000. + * The readable bit gets put here when both HV_MAP_GPA_DUNNO_1000 and + * HV_MAP_GPA_DUNNO_MASK_0700 are clear. */ +#define HV_MAP_GPA_DUNNO_ACCESS UINT32_C(0x0010) +/** Guess work. */ +#define HV_MAP_GPA_MAYBE_ACCESS_MASK UINT32_C(0x001f) +/** Some kind of mask. */ +#define HV_MAP_GPA_DUNNO_MASK_0700 UINT32_C(0x0700) +/** Dunno what this is, but required for HV_MAP_GPA_DUNNO_ACCESS. */ +#define HV_MAP_GPA_DUNNO_1000 UINT32_C(0x1000) +/** Working with large 2MB pages. */ +#define HV_MAP_GPA_LARGE UINT32_C(0x2000) +/** Valid mask as per build 17101. */ +#define HV_MAP_GPA_VALID_MASK UINT32_C(0x7f1f) +/** @} */ + +/** Input for HvCallMapGpaPages. */ +typedef struct +{ + HV_PARTITION_ID TargetPartitionId; + HV_GPA_PAGE_NUMBER TargetGpaBase; + HV_MAP_GPA_FLAGS MapFlags; + uint32_t u32ExplicitPadding; + /* The repeating part: */ + RT_FLEXIBLE_ARRAY_EXTENSION + HV_SPA_PAGE_NUMBER PageList[RT_FLEXIBLE_ARRAY]; +} HV_INPUT_MAP_GPA_PAGES; +AssertCompileMemberOffset(HV_INPUT_MAP_GPA_PAGES, PageList, 24); +/** Pointer to the input for HvCallMapGpaPages. */ +typedef HV_INPUT_MAP_GPA_PAGES *PHV_INPUT_MAP_GPA_PAGES; + + +/** A parent to guest mapping pair for HvCallMapSparseGpaPages. */ +typedef struct +{ + HV_GPA_PAGE_NUMBER TargetGpaPageNumber; + HV_SPA_PAGE_NUMBER SourceSpaPageNumber; +} HV_GPA_MAPPING; +/** Pointer to a parent->guest mapping pair for HvCallMapSparseGpaPages. */ +typedef HV_GPA_MAPPING *PHV_GPA_MAPPING; + +/** Input for HvCallMapSparseGpaPages. */ +typedef struct +{ + HV_PARTITION_ID TargetPartitionId; + HV_MAP_GPA_FLAGS MapFlags; + uint32_t u32ExplicitPadding; + /* The repeating part: */ + RT_FLEXIBLE_ARRAY_EXTENSION + HV_GPA_MAPPING PageList[RT_FLEXIBLE_ARRAY]; +} HV_INPUT_MAP_SPARSE_GPA_PAGES; +AssertCompileMemberOffset(HV_INPUT_MAP_SPARSE_GPA_PAGES, PageList, 16); +/** Pointer to the input for HvCallMapSparseGpaPages. */ +typedef HV_INPUT_MAP_SPARSE_GPA_PAGES *PHV_INPUT_MAP_SPARSE_GPA_PAGES; + + +/** Input for HvCallUnmapGpaPages. */ +typedef struct +{ + HV_PARTITION_ID TargetPartitionId; + HV_GPA_PAGE_NUMBER TargetGpaBase; + /** This field is either an omission in the 7600 WDK or a later additions. + * Anyway, not quite sure what it does. Bit 2 seems to indicate 2MB pages. */ + uint64_t fFlags; +} HV_INPUT_UNMAP_GPA_PAGES; +AssertCompileSize(HV_INPUT_UNMAP_GPA_PAGES, 24); +/** Pointer to the input for HvCallUnmapGpaPages. */ +typedef HV_INPUT_UNMAP_GPA_PAGES *PHV_INPUT_UNMAP_GPA_PAGES; + + + +/** Cache types used by HvCallReadGpa and HvCallWriteGpa. */ +typedef enum +{ + HvCacheTypeX64Uncached = 0, + HvCacheTypeX64WriteCombining, + /* 2 & 3 are undefined. */ + HvCacheTypeX64WriteThrough = 4, + HvCacheTypeX64WriteProtected, + HvCacheTypeX64WriteBack +} HV_CACHE_TYPE; + +/** Control flags for HvCallReadGpa and HvCallWriteGpa. */ +typedef union +{ + uint64_t AsUINT64; + struct + { + uint64_t CacheType : 8; /**< HV_CACHE_TYPE */ +#ifndef IN_IDA_PRO + uint64_t Reserved : 56; +#endif + }; +} HV_ACCESS_GPA_CONTROL_FLAGS; + +/** Results codes for HvCallReadGpa and HvCallWriteGpa. */ +typedef enum +{ + HvAccessGpaSuccess = 0, + HvAccessGpaUnmapped, + HvAccessGpaReadIntercept, + HvAccessGpaWriteIntercept, + HvAccessGpaIllegalOverlayAccess +} HV_ACCESS_GPA_RESULT_CODE; + +/** The result of HvCallReadGpa and HvCallWriteGpa. */ +typedef union +{ + uint64_t AsUINT64; + struct + { + HV_ACCESS_GPA_RESULT_CODE ResultCode; + uint32_t Reserved; + }; +} HV_ACCESS_GPA_RESULT; + + +/** Input for HvCallReadGpa. */ +typedef struct +{ + HV_PARTITION_ID PartitionId; + HV_VP_INDEX VpIndex; + uint32_t ByteCount; + HV_GPA BaseGpa; + HV_ACCESS_GPA_CONTROL_FLAGS ControlFlags; +} HV_INPUT_READ_GPA; +AssertCompileSize(HV_INPUT_READ_GPA, 32); +/** Pointer to the input for HvCallReadGpa. */ +typedef HV_INPUT_READ_GPA *PHV_INPUT_READ_GPA; + +/** Output for HvCallReadGpa. */ +typedef struct +{ + HV_ACCESS_GPA_RESULT AccessResult; + uint8_t Data[16]; +} HV_OUTPUT_READ_GPA; +AssertCompileSize(HV_OUTPUT_READ_GPA, 24); +/** Pointer to the output for HvCallReadGpa. */ +typedef HV_OUTPUT_READ_GPA *PHV_OUTPUT_READ_GPA; + + +/** Input for HvCallWriteGpa. */ +typedef struct +{ + HV_PARTITION_ID PartitionId; + HV_VP_INDEX VpIndex; + uint32_t ByteCount; + HV_GPA BaseGpa; + HV_ACCESS_GPA_CONTROL_FLAGS ControlFlags; + uint8_t Data[16]; +} HV_INPUT_WRITE_GPA; +AssertCompileSize(HV_INPUT_READ_GPA, 32); +/** Pointer to the input for HvCallWriteGpa. */ +typedef HV_INPUT_READ_GPA *PHV_INPUT_READ_GPA; + +/** Output for HvCallWriteGpa. */ +typedef struct +{ + HV_ACCESS_GPA_RESULT AccessResult; +} HV_OUTPUT_WRITE_GPA; +AssertCompileSize(HV_OUTPUT_WRITE_GPA, 8); +/** Pointer to the output for HvCallWriteGpa. */ +typedef HV_OUTPUT_WRITE_GPA *PHV_OUTPUT_WRITE_GPA; + + +/** + * Register names used by HvCallGetVpRegisters and HvCallSetVpRegisters. + */ +typedef enum _HV_REGISTER_NAME +{ + HvRegisterExplicitSuspend = 0x00000000, + HvRegisterInterceptSuspend, + HvRegisterUnknown02, /**< Reads as 0 initially on exo part. */ + HvRegisterUnknown03, /**< Reads as 0 initially on exo part. */ + HvRegisterInternalActivityState, /**< @since about build 17758 */ + + HvRegisterHypervisorVersion = 0x00000100, /**< @since v5 @note Not readable on exo part. */ + + HvRegisterPrivilegesAndFeaturesInfo = 0x00000200, /**< @since v5 @note Not readable on exo part. */ + HvRegisterFeaturesInfo, /**< @since v5 @note Not readable on exo part. */ + HvRegisterImplementationLimitsInfo, /**< @since v5 @note Not readable on exo part. */ + HvRegisterHardwareFeaturesInfo, /**< @since v5 @note Not readable on exo part. */ + + HvRegisterGuestCrashP0 = 0x00000210, /**< @since v5 @note Not readable on exo part. */ + HvRegisterGuestCrashP1, /**< @since v5 @note Not readable on exo part. */ + HvRegisterGuestCrashP2, /**< @since v5 @note Not readable on exo part. */ + HvRegisterGuestCrashP3, /**< @since v5 @note Not readable on exo part. */ + HvRegisterGuestCrashP4, /**< @since v5 @note Not readable on exo part. */ + HvRegisterGuestCrashCtl, /**< @since v5 @note Not readable on exo part. */ + + HvRegisterPowerStateConfigC1 = 0x00000220, /**< @since v5 @note Not readable on exo part. */ + HvRegisterPowerStateTriggerC1, /**< @since v5 @note Not readable on exo part. */ + HvRegisterPowerStateConfigC2, /**< @since v5 @note Not readable on exo part. */ + HvRegisterPowerStateTriggerC2, /**< @since v5 @note Not readable on exo part. */ + HvRegisterPowerStateConfigC3, /**< @since v5 @note Not readable on exo part. */ + HvRegisterPowerStateTriggerC3, /**< @since v5 @note Not readable on exo part. */ + + HvRegisterSystemReset = 0x00000230, /**< @since v5 @note Not readable on exo part. */ + + HvRegisterProcessorClockFrequency = 0x00000240, /**< @since v5 @note Not readable on exo part. */ + HvRegisterInterruptClockFrequency, /**< @since v5 @note Not readable on exo part. */ + + HvRegisterGuestIdle = 0x00000250, /**< @since v5 @note Not readable on exo part. */ + + HvRegisterDebugDeviceOptions = 0x00000260, /**< @since v5 @note Not readable on exo part. */ + + HvRegisterPendingInterruption = 0x00010002, + HvRegisterInterruptState, + HvRegisterPendingEvent0, /**< @since v5 */ + HvRegisterPendingEvent1, /**< @since v5 */ + HvX64RegisterDeliverabilityNotifications, /**< @since v5c? Late 2017? */ + + HvX64RegisterRax = 0x00020000, + HvX64RegisterRcx, + HvX64RegisterRdx, + HvX64RegisterRbx, + HvX64RegisterRsp, + HvX64RegisterRbp, + HvX64RegisterRsi, + HvX64RegisterRdi, + HvX64RegisterR8, + HvX64RegisterR9, + HvX64RegisterR10, + HvX64RegisterR11, + HvX64RegisterR12, + HvX64RegisterR13, + HvX64RegisterR14, + HvX64RegisterR15, + HvX64RegisterRip, + HvX64RegisterRflags, + + HvX64RegisterXmm0 = 0x00030000, + HvX64RegisterXmm1, + HvX64RegisterXmm2, + HvX64RegisterXmm3, + HvX64RegisterXmm4, + HvX64RegisterXmm5, + HvX64RegisterXmm6, + HvX64RegisterXmm7, + HvX64RegisterXmm8, + HvX64RegisterXmm9, + HvX64RegisterXmm10, + HvX64RegisterXmm11, + HvX64RegisterXmm12, + HvX64RegisterXmm13, + HvX64RegisterXmm14, + HvX64RegisterXmm15, + HvX64RegisterFpMmx0, + HvX64RegisterFpMmx1, + HvX64RegisterFpMmx2, + HvX64RegisterFpMmx3, + HvX64RegisterFpMmx4, + HvX64RegisterFpMmx5, + HvX64RegisterFpMmx6, + HvX64RegisterFpMmx7, + HvX64RegisterFpControlStatus, + HvX64RegisterXmmControlStatus, + + HvX64RegisterCr0 = 0x00040000, + HvX64RegisterCr2, + HvX64RegisterCr3, + HvX64RegisterCr4, + HvX64RegisterCr8, + HvX64RegisterXfem, + + HvX64RegisterIntermediateCr0 = 0x00041000, /**< @since v5 */ + HvX64RegisterIntermediateCr4 = 0x00041003, /**< @since v5 */ + HvX64RegisterIntermediateCr8, /**< @since v5 */ + + HvX64RegisterDr0 = 0x00050000, + HvX64RegisterDr1, + HvX64RegisterDr2, + HvX64RegisterDr3, + HvX64RegisterDr6, + HvX64RegisterDr7, + + HvX64RegisterEs = 0x00060000, + HvX64RegisterCs, + HvX64RegisterSs, + HvX64RegisterDs, + HvX64RegisterFs, + HvX64RegisterGs, + HvX64RegisterLdtr, + HvX64RegisterTr, + + HvX64RegisterIdtr = 0x00070000, + HvX64RegisterGdtr, + + HvX64RegisterTsc = 0x00080000, + HvX64RegisterEfer, + HvX64RegisterKernelGsBase, + HvX64RegisterApicBase, + HvX64RegisterPat, + HvX64RegisterSysenterCs, + HvX64RegisterSysenterEip, + HvX64RegisterSysenterEsp, + HvX64RegisterStar, + HvX64RegisterLstar, + HvX64RegisterCstar, + HvX64RegisterSfmask, + HvX64RegisterInitialApicId, + + HvX64RegisterMtrrCap, /**< Not readable in exo partitions? */ + HvX64RegisterMtrrDefType, + + HvX64RegisterMtrrPhysBase0 = 0x00080010, + HvX64RegisterMtrrPhysBase1, + HvX64RegisterMtrrPhysBase2, + HvX64RegisterMtrrPhysBase3, + HvX64RegisterMtrrPhysBase4, + HvX64RegisterMtrrPhysBase5, + HvX64RegisterMtrrPhysBase6, + HvX64RegisterMtrrPhysBase7, + HvX64RegisterMtrrPhysBase8, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysBase9, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysBaseA, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysBaseB, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysBaseC, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysBaseD, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysBaseE, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysBaseF, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + + HvX64RegisterMtrrPhysMask0 = 0x00080040, + HvX64RegisterMtrrPhysMask1, + HvX64RegisterMtrrPhysMask2, + HvX64RegisterMtrrPhysMask3, + HvX64RegisterMtrrPhysMask4, + HvX64RegisterMtrrPhysMask5, + HvX64RegisterMtrrPhysMask6, + HvX64RegisterMtrrPhysMask7, + HvX64RegisterMtrrPhysMask8, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysMask9, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysMaskA, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysMaskB, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysMaskC, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysMaskD, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysMaskE, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterMtrrPhysMaskF, /**< @since v4 @note Appears not to be readable on exo partition (Threadripper). */ + + HvX64RegisterMtrrFix64k00000 = 0x00080070, + HvX64RegisterMtrrFix16k80000, + HvX64RegisterMtrrFix16kA0000, + HvX64RegisterMtrrFix4kC0000, + HvX64RegisterMtrrFix4kC8000, + HvX64RegisterMtrrFix4kD0000, + HvX64RegisterMtrrFix4kD8000, + HvX64RegisterMtrrFix4kE0000, + HvX64RegisterMtrrFix4kE8000, + HvX64RegisterMtrrFix4kF0000, + HvX64RegisterMtrrFix4kF8000, + HvX64RegisterTscAux, /**< @since v5c? late 2017? */ + + HvX64RegisterUnknown8007d = 0x0008007d, /**< Readable on exo partition (17134), initial value is zero. */ + + HvX64RegisterSpecCtrl = 0x00080084, /**< @since build about 17758 */ + HvX64RegisterPredCmd, /**< @since build about 17758 */ + + HvX64RegisterIa32MiscEnable = 0x000800a0, /**< @since v5 @note Appears not to be readable on exo partition (Threadripper). */ + HvX64RegisterIa32FeatureControl, /**< @since v5 @note Appears not to be readable on exo partition (Threadripper). */ + + HvX64RegisterApicId = 0x00084802, /**< @since build 17758 */ + HvX64RegisterApicVersion, /**< @since build 17758 */ + + /** Uptime counter or some such thing. Unit is different than HvRegisterTimeRefCount or the accounting is different. */ + HvX64RegisterVpRuntime = 0x00090000, + HvX64RegisterHypercall, + HvRegisterGuestOsId, + HvRegisterVpIndex, + HvRegisterTimeRefCount, /**< Time counter since partition creation, 100ns units. */ + + HvRegisterCpuManagementVersion = 0x00090007, /**< @since v5 @note Appears not to be readable on exo partition. */ + + HvX64RegisterEoi = 0x00090010, /**< @note Appears not to be readable on exo partition. */ + HvX64RegisterIcr, /**< @note Appears not to be readable on exo partition. */ + HvX64RegisterTpr, /**< @note Appears not to be readable on exo partition. */ + HvRegisterVpAssistPage, + /** Readable on exo partition (17134). Some kind of counter. */ + HvRegisterUnknown90014, + + HvRegisterStatsPartitionRetail = 0x00090020, + HvRegisterStatsPartitionInternal, + HvRegisterStatsVpRetail, + HvRegisterStatsVpInternal, + + HvRegisterSint0 = 0x000a0000, + HvRegisterSint1, + HvRegisterSint2, + HvRegisterSint3, + HvRegisterSint4, + HvRegisterSint5, + HvRegisterSint6, + HvRegisterSint7, + HvRegisterSint8, + HvRegisterSint9, + HvRegisterSint10, + HvRegisterSint11, + HvRegisterSint12, + HvRegisterSint13, + HvRegisterSint14, + HvRegisterSint15, + HvRegisterScontrol, + HvRegisterSversion, + HvRegisterSifp, + HvRegisterSipp, + HvRegisterEom, + HvRegisterSirbp, /**< @since v4 */ + + HvRegisterStimer0Config = 0x000b0000, + HvRegisterStimer0Count, + HvRegisterStimer1Config, + HvRegisterStimer1Count, + HvRegisterStimer2Config, + HvRegisterStimer2Count, + HvRegisterStimer3Config, + HvRegisterStimer3Count, + + HvRegisterUnknown0b0100 = 0x000b0100, /**< Readable on exo partition (17134), initial value is zero. */ + HvRegisterUnknown0b0101, /**< Readable on exo partition (17134), initial value is zero. */ + + HvX64RegisterYmm0Low = 0x000c0000, /**< @note Not readable on exo partition. Need something enabled? */ + HvX64RegisterYmm1Low, + HvX64RegisterYmm2Low, + HvX64RegisterYmm3Low, + HvX64RegisterYmm4Low, + HvX64RegisterYmm5Low, + HvX64RegisterYmm6Low, + HvX64RegisterYmm7Low, + HvX64RegisterYmm8Low, + HvX64RegisterYmm9Low, + HvX64RegisterYmm10Low, + HvX64RegisterYmm11Low, + HvX64RegisterYmm12Low, + HvX64RegisterYmm13Low, + HvX64RegisterYmm14Low, + HvX64RegisterYmm15Low, + HvX64RegisterYmm0High, + HvX64RegisterYmm1High, + HvX64RegisterYmm2High, + HvX64RegisterYmm3High, + HvX64RegisterYmm4High, + HvX64RegisterYmm5High, + HvX64RegisterYmm6High, + HvX64RegisterYmm7High, + HvX64RegisterYmm8High, + HvX64RegisterYmm9High, + HvX64RegisterYmm10High, + HvX64RegisterYmm11High, + HvX64RegisterYmm12High, + HvX64RegisterYmm13High, + HvX64RegisterYmm14High, + HvX64RegisterYmm15High, + + HvRegisterVsmVpVtlControl = 0x000d0000, /**< @note Not readable on exo partition. */ + + HvRegisterVsmCodePageOffsets = 0x000d0002, + HvRegisterVsmVpStatus, + HvRegisterVsmPartitionStatus, + HvRegisterVsmVina, /**< @note Not readable on exo partition. */ + HvRegisterVsmCapabilities, + HvRegisterVsmPartitionConfig, /**< @note Not readable on exo partition. */ + + HvRegisterVsmVpSecureConfigVtl0 = 0x000d0010, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl1, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl2, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl3, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl4, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl5, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl6, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl7, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl8, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl9, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl10, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl11, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl12, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl13, /**< @since v5 */ + HvRegisterVsmVpSecureConfigVtl14, /**< @since v5 */ + + HvRegisterUnknown0e0000 = 0x000e0000, /**< Readable on exo partition (17134), initial value zero. */ + HvRegisterUnknown0e0001, /**< Readable on exo partition (17134), initial value zero. */ + HvRegisterUnknown0e0002, /**< Readable on exo partition (17134), initial value zero. */ + HvRegisterUnknown0e0003 /**< Readable on exo partition (17134), initial value zero. */ +} HV_REGISTER_NAME; +AssertCompile(HvRegisterInterceptSuspend == 0x00000001); +AssertCompile(HvRegisterPendingEvent1 == 0x00010005); +AssertCompile(HvX64RegisterDeliverabilityNotifications == 0x00010006); +AssertCompile(HvX64RegisterRflags == 0x00020011); +AssertCompile(HvX64RegisterXmmControlStatus == 0x00030019); +AssertCompile(HvX64RegisterXfem == 0x00040005); +AssertCompile(HvX64RegisterIntermediateCr0 == 0x00041000); +AssertCompile(HvX64RegisterIntermediateCr4 == 0x00041003); +AssertCompile(HvX64RegisterDr7 == 0x00050005); +AssertCompile(HvX64RegisterTr == 0x00060007); +AssertCompile(HvX64RegisterGdtr == 0x00070001); +AssertCompile(HvX64RegisterInitialApicId == 0x0008000c); +AssertCompile(HvX64RegisterMtrrCap == 0x0008000d); +AssertCompile(HvX64RegisterMtrrDefType == 0x0008000e); +AssertCompile(HvX64RegisterMtrrPhysBaseF == 0x0008001f); +AssertCompile(HvX64RegisterMtrrPhysMaskF == 0x0008004f); +AssertCompile(HvX64RegisterMtrrFix4kF8000 == 0x0008007a); +AssertCompile(HvRegisterTimeRefCount == 0x00090004); +AssertCompile(HvRegisterCpuManagementVersion == 0x00090007); +AssertCompile(HvRegisterVpAssistPage == 0x00090013); +AssertCompile(HvRegisterStatsVpInternal == 0x00090023); +AssertCompile(HvRegisterSirbp == 0x000a0015); +AssertCompile(HvRegisterStimer3Count == 0x000b0007); +AssertCompile(HvX64RegisterYmm15High == 0x000c001f); +AssertCompile(HvRegisterVsmVpSecureConfigVtl14 == 0x000d001e); +AssertCompileSize(HV_REGISTER_NAME, 4); + + +/** Value format for HvRegisterExplicitSuspend. */ +typedef union +{ + uint64_t AsUINT64; + struct + { + uint64_t Suspended : 1; +#ifndef IN_IDA_PRO + uint64_t Reserved : 63; +#endif + }; +} HV_EXPLICIT_SUSPEND_REGISTER; +/** Pointer to a value of HvRegisterExplicitSuspend. */ +typedef HV_EXPLICIT_SUSPEND_REGISTER *PHV_EXPLICIT_SUSPEND_REGISTER; + +/** Value format for HvRegisterInterceptSuspend. */ +typedef union +{ + uint64_t AsUINT64; + struct + { + uint64_t Suspended : 1; + uint64_t TlbLocked : 1; +#ifndef IN_IDA_PRO + uint64_t Reserved : 62; +#endif + }; +} HV_INTERCEPT_SUSPEND_REGISTER; +/** Pointer to a value of HvRegisterInterceptSuspend. */ +typedef HV_INTERCEPT_SUSPEND_REGISTER *PHV_INTERCEPT_SUSPEND_REGISTER; + +/** Value format for HvRegisterInterruptState. + * @sa WHV_X64_INTERRUPT_STATE_REGISTER */ +typedef union +{ + uint64_t AsUINT64; + struct + { + uint64_t InterruptShadow : 1; + uint64_t NmiMasked : 1; +#ifndef IN_IDA_PRO + uint64_t Reserved : 62; +#endif + }; +} HV_X64_INTERRUPT_STATE_REGISTER; +/** Pointer to a value of HvRegisterInterruptState. */ +typedef HV_X64_INTERRUPT_STATE_REGISTER *PHV_X64_INTERRUPT_STATE_REGISTER; + +/** Pending exception type for HvRegisterPendingInterruption. + * @sa WHV_X64_PENDING_INTERRUPTION_TYPE */ +typedef enum +{ + HvX64PendingInterrupt = 0, + /* what is/was 1? */ + HvX64PendingNmi = 2, + HvX64PendingException + /* any more? */ +} HV_X64_PENDING_INTERRUPTION_TYPE; + +/** Value format for HvRegisterPendingInterruption. + * @sa WHV_X64_PENDING_INTERRUPTION_REGISTER */ +typedef union +{ + uint64_t AsUINT64; + struct + { + uint32_t InterruptionPending : 1; + uint32_t InterruptionType : 3; /**< HV_X64_PENDING_INTERRUPTION_TYPE */ + uint32_t DeliverErrorCode : 1; + uint32_t InstructionLength : 4; /**< @since v5? Wasn't in 7600 WDK */ + uint32_t NestedEvent : 1; /**< @since v5? Wasn't in 7600 WDK */ + uint32_t Reserved : 6; + uint32_t InterruptionVector : 16; + uint32_t ErrorCode; + }; +} HV_X64_PENDING_INTERRUPTION_REGISTER; +/** Pointer to a value of HvRegisterPendingInterruption. */ +typedef HV_X64_PENDING_INTERRUPTION_REGISTER *PHV_X64_PENDING_INTERRUPTION_REGISTER; + +/** Value format for HvX64RegisterDeliverabilityNotifications. + * Value format for HvRegisterPendingEvent0/1. + * @sa WHV_X64_DELIVERABILITY_NOTIFICATIONS_REGISTER */ +typedef union +{ + uint64_t AsUINT64; + struct + { + uint64_t NmiNotification : 1; + uint64_t InterruptNotification : 1; + uint64_t InterruptPriority : 4; +#ifndef IN_IDA_PRO + uint64_t Reserved : 58; +#endif + }; +} HV_X64_DELIVERABILITY_NOTIFICATIONS_REGISTER; +/** Pointer to a value of HvRegisterPendingEvent0/1. */ +typedef HV_X64_DELIVERABILITY_NOTIFICATIONS_REGISTER *PHV_X64_DELIVERABILITY_NOTIFICATIONS_REGISTER; + + +/** Value format for HvX64RegisterEs..Tr. + * @sa WHV_X64_SEGMENT_REGISTER */ +typedef struct _HV_X64_SEGMENT_REGISTER +{ + uint64_t Base; + uint32_t Limit; + uint16_t Selector; + union + { + struct + { + uint16_t SegmentType : 4; + uint16_t NonSystemSegment : 1; + uint16_t DescriptorPrivilegeLevel : 2; + uint16_t Present : 1; + uint16_t Reserved : 4; + uint16_t Available : 1; + uint16_t Long : 1; + uint16_t Default : 1; + uint16_t Granularity : 1; + }; + uint16_t Attributes; + }; +} HV_X64_SEGMENT_REGISTER; +AssertCompileSize(HV_X64_SEGMENT_REGISTER, 16); +/** Pointer to a value of HvX64RegisterEs..Tr. */ +typedef HV_X64_SEGMENT_REGISTER *PHV_X64_SEGMENT_REGISTER; + +/** Value format for HvX64RegisterIdtr/Gdtr. + * @sa WHV_X64_TABLE_REGISTER */ +typedef struct +{ + uint16_t Pad[3]; + uint16_t Limit; + uint64_t Base; +} HV_X64_TABLE_REGISTER; +AssertCompileSize(HV_X64_TABLE_REGISTER, 16); +/** Pointer to a value of HvX64RegisterIdtr/Gdtrr. */ +typedef HV_X64_TABLE_REGISTER *PHV_X64_TABLE_REGISTER; + +/** Value format for HvX64RegisterFpMmx0..7 in floating pointer mode. + * @sa WHV_X64_FP_REGISTER, RTFLOAT80U2 */ +typedef union +{ + HV_UINT128 AsUINT128; + struct + { + uint64_t Mantissa; + uint64_t BiasedExponent : 15; + uint64_t Sign : 1; +#ifndef IN_IDA_PRO + uint64_t Reserved : 48; +#endif + }; +} HV_X64_FP_REGISTER; +/** Pointer to a value of HvX64RegisterFpMmx0..7 in floating point mode. */ +typedef HV_X64_FP_REGISTER *PHV_X64_FP_REGISTER; + +/** Value union for HvX64RegisterFpMmx0..7. */ +typedef union +{ + HV_UINT128 AsUINT128; + HV_X64_FP_REGISTER Fp; + uint64_t Mmx; +} HV_X64_FP_MMX_REGISTER; +/** Pointer to a value of HvX64RegisterFpMmx0..7. */ +typedef HV_X64_FP_MMX_REGISTER *PHV_X64_FP_MMX_REGISTER; + +/** Value format for HvX64RegisterFpControlStatus. + * @sa WHV_X64_FP_CONTROL_STATUS_REGISTER */ +typedef union +{ + HV_UINT128 AsUINT128; + struct + { + uint16_t FpControl; + uint16_t FpStatus; + uint8_t FpTag; + uint8_t IgnNe : 1; + uint8_t Reserved : 7; + uint16_t LastFpOp; + union + { + uint64_t LastFpRip; + struct + { + uint32_t LastFpEip; + uint16_t LastFpCs; + }; + }; + }; +} HV_X64_FP_CONTROL_STATUS_REGISTER; +/** Pointer to a value of HvX64RegisterFpControlStatus. */ +typedef HV_X64_FP_CONTROL_STATUS_REGISTER *PHV_X64_FP_CONTROL_STATUS_REGISTER; + +/** Value format for HvX64RegisterXmmControlStatus. + * @sa WHV_X64_XMM_CONTROL_STATUS_REGISTER */ +typedef union +{ + HV_UINT128 AsUINT128; + struct + { + union + { + uint64_t LastFpRdp; + struct + { + uint32_t LastFpDp; + uint16_t LastFpDs; + }; + }; + uint32_t XmmStatusControl; + uint32_t XmmStatusControlMask; + }; +} HV_X64_XMM_CONTROL_STATUS_REGISTER; +/** Pointer to a value of HvX64RegisterXmmControlStatus. */ +typedef HV_X64_XMM_CONTROL_STATUS_REGISTER *PHV_X64_XMM_CONTROL_STATUS_REGISTER; + +/** Register value union. + * @sa WHV_REGISTER_VALUE */ +typedef union +{ + HV_UINT128 Reg128; + uint64_t Reg64; + uint32_t Reg32; + uint16_t Reg16; + uint8_t Reg8; + HV_EXPLICIT_SUSPEND_REGISTER ExplicitSuspend; + HV_INTERCEPT_SUSPEND_REGISTER InterceptSuspend; + HV_X64_INTERRUPT_STATE_REGISTER InterruptState; + HV_X64_PENDING_INTERRUPTION_REGISTER PendingInterruption; + HV_X64_DELIVERABILITY_NOTIFICATIONS_REGISTER DeliverabilityNotifications; + HV_X64_TABLE_REGISTER Table; + HV_X64_SEGMENT_REGISTER Segment; + HV_X64_FP_REGISTER Fp; + HV_X64_FP_CONTROL_STATUS_REGISTER FpControlStatus; + HV_X64_XMM_CONTROL_STATUS_REGISTER XmmControlStatus; +} HV_REGISTER_VALUE; +AssertCompileSize(HV_REGISTER_VALUE, 16); +/** Pointer to a Hyper-V register value union. */ +typedef HV_REGISTER_VALUE *PHV_REGISTER_VALUE; +/** Pointer to a const Hyper-V register value union. */ +typedef HV_REGISTER_VALUE const *PCHV_REGISTER_VALUE; + + +/** Input for HvCallGetVpRegisters. */ +typedef struct +{ + HV_PARTITION_ID PartitionId; + HV_VP_INDEX VpIndex; + /** Was this introduced after v2? Dunno what it it really is. */ + uint32_t fFlags; + /* The repeating part: */ + RT_FLEXIBLE_ARRAY_EXTENSION + HV_REGISTER_NAME Names[RT_FLEXIBLE_ARRAY]; +} HV_INPUT_GET_VP_REGISTERS; +AssertCompileMemberOffset(HV_INPUT_GET_VP_REGISTERS, Names, 16); +/** Pointer to input for HvCallGetVpRegisters. */ +typedef HV_INPUT_GET_VP_REGISTERS *PHV_INPUT_GET_VP_REGISTERS; +/* Output for HvCallGetVpRegisters is an array of HV_REGISTER_VALUE parallel to HV_INPUT_GET_VP_REGISTERS::Names. */ + + +/** Register and value pair for HvCallSetVpRegisters. */ +typedef struct +{ + HV_REGISTER_NAME Name; + uint32_t Pad0; + uint64_t Pad1; + HV_REGISTER_VALUE Value; +} HV_REGISTER_ASSOC; +AssertCompileSize(HV_REGISTER_ASSOC, 32); +AssertCompileMemberOffset(HV_REGISTER_ASSOC, Value, 16); +/** Pointer to a register and value pair for HvCallSetVpRegisters. */ +typedef HV_REGISTER_ASSOC *PHV_REGISTER_ASSOC; +/** Helper for clearing the alignment padding members. */ +#define HV_REGISTER_ASSOC_ZERO_PADDING(a_pRegAssoc) do { (a_pRegAssoc)->Pad0 = 0; (a_pRegAssoc)->Pad1 = 0; } while (0) +/** Helper for clearing the alignment padding members and the high 64-bit + * part of the value. */ +#define HV_REGISTER_ASSOC_ZERO_PADDING_AND_HI64(a_pRegAssoc) \ + do { (a_pRegAssoc)->Pad0 = 0; (a_pRegAssoc)->Pad1 = 0; (a_pRegAssoc)->Value.Reg128.High64 = 0; } while (0) + +/** Input for HvCallSetVpRegisters. */ +typedef struct +{ + HV_PARTITION_ID PartitionId; + HV_VP_INDEX VpIndex; + uint32_t RsvdZ; + /* The repeating part: */ + RT_FLEXIBLE_ARRAY_EXTENSION + HV_REGISTER_ASSOC Elements[RT_FLEXIBLE_ARRAY]; +} HV_INPUT_SET_VP_REGISTERS; +AssertCompileMemberOffset(HV_INPUT_SET_VP_REGISTERS, Elements, 16); +/** Pointer to input for HvCallSetVpRegisters. */ +typedef HV_INPUT_SET_VP_REGISTERS *PHV_INPUT_SET_VP_REGISTERS; + + + +/** + * Hyper-V SyncIC message types. + */ +typedef enum +{ + HvMessageTypeNone = 0x00000000, + + HvMessageTypeUnmappedGpa = 0x80000000, + HvMessageTypeGpaIntercept, + + HvMessageTimerExpired = 0x80000010, + + HvMessageTypeInvalidVpRegisterValue = 0x80000020, + HvMessageTypeUnrecoverableException, + HvMessageTypeUnsupportedFeature, + HvMessageTypeTlbPageSizeMismatch, /**< @since v5 */ + + /** @note Same as HvMessageTypeX64ApicEoi? Gone in 5.0. Missing from 7600 WDK + * headers even if it's in the 2.0 docs. */ + HvMessageTypeApicEoi = 0x80000030, + /** @note Same as HvMessageTypeX64LegacyFpError? Gone in 5.0, whereas 4.0b + * calls it HvMessageTypeX64LegacyFpError. Missing from 7600 WDK + * headers even if it's in the 2.0 docs. */ + HvMessageTypeFerrAsserted, + + HvMessageTypeEventLogBufferComplete = 0x80000040, + + HvMessageTypeX64IoPortIntercept = 0x80010000, + HvMessageTypeX64MsrIntercept, + HvMessageTypeX64CpuidIntercept, + HvMessageTypeX64ExceptionIntercept, + /** @note Appeared in 5.0 docs, but were here in 7600 WDK headers already. */ + HvMessageTypeX64ApicEoi, + /** @note Appeared in 5.0 docs, but were here in 7600 WDK headers already. */ + HvMessageTypeX64LegacyFpError, + /** @since v5 */ + HvMessageTypeX64RegisterIntercept, + /** @since WinHvPlatform? */ + HvMessageTypeX64Halt, + /** @since WinHvPlatform? */ + HvMessageTypeX64InterruptWindow + +} HV_MESSAGE_TYPE; +AssertCompileSize(HV_MESSAGE_TYPE, 4); +AssertCompile(HvMessageTypeX64RegisterIntercept == 0x80010006); +AssertCompile(HvMessageTypeX64Halt == 0x80010007); +AssertCompile(HvMessageTypeX64InterruptWindow == 0x80010008); +/** Pointer to a Hyper-V SyncIC message type. */ +typedef HV_MESSAGE_TYPE *PHV_MESSAGE_TYPE; + +/** Flag set for hypervisor messages, guest cannot send messages with this + * flag set. */ +#define HV_MESSAGE_TYPE_HYPERVISOR_MASK UINT32_C(0x80000000) + +/** Hyper-V SynIC message size (they are fixed sized). */ +#define HV_MESSAGE_SIZE 256 +/** Maximum Hyper-V SynIC message payload size in bytes. */ +#define HV_MESSAGE_MAX_PAYLOAD_BYTE_COUNT (HV_MESSAGE_SIZE - 16) +/** Maximum Hyper-V SynIC message payload size in QWORDs (uint64_t). */ +#define HV_MESSAGE_MAX_PAYLOAD_QWORD_COUNT (HV_MESSAGE_MAX_PAYLOAD_BYTE_COUNT / 8) + +/** SynIC message flags. */ +typedef union +{ + uint8_t AsUINT8; + struct + { + /** Messages are pending in the queue. */ + uint8_t MessagePending : 1; + uint8_t Reserved : 7; + }; +} HV_MESSAGE_FLAGS; +AssertCompileSize(HV_MESSAGE_FLAGS, 1); + +/** SynIC message header. */ +typedef struct +{ + HV_MESSAGE_TYPE MessageType; + /** The 2.0-5.0b docs all have this incorrectly switched with 'Reserved', WDK 7600 got it right. */ + uint8_t PayloadSize; + HV_MESSAGE_FLAGS MessageFlags; + uint16_t Reserved; + union + { + uint64_t OriginationId; + HV_PARTITION_ID Sender; + HV_PORT_ID Port; + }; +} HV_MESSAGE_HEADER; +AssertCompileSize(HV_MESSAGE_HEADER, 16); +/** Pointer to a Hyper-V message header. */ +typedef HV_MESSAGE_HEADER *PHV_MESSAGE_HEADER; +/** Pointer to a const Hyper-V message header. */ +typedef HV_MESSAGE_HEADER const *PCHV_MESSAGE_HEADER; + + + +/** @name Intercept access type. + * @{ */ +typedef uint8_t HV_INTERCEPT_ACCESS_TYPE; +#define HV_INTERCEPT_ACCESS_READ 0 +#define HV_INTERCEPT_ACCESS_WRITE 1 +#define HV_INTERCEPT_ACCESS_EXECUTE 2 +/** @} */ + +/** @name Intercept access type mask. + * @{ */ +typedef uint32_t HV_INTERCEPT_ACCESS_TYPE_MASK; +#define HV_INTERCEPT_ACCESS_MASK_NONE 0 +#define HV_INTERCEPT_ACCESS_MASK_READ 1 +#define HV_INTERCEPT_ACCESS_MASK_WRITE 2 +#define HV_INTERCEPT_ACCESS_MASK_EXECUTE 4 +/** @} */ + +/** X64 intercept execution state. + * @sa WHV_X64_VP_EXECUTION_STATE */ +typedef union +{ + uint16_t AsUINT16; + struct + { + uint16_t Cpl : 2; + uint16_t Cr0Pe : 1; + uint16_t Cr0Am : 1; + uint16_t EferLma : 1; + uint16_t DebugActive : 1; + uint16_t InterruptionPending : 1; + uint16_t Reserved0 : 5; + uint16_t InterruptShadow : 1; + uint16_t Reserved1 : 3; + }; +} HV_X64_VP_EXECUTION_STATE; +AssertCompileSize(HV_X64_VP_EXECUTION_STATE, 2); +/** Pointer to X86 intercept execution state. */ +typedef HV_X64_VP_EXECUTION_STATE *PHV_X64_VP_EXECUTION_STATE; +/** Pointer to const X86 intercept execution state. */ +typedef HV_X64_VP_EXECUTION_STATE const *PCHV_X64_VP_EXECUTION_STATE; + +/** X64 intercept message header. */ +typedef struct +{ + HV_VP_INDEX VpIndex; /**< 0x00 */ + uint8_t InstructionLength : 4; /**< 0x04[3:0]: Zero if not available, instruction fetch exit, ... */ + uint8_t Cr8 : 4; /**< 0x04[7:4]: Not sure since when, but after v2. */ + HV_INTERCEPT_ACCESS_TYPE InterceptAccessType; /**< 0x05 */ + HV_X64_VP_EXECUTION_STATE ExecutionState; /**< 0x06 */ + HV_X64_SEGMENT_REGISTER CsSegment; /**< 0x08 */ + uint64_t Rip; /**< 0x18 */ + uint64_t Rflags; /**< 0x20 */ +} HV_X64_INTERCEPT_MESSAGE_HEADER; +AssertCompileSize(HV_X64_INTERCEPT_MESSAGE_HEADER, 40); +/** Pointer to a x86 intercept message header. */ +typedef HV_X64_INTERCEPT_MESSAGE_HEADER *PHV_X64_INTERCEPT_MESSAGE_HEADER; + + +/** X64 memory access flags (HvMessageTypeGpaIntercept, HvMessageTypeUnmappedGpa). + * @sa WHV_MEMORY_ACCESS_INFO */ +typedef union +{ + uint8_t AsUINT8; + struct + { + uint8_t GvaValid : 1; + uint8_t Reserved : 7; + }; +} HV_X64_MEMORY_ACCESS_INFO; +AssertCompileSize(HV_X64_MEMORY_ACCESS_INFO, 1); + +/** The payload format for HvMessageTypeGpaIntercept and HvMessageTypeUnmappedGpa. + * @sa WHV_MEMORY_ACCESS_CONTEXT + * @note max message size. */ +typedef struct +{ + HV_X64_INTERCEPT_MESSAGE_HEADER Header; /**< 0x00 */ + HV_CACHE_TYPE CacheType; /**< 0x28 */ + uint8_t InstructionByteCount; /**< 0x2c */ + HV_X64_MEMORY_ACCESS_INFO MemoryAccessInfo; /**< 0x2d */ + uint16_t Reserved1; /**< 0x2e */ + uint64_t GuestVirtualAddress; /**< 0x30 */ + uint64_t GuestPhysicalAddress; /**< 0x38 */ + uint8_t InstructionBytes[16]; /**< 0x40 */ + /* We don't the following (v5 / WinHvPlatform): */ + HV_X64_SEGMENT_REGISTER DsSegment; /**< 0x50 */ + HV_X64_SEGMENT_REGISTER SsSegment; /**< 0x60 */ + uint64_t Rax; /**< 0x70 */ + uint64_t Rcx; /**< 0x78 */ + uint64_t Rdx; /**< 0x80 */ + uint64_t Rbx; /**< 0x88 */ + uint64_t Rsp; /**< 0x90 */ + uint64_t Rbp; /**< 0x98 */ + uint64_t Rsi; /**< 0xa0 */ + uint64_t Rdi; /**< 0xa8 */ + uint64_t R8; /**< 0xb0 */ + uint64_t R9; /**< 0xb8 */ + uint64_t R10; /**< 0xc0 */ + uint64_t R11; /**< 0xc8 */ + uint64_t R12; /**< 0xd0 */ + uint64_t R13; /**< 0xd8 */ + uint64_t R14; /**< 0xe0 */ + uint64_t R15; /**< 0xe8 */ +} HV_X64_MEMORY_INTERCEPT_MESSAGE; +AssertCompileSize(HV_X64_MEMORY_INTERCEPT_MESSAGE, 0xf0); +AssertCompileMemberOffset(HV_X64_MEMORY_INTERCEPT_MESSAGE, DsSegment, 0x50); +/** Pointer to a HvMessageTypeGpaIntercept or HvMessageTypeUnmappedGpa payload. */ +typedef HV_X64_MEMORY_INTERCEPT_MESSAGE *PHV_X64_MEMORY_INTERCEPT_MESSAGE; +/** Pointer to a const HvMessageTypeGpaIntercept or HvMessageTypeUnmappedGpa payload. */ +typedef HV_X64_MEMORY_INTERCEPT_MESSAGE const *PCHV_X64_MEMORY_INTERCEPT_MESSAGE; + + +/** The payload format for HvMessageTypeX64MsrIntercept. */ +typedef struct _HV_X64_MSR_INTERCEPT_MESSAGE +{ + HV_X64_INTERCEPT_MESSAGE_HEADER Header; /**< 0x00 */ + uint32_t MsrNumber; /**< 0x28 (ecx) */ + uint32_t Reserved; /**< 0x2c */ + uint64_t Rdx; /**< 0x30 */ + uint64_t Rax; /**< 0x38 */ +} HV_X64_MSR_INTERCEPT_MESSAGE; +AssertCompileSize(HV_X64_MSR_INTERCEPT_MESSAGE, 0x40); +/** Pointer to a HvMessageTypeX64MsrIntercept payload. */ +typedef HV_X64_MSR_INTERCEPT_MESSAGE *PHV_X64_MSR_INTERCEPT_MESSAGE; +/** Pointer to a const HvMessageTypeX64MsrIntercept payload. */ +typedef HV_X64_MSR_INTERCEPT_MESSAGE const *PCHV_X64_MSR_INTERCEPT_MESSAGE; + +/** Full MSR message. */ +typedef struct +{ + HV_MESSAGE_HEADER MsgHdr; + HV_X64_MSR_INTERCEPT_MESSAGE Payload; +} HV_X64_MSR_INTERCEPT_MESSAGE_FULL; + + +/** X64 I/O port access information (HvMessageTypeX64IoPortIntercept). */ +typedef union HV_X64_IO_PORT_ACCESS_INFO +{ + uint8_t AsUINT8; + struct + { + uint8_t AccessSize : 3; + uint8_t StringOp : 1; + uint8_t RepPrefix : 1; + uint8_t Reserved : 3; + }; +} HV_X64_IO_PORT_ACCESS_INFO; +AssertCompileSize(HV_X64_IO_PORT_ACCESS_INFO, 1); + +/** The payload format for HvMessageTypeX64IoPortIntercept. */ +typedef struct _HV_X64_IO_PORT_INTERCEPT_MESSAGE +{ + HV_X64_INTERCEPT_MESSAGE_HEADER Header; /**< 0x00 */ + uint16_t PortNumber; /**< 0x28 */ + HV_X64_IO_PORT_ACCESS_INFO AccessInfo; /**< 0x2a */ + uint8_t InstructionByteCount; /**< 0x2b */ + uint32_t Reserved; /**< 0x2c */ + uint64_t Rax; /**< 0x30 */ + uint8_t InstructionBytes[16]; /**< 0x38 */ + HV_X64_SEGMENT_REGISTER DsSegment; /**< 0x48 */ + HV_X64_SEGMENT_REGISTER EsSegment; /**< 0x58 */ + uint64_t Rcx; /**< 0x68 */ + uint64_t Rsi; /**< 0x70 */ + uint64_t Rdi; /**< 0x78 */ +} HV_X64_IO_PORT_INTERCEPT_MESSAGE; +AssertCompileSize(HV_X64_IO_PORT_INTERCEPT_MESSAGE, 128); +/** Pointer to a HvMessageTypeX64IoPortIntercept payload. */ +typedef HV_X64_IO_PORT_INTERCEPT_MESSAGE *PHV_X64_IO_PORT_INTERCEPT_MESSAGE; +/** Pointer to a const HvMessageTypeX64IoPortIntercept payload. */ +typedef HV_X64_IO_PORT_INTERCEPT_MESSAGE const *PCHV_X64_IO_PORT_INTERCEPT_MESSAGE; + +/** Full I/O port message. */ +typedef struct +{ + HV_MESSAGE_HEADER MsgHdr; + HV_X64_IO_PORT_INTERCEPT_MESSAGE Payload; +} HV_X64_IO_PORT_INTERCEPT_MESSAGE_FULL; + + +/** + * The payload format for HvMessageTypeX64CpuidIntercept, + * + * @note This message does not include HV_X64_INTERCEPT_MESSAGE_HEADER! + */ +typedef struct +{ + HV_X64_INTERCEPT_MESSAGE_HEADER Header; /**< 0x00: The usual intercept header. */ + uint64_t Rax; /**< 0x28: Input RAX. */ + uint64_t Rcx; /**< 0x30: Input RCX. */ + uint64_t Rdx; /**< 0x38: Input RDX. */ + uint64_t Rbx; /**< 0x40: Input RBX. */ + uint64_t DefaultResultRax; /**< 0x48: Default result RAX. */ + uint64_t DefaultResultRcx; /**< 0x50: Default result RCX. */ + uint64_t DefaultResultRdx; /**< 0x58: Default result RDX. */ + uint64_t DefaultResultRbx; /**< 0x60: Default result RBX. */ +} HV_X64_CPUID_INTERCEPT_MESSAGE; +AssertCompileSize(HV_X64_CPUID_INTERCEPT_MESSAGE, 0x68); +/** Pointer to a HvMessageTypeX64CpuidIntercept payload. */ +typedef HV_X64_CPUID_INTERCEPT_MESSAGE *PHV_X64_CPUID_INTERCEPT_MESSAGE; +/** Pointer to a const HvMessageTypeX64CpuidIntercept payload. */ +typedef HV_X64_CPUID_INTERCEPT_MESSAGE const *PCHV_X64_CPUID_INTERCEPT_MESSAGE; + +/** Full HvMessageTypeX64CpuidIntercept message. */ +typedef struct +{ + HV_MESSAGE_HEADER MsgHdr; + HV_X64_CPUID_INTERCEPT_MESSAGE Payload; +} HV_X64_CPUID_INTERCEPT_MESSAGE_FULL; + + +/** X64 exception information (HvMessageTypeX64ExceptionIntercept). + * @sa WHV_VP_EXCEPTION_INFO */ +typedef union +{ + uint8_t AsUINT8; + struct + { + uint8_t ErrorCodeValid : 1; + /** @todo WHV_VP_EXCEPTION_INFO::SoftwareException */ + uint8_t Reserved : 7; + }; +} HV_X64_EXCEPTION_INFO; +AssertCompileSize(HV_X64_EXCEPTION_INFO, 1); + +/** The payload format for HvMessageTypeX64ExceptionIntercept. + * @sa WHV_VP_EXCEPTION_CONTEXT + * @note max message size. */ +typedef struct +{ + HV_X64_INTERCEPT_MESSAGE_HEADER Header; /**< 0x00 */ + uint16_t ExceptionVector; /**< 0x28 */ + HV_X64_EXCEPTION_INFO ExceptionInfo; /**< 0x2a */ + uint8_t InstructionByteCount; /**< 0x2b */ + uint32_t ErrorCode; /**< 0x2c */ + uint64_t ExceptionParameter; /**< 0x30 */ + uint64_t Reserved; /**< 0x38 */ + uint8_t InstructionBytes[16]; /**< 0x40 */ + HV_X64_SEGMENT_REGISTER DsSegment; /**< 0x50 */ + HV_X64_SEGMENT_REGISTER SsSegment; /**< 0x60 */ + uint64_t Rax; /**< 0x70 */ + uint64_t Rcx; /**< 0x78 */ + uint64_t Rdx; /**< 0x80 */ + uint64_t Rbx; /**< 0x88 */ + uint64_t Rsp; /**< 0x90 */ + uint64_t Rbp; /**< 0x98 */ + uint64_t Rsi; /**< 0xa0 */ + uint64_t Rdi; /**< 0xa8 */ + uint64_t R8; /**< 0xb0 */ + uint64_t R9; /**< 0xb8 */ + uint64_t R10; /**< 0xc0 */ + uint64_t R11; /**< 0xc8 */ + uint64_t R12; /**< 0xd0 */ + uint64_t R13; /**< 0xd8 */ + uint64_t R14; /**< 0xe0 */ + uint64_t R15; /**< 0xe8 */ +} HV_X64_EXCEPTION_INTERCEPT_MESSAGE; +AssertCompileSize(HV_X64_EXCEPTION_INTERCEPT_MESSAGE, 0xf0); +/** Pointer to a HvMessageTypeX64ExceptionIntercept payload. */ +typedef HV_X64_EXCEPTION_INTERCEPT_MESSAGE *PHV_X64_EXCEPTION_INTERCEPT_MESSAGE; +/** Pointer to a ocnst HvMessageTypeX64ExceptionIntercept payload. */ +typedef HV_X64_EXCEPTION_INTERCEPT_MESSAGE const *PCHV_X64_EXCEPTION_INTERCEPT_MESSAGE; + + +/** + * The payload format for HvMessageTypeX64Halt, + * + * @note This message does not include HV_X64_INTERCEPT_MESSAGE_HEADER! + */ +typedef struct +{ + /** Seems to be a zero 64-bit field here. */ + uint64_t u64Reserved; +} HV_X64_HALT_MESSAGE; +/** Pointer to a HvMessageTypeX64Halt payload. */ +typedef HV_X64_HALT_MESSAGE *PHV_X64_HALT_MESSAGE; +/** Pointer to a const HvMessageTypeX64Halt payload. */ +typedef HV_X64_HALT_MESSAGE const *PCHV_X64_HALT_MESSAGE; + +/** Full HvMessageTypeX64Halt message. */ +typedef struct +{ + HV_MESSAGE_HEADER MsgHdr; + HV_X64_HALT_MESSAGE Payload; +} HV_X64_HALT_MESSAGE_FULL; + + +/** + * The payload format for HvMessageTypeX64InterruptWindow, + * + * @note This message does not include HV_X64_INTERCEPT_MESSAGE_HEADER! + */ +typedef struct +{ + /** 0x00: The usual intercept header. */ + HV_X64_INTERCEPT_MESSAGE_HEADER Header; + /** 0x28: What's pending. */ + HV_X64_PENDING_INTERRUPTION_TYPE Type; + /** 0x2c: Explicit structure alignment padding. */ + uint32_t u32ExplicitPadding; +} HV_X64_INTERRUPT_WINDOW_MESSAGE; +AssertCompileSize(HV_X64_INTERRUPT_WINDOW_MESSAGE, 0x30); +/** Pointer to a HvMessageTypeX64InterruptWindow payload. */ +typedef HV_X64_INTERRUPT_WINDOW_MESSAGE *PHV_X64_INTERRUPT_WINDOW_MESSAGE; +/** Pointer to a const HvMessageTypeX64InterruptWindow payload. */ +typedef HV_X64_INTERRUPT_WINDOW_MESSAGE const *PCHV_X64_INTERRUPT_WINDOW_MESSAGE; + +/** Full HvMessageTypeX64InterruptWindow message. */ +typedef struct +{ + /** Payload size is 0x30. */ + HV_MESSAGE_HEADER MsgHdr; + HV_X64_INTERRUPT_WINDOW_MESSAGE Payload; +} HV_X64_INTERRUPT_WINDOW_MESSAGE_FULL; + + + +/** Hyper-V SynIC message. */ +typedef struct +{ + HV_MESSAGE_HEADER Header; + /** 0x10 */ + union + { + uint64_t Payload[HV_MESSAGE_MAX_PAYLOAD_QWORD_COUNT]; + + /** Common header for X64 intercept messages. + * The HvMessageTypeUnrecoverableException message only has this. */ + HV_X64_INTERCEPT_MESSAGE_HEADER X64InterceptHeader; + /** HvMessageTypeGpaIntercept, HvMessageTypeUnmappedGpa. */ + HV_X64_MEMORY_INTERCEPT_MESSAGE X64MemoryIntercept; + /** HvMessageTypeX64IoPortIntercept */ + HV_X64_IO_PORT_INTERCEPT_MESSAGE X64IoPortIntercept; + /** HvMessageTypeX64MsrIntercept */ + HV_X64_MSR_INTERCEPT_MESSAGE X64MsrIntercept; + /** HvMessageTypeX64CpuidIntercept */ + HV_X64_CPUID_INTERCEPT_MESSAGE X64CpuIdIntercept; + /** HvMessageTypeX64ExceptionIntercept */ + HV_X64_EXCEPTION_INTERCEPT_MESSAGE X64ExceptionIntercept; + /** HvMessageTypeX64Halt. + * @note No intercept header? */ + HV_X64_HALT_MESSAGE X64Halt; + /** HvMessageTypeX64InterruptWindow. */ + HV_X64_INTERRUPT_WINDOW_MESSAGE X64InterruptWindow; + }; +} HV_MESSAGE; +AssertCompileSize(HV_MESSAGE, HV_MESSAGE_SIZE); +/** Pointer to a Hyper-V SynIC message. */ +typedef HV_MESSAGE *PHV_MESSAGE; +/** Pointer to const a Hyper-V SynIC message. */ +typedef HV_MESSAGE const *PCHV_MESSAGE; + +#endif /* !IPRT_INCLUDED_nt_hyperv_h */ + diff --git a/include/iprt/nt/miniport.h b/include/iprt/nt/miniport.h new file mode 100644 index 00000000..0525e306 --- /dev/null +++ b/include/iprt/nt/miniport.h @@ -0,0 +1,61 @@ +/** @file + * Safe way to include miniport.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_miniport_h +#define IPRT_INCLUDED_nt_miniport_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* basetsd.h(114) : warning C4668: '__midl' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +#endif + +RT_C_DECLS_BEGIN +#include <miniport.h> +RT_C_DECLS_END + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_nt_miniport_h */ + diff --git a/include/iprt/nt/ndis.h b/include/iprt/nt/ndis.h new file mode 100644 index 00000000..e8263edb --- /dev/null +++ b/include/iprt/nt/ndis.h @@ -0,0 +1,61 @@ +/** @file + * Safe way to include ndis.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_ndis_h +#define IPRT_INCLUDED_nt_ndis_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* warning C4668: 'NDIS_WRAPPER' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +#endif + +RT_C_DECLS_BEGIN +#include <ndis.h> +RT_C_DECLS_END + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_nt_ndis_h */ + diff --git a/include/iprt/nt/nt-and-windows.h b/include/iprt/nt/nt-and-windows.h new file mode 100644 index 00000000..e5bbbaff --- /dev/null +++ b/include/iprt/nt/nt-and-windows.h @@ -0,0 +1,68 @@ +/* $Id: nt-and-windows.h $ */ +/** @file + * IPRT - Header for code using both NT native and Windows APIs. + */ + +/* + * Copyright (C) 2013-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_nt_and_windows_h +#define IPRT_INCLUDED_nt_nt_and_windows_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#define _PEB IncompleteWindows__PEB +#define PEB IncompleteWindows_PEB +#define PPEB IncompleteWindows_PPEB + +#define _TEB IncompleteWindows__TEB +#define TEB IncompleteWindows_TEB +#define PTEB IncompleteWindows_PTEB + +#define IPRT_NT_USE_WINTERNL +#define IPRT_NT_HAVE_CURRENT_TEB_MACRO +#define WIN32_NO_STATUS +#include <iprt/win/windows.h> +#undef WIN32_NO_STATUS + +#undef _PEB +#undef PEB +#undef PPEB + +#undef _TEB +#undef TEB +#undef PTEB + +#include <iprt/nt/nt.h> + +#endif /* !IPRT_INCLUDED_nt_nt_and_windows_h */ + diff --git a/include/iprt/nt/nt-structures.h b/include/iprt/nt/nt-structures.h new file mode 100644 index 00000000..fbf83f0a --- /dev/null +++ b/include/iprt/nt/nt-structures.h @@ -0,0 +1,146 @@ +/* $Id: nt-structures.h $ */ +/** @file + * IPRT - Header for NT structures. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_nt_structures_h +#define IPRT_INCLUDED_nt_nt_structures_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include <iprt/types.h> + + +/** @name NT Kernel Structures + * @{ */ +typedef struct KTRAP_FRAME_AMD64 +{ + uint64_t P1Home; /**< 0x00 */ + uint64_t P2Home; /**< 0x08 */ + uint64_t P3Home; /**< 0x10 */ + uint64_t P4Home; /**< 0x18 */ + uint64_t P5; /**< 0x20 */ + uint8_t PreviousMode; /**< 0x28: KPROCESSOR_MODE / MODE - unused? */ + uint8_t PreviousIrql; /**< 0x29: KIRQL - Interrupts? */ + uint8_t FaultIndicator; /**< 0x2a: Holds (ErrCd >> 1) & 9) for \#PF. */ + uint8_t ExceptionActive; /**< 0x2b: 0 if interrupt, 1 if exception, 2 if service call, */ + uint32_t MxCsr; /**< 0x2c */ + /** @name Volatile general register state. Only saved on interrupts and exceptions. + * @{ */ + uint64_t Rax; /**< 0x30 */ + uint64_t Rcx; /**< 0x38 */ + uint64_t Rdx; /**< 0x40 */ + uint64_t R8; /**< 0x48 */ + uint64_t R9; /**< 0x50 */ + uint64_t R10; /**< 0x58 */ + uint64_t R11; /**< 0x60 */ + /** @} */ + uint64_t GsBaseOrSwap; /**< 0x68: GsBase if previous mode is kernel, GsSwap if pervious mode was user. */ + /** @name Volatile SSE state. Only saved on interrupts and exceptions. + * @{ */ + RTUINT128U Xmm0; /**< 0x70 */ + RTUINT128U Xmm1; /**< 0x80: RBP points here. */ + RTUINT128U Xmm2; /**< 0x90 */ + RTUINT128U Xmm3; /**< 0xa0 */ + RTUINT128U Xmm4; /**< 0xb0 */ + RTUINT128U Xmm5; /**< 0xc0 */ + /** @} */ + uint64_t FaultAddrOrCtxRecOrTS; /**< 0xd0: Used to save CR2 in \#PF and NMI handlers. */ + /** @name Usermode debug state. + * @{ */ + uint64_t Dr0; /**< 0xd8: Only if DR7 indicates active. */ + uint64_t Dr1; /**< 0xe0: Only if DR7 indicates active. */ + uint64_t Dr2; /**< 0xe8: Only if DR7 indicates active. */ + uint64_t Dr3; /**< 0xf0: Only if DR7 indicates active. */ + uint64_t Dr6; /**< 0xf8: Only if DR7 indicates active. */ + uint64_t Dr7; /**< 0x100: Considered active any of these bits are set: + X86_DR7_LE_ALL | X86_DR7_LE | X86_DR7_GE. */ + union + { + struct + { + uint64_t LastBranchControl; /**< 0x108 */ + uint32_t LastBranchMSR; /**< 0x110 */ + } amd; + struct + { + uint64_t DebugControl; /**< 0x108 */ + uint64_t LastBranchToRip; /**< 0x110 */ + uint64_t LastBranchFromRip; /**< 0x118 */ + uint64_t LastExceptionToRip; /**< 0x120 */ + uint64_t LastExceptionFromRip; /**< 0x128 */ + } intel; + } u; + /** @} */ + /** @name Segment registers. Not sure when these would actually be used. + * @{ */ + uint16_t SegDs; /**< 0x130 */ + uint16_t SegEs; /**< 0x132 */ + uint16_t SegFs; /**< 0x134 */ + uint16_t SegGs; /**< 0x136 */ + /** @} */ + uint64_t TrapFrame; /**< 0x138 */ + /** @name Some non-volatile registers only saved in service calls. + * @{ */ + uint64_t Rbx; /**< 0x140 */ + uint64_t Rdi; /**< 0x148 */ + uint64_t Rsi; /**< 0x150 */ + /** @} */ + uint64_t Rbp; /**< 0x158: Typically restored by: MOV RBP, [RBP + 0xd8] */ + uint64_t ErrCdOrXcptFrameOrS; /**< 0x160 */ + uint64_t Rip; /**< 0x168 - IRET RIP */ + uint16_t SegCs; /**< 0x170 - IRET CS */ + uint8_t Fill0; /**< 0x172 */ + uint8_t Logging; /**< 0x173 */ + uint16_t Fill1[2]; /**< 0x174 */ + uint32_t EFlags; /**< 0x178 - IRET EFLAGS - Uninitialized for stack switching/growth code path. */ + uint32_t Fill2; /**< 0x17c */ + uint64_t Rsp; /**< 0x180 - IRET RSP */ + uint16_t SegSs; /**< 0x188 - IRET SS */ + uint16_t Fill3; /**< 0x18a */ + uint32_t Fill4; /**< 0x18c */ +} KTRAP_FRAME_AMD64; +AssertCompileSize(KTRAP_FRAME_AMD64, 0x190); +/** Pointer to an AMD64 NT trap frame. */ +typedef KTRAP_FRAME_AMD64 *PKTRAP_FRAME_AMD64; +/** Pointer to a const AMD64 NT trap frame. */ +typedef KTRAP_FRAME_AMD64 const *PCKTRAP_FRAME_AMD64; + +/** @} */ + + +#endif /* !IPRT_INCLUDED_nt_nt_structures_h */ + diff --git a/include/iprt/nt/nt.h b/include/iprt/nt/nt.h new file mode 100644 index 00000000..c23cd9f0 --- /dev/null +++ b/include/iprt/nt/nt.h @@ -0,0 +1,3824 @@ +/* $Id: nt.h $ */ +/** @file + * IPRT - Header for code using the Native NT API. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_nt_h +#define IPRT_INCLUDED_nt_nt_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/** @def IPRT_NT_MAP_TO_ZW + * Map Nt calls to Zw calls. In ring-0 the Zw calls let you pass kernel memory + * to the APIs (takes care of the previous context checks). + */ +#ifdef DOXYGEN_RUNNING +# define IPRT_NT_MAP_TO_ZW +#endif + +#ifdef IPRT_NT_MAP_TO_ZW +# define NtQueryDirectoryFile ZwQueryDirectoryFile +# define NtQueryInformationFile ZwQueryInformationFile +# define NtQueryInformationProcess ZwQueryInformationProcess +# define NtQueryInformationThread ZwQueryInformationThread +# define NtQueryFullAttributesFile ZwQueryFullAttributesFile +# define NtQuerySystemInformation ZwQuerySystemInformation +# define NtQuerySecurityObject ZwQuerySecurityObject +# define NtSetInformationFile ZwSetInformationFile +# define NtClose ZwClose +# define NtCreateFile ZwCreateFile +# define NtReadFile ZwReadFile +# define NtWriteFile ZwWriteFile +# define NtFlushBuffersFile ZwFlushBuffersFile +/** @todo this is very incomplete! */ +#endif + +#include <ntstatus.h> + +/* + * Hacks common to both base header sets. + */ +#define RtlFreeUnicodeString WrongLinkage_RtlFreeUnicodeString +#define NtQueryObject Incomplete_NtQueryObject +#define ZwQueryObject Incomplete_ZwQueryObject +#define NtSetInformationObject Incomplete_NtSetInformationObject +#define _OBJECT_INFORMATION_CLASS Incomplete_OBJECT_INFORMATION_CLASS +#define OBJECT_INFORMATION_CLASS Incomplete_OBJECT_INFORMATION_CLASS +#define ObjectBasicInformation Incomplete_ObjectBasicInformation +#define ObjectTypeInformation Incomplete_ObjectTypeInformation +#define _PEB Incomplete__PEB +#define PEB Incomplete_PEB +#define PPEB Incomplete_PPEB +#define _TEB Incomplete__TEB +#define TEB Incomplete_TEB +#define PTEB Incomplete_PTEB +#define _PEB_LDR_DATA Incomplete__PEB_LDR_DATA +#define PEB_LDR_DATA Incomplete_PEB_LDR_DATA +#define PPEB_LDR_DATA Incomplete_PPEB_LDR_DATA +#define _KUSER_SHARED_DATA Incomplete__KUSER_SHARED_DATA +#define KUSER_SHARED_DATA Incomplete_KUSER_SHARED_DATA +#define PKUSER_SHARED_DATA Incomplete_PKUSER_SHARED_DATA + + + +#ifdef IPRT_NT_USE_WINTERNL +/* + * Use Winternl.h. + */ +# define _FILE_INFORMATION_CLASS IncompleteWinternl_FILE_INFORMATION_CLASS +# define FILE_INFORMATION_CLASS IncompleteWinternl_FILE_INFORMATION_CLASS +# define FileDirectoryInformation IncompleteWinternl_FileDirectoryInformation + +# define NtQueryInformationProcess IncompleteWinternl_NtQueryInformationProcess +# define NtSetInformationProcess IncompleteWinternl_NtSetInformationProcess +# define PROCESSINFOCLASS IncompleteWinternl_PROCESSINFOCLASS +# define _PROCESSINFOCLASS IncompleteWinternl_PROCESSINFOCLASS +# define PROCESS_BASIC_INFORMATION IncompleteWinternl_PROCESS_BASIC_INFORMATION +# define PPROCESS_BASIC_INFORMATION IncompleteWinternl_PPROCESS_BASIC_INFORMATION +# define _PROCESS_BASIC_INFORMATION IncompleteWinternl_PROCESS_BASIC_INFORMATION +# define ProcessBasicInformation IncompleteWinternl_ProcessBasicInformation +# define ProcessDebugPort IncompleteWinternl_ProcessDebugPort +# define ProcessWow64Information IncompleteWinternl_ProcessWow64Information +# define ProcessImageFileName IncompleteWinternl_ProcessImageFileName +# define ProcessBreakOnTermination IncompleteWinternl_ProcessBreakOnTermination + +# define RTL_USER_PROCESS_PARAMETERS IncompleteWinternl_RTL_USER_PROCESS_PARAMETERS +# define PRTL_USER_PROCESS_PARAMETERS IncompleteWinternl_PRTL_USER_PROCESS_PARAMETERS +# define _RTL_USER_PROCESS_PARAMETERS IncompleteWinternl__RTL_USER_PROCESS_PARAMETERS + +# define NtQueryInformationThread IncompleteWinternl_NtQueryInformationThread +# define NtSetInformationThread IncompleteWinternl_NtSetInformationThread +# define THREADINFOCLASS IncompleteWinternl_THREADINFOCLASS +# define _THREADINFOCLASS IncompleteWinternl_THREADINFOCLASS +# define ThreadIsIoPending IncompleteWinternl_ThreadIsIoPending + +# define NtQuerySystemInformation IncompleteWinternl_NtQuerySystemInformation +# define NtSetSystemInformation IncompleteWinternl_NtSetSystemInformation +# define NtQueryTimerResolution AddedRecentlyUseOwnPrototype_NtQueryTimerResolution +# define SYSTEM_INFORMATION_CLASS IncompleteWinternl_SYSTEM_INFORMATION_CLASS +# define _SYSTEM_INFORMATION_CLASS IncompleteWinternl_SYSTEM_INFORMATION_CLASS +# define SystemBasicInformation IncompleteWinternl_SystemBasicInformation +# define SystemPerformanceInformation IncompleteWinternl_SystemPerformanceInformation +# define SystemTimeOfDayInformation IncompleteWinternl_SystemTimeOfDayInformation +# define SystemProcessInformation IncompleteWinternl_SystemProcessInformation +# define SystemProcessorPerformanceInformation IncompleteWinternl_SystemProcessorPerformanceInformation +# define SystemInterruptInformation IncompleteWinternl_SystemInterruptInformation +# define SystemExceptionInformation IncompleteWinternl_SystemExceptionInformation +# define SystemRegistryQuotaInformation IncompleteWinternl_SystemRegistryQuotaInformation +# define SystemLookasideInformation IncompleteWinternl_SystemLookasideInformation +# define SystemPolicyInformation IncompleteWinternl_SystemPolicyInformation + + +# pragma warning(push) +# pragma warning(disable: 4668) +# define WIN32_NO_STATUS +# include <windef.h> +# include <winnt.h> +# include <winternl.h> +# undef WIN32_NO_STATUS +# include <ntstatus.h> +# pragma warning(pop) + +# ifndef OBJ_DONT_REPARSE +# define RTNT_NEED_CLIENT_ID +# endif + +# undef _FILE_INFORMATION_CLASS +# undef FILE_INFORMATION_CLASS +# undef FileDirectoryInformation + +# undef NtQueryInformationProcess +# undef NtSetInformationProcess +# undef PROCESSINFOCLASS +# undef _PROCESSINFOCLASS +# undef PROCESS_BASIC_INFORMATION +# undef PPROCESS_BASIC_INFORMATION +# undef _PROCESS_BASIC_INFORMATION +# undef ProcessBasicInformation +# undef ProcessDebugPort +# undef ProcessWow64Information +# undef ProcessImageFileName +# undef ProcessBreakOnTermination + +# undef RTL_USER_PROCESS_PARAMETERS +# undef PRTL_USER_PROCESS_PARAMETERS +# undef _RTL_USER_PROCESS_PARAMETERS + +# undef NtQueryInformationThread +# undef NtSetInformationThread +# undef THREADINFOCLASS +# undef _THREADINFOCLASS +# undef ThreadIsIoPending + +# undef NtQuerySystemInformation +# undef NtSetSystemInformation +# undef NtQueryTimerResolution +# undef SYSTEM_INFORMATION_CLASS +# undef _SYSTEM_INFORMATION_CLASS +# undef SystemBasicInformation +# undef SystemPerformanceInformation +# undef SystemTimeOfDayInformation +# undef SystemProcessInformation +# undef SystemProcessorPerformanceInformation +# undef SystemInterruptInformation +# undef SystemExceptionInformation +# undef SystemRegistryQuotaInformation +# undef SystemLookasideInformation +# undef SystemPolicyInformation + +# define RTNT_NEED_NT_GET_PRODUCT_TYPE + +#else +/* + * Use ntifs.h and wdm.h. + */ +# if _MSC_VER >= 1200 /* Fix/workaround for KeInitializeSpinLock visibility issue on AMD64. */ +# define FORCEINLINE static __forceinline +# else +# define FORCEINLINE static __inline +# endif + +# define _FSINFOCLASS OutdatedWdm_FSINFOCLASS +# define FS_INFORMATION_CLASS OutdatedWdm_FS_INFORMATION_CLASS +# define PFS_INFORMATION_CLASS OutdatedWdm_PFS_INFORMATION_CLASS +# define FileFsVolumeInformation OutdatedWdm_FileFsVolumeInformation +# define FileFsLabelInformation OutdatedWdm_FileFsLabelInformation +# define FileFsSizeInformation OutdatedWdm_FileFsSizeInformation +# define FileFsDeviceInformation OutdatedWdm_FileFsDeviceInformation +# define FileFsAttributeInformation OutdatedWdm_FileFsAttributeInformation +# define FileFsControlInformation OutdatedWdm_FileFsControlInformation +# define FileFsFullSizeInformation OutdatedWdm_FileFsFullSizeInformation +# define FileFsObjectIdInformation OutdatedWdm_FileFsObjectIdInformation +# define FileFsDriverPathInformation OutdatedWdm_FileFsDriverPathInformation +# define FileFsVolumeFlagsInformation OutdatedWdm_FileFsVolumeFlagsInformation +# define FileFsSectorSizeInformation OutdatedWdm_FileFsSectorSizeInformation +# define FileFsDataCopyInformation OutdatedWdm_FileFsDataCopyInformation +# define FileFsMetadataSizeInformation OutdatedWdm_FileFsMetadataSizeInformation +# define FileFsFullSizeInformationEx OutdatedWdm_FileFsFullSizeInformationEx +# define FileFsMaximumInformation OutdatedWdm_FileFsMaximumInformation +# define NtQueryVolumeInformationFile OutdatedWdm_NtQueryVolumeInformationFile +# define NtSetVolumeInformationFile OutdatedWdm_NtSetVolumeInformationFile +# define _MEMORY_INFORMATION_CLASS OutdatedWdm__MEMORY_INFORMATION_CLASS +# define MEMORY_INFORMATION_CLASS OutdatedWdm_MEMORY_INFORMATION_CLASS +# define MemoryBasicInformation OutdatedWdm_MemoryBasicInformation +# define NtQueryVirtualMemory OutdatedWdm_NtQueryVirtualMemory + +# pragma warning(push) +# ifdef RT_ARCH_X86 +# define _InterlockedAddLargeStatistic _InterlockedAddLargeStatistic_StupidDDKVsCompilerCrap +# pragma warning(disable: 4163) +# endif +# pragma warning(disable: 4668) +# pragma warning(disable: 4255) /* warning C4255: 'ObGetFilterVersion' : no function prototype given: converting '()' to '(void)' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# pragma warning(disable:4471) /* wdm.h(11057) : warning C4471: '_POOL_TYPE' : a forward declaration of an unscoped enumeration must have an underlying type (int assumed) */ +# endif +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# ifdef __cplusplus +# pragma warning(disable:5039) /* warning C5039: 'KeInitializeDpc': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif + +# include <ntifs.h> +# include <wdm.h> + +# ifdef RT_ARCH_X86 +# undef _InterlockedAddLargeStatistic +# endif +# pragma warning(pop) + +# undef _FSINFOCLASS +# undef FS_INFORMATION_CLASS +# undef PFS_INFORMATION_CLASS +# undef FileFsVolumeInformation +# undef FileFsLabelInformation +# undef FileFsSizeInformation +# undef FileFsDeviceInformation +# undef FileFsAttributeInformation +# undef FileFsControlInformation +# undef FileFsFullSizeInformation +# undef FileFsObjectIdInformation +# undef FileFsDriverPathInformation +# undef FileFsVolumeFlagsInformation +# undef FileFsSectorSizeInformation +# undef FileFsDataCopyInformation +# undef FileFsMetadataSizeInformation +# undef FileFsFullSizeInformationEx +# undef FileFsMaximumInformation +# undef NtQueryVolumeInformationFile +# undef NtSetVolumeInformationFile +# undef _MEMORY_INFORMATION_CLASS +# undef MEMORY_INFORMATION_CLASS +# undef MemoryBasicInformation +# undef NtQueryVirtualMemory + +# define IPRT_NT_NEED_API_GROUP_NTIFS +# ifndef NTDDI_WIN10_RS1 +# define RTNT_NEED_NT_GET_PRODUCT_TYPE +# elif NTDDI_VERSION < NTDDI_WIN10_RS1 +# define RTNT_NEED_NT_GET_PRODUCT_TYPE +# endif + +#endif + +#undef RtlFreeUnicodeString +#undef NtQueryObject +#undef ZwQueryObject +#undef NtSetInformationObject +#undef _OBJECT_INFORMATION_CLASS +#undef OBJECT_INFORMATION_CLASS +#undef ObjectBasicInformation +#undef ObjectTypeInformation +#undef _PEB +#undef PEB +#undef PPEB +#undef _TEB +#undef TEB +#undef PTEB +#undef _PEB_LDR_DATA +#undef PEB_LDR_DATA +#undef PPEB_LDR_DATA +#undef _KUSER_SHARED_DATA +#undef KUSER_SHARED_DATA +#undef PKUSER_SHARED_DATA + + +#include <iprt/types.h> +#include <iprt/assert.h> + + +/** @name Useful macros + * @{ */ +/** Indicates that we're targeting native NT in the current source. */ +#define RTNT_USE_NATIVE_NT 1 +/** Initializes a IO_STATUS_BLOCK. */ +#define RTNT_IO_STATUS_BLOCK_INITIALIZER { STATUS_FAILED_DRIVER_ENTRY, ~(uintptr_t)42 } +/** Reinitializes a IO_STATUS_BLOCK. */ +#define RTNT_IO_STATUS_BLOCK_REINIT(a_pIos) \ + do { (a_pIos)->Status = STATUS_FAILED_DRIVER_ENTRY; (a_pIos)->Information = ~(uintptr_t)42; } while (0) +/** Similar to INVALID_HANDLE_VALUE in the Windows environment. */ +#define RTNT_INVALID_HANDLE_VALUE ( (HANDLE)~(uintptr_t)0 ) +/** Constant UNICODE_STRING initializer. */ +#define RTNT_CONSTANT_UNISTR(a_String) { sizeof(a_String) - sizeof(WCHAR), sizeof(a_String), (WCHAR *)a_String } +/** Null UNICODE_STRING initializer. */ +#define RTNT_NULL_UNISTR() { 0, 0, NULL } + +/** Declaration wrapper for NT apis. + * Adds nothrow. Don't use with callbacks. */ +#define RT_DECL_NTAPI(type) DECL_NOTHROW(NTSYSAPI type NTAPI) +/** @} */ + + +/** @name IPRT helper functions for NT + * @{ */ +RT_C_DECLS_BEGIN + +RTDECL(int) RTNtPathOpen(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, + ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, + PHANDLE phHandle, PULONG_PTR puDisposition); +RTDECL(int) RTNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions, + ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir); +RTDECL(int) RTNtPathOpenDirEx(HANDLE hRootDir, struct _UNICODE_STRING *pNtName, ACCESS_MASK fDesiredAccess, + ULONG fShareAccess, ULONG fCreateOptions, ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir); +RTDECL(int) RTNtPathClose(HANDLE hHandle); + +/** + * Converts a windows-style path to NT format and encoding. + * + * @returns IPRT status code. + * @param pNtName Where to return the NT name. Free using + * RTNtPathFree. + * @param phRootDir Where to return the root handle, if applicable. + * @param pszPath The UTF-8 path. + */ +RTDECL(int) RTNtPathFromWinUtf8(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath); + +/** + * Converts a UTF-16 windows-style path to NT format. + * + * @returns IPRT status code. + * @param pNtName Where to return the NT name. Free using + * RTNtPathFree. + * @param phRootDir Where to return the root handle, if applicable. + * @param pwszPath The UTF-16 windows-style path. + * @param cwcPath The max length of the windows-style path in + * RTUTF16 units. Use RTSTR_MAX if unknown and @a + * pwszPath is correctly terminated. + */ +RTDECL(int) RTNtPathFromWinUtf16Ex(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir, PCRTUTF16 pwszPath, size_t cwcPath); + +/** + * How to handle ascent ('..' relative to a root handle). + */ +typedef enum RTNTPATHRELATIVEASCENT +{ + kRTNtPathRelativeAscent_Invalid = 0, + kRTNtPathRelativeAscent_Allow, + kRTNtPathRelativeAscent_Fail, + kRTNtPathRelativeAscent_Ignore, + kRTNtPathRelativeAscent_End, + kRTNtPathRelativeAscent_32BitHack = 0x7fffffff +} RTNTPATHRELATIVEASCENT; + +/** + * Converts a relative windows-style path to relative NT format and encoding. + * + * @returns IPRT status code. + * @param pNtName Where to return the NT name. Free using + * rtTNtPathToNative with phRootDir set to NULL. + * @param phRootDir On input, the handle to the directory the path + * is relative to. On output, the handle to + * specify as root directory in the object + * attributes when accessing the path. If + * enmAscent is kRTNtPathRelativeAscent_Allow, it + * may have been set to NULL. + * @param pszPath The relative UTF-8 path. + * @param enmAscent How to handle ascent. + * @param fMustReturnAbsolute Must convert to an absolute path. This + * is necessary if the root dir is a NT directory + * object (e.g. /Devices) since they cannot parse + * relative paths it seems. + */ +RTDECL(int) RTNtPathRelativeFromUtf8(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath, + RTNTPATHRELATIVEASCENT enmAscent, bool fMustReturnAbsolute); + +/** + * Ensures that the NT string has sufficient storage to hold @a cwcMin RTUTF16 + * chars plus a terminator. + * + * The NT string must have been returned by RTNtPathFromWinUtf8 or + * RTNtPathFromWinUtf16Ex. + * + * @returns IPRT status code. + * @param pNtName The NT path string. + * @param cwcMin The minimum number of RTUTF16 chars. Max 32767. + * @sa RTNtPathFree + */ +RTDECL(int) RTNtPathEnsureSpace(struct _UNICODE_STRING *pNtName, size_t cwcMin); + +/** + * Gets the NT path to the object represented by the given handle. + * + * @returns IPRT status code. + * @param pNtName Where to return the NT path. Free using + * RTNtPathFree. + * @param hHandle The handle. + * @param cwcExtra How much extra space is needed. + */ +RTDECL(int) RTNtPathFromHandle(struct _UNICODE_STRING *pNtName, HANDLE hHandle, size_t cwcExtra); + +/** + * Frees the native path and root handle. + * + * @param pNtName The NT path after a successful rtNtPathToNative + * call or RTNtPathRelativeFromUtf8. + * @param phRootDir The root handle variable from rtNtPathToNative, + */ +RTDECL(void) RTNtPathFree(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir); + + +/** + * Checks whether the path could be containing alternative 8.3 names generated + * by NTFS, FAT, or other similar file systems. + * + * @returns Pointer to the first component that might be an 8.3 name, NULL if + * not 8.3 path. + * @param pwszPath The path to check. + * + * @remarks This is making bad ASSUMPTION wrt to the naming scheme of 8.3 names, + * however, non-tilde 8.3 aliases are probably rare enough to not be + * worth all the extra code necessary to open each path component and + * check if we've got the short name or not. + */ +RTDECL(PRTUTF16) RTNtPathFindPossible8dot3Name(PCRTUTF16 pwszPath); + +/** + * Fixes up a path possibly containing one or more alternative 8-dot-3 style + * components. + * + * The path is fixed up in place. Errors are ignored. + * + * @returns VINF_SUCCESS if it all went smoothly, informational status codes + * indicating the nature of last problem we ran into. + * + * @param pUniStr The path to fix up. MaximumLength is the max buffer + * length. + * @param fPathOnly Whether to only process the path and leave the filename + * as passed in. + */ +RTDECL(int) RTNtPathExpand8dot3Path(struct _UNICODE_STRING *pUniStr, bool fPathOnly); + +/** + * Wrapper around RTNtPathExpand8dot3Path that allocates a buffer instead of + * working on the input buffer. + * + * @returns IPRT status code, see RTNtPathExpand8dot3Path(). + * @param pUniStrSrc The path to fix up. MaximumLength is the max buffer + * length. + * @param fPathOnly Whether to only process the path and leave the filename + * as passed in. + * @param pUniStrDst Output string. On success, the caller must use + * RTUtf16Free to free what the Buffer member points to. + * This is all zeros and NULL on failure. + */ +RTDECL(int) RTNtPathExpand8dot3PathA(struct _UNICODE_STRING const *pUniStrSrc, bool fPathOnly, struct _UNICODE_STRING *pUniStrDst); + + +RT_C_DECLS_END +/** @} */ + + +/** @name NT API delcarations. + * @{ */ +RT_C_DECLS_BEGIN + +/** @name Process access rights missing in ntddk headers + * @{ */ +#ifndef PROCESS_TERMINATE +# define PROCESS_TERMINATE UINT32_C(0x00000001) +#endif +#ifndef PROCESS_CREATE_THREAD +# define PROCESS_CREATE_THREAD UINT32_C(0x00000002) +#endif +#ifndef PROCESS_SET_SESSIONID +# define PROCESS_SET_SESSIONID UINT32_C(0x00000004) +#endif +#ifndef PROCESS_VM_OPERATION +# define PROCESS_VM_OPERATION UINT32_C(0x00000008) +#endif +#ifndef PROCESS_VM_READ +# define PROCESS_VM_READ UINT32_C(0x00000010) +#endif +#ifndef PROCESS_VM_WRITE +# define PROCESS_VM_WRITE UINT32_C(0x00000020) +#endif +#ifndef PROCESS_DUP_HANDLE +# define PROCESS_DUP_HANDLE UINT32_C(0x00000040) +#endif +#ifndef PROCESS_CREATE_PROCESS +# define PROCESS_CREATE_PROCESS UINT32_C(0x00000080) +#endif +#ifndef PROCESS_SET_QUOTA +# define PROCESS_SET_QUOTA UINT32_C(0x00000100) +#endif +#ifndef PROCESS_SET_INFORMATION +# define PROCESS_SET_INFORMATION UINT32_C(0x00000200) +#endif +#ifndef PROCESS_QUERY_INFORMATION +# define PROCESS_QUERY_INFORMATION UINT32_C(0x00000400) +#endif +#ifndef PROCESS_SUSPEND_RESUME +# define PROCESS_SUSPEND_RESUME UINT32_C(0x00000800) +#endif +#ifndef PROCESS_QUERY_LIMITED_INFORMATION +# define PROCESS_QUERY_LIMITED_INFORMATION UINT32_C(0x00001000) +#endif +#ifndef PROCESS_SET_LIMITED_INFORMATION +# define PROCESS_SET_LIMITED_INFORMATION UINT32_C(0x00002000) +#endif +#define PROCESS_UNKNOWN_4000 UINT32_C(0x00004000) +#define PROCESS_UNKNOWN_6000 UINT32_C(0x00008000) +#ifndef PROCESS_ALL_ACCESS +# define PROCESS_ALL_ACCESS ( STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | UINT32_C(0x0000ffff) ) +#endif +/** @} */ + +/** @name Thread access rights missing in ntddk headers + * @{ */ +#ifndef THREAD_QUERY_INFORMATION +# define THREAD_QUERY_INFORMATION UINT32_C(0x00000040) +#endif +#ifndef THREAD_SET_THREAD_TOKEN +# define THREAD_SET_THREAD_TOKEN UINT32_C(0x00000080) +#endif +#ifndef THREAD_IMPERSONATE +# define THREAD_IMPERSONATE UINT32_C(0x00000100) +#endif +#ifndef THREAD_DIRECT_IMPERSONATION +# define THREAD_DIRECT_IMPERSONATION UINT32_C(0x00000200) +#endif +#ifndef THREAD_RESUME +# define THREAD_RESUME UINT32_C(0x00001000) +#endif +#define THREAD_UNKNOWN_2000 UINT32_C(0x00002000) +#define THREAD_UNKNOWN_4000 UINT32_C(0x00004000) +#define THREAD_UNKNOWN_8000 UINT32_C(0x00008000) +/** @} */ + +/** @name Special handle values. + * @{ */ +#ifndef NtCurrentProcess +# define NtCurrentProcess() ( (HANDLE)-(intptr_t)1 ) +#endif +#ifndef NtCurrentThread +# define NtCurrentThread() ( (HANDLE)-(intptr_t)2 ) +#endif +#ifndef ZwCurrentProcess +# define ZwCurrentProcess() NtCurrentProcess() +#endif +#ifndef ZwCurrentThread +# define ZwCurrentThread() NtCurrentThread() +#endif +/** @} */ + + +/** @name Directory object access rights. + * @{ */ +#ifndef DIRECTORY_QUERY +# define DIRECTORY_QUERY UINT32_C(0x00000001) +#endif +#ifndef DIRECTORY_TRAVERSE +# define DIRECTORY_TRAVERSE UINT32_C(0x00000002) +#endif +#ifndef DIRECTORY_CREATE_OBJECT +# define DIRECTORY_CREATE_OBJECT UINT32_C(0x00000004) +#endif +#ifndef DIRECTORY_CREATE_SUBDIRECTORY +# define DIRECTORY_CREATE_SUBDIRECTORY UINT32_C(0x00000008) +#endif +#ifndef DIRECTORY_ALL_ACCESS +# define DIRECTORY_ALL_ACCESS ( STANDARD_RIGHTS_REQUIRED | UINT32_C(0x0000000f) ) +#endif +/** @} */ + + + +#ifdef RTNT_NEED_CLIENT_ID +typedef struct _CLIENT_ID +{ + HANDLE UniqueProcess; + HANDLE UniqueThread; +} CLIENT_ID; +#endif +#ifdef IPRT_NT_USE_WINTERNL +typedef CLIENT_ID *PCLIENT_ID; +#endif + +/** Extended affinity type, introduced in Windows 7 (?). */ +typedef struct _KAFFINITY_EX +{ + /** Count of valid bitmap entries. */ + uint16_t Count; + /** Count of allocated bitmap entries. */ + uint16_t Size; + /** Reserved / aligmment padding. */ + uint32_t Reserved; + /** Bitmap where one bit corresponds to a CPU. + * @note Started at 20 entries. W10 20H2 increased it to 32. Must be + * probed by passing a big buffer to KeInitializeAffinityEx and check + * the Size afterwards. */ + uintptr_t Bitmap[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; +} KAFFINITY_EX; +typedef KAFFINITY_EX *PKAFFINITY_EX; +typedef KAFFINITY_EX const *PCKAFFINITY_EX; + +/** @name User Shared Data + * @{ */ + +#ifdef IPRT_NT_USE_WINTERNL +typedef struct _KSYSTEM_TIME +{ + ULONG LowPart; + LONG High1Time; + LONG High2Time; +} KSYSTEM_TIME; +typedef KSYSTEM_TIME *PKSYSTEM_TIME; + +typedef enum _NT_PRODUCT_TYPE +{ + NtProductWinNt = 1, + NtProductLanManNt, + NtProductServer +} NT_PRODUCT_TYPE; + +#define PROCESSOR_FEATURE_MAX 64 + +typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE +{ + StandardDesign = 0, + NEC98x86, + EndAlternatives +} ALTERNATIVE_ARCHITECTURE_TYPE; + +# if 0 +typedef struct _XSTATE_FEATURE +{ + ULONG Offset; + ULONG Size; +} XSTATE_FEATURE; +typedef XSTATE_FEATURE *PXSTATE_FEATURE; + +#define MAXIMUM_XSTATE_FEATURES 64 + +typedef struct _XSTATE_CONFIGURATION +{ + ULONG64 EnabledFeatures; + ULONG Size; + ULONG OptimizedSave : 1; + XSTATE_FEATURE Features[MAXIMUM_XSTATE_FEATURES]; +} XSTATE_CONFIGURATION; +typedef XSTATE_CONFIGURATION *PXSTATE_CONFIGURATION; +# endif +#endif /* IPRT_NT_USE_WINTERNL */ + +typedef struct _KUSER_SHARED_DATA +{ + ULONG TickCountLowDeprecated; /**< 0x000 */ + ULONG TickCountMultiplier; /**< 0x004 */ + KSYSTEM_TIME volatile InterruptTime; /**< 0x008 */ + KSYSTEM_TIME volatile SystemTime; /**< 0x014 */ + KSYSTEM_TIME volatile TimeZoneBias; /**< 0x020 */ + USHORT ImageNumberLow; /**< 0x02c */ + USHORT ImageNumberHigh; /**< 0x02e */ + WCHAR NtSystemRoot[260]; /**< 0x030 - Seems to be last member in NT 3.51. */ + ULONG MaxStackTraceDepth; /**< 0x238 */ + ULONG CryptoExponent; /**< 0x23c */ + ULONG TimeZoneId; /**< 0x240 */ + ULONG LargePageMinimum; /**< 0x244 */ + ULONG AitSamplingValue; /**< 0x248 */ + ULONG AppCompatFlag; /**< 0x24c */ + ULONGLONG RNGSeedVersion; /**< 0x250 */ + ULONG GlobalValidationRunlevel; /**< 0x258 */ + LONG volatile TimeZoneBiasStamp; /**< 0x25c*/ + ULONG Reserved2; /**< 0x260 */ + NT_PRODUCT_TYPE NtProductType; /**< 0x264 */ + BOOLEAN ProductTypeIsValid; /**< 0x268 */ + BOOLEAN Reserved0[1]; /**< 0x269 */ + USHORT NativeProcessorArchitecture; /**< 0x26a */ + ULONG NtMajorVersion; /**< 0x26c */ + ULONG NtMinorVersion; /**< 0x270 */ + BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX]; /**< 0x274 */ + ULONG Reserved1; /**< 0x2b4 */ + ULONG Reserved3; /**< 0x2b8 */ + ULONG volatile TimeSlip; /**< 0x2bc */ + ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture; /**< 0x2c0 */ + ULONG AltArchitecturePad[1]; /**< 0x2c4 */ + LARGE_INTEGER SystemExpirationDate; /**< 0x2c8 */ + ULONG SuiteMask; /**< 0x2d0 */ + BOOLEAN KdDebuggerEnabled; /**< 0x2d4 */ + union /**< 0x2d5 */ + { + UCHAR MitigationPolicies; /**< 0x2d5 */ + struct + { + UCHAR NXSupportPolicy : 2; + UCHAR SEHValidationPolicy : 2; + UCHAR CurDirDevicesSkippedForDlls : 2; + UCHAR Reserved : 2; + }; + }; + UCHAR Reserved6[2]; /**< 0x2d6 */ + ULONG volatile ActiveConsoleId; /**< 0x2d8 */ + ULONG volatile DismountCount; /**< 0x2dc */ + ULONG ComPlusPackage; /**< 0x2e0 */ + ULONG LastSystemRITEventTickCount; /**< 0x2e4 */ + ULONG NumberOfPhysicalPages; /**< 0x2e8 */ + BOOLEAN SafeBootMode; /**< 0x2ec */ + UCHAR Reserved12[3]; /**< 0x2ed */ + union /**< 0x2f0 */ + { + ULONG SharedDataFlags; /**< 0x2f0 */ + struct + { + ULONG DbgErrorPortPresent : 1; + ULONG DbgElevationEnabled : 1; + ULONG DbgVirtEnabled : 1; + ULONG DbgInstallerDetectEnabled : 1; + ULONG DbgLkgEnabled : 1; + ULONG DbgDynProcessorEnabled : 1; + ULONG DbgConsoleBrokerEnabled : 1; + ULONG DbgSecureBootEnabled : 1; + ULONG SpareBits : 24; + }; + }; + ULONG DataFlagsPad[1]; /**< 0x2f4 */ + ULONGLONG TestRetInstruction; /**< 0x2f8 */ + LONGLONG QpcFrequency; /**< 0x300 */ + ULONGLONG SystemCallPad[3]; /**< 0x308 */ + union /**< 0x320 */ + { + ULONG64 volatile TickCountQuad; /**< 0x320 */ + KSYSTEM_TIME volatile TickCount; /**< 0x320 */ + struct /**< 0x320 */ + { + ULONG ReservedTickCountOverlay[3]; /**< 0x320 */ + ULONG TickCountPad[1]; /**< 0x32c */ + }; + }; + ULONG Cookie; /**< 0x330 */ + ULONG CookiePad[1]; /**< 0x334 */ + LONGLONG ConsoleSessionForegroundProcessId; /**< 0x338 */ + ULONGLONG TimeUpdateLock; /**< 0x340 */ + ULONGLONG BaselineSystemTimeQpc; /**< 0x348 */ + ULONGLONG BaselineInterruptTimeQpc; /**< 0x350 */ + ULONGLONG QpcSystemTimeIncrement; /**< 0x358 */ + ULONGLONG QpcInterruptTimeIncrement; /**< 0x360 */ + ULONG QpcSystemTimeIncrement32; /**< 0x368 */ + ULONG QpcInterruptTimeIncrement32; /**< 0x36c */ + UCHAR QpcSystemTimeIncrementShift; /**< 0x370 */ + UCHAR QpcInterruptTimeIncrementShift; /**< 0x371 */ + UCHAR Reserved8[14]; /**< 0x372 */ + USHORT UserModeGlobalLogger[16]; /**< 0x380 */ + ULONG ImageFileExecutionOptions; /**< 0x3a0 */ + ULONG LangGenerationCount; /**< 0x3a4 */ + ULONGLONG Reserved4; /**< 0x3a8 */ + ULONGLONG volatile InterruptTimeBias; /**< 0x3b0 - What QueryUnbiasedInterruptTimePrecise + * subtracts from interrupt time. */ + ULONGLONG volatile QpcBias; /**< 0x3b8 */ + ULONG volatile ActiveProcessorCount; /**< 0x3c0 */ + UCHAR volatile ActiveGroupCount; /**< 0x3c4 */ + UCHAR Reserved9; /**< 0x3c5 */ + union /**< 0x3c6 */ + { + USHORT QpcData; /**< 0x3c6 */ + struct /**< 0x3c6 */ + { + BOOLEAN volatile QpcBypassEnabled; /**< 0x3c6 */ + UCHAR QpcShift; /**< 0x3c7 */ + }; + }; + LARGE_INTEGER TimeZoneBiasEffectiveStart; /**< 0x3c8 */ + LARGE_INTEGER TimeZoneBiasEffectiveEnd; /**< 0x3d0 */ + XSTATE_CONFIGURATION XState; /**< 0x3d8 */ +} KUSER_SHARED_DATA; +typedef KUSER_SHARED_DATA *PKUSER_SHARED_DATA; +AssertCompileMemberOffset(KUSER_SHARED_DATA, InterruptTime, 0x008); +AssertCompileMemberOffset(KUSER_SHARED_DATA, SystemTime, 0x014); +AssertCompileMemberOffset(KUSER_SHARED_DATA, NtSystemRoot, 0x030); +AssertCompileMemberOffset(KUSER_SHARED_DATA, LargePageMinimum, 0x244); +AssertCompileMemberOffset(KUSER_SHARED_DATA, Reserved1, 0x2b4); +AssertCompileMemberOffset(KUSER_SHARED_DATA, TestRetInstruction, 0x2f8); +AssertCompileMemberOffset(KUSER_SHARED_DATA, Cookie, 0x330); +AssertCompileMemberOffset(KUSER_SHARED_DATA, ImageFileExecutionOptions, 0x3a0); +AssertCompileMemberOffset(KUSER_SHARED_DATA, XState, 0x3d8); +/** @def MM_SHARED_USER_DATA_VA + * Read only userland mapping of KUSER_SHARED_DATA. */ +#ifndef MM_SHARED_USER_DATA_VA +# if ARCH_BITS == 32 +# define MM_SHARED_USER_DATA_VA UINT32_C(0x7ffe0000) +# elif ARCH_BITS == 64 +# define MM_SHARED_USER_DATA_VA UINT64_C(0x7ffe0000) +# else +# error "Unsupported/undefined ARCH_BITS value." +# endif +#endif +/** @def KI_USER_SHARED_DATA + * Read write kernel mapping of KUSER_SHARED_DATA. */ +#ifndef KI_USER_SHARED_DATA +# ifdef RT_ARCH_X86 +# define KI_USER_SHARED_DATA UINT32_C(0xffdf0000) +# elif defined(RT_ARCH_AMD64) +# define KI_USER_SHARED_DATA UINT64_C(0xfffff78000000000) +# else +# error "PORT ME - KI_USER_SHARED_DATA" +# endif +#endif +/** @} */ + + +/** @name Process And Thread Environment Blocks + * @{ */ + +typedef struct _PEB_LDR_DATA +{ + uint32_t Length; + BOOLEAN Initialized; + BOOLEAN Padding[3]; + HANDLE SsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + /* End NT4 */ + LIST_ENTRY *EntryInProgress; + BOOLEAN ShutdownInProgress; + HANDLE ShutdownThreadId; +} PEB_LDR_DATA; +typedef PEB_LDR_DATA *PPEB_LDR_DATA; + +typedef struct _PEB_COMMON +{ + BOOLEAN InheritedAddressSpace; /**< 0x000 / 0x000 */ + BOOLEAN ReadImageFileExecOptions; /**< 0x001 / 0x001 */ + BOOLEAN BeingDebugged; /**< 0x002 / 0x002 */ + union + { + uint8_t BitField; /**< 0x003 / 0x003 */ + struct + { + uint8_t ImageUsesLargePages : 1; /**< 0x003 / 0x003 : Pos 0, 1 Bit */ + } Common; + struct + { + uint8_t ImageUsesLargePages : 1; /**< 0x003 / 0x003 : Pos 0, 1 Bit */ + uint8_t IsProtectedProcess : 1; /**< 0x003 / 0x003 : Pos 1, 1 Bit */ + uint8_t IsImageDynamicallyRelocated : 1; /**< 0x003 / 0x003 : Pos 2, 1 Bit - Differs from W80 */ + uint8_t SkipPatchingUser32Forwarders : 1; /**< 0x003 / 0x003 : Pos 3, 1 Bit - Differs from W80 */ + uint8_t IsPackagedProcess : 1; /**< 0x003 / 0x003 : Pos 4, 1 Bit - Differs from W80 */ + uint8_t IsAppContainer : 1; /**< 0x003 / 0x003 : Pos 5, 1 Bit - Differs from W80 */ + uint8_t IsProtectedProcessLight : 1; /**< 0x003 / 0x003 : Pos 6, 1 Bit - Differs from W80 */ + uint8_t SpareBits : 1; /**< 0x003 / 0x003 : Pos 7, 1 Bit */ + } W81; + struct + { + uint8_t ImageUsesLargePages : 1; /**< 0x003 / 0x003 : Pos 0, 1 Bit */ + uint8_t IsProtectedProcess : 1; /**< 0x003 / 0x003 : Pos 1, 1 Bit */ + uint8_t IsLegacyProcess : 1; /**< 0x003 / 0x003 : Pos 2, 1 Bit - Differs from W81 */ + uint8_t IsImageDynamicallyRelocated : 1; /**< 0x003 / 0x003 : Pos 3, 1 Bit - Differs from W81 */ + uint8_t SkipPatchingUser32Forwarders : 1; /**< 0x003 / 0x003 : Pos 4, 1 Bit - Differs from W81 */ + uint8_t IsPackagedProcess : 1; /**< 0x003 / 0x003 : Pos 5, 1 Bit - Differs from W81 */ + uint8_t IsAppContainer : 1; /**< 0x003 / 0x003 : Pos 6, 1 Bit - Differs from W81 */ + uint8_t SpareBits : 1; /**< 0x003 / 0x003 : Pos 7, 1 Bit */ + } W80; + struct + { + uint8_t ImageUsesLargePages : 1; /**< 0x003 / 0x003 : Pos 0, 1 Bit */ + uint8_t IsProtectedProcess : 1; /**< 0x003 / 0x003 : Pos 1, 1 Bit */ + uint8_t IsLegacyProcess : 1; /**< 0x003 / 0x003 : Pos 2, 1 Bit - Differs from W81, same as W80 & W6. */ + uint8_t IsImageDynamicallyRelocated : 1; /**< 0x003 / 0x003 : Pos 3, 1 Bit - Differs from W81, same as W80 & W6. */ + uint8_t SkipPatchingUser32Forwarders : 1; /**< 0x003 / 0x003 : Pos 4, 1 Bit - Added in W7; Differs from W81, same as W80. */ + uint8_t SpareBits : 3; /**< 0x003 / 0x003 : Pos 5, 3 Bit - Differs from W81 & W80, more spare bits. */ + } W7; + struct + { + uint8_t ImageUsesLargePages : 1; /**< 0x003 / 0x003 : Pos 0, 1 Bit */ + uint8_t IsProtectedProcess : 1; /**< 0x003 / 0x003 : Pos 1, 1 Bit */ + uint8_t IsLegacyProcess : 1; /**< 0x003 / 0x003 : Pos 2, 1 Bit - Differs from W81, same as W80 & W7. */ + uint8_t IsImageDynamicallyRelocated : 1; /**< 0x003 / 0x003 : Pos 3, 1 Bit - Differs from W81, same as W80 & W7. */ + uint8_t SpareBits : 4; /**< 0x003 / 0x003 : Pos 4, 4 Bit - Differs from W81, W80, & W7, more spare bits. */ + } W6; + struct + { + uint8_t ImageUsesLargePages : 1; /**< 0x003 / 0x003 : Pos 0, 1 Bit */ + uint8_t SpareBits : 7; /**< 0x003 / 0x003 : Pos 1, 7 Bit - Differs from W81, W80, & W7, more spare bits. */ + } W52; + struct + { + BOOLEAN SpareBool; + } W51; + } Diff0; +#if ARCH_BITS == 64 + uint32_t Padding0; /**< 0x004 / NA */ +#endif + HANDLE Mutant; /**< 0x008 / 0x004 */ + PVOID ImageBaseAddress; /**< 0x010 / 0x008 */ + PPEB_LDR_DATA Ldr; /**< 0x018 / 0x00c */ + struct _RTL_USER_PROCESS_PARAMETERS *ProcessParameters; /**< 0x020 / 0x010 */ + PVOID SubSystemData; /**< 0x028 / 0x014 */ + HANDLE ProcessHeap; /**< 0x030 / 0x018 */ + struct _RTL_CRITICAL_SECTION *FastPebLock; /**< 0x038 / 0x01c */ + union + { + struct + { + PVOID AtlThunkSListPtr; /**< 0x040 / 0x020 */ + PVOID IFEOKey; /**< 0x048 / 0x024 */ + union + { + ULONG CrossProcessFlags; /**< 0x050 / 0x028 */ + struct + { + uint32_t ProcessInJob : 1; /**< 0x050 / 0x028: Pos 0, 1 Bit */ + uint32_t ProcessInitializing : 1; /**< 0x050 / 0x028: Pos 1, 1 Bit */ + uint32_t ProcessUsingVEH : 1; /**< 0x050 / 0x028: Pos 2, 1 Bit */ + uint32_t ProcessUsingVCH : 1; /**< 0x050 / 0x028: Pos 3, 1 Bit */ + uint32_t ProcessUsingFTH : 1; /**< 0x050 / 0x028: Pos 4, 1 Bit */ + uint32_t ReservedBits0 : 1; /**< 0x050 / 0x028: Pos 5, 27 Bits */ + } W7, W8, W80, W81; + struct + { + uint32_t ProcessInJob : 1; /**< 0x050 / 0x028: Pos 0, 1 Bit */ + uint32_t ProcessInitializing : 1; /**< 0x050 / 0x028: Pos 1, 1 Bit */ + uint32_t ReservedBits0 : 30; /**< 0x050 / 0x028: Pos 2, 30 Bits */ + } W6; + }; +#if ARCH_BITS == 64 + uint32_t Padding1; /**< 0x054 / */ +#endif + } W6, W7, W8, W80, W81; + struct + { + PVOID AtlThunkSListPtr; /**< 0x040 / 0x020 */ + PVOID SparePtr2; /**< 0x048 / 0x024 */ + uint32_t EnvironmentUpdateCount; /**< 0x050 / 0x028 */ +#if ARCH_BITS == 64 + uint32_t Padding1; /**< 0x054 / */ +#endif + } W52; + struct + { + PVOID FastPebLockRoutine; /**< NA / 0x020 */ + PVOID FastPebUnlockRoutine; /**< NA / 0x024 */ + uint32_t EnvironmentUpdateCount; /**< NA / 0x028 */ + } W51; + } Diff1; + union + { + PVOID KernelCallbackTable; /**< 0x058 / 0x02c */ + PVOID UserSharedInfoPtr; /**< 0x058 / 0x02c - Alternative use in W6.*/ + }; + uint32_t SystemReserved; /**< 0x060 / 0x030 */ + union + { + struct + { + uint32_t AtlThunkSListPtr32; /**< 0x064 / 0x034 */ + } W7, W8, W80, W81; + struct + { + uint32_t SpareUlong; /**< 0x064 / 0x034 */ + } W52, W6; + struct + { + uint32_t ExecuteOptions : 2; /**< NA / 0x034: Pos 0, 2 Bits */ + uint32_t SpareBits : 30; /**< NA / 0x034: Pos 2, 30 Bits */ + } W51; + } Diff2; + union + { + struct + { + PVOID ApiSetMap; /**< 0x068 / 0x038 */ + } W7, W8, W80, W81; + struct + { + struct _PEB_FREE_BLOCK *FreeList; /**< 0x068 / 0x038 */ + } W52, W6; + struct + { + struct _PEB_FREE_BLOCK *FreeList; /**< NA / 0x038 */ + } W51; + } Diff3; + uint32_t TlsExpansionCounter; /**< 0x070 / 0x03c */ +#if ARCH_BITS == 64 + uint32_t Padding2; /**< 0x074 / NA */ +#endif + struct _RTL_BITMAP *TlsBitmap; /**< 0x078 / 0x040 */ + uint32_t TlsBitmapBits[2]; /**< 0x080 / 0x044 */ + PVOID ReadOnlySharedMemoryBase; /**< 0x088 / 0x04c */ + union + { + struct + { + PVOID SparePvoid0; /**< 0x090 / 0x050 - HotpatchInformation before W81. */ + } W81; + struct + { + PVOID HotpatchInformation; /**< 0x090 / 0x050 - Retired in W81. */ + } W6, W7, W80; + struct + { + PVOID ReadOnlySharedMemoryHeap; + } W52; + } Diff4; + PVOID *ReadOnlyStaticServerData; /**< 0x098 / 0x054 */ + PVOID AnsiCodePageData; /**< 0x0a0 / 0x058 */ + PVOID OemCodePageData; /**< 0x0a8 / 0x05c */ + PVOID UnicodeCaseTableData; /**< 0x0b0 / 0x060 */ + uint32_t NumberOfProcessors; /**< 0x0b8 / 0x064 */ + uint32_t NtGlobalFlag; /**< 0x0bc / 0x068 */ +#if ARCH_BITS == 32 + uint32_t Padding2b; +#endif + LARGE_INTEGER CriticalSectionTimeout; /**< 0x0c0 / 0x070 */ + SIZE_T HeapSegmentReserve; /**< 0x0c8 / 0x078 */ + SIZE_T HeapSegmentCommit; /**< 0x0d0 / 0x07c */ + SIZE_T HeapDeCommitTotalFreeThreshold; /**< 0x0d8 / 0x080 */ + SIZE_T HeapDeCommitFreeBlockThreshold; /**< 0x0e0 / 0x084 */ + uint32_t NumberOfHeaps; /**< 0x0e8 / 0x088 */ + uint32_t MaximumNumberOfHeaps; /**< 0x0ec / 0x08c */ + PVOID *ProcessHeaps; /**< 0x0f0 / 0x090 - Last NT 3.51 member. */ + PVOID GdiSharedHandleTable; /**< 0x0f8 / 0x094 */ + PVOID ProcessStarterHelper; /**< 0x100 / 0x098 */ + uint32_t GdiDCAttributeList; /**< 0x108 / 0x09c */ +#if ARCH_BITS == 64 + uint32_t Padding3; /**< 0x10c / NA */ +#endif + struct _RTL_CRITICAL_SECTION *LoaderLock; /**< 0x110 / 0x0a0 */ + uint32_t OSMajorVersion; /**< 0x118 / 0x0a4 */ + uint32_t OSMinorVersion; /**< 0x11c / 0x0a8 */ + uint16_t OSBuildNumber; /**< 0x120 / 0x0ac */ + uint16_t OSCSDVersion; /**< 0x122 / 0x0ae */ + uint32_t OSPlatformId; /**< 0x124 / 0x0b0 */ + uint32_t ImageSubsystem; /**< 0x128 / 0x0b4 */ + uint32_t ImageSubsystemMajorVersion; /**< 0x12c / 0x0b8 */ + uint32_t ImageSubsystemMinorVersion; /**< 0x130 / 0x0bc */ +#if ARCH_BITS == 64 + uint32_t Padding4; /**< 0x134 / NA */ +#endif + union + { + struct + { + SIZE_T ActiveProcessAffinityMask; /**< 0x138 / 0x0c0 */ + } W7, W8, W80, W81; + struct + { + SIZE_T ImageProcessAffinityMask; /**< 0x138 / 0x0c0 */ + } W52, W6; + } Diff5; + uint32_t GdiHandleBuffer[ARCH_BITS == 64 ? 60 : 34]; /**< 0x140 / 0x0c4 */ + PVOID PostProcessInitRoutine; /**< 0x230 / 0x14c */ + PVOID TlsExpansionBitmap; /**< 0x238 / 0x150 */ + uint32_t TlsExpansionBitmapBits[32]; /**< 0x240 / 0x154 */ + uint32_t SessionId; /**< 0x2c0 / 0x1d4 */ +#if ARCH_BITS == 64 + uint32_t Padding5; /**< 0x2c4 / NA */ +#endif + ULARGE_INTEGER AppCompatFlags; /**< 0x2c8 / 0x1d8 */ + ULARGE_INTEGER AppCompatFlagsUser; /**< 0x2d0 / 0x1e0 */ + PVOID pShimData; /**< 0x2d8 / 0x1e8 */ + PVOID AppCompatInfo; /**< 0x2e0 / 0x1ec */ + UNICODE_STRING CSDVersion; /**< 0x2e8 / 0x1f0 */ + struct _ACTIVATION_CONTEXT_DATA *ActivationContextData; /**< 0x2f8 / 0x1f8 */ + struct _ASSEMBLY_STORAGE_MAP *ProcessAssemblyStorageMap; /**< 0x300 / 0x1fc */ + struct _ACTIVATION_CONTEXT_DATA *SystemDefaultActivationContextData; /**< 0x308 / 0x200 */ + struct _ASSEMBLY_STORAGE_MAP *SystemAssemblyStorageMap; /**< 0x310 / 0x204 */ + SIZE_T MinimumStackCommit; /**< 0x318 / 0x208 */ + /* End of PEB in W52 (Windows XP (RTM))! */ + struct _FLS_CALLBACK_INFO *FlsCallback; /**< 0x320 / 0x20c */ + LIST_ENTRY FlsListHead; /**< 0x328 / 0x210 */ + PVOID FlsBitmap; /**< 0x338 / 0x218 */ + uint32_t FlsBitmapBits[4]; /**< 0x340 / 0x21c */ + uint32_t FlsHighIndex; /**< 0x350 / 0x22c */ + /* End of PEB in W52 (Windows Server 2003)! */ + PVOID WerRegistrationData; /**< 0x358 / 0x230 */ + PVOID WerShipAssertPtr; /**< 0x360 / 0x234 */ + /* End of PEB in W6 (windows Vista)! */ + union + { + struct + { + PVOID pUnused; /**< 0x368 / 0x238 - Was pContextData in W7. */ + } W8, W80, W81; + struct + { + PVOID pContextData; /**< 0x368 / 0x238 - Retired in W80. */ + } W7; + } Diff6; + PVOID pImageHeaderHash; /**< 0x370 / 0x23c */ + union + { + uint32_t TracingFlags; /**< 0x378 / 0x240 */ + struct + { + uint32_t HeapTracingEnabled : 1; /**< 0x378 / 0x240 : Pos 0, 1 Bit */ + uint32_t CritSecTracingEnabled : 1; /**< 0x378 / 0x240 : Pos 1, 1 Bit */ + uint32_t LibLoaderTracingEnabled : 1; /**< 0x378 / 0x240 : Pos 2, 1 Bit */ + uint32_t SpareTracingBits : 29; /**< 0x378 / 0x240 : Pos 3, 29 Bits */ + } W8, W80, W81; + struct + { + uint32_t HeapTracingEnabled : 1; /**< 0x378 / 0x240 : Pos 0, 1 Bit */ + uint32_t CritSecTracingEnabled : 1; /**< 0x378 / 0x240 : Pos 1, 1 Bit */ + uint32_t SpareTracingBits : 30; /**< 0x378 / 0x240 : Pos 3, 30 Bits - One bit more than W80 */ + } W7; + } Diff7; +#if ARCH_BITS == 64 + uint32_t Padding6; /**< 0x37c / NA */ +#endif + uint64_t CsrServerReadOnlySharedMemoryBase; /**< 0x380 / 0x248 */ + /* End of PEB in W8, W81. */ + uintptr_t TppWorkerpListLock; /**< 0x388 / 0x250 */ + LIST_ENTRY TppWorkerpList; /**< 0x390 / 0x254 */ + PVOID WaitOnAddressHashTable[128]; /**< 0x3a0 / 0x25c */ +#if ARCH_BITS == 32 + uint32_t ExplicitPadding7; /**< NA NA / 0x45c */ +#endif +} PEB_COMMON; +typedef PEB_COMMON *PPEB_COMMON; + +AssertCompileMemberOffset(PEB_COMMON, ProcessHeap, ARCH_BITS == 64 ? 0x30 : 0x18); +AssertCompileMemberOffset(PEB_COMMON, SystemReserved, ARCH_BITS == 64 ? 0x60 : 0x30); +AssertCompileMemberOffset(PEB_COMMON, TlsExpansionCounter, ARCH_BITS == 64 ? 0x70 : 0x3c); +AssertCompileMemberOffset(PEB_COMMON, NtGlobalFlag, ARCH_BITS == 64 ? 0xbc : 0x68); +AssertCompileMemberOffset(PEB_COMMON, LoaderLock, ARCH_BITS == 64 ? 0x110 : 0xa0); +AssertCompileMemberOffset(PEB_COMMON, Diff5.W52.ImageProcessAffinityMask, ARCH_BITS == 64 ? 0x138 : 0xc0); +AssertCompileMemberOffset(PEB_COMMON, PostProcessInitRoutine, ARCH_BITS == 64 ? 0x230 : 0x14c); +AssertCompileMemberOffset(PEB_COMMON, AppCompatFlags, ARCH_BITS == 64 ? 0x2c8 : 0x1d8); +AssertCompileSize(PEB_COMMON, ARCH_BITS == 64 ? 0x7a0 : 0x460); + +/** The size of the windows 10 (build 14393) PEB structure. */ +#define PEB_SIZE_W10 sizeof(PEB_COMMON) +/** The size of the windows 8.1 PEB structure. */ +#define PEB_SIZE_W81 RT_UOFFSETOF(PEB_COMMON, TppWorkerpListLock) +/** The size of the windows 8.0 PEB structure. */ +#define PEB_SIZE_W80 RT_UOFFSETOF(PEB_COMMON, TppWorkerpListLock) +/** The size of the windows 7 PEB structure. */ +#define PEB_SIZE_W7 RT_UOFFSETOF(PEB_COMMON, CsrServerReadOnlySharedMemoryBase) +/** The size of the windows vista PEB structure. */ +#define PEB_SIZE_W6 RT_UOFFSETOF(PEB_COMMON, Diff3) +/** The size of the windows server 2003 PEB structure. */ +#define PEB_SIZE_W52 RT_UOFFSETOF(PEB_COMMON, WerRegistrationData) +/** The size of the windows XP PEB structure. */ +#define PEB_SIZE_W51 RT_UOFFSETOF(PEB_COMMON, FlsCallback) + +#if 0 +typedef struct _NT_TIB +{ + struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; + PVOID StackBase; + PVOID StackLimit; + PVOID SubSystemTib; + union + { + PVOID FiberData; + ULONG Version; + }; + PVOID ArbitraryUserPointer; + struct _NT_TIB *Self; +} NT_TIB; +typedef NT_TIB *PNT_TIB; +#endif + +typedef struct _ACTIVATION_CONTEXT_STACK +{ + uint32_t Flags; + uint32_t NextCookieSequenceNumber; + PVOID ActiveFrame; + LIST_ENTRY FrameListCache; +} ACTIVATION_CONTEXT_STACK; + +/* Common TEB. */ +typedef struct _TEB_COMMON +{ + NT_TIB NtTib; /**< 0x000 / 0x000 */ + PVOID EnvironmentPointer; /**< 0x038 / 0x01c */ + CLIENT_ID ClientId; /**< 0x040 / 0x020 */ + PVOID ActiveRpcHandle; /**< 0x050 / 0x028 */ + PVOID ThreadLocalStoragePointer; /**< 0x058 / 0x02c */ + PPEB_COMMON ProcessEnvironmentBlock; /**< 0x060 / 0x030 */ + uint32_t LastErrorValue; /**< 0x068 / 0x034 */ + uint32_t CountOfOwnedCriticalSections; /**< 0x06c / 0x038 */ + PVOID CsrClientThread; /**< 0x070 / 0x03c */ + PVOID Win32ThreadInfo; /**< 0x078 / 0x040 */ + uint32_t User32Reserved[26]; /**< 0x080 / 0x044 */ + uint32_t UserReserved[5]; /**< 0x0e8 / 0x0ac */ + PVOID WOW32Reserved; /**< 0x100 / 0x0c0 */ + uint32_t CurrentLocale; /**< 0x108 / 0x0c4 */ + uint32_t FpSoftwareStatusRegister; /**< 0x10c / 0x0c8 */ + PVOID SystemReserved1[54]; /**< 0x110 / 0x0cc */ + uint32_t ExceptionCode; /**< 0x2c0 / 0x1a4 */ +#if ARCH_BITS == 64 + uint32_t Padding0; /**< 0x2c4 / NA */ +#endif + union + { + struct + { + struct _ACTIVATION_CONTEXT_STACK *ActivationContextStackPointer;/**< 0x2c8 / 0x1a8 */ + uint8_t SpareBytes[ARCH_BITS == 64 ? 24 : 36]; /**< 0x2d0 / 0x1ac */ + } W52, W6, W7, W8, W80, W81; +#if ARCH_BITS == 32 + struct + { + ACTIVATION_CONTEXT_STACK ActivationContextStack; /**< NA / 0x1a8 */ + uint8_t SpareBytes[20]; /**< NA / 0x1bc */ + } W51; +#endif + } Diff0; + union + { + struct + { + uint32_t TxFsContext; /**< 0x2e8 / 0x1d0 */ + } W6, W7, W8, W80, W81; + struct + { + uint32_t SpareBytesContinues; /**< 0x2e8 / 0x1d0 */ + } W52; + } Diff1; +#if ARCH_BITS == 64 + uint32_t Padding1; /**< 0x2ec / NA */ +#endif + /*_GDI_TEB_BATCH*/ uint8_t GdiTebBatch[ARCH_BITS == 64 ? 0x4e8 :0x4e0]; /**< 0x2f0 / 0x1d4 */ + CLIENT_ID RealClientId; /**< 0x7d8 / 0x6b4 */ + HANDLE GdiCachedProcessHandle; /**< 0x7e8 / 0x6bc */ + uint32_t GdiClientPID; /**< 0x7f0 / 0x6c0 */ + uint32_t GdiClientTID; /**< 0x7f4 / 0x6c4 */ + PVOID GdiThreadLocalInfo; /**< 0x7f8 / 0x6c8 */ + SIZE_T Win32ClientInfo[62]; /**< 0x800 / 0x6cc */ + PVOID glDispatchTable[233]; /**< 0x9f0 / 0x7c4 */ + SIZE_T glReserved1[29]; /**< 0x1138 / 0xb68 */ + PVOID glReserved2; /**< 0x1220 / 0xbdc */ + PVOID glSectionInfo; /**< 0x1228 / 0xbe0 */ + PVOID glSection; /**< 0x1230 / 0xbe4 */ + PVOID glTable; /**< 0x1238 / 0xbe8 */ + PVOID glCurrentRC; /**< 0x1240 / 0xbec */ + PVOID glContext; /**< 0x1248 / 0xbf0 */ + NTSTATUS LastStatusValue; /**< 0x1250 / 0xbf4 */ +#if ARCH_BITS == 64 + uint32_t Padding2; /**< 0x1254 / NA */ +#endif + UNICODE_STRING StaticUnicodeString; /**< 0x1258 / 0xbf8 */ + WCHAR StaticUnicodeBuffer[261]; /**< 0x1268 / 0xc00 */ +#if ARCH_BITS == 64 + WCHAR Padding3[3]; /**< 0x1472 / NA */ +#endif + PVOID DeallocationStack; /**< 0x1478 / 0xe0c */ + PVOID TlsSlots[64]; /**< 0x1480 / 0xe10 */ + LIST_ENTRY TlsLinks; /**< 0x1680 / 0xf10 */ + PVOID Vdm; /**< 0x1690 / 0xf18 */ + PVOID ReservedForNtRpc; /**< 0x1698 / 0xf1c */ + PVOID DbgSsReserved[2]; /**< 0x16a0 / 0xf20 */ + uint32_t HardErrorMode; /**< 0x16b0 / 0xf28 - Called HardErrorsAreDisabled in W51. */ +#if ARCH_BITS == 64 + uint32_t Padding4; /**< 0x16b4 / NA */ +#endif + PVOID Instrumentation[ARCH_BITS == 64 ? 11 : 9]; /**< 0x16b8 / 0xf2c */ + union + { + struct + { + GUID ActivityId; /**< 0x1710 / 0xf50 */ + PVOID SubProcessTag; /**< 0x1720 / 0xf60 */ + } W6, W7, W8, W80, W81; + struct + { + PVOID InstrumentationContinues[ARCH_BITS == 64 ? 3 : 5]; /**< 0x1710 / 0xf50 */ + } W52; + } Diff2; + union /**< 0x1728 / 0xf64 */ + { + struct + { + PVOID PerflibData; /**< 0x1728 / 0xf64 */ + } W8, W80, W81; + struct + { + PVOID EtwLocalData; /**< 0x1728 / 0xf64 */ + } W7, W6; + struct + { + PVOID SubProcessTag; /**< 0x1728 / 0xf64 */ + } W52; + struct + { + PVOID InstrumentationContinues[1]; /**< 0x1728 / 0xf64 */ + } W51; + } Diff3; + union + { + struct + { + PVOID EtwTraceData; /**< 0x1730 / 0xf68 */ + } W52, W6, W7, W8, W80, W81; + struct + { + PVOID InstrumentationContinues[1]; /**< 0x1730 / 0xf68 */ + } W51; + } Diff4; + PVOID WinSockData; /**< 0x1738 / 0xf6c */ + uint32_t GdiBatchCount; /**< 0x1740 / 0xf70 */ + union + { + union + { + PROCESSOR_NUMBER CurrentIdealProcessor; /**< 0x1744 / 0xf74 - W7+ */ + uint32_t IdealProcessorValue; /**< 0x1744 / 0xf74 - W7+ */ + struct + { + uint8_t ReservedPad1; /**< 0x1744 / 0xf74 - Called SpareBool0 in W6 */ + uint8_t ReservedPad2; /**< 0x1745 / 0xf75 - Called SpareBool0 in W6 */ + uint8_t ReservedPad3; /**< 0x1746 / 0xf76 - Called SpareBool0 in W6 */ + uint8_t IdealProcessor; /**< 0x1747 / 0xf77 */ + }; + } W6, W7, W8, W80, W81; + struct + { + BOOLEAN InDbgPrint; /**< 0x1744 / 0xf74 */ + BOOLEAN FreeStackOnTermination; /**< 0x1745 / 0xf75 */ + BOOLEAN HasFiberData; /**< 0x1746 / 0xf76 */ + uint8_t IdealProcessor; /**< 0x1747 / 0xf77 */ + } W51, W52; + } Diff5; + uint32_t GuaranteedStackBytes; /**< 0x1748 / 0xf78 */ +#if ARCH_BITS == 64 + uint32_t Padding5; /**< 0x174c / NA */ +#endif + PVOID ReservedForPerf; /**< 0x1750 / 0xf7c */ + PVOID ReservedForOle; /**< 0x1758 / 0xf80 */ + uint32_t WaitingOnLoaderLock; /**< 0x1760 / 0xf84 */ +#if ARCH_BITS == 64 + uint32_t Padding6; /**< 0x1764 / NA */ +#endif + union /**< 0x1770 / 0xf8c */ + { + struct + { + PVOID SavedPriorityState; /**< 0x1768 / 0xf88 */ + SIZE_T ReservedForCodeCoverage; /**< 0x1770 / 0xf8c */ + PVOID ThreadPoolData; /**< 0x1778 / 0xf90 */ + } W8, W80, W81; + struct + { + PVOID SavedPriorityState; /**< 0x1768 / 0xf88 */ + SIZE_T SoftPatchPtr1; /**< 0x1770 / 0xf8c */ + PVOID ThreadPoolData; /**< 0x1778 / 0xf90 */ + } W6, W7; + struct + { + PVOID SparePointer1; /**< 0x1768 / 0xf88 */ + SIZE_T SoftPatchPtr1; /**< 0x1770 / 0xf8c */ + PVOID SoftPatchPtr2; /**< 0x1778 / 0xf90 */ + } W52; +#if ARCH_BITS == 32 + struct _Wx86ThreadState + { + PVOID CallBx86Eip; /**< NA / 0xf88 */ + PVOID DeallocationCpu; /**< NA / 0xf8c */ + BOOLEAN UseKnownWx86Dll; /**< NA / 0xf90 */ + int8_t OleStubInvoked; /**< NA / 0xf91 */ + } W51; +#endif + } Diff6; + PVOID TlsExpansionSlots; /**< 0x1780 / 0xf94 */ +#if ARCH_BITS == 64 + PVOID DallocationBStore; /**< 0x1788 / NA */ + PVOID BStoreLimit; /**< 0x1790 / NA */ +#endif + union + { + struct + { + uint32_t MuiGeneration; /**< 0x1798 / 0xf98 */ + } W7, W8, W80, W81; + struct + { + uint32_t ImpersonationLocale; + } W6; + } Diff7; + uint32_t IsImpersonating; /**< 0x179c / 0xf9c */ + PVOID NlsCache; /**< 0x17a0 / 0xfa0 */ + PVOID pShimData; /**< 0x17a8 / 0xfa4 */ + union /**< 0x17b0 / 0xfa8 */ + { + struct + { + uint16_t HeapVirtualAffinity; /**< 0x17b0 / 0xfa8 */ + uint16_t LowFragHeapDataSlot; /**< 0x17b2 / 0xfaa */ + } W8, W80, W81; + struct + { + uint32_t HeapVirtualAffinity; /**< 0x17b0 / 0xfa8 */ + } W7; + } Diff8; +#if ARCH_BITS == 64 + uint32_t Padding7; /**< 0x17b4 / NA */ +#endif + HANDLE CurrentTransactionHandle; /**< 0x17b8 / 0xfac */ + struct _TEB_ACTIVE_FRAME *ActiveFrame; /**< 0x17c0 / 0xfb0 */ + /* End of TEB in W51 (Windows XP)! */ + PVOID FlsData; /**< 0x17c8 / 0xfb4 */ + union + { + struct + { + PVOID PreferredLanguages; /**< 0x17d0 / 0xfb8 */ + } W6, W7, W8, W80, W81; + struct + { + BOOLEAN SafeThunkCall; /**< 0x17d0 / 0xfb8 */ + uint8_t BooleanSpare[3]; /**< 0x17d1 / 0xfb9 */ + /* End of TEB in W52 (Windows server 2003)! */ + } W52; + } Diff9; + PVOID UserPrefLanguages; /**< 0x17d8 / 0xfbc */ + PVOID MergedPrefLanguages; /**< 0x17e0 / 0xfc0 */ + uint32_t MuiImpersonation; /**< 0x17e8 / 0xfc4 */ + union + { + uint16_t CrossTebFlags; /**< 0x17ec / 0xfc8 */ + struct + { + uint16_t SpareCrossTebBits : 16; /**< 0x17ec / 0xfc8 : Pos 0, 16 Bits */ + }; + }; + union + { + uint16_t SameTebFlags; /**< 0x17ee / 0xfca */ + struct + { + uint16_t SafeThunkCall : 1; /**< 0x17ee / 0xfca : Pos 0, 1 Bit */ + uint16_t InDebugPrint : 1; /**< 0x17ee / 0xfca : Pos 1, 1 Bit */ + uint16_t HasFiberData : 1; /**< 0x17ee / 0xfca : Pos 2, 1 Bit */ + uint16_t SkipThreadAttach : 1; /**< 0x17ee / 0xfca : Pos 3, 1 Bit */ + uint16_t WerInShipAssertCode : 1; /**< 0x17ee / 0xfca : Pos 4, 1 Bit */ + uint16_t RanProcessInit : 1; /**< 0x17ee / 0xfca : Pos 5, 1 Bit */ + uint16_t ClonedThread : 1; /**< 0x17ee / 0xfca : Pos 6, 1 Bit */ + uint16_t SuppressDebugMsg : 1; /**< 0x17ee / 0xfca : Pos 7, 1 Bit */ + } Common; + struct + { + uint16_t SafeThunkCall : 1; /**< 0x17ee / 0xfca : Pos 0, 1 Bit */ + uint16_t InDebugPrint : 1; /**< 0x17ee / 0xfca : Pos 1, 1 Bit */ + uint16_t HasFiberData : 1; /**< 0x17ee / 0xfca : Pos 2, 1 Bit */ + uint16_t SkipThreadAttach : 1; /**< 0x17ee / 0xfca : Pos 3, 1 Bit */ + uint16_t WerInShipAssertCode : 1; /**< 0x17ee / 0xfca : Pos 4, 1 Bit */ + uint16_t RanProcessInit : 1; /**< 0x17ee / 0xfca : Pos 5, 1 Bit */ + uint16_t ClonedThread : 1; /**< 0x17ee / 0xfca : Pos 6, 1 Bit */ + uint16_t SuppressDebugMsg : 1; /**< 0x17ee / 0xfca : Pos 7, 1 Bit */ + uint16_t DisableUserStackWalk : 1; /**< 0x17ee / 0xfca : Pos 8, 1 Bit */ + uint16_t RtlExceptionAttached : 1; /**< 0x17ee / 0xfca : Pos 9, 1 Bit */ + uint16_t InitialThread : 1; /**< 0x17ee / 0xfca : Pos 10, 1 Bit */ + uint16_t SessionAware : 1; /**< 0x17ee / 0xfca : Pos 11, 1 Bit - New Since W7. */ + uint16_t SpareSameTebBits : 4; /**< 0x17ee / 0xfca : Pos 12, 4 Bits */ + } W8, W80, W81; + struct + { + uint16_t SafeThunkCall : 1; /**< 0x17ee / 0xfca : Pos 0, 1 Bit */ + uint16_t InDebugPrint : 1; /**< 0x17ee / 0xfca : Pos 1, 1 Bit */ + uint16_t HasFiberData : 1; /**< 0x17ee / 0xfca : Pos 2, 1 Bit */ + uint16_t SkipThreadAttach : 1; /**< 0x17ee / 0xfca : Pos 3, 1 Bit */ + uint16_t WerInShipAssertCode : 1; /**< 0x17ee / 0xfca : Pos 4, 1 Bit */ + uint16_t RanProcessInit : 1; /**< 0x17ee / 0xfca : Pos 5, 1 Bit */ + uint16_t ClonedThread : 1; /**< 0x17ee / 0xfca : Pos 6, 1 Bit */ + uint16_t SuppressDebugMsg : 1; /**< 0x17ee / 0xfca : Pos 7, 1 Bit */ + uint16_t DisableUserStackWalk : 1; /**< 0x17ee / 0xfca : Pos 8, 1 Bit */ + uint16_t RtlExceptionAttached : 1; /**< 0x17ee / 0xfca : Pos 9, 1 Bit */ + uint16_t InitialThread : 1; /**< 0x17ee / 0xfca : Pos 10, 1 Bit */ + uint16_t SpareSameTebBits : 5; /**< 0x17ee / 0xfca : Pos 12, 4 Bits */ + } W7; + struct + { + uint16_t DbgSafeThunkCall : 1; /**< 0x17ee / 0xfca : Pos 0, 1 Bit */ + uint16_t DbgInDebugPrint : 1; /**< 0x17ee / 0xfca : Pos 1, 1 Bit */ + uint16_t DbgHasFiberData : 1; /**< 0x17ee / 0xfca : Pos 2, 1 Bit */ + uint16_t DbgSkipThreadAttach : 1; /**< 0x17ee / 0xfca : Pos 3, 1 Bit */ + uint16_t DbgWerInShipAssertCode : 1; /**< 0x17ee / 0xfca : Pos 4, 1 Bit */ + uint16_t DbgRanProcessInit : 1; /**< 0x17ee / 0xfca : Pos 5, 1 Bit */ + uint16_t DbgClonedThread : 1; /**< 0x17ee / 0xfca : Pos 6, 1 Bit */ + uint16_t DbgSuppressDebugMsg : 1; /**< 0x17ee / 0xfca : Pos 7, 1 Bit */ + uint16_t SpareSameTebBits : 8; /**< 0x17ee / 0xfca : Pos 8, 8 Bits */ + } W6; + } Diff10; + PVOID TxnScopeEnterCallback; /**< 0x17f0 / 0xfcc */ + PVOID TxnScopeExitCallback; /**< 0x17f8 / 0xfd0 */ + PVOID TxnScopeContext; /**< 0x1800 / 0xfd4 */ + uint32_t LockCount; /**< 0x1808 / 0xfd8 */ + union + { + struct + { + uint32_t SpareUlong0; /**< 0x180c / 0xfdc */ + } W7, W8, W80, W81; + struct + { + uint32_t ProcessRundown; + } W6; + } Diff11; + union + { + struct + { + PVOID ResourceRetValue; /**< 0x1810 / 0xfe0 */ + /* End of TEB in W7 (windows 7)! */ + PVOID ReservedForWdf; /**< 0x1818 / 0xfe4 - New Since W7. */ + /* End of TEB in W8 (windows 8.0 & 8.1)! */ + PVOID ReservedForCrt; /**< 0x1820 / 0xfe8 - New Since W10. */ + RTUUID EffectiveContainerId; /**< 0x1828 / 0xfec - New Since W10. */ + /* End of TEB in W10 14393! */ + } W8, W80, W81, W10; + struct + { + PVOID ResourceRetValue; /**< 0x1810 / 0xfe0 */ + } W7; + struct + { + uint64_t LastSwitchTime; /**< 0x1810 / 0xfe0 */ + uint64_t TotalSwitchOutTime; /**< 0x1818 / 0xfe8 */ + LARGE_INTEGER WaitReasonBitMap; /**< 0x1820 / 0xff0 */ + /* End of TEB in W6 (windows Vista)! */ + } W6; + } Diff12; +} TEB_COMMON; +typedef TEB_COMMON *PTEB_COMMON; +AssertCompileMemberOffset(TEB_COMMON, ExceptionCode, ARCH_BITS == 64 ? 0x2c0 : 0x1a4); +AssertCompileMemberOffset(TEB_COMMON, LastStatusValue, ARCH_BITS == 64 ? 0x1250 : 0xbf4); +AssertCompileMemberOffset(TEB_COMMON, DeallocationStack, ARCH_BITS == 64 ? 0x1478 : 0xe0c); +AssertCompileMemberOffset(TEB_COMMON, ReservedForNtRpc, ARCH_BITS == 64 ? 0x1698 : 0xf1c); +AssertCompileMemberOffset(TEB_COMMON, Instrumentation, ARCH_BITS == 64 ? 0x16b8 : 0xf2c); +AssertCompileMemberOffset(TEB_COMMON, Diff2, ARCH_BITS == 64 ? 0x1710 : 0xf50); +AssertCompileMemberOffset(TEB_COMMON, Diff3, ARCH_BITS == 64 ? 0x1728 : 0xf64); +AssertCompileMemberOffset(TEB_COMMON, Diff4, ARCH_BITS == 64 ? 0x1730 : 0xf68); +AssertCompileMemberOffset(TEB_COMMON, WinSockData, ARCH_BITS == 64 ? 0x1738 : 0xf6c); +AssertCompileMemberOffset(TEB_COMMON, GuaranteedStackBytes, ARCH_BITS == 64 ? 0x1748 : 0xf78); +AssertCompileMemberOffset(TEB_COMMON, MuiImpersonation, ARCH_BITS == 64 ? 0x17e8 : 0xfc4); +AssertCompileMemberOffset(TEB_COMMON, LockCount, ARCH_BITS == 64 ? 0x1808 : 0xfd8); +AssertCompileSize(TEB_COMMON, ARCH_BITS == 64 ? 0x1838 : 0x1000); + + +/** The size of the windows 8.1 PEB structure. */ +#define TEB_SIZE_W10 ( RT_UOFFSETOF(TEB_COMMON, Diff12.W10.EffectiveContainerId) + sizeof(RTUUID) ) +/** The size of the windows 8.1 PEB structure. */ +#define TEB_SIZE_W81 ( RT_UOFFSETOF(TEB_COMMON, Diff12.W8.ReservedForWdf) + sizeof(PVOID) ) +/** The size of the windows 8.0 PEB structure. */ +#define TEB_SIZE_W80 ( RT_UOFFSETOF(TEB_COMMON, Diff12.W8.ReservedForWdf) + sizeof(PVOID) ) +/** The size of the windows 7 PEB structure. */ +#define TEB_SIZE_W7 RT_UOFFSETOF(TEB_COMMON, Diff12.W8.ReservedForWdf) +/** The size of the windows vista PEB structure. */ +#define TEB_SIZE_W6 ( RT_UOFFSETOF(TEB_COMMON, Diff12.W6.WaitReasonBitMap) + sizeof(LARGE_INTEGER) ) +/** The size of the windows server 2003 PEB structure. */ +#define TEB_SIZE_W52 RT_ALIGN_Z(RT_UOFFSETOF(TEB_COMMON, Diff9.W52.BooleanSpare), sizeof(PVOID)) +/** The size of the windows XP PEB structure. */ +#define TEB_SIZE_W51 RT_UOFFSETOF(TEB_COMMON, FlsData) + + + +#define _PEB _PEB_COMMON +typedef PEB_COMMON PEB; +typedef PPEB_COMMON PPEB; + +#define _TEB _TEB_COMMON +typedef TEB_COMMON TEB; +typedef PTEB_COMMON PTEB; + +#if !defined(NtCurrentTeb) && !defined(IPRT_NT_HAVE_CURRENT_TEB_MACRO) +# ifdef RT_ARCH_X86 +DECL_FORCE_INLINE(PTEB) RTNtCurrentTeb(void) { return (PTEB)__readfsdword(RT_UOFFSETOF(TEB_COMMON, NtTib.Self)); } +DECL_FORCE_INLINE(PPEB) RTNtCurrentPeb(void) { return (PPEB)__readfsdword(RT_UOFFSETOF(TEB_COMMON, ProcessEnvironmentBlock)); } +DECL_FORCE_INLINE(uint32_t) RTNtCurrentThreadId(void) { return __readfsdword(RT_UOFFSETOF(TEB_COMMON, ClientId.UniqueThread)); } +DECL_FORCE_INLINE(NTSTATUS) RTNtLastStatusValue(void) { return (NTSTATUS)__readfsdword(RT_UOFFSETOF(TEB_COMMON, LastStatusValue)); } +DECL_FORCE_INLINE(uint32_t) RTNtLastErrorValue(void) { return __readfsdword(RT_UOFFSETOF(TEB_COMMON, LastErrorValue)); } +# elif defined(RT_ARCH_AMD64) +DECL_FORCE_INLINE(PTEB) RTNtCurrentTeb(void) { return (PTEB)__readgsqword(RT_UOFFSETOF(TEB_COMMON, NtTib.Self)); } +DECL_FORCE_INLINE(PPEB) RTNtCurrentPeb(void) { return (PPEB)__readgsqword(RT_UOFFSETOF(TEB_COMMON, ProcessEnvironmentBlock)); } +DECL_FORCE_INLINE(uint32_t) RTNtCurrentThreadId(void) { return __readgsdword(RT_UOFFSETOF(TEB_COMMON, ClientId.UniqueThread)); } +DECL_FORCE_INLINE(NTSTATUS) RTNtLastStatusValue(void) { return (NTSTATUS)__readgsdword(RT_UOFFSETOF(TEB_COMMON, LastStatusValue)); } +DECL_FORCE_INLINE(uint32_t) RTNtLastErrorValue(void) { return __readgsdword(RT_UOFFSETOF(TEB_COMMON, LastErrorValue)); } +# else +# error "Port me" +# endif +#else +# define RTNtCurrentTeb() ((PTEB)NtCurrentTeb()) +# define RTNtCurrentPeb() (RTNtCurrentTeb()->ProcessEnvironmentBlock) +# define RTNtCurrentThreadId() ((uint32_t)(uintptr_t)RTNtCurrentTeb()->ClientId.UniqueThread) +# define RTNtLastStatusValue() (RTNtCurrentTeb()->LastStatusValue) +# define RTNtLastErrorValue() (RTNtCurrentTeb()->LastErrorValue) +#endif +#define NtCurrentPeb() RTNtCurrentPeb() + +#ifdef IN_RING3 +RT_DECL_NTAPI(void) RtlAcquirePebLock(void); +RT_DECL_NTAPI(void) RtlReleasePebLock(void); +#endif + +/** @} */ + + +#ifdef IPRT_NT_USE_WINTERNL +RT_DECL_NTAPI(NTSTATUS) NtCreateSection(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PLARGE_INTEGER, ULONG, ULONG, HANDLE); +typedef enum _SECTION_INHERIT +{ + ViewShare = 1, + ViewUnmap +} SECTION_INHERIT; +#endif +RT_DECL_NTAPI(NTSTATUS) NtMapViewOfSection(HANDLE, HANDLE, PVOID *, ULONG, SIZE_T, PLARGE_INTEGER, PSIZE_T, SECTION_INHERIT, + ULONG, ULONG); +RT_DECL_NTAPI(NTSTATUS) NtFlushVirtualMemory(HANDLE, PVOID *, PSIZE_T, PIO_STATUS_BLOCK); +RT_DECL_NTAPI(NTSTATUS) NtUnmapViewOfSection(HANDLE, PVOID); + +#ifdef IPRT_NT_USE_WINTERNL +RT_DECL_NTAPI(NTSTATUS) NtOpenProcess(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PCLIENT_ID); +RT_DECL_NTAPI(NTSTATUS) ZwOpenProcess(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PCLIENT_ID); +#endif +RT_DECL_NTAPI(NTSTATUS) NtOpenThread(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PCLIENT_ID); +RT_DECL_NTAPI(NTSTATUS) ZwOpenThread(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PCLIENT_ID); +RT_DECL_NTAPI(NTSTATUS) NtAlertThread(HANDLE hThread); +#ifdef IPRT_NT_USE_WINTERNL +RT_DECL_NTAPI(NTSTATUS) ZwAlertThread(HANDLE hThread); +#endif +RT_DECL_NTAPI(NTSTATUS) NtTestAlert(void); + +#ifdef IPRT_NT_USE_WINTERNL +RT_DECL_NTAPI(NTSTATUS) NtOpenProcessToken(HANDLE, ACCESS_MASK, PHANDLE); +RT_DECL_NTAPI(NTSTATUS) NtOpenThreadToken(HANDLE, ACCESS_MASK, BOOLEAN, PHANDLE); +#endif +RT_DECL_NTAPI(NTSTATUS) ZwOpenProcessToken(HANDLE, ACCESS_MASK, PHANDLE); +RT_DECL_NTAPI(NTSTATUS) ZwOpenThreadToken(HANDLE, ACCESS_MASK, BOOLEAN, PHANDLE); + +#ifdef IPRT_NT_USE_WINTERNL +typedef struct _FILE_FS_VOLUME_INFORMATION +{ + LARGE_INTEGER VolumeCreationTime; + ULONG VolumeSerialNumber; + ULONG VolumeLabelLength; + BOOLEAN SupportsObjects; + WCHAR VolumeLabel[1]; +} FILE_FS_VOLUME_INFORMATION; +typedef FILE_FS_VOLUME_INFORMATION *PFILE_FS_VOLUME_INFORMATION; +typedef struct _FILE_FS_LABEL_INFORMATION +{ + ULONG VolumeLabelLength; + WCHAR VolumeLabel[1]; +} FILE_FS_LABEL_INFORMATION; +typedef FILE_FS_LABEL_INFORMATION *PFILE_FS_LABEL_INFORMATION; +typedef struct _FILE_FS_SIZE_INFORMATION +{ + LARGE_INTEGER TotalAllocationUnits; + LARGE_INTEGER AvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_SIZE_INFORMATION; +typedef FILE_FS_SIZE_INFORMATION *PFILE_FS_SIZE_INFORMATION; +typedef struct _FILE_FS_DEVICE_INFORMATION +{ + DEVICE_TYPE DeviceType; + ULONG Characteristics; +} FILE_FS_DEVICE_INFORMATION; +typedef FILE_FS_DEVICE_INFORMATION *PFILE_FS_DEVICE_INFORMATION; +typedef struct _FILE_FS_ATTRIBUTE_INFORMATION +{ + ULONG FileSystemAttributes; + LONG MaximumComponentNameLength; + ULONG FileSystemNameLength; + WCHAR FileSystemName[1]; +} FILE_FS_ATTRIBUTE_INFORMATION; +typedef FILE_FS_ATTRIBUTE_INFORMATION *PFILE_FS_ATTRIBUTE_INFORMATION; +typedef struct _FILE_FS_CONTROL_INFORMATION +{ + LARGE_INTEGER FreeSpaceStartFiltering; + LARGE_INTEGER FreeSpaceThreshold; + LARGE_INTEGER FreeSpaceStopFiltering; + LARGE_INTEGER DefaultQuotaThreshold; + LARGE_INTEGER DefaultQuotaLimit; + ULONG FileSystemControlFlags; +} FILE_FS_CONTROL_INFORMATION; +typedef FILE_FS_CONTROL_INFORMATION *PFILE_FS_CONTROL_INFORMATION; +typedef struct _FILE_FS_FULL_SIZE_INFORMATION +{ + LARGE_INTEGER TotalAllocationUnits; + LARGE_INTEGER CallerAvailableAllocationUnits; + LARGE_INTEGER ActualAvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_FULL_SIZE_INFORMATION; +typedef FILE_FS_FULL_SIZE_INFORMATION *PFILE_FS_FULL_SIZE_INFORMATION; +typedef struct _FILE_FS_OBJECTID_INFORMATION +{ + UCHAR ObjectId[16]; + UCHAR ExtendedInfo[48]; +} FILE_FS_OBJECTID_INFORMATION; +typedef FILE_FS_OBJECTID_INFORMATION *PFILE_FS_OBJECTID_INFORMATION; +typedef struct _FILE_FS_DRIVER_PATH_INFORMATION +{ + BOOLEAN DriverInPath; + ULONG DriverNameLength; + WCHAR DriverName[1]; +} FILE_FS_DRIVER_PATH_INFORMATION; +typedef FILE_FS_DRIVER_PATH_INFORMATION *PFILE_FS_DRIVER_PATH_INFORMATION; +typedef struct _FILE_FS_VOLUME_FLAGS_INFORMATION +{ + ULONG Flags; +} FILE_FS_VOLUME_FLAGS_INFORMATION; +typedef FILE_FS_VOLUME_FLAGS_INFORMATION *PFILE_FS_VOLUME_FLAGS_INFORMATION; +#endif +#if !defined(SSINFO_OFFSET_UNKNOWN) || defined(IPRT_NT_USE_WINTERNL) +typedef struct _FILE_FS_SECTOR_SIZE_INFORMATION +{ + ULONG LogicalBytesPerSector; + ULONG PhysicalBytesPerSectorForAtomicity; + ULONG PhysicalBytesPerSectorForPerformance; + ULONG FileSystemEffectivePhysicalBytesPerSectorForAtomicity; + ULONG Flags; + ULONG ByteOffsetForSectorAlignment; + ULONG ByteOffsetForPartitionAlignment; +} FILE_FS_SECTOR_SIZE_INFORMATION; +typedef FILE_FS_SECTOR_SIZE_INFORMATION *PFILE_FS_SECTOR_SIZE_INFORMATION; +# ifndef SSINFO_OFFSET_UNKNOWN +# define SSINFO_OFFSET_UNKNOWN 0xffffffffUL +# define SSINFO_FLAGS_ALIGNED_DEVICE 1UL +# define SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE 2UL +# define SSINFO_FLAGS_NO_SEEK_PENALTY 4UL +# define SSINFO_FLAGS_TRIM_ENABLED 8UL +# define SSINFO_FLAGS_BYTE_ADDRESSABLE 16UL +# endif +#endif +#ifdef IPRT_NT_USE_WINTERNL +typedef struct _FILE_FS_DATA_COPY_INFORMATION +{ + ULONG NumberOfCopies; +} FILE_FS_DATA_COPY_INFORMATION; +typedef FILE_FS_DATA_COPY_INFORMATION *PFILE_FS_DATA_COPY_INFORMATION; +typedef struct _FILE_FS_METADATA_SIZE_INFORMATION +{ + LARGE_INTEGER TotalMetadataAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_METADATA_SIZE_INFORMATION; +typedef FILE_FS_METADATA_SIZE_INFORMATION *PFILE_FS_METADATA_SIZE_INFORMATION; +typedef struct _FILE_FS_FULL_SIZE_INFORMATION_EX +{ + ULONGLONG ActualTotalAllocationUnits; + ULONGLONG ActualAvailableAllocationUnits; + ULONGLONG ActualPoolUnavailableAllocationUnits; + ULONGLONG CallerTotalAllocationUnits; + ULONGLONG CallerAvailableAllocationUnits; + ULONGLONG CallerPoolUnavailableAllocationUnits; + ULONGLONG UsedAllocationUnits; + ULONGLONG TotalReservedAllocationUnits; + ULONGLONG VolumeStorageReserveAllocationUnits; + ULONGLONG AvailableCommittedAllocationUnits; + ULONGLONG PoolAvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_FULL_SIZE_INFORMATION_EX; +typedef FILE_FS_FULL_SIZE_INFORMATION_EX *PFILE_FS_FULL_SIZE_INFORMATION_EX; +#endif /* IPRT_NT_USE_WINTERNL */ + +typedef enum _FSINFOCLASS +{ + FileFsVolumeInformation = 1, + FileFsLabelInformation, + FileFsSizeInformation, /**< FILE_FS_SIZE_INFORMATION */ + FileFsDeviceInformation, + FileFsAttributeInformation, + FileFsControlInformation, + FileFsFullSizeInformation, + FileFsObjectIdInformation, + FileFsDriverPathInformation, + FileFsVolumeFlagsInformation, + FileFsSectorSizeInformation, + FileFsDataCopyInformation, + FileFsMetadataSizeInformation, + FileFsFullSizeInformationEx, + FileFsMaximumInformation +} FS_INFORMATION_CLASS; +typedef FS_INFORMATION_CLASS *PFS_INFORMATION_CLASS; +RT_DECL_NTAPI(NTSTATUS) NtQueryVolumeInformationFile(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FS_INFORMATION_CLASS); +RT_DECL_NTAPI(NTSTATUS) NtSetVolumeInformationFile(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FS_INFORMATION_CLASS); + +#ifdef IPRT_NT_USE_WINTERNL +typedef struct _FILE_DIRECTORY_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_DIRECTORY_INFORMATION; +typedef FILE_DIRECTORY_INFORMATION *PFILE_DIRECTORY_INFORMATION; +typedef struct _FILE_FULL_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + WCHAR FileName[1]; +} FILE_FULL_DIR_INFORMATION; +typedef FILE_FULL_DIR_INFORMATION *PFILE_FULL_DIR_INFORMATION; +typedef struct _FILE_BOTH_DIR_INFORMATION +{ + ULONG NextEntryOffset; /**< 0x00: */ + ULONG FileIndex; /**< 0x04: */ + LARGE_INTEGER CreationTime; /**< 0x08: */ + LARGE_INTEGER LastAccessTime; /**< 0x10: */ + LARGE_INTEGER LastWriteTime; /**< 0x18: */ + LARGE_INTEGER ChangeTime; /**< 0x20: */ + LARGE_INTEGER EndOfFile; /**< 0x28: */ + LARGE_INTEGER AllocationSize; /**< 0x30: */ + ULONG FileAttributes; /**< 0x38: */ + ULONG FileNameLength; /**< 0x3c: */ + ULONG EaSize; /**< 0x40: */ + CCHAR ShortNameLength; /**< 0x44: */ + WCHAR ShortName[12]; /**< 0x46: */ + WCHAR FileName[1]; /**< 0x5e: */ +} FILE_BOTH_DIR_INFORMATION; +typedef FILE_BOTH_DIR_INFORMATION *PFILE_BOTH_DIR_INFORMATION; +typedef struct _FILE_BASIC_INFORMATION +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + ULONG FileAttributes; +} FILE_BASIC_INFORMATION; +typedef FILE_BASIC_INFORMATION *PFILE_BASIC_INFORMATION; +typedef struct _FILE_STANDARD_INFORMATION +{ + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_INFORMATION; +typedef FILE_STANDARD_INFORMATION *PFILE_STANDARD_INFORMATION; +typedef struct _FILE_NAME_INFORMATION +{ + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAME_INFORMATION; +typedef FILE_NAME_INFORMATION *PFILE_NAME_INFORMATION; +typedef FILE_NAME_INFORMATION FILE_NETWORK_PHYSICAL_NAME_INFORMATION; +typedef FILE_NETWORK_PHYSICAL_NAME_INFORMATION *PFILE_NETWORK_PHYSICAL_NAME_INFORMATION; +typedef struct _FILE_INTERNAL_INFORMATION +{ + LARGE_INTEGER IndexNumber; +} FILE_INTERNAL_INFORMATION; +typedef FILE_INTERNAL_INFORMATION *PFILE_INTERNAL_INFORMATION; +typedef struct _FILE_EA_INFORMATION +{ + ULONG EaSize; +} FILE_EA_INFORMATION; +typedef FILE_EA_INFORMATION *PFILE_EA_INFORMATION; +typedef struct _FILE_ACCESS_INFORMATION +{ + ACCESS_MASK AccessFlags; +} FILE_ACCESS_INFORMATION; +typedef FILE_ACCESS_INFORMATION *PFILE_ACCESS_INFORMATION; +typedef struct _FILE_RENAME_INFORMATION +{ + union + { + BOOLEAN ReplaceIfExists; + ULONG Flags; + }; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_RENAME_INFORMATION; +typedef FILE_RENAME_INFORMATION *PFILE_RENAME_INFORMATION; +typedef struct _FILE_LINK_INFORMATION +{ + union + { + BOOLEAN ReplaceIfExists; + ULONG Flags; + }; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_LINK_INFORMATION; +typedef FILE_LINK_INFORMATION *PFILE_LINK_INFORMATION; +typedef struct _FILE_NAMES_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAMES_INFORMATION; +typedef FILE_NAMES_INFORMATION *PFILE_NAMES_INFORMATION; +typedef struct _FILE_DISPOSITION_INFORMATION +{ + BOOLEAN DeleteFile; +} FILE_DISPOSITION_INFORMATION; +typedef FILE_DISPOSITION_INFORMATION *PFILE_DISPOSITION_INFORMATION; +typedef struct _FILE_POSITION_INFORMATION +{ + LARGE_INTEGER CurrentByteOffset; +} FILE_POSITION_INFORMATION; +typedef FILE_POSITION_INFORMATION *PFILE_POSITION_INFORMATION; +typedef struct _FILE_FULL_EA_INFORMATION +{ + ULONG NextEntryOffset; + UCHAR Flags; + UCHAR EaNameLength; + USHORT EaValueLength; + CHAR EaName[1]; +} FILE_FULL_EA_INFORMATION; +typedef FILE_FULL_EA_INFORMATION *PFILE_FULL_EA_INFORMATION; +typedef struct _FILE_MODE_INFORMATION +{ + ULONG Mode; +} FILE_MODE_INFORMATION; +typedef FILE_MODE_INFORMATION *PFILE_MODE_INFORMATION; +typedef struct _FILE_ALIGNMENT_INFORMATION +{ + ULONG AlignmentRequirement; +} FILE_ALIGNMENT_INFORMATION; +typedef FILE_ALIGNMENT_INFORMATION *PFILE_ALIGNMENT_INFORMATION; +typedef struct _FILE_ALL_INFORMATION +{ + FILE_BASIC_INFORMATION BasicInformation; + FILE_STANDARD_INFORMATION StandardInformation; + FILE_INTERNAL_INFORMATION InternalInformation; + FILE_EA_INFORMATION EaInformation; + FILE_ACCESS_INFORMATION AccessInformation; + FILE_POSITION_INFORMATION PositionInformation; + FILE_MODE_INFORMATION ModeInformation; + FILE_ALIGNMENT_INFORMATION AlignmentInformation; + FILE_NAME_INFORMATION NameInformation; +} FILE_ALL_INFORMATION; +typedef FILE_ALL_INFORMATION *PFILE_ALL_INFORMATION; +typedef struct _FILE_ALLOCATION_INFORMATION +{ + LARGE_INTEGER AllocationSize; +} FILE_ALLOCATION_INFORMATION; +typedef FILE_ALLOCATION_INFORMATION *PFILE_ALLOCATION_INFORMATION; +typedef struct _FILE_END_OF_FILE_INFORMATION +{ + LARGE_INTEGER EndOfFile; +} FILE_END_OF_FILE_INFORMATION; +typedef FILE_END_OF_FILE_INFORMATION *PFILE_END_OF_FILE_INFORMATION; +typedef struct _FILE_STREAM_INFORMATION +{ + ULONG NextEntryOffset; + ULONG StreamNameLength; + LARGE_INTEGER StreamSize; + LARGE_INTEGER StreamAllocationSize; + WCHAR StreamName[1]; +} FILE_STREAM_INFORMATION; +typedef FILE_STREAM_INFORMATION *PFILE_STREAM_INFORMATION; + +typedef struct _FILE_PIPE_INFORMATION +{ + ULONG ReadMode; + ULONG CompletionMode; +} FILE_PIPE_INFORMATION; +typedef FILE_PIPE_INFORMATION *PFILE_PIPE_INFORMATION; + +typedef struct _FILE_PIPE_LOCAL_INFORMATION +{ + ULONG NamedPipeType; + ULONG NamedPipeConfiguration; + ULONG MaximumInstances; + ULONG CurrentInstances; + ULONG InboundQuota; + ULONG ReadDataAvailable; + ULONG OutboundQuota; + ULONG WriteQuotaAvailable; + ULONG NamedPipeState; + ULONG NamedPipeEnd; +} FILE_PIPE_LOCAL_INFORMATION; +typedef FILE_PIPE_LOCAL_INFORMATION *PFILE_PIPE_LOCAL_INFORMATION; + +/** @name Pipe state (FILE_PIPE_LOCAL_INFORMATION::NamedPipeState) + * @{ */ +#if !defined(FILE_PIPE_DISCONNECTED_STATE) || defined(DOXYGEN_RUNNING) +# define FILE_PIPE_DISCONNECTED_STATE 0x00000001U +# define FILE_PIPE_LISTENING_STATE 0x00000002U +# define FILE_PIPE_CONNECTED_STATE 0x00000003U +# define FILE_PIPE_CLOSING_STATE 0x00000004U +#endif +/** @} */ + +/** @name Pipe config (FILE_PIPE_LOCAL_INFORMATION::NamedPipeConfiguration) + * @{ */ +#if !defined(FILE_PIPE_INBOUND) || defined(DOXYGEN_RUNNING) +# define FILE_PIPE_INBOUND 0x00000000U +# define FILE_PIPE_OUTBOUND 0x00000001U +# define FILE_PIPE_FULL_DUPLEX 0x00000002U +#endif +/** @} */ + +/** @name Pipe end (FILE_PIPE_LOCAL_INFORMATION::NamedPipeEnd) + * @{ */ +#if !defined(FILE_PIPE_CLIENT_END) || defined(DOXYGEN_RUNNING) +# define FILE_PIPE_CLIENT_END 0x00000000U +# define FILE_PIPE_SERVER_END 0x00000001U +#endif +/** @} */ + +typedef struct _FILE_PIPE_REMOTE_INFORMATION +{ + LARGE_INTEGER CollectDataTime; + ULONG MaximumCollectionCount; +} FILE_PIPE_REMOTE_INFORMATION; +typedef FILE_PIPE_REMOTE_INFORMATION *PFILE_PIPE_REMOTE_INFORMATION; +typedef struct _FILE_MAILSLOT_QUERY_INFORMATION +{ + ULONG MaximumMessageSize; + ULONG MailslotQuota; + ULONG NextMessageSize; + ULONG MessagesAvailable; + LARGE_INTEGER ReadTimeout; +} FILE_MAILSLOT_QUERY_INFORMATION; +typedef FILE_MAILSLOT_QUERY_INFORMATION *PFILE_MAILSLOT_QUERY_INFORMATION; +typedef struct _FILE_MAILSLOT_SET_INFORMATION +{ + PLARGE_INTEGER ReadTimeout; +} FILE_MAILSLOT_SET_INFORMATION; +typedef FILE_MAILSLOT_SET_INFORMATION *PFILE_MAILSLOT_SET_INFORMATION; +typedef struct _FILE_COMPRESSION_INFORMATION +{ + LARGE_INTEGER CompressedFileSize; + USHORT CompressionFormat; + UCHAR CompressionUnitShift; + UCHAR ChunkShift; + UCHAR ClusterShift; + UCHAR Reserved[3]; +} FILE_COMPRESSION_INFORMATION; +typedef FILE_COMPRESSION_INFORMATION *PFILE_COMPRESSION_INFORMATION; +typedef struct _FILE_OBJECTID_INFORMATION +{ + LONGLONG FileReference; + UCHAR ObjectId[16]; + union + { + struct + { + UCHAR BirthVolumeId[16]; + UCHAR BirthObjectId[16]; + UCHAR DomainId[16]; + }; + UCHAR ExtendedInfo[48]; + }; +} FILE_OBJECTID_INFORMATION; +typedef FILE_OBJECTID_INFORMATION *PFILE_OBJECTID_INFORMATION; +typedef struct _FILE_COMPLETION_INFORMATION +{ + HANDLE Port; + PVOID Key; +} FILE_COMPLETION_INFORMATION; +typedef FILE_COMPLETION_INFORMATION *PFILE_COMPLETION_INFORMATION; +typedef struct _FILE_MOVE_CLUSTER_INFORMATION +{ + ULONG ClusterCount; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_MOVE_CLUSTER_INFORMATION; +typedef FILE_MOVE_CLUSTER_INFORMATION *PFILE_MOVE_CLUSTER_INFORMATION; +typedef struct _FILE_QUOTA_INFORMATION +{ + ULONG NextEntryOffset; + ULONG SidLength; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER QuotaUsed; + LARGE_INTEGER QuotaThreshold; + LARGE_INTEGER QuotaLimit; + SID Sid; +} FILE_QUOTA_INFORMATION; +typedef FILE_QUOTA_INFORMATION *PFILE_QUOTA_INFORMATION; +typedef struct _FILE_REPARSE_POINT_INFORMATION +{ + LONGLONG FileReference; + ULONG Tag; +} FILE_REPARSE_POINT_INFORMATION; +typedef FILE_REPARSE_POINT_INFORMATION *PFILE_REPARSE_POINT_INFORMATION; +typedef struct _FILE_NETWORK_OPEN_INFORMATION +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; +} FILE_NETWORK_OPEN_INFORMATION; +typedef FILE_NETWORK_OPEN_INFORMATION *PFILE_NETWORK_OPEN_INFORMATION; +typedef struct _FILE_ATTRIBUTE_TAG_INFORMATION +{ + ULONG FileAttributes; + ULONG ReparseTag; +} FILE_ATTRIBUTE_TAG_INFORMATION; +typedef FILE_ATTRIBUTE_TAG_INFORMATION *PFILE_ATTRIBUTE_TAG_INFORMATION; +typedef struct _FILE_TRACKING_INFORMATION +{ + HANDLE DestinationFile; + ULONG ObjectInformationLength; + CHAR ObjectInformation[1]; +} FILE_TRACKING_INFORMATION; +typedef FILE_TRACKING_INFORMATION *PFILE_TRACKING_INFORMATION; +typedef struct _FILE_ID_BOTH_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} FILE_ID_BOTH_DIR_INFORMATION; +typedef FILE_ID_BOTH_DIR_INFORMATION *PFILE_ID_BOTH_DIR_INFORMATION; +typedef struct _FILE_ID_FULL_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} FILE_ID_FULL_DIR_INFORMATION; +typedef FILE_ID_FULL_DIR_INFORMATION *PFILE_ID_FULL_DIR_INFORMATION; +typedef struct _FILE_VALID_DATA_LENGTH_INFORMATION +{ + LARGE_INTEGER ValidDataLength; +} FILE_VALID_DATA_LENGTH_INFORMATION; +typedef FILE_VALID_DATA_LENGTH_INFORMATION *PFILE_VALID_DATA_LENGTH_INFORMATION; +typedef struct _FILE_IO_COMPLETION_NOTIFICATION_INFORMATION +{ + ULONG Flags; +} FILE_IO_COMPLETION_NOTIFICATION_INFORMATION; +typedef FILE_IO_COMPLETION_NOTIFICATION_INFORMATION *PFILE_IO_COMPLETION_NOTIFICATION_INFORMATION; +typedef enum _IO_PRIORITY_HINT +{ + IoPriorityVeryLow = 0, + IoPriorityLow, + IoPriorityNormal, + IoPriorityHigh, + IoPriorityCritical, + MaxIoPriorityTypes +} IO_PRIORITY_HINT; +AssertCompileSize(IO_PRIORITY_HINT, sizeof(int)); +typedef struct _FILE_IO_PRIORITY_HINT_INFORMATION +{ + IO_PRIORITY_HINT PriorityHint; +} FILE_IO_PRIORITY_HINT_INFORMATION; +typedef FILE_IO_PRIORITY_HINT_INFORMATION *PFILE_IO_PRIORITY_HINT_INFORMATION; +typedef struct _FILE_SFIO_RESERVE_INFORMATION +{ + ULONG RequestsPerPeriod; + ULONG Period; + BOOLEAN RetryFailures; + BOOLEAN Discardable; + ULONG RequestSize; + ULONG NumOutstandingRequests; +} FILE_SFIO_RESERVE_INFORMATION; +typedef FILE_SFIO_RESERVE_INFORMATION *PFILE_SFIO_RESERVE_INFORMATION; +typedef struct _FILE_SFIO_VOLUME_INFORMATION +{ + ULONG MaximumRequestsPerPeriod; + ULONG MinimumPeriod; + ULONG MinimumTransferSize; +} FILE_SFIO_VOLUME_INFORMATION; +typedef FILE_SFIO_VOLUME_INFORMATION *PFILE_SFIO_VOLUME_INFORMATION; +typedef struct _FILE_LINK_ENTRY_INFORMATION +{ + ULONG NextEntryOffset; + LONGLONG ParentFileId; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_LINK_ENTRY_INFORMATION; +typedef FILE_LINK_ENTRY_INFORMATION *PFILE_LINK_ENTRY_INFORMATION; +typedef struct _FILE_LINKS_INFORMATION +{ + ULONG BytesNeeded; + ULONG EntriesReturned; + FILE_LINK_ENTRY_INFORMATION Entry; +} FILE_LINKS_INFORMATION; +typedef FILE_LINKS_INFORMATION *PFILE_LINKS_INFORMATION; +typedef struct _FILE_PROCESS_IDS_USING_FILE_INFORMATION +{ + ULONG NumberOfProcessIdsInList; + ULONG_PTR ProcessIdList[1]; +} FILE_PROCESS_IDS_USING_FILE_INFORMATION; +typedef FILE_PROCESS_IDS_USING_FILE_INFORMATION *PFILE_PROCESS_IDS_USING_FILE_INFORMATION; +typedef struct _FILE_ID_GLOBAL_TX_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + LARGE_INTEGER FileId; + GUID LockingTransactionId; + ULONG TxInfoFlags; + WCHAR FileName[1]; +} FILE_ID_GLOBAL_TX_DIR_INFORMATION; +typedef FILE_ID_GLOBAL_TX_DIR_INFORMATION *PFILE_ID_GLOBAL_TX_DIR_INFORMATION; +typedef struct _FILE_IS_REMOTE_DEVICE_INFORMATION +{ + BOOLEAN IsRemote; +} FILE_IS_REMOTE_DEVICE_INFORMATION; +typedef FILE_IS_REMOTE_DEVICE_INFORMATION *PFILE_IS_REMOTE_DEVICE_INFORMATION; +typedef struct _FILE_NUMA_NODE_INFORMATION +{ + USHORT NodeNumber; +} FILE_NUMA_NODE_INFORMATION; +typedef FILE_NUMA_NODE_INFORMATION *PFILE_NUMA_NODE_INFORMATION; +typedef struct _FILE_STANDARD_LINK_INFORMATION +{ + ULONG NumberOfAccessibleLinks; + ULONG TotalNumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_LINK_INFORMATION; +typedef FILE_STANDARD_LINK_INFORMATION *PFILE_STANDARD_LINK_INFORMATION; +typedef struct _FILE_REMOTE_PROTOCOL_INFORMATION +{ + USHORT StructureVersion; + USHORT StructureSize; + ULONG Protocol; + USHORT ProtocolMajorVersion; + USHORT ProtocolMinorVersion; + USHORT ProtocolRevision; + USHORT Reserved; + ULONG Flags; + struct + { + ULONG Reserved[8]; + } GenericReserved; + struct + { + ULONG Reserved[16]; + } ProtocolSpecificReserved; +} FILE_REMOTE_PROTOCOL_INFORMATION; +typedef FILE_REMOTE_PROTOCOL_INFORMATION *PFILE_REMOTE_PROTOCOL_INFORMATION; +typedef struct _FILE_VOLUME_NAME_INFORMATION +{ + ULONG DeviceNameLength; + WCHAR DeviceName[1]; +} FILE_VOLUME_NAME_INFORMATION; +typedef FILE_VOLUME_NAME_INFORMATION *PFILE_VOLUME_NAME_INFORMATION; +# ifndef FILE_INVALID_FILE_ID +typedef struct _FILE_ID_128 +{ + BYTE Identifier[16]; +} FILE_ID_128; +typedef FILE_ID_128 *PFILE_ID_128; +# endif +typedef struct _FILE_ID_EXTD_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + ULONG ReparsePointTag; + FILE_ID_128 FileId; + WCHAR FileName[1]; +} FILE_ID_EXTD_DIR_INFORMATION; +typedef FILE_ID_EXTD_DIR_INFORMATION *PFILE_ID_EXTD_DIR_INFORMATION; +typedef struct _FILE_ID_EXTD_BOTH_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + ULONG ReparsePointTag; + FILE_ID_128 FileId; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[1]; +} FILE_ID_EXTD_BOTH_DIR_INFORMATION; +typedef FILE_ID_EXTD_BOTH_DIR_INFORMATION *PFILE_ID_EXTD_BOTH_DIR_INFORMATION; +typedef struct _FILE_ID_INFORMATION +{ + ULONGLONG VolumeSerialNumber; + FILE_ID_128 FileId; +} FILE_ID_INFORMATION; +typedef FILE_ID_INFORMATION *PFILE_ID_INFORMATION; +typedef struct _FILE_LINK_ENTRY_FULL_ID_INFORMATION +{ + ULONG NextEntryOffset; + FILE_ID_128 ParentFileId; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_LINK_ENTRY_FULL_ID_INFORMATION; +typedef FILE_LINK_ENTRY_FULL_ID_INFORMATION *PFILE_LINK_ENTRY_FULL_ID_INFORMATION; +typedef struct _FILE_LINKS_FULL_ID_INFORMATION { + ULONG BytesNeeded; + ULONG EntriesReturned; + FILE_LINK_ENTRY_FULL_ID_INFORMATION Entry; +} FILE_LINKS_FULL_ID_INFORMATION; +typedef FILE_LINKS_FULL_ID_INFORMATION *PFILE_LINKS_FULL_ID_INFORMATION; +typedef struct _FILE_DISPOSITION_INFORMATION_EX +{ + ULONG Flags; +} FILE_DISPOSITION_INFORMATION_EX; +typedef FILE_DISPOSITION_INFORMATION_EX *PFILE_DISPOSITION_INFORMATION_EX; +# ifndef QUERY_STORAGE_CLASSES_FLAGS_MEASURE_WRITE +typedef struct _FILE_DESIRED_STORAGE_CLASS_INFORMATION +{ + /*FILE_STORAGE_TIER_CLASS*/ ULONG Class; + ULONG Flags; +} FILE_DESIRED_STORAGE_CLASS_INFORMATION; +typedef FILE_DESIRED_STORAGE_CLASS_INFORMATION *PFILE_DESIRED_STORAGE_CLASS_INFORMATION; +# endif +typedef struct _FILE_STAT_INFORMATION +{ + LARGE_INTEGER FileId; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; + ULONG ReparseTag; + ULONG NumberOfLinks; + ACCESS_MASK EffectiveAccess; +} FILE_STAT_INFORMATION; +typedef FILE_STAT_INFORMATION *PFILE_STAT_INFORMATION; +typedef struct _FILE_STAT_LX_INFORMATION +{ + LARGE_INTEGER FileId; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; + ULONG ReparseTag; + ULONG NumberOfLinks; + ACCESS_MASK EffectiveAccess; + ULONG LxFlags; + ULONG LxUid; + ULONG LxGid; + ULONG LxMode; + ULONG LxDeviceIdMajor; + ULONG LxDeviceIdMinor; +} FILE_STAT_LX_INFORMATION; +typedef FILE_STAT_LX_INFORMATION *PFILE_STAT_LX_INFORMATION; +typedef struct _FILE_CASE_SENSITIVE_INFORMATION +{ + ULONG Flags; +} FILE_CASE_SENSITIVE_INFORMATION; +typedef FILE_CASE_SENSITIVE_INFORMATION *PFILE_CASE_SENSITIVE_INFORMATION; + +typedef enum _FILE_INFORMATION_CLASS +{ + FileDirectoryInformation = 1, + FileFullDirectoryInformation, + FileBothDirectoryInformation, + FileBasicInformation, + FileStandardInformation, + FileInternalInformation, + FileEaInformation, + FileAccessInformation, + FileNameInformation, + FileRenameInformation, + FileLinkInformation, + FileNamesInformation, + FileDispositionInformation, + FilePositionInformation, + FileFullEaInformation, + FileModeInformation, + FileAlignmentInformation, + FileAllInformation, + FileAllocationInformation, + FileEndOfFileInformation, + FileAlternateNameInformation, + FileStreamInformation, + FilePipeInformation, + FilePipeLocalInformation, + FilePipeRemoteInformation, + FileMailslotQueryInformation, + FileMailslotSetInformation, + FileCompressionInformation, + FileObjectIdInformation, + FileCompletionInformation, + FileMoveClusterInformation, + FileQuotaInformation, + FileReparsePointInformation, + FileNetworkOpenInformation, + FileAttributeTagInformation, + FileTrackingInformation, + FileIdBothDirectoryInformation, + FileIdFullDirectoryInformation, + FileValidDataLengthInformation, + FileShortNameInformation, + FileIoCompletionNotificationInformation, + FileIoStatusBlockRangeInformation, + FileIoPriorityHintInformation, + FileSfioReserveInformation, + FileSfioVolumeInformation, + FileHardLinkInformation, + FileProcessIdsUsingFileInformation, + FileNormalizedNameInformation, + FileNetworkPhysicalNameInformation, + FileIdGlobalTxDirectoryInformation, + FileIsRemoteDeviceInformation, + FileUnusedInformation, + FileNumaNodeInformation, + FileStandardLinkInformation, + FileRemoteProtocolInformation, + /* Defined with Windows 10: */ + FileRenameInformationBypassAccessCheck, + FileLinkInformationBypassAccessCheck, + FileVolumeNameInformation, + FileIdInformation, + FileIdExtdDirectoryInformation, + FileReplaceCompletionInformation, + FileHardLinkFullIdInformation, + FileIdExtdBothDirectoryInformation, + FileDispositionInformationEx, + FileRenameInformationEx, + FileRenameInformationExBypassAccessCheck, + FileDesiredStorageClassInformation, + FileStatInformation, + FileMemoryPartitionInformation, + FileStatLxInformation, + FileCaseSensitiveInformation, + FileLinkInformationEx, + FileLinkInformationExBypassAccessCheck, + FileStorageReserveIdInformation, + FileCaseSensitiveInformationForceAccessCheck, + FileMaximumInformation +} FILE_INFORMATION_CLASS; +typedef FILE_INFORMATION_CLASS *PFILE_INFORMATION_CLASS; +RT_DECL_NTAPI(NTSTATUS) NtQueryInformationFile(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS); +RT_DECL_NTAPI(NTSTATUS) NtQueryDirectoryFile(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, + FILE_INFORMATION_CLASS, BOOLEAN, PUNICODE_STRING, BOOLEAN); +RT_DECL_NTAPI(NTSTATUS) NtSetInformationFile(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS); +#endif /* IPRT_NT_USE_WINTERNL */ +RT_DECL_NTAPI(NTSTATUS) NtQueryAttributesFile(POBJECT_ATTRIBUTES, PFILE_BASIC_INFORMATION); +RT_DECL_NTAPI(NTSTATUS) NtQueryFullAttributesFile(POBJECT_ATTRIBUTES, PFILE_NETWORK_OPEN_INFORMATION); + + +/** @name SE_GROUP_XXX - Attributes returned with TokenGroup and others. + * @{ */ +#ifndef SE_GROUP_MANDATORY +# define SE_GROUP_MANDATORY UINT32_C(0x01) +#endif +#ifndef SE_GROUP_ENABLED_BY_DEFAULT +# define SE_GROUP_ENABLED_BY_DEFAULT UINT32_C(0x02) +#endif +#ifndef SE_GROUP_ENABLED +# define SE_GROUP_ENABLED UINT32_C(0x04) +#endif +#ifndef SE_GROUP_OWNER +# define SE_GROUP_OWNER UINT32_C(0x08) +#endif +#ifndef SE_GROUP_USE_FOR_DENY_ONLY +# define SE_GROUP_USE_FOR_DENY_ONLY UINT32_C(0x10) +#endif +#ifndef SE_GROUP_INTEGRITY +# define SE_GROUP_INTEGRITY UINT32_C(0x20) +#endif +#ifndef SE_GROUP_INTEGRITY_ENABLED +# define SE_GROUP_INTEGRITY_ENABLED UINT32_C(0x40) +#endif +#ifndef SE_GROUP_RESOURCE +# define SE_GROUP_RESOURCE UINT32_C(0x20000000) +#endif +#ifndef SE_GROUP_LOGON_ID +# define SE_GROUP_LOGON_ID UINT32_C(0xc0000000) +#endif +/** @} */ + + +#ifdef IPRT_NT_USE_WINTERNL + +/** For use with KeyBasicInformation. */ +typedef struct _KEY_BASIC_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG NameLength; + WCHAR Name[1]; +} KEY_BASIC_INFORMATION; +typedef KEY_BASIC_INFORMATION *PKEY_BASIC_INFORMATION; + +/** For use with KeyNodeInformation. */ +typedef struct _KEY_NODE_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; /**< Offset from the start of the structure. */ + ULONG ClassLength; + ULONG NameLength; + WCHAR Name[1]; +} KEY_NODE_INFORMATION; +typedef KEY_NODE_INFORMATION *PKEY_NODE_INFORMATION; + +/** For use with KeyFullInformation. */ +typedef struct _KEY_FULL_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; /**< Offset of the Class member. */ + ULONG ClassLength; + ULONG SubKeys; + ULONG MaxNameLen; + ULONG MaxClassLen; + ULONG Values; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + WCHAR Class[1]; +} KEY_FULL_INFORMATION; +typedef KEY_FULL_INFORMATION *PKEY_FULL_INFORMATION; + +/** For use with KeyNameInformation. */ +typedef struct _KEY_NAME_INFORMATION +{ + ULONG NameLength; + WCHAR Name[1]; +} KEY_NAME_INFORMATION; +typedef KEY_NAME_INFORMATION *PKEY_NAME_INFORMATION; + +/** For use with KeyCachedInformation. */ +typedef struct _KEY_CACHED_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG SubKeys; + ULONG MaxNameLen; + ULONG Values; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + ULONG NameLength; +} KEY_CACHED_INFORMATION; +typedef KEY_CACHED_INFORMATION *PKEY_CACHED_INFORMATION; + +/** For use with KeyVirtualizationInformation. */ +typedef struct _KEY_VIRTUALIZATION_INFORMATION +{ + ULONG VirtualizationCandidate : 1; + ULONG VirtualizationEnabled : 1; + ULONG VirtualTarget : 1; + ULONG VirtualStore : 1; + ULONG VirtualSource : 1; + ULONG Reserved : 27; +} KEY_VIRTUALIZATION_INFORMATION; +typedef KEY_VIRTUALIZATION_INFORMATION *PKEY_VIRTUALIZATION_INFORMATION; + +typedef enum _KEY_INFORMATION_CLASS +{ + KeyBasicInformation = 0, + KeyNodeInformation, + KeyFullInformation, + KeyNameInformation, + KeyCachedInformation, + KeyFlagsInformation, + KeyVirtualizationInformation, + KeyHandleTagsInformation, + MaxKeyInfoClass +} KEY_INFORMATION_CLASS; +RT_DECL_NTAPI(NTSTATUS) NtQueryKey(HANDLE, KEY_INFORMATION_CLASS, PVOID, ULONG, PULONG); +RT_DECL_NTAPI(NTSTATUS) NtEnumerateKey(HANDLE, ULONG, KEY_INFORMATION_CLASS, PVOID, ULONG, PULONG); + +typedef struct _MEMORY_SECTION_NAME +{ + UNICODE_STRING SectionFileName; + WCHAR NameBuffer[1]; +} MEMORY_SECTION_NAME; + +#ifdef IPRT_NT_USE_WINTERNL +typedef struct _PROCESS_BASIC_INFORMATION +{ + NTSTATUS ExitStatus; + PPEB PebBaseAddress; + ULONG_PTR AffinityMask; + int32_t BasePriority; + ULONG_PTR UniqueProcessId; + ULONG_PTR InheritedFromUniqueProcessId; +} PROCESS_BASIC_INFORMATION; +typedef PROCESS_BASIC_INFORMATION *PPROCESS_BASIC_INFORMATION; +#endif + +typedef enum _PROCESSINFOCLASS +{ + ProcessBasicInformation = 0, /**< 0 / 0x00 */ + ProcessQuotaLimits, /**< 1 / 0x01 */ + ProcessIoCounters, /**< 2 / 0x02 */ + ProcessVmCounters, /**< 3 / 0x03 */ + ProcessTimes, /**< 4 / 0x04 */ + ProcessBasePriority, /**< 5 / 0x05 */ + ProcessRaisePriority, /**< 6 / 0x06 */ + ProcessDebugPort, /**< 7 / 0x07 */ + ProcessExceptionPort, /**< 8 / 0x08 */ + ProcessAccessToken, /**< 9 / 0x09 */ + ProcessLdtInformation, /**< 10 / 0x0a */ + ProcessLdtSize, /**< 11 / 0x0b */ + ProcessDefaultHardErrorMode, /**< 12 / 0x0c */ + ProcessIoPortHandlers, /**< 13 / 0x0d */ + ProcessPooledUsageAndLimits, /**< 14 / 0x0e */ + ProcessWorkingSetWatch, /**< 15 / 0x0f */ + ProcessUserModeIOPL, /**< 16 / 0x10 */ + ProcessEnableAlignmentFaultFixup, /**< 17 / 0x11 */ + ProcessPriorityClass, /**< 18 / 0x12 */ + ProcessWx86Information, /**< 19 / 0x13 */ + ProcessHandleCount, /**< 20 / 0x14 */ + ProcessAffinityMask, /**< 21 / 0x15 */ + ProcessPriorityBoost, /**< 22 / 0x16 */ + ProcessDeviceMap, /**< 23 / 0x17 */ + ProcessSessionInformation, /**< 24 / 0x18 */ + ProcessForegroundInformation, /**< 25 / 0x19 */ + ProcessWow64Information, /**< 26 / 0x1a */ + ProcessImageFileName, /**< 27 / 0x1b */ + ProcessLUIDDeviceMapsEnabled, /**< 28 / 0x1c */ + ProcessBreakOnTermination, /**< 29 / 0x1d */ + ProcessDebugObjectHandle, /**< 30 / 0x1e */ + ProcessDebugFlags, /**< 31 / 0x1f */ + ProcessHandleTracing, /**< 32 / 0x20 */ + ProcessIoPriority, /**< 33 / 0x21 */ + ProcessExecuteFlags, /**< 34 / 0x22 */ + ProcessTlsInformation, /**< 35 / 0x23 */ + ProcessCookie, /**< 36 / 0x24 */ + ProcessImageInformation, /**< 37 / 0x25 */ + ProcessCycleTime, /**< 38 / 0x26 */ + ProcessPagePriority, /**< 39 / 0x27 */ + ProcessInstrumentationCallbak, /**< 40 / 0x28 */ + ProcessThreadStackAllocation, /**< 41 / 0x29 */ + ProcessWorkingSetWatchEx, /**< 42 / 0x2a */ + ProcessImageFileNameWin32, /**< 43 / 0x2b */ + ProcessImageFileMapping, /**< 44 / 0x2c */ + ProcessAffinityUpdateMode, /**< 45 / 0x2d */ + ProcessMemoryAllocationMode, /**< 46 / 0x2e */ + ProcessGroupInformation, /**< 47 / 0x2f */ + ProcessTokenVirtualizationEnabled, /**< 48 / 0x30 */ + ProcessOwnerInformation, /**< 49 / 0x31 */ + ProcessWindowInformation, /**< 50 / 0x32 */ + ProcessHandleInformation, /**< 51 / 0x33 */ + ProcessMitigationPolicy, /**< 52 / 0x34 */ + ProcessDynamicFunctionTableInformation, /**< 53 / 0x35 */ + ProcessHandleCheckingMode, /**< 54 / 0x36 */ + ProcessKeepAliveCount, /**< 55 / 0x37 */ + ProcessRevokeFileHandles, /**< 56 / 0x38 */ + ProcessWorkingSetControl, /**< 57 / 0x39 */ + ProcessHandleTable, /**< 58 / 0x3a */ + ProcessCheckStackExtentsMode, /**< 59 / 0x3b */ + ProcessCommandLineInformation, /**< 60 / 0x3c */ + ProcessProtectionInformation, /**< 61 / 0x3d */ + ProcessMemoryExhaustion, /**< 62 / 0x3e */ + ProcessFaultInformation, /**< 63 / 0x3f */ + ProcessTelemetryIdInformation, /**< 64 / 0x40 */ + ProcessCommitReleaseInformation, /**< 65 / 0x41 */ + ProcessDefaultCpuSetsInformation, /**< 66 / 0x42 - aka ProcessReserved1Information */ + ProcessAllowedCpuSetsInformation, /**< 67 / 0x43 - aka ProcessReserved2Information; PROCESS_SET_LIMITED_INFORMATION & audiog.exe; W10 */ + ProcessSubsystemProcess, /**< 68 / 0x44 */ + ProcessJobMemoryInformation, /**< 69 / 0x45 */ + ProcessInPrivate, /**< 70 / 0x46 */ + ProcessRaiseUMExceptionOnInvalidHandleClose,/**< 71 / 0x47 */ + ProcessIumChallengeResponse, /**< 72 / 0x48 */ + ProcessChildProcessInformation, /**< 73 / 0x49 */ + ProcessHighGraphicsPriorityInformation, /**< 74 / 0x4a */ + ProcessSubsystemInformation, /**< 75 / 0x4b */ + ProcessEnergyValues, /**< 76 / 0x4c */ + ProcessPowerThrottlingState, /**< 77 / 0x4d */ + ProcessReserved3Information, /**< 78 / 0x4e */ + ProcessWin32kSyscallFilterInformation, /**< 79 / 0x4f */ + ProcessDisableSystemAllowedCpuSets, /**< 80 / 0x50 */ + ProcessWakeInformation, /**< 81 / 0x51 */ + ProcessEnergyTrackingState, /**< 82 / 0x52 */ + ProcessManageWritesToExecutableMemory, /**< 83 / 0x53 */ + ProcessCaptureTrustletLiveDump, /**< 84 / 0x54 */ + ProcessTelemetryCoverage, /**< 85 / 0x55 */ + ProcessEnclaveInformation, /**< 86 / 0x56 */ + ProcessEnableReadWriteVmLogging, /**< 87 / 0x57 */ + ProcessUptimeInformation, /**< 88 / 0x58 */ + ProcessImageSection, /**< 89 / 0x59 */ + ProcessDebugAuthInformation, /**< 90 / 0x5a */ + ProcessSystemResourceManagement, /**< 92 / 0x5b */ + ProcessSequenceNumber, /**< 93 / 0x5c */ + MaxProcessInfoClass +} PROCESSINFOCLASS; +AssertCompile(ProcessSequenceNumber == 0x5c); +#endif +#if defined(IPRT_NT_USE_WINTERNL) || defined(WDK_NTDDI_VERSION) /* Present in ntddk.h from 7600.16385.1, but not in W10. */ +RT_DECL_NTAPI(NTSTATUS) NtQueryInformationProcess(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); +#endif +#ifdef IPRT_NT_USE_WINTERNL +#if ARCH_BITS == 32 +/** 64-bit API pass thru to WOW64 processes. */ +RT_DECL_NTAPI(NTSTATUS) NtWow64QueryInformationProcess64(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); +#endif + +typedef enum _THREADINFOCLASS +{ + ThreadBasicInformation = 0, + ThreadTimes, + ThreadPriority, + ThreadBasePriority, + ThreadAffinityMask, + ThreadImpersonationToken, + ThreadDescriptorTableEntry, + ThreadEnableAlignmentFaultFixup, + ThreadEventPair_Reusable, + ThreadQuerySetWin32StartAddress, + ThreadZeroTlsCell, + ThreadPerformanceCount, + ThreadAmILastThread, + ThreadIdealProcessor, + ThreadPriorityBoost, + ThreadSetTlsArrayAddress, + ThreadIsIoPending, + ThreadHideFromDebugger, + ThreadBreakOnTermination, + ThreadSwitchLegacyState, + ThreadIsTerminated, + ThreadLastSystemCall, + ThreadIoPriority, + ThreadCycleTime, + ThreadPagePriority, + ThreadActualBasePriority, + ThreadTebInformation, + ThreadCSwitchMon, + ThreadCSwitchPmu, + ThreadWow64Context, + ThreadGroupInformation, + ThreadUmsInformation, + ThreadCounterProfiling, + ThreadIdealProcessorEx, + ThreadCpuAccountingInformation, + MaxThreadInfoClass +} THREADINFOCLASS; +RT_DECL_NTAPI(NTSTATUS) NtSetInformationThread(HANDLE, THREADINFOCLASS, LPCVOID, ULONG); + +RT_DECL_NTAPI(NTSTATUS) NtQueryInformationToken(HANDLE, TOKEN_INFORMATION_CLASS, PVOID, ULONG, PULONG); +RT_DECL_NTAPI(NTSTATUS) ZwQueryInformationToken(HANDLE, TOKEN_INFORMATION_CLASS, PVOID, ULONG, PULONG); + +RT_DECL_NTAPI(NTSTATUS) NtReadFile(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, PLARGE_INTEGER, PULONG); +RT_DECL_NTAPI(NTSTATUS) NtWriteFile(HANDLE, HANDLE, PIO_APC_ROUTINE, void const *, PIO_STATUS_BLOCK, PVOID, ULONG, PLARGE_INTEGER, PULONG); +RT_DECL_NTAPI(NTSTATUS) NtFlushBuffersFile(HANDLE, PIO_STATUS_BLOCK); +RT_DECL_NTAPI(NTSTATUS) NtCancelIoFile(HANDLE, PIO_STATUS_BLOCK); + +RT_DECL_NTAPI(NTSTATUS) NtReadVirtualMemory(HANDLE, PVOID, PVOID, SIZE_T, PSIZE_T); +RT_DECL_NTAPI(NTSTATUS) NtWriteVirtualMemory(HANDLE, PVOID, void const *, SIZE_T, PSIZE_T); + +RT_DECL_NTAPI(NTSTATUS) RtlAddAccessAllowedAce(PACL, ULONG, ULONG, PSID); +RT_DECL_NTAPI(NTSTATUS) RtlCopySid(ULONG, PSID, PSID); +RT_DECL_NTAPI(NTSTATUS) RtlCreateAcl(PACL, ULONG, ULONG); +RT_DECL_NTAPI(NTSTATUS) RtlCreateSecurityDescriptor(PSECURITY_DESCRIPTOR, ULONG); +RT_DECL_NTAPI(BOOLEAN) RtlEqualSid(PSID, PSID); +RT_DECL_NTAPI(NTSTATUS) RtlGetVersion(PRTL_OSVERSIONINFOW); +RT_DECL_NTAPI(NTSTATUS) RtlInitializeSid(PSID, PSID_IDENTIFIER_AUTHORITY, UCHAR); +RT_DECL_NTAPI(NTSTATUS) RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR, BOOLEAN, PACL, BOOLEAN); +RT_DECL_NTAPI(PULONG) RtlSubAuthoritySid(PSID, ULONG); + +#endif /* IPRT_NT_USE_WINTERNL */ + +#ifdef RTNT_NEED_NT_GET_PRODUCT_TYPE +RT_DECL_NTAPI(BOOLEAN) RtlGetNtProductType(enum _NT_PRODUCT_TYPE *); /**< @since NT 3.1 */ +#endif + +/** For use with ObjectBasicInformation. + * A watered down version of this struct appears under the name + * PUBLIC_OBJECT_BASIC_INFORMATION in ntifs.h. It only defines + * the first four members, so don't trust the rest. */ +typedef struct _OBJECT_BASIC_INFORMATION +{ + ULONG Attributes; + ACCESS_MASK GrantedAccess; + ULONG HandleCount; + ULONG PointerCount; + /* Not in ntifs.h: */ + ULONG PagedPoolCharge; + ULONG NonPagedPoolCharge; + ULONG Reserved[3]; + ULONG NameInfoSize; + ULONG TypeInfoSize; + ULONG SecurityDescriptorSize; + LARGE_INTEGER CreationTime; +} OBJECT_BASIC_INFORMATION; +typedef OBJECT_BASIC_INFORMATION *POBJECT_BASIC_INFORMATION; + +/** For use with ObjectHandleFlagInformation. */ +typedef struct _OBJECT_HANDLE_FLAG_INFORMATION +{ + BOOLEAN Inherit; + BOOLEAN ProtectFromClose; +} OBJECT_HANDLE_FLAG_INFORMATION; +typedef OBJECT_HANDLE_FLAG_INFORMATION *POBJECT_HANDLE_FLAG_INFORMATION; + +/** + * Returned via ObjectTypesInformation, see also OBJECT_TYPES_INFORMATION. + * The next structure address is calculate: + * (uintptr_t)Name.Buffer + RT_ALIGN_32(Name.MaximumLength, sizeof(uintptr_t)) + */ +typedef struct _OBJECT_TYPE_INFORMATION +{ /* 64-bit offset */ + UNICODE_STRING TypeName; /**< 0x00 */ + ULONG TotalNumberOfObjects; /**< 0x10 */ + ULONG TotalNumberOfHandles; /**< 0x14 */ + ULONG TotalPagedPoolUsage; /**< 0x18 - not set by W10 19044 */ + ULONG TotalNonPagedPoolUsage; /**< 0x1c - not set by W10 19044 */ + ULONG TotalNamePoolUsage; /**< 0x20 - not set by W10 19044 */ + ULONG TotalHandleTableUsage; /**< 0x24 - not set by W10 19044 */ + ULONG HighWaterNumberOfObjects; /**< 0x28 */ + ULONG HighWaterNumberOfHandles; /**< 0x2c */ + ULONG HighWaterPagedPoolUsage; /**< 0x30 - not set by W10 19044 */ + ULONG HighWaterNonPagedPoolUsage; /**< 0x34 - not set by W10 19044 */ + ULONG HighWaterNamePoolUsage; /**< 0x38 - not set by W10 19044 */ + ULONG HighWaterHandleTableUsage; /**< 0x3c - not set by W10 19044 */ + ULONG InvalidAttributes; /**< 0x40 */ + GENERIC_MAPPING GenericMapping; /**< 0x44 */ + ULONG ValidAccessMask; /**< 0x54 */ + BOOLEAN SecurityRequired; /**< 0x58 */ + BOOLEAN MaintainHandleCount; /**< 0x59 */ + UCHAR TypeIndex; /**< 0x5a */ + UCHAR ReservedZero; /**< 0x5b */ + ULONG PoolType; /**< 0x5c */ + ULONG DefaultPagedPoolCharge; /**< 0x60 - not set by W10 19044 */ + ULONG DefaultNonPagedPoolCharge; /**< 0x64 - not set by W10 19044 */ + /* The name string follows after the structure. */ +} OBJECT_TYPE_INFORMATION; +AssertCompileSize(OBJECT_TYPE_INFORMATION, sizeof(UNICODE_STRING) + 0x58); +typedef OBJECT_TYPE_INFORMATION *POBJECT_TYPE_INFORMATION; + +/** Returned via ObjectTypesInformation. */ +typedef struct _OBJECT_TYPES_INFORMATION +{ + ULONG NumberOfTypes; + OBJECT_TYPE_INFORMATION FirstType; +} OBJECT_TYPES_INFORMATION; +typedef OBJECT_TYPES_INFORMATION *POBJECT_TYPES_INFORMATION; + +typedef enum _OBJECT_INFORMATION_CLASS +{ + ObjectBasicInformation = 0, + ObjectNameInformation, + ObjectTypeInformation, + ObjectTypesInformation, + ObjectHandleFlagInformation, + ObjectSessionInformation, + MaxObjectInfoClass +} OBJECT_INFORMATION_CLASS; +typedef OBJECT_INFORMATION_CLASS *POBJECT_INFORMATION_CLASS; +#ifdef IN_RING0 +# define NtQueryObject ZwQueryObject +#endif +RT_DECL_NTAPI(NTSTATUS) NtQueryObject(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG); +RT_DECL_NTAPI(NTSTATUS) NtSetInformationObject(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG); +RT_DECL_NTAPI(NTSTATUS) NtDuplicateObject(HANDLE, HANDLE, HANDLE, PHANDLE, ACCESS_MASK, ULONG, ULONG); + +RT_DECL_NTAPI(NTSTATUS) NtOpenDirectoryObject(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); + +typedef struct _OBJECT_DIRECTORY_INFORMATION +{ + UNICODE_STRING Name; + UNICODE_STRING TypeName; +} OBJECT_DIRECTORY_INFORMATION; +typedef OBJECT_DIRECTORY_INFORMATION *POBJECT_DIRECTORY_INFORMATION; +RT_DECL_NTAPI(NTSTATUS) NtQueryDirectoryObject(HANDLE, PVOID, ULONG, BOOLEAN, BOOLEAN, PULONG, PULONG); + +RT_DECL_NTAPI(NTSTATUS) NtSuspendProcess(HANDLE); +RT_DECL_NTAPI(NTSTATUS) NtResumeProcess(HANDLE); +/** @name ProcessDefaultHardErrorMode bit definitions. + * @{ */ +#define PROCESS_HARDERR_CRITICAL_ERROR UINT32_C(0x00000001) /**< Inverted from the win32 define. */ +#define PROCESS_HARDERR_NO_GP_FAULT_ERROR UINT32_C(0x00000002) +#define PROCESS_HARDERR_NO_ALIGNMENT_FAULT_ERROR UINT32_C(0x00000004) +#define PROCESS_HARDERR_NO_OPEN_FILE_ERROR UINT32_C(0x00008000) +/** @} */ +RT_DECL_NTAPI(NTSTATUS) NtSetInformationProcess(HANDLE, PROCESSINFOCLASS, PVOID, ULONG); +RT_DECL_NTAPI(NTSTATUS) NtTerminateProcess(HANDLE, LONG); + +/** Returned by NtQUerySection with SectionBasicInformation. */ +typedef struct _SECTION_BASIC_INFORMATION +{ + PVOID BaseAddress; + ULONG AllocationAttributes; + LARGE_INTEGER MaximumSize; +} SECTION_BASIC_INFORMATION; +typedef SECTION_BASIC_INFORMATION *PSECTION_BASIC_INFORMATION; + +/** Retured by ProcessImageInformation as well as NtQuerySection. */ +typedef struct _SECTION_IMAGE_INFORMATION +{ + PVOID TransferAddress; + ULONG ZeroBits; + SIZE_T MaximumStackSize; + SIZE_T CommittedStackSize; + ULONG SubSystemType; + union + { + struct + { + USHORT SubSystemMinorVersion; + USHORT SubSystemMajorVersion; + }; + ULONG SubSystemVersion; + }; + ULONG GpValue; + USHORT ImageCharacteristics; + USHORT DllCharacteristics; + USHORT Machine; + BOOLEAN ImageContainsCode; + union /**< Since Vista, used to be a spare BOOLEAN. */ + { + struct + { + UCHAR ComPlusNativeRead : 1; + UCHAR ComPlusILOnly : 1; + UCHAR ImageDynamicallyRelocated : 1; + UCHAR ImageMAppedFlat : 1; + UCHAR Reserved : 4; + }; + UCHAR ImageFlags; + }; + ULONG LoaderFlags; + ULONG ImageFileSize; /**< Since XP? */ + ULONG CheckSum; /**< Since Vista, Used to be a reserved/spare ULONG. */ +} SECTION_IMAGE_INFORMATION; +typedef SECTION_IMAGE_INFORMATION *PSECTION_IMAGE_INFORMATION; + +typedef enum _SECTION_INFORMATION_CLASS +{ + SectionBasicInformation = 0, + SectionImageInformation, + MaxSectionInfoClass +} SECTION_INFORMATION_CLASS; +RT_DECL_NTAPI(NTSTATUS) NtQuerySection(HANDLE, SECTION_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); + +RT_DECL_NTAPI(NTSTATUS) NtCreateSymbolicLinkObject(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PUNICODE_STRING pTarget); +RT_DECL_NTAPI(NTSTATUS) NtOpenSymbolicLinkObject(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); +RT_DECL_NTAPI(NTSTATUS) NtQuerySymbolicLinkObject(HANDLE, PUNICODE_STRING, PULONG); +#ifndef SYMBOLIC_LINK_QUERY +# define SYMBOLIC_LINK_QUERY UINT32_C(0x00000001) +#endif +#ifndef SYMBOLIC_LINK_ALL_ACCESS +# define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYMBOLIC_LINK_QUERY) +#endif + +RT_DECL_NTAPI(NTSTATUS) NtQueryInformationThread(HANDLE, THREADINFOCLASS, PVOID, ULONG, PULONG); +RT_DECL_NTAPI(NTSTATUS) NtResumeThread(HANDLE, PULONG); +RT_DECL_NTAPI(NTSTATUS) NtSuspendThread(HANDLE, PULONG); +RT_DECL_NTAPI(NTSTATUS) NtTerminateThread(HANDLE, LONG); +RT_DECL_NTAPI(NTSTATUS) NtGetContextThread(HANDLE, PCONTEXT); +RT_DECL_NTAPI(NTSTATUS) NtSetContextThread(HANDLE, PCONTEXT); +RT_DECL_NTAPI(NTSTATUS) ZwYieldExecution(void); + + +#ifndef SEC_FILE +# define SEC_FILE UINT32_C(0x00800000) +#endif +#ifndef SEC_IMAGE +# define SEC_IMAGE UINT32_C(0x01000000) +#endif +#ifndef SEC_PROTECTED_IMAGE +# define SEC_PROTECTED_IMAGE UINT32_C(0x02000000) +#endif +#ifndef SEC_NOCACHE +# define SEC_NOCACHE UINT32_C(0x10000000) +#endif +#ifndef MEM_ROTATE +# define MEM_ROTATE UINT32_C(0x00800000) +#endif +typedef enum _MEMORY_INFORMATION_CLASS +{ + MemoryBasicInformation = 0, + MemoryWorkingSetList, + MemorySectionName, + MemoryBasicVlmInformation +} MEMORY_INFORMATION_CLASS; +#ifndef IPRT_NT_USE_WINTERNL +# ifndef WDK_NTDDI_VERSION /* W10 ntifs.h has it, 7600.16385.1 didn't. */ +typedef struct _MEMORY_BASIC_INFORMATION +{ + PVOID BaseAddress; + PVOID AllocationBase; + ULONG AllocationProtect; +# if ARCH_BITS == 64 + USHORT PartitionId; +# endif + SIZE_T RegionSize; + ULONG State; + ULONG Protect; + ULONG Type; +} MEMORY_BASIC_INFORMATION; +typedef MEMORY_BASIC_INFORMATION *PMEMORY_BASIC_INFORMATION; +# endif +# define NtQueryVirtualMemory ZwQueryVirtualMemory +#endif +#if defined(IPRT_NT_USE_WINTERNL) || !defined(WDK_NTDDI_VERSION) /* W10 ntifs.h has it, 7600.16385.1 didn't. */ +RT_DECL_NTAPI(NTSTATUS) NtQueryVirtualMemory(HANDLE, void const *, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); +#endif +#ifdef IPRT_NT_USE_WINTERNL +RT_DECL_NTAPI(NTSTATUS) NtAllocateVirtualMemory(HANDLE, PVOID *, ULONG, PSIZE_T, ULONG, ULONG); +RT_DECL_NTAPI(NTSTATUS) NtFreeVirtualMemory(HANDLE, PVOID *, PSIZE_T, ULONG); +#endif +RT_DECL_NTAPI(NTSTATUS) NtProtectVirtualMemory(HANDLE, PVOID *, PSIZE_T, ULONG, PULONG); + +typedef enum _SYSTEM_INFORMATION_CLASS +{ + SystemBasicInformation = 0, + SystemCpuInformation, + SystemPerformanceInformation, + SystemTimeOfDayInformation, + SystemInformation_Unknown_4, + SystemProcessInformation, + SystemInformation_Unknown_6, + SystemInformation_Unknown_7, + SystemProcessorPerformanceInformation, + SystemInformation_Unknown_9, + SystemInformation_Unknown_10, + SystemModuleInformation, + SystemInformation_Unknown_12, + SystemInformation_Unknown_13, + SystemInformation_Unknown_14, + SystemInformation_Unknown_15, + SystemHandleInformation, + SystemInformation_Unknown_17, + SystemPageFileInformation, + SystemInformation_Unknown_19, + SystemInformation_Unknown_20, + SystemCacheInformation, + SystemInformation_Unknown_22, + SystemInterruptInformation, + SystemDpcBehaviourInformation, + SystemFullMemoryInformation, + SystemLoadGdiDriverInformation, /* 26 */ + SystemUnloadGdiDriverInformation, /* 27 */ + SystemTimeAdjustmentInformation, + SystemSummaryMemoryInformation, + SystemInformation_Unknown_30, + SystemInformation_Unknown_31, + SystemInformation_Unknown_32, + SystemExceptionInformation, + SystemCrashDumpStateInformation, + SystemKernelDebuggerInformation, + SystemContextSwitchInformation, + SystemRegistryQuotaInformation, + SystemInformation_Unknown_38, + SystemInformation_Unknown_39, + SystemInformation_Unknown_40, + SystemInformation_Unknown_41, + SystemInformation_Unknown_42, + SystemInformation_Unknown_43, + SystemCurrentTimeZoneInformation, + SystemLookasideInformation, + SystemSetTimeSlipEvent, + SystemCreateSession, + SystemDeleteSession, + SystemInformation_Unknown_49, + SystemRangeStartInformation, + SystemVerifierInformation, + SystemInformation_Unknown_52, + SystemSessionProcessInformation, + SystemLoadGdiDriverInSystemSpaceInformation, /* 54 */ + SystemInformation_Unknown_55, + SystemInformation_Unknown_56, + SystemExtendedProcessInformation, + SystemInformation_Unknown_58, + SystemInformation_Unknown_59, + SystemInformation_Unknown_60, + SystemInformation_Unknown_61, + SystemInformation_Unknown_62, + SystemInformation_Unknown_63, + SystemExtendedHandleInformation, /* 64 */ + SystemInformation_Unknown_65, + SystemInformation_Unknown_66, + SystemInformation_Unknown_67, /**< See https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/codeintegrity.htm */ + SystemInformation_Unknown_68, + SystemInformation_HotPatchInfo, /* 69 */ + SystemInformation_Unknown_70, + SystemInformation_Unknown_71, + SystemInformation_Unknown_72, + SystemInformation_Unknown_73, + SystemInformation_Unknown_74, + SystemInformation_Unknown_75, + SystemInformation_Unknown_76, + SystemInformation_Unknown_77, + SystemInformation_Unknown_78, + SystemInformation_Unknown_79, + SystemInformation_Unknown_80, + SystemInformation_Unknown_81, + SystemInformation_Unknown_82, + SystemInformation_Unknown_83, + SystemInformation_Unknown_84, + SystemInformation_Unknown_85, + SystemInformation_Unknown_86, + SystemInformation_Unknown_87, + SystemInformation_Unknown_88, + SystemInformation_Unknown_89, + SystemInformation_Unknown_90, + SystemInformation_Unknown_91, + SystemInformation_Unknown_92, + SystemInformation_Unknown_93, + SystemInformation_Unknown_94, + SystemInformation_Unknown_95, + SystemInformation_KiOpPrefetchPatchCount, /* 96 */ + SystemInformation_Unknown_97, + SystemInformation_Unknown_98, + SystemInformation_Unknown_99, + SystemInformation_Unknown_100, + SystemInformation_Unknown_101, + SystemInformation_Unknown_102, + SystemInformation_Unknown_103, + SystemInformation_Unknown_104, + SystemInformation_Unknown_105, + SystemInformation_Unknown_107, + SystemInformation_GetLogicalProcessorInformationEx, /* 107 */ + + /** @todo fill gap. they've added a whole bunch of things */ + SystemPolicyInformation = 134, + SystemInformationClassMax +} SYSTEM_INFORMATION_CLASS; + +#ifdef IPRT_NT_USE_WINTERNL +typedef struct _VM_COUNTERS +{ + SIZE_T PeakVirtualSize; + SIZE_T VirtualSize; + ULONG PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; +} VM_COUNTERS; +typedef VM_COUNTERS *PVM_COUNTERS; +#endif + +#if 0 +typedef struct _IO_COUNTERS +{ + ULONGLONG ReadOperationCount; + ULONGLONG WriteOperationCount; + ULONGLONG OtherOperationCount; + ULONGLONG ReadTransferCount; + ULONGLONG WriteTransferCount; + ULONGLONG OtherTransferCount; +} IO_COUNTERS; +typedef IO_COUNTERS *PIO_COUNTERS; +#endif + +typedef struct _RTNT_SYSTEM_PROCESS_INFORMATION +{ + ULONG NextEntryOffset; /**< 0x00 / 0x00 */ + ULONG NumberOfThreads; /**< 0x04 / 0x04 */ + LARGE_INTEGER Reserved1[3]; /**< 0x08 / 0x08 */ + LARGE_INTEGER CreationTime; /**< 0x20 / 0x20 */ + LARGE_INTEGER UserTime; /**< 0x28 / 0x28 */ + LARGE_INTEGER KernelTime; /**< 0x30 / 0x30 */ + UNICODE_STRING ProcessName; /**< 0x38 / 0x38 Clean unicode encoding? */ + int32_t BasePriority; /**< 0x40 / 0x48 */ + HANDLE UniqueProcessId; /**< 0x44 / 0x50 */ + HANDLE ParentProcessId; /**< 0x48 / 0x58 */ + ULONG HandleCount; /**< 0x4c / 0x60 */ + ULONG Reserved2; /**< 0x50 / 0x64 Session ID? */ + ULONG_PTR Reserved3; /**< 0x54 / 0x68 */ + VM_COUNTERS VmCounters; /**< 0x58 / 0x70 */ + IO_COUNTERS IoCounters; /**< 0x88 / 0xd0 Might not be present in earlier windows versions. */ + /* After this follows the threads, then the ProcessName.Buffer. */ +} RTNT_SYSTEM_PROCESS_INFORMATION; +typedef RTNT_SYSTEM_PROCESS_INFORMATION *PRTNT_SYSTEM_PROCESS_INFORMATION; +#ifndef IPRT_NT_USE_WINTERNL +typedef RTNT_SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION; +typedef SYSTEM_PROCESS_INFORMATION *PSYSTEM_PROCESS_INFORMATION; +#endif + +typedef struct _SYSTEM_HANDLE_ENTRY_INFO +{ + USHORT UniqueProcessId; + USHORT CreatorBackTraceIndex; + UCHAR ObjectTypeIndex; + UCHAR HandleAttributes; + USHORT HandleValue; + PVOID Object; + ULONG GrantedAccess; +} SYSTEM_HANDLE_ENTRY_INFO; +typedef SYSTEM_HANDLE_ENTRY_INFO *PSYSTEM_HANDLE_ENTRY_INFO; + +/** Returned by SystemHandleInformation */ +typedef struct _SYSTEM_HANDLE_INFORMATION +{ + ULONG NumberOfHandles; + SYSTEM_HANDLE_ENTRY_INFO Handles[1]; +} SYSTEM_HANDLE_INFORMATION; +typedef SYSTEM_HANDLE_INFORMATION *PSYSTEM_HANDLE_INFORMATION; + +/** Extended handle information entry. + * @remarks 3 x PVOID + 4 x ULONG = 28 bytes on 32-bit / 40 bytes on 64-bit */ +typedef struct _SYSTEM_HANDLE_ENTRY_INFO_EX +{ + PVOID Object; + HANDLE UniqueProcessId; + HANDLE HandleValue; + ACCESS_MASK GrantedAccess; + USHORT CreatorBackTraceIndex; + USHORT ObjectTypeIndex; + ULONG HandleAttributes; + ULONG Reserved; +} SYSTEM_HANDLE_ENTRY_INFO_EX; +typedef SYSTEM_HANDLE_ENTRY_INFO_EX *PSYSTEM_HANDLE_ENTRY_INFO_EX; + +/** Returned by SystemExtendedHandleInformation. */ +typedef struct _SYSTEM_HANDLE_INFORMATION_EX +{ + ULONG_PTR NumberOfHandles; + ULONG_PTR Reserved; + SYSTEM_HANDLE_ENTRY_INFO_EX Handles[1]; +} SYSTEM_HANDLE_INFORMATION_EX; +typedef SYSTEM_HANDLE_INFORMATION_EX *PSYSTEM_HANDLE_INFORMATION_EX; + +/** Returned by SystemSessionProcessInformation. */ +typedef struct _SYSTEM_SESSION_PROCESS_INFORMATION +{ + ULONG SessionId; + ULONG BufferLength; + /** Return buffer, SYSTEM_PROCESS_INFORMATION entries. */ + PVOID Buffer; +} SYSTEM_SESSION_PROCESS_INFORMATION; +typedef SYSTEM_SESSION_PROCESS_INFORMATION *PSYSTEM_SESSION_PROCESS_INFORMATION; + +typedef struct _RTL_PROCESS_MODULE_INFORMATION +{ + HANDLE Section; /**< 0x00 / 0x00 */ + PVOID MappedBase; /**< 0x04 / 0x08 */ + PVOID ImageBase; /**< 0x08 / 0x10 */ + ULONG ImageSize; /**< 0x0c / 0x18 */ + ULONG Flags; /**< 0x10 / 0x1c */ + USHORT LoadOrderIndex; /**< 0x14 / 0x20 */ + USHORT InitOrderIndex; /**< 0x16 / 0x22 */ + USHORT LoadCount; /**< 0x18 / 0x24 */ + USHORT OffsetToFileName; /**< 0x1a / 0x26 */ + UCHAR FullPathName[256]; /**< 0x1c / 0x28 */ +} RTL_PROCESS_MODULE_INFORMATION; +typedef RTL_PROCESS_MODULE_INFORMATION *PRTL_PROCESS_MODULE_INFORMATION; + +/** Returned by SystemModuleInformation. */ +typedef struct _RTL_PROCESS_MODULES +{ + ULONG NumberOfModules; + RTL_PROCESS_MODULE_INFORMATION Modules[1]; /**< 0x04 / 0x08 */ +} RTL_PROCESS_MODULES; +typedef RTL_PROCESS_MODULES *PRTL_PROCESS_MODULES; + +RT_DECL_NTAPI(NTSTATUS) NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); +#ifndef IPRT_NT_MAP_TO_ZW +RT_DECL_NTAPI(NTSTATUS) ZwQuerySystemInformation(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); +#endif + +RT_DECL_NTAPI(NTSTATUS) NtSetTimerResolution(ULONG cNtTicksWanted, BOOLEAN fSetResolution, PULONG pcNtTicksCur); +RT_DECL_NTAPI(NTSTATUS) NtQueryTimerResolution(PULONG pcNtTicksMin, PULONG pcNtTicksMax, PULONG pcNtTicksCur); + +RT_DECL_NTAPI(NTSTATUS) NtDelayExecution(BOOLEAN, PLARGE_INTEGER); +RT_DECL_NTAPI(NTSTATUS) NtYieldExecution(void); +#ifndef IPRT_NT_USE_WINTERNL +RT_DECL_NTAPI(NTSTATUS) NtWaitForSingleObject(HANDLE, BOOLEAN, PLARGE_INTEGER); +#endif +typedef NTSYSAPI NTSTATUS (NTAPI *PFNNTWAITFORSINGLEOBJECT)(HANDLE, BOOLEAN, PLARGE_INTEGER); +typedef enum _OBJECT_WAIT_TYPE { WaitAllObjects = 0, WaitAnyObject = 1, ObjectWaitTypeHack = 0x7fffffff } OBJECT_WAIT_TYPE; +RT_DECL_NTAPI(NTSTATUS) NtWaitForMultipleObjects(ULONG, PHANDLE, OBJECT_WAIT_TYPE, BOOLEAN, PLARGE_INTEGER); + +#ifdef IPRT_NT_USE_WINTERNL +RT_DECL_NTAPI(NTSTATUS) NtQuerySecurityObject(HANDLE, ULONG, PSECURITY_DESCRIPTOR, ULONG, PULONG); +#endif + +#ifdef IPRT_NT_USE_WINTERNL +typedef enum _EVENT_TYPE +{ + /* Manual reset event. */ + NotificationEvent = 0, + /* Automaitc reset event. */ + SynchronizationEvent +} EVENT_TYPE; +#endif +RT_DECL_NTAPI(NTSTATUS) NtCreateEvent(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, EVENT_TYPE, BOOLEAN); +RT_DECL_NTAPI(NTSTATUS) NtOpenEvent(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); +typedef NTSYSAPI NTSTATUS (NTAPI *PFNNTCLEAREVENT)(HANDLE); +RT_DECL_NTAPI(NTSTATUS) NtClearEvent(HANDLE); +RT_DECL_NTAPI(NTSTATUS) NtResetEvent(HANDLE, PULONG); +RT_DECL_NTAPI(NTSTATUS) NtSetEvent(HANDLE, PULONG); +typedef NTSYSAPI NTSTATUS (NTAPI *PFNNTSETEVENT)(HANDLE, PULONG); +typedef enum _EVENT_INFORMATION_CLASS +{ + EventBasicInformation = 0 +} EVENT_INFORMATION_CLASS; +/** Data returned by NtQueryEvent + EventBasicInformation. */ +typedef struct EVENT_BASIC_INFORMATION +{ + EVENT_TYPE EventType; + ULONG EventState; +} EVENT_BASIC_INFORMATION; +typedef EVENT_BASIC_INFORMATION *PEVENT_BASIC_INFORMATION; +RT_DECL_NTAPI(NTSTATUS) NtQueryEvent(HANDLE, EVENT_INFORMATION_CLASS, PVOID, ULONG, PULONG); + +#ifdef IPRT_NT_USE_WINTERNL +/** For NtQueryValueKey. */ +typedef enum _KEY_VALUE_INFORMATION_CLASS +{ + KeyValueBasicInformation = 0, + KeyValueFullInformation, + KeyValuePartialInformation, + KeyValueFullInformationAlign64, + KeyValuePartialInformationAlign64 +} KEY_VALUE_INFORMATION_CLASS; + +/** KeyValuePartialInformation and KeyValuePartialInformationAlign64 struct. */ +typedef struct _KEY_VALUE_PARTIAL_INFORMATION +{ + ULONG TitleIndex; + ULONG Type; + ULONG DataLength; + UCHAR Data[1]; +} KEY_VALUE_PARTIAL_INFORMATION; +typedef KEY_VALUE_PARTIAL_INFORMATION *PKEY_VALUE_PARTIAL_INFORMATION; +#endif +RT_DECL_NTAPI(NTSTATUS) NtOpenKey(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); +RT_DECL_NTAPI(NTSTATUS) NtQueryValueKey(HANDLE, PUNICODE_STRING, KEY_VALUE_INFORMATION_CLASS, PVOID, ULONG, PULONG); + + +RT_DECL_NTAPI(NTSTATUS) RtlAddAccessDeniedAce(PACL, ULONG, ULONG, PSID); + + +typedef struct _CURDIR +{ + UNICODE_STRING DosPath; + HANDLE Handle; /**< 0x10 / 0x08 */ +} CURDIR; +AssertCompileSize(CURDIR, ARCH_BITS == 32 ? 0x0c : 0x18); +typedef CURDIR *PCURDIR; + +typedef struct _RTL_DRIVE_LETTER_CURDIR +{ + USHORT Flags; + USHORT Length; + ULONG TimeStamp; + STRING DosPath; /**< Yeah, it's STRING according to dt ntdll!_RTL_DRIVE_LETTER_CURDIR. */ +} RTL_DRIVE_LETTER_CURDIR; +typedef RTL_DRIVE_LETTER_CURDIR *PRTL_DRIVE_LETTER_CURDIR; + +typedef struct _RTL_USER_PROCESS_PARAMETERS +{ + ULONG MaximumLength; /**< 0x000 / 0x000 */ + ULONG Length; /**< 0x004 / 0x004 */ + ULONG Flags; /**< 0x008 / 0x008 */ + ULONG DebugFlags; /**< 0x00c / 0x00c */ + HANDLE ConsoleHandle; /**< 0x010 / 0x010 */ + ULONG ConsoleFlags; /**< 0x018 / 0x014 */ + HANDLE StandardInput; /**< 0x020 / 0x018 */ + HANDLE StandardOutput; /**< 0x028 / 0x01c */ + HANDLE StandardError; /**< 0x030 / 0x020 */ + CURDIR CurrentDirectory; /**< 0x038 / 0x024 */ + UNICODE_STRING DllPath; /**< 0x050 / 0x030 */ + UNICODE_STRING ImagePathName; /**< 0x060 / 0x038 */ + UNICODE_STRING CommandLine; /**< 0x070 / 0x040 */ + PWSTR Environment; /**< 0x080 / 0x048 */ + ULONG StartingX; /**< 0x088 / 0x04c */ + ULONG StartingY; /**< 0x090 / 0x050 */ + ULONG CountX; /**< 0x094 / 0x054 */ + ULONG CountY; /**< 0x098 / 0x058 */ + ULONG CountCharsX; /**< 0x09c / 0x05c */ + ULONG CountCharsY; /**< 0x0a0 / 0x060 */ + ULONG FillAttribute; /**< 0x0a4 / 0x064 */ + ULONG WindowFlags; /**< 0x0a8 / 0x068 */ + ULONG ShowWindowFlags; /**< 0x0ac / 0x06c */ + UNICODE_STRING WindowTitle; /**< 0x0b0 / 0x070 */ + UNICODE_STRING DesktopInfo; /**< 0x0c0 / 0x078 */ + UNICODE_STRING ShellInfo; /**< 0x0d0 / 0x080 */ + UNICODE_STRING RuntimeInfo; /**< 0x0e0 / 0x088 */ + RTL_DRIVE_LETTER_CURDIR CurrentDirectories[0x20]; /**< 0x0f0 / 0x090 */ + SIZE_T EnvironmentSize; /**< 0x3f0 / 0x - Added in Vista */ + SIZE_T EnvironmentVersion; /**< 0x3f8 / 0x - Added in Windows 7. */ + PVOID PackageDependencyData; /**< 0x400 / 0x - Added Windows 8? */ + ULONG ProcessGroupId; /**< 0x408 / 0x - Added Windows 8? */ + ULONG LoaderThreads; /**< 0x40c / 0x - Added Windows 10? */ +} RTL_USER_PROCESS_PARAMETERS; +typedef RTL_USER_PROCESS_PARAMETERS *PRTL_USER_PROCESS_PARAMETERS; +#define RTL_USER_PROCESS_PARAMS_FLAG_NORMALIZED 1 + +typedef struct _RTL_USER_PROCESS_INFORMATION +{ + ULONG Size; + HANDLE ProcessHandle; + HANDLE ThreadHandle; + CLIENT_ID ClientId; + SECTION_IMAGE_INFORMATION ImageInformation; +} RTL_USER_PROCESS_INFORMATION; +typedef RTL_USER_PROCESS_INFORMATION *PRTL_USER_PROCESS_INFORMATION; + + +RT_DECL_NTAPI(NTSTATUS) RtlCreateUserProcess(PUNICODE_STRING, ULONG, PRTL_USER_PROCESS_PARAMETERS, PSECURITY_DESCRIPTOR, + PSECURITY_DESCRIPTOR, HANDLE, BOOLEAN, HANDLE, HANDLE, PRTL_USER_PROCESS_INFORMATION); +RT_DECL_NTAPI(NTSTATUS) RtlCreateProcessParameters(PRTL_USER_PROCESS_PARAMETERS *, PUNICODE_STRING ImagePathName, + PUNICODE_STRING DllPath, PUNICODE_STRING CurrentDirectory, + PUNICODE_STRING CommandLine, PUNICODE_STRING Environment, + PUNICODE_STRING WindowTitle, PUNICODE_STRING DesktopInfo, + PUNICODE_STRING ShellInfo, PUNICODE_STRING RuntimeInfo); +RT_DECL_NTAPI(VOID) RtlDestroyProcessParameters(PRTL_USER_PROCESS_PARAMETERS); +RT_DECL_NTAPI(NTSTATUS) RtlCreateUserThread(HANDLE, PSECURITY_DESCRIPTOR, BOOLEAN, ULONG, SIZE_T, SIZE_T, + PFNRT, PVOID, PHANDLE, PCLIENT_ID); + +#ifndef RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO +typedef struct _RTL_CRITICAL_SECTION +{ + struct _RTL_CRITICAL_SECTION_DEBUG *DebugInfo; + LONG LockCount; + LONG Recursioncount; + HANDLE OwningThread; + HANDLE LockSemaphore; + ULONG_PTR SpinCount; +} RTL_CRITICAL_SECTION; +typedef RTL_CRITICAL_SECTION *PRTL_CRITICAL_SECTION; +#endif + +/*RT_DECL_NTAPI(ULONG) RtlNtStatusToDosError(NTSTATUS rcNt);*/ + +/** @def RTL_QUERY_REGISTRY_TYPECHECK + * WDK 8.1+, backported in updates, ignored in older. */ +#if !defined(RTL_QUERY_REGISTRY_TYPECHECK) || defined(DOXYGEN_RUNNING) +# define RTL_QUERY_REGISTRY_TYPECHECK UINT32_C(0x00000100) +#endif +/** @def RTL_QUERY_REGISTRY_TYPECHECK_SHIFT + * WDK 8.1+, backported in updates, ignored in older. */ +#if !defined(RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) || defined(DOXYGEN_RUNNING) +# define RTL_QUERY_REGISTRY_TYPECHECK_SHIFT 24 +#endif + +RT_DECL_NTAPI(VOID) RtlFreeUnicodeString(PUNICODE_STRING); + +RT_C_DECLS_END +/** @} */ + + +#if defined(IN_RING0) || defined(DOXYGEN_RUNNING) +/** @name NT Kernel APIs + * @{ */ +RT_C_DECLS_BEGIN + +typedef ULONG KEPROCESSORINDEX; /**< Bitmap indexes != process numbers, apparently. */ + +RT_DECL_NTAPI(VOID) KeInitializeAffinityEx(PKAFFINITY_EX pAffinity); +typedef VOID (NTAPI *PFNKEINITIALIZEAFFINITYEX)(PKAFFINITY_EX pAffinity); +RT_DECL_NTAPI(VOID) KeAddProcessorAffinityEx(PKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +typedef VOID (NTAPI *PFNKEADDPROCESSORAFFINITYEX)(PKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +RT_DECL_NTAPI(VOID) KeRemoveProcessorAffinityEx(PKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +typedef VOID (NTAPI *PFNKEREMOVEPROCESSORAFFINITYEX)(PKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +RT_DECL_NTAPI(BOOLEAN) KeInterlockedSetProcessorAffinityEx(PKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +typedef BOOLEAN (NTAPI *PFNKEINTERLOCKEDSETPROCESSORAFFINITYEX)(PKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +RT_DECL_NTAPI(BOOLEAN) KeInterlockedClearProcessorAffinityEx(PKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +typedef BOOLEAN (NTAPI *PFNKEINTERLOCKEDCLEARPROCESSORAFFINITYEX)(PKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +RT_DECL_NTAPI(BOOLEAN) KeCheckProcessorAffinityEx(PCKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +typedef BOOLEAN (NTAPI *PFNKECHECKPROCESSORAFFINITYEX)(PCKAFFINITY_EX pAffinity, KEPROCESSORINDEX idxProcessor); +RT_DECL_NTAPI(VOID) KeCopyAffinityEx(PKAFFINITY_EX pDst, PCKAFFINITY_EX pSrc); +typedef VOID (NTAPI *PFNKECOPYAFFINITYEX)(PKAFFINITY_EX pDst, PCKAFFINITY_EX pSrc); +RT_DECL_NTAPI(VOID) KeComplementAffinityEx(PKAFFINITY_EX pResult, PCKAFFINITY_EX pIn); +typedef VOID (NTAPI *PFNKECOMPLEMENTAFFINITYEX)(PKAFFINITY_EX pResult, PCKAFFINITY_EX pIn); +RT_DECL_NTAPI(BOOLEAN) KeAndAffinityEx(PCKAFFINITY_EX pIn1, PCKAFFINITY_EX pIn2, PKAFFINITY_EX pResult OPTIONAL); +typedef BOOLEAN (NTAPI *PFNKEANDAFFINITYEX)(PCKAFFINITY_EX pIn1, PCKAFFINITY_EX pIn2, PKAFFINITY_EX pResult OPTIONAL); +RT_DECL_NTAPI(BOOLEAN) KeOrAffinityEx(PCKAFFINITY_EX pIn1, PCKAFFINITY_EX pIn2, PKAFFINITY_EX pResult OPTIONAL); +typedef BOOLEAN (NTAPI *PFNKEORAFFINITYEX)(PCKAFFINITY_EX pIn1, PCKAFFINITY_EX pIn2, PKAFFINITY_EX pResult OPTIONAL); +/** Works like anding the complemented subtrahend with the minuend. */ +RT_DECL_NTAPI(BOOLEAN) KeSubtractAffinityEx(PCKAFFINITY_EX pMinuend, PCKAFFINITY_EX pSubtrahend, PKAFFINITY_EX pResult OPTIONAL); +typedef BOOLEAN (NTAPI *PFNKESUBTRACTAFFINITYEX)(PCKAFFINITY_EX pMinuend, PCKAFFINITY_EX pSubtrahend, PKAFFINITY_EX pResult OPTIONAL); +RT_DECL_NTAPI(BOOLEAN) KeIsEqualAffinityEx(PCKAFFINITY_EX pLeft, PCKAFFINITY_EX pRight); +typedef BOOLEAN (NTAPI *PFNKEISEQUALAFFINITYEX)(PCKAFFINITY_EX pLeft, PCKAFFINITY_EX pRight); +RT_DECL_NTAPI(BOOLEAN) KeIsEmptyAffinityEx(PCKAFFINITY_EX pAffinity); +typedef BOOLEAN (NTAPI *PFNKEISEMPTYAFFINITYEX)(PCKAFFINITY_EX pAffinity); +RT_DECL_NTAPI(BOOLEAN) KeIsSubsetAffinityEx(PCKAFFINITY_EX pSubset, PCKAFFINITY_EX pSuperSet); +typedef BOOLEAN (NTAPI *PFNKEISSUBSETAFFINITYEX)(PCKAFFINITY_EX pSubset, PCKAFFINITY_EX pSuperSet); +RT_DECL_NTAPI(ULONG) KeCountSetBitsAffinityEx(PCKAFFINITY_EX pAffinity); +typedef ULONG (NTAPI *PFNKECOUNTSETAFFINITYEX)(PCKAFFINITY_EX pAffinity); +RT_DECL_NTAPI(KEPROCESSORINDEX) KeFindFirstSetLeftAffinityEx(PCKAFFINITY_EX pAffinity); +typedef KEPROCESSORINDEX (NTAPI *PFNKEFINDFIRSTSETLEFTAFFINITYEX)(PCKAFFINITY_EX pAffinity); +typedef NTSTATUS (NTAPI *PFNKEGETPROCESSORNUMBERFROMINDEX)(KEPROCESSORINDEX idxProcessor, PPROCESSOR_NUMBER pProcNumber); +typedef KEPROCESSORINDEX (NTAPI *PFNKEGETPROCESSORINDEXFROMNUMBER)(const PROCESSOR_NUMBER *pProcNumber); +typedef NTSTATUS (NTAPI *PFNKEGETPROCESSORNUMBERFROMINDEX)(KEPROCESSORINDEX ProcIndex, PROCESSOR_NUMBER *pProcNumber); +typedef KEPROCESSORINDEX (NTAPI *PFNKEGETCURRENTPROCESSORNUMBEREX)(const PROCESSOR_NUMBER *pProcNumber); +typedef KAFFINITY (NTAPI *PFNKEQUERYACTIVEPROCESSORS)(VOID); +typedef ULONG (NTAPI *PFNKEQUERYMAXIMUMPROCESSORCOUNT)(VOID); +typedef ULONG (NTAPI *PFNKEQUERYMAXIMUMPROCESSORCOUNTEX)(USHORT GroupNumber); +typedef USHORT (NTAPI *PFNKEQUERYMAXIMUMGROUPCOUNT)(VOID); +typedef ULONG (NTAPI *PFNKEQUERYACTIVEPROCESSORCOUNT)(KAFFINITY *pfActiveProcessors); +typedef ULONG (NTAPI *PFNKEQUERYACTIVEPROCESSORCOUNTEX)(USHORT GroupNumber); +typedef NTSTATUS (NTAPI *PFNKEQUERYLOGICALPROCESSORRELATIONSHIP)(PROCESSOR_NUMBER *pProcNumber, + LOGICAL_PROCESSOR_RELATIONSHIP RelationShipType, + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *pInfo, PULONG pcbInfo); +typedef PVOID (NTAPI *PFNKEREGISTERPROCESSORCHANGECALLBACK)(PPROCESSOR_CALLBACK_FUNCTION pfnCallback, void *pvUser, ULONG fFlags); +typedef VOID (NTAPI *PFNKEDEREGISTERPROCESSORCHANGECALLBACK)(PVOID pvCallback); +typedef NTSTATUS (NTAPI *PFNKESETTARGETPROCESSORDPCEX)(KDPC *pDpc, PROCESSOR_NUMBER *pProcNumber); +typedef LOGICAL (NTAPI *PFNKESHOULDYIELDPROCESSOR)(void); + +RT_DECL_NTAPI(BOOLEAN) ObFindHandleForObject(PEPROCESS pProcess, PVOID pvObject, POBJECT_TYPE pObjectType, + PVOID pvOptionalConditions, PHANDLE phFound); +RT_DECL_NTAPI(NTSTATUS) ObReferenceObjectByName(PUNICODE_STRING pObjectPath, ULONG fAttributes, PACCESS_STATE pAccessState, + ACCESS_MASK fDesiredAccess, POBJECT_TYPE pObjectType, + KPROCESSOR_MODE enmAccessMode, PVOID pvParseContext, PVOID *ppvObject); +RT_DECL_NTAPI(HANDLE) PsGetProcessInheritedFromUniqueProcessId(PEPROCESS); +RT_DECL_NTAPI(UCHAR *) PsGetProcessImageFileName(PEPROCESS); +RT_DECL_NTAPI(BOOLEAN) PsIsProcessBeingDebugged(PEPROCESS); +RT_DECL_NTAPI(ULONG) PsGetProcessSessionId(PEPROCESS); +extern DECLIMPORT(POBJECT_TYPE *) LpcPortObjectType; /**< In vista+ this is the ALPC port object type. */ +extern DECLIMPORT(POBJECT_TYPE *) LpcWaitablePortObjectType; /**< In vista+ this is the ALPC port object type. */ + +typedef VOID (NTAPI *PFNHALREQUESTIPI_PRE_W7)(KAFFINITY TargetSet); +typedef VOID (NTAPI *PFNHALREQUESTIPI_W7PLUS)(ULONG uUsuallyZero, PCKAFFINITY_EX pTargetSet); + +RT_C_DECLS_END +/** @ */ +#endif /* IN_RING0 */ + + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +/** @name NT Userland APIs + * @{ */ +RT_C_DECLS_BEGIN + +#if 0 /** @todo figure this out some time... */ +typedef struct CSR_MSG_DATA_CREATED_PROCESS +{ + HANDLE hProcess; + HANDLE hThread; + CLIENT_ID + DWORD idProcess; + DWORD idThread; + DWORD fCreate; + +} CSR_MSG_DATA_CREATED_PROCESS; + +#define CSR_MSG_NO_CREATED_PROCESS UINT32_C(0x10000) +#define CSR_MSG_NO_CREATED_THREAD UINT32_C(0x10001) +RT_DECL_NTAPI(NTSTATUS) CsrClientCallServer(PVOID, PVOID, ULONG, SIZE_T); +#endif + +RT_DECL_NTAPI(VOID) LdrInitializeThunk(PVOID, PVOID, PVOID); + +typedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA +{ + ULONG Flags; + PCUNICODE_STRING FullDllName; + PCUNICODE_STRING BaseDllName; + PVOID DllBase; + ULONG SizeOfImage; +} LDR_DLL_LOADED_NOTIFICATION_DATA, LDR_DLL_UNLOADED_NOTIFICATION_DATA; +typedef LDR_DLL_LOADED_NOTIFICATION_DATA *PLDR_DLL_LOADED_NOTIFICATION_DATA, *PLDR_DLL_UNLOADED_NOTIFICATION_DATA; +typedef LDR_DLL_LOADED_NOTIFICATION_DATA const *PCLDR_DLL_LOADED_NOTIFICATION_DATA, *PCLDR_DLL_UNLOADED_NOTIFICATION_DATA; + +typedef union _LDR_DLL_NOTIFICATION_DATA +{ + LDR_DLL_LOADED_NOTIFICATION_DATA Loaded; + LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded; +} LDR_DLL_NOTIFICATION_DATA; +typedef LDR_DLL_NOTIFICATION_DATA *PLDR_DLL_NOTIFICATION_DATA; +typedef LDR_DLL_NOTIFICATION_DATA const *PCLDR_DLL_NOTIFICATION_DATA; + +typedef VOID (NTAPI *PLDR_DLL_NOTIFICATION_FUNCTION)(ULONG ulReason, PCLDR_DLL_NOTIFICATION_DATA pData, PVOID pvUser); + +#define LDR_DLL_NOTIFICATION_REASON_LOADED UINT32_C(1) +#define LDR_DLL_NOTIFICATION_REASON_UNLOADED UINT32_C(2) +RT_DECL_NTAPI(NTSTATUS) LdrRegisterDllNotification(ULONG fFlags, PLDR_DLL_NOTIFICATION_FUNCTION pfnCallback, PVOID pvUser, + PVOID *pvCookie); +typedef NTSTATUS (NTAPI *PFNLDRREGISTERDLLNOTIFICATION)(ULONG, PLDR_DLL_NOTIFICATION_FUNCTION, PVOID, PVOID *); +RT_DECL_NTAPI(NTSTATUS) LdrUnregisterDllNotification(PVOID pvCookie); +typedef NTSTATUS (NTAPI *PFNLDRUNREGISTERDLLNOTIFICATION)(PVOID); + +RT_DECL_NTAPI(NTSTATUS) LdrLoadDll(IN PWSTR pwszSearchPathOrFlags OPTIONAL, IN PULONG pfFlags OPTIONAL, + IN PCUNICODE_STRING pName, OUT PHANDLE phMod); +typedef NTSTATUS (NTAPI *PFNLDRLOADDLL)(IN PWSTR pwszSearchPathOrFlags OPTIONAL, IN PULONG pfFlags OPTIONAL, + IN PCUNICODE_STRING pName, OUT PHANDLE phMod); +RT_DECL_NTAPI(NTSTATUS) LdrUnloadDll(IN HANDLE hMod); +typedef NTSTATUS (NTAPI *PFNLDRUNLOADDLL)(IN HANDLE hMod); +RT_DECL_NTAPI(NTSTATUS) LdrGetDllHandle(IN PCWSTR pwszDllPath OPTIONAL, IN PULONG pfFlags OPTIONAL, + IN PCUNICODE_STRING pName, OUT PHANDLE phDll); +typedef NTSTATUS (NTAPI *PFNLDRGETDLLHANDLE)(IN PCWSTR pwszDllPath OPTIONAL, IN PULONG pfFlags OPTIONAL, + IN PCUNICODE_STRING pName, OUT PHANDLE phDll); +#define LDRGETDLLHANDLEEX_F_UNCHANGED_REFCOUNT RT_BIT_32(0) +#define LDRGETDLLHANDLEEX_F_PIN RT_BIT_32(1) +/** @since Windows XP. */ +RT_DECL_NTAPI(NTSTATUS) LdrGetDllHandleEx(IN ULONG fFlags, IN PCWSTR pwszDllPath OPTIONAL, IN PULONG pfFlags OPTIONAL, + IN PCUNICODE_STRING pName, OUT PHANDLE phDll); +/** @since Windows XP. */ +typedef NTSTATUS (NTAPI *PFNLDRGETDLLHANDLEEX)(IN ULONG fFlags, IN PCWSTR pwszDllPath OPTIONAL, IN PULONG pfFlags OPTIONAL, + IN PCUNICODE_STRING pName, OUT PHANDLE phDll); +/** @since Windows 7. */ +RT_DECL_NTAPI(NTSTATUS) LdrGetDllHandleByMapping(IN PVOID pvBase, OUT PHANDLE phDll); +/** @since Windows 7. */ +typedef NTSTATUS (NTAPI *PFNLDRGETDLLHANDLEBYMAPPING)(IN PVOID pvBase, OUT PHANDLE phDll); +/** @since Windows 7. */ +RT_DECL_NTAPI(NTSTATUS) LdrGetDllHandleByName(IN PCUNICODE_STRING pName OPTIONAL, IN PCUNICODE_STRING pFullName OPTIONAL, + OUT PHANDLE phDll); +/** @since Windows 7. */ +typedef NTSTATUS (NTAPI *PFNLDRGETDLLHANDLEBYNAME)(IN PCUNICODE_STRING pName OPTIONAL, IN PCUNICODE_STRING pFullName OPTIONAL, + OUT PHANDLE phDll); +#define LDRADDREFDLL_F_PIN RT_BIT_32(0) +RT_DECL_NTAPI(NTSTATUS) LdrAddRefDll(IN ULONG fFlags, IN HANDLE hDll); +typedef NTSTATUS (NTAPI *PFNLDRADDREFDLL)(IN ULONG fFlags, IN HANDLE hDll); +RT_DECL_NTAPI(NTSTATUS) LdrGetProcedureAddress(IN HANDLE hDll, IN ANSI_STRING const *pSymbol OPTIONAL, + IN ULONG uOrdinal OPTIONAL, OUT PVOID *ppvSymbol); +typedef NTSTATUS (NTAPI *PFNLDRGETPROCEDUREADDRESS)(IN HANDLE hDll, IN PCANSI_STRING pSymbol OPTIONAL, + IN ULONG uOrdinal OPTIONAL, OUT PVOID *ppvSymbol); +#define LDRGETPROCEDUREADDRESSEX_F_DONT_RECORD_FORWARDER RT_BIT_32(0) +/** @since Windows Vista. */ +RT_DECL_NTAPI(NTSTATUS) LdrGetProcedureAddressEx(IN HANDLE hDll, IN ANSI_STRING const *pSymbol OPTIONAL, + IN ULONG uOrdinal OPTIONAL, OUT PVOID *ppvSymbol, ULONG fFlags); +/** @since Windows Vista. */ +typedef NTSTATUS (NTAPI *PFNLDRGETPROCEDUREADDRESSEX)(IN HANDLE hDll, IN ANSI_STRING const *pSymbol OPTIONAL, + IN ULONG uOrdinal OPTIONAL, OUT PVOID *ppvSymbol, ULONG fFlags); +#define LDRLOCKLOADERLOCK_F_RAISE_ERRORS RT_BIT_32(0) +#define LDRLOCKLOADERLOCK_F_NO_WAIT RT_BIT_32(1) +#define LDRLOCKLOADERLOCK_DISP_INVALID UINT32_C(0) +#define LDRLOCKLOADERLOCK_DISP_ACQUIRED UINT32_C(1) +#define LDRLOCKLOADERLOCK_DISP_NOT_ACQUIRED UINT32_C(2) +/** @since Windows XP. */ +RT_DECL_NTAPI(NTSTATUS) LdrLockLoaderLock(IN ULONG fFlags, OUT PULONG puDisposition OPTIONAL, OUT PVOID *ppvCookie); +/** @since Windows XP. */ +typedef NTSTATUS (NTAPI *PFNLDRLOCKLOADERLOCK)(IN ULONG fFlags, OUT PULONG puDisposition OPTIONAL, OUT PVOID *ppvCookie); +#define LDRUNLOCKLOADERLOCK_F_RAISE_ERRORS RT_BIT_32(0) +/** @since Windows XP. */ +RT_DECL_NTAPI(NTSTATUS) LdrUnlockLoaderLock(IN ULONG fFlags, OUT PVOID pvCookie); +/** @since Windows XP. */ +typedef NTSTATUS (NTAPI *PFNLDRUNLOCKLOADERLOCK)(IN ULONG fFlags, OUT PVOID pvCookie); + +RT_DECL_NTAPI(NTSTATUS) RtlExpandEnvironmentStrings_U(PVOID, PUNICODE_STRING, PUNICODE_STRING, PULONG); +RT_DECL_NTAPI(VOID) RtlExitUserProcess(NTSTATUS rcExitCode); /**< Vista and later. */ +RT_DECL_NTAPI(VOID) RtlExitUserThread(NTSTATUS rcExitCode); +RT_DECL_NTAPI(NTSTATUS) RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG fFlags, + IN PCUNICODE_STRING pOrgName, + IN PUNICODE_STRING pDefaultSuffix, + IN OUT PUNICODE_STRING pStaticString, + IN OUT PUNICODE_STRING pDynamicString, + IN OUT PUNICODE_STRING *ppResultString, + IN PULONG pfNewFlags OPTIONAL, + IN PSIZE_T pcbFilename OPTIONAL, + IN PSIZE_T pcbNeeded OPTIONAL); +/** @since Windows 8. + * @note Status code is always zero in windows 10 build 14393. */ +RT_DECL_NTAPI(NTSTATUS) ApiSetQueryApiSetPresence(IN PCUNICODE_STRING pAllegedApiSetDll, OUT PBOOLEAN pfPresent); +/** @copydoc ApiSetQueryApiSetPresence */ +typedef NTSTATUS (NTAPI *PFNAPISETQUERYAPISETPRESENCE)(IN PCUNICODE_STRING pAllegedApiSetDll, OUT PBOOLEAN pfPresent); + + +# ifdef IPRT_NT_USE_WINTERNL +typedef NTSTATUS NTAPI RTL_HEAP_COMMIT_ROUTINE(PVOID, PVOID *, PSIZE_T); +typedef RTL_HEAP_COMMIT_ROUTINE *PRTL_HEAP_COMMIT_ROUTINE; +typedef struct _RTL_HEAP_PARAMETERS +{ + ULONG Length; + SIZE_T SegmentReserve; + SIZE_T SegmentCommit; + SIZE_T DeCommitFreeBlockThreshold; + SIZE_T DeCommitTotalFreeThreshold; + SIZE_T MaximumAllocationSize; + SIZE_T VirtualMemoryThreshold; + SIZE_T InitialCommit; + SIZE_T InitialReserve; + PRTL_HEAP_COMMIT_ROUTINE CommitRoutine; + SIZE_T Reserved[2]; +} RTL_HEAP_PARAMETERS; +typedef RTL_HEAP_PARAMETERS *PRTL_HEAP_PARAMETERS; +RT_DECL_NTAPI(PVOID) RtlCreateHeap(ULONG fFlags, PVOID pvHeapBase, SIZE_T cbReserve, SIZE_T cbCommit, PVOID pvLock, + PRTL_HEAP_PARAMETERS pParameters); +/** @name Heap flags (for RtlCreateHeap). + * @{ */ +/*# define HEAP_NO_SERIALIZE UINT32_C(0x00000001) +# define HEAP_GROWABLE UINT32_C(0x00000002) +# define HEAP_GENERATE_EXCEPTIONS UINT32_C(0x00000004) +# define HEAP_ZERO_MEMORY UINT32_C(0x00000008) +# define HEAP_REALLOC_IN_PLACE_ONLY UINT32_C(0x00000010) +# define HEAP_TAIL_CHECKING_ENABLED UINT32_C(0x00000020) +# define HEAP_FREE_CHECKING_ENABLED UINT32_C(0x00000040) +# define HEAP_DISABLE_COALESCE_ON_FREE UINT32_C(0x00000080)*/ +# define HEAP_SETTABLE_USER_VALUE UINT32_C(0x00000100) +# define HEAP_SETTABLE_USER_FLAG1 UINT32_C(0x00000200) +# define HEAP_SETTABLE_USER_FLAG2 UINT32_C(0x00000400) +# define HEAP_SETTABLE_USER_FLAG3 UINT32_C(0x00000800) +# define HEAP_SETTABLE_USER_FLAGS UINT32_C(0x00000e00) +# define HEAP_CLASS_0 UINT32_C(0x00000000) +# define HEAP_CLASS_1 UINT32_C(0x00001000) +# define HEAP_CLASS_2 UINT32_C(0x00002000) +# define HEAP_CLASS_3 UINT32_C(0x00003000) +# define HEAP_CLASS_4 UINT32_C(0x00004000) +# define HEAP_CLASS_5 UINT32_C(0x00005000) +# define HEAP_CLASS_6 UINT32_C(0x00006000) +# define HEAP_CLASS_7 UINT32_C(0x00007000) +# define HEAP_CLASS_8 UINT32_C(0x00008000) +# define HEAP_CLASS_MASK UINT32_C(0x0000f000) +# endif +# define HEAP_CLASS_PROCESS HEAP_CLASS_0 +# define HEAP_CLASS_PRIVATE HEAP_CLASS_1 +# define HEAP_CLASS_KERNEL HEAP_CLASS_2 +# define HEAP_CLASS_GDI HEAP_CLASS_3 +# define HEAP_CLASS_USER HEAP_CLASS_4 +# define HEAP_CLASS_CONSOLE HEAP_CLASS_5 +# define HEAP_CLASS_USER_DESKTOP HEAP_CLASS_6 +# define HEAP_CLASS_CSRSS_SHARED HEAP_CLASS_7 +# define HEAP_CLASS_CSRSS_PORT HEAP_CLASS_8 +# ifdef IPRT_NT_USE_WINTERNL +/*# define HEAP_CREATE_ALIGN_16 UINT32_C(0x00010000) +# define HEAP_CREATE_ENABLE_TRACING UINT32_C(0x00020000) +# define HEAP_CREATE_ENABLE_EXECUTE UINT32_C(0x00040000)*/ +# define HEAP_CREATE_VALID_MASK UINT32_C(0x0007f0ff) +# endif /* IPRT_NT_USE_WINTERNL */ +/** @} */ +# ifdef IPRT_NT_USE_WINTERNL +/** @name Heap tagging constants + * @{ */ +# define HEAP_GLOBAL_TAG UINT32_C(0x00000800) +/*# define HEAP_MAXIMUM_TAG UINT32_C(0x00000fff) +# define HEAP_PSEUDO_TAG_FLAG UINT32_C(0x00008000) +# define HEAP_TAG_SHIFT 18 */ +# define HEAP_TAG_MASK (HEAP_MAXIMUM_TAG << HEAP_TAG_SHIFT) +/** @} */ +RT_DECL_NTAPI(PVOID) RtlAllocateHeap(HANDLE hHeap, ULONG fFlags, SIZE_T cb); +RT_DECL_NTAPI(PVOID) RtlReAllocateHeap(HANDLE hHeap, ULONG fFlags, PVOID pvOld, SIZE_T cbNew); +RT_DECL_NTAPI(BOOLEAN) RtlFreeHeap(HANDLE hHeap, ULONG fFlags, PVOID pvMem); +# endif /* IPRT_NT_USE_WINTERNL */ +RT_DECL_NTAPI(SIZE_T) RtlCompactHeap(HANDLE hHeap, ULONG fFlags); +RT_DECL_NTAPI(SIZE_T) RtlSizeHeap(HANDLE hHeap, ULONG fFlags, PVOID pvMem); +RT_DECL_NTAPI(NTSTATUS) RtlGetLastNtStatus(VOID); +RT_DECL_NTAPI(ULONG) RtlGetLastWin32Error(VOID); +RT_DECL_NTAPI(VOID) RtlSetLastWin32Error(ULONG uError); +RT_DECL_NTAPI(VOID) RtlSetLastWin32ErrorAndNtStatusFromNtStatus(NTSTATUS rcNt); +RT_DECL_NTAPI(VOID) RtlRestoreLastWin32Error(ULONG uError); +RT_DECL_NTAPI(BOOLEAN) RtlQueryPerformanceCounter(PLARGE_INTEGER); +RT_DECL_NTAPI(uint64_t) RtlGetSystemTimePrecise(VOID); +typedef uint64_t (NTAPI * PFNRTLGETSYSTEMTIMEPRECISE)(VOID); +RT_DECL_NTAPI(uint64_t) RtlGetInterruptTimePrecise(uint64_t *puPerfTime); +typedef uint64_t (NTAPI * PFNRTLGETINTERRUPTTIMEPRECISE)(uint64_t *); +RT_DECL_NTAPI(BOOLEAN) RtlQueryUnbiasedInterruptTime(uint64_t *puInterruptTime); +typedef BOOLEAN (NTAPI * PFNRTLQUERYUNBIASEDINTERRUPTTIME)(uint64_t *); + +RT_C_DECLS_END +/** @} */ +#endif /* IN_RING3 */ + +#endif /* !IPRT_INCLUDED_nt_nt_h */ + diff --git a/include/iprt/nt/ntddk.h b/include/iprt/nt/ntddk.h new file mode 100644 index 00000000..51313368 --- /dev/null +++ b/include/iprt/nt/ntddk.h @@ -0,0 +1,83 @@ +/** @file + * Safe way to include ntddk.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_ntddk_h +#define IPRT_INCLUDED_nt_ntddk_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Make sure we get the right prototypes. */ +#include <iprt/sanitized/intrin.h> + +#define _InterlockedExchange _InterlockedExchange_StupidDDKVsCompilerCrap +#define _InterlockedExchangeAdd _InterlockedExchangeAdd_StupidDDKVsCompilerCrap +#define _InterlockedCompareExchange _InterlockedCompareExchange_StupidDDKVsCompilerCrap +#define _InterlockedAddLargeStatistic _InterlockedAddLargeStatistic_StupidDDKVsCompilerCrap +#define _interlockedbittestandset _interlockedbittestandset_StupidDDKVsCompilerCrap +#define _interlockedbittestandreset _interlockedbittestandreset_StupidDDKVsCompilerCrap +#define _interlockedbittestandset64 _interlockedbittestandset64_StupidDDKVsCompilerCrap +#define _interlockedbittestandreset64 _interlockedbittestandreset64_StupidDDKVsCompilerCrap + +#pragma warning(push) +#pragma warning(disable:4163) +#pragma warning(disable:4668) /* warning C4668: 'WHEA_DOWNLEVEL_TYPE_NAMES' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +#pragma warning(disable:4255) /* warning C4255: 'ObGetFilterVersion' : no function prototype given: converting '()' to '(void)' */ +#if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# pragma warning(disable:4471) /* wdm.h(11057) : warning C4471: '_POOL_TYPE' : a forward declaration of an unscoped enumeration must have an underlying type (int assumed) */ +#endif + +/* Include the sdk/ddk version header so _WIN32_VER and the rest gets defined before ntdef.h is included, + otherwise we'll miss out on DECLARE_GLOBAL_CONST_UNICODE_STRING and friends in the W10 SDKs. */ +#define DECLSPEC_DEPRECATED_DDK +#include <sdkddkver.h> + +/*RT_C_DECLS_BEGIN - no longer necessary it seems */ +#include <ntddk.h> +/*RT_C_DECLS_END - no longer necessary it seems */ +#pragma warning(pop) + +#undef _InterlockedExchange +#undef _InterlockedExchangeAdd +#undef _InterlockedCompareExchange +#undef _InterlockedAddLargeStatistic +#undef _interlockedbittestandset +#undef _interlockedbittestandreset +#undef _interlockedbittestandset64 +#undef _interlockedbittestandreset64 + +#endif /* !IPRT_INCLUDED_nt_ntddk_h */ + diff --git a/include/iprt/nt/rx.h b/include/iprt/nt/rx.h new file mode 100644 index 00000000..99c40d4a --- /dev/null +++ b/include/iprt/nt/rx.h @@ -0,0 +1,65 @@ +/** @file + * Safe way to include rx.h (DDK/IFS). + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_rx_h +#define IPRT_INCLUDED_nt_rx_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4668) /* rxovride.h(38) : warning C4668: 'DBG' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# pragma warning(disable: 4100) /* Fcb.h(1558) : warning C4100: 'SrvOpen' : unreferenced formal parameter */ +# pragma warning(disable: 4115) /* rxce.h(106) : warning C4115: '_ADAPTER_STATUS' : named type definition in parentheses */ +# ifndef __cplusplus +# pragma warning(disable: 4255) /* rxworkq.h(235) : warning C4255: 'RxInitializeDispatcher' : no function prototype given: converting '()' to '(void)' */ +# endif +#endif + +RT_C_DECLS_BEGIN + +#include <rx.h> + +RT_C_DECLS_END + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_nt_rx_h */ + diff --git a/include/iprt/nt/tdikrnl.h b/include/iprt/nt/tdikrnl.h new file mode 100644 index 00000000..94446f72 --- /dev/null +++ b/include/iprt/nt/tdikrnl.h @@ -0,0 +1,50 @@ +/** @file + * Safe way to include tdikrnl.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_tdikrnl_h +#define IPRT_INCLUDED_nt_tdikrnl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#pragma warning(push) +#pragma warning(disable:4668) /* warning C4668: 'NTDDI_WINS03' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +RT_C_DECLS_BEGIN +#include <tdikrnl.h> +RT_C_DECLS_END +#pragma warning(pop) + +#endif /* !IPRT_INCLUDED_nt_tdikrnl_h */ + diff --git a/include/iprt/nt/vid.h b/include/iprt/nt/vid.h new file mode 100644 index 00000000..a319af67 --- /dev/null +++ b/include/iprt/nt/vid.h @@ -0,0 +1,313 @@ +/** @file + * Virtualization Infrastructure Driver (VID) API. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_vid_h +#define IPRT_INCLUDED_nt_vid_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "hyperv.h" + + +/** + * Output from VidMessageSlotMap. + */ +typedef struct VID_MAPPED_MESSAGE_SLOT +{ + /** The message block mapping. */ + struct _HV_MESSAGE *pMsgBlock; + /** Copy of input iCpu. */ + uint32_t iCpu; + /** Explicit padding. */ + uint32_t uParentAdvisory; +} VID_MAPPED_MESSAGE_SLOT; +/** Pointer to VidMessageSlotMap output structure. */ +typedef VID_MAPPED_MESSAGE_SLOT *PVID_MAPPED_MESSAGE_SLOT; + + +/** @name VID_MESSAGE_MAPPING_HEADER::enmVidMsgType values (wild guess). + * @{ */ +/** Type mask, strips flags. */ +#define VID_MESSAGE_TYPE_MASK UINT32_C(0x00ffffff) +/** No return message necessary. */ +#define VID_MESSAGE_TYPE_FLAG_NO_RETURN UINT32_C(0x01000000) +/** Observed message values. */ +typedef enum +{ + /** Invalid zero value. */ + VidMessageInvalid = 0, + /** Guessing this means a message from the hypervisor. */ + VidMessageHypervisorMessage = 0x00000c | VID_MESSAGE_TYPE_FLAG_NO_RETURN, + /** Guessing this means stop request completed. Message length is 1 byte. */ + VidMessageStopRequestComplete = 0x00000d | VID_MESSAGE_TYPE_FLAG_NO_RETURN, +} VID_MESSAGE_TYPE; +AssertCompileSize(VID_MESSAGE_TYPE, 4); +/** @} */ + +/** + * Header of the message mapping returned by VidMessageSlotMap. + */ +typedef struct VID_MESSAGE_MAPPING_HEADER +{ + /** Current guess is that this is VID_MESSAGE_TYPE. */ + VID_MESSAGE_TYPE enmVidMsgType; + /** The message size or so it seems (0x100). */ + uint32_t cbMessage; + /** So far these have been zero. */ + uint32_t aZeroPPadding[2+4]; +} VID_MESSAGE_MAPPING_HEADER; +AssertCompileSize(VID_MESSAGE_MAPPING_HEADER, 32); + +/** + * VID processor status (VidGetVirtualProcessorRunningStatus). + * + * @note This is used internally in VID.SYS, in 17101 it's at offset 8 in their + * 'pVCpu' structure. + */ +typedef enum +{ + VidProcessorStatusStopped = 0, + VidProcessorStatusRunning, + VidProcessorStatusSuspended, + VidProcessorStatusUndefined = 0xffff +} VID_PROCESSOR_STATUS; +AssertCompileSize(VID_PROCESSOR_STATUS, 4); + + +/** I/O control input for VidMessageSlotHandleAndGetNext. */ +typedef struct VID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT +{ + HV_VP_INDEX iCpu; + uint32_t fFlags; /**< VID_MSHAGN_F_GET_XXX*/ + uint32_t cMillies; /**< Not present in build 17758 as the API changed to always to infinite waits. */ +} VID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT; +/** Pointer to input for VidMessageSlotHandleAndGetNext. */ +typedef VID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT *PVID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT; +/** Pointer to const input for VidMessageSlotHandleAndGetNext. */ +typedef VID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT const *PCVID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT; + +/** @name VID_MSHAGN_F_GET_XXX - Flags for VidMessageSlotHandleAndGetNext + * @{ */ +/** This will try get the next message, waiting if necessary. + * It is subject to NtAlertThread processing when it starts waiting. */ +#define VID_MSHAGN_F_GET_NEXT_MESSAGE RT_BIT_32(0) +/** ACK the message as handled and resume execution/whatever. + * This is executed before VID_MSHAGN_F_GET_NEXT_MESSAGE and should not be + * subject to NtAlertThread side effects. */ +#define VID_MSHAGN_F_HANDLE_MESSAGE RT_BIT_32(1) +/** Cancel VP execution (no other bit set). + * @since about build 17758. */ +#define VID_MSHAGN_F_CANCEL RT_BIT_32(2) +/** @} */ + +/** A 64-bit version of HV_PARTITION_PROPERTY_CODE. */ +typedef int64_t VID_PARTITION_PROPERTY_CODE; + + +#ifdef IN_RING3 +RT_C_DECLS_BEGIN + +/** Calling convention. */ +#ifndef WINAPI +# define VIDAPI __stdcall +#else +# define VIDAPI WINAPI +#endif + +/** Partition handle. */ +#ifndef WINAPI +typedef void *VID_PARTITION_HANDLE; +#else +typedef HANDLE VID_PARTITION_HANDLE; +#endif + +/** + * Gets the partition ID. + * + * The partition ID is the numeric identifier used when making hypercalls to the + * hypervisor. + * + * @note Starting with Windows 11 (or possibly earlier), this does not work on + * Exo partition as created by WHvCreatePartition. It returns a + * STATUS_NOT_IMPLEMENTED as the I/O control code is not allowed through. + * All partitions has an ID though, so just pure annoying blockheadedness + * sprung upon us w/o any chance of doing a memory managment rewrite in + * time. + */ +DECLIMPORT(BOOL) VIDAPI VidGetHvPartitionId(VID_PARTITION_HANDLE hPartition, HV_PARTITION_ID *pidPartition); + +/** + * Get a partition property. + * + * @returns Success indicator (details in LastErrorValue). + * @param hPartition The partition handle. + * @param enmProperty The property to get. Is a HV_PARTITION_PROPERTY_CODE + * type, but seems to be passed around as a 64-bit integer + * for some reason. + * @param puValue Where to return the property value. + */ +DECLIMPORT(BOOL) VIDAPI VidGetPartitionProperty(VID_PARTITION_HANDLE hPartition, VID_PARTITION_PROPERTY_CODE enmProperty, + PHV_PARTITION_PROPERTY puValue); + +/** + * @copydoc VidGetPartitionProperty + * @note Currently (Windows 11 GA) identical to VidGetPartitionProperty. + */ +DECLIMPORT(BOOL) VIDAPI VidGetExoPartitionProperty(VID_PARTITION_HANDLE hPartition, VID_PARTITION_PROPERTY_CODE enmProperty, + PHV_PARTITION_PROPERTY puValue); + +/** + * Starts asynchronous execution of a virtual CPU. + */ +DECLIMPORT(BOOL) VIDAPI VidStartVirtualProcessor(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu); + +/** + * Stops the asynchronous execution of a virtual CPU. + * + * @retval ERROR_VID_STOP_PENDING if busy with intercept, check messages. + */ +DECLIMPORT(BOOL) VIDAPI VidStopVirtualProcessor(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu); + +/** + * WHvCreateVirtualProcessor boils down to a call to VidMessageSlotMap and + * some internal WinHvPlatform state fiddling. + * + * Looks like it maps memory and returns the pointer to it. + * VidMessageSlotHandleAndGetNext is later used to wait for the next message and + * put (??) it into that memory mapping. + * + * @returns Success indicator (details in LastErrorValue). + * + * @param hPartition The partition handle. + * @param pOutput Where to return the pointer to the message memory + * mapping. The CPU index is also returned here. + * @param iCpu The CPU to wait-and-get messages for. + */ +DECLIMPORT(BOOL) VIDAPI VidMessageSlotMap(VID_PARTITION_HANDLE hPartition, PVID_MAPPED_MESSAGE_SLOT pOutput, HV_VP_INDEX iCpu); + +/** + * This is used by WHvRunVirtualProcessor to wait for the next exit msg. + * + * The message appears in the memory mapping returned by VidMessageSlotMap. + * + * @returns Success indicator (details only in LastErrorValue - LastStatusValue + * is not set). + * @retval STATUS_TIMEOUT for STATUS_TIMEOUT as well as STATUS_USER_APC and + * STATUS_ALERTED. + * + * @param hPartition The partition handle. + * @param iCpu The CPU to wait-and-get messages for. + * @param fFlags Flags, VID_MSHAGN_F_XXX. + * + * When starting or resuming execution, at least one of + * VID_MSHAGN_F_GET_NEXT_MESSAGE (bit 0) and + * VID_MSHAGN_F_HANDLE_MESSAGE (bit 1) must be set. + * + * When cancelling execution only VID_MSHAGN_F_CANCEL (big 2) + * must be set. + * + * @param cMillies The timeout, presumably in milliseconds. This parameter + * was dropped about build 17758. + * + * @todo Would be awfully nice if someone at Microsoft could hit at the + * flags here. + */ +DECLIMPORT(BOOL) VIDAPI VidMessageSlotHandleAndGetNext(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu, + uint32_t fFlags, uint32_t cMillies); +/** + * Gets the processor running status. + * + * This is probably only available in special builds, as one of the early I/O + * control dispatching routines will not let it thru. Lower down routines does + * implement it, so it's possible to patch it into working. This works for + * build 17101: eb vid+12180 0f 84 98 00 00 00 + * + * @retval ERROR_NOT_IMPLEMENTED + * + * @remarks VidExoFastIoControlPartition probably disapproves of this too. It + * could be very handy for debugging upon occation. + */ +DECLIMPORT(BOOL) VIDAPI VidGetVirtualProcessorRunningStatus(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu, + VID_PROCESSOR_STATUS *penmStatus); + +/** + * For query virtual processor registers and other state information. + * + * @returns Success indicator (details in LastErrorValue). + */ +DECLIMPORT(BOOL) VIDAPI VidGetVirtualProcessorState(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu, + HV_REGISTER_NAME const *paRegNames, uint32_t cRegisters, + HV_REGISTER_VALUE *paRegValues); + +/** + * For setting virtual processor registers and other state information. + * + * @returns Success indicator (details in LastErrorValue). + */ +DECLIMPORT(BOOL) VIDAPI VidSetVirtualProcessorState(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu, + HV_REGISTER_NAME const *paRegNames, uint32_t cRegisters, + HV_REGISTER_VALUE const *paRegValues); + +/** + * Wrapper around the HvCallGetMemoryBalance hypercall. + * + * When VID.SYS processes the request, it will also query + * HvPartitionPropertyVirtualTlbPageCount, so we're passing a 3rd return + * parameter in case the API is ever extended to match the I/O control. + * + * @returns Success indicator (details in LastErrorValue). + * @retval ERROR_NOT_IMPLEMENTED for exo partitions. + * + * @param hPartition The partition handle. + * @param pcPagesAvailable Where to return the number of unused pages + * still available to the partition. + * @param pcPagesInUse Where to return the number of pages currently + * in use by the partition. + * @param pReserved Pointer to dummy value, just in case they + * modify the API to include the nested TLB size. + * + * @note Not available for exo partitions, unfortunately. The + * VidExoFastIoControlPartition function deflects it, failing it with + * STATUS_NOT_IMPLEMENTED / ERROR_NOT_IMPLEMENTED. + */ +DECLIMPORT(BOOL) VIDAPI VidGetHvMemoryBalance(VID_PARTITION_HANDLE hPartition, uint64_t *pcPagesAvailable, + uint64_t *pcPagesInUse, uint64_t *pReserved); + +RT_C_DECLS_END +#endif /* IN_RING3 */ + +#endif /* !IPRT_INCLUDED_nt_vid_h */ + diff --git a/include/iprt/nt/video.h b/include/iprt/nt/video.h new file mode 100644 index 00000000..f48ab5ab --- /dev/null +++ b/include/iprt/nt/video.h @@ -0,0 +1,59 @@ +/** @file + * Safe way to include video.h (DDK). + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_video_h +#define IPRT_INCLUDED_nt_video_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* warning C4668: 'DBG' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# ifndef __cplusplus +# pragma warning(disable:4255) /* warning C4255: 'VideoPortGetCurrentIrql' : no function prototype given: converting '()' to '(void)'*/ +# endif +#endif + +#include <video.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_nt_video_h */ + diff --git a/include/iprt/nt/wdm.h b/include/iprt/nt/wdm.h new file mode 100644 index 00000000..06560e90 --- /dev/null +++ b/include/iprt/nt/wdm.h @@ -0,0 +1,81 @@ +/** @file + * Safe way to include wdm.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_nt_wdm_h +#define IPRT_INCLUDED_nt_wdm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Make sure we get the right prototypes. */ +#include <iprt/sanitized/intrin.h> + +#define _InterlockedExchange _InterlockedExchange_StupidDDKVsCompilerCrap +#define _InterlockedExchangeAdd _InterlockedExchangeAdd_StupidDDKVsCompilerCrap +#define _InterlockedCompareExchange _InterlockedCompareExchange_StupidDDKVsCompilerCrap +#define _InterlockedAddLargeStatistic _InterlockedAddLargeStatistic_StupidDDKVsCompilerCrap +#define _interlockedbittestandset _interlockedbittestandset_StupidDDKVsCompilerCrap +#define _interlockedbittestandreset _interlockedbittestandreset_StupidDDKVsCompilerCrap +#define _interlockedbittestandset64 _interlockedbittestandset64_StupidDDKVsCompilerCrap +#define _interlockedbittestandreset64 _interlockedbittestandreset64_StupidDDKVsCompilerCrap + +#pragma warning(push) +#pragma warning(disable:4163) +#pragma warning(disable:4668) /* warning C4668: 'WHEA_DOWNLEVEL_TYPE_NAMES' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +#pragma warning(disable:4255) /* warning C4255: 'ObGetFilterVersion' : no function prototype given: converting '()' to '(void)' */ +#pragma warning(disable:4005) /* wdm.h(29) : warning C4005: 'NO_INTERLOCKED_INTRINSICS' : macro redefinition */ +#if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# pragma warning(disable:4471) /* wdm.h(11057) : warning C4471: '_POOL_TYPE' : a forward declaration of an unscoped enumeration must have an underlying type (int assumed) */ +#endif +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# ifdef __cplusplus +# pragma warning(disable:5039) /* warning C5039: 'KeInitializeDpc': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +#include <wdm.h> +#pragma warning(pop) + +#undef _InterlockedExchange +#undef _InterlockedExchangeAdd +#undef _InterlockedCompareExchange +#undef _InterlockedAddLargeStatistic +#undef _interlockedbittestandset +#undef _interlockedbittestandreset +#undef _interlockedbittestandset64 +#undef _interlockedbittestandreset64 + +#endif /* !IPRT_INCLUDED_nt_wdm_h */ + diff --git a/include/iprt/once.h b/include/iprt/once.h new file mode 100644 index 00000000..eb734e79 --- /dev/null +++ b/include/iprt/once.h @@ -0,0 +1,231 @@ +/** @file + * IPRT - Execute Once. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_once_h +#define IPRT_INCLUDED_once_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/asm.h> +#include <iprt/errcore.h> +#include <iprt/list.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_once RTOnce - Execute Once + * @ingroup grp_rt + * @{ + */ + +/** + * Callback that gets executed once. + * + * @returns IPRT style status code, RTOnce returns this. + * + * @param pvUser The user parameter. + */ +typedef DECLCALLBACKTYPE(int32_t, FNRTONCE,(void *pvUser)); +/** Pointer to a FNRTONCE. */ +typedef FNRTONCE *PFNRTONCE; + +/** + * Callback that gets executed on IPRT/process termination. + * + * @param pvUser The user parameter. + * @param fLazyCleanUpOk Indicates whether lazy clean-up is OK (see + * initterm.h). + */ +typedef DECLCALLBACKTYPE(void, FNRTONCECLEANUP,(void *pvUser, bool fLazyCleanUpOk)); +/** Pointer to a FNRTONCE. */ +typedef FNRTONCECLEANUP *PFNRTONCECLEANUP; + +/** + * Execute once structure. + * + * This is typically a global variable that is statically initialized + * by RTONCE_INITIALIZER. + */ +typedef struct RTONCE +{ + /** Event semaphore that the other guys are blocking on. */ + RTSEMEVENTMULTI volatile hEventMulti; + /** Reference counter for hEventMulti. */ + int32_t volatile cEventRefs; + /** See RTONCESTATE. */ + int32_t volatile iState; + /** The return code of pfnOnce. */ + int32_t volatile rc; + + /** Pointer to the clean-up function. */ + PFNRTONCECLEANUP pfnCleanUp; + /** Argument to hand to the clean-up function. */ + void *pvUser; + /** Clean-up list entry. */ + RTLISTNODE CleanUpNode; +} RTONCE; +/** Pointer to a execute once struct. */ +typedef RTONCE *PRTONCE; + +/** + * The execute once statemachine. + */ +typedef enum RTONCESTATE +{ + /** RTOnce() has not been called. + * Next: NO_SEM */ + RTONCESTATE_UNINITIALIZED = 1, + /** RTOnce() is busy, no race. + * Next: CREATING_SEM, DONE */ + RTONCESTATE_BUSY_NO_SEM, + /** More than one RTOnce() caller is busy. + * Next: BUSY_HAVE_SEM, BUSY_SPIN, DONE_CREATING_SEM, DONE */ + RTONCESTATE_BUSY_CREATING_SEM, + /** More than one RTOnce() caller, the first is busy, the others are + * waiting. + * Next: DONE */ + RTONCESTATE_BUSY_HAVE_SEM, + /** More than one RTOnce() caller, the first is busy, the others failed to + * create a semaphore and are spinning. + * Next: DONE */ + RTONCESTATE_BUSY_SPIN, + /** More than one RTOnce() caller, the first has completed, the others + * are busy creating the semaphore. + * Next: DONE_HAVE_SEM */ + RTONCESTATE_DONE_CREATING_SEM, + /** More than one RTOnce() caller, the first is busy grabbing the + * semaphore, while the others are waiting. + * Next: DONE */ + RTONCESTATE_DONE_HAVE_SEM, + /** The execute once stuff has completed. */ + RTONCESTATE_DONE = 16 +} RTONCESTATE; + +/** Static initializer for RTONCE variables. */ +#define RTONCE_INITIALIZER \ + { NIL_RTSEMEVENTMULTI, 0, RTONCESTATE_UNINITIALIZED, VERR_INTERNAL_ERROR, NULL, NULL, { NULL, NULL } } + + +/** + * Serializes execution of the pfnOnce function, making sure it's + * executed exactly once and that nobody returns from RTOnce before + * it has executed successfully. + * + * @returns IPRT like status code returned by pfnOnce. + * + * @param pOnce Pointer to the execute once variable. + * @param pfnOnce The function to executed once. + * @param pfnCleanUp The function that will be doing the cleaning up. + * Optional. + * @param pvUser The user parameter for pfnOnce. + */ +RTDECL(int) RTOnceSlow(PRTONCE pOnce, PFNRTONCE pfnOnce, FNRTONCECLEANUP pfnCleanUp, void *pvUser); + +/** + * Serializes execution of the pfnOnce function, making sure it's + * executed exactly once and that nobody returns from RTOnce before + * it has executed successfully. + * + * @returns IPRT like status code returned by pfnOnce. + * + * @param pOnce Pointer to the execute once variable. + * @param pfnOnce The function to executed once. + * @param pvUser The user parameter for pfnOnce. + */ +DECLINLINE(int) RTOnce(PRTONCE pOnce, PFNRTONCE pfnOnce, void *pvUser) +{ + int32_t iState = ASMAtomicUoReadS32(&pOnce->iState); + if (RT_LIKELY( iState == RTONCESTATE_DONE + || iState == RTONCESTATE_DONE_CREATING_SEM + || iState == RTONCESTATE_DONE_HAVE_SEM )) + return ASMAtomicUoReadS32(&pOnce->rc); + return RTOnceSlow(pOnce, pfnOnce, NULL, pvUser); +} + +/** + * Execute pfnOnce once and register a termination clean-up callback. + * + * Serializes execution of the pfnOnce function, making sure it's + * executed exactly once and that nobody returns from RTOnce before + * it has executed successfully. + * + * @returns IPRT like status code returned by pfnOnce. + * + * @param pOnce Pointer to the execute once variable. + * @param pfnOnce The function to executed once. + * @param pfnCleanUp The function that will be doing the cleaning up. + * @param pvUser The user parameter for pfnOnce. + */ +DECLINLINE(int) RTOnceEx(PRTONCE pOnce, PFNRTONCE pfnOnce, PFNRTONCECLEANUP pfnCleanUp, void *pvUser) +{ + int32_t iState = ASMAtomicUoReadS32(&pOnce->iState); + if (RT_LIKELY( iState == RTONCESTATE_DONE + || iState == RTONCESTATE_DONE_CREATING_SEM + || iState == RTONCESTATE_DONE_HAVE_SEM )) + return ASMAtomicUoReadS32(&pOnce->rc); + return RTOnceSlow(pOnce, pfnOnce, pfnCleanUp, pvUser); +} + +/** + * Resets an execute once variable. + * + * The caller is responsible for making sure there are no concurrent accesses to + * the execute once variable. + * + * @param pOnce Pointer to the execute once variable. + */ +RTDECL(void) RTOnceReset(PRTONCE pOnce); + +/** + * Check whether the execute once variable was successfullly initialized. + */ +DECLINLINE(bool) RTOnceWasInitialized(PRTONCE pOnce) +{ + int32_t const iState = ASMAtomicUoReadS32(&pOnce->iState); + int32_t const rc = ASMAtomicUoReadS32(&pOnce->rc); + return RT_SUCCESS(rc) + && ( iState == RTONCESTATE_DONE + || iState == RTONCESTATE_DONE_CREATING_SEM + || iState == RTONCESTATE_DONE_HAVE_SEM); +} + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_once_h */ + diff --git a/include/iprt/param.h b/include/iprt/param.h new file mode 100644 index 00000000..224064b6 --- /dev/null +++ b/include/iprt/param.h @@ -0,0 +1,137 @@ +/** @file + * IPRT - Parameter Definitions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_param_h +#define IPRT_INCLUDED_param_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> + +/** @todo Much of the PAGE_* stuff here is obsolete and highly risky to have around. + * As for component configs (MM_*), either we gather all in here or we move those bits away! */ + +/** @defgroup grp_rt_param System Parameter Definitions + * @ingroup grp_rt_cdefs + * @{ + */ + +/* Undefine PAGE_SIZE and PAGE_SHIFT to avoid unnecessary noice when clashing + * with system headers. Include system headers before / after iprt depending + * on which you wish to take precedence. */ +#undef PAGE_SIZE +#undef PAGE_SHIFT + +/* Undefine PAGE_OFFSET_MASK to avoid the conflict with the-linux-kernel.h */ +#undef PAGE_OFFSET_MASK + +/** + * i386 Page size. + */ +#if defined(RT_ARCH_SPARC64) +# define PAGE_SIZE 8192 +#elif defined(RT_ARCH_ARM64) +# define PAGE_SIZE 16384 +#else +# define PAGE_SIZE 4096 +#endif + +/** + * i386 Page shift. + * This is used to convert between size (in bytes) and page count. + */ +#if defined(RT_ARCH_SPARC64) +# define PAGE_SHIFT 13 +#elif defined(RT_ARCH_ARM64) +# define PAGE_SHIFT 14 +#else +# define PAGE_SHIFT 12 +#endif + +/** + * i386 Page offset mask. + * + * @note If you do one-complement this, always insert a target type case after + * the operator! Otherwise you may end up with weird results. + */ +#if defined(RT_ARCH_SPARC64) +# define PAGE_OFFSET_MASK 0x1fff +#elif defined(RT_ARCH_ARM64) +# define PAGE_OFFSET_MASK 0x3fff +#else +# define PAGE_OFFSET_MASK 0xfff +#endif + +/** + * Page address mask for the uintptr_t sized pointers. + * + * Be careful when using this since it may be a size too big! + * @remark Physical addresses are always masked using X86_PTE_PAE_PG_MASK! + */ +#define PAGE_BASE_MASK (~(uintptr_t)PAGE_OFFSET_MASK) + +/** + * Get the page aligned address of a POINTER in the CURRENT context. + * + * @returns Page aligned address (it's an uintptr_t). + * @param pv The virtual address to align. + * + * @remarks Physical addresses are always masked using X86_PTE_PAE_PG_MASK! + * @remarks This only works with POINTERS in the current context. + * Do NOT use on guest address or physical address! + */ +#define PAGE_ADDRESS(pv) ((uintptr_t)(pv) & ~(uintptr_t)PAGE_OFFSET_MASK) + +/** + * Get the page aligned address of a physical address + * + * @returns Page aligned address (it's an RTHCPHYS or RTGCPHYS). + * @param Phys The physical address to align. + */ +#define PHYS_PAGE_ADDRESS(Phys) ((Phys) & X86_PTE_PAE_PG_MASK) + +/** + * Host max path (the reasonable value). + * @remarks defined both by iprt/param.h and iprt/path.h. + */ +#if !defined(IPRT_INCLUDED_path_h) || defined(DOXYGEN_RUNNING) +# define RTPATH_MAX (4096 + 4) /* (PATH_MAX + 1) on linux w/ some alignment */ +#endif + +/** @} */ + +#endif /* !IPRT_INCLUDED_param_h */ + diff --git a/include/iprt/path.h b/include/iprt/path.h new file mode 100644 index 00000000..285d9f19 --- /dev/null +++ b/include/iprt/path.h @@ -0,0 +1,1674 @@ +/** @file + * IPRT - Path Manipulation. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_path_h +#define IPRT_INCLUDED_path_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#ifdef IN_RING3 +# include <iprt/fs.h> +#endif + + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_path RTPath - Path Manipulation + * @ingroup grp_rt + * @{ + */ + +/** + * Host max path (the reasonable value). + * @remarks defined both by iprt/param.h and iprt/path.h. + */ +#if !defined(IPRT_INCLUDED_param_h) || defined(DOXYGEN_RUNNING) +# define RTPATH_MAX (4096 + 4) /* (PATH_MAX + 1) on linux w/ some alignment */ +#endif + +/** + * The absolute max host path length we are willing to support. + * @note Not really suitable for stack buffers. + */ +#define RTPATH_BIG_MAX (_64K) + +/** @def RTPATH_TAG + * The default allocation tag used by the RTPath allocation APIs. + * + * When not defined before the inclusion of iprt/string.h, this will default to + * the pointer to the current file name. The string API will make of use of + * this as pointer to a volatile but read-only string. + */ +#ifndef RTPATH_TAG +# define RTPATH_TAG (__FILE__) +#endif + + +/** @name RTPATH_F_XXX - Generic flags for APIs working on the file system. + * @{ */ +/** Last component: Work on the link. */ +#define RTPATH_F_ON_LINK RT_BIT_32(0) +/** Last component: Follow if link. */ +#define RTPATH_F_FOLLOW_LINK RT_BIT_32(1) +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTPATH_F_NO_SYMLINKS RT_BIT_32(2) +/** Current RTPATH_F_XXX flag mask. */ +#define RTPATH_F_MASK UINT32_C(0x00000007) +/** @} */ + +/** Validates a flags parameter containing RTPATH_F_*. + * @remarks The parameters will be referenced multiple times. */ +#define RTPATH_F_IS_VALID(a_fFlags, a_fIgnore) \ + ( ((a_fFlags) & ~(uint32_t)((a_fIgnore) | RTPATH_F_NO_SYMLINKS)) == RTPATH_F_ON_LINK \ + || ((a_fFlags) & ~(uint32_t)((a_fIgnore) | RTPATH_F_NO_SYMLINKS)) == RTPATH_F_FOLLOW_LINK ) + + +/** @name RTPATH_STR_F_XXX - Generic flags for APIs working with path strings. + * @{ + */ +/** Host OS path style (default 0 value). */ +#define RTPATH_STR_F_STYLE_HOST UINT32_C(0x00000000) +/** DOS, OS/2 and Windows path style. */ +#define RTPATH_STR_F_STYLE_DOS UINT32_C(0x00000001) +/** Unix path style. */ +#define RTPATH_STR_F_STYLE_UNIX UINT32_C(0x00000002) +/** Reserved path style. */ +#define RTPATH_STR_F_STYLE_RESERVED UINT32_C(0x00000003) +/** The path style mask. */ +#define RTPATH_STR_F_STYLE_MASK UINT32_C(0x00000003) +/** Partial path - no start. + * This causes the API to skip the root specification parsing. */ +#define RTPATH_STR_F_NO_START UINT32_C(0x00000010) +/** Partial path - no end. + * This causes the API to skip the filename and dir-slash parsing. */ +#define RTPATH_STR_F_NO_END UINT32_C(0x00000020) +/** Partial path - no start and no end. */ +#define RTPATH_STR_F_MIDDLE (RTPATH_STR_F_NO_START | RTPATH_STR_F_NO_END) + +/** Reserved for future use. */ +#define RTPATH_STR_F_RESERVED_MASK UINT32_C(0x0000ffcc) +/** @} */ + +/** Validates a flags parameter containing RTPATH_FSTR_. + * @remarks The parameters will be references multiple times. */ +#define RTPATH_STR_F_IS_VALID(a_fFlags, a_fIgnore) \ + ( ((a_fFlags) & ~((uint32_t)(a_fIgnore) | RTPATH_STR_F_STYLE_MASK | RTPATH_STR_F_MIDDLE)) == 0 \ + && ((a_fFlags) & RTPATH_STR_F_STYLE_MASK) != RTPATH_STR_F_STYLE_RESERVED \ + && ((a_fFlags) & RTPATH_STR_F_RESERVED_MASK) == 0 ) + + +/** @def RTPATH_STYLE + * The host path style. This is set to RTPATH_STR_F_STYLE_DOS, + * RTPATH_STR_F_STYLE_UNIX, or other future styles. */ +#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) +# define RTPATH_STYLE RTPATH_STR_F_STYLE_DOS +#else +# define RTPATH_STYLE RTPATH_STR_F_STYLE_UNIX +#endif + + +/** @def RTPATH_SLASH + * The preferred slash character. + * + * @remark IPRT will always accept unix slashes. So, normally you would + * never have to use this define. + */ +#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS +# define RTPATH_SLASH '\\' +#elif RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX +# define RTPATH_SLASH '/' +#else +# error "Unsupported RTPATH_STYLE value." +#endif + +/** @deprecated Use '/'! */ +#define RTPATH_DELIMITER RTPATH_SLASH + + +/** @def RTPATH_SLASH_STR + * The preferred slash character as a string, handy for concatenations + * with other strings. + * + * @remark IPRT will always accept unix slashes. So, normally you would + * never have to use this define. + */ +#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS +# define RTPATH_SLASH_STR "\\" +#elif RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX +# define RTPATH_SLASH_STR "/" +#else +# error "Unsupported RTPATH_STYLE value." +#endif + + +/** @def RTPATH_IS_SLASH + * Checks if a character is a slash. + * + * @returns true if it's a slash and false if not. + * @returns @param a_ch Char to check. + */ +#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS +# define RTPATH_IS_SLASH(a_ch) ( (a_ch) == '\\' || (a_ch) == '/' ) +#elif RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX +# define RTPATH_IS_SLASH(a_ch) ( (a_ch) == '/' ) +#else +# error "Unsupported RTPATH_STYLE value." +#endif + + +/** @def RTPATH_IS_VOLSEP + * Checks if a character marks the end of the volume specification. + * + * @remark This is sufficient for the drive letter concept on PC. + * However it might be insufficient on other platforms + * and even on PC a UNC volume spec won't be detected this way. + * Use the RTPath@<too be created@>() instead. + * + * @returns true if it is and false if it isn't. + * @returns @param a_ch Char to check. + */ +#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS +# define RTPATH_IS_VOLSEP(a_ch) ( (a_ch) == ':' ) +#elif RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX +# define RTPATH_IS_VOLSEP(a_ch) (false) +#else +# error "Unsupported RTPATH_STYLE value." +#endif + + +/** @def RTPATH_IS_SEP + * Checks if a character is path component separator + * + * @returns true if it is and false if it isn't. + * @returns @param a_ch Char to check. + * @ + */ +#define RTPATH_IS_SEP(a_ch) ( RTPATH_IS_SLASH(a_ch) || RTPATH_IS_VOLSEP(a_ch) ) + +#if defined(RT_OS_WINDOWS) || defined(DOXYGEN_RUNNING) +/** @def RTPATH_NT_PASSTHRU_PREFIX + * Prefix used to access the NT namespace directly. + * This forms an invalid UNC name. */ +# define RTPATH_NT_PASSTHRU_PREFIX "\\\\:iprtnt:\\" +#endif + +/** + * Checks if the path exists. + * + * Symbolic links will all be attempted resolved and broken links means false. + * + * @returns true if it exists and false if it doesn't. + * @param pszPath The path to check. + */ +RTDECL(bool) RTPathExists(const char *pszPath); + +/** + * Checks if the path exists. + * + * @returns true if it exists and false if it doesn't. + * @param pszPath The path to check. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + */ +RTDECL(bool) RTPathExistsEx(const char *pszPath, uint32_t fFlags); + +/** + * Sets the current working directory of the process. + * + * @returns IPRT status code. + * @param pszPath The path to the new working directory. + */ +RTDECL(int) RTPathSetCurrent(const char *pszPath); + +/** + * Gets the current working directory of the process. + * + * @returns IPRT status code. + * @param pszPath Where to store the path. + * @param cchPath The size of the buffer pszPath points to. + */ +RTDECL(int) RTPathGetCurrent(char *pszPath, size_t cchPath); + +/** + * Gets the current working directory on the specified drive. + * + * On systems without drive letters, the root slash will be returned. + * + * @returns IPRT status code. + * @param chDrive The drive we're querying the driver letter on. + * @param pszPath Where to store the working directroy path. + * @param cbPath The size of the buffer pszPath points to. + */ +RTDECL(int) RTPathGetCurrentOnDrive(char chDrive, char *pszPath, size_t cbPath); + +/** + * Gets the current working drive of the process. + * + * Normally drive letter and colon will be returned, never trailing a root + * slash. If the current directory is on a UNC share, the root of the share + * will be returned. On systems without drive letters, an empty string is + * returned for consistency. + * + * @returns IPRT status code. + * @param pszPath Where to store the working drive or UNC root. + * @param cbPath The size of the buffer pszPath points to. + */ +RTDECL(int) RTPathGetCurrentDrive(char *pszPath, size_t cbPath); + +/** + * Get the real path (no symlinks, no . or .. components), must exist. + * + * @returns iprt status code. + * @param pszPath The path to resolve. + * @param pszRealPath Where to store the real path. + * @param cchRealPath Size of the buffer. + */ +RTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, size_t cchRealPath); + +/** + * Same as RTPathReal only the result is RTStrDup()'ed. + * + * @returns Pointer to real path. Use RTStrFree() to free this string. + * @returns NULL if RTPathReal() or RTStrDup() fails. + * @param pszPath The path to resolve. + */ +RTDECL(char *) RTPathRealDup(const char *pszPath); + +/** + * Get the absolute path (starts from root, no . or .. components), doesn't have + * to exist. + * + * Note that this method is designed to never perform actual file system access, + * therefore symlinks are not resolved. + * + * @returns iprt status code. + * @param pszPath The path to resolve. + * @param pszAbsPath Where to store the absolute path. + * @param cbAbsPath Size of the buffer. + * + * @note Current implementation is buggy and will remove trailing slashes + * that would normally specify a directory. Don't depend on this. + */ +RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cbAbsPath); + +/** + * Same as RTPathAbs only the result is RTStrDup()'ed. + * + * @returns Pointer to the absolute path. Use RTStrFree() to free this string. + * @returns NULL if RTPathAbs() or RTStrDup() fails. + * @param pszPath The path to resolve. + * + * @note Current implementation is buggy and will remove trailing slashes + * that would normally specify a directory. Don't depend on this. + */ +RTDECL(char *) RTPathAbsDup(const char *pszPath); + +/** + * Get the absolute path (no symlinks, no . or .. components), assuming the + * given base path as the current directory. + * + * The resulting path doesn't have to exist. + * + * @returns iprt status code. + * @param pszBase The base path to act like a current directory. + * When NULL, the actual cwd is used (i.e. the call + * is equivalent to RTPathAbs(pszPath, ...). + * @param pszPath The path to resolve. + * @param fFlags One of the RTPATH_STR_F_STYLE_XXX flags combined + * with any of the RTPATHABS_F_XXX ones. Most + * users will pass RTPATH_STR_F_STYLE_HOST (0). + * @param pszAbsPath Where to store the absolute path. + * @param pcbAbsPath Hold the size of the buffer when called. The return + * value is the string length on success, and the + * required (or slightly more in some case) buffer + * size, including terminator, on VERR_BUFFER_OVERFLOW + * failures. + */ +RTDECL(int) RTPathAbsEx(const char *pszBase, const char *pszPath, uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath); + +/** @name RTPATHABS_F_XXX - Flags for RTPathAbsEx. + * @note The RTPATH_F_STR_XXX style flags also applies. + * @{ */ +/** Treat specified base directory as a root that cannot be ascended beyond. */ +#define RTPATHABS_F_STOP_AT_BASE RT_BIT_32(16) +/** Treat CWD as a root that cannot be ascended beyond. */ +#define RTPATHABS_F_STOP_AT_CWD RT_BIT_32(17) +/** Ensure trailing slash in the result. */ +#define RTPATHABS_F_ENSURE_TRAILING_SLASH RT_BIT_32(18) +/** @} */ + +/** + * Same as RTPathAbsEx only the result is RTStrDup()'ed. + * + * @returns Pointer to the absolute path. Use RTStrFree() to free this string. + * @retval NULL if RTPathAbsEx() or RTStrDup() fails. + * + * @param pszBase The base path to act like a current directory. + * When NULL, the actual cwd is used (i.e. the call + * is equivalent to RTPathAbs(pszPath, ...). + * @param pszPath The path to resolve. + * @param fFlags One of the RTPATH_STR_F_STYLE_XXX flags combined + * with any of the RTPATHABS_F_XXX ones. Most + * users will pass RTPATH_STR_F_STYLE_HOST (0). + */ +RTDECL(char *) RTPathAbsExDup(const char *pszBase, const char *pszPath, uint32_t fFlags); + +/** + * Strips the filename from a path. Truncates the given string in-place by overwriting the + * last path separator character with a null byte in a platform-neutral way. + * + * @param pszPath Path from which filename should be extracted, will be truncated. + * If the string contains no path separator, it will be changed to a "." string. + */ +RTDECL(void) RTPathStripFilename(char *pszPath); + +/** + * Strips the last suffix from a path. + * + * @param pszPath Path which suffix should be stripped. + */ +RTDECL(void) RTPathStripSuffix(char *pszPath); + +/** + * Strips the trailing slashes of a path name. + * + * Won't strip root slashes. + * + * @returns The new length of pszPath. + * @param pszPath Path to strip. + */ +RTDECL(size_t) RTPathStripTrailingSlash(char *pszPath); + +/** + * Skips the root specification, if present. + * + * @return Pointer to the first char after the root specification. This can be + * pointing to the terminator, if the path is only a root + * specification. + * @param pszPath The path to skip ahead in. + */ +RTDECL(char *) RTPathSkipRootSpec(const char *pszPath); + +/** + * Ensures that the path has a trailing path separator such that file names can + * be appended without further work. + * + * This can be helpful when preparing for efficiently combining a directory path + * with the filenames returned by RTDirRead. The return value gives you the + * position at which you copy the RTDIRENTRY::szName to construct a valid path + * to it. + * + * @returns The length of the path, 0 on buffer overflow. + * @param pszPath The path. + * @param cbPath The length of the path buffer @a pszPath points to. + */ +RTDECL(size_t) RTPathEnsureTrailingSeparator(char *pszPath, size_t cbPath); + +/** + * Same as RTPathEnsureTrailingSeparator but with selectable path style. + * + * @returns The length of the path, 0 on buffer overflow. + * @param pszPath The path. + * @param cbPath The length of the path buffer @a pszPath points to. + * @param fFlags The path style, RTPATH_STR_F_STYLE_XXX. + * @sa RTPathEnsureTrailingSeparator + */ +RTDECL(size_t) RTPathEnsureTrailingSeparatorEx(char *pszPath, size_t cbPath, uint32_t fFlags); + +/** + * Changes all the slashes in the specified path to DOS style. + * + * Unless @a fForce is set, nothing will be done when on a UNIX flavored system + * since paths wont work with DOS style slashes there. + * + * @returns @a pszPath. + * @param pszPath The path to modify. + * @param fForce Whether to force the conversion on non-DOS OSes. + */ +RTDECL(char *) RTPathChangeToDosSlashes(char *pszPath, bool fForce); + +/** + * Changes all the slashes in the specified path to unix style. + * + * Unless @a fForce is set, nothing will be done when on a UNIX flavored system + * since paths wont work with DOS style slashes there. + * + * @returns @a pszPath. + * @param pszPath The path to modify. + * @param fForce Whether to force the conversion on non-DOS OSes. + */ +RTDECL(char *) RTPathChangeToUnixSlashes(char *pszPath, bool fForce); + +/** + * Purges a string so it can be used as a file according to fFlags. + * + * Illegal filename characters are replaced by '_'. + * + * @returns pszString + * @param pszString The string to purge. + * @param fFlags One of the RTPATH_STR_F_STYLE_XXX flags. Most users + * will pass RTPATH_STR_F_STYLE_HOST (0). + */ +RTDECL(char *) RTPathPurgeFilename(char *pszString, uint32_t fFlags); + +/** + * Simple parsing of the a path. + * + * It figures the length of the directory component, the offset of + * the file name and the location of the suffix dot. + * + * @returns The path length. + * + * @param pszPath Path to find filename in. + * @param pcchDir Where to put the length of the directory component. If + * no directory, this will be 0. Optional. + * @param poffName Where to store the filename offset. + * If empty string or if it's ending with a slash this + * will be set to -1. Optional. + * @param poffSuff Where to store the suffix offset (the last dot). + * If empty string or if it's ending with a slash this + * will be set to -1. Optional. + */ +RTDECL(size_t) RTPathParseSimple(const char *pszPath, size_t *pcchDir, ssize_t *poffName, ssize_t *poffSuff); + +/** + * Finds the filename in a path. + * + * @returns Pointer to filename within pszPath. + * @returns NULL if no filename (i.e. empty string or ends with a slash). + * @param pszPath Path to find filename in. + */ +RTDECL(char *) RTPathFilename(const char *pszPath); +RTDECL(PRTUTF16) RTPathFilenameUtf16(PCRTUTF16 pwszPath); + +/** + * Finds the filename in a path, extended version. + * + * @returns Pointer to filename within pszPath. + * @returns NULL if no filename (i.e. empty string or ends with a slash). + * @param pszPath Path to find filename in. + * @param fFlags RTPATH_STR_F_STYLE_XXX. Other RTPATH_STR_F_XXX flags + * will be ignored. + */ +RTDECL(char *) RTPathFilenameEx(const char *pszPath, uint32_t fFlags); +RTDECL(PRTUTF16) RTPathFilenameExUtf16(PCRTUTF16 pwszPath, uint32_t fFlags); + +/** + * Finds the common path in a given set of paths. + * + * The paths are not made absolute or real, they are taken as given. + * + * @returns The common path length as represented by \a papszPaths[0], 0 if not + * found or invalid input. + * @param cPaths Number of paths in \a papszPaths. + * @param papszPaths Array of paths to find common path for. The paths must + * not contains ".." sequences, as that's too complicated + * to handle. + */ +RTDECL(size_t) RTPathFindCommon(size_t cPaths, const char * const *papszPaths); + +/** + * Finds the common path in a given set of paths, extended version. + * + * The paths are not made absolute or real, they are taken as given. + * + * @returns The common path length as represented by \a papszPaths[0], 0 if not + * found or invalid input. + * @param cPaths Number of paths in \a papszPaths. + * @param papszPaths Array of paths to find common path for. The paths must + * not contains ".." sequences, as that's too complicated + * to handle. + * @param fFlags RTPATH_STR_F_STYLE_XXX, RTPATH_STR_F_NO_START, and + * RTPATHFINDCOMMON_F_IGNORE_DOTDOT as desired. Other + * RTPATH_STR_F_XXX flags will be ignored. + */ +RTDECL(size_t) RTPathFindCommonEx(size_t cPaths, const char * const *papszPaths, uint32_t fFlags); + +/** @name RTPATHFINDCOMMON_F_XXX - Flags for RTPathFindCommonEx. + * @{ */ +/** Ignore the dangers of '..' components. */ +#define RTPATHFINDCOMMON_F_IGNORE_DOTDOT RT_BIT_32(16) +/** @} */ + +/** + * Finds the suffix part of in a path (last dot and onwards). + * + * @returns Pointer to suffix within pszPath. + * @returns NULL if no suffix + * @param pszPath Path to find suffix in. + * + * @remarks IPRT terminology: A suffix includes the dot, the extension starts + * after the dot. For instance suffix '.txt' and extension 'txt'. + */ +RTDECL(char *) RTPathSuffix(const char *pszPath); + +/** + * Checks if a path has an extension / suffix. + * + * @returns true if extension / suffix present. + * @returns false if no extension / suffix. + * @param pszPath Path to check. + */ +RTDECL(bool) RTPathHasSuffix(const char *pszPath); +/** Same thing, different name. */ +#define RTPathHasExt RTPathHasSuffix + +/** + * Checks if a path includes more than a filename. + * + * @returns true if path present. + * @returns false if no path. + * @param pszPath Path to check. + */ +RTDECL(bool) RTPathHasPath(const char *pszPath); +/** Misspelled, don't use. */ +#define RTPathHavePath RTPathHasPath + +/** + * Checks if the path starts with a root specifier or not. + * + * @returns @c true if it starts with root, @c false if not. + * + * @param pszPath Path to check. + */ +RTDECL(bool) RTPathStartsWithRoot(const char *pszPath); + +/** + * Determins the length of the parent part of the given path. + * + * @returns The length of the parent section of the path, including the final + * path separator. Returns 0 if only filename or empty path. + * @param pszPath The path to evaluate. + * + * @note Will stop at the server for UNC paths, so given "//server/share/" + * the parent length will be 9. + */ +RTDECL(size_t) RTPathParentLength(const char *pszPath); + +/** + * Determins the length of the parent part of the given path, extended variant. + * + * @returns The length of the parent section of the path, including the final + * path separator. Returns 0 if only filename or empty path. + * @param pszPath The path to evaluate. + * @param fFlags RTPATH_STR_F_STYLE_XXX and RTPATH_STR_F_NO_START. + * Asserts and ignores RTPATH_STR_F_NO_END. + * + * @note Will stop at the server for UNC paths, so given "//server/share/" + * the parent length will be 9. + */ +RTDECL(size_t) RTPathParentLengthEx(const char *pszPath, uint32_t fFlags); + +/** + * Counts the components in the specified path. + * + * An empty string has zero components. A lone root slash is considered have + * one. The paths "/init" and "/bin/" are considered having two components. An + * UNC share specifier like "\\myserver\share" will be considered as one single + * component. + * + * @returns The number of path components. + * @param pszPath The path to parse. + */ +RTDECL(size_t) RTPathCountComponents(const char *pszPath); + +/** + * Copies the specified number of path components from @a pszSrc and into @a + * pszDst. + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. In the latter case the buffer + * is not touched. + * + * @param pszDst The destination buffer. + * @param cbDst The size of the destination buffer. + * @param pszSrc The source path. + * @param cComponents The number of components to copy from @a pszSrc. + */ +RTDECL(int) RTPathCopyComponents(char *pszDst, size_t cbDst, const char *pszSrc, size_t cComponents); + +/** @name Path properties returned by RTPathParse and RTPathSplit. + * @{ */ + +/** Indicates that there is a filename. + * If not set, either a lone root spec was given (RTPATH_PROP_UNC, + * RTPATH_PROP_ROOT_SLASH, or RTPATH_PROP_VOLUME) or the final component had a + * trailing slash (RTPATH_PROP_DIR_SLASH). */ +#define RTPATH_PROP_FILENAME UINT16_C(0x0001) +/** Indicates that a directory was specified using a trailing slash. + * @note This is not set for lone root specifications (RTPATH_PROP_UNC, + * RTPATH_PROP_ROOT_SLASH, or RTPATH_PROP_VOLUME). + * @note The slash is not counted into the last component. However, it is + * counted into cchPath. */ +#define RTPATH_PROP_DIR_SLASH UINT16_C(0x0002) + +/** The filename has a suffix (extension). */ +#define RTPATH_PROP_SUFFIX UINT16_C(0x0004) +/** Indicates that this is an UNC path (Windows and OS/2 only). + * + * UNC = Universal Naming Convention. It is on the form '//Computer/', + * '//Namespace/', '//ComputerName/Resource' and '//Namespace/Resource'. + * RTPathParse, RTPathSplit and friends does not consider the 'Resource' as + * part of the UNC root specifier. Thus the root specs for the above examples + * would be '//ComputerName/' or '//Namespace/'. + * + * Please note that '//something' is not a UNC path, there must be a slash + * following the computer or namespace. + */ +#define RTPATH_PROP_UNC UINT16_C(0x0010) +/** A root slash was specified (unix style root). + * (While the path must relative if not set, this being set doesn't make it + * absolute.) + * + * This will be set in the following examples: '/', '/bin', 'C:/', 'C:/Windows', + * '//./', '//./PhysicalDisk0', '//example.org/', and '//example.org/share'. + * + * It will not be set for the following examples: '.', 'bin/ls', 'C:', and + * 'C:Windows'. + */ +#define RTPATH_PROP_ROOT_SLASH UINT16_C(0x0020) +/** A volume is specified (Windows, DOS and OS/2). + * For examples: 'C:', 'C:/', and 'A:/AutoExec.bat'. */ +#define RTPATH_PROP_VOLUME UINT16_C(0x0040) +/** The path is absolute, i.e. has a root specifier (root-slash, + * volume or UNC) and contains no winding '..' bits, though it may contain + * unnecessary slashes (RTPATH_PROP_EXTRA_SLASHES) and '.' components + * (RTPATH_PROP_DOT_REFS). + * + * On systems without volumes and UNC (unix style) it will be set for '/', + * '/bin/ls', and '/bin//./ls', but not for 'bin/ls', /bin/../usr/bin/env', + * '/./bin/ls' or '/.'. + * + * On systems with volumes, it will be set for 'C:/', C:/Windows', and + * 'C:/./Windows//', but not for 'C:', 'C:Windows', or 'C:/Windows/../boot.ini'. + * + * On systems with UNC paths, it will be set for '//localhost/', + * '//localhost/C$', '//localhost/C$/Windows/System32', '//localhost/.', and + * '//localhost/C$//./AutoExec.bat', but not for + * '//localhost/C$/Windows/../AutoExec.bat'. + * + * @note For the RTPathAbs definition, this flag needs to be set while both + * RTPATH_PROP_EXTRA_SLASHES and RTPATH_PROP_DOT_REFS must be cleared. + */ +#define RTPATH_PROP_ABSOLUTE UINT16_C(0x0100) +/** Relative path. Inverse of RTPATH_PROP_ABSOLUTE. */ +#define RTPATH_PROP_RELATIVE UINT16_C(0x0200) +/** The path contains unnecessary slashes. Meaning, that if */ +#define RTPATH_PROP_EXTRA_SLASHES UINT16_C(0x0400) +/** The path contains references to the special '.' (dot) directory link. */ +#define RTPATH_PROP_DOT_REFS UINT16_C(0x0800) +/** The path contains references to the special '..' (dot) directory link. + * RTPATH_PROP_RELATIVE will always be set together with this. */ +#define RTPATH_PROP_DOTDOT_REFS UINT16_C(0x1000) +/** Special UNC root. + * The share name is not sacred when this is set. */ +#define RTPATH_PROP_SPECIAL_UNC UINT16_C(0x2000) + + +/** Macro to determin whether to insert a slash after the first component when + * joining it with something else. + * (All other components in a split or parsed path requies slashes added.) */ +#define RTPATH_PROP_FIRST_NEEDS_NO_SLASH(a_fProps) \ + RT_BOOL( (a_fProps) & (RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_VOLUME | RTPATH_PROP_UNC) ) + +/** Macro to determin whether there is a root specification of any kind + * (unix, volumes, unc). */ +#define RTPATH_PROP_HAS_ROOT_SPEC(a_fProps) \ + RT_BOOL( (a_fProps) & (RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_VOLUME | RTPATH_PROP_UNC) ) + +/** @} */ + + +/** + * Parsed path. + * + * The first component is the root, volume or UNC specifier, if present. Use + * RTPATH_PROP_HAS_ROOT_SPEC() on RTPATHPARSED::fProps to determine its + * presence. + * + * Other than the root component, no component will include directory separators + * (slashes). + */ +typedef struct RTPATHPARSED +{ + /** Number of path components. + * This will always be set on VERR_BUFFER_OVERFLOW returns from RTPathParsed + * so the caller can calculate the required buffer size. */ + uint16_t cComps; + /** Path property flags, RTPATH_PROP_XXX */ + uint16_t fProps; + /** On success this is the length of the described path, i.e. sum of all + * component lengths and necessary separators. + * Do NOT use this to index in the source path in case it contains + * unnecessary slashes that RTPathParsed has ignored here. */ + uint16_t cchPath; + /** Reserved for future use. */ + uint16_t u16Reserved; + /** The offset of the filename suffix, offset of the NUL char if none. */ + uint16_t offSuffix; + /** The length of the suffix. */ + uint16_t cchSuffix; + /** Array of component descriptors (variable size). + * @note Don't try figure the end of the input path by adding up off and cch + * of the last component. If RTPATH_PROP_DIR_SLASH is set, there may + * be one or more trailing slashes that are unaccounted for! */ + RT_FLEXIBLE_ARRAY_EXTENSION + struct + { + /** The offset of the component. */ + uint16_t off; + /** The length of the component. */ + uint16_t cch; + } aComps[RT_FLEXIBLE_ARRAY]; +} RTPATHPARSED; +/** Pointer to to a parsed path result. */ +typedef RTPATHPARSED *PRTPATHPARSED; +/** Pointer to to a const parsed path result. */ +typedef RTPATHPARSED *PCRTPATHPARSED; + +/** Stupid hack for MSC and flexible arrays. */ +#define RTPATHPARSED_MIN_SIZE (sizeof(uint16_t) * (6 + 4)) + + +/** + * Parses the path. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER if pParsed or pszPath is an invalid pointer. + * @retval VERR_INVALID_PARAMETER if cbOutput is less than the RTPATHPARSED + * strucuture. No output. (asserted) + * @retval VERR_BUFFER_OVERFLOW there are more components in the path than + * there is space in aComps. The required amount of space can be + * determined from the pParsed->cComps: + * @code + * RT_OFFSETOF(RTPATHPARSED, aComps[pParsed->cComps]) + * @endcode + * @retval VERR_PATH_ZERO_LENGTH if the path is empty. + * + * @param pszPath The path to parse. + * @param pParsed Where to store the details of the parsed path. + * @param cbParsed The size of the buffer. Must be at least the + * size of RTPATHPARSED. + * @param fFlags Combination of RTPATH_STR_F_XXX flags. + * Most users will pass 0. + * @sa RTPathSplit, RTPathSplitA. + */ +RTDECL(int) RTPathParse(const char *pszPath, PRTPATHPARSED pParsed, size_t cbParsed, uint32_t fFlags); + +/** + * Reassembles a path parsed by RTPathParse. + * + * This will be more useful as more APIs manipulating the RTPATHPARSED output + * are added. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. + * The necessary length is @a pParsed->cchPath + 1 (updated). + * + * @param pszSrcPath The source path. + * @param pParsed The parser output for @a pszSrcPath. Caller may + * eliminate elements by setting their length to + * zero. The cchPath member is updated. + * @param fFlags Combination of RTPATH_STR_F_STYLE_XXX. + * Most users will pass 0. + * @param pszDstPath Pointer to the buffer where the path is to be + * reassembled. + * @param cbDstPath The size of the output buffer. + */ +RTDECL(int) RTPathParsedReassemble(const char *pszSrcPath, PRTPATHPARSED pParsed, uint32_t fFlags, + char *pszDstPath, size_t cbDstPath); + + +/** + * Output buffer for RTPathSplit and RTPathSplitA. + */ +typedef struct RTPATHSPLIT +{ + /** Number of path components. + * This will always be set on VERR_BUFFER_OVERFLOW returns from RTPathParsed + * so the caller can calculate the required buffer size. */ + uint16_t cComps; + /** Path property flags, RTPATH_PROP_XXX */ + uint16_t fProps; + /** On success this is the length of the described path, i.e. sum of all + * component lengths and necessary separators. + * Do NOT use this to index in the source path in case it contains + * unnecessary slashes that RTPathSplit has ignored here. */ + uint16_t cchPath; + /** Reserved (internal use). */ + uint16_t u16Reserved; + /** The amount of memory used (on success) or required (on + * VERR_BUFFER_OVERFLOW) of this structure and it's strings. */ + uint32_t cbNeeded; + /** Pointer to the filename suffix (the dot), if any. Points to the NUL + * character of the last component if none or if RTPATH_PROP_DIR_SLASH is + * present. */ + const char *pszSuffix; + /** Array of component strings (variable size). */ + RT_FLEXIBLE_ARRAY_EXTENSION + char *apszComps[RT_FLEXIBLE_ARRAY]; +} RTPATHSPLIT; +/** Pointer to a split path buffer. */ +typedef RTPATHSPLIT *PRTPATHSPLIT; +/** Pointer to a const split path buffer. */ +typedef RTPATHSPLIT const *PCRTPATHSPLIT; + +/** + * Splits the path into individual component strings, carved from user supplied + * the given buffer block. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER if pParsed or pszPath is an invalid pointer. + * @retval VERR_INVALID_PARAMETER if cbOutput is less than the RTPATHSPLIT + * strucuture. No output. (asserted) + * @retval VERR_BUFFER_OVERFLOW there are more components in the path than + * there is space in aComps. The required amount of space can be + * determined from the pParsed->cComps: + * @code + * RT_OFFSETOF(RTPATHPARSED, aComps[pParsed->cComps]) + * @endcode + * @retval VERR_PATH_ZERO_LENGTH if the path is empty. + * @retval VERR_FILENAME_TOO_LONG if the filename is too long (close to 64 KB). + * + * @param pszPath The path to parse. + * @param pSplit Where to store the details of the parsed path. + * @param cbSplit The size of the buffer pointed to by @a pSplit + * (variable sized array at the end). Must be at + * least the size of RTPATHSPLIT. + * @param fFlags Combination of RTPATH_STR_F_XXX flags. + * Most users will pass 0. + * + * @sa RTPathSplitA, RTPathParse. + */ +RTDECL(int) RTPathSplit(const char *pszPath, PRTPATHSPLIT pSplit, size_t cbSplit, uint32_t fFlags); + +/** + * Splits the path into individual component strings, allocating the buffer on + * the default thread heap. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER if pParsed or pszPath is an invalid pointer. + * @retval VERR_PATH_ZERO_LENGTH if the path is empty. + * + * @param pszPath The path to parse. + * @param ppSplit Where to return the pointer to the output on + * success. This must be freed by calling + * RTPathSplitFree(). + * @param fFlags Combination of RTPATH_STR_F_XXX flags. + * Most users will pass 0. + * @sa RTPathSplitFree, RTPathSplit, RTPathParse. + */ +#define RTPathSplitA(pszPath, ppSplit, fFlags) RTPathSplitATag(pszPath, ppSplit, fFlags, RTPATH_TAG) + +/** + * Splits the path into individual component strings, allocating the buffer on + * the default thread heap. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER if pParsed or pszPath is an invalid pointer. + * @retval VERR_PATH_ZERO_LENGTH if the path is empty. + * + * @param pszPath The path to parse. + * @param ppSplit Where to return the pointer to the output on + * success. This must be freed by calling + * RTPathSplitFree(). + * @param fFlags Combination of RTPATH_STR_F_XXX flags. + * Most users will pass 0. + * @param pszTag Allocation tag used for statistics and such. + * @sa RTPathSplitFree, RTPathSplit, RTPathParse. + */ +RTDECL(int) RTPathSplitATag(const char *pszPath, PRTPATHSPLIT *ppSplit, uint32_t fFlags, const char *pszTag); + +/** + * Frees buffer returned by RTPathSplitA. + * + * @param pSplit What RTPathSplitA returned. + * @sa RTPathSplitA + */ +RTDECL(void) RTPathSplitFree(PRTPATHSPLIT pSplit); + +/** + * Reassembles a path parsed by RTPathSplit. + * + * This will be more useful as more APIs manipulating the RTPATHSPLIT output are + * added. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if @a cbDstPath is less than or equal to + * RTPATHSPLIT::cchPath. + * + * @param pSplit A split path (see RTPathSplit, RTPathSplitA). + * @param fFlags Combination of RTPATH_STR_F_STYLE_XXX. + * Most users will pass 0. + * @param pszDstPath Pointer to the buffer where the path is to be + * reassembled. + * @param cbDstPath The size of the output buffer. + */ +RTDECL(int) RTPathSplitReassemble(PRTPATHSPLIT pSplit, uint32_t fFlags, char *pszDstPath, size_t cbDstPath); + +/** + * Checks if the two paths leads to the file system object. + * + * If the objects exist, we'll query attributes for them. If that's not + * conclusive (some OSes) or one of them doesn't exist, we'll use a combination + * of RTPathAbs and RTPathCompare to determine the result. + * + * @returns true, false, or VERR_FILENAME_TOO_LONG. + * @param pszPath1 The first path. + * @param pszPath2 The seoncd path. + */ +RTDECL(int) RTPathIsSame(const char *pszPath1, const char *pszPath2); + + +/** + * Compares two paths. + * + * The comparison takes platform-dependent details into account, + * such as: + * <ul> + * <li>On DOS-like platforms, both separator chars (|\| and |/|) are considered + * to be equal. + * <li>On platforms with case-insensitive file systems, mismatching characters + * are uppercased and compared again. + * </ul> + * + * @returns @< 0 if the first path less than the second path. + * @returns 0 if the first path identical to the second path. + * @returns @> 0 if the first path greater than the second path. + * + * @param pszPath1 Path to compare (must be an absolute path). + * @param pszPath2 Path to compare (must be an absolute path). + * + * @remarks File system details are currently ignored. This means that you won't + * get case-insensitive compares on unix systems when a path goes into a + * case-insensitive filesystem like FAT, HPFS, HFS, NTFS, JFS, or + * similar. For NT, OS/2 and similar you'll won't get case-sensitive + * compares on a case-sensitive file system. + */ +RTDECL(int) RTPathCompare(const char *pszPath1, const char *pszPath2); + +/** + * Checks if a path starts with the given parent path. + * + * This means that either the path and the parent path matches completely, or + * that the path is to some file or directory residing in the tree given by the + * parent directory. + * + * The path comparison takes platform-dependent details into account, + * see RTPathCompare() for details. + * + * @returns |true| when \a pszPath starts with \a pszParentPath (or when they + * are identical), or |false| otherwise. + * + * @param pszPath Path to check, must be an absolute path. + * @param pszParentPath Parent path, must be an absolute path. + * No trailing directory slash! + * + * @remarks This API doesn't currently handle root directory compares in a + * manner consistent with the other APIs. RTPathStartsWith(pszSomePath, + * "/") will not work if pszSomePath isn't "/". + */ +RTDECL(bool) RTPathStartsWith(const char *pszPath, const char *pszParentPath); + +/** + * Appends one partial path to another. + * + * The main purpose of this function is to deal correctly with the slashes when + * concatenating the two partial paths. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the result is too big to fit within + * cbPathDst bytes. No changes has been made. + * @retval VERR_INVALID_PARAMETER if the string pointed to by pszPath is longer + * than cbPathDst-1 bytes (failed to find terminator). Asserted. + * + * @param pszPath The path to append pszAppend to. This serves as both + * input and output. This can be empty, in which case + * pszAppend is just copied over. + * @param cbPathDst The size of the buffer pszPath points to, terminator + * included. This should NOT be strlen(pszPath). + * @param pszAppend The partial path to append to pszPath. This can be + * NULL, in which case nothing is done. + * + * @remarks See the RTPathAppendEx remarks. + */ +RTDECL(int) RTPathAppend(char *pszPath, size_t cbPathDst, const char *pszAppend); + +/** + * Appends one partial path to another. + * + * The main purpose of this function is to deal correctly with the slashes when + * concatenating the two partial paths. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the result is too big to fit within + * cbPathDst bytes. No changes has been made. + * @retval VERR_INVALID_PARAMETER if the string pointed to by pszPath is longer + * than cbPathDst-1 bytes (failed to find terminator). Asserted. + * + * @param pszPath The path to append pszAppend to. This serves as both + * input and output. This can be empty, in which case + * pszAppend is just copied over. + * @param cbPathDst The size of the buffer pszPath points to, terminator + * included. This should NOT be strlen(pszPath). + * @param pszAppend The partial path to append to pszPath. This can be + * NULL, in which case nothing is done. + * @param cchAppendMax The maximum number or characters to take from @a + * pszAppend. RTSTR_MAX is fine. + * @param fFlags Combination of RTPATH_STR_F_STYLE_XXX. + * Most users will pass 0 / RTPATH_STR_F_STYLE_HOST. + * + * @remarks On OS/2, Window and similar systems, concatenating a drive letter + * specifier with a slash prefixed path will result in an absolute + * path. Meaning, RTPathAppend(strcpy(szBuf, "C:"), sizeof(szBuf), + * "/bar") will result in "C:/bar". (This follows directly from the + * behavior when pszPath is empty.) + * + * On the other hand, when joining a drive letter specifier with a + * partial path that does not start with a slash, the result is not an + * absolute path. Meaning, RTPathAppend(strcpy(szBuf, "C:"), + * sizeof(szBuf), "bar") will result in "C:bar". + */ +RTDECL(int) RTPathAppendEx(char *pszPath, size_t cbPathDst, const char *pszAppend, size_t cchAppendMax, uint32_t fFlags); + +/** + * Like RTPathAppend, but with the base path as a separate argument instead of + * in the path buffer. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the result is too big to fit within + * cbPathDst bytes. + * @retval VERR_INVALID_PARAMETER if the string pointed to by pszPath is longer + * than cbPathDst-1 bytes (failed to find terminator). Asserted. + * + * @param pszPathDst Where to store the resulting path. + * @param cbPathDst The size of the buffer pszPathDst points to, + * terminator included. + * @param pszPathSrc The base path to copy into @a pszPathDst before + * appending @a pszAppend. + * @param pszAppend The partial path to append to pszPathSrc. This can + * be NULL, in which case nothing is done. + * + */ +RTDECL(int) RTPathJoin(char *pszPathDst, size_t cbPathDst, const char *pszPathSrc, + const char *pszAppend); + +/** + * Same as RTPathJoin, except that the output buffer is allocated. + * + * @returns Buffer containing the joined up path, call RTStrFree to free. NULL + * on allocation failure. + * @param pszPathSrc The base path to copy into @a pszPathDst before + * appending @a pszAppend. + * @param pszAppend The partial path to append to pszPathSrc. This can + * be NULL, in which case nothing is done. + * + */ +RTDECL(char *) RTPathJoinA(const char *pszPathSrc, const char *pszAppend); + +/** + * Extended version of RTPathJoin, both inputs can be specified as substrings. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the result is too big to fit within + * cbPathDst bytes. + * @retval VERR_INVALID_PARAMETER if the string pointed to by pszPath is longer + * than cbPathDst-1 bytes (failed to find terminator). Asserted. + * + * @param pszPathDst Where to store the resulting path. + * @param cbPathDst The size of the buffer pszPathDst points to, + * terminator included. + * @param pszPathSrc The base path to copy into @a pszPathDst before + * appending @a pszAppend. + * @param cchPathSrcMax The maximum number of bytes to copy from @a + * pszPathSrc. RTSTR_MAX is find. + * @param pszAppend The partial path to append to pszPathSrc. This can + * be NULL, in which case nothing is done. + * @param cchAppendMax The maximum number of bytes to copy from @a + * pszAppend. RTSTR_MAX is find. + * @param fFlags Combination of RTPATH_STR_F_STYLE_XXX. + * Most users will pass 0 / RTPATH_STR_F_STYLE_HOST. + * + */ +RTDECL(int) RTPathJoinEx(char *pszPathDst, size_t cbPathDst, + const char *pszPathSrc, size_t cchPathSrcMax, + const char *pszAppend, size_t cchAppendMax, uint32_t fFlags); + +/** + * Callback for RTPathTraverseList that's called for each element. + * + * @returns IPRT style status code. Return VERR_TRY_AGAIN to continue, any other + * value will abort the traversing and be returned to the caller. + * + * @param pchPath Pointer to the start of the current path. This is + * not null terminated. + * @param cchPath The length of the path. + * @param pvUser1 The first user parameter. + * @param pvUser2 The second user parameter. + */ +typedef DECLCALLBACKTYPE(int, FNRTPATHTRAVERSER,(char const *pchPath, size_t cchPath, void *pvUser1, void *pvUser2)); +/** Pointer to a FNRTPATHTRAVERSER. */ +typedef FNRTPATHTRAVERSER *PFNRTPATHTRAVERSER; + +/** + * Traverses a string that can contain multiple paths separated by a special + * character. + * + * @returns IPRT style status code from the callback or VERR_END_OF_STRING if + * the callback returned VERR_TRY_AGAIN for all paths in the string. + * + * @param pszPathList The string to traverse. + * @param chSep The separator character. Using the null terminator + * is fine, but the result will simply be that there + * will only be one callback for the entire string + * (save any leading white space). + * @param pfnCallback The callback. + * @param pvUser1 First user argument for the callback. + * @param pvUser2 Second user argument for the callback. + */ +RTDECL(int) RTPathTraverseList(const char *pszPathList, char chSep, PFNRTPATHTRAVERSER pfnCallback, void *pvUser1, void *pvUser2); + + +/** + * Calculate a relative path between the two given paths. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the result is too big to fit within + * cbPathDst bytes. + * @retval VERR_NOT_SUPPORTED if both paths start with different volume specifiers. + * @param pszPathDst Where to store the resulting path. + * @param cbPathDst The size of the buffer pszPathDst points to, + * terminator included. + * @param pszPathFrom The path to start from creating the relative path. + * @param fFromFile Whether @a pszPathFrom is a file and we should work + * relative to it's parent directory (@c true), or if + * we should assume @a pszPathFrom is a directory and + * work relative to it. + * @param pszPathTo The path to reach with the created relative path. + */ +RTDECL(int) RTPathCalcRelative(char *pszPathDst, size_t cbPathDst, const char *pszPathFrom, bool fFromFile, const char *pszPathTo); + +#ifdef IN_RING3 + +/** + * Gets the path to the directory containing the executable. + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathExecDir(char *pszPath, size_t cchPath); + +/** + * Gets the user home directory. + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathUserHome(char *pszPath, size_t cchPath); + +/** + * Gets the user documents directory. + * + * The returned path isn't guaranteed to exist. + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathUserDocuments(char *pszPath, size_t cchPath); + +/** + * Gets the directory of shared libraries. + * + * This is not the same as RTPathAppPrivateArch() as Linux depends all shared + * libraries in a common global directory where ld.so can find them. + * + * Linux: /usr/lib + * Solaris: /opt/@<application@>/@<arch>@ or something + * Windows: @<program files directory@>/@<application@> + * Old path: same as RTPathExecDir() + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathSharedLibs(char *pszPath, size_t cchPath); + +/** + * Gets the directory for architecture-independent application data, for + * example NLS files, module sources, ... + * + * Linux: /usr/shared/@<application@> + * Solaris: /opt/@<application@> + * Windows: @<program files directory@>/@<application@> + * Old path: same as RTPathExecDir() + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathAppPrivateNoArch(char *pszPath, size_t cchPath); + +/** + * Gets the directory for architecture-dependent application data, for + * example modules which can be loaded at runtime. + * + * Linux: /usr/lib/@<application@> + * Solaris: /opt/@<application@>/@<arch>@ or something + * Windows: @<program files directory@>/@<application@> + * Old path: same as RTPathExecDir() + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathAppPrivateArch(char *pszPath, size_t cchPath); + +/** + * Gets the toplevel directory for architecture-dependent application data. + * + * This differs from RTPathAppPrivateArch on Solaris only where it will work + * around the /opt/@<application@>/amd64 and /opt/@<application@>/i386 multi + * architecture installation style. + * + * Linux: /usr/lib/@<application@> + * Solaris: /opt/@<application@> + * Windows: @<program files directory@>/@<application@> + * Old path: same as RTPathExecDir() + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathAppPrivateArchTop(char *pszPath, size_t cchPath); + +/** + * Gets the directory for documentation. + * + * Linux: /usr/share/doc/@<application@> + * Solaris: /opt/@<application@> + * Windows: @<program files directory@>/@<application@> + * Old path: same as RTPathExecDir() + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathAppDocs(char *pszPath, size_t cchPath); + +/** + * Gets the temporary directory path. + * + * @returns iprt status code. + * @param pszPath Buffer where to store the path. + * @param cchPath Buffer size in bytes. + */ +RTDECL(int) RTPathTemp(char *pszPath, size_t cchPath); + + +/** + * RTPathGlobl result entry. + */ +typedef struct RTPATHGLOBENTRY +{ + /** List entry. */ + struct RTPATHGLOBENTRY *pNext; + /** RTDIRENTRYTYPE value. */ + uint8_t uType; + /** Unused explicit padding. */ + uint8_t bUnused; + /** The length of the path. */ + uint16_t cchPath; + /** The path to the file (variable length). */ + char szPath[1]; +} RTPATHGLOBENTRY; +/** Pointer to a GLOB result entry. */ +typedef RTPATHGLOBENTRY *PRTPATHGLOBENTRY; +/** Pointer to a const GLOB result entry. */ +typedef RTPATHGLOBENTRY const *PCRTPATHGLOBENTRY; +/** Pointer to a GLOB result entry pointer. */ +typedef PCRTPATHGLOBENTRY *PPCRTPATHGLOBENTRY; + +/** + * Performs wildcard expansion on a path pattern. + * + * @returns IPRT status code. + * + * @param pszPattern The pattern to expand. + * @param fFlags RTPATHGLOB_F_XXX. + * @param ppHead Where to return the head of the result list. This + * is always set to NULL on failure. + * @param pcResults Where to return the number of the result. Optional. + */ +RTDECL(int) RTPathGlob(const char *pszPattern, uint32_t fFlags, PPCRTPATHGLOBENTRY ppHead, uint32_t *pcResults); + +/** @name RTPATHGLOB_F_XXX - RTPathGlob flags + * @{ */ +/** Case insensitive. */ +#define RTPATHGLOB_F_IGNORE_CASE RT_BIT_32(0) +/** Do not expand \${EnvOrSpecialVariable} in the pattern. */ +#define RTPATHGLOB_F_NO_VARIABLES RT_BIT_32(1) +/** Do not interpret a leading tilde as a home directory reference. */ +#define RTPATHGLOB_F_NO_TILDE RT_BIT_32(2) +/** Only return the first match. */ +#define RTPATHGLOB_F_FIRST_ONLY RT_BIT_32(3) +/** Only match directories (implied if pattern ends with slash). */ +#define RTPATHGLOB_F_ONLY_DIRS RT_BIT_32(4) +/** Do not match directories. (Can't be used with RTPATHGLOB_F_ONLY_DIRS or + * patterns containing a trailing slash.) */ +#define RTPATHGLOB_F_NO_DIRS RT_BIT_32(5) +/** Disables the '**' wildcard pattern for matching zero or more subdirs. */ +#define RTPATHGLOB_F_NO_STARSTAR RT_BIT_32(6) +/** Mask of valid flags. */ +#define RTPATHGLOB_F_MASK UINT32_C(0x0000007f) +/** @} */ + +/** + * Frees the results produced by RTPathGlob. + * + * @param pHead What RTPathGlob returned. NULL ignored. + */ +RTDECL(void) RTPathGlobFree(PCRTPATHGLOBENTRY pHead); + + +/** + * Query information about a file system object. + * + * This API will resolve NOT symbolic links in the last component (just like + * unix lstat()). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the object exists, information returned. + * @retval VERR_PATH_NOT_FOUND if any but the last component in the specified + * path was not found or was not a directory. + * @retval VERR_FILE_NOT_FOUND if the object does not exist (but path to the + * parent directory exists). + * + * @param pszPath Path to the file system object. + * @param pObjInfo Object information structure to be filled on successful + * return. + * @param enmAdditionalAttribs + * Which set of additional attributes to request. + * Use RTFSOBJATTRADD_NOTHING if this doesn't matter. + */ +RTR3DECL(int) RTPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs); + +/** + * Query information about a file system object. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the object exists, information returned. + * @retval VERR_PATH_NOT_FOUND if any but the last component in the specified + * path was not found or was not a directory. + * @retval VERR_FILE_NOT_FOUND if the object does not exist (but path to the + * parent directory exists). + * + * @param pszPath Path to the file system object. + * @param pObjInfo Object information structure to be filled on successful return. + * @param enmAdditionalAttribs + * Which set of additional attributes to request. + * Use RTFSOBJATTRADD_NOTHING if this doesn't matter. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + */ +RTR3DECL(int) RTPathQueryInfoEx(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags); + +/** + * Changes the mode flags of a file system object. + * + * The API requires at least one of the mode flag sets (Unix/Dos) to + * be set. The type is ignored. + * + * This API will resolve symbolic links in the last component since + * mode isn't important for symbolic links. + * + * @returns iprt status code. + * @param pszPath Path to the file system object. + * @param fMode The new file mode, see @ref grp_rt_fs for details. + */ +RTR3DECL(int) RTPathSetMode(const char *pszPath, RTFMODE fMode); + +/** + * Gets the mode flags of a file system object. + * + * @returns iprt status code. + * @param pszPath Path to the file system object. + * @param pfMode Where to store the file mode, see @ref grp_rt_fs for details. + * + * @remark This is wrapper around RTPathQueryInfoEx(RTPATH_F_FOLLOW_LINK) and + * exists to complement RTPathSetMode(). + */ +RTR3DECL(int) RTPathGetMode(const char *pszPath, PRTFMODE pfMode); + +/** + * Changes one or more of the timestamps associated of file system object. + * + * This API will not resolve symbolic links in the last component (just + * like unix lutimes()). + * + * @returns iprt status code. + * @param pszPath Path to the file system object. + * @param pAccessTime Pointer to the new access time. + * @param pModificationTime Pointer to the new modification time. + * @param pChangeTime Pointer to the new change time. NULL if not to be changed. + * @param pBirthTime Pointer to the new time of birth. NULL if not to be changed. + * + * @remark The file system might not implement all these time attributes, + * the API will ignore the ones which aren't supported. + * + * @remark The file system might not implement the time resolution + * employed by this interface, the time will be chopped to fit. + * + * @remark The file system may update the change time even if it's + * not specified. + * + * @remark POSIX can only set Access & Modification and will always set both. + */ +RTR3DECL(int) RTPathSetTimes(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, + PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime); + +/** + * Changes one or more of the timestamps associated of file system object. + * + * @returns iprt status code. + * @param pszPath Path to the file system object. + * @param pAccessTime Pointer to the new access time. + * @param pModificationTime Pointer to the new modification time. + * @param pChangeTime Pointer to the new change time. NULL if not to be changed. + * @param pBirthTime Pointer to the new time of birth. NULL if not to be changed. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + * + * @remark The file system might not implement all these time attributes, + * the API will ignore the ones which aren't supported. + * + * @remark The file system might not implement the time resolution + * employed by this interface, the time will be chopped to fit. + * + * @remark The file system may update the change time even if it's + * not specified. + * + * @remark POSIX can only set Access & Modification and will always set both. + */ +RTR3DECL(int) RTPathSetTimesEx(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, + PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags); + +/** + * Gets one or more of the timestamps associated of file system object. + * + * @returns iprt status code. + * @param pszPath Path to the file system object. + * @param pAccessTime Where to store the access time. NULL is ok. + * @param pModificationTime Where to store the modification time. NULL is ok. + * @param pChangeTime Where to store the change time. NULL is ok. + * @param pBirthTime Where to store the creation time. NULL is ok. + * + * @remark This is wrapper around RTPathQueryInfo() and exists to complement + * RTPathSetTimes(). If the last component is a symbolic link, it will + * not be resolved. + */ +RTR3DECL(int) RTPathGetTimes(const char *pszPath, PRTTIMESPEC pAccessTime, PRTTIMESPEC pModificationTime, + PRTTIMESPEC pChangeTime, PRTTIMESPEC pBirthTime); + +/** + * Changes the owner and/or group of a file system object. + * + * This API will not resolve symbolic links in the last component (just + * like unix lchown()). + * + * @returns iprt status code. + * @param pszPath Path to the file system object. + * @param uid The new file owner user id. Pass NIL_RTUID to leave + * this unchanged. + * @param gid The new group id. Pass NIL_RTGUID to leave this + * unchanged. + */ +RTR3DECL(int) RTPathSetOwner(const char *pszPath, uint32_t uid, uint32_t gid); + +/** + * Changes the owner and/or group of a file system object. + * + * @returns iprt status code. + * @param pszPath Path to the file system object. + * @param uid The new file owner user id. Pass NIL_RTUID to leave + * this unchanged. + * @param gid The new group id. Pass NIL_RTGID to leave this + * unchanged. + * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK. + */ +RTR3DECL(int) RTPathSetOwnerEx(const char *pszPath, uint32_t uid, uint32_t gid, uint32_t fFlags); + +/** + * Gets the owner and/or group of a file system object. + * + * @returns iprt status code. + * @param pszPath Path to the file system object. + * @param pUid Where to store the owner user id. NULL is ok. + * @param pGid Where to store the group id. NULL is ok. + * + * @remark This is wrapper around RTPathQueryInfo() and exists to complement + * RTPathGetOwner(). If the last component is a symbolic link, it will + * not be resolved. + */ +RTR3DECL(int) RTPathGetOwner(const char *pszPath, uint32_t *pUid, uint32_t *pGid); + + +/** @name RTPathRename, RTDirRename & RTFileRename flags. + * @{ */ +/** Do not replace anything. */ +#define RTPATHRENAME_FLAGS_NO_REPLACE UINT32_C(0) +/** This will replace attempt any target which isn't a directory. */ +#define RTPATHRENAME_FLAGS_REPLACE RT_BIT(0) +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTPATHRENAME_FLAGS_NO_SYMLINKS RT_BIT(1) +/** @} */ + +/** + * Renames a path within a filesystem. + * + * This will rename symbolic links. If RTPATHRENAME_FLAGS_REPLACE is used and + * pszDst is a symbolic link, it will be replaced and not its target. + * + * @returns IPRT status code. + * @param pszSrc The source path. + * @param pszDst The destination path. + * @param fRename Rename flags, RTPATHRENAME_FLAGS_*. + */ +RTR3DECL(int) RTPathRename(const char *pszSrc, const char *pszDst, unsigned fRename); + +/** @name RTPathUnlink flags. + * @{ */ +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTPATHUNLINK_FLAGS_NO_SYMLINKS RT_BIT(0) +/** @} */ + +/** + * Removes the last component of the path. + * + * @returns IPRT status code. + * @param pszPath The path. + * @param fUnlink Unlink flags, RTPATHUNLINK_FLAGS_*. + */ +RTR3DECL(int) RTPathUnlink(const char *pszPath, uint32_t fUnlink); + +/** + * A /bin/rm tool. + * + * @returns Program exit code. + * + * @param cArgs The number of arguments. + * @param papszArgs The argument vector. (Note that this may be + * reordered, so the memory must be writable.) + */ +RTDECL(RTEXITCODE) RTPathRmCmd(unsigned cArgs, char **papszArgs); + +# ifdef RT_OS_WINDOWS + +/** + * Converts the given UTF-8 path into a native windows path. + * + * @returns IPRT status code. + * @param ppwszPath Where to return the path. This will always be + * set to NULL on failure. Use RTPathWinFree to + * free it when done. + * @param pszPath The UTF-8 path to convert. + * @param fFlags MBZ, reserved for future hacks. + * @sa RTPathWinFree, RTNtPathFromWinUtf8, RTNtPathRelativeFromUtf8. + */ +RTDECL(int) RTPathWinFromUtf8(PRTUTF16 *ppwszPath, const char *pszPath, uint32_t fFlags); + +/** + * Frees a native windows path returned by RTPathWinFromUtf8 + * + * @param pwszPath The path to free. NULL is ignored. + */ +RTDECL(void) RTPathWinFree(PRTUTF16 pwszPath); + +# endif /* RT_OS_WINDOWS */ + +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_path_h */ + diff --git a/include/iprt/pipe.h b/include/iprt/pipe.h new file mode 100644 index 00000000..a47f2d58 --- /dev/null +++ b/include/iprt/pipe.h @@ -0,0 +1,293 @@ +/** @file + * IPRT - Anonymous Pipes. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_pipe_h +#define IPRT_INCLUDED_pipe_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/fs.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_pipe RTPipe - Anonymous Pipes + * @ingroup grp_rt + * + * @note The current Windows implementation has some peculiarities, + * especially with respect to the write side where the it is possible + * to write one extra pipe buffer sized block of data when the pipe + * buffer is full. + * + * @{ + */ + +/** + * Create an anonymous pipe. + * + * @returns IPRT status code. + * @param phPipeRead Where to return the read end of the pipe. + * @param phPipeWrite Where to return the write end of the pipe. + * @param fFlags A combination of RTPIPE_C_XXX defines. + */ +RTDECL(int) RTPipeCreate(PRTPIPE phPipeRead, PRTPIPE phPipeWrite, uint32_t fFlags); + +/** @name RTPipeCreate flags. + * @{ */ +/** Mark the read end as inheritable. */ +#define RTPIPE_C_INHERIT_READ RT_BIT(0) +/** Mark the write end as inheritable. */ +#define RTPIPE_C_INHERIT_WRITE RT_BIT(1) +/** Mask of valid flags. */ +#define RTPIPE_C_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** + * Closes one end of a pipe created by RTPipeCreate. + * + * @returns IPRT status code. + * @param hPipe The pipe end to close. + */ +RTDECL(int) RTPipeClose(RTPIPE hPipe); + +/** + * Closes one end of a pipe created by RTPipeCreate, extended version. + * + * @returns IPRT status code. + * @param hPipe The pipe end to close. + * @param fLeaveOpen Wheter to leave the underlying native handle open + * (for RTPipeClose() this is @c false). + */ +RTDECL(int) RTPipeCloseEx(RTPIPE hPipe, bool fLeaveOpen); + +/** + * Creates an IPRT pipe handle from a native one. + * + * Do NOT use the native handle after passing it to this function, IPRT owns it + * and might even have closed in some cases (in order to gain some query + * information access on Windows). + * + * @returns IPRT status code. + * @param phPipe Where to return the pipe handle. + * @param hNativePipe The native pipe handle. + * @param fFlags Pipe flags, RTPIPE_N_XXX. + */ +RTDECL(int) RTPipeFromNative(PRTPIPE phPipe, RTHCINTPTR hNativePipe, uint32_t fFlags); + +/** @name RTPipeFromNative flags. + * @{ */ +/** The read end. */ +#define RTPIPE_N_READ RT_BIT(0) +/** The write end. */ +#define RTPIPE_N_WRITE RT_BIT(1) +/** Make sure the pipe is inheritable if set and not inheritable when clear. */ +#define RTPIPE_N_INHERIT RT_BIT(2) +/** Mask of valid flags for . */ +#define RTPIPE_N_VALID_MASK UINT32_C(0x00000007) +/** RTPipeFromNative: Leave the native pipe handle open on close. */ +#define RTPIPE_N_LEAVE_OPEN RT_BIT(3) +/** Mask of valid flags for RTPipeFromNative(). */ +#define RTPIPE_N_VALID_MASK_FN UINT32_C(0x0000000f) +/** @} */ + +/** + * Gets the native handle for an IPRT pipe handle. + * + * This is mainly for passing a pipe to a child and then closing the parent + * handle. IPRT also uses it internally to implement RTProcCreatEx and + * RTPollSetAdd on some platforms. Do NOT expect sane API behavior if used + * for any other purpose. + * + * @returns The native handle. -1 on failure. + * @param hPipe The IPRT pipe handle. + */ +RTDECL(RTHCINTPTR) RTPipeToNative(RTPIPE hPipe); + +/** + * Get the creation inheritability of the pipe. + * + * @returns true if inherited by children (when pipe was created), false if not. + * @param hPipe The IPRT pipe handle. + */ +RTDECL(int) RTPipeGetCreationInheritability(RTPIPE hPipe); + +/** + * Read bytes from a pipe, non-blocking. + * + * @returns IPRT status code. + * @retval VERR_WRONG_ORDER if racing a call to RTPipeReadBlocking. + * @retval VERR_BROKEN_PIPE if the remote party has disconnected and we've read + * all the buffered data. + * @retval VINF_TRY_AGAIN if no data was available. @a *pcbRead will be set to + * 0. + * @retval VERR_ACCESS_DENIED if it's a write pipe. + * + * @param hPipe The IPRT pipe handle to read from. + * @param pvBuf Where to put the bytes we read. + * @param cbToRead How much to read. Must be greater than 0. + * @param pcbRead Where to return the number of bytes that has been + * read (mandatory). This is 0 if there is no more + * bytes to read. + * @sa RTPipeReadBlocking. + */ +RTDECL(int) RTPipeRead(RTPIPE hPipe, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Read bytes from a pipe, blocking. + * + * @returns IPRT status code. + * @retval VERR_WRONG_ORDER if racing a call to RTPipeRead. + * @retval VERR_BROKEN_PIPE if the remote party has disconnected and we've read + * all the buffered data. + * @retval VERR_ACCESS_DENIED if it's a write pipe. + * + * @param hPipe The IPRT pipe handle to read from. + * @param pvBuf Where to put the bytes we read. + * @param cbToRead How much to read. + * @param pcbRead Where to return the number of bytes that has been + * read. Optional. + */ +RTDECL(int) RTPipeReadBlocking(RTPIPE hPipe, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Write bytes to a pipe, non-blocking. + * + * @returns IPRT status code. + * @retval VERR_WRONG_ORDER if racing a call to RTPipeWriteBlocking. + * @retval VERR_BROKEN_PIPE if the remote party has disconnected. Does not + * trigger when @a cbToWrite is 0. + * @retval VINF_TRY_AGAIN if no data was written. @a *pcbWritten will be set + * to 0. + * @retval VERR_ACCESS_DENIED if it's a read pipe. + * + * @param hPipe The IPRT pipe handle to write to. + * @param pvBuf What to write. + * @param cbToWrite How much to write. + * @param pcbWritten How many bytes we wrote, mandatory. The return can + * be 0. + */ +RTDECL(int) RTPipeWrite(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + +/** + * Write bytes to a pipe, blocking. + * + * @returns IPRT status code. + * @retval VERR_WRONG_ORDER if racing a call to RTPipeWrite. + * @retval VERR_BROKEN_PIPE if the remote party has disconnected. Does not + * trigger when @a cbToWrite is 0. + * @retval VERR_ACCESS_DENIED if it's a read pipe. + * + * @param hPipe The IPRT pipe handle to write to. + * @param pvBuf What to write. + * @param cbToWrite How much to write. + * @param pcbWritten How many bytes we wrote, optional. If NULL then all + * bytes will be written. + */ +RTDECL(int) RTPipeWriteBlocking(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + +/** + * Flushes the buffers for the specified pipe and making sure the other party + * reads them. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if not supported by the OS. + * @retval VERR_BROKEN_PIPE if the remote party has disconnected. + * @retval VERR_ACCESS_DENIED if it's a read pipe. + * + * @param hPipe The IPRT pipe handle to flush. + */ +RTDECL(int) RTPipeFlush(RTPIPE hPipe); + +/** + * Checks if the pipe is ready for reading or writing (depending on the pipe + * end). + * + * @returns IPRT status code. + * @retval VERR_TIMEOUT if the timeout was reached before the pipe was ready + * for reading/writing. + * @retval VERR_NOT_SUPPORTED if not supported by the OS? + * + * @param hPipe The IPRT pipe handle to select on. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait for ever. + */ +RTDECL(int) RTPipeSelectOne(RTPIPE hPipe, RTMSINTERVAL cMillies); + +/** + * Queries the number of bytes immediately available for reading. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if not supported by the OS. The caller shall + * handle this case. + * + * @param hPipe The IPRT read pipe handle. + * @param pcbReadable Where to return the number of bytes that is ready + * to be read. + */ +RTDECL(int) RTPipeQueryReadable(RTPIPE hPipe, size_t *pcbReadable); + +/** + * Query information about a pipe (mainly a VFS I/O stream formality). + * + * The only thing we guarentee to be returned is RTFSOBJINFO::Attr.fMode being + * set to FIFO and will reflect the read/write end in the RTFS_DOS_READONLY, + * RTFS_UNIX_IRUSR and RTFS_UNIX_IWUSR bits. + * + * Some implementations sometimes provide the pipe buffer size via + * RTFSOBJINFO::cbAllocated. + * + * Some implementations sometimes provide the available read data or available + * write space via RTFSOBJINFO::cbObject. + * + * Some implementations sometimes provide valid device and/or inode numbers. + * + * @returns iprt status code. + * + * @param hPipe The IPRT read pipe handle. + * @param pObjInfo Object information structure to be filled on successful + * return. + * @param enmAddAttr Which set of additional attributes to request. Use + * RTFSOBJATTRADD_NOTHING if this doesn't matter. + */ +RTDECL(int) RTPipeQueryInfo(RTPIPE hPipe, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_pipe_h */ + diff --git a/include/iprt/poll.h b/include/iprt/poll.h new file mode 100644 index 00000000..be2b3b6d --- /dev/null +++ b/include/iprt/poll.h @@ -0,0 +1,265 @@ +/** @file + * IPRT - Polling I/O Handles. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_poll_h +#define IPRT_INCLUDED_poll_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_poll RTPoll - Polling I/O Handles + * @ingroup grp_rt + * @{ + */ + +/** @name Poll events + * @{ */ +/** Readable without blocking. */ +#define RTPOLL_EVT_READ RT_BIT_32(0) +/** Writable without blocking. */ +#define RTPOLL_EVT_WRITE RT_BIT_32(1) +/** Error condition, hangup, exception or similar. */ +#define RTPOLL_EVT_ERROR RT_BIT_32(2) +/** Mask of the valid bits. */ +#define RTPOLL_EVT_VALID_MASK UINT32_C(0x00000007) +/** @} */ + +/** + * Polls on the specified poll set until an event occurs on one of the handles + * or the timeout expires. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if an event occurred on a handle. Note that these + * @retval VERR_INVALID_HANDLE if @a hPollSet is invalid. + * @retval VERR_CONCURRENT_ACCESS if another thread is already accessing the set. The + * user is responsible for ensuring single threaded access. + * @retval VERR_TIMEOUT if @a cMillies ellapsed without any events. + * @retval VERR_DEADLOCK if @a cMillies is set to RT_INDEFINITE_WAIT and there + * are no valid handles in the set. + * + * @param hPollSet The set to poll on. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait for ever. + * @param pfEvents Where to return details about the events that + * occurred. Optional. + * @param pid Where to return the ID associated with the + * handle when calling RTPollSetAdd. Optional. + * + * @sa RTPollNoResume + * + * @remarks The caller is responsible for ensuring + */ +RTDECL(int) RTPoll(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid); + +/** + * Same as RTPoll except that it will return when interrupted. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if an event occurred on a handle. Note that these + * @retval VERR_INVALID_HANDLE if @a hPollSet is invalid. + * @retval VERR_CONCURRENT_ACCESS if another thread is already accessing the set. The + * user is responsible for ensuring single threaded access. + * @retval VERR_TIMEOUT if @a cMillies ellapsed without any events. + * @retval VERR_DEADLOCK if @a cMillies is set to RT_INDEFINITE_WAIT and there + * are no valid handles in the set. + * @retval VERR_INTERRUPTED if a signal or other asynchronous event interrupted + * the polling. + * + * @param hPollSet The set to poll on. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait for ever. + * @param pfEvents Where to return details about the events that + * occurred. Optional. + * @param pid Where to return the ID associated with the + * handle when calling RTPollSetAdd. Optional. + */ +RTDECL(int) RTPollNoResume(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid); + +/** + * Creates a poll set with no members. + * + * @returns IPRT status code. + * @param phPollSet Where to return the poll set handle. + */ +RTDECL(int) RTPollSetCreate(PRTPOLLSET phPollSet); + +/** + * Destroys a poll set. + * + * @returns IPRT status code. + * @param hPollSet The poll set to destroy. NIL_POLLSET is quietly + * ignored (VINF_SUCCESS). + */ +RTDECL(int) RTPollSetDestroy(RTPOLLSET hPollSet); + +/** + * Adds a generic handle to the poll set. + * + * If a handle is entered more than once, it is recommended to add the one with + * RTPOLL_EVT_ERROR first to ensure that you get the right ID back when an error + * actually occurs. On some hosts it is possible that polling for + * RTPOLL_EVT_READ on a socket may cause it to return error conditions because + * the two cannot so easily be distinguished. + * + * Also note that RTPOLL_EVT_ERROR may be returned by RTPoll even if not asked + * for. + * + * @returns IPRT status code + * @retval VERR_CONCURRENT_ACCESS if another thread is already accessing the set. The + * user is responsible for ensuring single threaded access. + * @retval VERR_POLL_HANDLE_NOT_POLLABLE if the specified handle is not + * pollable. + * @retval VERR_POLL_HANDLE_ID_EXISTS if the handle ID is already in use in the + * set. + * + * @param hPollSet The poll set to modify. + * @param pHandle The handle to add. NIL handles are quietly + * ignored. + * @param fEvents Which events to poll for. + * @param id The handle ID. + */ +RTDECL(int) RTPollSetAdd(RTPOLLSET hPollSet, PCRTHANDLE pHandle, uint32_t fEvents, uint32_t id); + +/** + * Removes a generic handle from the poll set. + * + * @returns IPRT status code + * @retval VERR_INVALID_HANDLE if @a hPollSet not valid. + * @retval VERR_CONCURRENT_ACCESS if another thread is already accessing the set. The + * user is responsible for ensuring single threaded access. + * @retval VERR_POLL_HANDLE_ID_NOT_FOUND if @a id doesn't resolve to a valid + * handle. + * + * @param hPollSet The poll set to modify. + * @param id The handle ID of the handle that should be + * removed. + */ +RTDECL(int) RTPollSetRemove(RTPOLLSET hPollSet, uint32_t id); + + +/** + * Query a handle in the poll set by it's ID. + * + * @returns IPRT status code + * @retval VINF_SUCCESS if the handle was found. @a *pHandle is set. + * @retval VERR_INVALID_HANDLE if @a hPollSet is invalid. + * @retval VERR_CONCURRENT_ACCESS if another thread is already accessing the set. The + * user is responsible for ensuring single threaded access. + * @retval VERR_POLL_HANDLE_ID_NOT_FOUND if there is no handle with that ID. + * + * @param hPollSet The poll set to query. + * @param id The ID of the handle. + * @param pHandle Where to return the handle details. Optional. + */ +RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle); + +/** + * Gets the number of handles in the set. + * + * @retval The handle count. + * @retval UINT32_MAX if @a hPollSet is invalid or there is concurrent access. + * + * @param hPollSet The poll set. + */ +RTDECL(uint32_t) RTPollSetGetCount(RTPOLLSET hPollSet); + +/** + * Modifies the events to poll for for the given id. + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if @a hPollSet not valid. + * @retval VERR_CONCURRENT_ACCESS if another thread is already accessing the set. The + * user is responsible for ensuring single threaded access. + * @retval VERR_POLL_HANDLE_ID_NOT_FOUND if @a id doesn't resolve to a valid + * handle. + * + * @param hPollSet The poll set to modify. + * @param id The handle ID to change the events for. + * @param fEvents Which events to poll for. + */ +RTDECL(int) RTPollSetEventsChange(RTPOLLSET hPollSet, uint32_t id, uint32_t fEvents); + +/** + * Adds a pipe handle to the set. + * + * @returns See RTPollSetAdd. + * + * @param hPollSet The poll set. + * @param hPipe The pipe handle. + * @param fEvents Which events to poll for. + * @param id The handle ID. + * + * @todo Maybe we could figure out what to poll for depending on the kind of + * pipe we're dealing with. + */ +DECLINLINE(int) RTPollSetAddPipe(RTPOLLSET hPollSet, RTPIPE hPipe, uint32_t fEvents, uint32_t id) +{ + RTHANDLE Handle; + Handle.enmType = RTHANDLETYPE_PIPE; + Handle.u.uInt = 0; + Handle.u.hPipe = hPipe; + return RTPollSetAdd(hPollSet, &Handle, fEvents, id); +} + +/** + * Adds a socket handle to the set. + * + * @returns See RTPollSetAdd. + * + * @param hPollSet The poll set. + * @param hSocket The socket handle. + * @param fEvents Which events to poll for. + * @param id The handle ID. + */ +DECLINLINE(int) RTPollSetAddSocket(RTPOLLSET hPollSet, RTSOCKET hSocket, uint32_t fEvents, uint32_t id) +{ + RTHANDLE Handle; + Handle.enmType = RTHANDLETYPE_SOCKET; + Handle.u.uInt = 0; + Handle.u.hSocket = hSocket; + return RTPollSetAdd(hPollSet, &Handle, fEvents, id); +} + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_poll_h */ + diff --git a/include/iprt/power.h b/include/iprt/power.h new file mode 100644 index 00000000..d36e840d --- /dev/null +++ b/include/iprt/power.h @@ -0,0 +1,125 @@ +/** @file + * IPRT - Power management. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_power_h +#define IPRT_INCLUDED_power_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_power RTPower - Power management + * @ingroup grp_rt + * @{ + */ + +#ifdef IN_RING0 + +/** + * MP event, see FNRTPOWERNOTIFICATION. + */ +typedef enum RTPOWEREVENT +{ + /** The system will go into suspend mode. */ + RTPOWEREVENT_SUSPEND = 1, + /** The system has resumed. */ + RTPOWEREVENT_RESUME +} RTPOWEREVENT; + +/** + * Notification callback. + * + * The context this is called in differs a bit from platform to + * platform, so be careful while in here. + * + * @param enmEvent The event. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(void, FNRTPOWERNOTIFICATION,(RTPOWEREVENT enmEvent, void *pvUser)); +/** Pointer to a FNRTPOWERNOTIFICATION(). */ +typedef FNRTPOWERNOTIFICATION *PFNRTPOWERNOTIFICATION; + +/** + * Registers a notification callback for power events. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NO_MEMORY if a registration record cannot be allocated. + * @retval VERR_ALREADY_EXISTS if the pfnCallback and pvUser already exist + * in the callback list. + * + * @param pfnCallback The callback. + * @param pvUser The user argument to the callback function. + */ +RTDECL(int) RTPowerNotificationRegister(PFNRTPOWERNOTIFICATION pfnCallback, void *pvUser); + +/** + * This deregisters a notification callback registered via RTPowerNotificationRegister(). + * + * The pfnCallback and pvUser arguments must be identical to the registration call + * of we won't find the right entry. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_FOUND if no matching entry was found. + * + * @param pfnCallback The callback. + * @param pvUser The user argument to the callback function. + */ +RTDECL(int) RTPowerNotificationDeregister(PFNRTPOWERNOTIFICATION pfnCallback, void *pvUser); + +/** + * This calls all registered power management callback handlers registered via RTPowerNotificationRegister(). + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * + * @param enmEvent Power Management event + */ +RTDECL(int) RTPowerSignalEvent(RTPOWEREVENT enmEvent); + +#endif /* IN_RING0 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_power_h */ + diff --git a/include/iprt/process.h b/include/iprt/process.h new file mode 100644 index 00000000..de3590e8 --- /dev/null +++ b/include/iprt/process.h @@ -0,0 +1,479 @@ +/** @file + * IPRT - Process Management. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_process_h +#define IPRT_INCLUDED_process_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_process RTProc - Process Management + * @ingroup grp_rt + * @{ + */ + + +/** + * Process priority. + * + * The process priority is used to select how scheduling properties + * are assigned to the different thread types (see THREADTYPE). + * + * In addition to using the policy assigned to the process at startup (DEFAULT) + * it is possible to change the process priority at runtime. This allows for + * a GUI, resource manager or admin to adjust the general priority of a task + * without upsetting the fine-tuned priority of the threads within. + */ +typedef enum RTPROCPRIORITY +{ + /** Invalid priority. */ + RTPROCPRIORITY_INVALID = 0, + /** Default priority. + * Derive the scheduling policy from the priority of the RTR3Init() + * and RTProcSetPriority() callers and the rights the process have + * to alter its own priority. + */ + RTPROCPRIORITY_DEFAULT, + /** Flat priority. + * Assumes a scheduling policy which puts the process at the default priority + * and with all thread at the same priority. + */ + RTPROCPRIORITY_FLAT, + /** Low priority. + * Assumes a scheduling policy which puts the process mostly below the + * default priority of the host OS. + */ + RTPROCPRIORITY_LOW, + /** Normal priority. + * Assume a scheduling policy which shares the CPU resources fairly with + * other processes running with the default priority of the host OS. + */ + RTPROCPRIORITY_NORMAL, + /** High priority. + * Assumes a scheduling policy which puts the task above the default + * priority of the host OS. This policy might easily cause other tasks + * in the system to starve. + */ + RTPROCPRIORITY_HIGH, + /** Last priority, used for validation. */ + RTPROCPRIORITY_LAST +} RTPROCPRIORITY; + + +/** + * Get the current process identifier. + * + * @returns Process identifier. + */ +RTDECL(RTPROCESS) RTProcSelf(void); + + +#ifdef IN_RING0 +/** + * Get the current process handle. + * + * @returns Ring-0 process handle. + */ +RTR0DECL(RTR0PROCESS) RTR0ProcHandleSelf(void); +#endif + + +/** + * Translate a signal number to a short name on the form SIGXXXX. + * + * If the signal is not known, it will be formatted as a number into one of + * several static buffers. This means that there could be concurrency issues if + * this suddenly happens on multiple threads, though that is unlikely. + * + * @returns Readonly string naming the signal. + * @param iSignal The signal to name. + */ +RTDECL(const char *) RTProcSignalName(int iSignal); + +#ifdef IN_RING3 + +/** + * Attempts to alter the priority of the current process. + * + * @returns iprt status code. + * @param enmPriority The new priority. + */ +RTR3DECL(int) RTProcSetPriority(RTPROCPRIORITY enmPriority); + +/** + * Gets the current priority of this process. + * + * @returns The priority (see RTPROCPRIORITY). + */ +RTR3DECL(RTPROCPRIORITY) RTProcGetPriority(void); + +/** + * Create a child process. + * + * @returns iprt status code. + * @param pszExec Executable image to use to create the child process. + * @param papszArgs Pointer to an array of arguments to the child. The array terminated by an entry containing NULL. + * @param Env Handle to the environment block for the child. + * @param fFlags Flags, one of the RTPROC_FLAGS_* defines. + * @param pProcess Where to store the process identifier on successful return. + * The content is not changed on failure. NULL is allowed. + */ +RTR3DECL(int) RTProcCreate(const char *pszExec, const char * const *papszArgs, RTENV Env, unsigned fFlags, PRTPROCESS pProcess); + + +/** + * Create a child process. + * + * @returns IPRT status code. + * + * @param pszExec Executable image to use to create the child process. + * @param papszArgs Pointer to an array of arguments to the child. The + * array terminated by an entry containing NULL. + * @param hEnv Handle to the environment block for the child. Pass + * RTENV_DEFAULT to use the environment of the current + * process. + * @param fFlags Flags, one of the RTPROC_FLAGS_* defines. + * @param phStdIn The standard in handle to assign the new process. Pass + * NULL to use the same as the current process. If the + * handle is NIL, we'll close the standard input of the + * guest. + * @param phStdOut The standard out handle to assign the new process. Pass + * NULL to use the same as the current process. If the + * handle is NIL, we'll close the standard output of the + * guest. + * @param phStdErr The standard error handle to assign the new process. Pass + * NULL to use the same as the current process. If the + * handle is NIL, we'll close the standard error of the + * guest. + * @param pszAsUser User to run the process as. Pass NULL to use the same + * user as the current process. + * Windows: Use user\@domain (UPN, User Principal Name) + * format to specify a domain. + * @param pszPassword Password to use to authenticate @a pszAsUser. Must be + * NULL wif pszAsUser is NULL. Whether this is actually + * used or not depends on the platform. + * @param pvExtraData Points to additional data as per @a fFlags: + * - RTPROC_FLAGS_DESIRED_SESSION_ID: Pointing to a + * uint32_t variable with the desired session ID. + * @param phProcess Where to store the process handle on successful return. + * The content is not changed on failure. NULL is allowed. + * + * @remarks The handles does not have to be created as inheritable, but it + * doesn't hurt if they are as it may avoid race conditions on some + * platforms. + * + * @remarks The as-user feature isn't supported/implemented on all platforms and + * will cause a-yet-to-be-determined-error-status on these. + */ +RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags, + PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser, + const char *pszPassword, void *pvExtraData, PRTPROCESS phProcess); + +/** @name RTProcCreate and RTProcCreateEx flags + * @{ */ +/** Detach the child process from the parents process tree and process group, + * session or/and console (depends on the platform what's done applicable). + * + * The new process will not be a direct decendent of the parent and it will not + * be possible to wait for it, i.e. @a phProcess shall be NULL. */ +#define RTPROC_FLAGS_DETACHED RT_BIT(0) +/** Don't show the started process. + * This is a Windows (and maybe OS/2) concept, do not use on other platforms. */ +#define RTPROC_FLAGS_HIDDEN RT_BIT(1) +/** Use special code path for starting child processes from a service (daemon). + * This is a windows concept for dealing with the so called "Session 0" + * isolation which was introduced with Windows Vista. Do not use on other + * platforms. */ +#define RTPROC_FLAGS_SERVICE RT_BIT(2) +/** Suppress changing the process contract id for the child process + * on Solaris. Without this flag the contract id is always changed, as that's + * the more frequently used case. */ +#define RTPROC_FLAGS_SAME_CONTRACT RT_BIT(3) +/** Load user profile data when executing a process. + * This redefines the meaning of RTENV_DEFAULT to the profile environment. See + * also RTPROC_FLAGS_ONLY_BASIC_PROFILE */ +#define RTPROC_FLAGS_PROFILE RT_BIT(4) +/** Create process without a console window. + * This is a Windows (and OS/2) concept, do not use on other platforms. */ +#define RTPROC_FLAGS_NO_WINDOW RT_BIT(5) +/** Search the PATH for the executable. */ +#define RTPROC_FLAGS_SEARCH_PATH RT_BIT(6) +/** Don't quote and escape arguments on Windows and similar platforms where a + * command line is passed to the child process instead of an argument vector, + * just join up argv with a space between each. Ignored on platforms + * passing argument the vector. */ +#define RTPROC_FLAGS_UNQUOTED_ARGS RT_BIT(7) +/** Consider hEnv an environment change record to be applied to RTENV_DEFAULT. + * If hEnv is RTENV_DEFAULT, the flag has no effect. */ +#define RTPROC_FLAGS_ENV_CHANGE_RECORD RT_BIT(8) +/** Create process using the current impersonated thread token. + * Caller should also specify RTPROC_FLAGS_SERVICE and RTPROC_FLAGS_PROFILE. + * Windows only flag, ignored everywhere else. */ +#define RTPROC_FLAGS_AS_IMPERSONATED_TOKEN RT_BIT(9) +/** Hint that we don't expect to ever want to wait on the process. */ +#define RTPROC_FLAGS_NO_WAIT RT_BIT(10) +/** For use with RTPROC_FLAGS_SERVICE to specify a desired session ID + * (Windows only, ignored elsewhere). The @a pvExtraData argument points to + * a uint32_t containing the session ID, UINT32_MAX means any session. + * Can not be set with RTPROC_FLAGS_TOKEN_SUPPLIED */ +#define RTPROC_FLAGS_DESIRED_SESSION_ID RT_BIT(11) +/** This is a modifier to RTPROC_FLAGS_PROFILE on unix systems that makes it + * skip trying to dump the environment of a login shell. */ +#define RTPROC_FLAGS_ONLY_BASIC_PROFILE RT_BIT(12) +/** Don't translate arguments to the (guessed) child process codeset. + * This is ignored on Windows as it is using UTF-16. */ +#define RTPROC_FLAGS_UTF8_ARGV RT_BIT_32(13) +/** Create process using supplied token. The @a pvExtraData argument points to + * a HANDLE containing the token used as user credentials for process creation. + * Can not be set with RTPROC_FLAGS_DESIRED_SESSION_ID. + * Windows only flag, ignored everywhere else. */ +#define RTPROC_FLAGS_TOKEN_SUPPLIED RT_BIT(14) + +/** Valid flag mask. */ +#define RTPROC_FLAGS_VALID_MASK UINT32_C(0x7fff) +/** @} */ + + +/** + * Process exit reason. + */ +typedef enum RTPROCEXITREASON +{ + /** Normal exit. iStatus contains the exit code. */ + RTPROCEXITREASON_NORMAL = 1, + /** Any abnormal exit. iStatus is undefined. */ + RTPROCEXITREASON_ABEND, + /** Killed by a signal. The iStatus field contains the signal number. */ + RTPROCEXITREASON_SIGNAL +} RTPROCEXITREASON; + +/** + * Process exit status. + */ +typedef struct RTPROCSTATUS +{ + /** The process exit status if the exit was a normal one. */ + int iStatus; + /** The reason the process terminated. */ + RTPROCEXITREASON enmReason; +} RTPROCSTATUS; +/** Pointer to a process exit status structure. */ +typedef RTPROCSTATUS *PRTPROCSTATUS; +/** Pointer to a const process exit status structure. */ +typedef const RTPROCSTATUS *PCRTPROCSTATUS; + + +/** Flags for RTProcWait(). + * @{ */ +/** Block indefinitly waiting for the process to exit. */ +#define RTPROCWAIT_FLAGS_BLOCK 0 +/** Don't block, just check if the process have exited. */ +#define RTPROCWAIT_FLAGS_NOBLOCK 1 +/** @} */ + +/** + * Waits for a process, resumes on interruption. + * + * @returns VINF_SUCCESS when the status code for the process was collected and + * put in *pProcStatus. + * @returns VERR_PROCESS_NOT_FOUND if the specified process wasn't found. + * @returns VERR_PROCESS_RUNNING when the RTPROCWAIT_FLAGS_NOBLOCK and the + * process haven't exited yet. + * + * @param Process The process to wait for. + * @param fFlags The wait flags, any of the RTPROCWAIT_FLAGS_ \#defines. + * @param pProcStatus Where to store the exit status on success. + * Optional. + */ +RTR3DECL(int) RTProcWait(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus); + +/** + * Waits for a process, returns on interruption. + * + * @returns VINF_SUCCESS when the status code for the process was collected and + * put in *pProcStatus. + * @returns VERR_PROCESS_NOT_FOUND if the specified process wasn't found. + * @returns VERR_PROCESS_RUNNING when the RTPROCWAIT_FLAGS_NOBLOCK and the + * process haven't exited yet. + * @returns VERR_INTERRUPTED when the wait was interrupted by the arrival of a + * signal or other async event. + * + * @param Process The process to wait for. + * @param fFlags The wait flags, any of the RTPROCWAIT_FLAGS_ \#defines. + * @param pProcStatus Where to store the exit status on success. + * Optional. + */ +RTR3DECL(int) RTProcWaitNoResume(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus); + +/** + * Terminates (kills) a running process. + * + * @returns IPRT status code. + * @param Process The process to terminate. + */ +RTR3DECL(int) RTProcTerminate(RTPROCESS Process); + +/** + * Gets the processor affinity mask of the current process. + * + * @returns The affinity mask. + */ +RTR3DECL(uint64_t) RTProcGetAffinityMask(void); + +/** + * Gets the short process name. + * + * @returns Pointer to read-only name string. + * @note IPRT must've been initialized or the string will be empty. + */ +RTR3DECL(const char *) RTProcShortName(void); + +/** + * Gets the path to the executable image of the current process. + * + * @returns Pointer to read-only path string. + * @note IPRT must've been initialized or the string will be empty. + */ +RTR3DECL(const char *) RTProcExecutablePath(void); + +/** + * Gets a copy of the path to the executable image of the current process. + * + * @returns pszExecPath on success. NULL on buffer overflow or other errors. + * + * @param pszExecPath Where to store the path. + * @param cbExecPath The size of the buffer. + * @note IPRT must've been initialized or the string will be empty. + */ +RTR3DECL(char *) RTProcGetExecutablePath(char *pszExecPath, size_t cbExecPath); + +/** + * Daemonize the current process, making it a background process. + * + * The way this work is that it will spawn a detached / backgrounded / + * daemonized / call-it-what-you-want process that isn't a direct child of the + * current process. The spawned will have the same arguments a the caller, + * except that the @a pszDaemonizedOpt is appended to prevent that the new + * process calls this API again. + * + * The new process will have the standard handles directed to/from the + * bitbucket. + * + * @returns IPRT status code. On success it is normal for the caller to exit + * the process by returning from main(). + * + * @param papszArgs The argument vector of the calling process. + * @param pszDaemonizedOpt The daemonized option. This is appended to the + * end of the parameter list of the daemonized process. + */ +RTR3DECL(int) RTProcDaemonize(const char * const *papszArgs, const char *pszDaemonizedOpt); + +/** + * Daemonize the current process, making it a background process. The current + * process will exit if daemonizing is successful. + * + * @returns IPRT status code. On success it will only return in the child + * process, the parent will exit. On failure, it will return in the + * parent process and no child has been spawned. + * + * @param fNoChDir Pass false to change working directory to "/". + * @param fNoClose Pass false to redirect standard file streams to the null device. + * @param pszPidfile Path to a file to write the process id of the daemon + * process to. Daemonizing will fail if this file already + * exists or cannot be written. May be NULL. + */ +RTR3DECL(int) RTProcDaemonizeUsingFork(bool fNoChDir, bool fNoClose, const char *pszPidfile); + +/** + * Check if the given process is running on the system. + * + * This check is case sensitive on most systems, except for Windows, OS/2 and + * Darwin. + * + * @returns true if the process is running & false otherwise. + * @param pszName Process name to search for. If no path is given only the + * filename part of the running process set will be + * matched. If a path is specified, the full path will be + * matched. + */ +RTR3DECL(bool) RTProcIsRunningByName(const char *pszName); + +/** + * Queries the parent process ID. + * + * @returns IPRT status code + * @param hProcess The process to query the parent of. + * @param phParent Where to return the parent process ID. + */ +RTR3DECL(int) RTProcQueryParent(RTPROCESS hProcess, PRTPROCESS phParent); + +/** + * Query the username of the given process. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW if the given buffer size is to small for the username. + * @param hProcess The process handle to query the username for. + * NIL_PROCESS is an alias for the current process. + * @param pszUser Where to store the user name on success. + * @param cbUser The size of the user name buffer. + * @param pcbUser Where to store the username length on success + * or the required buffer size if VERR_BUFFER_OVERFLOW + * is returned. + */ +RTR3DECL(int) RTProcQueryUsername(RTPROCESS hProcess, char *pszUser, size_t cbUser, size_t *pcbUser); + +/** + * Query the username of the given process allocating the string for the username. + * + * @returns IPRT status code. + * @param hProcess The process handle to query the username for. + * @param ppszUser Where to store the pointer to the string containing + * the username on success. Free with RTStrFree(). + */ +RTR3DECL(int) RTProcQueryUsernameA(RTPROCESS hProcess, char **ppszUser); + +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_process_h */ + diff --git a/include/iprt/queueatomic.h b/include/iprt/queueatomic.h new file mode 100644 index 00000000..72b188e1 --- /dev/null +++ b/include/iprt/queueatomic.h @@ -0,0 +1,137 @@ +/** @file + * IPRT - Generic Work Queue with concurrent atomic access. + */ + +/* + * Copyright (C) 2013-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_queueatomic_h +#define IPRT_INCLUDED_queueatomic_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/asm.h> + +/** @defgroup grp_rt_queueatomic RTQueueAtomic - Generic Work Queue + * @ingroup grp_rt + * + * Implementation of a lockless work queue for threaded environments. + * @{ + */ + +RT_C_DECLS_BEGIN + +/** + * A work item + */ +typedef struct RTQUEUEATOMICITEM +{ + /** Pointer to the next work item in the list. */ + struct RTQUEUEATOMICITEM * volatile pNext; +} RTQUEUEATOMICITEM; +/** Pointer to a work item. */ +typedef RTQUEUEATOMICITEM *PRTQUEUEATOMICITEM; +/** Pointer to a work item pointer. */ +typedef PRTQUEUEATOMICITEM *PPRTQUEUEATOMICITEM; + +/** + * Work queue. + */ +typedef struct RTQUEUEATOMIC +{ + /* Head of the work queue. */ + volatile PRTQUEUEATOMICITEM pHead; +} RTQUEUEATOMIC; +/** Pointer to a work queue. */ +typedef RTQUEUEATOMIC *PRTQUEUEATOMIC; + +/** + * Initialize a work queue. + * + * @param pWorkQueue Pointer to an unitialised work queue. + */ +DECLINLINE(void) RTQueueAtomicInit(PRTQUEUEATOMIC pWorkQueue) +{ + ASMAtomicWriteNullPtr(&pWorkQueue->pHead); +} + +/** + * Insert a new item into the work queue. + * + * @param pWorkQueue The work queue to insert into. + * @param pItem The item to insert. + */ +DECLINLINE(void) RTQueueAtomicInsert(PRTQUEUEATOMIC pWorkQueue, PRTQUEUEATOMICITEM pItem) +{ + PRTQUEUEATOMICITEM pNext = ASMAtomicUoReadPtrT(&pWorkQueue->pHead, PRTQUEUEATOMICITEM); + PRTQUEUEATOMICITEM pHeadOld; + pItem->pNext = pNext; + while (!ASMAtomicCmpXchgExPtr(&pWorkQueue->pHead, pItem, pNext, &pHeadOld)) + { + pNext = pHeadOld; + Assert(pNext != pItem); + pItem->pNext = pNext; + ASMNopPause(); + } +} + +/** + * Remove all items from the given work queue and return them in the inserted order. + * + * @returns Pointer to the first item. + * @param pWorkQueue The work queue. + */ +DECLINLINE(PRTQUEUEATOMICITEM) RTQueueAtomicRemoveAll(PRTQUEUEATOMIC pWorkQueue) +{ + PRTQUEUEATOMICITEM pHead = ASMAtomicXchgPtrT(&pWorkQueue->pHead, NULL, PRTQUEUEATOMICITEM); + + /* Reverse it. */ + PRTQUEUEATOMICITEM pCur = pHead; + pHead = NULL; + while (pCur) + { + PRTQUEUEATOMICITEM pInsert = pCur; + pCur = pCur->pNext; + pInsert->pNext = pHead; + pHead = pInsert; + } + + return pHead; +} + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_queueatomic_h */ + diff --git a/include/iprt/rand.h b/include/iprt/rand.h new file mode 100644 index 00000000..149e0fb5 --- /dev/null +++ b/include/iprt/rand.h @@ -0,0 +1,330 @@ +/** @file + * IPRT - Random Numbers and Byte Streams. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_rand_h +#define IPRT_INCLUDED_rand_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_rand RTRand - Random Numbers and Byte Streams + * @ingroup grp_rt + * @{ + */ + +/** + * Fills a buffer with random bytes. + * + * @param pv Where to store the random bytes. + * @param cb Number of bytes to generate. + */ +RTDECL(void) RTRandBytes(void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** + * Generate a 32-bit signed random number in the set [i32First..i32Last]. + * + * @returns The random number. + * @param i32First First number in the set. + * @param i32Last Last number in the set. + */ +RTDECL(int32_t) RTRandS32Ex(int32_t i32First, int32_t i32Last) RT_NO_THROW_PROTO; + +/** + * Generate a 32-bit signed random number. + * + * @returns The random number. + */ +RTDECL(int32_t) RTRandS32(void) RT_NO_THROW_PROTO; + +/** + * Generate a 32-bit unsigned random number in the set [u32First..u32Last]. + * + * @returns The random number. + * @param u32First First number in the set. + * @param u32Last Last number in the set. + */ +RTDECL(uint32_t) RTRandU32Ex(uint32_t u32First, uint32_t u32Last) RT_NO_THROW_PROTO; + +/** + * Generate a 32-bit unsigned random number. + * + * @returns The random number. + */ +RTDECL(uint32_t) RTRandU32(void) RT_NO_THROW_PROTO; + +/** + * Generate a 64-bit signed random number in the set [i64First..i64Last]. + * + * @returns The random number. + * @param i64First First number in the set. + * @param i64Last Last number in the set. + */ +RTDECL(int64_t) RTRandS64Ex(int64_t i64First, int64_t i64Last) RT_NO_THROW_PROTO; + +/** + * Generate a 64-bit signed random number. + * + * @returns The random number. + */ +RTDECL(int64_t) RTRandS64(void) RT_NO_THROW_PROTO; + +/** + * Generate a 64-bit unsigned random number in the set [u64First..u64Last]. + * + * @returns The random number. + * @param u64First First number in the set. + * @param u64Last Last number in the set. + */ +RTDECL(uint64_t) RTRandU64Ex(uint64_t u64First, uint64_t u64Last) RT_NO_THROW_PROTO; + +/** + * Generate a 64-bit unsigned random number. + * + * @returns The random number. + */ +RTDECL(uint64_t) RTRandU64(void) RT_NO_THROW_PROTO; + + +/** + * Create an instance of the default random number generator. + * + * @returns IPRT status code. + * @param phRand Where to return the handle to the new random number + * generator. + */ +RTDECL(int) RTRandAdvCreate(PRTRAND phRand) RT_NO_THROW_PROTO; + +/** + * Create an instance of the default pseudo random number generator. + * + * @returns IPRT status code. + * @param phRand Where to store the handle to the generator. + */ +RTDECL(int) RTRandAdvCreatePseudo(PRTRAND phRand) RT_NO_THROW_PROTO; + +/** + * Create an instance of the Park-Miller pseudo random number generator. + * + * @returns IPRT status code. + * @param phRand Where to store the handle to the generator. + */ +RTDECL(int) RTRandAdvCreateParkMiller(PRTRAND phRand) RT_NO_THROW_PROTO; + +/** + * Create an instance of the faster random number generator for the OS. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED on platforms which doesn't have this feature. + * @retval VERR_FILE_NOT_FOUND on system where the random generator hasn't + * been installed or configured correctly. + * @retval VERR_PATH_NOT_FOUND for the same reasons as VERR_FILE_NOT_FOUND. + * + * @param phRand Where to store the handle to the generator. + * + * @remarks Think /dev/urandom. + */ +RTDECL(int) RTRandAdvCreateSystemFaster(PRTRAND phRand) RT_NO_THROW_PROTO; + +/** + * Create an instance of the truer random number generator for the OS. + * + * Don't use this unless you seriously need good random numbers because most + * systems will have will have problems producing sufficient entropy for this + * and you'll end up blocking while it accumulates. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED on platforms which doesn't have this feature. + * @retval VERR_FILE_NOT_FOUND on system where the random generator hasn't + * been installed or configured correctly. + * @retval VERR_PATH_NOT_FOUND for the same reasons as VERR_FILE_NOT_FOUND. + * + * @param phRand Where to store the handle to the generator. + * + * @remarks Think /dev/random. + */ +RTDECL(int) RTRandAdvCreateSystemTruer(PRTRAND phRand) RT_NO_THROW_PROTO; + +/** + * Destroys a random number generator. + * + * @returns IPRT status code. + * @param hRand Handle to the random number generator. + */ +RTDECL(int) RTRandAdvDestroy(RTRAND hRand) RT_NO_THROW_PROTO; + +/** + * Generic method for seeding of a random number generator. + * + * The different generators may have specialized methods for + * seeding, use one of those if you desire better control + * over the result. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if it isn't a pseudo generator. + * + * @param hRand Handle to the random number generator. + * @param u64Seed Seed. + */ +RTDECL(int) RTRandAdvSeed(RTRAND hRand, uint64_t u64Seed) RT_NO_THROW_PROTO; + +/** + * Save the current state of a pseudo generator. + * + * This can be use to save the state so it can later be resumed at the same + * position. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. *pcbState contains the length of the + * returned string and pszState contains the state string. + * @retval VERR_BUFFER_OVERFLOW if the supplied buffer is too small. *pcbState + * will contain the necessary buffer size. + * @retval VERR_NOT_SUPPORTED by non-psuedo generators. + * + * @param hRand Handle to the random number generator. + * @param pszState Where to store the state. The returned string will be + * null terminated and printable. + * @param pcbState The size of the buffer pszState points to on input, the + * size required / used on return (including the + * terminator, thus the 'cb' instead of 'cch'). + */ +RTDECL(int) RTRandAdvSaveState(RTRAND hRand, char *pszState, size_t *pcbState) RT_NO_THROW_PROTO; + +/** + * Restores the state of a pseudo generator. + * + * The state must have been obtained using RTRandAdvGetState. + * + * @returns IPRT status code. + * @retval VERR_PARSE_ERROR if the state string is malformed. + * @retval VERR_NOT_SUPPORTED by non-psuedo generators. + * + * @param hRand Handle to the random number generator. + * @param pszState The state to load. + */ +RTDECL(int) RTRandAdvRestoreState(RTRAND hRand, char const *pszState) RT_NO_THROW_PROTO; + +/** + * Fills a buffer with random bytes. + * + * @param hRand Handle to the random number generator. + * @param pv Where to store the random bytes. + * @param cb Number of bytes to generate. + */ +RTDECL(void) RTRandAdvBytes(RTRAND hRand, void *pv, size_t cb) RT_NO_THROW_PROTO; + +/** + * Generate a 32-bit signed random number in the set [i32First..i32Last]. + * + * @returns The random number. + * @param hRand Handle to the random number generator. + * @param i32First First number in the set. + * @param i32Last Last number in the set. + */ +RTDECL(int32_t) RTRandAdvS32Ex(RTRAND hRand, int32_t i32First, int32_t i32Last) RT_NO_THROW_PROTO; + +/** + * Generate a 32-bit signed random number. + * + * @returns The random number. + * @param hRand Handle to the random number generator. + */ +RTDECL(int32_t) RTRandAdvS32(RTRAND hRand) RT_NO_THROW_PROTO; + +/** + * Generate a 32-bit unsigned random number in the set [u32First..u32Last]. + * + * @returns The random number. + * @param hRand Handle to the random number generator. + * @param u32First First number in the set. + * @param u32Last Last number in the set. + */ +RTDECL(uint32_t) RTRandAdvU32Ex(RTRAND hRand, uint32_t u32First, uint32_t u32Last) RT_NO_THROW_PROTO; + +/** + * Generate a 32-bit unsigned random number. + * + * @returns The random number. + * @param hRand Handle to the random number generator. + */ +RTDECL(uint32_t) RTRandAdvU32(RTRAND hRand) RT_NO_THROW_PROTO; + +/** + * Generate a 64-bit signed random number in the set [i64First..i64Last]. + * + * @returns The random number. + * @param hRand Handle to the random number generator. + * @param i64First First number in the set. + * @param i64Last Last number in the set. + */ +RTDECL(int64_t) RTRandAdvS64Ex(RTRAND hRand, int64_t i64First, int64_t i64Last) RT_NO_THROW_PROTO; + +/** + * Generate a 64-bit signed random number. + * + * @returns The random number. + */ +RTDECL(int64_t) RTRandAdvS64(RTRAND hRand) RT_NO_THROW_PROTO; + +/** + * Generate a 64-bit unsigned random number in the set [u64First..u64Last]. + * + * @returns The random number. + * @param hRand Handle to the random number generator. + * @param u64First First number in the set. + * @param u64Last Last number in the set. + */ +RTDECL(uint64_t) RTRandAdvU64Ex(RTRAND hRand, uint64_t u64First, uint64_t u64Last) RT_NO_THROW_PROTO; + +/** + * Generate a 64-bit unsigned random number. + * + * @returns The random number. + * @param hRand Handle to the random number generator. + */ +RTDECL(uint64_t) RTRandAdvU64(RTRAND hRand) RT_NO_THROW_PROTO; + + +/** @} */ + +RT_C_DECLS_END + + +#endif /* !IPRT_INCLUDED_rand_h */ + diff --git a/include/iprt/req.h b/include/iprt/req.h new file mode 100644 index 00000000..a017e9e1 --- /dev/null +++ b/include/iprt/req.h @@ -0,0 +1,643 @@ +/** @file + * IPRT - Request Queue & Pool. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_req_h +#define IPRT_INCLUDED_req_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +#include <iprt/stdarg.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_req RTReq - Request Queue & Pool. + * @ingroup grp_rt + * @{ + */ + +/** Request queue handle. */ +typedef struct RTREQQUEUEINT *RTREQQUEUE; +/** Pointer to a request queue handle. */ +typedef RTREQQUEUE *PRTREQQUEUE; +/** NIL request queue handle. */ +#define NIL_RTREQQUEUE ((RTREQQUEUE)0) + +/** Request thread pool handle. */ +typedef struct RTREQPOOLINT *RTREQPOOL; +/** Poiner to a request thread pool handle. */ +typedef RTREQPOOL *PRTREQPOOL; +/** NIL request pool handle. */ +#define NIL_RTREQPOOL ((RTREQPOOL)0) + + +/** + * Request type. + */ +typedef enum RTREQTYPE +{ + /** Invalid request. */ + RTREQTYPE_INVALID = 0, + /** RT: Internal. */ + RTREQTYPE_INTERNAL, + /** Maximum request type (exclusive). Used for validation. */ + RTREQTYPE_MAX +} RTREQTYPE; + +/** + * Request flags. + */ +typedef enum RTREQFLAGS +{ + /** The request returns a IPRT status code. */ + RTREQFLAGS_IPRT_STATUS = 0, + /** The request is a void request and have no status code. */ + RTREQFLAGS_VOID = 1, + /** Return type mask. */ + RTREQFLAGS_RETURN_MASK = 1, + /** Caller does not wait on the packet. */ + RTREQFLAGS_NO_WAIT = 2 +} RTREQFLAGS; + + +/** A request packet. */ +typedef struct RTREQ RTREQ; +/** Pointer to an RT request packet. */ +typedef RTREQ *PRTREQ; +/** Nil request handle. */ +#define NIL_RTREQ ((PRTREQ)0) + + +#ifdef IN_RING3 + +/** + * Create a request packet queue + * + * @returns IPRT status code. + * @param phQueue Where to store the request queue handle. + */ +RTDECL(int) RTReqQueueCreate(PRTREQQUEUE phQueue); + +/** + * Destroy a request packet queue + * + * @returns IPRT status code. + * @param hQueue The request queue. + */ +RTDECL(int) RTReqQueueDestroy(RTREQQUEUE hQueue); + +/** + * Process one or more request packets + * + * @returns IPRT status code. Any non-VINF_SUCCESS returns from request + * processing is immediately propagated to the caller. + * @retval VERR_TIMEOUT if @a cMillies was reached without the packet being + * added. + * @retval VERR_INVALID_HANDLE if @a hQueue not a valid queue handle. + * + * @param hQueue The request queue. + * @param cMillies Max number of milliseconds to wait for a pending + * request. This is not adjusted down before another + * wait, so the function may end up waiting for much + * longer than the given amount if there are requests + * trickling in at a rate slightly higher than the + * timeout. + * + * Use RT_INDEFINITE_WAIT to process requests until a + * non-VINF_SUCCESS return code is encountered. + * + * @remarks The function may repeatedly try wait for @a cMillies on new + * requests if requests arrive before it times out. + */ +RTDECL(int) RTReqQueueProcess(RTREQQUEUE hQueue, RTMSINTERVAL cMillies); + +/** + * Allocate and queue a call request. + * + * If it's desired to poll on the completion of the request set cMillies + * to 0 and use RTReqWait() to check for completion. In the other case + * use RT_INDEFINITE_WAIT. + * The returned request packet must be freed using RTReqRelease(). + * + * @returns iprt statuscode. + * Will not return VERR_INTERRUPTED. + * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. + * + * @param hQueue The request queue. + * @param ppReq Where to store the pointer to the request. + * This will be NULL or a valid request pointer no matter what happens. + * @param cMillies Number of milliseconds to wait for the request to + * be completed. Use RT_INDEFINITE_WAIT to only + * wait till it's completed. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param ... Function arguments. + * + * @remarks See remarks on RTReqQueueCallV. + */ +RTDECL(int) RTReqQueueCall(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, PFNRT pfnFunction, unsigned cArgs, ...); + +/** + * Allocate and queue a call request to a void function. + * + * If it's desired to poll on the completion of the request set cMillies + * to 0 and use RTReqWait() to check for completion. In the other case + * use RT_INDEFINITE_WAIT. + * The returned request packet must be freed using RTReqRelease(). + * + * @returns IPRT status code. + * Will not return VERR_INTERRUPTED. + * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. + * + * @param hQueue The request queue. + * @param ppReq Where to store the pointer to the request. + * This will be NULL or a valid request pointer no matter what happens. + * @param cMillies Number of milliseconds to wait for the request to + * be completed. Use RT_INDEFINITE_WAIT to only + * wait till it's completed. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param ... Function arguments. + * + * @remarks See remarks on RTReqQueueCallV. + */ +RTDECL(int) RTReqQueueCallVoid(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, PFNRT pfnFunction, unsigned cArgs, ...); + +/** + * Allocate and queue a call request to a void function. + * + * If it's desired to poll on the completion of the request set cMillies + * to 0 and use RTReqWait() to check for completion. In the other case + * use RT_INDEFINITE_WAIT. + * The returned request packet must be freed using RTReqRelease(). + * + * @returns IPRT status code. + * Will not return VERR_INTERRUPTED. + * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. + * + * @param hQueue The request queue. + * @param ppReq Where to store the pointer to the request. Optional + * when RTREQFLAGS_NO_WAIT is used. + * This variable will be set to NIL or a valid request + * handle no matter what happens. + * @param cMillies Number of milliseconds to wait for the request to + * be completed. Use RT_INDEFINITE_WAIT to only + * wait till it's completed. + * @param fFlags A combination of the RTREQFLAGS values. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param ... Function arguments. + * + * @remarks See remarks on RTReqQueueCallV. + */ +RTDECL(int) RTReqQueueCallEx(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, ...); + +/** + * Allocate and queue a call request. + * + * If it's desired to poll on the completion of the request set cMillies + * to 0 and use RTReqWait() to check for completion. In the other case + * use RT_INDEFINITE_WAIT. + * The returned request packet must be freed using RTReqRelease(). + * + * @returns IPRT status code. + * Will not return VERR_INTERRUPTED. + * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. + * + * @param hQueue The request queue. + * @param ppReq Where to store the pointer to the request. Optional + * when RTREQFLAGS_NO_WAIT is used. + * This variable will be set to NIL or a valid request + * handle no matter what happens. + * @param cMillies Number of milliseconds to wait for the request to + * be completed. Use RT_INDEFINITE_WAIT to only + * wait till it's completed. + * @param fFlags A combination of the RTREQFLAGS values. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param Args Variable argument vector. + * + * @remarks Caveats: + * - Do not pass anything which is larger than an uintptr_t. + * - 64-bit integers are larger than uintptr_t on 32-bit hosts. + * Pass integers > 32-bit by reference (pointers). + * - Don't use NULL since it should be the integer 0 in C++ and may + * therefore end up with garbage in the bits 63:32 on 64-bit + * hosts because 'int' is 32-bit. + * Use (void *)NULL or (uintptr_t)0 instead of NULL. + */ +RTDECL(int) RTReqQueueCallV(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args); + +/** + * Checks if the queue is busy or not. + * + * The caller is responsible for dealing with any concurrent submitts. + * + * @returns true if busy, false if idle. + * @param hQueue The queue. + */ +RTDECL(bool) RTReqQueueIsBusy(RTREQQUEUE hQueue); + +/** + * Allocates a request packet. + * + * The caller allocates a request packet, fills in the request data + * union and queues the request. + * + * @returns IPRT status code. + * + * @param hQueue The request queue. + * @param enmType Package type. + * @param phReq Where to store the handle to the new request. + */ +RTDECL(int) RTReqQueueAlloc(RTREQQUEUE hQueue, RTREQTYPE enmType, PRTREQ *phReq); + + +/** + * Creates a request thread pool. + * + * The core configuration is given as parameters, finer pool tuning can be + * achieved via RTReqPoolSetCfgVar. + * + * @returns IPRT status code. + * @param cMaxThreads The maximum number of worker threads. + * UINT32_MAX is an alias for the highest + * allowed thread count. + * @param cMsMinIdle The number of milliseconds a worker + * thread needs to be idle before it is + * considered for shutdown. The value + * RT_INDEFINITE_WAIT disables automatic + * idle thread shutdown. + * @param cThreadsPushBackThreshold At which worker thread count the push + * back should kick in. + * @param cMsMaxPushBack The max number of milliseconds to push + * back a submitter. UINT32_MAX is an + * alias for the highest allowed push back. + * @param pszName The pool name. Keep it short as it is + * used for naming worker threads. + * @param phPool Where to return the pool handle. + */ +RTDECL(int) RTReqPoolCreate(uint32_t cMaxThreads, RTMSINTERVAL cMsMinIdle, + uint32_t cThreadsPushBackThreshold, uint32_t cMsMaxPushBack, + const char *pszName, PRTREQPOOL phPool); + +/** + * Retains a reference to a request thread pool. + * + * @returns The new reference count, UINT32_MAX on invalid handle (asserted). + * @param hPool The request thread pool handle. + */ +RTDECL(uint32_t) RTReqPoolRetain(RTREQPOOL hPool); + +/** + * Releases a reference to the request thread pool. + * + * When the reference count reaches zero, the request will be pooled for reuse. + * + * @returns The new reference count, UINT32_MAX on invalid handle (asserted). + * @param hPool The request thread pool handle. + */ +RTDECL(uint32_t) RTReqPoolRelease(RTREQPOOL hPool); + +/** + * Request thread pool configuration variable. + */ +typedef enum RTREQPOOLCFGVAR +{ + /** Invalid zero value. */ + RTREQPOOLCFGVAR_INVALID = 0, + /** The desired RTTHREADTYPE of the worker threads. */ + RTREQPOOLCFGVAR_THREAD_TYPE, + /** The RTTHREADFLAGS mask for the worker threads (not waitable). */ + RTREQPOOLCFGVAR_THREAD_FLAGS, + /** The minimum number of threads to keep handy once spawned. */ + RTREQPOOLCFGVAR_MIN_THREADS, + /** The maximum number of thread to start. */ + RTREQPOOLCFGVAR_MAX_THREADS, + /** The minimum number of milliseconds a worker thread needs to be idle + * before we consider shutting it down. The other shutdown criteria + * being set by RTREQPOOLCFGVAR_MIN_THREADS. The value + * RT_INDEFINITE_WAIT can be used to disable shutting down idle threads. */ + RTREQPOOLCFGVAR_MS_MIN_IDLE, + /** The sleep period, in milliseoncds, to employ when idling. The value + * RT_INDEFINITE_WAIT can be used to disable shutting down idle threads. */ + RTREQPOOLCFGVAR_MS_IDLE_SLEEP, + /** The number of threads at which to start pushing back. The value + * UINT64_MAX is an alias for the current upper thread count limit, i.e. + * disabling push back. The value 0 (zero) is an alias for the current + * lower thread count, a good value to start pushing back at. The value + * must otherwise be within */ + RTREQPOOLCFGVAR_PUSH_BACK_THRESHOLD, + /** The minimum push back time in milliseconds. */ + RTREQPOOLCFGVAR_PUSH_BACK_MIN_MS, + /** The maximum push back time in milliseconds. */ + RTREQPOOLCFGVAR_PUSH_BACK_MAX_MS, + /** The maximum number of free requests to keep handy for recycling. */ + RTREQPOOLCFGVAR_MAX_FREE_REQUESTS, + /** The end of the range of valid config variables. */ + RTREQPOOLCFGVAR_END, + /** Blow the type up to 32-bits. */ + RTREQPOOLCFGVAR_32BIT_HACK = 0x7fffffff +} RTREQPOOLCFGVAR; + + +/** + * Sets a config variable for a request thread pool. + * + * @returns IPRT status code. + * @param hPool The pool handle. + * @param enmVar The variable to set. + * @param uValue The new value. + */ +RTDECL(int) RTReqPoolSetCfgVar(RTREQPOOL hPool, RTREQPOOLCFGVAR enmVar, uint64_t uValue); + +/** + * Gets a config variable for a request thread pool. + * + * @returns The value, UINT64_MAX on invalid parameters. + * @param hPool The pool handle. + * @param enmVar The variable to query. + */ +RTDECL(uint64_t) RTReqPoolGetCfgVar(RTREQPOOL hPool, RTREQPOOLCFGVAR enmVar); + +/** + * Request thread pool statistics value names. + */ +typedef enum RTREQPOOLSTAT +{ + /** The invalid zero value, as per tradition. */ + RTREQPOOLSTAT_INVALID = 0, + /** The current number of worker threads. */ + RTREQPOOLSTAT_THREADS, + /** The number of threads that have been created. */ + RTREQPOOLSTAT_THREADS_CREATED, + /** The total number of requests that have been processed. */ + RTREQPOOLSTAT_REQUESTS_PROCESSED, + /** The total number of requests that have been submitted. */ + RTREQPOOLSTAT_REQUESTS_SUBMITTED, + /** The total number of requests that have been cancelled. */ + RTREQPOOLSTAT_REQUESTS_CANCELLED, + /** the current number of pending (waiting) requests. */ + RTREQPOOLSTAT_REQUESTS_PENDING, + /** The current number of active (executing) requests. */ + RTREQPOOLSTAT_REQUESTS_ACTIVE, + /** The current number of free (recycled) requests. */ + RTREQPOOLSTAT_REQUESTS_FREE, + /** Total time the requests took to process. */ + RTREQPOOLSTAT_NS_TOTAL_REQ_PROCESSING, + /** Total time the requests had to wait in the queue before being + * scheduled. */ + RTREQPOOLSTAT_NS_TOTAL_REQ_QUEUED, + /** Average time the requests took to process. */ + RTREQPOOLSTAT_NS_AVERAGE_REQ_PROCESSING, + /** Average time the requests had to wait in the queue before being + * scheduled. */ + RTREQPOOLSTAT_NS_AVERAGE_REQ_QUEUED, + /** The end of the valid statistics value names. */ + RTREQPOOLSTAT_END, + /** Blow the type up to 32-bit. */ + RTREQPOOLSTAT_32BIT_HACK = 0x7fffffff +} RTREQPOOLSTAT; + +/** + * Reads a statistics value from the request thread pool. + * + * @returns The value, UINT64_MAX if an invalid parameter was given. + * @param hPool The request thread pool handle. + * @param enmStat The statistics value to get. + */ +RTDECL(uint64_t) RTReqPoolGetStat(RTREQPOOL hPool, RTREQPOOLSTAT enmStat); + +/** + * Allocates a request packet. + * + * This is mostly for internal use, please use the convenience methods. + * + * @returns IPRT status code. + * + * @param hPool The request thread pool handle. + * @param enmType Package type. + * @param phReq Where to store the handle to the new request. + */ +RTDECL(int) RTReqPoolAlloc(RTREQPOOL hPool, RTREQTYPE enmType, PRTREQ *phReq); + +/** + * Calls a function on a worker thread. + * + * @returns IPRT status code. + * @param hPool The request thread pool handle. + * @param cMillies The number of milliseconds to wait for the request + * to be processed. + * @param phReq Where to store the pointer to the request. Optional + * when RTREQFLAGS_NO_WAIT is used. + * This variable will be set to NIL or a valid request + * handle no matter what happens. + * @param fFlags A combination of RTREQFLAGS values. + * @param pfnFunction The function to be called. Must be declared by a + * DECL macro because of calling conventions. + * @param cArgs The number of arguments in the ellipsis. + * @param ... Arguments. + * + * @remarks The function better avoid taking uint64_t and structs as part of the + * arguments (use pointers to these instead). In general anything + * that's larger than an uintptr_t is problematic. + */ +RTDECL(int) RTReqPoolCallEx(RTREQPOOL hPool, RTMSINTERVAL cMillies, PRTREQ *phReq, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, ...); + + +/** + * Calls a function on a worker thread. + * + * @returns IPRT status code. + * @param hPool The request thread pool handle. + * @param cMillies The number of milliseconds to wait for the request + * to be processed. + * @param phReq Where to store the pointer to the request. Optional + * when RTREQFLAGS_NO_WAIT is used. + * This variable will be set to NIL or a valid request + * handle no matter what happens. + * @param fFlags A combination of RTREQFLAGS values. + * @param pfnFunction The function to be called. Must be declared by a + * DECL macro because of calling conventions. + * @param cArgs The number of arguments in the variable argument + * list. + * @param va Arguments. + * @remarks See remarks on RTReqPoolCallEx. + */ +RTDECL(int) RTReqPoolCallExV(RTREQPOOL hPool, RTMSINTERVAL cMillies, PRTREQ *phReq, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, va_list va); + +/** + * Calls a function on a worker thread, wait for it to return. + * + * @returns IPRT status code returned by @a pfnFunction or request pool error. + * @param hPool The request thread pool handle. + * @param pfnFunction The function to be called. Must be declared by a + * DECL macro because of calling conventions. The + * function must return an int value compatible with + * the IPRT status code convention. + * @param cArgs The number of arguments in the elipsis. + * @param ... Arguments. + * @remarks See remarks on RTReqPoolCallEx. + */ +RTDECL(int) RTReqPoolCallWait(RTREQPOOL hPool, PFNRT pfnFunction, unsigned cArgs, ...); + +/** + * Calls a function on a worker thread, don't wait for it to return. + * + * @returns IPRT status code. + * @param hPool The request thread pool handle. + * @param pfnFunction The function to be called. Must be declared by a + * DECL macro because of calling conventions. The + * function should return an int value compatible with + * the IPRT status code convention, thought it's not + * all that important as it's thrown away. + * @param cArgs The number of arguments in the elipsis. + * @param ... Arguments. + * @remarks See remarks on RTReqPoolCallEx. + */ +RTDECL(int) RTReqPoolCallNoWait(RTREQPOOL hPool, PFNRT pfnFunction, unsigned cArgs, ...); + +/** + * Calls a void function on a worker thread. + * + * @returns IPRT status code. + * @param hPool The request thread pool handle. + * @param pfnFunction The function to be called. Must be declared by a + * DECL macro because of calling conventions. The + * function is taken to return void. + * @param cArgs The number of arguments in the elipsis. + * @param ... Arguments. + * @remarks See remarks on RTReqPoolCallEx. + */ +RTDECL(int) RTReqPoolCallVoidWait(RTREQPOOL hPool, PFNRT pfnFunction, unsigned cArgs, ...); + +/** + * Call a void function on a worker thread, don't wait for it to return. + * + * @returns IPRT status code. + * @param hPool The request thread pool handle. + * @param pfnFunction The function to be called. Must be declared by a + * DECL macro because of calling conventions. The + * function is taken to return void. + * @param cArgs The number of arguments in the elipsis. + * @param ... Arguments. + * @remarks See remarks on RTReqPoolCallEx. + */ +RTDECL(int) RTReqPoolCallVoidNoWait(RTREQPOOL hPool, PFNRT pfnFunction, unsigned cArgs, ...); + + +/** + * Retains a reference to a request. + * + * @returns The new reference count, UINT32_MAX on invalid handle (asserted). + * @param hReq The request handle. + */ +RTDECL(uint32_t) RTReqRetain(PRTREQ hReq); + +/** + * Releases a reference to the request. + * + * When the reference count reaches zero, the request will be pooled for reuse. + * + * @returns The new reference count, UINT32_MAX on invalid handle (asserted). + * @param hReq Package to release. + */ +RTDECL(uint32_t) RTReqRelease(PRTREQ hReq); + +/** + * Queues a request. + * + * The request must be allocated using RTReqQueueAlloc() or RTReqPoolAlloc() and + * contain all the required data. + * + * If it's desired to poll on the completion of the request set cMillies + * to 0 and use RTReqWait() to check for completion. In the other case + * use RT_INDEFINITE_WAIT. + * + * @returns IPRT status code. + * Will not return VERR_INTERRUPTED. + * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. + * + * @param pReq The request to queue. + * @param cMillies Number of milliseconds to wait for the request to + * be completed. Use RT_INDEFINITE_WAIT to only + * wait till it's completed. + */ +RTDECL(int) RTReqSubmit(PRTREQ pReq, RTMSINTERVAL cMillies); + +/** + * Cancels a pending request. + * + * @returns IPRT status code. + * @retval VERR_RT_REQUEST_STATE if the request is not cancellable. + * + * @param hReq The request to cancel. + */ +RTDECL(int) RTReqCancel(PRTREQ hReq); + +/** + * Waits for a request to be completed. + * + * @returns IPRT status code. + * Will not return VERR_INTERRUPTED. + * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. + * + * @param pReq The request to wait for. + * @param cMillies Number of milliseconds to wait. + * Use RT_INDEFINITE_WAIT to only wait till it's completed. + */ +RTDECL(int) RTReqWait(PRTREQ pReq, RTMSINTERVAL cMillies); + +/** + * Gets the status of the request. + * + * @returns IPRT status code. + * + * @param pReq The request to get the status for. + */ +RTDECL(int) RTReqGetStatus(PRTREQ pReq); + +#endif /* IN_RING3 */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_req_h */ + diff --git a/include/iprt/runtime-loader.h b/include/iprt/runtime-loader.h new file mode 100644 index 00000000..3892ffcf --- /dev/null +++ b/include/iprt/runtime-loader.h @@ -0,0 +1,189 @@ +/** @file + * IPRT - Runtime Loader Generation. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#include <iprt/types.h> +#ifdef RT_RUNTIME_LOADER_GENERATE_BODY_STUBS +# include <iprt/ldr.h> +# include <iprt/log.h> +# include <iprt/once.h> +#endif + +/** @defgroup grp_rt_runtime_loader Runtime Loader Generation + * @ingroup grp_rt + * + * How to use this loader generator + * + * This loader generator can be used to generate stub code for loading a shared + * library and its functions at runtime, or for generating a header file with + * the declaration of the loader function and optionally declarations for the + * functions loaded. It should be included in a header file or a C source + * file, after defining certain macros which it makes use of. + * + * To generate the C source code for function proxy stubs and the library + * loader function, you should define the following macros in your source file + * before including this header: + * + * RT_RUNTIME_LOADER_LIB_NAME - the file name of the library to load + * RT_RUNTIME_LOADER_FUNCTION - the name of the loader function + * RT_RUNTIME_LOADER_INSERT_SYMBOLS - a macro containing the names of the + * functions to be loaded, defined in the + * following pattern: + * @code + * #define RT_RUNTIME_LOADER_INSERT_SYMBOLS \ + * RT_PROXY_STUB(func_name, ret_type, (long_param_list), (short_param_list)) \ + * RT_PROXY_STUB(func_name2, ret_type2, (long_param_list2), (short_param_list2)) \ + * ... + * @endcode + * + * where long_param_list is a parameter list for declaring the function of the + * form (type1 arg1, type2 arg2, ...) and short_param_list for calling it, of + * the form (arg1, arg2, ...). + * + * To generate the header file, you should define RT_RUNTIME_LOADER_FUNCTION + * and if you wish to generate declarations for the functions you should + * additionally define RT_RUNTIME_LOADER_INSERT_SYMBOLS as above and + * RT_RUNTIME_LOADER_GENERATE_DECLS (without a value) before including this + * file. + * + * @{ + */ +/** @todo this is far too complicated. A script for generating the files would + * probably be preferable. + * + * bird> An alternative is to generate assembly jump wrappers, this only + * requires the symbol names and prefix. I've done this ages ago when we forked + * the EMX/GCC toolchain on OS/2... It's a wee bit more annoying in x86 PIC/PIE + * mode, but nothing that cannot be dealt with. + */ +/** @todo r=bird: The use of RTR3DECL here is an unresolved issue. */ +/** @todo r=bird: The lack of RT_C_DECLS_BEGIN/END is an unresolved issue. Here + * we'll get into trouble if we use the same symbol names as the + * original! */ +/** @todo r=bird: The prefix usage here is very confused: RT_RUNTIME_LOADER_XXX, + * RT_PROXY_STUB, etc. */ + +#ifdef RT_RUNTIME_LOADER_GENERATE_BODY_STUBS + +/* The following are the symbols which we need from the library. */ +# define RT_PROXY_STUB(function, rettype, signature, shortsig) \ + void (*function ## _fn)(void); \ + RTR3DECL(rettype) function signature \ + { return ( (rettype (*) signature) function ## _fn ) shortsig; } + +RT_RUNTIME_LOADER_INSERT_SYMBOLS + +# undef RT_PROXY_STUB + +/* Now comes a table of functions to be loaded from the library. */ +typedef struct +{ + const char *pszName; + void (**ppfn)(void); +} RTLDRSHAREDFUNC; + +# define RT_PROXY_STUB(s, dummy1, dummy2, dummy3 ) { #s , & s ## _fn } , +static RTLDRSHAREDFUNC g_aSharedFuncs[] = +{ + RT_RUNTIME_LOADER_INSERT_SYMBOLS + { NULL, NULL } +}; +# undef RT_PROXY_STUB + +/** + * The function which does the actual work for RT_RUNTIME_LOADER_FUNCTION, + * serialised for thread safety. + */ +static DECLCALLBACK(int) rtldrLoadOnce(void *) +{ + RTLDRMOD hLib; + int rc; + + LogFlowFunc(("\n")); + rc = RTLdrLoadEx(RT_RUNTIME_LOADER_LIB_NAME, &hLib, RTLDRLOAD_FLAGS_LOCAL | RTLDRLOAD_FLAGS_NO_UNLOAD, NULL); + for (unsigned i = 0; RT_SUCCESS(rc) && g_aSharedFuncs[i].pszName != NULL; ++i) + rc = RTLdrGetSymbol(hLib, g_aSharedFuncs[i].pszName, (void **)g_aSharedFuncs[i].ppfn); + LogFlowFunc(("rc = %Rrc\n", rc)); + + return rc; +} + +/** + * Load the shared library RT_RUNTIME_LOADER_LIB_NAME and resolve the symbols + * pointed to by RT_RUNTIME_LOADER_INSERT_SYMBOLS. + * + * May safely be called from multiple threads and will not return until the + * library is loaded or has failed to load. + * + * @returns IPRT status code. + */ +RTR3DECL(int) RT_RUNTIME_LOADER_FUNCTION(void) +{ + static RTONCE s_Once = RTONCE_INITIALIZER; + int rc; + + LogFlowFunc(("\n")); + rc = RTOnce(&s_Once, rtldrLoadOnce, NULL); + LogFlowFunc(("rc = %Rrc\n", rc)); + + return rc; +} + +#elif defined(RT_RUNTIME_LOADER_GENERATE_HEADER) +# ifdef RT_RUNTIME_LOADER_GENERATE_DECLS +/* Declarations of the functions that we need from + * RT_RUNTIME_LOADER_LIB_NAME */ +# define RT_PROXY_STUB(function, rettype, signature, shortsig) \ + RTR3DECL(rettype) function signature ; + +RT_RUNTIME_LOADER_INSERT_SYMBOLS + +# undef RT_PROXY_STUB +# endif /* RT_RUNTIME_LOADER_GENERATE_DECLS */ + +/** + * Try to dynamically load the library. This function should be called before + * attempting to use any of the library functions. It is safe to call this + * function multiple times. + * + * @returns iprt status code + */ +RTR3DECL(int) RT_RUNTIME_LOADER_FUNCTION(void); + +#else +# error "One of RT_RUNTIME_LOADER_GENERATE_HEADER or RT_RUNTIME_LOADER_GENERATE_BODY_STUBS must be defined when including this file" +#endif + +/** @} */ + diff --git a/include/iprt/runtime.h b/include/iprt/runtime.h new file mode 100644 index 00000000..5d2ddc5d --- /dev/null +++ b/include/iprt/runtime.h @@ -0,0 +1,99 @@ +/** @file + * IPRT - Include Everything. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_runtime_h +#define IPRT_INCLUDED_runtime_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/param.h> +#include <iprt/initterm.h> + +#if !defined(IN_RC) && !defined(IN_RING0_AGNOSTIC) +# include <iprt/alloca.h> +#endif +#include <iprt/asm.h> +#include <iprt/assert.h> +#include <iprt/avl.h> +#include <iprt/crc.h> +#include <iprt/critsect.h> +#include <iprt/dir.h> +#include <iprt/err.h> +#ifndef IN_RC +# include <iprt/file.h> +# include <iprt/fs.h> +#endif +#include <iprt/getopt.h> +#include <iprt/ldr.h> +#include <iprt/log.h> +#include <iprt/md5.h> +#ifndef IN_RC +# include <iprt/mem.h> +# include <iprt/mp.h> +#endif +#include <iprt/path.h> +#include <iprt/semaphore.h> +#include <iprt/spinlock.h> +#include <iprt/stdarg.h> +#include <iprt/string.h> +#include <iprt/system.h> +#include <iprt/table.h> +#ifndef IN_RC +# include <iprt/thread.h> +#endif +#include <iprt/time.h> +#include <iprt/timer.h> +#include <iprt/uni.h> +#include <iprt/uuid.h> +#include <iprt/zip.h> + +#ifdef IN_RING3 +# include <iprt/stream.h> +# include <iprt/tcp.h> +# include <iprt/ctype.h> +# include <iprt/alloca.h> /** @todo iprt/alloca.h should be made available in R0 and GC too! */ +# include <iprt/process.h> /** @todo iprt/process.h should be made available in R0 too (partly). */ +#endif + +#ifdef IN_RING0 +# include <iprt/memobj.h> +#endif + + +#endif /* !IPRT_INCLUDED_runtime_h */ + diff --git a/include/iprt/s3.h b/include/iprt/s3.h new file mode 100644 index 00000000..93c33454 --- /dev/null +++ b/include/iprt/s3.h @@ -0,0 +1,283 @@ +/* $Id: s3.h $ */ +/** @file + * IPRT - Simple Storage Service (S3) Communication API. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_s3_h +#define IPRT_INCLUDED_s3_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_s3 RTS3 - Simple Storage Service (S3) Communication API + * @ingroup grp_rt + * @{ + */ + +/** @todo the following three definitions may move the iprt/types.h later. */ +/** RTS3 interface handle. */ +typedef R3PTRTYPE(struct RTS3INTERNAL *) RTS3; +/** Pointer to a RTS3 interface handle. */ +typedef RTS3 *PRTS3; +/** Nil RTS3 interface handle. */ +#define NIL_RTS3 ((RTS3)0) + + +/** + * S3 progress callback. + * + * @returns Reserved, must be 0. + * + * @param uPercent The process completion percentage. + * @param pvUser The user parameter given to RTS3SetProgressCallback. + */ +typedef DECLCALLBACKTYPE(int, FNRTS3PROGRESS,(unsigned uPercent, void *pvUser)); +/** Pointer to a S3 progress callback. */ +typedef FNRTS3PROGRESS *PFNRTS3PROGRESS; + + +/** Pointer to an S3 bucket entry. */ +typedef struct RTS3BUCKETENTRY *PRTS3BUCKETENTRY; +/** Pointer to a const S3 bucket entry. */ +typedef struct RTS3BUCKETENTRY const *PCRTS3BUCKETENTRY; +/** + * RTS3 bucket entry. + * + * Represent a bucket of the S3 storage server. Bucket entries are chained as a + * doubly linked list using the pPrev & pNext member. + * + * @todo Consider making the entire list const unless there are plans for + * more APIs using this structure which requires the caller to create + * or modify it. + */ +typedef struct RTS3BUCKETENTRY +{ + /** The previous element. */ + PRTS3BUCKETENTRY pPrev; + /** The next element. */ + PRTS3BUCKETENTRY pNext; + + /** The name of the bucket. */ + char const *pszName; + /** The creation date of the bucket as string. */ + char const *pszCreationDate; +} RTS3BUCKETENTRY; + + +/** Pointer to an S3 key entry. */ +typedef struct RTS3KEYENTRY *PRTS3KEYENTRY; +/** Pointer to a const S3 key entry. */ +typedef struct RTS3KEYENTRY const *PCRTS3KEYENTRY; +/** + * RTS3 key entry. + * + * Represent a key of the S3 storage server. Key entries are chained as a doubly + * linked list using the pPrev & pNext member. + * + * @todo Consider making the entire list const unless there are plans for + * more APIs using this structure which requires the caller to create + * or modify it. + */ +typedef struct RTS3KEYENTRY +{ + /** The previous element. */ + PRTS3KEYENTRY pPrev; + /** The next element. */ + PRTS3KEYENTRY pNext; + + /** The name of the key. */ + char const *pszName; + /** The date this key was last modified as string. */ + char const *pszLastModified; + /** The size of the file behind this key in bytes. */ + uint64_t cbFile; +} RTS3KEYENTRY; + + +/** + * Creates a RTS3 interface handle. + * + * @returns iprt status code. + * + * @param phS3 Where to store the RTS3 handle. + * @param pszAccessKey The access key for the S3 storage server. + * @param pszSecretKey The secret access key for the S3 storage server. + * @param pszBaseUrl The base URL of the S3 storage server. + * @param pszUserAgent An optional user agent string used in the HTTP + * communication. + */ +RTR3DECL(int) RTS3Create(PRTS3 phS3, const char *pszAccessKey, const char *pszSecretKey, const char *pszBaseUrl, const char *pszUserAgent); + +/** + * Destroys a RTS3 interface handle. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + */ +RTR3DECL(void) RTS3Destroy(RTS3 hS3); + +/** + * Sets an optional progress callback. + * + * This callback function will be called when the completion percentage of an S3 + * operation changes. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + * @param pfnProgressCB The pointer to the progress function. + * @param pvUser The pvUser arg of FNRTS3PROGRESS. + */ +RTR3DECL(void) RTS3SetProgressCallback(RTS3 hS3, PFNRTS3PROGRESS pfnProgressCB, void *pvUser); + +/** + * Gets a list of all available buckets on the S3 storage server. + * + * You have to delete ppBuckets after usage with RTS3BucketsDestroy. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + * @param ppBuckets Where to store the pointer to the head of the + * returned bucket list. Consider the entire list + * read-only. + */ +RTR3DECL(int) RTS3GetBuckets(RTS3 hS3, PCRTS3BUCKETENTRY *ppBuckets); + +/** + * Destroys the bucket list returned by RTS3GetBuckets. + * + * @returns iprt status code. + * + * @param pBuckets Pointer to the first bucket entry. + */ +RTR3DECL(int) RTS3BucketsDestroy(PCRTS3BUCKETENTRY pBuckets); + +/** + * Creates a new bucket on the S3 storage server. + * + * This name have to be unique over all accounts on the S3 storage server. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + * @param pszBucketName Name of the new bucket. + */ +RTR3DECL(int) RTS3CreateBucket(RTS3 hS3, const char *pszBucketName); + +/** + * Deletes a bucket on the S3 storage server. + * + * The bucket must be empty. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + * @param pszBucketName Name of the bucket to delete. + */ +RTR3DECL(int) RTS3DeleteBucket(RTS3 hS3, const char *pszBucketName); + +/** + * Gets a list of all available keys in a bucket on the S3 storage server. + * + * You have to delete ppKeys after usage with RTS3KeysDestroy. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + * @param pszBucketName Name of the bucket to delete. + * @param ppKeys Where to store the pointer to the head of the + * returned key list. Consider the entire list + * read-only. + */ +RTR3DECL(int) RTS3GetBucketKeys(RTS3 hS3, const char *pszBucketName, PCRTS3KEYENTRY *ppKeys); + +/** + * Delete the key list returned by RTS3GetBucketKeys. + * + * @returns iprt status code. + * + * @param pKeys Pointer to the first key entry. + */ +RTR3DECL(int) RTS3KeysDestroy(PCRTS3KEYENTRY pKeys); + +/** + * Deletes a key in a bucket on the S3 storage server. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + * @param pszBucketName Name of the bucket contains pszKeyName. + * @param pszKeyName Name of the key to delete. + */ +RTR3DECL(int) RTS3DeleteKey(RTS3 hS3, const char *pszBucketName, const char *pszKeyName); + +/** + * Downloads a key from a bucket into a file. + * + * The file must not exists. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + * @param pszBucketName Name of the bucket that contains pszKeyName. + * @param pszKeyName Name of the key to download. + * @param pszFilename Name of the file to store the downloaded key as. + */ +RTR3DECL(int) RTS3GetKey(RTS3 hS3, const char *pszBucketName, const char *pszKeyName, const char *pszFilename); + +/** + * Uploads the content of a file into a key in the specified bucked. + * + * @returns iprt status code. + * + * @param hS3 Handle to the RTS3 interface. + * @param pszBucketName Name of the bucket where the new key should be + * created. + * @param pszKeyName Name of the new key. + * @param pszFilename Name of the file to upload the content of. + */ +RTR3DECL(int) RTS3PutKey(RTS3 hS3, const char *pszBucketName, const char *pszKeyName, const char *pszFilename); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_s3_h */ + diff --git a/include/iprt/sanitized/intrin.h b/include/iprt/sanitized/intrin.h new file mode 100644 index 00000000..39b5ad32 --- /dev/null +++ b/include/iprt/sanitized/intrin.h @@ -0,0 +1,62 @@ +/** @file + * Safe way to include intrin.h from VC++. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_sanitized_intrin_h +#define IPRT_INCLUDED_sanitized_intrin_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* Several incorrect __cplusplus uses. */ +# pragma warning(disable:4255) /* Incorrect __slwpcb prototype. */ +#endif + +/* This is a hack to avoid dragging in malloc.h from UCRT. */ +#if (defined(IPRT_NO_CRT) || defined(RT_OS_AGNOSTIC)) && !defined(_INC_MALLOC) +# define _INC_MALLOC 1 +# include <intrin.h> +# undef _INC_MALLOC +#else +# include <intrin.h> +#endif + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_sanitized_intrin_h */ + diff --git a/include/iprt/sanitized/iterator b/include/iprt/sanitized/iterator new file mode 100644 index 00000000..b3c78e0c --- /dev/null +++ b/include/iprt/sanitized/iterator @@ -0,0 +1,60 @@ +/** @file + * Safe way to include the 'iterator' header from the C++ library. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_sanitized_iterator +#define IPRT_INCLUDED_sanitized_iterator +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +/* + * Unfortunately, the 'iterator' file of VCC141 has trouble with C4091 in -Wall mode (via ios): + * xlocnum(1616): warning C4774: 'sprintf_s' : format string expected in argument 3 is not a string literal + */ +# pragma warning(push) +# if _MSC_VER >= 1910 /*RT_MSC_VER_VC141*/ +# pragma warning(disable:4774) +# endif +#endif + +#include <iterator> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_sanitized_iterator */ + diff --git a/include/iprt/sanitized/sstream b/include/iprt/sanitized/sstream new file mode 100644 index 00000000..46da7af5 --- /dev/null +++ b/include/iprt/sanitized/sstream @@ -0,0 +1,62 @@ +/** @file + * Safe way to include the 'sstream' header from the C++ library. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_sanitized_sstream +#define IPRT_INCLUDED_sanitized_sstream +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +/* + * Unfortunately, the 'sstream' file of VCC141 has trouble with C4091 in -Wall mode + * because it drags in string.h which causes stuff like: + * xlocnum(1616): warning C4774: 'sprintf_s' : format sstream expected in argument 3 is not a sstream literal + * sstream(530): warning C4774: '_scprintf' : format sstream expected in argument 1 is not a sstream literal + */ +# pragma warning(push) +# if _MSC_VER >= 1910 /*RT_MSC_VER_VC141*/ +# pragma warning(disable:4774) +# endif +#endif + +#include <sstream> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_sanitized_sstream */ + diff --git a/include/iprt/sanitized/string b/include/iprt/sanitized/string new file mode 100644 index 00000000..515d2a13 --- /dev/null +++ b/include/iprt/sanitized/string @@ -0,0 +1,61 @@ +/** @file + * Safe way to include the 'string' header from the C++ library. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_sanitized_string +#define IPRT_INCLUDED_sanitized_string +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +/* + * Unfortunately, the 'string' file of VCC141 has trouble with C4091 in -Wall mode: + * string(530): warning C4774: '_scprintf' : format string expected in argument 1 is not a string literal + * xlocnum(1616): warning C4774: 'sprintf_s' : format string expected in argument 3 is not a string literal + */ +# pragma warning(push) +# if _MSC_VER >= 1910 /*RT_MSC_VER_VC141*/ +# pragma warning(disable:4774) +# endif +#endif + +#include <string> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_sanitized_string */ + diff --git a/include/iprt/semaphore.h b/include/iprt/semaphore.h new file mode 100644 index 00000000..6d3e5f6a --- /dev/null +++ b/include/iprt/semaphore.h @@ -0,0 +1,1450 @@ +/** @file + * IPRT - Semaphore. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_semaphore_h +#define IPRT_INCLUDED_semaphore_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3) +# include <iprt/lockvalidator.h> +#endif + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_sems RTSem - Semaphores + * + * This module implements all kinds of event and mutex semaphores; in addition + * to these, IPRT implements "critical sections", which are fast recursive + * mutexes (see @ref grp_rt_critsect ). C++ users may find @ref grp_rt_cpp_lock + * interesting. + * + * @ingroup grp_rt + * @{ + */ + + +/** @name Generic Semaphore Wait Flags. + * + * @remarks Exactly one of RTSEMWAIT_FLAGS_RELATIVE and + * RTSEMWAIT_FLAGS_ABSOLUTE must be set, unless + * RTSEMWAIT_FLAGS_INDEFINITE is used. + * + * Exactly one of RTSEMWAIT_FLAGS_NANOSECS and + * RTSEMWAIT_FLAGS_MILLISECS must be set, unless + * RTSEMWAIT_FLAGS_INDEFINITE is used. + * + * Exactly one of RTSEMWAIT_FLAGS_RESUME and RTSEMWAIT_FLAGS_NORESUME + * must be set. + * + * The interruptible vs resume stuff is ring-0 vs ring-3 semantics. + * + * @{ */ +/** The timeout is relative. */ +#define RTSEMWAIT_FLAGS_RELATIVE RT_BIT_32(0) +/** The timeout is absolute. */ +#define RTSEMWAIT_FLAGS_ABSOLUTE RT_BIT_32(1) +/** The timeout is specified in nanoseconds. */ +#define RTSEMWAIT_FLAGS_NANOSECS RT_BIT_32(2) +/** The timeout is specified in milliseconds. */ +#define RTSEMWAIT_FLAGS_MILLISECS RT_BIT_32(3) +/** Indefinite wait. + * The relative/absolute and nano-/millisecond flags are ignored. */ +#define RTSEMWAIT_FLAGS_INDEFINITE RT_BIT_32(4) +/** Mask covering the time related bits. */ +#define RTSEMWAIT_FLAGS_TIME_MASK UINT32_C(0x0000001f) + +/** Interruptible wait. */ +#define RTSEMWAIT_FLAGS_INTERRUPTIBLE RT_BIT_32(5) +/** No automatic resume, same as interruptible. */ +#define RTSEMWAIT_FLAGS_NORESUME RTSEMWAIT_FLAGS_INTERRUPTIBLE +/** Uninterruptible wait. */ +#define RTSEMWAIT_FLAGS_UNINTERRUPTIBLE RT_BIT_32(6) +/** Resume on interrupt, same as uninterruptible. */ +#define RTSEMWAIT_FLAGS_RESUME RTSEMWAIT_FLAGS_UNINTERRUPTIBLE + +/** Macro for validate the flags. */ +#define RTSEMWAIT_FLAGS_ARE_VALID(fFlags) \ + ( !((fFlags) & UINT32_C(0xffffff80)) \ + && ( ((fFlags) & RTSEMWAIT_FLAGS_INDEFINITE) \ + ? ( (((fFlags) & UINT32_C(0x20))) ^ (((fFlags) >> 1) & UINT32_C(0x20)) ) == UINT32_C(0x20) \ + : ( (((fFlags) & UINT32_C(0x25))) ^ (((fFlags) >> 1) & UINT32_C(0x25)) ) == UINT32_C(0x25) )) +/** @} */ + + + +/** @defgroup grp_rt_sems_event RTSemEvent - Single Release Event Semaphores + * + * Event semaphores can be used for inter-thread communication when one thread + * wants to notify another thread that something happened. A thread can block + * ("wait") on an event semaphore until it is signalled by another thread; see + * RTSemEventCreate, RTSemEventSignal and RTSemEventWait. + * + * @{ */ + +/** + * Create an event semaphore. + * + * @returns iprt status code. + * @param phEventSem Where to store the handle to the newly created + * event semaphore. + */ +RTDECL(int) RTSemEventCreate(PRTSEMEVENT phEventSem); + +/** + * Create an event semaphore. + * + * @returns iprt status code. + * @param phEventSem Where to store the handle to the newly created + * event semaphore. + * @param fFlags Flags, any combination of the + * RTSEMEVENT_FLAGS_XXX \#defines. + * @param hClass The class (no reference consumed). Since we + * don't do order checks on event semaphores, the + * use of the class is limited to controlling the + * timeout threshold for deadlock detection. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKVALCLASS hClass, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(4, 5); + +/** @name RTSemMutexCreateEx flags + * @{ */ +/** Disables lock validation. */ +#define RTSEMEVENT_FLAGS_NO_LOCK_VAL UINT32_C(0x00000001) +/** Bootstrap hack for use with certain memory allocator locks only! */ +#define RTSEMEVENT_FLAGS_BOOTSTRAP_HACK UINT32_C(0x00000004) +/** @} */ + +/** + * Destroy an event semaphore. + * + * @returns iprt status code. + * @param hEventSem Handle of the event semaphore. NIL_RTSEMEVENT + * is quietly ignored (VINF_SUCCESS). + */ +RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem); + +/** + * Signal an event semaphore. + * + * The event semaphore will be signaled and automatically reset after exactly + * one thread have successfully returned from RTSemEventWait() after + * waiting/polling on that semaphore. + * + * @returns iprt status code. + * @param hEventSem The event semaphore to signal. + * + * @remarks ring-0: This works when preemption is disabled. However it is + * system specific whether it works in interrupt context or with + * interrupts disabled. + * + * ring-0/Darwin: This works when interrupts are disabled and thereby + * in interrupt context, except it cannot race semaphore destruction as + * the allocator does not work under these circumstances. + */ +RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem); + +/** + * Whether RTSemEventSignal can be safely called w/o risk of preemption. + * + * Checks whether the caller can safely signal a single release semaphore + * without any risk of getting preempted on locks or similar while doing so. + * This also checks whether the context is suitable in general. + * + * @returns true if safe, false if not. + * @remarks Only ring-0. + */ +RTR0DECL(bool) RTSemEventIsSignalSafe(void); + +/** + * Wait for the event semaphore to be signaled, resume on interruption. + * + * This function will resume if the wait is interrupted by an async system event + * (like a unix signal) or similar. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param hEventSem The event semaphore to wait on. + * @param cMillies Number of milliseconds to wait. + */ +RTDECL(int) RTSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies); + +/** + * Wait for the event semaphore to be signaled, return on interruption. + * + * This function will not resume the wait if interrupted. + * + * @returns iprt status code. + * @param hEventSem The event semaphore to wait on. + * @param cMillies Number of milliseconds to wait. + */ +RTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies); + +/** + * Extended API for waiting on an event semaphore to be signaled. + * + * @returns IPRT status code. + * @param hEventSem The event semaphore to wait on. + * @param fFlags Combination of RTSEMWAIT_FLAGS_XXX. + * @param uTimeout The timeout, ignored if + * RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags. + * Whether this is absolute or relative, + * milliseconds or nanoseconds depends on the @a + * fFlags value. Do not pass RT_INDEFINITE_WAIT + * here, use RTSEMWAIT_FLAGS_INDEFINITE instead. + */ +RTDECL(int) RTSemEventWaitEx(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout); + +/** + * Debug version of RTSemEventWaitEx that tracks the location. + * + * @returns IPRT status code, see RTSemEventWaitEx. + * @param hEventSem The event semaphore to wait on. + * @param fFlags See RTSemEventWaitEx. + * @param uTimeout See RTSemEventWaitEx. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemEventWaitExDebug(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout, + RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Gets the best timeout resolution that RTSemEventWaitEx can do. + * + * @returns The resolution in nanoseconds. + */ +RTDECL(uint32_t) RTSemEventGetResolution(void); + +/** + * Sets the signaller thread to one specific thread. + * + * This is only used for validating usage and deadlock detection. When used + * after calls to RTSemEventAddSignaller, the specified thread will be the only + * signalling thread. + * + * @param hEventSem The event semaphore. + * @param hThread The thread that will signal it. Pass + * NIL_RTTHREAD to indicate that there is no + * special signalling thread. + */ +RTDECL(void) RTSemEventSetSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread); + +/** + * To add more signalling threads. + * + * First call RTSemEventSetSignaller then add further threads with this. + * + * @param hEventSem The event semaphore. + * @param hThread The thread that will signal it. NIL_RTTHREAD is + * not accepted. + */ +RTDECL(void) RTSemEventAddSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread); + +/** + * To remove a signalling thread. + * + * Reverts work done by RTSemEventAddSignaller and RTSemEventSetSignaller. + * + * @param hEventSem The event semaphore. + * @param hThread A previously added thread. + */ +RTDECL(void) RTSemEventRemoveSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread); + +/** @} */ + + +/** @defgroup grp_rt_sems_event_multi RTSemEventMulti - Multiple Release Event Semaphores + * + * A variant of @ref grp_rt_sems_event where all threads will be unblocked when + * signalling the semaphore. + * + * @{ */ + +/** + * Creates a multiple release event semaphore. + * + * @returns iprt status code. + * @param phEventMultiSem Where to store the handle to the newly created + * multiple release event semaphore. + */ +RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem); + +/** + * Creates a multiple release event semaphore. + * + * @returns iprt status code. + * @param phEventMultiSem Where to store the handle to the newly created + * multiple release event semaphore. + * @param fFlags Flags, any combination of the + * RTSEMEVENTMULTI_FLAGS_XXX \#defines. + * @param hClass The class (no reference consumed). Since we + * don't do order checks on event semaphores, the + * use of the class is limited to controlling the + * timeout threshold for deadlock detection. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(4, 5); + +/** @name RTSemMutexCreateEx flags + * @{ */ +/** Disables lock validation. */ +#define RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL UINT32_C(0x00000001) +/** @} */ + +/** + * Destroy an event multi semaphore. + * + * @returns iprt status code. + * @param hEventMultiSem The multiple release event semaphore. NIL is + * quietly ignored (VINF_SUCCESS). + */ +RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem); + +/** + * Signal an event multi semaphore. + * + * @returns iprt status code. + * @param hEventMultiSem The multiple release event semaphore. + * + * @remarks ring-0: This works when preemption is disabled. However it is + * system specific whether it works in interrupt context or with + * interrupts disabled. + * + * ring-0/Darwin: This works when interrupts are disabled and thereby + * in interrupt context, except it cannot race semaphore destruction as + * the allocator does not work under these circumstances. + */ +RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem); + +/** + * Whether RTSemEventMultiSignal can be safely called w/o risk of preemption. + * + * Checks whether the caller can safely signal a multiple release semaphore + * without any risk of getting preempted on locks or similar while doing so. + * This also checks whether the context is suitable in general. + * + * @returns true if safe, false if not. + * @remarks Only ring-0. + */ +RTR0DECL(bool) RTSemEventMultiIsSignalSafe(void); + +/** + * Resets an event multi semaphore to non-signaled state. + * + * @returns iprt status code. + * @param hEventMultiSem The multiple release event semaphore. + */ +RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem); + +/** + * Wait for the event multi semaphore to be signaled, resume on interruption. + * + * This function will resume if the wait is interrupted by an async + * system event (like a unix signal) or similar. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param hEventMultiSem The multiple release event semaphore. + * @param cMillies Number of milliseconds to wait. + */ +RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies); + +/** + * Wait for the event multi semaphore to be signaled, return on interruption. + * + * This function will not resume the wait if interrupted. + * + * @returns iprt status code. + * @param hEventMultiSem The multiple release event semaphore. + * @param cMillies Number of milliseconds to wait. + * @todo Rename to RTSemEventMultiWaitIntr since it is mainly for + * ring-0 consumption. + */ +RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies); + +/** + * Extended API for waiting on an event semaphore to be signaled. + * + * @returns IPRT status code. + * @param hEventMultiSem The multiple release event semaphore to wait + * on. + * @param fFlags Combination of the RTSEMWAIT_FLAGS_XXX. + * @param uTimeout The timeout, ignored if + * RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags. + * Whether this is absolute or relative, + * milliseconds or nanoseconds depends on the @a + * fFlags value. Do not pass RT_INDEFINITE_WAIT + * here, use RTSEMWAIT_FLAGS_INDEFINITE instead. + */ +RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout); + +/** + * Debug version of RTSemEventMultiWaitEx that tracks the location. + + * @returns IPRT status code, see RTSemEventMultiWaitEx. + * @param hEventMultiSem The multiple release event semaphore handle. + * @param fFlags See RTSemEventMultiWaitEx. + * @param uTimeout See RTSemEventMultiWaitEx. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout, + RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Gets the best timeout resolution that RTSemEventMultiWaitEx can do. + * + * @returns The resolution in nanoseconds. + */ +RTDECL(uint32_t) RTSemEventMultiGetResolution(void); + +/** + * Sets the signaller thread to one specific thread. + * + * This is only used for validating usage and deadlock detection. When used + * after calls to RTSemEventAddSignaller, the specified thread will be the only + * signalling thread. + * + * @param hEventMultiSem The multiple release event semaphore. + * @param hThread The thread that will signal it. Pass + * NIL_RTTHREAD to indicate that there is no + * special signalling thread. + */ +RTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread); + +/** + * To add more signalling threads. + * + * First call RTSemEventSetSignaller then add further threads with this. + * + * @param hEventMultiSem The multiple release event semaphore. + * @param hThread The thread that will signal it. NIL_RTTHREAD is + * not accepted. + */ +RTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread); + +/** + * To remove a signalling thread. + * + * Reverts work done by RTSemEventAddSignaller and RTSemEventSetSignaller. + * + * @param hEventMultiSem The multiple release event semaphore. + * @param hThread A previously added thread. + */ +RTDECL(void) RTSemEventMultiRemoveSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread); + +/** @} */ + + +/** @defgroup grp_rt_sems_mutex RTSemMutex - Mutex semaphores. + * + * Mutex semaphores protect a section of code or data to which access must be + * exclusive. Only one thread can hold access to a critical section at one + * time. See RTSemMutexCreate, RTSemMutexRequest and RTSemMutexRelease. + * + * @remarks These are less efficient than "fast mutexes" and "critical + * sections", which IPRT implements as well; see @ref + * grp_rt_sems_fast_mutex and @ref grp_rt_critsect . + * + * @{ */ + +/** + * Create a mutex semaphore. + * + * @returns iprt status code. + * @param phMutexSem Where to store the mutex semaphore handle. + */ +RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMutexSem); + +/** + * Creates a read/write semaphore. + * + * @returns iprt status code. + * @param phMutexSem Where to store the handle to the newly created + * mutex semaphore. + * @param fFlags Flags, any combination of the + * RTSEMMUTEX_FLAGS_XXX \#defines. + * @param hClass The class (no reference consumed). If NIL, no + * lock order validation will be performed on this + * lock. + * @param uSubClass The sub-class. This is used to define lock + * order within a class. RTLOCKVAL_SUB_CLASS_NONE + * is the recommended value here. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTSemMutexCreateEx(PRTSEMMUTEX phMutexSem, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(5, 6); + +/** @name RTSemMutexCreateEx flags + * @{ */ +/** Disables lock validation. */ +#define RTSEMMUTEX_FLAGS_NO_LOCK_VAL UINT32_C(0x00000001) +/** @} */ + + +/** + * Destroy a mutex semaphore. + * + * @returns iprt status code. + * @param hMutexSem The mutex semaphore to destroy. NIL is quietly + * ignored (VINF_SUCCESS). + */ +RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMutexSem); + +/** + * Changes the lock validator sub-class of the mutex semaphore. + * + * It is recommended to try make sure that nobody is using this semaphore while + * changing the value. + * + * @returns The old sub-class. RTLOCKVAL_SUB_CLASS_INVALID is returns if the + * lock validator isn't compiled in or either of the parameters are + * invalid. + * @param hMutexSem The handle to the mutex semaphore. + * @param uSubClass The new sub-class value. + */ +RTDECL(uint32_t) RTSemMutexSetSubClass(RTSEMMUTEX hMutexSem, uint32_t uSubClass); + +/** + * Request ownership of a mutex semaphore, resume on interruption. + * + * This function will resume if the wait is interrupted by an async + * system event (like a unix signal) or similar. + * + * The same thread may request a mutex semaphore multiple times, + * a nested counter is kept to make sure it's released on the right + * RTSemMutexRelease() call. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param hMutexSem The mutex semaphore to request ownership over. + * @param cMillies The number of milliseconds to wait. + */ +RTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies); + +/** + * Request ownership of a mutex semaphore, return on interruption. + * + * This function will not resume the wait if interrupted. + * + * The same thread may request a mutex semaphore multiple times, + * a nested counter is kept to make sure it's released on the right + * RTSemMutexRelease() call. + * + * @returns iprt status code. + * @param hMutexSem The mutex semaphore to request ownership over. + * @param cMillies The number of milliseconds to wait. + */ +RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies); + +/** + * Debug version of RTSemMutexRequest that tracks the location. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param hMutexSem The mutex semaphore to request ownership over. + * @param cMillies The number of milliseconds to wait. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemMutexRequestDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Debug version of RTSemMutexRequestNoResume that tracks the location. + * + * @returns iprt status code. + * @param hMutexSem The mutex semaphore to request ownership over. + * @param cMillies The number of milliseconds to wait. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Request ownership of a mutex semaphore, extended edition. + * + * The same thread may request a mutex semaphore multiple times, + * a nested counter is kept to make sure it's released on the right + * RTSemMutexRelease() call. + * + * @returns iprt status code. + * @param hMutexSem The mutex semaphore to request ownership over. + * @param fFlags Combination of the RTSEMWAIT_FLAGS_XXX. + * @param uTimeout The timeout, ignored if + * RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags. + * Whether this is absolute or relative, + * milliseconds or nanoseconds depends on the @a + * fFlags value. Do not pass RT_INDEFINITE_WAIT + * here, use RTSEMWAIT_FLAGS_INDEFINITE instead. + */ +RTDECL(int) RTSemMutexRequestEx(RTSEMMUTEX hMutexSem, uint32_t fFlags, uint64_t uTimeout); + +/** + * Debug version of RTSemMutexRequestEx that tracks the location. + * + * @returns iprt status code. + * @param hMutexSem The mutex semaphore to request ownership over. + * @param fFlags See RTSemMutexRequestEx. + * @param uTimeout See RTSemMutexRequestEx. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemMutexRequestExDebug(RTSEMMUTEX hMutexSem, uint32_t fFlags, uint64_t uTimeout, + RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Release the ownership of a mutex semaphore. + * + * @returns iprt status code. + * @param hMutexSem The mutex to release the ownership of. It goes + * without saying the the calling thread must own + * it. + */ +RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem); + +/** + * Checks if the mutex semaphore is owned or not. + * + * @returns true if owned, false if not. + * @param hMutexSem The mutex semaphore. + */ +RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem); + +/* Strict build: Remap the two request calls to the debug versions. */ +#if defined(RT_STRICT) && !defined(RTSEMMUTEX_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) +# ifdef IPRT_INCLUDED_asm_h +# define RTSemMutexRequest(hMutexSem, cMillies) RTSemMutexRequestDebug((hMutexSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTSemMutexRequestNoResume(hMutexSem, cMillies) RTSemMutexRequestNoResumeDebug((hMutexSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTSemMutexRequestEx(hMutexSem, fFlags, uTimeout) RTSemMutexRequestExDebug((hMutexSem), (fFlags), (uTimeout), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define RTSemMutexRequest(hMutexSem, cMillies) RTSemMutexRequestDebug((hMutexSem), (cMillies), 0, RT_SRC_POS) +# define RTSemMutexRequestNoResume(hMutexSem, cMillies) RTSemMutexRequestNoResumeDebug((hMutexSem), (cMillies), 0, RT_SRC_POS) +# define RTSemMutexRequestEx(hMutexSem, fFlags, uTimeout) RTSemMutexRequestExDebug((hMutexSem), (fFlags), (uTimeout), 0, RT_SRC_POS) +# endif +#endif + +/* Strict lock order: Automatically classify locks by init location. */ +#if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3) && !defined(RTSEMMUTEX_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) +# define RTSemMutexCreate(phMutexSem) \ + RTSemMutexCreateEx((phMutexSem), 0 /*fFlags*/, \ + RTLockValidatorClassForSrcPos(RT_SRC_POS, NULL), \ + RTLOCKVAL_SUB_CLASS_NONE, NULL) +#endif + +/** @} */ + + +/** @defgroup grp_rt_sems_fast_mutex RTSemFastMutex - Fast Mutex Semaphores + * + * Fast mutexes work like regular mutexes in that they allow only a single + * thread access to a critical piece of code or data. As opposed to mutexes, + * they require no syscall if the fast mutex is not held (like critical + * sections). Unlike critical sections however, they are *not* recursive. + * + * @remarks The fast mutexes has sideeffects on IRQL on Windows hosts. So use + * with care and test on windows with the driver verifier enabled. + * + * @{ */ + +/** + * Create a fast mutex semaphore. + * + * @returns iprt status code. + * @param phFastMtx Where to store the handle to the newly created + * fast mutex semaphore. + * + * @remarks Fast mutex semaphores are not recursive. + */ +RTDECL(int) RTSemFastMutexCreate(PRTSEMFASTMUTEX phFastMtx); + +/** + * Destroy a fast mutex semaphore. + * + * @returns iprt status code. + * @param hFastMtx Handle to the fast mutex semaphore. NIL is + * quietly ignored (VINF_SUCCESS). + */ +RTDECL(int) RTSemFastMutexDestroy(RTSEMFASTMUTEX hFastMtx); + +/** + * Request ownership of a fast mutex semaphore. + * + * @returns iprt status code. + * @param hFastMtx Handle to the fast mutex semaphore. + */ +RTDECL(int) RTSemFastMutexRequest(RTSEMFASTMUTEX hFastMtx); + +/** + * Release the ownership of a fast mutex semaphore. + * + * @returns iprt status code. + * @param hFastMtx Handle to the fast mutex semaphore. It goes + * without saying the the calling thread must own + * it. + */ +RTDECL(int) RTSemFastMutexRelease(RTSEMFASTMUTEX hFastMtx); + +/** @} */ + + +/** @defgroup grp_rt_sems_spin_mutex RTSemSpinMutex - Spinning Mutex Semaphores + * + * A very adaptive variant of mutex semaphore that is tailored for the ring-0 + * logger. + * + * @{ */ + +/** + * Creates a spinning mutex semaphore. + * + * @returns iprt status code. + * @retval VERR_INVALID_PARAMETER on invalid flags. + * @retval VERR_NO_MEMORY if out of memory for the semaphore structure and + * handle. + * + * @param phSpinMtx Where to return the handle to the create semaphore. + * @param fFlags Flags, see RTSEMSPINMUTEX_FLAGS_XXX. + */ +RTDECL(int) RTSemSpinMutexCreate(PRTSEMSPINMUTEX phSpinMtx, uint32_t fFlags); + +/** @name RTSemSpinMutexCreate flags. + * @{ */ +/** Always take the semaphore in a IRQ safe way. + * (In plain words: always disable interrupts.) */ +#define RTSEMSPINMUTEX_FLAGS_IRQ_SAFE RT_BIT_32(0) +/** Mask of valid flags. */ +#define RTSEMSPINMUTEX_FLAGS_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Destroys a spinning mutex semaphore. + * + * @returns iprt status code. + * @retval VERR_INVALID_HANDLE (or crash) if the handle is invalid. (NIL will + * not cause this status.) + * + * @param hSpinMtx The semaphore handle. NIL_RTSEMSPINMUTEX is ignored + * quietly (VINF_SUCCESS). + */ +RTDECL(int) RTSemSpinMutexDestroy(RTSEMSPINMUTEX hSpinMtx); + +/** + * Request the spinning mutex semaphore. + * + * This may block if the context we're called in allows this. If not it will + * spin. If called in an interrupt context, we will only spin if the current + * owner isn't interrupted. Also, on some systems it is not always possible to + * wake up blocking threads in all contexts, so, which will either be indicated + * by returning VERR_SEM_BAD_CONTEXT or by temporarily switching the semaphore + * into pure spinlock state. + * + * Preemption will be disabled upon return. IRQs may also be disabled. + * + * @returns iprt status code. + * @retval VERR_SEM_BAD_CONTEXT if the context it's called in isn't suitable + * for releasing it if someone is sleeping on it. + * @retval VERR_SEM_DESTROYED if destroyed. + * @retval VERR_SEM_NESTED if held by the caller. Asserted. + * @retval VERR_INVALID_HANDLE if the handle is invalid. Asserted + * + * @param hSpinMtx The semaphore handle. + */ +RTDECL(int) RTSemSpinMutexRequest(RTSEMSPINMUTEX hSpinMtx); + +/** + * Like RTSemSpinMutexRequest but it won't block or spin if the semaphore is + * held by someone else. + * + * @returns iprt status code. + * @retval VERR_SEM_BUSY if held by someone else. + * @retval VERR_SEM_DESTROYED if destroyed. + * @retval VERR_SEM_NESTED if held by the caller. Asserted. + * @retval VERR_INVALID_HANDLE if the handle is invalid. Asserted + * + * @param hSpinMtx The semaphore handle. + */ +RTDECL(int) RTSemSpinMutexTryRequest(RTSEMSPINMUTEX hSpinMtx); + +/** + * Releases the semaphore previously acquired by RTSemSpinMutexRequest or + * RTSemSpinMutexTryRequest. + * + * @returns iprt status code. + * @retval VERR_SEM_DESTROYED if destroyed. + * @retval VERR_NOT_OWNER if not owner. Asserted. + * @retval VERR_INVALID_HANDLE if the handle is invalid. Asserted. + * + * @param hSpinMtx The semaphore handle. + */ +RTDECL(int) RTSemSpinMutexRelease(RTSEMSPINMUTEX hSpinMtx); + +/** @} */ + + +/** @defgroup grp_rt_sem_rw RTSemRW - Read / Write Semaphores + * + * Read/write semaphores are a fancier version of mutexes in that they grant + * read access to the protected data to several threads at the same time but + * allow only one writer at a time. This can make code scale better at the + * expense of slightly more overhead in mutex management. + * + * @{ */ + +/** + * Creates a read/write semaphore. + * + * @returns iprt status code. + * @param phRWSem Where to store the handle to the newly created + * RW semaphore. + */ +RTDECL(int) RTSemRWCreate(PRTSEMRW phRWSem); + +/** + * Creates a read/write semaphore. + * + * @returns iprt status code. + * @param phRWSem Where to store the handle to the newly created + * RW semaphore. + * @param fFlags Flags, any combination of the RTSEMRW_FLAGS_XXX + * \#defines. + * @param hClass The class (no reference consumed). If NIL, no + * lock order validation will be performed on this + * lock. + * @param uSubClass The sub-class. This is used to define lock + * order within a class. RTLOCKVAL_SUB_CLASS_NONE + * is the recommended value here. + * @param pszNameFmt Name format string for the lock validator, + * optional (NULL). Max length is 32 bytes. + * @param ... Format string arguments. + */ +RTDECL(int) RTSemRWCreateEx(PRTSEMRW phRWSem, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(5, 6); + +/** @name RTSemRWCreateEx flags + * @{ */ +/** Disables lock validation. */ +#define RTSEMRW_FLAGS_NO_LOCK_VAL UINT32_C(0x00000001) +/** @} */ + +/** + * Destroys a read/write semaphore. + * + * @returns iprt status code. + * @param hRWSem Handle to the read/write semaphore. NIL is + * quietly ignored (VINF_SUCCESS). + */ +RTDECL(int) RTSemRWDestroy(RTSEMRW hRWSem); + +/** + * Changes the lock validator sub-class of the read/write semaphore. + * + * It is recommended to try make sure that nobody is using this semaphore while + * changing the value. + * + * @returns The old sub-class. RTLOCKVAL_SUB_CLASS_INVALID is returns if the + * lock validator isn't compiled in or either of the parameters are + * invalid. + * @param hRWSem Handle to the read/write semaphore. + * @param uSubClass The new sub-class value. + */ +RTDECL(uint32_t) RTSemRWSetSubClass(RTSEMRW hRWSem, uint32_t uSubClass); + +/** + * Request read access to a read/write semaphore, resume on interruption + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INTERRUPT if the wait was interrupted. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param cMillies The number of milliseconds to wait. + */ +RTDECL(int) RTSemRWRequestRead(RTSEMRW hRWSem, RTMSINTERVAL cMillies); + +/** + * Request read access to a read/write semaphore, return on interruption + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INTERRUPT if the wait was interrupted. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param cMillies The number of milliseconds to wait. + */ +RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW hRWSem, RTMSINTERVAL cMillies); + +/** + * Debug version of RTSemRWRequestRead that tracks the location. + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INTERRUPT if the wait was interrupted. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param cMillies The number of milliseconds to wait. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemRWRequestReadDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Debug version of RTSemRWRequestWriteNoResume that tracks the location. + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INTERRUPT if the wait was interrupted. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param cMillies The number of milliseconds to wait. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemRWRequestReadNoResumeDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Request read access to a read/write semaphore, extended edition. + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INTERRUPT if the wait was interrupted. + * @retval VERR_TIMEOUT if the wait timed out. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param fFlags Combination of the RTSEMWAIT_FLAGS_XXX. + * @param uTimeout The timeout, ignored if + * RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags. + * Whether this is absolute or relative, + * milliseconds or nanoseconds depends on the @a + * fFlags value. Do not pass RT_INDEFINITE_WAIT + * here, use RTSEMWAIT_FLAGS_INDEFINITE instead. + */ +RTDECL(int) RTSemRWRequestReadEx(RTSEMRW hRWSem, uint32_t fFlags, uint64_t uTimeout); + + +/** + * Debug version of RTSemRWRequestReadEx that tracks the location. + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INTERRUPT if the wait was interrupted. + * @retval VERR_TIMEOUT if the wait timed out. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param fFlags See RTSemRWRequestReadEx. + * @param uTimeout See RTSemRWRequestReadEx. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemRWRequestReadExDebug(RTSEMRW hRWSem, uint32_t fFlags, uint64_t uTimeout, + RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Release read access to a read/write semaphore. + * + * @returns iprt status code. + * @param hRWSem Handle to the read/write semaphore. It goes + * without saying that caller must own read + * privileges to the semaphore. + */ +RTDECL(int) RTSemRWReleaseRead(RTSEMRW hRWSem); + +/** + * Request write access to a read/write semaphore, resume on interruption. + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_DEADLOCK if the caller owned the read lock. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param cMillies The number of milliseconds to wait. + */ +RTDECL(int) RTSemRWRequestWrite(RTSEMRW hRWSem, RTMSINTERVAL cMillies); + +/** + * Request write access to a read/write semaphore, return on interruption. + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INTERRUPT if the wait was interrupted. + * @retval VERR_DEADLOCK if the caller owned the read lock. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param cMillies The number of milliseconds to wait. + */ +RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW hRWSem, RTMSINTERVAL cMillies); + +/** + * Debug version of RTSemRWRequestWrite that tracks the location. + * + * @returns IPRT status code, see RTSemRWRequestWrite. + * @param hRWSem Handle to the read/write semaphore. + * @param cMillies The number of milliseconds to wait. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemRWRequestWriteDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Debug version of RTSemRWRequestWriteNoResume that tracks the location. + * + * @returns IPRT status code, see RTSemRWRequestWriteNoResume. + * @param hRWSem Handle to the read/write semaphore. + * @param cMillies The number of milliseconds to wait. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemRWRequestWriteNoResumeDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Request write access to a read/write semaphore, extended edition. + * + * @returns iprt status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INTERRUPTED if the wait was interrupted. + * @retval VERR_TIMEOUT if the wait timed out. + * @retval VERR_DEADLOCK if the caller owned the read lock. Do not depend on + * this as it is implementation specific. + * @retval VERR_INVALID_HANDLE if hRWSem is invalid. + * + * @param hRWSem Handle to the read/write semaphore. + * @param fFlags Combination of the RTSEMWAIT_FLAGS_XXX. + * @param uTimeout The timeout, ignored if + * RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags. + * Whether this is absolute or relative, + * milliseconds or nanoseconds depends on the @a + * fFlags value. Do not pass RT_INDEFINITE_WAIT + * here, use RTSEMWAIT_FLAGS_INDEFINITE instead. + */ +RTDECL(int) RTSemRWRequestWriteEx(RTSEMRW hRWSem, uint32_t fFlags, uint64_t uTimeout); + +/** + * Debug version of RTSemRWRequestWriteEx that tracks the location. + * + * @returns IPRT status code, see RTSemRWRequestWriteEx. + * @param hRWSem Handle to the read/write semaphore. + * @param fFlags See RTSemRWRequestWriteEx. + * @param uTimeout See RTSemRWRequestWriteEx. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where call is being made + * from. Use RT_SRC_POS when possible. Optional. + */ +RTDECL(int) RTSemRWRequestWriteExDebug(RTSEMRW hRWSem, uint32_t fFlags, uint64_t uTimeout, + RTHCUINTPTR uId, RT_SRC_POS_DECL); + +/** + * Release write access to a read/write semaphore. + * + * @returns iprt status code. + * @param hRWSem Handle to the read/write semaphore. Goes + * without saying that caller must have write + * access to the semaphore. + */ +RTDECL(int) RTSemRWReleaseWrite(RTSEMRW hRWSem); + +/** + * Checks if the caller is the exclusive semaphore owner. + * + * @returns true / false accoringly. + * @param hRWSem Handle to the read/write semaphore. + */ +RTDECL(bool) RTSemRWIsWriteOwner(RTSEMRW hRWSem); + +/** + * Checks if the caller is one of the read owners of the semaphore. + * + * @note !CAUTION! This API doesn't work reliably if lock validation isn't + * enabled. Meaning, the answer is not trustworhty unless + * RT_LOCK_STRICT or RTSEMRW_STRICT was defined at build time. Also, + * make sure you do not use RTSEMRW_FLAGS_NO_LOCK_VAL when creating + * the semaphore. And finally, if you used a locking class, don't + * disable deadlock detection by setting cMsMinDeadlock to + * RT_INDEFINITE_WAIT. + * + * In short, only use this for assertions. + * + * @returns true if reader, false if not. + * @param hRWSem Handle to the read/write semaphore. + * @param fWannaHear What you'd like to hear when lock validation is + * not available. (For avoiding asserting all over + * the place.) + */ +RTDECL(bool) RTSemRWIsReadOwner(RTSEMRW hRWSem, bool fWannaHear); + +/** + * Gets the write recursion count. + * + * @returns The write recursion count (0 if bad semaphore handle). + * @param hRWSem Handle to the read/write semaphore. + */ +RTDECL(uint32_t) RTSemRWGetWriteRecursion(RTSEMRW hRWSem); + +/** + * Gets the read recursion count of the current writer. + * + * @returns The read recursion count (0 if bad semaphore handle). + * @param hRWSem Handle to the read/write semaphore. + */ +RTDECL(uint32_t) RTSemRWGetWriterReadRecursion(RTSEMRW hRWSem); + +/** + * Gets the current number of reads. + * + * This includes all read recursions, so it might be higher than the number of + * read owners. It does not include reads done by the current writer. + * + * @returns The read count (0 if bad semaphore handle). + * @param hRWSem Handle to the read/write semaphore. + */ +RTDECL(uint32_t) RTSemRWGetReadCount(RTSEMRW hRWSem); + +/* Strict build: Remap the four request calls to the debug versions. */ +#if defined(RT_STRICT) && !defined(RTSEMRW_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) +# ifdef IPRT_INCLUDED_asm_h +# define RTSemRWRequestRead(hRWSem, cMillies) RTSemRWRequestReadDebug((hRWSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTSemRWRequestReadNoResume(hRWSem, cMillies) RTSemRWRequestReadNoResumeDebug((hRWSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTSemRWRequestWrite(hRWSem, cMillies) RTSemRWRequestWriteDebug((hRWSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTSemRWRequestWriteNoResume(hRWSem, cMillies) RTSemRWRequestWriteNoResumeDebug((hRWSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define RTSemRWRequestWriteEx(hRWSem, fFlags, uTimeout) RTSemRWRequestWriteExDebug((hRWSem), (fFlags), (uTimeout), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define RTSemRWRequestRead(hRWSem, cMillies) RTSemRWRequestReadDebug((hRWSem), (cMillies), 0, RT_SRC_POS) +# define RTSemRWRequestReadNoResume(hRWSem, cMillies) RTSemRWRequestReadNoResumeDebug((hRWSem), (cMillies), 0, RT_SRC_POS) +# define RTSemRWRequestWrite(hRWSem, cMillies) RTSemRWRequestWriteDebug((hRWSem), (cMillies), 0, RT_SRC_POS) +# define RTSemRWRequestWriteNoResume(hRWSem, cMillies) RTSemRWRequestWriteNoResumeDebug((hRWSem), (cMillies), 0, RT_SRC_POS) +# define RTSemRWRequestWriteEx(hRWSem, fFlags, uTimeout) RTSemRWRequestWriteExDebug((hRWSem), (fFlags), (uTimeout), 0, RT_SRC_POS) +# endif +#endif + +/* Strict lock order: Automatically classify locks by init location. */ +#if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3) && !defined(RTSEMRW_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) +# define RTSemRWCreate(phSemRW) \ + RTSemRWCreateEx((phSemRW), 0 /*fFlags*/, \ + RTLockValidatorClassForSrcPos(RT_SRC_POS, NULL), \ + RTLOCKVAL_SUB_CLASS_NONE, NULL) +#endif + +/** @} */ + + +/** @defgroup grp_rt_sems_pingpong RTSemPingPong - Ping-Pong Construct + * + * Serialization of a two way communication. + * + * @{ */ + +/** + * Ping-pong speaker + */ +typedef enum RTPINGPONGSPEAKER +{ + /** Not initialized. */ + RTPINGPONGSPEAKER_UNINITIALIZE = 0, + /** Ping is speaking, Pong is waiting. */ + RTPINGPONGSPEAKER_PING, + /** Pong is signaled, Ping is waiting. */ + RTPINGPONGSPEAKER_PONG_SIGNALED, + /** Pong is speaking, Ping is waiting. */ + RTPINGPONGSPEAKER_PONG, + /** Ping is signaled, Pong is waiting. */ + RTPINGPONGSPEAKER_PING_SIGNALED, + /** Hack to ensure that it's at least 32-bits wide. */ + RTPINGPONGSPEAKER_HACK = 0x7fffffff +} RTPINGPONGSPEAKER; + +/** + * Ping-Pong construct. + * + * Two threads, one saying Ping and the other saying Pong. The construct + * makes sure they don't speak out of turn and that they can wait and poll + * on the conversation. + */ +typedef struct RTPINGPONG +{ + /** The semaphore the Ping thread waits on. */ + RTSEMEVENT Ping; + /** The semaphore the Pong thread waits on. */ + RTSEMEVENT Pong; + /** The current speaker. */ + volatile RTPINGPONGSPEAKER enmSpeaker; +#if HC_ARCH_BITS == 64 + /** Padding the structure to become a multiple of sizeof(RTHCPTR). */ + uint32_t u32Padding; +#endif +} RTPINGPONG; +/** Pointer to Ping-Pong construct. */ +typedef RTPINGPONG *PRTPINGPONG; + +/** + * Init a Ping-Pong construct. + * + * @returns iprt status code. + * @param pPP Pointer to the ping-pong structure which needs initialization. + */ +RTDECL(int) RTSemPingPongInit(PRTPINGPONG pPP); + +/** + * Deletes a Ping-Pong construct. + * + * @returns iprt status code. + * @param pPP Pointer to the ping-pong structure which is to be destroyed. + * (I.e. put into uninitialized state.) + */ +RTDECL(int) RTSemPingPongDelete(PRTPINGPONG pPP); + +/** + * Signals the pong thread in a ping-pong construct. (I.e. sends ping.) + * This is called by the ping thread. + * + * @returns iprt status code. + * @param pPP Pointer to the ping-pong structure to ping. + */ +RTDECL(int) RTSemPing(PRTPINGPONG pPP); + +/** + * Signals the ping thread in a ping-pong construct. (I.e. sends pong.) + * This is called by the pong thread. + * + * @returns iprt status code. + * @param pPP Pointer to the ping-pong structure to pong. + */ +RTDECL(int) RTSemPong(PRTPINGPONG pPP); + +/** + * Wait function for the ping thread. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param pPP Pointer to the ping-pong structure to wait on. + * @param cMillies Number of milliseconds to wait. + */ +RTDECL(int) RTSemPingWait(PRTPINGPONG pPP, RTMSINTERVAL cMillies); + +/** + * Wait function for the pong thread. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param pPP Pointer to the ping-pong structure to wait on. + * @param cMillies Number of milliseconds to wait. + */ +RTDECL(int) RTSemPongWait(PRTPINGPONG pPP, RTMSINTERVAL cMillies); + + +/** + * Checks if the pong thread is speaking. + * + * @returns true / false. + * @param pPP Pointer to the ping-pong structure. + * @remark This is NOT the same as !RTSemPongIsSpeaker(). + */ +DECLINLINE(bool) RTSemPingIsSpeaker(PRTPINGPONG pPP) +{ + RTPINGPONGSPEAKER enmSpeaker = pPP->enmSpeaker; + return enmSpeaker == RTPINGPONGSPEAKER_PING; +} + + +/** + * Checks if the pong thread is speaking. + * + * @returns true / false. + * @param pPP Pointer to the ping-pong structure. + * @remark This is NOT the same as !RTSemPingIsSpeaker(). + */ +DECLINLINE(bool) RTSemPongIsSpeaker(PRTPINGPONG pPP) +{ + RTPINGPONGSPEAKER enmSpeaker = pPP->enmSpeaker; + return enmSpeaker == RTPINGPONGSPEAKER_PONG; +} + + +/** + * Checks whether the ping thread should wait. + * + * @returns true / false. + * @param pPP Pointer to the ping-pong structure. + * @remark This is NOT the same as !RTSemPongShouldWait(). + */ +DECLINLINE(bool) RTSemPingShouldWait(PRTPINGPONG pPP) +{ + RTPINGPONGSPEAKER enmSpeaker = pPP->enmSpeaker; + return enmSpeaker == RTPINGPONGSPEAKER_PONG + || enmSpeaker == RTPINGPONGSPEAKER_PONG_SIGNALED + || enmSpeaker == RTPINGPONGSPEAKER_PING_SIGNALED; +} + + +/** + * Checks whether the pong thread should wait. + * + * @returns true / false. + * @param pPP Pointer to the ping-pong structure. + * @remark This is NOT the same as !RTSemPingShouldWait(). + */ +DECLINLINE(bool) RTSemPongShouldWait(PRTPINGPONG pPP) +{ + RTPINGPONGSPEAKER enmSpeaker = pPP->enmSpeaker; + return enmSpeaker == RTPINGPONGSPEAKER_PING + || enmSpeaker == RTPINGPONGSPEAKER_PING_SIGNALED + || enmSpeaker == RTPINGPONGSPEAKER_PONG_SIGNALED; +} + +/** @} */ + + +/** @defgroup grp_rt_sems_xroads RTSemXRoads - Crossroads + * + * The crossroads semaphore is intended to prevent two classes of incompatible + * events from occurring simultaneously, like south/north bound traffic and + * west/east bound traffic at a 4-way junction. + * + * @remarks In order to simplify the implementation, the current flow is always + * given priority. So, it won't work at all well when busy! + * + * @remarks "XRoads" is used as a name because it is briefer than "crossroads" + * and it slightly stresses that is a 4 way crossing to the users of + * American English. + * @{ + */ + +/** + * Creates a crossroads semaphore. + * + * @returns IPRT status code. + * + * @param phXRoads Where to return the handle to the newly created + * crossroads semaphore. + */ +RTDECL(int) RTSemXRoadsCreate(PRTSEMXROADS phXRoads); + +/** + * Destroys a crossroads semaphore. + * + * @returns IPRT status code. + * + * @param hXRoads Handle to the crossroads semaphore that is to be + * destroyed. NIL_RTSEMXROADS is quitetly ignored + * (VINF_SUCCESS). + */ +RTDECL(int) RTSemXRoadsDestroy(RTSEMXROADS hXRoads); + +/** + * Enter the crossroads from the south or north. + * + * (Coupled with RTSemXRoadsNSLeave.) + * + * @returns IPRT status code. + * @param hXRoads Handle to the crossroads semaphore. + */ +RTDECL(int) RTSemXRoadsNSEnter(RTSEMXROADS hXRoads); + +/** + * Leave the crossroads to the north or south. + * + * (Coupled with RTSemXRoadsNSEnter.) + * + * @returns IPRT status code. + * @param hXRoads Handle to the crossroads semaphore. + */ +RTDECL(int) RTSemXRoadsNSLeave(RTSEMXROADS hXRoads); + +/** + * Leave the crossroads from the east or west. + * + * (Coupled with RTSemXRoadsEWLeave.) + * + * @returns IPRT status code. + * @param hXRoads Handle to the crossroads semaphore. + */ +RTDECL(int) RTSemXRoadsEWEnter(RTSEMXROADS hXRoads); + +/** + * Leave the crossroads to the west or east. + * + * (Coupled with RTSemXRoadsEWEnter.) + * + * @returns IPRT status code. + * @param hXRoads Handle to the crossroads semaphore. + */ +RTDECL(int) RTSemXRoadsEWLeave(RTSEMXROADS hXRoads); + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_semaphore_h */ + diff --git a/include/iprt/serialport.h b/include/iprt/serialport.h new file mode 100644 index 00000000..25f5fbe5 --- /dev/null +++ b/include/iprt/serialport.h @@ -0,0 +1,377 @@ +/** @file + * IPRT Serial Port API. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_serialport_h +#define IPRT_INCLUDED_serialport_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_serial IPRT Serial Port API + * @ingroup grp_rt + * + * The IPRT serial port API provides a platform independent API to control a + * serial port of the host. It supports receiving/transmitting data as well as + * controlling and monitoring the status lines of a standard serial port. + * + * The user of the API is currently resposible for serializing calls to it. + * The only exception is RTSerialPortEvtPollInterrupt() which can be called on + * any thread to interrupt another thread waiting in RTSerialPortEvtPoll(). + * + * @{ + */ + +/** Serial Port handle. */ +typedef struct RTSERIALPORTINTERNAL *RTSERIALPORT; +/** Pointer to a Serial Port handle. */ +typedef RTSERIALPORT *PRTSERIALPORT; +/** NIL Serial Port handle value. */ +#define NIL_RTSERIALPORT ((RTSERIALPORT)0) + + +/** + * Supported parity settings. + */ +typedef enum RTSERIALPORTPARITY +{ + /** Invalid parity setting. */ + RTSERIALPORTPARITY_INVALID = 0, + /** No parity used. */ + RTSERIALPORTPARITY_NONE, + /** Even parity used. */ + RTSERIALPORTPARITY_EVEN, + /** Odd parity used. */ + RTSERIALPORTPARITY_ODD, + /** Mark parity (parity bit always 1) used. */ + RTSERIALPORTPARITY_MARK, + /** Space parity (parity bit always 0) used. */ + RTSERIALPORTPARITY_SPACE, + /** 32bit hack. */ + RTSERIALPORTPARITY_32BIT_HACK = 0x7fffffff +} RTSERIALPORTPARITY; + + +/** + * Supported data bit count setting. + */ +typedef enum RTSERIALPORTDATABITS +{ + /** Invalid bitcount setting. */ + RTSERIALPORTDATABITS_INVALID = 0, + /** 5 data bits. */ + RTSERIALPORTDATABITS_5BITS, + /** 6 data bits. */ + RTSERIALPORTDATABITS_6BITS, + /** 7 data bits. */ + RTSERIALPORTDATABITS_7BITS, + /** 8 data bits. */ + RTSERIALPORTDATABITS_8BITS, + /** 32bit hack. */ + RTSERIALPORTDATABITS_32BIT_HACK = 0x7fffffff +} RTSERIALPORTDATABITS; + + +/** + * Supported stop bit setting. + */ +typedef enum RTSERIALPORTSTOPBITS +{ + /** Invalid stop bit setting. */ + RTSERIALPORTSTOPBITS_INVALID = 0, + /** One stop bit is used. */ + RTSERIALPORTSTOPBITS_ONE, + /** 1.5 stop bits are used. */ + RTSERIALPORTSTOPBITS_ONEPOINTFIVE, + /** 2 stop bits are used. */ + RTSERIALPORTSTOPBITS_TWO, + /** 32bit hack. */ + RTSERIALPORTSTOPBITS_32BIT_HACK = 0x7fffffff +} RTSERIALPORTSTOPBITS; + + +/** + * Serial port config structure. + */ +typedef struct RTSERIALPORTCFG +{ + /** Baud rate. */ + uint32_t uBaudRate; + /** Used parity. */ + RTSERIALPORTPARITY enmParity; + /** Number of data bits. */ + RTSERIALPORTDATABITS enmDataBitCount; + /** Number of stop bits. */ + RTSERIALPORTSTOPBITS enmStopBitCount; +} RTSERIALPORTCFG; +/** Pointer to a serial port config. */ +typedef RTSERIALPORTCFG *PRTSERIALPORTCFG; +/** Pointer to a const serial port config. */ +typedef const RTSERIALPORTCFG *PCRTSERIALPORTCFG; + + +/** @name RTSerialPortOpen flags + * @{ */ +/** Open the serial port with the receiver enabled to receive data. */ +#define RTSERIALPORT_OPEN_F_READ RT_BIT(0) +/** Open the serial port with the transmitter enabled to transmit data. */ +#define RTSERIALPORT_OPEN_F_WRITE RT_BIT(1) +/** Open the serial port with status line monitoring enabled to get notified about status line changes. */ +#define RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING RT_BIT(2) +/** Open the serial port with BREAK condition detection enabled (Requires extra work on some hosts). */ +#define RTSERIALPORT_OPEN_F_DETECT_BREAK_CONDITION RT_BIT(3) +/** Open the serial port with loopback mode enabled. */ +#define RTSERIALPORT_OPEN_F_ENABLE_LOOPBACK RT_BIT(4) +/** Bitmask of valid flags. */ +#define RTSERIALPORT_OPEN_F_VALID_MASK UINT32_C(0x0000001f) +/** @} */ + + +/** @name RTSerialPortChgModemLines flags + * @{ */ +/** Change the RTS (Ready To Send) line signal. */ +#define RTSERIALPORT_CHG_STS_LINES_F_RTS RT_BIT(0) +/** Change the DTR (Data Terminal Ready) line signal. */ +#define RTSERIALPORT_CHG_STS_LINES_F_DTR RT_BIT(1) +/** Bitmask of valid flags. */ +#define RTSERIALPORT_CHG_STS_LINES_F_VALID_MASK UINT32_C(0x00000003) +/** @} */ + + +/** @name RTSerialPortQueryStatusLines flags + * @{ */ +/** The DCD (Data Carrier Detect) signal is active. */ +#define RTSERIALPORT_STS_LINE_DCD RT_BIT(0) +/** The RI (Ring Indicator) signal is active. */ +#define RTSERIALPORT_STS_LINE_RI RT_BIT(1) +/** The DSR (Data Set Ready) signal is active. */ +#define RTSERIALPORT_STS_LINE_DSR RT_BIT(2) +/** The CTS (Clear To Send) signal is active. */ +#define RTSERIALPORT_STS_LINE_CTS RT_BIT(3) +/** @} */ + + +/** @name RTSerialPortEvtPoll flags + * @{ */ +/** Data was received and can be read. */ +#define RTSERIALPORT_EVT_F_DATA_RX RT_BIT(0) +/** All data was transmitted and there is room again in the transmit buffer. */ +#define RTSERIALPORT_EVT_F_DATA_TX RT_BIT(1) +/** A BREAK condition was detected on the communication channel. + * Only available when BREAK condition detection was enabled when opening the serial port .*/ +#define RTSERIALPORT_EVT_F_BREAK_DETECTED RT_BIT(2) +/** One of the monitored status lines changed, check with RTSerialPortQueryStatusLines(). + * Only available if status line monitoring was enabled when opening the serial port. */ +#define RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED RT_BIT(3) +/** Status line monitor failed with an error and status line monitoring is disabled, + * this cannot be given in the event mask but will be set if status line + * monitoring is enabled and the monitor failed. */ +#define RTSERIALPORT_EVT_F_STATUS_LINE_MONITOR_FAILED RT_BIT(4) +/** Bitmask of valid flags. */ +#define RTSERIALPORT_EVT_F_VALID_MASK UINT32_C(0x0000001f) +/** @} */ + + +/** + * Opens a serial port with the specified flags. + * + * @returns IPRT status code. + * @param phSerialPort Where to store the IPRT serial port handle on success. + * @param pszPortAddress The address of the serial port (host dependent). + * @param fFlags Flags to open the serial port with, see RTSERIALPORT_OPEN_F_*. + */ +RTDECL(int) RTSerialPortOpen(PRTSERIALPORT phSerialPort, const char *pszPortAddress, uint32_t fFlags); + + +/** + * Closes the given serial port handle. + * + * @returns IPRT status code. + * @param hSerialPort The IPRT serial port handle. + */ +RTDECL(int) RTSerialPortClose(RTSERIALPORT hSerialPort); + + +/** + * Gets the native handle for an IPRT serial port handle. + * + * @returns The native handle. -1 on failure. + * @param hSerialPort The IPRT serial port handle. + */ +RTDECL(RTHCINTPTR) RTSerialPortToNative(RTSERIALPORT hSerialPort); + + +/** + * Tries to read the given number of bytes from the serial port, blocking version. + * + * @returns IPRT status code. + * @retval VERR_SERIALPORT_BREAK_DETECTED if a break was detected before the requested number of bytes was received. + * @param hSerialPort The IPRT serial port handle. + * @param pvBuf Where to store the read data. + * @param cbToRead How much to read from the serial port. + * @param pcbRead Where to store the number of bytes received until an error condition occurred, optional. + */ +RTDECL(int) RTSerialPortRead(RTSERIALPORT hSerialPort, void *pvBuf, size_t cbToRead, size_t *pcbRead); + + +/** + * Tries to read the given number of bytes from the serial port, non-blocking version. + * + * @returns IPRT status code. + * @retval VERR_SERIALPORT_BREAK_DETECTED if a break was detected before anything could be received. + * @retval VINF_TRY_AGAIN if nothing could be read. + * @param hSerialPort The IPRT serial port handle. + * @param pvBuf Where to store the read data. + * @param cbToRead How much to read from the serial port. + * @param pcbRead Where to store the number of bytes received. + */ +RTDECL(int) RTSerialPortReadNB(RTSERIALPORT hSerialPort, void *pvBuf, size_t cbToRead, size_t *pcbRead); + + +/** + * Writes the given data to the serial port, blocking version. + * + * @returns IPRT status code. + * @param hSerialPort The IPRT serial port handle. + * @param pvBuf The data to write. + * @param cbToWrite How much to write. + * @param pcbWritten Where to store the number of bytes written until an error condition occurred, optional. + */ +RTDECL(int) RTSerialPortWrite(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + + +/** + * Writes the given data to the serial port, non-blocking version. + * + * @returns IPRT status code. + * @retval VINF_TRY_AGAIN if nothing could be written. + * @param hSerialPort The IPRT serial port handle. + * @param pvBuf The data to write. + * @param cbToWrite How much to write. + * @param pcbWritten Where to store the number of bytes written. + */ +RTDECL(int) RTSerialPortWriteNB(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + + +/** + * Queries the current active serial port config. + * + * @returns IPRT status code. + * @param hSerialPort The IPRT serial port handle. + * @param pCfg Where to store the current active config. + */ +RTDECL(int) RTSerialPortCfgQueryCurrent(RTSERIALPORT hSerialPort, PRTSERIALPORTCFG pCfg); + + +/** + * Change the serial port to the given config. + * + * @returns IPRT status code. + * @retval VERR_SERIALPORT_INVALID_BAUDRATE if the baud rate is not supported on the serial port. + * @param hSerialPort The IPRT serial port handle. + * @param pCfg The config to write. + * @param pErrInfo Where to store additional information on error, optional. + */ +RTDECL(int) RTSerialPortCfgSet(RTSERIALPORT hSerialPort, PCRTSERIALPORTCFG pCfg, PRTERRINFO pErrInfo); + + +/** + * Poll for an event on the given serial port. + * + * @returns IPRT status code. + * @retval VERR_TIMEOUT if the timeout was reached before an event happened. + * @retval VERR_INTERRUPTED if another thread interrupted the polling through RTSerialPortEvtPollInterrupt(). + * @param hSerialPort The IPRT serial port handle. + * @param fEvtMask The mask of events to receive, see RTSERIALPORT_EVT_F_* + * @param pfEvtsRecv Where to store the bitmask of events received. + * @param msTimeout Number of milliseconds to wait for an event. + */ +RTDECL(int) RTSerialPortEvtPoll(RTSERIALPORT hSerialPort, uint32_t fEvtMask, uint32_t *pfEvtsRecv, + RTMSINTERVAL msTimeout); + + +/** + * Interrupt another thread currently polling for an event. + * + * @returns IPRT status code. + * @param hSerialPort The IPRT serial port handle. + * + * @note Any thread. + */ +RTDECL(int) RTSerialPortEvtPollInterrupt(RTSERIALPORT hSerialPort); + + +/** + * Sets or clears a BREAK condition on the given serial port. + * + * @returns IPRT status code. + * @param hSerialPort The IPRT serial port handle. + * @param fSet Flag whether to set the BREAK condition or clear it. + */ +RTDECL(int) RTSerialPortChgBreakCondition(RTSERIALPORT hSerialPort, bool fSet); + + +/** + * Modify the status lines of the given serial port. + * + * @returns IPRT status code. + * @param hSerialPort The IPRT serial port handle. + * @param fClear Combination of status lines to clear, see RTSERIALPORT_CHG_STS_LINES_F_*. + * @param fSet Combination of status lines to set, see RTSERIALPORT_CHG_STS_LINES_F_*. + * + * @note fClear takes precedence over fSet in case the same status line bit is set in both arguments. + */ +RTDECL(int) RTSerialPortChgStatusLines(RTSERIALPORT hSerialPort, uint32_t fClear, uint32_t fSet); + + +/** + * Query the status of the status lines on the given serial port. + * + * @returns IPRT status code. + * @param hSerialPort The IPRT serial port handle. + * @param pfStsLines Where to store the bitmask of active status lines on success, + * see RTSERIALPORT_STS_LINE_*. + */ +RTDECL(int) RTSerialPortQueryStatusLines(RTSERIALPORT hSerialPort, uint32_t *pfStsLines); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_serialport_h */ + diff --git a/include/iprt/setjmp-without-sigmask.h b/include/iprt/setjmp-without-sigmask.h new file mode 100644 index 00000000..b73bce4c --- /dev/null +++ b/include/iprt/setjmp-without-sigmask.h @@ -0,0 +1,64 @@ +/** @file + * IPRT - setjmp/long without signal mask saving and restoring. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_setjmp_without_sigmask_h +#define IPRT_INCLUDED_setjmp_without_sigmask_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include <iprt/cdefs.h> +#include <setjmp.h> + +/* + * System V and ANSI-C setups does not by default map setjmp/longjmp to the + * signal mask saving/restoring variants (Linux included). This is mainly + * an issue on BSD derivatives. + */ +#if defined(IN_RING3) \ + && ( defined(RT_OS_DARWIN) \ + || defined(RT_OS_DRAGONFLY) \ + || defined(RT_OS_FREEBSD) \ + || defined(RT_OS_NETBSD) \ + || defined(RT_OS_OPENBSD) ) +# undef setjmp /* /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/setjmp.h defines it on macOS. */ +# define setjmp _setjmp +# define longjmp _longjmp +#endif + + +#endif /* !IPRT_INCLUDED_setjmp_without_sigmask_h */ + diff --git a/include/iprt/sg.h b/include/iprt/sg.h new file mode 100644 index 00000000..b0831d95 --- /dev/null +++ b/include/iprt/sg.h @@ -0,0 +1,460 @@ +/** @file + * IPRT - S/G buffer handling. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_sg_h +#define IPRT_INCLUDED_sg_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_sgbuf RTSgBuf - Scatter / Gather Buffers + * @ingroup grp_rt + * @{ + */ + +/** Pointer to a const S/G entry. */ +typedef const struct RTSGBUF *PCRTSGBUF; + +/** + * Callback for RTSgBufCopyToFn() called on every segment of the given S/G buffer. + * + * @returns Number of bytes copied for this segment, a value smaller than cbSrc will stop the copy operation. + * @param pSgBuf The S/G buffer for reference. + * @param pvSrc Where to copy from. + * @param cbSrc The number of bytes in the source buffer. + * @param pvUser Opaque user data passed in RTSgBufCopyToFn(). + */ +typedef DECLCALLBACKTYPE(size_t, FNRTSGBUFCOPYTO, (PCRTSGBUF pSgBuf, const void *pvSrc, size_t cbSrc, void *pvUser)); +/** Pointer to a FNRTSGBUFCOPYTO. */ +typedef FNRTSGBUFCOPYTO *PFNRTSGBUFCOPYTO; + +/** + * Callback for RTSgBufCopyFromFn() called on every segment of the given S/G buffer. + * + * @returns Number of bytes copied for this segment, a value smaller than cbDst will stop the copy operation. + * @param pSgBuf The S/G buffer for reference. + * @param pvDst Where to copy to. + * @param cbDst The number of bytes in the destination buffer. + * @param pvUser Opaque user data passed in RTSgBufCopyFromFn(). + */ +typedef DECLCALLBACKTYPE(size_t, FNRTSGBUFCOPYFROM, (PCRTSGBUF pSgBuf, void *pvDst, size_t cbDst, void *pvUser)); +/** Pointer to a FNRTSGBUFCOPYFROM. */ +typedef FNRTSGBUFCOPYFROM *PFNRTSGBUFCOPYFROM; + +/** + * A S/G entry. + */ +typedef struct RTSGSEG +{ + /** Pointer to the segment buffer. */ + void *pvSeg; + /** Size of the segment buffer. */ + size_t cbSeg; +} RTSGSEG; +/** Pointer to a S/G entry. */ +typedef RTSGSEG *PRTSGSEG; +/** Pointer to a const S/G entry. */ +typedef const RTSGSEG *PCRTSGSEG; +/** Pointer to a S/G entry pointer. */ +typedef PRTSGSEG *PPRTSGSEG; + +/** + * A S/G buffer. + * + * The members should be treated as private. + * + * @warning There is a lot of code, especially in the VFS area of IPRT, that + * totally ignores the idxSeg, pvSegCur and cbSegLeft members! So, + * it is not recommended to pass buffers that aren't fully reset or + * where cbSegLeft is shorter than what paSegs describes. + */ +typedef struct RTSGBUF +{ + /** Pointer to the scatter/gather array. */ + PCRTSGSEG paSegs; + /** Number of segments. */ + unsigned cSegs; + + /** Current segment we are in. */ + unsigned idxSeg; + /** Pointer to current byte within the current segment. */ + void *pvSegCur; + /** Number of bytes left in the current segment. */ + size_t cbSegLeft; +} RTSGBUF; +/** Pointer to a S/G entry. */ +typedef RTSGBUF *PRTSGBUF; +/** Pointer to a S/G entry pointer. */ +typedef PRTSGBUF *PPRTSGBUF; + + +/** + * Sums up the length of all the segments. + * + * @returns The complete segment length. + * @param pSgBuf The S/G buffer to check out. + */ +DECLINLINE(size_t) RTSgBufCalcTotalLength(PCRTSGBUF pSgBuf) +{ + size_t cb = 0; + unsigned i = pSgBuf->cSegs; + while (i-- > 0) + cb += pSgBuf->paSegs[i].cbSeg; + return cb; +} + +/** + * Sums up the number of bytes left from the current position. + * + * @returns Number of bytes left. + * @param pSgBuf The S/G buffer to check out. + */ +DECLINLINE(size_t) RTSgBufCalcLengthLeft(PCRTSGBUF pSgBuf) +{ + size_t cb = pSgBuf->cbSegLeft; + unsigned i = pSgBuf->cSegs; + while (i-- > pSgBuf->idxSeg + 1) + cb += pSgBuf->paSegs[i].cbSeg; + return cb; +} + +/** + * Checks if the current buffer position is at the start of the first segment. + * + * @returns true / false. + * @param pSgBuf The S/G buffer to check out. + */ +DECLINLINE(bool) RTSgBufIsAtStart(PCRTSGBUF pSgBuf) +{ + return pSgBuf->idxSeg == 0 + && ( pSgBuf->cSegs == 0 + || pSgBuf->pvSegCur == pSgBuf->paSegs[0].pvSeg); +} + +/** + * Checks if the current buffer position is at the end of all the segments. + * + * @returns true / false. + * @param pSgBuf The S/G buffer to check out. + */ +DECLINLINE(bool) RTSgBufIsAtEnd(PCRTSGBUF pSgBuf) +{ + return pSgBuf->idxSeg > pSgBuf->cSegs + || ( pSgBuf->idxSeg == pSgBuf->cSegs + && pSgBuf->cbSegLeft == 0); +} + +/** + * Checks if the current buffer position is at the start of the current segment. + * + * @returns true / false. + * @param pSgBuf The S/G buffer to check out. + */ +DECLINLINE(bool) RTSgBufIsAtStartOfSegment(PCRTSGBUF pSgBuf) +{ + return pSgBuf->idxSeg < pSgBuf->cSegs + && pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg == pSgBuf->pvSegCur; +} + +/** + * Initialize a S/G buffer structure. + * + * @returns nothing. + * @param pSgBuf Pointer to the S/G buffer to initialize. + * @param paSegs Pointer to the start of the segment array. + * @param cSegs Number of segments in the array. + * + * @note paSegs and cSegs can be NULL and 0 respectively to indicate an empty + * S/G buffer. Operations on the S/G buffer will not do anything in this + * case. + */ +RTDECL(void) RTSgBufInit(PRTSGBUF pSgBuf, PCRTSGSEG paSegs, size_t cSegs); + +/** + * Resets the internal buffer position of the S/G buffer to the beginning. + * + * @returns nothing. + * @param pSgBuf The S/G buffer to reset. + */ +RTDECL(void) RTSgBufReset(PRTSGBUF pSgBuf); + +/** + * Clones a given S/G buffer. + * + * @returns nothing. + * @param pSgBufNew The new S/G buffer to clone to. + * @param pSgBufOld The source S/G buffer to clone from. + * + * @note This is only a shallow copy. Both S/G buffers will point to the + * same segment array. + */ +RTDECL(void) RTSgBufClone(PRTSGBUF pSgBufNew, PCRTSGBUF pSgBufOld); + +/** + * Returns the next segment in the S/G buffer or NULL if no segments left. + * + * @returns Pointer to the next segment in the S/G buffer. + * @param pSgBuf The S/G buffer. + * @param cbDesired The max number of bytes to get. + * @param pcbSeg Where to store the size of the returned segment, this is + * equal or smaller than @a cbDesired. + * + * @note Use RTSgBufAdvance() to advance after read/writing into the buffer. + */ +DECLINLINE(void *) RTSgBufGetCurrentSegment(PRTSGBUF pSgBuf, size_t cbDesired, size_t *pcbSeg) +{ + if (!RTSgBufIsAtEnd(pSgBuf)) + { + *pcbSeg = RT_MIN(cbDesired, pSgBuf->cbSegLeft); + return pSgBuf->pvSegCur; + } + *pcbSeg = 0; + return NULL; +} + +/** + * Returns the next segment in the S/G buffer or NULL if no segment is left. + * + * @returns Pointer to the next segment in the S/G buffer. + * @param pSgBuf The S/G buffer. + * @param pcbSeg Where to store the size of the returned segment. + * Holds the number of bytes requested initially or 0 to + * indicate that the size doesn't matter. + * This may contain fewer bytes on success if the current segment + * is smaller than the amount of bytes requested. + * + * @note This operation advances the internal buffer pointer of both S/G buffers. + */ +RTDECL(void *) RTSgBufGetNextSegment(PRTSGBUF pSgBuf, size_t *pcbSeg); + +/** + * Copy data between two S/G buffers. + * + * @returns The number of bytes copied. + * @param pSgBufDst The destination S/G buffer. + * @param pSgBufSrc The source S/G buffer. + * @param cbCopy Number of bytes to copy. + * + * @note This operation advances the internal buffer pointer of both S/G buffers. + */ +RTDECL(size_t) RTSgBufCopy(PRTSGBUF pSgBufDst, PRTSGBUF pSgBufSrc, size_t cbCopy); + +/** + * Compares the content of two S/G buffers. + * + * @returns Whatever memcmp returns. + * @param pSgBuf1 First S/G buffer. + * @param pSgBuf2 Second S/G buffer. + * @param cbCmp How many bytes to compare. + * + * @note This operation doesn't change the internal position of the S/G buffers. + */ +RTDECL(int) RTSgBufCmp(PCRTSGBUF pSgBuf1, PCRTSGBUF pSgBuf2, size_t cbCmp); + +/** + * Compares the content of two S/G buffers - advanced version. + * + * @returns Whatever memcmp returns. + * @param pSgBuf1 First S/G buffer. + * @param pSgBuf2 Second S/G buffer. + * @param cbCmp How many bytes to compare. + * @param poffDiff Where to store the offset of the first different byte + * in the buffer starting from the position of the S/G + * buffer before this call. + * @param fAdvance Flag whether the internal buffer position should be advanced. + * + */ +RTDECL(int) RTSgBufCmpEx(PRTSGBUF pSgBuf1, PRTSGBUF pSgBuf2, size_t cbCmp, size_t *poffDiff, bool fAdvance); + +/** + * Fills an S/G buf with a constant byte. + * + * @returns The number of actually filled bytes. + * Can be less than than cbSet if the end of the S/G buffer was reached. + * @param pSgBuf The S/G buffer. + * @param ubFill The byte to fill the buffer with. + * @param cbSet How many bytes to set. + * + * @note This operation advances the internal buffer pointer of the S/G buffer. + */ +RTDECL(size_t) RTSgBufSet(PRTSGBUF pSgBuf, uint8_t ubFill, size_t cbSet); + +/** + * Copies data from an S/G buffer into a given non scattered buffer. + * + * @returns Number of bytes copied. + * @param pSgBuf The S/G buffer to copy from. + * @param pvBuf Buffer to copy the data into. + * @param cbCopy How many bytes to copy. + * + * @note This operation advances the internal buffer pointer of the S/G buffer. + */ +RTDECL(size_t) RTSgBufCopyToBuf(PRTSGBUF pSgBuf, void *pvBuf, size_t cbCopy); + +/** + * Copies data from a non scattered buffer into an S/G buffer. + * + * @returns Number of bytes copied. + * @param pSgBuf The S/G buffer to copy to. + * @param pvBuf Buffer to copy the data from. + * @param cbCopy How many bytes to copy. + * + * @note This operation advances the internal buffer pointer of the S/G buffer. + */ +RTDECL(size_t) RTSgBufCopyFromBuf(PRTSGBUF pSgBuf, const void *pvBuf, size_t cbCopy); + +/** + * Copies data from the given S/G buffer to a destination handled by the given callback. + * + * @returns Number of bytes copied. + * @param pSgBuf The S/G buffer to copy from. + * @param cbCopy How many bytes to copy. + * @param pfnCopyTo The callback to call on every S/G buffer segment until the operation finished. + * @param pvUser Opaque user data to pass in the given callback. + * + * @note This operation advances the internal buffer pointer of the S/G buffer. + */ +RTDECL(size_t) RTSgBufCopyToFn(PRTSGBUF pSgBuf, size_t cbCopy, PFNRTSGBUFCOPYTO pfnCopyTo, void *pvUser); + +/** + * Copies data to the given S/G buffer from a destination handled by the given callback. + * + * @returns Number of bytes copied. + * @param pSgBuf The S/G buffer to copy to. + * @param cbCopy How many bytes to copy. + * @param pfnCopyFrom The callback to call on every S/G buffer segment until the operation finished. + * @param pvUser Opaque user data to pass in the given callback. + * + * @note This operation advances the internal buffer pointer of the S/G buffer. + */ +RTDECL(size_t) RTSgBufCopyFromFn(PRTSGBUF pSgBuf, size_t cbCopy, PFNRTSGBUFCOPYFROM pfnCopyFrom, void *pvUser); + +/** + * Advances the internal buffer pointer. + * + * @returns Number of bytes the pointer was moved forward. + * @param pSgBuf The S/G buffer. + * @param cbAdvance Number of bytes to move forward. + */ +RTDECL(size_t) RTSgBufAdvance(PRTSGBUF pSgBuf, size_t cbAdvance); + +/** + * Constructs a new segment array starting from the current position + * and describing the given number of bytes. + * + * @returns Number of bytes the array describes. + * @param pSgBuf The S/G buffer. + * @param paSeg The uninitialized segment array. + * If NULL pcSeg will contain the number of segments needed + * to describe the requested amount of data. + * @param pcSeg The number of segments the given array has. + * This will hold the actual number of entries needed upon return. + * @param cbData Number of bytes the new array should describe. + * + * @note This operation advances the internal buffer pointer of the S/G buffer if paSeg is not NULL. + */ +RTDECL(size_t) RTSgBufSegArrayCreate(PRTSGBUF pSgBuf, PRTSGSEG paSeg, unsigned *pcSeg, size_t cbData); + +/** + * Returns whether the given S/G buffer is zeroed out from the current position + * upto the number of bytes to check. + * + * @returns true if the buffer has only zeros + * false otherwise. + * @param pSgBuf The S/G buffer. + * @param cbCheck Number of bytes to check. + */ +RTDECL(bool) RTSgBufIsZero(PRTSGBUF pSgBuf, size_t cbCheck); + +/** + * Maps the given S/G buffer to a segment array of another type (for example to + * iovec on POSIX or WSABUF on Windows). + * + * @param paMapped Where to store the pointer to the start of the native + * array or NULL. The memory needs to be freed with + * RTMemTmpFree(). + * @param pSgBuf The S/G buffer to map. + * @param Struct Struct used as the destination. + * @param pvBufField Name of the field holding the pointer to a buffer. + * @param TypeBufPtr Type of the buffer pointer. + * @param cbBufField Name of the field holding the size of the buffer. + * @param TypeBufSize Type of the field for the buffer size. + * @param cSegsMapped Where to store the number of segments the native array + * has. + * + * @note This operation maps the whole S/G buffer starting at the current + * internal position. The internal buffer position is unchanged by + * this operation. + * + * @remark Usage is a bit ugly but saves a few lines of duplicated code + * somewhere else and makes it possible to keep the S/G buffer members + * private without going through RTSgBufSegArrayCreate() first. + */ +#define RTSgBufMapToNative(paMapped, pSgBuf, Struct, pvBufField, TypeBufPtr, cbBufField, TypeBufSize, cSegsMapped) \ + do \ + { \ + AssertCompileMemberSize(Struct, pvBufField, RT_SIZEOFMEMB(RTSGSEG, pvSeg)); \ + /*AssertCompile(RT_SIZEOFMEMB(Struct, cbBufField) >= RT_SIZEOFMEMB(RTSGSEG, cbSeg));*/ \ + (cSegsMapped) = (pSgBuf)->cSegs - (pSgBuf)->idxSeg; \ + \ + /* We need room for at least one segment. */ \ + if ((pSgBuf)->cSegs == (pSgBuf)->idxSeg) \ + (cSegsMapped)++; \ + \ + (paMapped) = (Struct *)RTMemTmpAllocZ((cSegsMapped) * sizeof(Struct)); \ + if ((paMapped)) \ + { \ + /* The first buffer is special because we could be in the middle of a segment. */ \ + (paMapped)[0].pvBufField = (TypeBufPtr)(pSgBuf)->pvSegCur; \ + (paMapped)[0].cbBufField = (TypeBufSize)(pSgBuf)->cbSegLeft; \ + \ + for (unsigned i = 1; i < (cSegsMapped); i++) \ + { \ + (paMapped)[i].pvBufField = (TypeBufPtr)(pSgBuf)->paSegs[(pSgBuf)->idxSeg + i].pvSeg; \ + (paMapped)[i].cbBufField = (TypeBufSize)(pSgBuf)->paSegs[(pSgBuf)->idxSeg + i].cbSeg; \ + } \ + } \ + } while (0) + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_sg_h */ + diff --git a/include/iprt/sha.h b/include/iprt/sha.h new file mode 100644 index 00000000..d39e0ca7 --- /dev/null +++ b/include/iprt/sha.h @@ -0,0 +1,593 @@ +/** @file + * IPRT - SHA1 digest creation + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_sha_h +#define IPRT_INCLUDED_sha_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_sha RTSha - SHA Family of Hash Functions + * @ingroup grp_rt + * @{ + */ + +/** The size of a SHA-1 hash. */ +#define RTSHA1_HASH_SIZE 20 +/** The length of a SHA-1 digest string. The terminator is not included. */ +#define RTSHA1_DIGEST_LEN 40 + +/** + * SHA-1 context. + */ +typedef union RTSHA1CONTEXT +{ + uint64_t u64BetterAlignment; + uint8_t abPadding[8 + (5 + 80) * 4 + 4]; +#ifdef RT_SHA1_PRIVATE_CONTEXT + SHA_CTX Private; +#endif +#ifdef RT_SHA1_PRIVATE_ALT_CONTEXT + RTSHA1ALTPRIVATECTX AltPrivate; +#endif +} RTSHA1CONTEXT; +/** Pointer to an SHA-1 context. */ +typedef RTSHA1CONTEXT *PRTSHA1CONTEXT; + +/** + * Compute the SHA-1 hash of the data. + * + * @param pvBuf Pointer to the data. + * @param cbBuf The amount of data (in bytes). + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTSha1(const void *pvBuf, size_t cbBuf, uint8_t pabHash[RTSHA1_HASH_SIZE]); + +/** + * Computes the SHA-1 hash for the given data comparing it with the one given. + * + * @returns true on match, false on mismatch. + * @param pvBuf Pointer to the data. + * @param cbBuf The amount of data (in bytes). + * @param pabHash The hash to verify. (What is passed is a pointer to the + * caller's buffer.) + */ +RTDECL(bool) RTSha1Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA1_HASH_SIZE]); + +/** + * Initializes the SHA-1 context. + * + * @param pCtx Pointer to the SHA-1 context. + */ +RTDECL(void) RTSha1Init(PRTSHA1CONTEXT pCtx); + +/** + * Feed data into the SHA-1 computation. + * + * @param pCtx Pointer to the SHA-1 context. + * @param pvBuf Pointer to the data. + * @param cbBuf The length of the data (in bytes). + */ +RTDECL(void) RTSha1Update(PRTSHA1CONTEXT pCtx, const void *pvBuf, size_t cbBuf); + +/** + * Compute the SHA-1 hash of the data. + * + * @param pCtx Pointer to the SHA-1 context. + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTSha1Final(PRTSHA1CONTEXT pCtx, uint8_t pabHash[RTSHA1_HASH_SIZE]); + +/** + * Converts a SHA-1 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pabHash The binary digest returned by RTSha1Final or RTSha1. + * @param pszDigest Where to return the stringified digest. + * @param cchDigest The size of the output buffer. Should be at least + * RTSHA1_DIGEST_LEN + 1 bytes. + */ +RTDECL(int) RTSha1ToString(uint8_t const pabHash[RTSHA1_HASH_SIZE], char *pszDigest, size_t cchDigest); + +/** + * Converts a SHA-1 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pszDigest The stringified digest. Leading and trailing spaces are + * ignored. + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(int) RTSha1FromString(char const *pszDigest, uint8_t pabHash[RTSHA1_HASH_SIZE]); + +/** + * Creates a SHA1 digest for the given memory buffer. + * + * @returns iprt status code. + * + * @param pvBuf Memory buffer to create a SHA1 digest for. + * @param cbBuf The amount of data (in bytes). + * @param ppszDigest On success the SHA1 digest. + * @param pfnProgressCallback optional callback for the progress indication + * @param pvUser user defined pointer for the callback + */ +RTR3DECL(int) RTSha1Digest(void* pvBuf, size_t cbBuf, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser); + +/** + * Creates a SHA1 digest for the given file. + * + * @returns iprt status code. + * + * @param pszFile Filename to create a SHA1 digest for. + * @param ppszDigest On success the SHA1 digest. + * @param pfnProgressCallback optional callback for the progress indication + * @param pvUser user defined pointer for the callback + */ +RTR3DECL(int) RTSha1DigestFromFile(const char *pszFile, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser); + + + +/** The size of a SHA-256 hash. */ +#define RTSHA256_HASH_SIZE 32 +/** The length of a SHA-256 digest string. The terminator is not included. */ +#define RTSHA256_DIGEST_LEN 64 + +/** + * SHA-256 context. + */ +typedef union RTSHA256CONTEXT +{ + uint64_t u64BetterAlignment; + uint8_t abPadding[8 + (8 + 80) * 4]; +#ifdef RT_SHA256_PRIVATE_CONTEXT + SHA256_CTX Private; +#endif +#ifdef RT_SHA256_PRIVATE_ALT_CONTEXT + RTSHA256ALTPRIVATECTX AltPrivate; +#endif +} RTSHA256CONTEXT; +/** Pointer to an SHA-256 context. */ +typedef RTSHA256CONTEXT *PRTSHA256CONTEXT; + +/** + * Compute the SHA-256 hash of the data. + * + * @param pvBuf Pointer to the data. + * @param cbBuf The amount of data (in bytes). + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTSha256(const void *pvBuf, size_t cbBuf, uint8_t pabHash[RTSHA256_HASH_SIZE]); + +/** + * Computes the SHA-256 hash for the given data comparing it with the one given. + * + * @returns true on match, false on mismatch. + * @param pvBuf Pointer to the data. + * @param cbBuf The amount of data (in bytes). + * @param pabHash The hash to verify. (What is passed is a pointer to the + * caller's buffer.) + */ +RTDECL(bool) RTSha256Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA256_HASH_SIZE]); + +/** + * Initializes the SHA-256 context. + * + * @param pCtx Pointer to the SHA-256 context. + */ +RTDECL(void) RTSha256Init(PRTSHA256CONTEXT pCtx); + +/** + * Feed data into the SHA-256 computation. + * + * @param pCtx Pointer to the SHA-256 context. + * @param pvBuf Pointer to the data. + * @param cbBuf The length of the data (in bytes). + */ +RTDECL(void) RTSha256Update(PRTSHA256CONTEXT pCtx, const void *pvBuf, size_t cbBuf); + +/** + * Compute the SHA-256 hash of the data. + * + * @param pCtx Pointer to the SHA-256 context. + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTSha256Final(PRTSHA256CONTEXT pCtx, uint8_t pabHash[RTSHA256_HASH_SIZE]); + +/** + * Converts a SHA-256 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pabHash The binary digest returned by RTSha256Final or RTSha256. + * @param pszDigest Where to return the stringified digest. + * @param cchDigest The size of the output buffer. Should be at least + * RTSHA256_DIGEST_LEN + 1 bytes. + */ +RTDECL(int) RTSha256ToString(uint8_t const pabHash[RTSHA256_HASH_SIZE], char *pszDigest, size_t cchDigest); + +/** + * Converts a SHA-256 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pszDigest The stringified digest. Leading and trailing spaces are + * ignored. + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(int) RTSha256FromString(char const *pszDigest, uint8_t pabHash[RTSHA256_HASH_SIZE]); + +/** + * Creates a SHA256 digest for the given memory buffer. + * + * @returns iprt status code. + * + * @param pvBuf Memory buffer to create a + * SHA256 digest for. + * @param cbBuf The amount of data (in bytes). + * @param ppszDigest On success the SHA256 digest. + * @param pfnProgressCallback optional callback for the progress indication + * @param pvUser user defined pointer for the callback + */ +RTR3DECL(int) RTSha256Digest(void* pvBuf, size_t cbBuf, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser); + +/** + * Creates a SHA256 digest for the given file. + * + * @returns iprt status code. + * + * @param pszFile Filename to create a SHA256 + * digest for. + * @param ppszDigest On success the SHA256 digest. + * @param pfnProgressCallback optional callback for the progress indication + * @param pvUser user defined pointer for the callback + */ +RTR3DECL(int) RTSha256DigestFromFile(const char *pszFile, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser); + + + +/** The size of a SHA-224 hash. */ +#define RTSHA224_HASH_SIZE 28 +/** The length of a SHA-224 digest string. The terminator is not included. */ +#define RTSHA224_DIGEST_LEN 56 + +/** SHA-224 context (same as for SHA-256). */ +typedef RTSHA256CONTEXT RTSHA224CONTEXT; +/** Pointer to an SHA-224 context. */ +typedef RTSHA256CONTEXT *PRTSHA224CONTEXT; + +/** + * Compute the SHA-224 hash of the data. + * + * @param pvBuf Pointer to the data. + * @param cbBuf The amount of data (in bytes). + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTSha224(const void *pvBuf, size_t cbBuf, uint8_t pabHash[RTSHA224_HASH_SIZE]); + +/** + * Computes the SHA-224 hash for the given data comparing it with the one given. + * + * @returns true on match, false on mismatch. + * @param pvBuf Pointer to the data. + * @param cbBuf The amount of data (in bytes). + * @param pabHash The hash to verify. (What is passed is a pointer to the + * caller's buffer.) + */ +RTDECL(bool) RTSha224Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA224_HASH_SIZE]); + +/** + * Initializes the SHA-224 context. + * + * @param pCtx Pointer to the SHA-224 context. + */ +RTDECL(void) RTSha224Init(PRTSHA224CONTEXT pCtx); + +/** + * Feed data into the SHA-224 computation. + * + * @param pCtx Pointer to the SHA-224 context. + * @param pvBuf Pointer to the data. + * @param cbBuf The length of the data (in bytes). + */ +RTDECL(void) RTSha224Update(PRTSHA224CONTEXT pCtx, const void *pvBuf, size_t cbBuf); + +/** + * Compute the SHA-224 hash of the data. + * + * @param pCtx Pointer to the SHA-224 context. + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTSha224Final(PRTSHA224CONTEXT pCtx, uint8_t pabHash[RTSHA224_HASH_SIZE]); + +/** + * Converts a SHA-224 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pabHash The binary digest returned by RTSha224Final or RTSha224. + * @param pszDigest Where to return the stringified digest. + * @param cchDigest The size of the output buffer. Should be at least + * RTSHA224_DIGEST_LEN + 1 bytes. + */ +RTDECL(int) RTSha224ToString(uint8_t const pabHash[RTSHA224_HASH_SIZE], char *pszDigest, size_t cchDigest); + +/** + * Converts a SHA-224 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pszDigest The stringified digest. Leading and trailing spaces are + * ignored. + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(int) RTSha224FromString(char const *pszDigest, uint8_t pabHash[RTSHA224_HASH_SIZE]); + +/** + * Creates a SHA224 digest for the given memory buffer. + * + * @returns iprt status code. + * + * @param pvBuf Memory buffer to create a SHA224 digest for. + * @param cbBuf The amount of data (in bytes). + * @param ppszDigest On success the SHA224 digest. + * @param pfnProgressCallback optional callback for the progress indication + * @param pvUser user defined pointer for the callback + */ +RTR3DECL(int) RTSha224Digest(void* pvBuf, size_t cbBuf, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser); + +/** + * Creates a SHA224 digest for the given file. + * + * @returns iprt status code. + * + * @param pszFile Filename to create a SHA224 digest for. + * @param ppszDigest On success the SHA224 digest. + * @param pfnProgressCallback optional callback for the progress indication + * @param pvUser user defined pointer for the callback + */ +RTR3DECL(int) RTSha224DigestFromFile(const char *pszFile, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser); + + + +/** The size of a SHA-512 hash. */ +#define RTSHA512_HASH_SIZE 64 +/** The length of a SHA-512 digest string. The terminator is not included. */ +#define RTSHA512_DIGEST_LEN 128 + +/** + * SHA-512 context. + */ +typedef union RTSHA512CONTEXT +{ + uint64_t u64BetterAlignment; + uint8_t abPadding[16 + (80 + 8) * 8]; +#ifdef RT_SHA512_PRIVATE_CONTEXT + SHA512_CTX Private; +#endif +#ifdef RT_SHA512_PRIVATE_ALT_CONTEXT + RTSHA512ALTPRIVATECTX AltPrivate; +#endif +} RTSHA512CONTEXT; +/** Pointer to an SHA-512 context. */ +typedef RTSHA512CONTEXT *PRTSHA512CONTEXT; + +/** + * Compute the SHA-512 hash of the data. + * + * @param pvBuf Pointer to the data. + * @param cbBuf The amount of data (in bytes). + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTSha512(const void *pvBuf, size_t cbBuf, uint8_t pabHash[RTSHA512_HASH_SIZE]); + +/** + * Computes the SHA-512 hash for the given data comparing it with the one given. + * + * @returns true on match, false on mismatch. + * @param pvBuf Pointer to the data. + * @param cbBuf The amount of data (in bytes). + * @param pabHash The hash to verify. (What is passed is a pointer to the + * caller's buffer.) + */ +RTDECL(bool) RTSha512Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA512_HASH_SIZE]); + +/** + * Initializes the SHA-512 context. + * + * @param pCtx Pointer to the SHA-512 context. + */ +RTDECL(void) RTSha512Init(PRTSHA512CONTEXT pCtx); + +/** + * Feed data into the SHA-512 computation. + * + * @param pCtx Pointer to the SHA-512 context. + * @param pvBuf Pointer to the data. + * @param cbBuf The length of the data (in bytes). + */ +RTDECL(void) RTSha512Update(PRTSHA512CONTEXT pCtx, const void *pvBuf, size_t cbBuf); + +/** + * Compute the SHA-512 hash of the data. + * + * @param pCtx Pointer to the SHA-512 context. + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(void) RTSha512Final(PRTSHA512CONTEXT pCtx, uint8_t pabHash[RTSHA512_HASH_SIZE]); + +/** + * Converts a SHA-512 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pabHash The binary digest returned by RTSha512Final or RTSha512. + * @param pszDigest Where to return the stringified digest. + * @param cchDigest The size of the output buffer. Should be at least + * RTSHA512_DIGEST_LEN + 1 bytes. + */ +RTDECL(int) RTSha512ToString(uint8_t const pabHash[RTSHA512_HASH_SIZE], char *pszDigest, size_t cchDigest); + +/** + * Converts a SHA-512 hash to a digest string. + * + * @returns IPRT status code. + * + * @param pszDigest The stringified digest. Leading and trailing spaces are + * ignored. + * @param pabHash Where to store the hash. (What is passed is a pointer to + * the caller's buffer.) + */ +RTDECL(int) RTSha512FromString(char const *pszDigest, uint8_t pabHash[RTSHA512_HASH_SIZE]); + + +/** Macro for declaring the interface for a SHA-512 variation. + * @internal */ +#define RTSHA512_DECLARE_VARIANT(a_Name, a_UName) \ + typedef RTSHA512CONTEXT RT_CONCAT3(RTSHA,a_UName,CONTEXT); \ + typedef RTSHA512CONTEXT *RT_CONCAT3(PRTSHA,a_UName,CONTEXT); \ + RTDECL(void) RT_CONCAT(RTSha,a_Name)(const void *pvBuf, size_t cbBuf, uint8_t pabHash[RT_CONCAT3(RTSHA,a_UName,_HASH_SIZE)]); \ + RTDECL(bool) RT_CONCAT3(RTSha,a_Name,Check)(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RT_CONCAT3(RTSHA,a_UName,_HASH_SIZE)]); \ + RTDECL(void) RT_CONCAT3(RTSha,a_Name,Init)(RT_CONCAT3(PRTSHA,a_UName,CONTEXT) pCtx); \ + RTDECL(void) RT_CONCAT3(RTSha,a_Name,Update)(RT_CONCAT3(PRTSHA,a_UName,CONTEXT) pCtx, const void *pvBuf, size_t cbBuf); \ + RTDECL(void) RT_CONCAT3(RTSha,a_Name,Final)(RT_CONCAT3(PRTSHA,a_UName,CONTEXT) pCtx, uint8_t pabHash[RT_CONCAT3(RTSHA,a_UName,_HASH_SIZE)]); \ + RTDECL(int) RT_CONCAT3(RTSha,a_Name,ToString)(uint8_t const pabHash[RT_CONCAT3(RTSHA,a_UName,_HASH_SIZE)], char *pszDigest, size_t cchDigest); \ + RTDECL(int) RT_CONCAT3(RTSha,a_Name,FromString)(char const *pszDigest, uint8_t pabHash[RT_CONCAT3(RTSHA,a_UName,_HASH_SIZE)]) + + +/** The size of a SHA-384 hash. */ +#define RTSHA384_HASH_SIZE 48 +/** The length of a SHA-384 digest string. The terminator is not included. */ +#define RTSHA384_DIGEST_LEN 96 +RTSHA512_DECLARE_VARIANT(384,384); + +/** The size of a SHA-512/224 hash. */ +#define RTSHA512T224_HASH_SIZE 28 +/** The length of a SHA-512/224 digest string. The terminator is not + * included. */ +#define RTSHA512T224_DIGEST_LEN 56 +RTSHA512_DECLARE_VARIANT(512t224,512T224); + +/** The size of a SHA-512/256 hash. */ +#define RTSHA512T256_HASH_SIZE 32 +/** The length of a SHA-512/256 digest string. The terminator is not + * included. */ +#define RTSHA512T256_DIGEST_LEN 64 +RTSHA512_DECLARE_VARIANT(512t256,512T256); + + +/** + * SHA3 context. + */ +typedef union RTSHA3CONTEXT +{ + uint64_t a64Padding[26]; + uint8_t abPadding[208]; +#ifdef RT_SHA3_PRIVATE_CONTEXT + RTSHA3PRIVATECTX Private; +#endif +#ifdef RT_SHA3_PRIVATE_ALT_CONTEXT + RTSHA3ALTPRIVATECTX AltPrivate; +#endif +} RTSHA3CONTEXT; +/** Pointer to an SHA3 context. */ +typedef RTSHA3CONTEXT *PRTSHA3CONTEXT; + +/** Macro for declaring the interface for a SHA3 variation. + * + * @note The interface differes slightly from the older checksums: + * - Must call Final and/or Cleanup method. + * - Must use Clone instead of memcpy'ing the context. + * - Status codes are returned, Init may really fail. + * + * @internal */ +#define RTSHA3_DECLARE_VARIANT(a_Bits) \ + typedef struct RT_CONCAT3(RTSHA3T,a_Bits,CONTEXT) { RTSHA3CONTEXT Sha3; } RT_CONCAT3(RTSHA3T,a_Bits,CONTEXT); \ + typedef RT_CONCAT3(RTSHA3T,a_Bits,CONTEXT) *RT_CONCAT3(PRTSHA3T,a_Bits,CONTEXT); \ + RTDECL(int) RT_CONCAT(RTSha3t,a_Bits)(const void *pvBuf, size_t cbBuf, uint8_t pabHash[RT_CONCAT3(RTSHA3_,a_Bits,_HASH_SIZE)]); \ + RTDECL(bool) RT_CONCAT3(RTSha3t,a_Bits,Check)(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RT_CONCAT3(RTSHA3_,a_Bits,_HASH_SIZE)]); \ + RTDECL(int) RT_CONCAT3(RTSha3t,a_Bits,Init)(RT_CONCAT3(PRTSHA3T,a_Bits,CONTEXT) pCtx); \ + RTDECL(int) RT_CONCAT3(RTSha3t,a_Bits,Update)(RT_CONCAT3(PRTSHA3T,a_Bits,CONTEXT) pCtx, const void *pvBuf, size_t cbBuf); \ + RTDECL(int) RT_CONCAT3(RTSha3t,a_Bits,Final)(RT_CONCAT3(PRTSHA3T,a_Bits,CONTEXT) pCtx, uint8_t pabHash[RT_CONCAT3(RTSHA3_,a_Bits,_HASH_SIZE)]); \ + RTDECL(int) RT_CONCAT3(RTSha3t,a_Bits,Cleanup)(RT_CONCAT3(PRTSHA3T,a_Bits,CONTEXT) pCtx); \ + RTDECL(int) RT_CONCAT3(RTSha3t,a_Bits,Clone)(RT_CONCAT3(PRTSHA3T,a_Bits,CONTEXT) pCtx, RT_CONCAT3(RTSHA3T,a_Bits,CONTEXT) const *pCtxSrc); \ + RTDECL(int) RT_CONCAT3(RTSha3t,a_Bits,ToString)(uint8_t const pabHash[RT_CONCAT3(RTSHA3_,a_Bits,_HASH_SIZE)], char *pszDigest, size_t cchDigest); \ + RTDECL(int) RT_CONCAT3(RTSha3t,a_Bits,FromString)(char const *pszDigest, uint8_t pabHash[RT_CONCAT3(RTSHA3_,a_Bits,_HASH_SIZE)]) + +/** The size of a SHA-224 hash. */ +#define RTSHA3_224_HASH_SIZE 28 +/** The length of a SHA-224 digest string. The terminator is not included. */ +#define RTSHA3_224_DIGEST_LEN 56 +RTSHA3_DECLARE_VARIANT(224); + +/** The size of a SHA-256 hash. */ +#define RTSHA3_256_HASH_SIZE 32 +/** The length of a SHA-256 digest string. The terminator is not included. */ +#define RTSHA3_256_DIGEST_LEN 64 +RTSHA3_DECLARE_VARIANT(256); + +/** The size of a SHA-384 hash. */ +#define RTSHA3_384_HASH_SIZE 48 +/** The length of a SHA-384 digest string. The terminator is not included. */ +#define RTSHA3_384_DIGEST_LEN 96 +RTSHA3_DECLARE_VARIANT(384); + +/** The size of a SHA-512 hash. */ +#define RTSHA3_512_HASH_SIZE 64 +/** The length of a SHA-512 digest string. The terminator is not included. */ +#define RTSHA3_512_DIGEST_LEN 128 +RTSHA3_DECLARE_VARIANT(512); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_sha_h */ + diff --git a/include/iprt/shmem.h b/include/iprt/shmem.h new file mode 100644 index 00000000..7ea65f17 --- /dev/null +++ b/include/iprt/shmem.h @@ -0,0 +1,180 @@ +/** @file + * IPRT - Named shared memory. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_shmem_h +#define IPRT_INCLUDED_shmem_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_shmem RTShMem - Shared memory. + * @ingroup grp_rt + * @{ + */ + +/** @name Open flags for RTShMemOpen(). + * @{ + */ +/** Creates a new shared memory object or opens an already existing one. */ +#define RTSHMEM_O_F_CREATE RT_BIT_32(0) +/** Creates a new shared memory object failing if one with the same name exists already. */ +#define RTSHMEM_O_F_CREATE_EXCL (RTSHMEM_O_F_CREATE | RT_BIT_32(1)) +/** Opens the shared memory object for read access. */ +#define RTSHMEM_O_F_READ RT_BIT_32(2) +/** Opens the shared memory object for write access. */ +#define RTSHMEM_O_F_WRITE RT_BIT_32(3) +/** Opens the shared memory object for read and write access. */ +#define RTSHMEM_O_F_READWRITE (RTSHMEM_O_F_READ | RTSHMEM_O_F_WRITE) +/** Truncates the shared memory object to 0 bytes on open. */ +#define RTSHMEM_O_F_TRUNCATE RT_BIT_32(4) +/** Mappings may be created with executable access right (required to be known on Windows beforehand). */ +#define RTSHMEM_O_F_MAYBE_EXEC RT_BIT_32(5) +/** Mask of all valid flags. */ +#define RTSHMEM_O_F_VALID_MASK UINT32_C(0x0000003f) +/** @} */ + +/** + * Creates or opens a new shared memory object with the given name. + * + * @returns IPRT status code. + * @retval VERR_OUT_OF_RANGE if the mapping hint count is too big. + * @param phShMem Where to store the handle to the shared memory object on success. + * @param pszName Name of the shared memory object to open or create. + * @param fFlags Combination of RTSHMEM_O_F_* flags. + * @param cbMax Maximum number of bytes to reserve for the shared memory object. + * On some platforms this can be 0 and set to another value using RTShMemSetSize() afterwards. + * Giving 0 on Windows results in an error as shared memory objects there do not support + * changing the size afterwards. + * @param cMappingsHint Hint about the possible number of mappings created later on, set to 0 for a default value. + */ +RTDECL(int) RTShMemOpen(PRTSHMEM phShMem, const char *pszName, uint32_t fFlags, size_t cbMax, uint32_t cMappingsHint); + +/** + * Closes the given shared memory object. + * + * @returns IPRT status code. + * @retval VERR_INVALID_STATE if there is still a mapping active for the given shared memory object. + * @param hShMem The shared memory object handle. + * + * @note The shared memory object will be deleted if the creator closes it. + */ +RTDECL(int) RTShMemClose(RTSHMEM hShMem); + +/** + * Tries to delete a shared memory object with the given name. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the platform does not support deleting the shared memory object by name. + * @param pszName Name of the shared memory object to delete. + */ +RTDECL(int) RTShMemDelete(const char *pszName); + +/** + * Returns the number of references (i.e. mappings) held for the given shared memory object. + * + * @returns Reference count or 0 on invalid handle. + * @param hShMem The shared memory object handle. + */ +RTDECL(uint32_t) RTShMemRefCount(RTSHMEM hShMem); + +/** + * Sets the size of the given shared memory object. + * + * @returns IPRT status code. + * @retval VERR_INVALID_STATE if there are mappings active for the given shared memory object. + * @retval VERR_NOT_SUPPORTED on some hosts which do not support changing the size after creation. + * @param hShMem The shared memory object handle. + * @param cbMem Size of the memory object handle in bytes. + */ +RTDECL(int) RTShMemSetSize(RTSHMEM hShMem, size_t cbMem); + +/** + * Queries the current size of the shared memory object. + * + * @returns IPRT status code. + * @param hShMem The shared memory object handle. + * @param pcbMem Where to store the size of the shared memory object on success. + */ +RTDECL(int) RTShMemQuerySize(RTSHMEM hShMem, size_t *pcbMem); + +/** @name Region mapping flags for RTShMemMapRegion(). + * @{ + */ +/** Read access. */ +#define RTSHMEM_MAP_F_READ RT_BIT_32(0) +/** Write access. */ +#define RTSHMEM_MAP_F_WRITE RT_BIT_32(1) +/** Execute access. */ +#define RTSHMEM_MAP_F_EXEC RT_BIT_32(2) +/** Copy on write, any write creates a new page private to the callers address space and changes + * in that area are not shared with other processes using the hsared memory object. */ +#define RTSHMEM_MAP_F_COW RT_BIT_32(3) +/** Mask of all valid flags. */ +#define RTSHMEM_MAP_F_VALID_MASK UINT32_C(0x0000000f) +/** @} */ + +/** + * Maps a region of the given shared memory object into the callers address space. + * + * @returns IPRT status code. + * @retval VERR_SHMEM_MAXIMUM_MAPPINGS_REACHED if the maximum number of mappings was reached (host dependent). + * @retval VERR_ACCESS_DENIED if the requested memory access rights do not line up with the flags given when opening + * the memory object (requesting write access for a readonly shared memory object for example). + * @param hShMem The shared memory object handle. + * @param offRegion Offset into the shared memory object to start mapping at. + * @param cbRegion Size of the region to map. + * @param fFlags Desired properties of the mapped region, combination of RTSHMEM_MAP_F_* defines. + * @param ppv Where to store the start address of the mapped region on success. + */ +RTDECL(int) RTShMemMapRegion(RTSHMEM hShMem, size_t offRegion, size_t cbRegion, uint32_t fFlags, void **ppv); + +/** + * Unmaps the given region of the shared memory object. + * + * @returns IPRT status code. + * @param hShMem The shared memory object handle. + * @param pv Pointer to the mapped region obtained with RTShMemMapRegion() earlier on. + */ +RTDECL(int) RTShMemUnmapRegion(RTSHMEM hShMem, void *pv); + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_shmem_h */ + diff --git a/include/iprt/socket.h b/include/iprt/socket.h new file mode 100644 index 00000000..c7a572e7 --- /dev/null +++ b/include/iprt/socket.h @@ -0,0 +1,430 @@ +/** @file + * IPRT - Network Sockets. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_socket_h +#define IPRT_INCLUDED_socket_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/thread.h> +#include <iprt/net.h> +#include <iprt/sg.h> + +#ifdef IN_RING0 +# error "There are no RTSocket APIs available Ring-0 Host Context!" +#endif + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_socket RTSocket - Network Sockets + * @ingroup grp_rt + * @{ + */ + +/** Use the system default timeout for the connet attempt. */ +#define RT_SOCKETCONNECT_DEFAULT_WAIT (RT_INDEFINITE_WAIT - 1) + +/** + * Retains a reference to the socket handle. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hSocket The socket handle. + */ +RTDECL(uint32_t) RTSocketRetain(RTSOCKET hSocket); + +/** + * Release a reference to the socket handle. + * + * When the reference count reaches zero, the socket handle is shut down and + * destroyed. This will not be graceful shutdown, use the protocol specific + * close method if this is desired. + * + * @returns New reference count, UINT32_MAX on invalid handle (asserted). + * + * @param hSocket The socket handle. The NIL handle is quietly + * ignored and 0 is returned. + */ +RTDECL(uint32_t) RTSocketRelease(RTSOCKET hSocket); + +/** + * Shuts down the socket, close it and then release one handle reference. + * + * This is slightly different from RTSocketRelease which will first do the + * shutting down and closing when the reference count reaches zero. + * + * @returns IPRT status code. + * @param hSocket The socket handle. NIL is ignored. + * + * @remarks This will not perform a graceful shutdown of the socket, it will + * just destroy it. Use the protocol specific close method if this is + * desired. + */ +RTDECL(int) RTSocketClose(RTSOCKET hSocket); + +/** + * Creates an IPRT socket handle from a native one. + * + * Do NOT use the native handle after passing it to this function, IPRT owns it + * and might even have closed upon a successful return. + * + * @returns IPRT status code. + * @param phSocket Where to store the IPRT socket handle. + * @param uNative The native handle. + */ +RTDECL(int) RTSocketFromNative(PRTSOCKET phSocket, RTHCINTPTR uNative); + +/** + * Gets the native socket handle. + * + * @returns The native socket handle or RTHCUINTPTR_MAX if not invalid. + * @param hSocket The socket handle. + */ +RTDECL(RTHCUINTPTR) RTSocketToNative(RTSOCKET hSocket); + +/** + * Helper that ensures the correct inheritability of a socket. + * + * We're currently ignoring failures. + * + * @returns IPRT status code + * @param hSocket The socket handle. + * @param fInheritable The desired inheritability state. + */ +RTDECL(int) RTSocketSetInheritance(RTSOCKET hSocket, bool fInheritable); + +/** + * Parse Internet style addresses, getting a generic IPRT network address. + * + * @returns IPRT status code + * @param pszAddress Name or IP address. NULL or empty string (no + * spaces) is taken to mean INADDR_ANY, which is + * meaningful when binding a server socket for + * instance. + * @param uPort Port number (host byte order). + * @param pAddr Where to return the generic IPRT network address. + */ +RTDECL(int) RTSocketParseInetAddress(const char *pszAddress, unsigned uPort, PRTNETADDR pAddr); + +/** + * Try resolve a host name, returning the first matching address. + * + * @returns IPRT status code. + * @param pszHost Name or IP address to look up. + * @param pszAddress Where to return the stringified address. + * @param pcbAddress Input: The size of the @a pszResult buffer. + * Output: size of the returned string. This is set on + * VERR_BUFFER_OVERFLOW and most other error statuses. + * @param penmAddrType Input: Which kind of address to return. Valid values + * are: + * - RTNETADDRTYPE_IPV4 -> lookup AF_INET. + * - RTNETADDRTYPE_IPV6 -> lookup AF_INET6. + * - RTNETADDRTYPE_INVALID/NULL -> lookup anything. + * Output: The type of address that is being returned. + * Not modified on failure. + */ +RTDECL(int) RTSocketQueryAddressStr(const char *pszHost, char *pszAddress, size_t *pcbAddress, PRTNETADDRTYPE penmAddrType); + +/** + * Receive data from a socket. + * + * @returns IPRT status code. + * @param hSocket The socket handle. + * @param pvBuffer Where to put the data we read. + * @param cbBuffer Read buffer size. + * @param pcbRead Number of bytes read. If NULL the entire buffer + * will be filled upon successful return. If not NULL a + * partial read can be done successfully. + */ +RTDECL(int) RTSocketRead(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead); + +/** + * Receive data from a socket, including sender address. Mainly useful + * for datagram sockets. + * + * @returns IPRT status code. + * @param hSocket The socket handle. + * @param pvBuffer Where to put the data we read. + * @param cbBuffer Read buffer size. + * @param pcbRead Number of bytes read. Must be non-NULL. + * @param pSrcAddr Pointer to sender address buffer. May be NULL. + */ +RTDECL(int) RTSocketReadFrom(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead, PRTNETADDR pSrcAddr); + +/** + * Send data to a socket. + * + * @returns IPRT status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket The socket handle. + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + */ +RTDECL(int) RTSocketWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer); + +/** + * Send data to a socket, including destination address. Mainly useful + * for datagram sockets. + * + * @returns IPRT status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket The socket handle. + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + * @param pDstAddr Pointer to destination address. May be NULL. + */ +RTDECL(int) RTSocketWriteTo(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer, PCRTNETADDR pDstAddr); + +/** + * Checks if the socket is ready for reading (for I/O multiplexing). + * + * @returns IPRT status code. + * @param hSocket The socket handle. + * @param cMillies Number of milliseconds to wait for the socket. Use + * RT_INDEFINITE_WAIT to wait for ever. + */ +RTDECL(int) RTSocketSelectOne(RTSOCKET hSocket, RTMSINTERVAL cMillies); + +/** @name Select events + * @{ */ +/** Readable without blocking. */ +#define RTSOCKET_EVT_READ RT_BIT_32(0) +/** Writable without blocking. */ +#define RTSOCKET_EVT_WRITE RT_BIT_32(1) +/** Error condition, hangup, exception or similar. */ +#define RTSOCKET_EVT_ERROR RT_BIT_32(2) +/** Mask of the valid bits. */ +#define RTSOCKET_EVT_VALID_MASK UINT32_C(0x00000007) +/** @} */ + +/** + * Socket I/O multiplexing + * Checks if the socket is ready for one of the given events. + * + * @returns iprt status code. + * @param hSocket The Socket handle. + * @param fEvents Event mask to wait for. + * @param pfEvents Where to store the event mask on return. + * @param cMillies Number of milliseconds to wait for the socket. Use + * RT_INDEFINITE_WAIT to wait for ever. + */ +RTR3DECL(int) RTSocketSelectOneEx(RTSOCKET hSocket, uint32_t fEvents, uint32_t *pfEvents, RTMSINTERVAL cMillies); + +/** + * Shuts down one or both directions of communciation. + * + * @returns IPRT status code. + * @param hSocket The socket handle. + * @param fRead Whether to shutdown our read direction. + * @param fWrite Whether to shutdown our write direction. + */ +RTDECL(int) RTSocketShutdown(RTSOCKET hSocket, bool fRead, bool fWrite); + +/** + * Gets the address of the local side. + * + * @returns IPRT status code. + * @param hSocket The Socket handle. + * @param pAddr Where to store the local address on success. + */ +RTDECL(int) RTSocketGetLocalAddress(RTSOCKET hSocket, PRTNETADDR pAddr); + +/** + * Gets the address of the other party. + * + * @returns IPRT status code. + * @param hSocket The Socket handle. + * @param pAddr Where to store the peer address on success. + */ +RTDECL(int) RTSocketGetPeerAddress(RTSOCKET hSocket, PRTNETADDR pAddr); + +/** + * Send data from a scatter/gather buffer to a socket. + * + * @returns IPRT status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket The socket handle. + * @param pSgBuf Scatter/gather buffer to write data to socket. + */ +RTDECL(int) RTSocketSgWrite(RTSOCKET hSocket, PCRTSGBUF pSgBuf); + +/** + * Send data from multiple buffers to a socket. + * + * This is convenience wrapper around the RTSocketSgWrite and RTSgBufInit calls + * for lazy coders. The "L" in the function name is short for "list" just like + * in the execl libc API. + * + * @returns IPRT status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket The socket handle. + * @param cSegs The number of data segments in the following + * ellipsis. + * @param ... Pairs of buffer pointers (void const *) and buffer + * sizes (size_t). Make 101% sure the pointer is + * really size_t. + */ +RTDECL(int) RTSocketSgWriteL(RTSOCKET hSocket, size_t cSegs, ...); + +/** + * Send data from multiple buffers to a socket. + * + * This is convenience wrapper around the RTSocketSgWrite and RTSgBufInit calls + * for lazy coders. The "L" in the function name is short for "list" just like + * in the execl libc API. + * + * @returns IPRT status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket The socket handle. + * @param cSegs The number of data segments in the following + * argument list. + * @param va Pairs of buffer pointers (void const *) and buffer + * sizes (size_t). Make 101% sure the pointer is + * really size_t. + */ +RTDECL(int) RTSocketSgWriteLV(RTSOCKET hSocket, size_t cSegs, va_list va); + +/** + * Receive data from a socket. + * + * This version doesn't block if there is no data on the socket. + * + * @returns IPRT status code. + * + * @param hSocket The socket handle. + * @param pvBuffer Where to put the data we read. + * @param cbBuffer Read buffer size. + * @param pcbRead Number of bytes read. + */ +RTDECL(int) RTSocketReadNB(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead); + +/** + * Send data to a socket. + * + * This version doesn't block if there is not enough room for the message. + * + * @returns IPRT status code. + * + * @param hSocket The socket handle. + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + * @param pcbWritten Number of bytes written. + */ +RTDECL(int) RTSocketWriteNB(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer, size_t *pcbWritten); + +/** + * Send data to a socket, including destination address. Mainly useful + * for datagram sockets. + * + * This version doesn't block if there is not enough room for the message. + * + * @returns IPRT status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket The socket handle. + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + * @param pDstAddr Pointer to destination address. May be NULL. + */ +RTDECL(int) RTSocketWriteToNB(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer, PCRTNETADDR pDstAddr); + +/** + * Send data from a scatter/gather buffer to a socket. + * + * This version doesn't block if there is not enough room for the message. + * + * @returns iprt status code. + * + * @param hSocket The Socket handle. + * @param pSgBuf Scatter/gather buffer to write data to socket. + * @param pcbWritten Number of bytes written. + */ +RTR3DECL(int) RTSocketSgWriteNB(RTSOCKET hSocket, PCRTSGBUF pSgBuf, size_t *pcbWritten); + + +/** + * Send data from multiple buffers to a socket. + * + * This version doesn't block if there is not enough room for the message. + * This is convenience wrapper around the RTSocketSgWrite and RTSgBufInit calls + * for lazy coders. The "L" in the function name is short for "list" just like + * in the execl libc API. + * + * @returns IPRT status code. + * + * @param hSocket The socket handle. + * @param cSegs The number of data segments in the following + * ellipsis. + * @param pcbWritten Number of bytes written. + * @param ... Pairs of buffer pointers (void const *) and buffer + * sizes (size_t). Make 101% sure the pointer is + * really size_t. + */ +RTR3DECL(int) RTSocketSgWriteLNB(RTSOCKET hSocket, size_t cSegs, size_t *pcbWritten, ...); + +/** + * Send data from multiple buffers to a socket. + * + * This version doesn't block if there is not enough room for the message. + * This is convenience wrapper around the RTSocketSgWrite and RTSgBufInit calls + * for lazy coders. The "L" in the function name is short for "list" just like + * in the execl libc API. + * + * @returns IPRT status code. + * + * @param hSocket The socket handle. + * @param cSegs The number of data segments in the following + * argument list. + * @param pcbWritten Number of bytes written. + * @param va Pairs of buffer pointers (void const *) and buffer + * sizes (size_t). Make 101% sure the pointer is + * really size_t. + */ +RTR3DECL(int) RTSocketSgWriteLVNB(RTSOCKET hSocket, size_t cSegs, size_t *pcbWritten, va_list va); + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_socket_h */ + diff --git a/include/iprt/solaris/kmoddeps.mac b/include/iprt/solaris/kmoddeps.mac new file mode 100644 index 00000000..c9ec53e0 --- /dev/null +++ b/include/iprt/solaris/kmoddeps.mac @@ -0,0 +1,193 @@ +; $Id: kmoddeps.mac $ +;; @file +; Assembly macros for generating Solaris kernel module dependencies +; + +; +; Copyright (C) 2012-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +; Solaris kernel modules use non-standard ELF constructions to express inter- +; module dependencies, namely a DT_NEEDED tag inside a relocatable ELF file. +; The Solaris linker can generate these automatically; since yasm can't +; produce an ELF file which quite fits Solaris's requirements we create one +; manually using flat binary output format. In order to save unnecessary +; repetition, this file defines macros for the repetitive bits which can be +; reused by the actual dependency objects. Certainly not the nicest way to +; get the effect we want, but probably a reasonable compromise between +; cleanness and required effort. +; + +%ifdef RT_ARCH_AMD64 + +BITS 64 +;; +; Native word size +%define DNAT dq + +;; +; ELF machine number for the current architecture. +%define EM_CUR 62 ; EM_X86_64 + +;; +; ELF header class for the current architecture. +%define CLASS 2 + +%else + +BITS 32 +%define DNAT dd +%define EM_CUR 3 ; EM_386 +%define CLASS 1 + +%endif + +;; +; ELF file header, section tables and shared string table for the dependency +; object. +%macro kmoddeps_header 0 +elf_hdr: ; elfxx_hdr structure + db 7fh, "ELF" ; e_ident + db CLASS, 1, 1 ; e_ident + times 9 db 0 ; padding + dw 1 ; e_type ET_REL + dw EM_CUR ; e_machine + dd 1 ; e_version EV_CURRENT + DNAT 0 ; e_entry + DNAT 0 ; e_phoff + DNAT sect_hdr - $$ ; e_shoff + dd 0 ; e_flags + dw elf_hsize ; e_ehsize + dw 0 ; e_phentsize + dw 0 ; e_phnum + dw sect_hsize ; e_shentsize + dw 4 ; e_shnum + dw 1 ; e_shstrndx section .shstrtab +elf_hsize equ $ - elf_hdr + +sect_hdr: ; elfxx_shdr structure + times sect_hsize db 0 ; undefined section + +sect_hdr1: + dd str_shstrtab ; sh_name .shstrtab + dd 3 ; sh_type SHT_STRTAB + DNAT 20h ; sh_flags SHF_STRINGS + DNAT 0 ; sh_addr + DNAT shstrtab - $$ ; sh_offset + DNAT shstrtab_size ; sh_size + dd 0 ; sh_link + dd 0 ; sh_info + DNAT 1 ; sh_addralign + DNAT 0 ; sh_entsize +sect_hsize equ $ - sect_hdr1 + + dd str_dynstr ; sh_name .dynstr + dd 3 ; sh_type SHT_STRTAB + DNAT 20h ; sh_flags SHF_STRINGS + DNAT 0 ; sh_addr + DNAT dynstr - $$ ; sh_offset + DNAT dynstr_size ; sh_size + dd 0 ; sh_link + dd 0 ; sh_info + DNAT 1 ; sh_addralign + DNAT 0 ; sh_entsize + + dd str_dynamic ; sh_name .dynamic + dd 6 ; sh_type SHT_DYNAMIC + DNAT 1 ; sh_flags SHF_WRITE + DNAT 0 ; sh_addr + DNAT dynamic - $$ ; sh_offset + DNAT dynamic_size ; sh_size + dd 2 ; sh_link .dynstr + dd 0 ; sh_info + DNAT 8 ; sh_addralign + DNAT 0 ; sh_entsize + +shstrtab: +str_shstrtab equ $ - shstrtab + db ".shstrtab", 0 +str_dynstr equ $ - shstrtab + db ".dynstr", 0 +str_dynamic equ $ - shstrtab + db ".dynamic", 0 +shstrtab_size equ $ - shstrtab +%endmacro ; kmoddeps_header + +;; +; Start of the .dynstr section for the dependency object. +%macro kmoddeps_dynstr_start 0 +dynstr: + db 0 +%endmacro + +;; +; A .dynstr string entry for the dependency object. +; The parameters are a symbolic name for the string and the string itself. +%macro kmoddeps_dynstr_string 2 +dynstr_name_%1 equ $ - dynstr + db %2, 0 +%endmacro + +;; +; End of the .dynstr section for the dependency object. +%macro kmoddeps_dynstr_end 0 +dynstr_size equ $ - dynstr +%endmacro + +;; +; Start of the .dynamic section for the dependency object. +%macro kmoddeps_dynamic_start 0 +dynamic: +%endmacro + +;; +; A .dynamic DT_NEEDED entry for the dependency object. +; The parameter is a symbolic string name previously defined using +; @a kmoddeps_dynstr_string. +%macro kmoddeps_dynamic_needed 1 + DNAT 1 ; DT_NEEDED + DNAT dynstr_name_%1 +%endmacro + +;; +; End of the .dynamic section for the dependency object. +%macro kmoddeps_dynamic_end 0 + DNAT 1ah ; DT_FLAGS + DNAT 4 ; TEXTREL + DNAT 6ffffffbh ; DT_FLAGS1 + DNAT 0 + DNAT 601900h ; SUNW_STRPAD + DNAT 200h + DNAT 601b00h ; SUNW_LDMACH + DNAT 62 ; EM_X86_64 + times 22 DNAT 0 ; padding +dynamic_size equ $ - dynamic +%endmacro ; kmoddeps_dynamic_end + diff --git a/include/iprt/sort.h b/include/iprt/sort.h new file mode 100644 index 00000000..4e5d47de --- /dev/null +++ b/include/iprt/sort.h @@ -0,0 +1,141 @@ +/** @file + * IPRT - Sorting. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_sort_h +#define IPRT_INCLUDED_sort_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/** @defgroup grp_rt_sort RTSort - Sorting Algorithms + * @ingroup grp_rt + * @{ */ + +RT_C_DECLS_BEGIN + +/** + * Callback for comparing two array elements. + * + * @retval 0 if equal. + * @retval -1 if @a pvElement1 comes before @a pvElement2. + * @retval 1 if @a pvElement1 comes after @a pvElement2. + * + * @param pvElement1 The 1st element. + * @param pvElement2 The 2nd element. + * @param pvUser The user argument passed to the sorting function. + */ +typedef DECLCALLBACKTYPE(int, FNRTSORTCMP,(void const *pvElement1, void const *pvElement2, void *pvUser)); +/** Pointer to a compare function. */ +typedef FNRTSORTCMP *PFNRTSORTCMP; + +/** + * Sorter function for an array of variable sized elementes. + * + * @param pvArray The array to sort. + * @param cElements The number of elements in the array. + * @param cbElement The size of an array element. + * @param pfnCmp Callback function comparing two elements. + * @param pvUser User argument for the callback. + */ +typedef DECLCALLBACKTYPE(void, FNRTSORT,(void *pvArray, size_t cElements, size_t cbElement, PFNRTSORTCMP pfnCmp, void *pvUser)); +/** Pointer to a sorter function for an array of variable sized elements. */ +typedef FNRTSORT *PFNRTSORT; + +/** + * Pointer array sorter function. + * + * @param papvArray The array to sort. + * @param cElements The number of elements in the array. + * @param pfnCmp Callback function comparing two elements. + * @param pvUser User argument for the callback. + */ +typedef DECLCALLBACKTYPE(void, FNRTSORTAPV,(void **papvArray, size_t cElements, PFNRTSORTCMP pfnCmp, void *pvUser)); +/** Pointer to a pointer array sorter function. */ +typedef FNRTSORTAPV *PFNRTSORTAPV; + +/** + * Shell sort an array of variable sized elementes. + * + * @param pvArray The array to sort. + * @param cElements The number of elements in the array. + * @param cbElement The size of an array element. + * @param pfnCmp Callback function comparing two elements. + * @param pvUser User argument for the callback. + */ +RTDECL(void) RTSortShell(void *pvArray, size_t cElements, size_t cbElement, PFNRTSORTCMP pfnCmp, void *pvUser); + +/** + * Same as RTSortShell but speciallized for an array containing element + * pointers. + * + * @param papvArray The array to sort. + * @param cElements The number of elements in the array. + * @param pfnCmp Callback function comparing two elements. + * @param pvUser User argument for the callback. + */ +RTDECL(void) RTSortApvShell(void **papvArray, size_t cElements, PFNRTSORTCMP pfnCmp, void *pvUser); + +/** + * Checks if an array of variable sized elementes is sorted. + * + * @returns true if it is sorted, false if it isn't. + * @param pvArray The array to check. + * @param cElements The number of elements in the array. + * @param cbElement The size of an array element. + * @param pfnCmp Callback function comparing two elements. + * @param pvUser User argument for the callback. + */ +RTDECL(bool) RTSortIsSorted(void const *pvArray, size_t cElements, size_t cbElement, PFNRTSORTCMP pfnCmp, void *pvUser); + +/** + * Same as RTSortShell but speciallized for an array containing element + * pointers. + * + * @returns true if it is sorted, false if it isn't. + * @param papvArray The array to check. + * @param cElements The number of elements in the array. + * @param pfnCmp Callback function comparing two elements. + * @param pvUser User argument for the callback. + */ +RTDECL(bool) RTSortApvIsSorted(void const * const *papvArray, size_t cElements, PFNRTSORTCMP pfnCmp, void *pvUser); + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_sort_h */ + diff --git a/include/iprt/spinlock.h b/include/iprt/spinlock.h new file mode 100644 index 00000000..683be325 --- /dev/null +++ b/include/iprt/spinlock.h @@ -0,0 +1,105 @@ +/** @file + * IPRT - Spinlocks. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_spinlock_h +#define IPRT_INCLUDED_spinlock_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_rt_spinlock RTSpinlock - Spinlocks + * @ingroup grp_rt + * @{ + */ + +/** + * Creates a spinlock. + * + * @returns iprt status code. + * @param pSpinlock Where to store the spinlock handle. + * @param fFlags Creation flags, see RTSPINLOCK_FLAGS_XXX. + * @param pszName Spinlock name, for debugging purposes. String lifetime + * must be the same as the lock as it won't be copied. + */ +RTDECL(int) RTSpinlockCreate(PRTSPINLOCK pSpinlock, uint32_t fFlags, const char *pszName); + +/** @name RTSPINLOCK_FLAGS_XXX + * @{ */ +/** Disable interrupts when taking the spinlock, making it interrupt safe + * (sans NMI of course). + * + * This is generally the safest option, though it isn't really required unless + * the data being protect is also accessed from interrupt handler context. */ +#define RTSPINLOCK_FLAGS_INTERRUPT_SAFE RT_BIT(1) +/** No need to disable interrupts, the protect code/data is not used by + * interrupt handlers. */ +#define RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE RT_BIT(2) +/** @} */ + +/** + * Destroys a spinlock created by RTSpinlockCreate(). + * + * @returns iprt status code. + * @param Spinlock Spinlock returned by RTSpinlockCreate(). + */ +RTDECL(int) RTSpinlockDestroy(RTSPINLOCK Spinlock); + +/** + * Acquires the spinlock. + * + * @param Spinlock The spinlock to acquire. + */ +RTDECL(void) RTSpinlockAcquire(RTSPINLOCK Spinlock); + +/** + * Releases the spinlock. + * + * @param Spinlock The spinlock to acquire. + */ +RTDECL(void) RTSpinlockRelease(RTSPINLOCK Spinlock); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_spinlock_h */ + diff --git a/include/iprt/stdarg.h b/include/iprt/stdarg.h new file mode 100644 index 00000000..9d12cd8b --- /dev/null +++ b/include/iprt/stdarg.h @@ -0,0 +1,79 @@ +/** @file + * IPRT - stdarg.h wrapper. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_stdarg_h +#define IPRT_INCLUDED_stdarg_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef IPRT_NO_CRT +# include <iprt/types.h> +# include <iprt/nocrt/compiler/compiler.h> +#else +# include <iprt/cdefs.h> +# if defined(RT_OS_FREEBSD) && defined(_KERNEL) +# include <machine/stdarg.h> +# elif defined(RT_OS_NETBSD) && defined(_KERNEL) +# include <sys/stdarg.h> +# elif defined(RT_OS_SOLARIS) && defined(_KERNEL) && defined(__GNUC__) +# include <stdarg.h> +# if __GNUC__ >= 4 /* System headers refers to __builtin_stdarg_start. */ +# define __builtin_stdarg_start __builtin_va_start +# endif +# elif defined(RT_OS_LINUX) && defined(IN_RING0) +# include "linux/version.h" +# if RTLNX_VER_MIN(5,15,0) || RTLNX_RHEL_MAJ_PREREQ(9,1) +# include <linux/stdarg.h> +# else +# include <stdarg.h> +# endif +# else +# include <stdarg.h> +# endif +#endif + +/* + * Older MSC versions doesn't implement va_copy. Newer (12.0+?) ones does + * implement it like below, but for now it's easier to continue like for the + * older ones so we can more easily handle R0, RC and other weird contexts. + */ +#if !defined(va_copy) || defined(_MSC_VER) +# undef va_copy +# define va_copy(dst, src) do { (dst) = (src); } while (0) /** @todo check AMD64 */ +#endif + +#endif /* !IPRT_INCLUDED_stdarg_h */ + diff --git a/include/iprt/stdint.h b/include/iprt/stdint.h new file mode 100644 index 00000000..c76e5c6f --- /dev/null +++ b/include/iprt/stdint.h @@ -0,0 +1,349 @@ +/** @file + * IPRT - stdint.h wrapper (for backlevel compilers like MSC). + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_stdint_h +#define IPRT_INCLUDED_stdint_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> + + +/* + * Use the stdint.h on systems that have one. + */ +#if !(defined(RT_OS_LINUX) && defined(__KERNEL__)) \ + && !(defined(RT_OS_FREEBSD) && defined(_KERNEL)) \ + && !(defined(RT_OS_NETBSD) && defined(_KERNEL)) \ + && RT_MSC_PREREQ_EX(RT_MSC_VER_VS2010, 1 /*non-msc*/) \ + && !defined(__IBMC__) \ + && !defined(__IBMCPP__) \ + && !defined(IPRT_NO_CRT) \ + && !defined(IPRT_DONT_USE_SYSTEM_STDINT_H) \ + && !defined(DOXYGEN_RUNNING) + +# ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +# endif +# ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +# endif +# ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) +# endif +# include <stdint.h> +# ifdef _MSC_VER +# pragma warning(pop) +# endif + +# if defined(RT_OS_DARWIN) && defined(KERNEL) && defined(RT_ARCH_AMD64) + /* + * Kludge to fix the incorrect 32-bit constant macros in + * Kernel.framework/Headers/stdin.h. uint32_t and int32_t are + * int not long as these macros use, which is significant when + * targeting AMD64. (10a222) + */ +# undef INT32_C +# define INT32_C(Value) (Value) +# undef UINT32_C +# define UINT32_C(Value) (Value ## U) +# endif /* 64-bit darwin kludge. */ + +#elif defined(RT_OS_FREEBSD) && defined(_KERNEL) + +# ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +# endif +# ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +# endif +# include <sys/stdint.h> + +#elif defined(RT_OS_NETBSD) && defined(_KERNEL) + +# ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +# endif +# ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +# endif +# include <sys/stdint.h> + +#else /* No system stdint.h */ + +/* + * Define the types we use. + * The linux kernel defines all these in linux/types.h, so skip it. + */ +# if !(defined(RT_OS_LINUX) && defined(__KERNEL__)) \ + || defined(IPRT_NO_CRT) \ + || defined(IPRT_DONT_USE_SYSTEM_STDINT_H) \ + || defined(DOXGEN_RUNNING) + + /* Simplify the [u]int64_t type detection mess. */ +# undef IPRT_STDINT_USE_STRUCT_FOR_64_BIT_TYPES +# ifdef __IBMCPP__ +# if __IBMCPP__ < 350 && (defined(__WINDOWS__) || defined(_AIX) || defined(__OS2__)) +# define IPRT_STDINT_USE_STRUCT_FOR_64_BIT_TYPES +# endif +# endif +# ifdef __IBMC__ +# if __IBMC__ < 350 && (defined(__WINDOWS__) || defined(_AIX) || defined(__OS2__)) +# define IPRT_STDINT_USE_STRUCT_FOR_64_BIT_TYPES +# endif +# endif + + /* x-bit types */ +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) \ + || defined(RT_ARCH_ARM32) || defined(RT_ARCH_ARM64) \ + || defined(RT_ARCH_SPARC) || defined(RT_ARCH_SPARC64) +# if !defined(_INT8_T_DECLARED) && !defined(_INT8_T) +typedef signed char int8_t; +# endif +# if !defined(_UINT8_T_DECLARED) && !defined(_UINT8_T) +typedef unsigned char uint8_t; +# endif +# if !defined(_INT16_T_DECLARED) && !defined(_INT16_T) +typedef signed short int16_t; +# endif +# if !defined(_UINT16_T_DECLARED) && !defined(_UINT16_T) +typedef unsigned short uint16_t; +# endif +# if !defined(_INT32_T_DECLARED) && !defined(_INT32_T) +# if ARCH_BITS != 16 +typedef signed int int32_t; +# else +typedef signed long int32_t; +# endif +# endif +# if !defined(_UINT32_T_DECLARED) && !defined(_UINT32_T) +# if ARCH_BITS != 16 +typedef unsigned int uint32_t; +# else +typedef unsigned long uint32_t; +# endif +# endif +# if defined(_MSC_VER) +# if !defined(_INT64_T_DECLARED) && !defined(_INT64_T) +typedef signed _int64 int64_t; +# endif +# if !defined(_UINT64_T_DECLARED) && !defined(_UINT64_T) +typedef unsigned _int64 uint64_t; +# endif +# elif defined(__WATCOMC__) +# if !defined(_INT64_T_DECLARED) && !defined(_INT64_T) +typedef signed __int64 int64_t; +# endif +# if !defined(_UINT64_T_DECLARED) && !defined(_UINT64_T) +typedef unsigned __int64 uint64_t; +# endif +# elif defined(IPRT_STDINT_USE_STRUCT_FOR_64_BIT_TYPES) +# if !defined(_INT64_T_DECLARED) && !defined(_INT64_T) +typedef struct { uint32_t lo; int32_t hi; } int64_t; +# endif +# if !defined(_UINT64_T_DECLARED) && !defined(_UINT64_T) +typedef struct { uint32_t lo; uint32_t hi; } uint64_t; +# endif +# else /* Use long long for 64-bit types */ +# if !defined(_INT64_T_DECLARED) && !defined(_INT64_T) +typedef signed long long int64_t; +# endif +# if !defined(_UINT64_T_DECLARED) && !defined(_UINT64_T) +typedef unsigned long long uint64_t; +# endif +# endif + + /* max integer types */ +# if !defined(_INTMAX_T_DECLARED) && !defined(_INTMAX_T) +typedef int64_t intmax_t; +# endif +# if !defined(_UINTMAX_T_DECLARED) && !defined(_UINTMAX_T) +typedef uint64_t uintmax_t; +# endif + + /* smallest minimum-width integer types - assumes to be the same as above! */ +typedef int8_t int_least8_t; +typedef uint8_t uint_least8_t; +# define INT_LEAST8_MIN INT8_MIN +# define INT_LEAST8_MAX INT8_MAX +# define UINT_LEAST8_MAX UINT8_MAX +typedef int16_t int_least16_t; +typedef uint16_t uint_least16_t; +# define INT_LEAST16_MIN INT16_MIN +# define INT_LEAST16_MAX INT16_MAX +# define UINT_LEAST16_MAX UINT16_MAX +typedef int32_t int_least32_t; +typedef uint32_t uint_least32_t; +# define INT_LEAST32_MIN INT32_MIN +# define INT_LEAST32_MAX INT32_MAX +# define UINT_LEAST32_MAX UINT32_MAX +typedef int64_t int_least64_t; +typedef uint64_t uint_least64_t; +# define INT_LEAST64_MIN INT64_MIN +# define INT_LEAST64_MAX INT64_MAX +# define UINT_LEAST64_MAX UINT64_MAX + + /* fastest minimum-width integer types */ +typedef signed char int_fast8_t; +typedef unsigned char uint_fast8_t; +# define INT_FAST8_MIN INT8_MIN +# define INT_FAST8_MAX INT8_MAX +# define UINT_FAST8_MAX UINT8_MAX +typedef signed int int_fast16_t; +typedef unsigned int uint_fast16_t; +# if ARCH_BITS == 16 +# define INT_FAST16_MIN INT16_MIN +# define INT_FAST16_MAX INT16_MAX +# define UINT_FAST16_MAX UINT16_MAX +# else +# define INT_FAST16_MIN INT32_MIN +# define INT_FAST16_MAX INT32_MAX +# define UINT_FAST16_MAX UINT32_MAX +# endif +typedef int32_t int_fast32_t; +typedef uint32_t uint_fast32_t; +# define INT_FAST32_MIN INT32_MIN +# define INT_FAST32_MAX INT32_MAX +# define UINT_FAST32_MAX UINT32_MAX +typedef int64_t int_fast64_t; +typedef uint64_t uint_fast64_t; +# define INT_FAST64_MIN INT64_MIN +# define INT_FAST64_MAX INT64_MAX +# define UINT_FAST64_MAX UINT64_MAX + +# else +# error "PORTME: Add architecture. Don't forget to check the [U]INTx_C() and [U]INTMAX_MIN/MAX macros." +# endif + +# endif /* !linux kernel or stuff */ + + /* pointer <-> integer types */ +# if (!defined(_MSC_VER) && !defined(__WATCOMC__)) || defined(DOXYGEN_RUNNING) +# if ARCH_BITS == 32 \ + || defined(RT_OS_LINUX) \ + || defined(RT_OS_FREEBSD) +# if !defined(_INTPTR_T_DECLARED) && !defined(_INTPTR_T) && !defined(_INTPTR_T_DEFINED) +typedef signed long intptr_t; +# endif +# if !defined(_UINTPTR_T_DECLARED) && !defined(_UINTPTR_T) && !defined(_UINTPTR_T_DEFINED) +typedef unsigned long uintptr_t; +# endif +# else +# if !defined(_INTPTR_T_DECLARED) && !defined(_INTPTR_T) && !defined(_INTPTR_T_DEFINED) +typedef int64_t intptr_t; +# endif +# if !defined(_UINTPTR_T_DECLARED) && !defined(_UINTPTR_T) && !defined(_UINTPTR_T_DEFINED) +typedef uint64_t uintptr_t; +# endif +# endif +# endif /* !_MSC_VER */ + +#endif /* no system stdint.h */ + + +/* + * Make sure the [U]INTx_C(c) macros are present. + * For In C++ source the system stdint.h may have skipped these if it was + * included before we managed to define __STDC_CONSTANT_MACROS. (Kludge alert!) + */ +#if !defined(INT8_C) \ + || !defined(INT16_C) \ + || !defined(INT32_C) \ + || !defined(INT64_C) \ + || !defined(INTMAX_C) \ + || !defined(UINT8_C) \ + || !defined(UINT16_C) \ + || !defined(UINT32_C) \ + || !defined(UINT64_C) \ + || !defined(UINTMAX_C) +# define INT8_C(Value) (Value) +# define INT16_C(Value) (Value) +# define UINT8_C(Value) (Value) +# define UINT16_C(Value) (Value) +# if ARCH_BITS != 16 +# define INT32_C(Value) (Value) +# define UINT32_C(Value) (Value ## U) +# define INT64_C(Value) (Value ## LL) +# define UINT64_C(Value) (Value ## ULL) +# else +# define INT32_C(Value) (Value ## L) +# define UINT32_C(Value) (Value ## UL) +# define INT64_C(Value) (Value ## LL) +# define UINT64_C(Value) (Value ## ULL) +# endif +# define INTMAX_C(Value) INT64_C(Value) +# define UINTMAX_C(Value) UINT64_C(Value) +#endif + + +/* + * Make sure the INTx_MIN and [U]INTx_MAX macros are present. + * For In C++ source the system stdint.h may have skipped these if it was + * included before we managed to define __STDC_LIMIT_MACROS. (Kludge alert!) + */ +#if !defined(INT8_MIN) \ + || !defined(INT16_MIN) \ + || !defined(INT32_MIN) \ + || !defined(INT64_MIN) \ + || !defined(INT8_MAX) \ + || !defined(INT16_MAX) \ + || !defined(INT32_MAX) \ + || !defined(INT64_MAX) \ + || !defined(UINT8_MAX) \ + || !defined(UINT16_MAX) \ + || !defined(UINT32_MAX) \ + || !defined(UINT64_MAX) +# define INT8_MIN (INT8_C(-0x7f) - 1) +# define INT16_MIN (INT16_C(-0x7fff) - 1) +# define INT32_MIN (INT32_C(-0x7fffffff) - 1) +# define INT64_MIN (INT64_C(-0x7fffffffffffffff) - 1) +# define INT8_MAX INT8_C(0x7f) +# define INT16_MAX INT16_C(0x7fff) +# define INT32_MAX INT32_C(0x7fffffff) +# define INT64_MAX INT64_C(0x7fffffffffffffff) +# define UINT8_MAX UINT8_C(0xff) +# define UINT16_MAX UINT16_C(0xffff) +# define UINT32_MAX UINT32_C(0xffffffff) +# define UINT64_MAX UINT64_C(0xffffffffffffffff) + +# define INTMAX_MIN INT64_MIN +# define INTMAX_MAX INT64_MAX +# define UINTMAX_MAX UINT64_MAX +#endif + +#endif /* !IPRT_INCLUDED_stdint_h */ + diff --git a/include/iprt/strcache.h b/include/iprt/strcache.h new file mode 100644 index 00000000..a94fa616 --- /dev/null +++ b/include/iprt/strcache.h @@ -0,0 +1,201 @@ +/* $Id: strcache.h $ */ +/** @file + * IPRT - String Cache, stub implementation. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_strcache_h +#define IPRT_INCLUDED_strcache_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + + +/** + * Create a new string cache. + * + * @returns IPRT status code + * + * @param phStrCache Where to return the string cache handle. + * @param pszName The name of the cache (for debug purposes). + */ +RTDECL(int) RTStrCacheCreate(PRTSTRCACHE phStrCache, const char *pszName); + + +/** + * Destroys a string cache. + * + * This will cause all strings in the cache to be released and thus become + * invalid. + * + * @returns IPRT status. + * + * @param hStrCache Handle to the string cache. The nil and default + * handles are ignored quietly (VINF_SUCCESS). + */ +RTDECL(int) RTStrCacheDestroy(RTSTRCACHE hStrCache); + + +/** + * Enters a string into the cache. + * + * @returns Pointer to a read-only copy of the string. + * + * @param hStrCache Handle to the string cache. + * @param pchString Pointer to a string. This does not need to be + * zero terminated, but must not contain any zero + * characters. + * @param cchString The number of characters (bytes) to enter. + * + * @remarks It is implementation dependent whether the returned string pointer + * differs when entering the same string twice. + */ +RTDECL(const char *) RTStrCacheEnterN(RTSTRCACHE hStrCache, const char *pchString, size_t cchString); + +/** + * Enters a string into the cache. + * + * @returns Pointer to a read-only copy of the string. + * + * @param hStrCache Handle to the string cache. + * @param psz Pointer to a zero terminated string. + * + * @remarks See RTStrCacheEnterN. + */ +RTDECL(const char *) RTStrCacheEnter(RTSTRCACHE hStrCache, const char *psz); + + +/** + * Enters a string into the cache in lower cased form. + * + * @returns Pointer to a read-only lower cased copy of the string. + * + * @param hStrCache Handle to the string cache. + * @param pchString Pointer to a string. This does not need to be + * zero terminated, but must not contain any zero + * characters. + * @param cchString The number of characters (bytes) to enter. + * + * @remarks It is implementation dependent whether the returned string pointer + * differs when entering the same string twice. + */ +RTDECL(const char *) RTStrCacheEnterLowerN(RTSTRCACHE hStrCache, const char *pchString, size_t cchString); + +/** + * Enters a string into the cache in lower cased form. + * + * @returns Pointer to a read-only lower cased copy of the string. + * + * @param hStrCache Handle to the string cache. + * @param psz Pointer to a zero terminated string. + * + * @remarks See RTStrCacheEnterN. + */ +RTDECL(const char *) RTStrCacheEnterLower(RTSTRCACHE hStrCache, const char *psz); + + +/** + * Retains a reference to a string. + * + * @returns The new reference count. UINT32_MAX is returned if the string + * pointer is invalid. + */ +RTDECL(uint32_t) RTStrCacheRetain(const char *psz); + +/** + * Releases a reference to a string. + * + * @returns The new reference count. + * UINT32_MAX is returned if the string pointer is invalid. + * + * @param hStrCache Handle to the string cache. NIL is NOT allowed. + * @param psz Pointer to a cached string. + */ +RTDECL(uint32_t) RTStrCacheRelease(RTSTRCACHE hStrCache, const char *psz); + +/** + * Gets the string length of a cache entry. + * + * @returns The string length. 0 if the string is invalid (asserted). + * + * @param psz Pointer to a cached string. + */ +RTDECL(size_t) RTStrCacheLength(const char *psz); + + +/** + * Gets cache statistics. + * + * All parameters, except @a hStrCache, are optional and can be NULL. + * + * @returns Number of strings, UINT32_MAX on failure (or not supported). + * @param hStrCache Handle to the string cache. + * @param pcbStrings The number of string bytes (including + * terminators) . + * @param pcbChunks Amount of memory we've allocated for the + * internal allocator. + * @param pcbBigEntries Amount of memory we've allocated off the heap + * for really long strings that doesn't fit in the + * internal allocator. + * @param pcHashCollisions Number of hash table insert collisions. + * @param pcHashCollisions2 Number of hash table secondary insert + * collisions. + * @param pcHashInserts Number of hash table inserts. + * @param pcRehashes The number of rehashes. + * + * @remarks This is not a stable interface as it needs to reflect the cache + * implementation. + */ +RTDECL(uint32_t) RTStrCacheGetStats(RTSTRCACHE hStrCache, size_t *pcbStrings, size_t *pcbChunks, size_t *pcbBigEntries, + uint32_t *pcHashCollisions, uint32_t *pcHashCollisions2, uint32_t *pcHashInserts, + uint32_t *pcRehashes); + +/** + * Indicates whether this a real string cache or a cheap place holder. + * + * A real string cache will return the same address when a string is added + * multiple times. + * + * @returns true / false. + */ +RTDECL(bool) RTStrCacheIsRealImpl(void); + + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_strcache_h */ + diff --git a/include/iprt/stream.h b/include/iprt/stream.h new file mode 100644 index 00000000..927fd63a --- /dev/null +++ b/include/iprt/stream.h @@ -0,0 +1,542 @@ +/** @file + * IPRT - I/O Stream. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_stream_h +#define IPRT_INCLUDED_stream_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/stdarg.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_stream RTStrm - File Streams + * @ingroup grp_rt + * @{ + */ + +#ifndef IPRT_INCLUDED_message_h +/** Pointer to a stream. */ +typedef struct RTSTREAM *PRTSTREAM; +#endif + +/** Pointer to the standard input stream. */ +extern RTDATADECL(PRTSTREAM) g_pStdIn; + +/** Pointer to the standard error stream. */ +extern RTDATADECL(PRTSTREAM) g_pStdErr; + +/** Pointer to the standard output stream. */ +extern RTDATADECL(PRTSTREAM) g_pStdOut; + + +/** + * Opens a file stream. + * + * @returns iprt status code. + * @param pszFilename Path to the file to open. + * @param pszMode The open mode. See fopen() standard. + * Format: <a|r|w>[+][b|t][x][e|N|E] + * - 'a': Open or create file and writes + * append tos it. + * - 'r': Open existing file and read from it. + * - 'w': Open or truncate existing file and write + * to it. + * - '+': Open for both read and write access. + * - 'b' / 't': binary / text + * - 'x': exclusively create, no open. Only + * possible with 'w'. + * - 'e' / 'N': No inherit on exec. (The 'e' is + * how Linux and FreeBSD expresses this, the + * latter is Visual C++). + * @param ppStream Where to store the opened stream. + */ +RTR3DECL(int) RTStrmOpen(const char *pszFilename, const char *pszMode, PRTSTREAM *ppStream); + +/** + * Opens a file stream. + * + * @returns iprt status code. + * @param pszMode The open mode. See fopen() standard. + * Format: <a|r|w>[+][b|t][x][e|N|E] + * - 'a': Open or create file and writes + * append tos it. + * - 'r': Open existing file and read from it. + * - 'w': Open or truncate existing file and write + * to it. + * - '+': Open for both read and write access. + * - 'b' / 't': binary / text + * - 'x': exclusively create, no open. Only + * possible with 'w'. + * - 'e' / 'N': No inherit on exec. (The 'e' is + * how Linux and FreeBSD expresses this, the + * latter is Visual C++). + * @param ppStream Where to store the opened stream. + * @param pszFilenameFmt Filename path format string. + * @param args Arguments to the format string. + */ +RTR3DECL(int) RTStrmOpenFV(const char *pszMode, PRTSTREAM *ppStream, const char *pszFilenameFmt, + va_list args) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Opens a file stream. + * + * @returns iprt status code. + * @param pszMode The open mode. See fopen() standard. + * Format: <a|r|w>[+][b|t][x][e|N|E] + * - 'a': Open or create file and writes + * append tos it. + * - 'r': Open existing file and read from it. + * - 'w': Open or truncate existing file and write + * to it. + * - '+': Open for both read and write access. + * - 'b' / 't': binary / text + * - 'x': exclusively create, no open. Only + * possible with 'w'. + * - 'e' / 'N': No inherit on exec. (The 'e' is + * how Linux and FreeBSD expresses this, the + * latter is Visual C++). + * @param ppStream Where to store the opened stream. + * @param pszFilenameFmt Filename path format string. + * @param ... Arguments to the format string. + */ +RTR3DECL(int) RTStrmOpenF(const char *pszMode, PRTSTREAM *ppStream, const char *pszFilenameFmt, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Opens a file stream for a RTFILE handle, taking ownership of the handle. + * + * @returns iprt status code. + * @param hFile The file handle to use. On success, handle + * ownership is transfered to the stream and it will be + * closed when the stream closes. + * @param pszMode The open mode, accept the same as RTStrOpen and + * friends however it is only used to figure out what + * we can do with the handle. + * @param fFlags Reserved, must be zero. + * @param ppStream Where to store the opened stream. + */ +RTR3DECL(int) RTStrmOpenFileHandle(RTFILE hFile, const char *pszMode, uint32_t fFlags, PRTSTREAM *ppStream); + +/** + * Queries the file handle backing the stream. + * + * @returns iprt status code. + * @retval VERR_NOT_AVAILABLE if the stream has no valid handle associated with + * it. + * + * @param pStream The stream. + * @param phFile Where to return the file handle. This should not be + * closed! + */ +RTR3DECL(int) RTStrmQueryFileHandle(PRTSTREAM pStream, PRTFILE phFile); + +/** + * Closes the specified stream. + * + * @returns iprt status code. + * @param pStream The stream to close. + * + * @note The stream will be closed and freed even when failure is returned. + * It cannot be used again after this call. The error status is only + * to indicate that the flushing of buffers or the closing of the + * underlying file handle failed. + */ +RTR3DECL(int) RTStrmClose(PRTSTREAM pStream); + +/** + * Get the pending error of the stream. + * + * @returns iprt status code. of the stream. + * @param pStream The stream. + */ +RTR3DECL(int) RTStrmError(PRTSTREAM pStream); + +/** + * Clears stream error condition. + * + * All stream operations save RTStrmClose and this will fail + * while an error is asserted on the stream + * + * @returns iprt status code. + * @param pStream The stream. + */ +RTR3DECL(int) RTStrmClearError(PRTSTREAM pStream); + +/** + * Changes the stream mode. + * + * @returns iprt status code. + * @param pStream The stream. + * @param fBinary The desired binary (@c true) / text mode (@c false). + * Pass -1 to leave it unchanged. + * @param fCurrentCodeSet Whether converting the stream from UTF-8 to the + * current code set is desired (@c true) or not (@c + * false). Pass -1 to leave this property unchanged. + */ +RTR3DECL(int) RTStrmSetMode(PRTSTREAM pStream, int fBinary, int fCurrentCodeSet); + +/** Stream buffering modes. */ +typedef enum RTSTRMBUFMODE +{ + RTSTRMBUFMODE_INVALID = 0, + RTSTRMBUFMODE_FULL, /**< Full buffering. */ + RTSTRMBUFMODE_LINE, /**< Line buffering. On Windows this could be the same as RTSTRMBUFMODE_FULL. */ + RTSTRMBUFMODE_UNBUFFERED, /**< No buffering. */ + RTSTRMBUFMODE_END, + RTSTRMBUFMODE_32BIT_HACK = 0x7fffffff +} RTSTRMBUFMODE; + +/** + * Changes the stream buffering mode. + * + * @returns iprt status code. + * @param pStream The stream. + * @param enmBufMode The new buffering mode. + */ +RTR3DECL(int) RTStrmSetBufferingMode(PRTSTREAM pStream, RTSTRMBUFMODE enmBufMode); + +/** + * Returns the current echo mode. + * + * This works only for standard input streams. + * + * @returns iprt status code. + * @retval VERR_INVALID_FUNCTION if not a TTY. + * @param pStream The stream. + * @param pfEchoChars Where to store the flag whether typed characters are echoed. + */ +RTR3DECL(int) RTStrmInputGetEchoChars(PRTSTREAM pStream, bool *pfEchoChars); + +/** + * Changes the behavior for echoing inpit characters on the command line. + * + * This works only for standard input streams. + * + * @returns iprt status code. + * @retval VERR_INVALID_FUNCTION if not a TTY. + * @param pStream The stream. + * @param fEchoChars Flag whether echoing typed characters is wanted. + */ +RTR3DECL(int) RTStrmInputSetEchoChars(PRTSTREAM pStream, bool fEchoChars); + +/** + * Checks if this is a terminal (TTY) or not. + * + * @returns true if it is, false if it isn't or the stream isn't valid. + * @param pStream The stream. + */ +RTR3DECL(bool) RTStrmIsTerminal(PRTSTREAM pStream); + +/** + * Gets the width of the terminal the stream is associated with. + * + * @returns IPRT status code. + * @retval VERR_INVALID_FUNCTION if not connected to a terminal. + * @param pStream The stream. + * @param pcchWidth Where to return the width. This will never be zero + * and always be set, even on error. + */ +RTR3DECL(int) RTStrmQueryTerminalWidth(PRTSTREAM pStream, uint32_t *pcchWidth); + +/** + * Rewinds the stream. + * + * Stream errors will be reset on success. + * + * @returns IPRT status code. + * + * @param pStream The stream. + * + * @remarks Not all streams are rewindable and that behavior is currently + * undefined for those. + */ +RTR3DECL(int) RTStrmRewind(PRTSTREAM pStream); + +/** + * Changes the file position. + * + * @returns IPRT status code. + * + * @param pStream The stream. + * @param off The seek offset. + * @param uMethod Seek method, i.e. one of the RTFILE_SEEK_* defines. + * + * @remarks Not all streams are seekable and that behavior is currently + * undefined for those. + */ +RTR3DECL(int) RTStrmSeek(PRTSTREAM pStream, RTFOFF off, uint32_t uMethod); + +/** + * Tells the stream position. + * + * @returns Stream position or IPRT error status. Non-negative numbers are + * stream positions, while negative numbers are IPRT error stauses. + * + * @param pStream The stream. + * + * @remarks Not all streams have a position and that behavior is currently + * undefined for those. + */ +RTR3DECL(RTFOFF) RTStrmTell(PRTSTREAM pStream); + +/** + * Reads from a file stream. + * + * @returns iprt status code. + * @param pStream The stream. + * @param pvBuf Where to put the read bits. + * Must be cbRead bytes or more. + * @param cbToRead Number of bytes to read. + * @param pcbRead Where to store the number of bytes actually read. + * If NULL cbRead bytes are read or an error is returned. + */ +RTR3DECL(int) RTStrmReadEx(PRTSTREAM pStream, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Writes to a file stream. + * + * @returns iprt status code. + * @param pStream The stream. + * @param pvBuf Where to get the bits to write from. + * @param cbToWrite Number of bytes to write. + * @param pcbWritten Where to store the number of bytes actually written. + * If NULL cbWrite bytes are written or an error is returned. + */ +RTR3DECL(int) RTStrmWriteEx(PRTSTREAM pStream, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + +/** + * Reads from a file stream. + * + * @returns iprt status code. + * @param pStream The stream. + * @param pvBuf Where to put the read bits. + * Must be cbRead bytes or more. + * @param cbToRead Number of bytes to read. + */ +DECLINLINE(int) RTStrmRead(PRTSTREAM pStream, void *pvBuf, size_t cbToRead) +{ + return RTStrmReadEx(pStream, pvBuf, cbToRead, NULL); +} + +/** + * Writes to a file stream. + * + * @returns iprt status code. + * @param pStream The stream. + * @param pvBuf Where to get the bits to write from. + * @param cbToWrite Number of bytes to write. + */ +DECLINLINE(int) RTStrmWrite(PRTSTREAM pStream, const void *pvBuf, size_t cbToWrite) +{ + return RTStrmWriteEx(pStream, pvBuf, cbToWrite, NULL); +} + +/** + * Reads a character from a file stream. + * + * @returns The char as an unsigned char cast to int. + * @returns -1 on failure. + * @param pStream The stream. + */ +RTR3DECL(int) RTStrmGetCh(PRTSTREAM pStream); + +/** + * Writes a character to a file stream. + * + * @returns iprt status code. + * @param pStream The stream. + * @param ch The char to write. + */ +RTR3DECL(int) RTStrmPutCh(PRTSTREAM pStream, int ch); + +/** + * Writes a string to a file stream. + * + * @returns iprt status code. + * @param pStream The stream. + * @param pszString The string to write. + * No newlines or anything are appended or prepended. + * The terminating '\\0' is not written, of course. + */ +RTR3DECL(int) RTStrmPutStr(PRTSTREAM pStream, const char *pszString); + +/** + * Reads a line from a file stream. + * + * A line ends with a '\\n', '\\r\\n', '\\0' or the end of the file. + * + * @returns iprt status code. + * @retval VINF_BUFFER_OVERFLOW if the buffer wasn't big enough to read an + * entire line. + * @retval VERR_BUFFER_OVERFLOW if a lone '\\r' was encountered at the end of + * the buffer and we ended up dropping the following character. + * + * @param pStream The stream. + * @param pszString Where to store the line. + * The line will *NOT* contain any '\\n'. + * @param cbString The size of the string buffer. + */ +RTR3DECL(int) RTStrmGetLine(PRTSTREAM pStream, char *pszString, size_t cbString); + +/** + * Flushes a stream. + * + * @returns iprt status code. + * @param pStream The stream to flush. + */ +RTR3DECL(int) RTStrmFlush(PRTSTREAM pStream); + +/** + * Prints a formatted string to the specified stream. + * + * @returns Number of bytes printed. + * @param pStream The stream to print to. + * @param pszFormat Runtime format string. + * @param ... Arguments specified by pszFormat. + */ +RTR3DECL(int) RTStrmPrintf(PRTSTREAM pStream, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Prints a formatted string to the specified stream. + * + * @returns Number of bytes printed. + * @param pStream The stream to print to. + * @param pszFormat Runtime format string. + * @param args Arguments specified by pszFormat. + */ +RTR3DECL(int) RTStrmPrintfV(PRTSTREAM pStream, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Prints a formatted string to the specified stream, performing wrapping of + * lines considered too long. + * + * If the stream is to a terminal, the terminal width is used as the max line + * width. Otherwise, the width is taken from @a fFlags + * (RTSTRMWRAPPED_F_NON_TERMINAL_WIDTH_MASK / + * RTSTRMWRAPPED_F_NON_TERMINAL_WIDTH_SHIFT), defaulting to 80 if zero. + * + * @returns Low 16 bits is the line offset, high 16 bits the number of lines + * outputted. Apply RTSTRMWRAPPED_F_LINE_OFFSET_MASK to the value and + * it can be passed via @a fFlags to the next invocation (not necessary + * if all format strings ends with a newline). + * Negative values are IPRT error status codes. + * @param pStream The stream to print to. + * @param fFlags RTSTRMWRAPPED_F_XXX - flags, configuration and state. + * @param pszFormat Runtime format string. + * @param ... Arguments specified by pszFormat. + * @sa RTStrmWrappedPrintfV, RTStrmPrintf, RTStrmPrintfV + */ +RTDECL(int32_t) RTStrmWrappedPrintf(PRTSTREAM pStream, uint32_t fFlags, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Prints a formatted string to the specified stream, performing wrapping of + * lines considered too long. + * + * If the stream is to a terminal, the terminal width is used as the max line + * width. Otherwise, the width is taken from @a fFlags + * (RTSTRMWRAPPED_F_NON_TERMINAL_WIDTH_MASK / + * RTSTRMWRAPPED_F_NON_TERMINAL_WIDTH_SHIFT), defaulting to 80 if zero. + * + * @returns Low 16 bits is the line offset, high 16 bits the number of lines + * outputted. Apply RTSTRMWRAPPED_F_LINE_OFFSET_MASK to the value and + * it can be passed via @a fFlags to the next invocation (not necessary + * if all format strings ends with a newline). + * Negative values are IPRT error status codes. + * @param pStream The stream to print to. + * @param fFlags RTSTRMWRAPPED_F_XXX - flags, configuration and state. + * @param pszFormat Runtime format string. + * @param va Arguments specified by pszFormat. + * @sa RTStrmWrappedPrintf, RTStrmPrintf, RTStrmPrintfV + */ +RTDECL(int32_t) RTStrmWrappedPrintfV(PRTSTREAM pStream, uint32_t fFlags, const char *pszFormat, + va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** @name RTSTRMWRAPPED_F_XXX - Flags for RTStrmWrappedPrintf & + * RTStrmWrappedPrintfV. + * @{ */ +/** The current line offset mask. + * This should be used to passed the line off state from one call to the next + * when printing incomplete lines. If all format strings ends with a newline, + * this is not necessary. */ +#define RTSTRMWRAPPED_F_LINE_OFFSET_MASK UINT32_C(0x00000fff) +/** The non-terminal width mask. Defaults to 80 if not specified (zero). */ +#define RTSTRMWRAPPED_F_NON_TERMINAL_WIDTH_MASK UINT32_C(0x000ff000) +/** The non-terminal width shift. */ +#define RTSTRMWRAPPED_F_NON_TERMINAL_WIDTH_SHIFT 12 +/** The hanging indent level mask - defaults to 4 if zero. + * Used when RTSTRMWRAPPED_F_HANGING_INDENT is set. */ +#define RTSTRMWRAPPED_F_HANGING_INDENT_MASK UINT32_C(0x01f00000) +/** The hanging indent level shift. */ +#define RTSTRMWRAPPED_F_HANGING_INDENT_SHIFT 20 +/** Hanging indent. Used for command synopsis and such. */ +#define RTSTRMWRAPPED_F_HANGING_INDENT UINT32_C(0x80000000) +/** @} */ + +/** + * Dumper vprintf-like function outputting to a stream. + * + * @param pvUser The stream to print to. NULL means standard output. + * @param pszFormat Runtime format string. + * @param va Arguments specified by pszFormat. + */ +RTR3DECL(void) RTStrmDumpPrintfV(void *pvUser, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Prints a formatted string to the standard output stream (g_pStdOut). + * + * @returns Number of bytes printed. + * @param pszFormat Runtime format string. + * @param ... Arguments specified by pszFormat. + */ +RTR3DECL(int) RTPrintf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Prints a formatted string to the standard output stream (g_pStdOut). + * + * @returns Number of bytes printed. + * @param pszFormat Runtime format string. + * @param args Arguments specified by pszFormat. + */ +RTR3DECL(int) RTPrintfV(const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(1, 0); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_stream_h */ + diff --git a/include/iprt/string.h b/include/iprt/string.h new file mode 100644 index 00000000..d7b78bf3 --- /dev/null +++ b/include/iprt/string.h @@ -0,0 +1,3725 @@ +/** @file + * IPRT - String Manipulation. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_string_h +#define IPRT_INCLUDED_string_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/assert.h> +#include <iprt/stdarg.h> +#include <iprt/errcore.h> /* for VINF_SUCCESS */ +#if defined(RT_OS_LINUX) && defined(__KERNEL__) + /* no C++ hacks ('new' etc) here anymore! */ +# include <linux/string.h> + +#elif defined(IN_XF86_MODULE) && !defined(NO_ANSIC) + RT_C_DECLS_BEGIN +# include "xf86_ansic.h" + RT_C_DECLS_END + +#elif defined(RT_OS_FREEBSD) && defined(_KERNEL) + RT_C_DECLS_BEGIN +# include <sys/libkern.h> + RT_C_DECLS_END + +#elif defined(RT_OS_NETBSD) && defined(_KERNEL) + RT_C_DECLS_BEGIN +# include <lib/libkern/libkern.h> + RT_C_DECLS_END + +#elif defined(RT_OS_SOLARIS) && defined(_KERNEL) + /* + * Same case as with FreeBSD kernel: + * The string.h stuff clashes with sys/system.h + * ffs = find first set bit. + */ +# define ffs ffs_string_h +# define fls fls_string_h +# include <string.h> +# undef fls +# undef ffs +# undef strpbrk + +#else +# include <string.h> +#endif + +/* + * Supply prototypes for standard string functions provided by + * IPRT instead of the operating environment. + */ +#if defined(RT_OS_DARWIN) && defined(KERNEL) +RT_C_DECLS_BEGIN +void *memchr(const void *pv, int ch, size_t cb); +char *strpbrk(const char *pszStr, const char *pszChars); +RT_C_DECLS_END +#endif + +#if defined(RT_OS_FREEBSD) && defined(_KERNEL) +RT_C_DECLS_BEGIN +char *strpbrk(const char *pszStr, const char *pszChars); +RT_C_DECLS_END +#endif + +#if defined(RT_OS_NETBSD) && defined(_KERNEL) +RT_C_DECLS_BEGIN +char *strpbrk(const char *pszStr, const char *pszChars); +RT_C_DECLS_END +#endif + +#if (defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_WINDOWS)) && !defined(IPRT_NO_CRT) +RT_C_DECLS_BEGIN +# if !defined(RT_OS_DARWIN) || RT_CLANG_PREREQ(7 /* whatever post gcc-4.2 */, 0) +RTDECL(void *) mempcpy(void *pvDst, const void *pvSrc, size_t cb); +# else +void *mempcpy(void *pvDst, const void *pvSrc, size_t cb); +# endif +RT_C_DECLS_END +#endif + +#if (!defined(RT_OS_LINUX) || !defined(_GNU_SOURCE)) \ + && (!defined(RT_OS_OS2) || !defined(_GNU_SOURCE)) \ + && !defined(RT_OS_FREEBSD) \ + && !defined(RT_OS_NETBSD) +RT_C_DECLS_BEGIN +void *memrchr(const void *pv, int ch, size_t cb); +RT_C_DECLS_END +#endif + + +/** @def RT_USE_RTC_3629 + * When defined the UTF-8 range will stop at 0x10ffff. If not defined, the + * range stops at 0x7fffffff. + * @remarks Must be defined both when building and using the IPRT. */ +#ifdef DOXYGEN_RUNNING +# define RT_USE_RTC_3629 +#endif + + +/** + * Byte zero the specified object. + * + * This will use sizeof(Obj) to figure the size and will call memset, bzero + * or some compiler intrinsic to perform the actual zeroing. + * + * @param Obj The object to zero. Make sure to dereference pointers. + * + * @remarks Because the macro may use memset it has been placed in string.h + * instead of cdefs.h to avoid build issues because someone forgot + * to include this header. + * + * @ingroup grp_rt_cdefs + */ +#define RT_ZERO(Obj) RT_BZERO(&(Obj), sizeof(Obj)) + +/** + * Byte zero the specified memory area. + * + * This will call memset, bzero or some compiler intrinsic to clear the + * specified bytes of memory. + * + * @param pv Pointer to the memory. + * @param cb The number of bytes to clear. Please, don't pass 0. + * + * @remarks Because the macro may use memset it has been placed in string.h + * instead of cdefs.h to avoid build issues because someone forgot + * to include this header. + * + * @ingroup grp_rt_cdefs + */ +#define RT_BZERO(pv, cb) do { memset((pv), 0, cb); } while (0) + + +/** + * For copying a volatile variable to a non-volatile one. + * @param a_Dst The non-volatile destination variable. + * @param a_VolatileSrc The volatile source variable / dereferenced pointer. + */ +#define RT_COPY_VOLATILE(a_Dst, a_VolatileSrc) \ + do { \ + void const volatile *a_pvVolatileSrc_BCopy_Volatile = &(a_VolatileSrc); \ + AssertCompile(sizeof(a_Dst) == sizeof(a_VolatileSrc)); \ + memcpy(&(a_Dst), (void const *)a_pvVolatileSrc_BCopy_Volatile, sizeof(a_Dst)); \ + } while (0) + +/** + * For copy a number of bytes from a volatile buffer to a non-volatile one. + * + * @param a_pDst Pointer to the destination buffer. + * @param a_pVolatileSrc Pointer to the volatile source buffer. + * @param a_cbToCopy Number of bytes to copy. + */ +#define RT_BCOPY_VOLATILE(a_pDst, a_pVolatileSrc, a_cbToCopy) \ + do { \ + void const volatile *a_pvVolatileSrc_BCopy_Volatile = (a_pVolatileSrc); \ + memcpy((a_pDst), (void const *)a_pvVolatileSrc_BCopy_Volatile, (a_cbToCopy)); \ + } while (0) + + +/** @defgroup grp_rt_str RTStr - String Manipulation + * Mostly UTF-8 related helpers where the standard string functions won't do. + * @ingroup grp_rt + * @{ + */ + +RT_C_DECLS_BEGIN + + +/** + * The maximum string length. + */ +#define RTSTR_MAX (~(size_t)0) + + +/** @def RTSTR_TAG + * The default allocation tag used by the RTStr allocation APIs. + * + * When not defined before the inclusion of iprt/string.h, this will default to + * the pointer to the current file name. The string API will make of use of + * this as pointer to a volatile but read-only string. + */ +#if !defined(RTSTR_TAG) || defined(DOXYGEN_RUNNING) +# define RTSTR_TAG (__FILE__) +#endif + + +#ifdef IN_RING3 + +/** + * Allocates tmp buffer with default tag, translates pszString from UTF8 to + * current codepage. + * + * @returns iprt status code. + * @param ppszString Receives pointer of allocated native CP string. + * The returned pointer must be freed using RTStrFree(). + * @param pszString UTF-8 string to convert. + */ +#define RTStrUtf8ToCurrentCP(ppszString, pszString) RTStrUtf8ToCurrentCPTag((ppszString), (pszString), RTSTR_TAG) + +/** + * Allocates tmp buffer with custom tag, translates pszString from UTF-8 to + * current codepage. + * + * @returns iprt status code. + * @param ppszString Receives pointer of allocated native CP string. + * The returned pointer must be freed using + * RTStrFree()., const char *pszTag + * @param pszString UTF-8 string to convert. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR3DECL(int) RTStrUtf8ToCurrentCPTag(char **ppszString, const char *pszString, const char *pszTag); + +/** + * Allocates tmp buffer with default tag, translates pszString from UTF-8 to + * current codepage, extended version. + * + * @returns iprt status code. + * @param ppszString Receives pointer of allocated native CP string. + * The returned pointer must be freed using RTStrFree(). + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. The conversion stop + * when it reaches cchString or the string terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + */ +#define RTStrUtf8ToCurrentCPEx(ppszString, pszString, cchString) \ + RTStrUtf8ToCurrentCPExTag((ppszString), (pszString), (cchString), RTSTR_TAG) + +/** + * Allocates tmp buffer with custom tag, translates pszString from UTF8 to + * current codepage. + * + * @returns iprt status code. + * @param ppszString Receives pointer of allocated native CP string. + * The returned pointer must be freed using + * RTStrFree()., const char *pszTag + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. The conversion stop + * when it reaches cchString or the string terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR3DECL(int) RTStrUtf8ToCurrentCPExTag(char **ppszString, const char *pszString, size_t cchString, const char *pszTag); + +/** + * Allocates tmp buffer, translates pszString from current codepage to UTF-8. + * + * @returns iprt status code. + * @param ppszString Receives pointer of allocated UTF-8 string. + * The returned pointer must be freed using RTStrFree(). + * @param pszString Native string to convert. + */ +#define RTStrCurrentCPToUtf8(ppszString, pszString) RTStrCurrentCPToUtf8Tag((ppszString), (pszString), RTSTR_TAG) + +/** + * Allocates tmp buffer, translates pszString from current codepage to UTF-8. + * + * @returns iprt status code. + * @param ppszString Receives pointer of allocated UTF-8 string. + * The returned pointer must be freed using RTStrFree(). + * @param pszString Native string to convert. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR3DECL(int) RTStrCurrentCPToUtf8Tag(char **ppszString, const char *pszString, const char *pszTag); + +/** + * Allocates tmp buffer, translates pszString from console codepage to UTF-8. + * + * @returns iprt status code. + * @param ppszString Receives pointer of allocated UTF-8 string. + * The returned pointer must be freed using RTStrFree(). + * @param pszString Native string to convert. + */ +#define RTStrConsoleCPToUtf8(ppszString, pszString) RTStrConsoleCPToUtf8Tag((ppszString), (pszString), RTSTR_TAG) + +/** + * Allocates tmp buffer, translates pszString from console codepage to UTF-8. + * + * @returns iprt status code. + * @param ppszString Receives pointer of allocated UTF-8 string. + * The returned pointer must be freed using RTStrFree(). + * @param pszString Native string to convert. + * @param pszTag Allocation tag used for statistics and such. + */ +RTR3DECL(int) RTStrConsoleCPToUtf8Tag(char **ppszString, const char *pszString, const char *pszTag); + +#endif /* IN_RING3 */ + +/** + * Free string allocated by any of the non-UCS-2 string functions. + * + * @returns iprt status code. + * @param pszString Pointer to buffer with string to free. + * NULL is accepted. + */ +RTDECL(void) RTStrFree(char *pszString); + +/** + * Allocates a new copy of the given UTF-8 string (default tag). + * + * @returns Pointer to the allocated UTF-8 string. + * @param pszString UTF-8 string to duplicate. + */ +#define RTStrDup(pszString) RTStrDupTag((pszString), RTSTR_TAG) + +/** + * Allocates a new copy of the given UTF-8 string (custom tag). + * + * @returns Pointer to the allocated UTF-8 string. + * @param pszString UTF-8 string to duplicate. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(char *) RTStrDupTag(const char *pszString, const char *pszTag); + +/** + * Allocates a new copy of the given UTF-8 string (default tag). + * + * @returns iprt status code. + * @param ppszCopy Receives pointer of the allocated UTF-8 string. + * The returned pointer must be freed using RTStrFree(). + * @param pszString UTF-8 string to duplicate. + */ +#define RTStrDupEx(ppszCopy, pszString) RTStrDupExTag((ppszCopy), (pszString), RTSTR_TAG) + +/** + * Allocates a new copy of the given UTF-8 string (custom tag). + * + * @returns iprt status code. + * @param ppszCopy Receives pointer of the allocated UTF-8 string. + * The returned pointer must be freed using RTStrFree(). + * @param pszString UTF-8 string to duplicate. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrDupExTag(char **ppszCopy, const char *pszString, const char *pszTag); + +/** + * Allocates a new copy of the given UTF-8 substring (default tag). + * + * @returns Pointer to the allocated UTF-8 substring. + * @param pszString UTF-8 string to duplicate. + * @param cchMax The max number of chars to duplicate, not counting + * the terminator. + */ +#define RTStrDupN(pszString, cchMax) RTStrDupNTag((pszString), (cchMax), RTSTR_TAG) + +/** + * Allocates a new copy of the given UTF-8 substring (custom tag). + * + * @returns Pointer to the allocated UTF-8 substring. + * @param pszString UTF-8 string to duplicate. + * @param cchMax The max number of chars to duplicate, not counting + * the terminator. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(char *) RTStrDupNTag(const char *pszString, size_t cchMax, const char *pszTag); + +/** + * Allocates a new copy of the given UTF-8 substring (default tag). + * + * @returns iprt status code (VINF_SUCCESS or VERR_NO_STR_MEMORY). + * @param ppszCopy Receives pointer of the allocated UTF-8 substring. + * The returned pointer must be freed using RTStrFree(). + * @param pszString UTF-8 string to duplicate. + * @param cchMax The max number of chars to duplicate, not counting + * the terminator. + */ +#define RTStrDupNEx(ppszCopy, pszString, cchMax) RTStrDupNExTag((ppszCopy), (pszString), (cchMax), RTSTR_TAG) + +/** + * Allocates a new copy of the given UTF-8 substring (custom tag). + * + * @returns iprt status code (VINF_SUCCESS or VERR_NO_STR_MEMORY). + * @param ppszCopy Receives pointer of the allocated UTF-8 substring. + * The returned pointer must be freed using RTStrFree(). + * @param pszString UTF-8 string to duplicate. + * @param cchMax The max number of chars to duplicate, not counting + * the terminator. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrDupNExTag(char **ppszCopy, const char *pszString, size_t cchMax, const char *pszTag); + +/** + * Appends a string onto an existing IPRT allocated string (default tag). + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string pointer. The string + * pointer must either be NULL or point to a string + * returned by an IPRT string API. (In/Out) + * @param pszAppend The string to append. NULL and empty strings + * are quietly ignored. + */ +#define RTStrAAppend(ppsz, pszAppend) RTStrAAppendTag((ppsz), (pszAppend), RTSTR_TAG) + +/** + * Appends a string onto an existing IPRT allocated string (custom tag). + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string pointer. The string + * pointer must either be NULL or point to a string + * returned by an IPRT string API. (In/Out) + * @param pszAppend The string to append. NULL and empty strings + * are quietly ignored. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrAAppendTag(char **ppsz, const char *pszAppend, const char *pszTag); + +/** + * Appends N bytes from a strings onto an existing IPRT allocated string + * (default tag). + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string pointer. The string + * pointer must either be NULL or point to a string + * returned by an IPRT string API. (In/Out) + * @param pszAppend The string to append. Can be NULL if cchAppend + * is NULL. + * @param cchAppend The number of chars (not code points) to append + * from pszAppend. Must not be more than + * @a pszAppend contains, except for the special + * value RTSTR_MAX that can be used to indicate all + * of @a pszAppend without having to strlen it. + */ +#define RTStrAAppendN(ppsz, pszAppend, cchAppend) RTStrAAppendNTag((ppsz), (pszAppend), (cchAppend), RTSTR_TAG) + +/** + * Appends N bytes from a strings onto an existing IPRT allocated string (custom + * tag). + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string pointer. The string + * pointer must either be NULL or point to a string + * returned by an IPRT string API. (In/Out) + * @param pszAppend The string to append. Can be NULL if cchAppend + * is NULL. + * @param cchAppend The number of chars (not code points) to append + * from pszAppend. Must not be more than + * @a pszAppend contains, except for the special + * value RTSTR_MAX that can be used to indicate all + * of @a pszAppend without having to strlen it. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrAAppendNTag(char **ppsz, const char *pszAppend, size_t cchAppend, const char *pszTag); + +/** + * Appends one or more strings onto an existing IPRT allocated string. + * + * This is a very flexible and efficient alternative to using RTStrAPrintf to + * combine several strings together. + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string pointer. The string + * pointer must either be NULL or point to a string + * returned by an IPRT string API. (In/Out) + * @param cPairs The number of string / length pairs in the + * @a va. + * @param va List of string (const char *) and length + * (size_t) pairs. The strings will be appended to + * the string in the first argument. + */ +#define RTStrAAppendExNV(ppsz, cPairs, va) RTStrAAppendExNVTag((ppsz), (cPairs), (va), RTSTR_TAG) + +/** + * Appends one or more strings onto an existing IPRT allocated string. + * + * This is a very flexible and efficient alternative to using RTStrAPrintf to + * combine several strings together. + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string pointer. The string + * pointer must either be NULL or point to a string + * returned by an IPRT string API. (In/Out) + * @param cPairs The number of string / length pairs in the + * @a va. + * @param va List of string (const char *) and length + * (size_t) pairs. The strings will be appended to + * the string in the first argument. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrAAppendExNVTag(char **ppsz, size_t cPairs, va_list va, const char *pszTag); + +/** + * Appends one or more strings onto an existing IPRT allocated string + * (untagged). + * + * This is a very flexible and efficient alternative to using RTStrAPrintf to + * combine several strings together. + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string pointer. The string + * pointer must either be NULL or point to a string + * returned by an IPRT string API. (In/Out) + * @param cPairs The number of string / length pairs in the + * ellipsis. + * @param ... List of string (const char *) and length + * (size_t) pairs. The strings will be appended to + * the string in the first argument. + */ +DECLINLINE(int) RTStrAAppendExN(char **ppsz, size_t cPairs, ...) +{ + int rc; + va_list va; + va_start(va, cPairs); + rc = RTStrAAppendExNVTag(ppsz, cPairs, va, RTSTR_TAG); + va_end(va); + return rc; +} + +/** + * Appends one or more strings onto an existing IPRT allocated string (custom + * tag). + * + * This is a very flexible and efficient alternative to using RTStrAPrintf to + * combine several strings together. + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string pointer. The string + * pointer must either be NULL or point to a string + * returned by an IPRT string API. (In/Out) + * @param pszTag Allocation tag used for statistics and such. + * @param cPairs The number of string / length pairs in the + * ellipsis. + * @param ... List of string (const char *) and length + * (size_t) pairs. The strings will be appended to + * the string in the first argument. + */ +DECLINLINE(int) RTStrAAppendExNTag(char **ppsz, const char *pszTag, size_t cPairs, ...) +{ + int rc; + va_list va; + va_start(va, cPairs); + rc = RTStrAAppendExNVTag(ppsz, cPairs, va, pszTag); + va_end(va); + return rc; +} + +/** + * Truncates an IPRT allocated string (default tag). + * + * @retval VINF_SUCCESS. + * @retval VERR_OUT_OF_RANGE if cchNew is too long. Nothing is done. + * + * @param ppsz Pointer to the string pointer. The string + * pointer can be NULL if @a cchNew is 0, no change + * is made then. If we actually reallocate the + * string, the string pointer might be changed by + * this call. (In/Out) + * @param cchNew The new string length (excluding the + * terminator). The string must be at least this + * long or we'll return VERR_OUT_OF_RANGE and + * assert on you. + */ +#define RTStrATruncate(ppsz, cchNew) RTStrATruncateTag((ppsz), (cchNew), RTSTR_TAG) + +/** + * Truncates an IPRT allocated string. + * + * @retval VINF_SUCCESS. + * @retval VERR_OUT_OF_RANGE if cchNew is too long. Nothing is done. + * + * @param ppsz Pointer to the string pointer. The string + * pointer can be NULL if @a cchNew is 0, no change + * is made then. If we actually reallocate the + * string, the string pointer might be changed by + * this call. (In/Out) + * @param cchNew The new string length (excluding the + * terminator). The string must be at least this + * long or we'll return VERR_OUT_OF_RANGE and + * assert on you. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrATruncateTag(char **ppsz, size_t cchNew, const char *pszTag); + +/** + * Allocates memory for string storage (default tag). + * + * You should normally not use this function, except if there is some very + * custom string handling you need doing that isn't covered by any of the other + * APIs. + * + * @returns Pointer to the allocated string. The first byte is always set + * to the string terminator char, the contents of the remainder of the + * memory is undefined. The string must be freed by calling RTStrFree. + * + * NULL is returned if the allocation failed. Please translate this to + * VERR_NO_STR_MEMORY and not VERR_NO_MEMORY. Also consider + * RTStrAllocEx if an IPRT status code is required. + * + * @param cb How many bytes to allocate. If this is zero, we + * will allocate a terminator byte anyway. + */ +#define RTStrAlloc(cb) RTStrAllocTag((cb), RTSTR_TAG) + +/** + * Allocates memory for string storage (custom tag). + * + * You should normally not use this function, except if there is some very + * custom string handling you need doing that isn't covered by any of the other + * APIs. + * + * @returns Pointer to the allocated string. The first byte is always set + * to the string terminator char, the contents of the remainder of the + * memory is undefined. The string must be freed by calling RTStrFree. + * + * NULL is returned if the allocation failed. Please translate this to + * VERR_NO_STR_MEMORY and not VERR_NO_MEMORY. Also consider + * RTStrAllocEx if an IPRT status code is required. + * + * @param cb How many bytes to allocate. If this is zero, we + * will allocate a terminator byte anyway. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(char *) RTStrAllocTag(size_t cb, const char *pszTag); + +/** + * Allocates memory for string storage, with status code (default tag). + * + * You should normally not use this function, except if there is some very + * custom string handling you need doing that isn't covered by any of the other + * APIs. + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY + * + * @param ppsz Where to return the allocated string. This will + * be set to NULL on failure. On success, the + * returned memory will always start with a + * terminator char so that it is considered a valid + * C string, the contents of rest of the memory is + * undefined. + * @param cb How many bytes to allocate. If this is zero, we + * will allocate a terminator byte anyway. + */ +#define RTStrAllocEx(ppsz, cb) RTStrAllocExTag((ppsz), (cb), RTSTR_TAG) + +/** + * Allocates memory for string storage, with status code (custom tag). + * + * You should normally not use this function, except if there is some very + * custom string handling you need doing that isn't covered by any of the other + * APIs. + * + * @retval VINF_SUCCESS + * @retval VERR_NO_STR_MEMORY + * + * @param ppsz Where to return the allocated string. This will + * be set to NULL on failure. On success, the + * returned memory will always start with a + * terminator char so that it is considered a valid + * C string, the contents of rest of the memory is + * undefined. + * @param cb How many bytes to allocate. If this is zero, we + * will allocate a terminator byte anyway. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrAllocExTag(char **ppsz, size_t cb, const char *pszTag); + +/** + * Reallocates the specified string (default tag). + * + * You should normally not have use this function, except perhaps to truncate a + * really long string you've got from some IPRT string API, but then you should + * use RTStrATruncate. + * + * @returns VINF_SUCCESS. + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string variable containing the + * input and output string. + * + * When not freeing the string, the result will + * always have the last byte set to the terminator + * character so that when used for string + * truncation the result will be a valid C string + * (your job to keep it a valid UTF-8 string). + * + * When the input string is NULL and we're supposed + * to reallocate, the returned string will also + * have the first byte set to the terminator char + * so it will be a valid C string. + * + * @param cbNew When @a cbNew is zero, we'll behave like + * RTStrFree and @a *ppsz will be set to NULL. + * + * When not zero, this will be the new size of the + * memory backing the string, i.e. it includes the + * terminator char. + */ +#define RTStrRealloc(ppsz, cbNew) RTStrReallocTag((ppsz), (cbNew), RTSTR_TAG) + +/** + * Reallocates the specified string (custom tag). + * + * You should normally not have use this function, except perhaps to truncate a + * really long string you've got from some IPRT string API, but then you should + * use RTStrATruncate. + * + * @returns VINF_SUCCESS. + * @retval VERR_NO_STR_MEMORY if we failed to reallocate the string, @a *ppsz + * remains unchanged. + * + * @param ppsz Pointer to the string variable containing the + * input and output string. + * + * When not freeing the string, the result will + * always have the last byte set to the terminator + * character so that when used for string + * truncation the result will be a valid C string + * (your job to keep it a valid UTF-8 string). + * + * When the input string is NULL and we're supposed + * to reallocate, the returned string will also + * have the first byte set to the terminator char + * so it will be a valid C string. + * + * @param cbNew When @a cbNew is zero, we'll behave like + * RTStrFree and @a *ppsz will be set to NULL. + * + * When not zero, this will be the new size of the + * memory backing the string, i.e. it includes the + * terminator char. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrReallocTag(char **ppsz, size_t cbNew, const char *pszTag); + +/** + * Validates the UTF-8 encoding of the string. + * + * @returns iprt status code. + * @param psz The string. + */ +RTDECL(int) RTStrValidateEncoding(const char *psz); + +/** @name Flags for RTStrValidateEncodingEx and RTUtf16ValidateEncodingEx + * @{ + */ +/** Check that the string is zero terminated within the given size. + * VERR_BUFFER_OVERFLOW will be returned if the check fails. */ +#define RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED RT_BIT_32(0) +/** Check that the string is exactly the given length. + * If it terminates early, VERR_BUFFER_UNDERFLOW will be returned. When used + * together with RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED, the given length must + * include the terminator or VERR_BUFFER_OVERFLOW will be returned. */ +#define RTSTR_VALIDATE_ENCODING_EXACT_LENGTH RT_BIT_32(1) +/** @} */ + +/** + * Validates the UTF-8 encoding of the string. + * + * @returns iprt status code. + * @param psz The string. + * @param cch The max string length (/ size). Use RTSTR_MAX to + * process the entire string. + * @param fFlags Combination of RTSTR_VALIDATE_ENCODING_XXX flags. + */ +RTDECL(int) RTStrValidateEncodingEx(const char *psz, size_t cch, uint32_t fFlags); + +/** + * Checks if the UTF-8 encoding is valid. + * + * @returns true / false. + * @param psz The string. + */ +RTDECL(bool) RTStrIsValidEncoding(const char *psz); + +/** + * Purge all bad UTF-8 encoding in the string, replacing it with '?'. + * + * @returns The number of bad characters (0 if nothing was done). + * @param psz The string to purge. + */ +RTDECL(size_t) RTStrPurgeEncoding(char *psz); + +/** + * Sanitizes a (valid) UTF-8 string by replacing all characters outside a white + * list in-place by an ASCII replacedment character. + * + * Multi-byte characters will be replaced byte by byte. + * + * @returns The number of code points replaced. In the case of an incorrectly + * encoded string -1 will be returned, and the string is not completely + * processed. In the case of puszValidPairs having an odd number of + * code points, -1 will be also return but without any modification to + * the string. + * @param psz The string to sanitise. + * @param puszValidPairs A zero-terminated array of pairs of Unicode points. + * Each pair is the start and end point of a range, + * and the union of these ranges forms the white list. + * @param chReplacement The ASCII replacement character. + */ +RTDECL(ssize_t) RTStrPurgeComplementSet(char *psz, PCRTUNICP puszValidPairs, char chReplacement); + +/** + * Gets the number of code points the string is made up of, excluding + * the terminator. + * + * + * @returns Number of code points (RTUNICP). + * @returns 0 if the string was incorrectly encoded. + * @param psz The string. + */ +RTDECL(size_t) RTStrUniLen(const char *psz); + +/** + * Gets the number of code points the string is made up of, excluding + * the terminator. + * + * This function will validate the string, and incorrectly encoded UTF-8 + * strings will be rejected. + * + * @returns iprt status code. + * @param psz The string. + * @param cch The max string length. Use RTSTR_MAX to process the entire string. + * @param pcuc Where to store the code point count. + * This is undefined on failure. + */ +RTDECL(int) RTStrUniLenEx(const char *psz, size_t cch, size_t *pcuc); + +/** + * Translate a UTF-8 string into an unicode string (i.e. RTUNICPs), allocating the string buffer. + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param ppUniString Receives pointer to the allocated unicode string. + * The returned string must be freed using RTUniFree(). + */ +RTDECL(int) RTStrToUni(const char *pszString, PRTUNICP *ppUniString); + +/** + * Translates pszString from UTF-8 to an array of code points, allocating the result + * array if requested. + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. The conversion stop + * when it reaches cchString or the string terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppaCps If cCps is non-zero, this must either be pointing to pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppusz is NULL or cCps is zero a buffer of at least cCps items + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTUtf16Free(). + * @param cCps The number of code points in the unicode string. This includes the terminator. + * @param pcCps Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +RTDECL(int) RTStrToUniEx(const char *pszString, size_t cchString, PRTUNICP *ppaCps, size_t cCps, size_t *pcCps); + +/** + * Calculates the length of the string in RTUTF16 items. + * + * This function will validate the string, and incorrectly encoded UTF-8 + * strings will be rejected. The primary purpose of this function is to + * help allocate buffers for RTStrToUtf16Ex of the correct size. For most + * other purposes RTStrCalcUtf16LenEx() should be used. + * + * @returns Number of RTUTF16 items. + * @returns 0 if the string was incorrectly encoded. + * @param psz The string. + */ +RTDECL(size_t) RTStrCalcUtf16Len(const char *psz); + +/** + * Calculates the length of the string in RTUTF16 items. + * + * This function will validate the string, and incorrectly encoded UTF-8 + * strings will be rejected. + * + * @returns iprt status code. + * @param psz The string. + * @param cch The max string length. Use RTSTR_MAX to process the entire string. + * @param pcwc Where to store the string length. Optional. + * This is undefined on failure. + */ +RTDECL(int) RTStrCalcUtf16LenEx(const char *psz, size_t cch, size_t *pcwc); + +/** + * Translate a UTF-8 string into a UTF-16 allocating the result buffer (default + * tag). + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param ppwszString Receives pointer to the allocated UTF-16 string. + * The returned string must be freed using RTUtf16Free(). + */ +#define RTStrToUtf16(pszString, ppwszString) RTStrToUtf16Tag((pszString), (ppwszString), RTSTR_TAG) + +/** + * Translate a UTF-8 string into a UTF-16 allocating the result buffer (custom + * tag). + * + * This differs from RTStrToUtf16 in that it always produces a + * big-endian string. + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param ppwszString Receives pointer to the allocated UTF-16 string. + * The returned string must be freed using RTUtf16Free(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrToUtf16Tag(const char *pszString, PRTUTF16 *ppwszString, const char *pszTag); + +/** + * Translate a UTF-8 string into a UTF-16BE allocating the result buffer + * (default tag). + * + * This differs from RTStrToUtf16Tag in that it always produces a + * big-endian string. + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param ppwszString Receives pointer to the allocated UTF-16BE string. + * The returned string must be freed using RTUtf16Free(). + */ +#define RTStrToUtf16Big(pszString, ppwszString) RTStrToUtf16BigTag((pszString), (ppwszString), RTSTR_TAG) + +/** + * Translate a UTF-8 string into a UTF-16BE allocating the result buffer (custom + * tag). + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param ppwszString Receives pointer to the allocated UTF-16BE string. + * The returned string must be freed using RTUtf16Free(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrToUtf16BigTag(const char *pszString, PRTUTF16 *ppwszString, const char *pszTag); + +/** + * Translates pszString from UTF-8 to UTF-16, allocating the result buffer if requested. + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. The conversion stop + * when it reaches cchString or the string terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppwsz If cwc is non-zero, this must either be pointing to pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppwsz is NULL or cwc is zero a buffer of at least cwc items + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTUtf16Free(). + * @param cwc The buffer size in RTUTF16s. This includes the terminator. + * @param pcwc Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTStrToUtf16Ex(pszString, cchString, ppwsz, cwc, pcwc) \ + RTStrToUtf16ExTag((pszString), (cchString), (ppwsz), (cwc), (pcwc), RTSTR_TAG) + +/** + * Translates pszString from UTF-8 to UTF-16, allocating the result buffer if + * requested (custom tag). + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. The conversion stop + * when it reaches cchString or the string terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppwsz If cwc is non-zero, this must either be pointing to pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppwsz is NULL or cwc is zero a buffer of at least cwc items + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTUtf16Free(). + * @param cwc The buffer size in RTUTF16s. This includes the terminator. + * @param pcwc Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrToUtf16ExTag(const char *pszString, size_t cchString, + PRTUTF16 *ppwsz, size_t cwc, size_t *pcwc, const char *pszTag); + + +/** + * Translates pszString from UTF-8 to UTF-16BE, allocating the result buffer if requested. + * + * This differs from RTStrToUtf16Ex in that it always produces a + * big-endian string. + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. The conversion stop + * when it reaches cchString or the string terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppwsz If cwc is non-zero, this must either be pointing to pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppwsz is NULL or cwc is zero a buffer of at least cwc items + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTUtf16Free(). + * @param cwc The buffer size in RTUTF16s. This includes the terminator. + * @param pcwc Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTStrToUtf16BigEx(pszString, cchString, ppwsz, cwc, pcwc) \ + RTStrToUtf16BigExTag((pszString), (cchString), (ppwsz), (cwc), (pcwc), RTSTR_TAG) + +/** + * Translates pszString from UTF-8 to UTF-16BE, allocating the result buffer if + * requested (custom tag). + * + * This differs from RTStrToUtf16ExTag in that it always produces a + * big-endian string. + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. The conversion stop + * when it reaches cchString or the string terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppwsz If cwc is non-zero, this must either be pointing to pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppwsz is NULL or cwc is zero a buffer of at least cwc items + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTUtf16Free(). + * @param cwc The buffer size in RTUTF16s. This includes the terminator. + * @param pcwc Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrToUtf16BigExTag(const char *pszString, size_t cchString, + PRTUTF16 *ppwsz, size_t cwc, size_t *pcwc, const char *pszTag); + + +/** + * Calculates the length of the string in Latin-1 characters. + * + * This function will validate the string, and incorrectly encoded UTF-8 + * strings as well as string with codepoints outside the latin-1 range will be + * rejected. The primary purpose of this function is to help allocate buffers + * for RTStrToLatin1Ex of the correct size. For most other purposes + * RTStrCalcLatin1LenEx() should be used. + * + * @returns Number of Latin-1 characters. + * @returns 0 if the string was incorrectly encoded. + * @param psz The string. + */ +RTDECL(size_t) RTStrCalcLatin1Len(const char *psz); + +/** + * Calculates the length of the string in Latin-1 characters. + * + * This function will validate the string, and incorrectly encoded UTF-8 + * strings as well as string with codepoints outside the latin-1 range will be + * rejected. + * + * @returns iprt status code. + * @param psz The string. + * @param cch The max string length. Use RTSTR_MAX to process the + * entire string. + * @param pcch Where to store the string length. Optional. + * This is undefined on failure. + */ +RTDECL(int) RTStrCalcLatin1LenEx(const char *psz, size_t cch, size_t *pcch); + +/** + * Translate a UTF-8 string into a Latin-1 allocating the result buffer (default + * tag). + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param ppszString Receives pointer to the allocated Latin-1 string. + * The returned string must be freed using RTStrFree(). + */ +#define RTStrToLatin1(pszString, ppszString) RTStrToLatin1Tag((pszString), (ppszString), RTSTR_TAG) + +/** + * Translate a UTF-8 string into a Latin-1 allocating the result buffer (custom + * tag). + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param ppszString Receives pointer to the allocated Latin-1 string. + * The returned string must be freed using RTStrFree(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrToLatin1Tag(const char *pszString, char **ppszString, const char *pszTag); + +/** + * Translates pszString from UTF-8 to Latin-1, allocating the result buffer if requested. + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. + * The conversion stop when it reaches cchString or + * the string terminator ('\\0'). Use RTSTR_MAX to + * translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to + * pointer to a buffer of the specified size, or + * pointer to a NULL pointer. If *ppsz is NULL or cch + * is zero a buffer of at least cch items will be + * allocated to hold the translated string. If a + * buffer was requested it must be freed using + * RTStrFree(). + * @param cch The buffer size in bytes. This includes the + * terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTStrToLatin1Ex(pszString, cchString, ppsz, cch, pcch) \ + RTStrToLatin1ExTag((pszString), (cchString), (ppsz), (cch), (pcch), RTSTR_TAG) + +/** + * Translates pszString from UTF-8 to Latin1, allocating the result buffer if + * requested (custom tag). + * + * @returns iprt status code. + * @param pszString UTF-8 string to convert. + * @param cchString The maximum size in chars (the type) to convert. + * The conversion stop when it reaches cchString or + * the string terminator ('\\0'). Use RTSTR_MAX to + * translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to + * pointer to a buffer of the specified size, or + * pointer to a NULL pointer. If *ppsz is NULL or cch + * is zero a buffer of at least cch items will be + * allocated to hold the translated string. If a + * buffer was requested it must be freed using + * RTStrFree(). + * @param cch The buffer size in bytes. This includes the + * terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrToLatin1ExTag(const char *pszString, size_t cchString, char **ppsz, size_t cch, size_t *pcch, const char *pszTag); + +/** + * Get the unicode code point at the given string position. + * + * @returns unicode code point. + * @returns RTUNICP_INVALID if the encoding is invalid. + * @param psz The string. + */ +RTDECL(RTUNICP) RTStrGetCpInternal(const char *psz); + +/** + * Get the unicode code point at the given string position. + * + * @returns iprt status code + * @returns VERR_INVALID_UTF8_ENCODING if the encoding is invalid. + * @param ppsz The string cursor. + * This is advanced one character forward on failure. + * @param pCp Where to store the unicode code point. + * Stores RTUNICP_INVALID if the encoding is invalid. + */ +RTDECL(int) RTStrGetCpExInternal(const char **ppsz, PRTUNICP pCp); + +/** + * Get the unicode code point at the given string position for a string of a + * given length. + * + * @returns iprt status code + * @retval VERR_INVALID_UTF8_ENCODING if the encoding is invalid. + * @retval VERR_END_OF_STRING if *pcch is 0. *pCp is set to RTUNICP_INVALID. + * + * @param ppsz The string. + * @param pcch Pointer to the length of the string. This will be + * decremented by the size of the code point. + * @param pCp Where to store the unicode code point. + * Stores RTUNICP_INVALID if the encoding is invalid. + */ +RTDECL(int) RTStrGetCpNExInternal(const char **ppsz, size_t *pcch, PRTUNICP pCp); + +/** + * Put the unicode code point at the given string position + * and return the pointer to the char following it. + * + * This function will not consider anything at or following the + * buffer area pointed to by psz. It is therefore not suitable for + * inserting code points into a string, only appending/overwriting. + * + * @returns pointer to the char following the written code point. + * @param psz The string. + * @param CodePoint The code point to write. + * This should not be RTUNICP_INVALID or any other + * character out of the UTF-8 range. + * + * @remark This is a worker function for RTStrPutCp(). + * + */ +RTDECL(char *) RTStrPutCpInternal(char *psz, RTUNICP CodePoint); + +/** + * Get the unicode code point at the given string position. + * + * @returns unicode code point. + * @returns RTUNICP_INVALID if the encoding is invalid. + * @param psz The string. + * + * @remark We optimize this operation by using an inline function for + * the most frequent and simplest sequence, the rest is + * handled by RTStrGetCpInternal(). + */ +DECLINLINE(RTUNICP) RTStrGetCp(const char *psz) +{ + const unsigned char uch = *(const unsigned char *)psz; + if (!(uch & RT_BIT(7))) + return uch; + return RTStrGetCpInternal(psz); +} + +/** + * Get the unicode code point at the given string position. + * + * @returns iprt status code. + * @param ppsz Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * This is advanced one character forward on failure. + * @param pCp Where to store the code point. + * RTUNICP_INVALID is stored here on failure. + * + * @remark We optimize this operation by using an inline function for + * the most frequent and simplest sequence, the rest is + * handled by RTStrGetCpExInternal(). + */ +DECLINLINE(int) RTStrGetCpEx(const char **ppsz, PRTUNICP pCp) +{ + const unsigned char uch = **(const unsigned char **)ppsz; + if (!(uch & RT_BIT(7))) + { + (*ppsz)++; + *pCp = uch; + return VINF_SUCCESS; + } + return RTStrGetCpExInternal(ppsz, pCp); +} + +/** + * Get the unicode code point at the given string position for a string of a + * given maximum length. + * + * @returns iprt status code. + * @retval VERR_INVALID_UTF8_ENCODING if the encoding is invalid. + * @retval VERR_END_OF_STRING if *pcch is 0. *pCp is set to RTUNICP_INVALID. + * + * @param ppsz Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * @param pcch Pointer to the maximum string length. This will be + * decremented by the size of the code point found. + * @param pCp Where to store the code point. + * RTUNICP_INVALID is stored here on failure. + * + * @remark We optimize this operation by using an inline function for + * the most frequent and simplest sequence, the rest is + * handled by RTStrGetCpNExInternal(). + */ +DECLINLINE(int) RTStrGetCpNEx(const char **ppsz, size_t *pcch, PRTUNICP pCp) +{ + if (RT_LIKELY(*pcch != 0)) + { + const unsigned char uch = **(const unsigned char **)ppsz; + if (!(uch & RT_BIT(7))) + { + (*ppsz)++; + (*pcch)--; + *pCp = uch; + return VINF_SUCCESS; + } + } + return RTStrGetCpNExInternal(ppsz, pcch, pCp); +} + +/** + * Get the UTF-8 size in characters of a given Unicode code point. + * + * The code point is expected to be a valid Unicode one, but not necessarily in + * the range supported by UTF-8. + * + * @returns The number of chars (bytes) required to encode the code point, or + * zero if there is no UTF-8 encoding. + * @param CodePoint The unicode code point. + */ +DECLINLINE(size_t) RTStrCpSize(RTUNICP CodePoint) +{ + if (CodePoint < 0x00000080) + return 1; + if (CodePoint < 0x00000800) + return 2; + if (CodePoint < 0x00010000) + return 3; +#ifdef RT_USE_RTC_3629 + if (CodePoint < 0x00011000) + return 4; +#else + if (CodePoint < 0x00200000) + return 4; + if (CodePoint < 0x04000000) + return 5; + if (CodePoint < 0x7fffffff) + return 6; +#endif + return 0; +} + +/** + * Put the unicode code point at the given string position + * and return the pointer to the char following it. + * + * This function will not consider anything at or following the + * buffer area pointed to by psz. It is therefore not suitable for + * inserting code points into a string, only appending/overwriting. + * + * @returns pointer to the char following the written code point. + * @param psz The string. + * @param CodePoint The code point to write. + * This should not be RTUNICP_INVALID or any other + * character out of the UTF-8 range. + * + * @remark We optimize this operation by using an inline function for + * the most frequent and simplest sequence, the rest is + * handled by RTStrPutCpInternal(). + */ +DECLINLINE(char *) RTStrPutCp(char *psz, RTUNICP CodePoint) +{ + if (CodePoint < 0x80) + { + *psz++ = (char)CodePoint; + return psz; + } + return RTStrPutCpInternal(psz, CodePoint); +} + +/** + * Skips ahead, past the current code point. + * + * @returns Pointer to the char after the current code point. + * @param psz Pointer to the current code point. + * @remark This will not move the next valid code point, only past the current one. + */ +DECLINLINE(char *) RTStrNextCp(const char *psz) +{ + RTUNICP Cp; + RTStrGetCpEx(&psz, &Cp); + return (char *)psz; +} + +/** + * Skips back to the previous code point. + * + * @returns Pointer to the char before the current code point. + * @returns pszStart on failure. + * @param pszStart Pointer to the start of the string. + * @param psz Pointer to the current code point. + */ +RTDECL(char *) RTStrPrevCp(const char *pszStart, const char *psz); + + +/** @page pg_rt_str_format The IPRT Format Strings + * + * IPRT implements most of the commonly used format types and flags with the + * exception of floating point which is completely missing. In addition IPRT + * provides a number of IPRT specific format types for the IPRT typedefs and + * other useful things. Note that several of these extensions are similar to + * \%p and doesn't care much if you try add formating flags/width/precision. + * + * + * Group 0a, The commonly used format types: + * - \%s - Takes a pointer to a zero terminated string (UTF-8) and + * prints it with the optionally adjustment (width, -) and + * length restriction (precision). + * - \%ls - Same as \%s except that the input is UTF-16 (output UTF-8). + * - \%Ls - Same as \%s except that the input is UCS-32 (output UTF-8). + * - \%S - Same as \%s, used to convert to current codeset but this is + * now done by the streams code. Deprecated, use \%s. + * - \%lS - Ditto. Deprecated, use \%ls. + * - \%LS - Ditto. Deprecated, use \%Ls. + * - \%c - Takes a char and prints it. + * - \%d - Takes a signed integer and prints it as decimal. Thousand + * separator (\'), zero padding (0), adjustment (-+), width, + * precision + * - \%i - Same as \%d. + * - \%u - Takes an unsigned integer and prints it as decimal. Thousand + * separator (\'), zero padding (0), adjustment (-+), width, + * precision + * - \%x - Takes an unsigned integer and prints it as lowercased + * hexadecimal. The special hash (\#) flag causes a '0x' + * prefixed to be printed. Zero padding (0), adjustment (-+), + * width, precision. + * - \%X - Same as \%x except that it is uppercased. + * - \%o - Takes an unsigned (?) integer and prints it as octal. Zero + * padding (0), adjustment (-+), width, precision. + * - \%p - Takes a pointer (void technically) and prints it. Zero + * padding (0), adjustment (-+), width, precision. + * + * The \%d, \%i, \%u, \%x, \%X and \%o format types support the following + * argument type specifiers: + * - \%ll - long long (uint64_t). + * - \%L - long long (uint64_t). + * - \%l - long (uint32_t, uint64_t) + * - \%h - short (int16_t). + * - \%hh - char (int8_t). + * - \%H - char (int8_t). + * - \%z - size_t. + * - \%j - intmax_t (int64_t). + * - \%t - ptrdiff_t. + * The type in parentheses is typical sizes, however when printing those types + * you are better off using the special group 2 format types below (\%RX32 and + * such). + * + * + * Group 0b, IPRT format tricks: + * - %M - Replaces the format string, takes a string pointer. + * - %N - Nested formatting, takes a pointer to a format string + * followed by the pointer to a va_list variable. The va_list + * variable will not be modified and the caller must do va_end() + * on it. Make sure the va_list variable is NOT in a parameter + * list or some gcc versions/targets may get it all wrong. + * + * + * Group 1, the basic runtime typedefs (excluding those which obviously are + * pointer): + * - \%RTbool - Takes a bool value and prints 'true', 'false', or '!%d!'. + * - \%RTeic - Takes a #PCRTERRINFO value outputting 'rc: msg', + * or 'rc - msg' with the \# flag. + * - \%RTeim - Takes a #PCRTERRINFO value outputting ': msg', or + * ' - msg' with the \# flag. + * - \%RTfile - Takes a #RTFILE value. + * - \%RTfmode - Takes a #RTFMODE value. + * - \%RTfoff - Takes a #RTFOFF value. + * - \%RTfp16 - Takes a #RTFAR16 value. + * - \%RTfp32 - Takes a #RTFAR32 value. + * - \%RTfp64 - Takes a #RTFAR64 value. + * - \%RTgid - Takes a #RTGID value. + * - \%RTino - Takes a #RTINODE value. + * - \%RTint - Takes a #RTINT value. + * - \%RTiop - Takes a #RTIOPORT value. + * - \%RTldrm - Takes a #RTLDRMOD value. + * - \%RTmac - Takes a #PCRTMAC pointer. + * - \%RTnaddr - Takes a #PCRTNETADDR value. + * - \%RTnaipv4 - Takes a #RTNETADDRIPV4 value. + * - \%RTnaipv6 - Takes a #PCRTNETADDRIPV6 value. + * - \%RTnthrd - Takes a #RTNATIVETHREAD value. + * - \%RTnthrd - Takes a #RTNATIVETHREAD value. + * - \%RTproc - Takes a #RTPROCESS value. + * - \%RTptr - Takes a #RTINTPTR or #RTUINTPTR value (but not void *). + * - \%RTreg - Takes a #RTCCUINTREG value. + * - \%RTsel - Takes a #RTSEL value. + * - \%RTsem - Takes a #RTSEMEVENT, #RTSEMEVENTMULTI, #RTSEMMUTEX, #RTSEMFASTMUTEX, or #RTSEMRW value. + * - \%RTsock - Takes a #RTSOCKET value. + * - \%RTthrd - Takes a #RTTHREAD value. + * - \%RTuid - Takes a #RTUID value. + * - \%RTuint - Takes a #RTUINT value. + * - \%RTunicp - Takes a #RTUNICP value. + * - \%RTutf16 - Takes a #RTUTF16 value. + * - \%RTuuid - Takes a #PCRTUUID and will print the UUID as a string. + * - \%RTxuint - Takes a #RTUINT or #RTINT value, formatting it as hex. + * - \%RGi - Takes a #RTGCINT value. + * - \%RGp - Takes a #RTGCPHYS value. + * - \%RGr - Takes a #RTGCUINTREG value. + * - \%RGu - Takes a #RTGCUINT value. + * - \%RGv - Takes a #RTGCPTR, #RTGCINTPTR or #RTGCUINTPTR value. + * - \%RGx - Takes a #RTGCUINT or #RTGCINT value, formatting it as hex. + * - \%RHi - Takes a #RTHCINT value. + * - \%RHp - Takes a #RTHCPHYS value. + * - \%RHr - Takes a #RTHCUINTREG value. + * - \%RHu - Takes a #RTHCUINT value. + * - \%RHv - Takes a #RTHCPTR, #RTHCINTPTR or #RTHCUINTPTR value. + * - \%RHx - Takes a #RTHCUINT or #RTHCINT value, formatting it as hex. + * - \%RRv - Takes a #RTRCPTR, #RTRCINTPTR or #RTRCUINTPTR value. + * - \%RCi - Takes a #RTINT value. + * - \%RCp - Takes a #RTCCPHYS value. + * - \%RCr - Takes a #RTCCUINTREG value. + * - \%RCu - Takes a #RTUINT value. + * - \%RCv - Takes a #uintptr_t, #intptr_t, void * value. + * - \%RCx - Takes a #RTUINT or #RTINT value, formatting it as hex. + * + * + * Group 2, the generic integer types which are prefered over relying on what + * bit-count a 'long', 'short', or 'long long' has on a platform. This are + * highly prefered for the [u]intXX_t kind of types: + * - \%RI[8|16|32|64] - Signed integer value of the specifed bit count. + * - \%RU[8|16|32|64] - Unsigned integer value of the specifed bit count. + * - \%RX[8|16|32|64] - Hexadecimal integer value of the specifed bit count. + * + * + * Group 3, hex dumpers and other complex stuff which requires more than simple + * formatting: + * - \%Rhxd - Takes a pointer to the memory which is to be dumped in typical + * hex format. Use the precision to specify the length, and the width to + * set the number of bytes per line. Default width and precision is 16. + * - \%RhxD - Same as \%Rhxd, except that it skips duplicate lines. + * - \%Rhxs - Takes a pointer to the memory to be displayed as a hex string, + * i.e. a series of space separated bytes formatted as two digit hex value. + * Use the precision to specify the length. Default length is 16 bytes. + * The width, if specified, is ignored. + * The space separtor can get change to a colon by + * using the ' flag, and removed entirely using \#. + * - \%RhXd - Same as \%Rhxd, but takes an additional uint64_t + * value with the memory start address/offset after + * the memory pointer. + * - \%RhXD - Same as \%RhxD, but takes an additional uint64_t + * value with the memory start address/offset after + * the memory pointer. + * - \%RhXs - Same as \%Rhxs, but takes an additional uint64_t + * value with the memory start address/offset after + * the memory pointer. + * + * - \%Rhcb - Human readable byte size formatting, using + * binary unit prefixes (GiB, MiB and such). Takes a + * 64-bit unsigned integer as input. Does one + * decimal point by default, can do 0-3 via precision + * field. No rounding when calculating fraction. + * The space flag add a space between the value and + * unit. + * - \%RhcB - Same a \%Rhcb only the 'i' is skipped in the unit. + * - \%Rhci - SI variant of \%Rhcb, fraction is rounded. + * - \%Rhub - Human readable number formatting, using + * binary unit prefixes. Takes a 64-bit unsigned + * integer as input. Does one decimal point by + * default, can do 0-3 via precision field. No + * rounding when calculating fraction. The space + * flag add a space between the value and unit. + * - \%RhuB - Same a \%Rhub only the 'i' is skipped in the unit. + * - \%Rhui - SI variant of \%Rhub, fraction is rounded. + * + * - \%Rrc - Takes an integer iprt status code as argument. Will insert the + * status code define corresponding to the iprt status code. + * - \%Rrs - Takes an integer iprt status code as argument. Will insert the + * short description of the specified status code. + * - \%Rrf - Takes an integer iprt status code as argument. Will insert the + * full description of the specified status code. + * Note! Works like \%Rrs when IN_RT_STATIC is defined (so please avoid). + * - \%Rra - Takes an integer iprt status code as argument. Will insert the + * status code define + full description. + * Note! Reduced output when IN_RT_STATIC is defined (so please avoid). + * - \%Rwc - Takes a long Windows error code as argument. Will insert the status + * code define corresponding to the Windows error code. + * - \%Rwf - Takes a long Windows error code as argument. Will insert the + * full description of the specified status code. + * Note! Works like \%Rwc when IN_RT_STATIC is defined. + * - \%Rwa - Takes a long Windows error code as argument. Will insert the + * error code define + full description. + * Note! Reduced output when IN_RT_STATIC is defined (so please avoid). + * + * - \%Rhrc - Takes a COM/XPCOM status code as argument. Will insert the status + * code define corresponding to the Windows error code. + * - \%Rhrf - Takes a COM/XPCOM status code as argument. Will insert the + * full description of the specified status code. + * Note! Works like \%Rhrc when IN_RT_STATIC is + * defined on Windows (so please avoid). + * - \%Rhra - Takes a COM/XPCOM error code as argument. Will insert the + * error code define + full description. + * Note! Reduced output when IN_RT_STATIC is defined on Windows (so please avoid). + * + * - \%Rfn - Pretty printing of a function or method. It drops the + * return code and parameter list. + * - \%Rbn - Prints the base name. For dropping the path in + * order to save space when printing a path name. + * + * - \%lRbs - Same as \%ls except inlut is big endian UTF-16. + * + * On other platforms, \%Rw? simply prints the argument in a form of 0xXXXXXXXX. + * + * + * Group 4, structure dumpers: + * - \%RDtimespec - Takes a PCRTTIMESPEC. + * + * + * Group 5, XML / HTML, JSON and URI escapers: + * - \%RMas - Takes a string pointer (const char *) and outputs + * it as an attribute value with the proper escaping. + * This typically ends up in double quotes. + * + * - \%RMes - Takes a string pointer (const char *) and outputs + * it as an element with the necessary escaping. + * + * - \%RMjs - Takes a string pointer (const char *) and outputs + * it in quotes with proper JSON escaping. + * + * - \%RMpa - Takes a string pointer (const char *) and outputs + * it percent-encoded (RFC-3986). All reserved characters + * are encoded. + * + * - \%RMpf - Takes a string pointer (const char *) and outputs + * it percent-encoded (RFC-3986), form style. This + * means '+' is used to escape space (' ') and '%2B' + * is used to escape '+'. + * + * - \%RMpp - Takes a string pointer (const char *) and outputs + * it percent-encoded (RFC-3986), path style. This + * means '/' will not be escaped. + * + * - \%RMpq - Takes a string pointer (const char *) and outputs + * it percent-encoded (RFC-3986), query style. This + * means '+' will not be escaped. + * + * + * Group 6, CPU Architecture Register dumpers: + * - \%RAx86[reg] - Takes a 64-bit register value if the register is + * 64-bit or smaller. Check the code wrt which + * registers are implemented. + * + */ + +#ifndef DECLARED_FNRTSTROUTPUT /* duplicated in iprt/log.h & errcore.h */ +# define DECLARED_FNRTSTROUTPUT +/** + * Output callback. + * + * @returns number of bytes written. + * @param pvArg User argument. + * @param pachChars Pointer to an array of utf-8 characters. + * @param cbChars Number of bytes in the character array pointed to by pachChars. + */ +typedef DECLCALLBACKTYPE(size_t, FNRTSTROUTPUT,(void *pvArg, const char *pachChars, size_t cbChars)); +/** Pointer to callback function. */ +typedef FNRTSTROUTPUT *PFNRTSTROUTPUT; +#endif + +/** @name Format flag. + * These are used by RTStrFormat extensions and RTStrFormatNumber, mind + * that not all flags makes sense to both of the functions. + * @{ */ +#define RTSTR_F_CAPITAL 0x0001 +#define RTSTR_F_LEFT 0x0002 +#define RTSTR_F_ZEROPAD 0x0004 +#define RTSTR_F_SPECIAL 0x0008 +#define RTSTR_F_VALSIGNED 0x0010 +#define RTSTR_F_PLUS 0x0020 +#define RTSTR_F_BLANK 0x0040 +#define RTSTR_F_WIDTH 0x0080 +#define RTSTR_F_PRECISION 0x0100 +#define RTSTR_F_THOUSAND_SEP 0x0200 +#define RTSTR_F_OBFUSCATE_PTR 0x0400 + +#define RTSTR_F_BIT_MASK 0xf800 +#define RTSTR_F_8BIT 0x0800 +#define RTSTR_F_16BIT 0x1000 +#define RTSTR_F_32BIT 0x2000 +#define RTSTR_F_64BIT 0x4000 +#define RTSTR_F_128BIT 0x8000 +/** @} */ + +/** @def RTSTR_GET_BIT_FLAG + * Gets the bit flag for the specified type. + */ +#define RTSTR_GET_BIT_FLAG(type) \ + ( sizeof(type) * 8 == 32 ? RTSTR_F_32BIT \ + : sizeof(type) * 8 == 64 ? RTSTR_F_64BIT \ + : sizeof(type) * 8 == 16 ? RTSTR_F_16BIT \ + : sizeof(type) * 8 == 8 ? RTSTR_F_8BIT \ + : sizeof(type) * 8 == 128 ? RTSTR_F_128BIT \ + : 0) + + +/** + * Callback to format non-standard format specifiers. + * + * @returns The number of bytes formatted. + * @param pvArg Formatter argument. + * @param pfnOutput Pointer to output function. + * @param pvArgOutput Argument for the output function. + * @param ppszFormat Pointer to the format string pointer. Advance this till the char + * after the format specifier. + * @param pArgs Pointer to the argument list. Use this to fetch the arguments. + * @param cchWidth Format Width. -1 if not specified. + * @param cchPrecision Format Precision. -1 if not specified. + * @param fFlags Flags (RTSTR_NTFS_*). + * @param chArgSize The argument size specifier, 'l' or 'L'. + */ +typedef DECLCALLBACKTYPE(size_t, FNSTRFORMAT,(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, + const char **ppszFormat, va_list *pArgs, int cchWidth, + int cchPrecision, unsigned fFlags, char chArgSize)); +/** Pointer to a FNSTRFORMAT() function. */ +typedef FNSTRFORMAT *PFNSTRFORMAT; + + +/** + * Partial implementation of a printf like formatter. + * It doesn't do everything correct, and there is no floating point support. + * However, it supports custom formats by the means of a format callback. + * + * @returns number of bytes formatted. + * @param pfnOutput Output worker. + * Called in two ways. Normally with a string and its length. + * For termination, it's called with NULL for string, 0 for length. + * @param pvArgOutput Argument to the output worker. + * @param pfnFormat Custom format worker. + * @param pvArgFormat Argument to the format worker. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param InArgs Argument list. + */ +RTDECL(size_t) RTStrFormatV(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PFNSTRFORMAT pfnFormat, void *pvArgFormat, + const char *pszFormat, va_list InArgs) RT_IPRT_FORMAT_ATTR(5, 0); + +/** + * Partial implementation of a printf like formatter. + * + * It doesn't do everything correct, and there is no floating point support. + * However, it supports custom formats by the means of a format callback. + * + * @returns number of bytes formatted. + * @param pfnOutput Output worker. + * Called in two ways. Normally with a string and its length. + * For termination, it's called with NULL for string, 0 for length. + * @param pvArgOutput Argument to the output worker. + * @param pfnFormat Custom format worker. + * @param pvArgFormat Argument to the format worker. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... Argument list. + */ +RTDECL(size_t) RTStrFormat(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PFNSTRFORMAT pfnFormat, void *pvArgFormat, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6); + +/** + * Formats an integer number according to the parameters. + * + * @returns Length of the formatted number. + * @param psz Pointer to output string buffer of sufficient size. + * @param u64Value Value to format. + * @param uiBase Number representation base. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(int) RTStrFormatNumber(char *psz, uint64_t u64Value, unsigned int uiBase, signed int cchWidth, signed int cchPrecision, + unsigned int fFlags); + +/** + * Formats an unsigned 8-bit number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param u8Value The value to format. + * @param uiBase Number representation base. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(ssize_t) RTStrFormatU8(char *pszBuf, size_t cbBuf, uint8_t u8Value, unsigned int uiBase, + signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an unsigned 16-bit number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param u16Value The value to format. + * @param uiBase Number representation base. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(ssize_t) RTStrFormatU16(char *pszBuf, size_t cbBuf, uint16_t u16Value, unsigned int uiBase, + signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an unsigned 32-bit number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param u32Value The value to format. + * @param uiBase Number representation base. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(ssize_t) RTStrFormatU32(char *pszBuf, size_t cbBuf, uint32_t u32Value, unsigned int uiBase, + signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an unsigned 64-bit number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param u64Value The value to format. + * @param uiBase Number representation base. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(ssize_t) RTStrFormatU64(char *pszBuf, size_t cbBuf, uint64_t u64Value, unsigned int uiBase, + signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an unsigned 128-bit number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pu128Value The value to format. + * @param uiBase Number representation base. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + * @remarks The current implementation is limited to base 16 and doesn't do + * width or precision and probably ignores few flags too. + */ +RTDECL(ssize_t) RTStrFormatU128(char *pszBuf, size_t cbBuf, PCRTUINT128U pu128Value, unsigned int uiBase, + signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an unsigned 256-bit number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pu256Value The value to format. + * @param uiBase Number representation base. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + * @remarks The current implementation is limited to base 16 and doesn't do + * width or precision and probably ignores few flags too. + */ +RTDECL(ssize_t) RTStrFormatU256(char *pszBuf, size_t cbBuf, PCRTUINT256U pu256Value, unsigned int uiBase, + signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an unsigned 512-bit number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pu512Value The value to format. + * @param uiBase Number representation base. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + * @remarks The current implementation is limited to base 16 and doesn't do + * width or precision and probably ignores few flags too. + */ +RTDECL(ssize_t) RTStrFormatU512(char *pszBuf, size_t cbBuf, PCRTUINT512U pu512Value, unsigned int uiBase, + signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an 32-bit extended floating point number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pr32Value The value to format. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(ssize_t) RTStrFormatR32(char *pszBuf, size_t cbBuf, PCRTFLOAT32U pr32Value, signed int cchWidth, + signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an 64-bit extended floating point number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pr64Value The value to format. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(ssize_t) RTStrFormatR64(char *pszBuf, size_t cbBuf, PCRTFLOAT64U pr64Value, signed int cchWidth, + signed int cchPrecision, uint32_t fFlags); + +#if !defined(__IBMCPP__) && !defined(__IBMC__) + +/** + * Formats an 80-bit extended floating point number. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pr80Value The value to format. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(ssize_t) RTStrFormatR80(char *pszBuf, size_t cbBuf, PCRTFLOAT80U pr80Value, signed int cchWidth, + signed int cchPrecision, uint32_t fFlags); + +/** + * Formats an 80-bit extended floating point number, version 2. + * + * @returns The length of the formatted number or VERR_BUFFER_OVERFLOW. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pr80Value The value to format. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags, RTSTR_F_XXX. + */ +RTDECL(ssize_t) RTStrFormatR80u2(char *pszBuf, size_t cbBuf, PCRTFLOAT80U2 pr80Value, signed int cchWidth, + signed int cchPrecision, uint32_t fFlags); + +#endif /* uint16_t bitfields doesn't work */ + + +/** + * Callback for formatting a type. + * + * This is registered using the RTStrFormatTypeRegister function and will + * be called during string formatting to handle the specified %R[type]. + * The argument for this format type is assumed to be a pointer and it's + * passed in the @a pvValue argument. + * + * @returns Length of the formatted output. + * @param pfnOutput Output worker. + * @param pvArgOutput Argument to the output worker. + * @param pszType The type name. + * @param pvValue The argument value. + * @param cchWidth Width. + * @param cchPrecision Precision. + * @param fFlags Flags (NTFS_*). + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(size_t, FNRTSTRFORMATTYPE,(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, + const char *pszType, void const *pvValue, + int cchWidth, int cchPrecision, unsigned fFlags, + void *pvUser)); +/** Pointer to a FNRTSTRFORMATTYPE. */ +typedef FNRTSTRFORMATTYPE *PFNRTSTRFORMATTYPE; + + +/** + * Register a format handler for a type. + * + * The format handler is used to handle '%R[type]' format types, where the argument + * in the vector is a pointer value (a bit restrictive, but keeps it simple). + * + * The caller must ensure that no other thread will be making use of any of + * the dynamic formatting type facilities simultaneously with this call. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_ALREADY_EXISTS if the type has already been registered. + * @retval VERR_TOO_MANY_OPEN_FILES if all the type slots has been allocated already. + * + * @param pszType The type name. + * @param pfnHandler The handler address. See FNRTSTRFORMATTYPE for details. + * @param pvUser The user argument to pass to the handler. See RTStrFormatTypeSetUser + * for how to update this later. + */ +RTDECL(int) RTStrFormatTypeRegister(const char *pszType, PFNRTSTRFORMATTYPE pfnHandler, void *pvUser); + +/** + * Deregisters a format type. + * + * The caller must ensure that no other thread will be making use of any of + * the dynamic formatting type facilities simultaneously with this call. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_FILE_NOT_FOUND if not found. + * + * @param pszType The type to deregister. + */ +RTDECL(int) RTStrFormatTypeDeregister(const char *pszType); + +/** + * Sets the user argument for a type. + * + * This can be used if a user argument needs relocating in GC. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_FILE_NOT_FOUND if not found. + * + * @param pszType The type to update. + * @param pvUser The new user argument value. + */ +RTDECL(int) RTStrFormatTypeSetUser(const char *pszType, void *pvUser); + + +/** + * String printf. + * + * @returns The length of the returned string (in pszBuffer) excluding the + * terminator. + * @param pszBuffer Output buffer. + * @param cchBuffer Size of the output buffer. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + * + * @deprecated Use RTStrPrintf2V! Problematic return value on overflow. + */ +RTDECL(size_t) RTStrPrintfV(char *pszBuffer, size_t cchBuffer, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * String printf. + * + * @returns The length of the returned string (in pszBuffer) excluding the + * terminator. + * @param pszBuffer Output buffer. + * @param cchBuffer Size of the output buffer. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + * + * @deprecated Use RTStrPrintf2! Problematic return value on overflow. + */ +RTDECL(size_t) RTStrPrintf(char *pszBuffer, size_t cchBuffer, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * String printf with custom formatting. + * + * @returns The length of the returned string (in pszBuffer) excluding the + * terminator. + * @param pfnFormat Pointer to handler function for the custom formats. + * @param pvArg Argument to the pfnFormat function. + * @param pszBuffer Output buffer. + * @param cchBuffer Size of the output buffer. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + * + * @deprecated Use RTStrPrintf2ExV! Problematic return value on overflow. + */ +RTDECL(size_t) RTStrPrintfExV(PFNSTRFORMAT pfnFormat, void *pvArg, char *pszBuffer, size_t cchBuffer, + const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(5, 0); + +/** + * String printf with custom formatting. + * + * @returns The length of the returned string (in pszBuffer) excluding the + * terminator. + * @param pfnFormat Pointer to handler function for the custom formats. + * @param pvArg Argument to the pfnFormat function. + * @param pszBuffer Output buffer. + * @param cchBuffer Size of the output buffer. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + * + * @deprecated Use RTStrPrintf2Ex! Problematic return value on overflow. + */ +RTDECL(size_t) RTStrPrintfEx(PFNSTRFORMAT pfnFormat, void *pvArg, char *pszBuffer, size_t cchBuffer, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6); + +/** + * String printf, version 2. + * + * @returns On success, positive count of formatted character excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator char). + * + * @param pszBuffer Output buffer. + * @param cbBuffer Size of the output buffer. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + */ +RTDECL(ssize_t) RTStrPrintf2V(char *pszBuffer, size_t cbBuffer, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * String printf, version 2. + * + * @returns On success, positive count of formatted character excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator char). + * + * @param pszBuffer Output buffer. + * @param cbBuffer Size of the output buffer. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + */ +RTDECL(ssize_t) RTStrPrintf2(char *pszBuffer, size_t cbBuffer, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * String printf with custom formatting, version 2. + * + * @returns On success, positive count of formatted character excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator char). + * + * @param pfnFormat Pointer to handler function for the custom formats. + * @param pvArg Argument to the pfnFormat function. + * @param pszBuffer Output buffer. + * @param cbBuffer Size of the output buffer. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + */ +RTDECL(ssize_t) RTStrPrintf2ExV(PFNSTRFORMAT pfnFormat, void *pvArg, char *pszBuffer, size_t cbBuffer, + const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(5, 0); + +/** + * String printf with custom formatting, version 2. + * + * @returns On success, positive count of formatted character excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator char). + * + * @param pfnFormat Pointer to handler function for the custom formats. + * @param pvArg Argument to the pfnFormat function. + * @param pszBuffer Output buffer. + * @param cbBuffer Size of the output buffer. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + */ +RTDECL(ssize_t) RTStrPrintf2Ex(PFNSTRFORMAT pfnFormat, void *pvArg, char *pszBuffer, size_t cbBuffer, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6); + +/** + * Allocating string printf (default tag). + * + * @returns The length of the string in the returned *ppszBuffer excluding the + * terminator. + * @returns -1 on failure. + * @param ppszBuffer Where to store the pointer to the allocated output buffer. + * The buffer should be freed using RTStrFree(). + * On failure *ppszBuffer will be set to NULL. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + */ +#define RTStrAPrintfV(ppszBuffer, pszFormat, args) RTStrAPrintfVTag((ppszBuffer), (pszFormat), (args), RTSTR_TAG) + +/** + * Allocating string printf (custom tag). + * + * @returns The length of the string in the returned *ppszBuffer excluding the + * terminator. + * @returns -1 on failure. + * @param ppszBuffer Where to store the pointer to the allocated output buffer. + * The buffer should be freed using RTStrFree(). + * On failure *ppszBuffer will be set to NULL. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTStrAPrintfVTag(char **ppszBuffer, const char *pszFormat, va_list args, const char *pszTag) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Allocating string printf. + * + * @returns The length of the string in the returned *ppszBuffer excluding the + * terminator. + * @returns -1 on failure. + * @param ppszBuffer Where to store the pointer to the allocated output buffer. + * The buffer should be freed using RTStrFree(). + * On failure *ppszBuffer will be set to NULL. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(2, 3) RTStrAPrintf(char **ppszBuffer, const char *pszFormat, ...) +{ + int cbRet; + va_list va; + va_start(va, pszFormat); + cbRet = RTStrAPrintfVTag(ppszBuffer, pszFormat, va, RTSTR_TAG); + va_end(va); + return cbRet; +} + +/** + * Allocating string printf (custom tag). + * + * @returns The length of the string in the returned *ppszBuffer excluding the + * terminator. + * @returns -1 on failure. + * @param ppszBuffer Where to store the pointer to the allocated output buffer. + * The buffer should be freed using RTStrFree(). + * On failure *ppszBuffer will be set to NULL. + * @param pszTag Allocation tag used for statistics and such. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(3, 4) RTStrAPrintfTag(char **ppszBuffer, const char *pszTag, const char *pszFormat, ...) +{ + int cbRet; + va_list va; + va_start(va, pszFormat); + cbRet = RTStrAPrintfVTag(ppszBuffer, pszFormat, va, pszTag); + va_end(va); + return cbRet; +} + +/** + * Allocating string printf, version 2. + * + * @returns Formatted string. Use RTStrFree() to free it. NULL when out of + * memory. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + */ +#define RTStrAPrintf2V(pszFormat, args) RTStrAPrintf2VTag((pszFormat), (args), RTSTR_TAG) + +/** + * Allocating string printf, version 2. + * + * @returns Formatted string. Use RTStrFree() to free it. NULL when out of + * memory. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(char *) RTStrAPrintf2VTag(const char *pszFormat, va_list args, const char *pszTag) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Allocating string printf, version 2 (default tag). + * + * @returns Formatted string. Use RTStrFree() to free it. NULL when out of + * memory. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + */ +DECLINLINE(char *) RT_IPRT_FORMAT_ATTR(1, 2) RTStrAPrintf2(const char *pszFormat, ...) +{ + char *pszRet; + va_list va; + va_start(va, pszFormat); + pszRet = RTStrAPrintf2VTag(pszFormat, va, RTSTR_TAG); + va_end(va); + return pszRet; +} + +/** + * Allocating string printf, version 2 (custom tag). + * + * @returns Formatted string. Use RTStrFree() to free it. NULL when out of + * memory. + * @param pszTag Allocation tag used for statistics and such. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + */ +DECLINLINE(char *) RT_IPRT_FORMAT_ATTR(2, 3) RTStrAPrintf2Tag(const char *pszTag, const char *pszFormat, ...) +{ + char *pszRet; + va_list va; + va_start(va, pszFormat); + pszRet = RTStrAPrintf2VTag(pszFormat, va, pszTag); + va_end(va); + return pszRet; +} + +/** + * Strips blankspaces from both ends of the string. + * + * @returns Pointer to first non-blank char in the string. + * @param psz The string to strip. + */ +RTDECL(char *) RTStrStrip(char *psz); + +/** + * Strips blankspaces from the start of the string. + * + * @returns Pointer to first non-blank char in the string. + * @param psz The string to strip. + */ +RTDECL(char *) RTStrStripL(const char *psz); + +/** + * Strips blankspaces from the end of the string. + * + * @returns psz. + * @param psz The string to strip. + */ +RTDECL(char *) RTStrStripR(char *psz); + +/** + * String copy with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pszDst The destination buffer. + * @param cbDst The size of the destination buffer (in bytes). + * @param pszSrc The source string. NULL is not OK. + */ +RTDECL(int) RTStrCopy(char *pszDst, size_t cbDst, const char *pszSrc); + +/** + * String copy with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pszDst The destination buffer. + * @param cbDst The size of the destination buffer (in bytes). + * @param pszSrc The source string. NULL is not OK. + * @param cchSrcMax The maximum number of chars (not code points) to + * copy from the source string, not counting the + * terminator as usual. + */ +RTDECL(int) RTStrCopyEx(char *pszDst, size_t cbDst, const char *pszSrc, size_t cchSrcMax); + +/** + * String copy with overflow handling and buffer advancing. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param ppszDst Pointer to the destination buffer pointer. + * This will be advanced to the end of the copied + * bytes (points at the terminator). This is also + * updated on overflow. + * @param pcbDst Pointer to the destination buffer size + * variable. This will be updated in accord with + * the buffer pointer. + * @param pszSrc The source string. NULL is not OK. + */ +RTDECL(int) RTStrCopyP(char **ppszDst, size_t *pcbDst, const char *pszSrc); + +/** + * String copy with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param ppszDst Pointer to the destination buffer pointer. + * This will be advanced to the end of the copied + * bytes (points at the terminator). This is also + * updated on overflow. + * @param pcbDst Pointer to the destination buffer size + * variable. This will be updated in accord with + * the buffer pointer. + * @param pszSrc The source string. NULL is not OK. + * @param cchSrcMax The maximum number of chars (not code points) to + * copy from the source string, not counting the + * terminator as usual. + */ +RTDECL(int) RTStrCopyPEx(char **ppszDst, size_t *pcbDst, const char *pszSrc, size_t cchSrcMax); + +/** + * String concatenation with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pszDst The destination buffer. + * @param cbDst The size of the destination buffer (in bytes). + * @param pszSrc The source string. NULL is not OK. + */ +RTDECL(int) RTStrCat(char *pszDst, size_t cbDst, const char *pszSrc); + +/** + * String concatenation with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pszDst The destination buffer. + * @param cbDst The size of the destination buffer (in bytes). + * @param pszSrc The source string. NULL is not OK. + * @param cchSrcMax The maximum number of chars (not code points) to + * copy from the source string, not counting the + * terminator as usual. + */ +RTDECL(int) RTStrCatEx(char *pszDst, size_t cbDst, const char *pszSrc, size_t cchSrcMax); + +/** + * String concatenation with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param ppszDst Pointer to the destination buffer pointer. + * This will be advanced to the end of the copied + * bytes (points at the terminator). This is also + * updated on overflow. + * @param pcbDst Pointer to the destination buffer size + * variable. This will be updated in accord with + * the buffer pointer. + * @param pszSrc The source string. NULL is not OK. + */ +RTDECL(int) RTStrCatP(char **ppszDst, size_t *pcbDst, const char *pszSrc); + +/** + * String concatenation with overflow handling and buffer advancing. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param ppszDst Pointer to the destination buffer pointer. + * This will be advanced to the end of the copied + * bytes (points at the terminator). This is also + * updated on overflow. + * @param pcbDst Pointer to the destination buffer size + * variable. This will be updated in accord with + * the buffer pointer. + * @param pszSrc The source string. NULL is not OK. + * @param cchSrcMax The maximum number of chars (not code points) to + * copy from the source string, not counting the + * terminator as usual. + */ +RTDECL(int) RTStrCatPEx(char **ppszDst, size_t *pcbDst, const char *pszSrc, size_t cchSrcMax); + +/** + * Performs a case sensitive string compare between two UTF-8 strings. + * + * Encoding errors are ignored by the current implementation. So, the only + * difference between this and the CRT strcmp function is the handling of + * NULL arguments. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param psz1 First UTF-8 string. Null is allowed. + * @param psz2 Second UTF-8 string. Null is allowed. + */ +RTDECL(int) RTStrCmp(const char *psz1, const char *psz2); + +/** + * Performs a case sensitive string compare between two UTF-8 strings, given + * a maximum string length. + * + * Encoding errors are ignored by the current implementation. So, the only + * difference between this and the CRT strncmp function is the handling of + * NULL arguments. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param psz1 First UTF-8 string. Null is allowed. + * @param psz2 Second UTF-8 string. Null is allowed. + * @param cchMax The maximum string length + */ +RTDECL(int) RTStrNCmp(const char *psz1, const char *psz2, size_t cchMax); + +/** + * Performs a case insensitive string compare between two UTF-8 strings. + * + * This is a simplified compare, as only the simplified lower/upper case folding + * specified by the unicode specs are used. It does not consider character pairs + * as they are used in some languages, just simple upper & lower case compares. + * + * The result is the difference between the mismatching codepoints after they + * both have been lower cased. + * + * If the string encoding is invalid the function will assert (strict builds) + * and use RTStrCmp for the remainder of the string. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param psz1 First UTF-8 string. Null is allowed. + * @param psz2 Second UTF-8 string. Null is allowed. + */ +RTDECL(int) RTStrICmp(const char *psz1, const char *psz2); + +/** + * Performs a case insensitive string compare between two UTF-8 strings, given a + * maximum string length. + * + * This is a simplified compare, as only the simplified lower/upper case folding + * specified by the unicode specs are used. It does not consider character pairs + * as they are used in some languages, just simple upper & lower case compares. + * + * The result is the difference between the mismatching codepoints after they + * both have been lower cased. + * + * If the string encoding is invalid the function will assert (strict builds) + * and use RTStrNCmp for the remainder of the string. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param psz1 First UTF-8 string. Null is allowed. + * @param psz2 Second UTF-8 string. Null is allowed. + * @param cchMax Maximum string length + */ +RTDECL(int) RTStrNICmp(const char *psz1, const char *psz2, size_t cchMax); + +/** + * Performs a case insensitive string compare between a UTF-8 string and a 7-bit + * ASCII string. + * + * This is potentially faster than RTStrICmp and drags in less dependencies. It + * is really handy for hardcoded inputs. + * + * If the string encoding is invalid the function will assert (strict builds) + * and use RTStrCmp for the remainder of the string. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param psz1 First UTF-8 string. Null is allowed. + * @param psz2 Second string, 7-bit ASCII. Null is allowed. + * @sa RTStrICmp, RTUtf16ICmpAscii + */ +RTDECL(int) RTStrICmpAscii(const char *psz1, const char *psz2); + +/** + * Performs a case insensitive string compare between a UTF-8 string and a 7-bit + * ASCII string, given a maximum string length. + * + * This is potentially faster than RTStrNICmp and drags in less dependencies. + * It is really handy for hardcoded inputs. + * + * If the string encoding is invalid the function will assert (strict builds) + * and use RTStrNCmp for the remainder of the string. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param psz1 First UTF-8 string. Null is allowed. + * @param psz2 Second string, 7-bit ASCII. Null is allowed. + * @param cchMax Maximum string length + * @sa RTStrNICmp, RTUtf16NICmpAscii + */ +RTDECL(int) RTStrNICmpAscii(const char *psz1, const char *psz2, size_t cchMax); + +/** + * Checks whether @a pszString starts with @a pszStart. + * + * @returns true / false. + * @param pszString The string to check. + * @param pszStart The start string to check for. + */ +RTDECL(bool) RTStrStartsWith(const char *pszString, const char *pszStart); + +/** + * Checks whether @a pszString starts with @a pszStart, case insensitive. + * + * @returns true / false. + * @param pszString The string to check. + * @param pszStart The start string to check for. + */ +RTDECL(bool) RTStrIStartsWith(const char *pszString, const char *pszStart); + +/** + * Splits a string buffer with a given separator into separate strings. + * If no separators are found, no strings are returned. Consequtive separators will be skipped. + * + * @returns iprt status code. + * @param pcszStrings String buffer to split. + * @param cbStrings Size (in bytes) of string buffer to split, including terminator. + * @param pcszSeparator Separator to use / find for splitting strings. + * @param ppapszStrings Where to return the allocated string array on success. Needs to be free'd by the caller. + * @param pcStrings Where to return the number of split strings in \a ppapszStrings. + */ +RTDECL(int) RTStrSplit(const char *pcszStrings, size_t cbStrings, + const char *pcszSeparator, char ***ppapszStrings, size_t *pcStrings); + +/** + * Locates a case sensitive substring. + * + * If any of the two strings are NULL, then NULL is returned. If the needle is + * an empty string, then the haystack is returned (i.e. matches anything). + * + * @returns Pointer to the first occurrence of the substring if found, NULL if + * not. + * + * @param pszHaystack The string to search. + * @param pszNeedle The substring to search for. + * + * @remarks The difference between this and strstr is the handling of NULL + * pointers. + */ +RTDECL(char *) RTStrStr(const char *pszHaystack, const char *pszNeedle); + +/** + * Locates a case insensitive substring. + * + * If any of the two strings are NULL, then NULL is returned. If the needle is + * an empty string, then the haystack is returned (i.e. matches anything). + * + * @returns Pointer to the first occurrence of the substring if found, NULL if + * not. + * + * @param pszHaystack The string to search. + * @param pszNeedle The substring to search for. + * + */ +RTDECL(char *) RTStrIStr(const char *pszHaystack, const char *pszNeedle); + +/** + * Converts the string to lower case. + * + * @returns Pointer to the converted string. + * @param psz The string to convert. + */ +RTDECL(char *) RTStrToLower(char *psz); + +/** + * Converts the string to upper case. + * + * @returns Pointer to the converted string. + * @param psz The string to convert. + */ +RTDECL(char *) RTStrToUpper(char *psz); + +/** + * Checks if the string is case foldable, i.e. whether it would change if + * subject to RTStrToLower or RTStrToUpper. + * + * @returns true / false + * @param psz The string in question. + */ +RTDECL(bool) RTStrIsCaseFoldable(const char *psz); + +/** + * Checks if the string is upper cased (no lower case chars in it). + * + * @returns true / false + * @param psz The string in question. + */ +RTDECL(bool) RTStrIsUpperCased(const char *psz); + +/** + * Checks if the string is lower cased (no upper case chars in it). + * + * @returns true / false + * @param psz The string in question. + */ +RTDECL(bool) RTStrIsLowerCased(const char *psz); + +/** + * Find the length of a zero-terminated byte string, given + * a max string length. + * + * See also RTStrNLenEx. + * + * @returns The string length or cbMax. The returned length does not include + * the zero terminator if it was found. + * + * @param pszString The string. + * @param cchMax The max string length. + */ +RTDECL(size_t) RTStrNLen(const char *pszString, size_t cchMax); + +/** + * Find the length of a zero-terminated byte string, given + * a max string length. + * + * See also RTStrNLen. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the string has a length less than cchMax. + * @retval VERR_BUFFER_OVERFLOW if the end of the string wasn't found + * before cchMax was reached. + * + * @param pszString The string. + * @param cchMax The max string length. + * @param pcch Where to store the string length excluding the + * terminator. This is set to cchMax if the terminator + * isn't found. + */ +RTDECL(int) RTStrNLenEx(const char *pszString, size_t cchMax, size_t *pcch); + +/** The maximum size argument of a memchr call. */ +#define RTSTR_MEMCHR_MAX ((~(size_t)0 >> 1) - 15) + +/** + * Find the zero terminator in a string with a limited length. + * + * @returns Pointer to the zero terminator. + * @returns NULL if the zero terminator was not found. + * + * @param pszString The string. + * @param cchMax The max string length. RTSTR_MAX is fine. + */ +RTDECL(char *) RTStrEnd(char const *pszString, size_t cchMax); + +/** + * Finds the offset at which a simple character first occurs in a string. + * + * @returns The offset of the first occurence or the terminator offset. + * @param pszHaystack The string to search. + * @param chNeedle The character to search for. + */ +DECLINLINE(size_t) RTStrOffCharOrTerm(const char *pszHaystack, char chNeedle) +{ + const char *psz = pszHaystack; + char ch; + while ( (ch = *psz) != chNeedle + && ch != '\0') + psz++; + return (size_t)(psz - pszHaystack); +} + +/** + * Matches a simple string pattern. + * + * @returns true if the string matches the pattern, otherwise false. + * + * @param pszPattern The pattern. Special chars are '*' and '?', where the + * asterisk matches zero or more characters and question + * mark matches exactly one character. + * @param pszString The string to match against the pattern. + */ +RTDECL(bool) RTStrSimplePatternMatch(const char *pszPattern, const char *pszString); + +/** + * Matches a simple string pattern, neither which needs to be zero terminated. + * + * This is identical to RTStrSimplePatternMatch except that you can optionally + * specify the length of both the pattern and the string. The function will + * stop when it hits a string terminator or either of the lengths. + * + * @returns true if the string matches the pattern, otherwise false. + * + * @param pszPattern The pattern. Special chars are '*' and '?', where the + * asterisk matches zero or more characters and question + * mark matches exactly one character. + * @param cchPattern The pattern length. Pass RTSTR_MAX if you don't know the + * length and wish to stop at the string terminator. + * @param pszString The string to match against the pattern. + * @param cchString The string length. Pass RTSTR_MAX if you don't know the + * length and wish to match up to the string terminator. + */ +RTDECL(bool) RTStrSimplePatternNMatch(const char *pszPattern, size_t cchPattern, + const char *pszString, size_t cchString); + +/** + * Matches multiple patterns against a string. + * + * The patterns are separated by the pipe character (|). + * + * @returns true if the string matches the pattern, otherwise false. + * + * @param pszPatterns The patterns. + * @param cchPatterns The lengths of the patterns to use. Pass RTSTR_MAX to + * stop at the terminator. + * @param pszString The string to match against the pattern. + * @param cchString The string length. Pass RTSTR_MAX stop stop at the + * terminator. + * @param poffPattern Offset into the patterns string of the patttern that + * matched. If no match, this will be set to RTSTR_MAX. + * This is optional, NULL is fine. + */ +RTDECL(bool) RTStrSimplePatternMultiMatch(const char *pszPatterns, size_t cchPatterns, + const char *pszString, size_t cchString, + size_t *poffPattern); + +/** + * Compares two version strings RTStrICmp fashion. + * + * The version string is split up into sections at punctuation, spaces, + * underscores, dashes and plus signs. The sections are then split up into + * numeric and string sub-sections. Finally, the sub-sections are compared + * in a numeric or case insesntivie fashion depending on what they are. + * + * The following strings are considered to be equal: "1.0.0", "1.00.0", "1.0", + * "1". These aren't: "1.0.0r993", "1.0", "1.0r993", "1.0_Beta3", "1.1" + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * + * @param pszVer1 First version string to compare. + * @param pszVer2 Second version string to compare first version with. + */ +RTDECL(int) RTStrVersionCompare(const char *pszVer1, const char *pszVer2); + + +/** @defgroup rt_str_conv String To/From Number Conversions + * @{ */ + +/** + * Converts a string representation of a number to a 64-bit unsigned number. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_NEGATIVE_UNSIGNED + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param ppszNext Where to store the pointer to the first char + * following the number. (Optional) + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pu64 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToUInt64Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, uint64_t *pu64); + +/** + * Converts a string representation of a number to a 64-bit unsigned number, + * making sure the full string is converted. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_NEGATIVE_UNSIGNED + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * @retval VERR_TRAILING_SPACES + * @retval VERR_TRAILING_CHARS + * + * @param pszValue Pointer to the string value. + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pu64 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToUInt64Full(const char *pszValue, unsigned uBaseAndMaxLen, uint64_t *pu64); + +/** + * Converts a string representation of a number to a 64-bit unsigned number. + * The base is guessed. + * + * @returns 64-bit unsigned number on success. + * @returns 0 on failure. + * @param pszValue Pointer to the string value. + */ +RTDECL(uint64_t) RTStrToUInt64(const char *pszValue); + +/** + * Converts a string representation of a number to a 32-bit unsigned number. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_NEGATIVE_UNSIGNED + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param ppszNext Where to store the pointer to the first char + * following the number. (Optional) + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pu32 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToUInt32Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, uint32_t *pu32); + +/** + * Converts a string representation of a number to a 32-bit unsigned number, + * making sure the full string is converted. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_NEGATIVE_UNSIGNED + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * @retval VERR_TRAILING_SPACES + * @retval VERR_TRAILING_CHARS + * + * @param pszValue Pointer to the string value. + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pu32 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToUInt32Full(const char *pszValue, unsigned uBaseAndMaxLen, uint32_t *pu32); + +/** + * Converts a string representation of a number to a 32-bit unsigned number. + * The base is guessed. + * + * @returns 32-bit unsigned number on success. + * @returns 0 on failure. + * @param pszValue Pointer to the string value. + */ +RTDECL(uint32_t) RTStrToUInt32(const char *pszValue); + +/** + * Converts a string representation of a number to a 16-bit unsigned number. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_NEGATIVE_UNSIGNED + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param ppszNext Where to store the pointer to the first char + * following the number. (Optional) + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pu16 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToUInt16Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, uint16_t *pu16); + +/** + * Converts a string representation of a number to a 16-bit unsigned number, + * making sure the full string is converted. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_NEGATIVE_UNSIGNED + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * @retval VERR_TRAILING_SPACES + * @retval VERR_TRAILING_CHARS + * + * @param pszValue Pointer to the string value. + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pu16 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToUInt16Full(const char *pszValue, unsigned uBaseAndMaxLen, uint16_t *pu16); + +/** + * Converts a string representation of a number to a 16-bit unsigned number. + * The base is guessed. + * + * @returns 16-bit unsigned number on success. + * @returns 0 on failure. + * @param pszValue Pointer to the string value. + */ +RTDECL(uint16_t) RTStrToUInt16(const char *pszValue); + +/** + * Converts a string representation of a number to a 8-bit unsigned number. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_NEGATIVE_UNSIGNED + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param ppszNext Where to store the pointer to the first char + * following the number. (Optional) + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pu8 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToUInt8Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, uint8_t *pu8); + +/** + * Converts a string representation of a number to a 8-bit unsigned number, + * making sure the full string is converted. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_NEGATIVE_UNSIGNED + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * @retval VERR_TRAILING_SPACES + * @retval VERR_TRAILING_CHARS + * + * @param pszValue Pointer to the string value. + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pu8 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToUInt8Full(const char *pszValue, unsigned uBaseAndMaxLen, uint8_t *pu8); + +/** + * Converts a string representation of a number to a 8-bit unsigned number. + * The base is guessed. + * + * @returns 8-bit unsigned number on success. + * @returns 0 on failure. + * @param pszValue Pointer to the string value. + */ +RTDECL(uint8_t) RTStrToUInt8(const char *pszValue); + +/** + * Converts a string representation of a number to a 64-bit signed number. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param ppszNext Where to store the pointer to the first char + * following the number. (Optional) + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pi64 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToInt64Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int64_t *pi64); + +/** + * Converts a string representation of a number to a 64-bit signed number, + * making sure the full string is converted. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VINF_SUCCESS + * @retval VERR_TRAILING_CHARS + * @retval VERR_TRAILING_SPACES + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pi64 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToInt64Full(const char *pszValue, unsigned uBaseAndMaxLen, int64_t *pi64); + +/** + * Converts a string representation of a number to a 64-bit signed number. + * The base is guessed. + * + * @returns 64-bit signed number on success. + * @returns 0 on failure. + * @param pszValue Pointer to the string value. + */ +RTDECL(int64_t) RTStrToInt64(const char *pszValue); + +/** + * Converts a string representation of a number to a 32-bit signed number. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param ppszNext Where to store the pointer to the first char + * following the number. (Optional) + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pi32 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToInt32Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int32_t *pi32); + +/** + * Converts a string representation of a number to a 32-bit signed number, + * making sure the full string is converted. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VINF_SUCCESS + * @retval VERR_TRAILING_CHARS + * @retval VERR_TRAILING_SPACES + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pi32 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToInt32Full(const char *pszValue, unsigned uBaseAndMaxLen, int32_t *pi32); + +/** + * Converts a string representation of a number to a 32-bit signed number. + * The base is guessed. + * + * @returns 32-bit signed number on success. + * @returns 0 on failure. + * @param pszValue Pointer to the string value. + */ +RTDECL(int32_t) RTStrToInt32(const char *pszValue); + +/** + * Converts a string representation of a number to a 16-bit signed number. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param ppszNext Where to store the pointer to the first char + * following the number. (Optional) + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pi16 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToInt16Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int16_t *pi16); + +/** + * Converts a string representation of a number to a 16-bit signed number, + * making sure the full string is converted. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VINF_SUCCESS + * @retval VERR_TRAILING_CHARS + * @retval VERR_TRAILING_SPACES + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pi16 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToInt16Full(const char *pszValue, unsigned uBaseAndMaxLen, int16_t *pi16); + +/** + * Converts a string representation of a number to a 16-bit signed number. + * The base is guessed. + * + * @returns 16-bit signed number on success. + * @returns 0 on failure. + * @param pszValue Pointer to the string value. + */ +RTDECL(int16_t) RTStrToInt16(const char *pszValue); + +/** + * Converts a string representation of a number to a 8-bit signed number. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * @retval VINF_SUCCESS + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param ppszNext Where to store the pointer to the first char + * following the number. (Optional) + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pi8 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToInt8Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int8_t *pi8); + +/** + * Converts a string representation of a number to a 8-bit signed number, + * making sure the full string is converted. + * + * @returns iprt status code. + * Warnings are used to indicate conversion problems. + * @retval VWRN_NUMBER_TOO_BIG + * @retval VINF_SUCCESS + * @retval VERR_TRAILING_CHARS + * @retval VERR_TRAILING_SPACES + * @retval VERR_NO_DIGITS + * + * @param pszValue Pointer to the string value. + * @param uBaseAndMaxLen The low byte is the base of the representation, the + * upper 24 bits are the max length to parse. If the base + * is zero the function will look for known prefixes before + * defaulting to 10. A max length of zero means no length + * restriction. + * @param pi8 Where to store the converted number. (optional) + */ +RTDECL(int) RTStrToInt8Full(const char *pszValue, unsigned uBaseAndMaxLen, int8_t *pi8); + +/** + * Converts a string representation of a number to a 8-bit signed number. + * The base is guessed. + * + * @returns 8-bit signed number on success. + * @returns 0 on failure. + * @param pszValue Pointer to the string value. + */ +RTDECL(int8_t) RTStrToInt8(const char *pszValue); + + +/** + * Converts a string to long double floating point, extended edition. + * + * Please note that long double can be double precision, extended precision, or + * quad precision floating point depending on the platform and architecture. See + * RT_COMPILER_WITH_128BIT_LONG_DOUBLE and RT_COMPILER_WITH_80BIT_LONG_DOUBLE. + * + * @returns IPRT status code. + * @retval VERR_NO_DIGITS if no valid digits found. + * @retval VWRN_FLOAT_UNDERFLOW on underflow with denormal/subnormal return + * value + * @retval VERR_FLOAT_UNDERFLOW on underflow, value set to +/- zero. + * @retval VERR_FLOAT_OVERFLOW on overflow, value set to +/- infinity. + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * + * @param pszValue The string to parse. + * @param ppszNext Where to store the pointer to the first char following + * the number. Optional. + * @param cchMax Max number of character to parse. Zero means unlimited. + * @param plrd Where to return the number. Optional. + * + * @note This code isn't entirely perfect yet. It could exhibit rounding + * differences compared to strtold & the compiler, and extreme value + * may overflow/underflow prematurely depending on the build config. + */ +RTDECL(int) RTStrToLongDoubleEx(const char *pszValue, char **ppszNext, size_t cchMax, long double *plrd); + +/** + * Converts a string to double precision floating point, extended edition. + * + * @returns IPRT status code. + * @retval VERR_NO_DIGITS if no valid digits found. + * @retval VWRN_FLOAT_UNDERFLOW on underflow with denormal/subnormal return + * value + * @retval VERR_FLOAT_UNDERFLOW on underflow, value set to +/- zero. + * @retval VERR_FLOAT_OVERFLOW on overflow, value set to +/- infinity. + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * + * @param pszValue The string to parse. + * @param ppszNext Where to store the pointer to the first char following + * the number. Optional. + * @param cchMax Max number of character to parse. Zero means unlimited. + * @param prd Where to return the number. Optional. + * + * @note This code isn't entirely perfect yet. It could exhibit rounding + * differences compared to strtold & the compiler, and extreme value + * may overflow/underflow prematurely depending on the build config. + */ +RTDECL(int) RTStrToDoubleEx(const char *pszValue, char **ppszNext, size_t cchMax, double *prd); + +/** + * Converts a string to single precision floating point, extended edition. + * + * @returns IPRT status code. + * @retval VERR_NO_DIGITS if no valid digits found. + * @retval VWRN_FLOAT_UNDERFLOW on underflow with denormal/subnormal return + * value + * @retval VERR_FLOAT_UNDERFLOW on underflow, value set to +/- zero. + * @retval VERR_FLOAT_OVERFLOW on overflow, value set to +/- infinity. + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * + * @param pszValue The string to parse. + * @param ppszNext Where to store the pointer to the first char following + * the number. Optional. + * @param cchMax Max number of character to parse. Zero means unlimited. + * @param pr Where to return the number. Optional. + * + * @note This code isn't entirely perfect yet. It could exhibit rounding + * differences compared to strtold & the compiler, and extreme value + * may overflow/underflow prematurely depending on the build config. + */ +RTDECL(int) RTStrToFloatEx(const char *pszValue, char **ppszNext, size_t cchMax, float *pr); + + +/** + * Gets a long double NaN. + * + * @returns NaN value. + * @param pszTag Optional NaN tag for modifying the NaN value. We + * recognizes a string of hex digits for inserting into the + * fraction part. This may be followed 'quiet' or + * 'signaling', ignoring case and requiring at only the + * first character. The two components may be separated by + * zero or more '_' characters. Any other stuff in the tag + * will be ignored. + * + * If the tag is empty or we cannot grok any of it, we'll + * return a default quiet NaN. + * @param fPositive Whether the NaN value should be positive or negative + * (for what that's worth). + */ +RTDECL(long double) RTStrNanLongDouble(const char *pszTag, bool fPositive); + +/** + * Gets a double NaN. + * + * @returns NaN value. + * @param pszTag Optional NaN tag for modifying the NaN value. We + * recognizes a string of hex digits for inserting into the + * fraction part. This may be followed 'quiet' or + * 'signaling', ignoring case and requiring at only the + * first character. The two components may be separated by + * zero or more '_' characters. Any other stuff in the tag + * will be ignored. + * + * If the tag is empty or we cannot grok any of it, we'll + * return a default quiet NaN. + * @param fPositive Whether the NaN value should be positive or negative + * (for what that's worth). + */ +RTDECL(double) RTStrNanDouble(const char *pszTag, bool fPositive); + +/** + * Gets a float NaN. + * + * @returns NaN value. + * @param pszTag Optional NaN tag for modifying the NaN value. We + * recognizes a string of hex digits for inserting into the + * fraction part. This may be followed 'quiet' or + * 'signaling', ignoring case and requiring at only the + * first character. The two components may be separated by + * zero or more '_' characters. Any other stuff in the tag + * will be ignored. + * + * If the tag is empty or we cannot grok any of it, we'll + * return a default quiet NaN. + * @param fPositive Whether the NaN value should be positive or negative + * (for what that's worth). + */ +RTDECL(float) RTStrNanFloat(const char *pszTag, bool fPositive); + +/** + * Formats a buffer stream as hex bytes. + * + * The default is no separating spaces or line breaks or anything. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER if any of the pointers are wrong. + * @retval VERR_BUFFER_OVERFLOW if the buffer is insufficent to hold the bytes. + * + * @param pszBuf Output string buffer. + * @param cbBuf The size of the output buffer. + * @param pv Pointer to the bytes to stringify. + * @param cb The number of bytes to stringify. + * @param fFlags Combination of RTSTRPRINTHEXBYTES_F_XXX values. + * @sa RTUtf16PrintHexBytes. + */ +RTDECL(int) RTStrPrintHexBytes(char *pszBuf, size_t cbBuf, void const *pv, size_t cb, uint32_t fFlags); +/** @name RTSTRPRINTHEXBYTES_F_XXX - flags for RTStrPrintHexBytes and RTUtf16PritnHexBytes. + * @{ */ +/** Upper case hex digits, the default is lower case. */ +#define RTSTRPRINTHEXBYTES_F_UPPER RT_BIT(0) +/** Add a space between each group. */ +#define RTSTRPRINTHEXBYTES_F_SEP_SPACE RT_BIT(1) +/** Add a colon between each group. */ +#define RTSTRPRINTHEXBYTES_F_SEP_COLON RT_BIT(2) +/** @} */ + +/** + * Converts a string of hex bytes back into binary data. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER if any of the pointers are wrong. + * @retval VERR_BUFFER_OVERFLOW if the string contains too many hex bytes. + * @retval VERR_BUFFER_UNDERFLOW if there aren't enough hex bytes to fill up + * the output buffer. + * @retval VERR_UNEVEN_INPUT if the input contains a half byte. + * @retval VERR_NO_DIGITS + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * + * @param pszHex The string containing the hex bytes. + * @param pv Output buffer. + * @param cb The size of the output buffer. + * @param fFlags RTSTRCONVERTHEXBYTES_F_XXX. + */ +RTDECL(int) RTStrConvertHexBytes(char const *pszHex, void *pv, size_t cb, uint32_t fFlags); + +/** @name RTSTRCONVERTHEXBYTES_F_XXX - Flags for RTStrConvertHexBytes() and RTStrConvertHexBytesEx(). + * @{ */ +/** Accept colon as a byte separator. */ +#define RTSTRCONVERTHEXBYTES_F_SEP_COLON RT_BIT(0) +/** @} */ + +/** + * Converts a string of hex bytes back into binary data, extended version. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER if any of the pointers are wrong. + * @retval VERR_BUFFER_OVERFLOW if the string contains too many hex bytes. + * @retval VERR_BUFFER_UNDERFLOW if there aren't enough hex bytes to fill up + * the output buffer and *pcbReturned is NULL. + * @retval VINF_BUFFER_UNDERFLOW if there aren't enough hex bytes to fill up + * the output buffer and *pcbReturned is not NULL, *pcbReturned holds + * the actual number of bytes. + * @retval VERR_UNEVEN_INPUT if the input contains a half byte. + * @retval VERR_NO_DIGITS + * @retval VWRN_TRAILING_CHARS + * @retval VWRN_TRAILING_SPACES + * + * @param pszHex The string containing the hex bytes. + * @param pv Output buffer. + * @param cb The size of the output buffer. + * @param fFlags RTSTRCONVERTHEXBYTES_F_XXX. + * @param ppszNext Set to point at where we stopped decoding hex bytes. + * Optional. + * @param pcbReturned Where to return the number of bytes found. Optional. + */ +RTDECL(int) RTStrConvertHexBytesEx(char const *pszHex, void *pv, size_t cb, uint32_t fFlags, + const char **ppszNext, size_t *pcbReturned); + +/** @} */ + + +/** @defgroup rt_str_space Unique String Space + * @{ + */ + +/** Pointer to a string name space container node core. */ +typedef struct RTSTRSPACECORE *PRTSTRSPACECORE; +/** Pointer to a pointer to a string name space container node core. */ +typedef PRTSTRSPACECORE *PPRTSTRSPACECORE; + +/** + * String name space container node core. + */ +typedef struct RTSTRSPACECORE +{ + /** Pointer to the left leaf node. Don't touch. */ + PRTSTRSPACECORE pLeft; + /** Pointer to the left right node. Don't touch. */ + PRTSTRSPACECORE pRight; + /** Pointer to the list of string with the same hash key value. Don't touch. */ + PRTSTRSPACECORE pList; + /** Hash key. Don't touch. */ + uint32_t Key; + /** Height of this tree: max(heigth(left), heigth(right)) + 1. Don't touch */ + unsigned char uchHeight; + /** The string length. Read only! */ + size_t cchString; + /** Pointer to the string. Read only! */ + const char *pszString; +} RTSTRSPACECORE; + +/** String space. (Initialize with NULL.) */ +typedef PRTSTRSPACECORE RTSTRSPACE; +/** Pointer to a string space. */ +typedef PPRTSTRSPACECORE PRTSTRSPACE; + + +/** + * Inserts a string into a unique string space. + * + * @returns true on success. + * @returns false if the string collided with an existing string. + * @param pStrSpace The space to insert it into. + * @param pStr The string node. + */ +RTDECL(bool) RTStrSpaceInsert(PRTSTRSPACE pStrSpace, PRTSTRSPACECORE pStr); + +/** + * Removes a string from a unique string space. + * + * @returns Pointer to the removed string node. + * @returns NULL if the string was not found in the string space. + * @param pStrSpace The space to remove it from. + * @param pszString The string to remove. + */ +RTDECL(PRTSTRSPACECORE) RTStrSpaceRemove(PRTSTRSPACE pStrSpace, const char *pszString); + +/** + * Gets a string from a unique string space. + * + * @returns Pointer to the string node. + * @returns NULL if the string was not found in the string space. + * @param pStrSpace The space to get it from. + * @param pszString The string to get. + */ +RTDECL(PRTSTRSPACECORE) RTStrSpaceGet(PRTSTRSPACE pStrSpace, const char *pszString); + +/** + * Gets a string from a unique string space. + * + * @returns Pointer to the string node. + * @returns NULL if the string was not found in the string space. + * @param pStrSpace The space to get it from. + * @param pszString The string to get. + * @param cchMax The max string length to evaluate. Passing + * RTSTR_MAX is ok and makes it behave just like + * RTStrSpaceGet. + */ +RTDECL(PRTSTRSPACECORE) RTStrSpaceGetN(PRTSTRSPACE pStrSpace, const char *pszString, size_t cchMax); + +/** + * Callback function for RTStrSpaceEnumerate() and RTStrSpaceDestroy(). + * + * @returns 0 on continue. + * @returns Non-zero to aborts the operation. + * @param pStr The string node + * @param pvUser The user specified argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTSTRSPACECALLBACK,(PRTSTRSPACECORE pStr, void *pvUser)); +/** Pointer to callback function for RTStrSpaceEnumerate() and RTStrSpaceDestroy(). */ +typedef FNRTSTRSPACECALLBACK *PFNRTSTRSPACECALLBACK; + +/** + * Destroys the string space. + * + * The caller supplies a callback which will be called for each of the string + * nodes in for freeing their memory and other resources. + * + * @returns 0 or what ever non-zero return value pfnCallback returned + * when aborting the destruction. + * @param pStrSpace The space to destroy. + * @param pfnCallback The callback. + * @param pvUser The user argument. + */ +RTDECL(int) RTStrSpaceDestroy(PRTSTRSPACE pStrSpace, PFNRTSTRSPACECALLBACK pfnCallback, void *pvUser); + +/** + * Enumerates the string space. + * The caller supplies a callback which will be called for each of + * the string nodes. + * + * @returns 0 or what ever non-zero return value pfnCallback returned + * when aborting the destruction. + * @param pStrSpace The space to enumerate. + * @param pfnCallback The callback. + * @param pvUser The user argument. + */ +RTDECL(int) RTStrSpaceEnumerate(PRTSTRSPACE pStrSpace, PFNRTSTRSPACECALLBACK pfnCallback, void *pvUser); + +/** @} */ + + +/** @defgroup rt_str_hash Sting hashing + * @{ */ + +/** + * Hashes the given string using algorithm \#1. + * + * @returns String hash. + * @param pszString The string to hash. + */ +RTDECL(uint32_t) RTStrHash1(const char *pszString); + +/** + * Hashes the given string using algorithm \#1. + * + * @returns String hash. + * @param pszString The string to hash. + * @param cchString The max length to hash. Hashing will stop if the + * terminator character is encountered first. Passing + * RTSTR_MAX is fine. + */ +RTDECL(uint32_t) RTStrHash1N(const char *pszString, size_t cchString); + +/** + * Hashes the given strings as if they were concatenated using algorithm \#1. + * + * @returns String hash. + * @param cPairs The number of string / length pairs in the + * ellipsis. + * @param ... List of string (const char *) and length + * (size_t) pairs. Passing RTSTR_MAX as the size is + * fine. + */ +RTDECL(uint32_t) RTStrHash1ExN(size_t cPairs, ...); + +/** + * Hashes the given strings as if they were concatenated using algorithm \#1. + * + * @returns String hash. + * @param cPairs The number of string / length pairs in the @a va. + * @param va List of string (const char *) and length + * (size_t) pairs. Passing RTSTR_MAX as the size is + * fine. + */ +RTDECL(uint32_t) RTStrHash1ExNV(size_t cPairs, va_list va); + +/** @} */ + + +/** @defgroup rt_str_mem Raw memory operations. + * + * @note Following the memchr/memcpy/memcmp/memset tradition and putting these + * in the string.h header rather than in the mem.h one. + * + * @{ */ + +/** + * Searches @a pvHaystack for a 16-bit sized and aligned @a uNeedle. + * + * @returns Pointer to the first hit if found, NULL if not found. + * @param pvHaystack The memory to search. + * @param uNeedle The 16-bit value to find. + * @param cbHaystack Size of the memory to search. + * @sa memchr, RTStrMemFind32, RTStrMemFind64 + */ +RTDECL(uint16_t *) RTStrMemFind16(const void *pvHaystack, uint16_t uNeedle, size_t cbHaystack); + +/** + * Searches @a pvHaystack for a 32-bit sized and aligned @a uNeedle. + * + * @returns Pointer to the first hit if found, NULL if not found. + * @param pvHaystack The memory to search. + * @param uNeedle The 32-bit value to find. + * @param cbHaystack Size of the memory to search. + * @sa memchr, RTStrMemFind16, RTStrMemFind64 + */ +RTDECL(uint32_t *) RTStrMemFind32(const void *pvHaystack, uint32_t uNeedle, size_t cbHaystack); + +/** + * Searches @a pvHaystack for a 64-bit sized and aligned @a uNeedle. + * + * @returns Pointer to the first hit if found, NULL if not found. + * @param pvHaystack The memory to search. + * @param uNeedle The 64-bit value to find. + * @param cbHaystack Size of the memory to search. + * @sa memchr, RTStrMemFind16, RTStrMemFind32 + */ +RTDECL(uint64_t *) RTStrMemFind64(const void *pvHaystack, uint64_t uNeedle, size_t cbHaystack); + +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_string_h */ diff --git a/include/iprt/symlink.h b/include/iprt/symlink.h new file mode 100644 index 00000000..8b5e60f0 --- /dev/null +++ b/include/iprt/symlink.h @@ -0,0 +1,189 @@ +/** @file + * IPRT - Symbolic Link Manipulation. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_symlink_h +#define IPRT_INCLUDED_symlink_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_symlink RTSymlink - Symbolic Link Manipulation + * @ingroup grp_rt + * + * For querying and changing symlink info (mode, ownership, etc) please refer + * to the @ref grp_rt_path "RTPath" API: RTPathQueryInfoEx, RTPathSetOwnerEx, + * RTPathSetModeEx and RTPathSetTimesEx. + * + * @{ + */ + +/** + * Checks if the specified path exists and is a symlink. + * + * @returns true if it's a symlink, false if it isn't. + * @param pszSymlink The path to the symlink. + * + * @sa RTDirExists, RTPathExists, RTSymlinkExists. + */ +RTDECL(bool) RTSymlinkExists(const char *pszSymlink); + +/** + * Checks if this is a dangling link or not. + * + * If the target of @a pszSymlink is a symbolic link, this may return false if + * that or any subsequent links are dangling. + * + * @returns true if it's dangling, false if it isn't. + * @param pszSymlink The path to the symlink. + */ +RTDECL(bool) RTSymlinkIsDangling(const char *pszSymlink); + +/** + * RTSymlinkCreate link type argument. + */ +typedef enum RTSYMLINKTYPE +{ + /** Invalid value. */ + RTSYMLINKTYPE_INVALID = 0, + /** The link targets a directory. */ + RTSYMLINKTYPE_DIR, + /** The link targets a file (or whatever else). */ + RTSYMLINKTYPE_FILE, + /** It is not known what is being targeted. + * @remarks The RTSymlinkCreate API may probe the target to try figure + * out what is being targeted. */ + RTSYMLINKTYPE_UNKNOWN, + /** The end of the valid type values. */ + RTSYMLINKTYPE_END, + /** Blow the type up to 32-bit. */ + RTSYMLINKTYPE_32BIT_HACK = 0x7fffffff +} RTSYMLINKTYPE; + +/** @name RTSymlinkCreate flags. + * @{ */ +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTSYMLINKCREATE_FLAGS_NO_SYMLINKS RT_BIT(0) +/** @} */ + +/** + * Creates a symbolic link (@a pszSymlink) targeting @a pszTarget. + * + * @returns IPRT status code. + * + * @param pszSymlink The name of the symbolic link. + * @param pszTarget The path to the symbolic link target. This is + * relative to @a pszSymlink or an absolute path. + * @param enmType The symbolic link type. For Windows compatability + * it is very important to set this correctly. When + * RTSYMLINKTYPE_UNKNOWN is used, the API will try + * make a guess and may attempt query information + * about @a pszTarget in the process. + * @param fCreate Create flags, RTSYMLINKCREATE_FLAGS_*. + */ +RTDECL(int) RTSymlinkCreate(const char *pszSymlink, const char *pszTarget, + RTSYMLINKTYPE enmType, uint32_t fCreate); + +/** @name RTSymlinkDelete flags. + * @{ */ +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTSYMLINKDELETE_FLAGS_NO_SYMLINKS RT_BIT(0) +/** @} */ + +/** + * Deletes the specified symbolic link. + * + * This will try to refuse deleting non-symlinks, however there are usually + * races in the implementation of this check so no guarantees can be are made. + * + * @returns IPRT status code. + * @retval VERR_NOT_SYMLINK if @a pszSymlink does not specify a symbolic link. + * + * @param pszSymlink The symbolic link that should be removed. + * @param fDelete Delete flags, RTSYMLINKDELETE_FLAGS_*. + */ +RTDECL(int) RTSymlinkDelete(const char *pszSymlink, uint32_t fDelete); + +/** @name RTSymlinkRead flags. + * @{ */ +/** Don't allow symbolic links as part of the path. + * @remarks this flag is currently not implemented and will be ignored. */ +#define RTSYMLINKREAD_FLAGS_NO_SYMLINKS RT_BIT(0) +/** @} */ + +/** + * Read the symlink target. + * + * @returns IPRT status code. + * @retval VERR_NOT_SYMLINK if @a pszSymlink does not specify a symbolic link. + * @retval VERR_BUFFER_OVERFLOW if the link is larger than @a cbTarget. The + * buffer will contain what all we managed to read, fully terminated + * if @a cbTarget > 0. + * + * @param pszSymlink The symbolic link that should be read. + * @param pszTarget The target buffer. + * @param cbTarget The size of the target buffer. + * @param fRead Read flags, RTSYMLINKREAD_FLAGS_*. + */ +RTDECL(int) RTSymlinkRead(const char *pszSymlink, char *pszTarget, size_t cbTarget, uint32_t fRead); + +/** + * Read the symlink target into an API allocated buffer. + * + * This API eliminates the race involved in determining the right buffer size. + * + * @returns IPRT status code. + * @retval VERR_NOT_SYMLINK if @a pszSymlink does not specify a symbolic link. + * + * @param pszSymlink The symbolic link that should be read. + * @param ppszTarget Where to return the target string. Free the string + * by calling RTStrFree. + */ +RTDECL(int) RTSymlinkReadA(const char *pszSymlink, char **ppszTarget); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_symlink_h */ + diff --git a/include/iprt/system.h b/include/iprt/system.h new file mode 100644 index 00000000..a4bef54d --- /dev/null +++ b/include/iprt/system.h @@ -0,0 +1,379 @@ +/** @file + * IPRT - System Information. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_system_h +#define IPRT_INCLUDED_system_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_system RTSystem - System Information + * @ingroup grp_rt + * @{ + */ + +/** + * Info level for RTSystemGetOSInfo(). + */ +typedef enum RTSYSOSINFO +{ + RTSYSOSINFO_INVALID = 0, /**< The usual invalid entry. */ + RTSYSOSINFO_PRODUCT, /**< OS product name. (uname -o) */ + RTSYSOSINFO_RELEASE, /**< OS release. (uname -r) */ + RTSYSOSINFO_VERSION, /**< OS version, optional. (uname -v) */ + RTSYSOSINFO_SERVICE_PACK, /**< Service/fix pack level, optional. */ + RTSYSOSINFO_END /**< End of the valid info levels. */ +} RTSYSOSINFO; + + +/** + * Queries information about the OS. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_PARAMETER if enmInfo is invalid. + * @retval VERR_INVALID_POINTER if pszInfoStr is invalid. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. The buffer will + * contain the chopped off result in this case, provided cchInfo isn't 0. + * @retval VERR_NOT_SUPPORTED if the info level isn't implemented. The buffer will + * contain an empty string. + * + * @param enmInfo The OS info level. + * @param pszInfo Where to store the result. + * @param cchInfo The size of the output buffer. + */ +RTDECL(int) RTSystemQueryOSInfo(RTSYSOSINFO enmInfo, char *pszInfo, size_t cchInfo); + +/** + * Queries the total amount of RAM in the system. + * + * This figure does not given any information about how much memory is + * currently available. Use RTSystemQueryAvailableRam instead. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and *pcb on sucess. + * @retval VERR_ACCESS_DENIED if the information isn't accessible to the + * caller. + * + * @param pcb Where to store the result (in bytes). + */ +RTDECL(int) RTSystemQueryTotalRam(uint64_t *pcb); + +/** + * Queries the total amount of RAM accessible to the system. + * + * This figure should not include memory that is installed but not used, + * nor memory that will be slow to bring online. The definition of 'slow' + * here is slower than swapping out a MB of pages to disk. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and *pcb on success. + * @retval VERR_ACCESS_DENIED if the information isn't accessible to the + * caller. + * + * @param pcb Where to store the result (in bytes). + */ +RTDECL(int) RTSystemQueryAvailableRam(uint64_t *pcb); + +/** + * Queries the amount of RAM that is currently locked down or in some other + * way made impossible to virtualize within reasonably short time. + * + * The purposes of this API is, when combined with RTSystemQueryTotalRam, to + * be able to determine an absolute max limit for how much fixed memory it is + * (theoretically) possible to allocate (or lock down). + * + * The kind memory covered by this function includes: + * - locked (wired) memory - like for instance RTR0MemObjLockUser + * and RTR0MemObjLockKernel makes, + * - kernel pools and heaps - like for instance the ring-0 variant + * of RTMemAlloc taps into, + * - fixed (not pageable) kernel allocations - like for instance + * all the RTR0MemObjAlloc* functions makes, + * - any similar memory that isn't easily swapped out, discarded, + * or flushed to disk. + * + * This works against the value returned by RTSystemQueryTotalRam, and + * the value reported by this function can never be larger than what a + * call to RTSystemQueryTotalRam returns. + * + * The short time term here is relative to swapping to disk like in + * RTSystemQueryTotalRam. This could mean that (part of) the dirty buffers + * in the dynamic I/O cache could be included in the total. If the dynamic + * I/O cache isn't likely to either flush buffers when the load increases + * and put them back into normal circulation, they should be included in + * the memory accounted for here. + * + * @retval VINF_SUCCESS and *pcb on success. + * @retval VERR_NOT_SUPPORTED if the information isn't available on the + * system in general. The caller must handle this scenario. + * @retval VERR_ACCESS_DENIED if the information isn't accessible to the + * caller. + * + * @param pcb Where to store the result (in bytes). + * + * @remarks This function could've been inverted and called + * RTSystemQueryAvailableRam, but that might give impression that + * it would be possible to allocate the amount of memory it + * indicates for a single purpose, something which would be very + * improbable on most systems. + * + * @remarks We might have to add another output parameter to this function + * that indicates if some of the memory kinds listed above cannot + * be accounted for on the system and therefore is not include in + * the returned amount. + */ +RTDECL(int) RTSystemQueryUnavailableRam(uint64_t *pcb); + + +/** + * The DMI strings. + */ +typedef enum RTSYSDMISTR +{ + /** Invalid zero entry. */ + RTSYSDMISTR_INVALID = 0, + /** The product name. */ + RTSYSDMISTR_PRODUCT_NAME, + /** The product version. */ + RTSYSDMISTR_PRODUCT_VERSION, + /** The product UUID. */ + RTSYSDMISTR_PRODUCT_UUID, + /** The product serial. */ + RTSYSDMISTR_PRODUCT_SERIAL, + /** The system manufacturer. */ + RTSYSDMISTR_MANUFACTURER, + /** The end of the valid strings. */ + RTSYSDMISTR_END, + /** The usual 32-bit hack. */ + RTSYSDMISTR_32_BIT_HACK = 0x7fffffff +} RTSYSDMISTR; + +/** + * Queries a DMI string. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. The buffer will + * contain the chopped off result in this case, provided cbBuf isn't 0. + * @retval VERR_ACCESS_DENIED if the information isn't accessible to the + * caller. + * @retval VERR_NOT_SUPPORTED if the information isn't available on the system + * in general. The caller must expect this status code and deal with + * it. + * + * @param enmString Which string to query. + * @param pszBuf Where to store the string. This is always + * terminated, even on error. + * @param cbBuf The buffer size. + */ +RTDECL(int) RTSystemQueryDmiString(RTSYSDMISTR enmString, char *pszBuf, size_t cbBuf); + +/** @name Flags for RTSystemReboot and RTSystemShutdown. + * @{ */ +/** Reboot the system after shutdown. */ +#define RTSYSTEM_SHUTDOWN_REBOOT UINT32_C(0) +/** Reboot the system after shutdown. + * The call may return VINF_SYS_MAY_POWER_OFF if the OS / + * hardware combination may power off instead of halting. */ +#define RTSYSTEM_SHUTDOWN_HALT UINT32_C(1) +/** Power off the system after shutdown. + * This may be equvivalent to a RTSYSTEM_SHUTDOWN_HALT on systems where we + * cannot figure out whether the hardware/OS implements the actual powering + * off. If we can figure out that it's not supported, an + * VERR_SYS_CANNOT_POWER_OFF error is raised. */ +#define RTSYSTEM_SHUTDOWN_POWER_OFF UINT32_C(2) +/** Power off the system after shutdown, or halt it if that's not possible. */ +#define RTSYSTEM_SHUTDOWN_POWER_OFF_HALT UINT32_C(3) +/** The shutdown action mask. */ +#define RTSYSTEM_SHUTDOWN_ACTION_MASK UINT32_C(3) +/** Unplanned shutdown/reboot. */ +#define RTSYSTEM_SHUTDOWN_UNPLANNED UINT32_C(0) +/** Planned shutdown/reboot. */ +#define RTSYSTEM_SHUTDOWN_PLANNED RT_BIT_32(2) +/** Force the system to shutdown/reboot regardless of objecting application + * or other stuff. This flag might not be realized on all systems. */ +#define RTSYSTEM_SHUTDOWN_FORCE RT_BIT_32(3) +/** Parameter validation mask. */ +#define RTSYSTEM_SHUTDOWN_VALID_MASK UINT32_C(0x0000000f) +/** @} */ + +/** + * Shuts down the system. + * + * @returns IPRT status code on failure, on success it may or may not return + * depending on the OS. + * @retval VINF_SUCCESS + * @retval VINF_SYS_MAY_POWER_OFF + * @retval VERR_SYS_SHUTDOWN_FAILED + * @retval VERR_SYS_CANNOT_POWER_OFF + * + * @param cMsDelay The delay before the actual reboot. If this is + * not supported by the OS, an immediate reboot + * will be performed. + * @param fFlags Shutdown flags, see RTSYSTEM_SHUTDOWN_XXX. + * @param pszLogMsg Message for the log and users about why we're + * shutting down. + */ +RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char *pszLogMsg); + +/** + * Checks if we're executing inside a virtual machine (VM). + * + * The current implemention is very simplistic and won't try to detect the + * presence of a virtual machine monitor (VMM) unless it openly tells us it is + * there. + * + * @returns true if inside a VM, false if on real hardware. + * + * @todo If more information is needed, like which VMM it is and which + * version and such, add one or two new APIs. + */ +RTDECL(bool) RTSystemIsInsideVM(void); + +/** + * System firmware types. + */ +typedef enum RTSYSFWTYPE +{ + /** Invalid zero value. */ + RTSYSFWTYPE_INVALID = 0, + /** Unknown firmware. */ + RTSYSFWTYPE_UNKNOWN, + /** Firmware is BIOS. */ + RTSYSFWTYPE_BIOS, + /** Firmware is UEFI. */ + RTSYSFWTYPE_UEFI, + /** End valid firmware values (exclusive). */ + RTSYSFWTYPE_END, + /** The usual 32-bit hack. */ + RTSYSFWTYPE_32_BIT_HACK = 0x7fffffff +} RTSYSFWTYPE; +/** Pointer to a system firmware type. */ +typedef RTSYSFWTYPE *PRTSYSFWTYPE; + +/** + * Queries the system's firmware type. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if not supported or implemented. + * @param penmType Where to return the firmware type on success. + */ +RTDECL(int) RTSystemQueryFirmwareType(PRTSYSFWTYPE penmType); + +/** + * Translates the @a enmType value to a string. + * + * @returns Read-only name. + * @param enmType The firmware type to convert to string. + */ +RTDECL(const char *) RTSystemFirmwareTypeName(RTSYSFWTYPE enmType); + +/** + * Boolean firmware values queriable via RTSystemQueryFirmwareBoolean(). + */ +typedef enum RTSYSFWBOOL +{ + /** Invalid property, do not use. */ + RTSYSFWBOOL_INVALID = 0, + /** Whether Secure Boot is enabled or not (type: boolean). */ + RTSYSFWBOOL_SECURE_BOOT, + /** End of valid */ + RTSYSFWBOOL_END, + /** The usual 32-bit hack. */ + RTSYSFWBOOL_32_BIT_HACK = 0x7fffffff +} RTSYSFWBOOL; + +/** + * Queries the value of a firmware property. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if we cannot query firmware properties on the host. + * @retval VERR_SYS_UNSUPPORTED_FIRMWARE_PROPERTY if @a enmBoolean isn't + * supported. + * @param enmBoolean The value to query. + * @param pfValue Where to return the value. + */ +RTDECL(int) RTSystemQueryFirmwareBoolean(RTSYSFWBOOL enmBoolean, bool *pfValue); + +#ifdef RT_OS_WINDOWS + +/** + * Get the Windows NT build number. + * + * @returns NT build number. + * + * @remarks Windows NT only. Requires IPRT to be initialized. + */ +RTDECL(uint32_t) RTSystemGetNtBuildNo(void); + +/** Makes an NT version for comparison with RTSystemGetNtVersion(). */ +# define RTSYSTEM_MAKE_NT_VERSION(a_uMajor, a_uMinor, a_uBuild) \ + ( ((uint64_t)(a_uMajor) << 52) | ((uint64_t)((a_uMinor) & 0xfffU) << 40) | ((uint32_t)(a_uBuild)) ) +/** Extracts the major version number from a RTSYSTEM_MAKE_NT_VERSION value. */ +# define RTSYSTEM_NT_VERSION_GET_MAJOR(a_uNtVersion) ((uint32_t)((a_uNtVersion) >> 52)) +/** Extracts the minor version number from a RTSYSTEM_MAKE_NT_VERSION value. */ +# define RTSYSTEM_NT_VERSION_GET_MINOR(a_uNtVersion) ((uint32_t)((a_uNtVersion) >> 40) & UINT32_C(0xfff)) +/** Extracts the build number from a RTSYSTEM_MAKE_NT_VERSION value. */ +# define RTSYSTEM_NT_VERSION_GET_BUILD(a_uNtVersion) ((uint32_t)(a_uNtVersion)) + +/** + * Get the Windows NT version number. + * + * @returns Version formatted using RTSYSTEM_MAKE_NT_VERSION(). + * + * @remarks Windows NT only. Requires IPRT to be initialized. + */ +RTDECL(uint64_t) RTSystemGetNtVersion(void); + +/** + * Get the Windows NT product type (OSVERSIONINFOW::wProductType). + */ +RTDECL(uint8_t) RTSystemGetNtProductType(void); + +#endif /* RT_OS_WINDOWS */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_system_h */ + diff --git a/include/iprt/table.h b/include/iprt/table.h new file mode 100644 index 00000000..d8bd8f88 --- /dev/null +++ b/include/iprt/table.h @@ -0,0 +1,726 @@ +/** @file + * IPRT - Abstract Table/Trees. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_table_h +#define IPRT_INCLUDED_table_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/** @defgroup grp_rt_tab RTTab - Generic Tree and Table Interface. + * @ingroup grp_rt + * @{ + */ + +RT_C_DECLS_BEGIN + +/** Pointer to an allocator. */ +typedef struct RTTABALLOCATOR *PRTTABALLOCATOR; + +/** + * Allocates memory. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. (don't throw!) + * @param pAllocator The allocator structure. + * @param cb The number of bytes to allocate. (Never 0.) + */ +typedef DECLCALLBACKTYPE(void *, FNRTTABALLOC,(PRTTABALLOCATOR pAllocator, size_t cb)); +/** Pointer to a FNRTTABALLOC() function. */ +typedef FNRTTABALLOC *PFNRTTABALLOC; + +/** + * Frees memory. + * + * @param pAllocator The allocator structure. + * @param pv The memory to free. (can be NULL) + */ +typedef DECLCALLBACKTYPE(void *, FNRTTABFREE,(PRTTABALLOCATOR pAllocator, void *pv)); +/** Pointer to a FNRTTABFREE() function. */ +typedef FNRTTABFREE *PFNRTTABFREE; + +/** + * The allocator structure. + * (Hint: use this as like 'base class' for your custom allocators.) + */ +typedef struct RTTABALLOCATOR +{ + /** The allocation function. */ + PFNRTTABALLOC pfnAlloc; + /** The free function. */ + PFNRTTABFREE pfnFree; +} RTTABALLOCATOR; + +/** + * Gets the default allocator. + * + * @returns Pointer to the default allocator. + */ +RTDECL(RTTABALLOCATOR) RTTabDefaultAllocator(void); + + +/** + * Compares two table items. + * + * @returns 0 if equal + * @returns <0 if pvItem1 is less than pvItem2 (pvItem2 is then greater than pvItem1). + * @returns >0 if pvItem1 is less than pvItem2 (pvItem1 is then greater than pvItem2). + * + * @param pvItem1 The first item. + * @param pvItem2 The second item. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTTABCOMP,(const void *pvItem1, const void *pvItem2, void *pvUser)); +/** Pointer to a FNRTTABCOMP() function. */ +typedef FNRTTABCOMP *PFNRTTABCOMP; + +/** + * Duplicates a table item. + * This is used when duplicating or copying a table. + * + * @returns Pointer to the copy. + * @returns NULL on failure. + * + * @param pvItem The item to copy. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(void *, FNRTTABDUPLICATE,(const void *pvItem, void *pvUser)); +/** Pointer to a FNRTTABDUPLICATE() function. */ +typedef FNRTTABDUPLICATE *PFNRTTABDUPLICATE; + +/** + * Callback function for doing something with an item. + * + * What exactly we're doing is specific to the context of the call. + * + * @param pvItem The item. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(void, FNRTTABCALLBACK,(const void *pvItem, void *pvUser)); +/** Pointer to a FNRTTABCALLBACK() function. */ +typedef FNRTTABCALLBACK *PFNRTTABCALLBACK; + + +/** Pointer to const table operations. */ +typedef const struct RTTABOPS *PCRTTABOPS; +/** Pointer to a table. */ +typedef struct RTTAB *PRTTAB; +/** Pointer to a const table. */ +typedef const struct RTTAB *PCRTTAB; +/** Pointer to a traverser. */ +typedef struct RTTABTRAVERSER *PRTTABTRAVERSER; +/** Pointer to a const traverser. */ +typedef const struct RTTABTRAVERSER *PCRTTABTRAVERSER; +/** Pointer to a traverser core. */ +typedef struct RTTABTRAVERSERCORE *PRTTABTRAVERSERCORE; +/** Pointer to a const traverser core. */ +typedef const struct RTTABTRAVERSERCORE *PCRTTABTRAVERSERCORE; + + +/** + * Table operations. + */ +typedef struct RTTABOPS +{ + /** + * Create a table. + * + * @returns Pointer to the new table. + * @returns NULL if we're out of memory or some other resource. + * @param pOps The table operations. + * @param fCreateFlags The table type specific creation flags. + * @param pAllocator Custom allocator. Pass NULL for the default allocator. + * @param pfnComp The comparision function. + */ + DECLCALLBACKMEMBER(PRTTAB, pfnCreate,(PCRTTABOPS pOps, unsigned fCreateFlags, PRTTABALLOCATOR pAllocator, PFNRTTABCOMP pfnComp)); + + /** + * Duplicates a table to a table of the same type. + * + * @returns Pointer to the new table. + * @returns NULL if we're out of memory or some other resource. + * @param pTab The table to duplicate. + * @param pfnDuplicate Pointer to the item duplication function. If NULL the new table will + * be referencing the same data as the old one. + * @param pfnNewCB Callback which is called for all the items in the new table. Optional. + * @param pAllocator Custom allocator. Pass NULL to use the same allocator as pTab. + */ + DECLCALLBACKMEMBER(PRTTAB, pfnDuplicate,(PCRTTAB pTab, PFNRTTABDUPLICATE pfnDuplicate, PFNRTTABCALLBACK pfnNewCB, PRTTABALLOCATOR pAllocator)); + + /** + * Destroys a table. + * + * @param pTab The table to destroy. + */ + DECLCALLBACKMEMBER(void, pfnDestroy,(PRTTAB pTab)); + + /** + * Inserts an item into the table, if a matching item is encountered + * the pointer to the pointer to it will be returned. + * + * @returns Pointer to the item pointer in the table. + * This can be used to replace existing items (don't break anything, dude). + * @returns NULL if we failed to allocate memory for the new node. + * @param pTab The table. + * @param pvItem The item which will be inserted if an matching item was not found in the table. + */ + DECLCALLBACKMEMBER(void **, pfnProbe,(PRTTAB pTab, void *pvItem)); + + /** + * Inserts an item into the table, fail if a matching item exists. + * + * @returns NULL on success and allocation failure. + * @returns Pointer to the matching item. + * @param pTab The table. + * @param pvItem The item which is to be inserted. + */ + DECLCALLBACKMEMBER(void *, pfnInsert,(PRTTAB pTab, void *pvItem)); + + /** + * Inserts an item into the table, if a matching item is encountered + * it will be replaced and returned. + * + * @returns NULL if inserted and allocation failure. + * @returns Pointer to the replaced item. + * @param pTab The table. + * @param pvItem The item which is to be inserted. + */ + DECLCALLBACKMEMBER(void *, pfnReplace,(PRTTAB pTab, void *pvItem)); + + /** + * Removes an item from the table if found. + * + * @returns Pointer to the removed item. + * @returns NULL if no item matched pvItem. + * @param pTab The table. + * @param pvItem The item which is to be inserted. + */ + DECLCALLBACKMEMBER(void *, pfnRemove,(PRTTAB pTab, const void *pvItem)); + + /** + * Finds an item in the table. + * + * @returns Pointer to the item it found. + * @returns NULL if no item matched pvItem. + * @param pTab The table. + * @param pvItem The item which is to be inserted. + */ + DECLCALLBACKMEMBER(void *, pfnFind,(PRTTAB pTab, const void *pvItem)); + + /** + * Initializes a traverser to the NULL item. + * + * The NULL item is an imaginary table item before the first and after + * the last items in the table. + * + * @returns Pointer to the traverser positioned at the NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + */ + DECLCALLBACKMEMBER(PRTTABTRAVERSERCORE, pfnTravInit,(PRTTAB pTab, PRTTABTRAVERSER pTravNew)); + + /** + * Initializes a traverser to the first item in the table. + * + * If the table is empty, the traverser will be positioned at the NULL item + * like with RTTabTravInit(). + * + * @returns Pointer to the traverser positioned at the first item or NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + */ + DECLCALLBACKMEMBER(PRTTABTRAVERSERCORE, pfnTravFirst,(PRTTAB pTab, PRTTABTRAVERSER pTravNew)); + + /** + * Initializes a traverser to the last item in the table. + * + * If the table is empty, the traverser will be positioned at the NULL item + * like with RTTabTravInit(). + * + * @returns Pointer to the traverser positioned at the last item or NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + */ + DECLCALLBACKMEMBER(PRTTABTRAVERSERCORE, pfnTravLast,(PRTTAB pTab, PRTTABTRAVERSER pTravNew)); + + /** + * Initializes a traverser to an item matching the given one. + * + * If the item isn't found, the traverser will be positioned at the NULL item + * like with RTTabTravInit(). + * + * @returns Pointer to the traverser positioned at the matching item or NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + * @param pvItem The item to find the match to. + */ + DECLCALLBACKMEMBER(PRTTABTRAVERSERCORE, pfnTravFind,(PRTTAB pTab, PRTTABTRAVERSER pTravNew, const void *pvItem)); + + /** + * Initializes a traverser to the inserted item. + * + * If there already exists an item in the tree matching pvItem, the traverser + * is positioned at that item like with RTTabTravFind(). + * + * If the insert operation failes because of an out of memory condition, the + * traverser will be positioned at the NULL item like with RTTabTravInit(). + * + * @returns Pointer to the traverser positioned at the inserted, existing or NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + * @param pvItem The item to be inserted. + */ + DECLCALLBACKMEMBER(PRTTABTRAVERSERCORE, pfnTravInsert,(PRTTAB pTab, PRTTABTRAVERSER pTravNew, void *pvItem)); + + /** + * Duplicates a traverser. + * + * @returns The pointer to the duplicate. + * @returns NULL on allocation failure. + * + * @param pTrav The traverser to duplicate. + * @param pTravNew Pointer to a preallocated structure. Optional. + */ + DECLCALLBACKMEMBER(PRTTABTRAVERSERCORE, pfnTravDuplicate,(PRTTABTRAVERSERCORE pTrav, PCRTTABTRAVERSER pTravNew)); + + /** + * Frees a traverser. + * + * This can safely be called even if the traverser structure + * wasn't dynamically allocated or the constructor failed. + * + * @param pTrav The traverser which is to be free. + */ + DECLCALLBACKMEMBER(void, pfnTravFree,(PRTTABTRAVERSERCORE pTrav)); + + /** + * Gets the current item. + * + * @returns The current item. (NULL indicates the imaginary NULL item.) + * @param pTrav The traverser. + */ + DECLCALLBACKMEMBER(void *, pfnTravCur,(PCRTTABTRAVERSERCORE pTrav)); + + /** + * Advances to the next item. + * + * @returns The new current item. (NULL indicates the imaginary NULL item.) + * @param pTrav The traverser. + */ + DECLCALLBACKMEMBER(void *, pfnTravNext,(PRTTABTRAVERSERCORE pTrav)); + + /** + * Advances to the previous item. + * + * @returns The new current item. (NULL indicates the imaginary NULL item.) + * @param pTrav The traverser. + */ + DECLCALLBACKMEMBER(void *, pfnTravPrev,(PRTTABTRAVERSERCORE pTrav)); + + /** + * Replaces the current item. + * + * This has the same restrictions as RTTabProbe(), e.g. it's not permitted to + * break the order of the table. + * + * @returns The replaced item. + * @returns NULL if the current item is the NULL item. The traverser + * and table remains unchanged. + * @param pTrav The traverser. + * @param pvItem The item to be inserted. + */ + DECLCALLBACKMEMBER(void *, pfnTravReplace,(PRTTABTRAVERSERCORE pTrav, void *pvItem)); + + /** The type of table type. */ + const char *pszType; +} RTTABOPS; + +/** + * A table. + */ +typedef struct RTTAB +{ + /** The table operations. */ + PCRTTABOPS pOps; + /** The function for comparing table items. */ + PFNRTTABCOMP pfnComp; + /** The number of items in the table. */ + RTUINT cItems; + /** The table generation number. + * This must be updated whenever the table changes. */ + RTUINT idGeneration; +} RTTAB; + + +/** + * Create a table. + * + * @returns Pointer to the new table. + * @returns NULL if we're out of memory or some other resource. + * @param pOps The table operations. + * @param fCreateFlags The table type specific creation flags. + * @param pAllocator Custom allocator. Pass NULL for the default allocator. + * @param pfnComp The comparision function. + */ +DECLINLINE(PRTTAB) RTTabCreate(PCRTTABOPS pOps, unsigned fCreateFlags, PRTTABALLOCATOR pAllocator, PFNRTTABCOMP pfnComp) +{ + return pOps->pfnCreate(pOps, fCreateFlags, pAllocator, pfnComp); +} + +/** + * Duplicates a table to a table of the same type. + * + * @returns Pointer to the new table. + * @returns NULL if we're out of memory or some other resource. + * @param pTab The table to duplicate. + * @param pfnDuplicate Pointer to the item duplication function. If NULL the new table will + * be referencing the same data as the old one. + * @param pfnNewCB Callback which is called for all the items in the new table. Optional. + * @param pAllocator Custom allocator. Pass NULL to use the same allocator as pTab. + */ +DECLINLINE(PRTTAB) RTTabDuplicate(PCRTTAB pTab, PFNRTTABDUPLICATE pfnDuplicate, PFNRTTABCALLBACK pfnNewCB, PRTTABALLOCATOR pAllocator) +{ + return pTab->pOps->pfnDuplicate(pTab, pfnDuplicate, pfnNewCB, pAllocator); +} + +/** + * Destroys a table. + * + * @param pTab The table to destroy. + */ +DECLINLINE(void) RTTabDestroy(PRTTAB pTab) +{ + pTab->pOps->pfnDestroy(pTab); +} + +/** + * Count the item in the table. + * + * @returns Number of items in the table. + * @param pTab The table to count. + */ +DECLINLINE(RTUINT) RTTabCount(PRTTAB pTab) +{ + return pTab->cItems; +} + +/** + * Inserts an item into the table, if a matching item is encountered + * the pointer to the pointer to it will be returned. + * + * @returns Pointer to the item pointer in the table. + * This can be used to replace existing items (don't break anything, dude). + * @returns NULL if we failed to allocate memory for the new node. + * @param pTab The table. + * @param pvItem The item which will be inserted if an matching item was not found in the table. + */ +DECLINLINE(void **) RTTabProbe(PRTTAB pTab, void *pvItem) +{ + return pTab->pOps->pfnProbe(pTab, pvItem); +} + +/** + * Inserts an item into the table, fail if a matching item exists. + * + * @returns NULL on success and allocation failure. + * @returns Pointer to the matching item. + * @param pTab The table. + * @param pvItem The item which is to be inserted. + */ +DECLINLINE(void *) RTTabInsert(PRTTAB pTab, void *pvItem) +{ + return pTab->pOps->pfnInsert(pTab, pvItem); +} + +/** + * Inserts an item into the table, if a matching item is encountered + * it will be replaced and returned. + * + * @returns NULL if inserted and allocation failure. + * @returns Pointer to the replaced item. + * @param pTab The table. + * @param pvItem The item which is to be inserted. + */ +DECLINLINE(void *) RTTabReplace(PRTTAB pTab, void *pvItem) +{ + return pTab->pOps->pfnReplace(pTab, pvItem); +} + +/** + * Removes an item from the table if found. + * + * @returns Pointer to the removed item. + * @returns NULL if no item matched pvItem. + * @param pTab The table. + * @param pvItem The item which is to be inserted. + */ +DECLINLINE(void *) RTTabRemove(PRTTAB pTab, const void *pvItem) +{ + return pTab->pOps->pfnRemove(pTab, pvItem); +} + +/** + * Finds an item in the table. + * + * @returns Pointer to the item it found. + * @returns NULL if no item matched pvItem. + * @param pTab The table. + * @param pvItem The item to find the match to. + */ +DECLINLINE(void *) RTTabFind(PRTTAB pTab, const void *pvItem) +{ + return pTab->pOps->pfnFind(pTab, pvItem); +} + + +/** + * Common traverser core. + */ +typedef struct RTTABTRAVERSERCORE +{ + /** The table being traversed. */ + PRTTAB pTab; + /** Indicates that this traverser was allocated. */ + bool fAllocated; + /** The table generation id this traverser was last updated for. + * This is used to catch up with table changes. */ + RTUINT idGeneration; +} RTTABTRAVERSERCORE; + +/** + * Generic traverser structure. + * + * Tree implementations will use the tree specific part by mapping + * this structure onto their own internal traverser structure. + * + * @remark It would be better to use alloca() for allocating the structure, + * OTOH this is simpler for the user. + */ +typedef struct RTTABTRAVERSER +{ + /** The common core of the traverser data. */ + RTTABTRAVERSERCORE Core; + /** The tree specific data. */ + void *apvTreeSpecific[32]; +} RTTABTRAVERSER; + + +/** + * Initializes a traverser to the NULL item. + * + * The NULL item is an imaginary table item before the first and after + * the last items in the table. + * + * @returns Pointer to the traverser positioned at the NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + */ +DECLINLINE(PRTTABTRAVERSERCORE) RTTabTravInit(PRTTAB pTab, PRTTABTRAVERSER pTravNew) +{ + return pTab->pOps->pfnTravInit(pTab, pTravNew); +} + +/** + * Initializes a traverser to the first item in the table. + * + * If the table is empty, the traverser will be positioned at the NULL item + * like with RTTabTravInit(). + * + * @returns Pointer to the traverser positioned at the first item or NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + */ +DECLINLINE(PRTTABTRAVERSERCORE) RTTabTravFirst(PRTTAB pTab, PRTTABTRAVERSER pTravNew) +{ + return pTab->pOps->pfnTravFirst(pTab, pTravNew); +} + +/** + * Initializes a traverser to the last item in the table. + * + * If the table is empty, the traverser will be positioned at the NULL item + * like with RTTabTravInit(). + * + * @returns Pointer to the traverser positioned at the last item or NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + */ +DECLINLINE(PRTTABTRAVERSERCORE) RTTabTravLast(PRTTAB pTab, PRTTABTRAVERSER pTravNew) +{ + return pTab->pOps->pfnTravLast(pTab, pTravNew); +} + +/** + * Initializes a traverser to an item matching the given one. + * + * If the item isn't found, the traverser will be positioned at the NULL item + * like with RTTabTravInit(). + * + * @returns Pointer to the traverser positioned at the matching item or NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + * @param pvItem The item to find the match to. + */ +DECLINLINE(PRTTABTRAVERSERCORE) RTTabTravFind(PRTTAB pTab, PRTTABTRAVERSER pTravNew, const void *pvItem) +{ + return pTab->pOps->pfnTravFind(pTab, pTravNew, pvItem); +} + +/** + * Initializes a traverser to the inserted item. + * + * If there already exists an item in the tree matching pvItem, the traverser + * is positioned at that item like with RTTabTravFind(). + * + * If the insert operation failes because of an out of memory condition, the + * traverser will be positioned at the NULL item like with RTTabTravInit(). + * + * @returns Pointer to the traverser positioned at the inserted, existing or NULL item. + * @returns NULL on failure to allocate the traverser. + * + * @param pTab The table. + * @param pTravNew Pointer to a preallocated structure. Optional. + * @param pvItem The item to be inserted. + */ +DECLINLINE(PRTTABTRAVERSERCORE) RTTabTravInsert(PRTTAB pTab, PRTTABTRAVERSER pTravNew, void *pvItem) +{ + return pTab->pOps->pfnTravInsert(pTab, pTravNew, pvItem); +} + +/** + * Duplicates a traverser. + * + * @returns The pointer to the duplicate. + * @returns NULL on allocation failure. + * + * @param pTrav The traverser to duplicate. + * @param pTravNew Pointer to a preallocated structure. Optional. + */ +DECLINLINE(PRTTABTRAVERSERCORE) RTTabTravDuplicate(PRTTABTRAVERSERCORE pTrav, PCRTTABTRAVERSER pTravNew) +{ + if (pTrav) + return pTrav->pTab->pOps->pfnTravDuplicate(pTrav, pTravNew); + return NULL; +} + +/** + * Frees a traverser. + * + * This can safely be called even if the traverser structure + * wasn't dynamically allocated or the constructor failed. + * + * @param pTrav The traverser which is to be free. + */ +DECLINLINE(void) RTTabTravFree(PRTTABTRAVERSERCORE pTrav) +{ + if (pTrav && pTrav->fAllocated) + pTrav->pTab->pOps->pfnTravFree(pTrav); +} + +/** + * Gets the current item. + * + * @returns The current item. (NULL indicates the imaginary NULL item.) + * @param pTrav The traverser. + */ +DECLINLINE(void *) RTTabTravCur(PCRTTABTRAVERSERCORE pTrav) +{ + return pTrav->pTab->pOps->pfnTravCur(pTrav); +} + +/** + * Advances to the next item. + * + * @returns The new current item. (NULL indicates the imaginary NULL item.) + * @param pTrav The traverser. + */ +DECLINLINE(void *) RTTabTravNext(PRTTABTRAVERSERCORE pTrav) +{ + return pTrav->pTab->pOps->pfnTravNext(pTrav); +} + +/** + * Advances to the previous item. + * + * @returns The new current item. (NULL indicates the imaginary NULL item.) + * @param pTrav The traverser. + */ +DECLINLINE(void *) RTTabTravPrev(PRTTABTRAVERSERCORE pTrav) +{ + return pTrav->pTab->pOps->pfnTravPrev(pTrav); +} + +/** + * Replaces the current item. + * + * This has the same restrictions as RTTabProbe(), e.g. it's not permitted to + * break the order of the table. + * + * @returns The replaced item. + * @returns NULL if the current item is the NULL item. The traverser + * and table remains unchanged. + * @param pTrav The traverser. + * @param pvItem The item to be inserted. + */ +DECLINLINE(void *) RTTabTravReplace(PRTTABTRAVERSERCORE pTrav, void *pvItem) +{ + return pTrav->pTab->pOps->pfnTravReplace(pTrav, pvItem); +} + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_table_h */ diff --git a/include/iprt/tar.h b/include/iprt/tar.h new file mode 100644 index 00000000..9acc0d40 --- /dev/null +++ b/include/iprt/tar.h @@ -0,0 +1,184 @@ +/** @file + * IPRT - Tar archive I/O. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_tar_h +#define IPRT_INCLUDED_tar_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/time.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_tar RTTar - Tar archive I/O + * @ingroup grp_rt + * + * @deprecated Only used for legacy code and writing. Migrate new code to the + * VFS interface, add the write part when needed. + * + * @{ + */ + +/** A tar handle */ +typedef R3PTRTYPE(struct RTTARINTERNAL *) RTTAR; +/** Pointer to a RTTAR interface handle. */ +typedef RTTAR *PRTTAR; +/** Nil RTTAR interface handle. */ +#define NIL_RTTAR ((RTTAR)0) + +/** A tar file handle */ +typedef R3PTRTYPE(struct RTTARFILEINTERNAL *) RTTARFILE; +/** Pointer to a RTTARFILE interface handle. */ +typedef RTTARFILE *PRTTARFILE; +/** Nil RTTARFILE interface handle. */ +#define NIL_RTTARFILE ((RTTARFILE)0) + +/** Maximum length of a tar filename, excluding the terminating '\0'. More + * does not fit into a tar record. */ +#define RTTAR_NAME_MAX 99 + +/** + * Creates a Tar archive. + * + * Use the mask to specify the access type. + * + * @returns IPRT status code. + * + * @param phTar Where to store the RTTAR handle. + * @param pszTarname The file name of the tar archive to create. Should + * not exist. + * @param fMode Open flags, i.e a combination of the RTFILE_O_* defines. + * The ACCESS, ACTION and DENY flags are mandatory! + */ +RTR3DECL(int) RTTarOpen(PRTTAR phTar, const char *pszTarname, uint32_t fMode); + +/** + * Close the Tar archive. + * + * @returns IPRT status code. + * + * @param hTar Handle to the RTTAR interface. + */ +RTR3DECL(int) RTTarClose(RTTAR hTar); + +/** + * Open a file in the Tar archive. + * + * @returns IPRT status code. + * + * @param hTar The handle of the tar archive. + * @param phFile Where to store the handle to the opened file. + * @param pszFilename Path to the file which is to be opened. (UTF-8) + * @param fOpen Open flags, i.e a combination of the RTFILE_O_* defines. + * The ACCESS, ACTION flags are mandatory! DENY flags + * are currently not supported. + * + * @remarks Write mode means append mode only. It is not possible to make + * changes to existing files. + * + * @remarks Currently it is not possible to open more than one file in write + * mode. Although open more than one file in read only mode (even when + * one file is opened in write mode) is always possible. + */ +RTR3DECL(int) RTTarFileOpen(RTTAR hTar, PRTTARFILE phFile, const char *pszFilename, uint32_t fOpen); + +/** + * Close the file opened by RTTarFileOpen. + * + * @returns IPRT status code. + * + * @param hFile The file handle to close. + */ +RTR3DECL(int) RTTarFileClose(RTTARFILE hFile); + +/** + * Read bytes from a file at a given offset. + * This function may modify the file position. + * + * @returns IPRT status code. + * + * @param hFile Handle to the file. + * @param off Where to read. + * @param pvBuf Where to put the bytes we read. + * @param cbToRead How much to read. + * @param pcbRead Where to return how much we actually read. If NULL + * an error will be returned for a partial read. + */ +RTR3DECL(int) RTTarFileReadAt(RTTARFILE hFile, uint64_t off, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Write bytes to a file at a given offset. + * This function may modify the file position. + * + * @returns IPRT status code. + * + * @param hFile Handle to the file. + * @param off Where to write. + * @param pvBuf What to write. + * @param cbToWrite How much to write. + * @param pcbWritten Where to return how much we actually wrote. If NULL + * an error will be returned for a partial write. + */ +RTR3DECL(int) RTTarFileWriteAt(RTTARFILE hFile, uint64_t off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + +/** + * Query the size of the file. + * + * @returns IPRT status code. + * + * @param hFile Handle to the file. + * @param pcbSize Where to store the filesize. + */ +RTR3DECL(int) RTTarFileGetSize(RTTARFILE hFile, uint64_t *pcbSize); + +/** + * Set the size of the file. + * + * @returns IPRT status code. + * + * @param hFile Handle to the file. + * @param cbSize The new file size. + */ +RTR3DECL(int) RTTarFileSetSize(RTTARFILE hFile, uint64_t cbSize); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_tar_h */ + diff --git a/include/iprt/tcp.h b/include/iprt/tcp.h new file mode 100644 index 00000000..c637915e --- /dev/null +++ b/include/iprt/tcp.h @@ -0,0 +1,514 @@ +/** @file + * IPRT - TCP/IP. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_tcp_h +#define IPRT_INCLUDED_tcp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/thread.h> +#include <iprt/net.h> +#include <iprt/sg.h> +#include <iprt/socket.h> + +#ifdef IN_RING0 +# error "There are no RTFile APIs available Ring-0 Host Context!" +#endif + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_tcp RTTcp - TCP/IP + * @ingroup grp_rt + * @{ + */ + + +/** + * Serve a TCP Server connection. + * + * @returns iprt status code. + * @returns VERR_TCP_SERVER_STOP to terminate the server loop forcing + * the RTTcpCreateServer() call to return. + * @param hSocket The socket which the client is connected to. The call + * will close this socket. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTTCPSERVE,(RTSOCKET hSocket, void *pvUser)); +/** Pointer to a RTTCPSERVE(). */ +typedef FNRTTCPSERVE *PFNRTTCPSERVE; + +/** + * Create single connection at a time TCP Server in a separate thread. + * + * The thread will loop accepting connections and call pfnServe for + * each of the incoming connections in turn. The pfnServe function can + * return VERR_TCP_SERVER_STOP too terminate this loop. RTTcpServerDestroy() + * should be used to terminate the server. + * + * @returns iprt status code. + * @param pszAddress The address for creating a listening socket. + * If NULL or empty string the server is bound to all interfaces. + * @param uPort The port for creating a listening socket. + * @param enmType The thread type. + * @param pszThrdName The name of the worker thread. + * @param pfnServe The function which will serve a new client connection. + * @param pvUser User argument passed to pfnServe. + * @param ppServer Where to store the serverhandle. + */ +RTR3DECL(int) RTTcpServerCreate(const char *pszAddress, unsigned uPort, RTTHREADTYPE enmType, const char *pszThrdName, + PFNRTTCPSERVE pfnServe, void *pvUser, PPRTTCPSERVER ppServer); + +/** + * Create single connection at a time TCP Server. + * The caller must call RTTcpServerListen() to actually start the server. + * + * @returns iprt status code. + * @param pszAddress The address for creating a listening socket. + * If NULL the server is bound to all interfaces. + * @param uPort The port for creating a listening socket. + * @param ppServer Where to store the serverhandle. + */ +RTR3DECL(int) RTTcpServerCreateEx(const char *pszAddress, uint32_t uPort, PPRTTCPSERVER ppServer); + +/** + * Closes down and frees a TCP Server. + * This will also terminate any open connections to the server. + * + * @returns iprt status code. + * @param pServer Handle to the server. + */ +RTR3DECL(int) RTTcpServerDestroy(PRTTCPSERVER pServer); + +/** + * Listen for incoming connections. + * + * The function will loop accepting connections and call pfnServe for + * each of the incoming connections in turn. The pfnServe function can + * return VERR_TCP_SERVER_STOP too terminate this loop. A stopped server + * can only be destroyed. + * + * @returns iprt status code. + * @param pServer The server handle as returned from RTTcpServerCreateEx(). + * @param pfnServe The function which will serve a new client connection. + * @param pvUser User argument passed to pfnServe. + */ +RTR3DECL(int) RTTcpServerListen(PRTTCPSERVER pServer, PFNRTTCPSERVE pfnServe, void *pvUser); + +/** + * Listen and accept one incoming connection. + * + * This is an alternative to RTTcpServerListen for the use the callbacks are not + * possible. + * + * @returns IPRT status code. + * @retval VERR_TCP_SERVER_SHUTDOWN if shut down by RTTcpServerShutdown. + * @retval VERR_INTERRUPTED if the listening was interrupted. + * + * @param pServer The server handle as returned from RTTcpServerCreateEx(). + * @param phClientSocket Where to return the socket handle to the client + * connection (on success only). This must be closed + * by calling RTTcpServerDisconnectClient2(). + */ +RTR3DECL(int) RTTcpServerListen2(PRTTCPSERVER pServer, PRTSOCKET phClientSocket); + +/** + * Terminate the open connection to the server. + * + * @returns iprt status code. + * @param pServer Handle to the server. + */ +RTR3DECL(int) RTTcpServerDisconnectClient(PRTTCPSERVER pServer); + +/** + * Terminates an open client connect when using RTTcpListen2 + * + * @returns IPRT status code. + * @param hClientSocket The client socket handle. This will be invalid upon + * return, whether successful or not. NIL is quietly + * ignored (VINF_SUCCESS). + */ +RTR3DECL(int) RTTcpServerDisconnectClient2(RTSOCKET hClientSocket); + +/** + * Shuts down the server, leaving client connections open. + * + * @returns IPRT status code. + * @param pServer Handle to the server. + */ +RTR3DECL(int) RTTcpServerShutdown(PRTTCPSERVER pServer); + +/** + * Connect (as a client) to a TCP Server. + * + * @returns iprt status code. + * @param pszAddress The address to connect to. + * @param uPort The port to connect to. + * @param pSock Where to store the handle to the established connection. + */ +RTR3DECL(int) RTTcpClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock); + +/** Opaque pointer used by RTTcpClientConnectEx and RTTcpClientCancelConnect. */ +typedef struct RTTCPCLIENTCONNECTCANCEL *PRTTCPCLIENTCONNECTCANCEL; + +/** + * Connect (as a client) to a TCP Server, extended version. + * + * @returns iprt status code. + * @param pszAddress The address to connect to. + * @param uPort The port to connect to. + * @param pSock Where to store the handle to the established connection. + * @param cMillies Number of milliseconds to wait for the connect attempt to complete. + * Use RT_INDEFINITE_WAIT to wait for ever. + * Use RT_SOCKETCONNECT_DEFAULT_WAIT to wait for the default time + * configured on the running system. + * @param ppCancelCookie Where to store information for canceling the + * operation (from a different thread). Optional. + * + * The pointer _must_ be initialized to NULL before a + * series of connection attempts begins, i.e. at a time + * where there will be no RTTcpClientCancelConnect + * calls racing access. RTTcpClientCancelConnect will + * set it to a special non-NULL value that causes the + * current or/and next connect call to fail. + * + * @sa RTTcpClientCancelConnect + */ +RTR3DECL(int) RTTcpClientConnectEx(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock, + RTMSINTERVAL cMillies, PRTTCPCLIENTCONNECTCANCEL volatile *ppCancelCookie); + +/** + * Cancels a RTTcpClientConnectEx call on a different thread. + * + * @returns iprt status code. + * @param ppCancelCookie The address of the cookie pointer shared with the + * connect call. + */ +RTR3DECL(int) RTTcpClientCancelConnect(PRTTCPCLIENTCONNECTCANCEL volatile *ppCancelCookie); + +/** + * Close a socket returned by RTTcpClientConnect(). + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + */ +RTR3DECL(int) RTTcpClientClose(RTSOCKET hSocket); + +/** + * Close a socket returned by RTTcpClientConnect(). + * + * @returns iprt status code. + * @param hSocket The socket handle. + * @param fGracefulShutdown If true, try do a graceful shutdown of the + * outgoing pipe and draining any lingering input. + * This is sometimes better for the server side. + * If false, just close the connection without + * further ado. + */ +RTR3DECL(int) RTTcpClientCloseEx(RTSOCKET hSocket, bool fGracefulShutdown); + +/** + * Creates connected pair of TCP sockets. + * + * @returns IPRT status code. + * @param phServer Where to return the "server" side of the pair. + * @param phClient Where to return the "client" side of the pair. + * @param fFlags Reserved, must be zero. + * + * @note There is no server or client side, but we gotta call it something. + */ +RTR3DECL(int) RTTcpCreatePair(PRTSOCKET phServer, PRTSOCKET phClient, uint32_t fFlags); + +/** + * Receive data from a socket. + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + * @param pvBuffer Where to put the data we read. + * @param cbBuffer Read buffer size. + * @param pcbRead Number of bytes read. + * If NULL the entire buffer will be filled upon successful return. + * If not NULL a partial read can be done successfully. + */ +RTR3DECL(int) RTTcpRead(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead); + +/** + * Send data to a socket. + * + * @returns iprt status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket Socket descriptor. + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + */ +RTR3DECL(int) RTTcpWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer); + +/** + * Flush socket write buffers. + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + */ +RTR3DECL(int) RTTcpFlush(RTSOCKET hSocket); + +/** + * Enables or disables delaying sends to coalesce packets. + * + * The TCP/IP stack usually uses the Nagle algorithm (RFC 896) to implement the + * coalescing. + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + * @param fEnable When set to true enables coalescing. + */ +RTR3DECL(int) RTTcpSetSendCoalescing(RTSOCKET hSocket, bool fEnable); + +/** + * Sets send and receive buffer sizes. + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + * @param cbSize Buffer size in bytes. + */ +RTR3DECL(int) RTTcpSetBufferSize(RTSOCKET hSocket, uint32_t cbSize); + +/** + * Socket I/O multiplexing. + * Checks if the socket is ready for reading. + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + * @param cMillies Number of milliseconds to wait for the socket. + * Use RT_INDEFINITE_WAIT to wait for ever. + */ +RTR3DECL(int) RTTcpSelectOne(RTSOCKET hSocket, RTMSINTERVAL cMillies); + +/** + * Socket I/O multiplexing + * Checks if the socket is ready for one of the given events. + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + * @param fEvents Event mask to wait for. + * Use the RTSOCKET_EVT_* defines. + * @param pfEvents Where to store the event mask on return. + * @param cMillies Number of milliseconds to wait for the socket. + * Use RT_INDEFINITE_WAIT to wait for ever. + */ +RTR3DECL(int) RTTcpSelectOneEx(RTSOCKET hSocket, uint32_t fEvents, uint32_t *pfEvents, RTMSINTERVAL cMillies); + +#if 0 /* skipping these for now - RTTcpServer* handles this. */ +/** + * Listen for connection on a socket. + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + * @param cBackLog The maximum length the queue of pending connections + * may grow to. + */ +RTR3DECL(int) RTTcpListen(RTSOCKET hSocket, int cBackLog); + +/** + * Accept a connection on a socket. + * + * @returns iprt status code. + * @param hSocket Socket descriptor. + * @param uPort The port for accepting connection. + * @param pSockAccepted Where to store the handle to the accepted connection. + */ +RTR3DECL(int) RTTcpAccept(RTSOCKET hSocket, unsigned uPort, PRTSOCKET pSockAccepted); + +#endif + +/** + * Gets the address of the local side. + * + * @returns IPRT status code. + * @param hSocket Socket descriptor. + * @param pAddr Where to store the local address on success. + */ +RTR3DECL(int) RTTcpGetLocalAddress(RTSOCKET hSocket, PRTNETADDR pAddr); + +/** + * Gets the address of the other party. + * + * @returns IPRT status code. + * @param hSocket Socket descriptor. + * @param pAddr Where to store the peer address on success. + */ +RTR3DECL(int) RTTcpGetPeerAddress(RTSOCKET hSocket, PRTNETADDR pAddr); + +/** + * Send data from a scatter/gather buffer to a socket. + * + * @returns iprt status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket Socket descriptor. + * @param pSgBuf Scatter/gather buffer to write data to socket. + */ +RTR3DECL(int) RTTcpSgWrite(RTSOCKET hSocket, PCRTSGBUF pSgBuf); + + +/** + * Send data from multiple buffers to a socket. + * + * This is convenience wrapper around the RTSocketSgWrite and RTSgBufInit calls + * for lazy coders. The "L" in the function name is short for "list" just like + * in the execl libc API. + * + * @returns IPRT status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket The socket handle. + * @param cSegs The number of data segments in the following + * ellipsis. + * @param ... Pairs of buffer pointers (void const *) and buffer + * sizes (size_t). Make 101% sure the pointer is + * really size_t. + */ +RTR3DECL(int) RTTcpSgWriteL(RTSOCKET hSocket, size_t cSegs, ...); + +/** + * Send data from multiple buffers to a socket. + * + * This is convenience wrapper around the RTSocketSgWrite and RTSgBufInit calls + * for lazy coders. The "L" in the function name is short for "list" just like + * in the execl libc API. + * + * @returns IPRT status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket The socket handle. + * @param cSegs The number of data segments in the following + * argument list. + * @param va Pairs of buffer pointers (void const *) and buffer + * sizes (size_t). Make 101% sure the pointer is + * really size_t. + */ +RTR3DECL(int) RTTcpSgWriteLV(RTSOCKET hSocket, size_t cSegs, va_list va); + +/** + * Receive data from a socket. + * + * This version doesn't block if there is no data on the socket. + * + * @returns IPRT status code. + * + * @param hSocket Socket descriptor. + * @param pvBuffer Where to put the data we read. + * @param cbBuffer Read buffer size. + * @param pcbRead Number of bytes read. + */ +RTR3DECL(int) RTTcpReadNB(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead); + +/** + * Send data to a socket. + * + * This version doesn't block if there is not enough room for the message. + * + * @returns IPRT status code. + * + * @param hSocket Socket descriptor. + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + * @param pcbWritten Number of bytes written. + */ +RTR3DECL(int) RTTcpWriteNB(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer, size_t *pcbWritten); + +/** + * Send data from a scatter/gather buffer to a socket. + * + * This version doesn't block if there is not enough room for the message. + * + * @returns iprt status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param hSocket Socket descriptor. + * @param pSgBuf Scatter/gather buffer to write data to socket. + * @param pcbWritten Number of bytes written. + */ +RTR3DECL(int) RTTcpSgWriteNB(RTSOCKET hSocket, PCRTSGBUF pSgBuf, size_t *pcbWritten); + + +/** + * Send data from multiple buffers to a socket. + * + * This version doesn't block if there is not enough room for the message. + * This is convenience wrapper around the RTSocketSgWrite and RTSgBufInit calls + * for lazy coders. The "L" in the function name is short for "list" just like + * in the execl libc API. + * + * @returns IPRT status code. + * + * @param hSocket The socket handle. + * @param cSegs The number of data segments in the following + * ellipsis. + * @param pcbWritten Number of bytes written. + * @param ... Pairs of buffer pointers (void const *) and buffer + * sizes (size_t). Make 101% sure the pointer is + * really size_t. + */ +RTR3DECL(int) RTTcpSgWriteLNB(RTSOCKET hSocket, size_t cSegs, size_t *pcbWritten, ...); + +/** + * Send data from multiple buffers to a socket. + * + * This version doesn't block if there is not enough room for the message. + * This is convenience wrapper around the RTSocketSgWrite and RTSgBufInit calls + * for lazy coders. The "L" in the function name is short for "list" just like + * in the execl libc API. + * + * @returns IPRT status code. + * + * @param hSocket The socket handle. + * @param cSegs The number of data segments in the following + * argument list. + * @param pcbWritten Number of bytes written. + * @param va Pairs of buffer pointers (void const *) and buffer + * sizes (size_t). Make 101% sure the pointer is + * really size_t. + */ +RTR3DECL(int) RTTcpSgWriteLVNB(RTSOCKET hSocket, size_t cSegs, size_t *pcbWritten, va_list va); + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_tcp_h */ + diff --git a/include/iprt/test.h b/include/iprt/test.h new file mode 100644 index 00000000..9cd5ddbe --- /dev/null +++ b/include/iprt/test.h @@ -0,0 +1,1485 @@ +/** @file + * IPRT - Testcase Framework. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_test_h +#define IPRT_INCLUDED_test_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/stdarg.h> +#include <iprt/assert.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_test RTTest - Testcase Framework. + * @ingroup grp_rt + * @{ + */ + +/** A test handle. */ +typedef R3PTRTYPE(struct RTTESTINT *) RTTEST; +/** A pointer to a test handle. */ +typedef RTTEST *PRTTEST; +/** A const pointer to a test handle. */ +typedef RTTEST const *PCRTTEST; + +/** A NIL Test handle. */ +#define NIL_RTTEST ((RTTEST)0) + +/** + * Test message importance level. + */ +typedef enum RTTESTLVL +{ + /** Invalid 0. */ + RTTESTLVL_INVALID = 0, + /** Message should always be printed. */ + RTTESTLVL_ALWAYS, + /** Failure message. */ + RTTESTLVL_FAILURE, + /** Sub-test banner. */ + RTTESTLVL_SUB_TEST, + /** Info message. */ + RTTESTLVL_INFO, + /** Debug message. */ + RTTESTLVL_DEBUG, + /** The last (invalid). */ + RTTESTLVL_END +} RTTESTLVL; + + +/** + * Creates a test instance. + * + * @returns IPRT status code. + * @param pszTest The test name. + * @param phTest Where to store the test instance handle. + */ +RTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest); + +/** + * Creates a test instance for a child process. + * + * This differs from RTTestCreate in that it disabled result reporting to file + * and pipe in order to avoid producing invalid XML. + * + * @returns IPRT status code. + * @param pszTest The test name. + * @param phTest Where to store the test instance handle. + */ +RTR3DECL(int) RTTestCreateChild(const char *pszTest, PRTTEST phTest); + +/** @name RTTEST_C_XXX - Flags for RTTestCreateEx. + * @{ */ +/** Whether to check the IPRT_TEST_XXX variables when constructing the + * instance. The following environment variables get checks: + * + * - IPRT_TEST_MAX_LEVEL: String value indicating which level. + * The env. var. is applied if the program specified the default level + * (by passing RTTESTLVL_INVALID). + * + * - IPRT_TEST_PIPE: The native pipe/fifo handle to write XML + * results to. + * The env. var. is applied if iNativeTestPipe is -1. + * + * - IPRT_TEST_FILE: Path to file/named-pipe/fifo/whatever to + * write XML results to. + * The env. var. is applied if the program specified a NULL path, it is + * not applied if the program hands us an empty string. + * + * - IPRT_TEST_OMIT_TOP_TEST: If present, this makes the XML output omit + * the top level test element. + * The env. var is applied when present. + * + */ +#define RTTEST_C_USE_ENV RT_BIT(0) +/** Whether to omit the top test in the XML. */ +#define RTTEST_C_XML_OMIT_TOP_TEST RT_BIT(1) +/** Whether to delay the top test XML element until testing commences. */ +#define RTTEST_C_XML_DELAY_TOP_TEST RT_BIT(2) +/** Whether to try install the test instance in the test TLS slot. Setting + * this flag is incompatible with using the RTTestIXxxx variant of the API. */ +#define RTTEST_C_NO_TLS RT_BIT(3) +/** Don't report to the pipe (IPRT_TEST_PIPE or other). */ +#define RTTEST_C_NO_XML_REPORTING_PIPE RT_BIT(4) +/** Don't report to the results file (IPRT_TEST_FILE or other). */ +#define RTTEST_C_NO_XML_REPORTING_FILE RT_BIT(4) +/** No XML reporting to pipes, file or anything. + * Child processes may want to use this so they don't garble the output of + * the main test process. */ +#define RTTEST_C_NO_XML_REPORTING (RTTEST_C_NO_XML_REPORTING_PIPE | RTTEST_C_NO_XML_REPORTING_FILE) +/** Mask containing the valid bits. */ +#define RTTEST_C_VALID_MASK UINT32_C(0x0000003f) +/** @} */ + + +/** + * Creates a test instance. + * + * @returns IPRT status code. + * @param pszTest The test name. + * @param fFlags Flags, see RTTEST_C_XXX. + * @param enmMaxLevel The max message level. Use RTTESTLVL_INVALID for + * the default output level or one from the + * environment. If specified, the environment variable + * will not be able to override it. + * @param iNativeTestPipe Native handle to a test pipe. -1 if not interested. + * @param pszXmlFile The XML output file name. If NULL the environment + * may be used. To selectively avoid that, pass an + * empty string. + * @param phTest Where to store the test instance handle. + * + * @note At the moment, we don't fail if @a pszXmlFile or @a iNativeTestPipe + * fails to open. This may change later. + */ +RTR3DECL(int) RTTestCreateEx(const char *pszTest, uint32_t fFlags, RTTESTLVL enmMaxLevel, + RTHCINTPTR iNativeTestPipe, const char *pszXmlFile, PRTTEST phTest); + +/** + * Initializes IPRT and creates a test instance. + * + * Typical usage is: + * @code + int main(int argc, char **argv) + { + RTTEST hTest; + int rc = RTTestInitAndCreate("tstSomething", &hTest); + if (rc) + return rc; + ... + } + @endcode + * + * @returns RTEXITCODE_SUCCESS on success. On failure an error message is + * printed and a suitable exit code is return. + * + * @param pszTest The test name. + * @param phTest Where to store the test instance handle. + */ +RTR3DECL(RTEXITCODE) RTTestInitAndCreate(const char *pszTest, PRTTEST phTest); + +/** + * Variant of RTTestInitAndCreate that includes IPRT init flags and argument + * vectors. + * + * @returns RTEXITCODE_SUCCESS on success. On failure an error message is + * printed and a suitable exit code is return. + * + * @param cArgs Pointer to the argument count. + * @param ppapszArgs Pointer to the argument vector pointer. + * @param fRtInit Flags, see RTR3INIT_XXX. + * @param pszTest The test name. + * @param phTest Where to store the test instance handle. + */ +RTR3DECL(RTEXITCODE) RTTestInitExAndCreate(int cArgs, char ***ppapszArgs, uint32_t fRtInit, const char *pszTest, PRTTEST phTest); + +/** + * Destroys a test instance previously created by RTTestCreate. + * + * @returns IPRT status code. + * @param hTest The test handle. NIL_RTTEST is ignored. + */ +RTR3DECL(int) RTTestDestroy(RTTEST hTest); + +/** + * Changes the default test instance for the calling thread. + * + * @returns IPRT status code. + * + * @param hNewDefaultTest The new default test. NIL_RTTEST is fine. + * @param phOldTest Where to store the old test handle. Optional. + */ +RTR3DECL(int) RTTestSetDefault(RTTEST hNewDefaultTest, PRTTEST phOldTest); + +/** + * Changes the test case name. + * + * @returns IRPT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszName The new test case name. Empty string is not accepted, + * nor are strings longer than 127 chars. Keep it short + * but descriptive. + */ +RTR3DECL(int) RTTestChangeName(RTTEST hTest, const char *pszName); + +/** + * Allocate a block of guarded memory. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param cb The amount of memory to allocate. + * @param cbAlign The alignment of the returned block. + * @param fHead Head or tail optimized guard. + * @param ppvUser Where to return the pointer to the block. + */ +RTR3DECL(int) RTTestGuardedAlloc(RTTEST hTest, size_t cb, uint32_t cbAlign, bool fHead, void **ppvUser); + +/** + * Allocates a block of guarded memory where the guarded is immediately after + * the user memory. + * + * @returns Pointer to the allocated memory. NULL on failure. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param cb The amount of memory to allocate. + */ +RTR3DECL(void *) RTTestGuardedAllocTail(RTTEST hTest, size_t cb); + +/** + * Allocates a block of guarded memory where the guarded is right in front of + * the user memory. + * + * @returns Pointer to the allocated memory. NULL on failure. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param cb The amount of memory to allocate. + */ +RTR3DECL(void *) RTTestGuardedAllocHead(RTTEST hTest, size_t cb); + +/** + * Frees a block of guarded memory. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pv The memory. NULL is ignored. + */ +RTR3DECL(int) RTTestGuardedFree(RTTEST hTest, void *pv); + +/** + * Test vprintf making sure the output starts on a new line. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param enmLevel Message importance level. + * @param pszFormat The message. + * @param va Arguments. + */ +RTR3DECL(int) RTTestPrintfNlV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Test printf making sure the output starts on a new line. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param enmLevel Message importance level. + * @param pszFormat The message. + * @param ... Arguments. + */ +RTR3DECL(int) RTTestPrintfNl(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Test vprintf, makes sure lines are prefixed and so forth. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param enmLevel Message importance level. + * @param pszFormat The message. + * @param va Arguments. + */ +RTR3DECL(int) RTTestPrintfV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Test printf, makes sure lines are prefixed and so forth. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param enmLevel Message importance level. + * @param pszFormat The message. + * @param ... Arguments. + */ +RTR3DECL(int) RTTestPrintf(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Prints the test banner. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + */ +RTR3DECL(int) RTTestBanner(RTTEST hTest); + +/** + * Summaries the test, destroys the test instance and return an exit code. + * + * @returns Test program exit code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + */ +RTR3DECL(RTEXITCODE) RTTestSummaryAndDestroy(RTTEST hTest); + +/** + * Skips the test, destroys the test instance and return an exit code. + * + * @returns Test program exit code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszReasonFmt Text explaining why, optional (NULL). + * @param va Arguments for the reason format string. + */ +RTR3DECL(RTEXITCODE) RTTestSkipAndDestroyV(RTTEST hTest, const char *pszReasonFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Skips the test, destroys the test instance and return an exit code. + * + * @returns Test program exit code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszReasonFmt Text explaining why, optional (NULL). + * @param ... Arguments for the reason format string. + */ +RTR3DECL(RTEXITCODE) RTTestSkipAndDestroy(RTTEST hTest, const char *pszReasonFmt, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Starts a sub-test. + * + * This will perform an implicit RTTestSubDone() call if that has not been done + * since the last RTTestSub call. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszSubTest The sub-test name. + */ +RTR3DECL(int) RTTestSub(RTTEST hTest, const char *pszSubTest); + +/** + * Format string version of RTTestSub. + * + * See RTTestSub for details. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszSubTestFmt The sub-test name format string. + * @param ... Arguments. + */ +RTR3DECL(int) RTTestSubF(RTTEST hTest, const char *pszSubTestFmt, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Format string version of RTTestSub. + * + * See RTTestSub for details. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszSubTestFmt The sub-test name format string. + * @param va Arguments. + */ +RTR3DECL(int) RTTestSubV(RTTEST hTest, const char *pszSubTestFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Completes a sub-test. + * + * @returns Number of chars printed, negative numbers are IPRT error codes. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + */ +RTR3DECL(int) RTTestSubDone(RTTEST hTest); + +/** + * Prints an extended PASSED message, optional. + * + * This does not conclude the sub-test, it could be used to report the passing + * of a sub-sub-to-the-power-of-N-test. + * + * @returns Number of chars printed, negative numbers are IPRT error codes. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message. No trailing newline. + * @param va The arguments. + */ +RTR3DECL(int) RTTestPassedV(RTTEST hTest, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Prints an extended PASSED message, optional. + * + * This does not conclude the sub-test, it could be used to report the passing + * of a sub-sub-to-the-power-of-N-test. + * + * @returns Number of chars printed, negative numbers are IPRT error codes. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message. No trailing newline. + * @param ... The arguments. + */ +RTR3DECL(int) RTTestPassed(RTTEST hTest, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Marks the current test as 'SKIPPED' and optionally displays a message + * explaining why. + * + * @returns Number of chars printed, negative numbers are IPRT error codes. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message. No trailing newline. Can be NULL or empty. + * @param ... The arguments. + */ +RTR3DECL(int) RTTestSkipped(RTTEST hTest, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(2, 3); + +/** + * Marks the current test as 'SKIPPED' and optionally displays a message + * explaining why. + * + * @returns Number of chars printed, negative numbers are IPRT error codes. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message. No trailing newline. Can be NULL or empty. + * @param va The arguments. + */ +RTR3DECL(int) RTTestSkippedV(RTTEST hTest, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(2, 0); + + +/** + * Value units. + * + * @remarks This is an interface where we have to be binary compatible with both + * older versions of this header and other components using the same + * contant values. + * @remarks When adding a new item: + * - Always add at the end of the list. + * - Add it to rtTestUnitName in r3/test.cpp. + * - Add it as VMMDEV_TESTING_UNIT_ in include/VBox/VMMDevTesting.h. + * - Add it to g_aszBs2TestUnitNames in + * ValidationKit/bootsectors/bootsector2-common-routines.mac. + * - Add it to g_aszBs3TestUnitNames in bs3kit/bs3-cmn-TestData.c. + * - Add it to ValidationKit/common/constants/valueunit.py both as + * a constant (strip RTTESTUNIT_) and as a name (same as what + * rtTestUnitName returns) for mapping. Testmanager must be + * updated. + * - Add it to Value.kdBestByUnit in ValidationKit/analysis/reader.py. + */ +typedef enum RTTESTUNIT +{ + /** The customary invalid zero value. */ + RTTESTUNIT_INVALID = 0, + + RTTESTUNIT_PCT, /**< Percentage (10^-2). */ + RTTESTUNIT_BYTES, /**< Bytes. */ + RTTESTUNIT_BYTES_PER_SEC, /**< Bytes per second. */ + RTTESTUNIT_KILOBYTES, /**< Kilobytes. */ + RTTESTUNIT_KILOBYTES_PER_SEC, /**< Kilobytes per second. */ + RTTESTUNIT_MEGABYTES, /**< Megabytes. */ + RTTESTUNIT_MEGABYTES_PER_SEC, /**< Megabytes per second. */ + RTTESTUNIT_PACKETS, /**< Packets. */ + RTTESTUNIT_PACKETS_PER_SEC, /**< Packets per second. */ + RTTESTUNIT_FRAMES, /**< Frames. */ + RTTESTUNIT_FRAMES_PER_SEC, /**< Frames per second. */ + RTTESTUNIT_OCCURRENCES, /**< Occurrences. */ + RTTESTUNIT_OCCURRENCES_PER_SEC, /**< Occurrences per second. */ + RTTESTUNIT_CALLS, /**< Calls. */ + RTTESTUNIT_CALLS_PER_SEC, /**< Calls per second. */ + RTTESTUNIT_ROUND_TRIP, /**< Round trips. */ + RTTESTUNIT_SECS, /**< Seconds. */ + RTTESTUNIT_MS, /**< Milliseconds. */ + RTTESTUNIT_NS, /**< Nanoseconds. */ + RTTESTUNIT_NS_PER_CALL, /**< Nanoseconds per call. */ + RTTESTUNIT_NS_PER_FRAME, /**< Nanoseconds per frame. */ + RTTESTUNIT_NS_PER_OCCURRENCE, /**< Nanoseconds per occurrence. */ + RTTESTUNIT_NS_PER_PACKET, /**< Nanoseconds per frame. */ + RTTESTUNIT_NS_PER_ROUND_TRIP, /**< Nanoseconds per round trip. */ + RTTESTUNIT_INSTRS, /**< Instructions. */ + RTTESTUNIT_INSTRS_PER_SEC, /**< Instructions per second. */ + RTTESTUNIT_NONE, /**< No unit. */ + RTTESTUNIT_PP1K, /**< Parts per thousand (10^-3). */ + RTTESTUNIT_PP10K, /**< Parts per ten thousand (10^-4). */ + RTTESTUNIT_PPM, /**< Parts per million (10^-6). */ + RTTESTUNIT_PPB, /**< Parts per billion (10^-9). */ + RTTESTUNIT_TICKS, /**< CPU ticks. */ + RTTESTUNIT_TICKS_PER_CALL, /**< CPU ticks per call. */ + RTTESTUNIT_TICKS_PER_OCCURENCE, /**< CPU ticks per occurence. */ + RTTESTUNIT_PAGES, /**< Page count. */ + RTTESTUNIT_PAGES_PER_SEC, /**< Pages per second. */ + RTTESTUNIT_TICKS_PER_PAGE, /**< CPU ticks per page. */ + RTTESTUNIT_NS_PER_PAGE, /**< Nanoseconds per page. */ + RTTESTUNIT_PS, /**< Picoseconds. */ + RTTESTUNIT_PS_PER_CALL, /**< Picoseconds per call. */ + RTTESTUNIT_PS_PER_FRAME, /**< Picoseconds per frame. */ + RTTESTUNIT_PS_PER_OCCURRENCE, /**< Picoseconds per occurrence. */ + RTTESTUNIT_PS_PER_PACKET, /**< Picoseconds per frame. */ + RTTESTUNIT_PS_PER_ROUND_TRIP, /**< Picoseconds per round trip. */ + RTTESTUNIT_PS_PER_PAGE, /**< Picoseconds per page. */ + + /** The end of valid units. */ + RTTESTUNIT_END +} RTTESTUNIT; +AssertCompile(RTTESTUNIT_INSTRS == 0x19); +AssertCompile(RTTESTUNIT_NONE == 0x1b); +AssertCompile(RTTESTUNIT_NS_PER_PAGE == 0x26); +AssertCompile(RTTESTUNIT_PS_PER_PAGE == 0x2d); + +/** + * Report a named test result value. + * + * This is typically used for benchmarking but can be used for other purposes + * like reporting limits of some implementation. The value gets associated with + * the current sub test, the name must be unique within the sub test. + * + * @returns IPRT status code. + * + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszName The value name. + * @param u64Value The value. + * @param enmUnit The value unit. + */ +RTR3DECL(int) RTTestValue(RTTEST hTest, const char *pszName, uint64_t u64Value, RTTESTUNIT enmUnit); + +/** + * Same as RTTestValue, except that the name is now a format string. + * + * @returns IPRT status code. + * + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param u64Value The value. + * @param enmUnit The value unit. + * @param pszNameFmt The value name format string. + * @param ... String arguments. + */ +RTR3DECL(int) RTTestValueF(RTTEST hTest, uint64_t u64Value, RTTESTUNIT enmUnit, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(4, 5); + +/** + * Same as RTTestValue, except that the name is now a format string. + * + * @returns IPRT status code. + * + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param u64Value The value. + * @param enmUnit The value unit. + * @param pszNameFmt The value name format string. + * @param va String arguments. + */ +RTR3DECL(int) RTTestValueV(RTTEST hTest, uint64_t u64Value, RTTESTUNIT enmUnit, + const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(4, 0); + +/** + * Increments the error counter. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + */ +RTR3DECL(int) RTTestErrorInc(RTTEST hTest); + +/** + * Get the current error count. + * + * @returns The error counter, UINT32_MAX if no valid test handle. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + */ +RTR3DECL(uint32_t) RTTestErrorCount(RTTEST hTest); + +/** + * Get the error count of the current sub test. + * + * @returns The error counter, UINT32_MAX if no valid test handle. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + */ +RTR3DECL(uint32_t) RTTestSubErrorCount(RTTEST hTest); + +/** + * Increments the error counter and prints a failure message. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message. No trailing newline. + * @param va The arguments. + */ +RTR3DECL(int) RTTestFailedV(RTTEST hTest, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Increments the error counter and prints a failure message. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message. No trailing newline. + * @param ... The arguments. + */ +RTR3DECL(int) RTTestFailed(RTTEST hTest, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Same as RTTestPrintfV with RTTESTLVL_FAILURE. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message. + * @param va Arguments. + */ +RTR3DECL(int) RTTestFailureDetailsV(RTTEST hTest, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Same as RTTestPrintf with RTTESTLVL_FAILURE. + * + * @returns Number of chars printed. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message. + * @param ... Arguments. + */ +RTR3DECL(int) RTTestFailureDetails(RTTEST hTest, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Sets error context info to be printed with the first failure. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message, no trailing newline. NULL to clear the + * context message. + * @param va The arguments. + */ +RTR3DECL(int) RTTestErrContextV(RTTEST hTest, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Sets error context info to be printed with the first failure. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @param pszFormat The message, no trailing newline. NULL to clear the + * context message. + * @param ... The arguments. + */ +RTR3DECL(int) RTTestErrContext(RTTEST hTest, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Disables and shuts up assertions. + * + * Max 8 nestings. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + * @sa RTAssertSetMayPanic, RTAssertSetQuiet. + */ +RTR3DECL(int) RTTestDisableAssertions(RTTEST hTest); + +/** + * Restores the previous call to RTTestDisableAssertions. + * + * @returns IPRT status code. + * @param hTest The test handle. If NIL_RTTEST we'll use the one + * associated with the calling thread. + */ +RTR3DECL(int) RTTestRestoreAssertions(RTTEST hTest); + + +/** @def RTTEST_CHECK + * Check whether a boolean expression holds true. + * + * If the expression is false, call RTTestFailed giving the line number and expression. + * + * @param hTest The test handle. + * @param expr The expression to evaluate. + */ +#define RTTEST_CHECK(hTest, expr) \ + do { if (!(expr)) { \ + RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ + } \ + } while (0) +/** @def RTTEST_CHECK_RET + * Check whether a boolean expression holds true, returns on false. + * + * If the expression is false, call RTTestFailed giving the line number and + * expression, then return @a rcRet. + * + * @param hTest The test handle. + * @param expr The expression to evaluate. + * @param rcRet What to return on failure. + */ +#define RTTEST_CHECK_RET(hTest, expr, rcRet) \ + do { if (!(expr)) { \ + RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ + return (rcRet); \ + } \ + } while (0) +/** @def RTTEST_CHECK_RETV + * Check whether a boolean expression holds true, returns void on false. + * + * If the expression is false, call RTTestFailed giving the line number and + * expression, then return void. + * + * @param hTest The test handle. + * @param expr The expression to evaluate. + */ +#define RTTEST_CHECK_RETV(hTest, expr) \ + do { if (!(expr)) { \ + RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ + return; \ + } \ + } while (0) +/** @def RTTEST_CHECK_BREAK + * Check whether a boolean expression holds true. + * + * If the expression is false, call RTTestFailed giving the line number and + * expression, then break. + * + * @param hTest The test handle. + * @param expr The expression to evaluate. + */ +#define RTTEST_CHECK_BREAK(hTest, expr) \ + if (!(expr)) { \ + RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ + break; \ + } else do {} while (0) + + +/** @def RTTEST_CHECK_MSG + * Check whether a boolean expression holds true. + * + * If the expression is false, call RTTestFailed giving the line number and expression. + * + * @param hTest The test handle. + * @param expr The expression to evaluate. + * @param DetailsArgs Argument list for RTTestFailureDetails, including + * parenthesis. + */ +#define RTTEST_CHECK_MSG(hTest, expr, DetailsArgs) \ + do { if (!(expr)) { \ + RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ + RTTestFailureDetails DetailsArgs; \ + } \ + } while (0) +/** @def RTTEST_CHECK_MSG_RET + * Check whether a boolean expression holds true, returns on false. + * + * If the expression is false, call RTTestFailed giving the line number and expression. + * + * @param hTest The test handle. + * @param expr The expression to evaluate. + * @param DetailsArgs Argument list for RTTestFailureDetails, including + * parenthesis. + * @param rcRet What to return on failure. + */ +#define RTTEST_CHECK_MSG_RET(hTest, expr, DetailsArgs, rcRet) \ + do { if (!(expr)) { \ + RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ + RTTestFailureDetails DetailsArgs; \ + return (rcRet); \ + } \ + } while (0) +/** @def RTTEST_CHECK_MSG_RETV + * Check whether a boolean expression holds true, returns void on false. + * + * If the expression is false, call RTTestFailed giving the line number and expression. + * + * @param hTest The test handle. + * @param expr The expression to evaluate. + * @param DetailsArgs Argument list for RTTestFailureDetails, including + * parenthesis. + */ +#define RTTEST_CHECK_MSG_RETV(hTest, expr, DetailsArgs) \ + do { if (!(expr)) { \ + RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ + RTTestFailureDetails DetailsArgs; \ + return; \ + } \ + } while (0) + + +/** @def RTTEST_CHECK_RC + * Check whether an expression returns a specific IPRT style status code. + * + * If a different status code is return, call RTTestFailed giving the line + * number, expression, actual and expected status codes. + * + * @param hTest The test handle. + * @param rcExpr The expression resulting in an IPRT status code. + * @param rcExpect The expected return code. This may be referenced + * more than once by the macro. + */ +#define RTTEST_CHECK_RC(hTest, rcExpr, rcExpect) \ + do { \ + int rcCheck = (rcExpr); \ + if (rcCheck != (rcExpect)) { \ + RTTestFailed((hTest), "line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ + } \ + } while (0) +/** @def RTTEST_CHECK_RC_RET + * Check whether an expression returns a specific IPRT style status code. + * + * If a different status code is return, call RTTestFailed giving the line + * number, expression, actual and expected status codes, then return. + * + * @param hTest The test handle. + * @param rcExpr The expression resulting in an IPRT status code. + * This will be assigned to a local rcCheck variable + * that can be used as return value. + * @param rcExpect The expected return code. This may be referenced + * more than once by the macro. + * @param rcRet The return code. + */ +#define RTTEST_CHECK_RC_RET(hTest, rcExpr, rcExpect, rcRet) \ + do { \ + int rcCheck = (rcExpr); \ + if (rcCheck != (rcExpect)) { \ + RTTestFailed((hTest), "line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ + return (rcRet); \ + } \ + } while (0) +/** @def RTTEST_CHECK_RC_RETV + * Check whether an expression returns a specific IPRT style status code. + * + * If a different status code is return, call RTTestFailed giving the line + * number, expression, actual and expected status codes, then return. + * + * @param hTest The test handle. + * @param rcExpr The expression resulting in an IPRT status code. + * @param rcExpect The expected return code. This may be referenced + * more than once by the macro. + */ +#define RTTEST_CHECK_RC_RETV(hTest, rcExpr, rcExpect) \ + do { \ + int rcCheck = (rcExpr); \ + if (rcCheck != (rcExpect)) { \ + RTTestFailed((hTest), "line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ + return; \ + } \ + } while (0) +/** @def RTTEST_CHECK_RC_BREAK + * Check whether an expression returns a specific IPRT style status code. + * + * If a different status code is return, call RTTestFailed giving the line + * number, expression, actual and expected status codes, then break. + * + * @param hTest The test handle. + * @param rcExpr The expression resulting in an IPRT status code. + * @param rcExpect The expected return code. This may be referenced + * more than once by the macro. + */ +#define RTTEST_CHECK_RC_BREAK(hTest, rcExpr, rcExpect) \ + if (1) { \ + int rcCheck = (rcExpr); \ + if (rcCheck != (rcExpect)) { \ + RTTestFailed((hTest), "line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ + break; \ + } \ + } else do {} while (0) + + +/** @def RTTEST_CHECK_RC_OK + * Check whether a IPRT style status code indicates success. + * + * If the status indicates failure, call RTTestFailed giving the line number, + * expression and status code. + * + * @param hTest The test handle. + * @param rcExpr The expression resulting in an IPRT status code. + */ +#define RTTEST_CHECK_RC_OK(hTest, rcExpr) \ + do { \ + int rcCheck = (rcExpr); \ + if (RT_FAILURE(rcCheck)) { \ + RTTestFailed((hTest), "line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ + } \ + } while (0) +/** @def RTTEST_CHECK_RC_OK_RET + * Check whether a IPRT style status code indicates success. + * + * If the status indicates failure, call RTTestFailed giving the line number, + * expression and status code, then return with the specified value. + * + * @param hTest The test handle. + * @param rcExpr The expression resulting in an IPRT status code. + * This will be assigned to a local rcCheck variable + * that can be used as return value. + * @param rcRet The return code. + */ +#define RTTEST_CHECK_RC_OK_RET(hTest, rcExpr, rcRet) \ + do { \ + int rcCheck = (rcExpr); \ + if (RT_FAILURE(rcCheck)) { \ + RTTestFailed((hTest), "line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ + return (rcRet); \ + } \ + } while (0) +/** @def RTTEST_CHECK_RC_OK_RETV + * Check whether a IPRT style status code indicates success. + * + * If the status indicates failure, call RTTestFailed giving the line number, + * expression and status code, then return. + * + * @param hTest The test handle. + * @param rcExpr The expression resulting in an IPRT status code. + */ +#define RTTEST_CHECK_RC_OK_RETV(hTest, rcExpr) \ + do { \ + int rcCheck = (rcExpr); \ + if (RT_FAILURE(rcCheck)) { \ + RTTestFailed((hTest), "line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ + return; \ + } \ + } while (0) + + + + +/** @name Implicit Test Handle API Variation + * The test handle is retrieved from the test TLS entry of the calling thread. + * @{ + */ + +/** + * Test vprintf, makes sure lines are prefixed and so forth. + * + * @returns Number of chars printed. + * @param enmLevel Message importance level. + * @param pszFormat The message. + * @param va Arguments. + */ +RTR3DECL(int) RTTestIPrintfV(RTTESTLVL enmLevel, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Test printf, makes sure lines are prefixed and so forth. + * + * @returns Number of chars printed. + * @param enmLevel Message importance level. + * @param pszFormat The message. + * @param ... Arguments. + */ +RTR3DECL(int) RTTestIPrintf(RTTESTLVL enmLevel, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Starts a sub-test. + * + * This will perform an implicit RTTestSubDone() call if that has not been done + * since the last RTTestSub call. + * + * @returns Number of chars printed. + * @param pszSubTest The sub-test name. + */ +RTR3DECL(int) RTTestISub(const char *pszSubTest); + +/** + * Format string version of RTTestSub. + * + * See RTTestSub for details. + * + * @returns Number of chars printed. + * @param pszSubTestFmt The sub-test name format string. + * @param ... Arguments. + */ +RTR3DECL(int) RTTestISubF(const char *pszSubTestFmt, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Format string version of RTTestSub. + * + * See RTTestSub for details. + * + * @returns Number of chars printed. + * @param pszSubTestFmt The sub-test name format string. + * @param va Arguments. + */ +RTR3DECL(int) RTTestISubV(const char *pszSubTestFmt, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Completes a sub-test. + * + * @returns Number of chars printed. + */ +RTR3DECL(int) RTTestISubDone(void); + +/** + * Prints an extended PASSED message, optional. + * + * This does not conclude the sub-test, it could be used to report the passing + * of a sub-sub-to-the-power-of-N-test. + * + * @returns IPRT status code. + * @param pszFormat The message. No trailing newline. + * @param va The arguments. + */ +RTR3DECL(int) RTTestIPassedV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Prints an extended PASSED message, optional. + * + * This does not conclude the sub-test, it could be used to report the passing + * of a sub-sub-to-the-power-of-N-test. + * + * @returns IPRT status code. + * @param pszFormat The message. No trailing newline. + * @param ... The arguments. + */ +RTR3DECL(int) RTTestIPassed(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Report a named test result value. + * + * This is typically used for benchmarking but can be used for other purposes + * like reporting limits of some implementation. The value gets associated with + * the current sub test, the name must be unique within the sub test. + * + * @returns IPRT status code. + * + * @param pszName The value name. + * @param u64Value The value. + * @param enmUnit The value unit. + */ +RTR3DECL(int) RTTestIValue(const char *pszName, uint64_t u64Value, RTTESTUNIT enmUnit); + +/** + * Same as RTTestValue, except that the name is now a format string. + * + * @returns IPRT status code. + * + * @param u64Value The value. + * @param enmUnit The value unit. + * @param pszNameFmt The value name format string. + * @param ... String arguments. + */ +RTR3DECL(int) RTTestIValueF(uint64_t u64Value, RTTESTUNIT enmUnit, const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * Same as RTTestValue, except that the name is now a format string. + * + * @returns IPRT status code. + * + * @param u64Value The value. + * @param enmUnit The value unit. + * @param pszNameFmt The value name format string. + * @param va String arguments. + */ +RTR3DECL(int) RTTestIValueV(uint64_t u64Value, RTTESTUNIT enmUnit, const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * Increments the error counter. + * + * @returns IPRT status code. + */ +RTR3DECL(int) RTTestIErrorInc(void); + +/** + * Get the current error count. + * + * @returns The error counter, UINT32_MAX if no valid test handle. + */ +RTR3DECL(uint32_t) RTTestIErrorCount(void); + +/** + * Increments the error counter and prints a failure message. + * + * @returns IPRT status code. + * @param pszFormat The message. No trailing newline. + * @param va The arguments. + */ +RTR3DECL(int) RTTestIFailedV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Increments the error counter and prints a failure message. + * + * @returns IPRT status code. + * @param pszFormat The message. No trailing newline. + * @param ... The arguments. + */ +RTR3DECL(int) RTTestIFailed(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Increments the error counter, prints a failure message and returns the + * specified status code. + * + * This is mainly a convenience method for saving vertical space in the source + * code. + * + * @returns @a rcRet + * @param rcRet The IPRT status code to return. + * @param pszFormat The message. No trailing newline. + * @param va The arguments. + */ +RTR3DECL(int) RTTestIFailedRcV(int rcRet, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); + +/** + * Increments the error counter, prints a failure message and returns the + * specified status code. + * + * This is mainly a convenience method for saving vertical space in the source + * code. + * + * @returns @a rcRet + * @param rcRet The IPRT status code to return. + * @param pszFormat The message. No trailing newline. + * @param ... The arguments. + */ +RTR3DECL(int) RTTestIFailedRc(int rcRet, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); + +/** + * Same as RTTestIPrintfV with RTTESTLVL_FAILURE. + * + * @returns Number of chars printed. + * @param pszFormat The message. + * @param va Arguments. + */ +RTR3DECL(int) RTTestIFailureDetailsV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Same as RTTestIPrintf with RTTESTLVL_FAILURE. + * + * @returns Number of chars printed. + * @param pszFormat The message. + * @param ... Arguments. + */ +RTR3DECL(int) RTTestIFailureDetails(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Sets error context info to be printed with the first failure. + * + * @returns IPRT status code. + * @param pszFormat The message, no trailing newline. NULL to clear the + * context message. + * @param va The arguments. + */ +RTR3DECL(int) RTTestIErrContextV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Sets error context info to be printed with the first failure. + * + * @returns IPRT status code. + * @param pszFormat The message, no trailing newline. NULL to clear the + * context message. + * @param ... The arguments. + */ +RTR3DECL(int) RTTestIErrContext(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + +/** + * Disables and shuts up assertions. + * + * Max 8 nestings. + * + * @returns IPRT status code. + * @sa RTAssertSetMayPanic, RTAssertSetQuiet. + */ +RTR3DECL(int) RTTestIDisableAssertions(void); + +/** + * Restores the previous call to RTTestDisableAssertions. + * + * @returns IPRT status code. + */ +RTR3DECL(int) RTTestIRestoreAssertions(void); + + +/** @def RTTESTI_CHECK + * Check whether a boolean expression holds true. + * + * If the expression is false, call RTTestIFailed giving the line number and + * expression. + * + * @param expr The expression to evaluate. + */ +#define RTTESTI_CHECK(expr) \ + do { if (!(expr)) { \ + RTTestIFailed("line %u: %s", __LINE__, #expr); \ + } \ + } while (0) +/** @def RTTESTI_CHECK_RET + * Check whether a boolean expression holds true, returns on false. + * + * If the expression is false, call RTTestIFailed giving the line number and + * expression, then return @a rcRet. + * + * @param expr The expression to evaluate. + * @param rcRet What to return on failure. + */ +#define RTTESTI_CHECK_RET(expr, rcRet) \ + do { if (!(expr)) { \ + RTTestIFailed("line %u: %s", __LINE__, #expr); \ + return (rcRet); \ + } \ + } while (0) +/** @def RTTESTI_CHECK_RETV + * Check whether a boolean expression holds true, returns void on false. + * + * If the expression is false, call RTTestIFailed giving the line number and + * expression, then return void. + * + * @param expr The expression to evaluate. + */ +#define RTTESTI_CHECK_RETV(expr) \ + do { if (!(expr)) { \ + RTTestIFailed("line %u: %s", __LINE__, #expr); \ + return; \ + } \ + } while (0) +/** @def RTTESTI_CHECK_BREAK + * Check whether a boolean expression holds true, returns void on false. + * + * If the expression is false, call RTTestIFailed giving the line number and + * expression, then break. + * + * @param expr The expression to evaluate. + */ +#define RTTESTI_CHECK_BREAK(expr) \ + if (!(expr)) { \ + RTTestIFailed("line %u: %s", __LINE__, #expr); \ + break; \ + } else do {} while (0) + + +/** @def RTTESTI_CHECK_MSG + * Check whether a boolean expression holds true. + * + * If the expression is false, call RTTestIFailed giving the line number and + * expression. + * + * @param expr The expression to evaluate. + * @param DetailsArgs Argument list for RTTestIFailureDetails, including + * parenthesis. + */ +#define RTTESTI_CHECK_MSG(expr, DetailsArgs) \ + do { if (!(expr)) { \ + RTTestIFailed("line %u: %s", __LINE__, #expr); \ + RTTestIFailureDetails DetailsArgs; \ + } \ + } while (0) +/** @def RTTESTI_CHECK_MSG_BREAK + * Check whether a boolean expression holds true, returns on false. + * + * If the expression is false, call RTTestIFailed giving the line number and + * expression. + * + * @param expr The expression to evaluate. + * @param DetailsArgs Argument list for RTTestIFailureDetails, including + * parenthesis. + */ +#define RTTESTI_CHECK_MSG_BREAK(expr, DetailsArgs) \ + if (!(expr)) { \ + RTTestIFailed("line %u: %s", __LINE__, #expr); \ + RTTestIFailureDetails DetailsArgs; \ + break; \ + } else do {} while (0) +/** @def RTTESTI_CHECK_MSG_RET + * Check whether a boolean expression holds true, returns on false. + * + * If the expression is false, call RTTestIFailed giving the line number and + * expression. + * + * @param expr The expression to evaluate. + * @param DetailsArgs Argument list for RTTestIFailureDetails, including + * parenthesis. + * @param rcRet What to return on failure. + */ +#define RTTESTI_CHECK_MSG_RET(expr, DetailsArgs, rcRet) \ + do { if (!(expr)) { \ + RTTestIFailed("line %u: %s", __LINE__, #expr); \ + RTTestIFailureDetails DetailsArgs; \ + return (rcRet); \ + } \ + } while (0) +/** @def RTTESTI_CHECK_MSG_RETV + * Check whether a boolean expression holds true, returns void on false. + * + * If the expression is false, call RTTestIFailed giving the line number and + * expression. + * + * @param expr The expression to evaluate. + * @param DetailsArgs Argument list for RTTestIFailureDetails, including + * parenthesis. + */ +#define RTTESTI_CHECK_MSG_RETV(expr, DetailsArgs) \ + do { if (!(expr)) { \ + RTTestIFailed("line %u: %s", __LINE__, #expr); \ + RTTestIFailureDetails DetailsArgs; \ + return; \ + } \ + } while (0) + +/** @def RTTESTI_CHECK_RC + * Check whether an expression returns a specific IPRT style status code. + * + * If a different status code is return, call RTTestIFailed giving the line + * number, expression, actual and expected status codes. + * + * @param rcExpr The expression resulting in an IPRT status code. + * @param rcExpect The expected return code. This may be referenced + * more than once by the macro. + */ +#define RTTESTI_CHECK_RC(rcExpr, rcExpect) \ + do { \ + int rcCheck = (rcExpr); \ + if (rcCheck != (rcExpect)) { \ + RTTestIFailed("line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ + } \ + } while (0) +/** @def RTTESTI_CHECK_RC_RET + * Check whether an expression returns a specific IPRT style status code. + * + * If a different status code is return, call RTTestIFailed giving the line + * number, expression, actual and expected status codes, then return. + * + * @param rcExpr The expression resulting in an IPRT status code. + * This will be assigned to a local rcCheck variable + * that can be used as return value. + * @param rcExpect The expected return code. This may be referenced + * more than once by the macro. + * @param rcRet The return code. + */ +#define RTTESTI_CHECK_RC_RET(rcExpr, rcExpect, rcRet) \ + do { \ + int rcCheck = (rcExpr); \ + if (rcCheck != (rcExpect)) { \ + RTTestIFailed("line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ + return (rcRet); \ + } \ + } while (0) +/** @def RTTESTI_CHECK_RC_RETV + * Check whether an expression returns a specific IPRT style status code. + * + * If a different status code is return, call RTTestIFailed giving the line + * number, expression, actual and expected status codes, then return. + * + * @param rcExpr The expression resulting in an IPRT status code. + * @param rcExpect The expected return code. This may be referenced + * more than once by the macro. + */ +#define RTTESTI_CHECK_RC_RETV(rcExpr, rcExpect) \ + do { \ + int rcCheck = (rcExpr); \ + if (rcCheck != (rcExpect)) { \ + RTTestIFailed("line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ + return; \ + } \ + } while (0) +/** @def RTTESTI_CHECK_RC_BREAK + * Check whether an expression returns a specific IPRT style status code. + * + * If a different status code is return, call RTTestIFailed giving the line + * number, expression, actual and expected status codes, then break. + * + * @param rcExpr The expression resulting in an IPRT status code. + * @param rcExpect The expected return code. This may be referenced + * more than once by the macro. + */ +#define RTTESTI_CHECK_RC_BREAK(rcExpr, rcExpect) \ + if (1) { \ + int rcCheck = (rcExpr); \ + if (rcCheck != (rcExpect)) { \ + RTTestIFailed("line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ + break; \ + } \ + } else do {} while (0) +/** @def RTTESTI_CHECK_RC_OK + * Check whether a IPRT style status code indicates success. + * + * If the status indicates failure, call RTTestIFailed giving the line number, + * expression and status code. + * + * @param rcExpr The expression resulting in an IPRT status code. + */ +#define RTTESTI_CHECK_RC_OK(rcExpr) \ + do { \ + int rcCheck = (rcExpr); \ + if (RT_FAILURE(rcCheck)) { \ + RTTestIFailed("line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ + } \ + } while (0) +/** @def RTTESTI_CHECK_RC_OK_BREAK + * Check whether a IPRT style status code indicates success. + * + * If a different status code is return, call RTTestIFailed giving the line + * number, expression, actual and expected status codes, then break. + * + * @param rcExpr The expression resulting in an IPRT status code. + */ +#define RTTESTI_CHECK_RC_OK_BREAK(rcExpr) \ + do { \ + int rcCheck = (rcExpr); \ + if (RT_FAILURE(rcCheck)) { \ + RTTestIFailed("line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ + break; \ + } \ + } while (0) +/** @def RTTESTI_CHECK_RC_OK_RET + * Check whether a IPRT style status code indicates success. + * + * If the status indicates failure, call RTTestIFailed giving the line number, + * expression and status code, then return with the specified value. + * + * @param rcExpr The expression resulting in an IPRT status code. + * This will be assigned to a local rcCheck variable + * that can be used as return value. + * @param rcRet The return code. + */ +#define RTTESTI_CHECK_RC_OK_RET(rcExpr, rcRet) \ + do { \ + int rcCheck = (rcExpr); \ + if (RT_FAILURE(rcCheck)) { \ + RTTestIFailed("line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ + return (rcRet); \ + } \ + } while (0) +/** @def RTTESTI_CHECK_RC_OK_RETV + * Check whether a IPRT style status code indicates success. + * + * If the status indicates failure, call RTTestIFailed giving the line number, + * expression and status code, then return. + * + * @param rcExpr The expression resulting in an IPRT status code. + */ +#define RTTESTI_CHECK_RC_OK_RETV(rcExpr) \ + do { \ + int rcCheck = (rcExpr); \ + if (RT_FAILURE(rcCheck)) { \ + RTTestIFailed("line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ + return; \ + } \ + } while (0) + +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_test_h */ + diff --git a/include/iprt/thread.h b/include/iprt/thread.h new file mode 100644 index 00000000..551c8bcc --- /dev/null +++ b/include/iprt/thread.h @@ -0,0 +1,1023 @@ +/** @file + * IPRT - Threads. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_thread_h +#define IPRT_INCLUDED_thread_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/stdarg.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_thread RTThread - Thread Management + * @ingroup grp_rt + * @{ + */ + +/** + * The thread state. + */ +typedef enum RTTHREADSTATE +{ + /** The usual invalid 0 value. */ + RTTHREADSTATE_INVALID = 0, + /** The thread is being initialized. */ + RTTHREADSTATE_INITIALIZING, + /** The thread has terminated */ + RTTHREADSTATE_TERMINATED, + /** Probably running. */ + RTTHREADSTATE_RUNNING, + + /** Waiting on a critical section. */ + RTTHREADSTATE_CRITSECT, + /** Waiting on a event semaphore. */ + RTTHREADSTATE_EVENT, + /** Waiting on a event multiple wakeup semaphore. */ + RTTHREADSTATE_EVENT_MULTI, + /** Waiting on a fast mutex. */ + RTTHREADSTATE_FAST_MUTEX, + /** Waiting on a mutex. */ + RTTHREADSTATE_MUTEX, + /** Waiting on a read write semaphore, read (shared) access. */ + RTTHREADSTATE_RW_READ, + /** Waiting on a read write semaphore, write (exclusive) access. */ + RTTHREADSTATE_RW_WRITE, + /** The thread is sleeping. */ + RTTHREADSTATE_SLEEP, + /** Waiting on a spin mutex. */ + RTTHREADSTATE_SPIN_MUTEX, + /** End of the thread states. */ + RTTHREADSTATE_END, + + /** The usual 32-bit size hack. */ + RTTHREADSTATE_32BIT_HACK = 0x7fffffff +} RTTHREADSTATE; + +/** Checks if a thread state indicates that the thread is sleeping. */ +#define RTTHREAD_IS_SLEEPING(enmState) ((enmState) >= RTTHREADSTATE_CRITSECT) + +/** + * Thread types. + * Besides identifying the purpose of the thread, the thread type is + * used to select the scheduling properties. + * + * The types in are placed in a rough order of ascending priority. + */ +typedef enum RTTHREADTYPE +{ + /** Invalid type. */ + RTTHREADTYPE_INVALID = 0, + /** Infrequent poller thread. + * This type of thread will sleep for the most of the time, and do + * infrequent polls on resources at 0.5 sec or higher intervals. + */ + RTTHREADTYPE_INFREQUENT_POLLER, + /** Main heavy worker thread. + * Thread of this type is driving asynchronous tasks in the Main + * API which takes a long time and might involve a bit of CPU. Like + * for instance creating a fixed sized VDI. + */ + RTTHREADTYPE_MAIN_HEAVY_WORKER, + /** The emulation thread type. + * While being a thread with very high workload it still is vital + * that it gets scheduled frequently. When possible all other thread + * types except DEFAULT and GUI should interrupt this one ASAP when + * they become ready. + */ + RTTHREADTYPE_EMULATION, + /** The default thread type. + * Since it doesn't say much about the purpose of the thread + * nothing special is normally done to the scheduling. This type + * should be avoided. + * The main thread is registered with default type during RTR3Init() + * and that's what the default process priority is derived from. + */ + RTTHREADTYPE_DEFAULT, + /** The GUI thread type + * The GUI normally have a low workload but is frequently scheduled + * to handle events. When possible the scheduler should not leave + * threads of this kind waiting for too long (~50ms). + */ + RTTHREADTYPE_GUI, + /** Main worker thread. + * Thread of this type is driving asynchronous tasks in the Main API. + * In most cases this means little work an a lot of waiting. + */ + RTTHREADTYPE_MAIN_WORKER, + /** VRDP I/O thread. + * These threads are I/O threads in the RDP server will hang around + * waiting for data, process it and pass it on. + */ + RTTHREADTYPE_VRDP_IO, + /** The debugger type. + * Threads involved in servicing the debugger. It must remain + * responsive even when things are running wild in. + */ + RTTHREADTYPE_DEBUGGER, + /** Message pump thread. + * Thread pumping messages from one thread/process to another + * thread/process. The workload is very small, most of the time + * it's blocked waiting for messages to be produced or processed. + * This type of thread will be favored after I/O threads. + */ + RTTHREADTYPE_MSG_PUMP, + /** The I/O thread type. + * Doing I/O means shuffling data, waiting for request to arrive and + * for them to complete. The thread should be favored when competing + * with any other threads except timer threads. + */ + RTTHREADTYPE_IO, + /** The timer thread type. + * A timer thread is mostly waiting for the timer to tick + * and then perform a little bit of work. Accuracy is important here, + * so the thread should be favoured over all threads. If premention can + * be configured at thread level, it could be made very short. + */ + RTTHREADTYPE_TIMER, + /** Only used for validation. */ + RTTHREADTYPE_END +} RTTHREADTYPE; + + +#if !defined(IN_RC) || defined(DOXYGEN_RUNNING) + +/** + * Checks if the IPRT thread component has been initialized. + * + * This is used to avoid calling into RTThread before the runtime has been + * initialized. + * + * @returns @c true if it's initialized, @c false if not. + */ +RTDECL(bool) RTThreadIsInitialized(void); + +/** + * Get the thread handle of the current thread. + * + * @returns Thread handle. + */ +RTDECL(RTTHREAD) RTThreadSelf(void); + +/** + * Get the native thread handle of the current thread. + * + * @returns Native thread handle. + */ +RTDECL(RTNATIVETHREAD) RTThreadNativeSelf(void); + +/** + * Millisecond granular sleep function. + * + * @returns VINF_SUCCESS on success. + * @returns VERR_INTERRUPTED if a signal or other asynchronous stuff happened + * which interrupt the peaceful sleep. + * @param cMillies Number of milliseconds to sleep. + * 0 milliseconds means yielding the timeslice - deprecated! + * @remark See RTThreadNanoSleep() for sleeping for smaller periods of time. + */ +RTDECL(int) RTThreadSleep(RTMSINTERVAL cMillies); + +/** + * Millisecond granular sleep function, no logger calls. + * + * Same as RTThreadSleep, except it will never call into the IPRT logger. It + * can therefore safely be used in places where the logger is off limits, like + * at termination or init time. The electric fence heap is one consumer of + * this API. + * + * @returns VINF_SUCCESS on success. + * @returns VERR_INTERRUPTED if a signal or other asynchronous stuff happened + * which interrupt the peaceful sleep. + * @param cMillies Number of milliseconds to sleep. + * 0 milliseconds means yielding the timeslice - deprecated! + */ +RTDECL(int) RTThreadSleepNoLog(RTMSINTERVAL cMillies); + +/** + * Yields the CPU. + * + * @returns true if we yielded. + * @returns false if it's probable that we didn't yield. + */ +RTDECL(bool) RTThreadYield(void); + + + +/** + * Thread function. + * + * @returns 0 on success. + * @param ThreadSelf Thread handle to this thread. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTTHREAD,(RTTHREAD ThreadSelf, void *pvUser)); +/** Pointer to a FNRTTHREAD(). */ +typedef FNRTTHREAD *PFNRTTHREAD; + +/** + * Thread creation flags. + */ +typedef enum RTTHREADFLAGS +{ + /** This flag is used to keep the thread structure around so it can + * be waited on after termination. @sa RTThreadWait and + * RTThreadWaitNoResume. Not required for RTThreadUserWait and friends! + */ + RTTHREADFLAGS_WAITABLE = RT_BIT(0), + /** The bit number corresponding to the RTTHREADFLAGS_WAITABLE mask. */ + RTTHREADFLAGS_WAITABLE_BIT = 0, + + /** Call CoInitializeEx w/ COINIT_MULTITHREADED, COINIT_DISABLE_OLE1DDE and + * COINIT_SPEED_OVER_MEMORY. Ignored on non-windows platforms. */ + RTTHREADFLAGS_COM_MTA = RT_BIT(1), + /** Call CoInitializeEx w/ COINIT_APARTMENTTHREADED and + * COINIT_SPEED_OVER_MEMORY. Ignored on non-windows platforms. */ + RTTHREADFLAGS_COM_STA = RT_BIT(2), + + /** Mask all signals that we can mask. Ignored on most non-posix platforms. + * @note RTThreadPoke() will not necessarily work for a thread create with + * this flag. */ + RTTHREADFLAGS_NO_SIGNALS = RT_BIT(3), + + /** Mask of valid flags, use for validation. */ + RTTHREADFLAGS_MASK = UINT32_C(0xf) +} RTTHREADFLAGS; + +/** Max thread name length (including zero terminator). */ +#define RTTHREAD_NAME_LEN 16 + +/** + * Create a new thread. + * + * @returns iprt status code. + * @param pThread Where to store the thread handle to the new thread. (optional) + * @param pfnThread The thread function. + * @param pvUser User argument. + * @param cbStack The size of the stack for the new thread. + * Use 0 for the default stack size. + * @param enmType The thread type. Used for deciding scheduling attributes + * of the thread. + * @param fFlags Flags of the RTTHREADFLAGS type (ORed together). + * @param pszName Thread name. + * + * @remark When called in Ring-0, this API will create a new kernel thread and not a thread in + * the context of the calling process. + */ +RTDECL(int) RTThreadCreate(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack, + RTTHREADTYPE enmType, unsigned fFlags, const char *pszName); +#ifndef RT_OS_LINUX /* XXX crashes genksyms at least on 32-bit Linux hosts */ +/** Pointer to a RTThreadCreate function. */ +typedef DECLCALLBACKPTR(int, PFNRTTHREADCREATE,(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack, + RTTHREADTYPE enmType, unsigned fFlags, const char *pszName)); +#endif + + +/** + * Create a new thread. + * + * Same as RTThreadCreate except the name is given in the RTStrPrintfV form. + * + * @returns iprt status code. + * @param pThread See RTThreadCreate. + * @param pfnThread See RTThreadCreate. + * @param pvUser See RTThreadCreate. + * @param cbStack See RTThreadCreate. + * @param enmType See RTThreadCreate. + * @param fFlags See RTThreadCreate. + * @param pszNameFmt Thread name format. + * @param va Format arguments. + */ +RTDECL(int) RTThreadCreateV(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack, + RTTHREADTYPE enmType, uint32_t fFlags, const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(7, 0); + +/** + * Create a new thread. + * + * Same as RTThreadCreate except the name is given in the RTStrPrintf form. + * + * @returns iprt status code. + * @param pThread See RTThreadCreate. + * @param pfnThread See RTThreadCreate. + * @param pvUser See RTThreadCreate. + * @param cbStack See RTThreadCreate. + * @param enmType See RTThreadCreate. + * @param fFlags See RTThreadCreate. + * @param pszNameFmt Thread name format. + * @param ... Format arguments. + */ +RTDECL(int) RTThreadCreateF(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack, + RTTHREADTYPE enmType, uint32_t fFlags, const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(7, 8); + +/** + * Gets the native thread id of a IPRT thread. + * + * @returns The native thread id. + * @param Thread The IPRT thread. + */ +RTDECL(RTNATIVETHREAD) RTThreadGetNative(RTTHREAD Thread); + +/** + * Gets the native thread handle for a IPRT thread. + * + * @returns The thread handle. INVALID_HANDLE_VALUE on failure. + * @param hThread The IPRT thread handle. + * + * @note Windows only. + * @note Only valid after parent returns from the thread creation call. + */ +RTDECL(uintptr_t) RTThreadGetNativeHandle(RTTHREAD hThread); + +/** + * Gets the IPRT thread of a native thread. + * + * @returns The IPRT thread handle + * @returns NIL_RTTHREAD if not a thread known to IPRT. + * @param NativeThread The native thread handle/id. + */ +RTDECL(RTTHREAD) RTThreadFromNative(RTNATIVETHREAD NativeThread); + +/** + * Changes the type of the specified thread. + * + * @returns iprt status code. + * @param Thread The thread which type should be changed. + * @param enmType The new thread type. + * @remark In Ring-0 it only works if Thread == RTThreadSelf(). + */ +RTDECL(int) RTThreadSetType(RTTHREAD Thread, RTTHREADTYPE enmType); + +/** + * Wait for the thread to terminate, resume on interruption. + * + * @returns iprt status code. + * Will not return VERR_INTERRUPTED. + * @param Thread The thread to wait for. + * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for + * an indefinite wait. + * @param prc Where to store the return code of the thread. Optional. + */ +RTDECL(int) RTThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc); + +/** + * Wait for the thread to terminate, return on interruption. + * + * @returns iprt status code. + * @param Thread The thread to wait for. + * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for + * an indefinite wait. + * @param prc Where to store the return code of the thread. Optional. + */ +RTDECL(int) RTThreadWaitNoResume(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc); + +/** + * Gets the name of the current thread thread. + * + * @returns Pointer to readonly name string. + * @returns NULL on failure. + */ +RTDECL(const char *) RTThreadSelfName(void); + +/** + * Gets the name of a thread. + * + * @returns Pointer to readonly name string. + * @returns NULL on failure. + * @param Thread Thread handle of the thread to query the name of. + */ +RTDECL(const char *) RTThreadGetName(RTTHREAD Thread); + +/** + * Gets the type of the specified thread. + * + * @returns The thread type. + * @returns RTTHREADTYPE_INVALID if the thread handle is invalid. + * @param Thread The thread in question. + */ +RTDECL(RTTHREADTYPE) RTThreadGetType(RTTHREAD Thread); + +/** + * Sets the name of a thread. + * + * @returns iprt status code. + * @param Thread Thread handle of the thread to query the name of. + * @param pszName The thread name. + */ +RTDECL(int) RTThreadSetName(RTTHREAD Thread, const char *pszName); + +/** + * Checks if the specified thread is the main thread. + * + * @returns true if it is, false if it isn't. + * + * @param hThread The thread handle. + */ +RTDECL(bool) RTThreadIsMain(RTTHREAD hThread); + +/** + * Checks if the calling thread is known to IPRT. + * + * @returns @c true if it is, @c false if it isn't. + */ +RTDECL(bool) RTThreadIsSelfKnown(void); + +/** + * Checks if the calling thread is know to IPRT and is alive. + * + * @returns @c true if it is, @c false if it isn't. + */ +RTDECL(bool) RTThreadIsSelfAlive(void); + +#ifdef IN_RING0 +/** + * Checks whether the specified thread is terminating. + * + * @retval VINF_SUCCESS if not terminating. + * @retval VINF_THREAD_IS_TERMINATING if terminating. + * @retval VERR_INVALID_HANDLE if hThread is not NIL_RTTHREAD. + * @retval VERR_NOT_SUPPORTED if the OS doesn't provide ways to check. + * + * @param hThread The thread to query about, NIL_RTTHREAD is an alias for + * the calling thread. Must be NIL_RTTHREAD for now. + * + * @note Not suppored on all OSes, so check for VERR_NOT_SUPPORTED. + */ +RTDECL(int) RTThreadQueryTerminationStatus(RTTHREAD hThread); +#endif + +/** + * Signal the user event. + * + * @returns iprt status code. + */ +RTDECL(int) RTThreadUserSignal(RTTHREAD Thread); + +/** + * Wait for the user event. + * + * @returns iprt status code. + * @param Thread The thread to wait for. + * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for + * an indefinite wait. + */ +RTDECL(int) RTThreadUserWait(RTTHREAD Thread, RTMSINTERVAL cMillies); + +/** + * Wait for the user event, return on interruption. + * + * @returns iprt status code. + * @param Thread The thread to wait for. + * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for + * an indefinite wait. + */ +RTDECL(int) RTThreadUserWaitNoResume(RTTHREAD Thread, RTMSINTERVAL cMillies); + +/** + * Reset the user event. + * + * @returns iprt status code. + * @param Thread The thread to reset. + */ +RTDECL(int) RTThreadUserReset(RTTHREAD Thread); + +/** + * Pokes the thread. + * + * This will wake up or/and signal the thread, attempting to interrupt whatever + * it's currently doing. + * + * The posixy version of this will send a signal to the thread, quite likely + * waking it up from normal sleeps, waits, and I/O. When IPRT is in + * non-obtrusive mode, the posixy version will definitely return + * VERR_NOT_IMPLEMENTED, and it may also do so if no usable signal was found. + * + * On Windows the thread will be alerted, waking it up from most sleeps and + * waits, but not probably very little in the I/O area (needs testing). On NT + * 3.50 and 3.1 VERR_NOT_IMPLEMENTED will be returned. + * + * @returns IPRT status code. + * + * @param hThread The thread to poke. This must not be the + * calling thread. + * + * @note This is *NOT* implemented on all platforms and may cause unresolved + * symbols during linking or VERR_NOT_IMPLEMENTED at runtime. + * + */ +RTDECL(int) RTThreadPoke(RTTHREAD hThread); + +/** + * Controls the masking of the signal used by RTThreadPoke on posix systems. + * + * This function is not available on non-posix systems. + * + * @returns IPRT status code. + * + * @param hThread The current thread. + * @param fEnable Whether to enable poking (unblock) or to disable it + * (block the signal). + */ +RTDECL(int) RTThreadControlPokeSignal(RTTHREAD hThread, bool fEnable); + + +# ifdef IN_RING0 + +/** + * Check if preemption is currently enabled or not for the current thread. + * + * @note This may return true even on systems where preemption isn't + * possible. In that case, it means no call to RTThreadPreemptDisable + * has been made and interrupts are still enabled. + * + * @returns true if preemption is enabled, false if preemetion is disabled. + * @param hThread Must be NIL_RTTHREAD for now. + */ +RTDECL(bool) RTThreadPreemptIsEnabled(RTTHREAD hThread); + +/** + * Check if preemption is pending for the current thread. + * + * This function should be called regularly when executing larger portions of + * code with preemption disabled. + * + * @returns true if pending, false if not. + * @param hThread Must be NIL_RTTHREAD for now. + * + * @note If called with interrupts disabled, the NT kernel may temporarily + * re-enable them while checking. + */ +RTDECL(bool) RTThreadPreemptIsPending(RTTHREAD hThread); + +/** + * Is RTThreadPreemptIsPending reliable? + * + * @returns true if reliable, false if not. + */ +RTDECL(bool) RTThreadPreemptIsPendingTrusty(void); + +/** + * Is preemption possible on this system. + * + * @returns true if possible, false if not. + */ +RTDECL(bool) RTThreadPreemptIsPossible(void); + +/** + * Preemption state saved by RTThreadPreemptDisable and used by + * RTThreadPreemptRestore to restore the previous state. + */ +typedef struct RTTHREADPREEMPTSTATE +{ + /** In debug builds this will be used to check for cpu migration. */ + RTCPUID idCpu; +# ifdef RT_OS_WINDOWS + /** The old IRQL. Don't touch! */ + unsigned char uchOldIrql; + /** Reserved, MBZ. */ + uint8_t bReserved1; + /** Reserved, MBZ. */ + uint8_t bReserved2; + /** Reserved, MBZ. */ + uint8_t bReserved3; +# define RTTHREADPREEMPTSTATE_INITIALIZER { NIL_RTCPUID, 255, 0, 0, 0 } +# elif defined(RT_OS_HAIKU) + /** The cpu_state. Don't touch! */ + uint32_t uOldCpuState; +# define RTTHREADPREEMPTSTATE_INITIALIZER { NIL_RTCPUID, 0 } +# elif defined(RT_OS_SOLARIS) + /** The Old PIL. Don't touch! */ + uint32_t uOldPil; +# define RTTHREADPREEMPTSTATE_INITIALIZER { NIL_RTCPUID, UINT32_MAX } +# else + /** Reserved, MBZ. */ + uint32_t u32Reserved; +# define RTTHREADPREEMPTSTATE_INITIALIZER { NIL_RTCPUID, 0 } +# endif +} RTTHREADPREEMPTSTATE; +/** Pointer to a preemption state. */ +typedef RTTHREADPREEMPTSTATE *PRTTHREADPREEMPTSTATE; + +/** + * Disable preemption. + * + * A call to this function must be matched by exactly one call to + * RTThreadPreemptRestore(). + * + * @param pState Where to store the preemption state. + */ +RTDECL(void) RTThreadPreemptDisable(PRTTHREADPREEMPTSTATE pState); + +/** + * Restores the preemption state, undoing a previous call to + * RTThreadPreemptDisable. + * + * A call to this function must be matching a previous call to + * RTThreadPreemptDisable. + * + * @param pState The state return by RTThreadPreemptDisable. + */ +RTDECL(void) RTThreadPreemptRestore(PRTTHREADPREEMPTSTATE pState); + +/** + * Check if the thread is executing in interrupt context. + * + * @returns true if in interrupt context, false if not. + * @param hThread Must be NIL_RTTHREAD for now. + */ +RTDECL(bool) RTThreadIsInInterrupt(RTTHREAD hThread); + + +/** + * Thread context swithcing events. + */ +typedef enum RTTHREADCTXEVENT +{ + /** This thread is being scheduled out on the current CPU (includes preemption, + * waiting, sleep and whatever else may trigger scheduling). */ + RTTHREADCTXEVENT_OUT = 0, + /** This thread is being scheduled in on the current CPU and will resume + * execution. */ + RTTHREADCTXEVENT_IN, + /** The usual 32-bit size hack. */ + RTTHREADCTXEVENT_32BIT_HACK = 0x7fffffff +} RTTHREADCTXEVENT; + +/** + * Thread context switching hook callback. + * + * This hook function is called when a thread is scheduled and preempted. Check + * @a enmEvent to see which it is. Since the function is being called from + * hooks inside the scheduler, it is limited what you can do from this function. + * Do NOT acquire locks, sleep or yield the thread for instance. IRQ safe + * spinlocks are fine though. + * + * @returns IPRT status code. + * @param enmEvent The thread-context event. Please quitely ignore unknown + * events, we may add more (thread exit, ++) later. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(void, FNRTTHREADCTXHOOK,(RTTHREADCTXEVENT enmEvent, void *pvUser)); +/** Pointer to a context switching hook. */ +typedef FNRTTHREADCTXHOOK *PFNRTTHREADCTXHOOK; + +/** + * Initializes a thread context switching hook for the current thread. + * + * The hook is created as disabled, use RTThreadCtxHookEnable to enable it. + * + * @returns IPRT status code. + * @param phCtxHook Where to store the hook handle. + * @param fFlags Reserved for future extensions, must be zero. + * @param pfnCallback Pointer to a the hook function (callback) that + * should be called for all context switching events + * involving the current thread. + * @param pvUser User argument that will be passed to @a pfnCallback. + * @remarks Preemption must be enabled. + */ +RTDECL(int) RTThreadCtxHookCreate(PRTTHREADCTXHOOK phCtxHook, uint32_t fFlags, PFNRTTHREADCTXHOOK pfnCallback, void *pvUser); + +/** + * Destroys a thread context switching hook. + * + * Caller must make sure the hook is disabled before the final reference is + * released. Recommended to call this on the owning thread, otherwise the + * memory backing it may on some systems only be released when the thread + * terminates. + * + * @returns IPRT status code. + * + * @param hCtxHook The context hook handle. NIL_RTTHREADCTXHOOK is + * ignored and the function will return VINF_SUCCESS. + * @remarks Preemption must be enabled. + * @remarks Do not call from FNRTTHREADCTXHOOK. + */ +RTDECL(int) RTThreadCtxHookDestroy(RTTHREADCTXHOOK hCtxHook); + +/** + * Enables the context switching hooks for the current thread. + * + * @returns IPRT status code. + * @param hCtxHook The context hook handle. + * @remarks Should be called with preemption disabled. + */ +RTDECL(int) RTThreadCtxHookEnable(RTTHREADCTXHOOK hCtxHook); + +/** + * Disables the thread context switching hook for the current thread. + * + * Will not assert or fail if called twice or with a NIL handle. + * + * @returns IPRT status code. + * @param hCtxHook The context hook handle. NIL_RTTHREADCTXHOOK is + * ignored and the function wil return VINF_SUCCESS. + * @remarks Should be called with preemption disabled. + * @remarks Do not call from FNRTTHREADCTXHOOK. + */ +RTDECL(int) RTThreadCtxHookDisable(RTTHREADCTXHOOK hCtxHook); + +/** + * Is the thread context switching hook enabled? + * + * @returns true if registered, false if not supported or not registered. + * @param hCtxHook The context hook handle. NIL_RTTHREADCTXHOOK is + * ignored and the function will return false. + * + * @remarks Can be called from any thread, though is naturally subject to races + * when not called from the thread associated with the hook. + */ +RTDECL(bool) RTThreadCtxHookIsEnabled(RTTHREADCTXHOOK hCtxHook); + +# endif /* IN_RING0 */ + + +# ifdef IN_RING3 + +/** + * Adopts a non-IPRT thread. + * + * @returns IPRT status code. + * @param enmType The thread type. + * @param fFlags The thread flags. RTTHREADFLAGS_WAITABLE is not currently allowed. + * @param pszName The thread name. Optional + * @param pThread Where to store the thread handle. Optional. + */ +RTDECL(int) RTThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, const char *pszName, PRTTHREAD pThread); + +/** + * Get the thread handle of the current thread, automatically adopting alien + * threads. + * + * @returns Thread handle. + */ +RTDECL(RTTHREAD) RTThreadSelfAutoAdopt(void); + +/** + * Gets the affinity mask of the current thread. + * + * @returns IPRT status code. + * @param pCpuSet Where to return the CPU affienty set of the calling + * thread. + */ +RTR3DECL(int) RTThreadGetAffinity(PRTCPUSET pCpuSet); + +/** + * Sets the affinity mask of the current thread. + * + * @returns iprt status code. + * @param pCpuSet The set of CPUs this thread can run on. NULL means + * all CPUs. + */ +RTR3DECL(int) RTThreadSetAffinity(PCRTCPUSET pCpuSet); + +/** + * Binds the thread to one specific CPU. + * + * @returns iprt status code. + * @param idCpu The ID of the CPU to bind this thread to. Use + * NIL_RTCPUID to unbind it. + */ +RTR3DECL(int) RTThreadSetAffinityToCpu(RTCPUID idCpu); + +/** + * Unblocks a thread. + * + * This function is paired with RTThreadBlocking and RTThreadBlockingDebug. + * + * @param hThread The current thread. + * @param enmCurState The current state, used to check for nested blocking. + * The new state will be running. + */ +RTDECL(void) RTThreadUnblocked(RTTHREAD hThread, RTTHREADSTATE enmCurState); + +/** + * Change the thread state to blocking. + * + * @param hThread The current thread. + * @param enmState The sleep state. + * @param fReallySleeping Really going to sleep now. Use false before calls + * to other IPRT synchronization methods. + */ +RTDECL(void) RTThreadBlocking(RTTHREAD hThread, RTTHREADSTATE enmState, bool fReallySleeping); + +/** + * Get the current thread state. + * + * A thread that is reported as sleeping may actually still be running inside + * the lock validator or/and in the code of some other IPRT synchronization + * primitive. Use RTThreadGetReallySleeping + * + * @returns The thread state. + * @param hThread The thread. + */ +RTDECL(RTTHREADSTATE) RTThreadGetState(RTTHREAD hThread); + +/** + * Checks if the thread is really sleeping or not. + * + * @returns RTTHREADSTATE_RUNNING if not really sleeping, otherwise the state it + * is sleeping in. + * @param hThread The thread. + */ +RTDECL(RTTHREADSTATE) RTThreadGetReallySleeping(RTTHREAD hThread); + +/** + * Translate a thread state into a string. + * + * @returns Pointer to a read-only string containing the state name. + * @param enmState The state. + */ +RTDECL(const char *) RTThreadStateName(RTTHREADSTATE enmState); + + +/** + * Native thread states returned by RTThreadNativeState. + */ +typedef enum RTTHREADNATIVESTATE +{ + /** Invalid thread handle. */ + RTTHREADNATIVESTATE_INVALID = 0, + /** Unable to determine the thread state. */ + RTTHREADNATIVESTATE_UNKNOWN, + /** The thread is running. */ + RTTHREADNATIVESTATE_RUNNING, + /** The thread is blocked. */ + RTTHREADNATIVESTATE_BLOCKED, + /** The thread is suspended / stopped. */ + RTTHREADNATIVESTATE_SUSPENDED, + /** The thread has terminated. */ + RTTHREADNATIVESTATE_TERMINATED, + /** Make sure it's a 32-bit type. */ + RTTHREADNATIVESTATE_32BIT_HACK = 0x7fffffff +} RTTHREADNATIVESTATE; + + +/** + * Get the native state of a thread. + * + * @returns Native state. + * @param hThread The thread handle. + * + * @remarks Not yet implemented on all systems, so have a backup plan for + * RTTHREADNATIVESTATE_UNKNOWN. + */ +RTDECL(RTTHREADNATIVESTATE) RTThreadGetNativeState(RTTHREAD hThread); + + +/** + * Get the execution times of the specified thread + * + * @returns IPRT status code. + * @param pKernelTime Kernel execution time in ms (out) + * @param pUserTime User execution time in ms (out) + * + */ +RTR3DECL(int) RTThreadGetExecutionTimeMilli(uint64_t *pKernelTime, uint64_t *pUserTime); + +/** @name Thread Local Storage + * @{ + */ +/** + * Thread termination callback for destroying a non-zero TLS entry. + * + * @remarks It is not permitable to use any RTTls APIs at this time. Doing so + * may lead to endless loops, crashes, and other bad stuff. + * + * @param pvValue The current value. + */ +typedef DECLCALLBACKTYPE(void, FNRTTLSDTOR,(void *pvValue)); +/** Pointer to a FNRTTLSDTOR. */ +typedef FNRTTLSDTOR *PFNRTTLSDTOR; + +/** + * Allocates a TLS entry (index). + * + * Example code: + * @code + RTTLS g_iTls = NIL_RTTLS; + + ... + + // once for the process, allocate the TLS index + if (g_iTls == NIL_RTTLS) + g_iTls = RTTlsAlloc(); + + // set the thread-local value. + RTTlsSet(g_iTls, pMyData); + + ... + + // get the thread-local value + PMYDATA pMyData = (PMYDATA)RTTlsGet(g_iTls); + + @endcode + * + * @returns the index of the allocated TLS entry. + * @returns NIL_RTTLS on failure. + */ +RTR3DECL(RTTLS) RTTlsAlloc(void); + +/** + * Variant of RTTlsAlloc that returns a status code. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if pfnDestructor is non-NULL and the platform + * doesn't support this feature. + * + * @param piTls Where to store the index of the allocated TLS entry. + * This is set to NIL_RTTLS on failure. + * @param pfnDestructor Optional callback function for cleaning up on + * thread termination. + * @note In static builds on windows, the destructor will only be invoked for + * IPRT threads. + * @note There are probably OS specific restrictions on what operations you + * are allowed to perform from a TLS destructor, so keep it simple. + */ +RTR3DECL(int) RTTlsAllocEx(PRTTLS piTls, PFNRTTLSDTOR pfnDestructor); + +/** + * Frees a TLS entry. + * + * @returns IPRT status code. + * @param iTls The index of the TLS entry. + */ +RTR3DECL(int) RTTlsFree(RTTLS iTls); + +/** + * Get the (thread-local) value stored in a TLS entry. + * + * @returns value in given TLS entry. + * @retval NULL if RTTlsSet() has not yet been called on this thread, or if the + * TLS index is invalid. + * + * @param iTls The index of the TLS entry. + */ +RTR3DECL(void *) RTTlsGet(RTTLS iTls); + +/** + * Get the value stored in a TLS entry. + * + * @returns IPRT status code. + * @param iTls The index of the TLS entry. + * @param ppvValue Where to store the value. The value will be NULL if + * RTTlsSet has not yet been called on this thread. + */ +RTR3DECL(int) RTTlsGetEx(RTTLS iTls, void **ppvValue); + +/** + * Set the value stored in an allocated TLS entry. + * + * @returns IPRT status. + * @param iTls The index of the TLS entry. + * @param pvValue The value to store. + * + * @remarks Note that NULL is considered a special value. + */ +RTR3DECL(int) RTTlsSet(RTTLS iTls, void *pvValue); + +/** @} */ + +# endif /* IN_RING3 */ +#endif /* !IN_RC || defined(DOXYGEN_RUNNING) */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_thread_h */ + diff --git a/include/iprt/time.h b/include/iprt/time.h new file mode 100644 index 00000000..178f1e33 --- /dev/null +++ b/include/iprt/time.h @@ -0,0 +1,1352 @@ +/** @file + * IPRT - Time. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_time_h +#define IPRT_INCLUDED_time_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/assertcompile.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_time RTTime - Time + * @ingroup grp_rt + * @{ + */ + +/** Time Specification. + * + * Use the inline RTTimeSpecGet/Set to operate on structure this so we + * can easily change the representation if required later. + * + * The current representation is in nanoseconds relative to the unix epoch + * (1970-01-01 00:00:00 UTC). This gives us an approximate span from + * 1678 to 2262 without sacrificing the resolution offered by the various + * host OSes (BSD & LINUX 1ns, NT 100ns). + */ +typedef struct RTTIMESPEC +{ + /** Nanoseconds since epoch. + * The name is intentially too long to be comfortable to use because you should be + * using inline helpers! */ + int64_t i64NanosecondsRelativeToUnixEpoch; +} RTTIMESPEC; + + +/** @name RTTIMESPEC methods + * @{ */ + +/** + * Gets the time as nanoseconds relative to the unix epoch. + * + * @returns Nanoseconds relative to unix epoch. + * @param pTime The time spec to interpret. + */ +DECLINLINE(int64_t) RTTimeSpecGetNano(PCRTTIMESPEC pTime) +{ + return pTime->i64NanosecondsRelativeToUnixEpoch; +} + + +/** + * Sets the time give by nanoseconds relative to the unix epoch. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Nano The new time in nanoseconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetNano(PRTTIMESPEC pTime, int64_t i64Nano) +{ + pTime->i64NanosecondsRelativeToUnixEpoch = i64Nano; + return pTime; +} + + +/** + * Gets the time as microseconds relative to the unix epoch. + * + * @returns microseconds relative to unix epoch. + * @param pTime The time spec to interpret. + */ +DECLINLINE(int64_t) RTTimeSpecGetMicro(PCRTTIMESPEC pTime) +{ + return pTime->i64NanosecondsRelativeToUnixEpoch / RT_NS_1US; +} + + +/** + * Sets the time given by microseconds relative to the unix epoch. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Micro The new time in microsecond. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetMicro(PRTTIMESPEC pTime, int64_t i64Micro) +{ + pTime->i64NanosecondsRelativeToUnixEpoch = i64Micro * RT_NS_1US; + return pTime; +} + + +/** + * Gets the time as milliseconds relative to the unix epoch. + * + * @returns milliseconds relative to unix epoch. + * @param pTime The time spec to interpret. + */ +DECLINLINE(int64_t) RTTimeSpecGetMilli(PCRTTIMESPEC pTime) +{ + return pTime->i64NanosecondsRelativeToUnixEpoch / RT_NS_1MS; +} + + +/** + * Sets the time given by milliseconds relative to the unix epoch. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Milli The new time in milliseconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetMilli(PRTTIMESPEC pTime, int64_t i64Milli) +{ + pTime->i64NanosecondsRelativeToUnixEpoch = i64Milli * RT_NS_1MS; + return pTime; +} + + +/** + * Gets the time as seconds relative to the unix epoch. + * + * @returns seconds relative to unix epoch. + * @param pTime The time spec to interpret. + */ +DECLINLINE(int64_t) RTTimeSpecGetSeconds(PCRTTIMESPEC pTime) +{ + return pTime->i64NanosecondsRelativeToUnixEpoch / RT_NS_1SEC; +} + + +/** + * Sets the time given by seconds relative to the unix epoch. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Seconds The new time in seconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetSeconds(PRTTIMESPEC pTime, int64_t i64Seconds) +{ + pTime->i64NanosecondsRelativeToUnixEpoch = i64Seconds * RT_NS_1SEC; + return pTime; +} + + +/** + * Makes the time spec absolute like abs() does (i.e. a positive value). + * + * @returns pTime. + * @param pTime The time spec to modify. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecAbsolute(PRTTIMESPEC pTime) +{ + if (pTime->i64NanosecondsRelativeToUnixEpoch < 0) + pTime->i64NanosecondsRelativeToUnixEpoch = -pTime->i64NanosecondsRelativeToUnixEpoch; + return pTime; +} + + +/** + * Negates the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecNegate(PRTTIMESPEC pTime) +{ + pTime->i64NanosecondsRelativeToUnixEpoch = -pTime->i64NanosecondsRelativeToUnixEpoch; + return pTime; +} + + +/** + * Adds a time period to the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param pTimeAdd The time spec to add to pTime. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecAdd(PRTTIMESPEC pTime, PCRTTIMESPEC pTimeAdd) +{ + pTime->i64NanosecondsRelativeToUnixEpoch += pTimeAdd->i64NanosecondsRelativeToUnixEpoch; + return pTime; +} + + +/** + * Adds a time period give as nanoseconds from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Nano The time period in nanoseconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecAddNano(PRTTIMESPEC pTime, int64_t i64Nano) +{ + pTime->i64NanosecondsRelativeToUnixEpoch += i64Nano; + return pTime; +} + + +/** + * Adds a time period give as microseconds from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Micro The time period in microseconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecAddMicro(PRTTIMESPEC pTime, int64_t i64Micro) +{ + pTime->i64NanosecondsRelativeToUnixEpoch += i64Micro * RT_NS_1US; + return pTime; +} + + +/** + * Adds a time period give as milliseconds from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Milli The time period in milliseconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecAddMilli(PRTTIMESPEC pTime, int64_t i64Milli) +{ + pTime->i64NanosecondsRelativeToUnixEpoch += i64Milli * RT_NS_1MS; + return pTime; +} + + +/** + * Adds a time period give as seconds from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Seconds The time period in seconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecAddSeconds(PRTTIMESPEC pTime, int64_t i64Seconds) +{ + pTime->i64NanosecondsRelativeToUnixEpoch += i64Seconds * RT_NS_1SEC; + return pTime; +} + + +/** + * Subtracts a time period from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param pTimeSub The time spec to subtract from pTime. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSub(PRTTIMESPEC pTime, PCRTTIMESPEC pTimeSub) +{ + pTime->i64NanosecondsRelativeToUnixEpoch -= pTimeSub->i64NanosecondsRelativeToUnixEpoch; + return pTime; +} + + +/** + * Subtracts a time period give as nanoseconds from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Nano The time period in nanoseconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSubNano(PRTTIMESPEC pTime, int64_t i64Nano) +{ + pTime->i64NanosecondsRelativeToUnixEpoch -= i64Nano; + return pTime; +} + + +/** + * Subtracts a time period give as microseconds from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Micro The time period in microseconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSubMicro(PRTTIMESPEC pTime, int64_t i64Micro) +{ + pTime->i64NanosecondsRelativeToUnixEpoch -= i64Micro * RT_NS_1US; + return pTime; +} + + +/** + * Subtracts a time period give as milliseconds from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Milli The time period in milliseconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSubMilli(PRTTIMESPEC pTime, int64_t i64Milli) +{ + pTime->i64NanosecondsRelativeToUnixEpoch -= i64Milli * RT_NS_1MS; + return pTime; +} + + +/** + * Subtracts a time period give as seconds from the time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Seconds The time period in seconds. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSubSeconds(PRTTIMESPEC pTime, int64_t i64Seconds) +{ + pTime->i64NanosecondsRelativeToUnixEpoch -= i64Seconds * RT_NS_1SEC; + return pTime; +} + + +/** + * Gives the time in seconds and nanoseconds. + * + * @returns pTime. + * @param pTime The time spec to interpret. + * @param *pi32Seconds Where to store the time period in seconds. + * @param *pi32Nano Where to store the time period in nanoseconds. + */ +DECLINLINE(void) RTTimeSpecGetSecondsAndNano(PRTTIMESPEC pTime, int32_t *pi32Seconds, int32_t *pi32Nano) +{ + int64_t i64 = RTTimeSpecGetNano(pTime); + int32_t i32Nano = (int32_t)(i64 % RT_NS_1SEC); + i64 /= RT_NS_1SEC; + if (i32Nano < 0) + { + i32Nano += RT_NS_1SEC; + i64--; + } + *pi32Seconds = (int32_t)i64; + *pi32Nano = i32Nano; +} + +/** @def RTTIME_LINUX_KERNEL_PREREQ + * Prerequisite minimum linux kernel version. + * @note Cannot really be moved to iprt/cdefs.h, see the-linux-kernel.h */ +/** @def RTTIME_LINUX_KERNEL_PREREQ_LT + * Prerequisite maxium linux kernel version (LT=less-than). + * @note Cannot really be moved to iprt/cdefs.h, see the-linux-kernel.h */ +#if defined(RT_OS_LINUX) && defined(LINUX_VERSION_CODE) && defined(KERNEL_VERSION) +# define RTTIME_LINUX_KERNEL_PREREQ(a, b, c) (LINUX_VERSION_CODE >= KERNEL_VERSION(a, b, c)) +# define RTTIME_LINUX_KERNEL_PREREQ_LT(a, b, c) (!RTTIME_LINUX_KERNEL_PREREQ(a, b, c)) +#else +# define RTTIME_LINUX_KERNEL_PREREQ(a, b, c) 0 +# define RTTIME_LINUX_KERNEL_PREREQ_LT(a, b, c) 0 +#endif + +/* PORTME: Add struct timeval guard macro here. */ +#if defined(RTTIME_INCL_TIMEVAL) \ + || defined(_SYS__TIMEVAL_H_) \ + || defined(_SYS_TIME_H) \ + || defined(_TIMEVAL) \ + || defined(_STRUCT_TIMEVAL) \ + || ( defined(RT_OS_LINUX) \ + && defined(_LINUX_TIME_H) \ + && ( !defined(__KERNEL__) \ + || RTTIME_LINUX_KERNEL_PREREQ_LT(5,6,0) /* @bugref{9757} */ ) ) \ + || (defined(RT_OS_NETBSD) && defined(_SYS_TIME_H_)) + +/** + * Gets the time as POSIX timeval. + * + * @returns pTime. + * @param pTime The time spec to interpret. + * @param pTimeval Where to store the time as POSIX timeval. + */ +DECLINLINE(struct timeval *) RTTimeSpecGetTimeval(PCRTTIMESPEC pTime, struct timeval *pTimeval) +{ + int64_t i64 = RTTimeSpecGetMicro(pTime); + int32_t i32Micro = (int32_t)(i64 % RT_US_1SEC); + i64 /= RT_US_1SEC; + if (i32Micro < 0) + { + i32Micro += RT_US_1SEC; + i64--; + } + pTimeval->tv_sec = (time_t)i64; + pTimeval->tv_usec = i32Micro; + return pTimeval; +} + +/** + * Sets the time as POSIX timeval. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param pTimeval Pointer to the POSIX timeval struct with the new time. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetTimeval(PRTTIMESPEC pTime, const struct timeval *pTimeval) +{ + return RTTimeSpecAddMicro(RTTimeSpecSetSeconds(pTime, pTimeval->tv_sec), pTimeval->tv_usec); +} + +#endif /* various ways of detecting struct timeval */ + + +/* PORTME: Add struct timespec guard macro here. */ +#if defined(RTTIME_INCL_TIMESPEC) \ + || defined(_SYS__TIMESPEC_H_) \ + || defined(TIMEVAL_TO_TIMESPEC) \ + || defined(_TIMESPEC) \ + || ( defined(_STRUCT_TIMESPEC) \ + && ( !defined(RT_OS_LINUX) \ + || !defined(__KERNEL__) \ + || RTTIME_LINUX_KERNEL_PREREQ_LT(5,6,0) /* @bugref{9757} */ ) ) \ + || (defined(RT_OS_NETBSD) && defined(_SYS_TIME_H_)) + +/** + * Gets the time as POSIX timespec. + * + * @returns pTimespec. + * @param pTime The time spec to interpret. + * @param pTimespec Where to store the time as POSIX timespec. + */ +DECLINLINE(struct timespec *) RTTimeSpecGetTimespec(PCRTTIMESPEC pTime, struct timespec *pTimespec) +{ + int64_t i64 = RTTimeSpecGetNano(pTime); + int32_t i32Nano = (int32_t)(i64 % RT_NS_1SEC); + i64 /= RT_NS_1SEC; + if (i32Nano < 0) + { + i32Nano += RT_NS_1SEC; + i64--; + } + pTimespec->tv_sec = (time_t)i64; + pTimespec->tv_nsec = i32Nano; + return pTimespec; +} + +/** + * Sets the time as POSIX timespec. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param pTimespec Pointer to the POSIX timespec struct with the new time. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetTimespec(PRTTIMESPEC pTime, const struct timespec *pTimespec) +{ + return RTTimeSpecAddNano(RTTimeSpecSetSeconds(pTime, pTimespec->tv_sec), pTimespec->tv_nsec); +} + +#endif /* various ways of detecting struct timespec */ + + +#if defined(RT_OS_LINUX) && defined(_LINUX_TIME64_H) /* since linux 3.17 */ + +/** + * Gets the time a linux 64-bit timespec structure. + * @returns pTimespec. + * @param pTime The time spec to modify. + * @param pTimespec Where to store the time as linux 64-bit timespec. + */ +DECLINLINE(struct timespec64 *) RTTimeSpecGetTimespec64(PCRTTIMESPEC pTime, struct timespec64 *pTimespec) +{ + int64_t i64 = RTTimeSpecGetNano(pTime); + int32_t i32Nano = (int32_t)(i64 % RT_NS_1SEC); + i64 /= RT_NS_1SEC; + if (i32Nano < 0) + { + i32Nano += RT_NS_1SEC; + i64--; + } + pTimespec->tv_sec = i64; + pTimespec->tv_nsec = i32Nano; + return pTimespec; +} + +/** + * Sets the time from a linux 64-bit timespec structure. + * @returns pTime. + * @param pTime The time spec to modify. + * @param pTimespec Pointer to the linux 64-bit timespec struct with the new time. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetTimespec64(PRTTIMESPEC pTime, const struct timespec64 *pTimespec) +{ + return RTTimeSpecAddNano(RTTimeSpecSetSeconds(pTime, pTimespec->tv_sec), pTimespec->tv_nsec); +} + +#endif /* RT_OS_LINUX && _LINUX_TIME64_H */ + + +/** The offset of the unix epoch and the base for NT time (in 100ns units). + * Nt time starts at 1601-01-01 00:00:00. */ +#define RTTIME_NT_TIME_OFFSET_UNIX (116444736000000000LL) + + +/** + * Gets the time as NT time. + * + * @returns NT time. + * @param pTime The time spec to interpret. + */ +DECLINLINE(int64_t) RTTimeSpecGetNtTime(PCRTTIMESPEC pTime) +{ + return pTime->i64NanosecondsRelativeToUnixEpoch / 100 + + RTTIME_NT_TIME_OFFSET_UNIX; +} + + +/** + * Sets the time given by Nt time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param u64NtTime The new time in Nt time. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetNtTime(PRTTIMESPEC pTime, uint64_t u64NtTime) +{ + pTime->i64NanosecondsRelativeToUnixEpoch = + ((int64_t)u64NtTime - RTTIME_NT_TIME_OFFSET_UNIX) * 100; + return pTime; +} + + +#ifdef _FILETIME_ + +/** + * Gets the time as NT file time. + * + * @returns pFileTime. + * @param pTime The time spec to interpret. + * @param pFileTime Pointer to NT filetime structure. + */ +DECLINLINE(PFILETIME) RTTimeSpecGetNtFileTime(PCRTTIMESPEC pTime, PFILETIME pFileTime) +{ + *((uint64_t *)pFileTime) = RTTimeSpecGetNtTime(pTime); + return pFileTime; +} + +/** + * Sets the time as NT file time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param pFileTime Where to store the time as Nt file time. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetNtFileTime(PRTTIMESPEC pTime, const FILETIME *pFileTime) +{ + return RTTimeSpecSetNtTime(pTime, *(const uint64_t *)pFileTime); +} + +#endif /* _FILETIME_ */ + + +/** The offset to the start of DOS time. + * DOS time starts 1980-01-01 00:00:00. */ +#define RTTIME_OFFSET_DOS_TIME (315532800000000000LL) + + +/** + * Gets the time as seconds relative to the start of dos time. + * + * @returns seconds relative to the start of dos time. + * @param pTime The time spec to interpret. + */ +DECLINLINE(int64_t) RTTimeSpecGetDosSeconds(PCRTTIMESPEC pTime) +{ + return (pTime->i64NanosecondsRelativeToUnixEpoch - RTTIME_OFFSET_DOS_TIME) + / RT_NS_1SEC; +} + + +/** + * Sets the time given by seconds relative to the start of dos time. + * + * @returns pTime. + * @param pTime The time spec to modify. + * @param i64Seconds The new time in seconds relative to the start of dos time. + */ +DECLINLINE(PRTTIMESPEC) RTTimeSpecSetDosSeconds(PRTTIMESPEC pTime, int64_t i64Seconds) +{ + pTime->i64NanosecondsRelativeToUnixEpoch = i64Seconds * RT_NS_1SEC + + RTTIME_OFFSET_DOS_TIME; + return pTime; +} + + +/** + * Compare two time specs. + * + * @returns true they are equal. + * @returns false they are not equal. + * @param pTime1 The 1st time spec. + * @param pTime2 The 2nd time spec. + */ +DECLINLINE(bool) RTTimeSpecIsEqual(PCRTTIMESPEC pTime1, PCRTTIMESPEC pTime2) +{ + return pTime1->i64NanosecondsRelativeToUnixEpoch == pTime2->i64NanosecondsRelativeToUnixEpoch; +} + + +/** + * Compare two time specs. + * + * @returns 0 if equal, -1 if @a pLeft is smaller, 1 if @a pLeft is larger. + * @returns false they are not equal. + * @param pLeft The 1st time spec. + * @param pRight The 2nd time spec. + */ +DECLINLINE(int) RTTimeSpecCompare(PCRTTIMESPEC pLeft, PCRTTIMESPEC pRight) +{ + if (pLeft->i64NanosecondsRelativeToUnixEpoch == pRight->i64NanosecondsRelativeToUnixEpoch) + return 0; + return pLeft->i64NanosecondsRelativeToUnixEpoch < pRight->i64NanosecondsRelativeToUnixEpoch ? -1 : 1; +} + + +/** + * Converts a time spec to a ISO date string. + * + * @returns psz on success. + * @returns NULL on buffer underflow. + * @param pTime The time spec. + * @param psz Where to store the string. + * @param cb The size of the buffer. + */ +RTDECL(char *) RTTimeSpecToString(PCRTTIMESPEC pTime, char *psz, size_t cb); + +/** + * Attempts to convert an ISO date string to a time structure. + * + * We're a little forgiving with zero padding, unspecified parts, and leading + * and trailing spaces. + * + * @retval pTime on success, + * @retval NULL on failure. + * @param pTime The time spec. + * @param pszString The ISO date string to convert. + */ +RTDECL(PRTTIMESPEC) RTTimeSpecFromString(PRTTIMESPEC pTime, const char *pszString); + +/** + * Formats duration as best we can according to ISO-8601, with no fraction. + * + * See RTTimeFormatDurationEx for details. + * + * @returns Number of characters in the output on success. VERR_BUFFER_OVEFLOW + * on failure. + * @param pszDst Pointer to the output buffer. In case of overflow, + * the max number of characters will be written and + * zero terminated, provided @a cbDst isn't zero. + * @param cbDst The size of the output buffer. + * @param pDuration The duration to format. + */ +RTDECL(int) RTTimeFormatDuration(char *pszDst, size_t cbDst, PCRTTIMESPEC pDuration); + +/** + * Formats duration as best we can according to ISO-8601. + * + * The returned value is on the form "[-]PnnnnnWnDTnnHnnMnn.fffffffffS", where a + * sequence of 'n' can be between 1 and the given lenght, and all but the + * "nn.fffffffffS" part is optional and will only be outputted when the duration + * is sufficiently large. The code currently does not omit any inbetween + * elements other than the day count (D), so an exactly 7 day duration is + * formatted as "P1WT0H0M0.000000000S" when @a cFractionDigits is 9. + * + * @returns Number of characters in the output on success. VERR_BUFFER_OVEFLOW + * on failure. + * @retval VERR_OUT_OF_RANGE if @a cFractionDigits is too large. + * @param pszDst Pointer to the output buffer. In case of overflow, + * the max number of characters will be written and + * zero terminated, provided @a cbDst isn't zero. + * @param cbDst The size of the output buffer. + * @param pDuration The duration to format. + * @param cFractionDigits Number of digits in the second fraction part. Zero + * for whole no fraction. Max is 9 (nano seconds). + */ +RTDECL(ssize_t) RTTimeFormatDurationEx(char *pszDst, size_t cbDst, PCRTTIMESPEC pDuration, uint32_t cFractionDigits); + +/** Max length of a RTTimeFormatDurationEx output string. */ +#define RTTIME_DURATION_STR_LEN (sizeof("-P99999W7D23H59M59.123456789S") + 2) + +/** @} */ + + +/** + * Exploded time. + */ +typedef struct RTTIME +{ + /** The year number. */ + int32_t i32Year; + /** The month of the year (1-12). January is 1. */ + uint8_t u8Month; + /** The day of the week (0-6). Monday is 0. */ + uint8_t u8WeekDay; + /** The day of the year (1-366). January the 1st is 1. */ + uint16_t u16YearDay; + /** The day of the month (1-31). */ + uint8_t u8MonthDay; + /** Hour of the day (0-23). */ + uint8_t u8Hour; + /** The minute of the hour (0-59). */ + uint8_t u8Minute; + /** The second of the minute (0-60). + * (u32Nanosecond / 1000000) */ + uint8_t u8Second; + /** The nanoseconds of the second (0-999999999). */ + uint32_t u32Nanosecond; + /** Flags, of the RTTIME_FLAGS_* \#defines. */ + uint32_t fFlags; + /** UTC time offset in minutes (-840-840). Positive for timezones east of + * UTC, negative for zones to the west. Same as what RTTimeLocalDeltaNano + * & RTTimeLocalDeltaNanoFor returns, just different unit. */ + int32_t offUTC; +} RTTIME; +AssertCompileSize(RTTIME, 24); +/** Pointer to a exploded time structure. */ +typedef RTTIME *PRTTIME; +/** Pointer to a const exploded time structure. */ +typedef const RTTIME *PCRTTIME; + +/** @name RTTIME::fFlags values. + * @{ */ +/** Set if the time is UTC. If clear the time local time. */ +#define RTTIME_FLAGS_TYPE_MASK 3 +/** the time is UTC time. */ +#define RTTIME_FLAGS_TYPE_UTC 2 +/** The time is local time. */ +#define RTTIME_FLAGS_TYPE_LOCAL 3 + +/** Set if the time is local and daylight saving time is in effect. + * Not bit is not valid if RTTIME_FLAGS_NO_DST_DATA is set. */ +#define RTTIME_FLAGS_DST RT_BIT(4) +/** Set if the time is local and there is no data available on daylight saving time. */ +#define RTTIME_FLAGS_NO_DST_DATA RT_BIT(5) +/** Set if the year is a leap year. + * This is mutual exclusiv with RTTIME_FLAGS_COMMON_YEAR. */ +#define RTTIME_FLAGS_LEAP_YEAR RT_BIT(6) +/** Set if the year is a common year. + * This is mutual exclusiv with RTTIME_FLAGS_LEAP_YEAR. */ +#define RTTIME_FLAGS_COMMON_YEAR RT_BIT(7) +/** The mask of valid flags. */ +#define RTTIME_FLAGS_MASK UINT32_C(0xff) +/** @} */ + + +/** + * Gets the current system time (UTC). + * + * @returns pTime. + * @param pTime Where to store the time. + */ +RTDECL(PRTTIMESPEC) RTTimeNow(PRTTIMESPEC pTime); + +/** + * Sets the system time. + * + * @returns IPRT status code + * @param pTime The new system time (UTC). + * + * @remarks This will usually fail because changing the wall time is usually + * requires extra privileges. + */ +RTDECL(int) RTTimeSet(PCRTTIMESPEC pTime); + +/** + * Explodes a time spec (UTC). + * + * @returns pTime. + * @param pTime Where to store the exploded time. + * @param pTimeSpec The time spec to exploded. + */ +RTDECL(PRTTIME) RTTimeExplode(PRTTIME pTime, PCRTTIMESPEC pTimeSpec); + +/** + * Implodes exploded time to a time spec (UTC). + * + * @returns pTime on success. + * @returns NULL if the pTime data is invalid. + * @param pTimeSpec Where to store the imploded UTC time. + * If pTime specifies a time which outside the range, maximum or + * minimum values will be returned. + * @param pTime Pointer to the exploded time to implode. + * The fields u8Month, u8WeekDay and u8MonthDay are not used, + * and all the other fields are expected to be within their + * bounds. Use RTTimeNormalize() to calculate u16YearDay and + * normalize the ranges of the fields. + */ +RTDECL(PRTTIMESPEC) RTTimeImplode(PRTTIMESPEC pTimeSpec, PCRTTIME pTime); + +/** + * Normalizes the fields of a time structure. + * + * It is possible to calculate year-day from month/day and vice + * versa. If you adjust any of of these, make sure to zero the + * other so you make it clear which of the fields to use. If + * it's ambiguous, the year-day field is used (and you get + * assertions in debug builds). + * + * All the time fields and the year-day or month/day fields will + * be adjusted for overflows. (Since all fields are unsigned, there + * is no underflows.) It is possible to exploit this for simple + * date math, though the recommended way of doing that to implode + * the time into a timespec and do the math on that. + * + * @returns pTime on success. + * @returns NULL if the data is invalid. + * + * @param pTime The time structure to normalize. + * + * @remarks This function doesn't work with local time, only with UTC time. + */ +RTDECL(PRTTIME) RTTimeNormalize(PRTTIME pTime); + +/** + * Gets the current local system time. + * + * @returns pTime. + * @param pTime Where to store the local time. + */ +RTDECL(PRTTIMESPEC) RTTimeLocalNow(PRTTIMESPEC pTime); + +/** + * Gets the current delta between UTC and local time. + * + * @code + * RTTIMESPEC LocalTime; + * RTTimeSpecAddNano(RTTimeNow(&LocalTime), RTTimeLocalDeltaNano()); + * @endcode + * + * @returns Returns the nanosecond delta between UTC and local time. + */ +RTDECL(int64_t) RTTimeLocalDeltaNano(void); + +/** + * Gets the delta between UTC and local time at the given time. + * + * @code + * RTTIMESPEC LocalTime; + * RTTimeNow(&LocalTime); + * RTTimeSpecAddNano(&LocalTime, RTTimeLocalDeltaNanoFor(&LocalTime)); + * @endcode + * + * @param pTimeSpec The time spec giving the time to get the delta for. + * @returns Returns the nanosecond delta between UTC and local time. + */ +RTDECL(int64_t) RTTimeLocalDeltaNanoFor(PCRTTIMESPEC pTimeSpec); + +/** + * Explodes a time spec to the localized timezone. + * + * @returns pTime. + * @param pTime Where to store the exploded time. + * @param pTimeSpec The time spec to exploded (UTC). + */ +RTDECL(PRTTIME) RTTimeLocalExplode(PRTTIME pTime, PCRTTIMESPEC pTimeSpec); + +/** + * Normalizes the fields of a time structure containing local time. + * + * See RTTimeNormalize for details. + * + * @returns pTime on success. + * @returns NULL if the data is invalid. + * @param pTime The time structure to normalize. + */ +RTDECL(PRTTIME) RTTimeLocalNormalize(PRTTIME pTime); + +/** + * Converts a time structure to UTC, relying on UTC offset information + * if it contains local time. + * + * @returns pTime on success. + * @returns NULL if the data is invalid. + * @param pTime The time structure to convert. + */ +RTDECL(PRTTIME) RTTimeConvertToZulu(PRTTIME pTime); + +/** + * Converts a time spec to a ISO date string. + * + * @returns psz on success. + * @returns NULL on buffer underflow. + * @param pTime The time. Caller should've normalized this. + * @param psz Where to store the string. + * @param cb The size of the buffer. + */ +RTDECL(char *) RTTimeToString(PCRTTIME pTime, char *psz, size_t cb); + +/** + * Converts a time spec to a ISO date string, extended version. + * + * @returns Output string length on success (positive), VERR_BUFFER_OVERFLOW + * (negative) or VERR_OUT_OF_RANGE (negative) on failure. + * @param pTime The time. Caller should've normalized this. + * @param psz Where to store the string. + * @param cb The size of the buffer. + * @param cFractionDigits Number of digits in the fraction. Max is 9. + */ +RTDECL(ssize_t) RTTimeToStringEx(PCRTTIME pTime, char *psz, size_t cb, unsigned cFractionDigits); + +/** Suggested buffer length for RTTimeToString and RTTimeToStringEx output, including terminator. */ +#define RTTIME_STR_LEN 40 + +/** + * Attempts to convert an ISO date string to a time structure. + * + * We're a little forgiving with zero padding, unspecified parts, and leading + * and trailing spaces. + * + * @retval pTime on success, + * @retval NULL on failure. + * @param pTime Where to store the time on success. + * @param pszString The ISO date string to convert. + */ +RTDECL(PRTTIME) RTTimeFromString(PRTTIME pTime, const char *pszString); + +/** + * Formats the given time on a RTC-2822 compliant format. + * + * @returns Output string length on success (positive), VERR_BUFFER_OVERFLOW + * (negative) on failure. + * @param pTime The time. Caller should've normalized this. + * @param psz Where to store the string. + * @param cb The size of the buffer. + * @param fFlags RTTIME_RFC2822_F_XXX + * @sa RTTIME_RFC2822_LEN + */ +RTDECL(ssize_t) RTTimeToRfc2822(PRTTIME pTime, char *psz, size_t cb, uint32_t fFlags); + +/** Suggested buffer length for RTTimeToRfc2822 output, including terminator. */ +#define RTTIME_RFC2822_LEN 40 +/** @name RTTIME_RFC2822_F_XXX + * @{ */ +/** Use the deprecated GMT timezone instead of +/-0000. + * This is required by the HTTP RFC-7231 7.1.1.1. */ +#define RTTIME_RFC2822_F_GMT RT_BIT_32(0) +/** @} */ + +/** + * Attempts to convert an RFC-2822 date string to a time structure. + * + * We're a little forgiving with zero padding, unspecified parts, and leading + * and trailing spaces. + * + * @retval pTime on success, + * @retval NULL on failure. + * @param pTime Where to store the time on success. + * @param pszString The ISO date string to convert. + */ +RTDECL(PRTTIME) RTTimeFromRfc2822(PRTTIME pTime, const char *pszString); + +/** + * Checks if a year is a leap year or not. + * + * @returns true if it's a leap year. + * @returns false if it's a common year. + * @param i32Year The year in question. + */ +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. + */ +RTDECL(uint64_t) RTTimeNanoTS(void); + +/** + * Gets the current millisecond timestamp. + * + * @returns millisecond timestamp. + */ +RTDECL(uint64_t) RTTimeMilliTS(void); + +/** + * Debugging the time api. + * + * @returns the number of 1ns steps which has been applied by RTTimeNanoTS(). + */ +RTDECL(uint32_t) RTTimeDbgSteps(void); + +/** + * Debugging the time api. + * + * @returns the number of times the TSC interval expired RTTimeNanoTS(). + */ +RTDECL(uint32_t) RTTimeDbgExpired(void); + +/** + * Debugging the time api. + * + * @returns the number of bad previous values encountered by RTTimeNanoTS(). + */ +RTDECL(uint32_t) RTTimeDbgBad(void); + +/** + * Debugging the time api. + * + * @returns the number of update races in RTTimeNanoTS(). + */ +RTDECL(uint32_t) RTTimeDbgRaces(void); + + +RTDECL(const char *) RTTimeNanoTSWorkerName(void); + + +/** @name RTTimeNanoTS GIP worker functions, for TM. + * @{ */ + +/** Extra info optionally returned by the RTTimeNanoTS GIP workers. */ +typedef struct RTITMENANOTSEXTRA +{ + /** The TSC value used (delta adjusted). */ + uint64_t uTSCValue; +} RTITMENANOTSEXTRA; +/** Pointer to extra info optionally returned by the RTTimeNanoTS GIP workers. */ +typedef RTITMENANOTSEXTRA *PRTITMENANOTSEXTRA; + +/** Pointer to a RTTIMENANOTSDATA structure. */ +typedef struct RTTIMENANOTSDATA *PRTTIMENANOTSDATA; + +/** + * Nanosecond timestamp data. + * + * This is used to keep track of statistics and callback so IPRT + * and TM (VirtualBox) can share code. + * + * @remark Keep this in sync with the assembly version in timesupA.asm. + */ +typedef struct RTTIMENANOTSDATA +{ + /** Where the previous timestamp is stored. + * This is maintained to ensure that time doesn't go backwards or anything. */ + uint64_t volatile *pu64Prev; + + /** + * Helper function that's used by the assembly routines when something goes bust. + * + * @param pData Pointer to this structure. + * @param u64NanoTS The calculated nano ts. + * @param u64DeltaPrev The delta relative to the previously returned timestamp. + * @param u64PrevNanoTS The previously returned timestamp (as it was read it). + */ + DECLCALLBACKMEMBER(void, pfnBad,(PRTTIMENANOTSDATA pData, uint64_t u64NanoTS, uint64_t u64DeltaPrev, uint64_t u64PrevNanoTS)); + + /** + * Callback for when rediscovery is required. + * + * @returns Nanosecond timestamp. + * @param pData Pointer to this structure. + * @param pExtra Where to return extra time info. Optional. + */ + DECLCALLBACKMEMBER(uint64_t, pfnRediscover,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra)); + + /** + * Callback for when some CPU index related stuff goes wrong. + * + * @returns Nanosecond timestamp. + * @param pData Pointer to this structure. + * @param pExtra Where to return extra time info. Optional. + * @param idApic The APIC ID if available, otherwise (UINT16_MAX-1). + * @param iCpuSet The CPU set index if available, otherwise + * (UINT16_MAX-1). + * @param iGipCpu The GIP CPU array index if available, otherwise + * (UINT16_MAX-1). + */ + DECLCALLBACKMEMBER(uint64_t, pfnBadCpuIndex,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra, + uint16_t idApic, uint16_t iCpuSet, uint16_t iGipCpu)); + + /** Number of 1ns steps because of overshooting the period. */ + uint32_t c1nsSteps; + /** The number of times the interval expired (overflow). */ + uint32_t cExpired; + /** Number of "bad" previous values. */ + uint32_t cBadPrev; + /** The number of update races. */ + uint32_t cUpdateRaces; +} RTTIMENANOTSDATA; + +#ifndef IN_RING3 +/** + * The Ring-3 layout of the RTTIMENANOTSDATA structure. + */ +typedef struct RTTIMENANOTSDATAR3 +{ + R3PTRTYPE(uint64_t volatile *) pu64Prev; + DECLR3CALLBACKMEMBER(void, pfnBad,(PRTTIMENANOTSDATA pData, uint64_t u64NanoTS, uint64_t u64DeltaPrev, uint64_t u64PrevNanoTS)); + DECLR3CALLBACKMEMBER(uint64_t, pfnRediscover,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra)); + DECLR3CALLBACKMEMBER(uint64_t, pfnBadCpuIndex,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra, + uint16_t idApic, uint16_t iCpuSet, uint16_t iGipCpu)); + uint32_t c1nsSteps; + uint32_t cExpired; + uint32_t cBadPrev; + uint32_t cUpdateRaces; +} RTTIMENANOTSDATAR3; +#else +typedef RTTIMENANOTSDATA RTTIMENANOTSDATAR3; +#endif + +#ifndef IN_RING0 +/** + * The Ring-3 layout of the RTTIMENANOTSDATA structure. + */ +typedef struct RTTIMENANOTSDATAR0 +{ + R0PTRTYPE(uint64_t volatile *) pu64Prev; + DECLR0CALLBACKMEMBER(void, pfnBad,(PRTTIMENANOTSDATA pData, uint64_t u64NanoTS, uint64_t u64DeltaPrev, uint64_t u64PrevNanoTS)); + DECLR0CALLBACKMEMBER(uint64_t, pfnRediscover,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra)); + DECLR0CALLBACKMEMBER(uint64_t, pfnBadCpuIndex,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra, + uint16_t idApic, uint16_t iCpuSet, uint16_t iGipCpu)); + uint32_t c1nsSteps; + uint32_t cExpired; + uint32_t cBadPrev; + uint32_t cUpdateRaces; +} RTTIMENANOTSDATAR0; +#else +typedef RTTIMENANOTSDATA RTTIMENANOTSDATAR0; +#endif + +#ifndef IN_RC +/** + * The RC layout of the RTTIMENANOTSDATA structure. + */ +typedef struct RTTIMENANOTSDATARC +{ + RCPTRTYPE(uint64_t volatile *) pu64Prev; + DECLRCCALLBACKMEMBER(void, pfnBad,(PRTTIMENANOTSDATA pData, uint64_t u64NanoTS, uint64_t u64DeltaPrev, uint64_t u64PrevNanoTS)); + DECLRCCALLBACKMEMBER(uint64_t, pfnRediscover,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra)); + DECLRCCALLBACKMEMBER(uint64_t, pfnBadCpuIndex,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra, + uint16_t idApic, uint16_t iCpuSet, uint16_t iGipCpu)); + uint32_t c1nsSteps; + uint32_t cExpired; + uint32_t cBadPrev; + uint32_t cUpdateRaces; +} RTTIMENANOTSDATARC; +#else +typedef RTTIMENANOTSDATA RTTIMENANOTSDATARC; +#endif + +/** Internal RTTimeNanoTS worker (assembly). */ +typedef DECLCALLBACKTYPE(uint64_t, FNTIMENANOTSINTERNAL,(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra)); +/** Pointer to an internal RTTimeNanoTS worker (assembly). */ +typedef FNTIMENANOTSINTERNAL *PFNTIMENANOTSINTERNAL; +RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarNoDelta(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarNoDelta(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +#ifdef IN_RING3 +RTDECL(uint64_t) RTTimeNanoTSLegacyAsyncUseApicId(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacyAsyncUseApicIdExt0B(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacyAsyncUseApicIdExt8000001E(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacyAsyncUseRdtscp(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacyAsyncUseRdtscpGroupChNumCl(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacyAsyncUseIdtrLim(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarWithDeltaUseApicId(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt0B(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarWithDeltaUseApicIdExt8000001E(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarWithDeltaUseRdtscp(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarWithDeltaUseIdtrLim(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceAsyncUseApicId(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceAsyncUseApicIdExt0B(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceAsyncUseApicIdExt8000001E(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceAsyncUseRdtscp(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceAsyncUseRdtscpGroupChNumCl(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceAsyncUseIdtrLim(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicId(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt0B(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicIdExt8000001E(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarWithDeltaUseRdtscp(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarWithDeltaUseIdtrLim(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +#else +RTDECL(uint64_t) RTTimeNanoTSLegacyAsync(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarWithDelta(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceAsync(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarWithDelta(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra); +#endif + +/** @} */ + + +/** + * Gets the current nanosecond timestamp. + * + * This differs from RTTimeNanoTS in that it will use system APIs and not do any + * resolution or performance optimizations. + * + * @returns nanosecond timestamp. + */ +RTDECL(uint64_t) RTTimeSystemNanoTS(void); + +/** + * Gets the current millisecond timestamp. + * + * This differs from RTTimeNanoTS in that it will use system APIs and not do any + * resolution or performance optimizations. + * + * @returns millisecond timestamp. + */ +RTDECL(uint64_t) RTTimeSystemMilliTS(void); + +/** + * Get the nanosecond timestamp relative to program startup. + * + * @returns Timestamp relative to program startup. + */ +RTDECL(uint64_t) RTTimeProgramNanoTS(void); + +/** + * Get the microsecond timestamp relative to program startup. + * + * @returns Timestamp relative to program startup. + */ +RTDECL(uint64_t) RTTimeProgramMicroTS(void); + +/** + * Get the millisecond timestamp relative to program startup. + * + * @returns Timestamp relative to program startup. + */ +RTDECL(uint64_t) RTTimeProgramMilliTS(void); + +/** + * Get the second timestamp relative to program startup. + * + * @returns Timestamp relative to program startup. + */ +RTDECL(uint32_t) RTTimeProgramSecTS(void); + +/** + * Get the RTTimeNanoTS() of when the program started. + * + * @returns Program startup timestamp. + */ +RTDECL(uint64_t) RTTimeProgramStartNanoTS(void); + + +/** + * Time zone information. + */ +typedef struct RTTIMEZONEINFO +{ + /** Unix time zone name (continent/country[/city]|). */ + const char *pszUnixName; + /** Windows time zone name. */ + const char *pszWindowsName; + /** The length of the unix time zone name. */ + uint8_t cchUnixName; + /** The length of the windows time zone name. */ + uint8_t cchWindowsName; + /** Two letter country/territory code if applicable, otherwise 'ZZ'. */ + char szCountry[3]; + /** Two letter windows country/territory code if applicable. + * Empty string if no windows mapping. */ + char szWindowsCountry[3]; +#if 0 /* Add when needed and it's been extracted. */ + /** The standard delta in minutes (add to UTC). */ + int16_t cMinStdDelta; + /** The daylight saving time delta in minutes (add to UTC). */ + int16_t cMinDstDelta; +#endif + /** closest matching windows time zone index. */ + uint32_t idxWindows; + /** Flags, RTTIMEZONEINFO_F_XXX. */ + uint32_t fFlags; +} RTTIMEZONEINFO; +/** Pointer to time zone info. */ +typedef RTTIMEZONEINFO const *PCRTTIMEZONEINFO; + +/** @name RTTIMEZONEINFO_F_XXX - time zone info flags. + * @{ */ +/** Indicates golden mapping entry for a windows time zone name. */ +#define RTTIMEZONEINFO_F_GOLDEN RT_BIT_32(0) +/** @} */ + +/** + * Looks up static time zone information by unix name. + * + * @returns Pointer to info entry if found, NULL if not. + * @param pszName The unix zone name (TZ). + */ +RTDECL(PCRTTIMEZONEINFO) RTTimeZoneGetInfoByUnixName(const char *pszName); + +/** + * Looks up static time zone information by window name. + * + * @returns Pointer to info entry if found, NULL if not. + * @param pszName The windows zone name (reg key). + */ +RTDECL(PCRTTIMEZONEINFO) RTTimeZoneGetInfoByWindowsName(const char *pszName); + +/** + * Looks up static time zone information by windows index. + * + * @returns Pointer to info entry if found, NULL if not. + * @param idxZone The windows timezone index. + */ +RTDECL(PCRTTIMEZONEINFO) RTTimeZoneGetInfoByWindowsIndex(uint32_t idxZone); + +/** + * Get the current time zone (TZ). + * + * @returns IPRT status code. + * @param pszName Where to return the time zone name. + * @param cbName The size of the name buffer. + */ +RTDECL(int) RTTimeZoneGetCurrent(char *pszName, size_t cbName); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_time_h */ + diff --git a/include/iprt/timer.h b/include/iprt/timer.h new file mode 100644 index 00000000..8cb34987 --- /dev/null +++ b/include/iprt/timer.h @@ -0,0 +1,400 @@ +/** @file + * IPRT - Timer. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_timer_h +#define IPRT_INCLUDED_timer_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include <iprt/cdefs.h> +#include <iprt/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_timer RTTimer - Timer + * + * The IPRT timer API provides a simple abstraction of recurring and one-shot callback timers. + * + * Because of the great variation in the native APIs and the quality of + * the service delivered by those native APIs, the timers are operated + * on at best effort basis. + * + * All the ring-3 implementations are naturally at the mercy of the scheduler, + * which means that the callback rate might vary quite a bit and we might skip + * ticks. Many systems have a restriction that a process can only have one + * timer. IPRT currently makes no efforts at multiplexing timers in those kind + * of situations and will simply fail if you try to create more than one timer. + * + * Things are generally better in ring-0. The implementations will use interrupt + * time callbacks wherever available, and if not, resort to a high priority + * kernel thread. + * + * @ingroup grp_rt + * @{ + */ + + +/** Timer handle. */ +typedef struct RTTIMER *PRTTIMER; + +/** + * Timer callback function. + * + * The context this call is made in varies with different platforms and + * kernel / user mode IPRT. + * + * In kernel mode a timer callback should not waste time, it shouldn't + * waste stack and it should be prepared that some APIs might not work + * correctly because of weird OS restrictions in this context that we + * haven't discovered and avoided yet. Please fix those APIs so they + * at least avoid panics and weird behaviour. + * + * @param pTimer Timer handle. + * @param pvUser User argument. + * @param iTick The current timer tick. This is always 1 on the first + * callback after the timer was started. For omni timers + * this will be 1 when a cpu comes back online. + */ +typedef DECLCALLBACKTYPE(void, FNRTTIMER,(PRTTIMER pTimer, void *pvUser, uint64_t iTick)); +/** Pointer to FNRTTIMER() function. */ +typedef FNRTTIMER *PFNRTTIMER; + + +/** + * Create a recurring timer. + * + * @returns iprt status code. + * @param ppTimer Where to store the timer handle. + * @param uMilliesInterval Milliseconds between the timer ticks. + * This is rounded up to the system granularity. + * @param pfnTimer Callback function which shall be scheduled for execution + * on every timer tick. + * @param pvUser User argument for the callback. + * @see RTTimerCreateEx, RTTimerStart, RTTimerStop, RTTimerChangeInterval, + * RTTimerDestroy, RTTimerGetSystemGranularity + */ +RTDECL(int) RTTimerCreate(PRTTIMER *ppTimer, unsigned uMilliesInterval, PFNRTTIMER pfnTimer, void *pvUser); + +/** + * Create a suspended timer. + * + * @returns iprt status code. + * @retval VERR_NOT_SUPPORTED if an unsupported flag was specfied. + * @retval VERR_CPU_NOT_FOUND if the specified CPU + * + * @param ppTimer Where to store the timer handle. + * @param u64NanoInterval The interval between timer ticks specified in nanoseconds if it's + * a recurring timer. This is rounded to the fit the system timer granularity. + * For one shot timers, pass 0. + * @param fFlags Timer flags. + * @param pfnTimer Callback function which shall be scheduled for execution + * on every timer tick. + * @param pvUser User argument for the callback. + * @see RTTimerStart, RTTimerStop, RTTimerChangeInterval, RTTimerDestroy, + * RTTimerGetSystemGranularity, RTTimerCanDoHighResolution + */ +RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser); + +/** @name RTTimerCreateEx flags + * @{ */ +/** Any CPU is fine. (Must be 0.) */ +#define RTTIMER_FLAGS_CPU_ANY UINT32_C(0) +/** One specific CPU */ +#define RTTIMER_FLAGS_CPU_SPECIFIC RT_BIT(16) +/** Omni timer, run on all online CPUs. + * @remarks The timer callback isn't necessarily running at the time same time on each CPU. */ +#define RTTIMER_FLAGS_CPU_ALL ( RTTIMER_FLAGS_CPU_MASK | RTTIMER_FLAGS_CPU_SPECIFIC ) +/** CPU mask. */ +#define RTTIMER_FLAGS_CPU_MASK UINT32_C(0xffff) +/** Desire a high resolution timer that works with RTTimerChangeInterval and + * isn't subject to RTTimerGetSystemGranularity rounding. + * @remarks This is quietly ignored if the feature isn't supported. */ +#define RTTIMER_FLAGS_HIGH_RES RT_BIT(17) +/** Convert a CPU set index (0-based) to RTTimerCreateEx flags. + * This will automatically OR in the RTTIMER_FLAGS_CPU_SPECIFIC flag. */ +#define RTTIMER_FLAGS_CPU(iCpu) ( (iCpu) | RTTIMER_FLAGS_CPU_SPECIFIC ) +/** Macro that validates the flags. */ +#define RTTIMER_FLAGS_ARE_VALID(fFlags) \ + ( !((fFlags) & ((fFlags) & RTTIMER_FLAGS_CPU_SPECIFIC ? ~UINT32_C(0x3ffff) : ~UINT32_C(0x30000))) ) +/** @} */ + +/** + * Stops and destroys a running timer. + * + * @returns iprt status code. + * @retval VERR_INVALID_CONTEXT if executing at the wrong IRQL (windows), PIL + * (solaris), or similar. Portable code does not destroy timers with + * preemption (or interrupts) disabled. + * @param pTimer Timer to stop and destroy. NULL is ok. + */ +RTDECL(int) RTTimerDestroy(PRTTIMER pTimer); + +/** + * Starts a suspended timer. + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if pTimer isn't valid. + * @retval VERR_TIMER_ACTIVE if the timer isn't suspended. + * @retval VERR_CPU_OFFLINE if the CPU the timer was created to run on is not + * online (this include the case where it's not present in the + * system). + * + * @param pTimer The timer to activate. + * @param u64First The RTTimeSystemNanoTS() for when the timer should start + * firing (relative). If 0 is specified, the timer will + * fire ASAP. + * @remarks When RTTimerCanDoHighResolution returns true, this API is + * callable with preemption disabled in ring-0. + * @see RTTimerStop + */ +RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First); + +/** + * Stops an active timer. + * + * @todo May return while the timer callback function is being services on + * some platforms (ring-0 Windows, ring-0 linux). This needs to be + * addressed at some point... + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if pTimer isn't valid. + * @retval VERR_TIMER_SUSPENDED if the timer isn't active. + * @retval VERR_NOT_SUPPORTED if the IPRT implementation doesn't support + * stopping a timer. + * + * @param pTimer The timer to suspend. + * @remarks Can be called from the timer callback function to stop it. + * @see RTTimerStart + */ +RTDECL(int) RTTimerStop(PRTTIMER pTimer); + +/** + * Changes the interval of a periodic timer. + * + * If the timer is active, it is implementation dependent whether the change + * takes place immediately or after the next tick. To get defined behavior, + * stop the timer before calling this API. + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if pTimer isn't valid. + * @retval VERR_NOT_SUPPORTED if not supported. + * @retval VERR_INVALID_STATE if not a periodic timer. + * + * @param pTimer The timer to activate. + * @param u64NanoInterval The interval between timer ticks specified in + * nanoseconds. This is rounded to the fit the + * system timer granularity. + * @remarks Callable from the timer callback. Callable with preemption + * disabled in ring-0. + */ +RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval); + +/** + * Gets the (current) timer granularity of the system. + * + * @returns The timer granularity of the system in nanoseconds. + * @see RTTimerRequestSystemGranularity + */ +RTDECL(uint32_t) RTTimerGetSystemGranularity(void); + +/** + * Requests a specific system timer granularity. + * + * Successfull calls to this API must be coupled with the exact same number of + * calls to RTTimerReleaseSystemGranularity() in order to undo any changes made. + * + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the requested value isn't supported by the host platform + * or if the host platform doesn't support modifying the system timer granularity. + * @retval VERR_PERMISSION_DENIED if the caller doesn't have the necessary privilege to + * modify the system timer granularity. + * + * @param u32Request The requested system timer granularity in nanoseconds. + * @param pu32Granted Where to store the granted system granularity. This is the value + * that should be passed to RTTimerReleaseSystemGranularity(). It + * is what RTTimerGetSystemGranularity() would return immediately + * after the change was made. + * + * The value differ from the request in two ways; rounding and + * scale. Meaning if your request is for 10.000.000 you might + * be granted 10.000.055 or 1.000.000. + * @see RTTimerReleaseSystemGranularity, RTTimerGetSystemGranularity + */ +RTDECL(int) RTTimerRequestSystemGranularity(uint32_t u32Request, uint32_t *pu32Granted); + +/** + * Releases a system timer granularity grant acquired by RTTimerRequestSystemGranularity(). + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the host platform doesn't have any way of modifying + * the system timer granularity. + * @retval VERR_WRONG_ORDER if nobody call RTTimerRequestSystemGranularity() with the + * given grant value. + * @param u32Granted The granted system granularity. + * @see RTTimerRequestSystemGranularity + */ +RTDECL(int) RTTimerReleaseSystemGranularity(uint32_t u32Granted); + +/** + * Checks if the system support high resolution timers. + * + * The kind of support we are checking for is the kind of dynamically + * reprogrammable timers employed by recent Solaris and Linux kernels. It also + * implies that we can specify microsecond (or even better maybe) intervals + * without getting into trouble. + * + * @returns true if supported, false it not. + * + * @remarks Returning true also means RTTimerChangeInterval must be implemented + * and RTTimerStart be callable with preemption disabled. + */ +RTDECL(bool) RTTimerCanDoHighResolution(void); + + +/** + * Timer callback function for low res timers. + * + * This is identical to FNRTTIMER except for the first parameter, so + * see FNRTTIMER for details. + * + * @param hTimerLR The low resolution timer handle. + * @param pvUser User argument. + * @param iTick The current timer tick. This is always 1 on the first + * callback after the timer was started. Will jump if we've + * skipped ticks when lagging behind. + */ +typedef DECLCALLBACKTYPE(void, FNRTTIMERLR,(RTTIMERLR hTimerLR, void *pvUser, uint64_t iTick)); +/** Pointer to FNRTTIMER() function. */ +typedef FNRTTIMERLR *PFNRTTIMERLR; + + +/** + * Create a recurring low resolution timer. + * + * @returns iprt status code. + * @param phTimerLR Where to store the timer handle. + * @param uMilliesInterval Milliseconds between the timer ticks, at least 100 ms. + * If higher resolution is required use the other API. + * @param pfnTimer Callback function which shall be scheduled for execution + * on every timer tick. + * @param pvUser User argument for the callback. + * @see RTTimerLRCreateEx, RTTimerLRDestroy, RTTimerLRStop + */ +RTDECL(int) RTTimerLRCreate(PRTTIMERLR phTimerLR, uint32_t uMilliesInterval, PFNRTTIMERLR pfnTimer, void *pvUser); + +/** + * Create a suspended low resolution timer. + * + * @returns iprt status code. + * @retval VERR_NOT_SUPPORTED if an unsupported flag was specfied. + * + * @param phTimerLR Where to store the timer handle. + * @param u64NanoInterval The interval between timer ticks specified in nanoseconds if it's + * a recurring timer, the minimum for is 100000000 ns. + * For one shot timers, pass 0. + * @param fFlags Timer flags. Same as RTTimerCreateEx. + * @param pfnTimer Callback function which shall be scheduled for execution + * on every timer tick. + * @param pvUser User argument for the callback. + * @see RTTimerLRStart, RTTimerLRStop, RTTimerLRDestroy + */ +RTDECL(int) RTTimerLRCreateEx(PRTTIMERLR phTimerLR, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMERLR pfnTimer, void *pvUser); + +/** + * Stops and destroys a running low resolution timer. + * + * @returns iprt status code. + * @param hTimerLR The low resolution timer to stop and destroy. + * NIL_RTTIMERLR is accepted. + */ +RTDECL(int) RTTimerLRDestroy(RTTIMERLR hTimerLR); + +/** + * Starts a low resolution timer. + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if pTimer isn't valid. + * @retval VERR_TIMER_ACTIVE if the timer isn't suspended. + * + * @param hTimerLR The low resolution timer to activate. + * @param u64First The RTTimeSystemNanoTS() for when the timer should start + * firing (relative), the minimum is 100000000 ns. + * If 0 is specified, the timer will fire ASAP. + * + * @see RTTimerLRStop + */ +RTDECL(int) RTTimerLRStart(RTTIMERLR hTimerLR, uint64_t u64First); + +/** + * Stops an active low resolution timer. + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if pTimer isn't valid. + * @retval VERR_TIMER_SUSPENDED if the timer isn't active. + * @retval VERR_NOT_SUPPORTED if the IPRT implementation doesn't support stopping a timer. + * + * @param hTimerLR The low resolution timer to suspend. + * + * @see RTTimerLRStart + */ +RTDECL(int) RTTimerLRStop(RTTIMERLR hTimerLR); + +/** + * Changes the interval of a low resolution timer. + * + * If the timer is active, the next tick will occure immediately just like with + * RTTimerLRStart() when u64First parameter is zero. + * + * @returns IPRT status code. + * @retval VERR_INVALID_HANDLE if pTimer isn't valid. + * @retval VERR_NOT_SUPPORTED if not supported. + * + * @param hTimerLR The low resolution timer to update. + * @param u64NanoInterval The interval between timer ticks specified in + * nanoseconds. This is rounded to the fit the + * system timer granularity. + * @remarks Callable from the timer callback. + */ +RTDECL(int) RTTimerLRChangeInterval(RTTIMERLR hTimerLR, uint64_t u64NanoInterval); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_timer_h */ diff --git a/include/iprt/tpm.h b/include/iprt/tpm.h new file mode 100644 index 00000000..04cd475e --- /dev/null +++ b/include/iprt/tpm.h @@ -0,0 +1,156 @@ +/** @file + * IPRT Trusted Platform Module API abstracting host specific APIs. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_tpm_h +#define IPRT_INCLUDED_tpm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +#include <iprt/formats/tpm.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_tpm IPRT Trusted Platform Module API + * @ingroup grp_rt + * + * This API provides a uniform way to access a Trusted Platform Module across all + * supported hosts. + * + * @{ + */ + + +/** + * TPM version. + */ +typedef enum RTTPMVERSION +{ + /** The usual invalid option. */ + RTTPMVERSION_INVALID = 0, + /** TPM conforms to version 1.2 of the TCG specification. */ + RTTPMVERSION_1_2, + /** TPM conforms to version 2.0 of the TCG specification. */ + RTTPMVERSION_2_0, + /** TPM version couldn't be acquired. */ + RTTPMVERSION_UNKNOWN, + /** Usual 32bit hack. */ + RTTPMVERSION_32BIT_HACK = 0x7fffffff +} RTTPMVERSION; +/** Pointer to a TPM version. */ +typedef RTTPMVERSION *PRTTPMVERSION; + +/** TPM handle. */ +typedef struct RTTPMINT *RTTPM; +/** Pointer to a TPM handle. */ +typedef RTTPM *PRTTPM; +/** NIL TPM handle value. */ +#define NIL_RTTPM ((RTTPM)0) + + +/** Default TPM of the host. */ +#define RTTPM_ID_DEFAULT UINT32_C(0xffffffff) + +/** + * Tries to open the given TPM returning a handle. + * + * @returns IPRT status code. + * @param phTpm Where to store the handle to the TPM module on success. + * @param idTpm The TPM to open, use RTTPM_ID_DEFAULT for the default TPM of the system. + */ +RTDECL(int) RTTpmOpen(PRTTPM phTpm, uint32_t idTpm); + + +/** + * Closes the given TPM handle freeing all allocated resources. + * + * @returns IPRT status code. + * @param hTpm Handle of the TPM to close. + */ +RTDECL(int) RTTpmClose(RTTPM hTpm); + + +/** + * Returns the version of the TPM for the given handle. + * + * @returns Version implemented by the TPM. + * @param hTpm Handle of the TPM. + */ +RTDECL(RTTPMVERSION) RTTpmGetVersion(RTTPM hTpm); + + +/** + * Returns the maximum locality supported by the given TPM. + * + * @returns Maximum locality supported (0-4). + * @param hTpm Handle of the TPM. + */ +RTDECL(uint32_t) RTTpmGetLocalityMax(RTTPM hTpm); + + +/** + * Cancels a currently executed request for the given TPM handle. + * + * @returns IPRT status code. + * @param hTpm Handle of the TPM. + */ +RTDECL(int) RTTpmReqCancel(RTTPM hTpm); + + +/** + * Executes the given request on the given TPM handle. + * + * @returns IPRT status code. + * @param hTpm Handle of the TPM. + * @param bLoc The locality to use (only 0 might be supported on some hosts). + * @param pvReq The request data. + * @param cbReq Size of the request in bytes. + * @param pvResp Where to store the response data. + * @param cbRespMax Size of the response buffer. + * @param pcbResp Where to store the actual size of the response, optional. + */ +RTDECL(int) RTTpmReqExec(RTTPM hTpm, uint8_t bLoc, const void *pvReq, size_t cbReq, + void *pvResp, size_t cbRespMax, size_t *pcbResp); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_tpm_h */ + diff --git a/include/iprt/trace.h b/include/iprt/trace.h new file mode 100644 index 00000000..32341d15 --- /dev/null +++ b/include/iprt/trace.h @@ -0,0 +1,228 @@ +/** @file + * IPRT - Tracing. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_trace_h +#define IPRT_INCLUDED_trace_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/stdarg.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_trace RTTrace - Tracing + * @ingroup grp_rt + * + * The tracing facility is somewhat similar to a stripped down logger that + * outputs to a circular buffer. Part of the idea here is that it can the + * overhead is much smaller and that it can be done without involving any + * locking or other thing that could throw off timing. + * + * @{ + */ + + +#ifdef DOXYGEN_RUNNING +# define RTTRACE_DISABLED +# define RTTRACE_ENABLED +#endif + +/** @def RTTRACE_DISABLED + * Use this compile time define to disable all tracing macros. This trumps + * RTTRACE_ENABLED. + */ + +/** @def RTTRACE_ENABLED + * Use this compile time define to enable tracing when not in debug mode + */ + +/* + * Determine whether tracing is enabled and forcefully normalize the indicators. + */ +#if (defined(DEBUG) || defined(RTTRACE_ENABLED)) && !defined(RTTRACE_DISABLED) +# undef RTTRACE_DISABLED +# undef RTTRACE_ENABLED +# define RTTRACE_ENABLED +#else +# undef RTTRACE_DISABLED +# undef RTTRACE_ENABLED +# define RTTRACE_DISABLED +#endif + + +/** @name RTTRACEBUF_FLAGS_XXX - RTTraceBufCarve and RTTraceBufCreate flags. + * @{ */ +/** Free the memory block on release using RTMemFree(). */ +#define RTTRACEBUF_FLAGS_FREE_ME RT_BIT_32(0) +/** Whether the trace buffer is disabled or enabled. */ +#define RTTRACEBUF_FLAGS_DISABLED RT_BIT_32(RTTRACEBUF_FLAGS_DISABLED_BIT) +/** The bit number corresponding to the RTTRACEBUF_FLAGS_DISABLED mask. */ +#define RTTRACEBUF_FLAGS_DISABLED_BIT 1 +/** Mask of the valid flags. */ +#define RTTRACEBUF_FLAGS_MASK UINT32_C(0x00000003) +/** @} */ + + +RTDECL(int) RTTraceBufCreate(PRTTRACEBUF hTraceBuf, uint32_t cEntries, uint32_t cbEntry, uint32_t fFlags); +RTDECL(int) RTTraceBufCarve(PRTTRACEBUF hTraceBuf, uint32_t cEntries, uint32_t cbEntry, uint32_t fFlags, + void *pvBlock, size_t *pcbBlock); +RTDECL(uint32_t) RTTraceBufRetain(RTTRACEBUF hTraceBuf); +RTDECL(uint32_t) RTTraceBufRelease(RTTRACEBUF hTraceBuf); +RTDECL(int) RTTraceBufDumpToLog(RTTRACEBUF hTraceBuf); +RTDECL(int) RTTraceBufDumpToAssert(RTTRACEBUF hTraceBuf); + +/** + * Trace buffer callback for processing one entry. + * + * Used by RTTraceBufEnumEntries. + * + * @returns IPRT status code. Any status code but VINF_SUCCESS will abort the + * enumeration and be returned by RTTraceBufEnumEntries. + * @param hTraceBuf The trace buffer handle. + * @param iEntry The entry number. + * @param NanoTS The timestamp of the entry. + * @param idCpu The ID of the CPU which added the entry. + * @param pszMsg The message text. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTTRACEBUFCALLBACK,(RTTRACEBUF hTraceBuf, uint32_t iEntry, uint64_t NanoTS, + RTCPUID idCpu, const char *pszMsg, void *pvUser)); +/** Pointer to trace buffer enumeration callback function. */ +typedef FNRTTRACEBUFCALLBACK *PFNRTTRACEBUFCALLBACK; + +/** + * Enumerates the used trace buffer entries, calling @a pfnCallback for each. + * + * @returns IPRT status code. Should the callback (@a pfnCallback) return + * anything other than VINF_SUCCESS, then the enumeration will be + * aborted and the status code will be returned by this function. + * @retval VINF_SUCCESS + * @retval VERR_INVALID_HANDLE + * @retval VERR_INVALID_PARAMETER + * @retval VERR_INVALID_POINTER + * + * @param hTraceBuf The trace buffer handle. Special handles are + * accepted. + * @param pfnCallback The callback to call for each entry. + * @param pvUser The user argument for the callback. + */ +RTDECL(int) RTTraceBufEnumEntries(RTTRACEBUF hTraceBuf, PFNRTTRACEBUFCALLBACK pfnCallback, void *pvUser); + +/** + * Gets the entry size used by the specified trace buffer. + * + * @returns The size on success, 0 if the handle is invalid. + * + * @param hTraceBuf The trace buffer handle. Special handles are + * accepted. + */ +RTDECL(uint32_t) RTTraceBufGetEntrySize(RTTRACEBUF hTraceBuf); + +/** + * Gets the number of entries in the specified trace buffer. + * + * @returns The entry count on success, 0 if the handle is invalid. + * + * @param hTraceBuf The trace buffer handle. Special handles are + * accepted. + */ +RTDECL(uint32_t) RTTraceBufGetEntryCount(RTTRACEBUF hTraceBuf); + + +/** + * Disables tracing. + * + * @returns @c true if tracing was enabled prior to this call, @c false if + * disabled already. + * + * @param hTraceBuf The trace buffer handle. Special handles are + * accepted. + */ +RTDECL(bool) RTTraceBufDisable(RTTRACEBUF hTraceBuf); + +/** + * Enables tracing. + * + * @returns @c true if tracing was enabled prior to this call, @c false if + * disabled already. + * + * @param hTraceBuf The trace buffer handle. Special handles are + * accepted. + */ +RTDECL(bool) RTTraceBufEnable(RTTRACEBUF hTraceBuf); + + +RTDECL(int) RTTraceBufAddMsg( RTTRACEBUF hTraceBuf, const char *pszMsg); +RTDECL(int) RTTraceBufAddMsgF( RTTRACEBUF hTraceBuf, const char *pszMsgFmt, ...) RT_IPRT_FORMAT_ATTR(2, 3); +RTDECL(int) RTTraceBufAddMsgV( RTTRACEBUF hTraceBuf, const char *pszMsgFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); +RTDECL(int) RTTraceBufAddMsgEx( RTTRACEBUF hTraceBuf, const char *pszMsg, size_t cbMaxMsg); + +RTDECL(int) RTTraceBufAddPos( RTTRACEBUF hTraceBuf, RT_SRC_POS_DECL); +RTDECL(int) RTTraceBufAddPosMsg( RTTRACEBUF hTraceBuf, RT_SRC_POS_DECL, const char *pszMsg); +RTDECL(int) RTTraceBufAddPosMsgEx( RTTRACEBUF hTraceBuf, RT_SRC_POS_DECL, const char *pszMsg, size_t cbMaxMsg); +RTDECL(int) RTTraceBufAddPosMsgF( RTTRACEBUF hTraceBuf, RT_SRC_POS_DECL, const char *pszMsgFmt, ...) RT_IPRT_FORMAT_ATTR(5, 6); +RTDECL(int) RTTraceBufAddPosMsgV( RTTRACEBUF hTraceBuf, RT_SRC_POS_DECL, const char *pszMsgFmt, va_list va) RT_IPRT_FORMAT_ATTR(5, 0); + + +RTDECL(int) RTTraceSetDefaultBuf(RTTRACEBUF hTraceBuf); +RTDECL(RTTRACEBUF) RTTraceGetDefaultBuf(void); + + +/** @def RTTRACE_BUF + * The trace buffer used by the macros. + */ +#ifndef RTTRACE_BUF +# define RTTRACE_BUF NULL +#endif + +/** + * Record the current source position. + */ +#ifdef RTTRACE_ENABLED +# define RTTRACE_POS() do { RTTraceBufAddPos(RTTRACE_BUF, RT_SRC_POS); } while (0) +#else +# define RTTRACE_POS() do { } while (0) +#endif + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_trace_h */ + diff --git a/include/iprt/tracelog.h b/include/iprt/tracelog.h new file mode 100644 index 00000000..61ae41c0 --- /dev/null +++ b/include/iprt/tracelog.h @@ -0,0 +1,706 @@ +/** @file + * IPRT - Binary trace log API. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_tracelog_h +#define IPRT_INCLUDED_tracelog_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/sg.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_tracelog RTTraceLog - Binary trace log API + * @ingroup grp_rt + * @{ + */ + +/** + * Trace log item type. + */ +typedef enum RTTRACELOGTYPE +{ + /** Invalid first value. */ + RTTRACELOGTYPE_INVALID = 0, + /** Boolean item type. */ + RTTRACELOGTYPE_BOOL, + /** Unsigned 8bit integer type. */ + RTTRACELOGTYPE_UINT8, + /** Signed 8bit integer type. */ + RTTRACELOGTYPE_INT8, + /** Unsigned 16bit integer type. */ + RTTRACELOGTYPE_UINT16, + /** Signed 16bit integer type. */ + RTTRACELOGTYPE_INT16, + /** Unsigned 32bit integer type. */ + RTTRACELOGTYPE_UINT32, + /** Signed 32bit integer type. */ + RTTRACELOGTYPE_INT32, + /** Unsigned 64bit integer type. */ + RTTRACELOGTYPE_UINT64, + /** Signed 64bit integer type. */ + RTTRACELOGTYPE_INT64, + /** 32bit floating point type. */ + RTTRACELOGTYPE_FLOAT32, + /** 64bit floating point type. */ + RTTRACELOGTYPE_FLOAT64, + /** Raw binary data type. */ + RTTRACELOGTYPE_RAWDATA, + /** Pointer data type. */ + RTTRACELOGTYPE_POINTER, + /** size_t data type. */ + RTTRACELOGTYPE_SIZE, + /** 32-bit hack. */ + RTTRACELOGTYPE_32BIT_HACK = 0x7fffffff +} RTTRACELOGTYPE; +/** Pointer to a trace log item type. */ +typedef RTTRACELOGTYPE *PRTTRACELOGTYPE; +/** Pointer to a const trace log item type. */ +typedef const RTTRACELOGTYPE *PCRTTRACELOGTYPE; + + +/** + * Trace log event severity. + */ +typedef enum RTTRACELOGEVTSEVERITY +{ + /** Invalid severity. */ + RTTRACELOGEVTSEVERITY_INVALID = 0, + /** Informational event. */ + RTTRACELOGEVTSEVERITY_INFO, + /** Warning event. */ + RTTRACELOGEVTSEVERITY_WARNING, + /** Error event. */ + RTTRACELOGEVTSEVERITY_ERROR, + /** Fatal event. */ + RTTRACELOGEVTSEVERITY_FATAL, + /** Debug event. */ + RTTRACELOGEVTSEVERITY_DEBUG, + /** 32bit hack.*/ + RTTRACELOGEVTSEVERITY_32BIT_HACK = 0x7fffffff +} RTTRACELOGEVTSEVERITY; +/** Pointer to a event severity class. */ +typedef RTTRACELOGEVTSEVERITY *PRTTRACELOGEVTSEVERITY; +/** Pointer to a const event severiy class. */ +typedef RTTRACELOGEVTSEVERITY *PCRTTRACELOGEVTSEVERITY; + + +/** + * Trace log reader event. + */ +typedef enum RTTRACELOGRDRPOLLEVT +{ + /** Invalid event. */ + RTTRACELOGRDRPOLLEVT_INVALID = 0, + /** The header was received and valid. */ + RTTRACELOGRDRPOLLEVT_HDR_RECVD, + /** Event data was fetched. */ + RTTRACELOGRDRPOLLEVT_TRACE_EVENT_RECVD, + /** 32bit hack. */ + RTTRACELOGRDRPOLLEVT_32BIT_HACK = 0x7fffffff +} RTTRACELOGRDRPOLLEVT; +/** Pointer to a trace log reader event. */ +typedef RTTRACELOGRDRPOLLEVT *PRTTRACELOGRDRPOLLEVT; + + +/** + * Trace log event item descriptor. + */ +typedef struct RTTRACELOGEVTITEMDESC +{ + /** Event item name. */ + const char *pszName; + /** Event item description. */ + const char *pszDesc; + /** Event item type. */ + RTTRACELOGTYPE enmType; + /** The size of the raw data if static for the item, + * 0 otherwise (and given when the event is logged). + * Only valid for the RTTRACELOGTYPE_RAWDATA type, + * ignored otherwise. */ + size_t cbRawData; +} RTTRACELOGEVTITEMDESC; +/** Pointer to an trace log event item descriptor. */ +typedef RTTRACELOGEVTITEMDESC *PRTTRACELOGEVTITEMDESC; +/** Pointer to a const trace log event item descriptor. */ +typedef const RTTRACELOGEVTITEMDESC *PCRTTRACELOGEVTITEMDESC; +/** Pointer to a trace log event item descriptor pointer. */ +typedef PRTTRACELOGEVTITEMDESC *PPRTTRACELOGEVTITEMDESC; +/** Pointer to a const trace log event item descriptor pointer. */ +typedef PCRTTRACELOGEVTITEMDESC *PPCRTTRACELOGEVTITEMDESC; + + +/** + * Trace log event descriptor. + */ +typedef struct RTTRACELOGEVTDESC +{ + /** Event identifier. */ + const char *pszId; + /** Event description. */ + const char *pszDesc; + /** Severity class of the event. */ + RTTRACELOGEVTSEVERITY enmSeverity; + /** Number of items recorded for an event. */ + uint32_t cEvtItems; + /** Pointer to array of event item descriptors. */ + PCRTTRACELOGEVTITEMDESC paEvtItemDesc; +} RTTRACELOGEVTDESC; +/** Pointer to a trace log event descriptor. */ +typedef RTTRACELOGEVTDESC *PRTTRACELOGEVTDESC; +/** Pointer to a const trace log event descriptor. */ +typedef const RTTRACELOGEVTDESC *PCRTTRACELOGEVTDESC; + + +/** + * Trace log event item value. + */ +typedef struct RTTRACELOGEVTVAL +{ + /** Pointer to the corresponding event item descriptor. */ + PCRTTRACELOGEVTITEMDESC pItemDesc; + /** Value union. */ + union + { + bool f; + uint8_t u8; + int8_t i8; + uint16_t u16; + int16_t i16; + uint32_t u32; + int32_t i32; + uint64_t u64; + int64_t i64; + uint64_t sz; + uint64_t uPtr; + float f32; + double f64; + struct + { + size_t cb; + const uint8_t *pb; + } RawData; + } u; +} RTTRACELOGEVTVAL; +/** Pointer to trace log event item value. */ +typedef RTTRACELOGEVTVAL *PRTTRACELOGEVTVAL; +/** Pointer to a const trace log event item value. */ +typedef const RTTRACELOGEVTVAL *PCRTTRACELOGEVTVAL; + + +/** + * Item mapping descriptor. + */ +typedef struct RTTRACELOGRDRMAPITEM +{ + /** The item name. */ + const char *pszName; + /** The value type to map the item to. */ + RTTRACELOGTYPE enmType; +} RTTRACELOGRDRMAPITEM; +/** Pointer to a mapping item descriptor. */ +typedef RTTRACELOGRDRMAPITEM *PRTTRACELOGRDRMAPITEM; +/** Pointer to a const mapping item descriptor. */ +typedef const RTTRACELOGRDRMAPITEM *PCRTTRACELOGRDRMAPITEM; + + +/** + * Event item to value mapping descriptor for RTTraceLogRdrEvtMapToStruct(). + */ +typedef struct RTTRACELOGRDRMAPDESC +{ + /** The event ID this mapping describes. */ + const char *pszEvtId; + /** Number of event items to extract. */ + uint32_t cEvtItems; + /** Pointer to the event items to extract (in the given order). */ + PCRTTRACELOGRDRMAPITEM paMapItems; +} RTTRACELOGRDRMAPDESC; +/** Pointer to a event mapping descriptor. */ +typedef RTTRACELOGRDRMAPDESC *PRTTRACELOGRDRMAPDESC; +/** Pointer to a const event mapping descriptor. */ +typedef const RTTRACELOGRDRMAPDESC *PCRTTRACELOGRDRMAPDESC; + + +/** + * Header for an event mapped to a binary. + */ +typedef struct RTTRACELOGRDREVTHDR +{ + /** The mapping descriptor this event was mapped to. */ + PCRTTRACELOGRDRMAPDESC pEvtMapDesc; + /** The event descriptor as extracted from the event log. */ + PCRTTRACELOGEVTDESC pEvtDesc; + /** Sequence number of the descriptor. */ + uint64_t idSeqNo; + /** The timestamp of the event. */ + uint64_t tsEvt; + /** Pointer to the event data items. */ + PCRTTRACELOGEVTVAL paEvtItems; +} RTTRACELOGRDREVTHDR; +/** Pointer to an event header. */ +typedef RTTRACELOGRDREVTHDR *PRTTRACELOGRDREVTHDR; +/** Pointer to a const event header. */ +typedef const RTTRACELOGRDREVTHDR *PCRTTRACELOGRDREVTHDR; + + +/** Event group ID. */ +typedef uint64_t RTTRACELOGEVTGRPID; +/** Pointer to the event group ID. */ +typedef RTTRACELOGEVTGRPID *PRTTRACELOGEVTGRPID; +/** Trace log event handle. */ +typedef uint64_t RTRACELOGEVT; +/** Pointer to a trace log event handle. */ +typedef RTRACELOGEVT *PRTRACELOGEVT; +/** Trace log writer handle. */ +typedef struct RTTRACELOGWRINT *RTTRACELOGWR; +/** Pointer to a trace log writer handle. */ +typedef RTTRACELOGWR *PRTTRACELOGWR; +/** NIL trace log writer handle value. */ +#define NIL_RTTRACELOGWR ((RTTRACELOGWR)0) +/** Trace log reader handle. */ +typedef struct RTTRACELOGRDRINT *RTTRACELOGRDR; +/** Pointer to a trace log reader handle. */ +typedef RTTRACELOGRDR *PRTTRACELOGRDR; +/** NIL trace log reader handle value. */ +#define NIL_RTTRACELOGRDR ((RTTRACELOGRDR)0) +/** Trace log reader iterator handle. */ +typedef struct RTTRACELOGRDRITINT *RTTRACELOGRDRIT; +/** Pointer to a trace log reader iterator handle. */ +typedef RTTRACELOGRDRIT *PRTTRACELOGRDRIT; +/** NIL trace log reader iterator handle. */ +#define NIL_RTTRACELOGRDRIT ((RTTRACELOGRDRIT)0) +/** Trace log reader event handle. */ +typedef struct RTTRACELOGRDREVTINT *RTTRACELOGRDREVT; +/** Pointer to a trace log reader event handle. */ +typedef RTTRACELOGRDREVT *PRTTRACELOGRDREVT; +/** NIL trace log reader event handle. */ +#define NIL_RTTRACELOGRDREVT ((RTTRACELOGRDREVT)0) + +/** A new grouped event is started. */ +#define RTTRACELOG_WR_ADD_EVT_F_GRP_START RT_BIT_32(0) +/** A grouped event is finished. */ +#define RTTRACELOG_WR_ADD_EVT_F_GRP_FINISH RT_BIT_32(1) + +/** + * Callback to stream out data from the trace log writer. + * + * @returns IPRT status code. + * @param pvUser Opaque user data passed on trace log writer creation. + * @param pvBuf Pointer to the buffer to stream out. + * @param cbBuf Number of bytes to stream. + * @param pcbWritten Where to store the number of bytes written on success, optional. + */ +typedef DECLCALLBACKTYPE(int, FNRTTRACELOGWRSTREAM,(void *pvUser, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)); +/** Pointer to a writer stream callback. */ +typedef FNRTTRACELOGWRSTREAM *PFNRTTRACELOGWRSTREAM; + + +/** + * Callback to stream int data to the trace log reader. + * + * @returns IPRT status code. + * @retval VERR_EOF if the stream reached the end. + * @retval VERR_INTERRUPTED if waiting for something to arrive was interrupted. + * @retval VERR_TIMEOUT if the timeout was reached. + * @param pvUser Opaque user data passed on trace log reader creation. + * @param pvBuf Where to store the read data. + * @param cbBuf Number of bytes the buffer can hold. + * @param pcbRead Where to store the number of bytes read on success. + * @param cMsTimeout How long to wait for something to arrive + */ +typedef DECLCALLBACKTYPE(int, FNRTTRACELOGRDRSTREAM,(void *pvUser, void *pvBuf, size_t cbBuf, size_t *pcbRead, + RTMSINTERVAL cMsTimeout)); +/** Pointer to a writer stream callback. */ +typedef FNRTTRACELOGRDRSTREAM *PFNRTTRACELOGRDRSTREAM; + + +/** + * Callback to close the stream. + * + * @returns IPRT status code. + * @param pvUser Opaque user data passed on trace log writer creation. + */ +typedef DECLCALLBACKTYPE(int, FNRTTRACELOGSTREAMCLOSE,(void *pvUser)); +/** Pointer to a stream close callback. */ +typedef FNRTTRACELOGSTREAMCLOSE *PFNRTTRACELOGSTREAMCLOSE; + + +/** + * Creates a new trace log writer. + * + * @returns IPRT status code. + * @param phTraceLogWr Where to store the handle to the trace log writer on success. + * @param pszDesc Optional description to store in the header. + * @param pfnStreamOut The callback to use for streaming the trace log data. + * @param pfnStreamClose The callback to use for closing the stream. + * @param pvUser Opaque user data to pass to the streaming callback. + */ +RTDECL(int) RTTraceLogWrCreate(PRTTRACELOGWR phTraceLogWr, const char *pszDesc, + PFNRTTRACELOGWRSTREAM pfnStreamOut, + PFNRTTRACELOGSTREAMCLOSE pfnStreamClose, void *pvUser); + + +/** + * Creates a new trace log writer streaming data to the given file. + * + * @returns IPRT status code. + * @param phTraceLogWr Where to store the handle to the trace log writer on success. + * @param pszDesc Optional description to store in the header. + * @param pszFilename The filename to stream the data to. + */ +RTDECL(int) RTTraceLogWrCreateFile(PRTTRACELOGWR phTraceLogWr, const char *pszDesc, + const char *pszFilename); + + +/** + * Creates a new TCP server style trace log writer waiting for the other end to connect to it. + * + * @returns IPRT status code. + * @param phTraceLogWr Where to store the handle to the trace log writer on success. + * @param pszDesc Optional description to store in the header. + * @param pszListen The address to listen on, NULL to listen on all interfaces. + * @param uPort The port to listen on. + * + * @note The writer will block here until a client has connected. + */ +RTDECL(int) RTTraceLogWrCreateTcpServer(PRTTRACELOGWR phTraceLogWr, const char *pszDesc, + const char *pszListen, unsigned uPort); + + +/** + * Creates a new TCP client style trace log writer connecting to the other end. + * + * @returns IPRT status code. + * @param phTraceLogWr Where to store the handle to the trace log writer on success. + * @param pszDesc Optional description to store in the header. + * @param pszAddress The address to connect to. + * @param uPort The port to connect to. + * + * @note An error is returned if no connection can be established. + */ +RTDECL(int) RTTraceLogWrCreateTcpClient(PRTTRACELOGWR phTraceLogWr, const char *pszDesc, + const char *pszAddress, unsigned uPort); + + +/** + * Destroys the given trace log writer instance. + * + * @returns IPRT status code. + * @param hTraceLogWr The trace log writer instance handle. + */ +RTDECL(int) RTTraceLogWrDestroy(RTTRACELOGWR hTraceLogWr); + + +/** + * Adds a given event structure descriptor to the given trace log writer instance + * (for prepopulation). + * + * @returns IPRT status code. + * @param hTraceLogWr The trace log writer instance handle. + * @param pEvtDesc The event structure descriptor to add. + * + * @note The event descriptor is keyed by the pointer for faster lookup in subsequent calls, + * so don't free after this method finishes. + */ +RTDECL(int) RTTraceLogWrAddEvtDesc(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc); + + +/** + * Adds a new event to the trace log. + * + * @returns IPRT status code. + * @param hTraceLogWr The trace log writer instance handle. + * @param pEvtDesc The event descriptor to use for formatting. + * @param fFlags Flags to use for this event.y + * @param uGrpId A unique group ID for grouped events. + * @param uParentGrpId A parent group ID this event originated from. + * @param pvEvtData Pointer to the raw event data. + * @param pacbRawData Pointer to the array of size indicators for non static raw data in the event data stream. + * + * @note The event descriptor is keyed by the pointer for faster lookup in subsequent calls, + * so don't free after this method finishes. + */ +RTDECL(int) RTTraceLogWrEvtAdd(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags, + RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, + const void *pvEvtData, size_t *pacbRawData); + + +/** + * Adds a new event to the trace log. + * + * @returns IPRT status code. + * @param hTraceLogWr The trace log writer instance handle. + * @param pEvtDesc The event descriptor used for formatting the data. + * @param fFlags Flags to use for this event. + * @param uGrpId A unique group ID for grouped events. + * @param uParentGrpId A parent group ID this event originated from. + * @param pSgBufEvtData S/G buffer holding the raw event data. + * @param pacbRawData Pointer to the array of size indicators for non static raw data in the event data stream. + * + * @note The event descriptor is keyed by the pointer for faster lookup in subsequent calls, + * so don't free after this method finishes. + */ +RTDECL(int) RTTraceLogWrEvtAddSg(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags, + RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, + PRTSGBUF *pSgBufEvtData, size_t *pacbRawData); + + +/** + * Adds a new event to the trace log - list variant. + * + * @returns IPRT status code. + * @param hTraceLogWr The trace log writer instance handle. + * @param pEvtDesc The event descriptor used for formatting the data. + * @param fFlags Flags to use for this event. + * @param uGrpId A unique group ID for grouped events. + * @param uParentGrpId A parent group ID this event originated from. + * @param va The event data as single items as described by the descriptor. + * + * @note The event descriptor is keyed by the pointer for faster lookup in subsequent calls, + * so don't free after this method finishes. + */ +RTDECL(int) RTTraceLogWrEvtAddLV(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags, + RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, va_list va); + + +/** + * Adds a new event to the trace log - list variant. + * + * @returns IPRT status code. + * @param hTraceLogWr The trace log writer instance handle. + * @param pEvtDesc The event descriptor used for formatting the data. + * @param fFlags Flags to use for this event. + * @param uGrpId A unique group ID for grouped events. + * @param uParentGrpId A parent group ID this event originated from. + * @param ... The event data as single items as described by the descriptor. + * + * @note The event descriptor is keyed by the pointer for faster lookup in subsequent calls, + * so don't free after this method finishes. + */ +RTDECL(int) RTTraceLogWrEvtAddL(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags, + RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, ...); + + +/** + * Creates a new trace log reader instance. + * + * @returns IPRT status code. + * @param phTraceLogRdr Where to store the handle to the trace log reader instance on success. + * @param pfnStreamIn Callback to stream the data into the reader. + * @param pfnStreamClose The callback to use for closing the stream. + * @param pvUser Opaque user data passed to the stream callback. + */ +RTDECL(int) RTTraceLogRdrCreate(PRTTRACELOGRDR phTraceLogRdr, PFNRTTRACELOGRDRSTREAM pfnStreamIn, + PFNRTTRACELOGSTREAMCLOSE pfnStreamClose, void *pvUser); + + +/** + * Creates a new trace log reader for the given file. + * + * @returns IPRT status code. + * @param phTraceLogRdr Where to store the handle to the trace log reader instance on success. + * @param pszFilename The file to read the trace log data from. + */ +RTDECL(int) RTTraceLogRdrCreateFromFile(PRTTRACELOGRDR phTraceLogRdr, const char *pszFilename); + + +/** + * Destroys the given trace log reader instance. + * + * @returns IPRT status code. + * @param hTraceLogRdr The trace log reader instance handle. + */ +RTDECL(int) RTTraceLogRdrDestroy(RTTRACELOGRDR hTraceLogRdr); + + +/** + * Polls for an event on the trace log reader instance. + * + * @returns IPRT status code. + * @retval VERR_TIMEOUT if the timeout was reached. + * @retval VERR_INTERRUPTED if the poll was interrupted. + * @param hTraceLogRdr The trace log reader instance handle. + * @param penmEvt Where to store the event identifier. + * @param cMsTimeout How long to poll for an event. + */ +RTDECL(int) RTTraceLogRdrEvtPoll(RTTRACELOGRDR hTraceLogRdr, RTTRACELOGRDRPOLLEVT *penmEvt, RTMSINTERVAL cMsTimeout); + +/** + * Queries the last received event from the trace log read instance. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if no event was received so far. + * @param hTraceLogRdr The trace log reader instance handle. + * @param phRdrEvt Where to store the event handle on success. + */ +RTDECL(int) RTTraceLogRdrQueryLastEvt(RTTRACELOGRDR hTraceLogRdr, PRTTRACELOGRDREVT phRdrEvt); + +/** + * Queries a new iterator for walking received events. + * + * @returns IPRT status code + * @param hTraceLogRdr The trace log reader instance handle. + * @param phIt Where to store the handle to iterator on success. + */ +RTDECL(int) RTTraceLogRdrQueryIterator(RTTRACELOGRDR hTraceLogRdr, PRTTRACELOGRDRIT phIt); + + +/** + * Extracts the given number of events from the given trace log reader instance returning + * and array of events with the values filled in from the mapping descriptor. + * + * @returns IPRT status code. + * @param hTraceLogRdr The trace log reader instance handle. + * @param fFlags Flags controlling the behavior, MBZ. + * @param cEvts Number of events to extract, UINT32_MAX to map all immediately available events. + * @param paMapDesc Pointer to an array of mapping descriptors describing how to map events. + * @param ppaEvtHdr Where to return the pointer to the allocated array of event headers on success. + * @param pcEvts Where to store the returned number of events on success. + */ +RTDECL(int) RTTraceLogRdrEvtMapToStruct(RTTRACELOGRDR hTraceLogRdr, uint32_t fFlags, uint32_t cEvts, + PCRTTRACELOGRDRMAPDESC paMapDesc, PCRTTRACELOGRDREVTHDR *ppaEvtHdr, + uint32_t *pcEvts); + + +/** + * Frees all resources of the given array of event headers as allocated by RTTraceLogRdrEvtMapToStruct(). + * + * @returns nothing. + * @param paEvtHdr Pointer to the array of events as returned by RTTraceLogRdrEvtMapToStruct(). + * @param cEvts Number of events as returned by RTTraceLogRdrEvtMapToStruct(). + */ +RTDECL(void) RTTraceLogRdrEvtMapFree(PCRTTRACELOGRDREVTHDR paEvtHdr, uint32_t cEvts); + + +/** + * Frees a previously created iterator. + * + * @returns nothing. + * @param hIt The iterator handle to free. + */ +RTDECL(void) RTTraceLogRdrIteratorFree(RTTRACELOGRDRIT hIt); + + +/** + * Advances to the next event. + * + * @returns IPRT status code + * @retval VERR_TRACELOG_READER_ITERATOR_END if the iterator reached the end. + * @param hIt The iterator handle. + */ +RTDECL(int) RTTraceLogRdrIteratorNext(RTTRACELOGRDRIT hIt); + + +/** + * Queries the event at the current iterator position. + * + * @returns IPRT status code. + * @param hIt The iterator handle. + * @param phRdrEvt Where to store the event handle on success. + */ +RTDECL(int) RTTraceLogRdrIteratorQueryEvent(RTTRACELOGRDRIT hIt, PRTTRACELOGRDREVT phRdrEvt); + + +/** + * Returns the sequence number of the given event. + * + * @returns Sequence number of the given event. + * @param hRdrEvt The reader event handle. + */ +RTDECL(uint64_t) RTTraceLogRdrEvtGetSeqNo(RTTRACELOGRDREVT hRdrEvt); + + +/** + * Gets the timestamp of the given event. + * + * @returns Timestamp of the given event. + * @param hRdrEvt The reader event handle. + */ +RTDECL(uint64_t) RTTraceLogRdrEvtGetTs(RTTRACELOGRDREVT hRdrEvt); + + +/** + * Returns whether the given event is part of an event group. + * + * @returns Flag whether the event is part of a group. + * @param hRdrEvt The reader event handle. + */ +RTDECL(bool) RTTraceLogRdrEvtIsGrouped(RTTRACELOGRDREVT hRdrEvt); + + +/** + * Returns the event descriptor associated with the given event. + * + * @returns The trace log event descriptor associated with this event. + * @param hRdrEvt The reader event handle. + */ +RTDECL(PCRTTRACELOGEVTDESC) RTTraceLogRdrEvtGetDesc(RTTRACELOGRDREVT hRdrEvt); + + +/** + * Queries an event item by its name returning the value in the supplied buffer. + * + * @returns IPRT status code. + * @retval VERR_NOT_FOUND if the item name was not found for the given event. + * @param hRdrEvt The reader event handle. + * @param pszName The item name to query. + * @param pVal The item value buffer to initialise. + */ +RTDECL(int) RTTraceLogRdrEvtQueryVal(RTTRACELOGRDREVT hRdrEvt, const char *pszName, PRTTRACELOGEVTVAL pVal); + + +/** + * Fills the given value array using the values from the given event. + * + * @returns IPRT status code + * @param hRdrEvt The reader event handle. + * @param idxItemStart The index of the item to start filling the value in. + * @param paVals Array of values to fill. + * @param cVals Number of values the array is able to hold. + * @param pcVals Where to store the number of values filled on success. + */ +RTDECL(int) RTTraceLogRdrEvtFillVals(RTTRACELOGRDREVT hRdrEvt, unsigned idxItemStart, PRTTRACELOGEVTVAL paVals, + unsigned cVals, unsigned *pcVals); + +RT_C_DECLS_END + +/** @} */ + +#endif /* !IPRT_INCLUDED_tracelog_h */ + diff --git a/include/iprt/types.h b/include/iprt/types.h new file mode 100644 index 00000000..366c19a6 --- /dev/null +++ b/include/iprt/types.h @@ -0,0 +1,3890 @@ +/** @file + * IPRT - Types. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_types_h +#define IPRT_INCLUDED_types_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/stdint.h> +#include <iprt/stdarg.h> + +/* + * Include standard C types. + */ +#if !defined(IPRT_NO_CRT) && !defined(DOXYGEN_RUNNING) + +# if defined(IN_XF86_MODULE) && !defined(NO_ANSIC) + /* + * Kludge for xfree86 modules: size_t and other types are redefined. + */ +RT_C_DECLS_BEGIN +# include "xf86_ansic.h" +# undef NULL +RT_C_DECLS_END + +# elif defined(RT_OS_DARWIN) && defined(KERNEL) + /* + * Kludge for the darwin kernel: + * stddef.h is missing IIRC. + */ +# ifndef _PTRDIFF_T +# define _PTRDIFF_T + typedef __darwin_ptrdiff_t ptrdiff_t; +# endif +# include <sys/types.h> + +# elif defined(RT_OS_FREEBSD) && defined(_KERNEL) +# include <sys/param.h> +# undef PVM +# if __FreeBSD_version < 1200000 + /* + * Kludge for the FreeBSD kernel: + * stddef.h and sys/types.h have slightly different offsetof definitions + * when compiling in kernel mode. This is just to make GCC shut up. + */ +# ifndef _STDDEF_H_ +# undef offsetof +# endif +# include <sys/stddef.h> +# ifndef _SYS_TYPES_H_ +# undef offsetof +# endif +# include <sys/types.h> +# ifndef offsetof +# error "offsetof is not defined!" +# endif +# else +# include <sys/stddef.h> +# include <sys/types.h> +# endif + +# elif defined(RT_OS_FREEBSD) && HC_ARCH_BITS == 64 && defined(RT_ARCH_X86) + /* + * Kludge for compiling 32-bit code on a 64-bit FreeBSD: + * FreeBSD declares uint64_t and int64_t wrong (long unsigned and long int + * though they need to be long long unsigned and long long int). These + * defines conflict with our declaration in stdint.h. Adding the defines + * below omits the definitions in the system header. + */ +# include <stddef.h> +# define _UINT64_T_DECLARED +# define _INT64_T_DECLARED +# define _UINTPTR_T_DECLARED +# define _INTPTR_T_DECLARED +# include <sys/types.h> + +# elif defined(RT_OS_NETBSD) && defined(_KERNEL) + +# include <sys/types.h> + + /* + * Kludge for NetBSD-6.x where the definition of bool in + * <sys/types.h> does not check for C++. + */ +# if defined(__cplusplus) && defined(bool) +# undef bool +# undef true +# undef false +# endif + + /* + * Kludge for NetBSD-6.x where <sys/types.h> does not define + * ptrdiff_t for the kernel code. Note that we don't worry about + * redefinition in <stddef.h> since that header doesn't exist for + * _KERNEL code. + */ +# ifdef _BSD_PTRDIFF_T_ + typedef _BSD_PTRDIFF_T_ ptrdiff_t; +# endif + +# elif defined(RT_OS_LINUX) && defined(__KERNEL__) + /* + * Kludge for the linux kernel: + * 1. sys/types.h doesn't mix with the kernel. + * 2. Starting with 2.6.19, linux/types.h typedefs bool and linux/stddef.h + * declares false and true as enum values. + * 3. Starting with 2.6.24, linux/types.h typedefs uintptr_t. + * We work around these issues here and nowhere else. + */ +# if defined(__cplusplus) + typedef bool _Bool; +# endif +# define bool linux_bool +# define true linux_true +# define false linux_false +# define uintptr_t linux_uintptr_t +# include <linux/version.h> +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) +# include <generated/autoconf.h> +# else +# ifndef AUTOCONF_INCLUDED +# include <linux/autoconf.h> +# endif +# endif +# include <linux/compiler.h> +# if defined(__cplusplus) + /* + * Starting with 3.3, <linux/compiler-gcc.h> appends 'notrace' (which + * expands to __attribute__((no_instrument_function))) to inline, + * __inline and __inline__. Revert that. + */ +# undef inline +# define inline inline +# undef __inline__ +# define __inline__ __inline__ +# undef __inline +# define __inline __inline +# endif +# include <linux/types.h> +# include <linux/stddef.h> + /* + * Starting with 3.4, <linux/stddef.h> defines NULL as '((void*)0)' which + * does not work for C++ code. + */ +# undef NULL +# undef uintptr_t +# ifdef __GNUC__ +# if !RT_GNUC_PREREQ(4, 1) + /* + * <linux/compiler-gcc{3,4}.h> does + * #define __inline__ __inline__ __attribute__((always_inline)) + * in some older Linux kernels. Forcing inlining will fail for some RTStrA* + * functions with gcc <= 4.0 due to passing variable argument lists. + */ +# undef __inline__ +# define __inline__ __inline__ +# endif +# endif +# undef false +# undef true +# undef bool + +# elif !defined(DOXYGEN_RUNNING) && RT_MSC_PREREQ(RT_MSC_VER_VC140) && defined(RT_OS_AGNOSTIC) + /* Try avoid needing the UCRT just for stddef.h and sys/types.h. */ + /** @todo refine the RT_OS_AGNOSTIC test? */ +# include <vcruntime.h> + +# else +# include <stddef.h> +# include <sys/types.h> +# endif + + +/* Define any types missing from sys/types.h on Windows and OS/2. */ +# ifdef _MSC_VER +# undef ssize_t +typedef intptr_t ssize_t; +# endif +# if defined(RT_OS_OS2) && (defined(__IBMC__) || defined(__IBMCPP__)) +typedef signed long ssize_t; +# endif + +#else /* no crt */ +# include <iprt/nocrt/compiler/compiler.h> +#endif /* no crt */ + + + +/** @def NULL + * NULL pointer. + */ +#ifndef NULL +# ifdef __cplusplus +# define NULL 0 +# else +# define NULL ((void*)0) +# endif +#endif + + + +/** @defgroup grp_rt_types IPRT Base Types + * @{ + */ + +/* define wchar_t, we don't wanna include all the wcsstuff to get this. */ +#ifdef _MSC_VER +# ifndef _WCHAR_T_DEFINED + typedef unsigned short wchar_t; +# define _WCHAR_T_DEFINED +# endif +#endif +#ifdef __GNUC__ +/** @todo wchar_t on GNUC */ +#endif + +/* + * C doesn't have bool, nor does VisualAge for C++ v3.08. + */ +#if !defined(__cplusplus) || (defined(__IBMCPP__) && defined(RT_OS_OS2)) +# if defined(__GNUC__) +# if defined(RT_OS_LINUX) && __GNUC__ < 3 +typedef uint8_t bool; +# elif defined(RT_OS_FREEBSD) +# ifndef __bool_true_false_are_defined +typedef _Bool bool; +# endif +# elif defined(RT_OS_NETBSD) +# if !defined(_KERNEL) + /* + * For the kernel code <stdbool.h> is not available, but bool is + * provided by <sys/types.h> included above. + */ +# include <stdbool.h> + + /* + * ... but the story doesn't end here. The C standard says that + * <stdbool.h> defines preprocessor macro "bool" that expands to + * "_Bool", but adds that a program may undefine/redefine it + * (this is 7.16 in C99 and 7.18 in C11). We have to play this + * game here because X11 code uses "bool" as a struct member name + * - so undefine "bool" and provide it as a typedef instead. We + * still keep #include <stdbool.h> so that any code that might + * include it later doesn't mess things up. + */ +# undef bool + typedef _Bool bool; +# endif +# else +# undef bool /* see above netbsd explanation */ +typedef _Bool bool; +# endif +# else +# if RT_MSC_PREREQ(RT_MSC_VER_VC120) +# include <stdbool.h> +# else +typedef unsigned char bool; +# endif +# endif +# ifndef true +# define true (1) +# endif +# ifndef false +# define false (0) +# endif +#endif + + +/** + * 128-bit unsigned integer. + */ +#ifdef RT_COMPILER_WITH_128BIT_INT_TYPES +typedef __uint128_t uint128_t; +#else +typedef struct uint128_s +{ +# ifdef RT_BIG_ENDIAN + uint64_t Hi; + uint64_t Lo; +# else + uint64_t Lo; + uint64_t Hi; +# endif +} uint128_t; +#endif + + +/** + * 128-bit signed integer. + */ +#ifdef RT_COMPILER_WITH_128BIT_INT_TYPES +typedef __int128_t int128_t; +#else +typedef struct int128_s +{ +# ifdef RT_BIG_ENDIAN + int64_t Hi; + uint64_t Lo; +# else + uint64_t Lo; + int64_t Hi; +# endif +} int128_t; +#endif + + +/** + * 16-bit unsigned integer union. + */ +typedef union RTUINT16U +{ + /** natural view. */ + uint16_t u; + + /** 16-bit hi/lo view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint8_t Hi; + uint8_t Lo; +#else + uint8_t Lo; + uint8_t Hi; +#endif + } s; + + /** Unsigned 16-bit view. */ + uint16_t au16[1]; + /** Unsigned 8-bit view. */ + uint8_t au8[2]; + + /** Signed 16-bit view. */ + int16_t ai16[1]; + /** Signed 8-bit view. */ + int8_t ai8[2]; +} RTUINT16U; +/** Pointer to a 16-bit unsigned integer union. */ +typedef RTUINT16U RT_FAR *PRTUINT16U; +/** Pointer to a const 32-bit unsigned integer union. */ +typedef const RTUINT16U RT_FAR *PCRTUINT16U; + + +/** + * 32-bit unsigned integer union. + */ +typedef union RTUINT32U +{ + /** natural view. */ + uint32_t u; + /** Hi/Low view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint16_t Hi; + uint16_t Lo; +#else + uint16_t Lo; + uint16_t Hi; +#endif + } s; + /** Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint16_t w1; + uint16_t w0; +#else + uint16_t w0; + uint16_t w1; +#endif + } Words; + + /** Unsigned 32-bit view. */ + uint32_t au32[1]; + /** Unsigned 16-bit view. */ + uint16_t au16[2]; + /** Unsigned 8-bit view. */ + uint8_t au8[4]; + + /** Signed 32-bit view. */ + int32_t ai32[1]; + /** Signed 16-bit view. */ + int16_t ai16[2]; + /** Signed 8-bit view. */ + int8_t ai8[4]; +} RTUINT32U; +/** Pointer to a 32-bit unsigned integer union. */ +typedef RTUINT32U RT_FAR *PRTUINT32U; +/** Pointer to a const 32-bit unsigned integer union. */ +typedef const RTUINT32U RT_FAR *PCRTUINT32U; + + +/** + * 64-bit unsigned integer union. + */ +typedef union RTUINT64U +{ + /** Natural view. */ + uint64_t u; + /** Hi/Low view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint32_t Hi; + uint32_t Lo; +#else + uint32_t Lo; + uint32_t Hi; +#endif + } s; + /** Double-Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint32_t dw1; + uint32_t dw0; +#else + uint32_t dw0; + uint32_t dw1; +#endif + } DWords; + /** Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint16_t w3; + uint16_t w2; + uint16_t w1; + uint16_t w0; +#else + uint16_t w0; + uint16_t w1; + uint16_t w2; + uint16_t w3; +#endif + } Words; + + /** Unsigned 64-bit view. */ + uint64_t au64[1]; + /** Unsigned 32-bit view. */ + uint32_t au32[2]; + /** Unsigned 16-bit view. */ + uint16_t au16[4]; + /** Unsigned 8-bit view. */ + uint8_t au8[8]; + + /** Signed 64-bit view. */ + int64_t ai64[1]; + /** Signed 32-bit view. */ + int32_t ai32[2]; + /** Signed 16-bit view. */ + int16_t ai16[4]; + /** Signed 8-bit view. */ + int8_t ai8[8]; +} RTUINT64U; +/** Pointer to a 64-bit unsigned integer union. */ +typedef RTUINT64U RT_FAR *PRTUINT64U; +/** Pointer to a const 64-bit unsigned integer union. */ +typedef const RTUINT64U RT_FAR *PCRTUINT64U; + + +/** + * 128-bit unsigned integer union. + */ +#pragma pack(1) +typedef union RTUINT128U +{ + /** Hi/Low view. + * @remarks We put this first so we can have portable initializers + * (RTUINT128_INIT) */ + struct + { +#ifdef RT_BIG_ENDIAN + uint64_t Hi; + uint64_t Lo; +#else + uint64_t Lo; + uint64_t Hi; +#endif + } s; + + /** Natural view. + * WARNING! This member depends on the compiler supporting 128-bit stuff. */ + uint128_t u; + + /** Quad-Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint64_t qw1; + uint64_t qw0; +#else + uint64_t qw0; + uint64_t qw1; +#endif + } QWords; + /** Double-Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint32_t dw3; + uint32_t dw2; + uint32_t dw1; + uint32_t dw0; +#else + uint32_t dw0; + uint32_t dw1; + uint32_t dw2; + uint32_t dw3; +#endif + } DWords; + /** Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint16_t w7; + uint16_t w6; + uint16_t w5; + uint16_t w4; + uint16_t w3; + uint16_t w2; + uint16_t w1; + uint16_t w0; +#else + uint16_t w0; + uint16_t w1; + uint16_t w2; + uint16_t w3; + uint16_t w4; + uint16_t w5; + uint16_t w6; + uint16_t w7; +#endif + } Words; + + /** Unsigned 64-bit view. */ + uint64_t au64[2]; + /** Unsigned 32-bit view. */ + uint32_t au32[4]; + /** Unsigned 16-bit view. */ + uint16_t au16[8]; + /** Unsigned 8-bit view. */ + uint8_t au8[16]; + + /** Signed 64-bit view. */ + int64_t ai64[2]; + /** Signed 32-bit view. */ + int32_t ai32[4]; + /** Signed 16-bit view. */ + int16_t ai16[8]; + /** Signed 8-bit view. */ + int8_t ai8[16]; +} RTUINT128U; +#pragma pack() +/** Pointer to a 128-bit unsigned integer union. */ +typedef RTUINT128U RT_FAR *PRTUINT128U; +/** Pointer to a const 128-bit unsigned integer union. */ +typedef const RTUINT128U RT_FAR *PCRTUINT128U; + +/** @def RTUINT128_INIT + * Portable RTUINT128U initializer. */ +#ifdef RT_BIG_ENDIAN +# define RTUINT128_INIT(a_Hi, a_Lo) { { a_Hi, a_Lo } } +#else +# define RTUINT128_INIT(a_Hi, a_Lo) { { a_Lo, a_Hi } } +#endif + +/** @def RTUINT128_INIT_C + * Portable RTUINT128U initializer for 64-bit constants. */ +#ifdef RT_BIG_ENDIAN +# define RTUINT128_INIT_C(a_Hi, a_Lo) { { UINT64_C(a_Hi), UINT64_C(a_Lo) } } +#else +# define RTUINT128_INIT_C(a_Hi, a_Lo) { { UINT64_C(a_Lo), UINT64_C(a_Hi) } } +#endif + + +/** + * 256-bit unsigned integer union. + */ +#pragma pack(1) +typedef union RTUINT256U +{ + /** Quad-Word view (first as it's used by RTUINT256_INIT). */ + struct + { +#ifdef RT_BIG_ENDIAN + uint64_t qw3; + uint64_t qw2; + uint64_t qw1; + uint64_t qw0; +#else + uint64_t qw0; + uint64_t qw1; + uint64_t qw2; + uint64_t qw3; +#endif + } QWords; + /** Double-Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint32_t dw7; + uint32_t dw6; + uint32_t dw5; + uint32_t dw4; + uint32_t dw3; + uint32_t dw2; + uint32_t dw1; + uint32_t dw0; +#else + uint32_t dw0; + uint32_t dw1; + uint32_t dw2; + uint32_t dw3; + uint32_t dw4; + uint32_t dw5; + uint32_t dw6; + uint32_t dw7; +#endif + } DWords; + /** Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint16_t w15; + uint16_t w14; + uint16_t w13; + uint16_t w12; + uint16_t w11; + uint16_t w10; + uint16_t w9; + uint16_t w8; + uint16_t w7; + uint16_t w6; + uint16_t w5; + uint16_t w4; + uint16_t w3; + uint16_t w2; + uint16_t w1; + uint16_t w0; +#else + uint16_t w0; + uint16_t w1; + uint16_t w2; + uint16_t w3; + uint16_t w4; + uint16_t w5; + uint16_t w6; + uint16_t w7; + uint16_t w8; + uint16_t w9; + uint16_t w10; + uint16_t w11; + uint16_t w12; + uint16_t w13; + uint16_t w14; + uint16_t w15; +#endif + } Words; + + /** Double-Quad-Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + RTUINT128U dqw1; + RTUINT128U dqw0; +#else + RTUINT128U dqw0; + RTUINT128U dqw1; +#endif + } DQWords; + + /** Unsigned 128-bit view. */ + RTUINT128U au128[2]; + /** Unsigned 64-bit view. */ + uint64_t au64[4]; + /** Unsigned 32-bit view. */ + uint32_t au32[8]; + /** Unsigned 16-bit view. */ + uint16_t au16[16]; + /** Unsigned 8-bit view. */ + uint8_t au8[32]; + + /** Signed 64-bit view. */ + int64_t ai64[4]; + /** Signed 32-bit view. */ + int32_t ai32[8]; + /** Signed 16-bit view. */ + int16_t ai16[16]; + /** Signed 8-bit view. */ + int8_t ai8[32]; +} RTUINT256U; +#pragma pack() +/** Pointer to a 256-bit unsigned integer union. */ +typedef RTUINT256U RT_FAR *PRTUINT256U; +/** Pointer to a const 256-bit unsigned integer union. */ +typedef const RTUINT256U RT_FAR *PCRTUINT256U; + +/** @def RTUINT256_INIT + * Portable RTUINT256U initializer. */ +#ifdef RT_BIG_ENDIAN +# define RTUINT256_INIT(a_Qw3, a_Qw2, a_Qw1, a_Qw0) { { a_Qw3, a_Qw2, a_Qw1, a_Qw0 } } +#else +# define RTUINT256_INIT(a_Qw3, a_Qw2, a_Qw1, a_Qw0) { { a_Qw0, a_Qw1, a_Qw2, a_Qw3 } } +#endif + +/** @def RTUINT256_INIT_C + * Portable RTUINT256U initializer for 64-bit constants. */ +#define RTUINT256_INIT_C(a_Qw3, a_Qw2, a_Qw1, a_Qw0) \ + RTUINT256_INIT(UINT64_C(a_Qw3), UINT64_C(a_Qw2), UINT64_C(a_Qw1), UINT64_C(a_Qw0)) + + +/** + * 512-bit unsigned integer union. + */ +#pragma pack(1) +typedef union RTUINT512U +{ + /** Quad-Word view (first as it's used by RTUINT512_INIT). */ + struct + { +#ifdef RT_BIG_ENDIAN + uint64_t qw7; + uint64_t qw6; + uint64_t qw5; + uint64_t qw4; + uint64_t qw3; + uint64_t qw2; + uint64_t qw1; + uint64_t qw0; +#else + uint64_t qw0; + uint64_t qw1; + uint64_t qw2; + uint64_t qw3; + uint64_t qw4; + uint64_t qw5; + uint64_t qw6; + uint64_t qw7; +#endif + } QWords; + /** Double-Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint32_t dw15; + uint32_t dw14; + uint32_t dw13; + uint32_t dw12; + uint32_t dw11; + uint32_t dw10; + uint32_t dw9; + uint32_t dw8; + uint32_t dw7; + uint32_t dw6; + uint32_t dw5; + uint32_t dw4; + uint32_t dw3; + uint32_t dw2; + uint32_t dw1; + uint32_t dw0; +#else + uint32_t dw0; + uint32_t dw1; + uint32_t dw2; + uint32_t dw3; + uint32_t dw4; + uint32_t dw5; + uint32_t dw6; + uint32_t dw7; + uint32_t dw8; + uint32_t dw9; + uint32_t dw10; + uint32_t dw11; + uint32_t dw12; + uint32_t dw13; + uint32_t dw14; + uint32_t dw15; +#endif + } DWords; + /** Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + uint16_t w31; + uint16_t w30; + uint16_t w29; + uint16_t w28; + uint16_t w27; + uint16_t w26; + uint16_t w25; + uint16_t w24; + uint16_t w23; + uint16_t w22; + uint16_t w21; + uint16_t w20; + uint16_t w19; + uint16_t w18; + uint16_t w17; + uint16_t w16; + uint16_t w15; + uint16_t w14; + uint16_t w13; + uint16_t w12; + uint16_t w11; + uint16_t w10; + uint16_t w9; + uint16_t w8; + uint16_t w7; + uint16_t w6; + uint16_t w5; + uint16_t w4; + uint16_t w3; + uint16_t w2; + uint16_t w1; + uint16_t w0; +#else + uint16_t w0; + uint16_t w1; + uint16_t w2; + uint16_t w3; + uint16_t w4; + uint16_t w5; + uint16_t w6; + uint16_t w7; + uint16_t w8; + uint16_t w9; + uint16_t w10; + uint16_t w11; + uint16_t w12; + uint16_t w13; + uint16_t w14; + uint16_t w15; + uint16_t w16; + uint16_t w17; + uint16_t w18; + uint16_t w19; + uint16_t w20; + uint16_t w21; + uint16_t w22; + uint16_t w23; + uint16_t w24; + uint16_t w25; + uint16_t w26; + uint16_t w27; + uint16_t w28; + uint16_t w29; + uint16_t w30; + uint16_t w31; +#endif + } Words; + + /** Double-Quad-Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + RTUINT128U dqw3; + RTUINT128U dqw2; + RTUINT128U dqw1; + RTUINT128U dqw0; +#else + RTUINT128U dqw0; + RTUINT128U dqw1; + RTUINT128U dqw2; + RTUINT128U dqw3; +#endif + } DQWords; + + /** Octo-Word view. */ + struct + { +#ifdef RT_BIG_ENDIAN + RTUINT256U ow3; + RTUINT256U ow2; + RTUINT256U ow1; + RTUINT256U ow0; +#else + RTUINT256U ow0; + RTUINT256U ow1; + RTUINT256U ow2; + RTUINT256U ow3; +#endif + } OWords; + + /** 256-bit view. */ + RTUINT256U au256[2]; + /** 128-bit view. */ + RTUINT128U au128[4]; + /** 64-bit view. */ + uint64_t au64[8]; + /** 32-bit view. */ + uint32_t au32[16]; + /** 16-bit view. */ + uint16_t au16[32]; + /** 8-bit view. */ + uint8_t au8[64]; +} RTUINT512U; +#pragma pack() +/** Pointer to a 512-bit unsigned integer union. */ +typedef RTUINT512U RT_FAR *PRTUINT512U; +/** Pointer to a const 512-bit unsigned integer union. */ +typedef const RTUINT512U RT_FAR *PCRTUINT512U; + +/** @def RTUINT512_INIT + * Portable RTUINT512U initializer. */ +#ifdef RT_BIG_ENDIAN +# define RTUINT512_INIT(a_Qw7, a_Qw6, a_Qw5, a_Qw4, a_Qw3, a_Qw2, a_Qw1, a_Qw0) \ + { { a_Qw7, a_Qw6, a_Qw5, a_Qw4, a_Qw3, a_Qw2, a_Qw1, a_Qw0 } } +#else +# define RTUINT512_INIT(a_Qw7, a_Qw6, a_Qw5, a_Qw4, a_Qw3, a_Qw2, a_Qw1, a_Qw0) \ + { { a_Qw0, a_Qw1, a_Qw2, a_Qw3, a_Qw4, a_Qw5, a_Qw6, a_Qw7 } } +#endif + +/** @def RTUINT512_INIT_C + * Portable RTUINT512U initializer for 64-bit constants. */ +#define RTUINT512_INIT_C(a_Qw7, a_Qw6, a_Qw5, a_Qw4, a_Qw3, a_Qw2, a_Qw1, a_Qw0) \ + RTUINT512_INIT(UINT64_C(a_Qw7), UINT64_C(a_Qw6), UINT64_C(a_Qw5), UINT64_C(a_Qw4), \ + UINT64_C(a_Qw3), UINT64_C(a_Qw2), UINT64_C(a_Qw1), UINT64_C(a_Qw0)) + + +/** + * Single precision floating point format (32-bit). + */ +typedef union RTFLOAT32U +{ + /** Format using regular bitfields. */ + struct + { +# ifdef RT_BIG_ENDIAN + /** The sign indicator. */ + uint32_t fSign : 1; + /** The exponent (offsetted by 127). */ + uint32_t uExponent : 8; + /** The fraction. */ + uint32_t uFraction : 23; +# else + /** The fraction. */ + uint32_t uFraction : 23; + /** The exponent (offsetted by 127). */ + uint32_t uExponent : 8; + /** The sign indicator. */ + uint32_t fSign : 1; +# endif + } s; + +#if 1 /** @todo exclude targets which doesn't have a 64-bit double type. (currently none) */ + /** Double view. */ + float r; +#endif + /** Unsigned integer view. */ + uint32_t u; + /** 32-bit view. */ + uint32_t au32[1]; + /** 16-bit view. */ + uint16_t au16[2]; + /** 8-bit view. */ + uint8_t au8[4]; +} RTFLOAT32U; +/** Pointer to a single precision floating point format union. */ +typedef RTFLOAT32U RT_FAR *PRTFLOAT32U; +/** Pointer to a const single precision floating point format union. */ +typedef const RTFLOAT32U RT_FAR *PCRTFLOAT32U; +/** RTFLOAT32U initializer. */ +#ifdef RT_BIG_ENDIAN +# define RTFLOAT32U_INIT(a_fSign, a_uFraction, a_uExponent) { { (a_fSign), (a_uExponent), (a_uFraction) } } +#else +# define RTFLOAT32U_INIT(a_fSign, a_uFraction, a_uExponent) { { (a_uFraction), (a_uExponent), (a_fSign) } } +#endif +#define RTFLOAT32U_INIT_C(a_fSign, a_uFraction, a_uExponent) RTFLOAT32U_INIT((a_fSign), UINT32_C(a_uFraction), (a_uExponent)) +#define RTFLOAT32U_INIT_ZERO(a_fSign) RTFLOAT32U_INIT((a_fSign), 0, 0) +#define RTFLOAT32U_INIT_INF(a_fSign) RTFLOAT32U_INIT((a_fSign), 0, RTFLOAT32U_EXP_MAX) +#define RTFLOAT32U_INIT_SNAN(a_fSign) RTFLOAT32U_INIT((a_fSign), 1, RTFLOAT32U_EXP_MAX) +#define RTFLOAT32U_INIT_SNAN_EX(a_fSign, a_uVal) RTFLOAT32U_INIT((a_fSign), (a_uVal) ? (a_uVal) : 1, RTFLOAT32U_EXP_MAX) +#define RTFLOAT32U_INIT_SIGNALLING_NAN(a_fSign) RTFLOAT32U_INIT_SNAN(a_fSign) +#define RTFLOAT32U_INIT_QNAN(a_fSign) RTFLOAT32U_INIT((a_fSign), RT_BIT_32(RTFLOAT32U_FRACTION_BITS - 1), RTFLOAT32U_EXP_MAX) +#define RTFLOAT32U_INIT_QNAN_EX(a_fSign, a_uVal) RTFLOAT32U_INIT((a_fSign), RT_BIT_32(RTFLOAT32U_FRACTION_BITS - 1) | (a_uVal), RTFLOAT32U_EXP_MAX) +#define RTFLOAT32U_INIT_QUIET_NAN(a_fSign) RTFLOAT32U_INIT_QNAN(a_fSign) +#define RTFLOAT32U_INIT_NAN_EX(a_fQuiet, a_fSign, a_uVal) \ + RTFLOAT32U_INIT((a_fSign), \ + ((a_uVal) || (a_fQuiet) ? (a_uVal) : 1) | ((a_fQuiet) ? RT_BIT_32(RTFLOAT32U_FRACTION_BITS - 1) : 0), \ + RTFLOAT32U_EXP_MAX) + +/** The exponent bias for the RTFLOAT32U format. */ +#define RTFLOAT32U_EXP_BIAS (127) +/** The max exponent value for the RTFLOAT32U format. */ +#define RTFLOAT32U_EXP_MAX (255) +/** The exponent bias overflow/underflow adjust for the RTFLOAT32U format. + * @note 754-1985 sec 7.3 & 7.4, not mentioned in later standard versions. */ +#define RTFLOAT32U_EXP_BIAS_ADJUST (192) +/** Fraction width (in bits) for the RTFLOAT32U format. */ +#define RTFLOAT32U_FRACTION_BITS (23) +/** Check if two 32-bit floating values are identical (memcmp, not + * numerically). */ +#define RTFLOAT32U_ARE_IDENTICAL(a_pLeft, a_pRight) ((a_pLeft)->u == (a_pRight)->u) +/** @name RTFLOAT32U classification macros + * @{ */ +#define RTFLOAT32U_IS_ZERO(a_pr32) (((a_pr32)->u & (RT_BIT_32(31) - 1)) == 0) +#define RTFLOAT32U_IS_SUBNORMAL(a_pr32) ((a_pr32)->s.uExponent == 0 && (a_pr32)->s.uFraction != 0) +#define RTFLOAT32U_IS_INF(a_pr32) ((a_pr32)->s.uExponent == 0xff && (a_pr32)->s.uFraction == 0) +#define RTFLOAT32U_IS_SIGNALLING_NAN(a_pr32) ((a_pr32)->s.uExponent == 0xff && !((a_pr32)->s.uFraction & RT_BIT_32(22)) \ + && (a_pr32)->s.uFraction != 0) +#define RTFLOAT32U_IS_QUIET_NAN(a_pr32) ((a_pr32)->s.uExponent == 0xff && ((a_pr32)->s.uFraction & RT_BIT_32(22))) +#define RTFLOAT32U_IS_NAN(a_pr32) ((a_pr32)->s.uExponent == 0xff && (a_pr32)->s.uFraction != 0) +#define RTFLOAT32U_IS_NORMAL(a_pr32) ((a_pr32)->s.uExponent > 0 && (a_pr32)->s.uExponent < 0xff) +/** @} */ + + +/** + * Double precision floating point format (64-bit). + */ +typedef union RTFLOAT64U +{ + /** Format using regular bitfields. */ + struct + { +# ifdef RT_BIG_ENDIAN + /** The sign indicator. */ + uint32_t fSign : 1; + /** The exponent (offsetted by 1023). */ + uint32_t uExponent : 11; + /** The fraction, bits 32 thru 51. */ + uint32_t uFractionHigh : 20; + /** The fraction, bits 0 thru 31. */ + uint32_t uFractionLow; +# else + /** The fraction, bits 0 thru 31. */ + uint32_t uFractionLow; + /** The fraction, bits 32 thru 51. */ + uint32_t uFractionHigh : 20; + /** The exponent (offsetted by 1023). */ + uint32_t uExponent : 11; + /** The sign indicator. */ + uint32_t fSign : 1; +# endif + } s; + +#ifdef RT_COMPILER_GROKS_64BIT_BITFIELDS + /** Format using 64-bit bitfields. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN + /** The sign indicator. */ + RT_GCC_EXTENSION uint64_t fSign : 1; + /** The exponent (offsetted by 1023). */ + RT_GCC_EXTENSION uint64_t uExponent : 11; + /** The fraction. */ + RT_GCC_EXTENSION uint64_t uFraction : 52; +# else + /** The fraction. */ + RT_GCC_EXTENSION uint64_t uFraction : 52; + /** The exponent (offsetted by 1023). */ + RT_GCC_EXTENSION uint64_t uExponent : 11; + /** The sign indicator. */ + RT_GCC_EXTENSION uint64_t fSign : 1; +# endif + } s64; +#endif + +#if 1 /** @todo exclude targets which doesn't have a 64-bit double type. (currently none) */ + /** Double view. */ + double rd, r; +#endif +#ifdef RT_COMPILER_WITH_64BIT_LONG_DOUBLE + /** Long double view. */ + long double lrd; +#endif + /** Unsigned integer view. */ + uint64_t u; + /** 64-bit view. */ + uint64_t au64[1]; + /** 32-bit view. */ + uint32_t au32[2]; + /** 16-bit view. */ + uint16_t au16[4]; + /** 8-bit view. */ + uint8_t au8[8]; +} RTFLOAT64U; +/** Pointer to a double precision floating point format union. */ +typedef RTFLOAT64U RT_FAR *PRTFLOAT64U; +/** Pointer to a const double precision floating point format union. */ +typedef const RTFLOAT64U RT_FAR *PCRTFLOAT64U; +/** RTFLOAT64U initializer. */ +#ifdef RT_BIG_ENDIAN +# define RTFLOAT64U_INIT(a_fSign, a_uFraction, a_uExponent) \ + { { (a_fSign), (a_uExponent), (uint32_t)((a_uFraction) >> 32), (uint32_t)((a_uFraction) & UINT32_MAX) } } +#else +# define RTFLOAT64U_INIT(a_fSign, a_uFraction, a_uExponent) \ + { { (uint32_t)((a_uFraction) & UINT32_MAX), (uint32_t)((a_uFraction) >> 32), (a_uExponent), (a_fSign) } } +#endif +#define RTFLOAT64U_INIT_C(a_fSign, a_uFraction, a_uExponent) RTFLOAT64U_INIT((a_fSign), UINT64_C(a_uFraction), (a_uExponent)) +#define RTFLOAT64U_INIT_ZERO(a_fSign) RTFLOAT64U_INIT((a_fSign), UINT64_C(0), 0) +#define RTFLOAT64U_INIT_INF(a_fSign) RTFLOAT64U_INIT((a_fSign), UINT64_C(0), RTFLOAT64U_EXP_MAX) +#define RTFLOAT64U_INIT_SNAN(a_fSign) RTFLOAT64U_INIT((a_fSign), UINT64_C(1), RTFLOAT64U_EXP_MAX) +#define RTFLOAT64U_INIT_SNAN_EX(a_fSign, a_uVal) RTFLOAT64U_INIT((a_fSign), (a_uVal) ? (a_uVal) : UINT64_C(1), RTFLOAT64U_EXP_MAX) +#define RTFLOAT64U_INIT_SIGNALLING_NAN(a_fSign) RTFLOAT64U_INIT_SNAN(a_fSign) +#define RTFLOAT64U_INIT_QNAN(a_fSign) RTFLOAT64U_INIT((a_fSign), RT_BIT_64(RTFLOAT64U_FRACTION_BITS - 1), RTFLOAT64U_EXP_MAX) +#define RTFLOAT64U_INIT_QNAN_EX(a_fSign, a_uVal) RTFLOAT64U_INIT((a_fSign), RT_BIT_64(RTFLOAT64U_FRACTION_BITS - 1) | (a_uVal), RTFLOAT64U_EXP_MAX) +#define RTFLOAT64U_INIT_QUIET_NAN(a_fSign) RTFLOAT64U_INIT_QNAN(a_fSign) +#define RTFLOAT64U_INIT_NAN_EX(a_fQuiet, a_fSign, a_uVal) \ + RTFLOAT64U_INIT((a_fSign), \ + ((a_uVal) || (a_fQuiet) ? (a_uVal) : UINT64_C(1)) | ((a_fQuiet) ? RT_BIT_64(RTFLOAT64U_FRACTION_BITS - 1) : UINT64_C(0)), \ + RTFLOAT64U_EXP_MAX) + +/** The exponent bias for the RTFLOAT64U format. */ +#define RTFLOAT64U_EXP_BIAS (1023) +/** The max exponent value for the RTFLOAT64U format. */ +#define RTFLOAT64U_EXP_MAX (2047) +/** The exponent bias overflow/underflow adjust for the RTFLOAT64U format. + * @note 754-1985 sec 7.3 & 7.4, not mentioned in later standard versions. */ +#define RTFLOAT64U_EXP_BIAS_ADJUST (1536) +/** Fraction width (in bits) for the RTFLOAT64U format. */ +#define RTFLOAT64U_FRACTION_BITS (52) +/** Check if two 64-bit floating values are identical (memcmp, not + * numerically). */ +#define RTFLOAT64U_ARE_IDENTICAL(a_pLeft, a_pRight) ((a_pLeft)->u == (a_pRight)->u) +/** @name RTFLOAT64U classification macros + * @{ */ +#define RTFLOAT64U_IS_ZERO(a_pr64) (((a_pr64)->u & (RT_BIT_64(63) - 1)) == 0) +#define RTFLOAT64U_IS_SUBNORMAL(a_pr64) ( (a_pr64)->s.uExponent == 0 \ + && ((a_pr64)->s.uFractionLow != 0 || (a_pr64)->s.uFractionHigh != 0) ) +#define RTFLOAT64U_IS_INF(a_pr64) ( (a_pr64)->s.uExponent == 0x7ff \ + && (a_pr64)->s.uFractionLow == 0 && (a_pr64)->s.uFractionHigh == 0) +#define RTFLOAT64U_IS_SIGNALLING_NAN(a_pr64) ( (a_pr64)->s.uExponent == 0x7ff \ + && !((a_pr64)->s.uFractionHigh & RT_BIT_32(19)) \ + && ((a_pr64)->s.uFractionHigh != 0 || (a_pr64)->s.uFractionLow != 0) ) +#define RTFLOAT64U_IS_QUIET_NAN(a_pr64) ((a_pr64)->s.uExponent == 0x7ff && ((a_pr64)->s.uFractionHigh & RT_BIT_32(19))) +#define RTFLOAT64U_IS_NAN(a_pr64) ( (a_pr64)->s.uExponent == 0x7ff \ + && ((a_pr64)->s.uFractionHigh != 0 || (a_pr64)->s.uFractionLow != 0) ) +#define RTFLOAT64U_IS_NORMAL(a_pr64) ((a_pr64)->s.uExponent > 0 && (a_pr64)->s.uExponent < 0x7ff) +/** @} */ + + + +#if !defined(__IBMCPP__) && !defined(__IBMC__) + +/** + * Extended Double precision floating point format (80-bit). + */ +# pragma pack(1) +typedef union RTFLOAT80U +{ + /** Format using bitfields. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN /** @todo big endian mapping is wrong. */ + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The mantissa. */ + uint64_t uMantissa; +# else + /** The mantissa. */ + uint64_t uMantissa; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; +# endif + } s; + + /** Format for accessing it as two separate components. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN /** @todo big endian mapping is wrong. */ + /** The sign bit and exponent. */ + uint16_t uSignAndExponent; + /** The mantissa. */ + uint64_t uMantissa; +# else + /** The mantissa. */ + uint64_t uMantissa; + /** The sign bit and exponent. */ + uint16_t uSignAndExponent; +# endif + } s2; + +# ifdef RT_COMPILER_GROKS_64BIT_BITFIELDS + /** 64-bit bitfields exposing the J bit and the fraction. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN /** @todo big endian mapping is wrong. */ + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The J bit, aka the integer bit. */ + RT_GCC_EXTENSION uint64_t fInteger : 1; + /** The fraction. */ + RT_GCC_EXTENSION uint64_t uFraction : 63; +# else + /** The fraction. */ + RT_GCC_EXTENSION uint64_t uFraction : 63; + /** The J bit, aka the integer bit. */ + RT_GCC_EXTENSION uint64_t fInteger : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; +# endif + } sj64; +# endif + + /** 64-bit view. */ + uint64_t au64[1]; + /** 32-bit view. */ + uint32_t au32[2]; + /** 16-bit view. */ + uint16_t au16[5]; + /** 8-bit view. */ + uint8_t au8[10]; +} RTFLOAT80U; +# pragma pack() +/** Pointer to a extended precision floating point format union. */ +typedef RTFLOAT80U RT_FAR *PRTFLOAT80U; +/** Pointer to a const extended precision floating point format union. */ +typedef const RTFLOAT80U RT_FAR *PCRTFLOAT80U; +/** RTFLOAT80U initializer. */ +# ifdef RT_BIG_ENDIAN +# define RTFLOAT80U_INIT(a_fSign, a_uMantissa, a_uExponent) { { (a_fSign), (a_uExponent), (a_uMantissa) } } +# else +# define RTFLOAT80U_INIT(a_fSign, a_uMantissa, a_uExponent) { { (a_uMantissa), (a_uExponent), (a_fSign) } } +# endif +# define RTFLOAT80U_INIT_C(a_fSign, a_uMantissa, a_uExponent) RTFLOAT80U_INIT((a_fSign), UINT64_C(a_uMantissa), (a_uExponent)) +# define RTFLOAT80U_INIT_ZERO(a_fSign) RTFLOAT80U_INIT((a_fSign), 0, 0) +# define RTFLOAT80U_INIT_INF(a_fSign) RTFLOAT80U_INIT((a_fSign), RT_BIT_64(63), RTFLOAT80U_EXP_MAX) +# define RTFLOAT80U_INIT_SIGNALLING_NAN(a_fSign) RTFLOAT80U_INIT_SNAN((a_fSign)) +# define RTFLOAT80U_INIT_SNAN(a_fSign) RTFLOAT80U_INIT((a_fSign), RT_BIT_64(63) | 1, RTFLOAT80U_EXP_MAX) +# define RTFLOAT80U_INIT_SNAN_EX(a_fSign, a_uVal) RTFLOAT80U_INIT((a_fSign), RT_BIT_64(63) | (a_uVal), RTFLOAT80U_EXP_MAX) +# define RTFLOAT80U_INIT_QUIET_NAN(a_fSign) RTFLOAT80U_INIT_QNAN((a_fSign)) +# define RTFLOAT80U_INIT_QNAN(a_fSign) RTFLOAT80U_INIT((a_fSign), RT_BIT_64(63) | RT_BIT_64(62), RTFLOAT80U_EXP_MAX) +# define RTFLOAT80U_INIT_QNAN_EX(a_fSign, a_uVal) RTFLOAT80U_INIT((a_fSign), RT_BIT_64(63) | RT_BIT_64(62) | (a_uVal), RTFLOAT80U_EXP_MAX) +#define RTFLOAT80U_INIT_NAN_EX(a_fQuiet, a_fSign, a_uVal) \ + RTFLOAT80U_INIT((a_fSign), \ + ((a_uVal) || (a_fQuiet) ? (a_uVal) : UINT64_C(1)) | ((a_fQuiet) ? RT_BIT_64(63) | RT_BIT_64(62) : RT_BIT_64(63)), \ + RTFLOAT80U_EXP_MAX) +# define RTFLOAT80U_INIT_INDEFINITE(a_fSign) RTFLOAT80U_INIT((a_fSign), RT_BIT_64(63) | RT_BIT_64(62), RTFLOAT80U_EXP_MAX) +# define RTFLOAT80U_INIT_IND(a_fSign) RTFLOAT80U_INIT_INDEFINITE(a_fSign) +/** The exponent bias for the RTFLOAT80U format. */ +# define RTFLOAT80U_EXP_BIAS (16383) +/** The max exponent value for the RTFLOAT80U format. */ +# define RTFLOAT80U_EXP_MAX (32767) +/** The exponent bias overflow/underflow adjust for the RTFLOAT80U format. + * @note 754-1985 sec 7.3 & 7.4, not mentioned in later standard versions. */ +# define RTFLOAT80U_EXP_BIAS_ADJUST (24576) +/** Fraction width (in bits) for the RTFLOAT80U format. */ +# define RTFLOAT80U_FRACTION_BITS (63) +/** Check if two 80-bit floating values are identical (memcmp, not + * numberically). */ +# define RTFLOAT80U_ARE_IDENTICAL(a_pLeft, a_pRight) \ + ( (a_pLeft)->au64[0] == (a_pRight)->au64[0] \ + && (a_pLeft)->au16[4] == (a_pRight)->au16[4] ) +/** @name RTFLOAT80U classification macros + * @{ */ +/** Is @a a_pr80 +0 or -0. */ +# define RTFLOAT80U_IS_ZERO(a_pr80) RTFLOAT80U_IS_ZERO_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_ZERO_EX(a_uMantissa, a_uExponent) \ + ((a_uExponent) == 0 && (a_uMantissa) == 0) +/** Is @a a_pr80 a denormal (does not match psuedo-denormal). */ +# define RTFLOAT80U_IS_DENORMAL(a_pr80) RTFLOAT80U_IS_DENORMAL_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_DENORMAL_EX(a_uMantissa, a_uExponent) \ + ((a_uExponent) == 0 && (a_uMantissa) < RT_BIT_64(63) && (a_uMantissa) != 0) +/** Is @a a_pr80 a pseudo-denormal. */ +# define RTFLOAT80U_IS_PSEUDO_DENORMAL(a_pr80) RTFLOAT80U_IS_PSEUDO_DENORMAL_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_PSEUDO_DENORMAL_EX(a_uMantissa, a_uExponent) \ + ((a_uExponent) == 0 && (a_uMantissa) >= RT_BIT_64(63)) +/** Is @a a_pr80 denormal or pseudo-denormal. */ +# define RTFLOAT80U_IS_DENORMAL_OR_PSEUDO_DENORMAL(a_pr80) \ + RTFLOAT80U_IS_DENORMAL_OR_PSEUDO_DENORMAL_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_DENORMAL_OR_PSEUDO_DENORMAL_EX(a_uMantissa, a_uExponent) ((a_uExponent) == 0 && (a_uMantissa) != 0) +/** Is @a a_pr80 +/-pseudo-infinity. */ +# define RTFLOAT80U_IS_PSEUDO_INF(a_pr80) RTFLOAT80U_IS_PSEUDO_INF_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_PSEUDO_INF_EX(a_uMantissa, a_uExponent) ((a_uExponent) == 0x7fff && (a_uMantissa) == 0) +/** Is @a a_pr80 pseudo-not-a-number. */ +# define RTFLOAT80U_IS_PSEUDO_NAN(a_pr80) RTFLOAT80U_IS_PSEUDO_NAN_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_PSEUDO_NAN_EX(a_uMantissa, a_uExponent) ((a_uExponent) == 0x7fff && !((a_uMantissa) & RT_BIT_64(63))) +/** Is @a a_pr80 infinity (does not match pseudo-infinity). */ +# define RTFLOAT80U_IS_INF(a_pr80) RTFLOAT80U_IS_INF_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_INF_EX(a_uMantissa, a_uExponent) ((a_uExponent) == 0x7fff && (a_uMantissa) == RT_BIT_64(63)) +/** Is @a a_pr80 a signalling not-a-number value. */ +# define RTFLOAT80U_IS_SIGNALLING_NAN(a_pr80) RTFLOAT80U_IS_SIGNALLING_NAN_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_SIGNALLING_NAN_EX(a_uMantissa, a_uExponent) \ + ( (a_uExponent) == 0x7fff \ + && ((a_uMantissa) & (RT_BIT_64(63) | RT_BIT_64(62))) == RT_BIT_64(63) \ + && ((a_uMantissa) & (RT_BIT_64(62) - 1)) != 0) +/** Is @a a_pr80 a quiet not-a-number value. */ +# define RTFLOAT80U_IS_QUIET_NAN(a_pr80) RTFLOAT80U_IS_QUIET_NAN_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_QUIET_NAN_EX(a_uMantissa, a_uExponent) \ + ( (a_uExponent) == 0x7fff \ + && ((a_uMantissa) & (RT_BIT_64(63) | RT_BIT_64(62))) == (RT_BIT_64(63) | RT_BIT_64(62)) \ + && ((a_uMantissa) & (RT_BIT_64(62) - 1)) != 0) +/** Is @a a_pr80 Signalling-, Quiet- or Pseudo-NaN. */ +# define RTFLOAT80U_IS_NAN(a_pr80) RTFLOAT80U_IS_NAN_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_NAN_EX(a_uMantissa, a_uExponent) ((a_uExponent) == 0x7fff && ((a_uMantissa) & (RT_BIT_64(63) - 1)) != 0) +/** Is @a a_pr80 Signalling- or Quiet-Nan, but not Pseudo-NaN. */ +# define RTFLOAT80U_IS_QUIET_OR_SIGNALLING_NAN(a_pr80) \ + RTFLOAT80U_IS_QUIET_OR_SIGNALLING_NAN_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_QUIET_OR_SIGNALLING_NAN_EX(a_uMantissa, a_uExponent) \ + ((a_uExponent) == 0x7fff && ((a_uMantissa) > RT_BIT_64(63))) +/** Is @a a_pr80 indefinite (ignoring sign). */ +# define RTFLOAT80U_IS_INDEFINITE(a_pr80) RTFLOAT80U_IS_INDEFINITE_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_INDEFINITE_EX(a_uMantissa, a_uExponent) \ + ((a_uExponent) == 0x7fff && (a_uMantissa) == (RT_BIT_64(63) | RT_BIT_64(62))) +/** Is @a a_pr80 Indefinite, Signalling- or Quiet-Nan, but not Pseudo-NaN (nor Infinity). */ +# define RTFLOAT80U_IS_INDEFINITE_OR_QUIET_OR_SIGNALLING_NAN(a_pr80) \ + RTFLOAT80U_IS_INDEFINITE_OR_QUIET_OR_SIGNALLING_NAN_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_INDEFINITE_OR_QUIET_OR_SIGNALLING_NAN_EX(a_uMantissa, a_uExponent) \ + ((a_uExponent) == 0x7fff && (a_uMantissa) > RT_BIT_64(63)) +/** Is @a a_pr80 an unnormal value (invalid operand on 387+). */ +# define RTFLOAT80U_IS_UNNORMAL(a_pr80) RTFLOAT80U_IS_UNNORMAL_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_UNNORMAL_EX(a_uMantissa, a_uExponent) \ + (!((a_uMantissa) & RT_BIT_64(63)) && (a_uExponent) > 0 && (a_uExponent) < 0x7fff) /* a_uExponent can be signed and up to 64-bit wide */ +/** Is @a a_pr80 a normal value (excludes zero). */ +# define RTFLOAT80U_IS_NORMAL(a_pr80) RTFLOAT80U_IS_NORMAL_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +# define RTFLOAT80U_IS_NORMAL_EX(a_uMantissa, a_uExponent) \ + (((a_uMantissa) & RT_BIT_64(63)) && (a_uExponent) > 0 && (a_uExponent) < 0x7fff) /* a_uExponent can be signed and up to 64-bit wide */ +/** Invalid 387 (and later) operands: Pseudo-Infinity, Psuedo-NaN, Unnormals. */ +#define RTFLOAT80U_IS_387_INVALID(a_pr80) RTFLOAT80U_IS_387_INVALID_EX((a_pr80)->s.uMantissa, (a_pr80)->s.uExponent) +#define RTFLOAT80U_IS_387_INVALID_EX(a_uMantissa, a_uExponent) \ + (!((a_uMantissa) & RT_BIT_64(63)) && (a_uExponent) > 0) +/** @} */ + + +/** + * A variant of RTFLOAT80U that may be larger than 80-bits depending on how the + * compiler implements long double. + * + * @note On AMD64 systems implementing the System V ABI, this will be 16 bytes! + * The last 6 bytes are unused padding taken up by the long double view. + */ +# pragma pack(1) +typedef union RTFLOAT80U2 +{ + /** Format using bitfields. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN /** @todo big endian mapping is wrong. */ + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The mantissa. */ + uint64_t uMantissa; +# else + /** The mantissa. */ + uint64_t uMantissa; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; +# endif + } s; + + /** Format for accessing it as two separate components. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN /** @todo big endian mapping is wrong. */ + /** The sign bit and exponent. */ + uint16_t uSignAndExponent; + /** The mantissa. */ + uint64_t uMantissa; +# else + /** The mantissa. */ + uint64_t uMantissa; + /** The sign bit and exponent. */ + uint16_t uSignAndExponent; +# endif + } s2; + + /** Bitfield exposing the J bit and the fraction. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN /** @todo big endian mapping is wrong. */ + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The J bit, aka the integer bit. */ + uint32_t fInteger : 1; + /** The fraction, bits 32 thru 62. */ + uint32_t uFractionHigh : 31; + /** The fraction, bits 0 thru 31. */ + uint32_t uFractionLow : 32; +# else + /** The fraction, bits 0 thru 31. */ + uint32_t uFractionLow : 32; + /** The fraction, bits 32 thru 62. */ + uint32_t uFractionHigh : 31; + /** The J bit, aka the integer bit. */ + uint32_t fInteger : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; +# endif + } sj; + +# ifdef RT_COMPILER_GROKS_64BIT_BITFIELDS + /** 64-bit bitfields exposing the J bit and the fraction. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN /** @todo big endian mapping is wrong. */ + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The J bit, aka the integer bit. */ + RT_GCC_EXTENSION uint64_t fInteger : 1; + /** The fraction. */ + RT_GCC_EXTENSION uint64_t uFraction : 63; +# else + /** The fraction. */ + RT_GCC_EXTENSION uint64_t uFraction : 63; + /** The J bit, aka the integer bit. */ + RT_GCC_EXTENSION uint64_t fInteger : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint16_t uExponent : 15; + /** The sign indicator. */ + RT_GCC_EXTENSION uint16_t fSign : 1; +# endif + } sj64; +# endif + +# ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE + /** Long double view. */ + long double lrd, r; +# endif + /** 64-bit view. */ + uint64_t au64[1]; + /** 32-bit view. */ + uint32_t au32[2]; + /** 16-bit view. */ + uint16_t au16[5]; + /** 8-bit view. */ + uint8_t au8[10]; +} RTFLOAT80U2; +# pragma pack() +/** Pointer to a extended precision floating point format union, 2nd + * variant. */ +typedef RTFLOAT80U2 RT_FAR *PRTFLOAT80U2; +/** Pointer to a const extended precision floating point format union, 2nd + * variant. */ +typedef const RTFLOAT80U2 RT_FAR *PCRTFLOAT80U2; + +#endif /* uint16_t bitfields doesn't work */ + + +/** + * Quadruple precision floating point format (128-bit). + */ +typedef union RTFLOAT128U +{ + /** Format using regular bitfields. */ + struct + { +# ifdef RT_BIG_ENDIAN + /** The sign indicator. */ + uint32_t fSign : 1; + /** The exponent (offsetted by 16383). */ + uint32_t uExponent : 15; + /** The fraction, bits 96 thru 111. */ + uint32_t uFractionHigh : 16; + /** The fraction, bits 64 thru 95. */ + uint32_t uFractionMid; + /** The fraction, bits 0 thru 63. */ + uint64_t uFractionLow; +# else + /** The fraction, bits 0 thru 63. */ + uint64_t uFractionLow; + /** The fraction, bits 64 thru 95. */ + uint32_t uFractionMid; + /** The fraction, bits 96 thru 111. */ + uint32_t uFractionHigh : 16; + /** The exponent (offsetted by 16383). */ + uint32_t uExponent : 15; + /** The sign indicator. */ + uint32_t fSign : 1; +# endif + } s; + + /** Format for accessing it as two separate components. */ + struct + { +# ifdef RT_BIG_ENDIAN + /** The sign bit and exponent. */ + uint16_t uSignAndExponent; + /** The fraction, bits 96 thru 111. */ + uint16_t uFractionHigh; + /** The fraction, bits 64 thru 95. */ + uint32_t uFractionMid; + /** The fraction, bits 0 thru 63. */ + uint64_t uFractionLow; +# else + /** The fraction, bits 0 thru 63. */ + uint64_t uFractionLow; + /** The fraction, bits 64 thru 95. */ + uint32_t uFractionMid; + /** The fraction, bits 96 thru 111. */ + uint16_t uFractionHigh; + /** The sign bit and exponent. */ + uint16_t uSignAndExponent; +# endif + } s2; + +#ifdef RT_COMPILER_GROKS_64BIT_BITFIELDS + /** Format using 64-bit bitfields. */ + RT_GCC_EXTENSION struct + { +# ifdef RT_BIG_ENDIAN + /** The sign indicator. */ + RT_GCC_EXTENSION uint64_t fSign : 1; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint64_t uExponent : 15; + /** The fraction, bits 64 thru 111. */ + RT_GCC_EXTENSION uint64_t uFractionHi : 48; + /** The fraction, bits 0 thru 63. */ + uint64_t uFractionLo; +# else + /** The fraction, bits 0 thru 63. */ + uint64_t uFractionLo; + /** The fraction, bits 64 thru 111. */ + RT_GCC_EXTENSION uint64_t uFractionHi : 48; + /** The exponent (offsetted by 16383). */ + RT_GCC_EXTENSION uint64_t uExponent : 15; + /** The sign indicator. */ + RT_GCC_EXTENSION uint64_t fSign : 1; +# endif + } s64; +#endif + +#ifdef RT_COMPILER_WITH_128BIT_LONG_DOUBLE + /** Long double view. */ + long double lrd, r; +#endif + /** 128-bit view. */ + RTUINT128U u128; + /** 64-bit view. */ + uint64_t au64[2]; + /** 32-bit view. */ + uint32_t au32[4]; + /** 16-bit view. */ + uint16_t au16[8]; + /** 8-bit view. */ + uint8_t au8[16]; +} RTFLOAT128U; +/** Pointer to a quadruple precision floating point format union. */ +typedef RTFLOAT128U RT_FAR *PRTFLOAT128U; +/** Pointer to a const quadruple precision floating point format union. */ +typedef const RTFLOAT128U RT_FAR *PCRTFLOAT128U; +/** RTFLOAT128U initializer. */ +#ifdef RT_BIG_ENDIAN +# define RTFLOAT128U_INIT(a_fSign, a_uFractionHi, a_uFractionLo, a_uExponent) \ + { { (a_fSign), (a_uExponent), (uint32_t)((a_uFractionHi) >> 32), (uint32_t)((a_uFractionHi) & UINT32_MAX), (a_uFractionLo) } } +#else +# define RTFLOAT128U_INIT(a_fSign, a_uFractionHi, a_uFractionLo, a_uExponent) \ + { { (a_uFractionLo), (uint32_t)((a_uFractionHi) & UINT32_MAX), (uint32_t)((a_uFractionHi) >> 32), (a_uExponent), (a_fSign) } } +#endif +#define RTFLOAT128U_INIT_C(a_fSign, a_uFractionHi, a_uFractionLo, a_uExponent) \ + RTFLOAT128U_INIT((a_fSign), UINT64_C(a_uFractionHi), UINT64_C(a_uFractionLo), (a_uExponent)) + +#define RTFLOAT128U_INIT_ZERO(a_fSign) RTFLOAT128U_INIT((a_fSign), UINT64_C(0), UINT64_C(0), 0) +#define RTFLOAT128U_INIT_INF(a_fSign) RTFLOAT128U_INIT((a_fSign), UINT64_C(0), UINT64_C(0), RTFLOAT128U_EXP_MAX) +#define RTFLOAT128U_INIT_SNAN(a_fSign) RTFLOAT128U_INIT((a_fSign), UINT64_C(0), UINT64_C(1), RTFLOAT128U_EXP_MAX) +#define RTFLOAT128U_INIT_SNAN_EX(a_fSign, a_uValHi, a_uValLo) \ + RTFLOAT128U_INIT((a_fSign), (a_uValHi), (a_uValHi) || (a_uValLo) ? (a_uValLo) : UINT64_C(1), RTFLOAT128U_EXP_MAX) +#define RTFLOAT128U_INIT_SIGNALLING_NAN(a_fSign) RTFLOAT128U_INIT_SNAN(a_fSign) +#define RTFLOAT128U_INIT_QNAN(a_fSign) \ + RTFLOAT128U_INIT((a_fSign), RT_BIT_64(RTFLOAT128U_FRACTION_BITS - 1 - 64), UINT64_C(0), RTFLOAT128U_EXP_MAX) +#define RTFLOAT128U_INIT_QNAN_EX(a_fSign, a_uValHi, a_uValLo) \ + RTFLOAT128U_INIT((a_fSign), RT_BIT_64(RTFLOAT128U_FRACTION_BITS - 1 - 64) | (a_uValHi), (a_uValLo), RTFLOAT128U_EXP_MAX) +#define RTFLOAT128U_INIT_QUIET_NAN(a_fSign) RTFLOAT128U_INIT_QNAN(a_fSign) +#define RTFLOAT128U_INIT_NAN_EX(a_fQuiet, a_fSign, a_uValHi, a_uValLo) \ + RTFLOAT128U_INIT((a_fSign), \ + ((a_fQuiet) ? RT_BIT_64(RTFLOAT128U_FRACTION_BITS - 1 - 64) : 0) | (a_uValHi), \ + (a_uValLo) || (a_uValHi) || (a_fQuiet) ? (a_uValLo) : UINT64_C(1), \ + RTFLOAT128U_EXP_MAX) + +/** The exponent bias for the RTFLOAT128U format. */ +#define RTFLOAT128U_EXP_BIAS (16383) +/** The max exponent value for the RTFLOAT128U format. */ +#define RTFLOAT128U_EXP_MAX (32767) +/** The exponent bias overflow/underflow adjust for the RTFLOAT128U format. + * @note This is stipulated based on RTFLOAT80U, it doesn't appear in any + * standard text as far as we know. */ +#define RTFLOAT128U_EXP_BIAS_ADJUST (24576) +/** Fraction width (in bits) for the RTFLOAT128U format. */ +#define RTFLOAT128U_FRACTION_BITS (112) +/** Check if two 128-bit floating values are identical (memcmp, not + * numerically). */ +#define RTFLOAT128U_ARE_IDENTICAL(a_pLeft, a_pRight) \ + ( (a_pLeft)->au64[0] == (a_pRight)->au64[0] && (a_pLeft)->au64[1] == (a_pRight)->au64[1] ) +/** @name RTFLOAT128U classification macros + * @{ */ +#define RTFLOAT128U_IS_ZERO(a_pr128) ( (a_pr128)->u128.s.Lo == 0 \ + && ((a_pr128)->u128.s.Hi & (RT_BIT_64(63) - 1)) == 0) +#define RTFLOAT128U_IS_SUBNORMAL(a_pr128) ( (a_pr128)->s.uExponent == 0 \ + && ( (a_pr128)->s.uFractionLow != 0 \ + || (a_pr128)->s.uFractionMid != 0 \ + || (a_pr128)->s.uFractionHigh != 0 ) ) +#define RTFLOAT128U_IS_INF(a_pr128) ( (a_pr128)->s.uExponent == RTFLOAT128U_EXP_MAX \ + && (a_pr128)->s.uFractionHigh == 0 \ + && (a_pr128)->s.uFractionMid == 0 \ + && (a_pr128)->s.uFractionLow == 0 ) +#define RTFLOAT128U_IS_SIGNALLING_NAN(a_pr128) ( (a_pr128)->s.uExponent == RTFLOAT128U_EXP_MAX \ + && !((a_pr128)->s.uFractionHigh & RT_BIT_32(15)) \ + && ( (a_pr128)->s.uFractionHigh != 0 \ + || (a_pr128)->s.uFractionMid != 0 \ + || (a_pr128)->s.uFractionLow != 0) ) +#define RTFLOAT128U_IS_QUIET_NAN(a_pr128) ( (a_pr128)->s.uExponent == RTFLOAT128U_EXP_MAX \ + && ((a_pr128)->s.uFractionHigh & RT_BIT_32(15))) +#define RTFLOAT128U_IS_NAN(a_pr128) ( (a_pr128)->s.uExponent == RTFLOAT128U_EXP_MAX \ + && ( (a_pr128)->s.uFractionLow != 0 \ + || (a_pr128)->s.uFractionMid != 0 \ + || (a_pr128)->s.uFractionHigh != 0) ) +#define RTFLOAT128U_IS_NORMAL(a_pr128) ((a_pr128)->s.uExponent > 0 && (a_pr128)->s.uExponent < RTFLOAT128U_EXP_MAX) +/** @} */ + + +/** + * Packed BCD 18-digit signed integer format (80-bit). + */ +#pragma pack(1) +typedef union RTPBCD80U +{ + /** Format using bitfields. */ + RT_GCC_EXTENSION struct + { + /** 18 packed BCD digits, two to a byte. */ + uint8_t abPairs[9]; + /** Padding, non-zero if indefinite. */ + RT_GCC_EXTENSION uint8_t uPad : 7; + /** The sign indicator. */ + RT_GCC_EXTENSION uint8_t fSign : 1; + } s; + + /** 64-bit view. */ + uint64_t au64[1]; + /** 32-bit view. */ + uint32_t au32[2]; + /** 16-bit view. */ + uint16_t au16[5]; + /** 8-bit view. */ + uint8_t au8[10]; +} RTPBCD80U; +#pragma pack() +/** Pointer to a packed BCD integer format union. */ +typedef RTPBCD80U RT_FAR *PRTPBCD80U; +/** Pointer to a const packed BCD integer format union. */ +typedef const RTPBCD80U RT_FAR *PCRTPBCD80U; +/** RTPBCD80U initializer. */ +#define RTPBCD80U_INIT_C(a_fSign, a_D17, a_D16, a_D15, a_D14, a_D13, a_D12, a_D11, a_D10, \ + a_D9, a_D8, a_D7, a_D6, a_D5, a_D4, a_D3, a_D2, a_D1, a_D0) \ + RTPBCD80U_INIT_EX_C(0, a_fSign, a_D17, a_D16, a_D15, a_D14, a_D13, a_D12, a_D11, a_D10, \ + a_D9, a_D8, a_D7, a_D6, a_D5, a_D4, a_D3, a_D2, a_D1, a_D0) +/** Extended RTPBCD80U initializer. */ +#define RTPBCD80U_INIT_EX_C(a_uPad, a_fSign, a_D17, a_D16, a_D15, a_D14, a_D13, a_D12, a_D11, a_D10, \ + a_D9, a_D8, a_D7, a_D6, a_D5, a_D4, a_D3, a_D2, a_D1, a_D0) \ + { { { RTPBCD80U_MAKE_PAIR(a_D1, a_D0), \ + RTPBCD80U_MAKE_PAIR(a_D3, a_D2), \ + RTPBCD80U_MAKE_PAIR(a_D5, a_D4), \ + RTPBCD80U_MAKE_PAIR(a_D7, a_D6), \ + RTPBCD80U_MAKE_PAIR(a_D9, a_D8), \ + RTPBCD80U_MAKE_PAIR(a_D11, a_D10), \ + RTPBCD80U_MAKE_PAIR(a_D13, a_D12), \ + RTPBCD80U_MAKE_PAIR(a_D15, a_D14), \ + RTPBCD80U_MAKE_PAIR(a_D17, a_D16), }, (a_uPad), (a_fSign) } } +/** RTPBCD80U initializer for the zero value. */ +#define RTPBCD80U_INIT_ZERO(a_fSign) RTPBCD80U_INIT_C(a_fSign, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0) +/** RTPBCD80U initializer for the indefinite value. */ +#define RTPBCD80U_INIT_INDEFINITE() RTPBCD80U_INIT_EX_C(0x7f,1, 0xf,0xf, 0xc,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0) +/** RTPBCD80U initializer for the minimum value. */ +#define RTPBCD80U_INIT_MIN() RTPBCD80U_INIT_C(1, 9,9, 9,9, 9,9, 9,9, 9,9, 9,9, 9,9, 9,9, 9,9) +/** RTPBCD80U initializer for the maximum value. */ +#define RTPBCD80U_INIT_MAX() RTPBCD80U_INIT_C(0, 9,9, 9,9, 9,9, 9,9, 9,9, 9,9, 9,9, 9,9, 9,9) +/** RTPBCD80U minimum value. */ +#define RTPBCD80U_MIN INT64_C(-999999999999999999) +/** RTPBCD80U maximum value. */ +#define RTPBCD80U_MAX INT64_C(999999999999999999) +/** Makes a packs a pair of BCD digits. */ +#define RTPBCD80U_MAKE_PAIR(a_D1, a_D0) ((a_D0) | ((a_D1) << 4)) +/** Retrieves the lower digit of a BCD digit pair. */ +#define RTPBCD80U_LO_DIGIT(a_bPair) ((a_bPair) & 0xf) +/** Retrieves the higher digit of a BCD digit pair. */ +#define RTPBCD80U_HI_DIGIT(a_bPair) ((a_bPair) >> 4) +/** Checks if the packaged BCD number is representing indefinite. */ +#define RTPBCD80U_IS_INDEFINITE(a_pd80) \ + ( (a_pd80)->s.uPad == 0x7f \ + && (a_pd80)->s.fSign == 1 \ + && (a_pd80)->s.abPairs[8] == 0xff \ + && (a_pd80)->s.abPairs[7] == RTPBCD80U_MAKE_PAIR(0xc, 0) \ + && (a_pd80)->s.abPairs[6] == 0 \ + && (a_pd80)->s.abPairs[5] == 0 \ + && (a_pd80)->s.abPairs[4] == 0 \ + && (a_pd80)->s.abPairs[3] == 0 \ + && (a_pd80)->s.abPairs[2] == 0 \ + && (a_pd80)->s.abPairs[1] == 0 \ + && (a_pd80)->s.abPairs[0] == 0) +/** Check if @a a_pd80Left and @a a_pd80Right are exactly the same. */ +#define RTPBCD80U_ARE_IDENTICAL(a_pd80Left, a_pd80Right) \ + ( (a_pd80Left)->au64[0] == (a_pd80Right)->au64[0] && (a_pd80Left)->au16[4] == (a_pd80Right)->au16[4] ) + + +/** Generic function type. + * @see PFNRT + */ +typedef DECLCALLBACKTYPE(void, FNRT,(void)); + +/** Generic function pointer. + * With -pedantic, gcc-4 complains when casting a function to a data object, for + * example: + * + * @code + * void foo(void) + * { + * } + * + * void *bar = (void *)foo; + * @endcode + * + * The compiler would warn with "ISO C++ forbids casting between + * pointer-to-function and pointer-to-object". The purpose of this warning is + * not to bother the programmer but to point out that he is probably doing + * something dangerous, assigning a pointer to executable code to a data object. + */ +typedef FNRT *PFNRT; + +/** Variant on PFNRT that takes one pointer argument. */ +typedef DECLCALLBACKTYPE(void, FNRT1,(void *pvArg)); +/** Pointer to FNRT1. */ +typedef FNRT1 *PFNRT1; + +/** Millisecond interval. */ +typedef uint32_t RTMSINTERVAL; +/** Pointer to a millisecond interval. */ +typedef RTMSINTERVAL RT_FAR *PRTMSINTERVAL; +/** Pointer to a const millisecond interval. */ +typedef const RTMSINTERVAL RT_FAR *PCRTMSINTERVAL; + +/** Pointer to a time spec structure. */ +typedef struct RTTIMESPEC RT_FAR *PRTTIMESPEC; +/** Pointer to a const time spec structure. */ +typedef const struct RTTIMESPEC RT_FAR *PCRTTIMESPEC; + + + +/** @defgroup grp_rt_types_both Common Guest and Host Context Basic Types + * @{ + */ + +/** Signed integer which can contain both GC and HC pointers. */ +#if (HC_ARCH_BITS == 32 && GC_ARCH_BITS == 32) || (HC_ARCH_BITS == 16 || GC_ARCH_BITS == 16) +typedef int32_t RTINTPTR; +#elif (HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64) +typedef int64_t RTINTPTR; +#else +# error Unsupported HC_ARCH_BITS and/or GC_ARCH_BITS values. +#endif +/** Pointer to signed integer which can contain both GC and HC pointers. */ +typedef RTINTPTR RT_FAR *PRTINTPTR; +/** Pointer const to signed integer which can contain both GC and HC pointers. */ +typedef const RTINTPTR RT_FAR *PCRTINTPTR; +/** The maximum value the RTINTPTR type can hold. */ +#if (HC_ARCH_BITS == 32 && GC_ARCH_BITS == 32) || (HC_ARCH_BITS == 16 || GC_ARCH_BITS == 16) +# define RTINTPTR_MAX INT32_MAX +#elif (HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64) +# define RTINTPTR_MAX INT64_MAX +#else +# error Unsupported HC_ARCH_BITS and/or GC_ARCH_BITS values. +#endif +/** The minimum value the RTINTPTR type can hold. */ +#if (HC_ARCH_BITS == 32 && GC_ARCH_BITS == 32) || (HC_ARCH_BITS == 16 || GC_ARCH_BITS == 16) +# define RTINTPTR_MIN INT32_MIN +#elif (HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64) +# define RTINTPTR_MIN INT64_MIN +#else +# error Unsupported HC_ARCH_BITS and/or GC_ARCH_BITS values. +#endif + +/** Unsigned integer which can contain both GC and HC pointers. */ +#if (HC_ARCH_BITS == 32 && GC_ARCH_BITS == 32) || (HC_ARCH_BITS == 16 || GC_ARCH_BITS == 16) +typedef uint32_t RTUINTPTR; +#elif (HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64) +typedef uint64_t RTUINTPTR; +#else +# error Unsupported HC_ARCH_BITS and/or GC_ARCH_BITS values. +#endif +/** Pointer to unsigned integer which can contain both GC and HC pointers. */ +typedef RTUINTPTR RT_FAR *PRTUINTPTR; +/** Pointer const to unsigned integer which can contain both GC and HC pointers. */ +typedef const RTUINTPTR RT_FAR *PCRTUINTPTR; +/** The maximum value the RTUINTPTR type can hold. */ +#if (HC_ARCH_BITS == 32 && GC_ARCH_BITS == 32) || (HC_ARCH_BITS == 16 || GC_ARCH_BITS == 16) +# define RTUINTPTR_MAX UINT32_MAX +#elif (HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64) +# define RTUINTPTR_MAX UINT64_MAX +#else +# error Unsupported HC_ARCH_BITS and/or GC_ARCH_BITS values. +#endif + +/** Signed integer. */ +typedef int32_t RTINT; +/** Pointer to signed integer. */ +typedef RTINT RT_FAR *PRTINT; +/** Pointer to const signed integer. */ +typedef const RTINT RT_FAR *PCRTINT; + +/** Unsigned integer. */ +typedef uint32_t RTUINT; +/** Pointer to unsigned integer. */ +typedef RTUINT RT_FAR *PRTUINT; +/** Pointer to const unsigned integer. */ +typedef const RTUINT RT_FAR *PCRTUINT; + +/** A file offset / size (off_t). */ +typedef int64_t RTFOFF; +/** Pointer to a file offset / size. */ +typedef RTFOFF RT_FAR *PRTFOFF; +/** The max value for RTFOFF. */ +#define RTFOFF_MAX INT64_MAX +/** The min value for RTFOFF. */ +#define RTFOFF_MIN INT64_MIN + +/** File mode (see iprt/fs.h). */ +typedef uint32_t RTFMODE; +/** Pointer to file mode. */ +typedef RTFMODE RT_FAR *PRTFMODE; + +/** Device unix number. */ +typedef uint32_t RTDEV; +/** Pointer to a device unix number. */ +typedef RTDEV RT_FAR *PRTDEV; + +/** @name RTDEV Macros + * @{ */ +/** + * Our makedev macro. + * @returns RTDEV + * @param uMajor The major device number. + * @param uMinor The minor device number. + */ +#define RTDEV_MAKE(uMajor, uMinor) ((RTDEV)( ((RTDEV)(uMajor) << 24) | (uMinor & UINT32_C(0x00ffffff)) )) +/** + * Get the major device node number from an RTDEV type. + * @returns The major device number of @a uDev + * @param uDev The device number. + */ +#define RTDEV_MAJOR(uDev) ((uDev) >> 24) +/** + * Get the minor device node number from an RTDEV type. + * @returns The minor device number of @a uDev + * @param uDev The device number. + */ +#define RTDEV_MINOR(uDev) ((uDev) & UINT32_C(0x00ffffff)) +/** @} */ + +/** i-node number. */ +typedef uint64_t RTINODE; +/** Pointer to a i-node number. */ +typedef RTINODE RT_FAR *PRTINODE; + +/** User id. */ +typedef uint32_t RTUID; +/** Pointer to a user id. */ +typedef RTUID RT_FAR *PRTUID; +/** NIL user id. + * @todo check this for portability! */ +#define NIL_RTUID (~(RTUID)0) + +/** Group id. */ +typedef uint32_t RTGID; +/** Pointer to a group id. */ +typedef RTGID RT_FAR *PRTGID; +/** NIL group id. + * @todo check this for portability! */ +#define NIL_RTGID (~(RTGID)0) + +/** I/O Port. */ +typedef uint16_t RTIOPORT; +/** Pointer to I/O Port. */ +typedef RTIOPORT RT_FAR *PRTIOPORT; +/** Pointer to const I/O Port. */ +typedef const RTIOPORT RT_FAR *PCRTIOPORT; + +/** Selector. */ +typedef uint16_t RTSEL; +/** Pointer to selector. */ +typedef RTSEL RT_FAR *PRTSEL; +/** Pointer to const selector. */ +typedef const RTSEL RT_FAR *PCRTSEL; +/** Max selector value. */ +#define RTSEL_MAX UINT16_MAX + +/** Far 16-bit pointer. */ +#pragma pack(1) +typedef struct RTFAR16 +{ + uint16_t off; + RTSEL sel; +} RTFAR16; +#pragma pack() +/** Pointer to Far 16-bit pointer. */ +typedef RTFAR16 RT_FAR *PRTFAR16; +/** Pointer to const Far 16-bit pointer. */ +typedef const RTFAR16 RT_FAR *PCRTFAR16; + +/** Far 32-bit pointer. */ +#pragma pack(1) +typedef struct RTFAR32 +{ + uint32_t off; + RTSEL sel; +} RTFAR32; +#pragma pack() +/** Pointer to Far 32-bit pointer. */ +typedef RTFAR32 RT_FAR *PRTFAR32; +/** Pointer to const Far 32-bit pointer. */ +typedef const RTFAR32 RT_FAR *PCRTFAR32; + +/** Far 64-bit pointer. */ +#pragma pack(1) +typedef struct RTFAR64 +{ + uint64_t off; + RTSEL sel; +} RTFAR64; +#pragma pack() +/** Pointer to Far 64-bit pointer. */ +typedef RTFAR64 RT_FAR *PRTFAR64; +/** Pointer to const Far 64-bit pointer. */ +typedef const RTFAR64 RT_FAR *PCRTFAR64; + +/** @} */ + + +/** @defgroup grp_rt_types_hc Host Context Basic Types + * @{ + */ + +/** HC Natural signed integer. + * @deprecated silly type. */ +typedef int32_t RTHCINT; +/** Pointer to HC Natural signed integer. + * @deprecated silly type. */ +typedef RTHCINT RT_FAR *PRTHCINT; +/** Pointer to const HC Natural signed integer. + * @deprecated silly type. */ +typedef const RTHCINT RT_FAR *PCRTHCINT; + +/** HC Natural unsigned integer. + * @deprecated silly type. */ +typedef uint32_t RTHCUINT; +/** Pointer to HC Natural unsigned integer. + * @deprecated silly type. */ +typedef RTHCUINT RT_FAR *PRTHCUINT; +/** Pointer to const HC Natural unsigned integer. + * @deprecated silly type. */ +typedef const RTHCUINT RT_FAR *PCRTHCUINT; + + +/** Signed integer which can contain a HC pointer. */ +#if HC_ARCH_BITS == 32 || HC_ARCH_BITS == 16 +typedef int32_t RTHCINTPTR; +#elif HC_ARCH_BITS == 64 +typedef int64_t RTHCINTPTR; +#else +# error Unsupported HC_ARCH_BITS value. +#endif +/** Pointer to signed integer which can contain a HC pointer. */ +typedef RTHCINTPTR RT_FAR *PRTHCINTPTR; +/** Pointer to const signed integer which can contain a HC pointer. */ +typedef const RTHCINTPTR RT_FAR *PCRTHCINTPTR; +/** Max RTHCINTPTR value. */ +#if HC_ARCH_BITS == 32 +# define RTHCINTPTR_MAX INT32_MAX +#elif HC_ARCH_BITS == 64 +# define RTHCINTPTR_MAX INT64_MAX +#else +# define RTHCINTPTR_MAX INT16_MAX +#endif +/** Min RTHCINTPTR value. */ +#if HC_ARCH_BITS == 32 +# define RTHCINTPTR_MIN INT32_MIN +#elif HC_ARCH_BITS == 64 +# define RTHCINTPTR_MIN INT64_MIN +#else +# define RTHCINTPTR_MIN INT16_MIN +#endif + +/** Signed integer which can contain a HC ring-3 pointer. */ +#if R3_ARCH_BITS == 32 || R3_ARCH_BITS == 16 +typedef int32_t RTR3INTPTR; +#elif R3_ARCH_BITS == 64 +typedef int64_t RTR3INTPTR; +#else +# error Unsupported R3_ARCH_BITS value. +#endif +/** Pointer to signed integer which can contain a HC ring-3 pointer. */ +typedef RTR3INTPTR RT_FAR *PRTR3INTPTR; +/** Pointer to const signed integer which can contain a HC ring-3 pointer. */ +typedef const RTR3INTPTR RT_FAR *PCRTR3INTPTR; +/** Max RTR3INTPTR value. */ +#if R3_ARCH_BITS == 32 || R3_ARCH_BITS == 16 +# define RTR3INTPTR_MAX INT32_MAX +#else +# define RTR3INTPTR_MAX INT64_MAX +#endif +/** Min RTR3INTPTR value. */ +#if R3_ARCH_BITS == 32 || R3_ARCH_BITS == 16 +# define RTR3INTPTR_MIN INT32_MIN +#else +# define RTR3INTPTR_MIN INT64_MIN +#endif + +/** Signed integer which can contain a HC ring-0 pointer. */ +#if R0_ARCH_BITS == 32 || R0_ARCH_BITS == 16 +typedef int32_t RTR0INTPTR; +#elif R0_ARCH_BITS == 64 +typedef int64_t RTR0INTPTR; +#else +# error Unsupported R0_ARCH_BITS value. +#endif +/** Pointer to signed integer which can contain a HC ring-0 pointer. */ +typedef RTR0INTPTR RT_FAR *PRTR0INTPTR; +/** Pointer to const signed integer which can contain a HC ring-0 pointer. */ +typedef const RTR0INTPTR RT_FAR *PCRTR0INTPTR; +/** Max RTR0INTPTR value. */ +#if R0_ARCH_BITS == 32 || R0_ARCH_BITS == 16 +# define RTR0INTPTR_MAX INT32_MAX +#else +# define RTR0INTPTR_MAX INT64_MAX +#endif +/** Min RTHCINTPTR value. */ +#if R0_ARCH_BITS == 32 || R0_ARCH_BITS == 16 +# define RTR0INTPTR_MIN INT32_MIN +#else +# define RTR0INTPTR_MIN INT64_MIN +#endif + + +/** Unsigned integer which can contain a HC pointer. */ +#if HC_ARCH_BITS == 32 || HC_ARCH_BITS == 16 +typedef uint32_t RTHCUINTPTR; +#elif HC_ARCH_BITS == 64 +typedef uint64_t RTHCUINTPTR; +#else +# error Unsupported HC_ARCH_BITS value. +#endif +/** Pointer to unsigned integer which can contain a HC pointer. */ +typedef RTHCUINTPTR RT_FAR *PRTHCUINTPTR; +/** Pointer to unsigned integer which can contain a HC pointer. */ +typedef const RTHCUINTPTR RT_FAR *PCRTHCUINTPTR; +/** Max RTHCUINTTPR value. */ +#if HC_ARCH_BITS == 32 || HC_ARCH_BITS == 16 +# define RTHCUINTPTR_MAX UINT32_MAX +#else +# define RTHCUINTPTR_MAX UINT64_MAX +#endif + +/** Unsigned integer which can contain a HC ring-3 pointer. */ +#if R3_ARCH_BITS == 32 || R3_ARCH_BITS == 16 +typedef uint32_t RTR3UINTPTR; +#elif R3_ARCH_BITS == 64 +typedef uint64_t RTR3UINTPTR; +#else +# error Unsupported R3_ARCH_BITS value. +#endif +/** Pointer to unsigned integer which can contain a HC ring-3 pointer. */ +typedef RTR3UINTPTR RT_FAR *PRTR3UINTPTR; +/** Pointer to unsigned integer which can contain a HC ring-3 pointer. */ +typedef const RTR3UINTPTR RT_FAR *PCRTR3UINTPTR; +/** Max RTHCUINTTPR value. */ +#if R3_ARCH_BITS == 32 || R3_ARCH_BITS == 16 +# define RTR3UINTPTR_MAX UINT32_MAX +#else +# define RTR3UINTPTR_MAX UINT64_MAX +#endif + +/** Unsigned integer which can contain a HC ring-0 pointer. */ +#if R0_ARCH_BITS == 32 || R0_ARCH_BITS == 16 +typedef uint32_t RTR0UINTPTR; +#elif R0_ARCH_BITS == 64 +typedef uint64_t RTR0UINTPTR; +#else +# error Unsupported R0_ARCH_BITS value. +#endif +/** Pointer to unsigned integer which can contain a HC ring-0 pointer. */ +typedef RTR0UINTPTR RT_FAR *PRTR0UINTPTR; +/** Pointer to unsigned integer which can contain a HC ring-0 pointer. */ +typedef const RTR0UINTPTR RT_FAR *PCRTR0UINTPTR; +/** Max RTR0UINTTPR value. */ +#if R0_ARCH_BITS == 32 || R0_ARCH_BITS == 16 +# define RTR0UINTPTR_MAX UINT32_MAX +#else +# define RTR0UINTPTR_MAX UINT64_MAX +#endif + + +/** Host Physical Memory Address. */ +typedef uint64_t RTHCPHYS; +/** Pointer to Host Physical Memory Address. */ +typedef RTHCPHYS RT_FAR *PRTHCPHYS; +/** Pointer to const Host Physical Memory Address. */ +typedef const RTHCPHYS RT_FAR *PCRTHCPHYS; +/** @def NIL_RTHCPHYS + * NIL HC Physical Address. + * NIL_RTHCPHYS is used to signal an invalid physical address, similar + * to the NULL pointer. + */ +#define NIL_RTHCPHYS (~(RTHCPHYS)0) +/** Max RTHCPHYS value. */ +#define RTHCPHYS_MAX UINT64_MAX + + +/** HC pointer. */ +#if !defined(IN_RC) || defined(DOXYGEN_RUNNING) +typedef void RT_FAR *RTHCPTR; +#else +typedef RTHCUINTPTR RTHCPTR; +#endif +/** Pointer to HC pointer. */ +typedef RTHCPTR RT_FAR *PRTHCPTR; +/** Pointer to const HC pointer. */ +typedef const RTHCPTR *PCRTHCPTR; +/** @def NIL_RTHCPTR + * NIL HC pointer. + */ +#define NIL_RTHCPTR ((RTHCPTR)0) +/** Max RTHCPTR value. */ +#define RTHCPTR_MAX ((RTHCPTR)RTHCUINTPTR_MAX) + + +/** HC ring-3 pointer. */ +#ifdef IN_RING3 +typedef void RT_FAR *RTR3PTR; +#else +typedef RTR3UINTPTR RTR3PTR; +#endif +/** Pointer to HC ring-3 pointer. */ +typedef RTR3PTR RT_FAR *PRTR3PTR; +/** Pointer to const HC ring-3 pointer. */ +typedef const RTR3PTR *PCRTR3PTR; +/** @def NIL_RTR3PTR + * NIL HC ring-3 pointer. + */ +#ifndef IN_RING3 +# define NIL_RTR3PTR ((RTR3PTR)0) +#else +# define NIL_RTR3PTR (NULL) +#endif +/** Max RTR3PTR value. */ +#define RTR3PTR_MAX ((RTR3PTR)RTR3UINTPTR_MAX) + +/** HC ring-0 pointer. */ +#ifdef IN_RING0 +typedef void RT_FAR *RTR0PTR; +#else +typedef RTR0UINTPTR RTR0PTR; +#endif +/** Pointer to HC ring-0 pointer. */ +typedef RTR0PTR RT_FAR *PRTR0PTR; +/** Pointer to const HC ring-0 pointer. */ +typedef const RTR0PTR *PCRTR0PTR; +/** @def NIL_RTR0PTR + * NIL HC ring-0 pointer. + */ +#ifndef IN_RING0 +# define NIL_RTR0PTR ((RTR0PTR)0) +#else +# define NIL_RTR0PTR (NULL) +#endif +/** Max RTR3PTR value. */ +#define RTR0PTR_MAX ((RTR0PTR)RTR0UINTPTR_MAX) + + +/** Unsigned integer register in the host context. */ +#if HC_ARCH_BITS == 32 +typedef uint32_t RTHCUINTREG; +#elif HC_ARCH_BITS == 64 +typedef uint64_t RTHCUINTREG; +#elif HC_ARCH_BITS == 16 +typedef uint16_t RTHCUINTREG; +#else +# error "Unsupported HC_ARCH_BITS!" +#endif +/** Pointer to an unsigned integer register in the host context. */ +typedef RTHCUINTREG RT_FAR *PRTHCUINTREG; +/** Pointer to a const unsigned integer register in the host context. */ +typedef const RTHCUINTREG RT_FAR *PCRTHCUINTREG; + +/** Unsigned integer register in the host ring-3 context. */ +#if R3_ARCH_BITS == 32 +typedef uint32_t RTR3UINTREG; +#elif R3_ARCH_BITS == 64 +typedef uint64_t RTR3UINTREG; +#elif R3_ARCH_BITS == 16 +typedef uint16_t RTR3UINTREG; +#else +# error "Unsupported R3_ARCH_BITS!" +#endif +/** Pointer to an unsigned integer register in the host ring-3 context. */ +typedef RTR3UINTREG RT_FAR *PRTR3UINTREG; +/** Pointer to a const unsigned integer register in the host ring-3 context. */ +typedef const RTR3UINTREG RT_FAR *PCRTR3UINTREG; + +/** Unsigned integer register in the host ring-3 context. */ +#if R0_ARCH_BITS == 32 +typedef uint32_t RTR0UINTREG; +#elif R0_ARCH_BITS == 64 +typedef uint64_t RTR0UINTREG; +#elif R0_ARCH_BITS == 16 +typedef uint16_t RTR0UINTREG; +#else +# error "Unsupported R3_ARCH_BITS!" +#endif +/** Pointer to an unsigned integer register in the host ring-3 context. */ +typedef RTR0UINTREG RT_FAR *PRTR0UINTREG; +/** Pointer to a const unsigned integer register in the host ring-3 context. */ +typedef const RTR0UINTREG RT_FAR *PCRTR0UINTREG; + +/** @} */ + + +/** @defgroup grp_rt_types_gc Guest Context Basic Types + * @{ + */ + +/** Natural signed integer in the GC. + * @deprecated silly type. */ +#if GC_ARCH_BITS == 32 +typedef int32_t RTGCINT; +#elif GC_ARCH_BITS == 64 /** @todo this isn't right, natural int is 32-bit, see RTHCINT. */ +typedef int64_t RTGCINT; +#endif +/** Pointer to natural signed integer in GC. + * @deprecated silly type. */ +typedef RTGCINT RT_FAR *PRTGCINT; +/** Pointer to const natural signed integer in GC. + * @deprecated silly type. */ +typedef const RTGCINT RT_FAR *PCRTGCINT; + +/** Natural unsigned integer in the GC. + * @deprecated silly type. */ +#if GC_ARCH_BITS == 32 +typedef uint32_t RTGCUINT; +#elif GC_ARCH_BITS == 64 /** @todo this isn't right, natural int is 32-bit, see RTHCUINT. */ +typedef uint64_t RTGCUINT; +#endif +/** Pointer to natural unsigned integer in GC. + * @deprecated silly type. */ +typedef RTGCUINT RT_FAR *PRTGCUINT; +/** Pointer to const natural unsigned integer in GC. + * @deprecated silly type. */ +typedef const RTGCUINT RT_FAR *PCRTGCUINT; + +/** Signed integer which can contain a GC pointer. */ +#if GC_ARCH_BITS == 32 +typedef int32_t RTGCINTPTR; +#elif GC_ARCH_BITS == 64 +typedef int64_t RTGCINTPTR; +#endif +/** Pointer to signed integer which can contain a GC pointer. */ +typedef RTGCINTPTR RT_FAR *PRTGCINTPTR; +/** Pointer to const signed integer which can contain a GC pointer. */ +typedef const RTGCINTPTR RT_FAR *PCRTGCINTPTR; + +/** Unsigned integer which can contain a GC pointer. */ +#if GC_ARCH_BITS == 32 +typedef uint32_t RTGCUINTPTR; +#elif GC_ARCH_BITS == 64 +typedef uint64_t RTGCUINTPTR; +#else +# error Unsupported GC_ARCH_BITS value. +#endif +/** Pointer to unsigned integer which can contain a GC pointer. */ +typedef RTGCUINTPTR RT_FAR *PRTGCUINTPTR; +/** Pointer to unsigned integer which can contain a GC pointer. */ +typedef const RTGCUINTPTR RT_FAR *PCRTGCUINTPTR; + +/** Unsigned integer which can contain a 32 bits GC pointer. */ +typedef uint32_t RTGCUINTPTR32; +/** Pointer to unsigned integer which can contain a 32 bits GC pointer. */ +typedef RTGCUINTPTR32 RT_FAR *PRTGCUINTPTR32; +/** Pointer to unsigned integer which can contain a 32 bits GC pointer. */ +typedef const RTGCUINTPTR32 RT_FAR *PCRTGCUINTPTR32; + +/** Unsigned integer which can contain a 64 bits GC pointer. */ +typedef uint64_t RTGCUINTPTR64; +/** Pointer to unsigned integer which can contain a 32 bits GC pointer. */ +typedef RTGCUINTPTR64 RT_FAR *PRTGCUINTPTR64; +/** Pointer to unsigned integer which can contain a 32 bits GC pointer. */ +typedef const RTGCUINTPTR64 RT_FAR *PCRTGCUINTPTR64; + +/** Guest Physical Memory Address.*/ +typedef uint64_t RTGCPHYS; +/** Pointer to Guest Physical Memory Address. */ +typedef RTGCPHYS RT_FAR *PRTGCPHYS; +/** Pointer to const Guest Physical Memory Address. */ +typedef const RTGCPHYS RT_FAR *PCRTGCPHYS; +/** @def NIL_RTGCPHYS + * NIL GC Physical Address. + * NIL_RTGCPHYS is used to signal an invalid physical address, similar + * to the NULL pointer. Note that this value may actually be valid in + * some contexts. + */ +#define NIL_RTGCPHYS (~(RTGCPHYS)0U) +/** Max guest physical memory address value. */ +#define RTGCPHYS_MAX UINT64_MAX + + +/** Guest Physical Memory Address; limited to 32 bits.*/ +typedef uint32_t RTGCPHYS32; +/** Pointer to Guest Physical Memory Address. */ +typedef RTGCPHYS32 RT_FAR *PRTGCPHYS32; +/** Pointer to const Guest Physical Memory Address. */ +typedef const RTGCPHYS32 RT_FAR *PCRTGCPHYS32; +/** @def NIL_RTGCPHYS32 + * NIL GC Physical Address. + * NIL_RTGCPHYS32 is used to signal an invalid physical address, similar + * to the NULL pointer. Note that this value may actually be valid in + * some contexts. + */ +#define NIL_RTGCPHYS32 (~(RTGCPHYS32)0) + + +/** Guest Physical Memory Address; limited to 64 bits.*/ +typedef uint64_t RTGCPHYS64; +/** Pointer to Guest Physical Memory Address. */ +typedef RTGCPHYS64 RT_FAR *PRTGCPHYS64; +/** Pointer to const Guest Physical Memory Address. */ +typedef const RTGCPHYS64 RT_FAR *PCRTGCPHYS64; +/** @def NIL_RTGCPHYS64 + * NIL GC Physical Address. + * NIL_RTGCPHYS64 is used to signal an invalid physical address, similar + * to the NULL pointer. Note that this value may actually be valid in + * some contexts. + */ +#define NIL_RTGCPHYS64 (~(RTGCPHYS64)0) + +/** Guest context pointer, 32 bits. + * Keep in mind that this type is an unsigned integer in + * HC and void pointer in GC. + */ +typedef RTGCUINTPTR32 RTGCPTR32; +/** Pointer to a guest context pointer. */ +typedef RTGCPTR32 RT_FAR *PRTGCPTR32; +/** Pointer to a const guest context pointer. */ +typedef const RTGCPTR32 RT_FAR *PCRTGCPTR32; +/** @def NIL_RTGCPTR32 + * NIL GC pointer. + */ +#define NIL_RTGCPTR32 ((RTGCPTR32)0) + +/** Guest context pointer, 64 bits. + */ +typedef RTGCUINTPTR64 RTGCPTR64; +/** Pointer to a guest context pointer. */ +typedef RTGCPTR64 RT_FAR *PRTGCPTR64; +/** Pointer to a const guest context pointer. */ +typedef const RTGCPTR64 RT_FAR *PCRTGCPTR64; +/** @def NIL_RTGCPTR64 + * NIL GC pointer. + */ +#define NIL_RTGCPTR64 ((RTGCPTR64)0) + +/** @typedef RTGCPTR + * Guest context pointer. + * Keep in mind that this type is an unsigned integer in HC and void pointer in GC. */ +/** @typedef PRTGCPTR + * Pointer to a guest context pointer. */ +/** @typedef PCRTGCPTR + * Pointer to a const guest context pointer. */ +/** @def NIL_RTGCPTR + * NIL GC pointer. */ +/** @def RTGCPTR_MAX + * Max RTGCPTR value. */ +#if GC_ARCH_BITS == 64 || defined(DOXYGEN_RUNNING) +typedef RTGCPTR64 RTGCPTR; +typedef PRTGCPTR64 PRTGCPTR; +typedef PCRTGCPTR64 PCRTGCPTR; +# define NIL_RTGCPTR NIL_RTGCPTR64 +# define RTGCPTR_MAX UINT64_MAX +#elif GC_ARCH_BITS == 32 +typedef RTGCPTR32 RTGCPTR; +typedef PRTGCPTR32 PRTGCPTR; +typedef PCRTGCPTR32 PCRTGCPTR; +# define NIL_RTGCPTR NIL_RTGCPTR32 +# define RTGCPTR_MAX UINT32_MAX +#else +# error "Unsupported GC_ARCH_BITS!" +#endif + +/** Unsigned integer register in the guest context. */ +typedef uint32_t RTGCUINTREG32; +/** Pointer to an unsigned integer register in the guest context. */ +typedef RTGCUINTREG32 RT_FAR *PRTGCUINTREG32; +/** Pointer to a const unsigned integer register in the guest context. */ +typedef const RTGCUINTREG32 RT_FAR *PCRTGCUINTREG32; + +typedef uint64_t RTGCUINTREG64; +/** Pointer to an unsigned integer register in the guest context. */ +typedef RTGCUINTREG64 RT_FAR *PRTGCUINTREG64; +/** Pointer to a const unsigned integer register in the guest context. */ +typedef const RTGCUINTREG64 RT_FAR *PCRTGCUINTREG64; + +#if GC_ARCH_BITS == 64 +typedef RTGCUINTREG64 RTGCUINTREG; +#elif GC_ARCH_BITS == 32 +typedef RTGCUINTREG32 RTGCUINTREG; +#else +# error "Unsupported GC_ARCH_BITS!" +#endif +/** Pointer to an unsigned integer register in the guest context. */ +typedef RTGCUINTREG RT_FAR *PRTGCUINTREG; +/** Pointer to a const unsigned integer register in the guest context. */ +typedef const RTGCUINTREG RT_FAR *PCRTGCUINTREG; + +/** @} */ + +/** @defgroup grp_rt_types_rc Raw mode Context Basic Types + * @{ + */ + +/** Raw mode context pointer; a 32 bits guest context pointer. + * Keep in mind that this type is an unsigned integer in + * HC and void pointer in RC. + */ +#ifdef IN_RC +typedef void RT_FAR *RTRCPTR; +#else +typedef uint32_t RTRCPTR; +#endif +/** Pointer to a raw mode context pointer. */ +typedef RTRCPTR RT_FAR *PRTRCPTR; +/** Pointer to a const raw mode context pointer. */ +typedef const RTRCPTR RT_FAR *PCRTRCPTR; +/** @def NIL_RTRCPTR + * NIL RC pointer. */ +#ifdef IN_RC +# define NIL_RTRCPTR (NULL) +#else +# define NIL_RTRCPTR ((RTRCPTR)0) +#endif +/** @def RTRCPTR_MAX + * The maximum value a RTRCPTR can have. Mostly used as INVALID value. + */ +#define RTRCPTR_MAX ((RTRCPTR)UINT32_MAX) + +/** Raw mode context pointer, unsigned integer variant. */ +typedef int32_t RTRCINTPTR; +/** @def RTRCUINTPTR_MAX + * The maximum value a RTRCUINPTR can have. + */ +#define RTRCUINTPTR_MAX ((RTRCUINTPTR)UINT32_MAX) + +/** Raw mode context pointer, signed integer variant. */ +typedef uint32_t RTRCUINTPTR; +/** @def RTRCINTPTR_MIN + * The minimum value a RTRCINPTR can have. + */ +#define RTRCINTPTR_MIN ((RTRCINTPTR)INT32_MIN) +/** @def RTRCINTPTR_MAX + * The maximum value a RTRCINPTR can have. + */ +#define RTRCINTPTR_MAX ((RTRCINTPTR)INT32_MAX) + +/* The following are only temporarily while we clean up RTRCPTR usage: */ +#ifdef IN_RC +typedef void RT_FAR *RTRGPTR; +#else +typedef uint64_t RTRGPTR; +#endif +typedef RTRGPTR RT_FAR *PRTRGPTR; +typedef const RTRGPTR RT_FAR *PCRTRGPTR; +#ifdef IN_RC +# define NIL_RTRGPTR (NULL) +#else +# define NIL_RTRGPTR ((RTRGPTR)0) +#endif + +/** @} */ + + +/** @defgroup grp_rt_types_cc Current Context Basic Types + * @{ + */ + +/** Current Context Physical Memory Address.*/ +#ifdef IN_RC +typedef RTGCPHYS RTCCPHYS; +#else +typedef RTHCPHYS RTCCPHYS; +#endif +/** Pointer to Current Context Physical Memory Address. */ +typedef RTCCPHYS RT_FAR *PRTCCPHYS; +/** Pointer to const Current Context Physical Memory Address. */ +typedef const RTCCPHYS RT_FAR *PCRTCCPHYS; +/** @def NIL_RTCCPHYS + * NIL CC Physical Address. + * NIL_RTCCPHYS is used to signal an invalid physical address, similar + * to the NULL pointer. + */ +#ifdef IN_RC +# define NIL_RTCCPHYS NIL_RTGCPHYS +#else +# define NIL_RTCCPHYS NIL_RTHCPHYS +#endif + +/** Unsigned integer register in the current context. */ +#if ARCH_BITS == 32 +typedef uint32_t RTCCUINTREG; +#elif ARCH_BITS == 64 +typedef uint64_t RTCCUINTREG; +#elif ARCH_BITS == 16 +typedef uint16_t RTCCUINTREG; +#else +# error "Unsupported ARCH_BITS!" +#endif +/** Pointer to an unsigned integer register in the current context. */ +typedef RTCCUINTREG RT_FAR *PRTCCUINTREG; +/** Pointer to a const unsigned integer register in the current context. */ +typedef RTCCUINTREG const RT_FAR *PCRTCCUINTREG; + +/** Signed integer register in the current context. */ +#if ARCH_BITS == 32 +typedef int32_t RTCCINTREG; +#elif ARCH_BITS == 64 +typedef int64_t RTCCINTREG; +#elif ARCH_BITS == 16 +typedef int16_t RTCCINTREG; +#endif +/** Pointer to a signed integer register in the current context. */ +typedef RTCCINTREG RT_FAR *PRTCCINTREG; +/** Pointer to a const signed integer register in the current context. */ +typedef RTCCINTREG const RT_FAR *PCRTCCINTREG; + +/** Unsigned integer register in the current context. + * @remarks This is for dealing with EAX in 16-bit mode. */ +#if ARCH_BITS == 16 && defined(RT_ARCH_X86) +typedef uint32_t RTCCUINTXREG; +#else +typedef RTCCUINTREG RTCCUINTXREG; +#endif +/** Pointer to an unsigned integer register in the current context. */ +typedef RTCCUINTREG RT_FAR *PRTCCUINTXREG; +/** Pointer to a const unsigned integer register in the current context. */ +typedef RTCCUINTREG const RT_FAR *PCRTCCUINTXREG; + +/** Signed integer extended register in the current context. + * @remarks This is for dealing with EAX in 16-bit mode. */ +#if ARCH_BITS == 16 && defined(RT_ARCH_X86) +typedef int32_t RTCCINTXREG; +#else +typedef RTCCINTREG RTCCINTXREG; +#endif +/** Pointer to a signed integer extended register in the current context. */ +typedef RTCCINTXREG RT_FAR *PRTCCINTXREG; +/** Pointer to a const signed integer extended register in the current + * context. */ +typedef RTCCINTXREG const RT_FAR *PCRTCCINTXREG; + +/** @def RTCCUINTREG_C + * Defines a constant of RTCCUINTREG type. + * @param a_Value Constant value */ +/** @def RTCCUINTREG_MAX + * Max value that RTCCUINTREG can hold. */ +/** @def RTCCUINTREG_FMT + * Generic IPRT format specifier for RTCCUINTREG. */ +/** @def RTCCUINTREG_XFMT + * Generic IPRT format specifier for RTCCUINTREG, hexadecimal. */ +/** @def RTCCINTREG_C + * Defines a constant of RTCCINTREG type. + * @param a_Value Constant value */ +/** @def RTCCINTREG_MAX + * Max value that RTCCINTREG can hold. */ +/** @def RTCCINTREG_MIN + * Min value that RTCCINTREG can hold. */ +/** @def RTCCINTREG_XFMT + * Generic IPRT format specifier for RTCCINTREG, hexadecimal. */ +#if ARCH_BITS == 32 +# define RTCCUINTREG_C(a_Value) UINT32_C(a_Value) +# define RTCCUINTREG_MAX UINT32_MAX +# define RTCCUINTREG_FMT "RU32" +# define RTCCUINTREG_XFMT "RX32" +# define RTCCINTREG_C(a_Value) INT32_C(a_Value) +# define RTCCINTREG_MAX INT32_MAX +# define RTCCINTREG_MIN INT32_MIN +# define RTCCINTREG_FMT "RI32" +# define RTCCINTREG_XFMT "RX32" +#elif ARCH_BITS == 64 +# define RTCCUINTREG_C(a_Value) UINT64_C(a_Value) +# define RTCCUINTREG_MAX UINT64_MAX +# define RTCCUINTREG_FMT "RU64" +# define RTCCUINTREG_XFMT "RX64" +# define RTCCINTREG_C(a_Value) INT64_C(a_Value) +# define RTCCINTREG_MAX INT64_MAX +# define RTCCINTREG_MIN INT64_MIN +# define RTCCINTREG_FMT "RI64" +# define RTCCINTREG_XFMT "RX64" +#elif ARCH_BITS == 16 +# define RTCCUINTREG_C(a_Value) UINT16_C(a_Value) +# define RTCCUINTREG_MAX UINT16_MAX +# define RTCCUINTREG_FMT "RU16" +# define RTCCUINTREG_XFMT "RX16" +# define RTCCINTREG_C(a_Value) INT16_C(a_Value) +# define RTCCINTREG_MAX INT16_MAX +# define RTCCINTREG_MIN INT16_MIN +# define RTCCINTREG_FMT "RI16" +# define RTCCINTREG_XFMT "RX16" +#else +# error "Unsupported ARCH_BITS!" +#endif +/** @def RTCCUINTXREG_C + * Defines a constant of RTCCUINTXREG type. + * @param a_Value Constant value */ +/** @def RTCCUINTXREG_MAX + * Max value that RTCCUINTXREG can hold. */ +/** @def RTCCUINTXREG_FMT + * Generic IPRT format specifier for RTCCUINTXREG. */ +/** @def RTCCUINTXREG_XFMT + * Generic IPRT format specifier for RTCCUINTXREG, hexadecimal. */ +/** @def RTCCINTXREG_C + * Defines a constant of RTCCINTXREG type. + * @param a_Value Constant value */ +/** @def RTCCINTXREG_MAX + * Max value that RTCCINTXREG can hold. */ +/** @def RTCCINTXREG_MIN + * Min value that RTCCINTXREG can hold. */ +/** @def RTCCINTXREG_FMT + * Generic IPRT format specifier for RTCCINTXREG. */ +/** @def RTCCINTXREG_XFMT + * Generic IPRT format specifier for RTCCINTXREG, hexadecimal. */ +/** @def RTCCINTXREG_BITS + * The width of RTCCINTXREG in bits (32 or 64). */ +#if ARCH_BITS == 16 && defined(RT_ARCH_X86) +# define RTCCUINTXREG_C(a_Value) UINT32_C(a_Value) +# define RTCCUINTXREG_MAX UINT32_MAX +# define RTCCUINTXREG_FMT "RU32" +# define RTCCUINTXREG_XFMT "RX32" +# define RTCCINTXREG_C(a_Value) INT32_C(a_Value) +# define RTCCINTXREG_MAX INT32_MAX +# define RTCCINTXREG_MIN INT32_MIN +# define RTCCINTXREG_FMT "RI32" +# define RTCCINTXREG_XFMT "RX32" +# define RTCCINTXREG_BITS 32 +#else +# define RTCCUINTXREG_C(a_Value) RTCCUINTREG_C(a_Value) +# define RTCCUINTXREG_MAX RTCCUINTREG_MAX +# define RTCCUINTXREG_FMT RTCCUINTREG_FMT +# define RTCCUINTXREG_XFMT RTCCUINTREG_XFMT +# define RTCCINTXREG_C(a_Value) RTCCINTREG_C(a_Value) +# define RTCCINTXREG_MAX RTCCINTREG_MAX +# define RTCCINTXREG_MIN RTCCINTREG_MIN +# define RTCCINTXREG_FMT RTCCINTREG_FMT +# define RTCCINTXREG_XFMT RTCCINTREG_XFMT +# define RTCCINTXREG_BITS ARCH_BITS +#endif +/** @} */ + + + +/** Pointer to a big integer number. */ +typedef struct RTBIGNUM RT_FAR *PRTBIGNUM; +/** Pointer to a const big integer number. */ +typedef struct RTBIGNUM const RT_FAR *PCRTBIGNUM; + + +/** Pointer to a critical section. */ +typedef struct RTCRITSECT RT_FAR *PRTCRITSECT; +/** Pointer to a const critical section. */ +typedef const struct RTCRITSECT RT_FAR *PCRTCRITSECT; + +/** Pointer to a read/write critical section. */ +typedef struct RTCRITSECTRW RT_FAR *PRTCRITSECTRW; +/** Pointer to a const read/write critical section. */ +typedef const struct RTCRITSECTRW RT_FAR *PCRTCRITSECTRW; + + +/** Condition variable handle. */ +typedef R3PTRTYPE(struct RTCONDVARINTERNAL RT_FAR *) RTCONDVAR; +/** Pointer to a condition variable handle. */ +typedef RTCONDVAR RT_FAR *PRTCONDVAR; +/** Nil condition variable handle. */ +#define NIL_RTCONDVAR 0 + +/** Cryptographic (certificate) store handle. */ +typedef R3R0PTRTYPE(struct RTCRSTOREINT RT_FAR *) RTCRSTORE; +/** Pointer to a Cryptographic (certificate) store handle. */ +typedef RTCRSTORE RT_FAR *PRTCRSTORE; +/** Nil Cryptographic (certificate) store handle. */ +#define NIL_RTCRSTORE 0 + +/** Pointer to a const (store) certificate context. */ +typedef struct RTCRCERTCTX const RT_FAR *PCRTCRCERTCTX; + +/** Cryptographic message digest handle. */ +typedef R3R0PTRTYPE(struct RTCRDIGESTINT RT_FAR *) RTCRDIGEST; +/** Pointer to a cryptographic message digest handle. */ +typedef RTCRDIGEST RT_FAR *PRTCRDIGEST; +/** NIL cryptographic message digest handle. */ +#define NIL_RTCRDIGEST (0) + +/** Cryptographic key handle. */ +typedef R3R0PTRTYPE(struct RTCRKEYINT RT_FAR *) RTCRKEY; +/** Pointer to a cryptographic key handle. */ +typedef RTCRKEY RT_FAR *PRTCRKEY; +/** Cryptographic key handle nil value. */ +#define NIL_RTCRKEY (0) + +/** Public key encryption schema handle. */ +typedef R3R0PTRTYPE(struct RTCRPKIXENCRYPTIONINT RT_FAR *) RTCRPKIXENCRYPTION; +/** Pointer to a public key encryption schema handle. */ +typedef RTCRPKIXENCRYPTION RT_FAR *PRTCRPKIXENCRYPTION; +/** NIL public key encryption schema handle */ +#define NIL_RTCRPKIXENCRYPTION (0) + +/** Public key signature schema handle. */ +typedef R3R0PTRTYPE(struct RTCRPKIXSIGNATUREINT RT_FAR *) RTCRPKIXSIGNATURE; +/** Pointer to a public key signature schema handle. */ +typedef RTCRPKIXSIGNATURE RT_FAR *PRTCRPKIXSIGNATURE; +/** NIL public key signature schema handle */ +#define NIL_RTCRPKIXSIGNATURE (0) + +/** X.509 certificate paths builder & validator handle. */ +typedef R3R0PTRTYPE(struct RTCRX509CERTPATHSINT RT_FAR *) RTCRX509CERTPATHS; +/** Pointer to a certificate paths builder & validator handle. */ +typedef RTCRX509CERTPATHS RT_FAR *PRTCRX509CERTPATHS; +/** Nil certificate paths builder & validator handle. */ +#define NIL_RTCRX509CERTPATHS 0 + +/** Directory handle. */ +typedef struct RTDIRINTERNAL *RTDIR; +/** Pointer to directory handle. */ +typedef RTDIR *PRTDIR; +/** NIL directory handle. */ +#define NIL_RTDIR ((RTDIR)0) + +/** File handle. */ +typedef R3R0PTRTYPE(struct RTFILEINT RT_FAR *) RTFILE; +/** Pointer to file handle. */ +typedef RTFILE RT_FAR *PRTFILE; +/** Nil file handle. */ +#define NIL_RTFILE ((RTFILE)~(RTHCINTPTR)0) + +/** Async I/O request handle. */ +typedef R3PTRTYPE(struct RTFILEAIOREQINTERNAL RT_FAR *) RTFILEAIOREQ; +/** Pointer to an async I/O request handle. */ +typedef RTFILEAIOREQ RT_FAR *PRTFILEAIOREQ; +/** Nil request handle. */ +#define NIL_RTFILEAIOREQ 0 + +/** Async I/O completion context handle. */ +typedef R3PTRTYPE(struct RTFILEAIOCTXINTERNAL RT_FAR *) RTFILEAIOCTX; +/** Pointer to an async I/O completion context handle. */ +typedef RTFILEAIOCTX RT_FAR *PRTFILEAIOCTX; +/** Nil context handle. */ +#define NIL_RTFILEAIOCTX 0 + +/** ISO image maker handle. */ +typedef struct RTFSISOMAKERINT RT_FAR *RTFSISOMAKER; +/** Pointer to an ISO image maker handle. */ +typedef RTFSISOMAKER RT_FAR *PRTFSISOMAKER; +/** NIL ISO maker handle. */ +#define NIL_RTFSISOMAKER ((RTFSISOMAKER)0) + +/** INI-file handle. */ +typedef struct RTINIFILEINT RT_FAR *RTINIFILE; +/** Pointer to an INI-file handle. */ +typedef RTINIFILE RT_FAR *PRTINIFILE; +/** NIL INI-file handle. */ +#define NIL_RTINIFILE ((RTINIFILE)0) + +/** Loader module handle. */ +typedef R3R0PTRTYPE(struct RTLDRMODINTERNAL RT_FAR *) RTLDRMOD; +/** Pointer to a loader module handle. */ +typedef RTLDRMOD RT_FAR *PRTLDRMOD; +/** Nil loader module handle. */ +#define NIL_RTLDRMOD 0 + +/** Lock validator class handle. */ +typedef R3R0PTRTYPE(struct RTLOCKVALCLASSINT RT_FAR *) RTLOCKVALCLASS; +/** Pointer to a lock validator class handle. */ +typedef RTLOCKVALCLASS RT_FAR *PRTLOCKVALCLASS; +/** Nil lock validator class handle. */ +#define NIL_RTLOCKVALCLASS ((RTLOCKVALCLASS)0) + +/** Ring-0 memory object handle. */ +typedef R0PTRTYPE(struct RTR0MEMOBJINTERNAL RT_FAR *) RTR0MEMOBJ; +/** Pointer to a Ring-0 memory object handle. */ +typedef RTR0MEMOBJ RT_FAR *PRTR0MEMOBJ; +/** Nil ring-0 memory object handle. */ +#define NIL_RTR0MEMOBJ 0 + +/** Native thread handle. */ +typedef RTHCUINTPTR RTNATIVETHREAD; +/** Pointer to an native thread handle. */ +typedef RTNATIVETHREAD RT_FAR *PRTNATIVETHREAD; +/** Nil native thread handle. */ +#define NIL_RTNATIVETHREAD (~(RTNATIVETHREAD)0) + +/** Pipe handle. */ +typedef R3R0PTRTYPE(struct RTPIPEINTERNAL RT_FAR *) RTPIPE; +/** Pointer to a pipe handle. */ +typedef RTPIPE RT_FAR *PRTPIPE; +/** Nil pipe handle. + * @remarks This is not 0 because of UNIX and OS/2 handle values. Take care! */ +#define NIL_RTPIPE ((RTPIPE)RTHCUINTPTR_MAX) + +/** @typedef RTPOLLSET + * Poll set handle. */ +typedef R3R0PTRTYPE(struct RTPOLLSETINTERNAL RT_FAR *) RTPOLLSET; +/** Pointer to a poll set handle. */ +typedef RTPOLLSET RT_FAR *PRTPOLLSET; +/** Nil poll set handle handle. */ +#define NIL_RTPOLLSET ((RTPOLLSET)0) + +/** Process identifier. */ +typedef uint32_t RTPROCESS; +/** Pointer to a process identifier. */ +typedef RTPROCESS RT_FAR *PRTPROCESS; +/** Nil process identifier. */ +#define NIL_RTPROCESS (~(RTPROCESS)0) + +/** Process ring-0 handle. */ +typedef RTR0UINTPTR RTR0PROCESS; +/** Pointer to a ring-0 process handle. */ +typedef RTR0PROCESS RT_FAR *PRTR0PROCESS; +/** Nil ring-0 process handle. */ +#define NIL_RTR0PROCESS (~(RTR0PROCESS)0) + +/** @typedef RTSEMEVENT + * Event Semaphore handle. */ +typedef R3R0PTRTYPE(struct RTSEMEVENTINTERNAL RT_FAR *) RTSEMEVENT; +/** Pointer to an event semaphore handle. */ +typedef RTSEMEVENT RT_FAR *PRTSEMEVENT; +/** Nil event semaphore handle. */ +#define NIL_RTSEMEVENT 0 + +/** @typedef RTSEMEVENTMULTI + * Event Multiple Release Semaphore handle. */ +typedef R3R0PTRTYPE(struct RTSEMEVENTMULTIINTERNAL RT_FAR *) RTSEMEVENTMULTI; +/** Pointer to an event multiple release semaphore handle. */ +typedef RTSEMEVENTMULTI RT_FAR *PRTSEMEVENTMULTI; +/** Nil multiple release event semaphore handle. */ +#define NIL_RTSEMEVENTMULTI 0 + +/** @typedef RTSEMFASTMUTEX + * Fast mutex Semaphore handle. */ +typedef R3R0PTRTYPE(struct RTSEMFASTMUTEXINTERNAL RT_FAR *) RTSEMFASTMUTEX; +/** Pointer to a fast mutex semaphore handle. */ +typedef RTSEMFASTMUTEX RT_FAR *PRTSEMFASTMUTEX; +/** Nil fast mutex semaphore handle. */ +#define NIL_RTSEMFASTMUTEX 0 + +/** @typedef RTSEMMUTEX + * Mutex Semaphore handle. */ +typedef R3R0PTRTYPE(struct RTSEMMUTEXINTERNAL RT_FAR *) RTSEMMUTEX; +/** Pointer to a mutex semaphore handle. */ +typedef RTSEMMUTEX RT_FAR *PRTSEMMUTEX; +/** Nil mutex semaphore handle. */ +#define NIL_RTSEMMUTEX 0 + +/** @typedef RTSEMSPINMUTEX + * Spinning mutex Semaphore handle. */ +typedef R3R0PTRTYPE(struct RTSEMSPINMUTEXINTERNAL RT_FAR *) RTSEMSPINMUTEX; +/** Pointer to a spinning mutex semaphore handle. */ +typedef RTSEMSPINMUTEX RT_FAR *PRTSEMSPINMUTEX; +/** Nil spinning mutex semaphore handle. */ +#define NIL_RTSEMSPINMUTEX 0 + +/** @typedef RTSEMRW + * Read/Write Semaphore handle. */ +typedef R3R0PTRTYPE(struct RTSEMRWINTERNAL RT_FAR *) RTSEMRW; +/** Pointer to a read/write semaphore handle. */ +typedef RTSEMRW RT_FAR *PRTSEMRW; +/** Nil read/write semaphore handle. */ +#define NIL_RTSEMRW 0 + +/** @typedef RTSEMXROADS + * Crossroads semaphore handle. */ +typedef R3R0PTRTYPE(struct RTSEMXROADSINTERNAL RT_FAR *) RTSEMXROADS; +/** Pointer to a crossroads semaphore handle. */ +typedef RTSEMXROADS RT_FAR *PRTSEMXROADS; +/** Nil crossroads semaphore handle. */ +#define NIL_RTSEMXROADS ((RTSEMXROADS)0) + +/** Spinlock handle. */ +typedef R3R0PTRTYPE(struct RTSPINLOCKINTERNAL RT_FAR *) RTSPINLOCK; +/** Pointer to a spinlock handle. */ +typedef RTSPINLOCK RT_FAR *PRTSPINLOCK; +/** Nil spinlock handle. */ +#define NIL_RTSPINLOCK 0 + +/** Socket handle. */ +typedef R3R0PTRTYPE(struct RTSOCKETINT RT_FAR *) RTSOCKET; +/** Pointer to socket handle. */ +typedef RTSOCKET RT_FAR *PRTSOCKET; +/** Nil socket handle. */ +#define NIL_RTSOCKET ((RTSOCKET)0) + +/** Pointer to a RTTCPSERVER handle. */ +typedef struct RTTCPSERVER RT_FAR *PRTTCPSERVER; +/** Pointer to a RTTCPSERVER handle. */ +typedef PRTTCPSERVER RT_FAR *PPRTTCPSERVER; +/** Nil RTTCPSERVER handle. */ +#define NIL_RTTCPSERVER ((PRTTCPSERVER)0) + +/** Pointer to a RTUDPSERVER handle. */ +typedef struct RTUDPSERVER RT_FAR *PRTUDPSERVER; +/** Pointer to a RTUDPSERVER handle. */ +typedef PRTUDPSERVER RT_FAR *PPRTUDPSERVER; +/** Nil RTUDPSERVER handle. */ +#define NIL_RTUDPSERVER ((PRTUDPSERVER)0) + +/** Thread handle.*/ +typedef R3R0PTRTYPE(struct RTTHREADINT RT_FAR *) RTTHREAD; +/** Pointer to thread handle. */ +typedef RTTHREAD RT_FAR *PRTTHREAD; +/** Nil thread handle. */ +#define NIL_RTTHREAD 0 + +/** Thread context switching hook handle. */ +typedef R0PTRTYPE(struct RTTHREADCTXHOOKINT RT_FAR *) RTTHREADCTXHOOK; +/** Pointer to Thread context switching hook handle. */ +typedef RTTHREADCTXHOOK RT_FAR *PRTTHREADCTXHOOK; +/** Nil Thread context switching hook handle. */ +#define NIL_RTTHREADCTXHOOK ((RTTHREADCTXHOOK)0) + +/** A TLS index. */ +typedef RTHCINTPTR RTTLS; +/** Pointer to a TLS index. */ +typedef RTTLS RT_FAR *PRTTLS; +/** Pointer to a const TLS index. */ +typedef RTTLS const RT_FAR *PCRTTLS; +/** NIL TLS index value. */ +#define NIL_RTTLS ((RTTLS)-1) + +/** Trace buffer handle. + * @remarks This is not a R3/R0 type like most other handles! + */ +typedef struct RTTRACEBUFINT RT_FAR *RTTRACEBUF; +/** Pointer to a trace buffer handle. */ +typedef RTTRACEBUF RT_FAR *PRTTRACEBUF; +/** Nil trace buffer handle. */ +#define NIL_RTTRACEBUF ((RTTRACEBUF)0) +/** The handle of the default trace buffer. + * This can be used with any of the RTTraceBufAdd APIs. */ +#define RTTRACEBUF_DEFAULT ((RTTRACEBUF)-2) + +/** Handle to a simple heap. */ +typedef R3R0PTRTYPE(struct RTHEAPSIMPLEINTERNAL RT_FAR *) RTHEAPSIMPLE; +/** Pointer to a handle to a simple heap. */ +typedef RTHEAPSIMPLE RT_FAR *PRTHEAPSIMPLE; +/** NIL simple heap handle. */ +#define NIL_RTHEAPSIMPLE ((RTHEAPSIMPLE)0) + +/** Handle to an offset based heap. */ +typedef R3R0PTRTYPE(struct RTHEAPOFFSETINTERNAL RT_FAR *) RTHEAPOFFSET; +/** Pointer to a handle to an offset based heap. */ +typedef RTHEAPOFFSET RT_FAR *PRTHEAPOFFSET; +/** NIL offset based heap handle. */ +#define NIL_RTHEAPOFFSET ((RTHEAPOFFSET)0) + +/** Handle to an environment block. */ +typedef R3PTRTYPE(struct RTENVINTERNAL RT_FAR *) RTENV; +/** Pointer to a handle to an environment block. */ +typedef RTENV RT_FAR *PRTENV; +/** NIL simple heap handle. */ +#define NIL_RTENV ((RTENV)0) + +/** A CPU identifier. + * @remarks This doesn't have to correspond to the APIC ID (intel/amd). Nor + * does it have to correspond to the bits in the affinity mask, at + * least not until we've sorted out Windows NT. */ +typedef uint32_t RTCPUID; +/** Pointer to a CPU identifier. */ +typedef RTCPUID RT_FAR *PRTCPUID; +/** Pointer to a const CPU identifier. */ +typedef RTCPUID const RT_FAR *PCRTCPUID; +/** Nil CPU Id. */ +#define NIL_RTCPUID ((RTCPUID)~0) + +/** The maximum number of CPUs a set can contain and IPRT is able + * to reference. (Should be max of support arch/platforms.) + * @remarks Must be a power of two and multiple of 64 (see RTCPUSET). */ +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) +# if defined(RT_OS_OS2) +# define RTCPUSET_MAX_CPUS 64 +# elif defined(RT_OS_DARWIN) || defined(RT_ARCH_X86) +# define RTCPUSET_MAX_CPUS 256 +# else +# define RTCPUSET_MAX_CPUS 1024 +# endif +#elif defined(RT_ARCH_SPARC) || defined(RT_ARCH_SPARC64) +# define RTCPUSET_MAX_CPUS 1024 +#else +# define RTCPUSET_MAX_CPUS 64 +#endif +/** A CPU set. + * @note Treat this as an opaque type and always use RTCpuSet* for + * manipulating it. */ +typedef struct RTCPUSET +{ + /** The bitmap. */ + uint64_t bmSet[RTCPUSET_MAX_CPUS / 64]; +} RTCPUSET; +/** Pointer to a CPU set. */ +typedef RTCPUSET RT_FAR *PRTCPUSET; +/** Pointer to a const CPU set. */ +typedef RTCPUSET const RT_FAR *PCRTCPUSET; + +/** A handle table handle. */ +typedef R3R0PTRTYPE(struct RTHANDLETABLEINT RT_FAR *) RTHANDLETABLE; +/** A pointer to a handle table handle. */ +typedef RTHANDLETABLE RT_FAR *PRTHANDLETABLE; +/** @def NIL_RTHANDLETABLE + * NIL handle table handle. */ +#define NIL_RTHANDLETABLE ((RTHANDLETABLE)0) + +/** A handle to a low resolution timer. */ +typedef R3R0PTRTYPE(struct RTTIMERLRINT RT_FAR *) RTTIMERLR; +/** A pointer to a low resolution timer handle. */ +typedef RTTIMERLR RT_FAR *PRTTIMERLR; +/** @def NIL_RTTIMERLR + * NIL low resolution timer handle value. */ +#define NIL_RTTIMERLR ((RTTIMERLR)0) + +/** Handle to a random number generator. */ +typedef R3R0PTRTYPE(struct RTRANDINT RT_FAR *) RTRAND; +/** Pointer to a random number generator handle. */ +typedef RTRAND RT_FAR *PRTRAND; +/** NIL random number generator handle value. */ +#define NIL_RTRAND ((RTRAND)0) + +/** Debug address space handle. */ +typedef R3R0PTRTYPE(struct RTDBGASINT RT_FAR *) RTDBGAS; +/** Pointer to a debug address space handle. */ +typedef RTDBGAS RT_FAR *PRTDBGAS; +/** NIL debug address space handle. */ +#define NIL_RTDBGAS ((RTDBGAS)0) + +/** Debug module handle. */ +typedef R3R0PTRTYPE(struct RTDBGMODINT RT_FAR *) RTDBGMOD; +/** Pointer to a debug module handle. */ +typedef RTDBGMOD RT_FAR *PRTDBGMOD; +/** NIL debug module handle. */ +#define NIL_RTDBGMOD ((RTDBGMOD)0) + +/** Pointer to an unwind machine state. */ +typedef struct RTDBGUNWINDSTATE RT_FAR *PRTDBGUNWINDSTATE; +/** Pointer to a const unwind machine state. */ +typedef struct RTDBGUNWINDSTATE const RT_FAR *PCRTDBGUNWINDSTATE; + +/** Manifest handle. */ +typedef struct RTMANIFESTINT RT_FAR *RTMANIFEST; +/** Pointer to a manifest handle. */ +typedef RTMANIFEST RT_FAR *PRTMANIFEST; +/** NIL manifest handle. */ +#define NIL_RTMANIFEST ((RTMANIFEST)~(uintptr_t)0) + +/** Memory pool handle. */ +typedef R3R0PTRTYPE(struct RTMEMPOOLINT RT_FAR *) RTMEMPOOL; +/** Pointer to a memory pool handle. */ +typedef RTMEMPOOL RT_FAR *PRTMEMPOOL; +/** NIL memory pool handle. */ +#define NIL_RTMEMPOOL ((RTMEMPOOL)0) +/** The default memory pool handle. */ +#define RTMEMPOOL_DEFAULT ((RTMEMPOOL)-2) + +/** String cache handle. */ +typedef R3R0PTRTYPE(struct RTSTRCACHEINT RT_FAR *) RTSTRCACHE; +/** Pointer to a string cache handle. */ +typedef RTSTRCACHE RT_FAR *PRTSTRCACHE; +/** NIL string cache handle. */ +#define NIL_RTSTRCACHE ((RTSTRCACHE)0) +/** The default string cache handle. */ +#define RTSTRCACHE_DEFAULT ((RTSTRCACHE)-2) + + +/** Virtual Filesystem handle. */ +typedef struct RTVFSINTERNAL RT_FAR *RTVFS; +/** Pointer to a VFS handle. */ +typedef RTVFS RT_FAR *PRTVFS; +/** A NIL VFS handle. */ +#define NIL_RTVFS ((RTVFS)~(uintptr_t)0) + +/** Virtual Filesystem base object handle. */ +typedef struct RTVFSOBJINTERNAL RT_FAR *RTVFSOBJ; +/** Pointer to a VFS base object handle. */ +typedef RTVFSOBJ RT_FAR *PRTVFSOBJ; +/** A NIL VFS base object handle. */ +#define NIL_RTVFSOBJ ((RTVFSOBJ)~(uintptr_t)0) + +/** Virtual Filesystem directory handle. */ +typedef struct RTVFSDIRINTERNAL RT_FAR *RTVFSDIR; +/** Pointer to a VFS directory handle. */ +typedef RTVFSDIR RT_FAR *PRTVFSDIR; +/** A NIL VFS directory handle. */ +#define NIL_RTVFSDIR ((RTVFSDIR)~(uintptr_t)0) + +/** Virtual Filesystem filesystem stream handle. */ +typedef struct RTVFSFSSTREAMINTERNAL RT_FAR *RTVFSFSSTREAM; +/** Pointer to a VFS filesystem stream handle. */ +typedef RTVFSFSSTREAM RT_FAR *PRTVFSFSSTREAM; +/** A NIL VFS filesystem stream handle. */ +#define NIL_RTVFSFSSTREAM ((RTVFSFSSTREAM)~(uintptr_t)0) + +/** Virtual Filesystem I/O stream handle. */ +typedef struct RTVFSIOSTREAMINTERNAL RT_FAR *RTVFSIOSTREAM; +/** Pointer to a VFS I/O stream handle. */ +typedef RTVFSIOSTREAM RT_FAR *PRTVFSIOSTREAM; +/** A NIL VFS I/O stream handle. */ +#define NIL_RTVFSIOSTREAM ((RTVFSIOSTREAM)~(uintptr_t)0) + +/** Virtual Filesystem file handle. */ +typedef struct RTVFSFILEINTERNAL RT_FAR *RTVFSFILE; +/** Pointer to a VFS file handle. */ +typedef RTVFSFILE RT_FAR *PRTVFSFILE; +/** A NIL VFS file handle. */ +#define NIL_RTVFSFILE ((RTVFSFILE)~(uintptr_t)0) + +/** Virtual Filesystem symbolic link handle. */ +typedef struct RTVFSSYMLINKINTERNAL RT_FAR *RTVFSSYMLINK; +/** Pointer to a VFS symbolic link handle. */ +typedef RTVFSSYMLINK RT_FAR *PRTVFSSYMLINK; +/** A NIL VFS symbolic link handle. */ +#define NIL_RTVFSSYMLINK ((RTVFSSYMLINK)~(uintptr_t)0) + +/** Async I/O manager handle. */ +typedef struct RTAIOMGRINT RT_FAR *RTAIOMGR; +/** Pointer to a async I/O manager handle. */ +typedef RTAIOMGR RT_FAR *PRTAIOMGR; +/** A NIL async I/O manager handle. */ +#define NIL_RTAIOMGR ((RTAIOMGR)~(uintptr_t)0) + +/** Async I/O manager file handle. */ +typedef struct RTAIOMGRFILEINT RT_FAR *RTAIOMGRFILE; +/** Pointer to a async I/O manager file handle. */ +typedef RTAIOMGRFILE RT_FAR *PRTAIOMGRFILE; +/** A NIL async I/O manager file handle. */ +#define NIL_RTAIOMGRFILE ((RTAIOMGRFILE)~(uintptr_t)0) + +/** Kernel module information record handle. */ +typedef struct RTKRNLMODINFOINT RT_FAR *RTKRNLMODINFO; +/** Pointer to a kernel information record handle. */ +typedef RTKRNLMODINFO RT_FAR *PRTKRNLMODINFO; +/** A NIL kernel module information record handle. */ +#define NIL_RTKRNLMODINFO ((RTKRNLMODINFO)~(uintptr_t)0); + +/** Shared memory object handle. */ +typedef struct RTSHMEMINT RT_FAR *RTSHMEM; +/** Pointer to a shared memory object handle. */ +typedef RTSHMEM RT_FAR *PRTSHMEM; +/** A NIL shared memory object handle. */ +#define NIL_RTSHMEM ((RTSHMEM)~(uintptr_t)0) + +/** EFI signature database handle. */ +typedef struct RTEFISIGDBINT RT_FAR *RTEFISIGDB; +/** Pointer to a EFI signature database handle. */ +typedef RTEFISIGDB RT_FAR *PRTEFISIGDB; +/** A NIL EFI signature database handle. */ +#define NIL_RTEFISIGDB ((RTEFISIGDB)~(uintptr_t)0) + + +/** + * Handle type. + * + * This is usually used together with RTHANDLEUNION. + */ +typedef enum RTHANDLETYPE +{ + /** The invalid zero value. */ + RTHANDLETYPE_INVALID = 0, + /** File handle. */ + RTHANDLETYPE_FILE, + /** Pipe handle */ + RTHANDLETYPE_PIPE, + /** Socket handle. */ + RTHANDLETYPE_SOCKET, + /** Thread handle. */ + RTHANDLETYPE_THREAD, + /** The end of the valid values. */ + RTHANDLETYPE_END, + /** The 32-bit type blow up. */ + RTHANDLETYPE_32BIT_HACK = 0x7fffffff +} RTHANDLETYPE; +/** Pointer to a handle type. */ +typedef RTHANDLETYPE RT_FAR *PRTHANDLETYPE; + +/** + * Handle union. + * + * This is usually used together with RTHANDLETYPE or as RTHANDLE. + */ +typedef union RTHANDLEUNION +{ + RTFILE hFile; /**< File handle. */ + RTPIPE hPipe; /**< Pipe handle. */ + RTSOCKET hSocket; /**< Socket handle. */ + RTTHREAD hThread; /**< Thread handle. */ + /** Generic integer handle value. + * Note that RTFILE is not yet pointer sized, so accessing it via this member + * isn't necessarily safe or fully portable. */ + RTHCUINTPTR uInt; +} RTHANDLEUNION; +/** Pointer to a handle union. */ +typedef RTHANDLEUNION RT_FAR *PRTHANDLEUNION; +/** Pointer to a const handle union. */ +typedef RTHANDLEUNION const RT_FAR *PCRTHANDLEUNION; + +/** + * Generic handle. + */ +typedef struct RTHANDLE +{ + /** The handle type. */ + RTHANDLETYPE enmType; + /** The handle value. */ + RTHANDLEUNION u; +} RTHANDLE; +/** Pointer to a generic handle. */ +typedef RTHANDLE RT_FAR *PRTHANDLE; +/** Pointer to a const generic handle. */ +typedef RTHANDLE const RT_FAR *PCRTHANDLE; + + +/** + * Standard handles. + * + * @remarks These have the correct file descriptor values for unixy systems and + * can be used directly in code specific to those platforms. + */ +typedef enum RTHANDLESTD +{ + /** Invalid standard handle. */ + RTHANDLESTD_INVALID = -1, + /** The standard input handle. */ + RTHANDLESTD_INPUT = 0, + /** The standard output handle. */ + RTHANDLESTD_OUTPUT, + /** The standard error handle. */ + RTHANDLESTD_ERROR, + /** The typical 32-bit type hack. */ + RTHANDLESTD_32BIT_HACK = 0x7fffffff +} RTHANDLESTD; + + +/** + * Error info. + * + * See RTErrInfo*. + */ +typedef struct RTERRINFO +{ + /** Flags, see RTERRINFO_FLAGS_XXX. */ + uint32_t fFlags; + /** The status code. */ + int32_t rc; + /** The size of the message */ + size_t cbMsg; + /** The error buffer. */ + char *pszMsg; + /** Reserved for future use. */ + void *apvReserved[2]; +} RTERRINFO; +/** Pointer to an error info structure. */ +typedef RTERRINFO RT_FAR *PRTERRINFO; +/** Pointer to a const error info structure. */ +typedef RTERRINFO const RT_FAR *PCRTERRINFO; + +/** + * Static error info structure, see RTErrInfoInitStatic. + */ +typedef struct RTERRINFOSTATIC +{ + /** The core error info. */ + RTERRINFO Core; + /** The static message buffer. */ + char szMsg[3072]; +} RTERRINFOSTATIC; +/** Pointer to a error info buffer. */ +typedef RTERRINFOSTATIC RT_FAR *PRTERRINFOSTATIC; +/** Pointer to a const static error info buffer. */ +typedef RTERRINFOSTATIC const RT_FAR *PCRTERRINFOSTATIC; + + +/** + * UUID data type. + * + * See RTUuid*. + * + * @remarks IPRT defines that the first three integers in the @c Gen struct + * interpretation are in little endian representation. This is + * different to many other UUID implementation, and requires + * conversion if you need to achieve consistent results. + */ +typedef union RTUUID +{ + /** 8-bit view. */ + uint8_t au8[16]; + /** 16-bit view. */ + uint16_t au16[8]; + /** 32-bit view. */ + uint32_t au32[4]; + /** 64-bit view. */ + uint64_t au64[2]; + /** The way the UUID is declared by the DCE specification. */ + struct + { + uint32_t u32TimeLow; + uint16_t u16TimeMid; + uint16_t u16TimeHiAndVersion; + uint8_t u8ClockSeqHiAndReserved; + uint8_t u8ClockSeqLow; + uint8_t au8Node[6]; + } Gen; +} RTUUID; +/** Pointer to UUID data. */ +typedef RTUUID RT_FAR *PRTUUID; +/** Pointer to readonly UUID data. */ +typedef const RTUUID RT_FAR *PCRTUUID; + +/** Initializes a RTUUID structure with all zeros (RTUuidIsNull() true). */ +#define RTUUID_INITIALIZE_NULL { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } + +/** UUID string maximum length. */ +#define RTUUID_STR_LENGTH 37 + + +/** Compression handle. */ +typedef struct RTZIPCOMP RT_FAR *PRTZIPCOMP; +/** Decompressor handle. */ +typedef struct RTZIPDECOMP RT_FAR *PRTZIPDECOMP; + + +/** + * Unicode Code Point. + */ +typedef uint32_t RTUNICP; +/** Pointer to an Unicode Code Point. */ +typedef RTUNICP RT_FAR *PRTUNICP; +/** Pointer to an Unicode Code Point. */ +typedef const RTUNICP RT_FAR *PCRTUNICP; +/** Max value a RTUNICP type can hold. */ +#define RTUNICP_MAX ( ~(RTUNICP)0 ) +/** Invalid code point. + * This is returned when encountered invalid encodings or invalid + * unicode code points. */ +#define RTUNICP_INVALID ( UINT32_C(0xfffffffe) ) + + +/** + * UTF-16 character. + * @remark wchar_t is not usable since it's compiler defined. + * @remark When we use the term character we're not talking about unicode code point, but + * the basic unit of the string encoding. Thus cwc - count of wide chars - means + * count of RTUTF16; cuc - count of unicode chars - means count of RTUNICP; + * and cch means count of the typedef 'char', which is assumed to be an octet. + */ +typedef uint16_t RTUTF16; +/** Pointer to a UTF-16 character. */ +typedef RTUTF16 RT_FAR *PRTUTF16; +/** Pointer to a const UTF-16 character. */ +typedef const RTUTF16 RT_FAR *PCRTUTF16; + + +/** + * String tuple to go with the RT_STR_TUPLE macro. + */ +typedef struct RTSTRTUPLE +{ + /** The string. */ + const char *psz; + /** The string length. */ + size_t cch; +} RTSTRTUPLE; +/** Pointer to a string tuple. */ +typedef RTSTRTUPLE RT_FAR *PRTSTRTUPLE; +/** Pointer to a const string tuple. */ +typedef RTSTRTUPLE const RT_FAR *PCRTSTRTUPLE; + +/** + * Wait for ever if we have to. + */ +#define RT_INDEFINITE_WAIT (~0U) + + +/** + * Generic process callback. + * + * @returns VBox status code. Failure will cancel the operation. + * @param uPercentage The percentage of the operation which has been completed. + * @param pvUser The user specified argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTPROGRESS,(unsigned uPercentage, void *pvUser)); +/** Pointer to a generic progress callback function, FNRTPROCESS(). */ +typedef FNRTPROGRESS *PFNRTPROGRESS; + +/** + * Generic vprintf-like callback function for dumpers. + * + * @param pvUser User argument. + * @param pszFormat The format string. + * @param va Arguments for the format string. + */ +typedef DECLCALLBACKTYPE(void, FNRTDUMPPRINTFV,(void *pvUser, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0)); +/** Pointer to a generic printf-like function for dumping. */ +typedef FNRTDUMPPRINTFV *PFNRTDUMPPRINTFV; + + +/** + * A point in a two dimentional coordinate system. + */ +typedef struct RTPOINT +{ + /** X coordinate. */ + int32_t x; + /** Y coordinate. */ + int32_t y; +} RTPOINT; +/** Pointer to a point. */ +typedef RTPOINT RT_FAR *PRTPOINT; +/** Pointer to a const point. */ +typedef const RTPOINT RT_FAR *PCRTPOINT; + + +/** + * Rectangle data type, double point. + */ +typedef struct RTRECT +{ + /** left X coordinate. */ + int32_t xLeft; + /** top Y coordinate. */ + int32_t yTop; + /** right X coordinate. (exclusive) */ + int32_t xRight; + /** bottom Y coordinate. (exclusive) */ + int32_t yBottom; +} RTRECT; +/** Pointer to a double point rectangle. */ +typedef RTRECT RT_FAR *PRTRECT; +/** Pointer to a const double point rectangle. */ +typedef const RTRECT RT_FAR *PCRTRECT; + + +/** + * Rectangle data type, point + size. + */ +typedef struct RTRECT2 +{ + /** X coordinate. + * Unless stated otherwise, this is the top left corner. */ + int32_t x; + /** Y coordinate. + * Unless stated otherwise, this is the top left corner. */ + int32_t y; + /** The width. + * Unless stated otherwise, this is to the right of (x,y) and will not + * be a negative number. */ + int32_t cx; + /** The height. + * Unless stated otherwise, this is down from (x,y) and will not be a + * negative number. */ + int32_t cy; +} RTRECT2; +/** Pointer to a point + size rectangle. */ +typedef RTRECT2 RT_FAR *PRTRECT2; +/** Pointer to a const point + size rectangle. */ +typedef const RTRECT2 RT_FAR *PCRTRECT2; + + +/** + * The size of a rectangle. + */ +typedef struct RTRECTSIZE +{ + /** The width (along the x-axis). */ + uint32_t cx; + /** The height (along the y-axis). */ + uint32_t cy; +} RTRECTSIZE; +/** Pointer to a rectangle size. */ +typedef RTRECTSIZE RT_FAR *PRTRECTSIZE; +/** Pointer to a const rectangle size. */ +typedef const RTRECTSIZE RT_FAR *PCRTRECTSIZE; + + +/** + * Ethernet MAC address. + * + * The first 24 bits make up the Organisationally Unique Identifier (OUI), + * where the first bit (little endian) indicates multicast (set) / unicast, + * and the second bit indicates locally (set) / global administered. If all + * bits are set, it's a broadcast. + */ +typedef union RTMAC +{ + /** @todo add a bitfield view of this stuff. */ + /** 8-bit view. */ + uint8_t au8[6]; + /** 16-bit view. */ + uint16_t au16[3]; +} RTMAC; +/** Pointer to a MAC address. */ +typedef RTMAC RT_FAR *PRTMAC; +/** Pointer to a readonly MAC address. */ +typedef const RTMAC RT_FAR *PCRTMAC; + + +/** Pointer to a lock validator record. + * The structure definition is found in iprt/lockvalidator.h. */ +typedef struct RTLOCKVALRECEXCL RT_FAR *PRTLOCKVALRECEXCL; +/** Pointer to a record of one ownership share. + * The structure definition is found in iprt/lockvalidator.h. */ +typedef struct RTLOCKVALRECSHRD RT_FAR *PRTLOCKVALRECSHRD; +/** Pointer to a lock validator source position. + * The structure definition is found in iprt/lockvalidator.h. */ +typedef struct RTLOCKVALSRCPOS RT_FAR *PRTLOCKVALSRCPOS; +/** Pointer to a const lock validator source position. + * The structure definition is found in iprt/lockvalidator.h. */ +typedef struct RTLOCKVALSRCPOS const RT_FAR *PCRTLOCKVALSRCPOS; + +/** @name Special sub-class values. + * The range 16..UINT32_MAX is available to the user, the range 0..15 is + * reserved for the lock validator. In the user range the locks can only be + * taking in ascending order. + * @{ */ +/** Invalid value. */ +#define RTLOCKVAL_SUB_CLASS_INVALID UINT32_C(0) +/** Not allowed to be taken with any other locks in the same class. + * This is the recommended value. */ +#define RTLOCKVAL_SUB_CLASS_NONE UINT32_C(1) +/** Any order is allowed within the class. */ +#define RTLOCKVAL_SUB_CLASS_ANY UINT32_C(2) +/** The first user value. */ +#define RTLOCKVAL_SUB_CLASS_USER UINT32_C(16) +/** @} */ + + +/** + * Digest types. + */ +typedef enum RTDIGESTTYPE +{ + /** Invalid digest value. */ + RTDIGESTTYPE_INVALID = 0, + /** Unknown digest type. */ + RTDIGESTTYPE_UNKNOWN, + /** CRC32 checksum. */ + RTDIGESTTYPE_CRC32, + /** CRC64 checksum. */ + RTDIGESTTYPE_CRC64, + /** MD2 checksum (unsafe!). */ + RTDIGESTTYPE_MD2, + /** MD4 checksum (unsafe!!). */ + RTDIGESTTYPE_MD4, + /** MD5 checksum (unsafe!). */ + RTDIGESTTYPE_MD5, + /** SHA-1 checksum (unsafe!). */ + RTDIGESTTYPE_SHA1, + /** SHA-224 checksum. */ + RTDIGESTTYPE_SHA224, + /** SHA-256 checksum. */ + RTDIGESTTYPE_SHA256, + /** SHA-384 checksum. */ + RTDIGESTTYPE_SHA384, + /** SHA-512 checksum. */ + RTDIGESTTYPE_SHA512, + /** SHA-512/224 checksum. */ + RTDIGESTTYPE_SHA512T224, + /** SHA-512/256 checksum. */ + RTDIGESTTYPE_SHA512T256, + /** SHA3-224 checksum. */ + RTDIGESTTYPE_SHA3_224, + /** SHA3-256 checksum. */ + RTDIGESTTYPE_SHA3_256, + /** SHA3-384 checksum. */ + RTDIGESTTYPE_SHA3_384, + /** SHA3-512 checksum. */ + RTDIGESTTYPE_SHA3_512, +#if 0 + /** SHAKE128 checksum. */ + RTDIGESTTYPE_SHAKE128, + /** SHAKE256 checksum. */ + RTDIGESTTYPE_SHAKE256, +#endif + /** End of valid types. */ + RTDIGESTTYPE_END, + /** Usual 32-bit type blowup. */ + RTDIGESTTYPE_32BIT_HACK = 0x7fffffff +} RTDIGESTTYPE; + +/** + * Process exit codes. + */ +typedef enum RTEXITCODE +{ + /** Success. */ + RTEXITCODE_SUCCESS = 0, + /** General failure. */ + RTEXITCODE_FAILURE = 1, + /** Invalid arguments. */ + RTEXITCODE_SYNTAX = 2, + /** Initialization failure (usually IPRT, but could be used for other + * components as well). */ + RTEXITCODE_INIT = 3, + /** Test skipped. */ + RTEXITCODE_SKIPPED = 4, + /** The end of valid exit codes. */ + RTEXITCODE_END, + /** The usual 32-bit type hack. */ + RTEXITCODE_32BIT_HACK = 0x7fffffff +} RTEXITCODE; + +/** + * Range descriptor. + */ +typedef struct RTRANGE +{ + /** Start offset. */ + uint64_t offStart; + /** Range size. */ + size_t cbRange; +} RTRANGE; +/** Pointer to a range descriptor. */ +typedef RTRANGE RT_FAR *PRTRANGE; +/** Pointer to a readonly range descriptor. */ +typedef const RTRANGE RT_FAR *PCRTRANGE; + + +/** + * Generic pointer union. + */ +typedef union RTPTRUNION +{ + /** Pointer into the void. */ + void RT_FAR *pv; + /** As a signed integer. */ + intptr_t i; + /** As an unsigned integer. */ + uintptr_t u; + /** Pointer to char value. */ + char RT_FAR *pch; + /** Pointer to char value. */ + unsigned char RT_FAR *puch; + /** Pointer to a int value. */ + int RT_FAR *pi; + /** Pointer to a unsigned int value. */ + unsigned int RT_FAR *pu; + /** Pointer to a long value. */ + long RT_FAR *pl; + /** Pointer to a long value. */ + unsigned long RT_FAR *pul; + /** Pointer to a 8-bit unsigned value. */ + uint8_t RT_FAR *pu8; + /** Pointer to a 16-bit unsigned value. */ + uint16_t RT_FAR *pu16; + /** Pointer to a 32-bit unsigned value. */ + uint32_t RT_FAR *pu32; + /** Pointer to a 64-bit unsigned value. */ + uint64_t RT_FAR *pu64; + /** Pointer to a 8-bit signed value. */ + int8_t RT_FAR *pi8; + /** Pointer to a 16-bit signed value. */ + int16_t RT_FAR *pi16; + /** Pointer to a 32-bit signed value. */ + int32_t RT_FAR *pi32; + /** Pointer to a 64-bit signed value. */ + int64_t RT_FAR *pi64; + /** Pointer to a UTF-16 character. */ + PRTUTF16 pwc; + /** Pointer to a UUID character. */ + PRTUUID pUuid; +} RTPTRUNION; +/** Pointer to a pointer union. */ +typedef RTPTRUNION RT_FAR *PRTPTRUNION; + +/** + * Generic const pointer union. + */ +typedef union RTCPTRUNION +{ + /** Pointer into the void. */ + void const RT_FAR *pv; + /** As a signed integer. */ + intptr_t i; + /** As an unsigned integer. */ + uintptr_t u; + /** Pointer to char value. */ + char const RT_FAR *pch; + /** Pointer to char value. */ + unsigned char const RT_FAR *puch; + /** Pointer to a int value. */ + int const RT_FAR *pi; + /** Pointer to a unsigned int value. */ + unsigned int const RT_FAR *pu; + /** Pointer to a long value. */ + long const RT_FAR *pl; + /** Pointer to a long value. */ + unsigned long const RT_FAR *pul; + /** Pointer to a 8-bit unsigned value. */ + uint8_t const RT_FAR *pu8; + /** Pointer to a 16-bit unsigned value. */ + uint16_t const RT_FAR *pu16; + /** Pointer to a 32-bit unsigned value. */ + uint32_t const RT_FAR *pu32; + /** Pointer to a 64-bit unsigned value. */ + uint64_t const RT_FAR *pu64; + /** Pointer to a 8-bit signed value. */ + int8_t const RT_FAR *pi8; + /** Pointer to a 16-bit signed value. */ + int16_t const RT_FAR *pi16; + /** Pointer to a 32-bit signed value. */ + int32_t const RT_FAR *pi32; + /** Pointer to a 64-bit signed value. */ + int64_t const RT_FAR *pi64; + /** Pointer to a UTF-16 character. */ + PCRTUTF16 pwc; + /** Pointer to a UUID character. */ + PCRTUUID pUuid; +} RTCPTRUNION; +/** Pointer to a const pointer union. */ +typedef RTCPTRUNION RT_FAR *PRTCPTRUNION; + +/** + * Generic volatile pointer union. + */ +typedef union RTVPTRUNION +{ + /** Pointer into the void. */ + void volatile RT_FAR *pv; + /** As a signed integer. */ + intptr_t i; + /** As an unsigned integer. */ + uintptr_t u; + /** Pointer to char value. */ + char volatile RT_FAR *pch; + /** Pointer to char value. */ + unsigned char volatile RT_FAR *puch; + /** Pointer to a int value. */ + int volatile RT_FAR *pi; + /** Pointer to a unsigned int value. */ + unsigned int volatile RT_FAR *pu; + /** Pointer to a long value. */ + long volatile RT_FAR *pl; + /** Pointer to a long value. */ + unsigned long volatile RT_FAR *pul; + /** Pointer to a 8-bit unsigned value. */ + uint8_t volatile RT_FAR *pu8; + /** Pointer to a 16-bit unsigned value. */ + uint16_t volatile RT_FAR *pu16; + /** Pointer to a 32-bit unsigned value. */ + uint32_t volatile RT_FAR *pu32; + /** Pointer to a 64-bit unsigned value. */ + uint64_t volatile RT_FAR *pu64; + /** Pointer to a 8-bit signed value. */ + int8_t volatile RT_FAR *pi8; + /** Pointer to a 16-bit signed value. */ + int16_t volatile RT_FAR *pi16; + /** Pointer to a 32-bit signed value. */ + int32_t volatile RT_FAR *pi32; + /** Pointer to a 64-bit signed value. */ + int64_t volatile RT_FAR *pi64; + /** Pointer to a UTF-16 character. */ + RTUTF16 volatile RT_FAR *pwc; + /** Pointer to a UUID character. */ + RTUUID volatile RT_FAR *pUuid; +} RTVPTRUNION; +/** Pointer to a const pointer union. */ +typedef RTVPTRUNION RT_FAR *PRTVPTRUNION; + +/** + * Generic const volatile pointer union. + */ +typedef union RTCVPTRUNION +{ + /** Pointer into the void. */ + void const volatile RT_FAR *pv; + /** As a signed integer. */ + intptr_t i; + /** As an unsigned integer. */ + uintptr_t u; + /** Pointer to char value. */ + char const volatile RT_FAR *pch; + /** Pointer to char value. */ + unsigned char const volatile RT_FAR *puch; + /** Pointer to a int value. */ + int const volatile RT_FAR *pi; + /** Pointer to a unsigned int value. */ + unsigned int const volatile RT_FAR *pu; + /** Pointer to a long value. */ + long const volatile RT_FAR *pl; + /** Pointer to a long value. */ + unsigned long const volatile RT_FAR *pul; + /** Pointer to a 8-bit unsigned value. */ + uint8_t const volatile RT_FAR *pu8; + /** Pointer to a 16-bit unsigned value. */ + uint16_t const volatile RT_FAR *pu16; + /** Pointer to a 32-bit unsigned value. */ + uint32_t const volatile RT_FAR *pu32; + /** Pointer to a 64-bit unsigned value. */ + uint64_t const volatile RT_FAR *pu64; + /** Pointer to a 8-bit signed value. */ + int8_t const volatile RT_FAR *pi8; + /** Pointer to a 16-bit signed value. */ + int16_t const volatile RT_FAR *pi16; + /** Pointer to a 32-bit signed value. */ + int32_t const volatile RT_FAR *pi32; + /** Pointer to a 64-bit signed value. */ + int64_t const volatile RT_FAR *pi64; + /** Pointer to a UTF-16 character. */ + RTUTF16 const volatile RT_FAR *pwc; + /** Pointer to a UUID character. */ + RTUUID const volatile RT_FAR *pUuid; +} RTCVPTRUNION; +/** Pointer to a const pointer union. */ +typedef RTCVPTRUNION RT_FAR *PRTCVPTRUNION; + + + +#ifdef __cplusplus +/** + * Strict type validation helper class. + * + * See RTErrStrictType and RT_SUCCESS_NP. + */ +class RTErrStrictType2 +{ +protected: + /** The status code. */ + int32_t m_rc; + +public: + /** + * Constructor. + * @param rc IPRT style status code. + */ + RTErrStrictType2(int32_t rc) : m_rc(rc) + { + } + + /** + * Get the status code. + * @returns IPRT style status code. + */ + int32_t getValue() const + { + return m_rc; + } +}; +#endif /* __cplusplus */ +/** @} */ + +#define IPRT_COMPLETED_types_h /* hack for watcom and nocrt headers depending on this one. */ +#endif /* !IPRT_INCLUDED_types_h */ + diff --git a/include/iprt/udp.h b/include/iprt/udp.h new file mode 100644 index 00000000..d06a2388 --- /dev/null +++ b/include/iprt/udp.h @@ -0,0 +1,191 @@ +/** @file + * IPRT - UDP/IP. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_udp_h +#define IPRT_INCLUDED_udp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/thread.h> +#include <iprt/net.h> +#include <iprt/sg.h> +#include <iprt/socket.h> + +#ifdef IN_RING0 +# error "There are no RTFile APIs available Ring-0 Host Context!" +#endif + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_udp RTUdp - UDP/IP + * @ingroup grp_rt + * @{ + */ + + +/** + * Handle incoming UDP datagrams. + * + * @returns iprt status code. + * @returns VERR_UDP_SERVER_STOP to terminate the server loop forcing + * the RTUdpCreateServer() call to return. + * @param Sock The socket on which the datagram needs to be received. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNRTUDPSERVE,(RTSOCKET Sock, void *pvUser)); +/** Pointer to a RTUDPSERVE(). */ +typedef FNRTUDPSERVE *PFNRTUDPSERVE; + +/** + * Create single datagram at a time UDP Server in a separate thread. + * + * The thread will loop accepting datagrams and call pfnServe for + * each of the incoming datagrams in turn. The pfnServe function can + * return VERR_UDP_SERVER_STOP too terminate this loop. RTUdpServerDestroy() + * should be used to terminate the server. + * + * @returns iprt status code. + * @param pszAddress The address for creating a datagram socket. + * If NULL or empty string the server is bound to all interfaces. + * @param uPort The port for creating a datagram socket. + * @param enmType The thread type. + * @param pszThrdName The name of the worker thread. + * @param pfnServe The function which will handle incoming datagrams. + * @param pvUser User argument passed to pfnServe. + * @param ppServer Where to store the serverhandle. + */ +RTR3DECL(int) RTUdpServerCreate(const char *pszAddress, unsigned uPort, RTTHREADTYPE enmType, const char *pszThrdName, + PFNRTUDPSERVE pfnServe, void *pvUser, PPRTUDPSERVER ppServer); + +/** + * Create single datagram at a time UDP Server. + * The caller must call RTUdpServerReceive() to actually start the server. + * + * @returns iprt status code. + * @param pszAddress The address for creating a datagram socket. + * If NULL the server is bound to all interfaces. + * @param uPort The port for creating a datagram socket. + * @param ppServer Where to store the serverhandle. + */ +RTR3DECL(int) RTUdpServerCreateEx(const char *pszAddress, uint32_t uPort, PPRTUDPSERVER ppServer); + +/** + * Shuts down the server. + * + * @returns IPRT status code. + * @param pServer Handle to the server. + */ +RTR3DECL(int) RTUdpServerShutdown(PRTUDPSERVER pServer); + +/** + * Closes down and frees a UDP Server. + * + * @returns iprt status code. + * @param pServer Handle to the server. + */ +RTR3DECL(int) RTUdpServerDestroy(PRTUDPSERVER pServer); + +/** + * Listen for incoming datagrams. + * + * The function will loop waiting for datagrams and call pfnServe for + * each of the incoming datagrams in turn. The pfnServe function can + * return VERR_UDP_SERVER_STOP too terminate this loop. A stopped server + * can only be destroyed. + * + * @returns iprt status code. + * @param pServer The server handle as returned from RTUdpServerCreateEx(). + * @param pfnServe The function which will handle incoming datagrams. + * @param pvUser User argument passed to pfnServe. + */ +RTR3DECL(int) RTUdpServerListen(PRTUDPSERVER pServer, PFNRTUDPSERVE pfnServe, void *pvUser); + +/** + * Receive data from a socket. + * + * @returns iprt status code. + * @param Sock Socket descriptor. + * @param pvBuffer Where to put the data we read. + * @param cbBuffer Read buffer size. + * @param pcbRead Number of bytes read. Must be non-NULL. + * @param pSrcAddr The network address to read from. + */ +RTR3DECL(int) RTUdpRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead, PRTNETADDR pSrcAddr); + +/** + * Send data to a socket. + * + * @returns iprt status code. + * @retval VERR_INTERRUPTED if interrupted before anything was written. + * + * @param pServer Handle to the server. + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + * @param pDstAddr Destination address. + */ +RTR3DECL(int) RTUdpWrite(PRTUDPSERVER pServer, const void *pvBuffer, + size_t cbBuffer, PCRTNETADDR pDstAddr); + +/** + * Create and connect a data socket. + * + * @returns iprt status code. + * @param pszAddress The address to connect to. + * @param uPort The port to connect to. + * @param pLocalAddr The local address to bind this socket to, can be + * NULL. + * @param pSock Where to store the handle to the established connection. + */ +RTR3DECL(int) RTUdpCreateClientSocket(const char *pszAddress, uint32_t uPort, PRTNETADDR pLocalAddr, PRTSOCKET pSock); + +/** + * Create a data socket acting as a server. + * + * @returns iprt status code. + * @param pszAddress The address to connect to. + * @param uPort The port to connect to. + * @param pSock Where to store the handle to the established connection. + */ +RTR3DECL(int) RTUdpCreateServerSocket(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock); + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_udp_h */ + diff --git a/include/iprt/uint128.h b/include/iprt/uint128.h new file mode 100644 index 00000000..50b19055 --- /dev/null +++ b/include/iprt/uint128.h @@ -0,0 +1,1479 @@ +/** @file + * IPRT - RTUINT128U & uint128_t methods. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_uint128_h +#define IPRT_INCLUDED_uint128_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/asm.h> +#include <iprt/asm-math.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_uint128 RTUInt128 - 128-bit Unsigned Integer Methods + * @ingroup grp_rt + * @{ + */ + + +/** + * Test if a 128-bit unsigned integer value is zero. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt128IsZero(PCRTUINT128U pValue) +{ +#if ARCH_BITS >= 64 + return pValue->s.Hi == 0 + && pValue->s.Lo == 0; +#else + return pValue->DWords.dw0 == 0 + && pValue->DWords.dw1 == 0 + && pValue->DWords.dw2 == 0 + && pValue->DWords.dw3 == 0; +#endif +} + + +/** + * Set a 128-bit unsigned integer value to zero. + * + * @returns pResult + * @param pResult The result variable. + */ +DECLINLINE(PRTUINT128U) RTUInt128SetZero(PRTUINT128U pResult) +{ +#if ARCH_BITS >= 64 + pResult->s.Hi = 0; + pResult->s.Lo = 0; +#else + pResult->DWords.dw0 = 0; + pResult->DWords.dw1 = 0; + pResult->DWords.dw2 = 0; + pResult->DWords.dw3 = 0; +#endif + return pResult; +} + + +/** + * Set a 128-bit unsigned integer value to the maximum value. + * + * @returns pResult + * @param pResult The result variable. + */ +DECLINLINE(PRTUINT128U) RTUInt128SetMax(PRTUINT128U pResult) +{ +#if ARCH_BITS >= 64 + pResult->s.Hi = UINT64_MAX; + pResult->s.Lo = UINT64_MAX; +#else + pResult->DWords.dw0 = UINT32_MAX; + pResult->DWords.dw1 = UINT32_MAX; + pResult->DWords.dw2 = UINT32_MAX; + pResult->DWords.dw3 = UINT32_MAX; +#endif + return pResult; +} + + + + +/** + * Adds two 128-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128Add(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi + pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo + pValue2->s.Lo; + if (pResult->s.Lo < pValue1->s.Lo) + pResult->s.Hi++; + return pResult; +} + + +/** + * Adds a 128-bit and a 64-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 64-bit. + */ +DECLINLINE(PRTUINT128U) RTUInt128AddU64(PRTUINT128U pResult, PCRTUINT128U pValue1, uint64_t uValue2) +{ + pResult->s.Hi = pValue1->s.Hi; + pResult->s.Lo = pValue1->s.Lo + uValue2; + if (pResult->s.Lo < pValue1->s.Lo) + pResult->s.Hi++; + return pResult; +} + + +/** + * Subtracts a 128-bit unsigned integer value from another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The minuend value. + * @param pValue2 The subtrahend value. + */ +DECLINLINE(PRTUINT128U) RTUInt128Sub(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + pResult->s.Lo = pValue1->s.Lo - pValue2->s.Lo; + pResult->s.Hi = pValue1->s.Hi - pValue2->s.Hi; + if (pResult->s.Lo > pValue1->s.Lo) + pResult->s.Hi--; + return pResult; +} + + +/** + * Multiplies two 128-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128Mul(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + RTUINT64U uTmp; + + /* multiply all dwords in v1 by v2.dw0. */ + pResult->s.Lo = (uint64_t)pValue1->DWords.dw0 * pValue2->DWords.dw0; + + uTmp.u = (uint64_t)pValue1->DWords.dw1 * pValue2->DWords.dw0; + pResult->DWords.dw3 = 0; + pResult->DWords.dw2 = uTmp.DWords.dw1; + pResult->DWords.dw1 += uTmp.DWords.dw0; + if (pResult->DWords.dw1 < uTmp.DWords.dw0) + if (pResult->DWords.dw2++ == UINT32_MAX) + pResult->DWords.dw3++; + + pResult->s.Hi += (uint64_t)pValue1->DWords.dw2 * pValue2->DWords.dw0; + pResult->DWords.dw3 += pValue1->DWords.dw3 * pValue2->DWords.dw0; + + /* multiply dw0, dw1 & dw2 in v1 by v2.dw1. */ + uTmp.u = (uint64_t)pValue1->DWords.dw0 * pValue2->DWords.dw1; + pResult->DWords.dw1 += uTmp.DWords.dw0; + if (pResult->DWords.dw1 < uTmp.DWords.dw0) + if (pResult->DWords.dw2++ == UINT32_MAX) + pResult->DWords.dw3++; + + pResult->DWords.dw2 += uTmp.DWords.dw1; + if (pResult->DWords.dw2 < uTmp.DWords.dw1) + pResult->DWords.dw3++; + + pResult->s.Hi += (uint64_t)pValue1->DWords.dw1 * pValue2->DWords.dw1; + pResult->DWords.dw3 += pValue1->DWords.dw2 * pValue2->DWords.dw1; + + /* multiply dw0 & dw1 in v1 by v2.dw2. */ + pResult->s.Hi += (uint64_t)pValue1->DWords.dw0 * pValue2->DWords.dw2; + pResult->DWords.dw3 += pValue1->DWords.dw1 * pValue2->DWords.dw2; + + /* multiply dw0 in v1 by v2.dw3. */ + pResult->DWords.dw3 += pValue1->DWords.dw0 * pValue2->DWords.dw3; + + return pResult; +} + + +/** + * Multiplies an 128-bit unsigned integer by a 64-bit unsigned integer value. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 64-bit. + */ +#if defined(RT_ARCH_AMD64) +RTDECL(PRTUINT128U) RTUInt128MulByU64(PRTUINT128U pResult, PCRTUINT128U pValue1, uint64_t uValue2); +#else +DECLINLINE(PRTUINT128U) RTUInt128MulByU64(PRTUINT128U pResult, PCRTUINT128U pValue1, uint64_t uValue2) +{ + uint32_t const uLoValue2 = (uint32_t)uValue2; + uint32_t const uHiValue2 = (uint32_t)(uValue2 >> 32); + RTUINT64U uTmp; + + /* multiply all dwords in v1 by uLoValue1. */ + pResult->s.Lo = (uint64_t)pValue1->DWords.dw0 * uLoValue2; + + uTmp.u = (uint64_t)pValue1->DWords.dw1 * uLoValue2; + pResult->DWords.dw3 = 0; + pResult->DWords.dw2 = uTmp.DWords.dw1; + pResult->DWords.dw1 += uTmp.DWords.dw0; + if (pResult->DWords.dw1 < uTmp.DWords.dw0) + if (pResult->DWords.dw2++ == UINT32_MAX) + pResult->DWords.dw3++; + + pResult->s.Hi += (uint64_t)pValue1->DWords.dw2 * uLoValue2; + pResult->DWords.dw3 += pValue1->DWords.dw3 * uLoValue2; + + /* multiply dw0, dw1 & dw2 in v1 by uHiValue2. */ + uTmp.u = (uint64_t)pValue1->DWords.dw0 * uHiValue2; + pResult->DWords.dw1 += uTmp.DWords.dw0; + if (pResult->DWords.dw1 < uTmp.DWords.dw0) + if (pResult->DWords.dw2++ == UINT32_MAX) + pResult->DWords.dw3++; + + pResult->DWords.dw2 += uTmp.DWords.dw1; + if (pResult->DWords.dw2 < uTmp.DWords.dw1) + pResult->DWords.dw3++; + + pResult->s.Hi += (uint64_t)pValue1->DWords.dw1 * uHiValue2; + pResult->DWords.dw3 += pValue1->DWords.dw2 * uHiValue2; + + return pResult; +} +#endif + + +/** + * Multiplies two 64-bit unsigned integer values with 128-bit precision. + * + * @returns pResult + * @param pResult The result variable. + * @param uValue1 The first value. 64-bit. + * @param uValue2 The second value, 64-bit. + */ +DECLINLINE(PRTUINT128U) RTUInt128MulU64ByU64(PRTUINT128U pResult, uint64_t uValue1, uint64_t uValue2) +{ +#ifdef RT_ARCH_AMD64 + pResult->s.Lo = ASMMult2xU64Ret2xU64(uValue1, uValue2, &pResult->s.Hi); +#else + uint32_t const uLoValue1 = (uint32_t)uValue1; + uint32_t const uHiValue1 = (uint32_t)(uValue1 >> 32); + uint32_t const uLoValue2 = (uint32_t)uValue2; + uint32_t const uHiValue2 = (uint32_t)(uValue2 >> 32); + RTUINT64U uTmp; + + /* Multiply uLoValue1 and uHiValue1 by uLoValue1. */ + pResult->s.Lo = (uint64_t)uLoValue1 * uLoValue2; + + uTmp.u = (uint64_t)uHiValue1 * uLoValue2; + pResult->DWords.dw3 = 0; + pResult->DWords.dw2 = uTmp.DWords.dw1; + pResult->DWords.dw1 += uTmp.DWords.dw0; + if (pResult->DWords.dw1 < uTmp.DWords.dw0) + if (pResult->DWords.dw2++ == UINT32_MAX) + pResult->DWords.dw3++; + + /* Multiply uLoValue1 and uHiValue1 by uHiValue2. */ + uTmp.u = (uint64_t)uLoValue1 * uHiValue2; + pResult->DWords.dw1 += uTmp.DWords.dw0; + if (pResult->DWords.dw1 < uTmp.DWords.dw0) + if (pResult->DWords.dw2++ == UINT32_MAX) + pResult->DWords.dw3++; + + pResult->DWords.dw2 += uTmp.DWords.dw1; + if (pResult->DWords.dw2 < uTmp.DWords.dw1) + pResult->DWords.dw3++; + + pResult->s.Hi += (uint64_t)uHiValue1 * uHiValue2; +#endif + return pResult; +} + + +/** + * Multiplies an 128-bit unsigned integer by a 64-bit unsigned integer value, + * returning a 256-bit result (top 64 bits are zero). + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 64-bit. + */ +#if defined(RT_ARCH_AMD64) +RTDECL(PRTUINT256U) RTUInt128MulByU64Ex(PRTUINT256U pResult, PCRTUINT128U pValue1, uint64_t uValue2); +#else +DECLINLINE(PRTUINT256U) RTUInt128MulByU64Ex(PRTUINT256U pResult, PCRTUINT128U pValue1, uint64_t uValue2) +{ + /* multiply the two qwords in pValue1 by uValue2. */ + uint64_t uTmp = 0; + pResult->QWords.qw0 = ASMMult2xU64Ret2xU64(pValue1->s.Lo, uValue2, &uTmp); + pResult->QWords.qw1 = ASMMult2xU64Ret2xU64(pValue1->s.Hi, uValue2, &pResult->QWords.qw2); + pResult->QWords.qw3 = 0; + pResult->QWords.qw1 += uTmp; + if (pResult->QWords.qw1 < uTmp) + pResult->QWords.qw2++; /* This cannot overflow AFAIK: 0xffff*0xffff = 0xFFFE0001 */ + + return pResult; +} +#endif + + +/** + * Multiplies two 128-bit unsigned integer values, returning a 256-bit result. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt128MulEx(PRTUINT256U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + RTUInt128MulByU64Ex(pResult, pValue1, pValue2->s.Lo); + if (pValue2->s.Hi) + { + /* Multiply the two qwords in pValue1 by the high part of uValue2. */ + uint64_t uTmpHi = 0; + uint64_t uTmpLo = ASMMult2xU64Ret2xU64(pValue1->s.Lo, pValue2->s.Hi, &uTmpHi); + pResult->QWords.qw1 += uTmpLo; + if (pResult->QWords.qw1 < uTmpLo) + if (++pResult->QWords.qw2 == 0) + pResult->QWords.qw3++; /* (cannot overflow, was == 0) */ + pResult->QWords.qw2 += uTmpHi; + if (pResult->QWords.qw2 < uTmpHi) + pResult->QWords.qw3++; /* (cannot overflow, was <= 1) */ + + uTmpLo = ASMMult2xU64Ret2xU64(pValue1->s.Hi, pValue2->s.Hi, &uTmpHi); + pResult->QWords.qw2 += uTmpLo; + if (pResult->QWords.qw2 < uTmpLo) + pResult->QWords.qw3++; /* (cannot overflow, was <= 2) */ + pResult->QWords.qw3 += uTmpHi; + } + + return pResult; +} + + +DECLINLINE(PRTUINT128U) RTUInt128DivRem(PRTUINT128U pQuotient, PRTUINT128U pRemainder, PCRTUINT128U pValue1, PCRTUINT128U pValue2); + +/** + * Divides a 128-bit unsigned integer value by another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT128U) RTUInt128Div(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + RTUINT128U Ignored; + return RTUInt128DivRem(pResult, &Ignored, pValue1, pValue2); +} + + +/** + * Divides a 128-bit unsigned integer value by another, returning the remainder. + * + * @returns pResult + * @param pResult The result variable (remainder). + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT128U) RTUInt128Mod(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + RTUINT128U Ignored; + RTUInt128DivRem(&Ignored, pResult, pValue1, pValue2); + return pResult; +} + + +/** + * Bitwise AND of two 128-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128And(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi & pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo & pValue2->s.Lo; + return pResult; +} + + +/** + * Bitwise OR of two 128-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128Or( PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi | pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo | pValue2->s.Lo; + return pResult; +} + + +/** + * Bitwise XOR of two 128-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128Xor(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi ^ pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo ^ pValue2->s.Lo; + return pResult; +} + + +/** + * Shifts a 128-bit unsigned integer value @a cBits to the left. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to shift. + * @param cBits The number of bits to shift it. + */ +DECLINLINE(PRTUINT128U) RTUInt128ShiftLeft(PRTUINT128U pResult, PCRTUINT128U pValue, int cBits) +{ + cBits &= 127; + if (cBits < 64) + { + pResult->s.Lo = pValue->s.Lo << cBits; + pResult->s.Hi = (pValue->s.Hi << cBits) | (pValue->s.Lo >> (64 - cBits)); + } + else + { + pResult->s.Lo = 0; + pResult->s.Hi = pValue->s.Lo << (cBits - 64); + } + return pResult; +} + + +/** + * Shifts a 128-bit unsigned integer value @a cBits to the right. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to shift. + * @param cBits The number of bits to shift it. + */ +DECLINLINE(PRTUINT128U) RTUInt128ShiftRight(PRTUINT128U pResult, PCRTUINT128U pValue, int cBits) +{ + cBits &= 127; + if (cBits < 64) + { + pResult->s.Hi = pValue->s.Hi >> cBits; + pResult->s.Lo = (pValue->s.Lo >> cBits) | (pValue->s.Hi << (64 - cBits)); + } + else + { + pResult->s.Hi = 0; + pResult->s.Lo = pValue->s.Hi >> (cBits - 64); + } + return pResult; +} + + +/** + * Boolean not (result 0 or 1). + * + * @returns pResult. + * @param pResult The result variable. + * @param pValue The value. + */ +DECLINLINE(PRTUINT128U) RTUInt128BooleanNot(PRTUINT128U pResult, PCRTUINT128U pValue) +{ + pResult->s.Lo = pValue->s.Lo || pValue->s.Hi ? 0 : 1; + pResult->s.Hi = 0; + return pResult; +} + + +/** + * Bitwise not (flips each bit of the 128 bits). + * + * @returns pResult. + * @param pResult The result variable. + * @param pValue The value. + */ +DECLINLINE(PRTUINT128U) RTUInt128BitwiseNot(PRTUINT128U pResult, PCRTUINT128U pValue) +{ + pResult->s.Hi = ~pValue->s.Hi; + pResult->s.Lo = ~pValue->s.Lo; + return pResult; +} + + +/** + * Assigns one 128-bit unsigned integer value to another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to assign. + */ +DECLINLINE(PRTUINT128U) RTUInt128Assign(PRTUINT128U pResult, PCRTUINT128U pValue) +{ +#if ARCH_BITS >= 64 + pResult->s.Hi = pValue->s.Hi; + pResult->s.Lo = pValue->s.Lo; +#else + pResult->DWords.dw0 = pValue->DWords.dw0; + pResult->DWords.dw1 = pValue->DWords.dw1; + pResult->DWords.dw2 = pValue->DWords.dw2; + pResult->DWords.dw3 = pValue->DWords.dw3; +#endif + return pResult; +} + + +/** + * Assigns a boolean value to 128-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param fValue The boolean value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignBoolean(PRTUINT128U pValueResult, bool fValue) +{ +#if ARCH_BITS >= 64 + pValueResult->s.Lo = fValue; + pValueResult->s.Hi = 0; +#else + pValueResult->DWords.dw0 = fValue; + pValueResult->DWords.dw1 = 0; + pValueResult->DWords.dw2 = 0; + pValueResult->DWords.dw3 = 0; +#endif + return pValueResult; +} + + +/** + * Assigns a 8-bit unsigned integer value to 128-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u8Value The 8-bit unsigned integer value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignU8(PRTUINT128U pValueResult, uint8_t u8Value) +{ +#if ARCH_BITS >= 64 + pValueResult->s.Lo = u8Value; + pValueResult->s.Hi = 0; +#else + pValueResult->DWords.dw0 = u8Value; + pValueResult->DWords.dw1 = 0; + pValueResult->DWords.dw2 = 0; + pValueResult->DWords.dw3 = 0; +#endif + return pValueResult; +} + + +/** + * Assigns a 16-bit unsigned integer value to 128-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u16Value The 16-bit unsigned integer value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignU16(PRTUINT128U pValueResult, uint16_t u16Value) +{ +#if ARCH_BITS >= 64 + pValueResult->s.Lo = u16Value; + pValueResult->s.Hi = 0; +#else + pValueResult->DWords.dw0 = u16Value; + pValueResult->DWords.dw1 = 0; + pValueResult->DWords.dw2 = 0; + pValueResult->DWords.dw3 = 0; +#endif + return pValueResult; +} + + +/** + * Assigns a 32-bit unsigned integer value to 128-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u32Value The 32-bit unsigned integer value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignU32(PRTUINT128U pValueResult, uint32_t u32Value) +{ +#if ARCH_BITS >= 64 + pValueResult->s.Lo = u32Value; + pValueResult->s.Hi = 0; +#else + pValueResult->DWords.dw0 = u32Value; + pValueResult->DWords.dw1 = 0; + pValueResult->DWords.dw2 = 0; + pValueResult->DWords.dw3 = 0; +#endif + return pValueResult; +} + + +/** + * Assigns a 64-bit unsigned integer value to 128-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u64Value The 64-bit unsigned integer value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignU64(PRTUINT128U pValueResult, uint64_t u64Value) +{ + pValueResult->s.Lo = u64Value; + pValueResult->s.Hi = 0; + return pValueResult; +} + + +/** + * Adds two 128-bit unsigned integer values, storing the result in the first. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignAdd(PRTUINT128U pValue1Result, PCRTUINT128U pValue2) +{ + uint64_t const uTmp = pValue1Result->s.Lo; + pValue1Result->s.Lo += pValue2->s.Lo; + if (pValue1Result->s.Lo < uTmp) + pValue1Result->s.Hi++; + pValue1Result->s.Hi += pValue2->s.Hi; + return pValue1Result; +} + + +/** + * Adds a 64-bit unsigned integer value to a 128-bit unsigned integer values, + * storing the result in the 128-bit one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param uValue2 The second value, 64-bit. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignAddU64(PRTUINT128U pValue1Result, uint64_t uValue2) +{ + pValue1Result->s.Lo += uValue2; + if (pValue1Result->s.Lo < uValue2) + pValue1Result->s.Hi++; + return pValue1Result; +} + + +/** + * Subtracts two 128-bit unsigned integer values, storing the result in the + * first. + * + * @returns pValue1Result. + * @param pValue1Result The minuend value and result. + * @param pValue2 The subtrahend value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignSub(PRTUINT128U pValue1Result, PCRTUINT128U pValue2) +{ + uint64_t const uTmp = pValue1Result->s.Lo; + pValue1Result->s.Lo -= pValue2->s.Lo; + if (pValue1Result->s.Lo > uTmp) + pValue1Result->s.Hi--; + pValue1Result->s.Hi -= pValue2->s.Hi; + return pValue1Result; +} + + +/** + * Negates a 128 number, storing the result in the input. + * + * @returns pValueResult. + * @param pValueResult The value to negate. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignNeg(PRTUINT128U pValueResult) +{ + /* result = 0 - value */ + if (pValueResult->s.Lo != 0) + { + pValueResult->s.Lo = UINT64_C(0) - pValueResult->s.Lo; + pValueResult->s.Hi = UINT64_MAX - pValueResult->s.Hi; + } + else + pValueResult->s.Hi = UINT64_C(0) - pValueResult->s.Hi; + return pValueResult; +} + + +/** + * Multiplies two 128-bit unsigned integer values, storing the result in the + * first. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignMul(PRTUINT128U pValue1Result, PCRTUINT128U pValue2) +{ + RTUINT128U Result; + RTUInt128Mul(&Result, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Divides a 128-bit unsigned integer value by another, storing the result in + * the first. + * + * @returns pValue1Result. + * @param pValue1Result The dividend value and result. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignDiv(PRTUINT128U pValue1Result, PCRTUINT128U pValue2) +{ + RTUINT128U Result; + RTUINT128U Ignored; + RTUInt128DivRem(&Result, &Ignored, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Divides a 128-bit unsigned integer value by another, storing the remainder in + * the first. + * + * @returns pValue1Result. + * @param pValue1Result The dividend value and result (remainder). + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignMod(PRTUINT128U pValue1Result, PCRTUINT128U pValue2) +{ + RTUINT128U Ignored; + RTUINT128U Result; + RTUInt128DivRem(&Ignored, &Result, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Performs a bitwise AND of two 128-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignAnd(PRTUINT128U pValue1Result, PCRTUINT128U pValue2) +{ +#if ARCH_BITS >= 64 + pValue1Result->s.Hi &= pValue2->s.Hi; + pValue1Result->s.Lo &= pValue2->s.Lo; +#else + pValue1Result->DWords.dw0 &= pValue2->DWords.dw0; + pValue1Result->DWords.dw1 &= pValue2->DWords.dw1; + pValue1Result->DWords.dw2 &= pValue2->DWords.dw2; + pValue1Result->DWords.dw3 &= pValue2->DWords.dw3; +#endif + return pValue1Result; +} + + +/** + * Performs a bitwise AND of a 128-bit unsigned integer value and a mask made + * up of the first N bits, assigning the result to the the 128-bit value. + * + * @returns pValueResult. + * @param pValueResult The value and result. + * @param cBits The number of bits to AND (counting from the first + * bit). + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignAndNFirstBits(PRTUINT128U pValueResult, unsigned cBits) +{ + if (cBits <= 64) + { + if (cBits != 64) + pValueResult->s.Lo &= (RT_BIT_64(cBits) - 1); + pValueResult->s.Hi = 0; + } + else if (cBits < 128) + pValueResult->s.Hi &= (RT_BIT_64(cBits - 64) - 1); +/** @todo \#if ARCH_BITS >= 64 */ + return pValueResult; +} + + +/** + * Performs a bitwise OR of two 128-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignOr(PRTUINT128U pValue1Result, PCRTUINT128U pValue2) +{ +#if ARCH_BITS >= 64 + pValue1Result->s.Hi |= pValue2->s.Hi; + pValue1Result->s.Lo |= pValue2->s.Lo; +#else + pValue1Result->DWords.dw0 |= pValue2->DWords.dw0; + pValue1Result->DWords.dw1 |= pValue2->DWords.dw1; + pValue1Result->DWords.dw2 |= pValue2->DWords.dw2; + pValue1Result->DWords.dw3 |= pValue2->DWords.dw3; +#endif + return pValue1Result; +} + + +/** + * ORs in a bit and assign the result to the input value. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param iBit The bit to set (0 based). + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignOrBit(PRTUINT128U pValue1Result, uint32_t iBit) +{ +#if ARCH_BITS >= 64 + if (iBit >= 64) + pValue1Result->s.Hi |= RT_BIT_64(iBit - 64); + else + pValue1Result->s.Lo |= RT_BIT_64(iBit); +#else + if (iBit >= 64) + { + if (iBit >= 96) + pValue1Result->DWords.dw3 |= RT_BIT_32(iBit - 96); + else + pValue1Result->DWords.dw2 |= RT_BIT_32(iBit - 64); + } + else + { + if (iBit >= 32) + pValue1Result->DWords.dw1 |= RT_BIT_32(iBit - 32); + else + pValue1Result->DWords.dw0 |= RT_BIT_32(iBit); + } +#endif + return pValue1Result; +} + + + +/** + * Performs a bitwise XOR of two 128-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignXor(PRTUINT128U pValue1Result, PCRTUINT128U pValue2) +{ +#if ARCH_BITS >= 64 + pValue1Result->s.Hi ^= pValue2->s.Hi; + pValue1Result->s.Lo ^= pValue2->s.Lo; +#else + pValue1Result->DWords.dw0 ^= pValue2->DWords.dw0; + pValue1Result->DWords.dw1 ^= pValue2->DWords.dw1; + pValue1Result->DWords.dw2 ^= pValue2->DWords.dw2; + pValue1Result->DWords.dw3 ^= pValue2->DWords.dw3; +#endif + return pValue1Result; +} + + +/** + * Performs a bitwise left shift on a 128-bit unsigned integer value, assigning + * the result to it. + * + * @returns pValueResult. + * @param pValueResult The first value and result. + * @param cBits The number of bits to shift. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignShiftLeft(PRTUINT128U pValueResult, int cBits) +{ + RTUINT128U const InVal = *pValueResult; +/** @todo \#if ARCH_BITS >= 64 */ + if (cBits > 0) + { + /* (left shift) */ + if (cBits >= 128) + RTUInt128SetZero(pValueResult); + else if (cBits >= 64) + { + pValueResult->s.Lo = 0; + pValueResult->s.Hi = InVal.s.Lo << (cBits - 64); + } + else + { + pValueResult->s.Hi = InVal.s.Hi << cBits; + pValueResult->s.Hi |= InVal.s.Lo >> (64 - cBits); + pValueResult->s.Lo = InVal.s.Lo << cBits; + } + } + else if (cBits < 0) + { + /* (right shift) */ + cBits = -cBits; + if (cBits >= 128) + RTUInt128SetZero(pValueResult); + else if (cBits >= 64) + { + pValueResult->s.Hi = 0; + pValueResult->s.Lo = InVal.s.Hi >> (cBits - 64); + } + else + { + pValueResult->s.Lo = InVal.s.Lo >> cBits; + pValueResult->s.Lo |= InVal.s.Hi << (64 - cBits); + pValueResult->s.Hi = InVal.s.Hi >> cBits; + } + } + return pValueResult; +} + + +/** + * Performs a bitwise left shift on a 128-bit unsigned integer value, assigning + * the result to it. + * + * @returns pValueResult. + * @param pValueResult The first value and result. + * @param cBits The number of bits to shift. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignShiftRight(PRTUINT128U pValueResult, int cBits) +{ + return RTUInt128AssignShiftLeft(pValueResult, -cBits); +} + + +/** + * Performs a bitwise NOT on a 128-bit unsigned integer value, assigning the + * result to it. + * + * @returns pValueResult + * @param pValueResult The value and result. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignBitwiseNot(PRTUINT128U pValueResult) +{ +#if ARCH_BITS >= 64 + pValueResult->s.Hi = ~pValueResult->s.Hi; + pValueResult->s.Lo = ~pValueResult->s.Lo; +#else + pValueResult->DWords.dw0 = ~pValueResult->DWords.dw0; + pValueResult->DWords.dw1 = ~pValueResult->DWords.dw1; + pValueResult->DWords.dw2 = ~pValueResult->DWords.dw2; + pValueResult->DWords.dw3 = ~pValueResult->DWords.dw3; +#endif + return pValueResult; +} + + +/** + * Performs a boolean NOT on a 128-bit unsigned integer value, assigning the + * result to it. + * + * @returns pValueResult + * @param pValueResult The value and result. + */ +DECLINLINE(PRTUINT128U) RTUInt128AssignBooleanNot(PRTUINT128U pValueResult) +{ + return RTUInt128AssignBoolean(pValueResult, RTUInt128IsZero(pValueResult)); +} + + +/** + * Compares two 128-bit unsigned integer values. + * + * @retval 0 if equal. + * @retval -1 if the first value is smaller than the second. + * @retval 1 if the first value is larger than the second. + * + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(int) RTUInt128Compare(PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ +#if ARCH_BITS >= 64 + if (pValue1->s.Hi != pValue2->s.Hi) + return pValue1->s.Hi > pValue2->s.Hi ? 1 : -1; + if (pValue1->s.Lo != pValue2->s.Lo) + return pValue1->s.Lo > pValue2->s.Lo ? 1 : -1; + return 0; +#else + if (pValue1->DWords.dw3 != pValue2->DWords.dw3) + return pValue1->DWords.dw3 > pValue2->DWords.dw3 ? 1 : -1; + if (pValue1->DWords.dw2 != pValue2->DWords.dw2) + return pValue1->DWords.dw2 > pValue2->DWords.dw2 ? 1 : -1; + if (pValue1->DWords.dw1 != pValue2->DWords.dw1) + return pValue1->DWords.dw1 > pValue2->DWords.dw1 ? 1 : -1; + if (pValue1->DWords.dw0 != pValue2->DWords.dw0) + return pValue1->DWords.dw0 > pValue2->DWords.dw0 ? 1 : -1; + return 0; +#endif +} + + +/** + * Tests if a 128-bit unsigned integer value is smaller than another. + * + * @returns true if the first value is smaller, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt128IsSmaller(PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ +#if ARCH_BITS >= 64 + return pValue1->s.Hi < pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo < pValue2->s.Lo); +#else + return pValue1->DWords.dw3 < pValue2->DWords.dw3 + || ( pValue1->DWords.dw3 == pValue2->DWords.dw3 + && ( pValue1->DWords.dw2 < pValue2->DWords.dw2 + || ( pValue1->DWords.dw2 == pValue2->DWords.dw2 + && ( pValue1->DWords.dw1 < pValue2->DWords.dw1 + || ( pValue1->DWords.dw1 == pValue2->DWords.dw1 + && pValue1->DWords.dw0 < pValue2->DWords.dw0))))); +#endif +} + + +/** + * Tests if a 128-bit unsigned integer value is larger than another. + * + * @returns true if the first value is larger, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt128IsLarger(PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ +#if ARCH_BITS >= 64 + return pValue1->s.Hi > pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo > pValue2->s.Lo); +#else + return pValue1->DWords.dw3 > pValue2->DWords.dw3 + || ( pValue1->DWords.dw3 == pValue2->DWords.dw3 + && ( pValue1->DWords.dw2 > pValue2->DWords.dw2 + || ( pValue1->DWords.dw2 == pValue2->DWords.dw2 + && ( pValue1->DWords.dw1 > pValue2->DWords.dw1 + || ( pValue1->DWords.dw1 == pValue2->DWords.dw1 + && pValue1->DWords.dw0 > pValue2->DWords.dw0))))); +#endif +} + + +/** + * Tests if a 128-bit unsigned integer value is larger or equal than another. + * + * @returns true if the first value is larger or equal, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt128IsLargerOrEqual(PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ +#if ARCH_BITS >= 64 + return pValue1->s.Hi > pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo >= pValue2->s.Lo); +#else + return pValue1->DWords.dw3 > pValue2->DWords.dw3 + || ( pValue1->DWords.dw3 == pValue2->DWords.dw3 + && ( pValue1->DWords.dw2 > pValue2->DWords.dw2 + || ( pValue1->DWords.dw2 == pValue2->DWords.dw2 + && ( pValue1->DWords.dw1 > pValue2->DWords.dw1 + || ( pValue1->DWords.dw1 == pValue2->DWords.dw1 + && pValue1->DWords.dw0 >= pValue2->DWords.dw0))))); +#endif +} + + +/** + * Tests if two 128-bit unsigned integer values not equal. + * + * @returns true if equal, false if not equal. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt128IsEqual(PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ +#if ARCH_BITS >= 64 + return pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo == pValue2->s.Lo; +#else + return pValue1->DWords.dw0 == pValue2->DWords.dw0 + && pValue1->DWords.dw1 == pValue2->DWords.dw1 + && pValue1->DWords.dw2 == pValue2->DWords.dw2 + && pValue1->DWords.dw3 == pValue2->DWords.dw3; +#endif +} + + +/** + * Tests if two 128-bit unsigned integer values are not equal. + * + * @returns true if not equal, false if equal. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt128IsNotEqual(PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + return !RTUInt128IsEqual(pValue1, pValue2); +} + + +/** + * Sets a bit in a 128-bit unsigned integer type. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to set. + */ +DECLINLINE(PRTUINT128U) RTUInt128BitSet(PRTUINT128U pValueResult, unsigned iBit) +{ + if (iBit < 64) + { +#if ARCH_BITS >= 64 + pValueResult->s.Lo |= RT_BIT_64(iBit); +#else + if (iBit < 32) + pValueResult->DWords.dw0 |= RT_BIT_32(iBit); + else + pValueResult->DWords.dw1 |= RT_BIT_32(iBit - 32); +#endif + } + else if (iBit < 128) + { +#if ARCH_BITS >= 64 + pValueResult->s.Hi |= RT_BIT_64(iBit - 64); +#else + if (iBit < 96) + pValueResult->DWords.dw2 |= RT_BIT_32(iBit - 64); + else + pValueResult->DWords.dw3 |= RT_BIT_32(iBit - 96); +#endif + } + return pValueResult; +} + + +/** + * Sets a bit in a 128-bit unsigned integer type. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to set. + */ +DECLINLINE(PRTUINT128U) RTUInt128BitClear(PRTUINT128U pValueResult, unsigned iBit) +{ + if (iBit < 64) + { +#if ARCH_BITS >= 64 + pValueResult->s.Lo &= ~RT_BIT_64(iBit); +#else + if (iBit < 32) + pValueResult->DWords.dw0 &= ~RT_BIT_32(iBit); + else + pValueResult->DWords.dw1 &= ~RT_BIT_32(iBit - 32); +#endif + } + else if (iBit < 128) + { +#if ARCH_BITS >= 64 + pValueResult->s.Hi &= ~RT_BIT_64(iBit - 64); +#else + if (iBit < 96) + pValueResult->DWords.dw2 &= ~RT_BIT_32(iBit - 64); + else + pValueResult->DWords.dw3 &= ~RT_BIT_32(iBit - 96); +#endif + } + return pValueResult; +} + + +/** + * Tests if a bit in a 128-bit unsigned integer value is set. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to test. + */ +DECLINLINE(bool) RTUInt128BitTest(PRTUINT128U pValueResult, unsigned iBit) +{ + bool fRc; + if (iBit < 64) + { +#if ARCH_BITS >= 64 + fRc = RT_BOOL(pValueResult->s.Lo & RT_BIT_64(iBit)); +#else + if (iBit < 32) + fRc = RT_BOOL(pValueResult->DWords.dw0 & RT_BIT_32(iBit)); + else + fRc = RT_BOOL(pValueResult->DWords.dw1 & RT_BIT_32(iBit - 32)); +#endif + } + else if (iBit < 128) + { +#if ARCH_BITS >= 64 + fRc = RT_BOOL(pValueResult->s.Hi & RT_BIT_64(iBit - 64)); +#else + if (iBit < 96) + fRc = RT_BOOL(pValueResult->DWords.dw2 & RT_BIT_32(iBit - 64)); + else + fRc = RT_BOOL(pValueResult->DWords.dw3 & RT_BIT_32(iBit - 96)); +#endif + } + else + fRc = false; + return fRc; +} + + +/** + * Set a range of bits a 128-bit unsigned integer value. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iFirstBit The first bit to test. + * @param cBits The number of bits to set. + */ +DECLINLINE(PRTUINT128U) RTUInt128BitSetRange(PRTUINT128U pValueResult, unsigned iFirstBit, unsigned cBits) +{ + /* bounds check & fix. */ + if (iFirstBit < 128) + { + if (iFirstBit + cBits > 128) + cBits = 128 - iFirstBit; + +#if ARCH_BITS >= 64 + if (iFirstBit + cBits < 64) + pValueResult->s.Lo |= (RT_BIT_64(cBits) - 1) << iFirstBit; + else if (iFirstBit + cBits < 128 && iFirstBit >= 64) + pValueResult->s.Hi |= (RT_BIT_64(cBits) - 1) << (iFirstBit - 64); + else +#else + if (iFirstBit + cBits < 32) + pValueResult->DWords.dw0 |= (RT_BIT_32(cBits) - 1) << iFirstBit; + else if (iFirstBit + cBits < 64 && iFirstBit >= 32) + pValueResult->DWords.dw1 |= (RT_BIT_32(cBits) - 1) << (iFirstBit - 32); + else if (iFirstBit + cBits < 96 && iFirstBit >= 64) + pValueResult->DWords.dw2 |= (RT_BIT_32(cBits) - 1) << (iFirstBit - 64); + else if (iFirstBit + cBits < 128 && iFirstBit >= 96) + pValueResult->DWords.dw3 |= (RT_BIT_32(cBits) - 1) << (iFirstBit - 96); + else +#endif + while (cBits-- > 0) + RTUInt128BitSet(pValueResult, iFirstBit++); + } + return pValueResult; +} + + +/** + * Test if all the bits of a 128-bit unsigned integer value are set. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt128BitAreAllSet(PRTUINT128U pValue) +{ +#if ARCH_BITS >= 64 + return pValue->s.Hi == UINT64_MAX + && pValue->s.Lo == UINT64_MAX; +#else + return pValue->DWords.dw0 == UINT32_MAX + && pValue->DWords.dw1 == UINT32_MAX + && pValue->DWords.dw2 == UINT32_MAX + && pValue->DWords.dw3 == UINT32_MAX; +#endif +} + + +/** + * Test if all the bits of a 128-bit unsigned integer value are clear. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt128BitAreAllClear(PRTUINT128U pValue) +{ +#if ARCH_BITS >= 64 + return pValue->s.Hi == 0 + && pValue->s.Lo == 0; +#else + return pValue->DWords.dw0 == 0 + && pValue->DWords.dw1 == 0 + && pValue->DWords.dw2 == 0 + && pValue->DWords.dw3 == 0; +#endif +} + + +/** + * Number of significant bits in the value. + * + * This is the same a ASMBitLastSetU64 and ASMBitLastSetU32. + * + * @returns 0 if zero, 1-base index of the last bit set. + * @param pValue The value to examine. + */ +DECLINLINE(uint32_t) RTUInt128BitCount(PCRTUINT128U pValue) +{ + uint32_t cBits; + if (pValue->s.Hi != 0) + { + if (pValue->DWords.dw3) + cBits = 96 + ASMBitLastSetU32(pValue->DWords.dw3); + else + cBits = 64 + ASMBitLastSetU32(pValue->DWords.dw2); + } + else + { + if (pValue->DWords.dw1) + cBits = 32 + ASMBitLastSetU32(pValue->DWords.dw1); + else + cBits = 0 + ASMBitLastSetU32(pValue->DWords.dw0); + } + return cBits; +} + + +/** + * Divides a 128-bit unsigned integer value by another, returning both quotient + * and remainder. + * + * @returns pQuotient, NULL if pValue2 is 0. + * @param pQuotient Where to return the quotient. + * @param pRemainder Where to return the remainder. + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT128U) RTUInt128DivRem(PRTUINT128U pQuotient, PRTUINT128U pRemainder, PCRTUINT128U pValue1, PCRTUINT128U pValue2) +{ + int iDiff; + + /* + * Sort out all the special cases first. + */ + /* Divide by zero or 1? */ + if (!pValue2->s.Hi) + { + if (!pValue2->s.Lo) + return NULL; + + if (pValue2->s.Lo == 1) + { + RTUInt128SetZero(pRemainder); + *pQuotient = *pValue1; + return pQuotient; + } + /** @todo RTUint128DivModBy64 */ + } + + /* Dividend is smaller? */ + iDiff = RTUInt128Compare(pValue1, pValue2); + if (iDiff < 0) + { + *pRemainder = *pValue1; + RTUInt128SetZero(pQuotient); + } + + /* The values are equal? */ + else if (iDiff == 0) + { + RTUInt128SetZero(pRemainder); + RTUInt128AssignU64(pQuotient, 1); + } + else + { + /* + * Prepare. + */ + uint32_t iBitAdder = RTUInt128BitCount(pValue1) - RTUInt128BitCount(pValue2); + RTUINT128U NormDivisor = *pValue2; + if (iBitAdder) + { + RTUInt128ShiftLeft(&NormDivisor, pValue2, iBitAdder); + if (RTUInt128IsLarger(&NormDivisor, pValue1)) + { + RTUInt128AssignShiftRight(&NormDivisor, 1); + iBitAdder--; + } + } + else + NormDivisor = *pValue2; + + RTUInt128SetZero(pQuotient); + *pRemainder = *pValue1; + + /* + * Do the division. + */ + if (RTUInt128IsLargerOrEqual(pRemainder, pValue2)) + { + for (;;) + { + if (RTUInt128IsLargerOrEqual(pRemainder, &NormDivisor)) + { + RTUInt128AssignSub(pRemainder, &NormDivisor); + RTUInt128AssignOrBit(pQuotient, iBitAdder); + } + if (RTUInt128IsSmaller(pRemainder, pValue2)) + break; + RTUInt128AssignShiftRight(&NormDivisor, 1); + iBitAdder--; + } + } + } + return pQuotient; +} + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_uint128_h */ + diff --git a/include/iprt/uint256.h b/include/iprt/uint256.h new file mode 100644 index 00000000..351f7f4e --- /dev/null +++ b/include/iprt/uint256.h @@ -0,0 +1,1241 @@ +/** @file + * IPRT - RTUINT256U methods. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_uint256_h +#define IPRT_INCLUDED_uint256_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/asm.h> +#include <iprt/asm-math.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_uint256 RTUInt256 - 256-bit Unsigned Integer Methods + * @ingroup grp_rt + * @{ + */ + + +/** + * Test if a 256-bit unsigned integer value is zero. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt256IsZero(PCRTUINT256U pValue) +{ +#if ARCH_BITS >= 64 + return pValue->QWords.qw0 == 0 + && pValue->QWords.qw1 == 0 + && pValue->QWords.qw2 == 0 + && pValue->QWords.qw3 == 0; +#else + return pValue->DWords.dw0 == 0 + && pValue->DWords.dw1 == 0 + && pValue->DWords.dw2 == 0 + && pValue->DWords.dw3 == 0 + && pValue->DWords.dw4 == 0 + && pValue->DWords.dw5 == 0 + && pValue->DWords.dw6 == 0 + && pValue->DWords.dw7 == 0; +#endif +} + + +/** + * Set a 256-bit unsigned integer value to zero. + * + * @returns pResult + * @param pResult The result variable. + */ +DECLINLINE(PRTUINT256U) RTUInt256SetZero(PRTUINT256U pResult) +{ +#if ARCH_BITS >= 64 + pResult->QWords.qw0 = 0; + pResult->QWords.qw1 = 0; + pResult->QWords.qw2 = 0; + pResult->QWords.qw3 = 0; +#else + pResult->DWords.dw0 = 0; + pResult->DWords.dw1 = 0; + pResult->DWords.dw2 = 0; + pResult->DWords.dw3 = 0; + pResult->DWords.dw4 = 0; + pResult->DWords.dw5 = 0; + pResult->DWords.dw6 = 0; + pResult->DWords.dw7 = 0; +#endif + return pResult; +} + + +/** + * Set a 256-bit unsigned integer value to the maximum value. + * + * @returns pResult + * @param pResult The result variable. + */ +DECLINLINE(PRTUINT256U) RTUInt256SetMax(PRTUINT256U pResult) +{ +#if ARCH_BITS >= 64 + pResult->QWords.qw0 = UINT64_MAX; + pResult->QWords.qw1 = UINT64_MAX; + pResult->QWords.qw2 = UINT64_MAX; + pResult->QWords.qw3 = UINT64_MAX; +#else + pResult->DWords.dw0 = UINT32_MAX; + pResult->DWords.dw1 = UINT32_MAX; + pResult->DWords.dw2 = UINT32_MAX; + pResult->DWords.dw3 = UINT32_MAX; + pResult->DWords.dw4 = UINT32_MAX; + pResult->DWords.dw5 = UINT32_MAX; + pResult->DWords.dw6 = UINT32_MAX; + pResult->DWords.dw7 = UINT32_MAX; +#endif + return pResult; +} + + + + +/** + * Adds two 256-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256Add(PRTUINT256U pResult, PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + unsigned uCarry; + pResult->QWords.qw0 = pValue1->QWords.qw0 + pValue2->QWords.qw0; + uCarry = pResult->QWords.qw0 < pValue1->QWords.qw0; + + pResult->QWords.qw1 = pValue1->QWords.qw1 + pValue2->QWords.qw1 + uCarry; + uCarry = uCarry ? pResult->QWords.qw1 <= pValue1->QWords.qw1 : pResult->QWords.qw1 < pValue1->QWords.qw1; + + pResult->QWords.qw2 = pValue1->QWords.qw2 + pValue2->QWords.qw2 + uCarry; + uCarry = uCarry ? pResult->QWords.qw2 <= pValue1->QWords.qw2 : pResult->QWords.qw2 < pValue1->QWords.qw2; + + pResult->QWords.qw3 = pValue1->QWords.qw3 + pValue2->QWords.qw3 + uCarry; + return pResult; +} + + +/** + * Adds a 256-bit and a 64-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 64-bit. + */ +DECLINLINE(PRTUINT256U) RTUInt256AddU64(PRTUINT256U pResult, PCRTUINT256U pValue1, uint64_t uValue2) +{ + pResult->QWords.qw3 = pValue1->QWords.qw3; + pResult->QWords.qw2 = pValue1->QWords.qw2; + pResult->QWords.qw1 = pValue1->QWords.qw1; + pResult->QWords.qw0 = pValue1->QWords.qw0 + uValue2; + if (pResult->QWords.qw0 < uValue2) + if (pResult->QWords.qw1++ == UINT64_MAX) + if (pResult->QWords.qw2++ == UINT64_MAX) + pResult->QWords.qw3++; + return pResult; +} + + +/** + * Subtracts a 256-bit unsigned integer value from another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The minuend value. + * @param pValue2 The subtrahend value. + */ +DECLINLINE(PRTUINT256U) RTUInt256Sub(PRTUINT256U pResult, PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + unsigned uBorrow; + pResult->QWords.qw0 = pValue1->QWords.qw0 - pValue2->QWords.qw0; + uBorrow = pResult->QWords.qw0 > pValue1->QWords.qw0; + + pResult->QWords.qw1 = pValue1->QWords.qw1 - pValue2->QWords.qw1 - uBorrow; + uBorrow = uBorrow ? pResult->QWords.qw1 >= pValue1->QWords.qw1 : pResult->QWords.qw1 > pValue1->QWords.qw1; + + pResult->QWords.qw2 = pValue1->QWords.qw2 - pValue2->QWords.qw2 - uBorrow; + uBorrow = uBorrow ? pResult->QWords.qw2 >= pValue1->QWords.qw2 : pResult->QWords.qw2 > pValue1->QWords.qw2; + + pResult->QWords.qw3 = pValue1->QWords.qw3 - pValue2->QWords.qw3 - uBorrow; + return pResult; +} + + +/** + * Multiplies two 256-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +RTDECL(PRTUINT256U) RTUInt256Mul(PRTUINT256U pResult, PCRTUINT256U pValue1, PCRTUINT256U pValue2); + +/** + * Multiplies an 256-bit unsigned integer by a 64-bit unsigned integer value. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 64-bit. + */ +RTDECL(PRTUINT256U) RTUInt256MulByU64(PRTUINT256U pResult, PCRTUINT256U pValue1, uint64_t uValue2); + +/** + * Divides a 256-bit unsigned integer value by another, returning both quotient + * and remainder. + * + * @returns pQuotient, NULL if pValue2 is 0. + * @param pQuotient Where to return the quotient. + * @param pRemainder Where to return the remainder. + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +RTDECL(PRTUINT256U) RTUInt256DivRem(PRTUINT256U pQuotient, PRTUINT256U pRemainder, PCRTUINT256U pValue1, PCRTUINT256U pValue2); + +/** + * Divides a 256-bit unsigned integer value by another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT256U) RTUInt256Div(PRTUINT256U pResult, PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + RTUINT256U Ignored; + return RTUInt256DivRem(pResult, &Ignored, pValue1, pValue2); +} + + +/** + * Divides a 256-bit unsigned integer value by another, returning the remainder. + * + * @returns pResult + * @param pResult The result variable (remainder). + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT256U) RTUInt256Mod(PRTUINT256U pResult, PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + RTUINT256U Ignored; + RTUInt256DivRem(&Ignored, pResult, pValue1, pValue2); + return pResult; +} + + +/** + * Bitwise AND of two 256-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256And(PRTUINT256U pResult, PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + pResult->QWords.qw0 = pValue1->QWords.qw0 & pValue2->QWords.qw0; + pResult->QWords.qw1 = pValue1->QWords.qw1 & pValue2->QWords.qw1; + pResult->QWords.qw2 = pValue1->QWords.qw2 & pValue2->QWords.qw2; + pResult->QWords.qw3 = pValue1->QWords.qw3 & pValue2->QWords.qw3; + return pResult; +} + + +/** + * Bitwise OR of two 256-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256Or( PRTUINT256U pResult, PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + pResult->QWords.qw0 = pValue1->QWords.qw0 | pValue2->QWords.qw0; + pResult->QWords.qw1 = pValue1->QWords.qw1 | pValue2->QWords.qw1; + pResult->QWords.qw2 = pValue1->QWords.qw2 | pValue2->QWords.qw2; + pResult->QWords.qw3 = pValue1->QWords.qw3 | pValue2->QWords.qw3; + return pResult; +} + + +/** + * Bitwise XOR of two 256-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256Xor(PRTUINT256U pResult, PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + pResult->QWords.qw0 = pValue1->QWords.qw0 ^ pValue2->QWords.qw0; + pResult->QWords.qw1 = pValue1->QWords.qw1 ^ pValue2->QWords.qw1; + pResult->QWords.qw2 = pValue1->QWords.qw2 ^ pValue2->QWords.qw2; + pResult->QWords.qw3 = pValue1->QWords.qw3 ^ pValue2->QWords.qw3; + return pResult; +} + + +/** + * Shifts a 256-bit unsigned integer value @a cBits to the left. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to shift. + * @param cBits The number of bits to shift it. This is masked + * by 255 before shifting. + */ +DECLINLINE(PRTUINT256U) RTUInt256ShiftLeft(PRTUINT256U pResult, PCRTUINT256U pValue, unsigned cBits) +{ + /* This is a bit bulky & impractical since we cannot access the data using + an array because it is organized according to host endianness. Sigh. */ + cBits &= 255; + if (!(cBits & 0x3f)) + { + if (cBits == 0) + *pResult = *pValue; + else + { + pResult->QWords.qw0 = 0; + if (cBits == 64) + { + pResult->QWords.qw1 = pValue->QWords.qw0; + pResult->QWords.qw2 = pValue->QWords.qw1; + pResult->QWords.qw3 = pValue->QWords.qw2; + } + else + { + pResult->QWords.qw1 = 0; + if (cBits == 128) + { + pResult->QWords.qw2 = pValue->QWords.qw0; + pResult->QWords.qw3 = pValue->QWords.qw1; + } + else + { + pResult->QWords.qw2 = 0; + pResult->QWords.qw3 = pValue->QWords.qw0; + } + } + } + } + else if (cBits < 128) + { + if (cBits < 64) + { + pResult->QWords.qw0 = pValue->QWords.qw0 << cBits; + pResult->QWords.qw1 = pValue->QWords.qw0 >> (64 - cBits); + pResult->QWords.qw1 |= pValue->QWords.qw1 << cBits; + pResult->QWords.qw2 = pValue->QWords.qw1 >> (64 - cBits); + pResult->QWords.qw2 |= pValue->QWords.qw2 << cBits; + pResult->QWords.qw3 = pValue->QWords.qw2 >> (64 - cBits); + pResult->QWords.qw3 |= pValue->QWords.qw3 << cBits; + } + else + { + cBits -= 64; + pResult->QWords.qw0 = 0; + pResult->QWords.qw1 = pValue->QWords.qw0 << cBits; + pResult->QWords.qw2 = pValue->QWords.qw0 >> (64 - cBits); + pResult->QWords.qw2 |= pValue->QWords.qw1 << cBits; + pResult->QWords.qw3 = pValue->QWords.qw1 >> (64 - cBits); + pResult->QWords.qw3 |= pValue->QWords.qw2 << cBits; + } + } + else + { + if (cBits < 192) + { + cBits -= 128; + pResult->QWords.qw0 = 0; + pResult->QWords.qw1 = 0; + pResult->QWords.qw2 = pValue->QWords.qw0 << cBits; + pResult->QWords.qw3 = pValue->QWords.qw0 >> (64 - cBits); + pResult->QWords.qw3 |= pValue->QWords.qw1 << cBits; + } + else + { + cBits -= 192; + pResult->QWords.qw0 = 0; + pResult->QWords.qw1 = 0; + pResult->QWords.qw2 = 0; + pResult->QWords.qw3 = pValue->QWords.qw0 << cBits; + } + } + return pResult; +} + + +/** + * Shifts a 256-bit unsigned integer value @a cBits to the right. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to shift. + * @param cBits The number of bits to shift it. This is masked + * by 255 before shifting. + */ +DECLINLINE(PRTUINT256U) RTUInt256ShiftRight(PRTUINT256U pResult, PCRTUINT256U pValue, unsigned cBits) +{ + /* This is a bit bulky & impractical since we cannot access the data using + an array because it is organized according to host endianness. Sigh. */ + cBits &= 255; + if (!(cBits & 0x3f)) + { + if (cBits == 0) + *pResult = *pValue; + else + { + if (cBits == 64) + { + pResult->QWords.qw0 = pValue->QWords.qw1; + pResult->QWords.qw1 = pValue->QWords.qw2; + pResult->QWords.qw2 = pValue->QWords.qw3; + } + else + { + if (cBits == 128) + { + pResult->QWords.qw0 = pValue->QWords.qw2; + pResult->QWords.qw1 = pValue->QWords.qw3; + } + else + { + pResult->QWords.qw0 = pValue->QWords.qw3; + pResult->QWords.qw1 = 0; + } + pResult->QWords.qw2 = 0; + } + pResult->QWords.qw3 = 0; + } + } + else if (cBits < 128) + { + if (cBits < 64) + { + pResult->QWords.qw0 = pValue->QWords.qw0 >> cBits; + pResult->QWords.qw0 |= pValue->QWords.qw1 << (64 - cBits); + pResult->QWords.qw1 = pValue->QWords.qw1 >> cBits; + pResult->QWords.qw1 |= pValue->QWords.qw2 << (64 - cBits); + pResult->QWords.qw2 = pValue->QWords.qw2 >> cBits; + pResult->QWords.qw2 |= pValue->QWords.qw3 << (64 - cBits); + pResult->QWords.qw3 = pValue->QWords.qw3 >> cBits; + } + else + { + cBits -= 64; + pResult->QWords.qw0 = pValue->QWords.qw1 >> cBits; + pResult->QWords.qw0 |= pValue->QWords.qw2 << (64 - cBits); + pResult->QWords.qw1 = pValue->QWords.qw2 >> cBits; + pResult->QWords.qw1 |= pValue->QWords.qw3 << (64 - cBits); + pResult->QWords.qw2 = pValue->QWords.qw3 >> cBits; + pResult->QWords.qw3 = 0; + } + } + else + { + if (cBits < 192) + { + cBits -= 128; + pResult->QWords.qw0 = pValue->QWords.qw2 >> cBits; + pResult->QWords.qw0 |= pValue->QWords.qw3 << (64 - cBits); + pResult->QWords.qw1 = pValue->QWords.qw3 >> cBits; + pResult->QWords.qw2 = 0; + pResult->QWords.qw3 = 0; + } + else + { + cBits -= 192; + pResult->QWords.qw0 = pValue->QWords.qw3 >> cBits; + pResult->QWords.qw1 = 0; + pResult->QWords.qw2 = 0; + pResult->QWords.qw3 = 0; + } + } + return pResult; +} + + +/** + * Boolean not (result 0 or 1). + * + * @returns pResult. + * @param pResult The result variable. + * @param pValue The value. + */ +DECLINLINE(PRTUINT256U) RTUInt256BooleanNot(PRTUINT256U pResult, PCRTUINT256U pValue) +{ + pResult->QWords.qw0 = RTUInt256IsZero(pValue); + pResult->QWords.qw1 = 0; + pResult->QWords.qw2 = 0; + pResult->QWords.qw3 = 0; + return pResult; +} + + +/** + * Bitwise not (flips each bit of the 256 bits). + * + * @returns pResult. + * @param pResult The result variable. + * @param pValue The value. + */ +DECLINLINE(PRTUINT256U) RTUInt256BitwiseNot(PRTUINT256U pResult, PCRTUINT256U pValue) +{ + pResult->QWords.qw0 = ~pValue->QWords.qw0; + pResult->QWords.qw1 = ~pValue->QWords.qw1; + pResult->QWords.qw2 = ~pValue->QWords.qw2; + pResult->QWords.qw3 = ~pValue->QWords.qw3; + return pResult; +} + + +/** + * Assigns one 256-bit unsigned integer value to another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to assign. + */ +DECLINLINE(PRTUINT256U) RTUInt256Assign(PRTUINT256U pResult, PCRTUINT256U pValue) +{ + pResult->QWords.qw0 = pValue->QWords.qw0; + pResult->QWords.qw1 = pValue->QWords.qw1; + pResult->QWords.qw2 = pValue->QWords.qw2; + pResult->QWords.qw3 = pValue->QWords.qw3; + return pResult; +} + + +/** + * Assigns a boolean value to 256-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param fValue The boolean value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignBoolean(PRTUINT256U pValueResult, bool fValue) +{ + pValueResult->QWords.qw0 = fValue; + pValueResult->QWords.qw1 = 0; + pValueResult->QWords.qw2 = 0; + pValueResult->QWords.qw3 = 0; + return pValueResult; +} + + +/** + * Assigns a 8-bit unsigned integer value to 256-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u8Value The 8-bit unsigned integer value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignU8(PRTUINT256U pValueResult, uint8_t u8Value) +{ + pValueResult->QWords.qw0 = u8Value; + pValueResult->QWords.qw1 = 0; + pValueResult->QWords.qw2 = 0; + pValueResult->QWords.qw3 = 0; + return pValueResult; +} + + +/** + * Assigns a 16-bit unsigned integer value to 256-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u16Value The 16-bit unsigned integer value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignU16(PRTUINT256U pValueResult, uint16_t u16Value) +{ + pValueResult->QWords.qw0 = u16Value; + pValueResult->QWords.qw1 = 0; + pValueResult->QWords.qw2 = 0; + pValueResult->QWords.qw3 = 0; + return pValueResult; +} + + +/** + * Assigns a 32-bit unsigned integer value to 256-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u32Value The 32-bit unsigned integer value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignU32(PRTUINT256U pValueResult, uint32_t u32Value) +{ + pValueResult->QWords.qw0 = u32Value; + pValueResult->QWords.qw1 = 0; + pValueResult->QWords.qw2 = 0; + pValueResult->QWords.qw3 = 0; + return pValueResult; +} + + +/** + * Assigns a 64-bit unsigned integer value to 256-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u64Value The 64-bit unsigned integer value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignU64(PRTUINT256U pValueResult, uint64_t u64Value) +{ + pValueResult->QWords.qw0 = u64Value; + pValueResult->QWords.qw1 = 0; + pValueResult->QWords.qw2 = 0; + pValueResult->QWords.qw3 = 0; + return pValueResult; +} + + +/** + * Adds two 256-bit unsigned integer values, storing the result in the first. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignAdd(PRTUINT256U pValue1Result, PCRTUINT256U pValue2) +{ + RTUINT256U const uTmpValue1 = *pValue1Result; /* lazy bird */ + return RTUInt256Add(pValue1Result, &uTmpValue1, pValue2); +} + + +/** + * Adds a 64-bit unsigned integer value to a 256-bit unsigned integer values, + * storing the result in the 256-bit one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param uValue2 The second value, 64-bit. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignAddU64(PRTUINT256U pValue1Result, uint64_t uValue2) +{ + RTUINT256U const uTmpValue1 = *pValue1Result; /* lazy bird */ + return RTUInt256AddU64(pValue1Result, &uTmpValue1, uValue2); +} + + +/** + * Subtracts two 256-bit unsigned integer values, storing the result in the + * first. + * + * @returns pValue1Result. + * @param pValue1Result The minuend value and result. + * @param pValue2 The subtrahend value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignSub(PRTUINT256U pValue1Result, PCRTUINT256U pValue2) +{ + RTUINT256U const uTmpValue1 = *pValue1Result; /* lazy bird */ + return RTUInt256Sub(pValue1Result, &uTmpValue1, pValue2); +} + + +#if 0 +/** + * Negates a 256 number, storing the result in the input. + * + * @returns pValueResult. + * @param pValueResult The value to negate. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignNeg(PRTUINT256U pValueResult) +{ + /* result = 0 - value */ + if (pValueResult->s.Lo != 0) + { + pValueResult->s.Lo = UINT64_C(0) - pValueResult->s.Lo; + pValueResult->s.Hi = UINT64_MAX - pValueResult->s.Hi; + } + else + pValueResult->s.Hi = UINT64_C(0) - pValueResult->s.Hi; + return pValueResult; +} +#endif + + +/** + * Multiplies two 256-bit unsigned integer values, storing the result in the + * first. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignMul(PRTUINT256U pValue1Result, PCRTUINT256U pValue2) +{ + RTUINT256U Result; + RTUInt256Mul(&Result, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Divides a 256-bit unsigned integer value by another, storing the result in + * the first. + * + * @returns pValue1Result. + * @param pValue1Result The dividend value and result. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignDiv(PRTUINT256U pValue1Result, PCRTUINT256U pValue2) +{ + RTUINT256U Result; + RTUINT256U Ignored; + RTUInt256DivRem(&Result, &Ignored, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Divides a 256-bit unsigned integer value by another, storing the remainder in + * the first. + * + * @returns pValue1Result. + * @param pValue1Result The dividend value and result (remainder). + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignMod(PRTUINT256U pValue1Result, PCRTUINT256U pValue2) +{ + RTUINT256U Ignored; + RTUINT256U Result; + RTUInt256DivRem(&Ignored, &Result, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Performs a bitwise AND of two 256-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignAnd(PRTUINT256U pValue1Result, PCRTUINT256U pValue2) +{ + pValue1Result->QWords.qw0 &= pValue2->QWords.qw0; + pValue1Result->QWords.qw1 &= pValue2->QWords.qw1; + pValue1Result->QWords.qw2 &= pValue2->QWords.qw2; + pValue1Result->QWords.qw3 &= pValue2->QWords.qw3; + return pValue1Result; +} + + +#if 0 +/** + * Performs a bitwise AND of a 256-bit unsigned integer value and a mask made + * up of the first N bits, assigning the result to the the 256-bit value. + * + * @returns pValueResult. + * @param pValueResult The value and result. + * @param cBits The number of bits to AND (counting from the first + * bit). + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignAndNFirstBits(PRTUINT256U pValueResult, unsigned cBits) +{ + if (cBits <= 64) + { + if (cBits != 64) + pValueResult->s.Lo &= (RT_BIT_64(cBits) - 1); + pValueResult->s.Hi = 0; + } + else if (cBits < 256) + pValueResult->s.Hi &= (RT_BIT_64(cBits - 64) - 1); +/** @todo \#if ARCH_BITS >= 64 */ + return pValueResult; +} +#endif + + +/** + * Performs a bitwise OR of two 256-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignOr(PRTUINT256U pValue1Result, PCRTUINT256U pValue2) +{ + pValue1Result->QWords.qw0 |= pValue2->QWords.qw0; + pValue1Result->QWords.qw1 |= pValue2->QWords.qw1; + pValue1Result->QWords.qw2 |= pValue2->QWords.qw2; + pValue1Result->QWords.qw3 |= pValue2->QWords.qw3; + return pValue1Result; +} + + +DECLINLINE(PRTUINT256U) RTUInt256BitSet(PRTUINT256U pValueResult, unsigned iBit); + +/** + * ORs in a bit and assign the result to the input value. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param iBit The bit to set (0 based). + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignOrBit(PRTUINT256U pValue1Result, uint32_t iBit) +{ + return RTUInt256BitSet(pValue1Result, (unsigned)iBit); +} + + +/** + * Performs a bitwise XOR of two 256-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignXor(PRTUINT256U pValue1Result, PCRTUINT256U pValue2) +{ + pValue1Result->QWords.qw0 ^= pValue2->QWords.qw0; + pValue1Result->QWords.qw1 ^= pValue2->QWords.qw1; + pValue1Result->QWords.qw2 ^= pValue2->QWords.qw2; + pValue1Result->QWords.qw3 ^= pValue2->QWords.qw3; + return pValue1Result; +} + + +/** + * Performs a bitwise left shift on a 256-bit unsigned integer value, assigning + * the result to it. + * + * @returns pValueResult. + * @param pValueResult The first value and result. + * @param cBits The number of bits to shift - signed. Negative + * values are translated to right shifts. If the + * absolute value is 256 or higher, the value is set to + * zero. + * + * @note This works differently from RTUInt256ShiftLeft and + * RTUInt256ShiftRight in that the shift count is signed and not masked + * by 255. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignShiftLeft(PRTUINT256U pValueResult, int cBits) +{ + if (cBits == 0) + return pValueResult; + if (cBits > 0) + { + /* (left shift) */ + if (cBits < 256) + { + RTUINT256U const InVal = *pValueResult; + return RTUInt256ShiftLeft(pValueResult, &InVal, cBits); + } + } + else if (cBits > -256) + { + /* (right shift) */ + cBits = -cBits; + RTUINT256U const InVal = *pValueResult; + return RTUInt256ShiftRight(pValueResult, &InVal, cBits); + } + return RTUInt256SetZero(pValueResult); +} + + +/** + * Performs a bitwise left shift on a 256-bit unsigned integer value, assigning + * the result to it. + * + * @returns pValueResult. + * @param pValueResult The first value and result. + * @param cBits The number of bits to shift - signed. Negative + * values are translated to left shifts. If the + * absolute value is 256 or higher, the value is set to + * zero. + * + * @note This works differently from RTUInt256ShiftRight and + * RTUInt256ShiftLeft in that the shift count is signed and not masked + * by 255. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignShiftRight(PRTUINT256U pValueResult, int cBits) +{ + if (cBits == 0) + return pValueResult; + if (cBits > 0) + { + /* (right shift) */ + if (cBits < 256) + { + RTUINT256U const InVal = *pValueResult; + return RTUInt256ShiftRight(pValueResult, &InVal, cBits); + } + } + else if (cBits > -256) + { + /* (left shift) */ + cBits = -cBits; + RTUINT256U const InVal = *pValueResult; + return RTUInt256ShiftLeft(pValueResult, &InVal, cBits); + } + return RTUInt256SetZero(pValueResult); +} + + +/** + * Performs a bitwise NOT on a 256-bit unsigned integer value, assigning the + * result to it. + * + * @returns pValueResult + * @param pValueResult The value and result. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignBitwiseNot(PRTUINT256U pValueResult) +{ + pValueResult->QWords.qw0 = ~pValueResult->QWords.qw0; + pValueResult->QWords.qw1 = ~pValueResult->QWords.qw1; + pValueResult->QWords.qw2 = ~pValueResult->QWords.qw2; + pValueResult->QWords.qw3 = ~pValueResult->QWords.qw3; + return pValueResult; +} + + +/** + * Performs a boolean NOT on a 256-bit unsigned integer value, assigning the + * result to it. + * + * @returns pValueResult + * @param pValueResult The value and result. + */ +DECLINLINE(PRTUINT256U) RTUInt256AssignBooleanNot(PRTUINT256U pValueResult) +{ + return RTUInt256AssignBoolean(pValueResult, RTUInt256IsZero(pValueResult)); +} + + +/** + * Compares two 256-bit unsigned integer values. + * + * @retval 0 if equal. + * @retval -1 if the first value is smaller than the second. + * @retval 1 if the first value is larger than the second. + * + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(int) RTUInt256Compare(PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + if (pValue1->QWords.qw3 != pValue2->QWords.qw3) + return pValue1->QWords.qw3 > pValue2->QWords.qw3 ? 1 : -1; + if (pValue1->QWords.qw2 != pValue2->QWords.qw2) + return pValue1->QWords.qw2 > pValue2->QWords.qw2 ? 1 : -1; + if (pValue1->QWords.qw1 != pValue2->QWords.qw1) + return pValue1->QWords.qw1 > pValue2->QWords.qw1 ? 1 : -1; + if (pValue1->QWords.qw0 != pValue2->QWords.qw0) + return pValue1->QWords.qw3 > pValue2->QWords.qw3 ? 1 : -1; + return 0; +} + + +/** + * Tests if a 256-bit unsigned integer value is smaller than another. + * + * @returns true if the first value is smaller, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt256IsSmaller(PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + return pValue1->QWords.qw3 < pValue2->QWords.qw3 + || ( pValue1->QWords.qw3 == pValue2->QWords.qw3 + && ( pValue1->QWords.qw2 < pValue2->QWords.qw2 + || ( pValue1->QWords.qw2 == pValue2->QWords.qw2 + && ( pValue1->QWords.qw1 < pValue2->QWords.qw1 + || ( pValue1->QWords.qw1 == pValue2->QWords.qw1 + && pValue1->QWords.qw0 < pValue2->QWords.qw0))))); +} + + +/** + * Tests if a 256-bit unsigned integer value is larger than another. + * + * @returns true if the first value is larger, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt256IsLarger(PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + return pValue1->QWords.qw3 > pValue2->QWords.qw3 + || ( pValue1->QWords.qw3 == pValue2->QWords.qw3 + && ( pValue1->QWords.qw2 > pValue2->QWords.qw2 + || ( pValue1->QWords.qw2 == pValue2->QWords.qw2 + && ( pValue1->QWords.qw1 > pValue2->QWords.qw1 + || ( pValue1->QWords.qw1 == pValue2->QWords.qw1 + && pValue1->QWords.qw0 > pValue2->QWords.qw0))))); +} + + +/** + * Tests if a 256-bit unsigned integer value is larger or equal than another. + * + * @returns true if the first value is larger or equal, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt256IsLargerOrEqual(PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + return pValue1->QWords.qw3 > pValue2->QWords.qw3 + || ( pValue1->QWords.qw3 == pValue2->QWords.qw3 + && ( pValue1->QWords.qw2 > pValue2->QWords.qw2 + || ( pValue1->QWords.qw2 == pValue2->QWords.qw2 + && ( pValue1->QWords.qw1 > pValue2->QWords.qw1 + || ( pValue1->QWords.qw1 == pValue2->QWords.qw1 + && pValue1->QWords.qw0 >= pValue2->DWords.dw0))))); +} + + +/** + * Tests if two 256-bit unsigned integer values not equal. + * + * @returns true if equal, false if not equal. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt256IsEqual(PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + return pValue1->QWords.qw0 == pValue2->QWords.qw0 + && pValue1->QWords.qw1 == pValue2->QWords.qw1 + && pValue1->QWords.qw2 == pValue2->QWords.qw2 + && pValue1->QWords.qw3 == pValue2->QWords.qw3; +} + + +/** + * Tests if two 256-bit unsigned integer values are not equal. + * + * @returns true if not equal, false if equal. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt256IsNotEqual(PCRTUINT256U pValue1, PCRTUINT256U pValue2) +{ + return !RTUInt256IsEqual(pValue1, pValue2); +} + + +/** + * Sets a bit in a 256-bit unsigned integer type. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to set. + */ +DECLINLINE(PRTUINT256U) RTUInt256BitSet(PRTUINT256U pValueResult, unsigned iBit) +{ + if (iBit < 256) + { + unsigned idxQWord = iBit >> 6; +#ifdef RT_BIG_ENDIAN + idxQWord = RT_ELEMENTS(pValueResult->au64) - idxQWord; +#endif + iBit &= 0x3f; + pValueResult->au64[idxQWord] |= RT_BIT_64(iBit); + } + return pValueResult; +} + + +/** + * Sets a bit in a 256-bit unsigned integer type. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to set. + */ +DECLINLINE(PRTUINT256U) RTUInt256BitClear(PRTUINT256U pValueResult, unsigned iBit) +{ + if (iBit < 256) + { + unsigned idxQWord = iBit >> 6; +#ifdef RT_BIG_ENDIAN + idxQWord = RT_ELEMENTS(pValueResult->au64) - idxQWord; +#endif + iBit &= 0x3f; + pValueResult->au64[idxQWord] &= ~RT_BIT_64(iBit); + } + return pValueResult; +} + + +/** + * Tests if a bit in a 256-bit unsigned integer value is set. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to test. + */ +DECLINLINE(bool) RTUInt256BitTest(PRTUINT256U pValueResult, unsigned iBit) +{ + bool fRc; + if (iBit < 256) + { + unsigned idxQWord = iBit >> 6; +#ifdef RT_BIG_ENDIAN + idxQWord = RT_ELEMENTS(pValueResult->au64) - idxQWord; +#endif + iBit &= 0x3f; + fRc = RT_BOOL(pValueResult->au64[idxQWord] & RT_BIT_64(iBit)); + } + else + fRc = false; + return fRc; +} + + +/** + * Set a range of bits a 256-bit unsigned integer value. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iFirstBit The first bit to test. + * @param cBits The number of bits to set. + */ +DECLINLINE(PRTUINT256U) RTUInt256BitSetRange(PRTUINT256U pValueResult, unsigned iFirstBit, unsigned cBits) +{ + /* bounds check & fix. */ + if (iFirstBit < 256) + { + if (iFirstBit + cBits > 256) + cBits = 256 - iFirstBit; + + /* Work the au64 array: */ +#ifdef RT_BIG_ENDIAN + int idxQWord = RT_ELEMENTS(pValueResult->au64) - (iFirstBit >> 6); + int const idxInc = -1; +#else + int idxQWord = iFirstBit >> 6; + int const idxInc = 1; +#endif + while (cBits > 0) + { + unsigned iQWordFirstBit = iFirstBit & 0x3f; + unsigned cQWordBits = cBits + iQWordFirstBit >= 64 ? 64 - iQWordFirstBit : cBits; + pValueResult->au64[idxQWord] |= cQWordBits < 64 ? (RT_BIT_64(cQWordBits) - 1) << iQWordFirstBit : UINT64_MAX; + + idxQWord += idxInc; + iFirstBit += cQWordBits; + cBits -= cQWordBits; + } + } + return pValueResult; +} + + +/** + * Test if all the bits of a 256-bit unsigned integer value are set. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt256BitAreAllSet(PRTUINT256U pValue) +{ + return pValue->QWords.qw0 == UINT64_MAX + && pValue->QWords.qw1 == UINT64_MAX + && pValue->QWords.qw2 == UINT64_MAX + && pValue->QWords.qw3 == UINT64_MAX; +} + + +/** + * Test if all the bits of a 256-bit unsigned integer value are clear. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt256BitAreAllClear(PRTUINT256U pValue) +{ + return RTUInt256IsZero(pValue); +} + + +/** + * Number of significant bits in the value. + * + * This is the same a ASMBitLastSetU64 and ASMBitLastSetU32. + * + * @returns 0 if zero, 1-base index of the last bit set. + * @param pValue The value to examine. + */ +DECLINLINE(uint32_t) RTUInt256BitCount(PCRTUINT256U pValue) +{ + uint64_t u64; + uint32_t cBits; + if ((u64 = pValue->QWords.qw3) != 0) + cBits = 192; + else if ((u64 = pValue->QWords.qw2) != 0) + cBits = 128; + else if ((u64 = pValue->QWords.qw1) != 0) + cBits = 64; + else + { + u64 = pValue->QWords.qw0; + cBits = 0; + } + return cBits + ASMBitLastSetU64(u64); +} + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_uint256_h */ + diff --git a/include/iprt/uint32.h b/include/iprt/uint32.h new file mode 100644 index 00000000..46140142 --- /dev/null +++ b/include/iprt/uint32.h @@ -0,0 +1,1068 @@ +/** @file + * IPRT - RTUINT32U methods for old 16-bit compilers (mainly for division). + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_uint32_h +#define IPRT_INCLUDED_uint32_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/asm.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_uint32 RTUInt32 - 32-bit Unsigned Integer Methods for 16-bit compilers. + * @ingroup grp_rt + * @{ + */ + +#define RTUINT32_HAVE_32BIT_BASICS + + +/** + * Test if a 32-bit unsigned integer value is zero. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt32IsZero(PRTUINT32U pValue) +{ + return pValue->s.Lo == 0 + && pValue->s.Hi == 0; +} + + +/** + * Set a 32-bit unsigned integer value to zero. + * + * @returns pResult + * @param pResult The result variable. + */ +DECLINLINE(PRTUINT32U) RTUInt32SetZero(PRTUINT32U pResult) +{ + pResult->s.Hi = 0; + pResult->s.Lo = 0; + return pResult; +} + + +/** + * Set a 32-bit unsigned integer value to the maximum value. + * + * @returns pResult + * @param pResult The result variable. + */ +DECLINLINE(PRTUINT32U) RTUInt32SetMax(PRTUINT32U pResult) +{ + pResult->s.Hi = UINT16_MAX; + pResult->s.Lo = UINT16_MAX; + return pResult; +} + + + + +/** + * Adds two 32-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32Add(PRTUINT32U pResult, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + pResult->u = pValue1->u + pValue2->u; +#else + pResult->s.Hi = pValue1->s.Hi + pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo + pValue2->s.Lo; + if (pResult->s.Lo < pValue1->s.Lo) + pResult->s.Hi++; +#endif + return pResult; +} + + +/** + * Adds a 32-bit and a 16-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 16-bit. + */ +DECLINLINE(PRTUINT32U) RTUInt32AddU16(PRTUINT32U pResult, PCRTUINT32U pValue1, uint16_t uValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + pResult->u = pValue1->u + uValue2; +#else + pResult->s.Hi = pValue1->s.Hi; + pResult->s.Lo = pValue1->s.Lo + uValue2; + if (pResult->s.Lo < pValue1->s.Lo) + pResult->s.Hi++; +#endif + return pResult; +} + + +/** + * Subtracts a 32-bit unsigned integer value from another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The minuend value. + * @param pValue2 The subtrahend value. + */ +DECLINLINE(PRTUINT32U) RTUInt32Sub(PRTUINT32U pResult, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + pResult->u = pValue1->u - pValue2->u; +#else + pResult->s.Lo = pValue1->s.Lo - pValue2->s.Lo; + pResult->s.Hi = pValue1->s.Hi - pValue2->s.Hi; + if (pResult->s.Lo > pValue1->s.Lo) + pResult->s.Hi--; +#endif + return pResult; +} + + +/** + * Multiplies two 32-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32Mul(PRTUINT32U pResult, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + pResult->u = (uint32_t)pValue1->s.Lo * pValue2->s.Lo; + pResult->s.Hi += pValue1->s.Hi * pValue2->s.Lo; + pResult->s.Hi += pValue1->s.Lo * pValue2->s.Hi; + + return pResult; +} + + +/** + * Multiplies an 32-bit unsigned integer by a 16-bit unsigned integer value. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 16-bit. + */ +DECLINLINE(PRTUINT32U) RTUInt32MulByU16(PRTUINT32U pResult, PCRTUINT32U pValue1, uint16_t uValue2) +{ + pResult->u = (uint32_t)pValue1->s.Lo * uValue2; + pResult->s.Hi += pValue1->s.Hi * uValue2; + return pResult; +} + + +DECLINLINE(PRTUINT32U) RTUInt32DivRem(PRTUINT32U pQuotient, PRTUINT32U pRemainder, PCRTUINT32U pValue1, PCRTUINT32U pValue2); + +/** + * Divides a 32-bit unsigned integer value by another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT32U) RTUInt32Div(PRTUINT32U pResult, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + RTUINT32U Ignored; + return RTUInt32DivRem(pResult, &Ignored, pValue1, pValue2); +} + + +/** + * Divides a 32-bit unsigned integer value by another, returning the remainder. + * + * @returns pResult + * @param pResult The result variable (remainder). + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT32U) RTUInt32Mod(PRTUINT32U pResult, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + RTUINT32U Ignored; + RTUInt32DivRem(&Ignored, pResult, pValue1, pValue2); + return pResult; +} + + +/** + * Bitwise AND of two 32-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32And(PRTUINT32U pResult, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi & pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo & pValue2->s.Lo; + return pResult; +} + + +/** + * Bitwise OR of two 32-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32Or( PRTUINT32U pResult, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi | pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo | pValue2->s.Lo; + return pResult; +} + + +/** + * Bitwise XOR of two 32-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32Xor(PRTUINT32U pResult, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi ^ pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo ^ pValue2->s.Lo; + return pResult; +} + + +/** + * Shifts a 32-bit unsigned integer value @a cBits to the left. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to shift. + * @param cBits The number of bits to shift it. + */ +DECLINLINE(PRTUINT32U) RTUInt32ShiftLeft(PRTUINT32U pResult, PCRTUINT32U pValue, int cBits) +{ + cBits &= 31; +#ifdef RTUINT32_HAVE_32BIT_BASICS + pResult->u = pValue->u << cBits; +#else + if (cBits < 16) + { + pResult->s.Lo = pValue->s.Lo << cBits; + pResult->s.Hi = (pValue->s.Hi << cBits) | (pValue->s.Lo >> (16 - cBits)); + } + else + { + pResult->s.Lo = 0; + pResult->s.Hi = pValue->s.Lo << (cBits - 16); + } +#endif + return pResult; +} + + +/** + * Shifts a 32-bit unsigned integer value @a cBits to the right. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to shift. + * @param cBits The number of bits to shift it. + */ +DECLINLINE(PRTUINT32U) RTUInt32ShiftRight(PRTUINT32U pResult, PCRTUINT32U pValue, int cBits) +{ + cBits &= 31; +#ifdef RTUINT32_HAVE_32BIT_BASICS + pResult->u = pValue->u >> cBits; +#else + if (cBits < 16) + { + pResult->s.Hi = pValue->s.Hi >> cBits; + pResult->s.Lo = (pValue->s.Lo >> cBits) | (pValue->s.Hi << (16 - cBits)); + } + else + { + pResult->s.Hi = 0; + pResult->s.Lo = pValue->s.Hi >> (cBits - 16); + } +#endif + return pResult; +} + + +/** + * Boolean not (result 0 or 1). + * + * @returns pResult. + * @param pResult The result variable. + * @param pValue The value. + */ +DECLINLINE(PRTUINT32U) RTUInt32BooleanNot(PRTUINT32U pResult, PCRTUINT32U pValue) +{ + pResult->s.Lo = pValue->s.Lo || pValue->s.Hi ? 0 : 1; + pResult->s.Hi = 0; + return pResult; +} + + +/** + * Bitwise not (flips each bit of the 32 bits). + * + * @returns pResult. + * @param pResult The result variable. + * @param pValue The value. + */ +DECLINLINE(PRTUINT32U) RTUInt32BitwiseNot(PRTUINT32U pResult, PCRTUINT32U pValue) +{ + pResult->s.Hi = ~pValue->s.Hi; + pResult->s.Lo = ~pValue->s.Lo; + return pResult; +} + + +/** + * Assigns one 32-bit unsigned integer value to another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to assign. + */ +DECLINLINE(PRTUINT32U) RTUInt32Assign(PRTUINT32U pResult, PCRTUINT32U pValue) +{ + pResult->s.Hi = pValue->s.Hi; + pResult->s.Lo = pValue->s.Lo; + return pResult; +} + + +/** + * Assigns a boolean value to 32-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param fValue The boolean value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignBoolean(PRTUINT32U pValueResult, bool fValue) +{ + pValueResult->s.Lo = fValue; + pValueResult->s.Hi = 0; + return pValueResult; +} + + +/** + * Assigns a 8-bit unsigned integer value to 32-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u8Value The 8-bit unsigned integer value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignU8(PRTUINT32U pValueResult, uint8_t u8Value) +{ + pValueResult->s.Lo = u8Value; + pValueResult->s.Hi = 0; + return pValueResult; +} + + +/** + * Assigns a 16-bit unsigned integer value to 32-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u16Value The 16-bit unsigned integer value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignU16(PRTUINT32U pValueResult, uint16_t u16Value) +{ + pValueResult->s.Lo = u16Value; + pValueResult->s.Hi = 0; + return pValueResult; +} + + +/** + * Adds two 32-bit unsigned integer values, storing the result in the first. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignAdd(PRTUINT32U pValue1Result, PCRTUINT32U pValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + pValue1Result->u += pValue2->u; +#else + uint16_t const uTmp = pValue1Result->s.Lo; + pValue1Result->s.Lo += pValue2->s.Lo; + if (pValue1Result->s.Lo < uTmp) + pValue1Result->s.Hi++; + pValue1Result->s.Hi += pValue2->s.Hi; +#endif + return pValue1Result; +} + + +/** + * Subtracts two 32-bit unsigned integer values, storing the result in the + * first. + * + * @returns pValue1Result. + * @param pValue1Result The minuend value and result. + * @param pValue2 The subtrahend value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignSub(PRTUINT32U pValue1Result, PCRTUINT32U pValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + pValue1Result->u -= pValue2->u; +#else + uint32_t const uTmp = pValue1Result->s.Lo; + pValue1Result->s.Lo -= pValue2->s.Lo; + if (pValue1Result->s.Lo > uTmp) + pValue1Result->s.Hi--; + pValue1Result->s.Hi -= pValue2->s.Hi; +#endif + return pValue1Result; +} + + +/** + * Multiplies two 32-bit unsigned integer values, storing the result in the + * first. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignMul(PRTUINT32U pValue1Result, PCRTUINT32U pValue2) +{ + RTUINT32U Result; + RTUInt32Mul(&Result, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Divides a 32-bit unsigned integer value by another, storing the result in + * the first. + * + * @returns pValue1Result. + * @param pValue1Result The dividend value and result. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignDiv(PRTUINT32U pValue1Result, PCRTUINT32U pValue2) +{ + RTUINT32U Result; + RTUINT32U Ignored; + RTUInt32DivRem(&Result, &Ignored, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Divides a 32-bit unsigned integer value by another, storing the remainder in + * the first. + * + * @returns pValue1Result. + * @param pValue1Result The dividend value and result (remainder). + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignMod(PRTUINT32U pValue1Result, PCRTUINT32U pValue2) +{ + RTUINT32U Ignored; + RTUINT32U Result; + RTUInt32DivRem(&Ignored, &Result, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Performs a bitwise AND of two 32-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignAnd(PRTUINT32U pValue1Result, PCRTUINT32U pValue2) +{ + pValue1Result->s.Hi &= pValue2->s.Hi; + pValue1Result->s.Lo &= pValue2->s.Lo; + return pValue1Result; +} + + +/** + * Performs a bitwise AND of a 32-bit unsigned integer value and a mask made up + * of the first N bits, assigning the result to the the 32-bit value. + * + * @returns pValueResult. + * @param pValueResult The value and result. + * @param cBits The number of bits to AND (counting from the first + * bit). + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignAndNFirstBits(PRTUINT32U pValueResult, unsigned cBits) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + if (cBits < 32) + pValueResult->u &= RT_BIT_32(cBits) - 1; +#else + if (cBits <= 16) + { + if (cBits != 16) + pValueResult->s.Lo &= (UINT16_C(1) << cBits) - 1; + pValueResult->s.Hi = 0; + } + else if (cBits < 16) + pValueResult->s.Hi &= (UINT16_C(1) << (cBits - 16)) - 1; +#endif + return pValueResult; +} + + +/** + * Performs a bitwise OR of two 32-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignOr(PRTUINT32U pValue1Result, PCRTUINT32U pValue2) +{ + pValue1Result->s.Hi |= pValue2->s.Hi; + pValue1Result->s.Lo |= pValue2->s.Lo; + return pValue1Result; +} + + +/** + * ORs in a bit and assign the result to the input value. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param iBit The bit to set (0 based). + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignOrBit(PRTUINT32U pValue1Result, unsigned iBit) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + pValue1Result->u |= RT_BIT_32(iBit); +#else + if (iBit >= 32) + pValue1Result->s.Hi |= UINT16_C(1) << (iBit - 32); + else + pValue1Result->s.Lo |= UINT16_C(1) << iBit; +#endif + return pValue1Result; +} + + + +/** + * Performs a bitwise XOR of two 32-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignXor(PRTUINT32U pValue1Result, PCRTUINT32U pValue2) +{ + pValue1Result->s.Hi ^= pValue2->s.Hi; + pValue1Result->s.Lo ^= pValue2->s.Lo; + return pValue1Result; +} + + +/** + * Performs a bitwise left shift on a 32-bit unsigned integer value, assigning + * the result to it. + * + * @returns pValueResult. + * @param pValueResult The first value and result. + * @param cBits The number of bits to shift. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignShiftLeft(PRTUINT32U pValueResult, int cBits) +{ +#ifndef RTUINT32_HAVE_32BIT_BASICS + RTUINT32U const InVal = *pValueResult; +#endif + if (cBits > 0) + { + /* (left shift) */ + cBits &= 31; +#ifdef RTUINT32_HAVE_32BIT_BASICS + pValueResult->u <<= cBits; +#else + if (cBits >= 16) + { + pValueResult->s.Lo = 0; + pValueResult->s.Hi = InVal.s.Lo << (cBits - 16); + } + else + { + pValueResult->s.Hi = InVal.s.Hi << cBits; + pValueResult->s.Hi |= InVal.s.Lo >> (16 - cBits); + pValueResult->s.Lo = InVal.s.Lo << cBits; + } +#endif + } + else if (cBits < 0) + { + /* (right shift) */ + cBits = -cBits; + cBits &= 31; +#ifdef RTUINT32_HAVE_32BIT_BASICS + pValueResult->u >>= cBits; +#else + if (cBits >= 16) + { + pValueResult->s.Hi = 0; + pValueResult->s.Lo = InVal.s.Hi >> (cBits - 16); + } + else + { + pValueResult->s.Lo = InVal.s.Lo >> cBits; + pValueResult->s.Lo |= InVal.s.Hi << (16 - cBits); + pValueResult->s.Hi = InVal.s.Hi >> cBits; + } +#endif + } + return pValueResult; +} + + +/** + * Performs a bitwise left shift on a 32-bit unsigned integer value, assigning + * the result to it. + * + * @returns pValueResult. + * @param pValueResult The first value and result. + * @param cBits The number of bits to shift. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignShiftRight(PRTUINT32U pValueResult, int cBits) +{ + return RTUInt32AssignShiftLeft(pValueResult, -cBits); +} + + +/** + * Performs a bitwise NOT on a 32-bit unsigned integer value, assigning the + * result to it. + * + * @returns pValueResult + * @param pValueResult The value and result. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignBitwiseNot(PRTUINT32U pValueResult) +{ + pValueResult->s.Hi = ~pValueResult->s.Hi; + pValueResult->s.Lo = ~pValueResult->s.Lo; + return pValueResult; +} + + +/** + * Performs a boolean NOT on a 32-bit unsigned integer value, assigning the + * result to it. + * + * @returns pValueResult + * @param pValueResult The value and result. + */ +DECLINLINE(PRTUINT32U) RTUInt32AssignBooleanNot(PRTUINT32U pValueResult) +{ + return RTUInt32AssignBoolean(pValueResult, RTUInt32IsZero(pValueResult)); +} + + +/** + * Compares two 32-bit unsigned integer values. + * + * @retval 0 if equal. + * @retval -1 if the first value is smaller than the second. + * @retval 1 if the first value is larger than the second. + * + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(int) RTUInt32Compare(PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + if (pValue1->s.Hi != pValue2->s.Hi) + return pValue1->s.Hi > pValue2->s.Hi ? 1 : -1; + if (pValue1->s.Lo != pValue2->s.Lo) + return pValue1->s.Lo > pValue2->s.Lo ? 1 : -1; + return 0; +} + + +/** + * Tests if a 64-bit unsigned integer value is smaller than another. + * + * @returns true if the first value is smaller, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt32IsSmaller(PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + return pValue1->u < pValue2->u; +#else + return pValue1->s.Hi < pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo < pValue2->s.Lo); +#endif +} + + +/** + * Tests if a 32-bit unsigned integer value is larger than another. + * + * @returns true if the first value is larger, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt32IsLarger(PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + return pValue1->u > pValue2->u; +#else + return pValue1->s.Hi > pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo > pValue2->s.Lo); +#endif +} + + +/** + * Tests if a 64-bit unsigned integer value is larger or equal than another. + * + * @returns true if the first value is larger or equal, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt32IsLargerOrEqual(PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + return pValue1->u >= pValue2->u; +#else + return pValue1->s.Hi > pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo >= pValue2->s.Lo); +#endif +} + + +/** + * Tests if two 64-bit unsigned integer values not equal. + * + * @returns true if equal, false if not equal. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt32IsEqual(PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + return pValue1->u == pValue2->u; +#else + return pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo == pValue2->s.Lo; +#endif +} + + +/** + * Tests if two 64-bit unsigned integer values are not equal. + * + * @returns true if not equal, false if equal. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt32IsNotEqual(PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + return !RTUInt32IsEqual(pValue1, pValue2); +} + + +/** + * Sets a bit in a 32-bit unsigned integer type. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to set. + */ +DECLINLINE(PRTUINT32U) RTUInt32BitSet(PRTUINT32U pValueResult, unsigned iBit) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + if (iBit < 32) + pValueResult->u |= RT_BIT_32(iBit); +#else + if (iBit < 16) + pValueResult->s.Lo |= UINT16_C(1) << iBit; + else if (iBit < 32) + pValueResult->s.Hi |= UINT16_C(1) << (iBit - 32); +#endif + return pValueResult; +} + + +/** + * Sets a bit in a 32-bit unsigned integer type. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to set. + */ +DECLINLINE(PRTUINT32U) RTUInt32BitClear(PRTUINT32U pValueResult, unsigned iBit) +{ +#ifdef RTUINT32_HAVE_32BIT_BASICS + if (iBit < 32) + pValueResult->u &= ~RT_BIT_32(iBit); + +#else + if (iBit < 16) + pValueResult->s.Lo &= ~RT_BIT_32(iBit); + else if (iBit < 32) + pValueResult->s.Hi &= ~RT_BIT_32(iBit - 32); +#endif + return pValueResult; +} + + +/** + * Tests if a bit in a 32-bit unsigned integer value is set. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to test. + */ +DECLINLINE(bool) RTUInt32BitTest(PRTUINT32U pValueResult, unsigned iBit) +{ + bool fRc; +#ifdef RTUINT32_HAVE_32BIT_BASICS + if (iBit < 32) + fRc = RT_BOOL(pValueResult->u & RT_BIT_32(iBit)); +#else + if (iBit < 16) + fRc = RT_BOOL(pValueResult->s.Lo & (UINT16_C(1) << iBit)); + else if (iBit < 32) + fRc = RT_BOOL(pValueResult->s.Hi & (UINT16_C(1) << (iBit - 64))); +#endif + else + fRc = false; + return fRc; +} + + +/** + * Set a range of bits a 32-bit unsigned integer value. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iFirstBit The first bit to test. + * @param cBits The number of bits to set. + */ +DECLINLINE(PRTUINT32U) RTUInt32BitSetRange(PRTUINT32U pValueResult, unsigned iFirstBit, unsigned cBits) +{ + /* bounds check & fix. */ + if (iFirstBit < 32) + { +#ifdef RTUINT32_HAVE_32BIT_BASICS + if (iFirstBit + cBits < 32) + pValueResult->u |= (RT_BIT_32(cBits) - 1) << iFirstBit; + else + pValueResult->u = UINT32_MAX << iFirstBit; +#else + if (iFirstBit + cBits > 32) + cBits = 32 - iFirstBit; + if (iFirstBit + cBits < 16) + pValueResult->s.Lo |= ((UINT16_C(1) << cBits) - 1) << iFirstBit; + else if (iFirstBit + cBits < 32 && iFirstBit >= 16) + pValueResult->s.Hi |= ((UINT16_C(1) << cBits) - 1) << (iFirstBit - 16); + else + while (cBits-- > 0) + RTUInt32BitSet(pValueResult, iFirstBit++); +#endif + } + return pValueResult; +} + + +/** + * Test if all the bits of a 32-bit unsigned integer value are set. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt32BitAreAllSet(PRTUINT32U pValue) +{ + return pValue->s.Hi == UINT16_MAX + && pValue->s.Lo == UINT16_MAX; +} + + +/** + * Test if all the bits of a 32-bit unsigned integer value are clear. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt32BitAreAllClear(PRTUINT32U pValue) +{ + return RTUInt32IsZero(pValue); +} + + +DECLINLINE(unsigned) RTUInt32BitCount(PCRTUINT32U pValue) +{ + unsigned cBits; + if (pValue->s.Hi != 0) + cBits = 16 + ASMBitLastSetU16(pValue->s.Hi); + else + cBits = ASMBitLastSetU16(pValue->s.Lo); + return cBits; +} + + +/** + * Divides a 32-bit unsigned integer value by another, returning both quotient + * and remainder. + * + * @returns pQuotient, NULL if pValue2 is 0. + * @param pQuotient Where to return the quotient. + * @param pRemainder Where to return the remainder. + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT32U) RTUInt32DivRem(PRTUINT32U pQuotient, PRTUINT32U pRemainder, PCRTUINT32U pValue1, PCRTUINT32U pValue2) +{ + int iDiff; + + /* + * Sort out all the special cases first. + */ + /* Divide by zero or 1? */ + if (!pValue2->s.Hi) + { + if (!pValue2->s.Lo) + return NULL; + + if (pValue2->s.Lo == 1) + { + RTUInt32SetZero(pRemainder); + *pQuotient = *pValue1; + return pQuotient; + } + /** @todo RTUInt32DivModByU32 */ + } + + /* Dividend is smaller? */ + iDiff = RTUInt32Compare(pValue1, pValue2); + if (iDiff < 0) + { + *pRemainder = *pValue1; + RTUInt32SetZero(pQuotient); + } + + /* The values are equal? */ + else if (iDiff == 0) + { + RTUInt32SetZero(pRemainder); + RTUInt32AssignU8(pQuotient, 1); + } + else + { + /* + * Prepare. + */ + unsigned iBitAdder = RTUInt32BitCount(pValue1) - RTUInt32BitCount(pValue2); + RTUINT32U NormDivisor = *pValue2; + if (iBitAdder) + { + RTUInt32ShiftLeft(&NormDivisor, pValue2, iBitAdder); + if (RTUInt32IsLarger(&NormDivisor, pValue1)) + { + RTUInt32AssignShiftRight(&NormDivisor, 1); + iBitAdder--; + } + } + else + NormDivisor = *pValue2; + + RTUInt32SetZero(pQuotient); + *pRemainder = *pValue1; + + /* + * Do the division. + */ + if (RTUInt32IsLargerOrEqual(pRemainder, pValue2)) + { + for (;;) + { + if (RTUInt32IsLargerOrEqual(pRemainder, &NormDivisor)) + { + RTUInt32AssignSub(pRemainder, &NormDivisor); + RTUInt32AssignOrBit(pQuotient, iBitAdder); + } + if (RTUInt32IsSmaller(pRemainder, pValue2)) + break; + RTUInt32AssignShiftRight(&NormDivisor, 1); + iBitAdder--; + } + } + } + return pQuotient; +} + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_uint32_h */ + diff --git a/include/iprt/uint64.h b/include/iprt/uint64.h new file mode 100644 index 00000000..8e9cf0e5 --- /dev/null +++ b/include/iprt/uint64.h @@ -0,0 +1,1343 @@ +/** @file + * IPRT - RTUINT64U methods for old 32-bit and 16-bit compilers. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_uint64_h +#define IPRT_INCLUDED_uint64_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/asm.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_uint64 RTUInt64 - 64-bit Unsigned Integer Methods for ancient compilers + * @ingroup grp_rt + * @{ + */ + + +/** + * Test if a 128-bit unsigned integer value is zero. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt64IsZero(PRTUINT64U pValue) +{ +#if ARCH_BITS >= 32 + return pValue->s.Lo == 0 + && pValue->s.Hi == 0; +#else + return pValue->Words.w0 == 0 + && pValue->Words.w1 == 0 + && pValue->Words.w2 == 0 + && pValue->Words.w3 == 0; +#endif +} + + +/** + * Set a 128-bit unsigned integer value to zero. + * + * @returns pResult + * @param pResult The result variable. + */ +DECLINLINE(PRTUINT64U) RTUInt64SetZero(PRTUINT64U pResult) +{ +#if ARCH_BITS >= 32 + pResult->s.Hi = 0; + pResult->s.Lo = 0; +#else + pResult->Words.w0 = 0; + pResult->Words.w1 = 0; + pResult->Words.w2 = 0; + pResult->Words.w3 = 0; +#endif + return pResult; +} + + +/** + * Set a 32-bit unsigned integer value to the maximum value. + * + * @returns pResult + * @param pResult The result variable. + */ +DECLINLINE(PRTUINT64U) RTUInt64SetMax(PRTUINT64U pResult) +{ +#if ARCH_BITS >= 32 + pResult->s.Hi = UINT32_MAX; + pResult->s.Lo = UINT32_MAX; +#else + pResult->Words.w0 = UINT16_MAX; + pResult->Words.w1 = UINT16_MAX; + pResult->Words.w2 = UINT16_MAX; + pResult->Words.w3 = UINT16_MAX; +#endif + return pResult; +} + + + + +/** + * Adds two 64-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64Add(PRTUINT64U pResult, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi + pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo + pValue2->s.Lo; + if (pResult->s.Lo < pValue1->s.Lo) + pResult->s.Hi++; + return pResult; +} + + +/** + * Adds a 64-bit and a 32-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 32-bit. + */ +DECLINLINE(PRTUINT64U) RTUInt64AddU32(PRTUINT64U pResult, PCRTUINT64U pValue1, uint32_t uValue2) +{ + pResult->s.Hi = pValue1->s.Hi; + pResult->s.Lo = pValue1->s.Lo + uValue2; + if (pResult->s.Lo < pValue1->s.Lo) + pResult->s.Hi++; + return pResult; +} + + +/** + * Subtracts a 64-bit unsigned integer value from another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The minuend value. + * @param pValue2 The subtrahend value. + */ +DECLINLINE(PRTUINT64U) RTUInt64Sub(PRTUINT64U pResult, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + pResult->s.Lo = pValue1->s.Lo - pValue2->s.Lo; + pResult->s.Hi = pValue1->s.Hi - pValue2->s.Hi; + if (pResult->s.Lo > pValue1->s.Lo) + pResult->s.Hi--; + return pResult; +} + + +/** + * Multiplies two 64-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64Mul(PRTUINT64U pResult, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + RTUINT32U uTmp; + + /* multiply all words in v1 by v2.w0. */ + pResult->s.Lo = (uint32_t)pValue1->Words.w0 * pValue2->Words.w0; + + uTmp.u = (uint32_t)pValue1->Words.w1 * pValue2->Words.w0; + pResult->Words.w3 = 0; + pResult->Words.w2 = uTmp.Words.w1; + pResult->Words.w1 += uTmp.Words.w0; + if (pResult->Words.w1 < uTmp.Words.w0) + if (pResult->Words.w2++ == UINT16_MAX) + pResult->Words.w3++; + + pResult->s.Hi += (uint32_t)pValue1->Words.w2 * pValue2->Words.w0; + pResult->Words.w3 += pValue1->Words.w3 * pValue2->Words.w0; + + /* multiply w0, w1 & w2 in v1 by v2.w1. */ + uTmp.u = (uint32_t)pValue1->Words.w0 * pValue2->Words.w1; + pResult->Words.w1 += uTmp.Words.w0; + if (pResult->Words.w1 < uTmp.Words.w0) + if (pResult->Words.w2++ == UINT16_MAX) + pResult->Words.w3++; + + pResult->Words.w2 += uTmp.Words.w1; + if (pResult->Words.w2 < uTmp.Words.w1) + pResult->Words.w3++; + + pResult->s.Hi += (uint32_t)pValue1->Words.w1 * pValue2->Words.w1; + pResult->Words.w3 += pValue1->Words.w2 * pValue2->Words.w1; + + /* multiply w0 & w1 in v1 by v2.w2. */ + pResult->s.Hi += (uint32_t)pValue1->Words.w0 * pValue2->Words.w2; + pResult->Words.w3 += pValue1->Words.w1 * pValue2->Words.w2; + + /* multiply w0 in v1 by v2.w3. */ + pResult->Words.w3 += pValue1->Words.w0 * pValue2->Words.w3; + + return pResult; +} + + +/** + * Multiplies an 64-bit unsigned integer by a 32-bit unsigned integer value. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param uValue2 The second value, 32-bit. + */ +DECLINLINE(PRTUINT64U) RTUInt64MulByU32(PRTUINT64U pResult, PCRTUINT64U pValue1, uint32_t uValue2) +{ + uint16_t const uLoValue2 = (uint16_t)uValue2; + uint16_t const uHiValue2 = (uint16_t)(uValue2 >> 16); + RTUINT32U uTmp; + + /* multiply all words in v1 by uLoValue1. */ + pResult->s.Lo = (uint32_t)pValue1->Words.w0 * uLoValue2; + + uTmp.u = (uint32_t)pValue1->Words.w1 * uLoValue2; + pResult->Words.w3 = 0; + pResult->Words.w2 = uTmp.Words.w1; + pResult->Words.w1 += uTmp.Words.w0; + if (pResult->Words.w1 < uTmp.Words.w0) + if (pResult->Words.w2++ == UINT16_MAX) + pResult->Words.w3++; + + pResult->s.Hi += (uint32_t)pValue1->Words.w2 * uLoValue2; + pResult->Words.w3 += pValue1->Words.w3 * uLoValue2; + + /* multiply w0, w1 & w2 in v1 by uHiValue2. */ + uTmp.u = (uint32_t)pValue1->Words.w0 * uHiValue2; + pResult->Words.w1 += uTmp.Words.w0; + if (pResult->Words.w1 < uTmp.Words.w0) + if (pResult->Words.w2++ == UINT16_MAX) + pResult->Words.w3++; + + pResult->Words.w2 += uTmp.Words.w1; + if (pResult->Words.w2 < uTmp.Words.w1) + pResult->Words.w3++; + + pResult->s.Hi += (uint32_t)pValue1->Words.w1 * uHiValue2; + pResult->Words.w3 += pValue1->Words.w2 * uHiValue2; + + return pResult; +} + + +/** + * Multiplies two 32-bit unsigned integer values with 64-bit precision. + * + * @returns pResult + * @param pResult The result variable. + * @param uValue1 The first value. 32-bit. + * @param uValue2 The second value, 32-bit. + */ +DECLINLINE(PRTUINT64U) RTUInt64MulU32ByU32(PRTUINT64U pResult, uint32_t uValue1, uint32_t uValue2) +{ + uint16_t const uLoValue1 = (uint16_t)uValue1; + uint16_t const uHiValue1 = (uint16_t)(uValue1 >> 16); + uint16_t const uLoValue2 = (uint16_t)uValue2; + uint16_t const uHiValue2 = (uint16_t)(uValue2 >> 16); + RTUINT32U uTmp; + + /* Multiply uLoValue1 and uHiValue1 by uLoValue1. */ + pResult->s.Lo = (uint32_t)uLoValue1 * uLoValue2; + + uTmp.u = (uint32_t)uHiValue1 * uLoValue2; + pResult->Words.w3 = 0; + pResult->Words.w2 = uTmp.Words.w1; + pResult->Words.w1 += uTmp.Words.w0; + if (pResult->Words.w1 < uTmp.Words.w0) + if (pResult->Words.w2++ == UINT16_MAX) + pResult->Words.w3++; + + /* Multiply uLoValue1 and uHiValue1 by uHiValue2. */ + uTmp.u = (uint32_t)uLoValue1 * uHiValue2; + pResult->Words.w1 += uTmp.Words.w0; + if (pResult->Words.w1 < uTmp.Words.w0) + if (pResult->Words.w2++ == UINT16_MAX) + pResult->Words.w3++; + + pResult->Words.w2 += uTmp.Words.w1; + if (pResult->Words.w2 < uTmp.Words.w1) + pResult->Words.w3++; + + pResult->s.Hi += (uint32_t)uHiValue1 * uHiValue2; + return pResult; +} + + +DECLINLINE(PRTUINT64U) RTUInt64DivRem(PRTUINT64U pQuotient, PRTUINT64U pRemainder, PCRTUINT64U pValue1, PCRTUINT64U pValue2); + +/** + * Divides a 64-bit unsigned integer value by another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT64U) RTUInt64Div(PRTUINT64U pResult, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + RTUINT64U Ignored; + return RTUInt64DivRem(pResult, &Ignored, pValue1, pValue2); +} + + +/** + * Divides a 64-bit unsigned integer value by another, returning the remainder. + * + * @returns pResult + * @param pResult The result variable (remainder). + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT64U) RTUInt64Mod(PRTUINT64U pResult, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + RTUINT64U Ignored; + RTUInt64DivRem(&Ignored, pResult, pValue1, pValue2); + return pResult; +} + + +/** + * Bitwise AND of two 64-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64And(PRTUINT64U pResult, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi & pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo & pValue2->s.Lo; + return pResult; +} + + +/** + * Bitwise OR of two 64-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64Or( PRTUINT64U pResult, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi | pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo | pValue2->s.Lo; + return pResult; +} + + +/** + * Bitwise XOR of two 64-bit unsigned integer values. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64Xor(PRTUINT64U pResult, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + pResult->s.Hi = pValue1->s.Hi ^ pValue2->s.Hi; + pResult->s.Lo = pValue1->s.Lo ^ pValue2->s.Lo; + return pResult; +} + + +/** + * Shifts a 64-bit unsigned integer value @a cBits to the left. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to shift. + * @param cBits The number of bits to shift it. + */ +DECLINLINE(PRTUINT64U) RTUInt64ShiftLeft(PRTUINT64U pResult, PCRTUINT64U pValue, int cBits) +{ + cBits &= 63; + if (cBits < 32) + { + pResult->s.Lo = pValue->s.Lo << cBits; + pResult->s.Hi = (pValue->s.Hi << cBits) | (pValue->s.Lo >> (32 - cBits)); + } + else + { + pResult->s.Lo = 0; + pResult->s.Hi = pValue->s.Lo << (cBits - 32); + } + return pResult; +} + + +/** + * Shifts a 64-bit unsigned integer value @a cBits to the right. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to shift. + * @param cBits The number of bits to shift it. + */ +DECLINLINE(PRTUINT64U) RTUInt64ShiftRight(PRTUINT64U pResult, PCRTUINT64U pValue, int cBits) +{ + cBits &= 63; + if (cBits < 32) + { + pResult->s.Hi = pValue->s.Hi >> cBits; + pResult->s.Lo = (pValue->s.Lo >> cBits) | (pValue->s.Hi << (32 - cBits)); + } + else + { + pResult->s.Hi = 0; + pResult->s.Lo = pValue->s.Hi >> (cBits - 32); + } + return pResult; +} + + +/** + * Boolean not (result 0 or 1). + * + * @returns pResult. + * @param pResult The result variable. + * @param pValue The value. + */ +DECLINLINE(PRTUINT64U) RTUInt64BooleanNot(PRTUINT64U pResult, PCRTUINT64U pValue) +{ + pResult->s.Lo = pValue->s.Lo || pValue->s.Hi ? 0 : 1; + pResult->s.Hi = 0; + return pResult; +} + + +/** + * Bitwise not (flips each bit of the 64 bits). + * + * @returns pResult. + * @param pResult The result variable. + * @param pValue The value. + */ +DECLINLINE(PRTUINT64U) RTUInt64BitwiseNot(PRTUINT64U pResult, PCRTUINT64U pValue) +{ + pResult->s.Hi = ~pValue->s.Hi; + pResult->s.Lo = ~pValue->s.Lo; + return pResult; +} + + +/** + * Assigns one 64-bit unsigned integer value to another. + * + * @returns pResult + * @param pResult The result variable. + * @param pValue The value to assign. + */ +DECLINLINE(PRTUINT64U) RTUInt64Assign(PRTUINT64U pResult, PCRTUINT64U pValue) +{ +#if ARCH_BITS >= 32 + pResult->s.Hi = pValue->s.Hi; + pResult->s.Lo = pValue->s.Lo; +#else + pResult->Words.w0 = pValue->Words.w0; + pResult->Words.w1 = pValue->Words.w1; + pResult->Words.w2 = pValue->Words.w2; + pResult->Words.w3 = pValue->Words.w3; +#endif + return pResult; +} + + +/** + * Assigns a boolean value to 64-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param fValue The boolean value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignBoolean(PRTUINT64U pValueResult, bool fValue) +{ +#if ARCH_BITS >= 32 + pValueResult->s.Lo = fValue; + pValueResult->s.Hi = 0; +#else + pValueResult->Words.w0 = fValue; + pValueResult->Words.w1 = 0; + pValueResult->Words.w2 = 0; + pValueResult->Words.w3 = 0; +#endif + return pValueResult; +} + + +/** + * Assigns a 8-bit unsigned integer value to 64-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u8Value The 8-bit unsigned integer value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignU8(PRTUINT64U pValueResult, uint8_t u8Value) +{ +#if ARCH_BITS >= 32 + pValueResult->s.Lo = u8Value; + pValueResult->s.Hi = 0; +#else + pValueResult->Words.w0 = u8Value; + pValueResult->Words.w1 = 0; + pValueResult->Words.w2 = 0; + pValueResult->Words.w3 = 0; +#endif + return pValueResult; +} + + +/** + * Assigns a 16-bit unsigned integer value to 64-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u16Value The 16-bit unsigned integer value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignU16(PRTUINT64U pValueResult, uint16_t u16Value) +{ +#if ARCH_BITS >= 32 + pValueResult->s.Lo = u16Value; + pValueResult->s.Hi = 0; +#else + pValueResult->Words.w0 = u16Value; + pValueResult->Words.w1 = 0; + pValueResult->Words.w2 = 0; + pValueResult->Words.w3 = 0; +#endif + return pValueResult; +} + + +/** + * Assigns a 32-bit unsigned integer value to 64-bit unsigned integer. + * + * @returns pValueResult + * @param pValueResult The result variable. + * @param u32Value The 32-bit unsigned integer value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignU32(PRTUINT64U pValueResult, uint32_t u32Value) +{ +#if ARCH_BITS >= 32 + pValueResult->s.Lo = u32Value; + pValueResult->s.Hi = 0; +#else + pValueResult->Words.w0 = (uint16_t)u32Value; + pValueResult->Words.w1 = u32Value >> 16; + pValueResult->Words.w2 = 0; + pValueResult->Words.w3 = 0; +#endif + return pValueResult; +} + + +/** + * Adds two 64-bit unsigned integer values, storing the result in the first. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignAdd(PRTUINT64U pValue1Result, PCRTUINT64U pValue2) +{ + uint32_t const uTmp = pValue1Result->s.Lo; + pValue1Result->s.Lo += pValue2->s.Lo; + if (pValue1Result->s.Lo < uTmp) + pValue1Result->s.Hi++; + pValue1Result->s.Hi += pValue2->s.Hi; + return pValue1Result; +} + + +/** + * Subtracts two 64-bit unsigned integer values, storing the result in the + * first. + * + * @returns pValue1Result. + * @param pValue1Result The minuend value and result. + * @param pValue2 The subtrahend value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignSub(PRTUINT64U pValue1Result, PCRTUINT64U pValue2) +{ + uint32_t const uTmp = pValue1Result->s.Lo; + pValue1Result->s.Lo -= pValue2->s.Lo; + if (pValue1Result->s.Lo > uTmp) + pValue1Result->s.Hi--; + pValue1Result->s.Hi -= pValue2->s.Hi; + return pValue1Result; +} + + +/** + * Multiplies two 64-bit unsigned integer values, storing the result in the + * first. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignMul(PRTUINT64U pValue1Result, PCRTUINT64U pValue2) +{ + RTUINT64U Result; + RTUInt64Mul(&Result, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Divides a 64-bit unsigned integer value by another, storing the result in + * the first. + * + * @returns pValue1Result. + * @param pValue1Result The dividend value and result. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignDiv(PRTUINT64U pValue1Result, PCRTUINT64U pValue2) +{ + RTUINT64U Result; + RTUINT64U Ignored; + RTUInt64DivRem(&Result, &Ignored, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Divides a 64-bit unsigned integer value by another, storing the remainder in + * the first. + * + * @returns pValue1Result. + * @param pValue1Result The dividend value and result (remainder). + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignMod(PRTUINT64U pValue1Result, PCRTUINT64U pValue2) +{ + RTUINT64U Ignored; + RTUINT64U Result; + RTUInt64DivRem(&Ignored, &Result, pValue1Result, pValue2); + *pValue1Result = Result; + return pValue1Result; +} + + +/** + * Performs a bitwise AND of two 64-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignAnd(PRTUINT64U pValue1Result, PCRTUINT64U pValue2) +{ +#if ARCH_BITS >= 32 + pValue1Result->s.Hi &= pValue2->s.Hi; + pValue1Result->s.Lo &= pValue2->s.Lo; +#else + pValue1Result->Words.w0 &= pValue2->Words.w0; + pValue1Result->Words.w1 &= pValue2->Words.w1; + pValue1Result->Words.w2 &= pValue2->Words.w2; + pValue1Result->Words.w3 &= pValue2->Words.w3; +#endif + return pValue1Result; +} + + +/** + * Performs a bitwise AND of a 64-bit unsigned integer value and a mask made + * up of the first N bits, assigning the result to the the 64-bit value. + * + * @returns pValueResult. + * @param pValueResult The value and result. + * @param cBits The number of bits to AND (counting from the first + * bit). + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignAndNFirstBits(PRTUINT64U pValueResult, unsigned cBits) +{ + if (cBits <= 32) + { + if (cBits != 32) + pValueResult->s.Lo &= (RT_BIT_32(cBits) - 1); + pValueResult->s.Hi = 0; + } + else if (cBits < 64) + pValueResult->s.Hi &= (RT_BIT_32(cBits - 32) - 1); + return pValueResult; +} + + +/** + * Performs a bitwise OR of two 64-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignOr(PRTUINT64U pValue1Result, PCRTUINT64U pValue2) +{ +#if ARCH_BITS >= 32 + pValue1Result->s.Hi |= pValue2->s.Hi; + pValue1Result->s.Lo |= pValue2->s.Lo; +#else + pValue1Result->Words.w0 |= pValue2->Words.w0; + pValue1Result->Words.w1 |= pValue2->Words.w1; + pValue1Result->Words.w2 |= pValue2->Words.w2; + pValue1Result->Words.w3 |= pValue2->Words.w3; +#endif + return pValue1Result; +} + + +/** + * ORs in a bit and assign the result to the input value. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param iBit The bit to set (0 based). + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignOrBit(PRTUINT64U pValue1Result, unsigned iBit) +{ +#if ARCH_BITS >= 32 + if (iBit >= 32) + pValue1Result->s.Hi |= RT_BIT_32(iBit - 32); + else + pValue1Result->s.Lo |= RT_BIT_32(iBit); +#else + if (iBit >= 32) + { + if (iBit >= 48) + pValue1Result->Words.w3 |= UINT16_C(1) << (iBit - 48); + else + pValue1Result->Words.w2 |= UINT16_C(1) << (iBit - 32); + } + else + { + if (iBit >= 16) + pValue1Result->Words.w1 |= UINT16_C(1) << (iBit - 16); + else + pValue1Result->Words.w0 |= UINT16_C(1) << (iBit); + } +#endif + return pValue1Result; +} + + + +/** + * Performs a bitwise XOR of two 64-bit unsigned integer values and assigned + * the result to the first one. + * + * @returns pValue1Result. + * @param pValue1Result The first value and result. + * @param pValue2 The second value. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignXor(PRTUINT64U pValue1Result, PCRTUINT64U pValue2) +{ +#if ARCH_BITS >= 32 + pValue1Result->s.Hi ^= pValue2->s.Hi; + pValue1Result->s.Lo ^= pValue2->s.Lo; +#else + pValue1Result->Words.w0 ^= pValue2->Words.w0; + pValue1Result->Words.w1 ^= pValue2->Words.w1; + pValue1Result->Words.w2 ^= pValue2->Words.w2; + pValue1Result->Words.w3 ^= pValue2->Words.w3; +#endif + return pValue1Result; +} + + +/** + * Performs a bitwise left shift on a 64-bit unsigned integer value, assigning + * the result to it. + * + * @returns pValueResult. + * @param pValueResult The first value and result. + * @param cBits The number of bits to shift. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignShiftLeft(PRTUINT64U pValueResult, int cBits) +{ + RTUINT64U const InVal = *pValueResult; + if (cBits > 0) + { + /* (left shift) */ + cBits &= 31; + if (cBits >= 32) + { + pValueResult->s.Lo = 0; + pValueResult->s.Hi = InVal.s.Lo << (cBits - 32); + } + else + { + pValueResult->s.Hi = InVal.s.Hi << cBits; + pValueResult->s.Hi |= InVal.s.Lo >> (32 - cBits); + pValueResult->s.Lo = InVal.s.Lo << cBits; + } + } + else if (cBits < 0) + { + /* (right shift) */ + cBits = -cBits; + cBits &= 31; + if (cBits >= 32) + { + pValueResult->s.Hi = 0; + pValueResult->s.Lo = InVal.s.Hi >> (cBits - 32); + } + else + { + pValueResult->s.Lo = InVal.s.Lo >> cBits; + pValueResult->s.Lo |= InVal.s.Hi << (32 - cBits); + pValueResult->s.Hi = InVal.s.Hi >> cBits; + } + } + return pValueResult; +} + + +/** + * Performs a bitwise left shift on a 64-bit unsigned integer value, assigning + * the result to it. + * + * @returns pValueResult. + * @param pValueResult The first value and result. + * @param cBits The number of bits to shift. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignShiftRight(PRTUINT64U pValueResult, int cBits) +{ + return RTUInt64AssignShiftLeft(pValueResult, -cBits); +} + + +/** + * Performs a bitwise NOT on a 64-bit unsigned integer value, assigning the + * result to it. + * + * @returns pValueResult + * @param pValueResult The value and result. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignBitwiseNot(PRTUINT64U pValueResult) +{ +#if ARCH_BITS >= 32 + pValueResult->s.Hi = ~pValueResult->s.Hi; + pValueResult->s.Lo = ~pValueResult->s.Lo; +#else + pValueResult->Words.w0 = ~pValueResult->Words.w0; + pValueResult->Words.w1 = ~pValueResult->Words.w1; + pValueResult->Words.w2 = ~pValueResult->Words.w2; + pValueResult->Words.w3 = ~pValueResult->Words.w3; +#endif + return pValueResult; +} + + +/** + * Performs a boolean NOT on a 64-bit unsigned integer value, assigning the + * result to it. + * + * @returns pValueResult + * @param pValueResult The value and result. + */ +DECLINLINE(PRTUINT64U) RTUInt64AssignBooleanNot(PRTUINT64U pValueResult) +{ + return RTUInt64AssignBoolean(pValueResult, RTUInt64IsZero(pValueResult)); +} + + +/** + * Compares two 64-bit unsigned integer values. + * + * @retval 0 if equal. + * @retval -1 if the first value is smaller than the second. + * @retval 1 if the first value is larger than the second. + * + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(int) RTUInt64Compare(PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ +#if ARCH_BITS >= 32 + if (pValue1->s.Hi != pValue2->s.Hi) + return pValue1->s.Hi > pValue2->s.Hi ? 1 : -1; + if (pValue1->s.Lo != pValue2->s.Lo) + return pValue1->s.Lo > pValue2->s.Lo ? 1 : -1; + return 0; +#else + if (pValue1->Words.w3 != pValue2->Words.w3) + return pValue1->Words.w3 > pValue2->Words.w3 ? 1 : -1; + if (pValue1->Words.w2 != pValue2->Words.w2) + return pValue1->Words.w2 > pValue2->Words.w2 ? 1 : -1; + if (pValue1->Words.w1 != pValue2->Words.w1) + return pValue1->Words.w1 > pValue2->Words.w1 ? 1 : -1; + if (pValue1->Words.w0 != pValue2->Words.w0) + return pValue1->Words.w0 > pValue2->Words.w0 ? 1 : -1; + return 0; +#endif +} + + +/** + * Tests if a 64-bit unsigned integer value is smaller than another. + * + * @returns true if the first value is smaller, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt64IsSmaller(PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ +#if ARCH_BITS >= 32 + return pValue1->s.Hi < pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo < pValue2->s.Lo); +#else + return pValue1->Words.w3 < pValue2->Words.w3 + || ( pValue1->Words.w3 == pValue2->Words.w3 + && ( pValue1->Words.w2 < pValue2->Words.w2 + || ( pValue1->Words.w2 == pValue2->Words.w2 + && ( pValue1->Words.w1 < pValue2->Words.w1 + || ( pValue1->Words.w1 == pValue2->Words.w1 + && pValue1->Words.w0 < pValue2->Words.w0))))); +#endif +} + + +/** + * Tests if a 32-bit unsigned integer value is larger than another. + * + * @returns true if the first value is larger, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt64IsLarger(PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ +#if ARCH_BITS >= 32 + return pValue1->s.Hi > pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo > pValue2->s.Lo); +#else + return pValue1->Words.w3 > pValue2->Words.w3 + || ( pValue1->Words.w3 == pValue2->Words.w3 + && ( pValue1->Words.w2 > pValue2->Words.w2 + || ( pValue1->Words.w2 == pValue2->Words.w2 + && ( pValue1->Words.w1 > pValue2->Words.w1 + || ( pValue1->Words.w1 == pValue2->Words.w1 + && pValue1->Words.w0 > pValue2->Words.w0))))); +#endif +} + + +/** + * Tests if a 64-bit unsigned integer value is larger or equal than another. + * + * @returns true if the first value is larger or equal, false if not. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt64IsLargerOrEqual(PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ +#if ARCH_BITS >= 32 + return pValue1->s.Hi > pValue2->s.Hi + || ( pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo >= pValue2->s.Lo); +#else + return pValue1->Words.w3 > pValue2->Words.w3 + || ( pValue1->Words.w3 == pValue2->Words.w3 + && ( pValue1->Words.w2 > pValue2->Words.w2 + || ( pValue1->Words.w2 == pValue2->Words.w2 + && ( pValue1->Words.w1 > pValue2->Words.w1 + || ( pValue1->Words.w1 == pValue2->Words.w1 + && pValue1->Words.w0 >= pValue2->Words.w0))))); +#endif +} + + +/** + * Tests if two 64-bit unsigned integer values not equal. + * + * @returns true if equal, false if not equal. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt64IsEqual(PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ +#if ARCH_BITS >= 32 + return pValue1->s.Hi == pValue2->s.Hi + && pValue1->s.Lo == pValue2->s.Lo; +#else + return pValue1->Words.w0 == pValue2->Words.w0 + && pValue1->Words.w1 == pValue2->Words.w1 + && pValue1->Words.w2 == pValue2->Words.w2 + && pValue1->Words.w3 == pValue2->Words.w3; +#endif +} + + +/** + * Tests if two 64-bit unsigned integer values are not equal. + * + * @returns true if not equal, false if equal. + * @param pValue1 The first value. + * @param pValue2 The second value. + */ +DECLINLINE(bool) RTUInt64IsNotEqual(PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + return !RTUInt64IsEqual(pValue1, pValue2); +} + + +/** + * Sets a bit in a 64-bit unsigned integer type. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to set. + */ +DECLINLINE(PRTUINT64U) RTUInt64BitSet(PRTUINT64U pValueResult, unsigned iBit) +{ + if (iBit < 32) + { +#if ARCH_BITS >= 32 + pValueResult->s.Lo |= RT_BIT_32(iBit); +#else + if (iBit < 16) + pValueResult->Words.w0 |= UINT16_C(1) << iBit; + else + pValueResult->Words.w1 |= UINT16_C(1) << (iBit - 32); +#endif + } + else if (iBit < 64) + { +#if ARCH_BITS >= 32 + pValueResult->s.Hi |= RT_BIT_32(iBit - 32); +#else + if (iBit < 48) + pValueResult->Words.w2 |= UINT16_C(1) << (iBit - 64); + else + pValueResult->Words.w3 |= UINT16_C(1) << (iBit - 96); +#endif + } + return pValueResult; +} + + +/** + * Sets a bit in a 64-bit unsigned integer type. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to set. + */ +DECLINLINE(PRTUINT64U) RTUInt64BitClear(PRTUINT64U pValueResult, unsigned iBit) +{ + if (iBit < 32) + { +#if ARCH_BITS >= 32 + pValueResult->s.Lo &= ~RT_BIT_32(iBit); +#else + if (iBit < 48) + pValueResult->Words.w0 &= ~(UINT16_C(1) << (iBit)); + else + pValueResult->Words.w1 &= ~(UINT16_C(1) << (iBit - 32)); +#endif + } + else if (iBit < 64) + { +#if ARCH_BITS >= 32 + pValueResult->s.Hi &= ~RT_BIT_32(iBit - 32); +#else + if (iBit < 48) + pValueResult->Words.w2 &= ~(UINT16_C(1) << (iBit - 64)); + else + pValueResult->Words.w3 &= ~(UINT16_C(1) << (iBit - 96)); +#endif + } + return pValueResult; +} + + +/** + * Tests if a bit in a 64-bit unsigned integer value is set. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iBit The bit to test. + */ +DECLINLINE(bool) RTUInt64BitTest(PRTUINT64U pValueResult, unsigned iBit) +{ + bool fRc; + if (iBit < 32) + { +#if ARCH_BITS >= 32 + fRc = RT_BOOL(pValueResult->s.Lo & RT_BIT_32(iBit)); +#else + if (iBit < 16) + fRc = RT_BOOL(pValueResult->Words.w0 & (UINT16_C(1) << (iBit))); + else + fRc = RT_BOOL(pValueResult->Words.w1 & (UINT16_C(1) << (iBit - 16))); +#endif + } + else if (iBit < 64) + { +#if ARCH_BITS >= 32 + fRc = RT_BOOL(pValueResult->s.Hi & RT_BIT_32(iBit - 32)); +#else + if (iBit < 48) + fRc = RT_BOOL(pValueResult->Words.w2 & (UINT16_C(1) << (iBit - 32))); + else + fRc = RT_BOOL(pValueResult->Words.w3 & (UINT16_C(1) << (iBit - 48))); +#endif + } + else + fRc = false; + return fRc; +} + + +/** + * Set a range of bits a 64-bit unsigned integer value. + * + * @returns pValueResult. + * @param pValueResult The input and output value. + * @param iFirstBit The first bit to test. + * @param cBits The number of bits to set. + */ +DECLINLINE(PRTUINT64U) RTUInt64BitSetRange(PRTUINT64U pValueResult, unsigned iFirstBit, unsigned cBits) +{ + /* bounds check & fix. */ + if (iFirstBit < 64) + { + if (iFirstBit + cBits > 64) + cBits = 64 - iFirstBit; + +#if ARCH_BITS >= 32 + if (iFirstBit + cBits < 32) + pValueResult->s.Lo |= (RT_BIT_32(cBits) - 1) << iFirstBit; + else if (iFirstBit + cBits < 64 && iFirstBit >= 32) + pValueResult->s.Hi |= (RT_BIT_32(cBits) - 1) << (iFirstBit - 32); + else +#else + if (iFirstBit + cBits < 16) + pValueResult->Words.w0 |= ((UINT16_C(1) << cBits) - 1) << iFirstBit; + else if (iFirstBit + cBits < 32 && iFirstBit >= 16) + pValueResult->Words.w1 |= ((UINT16_C(1) << cBits) - 1) << (iFirstBit - 16); + else if (iFirstBit + cBits < 48 && iFirstBit >= 32) + pValueResult->Words.w2 |= ((UINT16_C(1) << cBits) - 1) << (iFirstBit - 32); + else if (iFirstBit + cBits < 64 && iFirstBit >= 48) + pValueResult->Words.w3 |= ((UINT16_C(1) << cBits) - 1) << (iFirstBit - 48); + else +#endif + while (cBits-- > 0) + RTUInt64BitSet(pValueResult, iFirstBit++); + } + return pValueResult; +} + + +/** + * Test if all the bits of a 64-bit unsigned integer value are set. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt64BitAreAllSet(PRTUINT64U pValue) +{ +#if ARCH_BITS >= 32 + return pValue->s.Hi == UINT32_MAX + && pValue->s.Lo == UINT32_MAX; +#else + return pValue->Words.w0 == UINT16_MAX + && pValue->Words.w1 == UINT16_MAX + && pValue->Words.w2 == UINT16_MAX + && pValue->Words.w3 == UINT16_MAX; +#endif +} + + +/** + * Test if all the bits of a 64-bit unsigned integer value are clear. + * + * @returns true if they are, false if they aren't. + * @param pValue The input and output value. + */ +DECLINLINE(bool) RTUInt64BitAreAllClear(PRTUINT64U pValue) +{ + return RTUInt64IsZero(pValue); +} + + +DECLINLINE(unsigned) RTUInt64BitCount(PCRTUINT64U pValue) +{ + unsigned cBits; + if (pValue->s.Hi != 0) + { +#if ARCH_BITS >= 32 + cBits = 32 + ASMBitLastSetU32(pValue->s.Hi); +#else + if (pValue->Words.w3) + cBits = 48 + ASMBitLastSetU16(pValue->Words.w3); + else + cBits = 32 + ASMBitLastSetU16(pValue->Words.w2); +#endif + } + else + { +#if ARCH_BITS >= 32 + cBits = ASMBitLastSetU32(pValue->s.Lo); +#else + if (pValue->Words.w1) + cBits = 16 + ASMBitLastSetU16(pValue->Words.w1); + else + cBits = 0 + ASMBitLastSetU16(pValue->Words.w0); +#endif + } + return cBits; +} + + +/** + * Divides a 64-bit unsigned integer value by another, returning both quotient + * and remainder. + * + * @returns pQuotient, NULL if pValue2 is 0. + * @param pQuotient Where to return the quotient. + * @param pRemainder Where to return the remainder. + * @param pValue1 The dividend value. + * @param pValue2 The divisor value. + */ +DECLINLINE(PRTUINT64U) RTUInt64DivRem(PRTUINT64U pQuotient, PRTUINT64U pRemainder, PCRTUINT64U pValue1, PCRTUINT64U pValue2) +{ + int iDiff; + + /* + * Sort out all the special cases first. + */ + /* Divide by zero or 1? */ + if (!pValue2->s.Hi) + { + if (!pValue2->s.Lo) + return NULL; + + if (pValue2->s.Lo == 1) + { + RTUInt64SetZero(pRemainder); + *pQuotient = *pValue1; + return pQuotient; + } + /** @todo RTUInt64DivModByU32 */ + } + + /* Dividend is smaller? */ + iDiff = RTUInt64Compare(pValue1, pValue2); + if (iDiff < 0) + { + *pRemainder = *pValue1; + RTUInt64SetZero(pQuotient); + } + + /* The values are equal? */ + else if (iDiff == 0) + { + RTUInt64SetZero(pRemainder); + RTUInt64AssignU8(pQuotient, 1); + } + else + { + /* + * Prepare. + */ + unsigned iBitAdder = RTUInt64BitCount(pValue1) - RTUInt64BitCount(pValue2); + RTUINT64U NormDivisor = *pValue2; + if (iBitAdder) + { + RTUInt64ShiftLeft(&NormDivisor, pValue2, iBitAdder); + if (RTUInt64IsLarger(&NormDivisor, pValue1)) + { + RTUInt64AssignShiftRight(&NormDivisor, 1); + iBitAdder--; + } + } + else + NormDivisor = *pValue2; + + RTUInt64SetZero(pQuotient); + *pRemainder = *pValue1; + + /* + * Do the division. + */ + if (RTUInt64IsLargerOrEqual(pRemainder, pValue2)) + { + for (;;) + { + if (RTUInt64IsLargerOrEqual(pRemainder, &NormDivisor)) + { + RTUInt64AssignSub(pRemainder, &NormDivisor); + RTUInt64AssignOrBit(pQuotient, iBitAdder); + } + if (RTUInt64IsSmaller(pRemainder, pValue2)) + break; + RTUInt64AssignShiftRight(&NormDivisor, 1); + iBitAdder--; + } + } + } + return pQuotient; +} + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_uint64_h */ + diff --git a/include/iprt/uni.h b/include/iprt/uni.h new file mode 100644 index 00000000..ad804dcb --- /dev/null +++ b/include/iprt/uni.h @@ -0,0 +1,491 @@ +/** @file + * IPRT - Unicode Code Points. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_uni_h +#define IPRT_INCLUDED_uni_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/** @defgroup grp_rt_uni RTUniCp - Unicode Code Points + * @ingroup grp_rt + * @{ + */ + +/** @def RTUNI_USE_WCTYPE + * Define RTUNI_USE_WCTYPE to not use the IPRT unicode data but the + * data which the C runtime library provides. */ +#ifdef DOXYGEN_RUNNING +# define RTUNI_USE_WCTYPE +#endif + +#include <iprt/types.h> +#ifdef RTUNI_USE_WCTYPE +# include <wctype.h> +#endif + +RT_C_DECLS_BEGIN + + +#ifndef RTUNI_USE_WCTYPE + +/** + * A unicode flags range. + * @internal + */ +typedef struct RTUNIFLAGSRANGE +{ + /** The first code point of the range. */ + RTUNICP BeginCP; + /** The last + 1 code point of the range. */ + RTUNICP EndCP; + /** Pointer to the array of case folded code points. */ + const uint8_t *pafFlags; +} RTUNIFLAGSRANGE; +/** Pointer to a flags range. + * @internal */ +typedef RTUNIFLAGSRANGE *PRTUNIFLAGSRANGE; +/** Pointer to a const flags range. + * @internal */ +typedef const RTUNIFLAGSRANGE *PCRTUNIFLAGSRANGE; + +/** + * A unicode case folded range. + * @internal + */ +typedef struct RTUNICASERANGE +{ + /** The first code point of the range. */ + RTUNICP BeginCP; + /** The last + 1 code point of the range. */ + RTUNICP EndCP; + /** Pointer to the array of case folded code points. */ + PCRTUNICP paFoldedCPs; +} RTUNICASERANGE; +/** Pointer to a case folded range. + * @internal */ +typedef RTUNICASERANGE *PRTUNICASERANGE; +/** Pointer to a const case folded range. + * @internal */ +typedef const RTUNICASERANGE *PCRTUNICASERANGE; + +/** @name Unicode Code Point Flags. + * @internal + * @{ */ +#define RTUNI_UPPER RT_BIT(0) +#define RTUNI_LOWER RT_BIT(1) +#define RTUNI_ALPHA RT_BIT(2) +#define RTUNI_XDIGIT RT_BIT(3) +#define RTUNI_DDIGIT RT_BIT(4) +#define RTUNI_WSPACE RT_BIT(5) +/*#define RTUNI_BSPACE RT_BIT(6) - later */ +/** When set, the codepoint requires further checking wrt NFC and NFD + * normalization. I.e. set when either of QC_NFD and QC_NFC are not Y. */ +#define RTUNI_QC_NFX RT_BIT(7) +/** @} */ + + +/** + * Array of flags ranges. + * @internal + */ +extern RTDATADECL(const RTUNIFLAGSRANGE) g_aRTUniFlagsRanges[]; + +/** + * Gets the flags for a unicode code point. + * + * @returns The flag mask. (RTUNI_*) + * @param CodePoint The unicode code point. + * @internal + */ +DECLINLINE(RTUNICP) rtUniCpFlags(RTUNICP CodePoint) +{ + PCRTUNIFLAGSRANGE pCur = &g_aRTUniFlagsRanges[0]; + do + { + if (pCur->EndCP > CodePoint) + { + if (pCur->BeginCP <= CodePoint) + return pCur->pafFlags[CodePoint - pCur->BeginCP]; + break; + } + pCur++; + } while (pCur->EndCP != RTUNICP_MAX); + return 0; +} + + +/** + * Checks if a unicode code point is upper case. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsUpper(RTUNICP CodePoint) +{ + return (rtUniCpFlags(CodePoint) & RTUNI_UPPER) != 0; +} + + +/** + * Checks if a unicode code point is lower case. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsLower(RTUNICP CodePoint) +{ + return (rtUniCpFlags(CodePoint) & RTUNI_LOWER) != 0; +} + + +/** + * Checks if a unicode code point is case foldable. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsFoldable(RTUNICP CodePoint) +{ + /* Right enough. */ + return (rtUniCpFlags(CodePoint) & (RTUNI_LOWER | RTUNI_UPPER)) != 0; +} + + +/** + * Checks if a unicode code point is alphabetic. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsAlphabetic(RTUNICP CodePoint) +{ + return (rtUniCpFlags(CodePoint) & RTUNI_ALPHA) != 0; +} + + +/** + * Checks if a unicode code point is a decimal digit. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsDecDigit(RTUNICP CodePoint) +{ + return (rtUniCpFlags(CodePoint) & RTUNI_DDIGIT) != 0; +} + + +/** + * Checks if a unicode code point is a hexadecimal digit. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsHexDigit(RTUNICP CodePoint) +{ + return (rtUniCpFlags(CodePoint) & RTUNI_XDIGIT) != 0; +} + + +/** + * Checks if a unicode code point is white space. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsSpace(RTUNICP CodePoint) +{ + return (rtUniCpFlags(CodePoint) & RTUNI_WSPACE) != 0; +} + + + +/** + * Array of uppercase ranges. + * @internal + */ +extern RTDATADECL(const RTUNICASERANGE) g_aRTUniUpperRanges[]; + +/** + * Array of lowercase ranges. + * @internal + */ +extern RTDATADECL(const RTUNICASERANGE) g_aRTUniLowerRanges[]; + + +/** + * Folds a unicode code point using the specified range array. + * + * @returns FOlded code point. + * @param CodePoint The unicode code point to fold. + * @param pCur The case folding range to use. + */ +DECLINLINE(RTUNICP) rtUniCpFold(RTUNICP CodePoint, PCRTUNICASERANGE pCur) +{ + do + { + if (pCur->EndCP > CodePoint) + { + if (pCur->BeginCP <= CodePoint) + CodePoint = pCur->paFoldedCPs[CodePoint - pCur->BeginCP]; + break; + } + pCur++; + } while (pCur->EndCP != RTUNICP_MAX); + return CodePoint; +} + + +/** + * Folds a unicode code point to upper case. + * + * @returns Folded code point. + * @param CodePoint The unicode code point to fold. + */ +DECLINLINE(RTUNICP) RTUniCpToUpper(RTUNICP CodePoint) +{ + return rtUniCpFold(CodePoint, &g_aRTUniUpperRanges[0]); +} + + +/** + * Folds a unicode code point to lower case. + * + * @returns Folded code point. + * @param CodePoint The unicode code point to fold. + */ +DECLINLINE(RTUNICP) RTUniCpToLower(RTUNICP CodePoint) +{ + return rtUniCpFold(CodePoint, &g_aRTUniLowerRanges[0]); +} + + +#else /* RTUNI_USE_WCTYPE */ + + +/** + * Checks if a unicode code point is upper case. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsUpper(RTUNICP CodePoint) +{ + return !!iswupper(CodePoint); +} + + +/** + * Checks if a unicode code point is lower case. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsLower(RTUNICP CodePoint) +{ + return !!iswlower(CodePoint); +} + + +/** + * Checks if a unicode code point is case foldable. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsFoldable(RTUNICP CodePoint) +{ + /* Right enough. */ + return iswupper(CodePoint) || iswlower(CodePoint); +} + + +/** + * Checks if a unicode code point is alphabetic. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsAlphabetic(RTUNICP CodePoint) +{ + return !!iswalpha(CodePoint); +} + + +/** + * Checks if a unicode code point is a decimal digit. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsDecDigit(RTUNICP CodePoint) +{ + return !!iswdigit(CodePoint); +} + + +/** + * Checks if a unicode code point is a hexadecimal digit. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsHexDigit(RTUNICP CodePoint) +{ + return !!iswxdigit(CodePoint); +} + + +/** + * Checks if a unicode code point is white space. + * + * @returns true if it is. + * @returns false if it isn't. + * @param CodePoint The code point. + */ +DECLINLINE(bool) RTUniCpIsSpace(RTUNICP CodePoint) +{ + return !!iswspace(CodePoint); +} + + +/** + * Folds a unicode code point to upper case. + * + * @returns Folded code point. + * @param CodePoint The unicode code point to fold. + */ +DECLINLINE(RTUNICP) RTUniCpToUpper(RTUNICP CodePoint) +{ + return towupper(CodePoint); +} + + +/** + * Folds a unicode code point to lower case. + * + * @returns Folded code point. + * @param CodePoint The unicode code point to fold. + */ +DECLINLINE(RTUNICP) RTUniCpToLower(RTUNICP CodePoint) +{ + return towlower(CodePoint); +} + + +#endif /* RTUNI_USE_WCTYPE */ + + +/** + * Frees a unicode string. + * + * @param pusz The string to free. + */ +RTDECL(void) RTUniFree(PRTUNICP pusz); + + +/** + * Checks if a code point valid. + * + * Any code point (defined or not) within the 17 unicode planes (0 thru 16), + * except surrogates will be considered valid code points by this function. + * + * @returns true if in range, false if not. + * @param CodePoint The unicode code point to validate. + */ +DECLINLINE(bool) RTUniCpIsValid(RTUNICP CodePoint) +{ + return CodePoint <= 0x00d7ff + || ( CodePoint <= 0x10ffff + && CodePoint >= 0x00e000); +} + + +/** + * Checks if the given code point is in the BMP range. + * + * Surrogates are not considered in the BMP range by this function. + * + * @returns true if in BMP, false if not. + * @param CodePoint The unicode code point to consider. + */ +DECLINLINE(bool) RTUniCpIsBMP(RTUNICP CodePoint) +{ + return CodePoint <= 0xd7ff + || ( CodePoint <= 0xffff + && CodePoint >= 0xe000); +} + + +/** + * Folds a unicode code point to lower case. + * + * @returns Folded code point. + * @param CodePoint The unicode code point to fold. + */ +DECLINLINE(size_t) RTUniCpCalcUtf8Len(RTUNICP CodePoint) +{ + if (CodePoint < 0x80) + return 1; + return 2 + + (CodePoint >= 0x00000800) + + (CodePoint >= 0x00010000) + + (CodePoint >= 0x00200000) + + (CodePoint >= 0x04000000) + + (CodePoint >= 0x80000000) /* illegal */; +} + + + +RT_C_DECLS_END +/** @} */ + + +#endif /* !IPRT_INCLUDED_uni_h */ + diff --git a/include/iprt/uri.h b/include/iprt/uri.h new file mode 100644 index 00000000..75787cd4 --- /dev/null +++ b/include/iprt/uri.h @@ -0,0 +1,380 @@ +/** @file + * IPRT - Uniform Resource Identifier handling. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_uri_h +#define IPRT_INCLUDED_uri_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_uri RTUri - Uri parsing and creation + * + * URI parsing and creation based on RFC-3986. + * + * @remarks The whole specification isn't implemented and we only provide scheme + * specific special APIs for "file://". + * + * @ingroup grp_rt + * @{ + */ + + +/** + * Parsed URI. + * + * @remarks This structure is subject to change. + */ +typedef struct RTURIPARSED +{ + /** Magic value (for internal use only). */ + uint32_t u32Magic; + /** RTURIPARSED_F_XXX. */ + uint32_t fFlags; + + /** The length of the scheme. */ + size_t cchScheme; + + /** The offset into the string of the authority. */ + size_t offAuthority; + /** The authority length. + * @remarks The authority component can be zero length, so to check whether + * it's there or not consult RTURIPARSED_F_HAVE_AUTHORITY. */ + size_t cchAuthority; + + /** The offset into the string of the path. */ + size_t offPath; + /** The length of the path. */ + size_t cchPath; + + /** The offset into the string of the query. */ + size_t offQuery; + /** The length of the query. */ + size_t cchQuery; + + /** The offset into the string of the fragment. */ + size_t offFragment; + /** The length of the fragment. */ + size_t cchFragment; + + /** @name Authority subdivisions + * @{ */ + /** If there is a userinfo part, this is the start of it. Otherwise it's the + * same as offAuthorityHost. */ + size_t offAuthorityUsername; + /** The length of the username (zero if not present). */ + size_t cchAuthorityUsername; + /** If there is a userinfo part containing a password, this is the start of it. + * Otherwise it's the same as offAuthorityHost. */ + size_t offAuthorityPassword; + /** The length of the password (zero if not present). */ + size_t cchAuthorityPassword; + /** The offset of the host part of the authority. */ + size_t offAuthorityHost; + /** The length of the host part of the authority. */ + size_t cchAuthorityHost; + /** The authority port number, UINT32_MAX if not present or empty. */ + uint32_t uAuthorityPort; + /** @} */ +} RTURIPARSED; +/** Pointer to a parsed URI. */ +typedef RTURIPARSED *PRTURIPARSED; +/** Pointer to a const parsed URI. */ +typedef RTURIPARSED const *PCRTURIPARSED; + +/** @name RTURIPARSED_F_XXX - RTURIPARSED::fFlags + * @{ */ +/** Set if the URI contains escaped characters. */ +#define RTURIPARSED_F_CONTAINS_ESCAPED_CHARS UINT32_C(0x00000001) +/** Set if the URI has an authority component. Necessary since the authority + * component can have a zero length. */ +#define RTURIPARSED_F_HAS_AUTHORITY UINT32_C(0x00000002) +/** Set if there is a port component. */ +#define RTURIPARSED_F_HAS_PORT UINT32_C(0x00000004) +/** @} */ + +/** + * Parses a URI. + * + * @returns IPRT status code. + * @param pszUri The URI to parse. + * @param pParsed Where to return the details. This can be handed + * to the RTUriParsed* APIs for retriving + * information. + */ +RTDECL(int) RTUriParse(const char *pszUri, PRTURIPARSED pParsed); + +/** + * Extract the scheme out of a parsed URI. + * + * @returns the scheme if the URI is valid, NULL otherwise. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + */ +RTDECL(char *) RTUriParsedScheme(const char *pszUri, PCRTURIPARSED pParsed); + +/** + * Extract the authority out of a parsed URI. + * + * @returns the authority if the URI contains one, NULL otherwise. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + * @remarks The authority can have a zero length. + */ +RTDECL(char *) RTUriParsedAuthority(const char *pszUri, PCRTURIPARSED pParsed); + +/** + * Extract the username out of the authority component in a parsed URI. + * + * @returns The username if the URI contains one, otherwise NULL. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + * + * @todo This may currently be returning NULL when it maybe would be more + * appropriate to return an empty string... + */ +RTDECL(char *) RTUriParsedAuthorityUsername(const char *pszUri, PCRTURIPARSED pParsed); + +/** + * Extract the password out of the authority component in a parsed URI. + * + * @returns The password if the URI contains one, otherwise NULL. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + * + * @todo This may currently be returning NULL when it maybe would be more + * appropriate to return an empty string... + */ +RTDECL(char *) RTUriParsedAuthorityPassword(const char *pszUri, PCRTURIPARSED pParsed); + +/** + * Extract the host out of the authority component in a parsed URI. + * + * @returns The host if the URI contains one, otherwise NULL. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + * + * @todo This may currently be returning NULL when it maybe would be more + * appropriate to return an empty string... + */ +RTDECL(char *) RTUriParsedAuthorityHost(const char *pszUri, PCRTURIPARSED pParsed); + +/** + * Extract the port number out of the authority component in a parsed URI. + * + * @returns The port number if the URI contains one, otherwise UINT32_MAX. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + */ +RTDECL(uint32_t) RTUriParsedAuthorityPort(const char *pszUri, PCRTURIPARSED pParsed); + +/** + * Extract the path out of a parsed URI. + * + * @returns the path if the URI contains one, NULL otherwise. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + */ +RTDECL(char *) RTUriParsedPath(const char *pszUri, PCRTURIPARSED pParsed); + +/** + * Extract the query out of a parsed URI. + * + * @returns the query if the URI contains one, NULL otherwise. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + */ +RTDECL(char *) RTUriParsedQuery(const char *pszUri, PCRTURIPARSED pParsed); + +/** + * Extract the fragment out of a parsed URI. + * + * @returns the fragment if the URI contains one, NULL otherwise. + * @param pszUri The URI passed to RTUriParse when producing the + * info in @a pParsed. + * @param pParsed Pointer to the RTUriParse output. + */ +RTDECL(char *) RTUriParsedFragment(const char *pszUri, PCRTURIPARSED pParsed); + + + +/** + * Creates a generic URI. + * + * The returned pointer must be freed using RTStrFree(). + * + * @returns the new URI on success, NULL otherwise. + * @param pszScheme The URI scheme. + * @param pszAuthority The authority part of the URI (optional). + * @param pszPath The path part of the URI (optional). + * @param pszQuery The query part of the URI (optional). + * @param pszFragment The fragment part of the URI (optional). + */ +RTDECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery, + const char *pszFragment); + +/** + * Check whether the given scheme matches that of the URI. + * + * This does not validate the URI, it just compares the scheme, no more, no + * less. Thus it's much faster than using RTUriParsedScheme. + * + * @returns true if the scheme match, false if not. + * @param pszUri The URI to check. + * @param pszScheme The scheme to compare with. + */ +RTDECL(bool) RTUriIsSchemeMatch(const char *pszUri, const char *pszScheme); + +/** @defgroup grp_rt_uri_file RTUriFile - Uri file parsing and creation + * + * Implements basic "file:" scheme support to the generic RTUri interface. This + * is partly documented in RFC-1738. + * + * @{ + */ + +/** + * Creates a file URI. + * + * The returned pointer must be freed using RTStrFree(). + * + * @returns The new URI on success, NULL otherwise. Free With RTStrFree. + * @param pszPath The path to create an 'file://' URI for. This is + * assumed to be using the default path style of the + * system. + * + * @sa RTUriFileCreateEx, RTUriCreate + */ +RTDECL(char *) RTUriFileCreate(const char *pszPath); + +/** + * Creates an file URL for the given path. + * + * This API works like RTStrToUtf16Ex with regard to result allocation or + * buffering (i.e. it's a bit complicated but very flexible). + * + * @returns iprt status code. + * @param pszPath The path to convert to a file:// URL. + * @param fPathStyle The input path style, exactly one of + * RTPATH_STR_F_STYLE_HOST, RTPATH_STR_F_STYLE_DOS and + * RTPATH_STR_F_STYLE_UNIX. Must include iprt/path.h. + * @param ppszUri If cbUri is non-zero, this must either be pointing + * to pointer to a buffer of the specified size, or + * pointer to a NULL pointer. If *ppszUri is NULL or + * cbUri is zero a buffer of at least cbUri chars will + * be allocated to hold the URI. If a buffer was + * requested it must be freed using RTStrFree(). + * @param cbUri The buffer size in bytes (includes terminator). + * @param pcchUri Where to store the length of the URI string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @sa RTUriCreate, RTUriFileCreate + */ +RTDECL(int) RTUriFileCreateEx(const char *pszPath, uint32_t fPathStyle, char **ppszUri, size_t cbUri, size_t *pcchUri); + +/** + * Returns the file path encoded in the file URI. + * + * This differs a quite a bit from RTUriParsedPath in that it tries to be + * compatible with URL produced by older windows version. This API is basically + * producing the same results as the PathCreateFromUrl API on Windows. + * + * @returns The path if the URI contains one, system default path style, + * otherwise NULL. + * @param pszUri The alleged 'file://' URI to extract the path from. + * + * @sa RTUriParsedPath, RTUriFilePathEx + */ +RTDECL(char *) RTUriFilePath(const char *pszUri); + +/** + * Queries the file path for the given file URI. + * + * This API works like RTStrToUtf16Ex with regard to result allocation or + * buffering (i.e. it's a bit complicated but very flexible). + * + * This differs a quite a bit from RTUriParsedPath in that it tries to be + * compatible with URL produced by older windows version. This API is basically + * producing the same results as the PathCreateFromUrl API on Windows. + * + * @returns IPRT status code. + * @retval VERR_URI_NOT_FILE_SCHEME if not file scheme. + * + * @param pszUri The alleged file:// URI to extract the path from. + * @param fPathStyle The output path style, exactly one of + * RTPATH_STR_F_STYLE_HOST, RTPATH_STR_F_STYLE_DOS and + * RTPATH_STR_F_STYLE_UNIX. Must include iprt/path.h. + * @param ppszPath If cbPath is non-zero, this must either be pointing + * to pointer to a buffer of the specified size, or + * pointer to a NULL pointer. If *ppszPath is NULL or + * cbPath is zero a buffer of at least cbPath chars + * will be allocated to hold the path. If a buffer was + * requested it must be freed using RTStrFree(). + * @param cbPath The buffer size in bytes (includes terminator). + * @param pcchPath Where to store the length of the path string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @sa RTUriParsedPath, RTUriFilePath + */ +RTDECL(int) RTUriFilePathEx(const char *pszUri, uint32_t fPathStyle, char **ppszPath, size_t cbPath, size_t *pcchPath); + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_uri_h */ + diff --git a/include/iprt/utf16.h b/include/iprt/utf16.h new file mode 100644 index 00000000..ed193b1e --- /dev/null +++ b/include/iprt/utf16.h @@ -0,0 +1,1527 @@ +/** @file + * IPRT - String Manipulation, UTF-16 encoding. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_utf16_h +#define IPRT_INCLUDED_utf16_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/string.h> + +RT_C_DECLS_BEGIN + + +/** @defgroup rt_str_utf16 UTF-16 String Manipulation + * @ingroup grp_rt_str + * @{ + */ + +/** + * Allocates memory for UTF-16 string storage (default tag). + * + * You should normally not use this function, except if there is some very + * custom string handling you need doing that isn't covered by any of the other + * APIs. + * + * @returns Pointer to the allocated UTF-16 string. The first wide char is + * always set to the string terminator char, the contents of the + * remainder of the memory is undefined. The string must be freed by + * calling RTUtf16Free. + * + * NULL is returned if the allocation failed. Please translate this to + * VERR_NO_UTF16_MEMORY and not VERR_NO_MEMORY. Also consider + * RTUtf16AllocEx if an IPRT status code is required. + * + * @param cb How many bytes to allocate, will be rounded up + * to a multiple of two. If this is zero, we will + * allocate a terminator wide char anyway. + */ +#define RTUtf16Alloc(cb) RTUtf16AllocTag((cb), RTSTR_TAG) + +/** + * Allocates memory for UTF-16 string storage (custom tag). + * + * You should normally not use this function, except if there is some very + * custom string handling you need doing that isn't covered by any of the other + * APIs. + * + * @returns Pointer to the allocated UTF-16 string. The first wide char is + * always set to the string terminator char, the contents of the + * remainder of the memory is undefined. The string must be freed by + * calling RTUtf16Free. + * + * NULL is returned if the allocation failed. Please translate this to + * VERR_NO_UTF16_MEMORY and not VERR_NO_MEMORY. Also consider + * RTUtf16AllocExTag if an IPRT status code is required. + * + * @param cb How many bytes to allocate, will be rounded up + * to a multiple of two. If this is zero, we will + * allocate a terminator wide char anyway. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(PRTUTF16) RTUtf16AllocTag(size_t cb, const char *pszTag); + +/** + * Reallocates the specified UTF-16 string (default tag). + * + * You should normally not use this function, except if there is some very + * custom string handling you need doing that isn't covered by any of the other + * APIs. + * + * @returns VINF_SUCCESS. + * @retval VERR_NO_UTF16_MEMORY if we failed to reallocate the string, @a + * *ppwsz remains unchanged. + * + * @param ppwsz Pointer to the string variable containing the + * input and output string. + * + * When not freeing the string, the result will + * always have the last RTUTF16 set to the + * terminator character so that when used for + * string truncation the result will be a valid + * C-style string (your job to keep it a valid + * UTF-16 string). + * + * When the input string is NULL and we're supposed + * to reallocate, the returned string will also + * have the first RTUTF16 set to the terminator + * char so it will be a valid C-style string. + * + * @param cbNew When @a cbNew is zero, we'll behave like + * RTUtf16Free and @a *ppwsz will be set to NULL. + * + * When not zero, this will be rounded up to a + * multiple of two, and used as the new size of the + * memory backing the string, i.e. it includes the + * terminator (RTUTF16) char. + */ +#define RTUtf16Realloc(ppwsz, cbNew) RTUtf16ReallocTag((ppwsz), (cbNew), RTSTR_TAG) + +/** + * Reallocates the specified UTF-16 string (custom tag). + * + * You should normally not use this function, except if there is some very + * custom string handling you need doing that isn't covered by any of the other + * APIs. + * + * @returns VINF_SUCCESS. + * @retval VERR_NO_UTF16_MEMORY if we failed to reallocate the string, @a + * *ppwsz remains unchanged. + * + * @param ppwsz Pointer to the string variable containing the + * input and output string. + * + * When not freeing the string, the result will + * always have the last RTUTF16 set to the + * terminator character so that when used for + * string truncation the result will be a valid + * C-style string (your job to keep it a valid + * UTF-16 string). + * + * When the input string is NULL and we're supposed + * to reallocate, the returned string will also + * have the first RTUTF16 set to the terminator + * char so it will be a valid C-style string. + * + * @param cbNew When @a cbNew is zero, we'll behave like + * RTUtf16Free and @a *ppwsz will be set to NULL. + * + * When not zero, this will be rounded up to a + * multiple of two, and used as the new size of the + * memory backing the string, i.e. it includes the + * terminator (RTUTF16) char. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16ReallocTag(PRTUTF16 *ppwsz, size_t cbNew, const char *pszTag); + +/** + * Free a UTF-16 string allocated by RTStrToUtf16(), RTStrToUtf16Ex(), + * RTLatin1ToUtf16(), RTLatin1ToUtf16Ex(), RTUtf16Dup() or RTUtf16DupEx(). + * + * @returns iprt status code. + * @param pwszString The UTF-16 string to free. NULL is accepted. + */ +RTDECL(void) RTUtf16Free(PRTUTF16 pwszString); + +/** + * Allocates a new copy of the specified UTF-16 string (default tag). + * + * @returns Pointer to the allocated string copy. Use RTUtf16Free() to free it. + * @returns NULL when out of memory. + * @param pwszString UTF-16 string to duplicate. + * @remark This function will not make any attempt to validate the encoding. + */ +#define RTUtf16Dup(pwszString) RTUtf16DupTag((pwszString), RTSTR_TAG) + +/** + * Allocates a new copy of the specified UTF-16 string (custom tag). + * + * @returns Pointer to the allocated string copy. Use RTUtf16Free() to free it. + * @returns NULL when out of memory. + * @param pwszString UTF-16 string to duplicate. + * @param pszTag Allocation tag used for statistics and such. + * @remark This function will not make any attempt to validate the encoding. + */ +RTDECL(PRTUTF16) RTUtf16DupTag(PCRTUTF16 pwszString, const char *pszTag); + +/** + * Allocates a new copy of the specified UTF-16 string (default tag). + * + * @returns iprt status code. + * @param ppwszString Receives pointer of the allocated UTF-16 string. + * The returned pointer must be freed using RTUtf16Free(). + * @param pwszString UTF-16 string to duplicate. + * @param cwcExtra Number of extra RTUTF16 items to allocate. + * @remark This function will not make any attempt to validate the encoding. + */ +#define RTUtf16DupEx(ppwszString, pwszString, cwcExtra) \ + RTUtf16DupExTag((ppwszString), (pwszString), (cwcExtra), RTSTR_TAG) + +/** + * Allocates a new copy of the specified UTF-16 string (custom tag). + * + * @returns iprt status code. + * @param ppwszString Receives pointer of the allocated UTF-16 string. + * The returned pointer must be freed using RTUtf16Free(). + * @param pwszString UTF-16 string to duplicate. + * @param cwcExtra Number of extra RTUTF16 items to allocate. + * @param pszTag Allocation tag used for statistics and such. + * @remark This function will not make any attempt to validate the encoding. + */ +RTDECL(int) RTUtf16DupExTag(PRTUTF16 *ppwszString, PCRTUTF16 pwszString, size_t cwcExtra, const char *pszTag); + +/** + * Returns the length of a UTF-16 string in UTF-16 characters + * without trailing '\\0'. + * + * Surrogate pairs counts as two UTF-16 characters here. Use RTUtf16CpCnt() + * to get the exact number of code points in the string. + * + * @returns The number of RTUTF16 items in the string. + * @param pwszString Pointer the UTF-16 string. + * @remark This function will not make any attempt to validate the encoding. + */ +RTDECL(size_t) RTUtf16Len(PCRTUTF16 pwszString); + +/** + * Find the length of a zero-terminated byte string, given a max string length. + * + * @returns The string length or cbMax. The returned length does not include + * the zero terminator if it was found. + * + * @param pwszString The string. + * @param cwcMax The max string length in RTUTF16s. + * @sa RTUtf16NLenEx, RTStrNLen. + */ +RTDECL(size_t) RTUtf16NLen(PCRTUTF16 pwszString, size_t cwcMax); + +/** + * Find the length of a zero-terminated byte string, given + * a max string length. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if the string has a length less than cchMax. + * @retval VERR_BUFFER_OVERFLOW if the end of the string wasn't found + * before cwcMax was reached. + * + * @param pwszString The string. + * @param cwcMax The max string length in RTUTF16s. + * @param pcwc Where to store the string length excluding the + * terminator. This is set to cwcMax if the terminator + * isn't found. + * @sa RTUtf16NLen, RTStrNLenEx. + */ +RTDECL(int) RTUtf16NLenEx(PCRTUTF16 pwszString, size_t cwcMax, size_t *pcwc); + +/** + * Find the zero terminator in a string with a limited length. + * + * @returns Pointer to the zero terminator. + * @returns NULL if the zero terminator was not found. + * + * @param pwszString The string. + * @param cwcMax The max string length. RTSTR_MAX is fine. + */ +RTDECL(PCRTUTF16) RTUtf16End(PCRTUTF16 pwszString, size_t cwcMax); + +/** + * Finds a give UTF-16 character in a UTF-16 string. + * + * @returns Pointer to the first occurence of @a wc. + * @returns NULL if @a wc was not found. + * + * @param pwszString The string to search. + * @param wc The UTF-16 character to search for. + */ +RTDECL(PRTUTF16) RTUtf16Chr(PCRTUTF16 pwszString, RTUTF16 wc); + +/** + * Strips blankspaces from both ends of the string. + * + * @returns Pointer to first non-blank char in the string. + * @param pwsz The string to strip. + */ +RTDECL(PRTUTF16) RTUtf16Strip(PRTUTF16 pwsz); + +/** + * Strips blankspaces from the start of the string. + * + * @returns Pointer to first non-blank char in the string. + * @param pwsz The string to strip. + */ +RTDECL(PRTUTF16) RTUtf16StripL(PCRTUTF16 pwsz); + +/** + * Strips blankspaces from the end of the string. + * + * @returns pwsz. + * @param pwsz The string to strip. + */ +RTDECL(PRTUTF16) RTUtf16StripR(PRTUTF16 pwsz); + +/** + * String copy with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pwszDst The destination buffer. + * @param cwcDst The size of the destination buffer in RTUTF16s. + * @param pwszSrc The source string. NULL is not OK. + */ +RTDECL(int) RTUtf16Copy(PRTUTF16 pwszDst, size_t cwcDst, PCRTUTF16 pwszSrc); + +/** + * String copy with overflow handling, ASCII source. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pwszDst The destination buffer. + * @param cwcDst The size of the destination buffer in RTUTF16s. + * @param pszSrc The source string, pure ASCII. NULL is not OK. + */ +RTDECL(int) RTUtf16CopyAscii(PRTUTF16 pwszDst, size_t cwcDst, const char *pszSrc); + +/** + * String copy with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pwszDst The destination buffer. + * @param cwcDst The size of the destination buffer in RTUTF16s. + * @param pwszSrc The source string. NULL is not OK. + * @param cwcSrcMax The maximum number of chars (not code points) to + * copy from the source string, not counting the + * terminator as usual. + */ +RTDECL(int) RTUtf16CopyEx(PRTUTF16 pwszDst, size_t cwcDst, PCRTUTF16 pwszSrc, size_t cwcSrcMax); + +/** + * String concatenation with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pwszDst The destination buffer. + * @param cwcDst The size of the destination buffer in RTUTF16s. + * @param pwszSrc The source string. NULL is not OK. + */ +RTDECL(int) RTUtf16Cat(PRTUTF16 pwszDst, size_t cwcDst, PCRTUTF16 pwszSrc); + +/** + * String concatenation with overflow handling, ASCII source. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pwszDst The destination buffer. + * @param cwcDst The size of the destination buffer in RTUTF16s. + * @param pszSrc The source string, pure ASCII. NULL is not OK. + */ +RTDECL(int) RTUtf16CatAscii(PRTUTF16 pwszDst, size_t cwcDst, const char *pszSrc); + +/** + * String concatenation with overflow handling. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_BUFFER_OVERFLOW if the destination buffer is too small. The + * buffer will contain as much of the string as it can hold, fully + * terminated. + * + * @param pwszDst The destination buffer. + * @param cwcDst The size of the destination buffer in RTUTF16s. + * @param pwszSrc The source string. NULL is not OK. + * @param cwcSrcMax The maximum number of UTF-16 chars (not code + * points) to copy from the source string, not + * counting the terminator as usual. + */ +RTDECL(int) RTUtf16CatEx(PRTUTF16 pwszDst, size_t cwcDst, PCRTUTF16 pwszSrc, size_t cwcSrcMax); + +/** + * Performs a case sensitive string compare between two UTF-16 strings. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param pwsz2 Second UTF-16 string. Null is allowed. + * @remark This function will not make any attempt to validate the encoding. + */ +RTDECL(int) RTUtf16Cmp(PCRTUTF16 pwsz1, PCRTUTF16 pwsz2); + +/** + * Performs a case sensitive string compare between an UTF-16 string and a pure + * ASCII string. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param psz2 Second string, pure ASCII. Null is allowed. + * @remark This function will not make any attempt to validate the encoding. + */ +RTDECL(int) RTUtf16CmpAscii(PCRTUTF16 pwsz1, const char *psz2); + +/** + * Performs a case sensitive string compare between an UTF-16 string and a UTF-8 + * string. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param psz2 Second string, UTF-8. Null is allowed. + * @remarks NULL and empty strings are treated equally. + */ +RTDECL(int) RTUtf16CmpUtf8(PCRTUTF16 pwsz1, const char *psz2); + + +/** + * Performs a case sensitive and length limited string compare between two UTF-16 strings. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param pwsz2 Second UTF-16 string. Null is allowed. + * @param cwcMax Maximum number of characters (RTUTF16) from the first + * @remark This function will not make any attempt to validate the encoding. + */ +RTDECL(int) RTUtf16NCmp(PCRTUTF16 pwsz1, PCRTUTF16 pwsz2, size_t cwcMax); + +/** + * Performs a case sensitive and length limited string compare between an UTF-16 + * string and a pure ASCII string. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param psz2 Second string, pure ASCII. Null is allowed. + * @param cwcMax Maximum number of characters (RTUTF16) to compare. + * @remark This function will not make any attempt to validate the encoding. + */ +RTDECL(int) RTUtf16NCmpAscii(PCRTUTF16 pwsz1, const char *psz2, size_t cwcMax); + +/** + * Performs a case sensitive and length limited string compare between an UTF-16 + * string and a UTF-8 string. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param psz2 Second string, UTF-8. Null is allowed. + * @param cwcMax1 Maximum number of UTF-16 characters (RTUTF16) from the + * first string to compare. + * @param cchMax2 Maximum number of UTF-8 characters (char) from the + * second string to compare. + * @remarks NULL and empty strings are treated equally. + */ +RTDECL(int) RTUtf16NCmpUtf8(PCRTUTF16 pwsz1, const char *psz2, size_t cwcMax1, size_t cchMax2); + + +/** + * Performs a case insensitive string compare between two UTF-16 strings. + * + * This is a simplified compare, as only the simplified lower/upper case folding + * specified by the unicode specs are used. It does not consider character pairs + * as they are used in some languages, just simple upper & lower case compares. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param pwsz2 Second UTF-16 string. Null is allowed. + */ +RTDECL(int) RTUtf16ICmp(PCRTUTF16 pwsz1, PCRTUTF16 pwsz2); + +/** + * Performs a case insensitive string compare between two big endian UTF-16 + * strings. + * + * This is a simplified compare, as only the simplified lower/upper case folding + * specified by the unicode specs are used. It does not consider character pairs + * as they are used in some languages, just simple upper & lower case compares. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First big endian UTF-16 string. Null is allowed. + * @param pwsz2 Second big endian UTF-16 string. Null is allowed. + */ +RTDECL(int) RTUtf16BigICmp(PCRTUTF16 pwsz1, PCRTUTF16 pwsz2); + +/** + * Performs a case insensitive string compare between an UTF-16 string and a + * UTF-8 string. + * + * @returns < 0 if the first string less than the second string.s + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param psz2 Second string, UTF-8. Null is allowed. + * @remarks NULL and empty strings are treated equally. + */ +RTDECL(int) RTUtf16ICmpUtf8(PCRTUTF16 pwsz1, const char *psz2); + +/** + * Performs a case insensitive string compare between an UTF-16 string and a + * pure ASCII string. + * + * Since this compare only takes cares about the first 128 codepoints in + * unicode, no tables are needed and there aren't any real complications. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param psz2 Second string, pure ASCII. Null is allowed. + */ +RTDECL(int) RTUtf16ICmpAscii(PCRTUTF16 pwsz1, const char *psz2); + +/** + * Performs a case insensitive string compare between two UTF-16 strings + * using the current locale of the process (if applicable). + * + * This differs from RTUtf16ICmp() in that it will try, if a locale with the + * required data is available, to do a correct case-insensitive compare. It + * follows that it is more complex and thereby likely to be more expensive. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param pwsz2 Second UTF-16 string. Null is allowed. + */ +RTDECL(int) RTUtf16LocaleICmp(PCRTUTF16 pwsz1, PCRTUTF16 pwsz2); + +/** + * Performs a case insensitive string compare between two UTF-16 strings, + * stopping after N characters. + * + * This is a simplified compare, as only the simplified lower/upper case folding + * specified by the unicode specs are used. It does not consider character pairs + * as they are used in some languages, just simple upper & lower case compares. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First UTF-16 string. Null is allowed. + * @param pwsz2 Second UTF-16 string. Null is allowed. + * @param cwcMax Maximum number of characters to compare. + */ +RTDECL(int) RTUtf16NICmp(PCRTUTF16 pwsz1, PCRTUTF16 pwsz2, size_t cwcMax); + +/** + * Performs a case insensitive string compare between two big endian UTF-16 + * strings, stopping after N characters. + * + * This is a simplified compare, as only the simplified lower/upper case folding + * specified by the unicode specs are used. It does not consider character pairs + * as they are used in some languages, just simple upper & lower case compares. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 First big endian UTF-16 string. Null is allowed. + * @param pwsz2 Second big endian UTF-16 string. Null is allowed. + * @param cwcMax Maximum number of characters to compare. + */ +RTDECL(int) RTUtf16BigNICmp(PCRTUTF16 pwsz1, PCRTUTF16 pwsz2, size_t cwcMax); + +/** + * Performs a case insensitive string compare between a UTF-16 string and a pure + * ASCII string, stopping after N characters. + * + * Since this compare only takes cares about the first 128 codepoints in + * unicode, no tables are needed and there aren't any real complications. + * + * @returns < 0 if the first string less than the second string. + * @returns 0 if the first string identical to the second string. + * @returns > 0 if the first string greater than the second string. + * @param pwsz1 The UTF-16 first string. Null is allowed. + * @param psz2 The pure ASCII second string. Null is allowed. + * @param cwcMax Maximum number of UTF-16 characters to compare. + */ +RTDECL(int) RTUtf16NICmpAscii(PCRTUTF16 pwsz1, const char *psz2, size_t cwcMax); + + +/** + * Locates a substring, ascii version. + * + * @returns Offset into @a pwszString of the substring if found, -1 if not. + * @param pwszString The UTF-16 to search. NULL is allowed (no match). + * @param pszSubStr The pure ASCII substring to locate. NULL is allowed (not + * matching anything, just like an empty string). + */ +RTDECL(ssize_t) RTUtf16FindAscii(PCRTUTF16 pwszString, const char *pszSubStr); + + +/** + * Folds a UTF-16 string to lowercase. + * + * This is a very simple folding; is uses the simple lowercase + * code point, it is not related to any locale just the most common + * lowercase codepoint setup by the unicode specs, and it will not + * create new surrogate pairs or remove existing ones. + * + * @returns Pointer to the passed in string. + * @param pwsz The string to fold. + */ +RTDECL(PRTUTF16) RTUtf16ToLower(PRTUTF16 pwsz); + +/** + * Folds a UTF-16 string to uppercase. + * + * This is a very simple folding; is uses the simple uppercase + * code point, it is not related to any locale just the most common + * uppercase codepoint setup by the unicode specs, and it will not + * create new surrogate pairs or remove existing ones. + * + * @returns Pointer to the passed in string. + * @param pwsz The string to fold. + */ +RTDECL(PRTUTF16) RTUtf16ToUpper(PRTUTF16 pwsz); + +/** + * Validates the UTF-16 encoding of the string. + * + * @returns iprt status code. + * @param pwsz The string. + */ +RTDECL(int) RTUtf16ValidateEncoding(PCRTUTF16 pwsz); + +/** + * Validates the UTF-16 encoding of the string. + * + * @returns iprt status code. + * @param pwsz The string. + * @param cwc The max string length (/ size) in UTF-16 units. Use + * RTSTR_MAX to process the entire string. + * @param fFlags Combination of RTSTR_VALIDATE_ENCODING_XXX flags. + */ +RTDECL(int) RTUtf16ValidateEncodingEx(PCRTUTF16 pwsz, size_t cwc, uint32_t fFlags); + +/** + * Checks if the UTF-16 encoding is valid. + * + * @returns true / false. + * @param pwsz The string. + */ +RTDECL(bool) RTUtf16IsValidEncoding(PCRTUTF16 pwsz); + +/** + * Sanitise a (valid) UTF-16 string by replacing all characters outside a white + * list in-place by an ASCII replacement character. + * + * Surrogate paris will be replaced by two chars. + * + * @returns The number of code points replaced. In the case of an incorrectly + * encoded string -1 will be returned, and the string is not completely + * processed. In the case of puszValidPairs having an odd number of + * code points, -1 will be also return but without any modification to + * the string. + * @param pwsz The string to sanitise. + * @param puszValidPairs A zero-terminated array of pairs of Unicode points. + * Each pair is the start and end point of a range, + * and the union of these ranges forms the white list. + * @param chReplacement The ASCII replacement character. + * @sa RTStrPurgeComplementSet + */ +RTDECL(ssize_t) RTUtf16PurgeComplementSet(PRTUTF16 pwsz, PCRTUNICP puszValidPairs, char chReplacement); + + +/** + * Translate a UTF-16 string into a UTF-8 allocating the result buffer (default + * tag). + * + * @returns iprt status code. + * @param pwszString UTF-16 string to convert. + * @param ppszString Receives pointer of allocated UTF-8 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + */ +#define RTUtf16ToUtf8(pwszString, ppszString) RTUtf16ToUtf8Tag((pwszString), (ppszString), RTSTR_TAG) + +/** + * Translate a UTF-16 string into a UTF-8 allocating the result buffer. + * + * @returns iprt status code. + * @param pwszString UTF-16 string to convert. + * @param ppszString Receives pointer of allocated UTF-8 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16ToUtf8Tag(PCRTUTF16 pwszString, char **ppszString, const char *pszTag); + +/** + * Translate a UTF-16BE string into a UTF-8 allocating the result buffer + * (default tag). + * + * This differs from RTUtf16ToUtf8 in that the input is always a + * big-endian string. + * + * @returns iprt status code. + * @param pwszString UTF-16BE string to convert. + * @param ppszString Receives pointer of allocated UTF-8 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + */ +#define RTUtf16BigToUtf8(pwszString, ppszString) RTUtf16BigToUtf8Tag((pwszString), (ppszString), RTSTR_TAG) + +/** + * Translate a UTF-16BE string into a UTF-8 allocating the result buffer. + * + * This differs from RTUtf16ToUtf8Tag in that the input is always a + * big-endian string. + * + * @returns iprt status code. + * @param pwszString UTF-16BE string to convert. + * @param ppszString Receives pointer of allocated UTF-8 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16BigToUtf8Tag(PCRTUTF16 pwszString, char **ppszString, const char *pszTag); + +/** + * Translate a UTF-16LE string into a UTF-8 allocating the result buffer + * (default tag). + * + * This differs from RTUtf16ToUtf8 in that the input is always a + * little-endian string. + * + * @returns iprt status code. + * @param pwszString UTF-16LE string to convert. + * @param ppszString Receives pointer of allocated UTF-8 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + */ +#define RTUtf16LittleToUtf8(pwszString, ppszString) RTUtf16LittleToUtf8Tag((pwszString), (ppszString), RTSTR_TAG) + +/** + * Translate a UTF-16LE string into a UTF-8 allocating the result buffer. + * + * This differs from RTUtf16ToUtf8Tag in that the input is always a + * little-endian string. + * + * @returns iprt status code. + * @param pwszString UTF-16LE string to convert. + * @param ppszString Receives pointer of allocated UTF-8 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16LittleToUtf8Tag(PCRTUTF16 pwszString, char **ppszString, const char *pszTag); + + +/** + * Translates UTF-16 to UTF-8 using buffer provided by the caller or a fittingly + * sized buffer allocated by the function (default tag). + * + * @returns iprt status code. + * @param pwszString The UTF-16 string to convert. + * @param cwcString The number of RTUTF16 items to translate from pwszString. + * The translation will stop when reaching cwcString or the terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to a pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppsz is NULL or cch is zero a buffer of at least cch chars + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTStrFree(). + * @param cch The buffer size in chars (the type). This includes the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTUtf16ToUtf8Ex(pwszString, cwcString, ppsz, cch, pcch) \ + RTUtf16ToUtf8ExTag((pwszString), (cwcString), (ppsz), (cch), (pcch), RTSTR_TAG) + +/** + * Translates UTF-16 to UTF-8 using buffer provided by the caller or a fittingly + * sized buffer allocated by the function (custom tag). + * + * @returns iprt status code. + * @param pwszString The UTF-16 string to convert. + * @param cwcString The number of RTUTF16 items to translate from pwszString. + * The translation will stop when reaching cwcString or the terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to a pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppsz is NULL or cch is zero a buffer of at least cch chars + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTStrFree(). + * @param cch The buffer size in chars (the type). This includes the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16ToUtf8ExTag(PCRTUTF16 pwszString, size_t cwcString, char **ppsz, size_t cch, size_t *pcch, const char *pszTag); + +/** + * Translates UTF-16BE to UTF-8 using buffer provided by the caller or a + * fittingly sized buffer allocated by the function (default tag). + * + * This differs from RTUtf16ToUtf8Ex in that the input is always a + * big-endian string. + * + * @returns iprt status code. + * @param pwszString The UTF-16BE string to convert. + * @param cwcString The number of RTUTF16 items to translate from pwszString. + * The translation will stop when reaching cwcString or the terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to a pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppsz is NULL or cch is zero a buffer of at least cch chars + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTStrFree(). + * @param cch The buffer size in chars (the type). This includes the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTUtf16BigToUtf8Ex(pwszString, cwcString, ppsz, cch, pcch) \ + RTUtf16BigToUtf8ExTag((pwszString), (cwcString), (ppsz), (cch), (pcch), RTSTR_TAG) + +/** + * Translates UTF-16BE to UTF-8 using buffer provided by the caller or a + * fittingly sized buffer allocated by the function (custom tag). + * + * This differs from RTUtf16ToUtf8ExTag in that the input is always a + * big-endian string. + * + * @returns iprt status code. + * @param pwszString The UTF-16BE string to convert. + * @param cwcString The number of RTUTF16 items to translate from pwszString. + * The translation will stop when reaching cwcString or the terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to a pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppsz is NULL or cch is zero a buffer of at least cch chars + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTStrFree(). + * @param cch The buffer size in chars (the type). This includes the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16BigToUtf8ExTag(PCRTUTF16 pwszString, size_t cwcString, char **ppsz, size_t cch, size_t *pcch, const char *pszTag); + +/** + * Translates UTF-16LE to UTF-8 using buffer provided by the caller or a + * fittingly sized buffer allocated by the function (default tag). + * + * This differs from RTUtf16ToUtf8Ex in that the input is always a + * little-endian string. + * + * @returns iprt status code. + * @param pwszString The UTF-16LE string to convert. + * @param cwcString The number of RTUTF16 items to translate from pwszString. + * The translation will stop when reaching cwcString or the terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to a pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppsz is NULL or cch is zero a buffer of at least cch chars + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTStrFree(). + * @param cch The buffer size in chars (the type). This includes the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTUtf16LittleToUtf8Ex(pwszString, cwcString, ppsz, cch, pcch) \ + RTUtf16LittleToUtf8ExTag((pwszString), (cwcString), (ppsz), (cch), (pcch), RTSTR_TAG) + +/** + * Translates UTF-16LE to UTF-8 using buffer provided by the caller or a + * fittingly sized buffer allocated by the function (custom tag). + * + * This differs from RTUtf16ToUtf8ExTag in that the input is always a + * little-endian string. + * + * @returns iprt status code. + * @param pwszString The UTF-16LE string to convert. + * @param cwcString The number of RTUTF16 items to translate from pwszString. + * The translation will stop when reaching cwcString or the terminator ('\\0'). + * Use RTSTR_MAX to translate the entire string. + * @param ppsz If cch is non-zero, this must either be pointing to a pointer to + * a buffer of the specified size, or pointer to a NULL pointer. + * If *ppsz is NULL or cch is zero a buffer of at least cch chars + * will be allocated to hold the translated string. + * If a buffer was requested it must be freed using RTStrFree(). + * @param cch The buffer size in chars (the type). This includes the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16LittleToUtf8ExTag(PCRTUTF16 pwszString, size_t cwcString, char **ppsz, size_t cch, size_t *pcch, + const char *pszTag); + +/** + * Calculates the length of the UTF-16 string in UTF-8 chars (bytes). + * + * This function will validate the string, and incorrectly encoded UTF-16 + * strings will be rejected. The primary purpose of this function is to + * help allocate buffers for RTUtf16ToUtf8() of the correct size. For most + * other purposes RTUtf16ToUtf8Ex() should be used. + * + * @returns Number of char (bytes). + * @returns 0 if the string was incorrectly encoded. + * @param pwsz The UTF-16 string. + */ +RTDECL(size_t) RTUtf16CalcUtf8Len(PCRTUTF16 pwsz); + +/** + * Calculates the length of the UTF-16BE string in UTF-8 chars (bytes). + * + * This function will validate the string, and incorrectly encoded UTF-16BE + * strings will be rejected. The primary purpose of this function is to + * help allocate buffers for RTUtf16BigToUtf8() of the correct size. For most + * other purposes RTUtf16BigToUtf8Ex() should be used. + * + * @returns Number of char (bytes). + * @returns 0 if the string was incorrectly encoded. + * @param pwsz The UTF-16BE string. + */ +RTDECL(size_t) RTUtf16BigCalcUtf8Len(PCRTUTF16 pwsz); + +/** + * Calculates the length of the UTF-16LE string in UTF-8 chars (bytes). + * + * This function will validate the string, and incorrectly encoded UTF-16LE + * strings will be rejected. The primary purpose of this function is to + * help allocate buffers for RTUtf16LittleToUtf8() of the correct size. For + * most other purposes RTUtf16LittleToUtf8Ex() should be used. + * + * @returns Number of char (bytes). + * @returns 0 if the string was incorrectly encoded. + * @param pwsz The UTF-16LE string. + */ +RTDECL(size_t) RTUtf16LittleCalcUtf8Len(PCRTUTF16 pwsz); + +/** + * Calculates the length of the UTF-16 string in UTF-8 chars (bytes). + * + * This function will validate the string, and incorrectly encoded UTF-16 + * strings will be rejected. + * + * @returns iprt status code. + * @param pwsz The string. + * @param cwc The max string length. Use RTSTR_MAX to process the entire string. + * @param pcch Where to store the string length (in bytes). Optional. + * This is undefined on failure. + */ +RTDECL(int) RTUtf16CalcUtf8LenEx(PCRTUTF16 pwsz, size_t cwc, size_t *pcch); + +/** + * Calculates the length of the UTF-16BE string in UTF-8 chars (bytes). + * + * This function will validate the string, and incorrectly encoded UTF-16BE + * strings will be rejected. + * + * @returns iprt status code. + * @param pwsz The string. + * @param cwc The max string length. Use RTSTR_MAX to process the entire string. + * @param pcch Where to store the string length (in bytes). Optional. + * This is undefined on failure. + */ +RTDECL(int) RTUtf16BigCalcUtf8LenEx(PCRTUTF16 pwsz, size_t cwc, size_t *pcch); + +/** + * Calculates the length of the UTF-16LE string in UTF-8 chars (bytes). + * + * This function will validate the string, and incorrectly encoded UTF-16LE + * strings will be rejected. + * + * @returns iprt status code. + * @param pwsz The string. + * @param cwc The max string length. Use RTSTR_MAX to process the entire string. + * @param pcch Where to store the string length (in bytes). Optional. + * This is undefined on failure. + */ +RTDECL(int) RTUtf16LittleCalcUtf8LenEx(PCRTUTF16 pwsz, size_t cwc, size_t *pcch); + +/** + * Translate a UTF-16 string into a Latin-1 (ISO-8859-1) allocating the result + * buffer (default tag). + * + * @returns iprt status code. + * @param pwszString UTF-16 string to convert. + * @param ppszString Receives pointer of allocated Latin1 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + */ +#define RTUtf16ToLatin1(pwszString, ppszString) RTUtf16ToLatin1Tag((pwszString), (ppszString), RTSTR_TAG) + +/** + * Translate a UTF-16 string into a Latin-1 (ISO-8859-1) allocating the result + * buffer (custom tag). + * + * @returns iprt status code. + * @param pwszString UTF-16 string to convert. + * @param ppszString Receives pointer of allocated Latin1 string on + * success, and is always set to NULL on failure. + * The returned pointer must be freed using RTStrFree(). + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16ToLatin1Tag(PCRTUTF16 pwszString, char **ppszString, const char *pszTag); + +/** + * Translates UTF-16 to Latin-1 (ISO-8859-1) using buffer provided by the caller + * or a fittingly sized buffer allocated by the function (default tag). + * + * @returns iprt status code. + * @param pwszString The UTF-16 string to convert. + * @param cwcString The number of RTUTF16 items to translate from + * pwszString. The translation will stop when reaching + * cwcString or the terminator ('\\0'). Use RTSTR_MAX + * to translate the entire string. + * @param ppsz Pointer to the pointer to the Latin-1 string. The + * buffer can optionally be preallocated by the caller. + * + * If cch is zero, *ppsz is undefined. + * + * If cch is non-zero and *ppsz is not NULL, then this + * will be used as the output buffer. + * VERR_BUFFER_OVERFLOW will be returned if this is + * insufficient. + * + * If cch is zero or *ppsz is NULL, then a buffer of + * sufficient size is allocated. cch can be used to + * specify a minimum size of this buffer. Use + * RTUtf16Free() to free the result. + * + * @param cch The buffer size in chars (the type). This includes + * the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + */ +#define RTUtf16ToLatin1Ex(pwszString, cwcString, ppsz, cch, pcch) \ + RTUtf16ToLatin1ExTag((pwszString), (cwcString), (ppsz), (cch), (pcch), RTSTR_TAG) + +/** + * Translates UTF-16 to Latin-1 (ISO-8859-1) using buffer provided by the caller + * or a fittingly sized buffer allocated by the function (custom tag). + * + * @returns iprt status code. + * @param pwszString The UTF-16 string to convert. + * @param cwcString The number of RTUTF16 items to translate from + * pwszString. The translation will stop when reaching + * cwcString or the terminator ('\\0'). Use RTSTR_MAX + * to translate the entire string. + * @param ppsz Pointer to the pointer to the Latin-1 string. The + * buffer can optionally be preallocated by the caller. + * + * If cch is zero, *ppsz is undefined. + * + * If cch is non-zero and *ppsz is not NULL, then this + * will be used as the output buffer. + * VERR_BUFFER_OVERFLOW will be returned if this is + * insufficient. + * + * If cch is zero or *ppsz is NULL, then a buffer of + * sufficient size is allocated. cch can be used to + * specify a minimum size of this buffer. Use + * RTUtf16Free() to free the result. + * + * @param cch The buffer size in chars (the type). This includes + * the terminator. + * @param pcch Where to store the length of the translated string, + * excluding the terminator. (Optional) + * + * This may be set under some error conditions, + * however, only for VERR_BUFFER_OVERFLOW and + * VERR_NO_STR_MEMORY will it contain a valid string + * length that can be used to resize the buffer. + * @param pszTag Allocation tag used for statistics and such. + */ +RTDECL(int) RTUtf16ToLatin1ExTag(PCRTUTF16 pwszString, size_t cwcString, char **ppsz, size_t cch, size_t *pcch, const char *pszTag); + +/** + * Calculates the length of the UTF-16 string in Latin-1 (ISO-8859-1) chars. + * + * This function will validate the string, and incorrectly encoded UTF-16 + * strings will be rejected. The primary purpose of this function is to + * help allocate buffers for RTUtf16ToLatin1() of the correct size. For most + * other purposes RTUtf16ToLatin1Ex() should be used. + * + * @returns Number of char (bytes). + * @returns 0 if the string was incorrectly encoded. + * @param pwsz The UTF-16 string. + */ +RTDECL(size_t) RTUtf16CalcLatin1Len(PCRTUTF16 pwsz); + +/** + * Calculates the length of the UTF-16 string in Latin-1 (ISO-8859-1) chars. + * + * This function will validate the string, and incorrectly encoded UTF-16 + * strings will be rejected. + * + * @returns iprt status code. + * @param pwsz The string. + * @param cwc The max string length. Use RTSTR_MAX to process the + * entire string. + * @param pcch Where to store the string length (in bytes). Optional. + * This is undefined on failure. + */ +RTDECL(int) RTUtf16CalcLatin1LenEx(PCRTUTF16 pwsz, size_t cwc, size_t *pcch); + +/** + * Get the unicode code point at the given string position. + * + * @returns unicode code point. + * @returns RTUNICP_INVALID if the encoding is invalid. + * @param pwsz The string. + * + * @remark This is an internal worker for RTUtf16GetCp(). + */ +RTDECL(RTUNICP) RTUtf16GetCpInternal(PCRTUTF16 pwsz); + +/** + * Get the unicode code point at the given string position. + * + * @returns iprt status code. + * @param ppwsz Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * @param pCp Where to store the code point. + * RTUNICP_INVALID is stored here on failure. + * + * @remark This is an internal worker for RTUtf16GetCpEx(). + */ +RTDECL(int) RTUtf16GetCpExInternal(PCRTUTF16 *ppwsz, PRTUNICP pCp); + +/** + * Get the unicode code point at the given string position with length + * restriction. + * + * @returns iprt status code. + * @param ppwsz Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * @param pcwc Pointer to the max string length. This will be + * decremented corrsponding to the advancement of @a ppwsz. + * @param pCp Where to store the code point. + * RTUNICP_INVALID is stored here on failure. + * + * @remark This is an internal worker for RTUtf16GetCpNEx(). + */ +RTDECL(int) RTUtf16GetCpNExInternal(PCRTUTF16 *ppwsz, size_t *pcwc, PRTUNICP pCp); + +/** + * Get the unicode code point at the given string position, big endian. + * + * @returns iprt status code. + * @param ppwsz Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * @param pCp Where to store the code point. + * RTUNICP_INVALID is stored here on failure. + * + * @remark This is an internal worker for RTUtf16BigGetCpEx(). + */ +RTDECL(int) RTUtf16BigGetCpExInternal(PCRTUTF16 *ppwsz, PRTUNICP pCp); + +/** + * Put the unicode code point at the given string position + * and return the pointer to the char following it. + * + * This function will not consider anything at or following the + * buffer area pointed to by pwsz. It is therefore not suitable for + * inserting code points into a string, only appending/overwriting. + * + * @returns pointer to the char following the written code point. + * @param pwsz The string. + * @param CodePoint The code point to write. + * This should not be RTUNICP_INVALID or any other + * character out of the UTF-16 range. + * + * @remark This is an internal worker for RTUtf16GetCpEx(). + */ +RTDECL(PRTUTF16) RTUtf16PutCpInternal(PRTUTF16 pwsz, RTUNICP CodePoint); + +/** + * Get the unicode code point at the given string position. + * + * @returns unicode code point. + * @returns RTUNICP_INVALID if the encoding is invalid. + * @param pwsz The string. + * + * @remark We optimize this operation by using an inline function for + * everything which isn't a surrogate pair or an endian indicator. + */ +DECLINLINE(RTUNICP) RTUtf16GetCp(PCRTUTF16 pwsz) +{ + const RTUTF16 wc = *pwsz; + if (wc < 0xd800 || (wc > 0xdfff && wc < 0xfffe)) + return wc; + return RTUtf16GetCpInternal(pwsz); +} + +/** + * Get the unicode code point at the given string position. + * + * @returns iprt status code. + * @param ppwsz Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * @param pCp Where to store the code point. + * RTUNICP_INVALID is stored here on failure. + * + * @remark We optimize this operation by using an inline function for + * everything which isn't a surrogate pair or and endian indicator. + */ +DECLINLINE(int) RTUtf16GetCpEx(PCRTUTF16 *ppwsz, PRTUNICP pCp) +{ + const RTUTF16 wc = **ppwsz; + if (wc < 0xd800 || (wc > 0xdfff && wc < 0xfffe)) + { + (*ppwsz)++; + *pCp = wc; + return VINF_SUCCESS; + } + return RTUtf16GetCpExInternal(ppwsz, pCp); +} + +/** + * Get the unicode code point at the given string position. + * + * @returns iprt status code. + * @param ppwsz Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * @param pcwc Pointer to the max string length. This will be + * decremented corrsponding to the advancement of @a ppwsz. + * @param pCp Where to store the code point. RTUNICP_INVALID is stored + * here on failure. + * + * @remark We optimize this operation by using an inline function for + * everything which isn't a surrogate pair or and endian indicator. + */ +DECLINLINE(int) RTUtf16GetCpNEx(PCRTUTF16 *ppwsz, size_t *pcwc, PRTUNICP pCp) +{ + const size_t cwc = *pcwc; + if (cwc > 0) + { + const PCRTUTF16 pwsz = *ppwsz; + const RTUTF16 wc = *pwsz; + if (wc < 0xd800 || (wc > 0xdfff && wc < 0xfffe)) + { + *pCp = wc; + *pcwc = cwc - 1; + *ppwsz = pwsz + 1; + return VINF_SUCCESS; + } + } + return RTUtf16GetCpNExInternal(ppwsz, pcwc, pCp); +} + +/** + * Get the unicode code point at the given string position, big endian version. + * + * @returns iprt status code. + * @param ppwsz Pointer to the string pointer. This will be updated to + * point to the char following the current code point. + * @param pCp Where to store the code point. + * RTUNICP_INVALID is stored here on failure. + * + * @remark We optimize this operation by using an inline function for + * everything which isn't a surrogate pair or and endian indicator. + */ +DECLINLINE(int) RTUtf16BigGetCpEx(PCRTUTF16 *ppwsz, PRTUNICP pCp) +{ +#ifdef RT_BIG_ENDIAN + return RTUtf16GetCpEx(ppwsz, pCp); +#else +# ifdef IPRT_INCLUDED_asm_h + const RTUTF16 wc = RT_BE2H_U16(**ppwsz); + if (wc < 0xd800 || (wc > 0xdfff && wc < 0xfffe)) + { + (*ppwsz)++; + *pCp = wc; + return VINF_SUCCESS; + } +# endif + return RTUtf16BigGetCpExInternal(ppwsz, pCp); +#endif +} + +/** + * Put the unicode code point at the given string position + * and return the pointer to the char following it. + * + * This function will not consider anything at or following the + * buffer area pointed to by pwsz. It is therefore not suitable for + * inserting code points into a string, only appending/overwriting. + * + * @returns pointer to the char following the written code point. + * @param pwsz The string. + * @param CodePoint The code point to write. + * This should not be RTUNICP_INVALID or any other + * character out of the UTF-16 range. + * + * @remark We optimize this operation by using an inline function for + * everything which isn't a surrogate pair or and endian indicator. + */ +DECLINLINE(PRTUTF16) RTUtf16PutCp(PRTUTF16 pwsz, RTUNICP CodePoint) +{ + if (CodePoint < 0xd800 || (CodePoint > 0xd800 && CodePoint < 0xfffe)) + { + *pwsz++ = (RTUTF16)CodePoint; + return pwsz; + } + return RTUtf16PutCpInternal(pwsz, CodePoint); +} + +/** + * Skips ahead, past the current code point. + * + * @returns Pointer to the char after the current code point. + * @param pwsz Pointer to the current code point. + * @remark This will not move the next valid code point, only past the current one. + */ +DECLINLINE(PRTUTF16) RTUtf16NextCp(PCRTUTF16 pwsz) +{ + RTUNICP Cp; + RTUtf16GetCpEx(&pwsz, &Cp); + return (PRTUTF16)pwsz; +} + +/** + * Skips backwards, to the previous code point. + * + * @returns Pointer to the char after the current code point. + * @param pwszStart Pointer to the start of the string. + * @param pwsz Pointer to the current code point. + */ +RTDECL(PRTUTF16) RTUtf16PrevCp(PCRTUTF16 pwszStart, PCRTUTF16 pwsz); + + +/** + * Checks if the UTF-16 char is the high surrogate char (i.e. + * the 1st char in the pair). + * + * @returns true if it is. + * @returns false if it isn't. + * @param wc The character to investigate. + */ +DECLINLINE(bool) RTUtf16IsHighSurrogate(RTUTF16 wc) +{ + return wc >= 0xd800 && wc <= 0xdbff; +} + +/** + * Checks if the UTF-16 char is the low surrogate char (i.e. + * the 2nd char in the pair). + * + * @returns true if it is. + * @returns false if it isn't. + * @param wc The character to investigate. + */ +DECLINLINE(bool) RTUtf16IsLowSurrogate(RTUTF16 wc) +{ + return wc >= 0xdc00 && wc <= 0xdfff; +} + + +/** + * Checks if the two UTF-16 chars form a valid surrogate pair. + * + * @returns true if they do. + * @returns false if they doesn't. + * @param wcHigh The high (1st) character. + * @param wcLow The low (2nd) character. + */ +DECLINLINE(bool) RTUtf16IsSurrogatePair(RTUTF16 wcHigh, RTUTF16 wcLow) +{ + return RTUtf16IsHighSurrogate(wcHigh) + && RTUtf16IsLowSurrogate(wcLow); +} + +/** + * Formats a buffer stream as hex bytes. + * + * The default is no separating spaces or line breaks or anything. + * + * @returns IPRT status code. + * @retval VERR_INVALID_POINTER if any of the pointers are wrong. + * @retval VERR_BUFFER_OVERFLOW if the buffer is insufficent to hold the bytes. + * + * @param pwszBuf Output string buffer. + * @param cwcBuf The size of the output buffer in RTUTF16 units. + * @param pv Pointer to the bytes to stringify. + * @param cb The number of bytes to stringify. + * @param fFlags Combination of RTSTRPRINTHEXBYTES_F_XXX values. + * @sa RTStrPrintHexBytes. + */ +RTDECL(int) RTUtf16PrintHexBytes(PRTUTF16 pwszBuf, size_t cwcBuf, void const *pv, size_t cb, uint32_t fFlags); + +/** + * String printf producing UTF-16 output. + * + * @returns On success, positive count of formatted RTUTF16 units excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator) in RTUTF16 units. + * + * @param pwszBuffer Output buffer. + * @param cwcBuffer Size of the output buffer in RTUTF16 units. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + * + * @note This is similar to RTStrPrintf2V (not RTStrPrintfV)! + */ +RTDECL(ssize_t) RTUtf16PrintfV(PRTUTF16 pwszBuffer, size_t cwcBuffer, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(3, 0); + +/** + * String printf producing UTF-16 output. + * + * @returns On success, positive count of formatted RTUTF16 units excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator) in RTUTF16 units. + * + * @param pwszBuffer Output buffer. + * @param cwcBuffer Size of the output buffer in RTUTF16 units. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + * + * @note This is similar to RTStrPrintf2 (not RTStrPrintf)! + */ +RTDECL(ssize_t) RTUtf16Printf(PRTUTF16 pwszBuffer, size_t cwcBuffer, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); + +/** + * String printf producing UTF-16 output with custom formatting. + * + * @returns On success, positive count of formatted RTUTF16 units excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator) in RTUTF16 units. + * + * @param pfnFormat Pointer to handler function for the custom formats. + * @param pvArg Argument to the pfnFormat function. + * @param pwszBuffer Output buffer. + * @param cwcBuffer Size of the output buffer in RTUTF16 units. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param args The format argument. + * + * @note This is similar to RTStrPrintf2ExV (not RTStrPrintfExV)! + */ +RTDECL(ssize_t) RTUtf16PrintfExV(PFNSTRFORMAT pfnFormat, void *pvArg, PRTUTF16 pwszBuffer, size_t cwcBuffer, + const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(5, 0); + +/** + * String printf producing UTF-16 output with custom formatting. + * + * @returns On success, positive count of formatted RTUTF16 units excluding the + * terminator. On buffer overflow, negative number giving the required + * buffer size (including terminator) in RTUTF16 units. + * + * @param pfnFormat Pointer to handler function for the custom formats. + * @param pvArg Argument to the pfnFormat function. + * @param pwszBuffer Output buffer. + * @param cwcBuffer Size of the output buffer in RTUTF16 units. + * @param pszFormat Pointer to the format string, @see pg_rt_str_format. + * @param ... The format argument. + * + * @note This is similar to RTStrPrintf2Ex (not RTStrPrintfEx)! + */ +RTDECL(ssize_t) RTUtf16PrintfEx(PFNSTRFORMAT pfnFormat, void *pvArg, PRTUTF16 pwszBuffer, size_t cwcBuffer, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6); + +/** @} */ +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_utf16_h */ + diff --git a/include/iprt/uuid.h b/include/iprt/uuid.h new file mode 100644 index 00000000..3c95a641 --- /dev/null +++ b/include/iprt/uuid.h @@ -0,0 +1,198 @@ +/** @file + * IPRT - Universal Unique Identifiers (UUID). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_uuid_h +#define IPRT_INCLUDED_uuid_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_uuid RTUuid - Universally Unique Identifiers + * @ingroup grp_rt + * @{ + */ + +/** + * Generates new UUID value. + * + * @note IPRT uses little endian byte ordering in the UUID integer fields. If + * you want to pass IPRT UUIDs in binary representation to other UUID libraries + * and expect to get exactly the same string representation as in IPRT, you + * need to convert the first three integer fields (one 32 bit value, two 16 bit + * values) separately to big endian (also called network byte order). + * + * @sa RTUUID::Gen + * + * @returns iprt status code. + * @param pUuid Where to store generated uuid. + */ +RTDECL(int) RTUuidCreate(PRTUUID pUuid); + +/** + * Makes null UUID value. + * + * @returns iprt status code. + * @param pUuid Where to store generated null uuid. + */ +RTDECL(int) RTUuidClear(PRTUUID pUuid); + +/** + * Checks if UUID is null. + * + * @returns true if UUID is null. + * @param pUuid uuid to check. + */ +RTDECL(bool) RTUuidIsNull(PCRTUUID pUuid); + +/** + * Compares two UUID values. + * + * @returns 0 if eq, < 0 or > 0. + * @param pUuid1 First value to compare. NULL is treated like if + * RTUuidIsNull() return true. + * @param pUuid2 Second value to compare. NULL is treated like if + * RTUuidIsNull() return true. + */ +RTDECL(int) RTUuidCompare(PCRTUUID pUuid1, PCRTUUID pUuid2); + +/** + * Compares a UUID value with a UUID string. + * + * @note IPRT uses little endian byte ordering in the UUID integer fields. If + * you want to pass IPRT UUIDs in binary representation to other UUID libraries + * and expect to get exactly the same string representation as in IPRT, you need + * to convert the first three integer fields (one 32 bit value, two 16 bit + * values) separately to big endian (also called network byte order). + * Correspondingly, if you want to get the right result with UUIDs which are in + * big endian format, you need to convert them before using this function. + * + * @sa RTUUID::Gen + * + * @returns 0 if eq, < 0 or > 0. + * @param pUuid1 First value to compare. NULL is not allowed. + * @param pszString2 The 2nd UUID in string form. NULL or malformed + * string is not permitted. + */ +RTDECL(int) RTUuidCompareStr(PCRTUUID pUuid1, const char *pszString2); + +/** + * Compares two UUID strings. + * + * @returns 0 if eq, < 0 or > 0. + * @param pszString1 The 1st UUID in string from. NULL or malformed + * string is not permitted. + * @param pszString2 The 2nd UUID in string form. NULL or malformed + * string is not permitted. + */ +RTDECL(int) RTUuidCompare2Strs(const char *pszString1, const char *pszString2); + +/** + * Converts binary UUID to its string representation. + * + * @note IPRT uses little endian byte ordering in the UUID integer fields. If + * you want to pass IPRT UUIDs in binary representation to other UUID libraries + * and expect to get exactly the same string representation as in IPRT, you + * need to convert the first three integer fields (one 32 bit value, two 16 bit + * values) separately to big endian (also called network byte order). + * Correspondingly, if you want to get the right result with UUIDs which are in + * big endian format, you need to convert them before using this function. + * + * @sa RTUUID::Gen + * + * @returns iprt status code. + * @param pUuid Uuid to convert. + * @param pszString Where to store result string. + * @param cchString pszString buffer length, must be >= RTUUID_STR_LENGTH. + */ +RTDECL(int) RTUuidToStr(PCRTUUID pUuid, char *pszString, size_t cchString); + +/** + * Converts UUID from its string representation to binary format. + * + * @note IPRT uses little endian byte ordering in the UUID integer fields. If + * you want to pass IPRT UUIDs in binary representation to other UUID libraries + * and expect to get exactly the same string representation as in IPRT, you + * need to convert the first three integer fields (one 32 bit value, two 16 bit + * values) separately to big endian (also called network byte order). + * Correspondingly, if you want to get the right result with UUIDs which are in + * big endian format, you need to convert them before using this function. + * + * @sa RTUUID::Gen + * + * @returns iprt status code. + * @param pUuid Where to store result Uuid. + * @param pszString String with UUID text data. + */ +RTDECL(int) RTUuidFromStr(PRTUUID pUuid, const char *pszString); + +/** + * Converts binary UUID to its UTF-16 string representation. + * + * @note See note in RTUuidToStr. + * + * @sa RTUUID::Gen + * + * @returns iprt status code. + * @param pUuid Uuid to convert. + * @param pwszString Where to store result string. + * @param cwcString pszString buffer length, must be >= + * RTUUID_STR_LENGTH. + */ +RTDECL(int) RTUuidToUtf16(PCRTUUID pUuid, PRTUTF16 pwszString, size_t cwcString); + +/** + * Converts UUID from its UTF-16 string representation to binary format. + * + * @note See note in RTUuidFromStr. + * + * @sa RTUUID::Gen + * + * @returns iprt status code. + * @param pUuid Where to store result Uuid. + * @param pwszString String with UUID text data. + */ +RTDECL(int) RTUuidFromUtf16(PRTUUID pUuid, PCRTUTF16 pwszString); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_uuid_h */ + diff --git a/include/iprt/vector.h b/include/iprt/vector.h new file mode 100644 index 00000000..0e3f6a8a --- /dev/null +++ b/include/iprt/vector.h @@ -0,0 +1,389 @@ +/** @file + * IPRT - Vector - STL-inspired vector implementation in C. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +/** + * @todo the right Doxygen tag here + * This file defines a set of macros which provide a functionality and an + * interface roughly similar to the C++ STL vector container. To create a + * vector of a particular type one must first explicitly instantiate such a + * vector in the source file, e.g. + * RTVEC_DECL(TopLevels, Window *) + * without a semi-colon. This macro will define a structure (struct TopLevels) + * which contains a dynamically resizeable array of Window * elements. It + * will also define a number of inline methods for manipulating the structure, + * such as + * Window *TopLevelsPushBack(struct TopLevels *) + * which adds a new element to the end of the array and returns it, optionally + * reallocating the array if there is not enough space for the new element. + * (This particular method prototype differs from the STL equivalent - + * push_back - more than most of the other methods). + * + * To create a vector, one simply needs to declare the structure, in this case + * struct TopLevels = RTVEC_INITIALIZER; + * + * There are various other macros for declaring vectors with different + * allocators (e.g. RTVEC_DECL_ALLOCATOR) or with clean-up functions + * (e.g. RTVEC_DECL_DELETE). See the descriptions of the generic methods and + * the declarator macros below. + * + * One particular use of vectors is to assemble an array of a particular type + * in heap memory without knowing - or counting - the number of elements in + * advance. To do this, add the elements onto the array using PushBack, then + * extract the array from the vector using the (non-STL) Detach method. + * + * @note functions in this file are inline to prevent warnings about + * unused static functions. I assume that in this day and age a + * compiler makes its own decisions about whether to actually + * inline a function. + * @note since vector structures must be explicitly instanciated unlike the + * C++ vector template, care must be taken not to instanciate a + * particular type twice, e.g. once in a header and once in a code file. + * Only using vectors in code files and keeping them out of interfaces + * (or passing them as anonymously) makes it easier to take care of this. + */ + +#ifndef IPRT_INCLUDED_vector_h +#define IPRT_INCLUDED_vector_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/******************************************************************************* +* Header Files * +*******************************************************************************/ + +#include <iprt/assert.h> +#include <iprt/cdefs.h> +#include <iprt/errcore.h> +#include <iprt/mem.h> /** @todo Should the caller include this if they need + * it? */ + + +/** + * Generic vector structure + */ +/** @todo perhaps we should include an additional member for a parameter to + * three-argument reallocators, so that we can support e.g. mempools? */ +#define RTVEC_DECL_STRUCT(name, type) \ +struct name \ +{ \ + /** The number of elements in the vector */ \ + size_t mcElements; \ + /** The current capacity of the vector */ \ + size_t mcCapacity; \ + /** The elements themselves */ \ + type *mpElements; \ +}; + +/** Initialiser for an empty vector structure */ +#define RTVEC_INITIALIZER { 0, 0, NULL } + +/** The unit by which the vector capacity is increased */ +#define RTVECIMPL_ALLOC_UNIT 16 + +/** + * Generic method - get the size of a vector + */ +/** @todo What is the correct way to do doxygen for this sort of macro? */ +#define RTVEC_DECLFN_SIZE(name, type) \ +DECLINLINE(size_t) name ## Size(struct name *pVec) \ +{ \ + return(pVec->mcElements); \ +} + +/** + * Generic method - expand a vector + */ +#define RTVEC_DECLFN_RESERVE(name, type, pfnRealloc) \ +DECLINLINE(int) name ## Reserve(struct name *pVec, size_t cNewCapacity) \ +{ \ + void *pvNew; \ + \ + if (cNewCapacity <= pVec->mcCapacity) \ + return VINF_SUCCESS; \ + pvNew = pfnRealloc(pVec->mpElements, cNewCapacity * sizeof(type)); \ + if (!pvNew) \ + return VERR_NO_MEMORY; \ + pVec->mcCapacity = cNewCapacity; \ + pVec->mpElements = (type *)pvNew; \ + return VINF_SUCCESS; \ +} + +/** + * Generic method - return a pointer to the first element in the vector. + */ +#define RTVEC_DECLFN_BEGIN(name, type) \ +DECLINLINE(type *) name ## Begin(struct name *pVec) \ +{ \ + return(pVec->mpElements); \ +} + +/** + * Generic method - return a pointer to one past the last element in the + * vector. + */ +#define RTVEC_DECLFN_END(name, type) \ +DECLINLINE(type *) name ## End(struct name *pVec) \ +{ \ + return(&pVec->mpElements[pVec->mcElements]); \ +} + +/** + * Generic method - add a new, uninitialised element onto a vector and return + * it. + * @note this method differs from the STL equivalent by letting the caller + * post-initialise the new element rather than copying it from its + * argument. + */ +#define RTVEC_DECLFN_PUSHBACK(name, type) \ +DECLINLINE(type *) name ## PushBack(struct name *pVec) \ +{ \ + Assert(pVec->mcElements <= pVec->mcCapacity); \ + if ( pVec->mcElements == pVec->mcCapacity \ + && RT_FAILURE(name ## Reserve(pVec, pVec->mcCapacity \ + + RTVECIMPL_ALLOC_UNIT))) \ + return NULL; \ + ++pVec->mcElements; \ + return &pVec->mpElements[pVec->mcElements - 1]; \ +} + +/** + * Generic method - drop the last element from the vector. + */ +#define RTVEC_DECLFN_POPBACK(name) \ +DECLINLINE(void) name ## PopBack(struct name *pVec) \ +{ \ + Assert(pVec->mcElements <= pVec->mcCapacity); \ + --pVec->mcElements; \ +} + +/** + * Generic method - drop the last element from the vector, calling a clean-up + * method first. + * + * By taking an adapter function for the element to be dropped as an + * additional macro parameter we can support clean-up by pointer + * (pfnAdapter maps T* -> T*) or by value (maps T* -> T). pfnAdapter takes + * one argument of type @a type * and must return whatever type pfnDelete + * expects. + */ +/** @todo find a better name for pfnAdapter? */ +#define RTVEC_DECLFN_POPBACK_DELETE(name, type, pfnDelete, pfnAdapter) \ +DECLINLINE(void) name ## PopBack(struct name *pVec) \ +{ \ + Assert(pVec->mcElements <= pVec->mcCapacity); \ + --pVec->mcElements; \ + pfnDelete(pfnAdapter(&pVec->mpElements[pVec->mcElements])); \ +} + +/** + * Generic method - reset a vector to empty. + * @note This function does not free any memory + */ +#define RTVEC_DECLFN_CLEAR(name) \ +DECLINLINE(void) name ## Clear(struct name *pVec) \ +{ \ + Assert(pVec->mcElements <= pVec->mcCapacity); \ + pVec->mcElements = 0; \ +} + +/** + * Generic method - reset a vector to empty, calling a clean-up method on each + * element first. + * @note See @a RTVEC_DECLFN_POPBACK_DELETE for an explanation of pfnAdapter + * @note This function does not free any memory + * @note The cleanup function is currently called on the elements from first + * to last. The testcase expects this. + */ +#define RTVEC_DECLFN_CLEAR_DELETE(name, pfnDelete, pfnAdapter) \ +DECLINLINE(void) name ## Clear(struct name *pVec) \ +{ \ + size_t i; \ + \ + Assert(pVec->mcElements <= pVec->mcCapacity); \ + for (i = 0; i < pVec->mcElements; ++i) \ + pfnDelete(pfnAdapter(&pVec->mpElements[i])); \ + pVec->mcElements = 0; \ +} + +/** + * Generic method - detach the array contained inside a vector and reset the + * vector to empty. + * @note This function does not free any memory + */ +#define RTVEC_DECLFN_DETACH(name, type) \ +DECLINLINE(type *) name ## Detach(struct name *pVec) \ +{ \ + type *pArray = pVec->mpElements; \ + \ + Assert(pVec->mcElements <= pVec->mcCapacity); \ + pVec->mcElements = 0; \ + pVec->mpElements = NULL; \ + pVec->mcCapacity = 0; \ + return pArray; \ +} + +/** Common declarations for all vector types */ +#define RTVEC_DECL_COMMON(name, type, pfnRealloc) \ + RTVEC_DECL_STRUCT(name, type) \ + RTVEC_DECLFN_SIZE(name, type) \ + RTVEC_DECLFN_RESERVE(name, type, pfnRealloc) \ + RTVEC_DECLFN_BEGIN(name, type) \ + RTVEC_DECLFN_END(name, type) \ + RTVEC_DECLFN_PUSHBACK(name, type) \ + RTVEC_DECLFN_DETACH(name, type) + +/** + * Declarator macro - declare a vector type + * @param name the name of the C struct type describing the vector as + * well as the prefix of the functions for manipulating it + * @param type the type of the objects contained in the vector + * @param pfnRealloc the memory reallocation function used for expanding the + * vector + */ +#define RTVEC_DECL_ALLOCATOR(name, type, pfnRealloc) \ + RTVEC_DECL_COMMON(name, type, pfnRealloc) \ + RTVEC_DECLFN_POPBACK(name) \ + RTVEC_DECLFN_CLEAR(name) + +/** + * Generic method - inline id mapping delete adapter function - see the + * explanation of pfnAdapter in @a RTVEC_DECLFN_POPBACK_DELETE. + */ +#define RTVEC_DECLFN_DELETE_ADAPTER_ID(name, type) \ +DECLINLINE(type *) name ## DeleteAdapterId(type *arg) \ +{ \ + return arg; \ +} + +/** + * Generic method - inline pointer-to-value mapping delete adapter function - + * see the explanation of pfnAdapter in @a RTVEC_DECLFN_POPBACK_DELETE. + */ +#define RTVEC_DECLFN_DELETE_ADAPTER_TO_VALUE(name, type) \ +DECLINLINE(type) name ## DeleteAdapterToValue(type *arg) \ +{ \ + return *arg; \ +} + +/** + * Declarator macro - declare a vector type with a cleanup callback to be used + * when elements are dropped from the vector. The callback takes a pointer to + * @a type, + * NOT a value of type @a type. + * @param name the name of the C struct type describing the vector as + * well as the prefix of the functions for manipulating it + * @param type the type of the objects contained in the vector + * @param pfnRealloc the memory reallocation function used for expanding the + * vector + * @param pfnDelete the cleanup callback function - signature + * void pfnDelete(type *) + */ +#define RTVEC_DECL_ALLOCATOR_DELETE(name, type, pfnRealloc, pfnDelete) \ + RTVEC_DECL_COMMON(name, type, pfnRealloc) \ + RTVEC_DECLFN_DELETE_ADAPTER_ID(name, type) \ + RTVEC_DECLFN_POPBACK_DELETE(name, type, pfnDelete, \ + name ## DeleteAdapterId) \ + RTVEC_DECLFN_CLEAR_DELETE(name, pfnDelete, name ## DeleteAdapterId) + +/** + * Declarator macro - declare a vector type with a cleanup callback to be used + * when elements are dropped from the vector. The callback takes a parameter + * of type @a type, NOT a pointer to @a type. + * @param name the name of the C struct type describing the vector as + * well as the prefix of the functions for manipulating it + * @param type the type of the objects contained in the vector + * @param pfnRealloc the memory reallocation function used for expanding the + * vector + * @param pfnDelete the cleanup callback function - signature + * void pfnDelete(type) + */ +#define RTVEC_DECL_ALLOCATOR_DELETE_BY_VALUE(name, type, pfnRealloc, \ + pfnDelete) \ + RTVEC_DECL_COMMON(name, type, pfnRealloc) \ + RTVEC_DECLFN_DELETE_ADAPTER_TO_VALUE(name, type) \ + RTVEC_DECLFN_POPBACK_DELETE(name, type, pfnDelete, \ + name ## DeleteAdapterToValue) \ + RTVEC_DECLFN_CLEAR_DELETE(name, pfnDelete, \ + name ## DeleteAdapterToValue) + +/** + * Inline wrapper around RTMemRealloc macro to get a function usable as a + * callback. + */ +DECLINLINE(void *) rtvecReallocDefTag(void *pv, size_t cbNew) +{ + return RTMemRealloc(pv, cbNew); +} + +/** + * Declarator macro - declare a vector type (see @a RTVEC_DECL_ALLOCATOR) + * using RTMemRealloc as a memory allocator + * @param name the name of the C struct type describing the vector as + * well as the prefix of the functions for manipulating it + * @param type the type of the objects contained in the vector + */ +#define RTVEC_DECL(name, type) \ + RTVEC_DECL_ALLOCATOR(name, type, rtvecReallocDefTag) + +/** + * Declarator macro - declare a vector type with a cleanup by pointer callback + * (see @a RTVEC_DECL_ALLOCATOR_DELETE) using RTMemRealloc as a memory + * allocator + * @param name the name of the C struct type describing the vector as + * well as the prefix of the functions for manipulating it + * @param type the type of the objects contained in the vector + * @param pfnDelete the cleanup callback function - signature + * void pfnDelete(type *) + */ +#define RTVEC_DECL_DELETE(name, type, pfnDelete) \ + RTVEC_DECL_ALLOCATOR_DELETE(name, type, rtvecReallocDefTag, pfnDelete) + +/** + * Declarator macro - declare a vector type with a cleanup by value callback + * (see @a RTVEC_DECL_ALLOCATOR_DELETE_BY_VALUE) using RTMemRealloc as a memory + * allocator + * @param name the name of the C struct type describing the vector as + * well as the prefix of the functions for manipulating it + * @param type the type of the objects contained in the vector + * @param pfnDelete the cleanup callback function - signature + * void pfnDelete(type) + */ +#define RTVEC_DECL_DELETE_BY_VALUE(name, type, pfnDelete) \ + RTVEC_DECL_ALLOCATOR_DELETE_BY_VALUE(name, type, rtvecReallocDefTag, \ + pfnDelete) + +#endif /* !IPRT_INCLUDED_vector_h */ + diff --git a/include/iprt/vfs.h b/include/iprt/vfs.h new file mode 100644 index 00000000..21fccdf6 --- /dev/null +++ b/include/iprt/vfs.h @@ -0,0 +1,2021 @@ +/** @file + * IPRT - Virtual Filesystem. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_vfs_h +#define IPRT_INCLUDED_vfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/dir.h> +#include <iprt/fs.h> +#include <iprt/handle.h> +#include <iprt/symlink.h> +#include <iprt/sg.h> +#include <iprt/time.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_vfs RTVfs - Virtual Filesystem + * @ingroup grp_rt + * + * The virtual filesystem APIs are intended to make it possible to work on + * container files, file system sub-trees, file system overlays and other custom + * filesystem configurations. It also makes it possible to create filters, like + * automatically gunzipping a tar.gz file before feeding it to the RTTar API for + * unpacking - or vice versa. + * + * The virtual filesystem APIs are intended to mirror the RTDir, RTFile, RTPath + * and RTFs APIs pretty closely so that rewriting a piece of code to work with + * it should be easy. However there are some differences to the way the APIs + * works and the user should heed the documentation. The differences are + * usually motivated by simplification and in some case to make the VFS more + * flexible. + * + * @{ + */ + +/** + * The object type. + */ +typedef enum RTVFSOBJTYPE +{ + /** Invalid type. */ + RTVFSOBJTYPE_INVALID = 0, + /** Pure base object. + * This is returned by the filesystem stream to represent directories, + * devices, fifos and similar that needs to be created. */ + RTVFSOBJTYPE_BASE, + /** Virtual filesystem. */ + RTVFSOBJTYPE_VFS, + /** Filesystem stream. */ + RTVFSOBJTYPE_FS_STREAM, + /** Pure I/O stream. */ + RTVFSOBJTYPE_IO_STREAM, + /** Directory. */ + RTVFSOBJTYPE_DIR, + /** File. */ + RTVFSOBJTYPE_FILE, + /** Symbolic link. */ + RTVFSOBJTYPE_SYMLINK, + /** End of valid object types. */ + RTVFSOBJTYPE_END, + /** Pure I/O stream. */ + RTVFSOBJTYPE_32BIT_HACK = 0x7fffffff +} RTVFSOBJTYPE; +/** Pointer to a VFS object type. */ +typedef RTVFSOBJTYPE *PRTVFSOBJTYPE; + +/** + * Translates a RTVFSOBJTYPE value into a string. + * + * @returns Pointer to readonly name. + * @param enmType The object type to name. + */ +RTDECL(const char *) RTVfsTypeName(RTVFSOBJTYPE enmType); + + + +/** @name RTVfsCreate flags + * @{ */ +/** Whether the file system is read-only. */ +#define RTVFS_C_READONLY RT_BIT(0) +/** Whether we the VFS should be thread safe (i.e. automaticaly employ + * locks). */ +#define RTVFS_C_THREAD_SAFE RT_BIT(1) +/** @} */ + +/** + * Creates an empty virtual filesystem. + * + * @returns IPRT status code. + * @param pszName Name, for logging and such. + * @param fFlags Flags, MBZ. + * @param phVfs Where to return the VFS handle. Release the returned + * reference by calling RTVfsRelease. + */ +RTDECL(int) RTVfsCreate(const char *pszName, uint32_t fFlags, PRTVFS phVfs); +RTDECL(uint32_t) RTVfsRetain(RTVFS hVfs); +RTDECL(uint32_t) RTVfsRetainDebug(RTVFS hVfs, RT_SRC_POS_DECL); +RTDECL(uint32_t) RTVfsRelease(RTVFS hVfs); + +/** @name RTVFSMNT_F_XXX - Flags for RTVfsMount + * @{ */ +/** Mount read-only. */ +#define RTVFSMNT_F_READ_ONLY RT_BIT_32(0) +/** Purpose is . */ +#define RTVFSMNT_F_FOR_RANGE_IN_USE RT_BIT_32(1) +/** Valid mask. */ +#define RTVFSMNT_F_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** + * Does the file system detection and mounting. + * + * @returns IPRT status code. + * @retval VERR_VFS_UNSUPPORTED_FORMAT if not recognized as a support file + * system. + * @param hVfsFileIn The file handle of the volume. + * @param fFlags RTVFSMTN_F_XXX. + * @param phVfs Where to return the VFS handle on success. + * @param pErrInfo Where to return additional error information. + * Optional. + */ +RTDECL(int) RTVfsMountVol(RTVFSFILE hVfsFileIn, uint32_t fFlags, PRTVFS phVfs, PRTERRINFO pErrInfo); + +RTDECL(int) RTVfsAttach(RTVFS hVfs, const char *pszMountPoint, uint32_t fFlags, RTVFS hVfsAttach); +RTDECL(int) RTVfsDetach(RTVFS hVfs, const char *pszMountPoint, RTVFS hVfsToDetach, PRTVFS *phVfsDetached); +RTDECL(uint32_t) RTVfsGetAttachmentCount(RTVFS hVfs); +RTDECL(int) RTVfsGetAttachment(RTVFS hVfs, uint32_t iOrdinal, PRTVFS *phVfsAttached, uint32_t *pfFlags, + char *pszMountPoint, size_t cbMountPoint); + +/** + * Opens the root director of the given VFS. + * + * @returns IPRT status code. + * @param hVfs VFS handle. + * @param phDir Where to return the root directory handle. + */ +RTDECL(int) RTVfsOpenRoot(RTVFS hVfs, PRTVFSDIR phDir); + +/** + * Queries information about a object in the virtual filesystem. + * + * @returns IPRT Status code. + * @param hVfs VFS handle. + * @param pszPath Path to the object, relative to the VFS root. + * @param pObjInfo Where to return info. + * @param enmAddAttr What to return. + * @param fFlags RTPATH_F_XXX. + * @sa RTPathQueryInfoEx, RTVfsDirQueryPathInfo, RTVfsObjQueryInfo + */ +RTDECL(int) RTVfsQueryPathInfo(RTVFS hVfs, const char *pszPath, PRTFSOBJINFO pObjInfo, + RTFSOBJATTRADD enmAddAttr, uint32_t fFlags); + +/** + * Checks whether a given range is in use by the virtual filesystem. + * + * @returns IPRT status code. + * @param hVfs VFS handle. + * @param off Start offset to check. + * @param cb Number of bytes to check. + * @param pfUsed Where to store the result. + */ +RTDECL(int) RTVfsQueryRangeState(RTVFS hVfs, uint64_t off, size_t cb, bool *pfUsed); + +/** + * Queries the volume label. + * + * @returns IPRT status code. + * @param hVfs VFS handle. + * @param fAlternative For use with ISO files to retrieve the primary lable + * rather than the joliet / UDF one that the mount + * options would indicate. For other file systems, as + * well for ISO not mounted in joliet / UDF mode, the + * flag is ignored. + * @param pszLabel Where to store the lable. + * @param cbLabel Size of the buffer @a pszLable points at. + * @param pcbActual Where to return the label length, including the + * terminator. In case of VERR_BUFFER_OVERFLOW + * returns, this will be set to the required buffer + * size. Optional. + */ +RTDECL(int) RTVfsQueryLabel(RTVFS hVfs, bool fAlternative, char *pszLabel, size_t cbLabel, size_t *pcbActual); + + +/** @defgroup grp_rt_vfs_obj VFS Base Object API + * @{ + */ + +/** + * Retains a reference to the VFS base object handle. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(uint32_t) RTVfsObjRetain(RTVFSOBJ hVfsObj); +RTDECL(uint32_t) RTVfsObjRetainDebug(RTVFSOBJ hVfsObj, RT_SRC_POS_DECL); + +/** + * Releases a reference to the VFS base handle. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(uint32_t) RTVfsObjRelease(RTVFSOBJ hVfsObj); + +/** @name RTVFSOBJ_F_XXX - Flags or RTVfsObjOpen and RTVfsDirOpenObj. + * @note Must leave space for RTPATH_F_XXX. + * @{ */ +/** Directory (RTFS_TYPE_DIRECTORY). */ +#define RTVFSOBJ_F_OPEN_DIRECTORY RT_BIT_32(8) +/** Symbolic link (RTFS_TYPE_SYMLINK). */ +#define RTVFSOBJ_F_OPEN_SYMLINK RT_BIT_32(9) +/** Regular file (RTFS_TYPE_FILE). */ +#define RTVFSOBJ_F_OPEN_FILE RT_BIT_32(10) +/** Character device (RTFS_TYPE_DEV_CHAR). */ +#define RTVFSOBJ_F_OPEN_DEV_CHAR RT_BIT_32(11) +/** Block device (RTFS_TYPE_DEV_BLOCK). */ +#define RTVFSOBJ_F_OPEN_DEV_BLOCK RT_BIT_32(12) +/** Named pipe (fifo) (RTFS_TYPE_FIFO). */ +#define RTVFSOBJ_F_OPEN_FIFO RT_BIT_32(13) +/** Socket (RTFS_TYPE_SOCKET). */ +#define RTVFSOBJ_F_OPEN_SOCKET RT_BIT_32(14) +/** Mounted VFS. */ +#define RTVFSOBJ_F_OPEN_MOUNT RT_BIT_32(15) +/** Mask object types we wish to open. */ +#define RTVFSOBJ_F_OPEN_MASK UINT32_C(0x0000ff00) +/** Any kind of object that translates to RTVFSOBJTYPE_FILE. */ +#define RTVFSOBJ_F_OPEN_ANY_FILE (RTVFSOBJ_F_OPEN_FILE | RTVFSOBJ_F_OPEN_DEV_BLOCK) +/** Any kind of object that translates to RTVFSOBJTYPE_IOS or + * RTVFSOBJTYPE_FILE. */ +#define RTVFSOBJ_F_OPEN_ANY_IO_STREAM ( RTVFSOBJ_F_ANY_OPEN_FILE | RTVFSOBJ_F_DEV_OPEN_BLOCK \ + | RTVFSOBJ_F_OPEN_FIFO | RTVFSOBJ_F_OPEN_SOCKET) +/** Any kind of object. */ +#define RTVFSOBJ_F_OPEN_ANY RTVFSOBJ_F_OPEN_MASK + +/** Do't create anything, return file not found. */ +#define RTVFSOBJ_F_CREATE_NOTHING UINT32_C(0x00000000) +/** Create a file if the if the object was not found and the RTFILE_O_XXX + * flags allows it. */ +#define RTVFSOBJ_F_CREATE_FILE UINT32_C(0x00010000) +/** Create a directory if the object was not found and the RTFILE_O_XXX + * flags allows it. */ +#define RTVFSOBJ_F_CREATE_DIRECTORY UINT32_C(0x00020000) +/** The creation type mask. */ +#define RTVFSOBJ_F_CREATE_MASK UINT32_C(0x00070000) + +/** Indicate that this call is for traversal. + * @internal only */ +#define RTVFSOBJ_F_TRAVERSAL RT_BIT_32(31) +/** Valid mask for external callers. */ +#define RTVFSOBJ_F_VALID_MASK UINT32_C(0x0007ff00) +/** @} */ + +/** + * Opens any file system object in the given VFS. + * + * @returns IPRT status code. + * @param hVfs The VFS to open the object within. + * @param pszPath Path to the file. + * @param fFileOpen RTFILE_O_XXX flags. + * @param fObjFlags More flags: RTVFSOBJ_F_XXX, RTPATH_F_XXX. + * @param phVfsObj Where to return the object handle. + * @sa RTVfsDirOpenObj, RTVfsDirOpenDir, RTVfsDirOpenFile + */ +RTDECL(int) RTVfsObjOpen(RTVFS hVfs, const char *pszPath, uint64_t fFileOpen, uint32_t fObjFlags, PRTVFSOBJ phVfsObj); + +/** + * Query information about the object. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the @a enmAddAttr value is not handled by the + * implementation. + * + * @param hVfsObj The VFS object handle. + * @param pObjInfo Where to return the info. + * @param enmAddAttr Which additional attributes should be retrieved. + * @sa RTVfsIoStrmQueryInfo, RTVfsFileQueryInfo, RTFileQueryInfo, + * RTPathQueryInfo + */ +RTDECL(int) RTVfsObjQueryInfo(RTVFSOBJ hVfsObj, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr); + +/** + * Sets the file mode for the given VFS object. + * + * @returns IPRT status code. + * @retval VERR_INVALID_FUNCTION if the object type has no file mode to set. + * Only directories, files and symbolic links support this operation. + * + * @param hVfsObj The VFS object handle. + * @param fMode The mode mask. + * @param fMask The bits in the mode mask which should be changed. + */ +RTDECL(int) RTVfsObjSetMode(RTVFSOBJ hVfsObj, RTFMODE fMode, RTFMODE fMask); + +/** + * Sets one or more timestamps for the given VFS object. + * + * @returns IPRT status code. + * @retval VERR_INVALID_FUNCTION if the object type has no file mode to set. + * Only directories, files and symbolic links support this operation. + * + * @param hVfsObj The VFS object handle. + * @param pAccessTime Pointer to the new access time. NULL if not to + * be changed. + * @param pModificationTime Pointer to the new modifcation time. NULL if not + * to be changed. + * @param pChangeTime Pointer to the new change time. NULL if not to + * be changed. + * @param pBirthTime Pointer to the new time of birth. NULL if not to + * be changed. + * + * @remarks See RTFileSetTimes for restrictions and behavior imposed by the + * host OS or underlying VFS provider. + * @sa RTFileSetTimes, RTPathSetTimes + */ +RTDECL(int) RTVfsObjSetTimes(RTVFSOBJ hVfsObj, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, + PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime); + +/** + * Set the unix style owner and group on the given VFS object. + * + * @returns IPRT status code. + * @retval VERR_INVALID_FUNCTION if the object type has no file mode to set. + * Only directories, files and symbolic links support this operation. + * + * @param hVfsObj The VFS object handle. + * @param uid The user ID of the new owner. NIL_RTUID if + * unchanged. + * @param gid The group ID of the new owner group. NIL_RTGID if + * unchanged. + * + * @sa RTFileSetOwner, RTPathSetOwner. + */ +RTDECL(int) RTVfsObjSetOwner(RTVFSOBJ hVfsObj, RTUID uid, RTGID gid); + + +/** + * Gets the type of a VFS object. + * + * @returns The VFS object type on success, RTVFSOBJTYPE_INVALID on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(RTVFSOBJTYPE) RTVfsObjGetType(RTVFSOBJ hVfsObj); + +/** + * Converts a VFS base object handle to a VFS handle. + * + * @returns Referenced handle on success, NIL on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(RTVFS) RTVfsObjToVfs(RTVFSOBJ hVfsObj); + +/** + * Converts a VFS base object handle to a VFS filesystem stream handle. + * + * @returns Referenced handle on success, NIL on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(RTVFSFSSTREAM) RTVfsObjToFsStream(RTVFSOBJ hVfsObj); + +/** + * Converts a VFS base object handle to a VFS directory handle. + * + * @returns Referenced handle on success, NIL on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(RTVFSDIR) RTVfsObjToDir(RTVFSOBJ hVfsObj); + +/** + * Converts a VFS base object handle to a VFS I/O stream handle. + * + * @returns Referenced handle on success, NIL on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(RTVFSIOSTREAM) RTVfsObjToIoStream(RTVFSOBJ hVfsObj); + +/** + * Converts a VFS base object handle to a VFS file handle. + * + * @returns Referenced handle on success, NIL on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(RTVFSFILE) RTVfsObjToFile(RTVFSOBJ hVfsObj); + +/** + * Converts a VFS base object handle to a VFS symbolic link handle. + * + * @returns Referenced handle on success, NIL on failure. + * @param hVfsObj The VFS base object handle. + */ +RTDECL(RTVFSSYMLINK) RTVfsObjToSymlink(RTVFSOBJ hVfsObj); + + +/** + * Converts a VFS handle to a VFS base object handle. + * + * @returns Referenced handle on success, NIL if the input handle was invalid. + * @param hVfs The VFS handle. + */ +RTDECL(RTVFSOBJ) RTVfsObjFromVfs(RTVFS hVfs); + +/** + * Converts a VFS filesystem stream handle to a VFS base object handle. + * + * @returns Referenced handle on success, NIL if the input handle was invalid. + * @param hVfsFss The VFS filesystem stream handle. + */ +RTDECL(RTVFSOBJ) RTVfsObjFromFsStream(RTVFSFSSTREAM hVfsFss); + +/** + * Converts a VFS directory handle to a VFS base object handle. + * + * @returns Referenced handle on success, NIL if the input handle was invalid. + * @param hVfsDir The VFS directory handle. + */ +RTDECL(RTVFSOBJ) RTVfsObjFromDir(RTVFSDIR hVfsDir); + +/** + * Converts a VFS I/O stream handle to a VFS base object handle. + * + * @returns Referenced handle on success, NIL if the input handle was invalid. + * @param hVfsIos The VFS I/O stream handle. + */ +RTDECL(RTVFSOBJ) RTVfsObjFromIoStream(RTVFSIOSTREAM hVfsIos); + +/** + * Converts a VFS file handle to a VFS base object handle. + * + * @returns Referenced handle on success, NIL if the input handle was invalid. + * @param hVfsFile The VFS file handle. + */ +RTDECL(RTVFSOBJ) RTVfsObjFromFile(RTVFSFILE hVfsFile); + +/** + * Converts a VFS symbolic link handle to a VFS base object handle. + * + * @returns Referenced handle on success, NIL if the input handle was invalid. + * @param hVfsSym The VFS symbolic link handle. + */ +RTDECL(RTVFSOBJ) RTVfsObjFromSymlink(RTVFSSYMLINK hVfsSym); + +/** @} */ + + +/** @defgroup grp_rt_vfs_fsstream VFS Filesystem Stream API + * + * Filesystem streams are for tar, cpio and similar. Any virtual filesystem can + * be turned into a filesystem stream using RTVfsFsStrmFromVfs. + * + * @{ + */ + +RTDECL(uint32_t) RTVfsFsStrmRetain(RTVFSFSSTREAM hVfsFss); +RTDECL(uint32_t) RTVfsFsStrmRetainDebug(RTVFSFSSTREAM hVfsFss, RT_SRC_POS_DECL); +RTDECL(uint32_t) RTVfsFsStrmRelease(RTVFSFSSTREAM hVfsFss); +RTDECL(int) RTVfsFsStrmQueryInfo(RTVFSFSSTREAM hVfsFss, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr); + +/** + * Gets the next object in the stream. + * + * This call may affect the stream posision of a previously returned object. + * + * The type of object returned here typically boils down to three types: + * - I/O streams (representing files), + * - symbolic links + * - base object + * The base objects represent anything not convered by the two other, i.e. + * directories, device nodes, fifos, sockets and whatnot. The details can be + * queried using RTVfsObjQueryInfo. + * + * That said, absolutely any object except for filesystem stream objects can be + * returned by this call. Any generic code is adviced to just deal with it all. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if a new object was retrieved. + * @retval VERR_EOF when there are no more objects. + * @retval VERR_INVALID_FUNCTION if called on a non-readable stream. + * + * @param hVfsFss The file system stream handle. + * @param ppszName Where to return the object name. Must be freed by + * calling RTStrFree. + * @param penmType Where to return the object type. + * @param phVfsObj Where to return the object handle (referenced). This + * must be cast to the desired type before use. + */ +RTDECL(int) RTVfsFsStrmNext(RTVFSFSSTREAM hVfsFss, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj); + +/** + * Appends a VFS object to the stream. + * + * The stream must be writable. + * + * @returns IPRT status code. + * @retval VERR_INVALID_FUNCTION if called on a non-writable stream. + * @param hVfsFss The file system stream handle. + * @param pszPath The path. + * @param hVfsObj The VFS object to add. + * @param fFlags RTVFSFSSTRM_ADD_F_XXX. + */ +RTDECL(int) RTVfsFsStrmAdd(RTVFSFSSTREAM hVfsFss, const char *pszPath, RTVFSOBJ hVfsObj, uint32_t fFlags); + +/** @name RTVFSFSSTRM_ADD_F_XXX - Flags for RTVfsFsStrmAdd. + * @{ */ +/** Input is an I/O stream of indeterminate length, read to the end and then + * update the file header. + * @note This is *only* possible if the output stream is actually a file. */ +#define RTVFSFSSTRM_ADD_F_STREAM RT_BIT_32(0) +/** Mask of flags specific to the target stream. */ +#define RTVFSFSSTRM_ADD_F_SPECIFIC_MASK UINT32_C(0xff000000) +/** Valid bits. */ +#define RTVFSFSSTRM_ADD_F_VALID_MASK UINT32_C(0xff000001) +/** @} */ + +/** + * Pushes an byte stream onto the stream. + * + * The stream must be writable. + * + * This differs from RTVfsFsStrmAdd() in that it will create a regular file in + * the output file system stream and provide the actual content bytes via the + * returned I/O stream object. + * + * @returns IPRT status code. + * @retval VERR_INVALID_FUNCTION if called on a non-writable stream. + * @param hVfsFss The file system stream handle. + * @param pszPath The path to the file. + * @param cbFile The file size. This can also be set to UINT64_MAX if + * the file system stream is backed by a file. + * @param paObjInfo Array of zero or more RTFSOBJINFO structures containing + * different pieces of information about the file. If any + * provided, the first one should be a RTFSOBJATTRADD_UNIX + * one, additional can be supplied if wanted. What exactly + * is needed depends on the underlying FS stream + * implementation. + * @param cObjInfo Number of items in the array @a paObjInfo points at. + * @param fFlags RTVFSFSSTRM_PUSH_F_XXX. + * @param phVfsIos Where to return the I/O stream to feed the file content + * to. If the FS stream is backed by a file, the returned + * handle can be cast to a file if necessary. + */ +RTDECL(int) RTVfsFsStrmPushFile(RTVFSFSSTREAM hVfsFss, const char *pszPath, uint64_t cbFile, + PCRTFSOBJINFO paObjInfo, uint32_t cObjInfo, uint32_t fFlags, PRTVFSIOSTREAM phVfsIos); + +/** @name RTVFSFSSTRM_PUSH_F_XXX - Flags for RTVfsFsStrmPushFile. + * @{ */ +/** Input is an I/O stream of indeterminate length, read to the end and then + * update the file header. + * @note This is *only* possible if the output stream is actually a file. */ +#define RTVFSFSSTRM_PUSH_F_STREAM RT_BIT_32(0) +/** Mask of flags specific to the target stream. */ +#define RTVFSFSSTRM_PUSH_F_SPECIFIC_MASK UINT32_C(0xff000000) +/** Valid bits. */ +#define RTVFSFSSTRM_PUSH_F_VALID_MASK UINT32_C(0xff000001) +/** @} */ + +/** + * Marks the end of the stream. + * + * The stream must be writable. + * + * @returns IPRT status code. + * @retval VERR_INVALID_FUNCTION if called on a non-writable stream. + * @param hVfsFss The file system stream handle. + */ +RTDECL(int) RTVfsFsStrmEnd(RTVFSFSSTREAM hVfsFss); + +/** @} */ + + +/** @defgroup grp_rt_vfs_dir VFS Directory API + * @{ + */ + +/** + * Retains a reference to the VFS directory handle. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param hVfsDir The VFS directory handle. + */ +RTDECL(uint32_t) RTVfsDirRetain(RTVFSDIR hVfsDir); +RTDECL(uint32_t) RTVfsDirRetainDebug(RTVFSDIR hVfsDir, RT_SRC_POS_DECL); + +/** + * Releases a reference to the VFS directory handle. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param hVfsDir The VFS directory handle. + */ +RTDECL(uint32_t) RTVfsDirRelease(RTVFSDIR hVfsDir); + +/** + * Opens a directory in the specified file system. + * + * @returns IPRT status code. + * @param hVfs The VFS to open the directory within. + * @param pszPath Path to the directory, relative to the root. + * @param fFlags Reserved, MBZ. + * @param phVfsDir Where to return the directory. + */ +RTDECL(int) RTVfsDirOpen(RTVFS hVfs, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir); + +/** + * Opens any file system object in or under the given directory. + * + * @returns IPRT status code. + * @param hVfsDir The VFS directory start walking the @a pszPath + * relative to. + * @param pszPath Path to the file. + * @param fFileOpen RTFILE_O_XXX flags. + * @param fObjFlags More flags: RTVFSOBJ_F_XXX, RTPATH_F_XXX. + * @param phVfsObj Where to return the object handle. + * @sa RTVfsObjOpen, RTVfsDirOpenDir, RTVfsDirOpenFile + */ +RTDECL(int) RTVfsDirOpenObj(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fFileOpen, uint32_t fObjFlags, PRTVFSOBJ phVfsObj); + +/** + * Opens a file in or under the given directory. + * + * @returns IPRT status code. + * @param hVfsDir The VFS directory start walking the @a pszPath + * relative to. + * @param pszPath Path to the file. + * @param fOpen RTFILE_O_XXX flags. + * @param phVfsFile Where to return the file. + * @sa RTVfsDirOpenFileAsIoStream + */ +RTDECL(int) RTVfsDirOpenFile(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSFILE phVfsFile); + +/** + * Convenience wrapper around RTVfsDirOpenFile that returns an I/O stream. + * + * @returns IPRT status code. + * @param hVfsDir The VFS directory start walking the @a pszPath + * relative to. + * @param pszPath Path to the file. + * @param fOpen RTFILE_O_XXX flags. + * @param phVfsIos Where to return the I/O stream handle of the file. + * @sa RTVfsDirOpenFile + */ +RTDECL(int) RTVfsDirOpenFileAsIoStream(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos); + +/** + * Opens a directory in or under the given directory. + * + * @returns IPRT status code. + * @param hVfsDir The VFS directory start walking the @a pszPath + * relative to. + * @param pszPath Path to the file. + * @param fFlags Reserved, MBZ. + * @param phVfsDir Where to return the directory. + */ +RTDECL(int) RTVfsDirOpenDir(RTVFSDIR hVfsDir, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir); + +/** + * Creates a directory relative to @a hVfsDir. + * + * @returns IPRT status code + * @param hVfsDir The directory the path is relative to. + * @param pszRelPath The relative path to the new directory. + * @param fMode The file mode for the new directory. + * @param fFlags Directory creation flags, RTDIRCREATE_FLAGS_XXX. + * @param phVfsDir Where to return the handle to the newly created + * directory. Optional. + * @sa RTDirCreate, RTDirRelDirCreate + */ +RTDECL(int) RTVfsDirCreateDir(RTVFSDIR hVfsDir, const char *pszRelPath, RTFMODE fMode, uint32_t fFlags, PRTVFSDIR phVfsDir); + +/** + * Create a VFS directory handle from a standard IPRT directory handle (RTDIR). + * + * @returns IPRT status code. + * @param hDir The standard IPRT directory handle. + * @param fLeaveOpen Whether to leave the handle open when the VFS + * directory is released, or to close it (@c false). + * @param phVfsDir Where to return the VFS directory handle. + */ +RTDECL(int) RTVfsDirFromRTDir(RTDIR hDir, bool fLeaveOpen, PRTVFSDIR phVfsDir); + +/** + * RTDirOpen + RTVfsDirFromRTDir. + * + * @returns IPRT status code. + * @param pszPath The path to the directory. + * @param fFlags RTDIR_F_XXX. + * @param phVfsDir Where to return the VFS directory handle. + */ +RTDECL(int) RTVfsDirOpenNormal(const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir); + +/** Checks if @a hVfsDir was opened using RTVfsDirOpenNormal() or + * RTVfsDirFromRTDir(), either directly or indirectly. */ +RTDECL(bool) RTVfsDirIsStdDir(RTVFSDIR hVfsDir); + +/** + * Queries information about a object in or under the given directory. + * + * @returns IPRT Status code. + * @param hVfsDir The VFS directory start walking the @a pszPath + * relative to. + * @param pszPath Path to the object. + * @param pObjInfo Where to return info. + * @param enmAddAttr What to return. + * @param fFlags RTPATH_F_XXX. + * @sa RTPathQueryInfoEx, RTVfsQueryPathInfo, RTVfsObjQueryInfo + */ +RTDECL(int) RTVfsDirQueryPathInfo(RTVFSDIR hVfsDir, const char *pszPath, PRTFSOBJINFO pObjInfo, + RTFSOBJATTRADD enmAddAttr, uint32_t fFlags); + +/** + * Removes a directory relative to @a hVfsDir. + * + * @returns IPRT status code. + * @param hVfsDir The VFS directory to start walking the @a pszRelPath + * relative to. + * @param pszRelPath The path to the directory that should be removed. + * @param fFlags Reserved, MBZ. + */ +RTDECL(int) RTVfsDirRemoveDir(RTVFSDIR hVfsDir, const char *pszRelPath, uint32_t fFlags); + +/** + * Reads the next entry in the directory returning extended information. + * + * @returns VINF_SUCCESS and data in pDirEntry on success. + * @returns VERR_NO_MORE_FILES when the end of the directory has been reached. + * @returns VERR_BUFFER_OVERFLOW if the buffer is too small to contain the filename. If + * pcbDirEntry is specified it will be updated with the required buffer size. + * @returns suitable iprt status code on other errors. + * + * @param hVfsDir The VFS directory. + * @param pDirEntry Where to store the information about the next + * directory entry on success. + * @param pcbDirEntry Optional parameter used for variable buffer size. + * + * On input the variable pointed to contains the size of the pDirEntry + * structure. This must be at least OFFSET(RTDIRENTRYEX, szName[2]) bytes. + * + * On successful output the field is updated to + * OFFSET(RTDIRENTRYEX, szName[pDirEntry->cbName + 1]). + * + * When the data doesn't fit in the buffer and VERR_BUFFER_OVERFLOW is + * returned, this field contains the required buffer size. + * + * The value is unchanged in all other cases. + * @param enmAddAttr Which set of additional attributes to request. + * Use RTFSOBJATTRADD_NOTHING if this doesn't matter. + * + * @sa RTDirReadEx + */ +RTDECL(int) RTVfsDirReadEx(RTVFSDIR hVfsDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr); + +/** + * Rewind and restart the directory reading. + * + * @returns IRPT status code. + * @param hVfsDir The VFS directory. + */ +RTDECL(int) RTVfsDirRewind(RTVFSDIR hVfsDir); + +/** @} */ + + +/** @defgroup grp_rt_vfs_symlink VFS Symbolic Link API + * + * @remarks The TAR VFS and filesystem stream uses symbolic links for + * describing hard links as well. The users must use RTFS_IS_SYMLINK + * to check if it is a real symlink in those cases. + * + * @remarks Any VFS which is backed by a real file system may be subject to + * races with other processes or threads, so the user may get + * unexpected errors when this happends. This is a bit host specific, + * i.e. it might be prevent on windows if we care. + * + * @{ + */ + + +/** + * Retains a reference to the VFS symbolic link handle. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param hVfsSym The VFS symbolic link handle. + */ +RTDECL(uint32_t) RTVfsSymlinkRetain(RTVFSSYMLINK hVfsSym); +RTDECL(uint32_t) RTVfsSymlinkRetainDebug(RTVFSSYMLINK hVfsSym, RT_SRC_POS_DECL); + +/** + * Releases a reference to the VFS symbolic link handle. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param hVfsSym The VFS symbolic link handle. + */ +RTDECL(uint32_t) RTVfsSymlinkRelease(RTVFSSYMLINK hVfsSym); + +/** + * Query information about the symbolic link. + * + * @returns IPRT status code. + * @param hVfsSym The VFS symbolic link handle. + * @param pObjInfo Where to return the info. + * @param enmAddAttr Which additional attributes should be retrieved. + * + * @sa RTFileQueryInfo, RTPathQueryInfo, RTPathQueryInfoEx + */ +RTDECL(int) RTVfsSymlinkQueryInfo(RTVFSSYMLINK hVfsSym, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr); + +/** + * Set the unix style owner and group. + * + * @returns IPRT status code. + * @param hVfsSym The VFS symbolic link handle. + * @param fMode The new mode bits. + * @param fMask The mask indicating which bits we are changing. + * @sa RTFileSetMode, RTPathSetMode + */ +RTDECL(int) RTVfsSymlinkSetMode(RTVFSSYMLINK hVfsSym, RTFMODE fMode, RTFMODE fMask); + +/** + * Set the timestamps associated with the object. + * + * @returns IPRT status code. + * @param hVfsSym The VFS symbolic link handle. + * @param pAccessTime Pointer to the new access time. NULL if not + * to be changed. + * @param pModificationTime Pointer to the new modifcation time. NULL if + * not to be changed. + * @param pChangeTime Pointer to the new change time. NULL if not to be + * changed. + * @param pBirthTime Pointer to the new time of birth. NULL if not to be + * changed. + * @remarks See RTFileSetTimes for restrictions and behavior imposed by the + * host OS or underlying VFS provider. + * @sa RTFileSetTimes, RTPathSetTimes + */ +RTDECL(int) RTVfsSymlinkSetTimes(RTVFSSYMLINK hVfsSym, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, + PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime); + +/** + * Set the unix style owner and group. + * + * @returns IPRT status code. + * @param hVfsSym The VFS symbolic link handle. + * @param uid The user ID of the new owner. NIL_RTUID if + * unchanged. + * @param gid The group ID of the new owner group. NIL_RTGID if + * unchanged. + * @sa RTFileSetOwner, RTPathSetOwner. + */ +RTDECL(int) RTVfsSymlinkSetOwner(RTVFSSYMLINK hVfsSym, RTUID uid, RTGID gid); + +/** + * Read the symbolic link target. + * + * @returns IPRT status code. + * @param hVfsSym The VFS symbolic link handle. + * @param pszTarget The target buffer. + * @param cbTarget The size of the target buffer. + * @sa RTSymlinkRead + */ +RTDECL(int) RTVfsSymlinkRead(RTVFSSYMLINK hVfsSym, char *pszTarget, size_t cbTarget); + +/** @} */ + + + +/** @defgroup grp_rt_vfs_iostream VFS I/O Stream API + * @{ + */ + +/** + * Creates a VFS file from a memory buffer. + * + * @returns IPRT status code. + * + * @param fFlags A combination of RTFILE_O_READ and RTFILE_O_WRITE. + * @param pvBuf The buffer. This will be copied and not referenced + * after this function returns. + * @param cbBuf The buffer size. + * @param phVfsIos Where to return the VFS I/O stream handle. + */ +RTDECL(int) RTVfsIoStrmFromBuffer(uint32_t fFlags, void const *pvBuf, size_t cbBuf, PRTVFSIOSTREAM phVfsIos); + +/** + * Creates a VFS I/O stream handle from a standard IPRT file handle (RTFILE). + * + * @returns IPRT status code. + * @param hFile The standard IPRT file handle. + * @param fOpen The flags the handle was opened with. Pass 0 to + * have these detected. + * @param fLeaveOpen Whether to leave the handle open when the VFS file + * is released, or to close it (@c false). + * @param phVfsIos Where to return the VFS I/O stream handle. + */ +RTDECL(int) RTVfsIoStrmFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos); + +/** + * Creates a VFS I/O stream handle from a standard IPRT pipe handle (RTPIPE). + * + * @returns IPRT status code. + * @param hPipe The standard IPRT pipe handle. + * @param fLeaveOpen Whether to leave the handle open when the VFS file + * is released, or to close it (@c false). + * @param phVfsIos Where to return the VFS I/O stream handle. + */ +RTDECL(int) RTVfsIoStrmFromRTPipe(RTPIPE hPipe, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos); + +/** + * Convenience function combining RTFileOpen with RTVfsIoStrmFromRTFile. + * + * @returns IPRT status code. + * @param pszFilename The path to the file in the normal file system. + * @param fOpen The flags to pass to RTFileOpen when opening the + * file, i.e. RTFILE_O_XXX. + * @param phVfsIos Where to return the VFS I/O stream handle. + */ +RTDECL(int) RTVfsIoStrmOpenNormal(const char *pszFilename, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos); + +/** + * Create a VFS I/O stream handle from one of the standard handles. + * + * @returns IPRT status code. + * @param enmStdHandle The standard IPRT file handle. + * @param fOpen The flags the handle was opened with. Pass 0 to + * have these detected. + * @param fLeaveOpen Whether to leave the handle open when the VFS file + * is released, or to close it (@c false). + * @param phVfsIos Where to return the VFS I/O stream handle. + */ +RTDECL(int) RTVfsIoStrmFromStdHandle(RTHANDLESTD enmStdHandle, uint64_t fOpen, bool fLeaveOpen, + PRTVFSIOSTREAM phVfsIos); + +/** + * Retains a reference to the VFS I/O stream handle. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param hVfsIos The VFS I/O stream handle. + */ +RTDECL(uint32_t) RTVfsIoStrmRetain(RTVFSIOSTREAM hVfsIos); +RTDECL(uint32_t) RTVfsIoStrmRetainDebug(RTVFSIOSTREAM hVfsIos, RT_SRC_POS_DECL); + +/** + * Releases a reference to the VFS I/O stream handle. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param hVfsIos The VFS I/O stream handle. + */ +RTDECL(uint32_t) RTVfsIoStrmRelease(RTVFSIOSTREAM hVfsIos); + +/** + * Convert the VFS I/O stream handle to a VFS file handle. + * + * @returns The VFS file handle on success, this must be released. + * NIL_RTVFSFILE if the I/O stream handle is invalid. + * @param hVfsIos The VFS I/O stream handle. + * @sa RTVfsFileToIoStream + */ +RTDECL(RTVFSFILE) RTVfsIoStrmToFile(RTVFSIOSTREAM hVfsIos); + +/** + * Query information about the I/O stream. + * + * @returns IPRT status code. + * @param hVfsIos The VFS I/O stream handle. + * @param pObjInfo Where to return the info. + * @param enmAddAttr Which additional attributes should be retrieved. + * @sa RTFileQueryInfo + */ +RTDECL(int) RTVfsIoStrmQueryInfo(RTVFSIOSTREAM hVfsIos, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr); + +/** + * Read bytes from the I/O stream. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and the number of bytes read written to @a pcbRead. + * @retval VINF_TRY_AGAIN if @a fBlocking is @c false, @a pcbRead is not NULL, + * and no data was available. @a *pcbRead will be set to 0. + * @retval VINF_EOF when trying to read __beyond__ the end of the stream and + * @a pcbRead is not NULL (it will be set to the number of bytes read, + * or 0 if the end of the stream was reached before this call). + * When the last byte of the read request is the last byte in the + * stream, this status code will not be used. However, VINF_EOF is + * returned when attempting to read 0 bytes while standing at the end + * of the stream. + * @retval VERR_EOF when trying to read __beyond__ the end of the stream and + * @a pcbRead is NULL. + * @retval VERR_ACCESS_DENIED if the stream is not readable. + * + * @param hVfsIos The VFS I/O stream handle. + * @param pvBuf Where to store the read bytes. + * @param cbToRead The number of bytes to read. + * @param fBlocking Whether the call is blocking (@c true) or not. If + * not, the @a pcbRead parameter must not be NULL. + * @param pcbRead Where to always store the number of bytes actually + * read. This can be NULL if @a fBlocking is true. + * @sa RTVfsFileRead, RTFileRead, RTPipeRead, RTPipeReadBlocking, + * RTSocketRead + */ +RTDECL(int) RTVfsIoStrmRead(RTVFSIOSTREAM hVfsIos, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead); + +/** + * Read bytes from the I/O stream, optionally with offset. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and the number of bytes read written to @a pcbRead. + * @retval VINF_TRY_AGAIN if @a fBlocking is @c false, @a pcbRead is not NULL, + * and no data was available. @a *pcbRead will be set to 0. + * @retval VINF_EOF when trying to read __beyond__ the end of the stream and + * @a pcbRead is not NULL (it will be set to the number of bytes read, + * or 0 if the end of the stream was reached before this call). + * When the last byte of the read request is the last byte in the + * stream, this status code will not be used. However, VINF_EOF is + * returned when attempting to read 0 bytes while standing at the end + * of the stream. + * @retval VERR_EOF when trying to read __beyond__ the end of the stream and + * @a pcbRead is NULL. + * @retval VERR_ACCESS_DENIED if the stream is not readable. + * + * @param hVfsIos The VFS I/O stream handle. + * @param off Where to read at, -1 for the current position. + * @param pvBuf Where to store the read bytes. + * @param cbToRead The number of bytes to read. + * @param fBlocking Whether the call is blocking (@c true) or not. If + * not, the @a pcbRead parameter must not be NULL. + * @param pcbRead Where to always store the number of bytes actually + * read. This can be NULL if @a fBlocking is true. + * @sa RTVfsFileRead, RTFileRead, RTPipeRead, RTPipeReadBlocking, + * RTSocketRead + */ +RTDECL(int) RTVfsIoStrmReadAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead); + +/** + * Reads the remainder of the stream into a memory buffer. + * + * For simplifying string-style processing, the is a zero byte after the + * returned buffer, making sure it can be used as a zero terminated string. + * + * @returns IPRT status code. + * @param hVfsIos The VFS I/O stream handle. + * @param ppvBuf Where to return the buffer. Must pass to + * RTVfsIoStrmReadAllFree for freeing, not RTMemFree! + * @param pcbBuf Where to return the buffer size. + */ +RTDECL(int) RTVfsIoStrmReadAll(RTVFSIOSTREAM hVfsIos, void **ppvBuf, size_t *pcbBuf); + +/** + * Free memory buffer returned by RTVfsIoStrmReadAll. + * + * @param pvBuf What RTVfsIoStrmReadAll returned. + * @param cbBuf What RTVfsIoStrmReadAll returned. + */ +RTDECL(void) RTVfsIoStrmReadAllFree(void *pvBuf, size_t cbBuf); + +/** + * Write bytes to the I/O stream. + * + * @returns IPRT status code. + * @retval VERR_ACCESS_DENIED if the stream is not writable. + * + * @param hVfsIos The VFS I/O stream handle. + * @param pvBuf The bytes to write. + * @param cbToWrite The number of bytes to write. + * @param fBlocking Whether the call is blocking (@c true) or not. If + * not, the @a pcbWritten parameter must not be NULL. + * @param pcbWritten Where to always store the number of bytes actually + * written. This can be NULL if @a fBlocking is true. + * @sa RTVfsFileWrite, RTFileWrite, RTPipeWrite, RTPipeWriteBlocking, + * RTSocketWrite + */ +RTDECL(int) RTVfsIoStrmWrite(RTVFSIOSTREAM hVfsIos, const void *pvBuf, size_t cbToWrite, bool fBlocking, size_t *pcbWritten); +RTDECL(int) RTVfsIoStrmWriteAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, const void *pvBuf, size_t cbToWrite, bool fBlocking, size_t *pcbWritten); + +/** + * Reads bytes from the I/O stream into a scatter buffer. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and the number of bytes read written to @a pcbRead. + * @retval VINF_TRY_AGAIN if @a fBlocking is @c false, @a pcbRead is not NULL, + * and no data was available. @a *pcbRead will be set to 0. + * @retval VINF_EOF when trying to read __beyond__ the end of the stream and + * @a pcbRead is not NULL (it will be set to the number of bytes read, + * or 0 if the end of the stream was reached before this call). + * When the last byte of the read request is the last byte in the + * stream, this status code will not be used. However, VINF_EOF is + * returned when attempting to read 0 bytes while standing at the end + * of the stream. + * @retval VERR_EOF when trying to read __beyond__ the end of the stream and + * @a pcbRead is NULL. + * @retval VERR_ACCESS_DENIED if the stream is not readable. + * + * @param hVfsIos The VFS I/O stream handle. + * @param off Where to read at, -1 for the current position. + * @param pSgBuf Pointer to a scatter buffer descriptor. The number + * of bytes described by the segments is what will be + * attemted read. + * @param fBlocking Whether the call is blocking (@c true) or not. If + * not, the @a pcbRead parameter must not be NULL. + * @param pcbRead Where to always store the number of bytes actually + * read. This can be NULL if @a fBlocking is true. + * @sa RTFileSgRead, RTSocketSgRead, RTPipeRead, RTPipeReadBlocking + */ +RTDECL(int) RTVfsIoStrmSgRead(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead); + +/** + * Write bytes to the I/O stream from a gather buffer. + * + * @returns IPRT status code. + * @retval VERR_ACCESS_DENIED if the stream is not writable. + * + * @param hVfsIos The VFS I/O stream handle. + * @param off Where to write at, -1 for the current position. + * @param pSgBuf Pointer to a gather buffer descriptor. The number + * of bytes described by the segments is what will be + * attemted written. + * @param fBlocking Whether the call is blocking (@c true) or not. If + * not, the @a pcbWritten parameter must not be NULL. + * @param pcbWritten Where to always store the number of bytes actually + * written. This can be NULL if @a fBlocking is true. + * @sa RTFileSgWrite, RTSocketSgWrite + */ +RTDECL(int) RTVfsIoStrmSgWrite(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten); + +/** + * Flush any buffered data to the I/O stream. + * + * @returns IPRT status code. + * @param hVfsIos The VFS I/O stream handle. + * @sa RTVfsFileFlush, RTFileFlush, RTPipeFlush + */ +RTDECL(int) RTVfsIoStrmFlush(RTVFSIOSTREAM hVfsIos); + +/** + * Poll for events. + * + * @returns IPRT status code. + * @param hVfsIos The VFS I/O stream handle. + * @param fEvents The events to poll for (RTPOLL_EVT_XXX). + * @param cMillies How long to wait for event to eventuate. + * @param fIntr Whether the wait is interruptible and can return + * VERR_INTERRUPTED (@c true) or if this condition + * should be hidden from the caller (@c false). + * @param pfRetEvents Where to return the event mask. + * @sa RTVfsFilePoll, RTPollSetAdd, RTPoll, RTPollNoResume. + */ +RTDECL(int) RTVfsIoStrmPoll(RTVFSIOSTREAM hVfsIos, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, + uint32_t *pfRetEvents); +/** + * Tells the current I/O stream position. + * + * @returns Zero or higher - where to return the I/O stream offset. Values + * below zero are IPRT status codes (VERR_XXX). + * @param hVfsIos The VFS I/O stream handle. + * @sa RTFileTell + */ +RTDECL(RTFOFF) RTVfsIoStrmTell(RTVFSIOSTREAM hVfsIos); + +/** + * Skips @a cb ahead in the stream. + * + * @returns IPRT status code. + * @param hVfsIos The VFS I/O stream handle. + * @param cb The number bytes to skip. + */ +RTDECL(int) RTVfsIoStrmSkip(RTVFSIOSTREAM hVfsIos, RTFOFF cb); + +/** + * Fills the stream with @a cb zeros. + * + * @returns IPRT status code. + * @param hVfsIos The VFS I/O stream handle. + * @param cb The number of zero bytes to insert. + */ +RTDECL(int) RTVfsIoStrmZeroFill(RTVFSIOSTREAM hVfsIos, RTFOFF cb); + +/** + * Checks if we're at the end of the I/O stream. + * + * @returns true if at EOS, otherwise false. + * @param hVfsIos The VFS I/O stream handle. + */ +RTDECL(bool) RTVfsIoStrmIsAtEnd(RTVFSIOSTREAM hVfsIos); + +/** + * Get the RTFILE_O_XXX flags for the I/O stream. + * + * @returns RTFILE_O_XXX, 0 on failure. + * @param hVfsIos The VFS I/O stream handle. + */ +RTDECL(uint64_t) RTVfsIoStrmGetOpenFlags(RTVFSIOSTREAM hVfsIos); + +/** + * Process the rest of the stream, checking if it's all valid UTF-8 encoding. + * + * @returns IPRT status code. + * + * @param hVfsIos The VFS I/O stream handle. + * @param fFlags Flags governing the validation, see + * RTVFS_VALIDATE_UTF8_XXX. + * @param poffError Where to return the error offset. Optional. + */ +RTDECL(int) RTVfsIoStrmValidateUtf8Encoding(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, PRTFOFF poffError); + +/** @defgroup RTVFS_VALIDATE_UTF8_XXX RTVfsIoStrmValidateUtf8Encoding flags. + * @{ */ +/** The text must not contain any null terminator codepoints. */ +#define RTVFS_VALIDATE_UTF8_NO_NULL RT_BIT_32(0) +/** The codepoints must be in the range covered by RTC-3629. */ +#define RTVFS_VALIDATE_UTF8_BY_RTC_3629 RT_BIT_32(1) +/** Mask of valid flags. */ +#define RTVFS_VALIDATE_UTF8_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** + * Printf-like write function. + * + * @returns Number of characters written on success, negative error status on + * failure. + * @param hVfsIos The VFS I/O stream handle to write to. + * @param pszFormat The format string. + * @param ... Format arguments. + */ +RTDECL(ssize_t) RTVfsIoStrmPrintf(RTVFSIOSTREAM hVfsIos, const char *pszFormat, ...); + +/** + * Printf-like write function. + * + * @returns Number of characters written on success, negative error status on + * failure. + * @param hVfsIos The VFS I/O stream handle to write to. + * @param pszFormat The format string. + * @param va Format arguments. + */ +RTDECL(ssize_t) RTVfsIoStrmPrintfV(RTVFSIOSTREAM hVfsIos, const char *pszFormat, va_list va); + +/** + * VFS I/O stream output buffer structure to use with + * RTVfsIoStrmStrOutputCallback(). + */ +typedef struct VFSIOSTRMOUTBUF +{ + /** The I/O stream handle. */ + RTVFSIOSTREAM hVfsIos; + /** Size of this structure (for sanity). */ + size_t cbSelf; + /** Status code of the operation. */ + int rc; + /** Current offset into szBuf (number of output bytes pending). */ + size_t offBuf; + /** Modest output buffer. */ + char szBuf[256]; +} VFSIOSTRMOUTBUF; +/** Pointer to an VFS I/O stream output buffer for use with + * RTVfsIoStrmStrOutputCallback() */ +typedef VFSIOSTRMOUTBUF *PVFSIOSTRMOUTBUF; + +/** Initializer for a VFS I/O stream output buffer. */ +#define VFSIOSTRMOUTBUF_INIT(a_pOutBuf, a_hVfsIos) \ + do { \ + (a_pOutBuf)->hVfsIos = a_hVfsIos; \ + (a_pOutBuf)->cbSelf = sizeof(*(a_pOutBuf)); \ + (a_pOutBuf)->rc = VINF_SUCCESS; \ + (a_pOutBuf)->offBuf = 0; \ + (a_pOutBuf)->szBuf[0] = '\0'; \ + } while (0) + +/** + * @callback_method_impl{FNRTSTROUTPUT, + * For use with VFSIOSTRMOUTBUF. + * + * Users must use VFSIOSTRMOUTBUF_INIT to initialize a VFSIOSTRMOUTBUF and pass + * that as the outputter argument to the function this callback is handed to.} + */ +RTDECL(size_t) RTVfsIoStrmStrOutputCallback(void *pvArg, const char *pachChars, size_t cbChars); + +/** @} */ + + +/** @defgroup grp_rt_vfs_file VFS File API + * @{ + */ +RTDECL(int) RTVfsFileOpen(RTVFS hVfs, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile); + +/** + * Create a VFS file handle from a standard IPRT file handle (RTFILE). + * + * @returns IPRT status code. + * @param hFile The standard IPRT file handle. + * @param fOpen The flags the handle was opened with. Pass 0 to + * have these detected. + * @param fLeaveOpen Whether to leave the handle open when the VFS file + * is released, or to close it (@c false). + * @param phVfsFile Where to return the VFS file handle. + */ +RTDECL(int) RTVfsFileFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSFILE phVfsFile); +RTDECL(RTHCUINTPTR) RTVfsFileToNative(RTFILE hVfsFile); + +/** + * Convenience function combining RTFileOpen with RTVfsFileFromRTFile. + * + * @returns IPRT status code. + * @param pszFilename The path to the file in the normal file system. + * @param fOpen The flags to pass to RTFileOpen when opening the + * file, i.e. RTFILE_O_XXX. + * @param phVfsFile Where to return the VFS file handle. + */ +RTDECL(int) RTVfsFileOpenNormal(const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile); + +/** + * Convert the VFS file handle to a VFS I/O stream handle. + * + * @returns The VFS I/O stream handle on success, this must be released. + * NIL_RTVFSIOSTREAM if the file handle is invalid. + * @param hVfsFile The VFS file handle. + * @sa RTVfsIoStrmToFile + */ +RTDECL(RTVFSIOSTREAM) RTVfsFileToIoStream(RTVFSFILE hVfsFile); + +/** + * Retains a reference to the VFS file handle. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param hVfsFile The VFS file handle. + */ +RTDECL(uint32_t) RTVfsFileRetain(RTVFSFILE hVfsFile); +RTDECL(uint32_t) RTVfsFileRetainDebug(RTVFSFILE hVfsFile, RT_SRC_POS_DECL); + +/** + * Releases a reference to the VFS file handle. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param hVfsFile The VFS file handle. + */ +RTDECL(uint32_t) RTVfsFileRelease(RTVFSFILE hVfsFile); + +/** + * Query information about the object. + * + * @returns IPRT status code. + * @retval VERR_NOT_SUPPORTED if the @a enmAddAttr value is not handled by the + * implementation. + * + * @param hVfsFile The VFS file handle. + * @param pObjInfo Where to return the info. + * @param enmAddAttr Which additional attributes should be retrieved. + * @sa RTVfsObjQueryInfo, RTVfsFsStrmQueryInfo, RTVfsDirQueryInfo, + * RTVfsIoStrmQueryInfo, RTVfsFileQueryInfo, RTFileQueryInfo, + * RTPathQueryInfo. + */ +RTDECL(int) RTVfsFileQueryInfo(RTVFSFILE hVfsFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr); + +/** + * Read bytes from the file at the current position. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and the number of bytes read written to @a pcbRead. + * @retval VINF_EOF when trying to read __beyond__ the end of the file and + * @a pcbRead is not NULL (it will be set to the number of bytes read, + * or 0 if the end of the file was reached before this call). + * When the last byte of the read request is the last byte in the + * file, this status code will not be used. However, VINF_EOF is + * returned when attempting to read 0 bytes while standing at the end + * of the file. + * @retval VERR_EOF when trying to read __beyond__ the end of the file and + * @a pcbRead is NULL. + * @retval VERR_ACCESS_DENIED if the file is not readable. + * + * @param hVfsFile The VFS file handle. + * @param pvBuf Where to store the read bytes. + * @param cbToRead The number of bytes to read. + * @param pcbRead Where to always store the number of bytes actually + * read. Optional. + * @sa RTVfsIoStrmRead, RTFileRead, RTPipeRead, RTPipeReadBlocking, + * RTSocketRead + */ +RTDECL(int) RTVfsFileRead(RTVFSFILE hVfsFile, void *pvBuf, size_t cbToRead, size_t *pcbRead); +RTDECL(int) RTVfsFileReadAt(RTVFSFILE hVfsFile, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead); + +/** + * Write bytes to the file at the current position. + * + * @returns IPRT status code. + * @retval VERR_ACCESS_DENIED if the file is not writable. + * + * @param hVfsFile The VFS file handle. + * @param pvBuf The bytes to write. + * @param cbToWrite The number of bytes to write. + * @param pcbWritten Where to always store the number of bytes actually + * written. This can be NULL. + * @sa RTVfsIoStrmRead, RTFileWrite, RTPipeWrite, RTPipeWriteBlocking, + * RTSocketWrite + */ +RTDECL(int) RTVfsFileWrite(RTVFSFILE hVfsFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); +RTDECL(int) RTVfsFileWriteAt(RTVFSFILE hVfsFile, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten); + + +/** + * Reads bytes from the file into a scatter buffer. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS and the number of bytes read written to @a pcbRead. + * @retval VINF_TRY_AGAIN if @a fBlocking is @c false, @a pcbRead is not NULL, + * and no data was available. @a *pcbRead will be set to 0. + * @retval VINF_EOF when trying to read __beyond__ the end of the stream and + * @a pcbRead is not NULL (it will be set to the number of bytes read, + * or 0 if the end of the stream was reached before this call). + * When the last byte of the read request is the last byte in the + * stream, this status code will not be used. However, VINF_EOF is + * returned when attempting to read 0 bytes while standing at the end + * of the stream. + * @retval VERR_EOF when trying to read __beyond__ the end of the stream and + * @a pcbRead is NULL. + * @retval VERR_ACCESS_DENIED if the stream is not readable. + * + * @param hVfsFile The VFS file handle. + * @param off Where to read at, -1 for the current position. + * @param pSgBuf Pointer to a scatter buffer descriptor. The number + * of bytes described by the segments is what will be + * attemted read. + * @param fBlocking Whether the call is blocking (@c true) or not. If + * not, the @a pcbRead parameter must not be NULL. + * @param pcbRead Where to always store the number of bytes actually + * read. This can be NULL if @a fBlocking is true. + * @sa RTFileSgRead, RTSocketSgRead, RTPipeRead, RTPipeReadBlocking + */ +RTDECL(int) RTVfsFileSgRead(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead); + +/** + * Write bytes to the file from a gather buffer. + * + * @returns IPRT status code. + * @retval VERR_ACCESS_DENIED if the stream is not writable. + * + * @param hVfsFile The VFS file handle. + * @param off Where to write at, -1 for the current position. + * @param pSgBuf Pointer to a gather buffer descriptor. The number + * of bytes described by the segments is what will be + * attemted written. + * @param fBlocking Whether the call is blocking (@c true) or not. If + * not, the @a pcbWritten parameter must not be NULL. + * @param pcbWritten Where to always store the number of bytes actually + * written. This can be NULL if @a fBlocking is true. + * @sa RTFileSgWrite, RTSocketSgWrite + */ +RTDECL(int) RTVfsFileSgWrite(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten); + +/** + * Flush any buffered data to the file. + * + * @returns IPRT status code. + * @param hVfsFile The VFS file handle. + * @sa RTVfsIoStrmFlush, RTFileFlush, RTPipeFlush + */ +RTDECL(int) RTVfsFileFlush(RTVFSFILE hVfsFile); + +/** + * Poll for events. + * + * @returns IPRT status code. + * @param hVfsFile The VFS file handle. + * @param fEvents The events to poll for (RTPOLL_EVT_XXX). + * @param cMillies How long to wait for event to eventuate. + * @param fIntr Whether the wait is interruptible and can return + * VERR_INTERRUPTED (@c true) or if this condition + * should be hidden from the caller (@c false). + * @param pfRetEvents Where to return the event mask. + * @sa RTVfsIoStrmPoll, RTPollSetAdd, RTPoll, RTPollNoResume. + */ +RTDECL(RTFOFF) RTVfsFilePoll(RTVFSFILE hVfsFile, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, + uint32_t *pfRetEvents); + +/** + * Tells the current file position. + * + * @returns Zero or higher - where to return the file offset. Values + * below zero are IPRT status codes (VERR_XXX). + * @param hVfsFile The VFS file handle. + * @sa RTFileTell, RTVfsIoStrmTell. + */ +RTDECL(RTFOFF) RTVfsFileTell(RTVFSFILE hVfsFile); + +/** + * Changes the current read/write position of a file. + * + * @returns IPRT status code. + * + * @param hVfsFile The VFS file handle. + * @param offSeek The seek offset. + * @param uMethod The seek method. + * @param poffActual Where to optionally return the new file offset. + * + * @sa RTFileSeek + */ +RTDECL(int) RTVfsFileSeek(RTVFSFILE hVfsFile, RTFOFF offSeek, uint32_t uMethod, uint64_t *poffActual); + +/** + * Sets the size of a file. + * + * This may also be used for preallocating space + * (RTVFSFILE_SIZE_F_PREALLOC_KEEP_SIZE). + * + * @returns IPRT status code. + * @retval VERR_ACCESS_DENIED if handle isn't writable. + * @retval VERR_WRITE_PROTECT if read-only file system. + * @retval VERR_FILE_TOO_BIG if cbSize is larger than what the file system can + * theoretically deal with. + * @retval VERR_DISK_FULL if the file system if full. + * @retval VERR_NOT_SUPPORTED if fFlags indicates some operation that's not + * supported by the file system / host operating system. + * + * @param hVfsFile The VFS file handle. + * @param cbSize The new file size. + * @param fFlags RTVFSFILE_SIZE_F_NORMAL, RTVFSFILE_SIZE_F_GROW, or + * RTVFSFILE_SIZE_F_GROW_KEEP_SIZE. + * + * @sa RTFileSetSize, RTFileSetAllocationSize + */ +RTDECL(int) RTVfsFileSetSize(RTVFSFILE hVfsFile, uint64_t cbSize, uint32_t fFlags); + +/** @name RTVFSFILE_SIZE_F_XXX - RTVfsFileSetSize flags. + * @{ */ +/** Normal truncate or grow (zero'ed) like RTFileSetSize . */ +#define RTVFSFILE_SIZE_F_NORMAL UINT32_C(0x00000001) +/** Only grow the file, ignore call if cbSize would truncate the file. + * This is what RTFileSetAllocationSize does by default. */ +#define RTVFSFILE_SIZE_F_GROW UINT32_C(0x00000002) +/** Only grow the file, ignore call if cbSize would truncate the file. + * This is what RTFileSetAllocationSize does by default. */ +#define RTVFSFILE_SIZE_F_GROW_KEEP_SIZE UINT32_C(0x00000003) +/** Action mask. */ +#define RTVFSFILE_SIZE_F_ACTION_MASK UINT32_C(0x00000003) +/** Validate the flags. + * Will reference @a a_fFlags more than once. */ +#define RTVFSFILE_SIZE_F_IS_VALID(a_fFlags) \ + ( !((a_fFlags) & ~RTVFSFILE_SIZE_F_ACTION_MASK) && ((a_fFlags) & RTVFSFILE_SIZE_F_ACTION_MASK) != 0 ) +/** Mask of valid flags. */ +#define RTFILE_ALLOC_SIZE_F_VALID (RTFILE_ALLOC_SIZE_F_KEEP_SIZE) +/** @} */ + + +RTDECL(int) RTVfsFileQuerySize(RTVFSFILE hVfsFile, uint64_t *pcbSize); +RTDECL(RTFOFF) RTVfsFileGetMaxSize(RTVFSFILE hVfsFile); +RTDECL(int) RTVfsFileQueryMaxSize(RTVFSFILE hVfsFile, uint64_t *pcbMax); + +/** + * Get the RTFILE_O_XXX flags for the I/O stream. + * + * @returns RTFILE_O_XXX, 0 on failure. + * @param hVfsFile The VFS file handle. + */ +RTDECL(uint64_t) RTVfsFileGetOpenFlags(RTVFSFILE hVfsFile); + +/** + * Printf-like write function. + * + * @returns Number of characters written on success, negative error status on + * failure. + * @param hVfsFile The VFS file handle to write to. + * @param pszFormat The format string. + * @param ... Format arguments. + */ +RTDECL(ssize_t) RTVfsFilePrintf(RTVFSFILE hVfsFile, const char *pszFormat, ...); + +/** + * Printf-like write function. + * + * @returns Number of characters written on success, negative error status on + * failure. + * @param hVfsFile The VFS file handle to write to. + * @param pszFormat The format string. + * @param va Format arguments. + */ +RTDECL(ssize_t) RTVfsFilePrintfV(RTVFSFILE hVfsFile, const char *pszFormat, va_list va); + +/** @} */ + + +#ifdef DEBUG +# undef RTVfsRetain +# define RTVfsRetain(hVfs) RTVfsRetainDebug(hVfs, RT_SRC_POS) +# undef RTVfsObjRetain +# define RTVfsObjRetain(hVfsObj) RTVfsObjRetainDebug(hVfsObj, RT_SRC_POS) +# undef RTVfsDirRetain +# define RTVfsDirRetain(hVfsDir) RTVfsDirRetainDebug(hVfsDir, RT_SRC_POS) +# undef RTVfsFileRetain +# define RTVfsFileRetain(hVfsFile) RTVfsFileRetainDebug(hVfsFile, RT_SRC_POS) +# undef RTVfsIoStrmRetain +# define RTVfsIoStrmRetain(hVfsIos) RTVfsIoStrmRetainDebug(hVfsIos, RT_SRC_POS) +# undef RTVfsFsStrmRetain +# define RTVfsFsStrmRetain(hVfsFss) RTVfsFsStrmRetainDebug(hVfsFss, RT_SRC_POS) +#endif + + + +/** @defgroup grp_rt_vfs_misc VFS Miscellaneous + * @{ + */ + +/** + * Memorizes the I/O stream as a file backed by memory. + * + * @returns IPRT status code. + * + * @param hVfsIos The VFS I/O stream to memorize. This will be read + * to the end on success, on failure its position is + * undefined. + * @param fFlags A combination of RTFILE_O_READ and RTFILE_O_WRITE. + * @param phVfsFile Where to return the handle to the memory file on + * success. + */ +RTDECL(int) RTVfsMemorizeIoStreamAsFile(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, PRTVFSFILE phVfsFile); + +/** + * Creates a VFS file from a memory buffer. + * + * @returns IPRT status code. + * + * @param fFlags A combination of RTFILE_O_READ and RTFILE_O_WRITE. + * @param pvBuf The buffer. This will be copied and not referenced + * after this function returns. + * @param cbBuf The buffer size. + * @param phVfsFile Where to return the handle to the memory file on + * success. + */ +RTDECL(int) RTVfsFileFromBuffer(uint32_t fFlags, void const *pvBuf, size_t cbBuf, PRTVFSFILE phVfsFile); + +/** + * Creates a memory backed VFS file object for read and write. + * + * @returns IPRT status code. + * + * @param hVfsIos The VFS I/O stream to memorize. This will be read + * to the end on success, on failure its position is + * undefined. + * @param cbEstimate The estimated file size. + * @param phVfsFile Where to return the handle to the memory file on + * success. + * @sa RTVfsMemIoStrmCreate + */ +RTDECL(int) RTVfsMemFileCreate(RTVFSIOSTREAM hVfsIos, size_t cbEstimate, PRTVFSFILE phVfsFile); + +/** + * Creates a memory backed VFS file object for read and write. + * + * @returns IPRT status code. + * + * @param hVfsIos The VFS I/O stream to memorize. This will be read + * to the end on success, on failure its position is + * undefined. + * @param cbEstimate The estimated file size. + * @param phVfsIos Where to return the handle to the memory I/O stream + * on success. + * @sa RTVfsMemFileCreate + */ +RTDECL(int) RTVfsMemIoStrmCreate(RTVFSIOSTREAM hVfsIos, size_t cbEstimate, PRTVFSIOSTREAM phVfsIos); + +/** + * Pumps data from one I/O stream to another. + * + * The data is read in chunks from @a hVfsIosSrc and written to @a hVfsIosDst + * until @a hVfsIosSrc indicates end of stream. + * + * @returns IPRT status code + * + * @param hVfsIosSrc The input stream. + * @param hVfsIosDst The output stream. + * @param cbBufHint Hints at a good temporary buffer size, pass 0 if + * clueless. + */ +RTDECL(int) RTVfsUtilPumpIoStreams(RTVFSIOSTREAM hVfsIosSrc, RTVFSIOSTREAM hVfsIosDst, size_t cbBufHint); + + +/** + * Creates a progress wrapper for an I/O stream. + * + * @returns IRPT status code. + * @param hVfsIos The I/O stream to wrap. + * @param pfnProgress The progress callback. The return code is + * ignored by default, see + * RTVFSPROGRESS_F_CANCELABLE. + * @param pvUser The user argument to @a pfnProgress. + * @param fFlags RTVFSPROGRESS_F_XXX + * @param cbExpectedRead The expected number of bytes read. + * @param cbExpectedWritten The execpted number of bytes written. + * @param phVfsIos Where to return the I/O stream handle. + */ +RTDECL(int) RTVfsCreateProgressForIoStream(RTVFSIOSTREAM hVfsIos, PFNRTPROGRESS pfnProgress, void *pvUser, uint32_t fFlags, + uint64_t cbExpectedRead, uint64_t cbExpectedWritten, PRTVFSIOSTREAM phVfsIos); + +/** + * Creates a progress wrapper for a file stream. + * + * @returns IRPT status code. + * @param hVfsFile The file to wrap. + * @param pfnProgress The progress callback. The return code is + * ignored by default, see + * RTVFSPROGRESS_F_CANCELABLE. + * @param pvUser The user argument to @a pfnProgress. + * @param fFlags RTVFSPROGRESS_F_XXX + * @param cbExpectedRead The expected number of bytes read. + * @param cbExpectedWritten The execpted number of bytes written. + * @param phVfsFile Where to return the file handle. + */ +RTDECL(int) RTVfsCreateProgressForFile(RTVFSFILE hVfsFile, PFNRTPROGRESS pfnProgress, void *pvUser, uint32_t fFlags, + uint64_t cbExpectedRead, uint64_t cbExpectedWritten, PRTVFSFILE phVfsFile); + +/** @name RTVFSPROGRESS_F_XXX - Flags for RTVfsCreateProcessForIoStream and + * RTVfsCreateProcessForFile. + * @{ */ +/** Cancel if the callback returns a failure status code. + * This isn't default behavior because the cancelation is delayed one I/O + * operation in most cases and it's uncertain how the VFS user will handle the + * cancellation status code. */ +#define RTVFSPROGRESS_F_CANCELABLE RT_BIT_32(0) +/** Account forward seeks as reads. */ +#define RTVFSPROGRESS_F_FORWARD_SEEK_AS_READ RT_BIT_32(1) +/** Account fprward seeks as writes. */ +#define RTVFSPROGRESS_F_FORWARD_SEEK_AS_WRITE RT_BIT_32(2) +/** Valid bits. */ +#define RTVFSPROGRESS_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ + + +/** + * Create an I/O stream instance performing simple sequential read-ahead. + * + * @returns IPRT status code. + * @param hVfsIos The input stream to perform read ahead on. If this is + * actually for a file object, the returned I/O stream + * handle can also be cast to a file handle. + * @param fFlags Flags reserved for future use, MBZ. + * @param cBuffers How many read ahead buffers to use. Specify 0 for + * default value. + * @param cbBuffer The size of each read ahead buffer. Specify 0 for + * default value. + * @param phVfsIos Where to return the read ahead I/O stream handle. + * + * @remarks Careful using this on a message pipe or socket. The reads are + * performed in blocked mode and it may be host and/or implementation + * dependent whether they will return ready data immediate or wait + * until there's a whole @a cbBuffer (or default) worth ready. + * + * @sa RTVfsCreateReadAheadForFile + */ +RTDECL(int) RTVfsCreateReadAheadForIoStream(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, uint32_t cBuffers, uint32_t cbBuffer, + PRTVFSIOSTREAM phVfsIos); + +/** + * Create an I/O stream instance performing simple sequential read-ahead. + * + * @returns IPRT status code. + * @param hVfsFile The input file to perform read ahead on. + * @param fFlags Flags reserved for future use, MBZ. + * @param cBuffers How many read ahead buffers to use. Specify 0 for + * default value. + * @param cbBuffer The size of each read ahead buffer. Specify 0 for + * default value. + * @param phVfsFile Where to return the read ahead file handle. + * @sa RTVfsCreateReadAheadForIoStream + */ +RTDECL(int) RTVfsCreateReadAheadForFile(RTVFSFILE hVfsFile, uint32_t fFlags, uint32_t cBuffers, uint32_t cbBuffer, + PRTVFSFILE phVfsFile); + + +/** + * Create a file system stream for writing to a directory. + * + * This is just supposed to be a drop in replacement for the TAR creator stream + * that instead puts the files and stuff in a directory instead of a TAR + * archive. In addition, it has an undo feature for simplying cleaning up after + * a botched run + * + * @returns IPRT status code. + * @param hVfsBaseDir The base directory. + * @param fFlags RTVFSFSS2DIR_F_XXX + * @param phVfsFss Where to return the FSS handle. + * @sa RTVfsFsStrmToNormalDir, RTVfsFsStrmToDirUndo + */ +RTDECL(int) RTVfsFsStrmToDir(RTVFSDIR hVfsBaseDir, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss); + +/** + * Create a file system stream for writing to a normal directory. + * + * This is just supposed to be a drop in replacement for the TAR creator stream + * that instead puts the files and stuff in a directory instead of a TAR + * archive. In addition, it has an undo feature for simplying cleaning up after + * a botched run + * + * @returns IPRT status code. + * @param pszBaseDir The base directory. Must exist. + * @param fFlags RTVFSFSS2DIR_F_XXX + * @param phVfsFss Where to return the FSS handle. + * @sa RTVfsFsStrmToDir, RTVfsFsStrmToDirUndo + */ +RTDECL(int) RTVfsFsStrmToNormalDir(const char *pszBaseDir, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss); + +/** @name RTVFSFSS2DIR_F_XXX - Flags for RTVfsFsStrmToNormalDir + * @{ */ +/** Overwrite existing files (default is to not overwrite anything). */ +#define RTVFSFSS2DIR_F_OVERWRITE_FILES RT_BIT_32(0) +/** Valid bits. */ +#define RTVFSFSS2DIR_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +/** + * Deletes files, directories, symlinks and stuff created by a FSS returned by + * RTVfsFsStrmToNormalDir or RTVfsFsStrmToDir. + * + * @returns IPRT status code. + * @param hVfsFss The write-to-directory FSS handle. + */ +RTDECL(int) RTVfsFsStrmToDirUndo(RTVFSFSSTREAM hVfsFss); + + + +/** @} */ + + +/** @defgroup grp_rt_vfs_chain VFS Chains + * + * VFS chains is for doing pipe like things with VFS objects from the command + * line. Imagine you want to cat the readme.gz of an ISO you could do + * something like: + * RTCat :iprtvfs:file(stdfile,live.iso)|vfs(isofs)|iso(open,readme.gz)|ios(gunzip) + * or + * RTCat :iprtvfs:file(stdfile,live.iso)|ios(isofs,readme.gz)|ios(gunzip) + * + * Or say you want to read the README.TXT on a floppy image: + * RTCat :iprtvfs:file(stdfile,floppy.img,r)|vfs(fat)|ios(open,README.TXT) + * or + * RTCat :iprtvfs:file(stdfile,floppy.img,r)|vfs(fat)|README.TXT + * + * Or in the other direction, you want to write a STUFF.TGZ file to the above + * floppy image, using a lazy writer thread for compressing the data: + * RTTar cf :iprtvfs:file(stdfile,floppy.img,rw)|ios(fat,STUFF.TGZ)|ios(gzip)|ios(push) . + * + * + * A bit more formally: + * :iprtvfs:{type}({provider}[,provider-args])[{separator}{type}...][{separator}{path}] + * + * The @c type refers to VFS object that should be created by the @c provider. + * Valid types: + * - vfs: A virtual file system (volume). + * - fss: A file system stream (e.g. tar). + * - ios: An I/O stream. + * - file: A file. + * - dir: A directory. + * - sym: A symbolic link (not sure how useful this is). + * + * The @c provider refers to registered chain element providers (see + * RTVFSCHAINELEMENTREG for how that works internally). These are asked to + * create a VFS object of the specified type using the given arguments (if any). + * Default providers: + * - std: Standard file, directory and file system. + * - open: Opens a file, I/O stream or directory in a vfs or directory object. + * - pull: Read-ahead buffering thread on file or I/O stream. + * - push: Lazy-writer buffering thread on file or I/O stream. + * - gzip: Compresses an I/O stream. + * - gunzip: Decompresses an I/O stream. + * - fat: FAT file system accessor. + * - isofs: ISOFS file system accessor. + * + * As element @c separator we allow both colon (':') and the pipe character + * ('|'). The latter the conventional one, but since it's inconvenient on the + * command line, colon is provided as an alternative. + * + * In the final element we allow a simple @a path to be specified instead of the + * type-provider-arguments stuff. The previous object must be a directory, file + * system or file system stream. The application will determin exactly which + * operation or operations which will be performed. + * + * @{ + */ + +/** The path prefix used to identify an VFS chain specification. */ +#define RTVFSCHAIN_SPEC_PREFIX ":iprtvfs:" + +RTDECL(int) RTVfsChainOpenVfs(const char *pszSpec, PRTVFS phVfs, uint32_t *poffError, PRTERRINFO pErrInfo); +RTDECL(int) RTVfsChainOpenFsStream(const char *pszSpec, PRTVFSFSSTREAM phVfsFss, uint32_t *poffError, PRTERRINFO pErrInfo); + +/** + * Opens any kind of file system object. + * + * @returns IPRT status code. + * @param pszSpec The VFS chain specification or plain path. + * @param fFileOpen RTFILE_O_XXX flags. + * @param fObjFlags More flags: RTVFSOBJ_F_XXX, RTPATH_F_XXX. + * @param phVfsObj Where to return the handle to the opened object. + * @param poffError Where to on error return an offset into @a pszSpec + * of what cause the error. Optional. + * @param pErrInfo Where to return additional error information. + * Optional. + */ +RTDECL(int) RTVfsChainOpenObj(const char *pszSpec, uint64_t fFileOpen, uint32_t fObjFlags, + PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo); + +RTDECL(int) RTVfsChainOpenDir(const char *pszSpec, uint32_t fOpen, PRTVFSDIR phVfsDir, uint32_t *poffError, PRTERRINFO pErrInfo); +RTDECL(int) RTVfsChainOpenParentDir(const char *pszSpec, uint32_t fOpen, PRTVFSDIR phVfsDir, const char **ppszChild, + uint32_t *poffError, PRTERRINFO pErrInfo); +RTDECL(int) RTVfsChainOpenFile(const char *pszSpec, uint64_t fOpen, PRTVFSFILE phVfsFile, uint32_t *poffError, PRTERRINFO pErrInfo); +RTDECL(int) RTVfsChainOpenIoStream(const char *pszSpec, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos, uint32_t *poffError, PRTERRINFO pErrInfo); +RTDECL(int) RTVfsChainOpenSymlink(const char *pszSpec, PRTVFSSYMLINK phVfsSym, uint32_t *poffError, PRTERRINFO pErrInfo); + +RTDECL(int) RTVfsChainQueryInfo(const char *pszSpec, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, + uint32_t fFlags, uint32_t *poffError, PRTERRINFO pErrInfo); + +/** + * Tests if the given string is a chain specification or not. + * + * @returns true if it is, false if it isn't. + * @param pszSpec The alleged chain spec. + */ +RTDECL(bool) RTVfsChainIsSpec(const char *pszSpec); + +/** + * Queries the path from the final element. + * + * @returns IPRT status code. + * @retval VERR_VFS_CHAIN_NOT_PATH_ONLY if the final element isn't just a + * simple path. + * @param pszSpec The chain spec. + * @param ppszFinalPath Where to return a copy of the final path on success. + * Call RTStrFree when done. + * @param poffError Where to on error return an offset into @a pszSpec + * of what cause the error. Optional. + * + */ +RTDECL(int) RTVfsChainQueryFinalPath(const char *pszSpec, char **ppszFinalPath, uint32_t *poffError); + +/** + * Splits the given chain spec into a final path and the preceeding spec. + * + * This works on plain paths too. + * + * @returns IPRT status code. + * @param pszSpec The chain spec to split. This will be modified! + * @param ppszSpec Where to return the pointer to the chain spec part. + * This is set to NULL if it's a plain path or a chain + * spec with only a final-path element. + * @param ppszFinalPath Where to return the pointer to the final path. This + * is set to NULL if no final path. + * @param poffError Where to on error return an offset into @a pszSpec + * of what cause the error. Optional. + */ +RTDECL(int) RTVfsChainSplitOffFinalPath(char *pszSpec, char **ppszSpec, char **ppszFinalPath, uint32_t *poffError); + +/** + * Common code for reporting errors of a RTVfsChainOpen* API. + * + * @param pszFunction The API called. + * @param pszSpec The VFS chain specification or file path passed to the. + * @param rc The return code. + * @param offError The error offset value returned (0 if not captured). + * @param pErrInfo Additional error information. Optional. + * + * @sa RTVfsChainMsgErrorExitFailure + * @sa RTVfsChainOpenVfs, RTVfsChainOpenFsStream, RTVfsChainOpenDir, + * RTVfsChainOpenFile, RTVfsChainOpenIoStream, RTVfsChainOpenSymlink + */ +RTDECL(void) RTVfsChainMsgError(const char *pszFunction, const char *pszSpec, int rc, uint32_t offError, PRTERRINFO pErrInfo); + +/** + * Common code for reporting errors of a RTVfsChainOpen* API. + * + * @returns RTEXITCODE_FAILURE + * + * @param pszFunction The API called. + * @param pszSpec The VFS chain specification or file path passed to the. + * @param rc The return code. + * @param offError The error offset value returned (0 if not captured). + * @param pErrInfo Additional error information. Optional. + * + * @sa RTVfsChainMsgError + * @sa RTVfsChainOpenVfs, RTVfsChainOpenFsStream, RTVfsChainOpenDir, + * RTVfsChainOpenFile, RTVfsChainOpenIoStream, RTVfsChainOpenSymlink + */ +RTDECL(RTEXITCODE) RTVfsChainMsgErrorExitFailure(const char *pszFunction, const char *pszSpec, + int rc, uint32_t offError, PRTERRINFO pErrInfo); + + +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_vfs_h */ + diff --git a/include/iprt/vfslowlevel.h b/include/iprt/vfslowlevel.h new file mode 100644 index 00000000..aba442ca --- /dev/null +++ b/include/iprt/vfslowlevel.h @@ -0,0 +1,1588 @@ +/** @file + * IPRT - Virtual Filesystem. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_vfslowlevel_h +#define IPRT_INCLUDED_vfslowlevel_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/vfs.h> +#include <iprt/errcore.h> +#include <iprt/list.h> +#include <iprt/param.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_vfs_lowlevel RTVfs - Low-level Interface. + * @ingroup grp_rt_vfs + * @{ + */ + + +/** @name VFS Lock Abstraction + * @todo This should be moved somewhere else as it is of general use. + * @{ */ + +/** + * VFS lock types. + */ +typedef enum RTVFSLOCKTYPE +{ + /** Invalid lock type. */ + RTVFSLOCKTYPE_INVALID = 0, + /** Read write semaphore. */ + RTVFSLOCKTYPE_RW, + /** Fast mutex semaphore (critical section in ring-3). */ + RTVFSLOCKTYPE_FASTMUTEX, + /** Full fledged mutex semaphore. */ + RTVFSLOCKTYPE_MUTEX, + /** The end of valid lock types. */ + RTVFSLOCKTYPE_END, + /** The customary 32-bit type hack. */ + RTVFSLOCKTYPE_32BIT_HACK = 0x7fffffff +} RTVFSLOCKTYPE; + +/** VFS lock handle. */ +typedef struct RTVFSLOCKINTERNAL *RTVFSLOCK; +/** Pointer to a VFS lock handle. */ +typedef RTVFSLOCK *PRTVFSLOCK; +/** Nil VFS lock handle. */ +#define NIL_RTVFSLOCK ((RTVFSLOCK)~(uintptr_t)0) + +/** Special handle value for creating a new read/write semaphore based lock. */ +#define RTVFSLOCK_CREATE_RW ((RTVFSLOCK)~(uintptr_t)1) +/** Special handle value for creating a new fast mutex semaphore based lock. */ +#define RTVFSLOCK_CREATE_FASTMUTEX ((RTVFSLOCK)~(uintptr_t)2) +/** Special handle value for creating a new mutex semaphore based lock. */ +#define RTVFSLOCK_CREATE_MUTEX ((RTVFSLOCK)~(uintptr_t)3) + +/** + * Retains a reference to the VFS lock handle. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param hLock The VFS lock handle. + */ +RTDECL(uint32_t) RTVfsLockRetain(RTVFSLOCK hLock); + +/** + * Releases a reference to the VFS lock handle. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param hLock The VFS lock handle. + */ +RTDECL(uint32_t) RTVfsLockRelease(RTVFSLOCK hLock); + +/** + * Gets the lock type. + * + * @returns The lock type on success, RTVFSLOCKTYPE_INVALID if the handle is + * not valid. + * @param hLock The lock handle. + */ +RTDECL(RTVFSLOCKTYPE) RTVfsLockGetType(RTVFSLOCK hLock); + + + +RTDECL(void) RTVfsLockAcquireReadSlow(RTVFSLOCK hLock); +RTDECL(void) RTVfsLockReleaseReadSlow(RTVFSLOCK hLock); +RTDECL(void) RTVfsLockAcquireWriteSlow(RTVFSLOCK hLock); +RTDECL(void) RTVfsLockReleaseWriteSlow(RTVFSLOCK hLock); + +/** + * Acquire a read lock. + * + * @param hLock The lock handle, can be NIL. + */ +DECLINLINE(void) RTVfsLockAcquireRead(RTVFSLOCK hLock) +{ + if (hLock != NIL_RTVFSLOCK) + RTVfsLockAcquireReadSlow(hLock); +} + + +/** + * Release a read lock. + * + * @param hLock The lock handle, can be NIL. + */ +DECLINLINE(void) RTVfsLockReleaseRead(RTVFSLOCK hLock) +{ + if (hLock != NIL_RTVFSLOCK) + RTVfsLockReleaseReadSlow(hLock); +} + + +/** + * Acquire a write lock. + * + * @param hLock The lock handle, can be NIL. + */ +DECLINLINE(void) RTVfsLockAcquireWrite(RTVFSLOCK hLock) +{ + if (hLock != NIL_RTVFSLOCK) + RTVfsLockAcquireWriteSlow(hLock); +} + + +/** + * Release a write lock. + * + * @param hLock The lock handle, can be NIL. + */ +DECLINLINE(void) RTVfsLockReleaseWrite(RTVFSLOCK hLock) +{ + if (hLock != NIL_RTVFSLOCK) + RTVfsLockReleaseWriteSlow(hLock); +} + +/** @} */ + +/** + * Info queried via RTVFSOBJOPS::pfnQueryInfoEx, ++. + */ +typedef enum RTVFSQIEX +{ + /** Invalid zero value. */ + RTVFSQIEX_INVALID = 0, + /** Volume label. + * Returns a UTF-8 string. */ + RTVFSQIEX_VOL_LABEL, + /** Alternative volume label, the primary one for ISOs, otherwise treated same + * as RTVFSQIEX_VOL_LABEL. */ + RTVFSQIEX_VOL_LABEL_ALT, + /** Volume serial number. + * Returns a uint32_t, uint64_t or RTUUID. */ + RTVFSQIEX_VOL_SERIAL, + /** End of valid queries. */ + RTVFSQIEX_END, + + /** The usual 32-bit hack. */ + RTVFSQIEX_32BIT_SIZE_HACK = 0x7fffffff +} RTVFSQIEX; + + +/** + * The basis for all virtual file system objects. + */ +typedef struct RTVFSOBJOPS +{ + /** The structure version (RTVFSOBJOPS_VERSION). */ + uint32_t uVersion; + /** The object type for type introspection. */ + RTVFSOBJTYPE enmType; + /** The name of the operations. */ + const char *pszName; + + /** + * Close the object. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + */ + DECLCALLBACKMEMBER(int, pfnClose,(void *pvThis)); + + /** + * Get information about the file. + * + * @returns IPRT status code. See RTVfsObjQueryInfo. + * @retval VERR_WRONG_TYPE if file system or file system stream. + * + * @param pvThis The implementation specific file data. + * @param pObjInfo Where to return the object info on success. + * @param enmAddAttr Which set of additional attributes to request. + * @sa RTVfsObjQueryInfo, RTFileQueryInfo, RTPathQueryInfo + */ + DECLCALLBACKMEMBER(int, pfnQueryInfo,(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)); + + /** + * Query arbritray information about the file, volume, or whatever. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW sets pcbRet. + * + * @param pvThis The implementation specific file data. + * @param enmInfo The information being queried. + * @param pvInfo Where to return the info. + * @param cbInfo The size of the @a pvInfo buffer. + * @param pcbRet The size of the returned data. In case of + * VERR_BUFFER_OVERFLOW this will be set to the required + * buffer size. + */ + DECLCALLBACKMEMBER(int, pfnQueryInfoEx,(void *pvThis, RTVFSQIEX enmInfo, void *pvInfo, size_t cbInfo, size_t *pcbRet)); + + /** Marks the end of the structure (RTVFSOBJOPS_VERSION). */ + uintptr_t uEndMarker; +} RTVFSOBJOPS; +/** Pointer to constant VFS object operations. */ +typedef RTVFSOBJOPS const *PCRTVFSOBJOPS; + +/** The RTVFSOBJOPS structure version. */ +#define RTVFSOBJOPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x1f,2,0) + + +/** + * The VFS operations. + */ +typedef struct RTVFSOPS +{ + /** The basic object operation. */ + RTVFSOBJOPS Obj; + /** The structure version (RTVFSOPS_VERSION). */ + uint32_t uVersion; + /** The virtual file system feature mask. */ + uint32_t fFeatures; + + /** + * Opens the root directory. + * + * @returns IPRT status code. + * @param pvThis The implementation specific data. + * @param phVfsDir Where to return the handle to the root directory. + */ + DECLCALLBACKMEMBER(int, pfnOpenRoot,(void *pvThis, PRTVFSDIR phVfsDir)); + + /** + * Query the status of the given storage range (optional). + * + * This can be used by the image compaction utilites to evict non-zero blocks + * that aren't currently being used by the file system. + * + * @returns IPRT status code. + * @param pvThis The implementation specific data. + * @param off Start offset to check. + * @param cb Number of bytes to check. + * @param pfUsed Where to store whether the given range is in use. + */ + DECLCALLBACKMEMBER(int, pfnQueryRangeState,(void *pvThis, uint64_t off, size_t cb, bool *pfUsed)); + + /** @todo There will be more methods here to optimize opening and + * querying. */ + +#if 0 + /** + * Optional entry point for optimizing path traversal within the file system. + * + * @returns IPRT status code. + * @param pvThis The implementation specific data. + * @param pszPath The path to resolve. + * @param poffPath The current path offset on input, what we've + * traversed to on successful return. + * @param phVfs??? Return handle to what we've traversed. + * @param p??? Return other stuff... + */ + DECLCALLBACKMEMBER(int, pfnTraverse,(void *pvThis, const char *pszPath, size_t *poffPath, PRTVFS??? phVfs?, ???* p???)); +#endif + + /** @todo need rename API */ + + /** Marks the end of the structure (RTVFSOPS_VERSION). */ + uintptr_t uEndMarker; +} RTVFSOPS; +/** Pointer to constant VFS operations. */ +typedef RTVFSOPS const *PCRTVFSOPS; + +/** The RTVFSOPS structure version. */ +#define RTVFSOPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x0f,1,0) + +/** @name RTVFSOPS::fFeatures + * @{ */ +/** The VFS supports attaching other systems. */ +#define RTVFSOPS_FEAT_ATTACH RT_BIT_32(0) +/** @} */ + +/** + * Creates a new VFS handle. + * + * @returns IPRT status code + * @param pVfsOps The VFS operations. + * @param cbInstance The size of the instance data. + * @param hVfs The VFS handle to associate this VFS with. + * NIL_VFS is ok. + * @param hLock Handle to a custom lock to be used with the new + * object. The reference is consumed. NIL and + * special lock handles are fine. + * @param phVfs Where to return the new handle. + * @param ppvInstance Where to return the pointer to the instance data + * (size is @a cbInstance). + */ +RTDECL(int) RTVfsNew(PCRTVFSOPS pVfsOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, + PRTVFS phVfs, void **ppvInstance); + + +/** + * Creates a new VFS base object handle. + * + * @returns IPRT status code + * @param pObjOps The base object operations. + * @param cbInstance The size of the instance data. + * @param hVfs The VFS handle to associate this base object + * with. NIL_VFS is ok. + * @param hLock Handle to a custom lock to be used with the new + * object. The reference is consumed. NIL and + * special lock handles are fine. + * @param phVfsObj Where to return the new handle. + * @param ppvInstance Where to return the pointer to the instance data + * (size is @a cbInstance). + */ +RTDECL(int) RTVfsNewBaseObj(PCRTVFSOBJOPS pObjOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, + PRTVFSOBJ phVfsObj, void **ppvInstance); + + +/** + * Gets the private data of a base object. + * + * @returns Pointer to the private data. NULL if the handle is invalid in some + * way. + * @param hVfsObj The I/O base object handle. + * @param pObjOps The base object operations. This servers as a + * sort of password. + */ +RTDECL(void *) RTVfsObjToPrivate(RTVFSOBJ hVfsObj, PCRTVFSOBJOPS pObjOps); + +/** + * Additional operations for setting object attributes. + */ +typedef struct RTVFSOBJSETOPS +{ + /** The structure version (RTVFSOBJSETOPS_VERSION). */ + uint32_t uVersion; + /** The offset back to the RTVFSOBJOPS structure. */ + uint32_t offObjOps; + + /** + * Set the unix style owner and group. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param fMode The new mode bits. + * @param fMask The mask indicating which bits we are + * changing. + * @note Optional, failing with VERR_WRITE_PROTECT if NULL. + * @sa RTFileSetMode + */ + DECLCALLBACKMEMBER(int, pfnSetMode,(void *pvThis, RTFMODE fMode, RTFMODE fMask)); + + /** + * Set the timestamps associated with the object. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param pAccessTime Pointer to the new access time. NULL if not + * to be changed. + * @param pModificationTime Pointer to the new modifcation time. NULL if + * not to be changed. + * @param pChangeTime Pointer to the new change time. NULL if not + * to be changed. + * @param pBirthTime Pointer to the new time of birth. NULL if + * not to be changed. + * @remarks See RTFileSetTimes for restrictions and behavior imposed by the + * host OS or underlying VFS provider. + * @note Optional, failing with VERR_WRITE_PROTECT if NULL. + * @sa RTFileSetTimes + */ + DECLCALLBACKMEMBER(int, pfnSetTimes,(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, + PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)); + + /** + * Set the unix style owner and group. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param uid The user ID of the new owner. NIL_RTUID if + * unchanged. + * @param gid The group ID of the new owner group. NIL_RTGID if + * unchanged. + * @note Optional, failing with VERR_WRITE_PROTECT if NULL. + * @sa RTFileSetOwner + */ + DECLCALLBACKMEMBER(int, pfnSetOwner,(void *pvThis, RTUID uid, RTGID gid)); + + /** Marks the end of the structure (RTVFSOBJSETOPS_VERSION). */ + uintptr_t uEndMarker; +} RTVFSOBJSETOPS; +/** Pointer to const object attribute setter operations. */ +typedef RTVFSOBJSETOPS const *PCRTVFSOBJSETOPS; + +/** The RTVFSOBJSETOPS structure version. */ +#define RTVFSOBJSETOPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x2f,1,0) + + +/** + * The filesystem stream operations. + * + * @extends RTVFSOBJOPS + */ +typedef struct RTVFSFSSTREAMOPS +{ + /** The basic object operation. */ + RTVFSOBJOPS Obj; + /** The structure version (RTVFSFSSTREAMOPS_VERSION). */ + uint32_t uVersion; + /** Reserved field, MBZ. */ + uint32_t fReserved; + + /** + * Gets the next object in the stream. + * + * Readable streams only. + * + * @returns IPRT status code. + * @retval VINF_SUCCESS if a new object was retrieved. + * @retval VERR_EOF when there are no more objects. + * @param pvThis The implementation specific directory data. + * @param ppszName Where to return the object name. Must be freed by + * calling RTStrFree. + * @param penmType Where to return the object type. + * @param phVfsObj Where to return the object handle (referenced). This + * must be cast to the desired type before use. + * @sa RTVfsFsStrmNext + * + * @note Setting this member to NULL is okay for write-only streams. + */ + DECLCALLBACKMEMBER(int, pfnNext,(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)); + + /** + * Adds another object into the stream. + * + * Writable streams only. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszPath The path to the object. + * @param hVfsObj The object to add. + * @param fFlags Reserved for the future, MBZ. + * @sa RTVfsFsStrmAdd + * + * @note Setting this member to NULL is okay for read-only streams. + */ + DECLCALLBACKMEMBER(int, pfnAdd,(void *pvThis, const char *pszPath, RTVFSOBJ hVfsObj, uint32_t fFlags)); + + /** + * Pushes an byte stream onto the stream (optional). + * + * Writable streams only. + * + * This differs from RTVFSFSSTREAMOPS::pfnAdd() in that it will create a regular + * file in the output file system stream and provide the actual content bytes + * via the returned I/O stream object. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszPath The path to the file. + * @param cbFile The file size. This can also be set to UINT64_MAX if + * the file system stream is backed by a file. + * @param paObjInfo Array of zero or more RTFSOBJINFO structures containing + * different pieces of information about the file. If any + * provided, the first one should be a RTFSOBJATTRADD_UNIX + * one, additional can be supplied if wanted. What exactly + * is needed depends on the underlying FS stream + * implementation. + * @param cObjInfo Number of items in the array @a paObjInfo points at. + * @param fFlags RTVFSFSSTRM_PUSH_F_XXX. + * @param phVfsIos Where to return the I/O stream to feed the file content + * to. If the FS stream is backed by a file, the returned + * handle can be cast to a file if necessary. + */ + DECLCALLBACKMEMBER(int, pfnPushFile,(void *pvThis, const char *pszPath, uint64_t cbFile, + PCRTFSOBJINFO paObjInfo, uint32_t cObjInfo, uint32_t fFlags, PRTVFSIOSTREAM phVfsIos)); + + /** + * Marks the end of the stream. + * + * Writable streams only. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @sa RTVfsFsStrmEnd + * + * @note Setting this member to NULL is okay for read-only streams. + */ + DECLCALLBACKMEMBER(int, pfnEnd,(void *pvThis)); + + /** Marks the end of the structure (RTVFSFSSTREAMOPS_VERSION). */ + uintptr_t uEndMarker; +} RTVFSFSSTREAMOPS; +/** Pointer to const object attribute setter operations. */ +typedef RTVFSFSSTREAMOPS const *PCRTVFSFSSTREAMOPS; + +/** The RTVFSFSSTREAMOPS structure version. */ +#define RTVFSFSSTREAMOPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x3f,2,0) + + +/** + * Creates a new VFS filesystem stream handle. + * + * @returns IPRT status code + * @param pFsStreamOps The filesystem stream operations. + * @param cbInstance The size of the instance data. + * @param hVfs The VFS handle to associate this filesystem + * stream with. NIL_VFS is ok. + * @param hLock Handle to a custom lock to be used with the new + * object. The reference is consumed. NIL and + * special lock handles are fine. + * @param fAccess RTFILE_O_READ and/or RTFILE_O_WRITE. + * @param phVfsFss Where to return the new handle. + * @param ppvInstance Where to return the pointer to the instance data + * (size is @a cbInstance). + */ +RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, uint32_t fAccess, + PRTVFSFSSTREAM phVfsFss, void **ppvInstance); + +/** + * Gets the private data of an filesystem stream. + * + * @returns Pointer to the private data. NULL if the handle is invalid in some + * way. + * @param hVfsFss The FS stream handle. + * @param pFsStreamOps The FS stream operations. This servers as a + * sort of password. + */ +RTDECL(void *) RTVfsFsStreamToPrivate(RTVFSFSSTREAM hVfsFss, PCRTVFSFSSTREAMOPS pFsStreamOps); + + +/** + * The directory operations. + * + * @extends RTVFSOBJOPS + * @extends RTVFSOBJSETOPS + */ +typedef struct RTVFSDIROPS +{ + /** The basic object operation. */ + RTVFSOBJOPS Obj; + /** The structure version (RTVFSDIROPS_VERSION). */ + uint32_t uVersion; + /** Reserved field, MBZ. */ + uint32_t fReserved; + /** The object setter operations. */ + RTVFSOBJSETOPS ObjSet; + + /** + * Generic method for opening any kind of file system object. + * + * Can also create files and directories. Symbolic links, devices and such + * needs to be created using special methods or this would end up being way more + * complicated than it already is. + * + * There are optional specializations available. + * + * @returns IPRT status code. + * @retval VERR_PATH_NOT_FOUND or VERR_FILE_NOT_FOUND if @a pszEntry was not + * found. + * @retval VERR_IS_A_FILE if @a pszEntry is a file or similar but @a fFlags + * indicates that the type of object should not be opened. + * @retval VERR_IS_A_DIRECTORY if @a pszEntry is a directory but @a fFlags + * indicates that directories should not be opened. + * @retval VERR_IS_A_SYMLINK if @a pszEntry is a symbolic link but @a fFlags + * indicates that symbolic links should not be opened (or followed). + * @retval VERR_IS_A_FIFO if @a pszEntry is a FIFO but @a fFlags indicates that + * FIFOs should not be opened. + * @retval VERR_IS_A_SOCKET if @a pszEntry is a socket but @a fFlags indicates + * that sockets should not be opened. + * @retval VERR_IS_A_BLOCK_DEVICE if @a pszEntry is a block device but + * @a fFlags indicates that block devices should not be opened, or vice + * versa. + * + * @param pvThis The implementation specific directory data. + * @param pszEntry The name of the immediate file to open or create. + * @param fOpenFile RTFILE_O_XXX combination. + * @param fObjFlags More flags: RTVFSOBJ_F_XXX, RTPATH_F_XXX. + * The meaning of RTPATH_F_FOLLOW_LINK differs here, if + * @a pszEntry is a symlink it should be opened for + * traversal rather than according to @a fOpenFile. + * @param phVfsObj Where to return the handle to the opened object. + * @sa RTFileOpen, RTDirOpen + */ + DECLCALLBACKMEMBER(int, pfnOpen,(void *pvThis, const char *pszEntry, uint64_t fOpenFile, + uint32_t fObjFlags, PRTVFSOBJ phVfsObj)); + + /** + * Optional method for symbolic link handling in the vfsstddir.cpp. + * + * This is really just a hack to make symbolic link handling work when working + * with directory objects that doesn't have an associated VFS. It also helps + * deal with drive letters in symbolic links on Windows and OS/2. + * + * @returns IPRT status code. + * @retval VERR_PATH_IS_RELATIVE if @a pszPath isn't absolute and should be + * handled using pfnOpen(). + * + * @param pvThis The implementation specific directory data. + * @param pszRoot Path to the alleged root. + * @param phVfsDir Where to return the handle to the specified root + * directory (or may current dir on a drive letter). + */ + DECLCALLBACKMEMBER(int, pfnFollowAbsoluteSymlink,(void *pvThis, const char *pszRoot, PRTVFSDIR phVfsDir)); + + /** + * Open or create a file. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszFilename The name of the immediate file to open or create. + * @param fOpen The open flags (RTFILE_O_XXX). + * @param phVfsFile Where to return the handle to the opened file. + * @note Optional. RTVFSDIROPS::pfnOpenObj will be used if NULL. + * @sa RTFileOpen. + */ + DECLCALLBACKMEMBER(int, pfnOpenFile,(void *pvThis, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)); + + /** + * Open an existing subdirectory. + * + * @returns IPRT status code. + * @retval VERR_IS_A_SYMLINK if @a pszSubDir is a symbolic link. + * @retval VERR_NOT_A_DIRECTORY is okay for symbolic links too. + * + * @param pvThis The implementation specific directory data. + * @param pszSubDir The name of the immediate subdirectory to open. + * @param fFlags RTDIR_F_XXX. + * @param phVfsDir Where to return the handle to the opened directory. + * Optional. + * @note Optional. RTVFSDIROPS::pfnOpenObj will be used if NULL. + * @sa RTDirOpen. + */ + DECLCALLBACKMEMBER(int, pfnOpenDir,(void *pvThis, const char *pszSubDir, uint32_t fFlags, PRTVFSDIR phVfsDir)); + + /** + * Creates a new subdirectory. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszSubDir The name of the immediate subdirectory to create. + * @param fMode The mode mask of the new directory. + * @param phVfsDir Where to optionally return the handle to the newly + * create directory. + * @note Optional. RTVFSDIROPS::pfnOpenObj will be used if NULL. + * @sa RTDirCreate. + */ + DECLCALLBACKMEMBER(int, pfnCreateDir,(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)); + + /** + * Opens an existing symbolic link. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszSymlink The name of the immediate symbolic link to open. + * @param phVfsSymlink Where to optionally return the handle to the + * newly create symbolic link. + * @note Optional. RTVFSDIROPS::pfnOpenObj will be used if NULL. + * @sa RTSymlinkCreate. + */ + DECLCALLBACKMEMBER(int, pfnOpenSymlink,(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink)); + + /** + * Creates a new symbolic link. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszSymlink The name of the immediate symbolic link to create. + * @param pszTarget The symbolic link target. + * @param enmType The symbolic link type. + * @param phVfsSymlink Where to optionally return the handle to the + * newly create symbolic link. + * @sa RTSymlinkCreate. + */ + DECLCALLBACKMEMBER(int, pfnCreateSymlink,(void *pvThis, const char *pszSymlink, const char *pszTarget, + RTSYMLINKTYPE enmType, PRTVFSSYMLINK phVfsSymlink)); + + /** + * Query information about an entry. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszEntry The name of the directory entry to remove. + * @param pObjInfo Where to return the info on success. + * @param enmAddAttr Which set of additional attributes to request. + * @note Optional. RTVFSDIROPS::pfnOpenObj and RTVFSOBJOPS::pfnQueryInfo + * will be used if NULL. + * @sa RTPathQueryInfo, RTVFSOBJOPS::pfnQueryInfo + */ + DECLCALLBACKMEMBER(int, pfnQueryEntryInfo,(void *pvThis, const char *pszEntry, + PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)); + + /** + * Removes a directory entry. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszEntry The name of the directory entry to remove. + * @param fType If non-zero, this restricts the type of the entry to + * the object type indicated by the mask + * (RTFS_TYPE_XXX). + * @sa RTFileRemove, RTDirRemove, RTSymlinkRemove. + */ + DECLCALLBACKMEMBER(int, pfnUnlinkEntry,(void *pvThis, const char *pszEntry, RTFMODE fType)); + + /** + * Renames a directory entry. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pszEntry The name of the directory entry to rename. + * @param fType If non-zero, this restricts the type of the entry to + * the object type indicated by the mask + * (RTFS_TYPE_XXX). + * @param pszNewName The new entry name. + * @sa RTPathRename + * + * @todo This API is not flexible enough, must be able to rename between + * directories within a file system. + */ + DECLCALLBACKMEMBER(int, pfnRenameEntry,(void *pvThis, const char *pszEntry, RTFMODE fType, const char *pszNewName)); + + /** + * Rewind the directory stream so that the next read returns the first + * entry. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + */ + DECLCALLBACKMEMBER(int, pfnRewindDir,(void *pvThis)); + + /** + * Rewind the directory stream so that the next read returns the first + * entry. + * + * @returns IPRT status code. + * @param pvThis The implementation specific directory data. + * @param pDirEntry Output buffer. + * @param pcbDirEntry Complicated, see RTDirReadEx. + * @param enmAddAttr Which set of additional attributes to request. + * @sa RTDirReadEx + */ + DECLCALLBACKMEMBER(int, pfnReadDir,(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr)); + + /** Marks the end of the structure (RTVFSDIROPS_VERSION). */ + uintptr_t uEndMarker; +} RTVFSDIROPS; +/** Pointer to const directory operations. */ +typedef RTVFSDIROPS const *PCRTVFSDIROPS; +/** The RTVFSDIROPS structure version. */ +#define RTVFSDIROPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x4f,1,0) + + +/** + * Creates a new VFS directory handle. + * + * @returns IPRT status code + * @param pDirOps The directory operations. + * @param cbInstance The size of the instance data. + * @param fFlags RTVFSDIR_F_XXX + * @param hVfs The VFS handle to associate this directory with. + * NIL_VFS is ok. + * @param hLock Handle to a custom lock to be used with the new + * object. The reference is consumed. NIL and + * special lock handles are fine. + * @param phVfsDir Where to return the new handle. + * @param ppvInstance Where to return the pointer to the instance data + * (size is @a cbInstance). + */ +RTDECL(int) RTVfsNewDir(PCRTVFSDIROPS pDirOps, size_t cbInstance, uint32_t fFlags, RTVFS hVfs, RTVFSLOCK hLock, + PRTVFSDIR phVfsDir, void **ppvInstance); + +/** @name RTVFSDIR_F_XXX + * @{ */ +/** Don't reference the @a hVfs parameter passed to RTVfsNewDir. + * This is a permanent root directory hack. */ +#define RTVFSDIR_F_NO_VFS_REF RT_BIT_32(0) +/** @} */ + +/** + * Gets the private data of a directory. + * + * @returns Pointer to the private data. NULL if the handle is invalid in some + * way. + * @param hVfsDir The directory handle. + * @param pDirOps The directory operations. This servers as a + * sort of password. + */ +RTDECL(void *) RTVfsDirToPrivate(RTVFSDIR hVfsDir, PCRTVFSDIROPS pDirOps); + + +/** + * The symbolic link operations. + * + * @extends RTVFSOBJOPS + * @extends RTVFSOBJSETOPS + */ +typedef struct RTVFSSYMLINKOPS +{ + /** The basic object operation. */ + RTVFSOBJOPS Obj; + /** The structure version (RTVFSSYMLINKOPS_VERSION). */ + uint32_t uVersion; + /** Reserved field, MBZ. */ + uint32_t fReserved; + /** The object setter operations. */ + RTVFSOBJSETOPS ObjSet; + + /** + * Read the symbolic link target. + * + * @returns IPRT status code. + * @param pvThis The implementation specific symbolic link data. + * @param pszTarget The target buffer. + * @param cbTarget The size of the target buffer. + * @sa RTSymlinkRead + */ + DECLCALLBACKMEMBER(int, pfnRead,(void *pvThis, char *pszTarget, size_t cbTarget)); + + /** Marks the end of the structure (RTVFSSYMLINKOPS_VERSION). */ + uintptr_t uEndMarker; +} RTVFSSYMLINKOPS; +/** Pointer to const symbolic link operations. */ +typedef RTVFSSYMLINKOPS const *PCRTVFSSYMLINKOPS; +/** The RTVFSSYMLINKOPS structure version. */ +#define RTVFSSYMLINKOPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x5f,1,0) + + +/** + * Creates a new VFS symlink handle. + * + * @returns IPRT status code + * @param pSymlinkOps The symlink operations. + * @param cbInstance The size of the instance data. + * @param hVfs The VFS handle to associate this symlink object + * with. NIL_VFS is ok. + * @param hLock Handle to a custom lock to be used with the new + * object. The reference is consumed. NIL and + * special lock handles are fine. + * @param phVfsSym Where to return the new handle. + * @param ppvInstance Where to return the pointer to the instance data + * (size is @a cbInstance). + */ +RTDECL(int) RTVfsNewSymlink(PCRTVFSSYMLINKOPS pSymlinkOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, + PRTVFSSYMLINK phVfsSym, void **ppvInstance); + + +/** + * Gets the private data of a symbolic link. + * + * @returns Pointer to the private data. NULL if the handle is invalid in some + * way. + * @param hVfsSym The symlink handle. + * @param pSymlinkOps The symlink operations. This servers as a sort + * of password. + */ +RTDECL(void *) RTVfsSymlinkToPrivate(RTVFSSYMLINK hVfsSym, PCRTVFSSYMLINKOPS pSymlinkOps); + +/** + * The basis for all I/O objects (files, pipes, sockets, devices, ++). + * + * @extends RTVFSOBJOPS + */ +typedef struct RTVFSIOSTREAMOPS +{ + /** The basic object operation. */ + RTVFSOBJOPS Obj; + /** The structure version (RTVFSIOSTREAMOPS_VERSION). */ + uint32_t uVersion; + /** Feature field. */ + uint32_t fFeatures; + + /** + * Reads from the file/stream. + * + * @returns IPRT status code. See RTVfsIoStrmRead. + * @param pvThis The implementation specific file data. + * @param off Where to read at, -1 for the current position. + * @param pSgBuf Gather buffer describing the bytes that are to be + * written. + * @param fBlocking If @c true, the call is blocking, if @c false it + * should not block. + * @param pcbRead Where return the number of bytes actually read. + * This is set it 0 by the caller. If NULL, try read + * all and fail if incomplete. + * @sa RTVfsIoStrmRead, RTVfsIoStrmSgRead, RTVfsFileRead, + * RTVfsFileReadAt, RTFileRead, RTFileReadAt. + */ + DECLCALLBACKMEMBER(int, pfnRead,(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)); + + /** + * Writes to the file/stream. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param off Where to start wrinting, -1 for the current + * position. + * @param pSgBuf Gather buffers describing the bytes that are to be + * written. + * @param fBlocking If @c true, the call is blocking, if @c false it + * should not block. + * @param pcbWritten Where to return the number of bytes actually + * written. This is set it 0 by the caller. If + * NULL, try write it all and fail if incomplete. + * @note Optional, failing with VERR_WRITE_PROTECT if NULL. + * @sa RTFileWrite, RTFileWriteAt. + */ + DECLCALLBACKMEMBER(int, pfnWrite,(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)); + + /** + * Flushes any pending data writes to the stream. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @sa RTFileFlush. + */ + DECLCALLBACKMEMBER(int, pfnFlush,(void *pvThis)); + + /** + * Poll for events. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param fEvents The events to poll for (RTPOLL_EVT_XXX). + * @param cMillies How long to wait for event to eventuate. + * @param fIntr Whether the wait is interruptible and can return + * VERR_INTERRUPTED (@c true) or if this condition + * should be hidden from the caller (@c false). + * @param pfRetEvents Where to return the event mask. + * @note Optional. If NULL, immediately return all requested non-error + * events, waiting for errors works like sleep. + * @sa RTPollSetAdd, RTPoll, RTPollNoResume. + */ + DECLCALLBACKMEMBER(int, pfnPollOne,(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, + uint32_t *pfRetEvents)); + + /** + * Tells the current file/stream position. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param poffActual Where to return the actual offset. + * @sa RTFileTell + */ + DECLCALLBACKMEMBER(int, pfnTell,(void *pvThis, PRTFOFF poffActual)); + + /** + * Skips @a cb ahead in the stream. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param cb The number bytes to skip. + * @remarks This is optional and can be NULL. + */ + DECLCALLBACKMEMBER(int, pfnSkip,(void *pvThis, RTFOFF cb)); + + /** + * Fills the stream with @a cb zeros. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param cb The number of zero bytes to insert. + * @remarks This is optional and can be NULL. + */ + DECLCALLBACKMEMBER(int, pfnZeroFill,(void *pvThis, RTFOFF cb)); + + /** Marks the end of the structure (RTVFSIOSTREAMOPS_VERSION). */ + uintptr_t uEndMarker; +} RTVFSIOSTREAMOPS; +/** Pointer to const I/O stream operations. */ +typedef RTVFSIOSTREAMOPS const *PCRTVFSIOSTREAMOPS; + +/** The RTVFSIOSTREAMOPS structure version. */ +#define RTVFSIOSTREAMOPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x6f,1,0) + +/** @name RTVFSIOSTREAMOPS::fFeatures + * @{ */ +/** No scatter gather lists, thank you. */ +#define RTVFSIOSTREAMOPS_FEAT_NO_SG RT_BIT_32(0) +/** Mask of the valid I/O stream feature flags. */ +#define RTVFSIOSTREAMOPS_FEAT_VALID_MASK UINT32_C(0x00000001) +/** @} */ + + +/** + * Creates a new VFS I/O stream handle. + * + * @returns IPRT status code + * @param pIoStreamOps The I/O stream operations. + * @param cbInstance The size of the instance data. + * @param fOpen The open flags. The minimum is the access mask. + * @param hVfs The VFS handle to associate this I/O stream + * with. NIL_VFS is ok. + * @param hLock Handle to a custom lock to be used with the new + * object. The reference is consumed. NIL and + * special lock handles are fine. + * @param phVfsIos Where to return the new handle. + * @param ppvInstance Where to return the pointer to the instance data + * (size is @a cbInstance). + */ +RTDECL(int) RTVfsNewIoStream(PCRTVFSIOSTREAMOPS pIoStreamOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock, + PRTVFSIOSTREAM phVfsIos, void **ppvInstance); + + +/** + * Gets the private data of an I/O stream. + * + * @returns Pointer to the private data. NULL if the handle is invalid in some + * way. + * @param hVfsIos The I/O stream handle. + * @param pIoStreamOps The I/O stream operations. This servers as a + * sort of password. + */ +RTDECL(void *) RTVfsIoStreamToPrivate(RTVFSIOSTREAM hVfsIos, PCRTVFSIOSTREAMOPS pIoStreamOps); + + +/** + * The file operations. + * + * @extends RTVFSIOSTREAMOPS + * @extends RTVFSOBJSETOPS + */ +typedef struct RTVFSFILEOPS +{ + /** The I/O stream and basis object operations. */ + RTVFSIOSTREAMOPS Stream; + /** The structure version (RTVFSFILEOPS_VERSION). */ + uint32_t uVersion; + /** Reserved field, MBZ. */ + uint32_t fReserved; + /** The object setter operations. */ + RTVFSOBJSETOPS ObjSet; + + /** + * Changes the current file position. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param offSeek The offset to seek. + * @param uMethod The seek method, i.e. what the seek is relative to. + * @param poffActual Where to return the actual offset. + * @sa RTFileSeek + */ + DECLCALLBACKMEMBER(int, pfnSeek,(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)); + + /** + * Get the current file size. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param pcbFile Where to store the current file size. + * @sa RTFileQuerySize + */ + DECLCALLBACKMEMBER(int, pfnQuerySize,(void *pvThis, uint64_t *pcbFile)); + + /** + * Change the file size. + * + * @returns IPRT status code. + * @retval VERR_ACCESS_DENIED if handle isn't writable. + * @retval VERR_WRITE_PROTECT if read-only file system. + * @retval VERR_FILE_TOO_BIG if cbSize is larger than what the file system can + * theoretically deal with. + * @retval VERR_DISK_FULL if the file system if full. + * @retval VERR_NOT_SUPPORTED if fFlags indicates some operation that's not + * supported by the file system / host operating system. + * + * @param pvThis The implementation specific file data. + * @param pcbFile Where to store the current file size. + * @param fFlags RTVFSFILE_SET_SIZE_F_XXX. + * @note Optional. If NULL, VERR_WRITE_PROTECT will be returned. + * @sa RTFileSetSize, RTFileSetAllocationSize + */ + DECLCALLBACKMEMBER(int, pfnSetSize,(void *pvThis, uint64_t cbFile, uint32_t fFlags)); + + /** + * Determine the maximum file size. + * + * This won't take amount of freespace into account, just the limitations of the + * underlying file system / host operating system. + * + * @returns IPRT status code. + * @param pvThis The implementation specific file data. + * @param pcbMax Where to return the max file size. + * @note Optional. If NULL, VERR_NOT_IMPLEMENTED will be returned. + * @sa RTFileQueryMaxSizeEx + */ + DECLCALLBACKMEMBER(int, pfnQueryMaxSize,(void *pvThis, uint64_t *pcbMax)); + + /** @todo There will be more methods here. */ + + /** Marks the end of the structure (RTVFSFILEOPS_VERSION). */ + uintptr_t uEndMarker; +} RTVFSFILEOPS; +/** Pointer to const file operations. */ +typedef RTVFSFILEOPS const *PCRTVFSFILEOPS; + +/** The RTVFSFILEOPS structure version. */ +#define RTVFSFILEOPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x7f,2,0) + +/** + * Creates a new VFS file handle. + * + * @returns IPRT status code + * @param pFileOps The file operations. + * @param cbInstance The size of the instance data. + * @param fOpen The open flags. The minimum is the access mask. + * @param hVfs The VFS handle to associate this file with. + * NIL_VFS is ok. + * @param hLock Handle to a custom lock to be used with the new + * object. The reference is consumed. NIL and + * special lock handles are fine. + * @param phVfsFile Where to return the new handle. + * @param ppvInstance Where to return the pointer to the instance data + * (size is @a cbInstance). + */ +RTDECL(int) RTVfsNewFile(PCRTVFSFILEOPS pFileOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock, + PRTVFSFILE phVfsFile, void **ppvInstance); + + +/** @defgroup grp_rt_vfs_ll_util VFS Utility APIs + * @{ */ + +/** + * Parsed path. + */ +typedef struct RTVFSPARSEDPATH +{ + /** The length of the path in szCopy. */ + uint16_t cch; + /** The number of path components. */ + uint16_t cComponents; + /** Set if the path ends with slash, indicating that it's a directory + * reference and not a file reference. The slash has been removed from + * the copy. */ + bool fDirSlash; + /** Set if absolute. */ + bool fAbsolute; + /** The offset where each path component starts, i.e. the char after the + * slash. The array has cComponents + 1 entries, where the final one is + * cch + 1 so that one can always terminate the current component by + * szPath[aoffComponent[i] - 1] = '\0'. */ + uint16_t aoffComponents[RTPATH_MAX / 2 + 1]; + /** A normalized copy of the path. + * Reserve some extra space so we can be more relaxed about overflow + * checks and terminator paddings, especially when recursing. */ + char szPath[RTPATH_MAX]; +} RTVFSPARSEDPATH; +/** Pointer to a parsed path. */ +typedef RTVFSPARSEDPATH *PRTVFSPARSEDPATH; + +/** The max accepted path length. + * This must be a few chars shorter than RTVFSPARSEDPATH::szPath because we + * use two terminators and wish be a little bit lazy with checking. */ +#define RTVFSPARSEDPATH_MAX (RTPATH_MAX - 4) + +/** + * Appends @a pszPath (relative) to the already parsed path @a pPath. + * + * @retval VINF_SUCCESS + * @retval VERR_FILENAME_TOO_LONG + * @retval VERR_INTERNAL_ERROR_4 + * @param pPath The parsed path to append @a pszPath onto. + * This is both input and output. + * @param pszPath The path to append. This must be relative. + * @param piRestartComp The component to restart parsing at. This is + * input/output. The input does not have to be + * within the valid range. Optional. + */ +RTDECL(int) RTVfsParsePathAppend(PRTVFSPARSEDPATH pPath, const char *pszPath, uint16_t *piRestartComp); + +/** + * Parses a path. + * + * @retval VINF_SUCCESS + * @retval VERR_FILENAME_TOO_LONG + * @param pPath Where to store the parsed path. + * @param pszPath The path to parse. Absolute or relative to @a + * pszCwd. + * @param pszCwd The current working directory. Must be + * absolute. + */ +RTDECL(int) RTVfsParsePath(PRTVFSPARSEDPATH pPath, const char *pszPath, const char *pszCwd); + +/** + * Same as RTVfsParsePath except that it allocates a temporary buffer. + * + * @retval VINF_SUCCESS + * @retval VERR_NO_TMP_MEMORY + * @retval VERR_FILENAME_TOO_LONG + * @param pszPath The path to parse. Absolute or relative to @a + * pszCwd. + * @param pszCwd The current working directory. Must be + * absolute. + * @param ppPath Where to store the pointer to the allocated + * buffer containing the parsed path. This must + * be freed by calling RTVfsParsePathFree. NULL + * will be stored on failured. + */ +RTDECL(int) RTVfsParsePathA(const char *pszPath, const char *pszCwd, PRTVFSPARSEDPATH *ppPath); + +/** + * Frees a buffer returned by RTVfsParsePathA. + * + * @param pPath The parsed path buffer to free. NULL is fine. + */ +RTDECL(void) RTVfsParsePathFree(PRTVFSPARSEDPATH pPath); + +/** + * Dummy implementation of RTVFSIOSTREAMOPS::pfnPollOne. + * + * This handles the case where there is no chance any events my be raised and + * all that is required is to wait according to the parameters. + * + * @returns IPRT status code. + * @param fEvents The events to poll for (RTPOLL_EVT_XXX). + * @param cMillies How long to wait for event to eventuate. + * @param fIntr Whether the wait is interruptible and can return + * VERR_INTERRUPTED (@c true) or if this condition + * should be hidden from the caller (@c false). + * @param pfRetEvents Where to return the event mask. + * @sa RTVFSIOSTREAMOPS::pfnPollOne, RTPollSetAdd, RTPoll, RTPollNoResume. + */ +RTDECL(int) RTVfsUtilDummyPollOne(uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, uint32_t *pfRetEvents); + +/** @} */ + + +/** @defgroup grp_rt_vfs_lowlevel_chain VFS Chains (Low Level) + * @ref grp_rt_vfs_chain + * @{ + */ + +/** Pointer to a VFS chain element registration record. */ +typedef struct RTVFSCHAINELEMENTREG *PRTVFSCHAINELEMENTREG; +/** Pointer to a const VFS chain element registration record. */ +typedef struct RTVFSCHAINELEMENTREG const *PCRTVFSCHAINELEMENTREG; + +/** + * VFS chain element argument. + */ +typedef struct RTVFSCHAINELEMENTARG +{ + /** The string argument value. */ + char *psz; + /** The specification offset of this argument. */ + uint16_t offSpec; + /** Provider specific value. */ + uint64_t uProvider; +} RTVFSCHAINELEMENTARG; +/** Pointer to a VFS chain element argument. */ +typedef RTVFSCHAINELEMENTARG *PRTVFSCHAINELEMENTARG; + + +/** + * VFS chain element specification. + */ +typedef struct RTVFSCHAINELEMSPEC +{ + /** The provider name. + * This can be NULL if this is the final component and it's just a path. */ + char *pszProvider; + /** The input type, RTVFSOBJTYPE_INVALID if first. */ + RTVFSOBJTYPE enmTypeIn; + /** The element type. + * RTVFSOBJTYPE_END if this is the final component and it's just a path. */ + RTVFSOBJTYPE enmType; + /** The input spec offset of this element. */ + uint16_t offSpec; + /** The length of the input spec. */ + uint16_t cchSpec; + /** The number of arguments. */ + uint32_t cArgs; + /** Arguments. */ + PRTVFSCHAINELEMENTARG paArgs; + + /** The provider. */ + PCRTVFSCHAINELEMENTREG pProvider; + /** Provider specific value. */ + uint64_t uProvider; + /** The object (with reference). */ + RTVFSOBJ hVfsObj; +} RTVFSCHAINELEMSPEC; +/** Pointer to a chain element specification. */ +typedef RTVFSCHAINELEMSPEC *PRTVFSCHAINELEMSPEC; +/** Pointer to a const chain element specification. */ +typedef RTVFSCHAINELEMSPEC const *PCRTVFSCHAINELEMSPEC; + + +/** + * Parsed VFS chain specification. + */ +typedef struct RTVFSCHAINSPEC +{ + /** Open directory flags (RTFILE_O_XXX). */ + uint64_t fOpenFile; + /** To be defined. */ + uint32_t fOpenDir; + /** The type desired by the caller. */ + RTVFSOBJTYPE enmDesiredType; + /** The number of elements. */ + uint32_t cElements; + /** The elements. */ + PRTVFSCHAINELEMSPEC paElements; +} RTVFSCHAINSPEC; +/** Pointer to a parsed VFS chain specification. */ +typedef RTVFSCHAINSPEC *PRTVFSCHAINSPEC; +/** Pointer to a const, parsed VFS chain specification. */ +typedef RTVFSCHAINSPEC const *PCRTVFSCHAINSPEC; + + +/** + * A chain element provider registration record. + */ +typedef struct RTVFSCHAINELEMENTREG +{ + /** The version (RTVFSCHAINELEMENTREG_VERSION). */ + uint32_t uVersion; + /** Reserved, MBZ. */ + uint32_t fReserved; + /** The provider name (unique). */ + const char *pszName; + /** For chaining the providers. */ + RTLISTNODE ListEntry; + /** Help text. */ + const char *pszHelp; + + /** + * Checks the element specification. + * + * This is allowed to parse arguments and use pSpec->uProvider and + * pElement->paArgs[].uProvider to store information that pfnInstantiate and + * pfnCanReuseElement may use later on, thus avoiding duplicating work/code. + * + * @returns IPRT status code. + * @param pProviderReg Pointer to the element provider registration. + * @param pSpec The chain specification. + * @param pElement The chain element specification to validate. + * @param poffError Where to return error offset on failure. This is + * set to the pElement->offSpec on input, so it only + * needs to be adjusted if an argument is at fault. + * @param pErrInfo Where to return additional error information, if + * available. Optional. + */ + DECLCALLBACKMEMBER(int, pfnValidate,(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec, + PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)); + + /** + * Create a VFS object according to the element specification. + * + * @returns IPRT status code. + * @param pProviderReg Pointer to the element provider registration. + * @param pSpec The chain specification. + * @param pElement The chain element specification to instantiate. + * @param hPrevVfsObj Handle to the previous VFS object, NIL_RTVFSOBJ if + * first. + * @param phVfsObj Where to return the VFS object handle. + * @param poffError Where to return error offset on failure. This is + * set to the pElement->offSpec on input, so it only + * needs to be adjusted if an argument is at fault. + * @param pErrInfo Where to return additional error information, if + * available. Optional. + */ + DECLCALLBACKMEMBER(int, pfnInstantiate,(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec, + PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj, + PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)); + + /** + * Determins whether the element can be reused. + * + * This is for handling situations accessing the same file system twice, like + * for both the source and destiation of a copy operation. This allows not only + * sharing resources and avoid doing things twice, but also helps avoid file + * sharing violations and inconsistencies araising from the image being updated + * and read independently. + * + * @returns true if the element from @a pReuseSpec an be reused, false if not. + * @param pProviderReg Pointer to the element provider registration. + * @param pSpec The chain specification. + * @param pElement The chain element specification. + * @param pReuseSpec The chain specification of the existing chain. + * @param pReuseElement The chain element specification of the existing + * element that is being considered for reuse. + */ + DECLCALLBACKMEMBER(bool, pfnCanReuseElement,(PCRTVFSCHAINELEMENTREG pProviderReg, + PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement, + PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)); + + /** End marker (RTVFSCHAINELEMENTREG_VERSION). */ + uintptr_t uEndMarker; +} RTVFSCHAINELEMENTREG; + +/** The VFS chain element registration record version number. */ +#define RTVFSCHAINELEMENTREG_VERSION RT_MAKE_U32_FROM_U8(0xff, 0x7f, 1, 0) + + +/** + * Parses the specification. + * + * @returns IPRT status code. + * @param pszSpec The specification string to parse. + * @param fFlags Flags, see RTVFSCHAIN_PF_XXX. + * @param enmDesiredType The object type the caller wants to interface with. + * @param ppSpec Where to return the pointer to the parsed + * specification. This must be freed by calling + * RTVfsChainSpecFree. Will always be set (unless + * invalid parameters.) + * @param poffError Where to return the offset into the input + * specification of what's causing trouble. Always + * set, unless this argument causes an invalid pointer + * error. + */ +RTDECL(int) RTVfsChainSpecParse(const char *pszSpec, uint32_t fFlags, RTVFSOBJTYPE enmDesiredType, + PRTVFSCHAINSPEC *ppSpec, uint32_t *poffError); + +/** @name RTVfsChainSpecParse + * @{ */ +/** Mask of valid flags. */ +#define RTVFSCHAIN_PF_VALID_MASK UINT32_C(0x00000000) +/** @} */ + +/** + * Checks and setups the chain. + * + * @returns IPRT status code. + * @param pSpec The parsed specification. + * @param pReuseSpec Spec to reuse if applicable. Optional. + * @param phVfsObj Where to return the VFS object. + * @param ppszFinalPath Where to return the pointer to the final path if + * applicable. The caller needs to check whether this + * is NULL or a path, in the former case nothing more + * needs doing, whereas in the latter the caller must + * perform the desired operation(s) on *phVfsObj using + * the final path. + * @param poffError Where to return the offset into the input + * specification of what's causing trouble. Always + * set, unless this argument causes an invalid pointer + * error. + * @param pErrInfo Where to return additional error information, if + * available. Optional. + */ +RTDECL(int) RTVfsChainSpecCheckAndSetup(PRTVFSCHAINSPEC pSpec, PCRTVFSCHAINSPEC pReuseSpec, + PRTVFSOBJ phVfsObj, const char **ppszFinalPath, uint32_t *poffError, PRTERRINFO pErrInfo); + +/** + * Frees a parsed chain specification. + * + * @param pSpec What RTVfsChainSpecParse returned. NULL is + * quietly ignored. + */ +RTDECL(void) RTVfsChainSpecFree(PRTVFSCHAINSPEC pSpec); + +/** + * Registers a chain element provider. + * + * @returns IPRT status code + * @param pRegRec The registration record. + * @param fFromCtor Indicates where we're called from. + */ +RTDECL(int) RTVfsChainElementRegisterProvider(PRTVFSCHAINELEMENTREG pRegRec, bool fFromCtor); + +/** + * Deregisters a chain element provider. + * + * @returns IPRT status code + * @param pRegRec The registration record. + * @param fFromDtor Indicates where we're called from. + */ +RTDECL(int) RTVfsChainElementDeregisterProvider(PRTVFSCHAINELEMENTREG pRegRec, bool fFromDtor); + + +/** @def RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER + * Automatically registers a chain element provider using a global constructor + * and destructor hack. + * + * @param pRegRec Pointer to the registration record. + * @param name Some unique variable name prefix. + */ + +#ifdef __cplusplus +/** + * Class used for registering a VFS chain element provider. + */ +class RTVfsChainElementAutoRegisterHack +{ +private: + /** The registration record, NULL if registration failed. */ + PRTVFSCHAINELEMENTREG m_pRegRec; + +public: + RTVfsChainElementAutoRegisterHack(PRTVFSCHAINELEMENTREG a_pRegRec) + : m_pRegRec(a_pRegRec) + { + int rc = RTVfsChainElementRegisterProvider(m_pRegRec, true); + if (RT_FAILURE(rc)) + m_pRegRec = NULL; + } + + ~RTVfsChainElementAutoRegisterHack() + { + RTVfsChainElementDeregisterProvider(m_pRegRec, true); + m_pRegRec = NULL; + } +}; + +# define RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(pRegRec, name) \ + static RTVfsChainElementAutoRegisterHack name ## AutoRegistrationHack(pRegRec) + +#else +# define RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(pRegRec, name) \ + extern void *name ## AutoRegistrationHack = \ + &Sorry_but_RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER_does_not_work_in_c_source_files +#endif + + +/** + * Common worker for the 'stdfile' and 'open' providers for implementing + * RTVFSCHAINELEMENTREG::pfnValidate. + * + * Stores the RTFILE_O_XXX flags in pSpec->uProvider. + * + * @returns IPRT status code. + * @param pSpec The chain specification. + * @param pElement The chain element specification to validate. + * @param poffError Where to return error offset on failure. This is set to + * the pElement->offSpec on input, so it only needs to be + * adjusted if an argument is at fault. + * @param pErrInfo Where to return additional error information, if + * available. Optional. + */ +RTDECL(int) RTVfsChainValidateOpenFileOrIoStream(PRTVFSCHAINSPEC pSpec, PRTVFSCHAINELEMSPEC pElement, + uint32_t *poffError, PRTERRINFO pErrInfo); + + +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_vfslowlevel_h */ + diff --git a/include/iprt/win/Makefile.kup b/include/iprt/win/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/iprt/win/Makefile.kup diff --git a/include/iprt/win/audioclient.h b/include/iprt/win/audioclient.h new file mode 100644 index 00000000..4fb3fed1 --- /dev/null +++ b/include/iprt/win/audioclient.h @@ -0,0 +1,59 @@ +/** @file + * Safe way to include audioclient.h. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_audioclient_h +#define IPRT_INCLUDED_win_audioclient_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* ks.h(1978): warning C4668: '_WIN64' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' [SDK 7.1] */ +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# ifdef __cplusplus +# pragma warning(disable:4091) /* ksmedia.h(4356): warning C4091: 'typedef ': ignored on left of '<unnamed-enum-KSEVENT_DYNAMIC_FORMAT_CHANGE>' when no variable is declared [SDK 7.1] */ +# endif +# endif +#endif + +#include <audioclient.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_audioclient_h */ + diff --git a/include/iprt/win/commctrl.h b/include/iprt/win/commctrl.h new file mode 100644 index 00000000..349bac97 --- /dev/null +++ b/include/iprt/win/commctrl.h @@ -0,0 +1,61 @@ +/** @file + * Safe way to include commctrl.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_commctrl_h +#define IPRT_INCLUDED_win_commctrl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# ifdef __cplusplus +# pragma warning(disable:5039) /* commctrl.h(8323): warning C5039: 'DSA_DestroyCallback': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# ifdef __cplusplus +# pragma warning(disable:4668) /* um\prsht.h(130): warning C4668: 'ISOLATION_AWARE_ENABLED' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# endif +# endif +#endif + +#include <commctrl.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_commctrl_h */ + diff --git a/include/iprt/win/context-amd64.mac b/include/iprt/win/context-amd64.mac new file mode 100644 index 00000000..5a1ec649 --- /dev/null +++ b/include/iprt/win/context-amd64.mac @@ -0,0 +1,118 @@ +;; @file +; IPRT - Windows - AMD64 CPU Context Record for NASM/YASM. +; + +; +; Copyright (C) 2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___iprt_win_context_amd64_mac +%define ___iprt_win_context_amd64_mac + +%include "iprt/asmdefs.mac" + +struc CONTEXT + .P1Home resq 1 + .P2Home resq 1 + .P3Home resq 1 + .P4Home resq 1 + .P5Home resq 1 + .P6Home resq 1 + + .ContextFlags resd 1 + .MxCsr resd 1 + + .SegCs resw 1 ; CONTEXT_CONTROL + .SegDs resw 1 + .SegEs resw 1 + .SegFs resw 1 + .SegGs resw 1 + .SegSs resw 1 ; CONTEXT_CONTROL + .EFlags resd 1 ; CONTEXT_CONTROL + + .Dr0 resq 1 ; CONTEXT_DEBUG_REGISTERS + .Dr1 resq 1 ; CONTEXT_DEBUG_REGISTERS + .Dr2 resq 1 ; CONTEXT_DEBUG_REGISTERS + .Dr3 resq 1 ; CONTEXT_DEBUG_REGISTERS + .Dr6 resq 1 ; CONTEXT_DEBUG_REGISTERS + .Dr7 resq 1 ; CONTEXT_DEBUG_REGISTERS + + .Rax resq 1 ; CONTEXT_INTEGER + .Rcx resq 1 ; CONTEXT_INTEGER + .Rdx resq 1 ; CONTEXT_INTEGER + .Rbx resq 1 ; CONTEXT_INTEGER + .Rsp resq 1 ; CONTEXT_CONTROL + .Rbp resq 1 ; CONTEXT_INTEGER + .Rsi resq 1 ; CONTEXT_INTEGER + .Rdi resq 1 ; CONTEXT_INTEGER + .R8 resq 1 ; CONTEXT_INTEGER + .R9 resq 1 ; CONTEXT_INTEGER + .R10 resq 1 ; CONTEXT_INTEGER + .R11 resq 1 ; CONTEXT_INTEGER + .R12 resq 1 ; CONTEXT_INTEGER + .R13 resq 1 ; CONTEXT_INTEGER + .R14 resq 1 ; CONTEXT_INTEGER + .R15 resq 1 ; CONTEXT_INTEGER + + .Rip resq 1 ; CONTEXT_CONTROL + + .FltSave resb 512 ; X86FXSTATE - CONTEXT_FLOATING_POINT = Xmm0-Xmm15 + + .VectorRegisters resb (26 * 16) + .VectorControl resq 1 + + .DebugControl resq 1 + .LastBranchToRip resq 1 + .LastBranchFromRip resq 1 + .LastExceptionToRip resq 1 + .LastExceptionFromRip resq 1 +endstruc +%define CONTEXT_SIZE (0x4d0) +AssertCompileSize(CONTEXT, CONTEXT_SIZE) + +%define CONTEXT_AMD64 (0x00100000) +%define CONTEXT_CONTROL (0x00000001 | CONTEXT_AMD64) +%define CONTEXT_INTEGER (0x00000002 | CONTEXT_AMD64) +%define CONTEXT_SEGMENTS (0x00000004 | CONTEXT_AMD64) +%define CONTEXT_FLOATING_POINT (0x00000008 | CONTEXT_AMD64) +%define CONTEXT_DEBUG_REGISTERS (0x00000010 | CONTEXT_AMD64) +%define CONTEXT_FULL (0x0000000b | CONTEXT_AMD64) +%define CONTEXT_ALL (0x0000001f | CONTEXT_AMD64) + +%define CONTEXT_XSTATE (0x00000040 | CONTEXT_AMD64) +%define CONTEXT_KERNEL_CET (0x00000080 | CONTEXT_AMD64) +%define CONTEXT_EXCEPTION_ACTIVE (0x08000000) +%define CONTEXT_SERVICE_ACTIVE (0x10000000) +%define CONTEXT_UNWOUND_TO_CALL (0x20000000) +%define CONTEXT_EXCEPTION_REQUEST (0x40000000) +%define CONTEXT_EXCEPTION_REPORTING (0x80000000) + +%endif + diff --git a/include/iprt/win/context-x86.mac b/include/iprt/win/context-x86.mac new file mode 100644 index 00000000..1f126295 --- /dev/null +++ b/include/iprt/win/context-x86.mac @@ -0,0 +1,101 @@ +;; @file +; IPRT - Windows - X86 CPU Context Record for NASM/YASM. +; + +; +; Copyright (C) 2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___iprt_win_context_x86_mac +%define ___iprt_win_context_x86_mac + +%include "iprt/asmdefs.mac" + +struc CONTEXT + .ContextFlags resd 1 + + ; CONTEXT_DEBUG_REGISTERS: + .Dr0 resd 1 + .Dr1 resd 1 + .Dr2 resd 1 + .Dr3 resd 1 + .Dr6 resd 1 + .Dr7 resd 1 + + ; CONTEXT_FLOATING_POINT: + .FloatSave resb 112 ; X86FPUSTATE + 4 bytes + + ; CONTEXT_SEGMENTS: + .SegGs resd 1 + .SegFs resd 1 + .SegEs resd 1 + .SegDs resd 1 + + ; CONTEXT_INTEGER: + .Edi resd 1 + .Esi resd 1 + .Ebx resd 1 + .Edx resd 1 + .Ecx resd 1 + .Eax resd 1 + + ; CONTEXT_CONTROL: + .Ebp resd 1 + .Eip resd 1 + .SegCs resd 1 + .EFlags resd 1 + .Esp resd 1 + .SegSs resd 1 + + ; CONTEXT_EXTENDED_REGISTERS: + .ExtendedRegisters resb 512 +endstruc +%define CONTEXT_SIZE (0x2cc) +AssertCompileSize(CONTEXT, CONTEXT_SIZE) + +%define CONTEXT_i386 (0x00010000) +%define CONTEXT_CONTROL (0x00000001 | CONTEXT_i386) +%define CONTEXT_INTEGER (0x00000002 | CONTEXT_i386) +%define CONTEXT_SEGMENTS (0x00000004 | CONTEXT_i386) +%define CONTEXT_FLOATING_POINT (0x00000008 | CONTEXT_i386) +%define CONTEXT_DEBUG_REGISTERS (0x00000010 | CONTEXT_i386) +%define CONTEXT_EXTENDED_REGISTERS (0x00000020 | CONTEXT_i386) +%define CONTEXT_FULL (0x00000007 | CONTEXT_i386) +%define CONTEXT_ALL (0x0000003f | CONTEXT_i386) + +%define CONTEXT_XSTATE (0x00000040 | CONTEXT_i386) +%define CONTEXT_EXCEPTION_ACTIVE (0x08000000) +%define CONTEXT_SERVICE_ACTIVE (0x10000000) +; 0x20000000 = CONTEXT_UNWOUND_TO_CALL ? +%define CONTEXT_EXCEPTION_REQUEST (0x40000000) +%define CONTEXT_EXCEPTION_REPORTING (0x80000000) + +%endif + diff --git a/include/iprt/win/credentialprovider.h b/include/iprt/win/credentialprovider.h new file mode 100644 index 00000000..2d71cb6f --- /dev/null +++ b/include/iprt/win/credentialprovider.h @@ -0,0 +1,58 @@ +/** @file + * Safe way to include credentialprovider.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_credentialprovider_h +#define IPRT_INCLUDED_win_credentialprovider_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# ifdef __cplusplus +# pragma warning(disable:5039) /* commctrl.h(8323): warning C5039: 'DSA_DestroyCallback': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +#endif + +#include <credentialprovider.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_credentialprovider_h */ + diff --git a/include/iprt/win/d3d8.h b/include/iprt/win/d3d8.h new file mode 100644 index 00000000..14f1c4ed --- /dev/null +++ b/include/iprt/win/d3d8.h @@ -0,0 +1,60 @@ +/** @file + * Safe way to include d3d8.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_d3d8_h +#define IPRT_INCLUDED_win_d3d8_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +/*# pragma warning(disable:4163)*/ +# pragma warning(disable:4668) /* warning C4668: 'WHEA_DOWNLEVEL_TYPE_NAMES' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# pragma warning(disable:4255) /* warning C4255: 'ObGetFilterVersion' : no function prototype given: converting '()' to '(void)' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +#endif + +#include <d3d8.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + + +#endif /* !IPRT_INCLUDED_win_d3d8_h */ + diff --git a/include/iprt/win/d3d9.h b/include/iprt/win/d3d9.h new file mode 100644 index 00000000..52c02c53 --- /dev/null +++ b/include/iprt/win/d3d9.h @@ -0,0 +1,68 @@ +/** @file + * Safe way to include d3d9.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_d3d9_h +#define IPRT_INCLUDED_win_d3d9_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* d3d9.h includes windows.h (via objbase.h -> rpc.h), so do it up front using + our wrappers to avoid needing to duplicate warning workarounds for it. */ +#include <iprt/win/windows.h> + +#ifdef _MSC_VER +# pragma warning(push) +/*# pragma warning(disable:4163)*/ +# pragma warning(disable:4668) /* warning C4668: 'WHEA_DOWNLEVEL_TYPE_NAMES' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# pragma warning(disable:4255) /* warning C4255: 'ObGetFilterVersion' : no function prototype given: converting '()' to '(void)' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +# ifdef __cplusplus +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:5039) /* winbase.h(13179): warning C5039: 'TpSetCallbackCleanupGroup': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +#endif + +#include <d3d9.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_d3d9_h */ + diff --git a/include/iprt/win/d3dkmthk.h b/include/iprt/win/d3dkmthk.h new file mode 100644 index 00000000..af8fa34f --- /dev/null +++ b/include/iprt/win/d3dkmthk.h @@ -0,0 +1,61 @@ +/** @file + * Safe way to include d3dkmthk.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_d3dkmthk_h +#define IPRT_INCLUDED_win_d3dkmthk_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:4255) /* d3dkmthk.h(2061): warning C4255: 'PFND3DKMT_CHECKEXCLUSIVEOWNERSHIP': no function prototype given: converting '()' to '(void)' */ +# endif +#endif + +/* 10.0.22000.0 SDK: */ +#define DXGKDDI_INTERFACE_VERSION_WDDM_1_3 DXGKDDI_INTERFACE_VERSION_WDDM1_3 +#define DXGKDDI_INTERFACE_VERSION_WDDM_2_0 DXGKDDI_INTERFACE_VERSION_WDDM2_0 +#define DXGKDDI_INTERFACE_VERSION_WDDM1_3_M1 DXGKDDI_INTERFACE_VERSION_WDDM1_3 + +#include <d3dkmthk.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_d3dkmthk_h */ + diff --git a/include/iprt/win/dbghelp.h b/include/iprt/win/dbghelp.h new file mode 100644 index 00000000..00d50b32 --- /dev/null +++ b/include/iprt/win/dbghelp.h @@ -0,0 +1,61 @@ +/** @file + * Safe way to include Dbghelp.h. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_dbghelp_h +#define IPRT_INCLUDED_win_dbghelp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +/* + * Unfortunately, the Windows.h file in SDK 7.1 is not clean wrt warning C4091 with VCC140+: + * Dbghelp.h(1540): warning C4091: 'typedef ': ignored on left of '<unnamed-enum-hdBase>' when no variable is declared + * Dbghelp.h(3056): warning C4091: 'typedef ': ignored on left of '<unnamed-enum-sfImage>' when no variable is declared + */ +# pragma warning(push) +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:4091) +# endif +#endif + +#include <Dbghelp.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_dbghelp_h */ + diff --git a/include/iprt/win/dshow.h b/include/iprt/win/dshow.h new file mode 100644 index 00000000..eab1fdce --- /dev/null +++ b/include/iprt/win/dshow.h @@ -0,0 +1,56 @@ +/** @file + * Safe way to include dshow.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_dshow_h +#define IPRT_INCLUDED_win_dshow_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# if _MSC_VER >= 1920 /*RT_MSC_VER_VC142*/ +# pragma warning(disable:5204) /* strmif.h(16270): warning C5204: 'IAMFilterGraphCallback': class has virtual functions, but its trivial destructor is not virtual; instances of objects derived from this class may not be destructed correctly */ +# endif +#endif + +#include <dshow.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_dshow_h */ + diff --git a/include/iprt/win/endpointvolume.h b/include/iprt/win/endpointvolume.h new file mode 100644 index 00000000..ec9cced5 --- /dev/null +++ b/include/iprt/win/endpointvolume.h @@ -0,0 +1,58 @@ +/** @file + * Safe way to include endpointvolume.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_endpointvolume_h +#define IPRT_INCLUDED_win_endpointvolume_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4201) +# pragma warning(disable:4668) /* ks.h(1978): warning C4668: '_WIN64' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' [SDK 7.1] */ +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable: 4091) /* v7.1\include\ksmedia.h(4356): warning C4091: 'typedef ': ignored on left of '<unnamed-enum-KSEVENT_DYNAMIC_FORMAT_CHANGE>' when no variable is declared */ +# endif +#endif + +#include <endpointvolume.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_endpointvolume_h */ + diff --git a/include/iprt/win/imagehlp.h b/include/iprt/win/imagehlp.h new file mode 100644 index 00000000..138bdd3b --- /dev/null +++ b/include/iprt/win/imagehlp.h @@ -0,0 +1,61 @@ +/** @file + * Safe way to include ImageHlp.h. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_imagehlp_h +#define IPRT_INCLUDED_win_imagehlp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +/* + * Unfortunately, the ImageHlp.h file in SDK 7.1 is not clean wrt warning C4091 with VCC141: + * ImageHlp.h(1869): warning C4091: 'typedef ': ignored on left of '<unnamed-enum-hdBase>' when no variable is declared + * ImageHlp.h(3385): warning C4091: 'typedef ': ignored on left of '<unnamed-enum-sfImage>' when no variable is declared + */ +# pragma warning(push) +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:4091) +# endif +#endif + +#include <ImageHlp.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_imagehlp_h */ + diff --git a/include/iprt/win/intsafe.h b/include/iprt/win/intsafe.h new file mode 100644 index 00000000..182b93de --- /dev/null +++ b/include/iprt/win/intsafe.h @@ -0,0 +1,77 @@ +/** @file + * Safe way to include intsafe.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_intsafe_h +#define IPRT_INCLUDED_win_intsafe_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* There's a conflict between the Visual C++ 2010 stdint.h and wDK 7.1 intsafe.h + that we must to mediate here. Current approach is to use the stuff from + intsafe.h rather than the other. */ +#ifndef _INTSAFE_H_INCLUDED_ +# include <iprt/stdint.h> +# undef INT8_MIN +# undef INT16_MIN +# undef INT32_MIN +# undef INT8_MAX +# undef INT16_MAX +# undef INT32_MAX +# undef UINT8_MAX +# undef UINT16_MAX +# undef UINT32_MAX +# undef INT64_MIN +# undef INT64_MAX +# undef UINT64_MAX + +# ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* intsafe.h(55) : warning C4668: '__midl' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +# endif + +# include <intsafe.h> + +# ifdef _MSC_VER +# pragma warning(pop) +# endif + +#endif /* !_INTSAFE_H_INCLUDED_ */ + +#endif /* !IPRT_INCLUDED_win_intsafe_h */ + diff --git a/include/iprt/win/iphlpapi.h b/include/iprt/win/iphlpapi.h new file mode 100644 index 00000000..d823e1ac --- /dev/null +++ b/include/iprt/win/iphlpapi.h @@ -0,0 +1,50 @@ +/** @file + * Safe way to include iphlpapi.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_iphlpapi_h +#define IPRT_INCLUDED_win_iphlpapi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#pragma warning(push) +#pragma warning(disable:4668) /* 'NDIS_SUPPORT_NDIS6' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ + +#include <iphlpapi.h> + +#pragma warning(pop) + +#endif /* !IPRT_INCLUDED_win_iphlpapi_h */ + diff --git a/include/iprt/win/ks.h b/include/iprt/win/ks.h new file mode 100644 index 00000000..6febf26c --- /dev/null +++ b/include/iprt/win/ks.h @@ -0,0 +1,54 @@ +/** @file + * Safe way to include ks.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_ks_h +#define IPRT_INCLUDED_win_ks_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* C4668: '_WIN64' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +#endif + +#include <ks.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_ks_h */ + diff --git a/include/iprt/win/lazy-dbghelp.h b/include/iprt/win/lazy-dbghelp.h new file mode 100644 index 00000000..a6924bb1 --- /dev/null +++ b/include/iprt/win/lazy-dbghelp.h @@ -0,0 +1,151 @@ +/** @file + * Symbols from dbghelp.dll, allowing us to select which one to load. + */ + +/* + * Copyright (C) 2013-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_lazy_dbghelp_h +#define IPRT_INCLUDED_win_lazy_dbghelp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/ldrlazy.h> +#include <iprt/path.h> +#include <iprt/env.h> +#include <iprt/errcore.h> + + +/** + * Custom loader callback. + * @returns Module handle or NIL_RTLDRMOD. + */ +static int rtLdrLazyLoadDbgHelp(const char *pszFile, PRTLDRMOD phMod) +{ + static const struct + { + const char *pszEnv; + const char *pszSubDir; + } s_aLocations[] = + { +#ifdef RT_ARCH_AMD64 + { "ProgramFiles(x86)", "Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll" }, + { "ProgramFiles(x86)", "Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll" }, + { "ProgramFiles", "Debugging Tools for Windows (x64)\\dbghelp.dll" }, +#else + { "ProgramFiles", "Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll" }, + { "ProgramFiles", "Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll" }, + { "ProgramFiles", "Debugging Tools for Windows (x86)\\dbghelp.dll" }, +#endif /** @todo More places we should look? */ + }; + uint32_t i; + for (i = 0; i < RT_ELEMENTS(s_aLocations); i++) + { + char szPath[RTPATH_MAX]; + size_t cchPath; + int rc = RTEnvGetEx(RTENV_DEFAULT, s_aLocations[i].pszEnv, szPath, sizeof(szPath), &cchPath); + if (RT_SUCCESS(rc)) + { + rc = RTPathAppend(szPath, sizeof(szPath), s_aLocations[i].pszSubDir); + if (RT_SUCCESS(rc)) + { + rc = RTLdrLoad(szPath, phMod); + if (RT_SUCCESS(rc)) + return rc; + } + } + } + + /* Fall back on the system one, if present. */ + return RTLdrLoadSystem(pszFile, true /*fNoUnload*/, phMod); +} + +RTLDRLAZY_MODULE_EX(dbghelp, "dbghelp.dll", rtLdrLazyLoadDbgHelp); + +RTLDRLAZY_FUNC(dbghelp, BOOL, WINAPI, SymInitialize, (HANDLE a1, PCWSTR a2, BOOL a3), (a1, a2, a3), FALSE); +#undef SymInitialize +#define SymInitialize RTLDRLAZY_FUNC_NAME(dbghelp, SymInitialize) + +RTLDRLAZY_FUNC(dbghelp, BOOL, WINAPI, SymCleanup, (HANDLE a1), (a1), FALSE); +#undef SymCleanup +#define SymCleanup RTLDRLAZY_FUNC_NAME(dbghelp, SymCleanup) + +RTLDRLAZY_FUNC(dbghelp, DWORD, WINAPI, SymGetOptions, (VOID), (), 0); +#undef SymGetOptions +#define SymGetOptions RTLDRLAZY_FUNC_NAME(dbghelp, SymGetOptions) + +RTLDRLAZY_FUNC(dbghelp, DWORD, WINAPI, SymSetOptions, (DWORD a1), (a1), 0); +#undef SymSetOptions +#define SymSetOptions RTLDRLAZY_FUNC_NAME(dbghelp, SymSetOptions) + +RTLDRLAZY_FUNC(dbghelp, BOOL, WINAPI, SymRegisterCallback64, (HANDLE a1, PSYMBOL_REGISTERED_CALLBACK64 a2, ULONG64 a3), + (a1, a2, a3), FALSE); +#undef SymRegisterCallback64 +#define SymRegisterCallback64 RTLDRLAZY_FUNC_NAME(dbghelp, SymRegisterCallback64) + +RTLDRLAZY_FUNC(dbghelp, DWORD64, WINAPI, SymLoadModuleEx, + (HANDLE a1, HANDLE a2, PCSTR a3, PCSTR a4, DWORD64 a5, DWORD a6, PMODLOAD_DATA a7, DWORD a8), + (a1, a2, a3, a4, a5, a6, a7, a8), 0); +#undef SymLoadModuleEx +#define SymLoadModuleEx RTLDRLAZY_FUNC_NAME(dbghelp, SymLoadModuleEx) + +RTLDRLAZY_FUNC(dbghelp, DWORD64, WINAPI, SymLoadModuleExW, + (HANDLE a1, HANDLE a2, PCWSTR a3, PCWSTR a4, DWORD64 a5, DWORD a6, PMODLOAD_DATA a7, DWORD a8), + (a1, a2, a3, a4, a5, a6, a7, a8), 0); +#undef SymLoadModuleExW +#define SymLoadModuleExW RTLDRLAZY_FUNC_NAME(dbghelp, SymLoadModuleExW) + +RTLDRLAZY_FUNC(dbghelp, DWORD64, WINAPI, SymUnloadModule64, (HANDLE a1, DWORD64 a2), (a1, a2), 0); +#undef SymUnloadModule64 +#define SymUnloadModule64 RTLDRLAZY_FUNC_NAME(dbghelp, SymUnloadModule64) + +RTLDRLAZY_FUNC(dbghelp, BOOL, WINAPI, SymEnumSymbols, + (HANDLE a1, ULONG64 a2, PCSTR a3, PSYM_ENUMERATESYMBOLS_CALLBACK a4, PVOID a5), + (a1, a2, a3, a4, a5), FALSE); +#undef SymEnumSymbols +#define SymEnumSymbols RTLDRLAZY_FUNC_NAME(dbghelp, SymEnumSymbols) + +RTLDRLAZY_FUNC(dbghelp, BOOL, WINAPI, SymEnumLinesW, + (HANDLE a1, ULONG64 a2, PCWSTR a3, PCWSTR a4, PSYM_ENUMLINES_CALLBACKW a5, PVOID a6), + (a1, a2, a3, a4, a5, a6), FALSE); +#undef SymEnumLinesW +#define SymEnumLinesW RTLDRLAZY_FUNC_NAME(dbghelp, SymEnumLinesW) + +RTLDRLAZY_FUNC(dbghelp, BOOL, WINAPI, SymGetModuleInfo64, (HANDLE a1, DWORD64 a2, PIMAGEHLP_MODULE64 a3), (a1, a2, a3), FALSE); +#undef SymGetModuleInfo64 +#define SymGetModuleInfo64 RTLDRLAZY_FUNC_NAME(dbghelp, SymGetModuleInfo64) + + + + +#endif /* !IPRT_INCLUDED_win_lazy_dbghelp_h */ + diff --git a/include/iprt/win/mmreg.h b/include/iprt/win/mmreg.h new file mode 100644 index 00000000..8be69c7c --- /dev/null +++ b/include/iprt/win/mmreg.h @@ -0,0 +1,53 @@ +/** @file + * Safe way to include mmreg.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_mmreg_h +#define IPRT_INCLUDED_win_mmreg_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) /* Looks like this header messes with warning config, at least in the 7.1 SDK. */ +#endif + +#include <mmreg.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_mmreg_h */ + diff --git a/include/iprt/win/netioapi.h b/include/iprt/win/netioapi.h new file mode 100644 index 00000000..5abf1bac --- /dev/null +++ b/include/iprt/win/netioapi.h @@ -0,0 +1,46 @@ +/** @file + * Safe way to include netioapi.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_netioapi_h +#define IPRT_INCLUDED_win_netioapi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/win/ntddndis.h> /* this one has problems with -Wall */ +#include <netioapi.h> + +#endif /* !IPRT_INCLUDED_win_netioapi_h */ + diff --git a/include/iprt/win/ntdddisk.h b/include/iprt/win/ntdddisk.h new file mode 100644 index 00000000..452a5ac5 --- /dev/null +++ b/include/iprt/win/ntdddisk.h @@ -0,0 +1,50 @@ +/** @file + * Safe way to include ntdddisk.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_ntdddisk_h +#define IPRT_INCLUDED_win_ntdddisk_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#pragma warning(push) +#pragma warning(disable:4668) /* ntdddisk.h(137) : warning C4668: 'NTDDI_WIN2003' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ + +#include <ntdddisk.h> + +#pragma warning(pop) + +#endif /* !IPRT_INCLUDED_win_ntdddisk_h */ + diff --git a/include/iprt/win/ntddndis.h b/include/iprt/win/ntddndis.h new file mode 100644 index 00000000..fc9b8520 --- /dev/null +++ b/include/iprt/win/ntddndis.h @@ -0,0 +1,50 @@ +/** @file + * Safe way to include ntddndis.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_ntddndis_h +#define IPRT_INCLUDED_win_ntddndis_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#pragma warning(push) +#pragma warning(disable:4668) /* 'NDIS_SUPPORT_NDIS6' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ + +#include <ntddndis.h> + +#pragma warning(pop) + +#endif /* !IPRT_INCLUDED_win_ntddndis_h */ + diff --git a/include/iprt/win/ntverp.h b/include/iprt/win/ntverp.h new file mode 100644 index 00000000..484d8152 --- /dev/null +++ b/include/iprt/win/ntverp.h @@ -0,0 +1,50 @@ +/** @file + * Safe way to include ntverp.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_ntverp_h +#define IPRT_INCLUDED_win_ntverp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#pragma warning(push) +#pragma warning(disable:4668) /*ntverp.h(126) : warning C4668: 'OFFICIAL_BUILD' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ + +#include <ntverp.h> + +#pragma warning(pop) + +#endif /* !IPRT_INCLUDED_win_ntverp_h */ + diff --git a/include/iprt/win/objbase.h b/include/iprt/win/objbase.h new file mode 100644 index 00000000..8bcb5c00 --- /dev/null +++ b/include/iprt/win/objbase.h @@ -0,0 +1,69 @@ +/** @file + * Safe way to include objbase.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_objbase_h +#define IPRT_INCLUDED_win_objbase_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* objbase.h includes windows.h via rpc.h, so get ahead of it and include + it here via our cleanup wrapper. */ +#include <iprt/win/windows.h> + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* '__midl' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# if !defined(__cplusplus) +# pragma warning(disable:4255) /* 'FARPROC' : no function prototype given: converting '()' to '(void)' */ +# endif +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +# ifdef __cplusplus +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:5039) /* winbase.h(13179): warning C5039: 'TpSetCallbackCleanupGroup': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +#endif + +#include <objbase.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_objbase_h */ + diff --git a/include/iprt/win/objidl.h b/include/iprt/win/objidl.h new file mode 100644 index 00000000..d12e8bd7 --- /dev/null +++ b/include/iprt/win/objidl.h @@ -0,0 +1,63 @@ +/** @file + * Safe way to include objidl.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_objidl_h +#define IPRT_INCLUDED_win_objidl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* '__midl' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# pragma warning(disable:4255) /* windef.h(227) : warning C4255: 'NEARPROC' : no function prototype given: converting '()' to '(void)' */ +# endif +# ifdef __cplusplus +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:5039) /* winbase.h(13179): warning C5039: 'TpSetCallbackCleanupGroup': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +#endif + +#include <objidl.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_objidl_h */ + diff --git a/include/iprt/win/rpcproxy.h b/include/iprt/win/rpcproxy.h new file mode 100644 index 00000000..8d355bb2 --- /dev/null +++ b/include/iprt/win/rpcproxy.h @@ -0,0 +1,75 @@ +/** @file + * Safe way to include rpcproxy.h (not C++ clean). + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_rpcproxy_h +#define IPRT_INCLUDED_win_rpcproxy_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <objbase.h> + +#ifdef __cplusplus + +typedef struct IRpcStubBufferVtbl +{ + BEGIN_INTERFACE + HRESULT (STDMETHODCALLTYPE *QueryInterface)(IRpcStubBuffer *, REFIID, void **); + ULONG (STDMETHODCALLTYPE *AddRef)(IRpcStubBuffer *); + ULONG (STDMETHODCALLTYPE *Release)(IRpcStubBuffer *); + HRESULT (STDMETHODCALLTYPE *Connect)(IRpcStubBuffer *, IUnknown *); + void (STDMETHODCALLTYPE *Disconnect)(IRpcStubBuffer *); + HRESULT (STDMETHODCALLTYPE *Invoke)(IRpcStubBuffer *, RPCOLEMESSAGE *, IRpcChannelBuffer *); + IRpcStubBuffer * (STDMETHODCALLTYPE *IsIIDSupported)(IRpcStubBuffer *, REFIID); + ULONG (STDMETHODCALLTYPE *CountRefs)(IRpcStubBuffer *); + HRESULT (STDMETHODCALLTYPE *DebugServerQueryInterface)(IRpcStubBuffer *, void **); + void (STDMETHODCALLTYPE *DebugServerRelease)(IRpcStubBuffer *, void *); +} IRpcStubBufferVtbl; + +typedef struct IPSFactoryBufferVtbl +{ + HRESULT (STDMETHODCALLTYPE *QueryInterface)(IPSFactoryBuffer *, REFIID, void **); + ULONG (STDMETHODCALLTYPE *AddRef)(IPSFactoryBuffer *); + ULONG (STDMETHODCALLTYPE *Release)(IPSFactoryBuffer *); + HRESULT (STDMETHODCALLTYPE *CreateProxy)(IPSFactoryBuffer *, IUnknown *, REFIID riid, IRpcProxyBuffer **, void **); + HRESULT (STDMETHODCALLTYPE *CreateStub)(IPSFactoryBuffer *, REFIID, IUnknown *, IRpcStubBuffer **); +} IPSFactoryBufferVtbl; + +#endif /* __cplusplus */ + +#include <rpcproxy.h> + +#endif /* !IPRT_INCLUDED_win_rpcproxy_h */ + diff --git a/include/iprt/win/setupapi.h b/include/iprt/win/setupapi.h new file mode 100644 index 00000000..704cedaf --- /dev/null +++ b/include/iprt/win/setupapi.h @@ -0,0 +1,59 @@ +/** @file + * Safe way to include setupapi.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_setupapi_h +#define IPRT_INCLUDED_win_setupapi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* warning C4668: 'USE_SP_ALTPLATFORM_INFO_V1' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# ifdef __cplusplus +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:5039) /* winbase.h(13179): warning C5039: 'TpSetCallbackCleanupGroup': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +#endif + +#include <setupapi.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_setupapi_h */ + diff --git a/include/iprt/win/shlobj.h b/include/iprt/win/shlobj.h new file mode 100644 index 00000000..bcbfd343 --- /dev/null +++ b/include/iprt/win/shlobj.h @@ -0,0 +1,67 @@ +/** @file + * Safe way to include shlobj.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_shlobj_h +#define IPRT_INCLUDED_win_shlobj_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* warning C4668: 'USE_SP_ALTPLATFORM_INFO_V1' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# pragma warning(disable:4255) /* windef.h(227) : warning C4255: 'NEARPROC' : no function prototype given: converting '()' to '(void)' */ +# endif +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:4091) /* sdk/v7.1/include/shlobj.h(1151): warning C4091: 'typedef ': ignored on left of 'tagGPFIDL_FLAGS' when no variable is declared */ +# ifdef __cplusplus +# pragma warning(disable:5039) /* commctrl.h(8323): warning C5039: 'DSA_DestroyCallback': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +# if _MSC_VER >= 1910 /*RT_MSC_VER_VC141*/ +# pragma warning(disable:4768) /* sdk/v7.1/include/shlobj.h(1065): warning C4768: __declspec attributes before linkage specification are ignored */ +# endif +#endif + +#include <shlobj.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_shlobj_h */ + diff --git a/include/iprt/win/shlwapi.h b/include/iprt/win/shlwapi.h new file mode 100644 index 00000000..f1b037d1 --- /dev/null +++ b/include/iprt/win/shlwapi.h @@ -0,0 +1,53 @@ +/** @file + * Safe way to include shlwapi.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_shlwapi_h +#define IPRT_INCLUDED_win_shlwapi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#pragma warning(push) +#pragma warning(disable:4668) /* warning C4668: 'USE_SP_ALTPLATFORM_INFO_V1' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +#pragma warning(disable:4255) /* warning C4255: 'I_RpcMgmtEnableDedicatedThreadPool' : no function prototype given: converting '()' to '(void)' */ +#if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +#endif +#include <shlwapi.h> + +#pragma warning(pop) + +#endif /* !IPRT_INCLUDED_win_shlwapi_h */ + diff --git a/include/iprt/win/windef.h b/include/iprt/win/windef.h new file mode 100644 index 00000000..44c6a6ee --- /dev/null +++ b/include/iprt/win/windef.h @@ -0,0 +1,65 @@ +/** @file + * Safe way to include windef.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_windef_h +#define IPRT_INCLUDED_win_windef_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +/* + * Unfortunately, the windef.h file in SDK 7.1 is not clean wrt warning C4668: + * basetsd.h(114) : warning C4668: '__midl' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' + * winnt.h(13017) : warning C4668: '_DBG_MEMCPY_INLINE_' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' + */ +# pragma warning(push) +# pragma warning(disable:4668) +# ifndef __cplusplus +# pragma warning(disable:4255) /* warning C4255: 'FARPROC' : no function prototype given: converting '()' to '(void)' */ +# endif +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +#endif + +#include <windef.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_windef_h */ + diff --git a/include/iprt/win/windows.h b/include/iprt/win/windows.h new file mode 100644 index 00000000..b1612713 --- /dev/null +++ b/include/iprt/win/windows.h @@ -0,0 +1,110 @@ +/** @file + * Safe way to include Windows.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_windows_h +#define IPRT_INCLUDED_win_windows_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/* winioctl.h in windows 10 SDKs up to 22000(?) has a warning(push/pop) bug in the + portion taken from ntddscm.h causing trouble when using _WIN32_WINNT or NTDDI_VERSION + older than NTDDI_WIN10_RS5. In 18362 winioctl.h also tests against _WIN32_WINNT_WIN10_TH2 + and other sdkddkver.h defines which only exist in NTDDI variants, not in _WIN32_WINNT_XXX, + so we fake up those too to keep the precompiler warning free. + + Work around this by blocking out the buggy section on winioctl.h for now if the + NTDDI_VERSION target is too small. + + WDK_NTDDI_VERSION is not present in the W7 SDK, not sure when exactly it was added. + NTDDI_WIN10_RS5 is W10 1809. NTDDI_WIN10_CO is Windows 11? */ +#include <sdkddkver.h> +#ifdef _WIN32_WINNT_WIN10 +# ifndef _WIN32_WINNT_WIN10_TH2 +# define _WIN32_WINNT_WIN10_TH2 _WIN32_WINNT_WIN10 +# endif +# ifndef _WIN32_WINNT_WIN10_RS1 +# define _WIN32_WINNT_WIN10_RS1 _WIN32_WINNT_WIN10 +# endif +# ifndef _WIN32_WINNT_WIN10_RS2 +# define _WIN32_WINNT_WIN10_RS2 _WIN32_WINNT_WIN10 +# endif +# ifndef _WIN32_WINNT_WIN10_RS3 +# define _WIN32_WINNT_WIN10_RS3 _WIN32_WINNT_WIN10 +# endif +# ifndef _WIN32_WINNT_WIN10_RS4 +# define _WIN32_WINNT_WIN10_RS4 _WIN32_WINNT_WIN10 +# endif +# ifndef _WIN32_WINNT_WIN10_RS5 +# define _WIN32_WINNT_WIN10_RS5 _WIN32_WINNT_WIN10 +# endif +#endif +#if defined(NTDDI_WIN10_RS5) && !defined(NTDDI_WIN10_CO) && defined(WDK_NTDDI_VERSION) +# if NTDDI_VERSION < NTDDI_WIN10_RS5 +# define _NTDDSCM_H_ buggy, hope nobody needs it. +# endif +#endif + +#ifdef _MSC_VER +/* + * Unfortunately, the Windows.h file in SDK 7.1 is not clean wrt warning C4668: + * wincrypt.h(1848) : warning C4668: 'NTDDI_WINLH' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' + */ +# pragma warning(push) +# pragma warning(disable:4668) +# pragma warning(disable:4480) /* W10/wincrypt.h(9193) : warning C4480: nonstandard extension used: specifying underlying type for enum 'CertKeyType' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +# ifdef __cplusplus +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:5039) /* winbase.h(13179): warning C5039: 'TpSetCallbackCleanupGroup': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# else +# pragma warning(disable:4255) /* warning C4255: 'FARPROC' : no function prototype given: converting '()' to '(void)' */ +# endif +#endif + +#include <Windows.h> + +#ifdef _MSC_VER +# pragma warning(pop) +/* VS2010: Something causes this to be re-enabled above and triggering errors using RT_FLEXIBLE_ARRAY. */ +# pragma warning(disable:4200) +#endif + +#endif /* !IPRT_INCLUDED_win_windows_h */ + diff --git a/include/iprt/win/winsock.h b/include/iprt/win/winsock.h new file mode 100644 index 00000000..aabc3372 --- /dev/null +++ b/include/iprt/win/winsock.h @@ -0,0 +1,64 @@ +/** @file + * Safe way to include winsock2.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_winsock_h +#define IPRT_INCLUDED_win_winsock_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef _MSC_VER +/* + * Unfortunately, the Windows.h file in SDK 7.1 is not clean wrt warning C4668: + * wincrypt.h(1848) : warning C4668: 'NTDDI_WINLH' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' + */ +# pragma warning(push) +# pragma warning(disable:4668) +# ifndef __cplusplus +# pragma warning(disable:4255) /* warning C4255: 'FARPROC' : no function prototype given: converting '()' to '(void)' */ +# endif +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +#endif + +#include <winsock.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_winsock_h */ + diff --git a/include/iprt/win/winsock2.h b/include/iprt/win/winsock2.h new file mode 100644 index 00000000..4c834b9a --- /dev/null +++ b/include/iprt/win/winsock2.h @@ -0,0 +1,74 @@ +/** @file + * Safe way to include winsock2.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_winsock2_h +#define IPRT_INCLUDED_win_winsock2_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* winsock2.h includes windows.h, but without winsock.h, so we need to do it + up front using our wrapper header to avoid repeating tricks here. */ +#define _WINSOCKAPI_ /* do not include winsock.h via windows.h */ +#include <iprt/win/windows.h> + +#ifdef _MSC_VER +/* + * Unfortunately, the Windows.h file in SDK 7.1 is not clean wrt warning C4668: + * wincrypt.h(1848) : warning C4668: 'NTDDI_WINLH' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' + */ +# pragma warning(push) +# pragma warning(disable:4668) +# ifndef __cplusplus +# pragma warning(disable:4255) /* warning C4255: 'FARPROC' : no function prototype given: converting '()' to '(void)' */ +# endif +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# ifdef __cplusplus +# pragma warning(disable:5039) /* winbase.h(13179): warning C5039: 'TpSetCallbackCleanupGroup': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +#endif + +#include <winsock2.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_winsock2_h */ + diff --git a/include/iprt/win/ws2tcpip.h b/include/iprt/win/ws2tcpip.h new file mode 100644 index 00000000..ea5e7f2a --- /dev/null +++ b/include/iprt/win/ws2tcpip.h @@ -0,0 +1,67 @@ +/** @file + * Safe way to include ws2tcpip.h. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_win_ws2tcpip_h +#define IPRT_INCLUDED_win_ws2tcpip_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* ws2tcpip.h includes winsock2.h, so get ahead of it and include our cleanly + wrapped version first to avoid duplicating stuff here. */ +#include <iprt/win/winsock2.h> + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668) /* 'NDIS_SUPPORT_NDIS6' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# pragma warning(disable:4255) /* windef.h(227) : warning C4255: 'NEARPROC' : no function prototype given: converting '()' to '(void)' */ +# endif +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# ifdef __cplusplus +# pragma warning(disable:5039) /* ws2tcpip.h(874): warning C5039: 'WSAIoctl': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +#endif + +#include <ws2tcpip.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* !IPRT_INCLUDED_win_ws2tcpip_h */ + diff --git a/include/iprt/x86-helpers.h b/include/iprt/x86-helpers.h new file mode 100644 index 00000000..78f88762 --- /dev/null +++ b/include/iprt/x86-helpers.h @@ -0,0 +1,261 @@ +/** @file + * IPRT - X86 and AMD64 Helpers. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_x86_helpers_h +#define IPRT_INCLUDED_x86_helpers_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + + +/** @defgroup grp_rt_x86_helpers x86 Helper Functions + * @ingroup grp_rt_x86 + * @{ + */ + + +/** + * Tests if it a genuine Intel CPU based on the ASMCpuId(0) output. + * + * @returns true/false. + * @param uEBX EBX return from ASMCpuId(0) + * @param uECX ECX return from ASMCpuId(0) + * @param uEDX EDX return from ASMCpuId(0) + */ +DECLINLINE(bool) RTX86IsIntelCpu(uint32_t uEBX, uint32_t uECX, uint32_t uEDX) +{ + /* 'GenuineIntel' */ + return uEBX == UINT32_C(0x756e6547) /* 'Genu' */ + && uEDX == UINT32_C(0x49656e69) /* 'ineI' */ + && uECX == UINT32_C(0x6c65746e); /* 'ntel' */ +} + + +/** + * Tests if it an authentic AMD CPU based on the ASMCpuId(0) output. + * + * @returns true/false. + * @param uEBX EBX return from ASMCpuId(0) + * @param uECX ECX return from ASMCpuId(0) + * @param uEDX EDX return from ASMCpuId(0) + */ +DECLINLINE(bool) RTX86IsAmdCpu(uint32_t uEBX, uint32_t uECX, uint32_t uEDX) +{ + /* 'AuthenticAMD' */ + return uEBX == UINT32_C(0x68747541) /* 'Auth' */ + && uEDX == UINT32_C(0x69746e65) /* 'enti' */ + && uECX == UINT32_C(0x444d4163); /* 'dAMD' */ +} + + +/** + * Tests if it a centaur hauling VIA CPU based on the ASMCpuId(0) output. + * + * @returns true/false. + * @param uEBX EBX return from ASMCpuId(0). + * @param uECX ECX return from ASMCpuId(0). + * @param uEDX EDX return from ASMCpuId(0). + */ +DECLINLINE(bool) RTX86IsViaCentaurCpu(uint32_t uEBX, uint32_t uECX, uint32_t uEDX) +{ + /* 'CentaurHauls' */ + return uEBX == UINT32_C(0x746e6543) /* 'Cent' */ + && uEDX == UINT32_C(0x48727561) /* 'aurH' */ + && uECX == UINT32_C(0x736c7561); /* 'auls' */ +} + + +/** + * Tests if it a Shanghai CPU based on the ASMCpuId(0) output. + * + * @returns true/false. + * @param uEBX EBX return from ASMCpuId(0). + * @param uECX ECX return from ASMCpuId(0). + * @param uEDX EDX return from ASMCpuId(0). + */ +DECLINLINE(bool) RTX86IsShanghaiCpu(uint32_t uEBX, uint32_t uECX, uint32_t uEDX) +{ + /* ' Shanghai ' */ + return uEBX == UINT32_C(0x68532020) /* ' Sh' */ + && uEDX == UINT32_C(0x68676e61) /* 'angh' */ + && uECX == UINT32_C(0x20206961); /* 'ai ' */ +} + + +/** + * Tests if it a genuine Hygon CPU based on the ASMCpuId(0) output. + * + * @returns true/false. + * @param uEBX EBX return from ASMCpuId(0) + * @param uECX ECX return from ASMCpuId(0) + * @param uEDX EDX return from ASMCpuId(0) + */ +DECLINLINE(bool) RTX86IsHygonCpu(uint32_t uEBX, uint32_t uECX, uint32_t uEDX) +{ + /* 'HygonGenuine' */ + return uEBX == UINT32_C(0x6f677948) /* Hygo */ + && uECX == UINT32_C(0x656e6975) /* uine */ + && uEDX == UINT32_C(0x6e65476e); /* nGen */ +} + + +/** + * Checks whether ASMCpuId_EAX(0x00000000) indicates a valid range. + * + * + * @returns true/false. + * @param uEAX The EAX value of CPUID leaf 0x00000000. + * + * @note This only succeeds if there are at least two leaves in the range. + * @remarks The upper range limit is just some half reasonable value we've + * picked out of thin air. + */ +DECLINLINE(bool) RTX86IsValidStdRange(uint32_t uEAX) +{ + return uEAX >= UINT32_C(0x00000001) && uEAX <= UINT32_C(0x000fffff); +} + + +/** + * Checks whether ASMCpuId_EAX(0x80000000) indicates a valid range. + * + * This only succeeds if there are at least two leaves in the range. + * + * @returns true/false. + * @param uEAX The EAX value of CPUID leaf 0x80000000. + * + * @note This only succeeds if there are at least two leaves in the range. + * @remarks The upper range limit is just some half reasonable value we've + * picked out of thin air. + */ +DECLINLINE(bool) RTX86IsValidExtRange(uint32_t uEAX) +{ + return uEAX >= UINT32_C(0x80000001) && uEAX <= UINT32_C(0x800fffff); +} + + +/** + * Checks whether ASMCpuId_EAX(0x40000000) indicates a valid range. + * + * This only succeeds if there are at least two leaves in the range. + * + * @returns true/false. + * @param uEAX The EAX value of CPUID leaf 0x40000000. + * + * @note Unlike RTX86IsValidStdRange() and RTX86IsValidExtRange(), a single + * leaf is okay here. So, you always need to check the range. + * @remarks The upper range limit is take from the intel docs. + */ +DECLINLINE(bool) RTX86IsValidHypervisorRange(uint32_t uEAX) +{ + return uEAX >= UINT32_C(0x40000000) && uEAX <= UINT32_C(0x4fffffff); +} + + +/** + * Extracts the CPU family from ASMCpuId(1) or ASMCpuId(0x80000001) + * + * @returns Family. + * @param uEAX EAX return from ASMCpuId(1) or ASMCpuId(0x80000001). + */ +DECLINLINE(uint32_t) RTX86GetCpuFamily(uint32_t uEAX) +{ + return ((uEAX >> 8) & 0xf) == 0xf + ? ((uEAX >> 20) & 0x7f) + 0xf + : ((uEAX >> 8) & 0xf); +} + + +/** + * Extracts the CPU model from ASMCpuId(1) or ASMCpuId(0x80000001), Intel variant. + * + * @returns Model. + * @param uEAX EAX from ASMCpuId(1) or ASMCpuId(0x80000001). + */ +DECLINLINE(uint32_t) RTX86GetCpuModelIntel(uint32_t uEAX) +{ + return ((uEAX >> 8) & 0xf) == 0xf || (((uEAX >> 8) & 0xf) == 0x6) /* family! */ + ? ((uEAX >> 4) & 0xf) | ((uEAX >> 12) & 0xf0) + : ((uEAX >> 4) & 0xf); +} + + +/** + * Extracts the CPU model from ASMCpuId(1) or ASMCpuId(0x80000001), AMD variant. + * + * @returns Model. + * @param uEAX EAX from ASMCpuId(1) or ASMCpuId(0x80000001). + */ +DECLINLINE(uint32_t) RTX86GetCpuModelAMD(uint32_t uEAX) +{ + return ((uEAX >> 8) & 0xf) == 0xf + ? ((uEAX >> 4) & 0xf) | ((uEAX >> 12) & 0xf0) + : ((uEAX >> 4) & 0xf); +} + + +/** + * Extracts the CPU model from ASMCpuId(1) or ASMCpuId(0x80000001) + * + * @returns Model. + * @param uEAX EAX from ASMCpuId(1) or ASMCpuId(0x80000001). + * @param fIntel Whether it's an intel CPU. Use RTX86IsIntelCpu() or + * RTX86IsIntelCpu(). + */ +DECLINLINE(uint32_t) RTX86GetCpuModel(uint32_t uEAX, bool fIntel) +{ + return ((uEAX >> 8) & 0xf) == 0xf || (((uEAX >> 8) & 0xf) == 0x6 && fIntel) /* family! */ + ? ((uEAX >> 4) & 0xf) | ((uEAX >> 12) & 0xf0) + : ((uEAX >> 4) & 0xf); +} + + +/** + * Extracts the CPU stepping from ASMCpuId(1) or ASMCpuId(0x80000001) + * + * @returns Model. + * @param uEAX EAX from ASMCpuId(1) or ASMCpuId(0x80000001). + */ +DECLINLINE(uint32_t) RTX86GetCpuStepping(uint32_t uEAX) +{ + return uEAX & 0xf; +} + + +/** @} */ +#endif /* !IPRT_INCLUDED_x86_helpers_h */ + diff --git a/include/iprt/x86.h b/include/iprt/x86.h new file mode 100644 index 00000000..fe4e8ddf --- /dev/null +++ b/include/iprt/x86.h @@ -0,0 +1,4860 @@ +/** @file + * IPRT - X86 and AMD64 Structures and Definitions. + * + * @note x86.mac is generated from this file by running 'kmk incs' in the root. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_x86_h +#define IPRT_INCLUDED_x86_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef VBOX_FOR_DTRACE_LIB +# include <iprt/types.h> +# include <iprt/assert.h> +#else +# pragma D depends_on library vbox-types.d +#endif + +/** Workaround for Solaris sys/regset.h defining CS, DS and sys/controlregs.h + * defining MSR_IA32_FLUSH_CMD */ +#ifdef RT_OS_SOLARIS +# undef CS +# undef DS +# undef MSR_IA32_FLUSH_CMD +#endif + +/** @defgroup grp_rt_x86 x86 Types and Definitions + * @ingroup grp_rt + * @{ + */ + +#ifndef VBOX_FOR_DTRACE_LIB +/** + * EFLAGS Bits. + */ +typedef struct X86EFLAGSBITS +{ + /** Bit 0 - CF - Carry flag - Status flag. */ + unsigned u1CF : 1; + /** Bit 1 - 1 - Reserved flag. */ + unsigned u1Reserved0 : 1; + /** Bit 2 - PF - Parity flag - Status flag. */ + unsigned u1PF : 1; + /** Bit 3 - 0 - Reserved flag. */ + unsigned u1Reserved1 : 1; + /** Bit 4 - AF - Auxiliary carry flag - Status flag. */ + unsigned u1AF : 1; + /** Bit 5 - 0 - Reserved flag. */ + unsigned u1Reserved2 : 1; + /** Bit 6 - ZF - Zero flag - Status flag. */ + unsigned u1ZF : 1; + /** Bit 7 - SF - Signed flag - Status flag. */ + unsigned u1SF : 1; + /** Bit 8 - TF - Trap flag - System flag. */ + unsigned u1TF : 1; + /** Bit 9 - IF - Interrupt flag - System flag. */ + unsigned u1IF : 1; + /** Bit 10 - DF - Direction flag - Control flag. */ + unsigned u1DF : 1; + /** Bit 11 - OF - Overflow flag - Status flag. */ + unsigned u1OF : 1; + /** Bit 12-13 - IOPL - I/O privilege level flag - System flag. */ + unsigned u2IOPL : 2; + /** Bit 14 - NT - Nested task flag - System flag. */ + unsigned u1NT : 1; + /** Bit 15 - 0 - Reserved flag. */ + unsigned u1Reserved3 : 1; + /** Bit 16 - RF - Resume flag - System flag. */ + unsigned u1RF : 1; + /** Bit 17 - VM - Virtual 8086 mode - System flag. */ + unsigned u1VM : 1; + /** Bit 18 - AC - Alignment check flag - System flag. Works with CR0.AM. */ + unsigned u1AC : 1; + /** Bit 19 - VIF - Virtual interrupt flag - System flag. */ + unsigned u1VIF : 1; + /** Bit 20 - VIP - Virtual interrupt pending flag - System flag. */ + unsigned u1VIP : 1; + /** Bit 21 - ID - CPUID flag - System flag. If this responds to flipping CPUID is supported. */ + unsigned u1ID : 1; + /** Bit 22-31 - 0 - Reserved flag. */ + unsigned u10Reserved4 : 10; +} X86EFLAGSBITS; +/** Pointer to EFLAGS bits. */ +typedef X86EFLAGSBITS *PX86EFLAGSBITS; +/** Pointer to const EFLAGS bits. */ +typedef const X86EFLAGSBITS *PCX86EFLAGSBITS; +#endif /* !VBOX_FOR_DTRACE_LIB */ + +/** + * EFLAGS. + */ +typedef union X86EFLAGS +{ + /** The plain unsigned view. */ + uint32_t u; +#ifndef VBOX_FOR_DTRACE_LIB + /** The bitfield view. */ + X86EFLAGSBITS Bits; +#endif + /** The 8-bit view. */ + uint8_t au8[4]; + /** The 16-bit view. */ + uint16_t au16[2]; + /** The 32-bit view. */ + uint32_t au32[1]; + /** The 32-bit view. */ + uint32_t u32; +} X86EFLAGS; +/** Pointer to EFLAGS. */ +typedef X86EFLAGS *PX86EFLAGS; +/** Pointer to const EFLAGS. */ +typedef const X86EFLAGS *PCX86EFLAGS; + +/** + * RFLAGS (32 upper bits are reserved). + */ +typedef union X86RFLAGS +{ + /** The plain unsigned view. */ + uint64_t u; +#ifndef VBOX_FOR_DTRACE_LIB + /** The bitfield view. */ + X86EFLAGSBITS Bits; +#endif + /** The 8-bit view. */ + uint8_t au8[8]; + /** The 16-bit view. */ + uint16_t au16[4]; + /** The 32-bit view. */ + uint32_t au32[2]; + /** The 64-bit view. */ + uint64_t au64[1]; + /** The 64-bit view. */ + uint64_t u64; +} X86RFLAGS; +/** Pointer to RFLAGS. */ +typedef X86RFLAGS *PX86RFLAGS; +/** Pointer to const RFLAGS. */ +typedef const X86RFLAGS *PCX86RFLAGS; + + +/** @name EFLAGS + * @{ + */ +/** Bit 0 - CF - Carry flag - Status flag. */ +#define X86_EFL_CF RT_BIT_32(0) +#define X86_EFL_CF_BIT 0 +/** Bit 1 - Reserved, reads as 1. */ +#define X86_EFL_1 RT_BIT_32(1) +/** Bit 2 - PF - Parity flag - Status flag. */ +#define X86_EFL_PF RT_BIT_32(2) +#define X86_EFL_PF_BIT 2 +/** Bit 4 - AF - Auxiliary carry flag - Status flag. */ +#define X86_EFL_AF RT_BIT_32(4) +#define X86_EFL_AF_BIT 4 +/** Bit 6 - ZF - Zero flag - Status flag. */ +#define X86_EFL_ZF RT_BIT_32(6) +#define X86_EFL_ZF_BIT 6 +/** Bit 7 - SF - Signed flag - Status flag. */ +#define X86_EFL_SF RT_BIT_32(7) +#define X86_EFL_SF_BIT 7 +/** Bit 8 - TF - Trap flag - System flag. */ +#define X86_EFL_TF RT_BIT_32(8) +#define X86_EFL_TF_BIT 8 +/** Bit 9 - IF - Interrupt flag - System flag. */ +#define X86_EFL_IF RT_BIT_32(9) +#define X86_EFL_IF_BIT 9 +/** Bit 10 - DF - Direction flag - Control flag. */ +#define X86_EFL_DF RT_BIT_32(10) +#define X86_EFL_DF_BIT 10 +/** Bit 11 - OF - Overflow flag - Status flag. */ +#define X86_EFL_OF RT_BIT_32(11) +#define X86_EFL_OF_BIT 11 +/** Bit 12-13 - IOPL - I/O privilege level flag - System flag. */ +#define X86_EFL_IOPL (RT_BIT_32(12) | RT_BIT_32(13)) +/** Bit 14 - NT - Nested task flag - System flag. */ +#define X86_EFL_NT RT_BIT_32(14) +#define X86_EFL_NT_BIT 14 +/** Bit 16 - RF - Resume flag - System flag. */ +#define X86_EFL_RF RT_BIT_32(16) +#define X86_EFL_RF_BIT 16 +/** Bit 17 - VM - Virtual 8086 mode - System flag. */ +#define X86_EFL_VM RT_BIT_32(17) +#define X86_EFL_VM_BIT 17 +/** Bit 18 - AC - Alignment check flag - System flag. Works with CR0.AM. */ +#define X86_EFL_AC RT_BIT_32(18) +#define X86_EFL_AC_BIT 18 +/** Bit 19 - VIF - Virtual interrupt flag - System flag. */ +#define X86_EFL_VIF RT_BIT_32(19) +#define X86_EFL_VIF_BIT 19 +/** Bit 20 - VIP - Virtual interrupt pending flag - System flag. */ +#define X86_EFL_VIP RT_BIT_32(20) +#define X86_EFL_VIP_BIT 20 +/** Bit 21 - ID - CPUID flag - System flag. If this responds to flipping CPUID is supported. */ +#define X86_EFL_ID RT_BIT_32(21) +#define X86_EFL_ID_BIT 21 +/** All live bits. */ +#define X86_EFL_LIVE_MASK UINT32_C(0x003f7fd5) +/** Read as 1 bits. */ +#define X86_EFL_RA1_MASK RT_BIT_32(1) +/** Read as 0 bits, excluding bits 31:22. + * Bits 3, 5, 15, and 22 thru 31. */ +#define X86_EFL_RAZ_MASK UINT32_C(0xffc08028) +/** Read as 0 bits, excluding bits 31:22. + * Bits 3, 5 and 15. */ +#define X86_EFL_RAZ_LO_MASK UINT32_C(0x00008028) +/** IOPL shift. */ +#define X86_EFL_IOPL_SHIFT 12 +/** The IOPL level from the flags. */ +#define X86_EFL_GET_IOPL(efl) (((efl) >> X86_EFL_IOPL_SHIFT) & 3) +/** Bits restored by popf */ +#define X86_EFL_POPF_BITS ( X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_TF | X86_EFL_IF \ + | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT | X86_EFL_AC | X86_EFL_ID ) +/** Bits restored by popf */ +#define X86_EFL_POPF_BITS_386 ( X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_TF | X86_EFL_IF \ + | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT ) +/** The status bits commonly updated by arithmetic instructions. */ +#define X86_EFL_STATUS_BITS ( X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF ) +/** @} */ + + +/** CPUID Feature information - ECX. + * CPUID query with EAX=1. + */ +#ifndef VBOX_FOR_DTRACE_LIB +typedef struct X86CPUIDFEATECX +{ + /** Bit 0 - SSE3 - Supports SSE3 or not. */ + unsigned u1SSE3 : 1; + /** Bit 1 - PCLMULQDQ. */ + unsigned u1PCLMULQDQ : 1; + /** Bit 2 - DS Area 64-bit layout. */ + unsigned u1DTE64 : 1; + /** Bit 3 - MONITOR - Supports MONITOR/MWAIT. */ + unsigned u1Monitor : 1; + /** Bit 4 - CPL-DS - CPL Qualified Debug Store. */ + unsigned u1CPLDS : 1; + /** Bit 5 - VMX - Virtual Machine Technology. */ + unsigned u1VMX : 1; + /** Bit 6 - SMX: Safer Mode Extensions. */ + unsigned u1SMX : 1; + /** Bit 7 - EST - Enh. SpeedStep Tech. */ + unsigned u1EST : 1; + /** Bit 8 - TM2 - Terminal Monitor 2. */ + unsigned u1TM2 : 1; + /** Bit 9 - SSSE3 - Supplemental Streaming SIMD Extensions 3. */ + unsigned u1SSSE3 : 1; + /** Bit 10 - CNTX-ID - L1 Context ID. */ + unsigned u1CNTXID : 1; + /** Bit 11 - Reserved. */ + unsigned u1Reserved1 : 1; + /** Bit 12 - FMA. */ + unsigned u1FMA : 1; + /** Bit 13 - CX16 - CMPXCHG16B. */ + unsigned u1CX16 : 1; + /** Bit 14 - xTPR Update Control. Processor supports changing IA32_MISC_ENABLES[bit 23]. */ + unsigned u1TPRUpdate : 1; + /** Bit 15 - PDCM - Perf/Debug Capability MSR. */ + unsigned u1PDCM : 1; + /** Bit 16 - Reserved. */ + unsigned u1Reserved2 : 1; + /** Bit 17 - PCID - Process-context identifiers. */ + unsigned u1PCID : 1; + /** Bit 18 - Direct Cache Access. */ + unsigned u1DCA : 1; + /** Bit 19 - SSE4_1 - Supports SSE4_1 or not. */ + unsigned u1SSE4_1 : 1; + /** Bit 20 - SSE4_2 - Supports SSE4_2 or not. */ + unsigned u1SSE4_2 : 1; + /** Bit 21 - x2APIC. */ + unsigned u1x2APIC : 1; + /** Bit 22 - MOVBE - Supports MOVBE. */ + unsigned u1MOVBE : 1; + /** Bit 23 - POPCNT - Supports POPCNT. */ + unsigned u1POPCNT : 1; + /** Bit 24 - TSC-Deadline. */ + unsigned u1TSCDEADLINE : 1; + /** Bit 25 - AES. */ + unsigned u1AES : 1; + /** Bit 26 - XSAVE - Supports XSAVE. */ + unsigned u1XSAVE : 1; + /** Bit 27 - OSXSAVE - Supports OSXSAVE. */ + unsigned u1OSXSAVE : 1; + /** Bit 28 - AVX - Supports AVX instruction extensions. */ + unsigned u1AVX : 1; + /** Bit 29 - F16C - Supports 16-bit floating point conversion instructions. */ + unsigned u1F16C : 1; + /** Bit 30 - RDRAND - Supports RDRAND. */ + unsigned u1RDRAND : 1; + /** Bit 31 - Hypervisor present (we're a guest). */ + unsigned u1HVP : 1; +} X86CPUIDFEATECX; +#else /* VBOX_FOR_DTRACE_LIB */ +typedef uint32_t X86CPUIDFEATECX; +#endif /* VBOX_FOR_DTRACE_LIB */ +/** Pointer to CPUID Feature Information - ECX. */ +typedef X86CPUIDFEATECX *PX86CPUIDFEATECX; +/** Pointer to const CPUID Feature Information - ECX. */ +typedef const X86CPUIDFEATECX *PCX86CPUIDFEATECX; + + +/** CPUID Feature Information - EDX. + * CPUID query with EAX=1. + */ +#ifndef VBOX_FOR_DTRACE_LIB /* DTrace different (brain-dead from a C pov) bitfield implementation */ +typedef struct X86CPUIDFEATEDX +{ + /** Bit 0 - FPU - x87 FPU on Chip. */ + unsigned u1FPU : 1; + /** Bit 1 - VME - Virtual 8086 Mode Enhancements. */ + unsigned u1VME : 1; + /** Bit 2 - DE - Debugging extensions. */ + unsigned u1DE : 1; + /** Bit 3 - PSE - Page Size Extension. */ + unsigned u1PSE : 1; + /** Bit 4 - TSC - Time Stamp Counter. */ + unsigned u1TSC : 1; + /** Bit 5 - MSR - Model Specific Registers RDMSR and WRMSR Instructions. */ + unsigned u1MSR : 1; + /** Bit 6 - PAE - Physical Address Extension. */ + unsigned u1PAE : 1; + /** Bit 7 - MCE - Machine Check Exception. */ + unsigned u1MCE : 1; + /** Bit 8 - CX8 - CMPXCHG8B instruction. */ + unsigned u1CX8 : 1; + /** Bit 9 - APIC - APIC On-Chip. */ + unsigned u1APIC : 1; + /** Bit 10 - Reserved. */ + unsigned u1Reserved1 : 1; + /** Bit 11 - SEP - SYSENTER and SYSEXIT. */ + unsigned u1SEP : 1; + /** Bit 12 - MTRR - Memory Type Range Registers. */ + unsigned u1MTRR : 1; + /** Bit 13 - PGE - PTE Global Bit. */ + unsigned u1PGE : 1; + /** Bit 14 - MCA - Machine Check Architecture. */ + unsigned u1MCA : 1; + /** Bit 15 - CMOV - Conditional Move Instructions. */ + unsigned u1CMOV : 1; + /** Bit 16 - PAT - Page Attribute Table. */ + unsigned u1PAT : 1; + /** Bit 17 - PSE-36 - 36-bit Page Size Extension. */ + unsigned u1PSE36 : 1; + /** Bit 18 - PSN - Processor Serial Number. */ + unsigned u1PSN : 1; + /** Bit 19 - CLFSH - CLFLUSH Instruction. */ + unsigned u1CLFSH : 1; + /** Bit 20 - Reserved. */ + unsigned u1Reserved2 : 1; + /** Bit 21 - DS - Debug Store. */ + unsigned u1DS : 1; + /** Bit 22 - ACPI - Thermal Monitor and Software Controlled Clock Facilities. */ + unsigned u1ACPI : 1; + /** Bit 23 - MMX - Intel MMX 'Technology'. */ + unsigned u1MMX : 1; + /** Bit 24 - FXSR - FXSAVE and FXRSTOR Instructions. */ + unsigned u1FXSR : 1; + /** Bit 25 - SSE - SSE Support. */ + unsigned u1SSE : 1; + /** Bit 26 - SSE2 - SSE2 Support. */ + unsigned u1SSE2 : 1; + /** Bit 27 - SS - Self Snoop. */ + unsigned u1SS : 1; + /** Bit 28 - HTT - Hyper-Threading Technology. */ + unsigned u1HTT : 1; + /** Bit 29 - TM - Thermal Monitor. */ + unsigned u1TM : 1; + /** Bit 30 - Reserved - . */ + unsigned u1Reserved3 : 1; + /** Bit 31 - PBE - Pending Break Enabled. */ + unsigned u1PBE : 1; +} X86CPUIDFEATEDX; +#else /* VBOX_FOR_DTRACE_LIB */ +typedef uint32_t X86CPUIDFEATEDX; +#endif /* VBOX_FOR_DTRACE_LIB */ +/** Pointer to CPUID Feature Information - EDX. */ +typedef X86CPUIDFEATEDX *PX86CPUIDFEATEDX; +/** Pointer to const CPUID Feature Information - EDX. */ +typedef const X86CPUIDFEATEDX *PCX86CPUIDFEATEDX; + +/** @name CPUID Vendor information. + * CPUID query with EAX=0. + * @{ + */ +#define X86_CPUID_VENDOR_INTEL_EBX 0x756e6547 /* Genu */ +#define X86_CPUID_VENDOR_INTEL_ECX 0x6c65746e /* ntel */ +#define X86_CPUID_VENDOR_INTEL_EDX 0x49656e69 /* ineI */ + +#define X86_CPUID_VENDOR_AMD_EBX 0x68747541 /* Auth */ +#define X86_CPUID_VENDOR_AMD_ECX 0x444d4163 /* cAMD */ +#define X86_CPUID_VENDOR_AMD_EDX 0x69746e65 /* enti */ + +#define X86_CPUID_VENDOR_VIA_EBX 0x746e6543 /* Cent */ +#define X86_CPUID_VENDOR_VIA_ECX 0x736c7561 /* auls */ +#define X86_CPUID_VENDOR_VIA_EDX 0x48727561 /* aurH */ + +#define X86_CPUID_VENDOR_SHANGHAI_EBX 0x68532020 /* Sh */ +#define X86_CPUID_VENDOR_SHANGHAI_ECX 0x20206961 /* ai */ +#define X86_CPUID_VENDOR_SHANGHAI_EDX 0x68676e61 /* angh */ + +#define X86_CPUID_VENDOR_HYGON_EBX 0x6f677948 /* Hygo */ +#define X86_CPUID_VENDOR_HYGON_ECX 0x656e6975 /* uine */ +#define X86_CPUID_VENDOR_HYGON_EDX 0x6e65476e /* nGen */ +/** @} */ + + +/** @name CPUID Feature information. + * CPUID query with EAX=1. + * @{ + */ +/** ECX Bit 0 - SSE3 - Supports SSE3 or not. */ +#define X86_CPUID_FEATURE_ECX_SSE3 RT_BIT_32(0) +/** ECX Bit 1 - PCLMUL - PCLMULQDQ support (for AES-GCM). */ +#define X86_CPUID_FEATURE_ECX_PCLMUL RT_BIT_32(1) +/** ECX Bit 2 - DTES64 - DS Area 64-bit Layout. */ +#define X86_CPUID_FEATURE_ECX_DTES64 RT_BIT_32(2) +/** ECX Bit 3 - MONITOR - Supports MONITOR/MWAIT. */ +#define X86_CPUID_FEATURE_ECX_MONITOR RT_BIT_32(3) +/** ECX Bit 4 - CPL-DS - CPL Qualified Debug Store. */ +#define X86_CPUID_FEATURE_ECX_CPLDS RT_BIT_32(4) +/** ECX Bit 5 - VMX - Virtual Machine Technology. */ +#define X86_CPUID_FEATURE_ECX_VMX RT_BIT_32(5) +/** ECX Bit 6 - SMX - Safer Mode Extensions. */ +#define X86_CPUID_FEATURE_ECX_SMX RT_BIT_32(6) +/** ECX Bit 7 - EST - Enh. SpeedStep Tech. */ +#define X86_CPUID_FEATURE_ECX_EST RT_BIT_32(7) +/** ECX Bit 8 - TM2 - Terminal Monitor 2. */ +#define X86_CPUID_FEATURE_ECX_TM2 RT_BIT_32(8) +/** ECX Bit 9 - SSSE3 - Supplemental Streaming SIMD Extensions 3. */ +#define X86_CPUID_FEATURE_ECX_SSSE3 RT_BIT_32(9) +/** ECX Bit 10 - CNTX-ID - L1 Context ID. */ +#define X86_CPUID_FEATURE_ECX_CNTXID RT_BIT_32(10) +/** ECX Bit 11 - SDBG - Sillicon debug interface (IA32_DEBUG_INTERFACE MSR). + * See figure 3-6 and table 3-10, in intel Vol. 2A. from 2015-01-01. */ +#define X86_CPUID_FEATURE_ECX_SDBG RT_BIT_32(11) +/** ECX Bit 12 - FMA. */ +#define X86_CPUID_FEATURE_ECX_FMA RT_BIT_32(12) +/** ECX Bit 13 - CX16 - CMPXCHG16B. */ +#define X86_CPUID_FEATURE_ECX_CX16 RT_BIT_32(13) +/** ECX Bit 14 - xTPR Update Control. Processor supports changing IA32_MISC_ENABLES[bit 23]. */ +#define X86_CPUID_FEATURE_ECX_TPRUPDATE RT_BIT_32(14) +/** ECX Bit 15 - PDCM - Perf/Debug Capability MSR. */ +#define X86_CPUID_FEATURE_ECX_PDCM RT_BIT_32(15) +/** ECX Bit 17 - PCID - Process-context identifiers. */ +#define X86_CPUID_FEATURE_ECX_PCID RT_BIT_32(17) +/** ECX Bit 18 - DCA - Direct Cache Access. */ +#define X86_CPUID_FEATURE_ECX_DCA RT_BIT_32(18) +/** ECX Bit 19 - SSE4_1 - Supports SSE4_1 or not. */ +#define X86_CPUID_FEATURE_ECX_SSE4_1 RT_BIT_32(19) +/** ECX Bit 20 - SSE4_2 - Supports SSE4_2 or not. */ +#define X86_CPUID_FEATURE_ECX_SSE4_2 RT_BIT_32(20) +/** ECX Bit 21 - x2APIC support. */ +#define X86_CPUID_FEATURE_ECX_X2APIC RT_BIT_32(21) +/** ECX Bit 22 - MOVBE instruction. */ +#define X86_CPUID_FEATURE_ECX_MOVBE RT_BIT_32(22) +/** ECX Bit 23 - POPCNT instruction. */ +#define X86_CPUID_FEATURE_ECX_POPCNT RT_BIT_32(23) +/** ECX Bir 24 - TSC-Deadline. */ +#define X86_CPUID_FEATURE_ECX_TSCDEADL RT_BIT_32(24) +/** ECX Bit 25 - AES instructions. */ +#define X86_CPUID_FEATURE_ECX_AES RT_BIT_32(25) +/** ECX Bit 26 - XSAVE instruction. */ +#define X86_CPUID_FEATURE_ECX_XSAVE RT_BIT_32(26) +/** ECX Bit 27 - Copy of CR4.OSXSAVE. */ +#define X86_CPUID_FEATURE_ECX_OSXSAVE RT_BIT_32(27) +/** ECX Bit 28 - AVX. */ +#define X86_CPUID_FEATURE_ECX_AVX RT_BIT_32(28) +/** ECX Bit 29 - F16C - Half-precision convert instruction support. */ +#define X86_CPUID_FEATURE_ECX_F16C RT_BIT_32(29) +/** ECX Bit 30 - RDRAND instruction. */ +#define X86_CPUID_FEATURE_ECX_RDRAND RT_BIT_32(30) +/** ECX Bit 31 - Hypervisor Present (software only). */ +#define X86_CPUID_FEATURE_ECX_HVP RT_BIT_32(31) + + +/** Bit 0 - FPU - x87 FPU on Chip. */ +#define X86_CPUID_FEATURE_EDX_FPU RT_BIT_32(0) +/** Bit 1 - VME - Virtual 8086 Mode Enhancements. */ +#define X86_CPUID_FEATURE_EDX_VME RT_BIT_32(1) +/** Bit 2 - DE - Debugging extensions. */ +#define X86_CPUID_FEATURE_EDX_DE RT_BIT_32(2) +/** Bit 3 - PSE - Page Size Extension. */ +#define X86_CPUID_FEATURE_EDX_PSE RT_BIT_32(3) +#define X86_CPUID_FEATURE_EDX_PSE_BIT 3 /**< Bit number for X86_CPUID_FEATURE_EDX_PSE. */ +/** Bit 4 - TSC - Time Stamp Counter. */ +#define X86_CPUID_FEATURE_EDX_TSC RT_BIT_32(4) +/** Bit 5 - MSR - Model Specific Registers RDMSR and WRMSR Instructions. */ +#define X86_CPUID_FEATURE_EDX_MSR RT_BIT_32(5) +/** Bit 6 - PAE - Physical Address Extension. */ +#define X86_CPUID_FEATURE_EDX_PAE RT_BIT_32(6) +#define X86_CPUID_FEATURE_EDX_PAE_BIT 6 /**< Bit number for X86_CPUID_FEATURE_EDX_PAE. */ +/** Bit 7 - MCE - Machine Check Exception. */ +#define X86_CPUID_FEATURE_EDX_MCE RT_BIT_32(7) +/** Bit 8 - CX8 - CMPXCHG8B instruction. */ +#define X86_CPUID_FEATURE_EDX_CX8 RT_BIT_32(8) +/** Bit 9 - APIC - APIC On-Chip. */ +#define X86_CPUID_FEATURE_EDX_APIC RT_BIT_32(9) +/** Bit 11 - SEP - SYSENTER and SYSEXIT Present. */ +#define X86_CPUID_FEATURE_EDX_SEP RT_BIT_32(11) +/** Bit 12 - MTRR - Memory Type Range Registers. */ +#define X86_CPUID_FEATURE_EDX_MTRR RT_BIT_32(12) +/** Bit 13 - PGE - PTE Global Bit. */ +#define X86_CPUID_FEATURE_EDX_PGE RT_BIT_32(13) +/** Bit 14 - MCA - Machine Check Architecture. */ +#define X86_CPUID_FEATURE_EDX_MCA RT_BIT_32(14) +/** Bit 15 - CMOV - Conditional Move Instructions. */ +#define X86_CPUID_FEATURE_EDX_CMOV RT_BIT_32(15) +/** Bit 16 - PAT - Page Attribute Table. */ +#define X86_CPUID_FEATURE_EDX_PAT RT_BIT_32(16) +/** Bit 17 - PSE-36 - 36-bit Page Size Extension. */ +#define X86_CPUID_FEATURE_EDX_PSE36 RT_BIT_32(17) +/** Bit 18 - PSN - Processor Serial Number. */ +#define X86_CPUID_FEATURE_EDX_PSN RT_BIT_32(18) +/** Bit 19 - CLFSH - CLFLUSH Instruction. */ +#define X86_CPUID_FEATURE_EDX_CLFSH RT_BIT_32(19) +/** Bit 21 - DS - Debug Store. */ +#define X86_CPUID_FEATURE_EDX_DS RT_BIT_32(21) +/** Bit 22 - ACPI - Thermal Monitor and Software Controlled Clock Facilities. */ +#define X86_CPUID_FEATURE_EDX_ACPI RT_BIT_32(22) +/** Bit 23 - MMX - Intel MMX Technology. */ +#define X86_CPUID_FEATURE_EDX_MMX RT_BIT_32(23) +/** Bit 24 - FXSR - FXSAVE and FXRSTOR Instructions. */ +#define X86_CPUID_FEATURE_EDX_FXSR RT_BIT_32(24) +/** Bit 25 - SSE - SSE Support. */ +#define X86_CPUID_FEATURE_EDX_SSE RT_BIT_32(25) +/** Bit 26 - SSE2 - SSE2 Support. */ +#define X86_CPUID_FEATURE_EDX_SSE2 RT_BIT_32(26) +/** Bit 27 - SS - Self Snoop. */ +#define X86_CPUID_FEATURE_EDX_SS RT_BIT_32(27) +/** Bit 28 - HTT - Hyper-Threading Technology. */ +#define X86_CPUID_FEATURE_EDX_HTT RT_BIT_32(28) +/** Bit 29 - TM - Therm. Monitor. */ +#define X86_CPUID_FEATURE_EDX_TM RT_BIT_32(29) +/** Bit 31 - PBE - Pending Break Enabled. */ +#define X86_CPUID_FEATURE_EDX_PBE RT_BIT_32(31) +/** @} */ + +/** @name CPUID mwait/monitor information. + * CPUID query with EAX=5. + * @{ + */ +/** ECX Bit 0 - MWAITEXT - Supports mwait/monitor extensions or not. */ +#define X86_CPUID_MWAIT_ECX_EXT RT_BIT_32(0) +/** ECX Bit 1 - MWAITBREAK - Break mwait for external interrupt even if EFLAGS.IF=0. */ +#define X86_CPUID_MWAIT_ECX_BREAKIRQIF0 RT_BIT_32(1) +/** @} */ + + +/** @name CPUID Structured Extended Feature information. + * CPUID query with EAX=7. + * @{ + */ +/** EBX Bit 0 - FSGSBASE - Supports RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE. */ +#define X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE RT_BIT_32(0) +/** EBX Bit 1 - TSCADJUST - Supports MSR_IA32_TSC_ADJUST. */ +#define X86_CPUID_STEXT_FEATURE_EBX_TSC_ADJUST RT_BIT_32(1) +/** EBX Bit 2 - SGX - Supports Software Guard Extensions . */ +#define X86_CPUID_STEXT_FEATURE_EBX_SGX RT_BIT_32(2) +/** EBX Bit 3 - BMI1 - Advanced Bit Manipulation extension 1. */ +#define X86_CPUID_STEXT_FEATURE_EBX_BMI1 RT_BIT_32(3) +/** EBX Bit 4 - HLE - Hardware Lock Elision. */ +#define X86_CPUID_STEXT_FEATURE_EBX_HLE RT_BIT_32(4) +/** EBX Bit 5 - AVX2 - Advanced Vector Extensions 2. */ +#define X86_CPUID_STEXT_FEATURE_EBX_AVX2 RT_BIT_32(5) +/** EBX Bit 6 - FDP_EXCPTN_ONLY - FPU data pointer only updated on exceptions if set. */ +#define X86_CPUID_STEXT_FEATURE_EBX_FDP_EXCPTN_ONLY RT_BIT_32(6) +/** EBX Bit 7 - SMEP - Supervisor Mode Execution Prevention. */ +#define X86_CPUID_STEXT_FEATURE_EBX_SMEP RT_BIT_32(7) +/** EBX Bit 8 - BMI2 - Advanced Bit Manipulation extension 2. */ +#define X86_CPUID_STEXT_FEATURE_EBX_BMI2 RT_BIT_32(8) +/** EBX Bit 9 - ERMS - Supports Enhanced REP MOVSB/STOSB. */ +#define X86_CPUID_STEXT_FEATURE_EBX_ERMS RT_BIT_32(9) +/** EBX Bit 10 - INVPCID - Supports INVPCID. */ +#define X86_CPUID_STEXT_FEATURE_EBX_INVPCID RT_BIT_32(10) +/** EBX Bit 11 - RTM - Supports Restricted Transactional Memory. */ +#define X86_CPUID_STEXT_FEATURE_EBX_RTM RT_BIT_32(11) +/** EBX Bit 12 - PQM - Supports Platform Quality of Service Monitoring. */ +#define X86_CPUID_STEXT_FEATURE_EBX_PQM RT_BIT_32(12) +/** EBX Bit 13 - DEPFPU_CS_DS - Deprecates FPU CS, FPU DS values if set. */ +#define X86_CPUID_STEXT_FEATURE_EBX_DEPR_FPU_CS_DS RT_BIT_32(13) +/** EBX Bit 14 - MPE - Supports Intel Memory Protection Extensions. */ +#define X86_CPUID_STEXT_FEATURE_EBX_MPE RT_BIT_32(14) +/** EBX Bit 15 - PQE - Supports Platform Quality of Service Enforcement. */ +#define X86_CPUID_STEXT_FEATURE_EBX_PQE RT_BIT_32(15) +/** EBX Bit 16 - AVX512F - Supports AVX512F. */ +#define X86_CPUID_STEXT_FEATURE_EBX_AVX512F RT_BIT_32(16) +/** EBX Bit 18 - RDSEED - Supports RDSEED. */ +#define X86_CPUID_STEXT_FEATURE_EBX_RDSEED RT_BIT_32(18) +/** EBX Bit 19 - ADX - Supports ADCX/ADOX. */ +#define X86_CPUID_STEXT_FEATURE_EBX_ADX RT_BIT_32(19) +/** EBX Bit 20 - SMAP - Supports Supervisor Mode Access Prevention. */ +#define X86_CPUID_STEXT_FEATURE_EBX_SMAP RT_BIT_32(20) +/** EBX Bit 23 - CLFLUSHOPT - Supports CLFLUSHOPT (Cache Line Flush). */ +#define X86_CPUID_STEXT_FEATURE_EBX_CLFLUSHOPT RT_BIT_32(23) +/** EBX Bit 25 - INTEL_PT - Supports Intel Processor Trace. */ +#define X86_CPUID_STEXT_FEATURE_EBX_INTEL_PT RT_BIT_32(25) +/** EBX Bit 26 - AVX512PF - Supports AVX512PF. */ +#define X86_CPUID_STEXT_FEATURE_EBX_AVX512PF RT_BIT_32(26) +/** EBX Bit 27 - AVX512ER - Supports AVX512ER. */ +#define X86_CPUID_STEXT_FEATURE_EBX_AVX512ER RT_BIT_32(27) +/** EBX Bit 28 - AVX512CD - Supports AVX512CD. */ +#define X86_CPUID_STEXT_FEATURE_EBX_AVX512CD RT_BIT_32(28) +/** EBX Bit 29 - SHA - Supports Secure Hash Algorithm extensions. */ +#define X86_CPUID_STEXT_FEATURE_EBX_SHA RT_BIT_32(29) + +/** ECX Bit 0 - PREFETCHWT1 - Supports the PREFETCHWT1 instruction. */ +#define X86_CPUID_STEXT_FEATURE_ECX_PREFETCHWT1 RT_BIT_32(0) +/** ECX Bit 2 - UIMP - Supports user mode instruction prevention. */ +#define X86_CPUID_STEXT_FEATURE_ECX_UMIP RT_BIT_32(2) +/** ECX Bit 3 - PKU - Supports protection keys for user-mode pages. */ +#define X86_CPUID_STEXT_FEATURE_ECX_PKU RT_BIT_32(3) +/** ECX Bit 4 - OSPKE - Protection keys for user mode pages enabled. */ +#define X86_CPUID_STEXT_FEATURE_ECX_OSPKE RT_BIT_32(4) +/** ECX Bits 17-21 - MAWAU - Value used by BNDLDX and BNDSTX. */ +#define X86_CPUID_STEXT_FEATURE_ECX_MAWAU UINT32_C(0x003e0000) +/** ECX Bit 22 - RDPID - Support pread process ID. */ +#define X86_CPUID_STEXT_FEATURE_ECX_RDPID RT_BIT_32(2) +/** ECX Bit 30 - SGX_LC - Supports SGX launch configuration. */ +#define X86_CPUID_STEXT_FEATURE_ECX_SGX_LC RT_BIT_32(30) + +/** EDX Bit 10 - MD_CLEAR - Supports flushing MDS related buffers. */ +#define X86_CPUID_STEXT_FEATURE_EDX_MD_CLEAR RT_BIT_32(10) +/** EDX Bit 26 - IBRS & IBPB - Supports the IBRS flag in IA32_SPEC_CTRL and + * IBPB command in IA32_PRED_CMD. */ +#define X86_CPUID_STEXT_FEATURE_EDX_IBRS_IBPB RT_BIT_32(26) +/** 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 28 - FLUSH_CMD - Supports IA32_FLUSH_CMD MSR. */ +#define X86_CPUID_STEXT_FEATURE_EDX_FLUSH_CMD RT_BIT_32(28) +/** EDX Bit 29 - ARCHCAP - Supports the IA32_ARCH_CAPABILITIES MSR. */ +#define X86_CPUID_STEXT_FEATURE_EDX_ARCHCAP RT_BIT_32(29) +/** EDX Bit 31 - SSBD - Supports the SSBD flag in IA32_SPEC_CTRL. */ +#define X86_CPUID_STEXT_FEATURE_EDX_SSBD RT_BIT_32(31) + +/** @} */ + + +/** @name CPUID Extended Feature information. + * CPUID query with EAX=0x80000001. + * @{ + */ +/** ECX Bit 0 - LAHF/SAHF support in 64-bit mode. */ +#define X86_CPUID_EXT_FEATURE_ECX_LAHF_SAHF RT_BIT_32(0) + +/** EDX Bit 11 - SYSCALL/SYSRET. */ +#define X86_CPUID_EXT_FEATURE_EDX_SYSCALL RT_BIT_32(11) +/** EDX Bit 20 - No-Execute/Execute-Disable. */ +#define X86_CPUID_EXT_FEATURE_EDX_NX RT_BIT_32(20) +/** EDX Bit 26 - 1 GB large page. */ +#define X86_CPUID_EXT_FEATURE_EDX_PAGE1GB RT_BIT_32(26) +/** EDX Bit 27 - RDTSCP. */ +#define X86_CPUID_EXT_FEATURE_EDX_RDTSCP RT_BIT_32(27) +/** EDX Bit 29 - AMD Long Mode/Intel-64 Instructions. */ +#define X86_CPUID_EXT_FEATURE_EDX_LONG_MODE RT_BIT_32(29) +/** @}*/ + +/** @name CPUID AMD Feature information. + * CPUID query with EAX=0x80000001. + * @{ + */ +/** Bit 0 - FPU - x87 FPU on Chip. */ +#define X86_CPUID_AMD_FEATURE_EDX_FPU RT_BIT_32(0) +/** Bit 1 - VME - Virtual 8086 Mode Enhancements. */ +#define X86_CPUID_AMD_FEATURE_EDX_VME RT_BIT_32(1) +/** Bit 2 - DE - Debugging extensions. */ +#define X86_CPUID_AMD_FEATURE_EDX_DE RT_BIT_32(2) +/** Bit 3 - PSE - Page Size Extension. */ +#define X86_CPUID_AMD_FEATURE_EDX_PSE RT_BIT_32(3) +/** Bit 4 - TSC - Time Stamp Counter. */ +#define X86_CPUID_AMD_FEATURE_EDX_TSC RT_BIT_32(4) +/** Bit 5 - MSR - K86 Model Specific Registers RDMSR and WRMSR Instructions. */ +#define X86_CPUID_AMD_FEATURE_EDX_MSR RT_BIT_32(5) +/** Bit 6 - PAE - Physical Address Extension. */ +#define X86_CPUID_AMD_FEATURE_EDX_PAE RT_BIT_32(6) +/** Bit 7 - MCE - Machine Check Exception. */ +#define X86_CPUID_AMD_FEATURE_EDX_MCE RT_BIT_32(7) +/** Bit 8 - CX8 - CMPXCHG8B instruction. */ +#define X86_CPUID_AMD_FEATURE_EDX_CX8 RT_BIT_32(8) +/** Bit 9 - APIC - APIC On-Chip. */ +#define X86_CPUID_AMD_FEATURE_EDX_APIC RT_BIT_32(9) +/** Bit 12 - MTRR - Memory Type Range Registers. */ +#define X86_CPUID_AMD_FEATURE_EDX_MTRR RT_BIT_32(12) +/** Bit 13 - PGE - PTE Global Bit. */ +#define X86_CPUID_AMD_FEATURE_EDX_PGE RT_BIT_32(13) +/** Bit 14 - MCA - Machine Check Architecture. */ +#define X86_CPUID_AMD_FEATURE_EDX_MCA RT_BIT_32(14) +/** Bit 15 - CMOV - Conditional Move Instructions. */ +#define X86_CPUID_AMD_FEATURE_EDX_CMOV RT_BIT_32(15) +/** Bit 16 - PAT - Page Attribute Table. */ +#define X86_CPUID_AMD_FEATURE_EDX_PAT RT_BIT_32(16) +/** Bit 17 - PSE-36 - 36-bit Page Size Extension. */ +#define X86_CPUID_AMD_FEATURE_EDX_PSE36 RT_BIT_32(17) +/** Bit 22 - AXMMX - AMD Extensions to MMX Instructions. */ +#define X86_CPUID_AMD_FEATURE_EDX_AXMMX RT_BIT_32(22) +/** Bit 23 - MMX - Intel MMX Technology. */ +#define X86_CPUID_AMD_FEATURE_EDX_MMX RT_BIT_32(23) +/** Bit 24 - FXSR - FXSAVE and FXRSTOR Instructions. */ +#define X86_CPUID_AMD_FEATURE_EDX_FXSR RT_BIT_32(24) +/** Bit 25 - FFXSR - AMD fast FXSAVE and FXRSTOR Instructions. */ +#define X86_CPUID_AMD_FEATURE_EDX_FFXSR RT_BIT_32(25) +/** Bit 30 - 3DNOWEXT - AMD Extensions to 3DNow. */ +#define X86_CPUID_AMD_FEATURE_EDX_3DNOW_EX RT_BIT_32(30) +/** Bit 31 - 3DNOW - AMD 3DNow. */ +#define X86_CPUID_AMD_FEATURE_EDX_3DNOW RT_BIT_32(31) + +/** Bit 1 - CmpLegacy - Core multi-processing legacy mode. */ +#define X86_CPUID_AMD_FEATURE_ECX_CMPL RT_BIT_32(1) +/** Bit 2 - SVM - AMD VM extensions. */ +#define X86_CPUID_AMD_FEATURE_ECX_SVM RT_BIT_32(2) +/** Bit 3 - EXTAPIC - AMD extended APIC registers starting at 0x400. */ +#define X86_CPUID_AMD_FEATURE_ECX_EXT_APIC RT_BIT_32(3) +/** Bit 4 - CR8L - AMD LOCK MOV CR0 means MOV CR8. */ +#define X86_CPUID_AMD_FEATURE_ECX_CR8L RT_BIT_32(4) +/** Bit 5 - ABM - AMD Advanced bit manipulation. LZCNT instruction support. */ +#define X86_CPUID_AMD_FEATURE_ECX_ABM RT_BIT_32(5) +/** Bit 6 - SSE4A - AMD EXTRQ, INSERTQ, MOVNTSS, and MOVNTSD instruction support. */ +#define X86_CPUID_AMD_FEATURE_ECX_SSE4A RT_BIT_32(6) +/** Bit 7 - MISALIGNSSE - AMD Misaligned SSE mode. */ +#define X86_CPUID_AMD_FEATURE_ECX_MISALNSSE RT_BIT_32(7) +/** Bit 8 - 3DNOWPRF - AMD PREFETCH and PREFETCHW instruction support. */ +#define X86_CPUID_AMD_FEATURE_ECX_3DNOWPRF RT_BIT_32(8) +/** Bit 9 - OSVW - AMD OS visible workaround. */ +#define X86_CPUID_AMD_FEATURE_ECX_OSVW RT_BIT_32(9) +/** Bit 10 - IBS - Instruct based sampling. */ +#define X86_CPUID_AMD_FEATURE_ECX_IBS RT_BIT_32(10) +/** Bit 11 - XOP - Extended operation support (see APM6). */ +#define X86_CPUID_AMD_FEATURE_ECX_XOP RT_BIT_32(11) +/** Bit 12 - SKINIT - AMD SKINIT: SKINIT, STGI, and DEV support. */ +#define X86_CPUID_AMD_FEATURE_ECX_SKINIT RT_BIT_32(12) +/** Bit 13 - WDT - AMD Watchdog timer support. */ +#define X86_CPUID_AMD_FEATURE_ECX_WDT RT_BIT_32(13) +/** Bit 15 - LWP - Lightweight profiling support. */ +#define X86_CPUID_AMD_FEATURE_ECX_LWP RT_BIT_32(15) +/** Bit 16 - FMA4 - Four operand FMA instruction support. */ +#define X86_CPUID_AMD_FEATURE_ECX_FMA4 RT_BIT_32(16) +/** Bit 19 - NodeId - Indicates support for + * MSR_C001_100C[NodeId,NodesPerProcessr]. */ +#define X86_CPUID_AMD_FEATURE_ECX_NODEID RT_BIT_32(19) +/** Bit 21 - TBM - Trailing bit manipulation instruction support. */ +#define X86_CPUID_AMD_FEATURE_ECX_TBM RT_BIT_32(21) +/** Bit 22 - TopologyExtensions - . */ +#define X86_CPUID_AMD_FEATURE_ECX_TOPOEXT RT_BIT_32(22) +/** @} */ + + +/** @name CPUID AMD Feature information. + * CPUID query with EAX=0x80000007. + * @{ + */ +/** Bit 0 - TS - Temperature Sensor. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_TS RT_BIT_32(0) +/** Bit 1 - FID - Frequency ID Control. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_FID RT_BIT_32(1) +/** Bit 2 - VID - Voltage ID Control. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_VID RT_BIT_32(2) +/** Bit 3 - TTP - THERMTRIP. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_TTP RT_BIT_32(3) +/** Bit 4 - TM - Hardware Thermal Control. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_TM RT_BIT_32(4) +/** Bit 5 - STC - Software Thermal Control. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_STC RT_BIT_32(5) +/** Bit 6 - MC - 100 Mhz Multiplier Control. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_MC RT_BIT_32(6) +/** Bit 7 - HWPSTATE - Hardware P-State Control. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_HWPSTATE RT_BIT_32(7) +/** Bit 8 - TSCINVAR - TSC Invariant. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_TSCINVAR RT_BIT_32(8) +/** Bit 9 - CPB - TSC Invariant. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_CPB RT_BIT_32(9) +/** Bit 10 - EffFreqRO - MPERF/APERF. */ +#define X86_CPUID_AMD_ADVPOWER_EDX_EFRO RT_BIT_32(10) +/** Bit 11 - PFI - Processor feedback interface (see EAX). */ +#define X86_CPUID_AMD_ADVPOWER_EDX_PFI RT_BIT_32(11) +/** Bit 12 - PA - Processor accumulator (MSR c001_007a). */ +#define X86_CPUID_AMD_ADVPOWER_EDX_PA RT_BIT_32(12) +/** @} */ + + +/** @name CPUID AMD extended feature extensions ID (EBX). + * CPUID query with EAX=0x80000008. + * @{ + */ +/** Bit 0 - CLZERO - Clear zero instruction. */ +#define X86_CPUID_AMD_EFEID_EBX_CLZERO RT_BIT_32(0) +/** Bit 1 - IRPerf - Instructions retired count support. */ +#define X86_CPUID_AMD_EFEID_EBX_IRPERF RT_BIT_32(1) +/** Bit 2 - XSaveErPtr - Always XSAVE* and XRSTR* error pointers. */ +#define X86_CPUID_AMD_EFEID_EBX_XSAVE_ER_PTR RT_BIT_32(2) +/** Bit 4 - RDPRU - Supports the RDPRU instruction. */ +#define X86_CPUID_AMD_EFEID_EBX_RDPRU RT_BIT_32(4) +/** Bit 8 - MCOMMIT - Supports the MCOMMIT instruction. */ +#define X86_CPUID_AMD_EFEID_EBX_MCOMMIT RT_BIT_32(8) +/* AMD pipeline length: 9 feature bits ;-) */ +/** Bit 12 - IBPB - Supports the IBPB command in IA32_PRED_CMD. */ +#define X86_CPUID_AMD_EFEID_EBX_IBPB RT_BIT_32(12) +/** Bit 14 - IBRS - Supports the IBRS bit in IA32_SPEC_CTRL. */ +#define X86_CPUID_AMD_EFEID_EBX_IBRS RT_BIT_32(14) +/** Bit 15 - STIBP - Supports the STIBP bit in IA32_SPEC_CTRL. */ +#define X86_CPUID_AMD_EFEID_EBX_STIBP RT_BIT_32(15) +/** Bit 16 - IBRS always on mode - IBRS should be set once during boot only. */ +#define X86_CPUID_AMD_EFEID_EBX_IBRS_ALWAYS_ON RT_BIT_32(16) +/** Bit 17 - STIBP always on mode - STIBP should be set once during boot only. */ +#define X86_CPUID_AMD_EFEID_EBX_STIBP_ALWAYS_ON RT_BIT_32(17) +/** Bit 18 - IBRS preferred - IBRS is preferred over software mitigations. */ +#define X86_CPUID_AMD_EFEID_EBX_IBRS_PREFERRED RT_BIT_32(18) +/** Bit 24 - Speculative Store Bypass Disable supported in SPEC_CTL. */ +#define X86_CPUID_AMD_EFEID_EBX_SPEC_CTRL_SSBD RT_BIT_32(24) +/** Bit 25 - Speculative Store Bypass Disable supported in VIRT_SPEC_CTL. */ +#define X86_CPUID_AMD_EFEID_EBX_VIRT_SPEC_CTRL_SSBD RT_BIT_32(25) +/** Bit 26 - Speculative Store Bypass Disable not required. */ +#define X86_CPUID_AMD_EFEID_EBX_NO_SSBD_REQUIRED RT_BIT_32(26) +/** @} */ + + +/** @name CPUID AMD SVM Feature information. + * CPUID query with EAX=0x8000000a. + * @{ + */ +/** Bit 0 - NP - Nested Paging supported. */ +#define X86_CPUID_SVM_FEATURE_EDX_NESTED_PAGING RT_BIT(0) +/** Bit 1 - LbrVirt - Support for saving five debug MSRs. */ +#define X86_CPUID_SVM_FEATURE_EDX_LBR_VIRT RT_BIT(1) +/** Bit 2 - SVML - SVM locking bit supported. */ +#define X86_CPUID_SVM_FEATURE_EDX_SVM_LOCK RT_BIT(2) +/** Bit 3 - NRIPS - Saving the next instruction pointer is supported. */ +#define X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE RT_BIT(3) +/** Bit 4 - TscRateMsr - Support for MSR TSC ratio. */ +#define X86_CPUID_SVM_FEATURE_EDX_TSC_RATE_MSR RT_BIT(4) +/** Bit 5 - VmcbClean - Support VMCB clean bits. */ +#define X86_CPUID_SVM_FEATURE_EDX_VMCB_CLEAN RT_BIT(5) +/** Bit 6 - FlushByAsid - Indicate TLB flushing for current ASID only, and that + * VMCB.TLB_Control is supported. */ +#define X86_CPUID_SVM_FEATURE_EDX_FLUSH_BY_ASID RT_BIT(6) +/** Bit 7 - DecodeAssists - Indicate decode assists is supported. */ +#define X86_CPUID_SVM_FEATURE_EDX_DECODE_ASSISTS RT_BIT(7) +/** Bit 10 - PauseFilter - Indicates support for the PAUSE intercept filter. */ +#define X86_CPUID_SVM_FEATURE_EDX_PAUSE_FILTER RT_BIT(10) +/** Bit 12 - PauseFilterThreshold - Indicates support for the PAUSE + * intercept filter cycle count threshold. */ +#define X86_CPUID_SVM_FEATURE_EDX_PAUSE_FILTER_THRESHOLD RT_BIT(12) +/** Bit 13 - AVIC - Advanced Virtual Interrupt Controller. */ +#define X86_CPUID_SVM_FEATURE_EDX_AVIC RT_BIT(13) +/** Bit 15 - VMSAVEvirt - Supports virtualized VMSAVE/VMLOAD. */ +#define X86_CPUID_SVM_FEATURE_EDX_VIRT_VMSAVE_VMLOAD RT_BIT(15) +/** Bit 16 - VGIF - Supports virtualized GIF. */ +#define X86_CPUID_SVM_FEATURE_EDX_VGIF RT_BIT(16) +/** Bit 17 - GMET - Supports Guest Mode Execute Trap Extensions. */ +#define X86_CPUID_SVM_FEATURE_EDX_GMET RT_BIT(17) +/** Bit 19 - SSSCheck - SVM supervisor shadow stack restrictions. */ +#define X86_CPUID_SVM_FEATURE_EDX_SSSCHECK RT_BIT(19) +/** Bit 20 - SpecCtrl - Supports SPEC_CTRL Virtualization. */ +#define X86_CPUID_SVM_FEATURE_EDX_SPEC_CTRL RT_BIT(20) +/** Bit 23 - HOST_MCE_OVERRIDE - Supports host \#MC exception override. */ +#define X86_CPUID_SVM_FEATURE_EDX_HOST_MCE_OVERRIDE RT_BIT(23) +/** Bit 24 - TlbiCtl - Supports INVLPGB/TLBSYNC in VMCB and TLBSYNC intercept. */ +#define X86_CPUID_SVM_FEATURE_EDX_TLBICTL RT_BIT(24) +/** @} */ + + +/** @name CR0 + * @remarks The 286 (MSW), 386 and 486 ignores attempts at setting + * reserved flags. + * @{ */ +/** Bit 0 - PE - Protection Enabled */ +#define X86_CR0_PE RT_BIT_32(0) +#define X86_CR0_PROTECTION_ENABLE RT_BIT_32(0) +/** Bit 1 - MP - Monitor Coprocessor */ +#define X86_CR0_MP RT_BIT_32(1) +#define X86_CR0_MONITOR_COPROCESSOR RT_BIT_32(1) +/** Bit 2 - EM - Emulation. */ +#define X86_CR0_EM RT_BIT_32(2) +#define X86_CR0_EMULATE_FPU RT_BIT_32(2) +/** Bit 3 - TS - Task Switch. */ +#define X86_CR0_TS RT_BIT_32(3) +#define X86_CR0_TASK_SWITCH RT_BIT_32(3) +/** Bit 4 - ET - Extension flag. (386, 'hardcoded' to 1 on 486+) */ +#define X86_CR0_ET RT_BIT_32(4) +#define X86_CR0_EXTENSION_TYPE RT_BIT_32(4) +/** Bit 5 - NE - Numeric error (486+). */ +#define X86_CR0_NE RT_BIT_32(5) +#define X86_CR0_NUMERIC_ERROR RT_BIT_32(5) +/** Bit 16 - WP - Write Protect (486+). */ +#define X86_CR0_WP RT_BIT_32(16) +#define X86_CR0_WRITE_PROTECT RT_BIT_32(16) +/** Bit 18 - AM - Alignment Mask (486+). */ +#define X86_CR0_AM RT_BIT_32(18) +#define X86_CR0_ALIGMENT_MASK RT_BIT_32(18) +/** Bit 29 - NW - Not Write-though (486+). */ +#define X86_CR0_NW RT_BIT_32(29) +#define X86_CR0_NOT_WRITE_THROUGH RT_BIT_32(29) +/** Bit 30 - WP - Cache Disable (486+). */ +#define X86_CR0_CD RT_BIT_32(30) +#define X86_CR0_CACHE_DISABLE RT_BIT_32(30) +/** Bit 31 - PG - Paging. */ +#define X86_CR0_PG RT_BIT_32(31) +#define X86_CR0_PAGING RT_BIT_32(31) +#define X86_CR0_BIT_PG 31 /**< Bit number of X86_CR0_PG */ +/** @} */ + + +/** @name CR3 + * @{ */ +/** Bit 3 - PWT - Page-level Writes Transparent. */ +#define X86_CR3_PWT RT_BIT_32(3) +/** Bit 4 - PCD - Page-level Cache Disable. */ +#define X86_CR3_PCD RT_BIT_32(4) +/** Bits 12-31 - - Page directory page number. */ +#define X86_CR3_PAGE_MASK (0xfffff000) +/** Bits 5-31 - - PAE Page directory page number. */ +#define X86_CR3_PAE_PAGE_MASK (0xffffffe0) +/** Bits 12-51 - - AMD64 PML4 page number. + * @note This is a maxed out mask, the actual acceptable CR3 value can + * be lower depending on the PhysAddrSize from CPUID Fn8000_0008. */ +#define X86_CR3_AMD64_PAGE_MASK UINT64_C(0x000ffffffffff000) +/** Bits 12-51 - - Intel EPT PML4 page number (EPTP). + * @note This is a maxed out mask, the actual acceptable CR3/EPTP value can + * be lower depending on the PhysAddrSize from CPUID Fn8000_0008. */ +#define X86_CR3_EPT_PAGE_MASK UINT64_C(0x000ffffffffff000) +/** @} */ + + +/** @name CR4 + * @{ */ +/** Bit 0 - VME - Virtual-8086 Mode Extensions. */ +#define X86_CR4_VME RT_BIT_32(0) +/** Bit 1 - PVI - Protected-Mode Virtual Interrupts. */ +#define X86_CR4_PVI RT_BIT_32(1) +/** Bit 2 - TSD - Time Stamp Disable. */ +#define X86_CR4_TSD RT_BIT_32(2) +/** Bit 3 - DE - Debugging Extensions. */ +#define X86_CR4_DE RT_BIT_32(3) +/** Bit 4 - PSE - Page Size Extension. */ +#define X86_CR4_PSE RT_BIT_32(4) +/** Bit 5 - PAE - Physical Address Extension. */ +#define X86_CR4_PAE RT_BIT_32(5) +/** Bit 6 - MCE - Machine-Check Enable. */ +#define X86_CR4_MCE RT_BIT_32(6) +/** Bit 7 - PGE - Page Global Enable. */ +#define X86_CR4_PGE RT_BIT_32(7) +/** Bit 8 - PCE - Performance-Monitoring Counter Enable. */ +#define X86_CR4_PCE RT_BIT_32(8) +/** Bit 9 - OSFXSR - Operating System Support for FXSAVE and FXRSTORE instructions. */ +#define X86_CR4_OSFXSR RT_BIT_32(9) +/** Bit 10 - OSXMMEEXCPT - Operating System Support for Unmasked SIMD Floating-Point Exceptions. */ +#define X86_CR4_OSXMMEEXCPT RT_BIT_32(10) +/** Bit 11 - UMIP - User-Mode Instruction Prevention. */ +#define X86_CR4_UMIP RT_BIT_32(11) +/** Bit 13 - VMXE - VMX mode is enabled. */ +#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 + * extended states. */ +#define X86_CR4_OSXSAVE RT_BIT_32(18) +/** Bit 20 - SMEP - Supervisor-mode Execution Prevention enabled. */ +#define X86_CR4_SMEP RT_BIT_32(20) +/** Bit 21 - SMAP - Supervisor-mode Access Prevention enabled. */ +#define X86_CR4_SMAP RT_BIT_32(21) +/** Bit 22 - PKE - Protection Key Enable. */ +#define X86_CR4_PKE RT_BIT_32(22) +/** Bit 23 - CET - Control-flow Enhancement Technology enabled. */ +#define X86_CR4_CET RT_BIT_32(23) +/** @} */ + + +/** @name DR6 + * @{ */ +/** Bit 0 - B0 - Breakpoint 0 condition detected. */ +#define X86_DR6_B0 RT_BIT_32(0) +/** Bit 1 - B1 - Breakpoint 1 condition detected. */ +#define X86_DR6_B1 RT_BIT_32(1) +/** Bit 2 - B2 - Breakpoint 2 condition detected. */ +#define X86_DR6_B2 RT_BIT_32(2) +/** Bit 3 - B3 - Breakpoint 3 condition detected. */ +#define X86_DR6_B3 RT_BIT_32(3) +/** Mask of all the Bx bits. */ +#define X86_DR6_B_MASK UINT64_C(0x0000000f) +/** Bit 13 - BD - Debug register access detected. Corresponds to the X86_DR7_GD bit. */ +#define X86_DR6_BD RT_BIT_32(13) +/** Bit 14 - BS - Single step */ +#define X86_DR6_BS RT_BIT_32(14) +/** Bit 15 - BT - Task switch. (TSS T bit.) */ +#define X86_DR6_BT RT_BIT_32(15) +/** Bit 16 - RTM - Cleared if debug exception inside RTM (@sa X86_DR7_RTM). */ +#define X86_DR6_RTM RT_BIT_32(16) +/** Value of DR6 after powerup/reset. */ +#define X86_DR6_INIT_VAL UINT64_C(0xffff0ff0) +/** Bits which must be 1s in DR6. */ +#define X86_DR6_RA1_MASK UINT64_C(0xffff0ff0) +/** Bits which must be 1s in DR6, when RTM is supported. */ +#define X86_DR6_RA1_MASK_RTM UINT64_C(0xfffe0ff0) +/** Bits which must be 0s in DR6. */ +#define X86_DR6_RAZ_MASK RT_BIT_64(12) +/** Bits which must be 0s on writes to DR6. */ +#define X86_DR6_MBZ_MASK UINT64_C(0xffffffff00000000) +/** @} */ + +/** Get the DR6.Bx bit for a the given breakpoint. */ +#define X86_DR6_B(iBp) RT_BIT_64(iBp) + + +/** @name DR7 + * @{ */ +/** Bit 0 - L0 - Local breakpoint enable. Cleared on task switch. */ +#define X86_DR7_L0 RT_BIT_32(0) +/** Bit 1 - G0 - Global breakpoint enable. Not cleared on task switch. */ +#define X86_DR7_G0 RT_BIT_32(1) +/** Bit 2 - L1 - Local breakpoint enable. Cleared on task switch. */ +#define X86_DR7_L1 RT_BIT_32(2) +/** Bit 3 - G1 - Global breakpoint enable. Not cleared on task switch. */ +#define X86_DR7_G1 RT_BIT_32(3) +/** Bit 4 - L2 - Local breakpoint enable. Cleared on task switch. */ +#define X86_DR7_L2 RT_BIT_32(4) +/** Bit 5 - G2 - Global breakpoint enable. Not cleared on task switch. */ +#define X86_DR7_G2 RT_BIT_32(5) +/** Bit 6 - L3 - Local breakpoint enable. Cleared on task switch. */ +#define X86_DR7_L3 RT_BIT_32(6) +/** Bit 7 - G3 - Global breakpoint enable. Not cleared on task switch. */ +#define X86_DR7_G3 RT_BIT_32(7) +/** Bit 8 - LE - Local breakpoint exact. (Not supported (read ignored) by P6 and later.) */ +#define X86_DR7_LE RT_BIT_32(8) +/** Bit 9 - GE - Global breakpoint exact. (Not supported (read ignored) by P6 and later.) */ +#define X86_DR7_GE RT_BIT_32(9) + +/** L0, L1, L2, and L3. */ +#define X86_DR7_LE_ALL UINT64_C(0x0000000000000055) +/** L0, L1, L2, and L3. */ +#define X86_DR7_GE_ALL UINT64_C(0x00000000000000aa) + +/** Bit 11 - RTM - Enable advanced debugging of RTM transactions. + * Requires IA32_DEBUGCTL.RTM=1 too, and RTM HW support of course. */ +#define X86_DR7_RTM RT_BIT_32(11) +/** Bit 12 - IR (ICE) - Interrupt redirection on Pentium. When set, the in + * Circuit Emulator (ICE) will break emulation on breakpoints and stuff. + * May cause CPU hang if enabled without ICE attached when the ICEBP/INT1 + * instruction is executed. + * @see http://www.rcollins.org/secrets/DR7.html */ +#define X86_DR7_ICE_IR RT_BIT_32(12) +/** Bit 13 - GD - General detect enable. Enables emulators to get exceptions when + * any DR register is accessed. */ +#define X86_DR7_GD RT_BIT_32(13) +/** Bit 14 - TR1 (ICE) - Code discontinuity trace for use with ICE on + * Pentium. */ +#define X86_DR7_ICE_TR1 RT_BIT_32(14) +/** Bit 15 - TR2 (ICE) - Controls unknown ICE trace feature of the pentium. */ +#define X86_DR7_ICE_TR2 RT_BIT_32(15) +/** Bit 16 & 17 - R/W0 - Read write field 0. Values X86_DR7_RW_*. */ +#define X86_DR7_RW0_MASK (3 << 16) +/** Bit 18 & 19 - LEN0 - Length field 0. Values X86_DR7_LEN_*. */ +#define X86_DR7_LEN0_MASK (3 << 18) +/** Bit 20 & 21 - R/W1 - Read write field 0. Values X86_DR7_RW_*. */ +#define X86_DR7_RW1_MASK (3 << 20) +/** Bit 22 & 23 - LEN1 - Length field 0. Values X86_DR7_LEN_*. */ +#define X86_DR7_LEN1_MASK (3 << 22) +/** Bit 24 & 25 - R/W2 - Read write field 0. Values X86_DR7_RW_*. */ +#define X86_DR7_RW2_MASK (3 << 24) +/** Bit 26 & 27 - LEN2 - Length field 0. Values X86_DR7_LEN_*. */ +#define X86_DR7_LEN2_MASK (3 << 26) +/** Bit 28 & 29 - R/W3 - Read write field 0. Values X86_DR7_RW_*. */ +#define X86_DR7_RW3_MASK (3 << 28) +/** Bit 30 & 31 - LEN3 - Length field 0. Values X86_DR7_LEN_*. */ +#define X86_DR7_LEN3_MASK (3 << 30) + +/** Bits which reads as 1s. */ +#define X86_DR7_RA1_MASK RT_BIT_32(10) +/** Bits which reads as zeros. These are related to ICE (bits 12, 14, 15). */ +#define X86_DR7_RAZ_MASK UINT64_C(0x0000d800) +/** Bits which must be 0s when writing to DR7. */ +#define X86_DR7_MBZ_MASK UINT64_C(0xffffffff00000000) + +/** Calcs the L bit of Nth breakpoint. + * @param iBp The breakpoint number [0..3]. + */ +#define X86_DR7_L(iBp) ( UINT32_C(1) << (iBp * 2) ) + +/** Calcs the G bit of Nth breakpoint. + * @param iBp The breakpoint number [0..3]. + */ +#define X86_DR7_G(iBp) ( UINT32_C(1) << (iBp * 2 + 1) ) + +/** Calcs the L and G bits of Nth breakpoint. + * @param iBp The breakpoint number [0..3]. + */ +#define X86_DR7_L_G(iBp) ( UINT32_C(3) << (iBp * 2) ) + +/** @name Read/Write values. + * @{ */ +/** Break on instruction fetch only. */ +#define X86_DR7_RW_EO UINT32_C(0) +/** Break on write only. */ +#define X86_DR7_RW_WO UINT32_C(1) +/** Break on I/O read/write. This is only defined if CR4.DE is set. */ +#define X86_DR7_RW_IO UINT32_C(2) +/** Break on read or write (but not instruction fetches). */ +#define X86_DR7_RW_RW UINT32_C(3) +/** @} */ + +/** Shifts a X86_DR7_RW_* value to its right place. + * @param iBp The breakpoint number [0..3]. + * @param fRw One of the X86_DR7_RW_* value. + */ +#define X86_DR7_RW(iBp, fRw) ( (fRw) << ((iBp) * 4 + 16) ) + +/** Fetch the R/Wx bits for a given breakpoint (so it can be compared with + * one of the X86_DR7_RW_XXX constants). + * + * @returns X86_DR7_RW_XXX + * @param uDR7 DR7 value + * @param iBp The breakpoint number [0..3]. + */ +#define X86_DR7_GET_RW(uDR7, iBp) ( ( (uDR7) >> ((iBp) * 4 + 16) ) & UINT32_C(3) ) + +/** R/W0, R/W1, R/W2, and R/W3. */ +#define X86_DR7_RW_ALL_MASKS UINT32_C(0x33330000) + +#ifndef VBOX_FOR_DTRACE_LIB +/** Checks the RW and LEN fields are set up for an instruction breakpoint. + * @note This does not check if it's enabled. */ +# define X86_DR7_IS_EO_CFG(a_uDR7, a_iBp) ( ((a_uDR7) & (UINT32_C(0x000f0000) << ((a_iBp) * 4))) == 0 ) +/** Checks if an instruction breakpoint is enabled and configured correctly. + * @sa X86_DR7_IS_EO_CFG, X86_DR7_ANY_EO_ENABLED */ +# define X86_DR7_IS_EO_ENABLED(a_uDR7, a_iBp) \ + ( ((a_uDR7) & (UINT32_C(0x03) << ((a_iBp) * 2))) != 0 && X86_DR7_IS_EO_CFG(a_uDR7, a_iBp) ) +/** Checks if there are any instruction fetch breakpoint types configured in the + * RW and LEN registers. + * @sa X86_DR7_IS_EO_CFG, X86_DR7_IS_EO_ENABLED */ +# define X86_DR7_ANY_EO_ENABLED(a_uDR7) \ + ( (((a_uDR7) & UINT32_C(0x03)) != 0 && ((a_uDR7) & UINT32_C(0x000f0000)) == 0) \ + || (((a_uDR7) & UINT32_C(0x0c)) != 0 && ((a_uDR7) & UINT32_C(0x00f00000)) == 0) \ + || (((a_uDR7) & UINT32_C(0x30)) != 0 && ((a_uDR7) & UINT32_C(0x0f000000)) == 0) \ + || (((a_uDR7) & UINT32_C(0xc0)) != 0 && ((a_uDR7) & UINT32_C(0xf0000000)) == 0) ) + +/** Checks if there are any I/O breakpoint types configured in the RW + * registers. Does NOT check if these are enabled, sorry. */ +# define X86_DR7_ANY_RW_IO(uDR7) \ + ( ( UINT32_C(0x22220000) & (uDR7) ) /* any candidates? */ \ + && ( ( (UINT32_C(0x22220000) & (uDR7) ) >> 1 ) & ~(uDR7) ) ) +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x33330000)) == 0); +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x22220000)) == 1); +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x32320000)) == 1); +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x23230000)) == 1); +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x00000000)) == 0); +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x00010000)) == 0); +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x00020000)) == 1); +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x00030000)) == 0); +AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x00040000)) == 0); + +#endif /* !VBOX_FOR_DTRACE_LIB */ + +/** @name Length values. + * @{ */ +#define X86_DR7_LEN_BYTE UINT32_C(0) +#define X86_DR7_LEN_WORD UINT32_C(1) +#define X86_DR7_LEN_QWORD UINT32_C(2) /**< AMD64 long mode only. */ +#define X86_DR7_LEN_DWORD UINT32_C(3) +/** @} */ + +/** Shifts a X86_DR7_LEN_* value to its right place. + * @param iBp The breakpoint number [0..3]. + * @param cb One of the X86_DR7_LEN_* values. + */ +#define X86_DR7_LEN(iBp, cb) ( (cb) << ((iBp) * 4 + 18) ) + +/** Fetch the breakpoint length bits from the DR7 value. + * @param uDR7 DR7 value + * @param iBp The breakpoint number [0..3]. + */ +#define X86_DR7_GET_LEN(uDR7, iBp) ( ( (uDR7) >> ((iBp) * 4 + 18) ) & UINT32_C(0x3) ) + +/** Mask used to check if any breakpoints are enabled. */ +#define X86_DR7_ENABLED_MASK UINT32_C(0x000000ff) + +/** LEN0, LEN1, LEN2, and LEN3. */ +#define X86_DR7_LEN_ALL_MASKS UINT32_C(0xcccc0000) +/** R/W0, R/W1, R/W2, R/W3,LEN0, LEN1, LEN2, and LEN3. */ +#define X86_DR7_RW_LEN_ALL_MASKS UINT32_C(0xffff0000) + +/** Value of DR7 after powerup/reset. */ +#define X86_DR7_INIT_VAL 0x400 +/** @} */ + + +/** @name Machine Specific Registers + * @{ + */ +/** Machine check address register (P5). */ +#define MSR_P5_MC_ADDR UINT32_C(0x00000000) +/** Machine check type register (P5). */ +#define MSR_P5_MC_TYPE UINT32_C(0x00000001) +/** Time Stamp Counter. */ +#define MSR_IA32_TSC 0x10 +#define MSR_IA32_CESR UINT32_C(0x00000011) +#define MSR_IA32_CTR0 UINT32_C(0x00000012) +#define MSR_IA32_CTR1 UINT32_C(0x00000013) + +#define MSR_IA32_PLATFORM_ID 0x17 + +#ifndef MSR_IA32_APICBASE /* qemu cpu.h kludge */ +# define MSR_IA32_APICBASE 0x1b +/** Local APIC enabled. */ +# define MSR_IA32_APICBASE_EN RT_BIT_64(11) +/** X2APIC enabled (requires the EN bit to be set). */ +# define MSR_IA32_APICBASE_EXTD RT_BIT_64(10) +/** The processor is the boot strap processor (BSP). */ +# define MSR_IA32_APICBASE_BSP RT_BIT_64(8) +/** Minimum base address mask, consult CPUID leaf 0x80000008 for the actual + * width. */ +# define MSR_IA32_APICBASE_BASE_MIN UINT64_C(0x0000000ffffff000) +/** The default physical base address of the APIC. */ +# define MSR_IA32_APICBASE_ADDR UINT64_C(0x00000000fee00000) +/** Gets the physical base address from the MSR. */ +# define MSR_IA32_APICBASE_GET_ADDR(a_Msr) ((a_Msr) & X86_PAGE_4K_BASE_MASK) +#endif + +/** Undocumented intel MSR for reporting thread and core counts. + * Judging from the XNU sources, it seems to be introduced in Nehalem. The + * first 16 bits is the thread count. The next 16 bits the core count, except + * on Westmere where it seems it's only the next 4 bits for some reason. */ +#define MSR_CORE_THREAD_COUNT 0x35 + +/** CPU Feature control. */ +#define MSR_IA32_FEATURE_CONTROL 0x3A +/** Feature control - Lock MSR from writes (R/W0). */ +#define MSR_IA32_FEATURE_CONTROL_LOCK RT_BIT_64(0) +/** Feature control - Enable VMX inside SMX operation (R/WL). */ +#define MSR_IA32_FEATURE_CONTROL_SMX_VMXON RT_BIT_64(1) +/** Feature control - Enable VMX outside SMX operation (R/WL). */ +#define MSR_IA32_FEATURE_CONTROL_VMXON RT_BIT_64(2) +/** Feature control - SENTER local functions enable (R/WL). */ +#define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_0 RT_BIT_64(8) +#define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_1 RT_BIT_64(9) +#define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_2 RT_BIT_64(10) +#define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_3 RT_BIT_64(11) +#define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_4 RT_BIT_64(12) +#define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_5 RT_BIT_64(13) +#define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_6 RT_BIT_64(14) +/** Feature control - SENTER global enable (R/WL). */ +#define MSR_IA32_FEATURE_CONTROL_SENTER_GLOBAL_EN RT_BIT_64(15) +/** Feature control - SGX launch control enable (R/WL). */ +#define MSR_IA32_FEATURE_CONTROL_SGX_LAUNCH_EN RT_BIT_64(17) +/** Feature control - SGX global enable (R/WL). */ +#define MSR_IA32_FEATURE_CONTROL_SGX_GLOBAL_EN RT_BIT_64(18) +/** Feature control - LMCE on (R/WL). */ +#define MSR_IA32_FEATURE_CONTROL_LMCE RT_BIT_64(20) + +/** Per-processor TSC adjust MSR. */ +#define MSR_IA32_TSC_ADJUST 0x3B + +/** Spectre control register. + * Logical processor scope. Reset value 0, unaffected by SIPI & INIT. */ +#define MSR_IA32_SPEC_CTRL 0x48 +/** IBRS - Indirect branch restricted speculation. */ +#define MSR_IA32_SPEC_CTRL_F_IBRS RT_BIT_32(0) +/** STIBP - Single thread indirect branch predictors. */ +#define MSR_IA32_SPEC_CTRL_F_STIBP RT_BIT_32(1) +/** SSBD - Speculative Store Bypass Disable. */ +#define MSR_IA32_SPEC_CTRL_F_SSBD RT_BIT_32(2) + +/** Prediction command register. + * Write only, logical processor scope, no state since write only. */ +#define MSR_IA32_PRED_CMD 0x49 +/** IBPB - Indirect branch prediction barrie when written as 1. */ +#define MSR_IA32_PRED_CMD_F_IBPB RT_BIT_32(0) + +/** BIOS update trigger (microcode update). */ +#define MSR_IA32_BIOS_UPDT_TRIG 0x79 + +/** BIOS update signature (microcode). */ +#define MSR_IA32_BIOS_SIGN_ID 0x8B + +/** SMM monitor control. */ +#define MSR_IA32_SMM_MONITOR_CTL 0x9B +/** SMM control - Valid. */ +#define MSR_IA32_SMM_MONITOR_VALID RT_BIT_64(0) +/** SMM control - VMXOFF unblocks SMI. */ +#define MSR_IA32_SMM_MONITOR_VMXOFF_UNBLOCK_SMI RT_BIT_64(2) +/** SMM control - MSEG base physical address. */ +#define MSR_IA32_SMM_MONITOR_MSGEG_PHYSADDR(a) (((a) >> 12) & UINT64_C(0xfffff)) + +/** SMBASE - Base address of SMRANGE image (Read-only, SMM only). */ +#define MSR_IA32_SMBASE 0x9E + +/** General performance counter no. 0. */ +#define MSR_IA32_PMC0 0xC1 +/** General performance counter no. 1. */ +#define MSR_IA32_PMC1 0xC2 +/** General performance counter no. 2. */ +#define MSR_IA32_PMC2 0xC3 +/** General performance counter no. 3. */ +#define MSR_IA32_PMC3 0xC4 +/** General performance counter no. 4. */ +#define MSR_IA32_PMC4 0xC5 +/** General performance counter no. 5. */ +#define MSR_IA32_PMC5 0xC6 +/** General performance counter no. 6. */ +#define MSR_IA32_PMC6 0xC7 +/** General performance counter no. 7. */ +#define MSR_IA32_PMC7 0xC8 + +/** Nehalem power control. */ +#define MSR_IA32_PLATFORM_INFO 0xCE + +/** Get FSB clock status (Intel-specific). */ +#define MSR_IA32_FSB_CLOCK_STS 0xCD + +/** C-State configuration control. Intel specific: Nehalem, Sandy Bridge. */ +#define MSR_PKG_CST_CONFIG_CONTROL UINT32_C(0x000000e2) + +/** C0 Maximum Frequency Clock Count */ +#define MSR_IA32_MPERF 0xE7 +/** C0 Actual Frequency Clock Count */ +#define MSR_IA32_APERF 0xE8 + +/** MTRR Capabilities. */ +#define MSR_IA32_MTRR_CAP 0xFE + +/** Architecture capabilities (bugfixes). */ +#define MSR_IA32_ARCH_CAPABILITIES UINT32_C(0x10a) +/** CPU is no subject to meltdown problems. */ +#define MSR_IA32_ARCH_CAP_F_RDCL_NO RT_BIT_32(0) +/** CPU has better IBRS and you can leave it on all the time. */ +#define MSR_IA32_ARCH_CAP_F_IBRS_ALL RT_BIT_32(1) +/** CPU has return stack buffer (RSB) override. */ +#define MSR_IA32_ARCH_CAP_F_RSBO RT_BIT_32(2) +/** Virtual machine monitors need not flush the level 1 data cache on VM entry. + * This is also the case when MSR_IA32_ARCH_CAP_F_RDCL_NO is set. */ +#define MSR_IA32_ARCH_CAP_F_VMM_NEED_NOT_FLUSH_L1D RT_BIT_32(3) +/** CPU does not suffer from MDS issues. */ +#define MSR_IA32_ARCH_CAP_F_MDS_NO RT_BIT_32(4) + +/** Flush command register. */ +#define MSR_IA32_FLUSH_CMD UINT32_C(0x10b) +/** Flush the level 1 data cache when this bit is written. */ +#define MSR_IA32_FLUSH_CMD_F_L1D RT_BIT_32(0) + +/** Cache control/info. */ +#define MSR_BBL_CR_CTL3 UINT32_C(0x11e) + +#ifndef MSR_IA32_SYSENTER_CS /* qemu cpu.h kludge */ +/** SYSENTER_CS - the R0 CS, indirectly giving R0 SS, R3 CS and R3 DS. + * R0 SS == CS + 8 + * R3 CS == CS + 16 + * R3 SS == CS + 24 + */ +#define MSR_IA32_SYSENTER_CS 0x174 +/** SYSENTER_ESP - the R0 ESP. */ +#define MSR_IA32_SYSENTER_ESP 0x175 +/** SYSENTER_EIP - the R0 EIP. */ +#define MSR_IA32_SYSENTER_EIP 0x176 +#endif + +/** Machine Check Global Capabilities Register. */ +#define MSR_IA32_MCG_CAP 0x179 +/** Machine Check Global Status Register. */ +#define MSR_IA32_MCG_STATUS 0x17A +/** Machine Check Global Control Register. */ +#define MSR_IA32_MCG_CTRL 0x17B + +/** Page Attribute Table. */ +#define MSR_IA32_CR_PAT 0x277 +/** Default PAT MSR value on processor powerup / reset (see Intel spec. 11.12.4 + * "Programming the PAT", AMD spec. 7.8.2 "PAT Indexing") */ +#define MSR_IA32_CR_PAT_INIT_VAL UINT64_C(0x0007040600070406) + +/** Performance event select MSRs. (Intel only) */ +#define MSR_IA32_PERFEVTSEL0 0x186 +#define MSR_IA32_PERFEVTSEL1 0x187 +#define MSR_IA32_PERFEVTSEL2 0x188 +#define MSR_IA32_PERFEVTSEL3 0x189 + +/** Flexible ratio, seems to be undocumented, used by XNU (tsc.c). + * The 16th bit whether flex ratio is being used, in which case bits 15:8 + * holds a ratio that Apple takes for TSC granularity. + * + * @note This MSR conflicts the P4 MSR_MCG_R12 register. */ +#define MSR_FLEX_RATIO 0x194 +/** Performance state value and starting with Intel core more. + * Apple uses the >=core features to determine TSC granularity on older CPUs. */ +#define MSR_IA32_PERF_STATUS 0x198 +#define MSR_IA32_PERF_CTL 0x199 +#define MSR_IA32_THERM_STATUS 0x19c + +/** Offcore response event select registers. */ +#define MSR_OFFCORE_RSP_0 0x1a6 +#define MSR_OFFCORE_RSP_1 0x1a7 + +/** Enable misc. processor features (R/W). */ +#define MSR_IA32_MISC_ENABLE 0x1A0 +/** Enable fast-strings feature (for REP MOVS and REP STORS). */ +#define MSR_IA32_MISC_ENABLE_FAST_STRINGS RT_BIT_64(0) +/** Automatic Thermal Control Circuit Enable (R/W). */ +#define MSR_IA32_MISC_ENABLE_TCC RT_BIT_64(3) +/** Performance Monitoring Available (R). */ +#define MSR_IA32_MISC_ENABLE_PERF_MON RT_BIT_64(7) +/** Branch Trace Storage Unavailable (R/O). */ +#define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL RT_BIT_64(11) +/** Precise Event Based Sampling (PEBS) Unavailable (R/O). */ +#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL RT_BIT_64(12) +/** Enhanced Intel SpeedStep Technology Enable (R/W). */ +#define MSR_IA32_MISC_ENABLE_SST_ENABLE RT_BIT_64(16) +/** If MONITOR/MWAIT is supported (R/W). */ +#define MSR_IA32_MISC_ENABLE_MONITOR RT_BIT_64(18) +/** Limit CPUID Maxval to 3 leafs (R/W). */ +#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID RT_BIT_64(22) +/** When set to 1, xTPR messages are disabled (R/W). */ +#define MSR_IA32_MISC_ENABLE_XTPR_MSG_DISABLE RT_BIT_64(23) +/** When set to 1, the Execute Disable Bit feature (XD Bit) is disabled (R/W). */ +#define MSR_IA32_MISC_ENABLE_XD_DISABLE RT_BIT_64(34) + +/** Trace/Profile Resource Control (R/W) */ +#define MSR_IA32_DEBUGCTL UINT32_C(0x000001d9) +/** Last branch record. */ +#define MSR_IA32_DEBUGCTL_LBR RT_BIT_64(0) +/** Branch trace flag (single step on branches). */ +#define MSR_IA32_DEBUGCTL_BTF RT_BIT_64(1) +/** Performance monitoring pin control (AMD only). */ +#define MSR_IA32_DEBUGCTL_PB0 RT_BIT_64(2) +#define MSR_IA32_DEBUGCTL_PB1 RT_BIT_64(3) +#define MSR_IA32_DEBUGCTL_PB2 RT_BIT_64(4) +#define MSR_IA32_DEBUGCTL_PB3 RT_BIT_64(5) +/** Trace message enable (Intel only). */ +#define MSR_IA32_DEBUGCTL_TR RT_BIT_64(6) +/** Branch trace store (Intel only). */ +#define MSR_IA32_DEBUGCTL_BTS RT_BIT_64(7) +/** Branch trace interrupt (Intel only). */ +#define MSR_IA32_DEBUGCTL_BTINT RT_BIT_64(8) +/** Branch trace off in privileged code (Intel only). */ +#define MSR_IA32_DEBUGCTL_BTS_OFF_OS RT_BIT_64(9) +/** Branch trace off in user code (Intel only). */ +#define MSR_IA32_DEBUGCTL_BTS_OFF_USER RT_BIT_64(10) +/** Freeze LBR on PMI flag (Intel only). */ +#define MSR_IA32_DEBUGCTL_FREEZE_LBR_ON_PMI RT_BIT_64(11) +/** Freeze PERFMON on PMI flag (Intel only). */ +#define MSR_IA32_DEBUGCTL_FREEZE_PERFMON_ON_PMI RT_BIT_64(12) +/** Freeze while SMM enabled (Intel only). */ +#define MSR_IA32_DEBUGCTL_FREEZE_WHILE_SMM_EM RT_BIT_64(14) +/** Advanced debugging of RTM regions (Intel only). */ +#define MSR_IA32_DEBUGCTL_RTM RT_BIT_64(15) +/** Debug control MSR valid bits (Intel only). */ +#define MSR_IA32_DEBUGCTL_VALID_MASK_INTEL ( MSR_IA32_DEBUGCTL_LBR | MSR_IA32_DEBUGCTL_BTF | MSR_IA32_DEBUGCTL_TR \ + | MSR_IA32_DEBUGCTL_BTS | MSR_IA32_DEBUGCTL_BTINT | MSR_IA32_DEBUGCTL_BTS_OFF_OS \ + | MSR_IA32_DEBUGCTL_BTS_OFF_USER | MSR_IA32_DEBUGCTL_FREEZE_LBR_ON_PMI \ + | MSR_IA32_DEBUGCTL_FREEZE_PERFMON_ON_PMI | MSR_IA32_DEBUGCTL_FREEZE_WHILE_SMM_EM \ + | MSR_IA32_DEBUGCTL_RTM) + +/** @name Last branch registers for P4 and Xeon, models 0 thru 2. + * @{ */ +#define MSR_P4_LASTBRANCH_0 0x1db +#define MSR_P4_LASTBRANCH_1 0x1dc +#define MSR_P4_LASTBRANCH_2 0x1dd +#define MSR_P4_LASTBRANCH_3 0x1de + +/** LBR Top-of-stack MSR (index to most recent record). */ +#define MSR_P4_LASTBRANCH_TOS 0x1da +/** @} */ + +/** @name Last branch registers for Core 2 and related Xeons. + * @{ */ +#define MSR_CORE2_LASTBRANCH_0_FROM_IP 0x40 +#define MSR_CORE2_LASTBRANCH_1_FROM_IP 0x41 +#define MSR_CORE2_LASTBRANCH_2_FROM_IP 0x42 +#define MSR_CORE2_LASTBRANCH_3_FROM_IP 0x43 + +#define MSR_CORE2_LASTBRANCH_0_TO_IP 0x60 +#define MSR_CORE2_LASTBRANCH_1_TO_IP 0x61 +#define MSR_CORE2_LASTBRANCH_2_TO_IP 0x62 +#define MSR_CORE2_LASTBRANCH_3_TO_IP 0x63 + +/** LBR Top-of-stack MSR (index to most recent record). */ +#define MSR_CORE2_LASTBRANCH_TOS 0x1c9 +/** @} */ + +/** @name Last branch registers. + * @{ */ +#define MSR_LASTBRANCH_0_FROM_IP 0x680 +#define MSR_LASTBRANCH_1_FROM_IP 0x681 +#define MSR_LASTBRANCH_2_FROM_IP 0x682 +#define MSR_LASTBRANCH_3_FROM_IP 0x683 +#define MSR_LASTBRANCH_4_FROM_IP 0x684 +#define MSR_LASTBRANCH_5_FROM_IP 0x685 +#define MSR_LASTBRANCH_6_FROM_IP 0x686 +#define MSR_LASTBRANCH_7_FROM_IP 0x687 +#define MSR_LASTBRANCH_8_FROM_IP 0x688 +#define MSR_LASTBRANCH_9_FROM_IP 0x689 +#define MSR_LASTBRANCH_10_FROM_IP 0x68a +#define MSR_LASTBRANCH_11_FROM_IP 0x68b +#define MSR_LASTBRANCH_12_FROM_IP 0x68c +#define MSR_LASTBRANCH_13_FROM_IP 0x68d +#define MSR_LASTBRANCH_14_FROM_IP 0x68e +#define MSR_LASTBRANCH_15_FROM_IP 0x68f +#define MSR_LASTBRANCH_16_FROM_IP 0x690 +#define MSR_LASTBRANCH_17_FROM_IP 0x691 +#define MSR_LASTBRANCH_18_FROM_IP 0x692 +#define MSR_LASTBRANCH_19_FROM_IP 0x693 +#define MSR_LASTBRANCH_20_FROM_IP 0x694 +#define MSR_LASTBRANCH_21_FROM_IP 0x695 +#define MSR_LASTBRANCH_22_FROM_IP 0x696 +#define MSR_LASTBRANCH_23_FROM_IP 0x697 +#define MSR_LASTBRANCH_24_FROM_IP 0x698 +#define MSR_LASTBRANCH_25_FROM_IP 0x699 +#define MSR_LASTBRANCH_26_FROM_IP 0x69a +#define MSR_LASTBRANCH_27_FROM_IP 0x69b +#define MSR_LASTBRANCH_28_FROM_IP 0x69c +#define MSR_LASTBRANCH_29_FROM_IP 0x69d +#define MSR_LASTBRANCH_30_FROM_IP 0x69e +#define MSR_LASTBRANCH_31_FROM_IP 0x69f + +#define MSR_LASTBRANCH_0_TO_IP 0x6c0 +#define MSR_LASTBRANCH_1_TO_IP 0x6c1 +#define MSR_LASTBRANCH_2_TO_IP 0x6c2 +#define MSR_LASTBRANCH_3_TO_IP 0x6c3 +#define MSR_LASTBRANCH_4_TO_IP 0x6c4 +#define MSR_LASTBRANCH_5_TO_IP 0x6c5 +#define MSR_LASTBRANCH_6_TO_IP 0x6c6 +#define MSR_LASTBRANCH_7_TO_IP 0x6c7 +#define MSR_LASTBRANCH_8_TO_IP 0x6c8 +#define MSR_LASTBRANCH_9_TO_IP 0x6c9 +#define MSR_LASTBRANCH_10_TO_IP 0x6ca +#define MSR_LASTBRANCH_11_TO_IP 0x6cb +#define MSR_LASTBRANCH_12_TO_IP 0x6cc +#define MSR_LASTBRANCH_13_TO_IP 0x6cd +#define MSR_LASTBRANCH_14_TO_IP 0x6ce +#define MSR_LASTBRANCH_15_TO_IP 0x6cf +#define MSR_LASTBRANCH_16_TO_IP 0x6d0 +#define MSR_LASTBRANCH_17_TO_IP 0x6d1 +#define MSR_LASTBRANCH_18_TO_IP 0x6d2 +#define MSR_LASTBRANCH_19_TO_IP 0x6d3 +#define MSR_LASTBRANCH_20_TO_IP 0x6d4 +#define MSR_LASTBRANCH_21_TO_IP 0x6d5 +#define MSR_LASTBRANCH_22_TO_IP 0x6d6 +#define MSR_LASTBRANCH_23_TO_IP 0x6d7 +#define MSR_LASTBRANCH_24_TO_IP 0x6d8 +#define MSR_LASTBRANCH_25_TO_IP 0x6d9 +#define MSR_LASTBRANCH_26_TO_IP 0x6da +#define MSR_LASTBRANCH_27_TO_IP 0x6db +#define MSR_LASTBRANCH_28_TO_IP 0x6dc +#define MSR_LASTBRANCH_29_TO_IP 0x6dd +#define MSR_LASTBRANCH_30_TO_IP 0x6de +#define MSR_LASTBRANCH_31_TO_IP 0x6df + +#define MSR_LASTBRANCH_0_INFO 0xdc0 +#define MSR_LASTBRANCH_1_INFO 0xdc1 +#define MSR_LASTBRANCH_2_INFO 0xdc2 +#define MSR_LASTBRANCH_3_INFO 0xdc3 +#define MSR_LASTBRANCH_4_INFO 0xdc4 +#define MSR_LASTBRANCH_5_INFO 0xdc5 +#define MSR_LASTBRANCH_6_INFO 0xdc6 +#define MSR_LASTBRANCH_7_INFO 0xdc7 +#define MSR_LASTBRANCH_8_INFO 0xdc8 +#define MSR_LASTBRANCH_9_INFO 0xdc9 +#define MSR_LASTBRANCH_10_INFO 0xdca +#define MSR_LASTBRANCH_11_INFO 0xdcb +#define MSR_LASTBRANCH_12_INFO 0xdcc +#define MSR_LASTBRANCH_13_INFO 0xdcd +#define MSR_LASTBRANCH_14_INFO 0xdce +#define MSR_LASTBRANCH_15_INFO 0xdcf +#define MSR_LASTBRANCH_16_INFO 0xdd0 +#define MSR_LASTBRANCH_17_INFO 0xdd1 +#define MSR_LASTBRANCH_18_INFO 0xdd2 +#define MSR_LASTBRANCH_19_INFO 0xdd3 +#define MSR_LASTBRANCH_20_INFO 0xdd4 +#define MSR_LASTBRANCH_21_INFO 0xdd5 +#define MSR_LASTBRANCH_22_INFO 0xdd6 +#define MSR_LASTBRANCH_23_INFO 0xdd7 +#define MSR_LASTBRANCH_24_INFO 0xdd8 +#define MSR_LASTBRANCH_25_INFO 0xdd9 +#define MSR_LASTBRANCH_26_INFO 0xdda +#define MSR_LASTBRANCH_27_INFO 0xddb +#define MSR_LASTBRANCH_28_INFO 0xddc +#define MSR_LASTBRANCH_29_INFO 0xddd +#define MSR_LASTBRANCH_30_INFO 0xdde +#define MSR_LASTBRANCH_31_INFO 0xddf + +/** LBR branch tracking selection MSR. */ +#define MSR_LASTBRANCH_SELECT 0x1c8 +/** LBR Top-of-stack MSR (index to most recent record). */ +#define MSR_LASTBRANCH_TOS 0x1c9 +/** @} */ + +/** @name Last event record registers. + * @{ */ +/** Last event record source IP register. */ +#define MSR_LER_FROM_IP 0x1dd +/** Last event record destination IP register. */ +#define MSR_LER_TO_IP 0x1de +/** @} */ + +/** Intel TSX (Transactional Synchronization Extensions) control MSR. */ +#define MSR_IA32_TSX_CTRL 0x122 + +/** Variable range MTRRs. + * @{ */ +#define MSR_IA32_MTRR_PHYSBASE0 0x200 +#define MSR_IA32_MTRR_PHYSMASK0 0x201 +#define MSR_IA32_MTRR_PHYSBASE1 0x202 +#define MSR_IA32_MTRR_PHYSMASK1 0x203 +#define MSR_IA32_MTRR_PHYSBASE2 0x204 +#define MSR_IA32_MTRR_PHYSMASK2 0x205 +#define MSR_IA32_MTRR_PHYSBASE3 0x206 +#define MSR_IA32_MTRR_PHYSMASK3 0x207 +#define MSR_IA32_MTRR_PHYSBASE4 0x208 +#define MSR_IA32_MTRR_PHYSMASK4 0x209 +#define MSR_IA32_MTRR_PHYSBASE5 0x20a +#define MSR_IA32_MTRR_PHYSMASK5 0x20b +#define MSR_IA32_MTRR_PHYSBASE6 0x20c +#define MSR_IA32_MTRR_PHYSMASK6 0x20d +#define MSR_IA32_MTRR_PHYSBASE7 0x20e +#define MSR_IA32_MTRR_PHYSMASK7 0x20f +#define MSR_IA32_MTRR_PHYSBASE8 0x210 +#define MSR_IA32_MTRR_PHYSMASK8 0x211 +#define MSR_IA32_MTRR_PHYSBASE9 0x212 +#define MSR_IA32_MTRR_PHYSMASK9 0x213 +/** @} */ + +/** Fixed range MTRRs. + * @{ */ +#define MSR_IA32_MTRR_FIX64K_00000 0x250 +#define MSR_IA32_MTRR_FIX16K_80000 0x258 +#define MSR_IA32_MTRR_FIX16K_A0000 0x259 +#define MSR_IA32_MTRR_FIX4K_C0000 0x268 +#define MSR_IA32_MTRR_FIX4K_C8000 0x269 +#define MSR_IA32_MTRR_FIX4K_D0000 0x26a +#define MSR_IA32_MTRR_FIX4K_D8000 0x26b +#define MSR_IA32_MTRR_FIX4K_E0000 0x26c +#define MSR_IA32_MTRR_FIX4K_E8000 0x26d +#define MSR_IA32_MTRR_FIX4K_F0000 0x26e +#define MSR_IA32_MTRR_FIX4K_F8000 0x26f +/** @} */ + +/** MTRR Default Range. */ +#define MSR_IA32_MTRR_DEF_TYPE 0x2FF + +/** Global performance counter control facilities (Intel only). */ +#define MSR_IA32_PERF_GLOBAL_STATUS 0x38E +#define MSR_IA32_PERF_GLOBAL_CTRL 0x38F +#define MSR_IA32_PERF_GLOBAL_OVF_CTRL 0x390 + +/** Precise Event Based sampling (Intel only). */ +#define MSR_IA32_PEBS_ENABLE 0x3F1 + +#define MSR_IA32_MC0_CTL 0x400 +#define MSR_IA32_MC0_STATUS 0x401 + +/** Basic VMX information. */ +#define MSR_IA32_VMX_BASIC 0x480 +/** Allowed settings for pin-based VM execution controls. */ +#define MSR_IA32_VMX_PINBASED_CTLS 0x481 +/** Allowed settings for proc-based VM execution controls. */ +#define MSR_IA32_VMX_PROCBASED_CTLS 0x482 +/** Allowed settings for the VM-exit controls. */ +#define MSR_IA32_VMX_EXIT_CTLS 0x483 +/** Allowed settings for the VM-entry controls. */ +#define MSR_IA32_VMX_ENTRY_CTLS 0x484 +/** Misc VMX info. */ +#define MSR_IA32_VMX_MISC 0x485 +/** Fixed cleared bits in CR0. */ +#define MSR_IA32_VMX_CR0_FIXED0 0x486 +/** Fixed set bits in CR0. */ +#define MSR_IA32_VMX_CR0_FIXED1 0x487 +/** Fixed cleared bits in CR4. */ +#define MSR_IA32_VMX_CR4_FIXED0 0x488 +/** Fixed set bits in CR4. */ +#define MSR_IA32_VMX_CR4_FIXED1 0x489 +/** Information for enumerating fields in the VMCS. */ +#define MSR_IA32_VMX_VMCS_ENUM 0x48A +/** Allowed settings for secondary processor-based VM-execution controls. */ +#define MSR_IA32_VMX_PROCBASED_CTLS2 0x48B +/** EPT capabilities. */ +#define MSR_IA32_VMX_EPT_VPID_CAP 0x48C +/** Allowed settings of all pin-based VM execution controls. */ +#define MSR_IA32_VMX_TRUE_PINBASED_CTLS 0x48D +/** Allowed settings of all proc-based VM execution controls. */ +#define MSR_IA32_VMX_TRUE_PROCBASED_CTLS 0x48E +/** Allowed settings of all VMX exit controls. */ +#define MSR_IA32_VMX_TRUE_EXIT_CTLS 0x48F +/** Allowed settings of all VMX entry controls. */ +#define MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x490 +/** Allowed settings for the VM-function controls. */ +#define MSR_IA32_VMX_VMFUNC 0x491 +/** Tertiary processor-based VM execution controls. */ +#define MSR_IA32_VMX_PROCBASED_CTLS3 0x492 +/** Secondary VM-exit controls. */ +#define MSR_IA32_VMX_EXIT_CTLS2 0x493 + +/** Intel PT - Enable and control for trace packet generation. */ +#define MSR_IA32_RTIT_CTL 0x570 + +/** DS Save Area (R/W). */ +#define MSR_IA32_DS_AREA 0x600 +/** Running Average Power Limit (RAPL) power units. */ +#define MSR_RAPL_POWER_UNIT 0x606 +/** Package C3 Interrupt Response Limit. */ +#define MSR_PKGC3_IRTL 0x60a +/** Package C6/C7S Interrupt Response Limit 1. */ +#define MSR_PKGC_IRTL1 0x60b +/** Package C6/C7S Interrupt Response Limit 2. */ +#define MSR_PKGC_IRTL2 0x60c +/** Package C2 Residency Counter. */ +#define MSR_PKG_C2_RESIDENCY 0x60d +/** PKG RAPL Power Limit Control. */ +#define MSR_PKG_POWER_LIMIT 0x610 +/** PKG Energy Status. */ +#define MSR_PKG_ENERGY_STATUS 0x611 +/** PKG Perf Status. */ +#define MSR_PKG_PERF_STATUS 0x613 +/** PKG RAPL Parameters. */ +#define MSR_PKG_POWER_INFO 0x614 +/** DRAM RAPL Power Limit Control. */ +#define MSR_DRAM_POWER_LIMIT 0x618 +/** DRAM Energy Status. */ +#define MSR_DRAM_ENERGY_STATUS 0x619 +/** DRAM Performance Throttling Status. */ +#define MSR_DRAM_PERF_STATUS 0x61b +/** DRAM RAPL Parameters. */ +#define MSR_DRAM_POWER_INFO 0x61c +/** Package C10 Residency Counter. */ +#define MSR_PKG_C10_RESIDENCY 0x632 +/** PP0 Energy Status. */ +#define MSR_PP0_ENERGY_STATUS 0x639 +/** PP1 Energy Status. */ +#define MSR_PP1_ENERGY_STATUS 0x641 +/** Turbo Activation Ratio. */ +#define MSR_TURBO_ACTIVATION_RATIO 0x64c +/** Core Performance Limit Reasons. */ +#define MSR_CORE_PERF_LIMIT_REASONS 0x64f + +/** X2APIC MSR range start. */ +#define MSR_IA32_X2APIC_START 0x800 +/** X2APIC MSR - APIC ID Register. */ +#define MSR_IA32_X2APIC_ID 0x802 +/** X2APIC MSR - APIC Version Register. */ +#define MSR_IA32_X2APIC_VERSION 0x803 +/** X2APIC MSR - Task Priority Register. */ +#define MSR_IA32_X2APIC_TPR 0x808 +/** X2APIC MSR - Processor Priority register. */ +#define MSR_IA32_X2APIC_PPR 0x80A +/** X2APIC MSR - End Of Interrupt register. */ +#define MSR_IA32_X2APIC_EOI 0x80B +/** X2APIC MSR - Logical Destination Register. */ +#define MSR_IA32_X2APIC_LDR 0x80D +/** X2APIC MSR - Spurious Interrupt Vector Register. */ +#define MSR_IA32_X2APIC_SVR 0x80F +/** X2APIC MSR - In-service Register (bits 31:0). */ +#define MSR_IA32_X2APIC_ISR0 0x810 +/** X2APIC MSR - In-service Register (bits 63:32). */ +#define MSR_IA32_X2APIC_ISR1 0x811 +/** X2APIC MSR - In-service Register (bits 95:64). */ +#define MSR_IA32_X2APIC_ISR2 0x812 +/** X2APIC MSR - In-service Register (bits 127:96). */ +#define MSR_IA32_X2APIC_ISR3 0x813 +/** X2APIC MSR - In-service Register (bits 159:128). */ +#define MSR_IA32_X2APIC_ISR4 0x814 +/** X2APIC MSR - In-service Register (bits 191:160). */ +#define MSR_IA32_X2APIC_ISR5 0x815 +/** X2APIC MSR - In-service Register (bits 223:192). */ +#define MSR_IA32_X2APIC_ISR6 0x816 +/** X2APIC MSR - In-service Register (bits 255:224). */ +#define MSR_IA32_X2APIC_ISR7 0x817 +/** X2APIC MSR - Trigger Mode Register (bits 31:0). */ +#define MSR_IA32_X2APIC_TMR0 0x818 +/** X2APIC MSR - Trigger Mode Register (bits 63:32). */ +#define MSR_IA32_X2APIC_TMR1 0x819 +/** X2APIC MSR - Trigger Mode Register (bits 95:64). */ +#define MSR_IA32_X2APIC_TMR2 0x81A +/** X2APIC MSR - Trigger Mode Register (bits 127:96). */ +#define MSR_IA32_X2APIC_TMR3 0x81B +/** X2APIC MSR - Trigger Mode Register (bits 159:128). */ +#define MSR_IA32_X2APIC_TMR4 0x81C +/** X2APIC MSR - Trigger Mode Register (bits 191:160). */ +#define MSR_IA32_X2APIC_TMR5 0x81D +/** X2APIC MSR - Trigger Mode Register (bits 223:192). */ +#define MSR_IA32_X2APIC_TMR6 0x81E +/** X2APIC MSR - Trigger Mode Register (bits 255:224). */ +#define MSR_IA32_X2APIC_TMR7 0x81F +/** X2APIC MSR - Interrupt Request Register (bits 31:0). */ +#define MSR_IA32_X2APIC_IRR0 0x820 +/** X2APIC MSR - Interrupt Request Register (bits 63:32). */ +#define MSR_IA32_X2APIC_IRR1 0x821 +/** X2APIC MSR - Interrupt Request Register (bits 95:64). */ +#define MSR_IA32_X2APIC_IRR2 0x822 +/** X2APIC MSR - Interrupt Request Register (bits 127:96). */ +#define MSR_IA32_X2APIC_IRR3 0x823 +/** X2APIC MSR - Interrupt Request Register (bits 159:128). */ +#define MSR_IA32_X2APIC_IRR4 0x824 +/** X2APIC MSR - Interrupt Request Register (bits 191:160). */ +#define MSR_IA32_X2APIC_IRR5 0x825 +/** X2APIC MSR - Interrupt Request Register (bits 223:192). */ +#define MSR_IA32_X2APIC_IRR6 0x826 +/** X2APIC MSR - Interrupt Request Register (bits 255:224). */ +#define MSR_IA32_X2APIC_IRR7 0x827 +/** X2APIC MSR - Error Status Register. */ +#define MSR_IA32_X2APIC_ESR 0x828 +/** X2APIC MSR - LVT CMCI Register. */ +#define MSR_IA32_X2APIC_LVT_CMCI 0x82F +/** X2APIC MSR - Interrupt Command Register. */ +#define MSR_IA32_X2APIC_ICR 0x830 +/** X2APIC MSR - LVT Timer Register. */ +#define MSR_IA32_X2APIC_LVT_TIMER 0x832 +/** X2APIC MSR - LVT Thermal Sensor Register. */ +#define MSR_IA32_X2APIC_LVT_THERMAL 0x833 +/** X2APIC MSR - LVT Performance Counter Register. */ +#define MSR_IA32_X2APIC_LVT_PERF 0x834 +/** X2APIC MSR - LVT LINT0 Register. */ +#define MSR_IA32_X2APIC_LVT_LINT0 0x835 +/** X2APIC MSR - LVT LINT1 Register. */ +#define MSR_IA32_X2APIC_LVT_LINT1 0x836 +/** X2APIC MSR - LVT Error Register . */ +#define MSR_IA32_X2APIC_LVT_ERROR 0x837 +/** X2APIC MSR - Timer Initial Count Register. */ +#define MSR_IA32_X2APIC_TIMER_ICR 0x838 +/** X2APIC MSR - Timer Current Count Register. */ +#define MSR_IA32_X2APIC_TIMER_CCR 0x839 +/** X2APIC MSR - Timer Divide Configuration Register. */ +#define MSR_IA32_X2APIC_TIMER_DCR 0x83E +/** X2APIC MSR - Self IPI. */ +#define MSR_IA32_X2APIC_SELF_IPI 0x83F +/** X2APIC MSR range end. */ +#define MSR_IA32_X2APIC_END 0x8FF +/** X2APIC MSR - LVT start range. */ +#define MSR_IA32_X2APIC_LVT_START MSR_IA32_X2APIC_LVT_TIMER +/** X2APIC MSR - LVT end range (inclusive). */ +#define MSR_IA32_X2APIC_LVT_END MSR_IA32_X2APIC_LVT_ERROR + +/** K6 EFER - Extended Feature Enable Register. */ +#define MSR_K6_EFER UINT32_C(0xc0000080) +/** @todo document EFER */ +/** Bit 0 - SCE - System call extensions (SYSCALL / SYSRET). (R/W) */ +#define MSR_K6_EFER_SCE RT_BIT_32(0) +/** Bit 8 - LME - Long mode enabled. (R/W) */ +#define MSR_K6_EFER_LME RT_BIT_32(8) +#define MSR_K6_EFER_BIT_LME 8 /**< Bit number of MSR_K6_EFER_LME */ +/** Bit 10 - LMA - Long mode active. (R) */ +#define MSR_K6_EFER_LMA RT_BIT_32(10) +#define MSR_K6_EFER_BIT_LMA 10 /**< Bit number of MSR_K6_EFER_LMA */ +/** Bit 11 - NXE - No-Execute Page Protection Enabled. (R/W) */ +#define MSR_K6_EFER_NXE RT_BIT_32(11) +#define MSR_K6_EFER_BIT_NXE 11 /**< Bit number of MSR_K6_EFER_NXE */ +/** Bit 12 - SVME - Secure VM Extension Enabled. (R/W) */ +#define MSR_K6_EFER_SVME RT_BIT_32(12) +/** Bit 13 - LMSLE - Long Mode Segment Limit Enable. (R/W?) */ +#define MSR_K6_EFER_LMSLE RT_BIT_32(13) +/** Bit 14 - FFXSR - Fast FXSAVE / FXRSTOR (skip XMM*). (R/W) */ +#define MSR_K6_EFER_FFXSR RT_BIT_32(14) +/** Bit 15 - TCE - Translation Cache Extension. (R/W) */ +#define MSR_K6_EFER_TCE RT_BIT_32(15) +/** Bit 17 - MCOMMIT - Commit Stores to memory. (R/W) */ +#define MSR_K6_EFER_MCOMMIT RT_BIT_32(17) + +/** K6 STAR - SYSCALL/RET targets. */ +#define MSR_K6_STAR UINT32_C(0xc0000081) +/** Shift value for getting the SYSRET CS and SS value. */ +#define MSR_K6_STAR_SYSRET_CS_SS_SHIFT 48 +/** Shift value for getting the SYSCALL CS and SS value. */ +#define MSR_K6_STAR_SYSCALL_CS_SS_SHIFT 32 +/** Selector mask for use after shifting. */ +#define MSR_K6_STAR_SEL_MASK UINT32_C(0xffff) +/** The mask which give the SYSCALL EIP. */ +#define MSR_K6_STAR_SYSCALL_EIP_MASK UINT32_C(0xffffffff) +/** K6 WHCR - Write Handling Control Register. */ +#define MSR_K6_WHCR UINT32_C(0xc0000082) +/** K6 UWCCR - UC/WC Cacheability Control Register. */ +#define MSR_K6_UWCCR UINT32_C(0xc0000085) +/** K6 PSOR - Processor State Observability Register. */ +#define MSR_K6_PSOR UINT32_C(0xc0000087) +/** K6 PFIR - Page Flush/Invalidate Register. */ +#define MSR_K6_PFIR UINT32_C(0xc0000088) + +/** Performance counter MSRs. (AMD only) */ +#define MSR_K7_EVNTSEL0 UINT32_C(0xc0010000) +#define MSR_K7_EVNTSEL1 UINT32_C(0xc0010001) +#define MSR_K7_EVNTSEL2 UINT32_C(0xc0010002) +#define MSR_K7_EVNTSEL3 UINT32_C(0xc0010003) +#define MSR_K7_PERFCTR0 UINT32_C(0xc0010004) +#define MSR_K7_PERFCTR1 UINT32_C(0xc0010005) +#define MSR_K7_PERFCTR2 UINT32_C(0xc0010006) +#define MSR_K7_PERFCTR3 UINT32_C(0xc0010007) + +/** K8 LSTAR - Long mode SYSCALL target (RIP). */ +#define MSR_K8_LSTAR UINT32_C(0xc0000082) +/** K8 CSTAR - Compatibility mode SYSCALL target (RIP). */ +#define MSR_K8_CSTAR UINT32_C(0xc0000083) +/** K8 SF_MASK - SYSCALL flag mask. (aka SFMASK) */ +#define MSR_K8_SF_MASK UINT32_C(0xc0000084) +/** K8 FS.base - The 64-bit base FS register. */ +#define MSR_K8_FS_BASE UINT32_C(0xc0000100) +/** K8 GS.base - The 64-bit base GS register. */ +#define MSR_K8_GS_BASE UINT32_C(0xc0000101) +/** K8 KernelGSbase - Used with SWAPGS. */ +#define MSR_K8_KERNEL_GS_BASE UINT32_C(0xc0000102) +/** K8 TSC_AUX - Used with RDTSCP. */ +#define MSR_K8_TSC_AUX UINT32_C(0xc0000103) +#define MSR_K8_SYSCFG UINT32_C(0xc0010010) +#define MSR_K8_HWCR UINT32_C(0xc0010015) +#define MSR_K8_IORRBASE0 UINT32_C(0xc0010016) +#define MSR_K8_IORRMASK0 UINT32_C(0xc0010017) +#define MSR_K8_IORRBASE1 UINT32_C(0xc0010018) +#define MSR_K8_IORRMASK1 UINT32_C(0xc0010019) +#define MSR_K8_TOP_MEM1 UINT32_C(0xc001001a) +#define MSR_K8_TOP_MEM2 UINT32_C(0xc001001d) + +/** SMM MSRs. */ +#define MSR_K7_SMBASE UINT32_C(0xc0010111) +#define MSR_K7_SMM_ADDR UINT32_C(0xc0010112) +#define MSR_K7_SMM_MASK UINT32_C(0xc0010113) + +/** North bridge config? See BIOS & Kernel dev guides for + * details. */ +#define MSR_K8_NB_CFG UINT32_C(0xc001001f) + +/** Hypertransport interrupt pending register. + * "BIOS and Kernel Developer's Guide for AMD NPT Family 0Fh Processors" */ +#define MSR_K8_INT_PENDING UINT32_C(0xc0010055) + +/** SVM Control. */ +#define MSR_K8_VM_CR UINT32_C(0xc0010114) +/** Disables HDT (Hardware Debug Tool) and certain internal debug + * features. */ +#define MSR_K8_VM_CR_DPD RT_BIT_32(0) +/** If set, non-intercepted INIT signals are converted to \#SX + * exceptions. */ +#define MSR_K8_VM_CR_R_INIT RT_BIT_32(1) +/** Disables A20 masking. */ +#define MSR_K8_VM_CR_DIS_A20M RT_BIT_32(2) +/** Lock bit for this MSR controlling bits 3 (LOCK) and 4 (SVMDIS). */ +#define MSR_K8_VM_CR_LOCK RT_BIT_32(3) +/** SVM disable. When set, writes to EFER.SVME are treated as MBZ. When + * clear, EFER.SVME can be written normally. */ +#define MSR_K8_VM_CR_SVM_DISABLE RT_BIT_32(4) + +#define MSR_K8_IGNNE UINT32_C(0xc0010115) +#define MSR_K8_SMM_CTL UINT32_C(0xc0010116) +/** SVM - VM_HSAVE_PA - Physical address for saving and restoring + * host state during world switch. */ +#define MSR_K8_VM_HSAVE_PA UINT32_C(0xc0010117) + +/** Virtualized speculation control for AMD processors. + * + * Unified interface among different CPU generations. + * The VMM will set any architectural MSRs based on the CPU. + * See "White Paper: AMD64 Technology Speculative Store Bypass Disable 5.21.18" + * (12441_AMD64_SpeculativeStoreBypassDisable_Whitepaper_final.pdf) */ +#define MSR_AMD_VIRT_SPEC_CTL UINT32_C(0xc001011f) +/** Speculative Store Bypass Disable. */ +# define MSR_AMD_VIRT_SPEC_CTL_F_SSBD RT_BIT(2) + +/** @} */ + + +/** @name Page Table / Directory / Directory Pointers / L4. + * @{ + */ + +/** Page table/directory entry as an unsigned integer. */ +typedef uint32_t X86PGUINT; +/** Pointer to a page table/directory table entry as an unsigned integer. */ +typedef X86PGUINT *PX86PGUINT; +/** Pointer to an const page table/directory table entry as an unsigned integer. */ +typedef X86PGUINT const *PCX86PGUINT; + +/** Number of entries in a 32-bit PT/PD. */ +#define X86_PG_ENTRIES 1024 + + +/** PAE page table/page directory/pdpt/l4/l5 entry as an unsigned integer. */ +typedef uint64_t X86PGPAEUINT; +/** Pointer to a PAE page table/page directory/pdpt/l4/l5 entry as an unsigned integer. */ +typedef X86PGPAEUINT *PX86PGPAEUINT; +/** Pointer to an const PAE page table/page directory/pdpt/l4/l5 entry as an unsigned integer. */ +typedef X86PGPAEUINT const *PCX86PGPAEUINT; + +/** Number of entries in a PAE PT/PD. */ +#define X86_PG_PAE_ENTRIES 512 +/** Number of entries in a PAE PDPT. */ +#define X86_PG_PAE_PDPE_ENTRIES 4 + +/** Number of entries in an AMD64 PT/PD/PDPT/L4/L5. */ +#define X86_PG_AMD64_ENTRIES X86_PG_PAE_ENTRIES +/** Number of entries in an AMD64 PDPT. + * Just for complementing X86_PG_PAE_PDPE_ENTRIES, using X86_PG_AMD64_ENTRIES for this is fine too. */ +#define X86_PG_AMD64_PDPE_ENTRIES X86_PG_AMD64_ENTRIES + +/** The size of a default page. */ +#define X86_PAGE_SIZE X86_PAGE_4K_SIZE +/** The page shift of a default page. */ +#define X86_PAGE_SHIFT X86_PAGE_4K_SHIFT +/** The default page offset mask. */ +#define X86_PAGE_OFFSET_MASK X86_PAGE_4K_OFFSET_MASK +/** The default page base mask for virtual addresses. */ +#define X86_PAGE_BASE_MASK X86_PAGE_4K_BASE_MASK +/** The default page base mask for virtual addresses - 32bit version. */ +#define X86_PAGE_BASE_MASK_32 X86_PAGE_4K_BASE_MASK_32 + +/** The size of a 4KB page. */ +#define X86_PAGE_4K_SIZE _4K +/** The page shift of a 4KB page. */ +#define X86_PAGE_4K_SHIFT 12 +/** The 4KB page offset mask. */ +#define X86_PAGE_4K_OFFSET_MASK 0xfff +/** The 4KB page base mask for virtual addresses. */ +#define X86_PAGE_4K_BASE_MASK 0xfffffffffffff000ULL +/** The 4KB page base mask for virtual addresses - 32bit version. */ +#define X86_PAGE_4K_BASE_MASK_32 0xfffff000U + +/** The size of a 2MB page. */ +#define X86_PAGE_2M_SIZE _2M +/** The page shift of a 2MB page. */ +#define X86_PAGE_2M_SHIFT 21 +/** The 2MB page offset mask. */ +#define X86_PAGE_2M_OFFSET_MASK 0x001fffff +/** The 2MB page base mask for virtual addresses. */ +#define X86_PAGE_2M_BASE_MASK 0xffffffffffe00000ULL +/** The 2MB page base mask for virtual addresses - 32bit version. */ +#define X86_PAGE_2M_BASE_MASK_32 0xffe00000U + +/** The size of a 4MB page. */ +#define X86_PAGE_4M_SIZE _4M +/** The page shift of a 4MB page. */ +#define X86_PAGE_4M_SHIFT 22 +/** The 4MB page offset mask. */ +#define X86_PAGE_4M_OFFSET_MASK 0x003fffff +/** The 4MB page base mask for virtual addresses. */ +#define X86_PAGE_4M_BASE_MASK 0xffffffffffc00000ULL +/** The 4MB page base mask for virtual addresses - 32bit version. */ +#define X86_PAGE_4M_BASE_MASK_32 0xffc00000U + +/** The size of a 1GB page. */ +#define X86_PAGE_1G_SIZE _1G +/** The page shift of a 1GB page. */ +#define X86_PAGE_1G_SHIFT 30 +/** The 1GB page offset mask. */ +#define X86_PAGE_1G_OFFSET_MASK 0x3fffffff +/** The 1GB page base mask for virtual addresses. */ +#define X86_PAGE_1G_BASE_MASK UINT64_C(0xffffffffc0000000) + +/** + * Check if the given address is canonical. + */ +#define X86_IS_CANONICAL(a_u64Addr) ((uint64_t)(a_u64Addr) + UINT64_C(0x800000000000) < UINT64_C(0x1000000000000)) + +/** + * Gets the page base mask given the page shift. + */ +#define X86_GET_PAGE_BASE_MASK(a_cShift) (UINT64_C(0xffffffffffffffff) << (a_cShift)) + +/** + * Gets the page offset mask given the page shift. + */ +#define X86_GET_PAGE_OFFSET_MASK(a_cShift) (~X86_GET_PAGE_BASE_MASK(a_cShift)) + + +/** @name Page Table Entry + * @{ + */ +/** Bit 0 - P - Present bit. */ +#define X86_PTE_BIT_P 0 +/** Bit 1 - R/W - Read (clear) / Write (set) bit. */ +#define X86_PTE_BIT_RW 1 +/** Bit 2 - U/S - User (set) / Supervisor (clear) bit. */ +#define X86_PTE_BIT_US 2 +/** Bit 3 - PWT - Page level write thru bit. */ +#define X86_PTE_BIT_PWT 3 +/** Bit 4 - PCD - Page level cache disable bit. */ +#define X86_PTE_BIT_PCD 4 +/** Bit 5 - A - Access bit. */ +#define X86_PTE_BIT_A 5 +/** Bit 6 - D - Dirty bit. */ +#define X86_PTE_BIT_D 6 +/** Bit 7 - PAT - Page Attribute Table index bit. Reserved and 0 if not supported. */ +#define X86_PTE_BIT_PAT 7 +/** Bit 8 - G - Global flag. */ +#define X86_PTE_BIT_G 8 +/** Bits 63 - NX - PAE/LM - No execution flag. */ +#define X86_PTE_PAE_BIT_NX 63 + +/** Bit 0 - P - Present bit mask. */ +#define X86_PTE_P RT_BIT_32(0) +/** Bit 1 - R/W - Read (clear) / Write (set) bit mask. */ +#define X86_PTE_RW RT_BIT_32(1) +/** Bit 2 - U/S - User (set) / Supervisor (clear) bit mask. */ +#define X86_PTE_US RT_BIT_32(2) +/** Bit 3 - PWT - Page level write thru bit mask. */ +#define X86_PTE_PWT RT_BIT_32(3) +/** Bit 4 - PCD - Page level cache disable bit mask. */ +#define X86_PTE_PCD RT_BIT_32(4) +/** Bit 5 - A - Access bit mask. */ +#define X86_PTE_A RT_BIT_32(5) +/** Bit 6 - D - Dirty bit mask. */ +#define X86_PTE_D RT_BIT_32(6) +/** Bit 7 - PAT - Page Attribute Table index bit mask. Reserved and 0 if not supported. */ +#define X86_PTE_PAT RT_BIT_32(7) +/** Bit 8 - G - Global bit mask. */ +#define X86_PTE_G RT_BIT_32(8) + +/** Bits 9-11 - - Available for use to system software. */ +#define X86_PTE_AVL_MASK (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +/** Bits 12-31 - - Physical Page number of the next level. */ +#define X86_PTE_PG_MASK ( 0xfffff000 ) + +/** Bits 12-51 - - PAE - Physical Page number of the next level. */ +#define X86_PTE_PAE_PG_MASK UINT64_C(0x000ffffffffff000) +/** Bits 63 - NX - PAE/LM - No execution flag. */ +#define X86_PTE_PAE_NX RT_BIT_64(63) +/** Bits 62-52 - - PAE - MBZ bits when NX is active. */ +#define X86_PTE_PAE_MBZ_MASK_NX UINT64_C(0x7ff0000000000000) +/** Bits 63-52 - - PAE - MBZ bits when no NX. */ +#define X86_PTE_PAE_MBZ_MASK_NO_NX UINT64_C(0xfff0000000000000) +/** No bits - - LM - MBZ bits when NX is active. */ +#define X86_PTE_LM_MBZ_MASK_NX UINT64_C(0x0000000000000000) +/** Bits 63 - - LM - MBZ bits when no NX. */ +#define X86_PTE_LM_MBZ_MASK_NO_NX UINT64_C(0x8000000000000000) + +/** + * Page table entry. + */ +typedef struct X86PTEBITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** User(=1) / Supervisor (=0) flag. */ + uint32_t u1User : 1; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Accessed flag. + * Indicates that the page have been read or written to. */ + uint32_t u1Accessed : 1; + /** Dirty flag. + * Indicates that the page has been written to. */ + uint32_t u1Dirty : 1; + /** Reserved / If PAT enabled, bit 2 of the index. */ + uint32_t u1PAT : 1; + /** Global flag. (Ignored in all but final level.) */ + uint32_t u1Global : 1; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Physical Page number of the next level. */ + uint32_t u20PageNo : 20; +} X86PTEBITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PTEBITS, 4); +#endif +/** Pointer to a page table entry. */ +typedef X86PTEBITS *PX86PTEBITS; +/** Pointer to a const page table entry. */ +typedef const X86PTEBITS *PCX86PTEBITS; + +/** + * Page table entry. + */ +typedef union X86PTE +{ + /** Unsigned integer view */ + X86PGUINT u; +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Bit field view. */ + X86PTEBITS n; +#endif + /** 32-bit view. */ + uint32_t au32[1]; + /** 16-bit view. */ + uint16_t au16[2]; + /** 8-bit view. */ + uint8_t au8[4]; +} X86PTE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PTE, 4); +#endif +/** Pointer to a page table entry. */ +typedef X86PTE *PX86PTE; +/** Pointer to a const page table entry. */ +typedef const X86PTE *PCX86PTE; + + +/** + * PAE page table entry. + */ +typedef struct X86PTEPAEBITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** User(=1) / Supervisor(=0) flag. */ + uint32_t u1User : 1; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Accessed flag. + * Indicates that the page have been read or written to. */ + uint32_t u1Accessed : 1; + /** Dirty flag. + * Indicates that the page has been written to. */ + uint32_t u1Dirty : 1; + /** Reserved / If PAT enabled, bit 2 of the index. */ + uint32_t u1PAT : 1; + /** Global flag. (Ignored in all but final level.) */ + uint32_t u1Global : 1; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Physical Page number of the next level - Low Part. Don't use this. */ + uint32_t u20PageNoLow : 20; + /** Physical Page number of the next level - High Part. Don't use this. */ + uint32_t u20PageNoHigh : 20; + /** MBZ bits */ + uint32_t u11Reserved : 11; + /** No Execute flag. */ + uint32_t u1NoExecute : 1; +} X86PTEPAEBITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PTEPAEBITS, 8); +#endif +/** Pointer to a page table entry. */ +typedef X86PTEPAEBITS *PX86PTEPAEBITS; +/** Pointer to a page table entry. */ +typedef const X86PTEPAEBITS *PCX86PTEPAEBITS; + +/** + * PAE Page table entry. + */ +typedef union X86PTEPAE +{ + /** Unsigned integer view */ + X86PGPAEUINT u; +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Bit field view. */ + X86PTEPAEBITS n; +#endif + /** 32-bit view. */ + uint32_t au32[2]; + /** 16-bit view. */ + uint16_t au16[4]; + /** 8-bit view. */ + uint8_t au8[8]; +} X86PTEPAE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PTEPAE, 8); +#endif +/** Pointer to a PAE page table entry. */ +typedef X86PTEPAE *PX86PTEPAE; +/** Pointer to a const PAE page table entry. */ +typedef const X86PTEPAE *PCX86PTEPAE; +/** @} */ + +/** + * Page table. + */ +typedef struct X86PT +{ + /** PTE Array. */ + X86PTE a[X86_PG_ENTRIES]; +} X86PT; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PT, 4096); +#endif +/** Pointer to a page table. */ +typedef X86PT *PX86PT; +/** Pointer to a const page table. */ +typedef const X86PT *PCX86PT; + +/** The page shift to get the PT index. */ +#define X86_PT_SHIFT 12 +/** The PT index mask (apply to a shifted page address). */ +#define X86_PT_MASK 0x3ff + + +/** + * Page directory. + */ +typedef struct X86PTPAE +{ + /** PTE Array. */ + X86PTEPAE a[X86_PG_PAE_ENTRIES]; +} X86PTPAE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PTPAE, 4096); +#endif +/** Pointer to a page table. */ +typedef X86PTPAE *PX86PTPAE; +/** Pointer to a const page table. */ +typedef const X86PTPAE *PCX86PTPAE; + +/** The page shift to get the PA PTE index. */ +#define X86_PT_PAE_SHIFT 12 +/** The PAE PT index mask (apply to a shifted page address). */ +#define X86_PT_PAE_MASK 0x1ff + + +/** @name 4KB Page Directory Entry + * @{ + */ +/** Bit 0 - P - Present bit. */ +#define X86_PDE_P RT_BIT_32(0) +/** Bit 1 - R/W - Read (clear) / Write (set) bit. */ +#define X86_PDE_RW RT_BIT_32(1) +/** Bit 2 - U/S - User (set) / Supervisor (clear) bit. */ +#define X86_PDE_US RT_BIT_32(2) +/** Bit 3 - PWT - Page level write thru bit. */ +#define X86_PDE_PWT RT_BIT_32(3) +/** Bit 4 - PCD - Page level cache disable bit. */ +#define X86_PDE_PCD RT_BIT_32(4) +/** Bit 5 - A - Access bit. */ +#define X86_PDE_A RT_BIT_32(5) +/** Bit 7 - PS - Page size attribute. + * Clear mean 4KB pages, set means large pages (2/4MB). */ +#define X86_PDE_PS RT_BIT_32(7) +/** Bits 9-11 - - Available for use to system software. */ +#define X86_PDE_AVL_MASK (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +/** Bits 12-31 - - Physical Page number of the next level. */ +#define X86_PDE_PG_MASK ( 0xfffff000 ) + +/** Bits 12-51 - - PAE - Physical Page number of the next level. */ +#define X86_PDE_PAE_PG_MASK UINT64_C(0x000ffffffffff000) +/** Bits 63 - NX - PAE/LM - No execution flag. */ +#define X86_PDE_PAE_NX RT_BIT_64(63) +/** Bits 62-52, 7 - - PAE - MBZ bits when NX is active. */ +#define X86_PDE_PAE_MBZ_MASK_NX UINT64_C(0x7ff0000000000080) +/** Bits 63-52, 7 - - PAE - MBZ bits when no NX. */ +#define X86_PDE_PAE_MBZ_MASK_NO_NX UINT64_C(0xfff0000000000080) +/** Bit 7 - - LM - MBZ bits when NX is active. */ +#define X86_PDE_LM_MBZ_MASK_NX UINT64_C(0x0000000000000080) +/** Bits 63, 7 - - LM - MBZ bits when no NX. */ +#define X86_PDE_LM_MBZ_MASK_NO_NX UINT64_C(0x8000000000000080) + +/** + * Page directory entry. + */ +typedef struct X86PDEBITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** User(=1) / Supervisor (=0) flag. */ + uint32_t u1User : 1; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Accessed flag. + * Indicates that the page has been read or written to. */ + uint32_t u1Accessed : 1; + /** Reserved / Ignored (dirty bit). */ + uint32_t u1Reserved0 : 1; + /** Size bit if PSE is enabled - in any event it's 0. */ + uint32_t u1Size : 1; + /** Reserved / Ignored (global bit). */ + uint32_t u1Reserved1 : 1; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Physical Page number of the next level. */ + uint32_t u20PageNo : 20; +} X86PDEBITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDEBITS, 4); +#endif +/** Pointer to a page directory entry. */ +typedef X86PDEBITS *PX86PDEBITS; +/** Pointer to a const page directory entry. */ +typedef const X86PDEBITS *PCX86PDEBITS; + + +/** + * PAE page directory entry. + */ +typedef struct X86PDEPAEBITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** User(=1) / Supervisor (=0) flag. */ + uint32_t u1User : 1; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Accessed flag. + * Indicates that the page has been read or written to. */ + uint32_t u1Accessed : 1; + /** Reserved / Ignored (dirty bit). */ + uint32_t u1Reserved0 : 1; + /** Size bit if PSE is enabled - in any event it's 0. */ + uint32_t u1Size : 1; + /** Reserved / Ignored (global bit). / */ + uint32_t u1Reserved1 : 1; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Physical Page number of the next level - Low Part. Don't use! */ + uint32_t u20PageNoLow : 20; + /** Physical Page number of the next level - High Part. Don't use! */ + uint32_t u20PageNoHigh : 20; + /** MBZ bits */ + uint32_t u11Reserved : 11; + /** No Execute flag. */ + uint32_t u1NoExecute : 1; +} X86PDEPAEBITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDEPAEBITS, 8); +#endif +/** Pointer to a page directory entry. */ +typedef X86PDEPAEBITS *PX86PDEPAEBITS; +/** Pointer to a const page directory entry. */ +typedef const X86PDEPAEBITS *PCX86PDEPAEBITS; + +/** @} */ + + +/** @name 2/4MB Page Directory Entry + * @{ + */ +/** Bit 0 - P - Present bit. */ +#define X86_PDE4M_P RT_BIT_32(0) +/** Bit 1 - R/W - Read (clear) / Write (set) bit. */ +#define X86_PDE4M_RW RT_BIT_32(1) +/** Bit 2 - U/S - User (set) / Supervisor (clear) bit. */ +#define X86_PDE4M_US RT_BIT_32(2) +/** Bit 3 - PWT - Page level write thru bit. */ +#define X86_PDE4M_PWT RT_BIT_32(3) +/** Bit 4 - PCD - Page level cache disable bit. */ +#define X86_PDE4M_PCD RT_BIT_32(4) +/** Bit 5 - A - Access bit. */ +#define X86_PDE4M_A RT_BIT_32(5) +/** Bit 6 - D - Dirty bit. */ +#define X86_PDE4M_D RT_BIT_32(6) +/** Bit 7 - PS - Page size attribute. Clear mean 4KB pages, set means large pages (2/4MB). */ +#define X86_PDE4M_PS RT_BIT_32(7) +/** Bit 8 - G - Global flag. */ +#define X86_PDE4M_G RT_BIT_32(8) +/** Bits 9-11 - AVL - Available for use to system software. */ +#define X86_PDE4M_AVL (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +/** Bit 12 - PAT - Page Attribute Table index bit. Reserved and 0 if not supported. */ +#define X86_PDE4M_PAT RT_BIT_32(12) +/** Shift to get from X86_PTE_PAT to X86_PDE4M_PAT. */ +#define X86_PDE4M_PAT_SHIFT (12 - 7) +/** Bits 22-31 - - Physical Page number. */ +#define X86_PDE4M_PG_MASK ( 0xffc00000 ) +/** Bits 20-13 - - Physical Page number high part (32-39 bits). AMD64 hack. */ +#define X86_PDE4M_PG_HIGH_MASK ( 0x001fe000 ) +/** The number of bits to the high part of the page number. */ +#define X86_PDE4M_PG_HIGH_SHIFT 19 +/** Bit 21 - - MBZ bits for AMD CPUs, no PSE36. */ +#define X86_PDE4M_MBZ_MASK RT_BIT_32(21) + +/** Bits 21-51 - - PAE/LM - Physical Page number. + * (Bits 40-51 (long mode) & bits 36-51 (pae legacy) are reserved according to the Intel docs; AMD allows for more.) */ +#define X86_PDE2M_PAE_PG_MASK UINT64_C(0x000fffffffe00000) +/** Bits 63 - NX - PAE/LM - No execution flag. */ +#define X86_PDE2M_PAE_NX RT_BIT_64(63) +/** Bits 62-52, 20-13 - - PAE - MBZ bits when NX is active. */ +#define X86_PDE2M_PAE_MBZ_MASK_NX UINT64_C(0x7ff00000001fe000) +/** Bits 63-52, 20-13 - - PAE - MBZ bits when no NX. */ +#define X86_PDE2M_PAE_MBZ_MASK_NO_NX UINT64_C(0xfff00000001fe000) +/** Bits 20-13 - - LM - MBZ bits when NX is active. */ +#define X86_PDE2M_LM_MBZ_MASK_NX UINT64_C(0x00000000001fe000) +/** Bits 63, 20-13 - - LM - MBZ bits when no NX. */ +#define X86_PDE2M_LM_MBZ_MASK_NO_NX UINT64_C(0x80000000001fe000) + +/** + * 4MB page directory entry. + */ +typedef struct X86PDE4MBITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** User(=1) / Supervisor (=0) flag. */ + uint32_t u1User : 1; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Accessed flag. + * Indicates that the page have been read or written to. */ + uint32_t u1Accessed : 1; + /** Dirty flag. + * Indicates that the page has been written to. */ + uint32_t u1Dirty : 1; + /** Page size flag - always 1 for 4MB entries. */ + uint32_t u1Size : 1; + /** Global flag. */ + uint32_t u1Global : 1; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Reserved / If PAT enabled, bit 2 of the index. */ + uint32_t u1PAT : 1; + /** Bits 32-39 of the page number on AMD64. + * This AMD64 hack allows accessing 40bits of physical memory without PAE. */ + uint32_t u8PageNoHigh : 8; + /** Reserved. */ + uint32_t u1Reserved : 1; + /** Physical Page number of the page. */ + uint32_t u10PageNo : 10; +} X86PDE4MBITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDE4MBITS, 4); +#endif +/** Pointer to a page table entry. */ +typedef X86PDE4MBITS *PX86PDE4MBITS; +/** Pointer to a const page table entry. */ +typedef const X86PDE4MBITS *PCX86PDE4MBITS; + + +/** + * 2MB PAE page directory entry. + */ +typedef struct X86PDE2MPAEBITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** User(=1) / Supervisor(=0) flag. */ + uint32_t u1User : 1; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Accessed flag. + * Indicates that the page have been read or written to. */ + uint32_t u1Accessed : 1; + /** Dirty flag. + * Indicates that the page has been written to. */ + uint32_t u1Dirty : 1; + /** Page size flag - always 1 for 2MB entries. */ + uint32_t u1Size : 1; + /** Global flag. */ + uint32_t u1Global : 1; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Reserved / If PAT enabled, bit 2 of the index. */ + uint32_t u1PAT : 1; + /** Reserved. */ + uint32_t u9Reserved : 9; + /** Physical Page number of the next level - Low part. Don't use! */ + uint32_t u10PageNoLow : 10; + /** Physical Page number of the next level - High part. Don't use! */ + uint32_t u20PageNoHigh : 20; + /** MBZ bits */ + uint32_t u11Reserved : 11; + /** No Execute flag. */ + uint32_t u1NoExecute : 1; +} X86PDE2MPAEBITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDE2MPAEBITS, 8); +#endif +/** Pointer to a 2MB PAE page table entry. */ +typedef X86PDE2MPAEBITS *PX86PDE2MPAEBITS; +/** Pointer to a 2MB PAE page table entry. */ +typedef const X86PDE2MPAEBITS *PCX86PDE2MPAEBITS; + +/** @} */ + +/** + * Page directory entry. + */ +typedef union X86PDE +{ + /** Unsigned integer view. */ + X86PGUINT u; +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + X86PDEBITS n; + /** 4MB view (big). */ + X86PDE4MBITS b; +#endif + /** 8 bit unsigned integer view. */ + uint8_t au8[4]; + /** 16 bit unsigned integer view. */ + uint16_t au16[2]; + /** 32 bit unsigned integer view. */ + uint32_t au32[1]; +} X86PDE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDE, 4); +#endif +/** Pointer to a page directory entry. */ +typedef X86PDE *PX86PDE; +/** Pointer to a const page directory entry. */ +typedef const X86PDE *PCX86PDE; + +/** + * PAE page directory entry. + */ +typedef union X86PDEPAE +{ + /** Unsigned integer view. */ + X86PGPAEUINT u; +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + X86PDEPAEBITS n; + /** 2MB page view (big). */ + X86PDE2MPAEBITS b; +#endif + /** 8 bit unsigned integer view. */ + uint8_t au8[8]; + /** 16 bit unsigned integer view. */ + uint16_t au16[4]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} X86PDEPAE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDEPAE, 8); +#endif +/** Pointer to a page directory entry. */ +typedef X86PDEPAE *PX86PDEPAE; +/** Pointer to a const page directory entry. */ +typedef const X86PDEPAE *PCX86PDEPAE; + +/** + * Page directory. + */ +typedef struct X86PD +{ + /** PDE Array. */ + X86PDE a[X86_PG_ENTRIES]; +} X86PD; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PD, 4096); +#endif +/** Pointer to a page directory. */ +typedef X86PD *PX86PD; +/** Pointer to a const page directory. */ +typedef const X86PD *PCX86PD; + +/** The page shift to get the PD index. */ +#define X86_PD_SHIFT 22 +/** The PD index mask (apply to a shifted page address). */ +#define X86_PD_MASK 0x3ff + + +/** + * PAE page directory. + */ +typedef struct X86PDPAE +{ + /** PDE Array. */ + X86PDEPAE a[X86_PG_PAE_ENTRIES]; +} X86PDPAE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDPAE, 4096); +#endif +/** Pointer to a PAE page directory. */ +typedef X86PDPAE *PX86PDPAE; +/** Pointer to a const PAE page directory. */ +typedef const X86PDPAE *PCX86PDPAE; + +/** The page shift to get the PAE PD index. */ +#define X86_PD_PAE_SHIFT 21 +/** The PAE PD index mask (apply to a shifted page address). */ +#define X86_PD_PAE_MASK 0x1ff + + +/** @name Page Directory Pointer Table Entry (PAE) + * @{ + */ +/** Bit 0 - P - Present bit. */ +#define X86_PDPE_P RT_BIT_32(0) +/** Bit 1 - R/W - Read (clear) / Write (set) bit. Long Mode only. */ +#define X86_PDPE_RW RT_BIT_32(1) +/** Bit 2 - U/S - User (set) / Supervisor (clear) bit. Long Mode only. */ +#define X86_PDPE_US RT_BIT_32(2) +/** Bit 3 - PWT - Page level write thru bit. */ +#define X86_PDPE_PWT RT_BIT_32(3) +/** Bit 4 - PCD - Page level cache disable bit. */ +#define X86_PDPE_PCD RT_BIT_32(4) +/** Bit 5 - A - Access bit. Long Mode only. */ +#define X86_PDPE_A RT_BIT_32(5) +/** Bit 7 - PS - Page size (1GB). Long Mode only. */ +#define X86_PDPE_LM_PS RT_BIT_32(7) +/** Bits 9-11 - - Available for use to system software. */ +#define X86_PDPE_AVL_MASK (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +/** Bits 12-51 - - PAE - Physical Page number of the next level. */ +#define X86_PDPE_PG_MASK UINT64_C(0x000ffffffffff000) +/** Bits 30-51 - - PG - Physical address of the 1GB page referenced by this entry. */ +#define X86_PDPE1G_PG_MASK UINT64_C(0x000fffffc0000000) +/** Bits 63-52, 8-5, 2-1 - - PAE - MBZ bits (NX is long mode only). */ +#define X86_PDPE_PAE_MBZ_MASK UINT64_C(0xfff00000000001e6) +/** Bits 63 - NX - LM - No execution flag. Long Mode only. */ +#define X86_PDPE_LM_NX RT_BIT_64(63) +/** Bits 8, 7 - - LM - MBZ bits when NX is active. */ +#define X86_PDPE_LM_MBZ_MASK_NX UINT64_C(0x0000000000000180) +/** Bits 63, 8, 7 - - LM - MBZ bits when no NX. */ +#define X86_PDPE_LM_MBZ_MASK_NO_NX UINT64_C(0x8000000000000180) +/** Bits 29-13 - - LM - MBZ bits for 1GB page entry when NX is active. */ +#define X86_PDPE1G_LM_MBZ_MASK_NX UINT64_C(0x000000003fffe000) +/** Bits 63, 29-13 - - LM - MBZ bits for 1GB page entry when no NX. */ +#define X86_PDPE1G_LM_MBZ_MASK_NO_NX UINT64_C(0x800000003fffe000) + + +/** + * Page directory pointer table entry. + */ +typedef struct X86PDPEBITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Chunk of reserved bits. */ + uint32_t u2Reserved : 2; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Chunk of reserved bits. */ + uint32_t u4Reserved : 4; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Physical Page number of the next level - Low Part. Don't use! */ + uint32_t u20PageNoLow : 20; + /** Physical Page number of the next level - High Part. Don't use! */ + uint32_t u20PageNoHigh : 20; + /** MBZ bits */ + uint32_t u12Reserved : 12; +} X86PDPEBITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDPEBITS, 8); +#endif +/** Pointer to a page directory pointer table entry. */ +typedef X86PDPEBITS *PX86PTPEBITS; +/** Pointer to a const page directory pointer table entry. */ +typedef const X86PDPEBITS *PCX86PTPEBITS; + +/** + * Page directory pointer table entry. AMD64 version + */ +typedef struct X86PDPEAMD64BITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** User(=1) / Supervisor (=0) flag. */ + uint32_t u1User : 1; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Accessed flag. + * Indicates that the page have been read or written to. */ + uint32_t u1Accessed : 1; + /** Chunk of reserved bits. */ + uint32_t u3Reserved : 3; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Physical Page number of the next level - Low Part. Don't use! */ + uint32_t u20PageNoLow : 20; + /** Physical Page number of the next level - High Part. Don't use! */ + uint32_t u20PageNoHigh : 20; + /** MBZ bits */ + uint32_t u11Reserved : 11; + /** No Execute flag. */ + uint32_t u1NoExecute : 1; +} X86PDPEAMD64BITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDPEAMD64BITS, 8); +#endif +/** Pointer to a page directory pointer table entry. */ +typedef X86PDPEAMD64BITS *PX86PDPEAMD64BITS; +/** Pointer to a const page directory pointer table entry. */ +typedef const X86PDPEAMD64BITS *PCX86PDPEAMD64BITS; + +/** + * Page directory pointer table entry for 1GB page. (AMD64 only) + */ +typedef struct X86PDPE1GB +{ + /** 0: Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** 1: Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** 2: User(=1) / Supervisor (=0) flag. */ + uint32_t u1User : 1; + /** 3: Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** 4: Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** 5: Accessed flag. + * Indicates that the page have been read or written to. */ + uint32_t u1Accessed : 1; + /** 6: Dirty flag for 1GB pages. */ + uint32_t u1Dirty : 1; + /** 7: Indicates 1GB page if set. */ + uint32_t u1Size : 1; + /** 8: Global 1GB page. */ + uint32_t u1Global: 1; + /** 9-11: Available for use to system software. */ + uint32_t u3Available : 3; + /** 12: PAT bit for 1GB page. */ + uint32_t u1PAT : 1; + /** 13-29: MBZ bits. */ + uint32_t u17Reserved : 17; + /** 30-31: Physical page number - Low Part. Don't use! */ + uint32_t u2PageNoLow : 2; + /** 32-51: Physical Page number of the next level - High Part. Don't use! */ + uint32_t u20PageNoHigh : 20; + /** 52-62: MBZ bits */ + uint32_t u11Reserved : 11; + /** 63: No Execute flag. */ + uint32_t u1NoExecute : 1; +} X86PDPE1GB; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDPE1GB, 8); +#endif +/** Pointer to a page directory pointer table entry for a 1GB page. */ +typedef X86PDPE1GB *PX86PDPE1GB; +/** Pointer to a const page directory pointer table entry for a 1GB page. */ +typedef const X86PDPE1GB *PCX86PDPE1GB; + +/** + * Page directory pointer table entry. + */ +typedef union X86PDPE +{ + /** Unsigned integer view. */ + X86PGPAEUINT u; +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + X86PDPEBITS n; + /** AMD64 view. */ + X86PDPEAMD64BITS lm; + /** AMD64 big view. */ + X86PDPE1GB b; +#endif + /** 8 bit unsigned integer view. */ + uint8_t au8[8]; + /** 16 bit unsigned integer view. */ + uint16_t au16[4]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} X86PDPE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDPE, 8); +#endif +/** Pointer to a page directory pointer table entry. */ +typedef X86PDPE *PX86PDPE; +/** Pointer to a const page directory pointer table entry. */ +typedef const X86PDPE *PCX86PDPE; + + +/** + * Page directory pointer table. + */ +typedef struct X86PDPT +{ + /** PDE Array. */ + X86PDPE a[X86_PG_AMD64_PDPE_ENTRIES]; +} X86PDPT; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PDPT, 4096); +#endif +/** Pointer to a page directory pointer table. */ +typedef X86PDPT *PX86PDPT; +/** Pointer to a const page directory pointer table. */ +typedef const X86PDPT *PCX86PDPT; + +/** The page shift to get the PDPT index. */ +#define X86_PDPT_SHIFT 30 +/** The PDPT index mask (apply to a shifted page address). (32 bits PAE) */ +#define X86_PDPT_MASK_PAE 0x3 +/** The PDPT index mask (apply to a shifted page address). (64 bits PAE)*/ +#define X86_PDPT_MASK_AMD64 0x1ff + +/** @} */ + + +/** @name Page Map Level-4 Entry (Long Mode PAE) + * @{ + */ +/** Bit 0 - P - Present bit. */ +#define X86_PML4E_P RT_BIT_32(0) +/** Bit 1 - R/W - Read (clear) / Write (set) bit. */ +#define X86_PML4E_RW RT_BIT_32(1) +/** Bit 2 - U/S - User (set) / Supervisor (clear) bit. */ +#define X86_PML4E_US RT_BIT_32(2) +/** Bit 3 - PWT - Page level write thru bit. */ +#define X86_PML4E_PWT RT_BIT_32(3) +/** Bit 4 - PCD - Page level cache disable bit. */ +#define X86_PML4E_PCD RT_BIT_32(4) +/** Bit 5 - A - Access bit. */ +#define X86_PML4E_A RT_BIT_32(5) +/** Bits 9-11 - - Available for use to system software. */ +#define X86_PML4E_AVL_MASK (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +/** Bits 12-51 - - PAE - Physical Page number of the next level. */ +#define X86_PML4E_PG_MASK UINT64_C(0x000ffffffffff000) +/** Bits 8, 7 - - MBZ bits when NX is active. */ +#define X86_PML4E_MBZ_MASK_NX UINT64_C(0x0000000000000080) +/** Bits 63, 7 - - MBZ bits when no NX. */ +#define X86_PML4E_MBZ_MASK_NO_NX UINT64_C(0x8000000000000080) +/** Bits 63 - NX - PAE - No execution flag. */ +#define X86_PML4E_NX RT_BIT_64(63) + +/** + * Page Map Level-4 Entry + */ +typedef struct X86PML4EBITS +{ + /** Flags whether(=1) or not the page is present. */ + uint32_t u1Present : 1; + /** Read(=0) / Write(=1) flag. */ + uint32_t u1Write : 1; + /** User(=1) / Supervisor (=0) flag. */ + uint32_t u1User : 1; + /** Write Thru flag. If PAT enabled, bit 0 of the index. */ + uint32_t u1WriteThru : 1; + /** Cache disabled flag. If PAT enabled, bit 1 of the index. */ + uint32_t u1CacheDisable : 1; + /** Accessed flag. + * Indicates that the page have been read or written to. */ + uint32_t u1Accessed : 1; + /** Chunk of reserved bits. */ + uint32_t u3Reserved : 3; + /** Available for use to system software. */ + uint32_t u3Available : 3; + /** Physical Page number of the next level - Low Part. Don't use! */ + uint32_t u20PageNoLow : 20; + /** Physical Page number of the next level - High Part. Don't use! */ + uint32_t u20PageNoHigh : 20; + /** MBZ bits */ + uint32_t u11Reserved : 11; + /** No Execute flag. */ + uint32_t u1NoExecute : 1; +} X86PML4EBITS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PML4EBITS, 8); +#endif +/** Pointer to a page map level-4 entry. */ +typedef X86PML4EBITS *PX86PML4EBITS; +/** Pointer to a const page map level-4 entry. */ +typedef const X86PML4EBITS *PCX86PML4EBITS; + +/** + * Page Map Level-4 Entry. + */ +typedef union X86PML4E +{ + /** Unsigned integer view. */ + X86PGPAEUINT u; +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + X86PML4EBITS n; +#endif + /** 8 bit unsigned integer view. */ + uint8_t au8[8]; + /** 16 bit unsigned integer view. */ + uint16_t au16[4]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} X86PML4E; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PML4E, 8); +#endif +/** Pointer to a page map level-4 entry. */ +typedef X86PML4E *PX86PML4E; +/** Pointer to a const page map level-4 entry. */ +typedef const X86PML4E *PCX86PML4E; + + +/** + * Page Map Level-4. + */ +typedef struct X86PML4 +{ + /** PDE Array. */ + X86PML4E a[X86_PG_PAE_ENTRIES]; +} X86PML4; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86PML4, 4096); +#endif +/** Pointer to a page map level-4. */ +typedef X86PML4 *PX86PML4; +/** Pointer to a const page map level-4. */ +typedef const X86PML4 *PCX86PML4; + +/** The page shift to get the PML4 index. */ +#define X86_PML4_SHIFT 39 +/** The PML4 index mask (apply to a shifted page address). */ +#define X86_PML4_MASK 0x1ff + +/** @} */ + +/** @} */ + +/** + * 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 + + +/** @name Special FPU integer values. + * @{ */ +#define X86_FPU_INT64_INDEFINITE INT64_MIN +#define X86_FPU_INT32_INDEFINITE INT32_MIN +#define X86_FPU_INT16_INDEFINITE INT16_MIN +/** @} */ + +/** + * 32-bit protected mode FSTENV image. + */ +typedef struct X86FSTENV32P +{ + uint16_t FCW; /**< 0x00 */ + uint16_t padding1; /**< 0x02 */ + uint16_t FSW; /**< 0x04 */ + uint16_t padding2; /**< 0x06 */ + uint16_t FTW; /**< 0x08 */ + uint16_t padding3; /**< 0x0a */ + uint32_t FPUIP; /**< 0x0c */ + uint16_t FPUCS; /**< 0x10 */ + uint16_t FOP; /**< 0x12 */ + uint32_t FPUDP; /**< 0x14 */ + uint16_t FPUDS; /**< 0x18 */ + uint16_t padding4; /**< 0x1a */ +} X86FSTENV32P; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86FSTENV32P, 0x1c); +#endif +/** Pointer to a 32-bit protected mode FSTENV image. */ +typedef X86FSTENV32P *PX86FSTENV32P; +/** Pointer to a const 32-bit protected mode FSTENV image. */ +typedef X86FSTENV32P const *PCX86FSTENV32P; + + +/** + * 80-bit MMX/FPU register type. + */ +typedef struct X86FPUMMX +{ + uint8_t reg[10]; +} X86FPUMMX; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86FPUMMX, 10); +#endif +/** Pointer to a 80-bit MMX/FPU register type. */ +typedef X86FPUMMX *PX86FPUMMX; +/** Pointer to a const 80-bit MMX/FPU register type. */ +typedef const X86FPUMMX *PCX86FPUMMX; + +/** FPU (x87) register. */ +typedef union X86FPUREG +{ + /** MMX view. */ + uint64_t mmx; + /** FPU view - todo. */ + X86FPUMMX fpu; + /** Extended precision floating point view. */ + RTFLOAT80U r80; + /** Extended precision floating point view v2 */ + RTFLOAT80U2 r80Ex; + /** 8-bit view. */ + uint8_t au8[16]; + /** 16-bit view. */ + uint16_t au16[8]; + /** 32-bit view. */ + uint32_t au32[4]; + /** 64-bit view. */ + uint64_t au64[2]; + /** 128-bit view. (yeah, very helpful) */ + uint128_t au128[1]; +} X86FPUREG; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86FPUREG, 16); +#endif +/** Pointer to a FPU register. */ +typedef X86FPUREG *PX86FPUREG; +/** Pointer to a const FPU register. */ +typedef X86FPUREG const *PCX86FPUREG; + +/** FPU (x87) register - v2 with correct size. */ +#pragma pack(1) +typedef union X86FPUREG2 +{ + /** MMX view. */ + uint64_t mmx; + /** FPU view - todo. */ + X86FPUMMX fpu; + /** Extended precision floating point view. */ + RTFLOAT80U r80; + /** 8-bit view. */ + uint8_t au8[10]; + /** 16-bit view. */ + uint16_t au16[5]; + /** 32-bit view. */ + uint32_t au32[2]; + /** 64-bit view. */ + uint64_t au64[1]; +} X86FPUREG2; +#pragma pack() +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86FPUREG2, 10); +#endif +/** Pointer to a FPU register - v2. */ +typedef X86FPUREG2 *PX86FPUREG2; +/** Pointer to a const FPU register - v2. */ +typedef X86FPUREG2 const *PCX86FPUREG2; + +/** + * XMM register union. + */ +typedef union X86XMMREG +{ + /** XMM Register view. */ + uint128_t xmm; + /** 8-bit view. */ + uint8_t au8[16]; + /** 16-bit view. */ + uint16_t au16[8]; + /** 32-bit view. */ + uint32_t au32[4]; + /** 64-bit view. */ + uint64_t au64[2]; + /** Signed 8-bit view. */ + int8_t ai8[16]; + /** Signed 16-bit view. */ + int16_t ai16[8]; + /** Signed 32-bit view. */ + int32_t ai32[4]; + /** Signed 64-bit view. */ + int64_t ai64[2]; + /** 128-bit view. (yeah, very helpful) */ + uint128_t au128[1]; + /** Single precision floating point view. */ + RTFLOAT32U ar32[4]; + /** Double precision floating point view. */ + RTFLOAT64U ar64[2]; +#ifndef VBOX_FOR_DTRACE_LIB + /** Confusing nested 128-bit union view (this is what xmm should've been). */ + RTUINT128U uXmm; +#endif +} X86XMMREG; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XMMREG, 16); +#endif +/** Pointer to an XMM register state. */ +typedef X86XMMREG *PX86XMMREG; +/** Pointer to a const XMM register state. */ +typedef X86XMMREG const *PCX86XMMREG; + +/** + * YMM register union. + */ +typedef union X86YMMREG +{ + /** YMM register view. */ + RTUINT256U ymm; + /** 8-bit view. */ + uint8_t au8[32]; + /** 16-bit view. */ + uint16_t au16[16]; + /** 32-bit view. */ + uint32_t au32[8]; + /** 64-bit view. */ + uint64_t au64[4]; + /** 128-bit view. (yeah, very helpful) */ + uint128_t au128[2]; + /** Single precision floating point view. */ + RTFLOAT32U ar32[8]; + /** Double precision floating point view. */ + RTFLOAT64U ar64[4]; + /** XMM sub register view. */ + X86XMMREG aXmm[2]; +} X86YMMREG; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86YMMREG, 32); +#endif +/** Pointer to an YMM register state. */ +typedef X86YMMREG *PX86YMMREG; +/** Pointer to a const YMM register state. */ +typedef X86YMMREG const *PCX86YMMREG; + +/** + * ZMM register union. + */ +typedef union X86ZMMREG +{ + /** 8-bit view. */ + uint8_t au8[64]; + /** 16-bit view. */ + uint16_t au16[32]; + /** 32-bit view. */ + uint32_t au32[16]; + /** 64-bit view. */ + uint64_t au64[8]; + /** 128-bit view. (yeah, very helpful) */ + uint128_t au128[4]; + /** Single precision floating point view. */ + RTFLOAT32U ar32[16]; + /** Double precision floating point view. */ + RTFLOAT64U ar64[8]; + /** XMM sub register view. */ + X86XMMREG aXmm[4]; + /** YMM sub register view. */ + X86YMMREG aYmm[2]; +} X86ZMMREG; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86ZMMREG, 64); +#endif +/** Pointer to an ZMM register state. */ +typedef X86ZMMREG *PX86ZMMREG; +/** Pointer to a const ZMM register state. */ +typedef X86ZMMREG const *PCX86ZMMREG; + + +/** + * 32-bit FPU state (aka FSAVE/FRSTOR Memory Region). + */ +#pragma pack(1) +typedef struct X86FPUSTATE +{ + /** 0x00 - Control word. */ + uint16_t FCW; + /** 0x02 - Alignment word */ + uint16_t Dummy1; + /** 0x04 - Status word. */ + uint16_t FSW; + /** 0x06 - Alignment word */ + uint16_t Dummy2; + /** 0x08 - Tag word */ + uint16_t FTW; + /** 0x0a - Alignment word */ + uint16_t Dummy3; + + /** 0x0c - Instruction pointer. */ + uint32_t FPUIP; + /** 0x10 - Code selector. */ + uint16_t CS; + /** 0x12 - Opcode. */ + uint16_t FOP; + /** 0x14 - Data pointer. */ + uint32_t FPUOO; + /** 0x18 - FOS. */ + uint16_t FPUOS; + /** 0x0a - Alignment word */ + uint16_t Dummy4; + /** 0x1c - FPU register. */ + X86FPUREG2 regs[8]; +} X86FPUSTATE; +#pragma pack() +AssertCompileSize(X86FPUSTATE, 108); +/** Pointer to a FPU state. */ +typedef X86FPUSTATE *PX86FPUSTATE; +/** Pointer to a const FPU state. */ +typedef const X86FPUSTATE *PCX86FPUSTATE; + +/** + * FPU Extended state (aka FXSAVE/FXRSTORE Memory Region). + */ +#pragma pack(1) +typedef struct X86FXSTATE +{ + /** 0x00 - Control word. */ + uint16_t FCW; + /** 0x02 - Status word. */ + uint16_t FSW; + /** 0x04 - Tag word. (The upper byte is always zero.) */ + uint16_t FTW; + /** 0x06 - Opcode. */ + uint16_t FOP; + /** 0x08 - Instruction pointer. */ + uint32_t FPUIP; + /** 0x0c - Code selector. */ + uint16_t CS; + uint16_t Rsrvd1; + /** 0x10 - Data pointer. */ + uint32_t FPUDP; + /** 0x14 - Data segment */ + uint16_t DS; + /** 0x16 */ + uint16_t Rsrvd2; + /** 0x18 */ + uint32_t MXCSR; + /** 0x1c */ + uint32_t MXCSR_MASK; + /** 0x20 - FPU registers. */ + X86FPUREG aRegs[8]; + /** 0xA0 - XMM registers - 8 registers in 32 bits mode, 16 in long mode. */ + X86XMMREG aXMM[16]; + /* - offset 416 - */ + uint32_t au32RsrvdRest[(464 - 416) / sizeof(uint32_t)]; + /* - offset 464 - Software usable reserved bits. */ + uint32_t au32RsrvdForSoftware[(512 - 464) / sizeof(uint32_t)]; +} X86FXSTATE; +#pragma pack() +/** Pointer to a FPU Extended state. */ +typedef X86FXSTATE *PX86FXSTATE; +/** Pointer to a const FPU Extended state. */ +typedef const X86FXSTATE *PCX86FXSTATE; + +/** Offset for software usable reserved bits (464:511) where we store a 32-bit + * magic. Don't forget to update x86.mac if you change this! */ +#define X86_OFF_FXSTATE_RSVD 0x1d0 +/** The 32-bit magic used to recognize if this a 32-bit FPU state. Don't + * forget to update x86.mac if you change this! + * @todo r=bird: This has nothing what-so-ever to do here.... */ +#define X86_FXSTATE_RSVD_32BIT_MAGIC 0x32b3232b +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86FXSTATE, 512); +AssertCompileMemberOffset(X86FXSTATE, au32RsrvdForSoftware, X86_OFF_FXSTATE_RSVD); +#endif + +/** @name FPU status word flags. + * @{ */ +/** Exception Flag: Invalid operation. */ +#define X86_FSW_IE RT_BIT_32(0) +#define X86_FSW_IE_BIT 0 +/** Exception Flag: Denormalized operand. */ +#define X86_FSW_DE RT_BIT_32(1) +#define X86_FSW_DE_BIT 1 +/** Exception Flag: Zero divide. */ +#define X86_FSW_ZE RT_BIT_32(2) +#define X86_FSW_ZE_BIT 2 +/** Exception Flag: Overflow. */ +#define X86_FSW_OE RT_BIT_32(3) +#define X86_FSW_OE_BIT 3 +/** Exception Flag: Underflow. */ +#define X86_FSW_UE RT_BIT_32(4) +#define X86_FSW_UE_BIT 4 +/** Exception Flag: Precision. */ +#define X86_FSW_PE RT_BIT_32(5) +#define X86_FSW_PE_BIT 5 +/** Stack fault. */ +#define X86_FSW_SF RT_BIT_32(6) +#define X86_FSW_SF_BIT 6 +/** Error summary status. */ +#define X86_FSW_ES RT_BIT_32(7) +#define X86_FSW_ES_BIT 7 +/** Mask of exceptions flags, excluding the summary bit. */ +#define X86_FSW_XCPT_MASK UINT16_C(0x007f) +/** Mask of exceptions flags, including the summary bit. */ +#define X86_FSW_XCPT_ES_MASK UINT16_C(0x00ff) +/** Condition code 0. */ +#define X86_FSW_C0 RT_BIT_32(X86_FSW_C0_BIT) +#define X86_FSW_C0_BIT 8 +/** Condition code 1. */ +#define X86_FSW_C1 RT_BIT_32(X86_FSW_C1_BIT) +#define X86_FSW_C1_BIT 9 +/** Condition code 2. */ +#define X86_FSW_C2 RT_BIT_32(X86_FSW_C2_BIT) +#define X86_FSW_C2_BIT 10 +/** Top of the stack mask. */ +#define X86_FSW_TOP_MASK UINT16_C(0x3800) +/** TOP shift value. */ +#define X86_FSW_TOP_SHIFT 11 +/** Mask for getting TOP value after shifting it right. */ +#define X86_FSW_TOP_SMASK UINT16_C(0x0007) +/** Get the TOP value. */ +#define X86_FSW_TOP_GET(a_uFsw) (((a_uFsw) >> X86_FSW_TOP_SHIFT) & X86_FSW_TOP_SMASK) +/** Get the TOP value offsetted by a_iSt (0-7). */ +#define X86_FSW_TOP_GET_ST(a_uFsw, a_iSt) ((((a_uFsw) >> X86_FSW_TOP_SHIFT) + (a_iSt)) & X86_FSW_TOP_SMASK) +/** Condition code 3. */ +#define X86_FSW_C3 RT_BIT_32(X86_FSW_C3_BIT) +#define X86_FSW_C3_BIT 14 +/** Mask of exceptions flags, including the summary bit. */ +#define X86_FSW_C_MASK UINT16_C(0x4700) +/** FPU busy. */ +#define X86_FSW_B RT_BIT_32(15) +/** For use with FPREM and FPREM1. */ +#define X86_FSW_CX_TO_QUOTIENT(a_fFsw) \ + ( (((a_fFsw) & X86_FSW_C1) >> (X86_FSW_C1_BIT - 0)) \ + | (((a_fFsw) & X86_FSW_C3) >> (X86_FSW_C3_BIT - 1)) \ + | (((a_fFsw) & X86_FSW_C0) >> (X86_FSW_C0_BIT - 2)) ) +/** For use with FPREM and FPREM1. */ +#define X86_FSW_CX_FROM_QUOTIENT(a_uQuotient) \ + ( ((uint16_t)((a_uQuotient) & 1) << (X86_FSW_C1_BIT - 0)) \ + | ((uint16_t)((a_uQuotient) & 2) << (X86_FSW_C3_BIT - 1)) \ + | ((uint16_t)((a_uQuotient) & 4) << (X86_FSW_C0_BIT - 2)) ) +/** @} */ + + +/** @name FPU control word flags. + * @{ */ +/** Exception Mask: Invalid operation. */ +#define X86_FCW_IM RT_BIT_32(0) +#define X86_FCW_IM_BIT 0 +/** Exception Mask: Denormalized operand. */ +#define X86_FCW_DM RT_BIT_32(1) +#define X86_FCW_DM_BIT 1 +/** Exception Mask: Zero divide. */ +#define X86_FCW_ZM RT_BIT_32(2) +#define X86_FCW_ZM_BIT 2 +/** Exception Mask: Overflow. */ +#define X86_FCW_OM RT_BIT_32(3) +#define X86_FCW_OM_BIT 3 +/** Exception Mask: Underflow. */ +#define X86_FCW_UM RT_BIT_32(4) +#define X86_FCW_UM_BIT 4 +/** Exception Mask: Precision. */ +#define X86_FCW_PM RT_BIT_32(5) +#define X86_FCW_PM_BIT 5 +/** Mask all exceptions, the value typically loaded (by for instance fninit). + * @remarks This includes reserved bit 6. */ +#define X86_FCW_MASK_ALL UINT16_C(0x007f) +/** Mask all exceptions. Same as X86_FSW_XCPT_MASK. */ +#define X86_FCW_XCPT_MASK UINT16_C(0x003f) +/** Precision control mask. */ +#define X86_FCW_PC_MASK UINT16_C(0x0300) +/** Precision control shift. */ +#define X86_FCW_PC_SHIFT 8 +/** Precision control: 24-bit. */ +#define X86_FCW_PC_24 UINT16_C(0x0000) +/** Precision control: Reserved. */ +#define X86_FCW_PC_RSVD UINT16_C(0x0100) +/** Precision control: 53-bit. */ +#define X86_FCW_PC_53 UINT16_C(0x0200) +/** Precision control: 64-bit. */ +#define X86_FCW_PC_64 UINT16_C(0x0300) +/** Rounding control mask. */ +#define X86_FCW_RC_MASK UINT16_C(0x0c00) +/** Rounding control shift. */ +#define X86_FCW_RC_SHIFT 10 +/** Rounding control: To nearest. */ +#define X86_FCW_RC_NEAREST UINT16_C(0x0000) +/** Rounding control: Down. */ +#define X86_FCW_RC_DOWN UINT16_C(0x0400) +/** Rounding control: Up. */ +#define X86_FCW_RC_UP UINT16_C(0x0800) +/** Rounding control: Towards zero. */ +#define X86_FCW_RC_ZERO UINT16_C(0x0c00) +/** Infinity control mask - obsolete, 8087 & 287 only. */ +#define X86_FCW_IC_MASK UINT16_C(0x1000) +/** Infinity control: Affine - positive infinity is distictly different from + * negative infinity. + * @note 8087, 287 only */ +#define X86_FCW_IC_AFFINE UINT16_C(0x1000) +/** Infinity control: Projective - positive and negative infinity are the + * same (sign ignored). + * @note 8087, 287 only */ +#define X86_FCW_IC_PROJECTIVE UINT16_C(0x0000) +/** Bits which should be zero, apparently. */ +#define X86_FCW_ZERO_MASK UINT16_C(0xf080) +/** @} */ + +/** @name SSE MXCSR + * @{ */ +/** Exception Flag: Invalid operation. */ +#define X86_MXCSR_IE RT_BIT_32(0) +/** Exception Flag: Denormalized operand. */ +#define X86_MXCSR_DE RT_BIT_32(1) +/** Exception Flag: Zero divide. */ +#define X86_MXCSR_ZE RT_BIT_32(2) +/** Exception Flag: Overflow. */ +#define X86_MXCSR_OE RT_BIT_32(3) +/** Exception Flag: Underflow. */ +#define X86_MXCSR_UE RT_BIT_32(4) +/** Exception Flag: Precision. */ +#define X86_MXCSR_PE RT_BIT_32(5) +/** Exception Flags: mask */ +#define X86_MXCSR_XCPT_FLAGS UINT32_C(0x003f) + +/** Denormals are zero. */ +#define X86_MXCSR_DAZ RT_BIT_32(6) + +/** Exception Mask: Invalid operation. */ +#define X86_MXCSR_IM RT_BIT_32(7) +/** Exception Mask: Denormalized operand. */ +#define X86_MXCSR_DM RT_BIT_32(8) +/** Exception Mask: Zero divide. */ +#define X86_MXCSR_ZM RT_BIT_32(9) +/** Exception Mask: Overflow. */ +#define X86_MXCSR_OM RT_BIT_32(10) +/** Exception Mask: Underflow. */ +#define X86_MXCSR_UM RT_BIT_32(11) +/** Exception Mask: Precision. */ +#define X86_MXCSR_PM RT_BIT_32(12) +/** Exception Mask: mask. */ +#define X86_MXCSR_XCPT_MASK UINT32_C(0x1f80) +/** Exception Mask: shift. */ +#define X86_MXCSR_XCPT_MASK_SHIFT 7 + +/** Rounding control mask. */ +#define X86_MXCSR_RC_MASK UINT32_C(0x6000) +/** Rounding control shift. */ +#define X86_MXCSR_RC_SHIFT 13 +/** Rounding control: To nearest. */ +#define X86_MXCSR_RC_NEAREST UINT32_C(0x0000) +/** Rounding control: Down. */ +#define X86_MXCSR_RC_DOWN UINT32_C(0x2000) +/** Rounding control: Up. */ +#define X86_MXCSR_RC_UP UINT32_C(0x4000) +/** Rounding control: Towards zero. */ +#define X86_MXCSR_RC_ZERO UINT32_C(0x6000) + +/** Flush-to-zero for masked underflow. */ +#define X86_MXCSR_FZ RT_BIT_32(15) + +/** Misaligned Exception Mask (AMD MISALIGNSSE). */ +#define X86_MXCSR_MM RT_BIT_32(17) +/** Bits which should be zero, apparently. */ +#define X86_MXCSR_ZERO_MASK UINT32_C(0xfffd0000) +/** @} */ + +/** + * XSAVE header. + */ +typedef struct X86XSAVEHDR +{ + /** XTATE_BV - Bitmap indicating whether a component is in the state. */ + uint64_t bmXState; + /** XCOMP_BC - Bitmap used by instructions applying structure compaction. */ + uint64_t bmXComp; + /** Reserved for furture extensions, probably MBZ. */ + uint64_t au64Reserved[6]; +} X86XSAVEHDR; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVEHDR, 64); +#endif +/** Pointer to an XSAVE header. */ +typedef X86XSAVEHDR *PX86XSAVEHDR; +/** Pointer to a const XSAVE header. */ +typedef X86XSAVEHDR const *PCX86XSAVEHDR; + + +/** + * The high 128-bit YMM register state (XSAVE_C_YMM). + * (The lower 128-bits being in X86FXSTATE.) + */ +typedef struct X86XSAVEYMMHI +{ + /** 16 registers in 64-bit mode, 8 in 32-bit mode. */ + X86XMMREG aYmmHi[16]; +} X86XSAVEYMMHI; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVEYMMHI, 256); +#endif +/** Pointer to a high 128-bit YMM register state. */ +typedef X86XSAVEYMMHI *PX86XSAVEYMMHI; +/** Pointer to a const high 128-bit YMM register state. */ +typedef X86XSAVEYMMHI const *PCX86XSAVEYMMHI; + +/** + * Intel MPX bound registers state (XSAVE_C_BNDREGS). + */ +typedef struct X86XSAVEBNDREGS +{ + /** Array of registers (BND0...BND3). */ + struct + { + /** Lower bound. */ + uint64_t uLowerBound; + /** Upper bound. */ + uint64_t uUpperBound; + } aRegs[4]; +} X86XSAVEBNDREGS; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVEBNDREGS, 64); +#endif +/** Pointer to a MPX bound register state. */ +typedef X86XSAVEBNDREGS *PX86XSAVEBNDREGS; +/** Pointer to a const MPX bound register state. */ +typedef X86XSAVEBNDREGS const *PCX86XSAVEBNDREGS; + +/** + * Intel MPX bound config and status register state (XSAVE_C_BNDCSR). + */ +typedef struct X86XSAVEBNDCFG +{ + uint64_t fConfig; + uint64_t fStatus; +} X86XSAVEBNDCFG; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVEBNDCFG, 16); +#endif +/** Pointer to a MPX bound config and status register state. */ +typedef X86XSAVEBNDCFG *PX86XSAVEBNDCFG; +/** Pointer to a const MPX bound config and status register state. */ +typedef X86XSAVEBNDCFG *PCX86XSAVEBNDCFG; + +/** + * AVX-512 opmask state (XSAVE_C_OPMASK). + */ +typedef struct X86XSAVEOPMASK +{ + /** The K0..K7 values. */ + uint64_t aKRegs[8]; +} X86XSAVEOPMASK; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVEOPMASK, 64); +#endif +/** Pointer to a AVX-512 opmask state. */ +typedef X86XSAVEOPMASK *PX86XSAVEOPMASK; +/** Pointer to a const AVX-512 opmask state. */ +typedef X86XSAVEOPMASK const *PCX86XSAVEOPMASK; + +/** + * ZMM0-15 upper 256 bits introduced in AVX-512 (XSAVE_C_ZMM_HI256). + */ +typedef struct X86XSAVEZMMHI256 +{ + /** Upper 256-bits of ZMM0-15. */ + X86YMMREG aHi256Regs[16]; +} X86XSAVEZMMHI256; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVEZMMHI256, 512); +#endif +/** Pointer to a state comprising the upper 256-bits of ZMM0-15. */ +typedef X86XSAVEZMMHI256 *PX86XSAVEZMMHI256; +/** Pointer to a const state comprising the upper 256-bits of ZMM0-15. */ +typedef X86XSAVEZMMHI256 const *PCX86XSAVEZMMHI256; + +/** + * ZMM16-31 register state introduced in AVX-512 (XSAVE_C_ZMM_16HI). + */ +typedef struct X86XSAVEZMM16HI +{ + /** ZMM16 thru ZMM31. */ + X86ZMMREG aRegs[16]; +} X86XSAVEZMM16HI; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVEZMM16HI, 1024); +#endif +/** Pointer to a state comprising ZMM16-32. */ +typedef X86XSAVEZMM16HI *PX86XSAVEZMM16HI; +/** Pointer to a const state comprising ZMM16-32. */ +typedef X86XSAVEZMM16HI const *PCX86XSAVEZMM16HI; + +/** + * AMD Light weight profiling state (XSAVE_C_LWP). + * + * We probably won't play with this as AMD seems to be dropping from their "zen" + * processor micro architecture. + */ +typedef struct X86XSAVELWP +{ + /** Details when needed. */ + uint64_t auLater[128/8]; +} X86XSAVELWP; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVELWP, 128); +#endif + + +/** + * x86 FPU/SSE/AVX/XXXX state. + * + * Please bump DBGFCORE_FMT_VERSION by 1 in dbgfcorefmt.h if you make any + * changes to this structure. + */ +typedef struct X86XSAVEAREA +{ + /** The x87 and SSE region (or legacy region if you like). */ + X86FXSTATE x87; + /** The XSAVE header. */ + X86XSAVEHDR Hdr; + /** Beyond the header, there isn't really a fixed layout, but we can + generally assume the YMM (AVX) register extensions are present and + follows immediately. */ + union + { + /** The high 128-bit AVX registers for easy access by IEM. + * @note This ASSUMES they will always be here... */ + X86XSAVEYMMHI YmmHi; + + /** This is a typical layout on intel CPUs (good for debuggers). */ + struct + { + X86XSAVEYMMHI YmmHi; + X86XSAVEBNDREGS BndRegs; + X86XSAVEBNDCFG BndCfg; + uint8_t abFudgeToMatchDocs[0xB0]; + X86XSAVEOPMASK Opmask; + X86XSAVEZMMHI256 ZmmHi256; + X86XSAVEZMM16HI Zmm16Hi; + } Intel; + + /** This is a typical layout on AMD Bulldozer type CPUs (good for debuggers). */ + struct + { + X86XSAVEYMMHI YmmHi; + X86XSAVELWP Lwp; + } AmdBd; + + /** To enbling static deployments that have a reasonable chance of working for + * the next 3-6 CPU generations without running short on space, we allocate a + * lot of extra space here, making the structure a round 8KB in size. This + * leaves us 7616 bytes for extended state. The skylake xeons are likely to use + * 2112 of these, leaving us with 5504 bytes for future Intel generations. */ + uint8_t ab[8192 - 512 - 64]; + } u; +} X86XSAVEAREA; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86XSAVEAREA, 8192); +AssertCompileMemberSize(X86XSAVEAREA, u.Intel, 0x840 /*2112 => total 0xa80 (2688) */); +AssertCompileMemberOffset(X86XSAVEAREA, Hdr, 0x200); +AssertCompileMemberOffset(X86XSAVEAREA, u.Intel.YmmHi, 0x240); +AssertCompileMemberOffset(X86XSAVEAREA, u.Intel.BndRegs, 0x340); +AssertCompileMemberOffset(X86XSAVEAREA, u.Intel.BndCfg, 0x380); +AssertCompileMemberOffset(X86XSAVEAREA, u.Intel.Opmask, 0x440 /* 1088 */); +AssertCompileMemberOffset(X86XSAVEAREA, u.Intel.ZmmHi256, 0x480 /* 1152 */); +AssertCompileMemberOffset(X86XSAVEAREA, u.Intel.Zmm16Hi, 0x680 /* 1664 */); +#endif +/** Pointer to a XSAVE area. */ +typedef X86XSAVEAREA *PX86XSAVEAREA; +/** Pointer to a const XSAVE area. */ +typedef X86XSAVEAREA const *PCX86XSAVEAREA; + + +/** @name XSAVE_C_XXX - XSAVE State Components Bits (XCR0). + * @{ */ +/** Bit 0 - x87 - Legacy FPU state (bit number) */ +#define XSAVE_C_X87_BIT 0 +/** Bit 0 - x87 - Legacy FPU state. */ +#define XSAVE_C_X87 RT_BIT_64(XSAVE_C_X87_BIT) +/** Bit 1 - SSE - 128-bit SSE state (bit number). */ +#define XSAVE_C_SSE_BIT 1 +/** Bit 1 - SSE - 128-bit SSE state. */ +#define XSAVE_C_SSE RT_BIT_64(XSAVE_C_SSE_BIT) +/** Bit 2 - YMM_Hi128 - Upper 128 bits of YMM0-15 (AVX) (bit number). */ +#define XSAVE_C_YMM_BIT 2 +/** Bit 2 - YMM_Hi128 - Upper 128 bits of YMM0-15 (AVX). */ +#define XSAVE_C_YMM RT_BIT_64(XSAVE_C_YMM_BIT) +/** Bit 3 - BNDREGS - MPX bound register state (bit number). */ +#define XSAVE_C_BNDREGS_BIT 3 +/** Bit 3 - BNDREGS - MPX bound register state. */ +#define XSAVE_C_BNDREGS RT_BIT_64(XSAVE_C_BNDREGS_BIT) +/** Bit 4 - BNDCSR - MPX bound config and status state (bit number). */ +#define XSAVE_C_BNDCSR_BIT 4 +/** Bit 4 - BNDCSR - MPX bound config and status state. */ +#define XSAVE_C_BNDCSR RT_BIT_64(XSAVE_C_BNDCSR_BIT) +/** Bit 5 - Opmask - opmask state (bit number). */ +#define XSAVE_C_OPMASK_BIT 5 +/** Bit 5 - Opmask - opmask state. */ +#define XSAVE_C_OPMASK RT_BIT_64(XSAVE_C_OPMASK_BIT) +/** Bit 6 - ZMM_Hi256 - Upper 256 bits of ZMM0-15 (AVX-512) (bit number). */ +#define XSAVE_C_ZMM_HI256_BIT 6 +/** Bit 6 - ZMM_Hi256 - Upper 256 bits of ZMM0-15 (AVX-512). */ +#define XSAVE_C_ZMM_HI256 RT_BIT_64(XSAVE_C_ZMM_HI256_BIT) +/** Bit 7 - Hi16_ZMM - 512-bits ZMM16-31 state (AVX-512) (bit number). */ +#define XSAVE_C_ZMM_16HI_BIT 7 +/** Bit 7 - Hi16_ZMM - 512-bits ZMM16-31 state (AVX-512). */ +#define XSAVE_C_ZMM_16HI RT_BIT_64(XSAVE_C_ZMM_16HI_BIT) +/** Bit 9 - PKRU - Protection-key state (bit number). */ +#define XSAVE_C_PKRU_BIT 9 +/** Bit 9 - PKRU - Protection-key state. */ +#define XSAVE_C_PKRU RT_BIT_64(XSAVE_C_PKRU_BIT) +/** Bit 62 - LWP - Lightweight Profiling (AMD) (bit number). */ +#define XSAVE_C_LWP_BIT 62 +/** Bit 62 - LWP - Lightweight Profiling (AMD). */ +#define XSAVE_C_LWP RT_BIT_64(XSAVE_C_LWP_BIT) +/** Bit 63 - X - Reserved (MBZ) for extending XCR0 (bit number). */ +#define XSAVE_C_X_BIT 63 +/** Bit 63 - X - Reserved (MBZ) for extending XCR0 (AMD). */ +#define XSAVE_C_X RT_BIT_64(XSAVE_C_X_BIT) +/** @} */ + + + +/** @name Selector Descriptor + * @{ + */ + +#ifndef VBOX_FOR_DTRACE_LIB +/** + * Descriptor attributes (as seen by VT-x). + */ +typedef struct X86DESCATTRBITS +{ + /** 00 - Segment Type. */ + unsigned u4Type : 4; + /** 04 - Descriptor Type. System(=0) or code/data selector */ + unsigned u1DescType : 1; + /** 05 - Descriptor Privilege level. */ + unsigned u2Dpl : 2; + /** 07 - Flags selector present(=1) or not. */ + unsigned u1Present : 1; + /** 08 - Segment limit 16-19. */ + unsigned u4LimitHigh : 4; + /** 0c - Available for system software. */ + unsigned u1Available : 1; + /** 0d - 32 bits mode: Reserved - 0, long mode: Long Attribute Bit. */ + unsigned u1Long : 1; + /** 0e - This flags meaning depends on the segment type. Try make sense out + * of the intel manual yourself. */ + unsigned u1DefBig : 1; + /** 0f - Granularity of the limit. If set 4KB granularity is used, if + * clear byte. */ + unsigned u1Granularity : 1; + /** 10 - "Unusable" selector, special Intel (VT-x only?) bit. */ + unsigned u1Unusable : 1; +} X86DESCATTRBITS; +#endif /* !VBOX_FOR_DTRACE_LIB */ + +/** @name X86DESCATTR masks + * @{ */ +#define X86DESCATTR_TYPE UINT32_C(0x0000000f) +#define X86DESCATTR_DT UINT32_C(0x00000010) +#define X86DESCATTR_DPL UINT32_C(0x00000060) +#define X86DESCATTR_DPL_SHIFT 5 /**< Shift count for the DPL value. */ +#define X86DESCATTR_P UINT32_C(0x00000080) +#define X86DESCATTR_LIMIT_HIGH UINT32_C(0x00000f00) +#define X86DESCATTR_AVL UINT32_C(0x00001000) +#define X86DESCATTR_L UINT32_C(0x00002000) +#define X86DESCATTR_D UINT32_C(0x00004000) +#define X86DESCATTR_G UINT32_C(0x00008000) +#define X86DESCATTR_UNUSABLE UINT32_C(0x00010000) +/** @} */ + +#pragma pack(1) +typedef union X86DESCATTR +{ + /** Unsigned integer view. */ + uint32_t u; +#ifndef VBOX_FOR_DTRACE_LIB + /** Normal view. */ + X86DESCATTRBITS n; +#endif +} X86DESCATTR; +#pragma pack() +/** Pointer to descriptor attributes. */ +typedef X86DESCATTR *PX86DESCATTR; +/** Pointer to const descriptor attributes. */ +typedef const X86DESCATTR *PCX86DESCATTR; + +#ifndef VBOX_FOR_DTRACE_LIB + +/** + * Generic descriptor table entry + */ +#pragma pack(1) +typedef struct X86DESCGENERIC +{ + /** 00 - Limit - Low word. */ + unsigned u16LimitLow : 16; + /** 10 - Base address - low word. + * Don't try set this to 24 because MSC is doing stupid things then. */ + unsigned u16BaseLow : 16; + /** 20 - Base address - first 8 bits of high word. */ + unsigned u8BaseHigh1 : 8; + /** 28 - Segment Type. */ + unsigned u4Type : 4; + /** 2c - Descriptor Type. System(=0) or code/data selector */ + unsigned u1DescType : 1; + /** 2d - Descriptor Privilege level. */ + unsigned u2Dpl : 2; + /** 2f - Flags selector present(=1) or not. */ + unsigned u1Present : 1; + /** 30 - Segment limit 16-19. */ + unsigned u4LimitHigh : 4; + /** 34 - Available for system software. */ + unsigned u1Available : 1; + /** 35 - 32 bits mode: Reserved - 0, long mode: Long Attribute Bit. */ + unsigned u1Long : 1; + /** 36 - This flags meaning depends on the segment type. Try make sense out + * of the intel manual yourself. */ + unsigned u1DefBig : 1; + /** 37 - Granularity of the limit. If set 4KB granularity is used, if + * clear byte. */ + unsigned u1Granularity : 1; + /** 38 - Base address - highest 8 bits. */ + unsigned u8BaseHigh2 : 8; +} X86DESCGENERIC; +#pragma pack() +/** Pointer to a generic descriptor entry. */ +typedef X86DESCGENERIC *PX86DESCGENERIC; +/** Pointer to a const generic descriptor entry. */ +typedef const X86DESCGENERIC *PCX86DESCGENERIC; + +/** @name Bit offsets of X86DESCGENERIC members. + * @{*/ +#define X86DESCGENERIC_BIT_OFF_LIMIT_LOW (0) /**< Bit offset of X86DESCGENERIC::u16LimitLow. */ +#define X86DESCGENERIC_BIT_OFF_BASE_LOW (16) /**< Bit offset of X86DESCGENERIC::u16BaseLow. */ +#define X86DESCGENERIC_BIT_OFF_BASE_HIGH1 (32) /**< Bit offset of X86DESCGENERIC::u8BaseHigh1. */ +#define X86DESCGENERIC_BIT_OFF_TYPE (40) /**< Bit offset of X86DESCGENERIC::u4Type. */ +#define X86DESCGENERIC_BIT_OFF_DESC_TYPE (44) /**< Bit offset of X86DESCGENERIC::u1DescType. */ +#define X86DESCGENERIC_BIT_OFF_DPL (45) /**< Bit offset of X86DESCGENERIC::u2Dpl. */ +#define X86DESCGENERIC_BIT_OFF_PRESENT (47) /**< Bit offset of X86DESCGENERIC::uu1Present. */ +#define X86DESCGENERIC_BIT_OFF_LIMIT_HIGH (48) /**< Bit offset of X86DESCGENERIC::u4LimitHigh. */ +#define X86DESCGENERIC_BIT_OFF_AVAILABLE (52) /**< Bit offset of X86DESCGENERIC::u1Available. */ +#define X86DESCGENERIC_BIT_OFF_LONG (53) /**< Bit offset of X86DESCGENERIC::u1Long. */ +#define X86DESCGENERIC_BIT_OFF_DEF_BIG (54) /**< Bit offset of X86DESCGENERIC::u1DefBig. */ +#define X86DESCGENERIC_BIT_OFF_GRANULARITY (55) /**< Bit offset of X86DESCGENERIC::u1Granularity. */ +#define X86DESCGENERIC_BIT_OFF_BASE_HIGH2 (56) /**< Bit offset of X86DESCGENERIC::u8BaseHigh2. */ +/** @} */ + + +/** @name LAR mask + * @{ */ +#define X86LAR_F_TYPE UINT16_C( 0x0f00) +#define X86LAR_F_DT UINT16_C( 0x1000) +#define X86LAR_F_DPL UINT16_C( 0x6000) +#define X86LAR_F_DPL_SHIFT 13 /**< Shift count for the DPL value. */ +#define X86LAR_F_P UINT16_C( 0x8000) +#define X86LAR_F_AVL UINT32_C(0x00100000) +#define X86LAR_F_L UINT32_C(0x00200000) +#define X86LAR_F_D UINT32_C(0x00400000) +#define X86LAR_F_G UINT32_C(0x00800000) +/** @} */ + + +/** + * Call-, Interrupt-, Trap- or Task-gate descriptor (legacy). + */ +typedef struct X86DESCGATE +{ + /** 00 - Target code segment offset - Low word. + * Ignored if task-gate. */ + unsigned u16OffsetLow : 16; + /** 10 - Target code segment selector for call-, interrupt- and trap-gates, + * TSS selector if task-gate. */ + unsigned u16Sel : 16; + /** 20 - Number of parameters for a call-gate. + * Ignored if interrupt-, trap- or task-gate. */ + unsigned u5ParmCount : 5; + /** 25 - Reserved / ignored. */ + unsigned u3Reserved : 3; + /** 28 - Segment Type. */ + unsigned u4Type : 4; + /** 2c - Descriptor Type (0 = system). */ + unsigned u1DescType : 1; + /** 2d - Descriptor Privilege level. */ + unsigned u2Dpl : 2; + /** 2f - Flags selector present(=1) or not. */ + unsigned u1Present : 1; + /** 30 - Target code segment offset - High word. + * Ignored if task-gate. */ + unsigned u16OffsetHigh : 16; +} X86DESCGATE; +/** Pointer to a Call-, Interrupt-, Trap- or Task-gate descriptor entry. */ +typedef X86DESCGATE *PX86DESCGATE; +/** Pointer to a const Call-, Interrupt-, Trap- or Task-gate descriptor entry. */ +typedef const X86DESCGATE *PCX86DESCGATE; + +#endif /* VBOX_FOR_DTRACE_LIB */ + +/** + * Descriptor table entry. + */ +#pragma pack(1) +typedef union X86DESC +{ +#ifndef VBOX_FOR_DTRACE_LIB + /** Generic descriptor view. */ + X86DESCGENERIC Gen; + /** Gate descriptor view. */ + X86DESCGATE Gate; +#endif + + /** 8 bit unsigned integer view. */ + uint8_t au8[8]; + /** 16 bit unsigned integer view. */ + uint16_t au16[4]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** Unsigned integer view. */ + uint64_t u; +} X86DESC; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86DESC, 8); +#endif +#pragma pack() +/** Pointer to descriptor table entry. */ +typedef X86DESC *PX86DESC; +/** Pointer to const descriptor table entry. */ +typedef const X86DESC *PCX86DESC; + +/** @def X86DESC_BASE + * Return the base address of a descriptor. + */ +#define X86DESC_BASE(a_pDesc) /*ASM-NOINC*/ \ + ( ((uint32_t)((a_pDesc)->Gen.u8BaseHigh2) << 24) \ + | ( (a_pDesc)->Gen.u8BaseHigh1 << 16) \ + | ( (a_pDesc)->Gen.u16BaseLow ) ) + +/** @def X86DESC_LIMIT + * Return the limit of a descriptor. + */ +#define X86DESC_LIMIT(a_pDesc) /*ASM-NOINC*/ \ + ( ((uint32_t)((a_pDesc)->Gen.u4LimitHigh) << 16) \ + | ( (a_pDesc)->Gen.u16LimitLow ) ) + +/** @def X86DESC_LIMIT_G + * Return the limit of a descriptor with the granularity bit taken into account. + * @returns Selector limit (uint32_t). + * @param a_pDesc Pointer to the descriptor. + */ +#define X86DESC_LIMIT_G(a_pDesc) /*ASM-NOINC*/ \ + ( (a_pDesc)->Gen.u1Granularity \ + ? ( ( ((uint32_t)(a_pDesc)->Gen.u4LimitHigh << 16) | (a_pDesc)->Gen.u16LimitLow ) << 12 ) | UINT32_C(0xfff) \ + : ((uint32_t)(a_pDesc)->Gen.u4LimitHigh << 16) | (a_pDesc)->Gen.u16LimitLow \ + ) + +/** @def X86DESC_GET_HID_ATTR + * Get the descriptor attributes for the hidden register. + */ +#define X86DESC_GET_HID_ATTR(a_pDesc) /*ASM-NOINC*/ \ + ( ((a_pDesc)->u >> (16+16+8)) & UINT32_C(0xf0ff) ) /** @todo do we have a define for 0xf0ff? */ + +#ifndef VBOX_FOR_DTRACE_LIB + +/** + * 64 bits generic descriptor table entry + * Note: most of these bits have no meaning in long mode. + */ +#pragma pack(1) +typedef struct X86DESC64GENERIC +{ + /** Limit - Low word - *IGNORED*. */ + uint32_t u16LimitLow : 16; + /** Base address - low word. - *IGNORED* + * Don't try set this to 24 because MSC is doing stupid things then. */ + uint32_t u16BaseLow : 16; + /** Base address - first 8 bits of high word. - *IGNORED* */ + uint32_t u8BaseHigh1 : 8; + /** Segment Type. */ + uint32_t u4Type : 4; + /** Descriptor Type. System(=0) or code/data selector */ + uint32_t u1DescType : 1; + /** Descriptor Privilege level. */ + uint32_t u2Dpl : 2; + /** Flags selector present(=1) or not. */ + uint32_t u1Present : 1; + /** Segment limit 16-19. - *IGNORED* */ + uint32_t u4LimitHigh : 4; + /** Available for system software. - *IGNORED* */ + uint32_t u1Available : 1; + /** Long mode flag. */ + uint32_t u1Long : 1; + /** This flags meaning depends on the segment type. Try make sense out + * of the intel manual yourself. */ + uint32_t u1DefBig : 1; + /** Granularity of the limit. If set 4KB granularity is used, if + * clear byte. - *IGNORED* */ + uint32_t u1Granularity : 1; + /** Base address - highest 8 bits. - *IGNORED* */ + uint32_t u8BaseHigh2 : 8; + /** Base address - bits 63-32. */ + uint32_t u32BaseHigh3 : 32; + uint32_t u8Reserved : 8; + uint32_t u5Zeros : 5; + uint32_t u19Reserved : 19; +} X86DESC64GENERIC; +#pragma pack() +/** Pointer to a generic descriptor entry. */ +typedef X86DESC64GENERIC *PX86DESC64GENERIC; +/** Pointer to a const generic descriptor entry. */ +typedef const X86DESC64GENERIC *PCX86DESC64GENERIC; + +/** + * System descriptor table entry (64 bits) + * + * @remarks This is, save a couple of comments, identical to X86DESC64GENERIC... + */ +#pragma pack(1) +typedef struct X86DESC64SYSTEM +{ + /** Limit - Low word. */ + uint32_t u16LimitLow : 16; + /** Base address - low word. + * Don't try set this to 24 because MSC is doing stupid things then. */ + uint32_t u16BaseLow : 16; + /** Base address - first 8 bits of high word. */ + uint32_t u8BaseHigh1 : 8; + /** Segment Type. */ + uint32_t u4Type : 4; + /** Descriptor Type. System(=0) or code/data selector */ + uint32_t u1DescType : 1; + /** Descriptor Privilege level. */ + uint32_t u2Dpl : 2; + /** Flags selector present(=1) or not. */ + uint32_t u1Present : 1; + /** Segment limit 16-19. */ + uint32_t u4LimitHigh : 4; + /** Available for system software. */ + uint32_t u1Available : 1; + /** Reserved - 0. */ + uint32_t u1Reserved : 1; + /** This flags meaning depends on the segment type. Try make sense out + * of the intel manual yourself. */ + uint32_t u1DefBig : 1; + /** Granularity of the limit. If set 4KB granularity is used, if + * clear byte. */ + uint32_t u1Granularity : 1; + /** Base address - bits 31-24. */ + uint32_t u8BaseHigh2 : 8; + /** Base address - bits 63-32. */ + uint32_t u32BaseHigh3 : 32; + uint32_t u8Reserved : 8; + uint32_t u5Zeros : 5; + uint32_t u19Reserved : 19; +} X86DESC64SYSTEM; +#pragma pack() +/** Pointer to a system descriptor entry. */ +typedef X86DESC64SYSTEM *PX86DESC64SYSTEM; +/** Pointer to a const system descriptor entry. */ +typedef const X86DESC64SYSTEM *PCX86DESC64SYSTEM; + +/** + * Call-, Interrupt-, Trap- or Task-gate descriptor (64-bit). + */ +typedef struct X86DESC64GATE +{ + /** Target code segment offset - Low word. */ + uint32_t u16OffsetLow : 16; + /** Target code segment selector. */ + uint32_t u16Sel : 16; + /** Interrupt stack table for interrupt- and trap-gates. + * Ignored by call-gates. */ + uint32_t u3IST : 3; + /** Reserved / ignored. */ + uint32_t u5Reserved : 5; + /** Segment Type. */ + uint32_t u4Type : 4; + /** Descriptor Type (0 = system). */ + uint32_t u1DescType : 1; + /** Descriptor Privilege level. */ + uint32_t u2Dpl : 2; + /** Flags selector present(=1) or not. */ + uint32_t u1Present : 1; + /** Target code segment offset - High word. + * Ignored if task-gate. */ + uint32_t u16OffsetHigh : 16; + /** Target code segment offset - Top dword. + * Ignored if task-gate. */ + uint32_t u32OffsetTop : 32; + /** Reserved / ignored / must be zero. + * For call-gates bits 8 thru 12 must be zero, the other gates ignores this. */ + uint32_t u32Reserved : 32; +} X86DESC64GATE; +AssertCompileSize(X86DESC64GATE, 16); +/** Pointer to a Call-, Interrupt-, Trap- or Task-gate descriptor entry. */ +typedef X86DESC64GATE *PX86DESC64GATE; +/** Pointer to a const Call-, Interrupt-, Trap- or Task-gate descriptor entry. */ +typedef const X86DESC64GATE *PCX86DESC64GATE; + +#endif /* VBOX_FOR_DTRACE_LIB */ + +/** + * Descriptor table entry. + */ +#pragma pack(1) +typedef union X86DESC64 +{ +#ifndef VBOX_FOR_DTRACE_LIB + /** Generic descriptor view. */ + X86DESC64GENERIC Gen; + /** System descriptor view. */ + X86DESC64SYSTEM System; + /** Gate descriptor view. */ + X86DESC64GATE Gate; +#endif + + /** 8 bit unsigned integer view. */ + uint8_t au8[16]; + /** 16 bit unsigned integer view. */ + uint16_t au16[8]; + /** 32 bit unsigned integer view. */ + uint32_t au32[4]; + /** 64 bit unsigned integer view. */ + uint64_t au64[2]; +} X86DESC64; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86DESC64, 16); +#endif +#pragma pack() +/** Pointer to descriptor table entry. */ +typedef X86DESC64 *PX86DESC64; +/** Pointer to const descriptor table entry. */ +typedef const X86DESC64 *PCX86DESC64; + +/** @def X86DESC64_BASE + * Return the base of a 64-bit descriptor. + */ +#define X86DESC64_BASE(a_pDesc) /*ASM-NOINC*/ \ + ( ((uint64_t)((a_pDesc)->Gen.u32BaseHigh3) << 32) \ + | ((uint32_t)((a_pDesc)->Gen.u8BaseHigh2) << 24) \ + | ( (a_pDesc)->Gen.u8BaseHigh1 << 16) \ + | ( (a_pDesc)->Gen.u16BaseLow ) ) + + + +/** @name Host system descriptor table entry - Use with care! + * @{ */ +/** Host system descriptor table entry. */ +#if HC_ARCH_BITS == 64 +typedef X86DESC64 X86DESCHC; +#else +typedef X86DESC X86DESCHC; +#endif +/** Pointer to a host system descriptor table entry. */ +#if HC_ARCH_BITS == 64 +typedef PX86DESC64 PX86DESCHC; +#else +typedef PX86DESC PX86DESCHC; +#endif +/** Pointer to a const host system descriptor table entry. */ +#if HC_ARCH_BITS == 64 +typedef PCX86DESC64 PCX86DESCHC; +#else +typedef PCX86DESC PCX86DESCHC; +#endif +/** @} */ + + +/** @name Selector Descriptor Types. + * @{ + */ + +/** @name Non-System Selector Types. + * @{ */ +/** Code(=set)/Data(=clear) bit. */ +#define X86_SEL_TYPE_CODE 8 +/** Memory(=set)/System(=clear) bit. */ +#define X86_SEL_TYPE_MEMORY RT_BIT_32(4) +/** Accessed bit. */ +#define X86_SEL_TYPE_ACCESSED 1 +/** Expand down bit (for data selectors only). */ +#define X86_SEL_TYPE_DOWN 4 +/** Conforming bit (for code selectors only). */ +#define X86_SEL_TYPE_CONF 4 +/** Write bit (for data selectors only). */ +#define X86_SEL_TYPE_WRITE 2 +/** Read bit (for code selectors only). */ +#define X86_SEL_TYPE_READ 2 +/** The bit number of the code segment read bit (relative to u4Type). */ +#define X86_SEL_TYPE_READ_BIT 1 + +/** Read only selector type. */ +#define X86_SEL_TYPE_RO 0 +/** Accessed read only selector type. */ +#define X86_SEL_TYPE_RO_ACC (0 | X86_SEL_TYPE_ACCESSED) +/** Read write selector type. */ +#define X86_SEL_TYPE_RW 2 +/** Accessed read write selector type. */ +#define X86_SEL_TYPE_RW_ACC (2 | X86_SEL_TYPE_ACCESSED) +/** Expand down read only selector type. */ +#define X86_SEL_TYPE_RO_DOWN 4 +/** Accessed expand down read only selector type. */ +#define X86_SEL_TYPE_RO_DOWN_ACC (4 | X86_SEL_TYPE_ACCESSED) +/** Expand down read write selector type. */ +#define X86_SEL_TYPE_RW_DOWN 6 +/** Accessed expand down read write selector type. */ +#define X86_SEL_TYPE_RW_DOWN_ACC (6 | X86_SEL_TYPE_ACCESSED) +/** Execute only selector type. */ +#define X86_SEL_TYPE_EO (0 | X86_SEL_TYPE_CODE) +/** Accessed execute only selector type. */ +#define X86_SEL_TYPE_EO_ACC (0 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED) +/** Execute and read selector type. */ +#define X86_SEL_TYPE_ER (2 | X86_SEL_TYPE_CODE) +/** Accessed execute and read selector type. */ +#define X86_SEL_TYPE_ER_ACC (2 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED) +/** Conforming execute only selector type. */ +#define X86_SEL_TYPE_EO_CONF (4 | X86_SEL_TYPE_CODE) +/** Accessed Conforming execute only selector type. */ +#define X86_SEL_TYPE_EO_CONF_ACC (4 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED) +/** Conforming execute and write selector type. */ +#define X86_SEL_TYPE_ER_CONF (6 | X86_SEL_TYPE_CODE) +/** Accessed Conforming execute and write selector type. */ +#define X86_SEL_TYPE_ER_CONF_ACC (6 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED) +/** @} */ + + +/** @name System Selector Types. + * @{ */ +/** The TSS busy bit mask. */ +#define X86_SEL_TYPE_SYS_TSS_BUSY_MASK 2 + +/** Undefined system selector type. */ +#define X86_SEL_TYPE_SYS_UNDEFINED 0 +/** 286 TSS selector. */ +#define X86_SEL_TYPE_SYS_286_TSS_AVAIL 1 +/** LDT selector. */ +#define X86_SEL_TYPE_SYS_LDT 2 +/** 286 TSS selector - Busy. */ +#define X86_SEL_TYPE_SYS_286_TSS_BUSY 3 +/** 286 Callgate selector. */ +#define X86_SEL_TYPE_SYS_286_CALL_GATE 4 +/** Taskgate selector. */ +#define X86_SEL_TYPE_SYS_TASK_GATE 5 +/** 286 Interrupt gate selector. */ +#define X86_SEL_TYPE_SYS_286_INT_GATE 6 +/** 286 Trapgate selector. */ +#define X86_SEL_TYPE_SYS_286_TRAP_GATE 7 +/** Undefined system selector. */ +#define X86_SEL_TYPE_SYS_UNDEFINED2 8 +/** 386 TSS selector. */ +#define X86_SEL_TYPE_SYS_386_TSS_AVAIL 9 +/** Undefined system selector. */ +#define X86_SEL_TYPE_SYS_UNDEFINED3 0xA +/** 386 TSS selector - Busy. */ +#define X86_SEL_TYPE_SYS_386_TSS_BUSY 0xB +/** 386 Callgate selector. */ +#define X86_SEL_TYPE_SYS_386_CALL_GATE 0xC +/** Undefined system selector. */ +#define X86_SEL_TYPE_SYS_UNDEFINED4 0xD +/** 386 Interruptgate selector. */ +#define X86_SEL_TYPE_SYS_386_INT_GATE 0xE +/** 386 Trapgate selector. */ +#define X86_SEL_TYPE_SYS_386_TRAP_GATE 0xF +/** @} */ + +/** @name AMD64 System Selector Types. + * @{ */ +/** LDT selector. */ +#define AMD64_SEL_TYPE_SYS_LDT 2 +/** TSS selector - Busy. */ +#define AMD64_SEL_TYPE_SYS_TSS_AVAIL 9 +/** TSS selector - Busy. */ +#define AMD64_SEL_TYPE_SYS_TSS_BUSY 0xB +/** Callgate selector. */ +#define AMD64_SEL_TYPE_SYS_CALL_GATE 0xC +/** Interruptgate selector. */ +#define AMD64_SEL_TYPE_SYS_INT_GATE 0xE +/** Trapgate selector. */ +#define AMD64_SEL_TYPE_SYS_TRAP_GATE 0xF +/** @} */ + +/** @} */ + + +/** @name Descriptor Table Entry Flag Masks. + * These are for the 2nd 32-bit word of a descriptor. + * @{ */ +/** Bits 8-11 - TYPE - Descriptor type mask. */ +#define X86_DESC_TYPE_MASK (RT_BIT_32(8) | RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +/** Bit 12 - S - System (=0) or Code/Data (=1). */ +#define X86_DESC_S RT_BIT_32(12) +/** Bits 13-14 - DPL - Descriptor Privilege Level. */ +#define X86_DESC_DPL (RT_BIT_32(13) | RT_BIT_32(14)) +/** Bit 15 - P - Present. */ +#define X86_DESC_P RT_BIT_32(15) +/** Bit 20 - AVL - Available for system software. */ +#define X86_DESC_AVL RT_BIT_32(20) +/** Bit 22 - DB - Default operation size. 0 = 16 bit, 1 = 32 bit. */ +#define X86_DESC_DB RT_BIT_32(22) +/** Bit 23 - G - Granularity of the limit. If set 4KB granularity is + * used, if clear byte. */ +#define X86_DESC_G RT_BIT_32(23) +/** @} */ + +/** @} */ + + +/** @name Task Segments. + * @{ + */ + +/** + * The minimum TSS descriptor limit for 286 tasks. + */ +#define X86_SEL_TYPE_SYS_286_TSS_LIMIT_MIN 0x2b + +/** + * The minimum TSS descriptor segment limit for 386 tasks. + */ +#define X86_SEL_TYPE_SYS_386_TSS_LIMIT_MIN 0x67 + +/** + * 16-bit Task Segment (TSS). + */ +#pragma pack(1) +typedef struct X86TSS16 +{ + /** Back link to previous task. (static) */ + RTSEL selPrev; + /** Ring-0 stack pointer. (static) */ + uint16_t sp0; + /** Ring-0 stack segment. (static) */ + RTSEL ss0; + /** Ring-1 stack pointer. (static) */ + uint16_t sp1; + /** Ring-1 stack segment. (static) */ + RTSEL ss1; + /** Ring-2 stack pointer. (static) */ + uint16_t sp2; + /** Ring-2 stack segment. (static) */ + RTSEL ss2; + /** IP before task switch. */ + uint16_t ip; + /** FLAGS before task switch. */ + uint16_t flags; + /** AX before task switch. */ + uint16_t ax; + /** CX before task switch. */ + uint16_t cx; + /** DX before task switch. */ + uint16_t dx; + /** BX before task switch. */ + uint16_t bx; + /** SP before task switch. */ + uint16_t sp; + /** BP before task switch. */ + uint16_t bp; + /** SI before task switch. */ + uint16_t si; + /** DI before task switch. */ + uint16_t di; + /** ES before task switch. */ + RTSEL es; + /** CS before task switch. */ + RTSEL cs; + /** SS before task switch. */ + RTSEL ss; + /** DS before task switch. */ + RTSEL ds; + /** LDTR before task switch. */ + RTSEL selLdt; +} X86TSS16; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86TSS16, X86_SEL_TYPE_SYS_286_TSS_LIMIT_MIN + 1); +#endif +#pragma pack() +/** Pointer to a 16-bit task segment. */ +typedef X86TSS16 *PX86TSS16; +/** Pointer to a const 16-bit task segment. */ +typedef const X86TSS16 *PCX86TSS16; + + +/** + * 32-bit Task Segment (TSS). + */ +#pragma pack(1) +typedef struct X86TSS32 +{ + /** Back link to previous task. (static) */ + RTSEL selPrev; + uint16_t padding1; + /** Ring-0 stack pointer. (static) */ + uint32_t esp0; + /** Ring-0 stack segment. (static) */ + RTSEL ss0; + uint16_t padding_ss0; + /** Ring-1 stack pointer. (static) */ + uint32_t esp1; + /** Ring-1 stack segment. (static) */ + RTSEL ss1; + uint16_t padding_ss1; + /** Ring-2 stack pointer. (static) */ + uint32_t esp2; + /** Ring-2 stack segment. (static) */ + RTSEL ss2; + uint16_t padding_ss2; + /** Page directory for the task. (static) */ + uint32_t cr3; + /** EIP before task switch. */ + uint32_t eip; + /** EFLAGS before task switch. */ + uint32_t eflags; + /** EAX before task switch. */ + uint32_t eax; + /** ECX before task switch. */ + uint32_t ecx; + /** EDX before task switch. */ + uint32_t edx; + /** EBX before task switch. */ + uint32_t ebx; + /** ESP before task switch. */ + uint32_t esp; + /** EBP before task switch. */ + uint32_t ebp; + /** ESI before task switch. */ + uint32_t esi; + /** EDI before task switch. */ + uint32_t edi; + /** ES before task switch. */ + RTSEL es; + uint16_t padding_es; + /** CS before task switch. */ + RTSEL cs; + uint16_t padding_cs; + /** SS before task switch. */ + RTSEL ss; + uint16_t padding_ss; + /** DS before task switch. */ + RTSEL ds; + uint16_t padding_ds; + /** FS before task switch. */ + RTSEL fs; + uint16_t padding_fs; + /** GS before task switch. */ + RTSEL gs; + uint16_t padding_gs; + /** LDTR before task switch. */ + RTSEL selLdt; + uint16_t padding_ldt; + /** Debug trap flag */ + uint16_t fDebugTrap; + /** Offset relative to the TSS of the start of the I/O Bitmap + * and the end of the interrupt redirection bitmap. */ + uint16_t offIoBitmap; +} X86TSS32; +#pragma pack() +/** Pointer to task segment. */ +typedef X86TSS32 *PX86TSS32; +/** Pointer to const task segment. */ +typedef const X86TSS32 *PCX86TSS32; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86TSS32, X86_SEL_TYPE_SYS_386_TSS_LIMIT_MIN + 1); +AssertCompileMemberOffset(X86TSS32, cr3, 28); +AssertCompileMemberOffset(X86TSS32, offIoBitmap, 102); +#endif + +/** + * 64-bit Task segment. + */ +#pragma pack(1) +typedef struct X86TSS64 +{ + /** Reserved. */ + uint32_t u32Reserved; + /** Ring-0 stack pointer. (static) */ + uint64_t rsp0; + /** Ring-1 stack pointer. (static) */ + uint64_t rsp1; + /** Ring-2 stack pointer. (static) */ + uint64_t rsp2; + /** Reserved. */ + uint32_t u32Reserved2[2]; + /* IST */ + uint64_t ist1; + uint64_t ist2; + uint64_t ist3; + uint64_t ist4; + uint64_t ist5; + uint64_t ist6; + uint64_t ist7; + /* Reserved. */ + uint16_t u16Reserved[5]; + /** Offset relative to the TSS of the start of the I/O Bitmap + * and the end of the interrupt redirection bitmap. */ + uint16_t offIoBitmap; +} X86TSS64; +#pragma pack() +/** Pointer to a 64-bit task segment. */ +typedef X86TSS64 *PX86TSS64; +/** Pointer to a const 64-bit task segment. */ +typedef const X86TSS64 *PCX86TSS64; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(X86TSS64, X86_SEL_TYPE_SYS_386_TSS_LIMIT_MIN + 1); +#endif + +/** @} */ + + +/** @name Selectors. + * @{ + */ + +/** + * The shift used to convert a selector from and to index an index (C). + */ +#define X86_SEL_SHIFT 3 + +/** + * The mask used to mask off the table indicator and RPL of an selector. + */ +#define X86_SEL_MASK 0xfff8U + +/** + * The mask used to mask off the RPL of an selector. + * This is suitable for checking for NULL selectors. + */ +#define X86_SEL_MASK_OFF_RPL 0xfffcU + +/** + * The bit indicating that a selector is in the LDT and not in the GDT. + */ +#define X86_SEL_LDT 0x0004U + +/** + * The bit mask for getting the RPL of a selector. + */ +#define X86_SEL_RPL 0x0003U + +/** + * The mask covering both RPL and LDT. + * This is incidentally the same as sizeof(X86DESC) - 1, so good for limit + * checks. + */ +#define X86_SEL_RPL_LDT 0x0007U + +/** @} */ + + +/** + * x86 Exceptions/Faults/Traps. + */ +typedef enum X86XCPT +{ + /** \#DE - Divide error. */ + X86_XCPT_DE = 0x00, + /** \#DB - Debug event (single step, DRx, ..) */ + X86_XCPT_DB = 0x01, + /** NMI - Non-Maskable Interrupt */ + X86_XCPT_NMI = 0x02, + /** \#BP - Breakpoint (INT3). */ + X86_XCPT_BP = 0x03, + /** \#OF - Overflow (INTO). */ + X86_XCPT_OF = 0x04, + /** \#BR - Bound range exceeded (BOUND). */ + X86_XCPT_BR = 0x05, + /** \#UD - Undefined opcode. */ + X86_XCPT_UD = 0x06, + /** \#NM - Device not available (math coprocessor device). */ + X86_XCPT_NM = 0x07, + /** \#DF - Double fault. */ + X86_XCPT_DF = 0x08, + /** ??? - Coprocessor segment overrun (obsolete). */ + X86_XCPT_CO_SEG_OVERRUN = 0x09, + /** \#TS - Taskswitch (TSS). */ + X86_XCPT_TS = 0x0a, + /** \#NP - Segment no present. */ + X86_XCPT_NP = 0x0b, + /** \#SS - Stack segment fault. */ + X86_XCPT_SS = 0x0c, + /** \#GP - General protection fault. */ + X86_XCPT_GP = 0x0d, + /** \#PF - Page fault. */ + X86_XCPT_PF = 0x0e, + /* 0x0f is reserved (to avoid conflict with spurious interrupts in BIOS setup). */ + /** \#MF - Math fault (FPU). */ + X86_XCPT_MF = 0x10, + /** \#AC - Alignment check. */ + X86_XCPT_AC = 0x11, + /** \#MC - Machine check. */ + X86_XCPT_MC = 0x12, + /** \#XF - SIMD Floating-Point Exception. */ + X86_XCPT_XF = 0x13, + /** \#VE - Virtualization Exception (Intel only). */ + X86_XCPT_VE = 0x14, + /** \#CP - Control Protection Exception (Intel only). */ + X86_XCPT_CP = 0x15, + /** \#VC - VMM Communication Exception (AMD only). */ + X86_XCPT_VC = 0x1d, + /** \#SX - Security Exception (AMD only). */ + X86_XCPT_SX = 0x1e +} X86XCPT; +/** Pointer to a x86 exception code. */ +typedef X86XCPT *PX86XCPT; +/** Pointer to a const x86 exception code. */ +typedef const X86XCPT *PCX86XCPT; +/** The last valid (currently reserved) exception value. */ +#define X86_XCPT_LAST 0x1f + + +/** @name Trap Error Codes + * @{ + */ +/** External indicator. */ +#define X86_TRAP_ERR_EXTERNAL 1 +/** IDT indicator. */ +#define X86_TRAP_ERR_IDT 2 +/** Descriptor table indicator - If set LDT, if clear GDT. */ +#define X86_TRAP_ERR_TI 4 +/** Mask for getting the selector. */ +#define X86_TRAP_ERR_SEL_MASK 0xfff8 +/** Shift for getting the selector table index (C type index). */ +#define X86_TRAP_ERR_SEL_SHIFT 3 +/** @} */ + + +/** @name \#PF Trap Error Codes + * @{ + */ +/** Bit 0 - P - Not present (clear) or page level protection (set) fault. */ +#define X86_TRAP_PF_P RT_BIT_32(0) +/** Bit 1 - R/W - Read (clear) or write (set) access. */ +#define X86_TRAP_PF_RW RT_BIT_32(1) +/** Bit 2 - U/S - CPU executing in user mode (set) or supervisor mode (clear). */ +#define X86_TRAP_PF_US RT_BIT_32(2) +/** Bit 3 - RSVD- Reserved bit violation (set), i.e. reserved bit was set to 1. */ +#define X86_TRAP_PF_RSVD RT_BIT_32(3) +/** Bit 4 - I/D - Instruction fetch (set) / Data access (clear) - PAE + NXE. */ +#define X86_TRAP_PF_ID RT_BIT_32(4) +/** Bit 5 - PK - Protection-key violation (AMD64 mode only). */ +#define X86_TRAP_PF_PK RT_BIT_32(5) +/** @} */ + +#pragma pack(1) +/** + * 16-bit IDTR. + */ +typedef struct X86IDTR16 +{ + /** Offset. */ + uint16_t offSel; + /** Selector. */ + uint16_t uSel; +} X86IDTR16, *PX86IDTR16; +#pragma pack() + +#pragma pack(1) +/** + * 32-bit IDTR/GDTR. + */ +typedef struct X86XDTR32 +{ + /** Size of the descriptor table. */ + uint16_t cb; + /** Address of the descriptor table. */ +#ifndef VBOX_FOR_DTRACE_LIB + uint32_t uAddr; +#else + uint16_t au16Addr[2]; +#endif +} X86XDTR32, *PX86XDTR32; +#pragma pack() + +#pragma pack(1) +/** + * 64-bit IDTR/GDTR. + */ +typedef struct X86XDTR64 +{ + /** Size of the descriptor table. */ + uint16_t cb; + /** Address of the descriptor table. */ +#ifndef VBOX_FOR_DTRACE_LIB + uint64_t uAddr; +#else + uint16_t au16Addr[4]; +#endif +} X86XDTR64, *PX86XDTR64; +#pragma pack() + + +/** @name ModR/M + * @{ */ +#define X86_MODRM_RM_MASK UINT8_C(0x07) +#define X86_MODRM_REG_MASK UINT8_C(0x38) +#define X86_MODRM_REG_SMASK UINT8_C(0x07) +#define X86_MODRM_REG_SHIFT 3 +#define X86_MODRM_MOD_MASK UINT8_C(0xc0) +#define X86_MODRM_MOD_SMASK UINT8_C(0x03) +#define X86_MODRM_MOD_SHIFT 6 +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompile((X86_MODRM_RM_MASK | X86_MODRM_REG_MASK | X86_MODRM_MOD_MASK) == 0xff); +AssertCompile((X86_MODRM_REG_MASK >> X86_MODRM_REG_SHIFT) == X86_MODRM_REG_SMASK); +AssertCompile((X86_MODRM_MOD_MASK >> X86_MODRM_MOD_SHIFT) == X86_MODRM_MOD_SMASK); +/** @def X86_MODRM_MAKE + * @param a_Mod The mod value (0..3). + * @param a_Reg The register value (0..7). + * @param a_RegMem The register or memory value (0..7). */ +# define X86_MODRM_MAKE(a_Mod, a_Reg, a_RegMem) (((a_Mod) << X86_MODRM_MOD_SHIFT) | ((a_Reg) << X86_MODRM_REG_SHIFT) | (a_RegMem)) +#endif +/** @} */ + +/** @name SIB + * @{ */ +#define X86_SIB_BASE_MASK UINT8_C(0x07) +#define X86_SIB_INDEX_MASK UINT8_C(0x38) +#define X86_SIB_INDEX_SMASK UINT8_C(0x07) +#define X86_SIB_INDEX_SHIFT 3 +#define X86_SIB_SCALE_MASK UINT8_C(0xc0) +#define X86_SIB_SCALE_SMASK UINT8_C(0x03) +#define X86_SIB_SCALE_SHIFT 6 +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompile((X86_SIB_BASE_MASK | X86_SIB_INDEX_MASK | X86_SIB_SCALE_MASK) == 0xff); +AssertCompile((X86_SIB_INDEX_MASK >> X86_SIB_INDEX_SHIFT) == X86_SIB_INDEX_SMASK); +AssertCompile((X86_SIB_SCALE_MASK >> X86_SIB_SCALE_SHIFT) == X86_SIB_SCALE_SMASK); +#endif +/** @} */ + +/** @name General register indexes. + * @{ */ +#define X86_GREG_xAX 0 +#define X86_GREG_xCX 1 +#define X86_GREG_xDX 2 +#define X86_GREG_xBX 3 +#define X86_GREG_xSP 4 +#define X86_GREG_xBP 5 +#define X86_GREG_xSI 6 +#define X86_GREG_xDI 7 +#define X86_GREG_x8 8 +#define X86_GREG_x9 9 +#define X86_GREG_x10 10 +#define X86_GREG_x11 11 +#define X86_GREG_x12 12 +#define X86_GREG_x13 13 +#define X86_GREG_x14 14 +#define X86_GREG_x15 15 +/** @} */ +/** General register count. */ +#define X86_GREG_COUNT 16 + +/** @name X86_SREG_XXX - Segment register indexes. + * @{ */ +#define X86_SREG_ES 0 +#define X86_SREG_CS 1 +#define X86_SREG_SS 2 +#define X86_SREG_DS 3 +#define X86_SREG_FS 4 +#define X86_SREG_GS 5 +/** @} */ +/** Segment register count. */ +#define X86_SREG_COUNT 6 + + +/** @name X86_OP_XXX - Prefixes + * @{ */ +#define X86_OP_PRF_CS UINT8_C(0x2e) +#define X86_OP_PRF_SS UINT8_C(0x36) +#define X86_OP_PRF_DS UINT8_C(0x3e) +#define X86_OP_PRF_ES UINT8_C(0x26) +#define X86_OP_PRF_FS UINT8_C(0x64) +#define X86_OP_PRF_GS UINT8_C(0x65) +#define X86_OP_PRF_SIZE_OP UINT8_C(0x66) +#define X86_OP_PRF_SIZE_ADDR UINT8_C(0x67) +#define X86_OP_PRF_LOCK UINT8_C(0xf0) +#define X86_OP_PRF_REPZ UINT8_C(0xf3) +#define X86_OP_PRF_REPNZ UINT8_C(0xf2) +#define X86_OP_REX_B UINT8_C(0x41) +#define X86_OP_REX_X UINT8_C(0x42) +#define X86_OP_REX_R UINT8_C(0x44) +#define X86_OP_REX_W UINT8_C(0x48) +/** @} */ + + +/** @} */ + +#endif /* !IPRT_INCLUDED_x86_h */ + diff --git a/include/iprt/x86.mac b/include/iprt/x86.mac new file mode 100644 index 00000000..cd1b545a --- /dev/null +++ b/include/iprt/x86.mac @@ -0,0 +1,1409 @@ +;; @file +; IPRT - X86 and AMD64 Structures and Definitions. +; +; Automatically generated by various.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef IPRT_INCLUDED_x86_h +%define IPRT_INCLUDED_x86_h +%ifndef RT_WITHOUT_PRAGMA_ONCE +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%else +%endif +%ifdef RT_OS_SOLARIS +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_EFL_CF RT_BIT_32(0) +%define X86_EFL_CF_BIT 0 +%define X86_EFL_1 RT_BIT_32(1) +%define X86_EFL_PF RT_BIT_32(2) +%define X86_EFL_PF_BIT 2 +%define X86_EFL_AF RT_BIT_32(4) +%define X86_EFL_AF_BIT 4 +%define X86_EFL_ZF RT_BIT_32(6) +%define X86_EFL_ZF_BIT 6 +%define X86_EFL_SF RT_BIT_32(7) +%define X86_EFL_SF_BIT 7 +%define X86_EFL_TF RT_BIT_32(8) +%define X86_EFL_TF_BIT 8 +%define X86_EFL_IF RT_BIT_32(9) +%define X86_EFL_IF_BIT 9 +%define X86_EFL_DF RT_BIT_32(10) +%define X86_EFL_DF_BIT 10 +%define X86_EFL_OF RT_BIT_32(11) +%define X86_EFL_OF_BIT 11 +%define X86_EFL_IOPL (RT_BIT_32(12) | RT_BIT_32(13)) +%define X86_EFL_NT RT_BIT_32(14) +%define X86_EFL_NT_BIT 14 +%define X86_EFL_RF RT_BIT_32(16) +%define X86_EFL_RF_BIT 16 +%define X86_EFL_VM RT_BIT_32(17) +%define X86_EFL_VM_BIT 17 +%define X86_EFL_AC RT_BIT_32(18) +%define X86_EFL_AC_BIT 18 +%define X86_EFL_VIF RT_BIT_32(19) +%define X86_EFL_VIF_BIT 19 +%define X86_EFL_VIP RT_BIT_32(20) +%define X86_EFL_VIP_BIT 20 +%define X86_EFL_ID RT_BIT_32(21) +%define X86_EFL_ID_BIT 21 +%define X86_EFL_LIVE_MASK 0x003f7fd5 +%define X86_EFL_RA1_MASK RT_BIT_32(1) +%define X86_EFL_IOPL_SHIFT 12 +%define X86_EFL_GET_IOPL(efl) (((efl) >> X86_EFL_IOPL_SHIFT) & 3) +%define X86_EFL_POPF_BITS ( X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_TF | X86_EFL_IF \ + | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT | X86_EFL_AC | X86_EFL_ID ) +%define X86_EFL_POPF_BITS_386 ( X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_TF | X86_EFL_IF \ + | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT ) +%define X86_EFL_STATUS_BITS ( X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF ) +%ifndef VBOX_FOR_DTRACE_LIB +%else +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%else +%endif +%define X86_CPUID_VENDOR_INTEL_EBX 0x756e6547 +%define X86_CPUID_VENDOR_INTEL_ECX 0x6c65746e +%define X86_CPUID_VENDOR_INTEL_EDX 0x49656e69 +%define X86_CPUID_VENDOR_AMD_EBX 0x68747541 +%define X86_CPUID_VENDOR_AMD_ECX 0x444d4163 +%define X86_CPUID_VENDOR_AMD_EDX 0x69746e65 +%define X86_CPUID_VENDOR_VIA_EBX 0x746e6543 +%define X86_CPUID_VENDOR_VIA_ECX 0x736c7561 +%define X86_CPUID_VENDOR_VIA_EDX 0x48727561 +%define X86_CPUID_VENDOR_SHANGHAI_EBX 0x68532020 +%define X86_CPUID_VENDOR_SHANGHAI_ECX 0x20206961 +%define X86_CPUID_VENDOR_SHANGHAI_EDX 0x68676e61 +%define X86_CPUID_VENDOR_HYGON_EBX 0x6f677948 +%define X86_CPUID_VENDOR_HYGON_ECX 0x656e6975 +%define X86_CPUID_VENDOR_HYGON_EDX 0x6e65476e +%define X86_CPUID_FEATURE_ECX_SSE3 RT_BIT_32(0) +%define X86_CPUID_FEATURE_ECX_PCLMUL RT_BIT_32(1) +%define X86_CPUID_FEATURE_ECX_DTES64 RT_BIT_32(2) +%define X86_CPUID_FEATURE_ECX_MONITOR RT_BIT_32(3) +%define X86_CPUID_FEATURE_ECX_CPLDS RT_BIT_32(4) +%define X86_CPUID_FEATURE_ECX_VMX RT_BIT_32(5) +%define X86_CPUID_FEATURE_ECX_SMX RT_BIT_32(6) +%define X86_CPUID_FEATURE_ECX_EST RT_BIT_32(7) +%define X86_CPUID_FEATURE_ECX_TM2 RT_BIT_32(8) +%define X86_CPUID_FEATURE_ECX_SSSE3 RT_BIT_32(9) +%define X86_CPUID_FEATURE_ECX_CNTXID RT_BIT_32(10) +%define X86_CPUID_FEATURE_ECX_SDBG RT_BIT_32(11) +%define X86_CPUID_FEATURE_ECX_FMA RT_BIT_32(12) +%define X86_CPUID_FEATURE_ECX_CX16 RT_BIT_32(13) +%define X86_CPUID_FEATURE_ECX_TPRUPDATE RT_BIT_32(14) +%define X86_CPUID_FEATURE_ECX_PDCM RT_BIT_32(15) +%define X86_CPUID_FEATURE_ECX_PCID RT_BIT_32(17) +%define X86_CPUID_FEATURE_ECX_DCA RT_BIT_32(18) +%define X86_CPUID_FEATURE_ECX_SSE4_1 RT_BIT_32(19) +%define X86_CPUID_FEATURE_ECX_SSE4_2 RT_BIT_32(20) +%define X86_CPUID_FEATURE_ECX_X2APIC RT_BIT_32(21) +%define X86_CPUID_FEATURE_ECX_MOVBE RT_BIT_32(22) +%define X86_CPUID_FEATURE_ECX_POPCNT RT_BIT_32(23) +%define X86_CPUID_FEATURE_ECX_TSCDEADL RT_BIT_32(24) +%define X86_CPUID_FEATURE_ECX_AES RT_BIT_32(25) +%define X86_CPUID_FEATURE_ECX_XSAVE RT_BIT_32(26) +%define X86_CPUID_FEATURE_ECX_OSXSAVE RT_BIT_32(27) +%define X86_CPUID_FEATURE_ECX_AVX RT_BIT_32(28) +%define X86_CPUID_FEATURE_ECX_F16C RT_BIT_32(29) +%define X86_CPUID_FEATURE_ECX_RDRAND RT_BIT_32(30) +%define X86_CPUID_FEATURE_ECX_HVP RT_BIT_32(31) +%define X86_CPUID_FEATURE_EDX_FPU RT_BIT_32(0) +%define X86_CPUID_FEATURE_EDX_VME RT_BIT_32(1) +%define X86_CPUID_FEATURE_EDX_DE RT_BIT_32(2) +%define X86_CPUID_FEATURE_EDX_PSE RT_BIT_32(3) +%define X86_CPUID_FEATURE_EDX_PSE_BIT 3 +%define X86_CPUID_FEATURE_EDX_TSC RT_BIT_32(4) +%define X86_CPUID_FEATURE_EDX_MSR RT_BIT_32(5) +%define X86_CPUID_FEATURE_EDX_PAE RT_BIT_32(6) +%define X86_CPUID_FEATURE_EDX_PAE_BIT 6 +%define X86_CPUID_FEATURE_EDX_MCE RT_BIT_32(7) +%define X86_CPUID_FEATURE_EDX_CX8 RT_BIT_32(8) +%define X86_CPUID_FEATURE_EDX_APIC RT_BIT_32(9) +%define X86_CPUID_FEATURE_EDX_SEP RT_BIT_32(11) +%define X86_CPUID_FEATURE_EDX_MTRR RT_BIT_32(12) +%define X86_CPUID_FEATURE_EDX_PGE RT_BIT_32(13) +%define X86_CPUID_FEATURE_EDX_MCA RT_BIT_32(14) +%define X86_CPUID_FEATURE_EDX_CMOV RT_BIT_32(15) +%define X86_CPUID_FEATURE_EDX_PAT RT_BIT_32(16) +%define X86_CPUID_FEATURE_EDX_PSE36 RT_BIT_32(17) +%define X86_CPUID_FEATURE_EDX_PSN RT_BIT_32(18) +%define X86_CPUID_FEATURE_EDX_CLFSH RT_BIT_32(19) +%define X86_CPUID_FEATURE_EDX_DS RT_BIT_32(21) +%define X86_CPUID_FEATURE_EDX_ACPI RT_BIT_32(22) +%define X86_CPUID_FEATURE_EDX_MMX RT_BIT_32(23) +%define X86_CPUID_FEATURE_EDX_FXSR RT_BIT_32(24) +%define X86_CPUID_FEATURE_EDX_SSE RT_BIT_32(25) +%define X86_CPUID_FEATURE_EDX_SSE2 RT_BIT_32(26) +%define X86_CPUID_FEATURE_EDX_SS RT_BIT_32(27) +%define X86_CPUID_FEATURE_EDX_HTT RT_BIT_32(28) +%define X86_CPUID_FEATURE_EDX_TM RT_BIT_32(29) +%define X86_CPUID_FEATURE_EDX_PBE RT_BIT_32(31) +%define X86_CPUID_MWAIT_ECX_EXT RT_BIT_32(0) +%define X86_CPUID_MWAIT_ECX_BREAKIRQIF0 RT_BIT_32(1) +%define X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE RT_BIT_32(0) +%define X86_CPUID_STEXT_FEATURE_EBX_TSC_ADJUST RT_BIT_32(1) +%define X86_CPUID_STEXT_FEATURE_EBX_SGX RT_BIT_32(2) +%define X86_CPUID_STEXT_FEATURE_EBX_BMI1 RT_BIT_32(3) +%define X86_CPUID_STEXT_FEATURE_EBX_HLE RT_BIT_32(4) +%define X86_CPUID_STEXT_FEATURE_EBX_AVX2 RT_BIT_32(5) +%define X86_CPUID_STEXT_FEATURE_EBX_FDP_EXCPTN_ONLY RT_BIT_32(6) +%define X86_CPUID_STEXT_FEATURE_EBX_SMEP RT_BIT_32(7) +%define X86_CPUID_STEXT_FEATURE_EBX_BMI2 RT_BIT_32(8) +%define X86_CPUID_STEXT_FEATURE_EBX_ERMS RT_BIT_32(9) +%define X86_CPUID_STEXT_FEATURE_EBX_INVPCID RT_BIT_32(10) +%define X86_CPUID_STEXT_FEATURE_EBX_RTM RT_BIT_32(11) +%define X86_CPUID_STEXT_FEATURE_EBX_PQM RT_BIT_32(12) +%define X86_CPUID_STEXT_FEATURE_EBX_DEPR_FPU_CS_DS RT_BIT_32(13) +%define X86_CPUID_STEXT_FEATURE_EBX_MPE RT_BIT_32(14) +%define X86_CPUID_STEXT_FEATURE_EBX_PQE RT_BIT_32(15) +%define X86_CPUID_STEXT_FEATURE_EBX_AVX512F RT_BIT_32(16) +%define X86_CPUID_STEXT_FEATURE_EBX_RDSEED RT_BIT_32(18) +%define X86_CPUID_STEXT_FEATURE_EBX_ADX RT_BIT_32(19) +%define X86_CPUID_STEXT_FEATURE_EBX_SMAP RT_BIT_32(20) +%define X86_CPUID_STEXT_FEATURE_EBX_CLFLUSHOPT RT_BIT_32(23) +%define X86_CPUID_STEXT_FEATURE_EBX_INTEL_PT RT_BIT_32(25) +%define X86_CPUID_STEXT_FEATURE_EBX_AVX512PF RT_BIT_32(26) +%define X86_CPUID_STEXT_FEATURE_EBX_AVX512ER RT_BIT_32(27) +%define X86_CPUID_STEXT_FEATURE_EBX_AVX512CD RT_BIT_32(28) +%define X86_CPUID_STEXT_FEATURE_EBX_SHA RT_BIT_32(29) +%define X86_CPUID_STEXT_FEATURE_ECX_PREFETCHWT1 RT_BIT_32(0) +%define X86_CPUID_STEXT_FEATURE_ECX_UMIP RT_BIT_32(2) +%define X86_CPUID_STEXT_FEATURE_ECX_PKU RT_BIT_32(3) +%define X86_CPUID_STEXT_FEATURE_ECX_OSPKE RT_BIT_32(4) +%define X86_CPUID_STEXT_FEATURE_ECX_MAWAU 0x003e0000 +%define X86_CPUID_STEXT_FEATURE_ECX_RDPID RT_BIT_32(2) +%define X86_CPUID_STEXT_FEATURE_ECX_SGX_LC RT_BIT_32(30) +%define X86_CPUID_STEXT_FEATURE_EDX_MD_CLEAR RT_BIT_32(10) +%define X86_CPUID_STEXT_FEATURE_EDX_IBRS_IBPB RT_BIT_32(26) +%define X86_CPUID_STEXT_FEATURE_EDX_STIBP RT_BIT_32(27) +%define X86_CPUID_STEXT_FEATURE_EDX_FLUSH_CMD RT_BIT_32(28) +%define X86_CPUID_STEXT_FEATURE_EDX_ARCHCAP RT_BIT_32(29) +%define X86_CPUID_STEXT_FEATURE_EDX_SSBD RT_BIT_32(31) +%define X86_CPUID_EXT_FEATURE_ECX_LAHF_SAHF RT_BIT_32(0) +%define X86_CPUID_EXT_FEATURE_EDX_SYSCALL RT_BIT_32(11) +%define X86_CPUID_EXT_FEATURE_EDX_NX RT_BIT_32(20) +%define X86_CPUID_EXT_FEATURE_EDX_PAGE1GB RT_BIT_32(26) +%define X86_CPUID_EXT_FEATURE_EDX_RDTSCP RT_BIT_32(27) +%define X86_CPUID_EXT_FEATURE_EDX_LONG_MODE RT_BIT_32(29) +%define X86_CPUID_AMD_FEATURE_EDX_FPU RT_BIT_32(0) +%define X86_CPUID_AMD_FEATURE_EDX_VME RT_BIT_32(1) +%define X86_CPUID_AMD_FEATURE_EDX_DE RT_BIT_32(2) +%define X86_CPUID_AMD_FEATURE_EDX_PSE RT_BIT_32(3) +%define X86_CPUID_AMD_FEATURE_EDX_TSC RT_BIT_32(4) +%define X86_CPUID_AMD_FEATURE_EDX_MSR RT_BIT_32(5) +%define X86_CPUID_AMD_FEATURE_EDX_PAE RT_BIT_32(6) +%define X86_CPUID_AMD_FEATURE_EDX_MCE RT_BIT_32(7) +%define X86_CPUID_AMD_FEATURE_EDX_CX8 RT_BIT_32(8) +%define X86_CPUID_AMD_FEATURE_EDX_APIC RT_BIT_32(9) +%define X86_CPUID_AMD_FEATURE_EDX_MTRR RT_BIT_32(12) +%define X86_CPUID_AMD_FEATURE_EDX_PGE RT_BIT_32(13) +%define X86_CPUID_AMD_FEATURE_EDX_MCA RT_BIT_32(14) +%define X86_CPUID_AMD_FEATURE_EDX_CMOV RT_BIT_32(15) +%define X86_CPUID_AMD_FEATURE_EDX_PAT RT_BIT_32(16) +%define X86_CPUID_AMD_FEATURE_EDX_PSE36 RT_BIT_32(17) +%define X86_CPUID_AMD_FEATURE_EDX_AXMMX RT_BIT_32(22) +%define X86_CPUID_AMD_FEATURE_EDX_MMX RT_BIT_32(23) +%define X86_CPUID_AMD_FEATURE_EDX_FXSR RT_BIT_32(24) +%define X86_CPUID_AMD_FEATURE_EDX_FFXSR RT_BIT_32(25) +%define X86_CPUID_AMD_FEATURE_EDX_3DNOW_EX RT_BIT_32(30) +%define X86_CPUID_AMD_FEATURE_EDX_3DNOW RT_BIT_32(31) +%define X86_CPUID_AMD_FEATURE_ECX_CMPL RT_BIT_32(1) +%define X86_CPUID_AMD_FEATURE_ECX_SVM RT_BIT_32(2) +%define X86_CPUID_AMD_FEATURE_ECX_EXT_APIC RT_BIT_32(3) +%define X86_CPUID_AMD_FEATURE_ECX_CR8L RT_BIT_32(4) +%define X86_CPUID_AMD_FEATURE_ECX_ABM RT_BIT_32(5) +%define X86_CPUID_AMD_FEATURE_ECX_SSE4A RT_BIT_32(6) +%define X86_CPUID_AMD_FEATURE_ECX_MISALNSSE RT_BIT_32(7) +%define X86_CPUID_AMD_FEATURE_ECX_3DNOWPRF RT_BIT_32(8) +%define X86_CPUID_AMD_FEATURE_ECX_OSVW RT_BIT_32(9) +%define X86_CPUID_AMD_FEATURE_ECX_IBS RT_BIT_32(10) +%define X86_CPUID_AMD_FEATURE_ECX_XOP RT_BIT_32(11) +%define X86_CPUID_AMD_FEATURE_ECX_SKINIT RT_BIT_32(12) +%define X86_CPUID_AMD_FEATURE_ECX_WDT RT_BIT_32(13) +%define X86_CPUID_AMD_FEATURE_ECX_LWP RT_BIT_32(15) +%define X86_CPUID_AMD_FEATURE_ECX_FMA4 RT_BIT_32(16) +%define X86_CPUID_AMD_FEATURE_ECX_NODEID RT_BIT_32(19) +%define X86_CPUID_AMD_FEATURE_ECX_TBM RT_BIT_32(21) +%define X86_CPUID_AMD_FEATURE_ECX_TOPOEXT RT_BIT_32(22) +%define X86_CPUID_AMD_ADVPOWER_EDX_TS RT_BIT_32(0) +%define X86_CPUID_AMD_ADVPOWER_EDX_FID RT_BIT_32(1) +%define X86_CPUID_AMD_ADVPOWER_EDX_VID RT_BIT_32(2) +%define X86_CPUID_AMD_ADVPOWER_EDX_TTP RT_BIT_32(3) +%define X86_CPUID_AMD_ADVPOWER_EDX_TM RT_BIT_32(4) +%define X86_CPUID_AMD_ADVPOWER_EDX_STC RT_BIT_32(5) +%define X86_CPUID_AMD_ADVPOWER_EDX_MC RT_BIT_32(6) +%define X86_CPUID_AMD_ADVPOWER_EDX_HWPSTATE RT_BIT_32(7) +%define X86_CPUID_AMD_ADVPOWER_EDX_TSCINVAR RT_BIT_32(8) +%define X86_CPUID_AMD_ADVPOWER_EDX_CPB RT_BIT_32(9) +%define X86_CPUID_AMD_ADVPOWER_EDX_EFRO RT_BIT_32(10) +%define X86_CPUID_AMD_ADVPOWER_EDX_PFI RT_BIT_32(11) +%define X86_CPUID_AMD_ADVPOWER_EDX_PA RT_BIT_32(12) +%define X86_CPUID_AMD_EFEID_EBX_CLZERO RT_BIT_32(0) +%define X86_CPUID_AMD_EFEID_EBX_IRPERF RT_BIT_32(1) +%define X86_CPUID_AMD_EFEID_EBX_XSAVE_ER_PTR RT_BIT_32(2) +%define X86_CPUID_AMD_EFEID_EBX_RDPRU RT_BIT_32(4) +%define X86_CPUID_AMD_EFEID_EBX_MCOMMIT RT_BIT_32(8) +%define X86_CPUID_AMD_EFEID_EBX_IBPB RT_BIT_32(12) +%define X86_CPUID_AMD_EFEID_EBX_IBRS RT_BIT_32(14) +%define X86_CPUID_AMD_EFEID_EBX_STIBP RT_BIT_32(15) +%define X86_CPUID_AMD_EFEID_EBX_IBRS_ALWAYS_ON RT_BIT_32(16) +%define X86_CPUID_AMD_EFEID_EBX_STIBP_ALWAYS_ON RT_BIT_32(17) +%define X86_CPUID_AMD_EFEID_EBX_IBRS_PREFERRED RT_BIT_32(18) +%define X86_CPUID_AMD_EFEID_EBX_SPEC_CTRL_SSBD RT_BIT_32(24) +%define X86_CPUID_AMD_EFEID_EBX_VIRT_SPEC_CTRL_SSBD RT_BIT_32(25) +%define X86_CPUID_AMD_EFEID_EBX_NO_SSBD_REQUIRED RT_BIT_32(26) +%define X86_CPUID_SVM_FEATURE_EDX_NESTED_PAGING RT_BIT(0) +%define X86_CPUID_SVM_FEATURE_EDX_LBR_VIRT RT_BIT(1) +%define X86_CPUID_SVM_FEATURE_EDX_SVM_LOCK RT_BIT(2) +%define X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE RT_BIT(3) +%define X86_CPUID_SVM_FEATURE_EDX_TSC_RATE_MSR RT_BIT(4) +%define X86_CPUID_SVM_FEATURE_EDX_VMCB_CLEAN RT_BIT(5) +%define X86_CPUID_SVM_FEATURE_EDX_FLUSH_BY_ASID RT_BIT(6) +%define X86_CPUID_SVM_FEATURE_EDX_DECODE_ASSISTS RT_BIT(7) +%define X86_CPUID_SVM_FEATURE_EDX_PAUSE_FILTER RT_BIT(10) +%define X86_CPUID_SVM_FEATURE_EDX_PAUSE_FILTER_THRESHOLD RT_BIT(12) +%define X86_CPUID_SVM_FEATURE_EDX_AVIC RT_BIT(13) +%define X86_CPUID_SVM_FEATURE_EDX_VIRT_VMSAVE_VMLOAD RT_BIT(15) +%define X86_CPUID_SVM_FEATURE_EDX_VGIF RT_BIT(16) +%define X86_CPUID_SVM_FEATURE_EDX_GMET RT_BIT(17) +%define X86_CPUID_SVM_FEATURE_EDX_SSSCHECK RT_BIT(19) +%define X86_CPUID_SVM_FEATURE_EDX_SPEC_CTRL RT_BIT(20) +%define X86_CPUID_SVM_FEATURE_EDX_HOST_MCE_OVERRIDE RT_BIT(23) +%define X86_CPUID_SVM_FEATURE_EDX_TLBICTL RT_BIT(24) +%define X86_CR0_PE RT_BIT_32(0) +%define X86_CR0_PROTECTION_ENABLE RT_BIT_32(0) +%define X86_CR0_MP RT_BIT_32(1) +%define X86_CR0_MONITOR_COPROCESSOR RT_BIT_32(1) +%define X86_CR0_EM RT_BIT_32(2) +%define X86_CR0_EMULATE_FPU RT_BIT_32(2) +%define X86_CR0_TS RT_BIT_32(3) +%define X86_CR0_TASK_SWITCH RT_BIT_32(3) +%define X86_CR0_ET RT_BIT_32(4) +%define X86_CR0_EXTENSION_TYPE RT_BIT_32(4) +%define X86_CR0_NE RT_BIT_32(5) +%define X86_CR0_NUMERIC_ERROR RT_BIT_32(5) +%define X86_CR0_WP RT_BIT_32(16) +%define X86_CR0_WRITE_PROTECT RT_BIT_32(16) +%define X86_CR0_AM RT_BIT_32(18) +%define X86_CR0_ALIGMENT_MASK RT_BIT_32(18) +%define X86_CR0_NW RT_BIT_32(29) +%define X86_CR0_NOT_WRITE_THROUGH RT_BIT_32(29) +%define X86_CR0_CD RT_BIT_32(30) +%define X86_CR0_CACHE_DISABLE RT_BIT_32(30) +%define X86_CR0_PG RT_BIT_32(31) +%define X86_CR0_PAGING RT_BIT_32(31) +%define X86_CR0_BIT_PG 31 +%define X86_CR3_PWT RT_BIT_32(3) +%define X86_CR3_PCD RT_BIT_32(4) +%define X86_CR3_PAGE_MASK (0xfffff000) +%define X86_CR3_PAE_PAGE_MASK (0xffffffe0) +%define X86_CR3_AMD64_PAGE_MASK 0x000ffffffffff000 +%define X86_CR3_EPT_PAGE_MASK 0x0000fffffffff000 +%define X86_CR4_VME RT_BIT_32(0) +%define X86_CR4_PVI RT_BIT_32(1) +%define X86_CR4_TSD RT_BIT_32(2) +%define X86_CR4_DE RT_BIT_32(3) +%define X86_CR4_PSE RT_BIT_32(4) +%define X86_CR4_PAE RT_BIT_32(5) +%define X86_CR4_MCE RT_BIT_32(6) +%define X86_CR4_PGE RT_BIT_32(7) +%define X86_CR4_PCE RT_BIT_32(8) +%define X86_CR4_OSFXSR RT_BIT_32(9) +%define X86_CR4_OSXMMEEXCPT RT_BIT_32(10) +%define X86_CR4_UMIP RT_BIT_32(11) +%define X86_CR4_VMXE RT_BIT_32(13) +%define X86_CR4_SMXE RT_BIT_32(14) +%define X86_CR4_FSGSBASE RT_BIT_32(16) +%define X86_CR4_PCIDE RT_BIT_32(17) +%define X86_CR4_OSXSAVE RT_BIT_32(18) +%define X86_CR4_SMEP RT_BIT_32(20) +%define X86_CR4_SMAP RT_BIT_32(21) +%define X86_CR4_PKE RT_BIT_32(22) +%define X86_CR4_CET RT_BIT_32(23) +%define X86_DR6_B0 RT_BIT_32(0) +%define X86_DR6_B1 RT_BIT_32(1) +%define X86_DR6_B2 RT_BIT_32(2) +%define X86_DR6_B3 RT_BIT_32(3) +%define X86_DR6_B_MASK 0x0000000f +%define X86_DR6_BD RT_BIT_32(13) +%define X86_DR6_BS RT_BIT_32(14) +%define X86_DR6_BT RT_BIT_32(15) +%define X86_DR6_RTM RT_BIT_32(16) +%define X86_DR6_INIT_VAL 0xffff0ff0 +%define X86_DR6_RA1_MASK 0xffff0ff0 +%define X86_DR6_RA1_MASK_RTM 0xfffe0ff0 +%define X86_DR6_RAZ_MASK RT_BIT_64(12) +%define X86_DR6_MBZ_MASK 0xffffffff00000000 +%define X86_DR6_B(iBp) RT_BIT_64(iBp) +%define X86_DR7_L0 RT_BIT_32(0) +%define X86_DR7_G0 RT_BIT_32(1) +%define X86_DR7_L1 RT_BIT_32(2) +%define X86_DR7_G1 RT_BIT_32(3) +%define X86_DR7_L2 RT_BIT_32(4) +%define X86_DR7_G2 RT_BIT_32(5) +%define X86_DR7_L3 RT_BIT_32(6) +%define X86_DR7_G3 RT_BIT_32(7) +%define X86_DR7_LE RT_BIT_32(8) +%define X86_DR7_GE RT_BIT_32(9) +%define X86_DR7_LE_ALL 0x0000000000000055 +%define X86_DR7_GE_ALL 0x00000000000000aa +%define X86_DR7_RTM RT_BIT_32(11) +%define X86_DR7_ICE_IR RT_BIT_32(12) +%define X86_DR7_GD RT_BIT_32(13) +%define X86_DR7_ICE_TR1 RT_BIT_32(14) +%define X86_DR7_ICE_TR2 RT_BIT_32(15) +%define X86_DR7_RW0_MASK (3 << 16) +%define X86_DR7_LEN0_MASK (3 << 18) +%define X86_DR7_RW1_MASK (3 << 20) +%define X86_DR7_LEN1_MASK (3 << 22) +%define X86_DR7_RW2_MASK (3 << 24) +%define X86_DR7_LEN2_MASK (3 << 26) +%define X86_DR7_RW3_MASK (3 << 28) +%define X86_DR7_LEN3_MASK (3 << 30) +%define X86_DR7_RA1_MASK RT_BIT_32(10) +%define X86_DR7_RAZ_MASK 0x0000d800 +%define X86_DR7_MBZ_MASK 0xffffffff00000000 +%define X86_DR7_L(iBp) ( 1 << (iBp * 2) ) +%define X86_DR7_G(iBp) ( 1 << (iBp * 2 + 1) ) +%define X86_DR7_L_G(iBp) ( 3 << (iBp * 2) ) +%define X86_DR7_RW_EO 0 +%define X86_DR7_RW_WO 1 +%define X86_DR7_RW_IO 2 +%define X86_DR7_RW_RW 3 +%define X86_DR7_RW(iBp, fRw) ( (fRw) << ((iBp) * 4 + 16) ) +%define X86_DR7_GET_RW(uDR7, iBp) ( ( (uDR7) >> ((iBp) * 4 + 16) ) & 3 ) +%define X86_DR7_RW_ALL_MASKS 0x33330000 +%ifndef VBOX_FOR_DTRACE_LIB + %define X86_DR7_ANY_RW_IO(uDR7) \ + ( ( 0x22220000 & (uDR7) ) +%endif +%define X86_DR7_LEN_BYTE 0 +%define X86_DR7_LEN_WORD 1 +%define X86_DR7_LEN_QWORD 2 +%define X86_DR7_LEN_DWORD 3 +%define X86_DR7_LEN(iBp, cb) ( (cb) << ((iBp) * 4 + 18) ) +%define X86_DR7_GET_LEN(uDR7, iBp) ( ( (uDR7) >> ((iBp) * 4 + 18) ) & 0x3 ) +%define X86_DR7_ENABLED_MASK 0x000000ff +%define X86_DR7_LEN_ALL_MASKS 0xcccc0000 +%define X86_DR7_RW_LEN_ALL_MASKS 0xffff0000 +%define X86_DR7_INIT_VAL 0x400 +%define MSR_P5_MC_ADDR 0x00000000 +%define MSR_P5_MC_TYPE 0x00000001 +%define MSR_IA32_TSC 0x10 +%define MSR_IA32_CESR 0x00000011 +%define MSR_IA32_CTR0 0x00000012 +%define MSR_IA32_CTR1 0x00000013 +%define MSR_IA32_PLATFORM_ID 0x17 +%ifndef MSR_IA32_APICBASE + %define MSR_IA32_APICBASE 0x1b + %define MSR_IA32_APICBASE_EN RT_BIT_64(11) + %define MSR_IA32_APICBASE_EXTD RT_BIT_64(10) + %define MSR_IA32_APICBASE_BSP RT_BIT_64(8) + %define MSR_IA32_APICBASE_BASE_MIN 0x0000000ffffff000 + %define MSR_IA32_APICBASE_ADDR 0x00000000fee00000 + %define MSR_IA32_APICBASE_GET_ADDR(a_Msr) ((a_Msr) & X86_PAGE_4K_BASE_MASK) +%endif +%define MSR_CORE_THREAD_COUNT 0x35 +%define MSR_IA32_FEATURE_CONTROL 0x3A +%define MSR_IA32_FEATURE_CONTROL_LOCK RT_BIT_64(0) +%define MSR_IA32_FEATURE_CONTROL_SMX_VMXON RT_BIT_64(1) +%define MSR_IA32_FEATURE_CONTROL_VMXON RT_BIT_64(2) +%define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_0 RT_BIT_64(8) +%define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_1 RT_BIT_64(9) +%define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_2 RT_BIT_64(10) +%define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_3 RT_BIT_64(11) +%define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_4 RT_BIT_64(12) +%define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_5 RT_BIT_64(13) +%define MSR_IA32_FEATURE_CONTROL_SENTER_LOCAL_FN_6 RT_BIT_64(14) +%define MSR_IA32_FEATURE_CONTROL_SENTER_GLOBAL_EN RT_BIT_64(15) +%define MSR_IA32_FEATURE_CONTROL_SGX_LAUNCH_EN RT_BIT_64(17) +%define MSR_IA32_FEATURE_CONTROL_SGX_GLOBAL_EN RT_BIT_64(18) +%define MSR_IA32_FEATURE_CONTROL_LMCE RT_BIT_64(20) +%define MSR_IA32_TSC_ADJUST 0x3B +%define MSR_IA32_SPEC_CTRL 0x48 +%define MSR_IA32_SPEC_CTRL_F_IBRS RT_BIT_32(0) +%define MSR_IA32_SPEC_CTRL_F_STIBP RT_BIT_32(1) +%define MSR_IA32_SPEC_CTRL_F_SSBD RT_BIT_32(2) +%define MSR_IA32_PRED_CMD 0x49 +%define MSR_IA32_PRED_CMD_F_IBPB RT_BIT_32(0) +%define MSR_IA32_BIOS_UPDT_TRIG 0x79 +%define MSR_IA32_BIOS_SIGN_ID 0x8B +%define MSR_IA32_SMM_MONITOR_CTL 0x9B +%define MSR_IA32_SMM_MONITOR_VALID RT_BIT_64(0) +%define MSR_IA32_SMM_MONITOR_VMXOFF_UNBLOCK_SMI RT_BIT_64(2) +%define MSR_IA32_SMM_MONITOR_MSGEG_PHYSADDR(a) (((a) >> 12) & 0xfffff) +%define MSR_IA32_SMBASE 0x9E +%define MSR_IA32_PMC0 0xC1 +%define MSR_IA32_PMC1 0xC2 +%define MSR_IA32_PMC2 0xC3 +%define MSR_IA32_PMC3 0xC4 +%define MSR_IA32_PMC4 0xC5 +%define MSR_IA32_PMC5 0xC6 +%define MSR_IA32_PMC6 0xC7 +%define MSR_IA32_PMC7 0xC8 +%define MSR_IA32_PLATFORM_INFO 0xCE +%define MSR_IA32_FSB_CLOCK_STS 0xCD +%define MSR_PKG_CST_CONFIG_CONTROL 0x000000e2 +%define MSR_IA32_MPERF 0xE7 +%define MSR_IA32_APERF 0xE8 +%define MSR_IA32_MTRR_CAP 0xFE +%define MSR_IA32_ARCH_CAPABILITIES 0x10a +%define MSR_IA32_ARCH_CAP_F_RDCL_NO RT_BIT_32(0) +%define MSR_IA32_ARCH_CAP_F_IBRS_ALL RT_BIT_32(1) +%define MSR_IA32_ARCH_CAP_F_RSBO RT_BIT_32(2) +%define MSR_IA32_ARCH_CAP_F_VMM_NEED_NOT_FLUSH_L1D RT_BIT_32(3) +%define MSR_IA32_ARCH_CAP_F_MDS_NO RT_BIT_32(4) +%define MSR_IA32_FLUSH_CMD 0x10b +%define MSR_IA32_FLUSH_CMD_F_L1D RT_BIT_32(0) +%define MSR_BBL_CR_CTL3 0x11e +%ifndef MSR_IA32_SYSENTER_CS +%define MSR_IA32_SYSENTER_CS 0x174 +%define MSR_IA32_SYSENTER_ESP 0x175 +%define MSR_IA32_SYSENTER_EIP 0x176 +%endif +%define MSR_IA32_MCG_CAP 0x179 +%define MSR_IA32_MCG_STATUS 0x17A +%define MSR_IA32_MCG_CTRL 0x17B +%define MSR_IA32_CR_PAT 0x277 +%define MSR_IA32_CR_PAT_INIT_VAL 0x0007040600070406 +%define MSR_IA32_PERFEVTSEL0 0x186 +%define MSR_IA32_PERFEVTSEL1 0x187 +%define MSR_IA32_PERFEVTSEL2 0x188 +%define MSR_IA32_PERFEVTSEL3 0x189 +%define MSR_FLEX_RATIO 0x194 +%define MSR_IA32_PERF_STATUS 0x198 +%define MSR_IA32_PERF_CTL 0x199 +%define MSR_IA32_THERM_STATUS 0x19c +%define MSR_OFFCORE_RSP_0 0x1a6 +%define MSR_OFFCORE_RSP_1 0x1a7 +%define MSR_IA32_MISC_ENABLE 0x1A0 +%define MSR_IA32_MISC_ENABLE_FAST_STRINGS RT_BIT_64(0) +%define MSR_IA32_MISC_ENABLE_TCC RT_BIT_64(3) +%define MSR_IA32_MISC_ENABLE_PERF_MON RT_BIT_64(7) +%define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL RT_BIT_64(11) +%define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL RT_BIT_64(12) +%define MSR_IA32_MISC_ENABLE_SST_ENABLE RT_BIT_64(16) +%define MSR_IA32_MISC_ENABLE_MONITOR RT_BIT_64(18) +%define MSR_IA32_MISC_ENABLE_LIMIT_CPUID RT_BIT_64(22) +%define MSR_IA32_MISC_ENABLE_XTPR_MSG_DISABLE RT_BIT_64(23) +%define MSR_IA32_MISC_ENABLE_XD_DISABLE RT_BIT_64(34) +%define MSR_IA32_DEBUGCTL 0x000001d9 +%define MSR_IA32_DEBUGCTL_LBR RT_BIT_64(0) +%define MSR_IA32_DEBUGCTL_BTF RT_BIT_64(1) +%define MSR_IA32_DEBUGCTL_PB0 RT_BIT_64(2) +%define MSR_IA32_DEBUGCTL_PB1 RT_BIT_64(3) +%define MSR_IA32_DEBUGCTL_PB2 RT_BIT_64(4) +%define MSR_IA32_DEBUGCTL_PB3 RT_BIT_64(5) +%define MSR_IA32_DEBUGCTL_TR RT_BIT_64(6) +%define MSR_IA32_DEBUGCTL_BTS RT_BIT_64(7) +%define MSR_IA32_DEBUGCTL_BTINT RT_BIT_64(8) +%define MSR_IA32_DEBUGCTL_BTS_OFF_OS RT_BIT_64(9) +%define MSR_IA32_DEBUGCTL_BTS_OFF_USER RT_BIT_64(10) +%define MSR_IA32_DEBUGCTL_FREEZE_LBR_ON_PMI RT_BIT_64(11) +%define MSR_IA32_DEBUGCTL_FREEZE_PERFMON_ON_PMI RT_BIT_64(12) +%define MSR_IA32_DEBUGCTL_FREEZE_WHILE_SMM_EM RT_BIT_64(14) +%define MSR_IA32_DEBUGCTL_RTM RT_BIT_64(15) +%define MSR_IA32_DEBUGCTL_VALID_MASK_INTEL ( MSR_IA32_DEBUGCTL_LBR | MSR_IA32_DEBUGCTL_BTF | MSR_IA32_DEBUGCTL_TR \ + | MSR_IA32_DEBUGCTL_BTS | MSR_IA32_DEBUGCTL_BTINT | MSR_IA32_DEBUGCTL_BTS_OFF_OS \ + | MSR_IA32_DEBUGCTL_BTS_OFF_USER | MSR_IA32_DEBUGCTL_FREEZE_LBR_ON_PMI \ + | MSR_IA32_DEBUGCTL_FREEZE_PERFMON_ON_PMI | MSR_IA32_DEBUGCTL_FREEZE_WHILE_SMM_EM \ + | MSR_IA32_DEBUGCTL_RTM) +%define MSR_P4_LASTBRANCH_0 0x1db +%define MSR_P4_LASTBRANCH_1 0x1dc +%define MSR_P4_LASTBRANCH_2 0x1dd +%define MSR_P4_LASTBRANCH_3 0x1de +%define MSR_P4_LASTBRANCH_TOS 0x1da +%define MSR_CORE2_LASTBRANCH_0_FROM_IP 0x40 +%define MSR_CORE2_LASTBRANCH_1_FROM_IP 0x41 +%define MSR_CORE2_LASTBRANCH_2_FROM_IP 0x42 +%define MSR_CORE2_LASTBRANCH_3_FROM_IP 0x43 +%define MSR_CORE2_LASTBRANCH_0_TO_IP 0x60 +%define MSR_CORE2_LASTBRANCH_1_TO_IP 0x61 +%define MSR_CORE2_LASTBRANCH_2_TO_IP 0x62 +%define MSR_CORE2_LASTBRANCH_3_TO_IP 0x63 +%define MSR_CORE2_LASTBRANCH_TOS 0x1c9 +%define MSR_LASTBRANCH_0_FROM_IP 0x680 +%define MSR_LASTBRANCH_1_FROM_IP 0x681 +%define MSR_LASTBRANCH_2_FROM_IP 0x682 +%define MSR_LASTBRANCH_3_FROM_IP 0x683 +%define MSR_LASTBRANCH_4_FROM_IP 0x684 +%define MSR_LASTBRANCH_5_FROM_IP 0x685 +%define MSR_LASTBRANCH_6_FROM_IP 0x686 +%define MSR_LASTBRANCH_7_FROM_IP 0x687 +%define MSR_LASTBRANCH_8_FROM_IP 0x688 +%define MSR_LASTBRANCH_9_FROM_IP 0x689 +%define MSR_LASTBRANCH_10_FROM_IP 0x68a +%define MSR_LASTBRANCH_11_FROM_IP 0x68b +%define MSR_LASTBRANCH_12_FROM_IP 0x68c +%define MSR_LASTBRANCH_13_FROM_IP 0x68d +%define MSR_LASTBRANCH_14_FROM_IP 0x68e +%define MSR_LASTBRANCH_15_FROM_IP 0x68f +%define MSR_LASTBRANCH_16_FROM_IP 0x690 +%define MSR_LASTBRANCH_17_FROM_IP 0x691 +%define MSR_LASTBRANCH_18_FROM_IP 0x692 +%define MSR_LASTBRANCH_19_FROM_IP 0x693 +%define MSR_LASTBRANCH_20_FROM_IP 0x694 +%define MSR_LASTBRANCH_21_FROM_IP 0x695 +%define MSR_LASTBRANCH_22_FROM_IP 0x696 +%define MSR_LASTBRANCH_23_FROM_IP 0x697 +%define MSR_LASTBRANCH_24_FROM_IP 0x698 +%define MSR_LASTBRANCH_25_FROM_IP 0x699 +%define MSR_LASTBRANCH_26_FROM_IP 0x69a +%define MSR_LASTBRANCH_27_FROM_IP 0x69b +%define MSR_LASTBRANCH_28_FROM_IP 0x69c +%define MSR_LASTBRANCH_29_FROM_IP 0x69d +%define MSR_LASTBRANCH_30_FROM_IP 0x69e +%define MSR_LASTBRANCH_31_FROM_IP 0x69f +%define MSR_LASTBRANCH_0_TO_IP 0x6c0 +%define MSR_LASTBRANCH_1_TO_IP 0x6c1 +%define MSR_LASTBRANCH_2_TO_IP 0x6c2 +%define MSR_LASTBRANCH_3_TO_IP 0x6c3 +%define MSR_LASTBRANCH_4_TO_IP 0x6c4 +%define MSR_LASTBRANCH_5_TO_IP 0x6c5 +%define MSR_LASTBRANCH_6_TO_IP 0x6c6 +%define MSR_LASTBRANCH_7_TO_IP 0x6c7 +%define MSR_LASTBRANCH_8_TO_IP 0x6c8 +%define MSR_LASTBRANCH_9_TO_IP 0x6c9 +%define MSR_LASTBRANCH_10_TO_IP 0x6ca +%define MSR_LASTBRANCH_11_TO_IP 0x6cb +%define MSR_LASTBRANCH_12_TO_IP 0x6cc +%define MSR_LASTBRANCH_13_TO_IP 0x6cd +%define MSR_LASTBRANCH_14_TO_IP 0x6ce +%define MSR_LASTBRANCH_15_TO_IP 0x6cf +%define MSR_LASTBRANCH_16_TO_IP 0x6d0 +%define MSR_LASTBRANCH_17_TO_IP 0x6d1 +%define MSR_LASTBRANCH_18_TO_IP 0x6d2 +%define MSR_LASTBRANCH_19_TO_IP 0x6d3 +%define MSR_LASTBRANCH_20_TO_IP 0x6d4 +%define MSR_LASTBRANCH_21_TO_IP 0x6d5 +%define MSR_LASTBRANCH_22_TO_IP 0x6d6 +%define MSR_LASTBRANCH_23_TO_IP 0x6d7 +%define MSR_LASTBRANCH_24_TO_IP 0x6d8 +%define MSR_LASTBRANCH_25_TO_IP 0x6d9 +%define MSR_LASTBRANCH_26_TO_IP 0x6da +%define MSR_LASTBRANCH_27_TO_IP 0x6db +%define MSR_LASTBRANCH_28_TO_IP 0x6dc +%define MSR_LASTBRANCH_29_TO_IP 0x6dd +%define MSR_LASTBRANCH_30_TO_IP 0x6de +%define MSR_LASTBRANCH_31_TO_IP 0x6df +%define MSR_LASTBRANCH_0_INFO 0xdc0 +%define MSR_LASTBRANCH_1_INFO 0xdc1 +%define MSR_LASTBRANCH_2_INFO 0xdc2 +%define MSR_LASTBRANCH_3_INFO 0xdc3 +%define MSR_LASTBRANCH_4_INFO 0xdc4 +%define MSR_LASTBRANCH_5_INFO 0xdc5 +%define MSR_LASTBRANCH_6_INFO 0xdc6 +%define MSR_LASTBRANCH_7_INFO 0xdc7 +%define MSR_LASTBRANCH_8_INFO 0xdc8 +%define MSR_LASTBRANCH_9_INFO 0xdc9 +%define MSR_LASTBRANCH_10_INFO 0xdca +%define MSR_LASTBRANCH_11_INFO 0xdcb +%define MSR_LASTBRANCH_12_INFO 0xdcc +%define MSR_LASTBRANCH_13_INFO 0xdcd +%define MSR_LASTBRANCH_14_INFO 0xdce +%define MSR_LASTBRANCH_15_INFO 0xdcf +%define MSR_LASTBRANCH_16_INFO 0xdd0 +%define MSR_LASTBRANCH_17_INFO 0xdd1 +%define MSR_LASTBRANCH_18_INFO 0xdd2 +%define MSR_LASTBRANCH_19_INFO 0xdd3 +%define MSR_LASTBRANCH_20_INFO 0xdd4 +%define MSR_LASTBRANCH_21_INFO 0xdd5 +%define MSR_LASTBRANCH_22_INFO 0xdd6 +%define MSR_LASTBRANCH_23_INFO 0xdd7 +%define MSR_LASTBRANCH_24_INFO 0xdd8 +%define MSR_LASTBRANCH_25_INFO 0xdd9 +%define MSR_LASTBRANCH_26_INFO 0xdda +%define MSR_LASTBRANCH_27_INFO 0xddb +%define MSR_LASTBRANCH_28_INFO 0xddc +%define MSR_LASTBRANCH_29_INFO 0xddd +%define MSR_LASTBRANCH_30_INFO 0xdde +%define MSR_LASTBRANCH_31_INFO 0xddf +%define MSR_LASTBRANCH_SELECT 0x1c8 +%define MSR_LASTBRANCH_TOS 0x1c9 +%define MSR_LER_FROM_IP 0x1dd +%define MSR_LER_TO_IP 0x1de +%define MSR_IA32_TSX_CTRL 0x122 +%define MSR_IA32_MTRR_PHYSBASE0 0x200 +%define MSR_IA32_MTRR_PHYSMASK0 0x201 +%define MSR_IA32_MTRR_PHYSBASE1 0x202 +%define MSR_IA32_MTRR_PHYSMASK1 0x203 +%define MSR_IA32_MTRR_PHYSBASE2 0x204 +%define MSR_IA32_MTRR_PHYSMASK2 0x205 +%define MSR_IA32_MTRR_PHYSBASE3 0x206 +%define MSR_IA32_MTRR_PHYSMASK3 0x207 +%define MSR_IA32_MTRR_PHYSBASE4 0x208 +%define MSR_IA32_MTRR_PHYSMASK4 0x209 +%define MSR_IA32_MTRR_PHYSBASE5 0x20a +%define MSR_IA32_MTRR_PHYSMASK5 0x20b +%define MSR_IA32_MTRR_PHYSBASE6 0x20c +%define MSR_IA32_MTRR_PHYSMASK6 0x20d +%define MSR_IA32_MTRR_PHYSBASE7 0x20e +%define MSR_IA32_MTRR_PHYSMASK7 0x20f +%define MSR_IA32_MTRR_PHYSBASE8 0x210 +%define MSR_IA32_MTRR_PHYSMASK8 0x211 +%define MSR_IA32_MTRR_PHYSBASE9 0x212 +%define MSR_IA32_MTRR_PHYSMASK9 0x213 +%define MSR_IA32_MTRR_FIX64K_00000 0x250 +%define MSR_IA32_MTRR_FIX16K_80000 0x258 +%define MSR_IA32_MTRR_FIX16K_A0000 0x259 +%define MSR_IA32_MTRR_FIX4K_C0000 0x268 +%define MSR_IA32_MTRR_FIX4K_C8000 0x269 +%define MSR_IA32_MTRR_FIX4K_D0000 0x26a +%define MSR_IA32_MTRR_FIX4K_D8000 0x26b +%define MSR_IA32_MTRR_FIX4K_E0000 0x26c +%define MSR_IA32_MTRR_FIX4K_E8000 0x26d +%define MSR_IA32_MTRR_FIX4K_F0000 0x26e +%define MSR_IA32_MTRR_FIX4K_F8000 0x26f +%define MSR_IA32_MTRR_DEF_TYPE 0x2FF +%define MSR_IA32_PERF_GLOBAL_STATUS 0x38E +%define MSR_IA32_PERF_GLOBAL_CTRL 0x38F +%define MSR_IA32_PERF_GLOBAL_OVF_CTRL 0x390 +%define MSR_IA32_PEBS_ENABLE 0x3F1 +%define MSR_IA32_MC0_CTL 0x400 +%define MSR_IA32_MC0_STATUS 0x401 +%define MSR_IA32_VMX_BASIC 0x480 +%define MSR_IA32_VMX_PINBASED_CTLS 0x481 +%define MSR_IA32_VMX_PROCBASED_CTLS 0x482 +%define MSR_IA32_VMX_EXIT_CTLS 0x483 +%define MSR_IA32_VMX_ENTRY_CTLS 0x484 +%define MSR_IA32_VMX_MISC 0x485 +%define MSR_IA32_VMX_CR0_FIXED0 0x486 +%define MSR_IA32_VMX_CR0_FIXED1 0x487 +%define MSR_IA32_VMX_CR4_FIXED0 0x488 +%define MSR_IA32_VMX_CR4_FIXED1 0x489 +%define MSR_IA32_VMX_VMCS_ENUM 0x48A +%define MSR_IA32_VMX_PROCBASED_CTLS2 0x48B +%define MSR_IA32_VMX_EPT_VPID_CAP 0x48C +%define MSR_IA32_VMX_TRUE_PINBASED_CTLS 0x48D +%define MSR_IA32_VMX_TRUE_PROCBASED_CTLS 0x48E +%define MSR_IA32_VMX_TRUE_EXIT_CTLS 0x48F +%define MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x490 +%define MSR_IA32_VMX_VMFUNC 0x491 +%define MSR_IA32_VMX_PROCBASED_CTLS3 0x492 +%define MSR_IA32_RTIT_CTL 0x570 +%define MSR_IA32_DS_AREA 0x600 +%define MSR_RAPL_POWER_UNIT 0x606 +%define MSR_PKGC3_IRTL 0x60a +%define MSR_PKGC_IRTL1 0x60b +%define MSR_PKGC_IRTL2 0x60c +%define MSR_PKG_C2_RESIDENCY 0x60d +%define MSR_PKG_POWER_LIMIT 0x610 +%define MSR_PKG_ENERGY_STATUS 0x611 +%define MSR_PKG_PERF_STATUS 0x613 +%define MSR_PKG_POWER_INFO 0x614 +%define MSR_DRAM_POWER_LIMIT 0x618 +%define MSR_DRAM_ENERGY_STATUS 0x619 +%define MSR_DRAM_PERF_STATUS 0x61b +%define MSR_DRAM_POWER_INFO 0x61c +%define MSR_PKG_C10_RESIDENCY 0x632 +%define MSR_PP0_ENERGY_STATUS 0x639 +%define MSR_PP1_ENERGY_STATUS 0x641 +%define MSR_TURBO_ACTIVATION_RATIO 0x64c +%define MSR_CORE_PERF_LIMIT_REASONS 0x64f +%define MSR_IA32_X2APIC_START 0x800 +%define MSR_IA32_X2APIC_ID 0x802 +%define MSR_IA32_X2APIC_VERSION 0x803 +%define MSR_IA32_X2APIC_TPR 0x808 +%define MSR_IA32_X2APIC_PPR 0x80A +%define MSR_IA32_X2APIC_EOI 0x80B +%define MSR_IA32_X2APIC_LDR 0x80D +%define MSR_IA32_X2APIC_SVR 0x80F +%define MSR_IA32_X2APIC_ISR0 0x810 +%define MSR_IA32_X2APIC_ISR1 0x811 +%define MSR_IA32_X2APIC_ISR2 0x812 +%define MSR_IA32_X2APIC_ISR3 0x813 +%define MSR_IA32_X2APIC_ISR4 0x814 +%define MSR_IA32_X2APIC_ISR5 0x815 +%define MSR_IA32_X2APIC_ISR6 0x816 +%define MSR_IA32_X2APIC_ISR7 0x817 +%define MSR_IA32_X2APIC_TMR0 0x818 +%define MSR_IA32_X2APIC_TMR1 0x819 +%define MSR_IA32_X2APIC_TMR2 0x81A +%define MSR_IA32_X2APIC_TMR3 0x81B +%define MSR_IA32_X2APIC_TMR4 0x81C +%define MSR_IA32_X2APIC_TMR5 0x81D +%define MSR_IA32_X2APIC_TMR6 0x81E +%define MSR_IA32_X2APIC_TMR7 0x81F +%define MSR_IA32_X2APIC_IRR0 0x820 +%define MSR_IA32_X2APIC_IRR1 0x821 +%define MSR_IA32_X2APIC_IRR2 0x822 +%define MSR_IA32_X2APIC_IRR3 0x823 +%define MSR_IA32_X2APIC_IRR4 0x824 +%define MSR_IA32_X2APIC_IRR5 0x825 +%define MSR_IA32_X2APIC_IRR6 0x826 +%define MSR_IA32_X2APIC_IRR7 0x827 +%define MSR_IA32_X2APIC_ESR 0x828 +%define MSR_IA32_X2APIC_LVT_CMCI 0x82F +%define MSR_IA32_X2APIC_ICR 0x830 +%define MSR_IA32_X2APIC_LVT_TIMER 0x832 +%define MSR_IA32_X2APIC_LVT_THERMAL 0x833 +%define MSR_IA32_X2APIC_LVT_PERF 0x834 +%define MSR_IA32_X2APIC_LVT_LINT0 0x835 +%define MSR_IA32_X2APIC_LVT_LINT1 0x836 +%define MSR_IA32_X2APIC_LVT_ERROR 0x837 +%define MSR_IA32_X2APIC_TIMER_ICR 0x838 +%define MSR_IA32_X2APIC_TIMER_CCR 0x839 +%define MSR_IA32_X2APIC_TIMER_DCR 0x83E +%define MSR_IA32_X2APIC_SELF_IPI 0x83F +%define MSR_IA32_X2APIC_END 0x8FF +%define MSR_IA32_X2APIC_LVT_START MSR_IA32_X2APIC_LVT_TIMER +%define MSR_IA32_X2APIC_LVT_END MSR_IA32_X2APIC_LVT_ERROR +%define MSR_K6_EFER 0xc0000080 +%define MSR_K6_EFER_SCE RT_BIT_32(0) +%define MSR_K6_EFER_LME RT_BIT_32(8) +%define MSR_K6_EFER_BIT_LME 8 +%define MSR_K6_EFER_LMA RT_BIT_32(10) +%define MSR_K6_EFER_BIT_LMA 10 +%define MSR_K6_EFER_NXE RT_BIT_32(11) +%define MSR_K6_EFER_BIT_NXE 11 +%define MSR_K6_EFER_SVME RT_BIT_32(12) +%define MSR_K6_EFER_LMSLE RT_BIT_32(13) +%define MSR_K6_EFER_FFXSR RT_BIT_32(14) +%define MSR_K6_EFER_TCE RT_BIT_32(15) +%define MSR_K6_EFER_MCOMMIT RT_BIT_32(17) +%define MSR_K6_STAR 0xc0000081 +%define MSR_K6_STAR_SYSRET_CS_SS_SHIFT 48 +%define MSR_K6_STAR_SYSCALL_CS_SS_SHIFT 32 +%define MSR_K6_STAR_SEL_MASK 0xffff +%define MSR_K6_STAR_SYSCALL_EIP_MASK 0xffffffff +%define MSR_K6_WHCR 0xc0000082 +%define MSR_K6_UWCCR 0xc0000085 +%define MSR_K6_PSOR 0xc0000087 +%define MSR_K6_PFIR 0xc0000088 +%define MSR_K7_EVNTSEL0 0xc0010000 +%define MSR_K7_EVNTSEL1 0xc0010001 +%define MSR_K7_EVNTSEL2 0xc0010002 +%define MSR_K7_EVNTSEL3 0xc0010003 +%define MSR_K7_PERFCTR0 0xc0010004 +%define MSR_K7_PERFCTR1 0xc0010005 +%define MSR_K7_PERFCTR2 0xc0010006 +%define MSR_K7_PERFCTR3 0xc0010007 +%define MSR_K8_LSTAR 0xc0000082 +%define MSR_K8_CSTAR 0xc0000083 +%define MSR_K8_SF_MASK 0xc0000084 +%define MSR_K8_FS_BASE 0xc0000100 +%define MSR_K8_GS_BASE 0xc0000101 +%define MSR_K8_KERNEL_GS_BASE 0xc0000102 +%define MSR_K8_TSC_AUX 0xc0000103 +%define MSR_K8_SYSCFG 0xc0010010 +%define MSR_K8_HWCR 0xc0010015 +%define MSR_K8_IORRBASE0 0xc0010016 +%define MSR_K8_IORRMASK0 0xc0010017 +%define MSR_K8_IORRBASE1 0xc0010018 +%define MSR_K8_IORRMASK1 0xc0010019 +%define MSR_K8_TOP_MEM1 0xc001001a +%define MSR_K8_TOP_MEM2 0xc001001d +%define MSR_K7_SMBASE 0xc0010111 +%define MSR_K7_SMM_ADDR 0xc0010112 +%define MSR_K7_SMM_MASK 0xc0010113 +%define MSR_K8_NB_CFG 0xc001001f +%define MSR_K8_INT_PENDING 0xc0010055 +%define MSR_K8_VM_CR 0xc0010114 +%define MSR_K8_VM_CR_DPD RT_BIT_32(0) +%define MSR_K8_VM_CR_R_INIT RT_BIT_32(1) +%define MSR_K8_VM_CR_DIS_A20M RT_BIT_32(2) +%define MSR_K8_VM_CR_LOCK RT_BIT_32(3) +%define MSR_K8_VM_CR_SVM_DISABLE RT_BIT_32(4) +%define MSR_K8_IGNNE 0xc0010115 +%define MSR_K8_SMM_CTL 0xc0010116 +%define MSR_K8_VM_HSAVE_PA 0xc0010117 +%define MSR_AMD_VIRT_SPEC_CTL 0xc001011f + %define MSR_AMD_VIRT_SPEC_CTL_F_SSBD RT_BIT(2) +%define X86_PG_ENTRIES 1024 +%define X86_PG_PAE_ENTRIES 512 +%define X86_PG_PAE_PDPE_ENTRIES 4 +%define X86_PG_AMD64_ENTRIES X86_PG_PAE_ENTRIES +%define X86_PG_AMD64_PDPE_ENTRIES X86_PG_AMD64_ENTRIES +%define X86_PAGE_SIZE X86_PAGE_4K_SIZE +%define X86_PAGE_SHIFT X86_PAGE_4K_SHIFT +%define X86_PAGE_OFFSET_MASK X86_PAGE_4K_OFFSET_MASK +%define X86_PAGE_BASE_MASK X86_PAGE_4K_BASE_MASK +%define X86_PAGE_BASE_MASK_32 X86_PAGE_4K_BASE_MASK_32 +%define X86_PAGE_4K_SIZE _4K +%define X86_PAGE_4K_SHIFT 12 +%define X86_PAGE_4K_OFFSET_MASK 0xfff +%define X86_PAGE_4K_BASE_MASK 0xfffffffffffff000 +%define X86_PAGE_4K_BASE_MASK_32 0xfffff000 +%define X86_PAGE_2M_SIZE _2M +%define X86_PAGE_2M_SHIFT 21 +%define X86_PAGE_2M_OFFSET_MASK 0x001fffff +%define X86_PAGE_2M_BASE_MASK 0xffffffffffe00000 +%define X86_PAGE_2M_BASE_MASK_32 0xffe00000 +%define X86_PAGE_4M_SIZE _4M +%define X86_PAGE_4M_SHIFT 22 +%define X86_PAGE_4M_OFFSET_MASK 0x003fffff +%define X86_PAGE_4M_BASE_MASK 0xffffffffffc00000 +%define X86_PAGE_4M_BASE_MASK_32 0xffc00000 +%define X86_PAGE_1G_SIZE _1G +%define X86_PAGE_1G_SHIFT 30 +%define X86_PAGE_1G_OFFSET_MASK 0x3fffffff +%define X86_PAGE_1G_BASE_MASK 0xffffffffc0000000 +%define X86_IS_CANONICAL(a_u64Addr) ((uint64_t)(a_u64Addr) + 0x800000000000 < UINT64_C(0x1000000000000)) +%define X86_GET_PAGE_BASE_MASK(a_cShift) (0xffffffffffffffff << (a_cShift)) +%define X86_GET_PAGE_OFFSET_MASK(a_cShift) (~X86_GET_PAGE_BASE_MASK(a_cShift)) +%define X86_PTE_BIT_P 0 +%define X86_PTE_BIT_RW 1 +%define X86_PTE_BIT_US 2 +%define X86_PTE_BIT_PWT 3 +%define X86_PTE_BIT_PCD 4 +%define X86_PTE_BIT_A 5 +%define X86_PTE_BIT_D 6 +%define X86_PTE_BIT_PAT 7 +%define X86_PTE_BIT_G 8 +%define X86_PTE_PAE_BIT_NX 63 +%define X86_PTE_P RT_BIT_32(0) +%define X86_PTE_RW RT_BIT_32(1) +%define X86_PTE_US RT_BIT_32(2) +%define X86_PTE_PWT RT_BIT_32(3) +%define X86_PTE_PCD RT_BIT_32(4) +%define X86_PTE_A RT_BIT_32(5) +%define X86_PTE_D RT_BIT_32(6) +%define X86_PTE_PAT RT_BIT_32(7) +%define X86_PTE_G RT_BIT_32(8) +%define X86_PTE_AVL_MASK (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +%define X86_PTE_PG_MASK ( 0xfffff000 ) +%define X86_PTE_PAE_PG_MASK 0x000ffffffffff000 +%define X86_PTE_PAE_NX RT_BIT_64(63) +%define X86_PTE_PAE_MBZ_MASK_NX 0x7ff0000000000000 +%define X86_PTE_PAE_MBZ_MASK_NO_NX 0xfff0000000000000 +%define X86_PTE_LM_MBZ_MASK_NX 0x0000000000000000 +%define X86_PTE_LM_MBZ_MASK_NO_NX 0x8000000000000000 +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_PT_SHIFT 12 +%define X86_PT_MASK 0x3ff +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_PT_PAE_SHIFT 12 +%define X86_PT_PAE_MASK 0x1ff +%define X86_PDE_P RT_BIT_32(0) +%define X86_PDE_RW RT_BIT_32(1) +%define X86_PDE_US RT_BIT_32(2) +%define X86_PDE_PWT RT_BIT_32(3) +%define X86_PDE_PCD RT_BIT_32(4) +%define X86_PDE_A RT_BIT_32(5) +%define X86_PDE_PS RT_BIT_32(7) +%define X86_PDE_AVL_MASK (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +%define X86_PDE_PG_MASK ( 0xfffff000 ) +%define X86_PDE_PAE_PG_MASK 0x000ffffffffff000 +%define X86_PDE_PAE_NX RT_BIT_64(63) +%define X86_PDE_PAE_MBZ_MASK_NX 0x7ff0000000000080 +%define X86_PDE_PAE_MBZ_MASK_NO_NX 0xfff0000000000080 +%define X86_PDE_LM_MBZ_MASK_NX 0x0000000000000080 +%define X86_PDE_LM_MBZ_MASK_NO_NX 0x8000000000000080 +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_PDE4M_P RT_BIT_32(0) +%define X86_PDE4M_RW RT_BIT_32(1) +%define X86_PDE4M_US RT_BIT_32(2) +%define X86_PDE4M_PWT RT_BIT_32(3) +%define X86_PDE4M_PCD RT_BIT_32(4) +%define X86_PDE4M_A RT_BIT_32(5) +%define X86_PDE4M_D RT_BIT_32(6) +%define X86_PDE4M_PS RT_BIT_32(7) +%define X86_PDE4M_G RT_BIT_32(8) +%define X86_PDE4M_AVL (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +%define X86_PDE4M_PAT RT_BIT_32(12) +%define X86_PDE4M_PAT_SHIFT (12 - 7) +%define X86_PDE4M_PG_MASK ( 0xffc00000 ) +%define X86_PDE4M_PG_HIGH_MASK ( 0x001fe000 ) +%define X86_PDE4M_PG_HIGH_SHIFT 19 +%define X86_PDE4M_MBZ_MASK RT_BIT_32(21) +%define X86_PDE2M_PAE_PG_MASK 0x000fffffffe00000 +%define X86_PDE2M_PAE_NX RT_BIT_64(63) +%define X86_PDE2M_PAE_MBZ_MASK_NX 0x7ff00000001fe000 +%define X86_PDE2M_PAE_MBZ_MASK_NO_NX 0xfff00000001fe000 +%define X86_PDE2M_LM_MBZ_MASK_NX 0x00000000001fe000 +%define X86_PDE2M_LM_MBZ_MASK_NO_NX 0x80000000001fe000 +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_PD_SHIFT 22 +%define X86_PD_MASK 0x3ff +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_PD_PAE_SHIFT 21 +%define X86_PD_PAE_MASK 0x1ff +%define X86_PDPE_P RT_BIT_32(0) +%define X86_PDPE_RW RT_BIT_32(1) +%define X86_PDPE_US RT_BIT_32(2) +%define X86_PDPE_PWT RT_BIT_32(3) +%define X86_PDPE_PCD RT_BIT_32(4) +%define X86_PDPE_A RT_BIT_32(5) +%define X86_PDPE_LM_PS RT_BIT_32(7) +%define X86_PDPE_AVL_MASK (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +%define X86_PDPE_PG_MASK 0x000ffffffffff000 +%define X86_PDPE1G_PG_MASK 0x000fffffc0000000 +%define X86_PDPE_PAE_MBZ_MASK 0xfff00000000001e6 +%define X86_PDPE_LM_NX RT_BIT_64(63) +%define X86_PDPE_LM_MBZ_MASK_NX 0x0000000000000180 +%define X86_PDPE_LM_MBZ_MASK_NO_NX 0x8000000000000180 +%define X86_PDPE1G_LM_MBZ_MASK_NX 0x000000003fffe000 +%define X86_PDPE1G_LM_MBZ_MASK_NO_NX 0x800000003fffe000 +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_PDPT_SHIFT 30 +%define X86_PDPT_MASK_PAE 0x3 +%define X86_PDPT_MASK_AMD64 0x1ff +%define X86_PML4E_P RT_BIT_32(0) +%define X86_PML4E_RW RT_BIT_32(1) +%define X86_PML4E_US RT_BIT_32(2) +%define X86_PML4E_PWT RT_BIT_32(3) +%define X86_PML4E_PCD RT_BIT_32(4) +%define X86_PML4E_A RT_BIT_32(5) +%define X86_PML4E_AVL_MASK (RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +%define X86_PML4E_PG_MASK 0x000ffffffffff000 +%define X86_PML4E_MBZ_MASK_NX 0x0000000000000080 +%define X86_PML4E_MBZ_MASK_NO_NX 0x8000000000000080 +%define X86_PML4E_NX RT_BIT_64(63) +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_PML4_SHIFT 39 +%define X86_PML4_MASK 0x1ff +%define X86_INVPCID_TYPE_INDV_ADDR 0 +%define X86_INVPCID_TYPE_SINGLE_CONTEXT 1 +%define X86_INVPCID_TYPE_ALL_CONTEXT_INCL_GLOBAL 2 +%define X86_INVPCID_TYPE_ALL_CONTEXT_EXCL_GLOBAL 3 +%define X86_INVPCID_TYPE_MAX_VALID X86_INVPCID_TYPE_ALL_CONTEXT_EXCL_GLOBAL +%define X86_FPU_INT64_INDEFINITE INT64_MIN +%define X86_FPU_INT32_INDEFINITE INT32_MIN +%define X86_FPU_INT16_INDEFINITE INT16_MIN +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_OFF_FXSTATE_RSVD 0x1d0 +%define X86_FXSTATE_RSVD_32BIT_MAGIC 0x32b3232b +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_FSW_IE RT_BIT_32(0) +%define X86_FSW_IE_BIT 0 +%define X86_FSW_DE RT_BIT_32(1) +%define X86_FSW_DE_BIT 1 +%define X86_FSW_ZE RT_BIT_32(2) +%define X86_FSW_ZE_BIT 2 +%define X86_FSW_OE RT_BIT_32(3) +%define X86_FSW_OE_BIT 3 +%define X86_FSW_UE RT_BIT_32(4) +%define X86_FSW_UE_BIT 4 +%define X86_FSW_PE RT_BIT_32(5) +%define X86_FSW_PE_BIT 5 +%define X86_FSW_SF RT_BIT_32(6) +%define X86_FSW_SF_BIT 6 +%define X86_FSW_ES RT_BIT_32(7) +%define X86_FSW_ES_BIT 7 +%define X86_FSW_XCPT_MASK 0x007f +%define X86_FSW_XCPT_ES_MASK 0x00ff +%define X86_FSW_C0 RT_BIT_32(X86_FSW_C0_BIT) +%define X86_FSW_C0_BIT 8 +%define X86_FSW_C1 RT_BIT_32(X86_FSW_C1_BIT) +%define X86_FSW_C1_BIT 9 +%define X86_FSW_C2 RT_BIT_32(X86_FSW_C2_BIT) +%define X86_FSW_C2_BIT 10 +%define X86_FSW_TOP_MASK 0x3800 +%define X86_FSW_TOP_SHIFT 11 +%define X86_FSW_TOP_SMASK 0x0007 +%define X86_FSW_TOP_GET(a_uFsw) (((a_uFsw) >> X86_FSW_TOP_SHIFT) & X86_FSW_TOP_SMASK) +%define X86_FSW_TOP_GET_ST(a_uFsw, a_iSt) ((((a_uFsw) >> X86_FSW_TOP_SHIFT) + (a_iSt)) & X86_FSW_TOP_SMASK) +%define X86_FSW_C3 RT_BIT_32(X86_FSW_C3_BIT) +%define X86_FSW_C3_BIT 14 +%define X86_FSW_C_MASK 0x4700 +%define X86_FSW_B RT_BIT_32(15) +%define X86_FSW_CX_TO_QUOTIENT(a_fFsw) \ + ( (((a_fFsw) & X86_FSW_C1) >> (X86_FSW_C1_BIT - 0)) \ + | (((a_fFsw) & X86_FSW_C3) >> (X86_FSW_C3_BIT - 1)) \ + | (((a_fFsw) & X86_FSW_C0) >> (X86_FSW_C0_BIT - 2)) ) +%define X86_FSW_CX_FROM_QUOTIENT(a_uQuotient) \ + ( ((uint16_t)((a_uQuotient) & 1) << (X86_FSW_C1_BIT - 0)) \ + | ((uint16_t)((a_uQuotient) & 2) << (X86_FSW_C3_BIT - 1)) \ + | ((uint16_t)((a_uQuotient) & 4) << (X86_FSW_C0_BIT - 2)) ) +%define X86_FCW_IM RT_BIT_32(0) +%define X86_FCW_IM_BIT 0 +%define X86_FCW_DM RT_BIT_32(1) +%define X86_FCW_DM_BIT 1 +%define X86_FCW_ZM RT_BIT_32(2) +%define X86_FCW_ZM_BIT 2 +%define X86_FCW_OM RT_BIT_32(3) +%define X86_FCW_OM_BIT 3 +%define X86_FCW_UM RT_BIT_32(4) +%define X86_FCW_UM_BIT 4 +%define X86_FCW_PM RT_BIT_32(5) +%define X86_FCW_PM_BIT 5 +%define X86_FCW_MASK_ALL 0x007f +%define X86_FCW_XCPT_MASK 0x003f +%define X86_FCW_PC_MASK 0x0300 +%define X86_FCW_PC_SHIFT 8 +%define X86_FCW_PC_24 0x0000 +%define X86_FCW_PC_RSVD 0x0100 +%define X86_FCW_PC_53 0x0200 +%define X86_FCW_PC_64 0x0300 +%define X86_FCW_RC_MASK 0x0c00 +%define X86_FCW_RC_SHIFT 10 +%define X86_FCW_RC_NEAREST 0x0000 +%define X86_FCW_RC_DOWN 0x0400 +%define X86_FCW_RC_UP 0x0800 +%define X86_FCW_RC_ZERO 0x0c00 +%define X86_FCW_IC_MASK 0x1000 +%define X86_FCW_IC_AFFINE 0x1000 +%define X86_FCW_IC_PROJECTIVE 0x0000 +%define X86_FCW_ZERO_MASK 0xf080 +%define X86_MXCSR_IE RT_BIT_32(0) +%define X86_MXCSR_DE RT_BIT_32(1) +%define X86_MXCSR_ZE RT_BIT_32(2) +%define X86_MXCSR_OE RT_BIT_32(3) +%define X86_MXCSR_UE RT_BIT_32(4) +%define X86_MXCSR_PE RT_BIT_32(5) +%define X86_MXCSR_XCPT_FLAGS 0x003f +%define X86_MXCSR_DAZ RT_BIT_32(6) +%define X86_MXCSR_IM RT_BIT_32(7) +%define X86_MXCSR_DM RT_BIT_32(8) +%define X86_MXCSR_ZM RT_BIT_32(9) +%define X86_MXCSR_OM RT_BIT_32(10) +%define X86_MXCSR_UM RT_BIT_32(11) +%define X86_MXCSR_PM RT_BIT_32(12) +%define X86_MXCSR_XCPT_MASK 0x1f80 +%define X86_MXCSR_XCPT_MASK_SHIFT 7 +%define X86_MXCSR_RC_MASK 0x6000 +%define X86_MXCSR_RC_SHIFT 13 +%define X86_MXCSR_RC_NEAREST 0x0000 +%define X86_MXCSR_RC_DOWN 0x2000 +%define X86_MXCSR_RC_UP 0x4000 +%define X86_MXCSR_RC_ZERO 0x6000 +%define X86_MXCSR_FZ RT_BIT_32(15) +%define X86_MXCSR_MM RT_BIT_32(17) +%define X86_MXCSR_ZERO_MASK 0xfffd0000 +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define XSAVE_C_X87_BIT 0 +%define XSAVE_C_X87 RT_BIT_64(XSAVE_C_X87_BIT) +%define XSAVE_C_SSE_BIT 1 +%define XSAVE_C_SSE RT_BIT_64(XSAVE_C_SSE_BIT) +%define XSAVE_C_YMM_BIT 2 +%define XSAVE_C_YMM RT_BIT_64(XSAVE_C_YMM_BIT) +%define XSAVE_C_BNDREGS_BIT 3 +%define XSAVE_C_BNDREGS RT_BIT_64(XSAVE_C_BNDREGS_BIT) +%define XSAVE_C_BNDCSR_BIT 4 +%define XSAVE_C_BNDCSR RT_BIT_64(XSAVE_C_BNDCSR_BIT) +%define XSAVE_C_OPMASK_BIT 5 +%define XSAVE_C_OPMASK RT_BIT_64(XSAVE_C_OPMASK_BIT) +%define XSAVE_C_ZMM_HI256_BIT 6 +%define XSAVE_C_ZMM_HI256 RT_BIT_64(XSAVE_C_ZMM_HI256_BIT) +%define XSAVE_C_ZMM_16HI_BIT 7 +%define XSAVE_C_ZMM_16HI RT_BIT_64(XSAVE_C_ZMM_16HI_BIT) +%define XSAVE_C_PKRU_BIT 9 +%define XSAVE_C_PKRU RT_BIT_64(XSAVE_C_PKRU_BIT) +%define XSAVE_C_LWP_BIT 62 +%define XSAVE_C_LWP RT_BIT_64(XSAVE_C_LWP_BIT) +%define XSAVE_C_X_BIT 63 +%define XSAVE_C_X RT_BIT_64(XSAVE_C_X_BIT) +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86DESCATTR_TYPE 0x0000000f +%define X86DESCATTR_DT 0x00000010 +%define X86DESCATTR_DPL 0x00000060 +%define X86DESCATTR_DPL_SHIFT 5 +%define X86DESCATTR_P 0x00000080 +%define X86DESCATTR_LIMIT_HIGH 0x00000f00 +%define X86DESCATTR_AVL 0x00001000 +%define X86DESCATTR_L 0x00002000 +%define X86DESCATTR_D 0x00004000 +%define X86DESCATTR_G 0x00008000 +%define X86DESCATTR_UNUSABLE 0x00010000 +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%define X86DESCGENERIC_BIT_OFF_LIMIT_LOW (0) +%define X86DESCGENERIC_BIT_OFF_BASE_LOW (16) +%define X86DESCGENERIC_BIT_OFF_BASE_HIGH1 (32) +%define X86DESCGENERIC_BIT_OFF_TYPE (40) +%define X86DESCGENERIC_BIT_OFF_DESC_TYPE (44) +%define X86DESCGENERIC_BIT_OFF_DPL (45) +%define X86DESCGENERIC_BIT_OFF_PRESENT (47) +%define X86DESCGENERIC_BIT_OFF_LIMIT_HIGH (48) +%define X86DESCGENERIC_BIT_OFF_AVAILABLE (52) +%define X86DESCGENERIC_BIT_OFF_LONG (53) +%define X86DESCGENERIC_BIT_OFF_DEF_BIG (54) +%define X86DESCGENERIC_BIT_OFF_GRANULARITY (55) +%define X86DESCGENERIC_BIT_OFF_BASE_HIGH2 (56) +%define X86LAR_F_TYPE 0x0f00 +%define X86LAR_F_DT 0x1000 +%define X86LAR_F_DPL 0x6000 +%define X86LAR_F_DPL_SHIFT 13 +%define X86LAR_F_P 0x8000 +%define X86LAR_F_AVL 0x00100000 +%define X86LAR_F_L 0x00200000 +%define X86LAR_F_D 0x00400000 +%define X86LAR_F_G 0x00800000 +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%if HC_ARCH_BITS == 64 +%else +%endif +%if HC_ARCH_BITS == 64 +%else +%endif +%if HC_ARCH_BITS == 64 +%else +%endif +%define X86_SEL_TYPE_CODE 8 +%define X86_SEL_TYPE_MEMORY RT_BIT_32(4) +%define X86_SEL_TYPE_ACCESSED 1 +%define X86_SEL_TYPE_DOWN 4 +%define X86_SEL_TYPE_CONF 4 +%define X86_SEL_TYPE_WRITE 2 +%define X86_SEL_TYPE_READ 2 +%define X86_SEL_TYPE_READ_BIT 1 +%define X86_SEL_TYPE_RO 0 +%define X86_SEL_TYPE_RO_ACC (0 | X86_SEL_TYPE_ACCESSED) +%define X86_SEL_TYPE_RW 2 +%define X86_SEL_TYPE_RW_ACC (2 | X86_SEL_TYPE_ACCESSED) +%define X86_SEL_TYPE_RO_DOWN 4 +%define X86_SEL_TYPE_RO_DOWN_ACC (4 | X86_SEL_TYPE_ACCESSED) +%define X86_SEL_TYPE_RW_DOWN 6 +%define X86_SEL_TYPE_RW_DOWN_ACC (6 | X86_SEL_TYPE_ACCESSED) +%define X86_SEL_TYPE_EO (0 | X86_SEL_TYPE_CODE) +%define X86_SEL_TYPE_EO_ACC (0 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED) +%define X86_SEL_TYPE_ER (2 | X86_SEL_TYPE_CODE) +%define X86_SEL_TYPE_ER_ACC (2 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED) +%define X86_SEL_TYPE_EO_CONF (4 | X86_SEL_TYPE_CODE) +%define X86_SEL_TYPE_EO_CONF_ACC (4 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED) +%define X86_SEL_TYPE_ER_CONF (6 | X86_SEL_TYPE_CODE) +%define X86_SEL_TYPE_ER_CONF_ACC (6 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED) +%define X86_SEL_TYPE_SYS_TSS_BUSY_MASK 2 +%define X86_SEL_TYPE_SYS_UNDEFINED 0 +%define X86_SEL_TYPE_SYS_286_TSS_AVAIL 1 +%define X86_SEL_TYPE_SYS_LDT 2 +%define X86_SEL_TYPE_SYS_286_TSS_BUSY 3 +%define X86_SEL_TYPE_SYS_286_CALL_GATE 4 +%define X86_SEL_TYPE_SYS_TASK_GATE 5 +%define X86_SEL_TYPE_SYS_286_INT_GATE 6 +%define X86_SEL_TYPE_SYS_286_TRAP_GATE 7 +%define X86_SEL_TYPE_SYS_UNDEFINED2 8 +%define X86_SEL_TYPE_SYS_386_TSS_AVAIL 9 +%define X86_SEL_TYPE_SYS_UNDEFINED3 0xA +%define X86_SEL_TYPE_SYS_386_TSS_BUSY 0xB +%define X86_SEL_TYPE_SYS_386_CALL_GATE 0xC +%define X86_SEL_TYPE_SYS_UNDEFINED4 0xD +%define X86_SEL_TYPE_SYS_386_INT_GATE 0xE +%define X86_SEL_TYPE_SYS_386_TRAP_GATE 0xF +%define AMD64_SEL_TYPE_SYS_LDT 2 +%define AMD64_SEL_TYPE_SYS_TSS_AVAIL 9 +%define AMD64_SEL_TYPE_SYS_TSS_BUSY 0xB +%define AMD64_SEL_TYPE_SYS_CALL_GATE 0xC +%define AMD64_SEL_TYPE_SYS_INT_GATE 0xE +%define AMD64_SEL_TYPE_SYS_TRAP_GATE 0xF +%define X86_DESC_TYPE_MASK (RT_BIT_32(8) | RT_BIT_32(9) | RT_BIT_32(10) | RT_BIT_32(11)) +%define X86_DESC_S RT_BIT_32(12) +%define X86_DESC_DPL (RT_BIT_32(13) | RT_BIT_32(14)) +%define X86_DESC_P RT_BIT_32(15) +%define X86_DESC_AVL RT_BIT_32(20) +%define X86_DESC_DB RT_BIT_32(22) +%define X86_DESC_G RT_BIT_32(23) +%define X86_SEL_TYPE_SYS_286_TSS_LIMIT_MIN 0x2b +%define X86_SEL_TYPE_SYS_386_TSS_LIMIT_MIN 0x67 +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_SEL_SHIFT 3 +%define X86_SEL_MASK 0xfff8 +%define X86_SEL_MASK_OFF_RPL 0xfffc +%define X86_SEL_LDT 0x0004 +%define X86_SEL_RPL 0x0003 +%define X86_SEL_RPL_LDT 0x0007 +%define X86_XCPT_LAST 0x1f +%define X86_TRAP_ERR_EXTERNAL 1 +%define X86_TRAP_ERR_IDT 2 +%define X86_TRAP_ERR_TI 4 +%define X86_TRAP_ERR_SEL_MASK 0xfff8 +%define X86_TRAP_ERR_SEL_SHIFT 3 +%define X86_TRAP_PF_P RT_BIT_32(0) +%define X86_TRAP_PF_RW RT_BIT_32(1) +%define X86_TRAP_PF_US RT_BIT_32(2) +%define X86_TRAP_PF_RSVD RT_BIT_32(3) +%define X86_TRAP_PF_ID RT_BIT_32(4) +%define X86_TRAP_PF_PK RT_BIT_32(5) +%ifndef VBOX_FOR_DTRACE_LIB +%else +%endif +%ifndef VBOX_FOR_DTRACE_LIB +%else +%endif +%define X86_MODRM_RM_MASK 0x07 +%define X86_MODRM_REG_MASK 0x38 +%define X86_MODRM_REG_SMASK 0x07 +%define X86_MODRM_REG_SHIFT 3 +%define X86_MODRM_MOD_MASK 0xc0 +%define X86_MODRM_MOD_SMASK 0x03 +%define X86_MODRM_MOD_SHIFT 6 +%ifndef VBOX_FOR_DTRACE_LIB + %define X86_MODRM_MAKE(a_Mod, a_Reg, a_RegMem) (((a_Mod) << X86_MODRM_MOD_SHIFT) | ((a_Reg) << X86_MODRM_REG_SHIFT) | (a_RegMem)) +%endif +%define X86_SIB_BASE_MASK 0x07 +%define X86_SIB_INDEX_MASK 0x38 +%define X86_SIB_INDEX_SMASK 0x07 +%define X86_SIB_INDEX_SHIFT 3 +%define X86_SIB_SCALE_MASK 0xc0 +%define X86_SIB_SCALE_SMASK 0x03 +%define X86_SIB_SCALE_SHIFT 6 +%ifndef VBOX_FOR_DTRACE_LIB +%endif +%define X86_GREG_xAX 0 +%define X86_GREG_xCX 1 +%define X86_GREG_xDX 2 +%define X86_GREG_xBX 3 +%define X86_GREG_xSP 4 +%define X86_GREG_xBP 5 +%define X86_GREG_xSI 6 +%define X86_GREG_xDI 7 +%define X86_GREG_x8 8 +%define X86_GREG_x9 9 +%define X86_GREG_x10 10 +%define X86_GREG_x11 11 +%define X86_GREG_x12 12 +%define X86_GREG_x13 13 +%define X86_GREG_x14 14 +%define X86_GREG_x15 15 +%define X86_GREG_COUNT 16 +%define X86_SREG_ES 0 +%define X86_SREG_CS 1 +%define X86_SREG_SS 2 +%define X86_SREG_DS 3 +%define X86_SREG_FS 4 +%define X86_SREG_GS 5 +%define X86_SREG_COUNT 6 +%define X86_OP_PRF_CS 0x2e +%define X86_OP_PRF_SS 0x36 +%define X86_OP_PRF_DS 0x3e +%define X86_OP_PRF_ES 0x26 +%define X86_OP_PRF_FS 0x64 +%define X86_OP_PRF_GS 0x65 +%define X86_OP_PRF_SIZE_OP 0x66 +%define X86_OP_PRF_SIZE_ADDR 0x67 +%define X86_OP_PRF_LOCK 0xf0 +%define X86_OP_PRF_REPZ 0xf3 +%define X86_OP_PRF_REPNZ 0xf2 +%define X86_OP_REX_B 0x41 +%define X86_OP_REX_X 0x42 +%define X86_OP_REX_R 0x44 +%define X86_OP_REX_W 0x48 +%endif +%include "iprt/x86extra.mac" diff --git a/include/iprt/x86extra.mac b/include/iprt/x86extra.mac new file mode 100644 index 00000000..44986e95 --- /dev/null +++ b/include/iprt/x86extra.mac @@ -0,0 +1,225 @@ +;; @file +; IPRT - X86 and AMD64 Structures and Definitions that are not automatically +; converted from the C header file. +; + +; +; Copyright (C) 2012-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___iprt_x86extra_mac +%define ___iprt_x86extra_mac + + +%define X86_XCPT_DE 0x00 +%define X86_XCPT_DB 0x01 +%define X86_XCPT_NMI 0x02 +%define X86_XCPT_BP 0x03 +%define X86_XCPT_OF 0x04 +%define X86_XCPT_BR 0x05 +%define X86_XCPT_UD 0x06 +%define X86_XCPT_NM 0x07 +%define X86_XCPT_DF 0x08 +%define X86_XCPT_CO_SEG_OVERRUN 0x09 +%define X86_XCPT_TS 0x0a +%define X86_XCPT_NP 0x0b +%define X86_XCPT_SS 0x0c +%define X86_XCPT_GP 0x0d +%define X86_XCPT_PF 0x0e +%define X86_XCPT_MF 0x10 +%define X86_XCPT_AC 0x11 +%define X86_XCPT_MC 0x12 +%define X86_XCPT_XF 0x13 +%define X86_XCPT_VE 0x14 +%define X86_XCPT_SX 0x1f + +%define PAGE_SIZE 0x1000 + +;; Same a ~(X86_CR0_PE | X86_CR0_PG) except it won't cause assembler warnings. +%define X86_CR0_NO_PE_NO_PG 0x7ffffffe + + + +;; +; 32-bit protected mode fstenv image. +; +struc X86FSTENV32P + .FCW resw 1 + .padding1 resw 1 + .FSW resw 1 + .padding2 resw 1 + .FTW resw 1 + .padding3 resw 1 + .FPUIP resd 1 + .FPUCS resw 1 + .FOP resw 1 + .FPUDP resd 1 + .FPUDS resw 1 + .padding4 resw 1 +endstruc + + +;; +; The image saved by FXSAVE. +; +struc X86FXSTATE + .FCW resw 1 + .FSW resw 1 + .FTW resw 1 + .FOP resw 1 + .FPUIP resd 1 + .FPUCS resw 1 + .Rsrvd1 resw 1 + .FPUDP resd 1 + .FPUDS resw 1 + .Rsrvd2 resw 1 + .MXCSR resd 1 + .MXCSR_MASK resd 1 + .st0 resd 4 + .st1 resd 4 + .st2 resd 4 + .st3 resd 4 + .st4 resd 4 + .st5 resd 4 + .st6 resd 4 + .st7 resd 4 + .xmm0 resd 4 + .xmm1 resd 4 + .xmm2 resd 4 + .xmm3 resd 4 + .xmm4 resd 4 + .xmm5 resd 4 + .xmm6 resd 4 + .xmm7 resd 4 + .xmm8 resd 4 + .xmm9 resd 4 + .xmm10 resd 4 + .xmm11 resd 4 + .xmm12 resd 4 + .xmm13 resd 4 + .xmm14 resd 4 + .xmm15 resd 4 + .au32RsrvdRest resd 24 +endstruc + + +struc X86TSS16 + .selPrev resw 1 + .sp0 resw 1 + .ss0 resw 1 + .sp1 resw 1 + .ss1 resw 1 + .sp2 resw 1 + .ss2 resw 1 + .ip resw 1 + .flags resw 1 + .ax resw 1 + .cx resw 1 + .dx resw 1 + .bx resw 1 + .sp resw 1 + .bp resw 1 + .si resw 1 + .di resw 1 + .es resw 1 + .cs resw 1 + .ss resw 1 + .ds resw 1 + .selLdt resw 1 +endstruc +AssertCompileSize(X86TSS16, 44) + + +struc X86TSS32 + .selPrev resw 1 + .padding1 resw 1 + .esp0 resd 1 + .ss0 resw 1 + .padding_ss0 resw 1 + .esp1 resd 1 + .ss1 resw 1 + .padding_ss1 resw 1 + .esp2 resd 1 + .ss2 resw 1 + .padding_ss2 resw 1 + .cr3 resd 1 + .eip resd 1 + .eflags resd 1 + .eax resd 1 + .ecx resd 1 + .edx resd 1 + .ebx resd 1 + .esp resd 1 + .ebp resd 1 + .esi resd 1 + .edi resd 1 + .es resw 1 + .padding_es resw 1 + .cs resw 1 + .padding_cs resw 1 + .ss resw 1 + .padding_ss resw 1 + .ds resw 1 + .padding_ds resw 1 + .fs resw 1 + .padding_fs resw 1 + .gs resw 1 + .padding_gs resw 1 + .selLdt resw 1 + .padding_ldt resw 1 + .fDebugTrap resw 1 + .offIoBitmap resw 1 + ;.IntRedirBitmap resb 32 - this is optional. +endstruc +AssertCompileSize(X86TSS32,104) + + +struc X86TSS64 + .u32Reserved resd 1 + .rsp0 resq 1 + .rsp1 resq 1 + .rsp2 resq 1 + .u32Reserved2 resd 2 + .ist1 resq 1 + .ist2 resq 1 + .ist3 resq 1 + .ist4 resq 1 + .ist5 resq 1 + .ist6 resq 1 + .ist7 resq 1 + .u16Reserved resw 5 + .offIoBitmap resw 1 + ;.IntRedirBitmap resb 32 - this isn't really there!! VBox addition for x86TSS32 structure compatibility in x86.h. +endstruc +AssertCompileSize(X86TSS64, 104) + + +%endif + diff --git a/include/iprt/zero.h b/include/iprt/zero.h new file mode 100644 index 00000000..75dd3041 --- /dev/null +++ b/include/iprt/zero.h @@ -0,0 +1,67 @@ +/** @file + * IPRT - Zero Memory. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_zero_h +#define IPRT_INCLUDED_zero_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/param.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_zero RTZero - Zeroed Memory Objects + * @ingroup grp_rt + * @{ + */ + +extern RTDATADECL(uint8_t const) g_abRTZeroPage[PAGE_SIZE]; +extern RTDATADECL(uint8_t const) g_abRTZero4K[_4K]; +extern RTDATADECL(uint8_t const) g_abRTZero8K[_8K]; +extern RTDATADECL(uint8_t const) g_abRTZero16K[_16K]; +extern RTDATADECL(uint8_t const) g_abRTZero32K[_32K]; +extern RTDATADECL(uint8_t const) g_abRTZero64K[_64K]; + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_zero_h */ + diff --git a/include/iprt/zip.h b/include/iprt/zip.h new file mode 100644 index 00000000..4dc1ee19 --- /dev/null +++ b/include/iprt/zip.h @@ -0,0 +1,533 @@ +/** @file + * IPRT - Compression. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef IPRT_INCLUDED_zip_h +#define IPRT_INCLUDED_zip_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> +#include <iprt/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rt_zip RTZip - Compression + * @ingroup grp_rt + * @{ + */ + + + +/** + * Callback function for consuming compressed data during compression. + * + * @returns iprt status code. + * @param pvUser User argument. + * @param pvBuf Compressed data. + * @param cbBuf Size of the compressed data. + */ +typedef DECLCALLBACKTYPE(int, FNRTZIPOUT,(void *pvUser, const void *pvBuf, size_t cbBuf)); +/** Pointer to FNRTZIPOUT() function. */ +typedef FNRTZIPOUT *PFNRTZIPOUT; + +/** + * Callback function for supplying compressed data during decompression. + * + * @returns iprt status code. + * @param pvUser User argument. + * @param pvBuf Where to store the compressed data. + * @param cbBuf Size of the buffer. + * @param pcbBuf Number of bytes actually stored in the buffer. + */ +typedef DECLCALLBACKTYPE(int, FNRTZIPIN,(void *pvUser, void *pvBuf, size_t cbBuf, size_t *pcbBuf)); +/** Pointer to FNRTZIPIN() function. */ +typedef FNRTZIPIN *PFNRTZIPIN; + +/** + * Compression type. + * (Be careful with these they are stored in files!) + */ +typedef enum RTZIPTYPE +{ + /** Invalid. */ + RTZIPTYPE_INVALID = 0, + /** Choose best fitting one. */ + RTZIPTYPE_AUTO, + /** Store the data. */ + RTZIPTYPE_STORE, + /** Zlib compression the data. */ + RTZIPTYPE_ZLIB, + /** BZlib compress. */ + RTZIPTYPE_BZLIB, + /** libLZF compress. */ + RTZIPTYPE_LZF, + /** Lempel-Ziv-Jeff-Bonwick compression. */ + RTZIPTYPE_LZJB, + /** Lempel-Ziv-Oberhumer compression. */ + RTZIPTYPE_LZO, + /* Zlib compression the data without zlib header. */ + RTZIPTYPE_ZLIB_NO_HEADER, + /** End of valid the valid compression types. */ + RTZIPTYPE_END +} RTZIPTYPE; + +/** + * Compression level. + */ +typedef enum RTZIPLEVEL +{ + /** Store, don't compress. */ + RTZIPLEVEL_STORE = 0, + /** Fast compression. */ + RTZIPLEVEL_FAST, + /** Default compression. */ + RTZIPLEVEL_DEFAULT, + /** Maximal compression. */ + RTZIPLEVEL_MAX +} RTZIPLEVEL; + + +/** + * Create a stream compressor instance. + * + * @returns iprt status code. + * @param ppZip Where to store the instance handle. + * @param pvUser User argument which will be passed on to pfnOut and pfnIn. + * @param pfnOut Callback for consuming output of compression. + * @param enmType Type of compressor to create. + * @param enmLevel Compression level. + */ +RTDECL(int) RTZipCompCreate(PRTZIPCOMP *ppZip, void *pvUser, PFNRTZIPOUT pfnOut, RTZIPTYPE enmType, RTZIPLEVEL enmLevel); + +/** + * Compresses a chunk of memory. + * + * @returns iprt status code. + * @param pZip The compressor instance. + * @param pvBuf Pointer to buffer containing the bits to compress. + * @param cbBuf Number of bytes to compress. + */ +RTDECL(int) RTZipCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf); + +/** + * Finishes the compression. + * This will flush all data and terminate the compression data stream. + * + * @returns iprt status code. + * @param pZip The stream compressor instance. + */ +RTDECL(int) RTZipCompFinish(PRTZIPCOMP pZip); + +/** + * Destroys the stream compressor instance. + * + * @returns iprt status code. + * @param pZip The compressor instance. + */ +RTDECL(int) RTZipCompDestroy(PRTZIPCOMP pZip); + + +/** + * Create a stream decompressor instance. + * + * @returns iprt status code. + * @param ppZip Where to store the instance handle. + * @param pvUser User argument which will be passed on to pfnOut and pfnIn. + * @param pfnIn Callback for producing input for decompression. + */ +RTDECL(int) RTZipDecompCreate(PRTZIPDECOMP *ppZip, void *pvUser, PFNRTZIPIN pfnIn); + +/** + * Decompresses a chunk of memory. + * + * @returns iprt status code. + * @param pZip The stream decompressor instance. + * @param pvBuf Where to store the decompressed data. + * @param cbBuf Number of bytes to produce. If pcbWritten is set + * any number of bytes up to cbBuf might be returned. + * @param pcbWritten Number of bytes actually written to the buffer. If NULL + * cbBuf number of bytes must be written. + */ +RTDECL(int) RTZipDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten); + +/** + * Destroys the stream decompressor instance. + * + * @returns iprt status code. + * @param pZip The decompressor instance. + */ +RTDECL(int) RTZipDecompDestroy(PRTZIPDECOMP pZip); + + +/** + * Compress a chunk of memory into a block. + * + * @returns IPRT status code. + * + * @param enmType The compression type. + * @param enmLevel The compression level. + * @param fFlags Flags reserved for future extensions, MBZ. + * @param pvSrc Pointer to the input block. + * @param cbSrc Size of the input block. + * @param pvDst Pointer to the output buffer. + * @param cbDst The size of the output buffer. + * @param pcbDstActual Where to return the compressed size. + */ +RTDECL(int) RTZipBlockCompress(RTZIPTYPE enmType, RTZIPLEVEL enmLevel, uint32_t fFlags, + void const *pvSrc, size_t cbSrc, + void *pvDst, size_t cbDst, size_t *pcbDstActual) RT_NO_THROW_PROTO; + + +/** + * Decompress a block. + * + * @returns IPRT status code. + * + * @param enmType The compression type. + * @param fFlags Flags reserved for future extensions, MBZ. + * @param pvSrc Pointer to the input block. + * @param cbSrc Size of the input block. + * @param pcbSrcActual Where to return the compressed size. + * @param pvDst Pointer to the output buffer. + * @param cbDst The size of the output buffer. + * @param pcbDstActual Where to return the decompressed size. + */ +RTDECL(int) RTZipBlockDecompress(RTZIPTYPE enmType, uint32_t fFlags, + void const *pvSrc, size_t cbSrc, size_t *pcbSrcActual, + void *pvDst, size_t cbDst, size_t *pcbDstActual) RT_NO_THROW_PROTO; + + +/** + * Opens a gzip decompression I/O stream. + * + * @returns IPRT status code. + * + * @param hVfsIosIn The compressed input stream (must be readable). + * The reference is not consumed, instead another + * one is retained. + * @param fFlags Flags, MBZ. + * @param phVfsIosGunzip Where to return the handle to the gunzipped I/O + * stream (read). + */ +RTDECL(int) RTZipGzipDecompressIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSIOSTREAM phVfsIosGunzip); + +/** @name RTZipGzipDecompressIoStream flags. + * @{ */ +/** Allow the smaller ZLIB header as well as the regular GZIP header. */ +#define RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR RT_BIT(0) +/** @} */ + + +/** + * Opens a gzip decompression I/O stream. + * + * @returns IPRT status code. + * + * @param hVfsIosDst The compressed output stream (must be writable). + * The reference is not consumed, instead another + * one is retained. + * @param fFlags Flags, MBZ. + * @param uLevel The gzip compression level, 1 thru 9. + * @param phVfsIosGzip Where to return the gzip input I/O stream handle + * (you write to this). + */ +RTDECL(int) RTZipGzipCompressIoStream(RTVFSIOSTREAM hVfsIosDst, uint32_t fFlags, uint8_t uLevel, PRTVFSIOSTREAM phVfsIosGzip); + +/** + * A mini GZIP program. + * + * @returns Program exit code. + * + * @param cArgs The number of arguments. + * @param papszArgs The argument vector. (Note that this may be + * reordered, so the memory must be writable.) + */ +RTDECL(RTEXITCODE) RTZipGzipCmd(unsigned cArgs, char **papszArgs); + +/** + * Opens a TAR filesystem stream. + * + * This is used to extract, list or check a TAR archive. + * + * @returns IPRT status code. + * + * @param hVfsIosIn The input stream. The reference is not + * consumed, instead another one is retained. + * @param fFlags Flags, MBZ. + * @param phVfsFss Where to return the handle to the TAR + * filesystem stream. + */ +RTDECL(int) RTZipTarFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss); + +/** TAR format type. */ +typedef enum RTZIPTARFORMAT +{ + /** Customary invalid zero value. */ + RTZIPTARFORMAT_INVALID = 0, + /** Default format (GNU). */ + RTZIPTARFORMAT_DEFAULT, + /** The GNU format. */ + RTZIPTARFORMAT_GNU, + /** USTAR format from POSIX.1-1988. */ + RTZIPTARFORMAT_USTAR, + /** PAX format from POSIX.1-2001. */ + RTZIPTARFORMAT_PAX, + /** End of valid formats. */ + RTZIPTARFORMAT_END, + /** Make sure the type is at least 32 bits wide. */ + RTZIPTARFORMAT_32BIT_HACK = 0x7fffffff +} RTZIPTARFORMAT; + +/** + * Opens a TAR filesystem stream for the purpose of create a new TAR archive. + * + * @returns IPRT status code. + * + * @param hVfsIosOut The output stream, i.e. where the tar stuff is + * written. The reference is not consumed, instead + * another one is retained. + * @param enmFormat The desired output format. + * @param fFlags RTZIPTAR_C_XXX, except RTZIPTAR_C_UPDATE. + * @param phVfsFss Where to return the handle to the TAR + * filesystem stream. + */ +RTDECL(int) RTZipTarFsStreamToIoStream(RTVFSIOSTREAM hVfsIosOut, RTZIPTARFORMAT enmFormat, + uint32_t fFlags, PRTVFSFSSTREAM phVfsFss); + +/** @name RTZIPTAR_C_XXX - TAR creation flags (RTZipTarFsStreamToIoStream). + * @{ */ +/** Check for sparse files. + * @note Only supported when adding file objects. The files will be read + * twice. */ +#define RTZIPTAR_C_SPARSE RT_BIT_32(0) +/** Set if opening for updating. */ +#define RTZIPTAR_C_UPDATE RT_BIT_32(1) +/** Valid bits. */ +#define RTZIPTAR_C_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** + * Opens a TAR filesystem stream for the purpose of create a new TAR archive or + * updating an existing one. + * + * @returns IPRT status code. + * + * @param hVfsFile The TAR file handle, i.e. where the tar stuff is + * written and optionally read/update. The + * reference is not consumed, instead another one + * is retained. + * @param enmFormat The desired output format. + * @param fFlags RTZIPTAR_C_XXX. + * @param phVfsFss Where to return the handle to the TAR + * filesystem stream. + */ +RTDECL(int) RTZipTarFsStreamForFile(RTVFSFILE hVfsFile, RTZIPTARFORMAT enmFormat, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss); + +/** + * Set the owner to store the archive entries with. + * + * @returns IPRT status code. + * @param hVfsFss The handle to a TAR creator. + * @param uid The UID value to set. Passing NIL_RTUID makes + * it use the value found in RTFSOBJINFO. + * @param pszOwner The owner name to store. Passing NULL makes it + * use the value found in RTFSOBJINFO. + */ +RTDECL(int) RTZipTarFsStreamSetOwner(RTVFSFSSTREAM hVfsFss, RTUID uid, const char *pszOwner); + +/** + * Set the group to store the archive entries with. + * + * @returns IPRT status code. + * @param hVfsFss The handle to a TAR creator. + * @param gid The GID value to set. Passing NIL_RTUID makes + * it use the value found in RTFSOBJINFO. + * @param pszGroup The group name to store. Passing NULL makes it + * use the value found in RTFSOBJINFO. + */ +RTDECL(int) RTZipTarFsStreamSetGroup(RTVFSFSSTREAM hVfsFss, RTGID gid, const char *pszGroup); + +/** + * Set path prefix to store the archive entries with. + * + * @returns IPRT status code. + * @param hVfsFss The handle to a TAR creator. + * @param pszPrefix The path prefix to join the names with. Pass + * NULL for no prefix. + */ +RTDECL(int) RTZipTarFsStreamSetPrefix(RTVFSFSSTREAM hVfsFss, const char *pszPrefix); + +/** + * Set the AND and OR masks to apply to file (non-dir) modes in the archive. + * + * @returns IPRT status code. + * @param hVfsFss The handle to a TAR creator. + * @param fAndMode The bits to keep + * @param fOrMode The bits to set. + */ +RTDECL(int) RTZipTarFsStreamSetFileMode(RTVFSFSSTREAM hVfsFss, RTFMODE fAndMode, RTFMODE fOrMode); + +/** + * Set the AND and OR masks to apply to directory modes in the archive. + * + * @returns IPRT status code. + * @param hVfsFss The handle to a TAR creator. + * @param fAndMode The bits to keep + * @param fOrMode The bits to set. + */ +RTDECL(int) RTZipTarFsStreamSetDirMode(RTVFSFSSTREAM hVfsFss, RTFMODE fAndMode, RTFMODE fOrMode); + +/** + * Set the modification time to store the archive entires with. + * + * @returns IPRT status code. + * @param hVfsFss The handle to a TAR creator. + * @param pModificationTime The modification time to use. Pass NULL to use + * the value found in RTFSOBJINFO. + */ +RTDECL(int) RTZipTarFsStreamSetMTime(RTVFSFSSTREAM hVfsFss, PCRTTIMESPEC pModificationTime); + +/** + * Truncates a TAR creator stream in update mode. + * + * Use RTVfsFsStrmNext to examine the TAR stream and locate the cut-off point. + * + * After performing this call, the stream will be in write mode and + * RTVfsFsStrmNext will stop working (VERR_WRONG_ORDER). The RTVfsFsStrmAdd() + * and RTVfsFsStrmPushFile() can be used to add new object to the TAR file, + * starting at the trunction point. RTVfsFsStrmEnd() is used to finish the TAR + * file (this performs the actual file trunction). + * + * @returns IPRT status code. + * @param hVfsFss The handle to a TAR creator in update mode. + * @param hVfsObj Object returned by RTVfsFsStrmNext that the + * trunction is relative to. This doesn't have to + * be the current stream object, it can be an + * earlier one too. + * @param fAfter If set, @a hVfsObj will remain in the update TAR + * file. If clear, @a hVfsObj will not be + * included. + */ +RTDECL(int) RTZipTarFsStreamTruncate(RTVFSFSSTREAM hVfsFss, RTVFSOBJ hVfsObj, bool fAfter); + +/** + * A mini TAR program. + * + * @returns Program exit code. + * + * @param cArgs The number of arguments. + * @param papszArgs The argument vector. (Note that this may be + * reordered, so the memory must be writable.) + */ +RTDECL(RTEXITCODE) RTZipTarCmd(unsigned cArgs, char **papszArgs); + +/** + * Opens a ZIP filesystem stream. + * + * This is used to extract, list or check a ZIP archive. + * + * @returns IPRT status code. + * + * @param hVfsIosIn The compressed input stream. The reference is + * not consumed, instead another one is retained. + * @param fFlags Flags, MBZ. + * @param phVfsFss Where to return the handle to the TAR + * filesystem stream. + */ +RTDECL(int) RTZipPkzipFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss); + +/** + * A mini UNZIP program. + * + * @returns Program exit code. + * @ + * @param cArgs The number of arguments. + * @param papszArgs The argument vector. (Note that this may be + * reordered, so the memory must be writable.) + */ +RTDECL(RTEXITCODE) RTZipUnzipCmd(unsigned cArgs, char **papszArgs); + +/** + * Helper for decompressing files of a ZIP file located in memory. + * + * @returns IPRT status code. + * + * @param ppvDst Where to store the pointer to the allocated + * buffer. To be freed with RTMemFree(). + * @param pcbDst Where to store the pointer to the size of the + * allocated buffer. + * @param pvSrc Pointer to the buffer containing the .zip file. + * @param cbSrc Size of the buffer containing the .zip file. + * @param pszObject Name of the object to extract. + */ +RTDECL(int) RTZipPkzipMemDecompress(void **ppvDst, size_t *pcbDst, const void *pvSrc, size_t cbSrc, const char *pszObject); + +/** + * Opens a XAR filesystem stream. + * + * This is used to extract, list or check a XAR archive. + * + * @returns IPRT status code. + * + * @param hVfsIosIn The compressed input stream. The reference is + * not consumed, instead another one is retained. + * @param fFlags Flags, MBZ. + * @param phVfsFss Where to return the handle to the XAR filesystem + * stream. + */ +RTDECL(int) RTZipXarFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss); + +/** + * Opens a CPIO filesystem stream. + * + * This is used to extract, list or check a CPIO archive. + * + * @returns IPRT status code. + * + * @param hVfsIosIn The input stream. The reference is not + * consumed, instead another one is retained. + * @param fFlags Flags, MBZ. + * @param phVfsFss Where to return the handle to the CPIO + * filesystem stream. + */ +RTDECL(int) RTZipCpioFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !IPRT_INCLUDED_zip_h */ + |